From 437461d8090cfdef523a9003e00f1ad83a84ee5f Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 12 Feb 2020 13:40:58 -0700 Subject: [PATCH 0001/4254] Add more robust hashing based on a paper The paper in question can be referenced [here](https://courses.cs.washington.edu/courses/cse521/15sp/refs/thorup1.pdf) This will compute a hash that is almost just as performant as the previous hashing, but handles the case where if lower numbered bits are all 0 and the highest bit of the length of the container is less than the lowest bit of the key, the hash will always be 0. --- lib/pure/collections/hashcommon.nim | 10 ++++- lib/pure/hashes.nim | 60 ++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index d9a914afc..b97b67cb2 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -50,8 +50,16 @@ template rawGetKnownHCImpl() {.dirty.} = proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} = rawGetKnownHCImpl() +template bits(n): uint32 = + var temp = n + var bits = 0.uint32 + while temp != 0: + temp = temp shr 1 + bits += 1 + bits + template genHashImpl(key, hc: typed) = - hc = hash(key) + hc = hash(key, targetBits=bits(maxHash(t))) if hc == 0: # This almost never taken branch should be very predictable. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index ac8498517..111e25382 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -113,31 +113,65 @@ proc hash*[T: proc](x: T): Hash {.inline.} = result = hash(pointer(x)) const - prime = uint(11) + defaultSeedA = (17316035218449499591'u64).uint + defaultSeedB = (1734880652122947187'u64).uint -proc hash*(x: int): Hash {.inline.} = +template computeIntegerHash(x, numBits, seedA, seedB): Hash = + cast[Hash]((seedA*cast[uint](x) + seedB) shr (sizeof(x)*8 - targetBits*8)) + +proc hash*( + x: int, + targetBits = sizeof(uint).uint32, + seedA = defaultSeedA, + seedB = defaultSeedB +): Hash {.inline.} = ## Efficient hashing of integers. - result = cast[Hash](cast[uint](x) * prime) + result = computeIntegerHash(x, targetBits, seedA, seedB) -proc hash*(x: int64): Hash {.inline.} = +proc hash*( + x: int64, + targetBits = sizeof(uint).uint32, + seedA = defaultSeedA, + seedB = defaultSeedB +): Hash {.inline.} = ## Efficient hashing of `int64` integers. - result = cast[Hash](cast[uint](x) * prime) + result = computeIntegerHash(x, targetBits, seedA, seedB) -proc hash*(x: uint): Hash {.inline.} = +proc hash*( + x: uint, + targetBits = sizeof(uint).uint32, + seedA = defaultSeedA, + seedB = defaultSeedB +): Hash {.inline.} = ## Efficient hashing of unsigned integers. - result = cast[Hash](x * prime) + result = computeIntegerHash(x, targetBits, seedA, seedB) -proc hash*(x: uint64): Hash {.inline.} = +proc hash*( + x: uint64, + targetBits = sizeof(uint).uint32, + seedA = defaultSeedA, + seedB = defaultSeedB +): Hash {.inline.} = ## Efficient hashing of `uint64` integers. - result = cast[Hash](cast[uint](x) * prime) + result = computeIntegerHash(x, targetBits, seedA, seedB) -proc hash*(x: char): Hash {.inline.} = +proc hash*( + x: char, + targetBits = sizeof(uint).uint32, + seedA = defaultSeedA, + seedB = defaultSeedB +): Hash {.inline.} = ## Efficient hashing of characters. - result = cast[Hash](cast[uint](ord(x)) * prime) + result = computeIntegerHash(ord(x), targetBits, seedA, seedB) -proc hash*[T: Ordinal](x: T): Hash {.inline.} = +proc hash*[T: Ordinal]( + x: T, + targetBits = sizeof(uint).uint32, + seedA = defaultSeedA, + seedB = defaultSeedB +): Hash {.inline.} = ## Efficient hashing of other ordinal types (e.g. enums). - result = cast[Hash](cast[uint](ord(x)) * prime) + result = computeIntegerHash(x, targetBits, seedA, seedB) proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. From b3dad3007c5c534b79edcfbe2438bed389f50a03 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 13 Feb 2020 06:28:16 -0700 Subject: [PATCH 0002/4254] WIP 3 --- lib/pure/bitops.nim | 9 +++++++++ lib/pure/collections/hashcommon.nim | 11 ++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 9ebdabb7b..e00ea3109 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -355,6 +355,15 @@ proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} = when sizeof(x) <= 4: result = firstSetBitNim(x.uint32) else: result = firstSetBitNim(x.uint64) +proc lastSetBit*(x: SomeUnsignedInt): uint {.inline, noSideEffect.} = + ## Returns the 1-based index of the most significant set bit of x. + ## If x == 0, the result will also be 0 + var temp = x + result = 0 + while temp != 0: + temp = temp shr 1 + result += 1 + proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} = ## Quickly find the log base 2 of an integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1, diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index b97b67cb2..ce5ab5809 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -9,6 +9,7 @@ # An ``include`` file which contains common code for # hash sets and tables. +from bitops import lastSetBit const growthFactor = 2 @@ -50,16 +51,8 @@ template rawGetKnownHCImpl() {.dirty.} = proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} = rawGetKnownHCImpl() -template bits(n): uint32 = - var temp = n - var bits = 0.uint32 - while temp != 0: - temp = temp shr 1 - bits += 1 - bits - template genHashImpl(key, hc: typed) = - hc = hash(key, targetBits=bits(maxHash(t))) + hc = hash(key, targetBits=lastSetBit(maxHash(t))) if hc == 0: # This almost never taken branch should be very predictable. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. From ae108f7a567a87188b144d3fe4f99ddf808750de Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 13 Feb 2020 08:02:20 -0700 Subject: [PATCH 0003/4254] WIP 4 --- lib/pure/collections/hashcommon.nim | 2 +- lib/pure/hashes.nim | 14 +++++++------- tests/collections/thashsets.nim | 12 +++++++++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index ce5ab5809..6281074af 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -52,7 +52,7 @@ proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} = rawGetKnownHCImpl() template genHashImpl(key, hc: typed) = - hc = hash(key, targetBits=lastSetBit(maxHash(t))) + hc = hash(key, targetBits=lastSetBit(maxHash(t).uint)) if hc == 0: # This almost never taken branch should be very predictable. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 111e25382..9a511ce9d 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -117,11 +117,11 @@ const defaultSeedB = (1734880652122947187'u64).uint template computeIntegerHash(x, numBits, seedA, seedB): Hash = - cast[Hash]((seedA*cast[uint](x) + seedB) shr (sizeof(x)*8 - targetBits*8)) + cast[Hash]((seedA*cast[uint](x) + seedB) shr (sizeof(x)*8 - numBits*8)) proc hash*( x: int, - targetBits = sizeof(uint).uint32, + targetBits: SomeUnsignedInt = sizeof(uint), seedA = defaultSeedA, seedB = defaultSeedB ): Hash {.inline.} = @@ -130,7 +130,7 @@ proc hash*( proc hash*( x: int64, - targetBits = sizeof(uint).uint32, + targetBits: SomeUnsignedInt = sizeof(uint), seedA = defaultSeedA, seedB = defaultSeedB ): Hash {.inline.} = @@ -139,7 +139,7 @@ proc hash*( proc hash*( x: uint, - targetBits = sizeof(uint).uint32, + targetBits: SomeUnsignedInt = sizeof(uint), seedA = defaultSeedA, seedB = defaultSeedB ): Hash {.inline.} = @@ -148,7 +148,7 @@ proc hash*( proc hash*( x: uint64, - targetBits = sizeof(uint).uint32, + targetBits: SomeUnsignedInt = sizeof(uint), seedA = defaultSeedA, seedB = defaultSeedB ): Hash {.inline.} = @@ -157,7 +157,7 @@ proc hash*( proc hash*( x: char, - targetBits = sizeof(uint).uint32, + targetBits: SomeUnsignedInt = sizeof(uint), seedA = defaultSeedA, seedB = defaultSeedB ): Hash {.inline.} = @@ -166,7 +166,7 @@ proc hash*( proc hash*[T: Ordinal]( x: T, - targetBits = sizeof(uint).uint32, + targetBits: SomeUnsignedInt = sizeof(uint), seedA = defaultSeedA, seedB = defaultSeedB ): Hash {.inline.} = diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim index cd4401511..bccf4654f 100644 --- a/tests/collections/thashsets.nim +++ b/tests/collections/thashsets.nim @@ -1,4 +1,4 @@ -import sets, hashes, algorithm +import sets, hashes, algorithm, bitops block setEquality: @@ -120,3 +120,13 @@ block hashForOrderdSet: reversed = !$reversed doAssert hash(r) == reversed doAssert hash(s1) != reversed + +block hashDoesntHaveLowerBitsCleared: + let num32 = 0xFFFF.uint32 + let bits = num32.lastBitSet + + let h1 = hash(0xFFFFFFFF00000000'u64, targetBits=bits) + let h2 = hash(0x2345123400000000'u64, targetBits=bits) + + + doAssert (h1 and num32) != (h2 and num32) From 7dd787b8a3da541063008123b5c8e206b3036a28 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 14 Feb 2020 09:13:55 +0000 Subject: [PATCH 0004/4254] fixes #13368 (#13397) --- compiler/injectdestructors.nim | 15 ++++++++------- compiler/lowerings.nim | 5 +++-- tests/arc/tmovebug.nim | 11 +++++++++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index dc431ef38..bdd624281 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -251,7 +251,8 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} = result = t.attachedOps[attachedSink] != nil proc genSink(c: var Con; dest, ri: PNode): PNode = - if isFirstWrite(dest, c): # optimize sink call into a bitwise memcopy + if isUnpackedTuple(dest) or isFirstWrite(dest, c): + # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) else: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) @@ -592,6 +593,9 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = # make sure it's destroyed at the end of the proc: if not isUnpackedTuple(v): c.destroys.add genDestroy(c, v) + elif c.inLoop > 0: + # unpacked tuple needs reset at every loop iteration + result.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) if ri.kind == nkEmpty and c.inLoop > 0: ri = genDefaultCall(v.typ, c, v.info) if ri.kind != nkEmpty: @@ -660,14 +664,11 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = case ri.kind of nkCallKinds: - if isUnpackedTuple(dest): - result = newTree(nkFastAsgn, dest, p(ri, c, consumed)) - else: - result = genSink(c, dest, p(ri, c, consumed)) + result = genSink(c, dest, p(ri, c, consumed)) of nkBracketExpr: if isUnpackedTuple(ri[0]): - # unpacking of tuple: take over elements - result = newTree(nkFastAsgn, dest, p(ri, c, consumed)) + # unpacking of tuple: take over the elements + result = genSink(c, dest, p(ri, c, consumed)) elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and not aliases(dest, ri): # Rule 3: `=sink`(x, z); wasMoved(z) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index b3b6cbb5c..d569c4dc9 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -74,8 +74,9 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode = result.add(v) for i in 0.. Date: Fri, 14 Feb 2020 12:33:36 +0100 Subject: [PATCH 0005/4254] fix bug in int128 (#13403) --- compiler/int128.nim | 89 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/compiler/int128.nim b/compiler/int128.nim index 573cc6082..ebcd226ec 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -250,14 +250,14 @@ proc `shr`*(a: Int128, b: int): Int128 = if isNegative(a): result.sdata(3) = -1 result.sdata(2) = a.sdata(3) shr (b and 31) - result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31)) - result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31)) + result.udata[1] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr (b and 31)) + result.udata[0] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31)) elif b < 96: if isNegative(a): result.sdata(3) = -1 result.sdata(2) = -1 result.sdata(1) = a.sdata(3) shr (b and 31) - result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31)) + result.udata[0] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr (b and 31)) else: # b < 128 if isNegative(a): result.sdata(3) = -1 @@ -696,3 +696,86 @@ when isMainModule: doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma)) doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma)) doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma)) + + let e = parseDecimalInt128("70997106675279150998592376708984375") + + let strArray = [ + # toHex(e shr 0), toHex(e shr 1), toHex(e shr 2), toHex(e shr 3) + "000dac6d782d266a37300c32591eee37", "0006d636bc1693351b9806192c8f771b", "00036b1b5e0b499a8dcc030c9647bb8d", "0001b58daf05a4cd46e601864b23ddc6", + "0000dac6d782d266a37300c32591eee3", "00006d636bc1693351b9806192c8f771", "000036b1b5e0b499a8dcc030c9647bb8", "00001b58daf05a4cd46e601864b23ddc", + "00000dac6d782d266a37300c32591eee", "000006d636bc1693351b9806192c8f77", "0000036b1b5e0b499a8dcc030c9647bb", "000001b58daf05a4cd46e601864b23dd", + "000000dac6d782d266a37300c32591ee", "0000006d636bc1693351b9806192c8f7", "00000036b1b5e0b499a8dcc030c9647b", "0000001b58daf05a4cd46e601864b23d", + "0000000dac6d782d266a37300c32591e", "00000006d636bc1693351b9806192c8f", "000000036b1b5e0b499a8dcc030c9647", "00000001b58daf05a4cd46e601864b23", + "00000000dac6d782d266a37300c32591", "000000006d636bc1693351b9806192c8", "0000000036b1b5e0b499a8dcc030c964", "000000001b58daf05a4cd46e601864b2", + "000000000dac6d782d266a37300c3259", "0000000006d636bc1693351b9806192c", "00000000036b1b5e0b499a8dcc030c96", "0000000001b58daf05a4cd46e601864b", + "0000000000dac6d782d266a37300c325", "00000000006d636bc1693351b9806192", "000000000036b1b5e0b499a8dcc030c9", "00000000001b58daf05a4cd46e601864", + "00000000000dac6d782d266a37300c32", "000000000006d636bc1693351b980619", "0000000000036b1b5e0b499a8dcc030c", "000000000001b58daf05a4cd46e60186", + "000000000000dac6d782d266a37300c3", "0000000000006d636bc1693351b98061", "00000000000036b1b5e0b499a8dcc030", "0000000000001b58daf05a4cd46e6018", + "0000000000000dac6d782d266a37300c", "00000000000006d636bc1693351b9806", "000000000000036b1b5e0b499a8dcc03", "00000000000001b58daf05a4cd46e601", + "00000000000000dac6d782d266a37300", "000000000000006d636bc1693351b980", "0000000000000036b1b5e0b499a8dcc0", "000000000000001b58daf05a4cd46e60", + "000000000000000dac6d782d266a3730", "0000000000000006d636bc1693351b98", "00000000000000036b1b5e0b499a8dcc", "0000000000000001b58daf05a4cd46e6", + "0000000000000000dac6d782d266a373", "00000000000000006d636bc1693351b9", "000000000000000036b1b5e0b499a8dc", "00000000000000001b58daf05a4cd46e", + "00000000000000000dac6d782d266a37", "000000000000000006d636bc1693351b", "0000000000000000036b1b5e0b499a8d", "000000000000000001b58daf05a4cd46", + "000000000000000000dac6d782d266a3", "0000000000000000006d636bc1693351", "00000000000000000036b1b5e0b499a8", "0000000000000000001b58daf05a4cd4", + "0000000000000000000dac6d782d266a", "00000000000000000006d636bc169335", "000000000000000000036b1b5e0b499a", "00000000000000000001b58daf05a4cd", + "00000000000000000000dac6d782d266", "000000000000000000006d636bc16933", "0000000000000000000036b1b5e0b499", "000000000000000000001b58daf05a4c", + "000000000000000000000dac6d782d26", "0000000000000000000006d636bc1693", "00000000000000000000036b1b5e0b49", "0000000000000000000001b58daf05a4", + "0000000000000000000000dac6d782d2", "00000000000000000000006d636bc169", "000000000000000000000036b1b5e0b4", "00000000000000000000001b58daf05a", + "00000000000000000000000dac6d782d", "000000000000000000000006d636bc16", "0000000000000000000000036b1b5e0b", "000000000000000000000001b58daf05", + "000000000000000000000000dac6d782", "0000000000000000000000006d636bc1", "00000000000000000000000036b1b5e0", "0000000000000000000000001b58daf0", + "0000000000000000000000000dac6d78", "00000000000000000000000006d636bc", "000000000000000000000000036b1b5e", "00000000000000000000000001b58daf", + "00000000000000000000000000dac6d7", "000000000000000000000000006d636b", "0000000000000000000000000036b1b5", "000000000000000000000000001b58da", + "000000000000000000000000000dac6d", "0000000000000000000000000006d636", "00000000000000000000000000036b1b", "0000000000000000000000000001b58d", + "0000000000000000000000000000dac6", "00000000000000000000000000006d63", "000000000000000000000000000036b1", "00000000000000000000000000001b58", + "00000000000000000000000000000dac", "000000000000000000000000000006d6", "0000000000000000000000000000036b", "000000000000000000000000000001b5", + "000000000000000000000000000000da", "0000000000000000000000000000006d", "00000000000000000000000000000036", "0000000000000000000000000000001b", + "0000000000000000000000000000000d", "00000000000000000000000000000006", "00000000000000000000000000000003", "00000000000000000000000000000001", + "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", + "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", + "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", + ] + + for i in 0 ..< 128: + let str1 = toHex(e shr i) + let str2 = strArray[i] + doAssert str1 == str2 + + let strArray2 = [ + "000dac6d782d266a37300c32591eee37", "001b58daf05a4cd46e601864b23ddc6e", "0036b1b5e0b499a8dcc030c9647bb8dc", "006d636bc1693351b9806192c8f771b8", + "00dac6d782d266a37300c32591eee370", "01b58daf05a4cd46e601864b23ddc6e0", "036b1b5e0b499a8dcc030c9647bb8dc0", "06d636bc1693351b9806192c8f771b80", + "0dac6d782d266a37300c32591eee3700", "1b58daf05a4cd46e601864b23ddc6e00", "36b1b5e0b499a8dcc030c9647bb8dc00", "6d636bc1693351b9806192c8f771b800", + "dac6d782d266a37300c32591eee37000", "b58daf05a4cd46e601864b23ddc6e000", "6b1b5e0b499a8dcc030c9647bb8dc000", "d636bc1693351b9806192c8f771b8000", + "ac6d782d266a37300c32591eee370000", "58daf05a4cd46e601864b23ddc6e0000", "b1b5e0b499a8dcc030c9647bb8dc0000", "636bc1693351b9806192c8f771b80000", + "c6d782d266a37300c32591eee3700000", "8daf05a4cd46e601864b23ddc6e00000", "1b5e0b499a8dcc030c9647bb8dc00000", "36bc1693351b9806192c8f771b800000", + "6d782d266a37300c32591eee37000000", "daf05a4cd46e601864b23ddc6e000000", "b5e0b499a8dcc030c9647bb8dc000000", "6bc1693351b9806192c8f771b8000000", + "d782d266a37300c32591eee370000000", "af05a4cd46e601864b23ddc6e0000000", "5e0b499a8dcc030c9647bb8dc0000000", "bc1693351b9806192c8f771b80000000", + "782d266a37300c32591eee3700000000", "f05a4cd46e601864b23ddc6e00000000", "e0b499a8dcc030c9647bb8dc00000000", "c1693351b9806192c8f771b800000000", + "82d266a37300c32591eee37000000000", "05a4cd46e601864b23ddc6e000000000", "0b499a8dcc030c9647bb8dc000000000", "1693351b9806192c8f771b8000000000", + "2d266a37300c32591eee370000000000", "5a4cd46e601864b23ddc6e0000000000", "b499a8dcc030c9647bb8dc0000000000", "693351b9806192c8f771b80000000000", + "d266a37300c32591eee3700000000000", "a4cd46e601864b23ddc6e00000000000", "499a8dcc030c9647bb8dc00000000000", "93351b9806192c8f771b800000000000", + "266a37300c32591eee37000000000000", "4cd46e601864b23ddc6e000000000000", "99a8dcc030c9647bb8dc000000000000", "3351b9806192c8f771b8000000000000", + "66a37300c32591eee370000000000000", "cd46e601864b23ddc6e0000000000000", "9a8dcc030c9647bb8dc0000000000000", "351b9806192c8f771b80000000000000", + "6a37300c32591eee3700000000000000", "d46e601864b23ddc6e00000000000000", "a8dcc030c9647bb8dc00000000000000", "51b9806192c8f771b800000000000000", + "a37300c32591eee37000000000000000", "46e601864b23ddc6e000000000000000", "8dcc030c9647bb8dc000000000000000", "1b9806192c8f771b8000000000000000", + "37300c32591eee370000000000000000", "6e601864b23ddc6e0000000000000000", "dcc030c9647bb8dc0000000000000000", "b9806192c8f771b80000000000000000", + "7300c32591eee3700000000000000000", "e601864b23ddc6e00000000000000000", "cc030c9647bb8dc00000000000000000", "9806192c8f771b800000000000000000", + "300c32591eee37000000000000000000", "601864b23ddc6e000000000000000000", "c030c9647bb8dc000000000000000000", "806192c8f771b8000000000000000000", + "00c32591eee370000000000000000000", "01864b23ddc6e0000000000000000000", "030c9647bb8dc0000000000000000000", "06192c8f771b80000000000000000000", + "0c32591eee3700000000000000000000", "1864b23ddc6e00000000000000000000", "30c9647bb8dc00000000000000000000", "6192c8f771b800000000000000000000", + "c32591eee37000000000000000000000", "864b23ddc6e000000000000000000000", "0c9647bb8dc000000000000000000000", "192c8f771b8000000000000000000000", + "32591eee370000000000000000000000", "64b23ddc6e0000000000000000000000", "c9647bb8dc0000000000000000000000", "92c8f771b80000000000000000000000", + "2591eee3700000000000000000000000", "4b23ddc6e00000000000000000000000", "9647bb8dc00000000000000000000000", "2c8f771b800000000000000000000000", + "591eee37000000000000000000000000", "b23ddc6e000000000000000000000000", "647bb8dc000000000000000000000000", "c8f771b8000000000000000000000000", + "91eee370000000000000000000000000", "23ddc6e0000000000000000000000000", "47bb8dc0000000000000000000000000", "8f771b80000000000000000000000000", + "1eee3700000000000000000000000000", "3ddc6e00000000000000000000000000", "7bb8dc00000000000000000000000000", "f771b800000000000000000000000000", + "eee37000000000000000000000000000", "ddc6e000000000000000000000000000", "bb8dc000000000000000000000000000", "771b8000000000000000000000000000", + "ee370000000000000000000000000000", "dc6e0000000000000000000000000000", "b8dc0000000000000000000000000000", "71b80000000000000000000000000000", + "e3700000000000000000000000000000", "c6e00000000000000000000000000000", "8dc00000000000000000000000000000", "1b800000000000000000000000000000", + "37000000000000000000000000000000", "6e000000000000000000000000000000", "dc000000000000000000000000000000", "b8000000000000000000000000000000", + "70000000000000000000000000000000", "e0000000000000000000000000000000", "c0000000000000000000000000000000", "80000000000000000000000000000000", + ] + + for i in 0 ..< 128: + let str1 = toHex(e shl i) + let str2 = strArray2[i] + doAssert str1 == str2 From 3d7d06571c1cf287362c9f1b00b4e2d4f95fdc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Fri, 14 Feb 2020 21:15:52 +0100 Subject: [PATCH 0006/4254] isolate the build process from external config files (#13411) --- build_all.bat | 5 +++-- build_all.sh | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/build_all.bat b/build_all.bat index 59df15594..7967e2584 100644 --- a/build_all.bat +++ b/build_all.bat @@ -12,5 +12,6 @@ if not exist bin\nim.exe ( cd .. ) bin\nim.exe c --skipUserCfg --skipParentCfg koch -koch.exe boot -d:release -koch.exe tools \ No newline at end of file +koch.exe boot -d:release --skipUserCfg --skipParentCfg +koch.exe tools --skipUserCfg --skipParentCfg + diff --git a/build_all.sh b/build_all.sh index 2ed2233e9..d3bba2211 100644 --- a/build_all.sh +++ b/build_all.sh @@ -27,7 +27,7 @@ build_nim_csources(){ # some args were passed (eg: `--cpu i386`), need to call build.sh build_nim_csources_via_script "$@" else - # no args, use multhreaded (5X faster on 16 cores: 10s instead of 50s) + # no args, use multiple Make jobs (5X faster on 16 cores: 10s instead of 50s) makeX=make unamestr=$(uname) if [ "$unamestr" = 'FreeBSD' ]; then @@ -47,5 +47,6 @@ build_nim_csources(){ # Note: if fails, may need to `cd csources && git pull` echo_run bin/nim c --skipUserCfg --skipParentCfg koch -echo_run ./koch boot -d:release -echo_run ./koch tools # Compile Nimble and other tools. +echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg +echo_run ./koch tools --skipUserCfg --skipParentCfg # Compile Nimble and other tools. + From 3300e317a419d0f8f5e6dfcf822702a32738eb27 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 14 Feb 2020 21:28:50 +0100 Subject: [PATCH 0007/4254] add ggplotnim to important_packages (#13206) --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index f2ce8fb25..3018a21ff 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -30,6 +30,7 @@ pkg "easygl", "nim c -o:egl -r src/easygl.nim", true, "https://github.com/jackmo pkg "elvis" pkg "fragments", "nim c -r fragments/dsl.nim" pkg "gara" +pkg "ggplotnim", "nimble testCI", true pkg "glob" pkg "gnuplot" # pkg "godot", "nim c -r godot/godot.nim" # not yet compatible with Nim 0.19 From 5bf571f061d53d35aab727f420afd9f415987723 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Fri, 14 Feb 2020 20:59:37 +0000 Subject: [PATCH 0008/4254] Fix to asynchttpserver form data/body broken with #13147 (#13394) * Fix to asynchttpserver form data/body broken with #13147 * New implementation that use a interator instance of future streams * asynchttpserver now can handle chunks of data. --- changelog.md | 3 +- lib/pure/asynchttpserver.nim | 116 ++++++++++++++++++++++------------- 2 files changed, 75 insertions(+), 44 deletions(-) diff --git a/changelog.md b/changelog.md index 9bec0c47a..52b202d8c 100644 --- a/changelog.md +++ b/changelog.md @@ -65,7 +65,8 @@ ## Library changes -- `asynchttpserver` now the request body is a FutureStream. +- `asynchttpserver` added an iterator that allows the request body to be read in + chunks of data when new server "stream" option is set to true. - `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` and only returns once all pending async operations are guaranteed to have completed. - `asyncdispatch.drain` now consistently uses the passed timeout value for all diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 5292ac75a..9aed0255b 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -41,13 +41,13 @@ ## import asynchttpserver, asyncdispatch ## import strutils, strformat ## +## const stream = true # for test purposes switch from true to false +## ## proc htmlpage(contentLength, bodyLength: int): string = ## return &""" ## ## -## -## -## +## ## ##
## File:
@@ -65,17 +65,23 @@ ## bodyLength = 0 ## if req.reqMethod == HttpPost: ## contentLength = req.headers["Content-length"].parseInt -## if contentLength < 8*1024: # the default chunkSize -## # read the request body at once -## let body = await req.bodyStream.readAll(); -## bodyLength = body.len +## if stream: +## # Read 8*1024 bytes at a time +## # optional chunkSize parameter. The default is 8*1024 +## for length, data in req.bodyStream(8*1024): +## let content = await data +## if length == content.len: +## bodyLength += content.len +## else: +## # Handle exception +## await req.respond(Http400, +## "Bad Request. Data read has a different length than the expected.") +## return ## else: -## # read 8*1024 bytes at a time -## while (let data = await req.bodyStream.read(); data[0]): -## bodyLength += data[1].len +## bodyLength += req.body.len ## await req.respond(Http200, htmlpage(contentLength, bodyLength)) ## -## let server = newAsyncHttpServer(maxBody = 10485760) # 10 MB +## let server = newAsyncHttpServer(maxBody = 10485760, stream = stream) # 10 MB ## waitFor server.serve(Port(8080), cb) import tables, asyncnet, asyncdispatch, parseutils, uri, strutils @@ -93,9 +99,6 @@ const maxLine = 8*1024 when (NimMajor, NimMinor) >= (1, 1): - const - chunkSize = 8*1024 ## This seems perfectly reasonable for default chunkSize. - type Request* = object client*: AsyncSocket # TODO: Separate this into a Response object? @@ -104,8 +107,16 @@ when (NimMajor, NimMinor) >= (1, 1): protocol*: tuple[orig: string, major, minor: int] url*: Uri hostname*: string ## The hostname of the client that made the request. - body*: string # For future removal - bodyStream*: FutureStream[string] + body*: string + contentLength*: int + + type + AsyncHttpServer* = ref object + socket: AsyncSocket + reuseAddr: bool + reusePort: bool + maxBody: int ## The maximum content-length that will be read for the body. + stream: bool ## By default (stream = false), the body of the request is read immediately else: type Request* = object @@ -117,20 +128,30 @@ else: hostname*: string ## The hostname of the client that made the request. body*: string -type - AsyncHttpServer* = ref object - socket: AsyncSocket - reuseAddr: bool - reusePort: bool - maxBody: int ## The maximum content-length that will be read for the body. + type + AsyncHttpServer* = ref object + socket: AsyncSocket + reuseAddr: bool + reusePort: bool + maxBody: int ## The maximum content-length that will be read for the body. -proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, +when (NimMajor, NimMinor) >= (1, 1): + proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, + maxBody = 8388608, stream = false): AsyncHttpServer = + ## Creates a new ``AsyncHttpServer`` instance. + new result + result.reuseAddr = reuseAddr + result.reusePort = reusePort + result.maxBody = maxBody + result.stream = stream +else: + proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = - ## Creates a new ``AsyncHttpServer`` instance. - new result - result.reuseAddr = reuseAddr - result.reusePort = reusePort - result.maxBody = maxBody + ## Creates a new ``AsyncHttpServer`` instance. + new result + result.reuseAddr = reuseAddr + result.reusePort = reusePort + result.maxBody = maxBody proc addHeaders(msg: var string, headers: HttpHeaders) = for k, v in headers: @@ -193,13 +214,30 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = proc sendStatus(client: AsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L\c\L") +when (NimMajor, NimMinor) >= (1, 1): + iterator bodyStream*( + request: Request, + chunkSize: int = 8*1024): (int, Future[string]) = + ## The chunkSize parameter is optional and default value is 8*1024 bytes. + ## + ## This iterator return a tuple with the length of the data that was read + ## and a future. + var remainder = request.contentLength + while remainder > 0: + let readSize = min(remainder, chunkSize) + let data = request.client.recv(readSize) + if data.failed: + raise newException(ValueError, "Error reading POST data from client.") + yield (readSize, data) + remainder -= readSize + proc processRequest( server: AsyncHttpServer, req: FutureVar[Request], client: AsyncSocket, address: string, lineFut: FutureVar[string], - callback: proc (request: Request): Future[void] {.closure, gcsafe.}, + callback: proc (request: Request): Future[void] {.closure, gcsafe.} ): Future[bool] {.async.} = # Alias `request` to `req.mget()` so we don't have to write `mget` everywhere. @@ -213,13 +251,9 @@ proc processRequest( request.hostname.shallowCopy(address) assert client != nil request.client = client + request.body = "" when (NimMajor, NimMinor) >= (1, 1): - request.bodyStream = newFutureStream[string]() - # To uncomment in the future after compatibility issues - # with third parties are solved - # else: - # request.body = "" - request.body = "" # Temporary fix for future removal + request.contentLength = 0 # We should skip at least one empty line before the request # https://tools.ietf.org/html/rfc7230#section-3.5 @@ -316,16 +350,12 @@ proc processRequest( return false when (NimMajor, NimMinor) >= (1, 1): - var remainder = contentLength - while remainder > 0: - let readSize = min(remainder, chunkSize) - let data = await client.recv(read_size) - if data.len != read_size: + request.contentLength = contentLength + if not server.stream: + request.body = await client.recv(contentLength) + if request.body.len != contentLength: await request.respond(Http400, "Bad Request. Content-Length does not match actual.") return true - await request.bodyStream.write(data) - remainder -= data.len - request.bodyStream.complete() else: request.body = await client.recv(contentLength) if request.body.len != contentLength: From f3eb0a5970ff0b9ec5ed8b95551c79cea395e279 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 15 Feb 2020 19:53:40 +0100 Subject: [PATCH 0009/4254] capture macro now accepts variables of different types (#13356) * Capture macro can now accept variables of different types * Add test * Update examples * Use let instead of var --- lib/pure/sugar.nim | 8 +++++--- tests/closure/tcapture.nim | 14 +++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index fa28ffcf4..f18557e0e 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -165,7 +165,7 @@ template distinctBase*(T: typedesc): typedesc {.deprecated: "use distinctBase fr ## reverses ``type T = distinct A``; works recursively. typetraits.distinctBase(T) -macro capture*(locals: openArray[typed], body: untyped): untyped {.since: (1, 1).} = +macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} = ## Useful when creating a closure in a loop to capture some local loop variables ## by their current iteration values. Example: ## @@ -175,14 +175,16 @@ macro capture*(locals: openArray[typed], body: untyped): untyped {.since: (1, 1) ## for i in 5..7: ## for j in 7..9: ## if i * j == 42: - ## capture [i, j]: + ## capture i, j: ## myClosure = proc () = echo fmt"{i} * {j} = 42" ## myClosure() # output: 6 * 7 == 42 ## let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s] - ## var l = m.mapIt(capture([it], proc (s: string): string = it(s))) + ## var l = m.mapIt(capture(it, proc (s: string): string = it(s))) ## let r = l.mapIt(it("be")) ## echo r[0] & ", or " & r[1] # output: to be, or not to be var params = @[newIdentNode("auto")] + let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0] + else: locals for arg in locals: params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg)) result = newNimNode(nnkCall) diff --git a/tests/closure/tcapture.nim b/tests/closure/tcapture.nim index ff3490f07..dafc44739 100644 --- a/tests/closure/tcapture.nim +++ b/tests/closure/tcapture.nim @@ -2,7 +2,9 @@ discard """ output: ''' to be, or not to be (v: 1) +(w: -1) (v: 1) +(w: -1) ''' joinable: false """ @@ -14,13 +16,19 @@ var l = m.mapIt(capture([it], proc (s: string): string = it(s))) let r = l.mapIt(it("be")) echo r[0] & ", or " & r[1] -type O = object - v: int +type + O = object + v: int + U = object + w: int var o = O(v: 1) +var u = U(w: -1) var execute: proc() -capture [o]: +capture o, u: execute = proc() = echo o + echo u execute() o.v = -1 +u.w = 1 execute() From ba25f849a6bc39c9b326ea23a8d750472e7ace76 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 15 Feb 2020 19:31:00 -0300 Subject: [PATCH 0010/4254] Add browsers.osOpen (#12901) * Add osOpen alias for the operating system specific open command * Add `--git.devel` option to the documentation remove unused import (#12900) fix json regression D20191212T144944 (#12902) [backport] Peer Review Feedback https://github.com/nim-lang/Nim/pull/12901#issuecomment-565851680 Merge branch 'devel' of https://github.com/nim-lang/Nim into osopen Peer Review Feedback https://github.com/nim-lang/Nim/pull/12901#issuecomment-565851680 Update lib/pure/browsers.nim Co-Authored-By: Dominik Picheta Peer Review Feedback https://github.com/nim-lang/Nim/pull/12901#discussion_r358492316 allow typed/untyped in magic procs (#12911) NaN floatFormat with clang_cl (#12910) * clang_cl nan floatFormat * format add $nimeq for gdb (#12909) ARC: cycle detector (#12823) * first implementation of the =trace and =dispose hooks for the cycle collector * a cycle collector for ARC: progress * manual: the .acyclic pragma is a thing once again * gcbench: adaptations for --gc:arc * enable valgrind tests for the strutils tests * testament: better valgrind support * ARC refactoring: growable jumpstacks * ARC cycle detector: non-recursive algorithm * moved and renamed core/ files back to system/ * refactoring: --gc:arc vs --gc:orc since 'orc' is even more experimental and we want to ship --gc:arc soonish Cleanup leftovers of #12911(#12916) Fix single match output (#12920) fixes #12899 (#12921) * fixes #12899 * fixes regression: destroy global variables in reverse declaration order, closureleak test relies on it Implement NixOS distro check (#12914) Better case coverage error message for alias and range enum (#12913) fix error in assertions document (#12925) [backport] fix cmdline bugs affecting nimBetterRun correctness (#12933) [backport] fix #12919 tasyncclosestall flaky: Address already in use (#12934) system.reset is no longer magic (#12937) It has now means setting x to default for new and old runtime alike Fix #12785 (#12943) * Fix #12785 and add test * better variable name update documentation for `closureScope` and `capture` (#12886) fixes #12735 on osx, call dsymutil for debug builds (#12931) * fix #12735 osx: dsymutil needs to be called for debug builds * also write dsymutil command to extraCmds in json build file Auto-initialize deques (#12879) case coverage error message for `char` (#12948) lenVarargs: number of varargs elements (#12907) docs: tiny style improvements added guidelines for evolving Nim's stdlib fixes a bug that kept sugar.collect from working with for loop macros [backport] fixes #12826 fixes a regression a better bugfix fixes a test case fixes a silly regression fixes the distros.nim regression ported channels to ARC ported osproc.nim to ARC ported re.nim to ARC ARC: default to a shared heap with --threads:on osproc: fixes regression fixes another regression fixes #12945 (#12959) minor refactorings Fixes stackoverflow links in readme (#12963) [backport] Allow customize Host header [ci skip] docfix .. < => ..< (#12981) [backport] parsecfg: retain CRLF line breaks, fixes #12970 (#12971) generic stack trace overriding mechanism (#12922) * libbacktrace support * switch to a generic stack trace overriding mechanism When "nimStackTraceOverride" is defined, once of the imported modules can register its own procedure to replace the default stack trace generation by calling `registerStackTraceOverride(myOwnProc)`. Tested with `./koch boot -d:release --debugger:native -d:nimStackTraceOverride --import:libbacktrace` for the compiler itself and `./bin/nim c -r -f --stacktrace:off --debugger:native -d:nimStackTraceOverride --import:libbacktrace foo.nim` for an external program. * make the StackTraceOverrideProc {.noinline.} Added fix for handling TaintedStrings in streams and httpclient (#12969) * Added fix for taint mode in streams and httpclient * Removed taintMode export from system.nim Check pqntuples > 0 in getValue. Fixes #12973 (#12974) c_fflush() the rawWrite() buffer (#12987) Stack traces on an unbuffered stderr get out of sync with line-buffered stdout - usually on Windows terminals or CI logs. This fixes it by calling C's fflush() on the output buffer in the procedure used for printing stack traces. fixes #12989 Revert "fixes #12989" This reverts commit 928c2fee06bd11a0901c5f563b4953788be76ae6. fixes #12965 (#12991) fixes #12989 (#12992) * fixes #12989 * Revert "remove unwanted changes" This reverts commit 501829732a8e44deef2d815c303859efbe452cb5. fixes disruptek/nimph#102 multi-level nim.cfg use (#13001) [backport] --exception:goto switch for deterministic exception handling (#12977) This implements "deterministic" exception handling for Nim based on goto instead of setjmp. This means raising an exception is much cheaper than in C++'s table based implementations. Supports hard realtime systems. Default for --gc:arc and the C target because it's generally a good idea and arc is all about deterministic behavior. Note: This implies that fatal runtime traps are not catchable anymore! This needs to be documented. fix #12985 {.push.} now does not apply to generic instantiations (#12986) Sink to MemMove optimization in injectdestructors (#13002) remove default argument for readLines (#12807) [backport] fixes #12978 (#13012) Fix typo (#13015) [backport] fixes #12961 (#13019) fixes #12956 (#13020) fix #12988 (#13022) fix #12988 Fixes #13026 (#13028) fixes #12964 (#13027) fixes #13032 VM: support importc var, ptr/pointer types, cast int <=> ptr/pointer (#12877) * VM: allow certain hardcoded special var variables at CT * VM: allow all importc var, cast[int](ptr) * fix tests tests/vm/tstaticprintseq.nim, tests/cpp/t8241.nim * VM: == works for ptr/pointer nodes * bugfix: ==, cast now also works for pointer, not just ptr * VM supports cast PtrLikeKinds <=> PtrLikeKinds / int * improve cname handling * fixup + bug fix * VM: support cast from ref to int * address comment: opcLdGlobalDeref => opcLdGlobalDerefFFI * defensive check against typ == nil fix enumtostr crash for enum-range (#13035) fixes #13013, reverts previous changes to readLines() (#13036) [backport] * Revert "remove default argument for readLines (#12807) [backport]" This reverts commit c949b81efdeb08b38224e1678ad140b7b7663b15. reprjs: style changes fixes #12996 Rst parser respect `:start-after:` and `:end-before:` in `include` directive (#12972) * [FEATURE] rst parser respect :start-after: in include Rst parser now respects `:start-after:` and `:end-before:` attributes for `include` directive. * [DOC] include directive parsing proc update * [TEST] Added unit tests for include rst directive in `rst` module Allow `-o` option for `buildIndex` (#13037) [backport] Addressing #12771 This is also included in the docgen documentation [here](https://nim-lang.org/docs/docgen.html) but its not respected as reported in the issue. [cleanup] remove disabled (and obsolete) ttypetraits; rename ttypetraits2 => ttypetraits (#13041) * remove disabled (and obsolete) ttypetraits; rename ttypetraits2 => ttypetraits * D20200105T085828 fix super strange bug that causes CI to fail: builds.sr.ht with: `Error: Settle timed out after 120 attempts` Continue #13002 (#13021) testament/important_packages dont run hts (#13052) Modify the test command for nimly (nimble-package) (#13053) clean up deprecated stuff and unused imports in tests (#13059) --styleCheck:hint now works (#13055) [easy] --hint:link:on now shows link cmd instead of nothing (#13056) * --hint:link:on now shows link cmd instead of nothing * update doc for --listCmd add pqserverVersion,pqconnectionNeedsPassword,pqconnectionUsedPassword (#13060) basename supports pragmaexpr (#13045) * basename supports pragmaexpr * update changelog distinctBase type trait for distinct types (#13031) make SuccessX show project file + output file (#13043) * make SuccessX show project file + output file * address comments * fix test and add `result.err = reNimcCrash` otherwise hard to see where reNimcCrash used * address comments move entries from the wrong changelog file [ci skip] fix crash due to errant symbols in nim.cfg (#13073) [backport] Deleted misplaced separator (#13085) [backport] Misplaced separator, which was constantly breaking compilation on Haiku OS, was deleted. take the one good idea from --os:standalone and enable it via -d:StandaloneHeapSize (#13077) remove all remaining warnings when build nim (with -d:nimHasLibFFI) (#13084) * cleanup deprecations in evalffi + elsewhere * remove dead code getOrdValue64 Use '__noinline' instead of 'noinline' for N_NOINLINE gcc attribute, this prevents clashes with systems where 'noinline' might be already defined (#13089) Fix error check code in osproc (#13090) [backport] fixes #13072; no test case because it will be added later with more exception handling related bugfixes fixes #13070 typetraits: fixes #6454; genericParams; added lenTuple; added tuple type get (#13064) [backport] system/io.nim fix wrong documentation comment [ci skip] fixes an asyncftpclient bug; refs #13096 [backport] System cleanup, part 1 (#13069) * system.nim: mark what every .pop does * system.nim: un-nest when statements [backport] fix #12813, fix #13079 (#13099) Correctly remove a key from CountTable when it is set to zero. more arc features (#13098) * config update * ARC now supports 'repr' and 'new' with finalizers is supported Remove some unused/disabled OpenSSL functions (#13106) Add link to posix_utils.html in posix.nim (#13111) VM FFI: write(stderr, msg) and fprintf(cstderr, msg) now work at CT (#13083) fix the ftp store function read the local file bug (#13108) [backport] * Update asyncftpclient.nim When use newStringOfCap function not have assign memory for the string data,so if use this address the fault is rasise. * complelete the bugfix fix rtti sizeof for varargs in global scope (#13125) [backport] fixes #13122 (#13126) * fixes #13122 * moved tests to where they belong fixes #13112 (#13127) * improve line error information * fixes #13112 Expose more openSSL methods. (#13131) fixes #13100 nim doc now treats `export localSymbol` correctly (#13123) [backport] * fix #13100 nim doc now treats `export localSymbol` correctly * use owner instead fixes #13119 (#13128) * fixes #13119 * fixes a regression fixes #13105 (#13138) fixes #10665 (#13141) [backport] pass platform argument only if vccexe is used (#13078) * pass platform only if vccexe is used * fixes #12297 fixes #13104 [backport] (#13142) fixes #9674 [backport] (#13143) Fix typo in doc/destructors.rst (#13148) Added 'ansic' os support for minimal (embedded) targets (#13088) * os:any implementation * os:asny: omit flock/funlock calls in echoBinSafe * Disabled default "unhandled expection" reporting for `--os:any` to reduce code size. Added unhandledExceptionHook instead which can be used to get a notification from Nim and handle it from the application. System cleanup, part 2 (#13155) * create basic_types, arithmetics, exceptions, comparisons * create setops.nim * create memalloc.nim * create gc_interface.nim * create iterators_1.nim export normalizePathEnd (#13152) successX now correctly shows html output for `nim doc`, `nim jsondoc`; fix #13121 (#13116) * successX now correctly shows html output for nim doc * fixes #13121 * fixup hintSuccessX to be less weird ARC: misc bugfixes (#13156) * fixes #13102 * closes #13149 * ARC: fixes a move optimizer bug (there are more left regarding array and tuple indexing) * proper fix; fixes #12957 * fixes yet another case object '=' code generation problem CI fix timeout error (#13134) Remove obsolete code from osalloc (#13158) style fix: change 'JS' to 'js' to make it consistent (#13168) Working towards arc codegen (#13153) fixes #13029 fixes #12998 nim doc regression (#13117) fix tsizeof3 for aarch64 (#13169) Cleanup DFA (#13173) Fix docs (#13176) fixes #13095 (#13181) * fixes #13095 * fix typo make case-object transitions explicit, make unknownLineInfo a const, replace a few magic numbers with consts (#13170) ARC works for async on Windows (#13179) make sink operator optional (#13068) * make sink operator optional * bug fix, add changelog entry * Trigger build * fix one regression * fix test * Trigger build * fix typos Fix docs for subdirs too (#13180) * Fix doc subdirs * Extract to helper proc, and fix on windows followup on #10435 : should be diff, not show (#13162) fixes #13157 refs #13054 correctly handle {.exportc,dynlib.} and {.exportcpp,dynlib.} (#13136) * refs #13054 correctly handle {.exportc,dynlib.} and {.exportcpp,dynlib.} * put back NIM_EXTERNC for N_LIB_EXPORT; causes issues with compilerproc fixes #13144 (#13145) * fixup: genscript now does not copy nimbase.h but uses -I$nim/lib times: toUnixFloat, fromUnixFloat (#13044) maybe: allows optional chaining of field access and indexing when LHS i snil (#13023) * maybe: allows optional chaining * fix tools/kochdocs.nim * improve semantics to distinguish valid from invalid values * for now, wrapnil, isValid, unwrap are not exported fix docs + API for fieldPairs, fields (#13189) more on arc codegen (#13178) * arc codegen for union type * add more tests * fix offsetof * fix tsizeof test * fix style Add link to packaging.html (#13194) Fixes #13186 (#13188) fixes #13195 revert last commit Merge branch 'devel' of https://github.com/nim-lang/Nim into devel Revert "fixes #13195" This reverts commit cd7904f2b29e623998a1d32ee726d000f56fc5ce. fixes #13110 (#13197) fixes #13195 (#13198) * fixes #13195 * extra fix * fix typo compiler/ccgtypes: hide exportc proc unless it has dynlib (#13199) This hides most of stdlib's internal functions from resulting binaries/libraries, where they aren't needed on *nix. Static libraries are not affected by this change (visibility doesn't apply to them). fix range[enum] type conversion (#13204) [backport] Idxmin & idxmax, continuation (#13208) * Add idxmin() which returns the index of the minimum value * Add idxmax() which returns the index of the maximum value * Add tests for idxmin() * Add tests for idxmax() * Remove initialization of result = 0 * Adds overloading for arrays (no enums indexed arrays yet) * Add support for enum index arrays * Fix tests with enum * Fix tests for idxmax * Change names of the procedures to minIndex and maxIndex * address Araq's comments: - remove 'array' versions - add .since pragma - return 'int' instead of 'Natural' - add changelog entry Co-authored-by: Federico A. Corazza <20555025+Imperator26@users.noreply.github.com> fix #13211 relativePath("foo", ".") (#13213) fixes a critical times.nim bug reported on IRC [backport] (#13216) httpclient, maxredirects to Natural, newHttpClient/newAsyncHttpClient add headers argument instead of hardcoded empty (#13207) added note to re constructor regarding performance (#13224) Since I was new to regex I did not know that there is a compilation going on with ``re"[abc]"`` constructor and so I followed the other examples in the docs blindly, that is I just put the constructor directly in the arguments of match, find, etc., which was inside a loop and then wondered why my performance was so bad. Of course putting it outside the loop made it vastly more performant. People like me would benefit from the small note I added I would think :) [backport] Documentation Fix #12251 (#13226) [ci skip] [backport] times/getClockStr(): fix mistake in doc (#13229) [ci skip] new os.isRelativeTo (#13212) [backport] Fix typo and improve in code-block of 'lib/pure/parseutils.nim' (#13231) [ci skip] [backport] fix #11440, add docs to isNil for seq types needing nilseq (#13234) [ci skip] VM: allow overriding MaxLoopIterations without rebuilding nim (#13233) kochdocs: use a glob instead of hardcoded list; generate docs for compiler/; bugfixes (#13221) * kochdocs: use a glob instead of hardcoded list; generate docs for compiler/; bugfixes * fixup after #13212 isRelativeTo got merged fix lots of bugs with parentDir, refs #8734 (#13236) Unexport even more symbols (#13214) * system/gc: don't export markStackAndRegisters * compiler/cgen: unexport internal symbols As these functions are Nim-specific walkaround against C's optimization schemes, they don't serve any purpose being exported. * compiler/cgen: don't export global var unless marked * compiler/ccgthreadvars: don't export threadvar unless marked * tests/dll/visibility: also check for exports This ensure that these changes don't break manual exports. * compiler/cgen: hide all variables created for constants * compiler/ccgtypes: don't export RTTI variables * compiler/ccgexprs: make all complex const static * nimbase.h: fix export for windows * compiler/cgen, ccgthreadvars: export variables correctly For C/C++ variables, `extern` means that the variable is defined in an another unit. Added a new N_LIB_EXPORT_VAR to correctly export variables. Removed lib/system/allocators.nim. seqs_v2 and strs_v2 now uses allocShared0. (#13190) * Cleanup, remove lib/system/allocators.nim. seqs_v2 and strs_v2 now use allocShared0 by default. * Fixed -d:useMalloc allocShared / reallocShared / deallocShared. These now use the alloc/dealloc/realloc implementation that also takes care of zeroing memory at realloc. * Removed debug printfs * Removed unpairedEnvAllocs() from tests/destructor/tnewruntime_misc * More mmdisp cleanups. The shared allocators do not need to zero memory or throw since the regular ones already do that * Introduced realloc0 and reallocShared0, these procs are now used by strs_v2 and seqs_v2. This also allowed the -d:useMalloc allocator to drop the extra header with allocation length. * Moved strs_v2/seqs_v2 'allocated' flag into 'cap' field * Added 'getAllocStats()' to get low level alloc/dealloc counters. Enable with -d:allocStats * *allocShared implementations for boehm and go allocators now depend on the proper *allocImpl procs [backport] documentation: Add channels examples (#13202) [ci skip] [backport] Make all parseutils examples auto-checking (#13238) - Also fix one example's output (ikString -> ikStr, ikVar instead of ikExpr) Updated 'nim for embedded systems' section to use --os:any and --gc:arc (#13237) * Updated 'nim for embedded systems' section to use --os:any and --gc:arc * Added section about size optimization to embedded systems Remove name attribute from docutils.nimble (#13239) Fixes asyncftpclient multiline reading, fixes #4684 (#13242) Previously, the 4th character of `result` was checked for `'-'` every time, instead of each new line. Also made it work for taint mode. Fix typo for literal `[` (#13243) The literal value for the `tkBracketLe` token was incorrectly set to `]` rather than `[`. I've had a quick glance at the code and it doesn't look like this change will affect anything at all, but I haven't tested yet - let's see if the CI explodes... Add "origin" to window.location (#13251) Add "origin" to window location: https://www.w3schools.com/jsref/prop_loc_origin.asp nim dump: add libpath (#13249) contributing docs: symbols need package prefix; changed allocStats to nimAllocStats (#13247) testament/azure: major rewrite (#13246) This commit features a major rewrite of Azure Pipelines integration, turning the spaghetti it originally was into something maintainable. Key changes: - No longer requires a ton of hooks into testament. - Results are now cached then bulk-uploaded to prevent throttling from Azure Pipelines, avoiding costly timeouts. - A low timeout is also employed to avoid inflated test time. - The integration is now documented. Cleaned up mmdisp.nim, moved implementations into lib/system/mm/ (#13254) make goto based exceptions available for 'nim cpp' (#13244) * make goto based exceptions available for 'nim cpp' * optimize seq.add to be comparable to C++'s emplace_back ARC: remove unnecessary code ARC: optimize complete object constructors to use nimNewObjUninit make nre compile with --gc:arc Rename isNilOrWhitespace to isEmptyOrWhitespace and make it use allCharsInSet (#13258) * Rename isNilOrWhitespace to isEmptyOrWhitespace * Make isEmptyOrWhitespace use allCharsInSet(Whitespace) Clearer final objects error; fixes #13256 (#13257) scrollTop must be settable (#13263) * scrollTop must be assignable Make scrollTop settable * add missing export fixes #13219 (#13272) fixes #13281 (#13282) * fixes ##13281 * add comment to test unittest add resetOutputFormatters proc (#13267) * add resetOutputFormatters * remove space * resolve comments TlSF Alloctor: use less memory for --gc:arc (#13280) Tiny since cleanup (#13286) nimv2 widestring indexing (#13279) Repr v2 progress (#13268) * progress on repr_v2 * repr progress * add ref objects with distrinct * fix failing tests refactor htmldocs; gitignore it removed unused import fix stdout(etc) for emscripten csize => csize_t for sysctl Thread attributes should be destroyed using the pthread_attr_destroy() (#13293) On some OSes (such as FreeBSD or Solaris), pthread_attr_init allocate memory. So it is necessary to deallocate that memory by using pthread_attr_destroy. fix critical bug discovered by #11591 (#13290) [backport] miscellaneous bug fixes (#13291) * fix for emscripten etc * add testcase for #13290 * replace deprecated isNilOrWhitespace CT FFI: fix for windows; fix case transition; error msg shows more useful context (#13292) * evalffi: fix case transition * evalffi: fix for windows * evallffi: `cannot import` errmsg now also shows which library it tried to import symbol from refs #8391 std/os now shows runtime context for raiseOSError exceptions (#13294) * refs #8391: fix errmsg for setCurrentDir * raiseOSError calls for copyFile * refs #8391 std/os now shows runtime context for raiseOSError exceptions build_all.sh: building csources 5X faster thanks to make -j (#13300) * build_all.sh: building csources 5X faster thanks to make -j * fix for freebsd * use OS-dependent formula to get number of logical cores * make is an optional dependency Fix capture for object types (#13315) * Fix capture for object|tuple|... types * Add test case Quote nim executable before executing. (#13316) [backport] In case nim executable is located in PATH containing spaces. fixes #13311 ReSync with devel Make build_all.sh more portable and a bit simpler (#13308) koch: enable checks in the compiler when running CI (#13323) fix #13132 tnetdial (#13318) enable testing -d:nimHasLibFFI mode (#13091) Fix #10717, fix #13284 (#13307) Fixed codegen for constant cstring with --gc:arc (#13326) * Fixed codegen for constant cstring with --gc:arc, fixes #13321 * Added test for #13321 Option to allow the request body to be processed outside the asynchttpserver library. (#13147) Allow the request body to be processed outside the asynchttpserver library to break big files into chunks of data. This change does not break anything. build_all.sh update (#13320) * Don't overload the system, don't crash when you can't determine the CPU count and don't rely on bash * Extract to variable * Limit number of spawned jobs for systems with weak IO * Use proper arithmetic braces contributing.rst: Add a special rule for 'outplace'-like features [backport] -d:danger should imply -d:release (#13336) nim secret: support linenoise when available (#13328) fix #13150 `nim doc --project` now works reliably (#13223) * fix #13150 `nim doc --project` works with duplicate names and with imports below main project file * add to help; fixup after #13212 isRelativeTo got merged * fix test tests/compilerapi/tcompilerapi.nim * remove nimblePkg field; compute on the fly instead * kochdocs: compiler docs now under compiler/ * --docRoot now has smart default: best among @pkg, @path make monotimes have zero overhead if you don't use it (#13338) [backport] fix #13349 regression: isNamedTuple now works with generic tuples (#13350) fixes #13269 (#13344) adding sqlite3 backup functions (#13346) * adding sqlite3 backup functions * changing sleep to sqlite3_sleep to prevent clashes Added a basic example how to handle a Post request. (#13339) * Added a basic example how to handle a Post request. They were also made minor cosmetic changes. * Minor fixes suggested by Yardanico * Fixed a wrong value in chunkSize constant. * Re-added the request.body for compatibility! replace old problematic isNamedTuple implementation by TypeTrait isNamedTuple in dollars.nim (#13347) * replace old problematic isNamedTuple implementation by TypeTrait isNamedTuple * fix for bootstrap fix #13182: `proc fun(a: varargs[Foo, conv])` now can be overloaded (#13345) [backport] miscellaneous bug fixes (part 3) (#13304) * fix deprecation; fix indentation * git clone: use -q * fix Warning: pragma before generic parameter list is deprecated; fix typo * bugfix: sysTypeFromName("float64") was never cached testament: introduce 'matrix' for testing multiple options (#13343) printing float values will have one more digit. (#13276) [backport] * printing float values will have one more digit. Fixes #13196 [backport] fix #13352 [backport] remove 'CountTable.mget' (#13355) It didn't work, and it was an oversight to be included in v1.0. fix #6736: templates in unittest now show actual value (#13354) Revert "printing float values will have one more digit. (#13276) [backport]" (#13363) This reverts commit b2c6db97f9f477f6999fa9c7aae5e32f10b6b3fe. Add sideEffect pragma to importC procs in posix, winlean and time module (#13370) * Add sideEffect pragma to procs in winlean * Add sideEffect pragma to procs in posix * Add test for #13306 * Add sideEffect pragma to procs in times * Fixes #13306 fixes #3339 by documenting the limitations of case-statement (#13366) fixes #13314 (#13372) testament: this now works: "testament r /abspath/to/test.nim" (#13358) fix `is` with generic types; fix `genericHead(Foo[T])` (#13303) * fix #9855, fix #9855, fix genericHead * render TTypeKind via toHumanStr fix #13255 (#13275) [backport] remove outplace version of 'merge' for CountTables (#13377) * remove outplace version of 'merge' for CountTables * remove 'merge' tests fix #13374 `nim c -r -` now generates $nimcache/stdinfile (#13380) [backport] fix #9634 don't crash on execCmdEx/readLine when inside gdb/lldb (#13232) * fix #9634 debugging a program using execCmdEx now works * only apply EINTR to c_gets for now This reverts commit c0f5305b5a0b46983dfd27e3d77ecbf4f8744dcc. lib.rst: add a link for jsconsole [backport] (#13383) Make vccexe parse response files (#13329) expectLen now shows the length that we got (#13387) fix several bugs with `repr` (#13386) fixes #13378 [backport] (#13392) remove dead code test_nimhcr_integration.(bat,sh) (#13388) * enable test for osx: import tests/dll/nimhcr_integration * re-disable osx test fix linenoise regression (#13395) * fix nightlies linenoise regression * fix other installers Revert "remove dead code test_nimhcr_integration.(bat,sh) (#13388)" (#13396) This reverts commit 90491ea0a98aaca198bebf3ce99a1f86559f18ec. fixes #13368 (#13397) fix bug in int128 (#13403) isolate the build process from external config files (#13411) add ggplotnim to important_packages (#13206) Fix to asynchttpserver form data/body broken with #13147 (#13394) * Fix to asynchttpserver form data/body broken with #13147 * New implementation that use a interator instance of future streams * asynchttpserver now can handle chunks of data. Merge branch 'devel' of https://github.com/nim-lang/Nim into osopen Squash Commits; Peer review feedbacks https://github.com/nim-lang/Nim/pull/12901#discussion_r379694384 --- changelog.md | 1 + lib/pure/browsers.nim | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 52b202d8c..33be5da21 100644 --- a/changelog.md +++ b/changelog.md @@ -44,6 +44,7 @@ - introduced new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, `CountTable.pop`, `Table.pop` - To `strtabs.nim`, added `StringTable.clear` overload that reuses the existing mode. +- Added `browsers.osOpen` const alias for the operating system specific *"open"* command. - Added `sugar.outplace` for turning in-place algorithms like `sort` and `shuffle` into operations that work on a copy of the data and return the mutated copy. As the existing `sorted` does. diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 3f2045c3b..ee302f950 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -19,6 +19,11 @@ when defined(windows): else: import os, osproc +const osOpenCmd* = + when defined(macos) or defined(windows): "open" else: "xdg-open" ## \ + ## Alias for the operating system specific *"open"* command, + ## ``"open"`` on MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc. + proc openDefaultBrowser*(url: string) = ## opens `url` with the user's default browser. This does not block. ## @@ -29,14 +34,14 @@ proc openDefaultBrowser*(url: string) = ## ## This proc doesn't raise an exception on error, beware. when defined(windows): - var o = newWideCString("open") + var o = newWideCString(osOpenCmd) var u = newWideCString(url) discard shellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL) elif defined(macosx): - discard execShellCmd("open " & quoteShell(url)) + discard execShellCmd(osOpenCmd & " " & quoteShell(url)) else: var u = quoteShell(url) - if execShellCmd("xdg-open " & u) == 0: return + if execShellCmd(osOpenCmd & " " & u) == 0: return for b in getEnv("BROWSER").string.split(PathSep): try: # we use ``startProcess`` here because we don't want to block! From 006fe4cfc4b07b7a2eac4cdfeacf7501667a3200 Mon Sep 17 00:00:00 2001 From: Khronos <39792509+Khronos31@users.noreply.github.com> Date: Mon, 17 Feb 2020 08:39:19 +0900 Subject: [PATCH 0011/4254] Fix vertical tab in JSON. (#13399) '\v' is not injected in JSON anymore --- lib/pure/json.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 319a7b7ff..cb02eb83c 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -586,7 +586,7 @@ proc escapeJsonUnquoted*(s: string; result: var string) = of '\b': result.add("\\b") of '\f': result.add("\\f") of '\t': result.add("\\t") - of '\v': result.add("\\v") + of '\v': result.add("\\u000b") of '\r': result.add("\\r") of '"': result.add("\\\"") of '\0'..'\7': result.add("\\u000" & $ord(c)) From 73553621a11f043bad9cc18cfde525709c49ad7e Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Mon, 17 Feb 2020 09:00:25 +0100 Subject: [PATCH 0012/4254] Improved assertion error messages on usage of JsonNode iterators on wrong kinds (#13389) --- lib/pure/json.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index cb02eb83c..82923ced0 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -739,33 +739,33 @@ proc `$`*(node: JsonNode): string = iterator items*(node: JsonNode): JsonNode = ## Iterator for the items of `node`. `node` has to be a JArray. - assert node.kind == JArray + assert node.kind == JArray, ": items() can not iterate a JsonNode of kind " & $node.kind for i in items(node.elems): yield i iterator mitems*(node: var JsonNode): var JsonNode = ## Iterator for the items of `node`. `node` has to be a JArray. Items can be ## modified. - assert node.kind == JArray + assert node.kind == JArray, ": mitems() can not iterate a JsonNode of kind " & $node.kind for i in mitems(node.elems): yield i iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] = ## Iterator for the child elements of `node`. `node` has to be a JObject. - assert node.kind == JObject + assert node.kind == JObject, ": pairs() can not iterate a JsonNode of kind " & $node.kind for key, val in pairs(node.fields): yield (key, val) iterator keys*(node: JsonNode): string = ## Iterator for the keys in `node`. `node` has to be a JObject. - assert node.kind == JObject + assert node.kind == JObject, ": keys() can not iterate a JsonNode of kind " & $node.kind for key in node.fields.keys: yield key iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] = ## Iterator for the child elements of `node`. `node` has to be a JObject. ## Values can be modified - assert node.kind == JObject + assert node.kind == JObject, ": mpairs() can not iterate a JsonNode of kind " & $node.kind for key, val in mpairs(node.fields): yield (key, val) From 8f73753a2ddd65c4016510d8472cf63d614ee0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=E3=81=AA=E4=BA=BA=EF=BC=88N=20na=20hito=EF=BC=89?= Date: Tue, 18 Feb 2020 02:40:39 +0900 Subject: [PATCH 0013/4254] Update LICENSE (#13421) --- copying.txt | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/copying.txt b/copying.txt index d2bf9a7a7..a7ba3143f 100644 --- a/copying.txt +++ b/copying.txt @@ -1,7 +1,7 @@ ===================================================== Nim -- a Compiler for Nim. https://nim-lang.org/ -Copyright (C) 2006-2018 Andreas Rumpf. All rights reserved. +Copyright (C) 2006-2020 Andreas Rumpf. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index 2c941af84..59107af34 100644 --- a/readme.md +++ b/readme.md @@ -188,7 +188,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2019 Andreas Rumpf, all rights reserved. +Copyright © 2006-2020 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org From 046bb0b881b1e4917fd0ff230f9d716d31f1f20c Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 18 Feb 2020 18:43:26 +0000 Subject: [PATCH 0014/4254] stdlib/system: add sink and move (#13283) --- lib/system.nim | 136 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 44 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 92470fbce..433829c3c 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -406,7 +406,7 @@ when defined(nimArrIdx): proc `[]`*[I: Ordinal;T](a: T; i: I): T {. noSideEffect, magic: "ArrGet".} proc `[]=`*[I: Ordinal;T,S](a: T; i: I; - x: S) {.noSideEffect, magic: "ArrPut".} + x: sink S) {.noSideEffect, magic: "ArrPut".} proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} proc arrGet[I: Ordinal;T](a: T; i: I): T {. @@ -427,7 +427,7 @@ type b*: U ## The upper bound (inclusive). Slice*[T] = HSlice[T, T] ## An alias for ``HSlice[T, T]``. -proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} = +proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} = ## Binary `slice`:idx: operator that constructs an interval ``[a, b]``, both `a` ## and `b` are inclusive. ## @@ -439,7 +439,7 @@ proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDo ## echo a[2 .. 3] # @[30, 40] result = HSlice[T, U](a: a, b: b) -proc `..`*[T](b: T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} = +proc `..`*[T](b: sink T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} = ## Unary `slice`:idx: operator that constructs an interval ``[default(int), b]``. ## ## .. code-block:: Nim @@ -1242,7 +1242,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = else: defaultImpl() -proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} = +proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} = ## Inserts `item` into `x` at position `i`. ## ## .. code-block:: Nim @@ -1525,48 +1525,96 @@ proc `@`*[T](a: openArray[T]): seq[T] = newSeq(result, a.len) for i in 0..a.len-1: result[i] = a[i] -proc `&`*[T](x, y: seq[T]): seq[T] {.noSideEffect.} = - ## Concatenates two sequences. - ## - ## Requires copying of the sequences. - ## - ## See also: - ## * `add(var seq[T], openArray[T]) <#add,seq[T][T],openArray[T]>`_ - ## - ## .. code-block:: Nim - ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) - newSeq(result, x.len + y.len) - for i in 0..x.len-1: - result[i] = x[i] - for i in 0..y.len-1: - result[i+x.len] = y[i] -proc `&`*[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = - ## Appends element y to the end of the sequence. - ## - ## Requires copying of the sequence. - ## - ## See also: - ## * `add(var seq[T], T) <#add,seq[T][T],T>`_ - ## - ## .. code-block:: Nim - ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) - newSeq(result, x.len + 1) - for i in 0..x.len-1: - result[i] = x[i] - result[x.len] = y +when defined(nimSeqsV2): -proc `&`*[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = - ## Prepends the element x to the beginning of the sequence. - ## - ## Requires copying of the sequence. - ## - ## .. code-block:: Nim - ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) - newSeq(result, y.len + 1) - result[0] = x - for i in 0..y.len-1: - result[i+1] = y[i] + proc `&`*[T](x, y: sink seq[T]): seq[T] {.noSideEffect.} = + ## Concatenates two sequences. + ## + ## Requires copying of the sequences. + ## + ## See also: + ## * `add(var seq[T], openArray[T]) <#add,seq[T][T],openArray[T]>`_ + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) + newSeq(result, x.len + y.len) + for i in 0..x.len-1: + result[i] = move(x[i]) + for i in 0..y.len-1: + result[i+x.len] = move(y[i]) + + proc `&`*[T](x: sink seq[T], y: sink T): seq[T] {.noSideEffect.} = + ## Appends element y to the end of the sequence. + ## + ## Requires copying of the sequence. + ## + ## See also: + ## * `add(var seq[T], T) <#add,seq[T][T],T>`_ + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) + newSeq(result, x.len + 1) + for i in 0..x.len-1: + result[i] = move(x[i]) + result[x.len] = move(y) + + proc `&`*[T](x: sink T, y: sink seq[T]): seq[T] {.noSideEffect.} = + ## Prepends the element x to the beginning of the sequence. + ## + ## Requires copying of the sequence. + ## + ## .. code-block:: Nim + ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) + newSeq(result, y.len + 1) + result[0] = move(x) + for i in 0..y.len-1: + result[i+1] = move(y[i]) + +else: + + proc `&`*[T](x, y: seq[T]): seq[T] {.noSideEffect.} = + ## Concatenates two sequences. + ## + ## Requires copying of the sequences. + ## + ## See also: + ## * `add(var seq[T], openArray[T]) <#add,seq[T][T],openArray[T]>`_ + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) + newSeq(result, x.len + y.len) + for i in 0..x.len-1: + result[i] = x[i] + for i in 0..y.len-1: + result[i+x.len] = y[i] + + proc `&`*[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = + ## Appends element y to the end of the sequence. + ## + ## Requires copying of the sequence. + ## + ## See also: + ## * `add(var seq[T], T) <#add,seq[T][T],T>`_ + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) + newSeq(result, x.len + 1) + for i in 0..x.len-1: + result[i] = x[i] + result[x.len] = y + + proc `&`*[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = + ## Prepends the element x to the beginning of the sequence. + ## + ## Requires copying of the sequence. + ## + ## .. code-block:: Nim + ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) + newSeq(result, y.len + 1) + result[0] = x + for i in 0..y.len-1: + result[i+1] = y[i] proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} From d1f9f11245a29f00bfa8cd86f9b4eb4ab0963a15 Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 18 Feb 2020 18:44:54 +0000 Subject: [PATCH 0015/4254] manual: documents changes regarding dynlib (#13425) * manual: documents changes regarding dynlib Closes #13416 * manual: clean up sentence phrasing --- changelog.md | 4 +++- doc/manual.rst | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 33be5da21..ad18bec6b 100644 --- a/changelog.md +++ b/changelog.md @@ -32,7 +32,9 @@ - Implicit conversions for `const` behave correctly now, meaning that code like `const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now. Simply write `const SOMECONST = 0` instead. - +- The `{.dynlib.}` pragma is now required for exporting symbols when making + shared objects on POSIX and macOS, which make it consistent with the behavior + on Windows. ## Library additions diff --git a/doc/manual.rst b/doc/manual.rst index 2f5673684..b31458fc4 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7224,6 +7224,9 @@ The string literal passed to ``exportc`` can be a format string: In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. +If the symbol should also be exported to a dynamic library, the ``dynlib`` +pragma should be used in addition to the ``exportc`` pragma. See +`Dynlib pragma for export <#foreign-function-interface-dynlib-pragma-for-export>`_. Extern pragma @@ -7363,10 +7366,7 @@ conjunction with the ``exportc`` pragma: proc exportme(): int {.cdecl, exportc, dynlib.} This is only useful if the program is compiled as a dynamic library via the -``--app:lib`` command line option. This pragma only has an effect for the code -generation on the Windows target, so when this pragma is forgotten and the dynamic -library is only tested on Mac and/or Linux, there won't be an error. On Windows -this pragma adds ``__declspec(dllexport)`` to the function declaration. +``--app:lib`` command line option. From 273a93581f851d2d16d6891d7dd1d7d9edfbb4ef Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 19 Feb 2020 02:07:18 -0800 Subject: [PATCH 0016/4254] fix incorrect lenTuple implementation (#13423) --- compiler/semmagic.nim | 4 ++++ lib/pure/typetraits.nim | 15 +++++++------ tests/metatype/ttypetraits.nim | 40 ++++++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 0571032dc..1671a8a26 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -187,6 +187,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) var operand = operand.skipTypes({tyGenericInst}) let cond = operand.kind == tyTuple and operand.n != nil result = newIntNodeT(toInt128(ord(cond)), traitCall, c.graph) + of "lenTuple": + var operand = operand.skipTypes({tyGenericInst}) + assert operand.kind == tyTuple, $operand.kind + result = newIntNodeT(toInt128(operand.len), traitCall, c.graph) of "distinctBase": var arg = operand.skipTypes({tyGenericInst}) if arg.kind == tyDistinct: diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index fd729b59e..04231db09 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -71,15 +71,14 @@ proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} ## Returns base type for distinct types, works only for distinct types. ## compile time error otherwise -import std/macros -macro lenTuple*(t: tuple): int {.since: (1, 1).} = - ## Return number of elements of `t` - newLit t.len - -macro lenTuple*(t: typedesc[tuple]): int {.since: (1, 1).} = +proc lenTuple*(T: typedesc[tuple]): int {.magic: "TypeTrait", since: (1, 1).} ## Return number of elements of `T` - newLit t.len + +since (1, 1): + template lenTuple*(t: tuple): int = + ## Return number of elements of `t` + lenTuple(type(t)) since (1, 1): template get*(T: typedesc[tuple], i: static int): untyped = @@ -87,6 +86,8 @@ since (1, 1): # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` type(default(T)[i]) +import std/macros + macro genericParams*(T: typedesc): untyped {.since: (1, 1).} = ## return tuple of generic params for generic `T` runnableExamples: diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 218ffadc2..a6813ed00 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -92,7 +92,43 @@ block distinctBase: doAssert($distinctBase(typeof(b2)) == "string") doAssert($distinctBase(typeof(c2)) == "int") +block: # lenTuple + doAssert not compiles(lenTuple(int)) + + type + MyTupleType = (int,float,string) + + static: doAssert MyTupleType.lenTuple == 3 + + type + MyGenericTuple[T] = (T,int,float) + MyGenericAlias = MyGenericTuple[string] + static: doAssert MyGenericAlias.lenTuple == 3 + + type + MyGenericTuple2[T,U] = (T,U,string) + MyGenericTuple2Alias[T] = MyGenericTuple2[T,int] + + MyGenericTuple2Alias2 = MyGenericTuple2Alias[float] + static: doAssert MyGenericTuple2Alias2.lenTuple == 3 + + static: doAssert (int, float).lenTuple == 2 + static: doAssert (1, ).lenTuple == 1 + static: doAssert ().lenTuple == 0 + + let x = (1,2,) + doAssert x.lenTuple == 2 + doAssert ().lenTuple == 0 + doAssert (1,).lenTuple == 1 + doAssert (int,).lenTuple == 1 + doAssert type(x).lenTuple == 2 + doAssert type(x).default.lenTuple == 2 + type T1 = (int,float) + type T2 = T1 + doAssert T2.lenTuple == 2 + block genericParams: + type Foo[T1, T2]=object doAssert genericParams(Foo[float, string]) is (float, string) type Foo1 = Foo[float, int] @@ -103,10 +139,6 @@ block genericParams: doAssert genericParams(Foo2).get(1) is Foo1 doAssert (int,).get(0) is int doAssert (int, float).get(1) is float - static: doAssert (int, float).lenTuple == 2 - static: doAssert (1, ).lenTuple == 1 - static: doAssert ().lenTuple == 0 - ############################################## # bug 13095 From 8c22518d673cf792fa064d2d561d1c6f03b823bb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 19 Feb 2020 08:19:55 -0800 Subject: [PATCH 0017/4254] [backport] pseudorandom probing for hash collision (#13418) --- lib/pure/collections/hashcommon.nim | 87 ++++++++++++++++---- lib/pure/collections/intsets.nim | 36 ++++++--- lib/pure/collections/setimpl.nim | 23 ++---- lib/pure/collections/sets.nim | 40 +++++---- lib/pure/collections/sharedtables.nim | 6 +- lib/pure/collections/tableimpl.nim | 47 +++++------ lib/pure/collections/tables.nim | 112 +++++++++++++++----------- lib/pure/hashes.nim | 32 +------- lib/pure/testutils.nim | 15 ++++ tests/arc/trepr.nim | 2 +- tests/collections/ttables.nim | 31 ++++++- tests/collections/ttablesthreads.nim | 5 +- 12 files changed, 258 insertions(+), 178 deletions(-) create mode 100644 lib/pure/testutils.nim diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index d9a914afc..bfc09ec3c 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -18,34 +18,87 @@ when not defined(nimHasDefault): var v: T v +const freeMarker = 0 +const deletedMarker = -1 + +type UHash = uint + # hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These # two procs retain clarity of that encoding without the space cost of an enum. -proc isEmpty(hcode: Hash): bool {.inline.} = - result = hcode == 0 +proc isFilledAndValid(hcode: Hash): bool {.inline.} = + result = hcode != 0 and hcode != deletedMarker + # performance: we could use bit magic if needed proc isFilled(hcode: Hash): bool {.inline.} = result = hcode != 0 -proc nextTry(h, maxHash: Hash): Hash {.inline.} = - result = (h + 1) and maxHash -proc mustRehash(length, counter: int): bool {.inline.} = - assert(length > counter) - result = (length * 2 < counter * 3) or (length - counter < 4) +proc translateBits(a: UHash, numBitsMask: int): UHash {.inline.} = + result = (a shr numBitsMask) or (a shl (UHash.sizeof * 8 - numBitsMask)) + +proc nextTry(h, maxHash: Hash, perturb: var UHash): Hash {.inline.} = + # FACTOR between hashcommon.nextTry, intsets.nextTry + # an optimization would be to use `(h + 1) and maxHash` for a few iterations + # and then switch to the formula below, to get "best of both worlds": good + # cache locality, except when a collision cluster is detected (ie, large number + # of iterations). + const PERTURB_SHIFT = 5 # consider tying this to `numBitsMask = fastLog2(t.dataLen)` + result = cast[Hash]((5*cast[uint](h) + 1 + perturb) and cast[uint](maxHash)) + perturb = perturb shr PERTURB_SHIFT + +proc mustRehash[T](t: T): bool {.inline.} = + # FACTOR between hashcommon.mustRehash, intsets.mustRehash + let counter2 = t.counter + t.countDeleted + let length = t.dataLen + assert(length > counter2) + result = (length * 2 < counter2 * 3) or (length - counter2 < 4) # synchronize with `rightSize` + +proc rightSize*(count: Natural): int {.inline.} = + ## Return the value of `initialSize` to support `count` items. + ## + ## If more items are expected to be added, simply add that + ## expected extra amount to the parameter before calling this. + ## + ## Internally, we want `mustRehash(t) == false` for t that was just resized. + # Make sure to synchronize with `mustRehash` + result = nextPowerOfTwo(count * 3 div 2 + 4) + +template getPerturb(t: typed, hc: Hash): UHash = + # we can't use `fastLog2(dataLen(t))` because importing `bitops` would cause codegen errors + # so we use a practical value of half the bit width (eg 64 / 2 = 32 on 64bit machines) + let numBitsMask = sizeof(Hash) * 4 # ie, sizeof(Hash) * 8 / 2 + # this makes a major difference for cases like #13393; it causes the bits + # that were masked out in 1st position so they'll be masked in instead, and + # influence the recursion in nextTry earlier rather than later. + translateBits(cast[uint](hc), numBitsMask) template rawGetKnownHCImpl() {.dirty.} = if t.dataLen == 0: return -1 var h: Hash = hc and maxHash(t) # start with real hash value - while isFilled(t.data[h].hcode): - # Compare hc THEN key with boolean short circuit. This makes the common case - # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. - # It does slow down succeeding lookups by one extra Hash cmp&and..usually - # just a few clock cycles, generally worth it for any non-integer-like A. - if t.data[h].hcode == hc and t.data[h].key == key: - return h - h = nextTry(h, maxHash(t)) - result = -1 - h # < 0 => MISSING; insert idx = -1 - result + var perturb = t.getPerturb(hc) + var deletedIndex = -1 + while true: + if isFilledAndValid(t.data[h].hcode): + # Compare hc THEN key with boolean short circuit. This makes the common case + # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. + # It does slow down succeeding lookups by one extra Hash cmp&and..usually + # just a few clock cycles, generally worth it for any non-integer-like A. + # performance: we optimize this: depending on type(key), skip hc comparison + if t.data[h].hcode == hc and t.data[h].key == key: + return h + h = nextTry(h, maxHash(t), perturb) + elif t.data[h].hcode == deletedMarker: + if deletedIndex == -1: + deletedIndex = h + h = nextTry(h, maxHash(t), perturb) + else: + break + if deletedIndex == -1: + result = -1 - h # < 0 => MISSING; insert idx = -1 - result + else: + # we prefer returning a (in fact the 1st found) deleted index + result = -1 - deletedIndex proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} = rawGetKnownHCImpl() @@ -54,6 +107,8 @@ template genHashImpl(key, hc: typed) = hc = hash(key) if hc == 0: # This almost never taken branch should be very predictable. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. + elif hc == deletedMarker: + hc = 214159261 template genHash(key: typed): Hash = var res: Hash diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 8338ceaca..7ca379783 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -46,30 +46,40 @@ type IntSet* = object ## An efficient set of `int` implemented as a sparse bit set. elems: int # only valid for small numbers counter, max: int + countDeleted: int head: PTrunk data: TrunkSeq a: array[0..33, int] # profiling shows that 34 elements are enough -proc mustRehash(length, counter: int): bool {.inline.} = - assert(length > counter) - result = (length * 2 < counter * 3) or (length - counter < 4) +proc mustRehash[T](t: T): bool {.inline.} = + # FACTOR between hashcommon.mustRehash, intsets.mustRehash + let counter2 = t.counter + t.countDeleted + let length = t.max + 1 + assert length > counter2 + result = (length * 2 < counter2 * 3) or (length - counter2 < 4) -proc nextTry(h, maxHash: Hash): Hash {.inline.} = - result = ((5 * h) + 1) and maxHash +proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} = + # FACTOR between hashcommon.nextTry, intsets.nextTry + const PERTURB_SHIFT = 5 + var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT + perturb = cast[Hash](perturb2) + result = ((5*h) + 1 + perturb) and maxHash proc intSetGet(t: IntSet, key: int): PTrunk = var h = key and t.max + var perturb = key while t.data[h] != nil: if t.data[h].key == key: return t.data[h] - h = nextTry(h, t.max) + h = nextTry(h, t.max, perturb) result = nil proc intSetRawInsert(t: IntSet, data: var TrunkSeq, desc: PTrunk) = var h = desc.key and t.max + var perturb = desc.key while data[h] != nil: assert(data[h] != desc) - h = nextTry(h, t.max) + h = nextTry(h, t.max, perturb) assert(data[h] == nil) data[h] = desc @@ -84,14 +94,16 @@ proc intSetEnlarge(t: var IntSet) = proc intSetPut(t: var IntSet, key: int): PTrunk = var h = key and t.max + var perturb = key while t.data[h] != nil: if t.data[h].key == key: return t.data[h] - h = nextTry(h, t.max) - if mustRehash(t.max + 1, t.counter): intSetEnlarge(t) + h = nextTry(h, t.max, perturb) + if mustRehash(t): intSetEnlarge(t) inc(t.counter) h = key and t.max - while t.data[h] != nil: h = nextTry(h, t.max) + perturb = key + while t.data[h] != nil: h = nextTry(h, t.max, perturb) assert(t.data[h] == nil) new(result) result.next = t.head @@ -100,6 +112,7 @@ proc intSetPut(t: var IntSet, key: int): PTrunk = t.data[h] = result proc bitincl(s: var IntSet, key: int) {.inline.} = + var ret: PTrunk var t = intSetPut(s, `shr`(key, TrunkShift)) var u = key and TrunkMask t.bits[u shr IntShift] = t.bits[u shr IntShift] or @@ -393,7 +406,8 @@ proc assign*(dest: var IntSet, src: IntSet) = var it = src.head while it != nil: var h = it.key and dest.max - while dest.data[h] != nil: h = nextTry(h, dest.max) + var perturb = it.key + while dest.data[h] != nil: h = nextTry(h, dest.max, perturb) assert(dest.data[h] == nil) var n: PTrunk new(n) diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index d2d1490ff..f8950e354 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -48,7 +48,7 @@ template inclImpl() {.dirty.} = var hc: Hash var index = rawGet(s, key, hc) if index < 0: - if mustRehash(len(s.data), s.counter): + if mustRehash(s): enlarge(s) index = rawGetKnownHC(s, key, hc) rawInsert(s, s.data, key, hc, -1 - index) @@ -62,17 +62,12 @@ template containsOrInclImpl() {.dirty.} = if index >= 0: result = true else: - if mustRehash(len(s.data), s.counter): + if mustRehash(s): enlarge(s) index = rawGetKnownHC(s, key, hc) rawInsert(s, s.data, key, hc, -1 - index) inc(s.counter) -template doWhile(a, b) = - while true: - b - if not a: break - proc exclImpl[A](s: var HashSet[A], key: A): bool {.inline.} = var hc: Hash var i = rawGet(s, key, hc) @@ -82,17 +77,9 @@ proc exclImpl[A](s: var HashSet[A], key: A): bool {.inline.} = if i >= 0: result = false dec(s.counter) - while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 - var j = i # The correctness of this depends on (h+1) in nextTry, - var r = j # though may be adaptable to other simple sequences. - s.data[i].hcode = 0 # mark current EMPTY - s.data[i].key = default(type(s.data[i].key)) - doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): - i = (i + 1) and msk # increment mod table size - if isEmpty(s.data[i].hcode): # end of collision cluster; So all done - return - r = s.data[i].hcode and msk # "home" location of key@i - s.data[j] = move(s.data[i]) # data[i] will be marked EMPTY next loop + inc(s.countDeleted) + s.data[i].hcode = deletedMarker + s.data[i].key = default(type(s.data[i].key)) template dollarImpl() {.dirty.} = result = "{" diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 9dd72cb56..9f800e6d1 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -68,6 +68,7 @@ type ## before calling other procs on it. data: KeyValuePairSeq[A] counter: int + countDeleted: int type OrderedKeyValuePair[A] = tuple[ @@ -80,15 +81,13 @@ type ## <#initOrderedSet,int>`_ before calling other procs on it. data: OrderedKeyValuePairSeq[A] counter, first, last: int + countDeleted: int const defaultInitialSize* = 64 include setimpl -proc rightSize*(count: Natural): int {.inline.} - - # --------------------------------------------------------------------- # ------------------------------ HashSet ------------------------------ # --------------------------------------------------------------------- @@ -250,7 +249,7 @@ iterator items*[A](s: HashSet[A]): A = ## echo b ## # --> {(a: 1, b: 3), (a: 0, b: 4)} for h in 0 .. high(s.data): - if isFilled(s.data[h].hcode): yield s.data[h].key + if isFilledAndValid(s.data[h].hcode): yield s.data[h].key proc containsOrIncl*[A](s: var HashSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was already in `s`. @@ -342,7 +341,7 @@ proc pop*[A](s: var HashSet[A]): A = doAssertRaises(KeyError, echo s.pop) for h in 0 .. high(s.data): - if isFilled(s.data[h].hcode): + if isFilledAndValid(s.data[h].hcode): result = s.data[h].key excl(s, result) return result @@ -593,16 +592,6 @@ proc `$`*[A](s: HashSet[A]): string = ## # --> {no, esc'aping, is " provided} dollarImpl() -proc rightSize*(count: Natural): int {.inline.} = - ## Return the value of `initialSize` to support `count` items. - ## - ## If more items are expected to be added, simply add that - ## expected extra amount to the parameter before calling this. - ## - ## Internally, we want `mustRehash(rightSize(x), x) == false`. - result = nextPowerOfTwo(count * 3 div 2 + 4) - - proc initSet*[A](initialSize = defaultInitialSize): HashSet[A] {.deprecated: "Deprecated since v0.20, use 'initHashSet'".} = initHashSet[A](initialSize) @@ -634,7 +623,7 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = var idx = 0 while h >= 0: var nxt = s.data[h].next - if isFilled(s.data[h].hcode): + if isFilledAndValid(s.data[h].hcode): yieldStmt inc(idx) h = nxt @@ -868,7 +857,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool = while h >= 0 and g >= 0: var nxh = s.data[h].next var nxg = t.data[g].next - if isFilled(s.data[h].hcode) and isFilled(t.data[g].hcode): + if isFilledAndValid(s.data[h].hcode) and isFilledAndValid(t.data[g].hcode): if s.data[h].key == t.data[g].key: inc compared else: @@ -1146,10 +1135,19 @@ when isMainModule and not defined(release): b.incl(2) assert b.len == 1 - for i in 0 .. 32: - var s = rightSize(i) - if s <= i or mustRehash(s, i): - echo "performance issue: rightSize() will not elide enlarge() at ", i + block: + type FakeTable = object + dataLen: int + counter: int + countDeleted: int + + var t: FakeTable + for i in 0 .. 32: + var s = rightSize(i) + t.dataLen = s + t.counter = i + doAssert s > i and not mustRehash(t), + "performance issue: rightSize() will not elide enlarge() at: " & $i block missingOrExcl: var s = toOrderedSet([2, 3, 6, 7]) diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 1a6148752..0fbbdb3eb 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -25,6 +25,7 @@ type SharedTable*[A, B] = object ## generic hash SharedTable data: KeyValuePairSeq[A, B] counter, dataLen: int + countDeleted: int lock: Lock template maxHash(t): untyped = t.dataLen-1 @@ -32,7 +33,7 @@ template maxHash(t): untyped = t.dataLen-1 include tableimpl template st_maybeRehashPutImpl(enlarge) {.dirty.} = - if mustRehash(t.dataLen, t.counter): + if mustRehash(t): enlarge(t) index = rawGetKnownHC(t, key, hc) index = -1 - index # important to transform for mgetOrPutImpl @@ -49,9 +50,10 @@ proc enlarge[A, B](t: var SharedTable[A, B]) = for i in 0..= 0: dec(t.counter) - block outer: - while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 - var j = i # The correctness of this depends on (h+1) in nextTry, - var r = j # though may be adaptable to other simple sequences. - t.data[i].hcode = 0 # mark current EMPTY - t.data[i].key = default(type(t.data[i].key)) - t.data[i].val = default(type(t.data[i].val)) - while true: - i = (i + 1) and msk # increment mod table size - if isEmpty(t.data[i].hcode): # end of collision cluster; So all done - break outer - r = t.data[i].hcode and msk # "home" location of key@i - if not ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): - break - when defined(js): - t.data[j] = t.data[i] - else: - t.data[j] = move(t.data[i]) # data[j] will be marked EMPTY next loop + inc(t.countDeleted) + t.data[i].hcode = deletedMarker + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) + # mustRehash + enlarge not needed because counter+countDeleted doesn't change template delImpl() {.dirty.} = var hc: Hash @@ -123,8 +116,8 @@ template initImpl(result: typed, size: int) = result.last = -1 template insertImpl() = # for CountTable - if t.dataLen == 0: initImpl(t, defaultInitialSize) - if mustRehash(len(t.data), t.counter): enlarge(t) + checkIfInitialized() + if mustRehash(t): enlarge(t) ctRawInsert(t, t.data, key, val) inc(t.counter) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index a0cc73ad6..bf08eaa92 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -233,6 +233,7 @@ type ## For creating an empty Table, use `initTable proc<#initTable,int>`_. data: KeyValuePairSeq[A, B] counter: int + countDeleted: int TableRef*[A, B] = ref Table[A, B] ## Ref version of `Table<#Table>`_. ## ## For creating a new empty TableRef, use `newTable proc @@ -250,8 +251,6 @@ template dataLen(t): untyped = len(t.data) include tableimpl -proc rightSize*(count: Natural): int {.inline.} - template get(t, key): untyped = ## retrieves the value at ``t[key]``. The value can be modified. ## If ``key`` is not in ``t``, the ``KeyError`` exception is raised. @@ -267,14 +266,16 @@ template get(t, key): untyped = proc enlarge[A, B](t: var Table[A, B]) = var n: KeyValuePairSeq[A, B] - newSeq(n, len(t.data) * growthFactor) + newSeq(n, t.counter.rightSize) swap(t.data, n) + t.countDeleted = 0 for i in countup(0, high(n)): let eh = n[i].hcode - if isFilled(eh): + if isFilledAndValid(eh): var j: Hash = eh and maxHash(t) + var perturb = t.getPerturb(eh) while isFilled(t.data[j].hcode): - j = nextTry(j, maxHash(t)) + j = nextTry(j, maxHash(t), perturb) when defined(js): rawInsert(t, t.data, n[i].key, n[i].val, eh, j) else: @@ -579,15 +580,6 @@ proc `==`*[A, B](s, t: Table[A, B]): bool = equalsImpl(s, t) -proc rightSize*(count: Natural): int {.inline.} = - ## Return the value of ``initialSize`` to support ``count`` items. - ## - ## If more items are expected to be added, simply add that - ## expected extra amount to the parameter before calling this. - ## - ## Internally, we want mustRehash(rightSize(x), x) == false. - result = nextPowerOfTwo(count * 3 div 2 + 4) - proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] @@ -670,7 +662,7 @@ iterator pairs*[A, B](t: Table[A, B]): (A, B) = ## # value: [1, 5, 7, 9] let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -692,7 +684,7 @@ iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -713,7 +705,7 @@ iterator keys*[A, B](t: Table[A, B]): A = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") @@ -734,7 +726,7 @@ iterator values*[A, B](t: Table[A, B]): B = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -756,36 +748,53 @@ iterator mvalues*[A, B](t: var Table[A, B]): var B = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") +template hasKeyOrPutCache(cache, h): bool = + # using `IntSet` would be an option worth considering to avoid quadratic + # behavior in case user misuses Table with lots of duplicate keys; but it + # has overhead in the common case of small number of duplicates. + # However: when lots of duplicates are used, all operations would be slow + # anyway because the full `hash(key)` is identical for these, which makes + # `nextTry` follow the exact same path for each key, resulting in large + # collision clusters. Alternatives could involve modifying the hash/retrieval + # based on duplicate key count. + var ret = false + for hi in cache: + if hi == h: + ret = true + break + if not ret: cache.add h + ret + iterator allValues*[A, B](t: Table[A, B]; key: A): B = ## Iterates over any value in the table ``t`` that belongs to the given ``key``. ## ## Used if you have a table with duplicate keys (as a result of using ## `add proc<#add,Table[A,B],A,B>`_). ## - ## **Examples:** - ## - ## .. code-block:: - ## var a = {'a': 3, 'b': 5}.toTable - ## for i in 1..3: - ## a.add('z', 10*i) - ## echo a # {'a': 3, 'b': 5, 'z': 10, 'z': 20, 'z': 30} - ## - ## for v in a.allValues('z'): - ## echo v - ## # 10 - ## # 20 - ## # 30 - var h: Hash = genHash(key) and high(t.data) + runnableExamples: + import testutils + var a = {'a': 3, 'b': 5}.toTable + for i in 1..3: a.add('z', 10*i) + doAssert a.sortedPairs == @[('a', 3), ('b', 5), ('z', 10), ('z', 20), ('z', 30)] + doAssert sortedItems(a.allValues('z')) == @[10, 20, 30] + + let hc = genHash(key) + var h: Hash = hc and high(t.data) let L = len(t) - while isFilled(t.data[h].hcode): - if t.data[h].key == key: - yield t.data[h].val - assert(len(t) == L, "the length of the table changed while iterating over it") - h = nextTry(h, high(t.data)) + var perturb = t.getPerturb(hc) + + var num = 0 + var cache: seq[Hash] + while isFilled(t.data[h].hcode): # `isFilledAndValid` would be incorrect, see test for `allValues` + if t.data[h].hcode == hc and t.data[h].key == key: + if not hasKeyOrPutCache(cache, h): + yield t.data[h].val + assert(len(t) == L, "the length of the table changed while iterating over it") + h = nextTry(h, high(t.data), perturb) @@ -1219,6 +1228,8 @@ type ## <#initOrderedTable,int>`_. data: OrderedKeyValuePairSeq[A, B] counter, first, last: int + countDeleted: int + OrderedTableRef*[A, B] = ref OrderedTable[A, B] ## Ref version of ## `OrderedTable<#OrderedTable>`_. ## @@ -1240,7 +1251,7 @@ proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int = proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], key: A, val: B, hc: Hash, h: Hash) = - rawInsertImpl() + rawInsertImpl(t) data[h].next = -1 if t.first < 0: t.first = h if t.last >= 0: data[t.last].next = h @@ -1248,18 +1259,20 @@ proc rawInsert[A, B](t: var OrderedTable[A, B], proc enlarge[A, B](t: var OrderedTable[A, B]) = var n: OrderedKeyValuePairSeq[A, B] - newSeq(n, len(t.data) * growthFactor) + newSeq(n, t.counter.rightSize) var h = t.first t.first = -1 t.last = -1 swap(t.data, n) + t.countDeleted = 0 while h >= 0: var nxt = n[h].next let eh = n[h].hcode - if isFilled(eh): + if isFilledAndValid(eh): var j: Hash = eh and maxHash(t) + var perturb = t.getPerturb(eh) while isFilled(t.data[j].hcode): - j = nextTry(j, maxHash(t)) + j = nextTry(j, maxHash(t), perturb) rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) h = nxt @@ -2211,6 +2224,7 @@ type ## <#initCountTable,int>`_. data: seq[tuple[key: A, val: int]] counter: int + countDeleted: int isSorted: bool CountTableRef*[A] = ref CountTable[A] ## Ref version of ## `CountTable<#CountTable>`_. @@ -2223,8 +2237,10 @@ type proc ctRawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = - var h: Hash = hash(key) and high(data) - while data[h].val != 0: h = nextTry(h, high(data)) + let hc = hash(key) + var perturb = t.getPerturb(hc) + var h: Hash = hc and high(data) + while data[h].val != 0: h = nextTry(h, high(data), perturb) # TODO: handle deletedMarker data[h].key = key data[h].val = val @@ -2251,10 +2267,12 @@ proc remove[A](t: var CountTable[A], key: A) = proc rawGet[A](t: CountTable[A], key: A): int = if t.data.len == 0: return -1 - var h: Hash = hash(key) and high(t.data) # start with real hash value - while t.data[h].val != 0: + let hc = hash(key) + var perturb = t.getPerturb(hc) + var h: Hash = hc and high(t.data) # start with real hash value + while t.data[h].val != 0: # TODO: may need to handle t.data[h].hcode == deletedMarker? if t.data[h].key == key: return h - h = nextTry(h, high(t.data)) + h = nextTry(h, high(t.data), perturb) result = -1 - h # < 0 => MISSING; insert idx = -1 - result template ctget(t, key, default: untyped): untyped = diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index ac8498517..b55a7865d 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -112,38 +112,14 @@ proc hash*[T: proc](x: T): Hash {.inline.} = else: result = hash(pointer(x)) -const - prime = uint(11) - -proc hash*(x: int): Hash {.inline.} = +proc hash*(x: int|int64|uint|uint64|char|Ordinal): Hash {.inline.} = ## Efficient hashing of integers. - result = cast[Hash](cast[uint](x) * prime) - -proc hash*(x: int64): Hash {.inline.} = - ## Efficient hashing of `int64` integers. - result = cast[Hash](cast[uint](x) * prime) - -proc hash*(x: uint): Hash {.inline.} = - ## Efficient hashing of unsigned integers. - result = cast[Hash](x * prime) - -proc hash*(x: uint64): Hash {.inline.} = - ## Efficient hashing of `uint64` integers. - result = cast[Hash](cast[uint](x) * prime) - -proc hash*(x: char): Hash {.inline.} = - ## Efficient hashing of characters. - result = cast[Hash](cast[uint](ord(x)) * prime) - -proc hash*[T: Ordinal](x: T): Hash {.inline.} = - ## Efficient hashing of other ordinal types (e.g. enums). - result = cast[Hash](cast[uint](ord(x)) * prime) + cast[Hash](ord(x)) proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. - var y = x + 1.0 - result = cast[ptr Hash](addr(y))[] - + var y = x + 0.0 # for denormalization + result = hash(cast[ptr Hash](addr(y))[]) # Forward declarations before methods that hash containers. This allows # containers to contain other containers diff --git a/lib/pure/testutils.nim b/lib/pure/testutils.nim new file mode 100644 index 000000000..bdf90b616 --- /dev/null +++ b/lib/pure/testutils.nim @@ -0,0 +1,15 @@ +## Utilities to help writing tests +## +## Unstable, experimental API. + +import std/[sequtils, algorithm] + +proc sortedPairs*[T](t: T): auto = + ## helps when writing tests involving tables in a way that's robust to + ## changes in hashing functions / table implementation. + toSeq(t.pairs).sorted + +template sortedItems*(t: untyped): untyped = + ## helps when writing tests involving tables in a way that's robust to + ## changes in hashing functions / table implementation. + sorted(toSeq(t)) diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index 7a92112ed..391622ff6 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -1,7 +1,7 @@ discard """ cmd: "nim c --gc:arc $file" nimout: '''(a: true, n: doAssert) -Table[system.string, trepr.MyType](data: @[], counter: 0) +Table[system.string, trepr.MyType](data: @[], counter: 0, countDeleted: 0) nil ''' """ diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 9eccf345a..7459b3f13 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -8,7 +8,12 @@ And we get here ''' joinable: false """ -import hashes, sequtils, tables, algorithm +import hashes, sequtils, tables, algorithm, testutils + +block tableDollar: + # other tests should use `sortedPairs` to be robust to future table/hash + # implementation changes + doAssert ${1: 'a', 2: 'b'}.toTable in ["{1: 'a', 2: 'b'}", "{2: 'b', 1: 'a'}"] # test should not be joined because it takes too long. block tableadds: @@ -188,6 +193,23 @@ block ttables2: run1() echo "2" +block allValues: + var t: Table[int, string] + var key = 0 + let n = 1000 + for i in 0.. Date: Wed, 19 Feb 2020 23:02:08 +0100 Subject: [PATCH 0018/4254] Remove testutils (#13435) [backport] --- lib/pure/collections/tables.nim | 7 ++++--- lib/pure/testutils.nim | 15 --------------- tests/collections/ttables.nim | 5 ++++- tests/collections/ttablesthreads.nim | 4 +++- 4 files changed, 11 insertions(+), 20 deletions(-) delete mode 100644 lib/pure/testutils.nim diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index bf08eaa92..2e3adc6fb 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -776,11 +776,12 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B = ## `add proc<#add,Table[A,B],A,B>`_). ## runnableExamples: - import testutils + import sequtils, algorithm + var a = {'a': 3, 'b': 5}.toTable for i in 1..3: a.add('z', 10*i) - doAssert a.sortedPairs == @[('a', 3), ('b', 5), ('z', 10), ('z', 20), ('z', 30)] - doAssert sortedItems(a.allValues('z')) == @[10, 20, 30] + doAssert toSeq(a.pairs).sorted == @[('a', 3), ('b', 5), ('z', 10), ('z', 20), ('z', 30)] + doAssert sorted(toSeq(a.allValues('z'))) == @[10, 20, 30] let hc = genHash(key) var h: Hash = hc and high(t.data) diff --git a/lib/pure/testutils.nim b/lib/pure/testutils.nim deleted file mode 100644 index bdf90b616..000000000 --- a/lib/pure/testutils.nim +++ /dev/null @@ -1,15 +0,0 @@ -## Utilities to help writing tests -## -## Unstable, experimental API. - -import std/[sequtils, algorithm] - -proc sortedPairs*[T](t: T): auto = - ## helps when writing tests involving tables in a way that's robust to - ## changes in hashing functions / table implementation. - toSeq(t.pairs).sorted - -template sortedItems*(t: untyped): untyped = - ## helps when writing tests involving tables in a way that's robust to - ## changes in hashing functions / table implementation. - sorted(toSeq(t)) diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 7459b3f13..bba95c1f1 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -8,7 +8,10 @@ And we get here ''' joinable: false """ -import hashes, sequtils, tables, algorithm, testutils +import hashes, sequtils, tables, algorithm + +proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted +template sortedItems(t: untyped): untyped = sorted(toSeq(t)) block tableDollar: # other tests should use `sortedPairs` to be robust to future table/hash diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim index 757a8cebe..9f7d77719 100644 --- a/tests/collections/ttablesthreads.nim +++ b/tests/collections/ttablesthreads.nim @@ -3,7 +3,9 @@ discard """ output: '''true''' """ -import hashes, tables, sharedtables, testutils +import hashes, tables, sharedtables, algorithm, sequtils + +proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted const data = { From 479f4ca6a3d02a85eb26243403ada518b341f430 Mon Sep 17 00:00:00 2001 From: Manav Date: Thu, 20 Feb 2020 19:46:19 +0530 Subject: [PATCH 0019/4254] Fixed non-working examples in Manual: Exception Handling (#13424) --- doc/manual.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index b31458fc4..ba13f2f02 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4106,6 +4106,8 @@ needs to fit the types of ``except`` branches, but the type of the ``finally`` branch always has to be ``void``: .. code-block:: nim + from strutils import parseInt + let x = try: parseInt("133a") except: -1 finally: echo "hi" @@ -4220,7 +4222,7 @@ Raise statement Example: .. code-block:: nim - raise newEOS("operating system failed") + raise newException(IOError, "IO failed") Apart from built-in operations like array indexing, memory allocation, etc. the ``raise`` statement is the only way to raise an exception. From bb777fef76057d594e48848693b7032b3b97068a Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Thu, 20 Feb 2020 13:15:34 -0500 Subject: [PATCH 0020/4254] Add `sequtils.unzip` to complement `sequtils.zip` (#13429) --- changelog.md | 2 +- lib/pure/collections/sequtils.nim | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index ad18bec6b..ce47249a8 100644 --- a/changelog.md +++ b/changelog.md @@ -61,7 +61,7 @@ - Added `wrapnils` module for chains of field-access and indexing where the LHS can be nil. This simplifies code by reducing need for if-else branches around intermediate maybe nil values. E.g. `echo ?.n.typ.kind` -- Added `minIndex` and `maxIndex` to the `sequtils` module +- Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. - Added `os.isRelativeTo` to tell whether a path is relative to another - Added `resetOutputFormatters` to `unittest` diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index d56742ba9..ac2201377 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -281,6 +281,21 @@ when (NimMajor, NimMinor) <= (1, 0): else: zipImpl(s1, s2, seq[(S, T)]) +proc unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = + ## Returns a tuple of two sequences split out from a sequence of 2-field tuples. + runnableExamples: + let + zipped = @[(1, 'a'), (2, 'b'), (3, 'c')] + unzipped1 = @[1, 2, 3] + unzipped2 = @['a', 'b', 'c'] + assert zipped.unzip() == (unzipped1, unzipped2) + assert zip(unzipped1, unzipped2).unzip() == (unzipped1, unzipped2) + result[0] = newSeqOfCap[S](s.len) + result[1] = newSeqOfCap[T](s.len) + for elem in s: + result[0].add(elem[0]) + result[1].add(elem[1]) + proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = ## Splits and distributes a sequence `s` into `num` sub-sequences. ## From 7a2b623d2a160f2a9a9464a29a51a343dec303ec Mon Sep 17 00:00:00 2001 From: genotrance Date: Thu, 20 Feb 2020 16:04:48 -0600 Subject: [PATCH 0021/4254] Fix #8648 - use parent streams to avoid hang (#13445) --- compiler/extccomp.nim | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e94cf87c2..7cc43d56e 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -555,7 +555,7 @@ proc getCompileOptions(conf: ConfigRef): string = proc vccplatform(conf: ConfigRef): string = # VCC specific but preferable over the config hacks people # had to do before, see #11306 - if conf.cCompiler == ccVcc: + if conf.cCompiler == ccVcc: let exe = getConfigVar(conf, conf.cCompiler, ".exe") if "vccexe.exe" == extractFilename(exe): result = case conf.target.targetCPU @@ -845,8 +845,7 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: let exitCode = p.peekExitCode if exitCode != 0: rawMessage(conf, errGenerated, "execution of an external compiler program '" & - cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" & - p.outputStream.readAll.strip) + cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n") if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors() var res = 0 if conf.numberOfProcessors <= 1: @@ -859,13 +858,13 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: else: tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): if optListCmd in conf.globalOptions or conf.verbosity > 1: - res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath}, + res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}, conf.numberOfProcessors, afterRunEvent=runCb) elif conf.verbosity == 1: - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath}, + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, conf.numberOfProcessors, prettyCb, afterRunEvent=runCb) else: - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath}, + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, conf.numberOfProcessors, afterRunEvent=runCb) if res != 0: if conf.numberOfProcessors <= 1: From 3667fd9f426eac968c326b3dc9571b7b7e8fef67 Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 21 Feb 2020 00:53:05 -0700 Subject: [PATCH 0022/4254] Make gdb script work on mac and linux; add windows gdb script (#13453) --- bin/nim-gdb | 16 ++++++++++++---- bin/nim-gdb.bat | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 bin/nim-gdb.bat diff --git a/bin/nim-gdb b/bin/nim-gdb index 9d6f462bb..e6e3a1c49 100755 --- a/bin/nim-gdb +++ b/bin/nim-gdb @@ -5,17 +5,25 @@ set -e which nim > /dev/null || (echo "nim not in PATH"; exit 1) which gdb > /dev/null || (echo "gdb not in PATH"; exit 1) +which readlink > /dev/null || which greadlink > /dev/null || (echo "readlink not in PATH. Please install coreutils from brew if on Mac."; exit 1) + +nreadlink () { + (which greadlink > /dev/null && greadlink "$@") || (which readlink > /dev/null && readlink "$@") || echo "Readlink could not be found" +} # Find out where the pretty printer Python module is -NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim)))) +NIM_SYSROOT=$(dirname $(dirname $(nreadlink -e $(which nim)))) GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py" # Run GDB with the additional arguments that load the pretty printers # Set the environment variable `NIM_GDB` to overwrite the call to a # different/specific command (defaults to `gdb`). NIM_GDB="${NIM_GDB:-gdb}" + +# This is needed for some reason. I can't get -eval-command to work ever +echo "source $GDB_PYTHON_MODULE_PATH" > gdbcommands.txt # exec replaces the new process of bash with gdb. It is always good to # have fewer processes. -exec ${NIM_GDB} \ - -eval-command "source $GDB_PYTHON_MODULE_PATH" \ - "$@" +exec ${NIM_GDB} --command="gdbcommands.txt" "$@" + +rm gdbcommands.txt diff --git a/bin/nim-gdb.bat b/bin/nim-gdb.bat new file mode 100644 index 000000000..58b66b61f --- /dev/null +++ b/bin/nim-gdb.bat @@ -0,0 +1,16 @@ +@echo off +for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i) + +for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi) + +set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py +set @NIM_GDB=gdb.exe + +@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt + +%@NIM_GDB% --command="wingdbcommand.txt" %* + +del wingdbcommand.txt /f /q + +EXIT /B %ERRORLEVEL% +@echo on From 1d90d9816b7c2065e333a000bc0208fb6c145f10 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 21 Feb 2020 16:58:30 +0100 Subject: [PATCH 0023/4254] fixes #13444 --- lib/pure/htmlgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index eb9dd9a73..e0518f5ee 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -89,7 +89,7 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", for i in 0 ..< argsList.len: if argsList[i].kind == nnkExprEqExpr: var name = getIdent(argsList[i][0]) - if delete(req, name) or delete(opt, name): + if name.startsWith("data-") or delete(req, name) or delete(opt, name): result.add(newStrLitNode(" ")) result.add(newStrLitNode(name)) result.add(newStrLitNode("=\"")) From e05aca8734702f0ad4beb0625780d354d7168bc7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 21 Feb 2020 08:26:52 -0800 Subject: [PATCH 0024/4254] make unzip faster: seq[i]=val can be 7X faster than seq.add(elem) (#13448) --- lib/pure/collections/sequtils.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index ac2201377..e32c784c6 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -290,11 +290,11 @@ proc unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = unzipped2 = @['a', 'b', 'c'] assert zipped.unzip() == (unzipped1, unzipped2) assert zip(unzipped1, unzipped2).unzip() == (unzipped1, unzipped2) - result[0] = newSeqOfCap[S](s.len) - result[1] = newSeqOfCap[T](s.len) - for elem in s: - result[0].add(elem[0]) - result[1].add(elem[1]) + result[0] = newSeq[S](s.len) + result[1] = newSeq[T](s.len) + for i in 0.. Date: Fri, 21 Feb 2020 21:06:41 +0100 Subject: [PATCH 0025/4254] fixes #13457 (#13458) --- lib/system/strs_v2.nim | 21 +++++++++++---------- tests/destructor/tnewruntime_misc.nim | 9 ++++++++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 6f28ad237..3beb14382 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -38,14 +38,13 @@ proc resize(old: int): int {.inline.} = proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = if isLiteral(s): - if addlen > 0: - let oldP = s.p - # can't mutate a literal, so we need a fresh copy here: - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen))) - s.p.cap = s.len + addlen - if s.len > 0: - # we are about to append, so there is no need to copy the \0 terminator: - copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len) + let oldP = s.p + # can't mutate a literal, so we need a fresh copy here: + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen))) + s.p.cap = s.len + addlen + if s.len > 0: + # we are about to append, so there is no need to copy the \0 terminator: + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len) else: let oldCap = s.p.cap and not strlitFlag if s.len + addlen > oldCap: @@ -110,8 +109,10 @@ proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} = if newLen == 0: frees(s) s.p = nil - elif newLen > s.len or isLiteral(s): - prepareAdd(s, newLen - s.len) + else: + if newLen > s.len or isLiteral(s): + prepareAdd(s, newLen - s.len) + s.p.data[newLen] = '\0' s.len = newLen proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index 263ea1bd4..f6e2a6157 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -7,7 +7,8 @@ axc ... destroying GenericObj[T] GenericObj[system.int] test -(allocCount: 17, deallocCount: 15)''' +(allocCount: 17, deallocCount: 15) +3''' """ import system / ansi_c @@ -132,3 +133,9 @@ proc xx(xml: string): MyObject = discard xx("test") echo getAllocStats() - s1 + +# bug #13457 +var s = "abcde" +s.setLen(3) + +echo s.cstring.len From 1276e386fe68ab2ac359657297a1a2c570d7aefb Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sat, 22 Feb 2020 01:14:55 +0300 Subject: [PATCH 0026/4254] Consider proc as a pointer type in options (#13460) * Consider proc as a pointer type in options * Add version annotation for SomePointer having proc in options * Log procs as pointers for options in changelog --- changelog.md | 2 ++ lib/pure/options.nim | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index ce47249a8..0e0b6ce3d 100644 --- a/changelog.md +++ b/changelog.md @@ -25,6 +25,8 @@ It didn't work well together with the existing inplace version of the same proc (`tables.merge(var CountTable, CountTable)`). It was an oversight to be included in v1.0. +- `options` now treats `proc` like other pointer types, meaning `nil` proc variables + are converted to `None`. ### Breaking changes in the compiler diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 28c4e4984..dc5cfa4bf 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -58,8 +58,12 @@ import typetraits -type - SomePointer = ref | ptr | pointer +when (NimMajor, NimMinor) >= (1, 1): + type + SomePointer = ref | ptr | pointer | proc +else: + type + SomePointer = ref | ptr | pointer type Option*[T] = object @@ -74,7 +78,7 @@ type proc option*[T](val: T): Option[T] = - ## Can be used to convert a pointer type (`ptr` or `ref`) to an option type. + ## Can be used to convert a pointer type (`ptr` or `ref` or `proc`) to an option type. ## It converts `nil` to `None`. ## ## See also: @@ -482,6 +486,11 @@ when isMainModule: let tmp = option(intref) check(sizeof(tmp) == sizeof(ptr int)) + + var prc = proc (x: int): int = x + 1 + check(option(prc).isSome) + prc = nil + check(option(prc).isNone) test "none[T]": check(none[int]().isNone) From a43583f9c8771c07436ee4175e216ab802ff6165 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 22 Feb 2020 00:07:53 -0800 Subject: [PATCH 0027/4254] relativePath("foo", "foo") is now ".", not "" (#13452) --- changelog.md | 4 +++- compiler/commands.nim | 2 ++ lib/pure/os.nim | 17 ++++++++++++++--- tests/js/tos.nim | 7 +++++++ tests/stdlib/tos.nim | 12 ++++++++---- tests/test_nimscript.nims | 3 +++ 6 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 tests/js/tos.nim diff --git a/changelog.md b/changelog.md index 0e0b6ce3d..d929ea0d9 100644 --- a/changelog.md +++ b/changelog.md @@ -27,7 +27,9 @@ It was an oversight to be included in v1.0. - `options` now treats `proc` like other pointer types, meaning `nil` proc variables are converted to `None`. - +- `relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid path + and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to restore the old + behavioe ### Breaking changes in the compiler diff --git a/compiler/commands.nim b/compiler/commands.nim index ca6ef5d94..cecb07386 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -865,6 +865,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "NimMinor", "0") # always be compatible with 1.0.2 for now: defineSymbol(conf.symbols, "NimPatch", "2") + # old behaviors go here: + defineSymbol(conf.symbols, "nimOldRelativePathBehavior") else: localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 452c856a6..aff91fccb 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -65,6 +65,8 @@ when weirdTarget and defined(nimErrorProcCanHaveBody): else: {.pragma: noNimScript.} +proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.} + type ReadEnvEffect* = object of ReadIOEffect ## Effect that denotes a read ## from an environment variable. @@ -359,9 +361,13 @@ proc relativePath*(path, base: string; sep = DirSep): string {. assert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" assert relativePath("", "/users/moo", '/') == "" assert relativePath("foo", ".", '/') == "foo" + assert relativePath("foo", "foo", '/') == "." if path.len == 0: return "" - let base = if base == ".": "" else: base + var base = if base == ".": "" else: base + var path = path + path.normalizePathAux + base.normalizePathAux when doslikeFileSystem: if isAbsolute(path) and isAbsolute(base): @@ -411,6 +417,9 @@ proc relativePath*(path, base: string; sep = DirSep): string {. if not f.hasNext(path): break ff = f.next(path) + when not defined(nimOldRelativePathBehavior): + if result.len == 0: result.add "." + proc isRelativeTo*(path: string, base: string): bool {.since: (1, 1).} = ## Returns true if `path` is relative to `base`. runnableExamples: @@ -1353,7 +1362,7 @@ when not weirdTarget: raise newException(ValueError, "The specified root is not absolute: " & root) joinPath(root, path) -proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScript.} = +proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## Normalize a path. ## ## Consecutive directory separators are collapsed, including an initial double slash. @@ -1402,7 +1411,9 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScr else: path = "." -proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [], noNimScript.} = +proc normalizePathAux(path: var string) = normalizePath(path) + +proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} = ## Returns a normalized path for the current OS. ## ## See also: diff --git a/tests/js/tos.nim b/tests/js/tos.nim new file mode 100644 index 000000000..7395a0ad7 --- /dev/null +++ b/tests/js/tos.nim @@ -0,0 +1,7 @@ +static: doAssert defined(nodejs) + +import os + +block: + doAssert "./foo//./bar/".normalizedPath == "foo/bar" + doAssert relativePath(".//foo/bar", "foo") == "bar" diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 03fc1f1e9..02a449b8c 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -329,15 +329,19 @@ block ospaths: doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" doAssert relativePath("", "/users/moo", '/') == "" doAssert relativePath("foo", "", '/') == "foo" - doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: "") - doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: "") - doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: "") - doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: "") + doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".") + doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".") + doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".") + doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".") doAssert relativePath("foo", ".", '/') == "foo" doAssert relativePath(".", ".", '/') == "." doAssert relativePath("..", ".", '/') == ".." + doAssert relativePath("foo", "foo") == "." + doAssert relativePath("", "foo") == "" + doAssert relativePath("././/foo", "foo//./") == "." + when doslikeFileSystem: doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim" doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim" diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 3efbb0a4c..91b23efbf 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -22,4 +22,7 @@ import unicode import uri import macros +block: + doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath + echo "Nimscript imports are successful." From c11b91d52db77de4958a504966b353d53f6404ae Mon Sep 17 00:00:00 2001 From: Lee Matos Date: Sat, 22 Feb 2020 03:09:04 -0500 Subject: [PATCH 0028/4254] Update advopt.txt to include link to nim cache docs (#13464) --- doc/advopt.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/advopt.txt b/doc/advopt.txt index 64d7a66e3..59eab4fb9 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -49,6 +49,7 @@ Advanced options: --import:PATH add an automatically imported module --include:PATH add an automatically included module --nimcache:PATH set the path used for generated files + see also https://nim-lang.org/docs/nimc.html#compiler-usage-generated-c-code-directory -c, --compileOnly:on|off compile Nim files only; do not assemble or link --noLinking:on|off compile Nim and generated files but do not link --noMain:on|off do not generate a main procedure From 13d292786e5a43b23f9a48643744c121c244b6ed Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sat, 22 Feb 2020 22:04:46 +0300 Subject: [PATCH 0029/4254] Remove genToArray in jsgen, a PHP remnant (#13466) --- compiler/jsgen.nim | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index d63856b87..51d23662c 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1795,26 +1795,6 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = else: r.res.add("$1 || [])" % [a.res]) -proc genToArray(p: PProc; n: PNode; r: var TCompRes) = - # we map mArray to PHP's array constructor, a mild hack: - var a, b: TCompRes - r.kind = resExpr - r.res = rope("array(") - let x = skipConv(n[1]) - if x.kind == nkBracket: - for i in 0.. 0: r.res.add(", ") - gen(p, it[0], a) - gen(p, it[1], b) - r.res.add("$# => $#" % [a.rdLoc, b.rdLoc]) - else: - localError(p.config, it.info, "'toArray' needs tuple constructors") - else: - localError(p.config, x.info, "'toArray' needs an array literal") - r.res.add(")") - proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) = useMagic(p, magic) r.res.add(magic & "(") From 3dad130034e3212159dda5d61988ca2b18959b24 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 23 Feb 2020 22:22:46 +0300 Subject: [PATCH 0030/4254] fix 3 minor bugs in joinPath (see #13455) (#13462) [backport] --- changelog.md | 2 ++ lib/pure/os.nim | 3 ++- lib/pure/pathnorm.nim | 3 ++- tests/stdlib/tos.nim | 4 ++++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index d929ea0d9..5041f4d7e 100644 --- a/changelog.md +++ b/changelog.md @@ -129,3 +129,5 @@ - The `FD` variant of `selector.unregister` for `ioselector_epoll` and `ioselector_select` now properly handle the `Event.User` select event type. +- `joinPath` path normalization when `/` is the first argument works correctly: + `assert "/" / "/a" == "/a"`. Fixed the edgecase: `assert "" / "" == ""`. diff --git a/lib/pure/os.nim b/lib/pure/os.nim index aff91fccb..5bdc5e11d 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -141,6 +141,7 @@ proc joinPath*(head, tail: string): string {. when defined(posix): assert joinPath("usr", "lib") == "usr/lib" assert joinPath("usr", "") == "usr/" + assert joinPath("", "") == "" assert joinPath("", "lib") == "lib" assert joinPath("", "/lib") == "/lib" assert joinPath("usr/", "/lib") == "usr/lib" @@ -149,7 +150,7 @@ proc joinPath*(head, tail: string): string {. result = newStringOfCap(head.len + tail.len) var state = 0 addNormalizePath(head, result, state, DirSep) - if tail.len == 0: + if result.len != 0 and result[^1] notin {DirSep, AltSep} and tail.len == 0: result.add DirSep else: addNormalizePath(tail, result, state, DirSep) diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 407ec156c..3659e85e6 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -69,7 +69,8 @@ proc addNormalizePath*(x: string; result: var string; state: var int; while hasNext(it, x): let b = next(it, x) if (state shr 1 == 0) and isSlash(x, b): - result.add dirSep + if result.len == 0 or result[^1] notin {DirSep, AltSep}: + result.add dirSep state = state or 1 elif isDotDot(x, b): if (state shr 1) >= 1: diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 02a449b8c..15b82fadf 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -361,6 +361,10 @@ block ospaths: doAssert joinPath("", "lib") == "lib" doAssert joinPath("", "/lib") == unixToNativePath"/lib" doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib" + doAssert joinPath("", "") == unixToNativePath"" + doAssert joinPath("/" / "") == unixToNativePath"/" + doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c" + doAssert joinPath("foo/","") == unixToNativePath"foo/" block getTempDir: block TMPDIR: From 3e8858d6947b0607b82bbe3ed0a82053280e530f Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 24 Feb 2020 09:41:28 +0100 Subject: [PATCH 0031/4254] add more files to the ignore list, hopefully fixes nightlies on windows (#13474) --- tools/kochdocs.nim | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 09b3268d1..9017fdf69 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -232,7 +232,10 @@ compiler/ccgstmts.nim compiler/ccgthreadvars.nim compiler/ccgtrav.nim compiler/ccgtypes.nim +compiler/hlo.nim compiler/jstypes.nim +compiler/packagehandling.nim +compiler/rodimpl.nim compiler/semcall.nim compiler/semexprs.nim compiler/semfields.nim @@ -245,30 +248,33 @@ compiler/semtempl.nim compiler/semtypes.nim compiler/sizealignoffsetimpl.nim compiler/suggest.nim -compiler/packagehandling.nim -compiler/hlo.nim -compiler/rodimpl.nim -compiler/vmops.nim compiler/vmhooks.nim +compiler/vmops.nim """.splitWhitespace() # not include files but doesn't work; not included/imported anywhere; dead code? const bad = """ -compiler/debuginfo.nim compiler/canonicalizer.nim +compiler/debuginfo.nim compiler/forloops.nim """.splitWhitespace() # these cause errors even though they're imported (some of which are mysterious) const bad2 = """ +compiler/aliases.nim +compiler/ast.nim +compiler/astalgo.nim compiler/closureiters.nim -compiler/tccgen.nim +compiler/evalffi.nim compiler/lambdalifting.nim compiler/layouter.nim -compiler/evalffi.nim compiler/nimfix/nimfix.nim compiler/plugins/active.nim compiler/plugins/itersgen.nim +compiler/renderer.nim +compiler/tccgen.nim +compiler/trees.nim +compiler/types.nim """.splitWhitespace() for a in walkDirRec("compiler"): From 84e78b4ffc005de7a76ec7d05bdfd0caf56a79b1 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Mon, 24 Feb 2020 11:57:15 +0300 Subject: [PATCH 0032/4254] Minor doc change in macros, future -> sugar (#13475) [ci skip] --- lib/core/macros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index f97cd73ad..31e133090 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1471,7 +1471,7 @@ macro expandMacros*(body: typed): untyped = ## For instance, ## ## .. code-block:: nim - ## import future, macros + ## import sugar, macros ## ## let ## x = 10 From 1cf5c280e3e5111732bfcf4bba3317a99c277593 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 24 Feb 2020 02:06:39 -0800 Subject: [PATCH 0033/4254] only enable linenoise for -d:nimUseLinenoise (#13478) * only enable linenoise for -d:nimUseLinenoise * fixup --- compiler/commands.nim | 5 +++-- compiler/llstream.nim | 6 ++++-- doc/koch.rst | 2 +- doc/nimc.rst | 2 +- koch.nim | 4 ++-- tools/niminst/niminst.nim | 3 ++- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index cecb07386..638444efe 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -18,7 +18,8 @@ template bootSwitch(name, expr, userString) = bootSwitch(usedRelease, defined(release), "-d:release") bootSwitch(usedDanger, defined(danger), "-d:danger") -bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise") +# `useLinenoise` deprecated in favor of `nimUseLinenoise`, kept for backward compatibility +bootSwitch(useLinenoise, defined(nimUseLinenoise) or defined(useLinenoise), "-d:nimUseLinenoise") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") @@ -101,7 +102,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger & - usedTinyC & usedGnuReadline & usedNativeStacktrace & + usedTinyC & useLinenoise & usedNativeStacktrace & usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index b550716d6..4d9456ff0 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -12,8 +12,10 @@ import pathutils -template imp(x) = import x -const hasRstdin = compiles(imp(rdstdin)) +# support `useGnuReadline`, `useLinenoise` for backwards compatibility +const hasRstdin = (defined(nimUseLinenoise) or defined(useLinenoise) or defined(useGnuReadline)) and + not defined(windows) + when hasRstdin: import rdstdin type diff --git a/doc/koch.rst b/doc/koch.rst index 0f8434064..436e0e406 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -35,7 +35,7 @@ options: By default a debug version is created, passing this option will force a release build, which is much faster and should be preferred unless you are debugging the compiler. --d:useLinenoise +-d:nimUseLinenoise Use the linenoise library for interactive mode (not needed on Windows). After compilation is finished you will hopefully end up with the nim diff --git a/doc/nimc.rst b/doc/nimc.rst index c1c418e01..b67c05a0e 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -528,7 +528,7 @@ for further information. The Nim compiler supports an interactive mode. This is also known as a `REPL`:idx: (*read eval print loop*). If Nim has been built with the - ``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal + ``-d:nimUseLinenoise`` switch, it uses the GNU readline library for terminal input management. To start Nim in interactive mode use the command ``nim secret``. To quit use the ``quit()`` command. To determine whether an input line is an incomplete statement to be continued these rules are used: diff --git a/koch.nim b/koch.nim index e3b743c44..e3ef73acd 100644 --- a/koch.nim +++ b/koch.nim @@ -55,8 +55,8 @@ Possible Commands: nimble builds the Nimble tool Boot options: -d:release produce a release version of the compiler - -d:useLinenoise use the linenoise library for interactive mode - (not needed on Windows) + -d:nimUseLinenoise use the linenoise library for interactive mode + `nim secret` (not needed on Windows) -d:leanCompiler produce a compiler without JS codegen or documentation generator in order to use less RAM for bootstrapping diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index d821a68bb..4746f328a 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -513,7 +513,8 @@ template gatherFiles(fun, libpath, outDir) = fun(src, dst) for f in walkFiles(libpath / "lib/*.h"): copySrc(f) - copySrc(libpath / "lib/wrappers/linenoise/linenoise.h") + # commenting out for now, see discussion in https://github.com/nim-lang/Nim/pull/13413 + # copySrc(libpath / "lib/wrappers/linenoise/linenoise.h") proc srcdist(c: var ConfigData) = let cCodeDir = getOutputDir(c) / "c_code" From c444ab9a54e3f1320b69bdb6e34d79ee403cd325 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 25 Feb 2020 08:46:08 +0100 Subject: [PATCH 0034/4254] make devel green again: tnetdial still doesn't work on Travis --- tests/stdlib/tnetdial.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim index 3847a239c..7c2197e4a 100644 --- a/tests/stdlib/tnetdial.nim +++ b/tests/stdlib/tnetdial.nim @@ -2,6 +2,7 @@ discard """ cmd: "nim c --threads:on $file" exitcode: 0 output: "OK" + disabled: "travis" """ import os, net, nativesockets, asyncdispatch From db540a0223480134598fb4806c55510cdef36bf1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 25 Feb 2020 08:49:16 -0800 Subject: [PATCH 0035/4254] fix #13449 texitcode flaky on windows (#13487) --- tests/osproc/texitcode.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/osproc/texitcode.nim b/tests/osproc/texitcode.nim index 558017716..0b05ca3cb 100644 --- a/tests/osproc/texitcode.nim +++ b/tests/osproc/texitcode.nim @@ -19,5 +19,8 @@ doAssert(waitForExit(p) == QuitFailure) # make sure that first call to running() after process exit returns false p = startProcess(filename, dir) -os.sleep(500) +for j in 0..<30: # refs #13449 + os.sleep(50) + if not running(p): break doAssert(not running(p)) +doAssert(waitForExit(p) == QuitFailure) # avoid zombies From e4ed19c12fcce046d990a918800d9031706e8b66 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Tue, 25 Feb 2020 15:19:51 -0500 Subject: [PATCH 0036/4254] [backport] tut1: Update the proc overloading examples (#13497) [skip ci] --- doc/tut1.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 9b411c932..6d54d88a3 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -743,13 +743,19 @@ Overloaded procedures Nim provides the ability to overload procedures similar to C++: .. code-block:: nim - proc toString(x: int): string = ... - proc toString(x: bool): string = - if x: result = "true" - else: result = "false" + proc toString(x: int): string = + result = + if x < 0: "negative" + elif x > 0: "positive" + else: "zero" - echo toString(13) # calls the toString(x: int) proc - echo toString(true) # calls the toString(x: bool) proc + proc toString(x: bool): string = + result = + if x: "yep" + else: "nope" + + assert toString(13) == "positive" # calls the toString(x: int) proc + assert toString(true) == "yep" # calls the toString(x: bool) proc (Note that ``toString`` is usually the `$ `_ operator in Nim.) The compiler chooses the most appropriate proc for the ``toString`` From 5d2483fb648ed2bc64889b07616ac753d46e3026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Wed, 26 Feb 2020 09:51:07 +0100 Subject: [PATCH 0037/4254] fix #13479 (#13503) --- compiler/vm.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 2e65a47f4..2d4d06c41 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -580,11 +580,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcCastIntToFloat32: let rb = instr.regB ensureKind(rkFloat) - regs[ra].floatVal = cast[float32](int32(regs[rb].intVal)) + regs[ra].floatVal = cast[float32](regs[rb].intVal) of opcCastIntToFloat64: let rb = instr.regB ensureKind(rkFloat) - regs[ra].floatVal = cast[float64](int64(regs[rb].intVal)) + regs[ra].floatVal = cast[float64](regs[rb].intVal) of opcCastPtrToInt: # RENAME opcCastPtrOrRefToInt decodeBImm(rkInt) From 94b0d6bb63e354c71bf072953d27c097eb7b38ca Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 26 Feb 2020 06:01:23 -0300 Subject: [PATCH 0038/4254] Documentation staticRead maximum file size limits (#13485) --- lib/system.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index 433829c3c..69083673b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2525,6 +2525,9 @@ proc staticRead*(filename: string): string {.magic: "Slurp".} ## Compile-time `readFile `_ proc for easy ## `resource`:idx: embedding: ## + ## The maximum file size limit that ``staticRead`` and ``slurp`` can read is + ## near or equal to the *free* memory of the device you are using to compile. + ## ## .. code-block:: Nim ## const myResource = staticRead"mydatafile.bin" ## From bd90199a2fd37568a5f5a6c7c394b160b229e90c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 Feb 2020 01:26:47 -0800 Subject: [PATCH 0039/4254] fix #8312 --hints:off and --warnings:off now honored everywhere (#13489) --- compiler/ccgstmts.nim | 2 +- compiler/extccomp.nim | 2 +- compiler/hlo.nim | 4 ++-- compiler/msgs.nim | 14 ++++++-------- compiler/nim.nim | 2 +- compiler/options.nim | 6 ++++++ compiler/semexprs.nim | 2 +- compiler/sempass2.nim | 14 +++++++------- compiler/syntaxes.nim | 2 +- 9 files changed, 26 insertions(+), 22 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index b9e26789f..c430dd062 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1412,7 +1412,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = proc genStmts(p: BProc, t: PNode) = var a: TLoc - let isPush = hintExtendedContext in p.config.notes + let isPush = p.config.hasHint(hintExtendedContext) if isPush: pushInfoContext(p.config, t.info) expr(p, t, a) if isPush: popInfoContext(p.config) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 7cc43d56e..c6f062c78 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -715,7 +715,7 @@ proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var if optCompileOnly notin conf.globalOptions: cmds.add(compileCmd) let (_, name, _) = splitFile(it.cname) - prettyCmds.add(if hintCC in conf.notes: "CC: " & demanglePackageName(name) else: "") + prettyCmds.add(if conf.hasHint(hintCC): "CC: " & demanglePackageName(name) else: "") if optGenScript in conf.globalOptions: script.add(compileCmd) script.add("\n") diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 6756bdc2a..bb69a1477 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -17,7 +17,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = # awful to semcheck before macro invocation, so we don't and treat # templates and macros as immediate in this context. var rule: string - if optHints in c.config.options and hintPattern in c.config.notes: + if c.config.hasHint(hintPattern): rule = renderTree(n, {renderNoComments}) let s = n[0].sym case s.kind @@ -27,7 +27,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = result = semTemplateExpr(c, n, s, {efFromHlo}) else: result = semDirectOp(c, n, {}) - if optHints in c.config.options and hintPattern in c.config.notes: + if c.config.hasHint(hintPattern): message(c.config, orig.info, hintPattern, rule & " --> '" & renderTree(result, {renderNoComments}) & "'") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 91fad9ac1..6d1ecb2b1 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -340,7 +340,7 @@ proc log*(s: string) = close(f) proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} = - if defined(debug) or msg == errInternal or hintStackTrace in conf.notes: + if defined(debug) or msg == errInternal or conf.hasHint(hintStackTrace): {.gcsafe.}: if stackTraceAvailable() and isNil(conf.writelnHook): writeStackTrace() @@ -410,8 +410,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = color = ErrorColor of warnMin..warnMax: sev = Severity.Warning - if optWarns notin conf.options: return - if msg notin conf.notes: return + if not conf.hasWarn(msg): return writeContext(conf, unknownLineInfo) title = WarningTitle color = WarningColor @@ -419,8 +418,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - if optHints notin conf.options: return - if msg notin conf.notes: return + if not conf.hasHint(msg): return title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] @@ -500,7 +498,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, conf.m.lastError = info of warnMin..warnMax: sev = Severity.Warning - ignoreMsg = optWarns notin conf.options or msg notin conf.notes + ignoreMsg = not conf.hasWarn(msg) if not ignoreMsg: writeContext(conf, info) title = WarningTitle color = WarningColor @@ -508,7 +506,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - ignoreMsg = optHints notin conf.options or msg notin conf.notes + ignoreMsg = not conf.hasHint(msg) title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] @@ -526,7 +524,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, KindColor, `%`(KindFormat, kind)) else: styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) - if hintSource in conf.notes: + if conf.hasHint(hintSource): conf.writeSurroundingSrc(info) handleError(conf, msg, eh, s) diff --git a/compiler/nim.nim b/compiler/nim.nim index cc1dc2fe7..b916f0d85 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -93,7 +93,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = self.processCmdLineAndProjectPath(conf) if not self.loadConfigsAndRunMainCommand(cache, conf): return - if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics()) + if conf.hasHint(hintGCStats): echo(GC_getStatistics()) #echo(GC_getStatistics()) if conf.errorCounter != 0: return when hasTinyCBackend: diff --git a/compiler/options.nim b/compiler/options.nim index c39ffa792..7a7ab0bcd 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -287,6 +287,12 @@ type severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string +proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = + optHints in conf.options and note in conf.notes + +proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool = + optWarns in conf.options and note in conf.notes + proc hcrOn*(conf: ConfigRef): bool = return optHotCodeReloading in conf.globalOptions template depConfigFields*(fn) {.dirty.} = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 375ea1cb1..f75642bcb 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -990,7 +990,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = result = semExpr(c, result) proc semExprNoType(c: PContext, n: PNode): PNode = - let isPush = hintExtendedContext in c.config.notes + let isPush = c.config.hasHint(hintExtendedContext) if isPush: pushInfoContext(c.config, n.info) result = semExpr(c, n, {efWantStmt}) discardCheck(c, result, {}) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 82287c675..98ef8cf85 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -262,7 +262,7 @@ proc useVar(a: PEffects, n: PNode) = if s.guard != nil: guardGlobal(a, n, s.guard) if {sfGlobal, sfThread} * s.flags == {sfGlobal} and (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): - #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) + #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n) markGcUnsafe(a, s) markSideEffect(a, s) else: @@ -463,7 +463,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = mergeTags(tracked, tagSpec, n) if notGcSafe(s.typ) and sfImportc notin s.flags: - if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) + if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, s) if tfNoSideEffect notin s.typ.flags: markSideEffect(tracked, s) @@ -544,7 +544,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) assumeTheWorst(tracked, n, op) # assume GcUnsafe unless in its type; 'forward' does not matter: if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): - if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) + if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner): markSideEffect(tracked, a) @@ -552,7 +552,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) mergeEffects(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) if notGcSafe(op): - if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) + if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags: markSideEffect(tracked, a) @@ -584,7 +584,7 @@ proc trackCase(tracked: PEffects, n: PNode) = let stringCase = skipTypes(n[0].typ, abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString} let interesting = not stringCase and interestingCaseExpr(n[0]) and - warnProveField in tracked.config.notes + tracked.config.hasWarn(warnProveField) var inter: TIntersection = @[] var toCover = 0 for i in 1.. Date: Wed, 26 Feb 2020 01:44:23 -0800 Subject: [PATCH 0040/4254] runCI: logs now show CPU/OS/etc info to be self contained (#13486) --- koch.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/koch.nim b/koch.nim index e3ef73acd..75d504758 100644 --- a/koch.nim +++ b/koch.nim @@ -472,9 +472,14 @@ proc xtemp(cmd: string) = finally: copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe) +proc hostInfo(): string = + "hostOS: $1, hostCPU: $2, int: $3, float: $4, cpuEndian: $5, cwd: $6" % + [hostOS, hostCPU, $int.sizeof, $float.sizeof, $cpuEndian, getCurrentDir()] + proc runCI(cmd: string) = doAssert cmd.len == 0, cmd # avoid silently ignoring echo "runCI:", cmd + echo hostInfo() # note(@araq): Do not replace these commands with direct calls (eg boot()) # as that would weaken our testing efforts. when defined(posix): # appveyor (on windows) didn't run this From 0c312ad898f793d9b095197d26074e6fd7f3328d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 Feb 2020 02:25:27 -0800 Subject: [PATCH 0041/4254] fix #13455 ; joinPath(a,b) now honors trailing slashes in b (or a if b = "") (#13467) * fix #13455 ; joinPath(a,b) now honors trailing slashes in b (or a if b = "") * fix test windows --- changelog.md | 3 ++- lib/pure/os.nim | 32 +++++++++++++++++++------------- tests/stdlib/tos.nim | 29 ++++++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index 5041f4d7e..1943df634 100644 --- a/changelog.md +++ b/changelog.md @@ -29,7 +29,8 @@ are converted to `None`. - `relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid path and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to restore the old - behavioe + behavior +- `joinPath(a,b)` now honors trailing slashes in `b` (or `a` if `b` = "") ### Breaking changes in the compiler diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 5bdc5e11d..3db518273 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -122,14 +122,21 @@ proc normalizePathEnd(path: string, trailingSep = false): string = since((1, 1)): export normalizePathEnd +template endsWith(a: string, b: set[char]): bool = + a.len > 0 and a[^1] in b + +proc joinPathImpl(result: var string, state: var int, tail: string) = + let trailingSep = tail.endsWith({DirSep, AltSep}) or tail.len == 0 and result.endsWith({DirSep, AltSep}) + addNormalizePath(tail, result, state, DirSep) + normalizePathEnd(result, trailingSep=trailingSep) + proc joinPath*(head, tail: string): string {. noSideEffect, rtl, extern: "nos$1".} = ## Joins two directory names to one. ## - ## If `head` is the empty string, `tail` is returned. If `tail` is the empty - ## string, `head` is returned with a trailing path separator. If `tail` starts - ## with a path separator it will be removed when concatenated to `head`. - ## Path separators will be normalized. + ## returns normalized path concatenation of `head` and `tail`, preserving + ## whether or not `tail` has a trailing slash (or, if tail if empty, whether + ## head has one). ## ## See also: ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ @@ -140,7 +147,9 @@ proc joinPath*(head, tail: string): string {. runnableExamples: when defined(posix): assert joinPath("usr", "lib") == "usr/lib" - assert joinPath("usr", "") == "usr/" + assert joinPath("usr", "lib/") == "usr/lib/" + assert joinPath("usr", "") == "usr" + assert joinPath("usr/", "") == "usr/" assert joinPath("", "") == "" assert joinPath("", "lib") == "lib" assert joinPath("", "/lib") == "/lib" @@ -149,11 +158,8 @@ proc joinPath*(head, tail: string): string {. result = newStringOfCap(head.len + tail.len) var state = 0 - addNormalizePath(head, result, state, DirSep) - if result.len != 0 and result[^1] notin {DirSep, AltSep} and tail.len == 0: - result.add DirSep - else: - addNormalizePath(tail, result, state, DirSep) + joinPathImpl(result, state, head) + joinPathImpl(result, state, tail) when false: if len(head) == 0: result = tail @@ -192,7 +198,7 @@ proc joinPath*(parts: varargs[string]): string {.noSideEffect, result = newStringOfCap(estimatedLen) var state = 0 for i in 0..high(parts): - addNormalizePath(parts[i], result, state, DirSep) + joinPathImpl(result, state, parts[i]) proc `/`*(head, tail: string): string {.noSideEffect.} = ## The same as `joinPath(head, tail) proc <#joinPath,string,string>`_. @@ -206,10 +212,10 @@ proc `/`*(head, tail: string): string {.noSideEffect.} = ## * `uri./ proc `_ runnableExamples: when defined(posix): - assert "usr" / "" == "usr/" + assert "usr" / "" == "usr" assert "" / "lib" == "lib" assert "" / "/lib" == "/lib" - assert "usr/" / "/lib" == "usr/lib" + assert "usr/" / "/lib/" == "usr/lib/" assert "usr" / "lib" / "../bin" == "usr/bin" return joinPath(head, tail) diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 15b82fadf..c649749e3 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -357,14 +357,37 @@ block ospaths: doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim" doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim" - doAssert joinPath("usr", "") == unixToNativePath"usr/" + doAssert joinPath("usr", "") == unixToNativePath"usr" doAssert joinPath("", "lib") == "lib" doAssert joinPath("", "/lib") == unixToNativePath"/lib" doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib" - doAssert joinPath("", "") == unixToNativePath"" - doAssert joinPath("/" / "") == unixToNativePath"/" + doAssert joinPath("", "") == unixToNativePath"" # issue #13455 + doAssert joinPath("", "/") == unixToNativePath"/" + doAssert joinPath("/", "/") == unixToNativePath"/" + doAssert joinPath("/", "") == unixToNativePath"/" + doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case... doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c" doAssert joinPath("foo/","") == unixToNativePath"foo/" + doAssert joinPath("foo/","abc") == unixToNativePath"foo/abc" + doAssert joinPath("foo//./","abc/.//") == unixToNativePath"foo/abc/" + doAssert joinPath("foo","abc") == unixToNativePath"foo/abc" + doAssert joinPath("","abc") == unixToNativePath"abc" + + doAssert joinPath("gook/.","abc") == unixToNativePath"gook/abc" + + # controversial: inconsistent with `joinPath("gook/.","abc")` + # on linux, `./foo` and `foo` are treated a bit differently for executables + # but not `./foo/bar` and `foo/bar` + doAssert joinPath(".", "/lib") == unixToNativePath"./lib" + doAssert joinPath(".","abc") == unixToNativePath"./abc" + + # cases related to issue #13455 + doAssert joinPath("foo", "", "") == "foo" + doAssert joinPath("foo", "") == "foo" + doAssert joinPath("foo/", "") == unixToNativePath"foo/" + doAssert joinPath("foo/", ".") == "foo" + doAssert joinPath("foo", "./") == unixToNativePath"foo/" + doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/" block getTempDir: block TMPDIR: From f091b5a0ee9b5585a08e9130d3ec682a9526ef39 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Wed, 26 Feb 2020 05:41:44 -0500 Subject: [PATCH 0042/4254] xmltree: Make indentation consistent with any num of children nodes (#13482) Ref: https://forum.nim-lang.org/t/5972 --- changelog.md | 2 + lib/pure/xmltree.nim | 169 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 137 insertions(+), 34 deletions(-) diff --git a/changelog.md b/changelog.md index 1943df634..7be7a722b 100644 --- a/changelog.md +++ b/changelog.md @@ -132,3 +132,5 @@ `ioselector_select` now properly handle the `Event.User` select event type. - `joinPath` path normalization when `/` is the first argument works correctly: `assert "/" / "/a" == "/a"`. Fixed the edgecase: `assert "" / "" == ""`. +- `xmltree` now adds indentation consistently to child nodes for any number + of children nodes. diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index b23e00fdb..fbb0ab13a 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -82,7 +82,9 @@ proc newElement*(tag: string): XmlNode = var a = newElement("firstTag") a.add newElement("childTag") assert a.kind == xnElement - assert $a == "" + assert $a == """ + +""" result = newXmlNode(xnElement) result.fTag = tag @@ -207,7 +209,9 @@ proc tag*(n: XmlNode): string {.inline.} = runnableExamples: var a = newElement("firstTag") a.add newElement("childTag") - assert $a == "" + assert $a == """ + +""" assert a.tag == "firstTag" assert n.k == xnElement @@ -225,9 +229,13 @@ proc `tag=`*(n: XmlNode, tag: string) {.inline.} = runnableExamples: var a = newElement("firstTag") a.add newElement("childTag") - assert $a == "" + assert $a == """ + +""" a.tag = "newTag" - assert $a == "" + assert $a == """ + +""" assert n.k == xnElement n.fTag = tag @@ -304,11 +312,13 @@ proc insert*(father, son: XmlNode, index: int) {.inline.} = ## * `add proc <#add,XmlNode,XmlNode>`_ ## * `delete proc <#delete,XmlNode,Natural>`_ runnableExamples: - from strutils import unindent var f = newElement("myTag") f.add newElement("first") f.insert(newElement("second"), 0) - assert ($f).unindent == "\n\n\n" + assert $f == """ + + +""" assert father.k == xnElement and son.k == xnElement if len(father.s) > index: @@ -327,7 +337,9 @@ proc delete*(n: XmlNode, i: Natural) {.noSideEffect.} = f.add newElement("first") f.insert(newElement("second"), 0) f.delete(0) - assert $f == "" + assert $f == """ + +""" assert n.k == xnElement n.s.delete(i) @@ -558,11 +570,8 @@ proc escape*(s: string): string = proc addIndent(result: var string, indent: int, addNewLines: bool) = if addNewLines: result.add("\n") - for i in 1..indent: result.add(' ') - -proc noWhitespace(n: XmlNode): bool = - for i in 0..n.len-1: - if n[i].kind in {xnText, xnEntity}: return true + for i in 1 .. indent: + result.add(' ') proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2, addNewLines = true) = @@ -578,6 +587,10 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2, s.add(b) assert s == "my text" + proc noWhitespace(n: XmlNode): bool = + for i in 0 ..< n.len: + if n[i].kind in {xnText, xnEntity}: return true + proc addEscapedAttr(result: var string, s: string) = # `addEscaped` alternative with less escaped characters. # Only to be used for escaping attribute values enclosed in double quotes! @@ -590,8 +603,18 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2, else: result.add(c) if n == nil: return + case n.k of xnElement: + if indent > 0: + result.addIndent(indent, addNewLines) + + let + addNewLines = if n.noWhitespace(): + false + else: + addNewLines + result.add('<') result.add(n.fTag) if not isNil(n.fAttr): @@ -601,27 +624,26 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2, result.add("=\"") result.addEscapedAttr(val) result.add('"') - if n.len > 0: - result.add('>') - if n.len > 1: - if noWhitespace(n): - # for mixed leaves, we cannot output whitespace for readability, - # because this would be wrong. For example: ``ab`` is - # different from ``a b``. - for i in 0..n.len-1: - result.add(n[i], indent+indWidth, indWidth, addNewLines) - else: - for i in 0..n.len-1: - result.addIndent(indent+indWidth, addNewLines) - result.add(n[i], indent+indWidth, indWidth, addNewLines) - result.addIndent(indent, addNewLines) - else: - result.add(n[0], indent+indWidth, indWidth, addNewLines) - result.add("") - else: + + if n.len == 0: result.add(" />") + return + + let + indentNext = if n.noWhitespace(): + indent + else: + indent+indWidth + result.add('>') + for i in 0 ..< n.len: + result.add(n[i], indentNext, indWidth, addNewLines) + + if not n.noWhitespace(): + result.addIndent(indent, addNewLines) + + result.add("") of xnText: result.addEscaped(n.fText) of xnComment: @@ -759,5 +781,84 @@ macro `<>`*(x: untyped): untyped = when isMainModule: - assert """Nim rules.""" == - $(<>a(href = "http://nim-lang.org", newText("Nim rules."))) + var + x: XmlNode + + x = <>a(href = "http://nim-lang.org", newText("Nim rules.")) + assert $x == """Nim rules.""" + + x = <>outer(<>inner()) + assert $x == """ + +""" + + x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4())) + assert $x == """ + + + + + + +""" + + x = <>l0(<>l1(<>l2(<>l3(<>l4())))) + assert $x == """ + + + + + + + +""" + + x = <>l0(<>l1p1(), <>l1p2(), <>l1p3()) + assert $x == """ + + + +""" + + x = <>l0(<>l1(<>l2p1(), <>l2p2())) + assert $x == """ + + + + +""" + + x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4())) + assert $x == """ + + + + + + + + + + + + + + +""" + + let + innermost = newElement("innermost") + middle = newXmlTree("middle", [innermost]) + innermost.add newText("innermost text") + x = newXmlTree("outer", [middle]) + assert $x == """ + + innermost text + +""" + + x = newElement("myTag") + x.add newText("my text") + x.add newElement("sonTag") + x.add newEntity("my entity") + assert $x == "my text&my entity;" From d55bbefdcc9c045b3a759f566a35dfc6b9bb1354 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 26 Feb 2020 20:36:06 +0100 Subject: [PATCH 0043/4254] =?UTF-8?q?added=20operateOn=20to=20sugar.nim=20?= =?UTF-8?q?to=20give=20Nim=20the=20chaining=20mechanism=20it=20de=E2=80=A6?= =?UTF-8?q?=20(#13092)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * implemented the with stdlib module as specified in https://github.com/nim-lang/RFCs/issues/193 * change sugar.outplace to sugar.dup according to https://github.com/nim-lang/RFCs/issues/193 * changelog update --- changelog.md | 14 +++++- lib/pure/sugar.nim | 62 ++++++++++++++++----------- lib/std/private/underscored_calls.nim | 38 ++++++++++++++++ lib/std/with.nim | 58 +++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 lib/std/private/underscored_calls.nim create mode 100644 lib/std/with.nim diff --git a/changelog.md b/changelog.md index 7be7a722b..f106ac2c2 100644 --- a/changelog.md +++ b/changelog.md @@ -52,7 +52,7 @@ `CountTable.pop`, `Table.pop` - To `strtabs.nim`, added `StringTable.clear` overload that reuses the existing mode. - Added `browsers.osOpen` const alias for the operating system specific *"open"* command. -- Added `sugar.outplace` for turning in-place algorithms like `sort` and `shuffle` into +- Added `sugar.dup` for turning in-place algorithms like `sort` and `shuffle` into operations that work on a copy of the data and return the mutated copy. As the existing `sorted` does. - Added `sugar.collect` that does comprehension for seq/set/table collections. @@ -71,6 +71,18 @@ - Added `resetOutputFormatters` to `unittest` +- Added a `with` macro for easy function chaining that's available + everywhere, there is no need to concern your APIs with returning the first argument + to enable "chaining", instead use the dedicated macro `with` that + was designed for it. For example: + +```nim + + + +``` + + ## Library changes - `asynchttpserver` added an iterator that allows the request body to be read in diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index f18557e0e..047280049 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -191,31 +191,41 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} result.add(newProc(newEmptyNode(), params, body, nnkProcDef)) for arg in locals: result.add(arg) -macro outplace*[T](arg: T, call: untyped; inplaceArgPosition: static[int] = 1): T {.since: (1, 1).} = - ## Turns an `in-place`:idx: algorithm into one that works on - ## a copy and returns this copy. The second parameter is the - ## index of the calling expression that is replaced by a copy - ## of this expression. - ## **Since**: Version 1.2. - runnableExamples: - import algorithm +when (NimMajor, NimMinor) >= (1, 1): + import std / private / underscored_calls - var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert a.outplace(sort()) == sorted(a) - #Chaining: - var aCopy = a - aCopy.insert(10) + macro dup*[T](arg: T, calls: varargs[untyped]): T = + ## Turns an `in-place`:idx: algorithm into one that works on + ## a copy and returns this copy. + ## **Since**: Version 1.2. + runnableExamples: + import algorithm - doAssert a.outplace(insert(10)).outplace(sort()) == sorted(aCopy) + var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + doAssert a.dup(sort) == sorted(a) + # Chaining: + var aCopy = a + aCopy.insert(10) + + doAssert a.dup(insert(10), sort) == sorted(aCopy) + + var s1 = "abc" + var s2 = "xyz" + doAssert s1 & s2 == s1.dup(&= s2) + + result = newNimNode(nnkStmtListExpr, arg) + let tmp = genSym(nskVar, "dupResult") + result.add newVarStmt(tmp, arg) + expectKind calls, nnkArgList + let body = + if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}: + calls[0] + else: + calls + for call in body: + result.add underscoredCall(call, tmp) + result.add tmp - expectKind call, nnkCallKinds - let tmp = genSym(nskVar, "outplaceResult") - var callsons = call[0..^1] - callsons.insert(tmp, inplaceArgPosition) - result = newTree(nnkStmtListExpr, - newVarStmt(tmp, arg), - copyNimNode(call).add callsons, - tmp) proc transLastStmt(n, res, bracketExpr: NimNode): (NimNode, NimNode, NimNode) {.since: (1, 1).} = # Looks for the last statement of the last statement, etc... @@ -312,17 +322,17 @@ when isMainModule: import algorithm var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert outplace(a, sort()) == sorted(a) - doAssert a.outplace(sort()) == sorted(a) + doAssert dup(a, sort(_)) == sorted(a) + doAssert a.dup(sort) == sorted(a) #Chaining: var aCopy = a aCopy.insert(10) - doAssert a.outplace(insert(10)).outplace(sort()) == sorted(aCopy) + doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy) import random const b = @[0, 1, 2] - let c = b.outplace shuffle() + let c = b.dup shuffle() doAssert c[0] == 1 doAssert c[1] == 0 diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim new file mode 100644 index 000000000..7db25c410 --- /dev/null +++ b/lib/std/private/underscored_calls.nim @@ -0,0 +1,38 @@ + +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This is an internal helper module. Do not use. + +import macros + +proc underscoredCall*(n, arg0: NimNode): NimNode = + proc underscorePos(n: NimNode): int = + for i in 1 ..< n.len: + if n[i].eqIdent("_"): return i + return -1 + + if n.kind in nnkCallKinds: + result = copyNimNode(n) + result.add n[0] + + let u = underscorePos(n) + if u < 0: + result.add arg0 + for i in 1..n.len-1: result.add n[i] + else: + for i in 1..u-1: result.add n[i] + result.add arg0 + for i in u+1..n.len-1: result.add n[i] + else: + # handle e.g. 'x.dup(sort)' + result = newNimNode(nnkCall, n) + result.add n + result.add arg0 + diff --git a/lib/std/with.nim b/lib/std/with.nim new file mode 100644 index 000000000..1dfb67c2e --- /dev/null +++ b/lib/std/with.nim @@ -0,0 +1,58 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the ``with`` macro for easy +## function chaining. See https://github.com/nim-lang/RFCs/issues/193 +## and https://github.com/nim-lang/RFCs/issues/192 for details leading to this +## particular design. +## +## **Since** version 1.2. + +import macros, private / underscored_calls + +macro with*(arg: typed; calls: varargs[untyped]): untyped = + ## This macro provides the `chaining`:idx: of function calls. + ## It does so by patching every call in `calls` to + ## use `arg` as the first argument. + ## **This evaluates `arg` multiple times!** + runnableExamples: + var x = "yay" + with x: + add "abc" + add "efg" + doAssert x == "yayabcefg" + + var a = 44 + with a: + += 4 + -= 5 + doAssert a == 43 + + result = newNimNode(nnkStmtList, arg) + expectKind calls, nnkArgList + let body = + if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}: + calls[0] + else: + calls + for call in body: + result.add underscoredCall(call, arg) + +when isMainModule: + type + Foo = object + col, pos: string + + proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) + proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) + + var f: Foo + with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) + echo f + From 9a93f73983945a44d891013f728e407ee421287b Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 26 Feb 2020 20:37:27 +0100 Subject: [PATCH 0044/4254] docgen: don't create compiler's docs + cleanup (#13509) --- tools/kochdocs.nim | 107 +++++---------------------------------------- 1 file changed, 12 insertions(+), 95 deletions(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 9017fdf69..4a07b7fd9 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -166,36 +166,19 @@ lib/posix/posix_linux_amd64_consts.nim lib/posix/posix_other_consts.nim lib/posix/posix_openbsd_amd64.nim """.splitWhitespace() - # some of these (eg lib/posix/posix_macos_amd64.nim) are include files - # but contain potentially valuable docs on OS-specific symbols (eg OSX) that - # don't end up in the main docs; we ignore these for now. when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): proc isRelativeTo(path, base: string): bool = - # pending #13212 use os.isRelativeTo let path = path.normalizedPath let base = base.normalizedPath let ret = relativePath(path, base) result = path.len > 0 and not ret.startsWith ".." proc getDocList(): seq[string] = - var t: HashSet[string] - for a in doc0: - doAssert a notin t - t.incl a - for a in withoutIndex: - doAssert a notin t, a - t.incl a - - for a in ignoredModules: - doAssert a notin t, a - t.incl a - - var t2: HashSet[string] - template myadd(a)= - result.add a - doAssert a notin t2, a - t2.incl a + var docIgnore: HashSet[string] + for a in doc0: docIgnore.incl a + for a in withoutIndex: docIgnore.incl a + for a in ignoredModules: docIgnore.incl a # don't ignore these even though in lib/system const goodSystem = """ @@ -208,81 +191,15 @@ lib/system/widestrs.nim """.splitWhitespace() for a in walkDirRec("lib"): - if a.splitFile.ext != ".nim": continue - if a.isRelativeTo("lib/pure/includes"): continue - if a.isRelativeTo("lib/genode"): continue - if a.isRelativeTo("lib/deprecated"): - if a notin @["lib/deprecated/pure/ospaths.nim"]: # REMOVE - continue - if a.isRelativeTo("lib/system"): - if a notin goodSystem: - continue - if a notin t: - result.add a - doAssert a notin t2, a - t2.incl a - - myadd "nimsuggest/sexp.nim" - # these are include files, even though some of them don't specify `included from ...` - const ignore = """ -compiler/ccgcalls.nim -compiler/ccgexprs.nim -compiler/ccgliterals.nim -compiler/ccgstmts.nim -compiler/ccgthreadvars.nim -compiler/ccgtrav.nim -compiler/ccgtypes.nim -compiler/hlo.nim -compiler/jstypes.nim -compiler/packagehandling.nim -compiler/rodimpl.nim -compiler/semcall.nim -compiler/semexprs.nim -compiler/semfields.nim -compiler/semgnrc.nim -compiler/seminst.nim -compiler/semmagic.nim -compiler/semobjconstr.nim -compiler/semstmts.nim -compiler/semtempl.nim -compiler/semtypes.nim -compiler/sizealignoffsetimpl.nim -compiler/suggest.nim -compiler/vmhooks.nim -compiler/vmops.nim -""".splitWhitespace() - - # not include files but doesn't work; not included/imported anywhere; dead code? - const bad = """ -compiler/canonicalizer.nim -compiler/debuginfo.nim -compiler/forloops.nim -""".splitWhitespace() - - # these cause errors even though they're imported (some of which are mysterious) - const bad2 = """ -compiler/aliases.nim -compiler/ast.nim -compiler/astalgo.nim -compiler/closureiters.nim -compiler/evalffi.nim -compiler/lambdalifting.nim -compiler/layouter.nim -compiler/nimfix/nimfix.nim -compiler/plugins/active.nim -compiler/plugins/itersgen.nim -compiler/renderer.nim -compiler/tccgen.nim -compiler/trees.nim -compiler/types.nim -""".splitWhitespace() - - for a in walkDirRec("compiler"): - if a.splitFile.ext != ".nim": continue - if a in ignore: continue - if a in bad: continue - if a in bad2: continue + if a.splitFile.ext != ".nim" or + a.isRelativeTo("lib/pure/includes") or + a.isRelativeTo("lib/genode") or + a.isRelativeTo("lib/deprecated") or + (a.isRelativeTo("lib/system") and a notin goodSystem) or + a in docIgnore: + continue result.add a + result.add "nimsuggest/sexp.nim" let doc = getDocList() From 42dad3a836f7eed860f300e68b33d4c0b39bd1f4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 Feb 2020 13:07:09 -0800 Subject: [PATCH 0045/4254] tables/sharedtables/intsets/etc: fix #13496, #13504, #13505; add lots of tests (#13498) [backport] * fix #13496 handle tombstones * add test * more tests * fix #13504; add SharedTable tests * fix #https://github.com/nim-lang/Nim/issues/13505 intsets.missingOrExcl silently gave wrong results sometimes * add test for tintsets --- lib/pure/collections/intsets.nim | 22 +++---- lib/pure/collections/setimpl.nim | 6 +- lib/pure/collections/sharedtables.nim | 5 ++ lib/pure/collections/tableimpl.nim | 22 +++++-- lib/pure/collections/tables.nim | 14 +++-- tests/collections/ttables.nim | 45 +++++++++++++- tests/sets/tsets_various.nim | 72 +++++++++++++++++++--- tests/stdlib/tintsets.nim | 65 ++++++++++++++++++++ tests/stdlib/tsharedtable.nim | 86 +++++++++++++++++++++++++-- 9 files changed, 296 insertions(+), 41 deletions(-) create mode 100644 tests/stdlib/tintsets.nim diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 7ca379783..1967a0149 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -330,6 +330,15 @@ proc excl*(s: var IntSet, other: IntSet) = for item in other: excl(s, item) +proc len*(s: IntSet): int {.inline.} = + ## Returns the number of elements in `s`. + if s.elems < s.a.len: + result = s.elems + else: + result = 0 + for _ in s: + inc(result) + proc missingOrExcl*(s: var IntSet, key: int): bool = ## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. ## @@ -348,9 +357,9 @@ proc missingOrExcl*(s: var IntSet, key: int): bool = assert a.missingOrExcl(5) == false assert a.missingOrExcl(5) == true - var count = s.elems + var count = s.len exclImpl(s, key) - result = count == s.elems + result = count == s.len proc clear*(result: var IntSet) = ## Clears the IntSet back to an empty state. @@ -514,15 +523,6 @@ proc disjoint*(s1, s2: IntSet): bool = return false return true -proc len*(s: IntSet): int {.inline.} = - ## Returns the number of elements in `s`. - if s.elems < s.a.len: - result = s.elems - else: - result = 0 - for _ in s: - inc(result) - proc card*(s: IntSet): int {.inline.} = ## Alias for `len() <#len,IntSet>`_. result = s.len() diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index f8950e354..f7a48ab91 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -38,7 +38,7 @@ proc enlarge[A](s: var HashSet[A]) = newSeq(n, len(s.data) * growthFactor) swap(s.data, n) # n is now old seq for i in countup(0, high(n)): - if isFilled(n[i].hcode): + if isFilledAndValid(n[i].hcode): var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode) rawInsert(s, s.data, n[i].key, n[i].hcode, j) @@ -112,7 +112,7 @@ proc enlarge[A](s: var OrderedSet[A]) = swap(s.data, n) while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): + if isFilled(n[h].hcode): # should be isFilledAndValid once tombstones are used var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode) rawInsert(s, s.data, n[h].key, n[h].hcode, j) h = nxt @@ -130,7 +130,7 @@ proc exclImpl[A](s: var OrderedSet[A], key: A): bool {.inline.} = result = true while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): + if isFilled(n[h].hcode): # should be isFilledAndValid once tombstones are used if n[h].hcode == hc and n[h].key == key: dec s.counter result = false diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 0fbbdb3eb..27ac5e84f 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -206,6 +206,11 @@ proc del*[A, B](t: var SharedTable[A, B], key: A) = withLock t: delImpl() +proc len*[A, B](t: var SharedTable[A, B]): int = + ## number of elements in `t` + withLock t: + result = t.counter + proc init*[A, B](t: var SharedTable[A, B], initialSize = 64) = ## creates a new hash table that is empty. ## diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index aabaeeeb3..d7facda72 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -107,13 +107,23 @@ template clearImpl() {.dirty.} = t.data[i].val = default(type(t.data[i].val)) t.counter = 0 +template ctAnd(a, b): bool = + # pending https://github.com/nim-lang/Nim/issues/13502 + when a: + when b: true + else: false + else: false + template initImpl(result: typed, size: int) = - assert isPowerOfTwo(size) - result.counter = 0 - newSeq(result.data, size) - when compiles(result.first): - result.first = -1 - result.last = -1 + when ctAnd(declared(SharedTable), type(result) is SharedTable): + init(result, size) + else: + assert isPowerOfTwo(size) + result.counter = 0 + newSeq(result.data, size) + when compiles(result.first): + result.first = -1 + result.last = -1 template insertImpl() = # for CountTable checkIfInitialized() diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 2e3adc6fb..131804a22 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1118,7 +1118,7 @@ iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = ## # value: [1, 5, 7, 9] let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1140,7 +1140,7 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1161,7 +1161,7 @@ iterator keys*[A, B](t: TableRef[A, B]): A = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1182,7 +1182,7 @@ iterator values*[A, B](t: TableRef[A, B]): B = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1203,7 +1203,7 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1282,6 +1282,10 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = var h = t.first while h >= 0: var nxt = t.data[h].next + # For OrderedTable/OrderedTableRef, isFilled is ok because `del` is O(n) + # and doesn't create tombsones, but if it does start using tombstones, + # carefully replace `isFilled` by `isFilledAndValid` as appropriate for these + # table types only, ditto with `OrderedSet`. if isFilled(t.data[h].hcode): yieldStmt h = nxt diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index bba95c1f1..9b7506d1a 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -173,9 +173,14 @@ block tableconstr: block ttables2: proc TestHashIntInt() = var tab = initTable[int,int]() - for i in 1..1_000_000: + when defined(nimTestsTablesDisableSlow): + # helps every single time when this test needs to be debugged + let n = 1_000 + else: + let n = 1_000_000 + for i in 1..n: tab[i] = i - for i in 1..1_000_000: + for i in 1..n: var x = tab[i] if x != i : echo "not found ", i @@ -395,3 +400,39 @@ block tablesref: orderedTableSortTest() echo "3" + +block: # https://github.com/nim-lang/Nim/issues/13496 + template testDel(body) = + block: + body + when t is CountTable|CountTableRef: + t.inc(15, 1) + t.inc(19, 2) + t.inc(17, 3) + t.inc(150, 4) + t.del(150) + else: + t[15] = 1 + t[19] = 2 + t[17] = 3 + t[150] = 4 + t.del(150) + doAssert t.len == 3 + doAssert sortedItems(t.values) == @[1, 2, 3] + doAssert sortedItems(t.keys) == @[15, 17, 19] + doAssert sortedPairs(t) == @[(15, 1), (17, 3), (19, 2)] + var s = newSeq[int]() + for v in t.values: s.add(v) + assert s.len == 3 + doAssert sortedItems(s) == @[1, 2, 3] + when t is OrderedTable|OrderedTableRef: + doAssert toSeq(t.keys) == @[15, 19, 17] + doAssert toSeq(t.values) == @[1,2,3] + doAssert toSeq(t.pairs) == @[(15, 1), (19, 2), (17, 3)] + + testDel(): (var t: Table[int, int]) + testDel(): (let t = newTable[int, int]()) + testDel(): (var t: OrderedTable[int, int]) + testDel(): (let t = newOrderedTable[int, int]()) + testDel(): (var t: CountTable[int]) + testDel(): (let t = newCountTable[int]()) diff --git a/tests/sets/tsets_various.nim b/tests/sets/tsets_various.nim index 8a63763b4..c27d8e124 100644 --- a/tests/sets/tsets_various.nim +++ b/tests/sets/tsets_various.nim @@ -7,9 +7,14 @@ set is empty import sets, hashes +from sequtils import toSeq +from algorithm import sorted + +proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted +template sortedItems(t: untyped): untyped = sorted(toSeq(t)) block tsetpop: - var a = initSet[int]() + var a = initHashSet[int]() for i in 1..1000: a.incl(i) doAssert len(a) == 1000 @@ -50,7 +55,7 @@ block tsets2: "80"] block tableTest1: - var t = initSet[tuple[x, y: int]]() + var t = initHashSet[tuple[x, y: int]]() t.incl((0,0)) t.incl((1,0)) assert(not t.containsOrIncl((0,1))) @@ -63,7 +68,7 @@ block tsets2: # "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}") block setTest2: - var t = initSet[string]() + var t = initHashSet[string]() t.incl("test") t.incl("111") t.incl("123") @@ -102,9 +107,9 @@ block tsets2: block tsets3: let - s1: HashSet[int] = toSet([1, 2, 4, 8, 16]) - s2: HashSet[int] = toSet([1, 2, 3, 5, 8]) - s3: HashSet[int] = toSet([3, 5, 7]) + s1: HashSet[int] = toHashSet([1, 2, 4, 8, 16]) + s2: HashSet[int] = toHashSet([1, 2, 3, 5, 8]) + s3: HashSet[int] = toHashSet([3, 5, 7]) block union: let @@ -172,7 +177,7 @@ block tsets3: assert i in s1_s3 xor i in s1 assert i in s2_s3 xor i in s2 - assert((s3 -+- s3) == initSet[int]()) + assert((s3 -+- s3) == initHashSet[int]()) assert((s3 -+- s1) == s1_s3) block difference: @@ -191,10 +196,61 @@ block tsets3: for i in s2: assert i in s2_s3 xor i in s3 - assert((s2 - s2) == initSet[int]()) + assert((s2 - s2) == initHashSet[int]()) block disjoint: assert(not disjoint(s1, s2)) assert disjoint(s1, s3) assert(not disjoint(s2, s3)) assert(not disjoint(s2, s2)) + +block: # https://github.com/nim-lang/Nim/issues/13496 + template testDel(body) = + block: + body + t.incl(15) + t.incl(19) + t.incl(17) + t.incl(150) + t.excl(150) + doAssert t.len == 3 + doAssert sortedItems(t) == @[15, 17, 19] + var s = newSeq[int]() + for v in t: s.add(v) + assert s.len == 3 + doAssert sortedItems(s) == @[15, 17, 19] + when t is OrderedSet: + doAssert sortedPairs(t) == @[(a: 0, b: 15), (a: 1, b: 19), (a: 2, b: 17)] + doAssert toSeq(t) == @[15, 19, 17] + + testDel(): (var t: HashSet[int]) + testDel(): (var t: OrderedSet[int]) + +block: # test correctness after a number of inserts/deletes + template testDel(body) = + block: + body + var expected: seq[int] + let n = 100 + let n2 = n*2 + for i in 0..=n or i mod 3 != 0) and i mod 7 != 0: + expected.add i + + for i in expected: doAssert i in t + doAssert t.len == expected.len + doAssert sortedItems(t) == expected + + testDel(): (var t: HashSet[int]) + testDel(): (var t: OrderedSet[int]) diff --git a/tests/stdlib/tintsets.nim b/tests/stdlib/tintsets.nim new file mode 100644 index 000000000..f859b87ae --- /dev/null +++ b/tests/stdlib/tintsets.nim @@ -0,0 +1,65 @@ +import intsets +import std/sets + +from sequtils import toSeq +from algorithm import sorted + +proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted +template sortedItems(t: untyped): untyped = sorted(toSeq(t)) + +block: # we use HashSet as groundtruth, it's well tested elsewhere + template testDel(t, t0) = + + template checkEquals() = + doAssert t.len == t0.len + for k in t0: + doAssert k in t + for k in t: + doAssert k in t0 + + doAssert sortedItems(t) == sortedItems(t0) + + template incl2(i) = + t.incl i + t0.incl i + + template excl2(i) = + t.excl i + t0.excl i + + block: + var expected: seq[int] + let n = 100 + let n2 = n*2 + for i in 0.. Date: Thu, 27 Feb 2020 01:43:13 -0800 Subject: [PATCH 0046/4254] cleanup Ordinal (#13501) --- compiler/condsyms.nim | 1 + lib/pure/hashes.nim | 2 +- lib/system.nim | 12 ++++++++++++ lib/system/arithmetics.nim | 4 ++-- lib/system/basic_types.nim | 6 +----- tests/system/tsystem_misc.nim | 17 +++++++++++++++++ tests/varres/tprevent_forloopvar_mutations.nim | 4 ++-- 7 files changed, 36 insertions(+), 10 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 344f6fd5a..d82f4811d 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -104,6 +104,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasCursor") defineSymbol("nimHasExceptionsQuery") defineSymbol("nimHasIsNamedTuple") + defineSymbol("nimHashOrdinalFixed") when defined(nimHasLibFFI): # Renaming as we can't conflate input vs output define flags; e.g. this diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index b55a7865d..52a724d7b 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -112,7 +112,7 @@ proc hash*[T: proc](x: T): Hash {.inline.} = else: result = hash(pointer(x)) -proc hash*(x: int|int64|uint|uint64|char|Ordinal): Hash {.inline.} = +proc hash*[T: Ordinal](x: T): Hash {.inline.} = ## Efficient hashing of integers. cast[Hash](ord(x)) diff --git a/lib/system.nim b/lib/system.nim index 69083673b..51ff3af40 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -87,6 +87,18 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## # Do here programmer friendly expensive sanity checks. ## # Put here the normal code +when defined(nimHashOrdinalFixed): + type + Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, + ## bool, character, and enumeration types + ## as well as their subtypes. See also + ## `SomeOrdinal`. +else: + # bootstrap <= 0.20.0 + type + OrdinalImpl[T] {.magic: Ordinal.} + Ordinal* = OrdinalImpl | uint | uint64 + when defined(nimHasRunnableExamples): proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".} ## A section you should use to mark `runnable example`:idx: code with. diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index ba9ade192..757a813e8 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -22,7 +22,7 @@ proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} ## echo pred(5) # => 4 ## echo pred(5, 3) # => 2 -proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.} +proc inc*[T: Ordinal](x: var T, y = 1) {.magic: "Inc", noSideEffect.} ## Increments the ordinal ``x`` by ``y``. ## ## If such a value does not exist, ``OverflowError`` is raised or a compile @@ -33,7 +33,7 @@ proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect. ## inc(i) # i <- 3 ## inc(i, 3) # i <- 6 -proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.} +proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} ## Decrements the ordinal ``x`` by ``y``. ## ## If such a value does not exist, ``OverflowError`` is raised or a compile diff --git a/lib/system/basic_types.nim b/lib/system/basic_types.nim index 39ad0a76c..a6bf69ebc 100644 --- a/lib/system/basic_types.nim +++ b/lib/system/basic_types.nim @@ -20,10 +20,6 @@ const off* = false ## Alias for ``false``. type - Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, - ## bool, character, and enumeration types - ## as well as their subtypes. - SomeSignedInt* = int|int8|int16|int32|int64 ## Type class matching all signed integer types. @@ -35,7 +31,7 @@ type SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint|uint8|uint16|uint32|uint64 ## Type class matching all ordinal types; however this includes enums with - ## holes. + ## holes. See also `Ordinal` BiggestInt* = int64 ## is an alias for the biggest signed integer type the Nim compiler diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 56af97f36..fff8b7022 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -193,3 +193,20 @@ block: a = {k1} b = {k1,k2} doAssert a < b + + +block: # Ordinal + doAssert int is Ordinal + doAssert uint is Ordinal + doAssert int64 is Ordinal + doAssert uint64 is Ordinal + doAssert char is Ordinal + type Foo = enum k1, k2 + doAssert Foo is Ordinal + doAssert Foo is SomeOrdinal + doAssert enum is SomeOrdinal + + # these fail: + # doAssert enum is Ordinal # fails + # doAssert Ordinal is SomeOrdinal + # doAssert SomeOrdinal is Ordinal diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index 398191658..ac62608af 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -3,9 +3,9 @@ discard """ line: 17 nimout: '''type mismatch: got but expected one of: -proc inc[T: Ordinal | uint | uint64](x: var T; y = 1) +proc inc[T: Ordinal](x: var T; y = 1) first type mismatch at position: 1 - required type for x: var T: Ordinal or uint or uint64 + required type for x: var T: Ordinal but expression 'i' is immutable, not 'var' expression: inc i From e84e01cb8cf8196ce70d9944f1262440a45e552d Mon Sep 17 00:00:00 2001 From: solo989 Date: Thu, 27 Feb 2020 02:08:57 -0800 Subject: [PATCH 0047/4254] Update pegs.nim to work at compiletime. No range errors. (#13459) --- lib/pure/pegs.nim | 328 +++++++++++++++++++++++++--------------------- 1 file changed, 175 insertions(+), 153 deletions(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 3c3941285..4f723b4af 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1420,7 +1420,7 @@ type PegLexer {.inheritable.} = object ## the lexer object. bufpos: int ## the current position within the buffer - buf: cstring ## the buffer itself + buf: string ## the buffer itself lineNumber: int ## the current line number lineStart: int ## index of last line start in buffer colOffset: int ## column to add @@ -1481,6 +1481,9 @@ proc handleHexChar(c: var PegLexer, xi: var int) = proc getEscapedChar(c: var PegLexer, tok: var Token) = inc(c.bufpos) + if c.bufpos >= len(c.buf): + tok.kind = tkInvalid + return case c.buf[c.bufpos] of 'r', 'R', 'c', 'C': add(tok.literal, '\c') @@ -1508,6 +1511,9 @@ proc getEscapedChar(c: var PegLexer, tok: var Token) = inc(c.bufpos) of 'x', 'X': inc(c.bufpos) + if c.bufpos >= len(c.buf): + tok.kind = tkInvalid + return var xi = 0 handleHexChar(c, xi) handleHexChar(c, xi) @@ -1517,7 +1523,7 @@ proc getEscapedChar(c: var PegLexer, tok: var Token) = var val = ord(c.buf[c.bufpos]) - ord('0') inc(c.bufpos) var i = 1 - while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): + while (c.bufpos < len(c.buf)) and (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): val = val * 10 + ord(c.buf[c.bufpos]) - ord('0') inc(c.bufpos) inc(i) @@ -1571,7 +1577,7 @@ proc getString(c: var PegLexer, tok: var Token) = proc getDollar(c: var PegLexer, tok: var Token) = var pos = c.bufpos + 1 - if c.buf[pos] in {'0'..'9'}: + if pos < c.buf.len and c.buf[pos] in {'0'..'9'}: tok.kind = tkBackref tok.index = 0 while pos < c.buf.len and c.buf[pos] in {'0'..'9'}: @@ -1586,54 +1592,55 @@ proc getCharSet(c: var PegLexer, tok: var Token) = tok.charset = {} var pos = c.bufpos + 1 var caret = false - if c.buf[pos] == '^': - inc(pos) - caret = true - while pos < c.buf.len: - var ch: char - case c.buf[pos] - of ']': - if pos < c.buf.len: inc(pos) - break - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - ch = tok.literal[tok.literal.len-1] - of '\C', '\L', '\0': - tok.kind = tkInvalid - break - else: - ch = c.buf[pos] + if pos < c.buf.len: + if c.buf[pos] == '^': inc(pos) - incl(tok.charset, ch) - if c.buf[pos] == '-': - if pos+1 < c.buf.len and c.buf[pos+1] == ']': - incl(tok.charset, '-') - inc(pos) + caret = true + while pos < c.buf.len: + var ch: char + case c.buf[pos] + of ']': + if pos < c.buf.len: inc(pos) + break + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + ch = tok.literal[tok.literal.len-1] + of '\C', '\L', '\0': + tok.kind = tkInvalid + break else: - if pos+1 < c.buf.len: + ch = c.buf[pos] + inc(pos) + incl(tok.charset, ch) + if c.buf[pos] == '-': + if pos+1 < c.buf.len and c.buf[pos+1] == ']': + incl(tok.charset, '-') inc(pos) - else: - break - var ch2: char - case c.buf[pos] - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - ch2 = tok.literal[tok.literal.len-1] - of '\C', '\L', '\0': - tok.kind = tkInvalid - break else: if pos+1 < c.buf.len: - ch2 = c.buf[pos] inc(pos) else: break - for i in ord(ch)+1 .. ord(ch2): - incl(tok.charset, chr(i)) + var ch2: char + case c.buf[pos] + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + ch2 = tok.literal[tok.literal.len-1] + of '\C', '\L', '\0': + tok.kind = tkInvalid + break + else: + if pos+1 < c.buf.len: + ch2 = c.buf[pos] + inc(pos) + else: + break + for i in ord(ch)+1 .. ord(ch2): + incl(tok.charset, chr(i)) c.bufpos = pos if caret: tok.charset = {'\1'..'\xFF'} - tok.charset @@ -1661,6 +1668,13 @@ proc getTok(c: var PegLexer, tok: var Token) = setLen(tok.literal, 0) skip(c) + if c.bufpos >= c.buf.len: + tok.kind = tkEof + tok.literal = "[EOF]" + add(tok.literal, '\0') + inc(c.bufpos) + return + case c.buf[c.bufpos] of '{': inc(c.bufpos) @@ -1700,6 +1714,8 @@ proc getTok(c: var PegLexer, tok: var Token) = of '$': getDollar(c, tok) of 'a'..'z', 'A'..'Z', '\128'..'\255': getSymbol(c, tok) + if c.bufpos >= c.buf.len: + return if c.buf[c.bufpos] in {'\'', '"'} or c.buf[c.bufpos] == '$' and c.bufpos+1 < c.buf.len and c.buf[c.bufpos+1] in {'0'..'9'}: @@ -1768,7 +1784,9 @@ proc arrowIsNextTok(c: PegLexer): bool = # the only look ahead we need var pos = c.bufpos while pos < c.buf.len and c.buf[pos] in {'\t', ' '}: inc(pos) - result = c.buf[pos] == '<' and (pos+1 < c.buf.len) and c.buf[pos+1] == '-' + if pos+1 >= c.buf.len: + return + result = c.buf[pos] == '<' and c.buf[pos+1] == '-' # ----------------------------- parser ---------------------------------------- @@ -2038,141 +2056,145 @@ proc escapePeg*(s: string): string = if inQuote: result.add('\'') when isMainModule: - assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" - assert match("(a b c)", peg"'(' @ ')'") - assert match("W_HI_Le", peg"\y 'while'") - assert(not match("W_HI_L", peg"\y 'while'")) - assert(not match("W_HI_Le", peg"\y v'while'")) - assert match("W_HI_Le", peg"y'while'") + proc pegsTest() = + assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" + assert match("(a b c)", peg"'(' @ ')'") + assert match("W_HI_Le", peg"\y 'while'") + assert(not match("W_HI_L", peg"\y 'while'")) + assert(not match("W_HI_Le", peg"\y v'while'")) + assert match("W_HI_Le", peg"y'while'") - assert($ +digits == $peg"\d+") - assert "0158787".match(peg"\d+") - assert "ABC 0232".match(peg"\w+\s+\d+") - assert "ABC".match(peg"\d+ / \w+") + assert($ +digits == $peg"\d+") + assert "0158787".match(peg"\d+") + assert "ABC 0232".match(peg"\w+\s+\d+") + assert "ABC".match(peg"\d+ / \w+") - var accum: seq[string] = @[] - for word in split("00232this02939is39an22example111", peg"\d+"): - accum.add(word) - assert(accum == @["this", "is", "an", "example"]) + var accum: seq[string] = @[] + for word in split("00232this02939is39an22example111", peg"\d+"): + accum.add(word) + assert(accum == @["this", "is", "an", "example"]) - assert matchLen("key", ident) == 3 + assert matchLen("key", ident) == 3 - var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) - assert matchLen("key1= cal9", pattern) == 11 + var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) + assert matchLen("key1= cal9", pattern) == 11 - var ws = newNonTerminal("ws", 1, 1) - ws.rule = *whitespace + var ws = newNonTerminal("ws", 1, 1) + ws.rule = *whitespace - var expr = newNonTerminal("expr", 1, 1) - expr.rule = sequence(capture(ident), *sequence( - nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) + var expr = newNonTerminal("expr", 1, 1) + expr.rule = sequence(capture(ident), *sequence( + nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) - var c: Captures - var s = "a+b + c +d+e+f" - assert rawMatch(s, expr.rule, 0, c) == len(s) - var a = "" - for i in 0..c.ml-1: - a.add(substr(s, c.matches[i][0], c.matches[i][1])) - assert a == "abcdef" - #echo expr.rule + var c: Captures + var s = "a+b + c +d+e+f" + assert rawMatch(s, expr.rule, 0, c) == len(s) + var a = "" + for i in 0..c.ml-1: + a.add(substr(s, c.matches[i][0], c.matches[i][1])) + assert a == "abcdef" + #echo expr.rule - #const filename = "lib/devel/peg/grammar.txt" - #var grammar = parsePeg(newFileStream(filename, fmRead), filename) - #echo "a <- [abc]*?".match(grammar) - assert find("_____abc_______", term("abc"), 2) == 5 - assert match("_______ana", peg"A <- 'ana' / . A") - assert match("abcs%%%", peg"A <- ..A / .A / '%'") + #const filename = "lib/devel/peg/grammar.txt" + #var grammar = parsePeg(newFileStream(filename, fmRead), filename) + #echo "a <- [abc]*?".match(grammar) + assert find("_____abc_______", term("abc"), 2) == 5 + assert match("_______ana", peg"A <- 'ana' / . A") + assert match("abcs%%%", peg"A <- ..A / .A / '%'") - var matches: array[0..MaxSubpatterns-1, string] - if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": - assert matches[0] == "abc" - else: - assert false + var matches: array[0..MaxSubpatterns-1, string] + if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": + assert matches[0] == "abc" + else: + assert false - var g2 = peg"""S <- A B / C D - A <- 'a'+ - B <- 'b'+ - C <- 'c'+ - D <- 'd'+ - """ - assert($g2 == "((A B) / (C D))") - assert match("cccccdddddd", g2) - assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey; var2<-key2key2") - assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "$1<-$2$2; $1<-$2$2") - assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") + var g2 = peg"""S <- A B / C D + A <- 'a'+ + B <- 'b'+ + C <- 'c'+ + D <- 'd'+ + """ + assert($g2 == "((A B) / (C D))") + assert match("cccccdddddd", g2) + assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey; var2<-key2key2") + assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "$1<-$2$2; $1<-$2$2") + assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") - if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": - assert matches[0] == "a" - else: - assert false + if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": + assert matches[0] == "a" + else: + assert false - if match("abcdefg", peg"c {d} ef {g}", matches, 2): - assert matches[0] == "d" - assert matches[1] == "g" - else: - assert false + if match("abcdefg", peg"c {d} ef {g}", matches, 2): + assert matches[0] == "d" + assert matches[1] == "g" + else: + assert false - accum = @[] - for x in findAll("abcdef", peg".", 3): - accum.add(x) - assert(accum == @["d", "e", "f"]) + accum = @[] + for x in findAll("abcdef", peg".", 3): + accum.add(x) + assert(accum == @["d", "e", "f"]) - for x in findAll("abcdef", peg"^{.}", 3): - assert x == "d" + for x in findAll("abcdef", peg"^{.}", 3): + assert x == "d" - if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": - assert matches[0] == "f" - assert matches[1] == "a, b" - else: - assert false + if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": + assert matches[0] == "f" + assert matches[1] == "a, b" + else: + assert false - assert match("eine übersicht und außerdem", peg"(\letter \white*)+") - # ß is not a lower cased letter?! - assert match("eine übersicht und auerdem", peg"(\lower \white*)+") - assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") - assert(not match("456678", peg"(\letter)+")) + assert match("eine übersicht und außerdem", peg"(\letter \white*)+") + # ß is not a lower cased letter?! + assert match("eine übersicht und auerdem", peg"(\lower \white*)+") + assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") + assert(not match("456678", peg"(\letter)+")) - assert("var1 = key; var2 = key2".replacef( - peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey;var2<-key2key2") + assert("var1 = key; var2 = key2".replacef( + peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey;var2<-key2key2") - assert match("prefix/start", peg"^start$", 7) + assert match("prefix/start", peg"^start$", 7) - if "foo" =~ peg"{'a'}?.*": - assert matches[0].len == 0 - else: assert false + if "foo" =~ peg"{'a'}?.*": + assert matches[0].len == 0 + else: assert false - if "foo" =~ peg"{''}.*": - assert matches[0] == "" - else: assert false + if "foo" =~ peg"{''}.*": + assert matches[0] == "" + else: assert false - if "foo" =~ peg"{'foo'}": - assert matches[0] == "foo" - else: assert false + if "foo" =~ peg"{'foo'}": + assert matches[0] == "foo" + else: assert false - let empty_test = peg"^\d*" - let str = "XYZ" + let empty_test = peg"^\d*" + let str = "XYZ" - assert(str.find(empty_test) == 0) - assert(str.match(empty_test)) + assert(str.find(empty_test) == 0) + assert(str.match(empty_test)) - proc handleMatches*(m: int, n: int, c: openArray[string]): string = - result = "" + proc handleMatches(m: int, n: int, c: openArray[string]): string = + result = "" - if m > 0: - result.add ", " + if m > 0: + result.add ", " - result.add case n: - of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'" - of 1: toLowerAscii(c[0]) & ": ''" - else: "" + result.add case n: + of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'" + of 1: toLowerAscii(c[0]) & ": ''" + else: "" - assert("Var1=key1;var2=Key2; VAR3". - replace(peg"{\ident}('='{\ident})* ';'* \s*", - handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''") + assert("Var1=key1;var2=Key2; VAR3". + replace(peg"{\ident}('='{\ident})* ';'* \s*", + handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''") - doAssert "test1".match(peg"""{@}$""") - doAssert "test2".match(peg"""{(!$ .)*} $""") + doAssert "test1".match(peg"""{@}$""") + doAssert "test2".match(peg"""{(!$ .)*} $""") + pegsTest() + static: + pegsTest() From 81b0718a8fca1ea3fa619ab75bb4cc9275026a4f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 24 Feb 2020 01:24:47 -0800 Subject: [PATCH 0048/4254] make CI tests faster + more precise --- tests/gc/gcleak2.nim | 77 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim index fe1718aef..eb71fe55f 100644 --- a/tests/gc/gcleak2.nim +++ b/tests/gc/gcleak2.nim @@ -2,6 +2,11 @@ discard """ outputsub: "no leak: " """ +## this test makes sure getOccupiedMem() is constant after a few iterations +## for --gc:bohem, --gc:markAndSweep, --gc:arc, --gc:orc. +## and for other gc, it consists of cycles with constant min/max after a few cycles. +## This ensures we have no leaks. + when defined(GC_setMaxPause): GC_setMaxPause 2_000 @@ -14,13 +19,75 @@ proc makeObj(): TTestObj = result.x = "Hello" result.s = @[1,2,3] +const collectAlways = defined(gcMarkAndSweep) or defined(boehmgc) +const isDeterministic = collectAlways or defined(gcArc) or defined(gcOrc) + ## when isDeterministic, we expect memory to reach a fixed point + ## after `numIterStable` iterations + +var memMax = 0 # peak + +when isDeterministic: + const numIterStable = 3 + # stabilize after this many iterations +else: + const numCycleStable = when defined(useRealtimeGC): 6 else: 4 + # stabilize after this many cycles; empirically determined + # after running all combinations of gc's with / without -d:release + var memPrevious = 0 + var memMin = int.high # right after a peak + var numCollections = 0 + +let numIter = when isDeterministic: 1_000 else: 1_000_000 + ## full collection is expensive, and the memory doesn't change after + ## each iteration so there's no point in a large `numIter` (this was taking + ## 350s for `nim c -r -d:release --gc:boehm` + `nim c -r --gc:boehm`, 50% + ## of running time of `testament/testament all`. + proc inProc() = - for i in 1 .. 1_000_000: - when defined(gcMarkAndSweep) or defined(boehmgc): - GC_fullcollect() + for i in 1 .. numIter: + when collectAlways: GC_fullcollect() var obj: TTestObj obj = makeObj() - if getOccupiedMem() > 300_000: quit("still a leak!") + let mem = getOccupiedMem() + when isDeterministic: + if i <= numIterStable: + memMax = mem + doAssert memMax <= 50_000 # adjust as needed + else: + # memory shouldn't increase after 1st few iterations + # on linux 386 it somehow takes 3 iters to converge + doAssert mem <= memMax + else: + if mem < memPrevious: + # a collection happened, it peaked at memPrevious + # echo (mem, memMin, memMax, numCollections, numIter, i) # for debugging + numCollections.inc + if numCollections <= numCycleStable: + # this is the 1st few collections, we update the min/max + doAssert memPrevious < 300_000 # adjust as needed + if memMin < mem: # `<` intentional; the valley may increase + memMin = mem + if memMax < memPrevious: + memMax = memPrevious + else: + # after a collection, we always go back to same level + doAssert mem <= memMin, $(mem, memMin) + + if numCollections >= numCycleStable: + # after a few cycles, the max stabilizes + doAssert mem <= memMax, $(mem, memMax) + + memPrevious = mem inProc() -echo "no leak: ", getOccupiedMem() +let mem = getOccupiedMem() +var msg = "no leak: " +when isDeterministic: + msg.add $(mem, memMax) + echo msg +else: + msg.add $(mem, memMin, memMax, numCollections, numIter) + echo msg + # make sure some collections did happen, otherwise the previous tests + # are meaningless + doAssert numCollections > 1000 # 3999 on local OSX; leaving some slack From 9b8c9abeade5f37b56f1c3824ea179efa9ce47e5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 27 Feb 2020 01:33:06 -0800 Subject: [PATCH 0049/4254] revert changes to tests/gc/gcleak2.nim --- tests/gc/gcleak2.nim | 77 +++----------------------------------------- 1 file changed, 5 insertions(+), 72 deletions(-) diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim index eb71fe55f..fe1718aef 100644 --- a/tests/gc/gcleak2.nim +++ b/tests/gc/gcleak2.nim @@ -2,11 +2,6 @@ discard """ outputsub: "no leak: " """ -## this test makes sure getOccupiedMem() is constant after a few iterations -## for --gc:bohem, --gc:markAndSweep, --gc:arc, --gc:orc. -## and for other gc, it consists of cycles with constant min/max after a few cycles. -## This ensures we have no leaks. - when defined(GC_setMaxPause): GC_setMaxPause 2_000 @@ -19,75 +14,13 @@ proc makeObj(): TTestObj = result.x = "Hello" result.s = @[1,2,3] -const collectAlways = defined(gcMarkAndSweep) or defined(boehmgc) -const isDeterministic = collectAlways or defined(gcArc) or defined(gcOrc) - ## when isDeterministic, we expect memory to reach a fixed point - ## after `numIterStable` iterations - -var memMax = 0 # peak - -when isDeterministic: - const numIterStable = 3 - # stabilize after this many iterations -else: - const numCycleStable = when defined(useRealtimeGC): 6 else: 4 - # stabilize after this many cycles; empirically determined - # after running all combinations of gc's with / without -d:release - var memPrevious = 0 - var memMin = int.high # right after a peak - var numCollections = 0 - -let numIter = when isDeterministic: 1_000 else: 1_000_000 - ## full collection is expensive, and the memory doesn't change after - ## each iteration so there's no point in a large `numIter` (this was taking - ## 350s for `nim c -r -d:release --gc:boehm` + `nim c -r --gc:boehm`, 50% - ## of running time of `testament/testament all`. - proc inProc() = - for i in 1 .. numIter: - when collectAlways: GC_fullcollect() + for i in 1 .. 1_000_000: + when defined(gcMarkAndSweep) or defined(boehmgc): + GC_fullcollect() var obj: TTestObj obj = makeObj() - let mem = getOccupiedMem() - when isDeterministic: - if i <= numIterStable: - memMax = mem - doAssert memMax <= 50_000 # adjust as needed - else: - # memory shouldn't increase after 1st few iterations - # on linux 386 it somehow takes 3 iters to converge - doAssert mem <= memMax - else: - if mem < memPrevious: - # a collection happened, it peaked at memPrevious - # echo (mem, memMin, memMax, numCollections, numIter, i) # for debugging - numCollections.inc - if numCollections <= numCycleStable: - # this is the 1st few collections, we update the min/max - doAssert memPrevious < 300_000 # adjust as needed - if memMin < mem: # `<` intentional; the valley may increase - memMin = mem - if memMax < memPrevious: - memMax = memPrevious - else: - # after a collection, we always go back to same level - doAssert mem <= memMin, $(mem, memMin) - - if numCollections >= numCycleStable: - # after a few cycles, the max stabilizes - doAssert mem <= memMax, $(mem, memMax) - - memPrevious = mem + if getOccupiedMem() > 300_000: quit("still a leak!") inProc() -let mem = getOccupiedMem() -var msg = "no leak: " -when isDeterministic: - msg.add $(mem, memMax) - echo msg -else: - msg.add $(mem, memMin, memMax, numCollections, numIter) - echo msg - # make sure some collections did happen, otherwise the previous tests - # are meaningless - doAssert numCollections > 1000 # 3999 on local OSX; leaving some slack +echo "no leak: ", getOccupiedMem() From fdc5925cbdd53ea8b2877fb56de5a1e5a3025a0c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 27 Feb 2020 01:36:06 -0800 Subject: [PATCH 0050/4254] CI tests run faster: save 120s in azure machines, 335s on local OSX --- tests/gc/gcleak2.nim | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim index fe1718aef..bc943dbe7 100644 --- a/tests/gc/gcleak2.nim +++ b/tests/gc/gcleak2.nim @@ -14,8 +14,20 @@ proc makeObj(): TTestObj = result.x = "Hello" result.s = @[1,2,3] +const numIter = + when defined(boehmgc): + # super slow because GC_fullcollect() at each iteration; especially + # on OSX 10.15 where it takes ~170s + # `getOccupiedMem` should be constant after each iteration for i >= 3 + 1_000 + elif defined(gcMarkAndSweep): + # likewise, somewhat slow, 1_000_000 would run for 8s + # and same remark as above + 100_000 + else: 1_000_000 + proc inProc() = - for i in 1 .. 1_000_000: + for i in 1 .. numIter: when defined(gcMarkAndSweep) or defined(boehmgc): GC_fullcollect() var obj: TTestObj From 73f5f1e80c9baf29c4d49dda7fa41351bb2b2400 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 27 Feb 2020 02:30:31 -0800 Subject: [PATCH 0051/4254] save another 33s of CI for tests/gc/gcleak.nim --- tests/gc/gcleak.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim index 0b2e6e14d..0bf993968 100644 --- a/tests/gc/gcleak.nim +++ b/tests/gc/gcleak.nim @@ -12,7 +12,14 @@ type proc makeObj(): TTestObj = result.x = "Hello" -for i in 1 .. 100_000: +const numIter = + # see tests/gc/gcleak2.nim + when defined(boehmgc): + 1_000 + elif defined(gcMarkAndSweep): 10_000 + else: 100_000 + +for i in 1 .. numIter: when defined(gcMarkAndSweep) or defined(boehmgc): GC_fullcollect() var obj = makeObj() From 96bffadf6045835ddefbf2903e135d50a93f7016 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Sat, 22 Feb 2020 15:09:37 -0600 Subject: [PATCH 0052/4254] Fix #9405 - cfg and nims run in sync --- compiler/cmdlinehelper.nim | 29 ++--------------------------- compiler/nimconf.nim | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index b3c0c46c2..a03899071 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -10,7 +10,7 @@ ## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix import - options, idents, nimconf, scriptconfig, extccomp, commands, msgs, + options, idents, nimconf, extccomp, commands, msgs, lineinfos, modulegraphs, condsyms, os, pathutils from strutils import normalize @@ -43,32 +43,13 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir()) proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool = - loadConfigs(DefaultConfig, cache, conf) # load all config files if self.suggestMode: conf.command = "nimsuggest" + loadConfigs(DefaultConfig, cache, conf) # load all config files - template runNimScriptIfExists(path: AbsoluteFile) = - let p = path # eval once - if fileExists(p): - runNimScript(cache, p, freshDefines = false, conf) - - # Caution: make sure this stays in sync with `loadConfigs` - if optSkipSystemConfigFile notin conf.globalOptions: - runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims)) - - if optSkipUserConfigFile notin conf.globalOptions: - runNimScriptIfExists(getUserConfigPath(DefaultConfigNims)) - - if optSkipParentConfigFiles notin conf.globalOptions: - for dir in parentDirs(conf.projectPath.string, fromRoot = true, inclusive = false): - runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims) - - if optSkipProjConfigFile notin conf.globalOptions: - runNimScriptIfExists(conf.projectPath / DefaultConfigNims) block: let scriptFile = conf.projectFull.changeFileExt("nims") if not self.suggestMode: - runNimScriptIfExists(scriptFile) # 'nim foo.nims' means to just run the NimScript file and do nothing more: if fileExists(scriptFile) and scriptFile == conf.projectFull: if conf.command == "": @@ -76,12 +57,6 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi return false elif conf.command.normalize == "e": return false - else: - if scriptFile != conf.projectFull: - runNimScriptIfExists(scriptFile) - else: - # 'nimsuggest foo.nims' means to just auto-complete the NimScript file - discard # now process command line arguments again, because some options in the # command line can overwrite the config file's settings diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 93cc21573..df1ceb610 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -11,7 +11,7 @@ import llstream, commands, os, strutils, msgs, lexer, - options, idents, wordrecg, strtabs, lineinfos, pathutils + options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig # ---------------- configuration file parser ----------------------------- # we use Nim's scanner here to save space and work @@ -248,17 +248,31 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) = if readConfigFile(configPath, cache, conf): configFiles.add(configPath) + template runNimScriptIfExists(path: AbsoluteFile) = + let p = path # eval once + if fileExists(p): + runNimScript(cache, p, freshDefines = false, conf) + if optSkipSystemConfigFile notin conf.globalOptions: readConfigFile(getSystemConfigPath(conf, cfg)) + if cfg == DefaultConfig: + runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims)) + if optSkipUserConfigFile notin conf.globalOptions: readConfigFile(getUserConfigPath(cfg)) + if cfg == DefaultConfig: + runNimScriptIfExists(getUserConfigPath(DefaultConfigNims)) + let pd = if not conf.projectPath.isEmpty: conf.projectPath else: AbsoluteDir(getCurrentDir()) if optSkipParentConfigFiles notin conf.globalOptions: for dir in parentDirs(pd.string, fromRoot=true, inclusive=false): readConfigFile(AbsoluteDir(dir) / cfg) + if cfg == DefaultConfig: + runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims) + if optSkipProjConfigFile notin conf.globalOptions: readConfigFile(pd / cfg) @@ -269,6 +283,20 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) = projectConfig = changeFileExt(conf.projectFull, "nim.cfg") readConfigFile(projectConfig) + if cfg == DefaultConfig: + runNimScriptIfExists(pd / DefaultConfigNims) + for filename in configFiles: # delayed to here so that `hintConf` is honored rawMessage(conf, hintConf, filename.string) + + block: + let scriptFile = conf.projectFull.changeFileExt("nims") + if conf.command != "nimsuggest": + runNimScriptIfExists(scriptFile) + else: + if scriptFile != conf.projectFull: + runNimScriptIfExists(scriptFile) + else: + # 'nimsuggest foo.nims' means to just auto-complete the NimScript file + discard From ce36fdc8974b843b2fb0404196c2778e8b0b91dd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 24 Feb 2020 19:20:52 -0800 Subject: [PATCH 0053/4254] correctly honor cmdline --hint:conf:on/off ; correctly show Conf hints in order --- compiler/cmdlinehelper.nim | 2 ++ compiler/commands.nim | 6 ++++++ compiler/msgs.nim | 5 ++++- compiler/nimconf.nim | 1 + compiler/options.nim | 4 ++++ compiler/scriptconfig.nim | 3 +-- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index a03899071..9df6d37e0 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -27,7 +27,9 @@ proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) = defineSymbol conf.symbols, name proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = + conf.isCmdLine = true self.processCmdLine(passCmd1, "", conf) + conf.isCmdLine = false if self.supportsStdinFile and conf.projectName == "-": handleStdinInput(conf) elif conf.projectName != "": diff --git a/compiler/commands.nim b/compiler/commands.nim index 638444efe..76203762c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -204,11 +204,17 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, incl(conf.notes, n) incl(conf.mainPackageNotes, n) incl(conf.enableNotes, n) + if conf.isCmdLine: + incl(conf.cmdLineNotes, n) + excl(conf.cmdLineDisabledNotes, n) of "off": excl(conf.notes, n) excl(conf.mainPackageNotes, n) incl(conf.disableNotes, n) excl(conf.foreignPackageNotes, n) + if conf.isCmdLine: + incl(conf.cmdLineDisabledNotes, n) + excl(conf.cmdLineNotes, n) else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc processCompile(conf: ConfigRef; filename: string) = diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6d1ecb2b1..7fa8e8aef 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -418,7 +418,10 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - if not conf.hasHint(msg): return + if msg in conf.cmdLineDisabledNotes: return # eg: `--hints:conf:off` passed on cmdline + # handle `--hints:off` (regardless of cmdline/cfg file) + # handle `--hints:conf:on` on cmdline + if not conf.hasHint(msg) and not (optHints in conf.options and msg in conf.cmdLineNotes)): return title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index df1ceb610..bd00832be 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -251,6 +251,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) = template runNimScriptIfExists(path: AbsoluteFile) = let p = path # eval once if fileExists(p): + configFiles.add(p) runNimScript(cache, p, freshDefines = false, conf) if optSkipSystemConfigFile notin conf.globalOptions: diff --git a/compiler/options.nim b/compiler/options.nim index 7a7ab0bcd..fc37979e2 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -231,6 +231,8 @@ type foreignPackageNotes*: TNoteKinds notes*: TNoteKinds mainPackageNotes*: TNoteKinds + cmdLineNotes*: TNoteKinds + cmdLineDisabledNotes*: TNoteKinds mainPackageId*: int errorCounter*: int hintCounter*: int @@ -286,6 +288,7 @@ type structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string + isCmdLine*: bool # whether we are currently processing cmdline args, not cfg files proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = optHints in conf.options and note in conf.notes @@ -391,6 +394,7 @@ proc newConfigRef*(): ConfigRef = arguments: "", suggestMaxResults: 10_000, maxLoopIterationsVM: 10_000_000, + isCmdLine: false, ) setTargetFromSystem(result.target) # enable colors by default on terminals diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index e9e720b1b..6aad1b25f 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -199,7 +199,6 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; freshDefines=true; conf: ConfigRef) = - rawMessage(conf, hintConf, scriptName.string) let oldSymbolFiles = conf.symbolFiles conf.symbolFiles = disabledSf @@ -224,7 +223,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; incl(m.flags, sfMainModule) graph.vm = setupVM(m, cache, scriptName.string, graph) - graph.compileSystemModule() # TODO: see why this unsets hintConf in conf.notes + graph.compileSystemModule() discard graph.processModule(m, llStreamOpen(scriptName, fmRead)) # watch out, "newruntime" can be set within NimScript itself and then we need From c1cbf94e2d41911fe11ea98e86000f9a851fc01a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 Feb 2020 03:10:11 -0800 Subject: [PATCH 0054/4254] remove isCmdLine; use passCmd1 --- compiler/cmdlinehelper.nim | 2 -- compiler/commands.nim | 4 ++-- compiler/msgs.nim | 2 +- compiler/options.nim | 2 -- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index 9df6d37e0..a03899071 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -27,9 +27,7 @@ proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) = defineSymbol conf.symbols, name proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = - conf.isCmdLine = true self.processCmdLine(passCmd1, "", conf) - conf.isCmdLine = false if self.supportsStdinFile and conf.projectName == "-": handleStdinInput(conf) elif conf.projectName != "": diff --git a/compiler/commands.nim b/compiler/commands.nim index 76203762c..d2f1f78b3 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -204,7 +204,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, incl(conf.notes, n) incl(conf.mainPackageNotes, n) incl(conf.enableNotes, n) - if conf.isCmdLine: + if pass == passCmd1: incl(conf.cmdLineNotes, n) excl(conf.cmdLineDisabledNotes, n) of "off": @@ -212,7 +212,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, excl(conf.mainPackageNotes, n) incl(conf.disableNotes, n) excl(conf.foreignPackageNotes, n) - if conf.isCmdLine: + if pass == passCmd1: incl(conf.cmdLineDisabledNotes, n) excl(conf.cmdLineNotes, n) else: localError(conf, info, errOnOrOffExpectedButXFound % arg) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 7fa8e8aef..197295249 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -421,7 +421,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = if msg in conf.cmdLineDisabledNotes: return # eg: `--hints:conf:off` passed on cmdline # handle `--hints:off` (regardless of cmdline/cfg file) # handle `--hints:conf:on` on cmdline - if not conf.hasHint(msg) and not (optHints in conf.options and msg in conf.cmdLineNotes)): return + if not conf.hasHint(msg) and not (optHints in conf.options and msg in conf.cmdLineNotes): return title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] diff --git a/compiler/options.nim b/compiler/options.nim index fc37979e2..9d073ce45 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -288,7 +288,6 @@ type structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string - isCmdLine*: bool # whether we are currently processing cmdline args, not cfg files proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = optHints in conf.options and note in conf.notes @@ -394,7 +393,6 @@ proc newConfigRef*(): ConfigRef = arguments: "", suggestMaxResults: 10_000, maxLoopIterationsVM: 10_000_000, - isCmdLine: false, ) setTargetFromSystem(result.target) # enable colors by default on terminals From 1056f9ecff60f624522f24e508d0976994bcef80 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 Feb 2020 12:49:44 -0800 Subject: [PATCH 0055/4254] properly handle note override logic/verbosity/config/cmdline using modifiedyNotes, cmdlineNotes --- compiler/commands.nim | 41 ++++++++++++++++++++--------------------- compiler/msgs.nim | 5 +---- compiler/options.nim | 12 +++++++----- compiler/passaux.nim | 4 ++-- compiler/pragmas.nim | 1 + 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index d2f1f78b3..0545ee2b0 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -199,23 +199,21 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, let x = findStr(lineinfos.WarningsToStr, id) if x >= 0: n = TNoteKind(x + ord(warnMin)) else: localError(conf, info, "unknown warning: " & id) - case substr(arg, i).normalize - of "on": - incl(conf.notes, n) - incl(conf.mainPackageNotes, n) - incl(conf.enableNotes, n) - if pass == passCmd1: - incl(conf.cmdLineNotes, n) - excl(conf.cmdLineDisabledNotes, n) - of "off": - excl(conf.notes, n) - excl(conf.mainPackageNotes, n) - incl(conf.disableNotes, n) - excl(conf.foreignPackageNotes, n) - if pass == passCmd1: - incl(conf.cmdLineDisabledNotes, n) - excl(conf.cmdLineNotes, n) - else: localError(conf, info, errOnOrOffExpectedButXFound % arg) + + let val = substr(arg, i).normalize + if val notin ["on", "off"]: + localError(conf, info, errOnOrOffExpectedButXFound % arg) + elif n notin conf.cmdlineNotes or pass == passCmd1: + if pass == passCmd1: incl(conf.cmdlineNotes, n) + incl(conf.modifiedyNotes, n) + case val + of "on": + incl(conf.notes, n) + incl(conf.mainPackageNotes, n) + of "off": + excl(conf.notes, n) + excl(conf.mainPackageNotes, n) + excl(conf.foreignPackageNotes, n) proc processCompile(conf: ConfigRef; filename: string) = var found = findFile(conf, filename) @@ -598,7 +596,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "deadcodeelim": discard # deprecated, dead code elim always on of "threads": processOnOffSwitchG(conf, {optThreads}, arg, pass, info) - #if optThreads in conf.globalOptions: incl(conf.notes, warnGcUnsafe) + #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe) of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info) of "implicitstatic": @@ -710,9 +708,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if verbosity notin {0..3}: localError(conf, info, "invalid verbosity level: '$1'" % arg) conf.verbosity = verbosity - conf.notes = NotesVerbosity[conf.verbosity] - incl(conf.notes, conf.enableNotes) - excl(conf.notes, conf.disableNotes) + var verb = NotesVerbosity[conf.verbosity] + ## We override the default `verb` by explicitly modified (set/unset) notes. + conf.notes = (conf.modifiedyNotes * conf.notes + verb) - + (conf.modifiedyNotes * verb - conf.notes) conf.mainPackageNotes = conf.notes of "parallelbuild": expectArg(conf, switch, arg, pass, info) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 197295249..6d1ecb2b1 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -418,10 +418,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - if msg in conf.cmdLineDisabledNotes: return # eg: `--hints:conf:off` passed on cmdline - # handle `--hints:off` (regardless of cmdline/cfg file) - # handle `--hints:conf:on` on cmdline - if not conf.hasHint(msg) and not (optHints in conf.options and msg in conf.cmdLineNotes): return + if not conf.hasHint(msg): return title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] diff --git a/compiler/options.nim b/compiler/options.nim index 9d073ce45..c93fc0648 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -226,13 +226,11 @@ type ideCmd*: IdeCmd oldNewlines*: bool cCompiler*: TSystemCC - enableNotes*: TNoteKinds - disableNotes*: TNoteKinds + modifiedyNotes*: TNoteKinds # notes that have been set/unset from either cmdline/configs + cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline foreignPackageNotes*: TNoteKinds - notes*: TNoteKinds + notes*: TNoteKinds # notes after resolving all logic(defaults, verbosity)/cmdline/configs mainPackageNotes*: TNoteKinds - cmdLineNotes*: TNoteKinds - cmdLineDisabledNotes*: TNoteKinds mainPackageId*: int errorCounter*: int hintCounter*: int @@ -289,6 +287,10 @@ type severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string +proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) = + if note notin conf.cmdlineNotes: + if enabled: incl(conf.notes, note) else: excl(conf.notes, note) + proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = optHints in conf.options and note in conf.notes diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 2ac89c24e..155b956df 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -28,8 +28,8 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode = let v = VerboseRef(context) if v.config.verbosity == 3: # system.nim deactivates all hints, for verbosity:3 we want the processing - # messages nonetheless, so we activate them again unconditionally: - incl(v.config.notes, hintProcessing) + # messages nonetheless, so we activate them again (but honor cmdlineNotes) + v.config.setNote(hintProcessing) message(v.config, n.info, hintProcessing, $idgen.gFrontEndId) const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 029128086..559c1c064 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -328,6 +328,7 @@ proc processNote(c: PContext, n: PNode) = n[1] = x if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk) else: excl(c.config.notes, nk) + # checkme: honor cmdlineNotes with: c.setNote(nk, x.kind == nkIntLit and x.intVal != 0) else: invalidPragma(c, n) From 25dc5f76e024de88478bc6ee3b559e731f227b69 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 28 Feb 2020 09:54:17 +0000 Subject: [PATCH 0056/4254] fixes #12627 (#13521) * fixes #12627 --- compiler/sem.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 7cd0aa6f2..831e16017 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -395,7 +395,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, if c.config.evalTemplateCounter > evalTemplateLimit: globalError(c.config, s.info, "template instantiation too nested") c.friendModules.add(s.owner.getModule) - + idSynchronizationPoint(5000) result = macroResult excl(result.flags, nfSem) #resetSemFlag n From c79df2fb6abb5663505de13c0ae5995d72ae71a8 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 28 Feb 2020 09:55:06 +0000 Subject: [PATCH 0057/4254] EndsInNoReturn in expressions extension, fixes #13490 (#13520) * fix #13490 --- compiler/ast.nim | 2 ++ compiler/sem.nim | 2 +- compiler/semstmts.nim | 7 ++----- compiler/vmgen.nim | 2 -- tests/casestmt/tcasestmt.nim | 37 ++++++++++++++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 5938d4e53..70c14ccaf 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -336,6 +336,8 @@ const tagEffects* = 3 # user defined tag ('gc', 'time' etc.) pragmasEffects* = 4 # not an effect, but a slot for pragmas in proc type effectListLen* = 5 # list of effects list + nkLastBlockStmts* = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} + # these must be last statements in a block type TTypeKind* = enum # order is important! diff --git a/compiler/sem.nim b/compiler/sem.nim index 831e16017..48f767af7 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -181,7 +181,7 @@ proc endsInNoReturn(n: PNode): bool = var it = n while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: it = it.lastSon - result = it.kind == nkRaiseStmt or + result = it.kind in nkLastBlockStmts or it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags proc commonType*(x: PType, y: PNode): PType = diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 7636705e0..deffe563c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -120,7 +120,7 @@ const proc implicitlyDiscardable(n: PNode): bool = var n = n while n.kind in skipForDiscardable: n = n.lastSon - result = n.kind == nkRaiseStmt or + result = n.kind in nkLastBlockStmts or (isCallExpr(n) and n[0].kind == nkSym and sfDiscardable in n[0].sym.flags) @@ -2162,9 +2162,6 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) = typ.n = res proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = - # these must be last statements in a block: - const - LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} result = n result.transitionSonsKind(nkStmtList) var voidContext = false @@ -2209,7 +2206,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = else: n.typ = n[i].typ if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr) - if n[i].kind in LastBlockStmts or + if n[i].kind in nkLastBlockStmts or n[i].kind in nkCallKinds and n[i][0].kind == nkSym and sfNoReturn in n[i][0].sym.flags: for j in i + 1.. Date: Sat, 29 Feb 2020 17:57:00 +0000 Subject: [PATCH 0058/4254] make it possible to pass linker options for vcc (#13535) [backport] --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index c6f062c78..b9d0f0ff6 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -149,7 +149,7 @@ compiler vcc: buildDll: " /LD", buildLib: "lib /OUT:$libfile $objfiles", linkerExe: "cl", - linkTmpl: "$options $builddll$vccplatform /Fe$exefile $objfiles $buildgui", + linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui $options", includeCmd: " /I", linkDirCmd: " /LIBPATH:", linkLibCmd: " $1.lib", From 525ab5a497d1b998bc67c5b1225db3556ac77d27 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 1 Mar 2020 23:52:29 +0300 Subject: [PATCH 0059/4254] Document import/include outside of top level semantics (#13548) --- doc/manual.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index ba13f2f02..71f6f73f9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5645,6 +5645,8 @@ It is not checked that the ``except`` list is really exported from the module. This feature allows to compile against an older version of the module that does not export these identifiers. +The ``import`` statement is only allowed at the top level. + Include statement ~~~~~~~~~~~~~~~~~ @@ -5655,6 +5657,18 @@ statement is useful to split up a large module into several files: .. code-block:: nim include fileA, fileB, fileC +The ``include`` statement can be used outside of the top level, as such: + +.. code-block:: nim + # Module A + echo "Hello World!" + +.. code-block:: nim + # Module B + proc main() = + include A + + main() # => Hello World! Module names in imports From 22d1ba4be76569d1df96cc8bfed47fccfc833019 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 1 Mar 2020 12:56:20 -0800 Subject: [PATCH 0060/4254] fixes #13543 and added times.isLeapDay (#13547) --- changelog.md | 1 + lib/pure/times.nim | 13 +++++++++++++ tests/stdlib/ttimes.nim | 10 +++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index f106ac2c2..e0fd64942 100644 --- a/changelog.md +++ b/changelog.md @@ -81,6 +81,7 @@ ``` +- Added `times.isLeapDay` ## Library changes diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 3fc4d69df..92b6cd3b7 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -637,6 +637,19 @@ proc isLeapYear*(year: int): bool = doAssert not isLeapYear(1900) year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0) +proc isLeapDay*(t: DateTime): bool {.since: (1,1).} = + ## returns whether `t` is a leap day, ie, Feb 29 in a leap year. This matters + ## as it affects time offset calculations. + runnableExamples: + let t = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) + doAssert t.isLeapDay + doAssert t+1.years-1.years != t + let t2 = initDateTime(28, mFeb, 2020, 00, 00, 00, utc()) + doAssert not t2.isLeapDay + doAssert t2+1.years-1.years == t2 + doAssertRaises(Exception): discard initDateTime(29, mFeb, 2021, 00, 00, 00, utc()) + t.year.isLeapYear and t.month == mFeb and t.monthday == 29 + proc getDaysInMonth*(month: Month, year: int): int = ## Get the number of days in ``month`` of ``year``. # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 97945b21d..0602aaa94 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -345,20 +345,24 @@ suite "ttimes": test "adding/subtracting TimeInterval": # add/subtract TimeIntervals and Time/TimeInfo let now = getTime().utc + let isSpecial = now.isLeapDay check now + convert(Seconds, Nanoseconds, 1).nanoseconds == now + 1.seconds check now + 1.weeks == now + 7.days check now - 1.seconds == now - 3.seconds + 2.seconds check now + 65.seconds == now + 1.minutes + 5.seconds check now + 60.minutes == now + 1.hours check now + 24.hours == now + 1.days - check now + 13.months == now + 1.years + 1.months + if not isSpecial: + check now + 13.months == now + 1.years + 1.months check toUnix(fromUnix(0) + 2.seconds) == 2 check toUnix(fromUnix(0) - 2.seconds) == -2 var ti1 = now + 1.years ti1 = ti1 - 1.years - check ti1 == now + if not isSpecial: + check ti1 == now ti1 = ti1 + 1.days - check ti1 == now + 1.days + if not isSpecial: + check ti1 == now + 1.days # Bug with adding a day to a Time let day = 24.hours From 653de5f27a89c781376be370e28f8f3ce7744040 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 2 Mar 2020 01:26:10 -0800 Subject: [PATCH 0061/4254] fix broken nim CI, disable blscurve (#13555) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 3018a21ff..344aff339 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -11,7 +11,7 @@ pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" pkg "asyncmysql", "", true pkg "bigints" pkg "binaryheap", "nim c -r binaryheap.nim" -pkg "blscurve", "", true +# pkg "blscurve", "", true # pending https://github.com/status-im/nim-blscurve/issues/39 pkg "bncurve", "", true pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" From 05e9473f80ec477c2e53e072e330d03bc3b0d4a0 Mon Sep 17 00:00:00 2001 From: PMunch Date: Mon, 2 Mar 2020 17:52:42 +0100 Subject: [PATCH 0062/4254] Add signatures object to jsondoc for routine types (#13530) jsondoc is meant to be read by computers, but yet the signatures of procedures where simply a string of the whole thing. This adds a signature object that unpacks this information into an object so it's easier to analyse the documented signatures. --- compiler/docgen.nim | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 15ff2e167..daa3a708d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -794,6 +794,35 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = result["description"] = %comm if r.buf.len > 0: result["code"] = %r.buf + if k in routineKinds: + result["signature"] = newJObject() + if n[paramsPos][0].kind != nkEmpty: + result["signature"]["return"] = %($n[paramsPos][0]) + if n[paramsPos].len > 1: + result["signature"]["arguments"] = newJArray() + for paramIdx in 1 ..< n[paramsPos].len: + for identIdx in 0 ..< n[paramsPos][paramIdx].len - 2: + let + paramName = $n[paramsPos][paramIdx][identIdx] + paramType = $n[paramsPos][paramIdx][^2] + if n[paramsPos][paramIdx][^1].kind != nkEmpty: + let paramDefault = $n[paramsPos][paramIdx][^1] + result["signature"]["arguments"].add %{"name": %paramName, "type": %paramType, "default": %paramDefault} + else: + result["signature"]["arguments"].add %{"name": %paramName, "type": %paramType} + if n[pragmasPos].kind != nkEmpty: + result["signature"]["pragmas"] = newJArray() + for pragma in n[pragmasPos]: + result["signature"]["pragmas"].add %($pragma) + if n[genericParamsPos].kind != nkEmpty: + result["signature"]["genericParams"] = newJArray() + for genericParam in n[genericParamsPos]: + var param = %{"name": %($genericParam)} + if genericParam.sym.typ.sons.len > 0: + param["types"] = newJArray() + for kind in genericParam.sym.typ.sons: + param["types"].add %($kind) + result["signature"]["genericParams"].add param proc checkForFalse(n: PNode): bool = result = n.kind == nkIdent and cmpIgnoreStyle(n.ident.s, "false") == 0 From 27241fda23905280c8b8a13d94efb46a7ebe9836 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 2 Mar 2020 08:55:17 -0800 Subject: [PATCH 0063/4254] fix #13528 nimgrep --word now works better with operators (#13537) --- tools/nimgrep.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 51685e556..26e219330 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -649,7 +649,8 @@ else: if optIgnoreStyle in options: pattern = styleInsensitive(pattern) if optWord in options: - pattern = r"\b(:?" & pattern & r")\b" + # see https://github.com/nim-lang/Nim/issues/13528#issuecomment-592786443 + pattern = r"(^|\W)(:?" & pattern & r")($|\W)" if {optIgnoreCase, optIgnoreStyle} * options != {}: reflags.incl reIgnoreCase let rep = if optRex in options: rex(pattern, reflags) From 451b724c40bc04e4a9c756b2fcd457cca3fd437c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 2 Mar 2020 09:05:14 -0800 Subject: [PATCH 0064/4254] make genericParams support static[T] generic params (#13433) * make genericParams support static[T] generic params * WrapStatic => StaticParam --- lib/pure/typetraits.nim | 34 ++++++++++++++++++++----- tests/metatype/ttypetraits.nim | 45 +++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 04231db09..0335d5488 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -86,13 +86,13 @@ since (1, 1): # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` type(default(T)[i]) + type StaticParam*[value] = object + ## used to wrap a static value in `genericParams` + import std/macros -macro genericParams*(T: typedesc): untyped {.since: (1, 1).} = - ## return tuple of generic params for generic `T` - runnableExamples: - type Foo[T1, T2]=object - doAssert genericParams(Foo[float, string]) is (float, string) +macro genericParamsImpl(T: typedesc): untyped = + # auxiliary macro needed, can't do it directly in `genericParams` result = newNimNode(nnkTupleConstr) var impl = getTypeImpl(T) expectKind(impl, nnkBracketExpr) @@ -107,11 +107,33 @@ macro genericParams*(T: typedesc): untyped {.since: (1, 1).} = continue of nnkBracketExpr: for i in 1.. Date: Mon, 2 Mar 2020 19:30:41 -0800 Subject: [PATCH 0065/4254] workaround refs #13563 freebsd CI (#13564) --- .builds/freebsd.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 7810e39af..b53cc3104 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,4 +1,9 @@ -image: freebsd/latest +# see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd +# these are all broken, pending https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=244549 +# image: freebsd/latest +# image: freebsd/current +# image: freebsd/12.x +image: freebsd/11.x packages: - databases/sqlite3 - devel/boehm-gc-threaded From eb42f38088d278d396855e7e284ea798c8a884f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Tue, 3 Mar 2020 12:42:43 +0100 Subject: [PATCH 0066/4254] Remove dead magics (#13551) --- compiler/ast.nim | 34 ++++++++++++++++------------------ compiler/ccgexprs.nim | 34 +++------------------------------- compiler/forloops.nim | 2 +- compiler/guards.nim | 11 ++++------- compiler/jsgen.nim | 14 ++------------ compiler/semfold.nim | 10 +--------- compiler/semmagic.nim | 4 +--- compiler/semtypes.nim | 6 ------ compiler/sigmatch.nim | 3 --- compiler/vm.nim | 5 ----- compiler/vmdef.nim | 2 +- compiler/vmgen.nim | 35 +++-------------------------------- lib/core/macros.nim | 2 +- lib/system/basic_types.nim | 22 +++++++++++----------- 14 files changed, 44 insertions(+), 140 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 70c14ccaf..3b10a89ea 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -336,7 +336,7 @@ const tagEffects* = 3 # user defined tag ('gc', 'time' etc.) pragmasEffects* = 4 # not an effect, but a slot for pragmas in proc type effectListLen* = 5 # list of effects list - nkLastBlockStmts* = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} + nkLastBlockStmts* = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} # these must be last statements in a block type @@ -599,12 +599,11 @@ type mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn, mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf, - mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, + mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, - mUnaryLt, mInc, mDec, mOrd, + mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mNewSeqOfCap, mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, - mXLenStr, mXLenSeq, mIncl, mExcl, mCard, mChr, mGCref, mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, @@ -620,7 +619,7 @@ type mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, - mEqRef, mEqUntracedRef, mLePtr, mLtPtr, + mEqRef, mLePtr, mLtPtr, mXor, mEqCString, mEqProc, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, @@ -629,18 +628,18 @@ type mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mConStrStr, mSlice, mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInRange, mInSet, mRepr, mExit, + mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mIsPartOf, mAstToStr, mParallel, - mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, + mSwap, mIsNil, mArrToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, - mDefault, mUnown, mAccessEnv, mAccessTypeInfo, mReset, + mDefault, mUnown, mAccessEnv, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, @@ -648,8 +647,8 @@ type mUInt, mUInt8, mUInt16, mUInt32, mUInt64, mFloat, mFloat32, mFloat64, mFloat128, mBool, mChar, mString, mCstring, - mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, - mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy, + mPointer, mNil, mExpr, mStmt, mTypeDesc, + mVoidType, mPNimrodNode, mSpawn, mDeepCopy, mIsMainModule, mCompileDate, mCompileTime, mProcCall, mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType, mCompileOption, mCompileOptionArg, @@ -662,7 +661,7 @@ type mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf, - mNBindSym, mLocals, mNCallSite, + mNBindSym, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, @@ -673,9 +672,9 @@ type # things that we can evaluate safely at compile time, even if not asked for it: const - ctfeWhitelist* = {mNone, mUnaryLt, mSucc, + ctfeWhitelist* = {mNone, mSucc, mPred, mInc, mDec, mOrd, mLengthOpenArray, - mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, + mLengthStr, mLengthArray, mLengthSeq, mArrGet, mArrPut, mAsgn, mDestroy, mIncl, mExcl, mCard, mChr, mAddI, mSubI, mMulI, mDivI, mModI, @@ -690,17 +689,16 @@ const mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, - mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, + mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInRange, mInSet, mRepr, - mCopyStr, mCopyStrLast} + mInSet, mRepr} type PNode* = ref TNode diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 632e4bb31..111e1053b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -617,7 +617,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mLeB: applyFormat("($1 <= $2)") of mLtB: applyFormat("($1 < $2)") of mEqRef: applyFormat("($1 == $2)") - of mEqUntracedRef: applyFormat("($1 == $2)") of mLePtr: applyFormat("($1 <= $2)") of mLtPtr: applyFormat("($1 < $2)") of mXor: applyFormat("($1 != $2)") @@ -1797,7 +1796,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const - lookupOpr: array[mLeSet..mSymDiffSet, string] = [ + lookupOpr: array[mLeSet..mMinusSet, string] = [ "for ($1 = 0; $1 < $2; $1++) { $n" & " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n", @@ -1807,8 +1806,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n", "&", "|", - "& ~", - "^"] + "& ~"] var a, b, i: TLoc var setType = skipTypes(e[1].typ, abstractVar) var size = int(getSize(p.config, setType)) @@ -1838,7 +1836,6 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mMulSet: binaryExpr(p, e, d, "($1 & $2)") of mPlusSet: binaryExpr(p, e, d, "($1 | $2)") of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)") - of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)") of mInSet: genInOp(p, e, d) else: internalError(p.config, e.info, "genSetOp()") @@ -1868,7 +1865,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) - of mMulSet, mPlusSet, mMinusSet, mSymDiffSet: + of mMulSet, mPlusSet, mMinusSet: # we inline the simple for loop for better code generation: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter initLocExpr(p, e[1], a) @@ -2118,9 +2115,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mRepr: genRepr(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d) of mSwap: genSwap(p, e, d) - of mUnaryLt: - if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)") - else: unaryExpr(p, e, d, "#subInt($1, 1)") of mInc, mDec: const opr: array[mInc..mDec, string] = ["+=", "-="] const fun64: array[mInc..mDec, string] = ["addInt64", @@ -2218,21 +2212,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mOrd: genOrd(p, e, d) of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: genArrayLen(p, e, d, op) - of mXLenStr: - if not p.module.compileToCpp: - unaryExpr(p, e, d, "($1->Sup.len)") - else: - unaryExpr(p, e, d, "$1->len") - of mXLenSeq: - # see 'taddhigh.nim' for why we need to use a temporary here: - var a, tmp: TLoc - initLocExpr(p, e[1], a) - getIntTemp(p, tmp) - if not p.module.compileToCpp: - lineCg(p, cpsStmts, "$1 = $2->Sup.len;$n", [tmp.r, rdLoc(a)]) - else: - lineCg(p, cpsStmts, "$1 = $2->len;$n", [tmp.r, rdLoc(a)]) - putIntoDest(p, d, e, tmp.r) of mGCref: unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n") of mGCunref: unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n") of mSetLengthStr: genSetLengthStr(p, e, d) @@ -2240,8 +2219,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op) - of mCopyStr, mCopyStrLast: - genCall(p, e, d) of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat: var opr = e[0].sym # Why would anyone want to set nodecl to one of these hardcoded magics? @@ -2296,11 +2273,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mMove: genMove(p, e, d) of mDestroy: genDestroy(p, e) of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0") - of mAccessTypeInfo: - var a: TLoc - var dummy: Rope - initLocExpr(p, e[1], a) - putIntoDest(p, d, e, rdMType(p, a, dummy)) of mSlice: localError(p.config, e.info, "invalid context for 'toOpenArray'; " & "'toOpenArray' is only valid within a call expression") diff --git a/compiler/forloops.nim b/compiler/forloops.nim index d857b3c51..729afb920 100644 --- a/compiler/forloops.nim +++ b/compiler/forloops.nim @@ -13,7 +13,7 @@ import ast, astalgo const someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, - mEqUntracedRef, mLeI, mLeF64, mLeU, mLeU64, mLeEnum, + mLeI, mLeF64, mLeU, mLeU64, mLeEnum, mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtU64, mLtEnum, mLtCh, mLtB, mLtPtr} diff --git a/compiler/guards.nim b/compiler/guards.nim index a2cbdbda2..97dc4f418 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -14,7 +14,7 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, const someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, - mEqUntracedRef, mEqStr, mEqSet, mEqCString} + mEqStr, mEqSet, mEqCString} # set excluded here as the semantics are vastly different: someLe = {mLeI, mLeF64, mLeU, mLeU64, mLeEnum, @@ -22,10 +22,9 @@ const someLt = {mLtI, mLtF64, mLtU, mLtU64, mLtEnum, mLtCh, mLtB, mLtPtr, mLtStr} - someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, - mXLenStr, mXLenSeq} + someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq} - someIn = {mInRange, mInSet} + someIn = {mInSet} someHigh = {mHigh} # we don't list unsigned here because wrap around semantics suck for @@ -258,7 +257,7 @@ proc canon*(n: PNode; o: Operators): PNode = result[i] = canon(n[i], o) elif n.kind == nkSym and n.sym.kind == skLet and n.sym.astdef.getMagic in (someEq + someAdd + someMul + someMin + - someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv): + someMax + someHigh + someSub + someLen + someDiv): result = n.sym.astdef.copyTree else: result = n @@ -271,8 +270,6 @@ proc canon*(n: PNode; o: Operators): PNode = of someHigh: # high == len+(-1) result = o.opAdd.buildCall(o.opLen.buildCall(result[1]), minusOne()) - of mUnaryLt: - result = buildCall(o.opAdd, result[1], minusOne()) of someSub: # x - 4 --> x + (-4) result = negate(result[1], result[2], result, o) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 51d23662c..1130e35f8 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -370,7 +370,7 @@ type const # magic checked op; magic unchecked op; jsMagics: TMagicOps = [ - ["addInt", ""], # AddI + mAddI: ["addInt", ""], ["subInt", ""], # SubI ["mulInt", ""], # MulI ["divInt", ""], # DivI @@ -414,7 +414,6 @@ const # magic checked op; magic unchecked op; ["", ""], # LeB ["", ""], # LtB ["", ""], # EqRef - ["", ""], # EqUntracedRef ["", ""], # LePtr ["", ""], # LtPtr ["", ""], # Xor @@ -588,7 +587,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mLeB: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtB: applyFormat("($1 < $2)", "($1 < $2)") of mEqRef: applyFormat("($1 == $2)", "($1 == $2)") - of mEqUntracedRef: applyFormat("($1 == $2)", "($1 == $2)") of mLePtr: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtPtr: applyFormat("($1 < $2)", "($1 < $2)") of mXor: applyFormat("($1 != $2)", "($1 != $2)") @@ -631,7 +629,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) - of mEqRef, mEqUntracedRef: + of mEqRef: if mapType(n[1].typ) != etyBaseIndex: arithAux(p, n, r, op) else: @@ -1890,10 +1888,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mAddI..mStrToStr: arith(p, n, r, op) of mRepr: genRepr(p, n, r) of mSwap: genSwap(p, n) - of mUnaryLt: - # XXX: range checking? - if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1") - else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)") of mAppendStrCh: binaryExpr(p, n, r, "addChar", "if ($1 != null) { addChar($3, $2); } else { $3 = [$2]; }") @@ -1959,8 +1953,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mOrd: genOrd(p, n, r) of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: unaryExpr(p, n, r, "", "($1 != null ? $2.length : 0)") - of mXLenStr, mXLenSeq: - unaryExpr(p, n, r, "", "$1.length") of mHigh: unaryExpr(p, n, r, "", "($1 != null ? ($2.length-1) : -1)") of mInc: @@ -2007,8 +1999,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mEcho: genEcho(p, n, r) of mNLen..mNError, mSlurp, mStaticExec: localError(p.config, n.info, errXMustBeCompileTime % n[0].sym.name.s) - of mCopyStr: - binaryExpr(p, n, r, "", "($1.slice($2))") of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)") of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)") diff --git a/compiler/semfold.nim b/compiler/semfold.nim index e8ca42db3..b20616e1d 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -188,7 +188,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = else: result = newIntNodeT(bitnot(getInt(a)), n, g) of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g) - of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: + of mLengthSeq, mLengthOpenArray, mLengthStr: if a.kind == nkNilLit: result = newIntNodeT(Zero, n, g) elif a.kind in {nkStrLit..nkTripleStrLit}: @@ -198,7 +198,6 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away # XXX: Hides overflow/underflow of mAbsI: result = foldAbs(getInt(a), n, g) - of mUnaryLt: result = foldSub(getOrdValue(a), One, n, g) of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g) of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g) of mAddI: result = foldAdd(getInt(a), getInt(b), n, g) @@ -330,9 +329,6 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mMinusSet: result = nimsets.diffSets(g.config, a, b) result.info = n.info - of mSymDiffSet: - result = nimsets.symdiffSets(g.config, a, b) - result.info = n.info of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g) of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, g) of mRepr: @@ -342,10 +338,6 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mBoolToStr: if getOrdValue(a) == 0: result = newStrNodeT("false", n, g) else: result = newStrNodeT("true", n, g) - of mCopyStr: result = newStrNodeT(substr(getStr(a), int(toInt64(getOrdValue(b)))), n, g) - of mCopyStrLast: - result = newStrNodeT(substr(getStr(a), toInt(getOrdValue(b)), - toInt(getOrdValue(c))), n, g) of mFloatToStr: result = newStrNodeT($getFloat(a), n, g) of mCStrToStr, mCharToStr: if a.kind == nkBracket: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 1671a8a26..ffdad5628 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -140,7 +140,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) if operand.kind == tyGenericParam or (traitCall.len > 2 and operand2.kind == tyGenericParam): return traitCall ## too early to evaluate - + let s = trait.sym.name.s case s of "or", "|": @@ -479,8 +479,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result.typ = n[1].typ of mDotDot: result = n - of mRoof: - localError(c.config, n.info, "builtin roof operator is not supported anymore") of mPlugin: let plugin = getPlugin(c.cache, n[0].sym) if plugin.isNil: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 61cbecec6..abc5de7e8 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1898,10 +1898,6 @@ proc processMagicType(c: PContext, m: PSym) = setMagicIntegral(c.config, m, tyCString, c.config.target.ptrSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) of mPointer: setMagicIntegral(c.config, m, tyPointer, c.config.target.ptrSize) - of mEmptySet: - setMagicIntegral(c.config, m, tySet, 1) - rawAddSon(m.typ, newTypeS(tyEmpty, c)) - of mIntSetBaseType: setMagicIntegral(c.config, m, tyRange, c.config.target.intSize) of mNil: setMagicType(c.config, m, tyNil, c.config.target.ptrSize) of mExpr: if m.name.s == "auto": @@ -1937,8 +1933,6 @@ proc processMagicType(c: PContext, m: PSym) = incl m.typ.flags, tfHasAsgn assert c.graph.sysTypes[tySequence] == nil c.graph.sysTypes[tySequence] = m.typ - of mOpt: - setMagicType(c.config, m, tyOpt, szUncomputedSize) of mOrdinal: setMagicIntegral(c.config, m, tyOrdinal, szUncomputedSize) rawAddSon(m.typ, newTypeS(tyNone, c)) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4105d3780..4f05282a3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -832,9 +832,6 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = # if lhs.kind in nkCallKinds and lhs[0].kind == nkSym: case lhs[0].sym.magic - of mUnaryLt: - return inferStaticParam(c, lhs[1], rhs + 1) - of mAddI, mAddU, mInc, mSucc: if lhs[1].kind == nkIntLit: return inferStaticParam(c, lhs[2], rhs - lhs[1].intVal) diff --git a/compiler/vm.nim b/compiler/vm.nim index 2d4d06c41..6a12b615e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1089,11 +1089,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = createSet(regs[ra]) move(regs[ra].node.sons, nimsets.diffSets(c.config, regs[rb].node, regs[rc].node).sons) - of opcSymdiffSet: - decodeBC(rkNode) - createSet(regs[ra]) - move(regs[ra].node.sons, - nimsets.symdiffSets(c.config, regs[rb].node, regs[rc].node).sons) of opcConcatStr: decodeBC(rkNode) createStr regs[ra] diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index a9ff7f2d0..176558eac 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -95,7 +95,7 @@ type opcEqRef, opcEqNimNode, opcSameNodeType, opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, - opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, + opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcIsNil, opcOf, opcIs, opcSubStr, opcParseFloat, opcConv, opcCast, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 0b8eafd17..75f673c0b 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -973,11 +973,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = case m of mAnd: c.genAndOr(n, opcFJmp, dest) of mOr: c.genAndOr(n, opcTJmp, dest) - of mUnaryLt: - let tmp = c.genx(n[1]) - if dest < 0: dest = c.getTemp(n.typ) - c.gABI(n, opcSubImmInt, dest, tmp, 1) - c.freeTemp(tmp) of mPred, mSubI: c.genAddSubInt(n, dest, opcSubInt) of mSucc, mAddI: @@ -1020,9 +1015,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.gABC(n, opcNewStr, dest, tmp) c.freeTemp(tmp) # XXX buggy - of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq: + of mLengthOpenArray, mLengthArray, mLengthSeq: genUnaryABI(c, n, dest, opcLenSeq) - of mLengthStr, mXLenStr: + of mLengthStr: genUnaryABI(c, n, dest, opcLenStr) of mIncl, mExcl: unused(c, n, dest) @@ -1078,7 +1073,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mLtF64: genBinaryABC(c, n, dest, opcLtFloat) of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu) of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu) - of mEqProc, mEqRef, mEqUntracedRef: + of mEqProc, mEqRef: genBinaryABC(c, n, dest, opcEqRef) of mXor: genBinaryABC(c, n, dest, opcXor) of mNot: genUnaryABC(c, n, dest, opcNot) @@ -1105,7 +1100,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mMulSet: genBinarySet(c, n, dest, opcMulSet) of mPlusSet: genBinarySet(c, n, dest, opcPlusSet) of mMinusSet: genBinarySet(c, n, dest, opcMinusSet) - of mSymDiffSet: genBinarySet(c, n, dest, opcSymdiffSet) of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr) of mInSet: genBinarySet(c, n, dest, opcContainsSet) of mRepr: genUnaryABC(c, n, dest, opcRepr) @@ -1126,29 +1120,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = unused(c, n, dest) c.gen(lowerSwap(c.graph, n, if c.prc == nil: c.module else: c.prc.sym)) of mIsNil: genUnaryABC(c, n, dest, opcIsNil) - of mCopyStr: - if dest < 0: dest = c.getTemp(n.typ) - var - tmp1 = c.genx(n[1]) - tmp2 = c.genx(n[2]) - tmp3 = c.getTemp(n[2].typ) - c.gABC(n, opcLenStr, tmp3, tmp1) - c.gABC(n, opcSubStr, dest, tmp1, tmp2) - c.gABC(n, opcSubStr, tmp3) - c.freeTemp(tmp1) - c.freeTemp(tmp2) - c.freeTemp(tmp3) - of mCopyStrLast: - if dest < 0: dest = c.getTemp(n.typ) - var - tmp1 = c.genx(n[1]) - tmp2 = c.genx(n[2]) - tmp3 = c.genx(n[3]) - c.gABC(n, opcSubStr, dest, tmp1, tmp2) - c.gABC(n, opcSubStr, tmp3) - c.freeTemp(tmp1) - c.freeTemp(tmp2) - c.freeTemp(tmp3) of mParseBiggestFloat: if dest < 0: dest = c.getTemp(n.typ) var d2: TRegister diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 31e133090..cc20f1dac 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1458,7 +1458,7 @@ proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = else: n == bindSym"true" # hacky solution for now when defined(nimMacrosGetNodeId): - proc nodeID*(n: NimNode): int {.magic: NodeId.} + proc nodeID*(n: NimNode): int {.magic: "NodeId".} ## Returns the id of ``n``, when the compiler has been compiled ## with the flag ``-d:useNodeids``, otherwise returns ``-1``. This ## proc is for the purpose to debug the compiler only. diff --git a/lib/system/basic_types.nim b/lib/system/basic_types.nim index a6bf69ebc..9db81d1c4 100644 --- a/lib/system/basic_types.nim +++ b/lib/system/basic_types.nim @@ -1,18 +1,18 @@ type - int* {.magic: Int.} ## Default integer type; bitwidth depends on + int* {.magic: "Int".} ## Default integer type; bitwidth depends on ## architecture, but is always the same as a pointer. - int8* {.magic: Int8.} ## Signed 8 bit integer type. - int16* {.magic: Int16.} ## Signed 16 bit integer type. - int32* {.magic: Int32.} ## Signed 32 bit integer type. - int64* {.magic: Int64.} ## Signed 64 bit integer type. - uint* {.magic: UInt.} ## Unsigned default integer type. - uint8* {.magic: UInt8.} ## Unsigned 8 bit integer type. - uint16* {.magic: UInt16.} ## Unsigned 16 bit integer type. - uint32* {.magic: UInt32.} ## Unsigned 32 bit integer type. - uint64* {.magic: UInt64.} ## Unsigned 64 bit integer type. + int8* {.magic: "Int8".} ## Signed 8 bit integer type. + int16* {.magic: "Int16".} ## Signed 16 bit integer type. + int32* {.magic: "Int32".} ## Signed 32 bit integer type. + int64* {.magic: "Int64".} ## Signed 64 bit integer type. + uint* {.magic: "UInt".} ## Unsigned default integer type. + uint8* {.magic: "UInt8".} ## Unsigned 8 bit integer type. + uint16* {.magic: "UInt16".} ## Unsigned 16 bit integer type. + uint32* {.magic: "UInt32".} ## Unsigned 32 bit integer type. + uint64* {.magic: "UInt64".} ## Unsigned 64 bit integer type. type # we need to start a new type section here, so that ``0`` can have a type - bool* {.magic: Bool.} = enum ## Built-in boolean type. + bool* {.magic: "Bool".} = enum ## Built-in boolean type. false = 0, true = 1 const From e8c057fb2729b2598b8cb62ae46f85139fb480fa Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 3 Mar 2020 16:25:59 +0100 Subject: [PATCH 0067/4254] important_packages: change the order of arguments in the template (#13577) Leads to a cleaner and less confusing code - an empty command doesn't mean 'nimble test' anymore. --- testament/categories.nim | 4 +- testament/important_packages.nim | 103 +++++++++++++++---------------- 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index f8cc625c4..9f50a4705 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -10,7 +10,7 @@ ## Include for the tester that contains test suites that test special features ## of the compiler. -# included from tester.nim +# included from testament.nim import important_packages @@ -456,10 +456,8 @@ let packageIndex = nimbleDir / "packages_official.json" iterator listPackages(): tuple[name, url, cmd: string, hasDeps: bool] = - let defaultCmd = "nimble test" let packageList = parseFile(packageIndex) for n, cmd, hasDeps, url in important_packages.packages.items: - let cmd = if cmd.len == 0: defaultCmd else: cmd if url.len != 0: yield (n, url, cmd, hasDeps) else: diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 344aff339..c90debfd6 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -1,96 +1,95 @@ -template pkg(name: string; cmd = "nimble test"; hasDeps = false; url = ""): untyped = +template pkg(name: string; hasDeps = false; cmd = "nimble test"; url = ""): untyped = packages.add((name, cmd, hasDeps, url)) var packages*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[] pkg "argparse" -pkg "arraymancer", "nim c tests/tests_cpu.nim", true -pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" -pkg "asyncmysql", "", true +pkg "arraymancer", true, "nim c tests/tests_cpu.nim" +pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" +pkg "asyncmysql", true pkg "bigints" -pkg "binaryheap", "nim c -r binaryheap.nim" +pkg "binaryheap", false, "nim c -r binaryheap.nim" # pkg "blscurve", "", true # pending https://github.com/status-im/nim-blscurve/issues/39 -pkg "bncurve", "", true -pkg "c2nim", "nim c testsuite/tester.nim" +pkg "bncurve", true +pkg "c2nim", false, "nim c testsuite/tester.nim" pkg "cascade" pkg "chroma" -pkg "chronicles", "nim c -o:chr -r chronicles.nim", true -pkg "chronos", "", true -pkg "cligen", "nim c -o:cligenn -r cligen.nim" -pkg "coco", "", true +pkg "chronicles", true, "nim c -o:chr -r chronicles.nim" +pkg "chronos", true +pkg "cligen", false, "nim c -o:cligenn -r cligen.nim" +pkg "coco", true pkg "combparser" pkg "compactdict" -pkg "comprehension", "", false, "https://github.com/alehander42/comprehension" +pkg "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" pkg "criterion" -pkg "dashing", "nim c tests/functional.nim" +pkg "dashing", false, "nim c tests/functional.nim" pkg "docopt" -pkg "easygl", "nim c -o:egl -r src/easygl.nim", true, "https://github.com/jackmott/easygl" +pkg "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" -pkg "fragments", "nim c -r fragments/dsl.nim" +pkg "fragments", false, "nim c -r fragments/dsl.nim" pkg "gara" -pkg "ggplotnim", "nimble testCI", true +pkg "ggplotnim", true, "nimble testCI" pkg "glob" pkg "gnuplot" -# pkg "godot", "nim c -r godot/godot.nim" # not yet compatible with Nim 0.19 -pkg "hts", "nim c -o:htss src/hts.nim" -pkg "illwill", "nimble examples" +pkg "hts", false, "nim c -o:htss src/hts.nim" +pkg "illwill", false, "nimble examples" pkg "inim" -pkg "itertools", "nim doc src/itertools.nim" +pkg "itertools", false, "nim doc src/itertools.nim" pkg "iterutils" pkg "jstin" -pkg "karax", "nim c -r tests/tester.nim" +pkg "karax", false, "nim c -r tests/tester.nim" pkg "loopfusion" pkg "msgpack4nim" -pkg "nake", "nim c nakefile.nim" -pkg "neo", "nim c -d:blas=openblas tests/all.nim", true +pkg "nake", false, "nim c nakefile.nim" +pkg "neo", true, "nim c -d:blas=openblas tests/all.nim" # pkg "nico", "", true -pkg "nicy", "nim c src/nicy.nim" -pkg "nigui", "nim c -o:niguii -r src/nigui.nim" -pkg "nimcrypto", "nim c -r tests/testall.nim" -pkg "NimData", "nim c -o:nimdataa src/nimdata.nim", true -pkg "nimes", "nim c src/nimes.nim", true -pkg "nimfp", "nim c -o:nfp -r src/fp.nim", true -pkg "nimgame2", "nim c nimgame2/nimgame.nim", true -pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim", true +pkg "nicy", false, "nim c src/nicy.nim" +pkg "nigui", false, "nim c -o:niguii -r src/nigui.nim" +pkg "nimcrypto", false, "nim c -r tests/testall.nim" +pkg "NimData", true, "nim c -o:nimdataa src/nimdata.nim" +pkg "nimes", true, "nim c src/nimes.nim" +pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim" +pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" +pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim" # pkg "nimlsp", "", true -pkg "nimly", "", true +pkg "nimly", true # pkg "nimongo", "nimble test_ci", true -pkg "nimpy", "nim c -r tests/nimfrompy.nim" +pkg "nimpy", false, "nim c -r tests/nimfrompy.nim" pkg "nimquery" -pkg "nimsl", "", true +pkg "nimsl", true pkg "nimsvg" # pkg "nimterop", "", true -pkg "nimx", "nim c --threads:on test/main.nim", true -pkg "norm", "nim c -r tests/tsqlite.nim", true +pkg "nimx", true, "nim c --threads:on test/main.nim" +pkg "norm", true, "nim c -r tests/tsqlite.nim" pkg "npeg" -pkg "ormin", "nim c -o:orminn ormin.nim", true +pkg "ormin", true, "nim c -o:orminn ormin.nim" pkg "parsetoml" pkg "patty" -pkg "plotly", "nim c --oldgensym:on examples/all.nim", true +pkg "plotly", true, "nim c --oldgensym:on examples/all.nim" pkg "pnm" pkg "polypbren" -pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim", true +pkg "protobuf", true, "nim c -o:protobuff -r src/protobuf.nim" pkg "rbtree" -pkg "react", "nimble example" -pkg "regex", "nim c src/regex", true -pkg "result", "nim c -r result.nim" -pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" -pkg "sdl1", "nim c -r src/sdl.nim" -pkg "sdl2_nim", "nim c -r sdl2/sdl.nim" -pkg "snip", "", false, "https://github.com/genotrance/snip" -pkg "stint", "nim c -o:stintt -r stint.nim" -pkg "strunicode", "nim c -r src/strunicode.nim", true -pkg "telebot", "nim c -o:tbot --oldgensym:on -r telebot.nim", true +pkg "react", false, "nimble example" +pkg "regex", true, "nim c src/regex" +pkg "result", false, "nim c -r result.nim" +pkg "rosencrantz", false, "nim c -o:rsncntz -r rosencrantz.nim" +pkg "sdl1", false, "nim c -r src/sdl.nim" +pkg "sdl2_nim", false, "nim c -r sdl2/sdl.nim" +pkg "snip", false, "nimble test", "https://github.com/genotrance/snip" +pkg "stint", false, "nim c -o:stintt -r stint.nim" +pkg "strunicode", true, "nim c -r src/strunicode.nim" +pkg "telebot", true, "nim c -o:tbot --oldgensym:on -r telebot.nim" pkg "tempdir" -pkg "tensordsl", "nim c -r tests/tests.nim", false, "https://krux02@bitbucket.org/krux02/tensordslnim.git" +pkg "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" pkg "tiny_sqlite" pkg "unicodedb" -pkg "unicodeplus", "", true +pkg "unicodeplus", true pkg "unpack" # pkg "winim", "", true pkg "with" pkg "ws" pkg "yaml" -pkg "zero_functional", "nim c -r test.nim" +pkg "zero_functional", false, "nim c -r test.nim" From f8175688a3b9c88b53685a35a454aeba4b2bcc5d Mon Sep 17 00:00:00 2001 From: genotrance Date: Tue, 3 Mar 2020 13:52:16 -0600 Subject: [PATCH 0068/4254] Fix docgen snippet numbering (#13507) --- compiler/docgen.nim | 2 +- lib/system/inclrtl.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index daa3a708d..6c98266b5 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -191,10 +191,10 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, initStrTable result.types result.onTestSnippet = proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) = + inc(gen.id) var d = TDocumentor(gen) var outp: AbsoluteFile if filename.len == 0: - inc(d.id) let nameOnly = splitFile(d.filename).name outp = getNimcacheDir(conf) / RelativeDir(nameOnly) / RelativeFile(nameOnly & "_snippet_" & $d.id & ".nim") diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index adbda9fd6..e84794c74 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -49,7 +49,7 @@ when defined(nimlocks): else: {.pragma: benign, gcsafe.} -template since(version, body: untyped) {.dirty.} = +template since(version, body: untyped) {.dirty, used.} = ## limitation: can't be used to annotate a template (eg typetraits.get), would ## error: cannot attach a custom pragma. when (NimMajor, NimMinor) >= version: From 8705ee7015382ac2957733dfef5e02a0831e7fb4 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 3 Mar 2020 23:03:33 +0100 Subject: [PATCH 0069/4254] ARC hotfix; proper destruction of seqs and strings after a move --- compiler/ccgexprs.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 111e1053b..277913b17 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2040,14 +2040,14 @@ proc genDestroy(p: BProc; n: PNode) = initLocExpr(p, arg, a) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #deallocShared($1.p);$n" & - " $1.p = NIM_NIL; }$n", + " $1.p = NIM_NIL; $1.len = 0; }$n", [rdLoc(a)]) of tySequence: var a: TLoc initLocExpr(p, arg, a) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #deallocShared($1.p);$n" & - " $1.p = NIM_NIL; }$n", + " $1.p = NIM_NIL; $1.len = 0; }$n", [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) else: discard "nothing to do" else: From 3ca8f0bde69d060c0b2298113aa02268c35c1550 Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 4 Mar 2020 07:15:34 +0100 Subject: [PATCH 0070/4254] [ci skip] important_packages: change the order in commented out packages too --- testament/important_packages.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index c90debfd6..9dbb4a4f9 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -11,7 +11,7 @@ pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" pkg "asyncmysql", true pkg "bigints" pkg "binaryheap", false, "nim c -r binaryheap.nim" -# pkg "blscurve", "", true # pending https://github.com/status-im/nim-blscurve/issues/39 +# pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39 pkg "bncurve", true pkg "c2nim", false, "nim c testsuite/tester.nim" pkg "cascade" @@ -44,7 +44,7 @@ pkg "loopfusion" pkg "msgpack4nim" pkg "nake", false, "nim c nakefile.nim" pkg "neo", true, "nim c -d:blas=openblas tests/all.nim" -# pkg "nico", "", true +# pkg "nico", true pkg "nicy", false, "nim c src/nicy.nim" pkg "nigui", false, "nim c -o:niguii -r src/nigui.nim" pkg "nimcrypto", false, "nim c -r tests/testall.nim" @@ -53,14 +53,14 @@ pkg "nimes", true, "nim c src/nimes.nim" pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim" pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim" -# pkg "nimlsp", "", true +# pkg "nimlsp", true pkg "nimly", true -# pkg "nimongo", "nimble test_ci", true +# pkg "nimongo", true, "nimble test_ci" pkg "nimpy", false, "nim c -r tests/nimfrompy.nim" pkg "nimquery" pkg "nimsl", true pkg "nimsvg" -# pkg "nimterop", "", true +# pkg "nimterop", true pkg "nimx", true, "nim c --threads:on test/main.nim" pkg "norm", true, "nim c -r tests/tsqlite.nim" pkg "npeg" @@ -88,7 +88,7 @@ pkg "tiny_sqlite" pkg "unicodedb" pkg "unicodeplus", true pkg "unpack" -# pkg "winim", "", true +# pkg "winim", true pkg "with" pkg "ws" pkg "yaml" From 34c16f5ecae765c014335525ef518233832832db Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 4 Mar 2020 09:50:36 +0300 Subject: [PATCH 0071/4254] fix #13409: Document as infix operator (#13570) --- doc/manual.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 71f6f73f9..516be24ea 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -559,7 +559,7 @@ following characters:: defined here.) These keywords are also operators: -``and or not xor shl shr div mod in notin is isnot of``. +``and or not xor shl shr div mod in notin is isnot of as``. `.`:tok: `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they are used for other notational purposes. @@ -632,21 +632,21 @@ has the second lowest precedence. Otherwise precedence is determined by the first character. -================ =============================================== ================== =============== -Precedence level Operators First character Terminal symbol -================ =============================================== ================== =============== - 10 (highest) ``$ ^`` OP10 - 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 - 8 ``+ -`` ``+ - ~ |`` OP8 - 7 ``&`` ``&`` OP7 - 6 ``..`` ``.`` OP6 - 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5 - 4 ``and`` OP4 - 3 ``or xor`` OP3 - 2 ``@ : ?`` OP2 - 1 *assignment operator* (like ``+=``, ``*=``) OP1 - 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 -================ =============================================== ================== =============== +================ ================================================== ================== =============== +Precedence level Operators First character Terminal symbol +================ ================================================== ================== =============== + 10 (highest) ``$ ^`` OP10 + 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 + 8 ``+ -`` ``+ - ~ |`` OP8 + 7 ``&`` ``&`` OP7 + 6 ``..`` ``.`` OP6 + 5 ``== <= < >= > != in notin is isnot not of as`` ``= < > !`` OP5 + 4 ``and`` OP4 + 3 ``or xor`` OP3 + 2 ``@ : ?`` OP2 + 1 *assignment operator* (like ``+=``, ``*=``) OP1 + 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 +================ ================================================== ================== =============== Whether an operator is used a prefix operator is also affected by preceding From 9961d1f67d623bc8a4f6bbab5714d945cbe4abc0 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 4 Mar 2020 10:25:59 +0100 Subject: [PATCH 0072/4254] fix #13531 by adding a test (#13581) --- tests/stdlib/tjson_unmarshall.nim | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/stdlib/tjson_unmarshall.nim diff --git a/tests/stdlib/tjson_unmarshall.nim b/tests/stdlib/tjson_unmarshall.nim new file mode 100644 index 000000000..69bed3ac9 --- /dev/null +++ b/tests/stdlib/tjson_unmarshall.nim @@ -0,0 +1,31 @@ +discard """ + output: ''' +Original: (kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)]) +jsonNode: {"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]} +Reversed: (kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)]) +''' +""" + +import json + +type + ContentNodeKind* = enum + P, + Br, + Text, + ContentNode* = object + case kind*: ContentNodeKind + of P: pChildren*: seq[ContentNode] + of Br: nil + of Text: textStr*: string + +let mynode = ContentNode(kind: P, pChildren: @[ + ContentNode(kind: Text, textStr: "mychild"), + ContentNode(kind: Br) +]) + +echo "Original: " & $mynode + +let jsonNode = %*mynode +echo "jsonNode: " & $jsonNode +echo "Reversed: " & $jsonNode.to(ContentNode) From 9fa070b1dc566c23b9f8c1684d33b63e9ed3b3c4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 4 Mar 2020 01:26:56 -0800 Subject: [PATCH 0073/4254] fix hintSuccess: `out` was wrong for `nim doc` without `-o` flag (#13569) --- compiler/docgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6c98266b5..064bdc93e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1135,8 +1135,8 @@ proc generateIndex*(d: PDoc) = proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html - if d.conf.outFile.isEmpty and not d.conf.outDir.isEmpty: - d.conf.outFile = outfile.relativeTo(d.conf.outDir) + if d.conf.outDir.isEmpty: d.conf.outDir = d.conf.projectPath + if d.conf.outFile.isEmpty: d.conf.outFile = outfile.relativeTo(d.conf.outDir) proc writeOutput*(d: PDoc, useWarning = false) = runAllExamples(d) From 0809098971080674f723cb219722487e42011fd1 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 4 Mar 2020 06:27:52 -0300 Subject: [PATCH 0074/4254] Nimpretty Fix negative indent breaks code (#13580) --- changelog.md | 1 + nimpretty/nimpretty.nim | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index e0fd64942..87bf8bd08 100644 --- a/changelog.md +++ b/changelog.md @@ -126,6 +126,7 @@ ### Tool changes +- Fix Nimpretty must not accept negative indentation argument because breaks file. ### Compiler changes diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index 95f428598..50d0d725f 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -44,8 +44,8 @@ proc writeVersion() = type PrettyOptions = object - indWidth: int - maxLineLen: int + indWidth: Natural + maxLineLen: Positive proc prettyPrint(infile, outfile: string, opt: PrettyOptions) = var conf = newConfigRef() From 614fb7567c80c3b071394714c3809c005aaad397 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 4 Mar 2020 13:46:42 +0100 Subject: [PATCH 0075/4254] std/compilesettings implementation (#13584) * Implement compileSetting() and compileSettingSeq() * Change from magic to vmop * better design for querySetting Co-authored-by: genotrance --- changelog.md | 12 ++++++++ compiler/vmops.nim | 33 ++++++++++++++++++++++ lib/std/compilesettings.nim | 54 ++++++++++++++++++++++++++++++++++++ tests/vm/tcompilesetting.nim | 19 +++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 lib/std/compilesettings.nim create mode 100644 tests/vm/tcompilesetting.nim diff --git a/changelog.md b/changelog.md index 87bf8bd08..ccc969ca6 100644 --- a/changelog.md +++ b/changelog.md @@ -78,10 +78,22 @@ ```nim +type + Foo = object + col, pos: string +proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) +proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) + +var f: Foo +with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) +echo f ``` + - Added `times.isLeapDay` +- Added a new module, `std / compilesettings` for querying the compiler about + diverse configuration settings. ## Library changes diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 1e3a258f3..8cb2a0552 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -102,6 +102,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode = result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord), newStrNode(nkStrLit, f)) +from std / compilesettings import SingleValueSetting, MultipleValueSetting + +proc querySettingImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): string = + case SingleValueSetting(switch) + of arguments: result = conf.arguments + of outFile: result = conf.outFile.string + of outDir: result = conf.outDir.string + of nimcacheDir: result = conf.nimcacheDir.string + of projectName: result = conf.projectName + of projectPath: result = conf.projectPath.string + of projectFull: result = conf.projectFull.string + of command: result = conf.command + of commandLine: result = conf.commandLine + of linkOptions: result = conf.linkOptions + of compileOptions: result = conf.compileOptions + of ccompilerPath: result = conf.cCompilerPath + +proc querySettingSeqImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): seq[string] = + template copySeq(field: untyped): untyped = + for i in field: result.add i.string + + case MultipleValueSetting(switch) + of nimblePaths: copySeq(conf.nimblePaths) + of searchPaths: copySeq(conf.searchPaths) + of lazyPaths: copySeq(conf.lazyPaths) + of commandArgs: result = conf.commandArgs + of cincludes: copySeq(conf.cIncludes) + of clibs: copySeq(conf.cLibs) + proc registerAdditionalOps*(c: PCtx) = proc gorgeExWrapper(a: VmArgs) = let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), @@ -152,6 +181,10 @@ proc registerAdditionalOps*(c: PCtx) = systemop getCurrentException registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) + registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} = + setResult(a, querySettingImpl(a, c.config, getInt(a, 0))) + registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} = + setResult(a, querySettingSeqImpl(a, c.config, getInt(a, 0))) if defined(nimsuggest) or c.config.cmd == cmdCheck: discard "don't run staticExec for 'nim suggest'" diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim new file mode 100644 index 000000000..12204658d --- /dev/null +++ b/lib/std/compilesettings.nim @@ -0,0 +1,54 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Nim Contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module allows querying the compiler about +## diverse configuration settings. + +# Note: Only add new enum values at the end to ensure binary compatibility with +# other Nim compiler versions! + +type + SingleValueSetting* {.pure.} = enum ## \ + ## settings resulting in a single string value + arguments, ## experimental: the arguments passed after '-r' + outFile, ## experimental: the output file + outDir, ## the output directory + nimcacheDir, ## the location of the 'nimcache' directory + projectName, ## the project's name that is being compiled + projectPath, ## experimental: some path to the project that is being compiled + projectFull, ## the full path to the project that is being compiled + command, ## experimental: the command (e.g. 'c', 'cpp', 'doc') passed to + ## the Nim compiler + commandLine, ## experimental: the command line passed to Nim + linkOptions, ## additional options passed to the linker + compileOptions, ## additional options passed to the C/C++ compiler + ccompilerPath ## the path to the C/C++ compiler + + MultipleValueSetting* {.pure.} = enum ## \ + ## settings resulting in a seq of string values + nimblePaths, ## the nimble path(s) + searchPaths, ## the search path for modules + lazyPaths, ## experimental: even more paths + commandArgs, ## the arguments passed to the Nim compiler + cincludes, ## the #include paths passed to the C/C++ compiler + clibs ## libraries passed to the C/C++ compiler + +proc querySetting*(setting: SingleValueSetting): string {. + compileTime, noSideEffect.} = discard + ## Can be used to get a string compile-time option. Example: + ## + ## .. code-block:: Nim + ## const nimcache = querySetting(SingleValueSetting.nimcacheDir) + +proc querySettingSeq*(setting: MultipleValueSetting): seq[string] {. + compileTime, noSideEffect.} = discard + ## Can be used to get a multi-string compile-time option. Example: + ## + ## .. code-block:: Nim + ## const nimblePaths = compileSettingSeq(MultipleValueSetting.nimblePaths) diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim new file mode 100644 index 000000000..0e936d377 --- /dev/null +++ b/tests/vm/tcompilesetting.nim @@ -0,0 +1,19 @@ +discard """ +cmd: "nim c --nimcache:myNimCache --nimblePath:myNimblePath $file" +joinable: false +""" + +import strutils + +import std / compilesettings + +const + nc = querySetting(nimcacheDir) + np = querySettingSeq(nimblePaths) + +static: + echo nc + echo np + +doAssert "myNimCache" in nc +doAssert "myNimblePath" in np[0] From a0eca7518223a18f3633150de2c8d3c1c9e71560 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 4 Mar 2020 14:28:53 +0100 Subject: [PATCH 0076/4254] sink parameter inference for types that have destructors (#13544) * ensure capitalize doesn't take an inferred sink parameter * sink parameter inference: first version, for now disabled. Changed that sink parameters can be consumed multiple times in order to adhere to our spec. * sink inference can now be disabled with .nosinks; sometimes for proc type interop this is required * fixes yet another critical DFA bug * better implementation that also understands if expressions etc * document sink parameter inference and allow for global disabling --- changelog.md | 4 +- compiler/ast.nim | 9 +++- compiler/commands.nim | 2 + compiler/condsyms.nim | 2 + compiler/dfa.nim | 2 + compiler/injectdestructors.nim | 12 ++--- compiler/options.nim | 7 +-- compiler/pragmas.nim | 8 +++- compiler/sempass2.nim | 22 +++++++-- compiler/semstmts.nim | 2 + compiler/sinkparameter_inference.nim | 70 ++++++++++++++++++++++++++++ compiler/wordrecg.nim | 8 ++-- doc/advopt.txt | 3 +- doc/destructors.rst | 17 +++++++ lib/pure/unicode.nim | 2 +- lib/system/assertions.nim | 4 +- tests/assert/tassert_c.nim | 4 +- tests/destructor/tarc2.nim | 4 ++ tests/destructor/tconsume_twice.nim | 4 +- 19 files changed, 158 insertions(+), 28 deletions(-) create mode 100644 compiler/sinkparameter_inference.nim diff --git a/changelog.md b/changelog.md index ccc969ca6..63296ce04 100644 --- a/changelog.md +++ b/changelog.md @@ -127,7 +127,6 @@ echo f - `=sink` type bound operator is now optional. Compiler can now use combination of `=destroy` and `copyMem` to move objects efficiently. - ## Language changes - Unsigned integer operators have been fixed to allow promotion of the first operand. @@ -150,6 +149,9 @@ echo f - The Nim compiler now supports a new pragma called ``.localPassc`` to pass specific compiler options to the C(++) backend for the C(++) file that was produced from the current Nim module. +- The compiler now inferes "sink parameters". To disable this for a specific routine, + annotate it with `.nosinks`. To disable it for a section of code, use + `{.push sinkInference: off.}`...`{.pop.}`. ## Bugfixes diff --git a/compiler/ast.nim b/compiler/ast.nim index 3b10a89ea..43ea2b39c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -229,7 +229,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 40 flags! + TSymFlag* = enum # 41 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -238,6 +238,8 @@ type sfGlobal, # symbol is at global scope sfForward, # symbol is forward declared + sfWasForwarded, # symbol had a forward declaration + # (implies it's too dangerous to patch its type signature) sfImportc, # symbol is external; imported sfExportc, # symbol is exported (under a specified name) sfMangleCpp, # mangle as cpp (combines with `sfExportc`) @@ -847,7 +849,7 @@ type position*: int # used for many different things: # for enum fields its position; # for fields its offset - # for parameters its position + # for parameters its position (starting with 0) # for a conditional: # 1 iff the symbol is defined, else 0 # (or not in symbol table) @@ -1865,6 +1867,9 @@ proc isInlineIterator*(typ: PType): bool {.inline.} = proc isClosureIterator*(typ: PType): bool {.inline.} = typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure +proc isClosure*(typ: PType): bool {.inline.} = + typ.kind == tyProc and typ.callConv == ccClosure + proc isSinkParam*(s: PSym): bool {.inline.} = s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags) diff --git a/compiler/commands.nim b/compiler/commands.nim index 0545ee2b0..935d7e2be 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -877,6 +877,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info) + of "sinkinference": + processOnOffSwitch(conf, {optSinkInference}, arg, pass, info) of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) handleStdinInput(conf) else: diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index d82f4811d..a84b0d878 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -111,3 +111,5 @@ proc initDefines*(symbols: StringTableRef) = # will report the right thing regardless of whether user adds # `-d:nimHasLibFFI` in his user config. defineSymbol("nimHasLibFFIEnabled") + + defineSymbol("nimHasSinkInference") diff --git a/compiler/dfa.nim b/compiler/dfa.nim index b46db9aed..0f23d7f1a 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -591,6 +591,8 @@ proc genUse(c: var Con; orig: PNode) = of PathKinds1: n = n[1] else: break + if n.kind in nkCallKinds: + gen(c, n) if n.kind == nkSym and n.sym.kind in InterestingSyms: c.code.add Instr(n: orig, kind: use) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index bdd624281..520ba46ce 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -321,8 +321,8 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = assert s.kind == nkSym and s.sym.kind == skParam if not isLastRead(s, c): - localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & - "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) + localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & + "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) type ProcessMode = enum @@ -498,10 +498,10 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} + nkCallKinds + nkLiterals: result = p(n, c, consumed) - elif n.kind == nkSym and isSinkParam(n.sym): + elif n.kind == nkSym and isSinkParam(n.sym) and isLastRead(n, c): # Sinked params can be consumed only once. We need to reset the memory # to disable the destructor which we have not elided - sinkParamIsLastReadCheck(c, n) + #sinkParamIsLastReadCheck(c, n) result = destructiveMoveVar(n, c) elif isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): # it is the last read, can be sinkArg. We need to reset the memory @@ -687,9 +687,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: result = genSink(c, dest, p(ri, c, consumed)) of nkSym: - if isSinkParam(ri.sym): + if isSinkParam(ri.sym) and isLastRead(ri, c): # Rule 3: `=sink`(x, z); wasMoved(z) - sinkParamIsLastReadCheck(c, ri) + #sinkParamIsLastReadCheck(c, ri) let snk = genSink(c, dest, ri) result = newTree(nkStmtList, snk, genWasMoved(ri, c)) elif ri.sym.kind != skParam and ri.sym.owner == c.owner and diff --git a/compiler/options.nim b/compiler/options.nim index c93fc0648..42406272c 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -39,7 +39,8 @@ type # please make sure we have under 32 options optMemTracker, optLaxStrings, optNilSeqs, - optOldAst + optOldAst, + optSinkInference # 'sink T' inference TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** @@ -200,7 +201,7 @@ type ## the incremental compilation mechanisms ## (+) means "part of the dependency" target*: Target # (+) - linesCompiled*: int # all lines that have been compiled + linesCompiled*: int # all lines that have been compiled options*: TOptions # (+) globalOptions*: TGlobalOptions # (+) macrosToExpand*: StringTableRef @@ -315,7 +316,7 @@ const DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, - optTrMacros, optNilCheck, optStyleCheck} + optTrMacros, optNilCheck, optStyleCheck, optSinkInference} DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, optListFullPaths} diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 559c1c064..3e89917ed 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -23,7 +23,7 @@ const wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed, wAlign} ## common pragmas for declarations, to a good approximation procPragmas* = declPragmas + {FirstCallConv..LastCallConv, - wMagic, wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader, + wMagic, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader, wCompilerProc, wNonReloadable, wCore, wProcVar, wVarargs, wCompileTime, wMerge, wBorrow, wImportCompilerProc, wThread, wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, @@ -53,7 +53,7 @@ const wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto, wInjectStmt, wExperimental, wThis, wUsed} lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv, - wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader, + wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader, wThread, wAsmNoStackFrame, wRaises, wLocks, wTags, wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these? typePragmas* = declPragmas + {wMagic, wAcyclic, @@ -357,6 +357,7 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} = of wByRef: {optByRef} of wImplicitStatic: {optImplicitStatic} of wPatterns, wTrMacros: {optTrMacros} + of wSinkInference: {optSinkInference} else: {} proc processExperimental(c: PContext; n: PNode) = @@ -889,6 +890,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wNoDestroy: noVal(c, it) incl(sym.flags, sfGeneratedOp) + of wNosinks: + noVal(c, it) + incl(sym.flags, sfWasForwarded) of wDynlib: processDynLib(c, it, sym) of wCompilerProc, wCore: diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 98ef8cf85..af706bee1 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -16,6 +16,7 @@ when defined(useDfa): import dfa import liftdestructors +include sinkparameter_inference #[ Second semantic checking pass over the AST. Necessary because the old way had some inherent problems. Performs: @@ -774,6 +775,10 @@ proc track(tracked: PEffects, n: PNode) = for i in 0.. p: sink T + passToSink(p) # p: sink + ObjConstr(fieldName: p) + [p, q] # array construction + + # Open question: + var local = p # sink parameter? + passToSink(local) + ]# + if optSinkInference notin config.options: return + case arg.kind + of nkSym: + if arg.sym.kind == skParam and + arg.sym.owner == owner and + owner.typ != nil and owner.typ.kind == tyProc and + arg.sym.typ.hasDestructor and + arg.sym.typ.kind notin {tyVar, tySink, tyOwned}: + # Watch out: cannot do this inference for procs with forward + # declarations. + if sfWasForwarded notin owner.flags: + let argType = arg.sym.typ + + let sinkType = newType(tySink, owner) + sinkType.size = argType.size + sinkType.align = argType.align + sinkType.paddingAtEnd = argType.paddingAtEnd + sinkType.add argType + + arg.sym.typ = sinkType + owner.typ[arg.sym.position+1] = sinkType + + #message(config, arg.info, warnUser, + # ("turned '$1' to a sink parameter") % [$arg]) + #echo config $ arg.info, " turned into a sink parameter ", arg.sym.name.s + elif sfWasForwarded notin arg.sym.flags: + # we only report every potential 'sink' parameter only once: + incl arg.sym.flags, sfWasForwarded + message(config, arg.info, hintPerformance, + ("could not turn '$1' to a sink parameter " & + "because '$2' was forward declared") % [arg.sym.name.s, owner.name.s]) + #echo config $ arg.info, " candidate for a sink parameter here" + of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr: + if not isEmptyType(arg.typ): + checkForSink(config, owner, arg.lastSon) + of nkIfStmt, nkIfExpr, nkWhen: + for branch in arg: + let value = branch.lastSon + if not isEmptyType(value.typ): + checkForSink(config, owner, value) + of nkCaseStmt: + for i in 1.. Date: Wed, 4 Mar 2020 14:56:40 +0000 Subject: [PATCH 0077/4254] nimsuggest: don't add CRLF to replies (#13545) This is already sent by replTcp after the message is sent. --- nimsuggest/nimsuggest.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index a48e9443d..31cedb72e 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -252,10 +252,10 @@ proc toSocket(stdoutSocket: Socket) {.gcsafe.} = let res = results.recv() case res.section of ideNone: break - of ideMsg: stdoutSocket.send(res.doc & "\c\L") - of ideKnown: stdoutSocket.send($(res.quality == 1) & "\c\L") - of ideProject: stdoutSocket.send(res.filePath & "\c\L") - else: stdoutSocket.send($res & "\c\L") + of ideMsg: stdoutSocket.send(res.doc) + of ideKnown: stdoutSocket.send($(res.quality == 1)) + of ideProject: stdoutSocket.send(res.filePath) + else: stdoutSocket.send($res) proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = var list = newSList() From 357edd86b429dfaa3c24dedabdad0eb68915616f Mon Sep 17 00:00:00 2001 From: Varriount Date: Wed, 4 Mar 2020 14:44:42 -0500 Subject: [PATCH 0078/4254] fix nightlies builds on Windows (#13587) Before the files that should have been ignored weren't ignored because of different dir separator ('\' vs '/') on Windows. --- tools/kochdocs.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 4a07b7fd9..a5166973a 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,6 +1,6 @@ ## Part of 'koch' responsible for the documentation generation. -import os, strutils, osproc, sets +import os, strutils, osproc, sets, pathnorm const gaCode* = " --doc.googleAnalytics:UA-48159761-1" @@ -195,11 +195,11 @@ lib/system/widestrs.nim a.isRelativeTo("lib/pure/includes") or a.isRelativeTo("lib/genode") or a.isRelativeTo("lib/deprecated") or - (a.isRelativeTo("lib/system") and a notin goodSystem) or - a in docIgnore: + (a.isRelativeTo("lib/system") and a.replace('\\', '/') notin goodSystem) or + a.replace('\\', '/') in docIgnore: continue result.add a - result.add "nimsuggest/sexp.nim" + result.add normalizePath("nimsuggest/sexp.nim") let doc = getDocList() From 62c113ebc7ba6fa1594b24158a6cc3e1170f4030 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 5 Mar 2020 15:31:22 +0100 Subject: [PATCH 0079/4254] fix #13579 joinPath("/foo/", "../a") is now /a (#13586) --- compiler/pathutils.nim | 2 ++ lib/pure/os.nim | 1 + lib/pure/pathnorm.nim | 5 +++++ tests/stdlib/tos.nim | 13 +++++++++++++ 4 files changed, 21 insertions(+) diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 1c35eb0b2..888e0a572 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -102,6 +102,8 @@ when true: when isMainModule: doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" + doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" + doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim" doAssert $RelativeDir"foo/bar" == "foo/bar" doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar" diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 3db518273..ba092da05 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -127,6 +127,7 @@ template endsWith(a: string, b: set[char]): bool = proc joinPathImpl(result: var string, state: var int, tail: string) = let trailingSep = tail.endsWith({DirSep, AltSep}) or tail.len == 0 and result.endsWith({DirSep, AltSep}) + normalizePathEnd(result, trailingSep=false) addNormalizePath(tail, result, state, DirSep) normalizePathEnd(result, trailingSep=trailingSep) diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 3659e85e6..8763ba878 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -76,6 +76,11 @@ proc addNormalizePath*(x: string; result: var string; state: var int; if (state shr 1) >= 1: var d = result.len # f/.. + # We could handle stripping trailing sep here: foo// => foo like this: + # while (d-1) > (state and 1) and result[d-1] in {DirSep, AltSep}: dec d + # but right now we instead handle it inside os.joinPath + + # strip path component: foo/bar => foo while (d-1) > (state and 1) and result[d-1] notin {DirSep, AltSep}: dec d if d > 0: diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index c649749e3..d713bfe0c 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -389,6 +389,19 @@ block ospaths: doAssert joinPath("foo", "./") == unixToNativePath"foo/" doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/" + # issue #13579 + doAssert joinPath("/foo", "../a") == unixToNativePath"/a" + doAssert joinPath("/foo/", "../a") == unixToNativePath"/a" + doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a" + doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a" + doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/" + doAssert joinPath("foo/", "../a") == unixToNativePath"a" + + when doslikeFileSystem: + doAssert joinPath("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", "..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + doAssert joinPath("C:\\foo", "..\\a") == r"C:\a" + doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a" + block getTempDir: block TMPDIR: # TMPDIR env var is not used if either of these are defined. From 83e715c5b6b2501c02459398a2f394c457758a55 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 5 Mar 2020 16:02:34 +0100 Subject: [PATCH 0080/4254] fixes #5170 (#13589) * fixes #5170 * make tests green --- compiler/semstmts.nim | 2 ++ compiler/sighashes.nim | 19 +++++++++---------- tests/errmsgs/tsigmatch.nim | 6 +++--- tests/errmsgs/tsigmatch2.nim | 4 ++-- tests/types/tissues_types.nim | 30 ++++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4d4f70245..b91e93025 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1298,6 +1298,8 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = checkConstructedType(c.config, s.info, s.typ) if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil: checkForMetaFields(c, s.typ.n) + # fix bug #5170: ensure locally scoped object types get a unique name: + if s.typ.kind == tyObject and not isTopLevel(c): incl(s.flags, sfGenSym) #instAllTypeBoundOp(c, n.info) diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index f94cd5bce..0902a839b 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -35,6 +35,7 @@ type CoIgnoreRange CoConsiderOwned CoDistinct + CoHashTypeInsideNode proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) @@ -61,7 +62,7 @@ proc hashTypeSym(c: var MD5Context, s: PSym) = c &= "." it = it.owner -proc hashTree(c: var MD5Context, n: PNode) = +proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) = if n == nil: c &= "\255" return @@ -75,6 +76,8 @@ proc hashTree(c: var MD5Context, n: PNode) = c &= n.ident.s of nkSym: hashSym(c, n.sym) + if CoHashTypeInsideNode in flags and n.sym.typ != nil: + hashType(c, n.sym.typ, flags) of nkCharLit..nkUInt64Lit: let v = n.intVal lowlevel v @@ -84,7 +87,7 @@ proc hashTree(c: var MD5Context, n: PNode) = of nkStrLit..nkTripleStrLit: c &= n.strVal else: - for i in 0.. Date: Thu, 5 Mar 2020 21:03:39 +0100 Subject: [PATCH 0081/4254] Removed simpleGetOrDefault (#13590) --- lib/pure/json.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 82923ced0..beb3f7049 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -523,8 +523,10 @@ proc getOrDefault*(node: JsonNode, key: string): JsonNode = if not isNil(node) and node.kind == JObject: result = node.fields.getOrDefault(key) -template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, - key: string): JsonNode = node.getOrDefault(key) +proc `{}`*(node: JsonNode, key: string): JsonNode = + ## Gets a field from a `node`. If `node` is nil or not an object or + ## value at `key` does not exist, returns nil + node.getOrDefault(key) proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) = ## Traverses the node and tries to set the value at the given location From b80d293a3f8c301a2d9188fb409162028a00edca Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 5 Mar 2020 23:55:53 -0800 Subject: [PATCH 0082/4254] close #12704 by adding a test (tuple codegen error) (#13592) * close #12704 by adding a test * move test to tests/metatype/ttypedesc2.nim --- tests/metatype/ttypedesc2.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/metatype/ttypedesc2.nim b/tests/metatype/ttypedesc2.nim index 89c38f367..96dab9052 100644 --- a/tests/metatype/ttypedesc2.nim +++ b/tests/metatype/ttypedesc2.nim @@ -35,9 +35,23 @@ type Point[T] = tuple[x, y: T] proc origin(T: typedesc): Point[T] = discard discard origin(int) +block: # issue #12704 + const a = $("a", "b") + proc fun() = + const str = $int + let b = $(str, "asdf") + fun() + # https://github.com/nim-lang/Nim/issues/7516 import typetraits +block: #issue #12704 + const a = $("a", "b") + proc fun() = + const str = name(int) + let b = $(str, "asdf") + fun() + proc hasDefault1(T: type = int): auto = return T.name doAssert hasDefault1(int) == "int" doAssert hasDefault1(string) == "string" From ec8a17cc861c8282ae33ae36030d1702e41b275a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 22 Feb 2020 11:46:24 +0000 Subject: [PATCH 0083/4254] Revert broken asynchttpserver FutureStream additions. As discussed in #13394, these changes cannot work. Reverted via ``` git revert --no-commit 5bf571f061d53d35aab727f420afd9f415987723 git revert --no-commit abd660c407d00d0c4f2129ff11bfc69badda8ece git revert --no-commit 955465e5f42b1353f69f3bd884908a7ef91ce13b git commit ``` --- changelog.md | 2 - lib/pure/asynchttpserver.nim | 172 ++++++----------------------------- 2 files changed, 29 insertions(+), 145 deletions(-) diff --git a/changelog.md b/changelog.md index 63296ce04..52406a972 100644 --- a/changelog.md +++ b/changelog.md @@ -98,8 +98,6 @@ echo f ## Library changes -- `asynchttpserver` added an iterator that allows the request body to be read in - chunks of data when new server "stream" option is set to true. - `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` and only returns once all pending async operations are guaranteed to have completed. - `asyncdispatch.drain` now consistently uses the passed timeout value for all diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 9aed0255b..186f0da41 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -29,129 +29,43 @@ ## await req.respond(Http200, "Hello World") ## ## waitFor server.serve(Port(8080), cb) -## -## Basic Post request handle -## ========================= -## -## This example will create an HTTP server on port 8080. The server will -## respond with a page with the actual and expected body length after -## submitting a file. -## -## .. code-block::nim -## import asynchttpserver, asyncdispatch -## import strutils, strformat -## -## const stream = true # for test purposes switch from true to false -## -## proc htmlpage(contentLength, bodyLength: int): string = -## return &""" -## -## -## -## -## -## File:
-## -##
-## Expected Body Length: {contentLength} bytes
-## Actual Body Length: {bodyLength} bytes -## -## -## """ -## -## proc cb(req: Request) {.async.} = -## var -## contentLength = 0 -## bodyLength = 0 -## if req.reqMethod == HttpPost: -## contentLength = req.headers["Content-length"].parseInt -## if stream: -## # Read 8*1024 bytes at a time -## # optional chunkSize parameter. The default is 8*1024 -## for length, data in req.bodyStream(8*1024): -## let content = await data -## if length == content.len: -## bodyLength += content.len -## else: -## # Handle exception -## await req.respond(Http400, -## "Bad Request. Data read has a different length than the expected.") -## return -## else: -## bodyLength += req.body.len -## await req.respond(Http200, htmlpage(contentLength, bodyLength)) -## -## let server = newAsyncHttpServer(maxBody = 10485760, stream = stream) # 10 MB -## waitFor server.serve(Port(8080), cb) import tables, asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore export httpcore except parseHeader +const + maxLine = 8*1024 + # TODO: If it turns out that the decisions that asynchttpserver makes # explicitly, about whether to close the client sockets or upgrade them are # wrong, then add a return value which determines what to do for the callback. # Also, maybe move `client` out of `Request` object and into the args for # the proc. +type + Request* = object + client*: AsyncSocket # TODO: Separate this into a Response object? + reqMethod*: HttpMethod + headers*: HttpHeaders + protocol*: tuple[orig: string, major, minor: int] + url*: Uri + hostname*: string ## The hostname of the client that made the request. + body*: string -const - maxLine = 8*1024 + AsyncHttpServer* = ref object + socket: AsyncSocket + reuseAddr: bool + reusePort: bool + maxBody: int ## The maximum content-length that will be read for the body. -when (NimMajor, NimMinor) >= (1, 1): - type - Request* = object - client*: AsyncSocket # TODO: Separate this into a Response object? - reqMethod*: HttpMethod - headers*: HttpHeaders - protocol*: tuple[orig: string, major, minor: int] - url*: Uri - hostname*: string ## The hostname of the client that made the request. - body*: string - contentLength*: int - - type - AsyncHttpServer* = ref object - socket: AsyncSocket - reuseAddr: bool - reusePort: bool - maxBody: int ## The maximum content-length that will be read for the body. - stream: bool ## By default (stream = false), the body of the request is read immediately -else: - type - Request* = object - client*: AsyncSocket # TODO: Separate this into a Response object? - reqMethod*: HttpMethod - headers*: HttpHeaders - protocol*: tuple[orig: string, major, minor: int] - url*: Uri - hostname*: string ## The hostname of the client that made the request. - body*: string - - type - AsyncHttpServer* = ref object - socket: AsyncSocket - reuseAddr: bool - reusePort: bool - maxBody: int ## The maximum content-length that will be read for the body. - -when (NimMajor, NimMinor) >= (1, 1): - proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, - maxBody = 8388608, stream = false): AsyncHttpServer = - ## Creates a new ``AsyncHttpServer`` instance. - new result - result.reuseAddr = reuseAddr - result.reusePort = reusePort - result.maxBody = maxBody - result.stream = stream -else: - proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, +proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = - ## Creates a new ``AsyncHttpServer`` instance. - new result - result.reuseAddr = reuseAddr - result.reusePort = reusePort - result.maxBody = maxBody + ## Creates a new ``AsyncHttpServer`` instance. + new result + result.reuseAddr = reuseAddr + result.reusePort = reusePort + result.maxBody = maxBody proc addHeaders(msg: var string, headers: HttpHeaders) = for k, v in headers: @@ -214,30 +128,13 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = proc sendStatus(client: AsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L\c\L") -when (NimMajor, NimMinor) >= (1, 1): - iterator bodyStream*( - request: Request, - chunkSize: int = 8*1024): (int, Future[string]) = - ## The chunkSize parameter is optional and default value is 8*1024 bytes. - ## - ## This iterator return a tuple with the length of the data that was read - ## and a future. - var remainder = request.contentLength - while remainder > 0: - let readSize = min(remainder, chunkSize) - let data = request.client.recv(readSize) - if data.failed: - raise newException(ValueError, "Error reading POST data from client.") - yield (readSize, data) - remainder -= readSize - proc processRequest( server: AsyncHttpServer, req: FutureVar[Request], client: AsyncSocket, address: string, lineFut: FutureVar[string], - callback: proc (request: Request): Future[void] {.closure, gcsafe.} + callback: proc (request: Request): Future[void] {.closure, gcsafe.}, ): Future[bool] {.async.} = # Alias `request` to `req.mget()` so we don't have to write `mget` everywhere. @@ -248,12 +145,10 @@ proc processRequest( # Header: val # \n request.headers.clear() + request.body = "" request.hostname.shallowCopy(address) assert client != nil request.client = client - request.body = "" - when (NimMajor, NimMinor) >= (1, 1): - request.contentLength = 0 # We should skip at least one empty line before the request # https://tools.ietf.org/html/rfc7230#section-3.5 @@ -348,19 +243,10 @@ proc processRequest( if contentLength > server.maxBody: await request.respondError(Http413) return false - - when (NimMajor, NimMinor) >= (1, 1): - request.contentLength = contentLength - if not server.stream: - request.body = await client.recv(contentLength) - if request.body.len != contentLength: - await request.respond(Http400, "Bad Request. Content-Length does not match actual.") - return true - else: - request.body = await client.recv(contentLength) - if request.body.len != contentLength: - await request.respond(Http400, "Bad Request. Content-Length does not match actual.") - return true + request.body = await client.recv(contentLength) + if request.body.len != contentLength: + await request.respond(Http400, "Bad Request. Content-Length does not match actual.") + return true elif request.reqMethod == HttpPost: await request.respond(Http411, "Content-Length required.") return true From 4bd388ad58ba246dce74aaa41b617b7cad0fff36 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 6 Mar 2020 18:29:28 +0000 Subject: [PATCH 0084/4254] Revert "nimsuggest: don't add CRLF to replies (#13545)" (#13597) This reverts commit a974684b149faa19645f1e18b7b11aa67f169997. The CRLF was to separate between each response, and removing them causes the responses to not be splitted correctly. I didn't notice that it was in a loop when I made the #13545. --- nimsuggest/nimsuggest.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 31cedb72e..a48e9443d 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -252,10 +252,10 @@ proc toSocket(stdoutSocket: Socket) {.gcsafe.} = let res = results.recv() case res.section of ideNone: break - of ideMsg: stdoutSocket.send(res.doc) - of ideKnown: stdoutSocket.send($(res.quality == 1)) - of ideProject: stdoutSocket.send(res.filePath) - else: stdoutSocket.send($res) + of ideMsg: stdoutSocket.send(res.doc & "\c\L") + of ideKnown: stdoutSocket.send($(res.quality == 1) & "\c\L") + of ideProject: stdoutSocket.send(res.filePath & "\c\L") + else: stdoutSocket.send($res & "\c\L") proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = var list = newSList() From 7ae081181831dcfe8ab83811f2b209c552c61fc7 Mon Sep 17 00:00:00 2001 From: Andrea Ferretti Date: Fri, 6 Mar 2020 19:38:56 +0100 Subject: [PATCH 0085/4254] Fix #13573 and #13574 (#13575) * Fix https://github.com/nim-lang/Nim/issues/13573 and https://github.com/nim-lang/Nim/issues/13574 * Restored asynchttpserver --- lib/pure/httpcore.nim | 12 ++++++++---- tests/stdlib/thttpcore.nim | 7 ++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 1e9a85a57..e6e0d35c4 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -105,11 +105,15 @@ proc newHttpHeaders*(): HttpHeaders = proc newHttpHeaders*(keyValuePairs: openArray[tuple[key: string, val: string]]): HttpHeaders = - var pairs: seq[tuple[key: string, val: seq[string]]] = @[] - for pair in keyValuePairs: - pairs.add((pair.key.toLowerAscii(), @[pair.val])) new result - result.table = newTable[string, seq[string]](pairs) + result.table = newTable[string, seq[string]]() + for pair in keyValuePairs: + let key = pair.key.toLowerAscii() + if key in result.table: + result.table[key].add(pair.val) + else: + result.table[key] = @[pair.val] + proc `$`*(headers: HttpHeaders): string = return $headers.table diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index 889c734c5..f96fcc3b8 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -4,7 +4,7 @@ output: "[Suite] httpcore" import unittest -import httpcore +import httpcore, strutils suite "httpcore": @@ -29,3 +29,8 @@ suite "httpcore": assert "baR" in h["cookiE"] h.del("coOKie") assert h.len == 0 + + # Test that header constructor works with repeated values + let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"}) + + assert seq[string](h1["a"]).join(",") == "1,2,3" From e056298ceb0fbddf6190f1b97f415b61323d446c Mon Sep 17 00:00:00 2001 From: Zed Date: Fri, 6 Mar 2020 19:55:45 +0100 Subject: [PATCH 0086/4254] Implement file streaming for httpclient's MultipartData (#12982) * Add `uploadFile` to POST files by streaming them * Use constant for \c\L * Formatting * Remove uploadFile * Implement MultipartData file streaming * Remove unnecessary var annotations * Call string on TaintedStrings Fixes #12789 * Move cl constant to httpcore * Fix `request` inconsistencies * Update documentaion * Clean up * Skip multipart formatting when there's 0 entries * Remove extraneous `cl` from multipart formatting * Update MultipartData `$` to match old behaviour * Update comment * Address comments --- lib/pure/httpclient.nim | 348 ++++++++++++++++++++++++---------------- lib/pure/httpcore.nim | 1 + 2 files changed, 207 insertions(+), 142 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 7c062c2e1..b7bdc8d17 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -52,6 +52,19 @@ ## ## echo client.postContent("http://validator.w3.org/check", multipart=data) ## +## To stream files from disk when performing the request, use ``addFiles``. +## +## **Note:** This will allocate a new ``Mimetypes`` database every time you call +## it, you can pass your own via the ``mimeDb`` parameter to avoid this. +## +## .. code-block:: Nim +## let mimes = newMimetypes() +## var client = newHttpClient() +## var data = newMultipartData() +## data.addFiles({"uploaded_file": "test.html"}, mimeDb = mimes) +## +## echo client.postContent("http://validator.w3.org/check", multipart=data) +## ## You can also make post requests with custom headers. ## This example sets ``Content-Type`` to ``application/json`` ## and uses a json object for the body @@ -177,7 +190,7 @@ include "system/inclrtl" -import net, strutils, uri, parseutils, base64, os, mimetypes, +import net, strutils, uri, parseutils, base64, os, mimetypes, streams, math, random, httpcore, times, tables, streams, std/monotimes import asyncnet, asyncdispatch, asyncfile import nativesockets @@ -252,9 +265,18 @@ type url*: Uri auth*: string + MultipartEntry = object + name, content: string + case isFile: bool + of true: + filename, contentType: string + fileSize: int64 + isStream: bool + else: discard + MultipartEntries* = openArray[tuple[name, content: string]] MultipartData* = ref object - content: seq[string] + content: seq[MultipartEntry] ProtocolError* = object of IOError ## exception that is raised when server ## does not conform to the implemented @@ -278,7 +300,6 @@ proc fileError(msg: string) = e.msg = msg raise e - when not defined(ssl): type SslContext = ref object var defaultSslContext {.threadvar.}: SslContext @@ -297,24 +318,28 @@ proc newProxy*(url: string, auth = ""): Proxy = proc newMultipartData*: MultipartData = ## Constructs a new ``MultipartData`` object. - MultipartData(content: @[]) - + MultipartData() proc `$`*(data: MultipartData): string {.since: (1, 1).} = ## convert MultipartData to string so it's human readable when echo ## see https://github.com/nim-lang/Nim/issues/11863 - const prefixLen = "Content-Disposition: form-data; ".len - for pos, item in data.content: - result &= "------------------------------ " - result.addInt pos - result &= " ------------------------------\n" - result &= item[prefixLen .. item.high] - -proc add*(p: var MultipartData, name, content: string, filename: string = "", - contentType: string = "") = - ## Add a value to the multipart data. Raises a `ValueError` exception if - ## `name`, `filename` or `contentType` contain newline characters. + const sep = "-".repeat(30) + for pos, entry in data.content: + result.add(sep & center($pos, 3) & sep) + result.add("\nname=\"" & entry.name & "\"") + if entry.isFile: + result.add("; filename=\"" & entry.filename & "\"\n") + result.add("Content-Type: " & entry.contentType) + result.add("\n\n" & entry.content & "\n") +proc add*(p: MultipartData, name, content: string, filename: string = "", + contentType: string = "", useStream = true) = + ## Add a value to the multipart data. + ## + ## When ``useStream`` is ``false``, the file will be read into memory. + ## + ## Raises a ``ValueError`` exception if + ## ``name``, ``filename`` or ``contentType`` contain newline characters. if {'\c', '\L'} in name: raise newException(ValueError, "name contains a newline character") if {'\c', '\L'} in filename: @@ -322,19 +347,22 @@ proc add*(p: var MultipartData, name, content: string, filename: string = "", if {'\c', '\L'} in contentType: raise newException(ValueError, "contentType contains a newline character") - var str = "Content-Disposition: form-data; name=\"" & name & "\"" - if filename.len > 0: - str.add("; filename=\"" & filename & "\"") - str.add("\c\L") - if contentType.len > 0: - str.add("Content-Type: " & contentType & "\c\L") - str.add("\c\L" & content & "\c\L") + var entry = MultipartEntry( + name: name, + content: content, + isFile: filename.len > 0 + ) - p.content.add(str) + if entry.isFile: + entry.isStream = useStream + entry.filename = filename + entry.contentType = contentType -proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData + p.content.add(entry) + +proc add*(p: MultipartData, xs: MultipartEntries): MultipartData {.discardable.} = - ## Add a list of multipart entries to the multipart data `p`. All values are + ## Add a list of multipart entries to the multipart data ``p``. All values are ## added without a filename and without a content type. ## ## .. code-block:: Nim @@ -344,70 +372,77 @@ proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData result = p proc newMultipartData*(xs: MultipartEntries): MultipartData = - ## Create a new multipart data object and fill it with the entries `xs` + ## Create a new multipart data object and fill it with the entries ``xs`` ## directly. ## ## .. code-block:: Nim ## var data = newMultipartData({"action": "login", "format": "json"}) - result = MultipartData(content: @[]) - result.add(xs) + result = MultipartData() + for entry in xs: + result.add(entry.name, entry.content) -proc addFiles*(p: var MultipartData, xs: openArray[tuple[name, file: string]]): - MultipartData {.discardable.} = - ## Add files to a multipart data object. The file will be opened from your - ## disk, read and sent with the automatically determined MIME type. Raises an - ## `IOError` if the file cannot be opened or reading fails. To manually - ## specify file content, filename and MIME type, use `[]=` instead. +proc addFiles*(p: MultipartData, xs: openArray[tuple[name, file: string]], + mimeDb = newMimetypes(), useStream = true): + MultipartData {.discardable.} = + ## Add files to a multipart data object. The files will be streamed from disk + ## when the request is being made. When ``stream`` is ``false``, the files are + ## instead read into memory, but beware this is very memory ineffecient even + ## for small files. The MIME types will automatically be determined. + ## Raises an ``IOError`` if the file cannot be opened or reading fails. To + ## manually specify file content, filename and MIME type, use ``[]=`` instead. ## ## .. code-block:: Nim ## data.addFiles({"uploaded_file": "public/test.html"}) - var m = newMimetypes() for name, file in xs.items: var contentType: string let (_, fName, ext) = splitFile(file) if ext.len > 0: - contentType = m.getMimetype(ext[1..ext.high], "") - p.add(name, readFile(file).string, fName & ext, contentType) + contentType = mimeDb.getMimetype(ext[1..ext.high], "") + let content = if useStream: file else: readFile(file).string + p.add(name, content, fName & ext, contentType, useStream = useStream) result = p -proc `[]=`*(p: var MultipartData, name, content: string) = - ## Add a multipart entry to the multipart data `p`. The value is added +proc `[]=`*(p: MultipartData, name, content: string) = + ## Add a multipart entry to the multipart data ``p``. The value is added ## without a filename and without a content type. ## ## .. code-block:: Nim ## data["username"] = "NimUser" p.add(name, content) -proc `[]=`*(p: var MultipartData, name: string, +proc `[]=`*(p: MultipartData, name: string, file: tuple[name, contentType, content: string]) = - ## Add a file to the multipart data `p`, specifying filename, contentType and - ## content manually. + ## Add a file to the multipart data ``p``, specifying filename, contentType + ## and content manually. ## ## .. code-block:: Nim ## data["uploaded_file"] = ("test.html", "text/html", ## "

test

") - p.add(name, file.content, file.name, file.contentType) + p.add(name, file.content, file.name, file.contentType, useStream = false) -proc format(p: MultipartData): tuple[contentType, body: string] = - if p == nil or p.content.len == 0: - return ("", "") - - # Create boundary that is not in the data to be formatted - var bound: string +proc getBoundary(p: MultipartData): string = + if p == nil or p.content.len == 0: return while true: - bound = $random(int.high) - var found = false - for s in p.content: - if bound in s: - found = true - if not found: - break + result = $random(int.high) + for i, entry in p.content: + if result in entry.content: break + elif i == p.content.high: return - result.contentType = "multipart/form-data; boundary=" & bound - result.body = "" - for s in p.content: - result.body.add("--" & bound & "\c\L" & s) - result.body.add("--" & bound & "--\c\L") +proc sendFile(socket: Socket | AsyncSocket, + entry: MultipartEntry) {.multisync.} = + const chunkSize = 2^18 + let file = + when socket is AsyncSocket: openAsync(entry.content) + else: newFileStream(entry.content, fmRead) + + var buffer: string + while true: + buffer = + when socket is AsyncSocket: (await read(file, chunkSize)).string + else: readStr(file, chunkSize).string + if buffer.len == 0: break + await socket.send(buffer) + file.close() proc redirection(status: string): bool = const redirectionNRs = ["301", "302", "303", "307"] @@ -427,8 +462,8 @@ proc getNewLocation(lastURL: string, headers: HttpHeaders): string = parsed.anchor = r.anchor result = $parsed -proc generateHeaders(requestUrl: Uri, httpMethod: string, - headers: HttpHeaders, body: string, proxy: Proxy): string = +proc generateHeaders(requestUrl: Uri, httpMethod: string, headers: HttpHeaders, + proxy: Proxy): string = # GET let upperMethod = httpMethod.toUpperAscii() result = upperMethod @@ -447,34 +482,28 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string, result.add($modifiedUrl) # HTTP/1.1\c\l - result.add(" HTTP/1.1\c\L") + result.add(" HTTP/1.1" & httpNewLine) # Host header. if not headers.hasKey("Host"): if requestUrl.port == "": - add(result, "Host: " & requestUrl.hostname & "\c\L") + add(result, "Host: " & requestUrl.hostname & httpNewLine) else: - add(result, "Host: " & requestUrl.hostname & ":" & requestUrl.port & "\c\L") + add(result, "Host: " & requestUrl.hostname & ":" & requestUrl.port & httpNewLine) # Connection header. if not headers.hasKey("Connection"): - add(result, "Connection: Keep-Alive\c\L") - - # Content length header. - const requiresBody = ["POST", "PUT", "PATCH"] - let needsContentLength = body.len > 0 or upperMethod in requiresBody - if needsContentLength and not headers.hasKey("Content-Length"): - add(result, "Content-Length: " & $body.len & "\c\L") + add(result, "Connection: Keep-Alive" & httpNewLine) # Proxy auth header. if not proxy.isNil and proxy.auth != "": let auth = base64.encode(proxy.auth) - add(result, "Proxy-Authorization: basic " & auth & "\c\L") + add(result, "Proxy-Authorization: basic " & auth & httpNewLine) for key, val in headers: - add(result, key & ": " & val & "\c\L") + add(result, key & ": " & val & httpNewLine) - add(result, "\c\L") + add(result, httpNewLine) type ProgressChangedProc*[ReturnType] = @@ -511,9 +540,9 @@ type type HttpClient* = HttpClientBase[Socket] -proc newHttpClient*(userAgent = defUserAgent, - maxRedirects = 5, sslContext = getDefaultSSL(), proxy: Proxy = nil, - timeout = -1, headers = newHttpHeaders()): HttpClient = +proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, + sslContext = getDefaultSSL(), proxy: Proxy = nil, + timeout = -1, headers = newHttpHeaders()): HttpClient = ## Creates a new HttpClient instance. ## ## ``userAgent`` specifies the user agent that will be used when making @@ -546,9 +575,9 @@ proc newHttpClient*(userAgent = defUserAgent, type AsyncHttpClient* = HttpClientBase[AsyncSocket] -proc newAsyncHttpClient*(userAgent = defUserAgent, - maxRedirects = 5, sslContext = getDefaultSSL(), - proxy: Proxy = nil, headers = newHttpHeaders()): AsyncHttpClient = +proc newAsyncHttpClient*(userAgent = defUserAgent, maxRedirects = 5, + sslContext = getDefaultSSL(), proxy: Proxy = nil, + headers = newHttpHeaders()): AsyncHttpClient = ## Creates a new AsyncHttpClient instance. ## ## ``userAgent`` specifies the user agent that will be used when making @@ -671,8 +700,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void] # Trailer headers will only be sent if the request specifies that we want # them: http://tools.ietf.org/html/rfc2616#section-3.6.1 -proc parseBody(client: HttpClient | AsyncHttpClient, - headers: HttpHeaders, +proc parseBody(client: HttpClient | AsyncHttpClient, headers: HttpHeaders, httpVersion: string): Future[void] {.multisync.} = # Reset progress from previous requests. client.contentTotal = 0 @@ -745,7 +773,7 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, # We've been disconnected. client.close() break - if line == "\c\L": + if line == httpNewLine: fullyRead = true break if not parsedStatus: @@ -846,7 +874,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient, connectUrl.port = if url.port != "": url.port else: "443" let proxyHeaderString = generateHeaders(connectUrl, $HttpConnect, - newHttpHeaders(), "", client.proxy) + newHttpHeaders(), client.proxy) await client.socket.send(proxyHeaderString) let proxyResp = await parseResponse(client, false) @@ -864,6 +892,45 @@ proc newConnection(client: HttpClient | AsyncHttpClient, client.currentURL = url client.connected = true +proc readFileSizes(client: HttpClient | AsyncHttpClient, + multipart: MultipartData) {.multisync.} = + for entry in multipart.content.mitems(): + if not entry.isFile: continue + if not entry.isStream: + entry.fileSize = entry.content.len + continue + + # TODO: look into making getFileSize work with async + let fileSize = getFileSize(entry.content) + entry.fileSize = fileSize + +proc format(entry: MultipartEntry, boundary: string): string = + result = "--" & boundary & httpNewLine + result.add("Content-Disposition: form-data; name=\"" & entry.name & "\"") + if entry.isFile: + result.add("; filename=\"" & entry.filename & "\"" & httpNewLine) + result.add("Content-Type: " & entry.contentType & httpNewLine) + else: + result.add(httpNewLine & httpNewLine & entry.content) + +proc format(client: HttpClient | AsyncHttpClient, + multipart: MultipartData): Future[seq[string]] {.multisync.} = + let bound = getBoundary(multipart) + client.headers["Content-Type"] = "multipart/form-data; boundary=" & bound + + await client.readFileSizes(multipart) + + var length: int64 + for entry in multipart.content: + result.add(format(entry, bound) & httpNewLine) + if entry.isFile: + length += entry.fileSize + httpNewLine.len + + result.add "--" & bound & "--" + + for s in result: length += s.len + client.headers["Content-Length"] = $length + proc override(fallback, override: HttpHeaders): HttpHeaders = # Right-biased map union for `HttpHeaders` if override.isNil: @@ -875,9 +942,9 @@ proc override(fallback, override: HttpHeaders): HttpHeaders = for k, vs in override.table: result[k] = vs -proc requestAux(client: HttpClient | AsyncHttpClient, url: string, - httpMethod: string, body = "", - headers: HttpHeaders = nil): Future[Response | AsyncResponse] +proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, + body = "", headers: HttpHeaders = nil, + multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = # Helper that actually makes the request. Does not handle redirects. let requestUrl = parseUri(url) @@ -885,6 +952,12 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string, if requestUrl.scheme == "": raise newException(ValueError, "No uri scheme supplied.") + var data: seq[string] + if multipart != nil and multipart.content.len > 0: + data = await client.format(multipart) + else: + client.headers["Content-Length"] = $body.len + when client is AsyncHttpClient: if not client.parseBodyFut.isNil: # let the current operation finish before making another request @@ -893,16 +966,30 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string, await newConnection(client, requestUrl) - let effectiveHeaders = client.headers.override(headers) + let newHeaders = client.headers.override(headers) + if not newHeaders.hasKey("user-agent") and client.userAgent.len > 0: + newHeaders["User-Agent"] = client.userAgent - if not effectiveHeaders.hasKey("user-agent") and client.userAgent != "": - effectiveHeaders["User-Agent"] = client.userAgent + let headerString = generateHeaders(requestUrl, httpMethod, newHeaders, + client.proxy) + await client.socket.send(headerString) - var headersString = generateHeaders(requestUrl, httpMethod, - effectiveHeaders, body, client.proxy) - - await client.socket.send(headersString) - if body != "": + if data.len > 0: + var buffer: string + for i, entry in multipart.content: + buffer.add data[i] + if not entry.isFile: continue + if buffer.len > 0: + await client.socket.send(buffer) + buffer.setLen(0) + if entry.isStream: + await client.socket.sendFile(entry) + else: + await client.socket.send(entry.content) + buffer.add httpNewLine + # send the rest and the last boundary + await client.socket.send(buffer & data[^1]) + elif body.len > 0: await client.socket.send(body) let getBody = httpMethod.toLowerAscii() notin ["head", "connect"] and @@ -910,8 +997,8 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string, result = await parseResponse(client, getBody) proc request*(client: HttpClient | AsyncHttpClient, url: string, - httpMethod: string, body = "", - headers: HttpHeaders = nil): Future[Response | AsyncResponse] + httpMethod: string, body = "", headers: HttpHeaders = nil, + multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a request ## using the custom method string specified by ``httpMethod``. @@ -922,7 +1009,7 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string, ## ## This procedure will follow redirects up to a maximum number of redirects ## specified in ``client.maxRedirects``. - result = await client.requestAux(url, httpMethod, body, headers) + result = await client.requestAux(url, httpMethod, body, headers, multipart) var lastURL = url for i in 1..client.maxRedirects: @@ -930,13 +1017,12 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string, let redirectTo = getNewLocation(lastURL, result.headers) # Guarantee method for HTTP 307: see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307 var meth = if result.status == "307": httpMethod else: "GET" - result = await client.requestAux(redirectTo, meth, body, headers) + result = await client.requestAux(redirectTo, meth, body, headers, multipart) lastURL = redirectTo - proc request*(client: HttpClient | AsyncHttpClient, url: string, - httpMethod = HttpGet, body = "", - headers: HttpHeaders = nil): Future[Response | AsyncResponse] + httpMethod = HttpGet, body = "", headers: HttpHeaders = nil, + multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a request ## using the method specified. @@ -947,7 +1033,7 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string, ## ## When a request is made to a different hostname, the current connection will ## be closed. - result = await request(client, url, $httpMethod, body, headers) + result = await request(client, url, $httpMethod, body, headers, multipart) proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync.} = ## Returns the content of a response as a string. @@ -980,42 +1066,25 @@ proc getContent*(client: HttpClient | AsyncHttpClient, return await responseContent(resp) proc delete*(client: HttpClient | AsyncHttpClient, - url: string): Future[Response | AsyncResponse] {.multisync.} = + url: string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a DELETE request. ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpDelete) proc deleteContent*(client: HttpClient | AsyncHttpClient, - url: string): Future[string] {.multisync.} = + url: string): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a DELETE request. let resp = await delete(client, url) return await responseContent(resp) -proc makeRequestContent(body = "", multipart: MultipartData = nil): (string, HttpHeaders) = - let (mpContentType, mpBody) = format(multipart) - # TODO: Support FutureStream for `body` parameter. - template withNewLine(x): untyped = - if x.len > 0 and not x.endsWith("\c\L"): - x & "\c\L" - else: - x - var xb = mpBody.withNewLine() & body - var headers = newHttpHeaders() - if multipart != nil: - headers["Content-Type"] = mpContentType - headers["Content-Length"] = $len(xb) - return (xb, headers) - proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "", multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a POST request. ## This procedure uses httpClient values such as ``client.maxRedirects``. - var (xb, headers) = makeRequestContent(body, multipart) - result = await client.request(url, $HttpPost, xb, headers) + result = await client.request(url, $HttpPost, body, multipart=multipart) -proc postContent*(client: HttpClient | AsyncHttpClient, url: string, - body = "", +proc postContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a POST request. @@ -1023,32 +1092,27 @@ proc postContent*(client: HttpClient | AsyncHttpClient, url: string, return await responseContent(resp) proc put*(client: HttpClient | AsyncHttpClient, url: string, body = "", - multipart: MultipartData = nil): Future[Response | AsyncResponse] - {.multisync.} = + multipart: MultipartData = nil): Future[Response | AsyncResponse] + {.multisync.} = ## Connects to the hostname specified by the URL and performs a PUT request. ## This procedure uses httpClient values such as ``client.maxRedirects``. - var (xb, headers) = makeRequestContent(body, multipart) - result = await client.request(url, $HttpPut, xb, headers) + result = await client.request(url, $HttpPut, body, multipart=multipart) -proc putContent*(client: HttpClient | AsyncHttpClient, url: string, - body = "", - multipart: MultipartData = nil): Future[string] - {.multisync.} = +proc putContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", + multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL andreturns the content of a PUT request. let resp = await put(client, url, body, multipart) return await responseContent(resp) proc patch*(client: HttpClient | AsyncHttpClient, url: string, body = "", - multipart: MultipartData = nil): Future[Response | AsyncResponse] - {.multisync.} = + multipart: MultipartData = nil): Future[Response | AsyncResponse] + {.multisync.} = ## Connects to the hostname specified by the URL and performs a PATCH request. ## This procedure uses httpClient values such as ``client.maxRedirects``. - var (xb, headers) = makeRequestContent(body, multipart) - result = await client.request(url, $HttpPatch, xb, headers) + result = await client.request(url, $HttpPatch, body, multipart=multipart) -proc patchContent*(client: HttpClient | AsyncHttpClient, url: string, - body = "", - multipart: MultipartData = nil): Future[string] +proc patchContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", + multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a PATCH request. let resp = await patch(client, url, body, multipart) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index e6e0d35c4..8c679c017 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -97,6 +97,7 @@ const Http504* = HttpCode(504) Http505* = HttpCode(505) +const httpNewLine* = "\c\L" const headerLimit* = 10_000 proc newHttpHeaders*(): HttpHeaders = From 6a5b3811e7c8f0d20e23cf8b57ac28024f2620e3 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 7 Mar 2020 11:10:22 -0300 Subject: [PATCH 0087/4254] Add isValidFilename (#13561) * Add os.isValidFilename * Add os.isValidFilename * Peer Review Feedbacks https://github.com/nim-lang/Nim/pull/13561#discussion_r388013139 * Peer Review Feedbacks https://github.com/nim-lang/Nim/pull/13561#issuecomment-595259568 * Add since to const * Update the documentation comment * Update the changelog * Update lib/pure/os.nim Co-Authored-By: Dominik Picheta * Update lib/pure/os.nim Co-Authored-By: Dominik Picheta * Peer Review Feedbacks, Add more Tests Co-authored-by: Dominik Picheta --- changelog.md | 2 +- lib/pure/os.nim | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 52406a972..38f9589db 100644 --- a/changelog.md +++ b/changelog.md @@ -69,7 +69,7 @@ - Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. - Added `os.isRelativeTo` to tell whether a path is relative to another - Added `resetOutputFormatters` to `unittest` - +- Added `os.isValidFilename` that returns `true` if `filename` argument is valid for crossplatform use. - Added a `with` macro for easy function chaining that's available everywhere, there is no need to concern your APIs with returning the first argument diff --git a/lib/pure/os.nim b/lib/pure/os.nim index ba092da05..1ee71c1fb 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -48,6 +48,20 @@ import const weirdTarget = defined(nimscript) or defined(js) +since (1, 1): + const + invalidFilenameChars* = {'/', '\\', ':', '*', '?', '"', '<', '>', '|', '^', '\0'} ## \ + ## Characters that may produce invalid filenames across Linux, Windows, Mac, etc. + ## You can check if your filename contains these char and strip them for safety. + ## Mac bans ``':'``, Linux bans ``'/'``, Windows bans all others. + invalidFilenames* = [ + "CON", "PRN", "AUX", "NUL", + "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"] ## \ + ## Filenames that may be invalid across Linux, Windows, Mac, etc. + ## You can check if your filename match these and rename it for safety + ## (Currently all invalid filenames are from Windows only). + when weirdTarget: discard elif defined(windows): @@ -3194,6 +3208,32 @@ proc setLastModificationTime*(file: string, t: times.Time) {.noNimScript.} = discard h.closeHandle if res == 0'i32: raiseOSError(osLastError(), file) +func isValidFilename*(filename: string, maxLen = 259.Positive): bool {.since: (1, 1).} = + ## Returns true if ``filename`` is valid for crossplatform use. + ## + ## This is useful if you want to copy or save files across Windows, Linux, Mac, etc. + ## You can pass full paths as argument too, but func only checks filenames. + ## It uses ``invalidFilenameChars``, ``invalidFilenames`` and ``maxLen`` to verify the specified ``filename``. + ## + ## .. code-block:: nim + ## assert not isValidFilename(" foo") ## Leading white space + ## assert not isValidFilename("foo ") ## Trailing white space + ## assert not isValidFilename("foo.") ## Ends with Dot + ## assert not isValidFilename("con.txt") ## "CON" is invalid (Windows) + ## assert not isValidFilename("OwO:UwU") ## ":" is invalid (Mac) + ## assert not isValidFilename("aux.bat") ## "AUX" is invalid (Windows) + ## + # https://docs.microsoft.com/en-us/dotnet/api/system.io.pathtoolongexception + # https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx + result = true + let f = filename.splitFile() + if unlikely(f.name.len + f.ext.len > maxLen or + f.name[0] == ' ' or f.name[^1] == ' ' or f.name[^1] == '.' or + find(f.name, invalidFilenameChars) != -1): return false + for invalid in invalidFilenames: + if cmpIgnoreCase(f.name, invalid) == 0: return false + when isMainModule: assert quoteShellWindows("aaa") == "aaa" @@ -3228,3 +3268,31 @@ when isMainModule: doAssert r"D:\".normalizePathEnd == r"D:" doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\" doAssert "/".normalizePathEnd == r"\" + + + block isValidFilenameTest: + # Negative Tests. + doAssert not isValidFilename("abcd", maxLen = 2) + doAssert not isValidFilename("0123456789", maxLen = 8) + doAssert not isValidFilename("con") + doAssert not isValidFilename("aux") + doAssert not isValidFilename("prn") + doAssert not isValidFilename("OwO|UwU") + doAssert not isValidFilename(" foo") + doAssert not isValidFilename("foo ") + doAssert not isValidFilename("foo.") + doAssert not isValidFilename("con.txt") + doAssert not isValidFilename("aux.bat") + doAssert not isValidFilename("prn.exe") + doAssert not isValidFilename("nim>.nim") + doAssert not isValidFilename(" foo.log") + # Positive Tests. + doAssert isValidFilename("abcd", maxLen = 42.Positive) + doAssert isValidFilename("c0n") + doAssert isValidFilename("foo.aux") + doAssert isValidFilename("bar.prn") + doAssert isValidFilename("OwO_UwU") + doAssert isValidFilename("cron") + doAssert isValidFilename("ux.bat") + doAssert isValidFilename("nim.nim") + doAssert isValidFilename("foo.log") From eae31a7f8d5f26bbfc27c3f0746a583154d451c9 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 7 Mar 2020 23:53:43 +0100 Subject: [PATCH 0088/4254] Only print the link command when listCmd is active; fix docs (#13603) --- compiler/extccomp.nim | 2 +- compiler/nim.cfg | 1 - doc/advopt.txt | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index b9d0f0ff6..b115721df 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -489,7 +489,7 @@ proc addExternalFileToLink*(conf: ConfigRef; filename: AbsoluteFile) = conf.externalToLink.insert(filename.string, 0) proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int = - rawMessage(conf, msg, cmd) + rawMessage(conf, msg, if msg == hintLinking and not(optListCmd in conf.globalOptions or conf.verbosity > 1): "" else: cmd) result = execCmd(cmd) proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) = diff --git a/compiler/nim.cfg b/compiler/nim.cfg index f913e76a3..a77fa84d3 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -1,7 +1,6 @@ # Special configuration file for the Nim project hint[XDeclaredButNotUsed]:off -hint[Link]:off define:booting define:nimcore diff --git a/doc/advopt.txt b/doc/advopt.txt index 5c0ed86ee..517edab5b 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -125,8 +125,8 @@ Advanced options: dynlib: "liblua.so.3" --dynlibOverrideAll disables the effects of the dynlib pragma - --listCmd list the compilation commands; can be combined with: - --hint:exec:on and --hint:link:on + --listCmd list the compilation commands; can be combined with + `--hint:exec:on` and `--hint:link:on` --asm produce assembler code --parallelBuild:0|1|... perform a parallel build value = number of processors (0 for auto-detect) From a693ce776557371a159c074d1d3f55683114a03a Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Sun, 8 Mar 2020 05:55:19 -0400 Subject: [PATCH 0089/4254] surgical fix for #13319 (#13604) --- compiler/rodimpl.nim | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim index 7a0f6fcef..8ee7ae564 100644 --- a/compiler/rodimpl.nim +++ b/compiler/rodimpl.nim @@ -667,7 +667,7 @@ proc loadType(g; id: int; info: TLineInfo): PType = rawAddSon(result, nil) else: let d = decodeVInt(b.s, b.pos) - rawAddSon(result, loadType(g, d, info)) + result.sons.add loadType(g, d, info) proc decodeLib(g; b; info: TLineInfo): PLib = result = nil @@ -719,10 +719,8 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym = else: internalError(g.config, info, "decodeSym: no ident") #echo "decoding: {", ident.s - new(result) - result.id = id - result.kind = k - result.name = ident # read the rest of the symbol description: + result = PSym(id: id, kind: k, name: ident) + # read the rest of the symbol description: g.incr.r.syms.add(result.id, result) if b.s[b.pos] == '^': inc(b.pos) From dc94c81cb0807dbb5cf60c782baa916bbd8458ed Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 9 Mar 2020 13:13:54 +0100 Subject: [PATCH 0090/4254] fixes #13605 (#13611) --- changelog.md | 3 +++ lib/pure/parseutils.nim | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 38f9589db..49567e929 100644 --- a/changelog.md +++ b/changelog.md @@ -115,6 +115,9 @@ echo f serve no purpose whatsoever. - `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers` argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`. +- `parseutils.parseUntil` has now a different behaviour if the `until` parameter is + empty. This was required for intuitive behaviour of the strscans module + (see bug #13605). ## Language additions diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 2c21c4952..6116751ff 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -354,12 +354,13 @@ proc parseUntil*(s: string, token: var string, until: string, doAssert myToken == "Hello " doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4 doAssert myToken == "llo " - if until.len == 0: - token.setLen(0) - return 0 + when (NimMajor, NimMinor) <= (1, 0): + if until.len == 0: + token.setLen(0) + return 0 var i = start while i < s.len: - if s[i] == until[0]: + if until.len > 0 and s[i] == until[0]: var u = 1 while i+u < s.len and u < until.len and s[i+u] == until[u]: inc u From 4aecc6b3465411d99dbd94e89c1bb3eb371d6fa6 Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 9 Mar 2020 14:08:50 +0100 Subject: [PATCH 0091/4254] fix #12508, unaligned access on sparc64 (#13594) --- lib/pure/hashes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 52a724d7b..d799fb062 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -162,7 +162,7 @@ proc murmurHash(x: openArray[byte]): Hash = # body while i < n * stepSize: var k1: uint32 - when defined(js): + when defined(js) or defined(sparc) or defined(sparc64): var j = stepSize while j > 0: dec j From 63af8ae53ca8e1ffd61a2c2d55d09c5fe30310e1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 9 Mar 2020 15:32:38 +0100 Subject: [PATCH 0092/4254] fixes #13596 (#13612) --- compiler/transf.nim | 13 +++++ tests/arc/tamemfiles.nim | 110 +++++++++++++++++++++++++++++++++++++++ tests/arc/testfile.txt | 2 + 3 files changed, 125 insertions(+) create mode 100644 tests/arc/tamemfiles.nim create mode 100644 tests/arc/testfile.txt diff --git a/compiler/transf.nim b/compiler/transf.nim index 68ef464c4..cd5eaa100 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -128,6 +128,19 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = b = s.getBody if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym, n.info) + elif c.inlining > 0: + # see bug #13596: we use ref-based equality in the DFA for destruction + # injections so we need to ensure unique nodes after iterator inlining + # which can lead to duplicated for loop bodies! Consider: + #[ + while remaining > 0: + if ending == nil: + yield ms + break + ... + yield ms + ]# + b = newSymNode(n.sym, n.info) else: b = n while tc != nil: diff --git a/tests/arc/tamemfiles.nim b/tests/arc/tamemfiles.nim new file mode 100644 index 000000000..97deb489f --- /dev/null +++ b/tests/arc/tamemfiles.nim @@ -0,0 +1,110 @@ +discard """ + output: ''' +loop 1a +loop 1b; cols: @[1, x] +loop 1c +loop 1d +loop 1a +loop 1b; cols: @[2, y] +loop 1c +loop 1d +''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13596 + +import tables, memfiles, strutils, os + +type Splitr* = tuple[ repeat: bool, chrDlm: char, setDlm: set[char], n: int ] + +type csize = uint +proc cmemchr*(s: pointer, c: char, n: csize): pointer {. + importc: "memchr", header: "" .} +proc `-!`*(p, q: pointer): int {.inline.} = + (cast[int](p) -% cast[int](q)).int +proc `+!`*(p: pointer, i: int): pointer {.inline.} = + cast[pointer](cast[int](p) +% i) +proc `+!`*(p: pointer, i: uint64): pointer {.inline.} = + cast[pointer](cast[uint64](p) + i) + +proc charEq(x, c: char): bool {.inline.} = x == c + +proc initSplitr*(delim: string): Splitr = + if delim == "white": #User can use any other permutation if needed + result.repeat = true + result.chrDlm = ' ' + result.setDlm = { ' ', '\t', '\n' } + result.n = result.setDlm.card + return + for c in delim: + if c in result.setDlm: + result.repeat = true + continue + result.setDlm.incl(c) + inc(result.n) + if result.n == 1: #support n==1 test to allow memchr optimization + result.chrDlm = delim[0] + +proc hash(x: MemSlice): int = 55542 + +template defSplit[T](slc: T, fs: var seq[MemSlice], n: int, repeat: bool, + sep: untyped, nextSep: untyped, isSep: untyped) {.dirty.} = + fs.setLen(if n < 1: 16 else: n) + var b = slc.data + var eob = b +! slc.size + while repeat and eob -! b > 0 and isSep((cast[cstring](b))[0], sep): + b = b +! 1 + if b == eob: fs.setLen(0); return + var e = nextSep(b, sep, (eob -! b).csize) + while e != nil: + if n < 1: #Unbounded msplit + if result == fs.len - 1: #Expand capacity + fs.setLen(if fs.len < 512: 2*fs.len else: fs.len + 512) + elif result == n - 1: #Need 1 more slot for final field + break + fs[result].data = b + fs[result].size = e -! b + result += 1 + while repeat and eob -! e > 0 and isSep((cast[cstring](e))[1], sep): + e = e +! 1 + b = e +! 1 + if eob -! b <= 0: + b = eob + break + e = nextSep(b, sep, (eob -! b).csize) + if not repeat or eob -! b > 0: + fs[result].data = b + fs[result].size = eob -! b + result += 1 + fs.setLen(result) + +proc msplit*(s: MemSlice, fs: var seq[MemSlice], sep=' ', n=0, + repeat=false): int = + defSplit(s, fs, n, repeat, sep, cmemchr, charEq) + +proc split*(s: Splitr, line: MemSlice, cols: var seq[MemSlice], + n=0) {.inline.} = + discard msplit(line, cols, s.chrDlm, n, s.repeat) + +######################################################################## +# Using lines instead of memSlices & split instead of splitr.split seems +# to mask the arc problem, as does simplifying `Table` to `seq[char]`. + +proc load(path: string, delim=" "): Table[MemSlice, seq[char]] = + let f = memfiles.open(path) + let splitr = initSplitr(delim) + var cols: seq[MemSlice] = @[ ] # re-used seq buffer + var nwSq = newSeqOfCap[char](1) # re-used seq value + nwSq.setLen 1 + for line in memSlices(f, eat='\0'): + stderr.write "loop 1a\n" + splitr.split(line, cols, 2) + stderr.write "loop 1b; cols: ", cols, "\n" + let cs = cast[cstring](cols[0].data) + stderr.write "loop 1c\n" #..reports exception here, but + nwSq[0] = cs[0] #..actually doing out of bounds here + stderr.write "loop 1d\n" + result[cols[1]] = nwSq + +discard load(getAppDir() / "testfile.txt") diff --git a/tests/arc/testfile.txt b/tests/arc/testfile.txt new file mode 100644 index 000000000..5169490be --- /dev/null +++ b/tests/arc/testfile.txt @@ -0,0 +1,2 @@ +1 x +2 y From ec5cef13cffdb43a7298736b65e1a76e83741dff Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 9 Mar 2020 18:12:52 +0100 Subject: [PATCH 0093/4254] fixes #13599 (#13614) --- compiler/ccgstmts.nim | 2 +- tests/destructor/tgotoexceptions5.nim | 39 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/destructor/tgotoexceptions5.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c430dd062..9c067a339 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1115,10 +1115,10 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = # 3. finally is run for exception handling code without any 'except' # handler present or only handlers that did not match. linefmt(p, cpsStmts, "*nimErr_ += oldNimErr$1_ + (*nimErr_ - oldNimErrFin$1_); oldNimErr$1_ = 0;$n", [lab]) - raiseExit(p) endBlock(p) # restore the real error value: linefmt(p, cpsStmts, "*nimErr_ += oldNimErr$1_;$n", [lab]) + if p.prc != nil: raiseExit(p) proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # code to generate: diff --git a/tests/destructor/tgotoexceptions5.nim b/tests/destructor/tgotoexceptions5.nim new file mode 100644 index 000000000..41e62aba0 --- /dev/null +++ b/tests/destructor/tgotoexceptions5.nim @@ -0,0 +1,39 @@ +discard """ + output: ''' +before +swallowed +before +swallowed B +''' + cmd: "nim c --gc:arc --exceptions:goto $file" +""" + +# bug #13599 +proc main() = + try: + echo "before" + raise newException(CatchableError, "foo") + except AssertionError: + echo "caught" + echo "after" + +try: + main() +except: + echo "swallowed" + +proc mainB() = + try: + echo "before" + raise newException(CatchableError, "foo") + # except CatchableError: # would work + except AssertionError: + echo "caught" + except: + raise + echo "after" + +try: + mainB() +except: + echo "swallowed B" From 7d07897a9941717432d5872c3e0f203704902738 Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 9 Mar 2020 21:16:56 +0100 Subject: [PATCH 0094/4254] travis now only builds devel docs --- .travis.yml | 56 +++++++---------------------------------------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/.travis.yml b/.travis.yml index d62fe20d2..4c4c35334 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,45 +4,12 @@ language: c dist: xenial matrix: - fast_finish: true - include: - os: linux env: - NIM_COMPILE_TO_CPP=false - CPU=amd64 - - os: linux - env: - - NIM_COMPILE_TO_CPP=false - - CPU=i386 - addons: - apt: - packages: - - gcc-multilib - - g++-multilib - - libcurl4-openssl-dev:i386 - - libgc-dev:i386 - - libglib2.0-dev:i386 - - libpulse-dev:i386 - - libsdl1.2-dev:i386 - - libsfml-dev:i386 - - - os: osx - env: - - NIM_COMPILE_TO_CPP=false - - CPU=amd64 - - - os: osx - env: - - NIM_COMPILE_TO_CPP=true - - CPU=amd64 - -# To allow failures for a failing configuration, use something like: -# allow_failures: -# - env: NIM_COMPILE_TO_CPP=true -# - os: osx - addons: apt: # update the list above if more deps are introduced @@ -53,18 +20,6 @@ addons: - libsfml-dev - libc6-dbg - valgrind - homebrew: - packages: - - boehmgc - - make - - sfml - update: true - -install: - - if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which gcc) -m32 \"\$@\"" > bin/gcc; fi - - if [[ $CPU = i386 ]]; then chmod 755 bin/gcc; fi - - if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which g++) -m32 \"\$@\"" > bin/g++; fi - - if [[ $CPU = i386 ]]; then chmod 755 bin/g++; fi before_script: - git clone --depth 1 https://github.com/nim-lang/csources.git @@ -75,11 +30,17 @@ script: - echo "travis_fold:start:nim_c_koch" - nim c koch - echo "travis_fold:end:nim_c_koch" - - ./koch runCI + - echo "travis_fold:start:koch_boot" + - ./koch boot + - echo "travis_fold:end:koch_boot" + - echo "travis_fold:start:koch_doc" + - ./koch doc + - echo "travis_fold:end:koch_doc" before_deploy: # Make https://nim-lang.github.io/Nim work the same as https://nim-lang.github.io/Nim/overview.html - cp -f ./doc/html/overview.html ./doc/html/index.html + deploy: # https://nim-lang.github.io/Nim provider: pages # local-dir *has* to be a relative path from the repo root. @@ -89,6 +50,3 @@ deploy: # https://nim-lang.github.io/Nim keep-history: false on: branch: devel - -# Extract failed tests -after_failure: nim c -r tools/ci_testresults.nim From 090ba1e3a390e9997f45001e18dc93ba7aa091c3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 10 Mar 2020 00:52:46 +0100 Subject: [PATCH 0095/4254] fixes #13436 (#13615) --- compiler/cgen.nim | 12 +++++++++--- compiler/injectdestructors.nim | 3 ++- tests/destructor/tgotoexceptions6.nim | 10 ++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 tests/destructor/tgotoexceptions6.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index fd14817e0..57424ec95 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1663,6 +1663,11 @@ proc genInitCode(m: BModule) = if beforeRetNeeded in m.initProc.flags: prc.add(~"\tBeforeRet_: ;$n") + + if sfMainModule in m.module.flags and m.config.exc == excGoto: + if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: + m.appcg(prc, "\t#nimTestErrorFlag();$n", []) + if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: prc.add(deinitFrame(m.initProc)) @@ -1990,9 +1995,10 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if b == nil: return var m = BModule(b) if sfMainModule in m.module.flags: - let testForError = getCompilerProc(graph, "nimTestErrorFlag") - if testForError != nil and graph.config.exc == excGoto: - n.add newTree(nkCall, testForError.newSymNode) + # phase ordering problem here: We need to announce this + # dependency to 'nimTestErrorFlag' before system.c has been written to disk. + if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil: + discard cgsym(m, "nimTestErrorFlag") for i in countdown(high(graph.globalDestructors), 0): n.add graph.globalDestructors[i] diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 520ba46ce..161cb7652 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -591,7 +591,8 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = # move the variable declaration to the top of the frame: c.addTopVar v # make sure it's destroyed at the end of the proc: - if not isUnpackedTuple(v): + if not isUnpackedTuple(v) and sfThread notin v.sym.flags: + # do not destroy thread vars for now at all for consistency. c.destroys.add genDestroy(c, v) elif c.inLoop > 0: # unpacked tuple needs reset at every loop iteration diff --git a/tests/destructor/tgotoexceptions6.nim b/tests/destructor/tgotoexceptions6.nim new file mode 100644 index 000000000..7c01f6a52 --- /dev/null +++ b/tests/destructor/tgotoexceptions6.nim @@ -0,0 +1,10 @@ +discard """ + cmd: "nim c --gc:arc --exceptions:goto $file" + outputsub: "Error: unhandled exception: virus detected [ValueError]" + exitcode: "1" +""" + +# bug #13436 +proc foo = + raise newException(ValueError, "virus detected") +foo() From ab5d962b508d6578232d8924d7c59f388ae6d9a3 Mon Sep 17 00:00:00 2001 From: genotrance Date: Tue, 10 Mar 2020 09:58:27 -0500 Subject: [PATCH 0096/4254] Revert "Support cross compiling from host to host (#12859)" (#13591) This reverts commit e4f7656772657069cd3e27704d687b292d8d24ab. --- compiler/extccomp.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index b115721df..4cc5043f8 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -411,7 +411,8 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = else: suffix - if optCompileOnly notin conf.globalOptions: + if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and + optCompileOnly notin conf.globalOptions: let fullCCname = platform.CPU[conf.target.targetCPU].name & '.' & platform.OS[conf.target.targetOS].name & '.' & CC[c].name & fullSuffix From 9e2bce2a8cd6f7f8edb0558ce7b553553eb94d02 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 10 Mar 2020 15:59:14 +0100 Subject: [PATCH 0097/4254] hotfix: make --useVersion:1.0 work --- lib/pure/typetraits.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 0335d5488..750c6233d 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -111,7 +111,8 @@ macro genericParamsImpl(T: typedesc): untyped = var ret: NimNode case ai.typeKind of ntyStatic: - ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai]) + since (1, 1): + ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai]) of ntyTypeDesc: ret = ai else: From 3b7b01779856f50de94467fef9409ce228aa1ff1 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 10 Mar 2020 16:00:58 +0100 Subject: [PATCH 0098/4254] fixes #13607 --- lib/windows/winlean.nim | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 649358cb6..9793429b2 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -128,12 +128,10 @@ const CREATE_NO_WINDOW* = 0x08000000'i32 -when useWinUnicode: - proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "GetVersionExW", sideEffect.} -else: - proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "GetVersionExA", sideEffect.} +proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "GetVersionExW", sideEffect.} +proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "GetVersionExA", sideEffect.} proc getVersion*(): DWORD {.stdcall, dynlib: "kernel32", importc: "GetVersion", sideEffect.} From e64f1c7ee4a25a1df837617f4a79ce7e515b9e0d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 10 Mar 2020 16:31:34 -0700 Subject: [PATCH 0099/4254] `koch --nim:pathto/nim boot` and `koch boot --hint:cc:off` now work (#13516) * `koch boot --hint:cc:off` now works * `koch --nim:pathto/nim boot` now works; code cleanup --- compiler/extccomp.nim | 33 +++++++++++++++++++-------------- compiler/lineinfos.nim | 2 +- koch.nim | 9 +++------ tools/kochdocs.nim | 18 +++++++++++------- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 4cc5043f8..6b4223433 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -705,6 +705,11 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = flags: {CfileFlag.External}) addExternalFileToCompile(conf, c) +proc displayProgressCC(conf: ConfigRef, path: string): string = + if conf.hasHint(hintCC): + let (_, name, _) = splitFile(path) + result = MsgKindToStr[hintCC] % demanglePackageName(name) + proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var TStringSeq, prettyCmds: var TStringSeq) = var currIdx = 0 @@ -715,8 +720,7 @@ proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var inc currIdx if optCompileOnly notin conf.globalOptions: cmds.add(compileCmd) - let (_, name, _) = splitFile(it.cname) - prettyCmds.add(if conf.hasHint(hintCC): "CC: " & demanglePackageName(name) else: "") + prettyCmds.add displayProgressCC(conf, $it.cname) if optGenScript in conf.globalOptions: script.add(compileCmd) script.add("\n") @@ -908,6 +912,11 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu else: platform.OS[conf.target.targetOS].dllFrmt % basename result = conf.getNimcacheDir / RelativeFile(targetName) +template callbackPrettyCmd(cmd) = + when declared(echo): + let cmd2 = cmd + if cmd2.len > 0: echo cmd2 + proc callCCompiler*(conf: ConfigRef) = var linkCmd: string @@ -918,10 +927,7 @@ proc callCCompiler*(conf: ConfigRef) = var script: Rope = nil var cmds: TStringSeq = @[] var prettyCmds: TStringSeq = @[] - let prettyCb = proc (idx: int) = - when declared(echo): - let cmd = prettyCmds[idx] - if cmd != "": echo cmd + let prettyCb = proc (idx: int) = callbackPrettyCmd(prettyCmds[idx]) compileCFiles(conf, conf.toCompile, script, cmds, prettyCmds) if optCompileOnly notin conf.globalOptions: execCmdsInParallel(conf, cmds, prettyCb) @@ -1126,12 +1132,9 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = doAssert c.len >= 2 cmds.add(c[1].getStr) - let (_, name, _) = splitFile(c[0].getStr) - prettyCmds.add("CC: " & demanglePackageName(name)) + prettyCmds.add displayProgressCC(conf, c[0].getStr) - let prettyCb = proc (idx: int) = - when declared(echo): - echo prettyCmds[idx] + let prettyCb = proc (idx: int) = callbackPrettyCmd(prettyCmds[idx]) execCmdsInParallel(conf, cmds, prettyCb) let linkCmd = data["linkcmd"] @@ -1146,9 +1149,11 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = execExternalProgram(conf, cmd2, hintExecuting) except: - when declared(echo): - echo getCurrentException().getStackTrace() - quit "error evaluating JSON file: " & jsonFile.string + let e = getCurrentException() + var msg = "\ncaught exception:n" & e.msg & "\nstacktrace:\n" & + getCurrentException().getStackTrace() & + "error evaluating JSON file: " & jsonFile.string + quit msg proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = for it in list: diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 9095dd13d..5ac65201e 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -99,7 +99,7 @@ const hintSuccess: "operation successful: $#", # keep in sync with `pegSuccess` see testament.nim hintSuccessX: "$loc LOC; $sec sec; $mem; $build build; proj: $project; out: $output", - hintCC: "CC: \'$1\'", # unused + hintCC: "CC: $1", hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", hintConvToBaseNotNeeded: "conversion to base object is not needed", diff --git a/koch.nim b/koch.nim index 75d504758..982517656 100644 --- a/koch.nim +++ b/koch.nim @@ -265,15 +265,12 @@ when false: proc findStartNim: string = # we try several things before giving up: + # * nimExe # * bin/nim # * $PATH/nim # If these fail, we try to build nim with the "build.(sh|bat)" script. - var nim = "nim".exe - result = "bin" / nim - if existsFile(result): return - for dir in split(getEnv("PATH"), PathSep): - if existsFile(dir / nim): return dir / nim - + let (nim, ok) = findNimImpl() + if ok: return nim when defined(Posix): const buildScript = "build.sh" if existsFile(buildScript): diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index a5166973a..75df629e3 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -18,15 +18,19 @@ proc exe*(f: string): string = when defined(windows): result = result.replace('/','\\') -proc findNim*(): string = - if nimExe.len > 0: return nimExe - var nim = "nim".exe - result = "bin" / nim - if existsFile(result): return +proc findNimImpl*(): tuple[path: string, ok: bool] = + if nimExe.len > 0: return (nimExe, true) + let nim = "nim".exe + result.path = "bin" / nim + result.ok = true + if existsFile(result.path): return for dir in split(getEnv("PATH"), PathSep): - if existsFile(dir / nim): return dir / nim + result.path = dir / nim + if existsFile(result.path): return # assume there is a symlink to the exe or something: - return nim + return (nim, false) + +proc findNim*(): string = findNimImpl().path proc exec*(cmd: string, errorcode: int = QuitFailure, additionalPath = "") = let prevPath = getEnv("PATH") From 2f557652d41dea81e43d36c3e89258ece620609e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Wed, 11 Mar 2020 01:01:25 +0100 Subject: [PATCH 0100/4254] fix operators containing percent for VM usage (#13536) * fixes #13513 * merge tarithmetics in tarithm --- compiler/ast.nim | 2 - compiler/ccgexprs.nim | 2 - compiler/forloops.nim | 4 +- compiler/guards.nim | 4 +- compiler/jsgen.nim | 126 ++++++++++++++++++------------------- compiler/semfold.nim | 4 +- compiler/vmgen.nim | 4 +- lib/system/arithmetics.nim | 91 +++++++++++++++------------ lib/system/comparisons.nim | 45 +++++++------ tests/arithm/tarithm.nim | 18 ++++++ tests/pragmas/t6448.nim | 2 +- 11 files changed, 165 insertions(+), 137 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 43ea2b39c..b82002b06 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -617,7 +617,6 @@ type mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, mLeU, mLtU, - mLeU64, mLtU64, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, @@ -687,7 +686,6 @@ const mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, mLeU, mLtU, - mLeU64, mLtU64, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 277913b17..f133b97a2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -605,8 +605,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mLtF64: applyFormat("($1 < $2)") of mLeU: applyFormat("((NU$3)($1) <= (NU$3)($2))") of mLtU: applyFormat("((NU$3)($1) < (NU$3)($2))") - of mLeU64: applyFormat("((NU64)($1) <= (NU64)($2))") - of mLtU64: applyFormat("((NU64)($1) < (NU64)($2))") of mEqEnum: applyFormat("($1 == $2)") of mLeEnum: applyFormat("($1 <= $2)") of mLtEnum: applyFormat("($1 < $2)") diff --git a/compiler/forloops.nim b/compiler/forloops.nim index 729afb920..ee91000d4 100644 --- a/compiler/forloops.nim +++ b/compiler/forloops.nim @@ -13,8 +13,8 @@ import ast, astalgo const someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, - mLeI, mLeF64, mLeU, mLeU64, mLeEnum, - mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtU64, mLtEnum, + mLeI, mLeF64, mLeU, mLeEnum, + mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtEnum, mLtCh, mLtB, mLtPtr} proc isCounter(s: PSym): bool {.inline.} = diff --git a/compiler/guards.nim b/compiler/guards.nim index 97dc4f418..5d0fa64eb 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -17,9 +17,9 @@ const mEqStr, mEqSet, mEqCString} # set excluded here as the semantics are vastly different: - someLe = {mLeI, mLeF64, mLeU, mLeU64, mLeEnum, + someLe = {mLeI, mLeF64, mLeU, mLeEnum, mLeCh, mLeB, mLePtr, mLeStr} - someLt = {mLtI, mLtF64, mLtU, mLtU64, mLtEnum, + someLt = {mLtI, mLtF64, mLtU, mLtEnum, mLtCh, mLtB, mLtPtr, mLtStr} someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq} diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 1130e35f8..e63ce7489 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -371,69 +371,67 @@ type const # magic checked op; magic unchecked op; jsMagics: TMagicOps = [ mAddI: ["addInt", ""], - ["subInt", ""], # SubI - ["mulInt", ""], # MulI - ["divInt", ""], # DivI - ["modInt", ""], # ModI - ["addInt", ""], # Succ - ["subInt", ""], # Pred - ["", ""], # AddF64 - ["", ""], # SubF64 - ["", ""], # MulF64 - ["", ""], # DivF64 - ["", ""], # ShrI - ["", ""], # ShlI - ["", ""], # AshrI - ["", ""], # BitandI - ["", ""], # BitorI - ["", ""], # BitxorI - ["nimMin", "nimMin"], # MinI - ["nimMax", "nimMax"], # MaxI - ["", ""], # addU - ["", ""], # subU - ["", ""], # mulU - ["", ""], # divU - ["", ""], # modU - ["", ""], # EqI - ["", ""], # LeI - ["", ""], # LtI - ["", ""], # EqF64 - ["", ""], # LeF64 - ["", ""], # LtF64 - ["", ""], # leU - ["", ""], # ltU - ["", ""], # leU64 - ["", ""], # ltU64 - ["", ""], # EqEnum - ["", ""], # LeEnum - ["", ""], # LtEnum - ["", ""], # EqCh - ["", ""], # LeCh - ["", ""], # LtCh - ["", ""], # EqB - ["", ""], # LeB - ["", ""], # LtB - ["", ""], # EqRef - ["", ""], # LePtr - ["", ""], # LtPtr - ["", ""], # Xor - ["", ""], # EqCString - ["", ""], # EqProc - ["negInt", ""], # UnaryMinusI - ["negInt64", ""], # UnaryMinusI64 - ["absInt", ""], # AbsI - ["", ""], # Not - ["", ""], # UnaryPlusI - ["", ""], # BitnotI - ["", ""], # UnaryPlusF64 - ["", ""], # UnaryMinusF64 - ["nimCharToStr", "nimCharToStr"], - ["nimBoolToStr", "nimBoolToStr"], - ["cstrToNimstr", "cstrToNimstr"], - ["cstrToNimstr", "cstrToNimstr"], - ["cstrToNimstr", "cstrToNimstr"], - ["cstrToNimstr", "cstrToNimstr"], - ["", ""]] + mSubI: ["subInt", ""], + mMulI: ["mulInt", ""], + mDivI: ["divInt", ""], + mModI: ["modInt", ""], + mSucc: ["addInt", ""], + mPred: ["subInt", ""], + mAddF64: ["", ""], + mSubF64: ["", ""], + mMulF64: ["", ""], + mDivF64: ["", ""], + mShrI: ["", ""], + mShlI: ["", ""], + mAshrI: ["", ""], + mBitandI: ["", ""], + mBitorI: ["", ""], + mBitxorI: ["", ""], + mMinI: ["nimMin", "nimMin"], + mMaxI: ["nimMax", "nimMax"], + mAddU: ["", ""], + mSubU: ["", ""], + mMulU: ["", ""], + mDivU: ["", ""], + mModU: ["", ""], + mEqI: ["", ""], + mLeI: ["", ""], + mLtI: ["", ""], + mEqF64: ["", ""], + mLeF64: ["", ""], + mLtF64: ["", ""], + mLeU: ["", ""], + mLtU: ["", ""], + mEqEnum: ["", ""], + mLeEnum: ["", ""], + mLtEnum: ["", ""], + mEqCh: ["", ""], + mLeCh: ["", ""], + mLtCh: ["", ""], + mEqB: ["", ""], + mLeB: ["", ""], + mLtB: ["", ""], + mEqRef: ["", ""], + mLePtr: ["", ""], + mLtPtr: ["", ""], + mXor: ["", ""], + mEqCString: ["", ""], + mEqProc: ["", ""], + mUnaryMinusI: ["negInt", ""], + mUnaryMinusI64: ["negInt64", ""], + mAbsI: ["absInt", ""], + mNot: ["", ""], + mUnaryPlusI: ["", ""], + mBitnotI: ["", ""], + mUnaryPlusF64: ["", ""], + mUnaryMinusF64: ["", ""], + mCharToStr: ["nimCharToStr", "nimCharToStr"], + mBoolToStr: ["nimBoolToStr", "nimBoolToStr"], + mIntToStr: ["cstrToNimstr", "cstrToNimstr"], + mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"], + mFloatToStr: ["cstrToNimstr", "cstrToNimstr"], + mCStrToStr: ["cstrToNimstr", "cstrToNimstr"], + mStrToStr: ["", ""]] proc needsTemp(p: PProc; n: PNode): bool = # check if n contains a call to determine @@ -575,8 +573,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mLtF64: applyFormat("($1 < $2)", "($1 < $2)") of mLeU: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtU: applyFormat("($1 < $2)", "($1 < $2)") - of mLeU64: applyFormat("($1 <= $2)", "($1 <= $2)") - of mLtU64: applyFormat("($1 < $2)", "($1 < $2)") of mEqEnum: applyFormat("($1 == $2)", "($1 == $2)") of mLeEnum: applyFormat("($1 <= $2)", "($1 <= $2)") of mLtEnum: applyFormat("($1 < $2)", "($1 < $2)") diff --git a/compiler/semfold.nim b/compiler/semfold.nim index b20616e1d..54850fcfe 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -288,9 +288,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mLtStr: result = newIntNodeT(toInt128(ord(getStr(a) < getStr(b))), n, g) of mLeStr: result = newIntNodeT(toInt128(ord(getStr(a) <= getStr(b))), n, g) of mEqStr: result = newIntNodeT(toInt128(ord(getStr(a) == getStr(b))), n, g) - of mLtU, mLtU64: + of mLtU: result = newIntNodeT(toInt128(ord(`<%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, g) - of mLeU, mLeU64: + of mLeU: result = newIntNodeT(toInt128(ord(`<=%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, g) of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, g) of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 75f673c0b..5b355bcab 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1071,8 +1071,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mEqF64: genBinaryABC(c, n, dest, opcEqFloat) of mLeF64: genBinaryABC(c, n, dest, opcLeFloat) of mLtF64: genBinaryABC(c, n, dest, opcLtFloat) - of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu) - of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu) + of mLePtr, mLeU: genBinaryABC(c, n, dest, opcLeu) + of mLtPtr, mLtU: genBinaryABC(c, n, dest, opcLtu) of mEqProc, mEqRef: genBinaryABC(c, n, dest, opcEqRef) of mXor: genBinaryABC(c, n, dest, opcXor) diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index 757a813e8..710566a6d 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -342,45 +342,6 @@ proc `xor`*(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int64): int64 {.magic: "BitxorI", noSideEffect.} -type - IntMax32 = int|int8|int16|int32 - -proc `+%`*(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.} -proc `+%`*(x, y: int64): int64 {.magic: "AddU", noSideEffect.} - ## Treats `x` and `y` as unsigned and adds them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `-%`*(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.} -proc `-%`*(x, y: int64): int64 {.magic: "SubU", noSideEffect.} - ## Treats `x` and `y` as unsigned and subtracts them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `*%`*(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.} -proc `*%`*(x, y: int64): int64 {.magic: "MulU", noSideEffect.} - ## Treats `x` and `y` as unsigned and multiplies them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `/%`*(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.} -proc `/%`*(x, y: int64): int64 {.magic: "DivU", noSideEffect.} - ## Treats `x` and `y` as unsigned and divides them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `%%`*(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.} -proc `%%`*(x, y: int64): int64 {.magic: "ModU", noSideEffect.} - ## Treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - - # unsigned integer operations: proc `not`*(x: uint): uint {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. @@ -461,8 +422,60 @@ proc `mod`*(x, y: uint16): uint16 {.magic: "ModU", noSideEffect.} proc `mod`*(x, y: uint32): uint32 {.magic: "ModU", noSideEffect.} proc `mod`*(x, y: uint64): uint64 {.magic: "ModU", noSideEffect.} +proc `+%`*(x, y: int): int {.inline.} = + ## Treats `x` and `y` as unsigned and adds them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + cast[int](cast[uint](x) + cast[uint](y)) +proc `+%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) + cast[uint8](y)) +proc `+%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) + cast[uint16](y)) +proc `+%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) + cast[uint32](y)) +proc `+%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) + cast[uint64](y)) +proc `-%`*(x, y: int): int {.inline.} = + ## Treats `x` and `y` as unsigned and subtracts them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + cast[int](cast[uint](x) - cast[uint](y)) +proc `-%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) - cast[uint8](y)) +proc `-%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) - cast[uint16](y)) +proc `-%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) - cast[uint32](y)) +proc `-%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) - cast[uint64](y)) +proc `*%`*(x, y: int): int {.inline.} = + ## Treats `x` and `y` as unsigned and multiplies them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + cast[int](cast[uint](x) * cast[uint](y)) +proc `*%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) * cast[uint8](y)) +proc `*%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) * cast[uint16](y)) +proc `*%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) * cast[uint32](y)) +proc `*%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) * cast[uint64](y)) + +proc `/%`*(x, y: int): int {.inline.} = + ## Treats `x` and `y` as unsigned and divides them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + cast[int](cast[uint](x) div cast[uint](y)) +proc `/%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) div cast[uint8](y)) +proc `/%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) div cast[uint16](y)) +proc `/%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) div cast[uint32](y)) +proc `/%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) div cast[uint64](y)) + +proc `%%`*(x, y: int): int {.inline.} = + ## Treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + cast[int](cast[uint](x) mod cast[uint](y)) +proc `%%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) mod cast[uint8](y)) +proc `%%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) mod cast[uint16](y)) +proc `%%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) mod cast[uint32](y)) +proc `%%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) mod cast[uint64](y)) proc `+=`*[T: SomeInteger](x: var T, y: T) {. magic: "Inc", noSideEffect.} diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 787820989..60ac554a6 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -161,16 +161,37 @@ proc `<`*(x, y: int16): bool {.magic: "LtI", noSideEffect.} proc `<`*(x, y: int32): bool {.magic: "LtI", noSideEffect.} proc `<`*(x, y: int64): bool {.magic: "LtI", noSideEffect.} +proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} + ## Returns true if ``x <= y``. +proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} -proc `<=%`*(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.} -proc `<=%`*(x, y: int64): bool {.magic: "LeU64", noSideEffect.} +proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} + ## Returns true if ``x < y``. +proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} + +proc `<=%`*(x, y: int): bool {.inline.} = ## Treats `x` and `y` as unsigned and compares them. ## Returns true if ``unsigned(x) <= unsigned(y)``. + cast[uint](x) <= cast[uint](y) +proc `<=%`*(x, y: int8): bool {.inline.} = cast[uint8](x) <= cast[uint8](y) +proc `<=%`*(x, y: int16): bool {.inline.} = cast[uint16](x) <= cast[uint16](y) +proc `<=%`*(x, y: int32): bool {.inline.} = cast[uint32](x) <= cast[uint32](y) +proc `<=%`*(x, y: int64): bool {.inline.} = cast[uint64](x) <= cast[uint64](y) -proc `<%`*(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.} -proc `<%`*(x, y: int64): bool {.magic: "LtU64", noSideEffect.} +proc `<%`*(x, y: int): bool {.inline.} = ## Treats `x` and `y` as unsigned and compares them. ## Returns true if ``unsigned(x) < unsigned(y)``. + cast[uint](x) < cast[uint](y) +proc `<%`*(x, y: int8): bool {.inline.} = cast[uint8](x) < cast[uint8](y) +proc `<%`*(x, y: int16): bool {.inline.} = cast[uint16](x) < cast[uint16](y) +proc `<%`*(x, y: int32): bool {.inline.} = cast[uint32](x) < cast[uint32](y) +proc `<%`*(x, y: int64): bool {.inline.} = cast[uint64](x) < cast[uint64](y) template `>=%`*(x, y: untyped): untyped = y <=% x ## Treats `x` and `y` as unsigned and compares them. @@ -180,7 +201,6 @@ template `>%`*(x, y: untyped): untyped = y <% x ## Treats `x` and `y` as unsigned and compares them. ## Returns true if ``unsigned(x) > unsigned(y)``. - proc `==`*(x, y: uint): bool {.magic: "EqI", noSideEffect.} ## Compares two unsigned integers for equality. proc `==`*(x, y: uint8): bool {.magic: "EqI", noSideEffect.} @@ -189,21 +209,6 @@ proc `==`*(x, y: uint32): bool {.magic: "EqI", noSideEffect.} proc `==`*(x, y: uint64): bool {.magic: "EqI", noSideEffect.} -proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} - ## Returns true if ``x <= y``. -proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} - -proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} - ## Returns true if ``unsigned(x) < unsigned(y)``. -proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} - - {.push stackTrace: off.} proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} = diff --git a/tests/arithm/tarithm.nim b/tests/arithm/tarithm.nim index fcb78bd7a..99306b3e8 100644 --- a/tests/arithm/tarithm.nim +++ b/tests/arithm/tarithm.nim @@ -12,7 +12,9 @@ int32 4294967295 2 0 +tUnsignedOps OK ''' +nimout: "tUnsignedOps OK" """ import typetraits @@ -167,3 +169,19 @@ block tissue12177: echo(a - b) echo(a * b) echo(a div b) + +block tUnsignedOps: + proc testUnsignedOps() = + let a: int8 = -128 + let b: int8 = 127 + + doAssert b +% 1 == -128 + doAssert b -% -1 == -128 + doAssert b *% 2 == -2 + doAssert a /% 4 == 32 + doAssert a %% 7 == 2 + echo "tUnsignedOps OK" + + testUnsignedOps() + static: + testUnsignedOps() diff --git a/tests/pragmas/t6448.nim b/tests/pragmas/t6448.nim index ab2e3811f..6efb56e08 100644 --- a/tests/pragmas/t6448.nim +++ b/tests/pragmas/t6448.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''ambiguous call; both foobar.async''' + errormsg: '''ambiguous call''' line: 10 disabled: "32bit" """ From 8e3a349561fb0af7f5bc77a4d436abb3ced75d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=81=E3=81=90=E3=81=BF=E7=99=BA=E5=8B=95=E6=A9=9F=20?= =?UTF-8?q?=28isVowel=20/=20GreenWing=29?= <60494954+pancakevirus@users.noreply.github.com> Date: Wed, 11 Mar 2020 16:26:10 +0900 Subject: [PATCH 0101/4254] fixed to jsonArrayEnd comment. (#13624) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo: start → end --- lib/pure/parsejson.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim index 0d7d7093e..18e6037f3 100644 --- a/lib/pure/parsejson.nim +++ b/lib/pure/parsejson.nim @@ -27,7 +27,7 @@ type jsonObjectStart, ## start of an object: the ``{`` token jsonObjectEnd, ## end of an object: the ``}`` token jsonArrayStart, ## start of an array: the ``[`` token - jsonArrayEnd ## start of an array: the ``]`` token + jsonArrayEnd ## end of an array: the ``]`` token TokKind* = enum # must be synchronized with TJsonEventKind! tkError, From f95eef99a97dc813cf2f819a6bbaa3b3ead67267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Wed, 11 Mar 2020 08:27:31 +0100 Subject: [PATCH 0102/4254] add expectIdent to macros (#12778) * add expectIdent to macros * apply feedback * Update lib/core/macros.nim Co-Authored-By: Clyybber * Update texpectIdent2.nim * Update texpectIdent1.nim Co-authored-by: Clyybber Co-authored-by: Andreas Rumpf --- changelog.md | 2 +- lib/core/macros.nim | 7 +++++++ tests/macros/texpectIdent1.nim | 18 ++++++++++++++++++ tests/macros/texpectIdent2.nim | 24 ++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/macros/texpectIdent1.nim create mode 100644 tests/macros/texpectIdent2.nim diff --git a/changelog.md b/changelog.md index 49567e929..44c654fd3 100644 --- a/changelog.md +++ b/changelog.md @@ -69,6 +69,7 @@ - Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. - Added `os.isRelativeTo` to tell whether a path is relative to another - Added `resetOutputFormatters` to `unittest` +- Added `expectIdent` to the `macros` module. - Added `os.isValidFilename` that returns `true` if `filename` argument is valid for crossplatform use. - Added a `with` macro for easy function chaining that's available @@ -95,7 +96,6 @@ echo f - Added a new module, `std / compilesettings` for querying the compiler about diverse configuration settings. - ## Library changes - `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` diff --git a/lib/core/macros.nim b/lib/core/macros.nim index cc20f1dac..57ce89c02 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1433,6 +1433,13 @@ else: else: result = false +proc expectIdent*(n: NimNode, name: string) {.compileTime, since: (1,1).} = + ## Check that ``eqIdent(n,name)`` holds true. If this is not the + ## case, compilation aborts with an error message. This is useful + ## for writing macros that check the AST that is passed to them. + if not eqIdent(n, name): + error("Expected identifier to be `" & name & "` here", n) + proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}= ## Search ``nnkFormalParams`` for an argument. expectKind(params, nnkFormalParams) diff --git a/tests/macros/texpectIdent1.nim b/tests/macros/texpectIdent1.nim new file mode 100644 index 000000000..26e52afb5 --- /dev/null +++ b/tests/macros/texpectIdent1.nim @@ -0,0 +1,18 @@ +discard """ +errormsg: "Expected identifier to be `foo` here" +line: 18 +""" + +import macros + +macro testUntyped(arg: untyped): void = + arg.expectKind nnkStmtList + arg.expectLen 2 + arg[0].expectKind nnkCall + arg[0][0].expectIdent "foo" # must pass + arg[1].expectKind nnkCall + arg[1][0].expectIdent "foo" # must fail + +testUntyped: + foo(123) + bar(321) diff --git a/tests/macros/texpectIdent2.nim b/tests/macros/texpectIdent2.nim new file mode 100644 index 000000000..887a6ddc3 --- /dev/null +++ b/tests/macros/texpectIdent2.nim @@ -0,0 +1,24 @@ +discard """ +errormsg: "Expected identifier to be `foo` here" +line: 24 +""" + +import macros + +macro testTyped(arg: typed): void = + arg.expectKind nnkStmtList + arg.expectLen 2 + arg[0].expectKind nnkCall + arg[0][0].expectIdent "foo" # must pass + arg[1].expectKind nnkCall + arg[1][0].expectIdent "foo" # must fail + +proc foo(arg: int) = + discard + +proc bar(arg: int) = + discard + +testTyped: + foo(123) + bar(321) From b0684ec425dca5e76eb6b27eb09a84fb523af49c Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 10 Mar 2020 09:42:23 +0100 Subject: [PATCH 0103/4254] fixes #12757 --- compiler/semtypes.nim | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index abc5de7e8..f05affc6b 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -893,7 +893,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = localError(c.config, n.info, "type '$1 void' is not allowed" % kindToStr[kind]) result = newOrPrevType(kind, prev, c) var isNilable = false - var isOwned = false + var wrapperKind = tyNone # check every except the last is an object: for i in isCall.. Date: Tue, 10 Mar 2020 10:39:43 +0100 Subject: [PATCH 0104/4254] fixes #13519 --- changelog.md | 4 ++++ compiler/ast.nim | 7 +++++-- compiler/commands.nim | 6 ++++-- lib/pure/asyncdispatch.nim | 2 +- lib/pure/asyncmacro.nim | 2 +- lib/system/assertions.nim | 2 +- tests/generics/tarc_misc.nim | 21 +++++++++++++++++++++ 7 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 tests/generics/tarc_misc.nim diff --git a/changelog.md b/changelog.md index 44c654fd3..b76946464 100644 --- a/changelog.md +++ b/changelog.md @@ -40,6 +40,10 @@ - The `{.dynlib.}` pragma is now required for exporting symbols when making shared objects on POSIX and macOS, which make it consistent with the behavior on Windows. +- The compiler is now more strict about type conversions concerning proc + types: Type conversions cannot be used to hide `.raise` effects or side + effects, instead a `cast` must be used. With the flag `--useVersion:1.0` the + old behaviour is emulated. ## Library additions diff --git a/compiler/ast.nim b/compiler/ast.nim index b82002b06..62c301a43 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -592,8 +592,11 @@ const tfReturnsNew* = tfInheritable skError* = skUnknown - # type flags that are essential for type equality: - eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr} +var + eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect} + ## type flags that are essential for type equality. + ## This is now a variable because for emulation of version:1.0 we + ## might exclude {tfGcSafe, tfNoSideEffect}. type TMagic* = enum # symbols that require compiler magic: diff --git a/compiler/commands.nim b/compiler/commands.nim index 935d7e2be..0c93654da 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -32,6 +32,7 @@ import pathutils, strtabs from incremental import nimIncremental +from ast import eqTypeFlags, tfGcSafe, tfNoSideEffect # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -869,10 +870,11 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "1.0": defineSymbol(conf.symbols, "NimMajor", "1") defineSymbol(conf.symbols, "NimMinor", "0") - # always be compatible with 1.0.2 for now: - defineSymbol(conf.symbols, "NimPatch", "2") + # always be compatible with 1.0.100: + defineSymbol(conf.symbols, "NimPatch", "100") # old behaviors go here: defineSymbol(conf.symbols, "nimOldRelativePathBehavior") + ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect} else: localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index d724242d7..732381ccb 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -278,7 +278,7 @@ when defined(windows) or defined(nimdoc): result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) result.handles = initSet[AsyncFD]() result.timers.newHeapQueue() - result.callbacks = initDeque[proc ()](64) + result.callbacks = initDeque[proc () {.closure, gcsafe.}](64) var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 11eba427b..ce84491eb 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -46,7 +46,7 @@ template createCb(retFutureSym, iteratorNameSym, else: {.gcsafe.}: {.push hint[ConvFromXtoItselfNotNeeded]: off.} - next.callback = (proc() {.closure, gcsafe.})(identName) + next.callback = cast[proc() {.closure, gcsafe.}](identName) {.pop.} except: futureVarCompletions diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index b918729dc..5eb700f4c 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -26,7 +26,7 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = # by ``assert``. type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} - Hide(raiseAssert)(msg) + cast[Hide](raiseAssert)(msg) template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = when enabled: diff --git a/tests/generics/tarc_misc.nim b/tests/generics/tarc_misc.nim new file mode 100644 index 000000000..3e7762556 --- /dev/null +++ b/tests/generics/tarc_misc.nim @@ -0,0 +1,21 @@ +discard """ + output: '''''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13519 + +var unrelated: seq[proc() {.closure, gcsafe.}] + +unrelated.add proc () = + echo "gcsafe" + +import tables, sequtils +let t = newTable[int, proc()]() + +type + MyProc = proc() {.closure.} + +var result: seq[MyProc] = @[] +for x in t.values: + result.add(x) From 60f8fdcdabf99ae60f7a743cfd682bd7c320408b Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 10 Mar 2020 11:10:52 +0100 Subject: [PATCH 0105/4254] fixes #13240 --- compiler/ccgexprs.nim | 9 ++++++++- tests/arc/tconst_to_sink.nim | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/arc/tconst_to_sink.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f133b97a2..1bed4bc6c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1340,7 +1340,14 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = #echo rendertree e, " ", e.isDeepConstExpr # inheritance in C++ does not allow struct initialization so # we skip this step here: - if not p.module.compileToCpp: + if not p.module.compileToCpp and optSeqDestructors notin p.config.globalOptions: + # disabled optimization: it is wrong for C++ and now also + # causes trouble for --gc:arc, see bug #13240 + #[ + var box: seq[Thing] + for i in 0..3: + box.add Thing(s1: "121") # pass by sink can mutate Thing. + ]# if handleConstExpr(p, e, d): return var t = e.typ.skipTypes(abstractInstOwned) let isRef = t.kind == tyRef diff --git a/tests/arc/tconst_to_sink.nim b/tests/arc/tconst_to_sink.nim new file mode 100644 index 000000000..ddcc46e67 --- /dev/null +++ b/tests/arc/tconst_to_sink.nim @@ -0,0 +1,25 @@ +discard """ + output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13240 + +type + Thing = object + s1: string + s2: string + +var box: seq[Thing] + +const c = [Thing(s1: "333"), Thing(s1: "abc", s2: "def")] + +for i in 0..high(c): + box.add c[i] + +for i in 0..3: + box.add Thing(s1: "3x") + +box.add Thing(s1: "lastone") + +echo box From 3aed8ff4326cbfabef074b28366d487e2bdc8ae2 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 10 Mar 2020 12:46:19 +0100 Subject: [PATCH 0106/4254] fixes async regression --- lib/pure/asyncdispatch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 732381ccb..5e4e3f699 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1122,7 +1122,7 @@ else: new result result.selector = newSelector[AsyncData]() result.timers.newHeapQueue() - result.callbacks = initDeque[proc ()](InitDelayedCallbackListSize) + result.callbacks = initDeque[proc () {.closure, gcsafe.}](InitDelayedCallbackListSize) var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher From f5f9243cc05cae998e4380a347da8e93ac547dd4 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 11 Mar 2020 09:28:10 +0100 Subject: [PATCH 0107/4254] disable chronos testing for now --- testament/important_packages.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 9dbb4a4f9..363171082 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -17,7 +17,8 @@ pkg "c2nim", false, "nim c testsuite/tester.nim" pkg "cascade" pkg "chroma" pkg "chronicles", true, "nim c -o:chr -r chronicles.nim" -pkg "chronos", true +# disable until my chronos fix was merged +#pkg "chronos", true pkg "cligen", false, "nim c -o:cligenn -r cligen.nim" pkg "coco", true pkg "combparser" From 281e02fc797ad98013ab29525256ba2ffdaf96a7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 11 Mar 2020 01:47:34 -0700 Subject: [PATCH 0108/4254] fixes #13558: toDateTime buggy on 29th, 30th and 31th of each month; breaking change: do not use `now` to compute result, was undocumented and non-sensical (#13565) --- changelog.md | 4 ++++ lib/pure/times.nim | 16 +++------------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/changelog.md b/changelog.md index b76946464..3cb9547f3 100644 --- a/changelog.md +++ b/changelog.md @@ -31,6 +31,10 @@ and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to restore the old behavior - `joinPath(a,b)` now honors trailing slashes in `b` (or `a` if `b` = "") +- `times.parse` now only uses input to compute its result, and not `now`: + `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of + `2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when + used on 29th, 30th, 31st of each month. ### Breaking changes in the compiler diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 92b6cd3b7..45ed6dd67 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -2248,19 +2248,9 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, input: string): DateTime = - var month = mJan - var year: int - var monthday: int - # `now()` is an expensive call, so we avoid it when possible - (year, month, monthday) = - if p.year.isNone or p.month.isNone or p.monthday.isNone: - let n = now() - (p.year.get(n.year), - p.month.get(n.month.int).Month, - p.monthday.get(n.monthday)) - else: - (p.year.get(), p.month.get().Month, p.monthday.get()) - + var year = p.year.get(0) + var month = p.month.get(1).Month + var monthday = p.monthday.get(1) year = case p.era of eraUnknown: From 70bd41dae08a7ba9a9e8f19a935bee26b689d00d Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 11 Mar 2020 17:30:36 +0100 Subject: [PATCH 0109/4254] fix #13310, Deque misbehaves on VM (#13625) * fix #13310, Deque misbehaves on VM * use 'when nimVM' --- lib/pure/collections/deques.nim | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 1aa525bd6..77579a52b 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -274,8 +274,9 @@ proc expandIfNeeded[T](deq: var Deque[T]) = if unlikely(deq.count >= cap): var n = newSeq[T](cap * 2) var i = 0 - for x in mitems(deq): # don't use copyMem because of the GC and because it's slower. - n[i] = move(x) + for x in mitems(deq): + when nimVM: n[i] = x # workaround for VM bug + else: n[i] = move(x) inc i deq.data = move(n) deq.mask = cap * 2 - 1 @@ -569,3 +570,15 @@ when isMainModule: foo(2, 1) foo(1, 5) foo(3, 2) + + import sets + block t13310: + proc main() = + var q = initDeque[HashSet[int16]](2) + q.addFirst([1'i16].toHashSet) + q.addFirst([2'i16].toHashSet) + q.addFirst([3'i16].toHashSet) + assert $q == "[{3}, {2}, {1}]" + + static: + main() From 6b3098c378430e3387854ffc413ce96bd94a3d2c Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 11 Mar 2020 23:04:33 +0100 Subject: [PATCH 0110/4254] Make listCmd honor hint:cc:off (#13606) * Make listCmd honor hint:cc:off * Tiny cleanup * Tiny tiny cleanup * VERY IMPORTANT: --hint:cc:on will overwrite --verbosity:0 :p * Tiny cleanup * Stupid * Move displayProgressCC to where its required * Tiny cleanup --- compiler/extccomp.nim | 85 ++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 6b4223433..34552e6f3 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -623,7 +623,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, var objfile = if cfile.obj.isEmpty: - if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf): + if CfileFlag.External notin cfile.flags or noAbsolutePaths(conf): toObjFile(conf, cf).string else: completeCfilePath(conf, toObjFile(conf, cf)).string @@ -705,26 +705,6 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = flags: {CfileFlag.External}) addExternalFileToCompile(conf, c) -proc displayProgressCC(conf: ConfigRef, path: string): string = - if conf.hasHint(hintCC): - let (_, name, _) = splitFile(path) - result = MsgKindToStr[hintCC] % demanglePackageName(name) - -proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var TStringSeq, - prettyCmds: var TStringSeq) = - var currIdx = 0 - for it in list: - # call the C compiler for the .c file: - if it.flags.contains(CfileFlag.Cached): continue - var compileCmd = getCompileCFileCmd(conf, it, currIdx == list.len - 1, produceOutput=true) - inc currIdx - if optCompileOnly notin conf.globalOptions: - cmds.add(compileCmd) - prettyCmds.add displayProgressCC(conf, $it.cname) - if optGenScript in conf.globalOptions: - script.add(compileCmd) - script.add("\n") - proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string, isDllBuild: bool): string = if optGenStaticLib in conf.globalOptions: @@ -862,15 +842,8 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: cmds[i]) else: tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): - if optListCmd in conf.globalOptions or conf.verbosity > 1: - res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}, - conf.numberOfProcessors, afterRunEvent=runCb) - elif conf.verbosity == 1: - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, conf.numberOfProcessors, prettyCb, afterRunEvent=runCb) - else: - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, - conf.numberOfProcessors, afterRunEvent=runCb) if res != 0: if conf.numberOfProcessors <= 1: rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % @@ -912,10 +885,12 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu else: platform.OS[conf.target.targetOS].dllFrmt % basename result = conf.getNimcacheDir / RelativeFile(targetName) -template callbackPrettyCmd(cmd) = - when declared(echo): - let cmd2 = cmd - if cmd2.len > 0: echo cmd2 +proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string = + if conf.hasHint(hintCC): + if optListCmd in conf.globalOptions or conf.verbosity > 1: + result = MsgKindToStr[hintCC] % (demanglePackageName(path.splitFile.name) & ": " & compileCmd) + else: + result = MsgKindToStr[hintCC] % demanglePackageName(path.splitFile.name) proc callCCompiler*(conf: ConfigRef) = var @@ -925,10 +900,22 @@ proc callCCompiler*(conf: ConfigRef) = # generated #var c = cCompiler var script: Rope = nil - var cmds: TStringSeq = @[] - var prettyCmds: TStringSeq = @[] - let prettyCb = proc (idx: int) = callbackPrettyCmd(prettyCmds[idx]) - compileCFiles(conf, conf.toCompile, script, cmds, prettyCmds) + var cmds: TStringSeq + var prettyCmds: TStringSeq + let prettyCb = proc (idx: int) = + if prettyCmds[idx].len > 0: echo prettyCmds[idx] + + for idx, it in conf.toCompile: + # call the C compiler for the .c file: + if CfileFlag.Cached in it.flags: continue + let compileCmd = getCompileCFileCmd(conf, it, idx == conf.toCompile.len - 1, produceOutput=true) + if optCompileOnly notin conf.globalOptions: + cmds.add(compileCmd) + prettyCmds.add displayProgressCC(conf, $it.cname, compileCmd) + if optGenScript in conf.globalOptions: + script.add(compileCmd) + script.add("\n") + if optCompileOnly notin conf.globalOptions: execCmdsInParallel(conf, cmds, prettyCb) if optNoLinking notin conf.globalOptions: @@ -947,7 +934,7 @@ proc callCCompiler*(conf: ConfigRef) = # don't relink each of the many binaries (one for each source file) if the nim code is # cached because that would take too much time for small changes - the only downside to # this is that if an external-to-link file changes the final target wouldn't be relinked - if x.flags.contains(CfileFlag.Cached): continue + if CfileFlag.Cached in x.flags: continue # we pass each object file as if it is the project file - a .dll will be created for each such # object file in the nimcache directory, and only in the case of the main project file will # there be probably an executable (if the project is such) which will be copied out of the nimcache @@ -965,7 +952,7 @@ proc callCCompiler*(conf: ConfigRef) = prettyCmds = map(prettyCmds, proc (curr: string): string = return curr.replace("CC", "Link")) execCmdsInParallel(conf, cmds, prettyCb) # only if not cached - copy the resulting main file from the nimcache folder to its originally intended destination - if not conf.toCompile[mainFileIdx].flags.contains(CfileFlag.Cached): + if CfileFlag.Cached notin conf.toCompile[mainFileIdx].flags: let mainObjFile = getObjFilePath(conf, conf.toCompile[mainFileIdx]) var src = conf.hcrLinkTargetName(mainObjFile, true) var dst = conf.prepareToWriteOutput @@ -1011,8 +998,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = f.write escapeJson(x) proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) = - var i = 0 - for it in clist: + for i, it in clist: if CfileFlag.Cached in it.flags: continue let compileCmd = getCompileCFileCmd(conf, it) if i > 0: lit ",\L" @@ -1021,7 +1007,6 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = lit ", " str compileCmd lit "]" - inc i proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList; llist: seq[string]) = @@ -1125,16 +1110,18 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = let data = json.parseFile(jsonFile.string) let toCompile = data["compile"] doAssert toCompile.kind == JArray - var cmds: TStringSeq = @[] - var prettyCmds: TStringSeq = @[] + var cmds: TStringSeq + var prettyCmds: TStringSeq + let prettyCb = proc (idx: int) = + if prettyCmds[idx].len > 0: echo prettyCmds[idx] + for c in toCompile: doAssert c.kind == JArray doAssert c.len >= 2 cmds.add(c[1].getStr) - prettyCmds.add displayProgressCC(conf, c[0].getStr) + prettyCmds.add displayProgressCC(conf, c[0].getStr, c[1].getStr) - let prettyCb = proc (idx: int) = callbackPrettyCmd(prettyCmds[idx]) execCmdsInParallel(conf, cmds, prettyCb) let linkCmd = data["linkcmd"] @@ -1150,10 +1137,8 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = except: let e = getCurrentException() - var msg = "\ncaught exception:n" & e.msg & "\nstacktrace:\n" & - getCurrentException().getStackTrace() & - "error evaluating JSON file: " & jsonFile.string - quit msg + quit "\ncaught exception:n" & e.msg & "\nstacktrace:\n" & e.getStackTrace() & + "error evaluating JSON file: " & jsonFile.string proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = for it in list: From f2c71527709377ddf6825f852a70eef32c2952a6 Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 11 Mar 2020 16:24:56 -0700 Subject: [PATCH 0111/4254] Add more JS stuff to dom.nim (#13483) * Add more JS stuff to dom.nim * Make all links to docs doc comments. * Fix minor textContent * space. * Remove Selection object. * More work on docs. * Fixing links. * Made the links be "see ". --- lib/js/dom.nim | 71 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index cd78f5560..92cc038c9 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -40,8 +40,8 @@ type onsubmit*: proc (event: Event) {.nimcall.} onunload*: proc (event: Event) {.nimcall.} - # https://developer.mozilla.org/en-US/docs/Web/Events DomEvent* {.pure.} = enum + ## see `docs`_ Abort = "abort", BeforeInput = "beforeinput", Blur = "blur", @@ -103,6 +103,8 @@ type memory*: PerformanceMemory timing*: PerformanceTiming + LocalStorage* {.importc.} = ref object + Window* = ref WindowObj WindowObj {.importc.} = object of EventTargetObj document*: Document @@ -129,6 +131,7 @@ type screen*: Screen performance*: Performance onpopstate*: proc (event: Event) + localStorage*: LocalStorage Frame* = ref FrameObj FrameObj {.importc.} = object of WindowObj @@ -165,10 +168,13 @@ type parentNode*: Node previousSibling*: Node innerHTML*: cstring + innerText*: cstring + textContent*: cstring style*: Style Document* = ref DocumentObj DocumentObj {.importc.} = object of NodeObj + activeElement*: Element alinkColor*: cstring bgColor*: cstring body*: Element @@ -211,8 +217,7 @@ type offsetLeft*: int offsetTop*: int - # https://developer.mozilla.org/en-US/docs/Web/API/ValidityState - ValidityState* = ref ValidityStateObj + ValidityState* = ref ValidityStateObj ## see `docs`_ ValidityStateObj {.importc.} = object badInput*: bool customError*: bool @@ -226,20 +231,24 @@ type valid*: bool valueMissing*: bool - # https://developer.mozilla.org/en-US/docs/Web/API/Blob - Blob* = ref BlobObj + Blob* = ref BlobObj ## see `docs`_ BlobObj {.importc.} = object of RootObj size*: int `type`*: cstring - # https://developer.mozilla.org/en-US/docs/Web/API/File - File* = ref FileObj + File* = ref FileObj ## see `docs`_ FileObj {.importc.} = object of Blob lastModified*: int name*: cstring - # https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement - InputElement* = ref InputElementObj + TextAreaElement* = ref TextAreaElementObj ## see `docs`_ + TextAreaElementObj {.importc.} = object of Element + value*: cstring + selectionStart*, selectionEnd*: int + selectionDirection*: cstring + rows*, cols*: int + + InputElement* = ref InputElementObj ## see `docs`_ InputElementObj {.importc.} = object of Element # Properties related to the parent form formAction*: cstring @@ -321,8 +330,7 @@ type text*: cstring value*: cstring - # https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement - FormElement* = ref FormObj + FormElement* = ref FormObj ## see `docs`_ FormObj {.importc.} = object of ElementObj acceptCharset*: cstring action*: cstring @@ -354,6 +362,7 @@ type backgroundImage*: cstring backgroundPosition*: cstring backgroundRepeat*: cstring + backgroundSize*: cstring border*: cstring borderBottom*: cstring borderBottomColor*: cstring @@ -364,6 +373,7 @@ type borderLeftColor*: cstring borderLeftStyle*: cstring borderLeftWidth*: cstring + borderRadius*: cstring borderRight*: cstring borderRightColor*: cstring borderRightStyle*: cstring @@ -375,6 +385,8 @@ type borderTopWidth*: cstring borderWidth*: cstring bottom*: cstring + boxSizing*: cstring + boxShadow*: cstring captionSide*: cstring clear*: cstring clip*: cstring @@ -409,7 +421,10 @@ type minHeight*: cstring minWidth*: cstring opacity*: cstring + outline*: cstring overflow*: cstring + overflowX*: cstring + overflowY*: cstring padding*: cstring paddingBottom*: cstring paddingLeft*: cstring @@ -419,6 +434,7 @@ type pageBreakBefore*: cstring pointerEvents*: cstring position*: cstring + resize*: cstring right*: cstring scrollbar3dLightColor*: cstring scrollbarArrowColor*: cstring @@ -447,8 +463,7 @@ type AtTarget, BubblingPhase - # https://developer.mozilla.org/en-US/docs/Web/API/Event - Event* = ref EventObj + Event* = ref EventObj ## see `docs`_ EventObj {.importc.} = object of RootObj bubbles*: bool cancelBubble*: bool @@ -461,14 +476,12 @@ type `type`*: cstring isTrusted*: bool - # https://developer.mozilla.org/en-US/docs/Web/API/UIEvent - UIEvent* = ref UIEventObj + UIEvent* = ref UIEventObj ## see `docs`_ UIEventObj {.importc.} = object of Event detail*: int64 view*: Window - # https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent - KeyboardEvent* = ref KeyboardEventObj + KeyboardEvent* = ref KeyboardEventObj ## see `docs`_ KeyboardEventObj {.importc.} = object of UIEvent altKey*, ctrlKey*, metaKey*, shiftKey*: bool code*: cstring @@ -477,8 +490,7 @@ type keyCode*: int location*: int - # https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values - KeyboardEventKey* {.pure.} = enum + KeyboardEventKey* {.pure.} = enum ## see `docs`_ # Modifier keys Alt, AltGraph, @@ -832,8 +844,7 @@ type FourthButton = 8, FifthButton = 16 - # https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent - MouseEvent* = ref MouseEventObj + MouseEvent* = ref MouseEventObj ## see `docs`_ MouseEventObj {.importc.} = object of UIEvent altKey*, ctrlKey*, metaKey*, shiftKey*: bool button*: int @@ -851,14 +862,12 @@ type File = "file", String = "string" - # https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem - DataTransferItem* = ref DataTransferItemObj + DataTransferItem* = ref DataTransferItemObj ## see `docs`_ DataTransferItemObj {.importc.} = object of RootObj kind*: cstring `type`*: cstring - # https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer - DataTransfer* = ref DataTransferObj + DataTransfer* = ref DataTransferObj ## see `docs`_ DataTransferObj {.importc.} = object of RootObj dropEffect*: cstring effectAllowed*: cstring @@ -893,8 +902,8 @@ type DragStart = "dragstart", Drop = "drop" - # https://developer.mozilla.org/en-US/docs/Web/API/DragEvent DragEvent* {.importc.} = object of MouseEvent + ## see `docs`_ dataTransfer*: DataTransfer TouchList* {.importc.} = ref object of RootObj @@ -1223,6 +1232,16 @@ proc checkValidity*(e: InputElement): bool # Blob "methods" proc slice*(e: Blob, startindex: int = 0, endindex: int = e.size, contentType: cstring = "") +# Performance "methods" +proc now*(p: Performance): float + +# LocalStorage "methods" +proc getItem*(ls: LocalStorage, key: cstring): cstring +proc setItem*(ls: LocalStorage, key, value: cstring) +proc hasItem*(ls: LocalStorage, key: cstring): bool +proc clear*(ls: LocalStorage) +proc removeItem*(ls: LocalStorage, key: cstring) + {.pop.} proc setAttr*(n: Node; key, val: cstring) {.importcpp: "#.setAttribute(@)".} From 64995db4fdc8d39a9d9c7a1bfb5d8e1dd8c0f902 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Wed, 11 Mar 2020 19:41:45 -0400 Subject: [PATCH 0112/4254] unicode.split: Fix the splitting when a Rune separator is used [backport] (#13629) * unicode.split: Fix the splitting when a Rune separator is used [backport] - Fixes https://github.com/nim-lang/Nim/issues/13628 - Ref https://irclogs.nim-lang.org/11-03-2020.html#20:01:34 * unicode.split: Remove the sepLen based logic.. resulted in wrong jumps --- lib/pure/unicode.nim | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index e1d6f9f9a..d166721d1 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -933,27 +933,23 @@ proc stringHasSep(s: string, index: int, sep: Rune): bool = fastRuneAt(s, index, rune, false) return sep == rune -template splitCommon(s, sep, maxsplit: untyped, sepLen: int = -1) = +template splitCommon(s, sep, maxsplit: untyped) = ## Common code for split procedures. + let + sLen = len(s) var last = 0 splits = maxsplit - if len(s) > 0: - while last <= len(s): + if sLen > 0: + while last <= sLen: var first = last - while last < len(s) and not stringHasSep(s, last, sep): - when sep is Rune: - inc(last, sepLen) - else: - inc(last, runeLenAt(s, last)) - if splits == 0: last = len(s) + while last < sLen and not stringHasSep(s, last, sep): + inc(last, runeLenAt(s, last)) + if splits == 0: last = sLen yield s[first .. (last - 1)] if splits == 0: break dec(splits) - when sep is Rune: - inc(last, sepLen) - else: - inc(last, if last < len(s): runeLenAt(s, last) else: 1) + inc(last, if last < sLen: runeLenAt(s, last) else: 1) iterator split*(s: string, seps: openArray[Rune] = unicodeSpaces, maxsplit: int = -1): string = @@ -1037,7 +1033,7 @@ iterator split*(s: string, sep: Rune, maxsplit: int = -1): string = ## "" ## "" ## - splitCommon(s, sep, maxsplit, sep.size) + splitCommon(s, sep, maxsplit) proc split*(s: string, seps: openArray[Rune] = unicodeSpaces, maxsplit: int = -1): seq[string] {.noSideEffect, rtl, extern: "nucSplitRunes".} = @@ -1424,6 +1420,7 @@ when isMainModule: "an", "example", "", ""] doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example "] + doAssert s3.split("×".runeAt(0)) == @[":this", "is", "an:example", "", ""] block stripTests: doAssert(strip("") == "") From bbc231f8e06c18fe640fa56a927df476c2426ccb Mon Sep 17 00:00:00 2001 From: genotrance Date: Thu, 12 Mar 2020 02:53:11 -0500 Subject: [PATCH 0113/4254] Fix #12676 (#13634) --- compiler/scriptconfig.nim | 4 ++-- lib/system/nimscript.nim | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 6aad1b25f..220486aed 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -57,9 +57,9 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; # Idea: Treat link to file as a file, but ignore link to directory to prevent # endless recursions out of the box. - cbos listFiles: + cbos listFilesImpl: listDirs(a, {pcFile, pcLinkToFile}) - cbos listDirs: + cbos listDirsImpl: listDirs(a, {pcDir}) cbos removeDir: if defined(nimsuggest) or graph.config.cmd == cmdCheck: diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 719e92c4a..b8abdaa38 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -26,13 +26,10 @@ template builtin = discard # We know the effects better than the compiler: {.push hint[XDeclaredButNotUsed]: off.} -proc listDirs*(dir: string): seq[string] = - ## Lists all the subdirectories (non-recursively) in the directory `dir`. - builtin -proc listFiles*(dir: string): seq[string] = - ## Lists all the files (non-recursively) in the directory `dir`. - builtin - +proc listDirsImpl(dir: string): seq[string] {. + tags: [ReadIOEffect], raises: [OSError].} = builtin +proc listFilesImpl(dir: string): seq[string] {. + tags: [ReadIOEffect], raises: [OSError].} = builtin proc removeDir(dir: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin proc removeFile(dir: string) {. @@ -47,6 +44,7 @@ proc copyDir(src, dest: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} = builtin + proc getError: string = builtin proc setCurrentDir(dir: string) = builtin proc getCurrentDir*(): string = @@ -196,6 +194,16 @@ template log(msg: string, body: untyped) = if mode != ScriptMode.WhatIf: body +proc listDirs*(dir: string): seq[string] = + ## Lists all the subdirectories (non-recursively) in the directory `dir`. + result = listDirsImpl(dir) + checkOsError() + +proc listFiles*(dir: string): seq[string] = + ## Lists all the files (non-recursively) in the directory `dir`. + result = listFilesImpl(dir) + checkOsError() + proc rmDir*(dir: string) {.raises: [OSError].} = ## Removes the directory `dir`. log "rmDir: " & dir: From d84c4bba9b5b20386fbf88b1695de6071a48da7d Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 12 Mar 2020 11:01:03 +0100 Subject: [PATCH 0114/4254] Fix #13633 --- compiler/extccomp.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 34552e6f3..dfc13edf5 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -998,10 +998,11 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = f.write escapeJson(x) proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) = + var comma = false for i, it in clist: if CfileFlag.Cached in it.flags: continue let compileCmd = getCompileCFileCmd(conf, it) - if i > 0: lit ",\L" + if comma: lit ",\L"; comma = false lit "[" str it.cname.string lit ", " From 2bb0ada79740b0961fd06ffd477c41dfef531544 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 12 Mar 2020 11:20:08 +0100 Subject: [PATCH 0115/4254] Amend fix for #13633 (#13636) --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index dfc13edf5..2e1846424 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1002,7 +1002,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = for i, it in clist: if CfileFlag.Cached in it.flags: continue let compileCmd = getCompileCFileCmd(conf, it) - if comma: lit ",\L"; comma = false + if comma: lit ",\L" else: comma = true lit "[" str it.cname.string lit ", " From 60a3e036f6aaecabdedfab1103bb859053359f8d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 12 Mar 2020 03:39:10 -0700 Subject: [PATCH 0116/4254] fix #13633 fix koch boot crashing regression (#13635) --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 2e1846424..ee921f4e1 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1138,7 +1138,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = except: let e = getCurrentException() - quit "\ncaught exception:n" & e.msg & "\nstacktrace:\n" & e.getStackTrace() & + quit "\ncaught exception:\n" & e.msg & "\nstacktrace:\n" & e.getStackTrace() & "error evaluating JSON file: " & jsonFile.string proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = From f0cd50f9c48ee6bb585cd85615e5844a8082a8c1 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 12 Mar 2020 16:15:46 +0100 Subject: [PATCH 0117/4254] Change order of forwarded koch boot command line options, so as to be able to overwrite the nimcache location (#13637) --- koch.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index 982517656..c2f28f2e0 100644 --- a/koch.nim +++ b/koch.nim @@ -316,10 +316,10 @@ proc boot(args: string) = # in order to use less memory, we split the build into two steps: # --compileOnly produces a $project.json file and does not run GCC/Clang. # jsonbuild then uses the $project.json file to build the Nim binary. - exec "$# $# $# $# --nimcache:$# --compileOnly compiler" / "nim.nim" % - [nimi, bootOptions, extraOption, args, smartNimcache] - exec "$# jsonscript $# --nimcache:$# compiler" / "nim.nim" % - [nimi, args, smartNimcache] + exec "$# $# $# --nimcache:$# $# --compileOnly compiler" / "nim.nim" % + [nimi, bootOptions, extraOption, smartNimcache, args] + exec "$# jsonscript --nimcache:$# $# compiler" / "nim.nim" % + [nimi, smartNimcache, args] if sameFileContent(output, i.thVersion): copyExe(output, finalDest) From 14b2354b7da36041ca046e60e833b5be9a04f1e4 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 12 Mar 2020 20:07:02 +0100 Subject: [PATCH 0118/4254] rename `lenTuple` and `lenVarargs` (#13639) * rename 'lenTuple' to 'tupleLen' Rationale: `lenTuple` is a tuple consisting of lengths (e.g. `(1, 5, 0)`), `tupleLen` is a length of a tuple (e.g. `tupleLen((1, 5, 0) == 3`) * rename 'lenVarargs' to 'varargsLen' The same rationale as a previous commit. Consistency. --- changelog.md | 2 +- compiler/semmagic.nim | 2 +- lib/pure/typetraits.nim | 6 ++-- lib/system.nim | 6 ++-- tests/metatype/ttypetraits.nim | 30 +++++++++---------- .../{tlenvarargs.nim => tvarargslen.nim} | 19 ++++++------ 6 files changed, 33 insertions(+), 32 deletions(-) rename tests/system/{tlenvarargs.nim => tvarargslen.nim} (84%) diff --git a/changelog.md b/changelog.md index 3cb9547f3..0fb99c6f4 100644 --- a/changelog.md +++ b/changelog.md @@ -66,7 +66,7 @@ - Added `sugar.collect` that does comprehension for seq/set/table collections. - Added `sugar.capture` for capturing some local loop variables when creating a closure. This is an enhanced version of `closureScope`. -- Added `typetraits.lenTuple` to get number of elements of a tuple/type tuple, +- Added `typetraits.tupleLen` to get number of elements of a tuple/type tuple, and `typetraits.get` to get the ith element of a type tuple. - Added `typetraits.genericParams` to return a tuple of generic params from a generic instantiation - Added `os.normalizePathEnd` for additional path sanitization. diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index ffdad5628..af80b3ca3 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -187,7 +187,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) var operand = operand.skipTypes({tyGenericInst}) let cond = operand.kind == tyTuple and operand.n != nil result = newIntNodeT(toInt128(ord(cond)), traitCall, c.graph) - of "lenTuple": + of "tupleLen": var operand = operand.skipTypes({tyGenericInst}) assert operand.kind == tyTuple, $operand.kind result = newIntNodeT(toInt128(operand.len), traitCall, c.graph) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 750c6233d..66b94e238 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -72,13 +72,13 @@ proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} ## compile time error otherwise -proc lenTuple*(T: typedesc[tuple]): int {.magic: "TypeTrait", since: (1, 1).} +proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait", since: (1, 1).} ## Return number of elements of `T` since (1, 1): - template lenTuple*(t: tuple): int = + template tupleLen*(t: tuple): int = ## Return number of elements of `t` - lenTuple(type(t)) + tupleLen(type(t)) since (1, 1): template get*(T: typedesc[tuple], i: static int): untyped = diff --git a/lib/system.nim b/lib/system.nim index 51ff3af40..5dff62806 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2682,10 +2682,10 @@ when defined(nimV2): import system/repr_v2 export repr_v2 -macro lenVarargs*(x: varargs[untyped]): int {.since: (1, 1).} = +macro varargsLen*(x: varargs[untyped]): int {.since: (1, 1).} = ## returns number of variadic arguments in `x` - proc lenVarargsImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.} - lenVarargsImpl(x) + proc varargsLenImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.} + varargsLenImpl(x) when false: template eval*(blk: typed): typed = diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 7badf8317..db8c8e5de 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -92,40 +92,40 @@ block distinctBase: doAssert($distinctBase(typeof(b2)) == "string") doAssert($distinctBase(typeof(c2)) == "int") -block: # lenTuple - doAssert not compiles(lenTuple(int)) +block: # tupleLen + doAssert not compiles(tupleLen(int)) type MyTupleType = (int,float,string) - static: doAssert MyTupleType.lenTuple == 3 + static: doAssert MyTupleType.tupleLen == 3 type MyGenericTuple[T] = (T,int,float) MyGenericAlias = MyGenericTuple[string] - static: doAssert MyGenericAlias.lenTuple == 3 + static: doAssert MyGenericAlias.tupleLen == 3 type MyGenericTuple2[T,U] = (T,U,string) MyGenericTuple2Alias[T] = MyGenericTuple2[T,int] MyGenericTuple2Alias2 = MyGenericTuple2Alias[float] - static: doAssert MyGenericTuple2Alias2.lenTuple == 3 + static: doAssert MyGenericTuple2Alias2.tupleLen == 3 - static: doAssert (int, float).lenTuple == 2 - static: doAssert (1, ).lenTuple == 1 - static: doAssert ().lenTuple == 0 + static: doAssert (int, float).tupleLen == 2 + static: doAssert (1, ).tupleLen == 1 + static: doAssert ().tupleLen == 0 let x = (1,2,) - doAssert x.lenTuple == 2 - doAssert ().lenTuple == 0 - doAssert (1,).lenTuple == 1 - doAssert (int,).lenTuple == 1 - doAssert type(x).lenTuple == 2 - doAssert type(x).default.lenTuple == 2 + doAssert x.tupleLen == 2 + doAssert ().tupleLen == 0 + doAssert (1,).tupleLen == 1 + doAssert (int,).tupleLen == 1 + doAssert type(x).tupleLen == 2 + doAssert type(x).default.tupleLen == 2 type T1 = (int,float) type T2 = T1 - doAssert T2.lenTuple == 2 + doAssert T2.tupleLen == 2 block genericParams: type Foo[T1, T2]=object diff --git a/tests/system/tlenvarargs.nim b/tests/system/tvarargslen.nim similarity index 84% rename from tests/system/tlenvarargs.nim rename to tests/system/tvarargslen.nim index ca12c8171..a129aa5c2 100644 --- a/tests/system/tlenvarargs.nim +++ b/tests/system/tvarargslen.nim @@ -1,9 +1,9 @@ discard """ output: ''' -tlenvarargs.nim:35:9 (1, 2) -tlenvarargs.nim:36:9 12 -tlenvarargs.nim:37:9 1 -tlenvarargs.nim:38:8 +tvarargslen.nim:35:9 (1, 2) +tvarargslen.nim:36:9 12 +tvarargslen.nim:37:9 1 +tvarargslen.nim:38:8 done ''' """ @@ -14,19 +14,19 @@ template myecho*(a: varargs[untyped]) = ## on macros.nim) so can be used in more contexts const info = instantiationInfo(-1, false) const loc = info.filename & ":" & $info.line & ":" & $info.column & " " - when lenVarargs(a) > 0: + when varargsLen(a) > 0: echo(loc, a) else: echo(loc) template fun*(a: varargs[untyped]): untyped = - lenVarargs(a) + varargsLen(a) template fun2*(a: varargs[typed]): untyped = - a.lenVarargs + a.varargsLen template fun3*(a: varargs[int]): untyped = - a.lenVarargs + a.varargsLen template fun4*(a: varargs[untyped]): untyped = len(a) @@ -49,11 +49,12 @@ proc main()= doAssert fun3(10) == 1 doAssert fun3(10, 11) == 2 - ## shows why `lenVarargs` can't be named `len` + ## shows why `varargsLen` can't be named `len` doAssert fun4("abcdef") == len("abcdef") ## workaround for BUG:D20191218T171447 whereby if testament expected output ends ## in space, testament strips it from expected output but not actual output, ## which leads to a mismatch when running test via megatest echo "done" + main() From a6682de0045468ae1d15afbd2fd5378960e15eb7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 12 Mar 2020 23:44:33 +0100 Subject: [PATCH 0119/4254] catchable defects (#13626) * allow defects to be caught even for --exceptions:goto (WIP) * implemented the new --panics:on|off switch; refs https://github.com/nim-lang/RFCs/issues/180 * new implementation for integer overflow checking * produce a warning if a user-defined exception type inherits from Exception directly * applied Timothee's suggestions; improved the documentation and replace the term 'checked runtime check' by 'panic' * fixes #13627 * don't inherit from Exception directly --- changelog.md | 8 ++ compiler/ast.nim | 4 +- compiler/ccgcalls.nim | 16 +++- compiler/ccgexprs.nim | 126 +++++++++++++----------- compiler/ccgstmts.nim | 63 ++++++------ compiler/cgen.nim | 1 + compiler/commands.nim | 4 + compiler/condsyms.nim | 1 + compiler/enumtostr.nim | 2 + compiler/lineinfos.nim | 7 +- compiler/modulegraphs.nim | 1 + compiler/options.nim | 11 ++- compiler/semstmts.nim | 2 +- compiler/semtypes.nim | 3 + compiler/sizealignoffsetimpl.nim | 2 +- doc/advopt.txt | 1 + doc/manual.rst | 34 ++++--- koch.nim | 2 +- lib/nimbase.h | 22 +++++ lib/system.nim | 5 +- lib/system/arithm.nim | 4 +- lib/system/chcks.nim | 18 +++- lib/system/fatal.nim | 19 +--- lib/system/gc.nim | 8 +- lib/system/gc_common.nim | 2 +- lib/system/gc_ms.nim | 6 +- lib/system/gc_regions.nim | 7 +- lib/system/integerops.nim | 132 ++++++++++++++++++++++++++ lib/system/mm/boehm.nim | 4 +- lib/system/mm/none.nim | 4 +- lib/system/mmdisp.nim | 6 +- tests/assert/tassert_c.nim | 2 +- tests/destructor/tgotoexceptions7.nim | 52 ++++++++++ tests/range/tsubrange2.nim | 2 +- tests/range/tsubrange3.nim | 2 +- 35 files changed, 441 insertions(+), 142 deletions(-) create mode 100644 lib/system/integerops.nim create mode 100644 tests/destructor/tgotoexceptions7.nim diff --git a/changelog.md b/changelog.md index 0fb99c6f4..fa753e7c4 100644 --- a/changelog.md +++ b/changelog.md @@ -161,6 +161,14 @@ echo f - The compiler now inferes "sink parameters". To disable this for a specific routine, annotate it with `.nosinks`. To disable it for a section of code, use `{.push sinkInference: off.}`...`{.pop.}`. +- The compiler now supports a new switch `--panics:on` that turns runtime + errors like `IndexError` or `OverflowError` into fatal errors that **cannot** + be caught via Nim's `try` statement. `--panics:on` can improve the + runtime efficiency and code size of your program significantly. +- The compiler now warns about inheriting directly from `system.Exception` as + this is **very bad** style. You should inherit from `ValueError`, `IOError`, + `OSError` or from a different specific exception type that inherits from + `CatchableError` and cannot be confused with a `Defect`. ## Bugfixes diff --git a/compiler/ast.nim b/compiler/ast.nim index 62c301a43..55ad2ba4b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -229,7 +229,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 41 flags! + TSymFlag* = enum # 42 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -289,6 +289,8 @@ type sfTemplateParam # symbol is a template parameter sfCursor # variable/field is a cursor, see RFC 177 for details sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation + sfAlwaysReturn # proc can never raise an exception, not even OverflowError + # or out-of-memory TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index da5dd9b76..3e2cf2271 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -557,6 +557,18 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add(~"];$n") line(p, cpsStmts, pl) +proc canRaiseDisp(p: BProc; n: PNode): bool = + # we assume things like sysFatal cannot raise themselves + if n.kind == nkSym and sfAlwaysReturn in n.sym.flags: + result = false + elif optPanics in p.config.globalOptions or + (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): + # we know we can be strict: + result = canRaise(n) + else: + # we have to be *very* conservative: + result = canRaiseConservative(n) + proc genCall(p: BProc, e: PNode, d: var TLoc) = if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: genClosureCall(p, nil, e, d) @@ -567,7 +579,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) = else: genPrefixCall(p, nil, e, d) postStmtActions(p) - if p.config.exc == excGoto and canRaise(e[0]): + if p.config.exc == excGoto and canRaiseDisp(p, e[0]): raiseExit(p) proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = @@ -580,5 +592,5 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = else: genPrefixCall(p, le, ri, d) postStmtActions(p) - if p.config.exc == excGoto and canRaise(ri[0]): + if p.config.exc == excGoto and canRaiseDisp(p, ri[0]): raiseExit(p) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1bed4bc6c..4aad1a4f8 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -506,23 +506,25 @@ template binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; else: getTypeDesc(p.module, t) var result = getTempName(p.module) linefmt(p, cpsLocals, "$1 $2;$n", [storage, result]) - lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n", [result, cpname, rdCharLoc(a), rdCharLoc(b)]) + lineCg(p, cpsStmts, "if (#$2($3, $4, &$1)) { #raiseOverflow(); $5};$n", + [result, cpname, rdCharLoc(a), rdCharLoc(b), raiseInstr(p)]) if size < p.config.target.intSize or t.kind in {tyRange, tyEnum}: - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n", - [result, intLiteral(firstOrd(p.config, t)), intLiteral(lastOrd(p.config, t))]) + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3){ #raiseOverflow(); $4}$n", + [result, intLiteral(firstOrd(p.config, t)), intLiteral(lastOrd(p.config, t)), + raiseInstr(p)]) result proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = const prc: array[mAddI..mPred, string] = [ - "addInt", "subInt", - "mulInt", "divInt", "modInt", - "addInt", "subInt" + "nimAddInt", "nimSubInt", + "nimMulInt", "nimDivInt", "nimModInt", + "nimAddInt", "nimSubInt" ] prc64: array[mAddI..mPred, string] = [ - "addInt64", "subInt64", - "mulInt64", "divInt64", "modInt64", - "addInt64", "subInt64" + "nimAddInt64", "nimSubInt64", + "nimMulInt64", "nimDivInt64", "nimModInt64", + "nimAddInt64", "nimSubInt64" ] opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"] var a, b: TLoc @@ -537,6 +539,12 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)] putIntoDest(p, d, e, res) else: + # we handle div by zero here so that we know that the compilerproc's + # result is only for overflows. + if m in {mDivI, mModI}: + linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); $2}$n", + [rdLoc(b), raiseInstr(p)]) + let res = binaryArithOverflowRaw(p, t, a, b, if t.kind == tyInt64: prc64[m] else: prc[m]) putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) @@ -549,8 +557,8 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = initLocExpr(p, e[1], a) t = skipTypes(e.typ, abstractRange) if optOverflowCheck in p.options: - linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n", - [rdLoc(a), intLiteral(firstOrd(p.config, t))]) + linefmt(p, cpsStmts, "if ($1 == $2){ #raiseOverflow(); $3}$n", + [rdLoc(a), intLiteral(firstOrd(p.config, t)), raiseInstr(p)]) case m of mUnaryMinusI: putIntoDest(p, d, e, "((NI$2)-($1))" % [rdLoc(a), rope(getSize(p.config, t) * 8)]) @@ -817,12 +825,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg)) if op.magic == mNot: linefmt(p, cpsStmts, - "if ($1) #raiseFieldError($2);$n", - [rdLoc(test), strLit]) + "if ($1){ #raiseFieldError($2); $3}$n", + [rdLoc(test), strLit, raiseInstr(p)]) else: linefmt(p, cpsStmts, - "if (!($1)) #raiseFieldError($2);$n", - [rdLoc(test), strLit]) + "if (!($1)){ #raiseFieldError($2); $3}$n", + [rdLoc(test), strLit, raiseInstr(p)]) proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = if optFieldCheck in p.options: @@ -861,11 +869,11 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = # semantic pass has already checked for const index expressions if firstOrd(p.config, ty) == 0: if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)): - linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError2($1, $2);$n", - [rdCharLoc(b), intLiteral(lastOrd(p.config, ty))]) + linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)){ #raiseIndexError2($1, $2); $3}$n", + [rdCharLoc(b), intLiteral(lastOrd(p.config, ty)), raiseInstr(p)]) else: - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError3($1, $2, $3);$n", - [rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))]) + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3){ #raiseIndexError3($1, $2, $3); $4}$n", + [rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)), raiseInstr(p)]) else: let idx = getOrdValue(y) if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty): @@ -888,19 +896,19 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = of tyOpenArray, tyVarargs: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n", - [rdLoc(a), rdLoc(b), rdLoc(arr)]) + "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n", + [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) of tyArray: let first = intLiteral(firstOrd(p.config, ty)) linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", - [rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))]) + "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)){ #raiseIndexError(); $5}$n", + [rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)), raiseInstr(p)]) of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)) #raiseIndexError();$n", - [rdLoc(a), rdLoc(b), lenExpr(p, arr)]) + "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)){ #raiseIndexError(); $4}$n", + [rdLoc(a), rdLoc(b), lenExpr(p, arr), raiseInstr(p)]) else: discard proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = @@ -908,8 +916,8 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = initLocExpr(p, x, a) initLocExpr(p, y, b) # emit range check: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError2($1,$2Len_0-1);$n", - [rdLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", + [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) @@ -924,12 +932,12 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if optBoundsCheck in p.options: if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): linefmt(p, cpsStmts, - "if ((NU)($1) > (NU)$2) #raiseIndexError2($1,$2);$n", - [rdLoc(b), lenExpr(p, a)]) + "if ((NU)($1) > (NU)$2){ #raiseIndexError2($1,$2); $3}$n", + [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) else: linefmt(p, cpsStmts, - "if ((NU)($1) >= (NU)$2) #raiseIndexError2($1,$2-1);$n", - [rdLoc(b), lenExpr(p, a)]) + "if ((NU)($1) >= (NU)$2){ #raiseIndexError2($1,$2-1); $3}$n", + [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = ropecg(p.module, "(*$1)", [a.r]) @@ -1938,21 +1946,33 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = # C code; plus it's the right thing to do for closures: genSomeCast(p, e, d) -proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) = +proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = var a: TLoc var dest = skipTypes(n.typ, abstractVar) + initLocExpr(p, n[0], a) if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures): - initLocExpr(p, n[0], a) - putIntoDest(p, d, n, "(($1) ($2))" % - [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) + discard "no need to generate a check because it was disabled" else: - let mm = if dest.kind in {tyUInt32, tyUInt64, tyUInt}: "chckRangeU" else: magic - initLocExpr(p, n[0], a) - putIntoDest(p, d, lodeTyp dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [ - getTypeDesc(p.module, dest), rdCharLoc(a), - genLiteral(p, n[1], dest), genLiteral(p, n[2], dest), - mm]), a.storage) + let raiser = + case skipTypes(n.typ, abstractVarRange).kind + of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU" + of tyFloat..tyFloat128: "raiseRangeErrorF" + else: "raiseRangeErrorI" + discard cgsym(p.module, raiser) + # This seems to be bug-compatible with Nim version 1 but what we + # should really do here is to check if uint64Value < high(int) + let boundaryCast = + if n[0].typ.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64}: + "(NI64)" + else: + "" + # emit range check: + linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n", + [rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest), + raiser, raiseInstr(p), boundaryCast]) + putIntoDest(p, d, n, "(($1) ($2))" % + [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) proc genConv(p: BProc, e: PNode, d: var TLoc) = let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink}) @@ -2004,9 +2024,9 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = [opr[m], rdLoc(a), rdLoc(b), getSimpleTypeDesc(p.module, e[1].typ)])) if optNaNCheck in p.options: - linefmt(p, cpsStmts, "#nanCheck($1);$n", [rdLoc(d)]) + linefmt(p, cpsStmts, "if ($1 != $1){ #raiseFloatInvalidOp(); $2}$n", [rdLoc(d), raiseInstr(p)]) if optInfCheck in p.options: - linefmt(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)]) + linefmt(p, cpsStmts, "if ($1 != 0.0 && $1*0.5 == $1) { #raiseFloatOverflow($1); $2}$n", [rdLoc(d), raiseInstr(p)]) else: binaryArith(p, e, d, m) @@ -2122,10 +2142,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mSwap: genSwap(p, e, d) of mInc, mDec: const opr: array[mInc..mDec, string] = ["+=", "-="] - const fun64: array[mInc..mDec, string] = ["addInt64", - "subInt64"] - const fun: array[mInc..mDec, string] = ["addInt", - "subInt"] + const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] + const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) @@ -2432,11 +2450,11 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = else: genTypeInfo(p.module, dest, n.info) if nilCheck != nil: - linefmt(p, cpsStmts, "if ($1) #chckObj($2, $3);$n", - [nilCheck, r, checkFor]) + linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n", + [nilCheck, r, checkFor, raiseInstr(p)]) else: - linefmt(p, cpsStmts, "#chckObj($1, $2);$n", - [r, checkFor]) + linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); $3}$n", + [r, checkFor, raiseInstr(p)]) if n[0].typ.kind != tyObject: putIntoDest(p, d, n, "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) @@ -2629,9 +2647,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = expr(p, n[1][0], d) of nkObjDownConv: downConv(p, n, d) of nkObjUpConv: upConv(p, n, d) - of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF") - of nkChckRange64: genRangeChck(p, n, d, "chckRange64") - of nkChckRange: genRangeChck(p, n, d, "chckRange") + of nkChckRangeF: genRangeChck(p, n, d) + of nkChckRange64: genRangeChck(p, n, d) + of nkChckRange: genRangeChck(p, n, d) of nkStringToCString: convStrToCStr(p, n, d) of nkCStringToString: convCStrToStr(p, n, d) of nkLambdaKinds: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 9c067a339..1c63ebaea 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -706,6 +706,22 @@ proc finallyActions(p: BProc) = if finallyBlock != nil: genSimpleBlock(p, finallyBlock[0]) +proc raiseInstr(p: BProc): Rope = + if p.config.exc == excGoto: + let L = p.nestedTryStmts.len + if L == 0: + p.flags.incl beforeRetNeeded + # easy case, simply goto 'ret': + result = ropecg(p.module, "goto BeforeRet_;$n", []) + else: + # raise inside an 'except' must go to the finally block, + # raise outside an 'except' block must go to the 'except' list. + result = ropecg(p.module, "goto LA$1_;$n", + [p.nestedTryStmts[L-1].label]) + # + ord(p.nestedTryStmts[L-1].inExcept)]) + else: + result = nil + proc genRaiseStmt(p: BProc, t: PNode) = if p.config.exc == excCpp: discard cgsym(p.module, "popCurrentExceptionEx") @@ -733,18 +749,9 @@ proc genRaiseStmt(p: BProc, t: PNode) = line(p, cpsStmts, ~"throw;$n") else: linefmt(p, cpsStmts, "#reraiseException();$n", []) - if p.config.exc == excGoto: - let L = p.nestedTryStmts.len - if L == 0: - p.flags.incl beforeRetNeeded - # easy case, simply goto 'ret': - lineCg(p, cpsStmts, "goto BeforeRet_;$n", []) - else: - # raise inside an 'except' must go to the finally block, - # raise outside an 'except' block must go to the 'except' list. - lineCg(p, cpsStmts, "goto LA$1_;$n", - [p.nestedTryStmts[L-1].label]) - # + ord(p.nestedTryStmts[L-1].inExcept)]) + let gotoInstr = raiseInstr(p) + if gotoInstr != nil: + line(p, cpsStmts, gotoInstr) template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, rangeFormat, eqFormat: FormatStr, labl: TLabel) = @@ -1009,14 +1016,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = genSimpleBlock(p, t[^1][0]) -proc bodyCanRaise(n: PNode): bool = +proc bodyCanRaise(p: BProc; n: PNode): bool = case n.kind of nkCallKinds: - result = canRaise(n[0]) + result = canRaiseDisp(p, n[0]) if not result: # also check the arguments: for i in 1 ..< n.len: - if bodyCanRaise(n[i]): return true + if bodyCanRaise(p, n[i]): return true of nkRaiseStmt: result = true of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, @@ -1024,22 +1031,24 @@ proc bodyCanRaise(n: PNode): bool = result = false else: for i in 0 ..< safeLen(n): - if bodyCanRaise(n[i]): return true + if bodyCanRaise(p, n[i]): return true result = false proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = - if not bodyCanRaise(t): + let fin = if t[^1].kind == nkFinally: t[^1] else: nil + inc p.labels + let lab = p.labels + p.nestedTryStmts.add((fin, false, Natural lab)) + + if not bodyCanRaise(p, t): # optimize away the 'try' block: expr(p, t[0], d) - if t.len > 1 and t[^1].kind == nkFinally: - genStmts(p, t[^1][0]) + linefmt(p, cpsStmts, "LA$1_: ;$n", [lab]) + if fin != nil: + genStmts(p, fin[0]) + discard pop(p.nestedTryStmts) return - let fin = if t[^1].kind == nkFinally: t[^1] else: nil - inc p.labels, 2 - let lab = p.labels-1 - p.nestedTryStmts.add((fin, false, Natural lab)) - p.flags.incl nimErrorFlagAccessed p.procSec(cpsLocals).add(ropecg(p.module, "NI oldNimErr$1_;$n", [lab])) linefmt(p, cpsStmts, "oldNimErr$1_ = *nimErr_; *nimErr_ = 0;;$n", [lab]) @@ -1099,7 +1108,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = #linefmt(p, cpsStmts, "LA$1_:;$n", [lab+1]) if i < t.len and t[i].kind == nkFinally: startBlock(p) - if not bodyCanRaise(t[i][0]): + if not bodyCanRaise(p, t[i][0]): # this is an important optimization; most destroy blocks are detected not to raise an # exception and so we help the C optimizer by not mutating nimErr_ pointlessly: genStmts(p, t[i][0]) @@ -1380,8 +1389,8 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = genCaseObjDiscMapping(p, e[0], t, field, oldVal) genCaseObjDiscMapping(p, e[1], t, field, newVal) lineCg(p, cpsStmts, - "#nimFieldDiscriminantCheckV2($1, $2);$n", - [rdLoc(oldVal), rdLoc(newVal)]) + "if ($1 != $2) { #raiseObjectCaseTransition(); $3}$n", + [rdLoc(oldVal), rdLoc(newVal), raiseInstr(p)]) else: genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field) genAssignment(p, a, tmp, {}) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 57424ec95..06507b6e6 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -276,6 +276,7 @@ proc postStmtActions(p: BProc) {.inline.} = proc accessThreadLocalVar(p: BProc, s: PSym) proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} proc genProc(m: BModule, prc: PSym) +proc raiseInstr(p: BProc): Rope template compileToCpp(m: BModule): untyped = m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags diff --git a/compiler/commands.nim b/compiler/commands.nim index 0c93654da..62d4d75dd 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -881,6 +881,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info) of "sinkinference": processOnOffSwitch(conf, {optSinkInference}, arg, pass, info) + of "panics": + processOnOffSwitchG(conf, {optPanics}, arg, pass, info) + if optPanics in conf.globalOptions: + defineSymbol(conf.symbols, "nimPanics") of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) handleStdinInput(conf) else: diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a84b0d878..da40dd2b7 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -113,3 +113,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasLibFFIEnabled") defineSymbol("nimHasSinkInference") + defineSymbol("nimNewIntegerOps") diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 42d844609..614190ac3 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -40,6 +40,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym = n[resultPos] = newSymNode(res) result.ast = n incl result.flags, sfFromGeneric + incl result.flags, sfAlwaysReturn proc searchObjCaseImpl(obj: PNode; field: PSym): PNode = case obj.kind @@ -101,3 +102,4 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra n[resultPos] = newSymNode(res) result.ast = n incl result.flags, sfFromGeneric + incl result.flags, sfAlwaysReturn diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 5ac65201e..6eac5bf1b 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -34,6 +34,7 @@ type warnTypelessParam, warnUseBase, warnWriteToForeignHeap, warnUnsafeCode, warnUnusedImportX, + warnInheritFromException, warnEachIdentIsTuple, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, @@ -81,6 +82,7 @@ const warnWriteToForeignHeap: "write to foreign heap", warnUnsafeCode: "unsafe code: '$1'", warnUnusedImportX: "imported and not used: '$1'", + warnInheritFromException: "inherit from a more precise exception type like ValueError, IOError or OSError", warnEachIdentIsTuple: "each identifier is a tuple", warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", warnProveField: "cannot prove that field '$1' is accessible", @@ -138,7 +140,8 @@ const "LanguageXNotSupported", "FieldXNotSupported", "CommentXIgnored", "TypelessParam", "UseBase", "WriteToForeignHeap", - "UnsafeCode", "UnusedImport", "EachIdentIsTuple", + "UnsafeCode", "UnusedImport", "InheritFromException", + "EachIdentIsTuple", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "ResultShadowed", "Spacing", "CaseTransition", "CycleCreated", "User"] @@ -227,7 +230,7 @@ type TErrorOutputs* = set[TErrorOutput] ERecoverableError* = object of ValueError - ESuggestDone* = object of Exception + ESuggestDone* = object of ValueError proc `==`*(a, b: FileIndex): bool {.borrow.} diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 3a6d28708..d3be4b3b6 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -165,6 +165,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} = proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo, {}) result.magic = m + result.flags = {sfAlwaysReturn} proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result = ModuleGraph() diff --git a/compiler/options.nim b/compiler/options.nim index 42406272c..88251a42e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -90,6 +90,7 @@ type # please make sure we have under 32 options optNimV019 optBenchmarkVM # Enables cpuTime() in the VM optProduceAsm # produce assembler code + optPanics # turn panics (sysFatal) into a process termination TGlobalOptions* = set[TGlobalOption] @@ -509,15 +510,17 @@ proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): Absolute proc absOutFile*(conf: ConfigRef): AbsoluteFile = result = conf.outDir / conf.outFile - if dirExists(result.string): - result.string.add ".out" + when defined(posix): + if dirExists(result.string): + result.string.add ".out" proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile = ## Create the output directory and returns a full path to the output file createDir conf.outDir result = conf.outDir / conf.outFile - if dirExists(result.string): - result.string.add ".out" + when defined(posix): + if dirExists(result.string): + result.string.add ".out" proc getPrefixDir*(conf: ConfigRef): AbsoluteDir = ## Gets the prefix dir, usually the parent directory where the binary resides. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b91e93025..cdb47d2a4 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1283,7 +1283,7 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0: x = x.lastSon if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and - s.typ.kind notin {tyObject, tyEnum}: + s.typ.skipTypes(abstractPtrs-{tyAlias}).kind notin {tyObject, tyEnum}: # type aliases are hard: var t = semTypeNode(c, x, nil) assert t != nil diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f05affc6b..e0be620c3 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -847,6 +847,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PTy # specialized object, there will be second check after instantiation # located in semGeneric. if concreteBase.kind == tyObject: + if concreteBase.sym != nil and concreteBase.sym.magic == mException and + sfSystemModule notin c.module.flags: + message(c.config, n.info, warnInheritFromException, "") addInheritedFields(c, check, pos, concreteBase) else: if concreteBase.kind != tyError: diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index ee88e276f..81d2f5faf 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -23,7 +23,7 @@ const szUncomputedSize* = -1 szTooBigSize* = -4 -type IllegalTypeRecursionError = object of Exception +type IllegalTypeRecursionError = object of ValueError proc raiseIllegalTypeRecursion() = raise newException(IllegalTypeRecursionError, "illegal type recursion") diff --git a/doc/advopt.txt b/doc/advopt.txt index 517edab5b..1ebec0f49 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -146,3 +146,4 @@ Advanced options: see also https://nim-lang.github.io/Nim/estp.html --benchmarkVM:on|off enable benchmarking of VM code with cpuTime() --sinkInference:on|off en-/disable sink parameter inference (default: on) + --panics:on|off turn panics into process terminations (default: off) diff --git a/doc/manual.rst b/doc/manual.rst index 516be24ea..3a0faed2e 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -105,13 +105,13 @@ identifier meanings, and in some cases expression values. An error detected during semantic analysis is called a `static error`:idx:. Errors described in this manual are static errors when not otherwise specified. -A `checked runtime error`:idx: is an error that the implementation detects +A `panic`:idx: is an error that the implementation detects and reports at runtime. The method for reporting such errors is via *raising exceptions* or *dying with a fatal error*. However, the implementation provides a means to disable these `runtime checks`:idx:. See the section pragmas_ for details. -Whether a checked runtime error results in an exception or in a fatal error is +Whether a panic results in an exception or in a fatal error is implementation specific. Thus the following program is invalid; even though the code purports to catch the `IndexError` from an out-of-bounds array access, the compiler may instead choose to allow the program to die with a fatal error. @@ -124,6 +124,12 @@ compiler may instead choose to allow the program to die with a fatal error. except IndexError: echo "invalid index" +The current implementation allows to switch between these different behaviors +via ``--panics:on|off``. When panics are turned on, the program dies on a +panic, if they are turned off the runtime errors are turned into +exceptions. The benefit of ``--panics:on`` is that it produces smaller binary +code and the compiler has more freedom to optimize the code. + An `unchecked runtime error`:idx: is an error that is not guaranteed to be detected, and can cause the subsequent behavior of the computation to be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx: @@ -869,9 +875,9 @@ Ordinal types have the following characteristics: the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to be defined. - Ordinal values have a smallest possible value. Trying to count further - down than the smallest value gives a checked runtime or static error. + down than the smallest value produces a panic or a static error. - Ordinal values have a largest possible value. Trying to count further - than the largest value gives a checked runtime or static error. + than the largest value produces a panic or a static error. Integers, bool, characters and enumeration types (and subranges of these types) belong to ordinal types. For reasons of simplicity of implementation @@ -982,7 +988,7 @@ lowest and highest value of the type. For example: to 5. ``PositiveFloat`` defines a subrange of all positive floating point values. NaN does not belong to any subrange of floating point types. Assigning any other value to a variable of type ``Subrange`` is a -checked runtime error (or static error if it can be determined during +panic (or a static error if it can be determined during semantic analysis). Assignments from the base type to one of its subrange types (and vice versa) are allowed. @@ -1763,9 +1769,9 @@ Nil If a reference points to *nothing*, it has the value ``nil``. ``nil`` is also the default value for all ``ref`` and ``ptr`` types. Dereferencing ``nil`` -is an unrecoverable fatal runtime error. A dereferencing operation ``p[]`` -implies that ``p`` is not nil. This can be exploited by the implementation to -optimize code like: +is an unrecoverable fatal runtime error (and not a panic). +A dereferencing operation ``p[]`` implies that ``p`` is not nil. This can be +exploited by the implementation to optimize code like: .. code-block:: nim @@ -4107,7 +4113,7 @@ branch always has to be ``void``: .. code-block:: nim from strutils import parseInt - + let x = try: parseInt("133a") except: -1 finally: echo "hi" @@ -4242,9 +4248,11 @@ The exception tree is defined in the `system `_ module. Every exception inherits from ``system.Exception``. Exceptions that indicate programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``) and are stricly speaking not catchable as they can also be mapped to an operation -that terminates the whole process. Exceptions that indicate any other runtime -error that can be caught inherit from ``system.CatchableError`` -(which is a subtype of ``Exception``). +that terminates the whole process. If panics are turned into exceptions, these +exceptions inherit from `Defect`. + +Exceptions that indicate any other runtime error that can be caught inherit from +``system.CatchableError`` (which is a subtype of ``Exception``). Imported exceptions @@ -5667,7 +5675,7 @@ The ``include`` statement can be used outside of the top level, as such: # Module B proc main() = include A - + main() # => Hello World! diff --git a/koch.nim b/koch.nim index c2f28f2e0..60d0e3544 100644 --- a/koch.nim +++ b/koch.nim @@ -475,7 +475,7 @@ proc hostInfo(): string = proc runCI(cmd: string) = doAssert cmd.len == 0, cmd # avoid silently ignoring - echo "runCI:", cmd + echo "runCI: ", cmd echo hostInfo() # note(@araq): Do not replace these commands with direct calls (eg boot()) # as that would weaken our testing efforts. diff --git a/lib/nimbase.h b/lib/nimbase.h index 004ba170b..d25c4dad0 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -545,4 +545,26 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz #define NIM_CHECK_SIZE(typ, sz) \ _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") +/* these exist to make the codegen logic simpler */ +#define nimModInt(a, b, res) (((*res) = (a) % (b)), 0) +#define nimModInt64(a, b, res) (((*res) = (a) % (b)), 0) + +/* these exist because we cannot have .compilerProcs that are importc'ed + by a different name */ + +#define nimAddInt64(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) +#define nimSubInt64(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) +#define nimMulInt64(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) + +#if NIM_INTBITS == 32 + #define nimAddInt(a, b, res) __builtin_sadd_overflow(a, b, res) + #define nimSubInt(a, b, res) __builtin_ssub_overflow(a, b, res) + #define nimMulInt(a, b, res) __builtin_smul_overflow(a, b, res) +#else + /* map it to the 'long long' variant */ + #define nimAddInt(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) + #define nimSubInt(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) + #define nimMulInt(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) +#endif + #endif /* NIMBASE_H */ diff --git a/lib/system.nim b/lib/system.nim index 5dff62806..602fbc1f1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2221,7 +2221,10 @@ when notJSnotNims: # we cannot compile this with stack tracing on # as it would recurse endlessly! - include "system/arithm" + when defined(nimNewIntegerOps): + include "system/integerops" + else: + include "system/arithm" {.pop.} diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index 16ac8affe..9e3ec79c4 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -409,13 +409,13 @@ when not declared(mulInt): # We avoid setting the FPU control word here for compatibility with libraries # written in other languages. -proc raiseFloatInvalidOp {.noinline.} = +proc raiseFloatInvalidOp {.compilerproc, noinline.} = sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") proc nanCheck(x: float64) {.compilerproc, inline.} = if x != x: raiseFloatInvalidOp() -proc raiseFloatOverflow(x: float64) {.noinline.} = +proc raiseFloatOverflow(x: float64) {.compilerproc, noinline.} = if x > 0.0: sysFatal(FloatOverflowError, "FPU operation caused an overflow") else: diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 52642bbf9..117543fcd 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -28,6 +28,19 @@ proc raiseIndexError() {.compilerproc, noinline.} = proc raiseFieldError(f: string) {.compilerproc, noinline.} = sysFatal(FieldError, f) +proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} = + sysFatal(RangeError, "value out of range: " & $i & " notin " & $a & " .. " & $b) + +proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} = + sysFatal(RangeError, "value out of range: " & $i & " notin " & $a & " .. " & $b) + +proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} = + # todo: better error reporting + sysFatal(RangeError, "value out of range") + +proc raiseObjectConversionError() {.compilerproc, noinline.} = + sysFatal(ObjectConversionError, "invalid object conversion") + proc chckIndx(i, a, b: int): int = if i >= a and i <= b: return i @@ -116,6 +129,5 @@ when not defined(nimV2): return true when defined(nimV2): - proc nimFieldDiscriminantCheckV2(oldDiscVal, newDiscVal: uint8) {.compilerproc.} = - if oldDiscVal != newDiscVal: - sysFatal(FieldError, "assignment to discriminant changes object branch") + proc raiseObjectCaseTransition() {.compilerproc.} = + sysFatal(FieldError, "assignment to discriminant changes object branch") diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index d68d06712..761e0dd69 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -24,7 +24,7 @@ when hostOS == "standalone": rawoutput(message) panic(arg) -elif (defined(nimQuirky) or gotoBasedExceptions) and not defined(nimscript): +elif (defined(nimQuirky) or defined(nimPanics)) and not defined(nimscript): import ansi_c proc name(t: typedesc): string {.magic: "TypeTrait".} @@ -46,20 +46,9 @@ elif (defined(nimQuirky) or gotoBasedExceptions) and not defined(nimscript): else: proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = - when declared(owned): - var e: owned(ref exceptn) - else: - var e: ref exceptn - new(e) - e.msg = message - raise e + raise (ref exceptn)(msg: message) proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = - when declared(owned): - var e: owned(ref exceptn) - else: - var e: ref exceptn - new(e) - e.msg = message & arg - raise e + raise (ref exceptn)(msg: message & arg) + {.pop.} diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 7be9f4b1f..15f316ccc 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -441,13 +441,15 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = zeroMem(result, size) when defined(memProfiler): nimProfile(size) +{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + let size = len * typ.base.size + GenericSeqSize result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) +{.pop.} proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = # generates a new object and sets its reference counter to 1 @@ -476,12 +478,14 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = sysAssert(allocInv(gch.region), "newObjRC1 end") when defined(memProfiler): nimProfile(size) +{.push overflowChecks: on.} proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + let size = len * typ.base.size + GenericSeqSize result = newObjRC1(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) +{.pop.} proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = collectCT(gch) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index fe07766d9..ff2b6ad6a 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -79,7 +79,7 @@ template decTypeSize(cell, t) = if t.kind in {tyString, tySequence}: let cap = cast[PGenericSeq](cellToUsr(cell)).space let size = if t.kind == tyString: cap+1+GenericSeqSize - else: addInt(mulInt(cap, t.base.size), GenericSeqSize) + else: cap * t.base.size + GenericSeqSize atomicDec t.sizes, size+sizeof(Cell) else: atomicDec t.sizes, t.base.size+sizeof(Cell) diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 271543445..a026b404b 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -305,20 +305,22 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = when defined(memProfiler): nimProfile(size) when not defined(nimSeqsV2): + {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + let size = len * typ.base.size + GenericSeqSize result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + let size = len * typ.base.size + GenericSeqSize result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) + {.pop.} proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = collectCT(gch, newsize + sizeof(Cell)) diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index 6b1640ab1..38365469e 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -334,20 +334,21 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(tlRegion, typ, size) when defined(memProfiler): nimProfile(size) +{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = roundup(addInt(mulInt(len, typ.base.size), GenericSeqSize), - MemAlign) + let size = roundup(len * typ.base.size + GenericSeqSize, MemAlign) result = rawNewSeq(tlRegion, typ, size) zeroMem(result, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len proc newStr(typ: PNimType, len: int; init: bool): pointer {.compilerRtl.} = - let size = roundup(addInt(len, GenericSeqSize), MemAlign) + let size = roundup(len + GenericSeqSize, MemAlign) result = rawNewSeq(tlRegion, typ, size) if init: zeroMem(result, size) cast[PGenericSeq](result).len = 0 cast[PGenericSeq](result).reserved = len +{.pop.} proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(tlRegion, typ, size) diff --git a/lib/system/integerops.nim b/lib/system/integerops.nim new file mode 100644 index 000000000..dc0197f14 --- /dev/null +++ b/lib/system/integerops.nim @@ -0,0 +1,132 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Integer arithmetic with overflow checking. Uses +# intrinsics or inline assembler. + +proc raiseOverflow {.compilerproc, noinline.} = + # a single proc to reduce code size to a minimum + sysFatal(OverflowError, "over- or underflow") + +proc raiseDivByZero {.compilerproc, noinline.} = + sysFatal(DivByZeroError, "division by zero") + +{.pragma: nimbaseH, importc, nodecl, noSideEffect, compilerproc.} + +when defined(gcc) or defined(clang): + # take the #define from nimbase.h + + proc nimAddInt(a, b: int, res: ptr int): bool {.nimbaseH.} + proc nimSubInt(a, b: int, res: ptr int): bool {.nimbaseH.} + proc nimMulInt(a, b: int, res: ptr int): bool {.nimbaseH.} + + proc nimAddInt64(a, b: int64; res: ptr int64): bool {.nimbaseH.} + proc nimSubInt64(a, b: int64; res: ptr int64): bool {.nimbaseH.} + proc nimMulInt64(a, b: int64; res: ptr int64): bool {.nimbaseH.} + +# unary minus and 'abs' not required here anymore and are directly handled +# in the code generator. +# 'nimModInt' does exist in nimbase.h without check as we moved the +# check for 0 to the codgen. +proc nimModInt(a, b: int; res: ptr int): bool {.nimbaseH.} + +proc nimModInt64(a, b: int64; res: ptr int64): bool {.nimbaseH.} + +# Platform independent versions. + +template addImplFallback(name, T, U) {.dirty.} = + when not declared(name): + proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = + let r = cast[T](cast[U](a) + cast[U](b)) + if (r xor a) >= T(0) or (r xor b) >= T(0): + res[] = r + else: + result = true + +addImplFallback(nimAddInt, int, uint) +addImplFallback(nimAddInt64, int64, uint64) + +template subImplFallback(name, T, U) {.dirty.} = + when not declared(name): + proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = + let r = cast[T](cast[U](a) - cast[U](b)) + if (r xor a) >= 0 or (r xor not b) >= 0: + res[] = r + else: + result = true + +subImplFallback(nimSubInt, int, uint) +subImplFallback(nimSubInt64, int64, uint64) + +template mulImplFallback(name, T, U, conv) {.dirty.} = + # + # This code has been inspired by Python's source code. + # The native int product x*y is either exactly right or *way* off, being + # just the last n bits of the true product, where n is the number of bits + # in an int (the delivered product is the true product plus i*2**n for + # some integer i). + # + # The native float64 product x*y is subject to three + # rounding errors: on a sizeof(int)==8 box, each cast to double can lose + # info, and even on a sizeof(int)==4 box, the multiplication can lose info. + # But, unlike the native int product, it's not in *range* trouble: even + # if sizeof(int)==32 (256-bit ints), the product easily fits in the + # dynamic range of a float64. So the leading 50 (or so) bits of the float64 + # product are correct. + # + # We check these two ways against each other, and declare victory if + # they're approximately the same. Else, because the native int product is + # the only one that can lose catastrophic amounts of information, it's the + # native int product that must have overflowed. + # + when not declared(name): + proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = + let r = cast[T](cast[U](a) * cast[U](b)) + let floatProd = conv(a) * conv(b) + let resAsFloat = conv(r) + # Fast path for normal case: small multiplicands, and no info + # is lost in either method. + if resAsFloat == floatProd: + res[] = r + else: + # Somebody somewhere lost info. Close enough, or way off? Note + # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). + # The difference either is or isn't significant compared to the + # true value (of which floatProd is a good approximation). + + # abs(diff)/abs(prod) <= 1/32 iff + # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" + if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): + res[] = r + else: + result = true + +mulImplFallback(nimMulInt, int, uint, toFloat) +mulImplFallback(nimMulInt64, int64, uint64, toBiggestFloat) + + +template divImplFallback(name, T) {.dirty.} = + proc name(a, b: T; res: ptr T): bool {.compilerproc, inline.} = + # we moved the b == 0 case out into the codegen. + if a == low(T) and b == T(-1): + result = true + else: + res[] = a div b + +divImplFallback(nimDivInt, int) +divImplFallback(nimDivInt64, int64) + +proc raiseFloatInvalidOp {.compilerproc, noinline.} = + sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") + +proc raiseFloatOverflow(x: float64) {.compilerproc, noinline.} = + if x > 0.0: + sysFatal(FloatOverflowError, "FPU operation caused an overflow") + else: + sysFatal(FloatUnderflowError, "FPU operations caused an underflow") diff --git a/lib/system/mm/boehm.nim b/lib/system/mm/boehm.nim index d02d52b52..a8b0e17b4 100644 --- a/lib/system/mm/boehm.nim +++ b/lib/system/mm/boehm.nim @@ -101,10 +101,12 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = else: result = alloc(size) if typ.finalizer != nil: boehmRegisterFinalizer(result, boehmgc_finalizer, typ.finalizer, nil, nil) +{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) + result = newObj(typ, len * typ.base.size + GenericSeqSize) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len +{.pop.} proc growObj(old: pointer, newsize: int): pointer = result = realloc(old, newsize) diff --git a/lib/system/mm/none.nim b/lib/system/mm/none.nim index 3572b062c..0079daac3 100644 --- a/lib/system/mm/none.nim +++ b/lib/system/mm/none.nim @@ -19,10 +19,12 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = proc newObjNoInit(typ: PNimType, size: int): pointer = result = alloc(size) +{.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) + result = newObj(typ, len * typ.base.size + GenericSeqSize) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len +{.pop.} proc growObj(old: pointer, newsize: int): pointer = result = realloc(old, newsize) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index d2d0d576f..2c3394df9 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -102,18 +102,20 @@ else: include "system/gc" when not declared(nimNewSeqOfCap) and not defined(nimSeqsV2): + {.push overflowChecks: on.} proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = when defined(gcRegions): - let s = mulInt(cap, typ.base.size) # newStr already adds GenericSeqSize + let s = cap * typ.base.size # newStr already adds GenericSeqSize result = newStr(typ, s, ntfNoRefs notin typ.base.flags) else: - let s = addInt(mulInt(cap, typ.base.size), GenericSeqSize) + let s = cap * typ.base.size + GenericSeqSize when declared(newObjNoInit): result = if ntfNoRefs in typ.base.flags: newObjNoInit(typ, s) else: newObj(typ, s) else: result = newObj(typ, s) cast[PGenericSeq](result).len = 0 cast[PGenericSeq](result).reserved = cap + {.pop.} {.pop.} diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index 98b859c1c..e9e6b5192 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -8,7 +8,7 @@ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo assertions.nim(29) failedAssertImpl assertions.nim(22) raiseAssert -fatal.nim(55) sysFatal""" +fatal.nim(49) sysFatal""" proc tmatch(x, p: string): bool = var i = 0 diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim new file mode 100644 index 000000000..30fe28e7c --- /dev/null +++ b/tests/destructor/tgotoexceptions7.nim @@ -0,0 +1,52 @@ +discard """ + cmd: "nim c --gc:arc --exceptions:goto --panics:off $file" + output: '''field error prevented +prevented! +caught +AssertionError +900''' +""" + +type + E = enum + kindA, kindB + Obj = object + case kind: E + of kindA: s: string + of kindB: i: int + + ObjA = ref object of RootObj + ObjB = ref object of ObjA + +proc takeRange(x: range[0..4]) = discard + +proc bplease(x: ObjB) = discard + +proc helper = doAssert(false) + +proc main(i: int) = + var obj = Obj(kind: kindA, s: "abc") + try: + obj.kind = kindB + except FieldError: + echo "field error prevented" + + try: + var objA = ObjA() + bplease(ObjB(objA)) + except ObjectConversionError: + echo "prevented!" + + try: + takeRange(i) + except RangeError: + echo "caught" + + try: + helper() + except AssertionError: + echo "AssertionError" + + echo i * i + +main(30) diff --git a/tests/range/tsubrange2.nim b/tests/range/tsubrange2.nim index e0fb71c5f..1b90b52c7 100644 --- a/tests/range/tsubrange2.nim +++ b/tests/range/tsubrange2.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "value out of range: 50 [RangeError]" + outputsub: "value out of range: 50 notin 0 .. 40 [RangeError]" exitcode: "1" """ diff --git a/tests/range/tsubrange3.nim b/tests/range/tsubrange3.nim index d3aae87df..ba9e6a143 100644 --- a/tests/range/tsubrange3.nim +++ b/tests/range/tsubrange3.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "value out of range: 50 [RangeError]" + outputsub: "value out of range: 50 notin 0 .. 40 [RangeError]" exitcode: "1" """ From 9eeb514dda08f1caadb0d8e01a8595d991530b52 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 13 Mar 2020 11:50:39 +0100 Subject: [PATCH 0120/4254] disable nimgame2 for now --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 363171082..d9c49cb7b 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -52,7 +52,7 @@ pkg "nimcrypto", false, "nim c -r tests/testall.nim" pkg "NimData", true, "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", true, "nim c src/nimes.nim" pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim" -pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" +#pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim" # pkg "nimlsp", true pkg "nimly", true From 380a505507a6df9cbb1fe77b5b6251dc14894921 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 13 Mar 2020 06:02:47 -0700 Subject: [PATCH 0121/4254] azure-pipelines: use OSX 10.15 (was just enabled upstream) (#13546) --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dccd0d05e..e04974f5b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,10 +12,10 @@ jobs: vmImage: 'ubuntu-16.04' CPU: i386 OSX_amd64: - vmImage: 'macOS-10.14' + vmImage: 'macOS-10.15' CPU: amd64 OSX_amd64_cpp: - vmImage: 'macOS-10.14' + vmImage: 'macOS-10.15' CPU: amd64 NIM_COMPILE_TO_CPP: true Windows_amd64: From 6e0c06f50e0450522b32a1bad23a3d2a4e36e9f9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 13 Mar 2020 12:42:41 -0700 Subject: [PATCH 0122/4254] fix #13218: avoid some irrelevant warnings for nim doc,rst2html,--app:lib, + other fixes (#13550) * fix #13218: avoid some irrelevant warnings for nim doc,rst2html * suppress warnRedefinitionOfLabel for nim doc * lots of fixes for UnusedImport warnings --- compiler/main.nim | 7 +++++++ compiler/options.nim | 8 ++++++++ doc/docgen_sample.nim | 4 ++-- lib/impure/rdstdin.nim | 2 +- lib/pure/asyncdispatch.nim | 2 +- lib/pure/asynchttpserver.nim | 2 +- lib/pure/encodings.nim | 3 ++- lib/pure/lenientops.nim | 2 -- lib/pure/selectors.nim | 3 ++- lib/pure/strformat.nim | 2 -- tools/kochdocs.nim | 4 +++- 11 files changed, 27 insertions(+), 12 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index c8bdc9447..0b538cb5a 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -225,6 +225,12 @@ proc mainCommand*(graph: ModuleGraph) = loadConfigs(DocConfig, cache, conf) commandDoc(cache, conf) of "doc2", "doc": + conf.setNoteDefaults(warnLockLevel, false) # issue #13218 + conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 + # because currently generates lots of false positives due to conflation + # of labels links in doc comments, eg for random.rand: + # ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer + # ## * `rand proc<#rand,Rand,range[]>`_ that returns a float when defined(leanCompiler): quit "compiler wasn't built with documentation generator" else: @@ -233,6 +239,7 @@ proc mainCommand*(graph: ModuleGraph) = defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, false) of "rst2html": + conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218 when defined(leanCompiler): quit "compiler wasn't built with documentation generator" else: diff --git a/compiler/options.nim b/compiler/options.nim index 88251a42e..26260a770 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -289,7 +289,15 @@ type severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string +proc setNoteDefaults*(conf: ConfigRef, note: TNoteKind, enabled = true) = + template fun(op) = + conf.notes.op note + conf.mainPackageNotes.op note + conf.foreignPackageNotes.op note + if enabled: fun(incl) else: fun(excl) + proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) = + # see also `prepareConfigNotes` which sets notes if note notin conf.cmdlineNotes: if enabled: incl(conf.notes, note) else: excl(conf.notes, note) diff --git a/doc/docgen_sample.nim b/doc/docgen_sample.nim index 875993187..7a167cb45 100644 --- a/doc/docgen_sample.nim +++ b/doc/docgen_sample.nim @@ -4,9 +4,9 @@ import strutils proc helloWorld*(times: int) = ## Takes an integer and outputs - ## as many "hello world!"s + ## as many indented "hello world!"s for i in 0 .. times-1: - echo "hello world!" + echo "hello world!".indent(2) # using indent to avoid `UnusedImport` helloWorld(5) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index b78c0d8cf..4c36afe6e 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -43,7 +43,7 @@ elif defined(genode): stdin.readLine(line) else: - import linenoise, termios + import linenoise proc readLineFromStdin*(prompt: string): TaintedString {. tags: [ReadIOEffect, WriteIOEffect].} = diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5e4e3f699..35eb646c6 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -168,7 +168,7 @@ include "system/inclrtl" -import os, tables, strutils, times, heapqueue, lists, options, asyncstreams +import os, tables, strutils, times, heapqueue, options, asyncstreams import options, math, std/monotimes import asyncfutures except callSoon diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 186f0da41..c806d972a 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -30,7 +30,7 @@ ## ## waitFor server.serve(Port(8080), cb) -import tables, asyncnet, asyncdispatch, parseutils, uri, strutils +import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore export httpcore except parseHeader diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index e3be1764b..ff9c3889a 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -10,7 +10,7 @@ ## Converts between different character encodings. On UNIX, this uses ## the `iconv`:idx: library, on Windows the Windows API. -import os, parseutils, strutils +import os when not defined(windows): type @@ -28,6 +28,7 @@ type ## for encoding errors when defined(windows): + import parseutils, strutils proc eqEncodingNames(a, b: string): bool = var i = 0 var j = 0 diff --git a/lib/pure/lenientops.nim b/lib/pure/lenientops.nim index cdea780a2..f73df5e5f 100644 --- a/lib/pure/lenientops.nim +++ b/lib/pure/lenientops.nim @@ -24,8 +24,6 @@ ## either casting to float or rounding to int might be preferred, and users ## should make an explicit choice. -import typetraits - proc `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = F(i) + f proc `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 0ab1e7754..743a92dd0 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -27,7 +27,7 @@ ## ## TODO: ``/dev/poll``, ``event ports`` and filesystem events. -import os, strutils, nativesockets +import os, nativesockets const hasThreadSupport = compileOption("threads") and defined(threadsafe) @@ -230,6 +230,7 @@ when defined(nimdoc): ## For *poll* and *select* selectors ``-1`` is returned. else: + import strutils when hasThreadSupport: import locks diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index bc0d4b069..838baaf02 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -744,8 +744,6 @@ when isMainModule: check &"{high(int64)}", "9223372036854775807" check &"{low(int64)}", "-9223372036854775808" - import json - doAssert fmt"{'a'} {'b'}" == "a b" echo("All tests ok") diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 75df629e3..87cdf53aa 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -149,8 +149,10 @@ lib/posix/linux.nim lib/posix/termios.nim lib/js/jscore.nim """.splitWhitespace() - + + # some of these are include files so shouldn't be docgen'd ignoredModules = """ +lib/prelude.nim lib/pure/future.nim lib/impure/osinfo_posix.nim lib/impure/osinfo_win.nim From ae5094e1432cef8c32575915ae1e19deffe7df61 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 15 Mar 2020 22:44:07 +0000 Subject: [PATCH 0123/4254] azure-pipelines: walkaround issues with triggers (#13657) See https://status.dev.azure.com/_event/179641421 --- azure-pipelines.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e04974f5b..310feb8f7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,3 +1,12 @@ +trigger: + branches: + include: + - '*' +pr: + branches: + include: + - '*' + jobs: - job: packages From fd3583803e8e310c2c6f60c79aab42a56b931a56 Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 16 Mar 2020 01:59:16 -0600 Subject: [PATCH 0124/4254] Fix gdb scripts (#13658) * Fix nim-gdb and rename to nim-gdb.bash * Add symlink to nim-gdb.bash * Fix windows debug script * Add PR suggestions * Make readlink check easier to maintain/understand * Swap symlinks --- bin/nim-gdb | 20 +++++++++----------- bin/nim-gdb.bash | 1 + bin/nim-gdb.bat | 6 +----- 3 files changed, 11 insertions(+), 16 deletions(-) create mode 120000 bin/nim-gdb.bash diff --git a/bin/nim-gdb b/bin/nim-gdb index e6e3a1c49..b9956073b 100755 --- a/bin/nim-gdb +++ b/bin/nim-gdb @@ -5,25 +5,23 @@ set -e which nim > /dev/null || (echo "nim not in PATH"; exit 1) which gdb > /dev/null || (echo "gdb not in PATH"; exit 1) -which readlink > /dev/null || which greadlink > /dev/null || (echo "readlink not in PATH. Please install coreutils from brew if on Mac."; exit 1) -nreadlink () { - (which greadlink > /dev/null && greadlink "$@") || (which readlink > /dev/null && readlink "$@") || echo "Readlink could not be found" -} +if [[ "$(uname -s)" == "Darwin" ]]; then + which greadlink > /dev/null || (echo "readlink not in PATH. Please install coreutils from homebrew."; exit 1) + READLINK=greadlink +else + which readlink > /dev/null || (echo "readlink not in PATH."; exit 1) + READLINK=readlink +fi # Find out where the pretty printer Python module is -NIM_SYSROOT=$(dirname $(dirname $(nreadlink -e $(which nim)))) +NIM_SYSROOT=$(dirname $(dirname $($READLINK -e $(which nim)))) GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py" # Run GDB with the additional arguments that load the pretty printers # Set the environment variable `NIM_GDB` to overwrite the call to a # different/specific command (defaults to `gdb`). NIM_GDB="${NIM_GDB:-gdb}" - -# This is needed for some reason. I can't get -eval-command to work ever -echo "source $GDB_PYTHON_MODULE_PATH" > gdbcommands.txt # exec replaces the new process of bash with gdb. It is always good to # have fewer processes. -exec ${NIM_GDB} --command="gdbcommands.txt" "$@" - -rm gdbcommands.txt +exec "${NIM_GDB}" -eval-command="source $GDB_PYTHON_MODULE_PATH" "$@" diff --git a/bin/nim-gdb.bash b/bin/nim-gdb.bash new file mode 120000 index 000000000..f6eba4b0c --- /dev/null +++ b/bin/nim-gdb.bash @@ -0,0 +1 @@ +nim-gdb \ No newline at end of file diff --git a/bin/nim-gdb.bat b/bin/nim-gdb.bat index 58b66b61f..453d700bd 100644 --- a/bin/nim-gdb.bat +++ b/bin/nim-gdb.bat @@ -6,11 +6,7 @@ for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi) set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py set @NIM_GDB=gdb.exe -@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt - -%@NIM_GDB% --command="wingdbcommand.txt" %* - -del wingdbcommand.txt /f /q +%@NIM_GDB% -eval-command="source %@GDB_PYTHON_MODULE_PATH%" %* EXIT /B %ERRORLEVEL% @echo on From fe53f6ef4f4fe296d70c68b8c56d3c8afa06a168 Mon Sep 17 00:00:00 2001 From: Kartik Saranathan <278928+Kartiku@users.noreply.github.com> Date: Mon, 16 Mar 2020 04:07:10 -0400 Subject: [PATCH 0125/4254] fix typo (#13660) [ci skip] --- doc/nimc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nimc.rst b/doc/nimc.rst index b67c05a0e..138f1e7f0 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -160,7 +160,7 @@ passed as a command line argument to the compiler. The ``nim`` executable processes configuration files in the following directories (in this order; later files overwrite previous settings): -1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. +1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. 2) If environment variable ``XDG_CONFIG_HOME`` is defined, ``$XDG_CONFIG_HOME/nim/nim.cfg`` or ``~/.config/nim/nim.cfg`` (POSIX) or ``%APPDATA%/nim/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. 3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option. 4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option. From 613ea6e85e8289fee92c396e07f8f1b2a991167f Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 16 Mar 2020 12:40:40 +0000 Subject: [PATCH 0126/4254] fixes #12747 [backport] (#13651) * fixes #12747 * fix tests * improve code style Co-authored-by: cooldome --- compiler/transf.nim | 15 ++++++++++++--- tests/destructor/tgcdestructors.nim | 2 +- tests/destructor/twidgets_unown.nim | 2 +- tests/iter/titer11.nim | 11 +++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index cd5eaa100..c1af6c23f 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -565,10 +565,19 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = case arg.kind of nkEmpty..nkNilLit: result = paDirectMapping - of nkPar, nkTupleConstr, nkCurly, nkBracket: - result = paFastAsgn + of nkDotExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr: + result = putArgInto(arg[0], formal) + of nkCurly, nkBracket: for i in 0.. Date: Mon, 16 Mar 2020 09:52:07 +0100 Subject: [PATCH 0127/4254] minor code style changes --- compiler/semtypes.nim | 2 +- compiler/semtypinst.nim | 2 +- compiler/types.nim | 21 +++++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e0be620c3..3951c071f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -225,7 +225,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = if not hasUnknownTypes: if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): localError(c.config, n.info, "type mismatch") - elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin tyFloat..tyFloat128 or + elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin {tyFloat..tyFloat128} or rangeT[0].kind == tyBool: localError(c.config, n.info, "ordinal or float type expected") elif enumHasHoles(rangeT[0]): diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 6d9e9873e..d3ab9d866 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -25,7 +25,7 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = elif t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") elif computeSize(conf, t) == szIllegalRecursion or isTupleRecursive(t): - localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") + localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") when false: if t.kind == tyObject and t[0] != nil: if t[0].kind != tyObject or tfFinal in t[0].flags: diff --git a/compiler/types.nim b/compiler/types.nim index 3c481ec23..63c5b66f2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1612,16 +1612,17 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = if cycleDetector.containsOrIncl(t.id): return true case t.kind: - of tyTuple: - var cycleDetectorCopy: IntSet - for i in 0.. Date: Mon, 16 Mar 2020 09:52:18 +0100 Subject: [PATCH 0128/4254] minor code style change --- compiler/types.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/types.nim b/compiler/types.nim index 63c5b66f2..fe7a60a12 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1611,7 +1611,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = return false if cycleDetector.containsOrIncl(t.id): return true - case t.kind: + case t.kind of tyTuple: var cycleDetectorCopy: IntSet for i in 0.. Date: Mon, 16 Mar 2020 12:54:31 +0100 Subject: [PATCH 0129/4254] fixes #13646 --- compiler/semexprs.nim | 12 +++++++++--- compiler/semtypinst.nim | 3 +++ tests/metatype/tmetatype_various.nim | 25 ++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f75642bcb..a479327be 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -232,13 +232,14 @@ proc semConv(c: PContext, n: PNode): PNode = result = newNodeI(nkConv, n.info) var targetType = semTypeNode(c, n[0], nil) - if targetType.kind == tyTypeDesc: + case targetType.kind + of tyTypeDesc: internalAssert c.config, targetType.len > 0 if targetType.base.kind == tyNone: return semTypeOf(c, n) else: targetType = targetType.base - elif targetType.kind == tyStatic: + of tyStatic: var evaluated = semStaticExpr(c, n[1]) if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc: result = n @@ -248,6 +249,7 @@ proc semConv(c: PContext, n: PNode): PNode = return evaluated else: targetType = targetType.base + else: discard maybeLiftType(targetType, c, n[0].info) @@ -268,7 +270,7 @@ proc semConv(c: PContext, n: PNode): PNode = targetType.skipTypes(abstractPtrs).kind == tyObject: localError(c.config, n.info, "object construction uses ':', not '='") var op = semExprWithType(c, n[1]) - if targetType.isMetaType: + if targetType.kind != tyGenericParam and targetType.isMetaType: let final = inferWithMetatype(c, targetType, op, true) result.add final result.typ = final.typ @@ -279,6 +281,10 @@ proc semConv(c: PContext, n: PNode): PNode = # here or needs to be overwritten too then. result.add op + if targetType.kind == tyGenericParam: + result.typ = makeTypeFromExpr(c, copyTree(result)) + return result + if not isSymChoice(op): let status = checkConvertible(c, result.typ, op) case status diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index d3ab9d866..5aec3eed9 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -618,6 +618,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = eraseVoidParams(result) skipIntLiteralParams(result) + of tyRange: + result[0] = result[0].skipTypes({tyStatic, tyDistinct}) + else: discard else: # If this type doesn't refer to a generic type we may still want to run it diff --git a/tests/metatype/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim index a56eca018..0dd948293 100644 --- a/tests/metatype/tmetatype_various.nim +++ b/tests/metatype/tmetatype_various.nim @@ -1,4 +1,7 @@ - +discard """ + output: '''[1, 0, 0, 0, 0, 0, 0, 0] + CTBool[Ct[system.uint32]]''' +""" block tconstraints: proc myGenericProc[T: object|tuple|int|ptr|ref|distinct](x: T): string = @@ -37,13 +40,29 @@ block tfieldaccessor: block tprocbothmeta: proc myFun[A](x: A): auto = result = float(x+10) - + proc myMap[T,S](sIn: seq[T], f: proc (q: T): S): seq[S] = result = newSeq[S](sIn.len) for i in 0.. Date: Mon, 16 Mar 2020 10:08:38 -0400 Subject: [PATCH 0130/4254] fix .deprecated. object typedef crash (#13643) * fix .deprecated. object typedef crash * fixup a test that i don't understand * disable the test rather than debug ci --- compiler/suggest.nim | 8 +++++--- nimsuggest/nimsuggest.nimble | 7 ++----- nimsuggest/tests/ttype_decl.nim | 8 +++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 11717c946..ff58bc92f 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -497,9 +497,11 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; proc extractPragma(s: PSym): PNode = if s.kind in routineKinds: result = s.ast[pragmasPos] - elif s.kind in {skType, skVar, skLet} and s.ast[0].kind == nkPragmaExpr: - # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] - result = s.ast[0][1] + elif s.kind in {skType, skVar, skLet}: + if s.ast != nil and s.ast.len > 0: + if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1: + # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] + result = s.ast[0][1] doAssert result == nil or result.kind == nkPragma proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = diff --git a/nimsuggest/nimsuggest.nimble b/nimsuggest/nimsuggest.nimble index 3651e12bd..53b5d1d6f 100644 --- a/nimsuggest/nimsuggest.nimble +++ b/nimsuggest/nimsuggest.nimble @@ -1,11 +1,8 @@ -[Package] -name = "nimsuggest" version = "0.1.0" author = "Andreas Rumpf" description = "Tool for providing auto completion data for Nim source code." license = "MIT" -bin = "nimsuggest" +bin = @["nimsuggest"] -[Deps] -Requires: "nim >= 0.11.2, compiler#head" +requires "nim >= 1.1.1" diff --git a/nimsuggest/tests/ttype_decl.nim b/nimsuggest/tests/ttype_decl.nim index e66d39a1c..6d9817ed2 100644 --- a/nimsuggest/tests/ttype_decl.nim +++ b/nimsuggest/tests/ttype_decl.nim @@ -2,14 +2,16 @@ discard """ disabled:true $nimsuggest --tester --maxresults:3 $file >sug $1 -sug;;skType;;ttype_decl.Other;;Other;;$file;;10;;2;;"";;0;;None -sug;;skType;;system.int;;int;;$lib/system.nim;;25;;2;;"";;0;;None -sug;;skType;;system.string;;string;;$lib/system.nim;;48;;2;;"";;0;;None +sug;;skType;;ttype_decl.Other;;Other;;$file;;11;;2;;"";;0;;None +sug;;skType;;system.int;;int;;$lib/system/basic_types.nim;;2;;2;;"";;0;;None +sug;;skType;;system.string;;string;;$lib/system.nim;;34;;2;;"";;0;;None """ import strutils type Other = object ## My other object. Foo = #[!]# + OldOne {.deprecated.} = object + x: int proc main(f: Foo) = From b9b53b6ca17662fbc71d9f632c4db859bf12c408 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 16 Mar 2020 16:24:50 +0100 Subject: [PATCH 0131/4254] fixes #13645 --- lib/nimbase.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/nimbase.h b/lib/nimbase.h index d25c4dad0..8c1c3d8a5 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -549,22 +549,24 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz #define nimModInt(a, b, res) (((*res) = (a) % (b)), 0) #define nimModInt64(a, b, res) (((*res) = (a) % (b)), 0) -/* these exist because we cannot have .compilerProcs that are importc'ed - by a different name */ +#if !defined(_MSC_VER) + /* these exist because we cannot have .compilerProcs that are importc'ed + by a different name */ -#define nimAddInt64(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) -#define nimSubInt64(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) -#define nimMulInt64(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) + #define nimAddInt64(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) + #define nimSubInt64(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) + #define nimMulInt64(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) -#if NIM_INTBITS == 32 - #define nimAddInt(a, b, res) __builtin_sadd_overflow(a, b, res) - #define nimSubInt(a, b, res) __builtin_ssub_overflow(a, b, res) - #define nimMulInt(a, b, res) __builtin_smul_overflow(a, b, res) -#else - /* map it to the 'long long' variant */ - #define nimAddInt(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) - #define nimSubInt(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) - #define nimMulInt(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) + #if NIM_INTBITS == 32 + #define nimAddInt(a, b, res) __builtin_sadd_overflow(a, b, res) + #define nimSubInt(a, b, res) __builtin_ssub_overflow(a, b, res) + #define nimMulInt(a, b, res) __builtin_smul_overflow(a, b, res) + #else + /* map it to the 'long long' variant */ + #define nimAddInt(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) + #define nimSubInt(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) + #define nimMulInt(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) + #endif #endif #endif /* NIMBASE_H */ From 5ba5b5202acdf5e597ef1e83ebae84608669d32b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 16 Mar 2020 18:40:17 +0100 Subject: [PATCH 0132/4254] fixes #13661 (#13664) [backport] --- compiler/semfold.nim | 1 - compiler/types.nim | 6 +++++- tests/misc/tunsignedconv.nim | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 54850fcfe..a8d42fe7a 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -439,7 +439,6 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = result = newIntNodeT(toInt128(getFloat(a)), n, g) of tyChar, tyUInt..tyUInt64, tyInt..tyInt64: var val = a.getOrdValue - if check: rangeCheck(n, val, g) result = newIntNodeT(val, n, g) if dstTyp.kind in {tyUInt..tyUInt64}: diff --git a/compiler/types.nim b/compiler/types.nim index fe7a60a12..c7fe529e1 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -87,7 +87,11 @@ proc isUnsigned*(t: PType): bool = t.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64} proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 = - case n.kind + var k = n.kind + if n.typ != nil and n.typ.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}: + k = nkUIntLit + + case k of nkCharLit, nkUIntLit..nkUInt64Lit: # XXX: enable this assert #assert n.typ == nil or isUnsigned(n.typ), $n.typ diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index 17d137947..af334dd19 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -1,3 +1,6 @@ +discard """ + output: '''uint''' +""" # Tests unsigned literals and implicit conversion between uints and ints # Passes if it compiles @@ -43,3 +46,12 @@ block t4176: var yyy: uint8 = 0 yyy = yyy - 127 doAssert type(yyy) is uint8 + +# bug #13661 + +proc fun(): uint = cast[uint](-1) +const x0 = fun() + +echo typeof(x0) + +discard $x0 From d375120c424fa94cc58228c2f0285c1b0b32919b Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 16 Mar 2020 18:49:27 +0100 Subject: [PATCH 0133/4254] rename sfAlwaysReturn to sfNeverRaises --- compiler/ast.nim | 2 +- compiler/ccgcalls.nim | 2 +- compiler/enumtostr.nim | 4 ++-- compiler/modulegraphs.nim | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 55ad2ba4b..33edcc953 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -289,7 +289,7 @@ type sfTemplateParam # symbol is a template parameter sfCursor # variable/field is a cursor, see RFC 177 for details sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation - sfAlwaysReturn # proc can never raise an exception, not even OverflowError + sfNeverRaises # proc can never raise an exception, not even OverflowError # or out-of-memory TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 3e2cf2271..3be3cbb6b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -559,7 +559,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = proc canRaiseDisp(p: BProc; n: PNode): bool = # we assume things like sysFatal cannot raise themselves - if n.kind == nkSym and sfAlwaysReturn in n.sym.flags: + if n.kind == nkSym and sfNeverRaises in n.sym.flags: result = false elif optPanics in p.config.globalOptions or (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 614190ac3..3eb703ade 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -40,7 +40,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym = n[resultPos] = newSymNode(res) result.ast = n incl result.flags, sfFromGeneric - incl result.flags, sfAlwaysReturn + incl result.flags, sfNeverRaises proc searchObjCaseImpl(obj: PNode; field: PSym): PNode = case obj.kind @@ -102,4 +102,4 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra n[resultPos] = newSymNode(res) result.ast = n incl result.flags, sfFromGeneric - incl result.flags, sfAlwaysReturn + incl result.flags, sfNeverRaises diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index d3be4b3b6..dff3f3b58 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -165,7 +165,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} = proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo, {}) result.magic = m - result.flags = {sfAlwaysReturn} + result.flags = {sfNeverRaises} proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result = ModuleGraph() From 955b31a7d9b3dff6dffc7d04c236c14521ef6f5b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 16 Mar 2020 23:00:26 +0100 Subject: [PATCH 0134/4254] fixes #13654 --- lib/impure/nre/private/util.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/impure/nre/private/util.nim b/lib/impure/nre/private/util.nim index f7d8b1d60..d227dcba3 100644 --- a/lib/impure/nre/private/util.nim +++ b/lib/impure/nre/private/util.nim @@ -47,5 +47,5 @@ template formatStr*(howExpr, namegetter, idgetter): untyped = i += 1 val.add(namegetter) else: - raise newException(Exception, "Syntax error in format string at " & $i) + raise newException(ValueError, "Syntax error in format string at " & $i) val From 6e4cd3e5bfcad550f423ae538909e3c73a95f445 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 16 Mar 2020 22:02:50 +0000 Subject: [PATCH 0135/4254] .github/workflows: new CI pipeline (#13656) * .github/workflows: new CI pipeline As Azure Pipelines went offline, this will be our (temporary?) replacement. This pipeline covers everything that Azure Pipelines does. * workflows/ci: disable pipeline * workflows/ci: properly disable the pipeline * gitattributes: .txt used in tests should be LF-terminated This avoids test failures when the compiler was cloned on an OS where git attempts to convert LF->CRLF. We target only .txt in tests/ as the minimum required to keep tests running correctly. * workflows/ci: re-enable for testing --- .gitattributes | 2 + .github/workflows/ci.yml | 122 +++++++++++++++++++++++++++++++++++++++ .gitignore | 2 + 3 files changed, 126 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..43aa0f580 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# tests expects the text files associated with them have LF only as EOL +tests/**/*.txt text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..446560663 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,122 @@ +name: Continous Integration +on: [push, pull_request] + +jobs: + build: + strategy: + matrix: + os: [ubuntu-18.04, macos-10.15, windows-2019] + cpu: [amd64, i386] + cpp: ['false', 'true'] + pkg: ['false', 'true'] + exclude: + - os: ubuntu-18.04 + cpp: 'true' + - os: ubuntu-18.04 + pkg: 'true' + - os: macos-10.15 + cpu: i386 + - os: macos-10.15 + pkg: 'true' + - os: windows-2019 + cpu: i386 + - os: windows-2019 + cpp: 'true' + name: '${{ matrix.os }} (${{ matrix.cpu }}, cpp: ${{ matrix.cpp }}, pkg: ${{ matrix.pkg }})' + runs-on: ${{ matrix.os }} + env: + NIM_COMPILE_TO_CPP: ${{ matrix.cpp }} + NIM_TEST_PACKAGES: ${{ matrix.pkg }} + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + - name: 'Checkout csources' + uses: actions/checkout@v2 + with: + repository: nim-lang/csources + path: csources + + - name: 'Install node.js 8.x' + uses: actions/setup-node@v1 + with: + node-version: '8.x' + - name: 'Install dependencies (Linux amd64)' + if: runner.os == 'Linux' && matrix.cpu == 'amd64' + run: | + sudo apt-fast update -qq + DEBIAN_FRONTEND='noninteractive' \ + sudo apt-fast install --no-install-recommends -yq \ + libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ + valgrind libc6-dbg + - name: 'Install dependencies (Linux i386)' + if: runner.os == 'Linux' && matrix.cpu == 'i386' + run: | + sudo dpkg --add-architecture i386 + + sudo apt-fast update -qq + DEBIAN_FRONTEND='noninteractive' \ + sudo apt-fast install --no-install-recommends --allow-downgrades -yq \ + g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \ + libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 \ + libffi-dev:i386 + + cat << EOF > bin/gcc + #!/bin/bash + + exec $(which gcc) -m32 "\$@" + EOF + cat << EOF > bin/g++ + #!/bin/bash + + exec $(which g++) -m32 "\$@" + EOF + + chmod 755 bin/gcc + chmod 755 bin/g++ + - name: 'Install dependencies (macOS)' + if: runner.os == 'macOS' + run: brew install boehmgc make sfml + - name: 'Install dependencies (Windows)' + if: runner.os == 'Windows' + shell: bash + run: | + mkdir dist + curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z + curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip + 7z x dist/mingw64.7z -odist + 7z x dist/dlls.zip -obin + echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" + + - name: 'Add build binaries to PATH' + shell: bash + run: echo "::add-path::${{ github.workspace }}/bin" + + - name: 'Build csources' + shell: bash + run: | + ncpu= + case '${{ runner.os }}' in + 'Linux') + ncpu=$(nproc) + ;; + 'macOS') + ncpu=$(sysctl -n hw.ncpu) + ;; + 'Windows') + ncpu=$NUMBER_OF_PROCESSORS + ;; + esac + [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 + + make -C csources -j $ncpu CC=gcc ucpu='${{ matrix.cpu }}' + - name: 'Build koch' + shell: bash + run: nim c koch + - name: 'Run CI' + shell: bash + run: ./koch runCI + + - name: 'Show failed tests' + if: failure() + shell: bash + run: nim c -r tools/ci_testresults.nim diff --git a/.gitignore b/.gitignore index de8732ee2..fee8f218d 100644 --- a/.gitignore +++ b/.gitignore @@ -87,6 +87,8 @@ megatest.nim !/.builds/ +!/.github + # ignore debug dirs generated by dsymutil on OSX *.dSYM From 5017320e7b4303c24c5585dc5c4536abc85a3dd8 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 16 Mar 2020 23:05:53 -0500 Subject: [PATCH 0136/4254] gitattributes: fix tests for windows Nim-generated files used in tests all end in LF, so we tell git to not touch them. Should allow a Windows user to clone and run tests without having to tweak their git settings --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 43aa0f580..a7cd44ba6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # tests expects the text files associated with them have LF only as EOL -tests/**/*.txt text eol=lf +**/test*/**/* text eol=lf From e5adaeed20e590c927f787cf0eb6bcd17767bd74 Mon Sep 17 00:00:00 2001 From: Leorize Date: Tue, 17 Mar 2020 02:18:00 -0500 Subject: [PATCH 0137/4254] workflows/ci: disable Since we got Azure Pipelines running, this will be a fallback pipeline. Activate by removing the `.disabled` suffix --- .github/workflows/{ci.yml => ci.yml.disabled} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{ci.yml => ci.yml.disabled} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml.disabled similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows/ci.yml.disabled From bec0522fca2fcaf57fd2c5b4ba6f43ccf47b7b32 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 17 Mar 2020 08:49:26 +0100 Subject: [PATCH 0138/4254] updated builds.sr.ht script according to their email (#13669) --- .builds/freebsd.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index b53cc3104..352fc2ccb 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,9 +1,5 @@ # see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd -# these are all broken, pending https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=244549 -# image: freebsd/latest -# image: freebsd/current -# image: freebsd/12.x -image: freebsd/11.x +image: freebsd/latest packages: - databases/sqlite3 - devel/boehm-gc-threaded From 6a23452bf4f386a57bcbb4e99c8d27149fe1d10b Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Tue, 17 Mar 2020 02:47:27 -0700 Subject: [PATCH 0139/4254] fix sets of scoped imported enums (#13666) --- compiler/ccgtypes.nim | 3 ++- tests/cpp/enum.hpp | 3 +++ tests/cpp/tenum_set.nim | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/cpp/enum.hpp create mode 100644 tests/cpp/tenum_set.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 759330a3e..22e9a5217 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -880,7 +880,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = m.s[cfsTypes].add(recdesc) elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result) of tySet: - result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon) + # Don't use the imported name as it may be scoped: 'Foo::SomeKind' + result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType m.typeCache[sig] = result if not isImportedType(t): let s = int(getSize(m.config, t)) diff --git a/tests/cpp/enum.hpp b/tests/cpp/enum.hpp new file mode 100644 index 000000000..268999d68 --- /dev/null +++ b/tests/cpp/enum.hpp @@ -0,0 +1,3 @@ +namespace namespaced { +enum Enum { A, B, C }; +} diff --git a/tests/cpp/tenum_set.nim b/tests/cpp/tenum_set.nim new file mode 100644 index 000000000..6afed722f --- /dev/null +++ b/tests/cpp/tenum_set.nim @@ -0,0 +1,9 @@ +discard """ +targets: "cpp" +output: "{A, B, C}" +""" + +type Enum {.importcpp: "namespaced::Enum", header: "enum.hpp".} = enum A, B, C + +var vals = {low(Enum) .. high(Enum)} +echo vals From af9c85270198455c7ba218fae919e79060a8960a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 17 Mar 2020 05:44:37 -0700 Subject: [PATCH 0140/4254] fix `nim doc subdir/foo` which was generating broken css; + other fixes (#13647) * docgen: minor refactoring via docOutDir * fix css for `nim doc subdir/foo` without --outdir nor -o * tcompilesetting.nim: keep `git status` clean * re-enable pkg nimgame2 that got fixed upstream --- compiler/docgen.nim | 24 ++++++++++++++---------- compiler/scriptconfig.nim | 4 ++-- testament/important_packages.nim | 2 +- tests/vm/tcompilesetting.nim | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 064bdc93e..fbdfbc884 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -54,6 +54,9 @@ proc nativeToUnix(path: string): string = result = replace(path, '\\', '/') else: result = path +proc docOutDir(conf: ConfigRef, subdir: RelativeDir = RelativeDir""): AbsoluteDir = + if not conf.outDir.isEmpty: conf.outDir else: conf.projectPath / subdir + proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): RelativeFile = ## returns a relative file that will be appended to outDir let file2 = $file @@ -146,12 +149,11 @@ proc parseRst(text, filename: string, proc getOutFile2(conf: ConfigRef; filename: RelativeFile, ext: string, dir: RelativeDir; guessTarget: bool): AbsoluteFile = if optWholeProject in conf.globalOptions: - let d = if conf.outDir.isEmpty: conf.projectPath / dir else: conf.outDir + let d = conf.docOutDir(dir) createDir(d) result = d / changeFileExt(filename, ext) elif guessTarget: - let d = if not conf.outDir.isEmpty: conf.outDir - else: conf.projectPath + let d = conf.docOutDir createDir(d) result = d / changeFileExt(filename, ext) elif not conf.outFile.isEmpty: @@ -1079,8 +1081,11 @@ proc genSection(d: PDoc, kind: TSymKind) = "sectionid", "sectionTitle", "sectionTitleID", "content"], [ ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]]) +const nimdocOutCss = "nimdoc.out.css" + # `out` to make it easier to use with gitignore in user's repos + proc cssHref(outDir: AbsoluteDir, destFile: AbsoluteFile): Rope = - rope($relativeTo(outDir / RelativeFile"nimdoc.out.css", destFile.splitFile().dir, '/')) + rope($relativeTo(outDir / nimdocOutCss.RelativeFile, destFile.splitFile().dir, '/')) proc genOutFile(d: PDoc): Rope = var @@ -1127,15 +1132,14 @@ proc genOutFile(d: PDoc): Rope = proc generateIndex*(d: PDoc) = if optGenIndex in d.conf.globalOptions: - let dir = if not d.conf.outDir.isEmpty: d.conf.outDir - else: d.conf.projectPath / htmldocsDir + let dir = d.conf.docOutDir(htmldocsDir) createDir(dir) let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt) writeIndexFile(d[], dest.string) proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html - if d.conf.outDir.isEmpty: d.conf.outDir = d.conf.projectPath + if d.conf.outDir.isEmpty: d.conf.outDir = d.conf.docOutDir if d.conf.outFile.isEmpty: d.conf.outFile = outfile.relativeTo(d.conf.outDir) proc writeOutput*(d: PDoc, useWarning = false) = @@ -1146,15 +1150,15 @@ proc writeOutput*(d: PDoc, useWarning = false) = else: template outfile: untyped = d.destFile #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, htmldocsDir) - createDir(outfile.splitFile.dir) + let dir = outfile.splitFile.dir + createDir(dir) updateOutfile(d, outfile) if not writeRope(content, outfile): rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile.string) elif not d.wroteCss: let cssSource = $d.conf.getPrefixDir() / "doc" / "nimdoc.css" - let cssDest = $d.conf.outDir / "nimdoc.out.css" - # renamed to make it easier to use with gitignore in user's repos + let cssDest = $dir / nimdocOutCss copyFile(cssSource, cssDest) d.wroteCss = true diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 220486aed..d53664912 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -12,9 +12,9 @@ import ast, modules, idents, passes, condsyms, - options, sem, llstream, vm, vmdef, commands, msgs, + options, sem, llstream, vm, vmdef, commands, os, times, osproc, wordrecg, strtabs, modulegraphs, - lineinfos, pathutils + pathutils # we support 'cmpIgnoreStyle' natively for efficiency: from strutils import cmpIgnoreStyle, contains diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d9c49cb7b..363171082 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -52,7 +52,7 @@ pkg "nimcrypto", false, "nim c -r tests/testall.nim" pkg "NimData", true, "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", true, "nim c src/nimes.nim" pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim" -#pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" +pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim" # pkg "nimlsp", true pkg "nimly", true diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim index 0e936d377..79527d584 100644 --- a/tests/vm/tcompilesetting.nim +++ b/tests/vm/tcompilesetting.nim @@ -1,5 +1,5 @@ discard """ -cmd: "nim c --nimcache:myNimCache --nimblePath:myNimblePath $file" +cmd: "nim c --nimcache:build/myNimCache --nimblePath:myNimblePath $file" joinable: false """ From 35d14095edcb530535a3f2b7e7e759c0f993e2c9 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 17 Mar 2020 15:36:38 +0000 Subject: [PATCH 0141/4254] Fixes #13659 (#13674) * fixes #13659 Co-authored-by: cooldome --- compiler/injectdestructors.nim | 4 ++-- tests/destructor/tselect.nim | 26 +++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 161cb7652..48faa7e84 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -619,10 +619,10 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: cycleCheck(n, c) assert n[1].kind notin {nkAsgn, nkFastAsgn} - result = moveOrCopy(n[0], n[1], c) + result = moveOrCopy(p(n[0], c, mode), n[1], c) else: result = copyNode(n) - result.add copyTree(n[0]) + result.add p(n[0], c, mode) result.add p(n[1], c, consumed) of nkRaiseStmt: if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty: diff --git a/tests/destructor/tselect.nim b/tests/destructor/tselect.nim index 9262b47d4..c22bf7203 100644 --- a/tests/destructor/tselect.nim +++ b/tests/destructor/tselect.nim @@ -1,6 +1,9 @@ discard """ output: '''abcsuffix -xyzsuffix''' +xyzsuffix +destroy foo 2 +destroy foo 1 +''' cmd: '''nim c --gc:arc $file''' """ @@ -24,3 +27,24 @@ proc test(param: string; cond: bool) = test("suffix", true) test("suffix", false) + + + +#-------------------------------------------------------------------- +# issue #13659 + +type + Foo = ref object + data: int + parent: Foo + +proc `=destroy`(self: var type(Foo()[])) = + echo "destroy foo ", self.data + for i in self.fields: i.reset + +proc getParent(self: Foo): Foo = self.parent + +var foo1 = Foo(data: 1) +var foo2 = Foo(data: 2, parent: foo1) + +foo2.getParent.data = 1 \ No newline at end of file From b737bb4be0956f8dce69ec8b7ccfe624890abaa5 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 17 Mar 2020 11:22:20 +0100 Subject: [PATCH 0142/4254] fixes a bug for 'dup' and 'with'; they can now handle nested statement lists that can result from macros --- lib/pure/sugar.nim | 9 +-------- lib/std/private/underscored_calls.nim | 29 ++++++++++++++++++--------- lib/std/with.nim | 9 +-------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 047280049..e9e7eb455 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -216,14 +216,7 @@ when (NimMajor, NimMinor) >= (1, 1): result = newNimNode(nnkStmtListExpr, arg) let tmp = genSym(nskVar, "dupResult") result.add newVarStmt(tmp, arg) - expectKind calls, nnkArgList - let body = - if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}: - calls[0] - else: - calls - for call in body: - result.add underscoredCall(call, tmp) + underscoredCalls(result, calls, tmp) result.add tmp diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim index 7db25c410..c7aeb6ae2 100644 --- a/lib/std/private/underscored_calls.nim +++ b/lib/std/private/underscored_calls.nim @@ -12,27 +12,38 @@ import macros -proc underscoredCall*(n, arg0: NimNode): NimNode = +proc underscoredCall(n, arg0: NimNode): NimNode = proc underscorePos(n: NimNode): int = for i in 1 ..< n.len: if n[i].eqIdent("_"): return i - return -1 + return 0 if n.kind in nnkCallKinds: result = copyNimNode(n) result.add n[0] let u = underscorePos(n) - if u < 0: - result.add arg0 - for i in 1..n.len-1: result.add n[i] - else: - for i in 1..u-1: result.add n[i] - result.add arg0 - for i in u+1..n.len-1: result.add n[i] + for i in 1..u-1: result.add n[i] + result.add arg0 + for i in u+1..n.len-1: result.add n[i] else: # handle e.g. 'x.dup(sort)' result = newNimNode(nnkCall, n) result.add n result.add arg0 +proc underscoredCalls*(result, calls, arg0: NimNode) = + proc handleStmtList(result, n, arg0: NimNode) = + for a in n: + if a.kind in {nnkStmtList, nnkStmtListExpr}: + handleStmtList(result, a, arg0) + else: + result.add underscoredCall(a, arg0) + + expectKind calls, nnkArgList + if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}: + # the 'macro: body' syntax is used: + handleStmtList(result, calls[0], arg0) + else: + for call in calls: + result.add underscoredCall(call, arg0) diff --git a/lib/std/with.nim b/lib/std/with.nim index 1dfb67c2e..c1ac96fcb 100644 --- a/lib/std/with.nim +++ b/lib/std/with.nim @@ -35,14 +35,7 @@ macro with*(arg: typed; calls: varargs[untyped]): untyped = doAssert a == 43 result = newNimNode(nnkStmtList, arg) - expectKind calls, nnkArgList - let body = - if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}: - calls[0] - else: - calls - for call in body: - result.add underscoredCall(call, arg) + underscoredCalls(result, calls, arg) when isMainModule: type From fe7b1dfb2a7a5a7e66dc0870b50d4f93259da875 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 17 Mar 2020 23:18:43 +0100 Subject: [PATCH 0143/4254] =?UTF-8?q?rewritten=20goto=20based=20exception?= =?UTF-8?q?=20handling;=20much=20cleaner=20implementation;=E2=80=A6=20(#13?= =?UTF-8?q?677)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rewritten goto based exception handling; much cleaner implementation; fixes #13668 --- compiler/ccgstmts.nim | 28 +++-------- compiler/cgen.nim | 2 +- lib/system/excpt.nim | 6 +-- tests/destructor/tgotoexceptions8.nim | 69 +++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 26 deletions(-) create mode 100644 tests/destructor/tgotoexceptions8.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 1c63ebaea..49098959b 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1040,27 +1040,14 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let lab = p.labels p.nestedTryStmts.add((fin, false, Natural lab)) - if not bodyCanRaise(p, t): - # optimize away the 'try' block: - expr(p, t[0], d) - linefmt(p, cpsStmts, "LA$1_: ;$n", [lab]) - if fin != nil: - genStmts(p, fin[0]) - discard pop(p.nestedTryStmts) - return - p.flags.incl nimErrorFlagAccessed - p.procSec(cpsLocals).add(ropecg(p.module, "NI oldNimErr$1_;$n", [lab])) - linefmt(p, cpsStmts, "oldNimErr$1_ = *nimErr_; *nimErr_ = 0;;$n", [lab]) - expr(p, t[0], d) if 1 < t.len and t[1].kind == nkExceptBranch: startBlock(p, "if (NIM_UNLIKELY(*nimErr_)) {$n") else: startBlock(p) - # pretend we did handle the error for the safe execution of the sections: - linefmt(p, cpsStmts, "LA$1_: oldNimErr$1_ = *nimErr_; *nimErr_ = 0;$n", [lab]) + linefmt(p, cpsStmts, "LA$1_:;$n", [lab]) p.nestedTryStmts[^1].inExcept = true var i = 1 @@ -1077,7 +1064,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = if i > 1: lineF(p, cpsStmts, "else", []) startBlock(p) # we handled the exception, remember this: - linefmt(p, cpsStmts, "--oldNimErr$1_;$n", [lab]) + linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) expr(p, t[i][0], d) else: var orExpr: Rope = nil @@ -1094,7 +1081,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) # we handled the exception, remember this: - linefmt(p, cpsStmts, "--oldNimErr$1_;$n", [lab]) + linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) expr(p, t[i][^1], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) @@ -1105,7 +1092,6 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = discard pop(p.nestedTryStmts) endBlock(p) - #linefmt(p, cpsStmts, "LA$1_:;$n", [lab+1]) if i < t.len and t[i].kind == nkFinally: startBlock(p) if not bodyCanRaise(p, t[i][0]): @@ -1114,8 +1100,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = genStmts(p, t[i][0]) else: # pretend we did handle the error for the safe execution of the 'finally' section: - p.procSec(cpsLocals).add(ropecg(p.module, "NI oldNimErrFin$1_;$n", [lab])) - linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = 0;$n", [lab]) + p.procSec(cpsLocals).add(ropecg(p.module, "NIM_BOOL oldNimErrFin$1_;$n", [lab])) + linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = NIM_FALSE;$n", [lab]) genStmts(p, t[i][0]) # this is correct for all these cases: # 1. finally is run during ordinary control flow @@ -1123,10 +1109,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = # error back to nil. # 3. finally is run for exception handling code without any 'except' # handler present or only handlers that did not match. - linefmt(p, cpsStmts, "*nimErr_ += oldNimErr$1_ + (*nimErr_ - oldNimErrFin$1_); oldNimErr$1_ = 0;$n", [lab]) + linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) endBlock(p) - # restore the real error value: - linefmt(p, cpsStmts, "*nimErr_ += oldNimErr$1_;$n", [lab]) if p.prc != nil: raiseExit(p) proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 06507b6e6..10dda0ca9 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -975,7 +975,7 @@ proc genProcBody(p: BProc; procBody: PNode) = genStmts(p, procBody) # modifies p.locals, p.init, etc. if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}: p.flags.incl nimErrorFlagDeclared - p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NI* nimErr_;$n", [])) + p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", [])) p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", [])) proc genProcAux(m: BModule, prc: PSym) = diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index a9c7ba02a..8337e0351 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -420,16 +420,16 @@ proc nimLeaveFinally() {.compilerRtl.} = quit(1) when gotoBasedExceptions: - var nimInErrorMode {.threadvar.}: int + var nimInErrorMode {.threadvar.}: bool - proc nimErrorFlag(): ptr int {.compilerRtl, inl.} = + proc nimErrorFlag(): ptr bool {.compilerRtl, inl.} = result = addr(nimInErrorMode) proc nimTestErrorFlag() {.compilerRtl.} = ## This proc must be called before ``currException`` is destroyed. ## It also must be called at the end of every thread to ensure no ## error is swallowed. - if currException != nil: + if nimInErrorMode and currException != nil: reportUnhandledError(currException) currException = nil quit(1) diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim new file mode 100644 index 000000000..e968cdce2 --- /dev/null +++ b/tests/destructor/tgotoexceptions8.nim @@ -0,0 +1,69 @@ +discard """ + output: '''A +B +X +inner finally +Y +outer finally +msg1 +msg2 +finally2 +finally1''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13668 + +proc main = + try: + try: + raise newException(IOError, "IOError") + + except: + echo "A" + raise newException(CatchableError, "CatchableError") + + except: + echo "B" + #discard + +proc mainB = + try: + try: + raise newException(IOError, "IOError") + + except: + echo "X" + raise newException(CatchableError, "CatchableError") + finally: + echo "inner finally" + + except: + echo "Y" + #discard + finally: + echo "outer finally" + +main() +mainB() + +when true: + #bug 7204 + proc nested_finally = + try: + raise newException(KeyError, "msg1") + except KeyError as ex: + echo ex.msg + try: + # pop exception + raise newException(ValueError, "msg2") # push: exception stack (1 entry) + except: + echo getCurrentExceptionMsg() + # pop exception (except) + finally: + echo "finally2" + # pop exception (except KeyError as ex) + finally: + echo "finally1" + + nested_finally() From 122751aa526e3b839fbc717f8c7cd9256a134dd1 Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Tue, 17 Mar 2020 15:41:07 -0700 Subject: [PATCH 0144/4254] add nnkMacroDef to RoutineNodes (#13676) --- lib/core/macros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 57ce89c02..d94371d21 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1085,7 +1085,7 @@ proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1] const RoutineNodes* = {nnkProcDef, nnkFuncDef, nnkMethodDef, nnkDo, nnkLambda, - nnkIteratorDef, nnkTemplateDef, nnkConverterDef} + nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef} AtomicNodes* = {nnkNone..nnkNilLit} CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv} From 51bd442b88de561ea4729c0ba550e63cad5be969 Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Tue, 17 Mar 2020 15:44:32 -0700 Subject: [PATCH 0145/4254] fix when statements in inheritable generic objects (#13667) [backport] --- compiler/semtypes.nim | 2 +- tests/objects/tobject3.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 3951c071f..867106b87 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -804,7 +804,7 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, addInheritedFieldsAux(c, check, pos, lastSon(n[i])) else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)") of nkRecList, nkRecWhen, nkElifBranch, nkElse: - for i in 0.. Date: Wed, 18 Mar 2020 10:37:36 +0100 Subject: [PATCH 0146/4254] fixes #13671 [backport] (#13678) --- compiler/semexprs.nim | 2 +- tests/misc/tunsignedconv.nim | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a479327be..cc8854577 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -522,7 +522,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) = a.add m changeType(m, tup[i], check) of nkCharLit..nkUInt64Lit: - if check and n.kind != nkUInt64Lit: + if check and n.kind != nkUInt64Lit and not sameType(n.typ, newType): let value = n.intVal if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType): localError(c.config, n.info, "cannot convert " & $value & diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index af334dd19..085d13aca 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -55,3 +55,8 @@ const x0 = fun() echo typeof(x0) discard $x0 + +# bug #13671 + +const x1 = cast[uint](-1) +discard $(x1,) From 3f1a85b7f03a4998f09a4fe6e8bf13672742fcb9 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 18 Mar 2020 10:47:46 +0100 Subject: [PATCH 0147/4254] fixes hash(HashSet) which was wrong as it didn't respect tombstones; refs #13649 --- lib/pure/collections/sets.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 9f800e6d1..caa25dbb3 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -574,7 +574,8 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] = proc hash*[A](s: HashSet[A]): Hash = ## Hashing of HashSet. for h in 0 .. high(s.data): - result = result xor s.data[h].hcode + if isFilledAndValid(s.data[h].hcode): + result = result xor s.data[h].hcode result = !$result proc `$`*[A](s: HashSet[A]): string = From a87062393a7acef21b911dbd356b675061a671ab Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Mar 2020 13:42:33 +0100 Subject: [PATCH 0148/4254] fixes #13622 (#13679) --- compiler/injectdestructors.nim | 6 ++++-- tests/arc/tstrformat.nim | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/arc/tstrformat.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 48faa7e84..5e51aeb9d 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -31,6 +31,7 @@ type emptyNode: PNode otherRead: PNode inLoop: int + declaredVars: IntSet # variables we already moved to the top level uninit: IntSet # set of uninit'ed vars uninitComputed: bool @@ -345,7 +346,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = var m = genCopy(c, tmp, n) m.add p(n, c, normal) result.add m - if isLValue(n) and not isClosureEnv(n): + if isLValue(n) and not isClosureEnv(n) and n.typ.skipTypes(abstractInst).kind != tyRef: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & "use 'move($1)' to prevent it") % $n) @@ -589,7 +590,8 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = if v.kind == nkSym: if sfCompileTime in v.sym.flags: continue # move the variable declaration to the top of the frame: - c.addTopVar v + if not containsOrIncl(c.declaredVars, v.sym.id): + c.addTopVar v # make sure it's destroyed at the end of the proc: if not isUnpackedTuple(v) and sfThread notin v.sym.flags: # do not destroy thread vars for now at all for consistency. diff --git a/tests/arc/tstrformat.nim b/tests/arc/tstrformat.nim new file mode 100644 index 000000000..00d7a6679 --- /dev/null +++ b/tests/arc/tstrformat.nim @@ -0,0 +1,20 @@ +discard """ + output: '''verstuff''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13622 + +import strformat + +template necho*(args: string) {.dirty.} = + if getCurrentException() != nil: + echo args + else: + stdout.writeLine(args) + +proc main(cond: bool; arg: string) = + if cond: + necho &"ver{arg}\n" + +main(true, "stuff") From ed263e174e7f9a7bce1863dc57979c1a752d2e66 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Mar 2020 05:43:32 -0700 Subject: [PATCH 0149/4254] fix #13524 astToStr now works inside generics (#13681) --- compiler/semgnrc.nim | 2 +- tests/generics/t13525.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/generics/t13525.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index a494db475..6fefc2233 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -226,7 +226,7 @@ proc semGenericStmt(c: PContext, n: PNode, var mixinContext = false if s != nil: incl(s.flags, sfUsed) - mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles} + mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr} let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen) case s.kind of skMacro: diff --git a/tests/generics/t13525.nim b/tests/generics/t13525.nim new file mode 100644 index 000000000..d1b8df78c --- /dev/null +++ b/tests/generics/t13525.nim @@ -0,0 +1,6 @@ +# https://github.com/nim-lang/Nim/issues/13524 +template fun(field): untyped = astToStr(field) +proc test1(): string = fun(nonexistant1) +proc test2[T](): string = fun(nonexistant2) # used to cause: Error: undeclared identifier: 'nonexistant2' +doAssert test1() == "nonexistant1" +doAssert test2[int]() == "nonexistant2" From 3f29911a9496d82c355b84e23d91e992c3ddfce5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Mar 2020 14:25:10 +0100 Subject: [PATCH 0150/4254] new feature: --staticBoundChecks:on to enforce static array index checking (#10965) --- compiler/astalgo.nim | 1 + compiler/commands.nim | 2 + compiler/guards.nim | 47 +++++++++++++---- compiler/lineinfos.nim | 7 ++- compiler/options.nim | 4 +- compiler/pragmas.nim | 7 ++- compiler/semparallel.nim | 16 +++--- compiler/sempass2.nim | 67 +++++++++++++++++++++++- compiler/trees.nim | 1 + compiler/types.nim | 2 +- compiler/wordrecg.nim | 4 +- tests/arc/timportedobj.nim | 28 +++++----- tests/notnil/tnotnil4.nim | 5 +- tests/parallel/tinvalid_array_bounds.nim | 4 +- tests/parallel/tuseafterdef.nim | 1 + tests/tools/second.nim | 6 +-- 16 files changed, 152 insertions(+), 50 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index fd95b3780..968918ba9 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -182,6 +182,7 @@ proc getModule*(s: PSym): PSym = assert((result.kind == skModule) or (result.owner != result)) while result != nil and result.kind != skModule: result = result.owner +proc fromSystem*(op: PSym): bool {.inline.} = sfSystemModule in getModule(op).flags proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym = for i in start..= 1: result = shallowCopy(n) for i in 0.. 'i < a.len+1' result = n + elif n[1].getMagic in someLen or n[2].getMagic in someLen: + result = n of someLe+someLt: if isLetLocation(n[1], true) or isLetLocation(n[2], true): # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1' @@ -401,10 +402,20 @@ type TModel* = object s*: seq[PNode] # the "knowledge base" o*: Operators + beSmart*: bool proc addFact*(m: var TModel, nn: PNode) = let n = usefulFact(nn, m.o) - if n != nil: m.s.add n + if n != nil: + if not m.beSmart: + m.s.add n + else: + let c = canon(n, m.o) + if c.getMagic == mAnd: + addFact(m, c[1]) + addFact(m, c[2]) + else: + m.s.add c proc addFactNeg*(m: var TModel, n: PNode) = let n = n.neg(m.o) @@ -614,6 +625,9 @@ proc impliesGe(fact, x, c: PNode): TImplication = proc impliesLe(fact, x, c: PNode): TImplication = if not isLocation(x): + if c.isValue: + if leValue(x, x): return impYes + else: return impNo return impliesGe(fact, c, x) case fact[0].sym.magic of someEq: @@ -799,7 +813,7 @@ proc ple(m: TModel; a, b: PNode): TImplication = if lastOrd(nil, a.typ) <= b.intVal: return impYes # 3 <= x iff low(x) <= 3 if a.isValue and b.typ != nil and b.typ.isOrdinalType: - if firstOrd(nil, b.typ) <= a.intVal: return impYes + if a.intVal <= firstOrd(nil, b.typ): return impYes # x <= x if sameTree(a, b): return impYes @@ -810,7 +824,11 @@ proc ple(m: TModel; a, b: PNode): TImplication = # x <= y+c if 0 <= c and x <= y # x <= y+(-c) if c <= 0 and y >= x - if b.getMagic in someAdd and zero() <=? b[2] and a <=? b[1]: return impYes + if b.getMagic in someAdd: + if zero() <=? b[2] and a <=? b[1]: return impYes + # x <= y-c if x+c <= y + if b[2] <=? zero() and (canon(m.o.opSub.buildCall(a, b[2]), m.o) <=? b[1]): + return impYes # x+c <= y if c <= 0 and x <= y if a.getMagic in someAdd and a[2] <=? zero() and a[1] <=? b: return impYes @@ -899,10 +917,13 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = # --> true if (len-100) <= (len-1) let x = fact[1] let y = fact[2] - if sameTree(x, a) and y.getMagic in someAdd and b.getMagic in someAdd and - sameTree(y[1], b[1]): - if ple(m, b[2], y[2]) == impYes: - return impYes + # x <= y. + # Question: x <= b? True iff y <= b. + if sameTree(x, a): + if ple(m, y, b) == impYes: return impYes + if y.getMagic in someAdd and b.getMagic in someAdd and sameTree(y[1], b[1]): + if ple(m, b[2], y[2]) == impYes: + return impYes # x <= y implies a <= b if a <= x and y <= b if ple(m, a, x) == impYes: @@ -961,6 +982,10 @@ proc proveLe*(m: TModel; a, b: PNode): TImplication = proc addFactLe*(m: var TModel; a, b: PNode) = m.s.add canon(m.o.opLe.buildCall(a, b), m.o) +proc addFactLt*(m: var TModel; a, b: PNode) = + let bb = m.o.opAdd.buildCall(b, minusOne()) + addFactLe(m, a, bb) + proc settype(n: PNode): PType = result = newType(tySet, n.typ.owner) addSonSkipIntLit(result, n.typ) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 6eac5bf1b..033a98513 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -36,7 +36,8 @@ type warnUnusedImportX, warnInheritFromException, warnEachIdentIsTuple, - warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, + warnProveInit, warnProveField, warnProveIndex, + warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser, hintSuccess, hintSuccessX, hintCC, @@ -87,6 +88,7 @@ const warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", warnProveField: "cannot prove that field '$1' is accessible", warnProveIndex: "cannot prove index '$1' is valid", + warnStaticIndexCheck: "$1", warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", warnUninit: "'$1' might not have been initialized", @@ -142,7 +144,8 @@ const "TypelessParam", "UseBase", "WriteToForeignHeap", "UnsafeCode", "UnusedImport", "InheritFromException", "EachIdentIsTuple", - "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", + "ProveInit", "ProveField", "ProveIndex", + "IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "ResultShadowed", "Spacing", "CaseTransition", "CycleCreated", "User"] diff --git a/compiler/options.nim b/compiler/options.nim index 26260a770..d9a7a06ef 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -26,7 +26,7 @@ type # please make sure we have under 32 options TOption* = enum # **keep binary compatible** optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optNilCheck, optRefCheck, - optNaNCheck, optInfCheck, optStyleCheck, + optNaNCheck, optInfCheck, optStaticBoundsCheck, optStyleCheck, optAssert, optLineDir, optWarns, optHints, optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support optLineTrace, # line tracing support (includes stack tracing) @@ -320,7 +320,7 @@ const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, par const ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck, - optStyleCheck, optRefCheck} + optStyleCheck} DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 3e89917ed..8196c1b4e 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -42,7 +42,8 @@ const wTags, wLocks, wGcSafe} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks, - wBoundChecks, wOverflowChecks, wNilChecks, wStyleChecks, wAssertions, + wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks, + wStyleChecks, wAssertions, wWarnings, wHints, wLineDir, wStackTrace, wLineTrace, wOptimization, wHint, wWarning, wError, wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop, @@ -344,6 +345,7 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} = of wFloatChecks: {optNaNCheck, optInfCheck} of wNanChecks: {optNaNCheck} of wInfChecks: {optInfCheck} + of wStaticBoundchecks: {optStaticBoundsCheck} of wStyleChecks: {optStyleCheck} of wAssertions: {optAssert} of wWarnings: {optWarns} @@ -1027,7 +1029,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wCodegenDecl: processCodegenDecl(c, it, sym) of wChecks, wObjChecks, wFieldChecks, wRangeChecks, wBoundChecks, wOverflowChecks, wNilChecks, wAssertions, wWarnings, wHints, - wLineDir, wOptimization, wStyleChecks, wCallconv, wDebugger, wProfiler, + wLineDir, wOptimization, wStaticBoundchecks, wStyleChecks, + wCallconv, wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks, wPatterns, wTrMacros: processOption(c, it, c.config.options) of wStackTrace, wLineTrace: diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 62264ab40..5614f9ee3 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -23,7 +23,7 @@ import ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs, - renderer, types, modulegraphs, options, spawn + renderer, types, modulegraphs, options, spawn, lineinfos from trees import getMagic from strutils import `%` @@ -129,10 +129,12 @@ template `?`(x): untyped = x.renderTree proc checkLe(c: AnalysisCtx; a, b: PNode) = case proveLe(c.guards, a, b) of impUnknown: - localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)") + message(c.graph.config, a.info, warnStaticIndexCheck, + "cannot prove: " & ?a & " <= " & ?b) of impYes: discard of impNo: - localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") + message(c.graph.config, a.info, warnStaticIndexCheck, + "can prove: " & ?a & " > " & ?b) proc checkBounds(c: AnalysisCtx; arr, idx: PNode) = checkLe(c, lowBound(c.graph.config, arr), idx) @@ -162,17 +164,17 @@ proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) = case proveLe(m, x, d) of impNo: discard of impUnknown, impYes: - localError(conf, x.info, + message(conf, x.info, warnStaticIndexCheck, "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % [?c, ?y, ?x, ?y, ?c, ?d]) of impYes: case proveLe(m, x, d) of impUnknown: - localError(conf, x.info, + message(conf, x.info, warnStaticIndexCheck, "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % [?x, ?d, ?x, ?y, ?c, ?d]) of impYes: - localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" % + message(conf, x.info, warnStaticIndexCheck, "($#)..($#) not disjoint from ($#)..($#)" % [?c, ?y, ?x, ?y, ?c, ?d]) of impNo: discard of impNo: discard @@ -261,8 +263,6 @@ proc min(a, b: PNode): PNode = elif a.intVal < b.intVal: result = a else: result = b -proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags - template pushSpawnId(c, body) {.dirty.} = inc c.spawns let oldSpawnId = c.currentSpawnId diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index af706bee1..5d4ad658c 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -75,6 +75,7 @@ type gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool inEnforcedNoSideEffects: bool maxLockLevel, currLockLevel: TLockLevel + currOptions: TOptions config: ConfigRef graph: ModuleGraph c: PContext @@ -668,6 +669,32 @@ proc cstringCheck(tracked: PEffects; n: PNode) = a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}): message(tracked.config, n.info, warnUnsafeCode, renderTree(n)) +proc checkLe(c: PEffects; a, b: PNode) = + case proveLe(c.guards, a, b) + of impUnknown: + #for g in c.guards.s: + # if g != nil: echo "I Know ", g + message(c.config, a.info, warnStaticIndexCheck, + "cannot prove: " & $a & " <= " & $b) + of impYes: + discard + of impNo: + message(c.config, a.info, warnStaticIndexCheck, + "can prove: " & $a & " > " & $b) + +proc checkBounds(c: PEffects; arr, idx: PNode) = + checkLe(c, lowBound(c.config, arr), idx) + checkLe(c, idx, highBound(c.config, arr, c.guards.o)) + +proc checkRange(c: PEffects; value: PNode; typ: PType) = + if typ.skipTypes(abstractInst - {tyRange}).kind == tyRange: + let lowBound = nkIntLit.newIntNode(firstOrd(c.config, typ)) + lowBound.info = value.info + let highBound = nkIntLit.newIntNode(lastOrd(c.config, typ)) + highBound.info = value.info + checkLe(c, lowBound, value) + checkLe(c, value, highBound) + proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = createTypeBoundOps(tracked.graph, tracked.c, typ, info) if (typ != nil and tfHasAsgn in typ.flags) or @@ -755,12 +782,17 @@ proc track(tracked: PEffects, n: PNode) = discard else: message(tracked.config, arg.info, warnProveInit, $arg) + # check required for 'nim check': if n[1].typ.len > 0: createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) createTypeBoundOps(tracked, n[1].typ, n.info) # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? + elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and + optStaticBoundsCheck in tracked.currOptions: + checkBounds(tracked, n[1], n[2]) + if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and tracked.owner.kind != skMacro: let opKind = find(AttachedOpToStr, a.sym.name.s.normalize) @@ -849,6 +881,28 @@ proc track(tracked: PEffects, n: PNode) = of nkForStmt, nkParForStmt: # we are very conservative here and assume the loop is never executed: let oldState = tracked.init.len + + let oldFacts = tracked.guards.s.len + let iterCall = n[n.len-2] + if optStaticBoundsCheck in tracked.currOptions and iterCall.kind in nkCallKinds: + let op = iterCall[0] + if op.kind == nkSym and fromSystem(op.sym): + let iterVar = n[0] + case op.sym.name.s + of "..", "countup", "countdown": + let lower = iterCall[1] + let upper = iterCall[2] + # for i in 0..n means 0 <= i and i <= n. Countdown is + # the same since only the iteration direction changes. + addFactLe(tracked.guards, lower, iterVar) + addFactLe(tracked.guards, iterVar, upper) + of "..<": + let lower = iterCall[1] + let upper = iterCall[2] + addFactLe(tracked.guards, lower, iterVar) + addFactLt(tracked.guards, iterVar, upper) + else: discard + for i in 0.. 1: # XXX this is a bit hacky: @@ -867,6 +920,7 @@ proc track(tracked: PEffects, n: PNode) = track(tracked, iterCall) track(tracked, loopBody) setLen(tracked.init, oldState) + setLen(tracked.guards.s, oldFacts) of nkObjConstr: when false: track(tracked, n[0]) let oldFacts = tracked.guards.s.len @@ -932,18 +986,27 @@ proc track(tracked: PEffects, n: PNode) = # a better solution will come up eventually. if n[1].typ.kind != tyString: createTypeBoundOps(tracked, n[1].typ, n[1].info) + if optStaticBoundsCheck in tracked.currOptions: + checkRange(tracked, n[1], n.typ) of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: if n.len == 1: track(tracked, n[0]) if tracked.owner.kind != skMacro: createTypeBoundOps(tracked, n.typ, n.info) createTypeBoundOps(tracked, n[0].typ, n[0].info) + if optStaticBoundsCheck in tracked.currOptions: + checkRange(tracked, n[0], n.typ) of nkBracket: for i in 0.. 0: result = firstOrd(conf, lastSon(t)) else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') - of tyUncheckedArray: + of tyUncheckedArray, tyCString: result = Zero else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index ed5d2649f..28b2f9c05 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -50,7 +50,7 @@ type wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangeChecks, wBoundChecks, wOverflowChecks, wNilChecks, - wFloatChecks, wNanChecks, wInfChecks, wStyleChecks, + wFloatChecks, wNanChecks, wInfChecks, wStyleChecks, wStaticBoundchecks, wNonReloadable, wExecuteOnReload, wAssertions, wPatterns, wTrMacros, wSinkInference, wWarnings, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, @@ -137,7 +137,7 @@ const "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", "noconv", "on", "off", "checks", "rangechecks", "boundchecks", "overflowchecks", "nilchecks", - "floatchecks", "nanchecks", "infchecks", "stylechecks", + "floatchecks", "nanchecks", "infchecks", "stylechecks", "staticboundchecks", "nonreloadable", "executeonreload", "assertions", "patterns", "trmacros", "sinkinference", "warnings", "hints", diff --git a/tests/arc/timportedobj.nim b/tests/arc/timportedobj.nim index 82d7b4740..9a88a9468 100644 --- a/tests/arc/timportedobj.nim +++ b/tests/arc/timportedobj.nim @@ -1,14 +1,14 @@ -discard """ - cmd: "nim c --gc:arc $file" - action: "compile" -""" - -# bug #13269 - -import posix -proc foo*() = - var last = newSeq[Stat]() - var next = last - for i in 0..3: - last = next -foo() +discard """ + cmd: "nim c --gc:arc $file" + action: "compile" +""" + +# bug #13269 + +import posix +proc foo*() = + var last = newSeq[Stat]() + var next = last + for i in 0..3: + last = next +foo() diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim index 4fd169827..c5178f71b 100644 --- a/tests/notnil/tnotnil4.nim +++ b/tests/notnil/tnotnil4.nim @@ -10,8 +10,9 @@ proc check(a: TObj not nil) = proc doit() = var x : array[0..1, TObj] - if x[0] != nil: - check(x[0]) + let y = x[0] + if y != nil: + check(y) doit() diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim index 4c6065fd6..15bf526df 100644 --- a/tests/parallel/tinvalid_array_bounds.nim +++ b/tests/parallel/tinvalid_array_bounds.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "can prove: i + 1 > 30" - line: 21 + errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)" + line: 20 """ import threadpool diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim index 833c72a0a..f1ae6e923 100644 --- a/tests/parallel/tuseafterdef.nim +++ b/tests/parallel/tuseafterdef.nim @@ -1,6 +1,7 @@ discard """ errormsg: "(k)..(k) not disjoint from (k)..(k)" line: 23 + action: compile """ # bug #1597 diff --git a/tests/tools/second.nim b/tests/tools/second.nim index 0dbe72adb..ee94af25f 100644 --- a/tests/tools/second.nim +++ b/tests/tools/second.nim @@ -1,3 +1,3 @@ -import tables - -let dataEx* = {1: 2, 3: 4}.toTable +import tables + +let dataEx* = {1: 2, 3: 4}.toTable From a96842aaeb46ddf3990f9632259a26cb451c5b80 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 18 Mar 2020 14:43:28 +0100 Subject: [PATCH 0151/4254] removed .gitattributes as it only causes trouble for me --- .gitattributes | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index a7cd44ba6..000000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# tests expects the text files associated with them have LF only as EOL -**/test*/**/* text eol=lf From fb641483f0e2ed974b89d629ea5ec28e5e6145ce Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Mar 2020 16:57:34 +0100 Subject: [PATCH 0152/4254] arc optimizations (#13325) * scope based destructors * handle 'or' and 'and' expressions properly, see the new test arc/tcontrolflow.nim * make this branch mergable, logic is disabled for now --- compiler/ccgexprs.nim | 4 + compiler/cgmeth.nim | 2 +- compiler/closureiters.nim | 4 +- compiler/injectdestructors.nim | 321 ++++++++++++++++++------- doc/destructors.rst | 1 + lib/system.nim | 9 +- tests/arc/tcontrolflow.nim | 55 +++++ tests/destructor/tasync_prototype.nim | 5 + tests/destructor/tdestructor.nim | 2 +- tests/destructor/tmisc_destructors.nim | 2 +- tests/destructor/tv2_raise.nim | 2 +- 11 files changed, 312 insertions(+), 95 deletions(-) create mode 100644 tests/arc/tcontrolflow.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4aad1a4f8..4cf6f36db 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2573,6 +2573,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: putLocIntoDest(p, d, sym.loc) of skTemp: + if sym.loc.r == nil: + # we now support undeclared 'skTemp' variables for easier + # transformations in other parts of the compiler: + assignLocalVar(p, n) if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index a71ac6ea7..edf9db383 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This module implements code generation for multi methods. +## This module implements code generation for methods. import intsets, options, ast, msgs, idents, renderer, types, magicsys, diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index ef08a7bae..3422a8a46 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -154,8 +154,8 @@ type # is their finally. For finally it is parent finally. Otherwise -1 const - nkSkip = { nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt, - nkCommentStmt } + procDefs + nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt, + nkCommentStmt} + procDefs proc newStateAccess(ctx: var Ctx): PNode = if ctx.stateVarSym.isNil: diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 5e51aeb9d..55886540c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -13,6 +13,13 @@ ## See doc/destructors.rst for a spec of the implemented rewrite rules +## XXX Optimization to implement: if a local variable is only assigned +## string literals as in ``let x = conf: "foo" else: "bar"`` do not +## produce a destructor call for ``x``. The address of ``x`` must also +## not have been taken. ``x = "abc"; x.add(...)`` + +# Todo: +# - eliminate 'wasMoved(x); destroy(x)' pairs as a post processing step. import intsets, ast, msgs, renderer, magicsys, types, idents, @@ -20,6 +27,10 @@ import lineinfos, parampatterns, sighashes from trees import exprStructuralEquivalent +from algorithm import reverse + +const + scopeBasedDestruction = false type Con = object @@ -27,10 +38,13 @@ type g: ControlFlowGraph jumpTargets: IntSet destroys, topLevelVars: PNode + scopeDestroys: seq[PNode] # used as a stack that pop from + # at strategic places which try to + # mimic the natural scope. graph: ModuleGraph emptyNode: PNode otherRead: PNode - inLoop: int + inLoop, hasUnstructuredCf, inDangerousBranch: int declaredVars: IntSet # variables we already moved to the top level uninit: IntSet # set of uninit'ed vars uninitComputed: bool @@ -285,7 +299,6 @@ proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) sym.typ = typ result = newSymNode(sym) - c.addTopVar(result) proc genWasMoved(n: PNode; c: var Con): PNode = result = newNodeI(nkCall, n.info) @@ -339,10 +352,10 @@ proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':' proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) - # XXX This is only required if we are in a loop. Since we move temporaries - # out of loops we need to mark it as 'wasMoved'. - result.add genWasMoved(tmp, c) + when not scopeBasedDestruction: + c.addTopVar(tmp) if hasDestructor(n.typ): + result.add genWasMoved(tmp, c) var m = genCopy(c, tmp, n) m.add p(n, c, normal) result.add m @@ -354,6 +367,8 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = if c.graph.config.selectedGC in {gcArc, gcOrc}: assert(not containsGarbageCollectedRef(n.typ)) result.add newTree(nkAsgn, tmp, p(n, c, normal)) + # Since we know somebody will take over the produced copy, there is + # no need to destroy it. result.add tmp proc isDangerousSeq(t: PType): bool {.inline.} = @@ -375,60 +390,137 @@ proc containsConstSeq(n: PNode): bool = if containsConstSeq(son): return true else: discard -template handleNested(n: untyped, processCall: untyped) = +proc handleTmpDestroys(c: var Con; body: PNode; t: PType; + oldHasUnstructuredCf, oldTmpDestroysLen: int) = + if c.hasUnstructuredCf == oldHasUnstructuredCf: + # no need for a try-finally statement: + if body.kind == nkStmtList: + for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): + body.add c.scopeDestroys[i] + elif isEmptyType(t): + var n = newNodeI(nkStmtList, body.info) + n.add body[^1] + for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): + n.add c.scopeDestroys[i] + body[^1] = n + elif body.kind == nkStmtListExpr and body.len > 0 and body[^1].kind == nkSym: + # special case: Do not translate (x; y; sym) into + # (x; y; tmp = sym; destroy(x); destroy(y); tmp ) + # but into + # (x; y; destroy(x); destroy(y); sym ) + let sym = body[^1] + body[^1] = c.scopeDestroys[^1] + for i in countdown(c.scopeDestroys.high - 1, oldTmpDestroysLen): + body.add c.scopeDestroys[i] + body.add sym + else: + # fun ahead: We have to transform (x; y; E()) into + # (x; y; tmp = E(); destroy(x); destroy(y); tmp ) + let t2 = body[^1].typ + let tmp = getTemp(c, t2, body.info) + when not scopeBasedDestruction: + c.addTopVar(tmp) + # the tmp does not have to be initialized + var n = newNodeIT(nkStmtListExpr, body.info, t2) + n.add newTree(nkFastAsgn, tmp, body[^1]) + for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): + n.add c.scopeDestroys[i] + n.add tmp + body[^1] = n + #c.scopeDestroys.add genDestroy(c, tmp) + else: + # unstructured control flow was used, use a 'try finally' to ensure + # destruction: + if isEmptyType(t): + var n = newNodeI(nkStmtList, body.info) + for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): + n.add c.scopeDestroys[i] + body[^1] = newTryFinally(body[^1], n) + else: + # fun ahead: We have to transform (x; y; E()) into + # ((try: tmp = (x; y; E()); finally: destroy(x); destroy(y)); tmp ) + let t2 = body[^1].typ + let tmp = getTemp(c, t2, body.info) + when not scopeBasedDestruction: + c.addTopVar(tmp) + # the tmp does not have to be initialized + var fin = newNodeI(nkStmtList, body.info) + for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): + fin.add c.scopeDestroys[i] + var n = newNodeIT(nkStmtListExpr, body.info, t2) + n.add newTryFinally(newTree(nkFastAsgn, tmp, body[^1]), fin) + n.add tmp + body[^1] = n + #c.scopeDestroys.add genDestroy(c, tmp) + + c.scopeDestroys.setLen oldTmpDestroysLen + +proc handleNested(n, dest: PNode; c: var Con; mode: ProcessMode): PNode = + template processCall(node: PNode): PNode = + if node.typ == nil or dest == nil: + p(node, c, mode) + else: + moveOrCopy(dest, node, c) + + proc handleScope(n, dest: PNode; t: PType; + takeOver: Natural; c: var Con; mode: ProcessMode): PNode = + let oldHasUnstructuredCf = c.hasUnstructuredCf + let oldTmpDestroysLen = c.scopeDestroys.len + result = shallowCopy(n) + for i in 0.. oldTmpDestroysLen: + handleTmpDestroys(c, result, t, oldHasUnstructuredCf, oldTmpDestroysLen) + else: + setLen(result.sons, last) + if c.scopeDestroys.len > oldTmpDestroysLen: + handleTmpDestroys(c, result, t, oldHasUnstructuredCf, oldTmpDestroysLen) + if result.kind != nkFinally: + result.add processCall(n[last]) + else: + result = newTree(nkStmtListExpr, result, processCall(n[last])) + result.typ = t + case n.kind of nkStmtList, nkStmtListExpr: if n.len == 0: return n - result = copyNode(n) - for i in 0.. 0: + # unpacked tuple needs reset at every loop iteration + res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) + elif sfThread notin v.sym.flags: + # do not destroy thread vars for now at all for consistency. + c.destroys.add genDestroy(c, v) + if ri.kind == nkEmpty and c.inLoop > 0: + res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c) + elif ri.kind != nkEmpty: + res.add moveOrCopy(v, ri, c) + +proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = + if not containsOrIncl(c.declaredVars, v.sym.id): + c.addTopVar(v) + if isUnpackedTuple(v): + if c.inLoop > 0: + # unpacked tuple needs reset at every loop iteration + res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) + elif {sfGlobal, sfThread} * v.sym.flags == {sfGlobal}: + c.destroys.add genDestroy(c, v) + else: + # We always translate 'var v = f()' into bitcopies. If 'v' is in a loop, + # the destruction at the loop end will free the resources. Other assignments + # will destroy the old value inside 'v'. If we have 'var v' without an initial + # default value we translate it into 'var v = default()'. We translate + # 'var x = someGlobal' into 'var v = default(); `=`(v, someGlobal). The + # lack of copy constructors is really beginning to hurt us. :-( + #if c.inDangerousBranch == 0: v.sym.flags.incl sfNoInit + c.scopeDestroys.add genDestroy(c, v) + if ri.kind == nkEmpty and c.inLoop > 0: + res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c) + elif ri.kind != nkEmpty: + res.add moveOrCopy(v, ri, c) + proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, - nkIfExpr, nkCaseStmt, nkWhen}: - handleNested(n): p(node, c, mode) + nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt}: + result = handleNested(n, nil, c, mode) elif mode == sinkArg: if n.containsConstSeq: # const sequences are not mutable and so we need to pass a copy to the @@ -522,6 +667,9 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = elif n.kind in {nkObjDownConv, nkObjUpConv}: result = copyTree(n) result[0] = p(n[0], c, sinkArg) + elif n.typ == nil: + # 'raise X' can be part of a 'case' expression. Deal with it here: + result = p(n, c, normal) else: # copy objects that are not temporary but passed to a 'sink' parameter result = passCopyToSink(n, c) @@ -554,12 +702,22 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = of nkCallKinds: let parameters = n[0].typ let L = if parameters != nil: parameters.len else: 0 + + var isDangerous = false + if n[0].kind == nkSym and n[0].sym.magic in {mOr, mAnd}: + inc c.inDangerousBranch + isDangerous = true + result = shallowCopy(n) for i in 1.. 0: - # unpacked tuple needs reset at every loop iteration - result.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) - if ri.kind == nkEmpty and c.inLoop > 0: - ri = genDefaultCall(v.typ, c, v.info) - if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c) + when not scopeBasedDestruction: + pVarTopLevel(v, c, ri, result) + else: + pVarScoped(v, c, ri, result) + else: + if ri.kind == nkEmpty and c.inLoop > 0: + ri = genDefaultCall(v.typ, c, v.info) + if ri.kind != nkEmpty: + result.add moveOrCopy(v, ri, c) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) @@ -634,6 +788,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = result.add call else: let tmp = getTemp(c, n[0].typ, n.info) + c.addTopVar(tmp) var m = genCopyNoCheck(c, tmp, n[0]) m.add p(n[0], c, normal) result = newTree(nkStmtList, genWasMoved(tmp, c), m) @@ -648,17 +803,22 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = result.add p(n[0], c, sinkArg) else: result.add copyNode(n[0]) + inc c.hasUnstructuredCf of nkWhileStmt: - result = copyNode(n) - inc c.inLoop - result.add p(n[0], c, normal) - result.add p(n[1], c, normal) - dec c.inLoop + result = handleNested(n, nil, c, mode) of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakStmt, nkBreakState: + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState: result = n + of nkBreakStmt: + inc c.hasUnstructuredCf + result = n + of nkReturnStmt: + result = shallowCopy(n) + for i in 0.. 0: result.add c.topLevelVars - if c.destroys.len > 0: - c.destroys.sons = reverseDestroys(c.destroys.sons) + if c.destroys.len > 0 or c.scopeDestroys.len > 0: + reverse c.destroys.sons + var fin: PNode if owner.kind == skModule: - result.add newTryFinally(body, extractDestroysForTemporaries(c, c.destroys)) + fin = newTryFinally(body, extractDestroysForTemporaries(c, c.destroys)) g.globalDestructors.add c.destroys else: - result.add newTryFinally(body, c.destroys) + fin = newTryFinally(body, c.destroys) + for i in countdown(c.scopeDestroys.high, 0): fin[1][0].add c.scopeDestroys[i] + result.add fin else: result.add body dbg: diff --git a/doc/destructors.rst b/doc/destructors.rst index 6d3ed00dd..0d4a6c985 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -451,6 +451,7 @@ for expressions of type ``lent T`` or of type ``var T``. result = Tree(kids: kids) # converted into: `=sink`(result.kids, kids); wasMoved(kids) + `=destroy`(kids) proc `[]`*(x: Tree; i: int): lent Tree = result = x.kids[i] diff --git a/lib/system.nim b/lib/system.nim index 602fbc1f1..cd941b19f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1954,14 +1954,7 @@ template newException*(exceptn: typedesc, message: string; parentException: ref Exception = nil): untyped = ## Creates an exception object of type ``exceptn`` and sets its ``msg`` field ## to `message`. Returns the new exception object. - when declared(owned): - var e: owned(ref exceptn) - else: - var e: ref exceptn - new(e) - e.msg = message - e.parent = parentException - e + (ref exceptn)(msg: message, parent: parentException) when hostOS == "standalone" and defined(nogc): proc nimToCStringConv(s: NimString): cstring {.compilerproc, inline.} = diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim new file mode 100644 index 000000000..8fc9bf61d --- /dev/null +++ b/tests/arc/tcontrolflow.nim @@ -0,0 +1,55 @@ +discard """ + output: '''begin A +elif +destroyed +end A +begin false +if +destroyed +end false +begin true +if +end true +''' + cmd: "nim c --gc:arc -d:danger $file" + disabled: "true" +""" +# we use the -d:danger switch to detect uninitialized stack +# slots more reliably (there shouldn't be any, of course). + +# XXX Enable once scope based destruction works! + +type + Foo = object + id: int + +proc `=destroy`(x: var Foo) = + if x.id != 0: + echo "destroyed" + x.id = 0 + +proc construct(): Foo = Foo(id: 3) + +proc elifIsEasy(cond: bool) = + echo "begin A" + if cond: + echo "if" + elif construct().id == 3: + echo "elif" + else: + echo "else" + echo "end A" + +elifIsEasy(false) + + +proc orIsHard(cond: bool) = + echo "begin ", cond + if cond or construct().id == 3: + echo "if" + else: + echo "else" + echo "end ", cond + +orIsHard(false) +orIsHard(true) diff --git a/tests/destructor/tasync_prototype.nim b/tests/destructor/tasync_prototype.nim index bd80adf0c..81fd824e9 100644 --- a/tests/destructor/tasync_prototype.nim +++ b/tests/destructor/tasync_prototype.nim @@ -32,7 +32,12 @@ proc serve(server: PAsyncHttpServer): PFutureBase = yield acceptAddrFut var fut = acceptAddrFut.value + # with the new scope based destruction, this cannot + # possibly work: var f {.cursor.} = processClient() + # It also seems to be the wrong way how to avoid the + # cycle. The cycle is caused by capturing the 'env' + # part from 'env.f'. when true: f.callback = proc () = diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index 5cfecea4e..b6d60323c 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -33,7 +33,7 @@ type p: pointer proc `=destroy`(o: var TMyObj) = - if o.p != nil: + if o.p != nil: dealloc o.p o.p = nil echo "myobj destroyed" diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim index 53c67e34b..73c54eab3 100644 --- a/tests/destructor/tmisc_destructors.nim +++ b/tests/destructor/tmisc_destructors.nim @@ -22,7 +22,7 @@ proc `=`(dest: var Foo, src: Foo) = assign_counter.inc proc test(): auto = - var a,b : Foo + var a, b: Foo return (a, b, Foo(boo: 5)) var (a, b, _) = test() diff --git a/tests/destructor/tv2_raise.nim b/tests/destructor/tv2_raise.nim index 828d0a396..4ea94a864 100644 --- a/tests/destructor/tv2_raise.nim +++ b/tests/destructor/tv2_raise.nim @@ -2,7 +2,7 @@ discard """ valgrind: true cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''OK 3 -(allocCount: 8, deallocCount: 3)''' +(allocCount: 8, deallocCount: 5)''' """ import strutils, math From 88566cc6518977ae807869d191706e41ef3ff2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Wed, 18 Mar 2020 21:36:48 +0100 Subject: [PATCH 0153/4254] allow category nimble-packages to test a single package (#13576) --- testament/categories.nim | 6 ++++-- testament/testament.nim | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 9f50a4705..43d39f227 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -478,7 +478,7 @@ proc makeSupTest(test, options: string, cat: Category): TTest = result.options = options result.startTime = epochTime() -proc testNimblePackages(r: var TResults, cat: Category) = +proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = if nimbleExe == "": echo "[Warning] - Cannot run nimble tests: Nimble binary not found." return @@ -491,6 +491,8 @@ proc testNimblePackages(r: var TResults, cat: Category) = var errors = 0 try: for name, url, cmd, hasDep in listPackages(): + if packageFilter notin name: + continue inc r.total var test = makeSupTest(url, "", cat) let buildPath = packagesDir / name @@ -706,7 +708,7 @@ proc processCategory(r: var TResults, cat: Category, compileExample(r, "examples/gtk/*.nim", options, cat) compileExample(r, "examples/talk/*.nim", options, cat) of "nimble-packages": - testNimblePackages(r, cat) + testNimblePackages(r, cat, options) of "niminaction": testNimInAction(r, cat, options) of "untestable": diff --git a/testament/testament.nim b/testament/testament.nim index a437f18dd..a041d771f 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -717,7 +717,6 @@ proc main() = of "c", "cat", "category": skips = loadSkipFrom(skipFrom) var cat = Category(p.key) - p.next processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = true) of "pcat": skips = loadSkipFrom(skipFrom) From a0ccfd16a77ea0e9ef3077dadf62de5fe9c52004 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 18 Mar 2020 18:55:39 -0300 Subject: [PATCH 0154/4254] Documentation GC (#13109) * Update Documentation about GC, add ARC based on code observations and https://forum.nim-lang.org/t/5734#35562 * Rephrase 'Garbage Collector' on documentation, see #13331 * Peer Review Feedbacks * When the body of a documentation section is all for garbage collector details then add 'for garbage collectors' to the title to identify they may not apply for ARC * Change 'GC' for 'garbage collector'. * Move 'Memory Management Strategies' at the top, without changes * Move the info for RefC GC from 'Introduction' to 'RefC' section without changes, make 'Introduction' about Nims 'Multi-paradigm Memory Management Strategies'. --- doc/gc.rst | 172 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 75 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index a41a30588..b82edd570 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -1,6 +1,6 @@ -========================== -Nim's Garbage Collector -========================== +======================= +Nim's Memory Management +======================= :Author: Andreas Rumpf :Version: |nimversion| @@ -14,37 +14,78 @@ Nim's Garbage Collector Introduction ============ -This document describes how the GC works and how to tune it for -(soft) `realtime systems`:idx:. - -The basic algorithm is *Deferred Reference Counting* with cycle detection. -References on the stack are not counted for better performance (and easier C -code generation). Cycle detection is currently done by a simple mark&sweep -GC that has to scan the full (thread local heap). ``--gc:v2`` replaces this -with an incremental mark and sweep. That it is not production ready yet, -however. +This document describes how the multi-paradigm memory management strategies work. +How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, +and how the memory management strategies that are not garbage collectors work. -The GC is only triggered in a memory allocation operation. It is not triggered -by some timer and does not run in a background thread. +Multi-paradigm Memory Management Strategies +=========================================== -To force a full collection call ``GC_fullCollect``. Note that it is generally -better to let the GC do its work and not enforce a full collection. +You can choose the memory management strategy to use when compiling source code, +you can pass ``--gc:`` on the compile command with the selected memory management strategy. + +- ``--gc:refc`` Deferred `reference counting `_ based garbage collector + with `cycle detection `_ + by a simple Mark&Sweep that has to scan the full heap, + is only triggered in a memory allocation operation and + it is not triggered by some timer and does not run in a background thread, + `thread local heap `_, + references on the stack are not counted for better performance (and easier C code generation), default. +- ``--gc:markAndSweep`` `Mark-And-Sweep `_ based garbage collector, + `thread local heap `_. +- ``--gc:boehm`` `Boehm `_ based garbage collector, + `stop-the-world `_, + `shared heap `_. +- ``--gc:go`` Go lang like garbage collector, + `stop-the-world `_, + `shared heap `_. +- ``--gc:regions`` `Stack `_ based garbage collector. +- ``--gc:arc`` Not a garbage collector. Plain `reference counting `_ with + `move semantic optimizations `_, + `shared heap `_, + can be optimized with `sink `_ and `lent `_ annotations, + designed to work well with `WebAssembly `_, `Emscripten `_, + `hot code reloading `_ and `address sanitizers `_, + basically it is like a shared heap with subgraphs with a single owner, + this is not the same as Swift and ObjectiveC lang ARC because those can not handle cycles, + can use `GOTO based Exception handling `_, + may become default in future releases. +- ``--gc:orc`` Not a garbage collector. Similar to ``--gc:arc`` but with improved + `cycle detection `_. + `Cycle detection `_ + will not be the default, because by definition it conflicts with + `deterministic memory management `_. +- ``--gc:none`` No memory management strategy nor garbage collector. + You should use `Manual memory management `_ with it. + +The same Nim code can be compiled to use any of the memory management strategies; +the Nim syntax generally will not change from one memory management strategy to another. + +No garbage collector nor memory management is used for `JavaScript and NodeJS +`_ compilation targets. +`NimScript `_ target uses Nim VM memory management strategy. + +All memory management strategies are supported equally on Nim when possible and aplicable, +even if there is a default one, all others should also work as documented. + +If you are new to Nim and just starting, the default memory management strategy is balanced to fit most common use cases. -Cycle collector -=============== +Cycle collector for garbage collectors +====================================== The cycle collector can be en-/disabled independently from the other parts of -the GC with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. +the garbage collector with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. -Realtime support -================ +Realtime support for garbage collectors +======================================= To enable realtime support, the symbol `useRealtimeGC`:idx: needs to be defined via ``--define:useRealtimeGC`` (you can put this into your config -file as well). With this switch the GC supports the following operations: +file as well). +With this switch the garbage collector supports the following operations: .. code-block:: nim proc GC_setMaxPause*(maxPauseInUs: int) @@ -52,24 +93,26 @@ file as well). With this switch the GC supports the following operations: The unit of the parameters ``maxPauseInUs`` and ``us`` is microseconds. -These two procs are the two modus operandi of the realtime GC: +These two procs are the two modus operandi of the realtime garbage collector: (1) GC_SetMaxPause Mode You can call ``GC_SetMaxPause`` at program startup and then each triggered - GC run tries to not take longer than ``maxPause`` time. However, it is + garbage collector run tries to not take longer than ``maxPause`` time. However, it is possible (and common) that the work is nevertheless not evenly distributed - as each call to ``new`` can trigger the GC and thus take ``maxPause`` + as each call to ``new`` can trigger the garbage collector and thus take ``maxPause`` time. (2) GC_step Mode - This allows the GC to perform some work for up to ``us`` time. This is - useful to call in a main loop to ensure the GC can do its work. To - bind all GC activity to a ``GC_step`` call, deactivate the GC with - ``GC_disable`` at program startup. If ``strongAdvice`` is set to ``true``, - GC will be forced to perform collection cycle. Otherwise, GC may decide not - to do anything, if there is not much garbage to collect. + This allows the garbage collector to perform some work for up to ``us`` time. + This is useful to call in a main loop to ensure the garbage collector can do its work. + To bind all garbage collector activity to a ``GC_step`` call, + deactivate the garbage collector with ``GC_disable`` at program startup. + If ``strongAdvice`` is set to ``true``, + then the garbage collector will be forced to perform collection cycle. + Otherwise, the garbage collector may decide not to do anything, + if there is not much garbage to collect. You may also specify the current stack size via ``stackSize`` parameter. It can improve performance, when you know that there are no unique Nim references below certain point on the stack. Make sure the size you specify @@ -82,11 +125,11 @@ time will be met in almost all cases on modern CPUs (with the cycle collector disabled). -Time measurement ----------------- +Time measurement with garbage collectors +---------------------------------------- -The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the -implementation): +The garbage collectors's way of measuring time uses +(see ``lib/system/timers.nim`` for the implementation): 1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. 2) ``mach_absolute_time`` on Mac OS X. @@ -95,14 +138,13 @@ implementation): As such it supports a resolution of nanoseconds internally; however the API uses microseconds for convenience. - -Define the symbol ``reportMissedDeadlines`` to make the GC output whenever it -missed a deadline. The reporting will be enhanced and supported by the API in -later versions of the collector. +Define the symbol ``reportMissedDeadlines`` to make the +garbage collector output whenever it missed a deadline. +The reporting will be enhanced and supported by the API in later versions of the collector. -Tweaking the GC ---------------- +Tweaking the garbage collector +------------------------------ The collector checks whether there is still time left for its work after every ``workPackage``'th iteration. This is currently set to 100 which means @@ -111,25 +153,27 @@ that up to 100 objects are traversed and freed before it checks again. Thus highly specialized environments or for older hardware. -Keeping track of memory ------------------------ +Keeping track of memory with garbage collectors +----------------------------------------------- If you need to pass around memory allocated by Nim to C, you can use the procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them -being freed by the GC. Other useful procs from `system `_ you can -use to keep track of memory are: +being freed by the garbage collector. +Other useful procs from `system `_ you can use to keep track of memory are: -* ``getTotalMem()`` Returns the amount of total memory managed by the GC. -* ``getOccupiedMem()`` Bytes reserved by the GC and used by objects. -* ``getFreeMem()`` Bytes reserved by the GC and not in use. +* ``getTotalMem()`` Returns the amount of total memory managed by the garbage collector. +* ``getOccupiedMem()`` Bytes reserved by the garbage collector and used by objects. +* ``getFreeMem()`` Bytes reserved by the garbage collector and not in use. +* ``GC_getStatistics()`` Garbage collector statistics as a human-readable string. These numbers are usually only for the running thread, not for the whole heap, with the exception of ``--gc:boehm`` and ``--gc:go``. -In addition to ``GC_ref`` and ``GC_unref`` you can avoid the GC by manually -allocating memory with procs like ``alloc``, ``allocShared``, or -``allocCStringArray``. The GC won't try to free them, you need to call their -respective *dealloc* pairs when you are done with them or they will leak. +In addition to ``GC_ref`` and ``GC_unref`` you can avoid the garbage collector by manually +allocating memory with procs like ``alloc``, ``alloc0``, ``allocShared``, ``allocShared0`` or ``allocCStringArray``. +The garbage collector won't try to free them, you need to call their respective *dealloc* pairs +(``dealloc``, ``deallocShared``, ``deallocCStringArray``, etc) +when you are done with them or they will leak. Heap dump @@ -143,29 +187,7 @@ the total amount of object instances for this type as well as the total amount of bytes these instances take up. This list is currently unsorted! You need to use external shell script hacking to sort it. -The numbers count the number of objects in all GC heaps, they refer to +The numbers count the number of objects in all garbage collector heaps, they refer to all running threads, not only to the current thread. (The current thread would be the thread that calls ``dumpNumberOfInstances``.) This might change in later versions. - - -Garbage collector options -------------------------- - -You can choose which garbage collector to use when compiling source code, -you can pass ``--gc:`` on the compile command with the choosed garbage collector. - -- ``--gc:refc`` Deferred `reference counting `_ with cycle detection, `thread local heap `_, default. -- ``--gc:markAndSweep`` `Mark-And-Sweep `_ based garbage collector, `thread local heap `_. -- ``--gc:boehm`` `Boehm `_ based garbage collector, `stop-the-world `_, `shared heap `_. -- ``--gc:go`` Go lang like garbage collector, `stop-the-world `_, `shared heap `_. -- ``--gc:regions`` `Stack `_ based garbage collector. -- ``--gc:none`` No garbage collector. - -The same Nim code can be compiled to use any of the garbage collectors; -the Nim syntax generally will not change from one garbage collector to another. -No garbage collector is used for `JavaScript and NodeJS -`_ compilation targets. -`NimScript `_ target uses Nim VM garbage collector. - -If you are new to Nim and just starting, the default garbage collector is balanced to fit most common use cases. From 15ba765ebd83e44d18a0a2c23016bdf3b4bbecca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Mar 2020 23:52:49 +0100 Subject: [PATCH 0155/4254] enable --tlsEmulation:on for --gc:arc (#13685) * enable --tlsEmulation:on for --gc:arc * make -d:useMalloc work with --gc:arc --threads:on --- compiler/ccgcalls.nim | 2 +- lib/system/memalloc.nim | 2 +- lib/system/mm/malloc.nim | 4 ++-- lib/system/threads.nim | 5 +---- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 3be3cbb6b..de979f4a0 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -559,7 +559,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = proc canRaiseDisp(p: BProc; n: PNode): bool = # we assume things like sysFatal cannot raise themselves - if n.kind == nkSym and sfNeverRaises in n.sym.flags: + if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: result = false elif optPanics in p.config.globalOptions or (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index df4df2c15..178d199b8 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -339,7 +339,7 @@ when defined(js): proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer = discard -when hasAlloc and hasThreadSupport: +when hasAlloc and hasThreadSupport and not defined(useMalloc): proc getOccupiedSharedMem*(): int {.rtl.} ## Returns the number of bytes that are owned by the process ## on the shared heap and hold data. This is only available when diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 27e32f87d..ad510cef2 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -75,6 +75,6 @@ proc alloc(r: var MemRegion, size: int): pointer = proc alloc0Impl(r: var MemRegion, size: int): pointer = result = alloc0Impl(size) proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) -proc deallocOsPages(r: var MemRegion) {.inline.} = discard -proc deallocOsPages() {.inline.} = discard +proc deallocOsPages(r: var MemRegion) = discard +proc deallocOsPages() = discard diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 54b07e467..b3a4e32e4 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -79,7 +79,7 @@ when not defined(useNimRtl): # use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. type - Thread* {.pure, final.}[TArg] = object + Thread*[TArg] = object core: PGcThread sys: SysThread when TArg is void: @@ -98,9 +98,6 @@ proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) = ## A thread is destructed when the ``.thread`` proc returns ## normally or when it raises an exception. Note that unhandled exceptions ## in a thread nevertheless cause the whole process to die. - when not defined(nimNoNilSeqs): - if threadDestructionHandlers.isNil: - threadDestructionHandlers = @[] threadDestructionHandlers.add handler template afterThreadRuns() = From c74cee4e6a86f2906136c27eb41972667e7c0faa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Mar 2020 06:41:54 +0100 Subject: [PATCH 0156/4254] gc.rst that doesn't lie (#13686) --- doc/gc.rst | 84 +++++++++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index b82edd570..01e6b347f 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -22,65 +22,45 @@ and how the memory management strategies that are not garbage collectors work. Multi-paradigm Memory Management Strategies =========================================== -You can choose the memory management strategy to use when compiling source code, -you can pass ``--gc:`` on the compile command with the selected memory management strategy. +To choose the memory management strategy use the ``--gc:`` switch. -- ``--gc:refc`` Deferred `reference counting `_ based garbage collector - with `cycle detection `_ - by a simple Mark&Sweep that has to scan the full heap, - is only triggered in a memory allocation operation and - it is not triggered by some timer and does not run in a background thread, - `thread local heap `_, - references on the stack are not counted for better performance (and easier C code generation), default. -- ``--gc:markAndSweep`` `Mark-And-Sweep `_ based garbage collector, - `thread local heap `_. -- ``--gc:boehm`` `Boehm `_ based garbage collector, - `stop-the-world `_, - `shared heap `_. -- ``--gc:go`` Go lang like garbage collector, - `stop-the-world `_, - `shared heap `_. -- ``--gc:regions`` `Stack `_ based garbage collector. -- ``--gc:arc`` Not a garbage collector. Plain `reference counting `_ with - `move semantic optimizations `_, - `shared heap `_, - can be optimized with `sink `_ and `lent `_ annotations, - designed to work well with `WebAssembly `_, `Emscripten `_, - `hot code reloading `_ and `address sanitizers `_, - basically it is like a shared heap with subgraphs with a single owner, - this is not the same as Swift and ObjectiveC lang ARC because those can not handle cycles, - can use `GOTO based Exception handling `_, - may become default in future releases. -- ``--gc:orc`` Not a garbage collector. Similar to ``--gc:arc`` but with improved - `cycle detection `_. - `Cycle detection `_ - will not be the default, because by definition it conflicts with - `deterministic memory management `_. -- ``--gc:none`` No memory management strategy nor garbage collector. - You should use `Manual memory management `_ with it. +- ``--gc:refc``. This is the default GC. It's a + deferred reference counting based garbage collector + with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread local. +- ``--gc:markAndSweep``. Simple Mark-And-Sweep based garbage collector. Heaps are thread local. +- ``--gc:boehm``. Boehm based garbage collector, it offers a shared heap. +- ``--gc:go``. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. +- ``--gc:arc``. Plain reference counting with + `move semantic optimizations `_, offers a shared heap. + It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles + cause memory leaks, beware. -The same Nim code can be compiled to use any of the memory management strategies; -the Nim syntax generally will not change from one memory management strategy to another. +- ``--gc:orc``. Same as ``-gc:arc`` but adds a cycle collector based on "trial deletion". + Unforunately that makes its performance profile hard to reason about so it is less + useful for hard realtime systems. -No garbage collector nor memory management is used for `JavaScript and NodeJS +- ``--gc:none``. No memory management strategy nor garbage collector. Allocated memory is + simply never freed. You should use ``--gc:arc`` instead. + + +JavaScript's garbage collector is used for the `JavaScript and NodeJS `_ compilation targets. -`NimScript `_ target uses Nim VM memory management strategy. - -All memory management strategies are supported equally on Nim when possible and aplicable, -even if there is a default one, all others should also work as documented. - -If you are new to Nim and just starting, the default memory management strategy is balanced to fit most common use cases. +The `NimScript `_ target uses the memory management strategy built into +the Nim compiler. -Cycle collector for garbage collectors -====================================== +Tweaking the refc GC +==================== + +Cycle collector +--------------- The cycle collector can be en-/disabled independently from the other parts of the garbage collector with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. -Realtime support for garbage collectors -======================================= +Soft realtime support +--------------------- To enable realtime support, the symbol `useRealtimeGC`:idx: needs to be defined via ``--define:useRealtimeGC`` (you can put this into your config @@ -119,8 +99,8 @@ These two procs are the two modus operandi of the realtime garbage collector: is greater than the potential worst case size. These procs provide a "best effort" realtime guarantee; in particular the -cycle collector is not aware of deadlines yet. Deactivate it to get more -predictable realtime behaviour. Tests show that a 2ms max pause +cycle collector is not aware of deadlines. Deactivate it to get more +predictable realtime behaviour. Tests show that a 1ms max pause time will be met in almost all cases on modern CPUs (with the cycle collector disabled). @@ -153,8 +133,8 @@ that up to 100 objects are traversed and freed before it checks again. Thus highly specialized environments or for older hardware. -Keeping track of memory with garbage collectors ------------------------------------------------ +Keeping track of memory +======================= If you need to pass around memory allocated by Nim to C, you can use the procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them From b33335d7fd467fbf40ae8fcb5417f6a3c659e8dc Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 19 Mar 2020 08:07:44 +0000 Subject: [PATCH 0157/4254] httpcore: deprecate `==`(string, HttpCode) (#13682) According to [RFC7230], the reason phrase attached to the status line is optional and clients should not rely on it. This in turn causes the proc to be practically useless, as clients should only inspect the return code. Ref #13680. [RFC7230]: https://tools.ietf.org/html/rfc7230#section-3.1.2 --- changelog.md | 3 +++ lib/pure/httpcore.nim | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index fa753e7c4..60e5988f1 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,9 @@ `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of `2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when used on 29th, 30th, 31st of each month. +- `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical + usage. The `$` operator can be used to obtain the string form of `HttpCode` + for comparison if desired. ### Breaking changes in the compiler diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 8c679c017..8916aa17d 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -290,7 +290,14 @@ proc `$`*(code: HttpCode): string = proc `==`*(a, b: HttpCode): bool {.borrow.} -proc `==`*(rawCode: string, code: HttpCode): bool = +proc `==`*(rawCode: string, code: HttpCode): bool + {.deprecated: "Deprecated since v1.2; use rawCode == $code instead".} = + ## Compare the string form of the status code with a HttpCode + ## + ## **Note**: According to HTTP/1.1 specification, the reason phrase is + ## optional and should be ignored by the client, making this + ## proc only suitable for comparing the ``HttpCode`` against the + ## string form of itself. return cmpIgnoreCase(rawCode, $code) == 0 proc is2xx*(code: HttpCode): bool = From b5c9881a3056bd427ac1df2960d5497327fba946 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 19 Mar 2020 09:09:01 +0100 Subject: [PATCH 0158/4254] add `move` to `tables` to prevent warnings when compiled with `--gc:arc` (#13684) --- lib/pure/collections/tables.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 131804a22..b79e396fd 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1274,7 +1274,7 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) = var perturb = t.getPerturb(eh) while isFilled(t.data[j].hcode): j = nextTry(j, maxHash(t), perturb) - rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) + rawInsert(t, t.data, move n[h].key, move n[h].val, n[h].hcode, j) h = nxt template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = @@ -1540,7 +1540,7 @@ proc del*[A, B](t: var OrderedTable[A, B], key: A) = dec t.counter else: var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode) - rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) + rawInsert(t, t.data, move n[h].key, move n[h].val, n[h].hcode, j) h = nxt proc pop*[A, B](t: var OrderedTable[A, B], key: A, val: var B): bool {.since: (1, 1).} = @@ -2253,7 +2253,7 @@ proc enlarge[A](t: var CountTable[A]) = var n: seq[tuple[key: A, val: int]] newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): - if t.data[i].val != 0: ctRawInsert(t, n, t.data[i].key, t.data[i].val) + if t.data[i].val != 0: ctRawInsert(t, n, move t.data[i].key, move t.data[i].val) swap(t.data, n) proc remove[A](t: var CountTable[A], key: A) = @@ -2263,7 +2263,7 @@ proc remove[A](t: var CountTable[A], key: A) = for i in countup(0, high(t.data)): if t.data[i].val != 0: if t.data[i].key != key: - ctRawInsert(t, n, t.data[i].key, t.data[i].val) + ctRawInsert(t, n, move t.data[i].key, move t.data[i].val) else: removed = true swap(t.data, n) From ba6e7c636574b5c7add118daa7df6e4331f23fe1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Mar 2020 09:56:30 +0100 Subject: [PATCH 0159/4254] added a switch -d:nimEmulateOverflowChecks for broken or old GCC versions (#13692) --- changelog.md | 6 ++++++ compiler/cgen.nim | 8 +++++--- lib/nimbase.h | 2 +- lib/system/integerops.nim | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 60e5988f1..655da5feb 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,12 @@ ## Changes affecting backwards compatibility +- The Nim compiler now implements a faster way to detect overflows based + on GCC's `__builtin_sadd_overflow` family of functions. (Clang also + supports these). Some versions of GCC lack this feature and unfortunately + we cannot detect this case reliably. So if you get compilation errors like + "undefined reference to '__builtin_saddll_overflow'" compile your programs + with `-d:nimEmulateOverflowChecks`. ### Breaking changes in the standard library diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 10dda0ca9..216f6ba68 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1234,13 +1234,15 @@ proc genVarPrototype(m: BModule, n: PNode) = "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) -proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} = +proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = result.addf("#define NIM_INTBITS $1\L", [ platform.CPU[conf.target.targetCPU].intSize.rope]) if conf.cppCustomNamespace.len > 0: result.add("#define USE_NIM_NAMESPACE ") result.add(conf.cppCustomNamespace) result.add("\L") + if conf.isDefined("nimEmulateOverflowChecks"): + result.add("#define NIM_EmulateOverflowChecks\L") proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = if optCompileOnly in conf.globalOptions: @@ -1263,7 +1265,7 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = result = getCopyright(conf, cfile) if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L") - addIntTypes(result, conf) + addNimDefines(result, conf) proc getSomeNameForModule(m: PSym): Rope = assert m.kind == skModule @@ -1825,7 +1827,7 @@ proc writeHeader(m: BModule) = var guard = "__$1__" % [m.filename.splitFile.name.rope] result.addf("#ifndef $1$n#define $1$n", [guard]) - addIntTypes(result, m.config) + addNimDefines(result, m.config) generateHeaders(m) generateThreadLocalStorage(m) diff --git a/lib/nimbase.h b/lib/nimbase.h index 8c1c3d8a5..eb750864a 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -549,7 +549,7 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz #define nimModInt(a, b, res) (((*res) = (a) % (b)), 0) #define nimModInt64(a, b, res) (((*res) = (a) % (b)), 0) -#if !defined(_MSC_VER) +#if !defined(_MSC_VER) && !defined(NIM_EmulateOverflowChecks) /* these exist because we cannot have .compilerProcs that are importc'ed by a different name */ diff --git a/lib/system/integerops.nim b/lib/system/integerops.nim index dc0197f14..6f3be4c89 100644 --- a/lib/system/integerops.nim +++ b/lib/system/integerops.nim @@ -19,7 +19,7 @@ proc raiseDivByZero {.compilerproc, noinline.} = {.pragma: nimbaseH, importc, nodecl, noSideEffect, compilerproc.} -when defined(gcc) or defined(clang): +when (defined(gcc) or defined(clang)) and not defined(nimEmulateOverflowChecks): # take the #define from nimbase.h proc nimAddInt(a, b: int, res: ptr int): bool {.nimbaseH.} From a17e87b516a075a04e3d27c55b9314090abf5bae Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 19 Mar 2020 02:23:05 -0700 Subject: [PATCH 0160/4254] fix #11458 oswalkdir (#13689) * fix #11458 oswalkdir * changelog --- changelog.md | 1 + lib/pure/oswalkdir.nim | 31 ++++--------------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index 655da5feb..127579644 100644 --- a/changelog.md +++ b/changelog.md @@ -135,6 +135,7 @@ echo f - `parseutils.parseUntil` has now a different behaviour if the `until` parameter is empty. This was required for intuitive behaviour of the strscans module (see bug #13605). +- `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs ## Language additions diff --git a/lib/pure/oswalkdir.nim b/lib/pure/oswalkdir.nim index 1cf561c22..7d80b312c 100644 --- a/lib/pure/oswalkdir.nim +++ b/lib/pure/oswalkdir.nim @@ -7,30 +7,7 @@ # distribution, for details about the copyright. # -## Compile-time only version for walkDir if you need it at compile-time -## for JavaScript. - -type - PathComponent* = enum ## Enumeration specifying a path component. - pcFile, ## path refers to a file - pcLinkToFile, ## path refers to a symbolic link to a file - pcDir, ## path refers to a directory - pcLinkToDir ## path refers to a symbolic link to a directory - -proc staticWalkDir(dir: string; relative: bool): seq[ - tuple[kind: PathComponent; path: string]] = - discard - -iterator walkDir*(dir: string; relative = false): tuple[kind: PathComponent; - path: string] = - for k, v in items(staticWalkDir(dir, relative)): - yield (k, v) - -iterator walkDirRec*(dir: string; filter = {pcFile, pcDir}): string = - var stack = @[dir] - while stack.len > 0: - for k, p in walkDir(stack.pop()): - if k in filter: - case k - of pcFile, pcLinkToFile: yield p - of pcDir, pcLinkToDir: stack.add(p) +## This module is deprecated, ``import os`` instead. +{.deprecated: "import os.nim instead".} +import os +export PathComponent, walkDir, walkDirRec From 1f2042411a5343ad8bbdc8d2b1a75ce4f866a04c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 19 Mar 2020 02:39:18 -0700 Subject: [PATCH 0161/4254] fix #13412 nim now recompiles for stdin input; SuccessX now configurable; can show whether it recompiled (#13506) * fix #13412 nim now recompiles for stdin input; SuccessX now indicates whether it recompiled --- compiler/extccomp.nim | 10 ++++++++++ compiler/lineinfos.nim | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index ee921f4e1..5fc532cd8 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1064,6 +1064,9 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = lit ",\L\"extraCmds\": " lit $(%* conf.extraCmds) + lit ",\L\"stdinInput\": " + lit $(%* conf.projectIsStdin) + if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): lit ",\L\"cmdline\": " str conf.commandLine @@ -1090,6 +1093,13 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol return true if hashNimExe() != data["nimexe"].getStr: return true + if not data.hasKey("stdinInput"): return true + let stdinInput = data["stdinInput"].getBool + if conf.projectIsStdin or stdinInput: + # could optimize by returning false if stdin input was the same, + # but I'm not sure how to get full stding input + return true + let depfilesPairs = data["depfiles"] doAssert depfilesPairs.kind == JArray for p in depfilesPairs: diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 033a98513..680b193f9 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -101,7 +101,7 @@ const warnCycleCreated: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", - # keep in sync with `pegSuccess` see testament.nim + # keep in sync with `testament.isSuccess` hintSuccessX: "$loc LOC; $sec sec; $mem; $build build; proj: $project; out: $output", hintCC: "CC: $1", hintLineTooLong: "line too long", From 034dad8e321edcf6cf88a2ad93fceafae267cc74 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Mar 2020 12:57:45 +0100 Subject: [PATCH 0162/4254] fixes #13691 (#13694) --- compiler/injectdestructors.nim | 7 +++++-- tests/arc/tarcmisc.nim | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 tests/arc/tarcmisc.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 55886540c..dec437427 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -602,7 +602,10 @@ proc pVarTopLevel(v: PNode; c: var Con; ri, res: PNode) = res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) elif sfThread notin v.sym.flags: # do not destroy thread vars for now at all for consistency. - c.destroys.add genDestroy(c, v) + if sfGlobal in v.sym.flags: + c.graph.globalDestructors.add genDestroy(c, v) + else: + c.destroys.add genDestroy(c, v) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c) elif ri.kind != nkEmpty: @@ -616,7 +619,7 @@ proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = # unpacked tuple needs reset at every loop iteration res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) elif {sfGlobal, sfThread} * v.sym.flags == {sfGlobal}: - c.destroys.add genDestroy(c, v) + c.graph.globalDestructors.add genDestroy(c, v) else: # We always translate 'var v = f()' into bitcopies. If 'v' is in a loop, # the destruction at the loop end will free the resources. Other assignments diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim new file mode 100644 index 000000000..9662ecf7f --- /dev/null +++ b/tests/arc/tarcmisc.nim @@ -0,0 +1,29 @@ +discard """ + output: ''' +destroyed: false +destroyed: false +destroying variable''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13691 +type Variable = ref object + value: int + +proc `=destroy`(self: var typeof(Variable()[])) = + echo "destroying variable" + +proc newVariable(value: int): Variable = + result = Variable() + result.value = value + +proc test(count: int) = + var v {.global.} = newVariable(10) + + var count = count - 1 + if count == 0: return + + test(count) + echo "destroyed: ", v.isNil + +test(3) From b3176b881744242b6c0041024a46a17c7b73c788 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 19 Mar 2020 19:38:25 +0000 Subject: [PATCH 0163/4254] Attempt to finish off araq cpp exceptions (#13695) * config update * disable a questionable test * remove c++ exception handling IDs, new impl doesn't require it anymore * C++ based exceptions finally work * fixes bootstrapping problem in C++ mode * teach GCC it's 2020 now * more bugfixes for C++ based exception handling * apply cooldome's patch * another attempt to enable C++11 * bug fix Co-authored-by: Araq Co-authored-by: cooldome --- compiler/ccgstmts.nim | 181 ++++++++++++++++++++++++-- compiler/ccgtypes.nim | 15 ++- compiler/cgen.nim | 5 - compiler/extccomp.nim | 28 +++- compiler/llstream.nim | 2 +- koch.nim | 6 +- lib/system/exceptions.nim | 6 - lib/system/excpt.nim | 32 +---- tests/cpp/tcppraise.nim | 2 +- tests/cpp/tterminate_handler.nim | 3 +- tests/exception/tcpp_imported_exc.nim | 23 ++-- tests/iter/tyieldintry.nim | 4 +- 12 files changed, 233 insertions(+), 74 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 49098959b..c1012cede 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -221,12 +221,11 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - if p.config.exc != excCpp: - # Pop exceptions that was handled by the - # except-blocks we are in - if noSafePoints notin p.flags: - for i in countdown(howManyExcepts-1, 0): - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + # Pop exceptions that was handled by the + # except-blocks we are in + if noSafePoints notin p.flags: + for i in countdown(howManyExcepts-1, 0): + linefmt(p, cpsStmts, "#popCurrentException();$n", []) proc genGotoState(p: BProc, n: PNode) = # we resist the temptation to translate it into duff's device as it later @@ -723,14 +722,16 @@ proc raiseInstr(p: BProc): Rope = result = nil proc genRaiseStmt(p: BProc, t: PNode) = - if p.config.exc == excCpp: - discard cgsym(p.module, "popCurrentExceptionEx") if t[0].kind != nkEmpty: var a: TLoc initLocExprSingleUse(p, t[0], a) finallyActions(p) var e = rdLoc(a) var typ = skipTypes(t[0].typ, abstractPtrs) + # XXX For reasons that currently escape me, this is only required by the new + # C++ based exception handling: + if p.config.exc == excCpp: + blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen) genLineDir(p, t) if isImportedException(typ, p.config): lineF(p, cpsStmts, "throw $1;$n", [e]) @@ -947,6 +948,170 @@ proc genRestoreFrameAfterException(p: BProc) = linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", []) proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = + #[ code to generate: + + std::exception_ptr error = nullptr; + try { + body; + } catch (Exception e) { + error = std::current_exception(); + if (ofExpr(e, TypeHere)) { + + error = nullptr; // handled + } else if (...) { + + } else { + throw; + } + } catch(...) { + // C++ exception occured, not under Nim's control. + } + { + /* finally: */ + printf('fin!\n'); + if (error) std::rethrow_exception(error); // re-raise the exception + } + ]# + p.module.includeHeader("") + + if not isEmptyType(t.typ) and d.k == locNone: + getTemp(p, t.typ, d) + genLineDir(p, t) + + inc(p.labels, 2) + let etmp = p.labels + + lineCg(p, cpsStmts, "std::exception_ptr T$1_ = nullptr;", [etmp]) + + let fin = if t[^1].kind == nkFinally: t[^1] else: nil + p.nestedTryStmts.add((fin, false, 0.Natural)) + + startBlock(p, "try {$n") + expr(p, t[0], d) + endBlock(p) + + # First pass: handle Nim based exceptions: + lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) + genRestoreFrameAfterException(p) + # an unhandled exception happened! + lineCg(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) + p.nestedTryStmts[^1].inExcept = true + var hasImportedCppExceptions = false + var i = 1 + var hasIf = false + var hasElse = false + while (i < t.len) and (t[i].kind == nkExceptBranch): + # bug #4230: avoid false sharing between branches: + if d.k == locTemp and isEmptyType(t.typ): d.k = locNone + if t[i].len == 1: + hasImportedCppExceptions = true + # general except section: + hasElse = true + if hasIf: lineF(p, cpsStmts, "else ", []) + startBlock(p) + # we handled the error: + linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) + expr(p, t[i][0], d) + linefmt(p, cpsStmts, "#popCurrentException();$n", []) + endBlock(p) + else: + var orExpr = Rope(nil) + var exvar = PNode(nil) + for j in 0..$1, $2)", [memberName, checkFor]) + + if orExpr != nil: + if hasIf: + startBlock(p, "else if ($1) {$n", [orExpr]) + else: + startBlock(p, "if ($1) {$n", [orExpr]) + hasIf = true + if exvar != nil: + fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnStack) + linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ), + rdLoc(exvar.sym.loc), rope(etmp+1)]) + # we handled the error: + linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) + expr(p, t[i][^1], d) + linefmt(p, cpsStmts, "#popCurrentException();$n", []) + endBlock(p) + inc(i) + if hasIf and not hasElse: + linefmt(p, cpsStmts, "else throw;$n", [etmp]) + linefmt(p, cpsStmts, "}$n", []) + + # Second pass: handle C++ based exceptions: + template genExceptBranchBody(body: PNode) {.dirty.} = + genRestoreFrameAfterException(p) + #linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) + expr(p, body, d) + + var catchAllPresent = false + incl p.flags, noSafePoints # mark as not needing 'popCurrentException' + if hasImportedCppExceptions: + for i in 1.. 0 and t[^1].kind == nkFinally: + if not catchAllPresent: + startBlock(p, "catch (...) {", []) + genRestoreFrameAfterException(p) + linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) + endBlock(p) + + startBlock(p) + genStmts(p, t[^1][0]) + linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp]) + endBlock(p) + +proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = + # There are two versions we generate, depending on whether we + # catch C++ exceptions, imported via .importcpp or not. The + # code can be easier if there are no imported C++ exceptions + # to deal with. + # code to generate: # # try diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 22e9a5217..926cf2f08 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -609,13 +609,14 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, appcg(m, result, " : public $1 {$n", [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)]) if typ.isException and m.config.exc == excCpp: - appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions - if typ.sym.magic == mException: - # Add cleanup destructor to Exception base class - appcg(m, result, "~$1();$n", [name]) - # define it out of the class body and into the procs section so we don't have to - # artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR) - appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name]) + when false: + appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions + if typ.sym.magic == mException: + # Add cleanup destructor to Exception base class + appcg(m, result, "~$1();$n", [name]) + # define it out of the class body and into the procs section so we don't have to + # artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR) + appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name]) hasField = true else: appcg(m, result, " {$n $1 Sup;$n", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 216f6ba68..66677e458 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -343,11 +343,6 @@ type proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, mode: ObjConstrMode) = - if p.module.compileToCpp and t.isException and p.config.exc == excCpp: - # init vtable in Exception object for polymorphic exceptions - includeHeader(p.module, "") - linefmt(p, section, "new ($1) $2;$n", [rdLoc(a), getTypeDesc(p.module, t)]) - #if optNimV2 in p.config.globalOptions: return case analyseObjectWithTypeField(t) of frNone: diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 5fc532cd8..307be249e 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -48,7 +48,8 @@ type # used on some platforms asmStmtFrmt: string, # format of ASM statement structStmtFmt: string, # Format for struct statement - produceAsm: string, # Format how to produce assembler listings + produceAsm: string, # Format how to produce assembler listings + cppXsupport: string, # what to do to enable C++X support props: TInfoCCProps] # properties of the C compiler @@ -85,6 +86,7 @@ compiler gcc: asmStmtFrmt: "asm($1);$n", structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name produceAsm: gnuAsmListing, + cppXsupport: "-std=gnu++14 -funsigned-char", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, hasAttribute}) @@ -111,6 +113,7 @@ compiler nintendoSwitchGCC: asmStmtFrmt: "asm($1);$n", structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name produceAsm: gnuAsmListing, + cppXsupport: "-std=gnu++14 -funsigned-char", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, hasAttribute}) @@ -158,6 +161,7 @@ compiler vcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", produceAsm: "/Fa$asmfile", + cppXsupport: "", props: {hasCpp, hasAssume, hasDeclspec}) compiler clangcl: @@ -204,6 +208,7 @@ compiler lcc: asmStmtFrmt: "_asm{$n$1$n}$n", structStmtFmt: "$1 $2", produceAsm: "", + cppXsupport: "", props: {}) # Borland C Compiler @@ -229,6 +234,7 @@ compiler bcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", produceAsm: "", + cppXsupport: "", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasAttribute}) @@ -255,6 +261,7 @@ compiler dmc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", produceAsm: "", + cppXsupport: "", props: {hasCpp}) # Watcom C Compiler @@ -280,6 +287,7 @@ compiler wcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", produceAsm: "", + cppXsupport: "", props: {hasCpp}) # Tiny C Compiler @@ -305,6 +313,7 @@ compiler tcc: asmStmtFrmt: "asm($1);$n", structStmtFmt: "$1 $2", produceAsm: gnuAsmListing, + cppXsupport: "", props: {hasSwitchRange, hasComputedGoto, hasGnuAsm}) # Pelles C Compiler @@ -331,6 +340,7 @@ compiler pcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", produceAsm: "", + cppXsupport: "", props: {}) # Your C Compiler @@ -356,6 +366,7 @@ compiler ucc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", produceAsm: "", + cppXsupport: "", props: {}) const @@ -389,8 +400,10 @@ proc nameToCC*(name: string): TSystemCC = return i result = ccNone -proc listCCnames(): seq[string] = +proc listCCnames(): string = + result = "" for i in succ(ccNone)..high(TSystemCC): + if i > succ(ccNone): result.add ", " result.add CC[i].name proc isVSCompatible*(conf: ConfigRef): bool = @@ -426,8 +439,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) = conf.cCompiler = nameToCC(ccname) if conf.cCompiler == ccNone: - let ccList = listCCnames().join(", ") - localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, ccList]) + localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, listCCnames()]) conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always") conf.linkOptions = "" conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path") @@ -576,8 +588,11 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} = result = (optGenScript in conf.globalOptions and conf.target.targetOS == osWindows) or (conf.target.hostOS == osWindows) +proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool = + conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c") + proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string = - result = if conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c"): + result = if useCpp(conf, cfile): CC[compiler].cppCompiler else: CC[compiler].compilerExe @@ -605,6 +620,9 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, ospNeedsPIC in platform.OS[conf.target.targetOS].props: options.add(' ' & CC[c].pic) + if useCpp(conf, cfile.cname): + options.add(' ' & CC[c].cppXsupport) + var compilePattern: string # compute include paths: var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 4d9456ff0..6df927c60 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -69,7 +69,7 @@ proc llStreamClose*(s: PLLStream) = of llsFile: close(s.f) -when not hasRstdin: +when not declared(readLineFromStdin): # fallback implementation: proc readLineFromStdin(prompt: string, line: var string): bool = stderr.write(prompt) diff --git a/koch.nim b/koch.nim index 60d0e3544..dc23488a7 100644 --- a/koch.nim +++ b/koch.nim @@ -296,7 +296,11 @@ proc boot(args: string) = let nimStart = findStartNim().quoteShell() for i in 0..2: - let defaultCommand = if useCpp: "cpp" else: "c" + # Nim versions < (1, 1) expect Nim's exception type to have a 'raiseId' field for + # C++ interop. Later Nim versions do this differently and removed the 'raiseId' field. + # Thus we always bootstrap the first iteration with "c" and not with "cpp" as + # a workaround. + let defaultCommand = if useCpp and i > 0: "cpp" else: "c" let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: "" echo "iteration: ", i+1 var extraOption = "" diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index f575f9b9f..3979fb66e 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -33,12 +33,6 @@ type trace: string else: trace: seq[StackTraceEntry] - when defined(nimBoostrapCsources0_19_0): - # see #10315, bootstrap with `nim cpp` from csources gave error: - # error: no member named 'raise_id' in 'Exception' - raise_id: uint # set when exception is raised - else: - raiseId: uint # set when exception is raised up: ref Exception # used for stacking exceptions. Not exported! Defect* = object of Exception ## \ diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 8337e0351..8ac47d26b 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -61,10 +61,6 @@ var currException {.threadvar.}: ref Exception gcFramePtr {.threadvar.}: GcFrame -when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions: - var - raiseCounter {.threadvar.}: uint - type FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame, excHandler: PSafePoint, currException: ref Exception] @@ -123,19 +119,7 @@ proc popCurrentException {.compilerRtl, inl.} = #showErrorMessage "B" proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = - # in cpp backend exceptions can pop-up in the different order they were raised, example #5628 - if currException.raiseId == id: - currException = currException.up - else: - var cur = currException.up - var prev = currException - while cur != nil and cur.raiseId != id: - prev = cur - cur = cur.up - if cur == nil: - showErrorMessage("popCurrentExceptionEx() exception was not found in the exception stack. Aborting...") - quit(1) - prev.up = cur.up + discard "only for bootstrapping compatbility" proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = currException = e @@ -444,11 +428,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = {.emit: "throw;".} else: pushCurrentException(e) - raiseCounter.inc - if raiseCounter == 0: - raiseCounter.inc # skip zero at overflow - e.raiseId = raiseCounter - {.emit: "`e`->raise();".} + {.emit: "throw e;".} elif defined(nimQuirky) or gotoBasedExceptions: # XXX This check should likely also be done in the setjmp case below. if e != currException: @@ -562,9 +542,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and var msg = "Unknown error in unexpected exception handler" try: - {.emit"#if !defined(_MSC_VER) || (_MSC_VER >= 1923)".} + {.emit: "#if !defined(_MSC_VER) || (_MSC_VER >= 1923)".} raise - {.emit"#endif".} + {.emit: "#endif".} except Exception: msg = currException.getStackTrace() & "Error: unhandled exception: " & currException.msg & " [" & $currException.name & "]" @@ -573,9 +553,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and except: msg = "Error: unhandled unknown cpp exception" - {.emit"#if defined(_MSC_VER) && (_MSC_VER < 1923)".} + {.emit: "#if defined(_MSC_VER) && (_MSC_VER < 1923)".} msg = "Error: unhandled unknown cpp exception" - {.emit"#endif".} + {.emit: "#endif".} when defined(genode): # stderr not available by default, use the LOG session diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim index 8f34cb3e4..f03956d4c 100644 --- a/tests/cpp/tcppraise.nim +++ b/tests/cpp/tcppraise.nim @@ -68,4 +68,4 @@ except: echo getCurrentExceptionMsg() discard -doAssert: getCurrentException() == nil \ No newline at end of file +doAssert: getCurrentException() == nil diff --git a/tests/cpp/tterminate_handler.nim b/tests/cpp/tterminate_handler.nim index 79949f4da..c5ccef53c 100644 --- a/tests/cpp/tterminate_handler.nim +++ b/tests/cpp/tterminate_handler.nim @@ -2,8 +2,9 @@ discard """ targets: "cpp" outputsub: "Error: unhandled unknown cpp exception" exitcode: 1 + disabled: true """ type Crap {.importcpp: "int".} = object var c: Crap -raise c \ No newline at end of file +raise c diff --git a/tests/exception/tcpp_imported_exc.nim b/tests/exception/tcpp_imported_exc.nim index c8349f7d5..8b96ca635 100644 --- a/tests/exception/tcpp_imported_exc.nim +++ b/tests/exception/tcpp_imported_exc.nim @@ -14,7 +14,7 @@ cpp exception caught ''' """ -type +type std_exception* {.importcpp: "std::exception", header: "".} = object std_runtime_error* {.importcpp: "std::runtime_error", header: "".} = object std_string* {.importcpp: "std::string", header: "".} = object @@ -25,7 +25,7 @@ proc constructRuntimeError(s: stdstring): std_runtime_error {.importcpp: "std::r proc what(ex: std_runtime_error): cstring {.importcpp: "((char *)#.what())".} -proc myexception = +proc myexception = raise constructRuntimeError(constructStdString("cpp_exception")) try: @@ -41,17 +41,17 @@ except std_exception: doAssert(getCurrentException() == nil) -proc earlyReturn = +proc earlyReturn = try: try: - myexception() + myexception() finally: echo "finally1" except: return finally: echo "finally2" - + earlyReturn() doAssert(getCurrentException() == nil) @@ -118,16 +118,15 @@ try: echo "finally 2" except: echo "expected" - - + doAssert(getCurrentException() == nil) try: - try: - myexception() - except std_runtime_error as ex: - echo "cpp exception caught" - raise newException(ValueError, "rewritten " & $ex.what()) + try: + myexception() + except std_runtime_error as ex: + echo "cpp exception caught" + raise newException(ValueError, "rewritten " & $ex.what()) except: doAssert(getCurrentExceptionMsg() == "rewritten cpp_exception") diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 62c16c741..35df55c24 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -1,9 +1,11 @@ discard """ -targets: "c cpp" +targets: "c" output: "ok" """ var closureIterResult = newSeq[int]() +# XXX Investigate why this fails now for 'nim cpp' + proc checkpoint(arg: int) = closureIterResult.add(arg) From 705e283fef845a7dd78a2f0e241b1ad0f05490d3 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 19 Mar 2020 16:40:52 -0300 Subject: [PATCH 0164/4254] Clean 1 old deprecated empty file (#13696) --- compiler/configuration.nim | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 compiler/configuration.nim diff --git a/compiler/configuration.nim b/compiler/configuration.nim deleted file mode 100644 index 22e0b834e..000000000 --- a/compiler/configuration.nim +++ /dev/null @@ -1,6 +0,0 @@ -## Use the module 'lineinfos' instead! - -{.deprecated.} - -import lineinfos -export lineinfos From 35fb38629f2f56d15afea15ba8597f18e2794229 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Mar 2020 22:58:16 +0100 Subject: [PATCH 0165/4254] cycle breaker (#13593) * cycle breaking as an alternative to cycle detection --- compiler/ccgexprs.nim | 40 +++--- compiler/ccgtypes.nim | 5 + compiler/liftdestructors.nim | 7 +- compiler/lineinfos.nim | 2 +- compiler/sempass2.nim | 10 +- lib/pure/asyncfutures.nim | 2 +- lib/system/cyclebreaker.nim | 227 +++++++++++++++++++++++++++++++++++ lib/system/cyclicrefs_v2.nim | 18 +-- lib/system/refs_v2.nim | 9 +- tests/arc/tasyncawait.nim | 19 +-- 10 files changed, 298 insertions(+), 41 deletions(-) create mode 100644 lib/system/cyclebreaker.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4cf6f36db..2d1005f5e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1606,10 +1606,33 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = a.storage) gcUsage(p.config, e) +proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = + result = rdLoc(a) + var t = skipTypes(a.t, abstractInst) + while t.kind in {tyVar, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyLent}: nilCheck = result + if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: + result = "(*$1)" % [result] + t = skipTypes(t.lastSon, abstractInst) + discard getTypeDesc(p.module, t) + if not p.module.compileToCpp: + while t.kind == tyObject and t[0] != nil: + result.add(".Sup") + t = skipTypes(t[0], skipPtrs) + result.add ".m_type" + proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = discard cgsym(p.module, "TNimType") let t = e[1].typ - putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info)) + if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo": + # ordinary static type information + putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info)) + else: + var a: TLoc + initLocExpr(p, e[1], a) + var nilCheck = Rope(nil) + # use the dynamic type stored at offset 0: + putIntoDest(p, d, e, rdMType(p, a, nilCheck)) template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = var a: TLoc @@ -2113,21 +2136,6 @@ proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) = n[0] = newSymNode(toStrProc) expr(p, n, d) -proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = - result = rdLoc(a) - var t = skipTypes(a.t, abstractInst) - while t.kind in {tyVar, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyLent}: nilCheck = result - if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: - result = "(*$1)" % [result] - t = skipTypes(t.lastSon, abstractInst) - discard getTypeDesc(p.module, t) - if not p.module.compileToCpp: - while t.kind == tyObject and t[0] != nil: - result.add(".Sup") - t = skipTypes(t[0], skipPtrs) - result.add ".m_type" - proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = case op of mOr, mAnd: genAndOr(p, e, d, op) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 926cf2f08..dbdd0a6c7 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1291,6 +1291,11 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = genProc(m, theProc) result = theProc.loc.r else: + if op == attachedTrace and m.config.selectedGC == gcOrc and + containsGarbageCollectedRef(t): + when false: + # re-enable this check + internalError(m.config, info, "no attached trace proc found") result = rope("NIM_NIL") proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 377ba149a..9a91ec2e9 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -484,10 +484,10 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if isFinal(elemType): let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) - body.add callCodegenProc(c.g, "nimTraceRef", c.info, x, typInfo, y) + body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y) else: # If the ref is polymorphic we have to account for this - body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, x, y) + body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x), y) of attachedDispose: # this is crucial! dispose is like =destroy but we don't follow refs # as that is dealt within the cycle collector. @@ -530,7 +530,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, cond, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: - body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, xenv, y) + body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv), y) of attachedDispose: # this is crucial! dispose is like =destroy but we don't follow refs # as that is dealt within the cycle collector. @@ -778,7 +778,6 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; # register this operation already: typ.attachedOps[kind] = result - if kind == attachedSink and typ.attachedOps[attachedDestructor] != nil and sfOverriden in typ.attachedOps[attachedDestructor].flags: ## compiler can use a combination of `=destroy` and memCopy for sink op diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 680b193f9..f7f3b7706 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -36,7 +36,7 @@ type warnUnusedImportX, warnInheritFromException, warnEachIdentIsTuple, - warnProveInit, warnProveField, warnProveIndex, + warnProveInit, warnProveField, warnProveIndex, warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser, diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 5d4ad658c..d5514d8d1 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -696,8 +696,16 @@ proc checkRange(c: PEffects; value: PNode; typ: PType) = checkLe(c, value, highBound) proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = + if typ == nil: return + let realType = typ.skipTypes(abstractInst) + when false: + # XXX fix this in liftdestructors instead + if realType.kind == tyRef and + optSeqDestructors in tracked.config.globalOptions: + createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info) + createTypeBoundOps(tracked.graph, tracked.c, typ, info) - if (typ != nil and tfHasAsgn in typ.flags) or + if (tfHasAsgn in typ.flags) or optSeqDestructors in tracked.config.globalOptions: tracked.owner.flags.incl sfInjectDestructors diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 7aac192d2..236a829e3 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -382,7 +382,7 @@ proc read*[T](future: Future[T] | FutureVar[T]): T = injectStacktrace(fut) raise fut.error when T isnot void: - return fut.value + result = fut.value else: # TODO: Make a custom exception type for this? raise newException(ValueError, "Future still in progress.") diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim new file mode 100644 index 000000000..e036acb53 --- /dev/null +++ b/lib/system/cyclebreaker.nim @@ -0,0 +1,227 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +#[ +A Cycle breaker for Nim +----------------------- + +Instead of "collecting" cycles with all of its pitfalls we will break cycles. +We exploit that every 'ref' can be 'nil' for this and so get away without +a distinction between weak and strong pointers. The required runtime +mechanisms are the same though: We need to be able to traverse the graph. +This design has the tremendous benefit that it doesn't require a dedicated +'rawDispose' operation and that it plays well with Nim's cost model. +The cost of freeing a subgraph with cycles is 2 * N rather than N, that's all. + +Cycles do not have to be prepared via .acyclic, there are not multiple +pointless traversals, only a single proc, `breakCycles` is exposed as a +separate module. + +Algorithm +--------- + +We traverse the graph and notice the nodes we've already traversed. If we +marked the node already, we set the pointer that leads to this node to 'nil' +and decrement the reference count of the cell we pointed at. + +We notice that multiple paths to the same object do not mean +we found a cycle, it only means the node is shared. + + + a -------> b <----- c + | ^ ^ + +----------+ | + | | + +-------------------+ + +If we simply remove all links to already processed nodes we end up with: + + a -------> b c + | ^ + + | + | | + +-------------------+ + +That seems acceptable, no leak is produced. This implies that the standard +depth-first traversal suffices. + +]# +const + colGreen = 0b000 + colYellow = 0b001 + colRed = 0b010 + rcShift = 3 # shift by rcShift to get the reference counter + colorMask = 0b011 + +type + TraceProc = proc (p, env: pointer) {.nimcall, benign.} + DisposeProc = proc (p: pointer) {.nimcall, benign.} + +template color(c): untyped = c.rc and colorMask +template setColor(c, col) = + c.rc = c.rc and not colorMask or col + +proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = + let h = head(p) + inc h.rc, rcIncrement + +type + CellTuple = (ptr pointer, PNimType) + CellArray = ptr UncheckedArray[CellTuple] + CellSeq = object + len, cap: int + d: CellArray + + GcEnv = object + traceStack: CellSeq + +# ------------------- cell seq handling -------------------------------------- + +proc add(s: var CellSeq, c: ptr pointer; t: PNimType) {.inline.} = + if s.len >= s.cap: + s.cap = s.cap * 3 div 2 + when defined(useMalloc): + var d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + else: + var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + copyMem(d, s.d, s.len * sizeof(CellTuple)) + when defined(useMalloc): + c_free(s.d) + else: + dealloc(s.d) + s.d = d + # XXX: realloc? + s.d[s.len] = (c, t) + inc(s.len) + +proc init(s: var CellSeq, cap: int = 1024) = + s.len = 0 + s.cap = cap + when defined(useMalloc): + s.d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + else: + s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + +proc deinit(s: var CellSeq) = + when defined(useMalloc): + c_free(s.d) + else: + dealloc(s.d) + s.d = nil + s.len = 0 + s.cap = 0 + +proc pop(s: var CellSeq): (ptr pointer, PNimType) = + result = s.d[s.len-1] + dec s.len + +# ---------------------------------------------------------------------------- + +proc trace(p: pointer; desc: PNimType; j: var GcEnv) {.inline.} = + when false: + cprintf("[Trace] desc: %p %p\n", desc, p) + cprintf("[Trace] trace: %p\n", desc.traceImpl) + if desc.traceImpl != nil: + cast[TraceProc](desc.traceImpl)(p, addr(j)) + +proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = + let p = cast[ptr pointer](q) + when traceCollector: + cprintf("[Trace] raw: %p\n", p) + cprintf("[Trace] deref: %p\n", p[]) + if p[] != nil: + var j = cast[ptr GcEnv](env) + j.traceStack.add(p, desc) + +proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = + let p = cast[ptr pointer](q) + when traceCollector: + cprintf("[TraceDyn] raw: %p\n", p) + cprintf("[TraceDyn] deref: %p\n", p[]) + if p[] != nil: + var j = cast[ptr GcEnv](env) + j.traceStack.add(p, cast[ptr PNimType](p[])[]) + +var markerGeneration: int + +proc breakCycles(s: Cell; desc: PNimType) = + let markerColor = if (markerGeneration and 1) == 0: colRed + else: colYellow + atomicInc markerGeneration + when traceCollector: + cprintf("[BreakCycles] starting: %p %s RC %ld trace proc %p\n", + s, desc.name, s.rc shr rcShift, desc.traceImpl) + + var j: GcEnv + init j.traceStack + s.setColor markerColor + trace(s +! sizeof(RefHeader), desc, j) + + while j.traceStack.len > 0: + let (u, desc) = j.traceStack.pop() + let p = u[] + let t = head(p) + if t.color != markerColor: + t.setColor markerColor + trace(p, desc, j) + when traceCollector: + cprintf("[BreakCycles] followed: %p RC %ld\n", t, t.rc shr rcShift) + else: + if (t.rc shr rcShift) > 0: + dec t.rc, rcIncrement + # mark as a link that the produced destructor does not have to follow: + u[] = nil + when traceCollector: + cprintf("[BreakCycles] niled out: %p RC %ld\n", t, t.rc shr rcShift) + else: + # anyhow as a link that the produced destructor does not have to follow: + u[] = nil + cprintf("[Bug] %p %s RC %ld\n", t, desc.name, t.rc shr rcShift) + deinit j.traceStack + +proc thinout*[T](x: ref T) {.inline.} = + ## turn the subgraph starting with `x` into its spanning tree by + ## `nil`'ing out any pointers that would harm the spanning tree + ## structure. Any back pointers that introduced cycles + ## and thus would keep the graph from being freed are `nil`'ed. + ## This is a form of cycle collection that works well with Nim's ARC + ## and its associated cost model. + proc getDynamicTypeInfo[T](x: T): PNimType {.magic: "GetTypeInfo", noSideEffect, locks: 0.} + + breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[])) + +proc thinout*[T: proc](x: T) {.inline.} = + proc rawEnv[T: proc](x: T): pointer {.noSideEffect, inline.} = + {.emit: """ + `result` = `x`.ClE_0; + """.} + + let p = rawEnv(x) + breakCycles(head(p), cast[ptr PNimType](p)[]) + +proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = + if p != nil: + var cell = head(p) + if (cell.rc and not rcMask) == 0: + result = true + #cprintf("[DESTROY] %p\n", p) + else: + dec cell.rc, rcIncrement + # According to Lins it's correct to do nothing else here. + #cprintf("[DeCREF] %p\n", p) + +proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = + if p != nil: + var cell = head(p) + if (cell.rc and not rcMask) == 0: + result = true + #cprintf("[DESTROY] %p %s\n", p, desc.name) + else: + dec cell.rc, rcIncrement + #cprintf("[DeCREF] %p %s %ld\n", p, desc.name, cell.rc) diff --git a/lib/system/cyclicrefs_v2.nim b/lib/system/cyclicrefs_v2.nim index 4fbb4fc94..0dd669925 100644 --- a/lib/system/cyclicrefs_v2.nim +++ b/lib/system/cyclicrefs_v2.nim @@ -43,6 +43,7 @@ proc markCyclic*[T](x: ref T) {.inline.} = ## Experimental API. Do not use! let h = head(cast[pointer](x)) h.setColor colYellow + type CellTuple = (Cell, PNimType) CellArray = ptr UncheckedArray[CellTuple] @@ -153,18 +154,19 @@ proc scanGreen(s: Cell; desc: PNimType; j: var GcEnv) = when traceCollector: cprintf("[Cycle inc] %p %ld color %ld\n", t, t.rc shr rcShift, t.color) -proc nimTraceRef(p: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = - if p != nil: - var t = head(p) +proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = + let p = cast[ptr pointer](q) + if p[] != nil: var j = cast[ptr GcEnv](env) + var t = head(p[]) j.traceStack.add(t, desc) -proc nimTraceRefDyn(p: pointer; env: pointer) {.compilerRtl.} = - if p != nil: - let desc = cast[ptr PNimType](p)[] - var t = head(p) +proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = + let p = cast[ptr pointer](q) + if p[] != nil: var j = cast[ptr GcEnv](env) - j.traceStack.add(t, desc) + var t = head(p[]) + j.traceStack.add(t, cast[ptr PNimType](p[])[]) proc scan(s: Cell; desc: PNimType; j: var GcEnv) = when traceCollector: diff --git a/lib/system/refs_v2.nim b/lib/system/refs_v2.nim index f6f3ba01c..9527db1e3 100644 --- a/lib/system/refs_v2.nim +++ b/lib/system/refs_v2.nim @@ -70,7 +70,7 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = else: result = alloc0(s) +! sizeof(RefHeader) when traceCollector: - cprintf("[Allocated] %p\n", result -! sizeof(RefHeader)) + cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = # Same as 'newNewObj' but do not initialize the memory to zero. @@ -87,7 +87,7 @@ proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = orig.rc = 0 result = orig +! sizeof(RefHeader) when traceCollector: - cprintf("[Allocated] %p\n", result -! sizeof(RefHeader)) + cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = dec head(p).rc, rcIncrement @@ -128,7 +128,10 @@ proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = nimRawDispose(p) when defined(gcOrc): - include cyclicrefs_v2 + when defined(nimThinout): + include cyclebreaker + else: + include cyclicrefs_v2 proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = if p != nil: diff --git a/tests/arc/tasyncawait.nim b/tests/arc/tasyncawait.nim index 89e924104..6b5b301a6 100644 --- a/tests/arc/tasyncawait.nim +++ b/tests/arc/tasyncawait.nim @@ -1,5 +1,5 @@ discard """ - output: "5000" + outputsub: "result: 5000" cmd: "nim c --gc:arc $file" """ @@ -59,11 +59,16 @@ proc createServer(port: Port) {.async.} = while true: asyncCheck readMessages(await accept(server)) -asyncCheck createServer(Port(10335)) -asyncCheck launchSwarm(Port(10335)) -while true: - poll() - if clientCount == swarmSize: break +proc main = + asyncCheck createServer(Port(10335)) + asyncCheck launchSwarm(Port(10335)) + while true: + poll() + if clientCount == swarmSize: break + +let mem = getOccupiedMem() +main() assert msgCount == swarmSize * messagesToSend -echo msgCount +echo "result: ", msgCount +echo "memory: ", formatSize(getOccupiedMem() - mem) From 28b6b1c3fbe218013ef2db2861b6f5b20641c381 Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Fri, 20 Mar 2020 01:22:40 -0700 Subject: [PATCH 0166/4254] fix nimpretty warning (#13700) --- nimpretty/nimpretty.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index 50d0d725f..cca4e7aa8 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -67,8 +67,7 @@ proc main = # `prettyPrint` could over-write it (note that the backup may happen even # if input is not actually over-written, when nimpretty is a noop). # --backup was un-documented (rely on git instead). - var opt: PrettyOptions - opt.maxLineLen = 80 + var opt = PrettyOptions(indWidth: 0, maxLineLen: 80) for kind, key, val in getopt(): case kind of cmdArgument: From 1037318e6817157e97d368a01852b021d7c3c9b7 Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Fri, 20 Mar 2020 01:24:04 -0700 Subject: [PATCH 0167/4254] fix nimsuggest warning (#13699) --- nimsuggest/crashtester.nim | 2 +- nimsuggest/nimsuggest.nim | 3 --- nimsuggest/tester.nim | 6 +++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/nimsuggest/crashtester.nim b/nimsuggest/crashtester.nim index 10fef2b23..ead97adec 100644 --- a/nimsuggest/crashtester.nim +++ b/nimsuggest/crashtester.nim @@ -32,7 +32,7 @@ proc callNimsuggest() = if a == DummyEof: break var line = 0 - for i in 0..< contents.len: + for i in 0 ..< contents.len: let slic = contents[0..i] writeFile("temp000.nim", slic) let (line, col) = getPosition(slic) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index a48e9443d..56646db35 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -97,9 +97,6 @@ const "type 'debug' to toggle debug mode on/off\n" & "type 'terse' to toggle terse mode on/off" -type - EUnexpectedCommand = object of Exception - proc parseQuoted(cmd: string; outp: var string; start: int): int = var i = start i += skipWhitespace(cmd, i) diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index d0870347e..019181810 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -206,13 +206,13 @@ proc sexpToAnswer(s: SexpNode): string = result.add '\t' result.add file result.add '\t' - result.add line + result.addInt line result.add '\t' - result.add col + result.addInt col result.add '\t' result.add doc result.add '\t' - result.add a[8].getNum + result.addInt a[8].getNum if a.len >= 10: result.add '\t' result.add a[9].getStr From 55d3780b7bef2a171ee2a2e4ff856e5f91335b47 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 20 Mar 2020 05:24:35 -0300 Subject: [PATCH 0168/4254] Remove 2 old deprecated files (#13702) --- lib/impure/osinfo_posix.nim | 10 ---------- lib/impure/osinfo_win.nim | 10 ---------- tools/kochdocs.nim | 4 +--- 3 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 lib/impure/osinfo_posix.nim delete mode 100644 lib/impure/osinfo_win.nim diff --git a/lib/impure/osinfo_posix.nim b/lib/impure/osinfo_posix.nim deleted file mode 100644 index 0362fca12..000000000 --- a/lib/impure/osinfo_posix.nim +++ /dev/null @@ -1,10 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Dominik Picheta -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -{.error: "This module has been moved to the 'osinfo' nimble package.".} diff --git a/lib/impure/osinfo_win.nim b/lib/impure/osinfo_win.nim deleted file mode 100644 index 0362fca12..000000000 --- a/lib/impure/osinfo_win.nim +++ /dev/null @@ -1,10 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Dominik Picheta -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -{.error: "This module has been moved to the 'osinfo' nimble package.".} diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 87cdf53aa..0dd6dbc2f 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -149,13 +149,11 @@ lib/posix/linux.nim lib/posix/termios.nim lib/js/jscore.nim """.splitWhitespace() - + # some of these are include files so shouldn't be docgen'd ignoredModules = """ lib/prelude.nim lib/pure/future.nim -lib/impure/osinfo_posix.nim -lib/impure/osinfo_win.nim lib/pure/collections/hashcommon.nim lib/pure/collections/tableimpl.nim lib/pure/collections/setimpl.nim From dd362ab4c0f574f781fb450b479d9dda8ced1e63 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 20 Mar 2020 01:28:03 -0700 Subject: [PATCH 0169/4254] fix #13538 sigmatch errors are now sorted (#13701) * fix #13538 sigmatch now sorted and has reliable order * re-enable tests that were disabled because of that bug * fix remaining tests and un-disable 2 other tests that were affected by this bug --- compiler/semcall.nim | 7 ++++ tests/concepts/t3330.nim | 42 +++++++++++----------- tests/concepts/texplain.nim | 28 +++++++-------- tests/errmsgs/tsigmatch.nim | 14 ++++---- tests/errmsgs/tsigmatch2.nim | 8 ++--- tests/errmsgs/tunknown_named_parameter.nim | 10 +++--- 6 files changed, 58 insertions(+), 51 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c0227db19..55ff80b6c 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -10,6 +10,8 @@ ## This module implements semantic checking for calls. # included from sem.nim +from algorithm import sort + proc sameMethodDispatcher(a, b: PSym): bool = result = false if a.kind == skMethod and b.kind == skMethod: @@ -178,9 +180,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): var maybeWrongSpace = false + var candidatesAll: seq[string] var candidates = "" var skipped = 0 for err in errors: + candidates.setLen 0 if filterOnlyFirst and err.firstMismatch.arg == 1: inc skipped continue @@ -225,6 +229,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): maybeWrongSpace = true for diag in err.diagnostics: candidates.add(diag & "\n") + candidatesAll.add candidates + candidatesAll.sort # fix #13538 + candidates = join(candidatesAll) if skipped > 0: candidates.add($skipped & " other mismatching symbols have been " & "suppressed; compile with --showAllMismatches:on to see them\n") diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index 067e81133..9de71f3ac 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -1,6 +1,5 @@ discard """ errormsg: "type mismatch: got " -disabled: "32bit" nimout: ''' t3330.nim(78, 4) Error: type mismatch: got but expected one of: @@ -9,33 +8,33 @@ proc test(foo: Foo[int]) required type for foo: Foo[int] but expression 'bar' is of type: Bar[system.int] t3330.nim(63, 8) Hint: Non-matching candidates for add(k, string, T) -proc add(x: var string; y: string) - first type mismatch at position: 1 - required type for x: var string - but expression 'k' is of type: Alias -proc add[T](x: var seq[T]; y: openArray[T]) - first type mismatch at position: 1 - required type for x: var seq[T] - but expression 'k' is of type: Alias proc add(result: var string; x: float) first type mismatch at position: 1 required type for result: var string but expression 'k' is of type: Alias -proc add[T](x: var seq[T]; y: T) +proc add(result: var string; x: int64) first type mismatch at position: 1 - required type for x: var seq[T] - but expression 'k' is of type: Alias -proc add(x: var string; y: cstring) - first type mismatch at position: 1 - required type for x: var string + required type for result: var string but expression 'k' is of type: Alias proc add(x: var string; y: char) first type mismatch at position: 1 required type for x: var string but expression 'k' is of type: Alias -proc add(result: var string; x: int64) +proc add(x: var string; y: cstring) first type mismatch at position: 1 - required type for result: var string + required type for x: var string + but expression 'k' is of type: Alias +proc add(x: var string; y: string) + first type mismatch at position: 1 + required type for x: var string + but expression 'k' is of type: Alias +proc add[T](x: var seq[T]; y: T) + first type mismatch at position: 1 + required type for x: var seq[T] + but expression 'k' is of type: Alias +proc add[T](x: var seq[T]; y: openArray[T]) + first type mismatch at position: 1 + required type for x: var seq[T] but expression 'k' is of type: Alias t3330.nim(63, 8) template/generic instantiation of `add` from here @@ -46,10 +45,11 @@ t3330.nim(71, 6) Foo: 'bar.x' cannot be assigned to expression: test(bar)''' """ -# Note: currently disabled on 32bit because the candidates are presented in -# different order on travis with `NIM_COMPILE_TO_CPP=false CPU=i386`; -# a possible fix would be to sort the candidates by proc signature or -# declaration location + + + + + diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim index 2b19c8b4d..344b6d53f 100644 --- a/tests/concepts/texplain.nim +++ b/tests/concepts/texplain.nim @@ -37,20 +37,24 @@ texplain.nim(124, 5) ExplainedConcept: concept predicate failed texplain.nim(168, 20) Error: type mismatch: got but expected one of: +proc e(i: int): int + first type mismatch at position: 1 + required type for i: int + but expression 'n' is of type: NonMatchingType proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression 'n' is of type: NonMatchingType texplain.nim(168, 9) template/generic instantiation of `assert` from here texplain.nim(124, 5) ExplainedConcept: concept predicate failed -proc e(i: int): int - first type mismatch at position: 1 - required type for i: int - but expression 'n' is of type: NonMatchingType expression: e(n) texplain.nim(169, 20) Error: type mismatch: got but expected one of: +proc r(i: string): int + first type mismatch at position: 1 + required type for i: string + but expression 'n' is of type: NonMatchingType proc r(o: RegularConcept): int first type mismatch at position: 1 required type for o: RegularConcept @@ -61,21 +65,17 @@ proc r[T](a: SomeNumber; b: T; c: auto) first type mismatch at position: 1 required type for a: SomeNumber but expression 'n' is of type: NonMatchingType -proc r(i: string): int - first type mismatch at position: 1 - required type for i: string - but expression 'n' is of type: NonMatchingType expression: r(n) texplain.nim(170, 20) Hint: Non-matching candidates for r(y) -proc r[T](a: SomeNumber; b: T; c: auto) - first type mismatch at position: 1 - required type for a: SomeNumber - but expression 'y' is of type: MatchingType proc r(i: string): int first type mismatch at position: 1 required type for i: string but expression 'y' is of type: MatchingType +proc r[T](a: SomeNumber; b: T; c: auto) + first type mismatch at position: 1 + required type for a: SomeNumber + but expression 'y' is of type: MatchingType texplain.nim(178, 2) Error: type mismatch: got but expected one of: @@ -97,10 +97,10 @@ expression: f(y)''' errormsg: "type mismatch: got " line: 178 - disabled: 32bit """ -# disabled on 32 bit, because the order of suggested alternatives ``r`` differs + + # proc r[T](a: SomeNumber; b: T; c: auto) # proc r(i: string): int # proc r(o: RegularConcept): int diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim index 6b85d1408..414c972c9 100644 --- a/tests/errmsgs/tsigmatch.nim +++ b/tests/errmsgs/tsigmatch.nim @@ -3,13 +3,13 @@ discard """ nimout: ''' tsigmatch.nim(111, 4) Error: type mismatch: got but expected one of: +proc f(a: A) + first type mismatch at position: 2 + extra argument given proc f(b: B) first type mismatch at position: 1 required type for b: B but expression 'A()' is of type: A -proc f(a: A) - first type mismatch at position: 2 - extra argument given expression: f(A(), "extra") tsigmatch.nim(125, 6) Error: type mismatch: got @@ -61,14 +61,14 @@ proc f(a1: string; a2: varargs[string]; a3: float; a4: var string) expression: f("asdf", "1", "2", "3", "4", 2.3, "bad") tsigmatch.nim(164, 4) Error: type mismatch: got but expected one of: -proc f(x: string; a0: var int) - first type mismatch at position: 2 - required type for a0: var int - but expression 'a0 = 12' is immutable, not 'var' proc f(x: string; a0: string) first type mismatch at position: 2 required type for a0: string but expression 'a0 = 12' is of type: int literal(12) +proc f(x: string; a0: var int) + first type mismatch at position: 2 + required type for a0: var int + but expression 'a0 = 12' is immutable, not 'var' expression: f(foo, a0 = 12) tsigmatch.nim(171, 7) Error: type mismatch: got diff --git a/tests/errmsgs/tsigmatch2.nim b/tests/errmsgs/tsigmatch2.nim index 4e95d3e1b..580743f3e 100644 --- a/tests/errmsgs/tsigmatch2.nim +++ b/tests/errmsgs/tsigmatch2.nim @@ -3,14 +3,14 @@ discard """ nimout: ''' tsigmatch2.nim(40, 14) Error: type mismatch: got but expected one of: -proc foo(i: Foo): string - first type mismatch at position: 1 - required type for i: Foo - but expression '1.2' is of type: float64 proc foo(args: varargs[string, myproc]): string first type mismatch at position: 1 required type for args: varargs[string] but expression '1.2' is of type: float64 +proc foo(i: Foo): string + first type mismatch at position: 1 + required type for i: Foo + but expression '1.2' is of type: float64 expression: foo(1.2) tsigmatch2.nim(46, 7) Error: type mismatch: got diff --git a/tests/errmsgs/tunknown_named_parameter.nim b/tests/errmsgs/tunknown_named_parameter.nim index e9be23068..b139310db 100644 --- a/tests/errmsgs/tunknown_named_parameter.nim +++ b/tests/errmsgs/tunknown_named_parameter.nim @@ -6,22 +6,22 @@ proc rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: char but expression '{':'}' is of type: set[char] -proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[string] - first type mismatch at position: 3 - unknown named parameter: maxsplits proc rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: string but expression '{':'}' is of type: set[char] +proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[string] + first type mismatch at position: 3 + unknown named parameter: maxsplits expression: rsplit("abc:def", {':'}, maxsplits = 1) ''' -disabled: 32bit """ + # bug #8043 -# disabled on 32 bit systems because the order of suggested proc alternatives is different. + import strutils "abc:def".rsplit({':'}, maxsplits = 1) From 70d93636cb85a5397fe9efcd463e6e39eb20501c Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 20 Mar 2020 06:21:42 -0300 Subject: [PATCH 0170/4254] Add Base64 safe (#13672) * Implement RFC-4648 Section-7 * https://github.com/nim-lang/Nim/pull/13672#issuecomment-600993466 --- changelog.md | 2 ++ lib/pure/base64.nim | 37 ++++++++++++++++++++++++++++--------- tests/stdlib/tbase64.nim | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 127579644..e7e3aaf0c 100644 --- a/changelog.md +++ b/changelog.md @@ -112,6 +112,8 @@ echo f - Added `times.isLeapDay` - Added a new module, `std / compilesettings` for querying the compiler about diverse configuration settings. +- `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. + ## Library changes diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 067f21c5f..f418a9d44 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -46,6 +46,13 @@ ## let decoded = decode("SGVsbG8gV29ybGQ=") ## assert decoded == "Hello World" ## +## URL Safe Base64 +## --------------- +## +## .. code-block::nim +## import base64 +## doAssert encode("c\xf7>", safe = true) == "Y_c-" +## doAssert encode("c\xf7>", safe = false) == "Y/c+" ## ## See also ## ======== @@ -56,9 +63,10 @@ const cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + cb64safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" invalidChar = 255 -template encodeInternal(s: typed): untyped = +template encodeInternal(s: typed, alphabet: string): untyped = ## encodes `s` into base64 representation. proc encodeSize(size: int): int = return (size * 4 div 3) + 6 @@ -78,7 +86,7 @@ template encodeInternal(s: typed): untyped = inc inputIndex template outputChar(x: untyped) = - result[outputIndex] = cb64[x and 63] + result[outputIndex] = alphabet[x and 63] inc outputIndex template outputChar(c: char) = @@ -112,12 +120,18 @@ template encodeInternal(s: typed): untyped = result.setLen(outputIndex) -proc encode*[T: SomeInteger|char](s: openArray[T]): string = +proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string = ## Encodes `s` into base64 representation. ## ## This procedure encodes an openarray (array or sequence) of either integers ## or characters. ## + ## If ``safe`` is ``true`` then it will encode using the + ## URL-Safe and Filesystem-safe standard alphabet characters, + ## which substitutes ``-`` instead of ``+`` and ``_`` instead of ``/``. + ## * https://en.wikipedia.org/wiki/Base64#URL_applications + ## * https://tools.ietf.org/html/rfc4648#page-7 + ## ## **See also:** ## * `encode proc<#encode,string>`_ for encoding a string ## * `decode proc<#decode,string>`_ for decoding a string @@ -125,19 +139,27 @@ proc encode*[T: SomeInteger|char](s: openArray[T]): string = assert encode(['n', 'i', 'm']) == "bmlt" assert encode(@['n', 'i', 'm']) == "bmlt" assert encode([1, 2, 3, 4, 5]) == "AQIDBAU=" - encodeInternal(s) + if safe: encodeInternal(s, cb64safe) + else: encodeInternal(s, cb64) -proc encode*(s: string): string = +proc encode*(s: string, safe = false): string = ## Encodes ``s`` into base64 representation. ## ## This procedure encodes a string. ## + ## If ``safe`` is ``true`` then it will encode using the + ## URL-Safe and Filesystem-safe standard alphabet characters, + ## which substitutes ``-`` instead of ``+`` and ``_`` instead of ``/``. + ## * https://en.wikipedia.org/wiki/Base64#URL_applications + ## * https://tools.ietf.org/html/rfc4648#page-7 + ## ## **See also:** ## * `encode proc<#encode,openArray[T]>`_ for encoding an openarray ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encode("Hello World") == "SGVsbG8gV29ybGQ=" - encodeInternal(s) + if safe: encodeInternal(s, cb64safe) + else: encodeInternal(s, cb64) proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = ## Encodes ``s`` into base64 representation as lines. @@ -232,6 +254,3 @@ proc decode*(s: string): string = outputChar(a shl 2 or b shr 4) outputChar(b shl 4 or c shr 2) result.setLen(outputIndex) - - - diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index 9db6e8802..e5b13642c 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -39,6 +39,21 @@ proc main() = except ValueError: discard + block base64urlSafe: + doAssert encode("c\xf7>", safe = true) == "Y_c-" + doAssert encode("c\xf7>", safe = false) == "Y/c+" # Not a nice URL :( + doAssert decode("Y/c+") == decode("Y_c-") + # Output must not change with safe=true + doAssert encode("Hello World", safe = true) == "SGVsbG8gV29ybGQ=" + doAssert encode("leasure.", safe = true) == "bGVhc3VyZS4=" + doAssert encode("easure.", safe = true) == "ZWFzdXJlLg==" + doAssert encode("asure.", safe = true) == "YXN1cmUu" + doAssert encode("sure.", safe = true) == "c3VyZS4=" + doAssert encode([1,2,3], safe = true) == "AQID" + doAssert encode(['h','e','y'], safe = true) == "aGV5" + doAssert encode("", safe = true) == "" + doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==" + echo "OK" main() From 12ab5059a0930bd642db43a96bcaa64f2a3c5327 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 20 Mar 2020 10:46:40 +0100 Subject: [PATCH 0171/4254] make 'nim check' more robust for illdefined constants --- compiler/semexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cc8854577..c678d3674 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1142,7 +1142,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # It is clear that ``[]`` means two totally different things. Thus, we # copy `x`'s AST into each context, so that the type fixup phase can # deal with two different ``[]``. - if s.ast.len == 0: result = inlineConst(c, n, s) + if s.ast.safeLen == 0: result = inlineConst(c, n, s) else: result = newSymNode(s, n.info) of tyStatic: if typ.n != nil: From dae9865b14fffd98ca0ef20517500831169861e7 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 20 Mar 2020 10:46:58 +0100 Subject: [PATCH 0172/4254] fight the code bloat in base64.nim --- lib/pure/base64.nim | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index f418a9d44..aaad26f96 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -61,12 +61,21 @@ ## * `md5 module`_ implements the MD5 checksum algorithm ## * `sha1 module`_ implements a sha1 encoder and decoder +template cbBase(a, b): untyped = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', a, b] + +let + cb64 = cbBase('+', '/') + cb64safe = cbBase('-', '_') + const - cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - cb64safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" invalidChar = 255 -template encodeInternal(s: typed, alphabet: string): untyped = +template encodeInternal(s: typed, alphabet: ptr array[64, char]): untyped = ## encodes `s` into base64 representation. proc encodeSize(size: int): int = return (size * 4 div 3) + 6 @@ -139,8 +148,8 @@ proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string = assert encode(['n', 'i', 'm']) == "bmlt" assert encode(@['n', 'i', 'm']) == "bmlt" assert encode([1, 2, 3, 4, 5]) == "AQIDBAU=" - if safe: encodeInternal(s, cb64safe) - else: encodeInternal(s, cb64) + let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) + encodeInternal(s, lookupTable) proc encode*(s: string, safe = false): string = ## Encodes ``s`` into base64 representation. @@ -158,8 +167,8 @@ proc encode*(s: string, safe = false): string = ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encode("Hello World") == "SGVsbG8gV29ybGQ=" - if safe: encodeInternal(s, cb64safe) - else: encodeInternal(s, cb64) + let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) + encodeInternal(s, lookupTable) proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = ## Encodes ``s`` into base64 representation as lines. From f4dbdd311fbb3dd99dafca2179f17f2747531b4f Mon Sep 17 00:00:00 2001 From: Hayden Date: Fri, 20 Mar 2020 05:59:05 -0400 Subject: [PATCH 0173/4254] Detect Ubuntu by checking release() and uname() (#13704) This will improve detection of Ubuntu when running on Ubuntu on WSL. #13703 --- lib/pure/distros.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 63cfe6719..8d4fbc857 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -156,7 +156,9 @@ proc detectOsImpl(d: Distribution): bool = of Distribution.Posix: result = defined(posix) of Distribution.MacOSX: result = defined(macosx) of Distribution.Linux: result = defined(linux) - of Distribution.Ubuntu, Distribution.Gentoo, Distribution.FreeBSD, + of Distribution.Ubuntu: + result = "Ubuntu" in release() or ("-" & $d & " ") in uname() + of Distribution.Gentoo, Distribution.FreeBSD, Distribution.OpenBSD: result = ("-" & $d & " ") in uname() of Distribution.RedHat: From 253e1b9e96111acb893411bd12540e46d158f9f6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 20 Mar 2020 14:35:45 +0100 Subject: [PATCH 0174/4254] fixes #13698 (#13706) --- compiler/ccgexprs.nim | 4 +++- tests/misc/tunsignedconv.nim | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2d1005f5e..9c683a071 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1985,8 +1985,10 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = discard cgsym(p.module, raiser) # This seems to be bug-compatible with Nim version 1 but what we # should really do here is to check if uint64Value < high(int) + let n0t = n[0].typ let boundaryCast = - if n[0].typ.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64}: + if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or + (n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"): "(NI64)" else: "" diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index 085d13aca..bc7aff30a 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -1,5 +1,6 @@ discard """ - output: '''uint''' + output: '''uint +1''' """ # Tests unsigned literals and implicit conversion between uints and ints @@ -60,3 +61,7 @@ discard $x0 const x1 = cast[uint](-1) discard $(x1,) + +# bug 13698 +let n: csize = 1 +echo n.int32 From 0f2377ebef3be9f4f567a97950ed566f53fcdfb5 Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 20 Mar 2020 07:38:33 -0600 Subject: [PATCH 0175/4254] =?UTF-8?q?Revert=20=C2=96#13658=20for=20nim-gdb?= =?UTF-8?q?.bat.=20Fixes=20#13705=20(#13707)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/nim-gdb.bat | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/nim-gdb.bat b/bin/nim-gdb.bat index 453d700bd..e98a2063c 100644 --- a/bin/nim-gdb.bat +++ b/bin/nim-gdb.bat @@ -6,7 +6,9 @@ for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi) set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py set @NIM_GDB=gdb.exe -%@NIM_GDB% -eval-command="source %@GDB_PYTHON_MODULE_PATH%" %* +@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt +%@NIM_GDB% --command="wingdbcommand.txt" %* +del wingdbcommand.txt /f /q EXIT /B %ERRORLEVEL% @echo on From 8215c576664e0bd689c16739f72d5b79cf302ec8 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 20 Mar 2020 15:06:53 +0100 Subject: [PATCH 0176/4254] threadpool.nim: allow control over MaxThreadPoolSize and MaxDistinguishedThread; refs #10584 --- lib/pure/concurrency/threadpool.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 1f7df7c00..ec950aa19 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -317,9 +317,9 @@ proc nimArgsPassingDone(p: pointer) {.compilerProc.} = signal(w.taskStarted) const - MaxThreadPoolSize* = 256 ## Maximum size of the thread pool. 256 threads - ## should be good enough for anybody ;-) - MaxDistinguishedThread* = 32 ## Maximum number of "distinguished" threads. + MaxThreadPoolSize* {.intdefine.} = 256 ## Maximum size of the thread pool. 256 threads + ## should be good enough for anybody ;-) + MaxDistinguishedThread* {.intdefine.} = 32 ## Maximum number of "distinguished" threads. type ThreadId* = range[0..MaxDistinguishedThread-1] From 1d665adecde3b3bf16e64068e83c0b3cb0171856 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 20 Mar 2020 08:39:55 -0700 Subject: [PATCH 0177/4254] [RFC] 'walkDir' now has a new 'checkDir' flag, to mimic behaviour of other languages (#13642) Co-authored-by: narimiran --- changelog.md | 12 +++++++++--- compiler/scriptconfig.nim | 2 +- lib/pure/os.nim | 36 +++++++++++++++++++++++++----------- lib/system/nimscript.nim | 6 +++--- tests/newconfig/tfoo.nims | 11 +++++------ tests/stdlib/tos.nim | 20 +++++++++++++------- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/changelog.md b/changelog.md index e7e3aaf0c..d3c85d666 100644 --- a/changelog.md +++ b/changelog.md @@ -7,7 +7,7 @@ on GCC's `__builtin_sadd_overflow` family of functions. (Clang also supports these). Some versions of GCC lack this feature and unfortunately we cannot detect this case reliably. So if you get compilation errors like - "undefined reference to '__builtin_saddll_overflow'" compile your programs + "undefined reference to `__builtin_saddll_overflow`" compile your programs with `-d:nimEmulateOverflowChecks`. @@ -34,8 +34,8 @@ - `options` now treats `proc` like other pointer types, meaning `nil` proc variables are converted to `None`. - `relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid path - and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to restore the old - behavior + and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to + restore the old behavior - `joinPath(a,b)` now honors trailing slashes in `b` (or `a` if `b` = "") - `times.parse` now only uses input to compute its result, and not `now`: `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of @@ -44,6 +44,12 @@ - `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical usage. The `$` operator can be used to obtain the string form of `HttpCode` for comparison if desired. +- `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false). + If it is set to true, it will throw if input dir is invalid instead of a noop + (which is the default behaviour, as it was before this change), + `os.walkDirRec` only throws if top-level dir is invalid, but ignores errors for + subdirs, otherwise it would be impossible to resume iteration. + ### Breaking changes in the compiler diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index d53664912..13ab03426 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -65,7 +65,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; if defined(nimsuggest) or graph.config.cmd == cmdCheck: discard else: - os.removeDir getString(a, 0) + os.removeDir(getString(a, 0), getBool(a, 1)) cbos removeFile: if defined(nimsuggest) or graph.config.cmd == cmdCheck: discard diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 1ee71c1fb..e90d3c514 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2028,8 +2028,8 @@ proc staticWalkDir(dir: string; relative: bool): seq[ tuple[kind: PathComponent, path: string]] = discard -iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: string] {. - tags: [ReadDirEffect].} = +iterator walkDir*(dir: string; relative = false, checkDir = false): + tuple[kind: PathComponent, path: string] {.tags: [ReadDirEffect].} = ## Walks over the directory `dir` and yields for each directory or file in ## `dir`. The component type and full path for each item are returned. ## @@ -2038,7 +2038,6 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: ## Example: This directory structure:: ## dirA / dirB / fileB1.txt ## / dirC - ## / fileA1.txt ## / fileA2.txt ## ## and this code: @@ -2069,7 +2068,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: elif defined(windows): var f: WIN32_FIND_DATA var h = findFirstFile(dir / "*", f) - if h != -1: + if h == -1: + if checkDir: + raiseOSError(osLastError(), dir) + else: defer: findClose(h) while true: var k = pcFile @@ -2087,7 +2089,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: else: raiseOSError(errCode.OSErrorCode) else: var d = opendir(dir) - if d != nil: + if d == nil: + if checkDir: + raiseOSError(osLastError(), dir) + else: defer: discard closedir(d) while true: var x = readdir(d) @@ -2122,7 +2127,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: iterator walkDirRec*(dir: string, yieldFilter = {pcFile}, followFilter = {pcDir}, - relative = false): string {.tags: [ReadDirEffect].} = + relative = false, checkDir = false): string {.tags: [ReadDirEffect].} = ## Recursively walks over the directory `dir` and yields for each file ## or directory in `dir`. ## @@ -2159,14 +2164,20 @@ iterator walkDirRec*(dir: string, ## * `walkDir iterator <#walkDir.i,string>`_ var stack = @[""] + var checkDir = checkDir while stack.len > 0: let d = stack.pop() - for k, p in walkDir(dir / d, relative = true): + for k, p in walkDir(dir / d, relative = true, checkDir = checkDir): let rel = d / p if k in {pcDir, pcLinkToDir} and k in followFilter: stack.add rel if k in yieldFilter: yield if relative: rel else: dir / rel + checkDir = false + # We only check top-level dir, otherwise if a subdir is invalid (eg. wrong + # permissions), it'll abort iteration and there would be no way to + # continue iteration. + # Future work can provide a way to customize this and do error reporting. proc rawRemoveDir(dir: string) {.noNimScript.} = when defined(windows): @@ -2181,13 +2192,13 @@ proc rawRemoveDir(dir: string) {.noNimScript.} = else: if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError(), dir) -proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ +proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ WriteDirEffect, ReadDirEffect], benign, noNimScript.} = ## Removes the directory `dir` including all subdirectories and files ## in `dir` (recursively). ## ## If this fails, `OSError` is raised. This does not fail if the directory never - ## existed in the first place. + ## existed in the first place, unless `checkDir` = true ## ## See also: ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ @@ -2197,10 +2208,13 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ ## * `copyDir proc <#copyDir,string,string>`_ ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ ## * `moveDir proc <#moveDir,string,string>`_ - for kind, path in walkDir(dir): + for kind, path in walkDir(dir, checkDir = checkDir): case kind of pcFile, pcLinkToFile, pcLinkToDir: removeFile(path) - of pcDir: removeDir(path) + of pcDir: removeDir(path, true) + # for subdirectories there is no benefit in `checkDir = false` + # (unless perhaps for edge case of concurrent processes also deleting + # the same files) rawRemoveDir(dir) proc rawCreateDir(dir: string): bool {.noNimScript.} = diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index b8abdaa38..f2a843652 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -30,7 +30,7 @@ proc listDirsImpl(dir: string): seq[string] {. tags: [ReadIOEffect], raises: [OSError].} = builtin proc listFilesImpl(dir: string): seq[string] {. tags: [ReadIOEffect], raises: [OSError].} = builtin -proc removeDir(dir: string) {. +proc removeDir(dir: string, checkDir = true) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin proc removeFile(dir: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin @@ -204,10 +204,10 @@ proc listFiles*(dir: string): seq[string] = result = listFilesImpl(dir) checkOsError() -proc rmDir*(dir: string) {.raises: [OSError].} = +proc rmDir*(dir: string, checkDir = false) {.raises: [OSError].} = ## Removes the directory `dir`. log "rmDir: " & dir: - removeDir dir + removeDir(dir, checkDir = checkDir) checkOsError() proc rmFile*(file: string) {.raises: [OSError].} = diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index 8dcc7d6f1..9e6405a27 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -24,8 +24,10 @@ doAssert(existsEnv("dummy") == false) # issue #7283 putEnv("dummy", "myval") -doAssert(existsEnv("dummy") == true) +doAssert(existsEnv("dummy")) doAssert(getEnv("dummy") == "myval") +delEnv("dummy") +doAssert(existsEnv("dummy") == false) # issue #7393 let wd = getCurrentDir() @@ -64,6 +66,8 @@ else: assert toDll("nim") == "libnim.so" rmDir("tempXYZ") +doAssertRaises(OSError): + rmDir("tempXYZ", checkDir = true) assert dirExists("tempXYZ") == false mkDir("tempXYZ") assert dirExists("tempXYZ") == true @@ -81,8 +85,3 @@ when false: rmDir("tempXYZ") assert dirExists("tempXYZ") == false - -putEnv("dummy", "myval") -doAssert(existsEnv("dummy") == true) -delEnv("dummy") -doAssert(existsEnv("dummy") == false) diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index d713bfe0c..be5384015 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -163,13 +163,19 @@ block walkDirRec: removeDir("walkdir_test") -when not defined(windows): - block walkDirRelative: - createDir("walkdir_test") - createSymlink(".", "walkdir_test/c") - for k, p in walkDir("walkdir_test", true): - doAssert k == pcLinkToDir - removeDir("walkdir_test") +block: # walkDir + doAssertRaises(OSError): + for a in walkDir("nonexistant", checkDir = true): discard + doAssertRaises(OSError): + for p in walkDirRec("nonexistant", checkDir = true): discard + + when not defined(windows): + block walkDirRelative: + createDir("walkdir_test") + createSymlink(".", "walkdir_test/c") + for k, p in walkDir("walkdir_test", true): + doAssert k == pcLinkToDir + removeDir("walkdir_test") block normalizedPath: doAssert normalizedPath("") == "" From 5b854442448af96d57135ba7328b0c21f1f80f40 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Fri, 20 Mar 2020 16:11:39 +0000 Subject: [PATCH 0178/4254] SSL certificate verify GitHub action (#13697) * Implement SSL/TLS certificate checking #782 * SSL: Add nimDisableCertificateValidation Remove NIM_SSL_CERT_VALIDATION env var tests/untestable/thttpclient_ssl.nim ran successfully on Linux with libssl 1.1.1d * SSL: update integ test to skip flapping tests * Revert .travis.yml change * nimDisableCertificateValidation disable imports Prevent loading symbols that are not defined on older SSL libs * SSL: disable verification in net.nim ..when nimDisableCertificateValidation is set * Update changelog * Fix peername type * Add define check for windows * Disable test on windows * Add exprimental GitHub action CI for SSL * Test nimDisableCertificateValidation --- .github/workflows/ci_ssl.yml | 91 ++++++++ appveyor.yml | 2 + changelog.md | 2 + lib/pure/httpclient.nim | 9 + lib/pure/net.nim | 88 ++++++-- lib/pure/ssl_certs.nim | 97 +++++++++ lib/wrappers/openssl.nim | 71 ++++++ tests/stdlib/thttpclient_ssl.nim | 126 +++++++++++ tests/stdlib/thttpclient_ssl_cert.pem | 29 +++ tests/stdlib/thttpclient_ssl_key.pem | 52 +++++ tests/untestable/thttpclient_ssl.nim | 203 ++++++++++++++++++ tests/untestable/thttpclient_ssl_disabled.nim | 40 ++++ tests/untestable/thttpclient_ssl_env_var.nim | 74 +++++++ 13 files changed, 872 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci_ssl.yml create mode 100644 lib/pure/ssl_certs.nim create mode 100644 tests/stdlib/thttpclient_ssl.nim create mode 100644 tests/stdlib/thttpclient_ssl_cert.pem create mode 100644 tests/stdlib/thttpclient_ssl_key.pem create mode 100644 tests/untestable/thttpclient_ssl.nim create mode 100644 tests/untestable/thttpclient_ssl_disabled.nim create mode 100644 tests/untestable/thttpclient_ssl_env_var.nim diff --git a/.github/workflows/ci_ssl.yml b/.github/workflows/ci_ssl.yml new file mode 100644 index 000000000..fe5faded6 --- /dev/null +++ b/.github/workflows/ci_ssl.yml @@ -0,0 +1,91 @@ +name: Nim SSL CI +on: + pull_request: + # Run only on changes on related files + paths: + - 'lib/pure/httpclient.nim' + - 'lib/pure/net.nim' + - 'lib/pure/ssl_certs.nim' + - 'lib/wrappers/openssl.nim' + - 'tests/stdlib/thttpclient_ssl*' + - 'tests/untestable/thttpclient_ssl*' + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-18.04, macos-10.15, windows-2019] + cpu: [amd64] + name: '${{ matrix.os }} (${{ matrix.cpu }})' + runs-on: ${{ matrix.os }} + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + + - name: 'Checkout csources' + uses: actions/checkout@v2 + with: + repository: nim-lang/csources + path: csources + + - name: 'Install dependencies (Linux amd64)' + if: runner.os == 'Linux' && matrix.cpu == 'amd64' + run: | + sudo apt-fast update -qq + DEBIAN_FRONTEND='noninteractive' \ + sudo apt-fast install --no-install-recommends -y libssl1.1 + - name: 'Install dependencies (macOS)' + if: runner.os == 'macOS' + run: brew install make + - name: 'Install dependencies (Windows)' + if: runner.os == 'Windows' + shell: bash + run: | + mkdir dist + curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z + curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip + 7z x dist/mingw64.7z -odist + 7z x dist/dlls.zip -obin + echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" + + - name: 'Add build binaries to PATH' + shell: bash + run: echo "::add-path::${{ github.workspace }}/bin" + + - name: 'Build 1-stage compiler from csources' + shell: bash + run: | + ncpu= + case '${{ runner.os }}' in + 'Linux') + ncpu=$(nproc) + ;; + 'macOS') + ncpu=$(sysctl -n hw.ncpu) + ;; + 'Windows') + ncpu=$NUMBER_OF_PROCESSORS + ;; + esac + [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 + + make -C csources -j $ncpu CC=gcc ucpu='${{ matrix.cpu }}' + + - name: 'Build koch' + shell: bash + run: nim c koch + + - name: 'Build the real compiler' + shell: bash + run: ./koch boot + + - name: 'Run SSL nimDisableCertificateValidation integration tests' + shell: bash + run: nim c -d:nimDisableCertificateValidation -d:ssl -r -p:. tests/untestable/thttpclient_ssl_disabled.nim + + - name: 'Run SSL certificate check integration tests' + # Not supported on Windows due to old openssl version + if: runner.os != 'Windows' + shell: bash + run: nim c -d:ssl -p:. --threads:on -r tests/untestable/thttpclient_ssl.nim diff --git a/appveyor.yml b/appveyor.yml index e9407d124..5468ac88a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,6 +29,8 @@ install: - cd .. build_script: + - openssl version + - openssl version -d - bin\nim c koch - koch runCI diff --git a/changelog.md b/changelog.md index d3c85d666..d5d1be956 100644 --- a/changelog.md +++ b/changelog.md @@ -144,6 +144,8 @@ echo f empty. This was required for intuitive behaviour of the strscans module (see bug #13605). - `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs +- `net.newContext` now performs SSL Certificate checking on Linux and OSX. + Define `nimDisableCertificateValidation` to disable it globally. ## Language additions diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index b7bdc8d17..e3e5a5c11 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -119,6 +119,14 @@ ## You will also have to compile with ``ssl`` defined like so: ## ``nim c -d:ssl ...``. ## +## Certificate validation is NOT performed by default. +## This will change in future. +## +## A set of directories and files from the `ssl_certs `_ +## module are scanned to locate CA certificates. +## +## See `newContext `_ to tweak or disable certificate validation. +## ## Timeouts ## ======== ## @@ -552,6 +560,7 @@ proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, ## default is 5. ## ## ``sslContext`` specifies the SSL context to use for HTTPS requests. + ## See `SSL/TLS support <##ssl-tls-support>`_ ## ## ``proxy`` specifies an HTTP proxy to use for this HTTP client's ## connections. diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 0d4440242..ca3d37259 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -67,6 +67,8 @@ {.deadCodeElim: on.} # dce option deprecated import nativesockets, os, strutils, parseutils, times, sets, options, std/monotimes +from ospaths import getEnv +from ssl_certs import scanSSLCertificates export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol @@ -83,7 +85,7 @@ when defineSsl: SslError* = object of Exception SslCVerifyMode* = enum - CVerifyNone, CVerifyPeer + CVerifyNone, CVerifyPeer, CVerifyPeerUseEnvVars SslProtVersion* = enum protSSLv2, protSSLv3, protTLSv1, protSSLv23 @@ -517,17 +519,30 @@ when defineSsl: raiseSSLError("Verification of private key file failed.") proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, - certFile = "", keyFile = "", cipherList = "ALL"): SslContext = + certFile = "", keyFile = "", cipherList = "ALL", + caDir = "", caFile = ""): SSLContext = ## Creates an SSL context. ## ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 ## are available with the addition of ``protSSLv23`` which allows for ## compatibility with all of them. ## - ## There are currently only two options for verify mode; - ## one is ``CVerifyNone`` and with it certificates will not be verified - ## the other is ``CVerifyPeer`` and certificates will be verified for - ## it, ``CVerifyPeer`` is the safest choice. + ## There are three options for verify mode: + ## ``CVerifyNone``: certificates are not verified; + ## ``CVerifyPeer``: certificates are verified; + ## ``CVerifyPeerUseEnvVars``: certificates are verified and the optional + ## environment variables SSL_CERT_FILE and SSL_CERT_DIR are also used to + ## locate certificates + ## + ## The `nimDisableCertificateValidation` define overrides verifyMode and + ## disables certificate verification globally! + ## + ## CA certificates will be loaded, in the following order, from: + ## + ## - caFile, caDir, parameters, if set + ## - if `verifyMode` is set to ``CVerifyPeerUseEnvVars``, + ## the SSL_CERT_FILE and SSL_CERT_DIR environment variables are used + ## - a set of files and directories from the `ssl_certs `_ file. ## ## The last two parameters specify the certificate file path and the key file ## path, a server socket will most likely not work without these. @@ -550,18 +565,41 @@ when defineSsl: if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1: raiseSSLError() - case verifyMode - of CVerifyPeer: - newCTX.SSL_CTX_set_verify(SSL_VERIFY_PEER, nil) - of CVerifyNone: + + when defined(nimDisableCertificateValidation) or defined(windows): newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil) + else: + case verifyMode + of CVerifyPeer, CVerifyPeerUseEnvVars: + newCTX.SSL_CTX_set_verify(SSL_VERIFY_PEER, nil) + of CVerifyNone: + newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil) + if newCTX == nil: raiseSSLError() discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) - result = SslContext(context: newCTX, referencedData: initSet[int](), + when not defined(nimDisableCertificateValidation) and not defined(windows): + if verifyMode != CVerifyNone: + # Use the caDir and caFile parameters if set + if caDir != "" or caFile != "": + if newCTX.SSL_CTX_load_verify_locations(caDir, caFile) != 0: + raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).") + + else: + # Scan for certs in known locations. For CVerifyPeerUseEnvVars also scan + # the SSL_CERT_FILE and SSL_CERT_DIR env vars + var found = false + for fn in scanSSLCertificates(): + if newCTX.SSL_CTX_load_verify_locations(fn, "") == 0: + found = true + break + if not found: + raise newException(IOError, "No SSL/TLS CA certificates found.") + + result = SSLContext(context: newCTX, referencedData: initSet[int](), extraInternal: new(SslContextExtraInternal)) proc getExtraInternal(ctx: SslContext): SslContextExtraInternal = @@ -645,6 +683,7 @@ when defineSsl: ## This must be called on an unconnected socket; an SSL session will ## be started when the socket is connected. ## + ## FIXME: ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. @@ -660,7 +699,25 @@ when defineSsl: if SSL_set_fd(socket.sslHandle, socket.fd) != 1: raiseSSLError() - proc wrapConnectedSocket*(ctx: SslContext, socket: Socket, + proc checkCertName(socket: Socket, hostname: string) = + ## Check if the certificate Subject Alternative Name (SAN) or Subject CommonName (CN) matches hostname. + ## Wildcards match only in the left-most label. + ## When name starts with a dot it will be matched by a certificate valid for any subdomain + when not defined(nimDisableCertificateValidation) and not defined(windows): + assert socket.isSSL + let certificate = socket.sslHandle.SSL_get_peer_certificate() + if certificate.isNil: + raiseSSLError("No SSL certificate found.") + + const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint + const size = 1024 + var peername: string = newString(size) + let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint, + X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, peername) + if match != 1: + raiseSSLError("SSL Certificate check failed.") + + proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket, handshake: SslHandshakeType, hostname: string = "") = ## Wraps a connected socket in an SSL context. This function effectively @@ -671,6 +728,7 @@ when defineSsl: ## This should be called on a connected socket, and will perform ## an SSL handshake immediately. ## + ## FIXME: ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. wrapSocket(ctx, socket) @@ -682,6 +740,9 @@ when defineSsl: discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) let ret = SSL_connect(socket.sslHandle) socketError(socket, ret) + when not defined(nimDisableCertificateValidation) and not defined(windows): + if hostname.len > 0 and not isIpAddress(hostname): + socket.checkCertName(hostname) of handshakeAsServer: let ret = SSL_accept(socket.sslHandle) socketError(socket, ret) @@ -1638,6 +1699,9 @@ proc connect*(socket: Socket, address: string, let ret = SSL_connect(socket.sslHandle) socketError(socket, ret) + when not defined(nimDisableCertificateValidation) and not defined(windows): + if not isIpAddress(address): + socket.checkCertName(address) proc connectAsync(socket: Socket, name: string, port = Port(0), af: Domain = AF_INET) {.tags: [ReadIOEffect].} = diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim new file mode 100644 index 000000000..7b1550004 --- /dev/null +++ b/lib/pure/ssl_certs.nim @@ -0,0 +1,97 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +## Scan for SSL/TLS CA certificates on disk +## The default locations can be overridden using the SSL_CERT_FILE and +## SSL_CERT_DIR environment variables. + +import os, strutils +from ospaths import existsEnv, getEnv +import strutils + +# SECURITY: this unnecessarily scans through dirs/files regardless of the +# actual host OS/distribution. Hopefully all the paths are writeble only by +# root. + +# FWIW look for files before scanning entire dirs. + +const certificate_paths = [ + # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo + # NetBSD (security/mozilla-rootcerts) + # SLES10/SLES11, https://golang.org/issue/12139 + "/etc/ssl/certs/ca-certificates.crt", + # OpenSUSE + "/etc/ssl/ca-bundle.pem", + # Red Hat 5+, Fedora, Centos + "/etc/pki/tls/certs/ca-bundle.crt", + # Red Hat 4 + "/usr/share/ssl/certs/ca-bundle.crt", + # FreeBSD (security/ca-root-nss package) + "/usr/local/share/certs/ca-root-nss.crt", + # CentOS/RHEL 7 + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", + # OpenBSD, FreeBSD (optional symlink) + "/etc/ssl/cert.pem", + # Mac OS X + "/System/Library/OpenSSL/certs/cert.pem", + # Fedora/RHEL + "/etc/pki/tls/certs", + # Android + "/system/etc/security/cacerts", + # FreeBSD + "/usr/local/share/certs", + # NetBSD + "/etc/openssl/certs", +] + +iterator scanSSLCertificates*(useEnvVars = false): string = + ## Scan for SSL/TLS CA certificates on disk. + ## + ## if `useEnvVars` is true, the SSL_CERT_FILE and SSL_CERT_DIR + ## environment variables can be used to override the certificate + ## directories to scan or specify a CA certificate file. + if existsEnv("SSL_CERT_FILE"): + yield getEnv("SSL_CERT_FILE") + + elif existsEnv("SSL_CERT_DIR"): + let p = getEnv("SSL_CERT_DIR") + for fn in joinPath(p, "*").walkFiles(): + yield fn + + else: + for p in certificate_paths: + if p.endsWith(".pem") or p.endsWith(".crt"): + if existsFile(p): + yield p + elif existsDir(p): + for fn in joinPath(p, "*").walkFiles(): + yield fn + +# Certificates management on windows +# when defined(windows) or defined(nimdoc): +# +# import openssl +# +# type +# PCCertContext {.final, pure.} = pointer +# X509 {.final, pure.} = pointer +# CertStore {.final, pure.} = pointer +# +# # OpenSSL cert store +# +# {.push stdcall, dynlib: "kernel32", importc.} +# +# proc CertOpenSystemStore*(hprov: pointer=nil, szSubsystemProtocol: cstring): CertStore +# +# proc CertEnumCertificatesInStore*(hCertStore: CertStore, pPrevCertContext: PCCertContext): pointer +# +# proc CertFreeCertificateContext*(pContext: PCCertContext): bool +# +# proc CertCloseStore*(hCertStore:CertStore, flags:cint): bool +# +# {.pop.} diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 4a53fba80..789b3611c 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -647,3 +647,74 @@ proc md5_Str*(str: string): string = when defined(nimHasStyleChecks): {.pop.} + + +# Certificate validation +# On old openSSL version some of these symbols are not available +when not defined(nimDisableCertificateValidation) and not defined(windows): + + proc SSL_get_peer_certificate*(ssl: SslCtx): PX509{.cdecl, dynlib: DLLSSLName, + importc.} + + proc X509_get_subject_name*(a: PX509): PX509_NAME{.cdecl, dynlib: DLLSSLName, importc.} + + proc X509_get_issuer_name*(a: PX509): PX509_NAME{.cdecl, dynlib: DLLUtilName, importc.} + + proc X509_NAME_oneline*(a: PX509_NAME, buf: cstring, size: cint): cstring {. + cdecl, dynlib:DLLSSLName, importc.} + + proc X509_NAME_get_text_by_NID*(subject:cstring, NID: cint, buf: cstring, size: cint): cint{. + cdecl, dynlib:DLLSSLName, importc.} + + proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.} + + # Certificates store + + type PX509_STORE* = SslPtr + type PX509_OBJECT* = SslPtr + + {.push callconv:cdecl, dynlib:DLLUtilName, importc.} + + proc X509_OBJECT_new*(): PX509_OBJECT + proc X509_OBJECT_free*(a: PX509_OBJECT) + + proc X509_STORE_new*(): PX509_STORE + proc X509_STORE_free*(v: PX509_STORE) + proc X509_STORE_lock*(ctx: PX509_STORE): cint + proc X509_STORE_unlock*(ctx: PX509_STORE): cint + proc X509_STORE_up_ref*(v: PX509_STORE): cint + proc X509_STORE_set_flags*(ctx: PX509_STORE; flags: culong): cint + proc X509_STORE_set_purpose*(ctx: PX509_STORE; purpose: cint): cint + proc X509_STORE_set_trust*(ctx: PX509_STORE; trust: cint): cint + proc X509_STORE_add_cert*(ctx: PX509_STORE; x: PX509): cint + + proc d2i_X509*(px: ptr PX509, i: ptr ptr cuchar, len: cint): PX509 + + proc i2d_X509*(cert: PX509; o: ptr ptr cuchar): cint + + {.pop.} + + proc d2i_X509*(b: string): PX509 = + ## decode DER/BER bytestring into X.509 certificate struct + var bb = b.cstring + let i = cast[ptr ptr cuchar](addr bb) + let ret = d2i_X509(addr result, i, b.len.cint) + if ret.isNil: + raise newException(Exception, "X.509 certificate decoding failed") + + proc i2d_X509*(cert: PX509): string = + ## encode `cert` to DER string + let encoded_length = i2d_X509(cert, nil) + result = newString(encoded_length) + var q = result.cstring + let o = cast[ptr ptr cuchar](addr q) + let length = i2d_X509(cert, o) + if length.int <= 0: + raise newException(Exception, "X.509 certificate encoding failed") + + when isMainModule: + # A simple certificate test + let certbytes = readFile("certificate.der") + let cert = d2i_X509(certbytes) + let encoded = cert.i2d_X509() + assert encoded == certbytes diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim new file mode 100644 index 000000000..f247ae442 --- /dev/null +++ b/tests/stdlib/thttpclient_ssl.nim @@ -0,0 +1,126 @@ +discard """ + cmd: "nim $target --threads:on -d:ssl $options $file" +""" + +# Nim - Basic SSL integration tests +# (c) Copyright 2018 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +## Warning: this test performs local networking. +## Test with: +## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim + +when not defined(windows): + # Disabled on Windows due to old OpenSSL version + + import + httpclient, + net, + openssl, + os, + strutils, + threadpool, + times, + unittest + + # bogus self-signed certificate + const + certFile = "tests/stdlib/thttpclient_ssl_cert.pem" + keyFile = "tests/stdlib/thttpclient_ssl_key.pem" + + proc log(msg: string) = + when defined(ssldebug): + echo " [" & $epochTime() & "] " & msg + # FIXME + echo " [" & $epochTime() & "] " & msg + discard + + proc runServer(port: Port): bool {.thread.} = + ## Run a trivial HTTPS server in a {.thread.} + ## Exit after serving one request + + var socket = newSocket() + socket.setSockOpt(OptReusePort, true) + socket.bindAddr(port) + + var ctx = newContext(certFile=certFile, keyFile=keyFile) + + ## Handle one connection + socket.listen() + + var client: Socket + var address = "" + + log "server: ready" + socket.acceptAddr(client, address) + log "server: incoming connection" + + var ssl: SslPtr = SSL_new(ctx.context) + discard SSL_set_fd(ssl, client.getFd()) + log "server: accepting connection" + if SSL_accept(ssl) <= 0: + ERR_print_errors_fp(stderr) + else: + const reply = "HTTP/1.0 200 OK\r\nServer: test\r\nContent-type: text/html\r\nContent-Length: 0\r\n\r\n" + log "server: sending reply" + discard SSL_write(ssl, reply.cstring, reply.len) + + log "server: receiving a line" + let line = client.recvLine() + log "server: received $# bytes" % $line.len + log "closing" + SSL_free(ssl) + close(client) + close(socket) + log "server: exited" + + + suite "SSL self signed certificate check": + + test "TCP socket": + const port = 12347.Port + let t = spawn runServer(port) + sleep(100) + var sock = newSocket() + var ctx = newContext() + ctx.wrapSocket(sock) + try: + log "client: connect" + sock.connect("127.0.0.1", port) + fail() + except: + let msg = getCurrentExceptionMsg() + check(msg.contains("certificate verify failed")) + + test "HttpClient default: no check": + const port = 12345.Port + let t = spawn runServer(port) + sleep(100) + + var client = newHttpClient() + try: + log "client: connect" + discard client.getContent("https://127.0.0.1:12345") + except: + let msg = getCurrentExceptionMsg() + log "client: unexpected exception: " & msg + fail() + + test "HttpClient with CVerifyPeer": + const port = 12346.Port + let t = spawn runServer(port) + sleep(100) + + var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer)) + try: + log "client: connect" + discard client.getContent("https://127.0.0.1:12346") + log "getContent should have raised an exception" + fail() + except: + let msg = getCurrentExceptionMsg() + log "client: exception: " & msg + # SSL_shutdown:shutdown while in init + check(msg.contains("shutdown while in init") or msg.contains("alert number 48")) diff --git a/tests/stdlib/thttpclient_ssl_cert.pem b/tests/stdlib/thttpclient_ssl_cert.pem new file mode 100644 index 000000000..f15c15c52 --- /dev/null +++ b/tests/stdlib/thttpclient_ssl_cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFCTCCAvGgAwIBAgIURYQOmGzeh3Vy7Gk6Go4uAPwcNwAwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MDEyMzAwMTgzNFoXDTQ2MDYw +OTAwMTgzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAzoEVEl7yqY+RqIagXDD4JB7LyONDvh8aJvBMnJVBgjaL +JdkfQjvPGUzUkEbU5nc6u7lqFxzEv7hXrssQCB7TwJwfS2PT1Rj14IFlYPyw4DEe +P1RVS/awurtv3jwumarVl7LR+IQfo59kJ/P8jZt8H3HscDbyhXcHeOWI6q+XlfdV +mTUJVvABdUuOiIFjgfFVTpo+CKxy7c5caRDK7g1s9xB1/M9PUfJvHY1WrBWFOZf0 +Bl8iwn+ahuxfIVqsFL9leqLykgi1f4L20p7RaAK95TXCo3CszZm4Fsw9zhzkjoU7 +2h0nuYl197LZvRs3u/JJjzZERmsfVPIs5BtO8/MN1MvRn6hIGU5Q3kOVWqWxSkSl +njrf+uwUdn/24uSCnygNeDuJzwW/2q4N9YI3oovqNIGpkT3FbAm7UKwI4lwhwmqw +7WH+92ELj0BinmsMMRPD2OqvK+vzLVqwUIQkYug+Hjys6QGXMlrL0krrj7XOKSc3 +SvZa4j0S/Y5CKkw5xuZXxITsdaV6hGi3d/kuT+1ttOSfIIXJXDEiu4pYRfziKU1a +8EhHMEajEi6ueLw7QmEPVx398erRwiUuP2y43yZ4mwVwvN3i5jlVztl4XsglDmQ+ +hahstVdMMA34K2rK0U8q8YjdYm+z99NmGEPYrS6Qnpr1xrICN83FOWFI0k7ttyMC +AwEAAaNTMFEwHQYDVR0OBBYEFLqMY6eP3h3gu+ANs77xDBRnElxyMB8GA1UdIwQY +MBaAFLqMY6eP3h3gu+ANs77xDBRnElxyMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggIBAJS+wyy0r+tVAlCa6V/xxlCDtW9n6L2nsqJXEjME0VvwGs3m +ima68LyTQJqCSjjxSotaNOYKzUu4vRA3JssV+fUDR+NpmhpRuM74XmO05HUQkp9U +dBEHyXp2aRQ9LSdvHo5D+RW+J4sHFb3PbU8NPx/t5Dg7il92S2QJQz1jNl+Nezc6 +2O8Vt1YbvWXfqM47URTpnQbWoo38pI44AgAuW3QagucKWsyounmhx65XcdtLn99g +oZt496pU+hBpYu/IpXuBKNC4FvOrXTWAPkAbbYP39UFyiKwIyTosK+qdbhBlt1xi +bBPn6N1W9L2BvUwM8fEB/qBuR9UfcMsIYJsWbbXMfyeF6lbaP7xD01rm+yU5PMMI +Co40abixMntz4J3T2ixdCptf0He1U/UegOHwG1ZGgQzvOG6qI/xkNktDaSA75KR7 +BvPV1CmZC4ovVo1L4STrwnoRz5J49PNOHi9Okj9zJ99H7nsmsK16oxpIYkYHJWn+ +45jpG8SlDp7oev1OGGk/z+ZOTz+LcNxyvsRQVN8w5zNmjCSWiGqz+UUgppCZg8qd +ECWokNQ5Lr20t1whynrX5bH0l887WPCQmm5VduRoyKFGhCRBSzcCtowSpiwZglUk +CV0jgFKoteItdzZgsND5I1GaNOxZlnK3wN4H0pgZv7HlW6SP1OYd2Y67waJ7 +-----END CERTIFICATE----- diff --git a/tests/stdlib/thttpclient_ssl_key.pem b/tests/stdlib/thttpclient_ssl_key.pem new file mode 100644 index 000000000..6ab04122c --- /dev/null +++ b/tests/stdlib/thttpclient_ssl_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDOgRUSXvKpj5Go +hqBcMPgkHsvI40O+Hxom8EyclUGCNosl2R9CO88ZTNSQRtTmdzq7uWoXHMS/uFeu +yxAIHtPAnB9LY9PVGPXggWVg/LDgMR4/VFVL9rC6u2/ePC6ZqtWXstH4hB+jn2Qn +8/yNm3wfcexwNvKFdwd45Yjqr5eV91WZNQlW8AF1S46IgWOB8VVOmj4IrHLtzlxp +EMruDWz3EHX8z09R8m8djVasFYU5l/QGXyLCf5qG7F8hWqwUv2V6ovKSCLV/gvbS +ntFoAr3lNcKjcKzNmbgWzD3OHOSOhTvaHSe5iXX3stm9Gze78kmPNkRGax9U8izk +G07z8w3Uy9GfqEgZTlDeQ5VapbFKRKWeOt/67BR2f/bi5IKfKA14O4nPBb/arg31 +gjeii+o0gamRPcVsCbtQrAjiXCHCarDtYf73YQuPQGKeawwxE8PY6q8r6/MtWrBQ +hCRi6D4ePKzpAZcyWsvSSuuPtc4pJzdK9lriPRL9jkIqTDnG5lfEhOx1pXqEaLd3 ++S5P7W205J8ghclcMSK7ilhF/OIpTVrwSEcwRqMSLq54vDtCYQ9XHf3x6tHCJS4/ +bLjfJnibBXC83eLmOVXO2XheyCUOZD6FqGy1V0wwDfgrasrRTyrxiN1ib7P302YY +Q9itLpCemvXGsgI3zcU5YUjSTu23IwIDAQABAoICAQCdR60/57cUs/dxjs/2R4nH +IPl/ELEYzeGCRMVlATz6qwZCFmN7c8ghceX32SrwOWEvd2G5Jr0ndIS76YdVV/1Z +ls8zAV5m0HL8wjDvtKYWqvJps5afm80w+++RKO8pNPcnahgIGsFqQszqrSbux7y6 +ym8VbJQ8WNMFHnWwoXpnyxCT9tQdNgE2UAzIJRwf7SpXCp0yx/1k6CZ0E0ksFGeo +qQ3kNhUoyegdbvfTazSkD/rZG36C+uM73i36Xm/wAXKN/CuaVC3AZ4QMGNBPUr9F +IzQSfY/vrCOMoZR1NoZRkmJqlogaBPsnZD34jRFfAYNLIz7PD2m2rhjIx4/Tt4wQ +5mUwga9ud0ly5wSzswudw07mTYtsLbWrUn6QdFxSwbQ0tXh9PJrqCSJDmYIptuu/ +6zjg8hQLg7y37xMDMCdKtviHx+ndVpW3StTwB/z7lDA6yuYY6nYN0dJTJS3qQheo +maPG4Xf4FBcD4Is73BjBCf3QR6WIv0ZOG3/GZ1OqLRrPg1u/3UJkpa4LE/6qNUxf +zdBZSPyQZExBvOqdklEI+1OcqofmWq2n7Amct45buDbFryehEhfJ1HHtkXkTEsut +azfQeaGem/jKxcTD+1bWs/Q5Nn+QFfKr0NFjXSLoITWQkgQD1qISw3DC72jYXlsm +S4CmCDW1dHZlmWZq+Mh34QKCAQEA+2JFRa1yYZ0tPt88sOjJYyw9yUxB9Nv9cKrs +kdkhKHKevF+0BUbRLfp9bod+Wlv66pgQi6ZGKkGD7lCam/3FIBlmmiG8AOoXdoGy +t17XCzlYy348mnHra2X+JBAN51ivPemdlGZShLbNMkGdL1khtjHL9vSr1KgFn3F/ +8nstVQ9nzHTCK0HWpBGn/EK3dd8lcYZDd7Fcgjz7E3xQDz/XZt0HMwwGaLnQ1L7T +glIyeNdqLBp4v0NT6L1AAk5rQJONo57AepblwacYhoW9mR5K0bm/BMo5+xwMtYz9 +69ZuMNW8qdaWrzeEsxM1PDbcOoVqChF10w0Ih/MkhKGpN/GxUQKCAQEA0kvWUkEK +1BBhwGyuKrMnUC3jnQ36KpsjlryMUArdjS2gVBztGW2p2CUWasEgZdxpwQmnqKyz +4hcZaU/JUleutTI5raxzju4Ve87c+koOiamhw/zaiLCpLn2j0Rh2qxp7QvPPRO0V +1MN347wjCTx/5/j8WffgWqWfqdrd8JheKal/OHlTZA3DG77FIVnUyov8Np+lTd1x +NpWr/AOreZlMBq/X/kmWCe+fP901fGdi3cdsKcJcdLPv9KFciSjBlAlaLMnBgLWo +RrIuNxdH3dRX4rzBSpdNq72n8NaH+A10eoXrlC4eWLo7vRSTe4WRgUAIbhVifnJk +z4B5FqC/aVgkMwKCAQEAtq983h0lcbDy76z2Ay65I/xDzqU/jX3OGfHtSDS+NxHN +L+JxBiCn5b0TKJ8JAQu1NoVaCNLGTPEdurQTF+f9OM2c1chMQ3HbqUCqKz6eEscT +M5dC3Y6KYptVbMnKAOVfPSQoY29U6qOaTbqHS6B/slNQAeFfeoS8yVmHfSVtFVLD +wT7c2OjY3pUCOn4Vq3CGWpETOMnJC9DbOhbua5aeqF9aWwuTIMpg7CrdtOidS1pp +CzIVrBF2yj22ZbatlNlmZpD5Gl3NDMWtOh25Yqwz/WP6YLXCGy4QQmP7KEfF/nFl +0RtkmGNFaYo89sx7kX/hRv3XXZAsMfhOAqElQ8W+cQKCAQAdL/lnIS/njv6CPpNN +yd/C+RuGSNJX54BhA3pWAawOVC7Ufc9KoDXakgsydeuRN65V5IkomA+/aYVVYIWI +sDLHY1kuCalgRRsmO+fftTefU7PoB8gtAJf6o+WAt+yAgwRonn4+Csnk5dxV917F +gWgfQieENSsmaaZnZME5C2zGS4gkxnIUiPRzfV7O6jDmi9dNnYrL69gyw0NDjx7V +mbk7lFxeJsh0SJXJv2IVCiRms68HfLpoWDENuvek8cssSMADR11cB9p7NW/Epa6L +01T/W0NYnvdgxsnwW1Yzz2pDNyMjReNgXTi9XYW6tyci0UhaPw2Ujzv+sM4dneHz +NRCRAoIBAHqXaeC1uTGSzfLvRz81ifgDRP8H9L1HLt7ZWL6XMp1ph+P6yYFXM4JK +WeP3cdKO/kQOD/fLuhYT92T2hHEadT8CQqpsBMQt29Zlm4oYWHB7ERiZqaGX3/T0 +U1TlL0WxthoHPY2HwA6pmDTmUzDk3tFlgk+XOmLsDacBdC6EsFwA+tyEPVxmkb0J +H+j7D4NxwysAyWCB9fWU1FV+JJJel+nz88i7Gb8uJ+kSktnFxjv/G9p+OkDYlaUt +j8lc6LOuNOA9M7XT1BIKpZytnSVtwZWkMmu23OLMM/d07tPJYtHIa92On7XKBPc2 +6THbQsJpR5AalTVvXs3X1RnCLnHiNYg= +-----END PRIVATE KEY----- diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim new file mode 100644 index 000000000..3744df92d --- /dev/null +++ b/tests/untestable/thttpclient_ssl.nim @@ -0,0 +1,203 @@ +# +# +# Nim - SSL integration tests +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +## Warning: this test performs external networking. +## Test with: +## ./bin/nim c -d:ssl -p:. --threads:on -r tests/untestable/thttpclient_ssl.nim +## +## See https://github.com/FedericoCeratto/ssl-comparison/blob/master/README.md +## for a comparison with other clients. + +import + httpclient, + net, + strutils, + threadpool, + unittest + + +type + # bad and dubious tests should not pass SSL validation + # "_broken" mark the test as skipped. Some tests have different + # behavior depending on OS and SSL version! + # TODO: chase and fix the broken tests + Category = enum + good, bad, dubious, good_broken, bad_broken, dubious_broken + CertTest = tuple[url:string, category:Category, desc: string] + +const certificate_tests: array[0..55, CertTest] = [ + ("https://wrong.host.badssl.com/", bad, "wrong.host"), + ("https://captive-portal.badssl.com/", bad, "captive-portal"), + ("https://expired.badssl.com/", bad, "expired"), + ("https://google.com/", good, "good"), + ("https://self-signed.badssl.com/", bad, "self-signed"), + ("https://untrusted-root.badssl.com/", bad, "untrusted-root"), + ("https://revoked.badssl.com/", bad_broken, "revoked"), + ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"), + ("https://no-common-name.badssl.com/", dubious_broken, "no-common-name"), + ("https://no-subject.badssl.com/", dubious_broken, "no-subject"), + ("https://incomplete-chain.badssl.com/", dubious, "incomplete-chain"), + ("https://sha1-intermediate.badssl.com/", bad_broken, "sha1-intermediate"), + ("https://sha256.badssl.com/", good, "sha256"), + ("https://sha384.badssl.com/", good, "sha384"), + ("https://sha512.badssl.com/", good, "sha512"), + ("https://1000-sans.badssl.com/", good, "1000-sans"), + ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), + ("https://ecc256.badssl.com/", good, "ecc256"), + ("https://ecc384.badssl.com/", good, "ecc384"), + ("https://rsa2048.badssl.com/", good, "rsa2048"), + ("https://rsa8192.badssl.com/", dubious_broken, "rsa8192"), + ("http://http.badssl.com/", good, "regular http"), + ("https://http.badssl.com/", bad_broken, "http on https URL"), # FIXME + ("https://cbc.badssl.com/", dubious_broken, "cbc"), + ("https://rc4-md5.badssl.com/", bad, "rc4-md5"), + ("https://rc4.badssl.com/", bad, "rc4"), + ("https://3des.badssl.com/", bad, "3des"), + ("https://null.badssl.com/", bad, "null"), + ("https://mozilla-old.badssl.com/", bad_broken, "mozilla-old"), + ("https://mozilla-intermediate.badssl.com/", dubious_broken, "mozilla-intermediate"), + ("https://mozilla-modern.badssl.com/", good, "mozilla-modern"), + ("https://dh480.badssl.com/", bad, "dh480"), + ("https://dh512.badssl.com/", bad, "dh512"), + ("https://dh1024.badssl.com/", dubious_broken, "dh1024"), + ("https://dh2048.badssl.com/", good, "dh2048"), + ("https://dh-small-subgroup.badssl.com/", bad_broken, "dh-small-subgroup"), + ("https://dh-composite.badssl.com/", bad_broken, "dh-composite"), + ("https://static-rsa.badssl.com/", dubious_broken, "static-rsa"), + ("https://tls-v1-0.badssl.com:1010/", dubious_broken, "tls-v1-0"), + ("https://tls-v1-1.badssl.com:1011/", dubious_broken, "tls-v1-1"), + ("https://invalid-expected-sct.badssl.com/", bad_broken, "invalid-expected-sct"), + ("https://hsts.badssl.com/", good, "hsts"), + ("https://upgrade.badssl.com/", good, "upgrade"), + ("https://preloaded-hsts.badssl.com/", good, "preloaded-hsts"), + ("https://subdomain.preloaded-hsts.badssl.com/", bad, "subdomain.preloaded-hsts"), + ("https://https-everywhere.badssl.com/", good, "https-everywhere"), + ("https://long-extended-subdomain-name-containing-many-letters-and-dashes.badssl.com/", good, + "long-extended-subdomain-name-containing-many-letters-and-dashes"), + ("https://longextendedsubdomainnamewithoutdashesinordertotestwordwrapping.badssl.com/", good, + "longextendedsubdomainnamewithoutdashesinordertotestwordwrapping"), + ("https://superfish.badssl.com/", bad, "(Lenovo) Superfish"), + ("https://edellroot.badssl.com/", bad, "(Dell) eDellRoot"), + ("https://dsdtestprovider.badssl.com/", bad, "(Dell) DSD Test Provider"), + ("https://preact-cli.badssl.com/", bad, "preact-cli"), + ("https://webpack-dev-server.badssl.com/", bad, "webpack-dev-server"), + ("https://mitm-software.badssl.com/", bad, "mitm-software"), + ("https://sha1-2016.badssl.com/", dubious, "sha1-2016"), + ("https://sha1-2017.badssl.com/", bad, "sha1-2017"), +] + + +template evaluate(exception_msg: string, category: Category, desc: string) = + # Evaluate test outcome. Testes flagged as _broken are evaluated and skipped + let raised = (exception_msg.len > 0) + let should_not_raise = category in {good, dubious_broken, bad_broken} + if should_not_raise xor raised: + # we are seeing a known behavior + if category in {good_broken, dubious_broken, bad_broken}: + skip() + if raised: + check exception_msg == "No SSL certificate found." or + exception_msg == "SSL Certificate check failed." or + exception_msg.contains("certificate verify failed") or + exception_msg.contains("key too small") or + exception_msg.contains "shutdown while in init" + + else: + # this is unexpected + if raised: + echo " $# ($#) raised: $#" % [desc, $category, exception_msg] + else: + echo " $# ($#) did not raise" % [desc, $category] + if category in {good, dubious, bad}: + fail() + + +suite "SSL certificate check - httpclient": + + for i, ct in certificate_tests: + + test ct.desc: + var ctx = newContext(verifyMode=CVerifyPeer) + var client = newHttpClient(sslContext=ctx) + let exception_msg = + try: + let a = $client.getContent(ct.url) + "" + except: + getCurrentExceptionMsg() + + evaluate(exception_msg, ct.category, ct.desc) + + + +# threaded tests + + +type + TTOutcome = ref object + desc, exception_msg: string + category: Category + +proc run_t_test(ct: CertTest): TTOutcome {.thread.} = + ## Run test in a {.thread.} - return by ref + result = TTOutcome(desc:ct.desc, exception_msg:"", category: ct.category) + try: + var ctx = newContext(verifyMode=CVerifyPeer) + var client = newHttpClient(sslContext=ctx) + let a = $client.getContent(ct.url) + except: + result.exception_msg = getCurrentExceptionMsg() + + +suite "SSL certificate check - httpclient - threaded": + + # Spawn threads before the "test" blocks + var outcomes = newSeq[FlowVar[TTOutcome]](certificate_tests.len) + for i, ct in certificate_tests: + let t = spawn run_t_test(ct) + outcomes[i] = t + + # create "test" blocks and handle thread outputs + for t in outcomes: + let outcome = ^t # wait for a thread to terminate + + test outcome.desc: + + evaluate(outcome.exception_msg, outcome.category, outcome.desc) + + +# net tests + + +type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string] +const net_tests:array[0..3, NetSocketTest] = [ + ("imap.gmail.com", 993.Port, good, "IMAP"), + ("wrong.host.badssl.com", 443.Port, bad, "wrong.host"), + ("captive-portal.badssl.com", 443.Port, bad, "captive-portal"), + ("expired.badssl.com", 443.Port, bad, "expired"), +] +# TODO: ("null.badssl.com", 443.Port, bad_broken, "null"), + + +suite "SSL certificate check - sockets": + + for ct in net_tests: + + test ct.desc: + + var sock = newSocket() + var ctx = newContext() + ctx.wrapSocket(sock) + let exception_msg = + try: + sock.connect(ct.hostname, ct.port) + "" + except: + getCurrentExceptionMsg() + + evaluate(exception_msg, ct.category, ct.desc) diff --git a/tests/untestable/thttpclient_ssl_disabled.nim b/tests/untestable/thttpclient_ssl_disabled.nim new file mode 100644 index 000000000..4d4ede4de --- /dev/null +++ b/tests/untestable/thttpclient_ssl_disabled.nim @@ -0,0 +1,40 @@ +# +# Nim - SSL integration tests +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +## Warning: this test performs external networking. +## Compile and run with: +## ./bin/nim c -d:nimDisableCertificateValidation -d:ssl -r -p:. tests/untestable/thttpclient_ssl_disabled.nim + +import httpclient, + net, + unittest, + ospaths + +from strutils import contains + +const expired = "https://expired.badssl.com/" + +doAssert defined(nimDisableCertificateValidation) + +suite "SSL certificate check - disabled": + + test "httpclient in insecure mode": + var ctx = newContext(verifyMode = CVerifyPeer) + var client = newHttpClient(sslContext = ctx) + let a = $client.getContent(expired) + + test "httpclient in insecure mode": + var ctx = newContext(verifyMode = CVerifyPeerUseEnvVars) + var client = newHttpClient(sslContext = ctx) + let a = $client.getContent(expired) + + test "net socket in insecure mode": + var sock = newSocket() + var ctx = newContext(verifyMode = CVerifyPeerUseEnvVars) + ctx.wrapSocket(sock) + sock.connect("expired.badssl.com", 443.Port) + sock.close diff --git a/tests/untestable/thttpclient_ssl_env_var.nim b/tests/untestable/thttpclient_ssl_env_var.nim new file mode 100644 index 000000000..32af43579 --- /dev/null +++ b/tests/untestable/thttpclient_ssl_env_var.nim @@ -0,0 +1,74 @@ +# +# Nim - SSL integration tests +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +## Warning: this test performs external networking. +## Compile with: +## ./bin/nim c -d:ssl -p:. tests/untestable/thttpclient_ssl_env_var.nim +## +## Test with: +## SSL_CERT_FILE=BogusInexistentFileName tests/untestable/thttpclient_ssl_env_var +## SSL_CERT_DIR=BogusInexistentDirName tests/untestable/thttpclient_ssl_env_var + +import httpclient, unittest, ospaths +from net import newSocket, newContext, wrapSocket, connect, close, Port, + CVerifyPeerUseEnvVars +from strutils import contains + +const + expired = "https://expired.badssl.com/" + good = "https://google.com/" + + +suite "SSL certificate check": + + test "httpclient with inexistent file": + if existsEnv("SSL_CERT_FILE"): + var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) + var client = newHttpClient(sslContext=ctx) + checkpoint("Client created") + check client.getContent("https://google.com").contains("doctype") + checkpoint("Google ok") + try: + let a = $client.getContent(good) + echo "Connection should have failed" + fail() + except: + echo getCurrentExceptionMsg() + check getCurrentExceptionMsg().contains("certificate verify failed") + + elif existsEnv("SSL_CERT_DIR"): + try: + var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) + var client = newHttpClient(sslContext=ctx) + echo "Should have raised 'No SSL/TLS CA certificates found.'" + fail() + except: + check getCurrentExceptionMsg() == + "No SSL/TLS CA certificates found." + + test "net socket with inexistent file": + if existsEnv("SSL_CERT_FILE"): + var sock = newSocket() + var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) + ctx.wrapSocket(sock) + checkpoint("Socket created") + try: + sock.connect("expired.badssl.com", 443.Port) + fail() + except: + sock.close + check getCurrentExceptionMsg().contains("certificate verify failed") + + elif existsEnv("SSL_CERT_DIR"): + var sock = newSocket() + checkpoint("Socket created") + try: + var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) # raises here + fail() + except: + check getCurrentExceptionMsg() == + "No SSL/TLS CA certificates found." From b6e04eafcec43124f0f2843ed6b146bef3d86e22 Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 20 Mar 2020 17:15:48 +0100 Subject: [PATCH 0179/4254] [ci skip] add back unintentionally removed line --- lib/pure/os.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e90d3c514..d54dc5b83 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2038,6 +2038,7 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): ## Example: This directory structure:: ## dirA / dirB / fileB1.txt ## / dirC + ## / fileA1.txt ## / fileA2.txt ## ## and this code: From 586ebb090b3c7fd2fedbaa24e2b00b7caae4e009 Mon Sep 17 00:00:00 2001 From: cooldome Date: Sat, 21 Mar 2020 06:12:10 +0000 Subject: [PATCH 0180/4254] fixes #13708 (#13711) * fixes #13708 * differentiate between arc and rest of GC Co-authored-by: cooldome --- compiler/lowerings.nim | 4 ++-- compiler/spawn.nim | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index d569c4dc9..091b291c2 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -312,10 +312,10 @@ proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode = result = indirectAccess(newSymNode(a), b, info) -proc genAddrOf*(n: PNode): PNode = +proc genAddrOf*(n: PNode, typeKind = tyPtr): PNode = result = newNodeI(nkAddr, n.info, 1) result[0] = n - result.typ = newType(tyPtr, n.typ.owner) + result.typ = newType(typeKind, n.typ.owner) result.typ.rawAddSon(n.typ) proc genDeref*(n: PNode; k = nkHiddenDeref): PNode = diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 382237e70..2c206b599 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -65,14 +65,24 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: P vpart[2] = if varInit.isNil: v else: vpart[1] varSection.add vpart if varInit != nil: - if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions: - varInit.add newFastAsgnStmt(newSymNode(result), v) - else: - let deepCopyCall = newNodeI(nkCall, varInit.info, 3) - deepCopyCall[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy)) - deepCopyCall[1] = newSymNode(result) - deepCopyCall[2] = v - varInit.add deepCopyCall + if g.config.selectedGC in {gcArc, gcOrc}: + if typ.attachedOps[attachedAsgn] != nil: + var call = newNode(nkCall) + call.add newSymNode(typ.attachedOps[attachedAsgn]) + call.add genAddrOf(newSymNode(result), tyVar) + call.add v + varInit.add call + else: + varInit.add newFastAsgnStmt(newSymNode(result), v) + else: + if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions: + varInit.add newFastAsgnStmt(newSymNode(result), v) + else: + let deepCopyCall = newNodeI(nkCall, varInit.info, 3) + deepCopyCall[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy)) + deepCopyCall[1] = newSymNode(result) + deepCopyCall[2] = v + varInit.add deepCopyCall discard """ We generate roughly this: From 86b9435138109441ffaa5a9c221f641ec3ed4b05 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sun, 22 Mar 2020 06:52:44 +0900 Subject: [PATCH 0181/4254] Add EPOLLEXCLUSIVE (#13718) --- lib/posix/epoll.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 2d38137bb..2236bb16b 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -23,6 +23,7 @@ const EPOLLWRBAND* = 0x00000200 EPOLLMSG* = 0x00000400 EPOLLRDHUP* = 0x00002000 + EPOLLEXCLUSIVE* = 1 shl 28 EPOLLWAKEUP* = 1 shl 29 EPOLLONESHOT* = 1 shl 30 EPOLLET* = 1 shl 31 From 047d3af6daf73c378677f2cb3d5dbde80c35f790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Sun, 22 Mar 2020 19:35:55 +0100 Subject: [PATCH 0182/4254] fix #13720 (#13721) --- compiler/types.nim | 2 +- tests/types/tillegaltuplerecursion.nim | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 4fcc3a2cf..6b596b22e 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1623,7 +1623,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = if isTupleRecursive(t[i], cycleDetectorCopy): return true of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyLent, tySink, - tyArray, tyUncheckedArray, tySequence: + tyArray, tyUncheckedArray, tySequence, tyDistinct: return isTupleRecursive(t.lastSon, cycleDetector) else: return false diff --git a/tests/types/tillegaltuplerecursion.nim b/tests/types/tillegaltuplerecursion.nim index c822e8880..cb75ad9c3 100644 --- a/tests/types/tillegaltuplerecursion.nim +++ b/tests/types/tillegaltuplerecursion.nim @@ -35,4 +35,6 @@ type children: ptr MyType9 MyType9 = tuple - children: MyType0 + children: MyType10 + + MyType10 = distinct seq[MyType0] From 474dd981250898e32275c918cbd4b183a18bffd8 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 21 Mar 2020 09:24:10 +0100 Subject: [PATCH 0183/4254] typo --- compiler/ccgtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index dbdd0a6c7..f939eb326 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -532,7 +532,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, unionBody.add("struct {") else: if hasAttribute in CC[m.config.cCompiler].props: - unionBody.add("struct __attribute__((__packed__)){" ) + unionBody.add("struct __attribute__((__packed__)){") else: unionBody.addf("#pragma pack(push, 1)$nstruct{", []) unionBody.add(a) From 64ffa17f0fac789f259d3db48a28f1605805a366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Sun, 22 Mar 2020 20:01:01 +0100 Subject: [PATCH 0184/4254] fixes #13715 (#13716) * fixes #13715 * fix test --- compiler/types.nim | 5 ++++- tests/errmsgs/t8434.nim | 2 +- tests/types/tillegalseqrecursion.nim | 6 ++++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/types/tillegalseqrecursion.nim diff --git a/compiler/types.nim b/compiler/types.nim index 6b596b22e..33c81f9cc 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -593,7 +593,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyUncheckedArray: result = "UncheckedArray[" & typeToString(t[0]) & ']' of tySequence: - result = "seq[" & typeToString(t[0]) & ']' + if t.sym != nil and prefer != preferResolved: + result = t.sym.name.s + else: + result = "seq[" & typeToString(t[0]) & ']' of tyOpt: result = "opt[" & typeToString(t[0]) & ']' of tyOrdinal: diff --git a/tests/errmsgs/t8434.nim b/tests/errmsgs/t8434.nim index c8bc1193b..5d962ee5c 100644 --- a/tests/errmsgs/t8434.nim +++ b/tests/errmsgs/t8434.nim @@ -3,7 +3,7 @@ discard """ nimout: '''but expected one of: proc fun0[T1: int | float | object | array | seq](a1: T1; a2: int) first type mismatch at position: 1 - required type for a1: T1: int or float or object or array or seq[T] + required type for a1: T1: int or float or object or array or seq but expression 'byte(1)' is of type: byte expression: fun0(byte(1), 0) diff --git a/tests/types/tillegalseqrecursion.nim b/tests/types/tillegalseqrecursion.nim new file mode 100644 index 000000000..9221bb38a --- /dev/null +++ b/tests/types/tillegalseqrecursion.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "illegal recursion in type 'CyclicSeq'" +""" +# issue #13715 +type + CyclicSeq = seq[ref CyclicSeq] From a5f02cac85281fc2804e910f330f0c11d3c4f77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Sun, 22 Mar 2020 20:03:51 +0100 Subject: [PATCH 0185/4254] fix #13417 (#13712) * fix #13417 * add test --- compiler/transf.nim | 21 ++++++++++----------- tests/iter/titer_issues.nim | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index c1af6c23f..2bd64804e 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -554,14 +554,14 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = # inline context. if formal.kind == tyTypeDesc: return paDirectMapping if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}: - case arg.kind - of nkStmtListExpr: - return paComplexOpenarray + case arg.skipHidden.kind of nkBracket: return paFastAsgnTakeTypeFromArg + of nkSym: + return paDirectMapping else: - return paDirectMapping # XXX really correct? - # what if ``arg`` has side-effects? + return paComplexOpenarray + case arg.kind of nkEmpty..nkNilLit: result = paDirectMapping @@ -569,14 +569,14 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = result = putArgInto(arg[0], formal) of nkCurly, nkBracket: for i in 0..= ff.n.len: return result @@ -671,9 +671,8 @@ proc transformFor(c: PTransf, n: PNode): PNode = idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! of paComplexOpenarray: - let typ = newType(tySequence, formal.owner) - addSonSkipIntLit(typ, formal.typ[0]) - var temp = newTemp(c, typ, formal.info) + # arrays will deep copy here (pretty bad). + var temp = newTemp(c, arg.typ, formal.info) addVar(v, temp) stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg)) idNodeTablePut(newC.mapping, formal, temp) diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index a7830dfab..b8a117e59 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -213,3 +213,24 @@ block t2023_objiter: var o = init() echo(o.iter()) + +block: + # bug #13417 + + var effectCounterP1 = 0 + + proc p1(): seq[int] = + inc effectCounterP1 + @[1,2] + + iterator ip1(v: openArray[int]): auto = + for x in v: + yield x + + var effectCounterLoop = 0 + + for x in ip1(p1()): + inc effectCounterLoop + + doAssert effectCounterP1 == 1 + doAssert effectCounterLoop == 2 From 4c1fdc2e8ff3851b2a6412681680337acda3477d Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 22 Mar 2020 19:06:45 +0100 Subject: [PATCH 0186/4254] Windows API callbacks cannot raise exceptions --- lib/windows/winlean.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 9793429b2..13a70d6ef 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -961,13 +961,13 @@ type dwRemoteAddressLength: DWORD, lpdwBytesReceived: ptr DWORD, lpOverlapped: POVERLAPPED): bool {. - stdcall,gcsafe.} + stdcall, gcsafe, raises: [].} WSAPROC_CONNECTEX* = proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, lpSendBuffer: pointer, dwSendDataLength: DWORD, lpdwBytesSent: ptr DWORD, lpOverlapped: POVERLAPPED): bool {. - stdcall,gcsafe.} + stdcall, gcsafe, raises: [].} WSAPROC_GETACCEPTEXSOCKADDRS* = proc(lpOutputBuffer: pointer, dwReceiveDataLength: DWORD, @@ -977,7 +977,7 @@ type LocalSockaddrLength: ptr cint, RemoteSockaddr: ptr PSockAddr, RemoteSockaddrLength: ptr cint) {. - stdcall,gcsafe.} + stdcall, gcsafe, raises: [].} const WT_EXECUTEDEFAULT* = 0x00000000'i32 From ef2566218e701e6294608c6c30a367624786dcd6 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 22 Mar 2020 19:32:37 +0100 Subject: [PATCH 0187/4254] better error messages for Nim's effect system --- changelog.md | 1 + compiler/semcall.nim | 17 ++++++++++++++ compiler/sempass2.nim | 46 +++++++++++++++++++++---------------- tests/effects/teffects1.nim | 3 ++- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/changelog.md b/changelog.md index d5d1be956..a471ffbb2 100644 --- a/changelog.md +++ b/changelog.md @@ -189,6 +189,7 @@ echo f this is **very bad** style. You should inherit from `ValueError`, `IOError`, `OSError` or from a different specific exception type that inherits from `CatchableError` and cannot be confused with a `Defect`. +- The error reporting for Nim's effect system has been improved. ## Bugfixes diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 55ff80b6c..d8834dc90 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -136,6 +136,23 @@ proc effectProblem(f, a: PType; result: var string) = elif tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags: result.add "\n This expression can have side effects. Annotate the " & "proc with {.noSideEffect.} to get extended error information." + else: + case compatibleEffects(f, a) + of efCompat: discard + of efRaisesDiffer: + result.add "\n The `.raises` requirements differ." + of efRaisesUnknown: + result.add "\n The `.raises` requirements differ. Annotate the " & + "proc with {.raises: [].} to get extended error information." + of efTagsDiffer: + result.add "\n The `.tags` requirements differ." + of efTagsUnknown: + result.add "\n The `.tags` requirements differ. Annotate the " & + "proc with {.tags: [].} to get extended error information." + of efLockLevelsDiffer: + result.add "\n The `.locks` requirements differ. Annotate the " & + "proc with {.locks: 0.} to get extended error information." + proc renderNotLValue(n: PNode): string = result = $n diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d5514d8d1..c8ad14c41 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -281,8 +281,14 @@ proc addToIntersection(inter: var TIntersection, s: int) = return inter.add((id: s, count: 1)) -proc throws(tracked, n: PNode) = - if n.typ == nil or n.typ.kind != tyError: tracked.add n +proc throws(tracked, n, orig: PNode) = + if n.typ == nil or n.typ.kind != tyError: + if orig != nil: + let x = copyNode(n) + x.info = orig.info + tracked.add x + else: + tracked.add n proc getEbase(g: ModuleGraph; info: TLineInfo): PType = result = g.sysTypeFromName(info, "Exception") @@ -302,34 +308,34 @@ proc createTag(g: ModuleGraph; n: PNode): PNode = result.typ = g.sysTypeFromName(n.info, "RootEffect") if not n.isNil: result.info = n.info -proc addEffect(a: PEffects, e: PNode, useLineInfo=true) = +proc addEffect(a: PEffects, e, comesFrom: PNode) = assert e.kind != nkRaiseStmt var aa = a.exc for i in a.bottom.. Date: Sun, 22 Mar 2020 21:00:37 +0100 Subject: [PATCH 0188/4254] introduce getPeerCertificates, fixes #13299 (#13650) * make i2d_X509 and d2i_X509 always available i2d_X509 and d2i_X509 have been available in all versions of OpenSSL, so make them available even if nimDisableCertificateValidation is set. * introduce getPeerCertificates, fixes #13299 getPeerCertificates retrieves the verified certificate chain of the peer we are connected to through an SSL-wrapped Socket/AsyncSocket. This introduces the new type Certificate which stores a DER-encoded X509 certificate. --- changelog.md | 3 +++ lib/pure/asyncnet.nim | 13 ++++++++++ lib/pure/net.nim | 34 +++++++++++++++++++++++++ lib/wrappers/openssl.nim | 54 ++++++++++++++++++++++++---------------- 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/changelog.md b/changelog.md index a471ffbb2..622f9de0b 100644 --- a/changelog.md +++ b/changelog.md @@ -119,6 +119,9 @@ echo f - Added a new module, `std / compilesettings` for querying the compiler about diverse configuration settings. - `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. +- Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for + retrieving the verified certificate chain of the peer we are connected to + through an SSL-wrapped `Socket`/`AsyncSocket`. ## Library changes diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 88852fb84..8bdab88b1 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -95,6 +95,8 @@ ## runForever() ## +include "system/inclrtl" + import asyncdispatch import nativesockets import net @@ -743,6 +745,17 @@ when defineSsl: of handshakeAsServer: sslSetAcceptState(socket.sslHandle) + proc getPeerCertificates*(socket: AsyncSocket): seq[Certificate] {.since: (1, 1).} = + ## Returns the certificate chain received by the peer we are connected to + ## through the given socket. + ## The handshake must have been completed and the certificate chain must + ## have been verified successfully or else an empty sequence is returned. + ## The chain is ordered from leaf certificate to root certificate. + if not socket.isSsl: + result = newSeq[Certificate]() + else: + result = getPeerCertificates(socket.sslHandle) + proc getSockOpt*(socket: AsyncSocket, opt: SOBool, level = SOL_SOCKET): bool {. tags: [ReadIOEffect].} = ## Retrieves option ``opt`` as a boolean value. diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ca3d37259..2f43573ac 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -64,6 +64,8 @@ ## socket.acceptAddr(client, address) ## echo("Client connected from: ", address) +include "system/inclrtl" + {.deadCodeElim: on.} # dce option deprecated import nativesockets, os, strutils, parseutils, times, sets, options, std/monotimes @@ -82,6 +84,8 @@ when defineSsl: when defineSsl: type + Certificate* = string ## DER encoded certificate + SslError* = object of Exception SslCVerifyMode* = enum @@ -747,6 +751,36 @@ when defineSsl: let ret = SSL_accept(socket.sslHandle) socketError(socket, ret) + proc getPeerCertificates*(sslHandle: SslPtr): seq[Certificate] {.since: (1, 1).} = + ## Returns the certificate chain received by the peer we are connected to + ## through the OpenSSL connection represented by ``sslHandle``. + ## The handshake must have been completed and the certificate chain must + ## have been verified successfully or else an empty sequence is returned. + ## The chain is ordered from leaf certificate to root certificate. + result = newSeq[Certificate]() + if SSL_get_verify_result(sslHandle) != X509_V_OK: + return + let stack = SSL_get0_verified_chain(sslHandle) + if stack == nil: + return + let length = OPENSSL_sk_num(stack) + if length == 0: + return + for i in 0 .. length - 1: + let x509 = cast[PX509](OPENSSL_sk_value(stack, i)) + result.add(i2d_X509(x509)) + + proc getPeerCertificates*(socket: Socket): seq[Certificate] {.since: (1, 1).} = + ## Returns the certificate chain received by the peer we are connected to + ## through the given socket. + ## The handshake must have been completed and the certificate chain must + ## have been verified successfully or else an empty sequence is returned. + ## The chain is ordered from leaf certificate to root certificate. + if not socket.isSsl: + result = newSeq[Certificate]() + else: + result = getPeerCertificates(socket.sslHandle) + proc getSocketError*(socket: Socket): OSErrorCode = ## Checks ``osLastError`` for a valid error. If it has been reset it uses ## the last error stored in the socket object. diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 789b3611c..94da4fc79 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -91,6 +91,7 @@ type PSslPtr* = ptr SslPtr SslCtx* = SslPtr PSSL_METHOD* = SslPtr + PSTACK* = SslPtr PX509* = SslPtr PX509_NAME* = SslPtr PEVP_MD* = SslPtr @@ -359,6 +360,8 @@ proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} proc SSL_get_SSL_CTX*(ssl: SslPtr): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} proc SSL_set_SSL_CTX*(ssl: SslPtr, ctx: SslCtx): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_get0_verified_chain*(ssl: SslPtr): PSTACK {.cdecl, dynlib: DLLSSLName, + importc.} proc SSL_CTX_new*(meth: PSSL_METHOD): SslCtx{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_load_verify_locations*(ctx: SslCtx, CAfile: cstring, @@ -426,6 +429,35 @@ proc ERR_peek_last_error*(): cint{.cdecl, dynlib: DLLUtilName, importc.} proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.} +proc OPENSSL_sk_num*(stack: PSTACK): int {.cdecl, dynlib: DLLSSLName, importc.} + +proc OPENSSL_sk_value*(stack: PSTACK, index: int): pointer {.cdecl, + dynlib: DLLSSLName, importc.} + +proc d2i_X509*(px: ptr PX509, i: ptr ptr cuchar, len: cint): PX509 {.cdecl, + dynlib: DLLSSLName, importc.} + +proc i2d_X509*(cert: PX509; o: ptr ptr cuchar): cint {.cdecl, + dynlib: DLLSSLName, importc.} + +proc d2i_X509*(b: string): PX509 = + ## decode DER/BER bytestring into X.509 certificate struct + var bb = b.cstring + let i = cast[ptr ptr cuchar](addr bb) + let ret = d2i_X509(addr result, i, b.len.cint) + if ret.isNil: + raise newException(Exception, "X.509 certificate decoding failed") + +proc i2d_X509*(cert: PX509): string = + ## encode `cert` to DER string + let encoded_length = i2d_X509(cert, nil) + result = newString(encoded_length) + var q = result.cstring + let o = cast[ptr ptr cuchar](addr q) + let length = i2d_X509(cert, o) + if length.int <= 0: + raise newException(Exception, "X.509 certificate encoding failed") + when not useWinVersion and not defined(macosx) and not defined(android) and not defined(nimNoAllocForSSL): proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLUtilName, importc.} @@ -688,30 +720,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows): proc X509_STORE_set_trust*(ctx: PX509_STORE; trust: cint): cint proc X509_STORE_add_cert*(ctx: PX509_STORE; x: PX509): cint - proc d2i_X509*(px: ptr PX509, i: ptr ptr cuchar, len: cint): PX509 - - proc i2d_X509*(cert: PX509; o: ptr ptr cuchar): cint - {.pop.} - proc d2i_X509*(b: string): PX509 = - ## decode DER/BER bytestring into X.509 certificate struct - var bb = b.cstring - let i = cast[ptr ptr cuchar](addr bb) - let ret = d2i_X509(addr result, i, b.len.cint) - if ret.isNil: - raise newException(Exception, "X.509 certificate decoding failed") - - proc i2d_X509*(cert: PX509): string = - ## encode `cert` to DER string - let encoded_length = i2d_X509(cert, nil) - result = newString(encoded_length) - var q = result.cstring - let o = cast[ptr ptr cuchar](addr q) - let length = i2d_X509(cert, o) - if length.int <= 0: - raise newException(Exception, "X.509 certificate encoding failed") - when isMainModule: # A simple certificate test let certbytes = readFile("certificate.der") From 7ee08b8cf6e98312986c821119e4c779505ed6aa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 23 Mar 2020 09:57:17 +0100 Subject: [PATCH 0189/4254] Revert "fix #13417 (#13712)" (#13728) This reverts commit a5f02cac85281fc2804e910f330f0c11d3c4f77b. --- compiler/transf.nim | 21 +++++++++++---------- tests/iter/titer_issues.nim | 21 --------------------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 2bd64804e..c1af6c23f 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -554,14 +554,14 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = # inline context. if formal.kind == tyTypeDesc: return paDirectMapping if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}: - case arg.skipHidden.kind + case arg.kind + of nkStmtListExpr: + return paComplexOpenarray of nkBracket: return paFastAsgnTakeTypeFromArg - of nkSym: - return paDirectMapping else: - return paComplexOpenarray - + return paDirectMapping # XXX really correct? + # what if ``arg`` has side-effects? case arg.kind of nkEmpty..nkNilLit: result = paDirectMapping @@ -569,14 +569,14 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = result = putArgInto(arg[0], formal) of nkCurly, nkBracket: for i in 0..= ff.n.len: return result @@ -671,8 +671,9 @@ proc transformFor(c: PTransf, n: PNode): PNode = idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! of paComplexOpenarray: - # arrays will deep copy here (pretty bad). - var temp = newTemp(c, arg.typ, formal.info) + let typ = newType(tySequence, formal.owner) + addSonSkipIntLit(typ, formal.typ[0]) + var temp = newTemp(c, typ, formal.info) addVar(v, temp) stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg)) idNodeTablePut(newC.mapping, formal, temp) diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index b8a117e59..a7830dfab 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -213,24 +213,3 @@ block t2023_objiter: var o = init() echo(o.iter()) - -block: - # bug #13417 - - var effectCounterP1 = 0 - - proc p1(): seq[int] = - inc effectCounterP1 - @[1,2] - - iterator ip1(v: openArray[int]): auto = - for x in v: - yield x - - var effectCounterLoop = 0 - - for x in ip1(p1()): - inc effectCounterLoop - - doAssert effectCounterP1 == 1 - doAssert effectCounterLoop == 2 From fa06203e90d9bb9211d0b6b9726fc9f2c5dc80ad Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Mon, 23 Mar 2020 06:08:37 -0400 Subject: [PATCH 0190/4254] add error for missing commandLineParams (#13719) * add error for missing commandLineParams * fixup * rewrite --- lib/pure/os.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index d54dc5b83..fda482bc3 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2770,6 +2770,10 @@ when declared(paramCount) or defined(nimdoc): result = @[] for i in 1..paramCount(): result.add(paramStr(i)) +else: + proc commandLineParams*(): seq[TaintedString] {.error: + "commandLineParams() unsupported by dynamic libraries".} = + discard when not weirdTarget and (defined(freebsd) or defined(dragonfly)): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, From 913bc95964458d3eb2fc4d8a108031e6b9398da5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 23 Mar 2020 03:15:45 -0700 Subject: [PATCH 0191/4254] new syntax for lvalue references: `var b {.byaddr.} = expr` (#13508) * new syntax for lvalue references: `var b {.byaddr.} = expr` * on type mismatch, `???(0, 0)` not shown anymore * * compiler now lowers `var a: {.foo.}: MyType = expr` to foo(a, MyType, expr) * new pragmas.byaddr defined in pure library code exploiting this lowering * skip `template foo() {.pragma.}` --- changelog.md | 5 ++- compiler/semstmts.nim | 46 +++++++++++++++++++++++++ lib/std/pragmas.nim | 19 +++++++++++ tests/stdlib/tpragmas.nim | 70 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 lib/std/pragmas.nim create mode 100644 tests/stdlib/tpragmas.nim diff --git a/changelog.md b/changelog.md index 622f9de0b..daed6c02b 100644 --- a/changelog.md +++ b/changelog.md @@ -149,7 +149,7 @@ echo f - `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs - `net.newContext` now performs SSL Certificate checking on Linux and OSX. Define `nimDisableCertificateValidation` to disable it globally. - +- new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by `import pragmas` ## Language additions @@ -159,6 +159,9 @@ echo f - `=sink` type bound operator is now optional. Compiler can now use combination of `=destroy` and `copyMem` to move objects efficiently. +- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for non builtin pragmas, + enabling things like lvalue references, see `pragmas.byaddr` + ## Language changes - Unsigned integer operators have been fixed to allow promotion of the first operand. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index cdb47d2a4..30f14b524 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -431,7 +431,53 @@ proc setVarType(c: PContext; v: PSym, typ: PType) = "; new type is: " & typeToString(typ, preferDesc)) v.typ = typ +proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = + var b = a[0] + if b.kind == nkPragmaExpr: + if b[1].len != 1: + # we could in future support pragmas w args eg: `var foo {.bar:"goo".} = expr` + return nil + let nodePragma = b[1][0] + # see: `singlePragma` + if nodePragma.kind notin {nkIdent, nkAccQuoted}: + return nil + let ident = considerQuotedIdent(c, nodePragma) + var userPragma = strTableGet(c.userPragmas, ident) + if userPragma != nil: return nil + + let w = nodePragma.whichPragma + if n.kind == nkVarSection and w in varPragmas or + n.kind == nkLetSection and w in letPragmas or + n.kind == nkConstSection and w in constPragmas: + return nil + + let sym = searchInScopes(c, ident) + if sfCustomPragma in sym.flags: return nil # skip `template myAttr() {.pragma.}` + let lhs = b[0] + let clash = strTableGet(c.currentScope.symbols, lhs.ident) + if clash != nil: + # refs https://github.com/nim-lang/Nim/issues/8275 + wrongRedefinition(c, lhs.info, lhs.ident.s, clash.info) + + result = newTree(nkCall) + doAssert nodePragma.kind in {nkIdent, nkAccQuoted}, $nodePragma.kind + result.add nodePragma + result.add lhs + if a[1].kind != nkEmpty: + result.add a[1] + else: + result.add newNodeIT(nkNilLit, a.info, c.graph.sysTypes[tyNil]) + result.add a[2] + result.info = a.info + let ret = newNodeI(nkStmtList, a.info) + ret.add result + result = semExprNoType(c, ret) + proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = + if n.len == 1: + result = semLowerLetVarCustomPragma(c, n[0], n) + if result!=nil: return result + var b: PNode result = copyNode(n) for i in 0.. Date: Mon, 23 Mar 2020 12:03:49 +0100 Subject: [PATCH 0192/4254] trees.nim: compare floating points by their bitpatterns because NaN comparisions are always false (WORST design in the history of computing!) --- compiler/trees.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index 3b715053e..8c89ccca9 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -39,7 +39,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal + of nkFloatLit..nkFloat64Lit: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkCommentStmt: result = a.comment == b.comment of nkEmpty, nkNilLit, nkType: result = true From ee440df02dfae8408d8129faac3a963c5624901d Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 23 Mar 2020 12:04:23 +0100 Subject: [PATCH 0193/4254] disable even more of scope based destruction handling; fixes #13709 --- compiler/injectdestructors.nim | 105 ++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 7 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index dec437427..743bf9e23 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -499,7 +499,6 @@ proc handleNested(n, dest: PNode; c: var Con; mode: ProcessMode): PNode = result[last] = processCall(n[last]) # A statement list does not introduce a scope, the AST can # contain silly nested statement lists. - #result = handleScope(n, dest, n.typ, 0, c, mode) of nkBlockStmt, nkBlockExpr: result = handleScope(n, dest, n.typ, 1, c, mode) of nkIfStmt, nkIfExpr: @@ -513,13 +512,11 @@ proc handleNested(n, dest: PNode; c: var Con; mode: ProcessMode): PNode = result.add handleScope(n[i], dest, n[i][^1].typ, n[i].len - 1, c, mode) of nkWhen: # This should be a "when nimvm" node. result = copyTree(n) - result[1][0] = handleScope(n[1][0], dest, n[1][0][^1].typ, 0, c, mode) + result[1][0] = processCall(n[1][0]) + # handleScope(n[1][0], dest, n[1][0][^1].typ, 0, c, mode) of nkWhileStmt: - #result = copyNode(n) inc c.inLoop result = handleScope(n, dest, nil, 0, c, mode) - #result.add p(n[0], c, normal) - #result.add p(n[1], c, normal) dec c.inLoop else: assert(false) @@ -634,10 +631,101 @@ proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = elif ri.kind != nkEmpty: res.add moveOrCopy(v, ri, c) +template handleNestedTempl(n: untyped, processCall: untyped) = + case n.kind + of nkStmtList, nkStmtListExpr: + if n.len == 0: return n + result = copyNode(n) + for i in 0.. Date: Mon, 23 Mar 2020 12:06:33 +0100 Subject: [PATCH 0194/4254] trees.nim: compare floating points by their bitpatterns because NaN comparisions are always false (WORST design in the history of computing!) --- compiler/trees.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index 8c89ccca9..cd26b2b4f 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -64,7 +64,7 @@ proc sameTree*(a, b: PNode): bool = result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal + of nkFloatLit..nkFloat64Lit: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true else: From e05fd1d00fb940aa89fdd7bd9f98e091abfd378b Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 23 Mar 2020 13:05:29 +0100 Subject: [PATCH 0195/4254] hotfix: make 'nim doc nimhcr' work on all platforms --- lib/nimhcr.nim | 58 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 1bafa98cb..372ee1973 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -228,39 +228,39 @@ when defined(createNimHcr): {.pragma: nimhcr, compilerProc, exportc, dynlib.} - when hostCPU in ["i386", "amd64"]: - type - ShortJumpInstruction {.packed.} = object - opcode: byte - offset: int32 + # XXX these types are CPU specific and need ARM etc support + type + ShortJumpInstruction {.packed.} = object + opcode: byte + offset: int32 - LongJumpInstruction {.packed.} = object - opcode1: byte - opcode2: byte - offset: int32 - absoluteAddr: pointer + LongJumpInstruction {.packed.} = object + opcode1: byte + opcode2: byte + offset: int32 + absoluteAddr: pointer - proc writeJump(jumpTableEntry: ptr LongJumpInstruction, targetFn: pointer) = - let - jumpFrom = jumpTableEntry.shift(sizeof(ShortJumpInstruction)) - jumpDistance = distance(jumpFrom, targetFn) + proc writeJump(jumpTableEntry: ptr LongJumpInstruction, targetFn: pointer) = + let + jumpFrom = jumpTableEntry.shift(sizeof(ShortJumpInstruction)) + jumpDistance = distance(jumpFrom, targetFn) - if abs(jumpDistance) < 0x7fff0000: - let shortJump = cast[ptr ShortJumpInstruction](jumpTableEntry) - shortJump.opcode = 0xE9 # relative jump - shortJump.offset = int32(jumpDistance) + if abs(jumpDistance) < 0x7fff0000: + let shortJump = cast[ptr ShortJumpInstruction](jumpTableEntry) + shortJump.opcode = 0xE9 # relative jump + shortJump.offset = int32(jumpDistance) + else: + jumpTableEntry.opcode1 = 0xff # indirect absolute jump + jumpTableEntry.opcode2 = 0x25 + when hostCPU == "i386": + # on x86 we write the absolute address of the following pointer + jumpTableEntry.offset = cast[int32](addr jumpTableEntry.absoluteAddr) else: - jumpTableEntry.opcode1 = 0xff # indirect absolute jump - jumpTableEntry.opcode2 = 0x25 - when hostCPU == "i386": - # on x86 we write the absolute address of the following pointer - jumpTableEntry.offset = cast[int32](addr jumpTableEntry.absoluteAddr) - else: - # on x64, we use a relative address for the same location - jumpTableEntry.offset = 0 - jumpTableEntry.absoluteAddr = targetFn + # on x64, we use a relative address for the same location + jumpTableEntry.offset = 0 + jumpTableEntry.absoluteAddr = targetFn - elif hostCPU == "arm": + if hostCPU == "arm": const jumpSize = 8 elif hostCPU == "arm64": const jumpSize = 16 @@ -556,7 +556,7 @@ when defined(createNimHcr): inc(generation) trace "HCR RELOADING: ", generation - var traversedHandlerModules = initSet[string]() + var traversedHandlerModules = initHashSet[string]() proc recursiveExecuteHandlers(isBefore: bool, module: string) = # do not process an already traversed module From fc5dd11b3da555a3617c1163dc3105973d101b97 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 23 Mar 2020 15:47:10 +0100 Subject: [PATCH 0196/4254] fixes #13722 (#13729) * fixes #13722 * better fix --- compiler/injectdestructors.nim | 2 +- lib/pure/base64.nim | 28 ++++++++++++++++++++-------- tests/stdlib/tbase64.nim | 9 ++++++--- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 743bf9e23..29199aa41 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -616,7 +616,7 @@ proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = # unpacked tuple needs reset at every loop iteration res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) elif {sfGlobal, sfThread} * v.sym.flags == {sfGlobal}: - c.graph.globalDestructors.add genDestroy(c, v) + c.graph.globalDestructors.add genDestroy(c, v) else: # We always translate 'var v = f()' into bitcopies. If 'v' is in a loop, # the destruction at the loop end will free the resources. Other assignments diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index aaad26f96..b715e749e 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -72,13 +72,17 @@ let cb64 = cbBase('+', '/') cb64safe = cbBase('-', '_') +const + cb64VM = cbBase('+', '/') + cb64safeVM = cbBase('-', '_') + const invalidChar = 255 -template encodeInternal(s: typed, alphabet: ptr array[64, char]): untyped = +template encodeSize(size: int): int = (size * 4 div 3) + 6 + +template encodeInternal(s, alphabet: typed): untyped = ## encodes `s` into base64 representation. - proc encodeSize(size: int): int = - return (size * 4 div 3) + 6 result.setLen(encodeSize(s.len)) @@ -94,7 +98,7 @@ template encodeInternal(s: typed, alphabet: ptr array[64, char]): untyped = n = exp inc inputIndex - template outputChar(x: untyped) = + template outputChar(x: typed) = result[outputIndex] = alphabet[x and 63] inc outputIndex @@ -129,6 +133,16 @@ template encodeInternal(s: typed, alphabet: ptr array[64, char]): untyped = result.setLen(outputIndex) +template encodeImpl() {.dirty.} = + when nimVM: + block: + let lookupTableVM = if safe: cb64safeVM else: cb64VM + encodeInternal(s, lookupTableVM) + else: + block: + let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) + encodeInternal(s, lookupTable) + proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string = ## Encodes `s` into base64 representation. ## @@ -148,8 +162,7 @@ proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string = assert encode(['n', 'i', 'm']) == "bmlt" assert encode(@['n', 'i', 'm']) == "bmlt" assert encode([1, 2, 3, 4, 5]) == "AQIDBAU=" - let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) - encodeInternal(s, lookupTable) + encodeImpl() proc encode*(s: string, safe = false): string = ## Encodes ``s`` into base64 representation. @@ -167,8 +180,7 @@ proc encode*(s: string, safe = false): string = ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encode("Hello World") == "SGVsbG8gV29ybGQ=" - let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) - encodeInternal(s, lookupTable) + encodeImpl() proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = ## Encodes ``s`` into base64 representation as lines. diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index e5b13642c..19b126437 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -1,8 +1,13 @@ discard """ - output: "OK" + output: '''YQ==''' + nimout: '''YQ==''' """ import base64 +import base64 +static: echo encode("a") +echo encode("a") + proc main() = doAssert encode("Hello World") == "SGVsbG8gV29ybGQ=" doAssert encode("leasure.") == "bGVhc3VyZS4=" @@ -54,6 +59,4 @@ proc main() = doAssert encode("", safe = true) == "" doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==" - echo "OK" - main() From 4fb7f076d89ca52704c78e0c984d41ba9d48ae5b Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 23 Mar 2020 20:03:07 +0100 Subject: [PATCH 0197/4254] fix #13731, ambiguous repr of pointers (#13732) --- lib/system/repr_v2.nim | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index beca1d842..6bf45b4ce 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -47,7 +47,7 @@ proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.} proc repr*(p: pointer): string = ## repr of pointer as its hexadecimal value - if p == nil: + if p == nil: result = "nil" else: when nimvm: @@ -66,7 +66,7 @@ template repr*(x: distinct): string = template repr*(t: typedesc): string = $t -proc reprObject[T: tuple|object](res: var string, x: T) = +proc reprObject[T: tuple|object](res: var string, x: T) = res.add '(' var firstElement = true const isNamed = T is object or isNamedTuple(T) @@ -98,10 +98,6 @@ proc repr*[T: tuple|object](x: T): string = when T is object: result = $typeof(x) reprObject(result, x) - -proc repr*[T](x: ptr T): string = - result.add repr(pointer(x)) & " " - result.add repr(x[]) proc repr*[T](x: ref T | ptr T): string = if isNil(x): return "nil" From c0dbcffca643ac79e0c03c9509e92f5841b38a94 Mon Sep 17 00:00:00 2001 From: Euan Date: Mon, 23 Mar 2020 20:39:40 +0000 Subject: [PATCH 0198/4254] __stderrp and friends are only on FreeBSD & DragonFlyBSD. (#13735) --- lib/system/ansi_c.nim | 2 +- lib/system/io.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 1ff15611c..0b4b25992 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -117,7 +117,7 @@ type CFilePtr* = ptr CFile ## The type representing a file handle. # duplicated between io and ansi_c -const stdioUsesMacros = (defined(osx) or defined(bsd)) and not defined(emscripten) +const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined(dragonfly)) and not defined(emscripten) const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr" const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout" const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin" diff --git a/lib/system/io.nim b/lib/system/io.nim index 7b9a893bb..98d9347be 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -39,7 +39,7 @@ type # text file handling: when not defined(nimscript) and not defined(js): # duplicated between io and ansi_c - const stdioUsesMacros = (defined(osx) or defined(bsd)) and not defined(emscripten) + const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined(dragonfly)) and not defined(emscripten) const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr" const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout" const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin" From 5300baae062b892bb133850d88428a34d66592ed Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 24 Mar 2020 09:46:30 +0100 Subject: [PATCH 0199/4254] use nimEmulateOverflowChecks for ARM/ARM64 --- config/nim.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/nim.cfg b/config/nim.cfg index bbfac1f31..9f152b879 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -307,6 +307,10 @@ tcc.options.always = "-w" @end @end +@if arm or arm64: + --define:nimEmulateOverflowChecks +@end + @if nimv019: --multimethods:on --oldAst:on From 46c827be6a959be3d3bb840d1582bac8fc55bda6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 24 Mar 2020 02:14:49 -0700 Subject: [PATCH 0200/4254] fix #13737 (#13738) --- compiler/semstmts.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 30f14b524..6b01e241b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -452,7 +452,8 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = return nil let sym = searchInScopes(c, ident) - if sfCustomPragma in sym.flags: return nil # skip `template myAttr() {.pragma.}` + if sym == nil or sfCustomPragma in sym.flags: return nil + # skip if not in scope; skip `template myAttr() {.pragma.}` let lhs = b[0] let clash = strTableGet(c.currentScope.symbols, lhs.ident) if clash != nil: From 182d3c16e3b7aac9ed3575dec55e6d9a3d5042c4 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 25 Mar 2020 13:44:52 +0000 Subject: [PATCH 0201/4254] fixes #13744 (#13749) * fixes #13744 * improve style Co-authored-by: cooldome --- compiler/ccgexprs.nim | 2 ++ compiler/transf.nim | 2 +- compiler/vm.nim | 6 ++++++ tests/types/tcast1.nim | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 9c683a071..e1561ae12 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1941,6 +1941,8 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = elif optSeqDestructors in p.config.globalOptions and etyp.kind in {tySequence, tyString}: putIntoDest(p, d, e, "(*($1*) (&$2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) + elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes: + putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage) else: putIntoDest(p, d, e, "(($1) ($2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) diff --git a/compiler/transf.nim b/compiler/transf.nim index c1af6c23f..18d9b9130 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -462,7 +462,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = var dest = skipTypes(n.typ, abstractVarRange) var source = skipTypes(n[1].typ, abstractVarRange) case dest.kind - of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: + of tyInt..tyInt64, tyEnum, tyChar, tyUInt8..tyUInt32: # we don't include uint and uint64 here as these are no ordinal types ;-) if not isOrdinalType(source): # float -> int conversions. ugh. diff --git a/compiler/vm.nim b/compiler/vm.nim index 6a12b615e..8e05c5618 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -463,6 +463,12 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): value = (value shl srcDist) shr srcDist value = (value shl destDist) shr destDist dest.intVal = cast[BiggestInt](value) + of tyBool: + dest.ensureKind(rkInt) + dest.intVal = + case skipTypes(srctyp, abstractRange).kind + of tyFloat..tyFloat64: int(src.floatVal != 0.0) + else: int(src.intVal != 0) of tyFloat..tyFloat64: dest.ensureKind(rkFloat) case skipTypes(srctyp, abstractRange).kind diff --git a/tests/types/tcast1.nim b/tests/types/tcast1.nim index 10e876ded..04596baff 100644 --- a/tests/types/tcast1.nim +++ b/tests/types/tcast1.nim @@ -19,3 +19,38 @@ proc remap2[T](s: seq[int], typ: typedesc[T]): seq[T] = echo remap1(@[1,2,3], float) echo remap2(@[1,2,3], float) + + +#-------------------------------------------------------------------- +# conversion to bool, issue #13744 +proc test_conv_to_bool = + var + i0 = 0 + i1 = 1 + ih = high(uint) + il = low(int) + + f0 = 0.0 + f1 = 1.0 + fh = Inf + fl = -Inf + f_nan = NaN + + doAssert(bool(i0) == false) + doAssert(bool(i1) == true) + doAssert(bool(-i1) == true) + doAssert(bool(il) == true) + doAssert(bool(ih) == true) + + doAssert(bool(f0) == false) + doAssert(bool(-f0) == false) + doAssert(bool(f1) == true) + doAssert(bool(-f1) == true) + doAssert(bool(fh) == true) + doAssert(bool(fl) == true) + doAssert(bool(fnan) == true) # NaN to bool gives true according to standard + + +static: + test_conv_to_bool() +test_conv_to_bool() \ No newline at end of file From 5b55aa52d05ff911d64febc973bed1f0c2d97d25 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 25 Mar 2020 19:15:34 +0100 Subject: [PATCH 0202/4254] fix deprecations and other warnings (#13748) --- lib/pure/asyncdispatch.nim | 10 ++++---- lib/pure/ioselects/ioselectors_select.nim | 4 ++-- lib/pure/net.nim | 6 ++--- lib/pure/nimprof.nim | 2 +- nimsuggest/tests/tsug_regression.nim | 6 ++--- tests/async/t6846.nim | 3 +-- tests/async/tacceptcloserace.nim | 4 ++-- tests/async/tasyncconnect.nim | 2 +- tests/async/tasyncdial.nim | 2 +- tests/async/tioselectors.nim | 6 ++--- tests/async/tnewasyncudp.nim | 12 +++++----- tests/async/twinasyncrw.nim | 4 ++-- tests/collections/tcollections_to_string.nim | 6 ++--- tests/collections/thashsets.nim | 14 ++++++------ tests/generics/mdotlookup.nim | 2 +- tests/macros/tmacrogensym.nim | 8 +++---- tests/manyloc/nake/nakefile.nim | 4 ++-- tests/stdlib/thttpclient.nim | 2 +- tests/stdlib/tmath.nim | 24 ++++++++++---------- tests/stdlib/tmget.nim | 2 +- tests/stdlib/tnetdial.nim | 2 +- tests/stdlib/tosproc.nim | 4 ++-- 22 files changed, 63 insertions(+), 66 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 35eb646c6..4ab0cf214 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -276,7 +276,7 @@ when defined(windows) or defined(nimdoc): ## Creates a new Dispatcher instance. new result result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) - result.handles = initSet[AsyncFD]() + result.handles = initHashSet[AsyncFD]() result.timers.newHeapQueue() result.callbacks = initDeque[proc () {.closure, gcsafe.}](64) @@ -398,7 +398,7 @@ when defined(windows) or defined(nimdoc): addr bytesRet, nil, nil) == 0 proc initAll() = - let dummySock = newNativeSocket() + let dummySock = createNativeSocket() if dummySock == INVALID_SOCKET: raiseOSError(osLastError()) var fun: pointer = nil @@ -713,7 +713,7 @@ when defined(windows) or defined(nimdoc): verifyPresence(socket) var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr") - var clientSock = newNativeSocket() + var clientSock = createNativeSocket() if clientSock == osInvalidSocket: raiseOSError(osLastError()) const lpOutputLen = 1024 @@ -1121,7 +1121,7 @@ else: proc newDispatcher*(): owned(PDispatcher) = new result result.selector = newSelector[AsyncData]() - result.timers.newHeapQueue() + result.timers.clear() result.callbacks = initDeque[proc () {.closure, gcsafe.}](InitDelayedCallbackListSize) var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher @@ -1574,7 +1574,7 @@ proc poll*(timeout = 500) = discard runOnce(timeout) template createAsyncNativeSocketImpl(domain, sockType, protocol) = - let handle = newNativeSocket(domain, sockType, protocol) + let handle = createNativeSocket(domain, sockType, protocol) if handle == osInvalidSocket: return osInvalidSocket.AsyncFD handle.setBlocking(false) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index b90a01c06..02a853b42 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -113,8 +113,8 @@ proc close*[T](s: Selector[T]) = when defined(windows): proc newSelectEvent*(): SelectEvent = - var ssock = newNativeSocket() - var wsock = newNativeSocket() + var ssock = createNativeSocket() + var wsock = createNativeSocket() var rsock: SocketHandle = INVALID_SOCKET var saddr = Sockaddr_in() diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 2f43573ac..261f83583 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -67,9 +67,7 @@ include "system/inclrtl" {.deadCodeElim: on.} # dce option deprecated -import nativesockets, os, strutils, parseutils, times, sets, options, - std/monotimes -from ospaths import getEnv +import nativesockets, os, strutils, times, sets, options, std/monotimes from ssl_certs import scanSSLCertificates export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol @@ -603,7 +601,7 @@ when defineSsl: if not found: raise newException(IOError, "No SSL/TLS CA certificates found.") - result = SSLContext(context: newCTX, referencedData: initSet[int](), + result = SSLContext(context: newCTX, referencedData: initHashSet[int](), extraInternal: new(SslContextExtraInternal)) proc getExtraInternal(ctx: SslContext): SslContextExtraInternal = diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index fad8b66a1..57ea466e5 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -181,7 +181,7 @@ proc writeProfile() {.noconv.} = var perProc = initCountTable[string]() for i in 0..entries-1: - var dups = initSet[string]() + var dups = initHashSet[string]() for ii in 0..high(StackTrace.lines): let procname = profileData[i].st[ii] if isNil(procname): break diff --git a/nimsuggest/tests/tsug_regression.nim b/nimsuggest/tests/tsug_regression.nim index 1b23da806..1607f5244 100644 --- a/nimsuggest/tests/tsug_regression.nim +++ b/nimsuggest/tests/tsug_regression.nim @@ -7,9 +7,9 @@ type X = object proc main = # bug #52 var - set0 = initSet[int]() - set1 = initSet[X]() - set2 = initSet[ref int]() + set0 = initHashSet[int]() + set1 = initHashSet[X]() + set2 = initHashSet[ref int]() map0 = initTable[int, int]() map1 = initOrderedTable[string, int]() diff --git a/tests/async/t6846.nim b/tests/async/t6846.nim index 687a3f865..7fe38f3b3 100644 --- a/tests/async/t6846.nim +++ b/tests/async/t6846.nim @@ -6,11 +6,10 @@ discard """ import asyncdispatch import asyncfile -import times var asyncStdout = 1.AsyncFD.newAsyncFile() proc doStuff: Future[void] {.async.} = await asyncStdout.write "hello world\n" let fut = doStuff() -doAssert fut.finished, "Poll is needed unnecessarily. See #6846." \ No newline at end of file +doAssert fut.finished, "Poll is needed unnecessarily. See #6846." diff --git a/tests/async/tacceptcloserace.nim b/tests/async/tacceptcloserace.nim index cbb5b5098..fee6537d2 100644 --- a/tests/async/tacceptcloserace.nim +++ b/tests/async/tacceptcloserace.nim @@ -8,7 +8,7 @@ import asyncdispatch, net, os, nativesockets # bug: https://github.com/nim-lang/Nim/issues/5279 proc setupServerSocket(hostname: string, port: Port): AsyncFD = - let fd = newNativeSocket() + let fd = createNativeSocket() if fd == osInvalidSocket: raiseOSError(osLastError()) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) @@ -30,7 +30,7 @@ for i in 0..100: if not fut.failed: fut.read().closeSocket() - var fd = newAsyncNativeSocket() + var fd = createAsyncNativeSocket() waitFor fd.connect("localhost", port) serverFd.closeSocket() fd.closeSocket() diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim index f63a87990..564f6c67c 100644 --- a/tests/async/tasyncconnect.nim +++ b/tests/async/tasyncconnect.nim @@ -18,7 +18,7 @@ when defined(windows) or defined(nimdoc): quit("Error: unhandled exception: Connection refused") else: proc testAsyncConnect() {.async.} = - var s = newAsyncNativeSocket() + var s = createAsyncNativeSocket() await s.connect(testHost, testPort) diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim index bbff7028d..a755de74e 100644 --- a/tests/async/tasyncdial.nim +++ b/tests/async/tasyncdial.nim @@ -13,7 +13,7 @@ proc setupServerSocket(hostname: string, port: Port, domain: Domain): AsyncFD = ## Creates a socket, binds it to the specified address, and starts listening for connections. ## Registers the descriptor with the dispatcher of the current thread ## Raises OSError in case of an error. - let fd = newNativeSocket(domain) + let fd = createNativeSocket(domain) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, domain) if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index e172e1452..48aa64838 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -13,7 +13,7 @@ template processTest(t, x: untyped) = when defined(macosx): echo "All tests passed!" elif not defined(windows): - import os, posix, nativesockets, times + import os, posix, nativesockets when ioselSupportedPlatform: import osproc @@ -445,7 +445,7 @@ elif not defined(windows): var thr: array[0..7, Thread[SelectEvent]] var selector = newSelector[int]() - var sock = newNativeSocket() + var sock = createNativeSocket() var event = newSelectEvent() for i in 0..high(thr): createThread(thr[i], event_wait_thread, event) @@ -475,7 +475,7 @@ else: proc socket_notification_test(): bool = proc create_test_socket(): SocketHandle = - var sock = newNativeSocket() + var sock = createNativeSocket() setBlocking(sock, false) result = sock diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim index feab46319..76462c21d 100644 --- a/tests/async/tnewasyncudp.nim +++ b/tests/async/tnewasyncudp.nim @@ -40,9 +40,9 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = var saddr = Sockaddr_in() while i < swarmSize: var peeraddr = prepareAddress(INADDR_LOOPBACK, 0) - var sock = newAsyncNativeSocket(nativesockets.AF_INET, - nativesockets.SOCK_DGRAM, - Protocol.IPPROTO_UDP) + var sock = createAsyncNativeSocket(nativesockets.AF_INET, + nativesockets.SOCK_DGRAM, + Protocol.IPPROTO_UDP) if bindAddr(sock.SocketHandle, cast[ptr SockAddr](peeraddr), sizeof(Sockaddr_in).Socklen) < 0'i32: raiseOSError(osLastError()) @@ -91,9 +91,9 @@ proc readMessages(server: AsyncFD) {.async.} = proc createServer() {.async.} = var name = prepareAddress(INADDR_LOOPBACK, serverPort) - var server = newAsyncNativeSocket(nativesockets.AF_INET, - nativesockets.SOCK_DGRAM, - Protocol.IPPROTO_UDP) + var server = createAsyncNativeSocket(nativesockets.AF_INET, + nativesockets.SOCK_DGRAM, + Protocol.IPPROTO_UDP) if bindAddr(server.SocketHandle, cast[ptr SockAddr](name), sizeof(Sockaddr_in).Socklen) < 0'i32: raiseOSError(osLastError()) diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim index db10fffce..352c53b41 100644 --- a/tests/async/twinasyncrw.nim +++ b/tests/async/twinasyncrw.nim @@ -208,7 +208,7 @@ when defined(windows): proc launchSwarm(port: Port) {.async.} = for i in 0 ..< swarmSize: - var sock = newNativeSocket() + var sock = createNativeSocket() setBlocking(sock, false) await winConnect(AsyncFD(sock), "localhost", port) @@ -229,7 +229,7 @@ when defined(windows): doAssert false proc createServer(port: Port) {.async.} = - var server = newNativeSocket() + var server = createNativeSocket() setBlocking(server, false) block: var name = Sockaddr_in() diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim index 686b9916b..8915e9fea 100644 --- a/tests/collections/tcollections_to_string.nim +++ b/tests/collections/tcollections_to_string.nim @@ -19,9 +19,9 @@ doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]""" doAssert $(@['1', '2', '3']) == """@['1', '2', '3']""" # Tests for sets -doAssert $(toSet([1])) == "{1}" -doAssert $(toSet(["1"])) == """{"1"}""" -doAssert $(toSet(['1'])) == """{'1'}""" +doAssert $(toHashSet([1])) == "{1}" +doAssert $(toHashSet(["1"])) == """{"1"}""" +doAssert $(toHashSet(['1'])) == """{'1'}""" doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}" doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}""" doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}""" diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim index cd4401511..bc387d292 100644 --- a/tests/collections/thashsets.nim +++ b/tests/collections/thashsets.nim @@ -3,9 +3,9 @@ import sets, hashes, algorithm block setEquality: var - a = initSet[int]() - b = initSet[int]() - c = initSet[string]() + a = initHashSet[int]() + b = initHashSet[int]() + c = initHashSet[string]() for i in 0..5: a.incl(i) for i in 1..6: b.incl(i) @@ -16,27 +16,27 @@ block setEquality: block setsContainingTuples: - var set = initSet[tuple[i: int, i64: int64, f: float]]() + var set = initHashSet[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]]]() + var s = initHashSet[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]]() + var s = initHashSet[seq[int]]() s.incl( @[1, 2, 3] ) doAssert s.contains(@[1, 2, 3]) doAssert( not s.contains(@[4, 5, 6]) ) block setClearWorked: - var s = initSet[char]() + var s = initHashSet[char]() for c in "this is a test": s.incl(c) diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 2984574c2..470fa0a51 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -9,7 +9,7 @@ proc foo*(b: any) = import sets -var intset = initSet[int]() +var intset = initHashSet[int]() proc fn*[T](a: T) = if a in intset: echo("true") diff --git a/tests/macros/tmacrogensym.nim b/tests/macros/tmacrogensym.nim index 15a08c574..7c0d75f82 100644 --- a/tests/macros/tmacrogensym.nim +++ b/tests/macros/tmacrogensym.nim @@ -1,6 +1,6 @@ import nativesockets, asyncdispatch, macros var p = newDispatcher() -var sock = newAsyncNativeSocket() +var sock = createAsyncNativeSocket() proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} = case node.kind @@ -27,7 +27,7 @@ macro async2(prc: untyped): untyped = # -> iterator nameIter(): FutureBase {.closure.} = # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work. - var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter") + var iteratorNameSym = genSym(nskIterator, $prc[0] & "Iter") assert iteratorNameSym.symKind == nskIterator #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter") var procBody = prc[6].convertReturns(retFutureSym) @@ -39,7 +39,7 @@ macro async2(prc: untyped): untyped = # -> var nameIterVar = nameIter # -> var first = nameIterVar() - var varNameIterSym = newIdentNode($prc[0].ident & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar") + var varNameIterSym = newIdentNode($prc[0] & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar") var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym) outerProcBody.add varNameIter var varFirstSym = genSym(nskVar, "first") @@ -52,7 +52,7 @@ macro async2(prc: untyped): untyped = # Remove the 'closure' pragma. for i in 0 ..< result[4].len: - if result[4][i].ident == !"async": + if result[4][i] == newIdentNode("async"): result[4].del(i) result[6] = outerProcBody diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 35ed3cbb0..0b5055512 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -63,7 +63,7 @@ task "release", "release build": ## zip up all the files and such or something useful here task "testskel", "create skeleton test dir for testing": - let dirname = "test-"& $random(5000) + let dirname = "test-" & $random(5000) removeDir dirName createDir dirName/"data/fnt" copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf" @@ -133,7 +133,7 @@ task "download", "download game assets": else: ## this crashes, dunno why var z: TZipArchive - destDir = getCurrentDir()/("unzip"& $random(5000)) + destDir = getCurrentDir()/("unzip" & $random(5000)) if not z.open(path, fmRead): echo "Could not open zip, bad download?" return diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim index 66fc123e3..6a634d90f 100644 --- a/tests/stdlib/thttpclient.nim +++ b/tests/stdlib/thttpclient.nim @@ -14,7 +14,7 @@ const manualTests = false proc makeIPv6HttpServer(hostname: string, port: Port, message: string): AsyncFD = - let fd = newNativeSocket(AF_INET6) + let fd = createNativeSocket(AF_INET6) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, AF_INET6) if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index a023be86c..0de09a858 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -22,58 +22,58 @@ suite "random int": var set = initHashSet[int](128) for i in 1..1000: - incl(set, random(high(int))) + incl(set, rand(high(int))) check len(set) == 1000 test "single number bounds work": var rand: int for i in 1..1000: - rand = random(1000) + rand = rand(1000) check rand < 1000 check rand > -1 test "slice bounds work": var rand: int for i in 1..1000: - rand = random(100..1000) + rand = rand(100..1000) check rand < 1000 check rand >= 100 test " again gives new numbers": - var rand1 = random(1000000) + var rand1 = rand(1000000) os.sleep(200) - var rand2 = random(1000000) + var rand2 = rand(1000000) check rand1 != rand2 suite "random float": test "there might be some randomness": - var set = initSet[float](128) + var set = initHashSet[float](128) for i in 1..100: - incl(set, random(1.0)) + incl(set, rand(1.0)) check len(set) == 100 test "single number bounds work": var rand: float for i in 1..1000: - rand = random(1000.0) + rand = rand(1000.0) check rand < 1000.0 check rand > -1.0 test "slice bounds work": var rand: float for i in 1..1000: - rand = random(100.0..1000.0) + rand = rand(100.0..1000.0) check rand < 1000.0 check rand >= 100.0 test " again gives new numbers": - var rand1:float = random(1000000.0) + var rand1:float = rand(1000000.0) os.sleep(200) - var rand2:float = random(1000000.0) + var rand2:float = rand(1000000.0) check rand1 != rand2 suite "cumsum": @@ -144,4 +144,4 @@ suite "^": check: compiles(5.5 ^ 2.int8) check: compiles(5.5 ^ 2.uint) check: compiles(5.5 ^ 2.uint8) - check: not compiles(5.5 ^ 2.2) \ No newline at end of file + check: not compiles(5.5 ^ 2.2) diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim index 5e2e327f4..52e61fd24 100644 --- a/tests/stdlib/tmget.nim +++ b/tests/stdlib/tmget.nim @@ -104,7 +104,7 @@ block: import sets block: - var x = initSet[int]() + var x = initHashSet[int]() x.incl 5 try: echo x[6] diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim index 7c2197e4a..f940bd630 100644 --- a/tests/stdlib/tnetdial.nim +++ b/tests/stdlib/tnetdial.nim @@ -12,7 +12,7 @@ import os, net, nativesockets, asyncdispatch const port = Port(28431) proc initIPv6Server(hostname: string, port: Port): AsyncFD = - let fd = newNativeSocket(AF_INET6) + let fd = createNativeSocket(AF_INET6) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, AF_INET6) if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index 1859877e7..fc65606f6 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -47,7 +47,7 @@ when defined(case_testfile): # compiled test file for child process else: - import os, osproc, strutils, posix + import os, osproc, strutils const nim = getCurrentCompilerExe() block execShellCmdTest: @@ -74,7 +74,7 @@ else: block execProcessTest: let dir = parentDir(currentSourcePath()) - let (outp, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim")) + let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim")) doAssert err == 0 let exePath = dir / addFileExt("osproctest", ExeExt) let outStr1 = execProcess(exePath, workingDir = dir, args = ["foo", From 84b378b94fffed6e4e32cfebdd940a80425226d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Wed, 25 Mar 2020 14:42:34 -0400 Subject: [PATCH 0203/4254] docs: say that `nil` can be used as a value (#13756) and improve wording in other ways Showing that `nil` can be assigned helps to warn readers that variables can be `nil` even after being assigned a value. --- doc/manual.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 3a0faed2e..bffb9e60c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1767,12 +1767,15 @@ further information. Nil --- -If a reference points to *nothing*, it has the value ``nil``. ``nil`` is also -the default value for all ``ref`` and ``ptr`` types. Dereferencing ``nil`` -is an unrecoverable fatal runtime error (and not a panic). -A dereferencing operation ``p[]`` implies that ``p`` is not nil. This can be -exploited by the implementation to optimize code like: +If a reference points to *nothing*, it has the value ``nil``. ``nil`` is the +default value for all ``ref`` and ``ptr`` types. The ``nil`` value can also be +used like any other literal value. For example, it can be used in an assignment +like ``myRef = nil``. +Dereferencing ``nil`` is an unrecoverable fatal runtime error (and not a panic). + +A successful dereferencing operation ``p[]`` implies that ``p`` is not nil. This +can be exploited by the implementation to optimize code like: .. code-block:: nim From febd48f3432f908e7767d1e7f894748c617d1700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Wed, 25 Mar 2020 16:08:24 -0400 Subject: [PATCH 0204/4254] [skip ci] docs: reword Part 3 link to communicate that it exists (#13755) --- doc/tut2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tut2.rst b/doc/tut2.rst index d9a37f7ec..9dbfa39c3 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -677,4 +677,4 @@ JavaScript-compatible code you should remember the following: Part 3 ====== -Next part will be entirely about metaprogramming via macros: `Part III `_ +The next part is entirely about metaprogramming via macros: `Part III `_ From a8a464810e0473da61b9daf28311bc76411601bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Wed, 25 Mar 2020 16:09:23 -0400 Subject: [PATCH 0205/4254] [ci skip] docs: make the syntax for generics easy to look up (#13754) --- doc/tut2.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/tut2.rst b/doc/tut2.rst index 9dbfa39c3..419e06930 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -469,7 +469,8 @@ Generics ======== Generics are Nim's means to parametrize procs, iterators or types -with `type parameters`:idx:. They are most useful for efficient type safe +with `type parameters`:idx:. Generic parameters are written within square +brackets, for example ``Foo[T]``. They are most useful for efficient type safe containers: .. code-block:: nim From e1e062197ec13da4516642270e2057b0c26248cb Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 25 Mar 2020 21:28:16 +0100 Subject: [PATCH 0206/4254] bump copyright year to 2020 (#13753) --- compiler/options.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/options.nim b/compiler/options.nim index d9a7a06ef..d906cd852 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -19,7 +19,7 @@ const useEffectSystem* = true useWriteTracking* = false hasFFI* = defined(nimHasLibFFI) - copyrightYear* = "2019" + copyrightYear* = "2020" type # please make sure we have under 32 options # (improves code efficiency a lot!) From 764a81ca253b78d0faa75a24dffc8d111362974f Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 25 Mar 2020 20:36:22 +0000 Subject: [PATCH 0207/4254] Continue bool conversion fixing (#13751) * continue fixing #13744 * improve style * improve test Co-authored-by: cooldome --- compiler/semexprs.nim | 4 +++- compiler/semfold.nim | 9 +++++++++ tests/types/tcast1.nim | 9 ++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c678d3674..c2f117efa 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -147,7 +147,9 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = result = checkConversionBetweenObjects(d.skipTypes(abstractInst), s.skipTypes(abstractInst), pointers) elif (targetBaseTyp.kind in IntegralTypes) and (srcBaseTyp.kind in IntegralTypes): - if targetTyp.isOrdinalType: + if targetTyp.kind == tyBool: + discard "convOk" + elif targetTyp.isOrdinalType: if src.kind in nkCharLit..nkUInt64Lit and src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp): result = convNotInRange diff --git a/compiler/semfold.nim b/compiler/semfold.nim index a8d42fe7a..4131347a2 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -433,6 +433,15 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = # echo high(int64) # writeStackTrace() case dstTyp.kind + of tyBool: + case srcTyp.kind + of tyFloat..tyFloat64: + result = newIntNodeT(int(getFloat(a) != 0.0), n, g) + of tyChar, tyUInt..tyUInt64, tyInt..tyInt64: + result = newIntNodeT(int(a.getOrdValue != 0), n, g) + else: + result = a + result.typ = n.typ of tyInt..tyInt64, tyUInt..tyUInt64: case srcTyp.kind of tyFloat..tyFloat64: diff --git a/tests/types/tcast1.nim b/tests/types/tcast1.nim index 04596baff..ab375b8b2 100644 --- a/tests/types/tcast1.nim +++ b/tests/types/tcast1.nim @@ -52,5 +52,12 @@ proc test_conv_to_bool = static: + doAssert(bool(0) == false) + doAssert(bool(-1) == true) + doAssert(bool(2) == true) + doAssert(bool(NaN) == true) + doAssert(bool(0.0) == false) + doAssert(bool(-0.0) == false) test_conv_to_bool() -test_conv_to_bool() \ No newline at end of file +test_conv_to_bool() + From 98753da33188e3eef2362c4ed3c2bea166b8f10b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 25 Mar 2020 13:47:03 -0700 Subject: [PATCH 0208/4254] distinctBase overload for values (#13746) --- changelog.md | 2 +- lib/pure/typetraits.nim | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index daed6c02b..a452965b2 100644 --- a/changelog.md +++ b/changelog.md @@ -122,7 +122,7 @@ echo f - Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for retrieving the verified certificate chain of the peer we are connected to through an SSL-wrapped `Socket`/`AsyncSocket`. - +- Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` ## Library changes diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 66b94e238..ef28f83b0 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -71,6 +71,13 @@ proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} ## Returns base type for distinct types, works only for distinct types. ## compile time error otherwise +since (1, 1): + template distinctBase*[T](a: T): untyped = + ## overload for values + runnableExamples: + type MyInt = distinct int + doAssert 12.MyInt.distinctBase == 12 + distinctBase(type(a))(a) proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait", since: (1, 1).} ## Return number of elements of `T` From 1b31e08917f3644b80a10b581089b816ef2db214 Mon Sep 17 00:00:00 2001 From: Euan Date: Thu, 26 Mar 2020 08:11:32 +0000 Subject: [PATCH 0209/4254] `import macros` rather than `import std/macros`. (#13762) --- lib/pure/typetraits.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index ef28f83b0..8f83a9dda 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -96,7 +96,8 @@ since (1, 1): type StaticParam*[value] = object ## used to wrap a static value in `genericParams` -import std/macros +# NOTE: See https://github.com/nim-lang/Nim/issues/13758 - `import std/macros` does not work on OpenBSD +import macros macro genericParamsImpl(T: typedesc): untyped = # auxiliary macro needed, can't do it directly in `genericParams` From e50441ab33d1b287a89ad4e2d795c80b7f8077c0 Mon Sep 17 00:00:00 2001 From: zah Date: Thu, 26 Mar 2020 10:26:19 +0200 Subject: [PATCH 0210/4254] Fix typeSym.getImpl for ref types (#13752) * Fix typeSym.getImpl for ref types * Fix a codegen issue affecting the test suite of nim-beacon-chain * Fix tests/stdlib/tjsonmacro To understand the fix better it may help to take a look at the history of the replaced code. The nil check that is removed in this commit was introduced in another fix that failed to identify the root cause of the issue - namely that we allow an object type to exist for which no ast is present: https://github.com/nim-lang/Nim/pull/9601/files The original intention of the code is more obvious here: https://github.com/nim-lang/Nim/pull/9538/files --- compiler/ccgexprs.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/vmdeps.nim | 8 ++-- tests/macros/tmacrotypes.nim | 84 +++++++++++++++++++++++++++++++++++- 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e1561ae12..fcedcf001 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2950,7 +2950,7 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = else: internalError(p.config, n.info, "node has no type") else: - ty = skipTypes(n.typ, abstractInstOwned).kind + ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind case ty of tySet: var cs: TBitSet diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6b01e241b..5232c5706 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1279,12 +1279,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"), getCurrOwner(c), s.info) + obj.ast = a if sfPure in s.flags: obj.flags.incl sfPure obj.typ = st.lastSon st.lastSon.sym = obj - proc checkForMetaFields(c: PContext; n: PNode) = proc checkMeta(c: PContext; n: PNode; t: PType) = if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags: diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 79d49698a..7cfba046a 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -159,10 +159,10 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyObject: if inst: result = newNodeX(nkObjectTy) - if t.sym.ast != nil: - result.add t.sym.ast[2][0].copyTree # copy object pragmas - else: - result.add newNodeI(nkEmpty, info) + var objectDef = t.sym.ast[2] + if objectDef.kind == nkRefTy: + objectDef = objectDef[0] + result.add objectDef[0].copyTree # copy object pragmas if t[0] == nil: result.add newNodeI(nkEmpty, info) else: # handle parent object diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim index 8cf93a593..cfc4ef7fb 100644 --- a/tests/macros/tmacrotypes.nim +++ b/tests/macros/tmacrotypes.nim @@ -4,11 +4,40 @@ void; ntyVoid; void; void int; ntyInt; int; int proc (); ntyProc; proc[void]; proc () voidProc; ntyProc; proc[void]; proc () +listing fields for ObjType +a: string +b: int +listing fields for ObjRef +skipping ref type +a: string +b: int +listing fields for RefType +skipping ref type +a: int +b: float +listing fields for typeof(a) +skipping ref type +a: string +b: int +listing fields for typeof(b) +skipping ref type +a: string +b: int +listing fields for typeof(c) +skipping ref type +a: int +b: float +listing fields for typeof(x) +a: string +b: int +listing fields for typeof(x) +a: int +b: float typeDesc[range[1 .. 5]]; ntyTypeDesc; typeDesc[range[1, 5]]; typeDesc[range[1 .. 5]] typeDesc[range]; ntyTypeDesc; typeDesc[range[T]]; typeDesc[range]''' """ -import macros +import macros, typetraits macro checkType(ex: typed): untyped = echo ex.getTypeInst.repr, "; ", ex.typeKind, "; ", ex.getType.repr, "; ", ex.getTypeImpl.repr @@ -17,7 +46,6 @@ macro checkProcType(fn: typed): untyped = let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr - proc voidProc = echo "hello" proc intProc(a: int, b: float): int {.checkProcType.} = 10 @@ -26,6 +54,58 @@ checkType(intProc(10, 20.0)) checkType(voidProc) checkProcType(voidProc) +macro listFields(T: typed) = + echo "listing fields for ", repr(T) + let inputExprType = getType(T) + + var objType = inputExprType[1] + if objType.kind == nnkBracketExpr and objType.len > 1: + if ((objType[0].kind == nnkRefTy) or + (objType[0].kind == nnkSym and eqIdent(objType[0], "ref"))): + echo "skipping ref type" + objType = objType[1] + + let typeAst = objType.getImpl + + var objectDef = typeAst[2] + if objectDef.kind == nnkRefTy: + objectDef = objectDef[0] + + let recList = objectDef[2] + for rec in recList: + echo $rec[0], ": ", $rec[1] + +type + ObjType* = object of RootObj + a: string + b: int + + ObjRef = ref ObjType + + RefType* = ref object of RootObj + a: int + b: float + +listFields ObjType +listFields ObjRef +listFields RefType + +let + a = new ObjType + b = new ObjRef + c = new RefType + +listFields typeOf(a) +listFields typeOf(b) +listFields typeOf(c) + +proc genericProc(x: object) = + listFields typeOf(x) + +genericProc a[] +genericProc b[] +genericProc c[] + # bug #10548 block: var c {.compileTime.} = 0 From 2da438c33b55ddfefd5d0e5e876721a00dabd42c Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 26 Mar 2020 08:26:56 +0000 Subject: [PATCH 0211/4254] asyncdispatch: fix erroneous set construction (#13765) These constants were defined as `cint`. They can be huge on certain systems, such as Haiku, and trigger out-of-bounds errors in asyncdispatch. Ref #13764. --- lib/pure/asyncdispatch.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 4ab0cf214..5d34f9fca 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1407,7 +1407,9 @@ else: MSG_NOSIGNAL) if res < 0: let lastError = osLastError() - if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: + if lastError.int32 != EINTR and + lastError.int32 != EWOULDBLOCK and + lastError.int32 != EAGAIN: if flags.isDisconnectionError(lastError): retFuture.complete() else: From 6162da812af822f739dd00bb1b6c12658a89c669 Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 26 Mar 2020 13:47:15 +0000 Subject: [PATCH 0212/4254] ssl_certs: add Haiku support (#13761) --- lib/pure/ssl_certs.nim | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index 7b1550004..9845de9b6 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -49,6 +49,18 @@ const certificate_paths = [ "/etc/openssl/certs", ] +when defined(haiku): + const + B_FIND_PATH_EXISTING_ONLY = 0x4 + B_FIND_PATH_DATA_DIRECTORY = 6 + + proc find_paths_etc(architecture: cstring, baseDirectory: cint, + subPath: cstring, flags: uint32, + paths: var ptr UncheckedArray[cstring], + pathCount: var csize): int32 + {.importc, header: "".} + proc free(p: pointer) {.importc, header: "".} + iterator scanSSLCertificates*(useEnvVars = false): string = ## Scan for SSL/TLS CA certificates on disk. ## @@ -64,13 +76,26 @@ iterator scanSSLCertificates*(useEnvVars = false): string = yield fn else: - for p in certificate_paths: - if p.endsWith(".pem") or p.endsWith(".crt"): - if existsFile(p): - yield p - elif existsDir(p): - for fn in joinPath(p, "*").walkFiles(): - yield fn + when not defined(haiku): + for p in certificate_paths: + if p.endsWith(".pem") or p.endsWith(".crt"): + if existsFile(p): + yield p + elif existsDir(p): + for fn in joinPath(p, "*").walkFiles(): + yield fn + else: + var + paths: ptr UncheckedArray[cstring] + size: csize + let err = find_paths_etc( + nil, B_FIND_PATH_DATA_DIRECTORY, "ssl/CARootCertificates.pem", + B_FIND_PATH_EXISTING_ONLY, paths, size + ) + if err == 0: + defer: free(paths) + for i in 0 ..< size: + yield $paths[i] # Certificates management on windows # when defined(windows) or defined(nimdoc): From 2925a47ae6aaa8e93117a29b018582540bf55856 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 26 Mar 2020 16:18:45 +0100 Subject: [PATCH 0213/4254] Fix vm.nim for --gc:arc (#13741) * koch boot --gc:arc now passes the nim stage ... but generates invalid C code * Move it closer to where its used * Try something else * Poor mans var * Use UncheckedArray instead --- compiler/vm.nim | 16 ++-------------- compiler/vmdef.nim | 14 +++++++++++++- compiler/vmhooks.nim | 41 +++++++++++++++-------------------------- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 8e05c5618..a2c6e686d 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -28,18 +28,6 @@ when hasFFI: import evalffi type - TRegisterKind = enum - rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr - TFullReg = object # with a custom mark proc, we could use the same - # data representation as LuaJit (tagged NaNs). - case kind: TRegisterKind - of rkNone: nil - of rkInt: intVal: BiggestInt - of rkFloat: floatVal: BiggestFloat - of rkNode: node: PNode - of rkRegisterAddr: regAddr: ptr TFullReg - of rkNodeAddr: nodeAddr: ptr PNode - PStackFrame* = ref TStackFrame TStackFrame* = object prc: PSym # current prc; proc that is evaluated @@ -1206,7 +1194,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if prc.offset < -1: # it's a callback: c.callbacks[-prc.offset-2].value( - VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs), + VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), currentException: c.currentExceptionA, currentLineInfo: c.debug[pc])) elif importcCond(prc): @@ -1525,7 +1513,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = rc = instr.regC idx = int(regs[rb+rc-1].intVal) callback = c.callbacks[idx].value - args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs), + args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), currentException: c.currentExceptionA, currentLineInfo: c.debug[pc]) callback(args) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 176558eac..7b51c626d 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -212,6 +212,18 @@ type slotTempComplex, # some complex temporary (s.node field is used) slotTempPerm # slot is temporary but permanent (hack) + TRegisterKind* = enum + rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr + TFullReg* = object # with a custom mark proc, we could use the same + # data representation as LuaJit (tagged NaNs). + case kind*: TRegisterKind + of rkNone: nil + of rkInt: intVal*: BiggestInt + of rkFloat: floatVal*: BiggestFloat + of rkNode: node*: PNode + of rkRegisterAddr: regAddr*: ptr TFullReg + of rkNodeAddr: nodeAddr*: ptr PNode + PProc* = ref object blocks*: seq[TBlock] # blocks; temp data structure sym*: PSym @@ -220,7 +232,7 @@ type VmArgs* = object ra*, rb*, rc*: Natural - slots*: pointer + slots*: ptr UncheckedArray[TFullReg] currentException*: PNode currentLineInfo*: TLineInfo VmCallback* = proc (args: VmArgs) {.closure.} diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim index 412c93a77..d211d8343 100644 --- a/compiler/vmhooks.nim +++ b/compiler/vmhooks.nim @@ -10,10 +10,8 @@ import pathutils template setX(k, field) {.dirty.} = - var s: seq[TFullReg] - move(s, cast[seq[TFullReg]](a.slots)) - s[a.ra].ensureKind(k) - s[a.ra].field = v + a.slots[a.ra].ensureKind(k) + a.slots[a.ra].field = v proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal) proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal) @@ -22,45 +20,36 @@ proc setResult*(a: VmArgs; v: bool) = setX(rkInt, intVal) proc setResult*(a: VmArgs; v: string) = - var s: seq[TFullReg] - move(s, cast[seq[TFullReg]](a.slots)) - s[a.ra].ensureKind(rkNode) - s[a.ra].node = newNode(nkStrLit) - s[a.ra].node.strVal = v + a.slots[a.ra].ensureKind(rkNode) + a.slots[a.ra].node = newNode(nkStrLit) + a.slots[a.ra].node.strVal = v proc setResult*(a: VmArgs; n: PNode) = - var s: seq[TFullReg] - move(s, cast[seq[TFullReg]](a.slots)) - s[a.ra].ensureKind(rkNode) - s[a.ra].node = n + a.slots[a.ra].ensureKind(rkNode) + a.slots[a.ra].node = n proc setResult*(a: VmArgs; v: AbsoluteDir) = setResult(a, v.string) proc setResult*(a: VmArgs; v: seq[string]) = - var s: seq[TFullReg] - move(s, cast[seq[TFullReg]](a.slots)) - s[a.ra].ensureKind(rkNode) + a.slots[a.ra].ensureKind(rkNode) var n = newNode(nkBracket) for x in v: n.add newStrNode(nkStrLit, x) - s[a.ra].node = n + a.slots[a.ra].node = n template getX(k, field) {.dirty.} = doAssert i < a.rc-1 - let s = cast[seq[TFullReg]](a.slots) - doAssert s[i+a.rb+1].kind == k - result = s[i+a.rb+1].field + doAssert a.slots[i+a.rb+1].kind == k + result = a.slots[i+a.rb+1].field proc getInt*(a: VmArgs; i: Natural): BiggestInt = getX(rkInt, intVal) proc getBool*(a: VmArgs; i: Natural): bool = getInt(a, i) != 0 proc getFloat*(a: VmArgs; i: Natural): BiggestFloat = getX(rkFloat, floatVal) proc getString*(a: VmArgs; i: Natural): string = doAssert i < a.rc-1 - let s = cast[seq[TFullReg]](a.slots) - doAssert s[i+a.rb+1].kind == rkNode - result = s[i+a.rb+1].node.strVal + doAssert a.slots[i+a.rb+1].kind == rkNode + result = a.slots[i+a.rb+1].node.strVal proc getNode*(a: VmArgs; i: Natural): PNode = doAssert i < a.rc-1 - let s = cast[seq[TFullReg]](a.slots) - doAssert s[i+a.rb+1].kind == rkNode - result = s[i+a.rb+1].node + doAssert a.slots[i+a.rb+1].kind == rkNode + result = a.slots[i+a.rb+1].node From 289b31ee752982c2660fc88bb96bbbf2c11836b4 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 26 Mar 2020 19:15:38 +0000 Subject: [PATCH 0214/4254] make nim_temp compile with --gc:arc --sinkInference:off (#13769) * make nim_temp compiler with --gc:arc * trigger build Co-authored-by: cooldome --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 66677e458..e03ddff09 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -425,7 +425,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t - if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst).kind in {tyString, tySequence}: + if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), From 142c59fc378f11301023c2940e08feeea3448696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Fri, 27 Mar 2020 08:36:21 +0100 Subject: [PATCH 0215/4254] fix typos and deprecation warnings for tconvariancerules.nim (#13772) --- tests/cpp/tcovariancerules.nim | 41 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim index e1769b0e6..49fe8015b 100644 --- a/tests/cpp/tcovariancerules.nim +++ b/tests/cpp/tcovariancerules.nim @@ -28,9 +28,9 @@ template reject(x) = import macros -macro skipElse(n: untyped): typed = n[0] +macro skipElse(n: untyped): untyped = n[0] -template acceptWithCovariance(x, otherwise): typed = +template acceptWithCovariance(x, otherwise): untyped = when nimEnableCovariance: x else: @@ -79,16 +79,16 @@ proc wantsCovariantSeq2(s: seq[AnimalRef]) = proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) = for a in s: echo a.x -proc wantsCovariantOperArray(s: openarray[ref Animal]) = +proc wantsCovariantOpenArray(s: openarray[ref Animal]) = for a in s: echo a.x -proc modifiesCovariantOperArray(s: var openarray[ref Animal]) = +proc modifiesCovariantOpenArray(s: var openarray[ref Animal]) = for a in s: echo a.x -proc modifiesDerivedOperArray(s: var openarray[ref Dog]) = +proc modifiesDerivedOpenArray(s: var openarray[ref Dog]) = for a in s: echo a.x -proc wantsNonCovariantOperArray(s: openarray[Animal]) = +proc wantsNonCovariantOpenArray(s: openarray[Animal]) = for a in s: echo a.x proc wantsCovariantArray(s: array[2, ref Animal]) = @@ -199,15 +199,15 @@ accept: wantsCovariantSeq3(@[AnimalRef(cat), dog]) wantsCovariantSeq3(@[cat, dog]) - wantsCovariantOperArray([cat, dog]) + wantsCovariantOpenArray([cat, dog]) acceptWithCovariance: wantsCovariantSeq1(@[cat, cat]) wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")]) # XXX: wantsCovariantSeq3(@[cat, cat]) - wantsCovariantOperArray(@[cat, cat]) - wantsCovariantOperArray([dog, dog]) + wantsCovariantOpenArray(@[cat, cat]) + wantsCovariantOpenArray([dog, dog]) else: echo "cat" echo "cat" @@ -226,7 +226,7 @@ accept: modifiesDerivedArray(dogRefsArray) modifiesDerivedSeq(dogRefs) -reject modifiesCovariantSeq(dogRefs) +reject modifiesCovariantSeqd(ogRefs) reject modifiesCovariantSeq(addr(dogRefs)) reject modifiesCovariantSeq(dogRefs.addr) @@ -245,19 +245,19 @@ when false: wantsNonCovariantArray animalValuesArray reject wantsNonCovariantSeq(dogRefs) -reject modifiesCovariantOperArray(dogRefs) +reject modifiesCovariantOpenArray(dogRefs) reject wantsNonCovariantArray(dogRefsArray) reject wantsNonCovariantSeq(dogValues) reject wantsNonCovariantArray(dogValuesArray) reject modifiesValueArray() -modifiesDerivedOperArray dogRefs -reject modifiesDerivedOperArray(dogValues) -reject modifiesDerivedOperArray(animalRefs) +modifiesDerivedOpenArray dogRefs +reject modifiesDerivedOpenArray(dogValues) +reject modifiesDerivedOpenArray(animalRefs) -reject wantsNonCovariantOperArray(animalRefs) -reject wantsNonCovariantOperArray(dogRefs) -reject wantsNonCovariantOperArray(dogValues) +reject wantsNonCovariantOpenArray(animalRefs) +reject wantsNonCovariantOpenArray(dogRefs) +reject wantsNonCovariantOpenArray(dogValues) var animalRefSeq: seq[ref Animal] @@ -300,12 +300,12 @@ template struct ARR { typedef T DataType[2]; DataType data; }; """.} type - MyPtr {.importcpp: "'0 *"} [out T] = object + MyPtr[out T] {.importcpp: "'0 *"} = object - MySeq {.importcpp: "ARR<'0>", nodecl} [out T] = object + MySeq[out T] {.importcpp: "ARR<'0>", nodecl} = object data: array[2, T] - MyAction {.importcpp: "FN<'0>::type"} [in T] = object + MyAction[in T] {.importcpp: "FN<'0>::type"} = object var cAnimal: MyPtr[Animal] @@ -415,4 +415,3 @@ reject usesAddressOfAnimalRefSeq(addr cAnimalValues) reject usesAddressOfAnimalRefSeq(addr cDogValues) accept usesAddressOfAnimalRefSeq(addr cAnimals) reject usesAddressOfAnimalRefSeq(addr cDogs) - From 0eaacbc2c45376383a6704c76687d05e62e8f772 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 27 Mar 2020 08:08:13 +0000 Subject: [PATCH 0216/4254] More fixes for Haiku (#13774) * osproc: move fork-based code path under the when conditional * osproc: avoid using the environ global on Haiku * osenv: import environ from stdlib.h on Haiku Haiku's environ is declared in `` by default, differing from POSIX and/or Linux. Import it from there to avoid collision with anyone importing `` from Nim. --- lib/pure/includes/osenv.nim | 2 + lib/pure/osproc.nim | 93 +++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index c4c6669f9..e06c4bc49 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -81,6 +81,8 @@ else: # at runtime. proc NSGetEnviron(): ptr cstringArray {. importc: "_NSGetEnviron", header: "".} + elif defined(haiku): + var gEnv {.importc: "environ", header: "".}: cstringArray else: var gEnv {.importc: "environ".}: cstringArray diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9b11d440b..9840973b2 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -826,10 +826,10 @@ elif not defined(useNimRtl): else: proc startProcessAuxFork(data: StartProcessData): Pid {. tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} - {.push stacktrace: off, profiler: off.} - proc startProcessAfterFork(data: ptr StartProcessData) {. - tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} - {.pop.} + {.push stacktrace: off, profiler: off.} + proc startProcessAfterFork(data: ptr StartProcessData) {. + tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} + {.pop.} proc startProcess(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, @@ -1003,56 +1003,57 @@ elif not defined(useNimRtl): return pid - {.push stacktrace: off, profiler: off.} - proc startProcessFail(data: ptr StartProcessData) = - var error: cint = errno - discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error)) - exitnow(1) + {.push stacktrace: off, profiler: off.} + proc startProcessFail(data: ptr StartProcessData) = + var error: cint = errno + discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error)) + exitnow(1) - when not defined(uClibc) and (not defined(linux) or defined(android)): - var environ {.importc.}: cstringArray + when not defined(uClibc) and (not defined(linux) or defined(android)) and + not defined(haiku): + var environ {.importc.}: cstringArray - proc startProcessAfterFork(data: ptr StartProcessData) = - # Warning: no GC here! - # Or anything that touches global structures - all called nim procs - # must be marked with stackTrace:off. Inspect C code after making changes. - if not (poParentStreams in data.options): - discard close(data.pStdin[writeIdx]) - if dup2(data.pStdin[readIdx], readIdx) < 0: - startProcessFail(data) - discard close(data.pStdout[readIdx]) - if dup2(data.pStdout[writeIdx], writeIdx) < 0: - startProcessFail(data) - discard close(data.pStderr[readIdx]) - if (poStdErrToStdOut in data.options): - if dup2(data.pStdout[writeIdx], 2) < 0: + proc startProcessAfterFork(data: ptr StartProcessData) = + # Warning: no GC here! + # Or anything that touches global structures - all called nim procs + # must be marked with stackTrace:off. Inspect C code after making changes. + if not (poParentStreams in data.options): + discard close(data.pStdin[writeIdx]) + if dup2(data.pStdin[readIdx], readIdx) < 0: startProcessFail(data) - else: - if dup2(data.pStderr[writeIdx], 2) < 0: + discard close(data.pStdout[readIdx]) + if dup2(data.pStdout[writeIdx], writeIdx) < 0: + startProcessFail(data) + discard close(data.pStderr[readIdx]) + if (poStdErrToStdOut in data.options): + if dup2(data.pStdout[writeIdx], 2) < 0: + startProcessFail(data) + else: + if dup2(data.pStderr[writeIdx], 2) < 0: + startProcessFail(data) + + if data.workingDir.len > 0: + if chdir(data.workingDir) < 0: startProcessFail(data) - if data.workingDir.len > 0: - if chdir(data.workingDir) < 0: - startProcessFail(data) + discard close(data.pErrorPipe[readIdx]) + discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC) - discard close(data.pErrorPipe[readIdx]) - discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC) - - if (poUsePath in data.options): - when defined(uClibc) or defined(linux): - # uClibc environment (OpenWrt included) doesn't have the full execvpe - let exe = findExe(data.sysCommand) - discard execve(exe, data.sysArgs, data.sysEnv) + if (poUsePath in data.options): + when defined(uClibc) or defined(linux) or defined(haiku): + # uClibc environment (OpenWrt included) doesn't have the full execvpe + let exe = findExe(data.sysCommand) + discard execve(exe, data.sysArgs, data.sysEnv) + else: + # MacOSX doesn't have execvpe, so we need workaround. + # On MacOSX we can arrive here only from fork, so this is safe: + environ = data.sysEnv + discard execvp(data.sysCommand, data.sysArgs) else: - # MacOSX doesn't have execvpe, so we need workaround. - # On MacOSX we can arrive here only from fork, so this is safe: - environ = data.sysEnv - discard execvp(data.sysCommand, data.sysArgs) - else: - discard execve(data.sysCommand, data.sysArgs, data.sysEnv) + discard execve(data.sysCommand, data.sysArgs, data.sysEnv) - startProcessFail(data) - {.pop.} + startProcessFail(data) + {.pop.} proc close(p: Process) = if poParentStreams notin p.options: From 0a49fe5fad36c917f459420d832cda306d449d6e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 27 Mar 2020 12:14:57 +0100 Subject: [PATCH 0217/4254] fixes #13763 (#13777) --- compiler/semstmts.nim | 4 +++- compiler/types.nim | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5232c5706..d0cab48a5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1329,8 +1329,10 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = else: while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0: x = x.lastSon + # we need the 'safeSkipTypes' here because illegally recursive types + # can enter at this point, see bug #13763 if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and - s.typ.skipTypes(abstractPtrs-{tyAlias}).kind notin {tyObject, tyEnum}: + s.typ.safeSkipTypes(abstractPtrs).kind notin {tyObject, tyEnum}: # type aliases are hard: var t = semTypeNode(c, x, nil) assert t != nil diff --git a/compiler/types.nim b/compiler/types.nim index 33c81f9cc..38dc15498 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1503,6 +1503,13 @@ proc containsCompileTimeOnly*(t: PType): bool = return true return false +proc safeSkipTypes*(t: PType, kinds: TTypeKinds): PType = + ## same as 'skipTypes' but with a simple cycle detector. + result = t + var seen = initIntSet() + while result.kind in kinds and not containsOrIncl(seen, result.id): + result = lastSon(result) + type OrdinalType* = enum NoneLike, IntLike, FloatLike From 95ab9ab75da074fcb60f9f2c0e4ef4eab7624f8b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 27 Mar 2020 22:45:22 -0700 Subject: [PATCH 0218/4254] [CI] fix recent freebsd systematic failure (#13788) --- .builds/freebsd.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 352fc2ccb..ef2e8f44d 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,20 +1,25 @@ # see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd image: freebsd/latest -packages: -- databases/sqlite3 -- devel/boehm-gc-threaded -- devel/pcre -- devel/sdl20 -- devel/sfml -- www/node -- devel/gmake -- devel/git + +# packages: +# - databases/sqlite3 +# - devel/boehm-gc-threaded +# - devel/pcre +# - devel/sdl20 +# - devel/sfml +# - www/node +# - devel/gmake +# - devel/git sources: - https://github.com/nim-lang/Nim environment: CC: /usr/bin/clang tasks: - setup: | + # workaround https://github.com/timotheecour/Nim/issues/76 + sudo pkg update -q -f + sudo pkg install -y -q databases/sqlite3 devel/boehm-gc-threaded devel/pcre \ + devel/sdl20 devel/sfml www/node devel/gmake devel/git cd Nim git clone --depth 1 -q https://github.com/nim-lang/csources.git gmake -C csources -j $(sysctl -n hw.ncpu) From cfa1a827dc2c782924e50c92f875277161128490 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 28 Mar 2020 00:51:16 -0700 Subject: [PATCH 0219/4254] fix #13730 (#13787) --- compiler/trees.nim | 8 ++++++-- tests/statictypes/tstatictypes.nim | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index cd26b2b4f..9a1186a4f 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -26,6 +26,10 @@ proc cyclicTree*(n: PNode): bool = var visited: seq[PNode] = @[] cyclicTreeAux(n, visited) +proc sameFloatIgnoreNan(a, b: BiggestFloat): bool {.inline.} = + ## ignores NaN semantics, but ensures 0.0 == -0.0, see #13730 + cast[uint64](a) == cast[uint64](b) or a == b + proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = if a == b: result = true @@ -39,7 +43,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) + of nkFloatLit..nkFloat64Lit: result = sameFloatIgnoreNan(a.floatVal, b.floatVal) of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkCommentStmt: result = a.comment == b.comment of nkEmpty, nkNilLit, nkType: result = true @@ -64,7 +68,7 @@ proc sameTree*(a, b: PNode): bool = result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) + of nkFloatLit..nkFloat64Lit: result = sameFloatIgnoreNan(a.floatVal, b.floatVal) of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true else: diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index c95e499d7..afd15b67d 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -88,6 +88,10 @@ when true: reject: var x = static(v) +block: # issue #13730 + type Foo[T: static[float]] = object + doAssert Foo[0.0] is Foo[-0.0] + when true: type ArrayWrapper1[S: static int] = object From 8c719fce54544c8d14ce7c0e4639c974c1748668 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 29 Mar 2020 09:39:58 -0300 Subject: [PATCH 0220/4254] Fix #13631 (#13789) --- lib/packages/docutils/rstgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index abbf99fed..13dff68e9 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1115,10 +1115,10 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = "\\href{$2}{$1}", [tmp0, tmp1]) of rnDirArg, rnRaw: renderAux(d, n, result) of rnRawHtml: - if d.target != outLatex: + if d.target != outLatex and not lastSon(n).isNil: result.add addNodes(lastSon(n)) of rnRawLatex: - if d.target == outLatex: + if d.target == outLatex and not lastSon(n).isNil: result.add addNodes(lastSon(n)) of rnImage, rnFigure: renderImage(d, n, result) From 06f8c5cb6f04319fd6ca6eafc496f3da882ab341 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 29 Mar 2020 09:08:50 -0700 Subject: [PATCH 0221/4254] fix #13794 HashSet leak (#13800) --- lib/pure/collections/setimpl.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index f7a48ab91..9e68cb072 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -35,8 +35,9 @@ proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A, proc enlarge[A](s: var HashSet[A]) = var n: KeyValuePairSeq[A] - newSeq(n, len(s.data) * growthFactor) + newSeq(n, s.counter.rightSize) swap(s.data, n) # n is now old seq + s.countDeleted = 0 for i in countup(0, high(n)): if isFilledAndValid(n[i].hcode): var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode) From 2a278f6eba5b154920177154bb48733268cacfc5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Mar 2020 22:00:18 +0200 Subject: [PATCH 0222/4254] '.push raises: []' now also affects proc types (#13776) * '.push raises: []' now also affects proc types * fixes the regression * less disruptive bugfix * another attempt --- compiler/commands.nim | 1 + compiler/options.nim | 1 + compiler/pragmas.nim | 6 +++--- compiler/semtypes.nim | 6 ++++++ tests/effects/teffects1.nim | 23 +++++++++++++++++++++-- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index bc6fdde8f..024e6b417 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -877,6 +877,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; # old behaviors go here: defineSymbol(conf.symbols, "nimOldRelativePathBehavior") ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect} + conf.globalOptions.incl optNimV1Emulation else: localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": diff --git a/compiler/options.nim b/compiler/options.nim index d906cd852..b38b5a6bc 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -91,6 +91,7 @@ type # please make sure we have under 32 options optBenchmarkVM # Enables cpuTime() in the VM optProduceAsm # produce assembler code optPanics # turn panics (sysFatal) into a process termination + optNimV1Emulation # emulate Nim v1.0 TGlobalOptions* = set[TGlobalOption] diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 8196c1b4e..52df47ef0 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -42,7 +42,7 @@ const wTags, wLocks, wGcSafe} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks, - wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks, + wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks, wStyleChecks, wAssertions, wWarnings, wHints, wLineDir, wStackTrace, wLineTrace, wOptimization, wHint, wWarning, wError, @@ -1029,7 +1029,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wCodegenDecl: processCodegenDecl(c, it, sym) of wChecks, wObjChecks, wFieldChecks, wRangeChecks, wBoundChecks, wOverflowChecks, wNilChecks, wAssertions, wWarnings, wHints, - wLineDir, wOptimization, wStaticBoundchecks, wStyleChecks, + wLineDir, wOptimization, wStaticBoundchecks, wStyleChecks, wCallconv, wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks, wPatterns, wTrMacros: processOption(c, it, c.config.options) @@ -1147,7 +1147,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: sym.flags.incl sfUsed of wLiftLocals: discard else: invalidPragma(c, it) - elif comesFromPush and whichKeyword(ident) in {wTags, wRaises}: + elif comesFromPush and whichKeyword(ident) != wInvalid: discard "ignore the .push pragma; it doesn't apply" else: if sym == nil or (sym.kind in {skVar, skLet, skParam, diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 867106b87..6e423181c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1580,6 +1580,12 @@ proc semProcTypeWithScope(c: PContext, n: PNode, if n[1].kind != nkEmpty and n[1].len > 0: pragma(c, s, n[1], procTypePragmas) when useEffectSystem: setEffectsForProcType(c.graph, result, n[1]) + elif c.optionStack.len > 0 and optNimV1Emulation notin c.config.globalOptions: + # we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'... + s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), + newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info)) + implicitPragmas(c, s, n, {wTags, wRaises}) + when useEffectSystem: setEffectsForProcType(c.graph, result, s.ast[pragmasPos]) closeScope(c) proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym = diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 6ca24d53e..3bd19f4ab 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -1,7 +1,13 @@ discard """ - errormsg: "can raise an unlisted exception: ref IOError" + errormsg: "type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}'" file: "teffects1.nim" - line: 17 + line: 38 + cmd: "nim check $file" + nimout: '''teffects1.nim(22, 28) template/generic instantiation from here +teffects1.nim(23, 13) Error: can raise an unlisted exception: ref IOError +teffects1.nim(22, 29) Hint: 'IO2Error' is declared but not used [XDeclaredButNotUsed] +teffects1.nim(38, 21) Error: type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' +.raise effects differ''' """ type @@ -18,3 +24,16 @@ proc lier(): int {.raises: [IO2Error].} = proc forw: int = raise newException(IOError, "arg") + +{.push raises: [Defect].} + +type + MyProcType* = proc(x: int): string #{.raises: [ValueError, Defect].} + +proc foo(x: int): string {.raises: [ValueError].} = + if x > 9: + raise newException(ValueError, "Use single digit") + $x + +var p: MyProcType = foo +{.pop.} From 8088633250872de8777c7078e636b2379780e107 Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 30 Mar 2020 13:18:12 +0200 Subject: [PATCH 0223/4254] faster CIs (#13803) * ttables: smaller table, 5x speedup * thavlak: less iterations, less loops; 30% speedup * tasyncclosestall: shorter timeout; 35% speedup * gcleak4: less iterations, 2x speedup * ttimes: remove deprecated stuff * tdangerisrelease: remove cpp backend, 3x speedup * tfrexp1: smaller range, 2x speedup * trtree: fix warnings, less iterations, 6x speedup * tasyncawait_cyclebreaker: smaller swarm size; 2x speedup * trealloc: smaller number of iterations; 10x speedup * towned_binary_tree: less iterations, 4x speedup * tclosure: remove unused code, less iterations; 2x speedup * twaitany: less durations; 1.4x speedup * tasync_misc: less iterations, 2x speedup * t8535: smaller sleep, 1.5x speedup * tmanyjoin: smaller sleep, 2x speedup * t12221: shorter sleeps, removed two slower tests; 1.6x speedup * tfuturestream: smaller sleep; 1.5x speedup * growobjcrash: less iterations; 2x speedup * ttryrecv: smaller sleep; 1.5x speedup * treusetvar: less threads; 2x speedup * delete tthreadanalysis2, basically a duplicate of tthreadanalysis * t7758: less iterations, 1.5x speedup * tasyncawait: smaller swarm, less messages; 1.5x speedup * tjsandnativeasync: smaller sleep, 1.5x speedup * tpendingcheck: smaller sleep, 1.5x speedup * remove rodfiles test category * move tseq from its own category to 'collections' category * remove unneeded tests and helpers from 'assert' category * stdlib: merge tbitops2 into tbitops * remove 'trepr2' from 'stdlib' cat * merge 'tstreams' into one file * remove 'tinefficient_const_table' from 'ccbugs' cat * merge 'tcollections_to_string' into 'tcollections' * tblocking_channel: smaller sleep, small speedup * tconvexhull: less iterartions; 1.2x speedup * merge 'tdeepcopy2' into 'tdeepcopy' * merge 'tdisjoint_slice2' into 'tdisjoint_slice1' * tmissing_deepcopy: smaller sequence * tsendtwice: smaller arrays; 5x speedup * remove 'tindexerrorformatbounds' * disable multimethod tests * remove 'gc:none' and 'refc' without 'd:useRealtimeGC' from gc tests * koch.nim: bootstrap just with '-d:release', no need for 'csource' * add github workflow for documentation * testament: no need for 8 sub-second decimals --- .github/workflows/ci_docs.yml | 45 ++++ koch.nim | 17 +- testament/categories.nim | 10 +- testament/testament.nim | 4 +- tests/assert/tassert2.nim | 44 ++-- tests/assert/tdoassert.nim | 20 -- tests/assert/testhelper.nim | 12 -- tests/assert/trelativeassert.nim | 11 - tests/async/t12221.nim | 30 +-- tests/async/t7758.nim | 2 +- tests/async/tasync_misc.nim | 4 +- tests/async/tasyncawait.nim | 6 +- tests/async/tasyncawait_cyclebreaker.nim | 6 +- tests/async/tasyncclosestall.nim | 1 - tests/async/tfuturestream.nim | 2 +- tests/async/tjsandnativeasync.nim | 2 +- tests/async/tpendingcheck.nim | 2 +- tests/ccgbugs/tinefficient_const_table.nim | 27 --- tests/closure/tclosure.nim | 218 +------------------- tests/collections/tcollections.nim | 108 +++++++++- tests/{seq => collections}/tseq.nim | 0 tests/collections/ttables.nim | 10 +- tests/destructor/towned_binary_tree.nim | 6 +- tests/exception/tindexerrorformatbounds.nim | 31 --- tests/gc/gcleak4.nim | 2 +- tests/gc/growobjcrash.nim | 2 +- tests/gc/thavlak.nim | 16 +- tests/generics/trtree.nim | 48 ++--- tests/method/tmultim.nim | 1 + tests/method/tmultimjs.nim | 1 + tests/misc/tdangerisrelease.nim | 3 +- tests/parallel/tblocking_channel.nim | 4 +- tests/parallel/tconvexhull.nim | 7 +- tests/parallel/tdeepcopy.nim | 60 ++++-- tests/parallel/tdeepcopy2.nim | 6 +- tests/parallel/tdisjoint_slice1.nim | 57 +++-- tests/parallel/tdisjoint_slice2.nim | 40 ---- tests/parallel/tmissing_deepcopy.nim | 6 +- tests/parallel/tsendtwice.nim | 4 +- tests/parallel/twaitany.nim | 8 +- tests/rodfiles/aconv.nim | 9 - tests/rodfiles/amethods.nim | 13 -- tests/rodfiles/bconv.nim | 9 - tests/rodfiles/bmethods.nim | 29 --- tests/rodfiles/bmethods2.nim | 29 --- tests/rodfiles/deada.nim | 8 - tests/rodfiles/deada2.nim | 12 -- tests/rodfiles/deadb.nim | 7 - tests/rodfiles/deadg.nim | 7 - tests/rodfiles/gtkex1.nim | 14 -- tests/rodfiles/gtkex2.nim | 22 -- tests/rodfiles/hallo.nim | 6 - tests/rodfiles/hallo2.nim | 17 -- tests/rodfiles/int2bool.nim | 7 - tests/rodfiles/nim.cfg | 2 - tests/rodfiles/tgeneric1.nim | 13 -- tests/rodfiles/tgeneric2.nim | 13 -- tests/stdlib/tbitops.nim | 176 +++++++++++++++- tests/stdlib/tbitops2.nim | 167 --------------- tests/stdlib/tbitops2.nim.cfg | 2 - tests/stdlib/tfrexp1.nim | 2 +- tests/stdlib/trepr2.nim | 37 ---- tests/stdlib/tstreams.nim | 15 +- tests/stdlib/tstreams2.nim | 12 -- tests/stdlib/tstreams3.nim | 20 -- tests/stdlib/ttimes.nim | 8 +- tests/system/trealloc.nim | 12 +- tests/threads/t8535.nim | 2 +- tests/threads/tmanyjoin.nim | 2 +- tests/threads/treusetvar.nim | 6 +- tests/threads/tthreadanalysis2.nim | 51 ----- tests/threads/ttryrecv.nim | 2 +- 72 files changed, 532 insertions(+), 1082 deletions(-) create mode 100644 .github/workflows/ci_docs.yml delete mode 100644 tests/assert/tdoassert.nim delete mode 100644 tests/assert/testhelper.nim delete mode 100644 tests/assert/trelativeassert.nim delete mode 100644 tests/ccgbugs/tinefficient_const_table.nim rename tests/{seq => collections}/tseq.nim (100%) delete mode 100644 tests/exception/tindexerrorformatbounds.nim delete mode 100644 tests/parallel/tdisjoint_slice2.nim delete mode 100644 tests/rodfiles/aconv.nim delete mode 100644 tests/rodfiles/amethods.nim delete mode 100644 tests/rodfiles/bconv.nim delete mode 100644 tests/rodfiles/bmethods.nim delete mode 100644 tests/rodfiles/bmethods2.nim delete mode 100644 tests/rodfiles/deada.nim delete mode 100644 tests/rodfiles/deada2.nim delete mode 100644 tests/rodfiles/deadb.nim delete mode 100644 tests/rodfiles/deadg.nim delete mode 100644 tests/rodfiles/gtkex1.nim delete mode 100644 tests/rodfiles/gtkex2.nim delete mode 100644 tests/rodfiles/hallo.nim delete mode 100644 tests/rodfiles/hallo2.nim delete mode 100644 tests/rodfiles/int2bool.nim delete mode 100644 tests/rodfiles/nim.cfg delete mode 100644 tests/rodfiles/tgeneric1.nim delete mode 100644 tests/rodfiles/tgeneric2.nim delete mode 100644 tests/stdlib/tbitops2.nim delete mode 100644 tests/stdlib/tbitops2.nim.cfg delete mode 100644 tests/stdlib/trepr2.nim delete mode 100644 tests/stdlib/tstreams2.nim delete mode 100644 tests/stdlib/tstreams3.nim delete mode 100644 tests/threads/tthreadanalysis2.nim diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml new file mode 100644 index 000000000..733f95b96 --- /dev/null +++ b/.github/workflows/ci_docs.yml @@ -0,0 +1,45 @@ +name: Nim Docs CI +on: + pull_request: + # Run only on changes on these files + paths: + - 'lib/*.nim' + - 'doc/*.rst' + +jobs: + build: + name: 'Docs builder' + runs-on: ubuntu-18.04 + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + + - name: 'Checkout csources' + uses: actions/checkout@v2 + with: + repository: nim-lang/csources + path: csources + + - name: 'Add build binaries to PATH' + shell: bash + run: echo "::add-path::${{ github.workspace }}/bin" + + - name: 'Build 1-stage compiler from csources' + shell: bash + run: | + ncpu=$(nproc) + [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 + + make -C csources -j $ncpu CC=gcc ucpu='amd64' + + - name: 'Build koch' + shell: bash + run: nim c koch + + - name: 'Build the real compiler' + shell: bash + run: ./koch boot + + - name: 'Build documentation' + shell: bash + run: ./koch doc diff --git a/koch.nim b/koch.nim index dc23488a7..b05b56916 100644 --- a/koch.nim +++ b/koch.nim @@ -481,10 +481,6 @@ proc runCI(cmd: string) = doAssert cmd.len == 0, cmd # avoid silently ignoring echo "runCI: ", cmd echo hostInfo() - # note(@araq): Do not replace these commands with direct calls (eg boot()) - # as that would weaken our testing efforts. - when defined(posix): # appveyor (on windows) didn't run this - kochExecFold("Boot", "boot") # boot without -d:nimHasLibFFI to make sure this still works kochExecFold("Boot in release mode", "boot -d:release") @@ -494,7 +490,7 @@ proc runCI(cmd: string) = if getEnv("NIM_TEST_PACKAGES", "false") == "true": execFold("Test selected Nimble packages", "nim c -r testament/testament cat nimble-packages") else: - buildTools() # altenatively, kochExec "tools --toolsNoNimble" + buildTools() ## run tests execFold("Test nimscript", "nim e tests/test_nimscript.nims") @@ -504,7 +500,7 @@ proc runCI(cmd: string) = # main bottleneck here execFold("Run tester", "nim c -r -d:nimCoroutines testament/testament --pedantic all -d:nimCoroutines") - block: # CT FFI + block CT_FFI: when defined(posix): # windows can be handled in future PR's execFold("nimble install -y libffi", "nimble install -y libffi") const nimFFI = "./bin/nim.ctffi" @@ -517,15 +513,6 @@ proc runCI(cmd: string) = when defined(posix): execFold("Run nimsuggest tests", "nim c -r nimsuggest/tester") - ## remaining actions - when defined(posix): - kochExecFold("Docs", "docs --git.commit:devel") - kochExecFold("C sources", "csource") - elif defined(windows): - when false: - kochExec "csource" - kochExec "zip" - proc pushCsources() = if not dirExists("../csources/.git"): quit "[Error] no csources git repository found" diff --git a/testament/categories.nim b/testament/categories.nim index 43d39f227..c6ebadfca 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -169,16 +169,8 @@ proc dllTests(r: var TResults, cat: Category, options: string) = # ------------------------------ GC tests ------------------------------------- proc gcTests(r: var TResults, cat: Category, options: string) = - template testWithNone(filename: untyped) = - testSpec r, makeTest("tests/gc" / filename, options & - " --gc:none", cat) - testSpec r, makeTest("tests/gc" / filename, options & - " -d:release --gc:none", cat) - template testWithoutMs(filename: untyped) = testSpec r, makeTest("tests/gc" / filename, options, cat) - testSpec r, makeTest("tests/gc" / filename, options & - " -d:release", cat) testSpec r, makeTest("tests/gc" / filename, options & " -d:release -d:useRealtimeGC", cat) when filename != "gctest": @@ -193,6 +185,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = " --gc:markAndSweep", cat) testSpec r, makeTest("tests/gc" / filename, options & " -d:release --gc:markAndSweep", cat) + template test(filename: untyped) = testWithoutBoehm filename when not defined(windows) and not defined(android): @@ -210,7 +203,6 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "gcleak" test "gcleak2" testWithoutBoehm "gctest" - testWithNone "gctest" test "gcleak3" test "gcleak4" # Disabled because it works and takes too long to run: diff --git a/testament/testament.nim b/testament/testament.nim index a041d771f..f01f3c6c9 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -260,7 +260,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout else: successOrig - let durationStr = duration.formatFloat(ffDecimal, precision = 8).align(11) + let durationStr = duration.formatFloat(ffDecimal, precision = 2).align(5) if backendLogging: backend.writeTestResult(name = name, category = test.cat.string, @@ -271,7 +271,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, given = given) r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success) if success == reSuccess: - maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " secs)" + maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " sec)" elif success == reDisabled: maybeStyledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name elif success == reJoined: diff --git a/tests/assert/tassert2.nim b/tests/assert/tassert2.nim index 50753ba11..3cff47a24 100644 --- a/tests/assert/tassert2.nim +++ b/tests/assert/tassert2.nim @@ -1,45 +1,30 @@ discard """ output: ''' -test1:ok -test2:ok -test3:ok -test4:ok -test5:ok -test6:ok -test7:ok +`false` first assertion from bar +`false` second assertion from bar -1 -tassert2.nim -test8:ok -test9:ok -test10:ok -test11:ok ''' """ -import testhelper +from strutils import endsWith + type TLineInfo = tuple[filename: string, line: int, column: int] TMyError = object of Exception lineinfo: TLineInfo EMyError = ref TMyError -echo("") # NOTE: when entering newlines, adjust `expectedEnd` outputs try: doAssert(false, "msg1") # doAssert test except AssertionError as e: - checkMsg(e.msg, "tassert2.nim(30, 11) `false` msg1", "test1") - -try: - assert false, "msg2" # assert test -except AssertionError as e: - checkMsg(e.msg, "tassert2.nim(35, 10) `false` msg2", "test2") + assert e.msg.endsWith "tassert2.nim(20, 11) `false` msg1" try: assert false # assert test with no msg except AssertionError as e: - checkMsg(e.msg, "tassert2.nim(40, 10) `false` ", "test3") + assert e.msg.endsWith "tassert2.nim(25, 10) `false` " try: let a = 1 @@ -47,13 +32,13 @@ try: # BUG: const folding would make "1+1==1" appear as `false` in # assert message except AssertionError as e: - checkMsg(e.msg, "`a + a == 1` ", "test4") + assert e.msg.endsWith "`a + a == 1` " try: let a = 1 doAssert a+a==1 # ditto with `doAssert` and no parens except AssertionError as e: - checkMsg(e.msg, "`a + a == 1` ", "test5") + assert e.msg.endsWith "`a + a == 1` " proc fooStatic() = # protect against https://github.com/nim-lang/Nim/issues/8758 @@ -80,12 +65,12 @@ block: proc bar: int = # local overrides that are active only in this proc onFailedAssert(msg): - checkMsg(msg, "tassert2.nim(85, 11) `false` first assertion from bar", "test6") + echo msg[^32..^1] assert(false, "first assertion from bar") onFailedAssert(msg): - checkMsg(msg, "tassert2.nim(91, 11) `false` second assertion from bar", "test7") + echo msg[^33..^1] return -1 assert(false, "second assertion from bar") @@ -97,8 +82,7 @@ block: foo() except: let e = EMyError(getCurrentException()) - echo e.lineinfo.filename - checkMsg(e.msg, "tassert2.nim(77, 11) `false` assertion from foo", "test8") + assert e.msg.endsWith "tassert2.nim(62, 11) `false` assertion from foo" block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518 template fun(a: string): string = @@ -109,14 +93,14 @@ block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518 doAssert fun("foo1") == fun("foo2"), "mymsg" except AssertionError as e: # used to expand out the template instantiaiton, sometimes filling hundreds of lines - checkMsg(e.msg, """tassert2.nim(109, 14) `fun("foo1") == fun("foo2")` mymsg""", "test9") + assert e.msg.endsWith "" block: ## checks for issue https://github.com/nim-lang/Nim/issues/9301 try: doAssert 1 + 1 == 3 except AssertionError as e: # used to const fold as false - checkMsg(e.msg, "tassert2.nim(116, 14) `1 + 1 == 3` ", "test10") + assert e.msg.endsWith "tassert2.nim(100, 14) `1 + 1 == 3` " block: ## checks AST isn't transformed as it used to let a = 1 @@ -124,4 +108,4 @@ block: ## checks AST isn't transformed as it used to doAssert a > 1 except AssertionError as e: # used to rewrite as `1 < a` - checkMsg(e.msg, "tassert2.nim(124, 14) `a > 1` ", "test11") + assert e.msg.endsWith "tassert2.nim(108, 14) `a > 1` " diff --git a/tests/assert/tdoassert.nim b/tests/assert/tdoassert.nim deleted file mode 100644 index fa9893505..000000000 --- a/tests/assert/tdoassert.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - cmd: "nim $target -d:release $options $file" - output: ''' -test1:ok -test2:ok -''' -""" - -import testhelper - -onFailedAssert(msg): - checkMsg(msg, "tdoassert.nim(15, 9) `a == 2` foo", "test1") - -var a = 1 -doAssert(a == 2, "foo") - -onFailedAssert(msg): - checkMsg(msg, "tdoassert.nim(20, 10) `a == 3` ", "test2") - -doAssert a == 3 diff --git a/tests/assert/testhelper.nim b/tests/assert/testhelper.nim deleted file mode 100644 index 03bdd2468..000000000 --- a/tests/assert/testhelper.nim +++ /dev/null @@ -1,12 +0,0 @@ -from strutils import endsWith, split -from os import isAbsolute - -proc checkMsg*(msg, expectedEnd, name: string, absolute = true)= - let filePrefix = msg.split(' ', maxSplit = 1)[0] - if absolute and not filePrefix.isAbsolute: - echo name, ":not absolute: `", msg & "`" - elif not msg.endsWith expectedEnd: - echo name, ":expected suffix:\n`" & expectedEnd & "`\ngot:\n`" & msg & "`" - else: - echo name, ":ok" - diff --git a/tests/assert/trelativeassert.nim b/tests/assert/trelativeassert.nim deleted file mode 100644 index 62ab2c421..000000000 --- a/tests/assert/trelativeassert.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - cmd: "nim $target $options --excessiveStackTrace:off $file" - output: ''' -test:ok -''' -""" -import testhelper -try: - doAssert(false, "msg") -except AssertionError as e: - checkMsg(e.msg, "trelativeassert.nim(9, 11) `false` msg", "test", false) diff --git a/tests/async/t12221.nim b/tests/async/t12221.nim index a6ccfb060..70e192356 100644 --- a/tests/async/t12221.nim +++ b/tests/async/t12221.nim @@ -1,7 +1,7 @@ import asyncdispatch, os, times proc doubleSleep(hardSleep: int) {.async.} = - await sleepAsync(100) + await sleepAsync(50) sleep(hardSleep) template assertTime(target, timeTook: float): untyped {.dirty.} = @@ -16,37 +16,25 @@ var # NOTE: this uses poll(3000) to limit timing error potential. start = epochTime() -fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(40) +fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20) while not fut.finished: - poll(3000) + poll(1000) assertTime(150, epochTime() - start) start = epochTime() -fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(100) +fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(50) while not fut.finished: - poll(3000) + poll(1000) assertTime(200, epochTime() - start) start = epochTime() -fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(40) and sleepAsync(300) +fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20) and sleepAsync(200) while not fut.finished: - poll(3000) + poll(1000) assertTime(300, epochTime() - start) start = epochTime() -fut = sleepAsync(50) and sleepAsync(150) and doubleSleep(100) and sleepAsync(300) +fut = (sleepAsync(40) and sleepAsync(100) and doubleSleep(20)) or sleepAsync(300) while not fut.finished: - poll(3000) -assertTime(300, epochTime() - start) - -start = epochTime() -fut = (sleepAsync(50) and sleepAsync(150) and doubleSleep(40)) or sleepAsync(700) -while not fut.finished: - poll(3000) + poll(1000) assertTime(150, epochTime() - start) - -start = epochTime() -fut = (sleepAsync(50) and sleepAsync(150) and doubleSleep(100)) or sleepAsync(700) -while not fut.finished: - poll(3000) -assertTime(200, epochTime() - start) diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim index ce4df1fc9..15aec1c04 100644 --- a/tests/async/t7758.nim +++ b/tests/async/t7758.nim @@ -12,4 +12,4 @@ proc main() = doAssert counter <= 4 -for i in 0 .. 10: main() +for i in 0 .. 4: main() diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index 1febdedb3..298fa64a9 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -9,11 +9,11 @@ block: #6100 done.complete(1) proc asyncSum: Future[int] {.async.} = - for _ in 1..10_000_000: + for _ in 1..1_000_000: result += await done let res = waitFor asyncSum() - doAssert(res == 10000000) + doAssert(res == 1_000_000) block: #7985 proc getData(): Future[JsonNode] {.async.} = diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index b1f893489..a52b0953d 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -1,13 +1,13 @@ discard """ - output: "5000" + output: "2000" """ import asyncdispatch, asyncnet, nativesockets, net, strutils, os var msgCount = 0 const - swarmSize = 50 - messagesToSend = 100 + swarmSize = 40 + messagesToSend = 50 var clientCount = 0 diff --git a/tests/async/tasyncawait_cyclebreaker.nim b/tests/async/tasyncawait_cyclebreaker.nim index 1eb2c4676..0304d4b82 100644 --- a/tests/async/tasyncawait_cyclebreaker.nim +++ b/tests/async/tasyncawait_cyclebreaker.nim @@ -1,5 +1,5 @@ discard """ - output: "50000" + output: "20000" cmd: "nim c -d:nimTypeNames -d:nimCycleBreaker $file" """ import asyncdispatch, asyncnet, nativesockets, net, strutils, os @@ -7,8 +7,8 @@ import asyncdispatch, asyncnet, nativesockets, net, strutils, os var msgCount = 0 const - swarmSize = 500 - messagesToSend = 100 + swarmSize = 400 + messagesToSend = 50 var clientCount = 0 diff --git a/tests/async/tasyncclosestall.nim b/tests/async/tasyncclosestall.nim index be8a13b98..d1c7a5fba 100644 --- a/tests/async/tasyncclosestall.nim +++ b/tests/async/tasyncclosestall.nim @@ -99,4 +99,3 @@ proc server() {.async.} = when isMainModule: waitFor server() - diff --git a/tests/async/tfuturestream.nim b/tests/async/tfuturestream.nim index b5772d5ac..a019df400 100644 --- a/tests/async/tfuturestream.nim +++ b/tests/async/tfuturestream.nim @@ -17,7 +17,7 @@ var fs = newFutureStream[int]() proc alpha() {.async.} = for i in 0 .. 5: await fs.write(i) - await sleepAsync(200) + await sleepAsync(100) echo("Done") fs.complete() diff --git a/tests/async/tjsandnativeasync.nim b/tests/async/tjsandnativeasync.nim index 45839899f..c4db3bcfb 100644 --- a/tests/async/tjsandnativeasync.nim +++ b/tests/async/tjsandnativeasync.nim @@ -19,7 +19,7 @@ else: proc foo() {.async.} = echo "hi" var s = epochTime() - await sleepAsync(500) + await sleepAsync(200) var e = epochTime() doAssert(e - s > 0.1) echo "bye" diff --git a/tests/async/tpendingcheck.nim b/tests/async/tpendingcheck.nim index a5537d8cb..4eceb0353 100644 --- a/tests/async/tpendingcheck.nim +++ b/tests/async/tpendingcheck.nim @@ -7,7 +7,7 @@ import asyncdispatch doAssert(not hasPendingOperations()) proc test() {.async.} = - await sleepAsync(100) + await sleepAsync(50) var f = test() while not f.finished: diff --git a/tests/ccgbugs/tinefficient_const_table.nim b/tests/ccgbugs/tinefficient_const_table.nim deleted file mode 100644 index 7422d0676..000000000 --- a/tests/ccgbugs/tinefficient_const_table.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - output: '''a -long -list -of -words''' - cmd: r"nim c --hints:on $options -d:release $file" - ccodecheck: "! @'genericSeqAssign'" - target: "c" -""" - -# bug #4354 -import tables -import sets -import strutils - -#const FRUITS = ["banana", "apple", "grapes"] -#let FRUITS = ["banana", "apple", "grapes"].toSet -const FRUITS = {"banana":0, "apple":0, "grapes":0}.toTable - -proc main() = - let L = "a long list of words".split() - for word in L: - if word notin FRUITS: - echo(word) - -main() diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim index cfef4193a..7e2ec7a77 100644 --- a/tests/closure/tclosure.nim +++ b/tests/closure/tclosure.nim @@ -41,10 +41,6 @@ block tclosure: proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) = for i in 0..n.len-1: n[i] = fn(n[i]) - proc foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int = - for i in 0..n.len-1: - result = fn(result, n[i]) - proc each(n: openarray[int], fn: proc(x: int) {.closure.}) = for i in 0..n.len-1: fn(n[i]) @@ -67,18 +63,6 @@ block tclosure: #OUT 2 4 6 8 10 - type - ITest = tuple[ - setter: proc(v: int), - getter: proc(): int] - - proc getInterf(): ITest = - var shared: int - - return (setter: proc (x: int) = shared = x, - getter: proc (): int = return shared) - - # bug #5015 type Mutator = proc(matched: string): string {.noSideEffect, gcsafe, locks: 0.} @@ -180,7 +164,7 @@ block tclosure0: block tclosure3: proc main = const n = 30 - for iterations in 0..50_000: + for iterations in 0..10_000: var s: seq[proc(): string {.closure.}] = @[] for i in 0 .. n-1: (proc () = @@ -203,210 +187,12 @@ block tclosure4: let json_elems = json_params["files"].elems # These fail compilation. var files = map(json_elems, proc (x: JsonNode): string = x.str) - #var files = json_elems.map do (x: JsonNode) -> string: x.str let text = """{"files": ["a", "b", "c"]}""" run((text.parseJson).fields) -import hashes, math -block tclosurebug2: - type - TSlotEnum = enum seEmpty, seFilled, seDeleted - TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] - TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - - TOrderedKeyValuePair[A, B] = tuple[ - slot: TSlotEnum, next: int, key: A, val: B] - TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]] - OrderedTable[A, B] = object ## table that remembers insertion order - data: TOrderedKeyValuePairSeq[A, B] - counter, first, last: int - - const - growthFactor = 2 - - proc mustRehash(length, counter: int): bool {.inline.} = - assert(length > counter) - result = (length * 2 < counter * 3) or (length - counter < 4) - - proc nextTry(h, maxHash: Hash): Hash {.inline.} = - result = ((5 * h) + 1) and maxHash - - template rawGetImpl() {.dirty.} = - var h: Hash = hash(key) and high(t.data) # start with real hash value - while t.data[h].slot != seEmpty: - if t.data[h].key == key and t.data[h].slot == seFilled: - return h - h = nextTry(h, high(t.data)) - result = -1 - - template rawInsertImpl() {.dirty.} = - var h: Hash = hash(key) and high(data) - while data[h].slot == seFilled: - h = nextTry(h, high(data)) - data[h].key = key - data[h].val = val - data[h].slot = seFilled - - template addImpl() {.dirty.} = - if mustRehash(len(t.data), t.counter): enlarge(t) - rawInsert(t, t.data, key, val) - inc(t.counter) - - template putImpl() {.dirty.} = - var index = rawGet(t, key) - if index >= 0: - t.data[index].val = val - else: - addImpl() - - proc len[A, B](t: OrderedTable[A, B]): int {.inline.} = - ## returns the number of keys in `t`. - result = t.counter - - template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = - var h = t.first - while h >= 0: - var nxt = t.data[h].next - if t.data[h].slot == seFilled: yieldStmt - h = nxt - - iterator pairs[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] = - ## iterates over any (key, value) pair in the table `t` in insertion - ## order. - forAllOrderedPairs: - yield (t.data[h].key, t.data[h].val) - - iterator mpairs[A, B](t: var OrderedTable[A, B]): tuple[key: A, val: var B] = - ## iterates over any (key, value) pair in the table `t` in insertion - ## order. The values can be modified. - forAllOrderedPairs: - yield (t.data[h].key, t.data[h].val) - - iterator keys[A, B](t: OrderedTable[A, B]): A = - ## iterates over any key in the table `t` in insertion order. - forAllOrderedPairs: - yield t.data[h].key - - iterator values[A, B](t: OrderedTable[A, B]): B = - ## iterates over any value in the table `t` in insertion order. - forAllOrderedPairs: - yield t.data[h].val - - iterator mvalues[A, B](t: var OrderedTable[A, B]): var B = - ## iterates over any value in the table `t` in insertion order. The values - ## can be modified. - forAllOrderedPairs: - yield t.data[h].val - - proc rawGet[A, B](t: OrderedTable[A, B], key: A): int = - rawGetImpl() - - proc `[]`[A, B](t: OrderedTable[A, B], key: A): B = - ## retrieves the value at ``t[key]``. If `key` is not in `t`, - ## default empty value for the type `B` is returned - ## and no exception is raised. One can check with ``hasKey`` whether the key - ## exists. - var index = rawGet(t, key) - if index >= 0: result = t.data[index].val - - proc mget[A, B](t: var OrderedTable[A, B], key: A): var B = - ## retrieves the value at ``t[key]``. The value can be modified. - ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. - var index = rawGet(t, key) - if index >= 0: result = t.data[index].val - else: raise newException(KeyError, "key not found: " & $key) - - proc hasKey[A, B](t: OrderedTable[A, B], key: A): bool = - ## returns true iff `key` is in the table `t`. - result = rawGet(t, key) >= 0 - - proc rawInsert[A, B](t: var OrderedTable[A, B], - data: var TOrderedKeyValuePairSeq[A, B], - key: A, val: B) = - rawInsertImpl() - data[h].next = -1 - if t.first < 0: t.first = h - if t.last >= 0: data[t.last].next = h - t.last = h - - proc enlarge[A, B](t: var OrderedTable[A, B]) = - var n: TOrderedKeyValuePairSeq[A, B] - newSeq(n, len(t.data) * growthFactor) - var h = t.first - t.first = -1 - t.last = -1 - while h >= 0: - var nxt = t.data[h].next - if t.data[h].slot == seFilled: - rawInsert(t, n, t.data[h].key, t.data[h].val) - h = nxt - swap(t.data, n) - - proc `[]=`[A, B](t: var OrderedTable[A, B], key: A, val: B) = - ## puts a (key, value)-pair into `t`. - putImpl() - - proc add[A, B](t: var OrderedTable[A, B], key: A, val: B) = - ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. - addImpl() - - proc iniOrderedTable[A, B](initialSize=64): OrderedTable[A, B] = - ## creates a new ordered hash table that is empty. `initialSize` needs to be - ## a power of two. - assert isPowerOfTwo(initialSize) - result.counter = 0 - result.first = -1 - result.last = -1 - newSeq(result.data, initialSize) - - proc toOrderedTable[A, B](pairs: openarray[tuple[key: A, - val: B]]): OrderedTable[A, B] = - ## creates a new ordered hash table that contains the given `pairs`. - result = iniOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) - for key, val in items(pairs): result[key] = val - - proc sort[A, B](t: var OrderedTable[A,B], - cmp: proc (x, y: tuple[key: A, val: B]): int {.closure.}) = - ## sorts the ordered table so that the entry with the highest counter comes - ## first. This is destructive (with the advantage of being efficient)! - ## You must not modify `t` afterwards! - ## You can use the iterators `pairs`, `keys`, and `values` to iterate over - ## `t` in the sorted order. - - # we use shellsort here; fast enough and simple - var h = 1 - while true: - h = 3 * h + 1 - if h >= high(t.data): break - while true: - h = h div 3 - for i in countup(h, high(t.data)): - var j = i - #echo(t.data.len, " ", j, " - ", h) - #echo(repr(t.data[j-h])) - proc rawCmp(x, y: TOrderedKeyValuePair[A, B]): int = - if x.slot in {seEmpty, seDeleted} and y.slot in {seEmpty, seDeleted}: - return 0 - elif x.slot in {seEmpty, seDeleted}: - return -1 - elif y.slot in {seEmpty, seDeleted}: - return 1 - else: - let item1 = (x.key, x.val) - let item2 = (y.key, y.val) - return cmp(item1, item2) - - while rawCmp(t.data[j-h], t.data[j]) <= 0: - swap(t.data[j], t.data[j-h]) - j = j-h - if j < h: break - if h == 1: break - - - import sugar block inference3304: type @@ -513,7 +299,7 @@ block tflatmap: let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng)) flatMap(s, g) - let f = nextInt.map(i => i - i mod 2) + discard nextInt.map(i => i - i mod 2) diff --git a/tests/collections/tcollections.nim b/tests/collections/tcollections.nim index 2f8cfece7..5c95cee28 100644 --- a/tests/collections/tcollections.nim +++ b/tests/collections/tcollections.nim @@ -2,7 +2,7 @@ discard """ output: "" """ -import deques, sequtils +import sets, tables, deques, lists, critbits, sequtils block tapply: @@ -52,3 +52,109 @@ block tmapit: # since ``len`` is not available var r = st.mapIt($(it+10)) doAssert r == @["10", "11", "12", "13", "14"] + + + +# Collections to string: + +# Tests for tuples +doAssert $(1, 2, 3) == "(1, 2, 3)" +doAssert $("1", "2", "3") == """("1", "2", "3")""" +doAssert $('1', '2', '3') == """('1', '2', '3')""" + +# Tests for seqs +doAssert $(@[1, 2, 3]) == "@[1, 2, 3]" +doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]""" +doAssert $(@['1', '2', '3']) == """@['1', '2', '3']""" + +# Tests for sets +doAssert $(toHashSet([1])) == "{1}" +doAssert $(toHashSet(["1"])) == """{"1"}""" +doAssert $(toHashSet(['1'])) == """{'1'}""" +doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}" +doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}""" +doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}""" + +# Tests for tables +doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}""" +doAssert $({"1": 1, "2": 2}.toTable) == """{"1": 1, "2": 2}""" + +# Tests for deques +block: + var d = initDeque[int]() + d.addLast(1) + doAssert $d == "[1]" +block: + var d = initDeque[string]() + d.addLast("1") + doAssert $d == """["1"]""" +block: + var d = initDeque[char]() + d.addLast('1') + doAssert $d == "['1']" + +# Tests for lists +block: + var l = initDoublyLinkedList[int]() + l.append(1) + l.append(2) + l.append(3) + doAssert $l == "[1, 2, 3]" +block: + var l = initDoublyLinkedList[string]() + l.append("1") + l.append("2") + l.append("3") + doAssert $l == """["1", "2", "3"]""" +block: + var l = initDoublyLinkedList[char]() + l.append('1') + l.append('2') + l.append('3') + doAssert $l == """['1', '2', '3']""" + +# Tests for critbits +block: + var t: CritBitTree[int] + t["a"] = 1 + doAssert $t == """{"a": 1}""" +block: + var t: CritBitTree[string] + t["a"] = "1" + doAssert $t == """{"a": "1"}""" +block: + var t: CritBitTree[char] + t["a"] = '1' + doAssert $t == """{"a": '1'}""" + + +# Test escaping behavior +block: + var s = "" + s.addQuoted('\0') + s.addQuoted('\31') + s.addQuoted('\127') + doAssert s == "'\\x00''\\x1F''\\x7F'" +block: + var s = "" + s.addQuoted('\\') + s.addQuoted('\'') + s.addQuoted('\"') + doAssert s == """'\\''\'''\"'""" +block: + var s = "" + s.addQuoted("å") + s.addQuoted("ä") + s.addQuoted("ö") + s.addEscapedChar('\xFF') + doAssert s == """"å""ä""ö"\xFF""" + +# Test customized element representation +type CustomString = object + +proc addQuoted(s: var string, x: CustomString) = + s.add("") + +block: + let s = @[CustomString()] + doAssert $s == "@[]" diff --git a/tests/seq/tseq.nim b/tests/collections/tseq.nim similarity index 100% rename from tests/seq/tseq.nim rename to tests/collections/tseq.nim diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 9b7506d1a..a59707865 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -173,19 +173,15 @@ block tableconstr: block ttables2: proc TestHashIntInt() = var tab = initTable[int,int]() - when defined(nimTestsTablesDisableSlow): - # helps every single time when this test needs to be debugged - let n = 1_000 - else: - let n = 1_000_000 + let n = 100_000 for i in 1..n: tab[i] = i for i in 1..n: var x = tab[i] if x != i : echo "not found ", i - proc run1() = # occupied Memory stays constant, but - for i in 1 .. 50: # aborts at run: 44 on win32 with 3.2GB with out of memory + proc run1() = + for i in 1 .. 50: TestHashIntInt() # bug #2107 diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim index 3ec80badf..72f7cae0c 100644 --- a/tests/destructor/towned_binary_tree.nim +++ b/tests/destructor/towned_binary_tree.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' - output: '''331665 -(allocCount: 333335, deallocCount: 333335)''' + output: '''31665 +(allocCount: 33335, deallocCount: 33335)''' """ # bug #11053 @@ -72,7 +72,7 @@ proc main() = cur = 5'i32 res = 0 - for i in 1 ..< 1000000: + for i in 1 ..< 100000: let a = i mod 3 cur = (cur * 57 + 43) mod 10007 case a: diff --git a/tests/exception/tindexerrorformatbounds.nim b/tests/exception/tindexerrorformatbounds.nim deleted file mode 100644 index 7563c5ffa..000000000 --- a/tests/exception/tindexerrorformatbounds.nim +++ /dev/null @@ -1,31 +0,0 @@ -import os, osproc, strutils - -const characters = "abcdefghijklmnopqrstuvwxyz" -var s: string - -# # chcks.nim:23 -# # test formatErrorIndexBound returns correct bounds -block: - s = characters - try: - discard s[0..999] - except IndexError: - let msg = getCurrentExceptionMsg() - let expected = "index $# not in 0 .. $#" % [$len(s), $(len(s)-1)] - doAssert msg.contains expected, $(msg, expected) - -block: - try: - discard paramStr(999) - except IndexError: - let msg = getCurrentExceptionMsg() - let expected = "index 999 not in 0 .. 0" - doAssert msg.contains expected, $(msg, expected) - -block: - const nim = getCurrentCompilerExe() - for i in 1..4: - let (outp, errC) = execCmdEx("$# e tests/exception/testindexerroroutput.nims test$#" % [nim, $i]) - let expected = "index 3 not in 0 .. 2" - doAssert errC != 0 - doAssert outp.contains expected, $(outp, errC, expected, i) diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim index fbe18a386..a72db67b7 100644 --- a/tests/gc/gcleak4.nim +++ b/tests/gc/gcleak4.nim @@ -35,7 +35,7 @@ proc newPlus(a, b: sink(ref TExpr)): ref TPlusExpr = const Limit = when compileOption("gc", "markAndSweep") or compileOption("gc", "boehm"): 5*1024*1024 else: 500_000 -for i in 0..100_000: +for i in 0..50_000: var s: array[0..11, ref TExpr] for j in 0..high(s): s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4)) diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index 07f92b8f4..84fd30a4f 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -18,7 +18,7 @@ const Limit = 5*1024*1024 proc main = var counter = 0 - for i in 0 .. 100_000: + for i in 0 .. 10_000: for k, v in handleRequest("nick=Elina2&type=activate"): inc counter if counter mod 100 == 0: diff --git a/tests/gc/thavlak.nim b/tests/gc/thavlak.nim index b4cdacf7c..471b9891c 100644 --- a/tests/gc/thavlak.nim +++ b/tests/gc/thavlak.nim @@ -1,13 +1,13 @@ discard """ output: '''Welcome to LoopTesterApp, Nim edition Constructing Simple CFG... -15000 dummy loops +5000 dummy loops Constructing CFG... Performing Loop Recognition 1 Iteration -Another 5 iterations... -..... -Found 1 loops (including artificial root node) (5)''' +Another 3 iterations... +... +Found 1 loops (including artificial root node) (3)''' """ # bug #3184 @@ -384,9 +384,9 @@ proc run(self: var LoopTesterApp) = discard self.cfg.createNode(1) self.buildConnect(0, 2) - echo "15000 dummy loops" + echo "5000 dummy loops" - for i in 1..15000: + for i in 1..5000: withScratchRegion: var h = newHavlakLoopFinder(self.cfg, newLsg()) discard h.findLoops @@ -414,10 +414,10 @@ proc run(self: var LoopTesterApp) = var h = newHavlakLoopFinder(self.cfg, newLsg()) var loops = h.findLoops - echo "Another 5 iterations..." + echo "Another 3 iterations..." var sum = 0 - for i in 1..5: + for i in 1..3: withScratchRegion: write stdout, "." flushFile(stdout) diff --git a/tests/generics/trtree.nim b/tests/generics/trtree.nim index 4bd7d11f4..b45ac8c83 100644 --- a/tests/generics/trtree.nim +++ b/tests/generics/trtree.nim @@ -72,20 +72,20 @@ proc newRStarTree*[M, D: Dim; RT, LT](minFill: range[30 .. 50] = 40): RStarTree[ result.root = newLeaf[M, D, RT, LT]() proc center(r: Box): auto =#BoxCenter[r.len, type(r[0].a)] = - var result: BoxCenter[r.len, type(r[0].a)] + var res: BoxCenter[r.len, type(r[0].a)] for i in 0 .. r.high: when r[0].a is SomeInteger: - result[i] = (r[i].a + r[i].b) div 2 + res[i] = (r[i].a + r[i].b) div 2 elif r[0].a is SomeFloat: - result[i] = (r[i].a + r[i].b) / 2 + res[i] = (r[i].a + r[i].b) / 2 else: assert false - return result + return res proc distance(c1, c2: BoxCenter): auto = - var result: type(c1[0]) + var res: type(c1[0]) for i in 0 .. c1.high: - result += (c1[i] - c2[i]) * (c1[i] - c2[i]) - return result + res += (c1[i] - c2[i]) * (c1[i] - c2[i]) + return res proc overlap(r1, r2: Box): auto = result = type(r1[0].a)(1) @@ -177,21 +177,6 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev n = nn.a[i0].n return n -proc chooseLeaf[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; level: int): H[M, D, RT, LT] = - assert level >= 0 - var n = t.root - while n.level > level: - var j = -1 # selected index - var x: type(b[0].a) - let nn = Node[M, D, RT, LT](n) - for i in 0 ..< n.numEntries: - let h = enlargement(nn.a[i].b, b) - if j < 0 or h < x or (x == h and area(nn.a[i].b) < area(nn.a[j].b)): - x = h - j = i - n = nn.a[j].n - return n - proc pickSeeds[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; bx: Box[D, RT]): (int, int) = var i0, j0: int var bi, bj: type(bx) @@ -412,12 +397,7 @@ proc adjustTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; l, ll: H[M, D, RT, LT nn = nil else: let h: N[M, D, RT, LT] = (b, nn) - if t of RStarTree[M, D, RT, LT]: - nn = overflowTreatment(RStarTree[M, D, RT, LT](t), p, h) - elif t of RTree[M, D, RT, LT]: - nn = quadraticSplit(RTree[M, D, RT, LT](t), p, h) - else: - assert false + nn = quadraticSplit(t, p, h) assert n == H[M, D, RT, LT](p) assert n != nil assert t.root != nil @@ -567,18 +547,16 @@ proc condenseTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: Leaf[M, D, RT rsinsert(RStarTree[M, D, RT, LT](t), Node[M, D, RT, LT](n).a[i], n.level) else: assert false - elif t of RTree[M, D, RT, LT]: + else: for n in q: if n of Leaf[M, D, RT, LT]: for i in 0 ..< n.numEntries: - insert(RTree[M, D, RT, LT](t), Leaf[M, D, RT, LT](n).a[i]) + insert(t, Leaf[M, D, RT, LT](n).a[i]) elif n of Node[M, D, RT, LT]: for i in 0 ..< n.numEntries: - insert(RTree[M, D, RT, LT](t), Node[M, D, RT, LT](n).a[i], n.level) + insert(t, Node[M, D, RT, LT](n).a[i], n.level) else: assert false - else: - assert false proc delete*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): bool {.discardable.} = let l = findLeaf(t, leaf) @@ -659,6 +637,4 @@ proc test(n: int) = assert r.len == r2.len assert r.sorted(system.cmp) == r2.sorted(system.cmp) -test(1500) - -# 651 lines +test(500) diff --git a/tests/method/tmultim.nim b/tests/method/tmultim.nim index 7023e18bf..b6fed024e 100644 --- a/tests/method/tmultim.nim +++ b/tests/method/tmultim.nim @@ -10,6 +10,7 @@ collide: thing, unit | do nothing ''' joinable: false + disabled: true """ diff --git a/tests/method/tmultimjs.nim b/tests/method/tmultimjs.nim index ce62a2c23..36960f2e1 100644 --- a/tests/method/tmultimjs.nim +++ b/tests/method/tmultimjs.nim @@ -4,6 +4,7 @@ discard """ Hi derived! hello ''' + disabled: true """ diff --git a/tests/misc/tdangerisrelease.nim b/tests/misc/tdangerisrelease.nim index 26ce75ac4..e1854dca5 100644 --- a/tests/misc/tdangerisrelease.nim +++ b/tests/misc/tdangerisrelease.nim @@ -1,6 +1,5 @@ discard """ - cmd: "nim $target $options -r $file" - targets: "c cpp" + cmd: "nim c $options -r $file" matrix: "-d:danger; -d:release" output: ''' a diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim index 8b8b49454..6ec0e1588 100644 --- a/tests/parallel/tblocking_channel.nim +++ b/tests/parallel/tblocking_channel.nim @@ -25,11 +25,11 @@ proc emitter() = spawn emitter() # At this point emitter should be stuck in `send` -sleep(100) # Sleep a bit to ensure that it is still stuck +sleep(50) # Sleep a bit to ensure that it is still stuck doAssert(not msgSent) spawn receiver() -sleep(100) # Sleep a bit to let receicer consume the messages +sleep(50) # Sleep a bit to let receicer consume the messages doAssert(msgSent) # Sender should be unblocked doAssert(chan.trySend(4)) diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim index 184a131a2..ebadb874d 100644 --- a/tests/parallel/tconvexhull.nim +++ b/tests/parallel/tconvexhull.nim @@ -51,12 +51,11 @@ proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : s ul[k] = spawn half[T](points, k == 0) result = concat(^ul[0], ^ul[1]) -var s = map(toSeq(0..99999), proc(x: int): Point = (float(x div 1000), float(x mod 1000))) +var s = map(toSeq(0..9999), proc(x: int): Point = (float(x div 100), float(x mod 100))) # On some runs, this pool size reduction will set the "shutdown" attribute on the # worker thread that executes our spawned task, before we can read the flowvars. setMaxPoolSize 2 -#echo convex_hull[Point](s, cmpPoint) -for i in 0..5: +for i in 0..2: doAssert convex_hull[Point](s, cmpPoint) == - @[(0.0, 0.0), (99.0, 0.0), (99.0, 999.0), (0.0, 999.0)] + @[(0.0, 0.0), (99.0, 0.0), (99.0, 99.0), (0.0, 99.0)] diff --git a/tests/parallel/tdeepcopy.nim b/tests/parallel/tdeepcopy.nim index 84e2edf3f..499ea94d4 100644 --- a/tests/parallel/tdeepcopy.nim +++ b/tests/parallel/tdeepcopy.nim @@ -1,18 +1,54 @@ discard """ - output: '''13 abc''' + output: ''' +13 abc +called deepCopy for int +called deepCopy for int +done999 999 +''' """ -type - PBinaryTree = ref object - le, ri: PBinaryTree - value: int +import threadpool + +block one: + type + PBinaryTree = ref object + le, ri: PBinaryTree + value: int + + proc main = + var x: PBinaryTree + deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13)))) + var y: string + deepCopy y, "abc" + echo x.ri.le.value, " ", y + + main() -proc main = - var x: PBinaryTree - deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13)))) - var y: string - deepCopy y, "abc" - echo x.ri.le.value, " ", y +block two: + type + Bar[T] = object + x: T -main() + proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] = + result.new + result.x = b.x + when T is int: + echo "called deepCopy for int" + else: + echo "called deepCopy for something else" + + proc foo(b: ref Bar[int]): int = 999 + +# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': + + proc main = + var dummy: ref Bar[int] + new(dummy) + dummy.x = 44 + #parallel: + let f = spawn foo(dummy) + let b = spawn foo(dummy) + echo "done", ^f, " ", ^b + + main() diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim index 2ad623ed1..a9caab604 100644 --- a/tests/parallel/tdeepcopy2.nim +++ b/tests/parallel/tdeepcopy2.nim @@ -1,7 +1,9 @@ discard """ - output: '''called deepCopy for int + output: ''' called deepCopy for int -done999 999''' +called deepCopy for int +done999 999 +''' """ import threadpool diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim index c1d0e52f8..edcc30ece 100644 --- a/tests/parallel/tdisjoint_slice1.nim +++ b/tests/parallel/tdisjoint_slice1.nim @@ -2,20 +2,49 @@ discard """ outputsub: "EVEN 28" """ -import threadpool +import threadpool, locks -proc odd(a: int) = echo "ODD ", a -proc even(a: int) = echo "EVEN ", a +block one: + proc odd(a: int) = echo "ODD ", a + proc even(a: int) = echo "EVEN ", a -proc main() = - var a: array[0..30, int] - for i in low(a)..high(a): a[i] = i - parallel: - var i = 0 - while i <= 29: - spawn even(a[i]) - spawn odd(a[i+1]) - inc i, 2 - # is correct here + proc main() = + var a: array[0..30, int] + for i in low(a)..high(a): a[i] = i + parallel: + var i = 0 + while i <= 29: + spawn even(a[i]) + spawn odd(a[i+1]) + inc i, 2 + # is correct here -main() + main() + + +block two: + var echoLock: Lock + initLock echoLock + + proc f(a: openArray[int]) = + for x in a: + withLock echoLock: + echo x + + proc f(a: int) = + withLock echoLock: + echo a + + proc main() = + var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] + parallel: + spawn f(a[0..2]) + #spawn f(a[16..30]) + var i = 3 + while i <= 8: + spawn f(a[i]) + spawn f(a[i+1]) + inc i, 2 + # is correct here + + main() diff --git a/tests/parallel/tdisjoint_slice2.nim b/tests/parallel/tdisjoint_slice2.nim deleted file mode 100644 index 25cb2362f..000000000 --- a/tests/parallel/tdisjoint_slice2.nim +++ /dev/null @@ -1,40 +0,0 @@ -discard """ - output: '''0 -1 -2 -3 -4 -5 -6 -7 -8''' - sortoutput: true -""" - -import threadpool, locks - -var echoLock: Lock -initLock echoLock - -proc f(a: openArray[int]) = - for x in a: - withLock echoLock: - echo x - -proc f(a: int) = - withLock echoLock: - echo a - -proc main() = - var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] - parallel: - spawn f(a[0..2]) - #spawn f(a[16..30]) - var i = 3 - while i <= 8: - spawn f(a[i]) - spawn f(a[i+1]) - inc i, 2 - # is correct here - -main() diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim index 94e027b60..7803439fa 100644 --- a/tests/parallel/tmissing_deepcopy.nim +++ b/tests/parallel/tmissing_deepcopy.nim @@ -26,10 +26,10 @@ proc greet(p:Person) = " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }" proc setup = - for i in 0 ..< 20: + for i in 0 ..< 10: people.add newPerson("Person" & $(i + 1)) - for i in 0 ..< 20: - people[i].friend = people[19-i] + for i in 0 ..< 10: + people[i].friend = people[9-i] proc update = parallel: diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim index 0b3ce15a5..03b7fda47 100644 --- a/tests/parallel/tsendtwice.nim +++ b/tests/parallel/tsendtwice.nim @@ -17,9 +17,9 @@ import tables type Base* = ref object of RootObj someSeq: seq[int] - baseData: array[400000, byte] + baseData: array[40000, byte] Derived* = ref object of Base - data: array[400000, byte] + data: array[40000, byte] type ThreadPool = ref object diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim index 2be3d432f..b58cadd86 100644 --- a/tests/parallel/twaitany.nim +++ b/tests/parallel/twaitany.nim @@ -3,7 +3,7 @@ discard """ """ # bug #7638 -import threadpool, os, strformat +import threadpool, os proc timer(d: int): int = #echo fmt"sleeping {d}" @@ -11,7 +11,7 @@ proc timer(d: int): int = #echo fmt"done {d}" return d -var durations = [1000, 1500, 2000, 2500, 3000] +var durations = [1000, 1500, 2000] var tasks: seq[FlowVarBase] = @[] var results: seq[int] = @[] @@ -25,11 +25,9 @@ while index != -1: #echo repr results index = blockUntilAny(tasks) -doAssert results.len == 5 +doAssert results.len == 3 doAssert 1000 in results doAssert 1500 in results doAssert 2000 in results -doAssert 2500 in results -doAssert 3000 in results sync() echo "true" diff --git a/tests/rodfiles/aconv.nim b/tests/rodfiles/aconv.nim deleted file mode 100644 index ffd8f3648..000000000 --- a/tests/rodfiles/aconv.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: "ugly conversion successful" -""" - -import int2bool - -if 4: - echo "ugly conversion successful" - diff --git a/tests/rodfiles/amethods.nim b/tests/rodfiles/amethods.nim deleted file mode 100644 index 29cf757f7..000000000 --- a/tests/rodfiles/amethods.nim +++ /dev/null @@ -1,13 +0,0 @@ - -type - TBaseClass* = object of RootObj - -proc newBaseClass*: ref TBaseClass = - new result - -method echoType*(x: ref TBaseClass) {.base.} = - echo "base class" - -proc echoAlias*(x: ref TBaseClass) = - echoType x - diff --git a/tests/rodfiles/bconv.nim b/tests/rodfiles/bconv.nim deleted file mode 100644 index 2289a7f97..000000000 --- a/tests/rodfiles/bconv.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: "ugly conversion successful 2" -""" - -import int2bool - -if 4: - echo "ugly conversion successful 2" - diff --git a/tests/rodfiles/bmethods.nim b/tests/rodfiles/bmethods.nim deleted file mode 100644 index c77941e4a..000000000 --- a/tests/rodfiles/bmethods.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - output: '''derived class -base class -''' -""" - -import amethods - - -type - TDerivedClass* = object of TBaseClass - -proc newDerivedClass: ref TDerivedClass = - new result - -method echoType*(x: ref TDerivedClass) = - echo "derived class" - -var b, d: ref TBaseClass - -b = newBaseClass() -d = newDerivedClass() - -#b.echoType() -#d.echoType() - -echoAlias d -echoAlias b - diff --git a/tests/rodfiles/bmethods2.nim b/tests/rodfiles/bmethods2.nim deleted file mode 100644 index c9d25eee4..000000000 --- a/tests/rodfiles/bmethods2.nim +++ /dev/null @@ -1,29 +0,0 @@ -discard """ - output: '''derived class 2 -base class -''' -""" - -import amethods - - -type - TDerivedClass* = object of TBaseClass - -proc newDerivedClass: ref TDerivedClass = - new result - -method echoType*(x: ref TDerivedClass) = - echo "derived class 2" - -var b, d: ref TBaseClass - -b = newBaseClass() -d = newDerivedClass() - -#b.echoType() -#d.echoType() - -echoAlias d -echoAlias b - diff --git a/tests/rodfiles/deada.nim b/tests/rodfiles/deada.nim deleted file mode 100644 index 3fa4192f8..000000000 --- a/tests/rodfiles/deada.nim +++ /dev/null @@ -1,8 +0,0 @@ -discard """ - output: '''246 -''' -""" - -import deadg, deadb - - diff --git a/tests/rodfiles/deada2.nim b/tests/rodfiles/deada2.nim deleted file mode 100644 index 2925b4d43..000000000 --- a/tests/rodfiles/deada2.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - output: '''246 -xyzabc -''' -""" - -import deadg, deadb - -# now add call to previously unused proc p2: -echo p2("xyz", "abc") - - diff --git a/tests/rodfiles/deadb.nim b/tests/rodfiles/deadb.nim deleted file mode 100644 index 776a07ac7..000000000 --- a/tests/rodfiles/deadb.nim +++ /dev/null @@ -1,7 +0,0 @@ - -import deadg - - -echo p1(123, 123) - - diff --git a/tests/rodfiles/deadg.nim b/tests/rodfiles/deadg.nim deleted file mode 100644 index 0aee59bb8..000000000 --- a/tests/rodfiles/deadg.nim +++ /dev/null @@ -1,7 +0,0 @@ -proc p1*(x, y: int): int = - result = x + y - -proc p2*(x, y: string): string = - result = x & y - - diff --git a/tests/rodfiles/gtkex1.nim b/tests/rodfiles/gtkex1.nim deleted file mode 100644 index 50779cb9e..000000000 --- a/tests/rodfiles/gtkex1.nim +++ /dev/null @@ -1,14 +0,0 @@ -import - cairo, glib2, gtk2 - -proc destroy(widget: PWidget, data: Pgpointer) {.cdecl.} = - main_quit() - -var - window: PWidget -nim_init() -window = window_new(WINDOW_TOPLEVEL) -discard signal_connect(window, "destroy", - SIGNAL_FUNC(gtkex1.destroy), nil) -show(window) -main() diff --git a/tests/rodfiles/gtkex2.nim b/tests/rodfiles/gtkex2.nim deleted file mode 100644 index 0949e4872..000000000 --- a/tests/rodfiles/gtkex2.nim +++ /dev/null @@ -1,22 +0,0 @@ - -import - glib2, gtk2 - -proc destroy(widget: PWidget, data: Pgpointer){.cdecl.} = - main_quit() - -var - window: PWidget - button: PWidget - -nim_init() -window = window_new(WINDOW_TOPLEVEL) -button = button_new("Click me") -set_border_width(PContainer(window), 5) -add(PContainer(window), button) -discard signal_connect(window, "destroy", - SIGNAL_FUNC(gtkex2.destroy), nil) -show(button) -show(window) -main() - diff --git a/tests/rodfiles/hallo.nim b/tests/rodfiles/hallo.nim deleted file mode 100644 index ac45be9fa..000000000 --- a/tests/rodfiles/hallo.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - output: "Hello World" -""" - -echo "Hello World" - diff --git a/tests/rodfiles/hallo2.nim b/tests/rodfiles/hallo2.nim deleted file mode 100644 index 40fe64cfd..000000000 --- a/tests/rodfiles/hallo2.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - output: "Hello World" -""" - -# Test incremental type information - -type - TNode = object {.pure.} - le, ri: ref TNode - data: string - -proc newNode(data: string): ref TNode = - new(result) - result.data = data - -echo newNode("Hello World").data - diff --git a/tests/rodfiles/int2bool.nim b/tests/rodfiles/int2bool.nim deleted file mode 100644 index bb0682844..000000000 --- a/tests/rodfiles/int2bool.nim +++ /dev/null @@ -1,7 +0,0 @@ - -{.overflowchecks: on.} - -converter uglyToBool*(x: int): bool = - result = x != 0 - - diff --git a/tests/rodfiles/nim.cfg b/tests/rodfiles/nim.cfg deleted file mode 100644 index 78fc8db64..000000000 --- a/tests/rodfiles/nim.cfg +++ /dev/null @@ -1,2 +0,0 @@ ---nimcache:"$projectPath/nimcache" ---symbolFiles:on diff --git a/tests/rodfiles/tgeneric1.nim b/tests/rodfiles/tgeneric1.nim deleted file mode 100644 index a3f7b870b..000000000 --- a/tests/rodfiles/tgeneric1.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: "abcd" -""" - -import tables - -var x = initTable[int, string]() - -x[2] = "ab" -x[5] = "cd" - -echo x[2], x[5] - diff --git a/tests/rodfiles/tgeneric2.nim b/tests/rodfiles/tgeneric2.nim deleted file mode 100644 index 552d60267..000000000 --- a/tests/rodfiles/tgeneric2.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: "abef" -""" - -import tables - -var x = initTable[int, string]() - -x[2] = "ab" -x[5] = "ef" - -echo x[2], x[5] - diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index e4461345e..3826cb1f9 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -1,10 +1,13 @@ discard """ nimout: "OK" - output: "OK" + output: ''' +OK +OK +''' """ import bitops -proc main() = +proc main1() = const U8 = 0b0011_0010'u8 const I8 = 0b0011_0010'i8 const U16 = 0b00100111_00101000'u16 @@ -261,7 +264,172 @@ block: # not ready for vm because exception is compile error doAssert false -main() +main1() static: # test everything on vm as well - main() + main1() + + + +proc main2() = + const U8 = 0b0011_0010'u8 + const I8 = 0b0011_0010'i8 + const U16 = 0b00100111_00101000'u16 + const I16 = 0b00100111_00101000'i16 + const U32 = 0b11010101_10011100_11011010_01010000'u32 + const I32 = 0b11010101_10011100_11011010_01010000'i32 + const U64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64 + const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64 + const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64 + const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64 + + doAssert( U64A.fastLog2 == 62) + doAssert( I64A.fastLog2 == 62) + doAssert( U64A.countLeadingZeroBits == 1) + doAssert( I64A.countLeadingZeroBits == 1) + doAssert( U64A.countTrailingZeroBits == 0) + doAssert( I64A.countTrailingZeroBits == 0) + doAssert( U64A.firstSetBit == 1) + doAssert( I64A.firstSetBit == 1) + doAssert( U64A.parityBits == 1) + doAssert( I64A.parityBits == 1) + doAssert( U64A.countSetBits == 29) + doAssert( I64A.countSetBits == 29) + doAssert( U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64) + doAssert( U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64) + + doAssert( U64B.firstSetBit == 36) + doAssert( I64B.firstSetBit == 36) + + doAssert( U32.fastLog2 == 31) + doAssert( I32.fastLog2 == 31) + doAssert( U32.countLeadingZeroBits == 0) + doAssert( I32.countLeadingZeroBits == 0) + doAssert( U32.countTrailingZeroBits == 4) + doAssert( I32.countTrailingZeroBits == 4) + doAssert( U32.firstSetBit == 5) + doAssert( I32.firstSetBit == 5) + doAssert( U32.parityBits == 0) + doAssert( I32.parityBits == 0) + doAssert( U32.countSetBits == 16) + doAssert( I32.countSetBits == 16) + doAssert( U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32) + doAssert( U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32) + + doAssert( U16.fastLog2 == 13) + doAssert( I16.fastLog2 == 13) + doAssert( U16.countLeadingZeroBits == 2) + doAssert( I16.countLeadingZeroBits == 2) + doAssert( U16.countTrailingZeroBits == 3) + doAssert( I16.countTrailingZeroBits == 3) + doAssert( U16.firstSetBit == 4) + doAssert( I16.firstSetBit == 4) + doAssert( U16.parityBits == 0) + doAssert( I16.parityBits == 0) + doAssert( U16.countSetBits == 6) + doAssert( I16.countSetBits == 6) + doAssert( U16.rotateLeftBits(12) == 0b10000010_01110010'u16) + doAssert( U16.rotateRightBits(12) == 0b01110010_10000010'u16) + + doAssert( U8.fastLog2 == 5) + doAssert( I8.fastLog2 == 5) + doAssert( U8.countLeadingZeroBits == 2) + doAssert( I8.countLeadingZeroBits == 2) + doAssert( U8.countTrailingZeroBits == 1) + doAssert( I8.countTrailingZeroBits == 1) + doAssert( U8.firstSetBit == 2) + doAssert( I8.firstSetBit == 2) + doAssert( U8.parityBits == 1) + doAssert( I8.parityBits == 1) + doAssert( U8.countSetBits == 3) + doAssert( I8.countSetBits == 3) + doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) + doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) + + static : + # test bitopts at compile time with vm + doAssert( U8.fastLog2 == 5) + doAssert( I8.fastLog2 == 5) + doAssert( U8.countLeadingZeroBits == 2) + doAssert( I8.countLeadingZeroBits == 2) + doAssert( U8.countTrailingZeroBits == 1) + doAssert( I8.countTrailingZeroBits == 1) + doAssert( U8.firstSetBit == 2) + doAssert( I8.firstSetBit == 2) + doAssert( U8.parityBits == 1) + doAssert( I8.parityBits == 1) + doAssert( U8.countSetBits == 3) + doAssert( I8.countSetBits == 3) + doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) + doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) + + + + template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) = + doAssert( ffunc(0'u8) == expected) + doAssert( ffunc(0'i8) == expected) + doAssert( ffunc(0'u16) == expected) + doAssert( ffunc(0'i16) == expected) + doAssert( ffunc(0'u32) == expected) + doAssert( ffunc(0'i32) == expected) + doAssert( ffunc(0'u64) == expected) + doAssert( ffunc(0'i64) == expected) + + template test_undefined(ffunc: untyped; expected: int) = + test_undefined_impl(ffunc, expected, false) + static: + test_undefined_impl(ffunc, expected, true) + + when defined(noUndefinedBitOpts): + # check for undefined behavior with zero. + test_undefined(countSetBits, 0) + test_undefined(parityBits, 0) + test_undefined(firstSetBit, 0) + test_undefined(countLeadingZeroBits, 0) + test_undefined(countTrailingZeroBits, 0) + test_undefined(fastLog2, -1) + + # check for undefined behavior with rotate by zero. + doAssert( U8.rotateLeftBits(0) == U8) + doAssert( U8.rotateRightBits(0) == U8) + doAssert( U16.rotateLeftBits(0) == U16) + doAssert( U16.rotateRightBits(0) == U16) + doAssert( U32.rotateLeftBits(0) == U32) + doAssert( U32.rotateRightBits(0) == U32) + doAssert( U64A.rotateLeftBits(0) == U64A) + doAssert( U64A.rotateRightBits(0) == U64A) + + # check for undefined behavior with rotate by integer width. + doAssert( U8.rotateLeftBits(8) == U8) + doAssert( U8.rotateRightBits(8) == U8) + doAssert( U16.rotateLeftBits(16) == U16) + doAssert( U16.rotateRightBits(16) == U16) + doAssert( U32.rotateLeftBits(32) == U32) + doAssert( U32.rotateRightBits(32) == U32) + doAssert( U64A.rotateLeftBits(64) == U64A) + doAssert( U64A.rotateRightBits(64) == U64A) + + static: # check for undefined behavior with rotate by zero. + doAssert( U8.rotateLeftBits(0) == U8) + doAssert( U8.rotateRightBits(0) == U8) + doAssert( U16.rotateLeftBits(0) == U16) + doAssert( U16.rotateRightBits(0) == U16) + doAssert( U32.rotateLeftBits(0) == U32) + doAssert( U32.rotateRightBits(0) == U32) + doAssert( U64A.rotateLeftBits(0) == U64A) + doAssert( U64A.rotateRightBits(0) == U64A) + + # check for undefined behavior with rotate by integer width. + doAssert( U8.rotateLeftBits(8) == U8) + doAssert( U8.rotateRightBits(8) == U8) + doAssert( U16.rotateLeftBits(16) == U16) + doAssert( U16.rotateRightBits(16) == U16) + doAssert( U32.rotateLeftBits(32) == U32) + doAssert( U32.rotateRightBits(32) == U32) + doAssert( U64A.rotateLeftBits(64) == U64A) + doAssert( U64A.rotateRightBits(64) == U64A) + + echo "OK" + +main2() + diff --git a/tests/stdlib/tbitops2.nim b/tests/stdlib/tbitops2.nim deleted file mode 100644 index e8c7318be..000000000 --- a/tests/stdlib/tbitops2.nim +++ /dev/null @@ -1,167 +0,0 @@ -discard """ - output: "OK" -""" -import bitops - - -proc main() = - const U8 = 0b0011_0010'u8 - const I8 = 0b0011_0010'i8 - const U16 = 0b00100111_00101000'u16 - const I16 = 0b00100111_00101000'i16 - const U32 = 0b11010101_10011100_11011010_01010000'u32 - const I32 = 0b11010101_10011100_11011010_01010000'i32 - const U64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64 - const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64 - const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64 - const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64 - - doAssert( U64A.fastLog2 == 62) - doAssert( I64A.fastLog2 == 62) - doAssert( U64A.countLeadingZeroBits == 1) - doAssert( I64A.countLeadingZeroBits == 1) - doAssert( U64A.countTrailingZeroBits == 0) - doAssert( I64A.countTrailingZeroBits == 0) - doAssert( U64A.firstSetBit == 1) - doAssert( I64A.firstSetBit == 1) - doAssert( U64A.parityBits == 1) - doAssert( I64A.parityBits == 1) - doAssert( U64A.countSetBits == 29) - doAssert( I64A.countSetBits == 29) - doAssert( U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64) - doAssert( U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64) - - doAssert( U64B.firstSetBit == 36) - doAssert( I64B.firstSetBit == 36) - - doAssert( U32.fastLog2 == 31) - doAssert( I32.fastLog2 == 31) - doAssert( U32.countLeadingZeroBits == 0) - doAssert( I32.countLeadingZeroBits == 0) - doAssert( U32.countTrailingZeroBits == 4) - doAssert( I32.countTrailingZeroBits == 4) - doAssert( U32.firstSetBit == 5) - doAssert( I32.firstSetBit == 5) - doAssert( U32.parityBits == 0) - doAssert( I32.parityBits == 0) - doAssert( U32.countSetBits == 16) - doAssert( I32.countSetBits == 16) - doAssert( U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32) - doAssert( U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32) - - doAssert( U16.fastLog2 == 13) - doAssert( I16.fastLog2 == 13) - doAssert( U16.countLeadingZeroBits == 2) - doAssert( I16.countLeadingZeroBits == 2) - doAssert( U16.countTrailingZeroBits == 3) - doAssert( I16.countTrailingZeroBits == 3) - doAssert( U16.firstSetBit == 4) - doAssert( I16.firstSetBit == 4) - doAssert( U16.parityBits == 0) - doAssert( I16.parityBits == 0) - doAssert( U16.countSetBits == 6) - doAssert( I16.countSetBits == 6) - doAssert( U16.rotateLeftBits(12) == 0b10000010_01110010'u16) - doAssert( U16.rotateRightBits(12) == 0b01110010_10000010'u16) - - doAssert( U8.fastLog2 == 5) - doAssert( I8.fastLog2 == 5) - doAssert( U8.countLeadingZeroBits == 2) - doAssert( I8.countLeadingZeroBits == 2) - doAssert( U8.countTrailingZeroBits == 1) - doAssert( I8.countTrailingZeroBits == 1) - doAssert( U8.firstSetBit == 2) - doAssert( I8.firstSetBit == 2) - doAssert( U8.parityBits == 1) - doAssert( I8.parityBits == 1) - doAssert( U8.countSetBits == 3) - doAssert( I8.countSetBits == 3) - doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) - doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) - - static : - # test bitopts at compile time with vm - doAssert( U8.fastLog2 == 5) - doAssert( I8.fastLog2 == 5) - doAssert( U8.countLeadingZeroBits == 2) - doAssert( I8.countLeadingZeroBits == 2) - doAssert( U8.countTrailingZeroBits == 1) - doAssert( I8.countTrailingZeroBits == 1) - doAssert( U8.firstSetBit == 2) - doAssert( I8.firstSetBit == 2) - doAssert( U8.parityBits == 1) - doAssert( I8.parityBits == 1) - doAssert( U8.countSetBits == 3) - doAssert( I8.countSetBits == 3) - doAssert( U8.rotateLeftBits(3) == 0b10010001'u8) - doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8) - - - - template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) = - doAssert( ffunc(0'u8) == expected) - doAssert( ffunc(0'i8) == expected) - doAssert( ffunc(0'u16) == expected) - doAssert( ffunc(0'i16) == expected) - doAssert( ffunc(0'u32) == expected) - doAssert( ffunc(0'i32) == expected) - doAssert( ffunc(0'u64) == expected) - doAssert( ffunc(0'i64) == expected) - - template test_undefined(ffunc: untyped; expected: int) = - test_undefined_impl(ffunc, expected, false) - static: - test_undefined_impl(ffunc, expected, true) - - when defined(noUndefinedBitOpts): - # check for undefined behavior with zero. - test_undefined(countSetBits, 0) - test_undefined(parityBits, 0) - test_undefined(firstSetBit, 0) - test_undefined(countLeadingZeroBits, 0) - test_undefined(countTrailingZeroBits, 0) - test_undefined(fastLog2, -1) - - # check for undefined behavior with rotate by zero. - doAssert( U8.rotateLeftBits(0) == U8) - doAssert( U8.rotateRightBits(0) == U8) - doAssert( U16.rotateLeftBits(0) == U16) - doAssert( U16.rotateRightBits(0) == U16) - doAssert( U32.rotateLeftBits(0) == U32) - doAssert( U32.rotateRightBits(0) == U32) - doAssert( U64A.rotateLeftBits(0) == U64A) - doAssert( U64A.rotateRightBits(0) == U64A) - - # check for undefined behavior with rotate by integer width. - doAssert( U8.rotateLeftBits(8) == U8) - doAssert( U8.rotateRightBits(8) == U8) - doAssert( U16.rotateLeftBits(16) == U16) - doAssert( U16.rotateRightBits(16) == U16) - doAssert( U32.rotateLeftBits(32) == U32) - doAssert( U32.rotateRightBits(32) == U32) - doAssert( U64A.rotateLeftBits(64) == U64A) - doAssert( U64A.rotateRightBits(64) == U64A) - - static: # check for undefined behavior with rotate by zero. - doAssert( U8.rotateLeftBits(0) == U8) - doAssert( U8.rotateRightBits(0) == U8) - doAssert( U16.rotateLeftBits(0) == U16) - doAssert( U16.rotateRightBits(0) == U16) - doAssert( U32.rotateLeftBits(0) == U32) - doAssert( U32.rotateRightBits(0) == U32) - doAssert( U64A.rotateLeftBits(0) == U64A) - doAssert( U64A.rotateRightBits(0) == U64A) - - # check for undefined behavior with rotate by integer width. - doAssert( U8.rotateLeftBits(8) == U8) - doAssert( U8.rotateRightBits(8) == U8) - doAssert( U16.rotateLeftBits(16) == U16) - doAssert( U16.rotateRightBits(16) == U16) - doAssert( U32.rotateLeftBits(32) == U32) - doAssert( U32.rotateRightBits(32) == U32) - doAssert( U64A.rotateLeftBits(64) == U64A) - doAssert( U64A.rotateRightBits(64) == U64A) - - echo "OK" - -main() diff --git a/tests/stdlib/tbitops2.nim.cfg b/tests/stdlib/tbitops2.nim.cfg deleted file mode 100644 index e1cb77e82..000000000 --- a/tests/stdlib/tbitops2.nim.cfg +++ /dev/null @@ -1,2 +0,0 @@ --d:noIntrinsicsBitOpts --d:noUndefinedBitOps diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim index a32ecbc23..6da185420 100644 --- a/tests/stdlib/tfrexp1.nim +++ b/tests/stdlib/tfrexp1.nim @@ -41,6 +41,6 @@ when manualTest: frexp_test(-1000.0, 1000.0, 0.0125) else: - frexp_test(-1000000.0, 1000000.0, 0.125) + frexp_test(-200000.0, 200000.0, 0.125) echo "ok" diff --git a/tests/stdlib/trepr2.nim b/tests/stdlib/trepr2.nim deleted file mode 100644 index 7b9f9db28..000000000 --- a/tests/stdlib/trepr2.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ -outputsub: "" -""" - -# output not testable because repr prints pointer addresses -# test the new "repr" built-in proc - -type - TEnum = enum - en1, en2, en3, en4, en5, en6 - - TPoint {.final.} = object - x, y, z: int - s: array[0..1, string] - e: TEnum - -var - p: TPoint - q: ref TPoint - s: seq[ref TPoint] - -p.x = 0 -p.y = 13 -p.z = 45 -p.s[0] = "abc" -p.s[1] = "xyz" -p.e = en6 - -new(q) -q[] = p - -s = @[q, q, q, q] - -writeLine(stdout, repr(p)) -writeLine(stdout, repr(q)) -writeLine(stdout, repr(s)) -writeLine(stdout, repr(en4)) diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 559824d85..354bdf60f 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -1,11 +1,16 @@ discard """ -input: "Arne" -output: ''' + input: "Arne" + output: ''' Hello! What is your name? Nice name: Arne fs is: nil threw exception +''' + nimout: ''' +I +AM +GROOT ''' disabled: "windows" """ @@ -38,3 +43,9 @@ block tstreams3: var fs = openFileStream("shouldneverexist.txt") except IoError: echo "threw exception" + + static: + var s = newStringStream("I\nAM\nGROOT") + for line in s.lines: + echo line + s.close diff --git a/tests/stdlib/tstreams2.nim b/tests/stdlib/tstreams2.nim deleted file mode 100644 index 70f0bac32..000000000 --- a/tests/stdlib/tstreams2.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - output: '''fs is: nil''' -""" -import streams -var - fs = newFileStream("amissingfile.txt") - line = "" -echo "fs is: ",repr(fs) -if not isNil(fs): - while fs.readLine(line): - echo line - fs.close() diff --git a/tests/stdlib/tstreams3.nim b/tests/stdlib/tstreams3.nim deleted file mode 100644 index 89f45f275..000000000 --- a/tests/stdlib/tstreams3.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - output: "threw exception" - nimout: ''' -I -AM -GROOT -''' -""" -import streams - -try: - var fs = openFileStream("shouldneverexist.txt") -except IoError: - echo "threw exception" - -static: - var s = newStringStream("I\nAM\nGROOT") - for line in s.lines: - echo line - s.close diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 0602aaa94..60e2ffdbe 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -309,7 +309,7 @@ suite "ttimes": check dt.nanosecond == convert(Milliseconds, Nanoseconds, 1) check d(seconds = 1, milliseconds = 500) * 2 == d(seconds = 3) check d(seconds = 3) div 2 == d(seconds = 1, milliseconds = 500) - check d(milliseconds = 1001).seconds == 1 + check d(milliseconds = 1001).inSeconds == 1 check d(seconds = 1, milliseconds = 500) - d(milliseconds = 1250) == d(milliseconds = 250) check d(seconds = 1, milliseconds = 1) < d(seconds = 1, milliseconds = 2) @@ -504,12 +504,6 @@ suite "ttimes": check $parse("02 Fir 2019", "dd MMM yyyy", utc(), loc) == "2019-01-02T00:00:00Z" check $parse("Fourthy 6, 2017", "MMMM d, yyyy", utc(), loc) == "2017-04-06T00:00:00Z" - test "countLeapYears": - # 1920, 2004 and 2020 are leap years, and should be counted starting at the following year - check countLeapYears(1920) + 1 == countLeapYears(1921) - check countLeapYears(2004) + 1 == countLeapYears(2005) - check countLeapYears(2020) + 1 == countLeapYears(2021) - test "timezoneConversion": var l = now() let u = l.utc diff --git a/tests/system/trealloc.nim b/tests/system/trealloc.nim index 7180b8eda..e8d772dbd 100644 --- a/tests/system/trealloc.nim +++ b/tests/system/trealloc.nim @@ -11,12 +11,12 @@ const BUFFER_SIZE = 5000 var buffer = cast[ptr uint16](alloc(BUFFER_SIZE)) var total_size: int64 = 0 -for i in 0 .. 4000: - let size = BUFFER_SIZE * i - #echo "requesting ", size - total_size += size.int64 - buffer = cast[ptr uint16](realloc(buffer, size)) - #echo totalSize, " total: ", getTotalMem(), " occupied: ", getOccupiedMem(), " free: ", getFreeMem() +for i in 0 .. 1000: + let size = BUFFER_SIZE * i + #echo "requesting ", size + total_size += size.int64 + buffer = cast[ptr uint16](realloc(buffer, size)) + #echo totalSize, " total: ", getTotalMem(), " occupied: ", getOccupiedMem(), " free: ", getFreeMem() dealloc(buffer) echo "success" diff --git a/tests/threads/t8535.nim b/tests/threads/t8535.nim index dfc95547d..1af11f9ad 100644 --- a/tests/threads/t8535.nim +++ b/tests/threads/t8535.nim @@ -22,7 +22,7 @@ import asyncdispatch import threadpool proc f1() = - waitFor sleepAsync(100) + waitFor sleepAsync(20) echo "hello" spawn f1() diff --git a/tests/threads/tmanyjoin.nim b/tests/threads/tmanyjoin.nim index 2c1cda494..aca284965 100644 --- a/tests/threads/tmanyjoin.nim +++ b/tests/threads/tmanyjoin.nim @@ -12,7 +12,7 @@ type const ThreadsCount = 129 - SleepTime = 1000 + SleepTime = 250 proc worker(p: Marker) {.thread.} = acquire(p.lock) diff --git a/tests/threads/treusetvar.nim b/tests/threads/treusetvar.nim index 672da6bdd..2b0017595 100644 --- a/tests/threads/treusetvar.nim +++ b/tests/threads/treusetvar.nim @@ -1,8 +1,8 @@ discard """ - outputsub: "129" + outputsub: "65" """ -import os, locks +import locks type MarkerObj = object @@ -11,7 +11,7 @@ type Marker = ptr MarkerObj const - ThreadsCount = 129 + ThreadsCount = 65 proc worker(p: Marker) {.thread.} = acquire(p.lock) diff --git a/tests/threads/tthreadanalysis2.nim b/tests/threads/tthreadanalysis2.nim deleted file mode 100644 index 067e186a8..000000000 --- a/tests/threads/tthreadanalysis2.nim +++ /dev/null @@ -1,51 +0,0 @@ -discard """ - errormsg: "'threadFunc' is not GC-safe" - file: "tthreadanalysis2.nim" - line: 37 - cmd: "nim $target --hints:on --threads:on $options $file" -""" - -import os - -var - thr: array[0..5, Thread[tuple[a, b: int]]] - -proc doNothing() = discard - -type - PNode = ref TNode - TNode = object {.pure.} - le, ri: PNode - data: string - -var - root: PNode - -proc buildTree(depth: int): PNode = - if depth == 3: return nil - new(result) - result.le = buildTree(depth-1) - result.ri = buildTree(depth-1) - result.data = $depth - -proc echoLeTree(n: PNode) = - var it = n - while it != nil: - echo it.data - it = it.le - -proc threadFunc(interval: tuple[a, b: int]) {.thread.} = - doNothing() - for i in interval.a..interval.b: - var r = buildTree(i) - echoLeTree(r) # for local data - root = buildTree(2) # BAD! - #echoLeTree(root) # and the same for foreign data :-) - -proc main = - root = buildTree(5) - for i in 0..high(thr): - createThread(thr[i], threadFunc, (i*100, i*100+50)) - joinThreads(thr) - -main() diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim index 87dec6e79..cadf6c550 100644 --- a/tests/threads/ttryrecv.nim +++ b/tests/threads/ttryrecv.nim @@ -11,7 +11,7 @@ type PComm = ptr Channel[int] proc doAction(outC: PComm) {.thread.} = for i in 0 ..< 5: - sleep(rand(100)) + sleep(rand(50)) send(outC[], i) var From 19cab9fa51fdb9a244ca35e978e9daa8cc81a785 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 30 Mar 2020 04:45:32 -0700 Subject: [PATCH 0224/4254] stacktraces can now show custom runtime msgs per frame (#13351) * stacktraces can now show custom runtime msgs * improve tests/stdlib/tstackframes.nim * fix test for --gc:arc * test --stacktraceMsgs:on and --stacktraceMsgs:off * --stacktracemsgs:off by default --- changelog.md | 3 +++ compiler/commands.nim | 2 ++ compiler/condsyms.nim | 1 + compiler/options.nim | 6 ++++-- compiler/semexprs.nim | 5 +++++ doc/advopt.txt | 1 + lib/nimbase.h | 1 + lib/std/stackframes.nim | 30 +++++++++++++++++++++++++++ lib/system.nim | 36 ++++++++++++++++++--------------- lib/system/exceptions.nim | 9 +++++++++ lib/system/excpt.nim | 24 ++++++++++++++++++++-- tests/assert/tassert_c.nim | 2 +- tests/stdlib/mstackframes.nim | 38 +++++++++++++++++++++++++++++++++++ tests/stdlib/tstackframes.nim | 34 +++++++++++++++++++++++++++++++ 14 files changed, 171 insertions(+), 21 deletions(-) create mode 100644 lib/std/stackframes.nim create mode 100644 tests/stdlib/mstackframes.nim create mode 100644 tests/stdlib/tstackframes.nim diff --git a/changelog.md b/changelog.md index a452965b2..42f469567 100644 --- a/changelog.md +++ b/changelog.md @@ -150,6 +150,9 @@ echo f - `net.newContext` now performs SSL Certificate checking on Linux and OSX. Define `nimDisableCertificateValidation` to disable it globally. - new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by `import pragmas` +- new module `std/stackframes`, in particular `setFrameMsg` which enables + custom runtime annotation of stackframes, see #13351 for examples. Turn on/off via + `--stackTraceMsgs:on/off` ## Language additions diff --git a/compiler/commands.nim b/compiler/commands.nim index 024e6b417..4caccd165 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -281,6 +281,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool of "hints": result = contains(conf.options, optHints) of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis) of "stacktrace": result = contains(conf.options, optStackTrace) + of "stacktracemsgs": result = contains(conf.options, optStackTraceMsgs) of "linetrace": result = contains(conf.options, optLineTrace) of "debugger": result = contains(conf.globalOptions, optCDebug) of "profiler": result = contains(conf.options, optProfiler) @@ -531,6 +532,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info) + of "stacktracemsgs": processOnOffSwitch(conf, {optStackTraceMsgs}, arg, pass, info) of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info) of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info) of "debugger": diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index da40dd2b7..b6997e6fc 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -114,3 +114,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasSinkInference") defineSymbol("nimNewIntegerOps") + defineSymbol("nimHasStacktraceMsgs") diff --git a/compiler/options.nim b/compiler/options.nim index b38b5a6bc..8b2523478 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -28,7 +28,9 @@ type # please make sure we have under 32 options optOverflowCheck, optNilCheck, optRefCheck, optNaNCheck, optInfCheck, optStaticBoundsCheck, optStyleCheck, optAssert, optLineDir, optWarns, optHints, - optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support + optOptimizeSpeed, optOptimizeSize, + optStackTrace, # stack tracing support + optStackTraceMsgs, # enable custom runtime msgs via `setFrameMsg` optLineTrace, # line tracing support (includes stack tracing) optByRef, # use pass by ref for objects # (for interfacing with C) @@ -325,7 +327,7 @@ const DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, - optHints, optStackTrace, optLineTrace, + optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` optTrMacros, optNilCheck, optStyleCheck, optSinkInference} DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, optListFullPaths} diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c2f117efa..d6659f76b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,6 +10,9 @@ # this module does the semantic checking for expressions # included from sem.nim +when defined(nimCompilerStackraceHints): + import std/stackframes + const errExprXHasNoType = "expression '$1' has no type (or is ambiguous)" errXExpectsTypeOrValue = "'$1' expects a type or value" @@ -2557,6 +2560,8 @@ proc shouldBeBracketExpr(n: PNode): bool = return true proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = + when defined(nimCompilerStackraceHints): + setFrameMsg c.config$n.info & " " & $n.kind result = n if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if nfSem in n.flags: return diff --git a/doc/advopt.txt b/doc/advopt.txt index 1ebec0f49..157208a05 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -92,6 +92,7 @@ Advanced options: turn support for hot code reloading on|off --excessiveStackTrace:on|off stack traces use full file paths + --stackTraceMsgs:on|off enable user defined stack frame msgs via `setFrameMsg` --oldNewlines:on|off turn on|off the old behaviour of "\n" --laxStrings:on|off when turned on, accessing the zero terminator in strings is allowed; only for backwards compatibility diff --git a/lib/nimbase.h b/lib/nimbase.h index eb750864a..5b0dcc2c8 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -489,6 +489,7 @@ struct TFrame_ { NCSTRING filename; NI16 len; NI16 calldepth; + NI frameMsgLen; }; #define NIM_POSIX_INIT __attribute__((constructor)) diff --git a/lib/std/stackframes.nim b/lib/std/stackframes.nim new file mode 100644 index 000000000..dbd866536 --- /dev/null +++ b/lib/std/stackframes.nim @@ -0,0 +1,30 @@ +const NimStackTrace = compileOption("stacktrace") +const NimStackTraceMsgs = compileOption("stacktraceMsgs") + +template procName*(): string = + ## returns current C/C++ function name + when defined(c) or defined(cpp): + var name {.inject.}: cstring + {.emit: "`name` = __func__;".} + $name + +template getPFrame*(): PFrame = + ## avoids a function call (unlike `getFrame()`) + block: + when NimStackTrace: + var framePtr {.inject.}: PFrame + {.emit: "`framePtr` = &FR_;".} + framePtr + +template setFrameMsg*(msg: string, prefix = " ") = + ## attach a msg to current `PFrame`. This can be called multiple times + ## in a given PFrame. Noop unless passing --stacktraceMsgs and --stacktrace + when NimStackTrace and NimStackTraceMsgs: + block: + var fr {.inject.}: PFrame + {.emit: "`fr` = &FR_;".} + # consider setting a custom upper limit on size (analog to stack overflow) + frameMsgBuf.setLen fr.frameMsgLen + frameMsgBuf.add prefix + frameMsgBuf.add msg + fr.frameMsgLen += prefix.len + msg.len diff --git a/lib/system.nim b/lib/system.nim index cd941b19f..469821fab 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -54,6 +54,23 @@ type include "system/basic_types" + +proc compileOption*(option: string): bool {. + magic: "CompileOption", noSideEffect.} + ## Can be used to determine an `on|off` compile-time option. Example: + ## + ## .. code-block:: Nim + ## when compileOption("floatchecks"): + ## echo "compiled with floating point NaN and Inf checks" + +proc compileOption*(option, arg: string): bool {. + magic: "CompileOptionArg", noSideEffect.} + ## Can be used to determine an enum compile-time option. Example: + ## + ## .. code-block:: Nim + ## when compileOption("opt", "size") and compileOption("gc", "boehm"): + ## echo "compiled with optimization for size and uses Boehm's GC" + {.push warning[GcMem]: off, warning[Uninit]: off.} {.push hints: off.} @@ -1040,22 +1057,6 @@ const # emit this flag # for string literals, it allows for some optimizations. -proc compileOption*(option: string): bool {. - magic: "CompileOption", noSideEffect.} - ## Can be used to determine an `on|off` compile-time option. Example: - ## - ## .. code-block:: Nim - ## when compileOption("floatchecks"): - ## echo "compiled with floating point NaN and Inf checks" - -proc compileOption*(option, arg: string): bool {. - magic: "CompileOptionArg", noSideEffect.} - ## Can be used to determine an enum compile-time option. Example: - ## - ## .. code-block:: Nim - ## when compileOption("opt", "size") and compileOption("gc", "boehm"): - ## echo "compiled with optimization for size and uses Boehm's GC" - const hasThreadSupport = compileOption("threads") and not defined(nimscript) hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own @@ -1891,6 +1892,7 @@ var type PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; ## part of the debugger API. + # keep in sync with nimbase.h `struct TFrame_` TFrame* {.importc, nodecl, final.} = object ## The frame itself. prev*: PFrame ## Previous frame; used for chaining the call stack. procname*: cstring ## Name of the proc that is currently executing. @@ -1898,6 +1900,8 @@ type filename*: cstring ## Filename of the proc that is currently executing. len*: int16 ## Length of the inspectable slots. calldepth*: int16 ## Used for max call depth checking. + when NimStackTraceMsgs: + frameMsgLen*: int ## end position in frameMsgBuf for this frame. when defined(js): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index 3979fb66e..516de8252 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -1,3 +1,7 @@ +const NimStackTraceMsgs = + when defined(nimHasStacktraceMsgs): compileOption("stacktraceMsgs") + else: false + type RootEffect* {.compilerproc.} = object of RootObj ## \ ## Base effect class. @@ -16,6 +20,11 @@ type procname*: cstring ## Name of the proc that is currently executing. line*: int ## Line number of the proc that is currently executing. filename*: cstring ## Filename of the proc that is currently executing. + when NimStackTraceMsgs: + frameMsg*: string ## When a stacktrace is generated in a given frame and + ## rendered at a later time, we should ensure the stacktrace + ## data isn't invalidated; any pointer into PFrame is + ## subject to being invalidated so shouldn't be stored. Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ ## Base exception class. diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 8ac47d26b..76d188ea6 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -53,6 +53,8 @@ type len: int prev: ptr GcFrameHeader +when NimStackTraceMsgs: + var frameMsgBuf* {.threadvar.}: string var framePtr {.threadvar.}: PFrame excHandler {.threadvar.}: PSafePoint @@ -224,10 +226,17 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) = s[last] = StackTraceEntry(procname: it.procname, line: it.line, filename: it.filename) + when NimStackTraceMsgs: + let first = if it.prev == nil: 0 else: it.prev.frameMsgLen + if it.frameMsgLen > first: + s[last].frameMsg.setLen(it.frameMsgLen - first) + # somehow string slicing not available here + for i in first .. it.frameMsgLen-1: + s[last].frameMsg[i-first] = frameMsgBuf[i] it = it.prev dec last -template addFrameEntry(s, f: untyped) = +template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) = var oldLen = s.len add(s, f.filename) if f.line > 0: @@ -236,6 +245,12 @@ template addFrameEntry(s, f: untyped) = add(s, ')') for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ') add(s, f.procname) + when NimStackTraceMsgs: + when type(f) is StackTraceEntry: + add(s, f.frameMsg) + else: + var first = if f.prev == nil: 0 else: f.prev.frameMsgLen + for i in first.. 0: + main1(n-1) + +proc main2(n: int) = + count.inc + setFrameMsg $("main2", n, count) + proc bar() = + setFrameMsg $("bar ",) + if n < 3: raise newException(CatchableError, "on purpose") + bar() + main2(n-1) + +proc main() = + var z = 0 + setFrameMsg "\n z: " & $z, prefix = "" + # multiple calls inside a frame are possible + z.inc + setFrameMsg "\n z: " & $z, prefix = "" + try: + main2(5) + except CatchableError: + main1(10) # goes deep and then unwinds; sanity check to ensure `setFrameMsg` from inside + # `main1` won't invalidate the stacktrace; if StackTraceEntry.frameMsg + # were a reference instead of a copy, this would fail. + let e = getCurrentException() + let trace = e.getStackTrace + echo trace + +main() diff --git a/tests/stdlib/tstackframes.nim b/tests/stdlib/tstackframes.nim new file mode 100644 index 000000000..be66eb836 --- /dev/null +++ b/tests/stdlib/tstackframes.nim @@ -0,0 +1,34 @@ +import std/[strformat,os,osproc] +import "$nim/compiler/unittest_light" # works even if moved by megatest + +proc main(opt: string, expected: string) = + const nim = getCurrentCompilerExe() + const file = currentSourcePath().parentDir / "mstackframes.nim" + let cmd = fmt"{nim} c -r --excessiveStackTrace:off --stacktraceMsgs:{opt} --hints:off {file}" + let (output, exitCode) = execCmdEx(cmd) + assertEquals output, expected + doAssert exitCode == 0 + +main("on"): """ +mstackframes.nim(38) mstackframes +mstackframes.nim(29) main + z: 0 + z: 1 +mstackframes.nim(20) main2 ("main2", 5, 1) +mstackframes.nim(20) main2 ("main2", 4, 2) +mstackframes.nim(20) main2 ("main2", 3, 3) +mstackframes.nim(19) main2 ("main2", 2, 4) +mstackframes.nim(18) bar ("bar ",) + +""" + +main("off"): """ +mstackframes.nim(38) mstackframes +mstackframes.nim(29) main +mstackframes.nim(20) main2 +mstackframes.nim(20) main2 +mstackframes.nim(20) main2 +mstackframes.nim(19) main2 +mstackframes.nim(18) bar + +""" From 119b0ce66fcadadf49e0a6ecec215cf3733723dd Mon Sep 17 00:00:00 2001 From: Huy Doan <106477+ba0f3@users.noreply.github.com> Date: Tue, 31 Mar 2020 16:25:12 +0700 Subject: [PATCH 0225/4254] Fix telebot test failed, closes ba0f3/telebot.nim#49 [ref #13812] (#13814) I was update telebot to version 1.0.0, update folder structure follow `nimble` guideline --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 363171082..f4976de26 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -82,7 +82,7 @@ pkg "sdl2_nim", false, "nim c -r sdl2/sdl.nim" pkg "snip", false, "nimble test", "https://github.com/genotrance/snip" pkg "stint", false, "nim c -o:stintt -r stint.nim" pkg "strunicode", true, "nim c -r src/strunicode.nim" -pkg "telebot", true, "nim c -o:tbot --oldgensym:on -r telebot.nim" +pkg "telebot", true, "nim c -o:tbot -r src/telebot.nim" pkg "tempdir" pkg "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" pkg "tiny_sqlite" From 1e4093d949ab015cd1e3e62cf0f47d83ef0bca38 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 31 Mar 2020 06:43:35 -0700 Subject: [PATCH 0226/4254] refs #13797 (#13812) --- lib/pure/times.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 45ed6dd67..b9410e14c 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1073,7 +1073,7 @@ proc zonedTimeFromAdjTime*(zone: Timezone, adjTime: Time): ZonedTime = proc `$`*(zone: Timezone): string = ## Returns the name of the timezone. - zone.name + if zone != nil: result = zone.name proc `==`*(zone1, zone2: Timezone): bool = ## Two ``Timezone``'s are considered equal if their name is equal. From 42d2c3088e1f869148fd6eb1fdce2b33f859dc2d Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 31 Mar 2020 10:47:57 -0300 Subject: [PATCH 0227/4254] Add Documentation (#13811) * Add more Docs and runnableExamples --- lib/impure/rdstdin.nim | 10 +++++++-- lib/posix/posix_utils.nim | 1 - lib/pure/browsers.nim | 3 +++ lib/pure/collections/critbits.nim | 26 ++++++++++++++++++++++ lib/pure/concurrency/cpuinfo.nim | 3 +++ lib/pure/mersenne.nim | 8 +++++++ lib/pure/mimetypes.nim | 32 +++++++++++++------------- lib/pure/punycode.nim | 37 +++++++++++++++++++++++++++++++ lib/pure/stats.nim | 16 +++++++++++++ lib/std/editdistance.nim | 4 +++- lib/std/sums.nim | 8 +++++++ lib/system/assertions.nim | 6 +++++ 12 files changed, 135 insertions(+), 19 deletions(-) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 4c36afe6e..670b5ab72 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -12,7 +12,14 @@ ## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine`` ## is used. This suffices because Windows' console already provides the ## wanted functionality. - +## +## **Examples:** +## +## .. code-block:: nim +## echo readLineFromStdin("Is Nim awesome? (Y/n):") +## var userResponse: string +## doAssert readLineFromStdin("How are you?:", line = userResponse) +## echo userResponse {.deadCodeElim: on.} # dce option deprecated when defined(Windows): @@ -66,4 +73,3 @@ else: historyAdd(buffer) linenoise.free(buffer) result = true - diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 20a71971a..5600a5db5 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -98,4 +98,3 @@ proc mkdtemp*(prefix: string): string = if mkdtemp(tmpl) == nil: raise newException(OSError, $strerror(errno)) return $tmpl - diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index ee302f950..81a231aa2 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -33,6 +33,9 @@ proc openDefaultBrowser*(url: string) = ## used to determine the default browser to use. ## ## This proc doesn't raise an exception on error, beware. + ## + ## .. code-block:: nim + ## block: openDefaultBrowser("https://nim-lang.org") when defined(windows): var o = newWideCString(osOpenCmd) var u = newWideCString(url) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index a28bb447c..250042e7a 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -324,6 +324,32 @@ proc `$`*[T](c: CritBitTree[T]): string = result.addQuoted(val) result.add("}") + +runnableExamples: + static: + block: + var critbitAsSet: CritBitTree[void] + doAssert critbitAsSet.len == 0 + incl critbitAsSet, "kitten" + doAssert critbitAsSet.len == 1 + incl critbitAsSet, "puppy" + doAssert critbitAsSet.len == 2 + incl critbitAsSet, "kitten" + doAssert critbitAsSet.len == 2 + incl critbitAsSet, "" + doAssert critbitAsSet.len == 3 + block: + var critbitAsDict: CritBitTree[int] + critbitAsDict["key"] = 42 + doAssert critbitAsDict["key"] == 42 + critbitAsDict["key"] = 0 + doAssert critbitAsDict["key"] == 0 + critbitAsDict["key"] = -int.high + doAssert critbitAsDict["key"] == -int.high + critbitAsDict["key"] = int.high + doAssert critbitAsDict["key"] == int.high + + when isMainModule: import sequtils diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 515d7e2da..51f80b103 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -49,6 +49,9 @@ when defined(haiku): proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = ## returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. + ## + ## .. code-block:: nim + ## block: doAssert countProcessors() >= 0 when defined(windows): type SYSTEM_INFO {.final, pure.} = object diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index a2b8914d9..812893508 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -39,6 +39,14 @@ proc getNum*(m: var MersenneTwister): uint32 = result = result xor ((result shl 15'u32) and 0xefc60000'u32) result = result xor (result shr 18'u32) + +runnableExamples: + static: + block: + var rando: MersenneTwister = newMersenneTwister(uint32.high) ## Must be "var". + doAssert rando.getNum() != rando.getNum() ## Pseudo random number. Works at compile-time. + + # Test when not defined(testing) and isMainModule: var mt = newMersenneTwister(2525) diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index f3f6e9324..3bbd0d243 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -1917,18 +1917,20 @@ func register*(mimedb: var MimeDB, ext: string, mimetype: string) = mimedb.mimes[ext.toLowerAscii()] = mimetype.toLowerAscii() runnableExamples: - var m = newMimetypes() - assert m.getMimetype("mp4") == "video/mp4" - assert m.getExt("text/html") == "html" - ## Values can be uppercase too. - assert m.getMimetype("MP4") == "video/mp4" - assert m.getExt("TEXT/HTML") == "html" - ## If values are invalid then ``default`` is returned. - assert m.getMimetype("INVALID") == "text/plain" - assert m.getExt("INVALID/NONEXISTENT") == "txt" - assert m.getMimetype("") == "text/plain" - assert m.getExt("") == "txt" - ## Register new Mimetypes. - m.register(ext = "fakext", mimetype = "text/fakelang") - assert m.getMimetype("fakext") == "text/fakelang" - assert m.getMimetype("FaKeXT") == "text/fakelang" + static: + block: + var m = newMimetypes() + doAssert m.getMimetype("mp4") == "video/mp4" + doAssert m.getExt("text/html") == "html" + ## Values can be uppercase too. + doAssert m.getMimetype("MP4") == "video/mp4" + doAssert m.getExt("TEXT/HTML") == "html" + ## If values are invalid then ``default`` is returned. + doAssert m.getMimetype("INVALID") == "text/plain" + doAssert m.getExt("INVALID/NONEXISTENT") == "txt" + doAssert m.getMimetype("") == "text/plain" + doAssert m.getExt("") == "txt" + ## Register new Mimetypes. + m.register(ext = "fakext", mimetype = "text/fakelang") + doAssert m.getMimetype("fakext") == "text/fakelang" + doAssert m.getMimetype("FaKeXT") == "text/fakelang" diff --git a/lib/pure/punycode.nim b/lib/pure/punycode.nim index ce80a37fa..fc80fabfd 100644 --- a/lib/pure/punycode.nim +++ b/lib/pure/punycode.nim @@ -171,6 +171,43 @@ proc decode*(encoded: string): string {.raises: [PunyError].} = insert(result, $Rune(n), i) inc i + +runnableExamples: + static: + block: + doAssert encode("") == "" + doAssert encode("a") == "a-" + doAssert encode("A") == "A-" + doAssert encode("3") == "3-" + doAssert encode("-") == "--" + doAssert encode("--") == "---" + doAssert encode("abc") == "abc-" + doAssert encode("London") == "London-" + doAssert encode("Lloyd-Atkinson") == "Lloyd-Atkinson-" + doAssert encode("This has spaces") == "This has spaces-" + doAssert encode("ü") == "tda" + doAssert encode("München") == "Mnchen-3ya" + doAssert encode("Mnchen-3ya") == "Mnchen-3ya-" + doAssert encode("München-Ost") == "Mnchen-Ost-9db" + doAssert encode("Bahnhof München-Ost") == "Bahnhof Mnchen-Ost-u6b" + block: + doAssert decode("") == "" + doAssert decode("a-") == "a" + doAssert decode("A-") == "A" + doAssert decode("3-") == "3" + doAssert decode("--") == "-" + doAssert decode("---") == "--" + doAssert decode("abc-") == "abc" + doAssert decode("London-") == "London" + doAssert decode("Lloyd-Atkinson-") == "Lloyd-Atkinson" + doAssert decode("This has spaces-") == "This has spaces" + doAssert decode("tda") == "ü" + doAssert decode("Mnchen-3ya") == "München" + doAssert decode("Mnchen-3ya-") == "Mnchen-3ya" + doAssert decode("Mnchen-Ost-9db") == "München-Ost" + doAssert decode("Bahnhof Mnchen-Ost-u6b") == "Bahnhof München-Ost" + + when isMainModule: assert(decode(encode("", "bücher")) == "bücher") assert(decode(encode("münchen")) == "münchen") diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index d62276da9..ac48d9eee 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -320,6 +320,22 @@ proc `+=`*(a: var RunningRegress, b: RunningRegress) = {.pop.} {.pop.} + +runnableExamples: + static: + block: + var statistics: RunningStat ## Must be "var" + statistics.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) + doAssert statistics.n == 8 + doAssert statistics.mean() is SomeFloat + doAssert statistics.variance() is SomeFloat + doAssert statistics.varianceS() is SomeFloat + doAssert statistics.skewness() is SomeFloat + doAssert statistics.skewnessS() is SomeFloat + doAssert statistics.kurtosis() is SomeFloat + doAssert statistics.kurtosisS() is SomeFloat + + when isMainModule: proc clean(x: float): float = result = round(1.0e8*x).float * 1.0e-8 diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim index 0cb5edc9b..f365d4ab2 100644 --- a/lib/std/editdistance.nim +++ b/lib/std/editdistance.nim @@ -13,10 +13,11 @@ import unicode proc editDistance*(a, b: string): int {.noSideEffect.} = - ## Returns the unicode-rune edit distance between ``a`` and ``b``. + ## Returns the **unicode-rune** edit distance between ``a`` and ``b``. ## ## This uses the `Levenshtein`:idx: distance algorithm with only a linear ## memory overhead. + runnableExamples: static: doAssert editdistance("Kitten", "Bitten") == 1 if len(a) > len(b): # make ``b`` the longer string return editDistance(b, a) @@ -181,6 +182,7 @@ proc editDistanceAscii*(a, b: string): int {.noSideEffect.} = ## ## This uses the `Levenshtein`:idx: distance algorithm with only a linear ## memory overhead. + runnableExamples: static: doAssert editDistanceAscii("Kitten", "Bitten") == 1 var len1 = a.len var len2 = b.len if len1 > len2: diff --git a/lib/std/sums.nim b/lib/std/sums.nim index dc9d8d507..a48360180 100644 --- a/lib/std/sums.nim +++ b/lib/std/sums.nim @@ -54,6 +54,14 @@ func sumPairs*[T](x: openArray[T]): T = if n == 0: T(0) else: sumPairwise(x, 0, n) +runnableExamples: + static: + block: + const data = [1, 2, 3, 4, 5, 6, 7, 8, 9] + doAssert sumKbn(data) == 45 + doAssert sumPairs(data) == 45 + + when isMainModule: from math import pow diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 5eb700f4c..13836a540 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -48,11 +48,17 @@ template assert*(cond: untyped, msg = "") = ## The compiler may not generate any code at all for ``assert`` if it is ## advised to do so through the ``-d:danger`` or ``--assertions:off`` ## `command line switches `_. + ## + ## .. code-block:: nim + ## static: assert 1 == 9, "This works when not built with -d:danger or --assertions:off" const expr = astToStr(cond) assertImpl(cond, msg, expr, compileOption("assertions")) template doAssert*(cond: untyped, msg = "") = ## Similar to ``assert`` but is always turned on regardless of ``--assertions``. + ## + ## .. code-block:: nim + ## static: assert 1 == 9, "This works when built with/without -d:danger or --assertions:off" const expr = astToStr(cond) assertImpl(cond, msg, expr, true) From 5621ff6d097b07bf39b3e05120068c838812ab69 Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 31 Mar 2020 13:48:56 +0000 Subject: [PATCH 0228/4254] workflows/ci_docs: lots of goodies (#13809) * workflows/ci_docs: publish documentation to Github Pages This should be a complete replacement for our current Travis CI setup. * workflows/ci_docs: run docgen upon modification to the css on push So that any changes regarding the stylesheets would be reflected on the published docs. * workflows/ci_docs: build the compiler in release mode * workflows/ci_docs: set branch name for the generated docs This makes the "Source" links work correctly. * workflows/ci_docs: run docgen on windows and osx too Only deploy the Linux-generated version. * workflows/ci_docs: cache csources compiler This should cut the time spent building csources, which is about 1-2mins depending on OS. --- .github/workflows/ci_docs.yml | 110 +++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 733f95b96..cc3728939 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -1,36 +1,105 @@ name: Nim Docs CI on: + push: + # Run only on changes on these files + paths: + - 'lib/**.nim' + - 'doc/**.rst' + - 'doc/nimdoc.css' + pull_request: # Run only on changes on these files paths: - - 'lib/*.nim' - - 'doc/*.rst' + - 'lib/**.nim' + - 'doc/**.rst' jobs: build: - name: 'Docs builder' - runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + target: [linux, windows, osx] + include: + - target: linux + os: ubuntu-18.04 + - target: windows + os: windows-2019 + - target: osx + os: macos-10.15 + + name: ${{ matrix.target }} + runs-on: ${{ matrix.os }} + steps: - name: 'Checkout' uses: actions/checkout@v2 - - name: 'Checkout csources' - uses: actions/checkout@v2 - with: - repository: nim-lang/csources - path: csources + - name: 'Install build dependencies (macOS)' + if: runner.os == 'macOS' + run: brew install make + + - name: 'Install build dependencies (Windows)' + if: runner.os == 'Windows' + shell: bash + run: | + mkdir dist + curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z + curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip + 7z x dist/mingw64.7z -odist + 7z x dist/dlls.zip -obin + echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" - name: 'Add build binaries to PATH' shell: bash run: echo "::add-path::${{ github.workspace }}/bin" + - name: 'Get current csources version' + id: csources-version + shell: bash + run: | + sha=$(git ls-remote https://github.com/nim-lang/csources master | cut -f 1) + echo "::set-output name=sha::$sha" + + - name: 'Get prebuilt csources from cache' + id: csources-cache + uses: actions/cache@v1 + with: + path: bin + key: '${{ matrix.os }}-${{ steps.csources-version.outputs.sha }}' + + - name: 'Checkout csources' + if: steps.csources-cache.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + repository: nim-lang/csources + path: csources + - name: 'Build 1-stage compiler from csources' shell: bash run: | - ncpu=$(nproc) - [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 + ext= + [[ '${{ runner.os }}' == 'Windows' ]] && ext=.exe + if [[ ! -x bin/nim-csources$ext ]]; then + ncpu= + case '${{ runner.os }}' in + 'Linux') + ncpu=$(nproc) + ;; + 'macOS') + ncpu=$(sysctl -n hw.ncpu) + ;; + 'Windows') + ncpu=$NUMBER_OF_PROCESSORS + ;; + esac + [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 - make -C csources -j $ncpu CC=gcc ucpu='amd64' + make -C csources -j $ncpu CC=gcc + cp bin/nim{,-csources}$ext + else + echo 'Cache hit, using prebuilt csources' + cp bin/nim{-csources,}$ext + fi - name: 'Build koch' shell: bash @@ -38,8 +107,21 @@ jobs: - name: 'Build the real compiler' shell: bash - run: ./koch boot + run: ./koch boot -d:release - name: 'Build documentation' shell: bash - run: ./koch doc + run: ./koch doc --git.commit:devel + + - name: 'Prepare documentation for deployment' + if: github.event_name == 'push' && github.ref == 'devel' && matrix.target == 'linux' + shell: bash + run: cp -f doc/html/{overview,index}.html + + - name: 'Publish documentation to Github Pages' + if: github.event_name == 'push' && github.ref == 'devel' && matrix.target == 'linux' + uses: crazy-max/ghaction-github-pages@v1 + with: + build-dir: doc/html + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 7abeba6aeb2de6ab55702524a2c35da1c7da2ee1 Mon Sep 17 00:00:00 2001 From: Euan Date: Tue, 31 Mar 2020 14:50:24 +0100 Subject: [PATCH 0229/4254] #13806 - getApplFreebsd might lose data (#13807) * #13806 - first call sysctl with a null buffer to get the length, then alloc buffer and call again * Use csize_t rather than csize * Suggestions from @Clyybber Co-authored-by: Euan Torano --- lib/pure/os.nim | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index fda482bc3..98143bc1a 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2791,23 +2791,23 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly)): const KERN_PROC_PATHNAME = 9 proc getApplFreebsd(): string = - var pathLength = csize_t(MAX_PATH) - result = newString(pathLength) + var pathLength = csize_t(0) var req = [CTL_KERN.cint, KERN_PROC.cint, KERN_PROC_PATHNAME.cint, -1.cint] - while true: - let res = sysctl(addr req[0], 4, cast[pointer](addr result[0]), - addr pathLength, nil, 0) - if res < 0: - let err = osLastError() - if err.int32 == ENOMEM: - result = newString(pathLength) - else: - result.setLen(0) # error! - break - else: - # trim the trailing null byte, as the result is a string not a cstring - result.setLen(pathLength-1) - break + + # first call to get the required length + var res = sysctl(addr req[0], 4, nil, addr pathLength, nil, 0) + + if res < 0: + return "" + + result.setLen(pathLength) + res = sysctl(addr req[0], 4, addr result[0], addr pathLength, nil, 0) + + if res < 0: + return "" + + let realLen = len(cstring(result)) + setLen(result, realLen) when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)): proc getApplAux(procPath: string): string = From b1aa3b1eeada17453cee9af5c9227c85e0b73d54 Mon Sep 17 00:00:00 2001 From: c-blake Date: Tue, 31 Mar 2020 13:18:45 -0400 Subject: [PATCH 0230/4254] Unwind just the "pseudorandom probing" part of recent sets,tables changes (#13816) * Unwind just the "pseudorandom probing" (whole hash-code-keyed variable stride double hashing) part of recent sets & tables changes (which has still been causing bugs over a month later (e.g., two days ago https://github.com/nim-lang/Nim/issues/13794) as well as still having several "figure this out" implementation question comments in them (see just diffs of this PR). This topic has been discussed in many places: https://github.com/nim-lang/Nim/issues/13393 https://github.com/nim-lang/Nim/pull/13418 https://github.com/nim-lang/Nim/pull/13440 https://github.com/nim-lang/Nim/issues/13794 Alternative/non-mandatory stronger integer hashes (or vice-versa opt-in identity hashes) are a better solution that is more general (no illusion of one hard-coded sequence solving all problems) while retaining the virtues of linear probing such as cache obliviousness and age-less tables under delete-heavy workloads (still untested after a month of this change). The only real solution for truly adversarial keys is a hash keyed off of data unobservable to attackers. That all fits better with a few families of user-pluggable/define-switchable hashes which can be provided in a separate PR more about `hashes.nim`. This PR carefully preserves the better (but still hard coded!) probing of the `intsets` and other recent fixes like `move` annotations, hash order invariant tests, `intsets.missingOrExcl` fixing, and the move of `rightSize` into `hashcommon.nim`. * Fix `data.len` -> `dataLen` problem. --- lib/pure/collections/hashcommon.nim | 80 +++++----------------- lib/pure/collections/intsets.nim | 8 +-- lib/pure/collections/setimpl.nim | 28 +++++--- lib/pure/collections/sets.nim | 14 ++-- lib/pure/collections/sharedtables.nim | 4 +- lib/pure/collections/tableimpl.nim | 42 +++++++----- lib/pure/collections/tables.nim | 96 ++++++++------------------- tests/arc/trepr.nim | 2 +- 8 files changed, 99 insertions(+), 175 deletions(-) diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index bfc09ec3c..e998145e7 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -18,87 +18,43 @@ when not defined(nimHasDefault): var v: T v -const freeMarker = 0 -const deletedMarker = -1 - -type UHash = uint - # hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These # two procs retain clarity of that encoding without the space cost of an enum. -proc isFilledAndValid(hcode: Hash): bool {.inline.} = - result = hcode != 0 and hcode != deletedMarker - # performance: we could use bit magic if needed +proc isEmpty(hcode: Hash): bool {.inline.} = + result = hcode == 0 proc isFilled(hcode: Hash): bool {.inline.} = result = hcode != 0 - -proc translateBits(a: UHash, numBitsMask: int): UHash {.inline.} = - result = (a shr numBitsMask) or (a shl (UHash.sizeof * 8 - numBitsMask)) - -proc nextTry(h, maxHash: Hash, perturb: var UHash): Hash {.inline.} = - # FACTOR between hashcommon.nextTry, intsets.nextTry - # an optimization would be to use `(h + 1) and maxHash` for a few iterations - # and then switch to the formula below, to get "best of both worlds": good - # cache locality, except when a collision cluster is detected (ie, large number - # of iterations). - const PERTURB_SHIFT = 5 # consider tying this to `numBitsMask = fastLog2(t.dataLen)` - result = cast[Hash]((5*cast[uint](h) + 1 + perturb) and cast[uint](maxHash)) - perturb = perturb shr PERTURB_SHIFT +proc nextTry(h, maxHash: Hash): Hash {.inline.} = + result = (h + 1) and maxHash proc mustRehash[T](t: T): bool {.inline.} = - # FACTOR between hashcommon.mustRehash, intsets.mustRehash - let counter2 = t.counter + t.countDeleted - let length = t.dataLen - assert(length > counter2) - result = (length * 2 < counter2 * 3) or (length - counter2 < 4) # synchronize with `rightSize` + assert(t.dataLen > t.counter) + result = (t.dataLen * 2 < t.counter * 3) or (t.dataLen - t.counter < 4) proc rightSize*(count: Natural): int {.inline.} = - ## Return the value of `initialSize` to support `count` items. + ## Return the value of ``initialSize`` to support ``count`` items. ## ## If more items are expected to be added, simply add that ## expected extra amount to the parameter before calling this. - ## - ## Internally, we want `mustRehash(t) == false` for t that was just resized. + # # Make sure to synchronize with `mustRehash` result = nextPowerOfTwo(count * 3 div 2 + 4) -template getPerturb(t: typed, hc: Hash): UHash = - # we can't use `fastLog2(dataLen(t))` because importing `bitops` would cause codegen errors - # so we use a practical value of half the bit width (eg 64 / 2 = 32 on 64bit machines) - let numBitsMask = sizeof(Hash) * 4 # ie, sizeof(Hash) * 8 / 2 - # this makes a major difference for cases like #13393; it causes the bits - # that were masked out in 1st position so they'll be masked in instead, and - # influence the recursion in nextTry earlier rather than later. - translateBits(cast[uint](hc), numBitsMask) - template rawGetKnownHCImpl() {.dirty.} = if t.dataLen == 0: return -1 var h: Hash = hc and maxHash(t) # start with real hash value - var perturb = t.getPerturb(hc) - var deletedIndex = -1 - while true: - if isFilledAndValid(t.data[h].hcode): - # Compare hc THEN key with boolean short circuit. This makes the common case - # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. - # It does slow down succeeding lookups by one extra Hash cmp&and..usually - # just a few clock cycles, generally worth it for any non-integer-like A. - # performance: we optimize this: depending on type(key), skip hc comparison - if t.data[h].hcode == hc and t.data[h].key == key: - return h - h = nextTry(h, maxHash(t), perturb) - elif t.data[h].hcode == deletedMarker: - if deletedIndex == -1: - deletedIndex = h - h = nextTry(h, maxHash(t), perturb) - else: - break - if deletedIndex == -1: - result = -1 - h # < 0 => MISSING; insert idx = -1 - result - else: - # we prefer returning a (in fact the 1st found) deleted index - result = -1 - deletedIndex + while isFilled(t.data[h].hcode): + # Compare hc THEN key with boolean short circuit. This makes the common case + # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. + # It does slow down succeeding lookups by one extra Hash cmp&and..usually + # just a few clock cycles, generally worth it for any non-integer-like A. + if t.data[h].hcode == hc and t.data[h].key == key: + return h + h = nextTry(h, maxHash(t)) + result = -1 - h # < 0 => MISSING; insert idx = -1 - result proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} = rawGetKnownHCImpl() @@ -107,8 +63,6 @@ template genHashImpl(key, hc: typed) = hc = hash(key) if hc == 0: # This almost never taken branch should be very predictable. hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. - elif hc == deletedMarker: - hc = 214159261 template genHash(key: typed): Hash = var res: Hash diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 1967a0149..eae3fa447 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -46,20 +46,16 @@ type IntSet* = object ## An efficient set of `int` implemented as a sparse bit set. elems: int # only valid for small numbers counter, max: int - countDeleted: int head: PTrunk data: TrunkSeq a: array[0..33, int] # profiling shows that 34 elements are enough proc mustRehash[T](t: T): bool {.inline.} = - # FACTOR between hashcommon.mustRehash, intsets.mustRehash - let counter2 = t.counter + t.countDeleted let length = t.max + 1 - assert length > counter2 - result = (length * 2 < counter2 * 3) or (length - counter2 < 4) + assert length > t.counter + result = (length * 2 < t.counter * 3) or (length - t.counter < 4) proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} = - # FACTOR between hashcommon.nextTry, intsets.nextTry const PERTURB_SHIFT = 5 var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT perturb = cast[Hash](perturb2) diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index 9e68cb072..d798cbcb3 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -35,11 +35,10 @@ proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A, proc enlarge[A](s: var HashSet[A]) = var n: KeyValuePairSeq[A] - newSeq(n, s.counter.rightSize) + newSeq(n, len(s.data) * growthFactor) swap(s.data, n) # n is now old seq - s.countDeleted = 0 for i in countup(0, high(n)): - if isFilledAndValid(n[i].hcode): + if isFilled(n[i].hcode): var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode) rawInsert(s, s.data, n[i].key, n[i].hcode, j) @@ -69,6 +68,11 @@ template containsOrInclImpl() {.dirty.} = rawInsert(s, s.data, key, hc, -1 - index) inc(s.counter) +template doWhile(a, b) = + while true: + b + if not a: break + proc exclImpl[A](s: var HashSet[A], key: A): bool {.inline.} = var hc: Hash var i = rawGet(s, key, hc) @@ -78,9 +82,17 @@ proc exclImpl[A](s: var HashSet[A], key: A): bool {.inline.} = if i >= 0: result = false dec(s.counter) - inc(s.countDeleted) - s.data[i].hcode = deletedMarker - s.data[i].key = default(type(s.data[i].key)) + while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 + var j = i # The correctness of this depends on (h+1) in nextTry, + var r = j # though may be adaptable to other simple sequences. + s.data[i].hcode = 0 # mark current EMPTY + s.data[i].key = default(type(s.data[i].key)) + doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): + i = (i + 1) and msk # increment mod table size + if isEmpty(s.data[i].hcode): # end of collision cluster; So all done + return + r = s.data[i].hcode and msk # "home" location of key@i + s.data[j] = move(s.data[i]) # data[i] will be marked EMPTY next loop template dollarImpl() {.dirty.} = result = "{" @@ -113,7 +125,7 @@ proc enlarge[A](s: var OrderedSet[A]) = swap(s.data, n) while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): # should be isFilledAndValid once tombstones are used + if isFilled(n[h].hcode): var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode) rawInsert(s, s.data, n[h].key, n[h].hcode, j) h = nxt @@ -131,7 +143,7 @@ proc exclImpl[A](s: var OrderedSet[A], key: A): bool {.inline.} = result = true while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): # should be isFilledAndValid once tombstones are used + if isFilled(n[h].hcode): if n[h].hcode == hc and n[h].key == key: dec s.counter result = false diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index caa25dbb3..8c04a05e3 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -68,7 +68,6 @@ type ## before calling other procs on it. data: KeyValuePairSeq[A] counter: int - countDeleted: int type OrderedKeyValuePair[A] = tuple[ @@ -81,7 +80,6 @@ type ## <#initOrderedSet,int>`_ before calling other procs on it. data: OrderedKeyValuePairSeq[A] counter, first, last: int - countDeleted: int const defaultInitialSize* = 64 @@ -249,7 +247,7 @@ iterator items*[A](s: HashSet[A]): A = ## echo b ## # --> {(a: 1, b: 3), (a: 0, b: 4)} for h in 0 .. high(s.data): - if isFilledAndValid(s.data[h].hcode): yield s.data[h].key + if isFilled(s.data[h].hcode): yield s.data[h].key proc containsOrIncl*[A](s: var HashSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was already in `s`. @@ -341,7 +339,7 @@ proc pop*[A](s: var HashSet[A]): A = doAssertRaises(KeyError, echo s.pop) for h in 0 .. high(s.data): - if isFilledAndValid(s.data[h].hcode): + if isFilled(s.data[h].hcode): result = s.data[h].key excl(s, result) return result @@ -574,8 +572,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] = proc hash*[A](s: HashSet[A]): Hash = ## Hashing of HashSet. for h in 0 .. high(s.data): - if isFilledAndValid(s.data[h].hcode): - result = result xor s.data[h].hcode + result = result xor s.data[h].hcode result = !$result proc `$`*[A](s: HashSet[A]): string = @@ -593,6 +590,7 @@ proc `$`*[A](s: HashSet[A]): string = ## # --> {no, esc'aping, is " provided} dollarImpl() + proc initSet*[A](initialSize = defaultInitialSize): HashSet[A] {.deprecated: "Deprecated since v0.20, use 'initHashSet'".} = initHashSet[A](initialSize) @@ -624,7 +622,7 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = var idx = 0 while h >= 0: var nxt = s.data[h].next - if isFilledAndValid(s.data[h].hcode): + if isFilled(s.data[h].hcode): yieldStmt inc(idx) h = nxt @@ -858,7 +856,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool = while h >= 0 and g >= 0: var nxh = s.data[h].next var nxg = t.data[g].next - if isFilledAndValid(s.data[h].hcode) and isFilledAndValid(t.data[g].hcode): + if isFilled(s.data[h].hcode) and isFilled(t.data[g].hcode): if s.data[h].key == t.data[g].key: inc compared else: diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 27ac5e84f..2a1c0543f 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -25,7 +25,6 @@ type SharedTable*[A, B] = object ## generic hash SharedTable data: KeyValuePairSeq[A, B] counter, dataLen: int - countDeleted: int lock: Lock template maxHash(t): untyped = t.dataLen-1 @@ -50,10 +49,9 @@ proc enlarge[A, B](t: var SharedTable[A, B]) = for i in 0..= 0: dec(t.counter) - inc(t.countDeleted) - t.data[i].hcode = deletedMarker - t.data[i].key = default(type(t.data[i].key)) - t.data[i].val = default(type(t.data[i].val)) - # mustRehash + enlarge not needed because counter+countDeleted doesn't change + block outer: + while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 + var j = i # The correctness of this depends on (h+1) in nextTry, + var r = j # though may be adaptable to other simple sequences. + t.data[i].hcode = 0 # mark current EMPTY + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) + while true: + i = (i + 1) and msk # increment mod table size + if isEmpty(t.data[i].hcode): # end of collision cluster; So all done + break outer + r = t.data[i].hcode and msk # "home" location of key@i + if not ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): + break + when defined(js): + t.data[j] = t.data[i] + else: + t.data[j] = move(t.data[i]) # data[j] will be marked EMPTY next loop template delImpl() {.dirty.} = var hc: Hash @@ -108,7 +115,6 @@ template clearImpl() {.dirty.} = t.counter = 0 template ctAnd(a, b): bool = - # pending https://github.com/nim-lang/Nim/issues/13502 when a: when b: true else: false @@ -126,7 +132,7 @@ template initImpl(result: typed, size: int) = result.last = -1 template insertImpl() = # for CountTable - checkIfInitialized() + if t.dataLen == 0: initImpl(t, defaultInitialSize) if mustRehash(t): enlarge(t) ctRawInsert(t, t.data, key, val) inc(t.counter) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index b79e396fd..131e0ad80 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -233,7 +233,6 @@ type ## For creating an empty Table, use `initTable proc<#initTable,int>`_. data: KeyValuePairSeq[A, B] counter: int - countDeleted: int TableRef*[A, B] = ref Table[A, B] ## Ref version of `Table<#Table>`_. ## ## For creating a new empty TableRef, use `newTable proc @@ -266,16 +265,14 @@ template get(t, key): untyped = proc enlarge[A, B](t: var Table[A, B]) = var n: KeyValuePairSeq[A, B] - newSeq(n, t.counter.rightSize) + newSeq(n, len(t.data) * growthFactor) swap(t.data, n) - t.countDeleted = 0 for i in countup(0, high(n)): let eh = n[i].hcode - if isFilledAndValid(eh): + if isFilled(eh): var j: Hash = eh and maxHash(t) - var perturb = t.getPerturb(eh) while isFilled(t.data[j].hcode): - j = nextTry(j, maxHash(t), perturb) + j = nextTry(j, maxHash(t)) when defined(js): rawInsert(t, t.data, n[i].key, n[i].val, eh, j) else: @@ -662,7 +659,7 @@ iterator pairs*[A, B](t: Table[A, B]): (A, B) = ## # value: [1, 5, 7, 9] let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -684,7 +681,7 @@ iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -705,7 +702,7 @@ iterator keys*[A, B](t: Table[A, B]): A = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") @@ -726,7 +723,7 @@ iterator values*[A, B](t: Table[A, B]): B = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -748,27 +745,10 @@ iterator mvalues*[A, B](t: var Table[A, B]): var B = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") -template hasKeyOrPutCache(cache, h): bool = - # using `IntSet` would be an option worth considering to avoid quadratic - # behavior in case user misuses Table with lots of duplicate keys; but it - # has overhead in the common case of small number of duplicates. - # However: when lots of duplicates are used, all operations would be slow - # anyway because the full `hash(key)` is identical for these, which makes - # `nextTry` follow the exact same path for each key, resulting in large - # collision clusters. Alternatives could involve modifying the hash/retrieval - # based on duplicate key count. - var ret = false - for hi in cache: - if hi == h: - ret = true - break - if not ret: cache.add h - ret - iterator allValues*[A, B](t: Table[A, B]; key: A): B = ## Iterates over any value in the table ``t`` that belongs to the given ``key``. ## @@ -782,20 +762,13 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B = for i in 1..3: a.add('z', 10*i) doAssert toSeq(a.pairs).sorted == @[('a', 3), ('b', 5), ('z', 10), ('z', 20), ('z', 30)] doAssert sorted(toSeq(a.allValues('z'))) == @[10, 20, 30] - - let hc = genHash(key) - var h: Hash = hc and high(t.data) + var h: Hash = genHash(key) and high(t.data) let L = len(t) - var perturb = t.getPerturb(hc) - - var num = 0 - var cache: seq[Hash] - while isFilled(t.data[h].hcode): # `isFilledAndValid` would be incorrect, see test for `allValues` - if t.data[h].hcode == hc and t.data[h].key == key: - if not hasKeyOrPutCache(cache, h): - yield t.data[h].val - assert(len(t) == L, "the length of the table changed while iterating over it") - h = nextTry(h, high(t.data), perturb) + while isFilled(t.data[h].hcode): + if t.data[h].key == key: + yield t.data[h].val + assert(len(t) == L, "the length of the table changed while iterating over it") + h = nextTry(h, high(t.data)) @@ -1118,7 +1091,7 @@ iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = ## # value: [1, 5, 7, 9] let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1140,7 +1113,7 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1161,7 +1134,7 @@ iterator keys*[A, B](t: TableRef[A, B]): A = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1182,7 +1155,7 @@ iterator values*[A, B](t: TableRef[A, B]): B = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1203,7 +1176,7 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B = let L = len(t) for h in 0 .. high(t.data): - if isFilledAndValid(t.data[h].hcode): + if isFilled(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1229,8 +1202,6 @@ type ## <#initOrderedTable,int>`_. data: OrderedKeyValuePairSeq[A, B] counter, first, last: int - countDeleted: int - OrderedTableRef*[A, B] = ref OrderedTable[A, B] ## Ref version of ## `OrderedTable<#OrderedTable>`_. ## @@ -1252,7 +1223,7 @@ proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int = proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], key: A, val: B, hc: Hash, h: Hash) = - rawInsertImpl(t) + rawInsertImpl() data[h].next = -1 if t.first < 0: t.first = h if t.last >= 0: data[t.last].next = h @@ -1260,20 +1231,18 @@ proc rawInsert[A, B](t: var OrderedTable[A, B], proc enlarge[A, B](t: var OrderedTable[A, B]) = var n: OrderedKeyValuePairSeq[A, B] - newSeq(n, t.counter.rightSize) + newSeq(n, len(t.data) * growthFactor) var h = t.first t.first = -1 t.last = -1 swap(t.data, n) - t.countDeleted = 0 while h >= 0: var nxt = n[h].next let eh = n[h].hcode - if isFilledAndValid(eh): + if isFilled(eh): var j: Hash = eh and maxHash(t) - var perturb = t.getPerturb(eh) while isFilled(t.data[j].hcode): - j = nextTry(j, maxHash(t), perturb) + j = nextTry(j, maxHash(t)) rawInsert(t, t.data, move n[h].key, move n[h].val, n[h].hcode, j) h = nxt @@ -1282,10 +1251,6 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = var h = t.first while h >= 0: var nxt = t.data[h].next - # For OrderedTable/OrderedTableRef, isFilled is ok because `del` is O(n) - # and doesn't create tombsones, but if it does start using tombstones, - # carefully replace `isFilled` by `isFilledAndValid` as appropriate for these - # table types only, ditto with `OrderedSet`. if isFilled(t.data[h].hcode): yieldStmt h = nxt @@ -2229,7 +2194,6 @@ type ## <#initCountTable,int>`_. data: seq[tuple[key: A, val: int]] counter: int - countDeleted: int isSorted: bool CountTableRef*[A] = ref CountTable[A] ## Ref version of ## `CountTable<#CountTable>`_. @@ -2242,10 +2206,8 @@ type proc ctRawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = - let hc = hash(key) - var perturb = t.getPerturb(hc) - var h: Hash = hc and high(data) - while data[h].val != 0: h = nextTry(h, high(data), perturb) # TODO: handle deletedMarker + var h: Hash = hash(key) and high(data) + while data[h].val != 0: h = nextTry(h, high(data)) data[h].key = key data[h].val = val @@ -2272,12 +2234,10 @@ proc remove[A](t: var CountTable[A], key: A) = proc rawGet[A](t: CountTable[A], key: A): int = if t.data.len == 0: return -1 - let hc = hash(key) - var perturb = t.getPerturb(hc) - var h: Hash = hc and high(t.data) # start with real hash value - while t.data[h].val != 0: # TODO: may need to handle t.data[h].hcode == deletedMarker? + var h: Hash = hash(key) and high(t.data) # start with real hash value + while t.data[h].val != 0: if t.data[h].key == key: return h - h = nextTry(h, high(t.data), perturb) + h = nextTry(h, high(t.data)) result = -1 - h # < 0 => MISSING; insert idx = -1 - result template ctget(t, key, default: untyped): untyped = diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index 391622ff6..7a92112ed 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -1,7 +1,7 @@ discard """ cmd: "nim c --gc:arc $file" nimout: '''(a: true, n: doAssert) -Table[system.string, trepr.MyType](data: @[], counter: 0, countDeleted: 0) +Table[system.string, trepr.MyType](data: @[], counter: 0) nil ''' """ From 40898871a9bde4353edc21423b0e8bfe03f68414 Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 31 Mar 2020 17:36:37 +0000 Subject: [PATCH 0231/4254] workflows/ci_docs: fix documentation deployment (#13819) * workflows/ci_docs: fix docs publishing It turns out that github.ref is the full ref name, so we have to be a bit more specific. See https://developer.github.com/v3/activity/events/types/#pushevent Also fixed a silly typo :) * workflows/ci_docs: run CI when there are changes to the workflow --- .github/workflows/ci_docs.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index cc3728939..a1e0920b6 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -6,12 +6,14 @@ on: - 'lib/**.nim' - 'doc/**.rst' - 'doc/nimdoc.css' + - '.github/workflows/ci_docs.yml' pull_request: # Run only on changes on these files paths: - 'lib/**.nim' - 'doc/**.rst' + - '.github/workflows/ci_docs.yml' jobs: build: @@ -114,14 +116,18 @@ jobs: run: ./koch doc --git.commit:devel - name: 'Prepare documentation for deployment' - if: github.event_name == 'push' && github.ref == 'devel' && matrix.target == 'linux' + if: | + github.event_name == 'push' && github.ref == 'refs/heads/devel' && + matrix.target == 'linux' shell: bash run: cp -f doc/html/{overview,index}.html - name: 'Publish documentation to Github Pages' - if: github.event_name == 'push' && github.ref == 'devel' && matrix.target == 'linux' + if: | + github.event_name == 'push' && github.ref == 'refs/heads/devel' && + matrix.target == 'linux' uses: crazy-max/ghaction-github-pages@v1 with: - build-dir: doc/html + build_dir: doc/html env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 9134bb9cfb81297d00ccd6d41fe975e853fca2e5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 31 Mar 2020 21:14:05 +0200 Subject: [PATCH 0232/4254] macros for proc types, macros for types (#13778) * new minor feature: macros for proc types, to be documented * Finished the implementation and added tests * [skip ci] Describe the new custom pragmas in the manual and the changelog Co-authored-by: Zahary Karadjov --- changelog.md | 2 + compiler/ast.nim | 59 +++++++-------- compiler/semstmts.nim | 122 ++++++++++++++++--------------- compiler/semtypes.nim | 48 ++++++++++-- doc/manual.rst | 118 +++++++++++++++++++----------- lib/pure/asyncmacro.nim | 6 ++ tests/pragmas/tcustom_pragma.nim | 88 +++++++++++++++++++++- 7 files changed, 303 insertions(+), 140 deletions(-) diff --git a/changelog.md b/changelog.md index 42f469567..78c707bf4 100644 --- a/changelog.md +++ b/changelog.md @@ -165,6 +165,8 @@ echo f - `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for non builtin pragmas, enabling things like lvalue references, see `pragmas.byaddr` +- `macro pragmas` can now be used in type sections. + ## Language changes - Unsigned integer operators have been fixed to allow promotion of the first operand. diff --git a/compiler/ast.nim b/compiler/ast.nim index 33edcc953..8b000ecb9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1597,48 +1597,43 @@ proc transitionToLet*(s: PSym) = s.bitsize = obj.bitsize s.alignment = obj.alignment -proc shallowCopy*(src: PNode): PNode = - # does not copy its sons, but provides space for them: - if src == nil: return nil - result = newNode(src.kind) - result.info = src.info - result.typ = src.typ - result.flags = src.flags * PersistentNodeFlags - result.comment = src.comment +template copyNodeImpl(dst, src, processSonsStmt) = + if src == nil: return + dst = newNode(src.kind) + dst.info = src.info + dst.typ = src.typ + dst.flags = src.flags * PersistentNodeFlags + dst.comment = src.comment when defined(useNodeIds): - if result.id == nodeIdToDebug: + if dst.id == nodeIdToDebug: echo "COMES FROM ", src.id case src.kind - of nkCharLit..nkUInt64Lit: result.intVal = src.intVal - of nkFloatLiterals: result.floatVal = src.floatVal - of nkSym: result.sym = src.sym - of nkIdent: result.ident = src.ident - of nkStrLit..nkTripleStrLit: result.strVal = src.strVal - else: newSeq(result.sons, src.len) + of nkCharLit..nkUInt64Lit: dst.intVal = src.intVal + of nkFloatLiterals: dst.floatVal = src.floatVal + of nkSym: dst.sym = src.sym + of nkIdent: dst.ident = src.ident + of nkStrLit..nkTripleStrLit: dst.strVal = src.strVal + else: processSonsStmt + +proc shallowCopy*(src: PNode): PNode = + # does not copy its sons, but provides space for them: + copyNodeImpl(result, src): + newSeq(result.sons, src.len) proc copyTree*(src: PNode): PNode = # copy a whole syntax tree; performs deep copying - if src == nil: - return nil - result = newNode(src.kind) - result.info = src.info - result.typ = src.typ - result.flags = src.flags * PersistentNodeFlags - result.comment = src.comment - when defined(useNodeIds): - if result.id == nodeIdToDebug: - echo "COMES FROM ", src.id - case src.kind - of nkCharLit..nkUInt64Lit: result.intVal = src.intVal - of nkFloatLiterals: result.floatVal = src.floatVal - of nkSym: result.sym = src.sym - of nkIdent: result.ident = src.ident - of nkStrLit..nkTripleStrLit: result.strVal = src.strVal - else: + copyNodeImpl(result, src): newSeq(result.sons, src.len) for i in 0..= 1: it[0] else: it + let it = n[i] + let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it if whichPragma(it) != wInvalid: # Not a custom pragma diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 6e423181c..7cddc7520 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1567,9 +1567,44 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = result.n[3] = semConceptBody(c, n[3]) closeScope(c) +proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode = + for p in pragmas: + let key = if p.kind in nkPragmaCallKinds and p.len >= 1: p[0] else: p + + if p.kind == nkEmpty or whichPragma(p) != wInvalid: + discard "builtin pragma" + elif strTableGet(c.userPragmas, considerQuotedIdent(c, key)) != nil: + discard "User-defined pragma" + else: + # we transform ``(arg1, arg2: T) {.m, rest.}`` into ``m((arg1, arg2: T) {.rest.})`` and + # let the semantic checker deal with it: + var x = newNodeI(nkCall, key.info) + x.add(key) + if p.kind in nkPragmaCallKinds and p.len > 1: + # pass pragma arguments to the macro too: + for i in 1 ..< p.len: + x.add(p[i]) + # Also pass the node the pragma has been applied to + x.add(operand.copyTreeWithoutNode(p)) + # recursion assures that this works for multiple macro annotations too: + var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared}) + if r != nil: + doAssert r[0].kind == nkSym + let m = r[0].sym + case m.kind + of skMacro: return semMacroExpr(c, r, r, m, {efNoSemCheck}) + of skTemplate: return semTemplateExpr(c, r, m, {efNoSemCheck}) + else: doAssert(false, "cannot happen") + proc semProcTypeWithScope(c: PContext, n: PNode, - prev: PType, kind: TSymKind): PType = + prev: PType, kind: TSymKind): PType = checkSonsLen(n, 2, c.config) + + if n[1].kind != nkEmpty and n[1].len > 0: + let macroEval = applyTypeSectionPragmas(c, n[1], n) + if macroEval != nil: + return semTypeNode(c, macroEval, prev) + openScope(c) result = semProcTypeNode(c, n[0], nil, prev, kind, isType=true) # start with 'ccClosure', but of course pragmas can overwrite this: @@ -1845,11 +1880,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result.addSonSkipIntLit(child) else: result = semProcTypeWithScope(c, n, prev, skIterator) - result.flags.incl(tfIterator) - if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline): - result.callConv = ccInline - else: - result.callConv = ccClosure + if result.kind == tyProc: + result.flags.incl(tfIterator) + if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline): + result.callConv = ccInline + else: + result.callConv = ccClosure of nkProcTy: if n.len == 0: result = newConstraint(c, tyProc) diff --git a/doc/manual.rst b/doc/manual.rst index bffb9e60c..4c1d5c659 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5353,26 +5353,6 @@ powerful programming construct that still suffices. So the "check list" is: (4) Else: Use a macro. -Macros as pragmas ------------------ - -Whole routines (procs, iterators etc.) can also be passed to a template or -a macro via the pragma notation: - -.. code-block:: nim - template m(s: untyped) = discard - - proc p() {.m.} = discard - -This is a simple syntactic transformation into: - -.. code-block:: nim - template m(s: untyped) = discard - - m: - proc p() = discard - - For Loop Macro -------------- @@ -6408,29 +6388,6 @@ the created global variables within a module is not defined, but all of them will be initialized after any top-level variables in their originating module and before any variable in a module that imports it. -pragma pragma -------------- - -The ``pragma`` pragma can be used to declare user defined pragmas. This is -useful because Nim's templates and macros do not affect pragmas. User -defined pragmas are in a different module-wide scope than all other symbols. -They cannot be imported from a module. - -Example: - -.. code-block:: nim - when appType == "lib": - {.pragma: rtl, exportc, dynlib, cdecl.} - else: - {.pragma: rtl, importc, dynlib: "client.dll", cdecl.} - - proc p*(a, b: int): int {.rtl.} = - result = a+b - -In the example a new pragma named ``rtl`` is introduced that either imports -a symbol from a dynamic library or exports the symbol for dynamic library -generation. - Disabling certain messages -------------------------- Nim generates some warnings and hints ("line too long") that may annoy the @@ -7127,6 +7084,34 @@ used. To see if a value was provided, `defined(FooBar)` can be used. The syntax `-d:flag` is actually just a shortcut for `-d:flag=true`. +User-defined pragmas +==================== + + +pragma pragma +------------- + +The ``pragma`` pragma can be used to declare user defined pragmas. This is +useful because Nim's templates and macros do not affect pragmas. User +defined pragmas are in a different module-wide scope than all other symbols. +They cannot be imported from a module. + +Example: + +.. code-block:: nim + when appType == "lib": + {.pragma: rtl, exportc, dynlib, cdecl.} + else: + {.pragma: rtl, importc, dynlib: "client.dll", cdecl.} + + proc p*(a, b: int): int {.rtl.} = + result = a+b + +In the example a new pragma named ``rtl`` is introduced that either imports +a symbol from a dynamic library or exports the symbol for dynamic library +generation. + + Custom annotations ------------------ It is possible to define custom typed pragmas. Custom pragmas do not effect @@ -7193,6 +7178,51 @@ More examples with custom pragmas: alpha {.editRange: [0.0..1.0], animatable.}: float32 +Macro pragmas +------------- + +All macros and templates can also be used as pragmas. They can be attached +to routines (procs, iterators, etc), type names or type expressions. The +compiler will perform the following simple syntactic transformations: + +.. code-block:: nim + template command(name: string, def: untyped) = discard + + proc p() {.command("print").} = discard + +This is translated to: + +.. code-block:: nim + command("print"): + proc p() = discard + +------ + +.. code-block:: nim + type + AsyncEventHandler = proc (x: Event) {.async.} + +This is translated to: + +.. code-block:: nim + type + AsyncEventHandler = async(proc (x: Event)) + +------ + +.. code-block:: nim + type + MyObject {.schema: "schema.protobuf".} = object + +This is translated to a call to the ``schema`` macro with a `nnkTypeDef` +AST node capturing both the left-hand side and right-hand side of the +definition. The macro can return a potentially modified `nnkTypeDef` tree +will replace the original row in the type section. + +When multiple macro pragmas are applied to the same definition, the +compiler will apply them consequently from left to right. Each macro +will receive as input the output of the previous one. + Foreign function interface @@ -7269,7 +7299,6 @@ In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. - Bycopy pragma ------------- @@ -7313,6 +7342,7 @@ checked. **Future directions**: GC'ed memory should be allowed in unions and the GC should scan unions conservatively. + Packed pragma ------------- The ``packed`` pragma can be applied to any ``object`` type. It ensures diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index ce84491eb..c6f4ae04a 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -212,6 +212,12 @@ proc verifyReturnType(typeName: string) {.compileTime.} = proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. ## The ``async`` macro supports a stmtList holding multiple async procedures. + if prc.kind == nnkProcTy: + result = prc + if prc[0][0].kind == nnkEmpty: + result[0][0] = parseExpr("Future[void]") + return result + if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: error("Cannot transform this node kind into an async proc." & " proc/method definition or lambda node expected.") diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 719af4d50..2d970aba1 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -1,6 +1,6 @@ {.experimental: "notnil".} -import macros +import macros, asyncmacro, asyncfutures block: template myAttr() {.pragma.} @@ -249,3 +249,89 @@ block: var e {.fooBar("foo", 123, 'u').}: int doAssert(hasCustomPragma(e, fooBar)) doAssert(getCustomPragmaVal(e, fooBar).c == 123) + +block: + macro expectedAst(expectedRepr: static[string], input: untyped): untyped = + assert input.treeRepr & "\n" == expectedRepr + return input + + const procTypeAst = """ +ProcTy + FormalParams + Empty + IdentDefs + Ident "x" + Ident "int" + Empty + Pragma + Ident "async" +""" + + type + Foo = proc (x: int) {.expectedAst(procTypeAst), async.} + + static: assert Foo is proc(x: int): Future[void] + + const asyncProcTypeAst = """ +ProcTy + FormalParams + BracketExpr + Ident "Future" + Ident "void" + IdentDefs + Ident "s" + Ident "string" + Empty + Pragma +""" + + type + Bar = proc (s: string) {.async, expectedAst(asyncProcTypeAst).} + + static: assert Bar is proc(x: string): Future[void] + + const typeAst = """ +TypeDef + PragmaExpr + Ident "Baz" + Pragma + Empty + ObjectTy + Empty + Empty + RecList + IdentDefs + Ident "x" + Ident "string" + Empty +""" + + type + Baz {.expectedAst(typeAst).} = object + x: string + + static: assert Baz.x is string + + const procAst = """ +ProcDef + Ident "bar" + Empty + Empty + FormalParams + Ident "string" + IdentDefs + Ident "s" + Ident "string" + Empty + Empty + Empty + StmtList + ReturnStmt + Ident "s" +""" + + proc bar(s: string): string {.expectedAst(procAst).} = + return s + + static: assert bar("x") == "x" + From c70b3952ff6fc181875c3ca1a28c6bba6617c1a8 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 31 Mar 2020 20:15:06 +0100 Subject: [PATCH 0233/4254] fixes #13810 (#13821) Co-authored-by: cooldome --- compiler/liftdestructors.nim | 2 +- tests/arc/tarcmisc.nim | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 9a91ec2e9..9e19b9bc2 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -128,7 +128,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) = if t.len > 0 and t[0] != nil: - fillBodyObjTImpl(c, skipTypes(t[0], abstractPtrs), body, x, y) + fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y) fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false) proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 9662ecf7f..687254794 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -2,7 +2,9 @@ discard """ output: ''' destroyed: false destroyed: false -destroying variable''' +closed +destroying variable +''' cmd: "nim c --gc:arc $file" """ @@ -27,3 +29,22 @@ proc test(count: int) = echo "destroyed: ", v.isNil test(3) + + +#------------------------------------------------------------------------------ +# issue #13810 + +import streams + +type + A = ref AObj + AObj = object of RootObj + io: Stream + B = ref object of A + x: int + +proc `=destroy`(x: var AObj) = + close(x.io) + echo "closed" + +var x = B(io: newStringStream("thestream")) From c6586322ba6c81d5f548db141b8f05205727d6f2 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 31 Mar 2020 16:21:49 -0300 Subject: [PATCH 0234/4254] Fix a 'See XXX' on documentation, clean out (#13820) --- lib/core/macrocache.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/core/macrocache.nim b/lib/core/macrocache.nim index bd48b5bd4..8fe1fa603 100644 --- a/lib/core/macrocache.nim +++ b/lib/core/macrocache.nim @@ -11,8 +11,7 @@ ## time information across module boundaries in global variables. ## Starting with version 0.19 of Nim this is not directly supported anymore ## as it breaks incremental compilations. -## Instead the API here needs to be used. See XXX (wikipedia page) for a -## theoretical foundation behind this. +## Instead the API here needs to be used. type CacheSeq* = distinct string From dd44701728f6bc9e6e6b4b2548b707221a075758 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 31 Mar 2020 16:22:24 -0300 Subject: [PATCH 0235/4254] Tiny fix on browsers.openDefaultBrowser (#13818) --- lib/pure/browsers.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 81a231aa2..66652bbc1 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -25,7 +25,8 @@ const osOpenCmd* = ## ``"open"`` on MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc. proc openDefaultBrowser*(url: string) = - ## opens `url` with the user's default browser. This does not block. + ## Opens `url` with the user's default browser. This does not block. + ## The URL must not be empty string. ## ## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open`` ## command is used. Under Unix, it is checked if ``xdg-open`` exists and @@ -36,6 +37,7 @@ proc openDefaultBrowser*(url: string) = ## ## .. code-block:: nim ## block: openDefaultBrowser("https://nim-lang.org") + doAssert url.len > 0, "URL must not be empty string" when defined(windows): var o = newWideCString(osOpenCmd) var u = newWideCString(url) From 9ffec79300e35fe100c657317eff21e9b8779d8b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 31 Mar 2020 22:54:48 +0200 Subject: [PATCH 0236/4254] DrNim (Nim compiler with Z3 integration) (#13743) * code cleanups and feature additions * added basic test and koch/CI integration * make it build on Unix * DrNim: now buildable on Unix, only takes 10 minutes, enjoy * added basic documentation for DrNim which can also be seen as the RFC we're following * drnim: change the build setup so that drnim.exe ends up in bin/ * makes simple floating point ranges work * added basic float range check * drnim: teach Z3 about Nim's range types plus code refactoring * drnim: make unsigned numbers work * added and fixed index checking under setLen * first implementation of .ensures, .invariant and .assume (.requires still missing and so is proc type compatibility checking * drnim: .requires checking implemented * drnim: implemented .ensures properly * more impressive test involving min() * drnim: check for proc type compatibility and base method compatibility wrt .requires and .ensures * testament: support for 'pattern * koch: uses new feature of testament * drnim: added tiny musings about 'old' * Make testament work with old SSL versions * koch: add support for 'koch drnim -d:release' * drnim: preparations for the param.old notation --- compiler/ast.nim | 5 +- compiler/condsyms.nim | 1 + compiler/guards.nim | 3 + compiler/modulegraphs.nim | 4 + compiler/pragmas.nim | 37 +- compiler/semcall.nim | 8 +- compiler/semmagic.nim | 25 ++ compiler/sempass2.nim | 110 ++++- compiler/semstmts.nim | 2 +- compiler/sigmatch.nim | 2 + compiler/trees.nim | 6 + compiler/wordrecg.nim | 2 + doc/drnim.rst | 203 +++++++++ drnim/drnim.nim | 675 ++++++++++++++++++++++++++++ drnim/nim.cfg | 18 + drnim/tests/config.nims | 7 + drnim/tests/tbasic_array_index.nim | 43 ++ drnim/tests/tensures.nim | 31 ++ drnim/tests/tsetlen_invalidates.nim | 22 + koch.nim | 28 ++ lib/std/logic.nim | 10 + lib/system/strmantle.nim | 8 +- testament/categories.nim | 24 +- testament/testament.nim.cfg | 2 + tools/kochdocs.nim | 1 + 25 files changed, 1242 insertions(+), 35 deletions(-) create mode 100644 doc/drnim.rst create mode 100644 drnim/drnim.nim create mode 100644 drnim/nim.cfg create mode 100644 drnim/tests/config.nims create mode 100644 drnim/tests/tbasic_array_index.nim create mode 100644 drnim/tests/tensures.nim create mode 100644 drnim/tests/tsetlen_invalidates.nim create mode 100644 lib/std/logic.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 8b000ecb9..4d45f0e55 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -335,8 +335,8 @@ const nkEffectList* = nkArgList # hacks ahead: an nkEffectList is a node with 4 children: exceptionEffects* = 0 # exceptions at position 0 - usesEffects* = 1 # read effects at position 1 - writeEffects* = 2 # write effects at position 2 + requiresEffects* = 1 # 'requires' annotation + ensuresEffects* = 2 # 'ensures' annotation tagEffects* = 3 # user defined tag ('gc', 'time' etc.) pragmasEffects* = 4 # not an effect, but a slot for pragmas in proc type effectListLen* = 5 # list of effects list @@ -633,6 +633,7 @@ type mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, + mImplies, mIff, mExists, mForall, mOld, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mConStrStr, mSlice, diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index b6997e6fc..4fc882ab7 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -114,4 +114,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasSinkInference") defineSymbol("nimNewIntegerOps") + defineSymbol("nimHasInvariant") defineSymbol("nimHasStacktraceMsgs") diff --git a/compiler/guards.nim b/compiler/guards.nim index aaf7ecf0e..88441eb96 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -249,6 +249,9 @@ proc pred(n: PNode): PNode = else: result = n +proc buildLe*(o: Operators; a, b: PNode): PNode = + result = o.opLe.buildCall(a, b) + proc canon*(n: PNode; o: Operators): PNode = if n.safeLen >= 1: result = shallowCopy(n) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index dff3f3b58..db4c28af7 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -72,6 +72,10 @@ type onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} globalDestructors*: seq[PNode] + proofEngine*: proc (graph: ModuleGraph; assumptions: seq[PNode]; toProve: PNode): (bool, string) {.nimcall.} + requirementsCheck*: proc (graph: ModuleGraph; assumptions: seq[PNode]; + call, requirement: PNode): (bool, string) {.nimcall.} + compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {.nimcall.} TPassContext* = object of RootObj # the pass's context PPassContext* = ref TPassContext diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 52df47ef0..6056afb6c 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -28,7 +28,8 @@ const wBorrow, wImportCompilerProc, wThread, wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, - wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy} + wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy, + wRequires, wEnsures} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty, @@ -39,7 +40,7 @@ const iteratorPragmas* = declPragmas + {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect, wMagic, wBorrow, wDiscardable, wGensym, wInject, wRaises, - wTags, wLocks, wGcSafe} + wTags, wLocks, wGcSafe, wRequires, wEnsures} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks, wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks, @@ -52,11 +53,12 @@ const wDeprecated, wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto, - wInjectStmt, wExperimental, wThis, wUsed} + wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume} lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader, wThread, wAsmNoStackFrame, - wRaises, wLocks, wTags, wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these? + wRaises, wLocks, wTags, wRequires, wEnsures, + wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these? typePragmas* = declPragmas + {wMagic, wAcyclic, wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow, wIncompleteStruct, wByCopy, wByRef, @@ -73,7 +75,8 @@ const wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, - wThread, wRaises, wLocks, wTags, wGcSafe} + wThread, wRaises, wLocks, wTags, wGcSafe, + wRequires, wEnsures} forVarPragmas* = {wInject, wGensym} allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas enumFieldPragmas* = {wDeprecated} @@ -105,6 +108,26 @@ proc invalidPragma*(c: PContext; n: PNode) = proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) = localError(c.config, n.info, "cannot attach a custom pragma to '" & s.name.s & "'") +proc pragmaProposition(c: PContext, n: PNode) = + if n.kind notin nkPragmaCallKinds or n.len != 2: + localError(c.config, n.info, "proposition expected") + else: + n[1] = c.semExpr(c, n[1]) + +proc pragmaEnsures(c: PContext, n: PNode) = + if n.kind notin nkPragmaCallKinds or n.len != 2: + localError(c.config, n.info, "proposition expected") + else: + openScope(c) + let o = getCurrOwner(c) + if o.kind in routineKinds and o.typ != nil and o.typ.sons[0] != nil: + var s = newSym(skResult, getIdent(c.cache, "result"), o, n.info) + s.typ = o.typ.sons[0] + incl(s.flags, sfUsed) + addDecl(c, s) + n[1] = c.semExpr(c, n[1]) + closeScope(c) + proc pragmaAsm*(c: PContext, n: PNode): char = result = '\0' if n != nil: @@ -1146,6 +1169,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if sym == nil: invalidPragma(c, it) else: sym.flags.incl sfUsed of wLiftLocals: discard + of wRequires, wInvariant, wAssume: + pragmaProposition(c, it) + of wEnsures: + pragmaEnsures(c, it) else: invalidPragma(c, it) elif comesFromPush and whichKeyword(ident) != wInvalid: discard "ignore the .push pragma; it doesn't apply" diff --git a/compiler/semcall.nim b/compiler/semcall.nim index d8834dc90..321745c82 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -128,7 +128,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, else: break -proc effectProblem(f, a: PType; result: var string) = +proc effectProblem(f, a: PType; result: var string; c: PContext) = if f.kind == tyProc and a.kind == tyProc: if tfThread in f.flags and tfThread notin a.flags: result.add "\n This expression is not GC-safe. Annotate the " & @@ -152,7 +152,9 @@ proc effectProblem(f, a: PType; result: var string) = of efLockLevelsDiffer: result.add "\n The `.locks` requirements differ. Annotate the " & "proc with {.locks: 0.} to get extended error information." - + when defined(drnim): + if not c.graph.compatibleProps(c.graph, f, a): + result.add "\n The `.requires` or `.ensures` properties are incompatible." proc renderNotLValue(n: PNode): string = result = $n @@ -238,7 +240,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): var got = nArg.typ candidates.add typeToString(got) doAssert wanted != nil - if got != nil: effectProblem(wanted, got, candidates) + if got != nil: effectProblem(wanted, got, candidates, c) of kUnknown: discard "do not break 'nim check'" candidates.add "\n" if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index af80b3ca3..8c07d7d18 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -428,6 +428,27 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym result.typ = newProcType(result.info, result) result.typ.addParam newParam +proc semQuantifier(c: PContext; n: PNode): PNode = + checkMinSonsLen(n, 2, c.config) + openScope(c) + for i in 0..n.len-2: + let v = newSymS(skForVar, n[i], c) + styleCheckDef(c.config, v) + onDef(n.info, v) + n[i] = newSymNode(v) + addDecl(c, v) + n[^1] = forceBool(c, semExprWithType(c, n[^1])) + closeScope(c) + +proc semOld(c: PContext; n: PNode): PNode = + if n[1].kind == nkHiddenDeref: + n[1] = n[1][0] + if n[1].kind != nkSym or n[1].sym.kind != skParam: + localError(c.config, n[1].info, "'old' takes a parameter name") + elif n[1].sym.owner != getCurrOwner(c): + localError(c.config, n[1].info, n[1].sym.name.s & " does not belong to " & getCurrOwner(c).name.s) + result = n + proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = ## This is the preferred code point to implement magics. @@ -505,4 +526,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result[0] = newSymNode(t.destructor) of mUnown: result = semUnown(c, n) + of mExists, mForall: + result = semQuantifier(c, n) + of mOld: + result = semOld(c, n) else: result = n diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index c8ad14c41..4658f5454 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -565,6 +565,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) elif tfNoSideEffect notin op.flags: markSideEffect(tracked, a) if paramType != nil and paramType.kind == tyVar: + invalidateFacts(tracked.guards, n) if n.kind == nkSym and isLocalVar(tracked, n.sym): makeVolatile(tracked, n.sym) if paramType != nil and paramType.kind == tyProc and tfGcSafe in paramType.flags: @@ -675,28 +676,75 @@ proc cstringCheck(tracked: PEffects; n: PNode) = a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}): message(tracked.config, n.info, warnUnsafeCode, renderTree(n)) +proc prove(c: PEffects; prop: PNode): bool = + if c.graph.proofEngine != nil: + let (success, m) = c.graph.proofEngine(c.graph, c.guards.s, + canon(prop, c.guards.o)) + if not success: + message(c.config, prop.info, warnStaticIndexCheck, "cannot prove: " & $prop & m) + result = success + +proc patchResult(c: PEffects; n: PNode) = + if n.kind == nkSym and n.sym.kind == skResult: + let fn = c.owner + if fn != nil and fn.kind in routineKinds and fn.ast != nil and resultPos < fn.ast.len: + n.sym = fn.ast[resultPos].sym + else: + localError(c.config, n.info, "routine has no return type, but .requires contains 'result'") + else: + for i in 0.. " & $b) + if c.graph.proofEngine != nil: + var cmpOp = mLeI + if a.typ != nil: + case a.typ.skipTypes(abstractInst).kind + of tyFloat..tyFloat128: cmpOp = mLeF64 + of tyChar, tyUInt..tyUInt64: cmpOp = mLeU + else: discard + + let cmp = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), a, b) + cmp.info = a.info + discard prove(c, cmp) + else: + case proveLe(c.guards, a, b) + of impUnknown: + #for g in c.guards.s: + # if g != nil: echo "I Know ", g + message(c.config, a.info, warnStaticIndexCheck, + "cannot prove: " & $a & " <= " & $b) + of impYes: + discard + of impNo: + message(c.config, a.info, warnStaticIndexCheck, + "can prove: " & $a & " > " & $b) proc checkBounds(c: PEffects; arr, idx: PNode) = checkLe(c, lowBound(c.config, arr), idx) checkLe(c, idx, highBound(c.config, arr, c.guards.o)) proc checkRange(c: PEffects; value: PNode; typ: PType) = - if typ.skipTypes(abstractInst - {tyRange}).kind == tyRange: - let lowBound = nkIntLit.newIntNode(firstOrd(c.config, typ)) + let t = typ.skipTypes(abstractInst - {tyRange}) + if t.kind == tyRange: + let lowBound = copyTree(t.n[0]) lowBound.info = value.info - let highBound = nkIntLit.newIntNode(lastOrd(c.config, typ)) + let highBound = copyTree(t.n[1]) highBound.info = value.info checkLe(c, lowBound, value) checkLe(c, value, highBound) @@ -783,6 +831,7 @@ proc track(tracked: PEffects, n: PNode) = mergeEffects(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) gcsafeAndSideeffectCheck() + requiresCheck(tracked, n, op) if a.kind != nkSym or a.sym.magic != mNBindSym: for i in 1.. disp.typ.lockLevel: when true: message(g.config, branch.info, warnLockLevel, @@ -1088,14 +1149,22 @@ proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) = let tagsSpec = effectSpec(n, wTags) if not isNil(tagsSpec): effects[tagEffects] = tagsSpec + + let requiresSpec = propSpec(n, wRequires) + if not isNil(requiresSpec): + effects[requiresEffects] = requiresSpec + let ensuresSpec = propSpec(n, wEnsures) + if not isNil(ensuresSpec): + effects[ensuresEffects] = ensuresSpec + effects[pragmasEffects] = n proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) = newSeq(effects.sons, effectListLen) effects[exceptionEffects] = newNodeI(nkArgList, s.info) effects[tagEffects] = newNodeI(nkArgList, s.info) - effects[usesEffects] = g.emptyNode - effects[writeEffects] = g.emptyNode + effects[requiresEffects] = g.emptyNode + effects[ensuresEffects] = g.emptyNode effects[pragmasEffects] = g.emptyNode t.exc = effects[exceptionEffects] @@ -1155,6 +1224,15 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = # after the check, use the formal spec: effects[tagEffects] = tagsSpec + let requiresSpec = propSpec(p, wRequires) + if not isNil(requiresSpec): + effects[requiresEffects] = requiresSpec + let ensuresSpec = propSpec(p, wEnsures) + if not isNil(ensuresSpec): + patchResult(t, ensuresSpec) + effects[ensuresEffects] = ensuresSpec + discard prove(t, ensuresSpec) + if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: #localError(s.info, "'$1' is not GC-safe" % s.name.s) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d99a02183..b45c42fe1 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1930,7 +1930,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if n[pragmasPos].kind != nkEmpty: pragma(c, s, n[pragmasPos], validPragmas) # To ease macro generation that produce forwarded .async procs we now - # allow a bit redudancy in the pragma declarations. The rule is + # allow a bit redundancy in the pragma declarations. The rule is # a prototype's pragma list must be a superset of the current pragma # list. # XXX This needs more checks eventually, for example that external diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4f05282a3..79b3ea94c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -646,6 +646,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = return isNone when useEffectSystem: if compatibleEffects(f, a) != efCompat: return isNone + when defined(drnim): + if not c.c.graph.compatibleProps(c.c.graph, f, a): return isNone of tyNil: result = f.allowsNil diff --git a/compiler/trees.nim b/compiler/trees.nim index 9a1186a4f..455bf5301 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -148,6 +148,12 @@ proc effectSpec*(n: PNode, effectType: TSpecialWord): PNode = result.add(it[1]) return +proc propSpec*(n: PNode, effectType: TSpecialWord): PNode = + for i in 0..`_ proof +engine in order to allow verify / validate software written in Nim. +DrNim's command line options are the same as the Nim compiler's. + + +DrNim currently only checks the sections of your code that are marked +via ``staticBoundChecks: on``: + +.. code-block:: nim + + {.push staticBoundChecks: on.} + # <--- code section here ----> + {.pop.} + +DrNim currently only tries to prove array indexing or subrange checks, +overflow errors are *not* prevented. Overflows will be checked for in +the future. + +Later versions of the **Nim compiler** will **assume** that the checks inside +the ``staticBoundChecks: on`` environment have been proven correct and so +it will **omit** the runtime checks. If you do not want this behavior, use +instead ``{.push staticBoundChecks: defined(nimDrNim).}``. This way the +Nim compiler remains unaware of the performed proofs but DrNim will prove +your code. + + +Installation +============ + +Run ``koch drnim``, the executable will afterwards be in ``$nim/bin/drnim``. + + +Motivating Example +================== + +The follow example highlights what DrNim can easily do, even +without additional annotations: + +.. code-block:: nim + + {.push staticBoundChecks: on.} + + proc sum(a: openArray[int]): int = + for i in 0..a.len: + result += a[i] + + {.pop.} + + echo sum([1, 2, 3]) + +This program contains a famous "index out of bounds" bug. DrNim +detects it and produces the following error message:: + + cannot prove: i <= len(a) + -1; counter example: i -> 0 a.len -> 0 [IndexCheck] + +In other words for ``i == 0`` and ``a.len == 0`` (for example!) there would be +an index out of bounds error. + + +Pre-, postconditions and invariants +=================================== + +DrNim adds 4 additional annotations (pragmas) to Nim: + +- `requires`:idx: +- `ensures`:idx: +- `invariant`:idx: +- `assume`:idx: + +These pragmas are ignored by the Nim compiler so that they don't have to +be disabled via ``when defined(nimDrNim)``. + + +Invariant +--------- + +An ``invariant`` is a proposition that must be true after every loop +iteration, it's tied to the loop body it's part of. + + +Requires +-------- + +A ``requires`` annotation describes what the function expects to be true +before it's called so that it can perform its operation. A ``requires`` +annotation is also called a `precondition`:idx:. + + +Ensures +------- + +An ``ensures`` annotation describes what will be true after the function +call. An ``ensures`` annotation is also called a `postcondition`:idx:. + + +Assume +------ + +An ``assume`` annotation describes what DrNim should **assume** to be true +in this section of the program. It is an unsafe escape mechanism comparable +to Nim's ``cast`` statement. Use it only when you really know better +than DrNim. You should add a comment to a paper that proves the proposition +you assume. + + +Example: insertionSort +====================== + +**Note**: This example does not yet work with DrNim. ``forall`` and ``exists`` +are not implemented. + +.. code-block:: nim + + import std / logic + + proc insertionSort(a: var openArray[int]) {. + ensures: forall(i in 1.. 0 and a[t-1] > a[t]: + {.invariant: k < a.len.} + {.invariant: 0 <= t and t <= k.} + {.invariant: forall(j in 1..k, i in 0..``. +A ``prop`` is either a comparison or a compound:: + + prop = nim_bool_expression + | prop 'and' prop + | prop 'or' prop + | prop '->' prop # implication + | prop '<->' prop + | 'not' prop + | '(' prop ')' # you can group props via () + | forallProp + | existsProp + + forallProp = 'forall' '(' quantifierList ',' prop ')' + existsProp = 'exists' '(' quantifierList ',' prop ')' + + quantifierList = quantifier (',' quantifier)* + quantifier = 'in' nim_iteration_expression + + +``nim_iteration_expression`` here is an ordinary expression of Nim code +that describes an iteration space, for example ``1..4`` or ``1.. a.len``. + +The supported subset of Nim code that can be used in these expressions +is currently underspecified but ``let`` variables, function parameters +and ``result`` (which represents the function's final result) are amenable +for verification. The expressions must not have any side-effects and must +terminate. + +The operators ``forall``, ``exists``, ``->``, ``<->`` have to imported +from ``std / logic``. diff --git a/drnim/drnim.nim b/drnim/drnim.nim new file mode 100644 index 000000000..e814496e4 --- /dev/null +++ b/drnim/drnim.nim @@ -0,0 +1,675 @@ +# +# +# Doctor Nim +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +#[ + +- Most important bug: + + while i < x.len and use(s[i]): inc i # is safe + +- We need to map arrays to Z3 and test for something like 'forall(i, (i in 3..4) -> (a[i] > 3))' +- forall/exists need syntactic sugar as the manual +- We need teach DrNim what 'inc', 'dec' and 'swap' mean, for example + 'x in n..m; inc x' implies 'x in n+1..m+1' + +- We need an ``old`` annotation: + +proc f(x: var int; y: var int) {.ensures: x == old(x)+1 and y == old(y)+1 .} = + inc x + inc y + +var x = 3 +var y: range[N..M] +f(x, y) +{.assume: y in N+1 .. M+1.} +# --> y in N+1..M+1 + +proc myinc(x: var int) {.ensures: x-1 == old(x).} = + inc x + +facts(x) # x < 3 +myinc x +facts(x+1) + +We handle state transitions in this way: + + for every f in facts: + replace 'x' by 'old(x)' + facts.add ensuresClause + + # then we know: old(x) < 3; x-1 == old(x) + # we can conclude: x-1 < 3 but leave this task to Z3 + +]# + +import std / [ + parseopt, strutils, os, tables, times +] + +import ".." / compiler / [ + ast, types, renderer, + commands, options, msgs, + platform, + idents, lineinfos, cmdlinehelper, modulegraphs, condsyms, + pathutils, passes, passaux, sem, modules +] + +import z3 / z3_api + +when not defined(windows): + # on UNIX we use static linking because UNIX's lib*.so system is broken + # beyond repair and the neckbeards don't understand software development. + {.passL: "dist/z3/build/libz3.a".} + +const + HelpMessage = "DrNim Version $1 [$2: $3]\n" & + "Compiled at $4\n" & + "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" + +const + Usage = """ +drnim [options] [projectfile] + +Options: Same options that the Nim compiler supports. +""" + +proc getCommandLineDesc(conf: ConfigRef): string = + result = (HelpMessage % [system.NimVersion, platform.OS[conf.target.hostOS].name, + CPU[conf.target.hostCPU].name, CompileDate]) & + Usage + +proc helpOnError(conf: ConfigRef) = + msgWriteln(conf, getCommandLineDesc(conf), {msgStdout}) + msgQuit(0) + +type + CannotMapToZ3Error = object of ValueError + Z3Exception = object of ValueError + + DrCon = object + z3: Z3_context + graph: ModuleGraph + mapping: Table[string, Z3_ast] + canonParameterNames: bool + +proc stableName(result: var string; n: PNode) = + # we can map full Nim expressions like 'f(a, b, c)' to Z3 variables. + # We must be carefult to select a unique, stable name for these expressions + # based on structural equality. 'stableName' helps us with this problem. + case n.kind + of nkEmpty, nkNilLit, nkType: discard + of nkIdent: + result.add n.ident.s + of nkSym: + result.add n.sym.name.s + result.add '_' + result.addInt n.sym.id + of nkCharLit..nkUInt64Lit: + result.addInt n.intVal + of nkFloatLit..nkFloat64Lit: + result.addFloat n.floatVal + of nkStrLit..nkTripleStrLit: + result.add strutils.escape n.strVal + else: + result.add $n.kind + result.add '(' + for i in 0.. 0: result.add ", " + stableName(result, n[i]) + result.add ')' + +proc stableName(n: PNode): string = stableName(result, n) + +proc notImplemented(msg: string) {.noinline.} = + raise newException(CannotMapToZ3Error, "; cannot map to Z3: " & msg) + +proc translateEnsures(e, x: PNode): PNode = + if e.kind == nkSym and e.sym.kind == skResult: + result = x + else: + result = shallowCopy(e) + for i in 0 ..< safeLen(e): + result[i] = translateEnsures(e[i], x) + +proc typeToZ3(c: DrCon; t: PType): Z3_sort = + template ctx: untyped = c.z3 + case t.skipTypes(abstractInst+{tyVar}).kind + of tyEnum, tyInt..tyInt64: + result = Z3_mk_int_sort(ctx) + of tyBool: + result = Z3_mk_bool_sort(ctx) + of tyFloat..tyFloat128: + result = Z3_mk_fpa_sort_double(ctx) + of tyChar, tyUInt..tyUInt64: + result = Z3_mk_bv_sort(ctx, 64) + #cuint(getSize(c.graph.config, t) * 8)) + else: + notImplemented(typeToString(t)) + +template binary(op, a, b): untyped = + var arr = [a, b] + op(ctx, cuint(2), addr(arr[0])) + +proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast + +template quantorToZ3(fn) {.dirty.} = + template ctx: untyped = c.z3 + + var bound = newSeq[Z3_app](n.len-1) + for i in 0..n.len-2: + doAssert n[i].kind == nkSym + let v = n[i].sym + let name = Z3_mk_string_symbol(ctx, v.name.s) + let vz3 = Z3_mk_const(ctx, name, typeToZ3(c, v.typ)) + c.mapping[stableName(n[i])] = vz3 + bound[i] = Z3_to_app(ctx, vz3) + + var dummy: seq[PNode] + let x = nodeToZ3(c, n[^1], dummy) + result = fn(ctx, 0, bound.len.cuint, addr(bound[0]), 0, nil, x) + +proc forallToZ3(c: var DrCon; n: PNode): Z3_ast = quantorToZ3(Z3_mk_forall_const) +proc existsToZ3(c: var DrCon; n: PNode): Z3_ast = quantorToZ3(Z3_mk_exists_const) + +proc paramName(n: PNode): string = + case n.sym.kind + of skParam: result = "arg" & $n.sym.position + of skResult: result = "result" + else: result = stableName(n) + +proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = + template ctx: untyped = c.z3 + template rec(n): untyped = nodeToZ3(c, n, vars) + case n.kind + of nkSym: + let key = if c.canonParameterNames: paramName(n) else: stableName(n) + result = c.mapping.getOrDefault(key) + if pointer(result) == nil: + let name = Z3_mk_string_symbol(ctx, n.sym.name.s) + result = Z3_mk_const(ctx, name, typeToZ3(c, n.sym.typ)) + c.mapping[key] = result + vars.add n + of nkCharLit..nkUInt64Lit: + if n.typ != nil and n.typ.skipTypes(abstractInst).kind in {tyInt..tyInt64}: + # optimized for the common case + result = Z3_mk_int64(ctx, clonglong(n.intval), Z3_mk_int_sort(ctx)) + elif n.typ != nil and n.typ.kind == tyBool: + result = if n.intval != 0: Z3_mk_true(ctx) else: Z3_mk_false(ctx) + elif n.typ != nil and isUnsigned(n.typ): + result = Z3_mk_unsigned_int64(ctx, cast[uint64](n.intVal), typeToZ3(c, n.typ)) + else: + let zt = if n.typ == nil: Z3_mk_int_sort(ctx) else: typeToZ3(c, n.typ) + result = Z3_mk_numeral(ctx, $getOrdValue(n), zt) + of nkFloatLit..nkFloat64Lit: + result = Z3_mk_fpa_numeral_double(ctx, n.floatVal, Z3_mk_fpa_sort_double(ctx)) + of nkCallKinds: + assert n.len > 0 + assert n[0].kind == nkSym + let operator = n[0].sym.magic + case operator + of mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, + mEqStr, mEqSet, mEqCString: + result = Z3_mk_eq(ctx, rec n[1], rec n[2]) + of mLeI, mLeEnum, mLeCh, mLeB, mLePtr, mLeStr: + result = Z3_mk_le(ctx, rec n[1], rec n[2]) + of mLtI, mLtEnum, mLtCh, mLtB, mLtPtr, mLtStr: + result = Z3_mk_lt(ctx, rec n[1], rec n[2]) + of mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq: + # len(x) needs the same logic as 'x' itself + if n[1].kind == nkSym: + let key = stableName(n) + let sym = n[1].sym + result = c.mapping.getOrDefault(key) + if pointer(result) == nil: + let name = Z3_mk_string_symbol(ctx, sym.name.s & ".len") + result = Z3_mk_const(ctx, name, Z3_mk_int_sort(ctx)) + c.mapping[key] = result + vars.add n + else: + notImplemented(renderTree(n)) + of mAddI, mSucc: + result = binary(Z3_mk_add, rec n[1], rec n[2]) + of mSubI, mPred: + result = binary(Z3_mk_sub, rec n[1], rec n[2]) + of mMulI: + result = binary(Z3_mk_mul, rec n[1], rec n[2]) + of mDivI: + result = Z3_mk_div(ctx, rec n[1], rec n[2]) + of mModI: + result = Z3_mk_mod(ctx, rec n[1], rec n[2]) + of mMaxI: + # max(a, b) <=> ite(a < b, b, a) + result = Z3_mk_ite(ctx, Z3_mk_lt(ctx, rec n[1], rec n[2]), + rec n[2], rec n[1]) + of mMinI: + # min(a, b) <=> ite(a < b, a, b) + result = Z3_mk_ite(ctx, Z3_mk_lt(ctx, rec n[1], rec n[2]), + rec n[1], rec n[2]) + of mLeU: + result = Z3_mk_bvule(ctx, rec n[1], rec n[2]) + of mLtU: + result = Z3_mk_bvult(ctx, rec n[1], rec n[2]) + of mAnd: + result = binary(Z3_mk_and, rec n[1], rec n[2]) + of mOr: + result = binary(Z3_mk_or, rec n[1], rec n[2]) + of mXor: + result = Z3_mk_xor(ctx, rec n[1], rec n[2]) + of mNot: + result = Z3_mk_not(ctx, rec n[1]) + of mImplies: + result = Z3_mk_implies(ctx, rec n[1], rec n[2]) + of mIff: + result = Z3_mk_iff(ctx, rec n[1], rec n[2]) + of mForall: + result = forallToZ3(c, n) + of mExists: + result = existsToZ3(c, n) + of mLeF64: + result = Z3_mk_fpa_leq(ctx, rec n[1], rec n[2]) + of mLtF64: + result = Z3_mk_fpa_lt(ctx, rec n[1], rec n[2]) + of mAddF64: + result = Z3_mk_fpa_add(ctx, Z3_mk_fpa_round_nearest_ties_to_even(ctx), rec n[1], rec n[2]) + of mSubF64: + result = Z3_mk_fpa_sub(ctx, Z3_mk_fpa_round_nearest_ties_to_even(ctx), rec n[1], rec n[2]) + of mMulF64: + result = Z3_mk_fpa_mul(ctx, Z3_mk_fpa_round_nearest_ties_to_even(ctx), rec n[1], rec n[2]) + of mDivF64: + result = Z3_mk_fpa_div(ctx, Z3_mk_fpa_round_nearest_ties_to_even(ctx), rec n[1], rec n[2]) + of mShrI: + # XXX handle conversions from int to uint here somehow + result = Z3_mk_bvlshr(ctx, rec n[1], rec n[2]) + of mAshrI: + result = Z3_mk_bvashr(ctx, rec n[1], rec n[2]) + of mShlI: + result = Z3_mk_bvshl(ctx, rec n[1], rec n[2]) + of mBitandI: + result = Z3_mk_bvand(ctx, rec n[1], rec n[2]) + of mBitorI: + result = Z3_mk_bvor(ctx, rec n[1], rec n[2]) + of mBitxorI: + result = Z3_mk_bvxor(ctx, rec n[1], rec n[2]) + of mOrd, mChr: + result = rec n[1] + of mOld: + let key = (if c.canonParameterNames: paramName(n[1]) else: stableName(n[1])) & ".old" + result = c.mapping.getOrDefault(key) + if pointer(result) == nil: + let name = Z3_mk_string_symbol(ctx, $n) + result = Z3_mk_const(ctx, name, typeToZ3(c, n.typ)) + c.mapping[key] = result + # XXX change the logic in `addRangeInfo` for this + #vars.add n + + else: + # sempass2 adds some 'fact' like 'x = f(a, b)' (see addAsgnFact) + # 'f(a, b)' can have an .ensures annotation and we need to make use + # of this information. + # we need to map 'f(a, b)' to a Z3 variable of this name + let op = n[0].typ + if op != nil and op.n != nil and op.n.len > 0 and op.n[0].kind == nkEffectList and + ensuresEffects < op.n[0].len: + let ensures = op.n[0][ensuresEffects] + if ensures != nil and ensures.kind != nkEmpty: + let key = stableName(n) + result = c.mapping.getOrDefault(key) + if pointer(result) == nil: + let name = Z3_mk_string_symbol(ctx, $n) + result = Z3_mk_const(ctx, name, typeToZ3(c, n.typ)) + c.mapping[key] = result + vars.add n + + if pointer(result) == nil: + notImplemented(renderTree(n)) + of nkStmtListExpr, nkPar: + var isTrivial = true + for i in 0..n.len-2: + isTrivial = isTrivial and n[i].kind in {nkEmpty, nkCommentStmt} + if isTrivial: + result = nodeToZ3(c, n[^1], vars) + else: + notImplemented(renderTree(n)) + of nkHiddenDeref: + result = rec n[0] + else: + notImplemented(renderTree(n)) + +proc addRangeInfo(c: var DrCon, n: PNode, res: var seq[Z3_ast]) = + var cmpOp = mLeI + if n.typ != nil: + cmpOp = + case n.typ.skipTypes(abstractInst).kind + of tyFloat..tyFloat128: mLeF64 + of tyChar, tyUInt..tyUInt64: mLeU + else: mLeI + + var lowBound, highBound: PNode + if n.kind == nkSym: + let v = n.sym + let t = v.typ.skipTypes(abstractInst - {tyRange}) + + case t.kind + of tyRange: + lowBound = t.n[0] + highBound = t.n[1] + of tyFloat..tyFloat128: + # no range information for non-range'd floats + return + of tyUInt..tyUInt64, tyChar: + lowBound = newIntNode(nkUInt64Lit, firstOrd(nil, v.typ)) + lowBound.typ = v.typ + highBound = newIntNode(nkUInt64Lit, lastOrd(nil, v.typ)) + highBound.typ = v.typ + of tyInt..tyInt64, tyEnum: + lowBound = newIntNode(nkInt64Lit, firstOrd(nil, v.typ)) + highBound = newIntNode(nkInt64Lit, lastOrd(nil, v.typ)) + else: + # no range information available: + return + elif n.kind in nkCallKinds and n.len == 2 and n[0].kind == nkSym and + n[0].sym.magic in {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}: + # we know it's a 'len(x)' expression and we seek to teach + # Z3 that the result is >= 0 and <= high(int). + doAssert n.kind in nkCallKinds + doAssert n[0].kind == nkSym + doAssert n.len == 2 + + lowBound = newIntNode(nkInt64Lit, 0) + if n.typ != nil: + highBound = newIntNode(nkInt64Lit, lastOrd(nil, n.typ)) + else: + highBound = newIntNode(nkInt64Lit, high(int64)) + else: + let op = n[0].typ + if op != nil and op.n != nil and op.n.len > 0 and op.n[0].kind == nkEffectList and + ensuresEffects < op.n[0].len: + let ensures = op.n[0][ensuresEffects] + if ensures != nil and ensures.kind != nkEmpty: + var dummy: seq[PNode] + res.add nodeToZ3(c, translateEnsures(ensures, n), dummy) + return + + let x = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), lowBound, n) + let y = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), n, highBound) + + var dummy: seq[PNode] + res.add nodeToZ3(c, x, dummy) + res.add nodeToZ3(c, y, dummy) + +proc on_err(ctx: Z3_context, e: Z3_error_code) {.nimcall.} = + #writeStackTrace() + let msg = $Z3_get_error_msg(ctx, e) + raise newException(Z3Exception, msg) + +proc forall(ctx: Z3_context; vars: seq[Z3_ast]; assumption, body: Z3_ast): Z3_ast = + let x = Z3_mk_implies(ctx, assumption, body) + if vars.len > 0: + var bound: seq[Z3_app] + for v in vars: bound.add Z3_to_app(ctx, v) + result = Z3_mk_forall_const(ctx, 0, bound.len.cuint, addr(bound[0]), 0, nil, x) + else: + result = x + +proc conj(ctx: Z3_context; conds: seq[Z3_ast]): Z3_ast = + if conds.len > 0: + result = Z3_mk_and(ctx, cuint(conds.len), unsafeAddr conds[0]) + else: + result = Z3_mk_true(ctx) + +proc proofEngineAux(c: var DrCon; assumptions: seq[PNode]; toProve: PNode): (bool, string) = + c.mapping = initTable[string, Z3_ast]() + let cfg = Z3_mk_config() + Z3_set_param_value(cfg, "model", "true"); + let ctx = Z3_mk_context(cfg) + c.z3 = ctx + Z3_del_config(cfg) + Z3_set_error_handler(ctx, on_err) + + when false: + Z3_set_param_value(cfg, "timeout", "1000") + + try: + + #[ + For example, let's have these facts: + + i < 10 + i > 0 + + Question: + + i + 3 < 13 + + What we need to produce: + + forall(i, (i < 10) & (i > 0) -> (i + 3 < 13)) + + ]# + + var collectedVars: seq[PNode] + + let solver = Z3_mk_solver(ctx) + var lhs: seq[Z3_ast] + for assumption in assumptions: + if assumption != nil: + try: + let za = nodeToZ3(c, assumption, collectedVars) + #Z3_solver_assert ctx, solver, za + lhs.add za + except CannotMapToZ3Error: + discard "ignore a fact we cannot map to Z3" + + let z3toProve = nodeToZ3(c, toProve, collectedVars) + for v in collectedVars: + addRangeInfo(c, v, lhs) + + # to make Z3 produce nice counterexamples, we try to prove the + # negation of our conjecture and see if it's Z3_L_FALSE + let fa = Z3_mk_not(ctx, Z3_mk_implies(ctx, conj(ctx, lhs), z3toProve)) + + #Z3_mk_not(ctx, forall(ctx, collectedVars, conj(ctx, lhs), z3toProve)) + + #echo "toProve: ", Z3_ast_to_string(ctx, fa), " ", c.graph.config $ toProve.info + Z3_solver_assert ctx, solver, fa + + let z3res = Z3_solver_check(ctx, solver) + result[0] = z3res == Z3_L_FALSE + result[1] = "" + if not result[0]: + let counterex = strip($Z3_model_to_string(ctx, Z3_solver_get_model(ctx, solver))) + if counterex.len > 0: + result[1].add "; counter example: " & counterex + except ValueError: + result[0] = false + result[1] = getCurrentExceptionMsg() + finally: + Z3_del_context(ctx) + +proc proofEngine(graph: ModuleGraph; assumptions: seq[PNode]; toProve: PNode): (bool, string) = + var c: DrCon + c.graph = graph + result = proofEngineAux(c, assumptions, toProve) + +proc translateReq(r, call: PNode): PNode = + if r.kind == nkSym and r.sym.kind == skParam: + if r.sym.position+1 < call.len: + result = call[r.sym.position+1] + else: + notImplemented("no argument given for formal parameter: " & r.sym.name.s) + else: + result = shallowCopy(r) + for i in 0 ..< safeLen(r): + result[i] = translateReq(r[i], call) + +proc requirementsCheck(graph: ModuleGraph; assumptions: seq[PNode]; + call, requirement: PNode): (bool, string) {.nimcall.} = + try: + let r = translateReq(requirement, call) + result = proofEngine(graph, assumptions, r) + except ValueError: + result[0] = false + result[1] = getCurrentExceptionMsg() + +proc compatibleProps(graph: ModuleGraph; formal, actual: PType): bool {.nimcall.} = + #[ + Thoughts on subtyping rules for 'proc' types: + + proc a(y: int) {.requires: y > 0.} # a is 'weaker' than F + # 'requires' must be weaker (or equal) + # 'ensures' must be stronger (or equal) + + # a 'is weaker than' b iff b -> a + # a 'is stronger than' b iff a -> b + # --> We can use Z3 to compute whether 'var x: T = q' is valid + + type + F = proc (y: int) {.requires: y > 5.} + + var + x: F = a # valid? + ]# + proc isEmpty(n: PNode): bool {.inline.} = n == nil or n.safeLen == 0 + + result = true + if formal.n != nil and formal.n.len > 0 and formal.n[0].kind == nkEffectList and + ensuresEffects < formal.n[0].len: + + let frequires = formal.n[0][requiresEffects] + let fensures = formal.n[0][ensuresEffects] + + if actual.n != nil and actual.n.len > 0 and actual.n[0].kind == nkEffectList and + ensuresEffects < actual.n[0].len: + let arequires = actual.n[0][requiresEffects] + let aensures = actual.n[0][ensuresEffects] + + var c: DrCon + c.graph = graph + c.canonParameterNames = true + if not frequires.isEmpty: + result = not arequires.isEmpty and proofEngineAux(c, @[frequires], arequires)[0] + + if result: + if not fensures.isEmpty: + result = not aensures.isEmpty and proofEngineAux(c, @[aensures], fensures)[0] + else: + # formal has requirements but 'actual' has none, so make it + # incompatible. XXX What if the requirement only mentions that + # we already know from the type system? + result = frequires.isEmpty and fensures.isEmpty + +proc mainCommand(graph: ModuleGraph) = + let conf = graph.config + conf.lastCmdTime = epochTime() + + graph.proofEngine = proofEngine + graph.requirementsCheck = requirementsCheck + graph.compatibleProps = compatibleProps + + graph.config.errorMax = high(int) # do not stop after first error + defineSymbol(graph.config.symbols, "nimcheck") + defineSymbol(graph.config.symbols, "nimDrNim") + + registerPass graph, verbosePass + registerPass graph, semPass + compileProject(graph) + if conf.errorCounter == 0: + let mem = + when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" + else: formatSize(getTotalMem()) & " totmem" + let loc = $conf.linesCompiled + let build = if isDefined(conf, "danger"): "Dangerous Release" + elif isDefined(conf, "release"): "Release" + else: "Debug" + let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) + let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName + var output = $conf.absOutFile + if optListFullPaths notin conf.globalOptions: output = output.AbsoluteFile.extractFilename + rawMessage(conf, hintSuccessX, [ + "loc", loc, + "sec", sec, + "mem", mem, + "build", build, + "project", project, + "output", output, + ]) + +proc prependCurDir(f: AbsoluteFile): AbsoluteFile = + when defined(unix): + if os.isAbsolute(f.string): result = f + else: result = AbsoluteFile("./" & f.string) + else: + result = f + +proc addCmdPrefix(result: var string, kind: CmdLineKind) = + # consider moving this to std/parseopt + case kind + of cmdLongOption: result.add "--" + of cmdShortOption: result.add "-" + of cmdArgument, cmdEnd: discard + +proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = + var p = parseopt.initOptParser(cmd) + var argsCount = 1 + + config.commandLine.setLen 0 + config.command = "check" + config.cmd = cmdCheck + + while true: + parseopt.next(p) + case p.kind + of cmdEnd: break + of cmdLongOption, cmdShortOption: + config.commandLine.add " " + config.commandLine.addCmdPrefix p.kind + config.commandLine.add p.key.quoteShell # quoteShell to be future proof + if p.val.len > 0: + config.commandLine.add ':' + config.commandLine.add p.val.quoteShell + + if p.key == " ": + p.key = "-" + if processArgument(pass, p, argsCount, config): break + else: + processSwitch(pass, p, config) + of cmdArgument: + config.commandLine.add " " + config.commandLine.add p.key.quoteShell + if processArgument(pass, p, argsCount, config): break + if pass == passCmd2: + if {optRun, optWasNimscript} * config.globalOptions == {} and + config.arguments.len > 0 and config.command.normalize notin ["run", "e"]: + rawMessage(config, errGenerated, errArgsNeedRunOption) + +proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = + let self = NimProg( + supportsStdinFile: true, + processCmdLine: processCmdLine, + mainCommand: mainCommand + ) + self.initDefinesProg(conf, "drnim") + if paramCount() == 0: + helpOnError(conf) + return + + self.processCmdLineAndProjectPath(conf) + if not self.loadConfigsAndRunMainCommand(cache, conf): return + if conf.hasHint(hintGCStats): echo(GC_getStatistics()) + +when compileOption("gc", "v2") or compileOption("gc", "refc"): + # the new correct mark&sweep collector is too slow :-/ + GC_disableMarkAndSweep() + +when not defined(selftest): + let conf = newConfigRef() + handleCmdLine(newIdentCache(), conf) + when declared(GC_setMaxPause): + echo GC_getStatistics() + msgQuit(int8(conf.errorCounter > 0)) diff --git a/drnim/nim.cfg b/drnim/nim.cfg new file mode 100644 index 000000000..58c1725d9 --- /dev/null +++ b/drnim/nim.cfg @@ -0,0 +1,18 @@ +# Special configuration file for the Nim project + +hint[XDeclaredButNotUsed]:off + +define:booting +define:nimcore +define:drnim + +@if windows: + cincludes: "$lib/wrappers/libffi/common" +@end + +define:useStdoutAsStdmsg + +--path: "../../nimz3/src" +--path: "../dist/nimz3/src" + +#define:useNodeIds diff --git a/drnim/tests/config.nims b/drnim/tests/config.nims new file mode 100644 index 000000000..cd4ee4b08 --- /dev/null +++ b/drnim/tests/config.nims @@ -0,0 +1,7 @@ +switch("path", "$nim/testament/lib") # so we can `import stdtest/foo` in this dir + +## prevent common user config settings to interfere with testament expectations +## Indifidual tests can override this if needed to test for these options. +switch("colors", "off") +switch("listFullPaths", "off") +switch("excessiveStackTrace", "off") diff --git a/drnim/tests/tbasic_array_index.nim b/drnim/tests/tbasic_array_index.nim new file mode 100644 index 000000000..3f24ed3bd --- /dev/null +++ b/drnim/tests/tbasic_array_index.nim @@ -0,0 +1,43 @@ +discard """ + nimout: '''tbasic_array_index.nim(26, 17) Warning: cannot prove: 0 <= len(a) - 4; counter example: a.len -> 0 [IndexCheck] +tbasic_array_index.nim(32, 5) Warning: cannot prove: 4.0 <= 1.0 [IndexCheck] +tbasic_array_index.nim(38, 36) Warning: cannot prove: a <= 10'u32; counter example: a -> #x000000000000000b +''' + cmd: "drnim $file" + action: "compile" +""" + +{.push staticBoundChecks: defined(nimDrNim).} + +proc takeNat(n: Natural) = + discard + +proc p(a, b: openArray[int]) = + if a.len > 0: + echo a[0] + + for i in 0..a.len-8: + #{.invariant: i < a.len.} + echo a[i] + + for i in 0..min(a.len, b.len)-1: + echo a[i], " ", b[i] + + takeNat(a.len - 4) + +proc r(x: range[0.0..1.0]) = echo x + +proc sum() = + r 1.0 + r 4.0 + +proc ru(x: range[1u32..10u32]) = echo x + +proc xu(a: uint) = + if a >= 4u: + let chunk = range[1u32..10u32](a) + ru chunk + +{.pop.} + +p([1, 2, 3], [4, 5]) diff --git a/drnim/tests/tensures.nim b/drnim/tests/tensures.nim new file mode 100644 index 000000000..1283b493b --- /dev/null +++ b/drnim/tests/tensures.nim @@ -0,0 +1,31 @@ +discard """ + nimout: '''tensures.nim(11, 10) Warning: BEGIN [User] +tensures.nim(20, 5) Warning: cannot prove: +0 < n [IndexCheck] +tensures.nim(30, 10) Warning: END [User]''' + cmd: "drnim $file" + action: "compile" +""" + +{.push staticBoundChecks: defined(nimDrNim).} +{.warning: "BEGIN".} + +proc fac(n: int) {.requires: n > 0.} = + discard + +proc g(): int {.ensures: result > 0.} = + result = 10 + +fac 7 # fine +fac -45 # wrong + +fac g() # fine + +proc main = + var x = g() + fac x + +main() + +{.warning: "END".} +{.pop.} diff --git a/drnim/tests/tsetlen_invalidates.nim b/drnim/tests/tsetlen_invalidates.nim new file mode 100644 index 000000000..03620af10 --- /dev/null +++ b/drnim/tests/tsetlen_invalidates.nim @@ -0,0 +1,22 @@ +discard """ + nimout: ''' +tsetlen_invalidates.nim(15, 12) Warning: cannot prove: 0 <= len(a) + -1; counter example: a.len -> 0 [IndexCheck] +''' + cmd: "drnim $file" + action: "compile" +""" + +{.push staticBoundChecks: defined(nimDrNim).} + +proc p() = + var a = newSeq[int](3) + if a.len > 0: + a.setLen 0 + echo a[0] + + if a.len > 0: + echo a[0] + +{.pop.} + +p() diff --git a/koch.nim b/koch.nim index b05b56916..511b78df6 100644 --- a/koch.nim +++ b/koch.nim @@ -12,6 +12,10 @@ const NimbleStableCommit = "4007b2a778429a978e12307bf13a038029b4c4d9" # master +when not defined(windows): + const + Z3StableCommit = "65de3f748a6812eecd7db7c478d5fc54424d368b" # the version of Z3 that DrNim uses + when defined(gcc) and defined(windows): when defined(x86): {.link: "icons/koch.res".} @@ -473,6 +477,29 @@ proc xtemp(cmd: string) = finally: copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe) +proc buildDrNim(args: string) = + if not dirExists("dist/nimz3"): + exec("git clone https://github.com/zevv/nimz3.git dist/nimz3") + when defined(windows): + if not dirExists("dist/dlls"): + exec("git clone -q https://github.com/nim-lang/dlls.git dist/dlls") + copyExe("dist/dlls/libz3.dll", "bin/libz3.dll") + execFold("build drnim", "nim c -o:$1 $2 drnim/drnim" % ["bin/drnim".exe, args]) + else: + if not dirExists("dist/z3"): + exec("git clone -q https://github.com/Z3Prover/z3.git dist/z3") + withDir("dist/z3"): + exec("git fetch") + exec("git checkout " & Z3StableCommit) + createDir("build") + withDir("build"): + exec("""cmake -DZ3_BUILD_LIBZ3_SHARED=FALSE -G "Unix Makefiles" ../""") + exec("make -j4") + execFold("build drnim", "nim cpp --dynlibOverride=libz3 -o:$1 $2 drnim/drnim" % ["bin/drnim".exe, args]) + # always run the tests for now: + exec("testament/testament".exe & " --nim:" & "drnim".exe & " pat drnim/tests") + + proc hostInfo(): string = "hostOS: $1, hostCPU: $2, int: $3, float: $4, cpuEndian: $5, cwd: $6" % [hostOS, hostCPU, $int.sizeof, $float.sizeof, $cpuEndian, getCurrentDir()] @@ -636,6 +663,7 @@ when isMainModule: of "pushcsource", "pushcsources": pushCsources() of "valgrind": valgrind(op.cmdLineRest) of "c2nim": bundleC2nim(op.cmdLineRest) + of "drnim": buildDrNim(op.cmdLineRest) else: showHelp() break of cmdEnd: break diff --git a/lib/std/logic.nim b/lib/std/logic.nim new file mode 100644 index 000000000..3cc871a6e --- /dev/null +++ b/lib/std/logic.nim @@ -0,0 +1,10 @@ +## This module provides further logic operators like 'forall' and 'exists' +## They are only supported in ``.ensures`` etc pragmas. + +proc `->`*(a, b: bool): bool {.magic: "Implies".} +proc `<->`*(a, b: bool): bool {.magic: "Iff".} + +proc forall*(args: varargs[untyped]): bool {.magic: "Forall".} +proc exists*(args: varargs[untyped]): bool {.magic: "Exists".} + +proc old*[T](x: T): T {.magic: "Old".} diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index a111ec563..c3ac5fc1b 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -115,6 +115,9 @@ const 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22] +when defined(nimHasInvariant): + {.push staticBoundChecks: off.} + proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {.compilerproc.} = # This routine attempt to parse float that can parsed quickly. @@ -236,7 +239,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, # if exponent is greater try to fit extra exponent above 22 by multiplying # integer part is there is space left. let slop = 15 - kdigits - fdigits - if absExponent <= 22 + slop and not expNegative: + if absExponent <= 22 + slop and not expNegative: number = sign * integer.float * powtens[slop] * powtens[absExponent-slop] return i - start @@ -274,6 +277,9 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, else: number = c_strtod(t, nil) +when defined(nimHasInvariant): + {.pop.} # staticBoundChecks + proc nimInt64ToStr(x: int64): string {.compilerRtl.} = result = newStringOfCap(sizeof(x)*4) result.addInt x diff --git a/testament/categories.nim b/testament/categories.nim index c6ebadfca..601e9306e 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -728,12 +728,22 @@ proc processCategory(r: var TResults, cat: Category, proc processPattern(r: var TResults, pattern, options: string; simulate: bool) = var testsRun = 0 - for name in walkPattern(pattern): - if simulate: - echo "Detected test: ", name - else: - var test = makeTest(name, options, Category"pattern") - testSpec r, test - inc testsRun + if dirExists(pattern): + for k, name in walkDir(pattern): + if k in {pcFile, pcLinkToFile} and name.endsWith(".nim"): + if simulate: + echo "Detected test: ", name + else: + var test = makeTest(name, options, Category"pattern") + testSpec r, test + inc testsRun + else: + for name in walkPattern(pattern): + if simulate: + echo "Detected test: ", name + else: + var test = makeTest(name, options, Category"pattern") + testSpec r, test + inc testsRun if testsRun == 0: echo "no tests were found for pattern: ", pattern diff --git a/testament/testament.nim.cfg b/testament/testament.nim.cfg index 69f044554..f1fcd95f3 100644 --- a/testament/testament.nim.cfg +++ b/testament/testament.nim.cfg @@ -1,2 +1,4 @@ path = "$nim" # For compiler/nodejs -d:ssl # For azure +# my SSL doesn't have this feature and I don't care: +-d:nimDisableCertificateValidation diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 0dd6dbc2f..a23d17b21 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -110,6 +110,7 @@ doc/tut2.rst doc/tut3.rst doc/nimc.rst doc/hcr.rst +doc/drnim.rst doc/overview.rst doc/filters.rst doc/tools.rst From 567af54bafb80a43d72a4e608fae59cac40222fa Mon Sep 17 00:00:00 2001 From: lbartoletti Date: Tue, 31 Mar 2020 22:55:25 +0200 Subject: [PATCH 0237/4254] Add arm/arm64 for FreeBSD (#13822) * Add arm and arm64 for FreeBSD * Add arm64 with aarch64 and reorder to avoid conflict with arm --- compiler/installer.ini | 2 +- tools/niminst/buildsh.nimf | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index f8676ab08..939b328d0 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -9,7 +9,7 @@ Platforms: """ linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64 macosx: i386;amd64;powerpc64 solaris: i386;amd64;sparc;sparc64 - freebsd: i386;amd64;powerpc64 + freebsd: i386;amd64;powerpc64;arm;arm64 netbsd: i386;amd64 openbsd: i386;amd64 dragonfly: i386;amd64 diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 9289feb90..83c4aca6d 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -180,10 +180,10 @@ case $ucpu in ;; *alpha* ) mycpu="alpha" ;; + *aarch64*|*arm64* ) + mycpu="arm64" ;; *arm*|*armv6l*|*armv71* ) mycpu="arm" ;; - *aarch64* ) - mycpu="arm64" ;; *riscv64* ) mycpu="riscv64" ;; *) From 515b6d661e0def97cfe06303fd753b1443fef83e Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 31 Mar 2020 22:59:43 +0200 Subject: [PATCH 0238/4254] Small typo (#13824) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 4c1d5c659..84cf1d8c9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7217,7 +7217,7 @@ This is translated to: This is translated to a call to the ``schema`` macro with a `nnkTypeDef` AST node capturing both the left-hand side and right-hand side of the definition. The macro can return a potentially modified `nnkTypeDef` tree -will replace the original row in the type section. +which will replace the original row in the type section. When multiple macro pragmas are applied to the same definition, the compiler will apply them consequently from left to right. Each macro From fd202136b44271e6cd369eedc5496085e432fd03 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Apr 2020 04:46:59 -0700 Subject: [PATCH 0239/4254] fix #13829 (#13831) --- lib/system/io.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 98d9347be..9a4502cba 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -735,7 +735,7 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] = else: sysFatal(IOError, "cannot open: " & filename) -proc readLines*(filename: string): seq[TaintedString] {.deprecated: "use readLines with two arguments".} = +template readLines*(filename: string): seq[TaintedString] {.deprecated: "use readLines with two arguments".} = readLines(filename, 1) iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = From 48213c742829f3aced3a2949f6b794f344f4b25d Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 1 Apr 2020 11:49:31 +0200 Subject: [PATCH 0240/4254] encodeMIME should be encodeMime by our coding guidelines --- lib/pure/base64.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index b715e749e..9495c4d56 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -182,9 +182,9 @@ proc encode*(s: string, safe = false): string = assert encode("Hello World") == "SGVsbG8gV29ybGQ=" encodeImpl() -proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = +proc encodeMime*(s: string, lineLen = 75, newLine = "\r\n"): string = ## Encodes ``s`` into base64 representation as lines. - ## Used in email MIME forma, use ``lineLen`` and ``newline``. + ## Used in email MIME format, use ``lineLen`` and ``newline``. ## ## This procedure encodes a string according to MIME spec. ## @@ -192,7 +192,7 @@ proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = ## * `encode proc<#encode,string>`_ for encoding a string ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: - assert encodeMIME("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" + assert encodeMime("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" for i, c in encode(s): if i != 0 and (i mod lineLen == 0): result.add(newLine) From c2d29eb3e0c518753ecd27c3809366c36bd2aec4 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 1 Apr 2020 14:10:47 +0200 Subject: [PATCH 0241/4254] updated the changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 78c707bf4..b5eaba7c8 100644 --- a/changelog.md +++ b/changelog.md @@ -14,7 +14,7 @@ ### Breaking changes in the standard library - `base64.encode` no longer supports `lineLen` and `newLine`. - Use `base64.encodeMIME` instead. + Use `base64.encodeMime` instead. - `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" as the dir component of "/root_sub_dir" instead of the empty string. - `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples From d3020af44d57316b3d913962a64a0949714d26f7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Apr 2020 08:48:17 -0700 Subject: [PATCH 0242/4254] fix open file leak when running --debugger:native (#13832) --- compiler/cgen.nim | 5 +++-- compiler/ndi.nim | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e03ddff09..e93465d73 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1924,8 +1924,8 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = # it would generate multiple 'main' procs, for instance. proc writeModule(m: BModule, pending: bool) = + template onExit() = close(m.ndi, m.config) let cfile = getCFile(m) - if true or optForceFullMake in m.config.globalOptions: if moduleHasChanged(m.g.graph, m.module): genInitCode(m) @@ -1943,6 +1943,7 @@ proc writeModule(m: BModule, pending: bool) = when hasTinyCBackend: if conf.cmd == cmdRun: tccgen.compileCCode($code) + onExit() return if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} @@ -1966,7 +1967,7 @@ proc writeModule(m: BModule, pending: bool) = obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) if not fileExists(cf.obj): cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) - close(m.ndi) + onExit() proc updateCachedModule(m: BModule) = let cfile = getCFile(m) diff --git a/compiler/ndi.nim b/compiler/ndi.nim index 41f04cf0d..5af87237f 100644 --- a/compiler/ndi.nim +++ b/compiler/ndi.nim @@ -17,6 +17,8 @@ type enabled: bool f: File buf: string + filename: AbsoluteFile + syms: seq[PSym] proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) = f.buf.setLen 0 @@ -28,13 +30,20 @@ proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) = f.f.writeLine("\t", toFullPath(conf, s.info), "\t", f.buf) template writeMangledName*(f: NdiFile; s: PSym; conf: ConfigRef) = - if f.enabled: doWrite(f, s, conf) + if f.enabled: f.syms.add s proc open*(f: var NdiFile; filename: AbsoluteFile; conf: ConfigRef) = f.enabled = not filename.isEmpty if f.enabled: - f.f = open(filename.string, fmWrite, 8000) + f.filename = filename f.buf = newStringOfCap(20) -proc close*(f: var NdiFile) = - if f.enabled: close(f.f) +proc close*(f: var NdiFile, conf: ConfigRef) = + if f.enabled: + f.f = open(f.filename.string, fmWrite, 8000) + doAssert f.f != nil, f.filename.string + for s in f.syms: + doWrite(f, s, conf) + close(f.f) + f.syms.reset + f.filename.reset From 216fd59c44c7eb56431748389e3b2116692189a1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Apr 2020 08:49:29 -0700 Subject: [PATCH 0243/4254] make `usage of foo is a user-defined error` more informative (#13833) --- compiler/suggest.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index ff58bc92f..d8da2a7a4 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -523,14 +523,16 @@ proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = proc userError(conf: ConfigRef; info: TLineInfo; s: PSym) = let pragmaNode = extractPragma(s) - + template bail(prefix: string) = + localError(conf, info, "$1usage of '$2' is an {.error.} defined at $3" % + [prefix, s.name.s, toFileLineCol(conf, s.ast.info)]) if pragmaNode != nil: for it in pragmaNode: if whichPragma(it) == wError and it.safeLen == 2 and it[1].kind in {nkStrLit..nkTripleStrLit}: - localError(conf, info, it[1].strVal & "; usage of '$1' is a user-defined error" % s.name.s) + bail(it[1].strVal & "; ") return - localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s) + bail("") proc markOwnerModuleAsUsed(c: PContext; s: PSym) = var module = s From a8b6222c862d207a32c104699fc4f0f0a8bced17 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 27 Mar 2020 15:47:49 +0200 Subject: [PATCH 0244/4254] First steps, the compiler can boot with enforced requiresInit --- compiler/ast.nim | 12 +++++++----- compiler/pragmas.nim | 2 +- compiler/semobjconstr.nim | 13 ++++--------- compiler/sempass2.nim | 8 ++++---- compiler/semstmts.nim | 2 +- compiler/semtypes.nim | 10 +++++----- tests/types/temptyseqs.nim | 8 ++++---- 7 files changed, 26 insertions(+), 29 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 4d45f0e55..a4630732b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -517,8 +517,10 @@ type tfPartial, # type is declared as 'partial' tfNotNil, # type cannot be 'nil' - tfNeedsInit, # type constains a "not nil" constraint somewhere or some - # other type so that it requires initialization + tfHasRequiresInit,# type constains a "not nil" constraint somewhere or + # a `requiresInit` field, so the default zero init + # is not appropriate + tfRequiresInit, # all fields of the type must be initialized tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes @@ -1484,11 +1486,11 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: owner.flags.incl tfNotNil elif owner.kind notin HaveTheirOwnEmpty: - owner.flags.incl tfNeedsInit + owner.flags.incl tfHasRequiresInit - if tfNeedsInit in elem.flags: + if tfRequiresInit in elem.flags: if owner.kind in HaveTheirOwnEmpty: discard - else: owner.flags.incl tfNeedsInit + else: owner.flags.incl tfHasRequiresInit if elem.isMetaType: owner.flags.incl tfHasMeta diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6056afb6c..e4b72bed7 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1088,7 +1088,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wRequiresInit: noVal(c, it) if sym.typ == nil: invalidPragma(c, it) - else: incl(sym.typ.flags, tfNeedsInit) + else: incl(sym.typ.flags, tfRequiresInit) of wByRef: noVal(c, it) if sym == nil or sym.typ == nil: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 489bc6684..bc1e85425 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -138,7 +138,7 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string = for r in directFieldsInRecList(fieldsRecList): - if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}: + if {tfNotNil, tfRequiresInit} * r.sym.typ.flags != {}: let assignment = locateFieldInInitExpr(c, r.sym, initExpr) if assignment == nil: if result.len == 0: @@ -358,15 +358,10 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # It's possible that the object was not fully initialized while # specifying a .requiresInit. pragma. - # XXX: Turn this into an error in the next release - if tfNeedsInit in t.flags and initResult != initFull: - # XXX: Disable this warning for now, because tfNeedsInit is propagated - # too aggressively from fields to object types (and this is not correct - # in case objects) - when false: message(n.info, warnUser, + if tfRequiresInit in t.flags and initResult != initFull: + localError(c.config, n.info, "object type uses the 'requiresInit' pragma, but not all fields " & - "have been initialized. future versions of Nim will treat this as " & - "an error") + "have been initialized.") # Since we were traversing the object fields, it's possible that # not all of the fields specified in the constructor was visited. diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 4658f5454..65dce3ed8 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -184,7 +184,7 @@ proc initVar(a: PEffects, n: PNode; volatileCheck: bool) = proc initVarViaNew(a: PEffects, n: PNode) = if n.kind != nkSym: return let s = n.sym - if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}: + if {tfRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}: # 'x' is not nil, but that doesn't mean its "not nil" children # are initialized: initVar(a, n, volatileCheck=true) @@ -253,7 +253,7 @@ proc useVar(a: PEffects, n: PNode) = # If the variable is explicitly marked as .noinit. do not emit any error a.init.add s.id elif s.id notin a.init: - if {tfNeedsInit, tfNotNil} * s.typ.flags != {}: + if {tfRequiresInit, tfNotNil} * s.typ.flags != {}: message(a.config, n.info, warnProveInit, s.name.s) else: message(a.config, n.info, warnUninit, s.name.s) @@ -838,7 +838,7 @@ proc track(tracked: PEffects, n: PNode) = # may not look like an assignment, but it is: let arg = n[1] initVarViaNew(tracked, arg) - if arg.typ.len != 0 and {tfNeedsInit} * arg.typ.lastSon.flags != {}: + if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}: if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and n[2].intVal == 0: # var s: seq[notnil]; newSeq(s, 0) is a special case! @@ -1203,7 +1203,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = createTypeBoundOps(t, typ, param.info) if not isEmptyType(s.typ[0]) and - ({tfNeedsInit, tfNotNil} * s.typ[0].flags != {} or + ({tfRequiresInit, tfNotNil} * s.typ[0].flags != {} or s.typ[0].skipTypes(abstractInst).kind == tyVar) and s.kind in {skProc, skFunc, skConverter, skMethod}: var res = s.ast[resultPos].sym # get result symbol diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b45c42fe1..057972f0a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -336,7 +336,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and - {tfNotNil, tfNeedsInit} * v.typ.flags != {}: + {tfNotNil, tfRequiresInit} * v.typ.flags != {}: if v.astdef.isNil: message(c.config, v.info, warnProveInit, v.name.s) elif tfNotNil in v.typ.flags and not v.astdef.typ.isNil and tfNotNil notin v.astdef.typ.flags: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7cddc7520..92e7b8bd2 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -139,7 +139,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil): wrongRedefinition(c, e.info, e.name.s, conflict.info) inc(counter) - if tfNotNil in e.typ.flags and not hasNull: incl(result.flags, tfNeedsInit) + if tfNotNil in e.typ.flags and not hasNull: incl(result.flags, tfRequiresInit) proc semSet(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tySet, prev, c) @@ -254,15 +254,15 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType = result = semRangeAux(c, n[1], prev) let n = result.n if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0: - incl(result.flags, tfNeedsInit) + incl(result.flags, tfRequiresInit) elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0: - incl(result.flags, tfNeedsInit) + incl(result.flags, tfRequiresInit) elif n[0].kind in {nkFloatLit..nkFloat64Lit} and n[0].floatVal > 0.0: - incl(result.flags, tfNeedsInit) + incl(result.flags, tfRequiresInit) elif n[1].kind in {nkFloatLit..nkFloat64Lit} and n[1].floatVal < 0.0: - incl(result.flags, tfNeedsInit) + incl(result.flags, tfRequiresInit) else: if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<": localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported") diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim index 28c3b87b8..6e7b58ced 100644 --- a/tests/types/temptyseqs.nim +++ b/tests/types/temptyseqs.nim @@ -75,16 +75,16 @@ varargso("foo", "bar", "baz") type Flago = enum - tfNeedsInit, tfNotNil + tfRequiresInit, tfNotNil -var s: set[Flago] = {tfNeedsInit} +var s: set[Flago] = {tfRequiresInit} -if {tfNeedsInit, tfNotNil} * s != {}: +if {tfRequiresInit, tfNotNil} * s != {}: echo "yes" else: echo "no" -if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}: +if {tfRequiresInit, tfNotNil} * s <= {tfNotNil}: echo "yes" else: echo "no" From 7652aede41d81b4e7db2c70ffe462c6fb675d078 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 27 Mar 2020 18:43:23 +0200 Subject: [PATCH 0245/4254] More sophistication; Allow requiresInit to be specified per-field --- compiler/ast.nim | 3 +- compiler/pragmas.nim | 10 ++++-- compiler/semobjconstr.nim | 32 +++++++++++++------- tests/constructors/tinvalid_construction.nim | 31 +++++++++++++++++++ 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index a4630732b..a7eb2cac5 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -259,6 +259,7 @@ type # needed for the code generator sfProcvar, # proc can be passed to a proc var sfDiscriminant, # field is a discriminant in a record/object + sfRequiresInit, # field must be initialized during construction sfDeprecated, # symbol is deprecated sfExplain, # provide more diagnostics when this symbol is used sfError, # usage of symbol should trigger a compile-time error @@ -1488,7 +1489,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = elif owner.kind notin HaveTheirOwnEmpty: owner.flags.incl tfHasRequiresInit - if tfRequiresInit in elem.flags: + if {tfRequiresInit, tfHasRequiresInit} * elem.flags != {}: if owner.kind in HaveTheirOwnEmpty: discard else: owner.flags.incl tfHasRequiresInit diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index e4b72bed7..604ba063f 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -65,7 +65,7 @@ const wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wBorrow, wGcSafe, wPartial, wExplain, wPackage} fieldPragmas* = declPragmas + { - wGuard, wBitsize, wCursor} - {wExportNims, wNodecl} # why exclude these? + wGuard, wBitsize, wCursor, wRequiresInit} - {wExportNims, wNodecl} # why exclude these? varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar, wMagic, wHeader, wCompilerProc, wCore, wDynlib, wNoInit, wCompileTime, wGlobal, @@ -1087,8 +1087,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: incl(sym.typ.flags, tfUnion) of wRequiresInit: noVal(c, it) - if sym.typ == nil: invalidPragma(c, it) - else: incl(sym.typ.flags, tfRequiresInit) + if sym.kind == skField: + sym.flags.incl sfRequiresInit + elif sym.typ != nil: + incl(sym.typ.flags, tfRequiresInit) + else: + invalidPragma(c, it) of wByRef: noVal(c, it) if sym == nil or sym.typ == nil: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index bc1e85425..ee79f1a67 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -136,9 +136,11 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin if result.len != 0: result.add ", " result.add field.sym.name.s.quoteStr -proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string = +proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode, + requiresFullInit = false): string = for r in directFieldsInRecList(fieldsRecList): - if {tfNotNil, tfRequiresInit} * r.sym.typ.flags != {}: + if requiresFullInit or sfRequiresInit in r.sym.flags or + {tfNotNil, tfRequiresInit, tfHasRequiresInit} * r.sym.typ.flags != {}: let assignment = locateFieldInInitExpr(c, r.sym, initExpr) if assignment == nil: if result.len == 0: @@ -147,19 +149,22 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string result.add ", " result.add r.sym.name.s -proc checkForMissingFields(c: PContext, recList, initExpr: PNode) = - let missing = missingMandatoryFields(c, recList, initExpr) +proc checkForMissingFields(c: PContext, recList, initExpr: PNode, + requiresFullInit = false) = + let missing = missingMandatoryFields(c, recList, initExpr, requiresFullInit) if missing.len > 0: localError(c.config, initExpr.info, "fields not initialized: $1.", [missing]) proc semConstructFields(c: PContext, recNode: PNode, - initExpr: PNode, flags: TExprFlags): InitStatus = + initExpr: PNode, flags: TExprFlags, + requiresFullInit = false): InitStatus = result = initUnknown case recNode.kind of nkRecList: for field in recNode: - let status = semConstructFields(c, field, initExpr, flags) + let status = semConstructFields(c, field, initExpr, + flags, requiresFullInit) mergeInitStatus(result, status) of nkRecCase: @@ -171,7 +176,7 @@ proc semConstructFields(c: PContext, recNode: PNode, template checkMissingFields(branchNode: PNode) = if branchNode != nil: let fields = branchNode[^1] - checkForMissingFields(c, fields, initExpr) + checkForMissingFields(c, fields, initExpr, requiresFullInit) let discriminator = recNode[0] internalAssert c.config, discriminator.kind == nkSym @@ -179,7 +184,8 @@ proc semConstructFields(c: PContext, recNode: PNode, for i in 1.. Date: Fri, 27 Mar 2020 20:22:37 +0200 Subject: [PATCH 0246/4254] Don't allow 'var x: T' for objects that require initialization --- compiler/sem.nim | 18 ++++++ compiler/semobjconstr.nim | 68 +++++++++----------- compiler/semstmts.nim | 6 +- tests/constructors/tinvalid_construction.nim | 8 +++ 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 48f767af7..f4d992e25 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -58,6 +58,24 @@ proc isArrayConstr(n: PNode): bool {.inline.} = result = n.kind == nkBracket and n.typ.skipTypes(abstractInst).kind == tyArray +type + ObjConstrContext = object + typ: PType # The constructed type + initExpr: PNode # The init expression (nkObjConstr) + requiresFullInit: bool # A `requiresInit` derived type will + # set this to true while visiting + # parent types. + + InitStatus = enum # This indicates the result of object construction + initUnknown + initFull # All of the fields have been initialized + initPartial # Some of the fields have been initialized + initNone # None of the fields have been initialized + initConflict # Fields from different branches have been initialized + +proc semConstructType(c: PContext, initExpr: PNode, + t: PType, flags: TExprFlags): InitStatus + template semIdeForTemplateOrGenericCheck(conf, n, requiresCheck) = # we check quickly if the node is where the cursor is when defined(nimsuggest): diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index ee79f1a67..2d226aa33 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -11,14 +11,6 @@ # included from sem.nim -type - InitStatus = enum - initUnknown - initFull # All of the fields have been initialized - initPartial # Some of the fields have been initialized - initNone # None of the fields have been initialized - initConflict # Fields from different branches have been initialized - proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) = case newStatus of initConflict: @@ -136,12 +128,12 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin if result.len != 0: result.add ", " result.add field.sym.name.s.quoteStr -proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode, - requiresFullInit = false): string = +proc missingMandatoryFields(c: PContext, fieldsRecList: PNode, + constrCtx: ObjConstrContext): string = for r in directFieldsInRecList(fieldsRecList): - if requiresFullInit or sfRequiresInit in r.sym.flags or + if constrCtx.requiresFullInit or sfRequiresInit in r.sym.flags or {tfNotNil, tfRequiresInit, tfHasRequiresInit} * r.sym.typ.flags != {}: - let assignment = locateFieldInInitExpr(c, r.sym, initExpr) + let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr) if assignment == nil: if result.len == 0: result = r.sym.name.s @@ -149,34 +141,35 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode, result.add ", " result.add r.sym.name.s -proc checkForMissingFields(c: PContext, recList, initExpr: PNode, - requiresFullInit = false) = - let missing = missingMandatoryFields(c, recList, initExpr, requiresFullInit) +proc checkForMissingFields(c: PContext, recList: PNode, + constrCtx: ObjConstrContext) = + let missing = missingMandatoryFields(c, recList, constrCtx) if missing.len > 0: - localError(c.config, initExpr.info, "fields not initialized: $1.", [missing]) + localError(c.config, constrCtx.initExpr.info, + "The $1 type requires the following fields to be initialized: $2.", + [constrCtx.typ.sym.name.s, missing]) proc semConstructFields(c: PContext, recNode: PNode, - initExpr: PNode, flags: TExprFlags, - requiresFullInit = false): InitStatus = + constrCtx: ObjConstrContext, + flags: TExprFlags): InitStatus = result = initUnknown case recNode.kind of nkRecList: for field in recNode: - let status = semConstructFields(c, field, initExpr, - flags, requiresFullInit) + let status = semConstructFields(c, field, constrCtx, flags) mergeInitStatus(result, status) of nkRecCase: template fieldsPresentInBranch(branchIdx: int): string = let branch = recNode[branchIdx] let fields = branch[^1] - fieldsPresentInInitExpr(c, fields, initExpr) + fieldsPresentInInitExpr(c, fields, constrCtx.initExpr) template checkMissingFields(branchNode: PNode) = if branchNode != nil: let fields = branchNode[^1] - checkForMissingFields(c, fields, initExpr, requiresFullInit) + checkForMissingFields(c, fields, constrCtx) let discriminator = recNode[0] internalAssert c.config, discriminator.kind == nkSym @@ -184,14 +177,13 @@ proc semConstructFields(c: PContext, recNode: PNode, for i in 1.. Date: Fri, 27 Mar 2020 20:53:09 +0200 Subject: [PATCH 0247/4254] Plug another hole: default(T) forbidden for objects requiring initialization --- compiler/sem.nim | 19 +------------------ compiler/semexprs.nim | 6 ++++++ compiler/semobjconstr.nim | 18 ++++++++++++++++++ compiler/semstmts.nim | 2 +- tests/constructors/tinvalid_construction.nim | 5 +++++ 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index f4d992e25..3a4ff2cd9 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -46,6 +46,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc activate(c: PContext, n: PNode) +proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo) proc semQuoteAst(c: PContext, n: PNode): PNode proc finishMethod(c: PContext, s: PSym) proc evalAtCompileTime(c: PContext, n: PNode): PNode @@ -58,24 +59,6 @@ proc isArrayConstr(n: PNode): bool {.inline.} = result = n.kind == nkBracket and n.typ.skipTypes(abstractInst).kind == tyArray -type - ObjConstrContext = object - typ: PType # The constructed type - initExpr: PNode # The init expression (nkObjConstr) - requiresFullInit: bool # A `requiresInit` derived type will - # set this to true while visiting - # parent types. - - InitStatus = enum # This indicates the result of object construction - initUnknown - initFull # All of the fields have been initialized - initPartial # Some of the fields have been initialized - initNone # None of the fields have been initialized - initConflict # Fields from different branches have been initialized - -proc semConstructType(c: PContext, initExpr: PNode, - t: PType, flags: TExprFlags): InitStatus - template semIdeForTemplateOrGenericCheck(conf, n, requiresCheck) = # we check quickly if the node is where the cursor is when defined(nimsuggest): diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d6659f76b..58f3f9316 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2264,6 +2264,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mSizeOf: markUsed(c, n.info, s) result = semSizeof(c, setMs(n, s)) + of mDefault: + result = semDirectOp(c, n, flags) + c.config.internalAssert result[1].typ.kind == tyTypeDesc + let typ = result[1].typ.base + if typ.kind in {tyObject, tyTuple}: + checkDefaultConstruction(c, typ, n.info) else: result = semDirectOp(c, n, flags) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 2d226aa33..b9931f527 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -11,6 +11,21 @@ # included from sem.nim +type + ObjConstrContext = object + typ: PType # The constructed type + initExpr: PNode # The init expression (nkObjConstr) + requiresFullInit: bool # A `requiresInit` derived type will + # set this to true while visiting + # parent types. + + InitStatus = enum # This indicates the result of object construction + initUnknown + initFull # All of the fields have been initialized + initPartial # Some of the fields have been initialized + initNone # None of the fields have been initialized + initConflict # Fields from different branches have been initialized + proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) = case newStatus of initConflict: @@ -336,6 +351,9 @@ proc semConstructType(c: PContext, initExpr: PNode, constrCtx.requiresFullInit = constrCtx.requiresFullInit or tfRequiresInit in t.flags +proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo) = + discard semConstructType(c, newNodeI(nkObjConstr, info), typ, {}) + proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var t = semTypeNode(c, n[0], nil) result = newNodeIT(nkObjConstr, n.info, t) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 812d1ff71..373e5fcdb 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -616,7 +616,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = b[j] = newSymNode(v) if def.kind == nkEmpty: if v.typ.kind in {tyObject, tyTuple}: - discard semConstructType(c, newNodeI(nkObjConstr, v.info), v.typ, {}) + checkDefaultConstruction(c, v.typ, v.info) else: checkNilable(c, v) if sfCompileTime in v.flags: diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index 9afee3cd4..f84a18e68 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -125,12 +125,15 @@ accept PartialRequiresInit(a: 10, b: "x") accept PartialRequiresInit(a: 20) reject PartialRequiresInit(b: "x") reject PartialRequiresInit() +reject default(PartialRequiresInit) reject: var obj: PartialRequiresInit accept FullRequiresInit(a: 10, b: 20) reject FullRequiresInit(a: 10) reject FullRequiresInit(b: 20) +reject FullRequiresInit() +reject default(FullRequiresInit) reject: var obj: FullRequiresInit @@ -140,11 +143,13 @@ reject FullRequiresInitWithParent(a: notNilRef, b: nil, c: nil, e: 10, d: 20) # reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20) # c should not be missing reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10) # d should not be missing reject FullRequiresInitWithParent() +reject default(FullRequiresInitWithParent) reject: var obj: FullRequiresInitWithParent # this will be accepted, because the false outer branch will be taken and the inner A branch accept TNestedChoices() +accept default(TNestedChoices) accept: var obj: TNestedChoices From 54f06427c8c2d1a29bf7dab2b9e36fc4bb231d3c Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 27 Mar 2020 21:58:32 +0200 Subject: [PATCH 0248/4254] Enable the requiresInit checks only for objects --- compiler/semexprs.nim | 2 +- compiler/semstmts.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 58f3f9316..d39fe146e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2268,7 +2268,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = semDirectOp(c, n, flags) c.config.internalAssert result[1].typ.kind == tyTypeDesc let typ = result[1].typ.base - if typ.kind in {tyObject, tyTuple}: + if typ.kind == tyObject: checkDefaultConstruction(c, typ, n.info) else: result = semDirectOp(c, n, flags) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 373e5fcdb..fc624c710 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -615,7 +615,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: v.typ = tup b[j] = newSymNode(v) if def.kind == nkEmpty: - if v.typ.kind in {tyObject, tyTuple}: + if v.typ.kind == tyObject: checkDefaultConstruction(c, v.typ, v.info) else: checkNilable(c, v) From e0bb78553ad34282ff198c4f1121b14b18030dc2 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 27 Mar 2020 22:48:40 +0200 Subject: [PATCH 0249/4254] Fix tests/notnil/tnotnil_in_objconstr.nim --- tests/notnil/tnotnil_in_objconstr.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim index fb8ac8d6f..030c40d32 100644 --- a/tests/notnil/tnotnil_in_objconstr.nim +++ b/tests/notnil/tnotnil_in_objconstr.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "fields not initialized: bar" + errormsg: "The Foo type requires the following fields to be initialized: bar" line: "13" """ {.experimental: "notnil".} From 1b570f2b187fea9571476a1e2e768d2d4c2f7aa5 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Mar 2020 02:06:39 +0200 Subject: [PATCH 0250/4254] Turn the warning for uninitialized (result) variables into errors --- compiler/ast.nim | 3 + compiler/lineinfos.nim | 2 + compiler/semobjconstr.nim | 5 +- compiler/sempass2.nim | 17 ++-- compiler/semstmts.nim | 5 +- compiler/semtypes.nim | 5 +- tests/constructors/tinvalid_construction.nim | 83 +++++++++++++++++++- 7 files changed, 103 insertions(+), 17 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index a7eb2cac5..01f9ed29b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1396,6 +1396,9 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType = proc exactReplica*(t: PType): PType = copyType(t, t.owner, true) +template requiresInit*(t: PType): bool = + t.flags * {tfRequiresInit, tfHasRequiresInit, tfNotNil} != {} + proc copySym*(s: PSym): PSym = result = newSym(s.kind, s.name, s.owner, s.info, s.options) #result.ast = nil # BUGFIX; was: s.ast which made problems diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index f7f3b7706..585a95c80 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -23,6 +23,7 @@ type errGeneralParseError, errNewSectionExpected, errInvalidDirectiveX, + errProveInit, errGenerated, errUser, warnCannotOpenFile, @@ -63,6 +64,7 @@ const errGeneralParseError: "general parse error", errNewSectionExpected: "new section expected", errInvalidDirectiveX: "invalid directive: '$1'", + errProveInit: "Cannot prove that '$1' is initialized.", errGenerated: "$1", errUser: "$1", warnCannotOpenFile: "cannot open '$1'", diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index b9931f527..7222433b3 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -146,8 +146,9 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin proc missingMandatoryFields(c: PContext, fieldsRecList: PNode, constrCtx: ObjConstrContext): string = for r in directFieldsInRecList(fieldsRecList): - if constrCtx.requiresFullInit or sfRequiresInit in r.sym.flags or - {tfNotNil, tfRequiresInit, tfHasRequiresInit} * r.sym.typ.flags != {}: + if constrCtx.requiresFullInit or + sfRequiresInit in r.sym.flags or + r.sym.typ.requiresInit: let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr) if assignment == nil: if result.len == 0: diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 65dce3ed8..2d5e3e721 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -184,7 +184,7 @@ proc initVar(a: PEffects, n: PNode; volatileCheck: bool) = proc initVarViaNew(a: PEffects, n: PNode) = if n.kind != nkSym: return let s = n.sym - if {tfRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}: + if {tfRequiresInit, tfHasRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}: # 'x' is not nil, but that doesn't mean its "not nil" children # are initialized: initVar(a, n, volatileCheck=true) @@ -253,8 +253,8 @@ proc useVar(a: PEffects, n: PNode) = # If the variable is explicitly marked as .noinit. do not emit any error a.init.add s.id elif s.id notin a.init: - if {tfRequiresInit, tfNotNil} * s.typ.flags != {}: - message(a.config, n.info, warnProveInit, s.name.s) + if s.typ.requiresInit: + localError(a.config, n.info, errProveInit, s.name.s) else: message(a.config, n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: @@ -838,13 +838,13 @@ proc track(tracked: PEffects, n: PNode) = # may not look like an assignment, but it is: let arg = n[1] initVarViaNew(tracked, arg) - if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}: + if arg.typ.len != 0 and {tfRequiresInit, tfHasRequiresInit} * arg.typ.lastSon.flags != {}: if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and n[2].intVal == 0: # var s: seq[notnil]; newSeq(s, 0) is a special case! discard else: - message(tracked.config, arg.info, warnProveInit, $arg) + localError(tracked.config, arg.info, errProveInit, $arg) # check required for 'nim check': if n[1].typ.len > 0: @@ -1203,12 +1203,11 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = createTypeBoundOps(t, typ, param.info) if not isEmptyType(s.typ[0]) and - ({tfRequiresInit, tfNotNil} * s.typ[0].flags != {} or - s.typ[0].skipTypes(abstractInst).kind == tyVar) and - s.kind in {skProc, skFunc, skConverter, skMethod}: + (s.typ[0].requiresInit or s.typ[0].skipTypes(abstractInst).kind == tyVar) and + s.kind in {skProc, skFunc, skConverter, skMethod}: var res = s.ast[resultPos].sym # get result symbol if res.id notin t.init: - message(g.config, body.info, warnProveInit, "result") + localError(g.config, body.info, errProveInit, "result") let p = s.ast[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index fc624c710..23e581a53 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -335,8 +335,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = suggestSym(c.config, info, result, c.graph.usageSym) proc checkNilable(c: PContext; v: PSym) = - if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and - {tfNotNil, tfRequiresInit} * v.typ.flags != {}: + if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and v.typ.requiresInit: if v.astdef.isNil: message(c.config, v.info, warnProveInit, v.name.s) elif tfNotNil in v.typ.flags and not v.astdef.typ.isNil and tfNotNil notin v.astdef.typ.flags: @@ -485,7 +484,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var a = n[i] if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) + if a.kind notin {nkIdentDefs, nkVarTuple}: illFormedAst(a, c.config) checkMinSonsLen(a, 3, c.config) var typ: PType = nil diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 92e7b8bd2..1de181dbe 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -139,7 +139,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil): wrongRedefinition(c, e.info, e.name.s, conflict.info) inc(counter) - if tfNotNil in e.typ.flags and not hasNull: incl(result.flags, tfRequiresInit) + if tfNotNil in e.typ.flags and not hasNull: + result.flags.incl tfRequiresInit proc semSet(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tySet, prev, c) @@ -769,6 +770,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, f.typ = typ f.position = pos f.options = c.config.options + if sfRequiresInit in f.flags: + rectype.flags.incl tfHasRequiresInit if fieldOwner != nil and {sfImportc, sfExportc} * fieldOwner.flags != {} and not hasCaseFields and f.loc.r == nil: diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index f84a18e68..46156db6c 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -32,10 +32,14 @@ type a {.requiresInit.}: int b: string + PartialRequiresInitRef = ref PartialRequiresInit + FullRequiresInit {.requiresInit.} = object a: int b: int + FullRequiresInitRef = ref FullRequiresInit + FullRequiresInitWithParent {.requiresInit.} = object of THasNotNils e: int d: int @@ -72,8 +76,13 @@ var nilRef: TRefObj var notNilRef = TRefObj(x: 20) proc makeHasNotNils: ref THasNotNils = - result.a = TRefObj(x: 10) - result.b = TRefObj(x: 20) + (ref THasNotNils)(a: TRefObj(x: 10), + b: TRefObj(x: 20)) + +proc userDefinedDefault(T: typedesc): T = + # We'll use that to make sure the user cannot cheat + # with constructing requiresInit types + discard accept TObj() accept TObj(choice: A) @@ -125,7 +134,17 @@ accept PartialRequiresInit(a: 10, b: "x") accept PartialRequiresInit(a: 20) reject PartialRequiresInit(b: "x") reject PartialRequiresInit() +accept PartialRequiresInitRef(a: 10, b: "x") +accept PartialRequiresInitRef(a: 20) +reject PartialRequiresInitRef(b: "x") +reject PartialRequiresInitRef() +accept((ref PartialRequiresInit)(a: 10, b: "x")) +accept((ref PartialRequiresInit)(a: 20)) +reject((ref PartialRequiresInit)(b: "x")) +reject((ref PartialRequiresInit)()) + reject default(PartialRequiresInit) +reject userDefinedDefault(PartialRequiresInit) reject: var obj: PartialRequiresInit @@ -133,7 +152,17 @@ accept FullRequiresInit(a: 10, b: 20) reject FullRequiresInit(a: 10) reject FullRequiresInit(b: 20) reject FullRequiresInit() +accept FullRequiresInitRef(a: 10, b: 20) +reject FullRequiresInitRef(a: 10) +reject FullRequiresInitRef(b: 20) +reject FullRequiresInitRef() +accept((ref FullRequiresInit)(a: 10, b: 20)) +reject((ref FullRequiresInit)(a: 10)) +reject((ref FullRequiresInit)(b: 20)) +reject((ref FullRequiresInit)()) + reject default(FullRequiresInit) +reject userDefinedDefault(FullRequiresInit) reject: var obj: FullRequiresInit @@ -144,6 +173,7 @@ reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20) # reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10) # d should not be missing reject FullRequiresInitWithParent() reject default(FullRequiresInitWithParent) +reject userDefinedDefault(FullRequiresInitWithParent) reject: var obj: FullRequiresInitWithParent @@ -153,6 +183,55 @@ accept default(TNestedChoices) accept: var obj: TNestedChoices +reject: + # This proc is illegal, because it tries to produce + # a default object of a type that requires initialization: + proc defaultHasNotNils: THasNotNils = + discard + +reject: + # You cannot cheat by using the result variable to specify + # only some of the fields + proc invalidPartialTHasNotNils: THasNotNils = + result.c = nilRef + +reject: + # The same applies for requiresInit types + proc invalidPartialRequiersInit: PartialRequiresInit = + result.b = "x" + +# All code paths must return a value when the result requires initialization: +reject: + proc ifWithoutAnElse: THasNotNils = + if stdin.readLine == "": + return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) + +accept: + # All code paths must return a value when the result requires initialization: + proc wellFormedIf: THasNotNils = + if stdin.readLine == "": + return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) + else: + return THasNotNIls(a: notNilRef, b: notNilRef) + +reject: + proc caseWithoutAllCasesCovered: FullRequiresInit = + # Please note that these is no else branch here: + case stdin.readLine + of "x": + return FullRequiresInit(a: 10, b: 20) + of "y": + return FullRequiresInit(a: 30, b: 40) + +accept: + proc wellFormedCase: FullRequiresInit = + case stdin.readLine + of "x": + result = FullRequiresInit(a: 10, b: 20) + else: + # Mixing result and return is fine: + return FullRequiresInit(a: 30, b: 40) + # but if we supply a run-time value for the inner branch, the compiler won't be able to prove # that the notnil field was initialized reject TNestedChoices(outerChoice: false, innerChoice: x) # XXX: The error message is not very good here From f3be5a716fff715bd46f6f0293db04eb2f0f832d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Mar 2020 02:34:50 +0200 Subject: [PATCH 0251/4254] not nil types are illegal to construct through default(T) --- compiler/semexprs.nim | 2 ++ tests/constructors/tinvalid_construction.nim | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d39fe146e..d4f33eb41 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2270,6 +2270,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = let typ = result[1].typ.base if typ.kind == tyObject: checkDefaultConstruction(c, typ, n.info) + elif typ.kind in {tyRef, tyPtr} and tfNotNil in typ.flags: + localError(c.config, n.info, "not nil types don't have a default value") else: result = semDirectOp(c, n, flags) diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index 46156db6c..eb84c53c8 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -17,6 +17,8 @@ type THasNotNilsRef = ref THasNotNils + TRefObjNotNil = TRefObj not nil + TChoice = enum A, B, C, D, E, F TBaseHasNotNils = object of THasNotNils @@ -84,6 +86,9 @@ proc userDefinedDefault(T: typedesc): T = # with constructing requiresInit types discard +proc genericDefault(T: typedesc): T = + result = default(T) + accept TObj() accept TObj(choice: A) reject TObj(choice: A, bc: 10) # bc is in the wrong branch @@ -102,9 +107,18 @@ accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field reject THasNotNils() # again, missing fields accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field +reject default(THasNotNils) +reject userDefinedDefault(THasNotNils) + +reject default(TRefObjNotNil) +reject userDefinedDefault(TRefObjNotNil) +reject genericDefault(TRefObjNotNil) # missing not nils in base reject TBaseHasNotNils() +reject default(TBaseHasNotNils) +reject userDefinedDefault(TBaseHasNotNils) +reject genericDefault(TBaseHasNotNils) # once you take care of them, it's ok accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: D) From 0521f98486a6a95b388864747d584ddd5bf68391 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Mar 2020 02:17:47 +0200 Subject: [PATCH 0252/4254] Hrm, the new errors highlighted some code that seems to be broken New issue: since `Table[A, B]` allocates its backing storage with `newSeq[KeyValuePair[A, B]]`, it's no longer legal to create a table with `not nil` types used as either keys or values. --- lib/pure/collections/sequtils.nim | 5 ++--- lib/pure/collections/sharedtables.nim | 18 ++++++++---------- lib/pure/ioselects/ioselectors_epoll.nim | 3 +-- lib/pure/ioselects/ioselectors_kqueue.nim | 3 +-- lib/pure/ioselects/ioselectors_select.nim | 8 +++++++- lib/pure/parsecsv.nim | 4 ++-- tests/collections/ttables.nim | 2 +- tests/discard/tneedsdiscard_in_for.nim | 2 +- 8 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e32c784c6..893f31389 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -371,9 +371,8 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): b = map(a, proc(x: int): string = $x) assert b == @["1", "2", "3", "4"] - newSeq(result, s.len) - for i in 0 ..< s.len: - result[i] = op(s[i]) + result = newSeqOfCap[S](s.len) + for elem in s: result.add op(elem) proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) {.inline.} = diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 2a1c0543f..96f934f50 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -77,8 +77,7 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, try: var hc: Hash var index = rawGet(t, key, hc) - let hasKey = index >= 0 - if hasKey: + if index >= 0: var value {.inject.} = addr(t.data[index].val) body finally: @@ -104,8 +103,7 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, try: var hc: Hash var index = rawGet(t, key, hc) - let hasKey = index >= 0 - if hasKey: + if index >= 0: var value {.inject.} = addr(t.data[index].val) body1 else: @@ -119,13 +117,13 @@ proc mget*[A, B](t: var SharedTable[A, B], key: A): var B = withLock t: var hc: Hash var index = rawGet(t, key, hc) - let hasKey = index >= 0 - if hasKey: result = t.data[index].val - if not hasKey: - when compiles($key): - raise newException(KeyError, "key not found: " & $key) + if index >= 0: + result = t.data[index].val else: - raise newException(KeyError, "key not found") + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") proc mgetOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index bf13cc83e..002bddac5 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -502,8 +502,7 @@ proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) s.checkFd(fdi) - if fdi in s: - result = s.fds[fdi].data + result = s.fds[fdi].data proc setData*[T](s: Selector[T], fd: SocketHandle|int, data: T): bool = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 83e15d479..c5e19a011 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -600,8 +600,7 @@ proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) s.checkFd(fdi) - if fdi in s: - result = s.fds[fdi].data + result = s.fds[fdi].data proc setData*[T](s: Selector[T], fd: SocketHandle|int, data: T): bool = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 02a853b42..6a742df99 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -410,11 +410,17 @@ else: body proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = + # The compiler needs this to prove that all code paths return a value + result = (cast[ptr T](0'u))[] + s.withSelectLock(): let fdi = int(fd) for i in 0..= 0: - result = my.row[index] + assert index >= 0 + result = my.row[index] when not defined(testing) and isMainModule: import os diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index a59707865..2a590dd26 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -80,7 +80,7 @@ block thashes: # Test with range block: type - R = range[1..10] + R = range[0..9] var t = initTable[R,int]() # causes warning, why? t[1] = 42 # causes warning, why? t[2] = t[1] + 1 diff --git a/tests/discard/tneedsdiscard_in_for.nim b/tests/discard/tneedsdiscard_in_for.nim index 499b06009..ab5216150 100644 --- a/tests/discard/tneedsdiscard_in_for.nim +++ b/tests/discard/tneedsdiscard_in_for.nim @@ -8,7 +8,7 @@ type Rgba8 = object proc premultiply*(c: var Rgba8): var Rgba8 = - discard + return c type App = ref object From 7b7e42be546889447cb046c1cb2091885d8a19e3 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Mar 2020 19:05:01 +0300 Subject: [PATCH 0253/4254] More precise error messages for uninitialized fields in the presence of inheritance --- compiler/astalgo.nim | 7 ++++ compiler/semobjconstr.nim | 60 +++++++++++---------------- tests/notnil/tnotnil_in_objconstr.nim | 10 +++-- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 968918ba9..bd60ddd7d 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -1041,3 +1041,10 @@ proc isAddrNode*(n: PNode): bool = if n[0].kind == nkSym and n[0].sym.magic == mAddr: true else: false else: false + +proc listSymbolNames*(symbols: openArray[PSym]): string = + for sym in symbols: + if result.len > 0: + result.add ", " + result.add sym.name.s + diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 7222433b3..9d39dd5f8 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -13,11 +13,12 @@ type ObjConstrContext = object - typ: PType # The constructed type - initExpr: PNode # The init expression (nkObjConstr) - requiresFullInit: bool # A `requiresInit` derived type will - # set this to true while visiting - # parent types. + typ: PType # The constructed type + initExpr: PNode # The init expression (nkObjConstr) + requiresFullInit: bool # A `requiresInit` derived type will + # set this to true while visiting + # parent types. + missingFields: seq[PSym] # Fields that the user failed to specify InitStatus = enum # This indicates the result of object construction initUnknown @@ -143,30 +144,18 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin if result.len != 0: result.add ", " result.add field.sym.name.s.quoteStr -proc missingMandatoryFields(c: PContext, fieldsRecList: PNode, - constrCtx: ObjConstrContext): string = +proc collectMissingFields(c: PContext, fieldsRecList: PNode, + constrCtx: var ObjConstrContext) = for r in directFieldsInRecList(fieldsRecList): if constrCtx.requiresFullInit or sfRequiresInit in r.sym.flags or r.sym.typ.requiresInit: let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr) if assignment == nil: - if result.len == 0: - result = r.sym.name.s - else: - result.add ", " - result.add r.sym.name.s - -proc checkForMissingFields(c: PContext, recList: PNode, - constrCtx: ObjConstrContext) = - let missing = missingMandatoryFields(c, recList, constrCtx) - if missing.len > 0: - localError(c.config, constrCtx.initExpr.info, - "The $1 type requires the following fields to be initialized: $2.", - [constrCtx.typ.sym.name.s, missing]) + constrCtx.missingFields.add r.sym proc semConstructFields(c: PContext, recNode: PNode, - constrCtx: ObjConstrContext, + constrCtx: var ObjConstrContext, flags: TExprFlags): InitStatus = result = initUnknown @@ -182,10 +171,10 @@ proc semConstructFields(c: PContext, recNode: PNode, let fields = branch[^1] fieldsPresentInInitExpr(c, fields, constrCtx.initExpr) - template checkMissingFields(branchNode: PNode) = + template collectMissingFields(branchNode: PNode) = if branchNode != nil: let fields = branchNode[^1] - checkForMissingFields(c, fields, constrCtx) + collectMissingFields(c, fields, constrCtx) let discriminator = recNode[0] internalAssert c.config, discriminator.kind == nkSym @@ -299,7 +288,7 @@ proc semConstructFields(c: PContext, recNode: PNode, # When a branch is selected with a partial match, some of the fields # that were not initialized may be mandatory. We must check for this: if result == initPartial: - checkMissingFields branchNode + collectMissingFields branchNode else: result = initNone @@ -313,18 +302,18 @@ proc semConstructFields(c: PContext, recNode: PNode, # a result: let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0) let matchedBranch = recNode.pickCaseBranch defaultValue - checkMissingFields matchedBranch + collectMissingFields matchedBranch else: result = initPartial if discriminatorVal.kind == nkIntLit: # When the discriminator is a compile-time value, we also know # which branch will be selected: let matchedBranch = recNode.pickCaseBranch discriminatorVal - if matchedBranch != nil: checkMissingFields matchedBranch + if matchedBranch != nil: collectMissingFields matchedBranch else: # All bets are off. If any of the branches has a mandatory # fields we must produce an error: - for i in 1.. 0: + localError(c.config, constrCtx.initExpr.info, + "The $1 type requires the following fields to be initialized: $2.", + [constrCtx.typ.sym.name.s, listSymbolNames(constrCtx.missingFields)]) + proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo) = discard semConstructType(c, newNodeI(nkObjConstr, info), typ, {}) @@ -381,13 +378,6 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # branches will be reported as an error): let initResult = semConstructType(c, result, t, flags) - # It's possible that the object was not fully initialized while - # specifying a .requiresInit. pragma. - if tfRequiresInit in t.flags and initResult != initFull: - localError(c.config, n.info, - "object type uses the 'requiresInit' pragma, but not all fields " & - "have been initialized.") - # Since we were traversing the object fields, it's possible that # not all of the fields specified in the constructor was visited. # We'll check for such fields here: diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim index 030c40d32..471150f44 100644 --- a/tests/notnil/tnotnil_in_objconstr.nim +++ b/tests/notnil/tnotnil_in_objconstr.nim @@ -1,13 +1,17 @@ discard """ - errormsg: "The Foo type requires the following fields to be initialized: bar" - line: "13" + errormsg: "The Foo type requires the following fields to be initialized: bar, baz" + line: "17" """ {.experimental: "notnil".} # bug #2355 type - Foo = object + Base = object of RootObj + baz: ref int not nil + + Foo = object of Base foo: ref int bar: ref int not nil + var x: ref int = new(int) # Create instance without initializing the `bar` field var f = Foo(foo: x) From 4f3d309fb0d17e52644029f4c593cd670516655a Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Mar 2020 20:31:37 +0300 Subject: [PATCH 0254/4254] Perform nil checks during object construction and within compiles() Close https://github.com/nim-lang/Nim/issues/6494 --- compiler/sem.nim | 2 +- compiler/semexprs.nim | 5 ++++- compiler/sempass2.nim | 5 +++-- tests/constructors/tinvalid_construction.nim | 5 ++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 3a4ff2cd9..07b765f88 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -584,7 +584,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = result = buildEchoStmt(c, result) if c.config.cmd == cmdIdeTools: appendToModule(c.module, result) - trackTopLevelStmt(c, c.module, result) + trackStmt(c, c.module, result, isTopLevel = true) proc recoverContext(c: PContext) = # clean up in case of a semantic error: We clean up the stacks, etc. This is diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d4f33eb41..5484f4594 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2082,7 +2082,10 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var err: string try: result = semExpr(c, n, flags) - if c.config.errorCounter != oldErrorCount: result = nil + if result != nil: + trackStmt(c, c.module, result, isTopLevel = false) + if c.config.errorCounter != oldErrorCount: + result = nil except ERecoverableError: discard # undo symbol table changes (as far as it's possible): diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 2d5e3e721..3ad0a1931 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -996,6 +996,7 @@ proc track(tracked: PEffects, n: PNode) = createTypeBoundOps(tracked, x[1].typ, n.info) if x.kind == nkExprColonExpr: + notNilCheck(tracked, x[1], x[0].sym.typ) checkForSink(tracked.config, tracked.owner, x[1]) else: checkForSink(tracked.config, tracked.owner, x) @@ -1260,7 +1261,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = dataflowAnalysis(s, body) when false: trackWrites(s, body) -proc trackTopLevelStmt*(c: PContext; module: PSym; n: PNode) = +proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef, nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}: return @@ -1268,5 +1269,5 @@ proc trackTopLevelStmt*(c: PContext; module: PSym; n: PNode) = var effects = newNode(nkEffectList, n.info) var t: TEffects initEffects(g, effects, module, t, c) - t.isTopLevel = true + t.isTopLevel = isTopLevel track(t, n) diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index eb84c53c8..e6fdbcb85 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -75,7 +75,7 @@ type var x = D var nilRef: TRefObj -var notNilRef = TRefObj(x: 20) +let notNilRef = TRefObjNotNil(x: 20) proc makeHasNotNils: ref THasNotNils = (ref THasNotNils)(a: TRefObj(x: 10), @@ -102,8 +102,7 @@ reject TObj(a: 10, f: "") # conflicting fields accept TObj(choice: E, e1: TRefObj(x: 10), e2: 10) accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) -# XXX: the "not nil" logic in the compiler is not strong enough to catch this one yet: -# reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef) +reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef) # `b` shouldn't be nil reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field reject THasNotNils() # again, missing fields accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field From 06438ed1431ee8ad3ae2eda9dcb7fbe64739329a Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Mar 2020 20:49:13 +0300 Subject: [PATCH 0255/4254] Close https://github.com/nim-lang/Nim/issues/11428 --- tests/constructors/tinvalid_construction.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index e6fdbcb85..c17e2123c 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -256,3 +256,15 @@ reject TNestedChoices(outerChoice: false, innerChoice: C) accept TNestedChoices(outerChoice: false, innerChoice: C, notnil: notNilRef) reject TNestedChoices(outerChoice: false, innerChoice: C, notnil: nil) +block: + # https://github.com/nim-lang/Nim/issues/11428 + type + Enum = enum A, B, C + Thing = object + case kind: Enum + of A: discard + of B: s: string + of C: r: range[1..1] # DateTime + + # Fine to not initialize 'r' because this is implicitly initialized and known to be branch 'A'. + let someThing = Thing() From e63b673ce2557bcc3189bd5917b35327253b4c1b Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 30 Mar 2020 00:49:42 +0300 Subject: [PATCH 0256/4254] Fix https://github.com/nim-lang/Nim/issues/4907 --- compiler/semexprs.nim | 3 ++ compiler/semtypes.nim | 39 +++++++++++++++++-- tests/constructors/tinvalid_construction.nim | 41 +++++++++++++++++++- 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5484f4594..e405ec0ef 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2655,6 +2655,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = return var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) result.typ = makeTypeDesc(c, typ) + of nkStmtListType: + let typ = semTypeNode(c, n, nil) + result.typ = makeTypeDesc(c, typ) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1, c.config) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 1de181dbe..39df93b62 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1720,12 +1720,43 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = case n.len of 3: result = semTypeNode(c, n[1], prev) - if result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).kind in NilableTypes+GenericTypes+{tyForward} and - n[2].kind == nkNilLit: + if result.kind == tyTypeDesc and tfUnresolved notin result.flags: + result = result.base + if n[2].kind != nkNilLit: + localError(c.config, n.info, + "Invalid syntax. When used with a type, 'not' can be followed only by 'nil'") + if notnil notin c.features: + localError(c.config, n.info, + "enable the 'not nil' annotation with {.experimental: \"notnil\".}") + let resolvedType = result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}) + case resolvedType.kind + of tyGenericParam, tyTypeDesc, tyFromExpr: + # XXX: This is a really inappropraite hack, but it solves + # https://github.com/nim-lang/Nim/issues/4907 for now. + # + # A proper solution is to introduce a new type kind such + # as `tyNotNil[tyRef[SomeGenericParam]]`. This will allow + # semtypinst to replace the generic param correctly in + # situations like the following: + # + # type Foo[T] = object + # bar: ref T not nil + # baz: ref T + # + # The root of the problem is that `T` here must have a specific + # ID that is bound to a concrete type during instantiation. + # The use of `freshType` below breaks this. Another hack would + # be to reuse the same ID for the not nil type, but this will + # fail if the `T` parameter is referenced multiple times as in + # the example above. + # + # I suggest revisiting this once the language decides on whether + # `not nil` should be the default. We can then map nilable refs + # to other types such as `Option[T]`. + result = makeTypeFromExpr(c, newTree(nkStmtListType, n.copyTree)) + of NilableTypes + {tyGenericInvocation, tyForward}: result = freshType(result, prev) result.flags.incl(tfNotNil) - if notnil notin c.features: - localError(c.config, n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}") else: localError(c.config, n.info, errGenerated, "invalid type") of 2: diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index c17e2123c..6716bfb45 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -267,4 +267,43 @@ block: of C: r: range[1..1] # DateTime # Fine to not initialize 'r' because this is implicitly initialized and known to be branch 'A'. - let someThing = Thing() + var x = Thing() + discard x + +block: + # https://github.com/nim-lang/Nim/issues/4907 + type + Foo = ref object + Bar = object + + Thing[A, B] = ref object + a: A not nil + b: ref B + c: ref B not nil + + proc allocNotNil(T: typedesc): T not nil = + new result + + proc mutateThing(t: var Thing[Foo, Bar]) = + let fooNotNil = allocNotNil(Foo) + var foo: Foo + + let barNotNil = allocNotNil(ref Bar) + var bar: ref Bar + + t.a = fooNotNil + t.b = bar + t.b = barNotNil + t.c = barNotNil + + reject: + t.a = foo + + reject: + t.c = bar + + var thing = Thing[Foo, Bar](a: allocNotNil(Foo), + b: allocNotNil(ref Bar), + c: allocNotNil(ref Bar)) + mutateThing thing + From 2b66d665679912e62244a94c134ce910838fc107 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 30 Mar 2020 01:38:59 +0300 Subject: [PATCH 0257/4254] Fix a CI failure during koch doc --- compiler/sempass2.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 3ad0a1931..40b3b15ce 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -996,7 +996,8 @@ proc track(tracked: PEffects, n: PNode) = createTypeBoundOps(tracked, x[1].typ, n.info) if x.kind == nkExprColonExpr: - notNilCheck(tracked, x[1], x[0].sym.typ) + if x[0].kind == nkSym: + notNilCheck(tracked, x[1], x[0].sym.typ) checkForSink(tracked.config, tracked.owner, x[1]) else: checkForSink(tracked.config, tracked.owner, x) From d374c6373bed4d6807ff70b6179328e79fbe1ac8 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 30 Mar 2020 03:47:02 +0300 Subject: [PATCH 0258/4254] Fix tests/parallel/tguard2.nim --- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/sigmatch.nim | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 367c0eaf6..7fa671722 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -63,7 +63,7 @@ type # to the user. efWantStmt, efAllowStmt, efDetermineType, efExplain, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoEvaluateGeneric, efInCall, efFromHlo, + efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check, efNoUndeclared # Use this if undeclared identifiers should not raise an error during # overload resolution. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e405ec0ef..d920b0f25 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2082,7 +2082,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var err: string try: result = semExpr(c, n, flags) - if result != nil: + if result != nil and efNoSem2Check notin flags: trackStmt(c, c.module, result, isTopLevel = false) if c.config.errorCounter != oldErrorCount: result = nil diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 79b3ea94c..04ceb47b8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1937,7 +1937,9 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, var call = newNodeI(nkCall, arg.info) call.add(f.n.copyTree) call.add(arg.copyTree) - result = c.semTryExpr(c, call) + # XXX: This would be much nicer if we don't use `semTryExpr` and + # instead we directly search for overloads with `resolveOverloads`: + result = c.semTryExpr(c, call, {efNoSem2Check}) if result != nil: if result.typ == nil: return nil From ce9a4ed124d798d0287a62e4700a32f1d15878c9 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 30 Mar 2020 18:56:03 +0300 Subject: [PATCH 0259/4254] Replace tfHasRequiresInit with a more accurate mechanism The new mechanism can deal with more complex scenarios such as not nil field appearing in a non-default case object branch or a field within a generic object that may depend on a when branch. The commit also plugs another hole: the user is no longer able to create illegal default values through seq.setLen(N). --- compiler/ast.nim | 14 +-- compiler/pragmas.nim | 2 +- compiler/sem.nim | 4 +- compiler/semdata.nim | 1 + compiler/semexprs.nim | 14 ++- compiler/semobjconstr.nim | 57 ++++++---- compiler/sempass2.nim | 6 +- compiler/semstmts.nim | 6 +- compiler/semtypes.nim | 4 +- compiler/semtypinst.nim | 2 + tests/constructors/tinvalid_construction.nim | 112 +++++++++++++++++++ 11 files changed, 179 insertions(+), 43 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 01f9ed29b..f4f680811 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -517,11 +517,11 @@ type tfIterator, # type is really an iterator, not a tyProc tfPartial, # type is declared as 'partial' tfNotNil, # type cannot be 'nil' - - tfHasRequiresInit,# type constains a "not nil" constraint somewhere or + tfRequiresInit, # type constains a "not nil" constraint somewhere or # a `requiresInit` field, so the default zero init # is not appropriate - tfRequiresInit, # all fields of the type must be initialized + tfNeedsFullInit, # object type marked with {.requiresInit.} + # all fields must be initialized tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes @@ -1397,7 +1397,7 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType = proc exactReplica*(t: PType): PType = copyType(t, t.owner, true) template requiresInit*(t: PType): bool = - t.flags * {tfRequiresInit, tfHasRequiresInit, tfNotNil} != {} + t.flags * {tfRequiresInit, tfNotNil} != {} proc copySym*(s: PSym): PSym = result = newSym(s.kind, s.name, s.owner, s.info, s.options) @@ -1489,12 +1489,6 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = if tfNotNil in elem.flags: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: owner.flags.incl tfNotNil - elif owner.kind notin HaveTheirOwnEmpty: - owner.flags.incl tfHasRequiresInit - - if {tfRequiresInit, tfHasRequiresInit} * elem.flags != {}: - if owner.kind in HaveTheirOwnEmpty: discard - else: owner.flags.incl tfHasRequiresInit if elem.isMetaType: owner.flags.incl tfHasMeta diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 604ba063f..100ce1560 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1090,7 +1090,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if sym.kind == skField: sym.flags.incl sfRequiresInit elif sym.typ != nil: - incl(sym.typ.flags, tfRequiresInit) + incl(sym.typ.flags, tfNeedsFullInit) else: invalidPragma(c, it) of wByRef: diff --git a/compiler/sem.nim b/compiler/sem.nim index 07b765f88..471a30099 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -46,7 +46,6 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc activate(c: PContext, n: PNode) -proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo) proc semQuoteAst(c: PContext, n: PNode): PNode proc finishMethod(c: PContext, s: PSym) proc evalAtCompileTime(c: PContext, n: PNode): PNode @@ -54,6 +53,8 @@ proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode proc semStaticExpr(c: PContext, n: PNode): PNode proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType proc semTypeOf(c: PContext; n: PNode): PNode +proc computeRequiresInit(c: PContext, t: PType): bool +proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) proc hasUnresolvedArgs(c: PContext, n: PNode): bool proc isArrayConstr(n: PNode): bool {.inline.} = result = n.kind == nkBracket and @@ -512,6 +513,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = c.semExpr = semExpr c.semTryExpr = tryExpr c.semTryConstExpr = tryConstExpr + c.computeRequiresInit = computeRequiresInit c.semOperand = semOperand c.semConstBoolExpr = semConstBoolExpr c.semOverloadedCall = semOverloadedCall diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 7fa671722..fbc9762f3 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -103,6 +103,7 @@ type semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} + computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d920b0f25..56de00d56 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2267,13 +2267,19 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mSizeOf: markUsed(c, n.info, s) result = semSizeof(c, setMs(n, s)) + of mSetLengthSeq: + result = semDirectOp(c, n, flags) + let seqType = result[1].typ.skipTypes({tyPtr, tyRef, # in case we had auto-dereferencing + tyVar, tyGenericInst, tyOwned, tySink, + tyAlias, tyUserTypeClassInst}) + if seqType.kind == tySequence and seqType.base.requiresInit: + localError(c.config, n.info, "setLen can potentially expand the sequence, " & + "but the element type $1 doesn't have a default value.", + [typeToString(seqType.base)]) of mDefault: result = semDirectOp(c, n, flags) c.config.internalAssert result[1].typ.kind == tyTypeDesc - let typ = result[1].typ.base - if typ.kind == tyObject: - checkDefaultConstruction(c, typ, n.info) - elif typ.kind in {tyRef, tyPtr} and tfNotNil in typ.flags: + if result[1].typ.base.requiresInit: localError(c.config, n.info, "not nil types don't have a default value") else: result = semDirectOp(c, n, flags) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 9d39dd5f8..eb0589601 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -15,7 +15,7 @@ type ObjConstrContext = object typ: PType # The constructed type initExpr: PNode # The init expression (nkObjConstr) - requiresFullInit: bool # A `requiresInit` derived type will + needsFullInit: bool # A `requiresInit` derived type will # set this to true while visiting # parent types. missingFields: seq[PSym] # Fields that the user failed to specify @@ -147,7 +147,7 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin proc collectMissingFields(c: PContext, fieldsRecList: PNode, constrCtx: var ObjConstrContext) = for r in directFieldsInRecList(fieldsRecList): - if constrCtx.requiresFullInit or + if constrCtx.needsFullInit or sfRequiresInit in r.sym.flags or r.sym.typ.requiresInit: let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr) @@ -323,14 +323,11 @@ proc semConstructFields(c: PContext, recNode: PNode, else: internalAssert c.config, false -proc semConstructType(c: PContext, initExpr: PNode, - t: PType, flags: TExprFlags): InitStatus = +proc semConstructTypeAux(c: PContext, + constrCtx: var ObjConstrContext, + flags: TExprFlags): InitStatus = result = initUnknown - - var - t = t - constrCtx = ObjConstrContext(typ: t, initExpr: initExpr, - requiresFullInit: tfRequiresInit in t.flags) + var t = constrCtx.typ while true: let status = semConstructFields(c, t.n, constrCtx, flags) mergeInitStatus(result, status) @@ -339,18 +336,30 @@ proc semConstructType(c: PContext, initExpr: PNode, let base = t[0] if base == nil: break t = skipTypes(base, skipPtrs) - constrCtx.requiresFullInit = constrCtx.requiresFullInit or - tfRequiresInit in t.flags + constrCtx.needsFullInit = constrCtx.needsFullInit or + tfNeedsFullInit in t.flags - # It's possible that the object was not fully initialized while - # specifying a .requiresInit. pragma: - if constrCtx.missingFields.len > 0: - localError(c.config, constrCtx.initExpr.info, - "The $1 type requires the following fields to be initialized: $2.", - [constrCtx.typ.sym.name.s, listSymbolNames(constrCtx.missingFields)]) +proc initConstrContext(t: PType, initExpr: PNode): ObjConstrContext = + ObjConstrContext(typ: t, initExpr: initExpr, + needsFullInit: tfNeedsFullInit in t.flags) -proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo) = - discard semConstructType(c, newNodeI(nkObjConstr, info), typ, {}) +proc computeRequiresInit(c: PContext, t: PType): bool = + assert t.kind == tyObject + var constrCtx = initConstrContext(t, newNode(nkObjConstr)) + let initResult = semConstructTypeAux(c, constrCtx, {}) + constrCtx.missingFields.len > 0 + +proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = + var objType = t + while objType.kind != tyObject: + objType = objType.lastSon + assert objType != nil + var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info)) + let initResult = semConstructTypeAux(c, constrCtx, {}) + assert constrCtx.missingFields.len > 0 + localError(c.config, info, + "The $1 type doesn't have a default value. The following fields must be initialized: $2.", + [typeToString(t), listSymbolNames(constrCtx.missingFields)]) proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var t = semTypeNode(c, n[0], nil) @@ -376,7 +385,15 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # Check if the object is fully initialized by recursively testing each # field (if this is a case object, initialized fields in two different # branches will be reported as an error): - let initResult = semConstructType(c, result, t, flags) + var constrCtx = initConstrContext(t, result) + let initResult = semConstructTypeAux(c, constrCtx, flags) + + # It's possible that the object was not fully initialized while + # specifying a .requiresInit. pragma: + if constrCtx.missingFields.len > 0: + localError(c.config, result.info, + "The $1 type requires the following fields to be initialized: $2.", + [t.sym.name.s, listSymbolNames(constrCtx.missingFields)]) # Since we were traversing the object fields, it's possible that # not all of the fields specified in the constructor was visited. diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 40b3b15ce..79d969fbb 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -184,7 +184,7 @@ proc initVar(a: PEffects, n: PNode; volatileCheck: bool) = proc initVarViaNew(a: PEffects, n: PNode) = if n.kind != nkSym: return let s = n.sym - if {tfRequiresInit, tfHasRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}: + if {tfRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}: # 'x' is not nil, but that doesn't mean its "not nil" children # are initialized: initVar(a, n, volatileCheck=true) @@ -590,7 +590,7 @@ proc trackCase(tracked: PEffects, n: PNode) = track(tracked, n[0]) let oldState = tracked.init.len let oldFacts = tracked.guards.s.len - let stringCase = skipTypes(n[0].typ, + let stringCase = n[0].typ != nil and skipTypes(n[0].typ, abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString} let interesting = not stringCase and interestingCaseExpr(n[0]) and tracked.config.hasWarn(warnProveField) @@ -838,7 +838,7 @@ proc track(tracked: PEffects, n: PNode) = # may not look like an assignment, but it is: let arg = n[1] initVarViaNew(tracked, arg) - if arg.typ.len != 0 and {tfRequiresInit, tfHasRequiresInit} * arg.typ.lastSon.flags != {}: + if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}: if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and n[2].intVal == 0: # var s: seq[notnil]; newSeq(s, 0) is a special case! diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 23e581a53..215d554fb 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -614,8 +614,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: v.typ = tup b[j] = newSymNode(v) if def.kind == nkEmpty: - if v.typ.kind == tyObject: - checkDefaultConstruction(c, v.typ, v.info) + let actualType = v.typ.skipTypes({tyGenericInst, tyAlias, + tyUserTypeClassInst}) + if actualType.kind == tyObject and actualType.requiresInit: + defaultConstructionError(c, v.typ, v.info) else: checkNilable(c, v) if sfCompileTime in v.flags: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 39df93b62..21b95d3f6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -770,8 +770,6 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, f.typ = typ f.position = pos f.options = c.config.options - if sfRequiresInit in f.flags: - rectype.flags.incl tfHasRequiresInit if fieldOwner != nil and {sfImportc, sfExportc} * fieldOwner.flags != {} and not hasCaseFields and f.loc.r == nil: @@ -879,6 +877,8 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PTy pragma(c, s, n[0], typePragmas) if base == nil and tfInheritable notin result.flags: incl(result.flags, tfFinal) + if c.inGenericContext == 0 and computeRequiresInit(c, result): + result.flags.incl tfRequiresInit proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if n.len < 1: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 5aec3eed9..08ea85708 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -613,6 +613,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = of tyObject, tyTuple: propagateFieldFlags(result, result.n) + if result.kind == tyObject and cl.c.computeRequiresInit(cl.c, result): + result.flags.incl tfRequiresInit of tyProc: eraseVoidParams(result) diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index 6716bfb45..e98b530bb 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -10,6 +10,9 @@ type TRefObj = ref object x: int + IllegalToConstruct = object + x: cstring not nil + THasNotNils = object of RootObj a: TRefObj not nil b: TRefObj not nil @@ -89,6 +92,10 @@ proc userDefinedDefault(T: typedesc): T = proc genericDefault(T: typedesc): T = result = default(T) +reject IllegalToConstruct() +reject: + var x: IllegalToConstruct + accept TObj() accept TObj(choice: A) reject TObj(choice: A, bc: 10) # bc is in the wrong branch @@ -256,6 +263,111 @@ reject TNestedChoices(outerChoice: false, innerChoice: C) accept TNestedChoices(outerChoice: false, innerChoice: C, notnil: notNilRef) reject TNestedChoices(outerChoice: false, innerChoice: C, notnil: nil) +# Tests involving generics and sequences: +# +block: + # This test aims to show that it's possible to instantiate and + # use a sequence with a requiresInit type: + + var legalSeq: seq[IllegalToConstruct] + legalSeq.add IllegalToConstruct(x: "one") + var two = IllegalToConstruct(x: "two") + legalSeq.add two + var one = legalSeq[0] + var twoAgain = legalSeq.pop + + # It's not possible to tell the sequence to create elements + # for us though: + reject: + var illegalSeq = newSeq[IllegalToConstruct](10) + + reject: + var illegalSeq: seq[IllegalToConstruct] + newSeq(illegalSeq, 10) + + reject: + var illegalSeq: seq[IllegalToConstruct] + illegalSeq.setLen 10 + + # You can still use newSeqOfCap to write efficient code: + var anotherLegalSequence = newSeqOfCap[IllegalToConstruct](10) + for i in 0..9: + anotherLegalSequence.add IllegalToConstruct(x: "x") + +type DefaultConstructible[yesOrNo: static[bool]] = object + when yesOrNo: + x: string + else: + x: cstring not nil + +block: + # Constructability may also depend on the generic parameters of the type: + accept: + var a: DefaultConstructible[true] + var b = DefaultConstructible[true]() + var c = DefaultConstructible[true](x: "test") + var d = DefaultConstructible[false](x: "test") + + reject: + var y: DefaultConstructible[false] + + reject: + var y = DefaultConstructible[false]() + +block: + type + Hash = int + + HashTableSlotType = enum + Free = Hash(0) + Deleted = Hash(1) + HasKey = Hash(2) + + KeyValuePair[A, B] = object + key: A + case hash: HashTableSlotType + of Free, Deleted: + discard + else: + value: B + + # The above KeyValuePair is an interesting type because it + # may become unconstructible depending on the generic parameters: + accept KeyValuePair[int, string](hash: Deleted) + accept KeyValuePair[int, IllegalToConstruct](hash: Deleted) + + accept KeyValuePair[int, string](hash: HasKey) + reject KeyValuePair[int, IllegalToConstruct](hash: HasKey) + + # Since all the above variations don't have a non-constructible + # field in the default branch of the case object, we can construct + # such values: + accept KeyValuePair[int, string]() + accept KeyValuePair[int, IllegalToConstruct]() + accept KeyValuePair[DefaultConstructible[true], string]() + accept KeyValuePair[DefaultConstructible[true], IllegalToConstruct]() + + var a: KeyValuePair[int, string] + var b: KeyValuePair[int, IllegalToConstruct] + var c: KeyValuePair[DefaultConstructible[true], string] + var d: KeyValuePair[DefaultConstructible[true], IllegalToConstruct] + var s1 = newSeq[KeyValuePair[int, IllegalToConstruct]](10) + var s2 = newSeq[KeyValuePair[DefaultConstructible[true], IllegalToConstruct]](10) + + # But let's put the non-constructible values as keys: + reject KeyValuePair[IllegalToConstruct, int](hash: Deleted) + reject KeyValuePair[IllegalToConstruct, int]() + + type IllegalPair = KeyValuePair[DefaultConstructible[false], string] + + reject: + var x: IllegalPair + + reject: + var s = newSeq[IllegalPair](10) + +# Specific issues: +# block: # https://github.com/nim-lang/Nim/issues/11428 type From be95f8fdfac9ceb559f77b55630ca9e285fa9a2d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 1 Apr 2020 03:33:32 +0300 Subject: [PATCH 0260/4254] Turn some of the errors back into warnings --- compiler/lineinfos.nim | 6 +++ compiler/semexprs.nim | 14 ------ compiler/semmagic.nim | 17 +++++++- compiler/semobjconstr.nim | 5 +++ compiler/sempass2.nim | 6 +-- tests/constructors/tinvalid_construction.nim | 46 ++++++++++++++------ tests/objects/tobjects_issues.nim | 2 +- 7 files changed, 63 insertions(+), 33 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 585a95c80..658863676 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -37,6 +37,8 @@ type warnUnusedImportX, warnInheritFromException, warnEachIdentIsTuple, + warnUnsafeSetLen, + warnUnsafeDefault, warnProveInit, warnProveField, warnProveIndex, warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, @@ -87,6 +89,9 @@ const warnUnusedImportX: "imported and not used: '$1'", warnInheritFromException: "inherit from a more precise exception type like ValueError, IOError or OSError", warnEachIdentIsTuple: "each identifier is a tuple", + warnUnsafeSetLen: "setLen can potentially expand the sequence, " & + "but the element type '$1' doesn't have a valid default value", + warnUnsafeDefault: "The '$1' type doesn't have a valid default value", warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", warnProveField: "cannot prove that field '$1' is accessible", warnProveIndex: "cannot prove index '$1' is valid", @@ -146,6 +151,7 @@ const "TypelessParam", "UseBase", "WriteToForeignHeap", "UnsafeCode", "UnusedImport", "InheritFromException", "EachIdentIsTuple", + "UnsafeSetLen", "UnsafeDefault", "ProveInit", "ProveField", "ProveIndex", "IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "ResultShadowed", diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 56de00d56..5f82eb1e7 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2267,20 +2267,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mSizeOf: markUsed(c, n.info, s) result = semSizeof(c, setMs(n, s)) - of mSetLengthSeq: - result = semDirectOp(c, n, flags) - let seqType = result[1].typ.skipTypes({tyPtr, tyRef, # in case we had auto-dereferencing - tyVar, tyGenericInst, tyOwned, tySink, - tyAlias, tyUserTypeClassInst}) - if seqType.kind == tySequence and seqType.base.requiresInit: - localError(c.config, n.info, "setLen can potentially expand the sequence, " & - "but the element type $1 doesn't have a default value.", - [typeToString(seqType.base)]) - of mDefault: - result = semDirectOp(c, n, flags) - c.config.internalAssert result[1].typ.kind == tyTypeDesc - if result[1].typ.base.requiresInit: - localError(c.config, n.info, "not nil types don't have a default value") else: result = semDirectOp(c, n, flags) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 8c07d7d18..783846650 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -530,4 +530,19 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = semQuantifier(c, n) of mOld: result = semOld(c, n) - else: result = n + of mSetLengthSeq: + result = n + let seqType = result[1].typ.skipTypes({tyPtr, tyRef, # in case we had auto-dereferencing + tyVar, tyGenericInst, tyOwned, tySink, + tyAlias, tyUserTypeClassInst}) + if seqType.kind == tySequence and seqType.base.requiresInit: + message(c.config, n.info, warnUnsafeSetLen, typeToString(seqType.base)) + of mDefault: + result = n + c.config.internalAssert result[1].typ.kind == tyTypeDesc + let constructed = result[1].typ.base + if constructed.requiresInit: + message(c.config, n.info, warnUnsafeDefault, typeToString(constructed)) + else: + result = n + diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index eb0589601..eeec42900 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -336,6 +336,11 @@ proc semConstructTypeAux(c: PContext, let base = t[0] if base == nil: break t = skipTypes(base, skipPtrs) + if t.kind == tyGenericParam: + # XXX: This is not supposed to happen, but apparently + # there are some issues in semtypinst. Luckily, it + # seems to affect only `computeRequiresInit`. + return constrCtx.needsFullInit = constrCtx.needsFullInit or tfNeedsFullInit in t.flags diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 79d969fbb..a4e1dcf00 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -254,7 +254,7 @@ proc useVar(a: PEffects, n: PNode) = a.init.add s.id elif s.id notin a.init: if s.typ.requiresInit: - localError(a.config, n.info, errProveInit, s.name.s) + message(a.config, n.info, warnProveInit, s.name.s) else: message(a.config, n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: @@ -844,7 +844,7 @@ proc track(tracked: PEffects, n: PNode) = # var s: seq[notnil]; newSeq(s, 0) is a special case! discard else: - localError(tracked.config, arg.info, errProveInit, $arg) + message(tracked.config, arg.info, warnProveInit, $arg) # check required for 'nim check': if n[1].typ.len > 0: @@ -1209,7 +1209,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = s.kind in {skProc, skFunc, skConverter, skMethod}: var res = s.ast[resultPos].sym # get result symbol if res.id notin t.init: - localError(g.config, body.info, errProveInit, "result") + message(g.config, body.info, warnProveInit, "result") let p = s.ast[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index e98b530bb..4b372d68a 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -113,18 +113,18 @@ reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef) # `b` shouldn't be n reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field reject THasNotNils() # again, missing fields accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field -reject default(THasNotNils) -reject userDefinedDefault(THasNotNils) +# produces only warning: reject default(THasNotNils) +# produces only warning: reject userDefinedDefault(THasNotNils) -reject default(TRefObjNotNil) -reject userDefinedDefault(TRefObjNotNil) -reject genericDefault(TRefObjNotNil) +# produces only warning: reject default(TRefObjNotNil) +# produces only warning: reject userDefinedDefault(TRefObjNotNil) +# produces only warning: reject genericDefault(TRefObjNotNil) # missing not nils in base reject TBaseHasNotNils() -reject default(TBaseHasNotNils) -reject userDefinedDefault(TBaseHasNotNils) -reject genericDefault(TBaseHasNotNils) +# produces only warning: reject default(TBaseHasNotNils) +# produces only warning: reject userDefinedDefault(TBaseHasNotNils) +# produces only warning: reject genericDefault(TBaseHasNotNils) # once you take care of them, it's ok accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: D) @@ -163,8 +163,8 @@ accept((ref PartialRequiresInit)(a: 20)) reject((ref PartialRequiresInit)(b: "x")) reject((ref PartialRequiresInit)()) -reject default(PartialRequiresInit) -reject userDefinedDefault(PartialRequiresInit) +# produces only warning: reject default(PartialRequiresInit) +# produces only warning: reject userDefinedDefault(PartialRequiresInit) reject: var obj: PartialRequiresInit @@ -181,8 +181,8 @@ reject((ref FullRequiresInit)(a: 10)) reject((ref FullRequiresInit)(b: 20)) reject((ref FullRequiresInit)()) -reject default(FullRequiresInit) -reject userDefinedDefault(FullRequiresInit) +# produces only warning: reject default(FullRequiresInit) +# produces only warning: reject userDefinedDefault(FullRequiresInit) reject: var obj: FullRequiresInit @@ -192,8 +192,8 @@ reject FullRequiresInitWithParent(a: notNilRef, b: nil, c: nil, e: 10, d: 20) # reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20) # c should not be missing reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10) # d should not be missing reject FullRequiresInitWithParent() -reject default(FullRequiresInitWithParent) -reject userDefinedDefault(FullRequiresInitWithParent) +# produces only warning: reject default(FullRequiresInitWithParent) +# produces only warning: reject userDefinedDefault(FullRequiresInitWithParent) reject: var obj: FullRequiresInitWithParent @@ -203,28 +203,36 @@ accept default(TNestedChoices) accept: var obj: TNestedChoices +#[# produces only warning: reject: # This proc is illegal, because it tries to produce # a default object of a type that requires initialization: proc defaultHasNotNils: THasNotNils = discard +#]# +#[# produces only warning: reject: # You cannot cheat by using the result variable to specify # only some of the fields proc invalidPartialTHasNotNils: THasNotNils = result.c = nilRef +#]# +#[# produces only warning: reject: # The same applies for requiresInit types proc invalidPartialRequiersInit: PartialRequiresInit = result.b = "x" +#]# +#[# produces only warning: # All code paths must return a value when the result requires initialization: reject: proc ifWithoutAnElse: THasNotNils = if stdin.readLine == "": return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef) +#]# accept: # All code paths must return a value when the result requires initialization: @@ -234,6 +242,7 @@ accept: else: return THasNotNIls(a: notNilRef, b: notNilRef) +#[# produces only warning: reject: proc caseWithoutAllCasesCovered: FullRequiresInit = # Please note that these is no else branch here: @@ -242,6 +251,7 @@ reject: return FullRequiresInit(a: 10, b: 20) of "y": return FullRequiresInit(a: 30, b: 40) +#]# accept: proc wellFormedCase: FullRequiresInit = @@ -276,18 +286,24 @@ block: var one = legalSeq[0] var twoAgain = legalSeq.pop + #[# produces only warning: # It's not possible to tell the sequence to create elements # for us though: reject: var illegalSeq = newSeq[IllegalToConstruct](10) + #]# + #[# produces only warning: reject: var illegalSeq: seq[IllegalToConstruct] newSeq(illegalSeq, 10) + #]# + #[# produces only warning: reject: var illegalSeq: seq[IllegalToConstruct] illegalSeq.setLen 10 + #]# # You can still use newSeqOfCap to write efficient code: var anotherLegalSequence = newSeqOfCap[IllegalToConstruct](10) @@ -363,8 +379,10 @@ block: reject: var x: IllegalPair + #[# produces only warning: reject: var s = newSeq[IllegalPair](10) + #]# # Specific issues: # diff --git a/tests/objects/tobjects_issues.nim b/tests/objects/tobjects_issues.nim index fddfff7d5..f1a416d04 100644 --- a/tests/objects/tobjects_issues.nim +++ b/tests/objects/tobjects_issues.nim @@ -113,5 +113,5 @@ block t3038: Type = ref object of RootObj SubType[T] = ref object of Type data: Data[T] - SubSubType = ref object of SubType + SubSubType = ref object of SubType[int] SubSubSubType = ref object of SubSubType From 08afa030756cd3209520f6db596605116bc246ac Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 1 Apr 2020 04:01:25 +0300 Subject: [PATCH 0261/4254] The raises list can now use expressions referencing the generic params --- compiler/pragmas.nim | 11 +++++++---- compiler/sem.nim | 1 + compiler/semdata.nim | 2 ++ compiler/sempass2.nim | 7 ++++++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 100ce1560..6816a1705 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -637,10 +637,13 @@ proc processPragma(c: PContext, n: PNode, i: int) = proc pragmaRaisesOrTags(c: PContext, n: PNode) = proc processExc(c: PContext, x: PNode) = - var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs) - if t.kind != tyObject: - localError(c.config, x.info, errGenerated, "invalid type for raises/tags list") - x.typ = t + if c.hasUnresolvedArgs(c, x): + x.typ = makeTypeFromExpr(c, x) + else: + var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs) + if t.kind != tyObject and not t.isMetaType: + localError(c.config, x.info, errGenerated, "invalid type for raises/tags list") + x.typ = t if n.kind in nkPragmaCallKinds and n.len == 2: let it = n[1] diff --git a/compiler/sem.nim b/compiler/sem.nim index 471a30099..1ced234f5 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -521,6 +521,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = c.semGenerateInstance = generateInstance c.semTypeNode = semTypeNode c.instTypeBoundOp = sigmatch.instTypeBoundOp + c.hasUnresolvedArgs = hasUnresolvedArgs pushProcCon(c, module) pushOwner(c, c.module) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index fbc9762f3..7ec4c423f 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -104,6 +104,8 @@ type semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.} + hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool + semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index a4e1dcf00..86149330e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1083,7 +1083,12 @@ proc track(tracked: PEffects, n: PNode) = for i in 0.. Date: Wed, 1 Apr 2020 04:45:44 +0300 Subject: [PATCH 0262/4254] Fix tests/types/tparameterizedparent0 --- compiler/semobjconstr.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index eeec42900..682e74440 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -336,7 +336,7 @@ proc semConstructTypeAux(c: PContext, let base = t[0] if base == nil: break t = skipTypes(base, skipPtrs) - if t.kind == tyGenericParam: + if t.kind != tyObject: # XXX: This is not supposed to happen, but apparently # there are some issues in semtypinst. Luckily, it # seems to affect only `computeRequiresInit`. From 484548c784f69cadc1f6480a24e99183a0e6a930 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 1 Apr 2020 14:34:24 +0200 Subject: [PATCH 0263/4254] revert stdlib changes which are not required anymore --- lib/pure/collections/sequtils.nim | 5 +++-- lib/pure/collections/sharedtables.nim | 18 ++++++++++-------- lib/pure/ioselects/ioselectors_epoll.nim | 3 ++- lib/pure/ioselects/ioselectors_kqueue.nim | 3 ++- lib/pure/ioselects/ioselectors_select.nim | 8 +------- lib/pure/parsecsv.nim | 4 ++-- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 893f31389..e32c784c6 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -371,8 +371,9 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): b = map(a, proc(x: int): string = $x) assert b == @["1", "2", "3", "4"] - result = newSeqOfCap[S](s.len) - for elem in s: result.add op(elem) + newSeq(result, s.len) + for i in 0 ..< s.len: + result[i] = op(s[i]) proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) {.inline.} = diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 96f934f50..2a1c0543f 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -77,7 +77,8 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, try: var hc: Hash var index = rawGet(t, key, hc) - if index >= 0: + let hasKey = index >= 0 + if hasKey: var value {.inject.} = addr(t.data[index].val) body finally: @@ -103,7 +104,8 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, try: var hc: Hash var index = rawGet(t, key, hc) - if index >= 0: + let hasKey = index >= 0 + if hasKey: var value {.inject.} = addr(t.data[index].val) body1 else: @@ -117,13 +119,13 @@ proc mget*[A, B](t: var SharedTable[A, B], key: A): var B = withLock t: var hc: Hash var index = rawGet(t, key, hc) - if index >= 0: - result = t.data[index].val + let hasKey = index >= 0 + if hasKey: result = t.data[index].val + if not hasKey: + when compiles($key): + raise newException(KeyError, "key not found: " & $key) else: - when compiles($key): - raise newException(KeyError, "key not found: " & $key) - else: - raise newException(KeyError, "key not found") + raise newException(KeyError, "key not found") proc mgetOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 002bddac5..bf13cc83e 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -502,7 +502,8 @@ proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) s.checkFd(fdi) - result = s.fds[fdi].data + if fdi in s: + result = s.fds[fdi].data proc setData*[T](s: Selector[T], fd: SocketHandle|int, data: T): bool = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index c5e19a011..83e15d479 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -600,7 +600,8 @@ proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) s.checkFd(fdi) - result = s.fds[fdi].data + if fdi in s: + result = s.fds[fdi].data proc setData*[T](s: Selector[T], fd: SocketHandle|int, data: T): bool = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 6a742df99..02a853b42 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -410,17 +410,11 @@ else: body proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = - # The compiler needs this to prove that all code paths return a value - result = (cast[ptr T](0'u))[] - s.withSelectLock(): let fdi = int(fd) for i in 0..= 0 - result = my.row[index] + if index >= 0: + result = my.row[index] when not defined(testing) and isMainModule: import os From 48169847265e13d3b12d670230ad6d33a9d384cc Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 1 Apr 2020 14:39:58 -0300 Subject: [PATCH 0264/4254] Documentation, add more examples (#13825) --- lib/posix/inotify.nim | 10 ++++++++++ lib/pure/concurrency/cpuinfo.nim | 8 +++++--- lib/pure/osproc.nim | 1 + lib/pure/stats.nim | 15 ++++++++------- lib/system/assertions.nim | 4 ++-- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim index f88e48a2d..9728b749b 100644 --- a/lib/posix/inotify.nim +++ b/lib/posix/inotify.nim @@ -70,3 +70,13 @@ proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint{. # Remove the watch specified by WD from the inotify instance FD. proc inotify_rm_watch*(fd: cint; wd: cint): cint{.cdecl, importc: "inotify_rm_watch", header: "".} + + +runnableExamples: + when defined(linux): + block: + let inoty: cint = inotify_init() ## Create 1 Inotify. + doAssert inoty >= 0 ## Check for errors. + let watchdoge: cint = inotify_add_watch(inoty, ".", IN_ALL_EVENTS) ## Add directory to watchdog. + doAssert watchdoge >= 0 ## Check for errors. + doAssert inotify_rm_watch(inoty, watchdoge) >= 0 ## Remove directory from the watchdog diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 51f80b103..3e5695360 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -49,9 +49,6 @@ when defined(haiku): proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = ## returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. - ## - ## .. code-block:: nim - ## block: doAssert countProcessors() >= 0 when defined(windows): type SYSTEM_INFO {.final, pure.} = object @@ -98,3 +95,8 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = else: result = sysconf(SC_NPROCESSORS_ONLN) if result <= 0: result = 0 + + +runnableExamples: + block: + doAssert countProcessors() > 0 diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9840973b2..92575e5f3 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -293,6 +293,7 @@ proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", proc countProcessors*(): int {.rtl, extern: "nosp$1".} = ## Returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. + ## It is implemented just calling `cpuinfo.countProcessors`. result = cpuinfo.countProcessors() proc execProcesses*(cmds: openArray[string], diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index ac48d9eee..8684cb60a 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -327,13 +327,14 @@ runnableExamples: var statistics: RunningStat ## Must be "var" statistics.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) doAssert statistics.n == 8 - doAssert statistics.mean() is SomeFloat - doAssert statistics.variance() is SomeFloat - doAssert statistics.varianceS() is SomeFloat - doAssert statistics.skewness() is SomeFloat - doAssert statistics.skewnessS() is SomeFloat - doAssert statistics.kurtosis() is SomeFloat - doAssert statistics.kurtosisS() is SomeFloat + template `===`(a, b: float): bool = (abs(a - b) < 1e-9) + doAssert statistics.mean() === 2.0 + doAssert statistics.variance() === 1.5 + doAssert statistics.varianceS() === 1.714285714285715 + doAssert statistics.skewness() === 0.8164965809277261 + doAssert statistics.skewnessS() === 1.018350154434631 + doAssert statistics.kurtosis() === -1.0 + doAssert statistics.kurtosisS() === -0.7000000000000008 when isMainModule: diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 13836a540..64ed44ea7 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -50,7 +50,7 @@ template assert*(cond: untyped, msg = "") = ## `command line switches `_. ## ## .. code-block:: nim - ## static: assert 1 == 9, "This works when not built with -d:danger or --assertions:off" + ## static: assert 1 == 9, "This assertion generates code when not built with -d:danger or --assertions:off" const expr = astToStr(cond) assertImpl(cond, msg, expr, compileOption("assertions")) @@ -58,7 +58,7 @@ template doAssert*(cond: untyped, msg = "") = ## Similar to ``assert`` but is always turned on regardless of ``--assertions``. ## ## .. code-block:: nim - ## static: assert 1 == 9, "This works when built with/without -d:danger or --assertions:off" + ## static: doAssert 1 == 9, "This assertion generates code when built with/without -d:danger or --assertions:off" const expr = astToStr(cond) assertImpl(cond, msg, expr, true) From bc37668c5a6f1664b34a16af2dee8aa9218b97a4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 1 Apr 2020 20:30:28 +0200 Subject: [PATCH 0265/4254] fixes #13782 (#13834) --- compiler/ccgcalls.nim | 75 ++++++++++++++++++++------- compiler/ccgstmts.nim | 3 ++ compiler/cgendata.nim | 1 + tests/destructor/tgotoexceptions4.nim | 22 +++++++- 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index de979f4a0..9155064a5 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -9,6 +9,18 @@ # # included from cgen.nim +proc canRaiseDisp(p: BProc; n: PNode): bool = + # we assume things like sysFatal cannot raise themselves + if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: + result = false + elif optPanics in p.config.globalOptions or + (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): + # we know we can be strict: + result = canRaise(n) + else: + # we have to be *very* conservative: + result = canRaiseConservative(n) + proc leftAppearsOnRightSide(le, ri: PNode): bool = if le != nil: for i in 1.. 1: pl.add(~", ") @@ -262,8 +300,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) genCallPattern() + if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) # no need for deep copying - else: + elif isHarmlessStore(p, canRaise, d): if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc @@ -272,10 +311,24 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] else: list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] - genAssignment(p, d, list, {}) # no need for deep copying + if canRaise: raiseExit(p) + else: + var tmp: TLoc + getTemp(p, typ[0], tmp) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.lode, OnUnknown) + if tfIterator in typ.flags: + list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] + else: + list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] + genAssignment(p, tmp, list, {}) + if canRaise: raiseExit(p) + genAssignment(p, d, tmp, {}) else: genCallPattern() + if canRaise: raiseExit(p) proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = if i < typ.len: @@ -557,18 +610,6 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add(~"];$n") line(p, cpsStmts, pl) -proc canRaiseDisp(p: BProc; n: PNode): bool = - # we assume things like sysFatal cannot raise themselves - if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: - result = false - elif optPanics in p.config.globalOptions or - (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): - # we know we can be strict: - result = canRaise(n) - else: - # we have to be *very* conservative: - result = canRaiseConservative(n) - proc genCall(p: BProc, e: PNode, d: var TLoc) = if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: genClosureCall(p, nil, e, d) @@ -579,8 +620,6 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) = else: genPrefixCall(p, nil, e, d) postStmtActions(p) - if p.config.exc == excGoto and canRaiseDisp(p, e[0]): - raiseExit(p) proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: @@ -592,5 +631,3 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = else: genPrefixCall(p, le, ri, d) postStmtActions(p) - if p.config.exc == excGoto and canRaiseDisp(p, ri[0]): - raiseExit(p) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c1012cede..bb9d30b8f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1203,6 +1203,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let fin = if t[^1].kind == nkFinally: t[^1] else: nil inc p.labels let lab = p.labels + let hasExcept = t[1].kind == nkExceptBranch + if hasExcept: inc p.withinTryWithExcept p.nestedTryStmts.add((fin, false, Natural lab)) p.flags.incl nimErrorFlagAccessed @@ -1277,6 +1279,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) endBlock(p) if p.prc != nil: raiseExit(p) + if hasExcept: inc p.withinTryWithExcept proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # code to generate: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 326bdeb45..bf7daeea6 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -95,6 +95,7 @@ type splitDecls*: int # > 0 if we are in some context for C++ that # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) + withinTryWithExcept*: int # required for goto based exception handling sigConflicts*: CountTable[string] TTypeSeq* = seq[PType] diff --git a/tests/destructor/tgotoexceptions4.nim b/tests/destructor/tgotoexceptions4.nim index 918169084..b2b481256 100644 --- a/tests/destructor/tgotoexceptions4.nim +++ b/tests/destructor/tgotoexceptions4.nim @@ -4,7 +4,9 @@ discard """ caught in fun caughtsome msgMyExcept in finally -caught1''' +caught1 +123 +123''' """ when true: @@ -38,3 +40,21 @@ when true: except CatchableError: echo "caught1" funB() + +# bug #13782 + +import strutils +var n = 123 + +try: n = parseInt("xxx") +except: discard + +echo n + +proc sameTestButForLocalVar = + var n = 123 + try: n = parseInt("xxx") + except: discard + echo n + +sameTestButForLocalVar() From 95997570681a2d2d451fa96058973b601444d272 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 1 Apr 2020 16:46:47 -0300 Subject: [PATCH 0266/4254] Add browsers.openDefaultBrowser without URL, implements IETF RFC-6694 Section-3 (#13835) --- changelog.md | 2 ++ lib/pure/browsers.nim | 52 +++++++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index b5eaba7c8..965320cc7 100644 --- a/changelog.md +++ b/changelog.md @@ -123,6 +123,8 @@ echo f retrieving the verified certificate chain of the peer we are connected to through an SSL-wrapped `Socket`/`AsyncSocket`. - Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` +- Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. + ## Library changes diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 66652bbc1..85b229983 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -13,6 +13,7 @@ ## Unstable API. import strutils +include "system/inclrtl" when defined(windows): import winlean @@ -24,20 +25,8 @@ const osOpenCmd* = ## Alias for the operating system specific *"open"* command, ## ``"open"`` on MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc. -proc openDefaultBrowser*(url: string) = - ## Opens `url` with the user's default browser. This does not block. - ## The URL must not be empty string. - ## - ## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open`` - ## command is used. Under Unix, it is checked if ``xdg-open`` exists and - ## used if it does. Otherwise the environment variable ``BROWSER`` is - ## used to determine the default browser to use. - ## - ## This proc doesn't raise an exception on error, beware. - ## - ## .. code-block:: nim - ## block: openDefaultBrowser("https://nim-lang.org") - doAssert url.len > 0, "URL must not be empty string" + +template openDefaultBrowserImpl(url: string) = when defined(windows): var o = newWideCString(osOpenCmd) var u = newWideCString(url) @@ -54,3 +43,38 @@ proc openDefaultBrowser*(url: string) = return except OSError: discard + +proc openDefaultBrowser*(url: string) = + ## Opens `url` with the user's default browser. This does not block. + ## The URL must not be empty string, to open on a blank page see `openDefaultBrowser()`. + ## + ## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open`` + ## command is used. Under Unix, it is checked if ``xdg-open`` exists and + ## used if it does. Otherwise the environment variable ``BROWSER`` is + ## used to determine the default browser to use. + ## + ## This proc doesn't raise an exception on error, beware. + ## + ## .. code-block:: nim + ## block: openDefaultBrowser("https://nim-lang.org") + doAssert url.len > 0, "URL must not be empty string" + openDefaultBrowserImpl(url) + +proc openDefaultBrowser*() {.since: (1, 1).} = + ## Opens the user's default browser without any `url` (blank page). This does not block. + ## Implements IETF RFC-6694 Section 3, "about:blank" must be reserved for a blank page. + ## + ## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open`` + ## command is used. Under Unix, it is checked if ``xdg-open`` exists and + ## used if it does. Otherwise the environment variable ``BROWSER`` is + ## used to determine the default browser to use. + ## + ## This proc doesn't raise an exception on error, beware. + ## + ## **See also:** + ## + ## * https://tools.ietf.org/html/rfc6694#section-3 + ## + ## .. code-block:: nim + ## block: openDefaultBrowser() + openDefaultBrowserImpl("http:about:blank") # See IETF RFC-6694 Section 3. From 9102ac8c7dda7abf6efee4cf0e104d415894e730 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 1 Apr 2020 20:05:55 -0300 Subject: [PATCH 0267/4254] Documentation and Code Style inotify (#13836) --- lib/posix/inotify.nim | 105 +++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim index 9728b749b..79b408425 100644 --- a/lib/posix/inotify.nim +++ b/lib/posix/inotify.nim @@ -7,76 +7,77 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - # Get the platform-dependent flags. # Structure describing an inotify event. type - InotifyEvent*{.pure, final, importc: "struct inotify_event", - header: "".} = object - wd*{.importc: "wd".}: cint # Watch descriptor. - mask*{.importc: "mask".}: uint32 # Watch mask. - cookie*{.importc: "cookie".}: uint32 # Cookie to synchronize two events. - len*{.importc: "len".}: uint32 # Length (including NULs) of name. - name*{.importc: "name".}: char # Name. + InotifyEvent* {.pure, final, importc: "struct inotify_event", + header: "".} = object ## An Inotify event. + wd* {.importc: "wd".}: FileHandle ## Watch descriptor. + mask* {.importc: "mask".}: uint32 ## Watch mask. + cookie* {.importc: "cookie".}: uint32 ## Cookie to synchronize two events. + len* {.importc: "len".}: uint32 ## Length (including NULs) of name. + name* {.importc: "name".}: char ## Name. # Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH. const - IN_ACCESS* = 0x00000001 # File was accessed. - IN_MODIFY* = 0x00000002 # File was modified. - IN_ATTRIB* = 0x00000004 # Metadata changed. - IN_CLOSE_WRITE* = 0x00000008 # Writtable file was closed. - IN_CLOSE_NOWRITE* = 0x00000010 # Unwrittable file closed. - IN_CLOSE* = (IN_CLOSE_WRITE or IN_CLOSE_NOWRITE) # Close. - IN_OPEN* = 0x00000020 # File was opened. - IN_MOVED_FROM* = 0x00000040 # File was moved from X. - IN_MOVED_TO* = 0x00000080 # File was moved to Y. - IN_MOVE* = (IN_MOVED_FROM or IN_MOVED_TO) # Moves. - IN_CREATE* = 0x00000100 # Subfile was created. - IN_DELETE* = 0x00000200 # Subfile was deleted. - IN_DELETE_SELF* = 0x00000400 # Self was deleted. - IN_MOVE_SELF* = 0x00000800 # Self was moved. + IN_ACCESS* = 0x00000001 ## File was accessed. + IN_MODIFY* = 0x00000002 ## File was modified. + IN_ATTRIB* = 0x00000004 ## Metadata changed. + IN_CLOSE_WRITE* = 0x00000008 ## Writtable file was closed. + IN_CLOSE_NOWRITE* = 0x00000010 ## Unwrittable file closed. + IN_CLOSE* = (IN_CLOSE_WRITE or IN_CLOSE_NOWRITE) ## Close. + IN_OPEN* = 0x00000020 ## File was opened. + IN_MOVED_FROM* = 0x00000040 ## File was moved from X. + IN_MOVED_TO* = 0x00000080 ## File was moved to Y. + IN_MOVE* = (IN_MOVED_FROM or IN_MOVED_TO) ## Moves. + IN_CREATE* = 0x00000100 ## Subfile was created. + IN_DELETE* = 0x00000200 ## Subfile was deleted. + IN_DELETE_SELF* = 0x00000400 ## Self was deleted. + IN_MOVE_SELF* = 0x00000800 ## Self was moved. + # Events sent by the kernel. const - IN_UNMOUNT* = 0x00002000 # Backing fs was unmounted. - IN_Q_OVERFLOW* = 0x00004000 # Event queued overflowed. - IN_IGNORED* = 0x00008000 # File was ignored. + IN_UNMOUNT* = 0x00002000 ## Backing fs was unmounted. + IN_Q_OVERFLOW* = 0x00004000 ## Event queued overflowed. + IN_IGNORED* = 0x00008000 ## File was ignored. + # Special flags. const - IN_ONLYDIR* = 0x01000000 # Only watch the path if it is a - # directory. - IN_DONT_FOLLOW* = 0x02000000 # Do not follow a sym link. - IN_EXCL_UNLINK* = 0x04000000 # Exclude events on unlinked - # objects. - IN_MASK_ADD* = 0x20000000 # Add to the mask of an already - # existing watch. - IN_ISDIR* = 0x40000000 # Event occurred against dir. - IN_ONESHOT* = 0x80000000 # Only send event once. + IN_ONLYDIR* = 0x01000000 ## Only watch the path if it is a directory. + IN_DONT_FOLLOW* = 0x02000000 ## Do not follow a sym link. + IN_EXCL_UNLINK* = 0x04000000 ## Exclude events on unlinked objects. + IN_MASK_ADD* = 0x20000000 ## Add to the mask of an already existing watch. + IN_ISDIR* = 0x40000000 ## Event occurred against dir. + IN_ONESHOT* = 0x80000000 ## Only send event once. + # All events which a program can wait on. const IN_ALL_EVENTS* = (IN_ACCESS or IN_MODIFY or IN_ATTRIB or IN_CLOSE_WRITE or IN_CLOSE_NOWRITE or IN_OPEN or IN_MOVED_FROM or IN_MOVED_TO or IN_CREATE or IN_DELETE or IN_DELETE_SELF or IN_MOVE_SELF) -# Create and initialize inotify instance. -proc inotify_init*(): cint{.cdecl, importc: "inotify_init", - header: "".} -# Create and initialize inotify instance. -proc inotify_init1*(flags: cint): cint{.cdecl, importc: "inotify_init1", + + +proc inotify_init*(): FileHandle {.cdecl, importc: "inotify_init", header: "".} -# Add watch of object NAME to inotify instance FD. Notify about -# events specified by MASK. -proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint{. - cdecl, importc: "inotify_add_watch", header: "".} -# Remove the watch specified by WD from the inotify instance FD. -proc inotify_rm_watch*(fd: cint; wd: cint): cint{.cdecl, + ## Create and initialize inotify instance. + +proc inotify_init1*(flags: cint): FileHandle {.cdecl, importc: "inotify_init1", + header: "".} + ## Create and initialize inotify instance. + +proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint {.cdecl, + importc: "inotify_add_watch", header: "".} + ## Add watch of object NAME to inotify instance FD. Notify about events specified by MASK. + +proc inotify_rm_watch*(fd: cint; wd: cint): cint {.cdecl, importc: "inotify_rm_watch", header: "".} + ## Remove the watch specified by WD from the inotify instance FD. runnableExamples: when defined(linux): - block: - let inoty: cint = inotify_init() ## Create 1 Inotify. - doAssert inoty >= 0 ## Check for errors. - let watchdoge: cint = inotify_add_watch(inoty, ".", IN_ALL_EVENTS) ## Add directory to watchdog. - doAssert watchdoge >= 0 ## Check for errors. - doAssert inotify_rm_watch(inoty, watchdoge) >= 0 ## Remove directory from the watchdog + let inoty: FileHandle = inotify_init() ## Create 1 Inotify. + doAssert inoty >= 0 ## Check for errors (FileHandle is alias to cint). + let watchdoge: cint = inotify_add_watch(inoty, ".", IN_ALL_EVENTS) ## Add directory to watchdog. + doAssert watchdoge >= 0 ## Check for errors. + doAssert inotify_rm_watch(inoty, watchdoge) >= 0 ## Remove directory from the watchdog From afd0afe0a3febc5ed2888dbca23e75c06741668e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 1 Apr 2020 21:56:18 -0300 Subject: [PATCH 0268/4254] Deprecate when declared(echo):echo (#13840) --- compiler/astalgo.nim | 136 +++++++++++++++++++++---------------------- compiler/dfa.nim | 3 +- compiler/lookups.nim | 19 +++--- lib/pure/osproc.nim | 2 +- 4 files changed, 79 insertions(+), 81 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index bd60ddd7d..47cf83715 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -24,55 +24,55 @@ proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope -when declared(echo): - # these are for debugging only: They are not really deprecated, but I want - # the warning so that release versions do not contain debugging statements: - proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.} - proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.} - proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.} - proc typekinds*(t: PType) {.deprecated.} = - var t = t - var s = "" - while t != nil and t.len > 0: - s.add $t.kind - s.add " " - t = t.lastSon - echo s +# these are for debugging only: They are not really deprecated, but I want +# the warning so that release versions do not contain debugging statements: +proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.} +proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.} +proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.} - template debug*(x: PSym|PType|PNode) {.deprecated.} = - when compiles(c.config): - debug(c.config, x) - elif compiles(c.graph.config): - debug(c.graph.config, x) +proc typekinds*(t: PType) {.deprecated.} = + var t = t + var s = "" + while t != nil and t.len > 0: + s.add $t.kind + s.add " " + t = t.lastSon + echo s + +template debug*(x: PSym|PType|PNode) {.deprecated.} = + when compiles(c.config): + debug(c.config, x) + elif compiles(c.graph.config): + debug(c.graph.config, x) + else: + error() + +template debug*(x: auto) {.deprecated.} = + echo x + +template mdbg*: bool {.deprecated.} = + when compiles(c.graph): + c.module.fileIdx == c.graph.config.projectMainIdx + elif compiles(c.module): + c.module.fileIdx == c.config.projectMainIdx + elif compiles(c.c.module): + c.c.module.fileIdx == c.c.config.projectMainIdx + elif compiles(m.c.module): + m.c.module.fileIdx == m.c.config.projectMainIdx + elif compiles(cl.c.module): + cl.c.module.fileIdx == cl.c.config.projectMainIdx + elif compiles(p): + when compiles(p.lex): + p.lex.fileIdx == p.lex.config.projectMainIdx else: - error() - - template debug*(x: auto) {.deprecated.} = - echo x - - template mdbg*: bool {.deprecated.} = - when compiles(c.graph): - c.module.fileIdx == c.graph.config.projectMainIdx - elif compiles(c.module): - c.module.fileIdx == c.config.projectMainIdx - elif compiles(c.c.module): - c.c.module.fileIdx == c.c.config.projectMainIdx - elif compiles(m.c.module): - m.c.module.fileIdx == m.c.config.projectMainIdx - elif compiles(cl.c.module): - cl.c.module.fileIdx == cl.c.config.projectMainIdx - elif compiles(p): - when compiles(p.lex): - p.lex.fileIdx == p.lex.config.projectMainIdx - else: - p.module.module.fileIdx == p.config.projectMainIdx - elif compiles(m.module.fileIdx): - m.module.fileIdx == m.config.projectMainIdx - elif compiles(L.fileIdx): - L.fileIdx == L.config.projectMainIdx - else: - error() + p.module.module.fileIdx == p.config.projectMainIdx + elif compiles(m.module.fileIdx): + m.module.fileIdx == m.config.projectMainIdx + elif compiles(L.fileIdx): + L.fileIdx == L.config.projectMainIdx + else: + error() # --------------------------- ident tables ---------------------------------- proc idTableGet*(t: TIdTable, key: PIdObj): RootRef @@ -628,30 +628,30 @@ proc value(this: var DebugPrinter; value: PNode) = this.closeCurly -when declared(echo): - proc debug(n: PSym; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - this.renderSymType = true - this.useColor = not defined(windows) - this.value(n) - echo($this.res) - proc debug(n: PType; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - this.renderSymType = true - this.useColor = not defined(windows) - this.value(n) - echo($this.res) +proc debug(n: PSym; conf: ConfigRef) = + var this: DebugPrinter + this.visited = initTable[pointer, int]() + this.renderSymType = true + this.useColor = not defined(windows) + this.value(n) + echo($this.res) - proc debug(n: PNode; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - #this.renderSymType = true - this.useColor = not defined(windows) - this.value(n) - echo($this.res) +proc debug(n: PType; conf: ConfigRef) = + var this: DebugPrinter + this.visited = initTable[pointer, int]() + this.renderSymType = true + this.useColor = not defined(windows) + this.value(n) + echo($this.res) + +proc debug(n: PNode; conf: ConfigRef) = + var this: DebugPrinter + this.visited = initTable[pointer, int]() + #this.renderSymType = true + this.useColor = not defined(windows) + this.value(n) + echo($this.res) proc nextTry(h, maxHash: Hash): Hash = result = ((5 * h) + 1) and maxHash diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0f23d7f1a..e4cadde5b 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -91,8 +91,7 @@ proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} = ## echos the ControlFlowGraph for debugging purposes. var buf = "" codeListing(c, buf, start, last) - when declared(echo): - echo buf + echo buf proc forkI(c: var Con; n: PNode): TPosition = result = TPosition(c.code.len) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 8c231212d..fe0e6fe7c 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -100,16 +100,15 @@ proc searchInScopes*(c: PContext, s: PIdent): PSym = if result != nil: return result = nil -when declared(echo): - proc debugScopes*(c: PContext; limit=0) {.deprecated.} = - var i = 0 - for scope in walkScopes(c.currentScope): - echo "scope ", i - for h in 0..high(scope.symbols.data): - if scope.symbols.data[h] != nil: - echo scope.symbols.data[h].name.s - if i == limit: break - inc i +proc debugScopes*(c: PContext; limit=0) {.deprecated.} = + var i = 0 + for scope in walkScopes(c.currentScope): + echo "scope ", i + for h in 0..high(scope.symbols.data): + if scope.symbols.data[h] != nil: + echo scope.symbols.data[h].name.s + if i == limit: break + inc i proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym = for scope in walkScopes(c.currentScope): diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 92575e5f3..1472d4e3d 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -892,7 +892,7 @@ elif not defined(useNimRtl): # Parent process. Copy process information. if poEchoCmd in options: - when declared(echo): echo(command, " ", join(args, " ")) + echo(command, " ", join(args, " ")) result.id = pid result.exitFlag = false From 46ca19ff18ef3db72abf740da7795eb84306305e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 1 Apr 2020 21:58:43 -0300 Subject: [PATCH 0269/4254] Deprecate DCE:on (#13839) --- lib/impure/db_sqlite.nim | 2 -- lib/impure/rdstdin.nim | 1 - lib/posix/epoll.nim | 2 -- lib/posix/linux.nim | 2 -- lib/posix/posix.nim | 1 - lib/posix/posix_macos_amd64.nim | 2 -- lib/posix/posix_openbsd_amd64.nim | 2 -- lib/posix/posix_other.nim | 2 -- lib/posix/posix_utils.nim | 2 -- lib/posix/termios.nim | 1 - lib/pure/fenv.nim | 2 -- lib/pure/net.nim | 1 - lib/pure/parseutils.nim | 3 --- lib/pure/ropes.nim | 2 -- lib/pure/strmisc.nim | 2 -- lib/pure/unicode.nim | 3 --- lib/windows/winlean.nim | 2 -- lib/wrappers/iup.nim | 2 -- lib/wrappers/mysql.nim | 1 - lib/wrappers/odbcsql.nim | 2 -- lib/wrappers/openssl.nim | 1 - lib/wrappers/pcre.nim | 2 -- lib/wrappers/postgres.nim | 1 - lib/wrappers/sqlite3.nim | 2 -- 24 files changed, 43 deletions(-) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index f182ae65a..74ba169aa 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -113,8 +113,6 @@ ## * `db_mysql module `_ for MySQL database wrapper ## * `db_postgres module `_ for PostgreSQL database wrapper -{.deadCodeElim: on.} # dce option deprecated - import sqlite3 import db_common diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 670b5ab72..9dbbd97ae 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -20,7 +20,6 @@ ## var userResponse: string ## doAssert readLineFromStdin("How are you?:", line = userResponse) ## echo userResponse -{.deadCodeElim: on.} # dce option deprecated when defined(Windows): proc readLineFromStdin*(prompt: string): TaintedString {. diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 2236bb16b..74433631d 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - from posix import SocketHandle const diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim index 25c7c7979..680b61461 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -1,5 +1,3 @@ -{.deadCodeElim: on.} # dce option deprecated - import posix const diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index f69d42cdd..dbc9f5109 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -33,7 +33,6 @@ # Dead code elimination ensures that we don't accidentally generate #includes # for files that might not exist on a specific platform! The user will get an # error only if they actually try to use the missing declaration -{.deadCodeElim: on.} # dce option deprecated when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 8a20d127f..536d51be5 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index d9ac84a1d..408e42255 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index e42092513..8213f796c 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 5600a5db5..5dbb163ca 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -11,8 +11,6 @@ # Where possible, contribute OS-independent procs in `os `_ instead. -{.deadCodeElim: on.} # dce option deprecated - import posix type Uname* = object diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 6a7ffb33e..b03ce74f3 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -7,7 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated import posix type diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index 6da6aedad..53b3e3b50 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -10,8 +10,6 @@ ## Floating-point environment. Handling of floating-point rounding and ## exceptions (overflow, division by zero, etc.). -{.deadCodeElim: on.} # dce option deprecated - when defined(Posix) and not defined(genode): {.passl: "-lm".} diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 261f83583..593e5c76e 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -66,7 +66,6 @@ include "system/inclrtl" -{.deadCodeElim: on.} # dce option deprecated import nativesockets, os, strutils, times, sets, options, std/monotimes from ssl_certs import scanSSLCertificates export nativesockets.Port, nativesockets.`$`, nativesockets.`==` diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 6116751ff..c358005f1 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -45,9 +45,6 @@ ## * `parsexml module`_ for a XML / HTML parser ## * `other parsers`_ for other parsers - -{.deadCodeElim: on.} # dce option deprecated - {.push debugger: off.} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 1205584db..f5023cb6c 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -19,8 +19,6 @@ include "system/inclrtl" import streams -{.deadCodeElim: on.} # dce option deprecated - {.push debugger: off.} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 43437ddb4..02bbdbcf4 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -12,8 +12,6 @@ import strutils -{.deadCodeElim: on.} # dce option deprecated - proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, procvar.} = ## Expand tab characters in `s` replacing them by spaces. diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index d166721d1..65509b2b2 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -20,9 +20,6 @@ ## * `unidecode module `_ ## * `encodings module `_ - -{.deadCodeElim: on.} # dce option deprecated - include "system/inclrtl" type diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 13a70d6ef..ee8c2343a 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -10,8 +10,6 @@ ## This module implements a small wrapper for some needed Win API procedures, ## so that the Nim compiler does not depend on the huge Windows module. -{.deadCodeElim: on.} # dce option deprecated - import dynlib when defined(nimHasStyleChecks): diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim index 1a9e6ab3e..3c1ff1483 100644 --- a/lib/wrappers/iup.nim +++ b/lib/wrappers/iup.nim @@ -34,8 +34,6 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # **************************************************************************** -{.deadCodeElim: on.} # dce option deprecated - when defined(windows): const dllname = "iup(|30|27|26|25|24).dll" elif defined(macosx): diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim index f8d4739ae..209f63c21 100644 --- a/lib/wrappers/mysql.nim +++ b/lib/wrappers/mysql.nim @@ -7,7 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated {.push, callconv: cdecl.} when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim index 14dd10ae3..be56b75d3 100644 --- a/lib/wrappers/odbcsql.nim +++ b/lib/wrappers/odbcsql.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - when not defined(ODBCVER): const ODBCVER = 0x0351 ## define ODBC version 3.51 by default diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 94da4fc79..9dafe2300 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -22,7 +22,6 @@ ## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim ## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passl:-lcrypto --passl:-lssl -r tests/untestable/tssl.nim -{.deadCodeElim: on.} # dce option deprecated when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim index 7012053b7..9144f6784 100644 --- a/lib/wrappers/pcre.nim +++ b/lib/wrappers/pcre.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - # The current PCRE version information. const diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim index c90116ea2..24eac54f9 100644 --- a/lib/wrappers/postgres.nim +++ b/lib/wrappers/postgres.nim @@ -15,7 +15,6 @@ # connection-protocol. # -{.deadCodeElim: on.} # dce option deprecated when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim index f4ec6180f..6fc6c7aa7 100644 --- a/lib/wrappers/sqlite3.nim +++ b/lib/wrappers/sqlite3.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} # dce option deprecated - when defined(nimHasStyleChecks): {.push styleChecks: off.} From 160d5fe589abd3878f56720bb764b82447e47b10 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 2 Apr 2020 03:47:45 -0300 Subject: [PATCH 0270/4254] Jsconsole update (#12448) * Improve jsconsole adding the rest of the stable api as documented on the standard at https://developer.mozilla.org/docs/Web/API/Console * Improve jsconsole, add runnableexamples * Simplify jsconsole --- changelog.md | 1 + lib/js/jsconsole.nim | 71 ++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/changelog.md b/changelog.md index 965320cc7..2e6da90aa 100644 --- a/changelog.md +++ b/changelog.md @@ -124,6 +124,7 @@ echo f through an SSL-wrapped `Socket`/`AsyncSocket`. - Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` - Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. +- Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target. ## Library changes diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index 199a5607e..35afd95ad 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -13,57 +13,58 @@ when not defined(js) and not defined(Nimdoc): {.error: "This module only works on the JavaScript platform".} -import macros +type Console* = ref object of RootObj -type Console* {.importc.} = ref object of RootObj +proc log*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/log -proc convertToConsoleLoggable*[T](v: T): RootRef {.importcpp: "#".} -template convertToConsoleLoggable*(v: string): RootRef = cast[RootRef](cstring(v)) +proc debug*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/debug -proc logImpl(console: Console) {.importcpp: "log", varargs.} -proc debugImpl(console: Console) {.importcpp: "debug", varargs.} -proc infoImpl(console: Console) {.importcpp: "info", varargs.} -proc errorImpl(console: Console) {.importcpp: "error", varargs.} -proc warnImpl(console: Console) {.importcpp: "warn", varargs.} +proc info*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/info -proc makeConsoleCall(console: NimNode, procName: NimNode, args: NimNode): NimNode = - result = newCall(procName, console) - for c in args: result.add(c) +proc error*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/error -macro log*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = - makeConsoleCall(console, bindSym "logImpl", args) +template exception*(console: Console, args: varargs[untyped]) = + ## Alias for `console.error()`. + error(console, args) -macro debug*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = - makeConsoleCall(console, bindSym "debugImpl", args) +proc trace*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/trace -macro info*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = - makeConsoleCall(console, bindSym "infoImpl", args) +proc warn*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/warn -macro error*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = - makeConsoleCall(console, bindSym "errorImpl", args) +proc clear*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/clear +proc count*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/count -macro warn*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = - ## https://developer.mozilla.org/en-US/docs/Web/API/Console/warn - makeConsoleCall(console, bindSym "warnImpl", args) +proc countReset*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/countReset -proc clear*(console: Console) {.importcpp: "clear".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/clear +proc group*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/group -proc count*(console: Console, label = "".cstring) {.importcpp: "count".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/count +proc groupCollapsed*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/groupCollapsed -proc countReset*(console: Console, label = "".cstring) {.importcpp: "countReset".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/countReset +proc groupEnd*(console: Console) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/groupEnd -proc group*(console: Console, label = "".cstring) {.importcpp: "group".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/group +proc time*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/time -proc groupCollapsed*(console: Console, label = "".cstring) {.importcpp: "groupCollapsed".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/groupCollapsed +proc timeEnd*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/timeEnd -proc groupEnd*(console: Console) {.importcpp: "groupEnd".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/groupEnd - -proc time*(console: Console, label = "".cstring) {.importcpp: "time".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/time - -proc timeEnd*(console: Console, label = "".cstring) {.importcpp: "timeEnd".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd - -proc timeLog*(console: Console, label = "".cstring) {.importcpp: "timeLog".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeLog +proc timeLog*(console: Console, label = "".cstring) {.importcpp.} + ## https://developer.mozilla.org/docs/Web/API/Console/timeLog +proc table*(console: Console) {.importcpp, varargs.} + ## https://developer.mozilla.org/docs/Web/API/Console/table var console* {.importc, nodecl.}: Console From c1672617350ff1b0b2c6d352d026c87729a056f0 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 2 Apr 2020 03:48:09 -0300 Subject: [PATCH 0271/4254] Deprecate PHP (#13838) --- lib/system/gc_regions.nim | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index 38365469e..7dab50072 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -8,22 +8,7 @@ # "Stack GC" for embedded devices or ultra performance requirements. -when defined(nimphpext): - proc roundup(x, v: int): int {.inline.} = - result = (x + (v-1)) and not (v-1) - proc emalloc(size: int): pointer {.importc: "_emalloc".} - proc efree(mem: pointer) {.importc: "_efree".} - - proc osAllocPages(size: int): pointer {.inline.} = - emalloc(size) - - proc osTryAllocPages(size: int): pointer {.inline.} = - emalloc(size) - - proc osDeallocPages(p: pointer, size: int) {.inline.} = - efree(p) - -elif defined(useMalloc): +when defined(useMalloc): proc roundup(x, v: int): int {.inline.} = result = (x + (v-1)) and not (v-1) proc emalloc(size: int): pointer {.importc: "malloc", header: "".} From 68539a2926dd5937e6af640ead200726b46b80b6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Apr 2020 23:53:52 -0700 Subject: [PATCH 0272/4254] fix last remaining warning when building nim (`intVal should be Int128`) + minor cleanups (#13841) --- compiler/ast.nim | 16 +++++++++------- compiler/int128.nim | 30 +++++++++++++++--------------- compiler/semfold.nim | 27 ++++----------------------- compiler/types.nim | 3 +-- 4 files changed, 29 insertions(+), 47 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index f4f680811..d7d0ef224 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -456,6 +456,9 @@ const tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + tyTypeClasses tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst} + # consider renaming as `tyAbstractVarRange` + abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, + tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} type TTypeKinds* = set[TTypeKind] @@ -1272,12 +1275,8 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType = while result.kind in kinds: result = lastSon(result) proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = - - # this is dirty. abstractVarRange isn't defined yet and therefore it - # is duplicated here. - const abstractVarRange = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, - tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} - case skipTypes(typ, abstractVarRange).kind + let kind = skipTypes(typ, abstractVarRange).kind + case kind of tyInt: result = newNode(nkIntLit) of tyInt8: result = newNode(nkInt8Lit) of tyInt16: result = newNode(nkInt16Lit) @@ -1289,9 +1288,12 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = of tyUInt16: result = newNode(nkUInt16Lit) of tyUInt32: result = newNode(nkUInt32Lit) of tyUInt64: result = newNode(nkUInt64Lit) - else: # tyBool, tyEnum + of tyBool,tyEnum: # XXX: does this really need to be the kind nkIntLit? result = newNode(nkIntLit) + of tyStatic: # that's a pre-existing bug, will fix in another PR + result = newNode(nkIntLit) + else: doAssert false, $kind result.intVal = intVal result.typ = typ diff --git a/compiler/int128.nim b/compiler/int128.nim index ebcd226ec..067edeeed 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -29,27 +29,27 @@ template high*(t: typedesc[Int128]): Int128 = Max proc `$`*(a: Int128): string -proc toInt128*[T: SomeInteger](arg: T): Int128 = - when T is SomeUnsignedInt: +proc toInt128*[T: SomeInteger | bool](arg: T): Int128 = + when T is bool: result.sdata(0) = int32(arg) + elif T is SomeUnsignedInt: when sizeof(arg) <= 4: result.udata[0] = uint32(arg) else: result.udata[0] = uint32(arg and T(0xffffffff)) result.udata[1] = uint32(arg shr 32) + elif sizeof(arg) <= 4: + result.sdata(0) = int32(arg) + if arg < 0: # sign extend + result.sdata(1) = -1 + result.sdata(2) = -1 + result.sdata(3) = -1 else: - when sizeof(arg) <= 4: - result.sdata(0) = int32(arg) - if arg < 0: # sign extend - result.sdata(1) = -1 - result.sdata(2) = -1 - result.sdata(3) = -1 - else: - let tmp = int64(arg) - result.udata[0] = uint32(tmp and 0xffffffff) - result.sdata(1) = int32(tmp shr 32) - if arg < 0: # sign extend - result.sdata(2) = -1 - result.sdata(3) = -1 + let tmp = int64(arg) + result.udata[0] = uint32(tmp and 0xffffffff) + result.sdata(1) = int32(tmp shr 32) + if arg < 0: # sign extend + result.sdata(2) = -1 + result.sdata(3) = -1 template isNegative(arg: Int128): bool = arg.sdata(3) < 0 diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 4131347a2..f0971bf09 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -20,26 +20,6 @@ proc errorType*(g: ModuleGraph): PType = result = newType(tyError, g.owners[^1]) result.flags.incl tfCheckedForDestructor -proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode {.deprecated: "intVal should be Int128".} = - case skipTypes(n.typ, abstractVarRange).kind - of tyInt: - result = newIntNode(nkIntLit, intVal) - # See bug #6989. 'pred' et al only produce an int literal type if the - # original type was 'int', not a distinct int etc. - if n.typ.kind == tyInt: - result.typ = getIntLitType(g, result) - else: - result.typ = n.typ - # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ... - #setIntLitType(result) - of tyChar: - result = newIntNode(nkCharLit, intVal) - result.typ = n.typ - else: - result = newIntNode(nkIntLit, intVal) - result.typ = n.typ - result.info = n.info - proc newIntNodeT*(intVal: Int128, n: PNode; g: ModuleGraph): PNode = result = newIntTypeNode(intVal, n.typ) # See bug #6989. 'pred' et al only produce an int literal type if the @@ -436,12 +416,13 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = of tyBool: case srcTyp.kind of tyFloat..tyFloat64: - result = newIntNodeT(int(getFloat(a) != 0.0), n, g) + result = newIntNodeT(toInt128(getFloat(a) != 0.0), n, g) of tyChar, tyUInt..tyUInt64, tyInt..tyInt64: - result = newIntNodeT(int(a.getOrdValue != 0), n, g) - else: + result = newIntNodeT(toInt128(a.getOrdValue != 0), n, g) + of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`? result = a result.typ = n.typ + else: doAssert false, $srcTyp.kind of tyInt..tyInt64, tyUInt..tyUInt64: case srcTyp.kind of tyFloat..tyFloat64: diff --git a/compiler/types.nim b/compiler/types.nim index 38dc15498..ecbe371e2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -63,8 +63,7 @@ const tyAlias, tyInferred, tySink, tyLent, tyOwned} abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} - abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, - tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} + # see also ast.abstractVarRange abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} abstractInstOwned* = abstractInst + {tyOwned} From d01245e501c3d90449383d055da9cb1fe5a24a7f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 2 Apr 2020 11:52:31 +0200 Subject: [PATCH 0273/4254] renamed new std/pragmas.nim to std/byaddr.nim (#13844) * renamed new std/pragmas.nim to std/byaddr.nim * minor code cleanup --- changelog.md | 4 ++-- lib/std/{pragmas.nim => byaddr.nim} | 10 +++++----- tests/stdlib/{tpragmas.nim => tbyaddr.nim} | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename lib/std/{pragmas.nim => byaddr.nim} (72%) rename tests/stdlib/{tpragmas.nim => tbyaddr.nim} (98%) diff --git a/changelog.md b/changelog.md index 2e6da90aa..7dccc20b9 100644 --- a/changelog.md +++ b/changelog.md @@ -152,7 +152,7 @@ echo f - `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs - `net.newContext` now performs SSL Certificate checking on Linux and OSX. Define `nimDisableCertificateValidation` to disable it globally. -- new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by `import pragmas` +- new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by `import std/byaddr` - new module `std/stackframes`, in particular `setFrameMsg` which enables custom runtime annotation of stackframes, see #13351 for examples. Turn on/off via `--stackTraceMsgs:on/off` @@ -166,7 +166,7 @@ echo f of `=destroy` and `copyMem` to move objects efficiently. - `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for non builtin pragmas, - enabling things like lvalue references, see `pragmas.byaddr` + enabling things like lvalue references, see `byaddr.byaddr` - `macro pragmas` can now be used in type sections. diff --git a/lib/std/pragmas.nim b/lib/std/byaddr.nim similarity index 72% rename from lib/std/pragmas.nim rename to lib/std/byaddr.nim index 5dce04c11..dd7d19da7 100644 --- a/lib/std/pragmas.nim +++ b/lib/std/byaddr.nim @@ -1,9 +1,9 @@ # see `semLowerLetVarCustomPragma` for compiler support that enables these # lowerings -template byaddr*(lhs, typ, expr) = +template byaddr*(lhs, typ, ex) = ## Allows a syntax for lvalue reference, exact analog to - ## `auto& a = expr;` in C++ + ## `auto& a = ex;` in C++ runnableExamples: var s = @[10,11,12] var a {.byaddr.} = s[0] @@ -12,8 +12,8 @@ template byaddr*(lhs, typ, expr) = doAssert a is int var b {.byaddr.}: int = s[0] doAssert a.addr == b.addr - when typ is type(nil): - let tmp = addr(expr) + when typ is typeof(nil): + let tmp = addr(ex) else: - let tmp: ptr typ = addr(expr) + let tmp: ptr typ = addr(ex) template lhs: untyped = tmp[] diff --git a/tests/stdlib/tpragmas.nim b/tests/stdlib/tbyaddr.nim similarity index 98% rename from tests/stdlib/tpragmas.nim rename to tests/stdlib/tbyaddr.nim index b91d7e547..b485635c7 100644 --- a/tests/stdlib/tpragmas.nim +++ b/tests/stdlib/tbyaddr.nim @@ -1,4 +1,4 @@ -import std/pragmas +import std/byaddr block: var s = @[10,11,12] From df8e0e7f0c3a2e340c625d8c55d9105da106dbfd Mon Sep 17 00:00:00 2001 From: Dean Eigenmann <7621705+decanus@users.noreply.github.com> Date: Thu, 2 Apr 2020 12:09:29 +0200 Subject: [PATCH 0274/4254] feature/count (#13837) --- changelog.md | 2 +- lib/pure/collections/sequtils.nim | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 7dccc20b9..32f6e0a1b 100644 --- a/changelog.md +++ b/changelog.md @@ -124,9 +124,9 @@ echo f through an SSL-wrapped `Socket`/`AsyncSocket`. - Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` - Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. +- Added `sequtils.countIt`, allowing for counting items using a predicate. - Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target. - ## Library changes - `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e32c784c6..0cc91b0d0 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -600,6 +600,25 @@ template keepItIf*(varSeq: seq, pred: untyped) = inc(pos) setLen(varSeq, pos) +since (1, 1): + template countIt*(s, pred: untyped): Natural = + ## Returns a count of all the items that fulfilled the predicate. + ## + ## The predicate needs to be an expression using + ## the ``it`` variable for testing, like: ``countIt(@[1, 2, 3], it > 2)``. + ## + runnableExamples: + let numbers = @[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6] + iterator iota(n: int): int = + for i in 0.. Date: Thu, 2 Apr 2020 12:57:15 +0200 Subject: [PATCH 0275/4254] added an .assert pragma and mentioned the pragmas in the changelog --- changelog.md | 4 ++++ compiler/pragmas.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/wordrecg.nim | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 32f6e0a1b..46b4a49b2 100644 --- a/changelog.md +++ b/changelog.md @@ -169,6 +169,10 @@ echo f enabling things like lvalue references, see `byaddr.byaddr` - `macro pragmas` can now be used in type sections. +- 5 new pragmas were added to Nim in order to make the upcoming tooling more + convenient to use. Nim compiler checks these pragmas for syntax but otherwise + ignores them. The pragmas are `requires`, `ensures`, `assume`, `assert`, `invariant`. + ## Language changes diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6816a1705..4b0cf406d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1176,7 +1176,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if sym == nil: invalidPragma(c, it) else: sym.flags.incl sfUsed of wLiftLocals: discard - of wRequires, wInvariant, wAssume: + of wRequires, wInvariant, wAssume, wAssert: pragmaProposition(c, it) of wEnsures: pragmaEnsures(c, it) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 86149330e..efc19952c 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1030,7 +1030,7 @@ proc track(tracked: PEffects, n: PNode) = when defined(drnim): if pragma == wAssume: addFact(tracked.guards, pragmaList[i][1]) - elif pragma == wInvariant: + elif pragma == wInvariant or pragma == wAssert: if prove(tracked, pragmaList[i][1]): addFact(tracked.guards, pragmaList[i][1]) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 2ce2b9322..55c38b76a 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -54,7 +54,7 @@ type wNonReloadable, wExecuteOnReload, wAssertions, wPatterns, wTrMacros, wSinkInference, wWarnings, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, - wRequires, wEnsures, wInvariant, wAssume, + wRequires, wEnsures, wInvariant, wAssume, wAssert, wDeadCodeElimUnused, # deprecated, dead code elim always happens wSafecode, wPackage, wNoForward, wReorder, wNoRewrite, wNoDestroy, wPragma, @@ -143,7 +143,7 @@ const "assertions", "patterns", "trmacros", "sinkinference", "warnings", "hints", "optimization", "raises", "writes", "reads", "size", "effects", "tags", - "requires", "ensures", "invariant", "assume", + "requires", "ensures", "invariant", "assume", "assert", "deadcodeelim", # deprecated, dead code elim always happens "safecode", "package", "noforward", "reorder", "norewrite", "nodestroy", "pragma", From 8ee0771b5a10cfd083ba2eba806e5d9d9f72b234 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 2 Apr 2020 15:01:14 +0200 Subject: [PATCH 0276/4254] return types must not be Natural for reasons I won't outline here --- lib/pure/collections/sequtils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 0cc91b0d0..ea02ff1fd 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -601,7 +601,7 @@ template keepItIf*(varSeq: seq, pred: untyped) = setLen(varSeq, pos) since (1, 1): - template countIt*(s, pred: untyped): Natural = + template countIt*(s, pred: untyped): int = ## Returns a count of all the items that fulfilled the predicate. ## ## The predicate needs to be an expression using From 7d17cd34b8d3ef134885f9317b9799d3c5952737 Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 2 Apr 2020 16:28:01 +0200 Subject: [PATCH 0277/4254] create a changelog for v1.2.0 --- changelog.md | 215 +------------ changelogs/changelog_1_2_0.md | 532 +++++++++++++++++++++++++++++++++ changelogs/changelog_X_XX_X.md | 26 +- 3 files changed, 543 insertions(+), 230 deletions(-) create mode 100644 changelogs/changelog_1_2_0.md diff --git a/changelog.md b/changelog.md index 46b4a49b2..139bdc832 100644 --- a/changelog.md +++ b/changelog.md @@ -1,220 +1,15 @@ -# 1.2 - xxxx-xx-xx +# v1.4.0 - yyyy-mm-dd -## Changes affecting backwards compatibility -- The Nim compiler now implements a faster way to detect overflows based - on GCC's `__builtin_sadd_overflow` family of functions. (Clang also - supports these). Some versions of GCC lack this feature and unfortunately - we cannot detect this case reliably. So if you get compilation errors like - "undefined reference to `__builtin_saddll_overflow`" compile your programs - with `-d:nimEmulateOverflowChecks`. - - -### Breaking changes in the standard library - -- `base64.encode` no longer supports `lineLen` and `newLine`. - Use `base64.encodeMime` instead. -- `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" - as the dir component of "/root_sub_dir" instead of the empty string. -- `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples - now do not have fields named "a" and "b". -- `strutils.formatFloat` with `precision = 0` has the same behavior in all - backends, and it is compatible with Python's behavior, - e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`. -- Global variable `lc` has been removed from sugar.nim. -- `distinctBase` has been moved from sugar.nim to typetraits and now implemented as - compiler type trait instead of macro. `distinctBase` in sugar module is now deprecated. -- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it - was an oversight to be included in v1.0. -- `tables.merge(CountTable, CountTable): CountTable` has been removed. - It didn't work well together with the existing inplace version of the same proc - (`tables.merge(var CountTable, CountTable)`). - It was an oversight to be included in v1.0. -- `options` now treats `proc` like other pointer types, meaning `nil` proc variables - are converted to `None`. -- `relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid path - and shouldn't be conflated with `"."`; use -d:nimOldRelativePathBehavior to - restore the old behavior -- `joinPath(a,b)` now honors trailing slashes in `b` (or `a` if `b` = "") -- `times.parse` now only uses input to compute its result, and not `now`: - `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of - `2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when - used on 29th, 30th, 31st of each month. -- `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical - usage. The `$` operator can be used to obtain the string form of `HttpCode` - for comparison if desired. -- `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false). - If it is set to true, it will throw if input dir is invalid instead of a noop - (which is the default behaviour, as it was before this change), - `os.walkDirRec` only throws if top-level dir is invalid, but ignores errors for - subdirs, otherwise it would be impossible to resume iteration. - - -### Breaking changes in the compiler - -- Implicit conversions for `const` behave correctly now, meaning that code like - `const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now. - Simply write `const SOMECONST = 0` instead. -- The `{.dynlib.}` pragma is now required for exporting symbols when making - shared objects on POSIX and macOS, which make it consistent with the behavior - on Windows. -- The compiler is now more strict about type conversions concerning proc - types: Type conversions cannot be used to hide `.raise` effects or side - effects, instead a `cast` must be used. With the flag `--useVersion:1.0` the - old behaviour is emulated. - - -## Library additions - -- `macros.newLit` now works for ref object types. -- `system.writeFile` has been overloaded to also support `openarray[byte]`. -- Added overloaded `strformat.fmt` macro that use specified characters as - delimiter instead of '{' and '}'. -- introduced new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, - `CountTable.pop`, `Table.pop` -- To `strtabs.nim`, added `StringTable.clear` overload that reuses the existing mode. -- Added `browsers.osOpen` const alias for the operating system specific *"open"* command. -- Added `sugar.dup` for turning in-place algorithms like `sort` and `shuffle` into - operations that work on a copy of the data and return the mutated copy. As the existing - `sorted` does. -- Added `sugar.collect` that does comprehension for seq/set/table collections. -- Added `sugar.capture` for capturing some local loop variables when creating a closure. - This is an enhanced version of `closureScope`. -- Added `typetraits.tupleLen` to get number of elements of a tuple/type tuple, - and `typetraits.get` to get the ith element of a type tuple. -- Added `typetraits.genericParams` to return a tuple of generic params from a generic instantiation -- Added `os.normalizePathEnd` for additional path sanitization. -- Added `times.fromUnixFloat,toUnixFloat`, subsecond resolution versions of `fromUnix`,`toUnixFloat`. -- Added `wrapnils` module for chains of field-access and indexing where the LHS can be nil. - This simplifies code by reducing need for if-else branches around intermediate maybe nil values. - E.g. `echo ?.n.typ.kind` -- Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. -- Added `os.isRelativeTo` to tell whether a path is relative to another -- Added `resetOutputFormatters` to `unittest` -- Added `expectIdent` to the `macros` module. -- Added `os.isValidFilename` that returns `true` if `filename` argument is valid for crossplatform use. - -- Added a `with` macro for easy function chaining that's available - everywhere, there is no need to concern your APIs with returning the first argument - to enable "chaining", instead use the dedicated macro `with` that - was designed for it. For example: - -```nim - -type - Foo = object - col, pos: string - -proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) -proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) - -var f: Foo -with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) -echo f - -``` - -- Added `times.isLeapDay` -- Added a new module, `std / compilesettings` for querying the compiler about - diverse configuration settings. -- `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. -- Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for - retrieving the verified certificate chain of the peer we are connected to - through an SSL-wrapped `Socket`/`AsyncSocket`. -- Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` -- Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. -- Added `sequtils.countIt`, allowing for counting items using a predicate. -- Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target. - -## Library changes - -- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` - and only returns once all pending async operations are guaranteed to have completed. -- `asyncdispatch.drain` now consistently uses the passed timeout value for all - iterations of the event loop, and not just the first iteration. - This is more consistent with the other asyncdispatch apis, and allows - `asyncdispatch.drain` to be more efficient. -- `base64.encode` and `base64.decode` was made faster by about 50%. -- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support - (ISO 40314). -- `macros.eqIdent` is now invariant to export markers and backtick quotes. -- `htmlgen.html` allows `lang` on the `` tag and common valid attributes. -- `macros.basename` and `basename=` got support for `PragmaExpr`, - so that an expression like `MyEnum {.pure.}` is handled correctly. -- `httpclient.maxredirects` changed from `int` to `Natural`, because negative values - serve no purpose whatsoever. -- `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers` - argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`. -- `parseutils.parseUntil` has now a different behaviour if the `until` parameter is - empty. This was required for intuitive behaviour of the strscans module - (see bug #13605). -- `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs -- `net.newContext` now performs SSL Certificate checking on Linux and OSX. - Define `nimDisableCertificateValidation` to disable it globally. -- new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by `import std/byaddr` -- new module `std/stackframes`, in particular `setFrameMsg` which enables - custom runtime annotation of stackframes, see #13351 for examples. Turn on/off via - `--stackTraceMsgs:on/off` - -## Language additions - -- An `align` pragma can now be used for variables and object fields, similar - to the `alignas` declaration modifier in C/C++. - -- `=sink` type bound operator is now optional. Compiler can now use combination - of `=destroy` and `copyMem` to move objects efficiently. - -- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for non builtin pragmas, - enabling things like lvalue references, see `byaddr.byaddr` - -- `macro pragmas` can now be used in type sections. -- 5 new pragmas were added to Nim in order to make the upcoming tooling more - convenient to use. Nim compiler checks these pragmas for syntax but otherwise - ignores them. The pragmas are `requires`, `ensures`, `assume`, `assert`, `invariant`. +## Standard library additions and changes ## Language changes -- Unsigned integer operators have been fixed to allow promotion of the first operand. -- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim - versions. The documentation was improved to acknowledge this special case. - See https://github.com/nim-lang/RFCs/issues/175 for more details. + +## Compiler changes -### Tool changes +## Tool changes -- Fix Nimpretty must not accept negative indentation argument because breaks file. - - -### Compiler changes - -- JS target indent is all spaces, instead of mixed spaces and tabs, for - generated JavaScript. -- The Nim compiler now supports the ``--asm`` command option for easier - inspection of the produced assembler code. -- The Nim compiler now supports a new pragma called ``.localPassc`` to - pass specific compiler options to the C(++) backend for the C(++) file - that was produced from the current Nim module. -- The compiler now inferes "sink parameters". To disable this for a specific routine, - annotate it with `.nosinks`. To disable it for a section of code, use - `{.push sinkInference: off.}`...`{.pop.}`. -- The compiler now supports a new switch `--panics:on` that turns runtime - errors like `IndexError` or `OverflowError` into fatal errors that **cannot** - be caught via Nim's `try` statement. `--panics:on` can improve the - runtime efficiency and code size of your program significantly. -- The compiler now warns about inheriting directly from `system.Exception` as - this is **very bad** style. You should inherit from `ValueError`, `IOError`, - `OSError` or from a different specific exception type that inherits from - `CatchableError` and cannot be confused with a `Defect`. -- The error reporting for Nim's effect system has been improved. - - -## Bugfixes - -- The `FD` variant of `selector.unregister` for `ioselector_epoll` and - `ioselector_select` now properly handle the `Event.User` select event type. -- `joinPath` path normalization when `/` is the first argument works correctly: - `assert "/" / "/a" == "/a"`. Fixed the edgecase: `assert "" / "" == ""`. -- `xmltree` now adds indentation consistently to child nodes for any number - of children nodes. diff --git a/changelogs/changelog_1_2_0.md b/changelogs/changelog_1_2_0.md new file mode 100644 index 000000000..a396e014b --- /dev/null +++ b/changelogs/changelog_1_2_0.md @@ -0,0 +1,532 @@ +# v1.2.0 - 2020-04-02 + + +## Standard library additions and changes + +- Added overloaded `strformat.fmt` macro that use specified characters as + delimiter instead of '{' and '}'. +- Added new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, + `CountTable.pop`, `Table.pop`. +- Added `strtabs.clear` overload that reuses the existing mode. +- Added `browsers.osOpen` const alias for the operating system specific *"open"* command. +- Added `sugar.dup` for turning in-place algorithms like `sort` and `shuffle` + into operations that work on a copy of the data and return the mutated copy, + like the existing `sorted` does. +- Added `sugar.collect` that does comprehension for seq/set/table collections. +- Added `sugar.capture` for capturing some local loop variables when creating a + closure. This is an enhanced version of `closureScope`. +- Added `typetraits.tupleLen` to get number of elements of a tuple/type tuple, + and `typetraits.get` to get the ith element of a type tuple. +- Added `typetraits.genericParams` to return a tuple of generic params from a + generic instantiation. +- `options` now treats `proc` like other pointer types, meaning `nil` proc variables + are converted to `None`. +- Added `os.normalizePathEnd` for additional path sanitization. +- Added `times.fromUnixFloat,toUnixFloat`, sub-second resolution versions of + `fromUnix`,`toUnixFloat`. +- Added `wrapnils` module for chains of field-access and indexing where the LHS + can be nil. This simplifies code by reducing need for if-else branches around + intermediate maybe nil values. E.g. `echo ?.n.typ.kind`. +- Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. +- Added `os.isRelativeTo` to tell whether a path is relative to another. +- Added `resetOutputFormatters` to `unittest`. +- Added `expectIdent` to the `macros` module. +- Added `os.isValidFilename` that returns `true` if `filename` argument is valid + for cross-platform use. +- Added `times.isLeapDay` +- `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. +- Added a new module, `std / compilesettings` for querying the compiler about + diverse configuration settings. +- Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for + retrieving the verified certificate chain of the peer we are connected to + through an SSL-wrapped `Socket`/`AsyncSocket`. +- Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. +- Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target. +- Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` +- Added new module `std/stackframes`, in particular `setFrameMsg`, which enables + custom runtime annotation of stackframes, see #13351 for examples. + Turn on/off via `--stackTraceMsgs:on/off`. +- Added `sequtils.countIt`, allowing for counting items using a predicate. +- Added a `with` macro for easy function chaining that's available everywhere, + there is no need to concern your APIs with returning the first argument + to enable "chaining", instead use the dedicated macro `with` that + was designed for it. For example: + +```nim +type + Foo = object + col, pos: string + +proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) +proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) + +var f: Foo +with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) +echo f +``` + +- `macros.newLit` now works for ref object types. +- `macro pragmas` can now be used in type sections. +- 5 new pragmas were added to Nim in order to make the upcoming tooling more + convenient to use. Nim compiler checks these pragmas for syntax but otherwise + ignores them. The pragmas are `requires`, `ensures`, `assume`, `assert`, `invariant`. +- `system.writeFile` has been overloaded to also support `openarray[byte]`. +- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` + and only returns once all pending async operations are guaranteed to have completed. +- `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples + now do not have fields named "a" and "b". +- `distinctBase` has been moved from `sugar` to `typetraits` and now it is + implemented as compiler type trait instead of macro. `distinctBase` in sugar + module is now deprecated. +- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it + was an oversight to be included in v1.0. +- `tables.merge(CountTable, CountTable): CountTable` has been removed. + It didn't work well together with the existing inplace version of the same proc + (`tables.merge(var CountTable, CountTable)`). + It was an oversight to be included in v1.0. +- `asyncdispatch.drain` now consistently uses the passed timeout value for all + iterations of the event loop, and not just the first iteration. + This is more consistent with the other asyncdispatch APIs, and allows + `asyncdispatch.drain` to be more efficient. +- `base64.encode` and `base64.decode` were made faster by about 50%. +- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support + (ISO 40314). +- `macros.eqIdent` is now invariant to export markers and backtick quotes. +- `htmlgen.html` allows `lang` in the `` tag and common valid attributes. +- `macros.basename` and `basename=` got support for `PragmaExpr`, + so that an expression like `MyEnum {.pure.}` is handled correctly. +- `httpclient.maxredirects` changed from `int` to `Natural`, because negative values + serve no purpose whatsoever. +- `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers` + argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`. +- `parseutils.parseUntil` has now a different behaviour if the `until` parameter is + empty. This was required for intuitive behaviour of the strscans module + (see bug #13605). +- `strutils.formatFloat` with `precision = 0` has the same behavior in all + backends, and it is compatible with Python's behavior, + e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`. +- `times.parse` now only uses input to compute its result, and not `now`: + `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of + `2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when + used on 29th, 30th, 31st of each month. +- `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical + usage. The `$` operator can be used to obtain the string form of `HttpCode` + for comparison if desired. +- `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs. +- `net.newContext` now performs SSL Certificate checking on Linux and OSX. + Define `nimDisableCertificateValidation` to disable it globally. +- `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false). + If it is set to true, it will throw if input dir is invalid instead of a noop + (which is the default behaviour, as it was before this change), + `os.walkDirRec` only throws if top-level dir is invalid, but ignores errors for + subdirs, otherwise it would be impossible to resume iteration. +- The `FD` variant of `selector.unregister` for `ioselector_epoll` and + `ioselector_select` now properly handle the `Event.User` select event type. +- `joinPath` path normalization when `/` is the first argument works correctly: + `assert "/" / "/a" == "/a"`. Fixed the edge case: `assert "" / "" == ""`. +- `xmltree` now adds indentation consistently to child nodes for any number + of children nodes. +- `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" + as the dir component of `/root_sub_dir` instead of the empty string. +- The deprecated `lc` macro has been removed from `sugar`. It is now replaced with the + more powerful `collect` macro. +- `os.relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid + path and shouldn't be conflated with `"."`; use `-d:nimOldRelativePathBehavior` + to restore the old behavior. +- `os.joinPath(a, b)` now honors trailing slashes in `b` (or `a` if `b` = ""). +- `base64.encode` no longer supports `lineLen` and `newLine`. + Use `base64.encodeMime` instead. + + +## Language changes + +- An `align` pragma can now be used for variables and object fields, similar + to the `alignas` declaration modifier in C/C++. +- `=sink` type bound operator is now optional. Compiler can now use combination + of `=destroy` and `copyMem` to move objects efficiently. +- Unsigned integer operators have been fixed to allow promotion of the first operand. +- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim + versions. The documentation was improved to acknowledge this special case. + See https://github.com/nim-lang/RFCs/issues/175 for more details. +- New syntax for lvalue references: `var b {.byaddr.} = expr` enabled by + `import std/byaddr`. +- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for + non-builtin pragmas, enabling things like lvalue references (see `pragmas.byaddr`). + + +## Compiler changes + +- Generated JS code uses spaces, instead of mixed spaces and tabs. +- The Nim compiler now supports the ``--asm`` command option for easier + inspection of the produced assembler code. +- The Nim compiler now supports a new pragma called ``.localPassc`` to + pass specific compiler options to the C(++) backend for the C(++) file + that was produced from the current Nim module. +- The compiler now inferes "sink parameters". To disable this for a specific routine, + annotate it with `.nosinks`. To disable it for a section of code, use + `{.push sinkInference: off.}`...`{.pop.}`. +- The compiler now supports a new switch `--panics:on` that turns runtime + errors like `IndexError` or `OverflowError` into fatal errors that **cannot** + be caught via Nim's `try` statement. `--panics:on` can improve the + runtime efficiency and code size of your program significantly. +- The compiler now warns about inheriting directly from `system.Exception` as + this is **very bad** style. You should inherit from `ValueError`, `IOError`, + `OSError` or from a different specific exception type that inherits from + `CatchableError` and cannot be confused with a `Defect`. +- The error reporting for Nim's effect system has been improved. +- Implicit conversions for `const` behave correctly now, meaning that code like + `const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now. + Simply write `const SOMECONST = 0` instead. +- The `{.dynlib.}` pragma is now required for exporting symbols when making + shared objects on POSIX and macOS, which make it consistent with the behavior + on Windows. +- The compiler is now more strict about type conversions concerning proc + types: Type conversions cannot be used to hide `.raise` effects or side + effects, instead a `cast` must be used. With the flag `--useVersion:1.0` the + old behaviour is emulated. +- The Nim compiler now implements a faster way to detect overflows based + on GCC's `__builtin_sadd_overflow` family of functions. (Clang also + supports these). Some versions of GCC lack this feature and unfortunately + we cannot detect this case reliably. So if you get compilation errors like + "undefined reference to `__builtin_saddll_overflow`" compile your programs + with `-d:nimEmulateOverflowChecks`. + + +## Tool changes + +- Nimpretty doesn't accept negative indentation argument anymore, because it was + breaking files. + + +## Bugfixes + +- Fixed "`nimgrep --nocolor` is ignored on posix; should be instead: `--nimgrep --color=[auto]|true|false`" + ([#7591](https://github.com/nim-lang/Nim/issues/7591)) +- Fixed "Runtime index on const array (of converted obj) causes C-compiler error" + ([#10514](https://github.com/nim-lang/Nim/issues/10514)) +- Fixed "windows x86 with vcc compile error with "asmNoStackFrame"" + ([#12298](https://github.com/nim-lang/Nim/issues/12298)) +- Fixed "[TODO] regression: Error: Locks requires --threads:on option" + ([#12330](https://github.com/nim-lang/Nim/issues/12330)) +- Fixed "Add --cc option to --help or --fullhelp output" + ([#12010](https://github.com/nim-lang/Nim/issues/12010)) +- Fixed "questionable `csize` definition in `system.nim`" + ([#12187](https://github.com/nim-lang/Nim/issues/12187)) +- Fixed "os.getAppFilename() returns incorrect results on OpenBSD" + ([#12389](https://github.com/nim-lang/Nim/issues/12389)) +- Fixed "HashSet[uint64] slow insertion depending on values" + ([#11764](https://github.com/nim-lang/Nim/issues/11764)) +- Fixed "Differences between compiling 'classic call syntax' vs 'method call syntax' ." + ([#12453](https://github.com/nim-lang/Nim/issues/12453)) +- Fixed "c -d:nodejs --> SIGSEGV: Illegal storage access" + ([#12502](https://github.com/nim-lang/Nim/issues/12502)) +- Fixed "Closure iterator crashes on --newruntime due to "dangling references"" + ([#12443](https://github.com/nim-lang/Nim/issues/12443)) +- Fixed "No `=destroy` for elements of closure environments other than for latest devel --gc:destructors" + ([#12577](https://github.com/nim-lang/Nim/issues/12577)) +- Fixed "strutils:formatBiggestFloat() gives different results in JS mode" + ([#8242](https://github.com/nim-lang/Nim/issues/8242)) +- Fixed "Regression (devel): the new `csize_t` definition isn't consistently used, nor tested thoroughly..." + ([#12597](https://github.com/nim-lang/Nim/issues/12597)) +- Fixed "tables.take() is defined only for `Table` and missed for other table containers" + ([#12519](https://github.com/nim-lang/Nim/issues/12519)) +- Fixed "`pthread_key_t` errors on OpenBSD" + ([#12135](https://github.com/nim-lang/Nim/issues/12135)) +- Fixed "newruntime: simple seq pop at ct results in compile error" + ([#12644](https://github.com/nim-lang/Nim/issues/12644)) +- Fixed "[Windows] finish.exe C:\Users\\.nimble\bin is not in your PATH environment variable." + ([#12319](https://github.com/nim-lang/Nim/issues/12319)) +- Fixed "Error with strformat + asyncdispatch + const" + ([#12612](https://github.com/nim-lang/Nim/issues/12612)) +- Fixed "MultipartData needs $" + ([#11863](https://github.com/nim-lang/Nim/issues/11863)) +- Fixed "Nim stdlib style issues with --styleCheck:error" + ([#12687](https://github.com/nim-lang/Nim/issues/12687)) +- Fixed "new $nimbleDir path substitution yields unexpected search paths" + ([#12767](https://github.com/nim-lang/Nim/issues/12767)) +- Fixed "Regression: inlined procs now get multiple rounds of destructor injection" + ([#12766](https://github.com/nim-lang/Nim/issues/12766)) +- Fixed "newruntime: compiler generates defective code" + ([#12669](https://github.com/nim-lang/Nim/issues/12669)) +- Fixed "broken windows modules path handling because of 'os.relativePath' breaking changes" + ([#12734](https://github.com/nim-lang/Nim/issues/12734)) +- Fixed "for loop tuple syntax not rendered correctly" + ([#12740](https://github.com/nim-lang/Nim/issues/12740)) +- Fixed "Crash when trying to use `type.name[0]`" + ([#12804](https://github.com/nim-lang/Nim/issues/12804)) +- Fixed "Enums should be considered Trivial types in Atomics" + ([#12812](https://github.com/nim-lang/Nim/issues/12812)) +- Fixed "Produce static/const initializations for variables when possible" + ([#12216](https://github.com/nim-lang/Nim/issues/12216)) +- Fixed "Assigning descriminator field leads to internal assert with --gc:destructors" + ([#12821](https://github.com/nim-lang/Nim/issues/12821)) +- Fixed "nimsuggest `use` command does not return all instances of symbol" + ([#12832](https://github.com/nim-lang/Nim/issues/12832)) +- Fixed "@[] is a problem for --gc:destructors" + ([#12820](https://github.com/nim-lang/Nim/issues/12820)) +- Fixed "Codegen ICE in allPathsAsgnResult" + ([#12827](https://github.com/nim-lang/Nim/issues/12827)) +- Fixed "seq[Object with ref and destructor type] doesn't work in old runtime" + ([#12882](https://github.com/nim-lang/Nim/issues/12882)) +- Fixed "Destructor not invoked because it is instantiated too late, old runtime" + ([#12883](https://github.com/nim-lang/Nim/issues/12883)) +- Fixed "The collect macro does not handle if/case correctly" + ([#12874](https://github.com/nim-lang/Nim/issues/12874)) +- Fixed "allow typed/untyped params in magic procs (even if not in stdlib)" + ([#12911](https://github.com/nim-lang/Nim/issues/12911)) +- Fixed "ARC/newruntime memory corruption" + ([#12899](https://github.com/nim-lang/Nim/issues/12899)) +- Fixed "tasyncclosestall.nim still flaky test: Address already in use" + ([#12919](https://github.com/nim-lang/Nim/issues/12919)) +- Fixed "newruntime and computed goto: variables inside the loop are in generated code uninitialised" + ([#12785](https://github.com/nim-lang/Nim/issues/12785)) +- Fixed "osx: dsymutil needs to be called for debug builds to keep debug info" + ([#12735](https://github.com/nim-lang/Nim/issues/12735)) +- Fixed "codegen ICE with ref objects, gc:destructors" + ([#12826](https://github.com/nim-lang/Nim/issues/12826)) +- Fixed "mutable iterator cannot yield named tuples" + ([#12945](https://github.com/nim-lang/Nim/issues/12945)) +- Fixed "parsecfg stores "\r\n" line breaks just as "\n"" + ([#12970](https://github.com/nim-lang/Nim/issues/12970)) +- Fixed "db_postgres.getValue issues warning when no rows found" + ([#12973](https://github.com/nim-lang/Nim/issues/12973)) +- Fixed "ARC: Unpacking tuple with seq causes segfault" + ([#12989](https://github.com/nim-lang/Nim/issues/12989)) +- Fixed "ARC/newruntime: strutils.join on seq with only empty strings causes segfault" + ([#12965](https://github.com/nim-lang/Nim/issues/12965)) +- Fixed "regression (1.0.4): `{.push exportc.}` wrongly affects generic instantiations, causing codegen errors" + ([#12985](https://github.com/nim-lang/Nim/issues/12985)) +- Fixed "cdt, crash with --gc:arc, works fine with default gc" + ([#12978](https://github.com/nim-lang/Nim/issues/12978)) +- Fixed "ARC: No indexError thrown on out-of-bound seq access, SIGSEGV instead" + ([#12961](https://github.com/nim-lang/Nim/issues/12961)) +- Fixed "ARC/async: Returning in a try-block results in wrong codegen" + ([#12956](https://github.com/nim-lang/Nim/issues/12956)) +- Fixed "asm keyword is generating wrong output C code when --cc:tcc" + ([#12988](https://github.com/nim-lang/Nim/issues/12988)) +- Fixed "Destructor not invoked" + ([#13026](https://github.com/nim-lang/Nim/issues/13026)) +- Fixed "ARC/newruntime: Adding inherited var ref object to seq with base type causes segfault" + ([#12964](https://github.com/nim-lang/Nim/issues/12964)) +- Fixed "Style check error with JS compiler target" + ([#13032](https://github.com/nim-lang/Nim/issues/13032)) +- Fixed "regression(1.0.4): undeclared identifier: 'readLines'; plus another regression and bug" + ([#13013](https://github.com/nim-lang/Nim/issues/13013)) +- Fixed "regression(1.04) `invalid pragma: since` with nim js" + ([#12996](https://github.com/nim-lang/Nim/issues/12996)) +- Fixed "Sink to MemMove optimization in injectdestructors" + ([#13002](https://github.com/nim-lang/Nim/issues/13002)) +- Fixed "--gc:arc: `catch` doesn't work with exception subclassing" + ([#13072](https://github.com/nim-lang/Nim/issues/13072)) +- Fixed "nim c --gc:arc --exceptions:{setjmp,goto} incorrectly handles raise; `nim cpp --gc:arc` is ok" + ([#13070](https://github.com/nim-lang/Nim/issues/13070)) +- Fixed "typetraits feature request - get subtype of a generic type" + ([#6454](https://github.com/nim-lang/Nim/issues/6454)) +- Fixed "CountTable inconsistencies between keys() and len() after setting value to 0" + ([#12813](https://github.com/nim-lang/Nim/issues/12813)) +- Fixed "{.align.} pragma is not applied if there is a generic field" + ([#13122](https://github.com/nim-lang/Nim/issues/13122)) +- Fixed "ARC, finalizer, allow rebinding the same function multiple times" + ([#13112](https://github.com/nim-lang/Nim/issues/13112)) +- Fixed "`nim doc` treats `export localSymbol` incorrectly" + ([#13100](https://github.com/nim-lang/Nim/issues/13100)) +- Fixed "--gc:arc SIGSEGV (double free?)" + ([#13119](https://github.com/nim-lang/Nim/issues/13119)) +- Fixed "codegen bug with arc" + ([#13105](https://github.com/nim-lang/Nim/issues/13105)) +- Fixed "symbols not defined in the grammar" + ([#10665](https://github.com/nim-lang/Nim/issues/10665)) +- Fixed "[JS] Move is not defined" + ([#9674](https://github.com/nim-lang/Nim/issues/9674)) +- Fixed "[TODO] pathutils.`/` can return invalid AbsoluteFile" + ([#13121](https://github.com/nim-lang/Nim/issues/13121)) +- Fixed "regression(1.04) `nim doc main.nim` generates broken html (no css)" + ([#12998](https://github.com/nim-lang/Nim/issues/12998)) +- Fixed "Wrong supportsCopyMem on string in type section" + ([#13095](https://github.com/nim-lang/Nim/issues/13095)) +- Fixed "Arc, finalizer, out of memory" + ([#13157](https://github.com/nim-lang/Nim/issues/13157)) +- Fixed "`--genscript` messes up nimcache and future nim invocations" + ([#13144](https://github.com/nim-lang/Nim/issues/13144)) +- Fixed "--gc:arc with --exceptions:goto for "nim c" generate invalid c code" + ([#13186](https://github.com/nim-lang/Nim/issues/13186)) +- Fixed "[regression] duplicate member `_i1` codegen bug" + ([#13195](https://github.com/nim-lang/Nim/issues/13195)) +- Fixed "RTree investigations with valgrind for --gc:arc" + ([#13110](https://github.com/nim-lang/Nim/issues/13110)) +- Fixed "relativePath("foo", ".") returns wrong path" + ([#13211](https://github.com/nim-lang/Nim/issues/13211)) +- Fixed "asyncftpclient - problem with welcome.msg" + ([#4684](https://github.com/nim-lang/Nim/issues/4684)) +- Fixed "Unclear error message, lowest priority" + ([#13256](https://github.com/nim-lang/Nim/issues/13256)) +- Fixed "Channel messages are corrupted" + ([#13219](https://github.com/nim-lang/Nim/issues/13219)) +- Fixed "Codegen bug with exportc and case objects" + ([#13281](https://github.com/nim-lang/Nim/issues/13281)) +- Fixed "[bugfix] fix #11590: c compiler warnings silently ignored, giving undefined behavior" + ([#11591](https://github.com/nim-lang/Nim/issues/11591)) +- Fixed "[CI] tnetdial flaky test" + ([#13132](https://github.com/nim-lang/Nim/issues/13132)) +- Fixed "Cross-Compiling with -d:mingw fails to locate compiler under OSX" + ([#10717](https://github.com/nim-lang/Nim/issues/10717)) +- Fixed "`nim doc --project` broken with imports below main project file or duplicate names" + ([#13150](https://github.com/nim-lang/Nim/issues/13150)) +- Fixed "regression: isNamedTuple(MyGenericTuple[int]) is false, should be true" + ([#13349](https://github.com/nim-lang/Nim/issues/13349)) +- Fixed "--gc:arc codegen bug copying objects bound to C structs with missing C struct fields" + ([#13269](https://github.com/nim-lang/Nim/issues/13269)) +- Fixed "write requires conversion to string" + ([#13182](https://github.com/nim-lang/Nim/issues/13182)) +- Fixed "Some remarks to stdlib documentation" + ([#13352](https://github.com/nim-lang/Nim/issues/13352)) +- Fixed "a `check` in unittest generated by template doesn't show actual value" + ([#6736](https://github.com/nim-lang/Nim/issues/6736)) +- Fixed "Implicit return with case expression fails with 'var' return." + ([#3339](https://github.com/nim-lang/Nim/issues/3339)) +- Fixed "Segfault with closure on arc" + ([#13314](https://github.com/nim-lang/Nim/issues/13314)) +- Fixed "[Macro] Crash on malformed case statement with multiple else" + ([#13255](https://github.com/nim-lang/Nim/issues/13255)) +- Fixed "regression: `echo 'discard' | nim c -r -` generates a file '-' ; `-` should be treated specially" + ([#13374](https://github.com/nim-lang/Nim/issues/13374)) +- Fixed "on OSX, debugging (w gdb or lldb) a nim program crashes at the 1st call to `execCmdEx`" + ([#9634](https://github.com/nim-lang/Nim/issues/9634)) +- Fixed "Internal error in getTypeDescAux" + ([#13378](https://github.com/nim-lang/Nim/issues/13378)) +- Fixed "gc:arc mode breaks tuple let" + ([#13368](https://github.com/nim-lang/Nim/issues/13368)) +- Fixed "Nim compiler hangs for certain C/C++ compiler errors" + ([#8648](https://github.com/nim-lang/Nim/issues/8648)) +- Fixed "htmlgen does not support `data-*` attributes" + ([#13444](https://github.com/nim-lang/Nim/issues/13444)) +- Fixed "[gc:arc] setLen will cause string not to be null-terminated." + ([#13457](https://github.com/nim-lang/Nim/issues/13457)) +- Fixed "joinPath("", "") is "/" ; should be """ + ([#13455](https://github.com/nim-lang/Nim/issues/13455)) +- Fixed "[CI] flaky test on windows: tests/osproc/texitcode.nim" + ([#13449](https://github.com/nim-lang/Nim/issues/13449)) +- Fixed "Casting to float32 on NimVM is broken" + ([#13479](https://github.com/nim-lang/Nim/issues/13479)) +- Fixed "`--hints:off` doesn't work (doesn't override ~/.config/nim.cfg)" + ([#8312](https://github.com/nim-lang/Nim/issues/8312)) +- Fixed "joinPath("", "") is "/" ; should be """ + ([#13455](https://github.com/nim-lang/Nim/issues/13455)) +- Fixed "tables.values is broken" + ([#13496](https://github.com/nim-lang/Nim/issues/13496)) +- Fixed "global user config can override project specific config" + ([#9405](https://github.com/nim-lang/Nim/issues/9405)) +- Fixed "Non deterministic macros and id consistency problem" + ([#12627](https://github.com/nim-lang/Nim/issues/12627)) +- Fixed "try expression doesn't work with return on expect branch" + ([#13490](https://github.com/nim-lang/Nim/issues/13490)) +- Fixed "CI will break every 4 years on feb 28: times doesn't handle leap years properly" + ([#13543](https://github.com/nim-lang/Nim/issues/13543)) +- Fixed "[minor] `nimgrep --word` doesn't work with operators (eg misses `1 +% 2`)" + ([#13528](https://github.com/nim-lang/Nim/issues/13528)) +- Fixed "`as` is usable as infix operator but its existence and precedence are not documented" + ([#13409](https://github.com/nim-lang/Nim/issues/13409)) +- Fixed "JSON unmarshalling drops seq's items" + ([#13531](https://github.com/nim-lang/Nim/issues/13531)) +- Fixed "os.joinPath returns wrong path when head ends '\' or '/' and tail starts '..'." + ([#13579](https://github.com/nim-lang/Nim/issues/13579)) +- Fixed "Block-local types with the same name lead to bad codegen (sighashes regression)" + ([#5170](https://github.com/nim-lang/Nim/issues/5170)) +- Fixed "tuple codegen error" + ([#12704](https://github.com/nim-lang/Nim/issues/12704)) +- Fixed "newHttpHeaders does not accept repeated headers" + ([#13573](https://github.com/nim-lang/Nim/issues/13573)) +- Fixed "regression: --incremental:on fails on simplest example" + ([#13319](https://github.com/nim-lang/Nim/issues/13319)) +- Fixed "strscan can't get value of last element in format" + ([#13605](https://github.com/nim-lang/Nim/issues/13605)) +- Fixed "hashes_examples crashes with "Bus Error" (unaligned access) on sparc64" + ([#12508](https://github.com/nim-lang/Nim/issues/12508)) +- Fixed "gc:arc bug with re-used `seq[T]`" + ([#13596](https://github.com/nim-lang/Nim/issues/13596)) +- Fixed "`raise CatchableError` is broken with --gc:arc when throwing inside a proc" + ([#13599](https://github.com/nim-lang/Nim/issues/13599)) +- Fixed "cpp --gc:arc --exceptions:goto fails to raise with discard" + ([#13436](https://github.com/nim-lang/Nim/issues/13436)) +- Fixed "terminal doesn't compile with -d:useWinAnsi" + ([#13607](https://github.com/nim-lang/Nim/issues/13607)) +- Fixed "Parsing "sink ptr T" - region needs to be an object type" + ([#12757](https://github.com/nim-lang/Nim/issues/12757)) +- Fixed "gc:arc + threads:on + closures compilation error" + ([#13519](https://github.com/nim-lang/Nim/issues/13519)) +- Fixed "[ARC] segmentation fault" + ([#13240](https://github.com/nim-lang/Nim/issues/13240)) +- Fixed "times.toDateTime buggy on 29th, 30th and 31th of each month" + ([#13558](https://github.com/nim-lang/Nim/issues/13558)) +- Fixed "Deque misbehaves on VM" + ([#13310](https://github.com/nim-lang/Nim/issues/13310)) +- Fixed "Nimscript listFiles should throw exception when path is not found" + ([#12676](https://github.com/nim-lang/Nim/issues/12676)) +- Fixed "koch boot fails if even an empty config.nims is present in ~/.config/nims/ [devel regression]" + ([#13633](https://github.com/nim-lang/Nim/issues/13633)) +- Fixed "nim doc generates lots of false positive LockLevel warnings" + ([#13218](https://github.com/nim-lang/Nim/issues/13218)) +- Fixed "Arrays are passed by copy to iterators, causing crashes, unnecessary allocations and slowdowns" + ([#12747](https://github.com/nim-lang/Nim/issues/12747)) +- Fixed "Range types always uses signed integer as a base type" + ([#13646](https://github.com/nim-lang/Nim/issues/13646)) +- Fixed "Generate c code cannot compile with recent devel version" + ([#13645](https://github.com/nim-lang/Nim/issues/13645)) +- Fixed "[regression] VM: Error: cannot convert -1 to uint64" + ([#13661](https://github.com/nim-lang/Nim/issues/13661)) +- Fixed "Spurious raiseException(Exception) detected" + ([#13654](https://github.com/nim-lang/Nim/issues/13654)) +- Fixed "gc:arc memory leak" + ([#13659](https://github.com/nim-lang/Nim/issues/13659)) +- Fixed "Error: cannot convert -1 to uint (inside tuples)" + ([#13671](https://github.com/nim-lang/Nim/issues/13671)) +- Fixed "strformat issue with --gc:arc" + ([#13622](https://github.com/nim-lang/Nim/issues/13622)) +- Fixed "astToStr doesn't work inside generics" + ([#13524](https://github.com/nim-lang/Nim/issues/13524)) +- Fixed "oswalkdir.walkDirRec wont return folders" + ([#11458](https://github.com/nim-lang/Nim/issues/11458)) +- Fixed "`echo 'echo 1' | nim c -r -` silently gives wrong results (nimBetterRun not updated for stdin)" + ([#13412](https://github.com/nim-lang/Nim/issues/13412)) +- Fixed "gc:arc destroys the global variable accidentally." + ([#13691](https://github.com/nim-lang/Nim/issues/13691)) +- Fixed "[minor] sigmatch errors should be sorted, for reproducible errors" + ([#13538](https://github.com/nim-lang/Nim/issues/13538)) +- Fixed "Exception when converting csize to clong" + ([#13698](https://github.com/nim-lang/Nim/issues/13698)) +- Fixed "ARC: variables are no copied on the thread spawn causing crashes" + ([#13708](https://github.com/nim-lang/Nim/issues/13708)) +- Fixed "Illegal distinct seq causes compiler crash" + ([#13720](https://github.com/nim-lang/Nim/issues/13720)) +- Fixed "cyclic seq definition crashes the compiler" + ([#13715](https://github.com/nim-lang/Nim/issues/13715)) +- Fixed "Iterator with openArray parameter make the argument evaluated many times" + ([#13417](https://github.com/nim-lang/Nim/issues/13417)) +- Fixed "net/asyncnet: Unable to access peer's certificate chain" + ([#13299](https://github.com/nim-lang/Nim/issues/13299)) +- Fixed "Accidentally "SIGSEGV: Illegal storage access" error after arc optimizations (#13325)" + ([#13709](https://github.com/nim-lang/Nim/issues/13709)) +- Fixed "Base64 Regression" + ([#13722](https://github.com/nim-lang/Nim/issues/13722)) +- Fixed "A regression (?) with --gc:arc and repr" + ([#13731](https://github.com/nim-lang/Nim/issues/13731)) +- Fixed "Internal compiler error when using the new variable pragmas" + ([#13737](https://github.com/nim-lang/Nim/issues/13737)) +- Fixed "bool conversion produces vcc 2019 warning at cpp compilation stage" + ([#13744](https://github.com/nim-lang/Nim/issues/13744)) +- Fixed "Compiler "does not detect" a type recursion error in the wrong code, remaining frozen" + ([#13763](https://github.com/nim-lang/Nim/issues/13763)) +- Fixed "[minor] regression: `Foo[0.0] is Foo[-0.0]` is now false" + ([#13730](https://github.com/nim-lang/Nim/issues/13730)) +- Fixed "`nim doc` - only whitespace on first line causes segfault" + ([#13631](https://github.com/nim-lang/Nim/issues/13631)) +- Fixed "hashset regression" + ([#13794](https://github.com/nim-lang/Nim/issues/13794)) +- Fixed "`os.getApplFreebsd` could return incorrect paths in the case of a long path" + ([#13806](https://github.com/nim-lang/Nim/issues/13806)) +- Fixed "Destructors are not inherited" + ([#13810](https://github.com/nim-lang/Nim/issues/13810)) +- Fixed "io.readLines AssertionError on devel" + ([#13829](https://github.com/nim-lang/Nim/issues/13829)) +- Fixed "exceptions:goto accidentally reset the variable during exception handling" + ([#13782](https://github.com/nim-lang/Nim/issues/13782)) diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md index 45a8cbc44..48520fd44 100644 --- a/changelogs/changelog_X_XX_X.md +++ b/changelogs/changelog_X_XX_X.md @@ -1,34 +1,20 @@ -# vx.xx.x - yyyy-mm-dd +# v1.xx.x - yyyy-mm-dd This is an example file. The changes should go to changelog.md! -## Changes affecting backwards compatibility +## Standard library additions and changes -- Example item: `Foo` changed to `Bar`. - - -### Breaking changes in the standard library - - -### Breaking changes in the compiler - - -## Library additions - -## Library changes - -## Language additions +- Added `example.exampleProc`. +- Changed `example.foo` to take additional `bar` parameter. ## Language changes -### Tool changes +## Compiler changes -### Compiler changes +## Tool changes - -## Bugfixes From d23371fdd7e68c48873e09fb9e4abd76e0c57b66 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 3 Apr 2020 00:03:13 -0700 Subject: [PATCH 0278/4254] std/byaddr => std/decls (#13847) --- changelogs/changelog_1_2_0.md | 4 ++-- lib/std/{byaddr.nim => decls.nim} | 0 tests/stdlib/{tbyaddr.nim => tdecls.nim} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename lib/std/{byaddr.nim => decls.nim} (100%) rename tests/stdlib/{tbyaddr.nim => tdecls.nim} (98%) diff --git a/changelogs/changelog_1_2_0.md b/changelogs/changelog_1_2_0.md index a396e014b..6a5a6c586 100644 --- a/changelogs/changelog_1_2_0.md +++ b/changelogs/changelog_1_2_0.md @@ -149,9 +149,9 @@ echo f versions. The documentation was improved to acknowledge this special case. See https://github.com/nim-lang/RFCs/issues/175 for more details. - New syntax for lvalue references: `var b {.byaddr.} = expr` enabled by - `import std/byaddr`. + `import std/decls`. - `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for - non-builtin pragmas, enabling things like lvalue references (see `pragmas.byaddr`). + non-builtin pragmas, enabling things like lvalue references (see `decls.byaddr`). ## Compiler changes diff --git a/lib/std/byaddr.nim b/lib/std/decls.nim similarity index 100% rename from lib/std/byaddr.nim rename to lib/std/decls.nim diff --git a/tests/stdlib/tbyaddr.nim b/tests/stdlib/tdecls.nim similarity index 98% rename from tests/stdlib/tbyaddr.nim rename to tests/stdlib/tdecls.nim index b485635c7..3567639e0 100644 --- a/tests/stdlib/tbyaddr.nim +++ b/tests/stdlib/tdecls.nim @@ -1,4 +1,4 @@ -import std/byaddr +import std/decls block: var s = @[10,11,12] From 6b9ffc7fadcdaeccd971230733607761863946f0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 3 Apr 2020 15:05:43 +0800 Subject: [PATCH 0279/4254] fix asynchttpserver content-length header (#13846) --- lib/pure/asynchttpserver.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index c806d972a..a9ea4780f 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -99,9 +99,12 @@ proc respond*(req: Request, code: HttpCode, content: string, if headers != nil: msg.addHeaders(headers) - msg.add("Content-Length: ") - # this particular way saves allocations: - msg.add content.len + + if not headers.hasKey("Content-Length"): + msg.add("Content-Length: ") + # this particular way saves allocations: + msg.addInt content.len + msg.add "\c\L\c\L" msg.add(content) result = req.client.send(msg) From 93cd98dd143d45a31a7fd90ad8f0b3d3c4c7798f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 3 Apr 2020 00:10:45 -0700 Subject: [PATCH 0280/4254] move tinyc to a separate repo and allow installing external dependencency (eg tinyc) from koch / library code (#13850) * remove tinyc * installDeps * update tinyc paths --- .gitignore | 2 +- compiler/cgen.nim | 4 +- compiler/main.nim | 2 +- compiler/nim.nim | 2 +- compiler/tccgen.nim | 55 +- koch.nim | 27 +- tinyc/arm-asm.c | 94 - tinyc/arm-gen.c | 2151 ----- tinyc/arm-link.c | 392 - tinyc/arm64-gen.c | 1837 ---- tinyc/arm64-link.c | 250 - tinyc/c67-gen.c | 2540 ------ tinyc/c67-link.c | 131 - tinyc/coff.h | 446 - tinyc/config.h | 22 - tinyc/conftest.c | 87 - tinyc/elf.h | 3237 -------- tinyc/examples/ex1.c | 8 - tinyc/examples/ex2.c | 98 - tinyc/examples/ex3.c | 23 - tinyc/examples/ex4.c | 26 - tinyc/examples/ex5.c | 8 - tinyc/i386-asm.c | 1714 ---- tinyc/i386-asm.h | 480 -- tinyc/i386-gen.c | 1164 --- tinyc/i386-link.c | 244 - tinyc/i386-tok.h | 253 - tinyc/il-gen.c | 657 -- tinyc/il-opcodes.h | 251 - tinyc/include/float.h | 57 - tinyc/include/stdarg.h | 79 - tinyc/include/stdbool.h | 11 - tinyc/include/stddef.h | 54 - tinyc/include/varargs.h | 12 - tinyc/lib/alloca-arm.S | 17 - tinyc/lib/alloca86-bt.S | 47 - tinyc/lib/alloca86.S | 31 - tinyc/lib/alloca86_64-bt.S | 56 - tinyc/lib/alloca86_64.S | 34 - tinyc/lib/armeabi.c | 501 -- tinyc/lib/armflush.c | 58 - tinyc/lib/bcheck.c | 979 --- tinyc/lib/lib-arm64.c | 664 -- tinyc/lib/libtcc1.c | 622 -- tinyc/lib/va_list.c | 65 - tinyc/libtcc.c | 1982 ----- tinyc/libtcc.h | 100 - tinyc/stab.def | 234 - tinyc/stab.h | 17 - tinyc/tcc-doc.texi | 1326 --- tinyc/tcc.c | 371 - tinyc/tcc.h | 1657 ---- tinyc/tccasm.c | 1303 --- tinyc/tcccoff.c | 948 --- tinyc/tccelf.c | 2994 ------- tinyc/tccgen.c | 7369 ----------------- tinyc/tcclib.h | 80 - tinyc/tccpe.c | 2014 ----- tinyc/tccpp.c | 3903 --------- tinyc/tccrun.c | 840 -- tinyc/tcctok.h | 350 - tinyc/tcctools.c | 546 -- tinyc/tests/42test.h | 13 - tinyc/tests/abitest.c | 691 -- tinyc/tests/asmtest.S | 975 --- tinyc/tests/boundtest.c | 285 - tinyc/tests/gcctestsuite.sh | 33 - tinyc/tests/libtcc_test.c | 96 - tinyc/tests/pp/01.c | 6 - tinyc/tests/pp/01.expect | 1 - tinyc/tests/pp/02.c | 28 - tinyc/tests/pp/02.expect | 5 - tinyc/tests/pp/03.c | 15 - tinyc/tests/pp/03.expect | 5 - tinyc/tests/pp/04.c | 4 - tinyc/tests/pp/04.expect | 1 - tinyc/tests/pp/05.c | 7 - tinyc/tests/pp/05.expect | 3 - tinyc/tests/pp/06.c | 5 - tinyc/tests/pp/06.expect | 1 - tinyc/tests/pp/07.c | 4 - tinyc/tests/pp/07.expect | 2 - tinyc/tests/pp/08.c | 4 - tinyc/tests/pp/08.expect | 1 - tinyc/tests/pp/09.c | 4 - tinyc/tests/pp/09.expect | 1 - tinyc/tests/pp/10.c | 10 - tinyc/tests/pp/10.expect | 5 - tinyc/tests/pp/11.c | 31 - tinyc/tests/pp/11.expect | 15 - tinyc/tests/pp/12.S | 8 - tinyc/tests/pp/12.expect | 2 - tinyc/tests/pp/13.S | 6 - tinyc/tests/pp/13.expect | 2 - tinyc/tests/pp/14.c | 13 - tinyc/tests/pp/14.expect | 3 - tinyc/tests/pp/15.c | 18 - tinyc/tests/pp/15.expect | 5 - tinyc/tests/pp/16.c | 3 - tinyc/tests/pp/16.expect | 2 - tinyc/tests/pp/17.c | 14 - tinyc/tests/pp/17.expect | 6 - tinyc/tests/pp/18.c | 15 - tinyc/tests/pp/18.expect | 3 - tinyc/tests/pp/19.c | 101 - tinyc/tests/pp/19.expect | 14 - tinyc/tests/pp/20.c | 13 - tinyc/tests/pp/20.expect | 6 - tinyc/tests/pp/21.c | 36 - tinyc/tests/pp/21.expect | 8 - tinyc/tests/pp/pp-counter.c | 27 - tinyc/tests/pp/pp-counter.expect | 15 - tinyc/tests/tcctest.c | 3813 --------- tinyc/tests/tcctest.h | 9 - tinyc/tests/testfp.c | 510 -- tinyc/tests/tests2/00_assignment.c | 18 - tinyc/tests/tests2/00_assignment.expect | 3 - tinyc/tests/tests2/01_comment.c | 14 - tinyc/tests/tests2/01_comment.expect | 5 - tinyc/tests/tests2/02_printf.c | 18 - tinyc/tests/tests2/02_printf.expect | 15 - tinyc/tests/tests2/03_struct.c | 31 - tinyc/tests/tests2/03_struct.expect | 6 - tinyc/tests/tests2/04_for.c | 15 - tinyc/tests/tests2/04_for.expect | 10 - tinyc/tests/tests2/05_array.c | 21 - tinyc/tests/tests2/05_array.expect | 10 - tinyc/tests/tests2/06_case.c | 29 - tinyc/tests/tests2/06_case.expect | 8 - tinyc/tests/tests2/07_function.c | 30 - tinyc/tests/tests2/07_function.expect | 4 - tinyc/tests/tests2/08_while.c | 24 - tinyc/tests/tests2/08_while.expect | 11 - tinyc/tests/tests2/09_do_while.c | 24 - tinyc/tests/tests2/09_do_while.expect | 11 - tinyc/tests/tests2/10_pointer.c | 40 - tinyc/tests/tests2/10_pointer.expect | 8 - tinyc/tests/tests2/11_precedence.c | 40 - tinyc/tests/tests2/11_precedence.expect | 15 - tinyc/tests/tests2/12_hashdefine.c | 14 - tinyc/tests/tests2/12_hashdefine.expect | 2 - tinyc/tests/tests2/13_integer_literals.c | 20 - tinyc/tests/tests2/13_integer_literals.expect | 5 - tinyc/tests/tests2/14_if.c | 21 - tinyc/tests/tests2/14_if.expect | 2 - tinyc/tests/tests2/15_recursion.c | 21 - tinyc/tests/tests2/15_recursion.expect | 10 - tinyc/tests/tests2/16_nesting.c | 21 - tinyc/tests/tests2/16_nesting.expect | 18 - tinyc/tests/tests2/17_enum.c | 72 - tinyc/tests/tests2/17_enum.expect | 4 - tinyc/tests/tests2/18_include.c | 12 - tinyc/tests/tests2/18_include.expect | 3 - tinyc/tests/tests2/18_include.h | 1 - tinyc/tests/tests2/19_pointer_arithmetic.c | 28 - .../tests/tests2/19_pointer_arithmetic.expect | 3 - tinyc/tests/tests2/20_pointer_comparison.c | 24 - .../tests/tests2/20_pointer_comparison.expect | 6 - tinyc/tests/tests2/21_char_array.c | 33 - tinyc/tests/tests2/21_char_array.expect | 7 - tinyc/tests/tests2/22_floating_point.c | 50 - tinyc/tests/tests2/22_floating_point.expect | 16 - tinyc/tests/tests2/23_type_coercion.c | 54 - tinyc/tests/tests2/23_type_coercion.expect | 12 - tinyc/tests/tests2/24_math_library.c | 30 - tinyc/tests/tests2/24_math_library.expect | 18 - tinyc/tests/tests2/25_quicksort.c | 83 - tinyc/tests/tests2/25_quicksort.expect | 2 - tinyc/tests/tests2/26_character_constants.c | 17 - .../tests2/26_character_constants.expect | 8 - tinyc/tests/tests2/27_sizeof.c | 18 - tinyc/tests/tests2/27_sizeof.expect | 4 - tinyc/tests/tests2/28_strings.c | 45 - tinyc/tests/tests2/28_strings.expect | 19 - tinyc/tests/tests2/29_array_address.c | 13 - tinyc/tests/tests2/29_array_address.expect | 1 - tinyc/tests/tests2/30_hanoi.c | 122 - tinyc/tests/tests2/30_hanoi.expect | 71 - tinyc/tests/tests2/31_args.c | 14 - tinyc/tests/tests2/31_args.expect | 6 - tinyc/tests/tests2/32_led.c | 266 - tinyc/tests/tests2/32_led.expect | 4 - tinyc/tests/tests2/33_ternary_op.c | 15 - tinyc/tests/tests2/33_ternary_op.expect | 10 - tinyc/tests/tests2/34_array_assignment.c | 23 - tinyc/tests/tests2/34_array_assignment.expect | 2 - tinyc/tests/tests2/35_sizeof.c | 14 - tinyc/tests/tests2/35_sizeof.expect | 2 - tinyc/tests/tests2/36_array_initialisers.c | 21 - .../tests/tests2/36_array_initialisers.expect | 20 - tinyc/tests/tests2/37_sprintf.c | 17 - tinyc/tests/tests2/37_sprintf.expect | 20 - tinyc/tests/tests2/38_multiple_array_index.c | 32 - .../tests2/38_multiple_array_index.expect | 4 - tinyc/tests/tests2/39_typedef.c | 65 - tinyc/tests/tests2/39_typedef.expect | 3 - tinyc/tests/tests2/40_stdio.c | 52 - tinyc/tests/tests2/40_stdio.expect | 27 - tinyc/tests/tests2/41_hashif.c | 85 - tinyc/tests/tests2/41_hashif.expect | 6 - tinyc/tests/tests2/42_function_pointer.c | 22 - tinyc/tests/tests2/42_function_pointer.expect | 2 - tinyc/tests/tests2/43_void_param.c | 15 - tinyc/tests/tests2/43_void_param.expect | 1 - tinyc/tests/tests2/44_scoped_declarations.c | 17 - .../tests2/44_scoped_declarations.expect | 1 - tinyc/tests/tests2/45_empty_for.c | 18 - tinyc/tests/tests2/45_empty_for.expect | 10 - tinyc/tests/tests2/46_grep.c | 568 -- tinyc/tests/tests2/46_grep.expect | 3 - tinyc/tests/tests2/47_switch_return.c | 24 - tinyc/tests/tests2/47_switch_return.expect | 4 - tinyc/tests/tests2/48_nested_break.c | 26 - tinyc/tests/tests2/48_nested_break.expect | 1 - tinyc/tests/tests2/49_bracket_evaluation.c | 23 - .../tests/tests2/49_bracket_evaluation.expect | 1 - tinyc/tests/tests2/50_logical_second_arg.c | 29 - .../tests/tests2/50_logical_second_arg.expect | 20 - tinyc/tests/tests2/51_static.c | 30 - tinyc/tests/tests2/51_static.expect | 8 - tinyc/tests/tests2/52_unnamed_enum.c | 27 - tinyc/tests/tests2/52_unnamed_enum.expect | 9 - tinyc/tests/tests2/54_goto.c | 56 - tinyc/tests/tests2/54_goto.expect | 8 - tinyc/tests/tests2/55_lshift_type.c | 52 - tinyc/tests/tests2/55_lshift_type.expect | 1 - tinyc/tests/tests2/60_errors_and_warnings.c | 51 - .../tests2/60_errors_and_warnings.expect | 28 - tinyc/tests/tests2/64_macro_nesting.c | 12 - tinyc/tests/tests2/64_macro_nesting.expect | 1 - tinyc/tests/tests2/67_macro_concat.c | 14 - tinyc/tests/tests2/67_macro_concat.expect | 2 - .../tests/tests2/70_floating_point_literals.c | 77 - .../tests2/70_floating_point_literals.expect | 53 - tinyc/tests/tests2/71_macro_empty_arg.c | 9 - tinyc/tests/tests2/71_macro_empty_arg.expect | 1 - tinyc/tests/tests2/72_long_long_constant.c | 19 - .../tests/tests2/72_long_long_constant.expect | 1 - tinyc/tests/tests2/73_arm64.c | 527 -- tinyc/tests/tests2/73_arm64.expect | 174 - tinyc/tests/tests2/75_array_in_struct_init.c | 33 - .../tests2/75_array_in_struct_init.expect | 72 - .../tests/tests2/76_dollars_in_identifiers.c | 41 - .../tests2/76_dollars_in_identifiers.expect | 14 - tinyc/tests/tests2/77_push_pop_macro.c | 30 - tinyc/tests/tests2/77_push_pop_macro.expect | 5 - tinyc/tests/tests2/78_vla_label.c | 45 - tinyc/tests/tests2/78_vla_label.expect | 6 - tinyc/tests/tests2/79_vla_continue.c | 116 - tinyc/tests/tests2/79_vla_continue.expect | 5 - tinyc/tests/tests2/80_flexarray.c | 25 - tinyc/tests/tests2/80_flexarray.expect | 0 tinyc/tests/tests2/81_types.c | 43 - tinyc/tests/tests2/81_types.expect | 0 tinyc/tests/tests2/82_attribs_position.c | 19 - tinyc/tests/tests2/82_attribs_position.expect | 0 tinyc/tests/tests2/83_utf8_in_identifiers.c | 9 - .../tests2/83_utf8_in_identifiers.expect | 2 - tinyc/tests/tests2/84_hex-float.c | 12 - tinyc/tests/tests2/84_hex-float.expect | 1 - tinyc/tests/tests2/85_asm-outside-function.c | 9 - .../tests2/85_asm-outside-function.expect | 1 - tinyc/tests/tests2/86_memory-model.c | 38 - tinyc/tests/tests2/86_memory-model.expect | 1 - tinyc/tests/tests2/87_dead_code.c | 122 - tinyc/tests/tests2/87_dead_code.expect | 18 - tinyc/tests/tests2/88_codeopt.c | 68 - tinyc/tests/tests2/88_codeopt.expect | 2 - tinyc/tests/tests2/89_nocode_wanted.c | 112 - tinyc/tests/tests2/89_nocode_wanted.expect | 14 - tinyc/tests/tests2/90_struct-init.c | 282 - tinyc/tests/tests2/90_struct-init.expect | 43 - tinyc/tests/tests2/91_ptr_longlong_arith32.c | 15 - .../tests2/91_ptr_longlong_arith32.expect | 1 - tinyc/tests/tests2/92_enum_bitfield.c | 57 - tinyc/tests/tests2/92_enum_bitfield.expect | 0 tinyc/tests/tests2/93_integer_promotion.c | 71 - .../tests/tests2/93_integer_promotion.expect | 46 - tinyc/tests/tests2/94_generic.c | 64 - tinyc/tests/tests2/94_generic.expect | 13 - tinyc/tests/tests2/95_bitfields.c | 218 - tinyc/tests/tests2/95_bitfields.expect | 149 - tinyc/tests/tests2/95_bitfields_ms.c | 2 - tinyc/tests/tests2/95_bitfields_ms.expect | 149 - tinyc/tests/tests2/96_nodata_wanted.c | 84 - tinyc/tests/tests2/96_nodata_wanted.expect | 23 - tinyc/tests/tests2/97_utf8_string_literal.c | 12 - .../tests2/97_utf8_string_literal.expect | 1 - tinyc/tests/tests2/98_al_ax_extend.c | 41 - tinyc/tests/tests2/98_al_ax_extend.expect | 9 - tinyc/tests/tests2/99_fastcall.c | 276 - tinyc/tests/tests2/99_fastcall.expect | 1 - tinyc/tests/vla_test.c | 84 - tinyc/texi2pod.pl | 427 - tinyc/win32/build-tcc.bat | 189 - tinyc/win32/examples/dll.c | 13 - tinyc/win32/examples/fib.c | 24 - tinyc/win32/examples/hello_dll.c | 20 - tinyc/win32/examples/hello_win.c | 163 - tinyc/win32/include/_mingw.h | 170 - tinyc/win32/include/assert.h | 57 - tinyc/win32/include/conio.h | 409 - tinyc/win32/include/ctype.h | 281 - tinyc/win32/include/dir.h | 31 - tinyc/win32/include/direct.h | 68 - tinyc/win32/include/dirent.h | 135 - tinyc/win32/include/dos.h | 55 - tinyc/win32/include/errno.h | 75 - tinyc/win32/include/excpt.h | 123 - tinyc/win32/include/fcntl.h | 52 - tinyc/win32/include/fenv.h | 108 - tinyc/win32/include/inttypes.h | 297 - tinyc/win32/include/io.h | 418 - tinyc/win32/include/limits.h | 111 - tinyc/win32/include/locale.h | 91 - tinyc/win32/include/malloc.h | 181 - tinyc/win32/include/math.h | 737 -- tinyc/win32/include/mem.h | 13 - tinyc/win32/include/memory.h | 40 - tinyc/win32/include/process.h | 176 - tinyc/win32/include/sec_api/conio_s.h | 42 - tinyc/win32/include/sec_api/crtdbg_s.h | 19 - tinyc/win32/include/sec_api/io_s.h | 33 - tinyc/win32/include/sec_api/mbstring_s.h | 52 - tinyc/win32/include/sec_api/search_s.h | 25 - tinyc/win32/include/sec_api/stdio_s.h | 145 - tinyc/win32/include/sec_api/stdlib_s.h | 67 - tinyc/win32/include/sec_api/stralign_s.h | 30 - tinyc/win32/include/sec_api/string_s.h | 41 - tinyc/win32/include/sec_api/sys/timeb_s.h | 34 - tinyc/win32/include/sec_api/tchar_s.h | 266 - tinyc/win32/include/sec_api/time_s.h | 61 - tinyc/win32/include/sec_api/wchar_s.h | 128 - tinyc/win32/include/setjmp.h | 160 - tinyc/win32/include/share.h | 28 - tinyc/win32/include/signal.h | 63 - tinyc/win32/include/stdint.h | 212 - tinyc/win32/include/stdio.h | 429 - tinyc/win32/include/stdlib.h | 580 -- tinyc/win32/include/string.h | 164 - tinyc/win32/include/sys/fcntl.h | 13 - tinyc/win32/include/sys/file.h | 14 - tinyc/win32/include/sys/locking.h | 30 - tinyc/win32/include/sys/stat.h | 290 - tinyc/win32/include/sys/time.h | 69 - tinyc/win32/include/sys/timeb.h | 133 - tinyc/win32/include/sys/types.h | 118 - tinyc/win32/include/sys/unistd.h | 14 - tinyc/win32/include/sys/utime.h | 146 - tinyc/win32/include/tcc/tcc_libm.h | 201 - tinyc/win32/include/tchar.h | 1102 --- tinyc/win32/include/time.h | 287 - tinyc/win32/include/vadefs.h | 11 - tinyc/win32/include/values.h | 4 - tinyc/win32/include/wchar.h | 873 -- tinyc/win32/include/wctype.h | 172 - tinyc/win32/include/winapi/basetsd.h | 149 - tinyc/win32/include/winapi/basetyps.h | 85 - tinyc/win32/include/winapi/guiddef.h | 156 - tinyc/win32/include/winapi/poppack.h | 8 - tinyc/win32/include/winapi/pshpack1.h | 8 - tinyc/win32/include/winapi/pshpack2.h | 8 - tinyc/win32/include/winapi/pshpack4.h | 8 - tinyc/win32/include/winapi/pshpack8.h | 8 - tinyc/win32/include/winapi/winbase.h | 2951 ------- tinyc/win32/include/winapi/wincon.h | 301 - tinyc/win32/include/winapi/windef.h | 293 - tinyc/win32/include/winapi/windows.h | 127 - tinyc/win32/include/winapi/winerror.h | 3166 ------- tinyc/win32/include/winapi/wingdi.h | 4080 --------- tinyc/win32/include/winapi/winnt.h | 5835 ------------- tinyc/win32/include/winapi/winreg.h | 272 - tinyc/win32/include/winapi/winuser.h | 5651 ------------- tinyc/win32/include/winapi/winver.h | 160 - tinyc/win32/lib/chkstk.S | 191 - tinyc/win32/lib/crt1.c | 79 - tinyc/win32/lib/crt1w.c | 3 - tinyc/win32/lib/dllcrt1.c | 13 - tinyc/win32/lib/dllmain.c | 9 - tinyc/win32/lib/gdi32.def | 337 - tinyc/win32/lib/kernel32.def | 770 -- tinyc/win32/lib/msvcrt.def | 1399 ---- tinyc/win32/lib/user32.def | 658 -- tinyc/win32/lib/wincrt1.c | 75 - tinyc/win32/lib/wincrt1w.c | 3 - tinyc/win32/tcc-win32.txt | 168 - tinyc/x86_64-asm.h | 525 -- tinyc/x86_64-gen.c | 2229 ----- tinyc/x86_64-link.c | 295 - tools/deps.nim | 22 + 390 files changed, 80 insertions(+), 99388 deletions(-) delete mode 100644 tinyc/arm-asm.c delete mode 100644 tinyc/arm-gen.c delete mode 100644 tinyc/arm-link.c delete mode 100644 tinyc/arm64-gen.c delete mode 100644 tinyc/arm64-link.c delete mode 100644 tinyc/c67-gen.c delete mode 100644 tinyc/c67-link.c delete mode 100644 tinyc/coff.h delete mode 100644 tinyc/config.h delete mode 100644 tinyc/conftest.c delete mode 100644 tinyc/elf.h delete mode 100644 tinyc/examples/ex1.c delete mode 100644 tinyc/examples/ex2.c delete mode 100644 tinyc/examples/ex3.c delete mode 100644 tinyc/examples/ex4.c delete mode 100644 tinyc/examples/ex5.c delete mode 100644 tinyc/i386-asm.c delete mode 100644 tinyc/i386-asm.h delete mode 100644 tinyc/i386-gen.c delete mode 100644 tinyc/i386-link.c delete mode 100644 tinyc/i386-tok.h delete mode 100644 tinyc/il-gen.c delete mode 100644 tinyc/il-opcodes.h delete mode 100644 tinyc/include/float.h delete mode 100644 tinyc/include/stdarg.h delete mode 100644 tinyc/include/stdbool.h delete mode 100644 tinyc/include/stddef.h delete mode 100644 tinyc/include/varargs.h delete mode 100644 tinyc/lib/alloca-arm.S delete mode 100644 tinyc/lib/alloca86-bt.S delete mode 100644 tinyc/lib/alloca86.S delete mode 100644 tinyc/lib/alloca86_64-bt.S delete mode 100644 tinyc/lib/alloca86_64.S delete mode 100644 tinyc/lib/armeabi.c delete mode 100644 tinyc/lib/armflush.c delete mode 100644 tinyc/lib/bcheck.c delete mode 100644 tinyc/lib/lib-arm64.c delete mode 100644 tinyc/lib/libtcc1.c delete mode 100644 tinyc/lib/va_list.c delete mode 100644 tinyc/libtcc.c delete mode 100644 tinyc/libtcc.h delete mode 100644 tinyc/stab.def delete mode 100644 tinyc/stab.h delete mode 100644 tinyc/tcc-doc.texi delete mode 100644 tinyc/tcc.c delete mode 100644 tinyc/tcc.h delete mode 100644 tinyc/tccasm.c delete mode 100644 tinyc/tcccoff.c delete mode 100644 tinyc/tccelf.c delete mode 100644 tinyc/tccgen.c delete mode 100644 tinyc/tcclib.h delete mode 100644 tinyc/tccpe.c delete mode 100644 tinyc/tccpp.c delete mode 100644 tinyc/tccrun.c delete mode 100644 tinyc/tcctok.h delete mode 100644 tinyc/tcctools.c delete mode 100644 tinyc/tests/42test.h delete mode 100644 tinyc/tests/abitest.c delete mode 100644 tinyc/tests/asmtest.S delete mode 100644 tinyc/tests/boundtest.c delete mode 100644 tinyc/tests/gcctestsuite.sh delete mode 100644 tinyc/tests/libtcc_test.c delete mode 100644 tinyc/tests/pp/01.c delete mode 100644 tinyc/tests/pp/01.expect delete mode 100644 tinyc/tests/pp/02.c delete mode 100644 tinyc/tests/pp/02.expect delete mode 100644 tinyc/tests/pp/03.c delete mode 100644 tinyc/tests/pp/03.expect delete mode 100644 tinyc/tests/pp/04.c delete mode 100644 tinyc/tests/pp/04.expect delete mode 100644 tinyc/tests/pp/05.c delete mode 100644 tinyc/tests/pp/05.expect delete mode 100644 tinyc/tests/pp/06.c delete mode 100644 tinyc/tests/pp/06.expect delete mode 100644 tinyc/tests/pp/07.c delete mode 100644 tinyc/tests/pp/07.expect delete mode 100644 tinyc/tests/pp/08.c delete mode 100644 tinyc/tests/pp/08.expect delete mode 100644 tinyc/tests/pp/09.c delete mode 100644 tinyc/tests/pp/09.expect delete mode 100644 tinyc/tests/pp/10.c delete mode 100644 tinyc/tests/pp/10.expect delete mode 100644 tinyc/tests/pp/11.c delete mode 100644 tinyc/tests/pp/11.expect delete mode 100644 tinyc/tests/pp/12.S delete mode 100644 tinyc/tests/pp/12.expect delete mode 100644 tinyc/tests/pp/13.S delete mode 100644 tinyc/tests/pp/13.expect delete mode 100644 tinyc/tests/pp/14.c delete mode 100644 tinyc/tests/pp/14.expect delete mode 100644 tinyc/tests/pp/15.c delete mode 100644 tinyc/tests/pp/15.expect delete mode 100644 tinyc/tests/pp/16.c delete mode 100644 tinyc/tests/pp/16.expect delete mode 100644 tinyc/tests/pp/17.c delete mode 100644 tinyc/tests/pp/17.expect delete mode 100644 tinyc/tests/pp/18.c delete mode 100644 tinyc/tests/pp/18.expect delete mode 100644 tinyc/tests/pp/19.c delete mode 100644 tinyc/tests/pp/19.expect delete mode 100644 tinyc/tests/pp/20.c delete mode 100644 tinyc/tests/pp/20.expect delete mode 100644 tinyc/tests/pp/21.c delete mode 100644 tinyc/tests/pp/21.expect delete mode 100644 tinyc/tests/pp/pp-counter.c delete mode 100644 tinyc/tests/pp/pp-counter.expect delete mode 100644 tinyc/tests/tcctest.c delete mode 100644 tinyc/tests/tcctest.h delete mode 100644 tinyc/tests/testfp.c delete mode 100644 tinyc/tests/tests2/00_assignment.c delete mode 100644 tinyc/tests/tests2/00_assignment.expect delete mode 100644 tinyc/tests/tests2/01_comment.c delete mode 100644 tinyc/tests/tests2/01_comment.expect delete mode 100644 tinyc/tests/tests2/02_printf.c delete mode 100644 tinyc/tests/tests2/02_printf.expect delete mode 100644 tinyc/tests/tests2/03_struct.c delete mode 100644 tinyc/tests/tests2/03_struct.expect delete mode 100644 tinyc/tests/tests2/04_for.c delete mode 100644 tinyc/tests/tests2/04_for.expect delete mode 100644 tinyc/tests/tests2/05_array.c delete mode 100644 tinyc/tests/tests2/05_array.expect delete mode 100644 tinyc/tests/tests2/06_case.c delete mode 100644 tinyc/tests/tests2/06_case.expect delete mode 100644 tinyc/tests/tests2/07_function.c delete mode 100644 tinyc/tests/tests2/07_function.expect delete mode 100644 tinyc/tests/tests2/08_while.c delete mode 100644 tinyc/tests/tests2/08_while.expect delete mode 100644 tinyc/tests/tests2/09_do_while.c delete mode 100644 tinyc/tests/tests2/09_do_while.expect delete mode 100644 tinyc/tests/tests2/10_pointer.c delete mode 100644 tinyc/tests/tests2/10_pointer.expect delete mode 100644 tinyc/tests/tests2/11_precedence.c delete mode 100644 tinyc/tests/tests2/11_precedence.expect delete mode 100644 tinyc/tests/tests2/12_hashdefine.c delete mode 100644 tinyc/tests/tests2/12_hashdefine.expect delete mode 100644 tinyc/tests/tests2/13_integer_literals.c delete mode 100644 tinyc/tests/tests2/13_integer_literals.expect delete mode 100644 tinyc/tests/tests2/14_if.c delete mode 100644 tinyc/tests/tests2/14_if.expect delete mode 100644 tinyc/tests/tests2/15_recursion.c delete mode 100644 tinyc/tests/tests2/15_recursion.expect delete mode 100644 tinyc/tests/tests2/16_nesting.c delete mode 100644 tinyc/tests/tests2/16_nesting.expect delete mode 100644 tinyc/tests/tests2/17_enum.c delete mode 100644 tinyc/tests/tests2/17_enum.expect delete mode 100644 tinyc/tests/tests2/18_include.c delete mode 100644 tinyc/tests/tests2/18_include.expect delete mode 100644 tinyc/tests/tests2/18_include.h delete mode 100644 tinyc/tests/tests2/19_pointer_arithmetic.c delete mode 100644 tinyc/tests/tests2/19_pointer_arithmetic.expect delete mode 100644 tinyc/tests/tests2/20_pointer_comparison.c delete mode 100644 tinyc/tests/tests2/20_pointer_comparison.expect delete mode 100644 tinyc/tests/tests2/21_char_array.c delete mode 100644 tinyc/tests/tests2/21_char_array.expect delete mode 100644 tinyc/tests/tests2/22_floating_point.c delete mode 100644 tinyc/tests/tests2/22_floating_point.expect delete mode 100644 tinyc/tests/tests2/23_type_coercion.c delete mode 100644 tinyc/tests/tests2/23_type_coercion.expect delete mode 100644 tinyc/tests/tests2/24_math_library.c delete mode 100644 tinyc/tests/tests2/24_math_library.expect delete mode 100644 tinyc/tests/tests2/25_quicksort.c delete mode 100644 tinyc/tests/tests2/25_quicksort.expect delete mode 100644 tinyc/tests/tests2/26_character_constants.c delete mode 100644 tinyc/tests/tests2/26_character_constants.expect delete mode 100644 tinyc/tests/tests2/27_sizeof.c delete mode 100644 tinyc/tests/tests2/27_sizeof.expect delete mode 100644 tinyc/tests/tests2/28_strings.c delete mode 100644 tinyc/tests/tests2/28_strings.expect delete mode 100644 tinyc/tests/tests2/29_array_address.c delete mode 100644 tinyc/tests/tests2/29_array_address.expect delete mode 100644 tinyc/tests/tests2/30_hanoi.c delete mode 100644 tinyc/tests/tests2/30_hanoi.expect delete mode 100644 tinyc/tests/tests2/31_args.c delete mode 100644 tinyc/tests/tests2/31_args.expect delete mode 100644 tinyc/tests/tests2/32_led.c delete mode 100644 tinyc/tests/tests2/32_led.expect delete mode 100644 tinyc/tests/tests2/33_ternary_op.c delete mode 100644 tinyc/tests/tests2/33_ternary_op.expect delete mode 100644 tinyc/tests/tests2/34_array_assignment.c delete mode 100644 tinyc/tests/tests2/34_array_assignment.expect delete mode 100644 tinyc/tests/tests2/35_sizeof.c delete mode 100644 tinyc/tests/tests2/35_sizeof.expect delete mode 100644 tinyc/tests/tests2/36_array_initialisers.c delete mode 100644 tinyc/tests/tests2/36_array_initialisers.expect delete mode 100644 tinyc/tests/tests2/37_sprintf.c delete mode 100644 tinyc/tests/tests2/37_sprintf.expect delete mode 100644 tinyc/tests/tests2/38_multiple_array_index.c delete mode 100644 tinyc/tests/tests2/38_multiple_array_index.expect delete mode 100644 tinyc/tests/tests2/39_typedef.c delete mode 100644 tinyc/tests/tests2/39_typedef.expect delete mode 100644 tinyc/tests/tests2/40_stdio.c delete mode 100644 tinyc/tests/tests2/40_stdio.expect delete mode 100644 tinyc/tests/tests2/41_hashif.c delete mode 100644 tinyc/tests/tests2/41_hashif.expect delete mode 100644 tinyc/tests/tests2/42_function_pointer.c delete mode 100644 tinyc/tests/tests2/42_function_pointer.expect delete mode 100644 tinyc/tests/tests2/43_void_param.c delete mode 100644 tinyc/tests/tests2/43_void_param.expect delete mode 100644 tinyc/tests/tests2/44_scoped_declarations.c delete mode 100644 tinyc/tests/tests2/44_scoped_declarations.expect delete mode 100644 tinyc/tests/tests2/45_empty_for.c delete mode 100644 tinyc/tests/tests2/45_empty_for.expect delete mode 100644 tinyc/tests/tests2/46_grep.c delete mode 100644 tinyc/tests/tests2/46_grep.expect delete mode 100644 tinyc/tests/tests2/47_switch_return.c delete mode 100644 tinyc/tests/tests2/47_switch_return.expect delete mode 100644 tinyc/tests/tests2/48_nested_break.c delete mode 100644 tinyc/tests/tests2/48_nested_break.expect delete mode 100644 tinyc/tests/tests2/49_bracket_evaluation.c delete mode 100644 tinyc/tests/tests2/49_bracket_evaluation.expect delete mode 100644 tinyc/tests/tests2/50_logical_second_arg.c delete mode 100644 tinyc/tests/tests2/50_logical_second_arg.expect delete mode 100644 tinyc/tests/tests2/51_static.c delete mode 100644 tinyc/tests/tests2/51_static.expect delete mode 100644 tinyc/tests/tests2/52_unnamed_enum.c delete mode 100644 tinyc/tests/tests2/52_unnamed_enum.expect delete mode 100644 tinyc/tests/tests2/54_goto.c delete mode 100644 tinyc/tests/tests2/54_goto.expect delete mode 100644 tinyc/tests/tests2/55_lshift_type.c delete mode 100644 tinyc/tests/tests2/55_lshift_type.expect delete mode 100644 tinyc/tests/tests2/60_errors_and_warnings.c delete mode 100644 tinyc/tests/tests2/60_errors_and_warnings.expect delete mode 100644 tinyc/tests/tests2/64_macro_nesting.c delete mode 100644 tinyc/tests/tests2/64_macro_nesting.expect delete mode 100644 tinyc/tests/tests2/67_macro_concat.c delete mode 100644 tinyc/tests/tests2/67_macro_concat.expect delete mode 100644 tinyc/tests/tests2/70_floating_point_literals.c delete mode 100644 tinyc/tests/tests2/70_floating_point_literals.expect delete mode 100644 tinyc/tests/tests2/71_macro_empty_arg.c delete mode 100644 tinyc/tests/tests2/71_macro_empty_arg.expect delete mode 100644 tinyc/tests/tests2/72_long_long_constant.c delete mode 100644 tinyc/tests/tests2/72_long_long_constant.expect delete mode 100644 tinyc/tests/tests2/73_arm64.c delete mode 100644 tinyc/tests/tests2/73_arm64.expect delete mode 100644 tinyc/tests/tests2/75_array_in_struct_init.c delete mode 100644 tinyc/tests/tests2/75_array_in_struct_init.expect delete mode 100644 tinyc/tests/tests2/76_dollars_in_identifiers.c delete mode 100644 tinyc/tests/tests2/76_dollars_in_identifiers.expect delete mode 100644 tinyc/tests/tests2/77_push_pop_macro.c delete mode 100644 tinyc/tests/tests2/77_push_pop_macro.expect delete mode 100644 tinyc/tests/tests2/78_vla_label.c delete mode 100644 tinyc/tests/tests2/78_vla_label.expect delete mode 100644 tinyc/tests/tests2/79_vla_continue.c delete mode 100644 tinyc/tests/tests2/79_vla_continue.expect delete mode 100644 tinyc/tests/tests2/80_flexarray.c delete mode 100644 tinyc/tests/tests2/80_flexarray.expect delete mode 100644 tinyc/tests/tests2/81_types.c delete mode 100644 tinyc/tests/tests2/81_types.expect delete mode 100644 tinyc/tests/tests2/82_attribs_position.c delete mode 100644 tinyc/tests/tests2/82_attribs_position.expect delete mode 100644 tinyc/tests/tests2/83_utf8_in_identifiers.c delete mode 100644 tinyc/tests/tests2/83_utf8_in_identifiers.expect delete mode 100644 tinyc/tests/tests2/84_hex-float.c delete mode 100644 tinyc/tests/tests2/84_hex-float.expect delete mode 100644 tinyc/tests/tests2/85_asm-outside-function.c delete mode 100644 tinyc/tests/tests2/85_asm-outside-function.expect delete mode 100644 tinyc/tests/tests2/86_memory-model.c delete mode 100644 tinyc/tests/tests2/86_memory-model.expect delete mode 100644 tinyc/tests/tests2/87_dead_code.c delete mode 100644 tinyc/tests/tests2/87_dead_code.expect delete mode 100644 tinyc/tests/tests2/88_codeopt.c delete mode 100644 tinyc/tests/tests2/88_codeopt.expect delete mode 100644 tinyc/tests/tests2/89_nocode_wanted.c delete mode 100644 tinyc/tests/tests2/89_nocode_wanted.expect delete mode 100644 tinyc/tests/tests2/90_struct-init.c delete mode 100644 tinyc/tests/tests2/90_struct-init.expect delete mode 100644 tinyc/tests/tests2/91_ptr_longlong_arith32.c delete mode 100644 tinyc/tests/tests2/91_ptr_longlong_arith32.expect delete mode 100644 tinyc/tests/tests2/92_enum_bitfield.c delete mode 100644 tinyc/tests/tests2/92_enum_bitfield.expect delete mode 100644 tinyc/tests/tests2/93_integer_promotion.c delete mode 100644 tinyc/tests/tests2/93_integer_promotion.expect delete mode 100644 tinyc/tests/tests2/94_generic.c delete mode 100644 tinyc/tests/tests2/94_generic.expect delete mode 100644 tinyc/tests/tests2/95_bitfields.c delete mode 100644 tinyc/tests/tests2/95_bitfields.expect delete mode 100644 tinyc/tests/tests2/95_bitfields_ms.c delete mode 100644 tinyc/tests/tests2/95_bitfields_ms.expect delete mode 100644 tinyc/tests/tests2/96_nodata_wanted.c delete mode 100644 tinyc/tests/tests2/96_nodata_wanted.expect delete mode 100644 tinyc/tests/tests2/97_utf8_string_literal.c delete mode 100644 tinyc/tests/tests2/97_utf8_string_literal.expect delete mode 100644 tinyc/tests/tests2/98_al_ax_extend.c delete mode 100644 tinyc/tests/tests2/98_al_ax_extend.expect delete mode 100644 tinyc/tests/tests2/99_fastcall.c delete mode 100644 tinyc/tests/tests2/99_fastcall.expect delete mode 100644 tinyc/tests/vla_test.c delete mode 100644 tinyc/texi2pod.pl delete mode 100644 tinyc/win32/build-tcc.bat delete mode 100644 tinyc/win32/examples/dll.c delete mode 100644 tinyc/win32/examples/fib.c delete mode 100644 tinyc/win32/examples/hello_dll.c delete mode 100644 tinyc/win32/examples/hello_win.c delete mode 100644 tinyc/win32/include/_mingw.h delete mode 100644 tinyc/win32/include/assert.h delete mode 100644 tinyc/win32/include/conio.h delete mode 100644 tinyc/win32/include/ctype.h delete mode 100644 tinyc/win32/include/dir.h delete mode 100644 tinyc/win32/include/direct.h delete mode 100644 tinyc/win32/include/dirent.h delete mode 100644 tinyc/win32/include/dos.h delete mode 100644 tinyc/win32/include/errno.h delete mode 100644 tinyc/win32/include/excpt.h delete mode 100644 tinyc/win32/include/fcntl.h delete mode 100644 tinyc/win32/include/fenv.h delete mode 100644 tinyc/win32/include/inttypes.h delete mode 100644 tinyc/win32/include/io.h delete mode 100644 tinyc/win32/include/limits.h delete mode 100644 tinyc/win32/include/locale.h delete mode 100644 tinyc/win32/include/malloc.h delete mode 100644 tinyc/win32/include/math.h delete mode 100644 tinyc/win32/include/mem.h delete mode 100644 tinyc/win32/include/memory.h delete mode 100644 tinyc/win32/include/process.h delete mode 100644 tinyc/win32/include/sec_api/conio_s.h delete mode 100644 tinyc/win32/include/sec_api/crtdbg_s.h delete mode 100644 tinyc/win32/include/sec_api/io_s.h delete mode 100644 tinyc/win32/include/sec_api/mbstring_s.h delete mode 100644 tinyc/win32/include/sec_api/search_s.h delete mode 100644 tinyc/win32/include/sec_api/stdio_s.h delete mode 100644 tinyc/win32/include/sec_api/stdlib_s.h delete mode 100644 tinyc/win32/include/sec_api/stralign_s.h delete mode 100644 tinyc/win32/include/sec_api/string_s.h delete mode 100644 tinyc/win32/include/sec_api/sys/timeb_s.h delete mode 100644 tinyc/win32/include/sec_api/tchar_s.h delete mode 100644 tinyc/win32/include/sec_api/time_s.h delete mode 100644 tinyc/win32/include/sec_api/wchar_s.h delete mode 100644 tinyc/win32/include/setjmp.h delete mode 100644 tinyc/win32/include/share.h delete mode 100644 tinyc/win32/include/signal.h delete mode 100644 tinyc/win32/include/stdint.h delete mode 100644 tinyc/win32/include/stdio.h delete mode 100644 tinyc/win32/include/stdlib.h delete mode 100644 tinyc/win32/include/string.h delete mode 100644 tinyc/win32/include/sys/fcntl.h delete mode 100644 tinyc/win32/include/sys/file.h delete mode 100644 tinyc/win32/include/sys/locking.h delete mode 100644 tinyc/win32/include/sys/stat.h delete mode 100644 tinyc/win32/include/sys/time.h delete mode 100644 tinyc/win32/include/sys/timeb.h delete mode 100644 tinyc/win32/include/sys/types.h delete mode 100644 tinyc/win32/include/sys/unistd.h delete mode 100644 tinyc/win32/include/sys/utime.h delete mode 100644 tinyc/win32/include/tcc/tcc_libm.h delete mode 100644 tinyc/win32/include/tchar.h delete mode 100644 tinyc/win32/include/time.h delete mode 100644 tinyc/win32/include/vadefs.h delete mode 100644 tinyc/win32/include/values.h delete mode 100644 tinyc/win32/include/wchar.h delete mode 100644 tinyc/win32/include/wctype.h delete mode 100644 tinyc/win32/include/winapi/basetsd.h delete mode 100644 tinyc/win32/include/winapi/basetyps.h delete mode 100644 tinyc/win32/include/winapi/guiddef.h delete mode 100644 tinyc/win32/include/winapi/poppack.h delete mode 100644 tinyc/win32/include/winapi/pshpack1.h delete mode 100644 tinyc/win32/include/winapi/pshpack2.h delete mode 100644 tinyc/win32/include/winapi/pshpack4.h delete mode 100644 tinyc/win32/include/winapi/pshpack8.h delete mode 100644 tinyc/win32/include/winapi/winbase.h delete mode 100644 tinyc/win32/include/winapi/wincon.h delete mode 100644 tinyc/win32/include/winapi/windef.h delete mode 100644 tinyc/win32/include/winapi/windows.h delete mode 100644 tinyc/win32/include/winapi/winerror.h delete mode 100644 tinyc/win32/include/winapi/wingdi.h delete mode 100644 tinyc/win32/include/winapi/winnt.h delete mode 100644 tinyc/win32/include/winapi/winreg.h delete mode 100644 tinyc/win32/include/winapi/winuser.h delete mode 100644 tinyc/win32/include/winapi/winver.h delete mode 100644 tinyc/win32/lib/chkstk.S delete mode 100644 tinyc/win32/lib/crt1.c delete mode 100644 tinyc/win32/lib/crt1w.c delete mode 100644 tinyc/win32/lib/dllcrt1.c delete mode 100644 tinyc/win32/lib/dllmain.c delete mode 100644 tinyc/win32/lib/gdi32.def delete mode 100644 tinyc/win32/lib/kernel32.def delete mode 100644 tinyc/win32/lib/msvcrt.def delete mode 100644 tinyc/win32/lib/user32.def delete mode 100644 tinyc/win32/lib/wincrt1.c delete mode 100644 tinyc/win32/lib/wincrt1w.c delete mode 100644 tinyc/win32/tcc-win32.txt delete mode 100644 tinyc/x86_64-asm.h delete mode 100644 tinyc/x86_64-gen.c delete mode 100644 tinyc/x86_64-link.c create mode 100644 tools/deps.nim diff --git a/.gitignore b/.gitignore index fee8f218d..b967707d8 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,7 @@ testament.db /tests/**/*.json /tests/**/*.js /csources -dist/ +/dist/ # Private directories and files (IDEs) .*/ diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e93465d73..a8045e054 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1941,8 +1941,8 @@ proc writeModule(m: BModule, pending: bool) = var code = genModule(m, cf) if code != nil or m.config.symbolFiles != disabledSf: when hasTinyCBackend: - if conf.cmd == cmdRun: - tccgen.compileCCode($code) + if m.config.cmd == cmdRun: + tccgen.compileCCode($code, m.config) onExit() return diff --git a/compiler/main.nim b/compiler/main.nim index 0b538cb5a..217858137 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -200,7 +200,7 @@ proc mainCommand*(graph: ModuleGraph) = of "run": conf.cmd = cmdRun when hasTinyCBackend: - extccomp.setCC("tcc") + extccomp.setCC(conf, "tcc", unknownLineInfo) commandCompileToC(graph) else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") diff --git a/compiler/nim.nim b/compiler/nim.nim index b916f0d85..4bcb1b510 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -98,7 +98,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = if conf.errorCounter != 0: return when hasTinyCBackend: if conf.cmd == cmdRun: - tccgen.run(conf.arguments) + tccgen.run(conf, conf.arguments) if optRun in conf.globalOptions: var ex = quoteShell conf.absOutFile if conf.cmd == cmdCompileToJS: diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim index 8397185e8..ba553906a 100644 --- a/compiler/tccgen.nim +++ b/compiler/tccgen.nim @@ -8,12 +8,20 @@ # import - os, strutils, options, msgs, tinyc + os, strutils, options, msgs, tinyc, lineinfos, sequtils -{.compile: "../tinyc/libtcc.c".} +const tinyPrefix = "dist/nim-tinyc-archive".unixToNativePath +const nimRoot = currentSourcePath.parentDir.parentDir +const tinycRoot = nimRoot / tinyPrefix +when not dirExists(tinycRoot): + static: doAssert false, $(tinycRoot, "requires: ./koch installdeps tinyc") +{.compile: tinycRoot / "tinyc/libtcc.c".} + +var + gConf: ConfigRef # ugly but can be cleaned up if this is revived proc tinyCErrorHandler(closure: pointer, msg: cstring) {.cdecl.} = - rawMessage(errGenerated, $msg) + rawMessage(gConf, errGenerated, $msg) proc initTinyCState: PccState = result = openCCState() @@ -25,7 +33,7 @@ var proc addFile(filename: string) = if addFile(gTinyC, filename) != 0'i32: - rawMessage(errCannotOpenFile, filename) + rawMessage(gConf, errCannotOpenFile, filename) proc setupEnvironment = when defined(amd64): @@ -35,42 +43,47 @@ proc setupEnvironment = when defined(linux): defineSymbol(gTinyC, "__linux__", nil) defineSymbol(gTinyC, "__linux", nil) - var nimDir = getPrefixDir() + + var nimDir = getPrefixDir(gConf).string + var tinycRoot = nimDir / tinyPrefix + let libpath = nimDir / "lib" addIncludePath(gTinyC, libpath) when defined(windows): - addSysincludePath(gTinyC, nimDir / "tinyc/win32/include") - addSysincludePath(gTinyC, nimDir / "tinyc/include") + addSysincludePath(gTinyC, tinycRoot / "tinyc/win32/include") + addSysincludePath(gTinyC, tinycRoot / "tinyc/include") when defined(windows): defineSymbol(gTinyC, "_WIN32", nil) # we need Mingw's headers too: - var gccbin = getConfigVar("gcc.path") % ["nim", nimDir] + var gccbin = getConfigVar("gcc.path") % ["nim", tinycRoot] addSysincludePath(gTinyC, gccbin /../ "include") - #addFile(nimDir / r"tinyc\win32\wincrt1.o") - addFile(nimDir / r"tinyc\win32\alloca86.o") - addFile(nimDir / r"tinyc\win32\chkstk.o") - #addFile(nimDir / r"tinyc\win32\crt1.o") + #addFile(tinycRoot / r"tinyc\win32\wincrt1.o") + addFile(tinycRoot / r"tinyc\win32\alloca86.o") + addFile(tinycRoot / r"tinyc\win32\chkstk.o") + #addFile(tinycRoot / r"tinyc\win32\crt1.o") - #addFile(nimDir / r"tinyc\win32\dllcrt1.o") - #addFile(nimDir / r"tinyc\win32\dllmain.o") - addFile(nimDir / r"tinyc\win32\libtcc1.o") + #addFile(tinycRoot / r"tinyc\win32\dllcrt1.o") + #addFile(tinycRoot / r"tinyc\win32\dllmain.o") + addFile(tinycRoot / r"tinyc\win32\libtcc1.o") - #addFile(nimDir / r"tinyc\win32\lib\crt1.c") - #addFile(nimDir / r"tinyc\lib\libtcc1.c") + #addFile(tinycRoot / r"tinyc\win32\lib\crt1.c") + #addFile(tinycRoot / r"tinyc\lib\libtcc1.c") else: addSysincludePath(gTinyC, "/usr/include") when defined(amd64): addSysincludePath(gTinyC, "/usr/include/x86_64-linux-gnu") -proc compileCCode*(ccode: string) = +proc compileCCode*(ccode: string, conf: ConfigRef) = + gConf = conf if not libIncluded: libIncluded = true setupEnvironment() discard compileString(gTinyC, ccode) -proc run*(args: string) = - var s = @[cstring(gProjectName)] & map(split(args), proc(x: string): cstring = cstring(x)) +proc run*(conf: ConfigRef, args: string) = + doAssert gConf == conf + var s = @[cstring(conf.projectName)] & map(split(args), proc(x: string): cstring = cstring(x)) var err = tinyc.run(gTinyC, cint(s.len), cast[cstringArray](addr(s[0]))) != 0'i32 closeCCState(gTinyC) - if err: rawMessage(errExecutionOfProgramFailed, "") + if err: rawMessage(conf, errUnknown, "") diff --git a/koch.nim b/koch.nim index 511b78df6..ac7e34a07 100644 --- a/koch.nim +++ b/koch.nim @@ -31,6 +31,7 @@ import os, strutils, parseopt, osproc import tools / kochdocs +import tools / deps const VersionAsString = system.NimVersion @@ -73,6 +74,7 @@ Commands for core developers: zip builds the installation zip package xz builds the installation tar.xz package testinstall test tar.xz package; Unix only! + installdeps [options] installs external dependency (eg tinyc) to dist/ tests [options] run the testsuite (run a subset of tests by specifying a category, e.g. `tests cat async`) temp options creates a temporary compiler for testing @@ -120,6 +122,7 @@ proc copyExe(source, dest: string) = const compileNimInst = "tools/niminst/niminst" + distDir = "dist" proc csource(args: string) = nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " & @@ -127,18 +130,13 @@ proc csource(args: string) = [args, VersionAsString, compileNimInst]) proc bundleC2nim(args: string) = - if not dirExists("dist/c2nim/.git"): - exec("git clone -q https://github.com/nim-lang/c2nim.git dist/c2nim") + cloneDependency(distDir, "https://github.com/nim-lang/c2nim.git") nimCompile("dist/c2nim/c2nim", options = "--noNimblePath --path:. " & args) proc bundleNimbleExe(latest: bool, args: string) = - if not dirExists("dist/nimble/.git"): - exec("git clone -q https://github.com/nim-lang/nimble.git dist/nimble") - if not latest: - withDir("dist/nimble"): - exec("git fetch") - exec("git checkout " & NimbleStableCommit) + let commit = if latest: "HEAD" else: NimbleStableCommit + cloneDependency(distDir, "https://github.com/nim-lang/nimble.git", commit = commit) # installer.ini expects it under $nim/bin nimCompile("dist/nimble/src/nimble.nim", options = "-d:release --nilseqs:on " & args) @@ -156,6 +154,7 @@ proc buildNimble(latest: bool, args: string) = while dirExists("dist/nimble" & $id): inc id installDir = "dist/nimble" & $id + # consider using/adapting cloneDependency exec("git clone -q https://github.com/nim-lang/nimble.git " & installDir) withDir(installDir): if latest: @@ -504,6 +503,17 @@ proc hostInfo(): string = "hostOS: $1, hostCPU: $2, int: $3, float: $4, cpuEndian: $5, cwd: $6" % [hostOS, hostCPU, $int.sizeof, $float.sizeof, $cpuEndian, getCurrentDir()] +proc installDeps(dep: string, commit = "") = + # the hashes/urls are version controlled here, so can be changed seamlessly + # and tied to a nim release (mimicking git submodules) + var commit = commit + case dep + of "tinyc": + if commit.len == 0: commit = "916cc2f94818a8a382dd8d4b8420978816c1dfb3" + cloneDependency(distDir, "https://github.com/timotheecour/nim-tinyc-archive", commit) + else: doAssert false, "unsupported: " & dep + # xxx: also add linenoise, niminst etc, refs https://github.com/nim-lang/RFCs/issues/206 + proc runCI(cmd: string) = doAssert cmd.len == 0, cmd # avoid silently ignoring echo "runCI: ", cmd @@ -648,6 +658,7 @@ when isMainModule: of "distrohelper": geninstall() of "install": install(op.cmdLineRest) of "testinstall": testUnixInstall(op.cmdLineRest) + of "installdeps": installDeps(op.cmdLineRest) of "runci": runCI(op.cmdLineRest) of "test", "tests": tests(op.cmdLineRest) of "temp": temp(op.cmdLineRest) diff --git a/tinyc/arm-asm.c b/tinyc/arm-asm.c deleted file mode 100644 index 3b5ae661c..000000000 --- a/tinyc/arm-asm.c +++ /dev/null @@ -1,94 +0,0 @@ -/*************************************************************/ -/* - * ARM dummy assembler for TCC - * - */ - -#ifdef TARGET_DEFS_ONLY - -#define CONFIG_TCC_ASM -#define NB_ASM_REGS 16 - -ST_FUNC void g(int c); -ST_FUNC void gen_le16(int c); -ST_FUNC void gen_le32(int c); - -/*************************************************************/ -#else -/*************************************************************/ - -#include "tcc.h" - -static void asm_error(void) -{ - tcc_error("ARM asm not implemented."); -} - -/* XXX: make it faster ? */ -ST_FUNC void g(int c) -{ - int ind1; - if (nocode_wanted) - return; - ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) - section_realloc(cur_text_section, ind1); - cur_text_section->data[ind] = c; - ind = ind1; -} - -ST_FUNC void gen_le16 (int i) -{ - g(i); - g(i>>8); -} - -ST_FUNC void gen_le32 (int i) -{ - gen_le16(i); - gen_le16(i>>16); -} - -ST_FUNC void gen_expr32(ExprValue *pe) -{ - gen_le32(pe->v); -} - -ST_FUNC void asm_opcode(TCCState *s1, int opcode) -{ - asm_error(); -} - -ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) -{ - asm_error(); -} - -/* generate prolog and epilog code for asm statement */ -ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, - int nb_outputs, int is_output, - uint8_t *clobber_regs, - int out_reg) -{ -} - -ST_FUNC void asm_compute_constraints(ASMOperand *operands, - int nb_operands, int nb_outputs, - const uint8_t *clobber_regs, - int *pout_reg) -{ -} - -ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) -{ - asm_error(); -} - -ST_FUNC int asm_parse_regvar (int t) -{ - asm_error(); - return -1; -} - -/*************************************************************/ -#endif /* ndef TARGET_DEFS_ONLY */ diff --git a/tinyc/arm-gen.c b/tinyc/arm-gen.c deleted file mode 100644 index f535a09ce..000000000 --- a/tinyc/arm-gen.c +++ /dev/null @@ -1,2151 +0,0 @@ -/* - * ARMv4 code generator for TCC - * - * Copyright (c) 2003 Daniel Glöckner - * Copyright (c) 2012 Thomas Preud'homme - * - * Based on i386-gen.c by Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef TARGET_DEFS_ONLY - -#if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP) -#error "Currently TinyCC only supports float computation with VFP instructions" -#endif - -/* number of available registers */ -#ifdef TCC_ARM_VFP -#define NB_REGS 13 -#else -#define NB_REGS 9 -#endif - -#ifndef TCC_CPU_VERSION -# define TCC_CPU_VERSION 5 -#endif - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_R0 0x0004 -#define RC_R1 0x0008 -#define RC_R2 0x0010 -#define RC_R3 0x0020 -#define RC_R12 0x0040 -#define RC_F0 0x0080 -#define RC_F1 0x0100 -#define RC_F2 0x0200 -#define RC_F3 0x0400 -#ifdef TCC_ARM_VFP -#define RC_F4 0x0800 -#define RC_F5 0x1000 -#define RC_F6 0x2000 -#define RC_F7 0x4000 -#endif -#define RC_IRET RC_R0 /* function return: integer register */ -#define RC_LRET RC_R1 /* function return: second integer register */ -#define RC_FRET RC_F0 /* function return: float register */ - -/* pretty names for the registers */ -enum { - TREG_R0 = 0, - TREG_R1, - TREG_R2, - TREG_R3, - TREG_R12, - TREG_F0, - TREG_F1, - TREG_F2, - TREG_F3, -#ifdef TCC_ARM_VFP - TREG_F4, - TREG_F5, - TREG_F6, - TREG_F7, -#endif - TREG_SP = 13, - TREG_LR, -}; - -#ifdef TCC_ARM_VFP -#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0) -#endif - -/* return registers for function */ -#define REG_IRET TREG_R0 /* single word int return register */ -#define REG_LRET TREG_R1 /* second word return register (for long long) */ -#define REG_FRET TREG_F0 /* float return register */ - -#ifdef TCC_ARM_EABI -#define TOK___divdi3 TOK___aeabi_ldivmod -#define TOK___moddi3 TOK___aeabi_ldivmod -#define TOK___udivdi3 TOK___aeabi_uldivmod -#define TOK___umoddi3 TOK___aeabi_uldivmod -#endif - -/* defined if function parameters must be evaluated in reverse order */ -#define INVERT_FUNC_PARAMS - -/* defined if structures are passed as pointers. Otherwise structures - are directly pushed on stack. */ -/* #define FUNC_STRUCT_PARAM_AS_PTR */ - -/* pointer size, in bytes */ -#define PTR_SIZE 4 - -/* long double size and alignment, in bytes */ -#ifdef TCC_ARM_VFP -#define LDOUBLE_SIZE 8 -#endif - -#ifndef LDOUBLE_SIZE -#define LDOUBLE_SIZE 8 -#endif - -#ifdef TCC_ARM_EABI -#define LDOUBLE_ALIGN 8 -#else -#define LDOUBLE_ALIGN 4 -#endif - -/* maximum alignment (for aligned attribute support) */ -#define MAX_ALIGN 8 - -#define CHAR_IS_UNSIGNED - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#include "tcc.h" - -enum float_abi float_abi; - -ST_DATA const int reg_classes[NB_REGS] = { - /* r0 */ RC_INT | RC_R0, - /* r1 */ RC_INT | RC_R1, - /* r2 */ RC_INT | RC_R2, - /* r3 */ RC_INT | RC_R3, - /* r12 */ RC_INT | RC_R12, - /* f0 */ RC_FLOAT | RC_F0, - /* f1 */ RC_FLOAT | RC_F1, - /* f2 */ RC_FLOAT | RC_F2, - /* f3 */ RC_FLOAT | RC_F3, -#ifdef TCC_ARM_VFP - /* d4/s8 */ RC_FLOAT | RC_F4, -/* d5/s10 */ RC_FLOAT | RC_F5, -/* d6/s12 */ RC_FLOAT | RC_F6, -/* d7/s14 */ RC_FLOAT | RC_F7, -#endif -}; - -static int func_sub_sp_offset, last_itod_magic; -static int leaffunc; - -#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) -static CType float_type, double_type, func_float_type, func_double_type; -ST_FUNC void arm_init(struct TCCState *s) -{ - float_type.t = VT_FLOAT; - double_type.t = VT_DOUBLE; - func_float_type.t = VT_FUNC; - func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD); - func_double_type.t = VT_FUNC; - func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD); - - float_abi = s->float_abi; -#ifndef TCC_ARM_HARDFLOAT - tcc_warning("soft float ABI currently not supported: default to softfp"); -#endif -} -#else -#define func_float_type func_old_type -#define func_double_type func_old_type -#define func_ldouble_type func_old_type -ST_FUNC void arm_init(struct TCCState *s) -{ -#if 0 -#if !defined (TCC_ARM_VFP) - tcc_warning("Support for FPA is deprecated and will be removed in next" - " release"); -#endif -#if !defined (TCC_ARM_EABI) - tcc_warning("Support for OABI is deprecated and will be removed in next" - " release"); -#endif -#endif -} -#endif - -static int two2mask(int a,int b) { - return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); -} - -static int regmask(int r) { - return reg_classes[r]&~(RC_INT|RC_FLOAT); -} - -/******************************************************/ - -#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) -const char *default_elfinterp(struct TCCState *s) -{ - if (s->float_abi == ARM_HARD_FLOAT) - return "/lib/ld-linux-armhf.so.3"; - else - return "/lib/ld-linux.so.3"; -} -#endif - -void o(uint32_t i) -{ - /* this is a good place to start adding big-endian support*/ - int ind1; - if (nocode_wanted) - return; - ind1 = ind + 4; - if (!cur_text_section) - tcc_error("compiler error! This happens f.ex. if the compiler\n" - "can't evaluate constant expressions outside of a function."); - if (ind1 > cur_text_section->data_allocated) - section_realloc(cur_text_section, ind1); - cur_text_section->data[ind++] = i&255; - i>>=8; - cur_text_section->data[ind++] = i&255; - i>>=8; - cur_text_section->data[ind++] = i&255; - i>>=8; - cur_text_section->data[ind++] = i; -} - -static uint32_t stuff_const(uint32_t op, uint32_t c) -{ - int try_neg=0; - uint32_t nc = 0, negop = 0; - - switch(op&0x1F00000) - { - case 0x800000: //add - case 0x400000: //sub - try_neg=1; - negop=op^0xC00000; - nc=-c; - break; - case 0x1A00000: //mov - case 0x1E00000: //mvn - try_neg=1; - negop=op^0x400000; - nc=~c; - break; - case 0x200000: //xor - if(c==~0) - return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000; - break; - case 0x0: //and - if(c==~0) - return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000; - case 0x1C00000: //bic - try_neg=1; - negop=op^0x1C00000; - nc=~c; - break; - case 0x1800000: //orr - if(c==~0) - return (op&0xFFF0FFFF)|0x1E00000; - break; - } - do { - uint32_t m; - int i; - if(c<256) /* catch undefined <<32 */ - return op|c; - for(i=2;i<32;i+=2) { - m=(0xff>>i)|(0xff<<(32-i)); - if(!(c&~m)) - return op|(i<<7)|(c<>(32-i)); - } - op=negop; - c=nc; - } while(try_neg--); - return 0; -} - - -//only add,sub -void stuff_const_harder(uint32_t op, uint32_t v) { - uint32_t x; - x=stuff_const(op,v); - if(x) - o(x); - else { - uint32_t a[16], nv, no, o2, n2; - int i,j,k; - a[0]=0xff; - o2=(op&0xfff0ffff)|((op&0xf000)<<4);; - for(i=1;i<16;i++) - a[i]=(a[i-1]>>2)|(a[i-1]<<30); - for(i=0;i<12;i++) - for(j=i<4?i+12:15;j>=i+4;j--) - if((v&(a[i]|a[j]))==v) { - o(stuff_const(op,v&a[i])); - o(stuff_const(o2,v&a[j])); - return; - } - no=op^0xC00000; - n2=o2^0xC00000; - nv=-v; - for(i=0;i<12;i++) - for(j=i<4?i+12:15;j>=i+4;j--) - if((nv&(a[i]|a[j]))==nv) { - o(stuff_const(no,nv&a[i])); - o(stuff_const(n2,nv&a[j])); - return; - } - for(i=0;i<8;i++) - for(j=i+4;j<12;j++) - for(k=i<4?i+12:15;k>=j+4;k--) - if((v&(a[i]|a[j]|a[k]))==v) { - o(stuff_const(op,v&a[i])); - o(stuff_const(o2,v&a[j])); - o(stuff_const(o2,v&a[k])); - return; - } - no=op^0xC00000; - nv=-v; - for(i=0;i<8;i++) - for(j=i+4;j<12;j++) - for(k=i<4?i+12:15;k>=j+4;k--) - if((nv&(a[i]|a[j]|a[k]))==nv) { - o(stuff_const(no,nv&a[i])); - o(stuff_const(n2,nv&a[j])); - o(stuff_const(n2,nv&a[k])); - return; - } - o(stuff_const(op,v&a[0])); - o(stuff_const(o2,v&a[4])); - o(stuff_const(o2,v&a[8])); - o(stuff_const(o2,v&a[12])); - } -} - -uint32_t encbranch(int pos, int addr, int fail) -{ - addr-=pos+8; - addr/=4; - if(addr>=0x1000000 || addr<-0x1000000) { - if(fail) - tcc_error("FIXME: function bigger than 32MB"); - return 0; - } - return 0x0A000000|(addr&0xffffff); -} - -int decbranch(int pos) -{ - int x; - x=*(uint32_t *)(cur_text_section->data + pos); - x&=0x00ffffff; - if(x&0x800000) - x-=0x1000000; - return x*4+pos+8; -} - -/* output a symbol and patch all calls to it */ -void gsym_addr(int t, int a) -{ - uint32_t *x; - int lt; - while(t) { - x=(uint32_t *)(cur_text_section->data + t); - t=decbranch(lt=t); - if(a==lt+4) - *x=0xE1A00000; // nop - else { - *x &= 0xff000000; - *x |= encbranch(lt,a,1); - } - } -} - -void gsym(int t) -{ - gsym_addr(t, ind); -} - -#ifdef TCC_ARM_VFP -static uint32_t vfpr(int r) -{ - if(rTREG_F7) - tcc_error("compiler error! register %i is no vfp register",r); - return r - TREG_F0; -} -#else -static uint32_t fpr(int r) -{ - if(rTREG_F3) - tcc_error("compiler error! register %i is no fpa register",r); - return r - TREG_F0; -} -#endif - -static uint32_t intr(int r) -{ - if(r == TREG_R12) - return 12; - if(r >= TREG_R0 && r <= TREG_R3) - return r - TREG_R0; - if (r >= TREG_SP && r <= TREG_LR) - return r + (13 - TREG_SP); - tcc_error("compiler error! register %i is no int register",r); -} - -static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift) -{ - if(*off>maxoff || *off&((1<r; - ft = sv->type.t; - fc = sv->c.i; - - if(fc>=0) - sign=0; - else { - sign=1; - fc=-fc; - } - - v = fr & VT_VALMASK; - if (fr & VT_LVAL) { - uint32_t base = 0xB; // fp - if(v == VT_LLOCAL) { - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = sv->c.i; - load(TREG_LR, &v1); - base = 14; /* lr */ - fc=sign=0; - v=VT_LOCAL; - } else if(v == VT_CONST) { - v1.type.t = VT_PTR; - v1.r = fr&~VT_LVAL; - v1.c.i = sv->c.i; - v1.sym=sv->sym; - load(TREG_LR, &v1); - base = 14; /* lr */ - fc=sign=0; - v=VT_LOCAL; - } else if(v < VT_CONST) { - base=intr(v); - fc=sign=0; - v=VT_LOCAL; - } - if(v == VT_LOCAL) { - if(is_float(ft)) { - calcaddr(&base,&fc,&sign,1020,2); -#ifdef TCC_ARM_VFP - op=0xED100A00; /* flds */ - if(!sign) - op|=0x800000; - if ((ft & VT_BTYPE) != VT_FLOAT) - op|=0x100; /* flds -> fldd */ - o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); -#else - op=0xED100100; - if(!sign) - op|=0x800000; -#if LDOUBLE_SIZE == 8 - if ((ft & VT_BTYPE) != VT_FLOAT) - op|=0x8000; -#else - if ((ft & VT_BTYPE) == VT_DOUBLE) - op|=0x8000; - else if ((ft & VT_BTYPE) == VT_LDOUBLE) - op|=0x400000; -#endif - o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); -#endif - } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE - || (ft & VT_BTYPE) == VT_SHORT) { - calcaddr(&base,&fc,&sign,255,0); - op=0xE1500090; - if ((ft & VT_BTYPE) == VT_SHORT) - op|=0x20; - if ((ft & VT_UNSIGNED) == 0) - op|=0x40; - if(!sign) - op|=0x800000; - o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); - } else { - calcaddr(&base,&fc,&sign,4095,0); - op=0xE5100000; - if(!sign) - op|=0x800000; - if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) - op|=0x400000; - o(op|(intr(r)<<12)|fc|(base<<16)); - } - return; - } - } else { - if (v == VT_CONST) { - op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.i); - if (fr & VT_SYM || !op) { - o(0xE59F0000|(intr(r)<<12)); - o(0xEA000000); - if(fr & VT_SYM) - greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); - o(sv->c.i); - } else - o(op); - return; - } else if (v == VT_LOCAL) { - op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.i); - if (fr & VT_SYM || !op) { - o(0xE59F0000|(intr(r)<<12)); - o(0xEA000000); - if(fr & VT_SYM) // needed ? - greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); - o(sv->c.i); - o(0xE08B0000|(intr(r)<<12)|intr(r)); - } else - o(op); - return; - } else if(v == VT_CMP) { - o(mapcc(sv->c.i)|0x3A00001|(intr(r)<<12)); - o(mapcc(negcc(sv->c.i))|0x3A00000|(intr(r)<<12)); - return; - } else if (v == VT_JMP || v == VT_JMPI) { - int t; - t = v & 1; - o(0xE3A00000|(intr(r)<<12)|t); - o(0xEA000000); - gsym(sv->c.i); - o(0xE3A00000|(intr(r)<<12)|(t^1)); - return; - } else if (v < VT_CONST) { - if(is_float(ft)) -#ifdef TCC_ARM_VFP - o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */ -#else - o(0xEE008180|(fpr(r)<<12)|fpr(v)); -#endif - else - o(0xE1A00000|(intr(r)<<12)|intr(v)); - return; - } - } - tcc_error("load unimplemented!"); -} - -/* store register 'r' in lvalue 'v' */ -void store(int r, SValue *sv) -{ - SValue v1; - int v, ft, fc, fr, sign; - uint32_t op; - - fr = sv->r; - ft = sv->type.t; - fc = sv->c.i; - - if(fc>=0) - sign=0; - else { - sign=1; - fc=-fc; - } - - v = fr & VT_VALMASK; - if (fr & VT_LVAL || fr == VT_LOCAL) { - uint32_t base = 0xb; /* fp */ - if(v < VT_CONST) { - base=intr(v); - v=VT_LOCAL; - fc=sign=0; - } else if(v == VT_CONST) { - v1.type.t = ft; - v1.r = fr&~VT_LVAL; - v1.c.i = sv->c.i; - v1.sym=sv->sym; - load(TREG_LR, &v1); - base = 14; /* lr */ - fc=sign=0; - v=VT_LOCAL; - } - if(v == VT_LOCAL) { - if(is_float(ft)) { - calcaddr(&base,&fc,&sign,1020,2); -#ifdef TCC_ARM_VFP - op=0xED000A00; /* fsts */ - if(!sign) - op|=0x800000; - if ((ft & VT_BTYPE) != VT_FLOAT) - op|=0x100; /* fsts -> fstd */ - o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); -#else - op=0xED000100; - if(!sign) - op|=0x800000; -#if LDOUBLE_SIZE == 8 - if ((ft & VT_BTYPE) != VT_FLOAT) - op|=0x8000; -#else - if ((ft & VT_BTYPE) == VT_DOUBLE) - op|=0x8000; - if ((ft & VT_BTYPE) == VT_LDOUBLE) - op|=0x400000; -#endif - o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); -#endif - return; - } else if((ft & VT_BTYPE) == VT_SHORT) { - calcaddr(&base,&fc,&sign,255,0); - op=0xE14000B0; - if(!sign) - op|=0x800000; - o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf)); - } else { - calcaddr(&base,&fc,&sign,4095,0); - op=0xE5000000; - if(!sign) - op|=0x800000; - if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) - op|=0x400000; - o(op|(intr(r)<<12)|fc|(base<<16)); - } - return; - } - } - tcc_error("store unimplemented"); -} - -static void gadd_sp(int val) -{ - stuff_const_harder(0xE28DD000,val); -} - -/* 'is_jmp' is '1' if it is a jump */ -static void gcall_or_jmp(int is_jmp) -{ - int r; - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - uint32_t x; - /* constant case */ - x=encbranch(ind,ind+vtop->c.i,0); - if(x) { - if (vtop->r & VT_SYM) { - /* relocation case */ - greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24); - } else - put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0); - o(x|(is_jmp?0xE0000000:0xE1000000)); - } else { - if(!is_jmp) - o(0xE28FE004); // add lr,pc,#4 - o(0xE51FF004); // ldr pc,[pc,#-4] - if (vtop->r & VT_SYM) - greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); - o(vtop->c.i); - } - } else { - /* otherwise, indirect call */ - r = gv(RC_INT); - if(!is_jmp) - o(0xE1A0E00F); // mov lr,pc - o(0xE1A0F000|intr(r)); // mov pc,r - } -} - -static int unalias_ldbl(int btype) -{ -#if LDOUBLE_SIZE == 8 - if (btype == VT_LDOUBLE) - btype = VT_DOUBLE; -#endif - return btype; -} - -/* Return whether a structure is an homogeneous float aggregate or not. - The answer is true if all the elements of the structure are of the same - primitive float type and there is less than 4 elements. - - type: the type corresponding to the structure to be tested */ -static int is_hgen_float_aggr(CType *type) -{ - if ((type->t & VT_BTYPE) == VT_STRUCT) { - struct Sym *ref; - int btype, nb_fields = 0; - - ref = type->ref->next; - btype = unalias_ldbl(ref->type.t & VT_BTYPE); - if (btype == VT_FLOAT || btype == VT_DOUBLE) { - for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); - return !ref && nb_fields <= 4; - } - } - return 0; -} - -struct avail_regs { - signed char avail[3]; /* 3 holes max with only float and double alignments */ - int first_hole; /* first available hole */ - int last_hole; /* last available hole (none if equal to first_hole) */ - int first_free_reg; /* next free register in the sequence, hole excluded */ -}; - -#define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 } - -/* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC - param) according to the rules described in the procedure call standard for - the ARM architecture (AAPCS). If found, the registers are assigned to this - VFP CPRC parameter. Registers are allocated in sequence unless a hole exists - and the parameter is a single float. - - avregs: opaque structure to keep track of available VFP co-processor regs - align: alignment constraints for the param, as returned by type_size() - size: size of the parameter, as returned by type_size() */ -int assign_vfpreg(struct avail_regs *avregs, int align, int size) -{ - int first_reg = 0; - - if (avregs->first_free_reg == -1) - return -1; - if (align >> 3) { /* double alignment */ - first_reg = avregs->first_free_reg; - /* alignment constraint not respected so use next reg and record hole */ - if (first_reg & 1) - avregs->avail[avregs->last_hole++] = first_reg++; - } else { /* no special alignment (float or array of float) */ - /* if single float and a hole is available, assign the param to it */ - if (size == 4 && avregs->first_hole != avregs->last_hole) - return avregs->avail[avregs->first_hole++]; - else - first_reg = avregs->first_free_reg; - } - if (first_reg + size / 4 <= 16) { - avregs->first_free_reg = first_reg + size / 4; - return first_reg; - } - avregs->first_free_reg = -1; - return -1; -} - -/* Returns whether all params need to be passed in core registers or not. - This is the case for function part of the runtime ABI. */ -int floats_in_core_regs(SValue *sval) -{ - if (!sval->sym) - return 0; - - switch (sval->sym->v) { - case TOK___floatundisf: - case TOK___floatundidf: - case TOK___fixunssfdi: - case TOK___fixunsdfdi: -#ifndef TCC_ARM_VFP - case TOK___fixunsxfdi: -#endif - case TOK___floatdisf: - case TOK___floatdidf: - case TOK___fixsfdi: - case TOK___fixdfdi: - return 1; - - default: - return 0; - } -} - -/* Return the number of registers needed to return the struct, or 0 if - returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { -#ifdef TCC_ARM_EABI - int size, align; - size = type_size(vt, &align); - if (float_abi == ARM_HARD_FLOAT && !variadic && - (is_float(vt->t) || is_hgen_float_aggr(vt))) { - *ret_align = 8; - *regsize = 8; - ret->ref = NULL; - ret->t = VT_DOUBLE; - return (size + 7) >> 3; - } else if (size <= 4) { - *ret_align = 4; - *regsize = 4; - ret->ref = NULL; - ret->t = VT_INT; - return 1; - } else - return 0; -#else - return 0; -#endif -} - -/* Parameters are classified according to how they are copied to their final - destination for the function call. Because the copying is performed class - after class according to the order in the union below, it is important that - some constraints about the order of the members of this union are respected: - - CORE_STRUCT_CLASS must come after STACK_CLASS; - - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and - VFP_STRUCT_CLASS; - - VFP_STRUCT_CLASS must come after VFP_CLASS. - See the comment for the main loop in copy_params() for the reason. */ -enum reg_class { - STACK_CLASS = 0, - CORE_STRUCT_CLASS, - VFP_CLASS, - VFP_STRUCT_CLASS, - CORE_CLASS, - NB_CLASSES -}; - -struct param_plan { - int start; /* first reg or addr used depending on the class */ - int end; /* last reg used or next free addr depending on the class */ - SValue *sval; /* pointer to SValue on the value stack */ - struct param_plan *prev; /* previous element in this class */ -}; - -struct plan { - struct param_plan *pplans; /* array of all the param plans */ - struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */ -}; - -#define add_param_plan(plan,pplan,class) \ - do { \ - pplan.prev = plan->clsplans[class]; \ - plan->pplans[plan ## _nb] = pplan; \ - plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \ - } while(0) - -/* Assign parameters to registers and stack with alignment according to the - rules in the procedure call standard for the ARM architecture (AAPCS). - The overall assignment is recorded in an array of per parameter structures - called parameter plans. The parameter plans are also further organized in a - number of linked lists, one per class of parameter (see the comment for the - definition of union reg_class). - - nb_args: number of parameters of the function for which a call is generated - float_abi: float ABI in use for this function call - plan: the structure where the overall assignment is recorded - todo: a bitmap that record which core registers hold a parameter - - Returns the amount of stack space needed for parameter passing - - Note: this function allocated an array in plan->pplans with tcc_malloc. It - is the responsibility of the caller to free this array once used (ie not - before copy_params). */ -static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo) -{ - int i, size, align; - int ncrn /* next core register number */, nsaa /* next stacked argument address*/; - int plan_nb = 0; - struct param_plan pplan; - struct avail_regs avregs = AVAIL_REGS_INITIALIZER; - - ncrn = nsaa = 0; - *todo = 0; - plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans)); - memset(plan->clsplans, 0, sizeof(plan->clsplans)); - for(i = nb_args; i-- ;) { - int j, start_vfpreg = 0; - CType type = vtop[-i].type; - type.t &= ~VT_ARRAY; - size = type_size(&type, &align); - size = (size + 3) & ~3; - align = (align + 3) & ~3; - switch(vtop[-i].type.t & VT_BTYPE) { - case VT_STRUCT: - case VT_FLOAT: - case VT_DOUBLE: - case VT_LDOUBLE: - if (float_abi == ARM_HARD_FLOAT) { - int is_hfa = 0; /* Homogeneous float aggregate */ - - if (is_float(vtop[-i].type.t) - || (is_hfa = is_hgen_float_aggr(&vtop[-i].type))) { - int end_vfpreg; - - start_vfpreg = assign_vfpreg(&avregs, align, size); - end_vfpreg = start_vfpreg + ((size - 1) >> 2); - if (start_vfpreg >= 0) { - pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]}; - if (is_hfa) - add_param_plan(plan, pplan, VFP_STRUCT_CLASS); - else - add_param_plan(plan, pplan, VFP_CLASS); - continue; - } else - break; - } - } - ncrn = (ncrn + (align-1)/4) & ~((align/4) - 1); - if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) { - /* The parameter is allocated both in core register and on stack. As - * such, it can be of either class: it would either be the last of - * CORE_STRUCT_CLASS or the first of STACK_CLASS. */ - for (j = ncrn; j < 4 && j < ncrn + size / 4; j++) - *todo|=(1< 4) - nsaa = (ncrn - 4) * 4; - } else { - ncrn = 4; - break; - } - continue; - default: - if (ncrn < 4) { - int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG; - - if (is_long) { - ncrn = (ncrn + 1) & -2; - if (ncrn == 4) - break; - } - pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]}; - ncrn++; - if (is_long) - pplan.end = ncrn++; - add_param_plan(plan, pplan, CORE_CLASS); - continue; - } - } - nsaa = (nsaa + (align - 1)) & ~(align - 1); - pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]}; - add_param_plan(plan, pplan, STACK_CLASS); - nsaa += size; /* size already rounded up before */ - } - return nsaa; -} - -#undef add_param_plan - -/* Copy parameters to their final destination (core reg, VFP reg or stack) for - function call. - - nb_args: number of parameters the function take - plan: the overall assignment plan for parameters - todo: a bitmap indicating what core reg will hold a parameter - - Returns the number of SValue added by this function on the value stack */ -static int copy_params(int nb_args, struct plan *plan, int todo) -{ - int size, align, r, i, nb_extra_sval = 0; - struct param_plan *pplan; - int pass = 0; - - /* Several constraints require parameters to be copied in a specific order: - - structures are copied to the stack before being loaded in a reg; - - floats loaded to an odd numbered VFP reg are first copied to the - preceding even numbered VFP reg and then moved to the next VFP reg. - - It is thus important that: - - structures assigned to core regs must be copied after parameters - assigned to the stack but before structures assigned to VFP regs because - a structure can lie partly in core registers and partly on the stack; - - parameters assigned to the stack and all structures be copied before - parameters assigned to a core reg since copying a parameter to the stack - require using a core reg; - - parameters assigned to VFP regs be copied before structures assigned to - VFP regs as the copy might use an even numbered VFP reg that already - holds part of a structure. */ -again: - for(i = 0; i < NB_CLASSES; i++) { - for(pplan = plan->clsplans[i]; pplan; pplan = pplan->prev) { - - if (pass - && (i != CORE_CLASS || pplan->sval->r < VT_CONST)) - continue; - - vpushv(pplan->sval); - pplan->sval->r = pplan->sval->r2 = VT_CONST; /* disable entry */ - switch(i) { - case STACK_CLASS: - case CORE_STRUCT_CLASS: - case VFP_STRUCT_CLASS: - if ((pplan->sval->type.t & VT_BTYPE) == VT_STRUCT) { - int padding = 0; - size = type_size(&pplan->sval->type, &align); - /* align to stack align size */ - size = (size + 3) & ~3; - if (i == STACK_CLASS && pplan->prev) - padding = pplan->start - pplan->prev->end; - size += padding; /* Add padding if any */ - /* allocate the necessary size on stack */ - gadd_sp(-size); - /* generate structure store */ - r = get_reg(RC_INT); - o(0xE28D0000|(intr(r)<<12)|padding); /* add r, sp, padding */ - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); /* memcpy to current sp + potential padding */ - - /* Homogeneous float aggregate are loaded to VFP registers - immediately since there is no way of loading data in multiple - non consecutive VFP registers as what is done for other - structures (see the use of todo). */ - if (i == VFP_STRUCT_CLASS) { - int first = pplan->start, nb = pplan->end - first + 1; - /* vpop.32 {pplan->start, ..., pplan->end} */ - o(0xECBD0A00|(first&1)<<22|(first>>1)<<12|nb); - /* No need to write the register used to a SValue since VFP regs - cannot be used for gcall_or_jmp */ - } - } else { - if (is_float(pplan->sval->type.t)) { -#ifdef TCC_ARM_VFP - r = vfpr(gv(RC_FLOAT)) << 12; - if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) - size = 4; - else { - size = 8; - r |= 0x101; /* vpush.32 -> vpush.64 */ - } - o(0xED2D0A01 + r); /* vpush */ -#else - r = fpr(gv(RC_FLOAT)) << 12; - if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) - size = 4; - else if ((pplan->sval->type.t & VT_BTYPE) == VT_DOUBLE) - size = 8; - else - size = LDOUBLE_SIZE; - - if (size == 12) - r |= 0x400000; - else if(size == 8) - r|=0x8000; - - o(0xED2D0100|r|(size>>2)); /* some kind of vpush for FPA */ -#endif - } else { - /* simple type (currently always same size) */ - /* XXX: implicit cast ? */ - size=4; - if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { - lexpand_nr(); - size = 8; - r = gv(RC_INT); - o(0xE52D0004|(intr(r)<<12)); /* push r */ - vtop--; - } - r = gv(RC_INT); - o(0xE52D0004|(intr(r)<<12)); /* push r */ - } - if (i == STACK_CLASS && pplan->prev) - gadd_sp(pplan->prev->end - pplan->start); /* Add padding if any */ - } - break; - - case VFP_CLASS: - gv(regmask(TREG_F0 + (pplan->start >> 1))); - if (pplan->start & 1) { /* Must be in upper part of double register */ - o(0xEEF00A40|((pplan->start>>1)<<12)|(pplan->start>>1)); /* vmov.f32 s(n+1), sn */ - vtop->r = VT_CONST; /* avoid being saved on stack by gv for next float */ - } - break; - - case CORE_CLASS: - if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { - lexpand_nr(); - gv(regmask(pplan->end)); - pplan->sval->r2 = vtop->r; - vtop--; - } - gv(regmask(pplan->start)); - /* Mark register as used so that gcall_or_jmp use another one - (regs >=4 are free as never used to pass parameters) */ - pplan->sval->r = vtop->r; - break; - } - vtop--; - } - } - - /* second pass to restore registers that were saved on stack by accident. - Maybe redundant after the "lvalue_save" patch in tccgen.c:gv() */ - if (++pass < 2) - goto again; - - /* Manually free remaining registers since next parameters are loaded - * manually, without the help of gv(int). */ - save_regs(nb_args); - - if(todo) { - o(0xE8BD0000|todo); /* pop {todo} */ - for(pplan = plan->clsplans[CORE_STRUCT_CLASS]; pplan; pplan = pplan->prev) { - int r; - pplan->sval->r = pplan->start; - /* An SValue can only pin 2 registers at best (r and r2) but a structure - can occupy more than 2 registers. Thus, we need to push on the value - stack some fake parameter to have on SValue for each registers used - by a structure (r2 is not used). */ - for (r = pplan->start + 1; r <= pplan->end; r++) { - if (todo & (1 << r)) { - nb_extra_sval++; - vpushi(0); - vtop->r = r; - } - } - } - } - return nb_extra_sval; -} - -/* Generate function call. The function address is pushed first, then - all the parameters in call order. This functions pops all the - parameters and the function address. */ -void gfunc_call(int nb_args) -{ - int r, args_size; - int def_float_abi = float_abi; - int todo; - struct plan plan; - -#ifdef TCC_ARM_EABI - int variadic; - - if (float_abi == ARM_HARD_FLOAT) { - variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS); - if (variadic || floats_in_core_regs(&vtop[-nb_args])) - float_abi = ARM_SOFTFP_FLOAT; - } -#endif - /* cannot let cpu flags if other instruction are generated. Also avoid leaving - VT_JMP anywhere except on the top of the stack because it would complicate - the code generator. */ - r = vtop->r & VT_VALMASK; - if (r == VT_CMP || (r & ~1) == VT_JMP) - gv(RC_INT); - - args_size = assign_regs(nb_args, float_abi, &plan, &todo); - -#ifdef TCC_ARM_EABI - if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */ - args_size = (args_size + 7) & ~7; - o(0xE24DD004); /* sub sp, sp, #4 */ - } -#endif - - nb_args += copy_params(nb_args, &plan, todo); - tcc_free(plan.pplans); - - /* Move fct SValue on top as required by gcall_or_jmp */ - vrotb(nb_args + 1); - gcall_or_jmp(0); - if (args_size) - gadd_sp(args_size); /* pop all parameters passed on the stack */ -#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) - if(float_abi == ARM_SOFTFP_FLOAT && is_float(vtop->type.ref->type.t)) { - if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { - o(0xEE000A10); /*vmov s0, r0 */ - } else { - o(0xEE000B10); /* vmov.32 d0[0], r0 */ - o(0xEE201B10); /* vmov.32 d0[1], r1 */ - } - } -#endif - vtop -= nb_args + 1; /* Pop all params and fct address from value stack */ - leaffunc = 0; /* we are calling a function, so we aren't in a leaf function */ - float_abi = def_float_abi; -} - -/* generate function prolog of type 't' */ -void gfunc_prolog(CType *func_type) -{ - Sym *sym,*sym2; - int n, nf, size, align, rs, struct_ret = 0; - int addr, pn, sn; /* pn=core, sn=stack */ - CType ret_type; - -#ifdef TCC_ARM_EABI - struct avail_regs avregs = AVAIL_REGS_INITIALIZER; -#endif - - sym = func_type->ref; - func_vt = sym->type; - func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS); - - n = nf = 0; - if ((func_vt.t & VT_BTYPE) == VT_STRUCT && - !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs)) - { - n++; - struct_ret = 1; - func_vc = 12; /* Offset from fp of the place to store the result */ - } - for(sym2 = sym->next; sym2 && (n < 4 || nf < 16); sym2 = sym2->next) { - size = type_size(&sym2->type, &align); -#ifdef TCC_ARM_EABI - if (float_abi == ARM_HARD_FLOAT && !func_var && - (is_float(sym2->type.t) || is_hgen_float_aggr(&sym2->type))) { - int tmpnf = assign_vfpreg(&avregs, align, size); - tmpnf += (size + 3) / 4; - nf = (tmpnf > nf) ? tmpnf : nf; - } else -#endif - if (n < 4) - n += (size + 3) / 4; - } - o(0xE1A0C00D); /* mov ip,sp */ - if (func_var) - n=4; - if (n) { - if(n>4) - n=4; -#ifdef TCC_ARM_EABI - n=(n+1)&-2; -#endif - o(0xE92D0000|((1<16) - nf=16; - nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */ - o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */ - } - o(0xE92D5800); /* save fp, ip, lr */ - o(0xE1A0B00D); /* mov fp, sp */ - func_sub_sp_offset = ind; - o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */ - -#ifdef TCC_ARM_EABI - if (float_abi == ARM_HARD_FLOAT) { - func_vc += nf * 4; - avregs = AVAIL_REGS_INITIALIZER; - } -#endif - pn = struct_ret, sn = 0; - while ((sym = sym->next)) { - CType *type; - type = &sym->type; - size = type_size(type, &align); - size = (size + 3) >> 2; - align = (align + 3) & ~3; -#ifdef TCC_ARM_EABI - if (float_abi == ARM_HARD_FLOAT && !func_var && (is_float(sym->type.t) - || is_hgen_float_aggr(&sym->type))) { - int fpn = assign_vfpreg(&avregs, align, size << 2); - if (fpn >= 0) - addr = fpn * 4; - else - goto from_stack; - } else -#endif - if (pn < 4) { -#ifdef TCC_ARM_EABI - pn = (pn + (align-1)/4) & -(align/4); -#endif - addr = (nf + pn) * 4; - pn += size; - if (!sn && pn > 4) - sn = (pn - 4); - } else { -#ifdef TCC_ARM_EABI -from_stack: - sn = (sn + (align-1)/4) & -(align/4); -#endif - addr = (n + nf + sn) * 4; - sn += size; - } - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), - addr + 12); - } - last_itod_magic=0; - leaffunc = 1; - loc = 0; -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - uint32_t x; - int diff; - /* Copy float return value to core register if base standard is used and - float computation is made with VFP */ -#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) - if ((float_abi == ARM_SOFTFP_FLOAT || func_var) && is_float(func_vt.t)) { - if((func_vt.t & VT_BTYPE) == VT_FLOAT) - o(0xEE100A10); /* fmrs r0, s0 */ - else { - o(0xEE100B10); /* fmrdl r0, d0 */ - o(0xEE301B10); /* fmrdh r1, d0 */ - } - } -#endif - o(0xE89BA800); /* restore fp, sp, pc */ - diff = (-loc + 3) & -4; -#ifdef TCC_ARM_EABI - if(!leaffunc) - diff = ((diff + 11) & -8) - 4; -#endif - if(diff > 0) { - x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */ - if(x) - *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x; - else { - int addr; - addr=ind; - o(0xE59FC004); /* ldr ip,[pc+4] */ - o(0xE04BD00C); /* sub sp,fp,ip */ - o(0xE1A0F00E); /* mov pc,lr */ - o(diff); - *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); - } - } -} - -/* generate a jump to a label */ -int gjmp(int t) -{ - int r; - if (nocode_wanted) - return t; - r=ind; - o(0xE0000000|encbranch(r,t,1)); - return r; -} - -/* generate a jump to a fixed address */ -void gjmp_addr(int a) -{ - gjmp(a); -} - -/* generate a test. set 'inv' to invert test. Stack entry is popped */ -int gtst(int inv, int t) -{ - int v, r; - uint32_t op; - - v = vtop->r & VT_VALMASK; - r=ind; - - if (nocode_wanted) { - ; - } else if (v == VT_CMP) { - op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); - op|=encbranch(r,t,1); - o(op); - t=r; - } else if (v == VT_JMP || v == VT_JMPI) { - if ((v & 1) == inv) { - if(!vtop->c.i) - vtop->c.i=t; - else { - uint32_t *x; - int p,lp; - if(t) { - p = vtop->c.i; - do { - p = decbranch(lp=p); - } while(p); - x = (uint32_t *)(cur_text_section->data + lp); - *x &= 0xff000000; - *x |= encbranch(lp,t,1); - } - t = vtop->c.i; - } - } else { - t = gjmp(t); - gsym(vtop->c.i); - } - } - vtop--; - return t; -} - -/* generate an integer binary operation */ -void gen_opi(int op) -{ - int c, func = 0; - uint32_t opc = 0, r, fr; - unsigned short retreg = REG_IRET; - - c=0; - switch(op) { - case '+': - opc = 0x8; - c=1; - break; - case TOK_ADDC1: /* add with carry generation */ - opc = 0x9; - c=1; - break; - case '-': - opc = 0x4; - c=1; - break; - case TOK_SUBC1: /* sub with carry generation */ - opc = 0x5; - c=1; - break; - case TOK_ADDC2: /* add with carry use */ - opc = 0xA; - c=1; - break; - case TOK_SUBC2: /* sub with carry use */ - opc = 0xC; - c=1; - break; - case '&': - opc = 0x0; - c=1; - break; - case '^': - opc = 0x2; - c=1; - break; - case '|': - opc = 0x18; - c=1; - break; - case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr)); - return; - case TOK_SHL: - opc = 0; - c=2; - break; - case TOK_SHR: - opc = 1; - c=2; - break; - case TOK_SAR: - opc = 2; - c=2; - break; - case '/': - case TOK_PDIV: - func=TOK___divsi3; - c=3; - break; - case TOK_UDIV: - func=TOK___udivsi3; - c=3; - break; - case '%': -#ifdef TCC_ARM_EABI - func=TOK___aeabi_idivmod; - retreg=REG_LRET; -#else - func=TOK___modsi3; -#endif - c=3; - break; - case TOK_UMOD: -#ifdef TCC_ARM_EABI - func=TOK___aeabi_uidivmod; - retreg=REG_LRET; -#else - func=TOK___umodsi3; -#endif - c=3; - break; - case TOK_UMULL: - gv2(RC_INT, RC_INT); - r=intr(vtop[-1].r2=get_reg(RC_INT)); - c=vtop[-1].r; - vtop[-1].r=get_reg_ex(RC_INT,regmask(c)); - vtop--; - o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r)); - return; - default: - opc = 0x15; - c=1; - break; - } - switch(c) { - case 1: - if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - if(opc == 4 || opc == 5 || opc == 0xc) { - vswap(); - opc|=2; // sub -> rsb - } - } - if ((vtop->r & VT_VALMASK) == VT_CMP || - (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) - gv(RC_INT); - vswap(); - c=intr(gv(RC_INT)); - vswap(); - opc=0xE0000000|(opc<<20)|(c<<16); - if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - uint32_t x; - x=stuff_const(opc|0x2000000,vtop->c.i); - if(x) { - r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); - o(x|(r<<12)); - goto done; - } - } - fr=intr(gv(RC_INT)); - r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); - o(opc|(r<<12)|fr); -done: - vtop--; - if (op >= TOK_ULT && op <= TOK_GT) { - vtop->r = VT_CMP; - vtop->c.i = op; - } - break; - case 2: - opc=0xE1A00000|(opc<<5); - if ((vtop->r & VT_VALMASK) == VT_CMP || - (vtop->r & (VT_VALMASK & ~1)) == VT_JMP) - gv(RC_INT); - vswap(); - r=intr(gv(RC_INT)); - vswap(); - opc|=r; - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); - c = vtop->c.i & 0x1f; - o(opc|(c<<7)|(fr<<12)); - } else { - fr=intr(gv(RC_INT)); - c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r))); - o(opc|(c<<12)|(fr<<8)|0x10); - } - vtop--; - break; - case 3: - vpush_global_sym(&func_old_type, func); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = retreg; - break; - default: - tcc_error("gen_opi %i unimplemented!",op); - } -} - -#ifdef TCC_ARM_VFP -static int is_zero(int i) -{ - if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) - return 0; - if (vtop[i].type.t == VT_FLOAT) - return (vtop[i].c.f == 0.f); - else if (vtop[i].type.t == VT_DOUBLE) - return (vtop[i].c.d == 0.0); - return (vtop[i].c.ld == 0.l); -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - * two operands are guaranteed to have the same floating point type */ -void gen_opf(int op) -{ - uint32_t x; - int fneg=0,r; - x=0xEE000A00|T2CPR(vtop->type.t); - switch(op) { - case '+': - if(is_zero(-1)) - vswap(); - if(is_zero(0)) { - vtop--; - return; - } - x|=0x300000; - break; - case '-': - x|=0x300040; - if(is_zero(0)) { - vtop--; - return; - } - if(is_zero(-1)) { - x|=0x810000; /* fsubX -> fnegX */ - vswap(); - vtop--; - fneg=1; - } - break; - case '*': - x|=0x200000; - break; - case '/': - x|=0x800000; - break; - default: - if(op < TOK_ULT || op > TOK_GT) { - tcc_error("unknown fp op %x!",op); - return; - } - if(is_zero(-1)) { - vswap(); - switch(op) { - case TOK_LT: op=TOK_GT; break; - case TOK_GE: op=TOK_ULE; break; - case TOK_LE: op=TOK_GE; break; - case TOK_GT: op=TOK_ULT; break; - } - } - x|=0xB40040; /* fcmpX */ - if(op!=TOK_EQ && op!=TOK_NE) - x|=0x80; /* fcmpX -> fcmpeX */ - if(is_zero(0)) { - vtop--; - o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */ - } else { - x|=vfpr(gv(RC_FLOAT)); - vswap(); - o(x|(vfpr(gv(RC_FLOAT))<<12)); - vtop--; - } - o(0xEEF1FA10); /* fmstat */ - - switch(op) { - case TOK_LE: op=TOK_ULE; break; - case TOK_LT: op=TOK_ULT; break; - case TOK_UGE: op=TOK_GE; break; - case TOK_UGT: op=TOK_GT; break; - } - - vtop->r = VT_CMP; - vtop->c.i = op; - return; - } - r=gv(RC_FLOAT); - x|=vfpr(r); - r=regmask(r); - if(!fneg) { - int r2; - vswap(); - r2=gv(RC_FLOAT); - x|=vfpr(r2)<<16; - r|=regmask(r2); - } - vtop->r=get_reg_ex(RC_FLOAT,r); - if(!fneg) - vtop--; - o(x|(vfpr(vtop->r)<<12)); -} - -#else -static uint32_t is_fconst() -{ - long double f; - uint32_t r; - if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) - return 0; - if (vtop->type.t == VT_FLOAT) - f = vtop->c.f; - else if (vtop->type.t == VT_DOUBLE) - f = vtop->c.d; - else - f = vtop->c.ld; - if(!ieee_finite(f)) - return 0; - r=0x8; - if(f<0.0) { - r=0x18; - f=-f; - } - if(f==0.0) - return r; - if(f==1.0) - return r|1; - if(f==2.0) - return r|2; - if(f==3.0) - return r|3; - if(f==4.0) - return r|4; - if(f==5.0) - return r|5; - if(f==0.5) - return r|6; - if(f==10.0) - return r|7; - return 0; -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -void gen_opf(int op) -{ - uint32_t x, r, r2, c1, c2; - //fputs("gen_opf\n",stderr); - vswap(); - c1 = is_fconst(); - vswap(); - c2 = is_fconst(); - x=0xEE000100; -#if LDOUBLE_SIZE == 8 - if ((vtop->type.t & VT_BTYPE) != VT_FLOAT) - x|=0x80; -#else - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - x|=0x80; - else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) - x|=0x80000; -#endif - switch(op) - { - case '+': - if(!c2) { - vswap(); - c2=c1; - } - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - if(c2) { - if(c2>0xf) - x|=0x200000; // suf - r2=c2&0xf; - } else { - r2=fpr(gv(RC_FLOAT)); - } - break; - case '-': - if(c2) { - if(c2<=0xf) - x|=0x200000; // suf - r2=c2&0xf; - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - } else if(c1 && c1<=0xf) { - x|=0x300000; // rsf - r2=c1; - r=fpr(gv(RC_FLOAT)); - vswap(); - } else { - x|=0x200000; // suf - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - r2=fpr(gv(RC_FLOAT)); - } - break; - case '*': - if(!c2 || c2>0xf) { - vswap(); - c2=c1; - } - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - if(c2 && c2<=0xf) - r2=c2; - else - r2=fpr(gv(RC_FLOAT)); - x|=0x100000; // muf - break; - case '/': - if(c2 && c2<=0xf) { - x|=0x400000; // dvf - r2=c2; - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - } else if(c1 && c1<=0xf) { - x|=0x500000; // rdf - r2=c1; - r=fpr(gv(RC_FLOAT)); - vswap(); - } else { - x|=0x400000; // dvf - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - r2=fpr(gv(RC_FLOAT)); - } - break; - default: - if(op >= TOK_ULT && op <= TOK_GT) { - x|=0xd0f110; // cmfe -/* bug (intention?) in Linux FPU emulator - doesn't set carry if equal */ - switch(op) { - case TOK_ULT: - case TOK_UGE: - case TOK_ULE: - case TOK_UGT: - tcc_error("unsigned comparison on floats?"); - break; - case TOK_LT: - op=TOK_Nset; - break; - case TOK_LE: - op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */ - break; - case TOK_EQ: - case TOK_NE: - x&=~0x400000; // cmfe -> cmf - break; - } - if(c1 && !c2) { - c2=c1; - vswap(); - switch(op) { - case TOK_Nset: - op=TOK_GT; - break; - case TOK_GE: - op=TOK_ULE; - break; - case TOK_ULE: - op=TOK_GE; - break; - case TOK_GT: - op=TOK_Nset; - break; - } - } - vswap(); - r=fpr(gv(RC_FLOAT)); - vswap(); - if(c2) { - if(c2>0xf) - x|=0x200000; - r2=c2&0xf; - } else { - r2=fpr(gv(RC_FLOAT)); - } - vtop[-1].r = VT_CMP; - vtop[-1].c.i = op; - } else { - tcc_error("unknown fp op %x!",op); - return; - } - } - if(vtop[-1].r == VT_CMP) - c1=15; - else { - c1=vtop->r; - if(r2&0x8) - c1=vtop[-1].r; - vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1)); - c1=fpr(vtop[-1].r); - } - vtop--; - o(x|(r<<16)|(c1<<12)|r2); -} -#endif - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -ST_FUNC void gen_cvt_itof1(int t) -{ - uint32_t r, r2; - int bt; - bt=vtop->type.t & VT_BTYPE; - if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { -#ifndef TCC_ARM_VFP - uint32_t dsize = 0; -#endif - r=intr(gv(RC_INT)); -#ifdef TCC_ARM_VFP - r2=vfpr(vtop->r=get_reg(RC_FLOAT)); - o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */ - r2|=r2<<12; - if(!(vtop->type.t & VT_UNSIGNED)) - r2|=0x80; /* fuitoX -> fsituX */ - o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/ -#else - r2=fpr(vtop->r=get_reg(RC_FLOAT)); - if((t & VT_BTYPE) != VT_FLOAT) - dsize=0x80; /* flts -> fltd */ - o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */ - if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { - uint32_t off = 0; - o(0xE3500000|(r<<12)); /* cmp */ - r=fpr(get_reg(RC_FLOAT)); - if(last_itod_magic) { - off=ind+8-last_itod_magic; - off/=4; - if(off>255) - off=0; - } - o(0xBD1F0100|(r<<12)|off); /* ldflts */ - if(!off) { - o(0xEA000000); /* b */ - last_itod_magic=ind; - o(0x4F800000); /* 4294967296.0f */ - } - o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */ - } -#endif - return; - } else if(bt == VT_LLONG) { - int func; - CType *func_type = 0; - if((t & VT_BTYPE) == VT_FLOAT) { - func_type = &func_float_type; - if(vtop->type.t & VT_UNSIGNED) - func=TOK___floatundisf; - else - func=TOK___floatdisf; -#if LDOUBLE_SIZE != 8 - } else if((t & VT_BTYPE) == VT_LDOUBLE) { - func_type = &func_ldouble_type; - if(vtop->type.t & VT_UNSIGNED) - func=TOK___floatundixf; - else - func=TOK___floatdixf; - } else if((t & VT_BTYPE) == VT_DOUBLE) { -#else - } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) { -#endif - func_type = &func_double_type; - if(vtop->type.t & VT_UNSIGNED) - func=TOK___floatundidf; - else - func=TOK___floatdidf; - } - if(func_type) { - vpush_global_sym(func_type, func); - vswap(); - gfunc_call(1); - vpushi(0); - vtop->r=TREG_F0; - return; - } - } - tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t); -} - -/* convert fp to int 't' type */ -void gen_cvt_ftoi(int t) -{ - uint32_t r, r2; - int u, func = 0; - u=t&VT_UNSIGNED; - t&=VT_BTYPE; - r2=vtop->type.t & VT_BTYPE; - if(t==VT_INT) { -#ifdef TCC_ARM_VFP - r=vfpr(gv(RC_FLOAT)); - u=u?0:0x10000; - o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */ - r2=intr(vtop->r=get_reg(RC_INT)); - o(0xEE100A10|(r<<16)|(r2<<12)); - return; -#else - if(u) { - if(r2 == VT_FLOAT) - func=TOK___fixunssfsi; -#if LDOUBLE_SIZE != 8 - else if(r2 == VT_LDOUBLE) - func=TOK___fixunsxfsi; - else if(r2 == VT_DOUBLE) -#else - else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) -#endif - func=TOK___fixunsdfsi; - } else { - r=fpr(gv(RC_FLOAT)); - r2=intr(vtop->r=get_reg(RC_INT)); - o(0xEE100170|(r2<<12)|r); - return; - } -#endif - } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 - if(r2 == VT_FLOAT) - func=TOK___fixsfdi; -#if LDOUBLE_SIZE != 8 - else if(r2 == VT_LDOUBLE) - func=TOK___fixxfdi; - else if(r2 == VT_DOUBLE) -#else - else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) -#endif - func=TOK___fixdfdi; - } - if(func) { - vpush_global_sym(&func_old_type, func); - vswap(); - gfunc_call(1); - vpushi(0); - if(t == VT_LLONG) - vtop->r2 = REG_LRET; - vtop->r = REG_IRET; - return; - } - tcc_error("unimplemented gen_cvt_ftoi!"); -} - -/* convert from one floating point type to another */ -void gen_cvt_ftof(int t) -{ -#ifdef TCC_ARM_VFP - if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) { - uint32_t r = vfpr(gv(RC_FLOAT)); - o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t)); - } -#else - /* all we have to do on i386 and FPA ARM is to put the float in a register */ - gv(RC_FLOAT); -#endif -} - -/* computed goto support */ -void ggoto(void) -{ - gcall_or_jmp(1); - vtop--; -} - -/* Save the stack pointer onto the stack and return the location of its address */ -ST_FUNC void gen_vla_sp_save(int addr) { - SValue v; - v.type.t = VT_PTR; - v.r = VT_LOCAL | VT_LVAL; - v.c.i = addr; - store(TREG_SP, &v); -} - -/* Restore the SP from a location on the stack */ -ST_FUNC void gen_vla_sp_restore(int addr) { - SValue v; - v.type.t = VT_PTR; - v.r = VT_LOCAL | VT_LVAL; - v.c.i = addr; - load(TREG_SP, &v); -} - -/* Subtract from the stack pointer, and push the resulting value onto the stack */ -ST_FUNC void gen_vla_alloc(CType *type, int align) { - int r = intr(gv(RC_INT)); - o(0xE04D0000|(r<<12)|r); /* sub r, sp, r */ -#ifdef TCC_ARM_EABI - if (align < 8) - align = 8; -#else - if (align < 4) - align = 4; -#endif - if (align & (align - 1)) - tcc_error("alignment is not a power of 2: %i", align); - o(stuff_const(0xE3C0D000|(r<<16), align - 1)); /* bic sp, r, #align-1 */ - vpop(); -} - -/* end of ARM code generator */ -/*************************************************************/ -#endif -/*************************************************************/ diff --git a/tinyc/arm-link.c b/tinyc/arm-link.c deleted file mode 100644 index aee35afef..000000000 --- a/tinyc/arm-link.c +++ /dev/null @@ -1,392 +0,0 @@ -#ifdef TARGET_DEFS_ONLY - -#define EM_TCC_TARGET EM_ARM - -/* relocation type for 32 bit data relocation */ -#define R_DATA_32 R_ARM_ABS32 -#define R_DATA_PTR R_ARM_ABS32 -#define R_JMP_SLOT R_ARM_JUMP_SLOT -#define R_GLOB_DAT R_ARM_GLOB_DAT -#define R_COPY R_ARM_COPY -#define R_RELATIVE R_ARM_RELATIVE - -#define R_NUM R_ARM_NUM - -#define ELF_START_ADDR 0x00008000 -#define ELF_PAGE_SIZE 0x1000 - -#define PCRELATIVE_DLLPLT 1 -#define RELOCATE_DLLPLT 0 - -enum float_abi { - ARM_SOFTFP_FLOAT, - ARM_HARD_FLOAT, -}; - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -/* Returns 1 for a code relocation, 0 for a data relocation. For unknown - relocations, returns -1. */ -int code_reloc (int reloc_type) -{ - switch (reloc_type) { - case R_ARM_MOVT_ABS: - case R_ARM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_ABS32: - case R_ARM_REL32: - case R_ARM_GOTPC: - case R_ARM_GOTOFF: - case R_ARM_GOT32: - case R_ARM_COPY: - case R_ARM_GLOB_DAT: - case R_ARM_NONE: - return 0; - - case R_ARM_PC24: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PLT32: - case R_ARM_THM_PC22: - case R_ARM_THM_JUMP24: - case R_ARM_PREL31: - case R_ARM_V4BX: - case R_ARM_JUMP_SLOT: - return 1; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -/* Returns an enumerator to describe whether and when the relocation needs a - GOT and/or PLT entry to be created. See tcc.h for a description of the - different values. */ -int gotplt_entry_type (int reloc_type) -{ - switch (reloc_type) { - case R_ARM_NONE: - case R_ARM_COPY: - case R_ARM_GLOB_DAT: - case R_ARM_JUMP_SLOT: - return NO_GOTPLT_ENTRY; - - case R_ARM_PC24: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PLT32: - case R_ARM_THM_PC22: - case R_ARM_THM_JUMP24: - case R_ARM_MOVT_ABS: - case R_ARM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_PREL31: - case R_ARM_ABS32: - case R_ARM_REL32: - case R_ARM_V4BX: - return AUTO_GOTPLT_ENTRY; - - case R_ARM_GOTPC: - case R_ARM_GOTOFF: - return BUILD_GOT_ONLY; - - case R_ARM_GOT32: - return ALWAYS_GOTPLT_ENTRY; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) -{ - Section *plt = s1->plt; - uint8_t *p; - unsigned plt_offset; - - /* when building a DLL, GOT entry accesses must be done relative to - start of GOT (see x86_64 example above) */ - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_error("DLLs unimplemented!"); - - /* empty PLT: create PLT0 entry that push address of call site and - jump to ld.so resolution routine (GOT + 8) */ - if (plt->data_offset == 0) { - p = section_ptr_add(plt, 20); - write32le(p, 0xe52de004); /* push {lr} */ - write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */ - write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */ - write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ - /* p+16 is set in relocate_plt */ - } - plt_offset = plt->data_offset; - - if (attr->plt_thumb_stub) { - p = section_ptr_add(plt, 4); - write32le(p, 0x4778); /* bx pc */ - write32le(p+2, 0x46c0); /* nop */ - } - p = section_ptr_add(plt, 16); - /* Jump to GOT entry where ld.so initially put address of PLT0 */ - write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */ - write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */ - write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */ - /* p + 12 contains offset to GOT entry once patched by relocate_plt */ - write32le(p+12, got_offset); - return plt_offset; -} - -/* relocate the PLT: compute addresses and offsets in the PLT now that final - address for PLT and GOT are known (see fill_program_header) */ -ST_FUNC void relocate_plt(TCCState *s1) -{ - uint8_t *p, *p_end; - - if (!s1->plt) - return; - - p = s1->plt->data; - p_end = p + s1->plt->data_offset; - - if (p < p_end) { - int x = s1->got->sh_addr - s1->plt->sh_addr - 12; - write32le(s1->plt->data + 16, x - 16); - p += 20; - while (p < p_end) { - if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */ - p += 4; - add32le(p + 12, x + s1->plt->data - p); - p += 16; - } - } -} - -void relocate_init(Section *sr) {} - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) -{ - ElfW(Sym) *sym; - int sym_index; - - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - - switch(type) { - case R_ARM_PC24: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PLT32: - { - int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; - x = (*(int *) ptr) & 0xffffff; -#ifdef DEBUG_RELOC - printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); -#endif - (*(int *)ptr) &= 0xff000000; - if (x & 0x800000) - x -= 0x1000000; - x <<= 2; - blx_avail = (TCC_CPU_VERSION >= 5); - is_thumb = val & 1; - is_bl = (*(unsigned *) ptr) >> 24 == 0xeb; - is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl)); - x += val - addr; -#ifdef DEBUG_RELOC - printf (" newx=0x%x name=%s\n", x, - (char *) symtab_section->link->data + sym->st_name); -#endif - h = x & 2; - th_ko = (x & 3) && (!blx_avail || !is_call); - if (th_ko || x >= 0x2000000 || x < -0x2000000) - tcc_error("can't relocate value at %x,%d",addr, type); - x >>= 2; - x &= 0xffffff; - /* Only reached if blx is avail and it is a call */ - if (is_thumb) { - x |= h << 24; - (*(int *)ptr) = 0xfa << 24; /* bl -> blx */ - } - (*(int *) ptr) |= x; - } - return; - /* Since these relocations only concern Thumb-2 and blx instruction was - introduced before Thumb-2, we can assume blx is available and not - guard its use */ - case R_ARM_THM_PC22: - case R_ARM_THM_JUMP24: - { - int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; - int to_thumb, is_call, to_plt, blx_bit = 1 << 12; - Section *plt; - - /* weak reference */ - if (sym->st_shndx == SHN_UNDEF && - ELFW(ST_BIND)(sym->st_info) == STB_WEAK) - return; - - /* Get initial offset */ - hi = (*(uint16_t *)ptr); - lo = (*(uint16_t *)(ptr+2)); - s = (hi >> 10) & 1; - j1 = (lo >> 13) & 1; - j2 = (lo >> 11) & 1; - i1 = (j1 ^ s) ^ 1; - i2 = (j2 ^ s) ^ 1; - imm10 = hi & 0x3ff; - imm11 = lo & 0x7ff; - x = (s << 24) | (i1 << 23) | (i2 << 22) | - (imm10 << 12) | (imm11 << 1); - if (x & 0x01000000) - x -= 0x02000000; - - /* Relocation infos */ - to_thumb = val & 1; - plt = s1->plt; - to_plt = (val >= plt->sh_addr) && - (val < plt->sh_addr + plt->data_offset); - is_call = (type == R_ARM_THM_PC22); - - if (!to_thumb && !to_plt && !is_call) { - int index; - uint8_t *p; - char *name, buf[1024]; - Section *text_section; - - name = (char *) symtab_section->link->data + sym->st_name; - text_section = s1->sections[sym->st_shndx]; - /* Modify reloc to target a thumb stub to switch to ARM */ - snprintf(buf, sizeof(buf), "%s_from_thumb", name); - index = put_elf_sym(symtab_section, - text_section->data_offset + 1, - sym->st_size, sym->st_info, 0, - sym->st_shndx, buf); - to_thumb = 1; - val = text_section->data_offset + 1; - rel->r_info = ELFW(R_INFO)(index, type); - /* Create a thumb stub function to switch to ARM mode */ - put_elf_reloc(symtab_section, text_section, - text_section->data_offset + 4, R_ARM_JUMP24, - sym_index); - p = section_ptr_add(text_section, 8); - write32le(p, 0x4778); /* bx pc */ - write32le(p+2, 0x46c0); /* nop */ - write32le(p+4, 0xeafffffe); /* b $sym */ - } - - /* Compute final offset */ - x += val - addr; - if (!to_thumb && is_call) { - blx_bit = 0; /* bl -> blx */ - x = (x + 3) & -4; /* Compute offset from aligned PC */ - } - - /* Check that relocation is possible - * offset must not be out of range - * if target is to be entered in arm mode: - - bit 1 must not set - - instruction must be a call (bl) or a jump to PLT */ - if (!to_thumb || x >= 0x1000000 || x < -0x1000000) - if (to_thumb || (val & 2) || (!is_call && !to_plt)) - tcc_error("can't relocate value at %x,%d",addr, type); - - /* Compute and store final offset */ - s = (x >> 24) & 1; - i1 = (x >> 23) & 1; - i2 = (x >> 22) & 1; - j1 = s ^ (i1 ^ 1); - j2 = s ^ (i2 ^ 1); - imm10 = (x >> 12) & 0x3ff; - imm11 = (x >> 1) & 0x7ff; - (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | - (s << 10) | imm10); - (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | - (j1 << 13) | blx_bit | (j2 << 11) | - imm11); - } - return; - case R_ARM_MOVT_ABS: - case R_ARM_MOVW_ABS_NC: - { - int x, imm4, imm12; - if (type == R_ARM_MOVT_ABS) - val >>= 16; - imm12 = val & 0xfff; - imm4 = (val >> 12) & 0xf; - x = (imm4 << 16) | imm12; - if (type == R_ARM_THM_MOVT_ABS) - *(int *)ptr |= x; - else - *(int *)ptr += x; - } - return; - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - { - int x, i, imm4, imm3, imm8; - if (type == R_ARM_THM_MOVT_ABS) - val >>= 16; - imm8 = val & 0xff; - imm3 = (val >> 8) & 0x7; - i = (val >> 11) & 1; - imm4 = (val >> 12) & 0xf; - x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4; - if (type == R_ARM_THM_MOVT_ABS) - *(int *)ptr |= x; - else - *(int *)ptr += x; - } - return; - case R_ARM_PREL31: - { - int x; - x = (*(int *)ptr) & 0x7fffffff; - (*(int *)ptr) &= 0x80000000; - x = (x * 2) / 2; - x += val - addr; - if((x^(x>>1))&0x40000000) - tcc_error("can't relocate value at %x,%d",addr, type); - (*(int *)ptr) |= x & 0x7fffffff; - } - case R_ARM_ABS32: - *(int *)ptr += val; - return; - case R_ARM_REL32: - *(int *)ptr += val - addr; - return; - case R_ARM_GOTPC: - *(int *)ptr += s1->got->sh_addr - addr; - return; - case R_ARM_GOTOFF: - *(int *)ptr += val - s1->got->sh_addr; - return; - case R_ARM_GOT32: - /* we load the got offset */ - *(int *)ptr += s1->sym_attrs[sym_index].got_offset; - return; - case R_ARM_COPY: - return; - case R_ARM_V4BX: - /* trade Thumb support for ARMv4 support */ - if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) - *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ - return; - case R_ARM_GLOB_DAT: - case R_ARM_JUMP_SLOT: - *(addr_t *)ptr = val; - return; - case R_ARM_NONE: - /* Nothing to do. Normally used to indicate a dependency - on a certain symbol (like for exception handling under EABI). */ - return; - default: - fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", - type, (unsigned)addr, ptr, (unsigned)val); - return; - } -} - -#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/arm64-gen.c b/tinyc/arm64-gen.c deleted file mode 100644 index 86b3af73b..000000000 --- a/tinyc/arm64-gen.c +++ /dev/null @@ -1,1837 +0,0 @@ -/* - * A64 code generator for TCC - * - * Copyright (c) 2014-2015 Edmund Grimley Evans - * - * Copying and distribution of this file, with or without modification, - * are permitted in any medium without royalty provided the copyright - * notice and this notice are preserved. This file is offered as-is, - * without any warranty. - */ - -#ifdef TARGET_DEFS_ONLY - -// Number of registers available to allocator: -#define NB_REGS 28 // x0-x18, x30, v0-v7 - -#define TREG_R(x) (x) // x = 0..18 -#define TREG_R30 19 -#define TREG_F(x) (x + 20) // x = 0..7 - -// Register classes sorted from more general to more precise: -#define RC_INT (1 << 0) -#define RC_FLOAT (1 << 1) -#define RC_R(x) (1 << (2 + (x))) // x = 0..18 -#define RC_R30 (1 << 21) -#define RC_F(x) (1 << (22 + (x))) // x = 0..7 - -#define RC_IRET (RC_R(0)) // int return register class -#define RC_FRET (RC_F(0)) // float return register class - -#define REG_IRET (TREG_R(0)) // int return register number -#define REG_FRET (TREG_F(0)) // float return register number - -#define PTR_SIZE 8 - -#define LDOUBLE_SIZE 16 -#define LDOUBLE_ALIGN 16 - -#define MAX_ALIGN 16 - -#define CHAR_IS_UNSIGNED - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#include "tcc.h" -#include - -ST_DATA const int reg_classes[NB_REGS] = { - RC_INT | RC_R(0), - RC_INT | RC_R(1), - RC_INT | RC_R(2), - RC_INT | RC_R(3), - RC_INT | RC_R(4), - RC_INT | RC_R(5), - RC_INT | RC_R(6), - RC_INT | RC_R(7), - RC_INT | RC_R(8), - RC_INT | RC_R(9), - RC_INT | RC_R(10), - RC_INT | RC_R(11), - RC_INT | RC_R(12), - RC_INT | RC_R(13), - RC_INT | RC_R(14), - RC_INT | RC_R(15), - RC_INT | RC_R(16), - RC_INT | RC_R(17), - RC_INT | RC_R(18), - RC_R30, // not in RC_INT as we make special use of x30 - RC_FLOAT | RC_F(0), - RC_FLOAT | RC_F(1), - RC_FLOAT | RC_F(2), - RC_FLOAT | RC_F(3), - RC_FLOAT | RC_F(4), - RC_FLOAT | RC_F(5), - RC_FLOAT | RC_F(6), - RC_FLOAT | RC_F(7) -}; - -#define IS_FREG(x) ((x) >= TREG_F(0)) - -static uint32_t intr(int r) -{ - assert(TREG_R(0) <= r && r <= TREG_R30); - return r < TREG_R30 ? r : 30; -} - -static uint32_t fltr(int r) -{ - assert(TREG_F(0) <= r && r <= TREG_F(7)); - return r - TREG_F(0); -} - -// Add an instruction to text section: -ST_FUNC void o(unsigned int c) -{ - int ind1 = ind + 4; - if (nocode_wanted) - return; - if (ind1 > cur_text_section->data_allocated) - section_realloc(cur_text_section, ind1); - write32le(cur_text_section->data + ind, c); - ind = ind1; -} - -static int arm64_encode_bimm64(uint64_t x) -{ - int neg = x & 1; - int rep, pos, len; - - if (neg) - x = ~x; - if (!x) - return -1; - - if (x >> 2 == (x & (((uint64_t)1 << (64 - 2)) - 1))) - rep = 2, x &= ((uint64_t)1 << 2) - 1; - else if (x >> 4 == (x & (((uint64_t)1 << (64 - 4)) - 1))) - rep = 4, x &= ((uint64_t)1 << 4) - 1; - else if (x >> 8 == (x & (((uint64_t)1 << (64 - 8)) - 1))) - rep = 8, x &= ((uint64_t)1 << 8) - 1; - else if (x >> 16 == (x & (((uint64_t)1 << (64 - 16)) - 1))) - rep = 16, x &= ((uint64_t)1 << 16) - 1; - else if (x >> 32 == (x & (((uint64_t)1 << (64 - 32)) - 1))) - rep = 32, x &= ((uint64_t)1 << 32) - 1; - else - rep = 64; - - pos = 0; - if (!(x & (((uint64_t)1 << 32) - 1))) x >>= 32, pos += 32; - if (!(x & (((uint64_t)1 << 16) - 1))) x >>= 16, pos += 16; - if (!(x & (((uint64_t)1 << 8) - 1))) x >>= 8, pos += 8; - if (!(x & (((uint64_t)1 << 4) - 1))) x >>= 4, pos += 4; - if (!(x & (((uint64_t)1 << 2) - 1))) x >>= 2, pos += 2; - if (!(x & (((uint64_t)1 << 1) - 1))) x >>= 1, pos += 1; - - len = 0; - if (!(~x & (((uint64_t)1 << 32) - 1))) x >>= 32, len += 32; - if (!(~x & (((uint64_t)1 << 16) - 1))) x >>= 16, len += 16; - if (!(~x & (((uint64_t)1 << 8) - 1))) x >>= 8, len += 8; - if (!(~x & (((uint64_t)1 << 4) - 1))) x >>= 4, len += 4; - if (!(~x & (((uint64_t)1 << 2) - 1))) x >>= 2, len += 2; - if (!(~x & (((uint64_t)1 << 1) - 1))) x >>= 1, len += 1; - - if (x) - return -1; - if (neg) { - pos = (pos + len) & (rep - 1); - len = rep - len; - } - return ((0x1000 & rep << 6) | (((rep - 1) ^ 31) << 1 & 63) | - ((rep - pos) & (rep - 1)) << 6 | (len - 1)); -} - -static uint32_t arm64_movi(int r, uint64_t x) -{ - uint64_t m = 0xffff; - int e; - if (!(x & ~m)) - return 0x52800000 | r | x << 5; // movz w(r),#(x) - if (!(x & ~(m << 16))) - return 0x52a00000 | r | x >> 11; // movz w(r),#(x >> 16),lsl #16 - if (!(x & ~(m << 32))) - return 0xd2c00000 | r | x >> 27; // movz x(r),#(x >> 32),lsl #32 - if (!(x & ~(m << 48))) - return 0xd2e00000 | r | x >> 43; // movz x(r),#(x >> 48),lsl #48 - if ((x & ~m) == m << 16) - return (0x12800000 | r | - (~x << 5 & 0x1fffe0)); // movn w(r),#(~x) - if ((x & ~(m << 16)) == m) - return (0x12a00000 | r | - (~x >> 11 & 0x1fffe0)); // movn w(r),#(~x >> 16),lsl #16 - if (!~(x | m)) - return (0x92800000 | r | - (~x << 5 & 0x1fffe0)); // movn x(r),#(~x) - if (!~(x | m << 16)) - return (0x92a00000 | r | - (~x >> 11 & 0x1fffe0)); // movn x(r),#(~x >> 16),lsl #16 - if (!~(x | m << 32)) - return (0x92c00000 | r | - (~x >> 27 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32 - if (!~(x | m << 48)) - return (0x92e00000 | r | - (~x >> 43 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32 - if (!(x >> 32) && (e = arm64_encode_bimm64(x | x << 32)) >= 0) - return 0x320003e0 | r | (uint32_t)e << 10; // movi w(r),#(x) - if ((e = arm64_encode_bimm64(x)) >= 0) - return 0xb20003e0 | r | (uint32_t)e << 10; // movi x(r),#(x) - return 0; -} - -static void arm64_movimm(int r, uint64_t x) -{ - uint32_t i; - if ((i = arm64_movi(r, x))) - o(i); // a single MOV - else { - // MOVZ/MOVN and 1-3 MOVKs - int z = 0, m = 0; - uint32_t mov1 = 0xd2800000; // movz - uint64_t x1 = x; - for (i = 0; i < 64; i += 16) { - z += !(x >> i & 0xffff); - m += !(~x >> i & 0xffff); - } - if (m > z) { - x1 = ~x; - mov1 = 0x92800000; // movn - } - for (i = 0; i < 64; i += 16) - if (x1 >> i & 0xffff) { - o(mov1 | r | (x1 >> i & 0xffff) << 5 | i << 17); - // movz/movn x(r),#(*),lsl #(i) - break; - } - for (i += 16; i < 64; i += 16) - if (x1 >> i & 0xffff) - o(0xf2800000 | r | (x >> i & 0xffff) << 5 | i << 17); - // movk x(r),#(*),lsl #(i) - } -} - -// Patch all branches in list pointed to by t to branch to a: -ST_FUNC void gsym_addr(int t_, int a_) -{ - uint32_t t = t_; - uint32_t a = a_; - while (t) { - unsigned char *ptr = cur_text_section->data + t; - uint32_t next = read32le(ptr); - if (a - t + 0x8000000 >= 0x10000000) - tcc_error("branch out of range"); - write32le(ptr, (a - t == 4 ? 0xd503201f : // nop - 0x14000000 | ((a - t) >> 2 & 0x3ffffff))); // b - t = next; - } -} - -// Patch all branches in list pointed to by t to branch to current location: -ST_FUNC void gsym(int t) -{ - gsym_addr(t, ind); -} - -static int arm64_type_size(int t) -{ - switch (t & VT_BTYPE) { - case VT_INT: return 2; - case VT_BYTE: return 0; - case VT_SHORT: return 1; - case VT_PTR: return 3; - case VT_FUNC: return 3; - case VT_FLOAT: return 2; - case VT_DOUBLE: return 3; - case VT_LDOUBLE: return 4; - case VT_BOOL: return 0; - case VT_LLONG: return 3; - } - assert(0); - return 0; -} - -static void arm64_spoff(int reg, uint64_t off) -{ - uint32_t sub = off >> 63; - if (sub) - off = -off; - if (off < 4096) - o(0x910003e0 | sub << 30 | reg | off << 10); - // (add|sub) x(reg),sp,#(off) - else { - arm64_movimm(30, off); // use x30 for offset - o(0x8b3e63e0 | sub << 30 | reg); // (add|sub) x(reg),sp,x30 - } -} - -static void arm64_ldrx(int sg, int sz_, int dst, int bas, uint64_t off) -{ - uint32_t sz = sz_; - if (sz >= 2) - sg = 0; - if (!(off & ~((uint32_t)0xfff << sz))) - o(0x39400000 | dst | bas << 5 | off << (10 - sz) | - (uint32_t)!!sg << 23 | sz << 30); // ldr(*) x(dst),[x(bas),#(off)] - else if (off < 256 || -off <= 256) - o(0x38400000 | dst | bas << 5 | (off & 511) << 12 | - (uint32_t)!!sg << 23 | sz << 30); // ldur(*) x(dst),[x(bas),#(off)] - else { - arm64_movimm(30, off); // use x30 for offset - o(0x38206800 | dst | bas << 5 | (uint32_t)30 << 16 | - (uint32_t)(!!sg + 1) << 22 | sz << 30); // ldr(*) x(dst),[x(bas),x30] - } -} - -static void arm64_ldrv(int sz_, int dst, int bas, uint64_t off) -{ - uint32_t sz = sz_; - if (!(off & ~((uint32_t)0xfff << sz))) - o(0x3d400000 | dst | bas << 5 | off << (10 - sz) | - (sz & 4) << 21 | (sz & 3) << 30); // ldr (s|d|q)(dst),[x(bas),#(off)] - else if (off < 256 || -off <= 256) - o(0x3c400000 | dst | bas << 5 | (off & 511) << 12 | - (sz & 4) << 21 | (sz & 3) << 30); // ldur (s|d|q)(dst),[x(bas),#(off)] - else { - arm64_movimm(30, off); // use x30 for offset - o(0x3c606800 | dst | bas << 5 | (uint32_t)30 << 16 | - sz << 30 | (sz & 4) << 21); // ldr (s|d|q)(dst),[x(bas),x30] - } -} - -static void arm64_ldrs(int reg_, int size) -{ - uint32_t reg = reg_; - // Use x30 for intermediate value in some cases. - switch (size) { - default: assert(0); break; - case 1: - arm64_ldrx(0, 0, reg, reg, 0); - break; - case 2: - arm64_ldrx(0, 1, reg, reg, 0); - break; - case 3: - arm64_ldrx(0, 1, 30, reg, 0); - arm64_ldrx(0, 0, reg, reg, 2); - o(0x2a0043c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #16 - break; - case 4: - arm64_ldrx(0, 2, reg, reg, 0); - break; - case 5: - arm64_ldrx(0, 2, 30, reg, 0); - arm64_ldrx(0, 0, reg, reg, 4); - o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 - break; - case 6: - arm64_ldrx(0, 2, 30, reg, 0); - arm64_ldrx(0, 1, reg, reg, 4); - o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 - break; - case 7: - arm64_ldrx(0, 2, 30, reg, 0); - arm64_ldrx(0, 2, reg, reg, 3); - o(0x53087c00 | reg | reg << 5); // lsr w(reg), w(reg), #8 - o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 - break; - case 8: - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 9: - arm64_ldrx(0, 0, reg + 1, reg, 8); - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 10: - arm64_ldrx(0, 1, reg + 1, reg, 8); - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 11: - arm64_ldrx(0, 2, reg + 1, reg, 7); - o(0x53087c00 | (reg+1) | (reg+1) << 5); // lsr w(reg+1), w(reg+1), #8 - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 12: - arm64_ldrx(0, 2, reg + 1, reg, 8); - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 13: - arm64_ldrx(0, 3, reg + 1, reg, 5); - o(0xd358fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #24 - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 14: - arm64_ldrx(0, 3, reg + 1, reg, 6); - o(0xd350fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #16 - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 15: - arm64_ldrx(0, 3, reg + 1, reg, 7); - o(0xd348fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #8 - arm64_ldrx(0, 3, reg, reg, 0); - break; - case 16: - o(0xa9400000 | reg | (reg+1) << 10 | reg << 5); - // ldp x(reg),x(reg+1),[x(reg)] - break; - } -} - -static void arm64_strx(int sz_, int dst, int bas, uint64_t off) -{ - uint32_t sz = sz_; - if (!(off & ~((uint32_t)0xfff << sz))) - o(0x39000000 | dst | bas << 5 | off << (10 - sz) | sz << 30); - // str(*) x(dst),[x(bas],#(off)] - else if (off < 256 || -off <= 256) - o(0x38000000 | dst | bas << 5 | (off & 511) << 12 | sz << 30); - // stur(*) x(dst),[x(bas],#(off)] - else { - arm64_movimm(30, off); // use x30 for offset - o(0x38206800 | dst | bas << 5 | (uint32_t)30 << 16 | sz << 30); - // str(*) x(dst),[x(bas),x30] - } -} - -static void arm64_strv(int sz_, int dst, int bas, uint64_t off) -{ - uint32_t sz = sz_; - if (!(off & ~((uint32_t)0xfff << sz))) - o(0x3d000000 | dst | bas << 5 | off << (10 - sz) | - (sz & 4) << 21 | (sz & 3) << 30); // str (s|d|q)(dst),[x(bas),#(off)] - else if (off < 256 || -off <= 256) - o(0x3c000000 | dst | bas << 5 | (off & 511) << 12 | - (sz & 4) << 21 | (sz & 3) << 30); // stur (s|d|q)(dst),[x(bas),#(off)] - else { - arm64_movimm(30, off); // use x30 for offset - o(0x3c206800 | dst | bas << 5 | (uint32_t)30 << 16 | - sz << 30 | (sz & 4) << 21); // str (s|d|q)(dst),[x(bas),x30] - } -} - -static void arm64_sym(int r, Sym *sym, unsigned long addend) -{ - // Currently TCC's linker does not generate COPY relocations for - // STT_OBJECTs when tcc is invoked with "-run". This typically - // results in "R_AARCH64_ADR_PREL_PG_HI21 relocation failed" when - // a program refers to stdin. A workaround is to avoid that - // relocation and use only relocations with unlimited range. - int avoid_adrp = 1; - - if (avoid_adrp || sym->a.weak) { - // (GCC uses a R_AARCH64_ABS64 in this case.) - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend); - o(0xd2800000 | r); // mov x(rt),#0,lsl #0 - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G1_NC, addend); - o(0xf2a00000 | r); // movk x(rt),#0,lsl #16 - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G2_NC, addend); - o(0xf2c00000 | r); // movk x(rt),#0,lsl #32 - greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend); - o(0xf2e00000 | r); // movk x(rt),#0,lsl #48 - } - else { - greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, addend); - o(0x90000000 | r); - greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend); - o(0x91000000 | r | r << 5); - } -} - -ST_FUNC void load(int r, SValue *sv) -{ - int svtt = sv->type.t; - int svr = sv->r & ~VT_LVAL_TYPE; - int svrv = svr & VT_VALMASK; - uint64_t svcul = (uint32_t)sv->c.i; - svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul; - - if (svr == (VT_LOCAL | VT_LVAL)) { - if (IS_FREG(r)) - arm64_ldrv(arm64_type_size(svtt), fltr(r), 29, svcul); - else - arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), - intr(r), 29, svcul); - return; - } - - if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { - if (IS_FREG(r)) - arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); - else - arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), - intr(r), intr(svrv), 0); - return; - } - - if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { - arm64_sym(30, sv->sym, svcul); // use x30 for address - if (IS_FREG(r)) - arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0); - else - arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), - intr(r), 30, 0); - return; - } - - if (svr == (VT_CONST | VT_SYM)) { - arm64_sym(intr(r), sv->sym, svcul); - return; - } - - if (svr == VT_CONST) { - if ((svtt & VT_BTYPE) != VT_VOID) - arm64_movimm(intr(r), arm64_type_size(svtt) == 3 ? - sv->c.i : (uint32_t)svcul); - return; - } - - if (svr < VT_CONST) { - if (IS_FREG(r) && IS_FREG(svr)) - if (svtt == VT_LDOUBLE) - o(0x4ea01c00 | fltr(r) | fltr(svr) << 5); - // mov v(r).16b,v(svr).16b - else - o(0x1e604000 | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr) - else if (!IS_FREG(r) && !IS_FREG(svr)) - o(0xaa0003e0 | intr(r) | intr(svr) << 16); // mov x(r),x(svr) - else - assert(0); - return; - } - - if (svr == VT_LOCAL) { - if (-svcul < 0x1000) - o(0xd10003a0 | intr(r) | -svcul << 10); // sub x(r),x29,#... - else { - arm64_movimm(30, -svcul); // use x30 for offset - o(0xcb0003a0 | intr(r) | (uint32_t)30 << 16); // sub x(r),x29,x30 - } - return; - } - - if (svr == VT_JMP || svr == VT_JMPI) { - int t = (svr == VT_JMPI); - arm64_movimm(intr(r), t); - o(0x14000002); // b .+8 - gsym(svcul); - arm64_movimm(intr(r), t ^ 1); - return; - } - - if (svr == (VT_LLOCAL | VT_LVAL)) { - arm64_ldrx(0, 3, 30, 29, svcul); // use x30 for offset - if (IS_FREG(r)) - arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0); - else - arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), - intr(r), 30, 0); - return; - } - - printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); - assert(0); -} - -ST_FUNC void store(int r, SValue *sv) -{ - int svtt = sv->type.t; - int svr = sv->r & ~VT_LVAL_TYPE; - int svrv = svr & VT_VALMASK; - uint64_t svcul = (uint32_t)sv->c.i; - svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul; - - if (svr == (VT_LOCAL | VT_LVAL)) { - if (IS_FREG(r)) - arm64_strv(arm64_type_size(svtt), fltr(r), 29, svcul); - else - arm64_strx(arm64_type_size(svtt), intr(r), 29, svcul); - return; - } - - if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { - if (IS_FREG(r)) - arm64_strv(arm64_type_size(svtt), fltr(r), intr(svrv), 0); - else - arm64_strx(arm64_type_size(svtt), intr(r), intr(svrv), 0); - return; - } - - if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { - arm64_sym(30, sv->sym, svcul); // use x30 for address - if (IS_FREG(r)) - arm64_strv(arm64_type_size(svtt), fltr(r), 30, 0); - else - arm64_strx(arm64_type_size(svtt), intr(r), 30, 0); - return; - } - - printf("store(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); - assert(0); -} - -static void arm64_gen_bl_or_b(int b) -{ - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - assert(!b && (vtop->r & VT_SYM)); - greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0); - o(0x94000000); // bl . - } - else - o(0xd61f0000 | (uint32_t)!b << 21 | intr(gv(RC_R30)) << 5); // br/blr -} - -static int arm64_hfa_aux(CType *type, int *fsize, int num) -{ - if (is_float(type->t)) { - int a, n = type_size(type, &a); - if (num >= 4 || (*fsize && *fsize != n)) - return -1; - *fsize = n; - return num + 1; - } - else if ((type->t & VT_BTYPE) == VT_STRUCT) { - int is_struct = 0; // rather than union - Sym *field; - for (field = type->ref->next; field; field = field->next) - if (field->c) { - is_struct = 1; - break; - } - if (is_struct) { - int num0 = num; - for (field = type->ref->next; field; field = field->next) { - if (field->c != (num - num0) * *fsize) - return -1; - num = arm64_hfa_aux(&field->type, fsize, num); - if (num == -1) - return -1; - } - if (type->ref->c != (num - num0) * *fsize) - return -1; - return num; - } - else { // union - int num0 = num; - for (field = type->ref->next; field; field = field->next) { - int num1 = arm64_hfa_aux(&field->type, fsize, num0); - if (num1 == -1) - return -1; - num = num1 < num ? num : num1; - } - if (type->ref->c != (num - num0) * *fsize) - return -1; - return num; - } - } - else if (type->t & VT_ARRAY) { - int num1; - if (!type->ref->c) - return num; - num1 = arm64_hfa_aux(&type->ref->type, fsize, num); - if (num1 == -1 || (num1 != num && type->ref->c > 4)) - return -1; - num1 = num + type->ref->c * (num1 - num); - if (num1 > 4) - return -1; - return num1; - } - return -1; -} - -static int arm64_hfa(CType *type, int *fsize) -{ - if ((type->t & VT_BTYPE) == VT_STRUCT || (type->t & VT_ARRAY)) { - int sz = 0; - int n = arm64_hfa_aux(type, &sz, 0); - if (0 < n && n <= 4) { - if (fsize) - *fsize = sz; - return n; - } - } - return 0; -} - -static unsigned long arm64_pcs_aux(int n, CType **type, unsigned long *a) -{ - int nx = 0; // next integer register - int nv = 0; // next vector register - unsigned long ns = 32; // next stack offset - int i; - - for (i = 0; i < n; i++) { - int hfa = arm64_hfa(type[i], 0); - int size, align; - - if ((type[i]->t & VT_ARRAY) || - (type[i]->t & VT_BTYPE) == VT_FUNC) - size = align = 8; - else - size = type_size(type[i], &align); - - if (hfa) - // B.2 - ; - else if (size > 16) { - // B.3: replace with pointer - if (nx < 8) - a[i] = nx++ << 1 | 1; - else { - ns = (ns + 7) & ~7; - a[i] = ns | 1; - ns += 8; - } - continue; - } - else if ((type[i]->t & VT_BTYPE) == VT_STRUCT) - // B.4 - size = (size + 7) & ~7; - - // C.1 - if (is_float(type[i]->t) && nv < 8) { - a[i] = 16 + (nv++ << 1); - continue; - } - - // C.2 - if (hfa && nv + hfa <= 8) { - a[i] = 16 + (nv << 1); - nv += hfa; - continue; - } - - // C.3 - if (hfa) { - nv = 8; - size = (size + 7) & ~7; - } - - // C.4 - if (hfa || (type[i]->t & VT_BTYPE) == VT_LDOUBLE) { - ns = (ns + 7) & ~7; - ns = (ns + align - 1) & -align; - } - - // C.5 - if ((type[i]->t & VT_BTYPE) == VT_FLOAT) - size = 8; - - // C.6 - if (hfa || is_float(type[i]->t)) { - a[i] = ns; - ns += size; - continue; - } - - // C.7 - if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size <= 8 && nx < 8) { - a[i] = nx++ << 1; - continue; - } - - // C.8 - if (align == 16) - nx = (nx + 1) & ~1; - - // C.9 - if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size == 16 && nx < 7) { - a[i] = nx << 1; - nx += 2; - continue; - } - - // C.10 - if ((type[i]->t & VT_BTYPE) == VT_STRUCT && size <= (8 - nx) * 8) { - a[i] = nx << 1; - nx += (size + 7) >> 3; - continue; - } - - // C.11 - nx = 8; - - // C.12 - ns = (ns + 7) & ~7; - ns = (ns + align - 1) & -align; - - // C.13 - if ((type[i]->t & VT_BTYPE) == VT_STRUCT) { - a[i] = ns; - ns += size; - continue; - } - - // C.14 - if (size < 8) - size = 8; - - // C.15 - a[i] = ns; - ns += size; - } - - return ns - 32; -} - -static unsigned long arm64_pcs(int n, CType **type, unsigned long *a) -{ - unsigned long stack; - - // Return type: - if ((type[0]->t & VT_BTYPE) == VT_VOID) - a[0] = -1; - else { - arm64_pcs_aux(1, type, a); - assert(a[0] == 0 || a[0] == 1 || a[0] == 16); - } - - // Argument types: - stack = arm64_pcs_aux(n, type + 1, a + 1); - - if (0) { - int i; - for (i = 0; i <= n; i++) { - if (!i) - printf("arm64_pcs return: "); - else - printf("arm64_pcs arg %d: ", i); - if (a[i] == (unsigned long)-1) - printf("void\n"); - else if (a[i] == 1 && !i) - printf("X8 pointer\n"); - else if (a[i] < 16) - printf("X%lu%s\n", a[i] / 2, a[i] & 1 ? " pointer" : ""); - else if (a[i] < 32) - printf("V%lu\n", a[i] / 2 - 8); - else - printf("stack %lu%s\n", - (a[i] - 32) & ~1, a[i] & 1 ? " pointer" : ""); - } - } - - return stack; -} - -ST_FUNC void gfunc_call(int nb_args) -{ - CType *return_type; - CType **t; - unsigned long *a, *a1; - unsigned long stack; - int i; - - return_type = &vtop[-nb_args].type.ref->type; - if ((return_type->t & VT_BTYPE) == VT_STRUCT) - --nb_args; - - t = tcc_malloc((nb_args + 1) * sizeof(*t)); - a = tcc_malloc((nb_args + 1) * sizeof(*a)); - a1 = tcc_malloc((nb_args + 1) * sizeof(*a1)); - - t[0] = return_type; - for (i = 0; i < nb_args; i++) - t[nb_args - i] = &vtop[-i].type; - - stack = arm64_pcs(nb_args, t, a); - - // Allocate space for structs replaced by pointer: - for (i = nb_args; i; i--) - if (a[i] & 1) { - SValue *arg = &vtop[i - nb_args]; - int align, size = type_size(&arg->type, &align); - assert((arg->type.t & VT_BTYPE) == VT_STRUCT); - stack = (stack + align - 1) & -align; - a1[i] = stack; - stack += size; - } - - stack = (stack + 15) >> 4 << 4; - - assert(stack < 0x1000); - if (stack) - o(0xd10003ff | stack << 10); // sub sp,sp,#(n) - - // First pass: set all values on stack - for (i = nb_args; i; i--) { - vpushv(vtop - nb_args + i); - - if (a[i] & 1) { - // struct replaced by pointer - int r = get_reg(RC_INT); - arm64_spoff(intr(r), a1[i]); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - if (a[i] >= 32) { - // pointer on stack - r = get_reg(RC_INT); - arm64_spoff(intr(r), a1[i]); - arm64_strx(3, intr(r), 31, (a[i] - 32) >> 1 << 1); - } - } - else if (a[i] >= 32) { - // value on stack - if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { - int r = get_reg(RC_INT); - arm64_spoff(intr(r), a[i] - 32); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - } - else if (is_float(vtop->type.t)) { - gv(RC_FLOAT); - arm64_strv(arm64_type_size(vtop[0].type.t), - fltr(vtop[0].r), 31, a[i] - 32); - } - else { - gv(RC_INT); - arm64_strx(arm64_type_size(vtop[0].type.t), - intr(vtop[0].r), 31, a[i] - 32); - } - } - - --vtop; - } - - // Second pass: assign values to registers - for (i = nb_args; i; i--, vtop--) { - if (a[i] < 16 && !(a[i] & 1)) { - // value in general-purpose registers - if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { - int align, size = type_size(&vtop->type, &align); - vtop->type.t = VT_PTR; - gaddrof(); - gv(RC_R(a[i] / 2)); - arm64_ldrs(a[i] / 2, size); - } - else - gv(RC_R(a[i] / 2)); - } - else if (a[i] < 16) - // struct replaced by pointer in register - arm64_spoff(a[i] / 2, a1[i]); - else if (a[i] < 32) { - // value in floating-point registers - if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { - uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz); - vtop->type.t = VT_PTR; - gaddrof(); - gv(RC_R30); - for (j = 0; j < n; j++) - o(0x3d4003c0 | - (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | - (a[i] / 2 - 8 + j) | - j << 10); // ldr ([sdq])(*),[x30,#(j * sz)] - } - else - gv(RC_F(a[i] / 2 - 8)); - } - } - - if ((return_type->t & VT_BTYPE) == VT_STRUCT) { - if (a[0] == 1) { - // indirect return: set x8 and discard the stack value - gv(RC_R(8)); - --vtop; - } - else - // return in registers: keep the address for after the call - vswap(); - } - - save_regs(0); - arm64_gen_bl_or_b(0); - --vtop; - if (stack) - o(0x910003ff | stack << 10); // add sp,sp,#(n) - - { - int rt = return_type->t; - int bt = rt & VT_BTYPE; - if (bt == VT_BYTE || bt == VT_SHORT) - // Promote small integers: - o(0x13001c00 | (bt == VT_SHORT) << 13 | - (uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0 - else if (bt == VT_STRUCT && !(a[0] & 1)) { - // A struct was returned in registers, so write it out: - gv(RC_R(8)); - --vtop; - if (a[0] == 0) { - int align, size = type_size(return_type, &align); - assert(size <= 16); - if (size > 8) - o(0xa9000500); // stp x0,x1,[x8] - else if (size) - arm64_strx(size > 4 ? 3 : size > 2 ? 2 : size > 1, 0, 8, 0); - - } - else if (a[0] == 16) { - uint32_t j, sz, n = arm64_hfa(return_type, &sz); - for (j = 0; j < n; j++) - o(0x3d000100 | - (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | - (a[i] / 2 - 8 + j) | - j << 10); // str ([sdq])(*),[x8,#(j * sz)] - } - } - } - - tcc_free(a1); - tcc_free(a); - tcc_free(t); -} - -static unsigned long arm64_func_va_list_stack; -static int arm64_func_va_list_gr_offs; -static int arm64_func_va_list_vr_offs; -static int arm64_func_sub_sp_offset; - -ST_FUNC void gfunc_prolog(CType *func_type) -{ - int n = 0; - int i = 0; - Sym *sym; - CType **t; - unsigned long *a; - - // Why doesn't the caller (gen_function) set func_vt? - func_vt = func_type->ref->type; - func_vc = 144; // offset of where x8 is stored - - for (sym = func_type->ref; sym; sym = sym->next) - ++n; - t = tcc_malloc(n * sizeof(*t)); - a = tcc_malloc(n * sizeof(*a)); - - for (sym = func_type->ref; sym; sym = sym->next) - t[i++] = &sym->type; - - arm64_func_va_list_stack = arm64_pcs(n - 1, t, a); - - o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! - o(0xad0087e0); // stp q0,q1,[sp,#16] - o(0xad018fe2); // stp q2,q3,[sp,#48] - o(0xad0297e4); // stp q4,q5,[sp,#80] - o(0xad039fe6); // stp q6,q7,[sp,#112] - o(0xa90923e8); // stp x8,x8,[sp,#144] - o(0xa90a07e0); // stp x0,x1,[sp,#160] - o(0xa90b0fe2); // stp x2,x3,[sp,#176] - o(0xa90c17e4); // stp x4,x5,[sp,#192] - o(0xa90d1fe6); // stp x6,x7,[sp,#208] - - arm64_func_va_list_gr_offs = -64; - arm64_func_va_list_vr_offs = -128; - - for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) { - int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 : - a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 : - 224 + ((a[i] - 32) >> 1 << 1)); - sym_push(sym->v & ~SYM_FIELD, &sym->type, - (a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t), - off); - - if (a[i] < 16) { - int align, size = type_size(&sym->type, &align); - arm64_func_va_list_gr_offs = (a[i] / 2 - 7 + - (!(a[i] & 1) && size > 8)) * 8; - } - else if (a[i] < 32) { - uint32_t hfa = arm64_hfa(&sym->type, 0); - arm64_func_va_list_vr_offs = (a[i] / 2 - 16 + - (hfa ? hfa : 1)) * 16; - } - - // HFAs of float and double need to be written differently: - if (16 <= a[i] && a[i] < 32 && (sym->type.t & VT_BTYPE) == VT_STRUCT) { - uint32_t j, sz, k = arm64_hfa(&sym->type, &sz); - if (sz < 16) - for (j = 0; j < k; j++) { - o(0x3d0003e0 | -(sz & 8) << 27 | (sz & 4) << 29 | - ((a[i] - 16) / 2 + j) | (off / sz + j) << 10); - // str ([sdq])(*),[sp,#(j * sz)] - } - } - } - - tcc_free(a); - tcc_free(t); - - o(0x910003fd); // mov x29,sp - arm64_func_sub_sp_offset = ind; - // In gfunc_epilog these will be replaced with code to decrement SP: - o(0xd503201f); // nop - o(0xd503201f); // nop - loc = 0; -} - -ST_FUNC void gen_va_start(void) -{ - int r; - --vtop; // we don't need the "arg" - gaddrof(); - r = intr(gv(RC_INT)); - - if (arm64_func_va_list_stack) { - //xx could use add (immediate) here - arm64_movimm(30, arm64_func_va_list_stack + 224); - o(0x8b1e03be); // add x30,x29,x30 - } - else - o(0x910383be); // add x30,x29,#224 - o(0xf900001e | r << 5); // str x30,[x(r)] - - if (arm64_func_va_list_gr_offs) { - if (arm64_func_va_list_stack) - o(0x910383be); // add x30,x29,#224 - o(0xf900041e | r << 5); // str x30,[x(r),#8] - } - - if (arm64_func_va_list_vr_offs) { - o(0x910243be); // add x30,x29,#144 - o(0xf900081e | r << 5); // str x30,[x(r),#16] - } - - arm64_movimm(30, arm64_func_va_list_gr_offs); - o(0xb900181e | r << 5); // str w30,[x(r),#24] - - arm64_movimm(30, arm64_func_va_list_vr_offs); - o(0xb9001c1e | r << 5); // str w30,[x(r),#28] - - --vtop; -} - -ST_FUNC void gen_va_arg(CType *t) -{ - int align, size = type_size(t, &align); - int fsize, hfa = arm64_hfa(t, &fsize); - uint32_t r0, r1; - - if (is_float(t->t)) { - hfa = 1; - fsize = size; - } - - gaddrof(); - r0 = intr(gv(RC_INT)); - r1 = get_reg(RC_INT); - vtop[0].r = r1 | lvalue_type(t->t); - r1 = intr(r1); - - if (!hfa) { - uint32_t n = size > 16 ? 8 : (size + 7) & -8; - o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs - if (align == 16) { - assert(0); // this path untested but needed for __uint128_t - o(0x11003fde); // add w30,w30,#15 - o(0x121c6fde); // and w30,w30,#-16 - } - o(0x310003c0 | r1 | n << 10); // adds w(r1),w30,#(n) - o(0x540000ad); // b.le .+20 - o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack - o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n) - o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack - o(0x14000004); // b .+16 - o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs - o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top - o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw - if (size > 16) - o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)] - } - else { - uint32_t rsz = hfa << 4; - uint32_t ssz = (size + 7) & -(uint32_t)8; - uint32_t b1, b2; - o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs - o(0x310003c0 | r1 | rsz << 10); // adds w(r1),w30,#(rsz) - b1 = ind; o(0x5400000d); // b.le lab1 - o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack - if (fsize == 16) { - o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15 - o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16 - } - o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz) - o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack - b2 = ind; o(0x14000000); // b lab2 - // lab1: - write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3); - o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs - o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top - if (hfa == 1 || fsize == 16) - o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw - else { - // We need to change the layout of this HFA. - // Get some space on the stack using global variable "loc": - loc = (loc - size) & -(uint32_t)align; - o(0x8b3ec000 | 30 | r1 << 5); // add x30,x(r1),w30,sxtw - arm64_movimm(r1, loc); - o(0x8b0003a0 | r1 | r1 << 16); // add x(r1),x29,x(r1) - o(0x4c402bdc | (uint32_t)fsize << 7 | - (uint32_t)(hfa == 2) << 15 | - (uint32_t)(hfa == 3) << 14); // ld1 {v28.(4s|2d),...},[x30] - o(0x0d00801c | r1 << 5 | (fsize == 8) << 10 | - (uint32_t)(hfa != 2) << 13 | - (uint32_t)(hfa != 3) << 21); // st(hfa) {v28.(s|d),...}[0],[x(r1)] - } - // lab2: - write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2); - } -} - -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, - int *align, int *regsize) -{ - return 0; -} - -ST_FUNC void gfunc_return(CType *func_type) -{ - CType *t = func_type; - unsigned long a; - - arm64_pcs(0, &t, &a); - switch (a) { - case -1: - break; - case 0: - if ((func_type->t & VT_BTYPE) == VT_STRUCT) { - int align, size = type_size(func_type, &align); - gaddrof(); - gv(RC_R(0)); - arm64_ldrs(0, size); - } - else - gv(RC_IRET); - break; - case 1: { - CType type = *func_type; - mk_pointer(&type); - vset(&type, VT_LOCAL | VT_LVAL, func_vc); - indir(); - vswap(); - vstore(); - break; - } - case 16: - if ((func_type->t & VT_BTYPE) == VT_STRUCT) { - uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz); - gaddrof(); - gv(RC_R(0)); - for (j = 0; j < n; j++) - o(0x3d400000 | - (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | - j | j << 10); // ldr ([sdq])(*),[x0,#(j * sz)] - } - else - gv(RC_FRET); - break; - default: - assert(0); - } - vtop--; -} - -ST_FUNC void gfunc_epilog(void) -{ - if (loc) { - // Insert instructions to subtract size of stack frame from SP. - unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset; - uint64_t diff = (-loc + 15) & ~15; - if (!(diff >> 24)) { - if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff) - write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10); - if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12 - write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10); - } - else { - // In this case we may subtract more than necessary, - // but always less than 17/16 of what we were aiming for. - int i = 0; - int j = 0; - while (diff >> 20) { - diff = (diff + 0xffff) >> 16; - ++i; - } - while (diff >> 16) { - diff = (diff + 1) >> 1; - ++j; - } - write32le(ptr, 0xd2800010 | diff << 5 | i << 21); - // mov x16,#(diff),lsl #(16 * i) - write32le(ptr + 4, 0xcb3063ff | j << 10); - // sub sp,sp,x16,lsl #(j) - } - } - o(0x910003bf); // mov sp,x29 - o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 - - o(0xd65f03c0); // ret -} - -// Generate forward branch to label: -ST_FUNC int gjmp(int t) -{ - int r = ind; - if (nocode_wanted) - return t; - o(t); - return r; -} - -// Generate branch to known address: -ST_FUNC void gjmp_addr(int a) -{ - assert(a - ind + 0x8000000 < 0x10000000); - o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff)); -} - -ST_FUNC int gtst(int inv, int t) -{ - int bt = vtop->type.t & VT_BTYPE; - if (bt == VT_LDOUBLE) { - uint32_t a, b, f = fltr(gv(RC_FLOAT)); - a = get_reg(RC_INT); - vpushi(0); - vtop[0].r = a; - b = get_reg(RC_INT); - a = intr(a); - b = intr(b); - o(0x4e083c00 | a | f << 5); // mov x(a),v(f).d[0] - o(0x4e183c00 | b | f << 5); // mov x(b),v(f).d[1] - o(0xaa000400 | a | a << 5 | b << 16); // orr x(a),x(a),x(b),lsl #1 - o(0xb4000040 | a | !!inv << 24); // cbz/cbnz x(a),.+8 - --vtop; - } - else if (bt == VT_FLOAT || bt == VT_DOUBLE) { - uint32_t a = fltr(gv(RC_FLOAT)); - o(0x1e202008 | a << 5 | (bt != VT_FLOAT) << 22); // fcmp - o(0x54000040 | !!inv); // b.eq/b.ne .+8 - } - else { - uint32_t ll = (bt == VT_PTR || bt == VT_LLONG); - uint32_t a = intr(gv(RC_INT)); - o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8 - } - --vtop; - return gjmp(t); -} - -static int arm64_iconst(uint64_t *val, SValue *sv) -{ - if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) - return 0; - if (val) { - int t = sv->type.t; - int bt = t & VT_BTYPE; - *val = ((bt == VT_LLONG || bt == VT_PTR) ? sv->c.i : - (uint32_t)sv->c.i | - (t & VT_UNSIGNED ? 0 : -(sv->c.i & 0x80000000))); - } - return 1; -} - -static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val, - uint32_t x, uint32_t a) -{ - if (op == '-' && !rev) { - val = -val; - op = '+'; - } - val = l ? val : (uint32_t)val; - - switch (op) { - - case '+': { - uint32_t s = l ? val >> 63 : val >> 31; - val = s ? -val : val; - val = l ? val : (uint32_t)val; - if (!(val & ~(uint64_t)0xfff)) - o(0x11000000 | l << 31 | s << 30 | x | a << 5 | val << 10); - else if (!(val & ~(uint64_t)0xfff000)) - o(0x11400000 | l << 31 | s << 30 | x | a << 5 | val >> 12 << 10); - else { - arm64_movimm(30, val); // use x30 - o(0x0b1e0000 | l << 31 | s << 30 | x | a << 5); - } - return 1; - } - - case '-': - if (!val) - o(0x4b0003e0 | l << 31 | x | a << 16); // neg - else if (val == (l ? (uint64_t)-1 : (uint32_t)-1)) - o(0x2a2003e0 | l << 31 | x | a << 16); // mvn - else { - arm64_movimm(30, val); // use x30 - o(0x4b0003c0 | l << 31 | x | a << 16); // sub - } - return 1; - - case '^': - if (val == -1 || (val == 0xffffffff && !l)) { - o(0x2a2003e0 | l << 31 | x | a << 16); // mvn - return 1; - } - // fall through - case '&': - case '|': { - int e = arm64_encode_bimm64(l ? val : val | val << 32); - if (e < 0) - return 0; - o((op == '&' ? 0x12000000 : - op == '|' ? 0x32000000 : 0x52000000) | - l << 31 | x | a << 5 | (uint32_t)e << 10); - return 1; - } - - case TOK_SAR: - case TOK_SHL: - case TOK_SHR: { - uint32_t n = 32 << l; - val = val & (n - 1); - if (rev) - return 0; - if (!val) - assert(0); - else if (op == TOK_SHL) - o(0x53000000 | l << 31 | l << 22 | x | a << 5 | - (n - val) << 16 | (n - 1 - val) << 10); // lsl - else - o(0x13000000 | (op == TOK_SHR) << 30 | l << 31 | l << 22 | - x | a << 5 | val << 16 | (n - 1) << 10); // lsr/asr - return 1; - } - - } - return 0; -} - -static void arm64_gen_opil(int op, uint32_t l) -{ - uint32_t x, a, b; - - // Special treatment for operations with a constant operand: - { - uint64_t val; - int rev = 1; - - if (arm64_iconst(0, &vtop[0])) { - vswap(); - rev = 0; - } - if (arm64_iconst(&val, &vtop[-1])) { - gv(RC_INT); - a = intr(vtop[0].r); - --vtop; - x = get_reg(RC_INT); - ++vtop; - if (arm64_gen_opic(op, l, rev, val, intr(x), a)) { - vtop[0].r = x; - vswap(); - --vtop; - return; - } - } - if (!rev) - vswap(); - } - - gv2(RC_INT, RC_INT); - assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); - a = intr(vtop[-1].r); - b = intr(vtop[0].r); - vtop -= 2; - x = get_reg(RC_INT); - ++vtop; - vtop[0].r = x; - x = intr(x); - - switch (op) { - case '%': - // Use x30 for quotient: - o(0x1ac00c00 | l << 31 | 30 | a << 5 | b << 16); // sdiv - o(0x1b008000 | l << 31 | x | (uint32_t)30 << 5 | - b << 16 | a << 10); // msub - break; - case '&': - o(0x0a000000 | l << 31 | x | a << 5 | b << 16); // and - break; - case '*': - o(0x1b007c00 | l << 31 | x | a << 5 | b << 16); // mul - break; - case '+': - o(0x0b000000 | l << 31 | x | a << 5 | b << 16); // add - break; - case '-': - o(0x4b000000 | l << 31 | x | a << 5 | b << 16); // sub - break; - case '/': - o(0x1ac00c00 | l << 31 | x | a << 5 | b << 16); // sdiv - break; - case '^': - o(0x4a000000 | l << 31 | x | a << 5 | b << 16); // eor - break; - case '|': - o(0x2a000000 | l << 31 | x | a << 5 | b << 16); // orr - break; - case TOK_EQ: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9f17e0 | x); // cset wA,eq - break; - case TOK_GE: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9fb7e0 | x); // cset wA,ge - break; - case TOK_GT: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9fd7e0 | x); // cset wA,gt - break; - case TOK_LE: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9fc7e0 | x); // cset wA,le - break; - case TOK_LT: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9fa7e0 | x); // cset wA,lt - break; - case TOK_NE: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9f07e0 | x); // cset wA,ne - break; - case TOK_SAR: - o(0x1ac02800 | l << 31 | x | a << 5 | b << 16); // asr - break; - case TOK_SHL: - o(0x1ac02000 | l << 31 | x | a << 5 | b << 16); // lsl - break; - case TOK_SHR: - o(0x1ac02400 | l << 31 | x | a << 5 | b << 16); // lsr - break; - case TOK_UDIV: - case TOK_PDIV: - o(0x1ac00800 | l << 31 | x | a << 5 | b << 16); // udiv - break; - case TOK_UGE: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9f37e0 | x); // cset wA,cs - break; - case TOK_UGT: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9f97e0 | x); // cset wA,hi - break; - case TOK_ULT: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9f27e0 | x); // cset wA,cc - break; - case TOK_ULE: - o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp - o(0x1a9f87e0 | x); // cset wA,ls - break; - case TOK_UMOD: - // Use x30 for quotient: - o(0x1ac00800 | l << 31 | 30 | a << 5 | b << 16); // udiv - o(0x1b008000 | l << 31 | x | (uint32_t)30 << 5 | - b << 16 | a << 10); // msub - break; - default: - assert(0); - } -} - -ST_FUNC void gen_opi(int op) -{ - arm64_gen_opil(op, 0); -} - -ST_FUNC void gen_opl(int op) -{ - arm64_gen_opil(op, 1); -} - -ST_FUNC void gen_opf(int op) -{ - uint32_t x, a, b, dbl; - - if (vtop[0].type.t == VT_LDOUBLE) { - CType type = vtop[0].type; - int func = 0; - int cond = -1; - switch (op) { - case '*': func = TOK___multf3; break; - case '+': func = TOK___addtf3; break; - case '-': func = TOK___subtf3; break; - case '/': func = TOK___divtf3; break; - case TOK_EQ: func = TOK___eqtf2; cond = 1; break; - case TOK_NE: func = TOK___netf2; cond = 0; break; - case TOK_LT: func = TOK___lttf2; cond = 10; break; - case TOK_GE: func = TOK___getf2; cond = 11; break; - case TOK_LE: func = TOK___letf2; cond = 12; break; - case TOK_GT: func = TOK___gttf2; cond = 13; break; - default: assert(0); break; - } - vpush_global_sym(&func_old_type, func); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = cond < 0 ? REG_FRET : REG_IRET; - if (cond < 0) - vtop->type = type; - else { - o(0x7100001f); // cmp w0,#0 - o(0x1a9f07e0 | (uint32_t)cond << 12); // cset w0,(cond) - } - return; - } - - dbl = vtop[0].type.t != VT_FLOAT; - gv2(RC_FLOAT, RC_FLOAT); - assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); - a = fltr(vtop[-1].r); - b = fltr(vtop[0].r); - vtop -= 2; - switch (op) { - case TOK_EQ: case TOK_NE: - case TOK_LT: case TOK_GE: case TOK_LE: case TOK_GT: - x = get_reg(RC_INT); - ++vtop; - vtop[0].r = x; - x = intr(x); - break; - default: - x = get_reg(RC_FLOAT); - ++vtop; - vtop[0].r = x; - x = fltr(x); - break; - } - - switch (op) { - case '*': - o(0x1e200800 | dbl << 22 | x | a << 5 | b << 16); // fmul - break; - case '+': - o(0x1e202800 | dbl << 22 | x | a << 5 | b << 16); // fadd - break; - case '-': - o(0x1e203800 | dbl << 22 | x | a << 5 | b << 16); // fsub - break; - case '/': - o(0x1e201800 | dbl << 22 | x | a << 5 | b << 16); // fdiv - break; - case TOK_EQ: - o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp - o(0x1a9f17e0 | x); // cset w(x),eq - break; - case TOK_GE: - o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp - o(0x1a9fb7e0 | x); // cset w(x),ge - break; - case TOK_GT: - o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp - o(0x1a9fd7e0 | x); // cset w(x),gt - break; - case TOK_LE: - o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp - o(0x1a9f87e0 | x); // cset w(x),ls - break; - case TOK_LT: - o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp - o(0x1a9f57e0 | x); // cset w(x),mi - break; - case TOK_NE: - o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp - o(0x1a9f07e0 | x); // cset w(x),ne - break; - default: - assert(0); - } -} - -// Generate sign extension from 32 to 64 bits: -ST_FUNC void gen_cvt_sxtw(void) -{ - uint32_t r = intr(gv(RC_INT)); - o(0x93407c00 | r | r << 5); // sxtw x(r),w(r) -} - -ST_FUNC void gen_cvt_itof(int t) -{ - if (t == VT_LDOUBLE) { - int f = vtop->type.t; - int func = (f & VT_BTYPE) == VT_LLONG ? - (f & VT_UNSIGNED ? TOK___floatunditf : TOK___floatditf) : - (f & VT_UNSIGNED ? TOK___floatunsitf : TOK___floatsitf); - vpush_global_sym(&func_old_type, func); - vrott(2); - gfunc_call(1); - vpushi(0); - vtop->type.t = t; - vtop->r = REG_FRET; - return; - } - else { - int d, n = intr(gv(RC_INT)); - int s = !(vtop->type.t & VT_UNSIGNED); - uint32_t l = ((vtop->type.t & VT_BTYPE) == VT_LLONG); - --vtop; - d = get_reg(RC_FLOAT); - ++vtop; - vtop[0].r = d; - o(0x1e220000 | (uint32_t)!s << 16 | - (uint32_t)(t != VT_FLOAT) << 22 | fltr(d) | - l << 31 | n << 5); // [us]cvtf [sd](d),[wx](n) - } -} - -ST_FUNC void gen_cvt_ftoi(int t) -{ - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - int func = (t & VT_BTYPE) == VT_LLONG ? - (t & VT_UNSIGNED ? TOK___fixunstfdi : TOK___fixtfdi) : - (t & VT_UNSIGNED ? TOK___fixunstfsi : TOK___fixtfsi); - vpush_global_sym(&func_old_type, func); - vrott(2); - gfunc_call(1); - vpushi(0); - vtop->type.t = t; - vtop->r = REG_IRET; - return; - } - else { - int d, n = fltr(gv(RC_FLOAT)); - uint32_t l = ((vtop->type.t & VT_BTYPE) != VT_FLOAT); - --vtop; - d = get_reg(RC_INT); - ++vtop; - vtop[0].r = d; - o(0x1e380000 | - (uint32_t)!!(t & VT_UNSIGNED) << 16 | - (uint32_t)((t & VT_BTYPE) == VT_LLONG) << 31 | intr(d) | - l << 22 | n << 5); // fcvtz[su] [wx](d),[sd](n) - } -} - -ST_FUNC void gen_cvt_ftof(int t) -{ - int f = vtop[0].type.t; - assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE); - assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE); - if (t == f) - return; - - if (t == VT_LDOUBLE || f == VT_LDOUBLE) { - int func = (t == VT_LDOUBLE) ? - (f == VT_FLOAT ? TOK___extendsftf2 : TOK___extenddftf2) : - (t == VT_FLOAT ? TOK___trunctfsf2 : TOK___trunctfdf2); - vpush_global_sym(&func_old_type, func); - vrott(2); - gfunc_call(1); - vpushi(0); - vtop->type.t = t; - vtop->r = REG_FRET; - } - else { - int x, a; - gv(RC_FLOAT); - assert(vtop[0].r < VT_CONST); - a = fltr(vtop[0].r); - --vtop; - x = get_reg(RC_FLOAT); - ++vtop; - vtop[0].r = x; - x = fltr(x); - - if (f == VT_FLOAT) - o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a) - else - o(0x1e624000 | x | a << 5); // fcvt s(x),d(a) - } -} - -ST_FUNC void ggoto(void) -{ - arm64_gen_bl_or_b(1); - --vtop; -} - -ST_FUNC void gen_clear_cache(void) -{ - uint32_t beg, end, dsz, isz, p, lab1, b1; - gv2(RC_INT, RC_INT); - vpushi(0); - vtop->r = get_reg(RC_INT); - vpushi(0); - vtop->r = get_reg(RC_INT); - vpushi(0); - vtop->r = get_reg(RC_INT); - beg = intr(vtop[-4].r); // x0 - end = intr(vtop[-3].r); // x1 - dsz = intr(vtop[-2].r); // x2 - isz = intr(vtop[-1].r); // x3 - p = intr(vtop[0].r); // x4 - vtop -= 5; - - o(0xd53b0020 | isz); // mrs x(isz),ctr_el0 - o(0x52800080 | p); // mov w(p),#4 - o(0x53104c00 | dsz | isz << 5); // ubfx w(dsz),w(isz),#16,#4 - o(0x1ac02000 | dsz | p << 5 | dsz << 16); // lsl w(dsz),w(p),w(dsz) - o(0x12000c00 | isz | isz << 5); // and w(isz),w(isz),#15 - o(0x1ac02000 | isz | p << 5 | isz << 16); // lsl w(isz),w(p),w(isz) - o(0x51000400 | p | dsz << 5); // sub w(p),w(dsz),#1 - o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p) - b1 = ind; o(0x14000000); // b - lab1 = ind; - o(0xd50b7b20 | p); // dc cvau,x(p) - o(0x8b000000 | p | p << 5 | dsz << 16); // add x(p),x(p),x(dsz) - write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2); - o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end) - o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1 - o(0xd5033b9f); // dsb ish - o(0x51000400 | p | isz << 5); // sub w(p),w(isz),#1 - o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p) - b1 = ind; o(0x14000000); // b - lab1 = ind; - o(0xd50b7520 | p); // ic ivau,x(p) - o(0x8b000000 | p | p << 5 | isz << 16); // add x(p),x(p),x(isz) - write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2); - o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end) - o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1 - o(0xd5033b9f); // dsb ish - o(0xd5033fdf); // isb -} - -ST_FUNC void gen_vla_sp_save(int addr) { - uint32_t r = intr(get_reg(RC_INT)); - o(0x910003e0 | r); // mov x(r),sp - arm64_strx(3, r, 29, addr); -} - -ST_FUNC void gen_vla_sp_restore(int addr) { - // Use x30 because this function can be called when there - // is a live return value in x0 but there is nothing on - // the value stack to prevent get_reg from returning x0. - uint32_t r = 30; - arm64_ldrx(0, 3, r, 29, addr); - o(0x9100001f | r << 5); // mov sp,x(r) -} - -ST_FUNC void gen_vla_alloc(CType *type, int align) { - uint32_t r = intr(gv(RC_INT)); - o(0x91003c00 | r | r << 5); // add x(r),x(r),#15 - o(0x927cec00 | r | r << 5); // bic x(r),x(r),#15 - o(0xcb2063ff | r << 16); // sub sp,sp,x(r) - vpop(); -} - -/* end of A64 code generator */ -/*************************************************************/ -#endif -/*************************************************************/ diff --git a/tinyc/arm64-link.c b/tinyc/arm64-link.c deleted file mode 100644 index 73e503e6b..000000000 --- a/tinyc/arm64-link.c +++ /dev/null @@ -1,250 +0,0 @@ -#ifdef TARGET_DEFS_ONLY - -#define EM_TCC_TARGET EM_AARCH64 - -#define R_DATA_32 R_AARCH64_ABS32 -#define R_DATA_PTR R_AARCH64_ABS64 -#define R_JMP_SLOT R_AARCH64_JUMP_SLOT -#define R_GLOB_DAT R_AARCH64_GLOB_DAT -#define R_COPY R_AARCH64_COPY -#define R_RELATIVE R_AARCH64_RELATIVE - -#define R_NUM R_AARCH64_NUM - -#define ELF_START_ADDR 0x00400000 -#define ELF_PAGE_SIZE 0x1000 - -#define PCRELATIVE_DLLPLT 1 -#define RELOCATE_DLLPLT 1 - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -/* Returns 1 for a code relocation, 0 for a data relocation. For unknown - relocations, returns -1. */ -int code_reloc (int reloc_type) -{ - switch (reloc_type) { - case R_AARCH64_ABS32: - case R_AARCH64_ABS64: - case R_AARCH64_PREL32: - case R_AARCH64_MOVW_UABS_G0_NC: - case R_AARCH64_MOVW_UABS_G1_NC: - case R_AARCH64_MOVW_UABS_G2_NC: - case R_AARCH64_MOVW_UABS_G3: - case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_GLOB_DAT: - case R_AARCH64_COPY: - return 0; - - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: - case R_AARCH64_JUMP_SLOT: - return 1; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -/* Returns an enumerator to describe whether and when the relocation needs a - GOT and/or PLT entry to be created. See tcc.h for a description of the - different values. */ -int gotplt_entry_type (int reloc_type) -{ - switch (reloc_type) { - case R_AARCH64_PREL32: - case R_AARCH64_MOVW_UABS_G0_NC: - case R_AARCH64_MOVW_UABS_G1_NC: - case R_AARCH64_MOVW_UABS_G2_NC: - case R_AARCH64_MOVW_UABS_G3: - case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_GLOB_DAT: - case R_AARCH64_JUMP_SLOT: - case R_AARCH64_COPY: - return NO_GOTPLT_ENTRY; - - case R_AARCH64_ABS32: - case R_AARCH64_ABS64: - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: - return AUTO_GOTPLT_ENTRY; - - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_LD64_GOT_LO12_NC: - return ALWAYS_GOTPLT_ENTRY; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) -{ - Section *plt = s1->plt; - uint8_t *p; - unsigned plt_offset; - - if (s1->output_type == TCC_OUTPUT_DLL) - tcc_error("DLLs unimplemented!"); - - if (plt->data_offset == 0) { - section_ptr_add(plt, 32); - } - plt_offset = plt->data_offset; - - p = section_ptr_add(plt, 16); - write32le(p, got_offset); - write32le(p + 4, (uint64_t) got_offset >> 32); - return plt_offset; -} - -/* relocate the PLT: compute addresses and offsets in the PLT now that final - address for PLT and GOT are known (see fill_program_header) */ -ST_FUNC void relocate_plt(TCCState *s1) -{ - uint8_t *p, *p_end; - - if (!s1->plt) - return; - - p = s1->plt->data; - p_end = p + s1->plt->data_offset; - - if (p < p_end) { - uint64_t plt = s1->plt->sh_addr; - uint64_t got = s1->got->sh_addr; - uint64_t off = (got >> 12) - (plt >> 12); - if ((off + ((uint32_t)1 << 20)) >> 21) - tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); - write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! - write32le(p + 4, (0x90000010 | // adrp x16,... - (off & 0x1ffffc) << 3 | (off & 3) << 29)); - write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...] - (got & 0xff8) << 7)); - write32le(p + 12, (0x91000210 | // add x16,x16,#... - (got & 0xfff) << 10)); - write32le(p + 16, 0xd61f0220); // br x17 - write32le(p + 20, 0xd503201f); // nop - write32le(p + 24, 0xd503201f); // nop - write32le(p + 28, 0xd503201f); // nop - p += 32; - while (p < p_end) { - uint64_t pc = plt + (p - s1->plt->data); - uint64_t addr = got + read64le(p); - uint64_t off = (addr >> 12) - (pc >> 12); - if ((off + ((uint32_t)1 << 20)) >> 21) - tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); - write32le(p, (0x90000010 | // adrp x16,... - (off & 0x1ffffc) << 3 | (off & 3) << 29)); - write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...] - (addr & 0xff8) << 7)); - write32le(p + 8, (0x91000210 | // add x16,x16,#... - (addr & 0xfff) << 10)); - write32le(p + 12, 0xd61f0220); // br x17 - p += 16; - } - } -} - -void relocate_init(Section *sr) {} - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) -{ - int sym_index = ELFW(R_SYM)(rel->r_info); -#ifdef DEBUG_RELOC - ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; -#endif - - switch(type) { - case R_AARCH64_ABS64: - write64le(ptr, val); - return; - case R_AARCH64_ABS32: - write32le(ptr, val); - return; - case R_AARCH64_PREL32: - write32le(ptr, val - addr); - return; - case R_AARCH64_MOVW_UABS_G0_NC: - write32le(ptr, ((read32le(ptr) & 0xffe0001f) | - (val & 0xffff) << 5)); - return; - case R_AARCH64_MOVW_UABS_G1_NC: - write32le(ptr, ((read32le(ptr) & 0xffe0001f) | - (val >> 16 & 0xffff) << 5)); - return; - case R_AARCH64_MOVW_UABS_G2_NC: - write32le(ptr, ((read32le(ptr) & 0xffe0001f) | - (val >> 32 & 0xffff) << 5)); - return; - case R_AARCH64_MOVW_UABS_G3: - write32le(ptr, ((read32le(ptr) & 0xffe0001f) | - (val >> 48 & 0xffff) << 5)); - return; - case R_AARCH64_ADR_PREL_PG_HI21: { - uint64_t off = (val >> 12) - (addr >> 12); - if ((off + ((uint64_t)1 << 20)) >> 21) - tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); - write32le(ptr, ((read32le(ptr) & 0x9f00001f) | - (off & 0x1ffffc) << 3 | (off & 3) << 29)); - return; - } - case R_AARCH64_ADD_ABS_LO12_NC: - write32le(ptr, ((read32le(ptr) & 0xffc003ff) | - (val & 0xfff) << 10)); - return; - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: -#ifdef DEBUG_RELOC - printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, - (char *) symtab_section->link->data + sym->st_name); -#endif - if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) - tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed" - " (val=%lx, addr=%lx)", val, addr); - write32le(ptr, (0x14000000 | - (uint32_t)(type == R_AARCH64_CALL26) << 31 | - ((val - addr) >> 2 & 0x3ffffff))); - return; - case R_AARCH64_ADR_GOT_PAGE: { - uint64_t off = - (((s1->got->sh_addr + - s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); - if ((off + ((uint64_t)1 << 20)) >> 21) - tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); - write32le(ptr, ((read32le(ptr) & 0x9f00001f) | - (off & 0x1ffffc) << 3 | (off & 3) << 29)); - return; - } - case R_AARCH64_LD64_GOT_LO12_NC: - write32le(ptr, - ((read32le(ptr) & 0xfff803ff) | - ((s1->got->sh_addr + - s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7)); - return; - case R_AARCH64_COPY: - return; - case R_AARCH64_GLOB_DAT: - case R_AARCH64_JUMP_SLOT: - /* They don't need addend */ -#ifdef DEBUG_RELOC - printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, - val - rel->r_addend, - (char *) symtab_section->link->data + sym->st_name); -#endif - write64le(ptr, val - rel->r_addend); - return; - default: - fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", - type, (unsigned)addr, ptr, (unsigned)val); - return; - } -} - -#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/c67-gen.c b/tinyc/c67-gen.c deleted file mode 100644 index bcb4b0e3e..000000000 --- a/tinyc/c67-gen.c +++ /dev/null @@ -1,2540 +0,0 @@ -/* - * TMS320C67xx code generator for TCC - * - * Copyright (c) 2001, 2002 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef TARGET_DEFS_ONLY - -/* #define ASSEMBLY_LISTING_C67 */ - -/* number of available registers */ -#define NB_REGS 24 - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_EAX 0x0004 -#define RC_ST0 0x0008 -#define RC_ECX 0x0010 -#define RC_EDX 0x0020 -#define RC_INT_BSIDE 0x00000040 /* generic integer register on b side */ -#define RC_C67_A4 0x00000100 -#define RC_C67_A5 0x00000200 -#define RC_C67_B4 0x00000400 -#define RC_C67_B5 0x00000800 -#define RC_C67_A6 0x00001000 -#define RC_C67_A7 0x00002000 -#define RC_C67_B6 0x00004000 -#define RC_C67_B7 0x00008000 -#define RC_C67_A8 0x00010000 -#define RC_C67_A9 0x00020000 -#define RC_C67_B8 0x00040000 -#define RC_C67_B9 0x00080000 -#define RC_C67_A10 0x00100000 -#define RC_C67_A11 0x00200000 -#define RC_C67_B10 0x00400000 -#define RC_C67_B11 0x00800000 -#define RC_C67_A12 0x01000000 -#define RC_C67_A13 0x02000000 -#define RC_C67_B12 0x04000000 -#define RC_C67_B13 0x08000000 -#define RC_IRET RC_C67_A4 /* function return: integer register */ -#define RC_LRET RC_C67_A5 /* function return: second integer register */ -#define RC_FRET RC_C67_A4 /* function return: float register */ - -/* pretty names for the registers */ -enum { - TREG_EAX = 0, // really A2 - TREG_ECX, // really A3 - TREG_EDX, // really B0 - TREG_ST0, // really B1 - TREG_C67_A4, - TREG_C67_A5, - TREG_C67_B4, - TREG_C67_B5, - TREG_C67_A6, - TREG_C67_A7, - TREG_C67_B6, - TREG_C67_B7, - TREG_C67_A8, - TREG_C67_A9, - TREG_C67_B8, - TREG_C67_B9, - TREG_C67_A10, - TREG_C67_A11, - TREG_C67_B10, - TREG_C67_B11, - TREG_C67_A12, - TREG_C67_A13, - TREG_C67_B12, - TREG_C67_B13, -}; - -/* return registers for function */ -#define REG_IRET TREG_C67_A4 /* single word int return register */ -#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */ -#define REG_FRET TREG_C67_A4 /* float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -/* #define INVERT_FUNC_PARAMS */ - -/* defined if structures are passed as pointers. Otherwise structures - are directly pushed on stack. */ -/* #define FUNC_STRUCT_PARAM_AS_PTR */ - -/* pointer size, in bytes */ -#define PTR_SIZE 4 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 12 -#define LDOUBLE_ALIGN 4 -/* maximum alignment (for aligned attribute support) */ -#define MAX_ALIGN 8 - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#include "tcc.h" - -ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_FLOAT | RC_EAX, - // only allow even regs for floats (allow for doubles) - /* ecx */ RC_INT | RC_ECX, - /* edx */ RC_INT | RC_INT_BSIDE | RC_FLOAT | RC_EDX, - // only allow even regs for floats (allow for doubles) - /* st0 */ RC_INT | RC_INT_BSIDE | RC_ST0, - /* A4 */ RC_C67_A4, - /* A5 */ RC_C67_A5, - /* B4 */ RC_C67_B4, - /* B5 */ RC_C67_B5, - /* A6 */ RC_C67_A6, - /* A7 */ RC_C67_A7, - /* B6 */ RC_C67_B6, - /* B7 */ RC_C67_B7, - /* A8 */ RC_C67_A8, - /* A9 */ RC_C67_A9, - /* B8 */ RC_C67_B8, - /* B9 */ RC_C67_B9, - /* A10 */ RC_C67_A10, - /* A11 */ RC_C67_A11, - /* B10 */ RC_C67_B10, - /* B11 */ RC_C67_B11, - /* A12 */ RC_C67_A10, - /* A13 */ RC_C67_A11, - /* B12 */ RC_C67_B10, - /* B13 */ RC_C67_B11 -}; - -// although tcc thinks it is passing parameters on the stack, -// the C67 really passes up to the first 10 params in special -// regs or regs pairs (for 64 bit params). So keep track of -// the stack offsets so we can translate to the appropriate -// reg (pair) - -#define NoCallArgsPassedOnStack 10 -int NoOfCurFuncArgs; -int TranslateStackToReg[NoCallArgsPassedOnStack]; -int ParamLocOnStack[NoCallArgsPassedOnStack]; -int TotalBytesPushedOnStack; - -#ifndef FALSE -# define FALSE 0 -# define TRUE 1 -#endif - -#undef BOOL -#define BOOL int - -#define ALWAYS_ASSERT(x) \ -do {\ - if (!(x))\ - tcc_error("internal compiler error file at %s:%d", __FILE__, __LINE__);\ -} while (0) - -/******************************************************/ -static unsigned long func_sub_sp_offset; -static int func_ret_sub; - -static BOOL C67_invert_test; -static int C67_compare_reg; - -#ifdef ASSEMBLY_LISTING_C67 -FILE *f = NULL; -#endif - -void C67_g(int c) -{ - int ind1; - if (nocode_wanted) - return; -#ifdef ASSEMBLY_LISTING_C67 - fprintf(f, " %08X", c); -#endif - ind1 = ind + 4; - if (ind1 > (int) cur_text_section->data_allocated) - section_realloc(cur_text_section, ind1); - cur_text_section->data[ind] = c & 0xff; - cur_text_section->data[ind + 1] = (c >> 8) & 0xff; - cur_text_section->data[ind + 2] = (c >> 16) & 0xff; - cur_text_section->data[ind + 3] = (c >> 24) & 0xff; - ind = ind1; -} - - -/* output a symbol and patch all calls to it */ -void gsym_addr(int t, int a) -{ - int n, *ptr; - while (t) { - ptr = (int *) (cur_text_section->data + t); - { - Sym *sym; - - // extract 32 bit address from MVKH/MVKL - n = ((*ptr >> 7) & 0xffff); - n |= ((*(ptr + 1) >> 7) & 0xffff) << 16; - - // define a label that will be relocated - - sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0); - greloc(cur_text_section, sym, t, R_C60LO16); - greloc(cur_text_section, sym, t + 4, R_C60HI16); - - // clear out where the pointer was - - *ptr &= ~(0xffff << 7); - *(ptr + 1) &= ~(0xffff << 7); - } - t = n; - } -} - -void gsym(int t) -{ - gsym_addr(t, ind); -} - -// these are regs that tcc doesn't really know about, -// but assign them unique values so the mapping routines -// can distinguish them - -#define C67_A0 105 -#define C67_SP 106 -#define C67_B3 107 -#define C67_FP 108 -#define C67_B2 109 -#define C67_CREG_ZERO -1 /* Special code for no condition reg test */ - - -int ConvertRegToRegClass(int r) -{ - // only works for A4-B13 - - return RC_C67_A4 << (r - TREG_C67_A4); -} - - -// map TCC reg to C67 reg number - -int C67_map_regn(int r) -{ - if (r == 0) // normal tcc regs - return 0x2; // A2 - else if (r == 1) // normal tcc regs - return 3; // A3 - else if (r == 2) // normal tcc regs - return 0; // B0 - else if (r == 3) // normal tcc regs - return 1; // B1 - else if (r >= TREG_C67_A4 && r <= TREG_C67_B13) // these form a pattern of alt pairs - return (((r & 0xfffffffc) >> 1) | (r & 1)) + 2; - else if (r == C67_A0) - return 0; // set to A0 (offset reg) - else if (r == C67_B2) - return 2; // set to B2 (offset reg) - else if (r == C67_B3) - return 3; // set to B3 (return address reg) - else if (r == C67_SP) - return 15; // set to SP (B15) (offset reg) - else if (r == C67_FP) - return 15; // set to FP (A15) (offset reg) - else if (r == C67_CREG_ZERO) - return 0; // Special code for no condition reg test - else - ALWAYS_ASSERT(FALSE); - - return 0; -} - -// mapping from tcc reg number to -// C67 register to condition code field -// -// valid condition code regs are: -// -// tcc reg 2 ->B0 -> 1 -// tcc reg 3 ->B1 -> 2 -// tcc reg 0 -> A2 -> 5 -// tcc reg 1 -> A3 -> X -// tcc reg B2 -> 3 - -int C67_map_regc(int r) -{ - if (r == 0) // normal tcc regs - return 0x5; - else if (r == 2) // normal tcc regs - return 0x1; - else if (r == 3) // normal tcc regs - return 0x2; - else if (r == C67_B2) // normal tcc regs - return 0x3; - else if (r == C67_CREG_ZERO) - return 0; // Special code for no condition reg test - else - ALWAYS_ASSERT(FALSE); - - return 0; -} - - -// map TCC reg to C67 reg side A or B - -int C67_map_regs(int r) -{ - if (r == 0) // normal tcc regs - return 0x0; - else if (r == 1) // normal tcc regs - return 0x0; - else if (r == 2) // normal tcc regs - return 0x1; - else if (r == 3) // normal tcc regs - return 0x1; - else if (r >= TREG_C67_A4 && r <= TREG_C67_B13) // these form a pattern of alt pairs - return (r & 2) >> 1; - else if (r == C67_A0) - return 0; // set to A side - else if (r == C67_B2) - return 1; // set to B side - else if (r == C67_B3) - return 1; // set to B side - else if (r == C67_SP) - return 0x1; // set to SP (B15) B side - else if (r == C67_FP) - return 0x0; // set to FP (A15) A side - else - ALWAYS_ASSERT(FALSE); - - return 0; -} - -int C67_map_S12(char *s) -{ - if (strstr(s, ".S1") != NULL) - return 0; - else if (strcmp(s, ".S2")) - return 1; - else - ALWAYS_ASSERT(FALSE); - - return 0; -} - -int C67_map_D12(char *s) -{ - if (strstr(s, ".D1") != NULL) - return 0; - else if (strcmp(s, ".D2")) - return 1; - else - ALWAYS_ASSERT(FALSE); - - return 0; -} - - - -void C67_asm(char *s, int a, int b, int c) -{ - BOOL xpath; - -#ifdef ASSEMBLY_LISTING_C67 - if (!f) { - f = fopen("TCC67_out.txt", "wt"); - } - fprintf(f, "%04X ", ind); -#endif - - if (strstr(s, "MVKL") == s) { - C67_g((C67_map_regn(b) << 23) | - ((a & 0xffff) << 7) | (0x0a << 2) | (C67_map_regs(b) << 1)); - } else if (strstr(s, "MVKH") == s) { - C67_g((C67_map_regn(b) << 23) | - (((a >> 16) & 0xffff) << 7) | - (0x1a << 2) | (C67_map_regs(b) << 1)); - } else if (strstr(s, "STW.D SP POST DEC") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (15 << 18) | //SP B15 - (2 << 13) | //ucst5 (must keep 8 byte boundary !!) - (0xa << 9) | //mode a = post dec ucst - (0 << 8) | //r (LDDW bit 0) - (1 << 7) | //y D1/D2 use B side - (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STB.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STH.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STB.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STH.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STW.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STW.D *") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (C67_map_regn(b) << 18) | //base reg A0 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(b) << 7) | //y D1/D2 base reg side - (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STH.D *") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (C67_map_regn(b) << 18) | //base reg A0 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(b) << 7) | //y D1/D2 base reg side - (5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STB.D *") == s) { - C67_g((C67_map_regn(a) << 23) | //src - (C67_map_regn(b) << 18) | //base reg A0 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(b) << 7) | //y D1/D2 base reg side - (3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "STW.D +*") == s) { - ALWAYS_ASSERT(c < 32); - C67_g((C67_map_regn(a) << 23) | //src - (C67_map_regn(b) << 18) | //base reg A0 - (c << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(b) << 7) | //y D1/D2 base reg side - (7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of src - (0 << 0)); //parallel - } else if (strstr(s, "LDW.D SP PRE INC") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg B15 - (2 << 13) | //ucst5 (must keep 8 byte boundary) - (9 << 9) | //mode 9 = pre inc ucst5 - (0 << 8) | //r (LDDW bit 0) - (1 << 7) | //y D1/D2 B side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDDW.D SP PRE INC") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg B15 - (1 << 13) | //ucst5 (must keep 8 byte boundary) - (9 << 9) | //mode 9 = pre inc ucst5 - (1 << 8) | //r (LDDW bit 1) - (1 << 7) | //y D1/D2 B side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDW.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDDW.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (1 << 8) | //r (LDDW bit 1) - (0 << 7) | //y D1/D2 A side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDH.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDB.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDHU.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDBU.D *+SP[A0]") == s) { - C67_g((C67_map_regn(a) << 23) | //dst - (15 << 18) | //base reg A15 - (0 << 13) | //offset reg A0 - (5 << 9) | //mode 5 = pos offset, base reg + off reg - (0 << 8) | //r (LDDW bit 0) - (0 << 7) | //y D1/D2 A side - (1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(a) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDW.D *") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDDW.D *") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (1 << 8) | //r (LDDW bit 1) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDH.D *") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDB.D *") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDHU.D *") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDBU.D *") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (0 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "LDW.D +*") == s) { - C67_g((C67_map_regn(b) << 23) | //dst - (C67_map_regn(a) << 18) | //base reg A15 - (1 << 13) | //cst5 - (1 << 9) | //mode 1 = pos cst offset - (0 << 8) | //r (LDDW bit 0) - (C67_map_regs(a) << 7) | //y D1/D2 src side - (6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU - (1 << 2) | //opcode - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "CMPLTSP") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x3a << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPGTSP") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x39 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPEQSP") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x38 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } - - else if (strstr(s, "CMPLTDP") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x2a << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPGTDP") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x29 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPEQDP") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x28 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPLT") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x57 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPGT") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x47 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPEQ") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x53 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPLTU") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x5f << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "CMPGTU") == s) { - xpath = C67_map_regs(a) ^ C67_map_regs(b); - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x use cross path for src2 - (0x4f << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side for reg c - (0 << 0)); //parallel - } else if (strstr(s, "B DISP") == s) { - C67_g((0 << 29) | //creg - (0 << 28) | //z - (a << 7) | //cnst - (0x4 << 2) | //opcode fixed - (0 << 1) | //S0/S1 - (0 << 0)); //parallel - } else if (strstr(s, "B.") == s) { - xpath = C67_map_regs(c) ^ 1; - - C67_g((C67_map_regc(b) << 29) | //creg - (a << 28) | //inv - (0 << 23) | //dst - (C67_map_regn(c) << 18) | //src2 - (0 << 13) | // - (xpath << 12) | //x cross path if !B side - (0xd << 6) | //opcode - (0x8 << 2) | //opcode fixed - (1 << 1) | //must be S2 - (0 << 0)); //parallel - } else if (strstr(s, "MV.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (0 << 13) | //src1 (cst5) - (xpath << 12) | //x cross path if opposite sides - (0x2 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SPTRUNC.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0xb << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "DPTRUNC.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - ((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0x1 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "INTSP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0x4a << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "INTSPU.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0x49 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "INTDP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0x39 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "INTDPU.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - ((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0x3b << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SPDP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (0 << 13) | //src1 NA - (xpath << 12) | //x cross path if opposite sides - (0x2 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "DPSP.L") == s) { - ALWAYS_ASSERT(C67_map_regs(b) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - ((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason - (0 << 13) | //src1 NA - (0 << 12) | //x cross path if opposite sides - (0x9 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "ADD.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x3 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SUB.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x7 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "OR.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x7f << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "AND.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x7b << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "XOR.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x6f << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "ADDSP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x10 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "ADDDP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x18 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SUBSP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x11 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SUBDP.L") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x19 << 5) | //opcode - (0x6 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "MPYSP.M") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x1c << 7) | //opcode - (0x0 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "MPYDP.M") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 (possible x path) - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x0e << 7) | //opcode - (0x0 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "MPYI.M") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 (cst5) - (xpath << 12) | //x cross path if opposite sides - (0x4 << 7) | //opcode - (0x0 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SHR.S") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x37 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SHRU.S") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x27 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "SHL.S") == s) { - xpath = C67_map_regs(b) ^ C67_map_regs(c); - - ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a)); - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(c) << 23) | //dst - (C67_map_regn(b) << 18) | //src2 - (C67_map_regn(a) << 13) | //src1 - (xpath << 12) | //x cross path if opposite sides - (0x33 << 6) | //opcode - (0x8 << 2) | //opcode fixed - (C67_map_regs(c) << 1) | //side of dest - (0 << 0)); //parallel - } else if (strstr(s, "||ADDK") == s) { - xpath = 0; // no xpath required just use the side of the src/dst - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(b) << 23) | //dst - (a << 07) | //scst16 - (0x14 << 2) | //opcode fixed - (C67_map_regs(b) << 1) | //side of dst - (1 << 0)); //parallel - } else if (strstr(s, "ADDK") == s) { - xpath = 0; // no xpath required just use the side of the src/dst - - C67_g((0 << 29) | //creg - (0 << 28) | //inv - (C67_map_regn(b) << 23) | //dst - (a << 07) | //scst16 - (0x14 << 2) | //opcode fixed - (C67_map_regs(b) << 1) | //side of dst - (0 << 0)); //parallel - } else if (strstr(s, "NOP") == s) { - C67_g(((a - 1) << 13) | //no of cycles - (0 << 0)); //parallel - } else - ALWAYS_ASSERT(FALSE); - -#ifdef ASSEMBLY_LISTING_C67 - fprintf(f, " %s %d %d %d\n", s, a, b, c); -#endif - -} - -//r=reg to load, fr=from reg, symbol for relocation, constant - -void C67_MVKL(int r, int fc) -{ - C67_asm("MVKL.", fc, r, 0); -} - -void C67_MVKH(int r, int fc) -{ - C67_asm("MVKH.", fc, r, 0); -} - -void C67_STB_SP_A0(int r) -{ - C67_asm("STB.D *+SP[A0]", r, 0, 0); // STB r,*+SP[A0] -} - -void C67_STH_SP_A0(int r) -{ - C67_asm("STH.D *+SP[A0]", r, 0, 0); // STH r,*+SP[A0] -} - -void C67_STW_SP_A0(int r) -{ - C67_asm("STW.D *+SP[A0]", r, 0, 0); // STW r,*+SP[A0] -} - -void C67_STB_PTR(int r, int r2) -{ - C67_asm("STB.D *", r, r2, 0); // STB r, *r2 -} - -void C67_STH_PTR(int r, int r2) -{ - C67_asm("STH.D *", r, r2, 0); // STH r, *r2 -} - -void C67_STW_PTR(int r, int r2) -{ - C67_asm("STW.D *", r, r2, 0); // STW r, *r2 -} - -void C67_STW_PTR_PRE_INC(int r, int r2, int n) -{ - C67_asm("STW.D +*", r, r2, n); // STW r, *+r2 -} - -void C67_PUSH(int r) -{ - C67_asm("STW.D SP POST DEC", r, 0, 0); // STW r,*SP-- -} - -void C67_LDW_SP_A0(int r) -{ - C67_asm("LDW.D *+SP[A0]", r, 0, 0); // LDW *+SP[A0],r -} - -void C67_LDDW_SP_A0(int r) -{ - C67_asm("LDDW.D *+SP[A0]", r, 0, 0); // LDDW *+SP[A0],r -} - -void C67_LDH_SP_A0(int r) -{ - C67_asm("LDH.D *+SP[A0]", r, 0, 0); // LDH *+SP[A0],r -} - -void C67_LDB_SP_A0(int r) -{ - C67_asm("LDB.D *+SP[A0]", r, 0, 0); // LDB *+SP[A0],r -} - -void C67_LDHU_SP_A0(int r) -{ - C67_asm("LDHU.D *+SP[A0]", r, 0, 0); // LDHU *+SP[A0],r -} - -void C67_LDBU_SP_A0(int r) -{ - C67_asm("LDBU.D *+SP[A0]", r, 0, 0); // LDBU *+SP[A0],r -} - -void C67_LDW_PTR(int r, int r2) -{ - C67_asm("LDW.D *", r, r2, 0); // LDW *r,r2 -} - -void C67_LDDW_PTR(int r, int r2) -{ - C67_asm("LDDW.D *", r, r2, 0); // LDDW *r,r2 -} - -void C67_LDH_PTR(int r, int r2) -{ - C67_asm("LDH.D *", r, r2, 0); // LDH *r,r2 -} - -void C67_LDB_PTR(int r, int r2) -{ - C67_asm("LDB.D *", r, r2, 0); // LDB *r,r2 -} - -void C67_LDHU_PTR(int r, int r2) -{ - C67_asm("LDHU.D *", r, r2, 0); // LDHU *r,r2 -} - -void C67_LDBU_PTR(int r, int r2) -{ - C67_asm("LDBU.D *", r, r2, 0); // LDBU *r,r2 -} - -void C67_LDW_PTR_PRE_INC(int r, int r2) -{ - C67_asm("LDW.D +*", r, r2, 0); // LDW *+r,r2 -} - -void C67_POP(int r) -{ - C67_asm("LDW.D SP PRE INC", r, 0, 0); // LDW *++SP,r -} - -void C67_POP_DW(int r) -{ - C67_asm("LDDW.D SP PRE INC", r, 0, 0); // LDDW *++SP,r -} - -void C67_CMPLT(int s1, int s2, int dst) -{ - C67_asm("CMPLT.L1", s1, s2, dst); -} - -void C67_CMPGT(int s1, int s2, int dst) -{ - C67_asm("CMPGT.L1", s1, s2, dst); -} - -void C67_CMPEQ(int s1, int s2, int dst) -{ - C67_asm("CMPEQ.L1", s1, s2, dst); -} - -void C67_CMPLTU(int s1, int s2, int dst) -{ - C67_asm("CMPLTU.L1", s1, s2, dst); -} - -void C67_CMPGTU(int s1, int s2, int dst) -{ - C67_asm("CMPGTU.L1", s1, s2, dst); -} - - -void C67_CMPLTSP(int s1, int s2, int dst) -{ - C67_asm("CMPLTSP.S1", s1, s2, dst); -} - -void C67_CMPGTSP(int s1, int s2, int dst) -{ - C67_asm("CMPGTSP.S1", s1, s2, dst); -} - -void C67_CMPEQSP(int s1, int s2, int dst) -{ - C67_asm("CMPEQSP.S1", s1, s2, dst); -} - -void C67_CMPLTDP(int s1, int s2, int dst) -{ - C67_asm("CMPLTDP.S1", s1, s2, dst); -} - -void C67_CMPGTDP(int s1, int s2, int dst) -{ - C67_asm("CMPGTDP.S1", s1, s2, dst); -} - -void C67_CMPEQDP(int s1, int s2, int dst) -{ - C67_asm("CMPEQDP.S1", s1, s2, dst); -} - - -void C67_IREG_B_REG(int inv, int r1, int r2) // [!R] B r2 -{ - C67_asm("B.S2", inv, r1, r2); -} - - -// call with how many 32 bit words to skip -// (0 would branch to the branch instruction) - -void C67_B_DISP(int disp) // B +2 Branch with constant displacement -{ - // Branch point is relative to the 8 word fetch packet - // - // we will assume the text section always starts on an 8 word (32 byte boundary) - // - // so add in how many words into the fetch packet the branch is - - - C67_asm("B DISP", disp + ((ind & 31) >> 2), 0, 0); -} - -void C67_NOP(int n) -{ - C67_asm("NOP", n, 0, 0); -} - -void C67_ADDK(int n, int r) -{ - ALWAYS_ASSERT(abs(n) < 32767); - - C67_asm("ADDK", n, r, 0); -} - -void C67_ADDK_PARALLEL(int n, int r) -{ - ALWAYS_ASSERT(abs(n) < 32767); - - C67_asm("||ADDK", n, r, 0); -} - -void C67_Adjust_ADDK(int *inst, int n) -{ - ALWAYS_ASSERT(abs(n) < 32767); - - *inst = (*inst & (~(0xffff << 7))) | ((n & 0xffff) << 7); -} - -void C67_MV(int r, int v) -{ - C67_asm("MV.L", 0, r, v); -} - - -void C67_DPTRUNC(int r, int v) -{ - C67_asm("DPTRUNC.L", 0, r, v); -} - -void C67_SPTRUNC(int r, int v) -{ - C67_asm("SPTRUNC.L", 0, r, v); -} - -void C67_INTSP(int r, int v) -{ - C67_asm("INTSP.L", 0, r, v); -} - -void C67_INTDP(int r, int v) -{ - C67_asm("INTDP.L", 0, r, v); -} - -void C67_INTSPU(int r, int v) -{ - C67_asm("INTSPU.L", 0, r, v); -} - -void C67_INTDPU(int r, int v) -{ - C67_asm("INTDPU.L", 0, r, v); -} - -void C67_SPDP(int r, int v) -{ - C67_asm("SPDP.L", 0, r, v); -} - -void C67_DPSP(int r, int v) // note regs must be on the same side -{ - C67_asm("DPSP.L", 0, r, v); -} - -void C67_ADD(int r, int v) -{ - C67_asm("ADD.L", v, r, v); -} - -void C67_SUB(int r, int v) -{ - C67_asm("SUB.L", v, r, v); -} - -void C67_AND(int r, int v) -{ - C67_asm("AND.L", v, r, v); -} - -void C67_OR(int r, int v) -{ - C67_asm("OR.L", v, r, v); -} - -void C67_XOR(int r, int v) -{ - C67_asm("XOR.L", v, r, v); -} - -void C67_ADDSP(int r, int v) -{ - C67_asm("ADDSP.L", v, r, v); -} - -void C67_SUBSP(int r, int v) -{ - C67_asm("SUBSP.L", v, r, v); -} - -void C67_MPYSP(int r, int v) -{ - C67_asm("MPYSP.M", v, r, v); -} - -void C67_ADDDP(int r, int v) -{ - C67_asm("ADDDP.L", v, r, v); -} - -void C67_SUBDP(int r, int v) -{ - C67_asm("SUBDP.L", v, r, v); -} - -void C67_MPYDP(int r, int v) -{ - C67_asm("MPYDP.M", v, r, v); -} - -void C67_MPYI(int r, int v) -{ - C67_asm("MPYI.M", v, r, v); -} - -void C67_SHL(int r, int v) -{ - C67_asm("SHL.S", r, v, v); -} - -void C67_SHRU(int r, int v) -{ - C67_asm("SHRU.S", r, v, v); -} - -void C67_SHR(int r, int v) -{ - C67_asm("SHR.S", r, v, v); -} - - - -/* load 'r' from value 'sv' */ -void load(int r, SValue * sv) -{ - int v, t, ft, fc, fr, size = 0, element; - BOOL Unsigned = FALSE; - SValue v1; - - fr = sv->r; - ft = sv->type.t; - fc = sv->c.i; - - v = fr & VT_VALMASK; - if (fr & VT_LVAL) { - if (v == VT_LLOCAL) { - v1.type.t = VT_INT; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - load(r, &v1); - fr = r; - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - tcc_error("long double not supported"); - } else if ((ft & VT_TYPE) == VT_BYTE) { - size = 1; - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { - size = 1; - Unsigned = TRUE; - } else if ((ft & VT_TYPE) == VT_SHORT) { - size = 2; - } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { - size = 2; - Unsigned = TRUE; - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - size = 8; - } else { - size = 4; - } - - // check if fc is a positive reference on the stack, - // if it is tcc is referencing what it thinks is a parameter - // on the stack, so check if it is really in a register. - - - if (v == VT_LOCAL && fc > 0) { - int stack_pos = 8; - - for (t = 0; t < NoCallArgsPassedOnStack; t++) { - if (fc == stack_pos) - break; - - stack_pos += TranslateStackToReg[t]; - } - - // param has been pushed on stack, get it like a local var - - fc = ParamLocOnStack[t] - 8; - } - - if ((fr & VT_VALMASK) < VT_CONST) // check for pure indirect - { - if (size == 1) { - if (Unsigned) - C67_LDBU_PTR(v, r); // LDBU *v,r - else - C67_LDB_PTR(v, r); // LDB *v,r - } else if (size == 2) { - if (Unsigned) - C67_LDHU_PTR(v, r); // LDHU *v,r - else - C67_LDH_PTR(v, r); // LDH *v,r - } else if (size == 4) { - C67_LDW_PTR(v, r); // LDW *v,r - } else if (size == 8) { - C67_LDDW_PTR(v, r); // LDDW *v,r - } - - C67_NOP(4); // NOP 4 - return; - } else if (fr & VT_SYM) { - greloc(cur_text_section, sv->sym, ind, R_C60LO16); // rem the inst need to be patched - greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16); - - - C67_MVKL(C67_A0, fc); //r=reg to load, constant - C67_MVKH(C67_A0, fc); //r=reg to load, constant - - - if (size == 1) { - if (Unsigned) - C67_LDBU_PTR(C67_A0, r); // LDBU *A0,r - else - C67_LDB_PTR(C67_A0, r); // LDB *A0,r - } else if (size == 2) { - if (Unsigned) - C67_LDHU_PTR(C67_A0, r); // LDHU *A0,r - else - C67_LDH_PTR(C67_A0, r); // LDH *A0,r - } else if (size == 4) { - C67_LDW_PTR(C67_A0, r); // LDW *A0,r - } else if (size == 8) { - C67_LDDW_PTR(C67_A0, r); // LDDW *A0,r - } - - C67_NOP(4); // NOP 4 - return; - } else { - element = size; - - // divide offset in bytes to create element index - C67_MVKL(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant - C67_MVKH(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant - - if (size == 1) { - if (Unsigned) - C67_LDBU_SP_A0(r); // LDBU r, SP[A0] - else - C67_LDB_SP_A0(r); // LDB r, SP[A0] - } else if (size == 2) { - if (Unsigned) - C67_LDHU_SP_A0(r); // LDHU r, SP[A0] - else - C67_LDH_SP_A0(r); // LDH r, SP[A0] - } else if (size == 4) { - C67_LDW_SP_A0(r); // LDW r, SP[A0] - } else if (size == 8) { - C67_LDDW_SP_A0(r); // LDDW r, SP[A0] - } - - - C67_NOP(4); // NOP 4 - return; - } - } else { - if (v == VT_CONST) { - if (fr & VT_SYM) { - greloc(cur_text_section, sv->sym, ind, R_C60LO16); // rem the inst need to be patched - greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16); - } - C67_MVKL(r, fc); //r=reg to load, constant - C67_MVKH(r, fc); //r=reg to load, constant - } else if (v == VT_LOCAL) { - C67_MVKL(r, fc + 8); //r=reg to load, constant C67 stack points to next free - C67_MVKH(r, fc + 8); //r=reg to load, constant - C67_ADD(C67_FP, r); // MV v,r v -> r - } else if (v == VT_CMP) { - C67_MV(C67_compare_reg, r); // MV v,r v -> r - } else if (v == VT_JMP || v == VT_JMPI) { - t = v & 1; - C67_B_DISP(4); // Branch with constant displacement, skip over this branch, load, nop, load - C67_MVKL(r, t); // r=reg to load, 0 or 1 (do this while branching) - C67_NOP(4); // NOP 4 - gsym(fc); // modifies other branches to branch here - C67_MVKL(r, t ^ 1); // r=reg to load, 0 or 1 - } else if (v != r) { - C67_MV(v, r); // MV v,r v -> r - - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_MV(v + 1, r + 1); // MV v,r v -> r - } - } -} - - -/* store register 'r' in lvalue 'v' */ -void store(int r, SValue * v) -{ - int fr, bt, ft, fc, size, t, element; - - ft = v->type.t; - fc = v->c.i; - fr = v->r & VT_VALMASK; - bt = ft & VT_BTYPE; - /* XXX: incorrect if float reg to reg */ - - if (bt == VT_LDOUBLE) { - tcc_error("long double not supported"); - } else { - if (bt == VT_SHORT) - size = 2; - else if (bt == VT_BYTE) - size = 1; - else if (bt == VT_DOUBLE) - size = 8; - else - size = 4; - - if ((v->r & VT_VALMASK) == VT_CONST) { - /* constant memory reference */ - - if (v->r & VT_SYM) { - greloc(cur_text_section, v->sym, ind, R_C60LO16); // rem the inst need to be patched - greloc(cur_text_section, v->sym, ind + 4, R_C60HI16); - } - C67_MVKL(C67_A0, fc); //r=reg to load, constant - C67_MVKH(C67_A0, fc); //r=reg to load, constant - - if (size == 1) - C67_STB_PTR(r, C67_A0); // STB r, *A0 - else if (size == 2) - C67_STH_PTR(r, C67_A0); // STH r, *A0 - else if (size == 4 || size == 8) - C67_STW_PTR(r, C67_A0); // STW r, *A0 - - if (size == 8) - C67_STW_PTR_PRE_INC(r + 1, C67_A0, 1); // STW r, *+A0[1] - } else if ((v->r & VT_VALMASK) == VT_LOCAL) { - // check case of storing to passed argument that - // tcc thinks is on the stack but for C67 is - // passed as a reg. However it may have been - // saved to the stack, if that reg was required - // for a call to a child function - - if (fc > 0) // argument ?? - { - // walk through sizes and figure which param - - int stack_pos = 8; - - for (t = 0; t < NoCallArgsPassedOnStack; t++) { - if (fc == stack_pos) - break; - - stack_pos += TranslateStackToReg[t]; - } - - // param has been pushed on stack, get it like a local var - fc = ParamLocOnStack[t] - 8; - } - - if (size == 8) - element = 4; - else - element = size; - - // divide offset in bytes to create word index - C67_MVKL(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant - C67_MVKH(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant - - - - if (size == 1) - C67_STB_SP_A0(r); // STB r, SP[A0] - else if (size == 2) - C67_STH_SP_A0(r); // STH r, SP[A0] - else if (size == 4 || size == 8) - C67_STW_SP_A0(r); // STW r, SP[A0] - - if (size == 8) { - C67_ADDK(1, C67_A0); // ADDK 1,A0 - C67_STW_SP_A0(r + 1); // STW r, SP[A0] - } - } else { - if (size == 1) - C67_STB_PTR(r, fr); // STB r, *fr - else if (size == 2) - C67_STH_PTR(r, fr); // STH r, *fr - else if (size == 4 || size == 8) - C67_STW_PTR(r, fr); // STW r, *fr - - if (size == 8) { - C67_STW_PTR_PRE_INC(r + 1, fr, 1); // STW r, *+fr[1] - } - } - } -} - -/* 'is_jmp' is '1' if it is a jump */ -static void gcall_or_jmp(int is_jmp) -{ - int r; - Sym *sym; - - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - /* constant case */ - if (vtop->r & VT_SYM) { - /* relocation case */ - - // get add into A0, then start the jump B3 - - greloc(cur_text_section, vtop->sym, ind, R_C60LO16); // rem the inst need to be patched - greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16); - - C67_MVKL(C67_A0, 0); //r=reg to load, constant - C67_MVKH(C67_A0, 0); //r=reg to load, constant - C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // B.S2x A0 - - if (is_jmp) { - C67_NOP(5); // simple jump, just put NOP - } else { - // Call, must load return address into B3 during delay slots - - sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address - greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched - greloc(cur_text_section, sym, ind + 4, R_C60HI16); - C67_MVKL(C67_B3, 0); //r=reg to load, constant - C67_MVKH(C67_B3, 0); //r=reg to load, constant - C67_NOP(3); // put remaining NOPs - } - } else { - /* put an empty PC32 relocation */ - ALWAYS_ASSERT(FALSE); - } - } else { - /* otherwise, indirect call */ - r = gv(RC_INT); - C67_IREG_B_REG(0, C67_CREG_ZERO, r); // B.S2x r - - if (is_jmp) { - C67_NOP(5); // simple jump, just put NOP - } else { - // Call, must load return address into B3 during delay slots - - sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address - greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched - greloc(cur_text_section, sym, ind + 4, R_C60HI16); - C67_MVKL(C67_B3, 0); //r=reg to load, constant - C67_MVKH(C67_B3, 0); //r=reg to load, constant - C67_NOP(3); // put remaining NOPs - } - } -} - -/* Return the number of registers needed to return the struct, or 0 if - returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { - *ret_align = 1; // Never have to re-align return values for x86-64 - return 0; -} - -/* generate function call with address in (vtop->t, vtop->c) and free function - context. Stack entry is popped */ -void gfunc_call(int nb_args) -{ - int i, r, size = 0; - int args_sizes[NoCallArgsPassedOnStack]; - - if (nb_args > NoCallArgsPassedOnStack) { - tcc_error("more than 10 function params not currently supported"); - // handle more than 10, put some on the stack - } - - for (i = 0; i < nb_args; i++) { - if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { - ALWAYS_ASSERT(FALSE); - } else { - /* simple type (currently always same size) */ - /* XXX: implicit cast ? */ - - - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - tcc_error("long long not supported"); - } else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - tcc_error("long double not supported"); - } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { - size = 8; - } else { - size = 4; - } - - // put the parameter into the corresponding reg (pair) - - r = gv(RC_C67_A4 << (2 * i)); - - // must put on stack because with 1 pass compiler , no way to tell - // if an up coming nested call might overwrite these regs - - C67_PUSH(r); - - if (size == 8) { - C67_STW_PTR_PRE_INC(r + 1, C67_SP, 3); // STW r, *+SP[3] (go back and put the other) - } - args_sizes[i] = size; - } - vtop--; - } - // POP all the params on the stack into registers for the - // immediate call (in reverse order) - - for (i = nb_args - 1; i >= 0; i--) { - - if (args_sizes[i] == 8) - C67_POP_DW(TREG_C67_A4 + i * 2); - else - C67_POP(TREG_C67_A4 + i * 2); - } - gcall_or_jmp(0); - vtop--; -} - - -// to be compatible with Code Composer for the C67 -// the first 10 parameters must be passed in registers -// (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and -// ending with B12:B13. -// -// When a call is made, if the caller has its parameters -// in regs A4-B13 these must be saved before/as the call -// parameters are loaded and restored upon return (or if/when needed). - -/* generate function prolog of type 't' */ -void gfunc_prolog(CType * func_type) -{ - int addr, align, size, func_call, i; - Sym *sym; - CType *type; - - sym = func_type->ref; - func_call = sym->f.func_call; - addr = 8; - /* if the function returns a structure, then add an - implicit pointer parameter */ - func_vt = sym->type; - func_var = (sym->f.func_type == FUNC_ELLIPSIS); - if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { - func_vc = addr; - addr += 4; - } - - NoOfCurFuncArgs = 0; - - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); - size = type_size(type, &align); - size = (size + 3) & ~3; - - // keep track of size of arguments so - // we can translate where tcc thinks they - // are on the stack into the appropriate reg - - TranslateStackToReg[NoOfCurFuncArgs] = size; - NoOfCurFuncArgs++; - -#ifdef FUNC_STRUCT_PARAM_AS_PTR - /* structs are passed as pointer */ - if ((type->t & VT_BTYPE) == VT_STRUCT) { - size = 4; - } -#endif - addr += size; - } - func_ret_sub = 0; - /* pascal type call ? */ - if (func_call == FUNC_STDCALL) - func_ret_sub = addr - 8; - - C67_MV(C67_FP, C67_A0); // move FP -> A0 - C67_MV(C67_SP, C67_FP); // move SP -> FP - - // place all the args passed in regs onto the stack - - loc = 0; - for (i = 0; i < NoOfCurFuncArgs; i++) { - - ParamLocOnStack[i] = loc; // remember where the param is - loc += -8; - - C67_PUSH(TREG_C67_A4 + i * 2); - - if (TranslateStackToReg[i] == 8) { - C67_STW_PTR_PRE_INC(TREG_C67_A4 + i * 2 + 1, C67_SP, 3); // STW r, *+SP[1] (go back and put the other) - } - } - - TotalBytesPushedOnStack = -loc; - - func_sub_sp_offset = ind; // remember where we put the stack instruction - C67_ADDK(0, C67_SP); // ADDK.L2 loc,SP (just put zero temporarily) - - C67_PUSH(C67_A0); - C67_PUSH(C67_B3); -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - { - int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr - C67_POP(C67_B3); - C67_NOP(4); // NOP wait for load - C67_IREG_B_REG(0, C67_CREG_ZERO, C67_B3); // B.S2 B3 - C67_POP(C67_FP); - C67_ADDK(local, C67_SP); // ADDK.L2 loc,SP - C67_Adjust_ADDK((int *) (cur_text_section->data + - func_sub_sp_offset), - -local + TotalBytesPushedOnStack); - C67_NOP(3); // NOP - } -} - -/* generate a jump to a label */ -int gjmp(int t) -{ - int ind1 = ind; - if (nocode_wanted) - return t; - - C67_MVKL(C67_A0, t); //r=reg to load, constant - C67_MVKH(C67_A0, t); //r=reg to load, constant - C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // [!R] B.S2x A0 - C67_NOP(5); - return ind1; -} - -/* generate a jump to a fixed address */ -void gjmp_addr(int a) -{ - Sym *sym; - // I guess this routine is used for relative short - // local jumps, for now just handle it as the general - // case - - // define a label that will be relocated - - sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0); - greloc(cur_text_section, sym, ind, R_C60LO16); - greloc(cur_text_section, sym, ind + 4, R_C60HI16); - - gjmp(0); // place a zero there later the symbol will be added to it -} - -/* generate a test. set 'inv' to invert test. Stack entry is popped */ -int gtst(int inv, int t) -{ - int ind1, n; - int v, *p; - - v = vtop->r & VT_VALMASK; - if (nocode_wanted) { - ; - } else if (v == VT_CMP) { - /* fast case : can jump directly since flags are set */ - // C67 uses B2 sort of as flags register - ind1 = ind; - C67_MVKL(C67_A0, t); //r=reg to load, constant - C67_MVKH(C67_A0, t); //r=reg to load, constant - - if (C67_compare_reg != TREG_EAX && // check if not already in a conditional test reg - C67_compare_reg != TREG_EDX && - C67_compare_reg != TREG_ST0 && C67_compare_reg != C67_B2) { - C67_MV(C67_compare_reg, C67_B2); - C67_compare_reg = C67_B2; - } - - C67_IREG_B_REG(C67_invert_test ^ inv, C67_compare_reg, C67_A0); // [!R] B.S2x A0 - C67_NOP(5); - t = ind1; //return where we need to patch - - } else if (v == VT_JMP || v == VT_JMPI) { - /* && or || optimization */ - if ((v & 1) == inv) { - /* insert vtop->c jump list in t */ - - // I guess the idea is to traverse to the - // null at the end of the list and store t - // there - - n = vtop->c.i; - while (n != 0) { - p = (int *) (cur_text_section->data + n); - - // extract 32 bit address from MVKH/MVKL - n = ((*p >> 7) & 0xffff); - n |= ((*(p + 1) >> 7) & 0xffff) << 16; - } - *p |= (t & 0xffff) << 7; - *(p + 1) |= ((t >> 16) & 0xffff) << 7; - t = vtop->c.i; - - } else { - t = gjmp(t); - gsym(vtop->c.i); - } - } - vtop--; - return t; -} - -/* generate an integer binary operation */ -void gen_opi(int op) -{ - int r, fr, opc, t; - - switch (op) { - case '+': - case TOK_ADDC1: /* add with carry generation */ - opc = 0; - gen_op8: - - -// C67 can't do const compares, must load into a reg -// so just go to gv2 directly - tktk - - - - if (op >= TOK_ULT && op <= TOK_GT) - gv2(RC_INT_BSIDE, RC_INT); // make sure r (src1) is on the B Side of CPU - else - gv2(RC_INT, RC_INT); - - r = vtop[-1].r; - fr = vtop[0].r; - - C67_compare_reg = C67_B2; - - - if (op == TOK_LT) { - C67_CMPLT(r, fr, C67_B2); - C67_invert_test = FALSE; - } else if (op == TOK_GE) { - C67_CMPLT(r, fr, C67_B2); - C67_invert_test = TRUE; - } else if (op == TOK_GT) { - C67_CMPGT(r, fr, C67_B2); - C67_invert_test = FALSE; - } else if (op == TOK_LE) { - C67_CMPGT(r, fr, C67_B2); - C67_invert_test = TRUE; - } else if (op == TOK_EQ) { - C67_CMPEQ(r, fr, C67_B2); - C67_invert_test = FALSE; - } else if (op == TOK_NE) { - C67_CMPEQ(r, fr, C67_B2); - C67_invert_test = TRUE; - } else if (op == TOK_ULT) { - C67_CMPLTU(r, fr, C67_B2); - C67_invert_test = FALSE; - } else if (op == TOK_UGE) { - C67_CMPLTU(r, fr, C67_B2); - C67_invert_test = TRUE; - } else if (op == TOK_UGT) { - C67_CMPGTU(r, fr, C67_B2); - C67_invert_test = FALSE; - } else if (op == TOK_ULE) { - C67_CMPGTU(r, fr, C67_B2); - C67_invert_test = TRUE; - } else if (op == '+') - C67_ADD(fr, r); // ADD r,fr,r - else if (op == '-') - C67_SUB(fr, r); // SUB r,fr,r - else if (op == '&') - C67_AND(fr, r); // AND r,fr,r - else if (op == '|') - C67_OR(fr, r); // OR r,fr,r - else if (op == '^') - C67_XOR(fr, r); // XOR r,fr,r - else - ALWAYS_ASSERT(FALSE); - - vtop--; - if (op >= TOK_ULT && op <= TOK_GT) { - vtop->r = VT_CMP; - vtop->c.i = op; - } - break; - case '-': - case TOK_SUBC1: /* sub with carry generation */ - opc = 5; - goto gen_op8; - case TOK_ADDC2: /* add with carry use */ - opc = 2; - goto gen_op8; - case TOK_SUBC2: /* sub with carry use */ - opc = 3; - goto gen_op8; - case '&': - opc = 4; - goto gen_op8; - case '^': - opc = 6; - goto gen_op8; - case '|': - opc = 1; - goto gen_op8; - case '*': - case TOK_UMULL: - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - C67_MPYI(fr, r); // 32 bit multiply fr,r,fr - C67_NOP(8); // NOP 8 for worst case - break; - case TOK_SHL: - gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - C67_SHL(fr, r); // arithmetic/logical shift - break; - - case TOK_SHR: - gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - C67_SHRU(fr, r); // logical shift - break; - - case TOK_SAR: - gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - C67_SHR(fr, r); // arithmetic shift - break; - - case '/': - t = TOK__divi; - call_func: - vswap(); - /* call generic idiv function */ - vpush_global_sym(&func_old_type, t); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = REG_IRET; - vtop->r2 = VT_CONST; - break; - case TOK_UDIV: - case TOK_PDIV: - t = TOK__divu; - goto call_func; - case '%': - t = TOK__remi; - goto call_func; - case TOK_UMOD: - t = TOK__remu; - goto call_func; - - default: - opc = 7; - goto gen_op8; - } -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -/* XXX: need to use ST1 too */ -void gen_opf(int op) -{ - int ft, fc, fr, r; - - if (op >= TOK_ULT && op <= TOK_GT) - gv2(RC_EDX, RC_EAX); // make sure src2 is on b side - else - gv2(RC_FLOAT, RC_FLOAT); // make sure src2 is on b side - - ft = vtop->type.t; - fc = vtop->c.i; - r = vtop->r; - fr = vtop[-1].r; - - - if ((ft & VT_BTYPE) == VT_LDOUBLE) - tcc_error("long doubles not supported"); - - if (op >= TOK_ULT && op <= TOK_GT) { - - r = vtop[-1].r; - fr = vtop[0].r; - - C67_compare_reg = C67_B2; - - if (op == TOK_LT) { - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_CMPLTDP(r, fr, C67_B2); - else - C67_CMPLTSP(r, fr, C67_B2); - - C67_invert_test = FALSE; - } else if (op == TOK_GE) { - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_CMPLTDP(r, fr, C67_B2); - else - C67_CMPLTSP(r, fr, C67_B2); - - C67_invert_test = TRUE; - } else if (op == TOK_GT) { - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_CMPGTDP(r, fr, C67_B2); - else - C67_CMPGTSP(r, fr, C67_B2); - - C67_invert_test = FALSE; - } else if (op == TOK_LE) { - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_CMPGTDP(r, fr, C67_B2); - else - C67_CMPGTSP(r, fr, C67_B2); - - C67_invert_test = TRUE; - } else if (op == TOK_EQ) { - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_CMPEQDP(r, fr, C67_B2); - else - C67_CMPEQSP(r, fr, C67_B2); - - C67_invert_test = FALSE; - } else if (op == TOK_NE) { - if ((ft & VT_BTYPE) == VT_DOUBLE) - C67_CMPEQDP(r, fr, C67_B2); - else - C67_CMPEQSP(r, fr, C67_B2); - - C67_invert_test = TRUE; - } else { - ALWAYS_ASSERT(FALSE); - } - vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2 - } else { - if (op == '+') { - if ((ft & VT_BTYPE) == VT_DOUBLE) { - C67_ADDDP(r, fr); // ADD fr,r,fr - C67_NOP(6); - } else { - C67_ADDSP(r, fr); // ADD fr,r,fr - C67_NOP(3); - } - vtop--; - } else if (op == '-') { - if ((ft & VT_BTYPE) == VT_DOUBLE) { - C67_SUBDP(r, fr); // SUB fr,r,fr - C67_NOP(6); - } else { - C67_SUBSP(r, fr); // SUB fr,r,fr - C67_NOP(3); - } - vtop--; - } else if (op == '*') { - if ((ft & VT_BTYPE) == VT_DOUBLE) { - C67_MPYDP(r, fr); // MPY fr,r,fr - C67_NOP(9); - } else { - C67_MPYSP(r, fr); // MPY fr,r,fr - C67_NOP(3); - } - vtop--; - } else if (op == '/') { - if ((ft & VT_BTYPE) == VT_DOUBLE) { - // must call intrinsic DP floating point divide - vswap(); - /* call generic idiv function */ - vpush_global_sym(&func_old_type, TOK__divd); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = REG_FRET; - vtop->r2 = REG_LRET; - - } else { - // must call intrinsic SP floating point divide - vswap(); - /* call generic idiv function */ - vpush_global_sym(&func_old_type, TOK__divf); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = REG_FRET; - vtop->r2 = VT_CONST; - } - } else - ALWAYS_ASSERT(FALSE); - - - } -} - - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -void gen_cvt_itof(int t) -{ - int r; - - gv(RC_INT); - r = vtop->r; - - if ((t & VT_BTYPE) == VT_DOUBLE) { - if (t & VT_UNSIGNED) - C67_INTDPU(r, r); - else - C67_INTDP(r, r); - - C67_NOP(4); - vtop->type.t = VT_DOUBLE; - } else { - if (t & VT_UNSIGNED) - C67_INTSPU(r, r); - else - C67_INTSP(r, r); - C67_NOP(3); - vtop->type.t = VT_FLOAT; - } - -} - -/* convert fp to int 't' type */ -/* XXX: handle long long case */ -void gen_cvt_ftoi(int t) -{ - int r; - - gv(RC_FLOAT); - r = vtop->r; - - if (t != VT_INT) - tcc_error("long long not supported"); - else { - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { - C67_DPTRUNC(r, r); - C67_NOP(3); - } else { - C67_SPTRUNC(r, r); - C67_NOP(3); - } - - vtop->type.t = VT_INT; - - } -} - -/* convert from one floating point type to another */ -void gen_cvt_ftof(int t) -{ - int r, r2; - - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE && - (t & VT_BTYPE) == VT_FLOAT) { - // convert double to float - - gv(RC_FLOAT); // get it in a register pair - - r = vtop->r; - - C67_DPSP(r, r); // convert it to SP same register - C67_NOP(3); - - vtop->type.t = VT_FLOAT; - vtop->r2 = VT_CONST; // set this as unused - } else if ((vtop->type.t & VT_BTYPE) == VT_FLOAT && - (t & VT_BTYPE) == VT_DOUBLE) { - // convert float to double - - gv(RC_FLOAT); // get it in a register - - r = vtop->r; - - if (r == TREG_EAX) { // make sure the paired reg is avail - r2 = get_reg(RC_ECX); - } else if (r == TREG_EDX) { - r2 = get_reg(RC_ST0); - } else { - ALWAYS_ASSERT(FALSE); - r2 = 0; /* avoid warning */ - } - - C67_SPDP(r, r); // convert it to DP same register - C67_NOP(1); - - vtop->type.t = VT_DOUBLE; - vtop->r2 = r2; // set this as unused - } else { - ALWAYS_ASSERT(FALSE); - } -} - -/* computed goto support */ -void ggoto(void) -{ - gcall_or_jmp(1); - vtop--; -} - -/* Save the stack pointer onto the stack and return the location of its address */ -ST_FUNC void gen_vla_sp_save(int addr) { - tcc_error("variable length arrays unsupported for this target"); -} - -/* Restore the SP from a location on the stack */ -ST_FUNC void gen_vla_sp_restore(int addr) { - tcc_error("variable length arrays unsupported for this target"); -} - -/* Subtract from the stack pointer, and push the resulting value onto the stack */ -ST_FUNC void gen_vla_alloc(CType *type, int align) { - tcc_error("variable length arrays unsupported for this target"); -} - -/* end of C67 code generator */ -/*************************************************************/ -#endif -/*************************************************************/ diff --git a/tinyc/c67-link.c b/tinyc/c67-link.c deleted file mode 100644 index de72e442f..000000000 --- a/tinyc/c67-link.c +++ /dev/null @@ -1,131 +0,0 @@ -#ifdef TARGET_DEFS_ONLY - -#define EM_TCC_TARGET EM_C60 - -/* relocation type for 32 bit data relocation */ -#define R_DATA_32 R_C60_32 -#define R_DATA_PTR R_C60_32 -#define R_JMP_SLOT R_C60_JMP_SLOT -#define R_GLOB_DAT R_C60_GLOB_DAT -#define R_COPY R_C60_COPY -#define R_RELATIVE R_C60_RELATIVE - -#define R_NUM R_C60_NUM - -#define ELF_START_ADDR 0x00000400 -#define ELF_PAGE_SIZE 0x1000 - -#define PCRELATIVE_DLLPLT 0 -#define RELOCATE_DLLPLT 0 - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -/* Returns 1 for a code relocation, 0 for a data relocation. For unknown - relocations, returns -1. */ -int code_reloc (int reloc_type) -{ - switch (reloc_type) { - case R_C60_32: - case R_C60LO16: - case R_C60HI16: - case R_C60_GOT32: - case R_C60_GOTOFF: - case R_C60_GOTPC: - case R_C60_COPY: - return 0; - - case R_C60_PLT32: - return 1; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -/* Returns an enumerator to describe whether and when the relocation needs a - GOT and/or PLT entry to be created. See tcc.h for a description of the - different values. */ -int gotplt_entry_type (int reloc_type) -{ - switch (reloc_type) { - case R_C60_32: - case R_C60LO16: - case R_C60HI16: - case R_C60_COPY: - return NO_GOTPLT_ENTRY; - - case R_C60_GOTOFF: - case R_C60_GOTPC: - return BUILD_GOT_ONLY; - - case R_C60_PLT32: - case R_C60_GOT32: - return ALWAYS_GOTPLT_ENTRY; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) -{ - tcc_error("C67 got not implemented"); - return 0; -} - -/* relocate the PLT: compute addresses and offsets in the PLT now that final - address for PLT and GOT are known (see fill_program_header) */ -ST_FUNC void relocate_plt(TCCState *s1) -{ - uint8_t *p, *p_end; - - if (!s1->plt) - return; - - p = s1->plt->data; - p_end = p + s1->plt->data_offset; - - if (p < p_end) { - /* XXX: TODO */ - while (p < p_end) { - /* XXX: TODO */ - } - } -} - -void relocate_init(Section *sr) {} - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) -{ - switch(type) { - case R_C60_32: - *(int *)ptr += val; - break; - case R_C60LO16: - { - uint32_t orig; - - /* put the low 16 bits of the absolute address add to what is - already there */ - orig = ((*(int *)(ptr )) >> 7) & 0xffff; - orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; - - /* patch both at once - assumes always in pairs Low - High */ - *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | - (((val+orig) & 0xffff) << 7); - *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | - ((((val+orig)>>16) & 0xffff) << 7); - } - break; - case R_C60HI16: - break; - default: - fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", - type, (unsigned) addr, ptr, (unsigned) val); - break; - } -} - -#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/coff.h b/tinyc/coff.h deleted file mode 100644 index e8e6185a6..000000000 --- a/tinyc/coff.h +++ /dev/null @@ -1,446 +0,0 @@ -/**************************************************************************/ -/* COFF.H */ -/* COFF data structures and related definitions used by the linker */ -/**************************************************************************/ - -/*------------------------------------------------------------------------*/ -/* COFF FILE HEADER */ -/*------------------------------------------------------------------------*/ -struct filehdr { - unsigned short f_magic; /* magic number */ - unsigned short f_nscns; /* number of sections */ - long f_timdat; /* time & date stamp */ - long f_symptr; /* file pointer to symtab */ - long f_nsyms; /* number of symtab entries */ - unsigned short f_opthdr; /* sizeof(optional hdr) */ - unsigned short f_flags; /* flags */ - unsigned short f_TargetID; /* for C6x = 0x0099 */ - }; - -/*------------------------------------------------------------------------*/ -/* File header flags */ -/*------------------------------------------------------------------------*/ -#define F_RELFLG 0x01 /* relocation info stripped from file */ -#define F_EXEC 0x02 /* file is executable (no unresolved refs) */ -#define F_LNNO 0x04 /* line numbers stripped from file */ -#define F_LSYMS 0x08 /* local symbols stripped from file */ -#define F_GSP10 0x10 /* 34010 version */ -#define F_GSP20 0x20 /* 34020 version */ -#define F_SWABD 0x40 /* bytes swabbed (in names) */ -#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */ -#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */ -#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */ -#define F_PATCH 0x400 /* contains "patch" list in optional header */ -#define F_NODF 0x400 - -#define F_VERSION (F_GSP10 | F_GSP20) -#define F_BYTE_ORDER (F_LITTLE | F_BIG) -#define FILHDR struct filehdr - -/* #define FILHSZ sizeof(FILHDR) */ -#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */ - -#define COFF_C67_MAGIC 0x00c2 - -/*------------------------------------------------------------------------*/ -/* Macros to recognize magic numbers */ -/*------------------------------------------------------------------------*/ -#define ISMAGIC(x) (((unsigned short)(x))==(unsigned short)magic) -#define ISARCHIVE(x) ((((unsigned short)(x))==(unsigned short)ARTYPE)) -#define BADMAGIC(x) (((unsigned short)(x) & 0x8080) && !ISMAGIC(x)) - - -/*------------------------------------------------------------------------*/ -/* OPTIONAL FILE HEADER */ -/*------------------------------------------------------------------------*/ -typedef struct aouthdr { - short magic; /* see magic.h */ - short vstamp; /* version stamp */ - long tsize; /* text size in bytes, padded to FW bdry*/ - long dsize; /* initialized data " " */ - long bsize; /* uninitialized data " " */ - long entrypt; /* entry pt. */ - long text_start; /* base of text used for this file */ - long data_start; /* base of data used for this file */ -} AOUTHDR; - -#define AOUTSZ sizeof(AOUTHDR) - -/*----------------------------------------------------------------------*/ -/* When a UNIX aout header is to be built in the optional header, */ -/* the following magic numbers can appear in that header: */ -/* */ -/* AOUT1MAGIC : default : readonly sharable text segment */ -/* AOUT2MAGIC: : writable text segment */ -/* PAGEMAGIC : : configured for paging */ -/*----------------------------------------------------------------------*/ -#define AOUT1MAGIC 0410 -#define AOUT2MAGIC 0407 -#define PAGEMAGIC 0413 - - -/*------------------------------------------------------------------------*/ -/* COMMON ARCHIVE FILE STRUCTURES */ -/* */ -/* ARCHIVE File Organization: */ -/* _______________________________________________ */ -/* |__________ARCHIVE_MAGIC_STRING_______________| */ -/* |__________ARCHIVE_FILE_MEMBER_1______________| */ -/* | | */ -/* | Archive File Header "ar_hdr" | */ -/* |.............................................| */ -/* | Member Contents | */ -/* | 1. External symbol directory | */ -/* | 2. Text file | */ -/* |_____________________________________________| */ -/* |________ARCHIVE_FILE_MEMBER_2________________| */ -/* | "ar_hdr" | */ -/* |.............................................| */ -/* | Member Contents (.o or text file) | */ -/* |_____________________________________________| */ -/* | . . . | */ -/* | . . . | */ -/* | . . . | */ -/* |_____________________________________________| */ -/* |________ARCHIVE_FILE_MEMBER_n________________| */ -/* | "ar_hdr" | */ -/* |.............................................| */ -/* | Member Contents | */ -/* |_____________________________________________| */ -/* */ -/*------------------------------------------------------------------------*/ - -#define COFF_ARMAG "!\n" -#define SARMAG 8 -#define ARFMAG "`\n" - -struct ar_hdr /* archive file member header - printable ascii */ -{ - char ar_name[16]; /* file member name - `/' terminated */ - char ar_date[12]; /* file member date - decimal */ - char ar_uid[6]; /* file member user id - decimal */ - char ar_gid[6]; /* file member group id - decimal */ - char ar_mode[8]; /* file member mode - octal */ - char ar_size[10]; /* file member size - decimal */ - char ar_fmag[2]; /* ARFMAG - string to end header */ -}; - - -/*------------------------------------------------------------------------*/ -/* SECTION HEADER */ -/*------------------------------------------------------------------------*/ -struct scnhdr { - char s_name[8]; /* section name */ - long s_paddr; /* physical address */ - long s_vaddr; /* virtual address */ - long s_size; /* section size */ - long s_scnptr; /* file ptr to raw data for section */ - long s_relptr; /* file ptr to relocation */ - long s_lnnoptr; /* file ptr to line numbers */ - unsigned int s_nreloc; /* number of relocation entries */ - unsigned int s_nlnno; /* number of line number entries */ - unsigned int s_flags; /* flags */ - unsigned short s_reserved; /* reserved byte */ - unsigned short s_page; /* memory page id */ - }; - -#define SCNHDR struct scnhdr -#define SCNHSZ sizeof(SCNHDR) - -/*------------------------------------------------------------------------*/ -/* Define constants for names of "special" sections */ -/*------------------------------------------------------------------------*/ -/* #define _TEXT ".text" */ -#define _DATA ".data" -#define _BSS ".bss" -#define _CINIT ".cinit" -#define _TV ".tv" - -/*------------------------------------------------------------------------*/ -/* The low 4 bits of s_flags is used as a section "type" */ -/*------------------------------------------------------------------------*/ -#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */ -#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */ -#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */ -#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */ -#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */ -#define STYP_COPY 0x10 /* "copy" : used for C init tables - - not allocated, relocated, - loaded; reloc & lineno - entries processed normally */ -#define STYP_TEXT 0x20 /* section contains text only */ -#define STYP_DATA 0x40 /* section contains data only */ -#define STYP_BSS 0x80 /* section contains bss only */ - -#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */ -#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */ -#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8)) - - -/*------------------------------------------------------------------------*/ -/* RELOCATION ENTRIES */ -/*------------------------------------------------------------------------*/ -struct reloc -{ - long r_vaddr; /* (virtual) address of reference */ - short r_symndx; /* index into symbol table */ - unsigned short r_disp; /* additional bits for address calculation */ - unsigned short r_type; /* relocation type */ -}; - -#define RELOC struct reloc -#define RELSZ 10 /* sizeof(RELOC) */ - -/*--------------------------------------------------------------------------*/ -/* define all relocation types */ -/*--------------------------------------------------------------------------*/ - -#define R_ABS 0 /* absolute address - no relocation */ -#define R_DIR16 01 /* UNUSED */ -#define R_REL16 02 /* UNUSED */ -#define R_DIR24 04 /* UNUSED */ -#define R_REL24 05 /* 24 bits, direct */ -#define R_DIR32 06 /* UNUSED */ -#define R_RELBYTE 017 /* 8 bits, direct */ -#define R_RELWORD 020 /* 16 bits, direct */ -#define R_RELLONG 021 /* 32 bits, direct */ -#define R_PCRBYTE 022 /* 8 bits, PC-relative */ -#define R_PCRWORD 023 /* 16 bits, PC-relative */ -#define R_PCRLONG 024 /* 32 bits, PC-relative */ -#define R_OCRLONG 030 /* GSP: 32 bits, one's complement direct */ -#define R_GSPPCR16 031 /* GSP: 16 bits, PC relative (in words) */ -#define R_GSPOPR32 032 /* GSP: 32 bits, direct big-endian */ -#define R_PARTLS16 040 /* Brahma: 16 bit offset of 24 bit address*/ -#define R_PARTMS8 041 /* Brahma: 8 bit page of 24 bit address */ -#define R_PARTLS7 050 /* DSP: 7 bit offset of 16 bit address */ -#define R_PARTMS9 051 /* DSP: 9 bit page of 16 bit address */ -#define R_REL13 052 /* DSP: 13 bits, direct */ - - -/*------------------------------------------------------------------------*/ -/* LINE NUMBER ENTRIES */ -/*------------------------------------------------------------------------*/ -struct lineno -{ - union - { - long l_symndx ; /* sym. table index of function name - iff l_lnno == 0 */ - long l_paddr ; /* (physical) address of line number */ - } l_addr ; - unsigned short l_lnno ; /* line number */ -}; - -#define LINENO struct lineno -#define LINESZ 6 /* sizeof(LINENO) */ - - -/*------------------------------------------------------------------------*/ -/* STORAGE CLASSES */ -/*------------------------------------------------------------------------*/ -#define C_EFCN -1 /* physical end of function */ -#define C_NULL 0 -#define C_AUTO 1 /* automatic variable */ -#define C_EXT 2 /* external symbol */ -#define C_STAT 3 /* static */ -#define C_REG 4 /* register variable */ -#define C_EXTDEF 5 /* external definition */ -#define C_LABEL 6 /* label */ -#define C_ULABEL 7 /* undefined label */ -#define C_MOS 8 /* member of structure */ -#define C_ARG 9 /* function argument */ -#define C_STRTAG 10 /* structure tag */ -#define C_MOU 11 /* member of union */ -#define C_UNTAG 12 /* union tag */ -#define C_TPDEF 13 /* type definition */ -#define C_USTATIC 14 /* undefined static */ -#define C_ENTAG 15 /* enumeration tag */ -#define C_MOE 16 /* member of enumeration */ -#define C_REGPARM 17 /* register parameter */ -#define C_FIELD 18 /* bit field */ - -#define C_BLOCK 100 /* ".bb" or ".eb" */ -#define C_FCN 101 /* ".bf" or ".ef" */ -#define C_EOS 102 /* end of structure */ -#define C_FILE 103 /* file name */ -#define C_LINE 104 /* dummy sclass for line number entry */ -#define C_ALIAS 105 /* duplicate tag */ -#define C_HIDDEN 106 /* special storage class for external */ - /* symbols in dmert public libraries */ - -/*------------------------------------------------------------------------*/ -/* SYMBOL TABLE ENTRIES */ -/*------------------------------------------------------------------------*/ - -#define SYMNMLEN 8 /* Number of characters in a symbol name */ -#define FILNMLEN 14 /* Number of characters in a file name */ -#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */ - - -struct syment -{ - union - { - char _n_name[SYMNMLEN]; /* old COFF version */ - struct - { - long _n_zeroes; /* new == 0 */ - long _n_offset; /* offset into string table */ - } _n_n; - char *_n_nptr[2]; /* allows for overlaying */ - } _n; - long n_value; /* value of symbol */ - short n_scnum; /* section number */ - unsigned short n_type; /* type and derived type */ - char n_sclass; /* storage class */ - char n_numaux; /* number of aux. entries */ -}; - -#define n_name _n._n_name -#define n_nptr _n._n_nptr[1] -#define n_zeroes _n._n_n._n_zeroes -#define n_offset _n._n_n._n_offset - -/*------------------------------------------------------------------------*/ -/* Relocatable symbols have a section number of the */ -/* section in which they are defined. Otherwise, section */ -/* numbers have the following meanings: */ -/*------------------------------------------------------------------------*/ -#define N_UNDEF 0 /* undefined symbol */ -#define N_ABS -1 /* value of symbol is absolute */ -#define N_DEBUG -2 /* special debugging symbol */ -#define N_TV (unsigned short)-3 /* needs transfer vector (preload) */ -#define P_TV (unsigned short)-4 /* needs transfer vector (postload) */ - - -/*------------------------------------------------------------------------*/ -/* The fundamental type of a symbol packed into the low */ -/* 4 bits of the word. */ -/*------------------------------------------------------------------------*/ -#define _EF ".ef" - -#define T_NULL 0 /* no type info */ -#define T_ARG 1 /* function argument (only used by compiler) */ -#define T_CHAR 2 /* character */ -#define T_SHORT 3 /* short integer */ -#define T_INT 4 /* integer */ -#define T_LONG 5 /* long integer */ -#define T_FLOAT 6 /* floating point */ -#define T_DOUBLE 7 /* double word */ -#define T_STRUCT 8 /* structure */ -#define T_UNION 9 /* union */ -#define T_ENUM 10 /* enumeration */ -#define T_MOE 11 /* member of enumeration */ -#define T_UCHAR 12 /* unsigned character */ -#define T_USHORT 13 /* unsigned short */ -#define T_UINT 14 /* unsigned integer */ -#define T_ULONG 15 /* unsigned long */ - -/*------------------------------------------------------------------------*/ -/* derived types are: */ -/*------------------------------------------------------------------------*/ -#define DT_NON 0 /* no derived type */ -#define DT_PTR 1 /* pointer */ -#define DT_FCN 2 /* function */ -#define DT_ARY 3 /* array */ - -#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \ - ((basic) | ((d1) << 4) | ((d2) << 6) | ((d3) << 8) |\ - ((d4) << 10) | ((d5) << 12) | ((d6) << 14)) - -/*------------------------------------------------------------------------*/ -/* type packing constants and macros */ -/*------------------------------------------------------------------------*/ -#define N_BTMASK_COFF 017 -#define N_TMASK_COFF 060 -#define N_TMASK1_COFF 0300 -#define N_TMASK2_COFF 0360 -#define N_BTSHFT_COFF 4 -#define N_TSHIFT_COFF 2 - -#define BTYPE_COFF(x) ((x) & N_BTMASK_COFF) -#define ISINT(x) (((x) >= T_CHAR && (x) <= T_LONG) || \ - ((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM) -#define ISFLT_COFF(x) ((x) == T_DOUBLE || (x) == T_FLOAT) -#define ISPTR_COFF(x) (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF)) -#define ISFCN_COFF(x) (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF)) -#define ISARY_COFF(x) (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF)) -#define ISTAG_COFF(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG) - -#define INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF)) - - -/*------------------------------------------------------------------------*/ -/* AUXILIARY SYMBOL ENTRY */ -/*------------------------------------------------------------------------*/ -union auxent -{ - struct - { - long x_tagndx; /* str, un, or enum tag indx */ - union - { - struct - { - unsigned short x_lnno; /* declaration line number */ - unsigned short x_size; /* str, union, array size */ - } x_lnsz; - long x_fsize; /* size of function */ - } x_misc; - union - { - struct /* if ISFCN, tag, or .bb */ - { - long x_lnnoptr; /* ptr to fcn line # */ - long x_endndx; /* entry ndx past block end */ - } x_fcn; - struct /* if ISARY, up to 4 dimen. */ - { - unsigned short x_dimen[DIMNUM]; - } x_ary; - } x_fcnary; - unsigned short x_regcount; /* number of registers used by func */ - } x_sym; - struct - { - char x_fname[FILNMLEN]; - } x_file; - struct - { - long x_scnlen; /* section length */ - unsigned short x_nreloc; /* number of relocation entries */ - unsigned short x_nlinno; /* number of line numbers */ - } x_scn; -}; - -#define SYMENT struct syment -#define SYMESZ 18 /* sizeof(SYMENT) */ - -#define AUXENT union auxent -#define AUXESZ 18 /* sizeof(AUXENT) */ - -/*------------------------------------------------------------------------*/ -/* NAMES OF "SPECIAL" SYMBOLS */ -/*------------------------------------------------------------------------*/ -#define _STEXT ".text" -#define _ETEXT "etext" -#define _SDATA ".data" -#define _EDATA "edata" -#define _SBSS ".bss" -#define _END "end" -#define _CINITPTR "cinit" - -/*--------------------------------------------------------------------------*/ -/* ENTRY POINT SYMBOLS */ -/*--------------------------------------------------------------------------*/ -#define _START "_start" -#define _MAIN "_main" - /* _CSTART "_c_int00" (defined in params.h) */ - - -#define _TVORIG "_tvorig" -#define _TORIGIN "_torigin" -#define _DORIGIN "_dorigin" - -#define _SORIGIN "_sorigin" diff --git a/tinyc/config.h b/tinyc/config.h deleted file mode 100644 index a27c7484a..000000000 --- a/tinyc/config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Modified to not rely on a configure script: */ -#define CONFIG_SYSROOT "" -#define TCC_VERSION "0.9.27" - -#if defined(WIN32) || defined(_WIN32) -# define TCC_TARGET_PE 1 -# define TCC_TARGET_I386 -# define CONFIG_TCCDIR "." -#elif defined(__i386__) -# define CONFIG_USE_LIBGCC -# define TCC_TARGET_I386 -# define CONFIG_TCCDIR "/usr/local/lib/tcc" -# define GCC_MAJOR 4 -# define HOST_I386 1 -#else -# define CONFIG_USE_LIBGCC -# define TCC_TARGET_X86_64 -# define CONFIG_TCCDIR "/usr/local/lib/tcc" -# define GCC_MAJOR 4 -# define HOST_X86_64 1 -#endif - diff --git a/tinyc/conftest.c b/tinyc/conftest.c deleted file mode 100644 index 2824cc89d..000000000 --- a/tinyc/conftest.c +++ /dev/null @@ -1,87 +0,0 @@ -#include - -/* Define architecture */ -#if defined(__i386__) || defined _M_IX86 -# define TRIPLET_ARCH "i386" -#elif defined(__x86_64__) || defined _M_AMD64 -# define TRIPLET_ARCH "x86_64" -#elif defined(__arm__) -# define TRIPLET_ARCH "arm" -#elif defined(__aarch64__) -# define TRIPLET_ARCH "aarch64" -#else -# define TRIPLET_ARCH "unknown" -#endif - -/* Define OS */ -#if defined (__linux__) -# define TRIPLET_OS "linux" -#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) -# define TRIPLET_OS "kfreebsd" -#elif defined _WIN32 -# define TRIPLET_OS "win32" -#elif !defined (__GNU__) -# define TRIPLET_OS "unknown" -#endif - -/* Define calling convention and ABI */ -#if defined (__ARM_EABI__) -# if defined (__ARM_PCS_VFP) -# define TRIPLET_ABI "gnueabihf" -# else -# define TRIPLET_ABI "gnueabi" -# endif -#else -# define TRIPLET_ABI "gnu" -#endif - -#if defined _WIN32 -# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS -#elif defined __GNU__ -# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI -#else -# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI -#endif - -#if defined(_WIN32) -int _CRT_glob = 0; -#endif - -int main(int argc, char *argv[]) -{ - switch(argc == 2 ? argv[1][0] : 0) { - case 'b': - { - volatile unsigned foo = 0x01234567; - puts(*(unsigned char*)&foo == 0x67 ? "no" : "yes"); - break; - } -#ifdef __GNUC__ - case 'm': - printf("%d\n", __GNUC_MINOR__); - break; - case 'v': - printf("%d\n", __GNUC__); - break; -#elif defined __TINYC__ - case 'v': - puts("0"); - break; - case 'm': - printf("%d\n", __TINYC__); - break; -#else - case 'm': - case 'v': - puts("0"); - break; -#endif - case 't': - puts(TRIPLET); - break; - - default: - break; - } - return 0; -} diff --git a/tinyc/elf.h b/tinyc/elf.h deleted file mode 100644 index 9fed6eb73..000000000 --- a/tinyc/elf.h +++ /dev/null @@ -1,3237 +0,0 @@ -/* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-2012 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _ELF_H -#define _ELF_H 1 - -#ifndef _WIN32 -#include -#else -#ifndef __int8_t_defined -#define __int8_t_defined -typedef signed char int8_t; -typedef short int int16_t; -typedef int int32_t; -typedef long long int int64_t; -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long int uint64_t; -#endif -#endif - -/* Standard ELF types. */ - -/* Type for a 16-bit quantity. */ -typedef uint16_t Elf32_Half; -typedef uint16_t Elf64_Half; - -/* Types for signed and unsigned 32-bit quantities. */ -typedef uint32_t Elf32_Word; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; - -/* Types for signed and unsigned 64-bit quantities. */ -typedef uint64_t Elf32_Xword; -typedef int64_t Elf32_Sxword; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* Type of addresses. */ -typedef uint32_t Elf32_Addr; -typedef uint64_t Elf64_Addr; - -/* Type of file offsets. */ -typedef uint32_t Elf32_Off; -typedef uint64_t Elf64_Off; - -/* Type for section indices, which are 16-bit quantities. */ -typedef uint16_t Elf32_Section; -typedef uint16_t Elf64_Section; - -/* Type for version symbol information. */ -typedef Elf32_Half Elf32_Versym; -typedef Elf64_Half Elf64_Versym; - - -/* The ELF file header. This appears at the start of every ELF file. */ - -#define EI_NIDENT (16) - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ -} Elf32_Ehdr; - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf64_Half e_type; /* Object file type */ - Elf64_Half e_machine; /* Architecture */ - Elf64_Word e_version; /* Object file version */ - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; /* Processor-specific flags */ - Elf64_Half e_ehsize; /* ELF header size in bytes */ - Elf64_Half e_phentsize; /* Program header table entry size */ - Elf64_Half e_phnum; /* Program header table entry count */ - Elf64_Half e_shentsize; /* Section header table entry size */ - Elf64_Half e_shnum; /* Section header table entry count */ - Elf64_Half e_shstrndx; /* Section header string table index */ -} Elf64_Ehdr; - -/* Fields in the e_ident array. The EI_* macros are indices into the - array. The macros under each EI_* macro are the values the byte - may have. */ - -#define EI_MAG0 0 /* File identification byte 0 index */ -#define ELFMAG0 0x7f /* Magic number byte 0 */ - -#define EI_MAG1 1 /* File identification byte 1 index */ -#define ELFMAG1 'E' /* Magic number byte 1 */ - -#define EI_MAG2 2 /* File identification byte 2 index */ -#define ELFMAG2 'L' /* Magic number byte 2 */ - -#define EI_MAG3 3 /* File identification byte 3 index */ -#define ELFMAG3 'F' /* Magic number byte 3 */ - -/* Conglomeration of the identification bytes, for easy testing as a word. */ -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define EI_CLASS 4 /* File class byte index */ -#define ELFCLASSNONE 0 /* Invalid class */ -#define ELFCLASS32 1 /* 32-bit objects */ -#define ELFCLASS64 2 /* 64-bit objects */ -#define ELFCLASSNUM 3 - -#define EI_DATA 5 /* Data encoding byte index */ -#define ELFDATANONE 0 /* Invalid data encoding */ -#define ELFDATA2LSB 1 /* 2's complement, little endian */ -#define ELFDATA2MSB 2 /* 2's complement, big endian */ -#define ELFDATANUM 3 - -#define EI_VERSION 6 /* File version byte index */ - /* Value must be EV_CURRENT */ - -#define EI_OSABI 7 /* OS ABI identification */ -#define ELFOSABI_NONE 0 /* UNIX System V ABI */ -#define ELFOSABI_SYSV 0 /* Alias. */ -#define ELFOSABI_HPUX 1 /* HP-UX */ -#define ELFOSABI_NETBSD 2 /* NetBSD. */ -#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ -#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ -#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ -#define ELFOSABI_AIX 7 /* IBM AIX. */ -#define ELFOSABI_IRIX 8 /* SGI Irix. */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ -#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ -#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -#define EI_ABIVERSION 8 /* ABI version */ - -#define EI_PAD 9 /* Byte index of padding bytes */ - -/* Legal values for e_type (object file type). */ - -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* Relocatable file */ -#define ET_EXEC 2 /* Executable file */ -#define ET_DYN 3 /* Shared object file */ -#define ET_CORE 4 /* Core file */ -#define ET_NUM 5 /* Number of defined types */ -#define ET_LOOS 0xfe00 /* OS-specific range start */ -#define ET_HIOS 0xfeff /* OS-specific range end */ -#define ET_LOPROC 0xff00 /* Processor-specific range start */ -#define ET_HIPROC 0xffff /* Processor-specific range end */ - -/* Legal values for e_machine (architecture). */ - -#define EM_NONE 0 /* No machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SUN SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola m68k family */ -#define EM_88K 5 /* Motorola m88k family */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 big-endian */ -#define EM_S370 9 /* IBM System/370 */ -#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ - -#define EM_PARISC 15 /* HPPA */ -#define EM_VPP500 17 /* Fujitsu VPP500 */ -#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ -#define EM_960 19 /* Intel 80960 */ -#define EM_PPC 20 /* PowerPC */ -#define EM_PPC64 21 /* PowerPC 64-bit */ -#define EM_S390 22 /* IBM S390 */ - -#define EM_V800 36 /* NEC V800 series */ -#define EM_FR20 37 /* Fujitsu FR20 */ -#define EM_RH32 38 /* TRW RH-32 */ -#define EM_RCE 39 /* Motorola RCE */ -#define EM_ARM 40 /* ARM */ -#define EM_FAKE_ALPHA 41 /* Digital Alpha */ -#define EM_SH 42 /* Hitachi SH */ -#define EM_SPARCV9 43 /* SPARC v9 64-bit */ -#define EM_TRICORE 44 /* Siemens Tricore */ -#define EM_ARC 45 /* Argonaut RISC Core */ -#define EM_H8_300 46 /* Hitachi H8/300 */ -#define EM_H8_300H 47 /* Hitachi H8/300H */ -#define EM_H8S 48 /* Hitachi H8S */ -#define EM_H8_500 49 /* Hitachi H8/500 */ -#define EM_IA_64 50 /* Intel Merced */ -#define EM_MIPS_X 51 /* Stanford MIPS-X */ -#define EM_COLDFIRE 52 /* Motorola Coldfire */ -#define EM_68HC12 53 /* Motorola M68HC12 */ -#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ -#define EM_PCP 55 /* Siemens PCP */ -#define EM_NCPU 56 /* Sony nCPU embedded RISC */ -#define EM_NDR1 57 /* Denso NDR1 microprocessor */ -#define EM_STARCORE 58 /* Motorola Start*Core processor */ -#define EM_ME16 59 /* Toyota ME16 processor */ -#define EM_ST100 60 /* STMicroelectronic ST100 processor */ -#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ -#define EM_X86_64 62 /* AMD x86-64 architecture */ -#define EM_PDSP 63 /* Sony DSP Processor */ - -#define EM_FX66 66 /* Siemens FX66 microcontroller */ -#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ -#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */ -#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ -#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ -#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ -#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ -#define EM_SVX 73 /* Silicon Graphics SVx */ -#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ -#define EM_VAX 75 /* Digital VAX */ -#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ -#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ -#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ -#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ -#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ -#define EM_HUANY 81 /* Harvard University machine-independent object files */ -#define EM_PRISM 82 /* SiTera Prism */ -#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ -#define EM_FR30 84 /* Fujitsu FR30 */ -#define EM_D10V 85 /* Mitsubishi D10V */ -#define EM_D30V 86 /* Mitsubishi D30V */ -#define EM_V850 87 /* NEC v850 */ -#define EM_M32R 88 /* Mitsubishi M32R */ -#define EM_MN10300 89 /* Matsushita MN10300 */ -#define EM_MN10200 90 /* Matsushita MN10200 */ -#define EM_PJ 91 /* picoJava */ -#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ -#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ -#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ -#define EM_AARCH64 183 /* ARM AARCH64 */ -#define EM_TILEPRO 188 /* Tilera TILEPro */ -#define EM_TILEGX 191 /* Tilera TILE-Gx */ -#define EM_NUM 192 - -/* If it is necessary to assign new unofficial EM_* values, please - pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the - chances of collision with official or non-GNU unofficial values. */ - -#define EM_ALPHA 0x9026 -#define EM_C60 0x9c60 - -/* Legal values for e_version (version). */ - -#define EV_NONE 0 /* Invalid ELF version */ -#define EV_CURRENT 1 /* Current version */ -#define EV_NUM 2 - -/* Section header. */ - -typedef struct -{ - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -} Elf32_Shdr; - -typedef struct -{ - Elf64_Word sh_name; /* Section name (string tbl index) */ - Elf64_Word sh_type; /* Section type */ - Elf64_Xword sh_flags; /* Section flags */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Section size in bytes */ - Elf64_Word sh_link; /* Link to another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -/* Special section indices. */ - -#define SHN_UNDEF 0 /* Undefined section */ -#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ -#define SHN_LOPROC 0xff00 /* Start of processor-specific */ -#define SHN_BEFORE 0xff00 /* Order section before all others - (Solaris). */ -#define SHN_AFTER 0xff01 /* Order section after all others - (Solaris). */ -#define SHN_HIPROC 0xff1f /* End of processor-specific */ -#define SHN_LOOS 0xff20 /* Start of OS-specific */ -#define SHN_HIOS 0xff3f /* End of OS-specific */ -#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ -#define SHN_COMMON 0xfff2 /* Associated symbol is common */ -#define SHN_XINDEX 0xffff /* Index is in extra table. */ -#define SHN_HIRESERVE 0xffff /* End of reserved indices */ - -/* Legal values for sh_type (section type). */ - -#define SHT_NULL 0 /* Section header table entry unused */ -#define SHT_PROGBITS 1 /* Program data */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addends */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Dynamic linking information */ -#define SHT_NOTE 7 /* Notes */ -#define SHT_NOBITS 8 /* Program space with no data (bss) */ -#define SHT_REL 9 /* Relocation entries, no addends */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ -#define SHT_INIT_ARRAY 14 /* Array of constructors */ -#define SHT_FINI_ARRAY 15 /* Array of destructors */ -#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ -#define SHT_GROUP 17 /* Section group */ -#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */ -#define SHT_NUM 19 /* Number of defined types. */ -#define SHT_LOOS 0x60000000 /* Start OS-specific. */ -#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ -#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ -#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ -#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ -#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ -#define SHT_SUNW_move 0x6ffffffa -#define SHT_SUNW_COMDAT 0x6ffffffb -#define SHT_SUNW_syminfo 0x6ffffffc -#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ -#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ -#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ -#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ -#define SHT_HIOS 0x6fffffff /* End OS-specific type */ -#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ -#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ -#define SHT_LOUSER 0x80000000 /* Start of application-specific */ -#define SHT_HIUSER 0x8fffffff /* End of application-specific */ - -/* Legal values for sh_flags (section flags). */ - -#define SHF_WRITE (1 << 0) /* Writable */ -#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ -#define SHF_EXECINSTR (1 << 2) /* Executable */ -#define SHF_MERGE (1 << 4) /* Might be merged */ -#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ -#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ -#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ -#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling - required */ -#define SHF_GROUP (1 << 9) /* Section is member of a group. */ -#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ -#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ -#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ -#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ -#define SHF_ORDERED (1 << 30) /* Special ordering requirement - (Solaris). */ -#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless - referenced or allocated (Solaris).*/ - -/* Section group handling. */ -#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ - -/* Symbol table entry. */ - -typedef struct -{ - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf32_Section st_shndx; /* Section index */ -} Elf32_Sym; - -typedef struct -{ - Elf64_Word st_name; /* Symbol name (string tbl index) */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf64_Section st_shndx; /* Section index */ - Elf64_Addr st_value; /* Symbol value */ - Elf64_Xword st_size; /* Symbol size */ -} Elf64_Sym; - -/* The syminfo section if available contains additional information about - every dynamic symbol. */ - -typedef struct -{ - Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ - Elf32_Half si_flags; /* Per symbol flags */ -} Elf32_Syminfo; - -typedef struct -{ - Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ - Elf64_Half si_flags; /* Per symbol flags */ -} Elf64_Syminfo; - -/* Possible values for si_boundto. */ -#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ -#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ -#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ - -/* Possible bitmasks for si_flags. */ -#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ -#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ -#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ -#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy - loaded */ -/* Syminfo version values. */ -#define SYMINFO_NONE 0 -#define SYMINFO_CURRENT 1 -#define SYMINFO_NUM 2 - - -/* How to extract and insert information held in the st_info field. */ - -#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) -#define ELF32_ST_TYPE(val) ((val) & 0xf) -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ -#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) -#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) -#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) - -/* Legal values for ST_BIND subfield of st_info (symbol binding). */ - -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* Weak symbol */ -#define STB_NUM 3 /* Number of defined types. */ -#define STB_LOOS 10 /* Start of OS-specific */ -#define STB_GNU_UNIQUE 10 /* Unique symbol. */ -#define STB_HIOS 12 /* End of OS-specific */ -#define STB_LOPROC 13 /* Start of processor-specific */ -#define STB_HIPROC 15 /* End of processor-specific */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_NOTYPE 0 /* Symbol type is unspecified */ -#define STT_OBJECT 1 /* Symbol is a data object */ -#define STT_FUNC 2 /* Symbol is a code object */ -#define STT_SECTION 3 /* Symbol associated with a section */ -#define STT_FILE 4 /* Symbol's name is file name */ -#define STT_COMMON 5 /* Symbol is a common data object */ -#define STT_TLS 6 /* Symbol is thread-local data object*/ -#define STT_NUM 7 /* Number of defined types. */ -#define STT_LOOS 10 /* Start of OS-specific */ -#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ -#define STT_HIOS 12 /* End of OS-specific */ -#define STT_LOPROC 13 /* Start of processor-specific */ -#define STT_HIPROC 15 /* End of processor-specific */ - - -/* Symbol table indices are found in the hash buckets and chain table - of a symbol hash table section. This special index value indicates - the end of a chain, meaning no further symbols are found in that bucket. */ - -#define STN_UNDEF 0 /* End of a chain. */ - - -/* How to extract and insert information held in the st_other field. */ - -#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) - -/* For ELF64 the definitions are the same. */ -#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) - -/* Symbol visibility specification encoded in the st_other field. */ -#define STV_DEFAULT 0 /* Default symbol visibility rules */ -#define STV_INTERNAL 1 /* Processor specific hidden class */ -#define STV_HIDDEN 2 /* Sym unavailable in other modules */ -#define STV_PROTECTED 3 /* Not preemptible, not exported */ - - -/* Relocation table entry without addend (in section of type SHT_REL). */ - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ -} Elf32_Rel; - -/* I have seen two different definitions of the Elf64_Rel and - Elf64_Rela structures, so we'll leave them out until Novell (or - whoever) gets their act together. */ -/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ - -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ -} Elf64_Rel; - -/* Relocation table entry with addend (in section of type SHT_RELA). */ - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ - Elf32_Sword r_addend; /* Addend */ -} Elf32_Rela; - -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ - Elf64_Sxword r_addend; /* Addend */ -} Elf64_Rela; - -/* How to extract and insert information held in the r_info field. */ - -#define ELF32_R_SYM(val) ((val) >> 8) -#define ELF32_R_TYPE(val) ((val) & 0xff) -#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) - -/* Program segment header. */ - -typedef struct -{ - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -} Elf32_Phdr; - -typedef struct -{ - Elf64_Word p_type; /* Segment type */ - Elf64_Word p_flags; /* Segment flags */ - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment */ -} Elf64_Phdr; - -/* Special value for e_phnum. This indicates that the real number of - program headers is too large to fit into e_phnum. Instead the real - value is in the field sh_info of section 0. */ - -#define PN_XNUM 0xffff - -/* Legal values for p_type (segment type). */ - -#define PT_NULL 0 /* Program header table entry unused */ -#define PT_LOAD 1 /* Loadable program segment */ -#define PT_DYNAMIC 2 /* Dynamic linking information */ -#define PT_INTERP 3 /* Program interpreter */ -#define PT_NOTE 4 /* Auxiliary information */ -#define PT_SHLIB 5 /* Reserved */ -#define PT_PHDR 6 /* Entry for header table itself */ -#define PT_TLS 7 /* Thread-local storage segment */ -#define PT_NUM 8 /* Number of defined types */ -#define PT_LOOS 0x60000000 /* Start of OS-specific */ -#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ -#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ -#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ -#define PT_LOSUNW 0x6ffffffa -#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ -#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ -#define PT_HISUNW 0x6fffffff -#define PT_HIOS 0x6fffffff /* End of OS-specific */ -#define PT_LOPROC 0x70000000 /* Start of processor-specific */ -#define PT_HIPROC 0x7fffffff /* End of processor-specific */ - -/* Legal values for p_flags (segment flags). */ - -#define PF_X (1 << 0) /* Segment is executable */ -#define PF_W (1 << 1) /* Segment is writable */ -#define PF_R (1 << 2) /* Segment is readable */ -#define PF_MASKOS 0x0ff00000 /* OS-specific */ -#define PF_MASKPROC 0xf0000000 /* Processor-specific */ - -/* Legal values for note segment descriptor types for core files. */ - -#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ -#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ -#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ -#define NT_PRXREG 4 /* Contains copy of prxregset struct */ -#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ -#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ -#define NT_AUXV 6 /* Contains copy of auxv array */ -#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ -#define NT_ASRS 8 /* Contains copy of asrset struct */ -#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ -#define NT_PSINFO 13 /* Contains copy of psinfo struct */ -#define NT_PRCRED 14 /* Contains copy of prcred struct */ -#define NT_UTSNAME 15 /* Contains copy of utsname struct */ -#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ -#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ -#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ -#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ -#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ -#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ -#define NT_S390_TIMER 0x301 /* s390 timer register */ -#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ -#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ -#define NT_S390_CTRS 0x304 /* s390 control registers */ -#define NT_S390_PREFIX 0x305 /* s390 prefix register */ -#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ -#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ -#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ -#define NT_ARM_TLS 0x401 /* ARM TLS register */ -#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ -#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ - -/* Legal values for the note segment descriptor types for object files. */ - -#define NT_VERSION 1 /* Contains a version string. */ - - -/* Dynamic section entry. */ - -typedef struct -{ - Elf32_Sword d_tag; /* Dynamic entry type */ - union - { - Elf32_Word d_val; /* Integer value */ - Elf32_Addr d_ptr; /* Address value */ - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* Dynamic entry type */ - union - { - Elf64_Xword d_val; /* Integer value */ - Elf64_Addr d_ptr; /* Address value */ - } d_un; -} Elf64_Dyn; - -/* Legal values for d_tag (dynamic entry type). */ - -#define DT_NULL 0 /* Marks end of dynamic section */ -#define DT_NEEDED 1 /* Name of needed library */ -#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ -#define DT_PLTGOT 3 /* Processor defined value */ -#define DT_HASH 4 /* Address of symbol hash table */ -#define DT_STRTAB 5 /* Address of string table */ -#define DT_SYMTAB 6 /* Address of symbol table */ -#define DT_RELA 7 /* Address of Rela relocs */ -#define DT_RELASZ 8 /* Total size of Rela relocs */ -#define DT_RELAENT 9 /* Size of one Rela reloc */ -#define DT_STRSZ 10 /* Size of string table */ -#define DT_SYMENT 11 /* Size of one symbol table entry */ -#define DT_INIT 12 /* Address of init function */ -#define DT_FINI 13 /* Address of termination function */ -#define DT_SONAME 14 /* Name of shared object */ -#define DT_RPATH 15 /* Library search path (deprecated) */ -#define DT_SYMBOLIC 16 /* Start symbol search here */ -#define DT_REL 17 /* Address of Rel relocs */ -#define DT_RELSZ 18 /* Total size of Rel relocs */ -#define DT_RELENT 19 /* Size of one Rel reloc */ -#define DT_PLTREL 20 /* Type of reloc in PLT */ -#define DT_DEBUG 21 /* For debugging; unspecified */ -#define DT_TEXTREL 22 /* Reloc might modify .text */ -#define DT_JMPREL 23 /* Address of PLT relocs */ -#define DT_BIND_NOW 24 /* Process relocations of object */ -#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ -#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ -#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ -#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ -#define DT_RUNPATH 29 /* Library search path */ -#define DT_FLAGS 30 /* Flags for the object being loaded */ -#define DT_ENCODING 32 /* Start of encoded range */ -#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ -#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ -#define DT_NUM 34 /* Number used */ -#define DT_LOOS 0x6000000d /* Start of OS-specific */ -#define DT_HIOS 0x6ffff000 /* End of OS-specific */ -#define DT_LOPROC 0x70000000 /* Start of processor-specific */ -#define DT_HIPROC 0x7fffffff /* End of processor-specific */ -#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ - -/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the - Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's - approach. */ -#define DT_VALRNGLO 0x6ffffd00 -#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ -#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ -#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ -#define DT_CHECKSUM 0x6ffffdf8 -#define DT_PLTPADSZ 0x6ffffdf9 -#define DT_MOVEENT 0x6ffffdfa -#define DT_MOVESZ 0x6ffffdfb -#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ -#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting - the following DT_* entry. */ -#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ -#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ -#define DT_VALRNGHI 0x6ffffdff -#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ -#define DT_VALNUM 12 - -/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the - Dyn.d_un.d_ptr field of the Elf*_Dyn structure. - - If any adjustment is made to the ELF object after it has been - built these entries will need to be adjusted. */ -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ -#define DT_TLSDESC_PLT 0x6ffffef6 -#define DT_TLSDESC_GOT 0x6ffffef7 -#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ -#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ -#define DT_CONFIG 0x6ffffefa /* Configuration information. */ -#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ -#define DT_AUDIT 0x6ffffefc /* Object auditing. */ -#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ -#define DT_MOVETAB 0x6ffffefe /* Move table. */ -#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ -#define DT_ADDRNUM 11 - -/* The versioning entry types. The next are defined as part of the - GNU extension. */ -#define DT_VERSYM 0x6ffffff0 - -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa - -/* These were chosen by Sun. */ -#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ -#define DT_VERDEF 0x6ffffffc /* Address of version definition - table */ -#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ -#define DT_VERNEED 0x6ffffffe /* Address of table with needed - versions */ -#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ -#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ -#define DT_VERSIONTAGNUM 16 - -/* Sun added these machine-independent extensions in the "processor-specific" - range. Be compatible. */ -#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ -#define DT_FILTER 0x7fffffff /* Shared object to get values from */ -#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) -#define DT_EXTRANUM 3 - -/* Values of `d_un.d_val' in the DT_FLAGS entry. */ -#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ -#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ -#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ -#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ -#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ - -/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 - entry in the dynamic section. */ -#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ -#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ -#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ -#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ -#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ -#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ -#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ -#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ -#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ -#define DF_1_TRANS 0x00000200 -#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ -#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ -#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ -#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ -#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ -#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ -#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ -#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ -#define DF_1_IGNMULDEF 0x00040000 -#define DF_1_NOKSYMS 0x00080000 -#define DF_1_NOHDR 0x00100000 -#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ -#define DF_1_NORELOC 0x00400000 -#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ -#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ -#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ - -/* Flags for the feature selection in DT_FEATURE_1. */ -#define DTF_1_PARINIT 0x00000001 -#define DTF_1_CONFEXP 0x00000002 - -/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ -#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ -#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not - generally available. */ - -/* Version definition sections. */ - -typedef struct -{ - Elf32_Half vd_version; /* Version revision */ - Elf32_Half vd_flags; /* Version information */ - Elf32_Half vd_ndx; /* Version Index */ - Elf32_Half vd_cnt; /* Number of associated aux entries */ - Elf32_Word vd_hash; /* Version name hash value */ - Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ - Elf32_Word vd_next; /* Offset in bytes to next verdef - entry */ -} Elf32_Verdef; - -typedef struct -{ - Elf64_Half vd_version; /* Version revision */ - Elf64_Half vd_flags; /* Version information */ - Elf64_Half vd_ndx; /* Version Index */ - Elf64_Half vd_cnt; /* Number of associated aux entries */ - Elf64_Word vd_hash; /* Version name hash value */ - Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ - Elf64_Word vd_next; /* Offset in bytes to next verdef - entry */ -} Elf64_Verdef; - - -/* Legal values for vd_version (version revision). */ -#define VER_DEF_NONE 0 /* No version */ -#define VER_DEF_CURRENT 1 /* Current version */ -#define VER_DEF_NUM 2 /* Given version number */ - -/* Legal values for vd_flags (version information flags). */ -#define VER_FLG_BASE 0x1 /* Version definition of file itself */ -#define VER_FLG_WEAK 0x2 /* Weak version identifier */ - -/* Versym symbol index values. */ -#define VER_NDX_LOCAL 0 /* Symbol is local. */ -#define VER_NDX_GLOBAL 1 /* Symbol is global. */ -#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ -#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ - -/* Auxiliary version information. */ - -typedef struct -{ - Elf32_Word vda_name; /* Version or dependency names */ - Elf32_Word vda_next; /* Offset in bytes to next verdaux - entry */ -} Elf32_Verdaux; - -typedef struct -{ - Elf64_Word vda_name; /* Version or dependency names */ - Elf64_Word vda_next; /* Offset in bytes to next verdaux - entry */ -} Elf64_Verdaux; - - -/* Version dependency section. */ - -typedef struct -{ - Elf32_Half vn_version; /* Version of structure */ - Elf32_Half vn_cnt; /* Number of associated aux entries */ - Elf32_Word vn_file; /* Offset of filename for this - dependency */ - Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ - Elf32_Word vn_next; /* Offset in bytes to next verneed - entry */ -} Elf32_Verneed; - -typedef struct -{ - Elf64_Half vn_version; /* Version of structure */ - Elf64_Half vn_cnt; /* Number of associated aux entries */ - Elf64_Word vn_file; /* Offset of filename for this - dependency */ - Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ - Elf64_Word vn_next; /* Offset in bytes to next verneed - entry */ -} Elf64_Verneed; - - -/* Legal values for vn_version (version revision). */ -#define VER_NEED_NONE 0 /* No version */ -#define VER_NEED_CURRENT 1 /* Current version */ -#define VER_NEED_NUM 2 /* Given version number */ - -/* Auxiliary needed version information. */ - -typedef struct -{ - Elf32_Word vna_hash; /* Hash value of dependency name */ - Elf32_Half vna_flags; /* Dependency specific information */ - Elf32_Half vna_other; /* Unused */ - Elf32_Word vna_name; /* Dependency name string offset */ - Elf32_Word vna_next; /* Offset in bytes to next vernaux - entry */ -} Elf32_Vernaux; - -typedef struct -{ - Elf64_Word vna_hash; /* Hash value of dependency name */ - Elf64_Half vna_flags; /* Dependency specific information */ - Elf64_Half vna_other; /* Unused */ - Elf64_Word vna_name; /* Dependency name string offset */ - Elf64_Word vna_next; /* Offset in bytes to next vernaux - entry */ -} Elf64_Vernaux; - - -/* Legal values for vna_flags. */ -#define VER_FLG_WEAK 0x2 /* Weak version identifier */ - - -/* Auxiliary vector. */ - -/* This vector is normally only used by the program interpreter. The - usual definition in an ABI supplement uses the name auxv_t. The - vector is not usually defined in a standard file, but it - can't hurt. We rename it to avoid conflicts. The sizes of these - types are an arrangement between the exec server and the program - interpreter, so we don't fully specify them here. */ - -typedef struct -{ - uint32_t a_type; /* Entry type */ - union - { - uint32_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf32_auxv_t; - -typedef struct -{ - uint64_t a_type; /* Entry type */ - union - { - uint64_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf64_auxv_t; - -/* Legal values for a_type (entry type). */ - -#define AT_NULL 0 /* End of vector */ -#define AT_IGNORE 1 /* Entry should be ignored */ -#define AT_EXECFD 2 /* File descriptor of program */ -#define AT_PHDR 3 /* Program headers for program */ -#define AT_PHENT 4 /* Size of program header entry */ -#define AT_PHNUM 5 /* Number of program headers */ -#define AT_PAGESZ 6 /* System page size */ -#define AT_BASE 7 /* Base address of interpreter */ -#define AT_FLAGS 8 /* Flags */ -#define AT_ENTRY 9 /* Entry point of program */ -#define AT_NOTELF 10 /* Program is not ELF */ -#define AT_UID 11 /* Real uid */ -#define AT_EUID 12 /* Effective uid */ -#define AT_GID 13 /* Real gid */ -#define AT_EGID 14 /* Effective gid */ -#define AT_CLKTCK 17 /* Frequency of times() */ - -/* Some more special a_type values describing the hardware. */ -#define AT_PLATFORM 15 /* String identifying platform. */ -#define AT_HWCAP 16 /* Machine dependent hints about - processor capabilities. */ - -/* This entry gives some information about the FPU initialization - performed by the kernel. */ -#define AT_FPUCW 18 /* Used FPU control word. */ - -/* Cache block sizes. */ -#define AT_DCACHEBSIZE 19 /* Data cache block size. */ -#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ -#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ - -/* A special ignored value for PPC, used by the kernel to control the - interpretation of the AUXV. Must be > 16. */ -#define AT_IGNOREPPC 22 /* Entry should be ignored. */ - -#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ - -#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ - -#define AT_RANDOM 25 /* Address of 16 random bytes. */ - -#define AT_EXECFN 31 /* Filename of executable. */ - -/* Pointer to the global system page used for system calls and other - nice things. */ -#define AT_SYSINFO 32 -#define AT_SYSINFO_EHDR 33 - -/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains - log2 of line size; mask those to get cache size. */ -#define AT_L1I_CACHESHAPE 34 -#define AT_L1D_CACHESHAPE 35 -#define AT_L2_CACHESHAPE 36 -#define AT_L3_CACHESHAPE 37 - -/* Note section contents. Each entry in the note section begins with - a header of a fixed form. */ - -typedef struct -{ - Elf32_Word n_namesz; /* Length of the note's name. */ - Elf32_Word n_descsz; /* Length of the note's descriptor. */ - Elf32_Word n_type; /* Type of the note. */ -} Elf32_Nhdr; - -typedef struct -{ - Elf64_Word n_namesz; /* Length of the note's name. */ - Elf64_Word n_descsz; /* Length of the note's descriptor. */ - Elf64_Word n_type; /* Type of the note. */ -} Elf64_Nhdr; - -/* Known names of notes. */ - -/* Solaris entries in the note section have this name. */ -#define ELF_NOTE_SOLARIS "SUNW Solaris" - -/* Note entries for GNU systems have this name. */ -#define ELF_NOTE_GNU "GNU" - - -/* Defined types of notes for Solaris. */ - -/* Value of descriptor (one word) is desired pagesize for the binary. */ -#define ELF_NOTE_PAGESIZE_HINT 1 - - -/* Defined note types for GNU systems. */ - -/* ABI information. The descriptor consists of words: - word 0: OS descriptor - word 1: major version of the ABI - word 2: minor version of the ABI - word 3: subminor version of the ABI -*/ -#define NT_GNU_ABI_TAG 1 -#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ - -/* Known OSes. These values can appear in word 0 of an - NT_GNU_ABI_TAG note section entry. */ -#define ELF_NOTE_OS_LINUX 0 -#define ELF_NOTE_OS_GNU 1 -#define ELF_NOTE_OS_SOLARIS2 2 -#define ELF_NOTE_OS_FREEBSD 3 - -/* Synthetic hwcap information. The descriptor begins with two words: - word 0: number of entries - word 1: bitmask of enabled entries - Then follow variable-length entries, one byte followed by a - '\0'-terminated hwcap name string. The byte gives the bit - number to test if enabled, (1U << bit) & bitmask. */ -#define NT_GNU_HWCAP 2 - -/* Build ID bits as generated by ld --build-id. - The descriptor consists of any nonzero number of bytes. */ -#define NT_GNU_BUILD_ID 3 - -/* Version note generated by GNU gold containing a version string. */ -#define NT_GNU_GOLD_VERSION 4 - - -/* Move records. */ -typedef struct -{ - Elf32_Xword m_value; /* Symbol value. */ - Elf32_Word m_info; /* Size and index. */ - Elf32_Word m_poffset; /* Symbol offset. */ - Elf32_Half m_repeat; /* Repeat count. */ - Elf32_Half m_stride; /* Stride info. */ -} Elf32_Move; - -typedef struct -{ - Elf64_Xword m_value; /* Symbol value. */ - Elf64_Xword m_info; /* Size and index. */ - Elf64_Xword m_poffset; /* Symbol offset. */ - Elf64_Half m_repeat; /* Repeat count. */ - Elf64_Half m_stride; /* Stride info. */ -} Elf64_Move; - -/* Macro to construct move records. */ -#define ELF32_M_SYM(info) ((info) >> 8) -#define ELF32_M_SIZE(info) ((unsigned char) (info)) -#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) - -#define ELF64_M_SYM(info) ELF32_M_SYM (info) -#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) -#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) - - -/* Motorola 68k specific definitions. */ - -/* Values for Elf32_Ehdr.e_flags. */ -#define EF_CPU32 0x00810000 - -/* m68k relocs. */ - -#define R_68K_NONE 0 /* No reloc */ -#define R_68K_32 1 /* Direct 32 bit */ -#define R_68K_16 2 /* Direct 16 bit */ -#define R_68K_8 3 /* Direct 8 bit */ -#define R_68K_PC32 4 /* PC relative 32 bit */ -#define R_68K_PC16 5 /* PC relative 16 bit */ -#define R_68K_PC8 6 /* PC relative 8 bit */ -#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ -#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ -#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ -#define R_68K_GOT32O 10 /* 32 bit GOT offset */ -#define R_68K_GOT16O 11 /* 16 bit GOT offset */ -#define R_68K_GOT8O 12 /* 8 bit GOT offset */ -#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ -#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ -#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ -#define R_68K_PLT32O 16 /* 32 bit PLT offset */ -#define R_68K_PLT16O 17 /* 16 bit PLT offset */ -#define R_68K_PLT8O 18 /* 8 bit PLT offset */ -#define R_68K_COPY 19 /* Copy symbol at runtime */ -#define R_68K_GLOB_DAT 20 /* Create GOT entry */ -#define R_68K_JMP_SLOT 21 /* Create PLT entry */ -#define R_68K_RELATIVE 22 /* Adjust by program base */ -#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ -#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ -#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ -#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ -#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ -#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ -#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ -#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ -#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ -#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ -#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ -#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ -#define R_68K_TLS_LE32 37 /* 32 bit offset relative to - static TLS block */ -#define R_68K_TLS_LE16 38 /* 16 bit offset relative to - static TLS block */ -#define R_68K_TLS_LE8 39 /* 8 bit offset relative to - static TLS block */ -#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ -#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ -#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ -/* Keep this the last entry. */ -#define R_68K_NUM 43 - -/* Intel 80386 specific definitions. */ - -/* i386 relocs. */ - -#define R_386_NONE 0 /* No reloc */ -#define R_386_32 1 /* Direct 32 bit */ -#define R_386_PC32 2 /* PC relative 32 bit */ -#define R_386_GOT32 3 /* 32 bit GOT entry */ -#define R_386_PLT32 4 /* 32 bit PLT address */ -#define R_386_COPY 5 /* Copy symbol at runtime */ -#define R_386_GLOB_DAT 6 /* Create GOT entry */ -#define R_386_JMP_SLOT 7 /* Create PLT entry */ -#define R_386_RELATIVE 8 /* Adjust by program base */ -#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ -#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ -#define R_386_32PLT 11 -#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ -#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS - block offset */ -#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block - offset */ -#define R_386_TLS_LE 17 /* Offset relative to static TLS - block */ -#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of - general dynamic thread local data */ -#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of - local dynamic thread local data - in LE code */ -#define R_386_16 20 -#define R_386_PC16 21 -#define R_386_8 22 -#define R_386_PC8 23 -#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic - thread local data */ -#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ -#define R_386_TLS_GD_CALL 26 /* Relocation for call to - __tls_get_addr() */ -#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ -#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic - thread local data in LE code */ -#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ -#define R_386_TLS_LDM_CALL 30 /* Relocation for call to - __tls_get_addr() in LDM code */ -#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ -#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ -#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS - block offset */ -#define R_386_TLS_LE_32 34 /* Negated offset relative to static - TLS block */ -#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ -#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ -#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ -/* 38? */ -#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ -#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS - descriptor for - relaxation. */ -#define R_386_TLS_DESC 41 /* TLS descriptor containing - pointer to code and to - argument, returning the TLS - offset for the symbol. */ -#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ -#define R_386_GOT32X 43 /* 32 bit GOT entry, relaxable */ -/* Keep this the last entry. */ -#define R_386_NUM 44 - -/* SUN SPARC specific definitions. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ - -/* Values for Elf64_Ehdr.e_flags. */ - -#define EF_SPARCV9_MM 3 -#define EF_SPARCV9_TSO 0 -#define EF_SPARCV9_PSO 1 -#define EF_SPARCV9_RMO 2 -#define EF_SPARC_LEDATA 0x800000 /* little endian data */ -#define EF_SPARC_EXT_MASK 0xFFFF00 -#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ -#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ -#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ -#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ - -/* SPARC relocs. */ - -#define R_SPARC_NONE 0 /* No reloc */ -#define R_SPARC_8 1 /* Direct 8 bit */ -#define R_SPARC_16 2 /* Direct 16 bit */ -#define R_SPARC_32 3 /* Direct 32 bit */ -#define R_SPARC_DISP8 4 /* PC relative 8 bit */ -#define R_SPARC_DISP16 5 /* PC relative 16 bit */ -#define R_SPARC_DISP32 6 /* PC relative 32 bit */ -#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ -#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ -#define R_SPARC_HI22 9 /* High 22 bit */ -#define R_SPARC_22 10 /* Direct 22 bit */ -#define R_SPARC_13 11 /* Direct 13 bit */ -#define R_SPARC_LO10 12 /* Truncated 10 bit */ -#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ -#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ -#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ -#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ -#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ -#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ -#define R_SPARC_COPY 19 /* Copy symbol at runtime */ -#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ -#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ -#define R_SPARC_RELATIVE 22 /* Adjust by program base */ -#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ - -/* Additional Sparc64 relocs. */ - -#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ -#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ -#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ -#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ -#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ -#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ -#define R_SPARC_10 30 /* Direct 10 bit */ -#define R_SPARC_11 31 /* Direct 11 bit */ -#define R_SPARC_64 32 /* Direct 64 bit */ -#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ -#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ -#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ -#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ -#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ -#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ -#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */ -#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ -#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ -#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ -#define R_SPARC_7 43 /* Direct 7 bit */ -#define R_SPARC_5 44 /* Direct 5 bit */ -#define R_SPARC_6 45 /* Direct 6 bit */ -#define R_SPARC_DISP64 46 /* PC relative 64 bit */ -#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ -#define R_SPARC_HIX22 48 /* High 22 bit complemented */ -#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ -#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ -#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ -#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ -#define R_SPARC_REGISTER 53 /* Global register usage */ -#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ -#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ -#define R_SPARC_TLS_GD_HI22 56 -#define R_SPARC_TLS_GD_LO10 57 -#define R_SPARC_TLS_GD_ADD 58 -#define R_SPARC_TLS_GD_CALL 59 -#define R_SPARC_TLS_LDM_HI22 60 -#define R_SPARC_TLS_LDM_LO10 61 -#define R_SPARC_TLS_LDM_ADD 62 -#define R_SPARC_TLS_LDM_CALL 63 -#define R_SPARC_TLS_LDO_HIX22 64 -#define R_SPARC_TLS_LDO_LOX10 65 -#define R_SPARC_TLS_LDO_ADD 66 -#define R_SPARC_TLS_IE_HI22 67 -#define R_SPARC_TLS_IE_LO10 68 -#define R_SPARC_TLS_IE_LD 69 -#define R_SPARC_TLS_IE_LDX 70 -#define R_SPARC_TLS_IE_ADD 71 -#define R_SPARC_TLS_LE_HIX22 72 -#define R_SPARC_TLS_LE_LOX10 73 -#define R_SPARC_TLS_DTPMOD32 74 -#define R_SPARC_TLS_DTPMOD64 75 -#define R_SPARC_TLS_DTPOFF32 76 -#define R_SPARC_TLS_DTPOFF64 77 -#define R_SPARC_TLS_TPOFF32 78 -#define R_SPARC_TLS_TPOFF64 79 -#define R_SPARC_GOTDATA_HIX22 80 -#define R_SPARC_GOTDATA_LOX10 81 -#define R_SPARC_GOTDATA_OP_HIX22 82 -#define R_SPARC_GOTDATA_OP_LOX10 83 -#define R_SPARC_GOTDATA_OP 84 -#define R_SPARC_H34 85 -#define R_SPARC_SIZE32 86 -#define R_SPARC_SIZE64 87 -#define R_SPARC_WDISP10 88 -#define R_SPARC_JMP_IREL 248 -#define R_SPARC_IRELATIVE 249 -#define R_SPARC_GNU_VTINHERIT 250 -#define R_SPARC_GNU_VTENTRY 251 -#define R_SPARC_REV32 252 -/* Keep this the last entry. */ -#define R_SPARC_NUM 253 - -/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ - -#define DT_SPARC_REGISTER 0x70000001 -#define DT_SPARC_NUM 2 - -/* MIPS R3000 specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ -#define EF_MIPS_PIC 2 /* Contains PIC code */ -#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ -#define EF_MIPS_XGOT 8 -#define EF_MIPS_64BIT_WHIRL 16 -#define EF_MIPS_ABI2 32 -#define EF_MIPS_ABI_ON32 64 -#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ - -/* Legal values for MIPS architecture level. */ - -#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ -#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ -#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ -#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ -#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ -#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ -#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ - -/* The following are non-official names and should not be used. */ - -#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ -#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ -#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ -#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ -#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ -#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ -#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ - -/* Special section indices. */ - -#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ -#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ -#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ -#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ -#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ -#define SHT_MIPS_MSYM 0x70000001 -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ -#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ -#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ -#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ -#define SHT_MIPS_PACKAGE 0x70000007 -#define SHT_MIPS_PACKSYM 0x70000008 -#define SHT_MIPS_RELD 0x70000009 -#define SHT_MIPS_IFACE 0x7000000b -#define SHT_MIPS_CONTENT 0x7000000c -#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ -#define SHT_MIPS_SHDR 0x70000010 -#define SHT_MIPS_FDESC 0x70000011 -#define SHT_MIPS_EXTSYM 0x70000012 -#define SHT_MIPS_DENSE 0x70000013 -#define SHT_MIPS_PDESC 0x70000014 -#define SHT_MIPS_LOCSYM 0x70000015 -#define SHT_MIPS_AUXSYM 0x70000016 -#define SHT_MIPS_OPTSYM 0x70000017 -#define SHT_MIPS_LOCSTR 0x70000018 -#define SHT_MIPS_LINE 0x70000019 -#define SHT_MIPS_RFDESC 0x7000001a -#define SHT_MIPS_DELTASYM 0x7000001b -#define SHT_MIPS_DELTAINST 0x7000001c -#define SHT_MIPS_DELTACLASS 0x7000001d -#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ -#define SHT_MIPS_DELTADECL 0x7000001f -#define SHT_MIPS_SYMBOL_LIB 0x70000020 -#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ -#define SHT_MIPS_TRANSLATE 0x70000022 -#define SHT_MIPS_PIXIE 0x70000023 -#define SHT_MIPS_XLATE 0x70000024 -#define SHT_MIPS_XLATE_DEBUG 0x70000025 -#define SHT_MIPS_WHIRL 0x70000026 -#define SHT_MIPS_EH_REGION 0x70000027 -#define SHT_MIPS_XLATE_OLD 0x70000028 -#define SHT_MIPS_PDR_EXCEPTION 0x70000029 - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ -#define SHF_MIPS_MERGE 0x20000000 -#define SHF_MIPS_ADDR 0x40000000 -#define SHF_MIPS_STRINGS 0x80000000 -#define SHF_MIPS_NOSTRIP 0x08000000 -#define SHF_MIPS_LOCAL 0x04000000 -#define SHF_MIPS_NAMES 0x02000000 -#define SHF_MIPS_NODUPE 0x01000000 - - -/* Symbol tables. */ - -/* MIPS specific values for `st_other'. */ -#define STO_MIPS_DEFAULT 0x0 -#define STO_MIPS_INTERNAL 0x1 -#define STO_MIPS_HIDDEN 0x2 -#define STO_MIPS_PROTECTED 0x3 -#define STO_MIPS_PLT 0x8 -#define STO_MIPS_SC_ALIGN_UNUSED 0xff - -/* MIPS specific values for `st_info'. */ -#define STB_MIPS_SPLIT_COMMON 13 - -/* Entries found in sections of type SHT_MIPS_GPTAB. */ - -typedef union -{ - struct - { - Elf32_Word gt_current_g_value; /* -G value used for compilation */ - Elf32_Word gt_unused; /* Not used */ - } gt_header; /* First entry in section */ - struct - { - Elf32_Word gt_g_value; /* If this value were used for -G */ - Elf32_Word gt_bytes; /* This many bytes would be used */ - } gt_entry; /* Subsequent entries in section */ -} Elf32_gptab; - -/* Entry found in sections of type SHT_MIPS_REGINFO. */ - -typedef struct -{ - Elf32_Word ri_gprmask; /* General registers used */ - Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ - Elf32_Sword ri_gp_value; /* $gp register value */ -} Elf32_RegInfo; - -/* Entries found in sections of type SHT_MIPS_OPTIONS. */ - -typedef struct -{ - unsigned char kind; /* Determines interpretation of the - variable part of descriptor. */ - unsigned char size; /* Size of descriptor, including header. */ - Elf32_Section section; /* Section header index of section affected, - 0 for global options. */ - Elf32_Word info; /* Kind-specific information. */ -} Elf_Options; - -/* Values for `kind' field in Elf_Options. */ - -#define ODK_NULL 0 /* Undefined. */ -#define ODK_REGINFO 1 /* Register usage information. */ -#define ODK_EXCEPTIONS 2 /* Exception processing options. */ -#define ODK_PAD 3 /* Section padding options. */ -#define ODK_HWPATCH 4 /* Hardware workarounds performed */ -#define ODK_FILL 5 /* record the fill value used by the linker. */ -#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ -#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ -#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ - -/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ - -#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ -#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ -#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ -#define OEX_SMM 0x20000 /* Force sequential memory mode? */ -#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ -#define OEX_PRECISEFP OEX_FPDBUG -#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ - -#define OEX_FPU_INVAL 0x10 -#define OEX_FPU_DIV0 0x08 -#define OEX_FPU_OFLO 0x04 -#define OEX_FPU_UFLO 0x02 -#define OEX_FPU_INEX 0x01 - -/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ - -#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ -#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ -#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ -#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ - -#define OPAD_PREFIX 0x1 -#define OPAD_POSTFIX 0x2 -#define OPAD_SYMBOL 0x4 - -/* Entry found in `.options' section. */ - -typedef struct -{ - Elf32_Word hwp_flags1; /* Extra flags. */ - Elf32_Word hwp_flags2; /* Extra flags. */ -} Elf_Options_Hw; - -/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ - -#define OHWA0_R4KEOP_CHECKED 0x00000001 -#define OHWA1_R4KEOP_CLEAN 0x00000002 - -/* MIPS relocs. */ - -#define R_MIPS_NONE 0 /* No reloc */ -#define R_MIPS_16 1 /* Direct 16 bit */ -#define R_MIPS_32 2 /* Direct 32 bit */ -#define R_MIPS_REL32 3 /* PC relative 32 bit */ -#define R_MIPS_26 4 /* Direct 26 bit shifted */ -#define R_MIPS_HI16 5 /* High 16 bit */ -#define R_MIPS_LO16 6 /* Low 16 bit */ -#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ -#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ -#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ -#define R_MIPS_PC16 10 /* PC relative 16 bit */ -#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ -#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ - -#define R_MIPS_SHIFT5 16 -#define R_MIPS_SHIFT6 17 -#define R_MIPS_64 18 -#define R_MIPS_GOT_DISP 19 -#define R_MIPS_GOT_PAGE 20 -#define R_MIPS_GOT_OFST 21 -#define R_MIPS_GOT_HI16 22 -#define R_MIPS_GOT_LO16 23 -#define R_MIPS_SUB 24 -#define R_MIPS_INSERT_A 25 -#define R_MIPS_INSERT_B 26 -#define R_MIPS_DELETE 27 -#define R_MIPS_HIGHER 28 -#define R_MIPS_HIGHEST 29 -#define R_MIPS_CALL_HI16 30 -#define R_MIPS_CALL_LO16 31 -#define R_MIPS_SCN_DISP 32 -#define R_MIPS_REL16 33 -#define R_MIPS_ADD_IMMEDIATE 34 -#define R_MIPS_PJUMP 35 -#define R_MIPS_RELGOT 36 -#define R_MIPS_JALR 37 -#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ -#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ -#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ -#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ -#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ -#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ -#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ -#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ -#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ -#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ -#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ -#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ -#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ -#define R_MIPS_GLOB_DAT 51 -#define R_MIPS_COPY 126 -#define R_MIPS_JUMP_SLOT 127 -/* Keep this the last entry. */ -#define R_MIPS_NUM 128 - -/* Legal values for p_type field of Elf32_Phdr. */ - -#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ -#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ -#define PT_MIPS_OPTIONS 0x70000002 - -/* Special program header types. */ - -#define PF_MIPS_LOCAL 0x10000000 - -/* Legal values for d_tag field of Elf32_Dyn. */ - -#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ -#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ -#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ -#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ -#define DT_MIPS_FLAGS 0x70000005 /* Flags */ -#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ -#define DT_MIPS_MSYM 0x70000007 -#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ -#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ -#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ -#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ -#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ -#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ -#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ -#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ -#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ -#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ -#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ -#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in - DT_MIPS_DELTA_CLASS. */ -#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ -#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in - DT_MIPS_DELTA_INSTANCE. */ -#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ -#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in - DT_MIPS_DELTA_RELOC. */ -#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta - relocations refer to. */ -#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in - DT_MIPS_DELTA_SYM. */ -#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the - class declaration. */ -#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in - DT_MIPS_DELTA_CLASSSYM. */ -#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ -#define DT_MIPS_PIXIE_INIT 0x70000023 -#define DT_MIPS_SYMBOL_LIB 0x70000024 -#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 -#define DT_MIPS_LOCAL_GOTIDX 0x70000026 -#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 -#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 -#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ -#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ -#define DT_MIPS_DYNSTR_ALIGN 0x7000002b -#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ -#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve - function stored in GOT. */ -#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added - by rld on dlopen() calls. */ -#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ -#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ -#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ -/* The address of .got.plt in an executable using the new non-PIC ABI. */ -#define DT_MIPS_PLTGOT 0x70000032 -/* The base of the PLT in an executable using the new non-PIC ABI if that - PLT is writable. For a non-writable PLT, this is omitted or has a zero - value. */ -#define DT_MIPS_RWPLT 0x70000034 -#define DT_MIPS_NUM 0x35 - -/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ - -#define RHF_NONE 0 /* No flags */ -#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ -#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ -#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ -#define RHF_NO_MOVE (1 << 3) -#define RHF_SGI_ONLY (1 << 4) -#define RHF_GUARANTEE_INIT (1 << 5) -#define RHF_DELTA_C_PLUS_PLUS (1 << 6) -#define RHF_GUARANTEE_START_INIT (1 << 7) -#define RHF_PIXIE (1 << 8) -#define RHF_DEFAULT_DELAY_LOAD (1 << 9) -#define RHF_REQUICKSTART (1 << 10) -#define RHF_REQUICKSTARTED (1 << 11) -#define RHF_CORD (1 << 12) -#define RHF_NO_UNRES_UNDEF (1 << 13) -#define RHF_RLD_ORDER_SAFE (1 << 14) - -/* Entries found in sections of type SHT_MIPS_LIBLIST. */ - -typedef struct -{ - Elf32_Word l_name; /* Name (string table index) */ - Elf32_Word l_time_stamp; /* Timestamp */ - Elf32_Word l_checksum; /* Checksum */ - Elf32_Word l_version; /* Interface version */ - Elf32_Word l_flags; /* Flags */ -} Elf32_Lib; - -typedef struct -{ - Elf64_Word l_name; /* Name (string table index) */ - Elf64_Word l_time_stamp; /* Timestamp */ - Elf64_Word l_checksum; /* Checksum */ - Elf64_Word l_version; /* Interface version */ - Elf64_Word l_flags; /* Flags */ -} Elf64_Lib; - - -/* Legal values for l_flags. */ - -#define LL_NONE 0 -#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ -#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ -#define LL_REQUIRE_MINOR (1 << 2) -#define LL_EXPORTS (1 << 3) -#define LL_DELAY_LOAD (1 << 4) -#define LL_DELTA (1 << 5) - -/* Entries found in sections of type SHT_MIPS_CONFLICT. */ - -typedef Elf32_Addr Elf32_Conflict; - - -/* HPPA specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ -#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ -#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ -#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ -#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch - prediction. */ -#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ -#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ - -/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ - -#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ -#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ -#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ - -/* Additional section indices. */ - -#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tentatively declared - symbols in ANSI C. */ -#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ -#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ -#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ -#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ -#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ - -#define STT_HP_OPAQUE (STT_LOOS + 0x1) -#define STT_HP_STUB (STT_LOOS + 0x2) - -/* HPPA relocs. */ - -#define R_PARISC_NONE 0 /* No reloc. */ -#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ -#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ -#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ -#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ -#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ -#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ -#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ -#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ -#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ -#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ -#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ -#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ -#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ -#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ -#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ -#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ -#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ -#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ -#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ -#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ -#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ -#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ -#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ -#define R_PARISC_FPTR64 64 /* 64 bits function address. */ -#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ -#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ -#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ -#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ -#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ -#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ -#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ -#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ -#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ -#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ -#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ -#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ -#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ -#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ -#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ -#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ -#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ -#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ -#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ -#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ -#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ -#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LORESERVE 128 -#define R_PARISC_COPY 128 /* Copy relocation. */ -#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ -#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ -#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ -#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ -#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ -#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ -#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ -#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ -#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_GNU_VTENTRY 232 -#define R_PARISC_GNU_VTINHERIT 233 -#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ -#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ -#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ -#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ -#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ -#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ -#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ -#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ -#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ -#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ -#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ -#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ -#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L -#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R -#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L -#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R -#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 -#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 -#define R_PARISC_HIRESERVE 255 - -/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ - -#define PT_HP_TLS (PT_LOOS + 0x0) -#define PT_HP_CORE_NONE (PT_LOOS + 0x1) -#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) -#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) -#define PT_HP_CORE_COMM (PT_LOOS + 0x4) -#define PT_HP_CORE_PROC (PT_LOOS + 0x5) -#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) -#define PT_HP_CORE_STACK (PT_LOOS + 0x7) -#define PT_HP_CORE_SHM (PT_LOOS + 0x8) -#define PT_HP_CORE_MMF (PT_LOOS + 0x9) -#define PT_HP_PARALLEL (PT_LOOS + 0x10) -#define PT_HP_FASTBIND (PT_LOOS + 0x11) -#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) -#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) -#define PT_HP_STACK (PT_LOOS + 0x14) - -#define PT_PARISC_ARCHEXT 0x70000000 -#define PT_PARISC_UNWIND 0x70000001 - -/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ - -#define PF_PARISC_SBP 0x08000000 - -#define PF_HP_PAGE_SIZE 0x00100000 -#define PF_HP_FAR_SHARED 0x00200000 -#define PF_HP_NEAR_SHARED 0x00400000 -#define PF_HP_CODE 0x01000000 -#define PF_HP_MODIFY 0x02000000 -#define PF_HP_LAZYSWAP 0x04000000 -#define PF_HP_SBP 0x08000000 - - -/* Alpha specific definitions. */ - -/* Legal values for e_flags field of Elf64_Ehdr. */ - -#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ -#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ - -/* Legal values for sh_type field of Elf64_Shdr. */ - -/* These two are primarily concerned with ECOFF debugging info. */ -#define SHT_ALPHA_DEBUG 0x70000001 -#define SHT_ALPHA_REGINFO 0x70000002 - -/* Legal values for sh_flags field of Elf64_Shdr. */ - -#define SHF_ALPHA_GPREL 0x10000000 - -/* Legal values for st_other field of Elf64_Sym. */ -#define STO_ALPHA_NOPV 0x80 /* No PV required. */ -#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ - -/* Alpha relocs. */ - -#define R_ALPHA_NONE 0 /* No reloc */ -#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ -#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ -#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ -#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ -#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ -#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ -#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ -#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ -#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ -#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ -#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ -#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ -#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ -#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ -#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ -#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ -#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ -#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ -#define R_ALPHA_TLS_GD_HI 28 -#define R_ALPHA_TLSGD 29 -#define R_ALPHA_TLS_LDM 30 -#define R_ALPHA_DTPMOD64 31 -#define R_ALPHA_GOTDTPREL 32 -#define R_ALPHA_DTPREL64 33 -#define R_ALPHA_DTPRELHI 34 -#define R_ALPHA_DTPRELLO 35 -#define R_ALPHA_DTPREL16 36 -#define R_ALPHA_GOTTPREL 37 -#define R_ALPHA_TPREL64 38 -#define R_ALPHA_TPRELHI 39 -#define R_ALPHA_TPRELLO 40 -#define R_ALPHA_TPREL16 41 -/* Keep this the last entry. */ -#define R_ALPHA_NUM 46 - -/* Magic values of the LITUSE relocation addend. */ -#define LITUSE_ALPHA_ADDR 0 -#define LITUSE_ALPHA_BASE 1 -#define LITUSE_ALPHA_BYTOFF 2 -#define LITUSE_ALPHA_JSR 3 -#define LITUSE_ALPHA_TLS_GD 4 -#define LITUSE_ALPHA_TLS_LDM 5 - -/* Legal values for d_tag of Elf64_Dyn. */ -#define DT_ALPHA_PLTRO (DT_LOPROC + 0) -#define DT_ALPHA_NUM 1 - -/* PowerPC specific declarations */ - -/* Values for Elf32/64_Ehdr.e_flags. */ -#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ - -/* Cygnus local bits below */ -#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ -#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib - flag */ - -/* PowerPC relocations defined by the ABIs */ -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 /* 32bit absolute address */ -#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ -#define R_PPC_ADDR16 3 /* 16bit absolute address */ -#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ -#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ -#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ -#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ -#define R_PPC_ADDR14_BRTAKEN 8 -#define R_PPC_ADDR14_BRNTAKEN 9 -#define R_PPC_REL24 10 /* PC relative 26 bit */ -#define R_PPC_REL14 11 /* PC relative 16 bit */ -#define R_PPC_REL14_BRTAKEN 12 -#define R_PPC_REL14_BRNTAKEN 13 -#define R_PPC_GOT16 14 -#define R_PPC_GOT16_LO 15 -#define R_PPC_GOT16_HI 16 -#define R_PPC_GOT16_HA 17 -#define R_PPC_PLTREL24 18 -#define R_PPC_COPY 19 -#define R_PPC_GLOB_DAT 20 -#define R_PPC_JMP_SLOT 21 -#define R_PPC_RELATIVE 22 -#define R_PPC_LOCAL24PC 23 -#define R_PPC_UADDR32 24 -#define R_PPC_UADDR16 25 -#define R_PPC_REL32 26 -#define R_PPC_PLT32 27 -#define R_PPC_PLTREL32 28 -#define R_PPC_PLT16_LO 29 -#define R_PPC_PLT16_HI 30 -#define R_PPC_PLT16_HA 31 -#define R_PPC_SDAREL16 32 -#define R_PPC_SECTOFF 33 -#define R_PPC_SECTOFF_LO 34 -#define R_PPC_SECTOFF_HI 35 -#define R_PPC_SECTOFF_HA 36 - -/* PowerPC relocations defined for the TLS access ABI. */ -#define R_PPC_TLS 67 /* none (sym+add)@tls */ -#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ -#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ -#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ -#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ -#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ -#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ -#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ -#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ -#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ -#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ -#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ -#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ -#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ -#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ -#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ -#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ -#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ -#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ -#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ -#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ -#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ -#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ -#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ -#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ -#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ -#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ -#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ - -/* The remaining relocs are from the Embedded ELF ABI, and are not - in the SVR4 ELF ABI. */ -#define R_PPC_EMB_NADDR32 101 -#define R_PPC_EMB_NADDR16 102 -#define R_PPC_EMB_NADDR16_LO 103 -#define R_PPC_EMB_NADDR16_HI 104 -#define R_PPC_EMB_NADDR16_HA 105 -#define R_PPC_EMB_SDAI16 106 -#define R_PPC_EMB_SDA2I16 107 -#define R_PPC_EMB_SDA2REL 108 -#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ -#define R_PPC_EMB_MRKREF 110 -#define R_PPC_EMB_RELSEC16 111 -#define R_PPC_EMB_RELST_LO 112 -#define R_PPC_EMB_RELST_HI 113 -#define R_PPC_EMB_RELST_HA 114 -#define R_PPC_EMB_BIT_FLD 115 -#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ - -/* Diab tool relocations. */ -#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ -#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ -#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ -#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ -#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ -#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ - -/* GNU extension to support local ifunc. */ -#define R_PPC_IRELATIVE 248 - -/* GNU relocs used in PIC code sequences. */ -#define R_PPC_REL16 249 /* half16 (sym+add-.) */ -#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ -#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ -#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ - -/* This is a phony reloc to handle any old fashioned TOC16 references - that may still be in object files. */ -#define R_PPC_TOC16 255 - -/* PowerPC specific values for the Dyn d_tag field. */ -#define DT_PPC_GOT (DT_LOPROC + 0) -#define DT_PPC_NUM 1 - -/* PowerPC64 relocations defined by the ABIs */ -#define R_PPC64_NONE R_PPC_NONE -#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ -#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ -#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ -#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ -#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ -#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ -#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ -#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN -#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN -#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ -#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ -#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN -#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN -#define R_PPC64_GOT16 R_PPC_GOT16 -#define R_PPC64_GOT16_LO R_PPC_GOT16_LO -#define R_PPC64_GOT16_HI R_PPC_GOT16_HI -#define R_PPC64_GOT16_HA R_PPC_GOT16_HA - -#define R_PPC64_COPY R_PPC_COPY -#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT -#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT -#define R_PPC64_RELATIVE R_PPC_RELATIVE - -#define R_PPC64_UADDR32 R_PPC_UADDR32 -#define R_PPC64_UADDR16 R_PPC_UADDR16 -#define R_PPC64_REL32 R_PPC_REL32 -#define R_PPC64_PLT32 R_PPC_PLT32 -#define R_PPC64_PLTREL32 R_PPC_PLTREL32 -#define R_PPC64_PLT16_LO R_PPC_PLT16_LO -#define R_PPC64_PLT16_HI R_PPC_PLT16_HI -#define R_PPC64_PLT16_HA R_PPC_PLT16_HA - -#define R_PPC64_SECTOFF R_PPC_SECTOFF -#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO -#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI -#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA -#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ -#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ -#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ -#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ -#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ -#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ -#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ -#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ -#define R_PPC64_PLT64 45 /* doubleword64 L + A */ -#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ -#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ -#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ -#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ -#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ -#define R_PPC64_TOC 51 /* doubleword64 .TOC */ -#define R_PPC64_PLTGOT16 52 /* half16* M + A */ -#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ -#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ -#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ - -#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ -#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ -#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ -#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ -#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ -#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ -#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ -#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ -#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ -#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ -#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ - -/* PowerPC64 relocations defined for the TLS access ABI. */ -#define R_PPC64_TLS 67 /* none (sym+add)@tls */ -#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ -#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ -#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ -#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ -#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ -#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ -#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ -#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ -#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ -#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ -#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ -#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ -#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ -#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ -#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ -#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ -#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ -#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ -#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ -#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ -#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ -#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ -#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ -#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ -#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ -#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ -#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ -#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ -#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ -#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ -#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ -#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ -#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ -#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ -#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ -#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ -#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ -#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ -#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ - -/* GNU extension to support local ifunc. */ -#define R_PPC64_JMP_IREL 247 -#define R_PPC64_IRELATIVE 248 -#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ -#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ -#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ -#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ - -/* PowerPC64 specific values for the Dyn d_tag field. */ -#define DT_PPC64_GLINK (DT_LOPROC + 0) -#define DT_PPC64_OPD (DT_LOPROC + 1) -#define DT_PPC64_OPDSZ (DT_LOPROC + 2) -#define DT_PPC64_NUM 3 - - -/* ARM specific declarations */ - -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_ARM_RELEXEC 0x01 -#define EF_ARM_HASENTRY 0x02 -#define EF_ARM_INTERWORK 0x04 -#define EF_ARM_APCS_26 0x08 -#define EF_ARM_APCS_FLOAT 0x10 -#define EF_ARM_PIC 0x20 -#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ -#define EF_ARM_NEW_ABI 0x80 -#define EF_ARM_OLD_ABI 0x100 -#define EF_ARM_SOFT_FLOAT 0x200 -#define EF_ARM_VFP_FLOAT 0x400 -#define EF_ARM_MAVERICK_FLOAT 0x800 - -#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ -#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ - - -/* Other constants defined in the ARM ELF spec. version B-01. */ -/* NB. These conflict with values defined above. */ -#define EF_ARM_SYMSARESORTED 0x04 -#define EF_ARM_DYNSYMSUSESEGIDX 0x08 -#define EF_ARM_MAPSYMSFIRST 0x10 -#define EF_ARM_EABIMASK 0XFF000000 - -/* Constants defined in AAELF. */ -#define EF_ARM_BE8 0x00800000 -#define EF_ARM_LE8 0x00400000 - -#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) -#define EF_ARM_EABI_UNKNOWN 0x00000000 -#define EF_ARM_EABI_VER1 0x01000000 -#define EF_ARM_EABI_VER2 0x02000000 -#define EF_ARM_EABI_VER3 0x03000000 -#define EF_ARM_EABI_VER4 0x04000000 -#define EF_ARM_EABI_VER5 0x05000000 - -/* Additional symbol types for Thumb. */ -#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ -#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ - -/* ARM-specific values for sh_flags */ -#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ -#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined - in the input to a link step. */ - -/* ARM-specific program header flags */ -#define PF_ARM_SB 0x10000000 /* Segment contains the location - addressed by the static base. */ -#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ -#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ - -/* Processor specific values for the Phdr p_type field. */ -#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ - -/* Processor specific values for the Shdr sh_type field. */ -#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ -#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ -#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ - - -/* AArch64 relocs. */ - -#define R_AARCH64_NONE 0 /* No relocation. */ -#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ -#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ -#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ -#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ -#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ -#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ -#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ -#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ -#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ -#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ -#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ -#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ -#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ -#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ -#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ -#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ -#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ -#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ -#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ -#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ -#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ -#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ -#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ -#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ -#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ -#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ -#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ -#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ -#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ -#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ -#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ -#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ -#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ -#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ -#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ -#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ -#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ -#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ -#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ -#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ -#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ -#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ -#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ -#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ -#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ -#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ -#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ -#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ -#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ -#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ -#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ -#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ -#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ -#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ -#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ -#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ -#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ -#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ -#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ -#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ -#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ -#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ -#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ -#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ -#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ -#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ -#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ -#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ -#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ -#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ -#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ -#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ -#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ -#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ -#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ -#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ -#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ -#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ -#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ -#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ -#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ -#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ -#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ -#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ -#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ -#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ -#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ -#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ -#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ -#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ -/* Keep this the last entry. */ -#define R_AARCH64_NUM 1033 - -/* ARM relocs. */ - -#define R_ARM_NONE 0 /* No reloc */ -#define R_ARM_PC24 1 /* PC relative 26 bit branch */ -#define R_ARM_ABS32 2 /* Direct 32 bit */ -#define R_ARM_REL32 3 /* PC relative 32 bit */ -#define R_ARM_PC13 4 -#define R_ARM_ABS16 5 /* Direct 16 bit */ -#define R_ARM_ABS12 6 /* Direct 12 bit */ -#define R_ARM_THM_ABS5 7 -#define R_ARM_ABS8 8 /* Direct 8 bit */ -#define R_ARM_SBREL32 9 -#define R_ARM_THM_PC22 10 -#define R_ARM_THM_PC8 11 -#define R_ARM_AMP_VCALL9 12 -#define R_ARM_SWI24 13 /* Obsolete static relocation. */ -#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ -#define R_ARM_THM_SWI8 14 -#define R_ARM_XPC25 15 -#define R_ARM_THM_XPC22 16 -#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ -#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ -#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ -#define R_ARM_COPY 20 /* Copy symbol at runtime */ -#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ -#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ -#define R_ARM_RELATIVE 23 /* Adjust by program base */ -#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ -#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ -#define R_ARM_GOT32 26 /* 32 bit GOT entry */ -#define R_ARM_PLT32 27 /* 32 bit PLT address */ -#define R_ARM_CALL 28 -#define R_ARM_JUMP24 29 -#define R_ARM_THM_JUMP24 30 -#define R_ARM_ALU_PCREL_7_0 32 -#define R_ARM_ALU_PCREL_15_8 33 -#define R_ARM_ALU_PCREL_23_15 34 -#define R_ARM_LDR_SBREL_11_0 35 -#define R_ARM_ALU_SBREL_19_12 36 -#define R_ARM_ALU_SBREL_27_20 37 -#define R_ARM_V4BX 40 -#define R_ARM_PREL31 42 -#define R_ARM_MOVW_ABS_NC 43 -#define R_ARM_MOVT_ABS 44 -#define R_ARM_THM_MOVW_ABS_NC 47 -#define R_ARM_THM_MOVT_ABS 48 -#define R_ARM_TLS_GOTDESC 90 -#define R_ARM_TLS_CALL 91 -#define R_ARM_TLS_DESCSEQ 92 -#define R_ARM_THM_TLS_CALL 93 -#define R_ARM_GNU_VTENTRY 100 -#define R_ARM_GNU_VTINHERIT 101 -#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ -#define R_ARM_THM_PC9 103 /* thumb conditional branch */ -#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic - thread local data */ -#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic - thread local data */ -#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS - block */ -#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of - static TLS block offset */ -#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static - TLS block */ -#define R_ARM_THM_TLS_DESCSEQ 129 -#define R_ARM_IRELATIVE 160 -#define R_ARM_RXPC25 249 -#define R_ARM_RSBREL32 250 -#define R_ARM_THM_RPC22 251 -#define R_ARM_RREL32 252 -#define R_ARM_RABS22 253 -#define R_ARM_RPC24 254 -#define R_ARM_RBASE 255 -/* Keep this the last entry. */ -#define R_ARM_NUM 256 - -/* TMS320C67xx specific declarations */ - -/* XXX: no ELF standard yet*/ - -/* TMS320C67xx relocs. */ -#define R_C60_32 1 -#define R_C60_GOT32 3 /* 32 bit GOT entry */ -#define R_C60_PLT32 4 /* 32 bit PLT address */ -#define R_C60_COPY 5 /* Copy symbol at runtime */ -#define R_C60_GLOB_DAT 6 /* Create GOT entry */ -#define R_C60_JMP_SLOT 7 /* Create PLT entry */ -#define R_C60_RELATIVE 8 /* Adjust by program base */ -#define R_C60_GOTOFF 9 /* 32 bit offset to GOT */ -#define R_C60_GOTPC 10 /* 32 bit PC relative offset to GOT */ - -#define R_C60LO16 0x54 /* low 16 bit MVKL embedded */ -#define R_C60HI16 0x55 /* high 16 bit MVKH embedded */ -/* Keep this the last entry. */ -#define R_C60_NUM 0x56 - -/* IA-64 specific declarations. */ - -/* Processor specific flags for the Ehdr e_flags field. */ -#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ -#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ -#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ - -/* Processor specific values for the Phdr p_type field. */ -#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ -#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ -#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) -#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) -#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) - -/* Processor specific flags for the Phdr p_flags field. */ -#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ - -/* Processor specific values for the Shdr sh_type field. */ -#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ -#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ - -/* Processor specific flags for the Shdr sh_flags field. */ -#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ -#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ - -/* Processor specific values for the Dyn d_tag field. */ -#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) -#define DT_IA_64_NUM 1 - -/* IA-64 relocations. */ -#define R_IA64_NONE 0x00 /* none */ -#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ -#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ -#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ -#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ -#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ -#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ -#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ -#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ -#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ -#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ -#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ -#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ -#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ -#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ -#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ -#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ -#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ -#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ -#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ -#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ -#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ -#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ -#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ -#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ -#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ -#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ -#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ -#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ -#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ -#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ -#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ -#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ -#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ -#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ -#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ -#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ -#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ -#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ -#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ -#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ -#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ -#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ -#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ -#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ -#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ -#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ -#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ -#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ -#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ -#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ -#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ -#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ -#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ -#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ -#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ -#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ -#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ -#define R_IA64_COPY 0x84 /* copy relocation */ -#define R_IA64_SUB 0x85 /* Addend and symbol difference */ -#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ -#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ -#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ -#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ -#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ -#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ -#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ -#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ -#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ -#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ -#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ -#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ -#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ -#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ -#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ -#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ -#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ - -/* SH specific declarations */ - -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_SH_MACH_MASK 0x1f -#define EF_SH_UNKNOWN 0x0 -#define EF_SH1 0x1 -#define EF_SH2 0x2 -#define EF_SH3 0x3 -#define EF_SH_DSP 0x4 -#define EF_SH3_DSP 0x5 -#define EF_SH4AL_DSP 0x6 -#define EF_SH3E 0x8 -#define EF_SH4 0x9 -#define EF_SH2E 0xb -#define EF_SH4A 0xc -#define EF_SH2A 0xd -#define EF_SH4_NOFPU 0x10 -#define EF_SH4A_NOFPU 0x11 -#define EF_SH4_NOMMU_NOFPU 0x12 -#define EF_SH2A_NOFPU 0x13 -#define EF_SH3_NOMMU 0x14 -#define EF_SH2A_SH4_NOFPU 0x15 -#define EF_SH2A_SH3_NOFPU 0x16 -#define EF_SH2A_SH4 0x17 -#define EF_SH2A_SH3E 0x18 - -/* SH relocs. */ -#define R_SH_NONE 0 -#define R_SH_DIR32 1 -#define R_SH_REL32 2 -#define R_SH_DIR8WPN 3 -#define R_SH_IND12W 4 -#define R_SH_DIR8WPL 5 -#define R_SH_DIR8WPZ 6 -#define R_SH_DIR8BP 7 -#define R_SH_DIR8W 8 -#define R_SH_DIR8L 9 -#define R_SH_SWITCH16 25 -#define R_SH_SWITCH32 26 -#define R_SH_USES 27 -#define R_SH_COUNT 28 -#define R_SH_ALIGN 29 -#define R_SH_CODE 30 -#define R_SH_DATA 31 -#define R_SH_LABEL 32 -#define R_SH_SWITCH8 33 -#define R_SH_GNU_VTINHERIT 34 -#define R_SH_GNU_VTENTRY 35 -#define R_SH_TLS_GD_32 144 -#define R_SH_TLS_LD_32 145 -#define R_SH_TLS_LDO_32 146 -#define R_SH_TLS_IE_32 147 -#define R_SH_TLS_LE_32 148 -#define R_SH_TLS_DTPMOD32 149 -#define R_SH_TLS_DTPOFF32 150 -#define R_SH_TLS_TPOFF32 151 -#define R_SH_GOT32 160 -#define R_SH_PLT32 161 -#define R_SH_COPY 162 -#define R_SH_GLOB_DAT 163 -#define R_SH_JMP_SLOT 164 -#define R_SH_RELATIVE 165 -#define R_SH_GOTOFF 166 -#define R_SH_GOTPC 167 -/* Keep this the last entry. */ -#define R_SH_NUM 256 - -/* S/390 specific definitions. */ - -/* Valid values for the e_flags field. */ - -#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ - -/* Additional s390 relocs */ - -#define R_390_NONE 0 /* No reloc. */ -#define R_390_8 1 /* Direct 8 bit. */ -#define R_390_12 2 /* Direct 12 bit. */ -#define R_390_16 3 /* Direct 16 bit. */ -#define R_390_32 4 /* Direct 32 bit. */ -#define R_390_PC32 5 /* PC relative 32 bit. */ -#define R_390_GOT12 6 /* 12 bit GOT offset. */ -#define R_390_GOT32 7 /* 32 bit GOT offset. */ -#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ -#define R_390_COPY 9 /* Copy symbol at runtime. */ -#define R_390_GLOB_DAT 10 /* Create GOT entry. */ -#define R_390_JMP_SLOT 11 /* Create PLT entry. */ -#define R_390_RELATIVE 12 /* Adjust by program base. */ -#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ -#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ -#define R_390_GOT16 15 /* 16 bit GOT offset. */ -#define R_390_PC16 16 /* PC relative 16 bit. */ -#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ -#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ -#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ -#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ -#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ -#define R_390_64 22 /* Direct 64 bit. */ -#define R_390_PC64 23 /* PC relative 64 bit. */ -#define R_390_GOT64 24 /* 64 bit GOT offset. */ -#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ -#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ -#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ -#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ -#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ -#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ -#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ -#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ -#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ -#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ -#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ -#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ -#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ -#define R_390_TLS_GDCALL 38 /* Tag for function call in general - dynamic TLS code. */ -#define R_390_TLS_LDCALL 39 /* Tag for function call in local - dynamic TLS code. */ -#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic - thread local data. */ -#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic - thread local data. */ -#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic - thread local data in LE code. */ -#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic - thread local data in LE code. */ -#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS - block. */ -#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS - block. */ -#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ -#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ -#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS - block. */ -#define R_390_20 57 /* Direct 20 bit. */ -#define R_390_GOT20 58 /* 20 bit GOT offset. */ -#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ -#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS - block offset. */ -#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ -/* Keep this the last entry. */ -#define R_390_NUM 62 - - -/* CRIS relocations. */ -#define R_CRIS_NONE 0 -#define R_CRIS_8 1 -#define R_CRIS_16 2 -#define R_CRIS_32 3 -#define R_CRIS_8_PCREL 4 -#define R_CRIS_16_PCREL 5 -#define R_CRIS_32_PCREL 6 -#define R_CRIS_GNU_VTINHERIT 7 -#define R_CRIS_GNU_VTENTRY 8 -#define R_CRIS_COPY 9 -#define R_CRIS_GLOB_DAT 10 -#define R_CRIS_JUMP_SLOT 11 -#define R_CRIS_RELATIVE 12 -#define R_CRIS_16_GOT 13 -#define R_CRIS_32_GOT 14 -#define R_CRIS_16_GOTPLT 15 -#define R_CRIS_32_GOTPLT 16 -#define R_CRIS_32_GOTREL 17 -#define R_CRIS_32_PLT_GOTREL 18 -#define R_CRIS_32_PLT_PCREL 19 - -#define R_CRIS_NUM 20 - - -/* AMD x86-64 relocations. */ -#define R_X86_64_NONE 0 /* No reloc */ -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_COPY 5 /* Copy symbol at runtime */ -#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ -#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ -#define R_X86_64_RELATIVE 8 /* Adjust by program base */ -#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative - offset to GOT */ -#define R_X86_64_32 10 /* Direct 32 bit zero extended */ -#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ -#define R_X86_64_16 12 /* Direct 16 bit zero extended */ -#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ -#define R_X86_64_8 14 /* Direct 8 bit sign extended */ -#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ -#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ -#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ -#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ -#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset - to two GOT entries for GD symbol */ -#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset - to two GOT entries for LD symbol */ -#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ -#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset - to GOT entry for IE symbol */ -#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ -#define R_X86_64_PC64 24 /* PC relative 64 bit */ -#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ -#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative - offset to GOT */ -#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ -#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset - to GOT entry */ -#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ -#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ -#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset - to PLT entry */ -#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ -#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ -#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ -#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS - descriptor. */ -#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ -#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ -#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ -#define R_X86_64_GOTPCRELX 41 /* like GOTPCREL, but optionally with - linker optimizations */ -#define R_X86_64_REX_GOTPCRELX 42 /* like GOTPCRELX, but a REX prefix - is present */ - -#define R_X86_64_NUM 43 - - -/* AM33 relocations. */ -#define R_MN10300_NONE 0 /* No reloc. */ -#define R_MN10300_32 1 /* Direct 32 bit. */ -#define R_MN10300_16 2 /* Direct 16 bit. */ -#define R_MN10300_8 3 /* Direct 8 bit. */ -#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ -#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ -#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ -#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ -#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ -#define R_MN10300_24 9 /* Direct 24 bit. */ -#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ -#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ -#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ -#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ -#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ -#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ -#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ -#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ -#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ -#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ -#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ -#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ -#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ -#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ -#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ -#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ -#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ -#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block - offset. */ -#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block - offset. */ -#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS - block. */ -#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ -#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ -#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ -#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed - by linker relaxation. */ -#define R_MN10300_ALIGN 34 /* Alignment requirement for linker - relaxation. */ -#define R_MN10300_NUM 35 - - -/* M32R relocs. */ -#define R_M32R_NONE 0 /* No reloc. */ -#define R_M32R_16 1 /* Direct 16 bit. */ -#define R_M32R_32 2 /* Direct 32 bit. */ -#define R_M32R_24 3 /* Direct 24 bit. */ -#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ -#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ -#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ -#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ -#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ -#define R_M32R_LO16 9 /* Low 16 bit. */ -#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ -#define R_M32R_GNU_VTINHERIT 11 -#define R_M32R_GNU_VTENTRY 12 -/* M32R relocs use SHT_RELA. */ -#define R_M32R_16_RELA 33 /* Direct 16 bit. */ -#define R_M32R_32_RELA 34 /* Direct 32 bit. */ -#define R_M32R_24_RELA 35 /* Direct 24 bit. */ -#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ -#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ -#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ -#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ -#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ -#define R_M32R_LO16_RELA 41 /* Low 16 bit */ -#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ -#define R_M32R_RELA_GNU_VTINHERIT 43 -#define R_M32R_RELA_GNU_VTENTRY 44 -#define R_M32R_REL32 45 /* PC relative 32 bit. */ - -#define R_M32R_GOT24 48 /* 24 bit GOT entry */ -#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ -#define R_M32R_COPY 50 /* Copy symbol at runtime */ -#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ -#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ -#define R_M32R_RELATIVE 53 /* Adjust by program base */ -#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ -#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ -#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned - low */ -#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed - low */ -#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ -#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to - GOT with unsigned low */ -#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to - GOT with signed low */ -#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to - GOT */ -#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT - with unsigned low */ -#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT - with signed low */ -#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ -#define R_M32R_NUM 256 /* Keep this the last entry. */ - - -/* TILEPro relocations. */ -#define R_TILEPRO_NONE 0 /* No reloc */ -#define R_TILEPRO_32 1 /* Direct 32 bit */ -#define R_TILEPRO_16 2 /* Direct 16 bit */ -#define R_TILEPRO_8 3 /* Direct 8 bit */ -#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ -#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ -#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ -#define R_TILEPRO_LO16 7 /* Low 16 bit */ -#define R_TILEPRO_HI16 8 /* High 16 bit */ -#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ -#define R_TILEPRO_COPY 10 /* Copy relocation */ -#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ -#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ -#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ -#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ -#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ -#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ -#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ -#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ -#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ -#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ -#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ -#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ -#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ -#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ -#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ -#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ -#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ -#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ -#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ -#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ -#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ -#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ -#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ -#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ -#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ -#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ -#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ -#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ -#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ -#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ -#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ -#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ -#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ -#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ -#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ -#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ -#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ -#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ -/* Relocs 56-59 are currently not defined. */ -#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ -#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ -#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ -#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ -#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ -#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ -#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ -#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ - -#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ -#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ - -#define R_TILEPRO_NUM 130 - - -/* TILE-Gx relocations. */ -#define R_TILEGX_NONE 0 /* No reloc */ -#define R_TILEGX_64 1 /* Direct 64 bit */ -#define R_TILEGX_32 2 /* Direct 32 bit */ -#define R_TILEGX_16 3 /* Direct 16 bit */ -#define R_TILEGX_8 4 /* Direct 8 bit */ -#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ -#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ -#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ -#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ -#define R_TILEGX_HW0 9 /* hword 0 16-bit */ -#define R_TILEGX_HW1 10 /* hword 1 16-bit */ -#define R_TILEGX_HW2 11 /* hword 2 16-bit */ -#define R_TILEGX_HW3 12 /* hword 3 16-bit */ -#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ -#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ -#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ -#define R_TILEGX_COPY 16 /* Copy relocation */ -#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ -#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ -#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ -#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ -#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ -#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ -#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ -#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ -#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ -#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ -#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ -#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ -#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ -#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ -#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ -#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ -#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ -#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ -#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ -#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ -#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ -#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ -#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ -#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ -#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ -#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ -#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ -#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ -#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ -#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ -#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ -#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ -#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ -#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ -#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ -#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ -#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ -/* Relocs 90-91 are currently not defined. */ -#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ -#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ -/* Relocs 104-105 are currently not defined. */ -#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ -#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ -#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ -#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ -#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ -#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ -#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ -#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ -#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ -#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ - -#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ -#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ - -#define R_TILEGX_NUM 130 - - -#endif /* elf.h */ diff --git a/tinyc/examples/ex1.c b/tinyc/examples/ex1.c deleted file mode 100644 index 3d2a3e18f..000000000 --- a/tinyc/examples/ex1.c +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/local/bin/tcc -run -#include - -int main() -{ - printf("Hello World\n"); - return 0; -} diff --git a/tinyc/examples/ex2.c b/tinyc/examples/ex2.c deleted file mode 100644 index d415e39d7..000000000 --- a/tinyc/examples/ex2.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include - -#define N 20 - -int nb_num; -int tab[N]; -int stack_ptr; -int stack_op[N]; -int stack_res[60]; -int result; - -int find(int n, int i1, int a, int b, int op) -{ - int i, j; - int c; - - if (stack_ptr >= 0) { - stack_res[3*stack_ptr] = a; - stack_op[stack_ptr] = op; - stack_res[3*stack_ptr+1] = b; - stack_res[3*stack_ptr+2] = n; - if (n == result) - return 1; - tab[i1] = n; - } - - for(i=0;i - -int fib(n) -{ - if (n <= 2) - return 1; - else - return fib(n-1) + fib(n-2); -} - -int main(int argc, char **argv) -{ - int n; - if (argc < 2) { - printf("usage: fib n\n" - "Compute nth Fibonacci number\n"); - return 1; - } - - n = atoi(argv[1]); - printf("fib(%d) = %d\n", n, fib(n, 2)); - return 0; -} diff --git a/tinyc/examples/ex4.c b/tinyc/examples/ex4.c deleted file mode 100644 index f92c0da9f..000000000 --- a/tinyc/examples/ex4.c +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 -#include -#include -#include - -/* Yes, TCC can use X11 too ! */ - -int main(int argc, char **argv) -{ - Display *display; - Screen *screen; - - display = XOpenDisplay(""); - if (!display) { - fprintf(stderr, "Could not open X11 display\n"); - exit(1); - } - printf("X11 display opened.\n"); - screen = XScreenOfDisplay(display, 0); - printf("width = %d\nheight = %d\ndepth = %d\n", - screen->width, - screen->height, - screen->root_depth); - XCloseDisplay(display); - return 0; -} diff --git a/tinyc/examples/ex5.c b/tinyc/examples/ex5.c deleted file mode 100644 index 156425e39..000000000 --- a/tinyc/examples/ex5.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -int main() -{ - printf("Hello World\n"); - return 0; -} diff --git a/tinyc/i386-asm.c b/tinyc/i386-asm.c deleted file mode 100644 index 2e184974e..000000000 --- a/tinyc/i386-asm.c +++ /dev/null @@ -1,1714 +0,0 @@ -/* - * i386 specific functions for TCC assembler - * - * Copyright (c) 2001, 2002 Fabrice Bellard - * Copyright (c) 2009 Frédéric Feret (x86_64 support) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -#define MAX_OPERANDS 3 - -#define TOK_ASM_first TOK_ASM_clc -#define TOK_ASM_last TOK_ASM_emms -#define TOK_ASM_alllast TOK_ASM_subps - -#define OPC_B 0x01 /* only used with OPC_WL */ -#define OPC_WL 0x02 /* accepts w, l or no suffix */ -#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ -#define OPC_REG 0x04 /* register is added to opcode */ -#define OPC_MODRM 0x08 /* modrm encoding */ - -#define OPCT_MASK 0x70 -#define OPC_FWAIT 0x10 /* add fwait opcode */ -#define OPC_SHIFT 0x20 /* shift opcodes */ -#define OPC_ARITH 0x30 /* arithmetic opcodes */ -#define OPC_FARITH 0x40 /* FPU arithmetic opcodes */ -#define OPC_TEST 0x50 /* test opcodes */ -#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i)) - -#define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */ -#define OPC_48 0x200 /* Always has REX prefix */ -#ifdef TCC_TARGET_X86_64 -# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ -# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ -# define OPC_WLX OPC_WLQ -# define OPC_BWLX OPC_BWLQ -#else -# define OPC_WLX OPC_WL -# define OPC_BWLX OPC_BWL -#endif - -#define OPC_GROUP_SHIFT 13 - -/* in order to compress the operand type, we use specific operands and - we or only with EA */ -enum { - OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */ -#ifdef TCC_TARGET_X86_64 - OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */ -#endif - OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */ - OPT_SEG, - OPT_ST, -#ifdef TCC_TARGET_X86_64 - OPT_REG8_LOW, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but - with REX prefix, not used in insn templates */ -#endif - OPT_IM8, - OPT_IM8S, - OPT_IM16, - OPT_IM32, -#ifdef TCC_TARGET_X86_64 - OPT_IM64, -#endif - OPT_EAX, /* %al, %ax, %eax or %rax register */ - OPT_ST0, /* %st(0) register */ - OPT_CL, /* %cl register */ - OPT_DX, /* %dx register */ - OPT_ADDR, /* OP_EA with only offset */ - OPT_INDIR, /* *(expr) */ - /* composite types */ - OPT_COMPOSITE_FIRST, - OPT_IM, /* IM8 | IM16 | IM32 */ - OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ - OPT_REGW, /* REG16 | REG32 | REG64 */ - OPT_IMW, /* IM16 | IM32 */ - OPT_MMXSSE, /* MMX | SSE */ - OPT_DISP, /* Like OPT_ADDR, but emitted as displacement (for jumps) */ - OPT_DISP8, /* Like OPT_ADDR, but only 8bit (short jumps) */ - /* can be ored with any OPT_xxx */ - OPT_EA = 0x80 -}; - -#define OP_REG8 (1 << OPT_REG8) -#define OP_REG16 (1 << OPT_REG16) -#define OP_REG32 (1 << OPT_REG32) -#define OP_MMX (1 << OPT_MMX) -#define OP_SSE (1 << OPT_SSE) -#define OP_CR (1 << OPT_CR) -#define OP_TR (1 << OPT_TR) -#define OP_DB (1 << OPT_DB) -#define OP_SEG (1 << OPT_SEG) -#define OP_ST (1 << OPT_ST) -#define OP_IM8 (1 << OPT_IM8) -#define OP_IM8S (1 << OPT_IM8S) -#define OP_IM16 (1 << OPT_IM16) -#define OP_IM32 (1 << OPT_IM32) -#define OP_EAX (1 << OPT_EAX) -#define OP_ST0 (1 << OPT_ST0) -#define OP_CL (1 << OPT_CL) -#define OP_DX (1 << OPT_DX) -#define OP_ADDR (1 << OPT_ADDR) -#define OP_INDIR (1 << OPT_INDIR) -#ifdef TCC_TARGET_X86_64 -# define OP_REG64 (1 << OPT_REG64) -# define OP_REG8_LOW (1 << OPT_REG8_LOW) -# define OP_IM64 (1 << OPT_IM64) -# define OP_EA32 (OP_EA << 1) -#else -# define OP_REG64 0 -# define OP_REG8_LOW 0 -# define OP_IM64 0 -# define OP_EA32 0 -#endif - -#define OP_EA 0x40000000 -#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) - -#ifdef TCC_TARGET_X86_64 -# define TREG_XAX TREG_RAX -# define TREG_XCX TREG_RCX -# define TREG_XDX TREG_RDX -#else -# define TREG_XAX TREG_EAX -# define TREG_XCX TREG_ECX -# define TREG_XDX TREG_EDX -#endif - -typedef struct ASMInstr { - uint16_t sym; - uint16_t opcode; - uint16_t instr_type; - uint8_t nb_ops; - uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ -} ASMInstr; - -typedef struct Operand { - uint32_t type; - int8_t reg; /* register, -1 if none */ - int8_t reg2; /* second register, -1 if none */ - uint8_t shift; - ExprValue e; -} Operand; - -static const uint8_t reg_to_size[9] = { -/* - [OP_REG8] = 0, - [OP_REG16] = 1, - [OP_REG32] = 2, -#ifdef TCC_TARGET_X86_64 - [OP_REG64] = 3, -#endif -*/ - 0, 0, 1, 0, 2, 0, 0, 0, 3 -}; - -#define NB_TEST_OPCODES 30 - -static const uint8_t test_bits[NB_TEST_OPCODES] = { - 0x00, /* o */ - 0x01, /* no */ - 0x02, /* b */ - 0x02, /* c */ - 0x02, /* nae */ - 0x03, /* nb */ - 0x03, /* nc */ - 0x03, /* ae */ - 0x04, /* e */ - 0x04, /* z */ - 0x05, /* ne */ - 0x05, /* nz */ - 0x06, /* be */ - 0x06, /* na */ - 0x07, /* nbe */ - 0x07, /* a */ - 0x08, /* s */ - 0x09, /* ns */ - 0x0a, /* p */ - 0x0a, /* pe */ - 0x0b, /* np */ - 0x0b, /* po */ - 0x0c, /* l */ - 0x0c, /* nge */ - 0x0d, /* nl */ - 0x0d, /* ge */ - 0x0e, /* le */ - 0x0e, /* ng */ - 0x0f, /* nle */ - 0x0f, /* g */ -}; - -static const uint8_t segment_prefixes[] = { - 0x26, /* es */ - 0x2e, /* cs */ - 0x36, /* ss */ - 0x3e, /* ds */ - 0x64, /* fs */ - 0x65 /* gs */ -}; - -static const ASMInstr asm_instrs[] = { -#define ALT(x) x -/* This removes a 0x0f in the second byte */ -#define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))) -/* This constructs instr_type from opcode, type and group. */ -#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0)) -#define DEF_ASM_OP0(name, opcode) -#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } }, -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }}, -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }}, -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }}, -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif - /* last operation */ - { 0, }, -}; - -static const uint16_t op0_codes[] = { -#define ALT(x) -#define DEF_ASM_OP0(x, opcode) opcode, -#define DEF_ASM_OP0L(name, opcode, group, instr_type) -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif -}; - -static inline int get_reg_shift(TCCState *s1) -{ - int shift, v; - v = asm_int_expr(s1); - switch(v) { - case 1: - shift = 0; - break; - case 2: - shift = 1; - break; - case 4: - shift = 2; - break; - case 8: - shift = 3; - break; - default: - expect("1, 2, 4 or 8 constant"); - shift = 0; - break; - } - return shift; -} - -#ifdef TCC_TARGET_X86_64 -static int asm_parse_numeric_reg(int t, unsigned int *type) -{ - int reg = -1; - if (t >= TOK_IDENT && t < tok_ident) { - const char *s = table_ident[t - TOK_IDENT]->str; - char c; - *type = OP_REG64; - if (*s == 'c') { - s++; - *type = OP_CR; - } - if (*s++ != 'r') - return -1; - /* Don't allow leading '0'. */ - if ((c = *s++) >= '1' && c <= '9') - reg = c - '0'; - else - return -1; - if ((c = *s) >= '0' && c <= '5') - s++, reg = reg * 10 + c - '0'; - if (reg > 15) - return -1; - if ((c = *s) == 0) - ; - else if (*type != OP_REG64) - return -1; - else if (c == 'b' && !s[1]) - *type = OP_REG8; - else if (c == 'w' && !s[1]) - *type = OP_REG16; - else if (c == 'd' && !s[1]) - *type = OP_REG32; - else - return -1; - } - return reg; -} -#endif - -static int asm_parse_reg(unsigned int *type) -{ - int reg = 0; - *type = 0; - if (tok != '%') - goto error_32; - next(); - if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { - reg = tok - TOK_ASM_eax; - *type = OP_REG32; -#ifdef TCC_TARGET_X86_64 - } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { - reg = tok - TOK_ASM_rax; - *type = OP_REG64; - } else if (tok == TOK_ASM_rip) { - reg = -2; /* Probably should use different escape code. */ - *type = OP_REG64; - } else if ((reg = asm_parse_numeric_reg(tok, type)) >= 0 - && (*type == OP_REG32 || *type == OP_REG64)) { - ; -#endif - } else { - error_32: - expect("register"); - } - next(); - return reg; -} - -static void parse_operand(TCCState *s1, Operand *op) -{ - ExprValue e; - int reg, indir; - const char *p; - - indir = 0; - if (tok == '*') { - next(); - indir = OP_INDIR; - } - - if (tok == '%') { - next(); - if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) { - reg = tok - TOK_ASM_al; - op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ - op->reg = reg & 7; - if ((op->type & OP_REG) && op->reg == TREG_XAX) - op->type |= OP_EAX; - else if (op->type == OP_REG8 && op->reg == TREG_XCX) - op->type |= OP_CL; - else if (op->type == OP_REG16 && op->reg == TREG_XDX) - op->type |= OP_DX; - } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { - op->type = OP_DB; - op->reg = tok - TOK_ASM_dr0; - } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) { - op->type = OP_SEG; - op->reg = tok - TOK_ASM_es; - } else if (tok == TOK_ASM_st) { - op->type = OP_ST; - op->reg = 0; - next(); - if (tok == '(') { - next(); - if (tok != TOK_PPNUM) - goto reg_error; - p = tokc.str.data; - reg = p[0] - '0'; - if ((unsigned)reg >= 8 || p[1] != '\0') - goto reg_error; - op->reg = reg; - next(); - skip(')'); - } - if (op->reg == 0) - op->type |= OP_ST0; - goto no_skip; -#ifdef TCC_TARGET_X86_64 - } else if (tok >= TOK_ASM_spl && tok <= TOK_ASM_dil) { - op->type = OP_REG8 | OP_REG8_LOW; - op->reg = 4 + tok - TOK_ASM_spl; - } else if ((op->reg = asm_parse_numeric_reg(tok, &op->type)) >= 0) { - ; -#endif - } else { - reg_error: - tcc_error("unknown register %%%s", get_tok_str(tok, &tokc)); - } - next(); - no_skip: ; - } else if (tok == '$') { - /* constant value */ - next(); - asm_expr(s1, &e); - op->type = OP_IM32; - op->e = e; - if (!op->e.sym) { - if (op->e.v == (uint8_t)op->e.v) - op->type |= OP_IM8; - if (op->e.v == (int8_t)op->e.v) - op->type |= OP_IM8S; - if (op->e.v == (uint16_t)op->e.v) - op->type |= OP_IM16; -#ifdef TCC_TARGET_X86_64 - if (op->e.v != (int32_t)op->e.v && op->e.v != (uint32_t)op->e.v) - op->type = OP_IM64; -#endif - } - } else { - /* address(reg,reg2,shift) with all variants */ - op->type = OP_EA; - op->reg = -1; - op->reg2 = -1; - op->shift = 0; - if (tok != '(') { - asm_expr(s1, &e); - op->e = e; - } else { - next(); - if (tok == '%') { - unget_tok('('); - op->e.v = 0; - op->e.sym = NULL; - } else { - /* bracketed offset expression */ - asm_expr(s1, &e); - if (tok != ')') - expect(")"); - next(); - op->e.v = e.v; - op->e.sym = e.sym; - } - op->e.pcrel = 0; - } - if (tok == '(') { - unsigned int type = 0; - next(); - if (tok != ',') { - op->reg = asm_parse_reg(&type); - } - if (tok == ',') { - next(); - if (tok != ',') { - op->reg2 = asm_parse_reg(&type); - } - if (tok == ',') { - next(); - op->shift = get_reg_shift(s1); - } - } - if (type & OP_REG32) - op->type |= OP_EA32; - skip(')'); - } - if (op->reg == -1 && op->reg2 == -1) - op->type |= OP_ADDR; - } - op->type |= indir; -} - -/* XXX: unify with C code output ? */ -ST_FUNC void gen_expr32(ExprValue *pe) -{ - if (pe->pcrel) - /* If PC-relative, always set VT_SYM, even without symbol, - so as to force a relocation to be emitted. */ - gen_addrpc32(VT_SYM, pe->sym, pe->v); - else - gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); -} - -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_expr64(ExprValue *pe) -{ - gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); -} -#endif - -/* XXX: unify with C code output ? */ -static void gen_disp32(ExprValue *pe) -{ - Sym *sym = pe->sym; - if (sym && sym->r == cur_text_section->sh_num) { - /* same section: we can output an absolute value. Note - that the TCC compiler behaves differently here because - it always outputs a relocation to ease (future) code - elimination in the linker */ - gen_le32(pe->v + sym->jnext - ind - 4); - } else { - if (sym && sym->type.t == VT_VOID) { - sym->type.t = VT_FUNC; - sym->type.ref = NULL; - } - gen_addrpc32(VT_SYM, sym, pe->v); - } -} - -/* generate the modrm operand */ -static inline int asm_modrm(int reg, Operand *op) -{ - int mod, reg1, reg2, sib_reg1; - - if (op->type & (OP_REG | OP_MMX | OP_SSE)) { - g(0xc0 + (reg << 3) + op->reg); - } else if (op->reg == -1 && op->reg2 == -1) { - /* displacement only */ -#ifdef TCC_TARGET_X86_64 - g(0x04 + (reg << 3)); - g(0x25); -#else - g(0x05 + (reg << 3)); -#endif - gen_expr32(&op->e); -#ifdef TCC_TARGET_X86_64 - } else if (op->reg == -2) { - ExprValue *pe = &op->e; - g(0x05 + (reg << 3)); - gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); - return ind; -#endif - } else { - sib_reg1 = op->reg; - /* fist compute displacement encoding */ - if (sib_reg1 == -1) { - sib_reg1 = 5; - mod = 0x00; - } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) { - mod = 0x00; - } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) { - mod = 0x40; - } else { - mod = 0x80; - } - /* compute if sib byte needed */ - reg1 = op->reg; - if (op->reg2 != -1) - reg1 = 4; - g(mod + (reg << 3) + reg1); - if (reg1 == 4) { - /* add sib byte */ - reg2 = op->reg2; - if (reg2 == -1) - reg2 = 4; /* indicate no index */ - g((op->shift << 6) + (reg2 << 3) + sib_reg1); - } - /* add offset */ - if (mod == 0x40) { - g(op->e.v); - } else if (mod == 0x80 || op->reg == -1) { - gen_expr32(&op->e); - } - } - return 0; -} - -#ifdef TCC_TARGET_X86_64 -#define REX_W 0x48 -#define REX_R 0x44 -#define REX_X 0x42 -#define REX_B 0x41 - -static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type, - int regi, int rmi) -{ - unsigned char rex = width64 ? 0x48 : 0; - int saw_high_8bit = 0; - int i; - if (rmi == -1) { - /* No mod/rm byte, but we might have a register op nevertheless - (we will add it to the opcode later). */ - for(i = 0; i < nb_ops; i++) { - if (op_type[i] & (OP_REG | OP_ST)) { - if (ops[i].reg >= 8) { - rex |= REX_B; - ops[i].reg -= 8; - } else if (ops[i].type & OP_REG8_LOW) - rex |= 0x40; - else if (ops[i].type & OP_REG8 && ops[i].reg >= 4) - /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ - saw_high_8bit = ops[i].reg; - break; - } - } - } else { - if (regi != -1) { - if (ops[regi].reg >= 8) { - rex |= REX_R; - ops[regi].reg -= 8; - } else if (ops[regi].type & OP_REG8_LOW) - rex |= 0x40; - else if (ops[regi].type & OP_REG8 && ops[regi].reg >= 4) - /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ - saw_high_8bit = ops[regi].reg; - } - if (ops[rmi].type & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_EA)) { - if (ops[rmi].reg >= 8) { - rex |= REX_B; - ops[rmi].reg -= 8; - } else if (ops[rmi].type & OP_REG8_LOW) - rex |= 0x40; - else if (ops[rmi].type & OP_REG8 && ops[rmi].reg >= 4) - /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ - saw_high_8bit = ops[rmi].reg; - } - if (ops[rmi].type & OP_EA && ops[rmi].reg2 >= 8) { - rex |= REX_X; - ops[rmi].reg2 -= 8; - } - } - if (rex) { - if (saw_high_8bit) - tcc_error("can't encode register %%%ch when REX prefix is required", - "acdb"[saw_high_8bit-4]); - g(rex); - } -} -#endif - -static void maybe_print_stats (void) -{ - static int already = 1; - if (!already) - /* print stats about opcodes */ - { - const struct ASMInstr *pa; - int freq[4]; - int op_vals[500]; - int nb_op_vals, i, j; - - already = 1; - nb_op_vals = 0; - memset(freq, 0, sizeof(freq)); - for(pa = asm_instrs; pa->sym != 0; pa++) { - freq[pa->nb_ops]++; - //for(i=0;inb_ops;i++) { - for(j=0;jop_type[i] == op_vals[j]) - if (pa->instr_type == op_vals[j]) - goto found; - } - //op_vals[nb_op_vals++] = pa->op_type[i]; - op_vals[nb_op_vals++] = pa->instr_type; - found: ; - //} - } - for(i=0;i= TOK_ASM_wait && opcode <= TOK_ASM_repnz) - unget_tok(';'); - - /* get operands */ - pop = ops; - nb_ops = 0; - seg_prefix = 0; - alltypes = 0; - for(;;) { - if (tok == ';' || tok == TOK_LINEFEED) - break; - if (nb_ops >= MAX_OPERANDS) { - tcc_error("incorrect number of operands"); - } - parse_operand(s1, pop); - if (tok == ':') { - if (pop->type != OP_SEG || seg_prefix) - tcc_error("incorrect prefix"); - seg_prefix = segment_prefixes[pop->reg]; - next(); - parse_operand(s1, pop); - if (!(pop->type & OP_EA)) { - tcc_error("segment prefix must be followed by memory reference"); - } - } - pop++; - nb_ops++; - if (tok != ',') - break; - next(); - } - - s = 0; /* avoid warning */ - - /* optimize matching by using a lookup table (no hashing is needed - !) */ - for(pa = asm_instrs; pa->sym != 0; pa++) { - int it = pa->instr_type & OPCT_MASK; - s = 0; - if (it == OPC_FARITH) { - v = opcode - pa->sym; - if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) - continue; - } else if (it == OPC_ARITH) { - if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) - continue; - s = (opcode - pa->sym) % NBWLX; - if ((pa->instr_type & OPC_BWLX) == OPC_WLX) - { - /* We need to reject the xxxb opcodes that we accepted above. - Note that pa->sym for WLX opcodes is the 'w' token, - to get the 'b' token subtract one. */ - if (((opcode - pa->sym + 1) % NBWLX) == 0) - continue; - s++; - } - } else if (it == OPC_SHIFT) { - if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) - continue; - s = (opcode - pa->sym) % NBWLX; - } else if (it == OPC_TEST) { - if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) - continue; - /* cmovxx is a test opcode but accepts multiple sizes. - TCC doesn't accept the suffixed mnemonic, instead we - simply force size autodetection always. */ - if (pa->instr_type & OPC_WLX) - s = NBWLX - 1; - } else if (pa->instr_type & OPC_B) { -#ifdef TCC_TARGET_X86_64 - /* Some instructions don't have the full size but only - bwl form. insb e.g. */ - if ((pa->instr_type & OPC_WLQ) != OPC_WLQ - && !(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) - continue; -#endif - if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) - continue; - s = opcode - pa->sym; - } else if (pa->instr_type & OPC_WLX) { - if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) - continue; - s = opcode - pa->sym + 1; - } else { - if (pa->sym != opcode) - continue; - } - if (pa->nb_ops != nb_ops) - continue; -#ifdef TCC_TARGET_X86_64 - /* Special case for moves. Selecting the IM64->REG64 form - should only be done if we really have an >32bit imm64, and that - is hardcoded. Ignore it here. */ - if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 - && (ops[1].type & OP_REG) == OP_REG64 - && !(pa->instr_type & OPC_0F)) - continue; -#endif - /* now decode and check each operand */ - alltypes = 0; - for(i = 0; i < nb_ops; i++) { - int op1, op2; - op1 = pa->op_type[i]; - op2 = op1 & 0x1f; - switch(op2) { - case OPT_IM: - v = OP_IM8 | OP_IM16 | OP_IM32; - break; - case OPT_REG: - v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; - break; - case OPT_REGW: - v = OP_REG16 | OP_REG32 | OP_REG64; - break; - case OPT_IMW: - v = OP_IM16 | OP_IM32; - break; - case OPT_MMXSSE: - v = OP_MMX | OP_SSE; - break; - case OPT_DISP: - case OPT_DISP8: - v = OP_ADDR; - break; - default: - v = 1 << op2; - break; - } - if (op1 & OPT_EA) - v |= OP_EA; - op_type[i] = v; - if ((ops[i].type & v) == 0) - goto next; - alltypes |= ops[i].type; - } - /* all is matching ! */ - break; - next: ; - } - if (pa->sym == 0) { - if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) { - int b; - b = op0_codes[opcode - TOK_ASM_first]; - if (b & 0xff00) - g(b >> 8); - g(b); - return; - } else if (opcode <= TOK_ASM_alllast) { - tcc_error("bad operand with opcode '%s'", - get_tok_str(opcode, NULL)); - } else { - tcc_error("unknown opcode '%s'", - get_tok_str(opcode, NULL)); - } - } - /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ - autosize = NBWLX-1; -#ifdef TCC_TARGET_X86_64 - /* XXX the autosize should rather be zero, to not have to adjust this - all the time. */ - if ((pa->instr_type & OPC_BWLQ) == OPC_B) - autosize = NBWLX-2; -#endif - if (s == autosize) { - /* Check for register operands providing hints about the size. - Start from the end, i.e. destination operands. This matters - only for opcodes accepting different sized registers, lar and lsl - are such opcodes. */ - for(i = nb_ops - 1; s == autosize && i >= 0; i--) { - if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) - s = reg_to_size[ops[i].type & OP_REG]; - } - if (s == autosize) { - if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && - (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) - s = 2; - else if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && - (ops[0].type & OP_EA)) - s = NBWLX - 2; - else - tcc_error("cannot infer opcode suffix"); - } - } - -#ifdef TCC_TARGET_X86_64 - /* Generate addr32 prefix if needed */ - for(i = 0; i < nb_ops; i++) { - if (ops[i].type & OP_EA32) { - g(0x67); - break; - } - } -#endif - /* generate data16 prefix if needed */ - p66 = 0; - if (s == 1) - p66 = 1; - else { - /* accepting mmx+sse in all operands --> needs 0x66 to - switch to sse mode. Accepting only sse in an operand --> is - already SSE insn and needs 0x66/f2/f3 handling. */ - for (i = 0; i < nb_ops; i++) - if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE) - && ops[i].type & OP_SSE) - p66 = 1; - } - if (p66) - g(0x66); -#ifdef TCC_TARGET_X86_64 - rex64 = 0; - if (pa->instr_type & OPC_48) - rex64 = 1; - else if (s == 3 || (alltypes & OP_REG64)) { - /* generate REX prefix */ - int default64 = 0; - for(i = 0; i < nb_ops; i++) { - if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) { - /* If only 64bit regs are accepted in one operand - this is a default64 instruction without need for - REX prefixes, except for movabs(0xb8). */ - default64 = 1; - break; - } - } - /* XXX find better encoding for the default64 instructions. */ - if (((opcode != TOK_ASM_push && opcode != TOK_ASM_pop - && opcode != TOK_ASM_pushw && opcode != TOK_ASM_pushl - && opcode != TOK_ASM_pushq && opcode != TOK_ASM_popw - && opcode != TOK_ASM_popl && opcode != TOK_ASM_popq - && opcode != TOK_ASM_call && opcode != TOK_ASM_jmp)) - && !default64) - rex64 = 1; - } -#endif - - /* now generates the operation */ - if (OPCT_IS(pa->instr_type, OPC_FWAIT)) - g(0x9b); - if (seg_prefix) - g(seg_prefix); - - v = pa->opcode; - if (pa->instr_type & OPC_0F) - v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff); - if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { - /* kludge for imul $im, %reg */ - nb_ops = 3; - ops[2] = ops[1]; - op_type[2] = op_type[1]; - } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { - v--; /* int $3 case */ - nb_ops = 0; - } else if ((v == 0x06 || v == 0x07)) { - if (ops[0].reg >= 4) { - /* push/pop %fs or %gs */ - v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3); - } else { - v += ops[0].reg << 3; - } - nb_ops = 0; - } else if (v <= 0x05) { - /* arith case */ - v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; - } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) { - /* fpu arith case */ - v += ((opcode - pa->sym) / 6) << 3; - } - - /* search which operand will be used for modrm */ - modrm_index = -1; - modreg_index = -1; - if (pa->instr_type & OPC_MODRM) { - if (!nb_ops) { - /* A modrm opcode without operands is a special case (e.g. mfence). - It has a group and acts as if there's an register operand 0 - (ax). */ - i = 0; - ops[i].type = OP_REG; - ops[i].reg = 0; - goto modrm_found; - } - /* first look for an ea operand */ - for(i = 0;i < nb_ops; i++) { - if (op_type[i] & OP_EA) - goto modrm_found; - } - /* then if not found, a register or indirection (shift instructions) */ - for(i = 0;i < nb_ops; i++) { - if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) - goto modrm_found; - } -#ifdef ASM_DEBUG - tcc_error("bad op table"); -#endif - modrm_found: - modrm_index = i; - /* if a register is used in another operand then it is - used instead of group */ - for(i = 0;i < nb_ops; i++) { - int t = op_type[i]; - if (i != modrm_index && - (t & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { - modreg_index = i; - break; - } - } - } -#ifdef TCC_TARGET_X86_64 - asm_rex (rex64, ops, nb_ops, op_type, modreg_index, modrm_index); -#endif - - if (pa->instr_type & OPC_REG) { - /* mov $im, %reg case */ - if (v == 0xb0 && s >= 1) - v += 7; - for(i = 0; i < nb_ops; i++) { - if (op_type[i] & (OP_REG | OP_ST)) { - v += ops[i].reg; - break; - } - } - } - if (pa->instr_type & OPC_B) - v += s >= 1; - if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { - Sym *sym; - int jmp_disp; - - /* see if we can really generate the jump with a byte offset */ - sym = ops[0].e.sym; - if (!sym) - goto no_short_jump; - if (sym->r != cur_text_section->sh_num) - goto no_short_jump; - jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff); - if (jmp_disp == (int8_t)jmp_disp) { - /* OK to generate jump */ - ops[0].e.sym = 0; - ops[0].e.v = jmp_disp; - op_type[0] = OP_IM8S; - } else { - no_short_jump: - /* long jump will be allowed. need to modify the - opcode slightly */ - if (v == 0xeb) /* jmp */ - v = 0xe9; - else if (v == 0x70) /* jcc */ - v += 0x0f10; - else - tcc_error("invalid displacement"); - } - } - if (OPCT_IS(pa->instr_type, OPC_TEST)) - v += test_bits[opcode - pa->sym]; - op1 = v >> 16; - if (op1) - g(op1); - op1 = (v >> 8) & 0xff; - if (op1) - g(op1); - g(v); - - if (OPCT_IS(pa->instr_type, OPC_SHIFT)) { - reg = (opcode - pa->sym) / NBWLX; - if (reg == 6) - reg = 7; - } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) { - reg = (opcode - pa->sym) / NBWLX; - } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) { - reg = (opcode - pa->sym) / 6; - } else { - reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; - } - - pc = 0; - if (pa->instr_type & OPC_MODRM) { - /* if a register is used in another operand then it is - used instead of group */ - if (modreg_index >= 0) - reg = ops[modreg_index].reg; - pc = asm_modrm(reg, &ops[modrm_index]); - } - - /* emit constants */ -#ifndef TCC_TARGET_X86_64 - if (!(pa->instr_type & OPC_0F) - && (pa->opcode == 0x9a || pa->opcode == 0xea)) { - /* ljmp or lcall kludge */ - gen_expr32(&ops[1].e); - if (ops[0].e.sym) - tcc_error("cannot relocate"); - gen_le16(ops[0].e.v); - return; - } -#endif - for(i = 0;i < nb_ops; i++) { - v = op_type[i]; - if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) { - /* if multiple sizes are given it means we must look - at the op size */ - if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) { - if (s == 0) - v = OP_IM8; - else if (s == 1) - v = OP_IM16; - else if (s == 2 || (v & OP_IM64) == 0) - v = OP_IM32; - else - v = OP_IM64; - } - - if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym) - tcc_error("cannot relocate"); - - if (v & (OP_IM8 | OP_IM8S)) { - g(ops[i].e.v); - } else if (v & OP_IM16) { - gen_le16(ops[i].e.v); -#ifdef TCC_TARGET_X86_64 - } else if (v & OP_IM64) { - gen_expr64(&ops[i].e); -#endif - } else if (pa->op_type[i] == OPT_DISP || pa->op_type[i] == OPT_DISP8) { - gen_disp32(&ops[i].e); - } else { - gen_expr32(&ops[i].e); - } - } - } - - /* after immediate operands, adjust pc-relative address */ - if (pc) - add32le(cur_text_section->data + pc - 4, pc - ind); -} - -/* return the constraint priority (we allocate first the lowest - numbered constraints) */ -static inline int constraint_priority(const char *str) -{ - int priority, c, pr; - - /* we take the lowest priority */ - priority = 0; - for(;;) { - c = *str; - if (c == '\0') - break; - str++; - switch(c) { - case 'A': - pr = 0; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'S': - case 'D': - pr = 1; - break; - case 'q': - pr = 2; - break; - case 'r': - case 'R': - case 'p': - pr = 3; - break; - case 'N': - case 'M': - case 'I': - case 'e': - case 'i': - case 'm': - case 'g': - pr = 4; - break; - default: - tcc_error("unknown constraint '%c'", c); - pr = 0; - } - if (pr > priority) - priority = pr; - } - return priority; -} - -static const char *skip_constraint_modifiers(const char *p) -{ - while (*p == '=' || *p == '&' || *p == '+' || *p == '%') - p++; - return p; -} - -/* If T (a token) is of the form "%reg" returns the register - number and type, otherwise return -1. */ -ST_FUNC int asm_parse_regvar (int t) -{ - const char *s; - Operand op; - if (t < TOK_IDENT) - return -1; - s = table_ident[t - TOK_IDENT]->str; - if (s[0] != '%') - return -1; - t = tok_alloc(s+1, strlen(s)-1)->tok; - unget_tok(t); - unget_tok('%'); - parse_operand(tcc_state, &op); - /* Accept only integer regs for now. */ - if (op.type & OP_REG) - return op.reg; - else - return -1; -} - -#define REG_OUT_MASK 0x01 -#define REG_IN_MASK 0x02 - -#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) - -ST_FUNC void asm_compute_constraints(ASMOperand *operands, - int nb_operands, int nb_outputs, - const uint8_t *clobber_regs, - int *pout_reg) -{ - ASMOperand *op; - int sorted_op[MAX_ASM_OPERANDS]; - int i, j, k, p1, p2, tmp, reg, c, reg_mask; - const char *str; - uint8_t regs_allocated[NB_ASM_REGS]; - - /* init fields */ - for(i=0;iinput_index = -1; - op->ref_index = -1; - op->reg = -1; - op->is_memory = 0; - op->is_rw = 0; - } - /* compute constraint priority and evaluate references to output - constraints if input constraints */ - for(i=0;iconstraint; - str = skip_constraint_modifiers(str); - if (isnum(*str) || *str == '[') { - /* this is a reference to another constraint */ - k = find_constraint(operands, nb_operands, str, NULL); - if ((unsigned)k >= i || i < nb_outputs) - tcc_error("invalid reference in constraint %d ('%s')", - i, str); - op->ref_index = k; - if (operands[k].input_index >= 0) - tcc_error("cannot reference twice the same operand"); - operands[k].input_index = i; - op->priority = 5; - } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL - && op->vt->sym - && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) { - op->priority = 1; - op->reg = reg; - } else { - op->priority = constraint_priority(str); - } - } - - /* sort operands according to their priority */ - for(i=0;iconstraint; - /* no need to allocate references */ - if (op->ref_index >= 0) - continue; - /* select if register is used for output, input or both */ - if (op->input_index >= 0) { - reg_mask = REG_IN_MASK | REG_OUT_MASK; - } else if (j < nb_outputs) { - reg_mask = REG_OUT_MASK; - } else { - reg_mask = REG_IN_MASK; - } - if (op->reg >= 0) { - if (is_reg_allocated(op->reg)) - tcc_error("asm regvar requests register that's taken already"); - reg = op->reg; - goto reg_found; - } - try_next: - c = *str++; - switch(c) { - case '=': - goto try_next; - case '+': - op->is_rw = 1; - /* FALL THRU */ - case '&': - if (j >= nb_outputs) - tcc_error("'%c' modifier can only be applied to outputs", c); - reg_mask = REG_IN_MASK | REG_OUT_MASK; - goto try_next; - case 'A': - /* allocate both eax and edx */ - if (is_reg_allocated(TREG_XAX) || - is_reg_allocated(TREG_XDX)) - goto try_next; - op->is_llong = 1; - op->reg = TREG_XAX; - regs_allocated[TREG_XAX] |= reg_mask; - regs_allocated[TREG_XDX] |= reg_mask; - break; - case 'a': - reg = TREG_XAX; - goto alloc_reg; - case 'b': - reg = 3; - goto alloc_reg; - case 'c': - reg = TREG_XCX; - goto alloc_reg; - case 'd': - reg = TREG_XDX; - goto alloc_reg; - case 'S': - reg = 6; - goto alloc_reg; - case 'D': - reg = 7; - alloc_reg: - if (is_reg_allocated(reg)) - goto try_next; - goto reg_found; - case 'q': - /* eax, ebx, ecx or edx */ - for(reg = 0; reg < 4; reg++) { - if (!is_reg_allocated(reg)) - goto reg_found; - } - goto try_next; - case 'r': - case 'R': - case 'p': /* A general address, for x86(64) any register is acceptable*/ - /* any general register */ - for(reg = 0; reg < 8; reg++) { - if (!is_reg_allocated(reg)) - goto reg_found; - } - goto try_next; - reg_found: - /* now we can reload in the register */ - op->is_llong = 0; - op->reg = reg; - regs_allocated[reg] |= reg_mask; - break; - case 'e': - case 'i': - if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST)) - goto try_next; - break; - case 'I': - case 'N': - case 'M': - if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST)) - goto try_next; - break; - case 'm': - case 'g': - /* nothing special to do because the operand is already in - memory, except if the pointer itself is stored in a - memory variable (VT_LLOCAL case) */ - /* XXX: fix constant case */ - /* if it is a reference to a memory zone, it must lie - in a register, so we reserve the register in the - input registers and a load will be generated - later */ - if (j < nb_outputs || c == 'm') { - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { - /* any general register */ - for(reg = 0; reg < 8; reg++) { - if (!(regs_allocated[reg] & REG_IN_MASK)) - goto reg_found1; - } - goto try_next; - reg_found1: - /* now we can reload in the register */ - regs_allocated[reg] |= REG_IN_MASK; - op->reg = reg; - op->is_memory = 1; - } - } - break; - default: - tcc_error("asm constraint %d ('%s') could not be satisfied", - j, op->constraint); - break; - } - /* if a reference is present for that operand, we assign it too */ - if (op->input_index >= 0) { - operands[op->input_index].reg = op->reg; - operands[op->input_index].is_llong = op->is_llong; - } - } - - /* compute out_reg. It is used to store outputs registers to memory - locations references by pointers (VT_LLOCAL case) */ - *pout_reg = -1; - for(i=0;ireg >= 0 && - (op->vt->r & VT_VALMASK) == VT_LLOCAL && - !op->is_memory) { - for(reg = 0; reg < 8; reg++) { - if (!(regs_allocated[reg] & REG_OUT_MASK)) - goto reg_found2; - } - tcc_error("could not find free output register for reloading"); - reg_found2: - *pout_reg = reg; - break; - } - } - - /* print sorted constraints */ -#ifdef ASM_DEBUG - for(i=0;iid ? get_tok_str(op->id, NULL) : "", - op->constraint, - op->vt->r, - op->reg); - } - if (*pout_reg >= 0) - printf("out_reg=%d\n", *pout_reg); -#endif -} - -ST_FUNC void subst_asm_operand(CString *add_str, - SValue *sv, int modifier) -{ - int r, reg, size, val; - char buf[64]; - - r = sv->r; - if ((r & VT_VALMASK) == VT_CONST) { - if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' && - modifier != 'P') - cstr_ccat(add_str, '$'); - if (r & VT_SYM) { - const char *name = get_tok_str(sv->sym->v, NULL); - if (sv->sym->v >= SYM_FIRST_ANOM) { - /* In case of anonymous symbols ("L.42", used - for static data labels) we can't find them - in the C symbol table when later looking up - this name. So enter them now into the asm label - list when we still know the symbol. */ - get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym); - } - cstr_cat(add_str, name, -1); - if ((uint32_t)sv->c.i == 0) - goto no_offset; - cstr_ccat(add_str, '+'); - } - val = sv->c.i; - if (modifier == 'n') - val = -val; - snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); - cstr_cat(add_str, buf, -1); - no_offset:; -#ifdef TCC_TARGET_X86_64 - if (r & VT_LVAL) - cstr_cat(add_str, "(%rip)", -1); -#endif - } else if ((r & VT_VALMASK) == VT_LOCAL) { -#ifdef TCC_TARGET_X86_64 - snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i); -#else - snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); -#endif - cstr_cat(add_str, buf, -1); - } else if (r & VT_LVAL) { - reg = r & VT_VALMASK; - if (reg >= VT_CONST) - tcc_error("internal compiler error"); - snprintf(buf, sizeof(buf), "(%%%s)", -#ifdef TCC_TARGET_X86_64 - get_tok_str(TOK_ASM_rax + reg, NULL) -#else - get_tok_str(TOK_ASM_eax + reg, NULL) -#endif - ); - cstr_cat(add_str, buf, -1); - } else { - /* register case */ - reg = r & VT_VALMASK; - if (reg >= VT_CONST) - tcc_error("internal compiler error"); - - /* choose register operand size */ - if ((sv->type.t & VT_BTYPE) == VT_BYTE || - (sv->type.t & VT_BTYPE) == VT_BOOL) - size = 1; - else if ((sv->type.t & VT_BTYPE) == VT_SHORT) - size = 2; -#ifdef TCC_TARGET_X86_64 - else if ((sv->type.t & VT_BTYPE) == VT_LLONG || - (sv->type.t & VT_BTYPE) == VT_PTR) - size = 8; -#endif - else - size = 4; - if (size == 1 && reg >= 4) - size = 4; - - if (modifier == 'b') { - if (reg >= 4) - tcc_error("cannot use byte register"); - size = 1; - } else if (modifier == 'h') { - if (reg >= 4) - tcc_error("cannot use byte register"); - size = -1; - } else if (modifier == 'w') { - size = 2; - } else if (modifier == 'k') { - size = 4; -#ifdef TCC_TARGET_X86_64 - } else if (modifier == 'q') { - size = 8; -#endif - } - - switch(size) { - case -1: - reg = TOK_ASM_ah + reg; - break; - case 1: - reg = TOK_ASM_al + reg; - break; - case 2: - reg = TOK_ASM_ax + reg; - break; - default: - reg = TOK_ASM_eax + reg; - break; -#ifdef TCC_TARGET_X86_64 - case 8: - reg = TOK_ASM_rax + reg; - break; -#endif - } - snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); - cstr_cat(add_str, buf, -1); - } -} - -/* generate prolog and epilog code for asm statement */ -ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, - int nb_outputs, int is_output, - uint8_t *clobber_regs, - int out_reg) -{ - uint8_t regs_allocated[NB_ASM_REGS]; - ASMOperand *op; - int i, reg; - - /* Strictly speaking %Xbp and %Xsp should be included in the - call-preserved registers, but currently it doesn't matter. */ -#ifdef TCC_TARGET_X86_64 -#ifdef TCC_TARGET_PE - static uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 }; -#else - static uint8_t reg_saved[] = { 3, 12, 13, 14, 15 }; -#endif -#else - static uint8_t reg_saved[] = { 3, 6, 7 }; -#endif - - /* mark all used registers */ - memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated)); - for(i = 0; i < nb_operands;i++) { - op = &operands[i]; - if (op->reg >= 0) - regs_allocated[op->reg] = 1; - } - if (!is_output) { - /* generate reg save code */ - for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) { - reg = reg_saved[i]; - if (regs_allocated[reg]) { - if (reg >= 8) - g(0x41), reg-=8; - g(0x50 + reg); - } - } - - /* generate load code */ - for(i = 0; i < nb_operands; i++) { - op = &operands[i]; - if (op->reg >= 0) { - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && - op->is_memory) { - /* memory reference case (for both input and - output cases) */ - SValue sv; - sv = *op->vt; - sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; - sv.type.t = VT_PTR; - load(op->reg, &sv); - } else if (i >= nb_outputs || op->is_rw) { - /* load value in register */ - load(op->reg, op->vt); - if (op->is_llong) { - SValue sv; - sv = *op->vt; - sv.c.i += 4; - load(TREG_XDX, &sv); - } - } - } - } - } else { - /* generate save code */ - for(i = 0 ; i < nb_outputs; i++) { - op = &operands[i]; - if (op->reg >= 0) { - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { - if (!op->is_memory) { - SValue sv; - sv = *op->vt; - sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; - sv.type.t = VT_PTR; - load(out_reg, &sv); - - sv = *op->vt; - sv.r = (sv.r & ~VT_VALMASK) | out_reg; - store(op->reg, &sv); - } - } else { - store(op->reg, op->vt); - if (op->is_llong) { - SValue sv; - sv = *op->vt; - sv.c.i += 4; - store(TREG_XDX, &sv); - } - } - } - } - /* generate reg restore code */ - for(i = sizeof(reg_saved)/sizeof(reg_saved[0]) - 1; i >= 0; i--) { - reg = reg_saved[i]; - if (regs_allocated[reg]) { - if (reg >= 8) - g(0x41), reg-=8; - g(0x58 + reg); - } - } - } -} - -ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) -{ - int reg; - TokenSym *ts; -#ifdef TCC_TARGET_X86_64 - unsigned int type; -#endif - - if (!strcmp(str, "memory") || - !strcmp(str, "cc") || - !strcmp(str, "flags")) - return; - ts = tok_alloc(str, strlen(str)); - reg = ts->tok; - if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { - reg -= TOK_ASM_eax; - } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { - reg -= TOK_ASM_ax; -#ifdef TCC_TARGET_X86_64 - } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { - reg -= TOK_ASM_rax; - } else if ((reg = asm_parse_numeric_reg(reg, &type)) >= 0) { - ; -#endif - } else { - tcc_error("invalid clobber register '%s'", str); - } - clobber_regs[reg] = 1; -} diff --git a/tinyc/i386-asm.h b/tinyc/i386-asm.h deleted file mode 100644 index 65d517955..000000000 --- a/tinyc/i386-asm.h +++ /dev/null @@ -1,480 +0,0 @@ - DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ - DEF_ASM_OP0(cld, 0xfc) - DEF_ASM_OP0(cli, 0xfa) - DEF_ASM_OP0(clts, 0x0f06) - DEF_ASM_OP0(cmc, 0xf5) - DEF_ASM_OP0(lahf, 0x9f) - DEF_ASM_OP0(sahf, 0x9e) - DEF_ASM_OP0(pusha, 0x60) - DEF_ASM_OP0(popa, 0x61) - DEF_ASM_OP0(pushfl, 0x9c) - DEF_ASM_OP0(popfl, 0x9d) - DEF_ASM_OP0(pushf, 0x9c) - DEF_ASM_OP0(popf, 0x9d) - DEF_ASM_OP0(stc, 0xf9) - DEF_ASM_OP0(std, 0xfd) - DEF_ASM_OP0(sti, 0xfb) - DEF_ASM_OP0(aaa, 0x37) - DEF_ASM_OP0(aas, 0x3f) - DEF_ASM_OP0(daa, 0x27) - DEF_ASM_OP0(das, 0x2f) - DEF_ASM_OP0(aad, 0xd50a) - DEF_ASM_OP0(aam, 0xd40a) - DEF_ASM_OP0(cbw, 0x6698) - DEF_ASM_OP0(cwd, 0x6699) - DEF_ASM_OP0(cwde, 0x98) - DEF_ASM_OP0(cdq, 0x99) - DEF_ASM_OP0(cbtw, 0x6698) - DEF_ASM_OP0(cwtl, 0x98) - DEF_ASM_OP0(cwtd, 0x6699) - DEF_ASM_OP0(cltd, 0x99) - DEF_ASM_OP0(int3, 0xcc) - DEF_ASM_OP0(into, 0xce) - DEF_ASM_OP0(iret, 0xcf) - DEF_ASM_OP0(rsm, 0x0faa) - DEF_ASM_OP0(hlt, 0xf4) - DEF_ASM_OP0(nop, 0x90) - DEF_ASM_OP0(pause, 0xf390) - DEF_ASM_OP0(xlat, 0xd7) - - /* strings */ -ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL)) -ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL)) - -ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX)) - - /* bits */ - -ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - -ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - - /* prefixes */ - DEF_ASM_OP0(wait, 0x9b) - DEF_ASM_OP0(fwait, 0x9b) - DEF_ASM_OP0(aword, 0x67) - DEF_ASM_OP0(addr16, 0x67) - ALT(DEF_ASM_OP0(word, 0x66)) - DEF_ASM_OP0(data16, 0x66) - DEF_ASM_OP0(lock, 0xf0) - DEF_ASM_OP0(rep, 0xf3) - DEF_ASM_OP0(repe, 0xf3) - DEF_ASM_OP0(repz, 0xf3) - DEF_ASM_OP0(repne, 0xf2) - DEF_ASM_OP0(repnz, 0xf2) - - DEF_ASM_OP0(invd, 0x0f08) - DEF_ASM_OP0(wbinvd, 0x0f09) - DEF_ASM_OP0(cpuid, 0x0fa2) - DEF_ASM_OP0(wrmsr, 0x0f30) - DEF_ASM_OP0(rdtsc, 0x0f31) - DEF_ASM_OP0(rdmsr, 0x0f32) - DEF_ASM_OP0(rdpmc, 0x0f33) - DEF_ASM_OP0(ud2, 0x0f0b) - - /* NOTE: we took the same order as gas opcode definition order */ -ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX)) -ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR)) -ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) -ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG)) -ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG)) - -ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG32)) -ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG32)) -ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WLX, OPT_TR, OPT_REG32)) -ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_CR)) -ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_DB)) -ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_TR)) - -ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16)) -ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) - -ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REGW)) -ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WLX, OPT_IM8S)) -ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32)) -ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG)) - -ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REGW)) -ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG)) - -ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX)) -ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW)) -ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) - -ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX)) -ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8)) -ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) -ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) - -ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) -ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8)) -ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX)) -ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX)) - -ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG)) - -ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) - - /* arith */ -ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ -ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) -ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX)) -ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) - -ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) -ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX)) -ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) - -ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WLX, OPT_REGW)) -ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WLX, OPT_REGW)) -ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) -ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW)) -ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW)) - -ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) -ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) - - /* shifts */ -ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG)) - -ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) - -ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR)) -ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP)) -ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) -ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8)) - -ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32)) -ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32)) -ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA)) - -ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8)) -ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) -ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) - DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8) - DEF_ASM_OP0(leave, 0xc9) - DEF_ASM_OP0(ret, 0xc3) - DEF_ASM_OP0(retl,0xc3) -ALT(DEF_ASM_OP1(retl,0xc2, 0, 0, OPT_IM16)) -ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) - DEF_ASM_OP0(lret, 0xcb) -ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16)) - -ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8)) - DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8) - DEF_ASM_OP1(jecxz, 0xe3, 0, 0, OPT_DISP8) - - /* float */ - /* specific fcomp handling */ -ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) - -ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) - - DEF_ASM_OP0(fucompp, 0xdae9) - DEF_ASM_OP0(ftst, 0xd9e4) - DEF_ASM_OP0(fxam, 0xd9e5) - DEF_ASM_OP0(fld1, 0xd9e8) - DEF_ASM_OP0(fldl2t, 0xd9e9) - DEF_ASM_OP0(fldl2e, 0xd9ea) - DEF_ASM_OP0(fldpi, 0xd9eb) - DEF_ASM_OP0(fldlg2, 0xd9ec) - DEF_ASM_OP0(fldln2, 0xd9ed) - DEF_ASM_OP0(fldz, 0xd9ee) - - DEF_ASM_OP0(f2xm1, 0xd9f0) - DEF_ASM_OP0(fyl2x, 0xd9f1) - DEF_ASM_OP0(fptan, 0xd9f2) - DEF_ASM_OP0(fpatan, 0xd9f3) - DEF_ASM_OP0(fxtract, 0xd9f4) - DEF_ASM_OP0(fprem1, 0xd9f5) - DEF_ASM_OP0(fdecstp, 0xd9f6) - DEF_ASM_OP0(fincstp, 0xd9f7) - DEF_ASM_OP0(fprem, 0xd9f8) - DEF_ASM_OP0(fyl2xp1, 0xd9f9) - DEF_ASM_OP0(fsqrt, 0xd9fa) - DEF_ASM_OP0(fsincos, 0xd9fb) - DEF_ASM_OP0(frndint, 0xd9fc) - DEF_ASM_OP0(fscale, 0xd9fd) - DEF_ASM_OP0(fsin, 0xd9fe) - DEF_ASM_OP0(fcos, 0xd9ff) - DEF_ASM_OP0(fchs, 0xd9e0) - DEF_ASM_OP0(fabs, 0xd9e1) - DEF_ASM_OP0(fninit, 0xdbe3) - DEF_ASM_OP0(fnclex, 0xdbe2) - DEF_ASM_OP0(fnop, 0xd9d0) - - /* fp load */ - DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) - DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) - - /* fp store */ - DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) - - DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) - - /* exchange */ - DEF_ASM_OP0(fxch, 0xd9c9) -ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) - - /* misc FPU */ - DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) - - DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) - DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP0(fnstsw, 0xdfe0) -ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) -ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) - DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) -ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) -ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) - DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) - DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) - - /* segments */ - DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) -ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) - DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG) - DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG) -ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)) - DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG) - DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG16| OPT_EA) - DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) - - /* 486 */ - DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) -ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) -ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) - DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA ) - - DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA) - DEF_ASM_OP2(boundw, 0x6662, 0, OPC_MODRM, OPT_REG16, OPT_EA) - - /* pentium */ - DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA ) - - /* pentium pro */ -ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - /* mmx */ - DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ - DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE ) - DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) -ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 )) -ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX )) -ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE )) -ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )) - - DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - - /* sse */ - DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) -ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) - DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) -ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) - DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) -ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) - DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE ) - DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) - DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) - DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - -#undef ALT -#undef DEF_ASM_OP0 -#undef DEF_ASM_OP0L -#undef DEF_ASM_OP1 -#undef DEF_ASM_OP2 -#undef DEF_ASM_OP3 diff --git a/tinyc/i386-gen.c b/tinyc/i386-gen.c deleted file mode 100644 index b9c3599fd..000000000 --- a/tinyc/i386-gen.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* - * X86 code generator for TCC - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef TARGET_DEFS_ONLY - -/* number of available registers */ -#define NB_REGS 5 -#define NB_ASM_REGS 8 -#define CONFIG_TCC_ASM - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_EAX 0x0004 -#define RC_ST0 0x0008 -#define RC_ECX 0x0010 -#define RC_EDX 0x0020 -#define RC_EBX 0x0040 - -#define RC_IRET RC_EAX /* function return: integer register */ -#define RC_LRET RC_EDX /* function return: second integer register */ -#define RC_FRET RC_ST0 /* function return: float register */ - -/* pretty names for the registers */ -enum { - TREG_EAX = 0, - TREG_ECX, - TREG_EDX, - TREG_EBX, - TREG_ST0, - TREG_ESP = 4 -}; - -/* return registers for function */ -#define REG_IRET TREG_EAX /* single word int return register */ -#define REG_LRET TREG_EDX /* second word return register (for long long) */ -#define REG_FRET TREG_ST0 /* float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -#define INVERT_FUNC_PARAMS - -/* defined if structures are passed as pointers. Otherwise structures - are directly pushed on stack. */ -/* #define FUNC_STRUCT_PARAM_AS_PTR */ - -/* pointer size, in bytes */ -#define PTR_SIZE 4 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 12 -#define LDOUBLE_ALIGN 4 -/* maximum alignment (for aligned attribute support) */ -#define MAX_ALIGN 8 - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#include "tcc.h" - -/* define to 1/0 to [not] have EBX as 4th register */ -#define USE_EBX 0 - -ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_EAX, - /* ecx */ RC_INT | RC_ECX, - /* edx */ RC_INT | RC_EDX, - /* ebx */ (RC_INT | RC_EBX) * USE_EBX, - /* st0 */ RC_FLOAT | RC_ST0, -}; - -static unsigned long func_sub_sp_offset; -static int func_ret_sub; -#ifdef CONFIG_TCC_BCHECK -static addr_t func_bound_offset; -static unsigned long func_bound_ind; -#endif - -/* XXX: make it faster ? */ -ST_FUNC void g(int c) -{ - int ind1; - if (nocode_wanted) - return; - ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) - section_realloc(cur_text_section, ind1); - cur_text_section->data[ind] = c; - ind = ind1; -} - -ST_FUNC void o(unsigned int c) -{ - while (c) { - g(c); - c = c >> 8; - } -} - -ST_FUNC void gen_le16(int v) -{ - g(v); - g(v >> 8); -} - -ST_FUNC void gen_le32(int c) -{ - g(c); - g(c >> 8); - g(c >> 16); - g(c >> 24); -} - -/* output a symbol and patch all calls to it */ -ST_FUNC void gsym_addr(int t, int a) -{ - while (t) { - unsigned char *ptr = cur_text_section->data + t; - uint32_t n = read32le(ptr); /* next value */ - write32le(ptr, a - t - 4); - t = n; - } -} - -ST_FUNC void gsym(int t) -{ - gsym_addr(t, ind); -} - -/* instruction + 4 bytes data. Return the address of the data */ -static int oad(int c, int s) -{ - int t; - if (nocode_wanted) - return s; - o(c); - t = ind; - gen_le32(s); - return t; -} - -/* generate jmp to a label */ -#define gjmp2(instr,lbl) oad(instr,lbl) - -/* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addr32(int r, Sym *sym, int c) -{ - if (r & VT_SYM) - greloc(cur_text_section, sym, ind, R_386_32); - gen_le32(c); -} - -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) -{ - if (r & VT_SYM) - greloc(cur_text_section, sym, ind, R_386_PC32); - gen_le32(c - 4); -} - -/* generate a modrm reference. 'op_reg' contains the additional 3 - opcode bits */ -static void gen_modrm(int op_reg, int r, Sym *sym, int c) -{ - op_reg = op_reg << 3; - if ((r & VT_VALMASK) == VT_CONST) { - /* constant memory reference */ - o(0x05 | op_reg); - gen_addr32(r, sym, c); - } else if ((r & VT_VALMASK) == VT_LOCAL) { - /* currently, we use only ebp as base */ - if (c == (char)c) { - /* short reference */ - o(0x45 | op_reg); - g(c); - } else { - oad(0x85 | op_reg, c); - } - } else { - g(0x00 | op_reg | (r & VT_VALMASK)); - } -} - -/* load 'r' from value 'sv' */ -ST_FUNC void load(int r, SValue *sv) -{ - int v, t, ft, fc, fr; - SValue v1; - -#ifdef TCC_TARGET_PE - SValue v2; - sv = pe_getimport(sv, &v2); -#endif - - fr = sv->r; - ft = sv->type.t & ~VT_DEFSIGN; - fc = sv->c.i; - - ft &= ~(VT_VOLATILE | VT_CONSTANT); - - v = fr & VT_VALMASK; - if (fr & VT_LVAL) { - if (v == VT_LLOCAL) { - v1.type.t = VT_INT; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - fr = r; - if (!(reg_classes[fr] & RC_INT)) - fr = get_reg(RC_INT); - load(fr, &v1); - } - if ((ft & VT_BTYPE) == VT_FLOAT) { - o(0xd9); /* flds */ - r = 0; - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - o(0xdd); /* fldl */ - r = 0; - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - o(0xdb); /* fldt */ - r = 5; - } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { - o(0xbe0f); /* movsbl */ - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { - o(0xb60f); /* movzbl */ - } else if ((ft & VT_TYPE) == VT_SHORT) { - o(0xbf0f); /* movswl */ - } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { - o(0xb70f); /* movzwl */ - } else { - o(0x8b); /* movl */ - } - gen_modrm(r, fr, sv->sym, fc); - } else { - if (v == VT_CONST) { - o(0xb8 + r); /* mov $xx, r */ - gen_addr32(fr, sv->sym, fc); - } else if (v == VT_LOCAL) { - if (fc) { - o(0x8d); /* lea xxx(%ebp), r */ - gen_modrm(r, VT_LOCAL, sv->sym, fc); - } else { - o(0x89); - o(0xe8 + r); /* mov %ebp, r */ - } - } else if (v == VT_CMP) { - oad(0xb8 + r, 0); /* mov $0, r */ - o(0x0f); /* setxx %br */ - o(fc); - o(0xc0 + r); - } else if (v == VT_JMP || v == VT_JMPI) { - t = v & 1; - oad(0xb8 + r, t); /* mov $1, r */ - o(0x05eb); /* jmp after */ - gsym(fc); - oad(0xb8 + r, t ^ 1); /* mov $0, r */ - } else if (v != r) { - o(0x89); - o(0xc0 + r + v * 8); /* mov v, r */ - } - } -} - -/* store register 'r' in lvalue 'v' */ -ST_FUNC void store(int r, SValue *v) -{ - int fr, bt, ft, fc; - -#ifdef TCC_TARGET_PE - SValue v2; - v = pe_getimport(v, &v2); -#endif - - ft = v->type.t; - fc = v->c.i; - fr = v->r & VT_VALMASK; - ft &= ~(VT_VOLATILE | VT_CONSTANT); - bt = ft & VT_BTYPE; - /* XXX: incorrect if float reg to reg */ - if (bt == VT_FLOAT) { - o(0xd9); /* fsts */ - r = 2; - } else if (bt == VT_DOUBLE) { - o(0xdd); /* fstpl */ - r = 2; - } else if (bt == VT_LDOUBLE) { - o(0xc0d9); /* fld %st(0) */ - o(0xdb); /* fstpt */ - r = 7; - } else { - if (bt == VT_SHORT) - o(0x66); - if (bt == VT_BYTE || bt == VT_BOOL) - o(0x88); - else - o(0x89); - } - if (fr == VT_CONST || - fr == VT_LOCAL || - (v->r & VT_LVAL)) { - gen_modrm(r, v->r, v->sym, fc); - } else if (fr != r) { - o(0xc0 + fr + r * 8); /* mov r, fr */ - } -} - -static void gadd_sp(int val) -{ - if (val == (char)val) { - o(0xc483); - g(val); - } else { - oad(0xc481, val); /* add $xxx, %esp */ - } -} - -#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_PE -static void gen_static_call(int v) -{ - Sym *sym; - - sym = external_global_sym(v, &func_old_type, 0); - oad(0xe8, -4); - greloc(cur_text_section, sym, ind-4, R_386_PC32); -} -#endif - -/* 'is_jmp' is '1' if it is a jump */ -static void gcall_or_jmp(int is_jmp) -{ - int r; - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) { - /* constant and relocation case */ - greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32); - oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ - } else { - /* otherwise, indirect call */ - r = gv(RC_INT); - o(0xff); /* call/jmp *r */ - o(0xd0 + r + (is_jmp << 4)); - } - if (!is_jmp) { - int rt; - /* extend the return value to the whole register if necessary - visual studio and gcc do not always set the whole eax register - when assigning the return value of a function */ - rt = vtop->type.ref->type.t; - switch (rt & VT_BTYPE) { - case VT_BYTE: - if (rt & VT_UNSIGNED) { - o(0xc0b60f); /* movzx %al, %eax */ - } - else { - o(0xc0be0f); /* movsx %al, %eax */ - } - break; - case VT_SHORT: - if (rt & VT_UNSIGNED) { - o(0xc0b70f); /* movzx %ax, %eax */ - } - else { - o(0xc0bf0f); /* movsx %ax, %eax */ - } - break; - default: - break; - } - } -} - -static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; -static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; - -/* Return the number of registers needed to return the struct, or 0 if - returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) -{ -#ifdef TCC_TARGET_PE - int size, align; - *ret_align = 1; // Never have to re-align return values for x86 - *regsize = 4; - size = type_size(vt, &align); - if (size > 8 || (size & (size - 1))) - return 0; - if (size == 8) - ret->t = VT_LLONG; - else if (size == 4) - ret->t = VT_INT; - else if (size == 2) - ret->t = VT_SHORT; - else - ret->t = VT_BYTE; - ret->ref = NULL; - return 1; -#else - *ret_align = 1; // Never have to re-align return values for x86 - return 0; -#endif -} - -/* Generate function call. The function address is pushed first, then - all the parameters in call order. This functions pops all the - parameters and the function address. */ -ST_FUNC void gfunc_call(int nb_args) -{ - int size, align, r, args_size, i, func_call; - Sym *func_sym; - - args_size = 0; - for(i = 0;i < nb_args; i++) { - if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { - size = type_size(&vtop->type, &align); - /* align to stack align size */ - size = (size + 3) & ~3; - /* allocate the necessary size on stack */ - oad(0xec81, size); /* sub $xxx, %esp */ - /* generate structure store */ - r = get_reg(RC_INT); - o(0x89); /* mov %esp, r */ - o(0xe0 + r); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - args_size += size; - } else if (is_float(vtop->type.t)) { - gv(RC_FLOAT); /* only one float register */ - if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) - size = 4; - else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - size = 8; - else - size = 12; - oad(0xec81, size); /* sub $xxx, %esp */ - if (size == 12) - o(0x7cdb); - else - o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */ - g(0x24); - g(0x00); - args_size += size; - } else { - /* simple type (currently always same size) */ - /* XXX: implicit cast ? */ - r = gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - size = 8; - o(0x50 + vtop->r2); /* push r */ - } else { - size = 4; - } - o(0x50 + r); /* push r */ - args_size += size; - } - vtop--; - } - save_regs(0); /* save used temporary registers */ - func_sym = vtop->type.ref; - func_call = func_sym->f.func_call; - /* fast call case */ - if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || - func_call == FUNC_FASTCALLW) { - int fastcall_nb_regs; - uint8_t *fastcall_regs_ptr; - if (func_call == FUNC_FASTCALLW) { - fastcall_regs_ptr = fastcallw_regs; - fastcall_nb_regs = 2; - } else { - fastcall_regs_ptr = fastcall_regs; - fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; - } - for(i = 0;i < fastcall_nb_regs; i++) { - if (args_size <= 0) - break; - o(0x58 + fastcall_regs_ptr[i]); /* pop r */ - /* XXX: incorrect for struct/floats */ - args_size -= 4; - } - } -#ifndef TCC_TARGET_PE - else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT) - args_size -= 4; -#endif - gcall_or_jmp(0); - - if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW) - gadd_sp(args_size); - vtop--; -} - -#ifdef TCC_TARGET_PE -#define FUNC_PROLOG_SIZE (10 + USE_EBX) -#else -#define FUNC_PROLOG_SIZE (9 + USE_EBX) -#endif - -/* generate function prolog of type 't' */ -ST_FUNC void gfunc_prolog(CType *func_type) -{ - int addr, align, size, func_call, fastcall_nb_regs; - int param_index, param_addr; - uint8_t *fastcall_regs_ptr; - Sym *sym; - CType *type; - - sym = func_type->ref; - func_call = sym->f.func_call; - addr = 8; - loc = 0; - func_vc = 0; - - if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { - fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; - fastcall_regs_ptr = fastcall_regs; - } else if (func_call == FUNC_FASTCALLW) { - fastcall_nb_regs = 2; - fastcall_regs_ptr = fastcallw_regs; - } else { - fastcall_nb_regs = 0; - fastcall_regs_ptr = NULL; - } - param_index = 0; - - ind += FUNC_PROLOG_SIZE; - func_sub_sp_offset = ind; - /* if the function returns a structure, then add an - implicit pointer parameter */ - func_vt = sym->type; - func_var = (sym->f.func_type == FUNC_ELLIPSIS); -#ifdef TCC_TARGET_PE - size = type_size(&func_vt,&align); - if (((func_vt.t & VT_BTYPE) == VT_STRUCT) - && (size > 8 || (size & (size - 1)))) { -#else - if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { -#endif - /* XXX: fastcall case ? */ - func_vc = addr; - addr += 4; - param_index++; - } - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - size = type_size(type, &align); - size = (size + 3) & ~3; -#ifdef FUNC_STRUCT_PARAM_AS_PTR - /* structs are passed as pointer */ - if ((type->t & VT_BTYPE) == VT_STRUCT) { - size = 4; - } -#endif - if (param_index < fastcall_nb_regs) { - /* save FASTCALL register */ - loc -= 4; - o(0x89); /* movl */ - gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); - param_addr = loc; - } else { - param_addr = addr; - addr += size; - } - sym_push(sym->v & ~SYM_FIELD, type, - VT_LOCAL | lvalue_type(type->t), param_addr); - param_index++; - } - func_ret_sub = 0; - /* pascal type call or fastcall ? */ - if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW) - func_ret_sub = addr - 8; -#ifndef TCC_TARGET_PE - else if (func_vc) - func_ret_sub = 4; -#endif - -#ifdef CONFIG_TCC_BCHECK - /* leave some room for bound checking code */ - if (tcc_state->do_bounds_check) { - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - oad(0xb8, 0); /* lbound section pointer */ - oad(0xb8, 0); /* call to function */ - } -#endif -} - -/* generate function epilog */ -ST_FUNC void gfunc_epilog(void) -{ - addr_t v, saved_ind; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check - && func_bound_offset != lbounds_section->data_offset) { - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - /* generate bound local allocation */ - saved_ind = ind; - ind = func_bound_ind; - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); - greloc(cur_text_section, sym_data, - ind + 1, R_386_32); - oad(0xb8, 0); /* mov %eax, xxx */ - gen_static_call(TOK___bound_local_new); - ind = saved_ind; - - /* generate bound check local freeing */ - o(0x5250); /* save returned value, if any */ - greloc(cur_text_section, sym_data, ind + 1, R_386_32); - oad(0xb8, 0); /* mov %eax, xxx */ - gen_static_call(TOK___bound_local_delete); - o(0x585a); /* restore returned value, if any */ - } -#endif - - /* align local size to word & save local variables */ - v = (-loc + 3) & -4; - -#if USE_EBX - o(0x8b); - gen_modrm(TREG_EBX, VT_LOCAL, NULL, -(v+4)); -#endif - - o(0xc9); /* leave */ - if (func_ret_sub == 0) { - o(0xc3); /* ret */ - } else { - o(0xc2); /* ret n */ - g(func_ret_sub); - g(func_ret_sub >> 8); - } - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; -#ifdef TCC_TARGET_PE - if (v >= 4096) { - oad(0xb8, v); /* mov stacksize, %eax */ - gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */ - } else -#endif - { - o(0xe58955); /* push %ebp, mov %esp, %ebp */ - o(0xec81); /* sub esp, stacksize */ - gen_le32(v); -#ifdef TCC_TARGET_PE - o(0x90); /* adjust to FUNC_PROLOG_SIZE */ -#endif - } - o(0x53 * USE_EBX); /* push ebx */ - ind = saved_ind; -} - -/* generate a jump to a label */ -ST_FUNC int gjmp(int t) -{ - return gjmp2(0xe9, t); -} - -/* generate a jump to a fixed address */ -ST_FUNC void gjmp_addr(int a) -{ - int r; - r = a - ind - 2; - if (r == (char)r) { - g(0xeb); - g(r); - } else { - oad(0xe9, a - ind - 5); - } -} - -ST_FUNC void gtst_addr(int inv, int a) -{ - int v = vtop->r & VT_VALMASK; - if (v == VT_CMP) { - inv ^= (vtop--)->c.i; - a -= ind + 2; - if (a == (char)a) { - g(inv - 32); - g(a); - } else { - g(0x0f); - oad(inv - 16, a - 4); - } - } else if ((v & ~1) == VT_JMP) { - if ((v & 1) != inv) { - gjmp_addr(a); - gsym(vtop->c.i); - } else { - gsym(vtop->c.i); - o(0x05eb); - gjmp_addr(a); - } - vtop--; - } -} - -/* generate a test. set 'inv' to invert test. Stack entry is popped */ -ST_FUNC int gtst(int inv, int t) -{ - int v = vtop->r & VT_VALMASK; - if (nocode_wanted) { - ; - } else if (v == VT_CMP) { - /* fast case : can jump directly since flags are set */ - g(0x0f); - t = gjmp2((vtop->c.i - 16) ^ inv, t); - } else if (v == VT_JMP || v == VT_JMPI) { - /* && or || optimization */ - if ((v & 1) == inv) { - /* insert vtop->c jump list in t */ - uint32_t n1, n = vtop->c.i; - if (n) { - while ((n1 = read32le(cur_text_section->data + n))) - n = n1; - write32le(cur_text_section->data + n, t); - t = vtop->c.i; - } - } else { - t = gjmp(t); - gsym(vtop->c.i); - } - } - vtop--; - return t; -} - -/* generate an integer binary operation */ -ST_FUNC void gen_opi(int op) -{ - int r, fr, opc, c; - - switch(op) { - case '+': - case TOK_ADDC1: /* add with carry generation */ - opc = 0; - gen_op8: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - c = vtop->c.i; - if (c == (char)c) { - /* generate inc and dec for smaller code */ - if (c==1 && opc==0 && op != TOK_ADDC1) { - o (0x40 | r); // inc - } else if (c==1 && opc==5 && op != TOK_SUBC1) { - o (0x48 | r); // dec - } else { - o(0x83); - o(0xc0 | (opc << 3) | r); - g(c); - } - } else { - o(0x81); - oad(0xc0 | (opc << 3) | r, c); - } - } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - o((opc << 3) | 0x01); - o(0xc0 + r + fr * 8); - } - vtop--; - if (op >= TOK_ULT && op <= TOK_GT) { - vtop->r = VT_CMP; - vtop->c.i = op; - } - break; - case '-': - case TOK_SUBC1: /* sub with carry generation */ - opc = 5; - goto gen_op8; - case TOK_ADDC2: /* add with carry use */ - opc = 2; - goto gen_op8; - case TOK_SUBC2: /* sub with carry use */ - opc = 3; - goto gen_op8; - case '&': - opc = 4; - goto gen_op8; - case '^': - opc = 6; - goto gen_op8; - case '|': - opc = 1; - goto gen_op8; - case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - o(0xaf0f); /* imul fr, r */ - o(0xc0 + fr + r * 8); - break; - case TOK_SHL: - opc = 4; - goto gen_shift; - case TOK_SHR: - opc = 5; - goto gen_shift; - case TOK_SAR: - opc = 7; - gen_shift: - opc = 0xc0 | (opc << 3); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - c = vtop->c.i & 0x1f; - o(0xc1); /* shl/shr/sar $xxx, r */ - o(opc | r); - g(c); - } else { - /* we generate the shift in ecx */ - gv2(RC_INT, RC_ECX); - r = vtop[-1].r; - o(0xd3); /* shl/shr/sar %cl, r */ - o(opc | r); - } - vtop--; - break; - case '/': - case TOK_UDIV: - case TOK_PDIV: - case '%': - case TOK_UMOD: - case TOK_UMULL: - /* first operand must be in eax */ - /* XXX: need better constraint for second operand */ - gv2(RC_EAX, RC_ECX); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - save_reg(TREG_EDX); - /* save EAX too if used otherwise */ - save_reg_upstack(TREG_EAX, 1); - if (op == TOK_UMULL) { - o(0xf7); /* mul fr */ - o(0xe0 + fr); - vtop->r2 = TREG_EDX; - r = TREG_EAX; - } else { - if (op == TOK_UDIV || op == TOK_UMOD) { - o(0xf7d231); /* xor %edx, %edx, div fr, %eax */ - o(0xf0 + fr); - } else { - o(0xf799); /* cltd, idiv fr, %eax */ - o(0xf8 + fr); - } - if (op == '%' || op == TOK_UMOD) - r = TREG_EDX; - else - r = TREG_EAX; - } - vtop->r = r; - break; - default: - opc = 7; - goto gen_op8; - } -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -/* XXX: need to use ST1 too */ -ST_FUNC void gen_opf(int op) -{ - int a, ft, fc, swapped, r; - - /* convert constants to memory references */ - if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - vswap(); - gv(RC_FLOAT); - vswap(); - } - if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) - gv(RC_FLOAT); - - /* must put at least one value in the floating point register */ - if ((vtop[-1].r & VT_LVAL) && - (vtop[0].r & VT_LVAL)) { - vswap(); - gv(RC_FLOAT); - vswap(); - } - swapped = 0; - /* swap the stack if needed so that t1 is the register and t2 is - the memory reference */ - if (vtop[-1].r & VT_LVAL) { - vswap(); - swapped = 1; - } - if (op >= TOK_ULT && op <= TOK_GT) { - /* load on stack second operand */ - load(TREG_ST0, vtop); - save_reg(TREG_EAX); /* eax is used by FP comparison code */ - if (op == TOK_GE || op == TOK_GT) - swapped = !swapped; - else if (op == TOK_EQ || op == TOK_NE) - swapped = 0; - if (swapped) - o(0xc9d9); /* fxch %st(1) */ - if (op == TOK_EQ || op == TOK_NE) - o(0xe9da); /* fucompp */ - else - o(0xd9de); /* fcompp */ - o(0xe0df); /* fnstsw %ax */ - if (op == TOK_EQ) { - o(0x45e480); /* and $0x45, %ah */ - o(0x40fC80); /* cmp $0x40, %ah */ - } else if (op == TOK_NE) { - o(0x45e480); /* and $0x45, %ah */ - o(0x40f480); /* xor $0x40, %ah */ - op = TOK_NE; - } else if (op == TOK_GE || op == TOK_LE) { - o(0x05c4f6); /* test $0x05, %ah */ - op = TOK_EQ; - } else { - o(0x45c4f6); /* test $0x45, %ah */ - op = TOK_EQ; - } - vtop--; - vtop->r = VT_CMP; - vtop->c.i = op; - } else { - /* no memory reference possible for long double operations */ - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - load(TREG_ST0, vtop); - swapped = !swapped; - } - - switch(op) { - default: - case '+': - a = 0; - break; - case '-': - a = 4; - if (swapped) - a++; - break; - case '*': - a = 1; - break; - case '/': - a = 6; - if (swapped) - a++; - break; - } - ft = vtop->type.t; - fc = vtop->c.i; - if ((ft & VT_BTYPE) == VT_LDOUBLE) { - o(0xde); /* fxxxp %st, %st(1) */ - o(0xc1 + (a << 3)); - } else { - /* if saved lvalue, then we must reload it */ - r = vtop->r; - if ((r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_INT; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - load(r, &v1); - fc = 0; - } - - if ((ft & VT_BTYPE) == VT_DOUBLE) - o(0xdc); - else - o(0xd8); - gen_modrm(a, r, vtop->sym, fc); - } - vtop--; - } -} - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -ST_FUNC void gen_cvt_itof(int t) -{ - save_reg(TREG_ST0); - gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - /* signed long long to float/double/long double (unsigned case - is handled generically) */ - o(0x50 + vtop->r2); /* push r2 */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%esp) */ - o(0x08c483); /* add $8, %esp */ - } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED)) { - /* unsigned int to float/double/long double */ - o(0x6a); /* push $0 */ - g(0x00); - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%esp) */ - o(0x08c483); /* add $8, %esp */ - } else { - /* int to float/double/long double */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x2404db); /* fildl (%esp) */ - o(0x04c483); /* add $4, %esp */ - } - vtop->r = TREG_ST0; -} - -/* convert fp to int 't' type */ -ST_FUNC void gen_cvt_ftoi(int t) -{ - int bt = vtop->type.t & VT_BTYPE; - if (bt == VT_FLOAT) - vpush_global_sym(&func_old_type, TOK___fixsfdi); - else if (bt == VT_LDOUBLE) - vpush_global_sym(&func_old_type, TOK___fixxfdi); - else - vpush_global_sym(&func_old_type, TOK___fixdfdi); - vswap(); - gfunc_call(1); - vpushi(0); - vtop->r = REG_IRET; - vtop->r2 = REG_LRET; -} - -/* convert from one floating point type to another */ -ST_FUNC void gen_cvt_ftof(int t) -{ - /* all we have to do on i386 is to put the float in a register */ - gv(RC_FLOAT); -} - -/* computed goto support */ -ST_FUNC void ggoto(void) -{ - gcall_or_jmp(1); - vtop--; -} - -/* bound check support functions */ -#ifdef CONFIG_TCC_BCHECK - -/* generate a bounded pointer addition */ -ST_FUNC void gen_bounded_ptr_add(void) -{ - /* prepare fast i386 function call (args in eax and edx) */ - gv2(RC_EAX, RC_EDX); - /* save all temporary registers */ - vtop -= 2; - save_regs(0); - /* do a fast function call */ - gen_static_call(TOK___bound_ptr_add); - /* returned pointer is in eax */ - vtop++; - vtop->r = TREG_EAX | VT_BOUNDED; - /* address of bounding function call point */ - vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); -} - -/* patch pointer addition in vtop so that pointer dereferencing is - also tested */ -ST_FUNC void gen_bounded_ptr_deref(void) -{ - addr_t func; - int size, align; - Elf32_Rel *rel; - Sym *sym; - - size = 0; - /* XXX: put that code in generic part of tcc */ - if (!is_float(vtop->type.t)) { - if (vtop->r & VT_LVAL_BYTE) - size = 1; - else if (vtop->r & VT_LVAL_SHORT) - size = 2; - } - if (!size) - size = type_size(&vtop->type, &align); - switch(size) { - case 1: func = TOK___bound_ptr_indir1; break; - case 2: func = TOK___bound_ptr_indir2; break; - case 4: func = TOK___bound_ptr_indir4; break; - case 8: func = TOK___bound_ptr_indir8; break; - case 12: func = TOK___bound_ptr_indir12; break; - case 16: func = TOK___bound_ptr_indir16; break; - default: - tcc_error("unhandled size when dereferencing bounded pointer"); - func = 0; - break; - } - - /* patch relocation */ - /* XXX: find a better solution ? */ - rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); - sym = external_global_sym(func, &func_old_type, 0); - if (!sym->c) - put_extern_sym(sym, NULL, 0, 0); - rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); -} -#endif - -/* Save the stack pointer onto the stack */ -ST_FUNC void gen_vla_sp_save(int addr) { - /* mov %esp,addr(%ebp)*/ - o(0x89); - gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); -} - -/* Restore the SP from a location on the stack */ -ST_FUNC void gen_vla_sp_restore(int addr) { - o(0x8b); - gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); -} - -/* Subtract from the stack pointer, and push the resulting value onto the stack */ -ST_FUNC void gen_vla_alloc(CType *type, int align) { -#ifdef TCC_TARGET_PE - /* alloca does more than just adjust %rsp on Windows */ - vpush_global_sym(&func_old_type, TOK_alloca); - vswap(); /* Move alloca ref past allocation size */ - gfunc_call(1); -#else - int r; - r = gv(RC_INT); /* allocation size */ - /* sub r,%rsp */ - o(0x2b); - o(0xe0 | r); - /* We align to 16 bytes rather than align */ - /* and ~15, %esp */ - o(0xf0e483); - vpop(); -#endif -} - -/* end of X86 code generator */ -/*************************************************************/ -#endif -/*************************************************************/ diff --git a/tinyc/i386-link.c b/tinyc/i386-link.c deleted file mode 100644 index b44664404..000000000 --- a/tinyc/i386-link.c +++ /dev/null @@ -1,244 +0,0 @@ -#ifdef TARGET_DEFS_ONLY - -#define EM_TCC_TARGET EM_386 - -/* relocation type for 32 bit data relocation */ -#define R_DATA_32 R_386_32 -#define R_DATA_PTR R_386_32 -#define R_JMP_SLOT R_386_JMP_SLOT -#define R_GLOB_DAT R_386_GLOB_DAT -#define R_COPY R_386_COPY -#define R_RELATIVE R_386_RELATIVE - -#define R_NUM R_386_NUM - -#define ELF_START_ADDR 0x08048000 -#define ELF_PAGE_SIZE 0x1000 - -#define PCRELATIVE_DLLPLT 0 -#define RELOCATE_DLLPLT 0 - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -/* Returns 1 for a code relocation, 0 for a data relocation. For unknown - relocations, returns -1. */ -int code_reloc (int reloc_type) -{ - switch (reloc_type) { - case R_386_RELATIVE: - case R_386_16: - case R_386_32: - case R_386_GOTPC: - case R_386_GOTOFF: - case R_386_GOT32: - case R_386_GOT32X: - case R_386_GLOB_DAT: - case R_386_COPY: - return 0; - - case R_386_PC16: - case R_386_PC32: - case R_386_PLT32: - case R_386_JMP_SLOT: - return 1; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -/* Returns an enumerator to describe whether and when the relocation needs a - GOT and/or PLT entry to be created. See tcc.h for a description of the - different values. */ -int gotplt_entry_type (int reloc_type) -{ - switch (reloc_type) { - case R_386_RELATIVE: - case R_386_16: - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - case R_386_COPY: - return NO_GOTPLT_ENTRY; - - case R_386_32: - /* This relocations shouldn't normally need GOT or PLT - slots if it weren't for simplicity in the code generator. - See our caller for comments. */ - return AUTO_GOTPLT_ENTRY; - - case R_386_PC16: - case R_386_PC32: - return AUTO_GOTPLT_ENTRY; - - case R_386_GOTPC: - case R_386_GOTOFF: - return BUILD_GOT_ONLY; - - case R_386_GOT32: - case R_386_GOT32X: - case R_386_PLT32: - return ALWAYS_GOTPLT_ENTRY; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) -{ - Section *plt = s1->plt; - uint8_t *p; - int modrm; - unsigned plt_offset, relofs; - - /* on i386 if we build a DLL, we add a %ebx offset */ - if (s1->output_type == TCC_OUTPUT_DLL) - modrm = 0xa3; - else - modrm = 0x25; - - /* empty PLT: create PLT0 entry that pushes the library identifier - (GOT + PTR_SIZE) and jumps to ld.so resolution routine - (GOT + 2 * PTR_SIZE) */ - if (plt->data_offset == 0) { - p = section_ptr_add(plt, 16); - p[0] = 0xff; /* pushl got + PTR_SIZE */ - p[1] = modrm + 0x10; - write32le(p + 2, PTR_SIZE); - p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ - p[7] = modrm; - write32le(p + 8, PTR_SIZE * 2); - } - plt_offset = plt->data_offset; - - /* The PLT slot refers to the relocation entry it needs via offset. - The reloc entry is created below, so its offset is the current - data_offset */ - relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; - - /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ - p = section_ptr_add(plt, 16); - p[0] = 0xff; /* jmp *(got + x) */ - p[1] = modrm; - write32le(p + 2, got_offset); - p[6] = 0x68; /* push $xxx */ - write32le(p + 7, relofs); - p[11] = 0xe9; /* jmp plt_start */ - write32le(p + 12, -(plt->data_offset)); - return plt_offset; -} - -/* relocate the PLT: compute addresses and offsets in the PLT now that final - address for PLT and GOT are known (see fill_program_header) */ -ST_FUNC void relocate_plt(TCCState *s1) -{ - uint8_t *p, *p_end; - - if (!s1->plt) - return; - - p = s1->plt->data; - p_end = p + s1->plt->data_offset; - - if (p < p_end) { - add32le(p + 2, s1->got->sh_addr); - add32le(p + 8, s1->got->sh_addr); - p += 16; - while (p < p_end) { - add32le(p + 2, s1->got->sh_addr); - p += 16; - } - } -} - -static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ - -void relocate_init(Section *sr) -{ - qrel = (ElfW_Rel *) sr->data; -} - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) -{ - int sym_index, esym_index; - - sym_index = ELFW(R_SYM)(rel->r_info); - - switch (type) { - case R_386_32: - if (s1->output_type == TCC_OUTPUT_DLL) { - esym_index = s1->sym_attrs[sym_index].dyn_index; - qrel->r_offset = rel->r_offset; - if (esym_index) { - qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); - qrel++; - return; - } else { - qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); - qrel++; - } - } - add32le(ptr, val); - return; - case R_386_PC32: - if (s1->output_type == TCC_OUTPUT_DLL) { - /* DLL relocation */ - esym_index = s1->sym_attrs[sym_index].dyn_index; - if (esym_index) { - qrel->r_offset = rel->r_offset; - qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); - qrel++; - return; - } - } - add32le(ptr, val - addr); - return; - case R_386_PLT32: - add32le(ptr, val - addr); - return; - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - write32le(ptr, val); - return; - case R_386_GOTPC: - add32le(ptr, s1->got->sh_addr - addr); - return; - case R_386_GOTOFF: - add32le(ptr, val - s1->got->sh_addr); - return; - case R_386_GOT32: - case R_386_GOT32X: - /* we load the got offset */ - add32le(ptr, s1->sym_attrs[sym_index].got_offset); - return; - case R_386_16: - if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { - output_file: - tcc_error("can only produce 16-bit binary files"); - } - write16le(ptr, read16le(ptr) + val); - return; - case R_386_PC16: - if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) - goto output_file; - write16le(ptr, read16le(ptr) + val - addr); - return; - case R_386_RELATIVE: - /* do nothing */ - return; - case R_386_COPY: - /* This relocation must copy initialized data from the library - to the program .bss segment. Currently made like for ARM - (to remove noise of default case). Is this true? - */ - return; - default: - fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", - type, (unsigned)addr, ptr, (unsigned)val); - return; - } -} - -#endif /* !TARGET_DEFS_ONLY */ diff --git a/tinyc/i386-tok.h b/tinyc/i386-tok.h deleted file mode 100644 index 8c25af09d..000000000 --- a/tinyc/i386-tok.h +++ /dev/null @@ -1,253 +0,0 @@ -/* ------------------------------------------------------------------ */ -/* WARNING: relative order of tokens is important. */ - -/* register */ - DEF_ASM(al) - DEF_ASM(cl) - DEF_ASM(dl) - DEF_ASM(bl) - DEF_ASM(ah) - DEF_ASM(ch) - DEF_ASM(dh) - DEF_ASM(bh) - DEF_ASM(ax) - DEF_ASM(cx) - DEF_ASM(dx) - DEF_ASM(bx) - DEF_ASM(sp) - DEF_ASM(bp) - DEF_ASM(si) - DEF_ASM(di) - DEF_ASM(eax) - DEF_ASM(ecx) - DEF_ASM(edx) - DEF_ASM(ebx) - DEF_ASM(esp) - DEF_ASM(ebp) - DEF_ASM(esi) - DEF_ASM(edi) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(rax) - DEF_ASM(rcx) - DEF_ASM(rdx) - DEF_ASM(rbx) - DEF_ASM(rsp) - DEF_ASM(rbp) - DEF_ASM(rsi) - DEF_ASM(rdi) -#endif - DEF_ASM(mm0) - DEF_ASM(mm1) - DEF_ASM(mm2) - DEF_ASM(mm3) - DEF_ASM(mm4) - DEF_ASM(mm5) - DEF_ASM(mm6) - DEF_ASM(mm7) - DEF_ASM(xmm0) - DEF_ASM(xmm1) - DEF_ASM(xmm2) - DEF_ASM(xmm3) - DEF_ASM(xmm4) - DEF_ASM(xmm5) - DEF_ASM(xmm6) - DEF_ASM(xmm7) - DEF_ASM(cr0) - DEF_ASM(cr1) - DEF_ASM(cr2) - DEF_ASM(cr3) - DEF_ASM(cr4) - DEF_ASM(cr5) - DEF_ASM(cr6) - DEF_ASM(cr7) - DEF_ASM(tr0) - DEF_ASM(tr1) - DEF_ASM(tr2) - DEF_ASM(tr3) - DEF_ASM(tr4) - DEF_ASM(tr5) - DEF_ASM(tr6) - DEF_ASM(tr7) - DEF_ASM(db0) - DEF_ASM(db1) - DEF_ASM(db2) - DEF_ASM(db3) - DEF_ASM(db4) - DEF_ASM(db5) - DEF_ASM(db6) - DEF_ASM(db7) - DEF_ASM(dr0) - DEF_ASM(dr1) - DEF_ASM(dr2) - DEF_ASM(dr3) - DEF_ASM(dr4) - DEF_ASM(dr5) - DEF_ASM(dr6) - DEF_ASM(dr7) - DEF_ASM(es) - DEF_ASM(cs) - DEF_ASM(ss) - DEF_ASM(ds) - DEF_ASM(fs) - DEF_ASM(gs) - DEF_ASM(st) - DEF_ASM(rip) - -#ifdef TCC_TARGET_X86_64 - /* The four low parts of sp/bp/si/di that exist only on - x86-64 (encoding aliased to ah,ch,dh,dh when not using REX). */ - DEF_ASM(spl) - DEF_ASM(bpl) - DEF_ASM(sil) - DEF_ASM(dil) -#endif - /* generic two operands */ - DEF_BWLX(mov) - - DEF_BWLX(add) - DEF_BWLX(or) - DEF_BWLX(adc) - DEF_BWLX(sbb) - DEF_BWLX(and) - DEF_BWLX(sub) - DEF_BWLX(xor) - DEF_BWLX(cmp) - - /* unary ops */ - DEF_BWLX(inc) - DEF_BWLX(dec) - DEF_BWLX(not) - DEF_BWLX(neg) - DEF_BWLX(mul) - DEF_BWLX(imul) - DEF_BWLX(div) - DEF_BWLX(idiv) - - DEF_BWLX(xchg) - DEF_BWLX(test) - - /* shifts */ - DEF_BWLX(rol) - DEF_BWLX(ror) - DEF_BWLX(rcl) - DEF_BWLX(rcr) - DEF_BWLX(shl) - DEF_BWLX(shr) - DEF_BWLX(sar) - - DEF_WLX(shld) - DEF_WLX(shrd) - - DEF_ASM(pushw) - DEF_ASM(pushl) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(pushq) -#endif - DEF_ASM(push) - - DEF_ASM(popw) - DEF_ASM(popl) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(popq) -#endif - DEF_ASM(pop) - - DEF_BWL(in) - DEF_BWL(out) - - DEF_WLX(movzb) - DEF_ASM(movzwl) - DEF_ASM(movsbw) - DEF_ASM(movsbl) - DEF_ASM(movswl) -#ifdef TCC_TARGET_X86_64 - DEF_ASM(movsbq) - DEF_ASM(movswq) - DEF_ASM(movzwq) - DEF_ASM(movslq) -#endif - - DEF_WLX(lea) - - DEF_ASM(les) - DEF_ASM(lds) - DEF_ASM(lss) - DEF_ASM(lfs) - DEF_ASM(lgs) - - DEF_ASM(call) - DEF_ASM(jmp) - DEF_ASM(lcall) - DEF_ASM(ljmp) - - DEF_ASMTEST(j,) - - DEF_ASMTEST(set,) - DEF_ASMTEST(set,b) - DEF_ASMTEST(cmov,) - - DEF_WLX(bsf) - DEF_WLX(bsr) - DEF_WLX(bt) - DEF_WLX(bts) - DEF_WLX(btr) - DEF_WLX(btc) - - DEF_WLX(lar) - DEF_WLX(lsl) - - /* generic FP ops */ - DEF_FP(add) - DEF_FP(mul) - - DEF_ASM(fcom) - DEF_ASM(fcom_1) /* non existent op, just to have a regular table */ - DEF_FP1(com) - - DEF_FP(comp) - DEF_FP(sub) - DEF_FP(subr) - DEF_FP(div) - DEF_FP(divr) - - DEF_BWLX(xadd) - DEF_BWLX(cmpxchg) - - /* string ops */ - DEF_BWLX(cmps) - DEF_BWLX(scmp) - DEF_BWL(ins) - DEF_BWL(outs) - DEF_BWLX(lods) - DEF_BWLX(slod) - DEF_BWLX(movs) - DEF_BWLX(smov) - DEF_BWLX(scas) - DEF_BWLX(ssca) - DEF_BWLX(stos) - DEF_BWLX(ssto) - - /* generic asm ops */ -#define ALT(x) -#define DEF_ASM_OP0(name, opcode) DEF_ASM(name) -#define DEF_ASM_OP0L(name, opcode, group, instr_type) -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif - -#define ALT(x) -#define DEF_ASM_OP0(name, opcode) -#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name) -#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name) -#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name) -#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name) -#ifdef TCC_TARGET_X86_64 -# include "x86_64-asm.h" -#else -# include "i386-asm.h" -#endif diff --git a/tinyc/il-gen.c b/tinyc/il-gen.c deleted file mode 100644 index bb670ccb0..000000000 --- a/tinyc/il-gen.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * CIL code generator for TCC - * - * Copyright (c) 2002 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#error this code has bit-rotted since 2003 - -/* number of available registers */ -#define NB_REGS 3 - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_ST 0x0001 /* any stack entry */ -#define RC_ST0 0x0002 /* top of stack */ -#define RC_ST1 0x0004 /* top - 1 */ - -#define RC_INT RC_ST -#define RC_FLOAT RC_ST -#define RC_IRET RC_ST0 /* function return: integer register */ -#define RC_LRET RC_ST0 /* function return: second integer register */ -#define RC_FRET RC_ST0 /* function return: float register */ - -/* pretty names for the registers */ -enum { - REG_ST0 = 0, - REG_ST1, - REG_ST2, -}; - -const int reg_classes[NB_REGS] = { - /* ST0 */ RC_ST | RC_ST0, - /* ST1 */ RC_ST | RC_ST1, - /* ST2 */ RC_ST, -}; - -/* return registers for function */ -#define REG_IRET REG_ST0 /* single word int return register */ -#define REG_LRET REG_ST0 /* second word return register (for long long) */ -#define REG_FRET REG_ST0 /* float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -/* #define INVERT_FUNC_PARAMS */ - -/* defined if structures are passed as pointers. Otherwise structures - are directly pushed on stack. */ -/* #define FUNC_STRUCT_PARAM_AS_PTR */ - -/* pointer size, in bytes */ -#define PTR_SIZE 4 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 8 -#define LDOUBLE_ALIGN 8 - -/* function call context */ -typedef struct GFuncContext { - int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */ -} GFuncContext; - -/******************************************************/ -/* opcode definitions */ - -#define IL_OP_PREFIX 0xFE - -enum ILOPCodes { -#define OP(name, str, n) IL_OP_ ## name = n, -#include "il-opcodes.h" -#undef OP -}; - -char *il_opcodes_str[] = { -#define OP(name, str, n) [n] = str, -#include "il-opcodes.h" -#undef OP -}; - -/******************************************************/ - -/* arguments variable numbers start from there */ -#define ARG_BASE 0x70000000 - -static FILE *il_outfile; - -static void out_byte(int c) -{ - *(char *)ind++ = c; -} - -static void out_le32(int c) -{ - out_byte(c); - out_byte(c >> 8); - out_byte(c >> 16); - out_byte(c >> 24); -} - -static void init_outfile(void) -{ - if (!il_outfile) { - il_outfile = stdout; - fprintf(il_outfile, - ".assembly extern mscorlib\n" - "{\n" - ".ver 1:0:2411:0\n" - "}\n\n"); - } -} - -static void out_op1(int op) -{ - if (op & 0x100) - out_byte(IL_OP_PREFIX); - out_byte(op & 0xff); -} - -/* output an opcode with prefix */ -static void out_op(int op) -{ - out_op1(op); - fprintf(il_outfile, " %s\n", il_opcodes_str[op]); -} - -static void out_opb(int op, int c) -{ - out_op1(op); - out_byte(c); - fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c); -} - -static void out_opi(int op, int c) -{ - out_op1(op); - out_le32(c); - fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c); -} - -/* XXX: not complete */ -static void il_type_to_str(char *buf, int buf_size, - int t, const char *varstr) -{ - int bt; - Sym *s, *sa; - char buf1[256]; - const char *tstr; - - t = t & VT_TYPE; - bt = t & VT_BTYPE; - buf[0] = '\0'; - if (t & VT_UNSIGNED) - pstrcat(buf, buf_size, "unsigned "); - switch(bt) { - case VT_VOID: - tstr = "void"; - goto add_tstr; - case VT_BOOL: - tstr = "bool"; - goto add_tstr; - case VT_BYTE: - tstr = "int8"; - goto add_tstr; - case VT_SHORT: - tstr = "int16"; - goto add_tstr; - case VT_ENUM: - case VT_INT: - case VT_LONG: - tstr = "int32"; - goto add_tstr; - case VT_LLONG: - tstr = "int64"; - goto add_tstr; - case VT_FLOAT: - tstr = "float32"; - goto add_tstr; - case VT_DOUBLE: - case VT_LDOUBLE: - tstr = "float64"; - add_tstr: - pstrcat(buf, buf_size, tstr); - break; - case VT_STRUCT: - tcc_error("structures not handled yet"); - break; - case VT_FUNC: - s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - il_type_to_str(buf, buf_size, s->t, varstr); - pstrcat(buf, buf_size, "("); - sa = s->next; - while (sa != NULL) { - il_type_to_str(buf1, sizeof(buf1), sa->t, NULL); - pstrcat(buf, buf_size, buf1); - sa = sa->next; - if (sa) - pstrcat(buf, buf_size, ", "); - } - pstrcat(buf, buf_size, ")"); - goto no_var; - case VT_PTR: - s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - pstrcpy(buf1, sizeof(buf1), "*"); - if (varstr) - pstrcat(buf1, sizeof(buf1), varstr); - il_type_to_str(buf, buf_size, s->t, buf1); - goto no_var; - } - if (varstr) { - pstrcat(buf, buf_size, " "); - pstrcat(buf, buf_size, varstr); - } - no_var: ; -} - - -/* patch relocation entry with value 'val' */ -void greloc_patch1(Reloc *p, int val) -{ -} - -/* output a symbol and patch all calls to it */ -void gsym_addr(t, a) -{ -} - -/* output jump and return symbol */ -static int out_opj(int op, int c) -{ - out_op1(op); - out_le32(0); - if (c == 0) { - c = ind - (int)cur_text_section->data; - } - fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c); - return c; -} - -void gsym(int t) -{ - fprintf(il_outfile, "L%d:\n", t); -} - -/* load 'r' from value 'sv' */ -void load(int r, SValue *sv) -{ - int v, fc, ft; - - v = sv->r & VT_VALMASK; - fc = sv->c.i; - ft = sv->t; - - if (sv->r & VT_LVAL) { - if (v == VT_LOCAL) { - if (fc >= ARG_BASE) { - fc -= ARG_BASE; - if (fc >= 0 && fc <= 4) { - out_op(IL_OP_LDARG_0 + fc); - } else if (fc <= 0xff) { - out_opb(IL_OP_LDARG_S, fc); - } else { - out_opi(IL_OP_LDARG, fc); - } - } else { - if (fc >= 0 && fc <= 4) { - out_op(IL_OP_LDLOC_0 + fc); - } else if (fc <= 0xff) { - out_opb(IL_OP_LDLOC_S, fc); - } else { - out_opi(IL_OP_LDLOC, fc); - } - } - } else if (v == VT_CONST) { - /* XXX: handle globals */ - out_opi(IL_OP_LDSFLD, 0); - } else { - if ((ft & VT_BTYPE) == VT_FLOAT) { - out_op(IL_OP_LDIND_R4); - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - out_op(IL_OP_LDIND_R8); - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - out_op(IL_OP_LDIND_R8); - } else if ((ft & VT_TYPE) == VT_BYTE) - out_op(IL_OP_LDIND_I1); - else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) - out_op(IL_OP_LDIND_U1); - else if ((ft & VT_TYPE) == VT_SHORT) - out_op(IL_OP_LDIND_I2); - else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) - out_op(IL_OP_LDIND_U2); - else - out_op(IL_OP_LDIND_I4); - } - } else { - if (v == VT_CONST) { - /* XXX: handle globals */ - if (fc >= -1 && fc <= 8) { - out_op(IL_OP_LDC_I4_M1 + fc + 1); - } else { - out_opi(IL_OP_LDC_I4, fc); - } - } else if (v == VT_LOCAL) { - if (fc >= ARG_BASE) { - fc -= ARG_BASE; - if (fc <= 0xff) { - out_opb(IL_OP_LDARGA_S, fc); - } else { - out_opi(IL_OP_LDARGA, fc); - } - } else { - if (fc <= 0xff) { - out_opb(IL_OP_LDLOCA_S, fc); - } else { - out_opi(IL_OP_LDLOCA, fc); - } - } - } else { - /* XXX: do it */ - } - } -} - -/* store register 'r' in lvalue 'v' */ -void store(int r, SValue *sv) -{ - int v, fc, ft; - - v = sv->r & VT_VALMASK; - fc = sv->c.i; - ft = sv->t; - if (v == VT_LOCAL) { - if (fc >= ARG_BASE) { - fc -= ARG_BASE; - /* XXX: check IL arg store semantics */ - if (fc <= 0xff) { - out_opb(IL_OP_STARG_S, fc); - } else { - out_opi(IL_OP_STARG, fc); - } - } else { - if (fc >= 0 && fc <= 4) { - out_op(IL_OP_STLOC_0 + fc); - } else if (fc <= 0xff) { - out_opb(IL_OP_STLOC_S, fc); - } else { - out_opi(IL_OP_STLOC, fc); - } - } - } else if (v == VT_CONST) { - /* XXX: handle globals */ - out_opi(IL_OP_STSFLD, 0); - } else { - if ((ft & VT_BTYPE) == VT_FLOAT) - out_op(IL_OP_STIND_R4); - else if ((ft & VT_BTYPE) == VT_DOUBLE) - out_op(IL_OP_STIND_R8); - else if ((ft & VT_BTYPE) == VT_LDOUBLE) - out_op(IL_OP_STIND_R8); - else if ((ft & VT_BTYPE) == VT_BYTE) - out_op(IL_OP_STIND_I1); - else if ((ft & VT_BTYPE) == VT_SHORT) - out_op(IL_OP_STIND_I2); - else - out_op(IL_OP_STIND_I4); - } -} - -/* start function call and return function call context */ -void gfunc_start(GFuncContext *c, int func_call) -{ - c->func_call = func_call; -} - -/* push function parameter which is in (vtop->t, vtop->c). Stack entry - is then popped. */ -void gfunc_param(GFuncContext *c) -{ - if ((vtop->t & VT_BTYPE) == VT_STRUCT) { - tcc_error("structures passed as value not handled yet"); - } else { - /* simply push on stack */ - gv(RC_ST0); - } - vtop--; -} - -/* generate function call with address in (vtop->t, vtop->c) and free function - context. Stack entry is popped */ -void gfunc_call(GFuncContext *c) -{ - char buf[1024]; - - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - /* XXX: more info needed from tcc */ - il_type_to_str(buf, sizeof(buf), vtop->t, "xxx"); - fprintf(il_outfile, " call %s\n", buf); - } else { - /* indirect call */ - gv(RC_INT); - il_type_to_str(buf, sizeof(buf), vtop->t, NULL); - fprintf(il_outfile, " calli %s\n", buf); - } - vtop--; -} - -/* generate function prolog of type 't' */ -void gfunc_prolog(int t) -{ - int addr, u, func_call; - Sym *sym; - char buf[1024]; - - init_outfile(); - - /* XXX: pass function name to gfunc_prolog */ - il_type_to_str(buf, sizeof(buf), t, funcname); - fprintf(il_outfile, ".method static %s il managed\n", buf); - fprintf(il_outfile, "{\n"); - /* XXX: cannot do better now */ - fprintf(il_outfile, " .maxstack %d\n", NB_REGS); - fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n"); - - if (!strcmp(funcname, "main")) - fprintf(il_outfile, " .entrypoint\n"); - - sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - func_call = sym->r; - - addr = ARG_BASE; - /* if the function returns a structure, then add an - implicit pointer parameter */ - func_vt = sym->t; - func_var = (sym->c == FUNC_ELLIPSIS); - if ((func_vt & VT_BTYPE) == VT_STRUCT) { - func_vc = addr; - addr++; - } - /* define parameters */ - while ((sym = sym->next) != NULL) { - u = sym->t; - sym_push(sym->v & ~SYM_FIELD, u, - VT_LOCAL | lvalue_type(sym->type.t), addr); - addr++; - } -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - out_op(IL_OP_RET); - fprintf(il_outfile, "}\n\n"); -} - -/* generate a jump to a label */ -int gjmp(int t) -{ - return out_opj(IL_OP_BR, t); -} - -/* generate a jump to a fixed address */ -void gjmp_addr(int a) -{ - /* XXX: handle syms */ - out_opi(IL_OP_BR, a); -} - -/* generate a test. set 'inv' to invert test. Stack entry is popped */ -int gtst(int inv, int t) -{ - int v, *p, c; - - v = vtop->r & VT_VALMASK; - if (v == VT_CMP) { - c = vtop->c.i ^ inv; - switch(c) { - case TOK_EQ: - c = IL_OP_BEQ; - break; - case TOK_NE: - c = IL_OP_BNE_UN; - break; - case TOK_LT: - c = IL_OP_BLT; - break; - case TOK_LE: - c = IL_OP_BLE; - break; - case TOK_GT: - c = IL_OP_BGT; - break; - case TOK_GE: - c = IL_OP_BGE; - break; - case TOK_ULT: - c = IL_OP_BLT_UN; - break; - case TOK_ULE: - c = IL_OP_BLE_UN; - break; - case TOK_UGT: - c = IL_OP_BGT_UN; - break; - case TOK_UGE: - c = IL_OP_BGE_UN; - break; - } - t = out_opj(c, t); - } else if (v == VT_JMP || v == VT_JMPI) { - /* && or || optimization */ - if ((v & 1) == inv) { - /* insert vtop->c jump list in t */ - p = &vtop->c.i; - while (*p != 0) - p = (int *)*p; - *p = t; - t = vtop->c.i; - } else { - t = gjmp(t); - gsym(vtop->c.i); - } - } - vtop--; - return t; -} - -/* generate an integer binary operation */ -void gen_opi(int op) -{ - gv2(RC_ST1, RC_ST0); - switch(op) { - case '+': - out_op(IL_OP_ADD); - goto std_op; - case '-': - out_op(IL_OP_SUB); - goto std_op; - case '&': - out_op(IL_OP_AND); - goto std_op; - case '^': - out_op(IL_OP_XOR); - goto std_op; - case '|': - out_op(IL_OP_OR); - goto std_op; - case '*': - out_op(IL_OP_MUL); - goto std_op; - case TOK_SHL: - out_op(IL_OP_SHL); - goto std_op; - case TOK_SHR: - out_op(IL_OP_SHR_UN); - goto std_op; - case TOK_SAR: - out_op(IL_OP_SHR); - goto std_op; - case '/': - case TOK_PDIV: - out_op(IL_OP_DIV); - goto std_op; - case TOK_UDIV: - out_op(IL_OP_DIV_UN); - goto std_op; - case '%': - out_op(IL_OP_REM); - goto std_op; - case TOK_UMOD: - out_op(IL_OP_REM_UN); - std_op: - vtop--; - vtop[0].r = REG_ST0; - break; - case TOK_EQ: - case TOK_NE: - case TOK_LT: - case TOK_LE: - case TOK_GT: - case TOK_GE: - case TOK_ULT: - case TOK_ULE: - case TOK_UGT: - case TOK_UGE: - vtop--; - vtop[0].r = VT_CMP; - vtop[0].c.i = op; - break; - } -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -void gen_opf(int op) -{ - /* same as integer */ - gen_opi(op); -} - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -void gen_cvt_itof(int t) -{ - gv(RC_ST0); - if (t == VT_FLOAT) - out_op(IL_OP_CONV_R4); - else - out_op(IL_OP_CONV_R8); -} - -/* convert fp to int 't' type */ -/* XXX: handle long long case */ -void gen_cvt_ftoi(int t) -{ - gv(RC_ST0); - switch(t) { - case VT_INT | VT_UNSIGNED: - out_op(IL_OP_CONV_U4); - break; - case VT_LLONG: - out_op(IL_OP_CONV_I8); - break; - case VT_LLONG | VT_UNSIGNED: - out_op(IL_OP_CONV_U8); - break; - default: - out_op(IL_OP_CONV_I4); - break; - } -} - -/* convert from one floating point type to another */ -void gen_cvt_ftof(int t) -{ - gv(RC_ST0); - if (t == VT_FLOAT) { - out_op(IL_OP_CONV_R4); - } else { - out_op(IL_OP_CONV_R8); - } -} - -/* end of CIL code generator */ -/*************************************************************/ - diff --git a/tinyc/il-opcodes.h b/tinyc/il-opcodes.h deleted file mode 100644 index d53ffb2c5..000000000 --- a/tinyc/il-opcodes.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * CIL opcode definition - * - * Copyright (c) 2002 Fabrice Bellard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -OP(NOP, "nop", 0x00) -OP(BREAK, "break", 0x01) -OP(LDARG_0, "ldarg.0", 0x02) -OP(LDARG_1, "ldarg.1", 0x03) -OP(LDARG_2, "ldarg.2", 0x04) -OP(LDARG_3, "ldarg.3", 0x05) -OP(LDLOC_0, "ldloc.0", 0x06) -OP(LDLOC_1, "ldloc.1", 0x07) -OP(LDLOC_2, "ldloc.2", 0x08) -OP(LDLOC_3, "ldloc.3", 0x09) -OP(STLOC_0, "stloc.0", 0x0a) -OP(STLOC_1, "stloc.1", 0x0b) -OP(STLOC_2, "stloc.2", 0x0c) -OP(STLOC_3, "stloc.3", 0x0d) -OP(LDARG_S, "ldarg.s", 0x0e) -OP(LDARGA_S, "ldarga.s", 0x0f) -OP(STARG_S, "starg.s", 0x10) -OP(LDLOC_S, "ldloc.s", 0x11) -OP(LDLOCA_S, "ldloca.s", 0x12) -OP(STLOC_S, "stloc.s", 0x13) -OP(LDNULL, "ldnull", 0x14) -OP(LDC_I4_M1, "ldc.i4.m1", 0x15) -OP(LDC_I4_0, "ldc.i4.0", 0x16) -OP(LDC_I4_1, "ldc.i4.1", 0x17) -OP(LDC_I4_2, "ldc.i4.2", 0x18) -OP(LDC_I4_3, "ldc.i4.3", 0x19) -OP(LDC_I4_4, "ldc.i4.4", 0x1a) -OP(LDC_I4_5, "ldc.i4.5", 0x1b) -OP(LDC_I4_6, "ldc.i4.6", 0x1c) -OP(LDC_I4_7, "ldc.i4.7", 0x1d) -OP(LDC_I4_8, "ldc.i4.8", 0x1e) -OP(LDC_I4_S, "ldc.i4.s", 0x1f) -OP(LDC_I4, "ldc.i4", 0x20) -OP(LDC_I8, "ldc.i8", 0x21) -OP(LDC_R4, "ldc.r4", 0x22) -OP(LDC_R8, "ldc.r8", 0x23) -OP(LDPTR, "ldptr", 0x24) -OP(DUP, "dup", 0x25) -OP(POP, "pop", 0x26) -OP(JMP, "jmp", 0x27) -OP(CALL, "call", 0x28) -OP(CALLI, "calli", 0x29) -OP(RET, "ret", 0x2a) -OP(BR_S, "br.s", 0x2b) -OP(BRFALSE_S, "brfalse.s", 0x2c) -OP(BRTRUE_S, "brtrue.s", 0x2d) -OP(BEQ_S, "beq.s", 0x2e) -OP(BGE_S, "bge.s", 0x2f) -OP(BGT_S, "bgt.s", 0x30) -OP(BLE_S, "ble.s", 0x31) -OP(BLT_S, "blt.s", 0x32) -OP(BNE_UN_S, "bne.un.s", 0x33) -OP(BGE_UN_S, "bge.un.s", 0x34) -OP(BGT_UN_S, "bgt.un.s", 0x35) -OP(BLE_UN_S, "ble.un.s", 0x36) -OP(BLT_UN_S, "blt.un.s", 0x37) -OP(BR, "br", 0x38) -OP(BRFALSE, "brfalse", 0x39) -OP(BRTRUE, "brtrue", 0x3a) -OP(BEQ, "beq", 0x3b) -OP(BGE, "bge", 0x3c) -OP(BGT, "bgt", 0x3d) -OP(BLE, "ble", 0x3e) -OP(BLT, "blt", 0x3f) -OP(BNE_UN, "bne.un", 0x40) -OP(BGE_UN, "bge.un", 0x41) -OP(BGT_UN, "bgt.un", 0x42) -OP(BLE_UN, "ble.un", 0x43) -OP(BLT_UN, "blt.un", 0x44) -OP(SWITCH, "switch", 0x45) -OP(LDIND_I1, "ldind.i1", 0x46) -OP(LDIND_U1, "ldind.u1", 0x47) -OP(LDIND_I2, "ldind.i2", 0x48) -OP(LDIND_U2, "ldind.u2", 0x49) -OP(LDIND_I4, "ldind.i4", 0x4a) -OP(LDIND_U4, "ldind.u4", 0x4b) -OP(LDIND_I8, "ldind.i8", 0x4c) -OP(LDIND_I, "ldind.i", 0x4d) -OP(LDIND_R4, "ldind.r4", 0x4e) -OP(LDIND_R8, "ldind.r8", 0x4f) -OP(LDIND_REF, "ldind.ref", 0x50) -OP(STIND_REF, "stind.ref", 0x51) -OP(STIND_I1, "stind.i1", 0x52) -OP(STIND_I2, "stind.i2", 0x53) -OP(STIND_I4, "stind.i4", 0x54) -OP(STIND_I8, "stind.i8", 0x55) -OP(STIND_R4, "stind.r4", 0x56) -OP(STIND_R8, "stind.r8", 0x57) -OP(ADD, "add", 0x58) -OP(SUB, "sub", 0x59) -OP(MUL, "mul", 0x5a) -OP(DIV, "div", 0x5b) -OP(DIV_UN, "div.un", 0x5c) -OP(REM, "rem", 0x5d) -OP(REM_UN, "rem.un", 0x5e) -OP(AND, "and", 0x5f) -OP(OR, "or", 0x60) -OP(XOR, "xor", 0x61) -OP(SHL, "shl", 0x62) -OP(SHR, "shr", 0x63) -OP(SHR_UN, "shr.un", 0x64) -OP(NEG, "neg", 0x65) -OP(NOT, "not", 0x66) -OP(CONV_I1, "conv.i1", 0x67) -OP(CONV_I2, "conv.i2", 0x68) -OP(CONV_I4, "conv.i4", 0x69) -OP(CONV_I8, "conv.i8", 0x6a) -OP(CONV_R4, "conv.r4", 0x6b) -OP(CONV_R8, "conv.r8", 0x6c) -OP(CONV_U4, "conv.u4", 0x6d) -OP(CONV_U8, "conv.u8", 0x6e) -OP(CALLVIRT, "callvirt", 0x6f) -OP(CPOBJ, "cpobj", 0x70) -OP(LDOBJ, "ldobj", 0x71) -OP(LDSTR, "ldstr", 0x72) -OP(NEWOBJ, "newobj", 0x73) -OP(CASTCLASS, "castclass", 0x74) -OP(ISINST, "isinst", 0x75) -OP(CONV_R_UN, "conv.r.un", 0x76) -OP(ANN_DATA_S, "ann.data.s", 0x77) -OP(UNBOX, "unbox", 0x79) -OP(THROW, "throw", 0x7a) -OP(LDFLD, "ldfld", 0x7b) -OP(LDFLDA, "ldflda", 0x7c) -OP(STFLD, "stfld", 0x7d) -OP(LDSFLD, "ldsfld", 0x7e) -OP(LDSFLDA, "ldsflda", 0x7f) -OP(STSFLD, "stsfld", 0x80) -OP(STOBJ, "stobj", 0x81) -OP(CONV_OVF_I1_UN, "conv.ovf.i1.un", 0x82) -OP(CONV_OVF_I2_UN, "conv.ovf.i2.un", 0x83) -OP(CONV_OVF_I4_UN, "conv.ovf.i4.un", 0x84) -OP(CONV_OVF_I8_UN, "conv.ovf.i8.un", 0x85) -OP(CONV_OVF_U1_UN, "conv.ovf.u1.un", 0x86) -OP(CONV_OVF_U2_UN, "conv.ovf.u2.un", 0x87) -OP(CONV_OVF_U4_UN, "conv.ovf.u4.un", 0x88) -OP(CONV_OVF_U8_UN, "conv.ovf.u8.un", 0x89) -OP(CONV_OVF_I_UN, "conv.ovf.i.un", 0x8a) -OP(CONV_OVF_U_UN, "conv.ovf.u.un", 0x8b) -OP(BOX, "box", 0x8c) -OP(NEWARR, "newarr", 0x8d) -OP(LDLEN, "ldlen", 0x8e) -OP(LDELEMA, "ldelema", 0x8f) -OP(LDELEM_I1, "ldelem.i1", 0x90) -OP(LDELEM_U1, "ldelem.u1", 0x91) -OP(LDELEM_I2, "ldelem.i2", 0x92) -OP(LDELEM_U2, "ldelem.u2", 0x93) -OP(LDELEM_I4, "ldelem.i4", 0x94) -OP(LDELEM_U4, "ldelem.u4", 0x95) -OP(LDELEM_I8, "ldelem.i8", 0x96) -OP(LDELEM_I, "ldelem.i", 0x97) -OP(LDELEM_R4, "ldelem.r4", 0x98) -OP(LDELEM_R8, "ldelem.r8", 0x99) -OP(LDELEM_REF, "ldelem.ref", 0x9a) -OP(STELEM_I, "stelem.i", 0x9b) -OP(STELEM_I1, "stelem.i1", 0x9c) -OP(STELEM_I2, "stelem.i2", 0x9d) -OP(STELEM_I4, "stelem.i4", 0x9e) -OP(STELEM_I8, "stelem.i8", 0x9f) -OP(STELEM_R4, "stelem.r4", 0xa0) -OP(STELEM_R8, "stelem.r8", 0xa1) -OP(STELEM_REF, "stelem.ref", 0xa2) -OP(CONV_OVF_I1, "conv.ovf.i1", 0xb3) -OP(CONV_OVF_U1, "conv.ovf.u1", 0xb4) -OP(CONV_OVF_I2, "conv.ovf.i2", 0xb5) -OP(CONV_OVF_U2, "conv.ovf.u2", 0xb6) -OP(CONV_OVF_I4, "conv.ovf.i4", 0xb7) -OP(CONV_OVF_U4, "conv.ovf.u4", 0xb8) -OP(CONV_OVF_I8, "conv.ovf.i8", 0xb9) -OP(CONV_OVF_U8, "conv.ovf.u8", 0xba) -OP(REFANYVAL, "refanyval", 0xc2) -OP(CKFINITE, "ckfinite", 0xc3) -OP(MKREFANY, "mkrefany", 0xc6) -OP(ANN_CALL, "ann.call", 0xc7) -OP(ANN_CATCH, "ann.catch", 0xc8) -OP(ANN_DEAD, "ann.dead", 0xc9) -OP(ANN_HOISTED, "ann.hoisted", 0xca) -OP(ANN_HOISTED_CALL, "ann.hoisted.call", 0xcb) -OP(ANN_LAB, "ann.lab", 0xcc) -OP(ANN_DEF, "ann.def", 0xcd) -OP(ANN_REF_S, "ann.ref.s", 0xce) -OP(ANN_PHI, "ann.phi", 0xcf) -OP(LDTOKEN, "ldtoken", 0xd0) -OP(CONV_U2, "conv.u2", 0xd1) -OP(CONV_U1, "conv.u1", 0xd2) -OP(CONV_I, "conv.i", 0xd3) -OP(CONV_OVF_I, "conv.ovf.i", 0xd4) -OP(CONV_OVF_U, "conv.ovf.u", 0xd5) -OP(ADD_OVF, "add.ovf", 0xd6) -OP(ADD_OVF_UN, "add.ovf.un", 0xd7) -OP(MUL_OVF, "mul.ovf", 0xd8) -OP(MUL_OVF_UN, "mul.ovf.un", 0xd9) -OP(SUB_OVF, "sub.ovf", 0xda) -OP(SUB_OVF_UN, "sub.ovf.un", 0xdb) -OP(ENDFINALLY, "endfinally", 0xdc) -OP(LEAVE, "leave", 0xdd) -OP(LEAVE_S, "leave.s", 0xde) -OP(STIND_I, "stind.i", 0xdf) -OP(CONV_U, "conv.u", 0xe0) - -/* prefix instructions. we use an opcode >= 256 to ease coding */ - -OP(ARGLIST, "arglist", 0x100) -OP(CEQ, "ceq", 0x101) -OP(CGT, "cgt", 0x102) -OP(CGT_UN, "cgt.un", 0x103) -OP(CLT, "clt", 0x104) -OP(CLT_UN, "clt.un", 0x105) -OP(LDFTN, "ldftn", 0x106) -OP(LDVIRTFTN, "ldvirtftn", 0x107) -OP(JMPI, "jmpi", 0x108) -OP(LDARG, "ldarg", 0x109) -OP(LDARGA, "ldarga", 0x10a) -OP(STARG, "starg", 0x10b) -OP(LDLOC, "ldloc", 0x10c) -OP(LDLOCA, "ldloca", 0x10d) -OP(STLOC, "stloc", 0x10e) -OP(LOCALLOC, "localloc", 0x10f) -OP(ENDFILTER, "endfilter", 0x111) -OP(UNALIGNED, "unaligned", 0x112) -OP(VOLATILE, "volatile", 0x113) -OP(TAIL, "tail", 0x114) -OP(INITOBJ, "initobj", 0x115) -OP(ANN_LIVE, "ann.live", 0x116) -OP(CPBLK, "cpblk", 0x117) -OP(INITBLK, "initblk", 0x118) -OP(ANN_REF, "ann.ref", 0x119) -OP(RETHROW, "rethrow", 0x11a) -OP(SIZEOF, "sizeof", 0x11c) -OP(REFANYTYPE, "refanytype", 0x11d) -OP(ANN_DATA, "ann.data", 0x122) -OP(ANN_ARG, "ann.arg", 0x123) diff --git a/tinyc/include/float.h b/tinyc/include/float.h deleted file mode 100644 index f16f1f0cb..000000000 --- a/tinyc/include/float.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _FLOAT_H_ -#define _FLOAT_H_ - -#define FLT_RADIX 2 - -/* IEEE float */ -#define FLT_MANT_DIG 24 -#define FLT_DIG 6 -#define FLT_ROUNDS 1 -#define FLT_EPSILON 1.19209290e-07F -#define FLT_MIN_EXP (-125) -#define FLT_MIN 1.17549435e-38F -#define FLT_MIN_10_EXP (-37) -#define FLT_MAX_EXP 128 -#define FLT_MAX 3.40282347e+38F -#define FLT_MAX_10_EXP 38 - -/* IEEE double */ -#define DBL_MANT_DIG 53 -#define DBL_DIG 15 -#define DBL_EPSILON 2.2204460492503131e-16 -#define DBL_MIN_EXP (-1021) -#define DBL_MIN 2.2250738585072014e-308 -#define DBL_MIN_10_EXP (-307) -#define DBL_MAX_EXP 1024 -#define DBL_MAX 1.7976931348623157e+308 -#define DBL_MAX_10_EXP 308 - -/* horrible intel long double */ -#if defined __i386__ || defined __x86_64__ - -#define LDBL_MANT_DIG 64 -#define LDBL_DIG 18 -#define LDBL_EPSILON 1.08420217248550443401e-19L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176502e+4932L -#define LDBL_MAX_10_EXP 4932 - -#else - -/* same as IEEE double */ -#define LDBL_MANT_DIG 53 -#define LDBL_DIG 15 -#define LDBL_EPSILON 2.2204460492503131e-16 -#define LDBL_MIN_EXP (-1021) -#define LDBL_MIN 2.2250738585072014e-308 -#define LDBL_MIN_10_EXP (-307) -#define LDBL_MAX_EXP 1024 -#define LDBL_MAX 1.7976931348623157e+308 -#define LDBL_MAX_10_EXP 308 - -#endif - -#endif /* _FLOAT_H_ */ diff --git a/tinyc/include/stdarg.h b/tinyc/include/stdarg.h deleted file mode 100644 index 10ce733b4..000000000 --- a/tinyc/include/stdarg.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef _STDARG_H -#define _STDARG_H - -#ifdef __x86_64__ -#ifndef _WIN64 - -//This should be in sync with the declaration on our lib/libtcc1.c -/* GCC compatible definition of va_list. */ -typedef struct { - unsigned int gp_offset; - unsigned int fp_offset; - union { - unsigned int overflow_offset; - char *overflow_arg_area; - }; - char *reg_save_area; -} __va_list_struct; - -typedef __va_list_struct va_list[1]; - -void __va_start(__va_list_struct *ap, void *fp); -void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align); - -#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0)) -#define va_arg(ap, type) \ - (*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type)))) -#define va_copy(dest, src) (*(dest) = *(src)) -#define va_end(ap) - -/* avoid conflicting definition for va_list on Macs. */ -#define _VA_LIST_T - -#else /* _WIN64 */ -typedef char *va_list; -#define va_start(ap,last) __builtin_va_start(ap,last) -#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ - ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) -#define va_copy(dest, src) ((dest) = (src)) -#define va_end(ap) -#endif - -#elif __arm__ -typedef char *va_list; -#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) -#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ - & ~(_tcc_alignof(type) - 1)) -#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3) -#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ - &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) -#define va_copy(dest, src) (dest) = (src) -#define va_end(ap) - -#elif defined(__aarch64__) -typedef struct { - void *__stack; - void *__gr_top; - void *__vr_top; - int __gr_offs; - int __vr_offs; -} va_list; -#define va_start(ap, last) __va_start(ap, last) -#define va_arg(ap, type) __va_arg(ap, type) -#define va_end(ap) -#define va_copy(dest, src) ((dest) = (src)) - -#else /* __i386__ */ -typedef char *va_list; -/* only correct for i386 */ -#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3) -#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3))) -#define va_copy(dest, src) (dest) = (src) -#define va_end(ap) -#endif - -/* fix a buggy dependency on GCC in libio.h */ -typedef va_list __gnuc_va_list; -#define _VA_LIST_DEFINED - -#endif /* _STDARG_H */ diff --git a/tinyc/include/stdbool.h b/tinyc/include/stdbool.h deleted file mode 100644 index d2ee446e7..000000000 --- a/tinyc/include/stdbool.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _STDBOOL_H -#define _STDBOOL_H - -/* ISOC99 boolean */ - -#define bool _Bool -#define true 1 -#define false 0 -#define __bool_true_false_are_defined 1 - -#endif /* _STDBOOL_H */ diff --git a/tinyc/include/stddef.h b/tinyc/include/stddef.h deleted file mode 100644 index 694d50375..000000000 --- a/tinyc/include/stddef.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _STDDEF_H -#define _STDDEF_H - -typedef __SIZE_TYPE__ size_t; -typedef __PTRDIFF_TYPE__ ssize_t; -typedef __WCHAR_TYPE__ wchar_t; -typedef __PTRDIFF_TYPE__ ptrdiff_t; -typedef __PTRDIFF_TYPE__ intptr_t; -typedef __SIZE_TYPE__ uintptr_t; - -#ifndef __int8_t_defined -#define __int8_t_defined -typedef signed char int8_t; -typedef signed short int int16_t; -typedef signed int int32_t; -#ifdef __LP64__ -typedef signed long int int64_t; -#else -typedef signed long long int int64_t; -#endif -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -#ifdef __LP64__ -typedef unsigned long int uint64_t; -#else -typedef unsigned long long int uint64_t; -#endif -#endif - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#define offsetof(type, field) ((size_t)&((type *)0)->field) - -void *alloca(size_t size); - -#endif - -/* Older glibc require a wint_t from (when requested - by __need_wint_t, as otherwise stddef.h isn't allowed to - define this type). Note that this must be outside the normal - _STDDEF_H guard, so that it works even when we've included the file - already (without requiring wint_t). Some other libs define _WINT_T - if they've already provided that type, so we can use that as guard. - TCC defines __WINT_TYPE__ for us. */ -#if defined (__need_wint_t) -#ifndef _WINT_T -#define _WINT_T -typedef __WINT_TYPE__ wint_t; -#endif -#undef __need_wint_t -#endif diff --git a/tinyc/include/varargs.h b/tinyc/include/varargs.h deleted file mode 100644 index d614366ed..000000000 --- a/tinyc/include/varargs.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _VARARGS_H -#define _VARARGS_H - -#error "TinyCC no longer implements ." -#error "Revise your code to use ." - -#endif diff --git a/tinyc/lib/alloca-arm.S b/tinyc/lib/alloca-arm.S deleted file mode 100644 index 68556e36d..000000000 --- a/tinyc/lib/alloca-arm.S +++ /dev/null @@ -1,17 +0,0 @@ - .text - .align 2 - .global alloca - .type alloca, %function -alloca: -#ifdef __TINYC__ - .int 0xe060d00d - .int 0xe3cdd007 - .int 0xe1a0000d - .int 0xe1a0f00e -#else - rsb sp, r0, sp - bic sp, sp, #7 - mov r0, sp - mov pc, lr -#endif - .size alloca, .-alloca diff --git a/tinyc/lib/alloca86-bt.S b/tinyc/lib/alloca86-bt.S deleted file mode 100644 index 4f95cf134..000000000 --- a/tinyc/lib/alloca86-bt.S +++ /dev/null @@ -1,47 +0,0 @@ -/* ---------------------------------------------- */ -/* alloca86-bt.S */ - -.globl __bound_alloca - -__bound_alloca: - pop %edx - pop %eax - mov %eax, %ecx - add $3,%eax - and $-4,%eax - jz p6 - -#ifdef _WIN32 -p4: - cmp $4096,%eax - jbe p5 - test %eax,-4096(%esp) - sub $4096,%esp - sub $4096,%eax - jmp p4 - -p5: -#endif - - sub %eax,%esp - mov %esp,%eax - - push %edx - push %eax - push %ecx - push %eax - call __bound_new_region - add $8, %esp - pop %eax - pop %edx - -p6: - push %edx - push %edx - ret - -/* mark stack as nonexecutable */ -#if defined __ELF__ && defined __linux__ - .section .note.GNU-stack,"",@progbits -#endif -/* ---------------------------------------------- */ diff --git a/tinyc/lib/alloca86.S b/tinyc/lib/alloca86.S deleted file mode 100644 index bb7a2c24a..000000000 --- a/tinyc/lib/alloca86.S +++ /dev/null @@ -1,31 +0,0 @@ -/* ---------------------------------------------- */ -/* alloca86.S */ - -.globl alloca - -alloca: - pop %edx - pop %eax - add $3,%eax - and $-4,%eax - jz p3 - -#ifdef _WIN32 -p1: - cmp $4096,%eax - jbe p2 - test %eax,-4096(%esp) - sub $4096,%esp - sub $4096,%eax - jmp p1 -p2: -#endif - - sub %eax,%esp - mov %esp,%eax -p3: - push %edx - push %edx - ret - -/* ---------------------------------------------- */ diff --git a/tinyc/lib/alloca86_64-bt.S b/tinyc/lib/alloca86_64-bt.S deleted file mode 100644 index 4cbad90f8..000000000 --- a/tinyc/lib/alloca86_64-bt.S +++ /dev/null @@ -1,56 +0,0 @@ -/* ---------------------------------------------- */ -/* alloca86_64.S */ - -.globl __bound_alloca -__bound_alloca: - -#ifdef _WIN32 - # bound checking is not implemented - pop %rdx - mov %rcx,%rax - add $15,%rax - and $-16,%rax - jz p3 - -p1: - cmp $4096,%rax - jbe p2 - test %rax,-4096(%rsp) - sub $4096,%rsp - sub $4096,%rax - jmp p1 -p2: - - sub %rax,%rsp - mov %rsp,%rax - add $32,%rax - -p3: - push %rdx - ret -#else - pop %rdx - mov %rdi,%rax - mov %rax,%rsi # size, a second parm to the __bound_new_region - - add $15,%rax - and $-16,%rax - jz p3 - - - sub %rax,%rsp - mov %rsp,%rdi # pointer, a first parm to the __bound_new_region - mov %rsp,%rax - - push %rdx - push %rax - call __bound_new_region - pop %rax - pop %rdx - -p3: - push %rdx - ret -#endif - -/* ---------------------------------------------- */ diff --git a/tinyc/lib/alloca86_64.S b/tinyc/lib/alloca86_64.S deleted file mode 100644 index ae3c97de3..000000000 --- a/tinyc/lib/alloca86_64.S +++ /dev/null @@ -1,34 +0,0 @@ -/* ---------------------------------------------- */ -/* alloca86_64.S */ - -.globl alloca - -alloca: - pop %rdx -#ifdef _WIN32 - mov %rcx,%rax -#else - mov %rdi,%rax -#endif - add $15,%rax - and $-16,%rax - jz p3 - -#ifdef _WIN32 -p1: - cmp $4096,%rax - jbe p2 - test %rax,-4096(%rsp) - sub $4096,%rsp - sub $4096,%rax - jmp p1 -p2: -#endif - - sub %rax,%rsp - mov %rsp,%rax -p3: - push %rdx - ret - -/* ---------------------------------------------- */ diff --git a/tinyc/lib/armeabi.c b/tinyc/lib/armeabi.c deleted file mode 100644 index a59640dd0..000000000 --- a/tinyc/lib/armeabi.c +++ /dev/null @@ -1,501 +0,0 @@ -/* TCC ARM runtime EABI - Copyright (C) 2013 Thomas Preud'homme - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.*/ - -#ifdef __TINYC__ -#define INT_MIN (-2147483647 - 1) -#define INT_MAX 2147483647 -#define UINT_MAX 0xffffffff -#define LONG_MIN (-2147483647L - 1) -#define LONG_MAX 2147483647L -#define ULONG_MAX 0xffffffffUL -#define LLONG_MAX 9223372036854775807LL -#define LLONG_MIN (-9223372036854775807LL - 1) -#define ULLONG_MAX 0xffffffffffffffffULL -#else -#include -#endif - -/* We rely on the little endianness and EABI calling convention for this to - work */ - -typedef struct double_unsigned_struct { - unsigned low; - unsigned high; -} double_unsigned_struct; - -typedef struct unsigned_int_struct { - unsigned low; - int high; -} unsigned_int_struct; - -#define REGS_RETURN(name, type) \ - void name ## _return(type ret) {} - - -/* Float helper functions */ - -#define FLOAT_EXP_BITS 8 -#define FLOAT_FRAC_BITS 23 - -#define DOUBLE_EXP_BITS 11 -#define DOUBLE_FRAC_BITS 52 - -#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1) - -REGS_RETURN(unsigned_int_struct, unsigned_int_struct) -REGS_RETURN(double_unsigned_struct, double_unsigned_struct) - -/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */ - - -/* float to [unsigned] long long conversion */ -#define DEFINE__AEABI_F2XLZ(name, with_sign) \ -void __aeabi_ ## name(unsigned val) \ -{ \ - int exp, high_shift, sign; \ - double_unsigned_struct ret; \ - \ - /* compute sign */ \ - sign = val >> 31; \ - \ - /* compute real exponent */ \ - exp = val >> FLOAT_FRAC_BITS; \ - exp &= (1 << FLOAT_EXP_BITS) - 1; \ - exp -= ONE_EXP(FLOAT); \ - \ - /* undefined behavior if truncated value cannot be represented */ \ - if (with_sign) { \ - if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \ - return; \ - } else { \ - if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \ - return; \ - } \ - \ - val &= (1 << FLOAT_FRAC_BITS) - 1; \ - if (exp >= 32) { \ - ret.high = 1 << (exp - 32); \ - if (exp - 32 >= FLOAT_FRAC_BITS) { \ - ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \ - ret.low = 0; \ - } else { \ - high_shift = FLOAT_FRAC_BITS - (exp - 32); \ - ret.high |= val >> high_shift; \ - ret.low = val << (32 - high_shift); \ - } \ - } else { \ - ret.high = 0; \ - ret.low = 1 << exp; \ - if (exp > FLOAT_FRAC_BITS) \ - ret.low |= val << (exp - FLOAT_FRAC_BITS); \ - else \ - ret.low |= val >> (FLOAT_FRAC_BITS - exp); \ - } \ - \ - /* encode negative integer using 2's complement */ \ - if (with_sign && sign) { \ - ret.low = ~ret.low; \ - ret.high = ~ret.high; \ - if (ret.low == UINT_MAX) { \ - ret.low = 0; \ - ret.high++; \ - } else \ - ret.low++; \ - } \ - \ - double_unsigned_struct_return(ret); \ -} - -/* float to unsigned long long conversion */ -DEFINE__AEABI_F2XLZ(f2ulz, 0) - -/* float to long long conversion */ -DEFINE__AEABI_F2XLZ(f2lz, 1) - -/* double to [unsigned] long long conversion */ -#define DEFINE__AEABI_D2XLZ(name, with_sign) \ -void __aeabi_ ## name(double_unsigned_struct val) \ -{ \ - int exp, high_shift, sign; \ - double_unsigned_struct ret; \ - \ - /* compute sign */ \ - sign = val.high >> 31; \ - \ - /* compute real exponent */ \ - exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \ - exp &= (1 << DOUBLE_EXP_BITS) - 1; \ - exp -= ONE_EXP(DOUBLE); \ - \ - /* undefined behavior if truncated value cannot be represented */ \ - if (with_sign) { \ - if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \ - return; \ - } else { \ - if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \ - return; \ - } \ - \ - val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \ - if (exp >= 32) { \ - ret.high = 1 << (exp - 32); \ - if (exp >= DOUBLE_FRAC_BITS) { \ - high_shift = exp - DOUBLE_FRAC_BITS; \ - ret.high |= val.high << high_shift; \ - ret.high |= val.low >> (32 - high_shift); \ - ret.low = val.low << high_shift; \ - } else { \ - high_shift = DOUBLE_FRAC_BITS - exp; \ - ret.high |= val.high >> high_shift; \ - ret.low = val.high << (32 - high_shift); \ - ret.low |= val.low >> high_shift; \ - } \ - } else { \ - ret.high = 0; \ - ret.low = 1 << exp; \ - if (exp > DOUBLE_FRAC_BITS - 32) { \ - high_shift = exp - DOUBLE_FRAC_BITS - 32; \ - ret.low |= val.high << high_shift; \ - ret.low |= val.low >> (32 - high_shift); \ - } else \ - ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \ - } \ - \ - /* encode negative integer using 2's complement */ \ - if (with_sign && sign) { \ - ret.low = ~ret.low; \ - ret.high = ~ret.high; \ - if (ret.low == UINT_MAX) { \ - ret.low = 0; \ - ret.high++; \ - } else \ - ret.low++; \ - } \ - \ - double_unsigned_struct_return(ret); \ -} - -/* double to unsigned long long conversion */ -DEFINE__AEABI_D2XLZ(d2ulz, 0) - -/* double to long long conversion */ -DEFINE__AEABI_D2XLZ(d2lz, 1) - -/* long long to float conversion */ -#define DEFINE__AEABI_XL2F(name, with_sign) \ -unsigned __aeabi_ ## name(unsigned long long v) \ -{ \ - int s /* shift */, flb /* first lost bit */, sign = 0; \ - unsigned p = 0 /* power */, ret; \ - double_unsigned_struct val; \ - \ - /* fraction in negative float is encoded in 1's complement */ \ - if (with_sign && (v & (1ULL << 63))) { \ - sign = 1; \ - v = ~v + 1; \ - } \ - val.low = v; \ - val.high = v >> 32; \ - /* fill fraction bits */ \ - for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \ - if (p) { \ - ret = val.high & (p - 1); \ - if (s < FLOAT_FRAC_BITS) { \ - ret <<= FLOAT_FRAC_BITS - s; \ - ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \ - flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \ - } else { \ - flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \ - ret >>= s - FLOAT_FRAC_BITS; \ - } \ - s += 32; \ - } else { \ - for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ - if (p) { \ - ret = val.low & (p - 1); \ - if (s <= FLOAT_FRAC_BITS) { \ - ret <<= FLOAT_FRAC_BITS - s; \ - flb = 0; \ - } else { \ - flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \ - ret >>= s - FLOAT_FRAC_BITS; \ - } \ - } else \ - return 0; \ - } \ - if (flb) \ - ret++; \ - \ - /* fill exponent bits */ \ - ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \ - \ - /* fill sign bit */ \ - ret |= sign << 31; \ - \ - return ret; \ -} - -/* unsigned long long to float conversion */ -DEFINE__AEABI_XL2F(ul2f, 0) - -/* long long to float conversion */ -DEFINE__AEABI_XL2F(l2f, 1) - -/* long long to double conversion */ -#define __AEABI_XL2D(name, with_sign) \ -void __aeabi_ ## name(unsigned long long v) \ -{ \ - int s /* shift */, high_shift, sign = 0; \ - unsigned tmp, p = 0; \ - double_unsigned_struct val, ret; \ - \ - /* fraction in negative float is encoded in 1's complement */ \ - if (with_sign && (v & (1ULL << 63))) { \ - sign = 1; \ - v = ~v + 1; \ - } \ - val.low = v; \ - val.high = v >> 32; \ - \ - /* fill fraction bits */ \ - for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \ - if (p) { \ - tmp = val.high & (p - 1); \ - if (s < DOUBLE_FRAC_BITS - 32) { \ - high_shift = DOUBLE_FRAC_BITS - 32 - s; \ - ret.high = tmp << high_shift; \ - ret.high |= val.low >> (32 - high_shift); \ - ret.low = val.low << high_shift; \ - } else { \ - high_shift = s - (DOUBLE_FRAC_BITS - 32); \ - ret.high = tmp >> high_shift; \ - ret.low = tmp << (32 - high_shift); \ - ret.low |= val.low >> high_shift; \ - if ((val.low >> (high_shift - 1)) & 1) { \ - if (ret.low == UINT_MAX) { \ - ret.high++; \ - ret.low = 0; \ - } else \ - ret.low++; \ - } \ - } \ - s += 32; \ - } else { \ - for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ - if (p) { \ - tmp = val.low & (p - 1); \ - if (s <= DOUBLE_FRAC_BITS - 32) { \ - high_shift = DOUBLE_FRAC_BITS - 32 - s; \ - ret.high = tmp << high_shift; \ - ret.low = 0; \ - } else { \ - high_shift = s - (DOUBLE_FRAC_BITS - 32); \ - ret.high = tmp >> high_shift; \ - ret.low = tmp << (32 - high_shift); \ - } \ - } else { \ - ret.high = ret.low = 0; \ - double_unsigned_struct_return(ret); \ - } \ - } \ - \ - /* fill exponent bits */ \ - ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \ - \ - /* fill sign bit */ \ - ret.high |= sign << 31; \ - \ - double_unsigned_struct_return(ret); \ -} - -/* unsigned long long to double conversion */ -__AEABI_XL2D(ul2d, 0) - -/* long long to double conversion */ -__AEABI_XL2D(l2d, 1) - - -/* Long long helper functions */ - -/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */ - -#define define_aeabi_xdivmod_signed_type(basetype, type) \ -typedef struct type { \ - basetype quot; \ - unsigned basetype rem; \ -} type - -#define define_aeabi_xdivmod_unsigned_type(basetype, type) \ -typedef struct type { \ - basetype quot; \ - basetype rem; \ -} type - -#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \ -static inline rettype aeabi_ ## name (type num, type den) \ -{ \ - rettype ret; \ - type quot = 0; \ - \ - /* Increase quotient while it is less than numerator */ \ - while (num >= den) { \ - type q = 1; \ - \ - /* Find closest power of two */ \ - while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \ - q <<= 1; \ - \ - /* Compute difference between current quotient and numerator */ \ - num -= q * den; \ - quot += q; \ - } \ - ret.quot = quot; \ - ret.rem = num; \ - return ret; \ -} - -#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \ -void __aeabi_ ## name(type numerator, type denominator) \ -{ \ - unsigned type num, den; \ - urettype uxdiv_ret; \ - rettype ret; \ - \ - if (numerator >= 0) \ - num = numerator; \ - else \ - num = 0 - numerator; \ - if (denominator >= 0) \ - den = denominator; \ - else \ - den = 0 - denominator; \ - uxdiv_ret = aeabi_ ## uiname(num, den); \ - /* signs differ */ \ - if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \ - ret.quot = 0 - uxdiv_ret.quot; \ - else \ - ret.quot = uxdiv_ret.quot; \ - if (numerator < 0) \ - ret.rem = 0 - uxdiv_ret.rem; \ - else \ - ret.rem = uxdiv_ret.rem; \ - \ - rettype ## _return(ret); \ -} - -define_aeabi_xdivmod_signed_type(long long, lldiv_t); -define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t); -define_aeabi_xdivmod_signed_type(int, idiv_t); -define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t); - -REGS_RETURN(lldiv_t, lldiv_t) -REGS_RETURN(ulldiv_t, ulldiv_t) -REGS_RETURN(idiv_t, idiv_t) -REGS_RETURN(uidiv_t, uidiv_t) - -AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULLONG) - -__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG) - -void __aeabi_uldivmod(unsigned long long num, unsigned long long den) -{ - ulldiv_t_return(aeabi_uldivmod(num, den)); -} - -void __aeabi_llsl(double_unsigned_struct val, int shift) -{ - double_unsigned_struct ret; - - if (shift >= 32) { - val.high = val.low; - val.low = 0; - shift -= 32; - } - if (shift > 0) { - ret.low = val.low << shift; - ret.high = (val.high << shift) | (val.low >> (32 - shift)); - double_unsigned_struct_return(ret); - return; - } - double_unsigned_struct_return(val); -} - -#define aeabi_lsr(val, shift, fill, type) \ - type ## _struct ret; \ - \ - if (shift >= 32) { \ - val.low = val.high; \ - val.high = fill; \ - shift -= 32; \ - } \ - if (shift > 0) { \ - ret.high = val.high >> shift; \ - ret.low = (val.high << (32 - shift)) | (val.low >> shift); \ - type ## _struct_return(ret); \ - return; \ - } \ - type ## _struct_return(val); - -void __aeabi_llsr(double_unsigned_struct val, int shift) -{ - aeabi_lsr(val, shift, 0, double_unsigned); -} - -void __aeabi_lasr(unsigned_int_struct val, int shift) -{ - aeabi_lsr(val, shift, val.high >> 31, unsigned_int); -} - - -/* Integer division functions */ - -AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT) - -int __aeabi_idiv(int numerator, int denominator) -{ - unsigned num, den; - uidiv_t ret; - - if (numerator >= 0) - num = numerator; - else - num = 0 - numerator; - if (denominator >= 0) - den = denominator; - else - den = 0 - denominator; - ret = aeabi_uidivmod(num, den); - if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */ - ret.quot *= -1; - return ret.quot; -} - -unsigned __aeabi_uidiv(unsigned num, unsigned den) -{ - return aeabi_uidivmod(num, den).quot; -} - -__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT) - -void __aeabi_uidivmod(unsigned num, unsigned den) -{ - uidiv_t_return(aeabi_uidivmod(num, den)); -} diff --git a/tinyc/lib/armflush.c b/tinyc/lib/armflush.c deleted file mode 100644 index eae32605f..000000000 --- a/tinyc/lib/armflush.c +++ /dev/null @@ -1,58 +0,0 @@ -/* armflush.c - flush the instruction cache - - __clear_cache is used in tccrun.c, It is a built-in - intrinsic with gcc. However tcc in order to compile - itself needs this function */ - -#ifdef __TINYC__ - -/* syscall wrapper */ -unsigned syscall(unsigned syscall_nr, ...); - -/* arm-tcc supports only fake asm currently */ -__asm__( - ".global syscall\n" - "syscall:\n" - ".int 0xe92d4080\n" // push {r7, lr} - ".int 0xe1a07000\n" // mov r7, r0 - ".int 0xe1a00001\n" // mov r0, r1 - ".int 0xe1a01002\n" // mov r1, r2 - ".int 0xe1a02003\n" // mov r2, r3 - ".int 0xef000000\n" // svc 0x00000000 - ".int 0xe8bd8080\n" // pop {r7, pc} - ); - -/* from unistd.h: */ -#if defined(__thumb__) || defined(__ARM_EABI__) -# define __NR_SYSCALL_BASE 0x0 -#else -# define __NR_SYSCALL_BASE 0x900000 -#endif -#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000) -#define __ARM_NR_cacheflush (__ARM_NR_BASE+2) - -#else - -#define _GNU_SOURCE -#include -#include -#include - -#endif - -/* Flushing for tccrun */ -void __clear_cache(void *beginning, void *end) -{ -/* __ARM_NR_cacheflush is kernel private and should not be used in user space. - * However, there is no ARM asm parser in tcc so we use it for now */ -#if 1 - syscall(__ARM_NR_cacheflush, beginning, end, 0); -#else - __asm__ ("push {r7}\n\t" - "mov r7, #0xf0002\n\t" - "mov r2, #0\n\t" - "swi 0\n\t" - "pop {r7}\n\t" - "ret"); -#endif -} diff --git a/tinyc/lib/bcheck.c b/tinyc/lib/bcheck.c deleted file mode 100644 index 90f0ad2c3..000000000 --- a/tinyc/lib/bcheck.c +++ /dev/null @@ -1,979 +0,0 @@ -/* - * Tiny C Memory and bounds checker - * - * Copyright (c) 2002 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include - -#if !defined(__FreeBSD__) \ - && !defined(__FreeBSD_kernel__) \ - && !defined(__DragonFly__) \ - && !defined(__OpenBSD__) \ - && !defined(__NetBSD__) -#include -#endif - -#if !defined(_WIN32) -#include -#endif - -/* #define BOUND_DEBUG */ - -#ifdef BOUND_DEBUG - #define dprintf(a...) fprintf(a) -#else - #define dprintf(a...) -#endif - -/* define so that bound array is static (faster, but use memory if - bound checking not used) */ -/* #define BOUND_STATIC */ - -/* use malloc hooks. Currently the code cannot be reliable if no hooks */ -#define CONFIG_TCC_MALLOC_HOOKS -#define HAVE_MEMALIGN - -#if defined(__FreeBSD__) \ - || defined(__FreeBSD_kernel__) \ - || defined(__DragonFly__) \ - || defined(__OpenBSD__) \ - || defined(__NetBSD__) \ - || defined(__dietlibc__) \ - || defined(_WIN32) -//#warning Bound checking does not support malloc (etc.) in this environment. -#undef CONFIG_TCC_MALLOC_HOOKS -#undef HAVE_MEMALIGN -#endif - -#define BOUND_T1_BITS 13 -#define BOUND_T2_BITS 11 -#define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS) -#define BOUND_E_BITS (sizeof(size_t)) - -#define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS) -#define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS) -#define BOUND_T3_SIZE ((size_t)1 << BOUND_T3_BITS) - -#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS) -#define BOUND_T23_SIZE ((size_t)1 << BOUND_T23_BITS) - - -/* this pointer is generated when bound check is incorrect */ -#define INVALID_POINTER ((void *)(-2)) -/* size of an empty region */ -#define EMPTY_SIZE ((size_t)(-1)) -/* size of an invalid region */ -#define INVALID_SIZE 0 - -typedef struct BoundEntry { - size_t start; - size_t size; - struct BoundEntry *next; - size_t is_invalid; /* true if pointers outside region are invalid */ -} BoundEntry; - -/* external interface */ -void __bound_init(void); -void __bound_new_region(void *p, size_t size); -int __bound_delete_region(void *p); - -#ifdef __attribute__ - /* an __attribute__ macro is defined in the system headers */ - #undef __attribute__ -#endif -#define FASTCALL __attribute__((regparm(3))) - -void *__bound_malloc(size_t size, const void *caller); -void *__bound_memalign(size_t size, size_t align, const void *caller); -void __bound_free(void *ptr, const void *caller); -void *__bound_realloc(void *ptr, size_t size, const void *caller); -static void *libc_malloc(size_t size); -static void libc_free(void *ptr); -static void install_malloc_hooks(void); -static void restore_malloc_hooks(void); - -#ifdef CONFIG_TCC_MALLOC_HOOKS -static void *saved_malloc_hook; -static void *saved_free_hook; -static void *saved_realloc_hook; -static void *saved_memalign_hook; -#endif - -/* TCC definitions */ -extern char __bounds_start; /* start of static bounds table */ -/* error message, just for TCC */ -const char *__bound_error_msg; - -/* runtime error output */ -extern void rt_error(size_t pc, const char *fmt, ...); - -#ifdef BOUND_STATIC -static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */ -#else -static BoundEntry **__bound_t1; /* page table */ -#endif -static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */ -static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */ - -static BoundEntry *__bound_find_region(BoundEntry *e1, void *p) -{ - size_t addr, tmp; - BoundEntry *e; - - e = e1; - while (e != NULL) { - addr = (size_t)p; - addr -= e->start; - if (addr <= e->size) { - /* put region at the head */ - tmp = e1->start; - e1->start = e->start; - e->start = tmp; - tmp = e1->size; - e1->size = e->size; - e->size = tmp; - return e1; - } - e = e->next; - } - /* no entry found: return empty entry or invalid entry */ - if (e1->is_invalid) - return __bound_invalid_t2; - else - return __bound_empty_t2; -} - -/* print a bound error message */ -static void bound_error(const char *fmt, ...) -{ - __bound_error_msg = fmt; - fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt); - *(void **)0 = 0; /* force a runtime error */ -} - -static void bound_alloc_error(void) -{ - bound_error("not enough memory for bound checking code"); -} - -/* return '(p + offset)' for pointer arithmetic (a pointer can reach - the end of a region in this case */ -void * FASTCALL __bound_ptr_add(void *p, size_t offset) -{ - size_t addr = (size_t)p; - BoundEntry *e; - - dprintf(stderr, "%s %s: %p %x\n", - __FILE__, __FUNCTION__, p, (unsigned)offset); - - __bound_init(); - - e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; - e = (BoundEntry *)((char *)e + - ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); - addr -= e->start; - if (addr > e->size) { - e = __bound_find_region(e, p); - addr = (size_t)p - e->start; - } - addr += offset; - if (addr >= e->size) { - fprintf(stderr,"%s %s: %p is outside of the region\n", - __FILE__, __FUNCTION__, p + offset); - return INVALID_POINTER; /* return an invalid pointer */ - } - return p + offset; -} - -/* return '(p + offset)' for pointer indirection (the resulting must - be strictly inside the region */ -#define BOUND_PTR_INDIR(dsize) \ -void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ -{ \ - size_t addr = (size_t)p; \ - BoundEntry *e; \ - \ - dprintf(stderr, "%s %s: %p %x start\n", \ - __FILE__, __FUNCTION__, p, (unsigned)offset); \ - \ - __bound_init(); \ - e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \ - e = (BoundEntry *)((char *)e + \ - ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \ - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \ - addr -= e->start; \ - if (addr > e->size) { \ - e = __bound_find_region(e, p); \ - addr = (size_t)p - e->start; \ - } \ - addr += offset + dsize; \ - if (addr > e->size) { \ - fprintf(stderr,"%s %s: %p is outside of the region\n", \ - __FILE__, __FUNCTION__, p + offset); \ - return INVALID_POINTER; /* return an invalid pointer */ \ - } \ - dprintf(stderr, "%s %s: return p+offset = %p\n", \ - __FILE__, __FUNCTION__, p + offset); \ - return p + offset; \ -} - -BOUND_PTR_INDIR(1) -BOUND_PTR_INDIR(2) -BOUND_PTR_INDIR(4) -BOUND_PTR_INDIR(8) -BOUND_PTR_INDIR(12) -BOUND_PTR_INDIR(16) - -#if defined(__GNUC__) && (__GNUC__ >= 6) -/* - * At least gcc 6.2 complains when __builtin_frame_address is used with - * nonzero argument. - */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wframe-address" -#endif - -/* return the frame pointer of the caller */ -#define GET_CALLER_FP(fp)\ -{\ - fp = (size_t)__builtin_frame_address(1);\ -} - -/* called when entering a function to add all the local regions */ -void FASTCALL __bound_local_new(void *p1) -{ - size_t addr, size, fp, *p = p1; - - dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p); - GET_CALLER_FP(fp); - for(;;) { - addr = p[0]; - if (addr == 0) - break; - addr += fp; - size = p[1]; - p += 2; - __bound_new_region((void *)addr, size); - } - dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__); -} - -/* called when leaving a function to delete all the local regions */ -void FASTCALL __bound_local_delete(void *p1) -{ - size_t addr, fp, *p = p1; - GET_CALLER_FP(fp); - for(;;) { - addr = p[0]; - if (addr == 0) - break; - addr += fp; - p += 2; - __bound_delete_region((void *)addr); - } -} - -#if defined(__GNUC__) && (__GNUC__ >= 6) -#pragma GCC diagnostic pop -#endif - -static BoundEntry *__bound_new_page(void) -{ - BoundEntry *page; - size_t i; - - page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE); - if (!page) - bound_alloc_error(); - for(i=0;i> BOUND_T3_BITS; - if (end != 0) - t2_end = end >> BOUND_T3_BITS; - else - t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS); - -#if 0 - dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end); -#endif - - /* first we handle full pages */ - t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS; - t1_end = t2_end >> BOUND_T2_BITS; - - i = t2_start & (BOUND_T2_SIZE - 1); - j = t2_end & (BOUND_T2_SIZE - 1); - - if (t1_start == t1_end) { - page = get_page(t2_start >> BOUND_T2_BITS); - for(; i < j; i++) { - page[i].size = INVALID_SIZE; - page[i].is_invalid = 1; - } - } else { - if (i > 0) { - page = get_page(t2_start >> BOUND_T2_BITS); - for(; i < BOUND_T2_SIZE; i++) { - page[i].size = INVALID_SIZE; - page[i].is_invalid = 1; - } - } - for(i = t1_start; i < t1_end; i++) { - __bound_t1[i] = __bound_invalid_t2; - } - if (j != 0) { - page = get_page(t1_end); - for(i = 0; i < j; i++) { - page[i].size = INVALID_SIZE; - page[i].is_invalid = 1; - } - } - } -} - -void __bound_init(void) -{ - size_t i; - BoundEntry *page; - size_t start, size; - size_t *p; - - static int inited; - if (inited) - return; - - inited = 1; - - dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__); - - /* save malloc hooks and install bound check hooks */ - install_malloc_hooks(); - -#ifndef BOUND_STATIC - __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *)); - if (!__bound_t1) - bound_alloc_error(); -#endif - __bound_empty_t2 = __bound_new_page(); - for(i=0;i= v3.3, the alternative is to read - * start_brk from /proc/self/stat - */ - start = (size_t)sbrk(0); - size = 128 * 0x100000; - mark_invalid(start, size); -#endif - - /* add all static bound check values */ - p = (size_t *)&__bounds_start; - while (p[0] != 0) { - __bound_new_region((void *)p[0], p[1]); - p += 2; - } - - dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__); -} - -void __bound_main_arg(void **p) -{ - void *start = p; - while (*p++); - - dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n", - __FILE__, __FUNCTION__, start, (unsigned)((void *)p - start)); - - __bound_new_region(start, (void *) p - start); -} - -void __bound_exit(void) -{ - dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__); - restore_malloc_hooks(); -} - -static inline void add_region(BoundEntry *e, - size_t start, size_t size) -{ - BoundEntry *e1; - if (e->start == 0) { - /* no region : add it */ - e->start = start; - e->size = size; - } else { - /* already regions in the list: add it at the head */ - e1 = bound_new_entry(); - e1->start = e->start; - e1->size = e->size; - e1->next = e->next; - e->start = start; - e->size = size; - e->next = e1; - } -} - -/* create a new region. It should not already exist in the region list */ -void __bound_new_region(void *p, size_t size) -{ - size_t start, end; - BoundEntry *page, *e, *e2; - size_t t1_start, t1_end, i, t2_start, t2_end; - - dprintf(stderr, "%s, %s(%p, %x) start\n", - __FILE__, __FUNCTION__, p, (unsigned)size); - - __bound_init(); - - start = (size_t)p; - end = start + size; - t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); - t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); - - /* start */ - page = get_page(t1_start); - t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); - t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); - - - e = (BoundEntry *)((char *)page + t2_start); - add_region(e, start, size); - - if (t1_end == t1_start) { - /* same ending page */ - e2 = (BoundEntry *)((char *)page + t2_end); - if (e2 > e) { - e++; - for(;estart = start; - e->size = size; - } - add_region(e, start, size); - } - } else { - /* mark until end of page */ - e2 = page + BOUND_T2_SIZE; - e++; - for(;estart = start; - e->size = size; - } - /* mark intermediate pages, if any */ - for(i=t1_start+1;istart = start; - e->size = size; - } - } - /* last page */ - page = get_page(t1_end); - e2 = (BoundEntry *)((char *)page + t2_end); - for(e=page;estart = start; - e->size = size; - } - add_region(e, start, size); - } - - dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__); -} - -/* delete a region */ -static inline void delete_region(BoundEntry *e, void *p, size_t empty_size) -{ - size_t addr; - BoundEntry *e1; - - addr = (size_t)p; - addr -= e->start; - if (addr <= e->size) { - /* region found is first one */ - e1 = e->next; - if (e1 == NULL) { - /* no more region: mark it empty */ - e->start = 0; - e->size = empty_size; - } else { - /* copy next region in head */ - e->start = e1->start; - e->size = e1->size; - e->next = e1->next; - bound_free_entry(e1); - } - } else { - /* find the matching region */ - for(;;) { - e1 = e; - e = e->next; - /* region not found: do nothing */ - if (e == NULL) - break; - addr = (size_t)p - e->start; - if (addr <= e->size) { - /* found: remove entry */ - e1->next = e->next; - bound_free_entry(e); - break; - } - } - } -} - -/* WARNING: 'p' must be the starting point of the region. */ -/* return non zero if error */ -int __bound_delete_region(void *p) -{ - size_t start, end, addr, size, empty_size; - BoundEntry *page, *e, *e2; - size_t t1_start, t1_end, t2_start, t2_end, i; - - dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__); - - __bound_init(); - - start = (size_t)p; - t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); - t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); - - /* find region size */ - page = __bound_t1[t1_start]; - e = (BoundEntry *)((char *)page + t2_start); - addr = start - e->start; - if (addr > e->size) - e = __bound_find_region(e, p); - /* test if invalid region */ - if (e->size == EMPTY_SIZE || (size_t)p != e->start) - return -1; - /* compute the size we put in invalid regions */ - if (e->is_invalid) - empty_size = INVALID_SIZE; - else - empty_size = EMPTY_SIZE; - size = e->size; - end = start + size; - - /* now we can free each entry */ - t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); - t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS); - - delete_region(e, p, empty_size); - if (t1_end == t1_start) { - /* same ending page */ - e2 = (BoundEntry *)((char *)page + t2_end); - if (e2 > e) { - e++; - for(;estart = 0; - e->size = empty_size; - } - delete_region(e, p, empty_size); - } - } else { - /* mark until end of page */ - e2 = page + BOUND_T2_SIZE; - e++; - for(;estart = 0; - e->size = empty_size; - } - /* mark intermediate pages, if any */ - /* XXX: should free them */ - for(i=t1_start+1;istart = 0; - e->size = empty_size; - } - } - /* last page */ - page = get_page(t1_end); - e2 = (BoundEntry *)((char *)page + t2_end); - for(e=page;estart = 0; - e->size = empty_size; - } - delete_region(e, p, empty_size); - } - - dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__); - - return 0; -} - -/* return the size of the region starting at p, or EMPTY_SIZE if non - existent region. */ -static size_t get_region_size(void *p) -{ - size_t addr = (size_t)p; - BoundEntry *e; - - e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; - e = (BoundEntry *)((char *)e + - ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & - ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); - addr -= e->start; - if (addr > e->size) - e = __bound_find_region(e, p); - if (e->start != (size_t)p) - return EMPTY_SIZE; - return e->size; -} - -/* patched memory functions */ - -/* force compiler to perform stores coded up to this point */ -#define barrier() __asm__ __volatile__ ("": : : "memory") - -static void install_malloc_hooks(void) -{ -#ifdef CONFIG_TCC_MALLOC_HOOKS - saved_malloc_hook = __malloc_hook; - saved_free_hook = __free_hook; - saved_realloc_hook = __realloc_hook; - saved_memalign_hook = __memalign_hook; - __malloc_hook = __bound_malloc; - __free_hook = __bound_free; - __realloc_hook = __bound_realloc; - __memalign_hook = __bound_memalign; - - barrier(); -#endif -} - -static void restore_malloc_hooks(void) -{ -#ifdef CONFIG_TCC_MALLOC_HOOKS - __malloc_hook = saved_malloc_hook; - __free_hook = saved_free_hook; - __realloc_hook = saved_realloc_hook; - __memalign_hook = saved_memalign_hook; - - barrier(); -#endif -} - -static void *libc_malloc(size_t size) -{ - void *ptr; - restore_malloc_hooks(); - ptr = malloc(size); - install_malloc_hooks(); - return ptr; -} - -static void libc_free(void *ptr) -{ - restore_malloc_hooks(); - free(ptr); - install_malloc_hooks(); -} - -/* XXX: we should use a malloc which ensure that it is unlikely that - two malloc'ed data have the same address if 'free' are made in - between. */ -void *__bound_malloc(size_t size, const void *caller) -{ - void *ptr; - - /* we allocate one more byte to ensure the regions will be - separated by at least one byte. With the glibc malloc, it may - be in fact not necessary */ - ptr = libc_malloc(size + 1); - - if (!ptr) - return NULL; - - dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n", - __FILE__, __FUNCTION__, ptr, (unsigned)size); - - __bound_new_region(ptr, size); - return ptr; -} - -void *__bound_memalign(size_t size, size_t align, const void *caller) -{ - void *ptr; - - restore_malloc_hooks(); - -#ifndef HAVE_MEMALIGN - if (align > 4) { - /* XXX: handle it ? */ - ptr = NULL; - } else { - /* we suppose that malloc aligns to at least four bytes */ - ptr = malloc(size + 1); - } -#else - /* we allocate one more byte to ensure the regions will be - separated by at least one byte. With the glibc malloc, it may - be in fact not necessary */ - ptr = memalign(size + 1, align); -#endif - - install_malloc_hooks(); - - if (!ptr) - return NULL; - - dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n", - __FILE__, __FUNCTION__, ptr, (unsigned)size); - - __bound_new_region(ptr, size); - return ptr; -} - -void __bound_free(void *ptr, const void *caller) -{ - if (ptr == NULL) - return; - if (__bound_delete_region(ptr) != 0) - bound_error("freeing invalid region"); - - libc_free(ptr); -} - -void *__bound_realloc(void *ptr, size_t size, const void *caller) -{ - void *ptr1; - size_t old_size; - - if (size == 0) { - __bound_free(ptr, caller); - return NULL; - } else { - ptr1 = __bound_malloc(size, caller); - if (ptr == NULL || ptr1 == NULL) - return ptr1; - old_size = get_region_size(ptr); - if (old_size == EMPTY_SIZE) - bound_error("realloc'ing invalid pointer"); - memcpy(ptr1, ptr, old_size); - __bound_free(ptr, caller); - return ptr1; - } -} - -#ifndef CONFIG_TCC_MALLOC_HOOKS -void *__bound_calloc(size_t nmemb, size_t size) -{ - void *ptr; - size = size * nmemb; - ptr = __bound_malloc(size, NULL); - if (!ptr) - return NULL; - memset(ptr, 0, size); - return ptr; -} -#endif - -#if 0 -static void bound_dump(void) -{ - BoundEntry *page, *e; - size_t i, j; - - fprintf(stderr, "region dump:\n"); - for(i=0;isize != EMPTY_SIZE && e->start != 0) { - fprintf(stderr, "%08x:", - (i << (BOUND_T2_BITS + BOUND_T3_BITS)) + - (j << BOUND_T3_BITS)); - do { - fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size); - e = e->next; - } while (e != NULL); - fprintf(stderr, "\n"); - } - } - } -} -#endif - -/* some useful checked functions */ - -/* check that (p ... p + size - 1) lies inside 'p' region, if any */ -static void __bound_check(const void *p, size_t size) -{ - if (size == 0) - return; - p = __bound_ptr_add((void *)p, size - 1); - if (p == INVALID_POINTER) - bound_error("invalid pointer"); -} - -void *__bound_memcpy(void *dst, const void *src, size_t size) -{ - void* p; - - dprintf(stderr, "%s %s: start, dst=%p src=%p size=%x\n", - __FILE__, __FUNCTION__, dst, src, (unsigned)size); - - __bound_check(dst, size); - __bound_check(src, size); - /* check also region overlap */ - if (src >= dst && src < dst + size) - bound_error("overlapping regions in memcpy()"); - - p = memcpy(dst, src, size); - - dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p); - return p; -} - -void *__bound_memmove(void *dst, const void *src, size_t size) -{ - __bound_check(dst, size); - __bound_check(src, size); - return memmove(dst, src, size); -} - -void *__bound_memset(void *dst, int c, size_t size) -{ - __bound_check(dst, size); - return memset(dst, c, size); -} - -/* XXX: could be optimized */ -int __bound_strlen(const char *s) -{ - const char *p; - size_t len; - - len = 0; - for(;;) { - p = __bound_ptr_indir1((char *)s, len); - if (p == INVALID_POINTER) - bound_error("bad pointer in strlen()"); - if (*p == '\0') - break; - len++; - } - return len; -} - -char *__bound_strcpy(char *dst, const char *src) -{ - size_t len; - void *p; - - dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n", - __FILE__, __FUNCTION__, dst, src); - len = __bound_strlen(src); - p = __bound_memcpy(dst, src, len + 1); - dprintf(stderr, "%s %s: strcpy end, p = %p\n", - __FILE__, __FUNCTION__, p); - return p; -} diff --git a/tinyc/lib/lib-arm64.c b/tinyc/lib/lib-arm64.c deleted file mode 100644 index b8fd9e85a..000000000 --- a/tinyc/lib/lib-arm64.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * TCC runtime library for arm64. - * - * Copyright (c) 2015 Edmund Grimley Evans - * - * Copying and distribution of this file, with or without modification, - * are permitted in any medium without royalty provided the copyright - * notice and this notice are preserved. This file is offered as-is, - * without any warranty. - */ - -#ifdef __TINYC__ -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned uint32_t; -typedef long long int64_t; -typedef unsigned long long uint64_t; -void *memcpy(void*,void*,__SIZE_TYPE__); -#else -#include -#include -#endif - -void __clear_cache(void *beg, void *end) -{ - __arm64_clear_cache(beg, end); -} - -typedef struct { - uint64_t x0, x1; -} u128_t; - -static long double f3_zero(int sgn) -{ - long double f; - u128_t x = { 0, (uint64_t)sgn << 63 }; - memcpy(&f, &x, 16); - return f; -} - -static long double f3_infinity(int sgn) -{ - long double f; - u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; - memcpy(&f, &x, 16); - return f; -} - -static long double f3_NaN(void) -{ - long double f; -#if 0 - // ARM's default NaN usually has just the top fraction bit set: - u128_t x = { 0, 0x7fff800000000000 }; -#else - // GCC's library sets all fraction bits: - u128_t x = { -1, 0x7fffffffffffffff }; -#endif - memcpy(&f, &x, 16); - return f; -} - -static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt) -{ - u128_t x = { mnt.x0, - mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; - memcpy(f, &x, 16); - return 1; -} - -static int fp3_detect_NaNs(long double *f, - int a_sgn, int a_exp, u128_t a, - int b_sgn, int b_exp, u128_t b) -{ - // Detect signalling NaNs: - if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) - return fp3_convert_NaN(f, a_sgn, a); - if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) - return fp3_convert_NaN(f, b_sgn, b); - - // Detect quiet NaNs: - if (a_exp == 32767 && (a.x0 | a.x1 << 16)) - return fp3_convert_NaN(f, a_sgn, a); - if (b_exp == 32767 && (b.x0 | b.x1 << 16)) - return fp3_convert_NaN(f, b_sgn, b); - - return 0; -} - -static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) -{ - u128_t x; - memcpy(&x, &f, 16); - *sgn = x.x1 >> 63; - *exp = x.x1 >> 48 & 32767; - x.x1 = x.x1 << 16 >> 16; - if (*exp) - x.x1 |= (uint64_t)1 << 48; - else - *exp = 1; - *mnt = x; -} - -static u128_t f3_normalise(int32_t *exp, u128_t mnt) -{ - int sh; - if (!(mnt.x0 | mnt.x1)) - return mnt; - if (!mnt.x1) { - mnt.x1 = mnt.x0; - mnt.x0 = 0; - *exp -= 64; - } - for (sh = 32; sh; sh >>= 1) { - if (!(mnt.x1 >> (64 - sh))) { - mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh); - mnt.x0 = mnt.x0 << sh; - *exp -= sh; - } - } - return mnt; -} - -static u128_t f3_sticky_shift(int32_t sh, u128_t x) -{ - if (sh >= 128) { - x.x0 = !!(x.x0 | x.x1); - x.x1 = 0; - return x; - } - if (sh >= 64) { - x.x0 = x.x1 | !!x.x0; - x.x1 = 0; - sh -= 64; - } - if (sh > 0) { - x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh)); - x.x1 = x.x1 >> sh; - } - return x; -} - -static long double f3_round(int sgn, int32_t exp, u128_t x) -{ - long double f; - int error; - - if (exp > 0) { - x = f3_sticky_shift(13, x); - } - else { - x = f3_sticky_shift(14 - exp, x); - exp = 0; - } - - error = x.x0 & 3; - x.x0 = x.x0 >> 2 | x.x1 << 62; - x.x1 = x.x1 >> 2; - - if (error == 3 || ((error == 2) & (x.x0 & 1))) { - if (!++x.x0) { - ++x.x1; - if (x.x1 == (uint64_t)1 << 48) - exp = 1; - else if (x.x1 == (uint64_t)1 << 49) { - ++exp; - x.x0 = x.x0 >> 1 | x.x1 << 63; - x.x1 = x.x1 >> 1; - } - } - } - - if (exp >= 32767) - return f3_infinity(sgn); - - x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; - memcpy(&f, &x, 16); - return f; -} - -static long double f3_add(long double fa, long double fb, int neg) -{ - u128_t a, b, x; - int32_t a_exp, b_exp, x_exp; - int a_sgn, b_sgn, x_sgn; - long double fx; - - f3_unpack(&a_sgn, &a_exp, &a, fa); - f3_unpack(&b_sgn, &b_exp, &b, fb); - - if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) - return fx; - - b_sgn ^= neg; - - // Handle infinities and zeroes: - if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn) - return f3_NaN(); - if (a_exp == 32767) - return f3_infinity(a_sgn); - if (b_exp == 32767) - return f3_infinity(b_sgn); - if (!(a.x0 | a.x1 | b.x0 | b.x1)) - return f3_zero(a_sgn & b_sgn); - - a.x1 = a.x1 << 3 | a.x0 >> 61; - a.x0 = a.x0 << 3; - b.x1 = b.x1 << 3 | b.x0 >> 61; - b.x0 = b.x0 << 3; - - if (a_exp <= b_exp) { - a = f3_sticky_shift(b_exp - a_exp, a); - a_exp = b_exp; - } - else { - b = f3_sticky_shift(a_exp - b_exp, b); - b_exp = a_exp; - } - - x_sgn = a_sgn; - x_exp = a_exp; - if (a_sgn == b_sgn) { - x.x0 = a.x0 + b.x0; - x.x1 = a.x1 + b.x1 + (x.x0 < a.x0); - } - else { - x.x0 = a.x0 - b.x0; - x.x1 = a.x1 - b.x1 - (x.x0 > a.x0); - if (x.x1 >> 63) { - x_sgn ^= 1; - x.x0 = -x.x0; - x.x1 = -x.x1 - !!x.x0; - } - } - - if (!(x.x0 | x.x1)) - return f3_zero(0); - - x = f3_normalise(&x_exp, x); - - return f3_round(x_sgn, x_exp + 12, x); -} - -long double __addtf3(long double a, long double b) -{ - return f3_add(a, b, 0); -} - -long double __subtf3(long double a, long double b) -{ - return f3_add(a, b, 1); -} - -long double __multf3(long double fa, long double fb) -{ - u128_t a, b, x; - int32_t a_exp, b_exp, x_exp; - int a_sgn, b_sgn, x_sgn; - long double fx; - - f3_unpack(&a_sgn, &a_exp, &a, fa); - f3_unpack(&b_sgn, &b_exp, &b, fb); - - if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) - return fx; - - // Handle infinities and zeroes: - if ((a_exp == 32767 && !(b.x0 | b.x1)) || - (b_exp == 32767 && !(a.x0 | a.x1))) - return f3_NaN(); - if (a_exp == 32767 || b_exp == 32767) - return f3_infinity(a_sgn ^ b_sgn); - if (!(a.x0 | a.x1) || !(b.x0 | b.x1)) - return f3_zero(a_sgn ^ b_sgn); - - a = f3_normalise(&a_exp, a); - b = f3_normalise(&b_exp, b); - - x_sgn = a_sgn ^ b_sgn; - x_exp = a_exp + b_exp - 16352; - - { - // Convert to base (1 << 30), discarding bottom 6 bits, which are zero, - // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0): - uint64_t a0 = a.x0 << 28 >> 34; - uint64_t b0 = b.x0 << 28 >> 34; - uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34; - uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34; - uint64_t a2 = a.x1 << 32 >> 34; - uint64_t b2 = b.x1 << 32 >> 34; - uint64_t a3 = a.x1 >> 32; - uint64_t b3 = b.x1 >> 32; - // Use 16 small multiplications and additions that do not overflow: - uint64_t x0 = a0 * b0; - uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0; - uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0; - uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; - uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1; - uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2; - uint64_t x6 = (x5 >> 30) + a3 * b3; - // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...). - // Take the top 128 bits, setting bottom bit if any lower bits were set: - uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 | - !!(x3 << 38 | (x2 | x1 | x0) << 34)); - uint64_t y1 = x6; - // Top bit may be zero. Renormalise: - if (!(y1 >> 63)) { - y1 = y1 << 1 | y0 >> 63; - y0 = y0 << 1; - --x_exp; - } - x.x0 = y0; - x.x1 = y1; - } - - return f3_round(x_sgn, x_exp, x); -} - -long double __divtf3(long double fa, long double fb) -{ - u128_t a, b, x; - int32_t a_exp, b_exp, x_exp; - int a_sgn, b_sgn, x_sgn, i; - long double fx; - - f3_unpack(&a_sgn, &a_exp, &a, fa); - f3_unpack(&b_sgn, &b_exp, &b, fb); - - if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) - return fx; - - // Handle infinities and zeroes: - if ((a_exp == 32767 && b_exp == 32767) || - (!(a.x0 | a.x1) && !(b.x0 | b.x1))) - return f3_NaN(); - if (a_exp == 32767 || !(b.x0 | b.x1)) - return f3_infinity(a_sgn ^ b_sgn); - if (!(a.x0 | a.x1) || b_exp == 32767) - return f3_zero(a_sgn ^ b_sgn); - - a = f3_normalise(&a_exp, a); - b = f3_normalise(&b_exp, b); - - x_sgn = a_sgn ^ b_sgn; - x_exp = a_exp - b_exp + 16395; - - a.x0 = a.x0 >> 1 | a.x1 << 63; - a.x1 = a.x1 >> 1; - b.x0 = b.x0 >> 1 | b.x1 << 63; - b.x1 = b.x1 >> 1; - x.x0 = 0; - x.x1 = 0; - for (i = 0; i < 116; i++) { - x.x1 = x.x1 << 1 | x.x0 >> 63; - x.x0 = x.x0 << 1; - if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) { - a.x1 = a.x1 - b.x1 - (a.x0 < b.x0); - a.x0 = a.x0 - b.x0; - x.x0 |= 1; - } - a.x1 = a.x1 << 1 | a.x0 >> 63; - a.x0 = a.x0 << 1; - } - x.x0 |= !!(a.x0 | a.x1); - - x = f3_normalise(&x_exp, x); - - return f3_round(x_sgn, x_exp, x); -} - -long double __extendsftf2(float f) -{ - long double fx; - u128_t x; - uint32_t a; - uint64_t aa; - memcpy(&a, &f, 4); - aa = a; - x.x0 = 0; - if (!(a << 1)) - x.x1 = aa << 32; - else if (a << 1 >> 24 == 255) - x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 | - (uint64_t)!!(a << 9) << 47); - else - x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | - aa << 41 >> 16); - memcpy(&fx, &x, 16); - return fx; -} - -long double __extenddftf2(double f) -{ - long double fx; - u128_t x; - uint64_t a; - memcpy(&a, &f, 8); - x.x0 = a << 60; - if (!(a << 1)) - x.x1 = a; - else if (a << 1 >> 53 == 2047) - x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 | - (uint64_t)!!(a << 12) << 47); - else - x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; - memcpy(&fx, &x, 16); - return fx; -} - -float __trunctfsf2(long double f) -{ - u128_t mnt; - int32_t exp; - int sgn; - uint32_t x; - float fx; - - f3_unpack(&sgn, &exp, &mnt, f); - - if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) - x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); - else if (exp > 16510) - x = 0x7f800000 | (uint32_t)sgn << 31; - else if (exp < 16233) - x = (uint32_t)sgn << 31; - else { - exp -= 16257; - x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41); - if (exp < 0) { - x = x >> -exp | !!(x << (32 + exp)); - exp = 0; - } - if ((x & 3) == 3 || (x & 7) == 6) - x += 4; - x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; - } - memcpy(&fx, &x, 4); - return fx; -} - -double __trunctfdf2(long double f) -{ - u128_t mnt; - int32_t exp; - int sgn; - uint64_t x; - double fx; - - f3_unpack(&sgn, &exp, &mnt, f); - - if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) - x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | - mnt.x1 << 16 >> 12 | mnt.x0 >> 60); - else if (exp > 17406) - x = 0x7ff0000000000000 | (uint64_t)sgn << 63; - else if (exp < 15308) - x = (uint64_t)sgn << 63; - else { - exp -= 15361; - x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6); - if (exp < 0) { - x = x >> -exp | !!(x << (64 + exp)); - exp = 0; - } - if ((x & 3) == 3 || (x & 7) == 6) - x += 4; - x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; - } - memcpy(&fx, &x, 8); - return fx; -} - -int32_t __fixtfsi(long double fa) -{ - u128_t a; - int32_t a_exp; - int a_sgn; - int32_t x; - f3_unpack(&a_sgn, &a_exp, &a, fa); - if (a_exp < 16369) - return 0; - if (a_exp > 16413) - return a_sgn ? -0x80000000 : 0x7fffffff; - x = a.x1 >> (16431 - a_exp); - return a_sgn ? -x : x; -} - -int64_t __fixtfdi(long double fa) -{ - u128_t a; - int32_t a_exp; - int a_sgn; - int64_t x; - f3_unpack(&a_sgn, &a_exp, &a, fa); - if (a_exp < 16383) - return 0; - if (a_exp > 16445) - return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff; - x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); - return a_sgn ? -x : x; -} - -uint32_t __fixunstfsi(long double fa) -{ - u128_t a; - int32_t a_exp; - int a_sgn; - f3_unpack(&a_sgn, &a_exp, &a, fa); - if (a_sgn || a_exp < 16369) - return 0; - if (a_exp > 16414) - return -1; - return a.x1 >> (16431 - a_exp); -} - -uint64_t __fixunstfdi(long double fa) -{ - u128_t a; - int32_t a_exp; - int a_sgn; - f3_unpack(&a_sgn, &a_exp, &a, fa); - if (a_sgn || a_exp < 16383) - return 0; - if (a_exp > 16446) - return -1; - return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); -} - -long double __floatsitf(int32_t a) -{ - int sgn = 0; - int exp = 16414; - uint32_t mnt = a; - u128_t x = { 0, 0 }; - long double f; - int i; - if (a) { - if (a < 0) { - sgn = 1; - mnt = -mnt; - } - for (i = 16; i; i >>= 1) - if (!(mnt >> (32 - i))) { - mnt <<= i; - exp -= i; - } - x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | - (uint64_t)(mnt << 1) << 16); - } - memcpy(&f, &x, 16); - return f; -} - -long double __floatditf(int64_t a) -{ - int sgn = 0; - int exp = 16446; - uint64_t mnt = a; - u128_t x = { 0, 0 }; - long double f; - int i; - if (a) { - if (a < 0) { - sgn = 1; - mnt = -mnt; - } - for (i = 32; i; i >>= 1) - if (!(mnt >> (64 - i))) { - mnt <<= i; - exp -= i; - } - x.x0 = mnt << 49; - x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; - } - memcpy(&f, &x, 16); - return f; -} - -long double __floatunsitf(uint32_t a) -{ - int exp = 16414; - uint32_t mnt = a; - u128_t x = { 0, 0 }; - long double f; - int i; - if (a) { - for (i = 16; i; i >>= 1) - if (!(mnt >> (32 - i))) { - mnt <<= i; - exp -= i; - } - x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; - } - memcpy(&f, &x, 16); - return f; -} - -long double __floatunditf(uint64_t a) -{ - int exp = 16446; - uint64_t mnt = a; - u128_t x = { 0, 0 }; - long double f; - int i; - if (a) { - for (i = 32; i; i >>= 1) - if (!(mnt >> (64 - i))) { - mnt <<= i; - exp -= i; - } - x.x0 = mnt << 49; - x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; - } - memcpy(&f, &x, 16); - return f; -} - -static int f3_cmp(long double fa, long double fb) -{ - u128_t a, b; - memcpy(&a, &fa, 16); - memcpy(&b, &fb, 16); - return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : - ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || - (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 : - a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) : - a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 : - a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) : - a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 : - b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0); -} - -int __eqtf2(long double a, long double b) -{ - return !!f3_cmp(a, b); -} - -int __netf2(long double a, long double b) -{ - return !!f3_cmp(a, b); -} - -int __lttf2(long double a, long double b) -{ - return f3_cmp(a, b); -} - -int __letf2(long double a, long double b) -{ - return f3_cmp(a, b); -} - -int __gttf2(long double a, long double b) -{ - return -f3_cmp(b, a); -} - -int __getf2(long double a, long double b) -{ - return -f3_cmp(b, a); -} diff --git a/tinyc/lib/libtcc1.c b/tinyc/lib/libtcc1.c deleted file mode 100644 index 0e466180c..000000000 --- a/tinyc/lib/libtcc1.c +++ /dev/null @@ -1,622 +0,0 @@ -/* TCC runtime library. - Parts of this code are (c) 2002 Fabrice Bellard - - Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc. - -This file is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file into combinations with other programs, -and to distribute those combinations without any restriction coming -from the use of this file. (The General Public License restrictions -do apply in other respects; for example, they cover modification of -the file, and distribution when not linked into a combine -executable.) - -This file is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. -*/ - -#define W_TYPE_SIZE 32 -#define BITS_PER_UNIT 8 - -typedef int Wtype; -typedef unsigned int UWtype; -typedef unsigned int USItype; -typedef long long DWtype; -typedef unsigned long long UDWtype; - -struct DWstruct { - Wtype low, high; -}; - -typedef union -{ - struct DWstruct s; - DWtype ll; -} DWunion; - -typedef long double XFtype; -#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) -#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) - -/* the following deal with IEEE single-precision numbers */ -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define HIDDEN (1 << 23) -#define SIGN(fp) ((fp) & SIGNBIT) -#define EXP(fp) (((fp) >> 23) & 0xFF) -#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) -#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) - -/* the following deal with IEEE double-precision numbers */ -#define EXCESSD 1022 -#define HIDDEND (1 << 20) -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ - (fp.l.lower >> 22)) -#define HIDDEND_LL ((long long)1 << 52) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) - -/* the following deal with x86 long double-precision numbers */ -#define EXCESSLD 16382 -#define EXPLD(fp) (fp.l.upper & 0x7fff) -#define SIGNLD(fp) ((fp.l.upper) & 0x8000) - -/* only for x86 */ -union ldouble_long { - long double ld; - struct { - unsigned long long lower; - unsigned short upper; - } l; -}; - -union double_long { - double d; -#if 1 - struct { - unsigned int lower; - int upper; - } l; -#else - struct { - int upper; - unsigned int lower; - } l; -#endif - long long ll; -}; - -union float_long { - float f; - unsigned int l; -}; - -/* XXX: we don't support several builtin supports for now */ -#if !defined __x86_64__ && !defined __arm__ - -/* XXX: use gcc/tcc intrinsic ? */ -#if defined __i386__ -#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "0" ((USItype) (ah)), \ - "g" ((USItype) (bh)), \ - "1" ((USItype) (al)), \ - "g" ((USItype) (bl))) -#define umul_ppmm(w1, w0, u, v) \ - __asm__ ("mull %3" \ - : "=a" ((USItype) (w0)), \ - "=d" ((USItype) (w1)) \ - : "%0" ((USItype) (u)), \ - "rm" ((USItype) (v))) -#define udiv_qrnnd(q, r, n1, n0, dv) \ - __asm__ ("divl %4" \ - : "=a" ((USItype) (q)), \ - "=d" ((USItype) (r)) \ - : "0" ((USItype) (n0)), \ - "1" ((USItype) (n1)), \ - "rm" ((USItype) (dv))) -#define count_leading_zeros(count, x) \ - do { \ - USItype __cbtmp; \ - __asm__ ("bsrl %1,%0" \ - : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ - (count) = __cbtmp ^ 31; \ - } while (0) -#else -#error unsupported CPU type -#endif - -/* most of this code is taken from libgcc2.c from gcc */ - -static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) -{ - DWunion ww; - DWunion nn, dd; - DWunion rr; - UWtype d0, d1, n0, n1, n2; - UWtype q0, q1; - UWtype b, bm; - - nn.ll = n; - dd.ll = d; - - d0 = dd.s.low; - d1 = dd.s.high; - n0 = nn.s.low; - n1 = nn.s.high; - -#if !defined(UDIV_NEEDS_NORMALIZATION) - if (d1 == 0) - { - if (d0 > n1) - { - /* 0q = nn / 0D */ - - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - - /* Remainder in n0. */ - } - else - { - /* qq = NN / 0d */ - - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - - udiv_qrnnd (q1, n1, 0, n1, d0); - udiv_qrnnd (q0, n0, n1, n0, d0); - - /* Remainder in n0. */ - } - - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = 0; - *rp = rr.ll; - } - } - -#else /* UDIV_NEEDS_NORMALIZATION */ - - if (d1 == 0) - { - if (d0 > n1) - { - /* 0q = nn / 0D */ - - count_leading_zeros (bm, d0); - - if (bm != 0) - { - /* Normalize, i.e. make the most significant bit of the - denominator set. */ - - d0 = d0 << bm; - n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); - n0 = n0 << bm; - } - - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - - /* Remainder in n0 >> bm. */ - } - else - { - /* qq = NN / 0d */ - - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - - count_leading_zeros (bm, d0); - - if (bm == 0) - { - /* From (n1 >= d0) /\ (the most significant bit of d0 is set), - conclude (the most significant bit of n1 is set) /\ (the - leading quotient digit q1 = 1). - - This special case is necessary, not an optimization. - (Shifts counts of W_TYPE_SIZE are undefined.) */ - - n1 -= d0; - q1 = 1; - } - else - { - /* Normalize. */ - - b = W_TYPE_SIZE - bm; - - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q1, n1, n2, n1, d0); - } - - /* n1 != d0... */ - - udiv_qrnnd (q0, n0, n1, n0, d0); - - /* Remainder in n0 >> bm. */ - } - - if (rp != 0) - { - rr.s.low = n0 >> bm; - rr.s.high = 0; - *rp = rr.ll; - } - } -#endif /* UDIV_NEEDS_NORMALIZATION */ - - else - { - if (d1 > n1) - { - /* 00 = nn / DD */ - - q0 = 0; - q1 = 0; - - /* Remainder in n1n0. */ - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - /* 0q = NN / dd */ - - count_leading_zeros (bm, d1); - if (bm == 0) - { - /* From (n1 >= d1) /\ (the most significant bit of d1 is set), - conclude (the most significant bit of n1 is set) /\ (the - quotient digit q0 = 0 or 1). - - This special case is necessary, not an optimization. */ - - /* The condition on the next line takes advantage of that - n1 >= d1 (true due to program flow). */ - if (n1 > d1 || n0 >= d0) - { - q0 = 1; - sub_ddmmss (n1, n0, n1, n0, d1, d0); - } - else - q0 = 0; - - q1 = 0; - - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - UWtype m1, m0; - /* Normalize. */ - - b = W_TYPE_SIZE - bm; - - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q0, n1, n2, n1, d1); - umul_ppmm (m1, m0, q0, d0); - - if (m1 > n1 || (m1 == n1 && m0 > n0)) - { - q0--; - sub_ddmmss (m1, m0, m1, m0, d1, d0); - } - - q1 = 0; - - /* Remainder in (n1n0 - m1m0) >> bm. */ - if (rp != 0) - { - sub_ddmmss (n1, n0, n1, n0, m1, m0); - rr.s.low = (n1 << b) | (n0 >> bm); - rr.s.high = n1 >> bm; - *rp = rr.ll; - } - } - } - } - - ww.s.low = q0; - ww.s.high = q1; - return ww.ll; -} - -#define __negdi2(a) (-(a)) - -long long __divdi3(long long u, long long v) -{ - int c = 0; - DWunion uu, vv; - DWtype w; - - uu.ll = u; - vv.ll = v; - - if (uu.s.high < 0) { - c = ~c; - uu.ll = __negdi2 (uu.ll); - } - if (vv.s.high < 0) { - c = ~c; - vv.ll = __negdi2 (vv.ll); - } - w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); - if (c) - w = __negdi2 (w); - return w; -} - -long long __moddi3(long long u, long long v) -{ - int c = 0; - DWunion uu, vv; - DWtype w; - - uu.ll = u; - vv.ll = v; - - if (uu.s.high < 0) { - c = ~c; - uu.ll = __negdi2 (uu.ll); - } - if (vv.s.high < 0) - vv.ll = __negdi2 (vv.ll); - - __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w); - if (c) - w = __negdi2 (w); - return w; -} - -unsigned long long __udivdi3(unsigned long long u, unsigned long long v) -{ - return __udivmoddi4 (u, v, (UDWtype *) 0); -} - -unsigned long long __umoddi3(unsigned long long u, unsigned long long v) -{ - UDWtype w; - - __udivmoddi4 (u, v, &w); - return w; -} - -/* XXX: fix tcc's code generator to do this instead */ -long long __ashrdi3(long long a, int b) -{ -#ifdef __TINYC__ - DWunion u; - u.ll = a; - if (b >= 32) { - u.s.low = u.s.high >> (b - 32); - u.s.high = u.s.high >> 31; - } else if (b != 0) { - u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); - u.s.high = u.s.high >> b; - } - return u.ll; -#else - return a >> b; -#endif -} - -/* XXX: fix tcc's code generator to do this instead */ -unsigned long long __lshrdi3(unsigned long long a, int b) -{ -#ifdef __TINYC__ - DWunion u; - u.ll = a; - if (b >= 32) { - u.s.low = (unsigned)u.s.high >> (b - 32); - u.s.high = 0; - } else if (b != 0) { - u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); - u.s.high = (unsigned)u.s.high >> b; - } - return u.ll; -#else - return a >> b; -#endif -} - -/* XXX: fix tcc's code generator to do this instead */ -long long __ashldi3(long long a, int b) -{ -#ifdef __TINYC__ - DWunion u; - u.ll = a; - if (b >= 32) { - u.s.high = (unsigned)u.s.low << (b - 32); - u.s.low = 0; - } else if (b != 0) { - u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b)); - u.s.low = (unsigned)u.s.low << b; - } - return u.ll; -#else - return a << b; -#endif -} - -#endif /* !__x86_64__ */ - -/* XXX: fix tcc's code generator to do this instead */ -float __floatundisf(unsigned long long a) -{ - DWunion uu; - XFtype r; - - uu.ll = a; - if (uu.s.high >= 0) { - return (float)uu.ll; - } else { - r = (XFtype)uu.ll; - r += 18446744073709551616.0; - return (float)r; - } -} - -double __floatundidf(unsigned long long a) -{ - DWunion uu; - XFtype r; - - uu.ll = a; - if (uu.s.high >= 0) { - return (double)uu.ll; - } else { - r = (XFtype)uu.ll; - r += 18446744073709551616.0; - return (double)r; - } -} - -long double __floatundixf(unsigned long long a) -{ - DWunion uu; - XFtype r; - - uu.ll = a; - if (uu.s.high >= 0) { - return (long double)uu.ll; - } else { - r = (XFtype)uu.ll; - r += 18446744073709551616.0; - return (long double)r; - } -} - -unsigned long long __fixunssfdi (float a1) -{ - register union float_long fl1; - register int exp; - register unsigned long l; - - fl1.f = a1; - - if (fl1.l == 0) - return (0); - - exp = EXP (fl1.l) - EXCESS - 24; - - l = MANT(fl1.l); - if (exp >= 41) - return (unsigned long long)-1; - else if (exp >= 0) - return (unsigned long long)l << exp; - else if (exp >= -23) - return l >> -exp; - else - return 0; -} - -long long __fixsfdi (float a1) -{ - long long ret; int s; - ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1); - return s ? ret : -ret; -} - -unsigned long long __fixunsdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register unsigned long long l; - - dl1.d = a1; - - if (dl1.ll == 0) - return (0); - - exp = EXPD (dl1) - EXCESSD - 53; - - l = MANTD_LL(dl1); - - if (exp >= 12) - return (unsigned long long)-1; - else if (exp >= 0) - return l << exp; - else if (exp >= -52) - return l >> -exp; - else - return 0; -} - -long long __fixdfdi (double a1) -{ - long long ret; int s; - ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1); - return s ? ret : -ret; -} - -#ifndef __arm__ -unsigned long long __fixunsxfdi (long double a1) -{ - register union ldouble_long dl1; - register int exp; - register unsigned long long l; - - dl1.ld = a1; - - if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); - - exp = EXPLD (dl1) - EXCESSLD - 64; - - l = dl1.l.lower; - - if (exp > 0) - return (unsigned long long)-1; - else if (exp >= -63) - return l >> -exp; - else - return 0; -} - -long long __fixxfdi (long double a1) -{ - long long ret; int s; - ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1); - return s ? ret : -ret; -} -#endif /* !ARM */ diff --git a/tinyc/lib/va_list.c b/tinyc/lib/va_list.c deleted file mode 100644 index 8749f46f8..000000000 --- a/tinyc/lib/va_list.c +++ /dev/null @@ -1,65 +0,0 @@ -/* va_list.c - tinycc support for va_list on X86_64 */ - -#if defined __x86_64__ - -/* Avoid include files, they may not be available when cross compiling */ -extern void *memset(void *s, int c, __SIZE_TYPE__ n); -extern void abort(void); - -/* This should be in sync with our include/stdarg.h */ -enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack -}; - -/* GCC compatible definition of va_list. */ -typedef struct { - unsigned int gp_offset; - unsigned int fp_offset; - union { - unsigned int overflow_offset; - char *overflow_arg_area; - }; - char *reg_save_area; -} __va_list_struct; - -void __va_start(__va_list_struct *ap, void *fp) -{ - memset(ap, 0, sizeof(__va_list_struct)); - *ap = *(__va_list_struct *)((char *)fp - 16); - ap->overflow_arg_area = (char *)fp + ap->overflow_offset; - ap->reg_save_area = (char *)fp - 176 - 16; -} - -void *__va_arg(__va_list_struct *ap, - enum __va_arg_type arg_type, - int size, int align) -{ - size = (size + 7) & ~7; - align = (align + 7) & ~7; - switch (arg_type) { - case __va_gen_reg: - if (ap->gp_offset + size <= 48) { - ap->gp_offset += size; - return ap->reg_save_area + ap->gp_offset - size; - } - goto use_overflow_area; - - case __va_float_reg: - if (ap->fp_offset < 128 + 48) { - ap->fp_offset += 16; - return ap->reg_save_area + ap->fp_offset - 16; - } - size = 8; - goto use_overflow_area; - - case __va_stack: - use_overflow_area: - ap->overflow_arg_area += size; - ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align); - return ap->overflow_arg_area - size; - - default: /* should never happen */ - abort(); - } -} -#endif diff --git a/tinyc/libtcc.c b/tinyc/libtcc.c deleted file mode 100644 index 092c0ba32..000000000 --- a/tinyc/libtcc.c +++ /dev/null @@ -1,1982 +0,0 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -/********************************************************/ -/* global variables */ - -/* use GNU C extensions */ -ST_DATA int gnu_ext = 1; - -/* use TinyCC extensions */ -ST_DATA int tcc_ext = 1; - -/* XXX: get rid of this ASAP */ -ST_DATA struct TCCState *tcc_state; - -static int nb_states; - -/********************************************************/ - -#if ONE_SOURCE -#include "tccpp.c" -#include "tccgen.c" -#include "tccelf.c" -#include "tccrun.c" -#ifdef TCC_TARGET_I386 -#include "i386-gen.c" -#include "i386-link.c" -#include "i386-asm.c" -#endif -#ifdef TCC_TARGET_ARM -#include "arm-gen.c" -#include "arm-link.c" -#include "arm-asm.c" -#endif -#ifdef TCC_TARGET_ARM64 -#include "arm64-gen.c" -#include "arm64-link.c" -#endif -#ifdef TCC_TARGET_C67 -#include "c67-gen.c" -#include "c67-link.c" -#include "tcccoff.c" -#endif -#ifdef TCC_TARGET_X86_64 -#include "x86_64-gen.c" -#include "x86_64-link.c" -#include "i386-asm.c" -#endif -#ifdef CONFIG_TCC_ASM -#include "tccasm.c" -#endif -#ifdef TCC_TARGET_PE -#include "tccpe.c" -#endif -#endif /* ONE_SOURCE */ - -/********************************************************/ -#ifndef CONFIG_TCC_ASM -ST_FUNC void asm_instr(void) -{ - tcc_error("inline asm() not supported"); -} -ST_FUNC void asm_global_instr(void) -{ - tcc_error("inline asm() not supported"); -} -#endif - -/********************************************************/ -#ifdef _WIN32 -ST_FUNC char *normalize_slashes(char *path) -{ - char *p; - for (p = path; *p; ++p) - if (*p == '\\') - *p = '/'; - return path; -} - -static HMODULE tcc_module; - -/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */ -static void tcc_set_lib_path_w32(TCCState *s) -{ - char path[1024], *p; - GetModuleFileNameA(tcc_module, path, sizeof path); - p = tcc_basename(normalize_slashes(strlwr(path))); - if (p > path) - --p; - *p = 0; - tcc_set_lib_path(s, path); -} - -#ifdef TCC_TARGET_PE -static void tcc_add_systemdir(TCCState *s) -{ - char buf[1000]; - GetSystemDirectory(buf, sizeof buf); - tcc_add_library_path(s, normalize_slashes(buf)); -} -#endif - -#ifdef LIBTCC_AS_DLL -BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) -{ - if (DLL_PROCESS_ATTACH == dwReason) - tcc_module = hDll; - return TRUE; -} -#endif -#endif - -/********************************************************/ -/* copy a string and truncate it. */ -ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s) -{ - char *q, *q_end; - int c; - - if (buf_size > 0) { - q = buf; - q_end = buf + buf_size - 1; - while (q < q_end) { - c = *s++; - if (c == '\0') - break; - *q++ = c; - } - *q = '\0'; - } - return buf; -} - -/* strcat and truncate. */ -ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s) -{ - int len; - len = strlen(buf); - if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); - return buf; -} - -ST_FUNC char *pstrncpy(char *out, const char *in, size_t num) -{ - memcpy(out, in, num); - out[num] = '\0'; - return out; -} - -/* extract the basename of a file */ -PUB_FUNC char *tcc_basename(const char *name) -{ - char *p = strchr(name, 0); - while (p > name && !IS_DIRSEP(p[-1])) - --p; - return p; -} - -/* extract extension part of a file - * - * (if no extension, return pointer to end-of-string) - */ -PUB_FUNC char *tcc_fileextension (const char *name) -{ - char *b = tcc_basename(name); - char *e = strrchr(b, '.'); - return e ? e : strchr(b, 0); -} - -/********************************************************/ -/* memory management */ - -#undef free -#undef malloc -#undef realloc - -#ifndef MEM_DEBUG - -PUB_FUNC void tcc_free(void *ptr) -{ - free(ptr); -} - -PUB_FUNC void *tcc_malloc(unsigned long size) -{ - void *ptr; - ptr = malloc(size); - if (!ptr && size) - tcc_error("memory full (malloc)"); - return ptr; -} - -PUB_FUNC void *tcc_mallocz(unsigned long size) -{ - void *ptr; - ptr = tcc_malloc(size); - memset(ptr, 0, size); - return ptr; -} - -PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size) -{ - void *ptr1; - ptr1 = realloc(ptr, size); - if (!ptr1 && size) - tcc_error("memory full (realloc)"); - return ptr1; -} - -PUB_FUNC char *tcc_strdup(const char *str) -{ - char *ptr; - ptr = tcc_malloc(strlen(str) + 1); - strcpy(ptr, str); - return ptr; -} - -PUB_FUNC void tcc_memcheck(void) -{ -} - -#else - -#define MEM_DEBUG_MAGIC1 0xFEEDDEB1 -#define MEM_DEBUG_MAGIC2 0xFEEDDEB2 -#define MEM_DEBUG_MAGIC3 0xFEEDDEB3 -#define MEM_DEBUG_FILE_LEN 40 -#define MEM_DEBUG_CHECK3(header) \ - ((mem_debug_header_t*)((char*)header + header->size))->magic3 -#define MEM_USER_PTR(header) \ - ((char *)header + offsetof(mem_debug_header_t, magic3)) -#define MEM_HEADER_PTR(ptr) \ - (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) - -struct mem_debug_header { - unsigned magic1; - unsigned size; - struct mem_debug_header *prev; - struct mem_debug_header *next; - int line_num; - char file_name[MEM_DEBUG_FILE_LEN + 1]; - unsigned magic2; - ALIGNED(16) unsigned magic3; -}; - -typedef struct mem_debug_header mem_debug_header_t; - -static mem_debug_header_t *mem_debug_chain; -static unsigned mem_cur_size; -static unsigned mem_max_size; - -static mem_debug_header_t *malloc_check(void *ptr, const char *msg) -{ - mem_debug_header_t * header = MEM_HEADER_PTR(ptr); - if (header->magic1 != MEM_DEBUG_MAGIC1 || - header->magic2 != MEM_DEBUG_MAGIC2 || - MEM_DEBUG_CHECK3(header) != MEM_DEBUG_MAGIC3 || - header->size == (unsigned)-1) { - fprintf(stderr, "%s check failed\n", msg); - if (header->magic1 == MEM_DEBUG_MAGIC1) - fprintf(stderr, "%s:%u: block allocated here.\n", - header->file_name, header->line_num); - exit(1); - } - return header; -} - -PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) -{ - int ofs; - mem_debug_header_t *header; - - header = malloc(sizeof(mem_debug_header_t) + size); - if (!header) - tcc_error("memory full (malloc)"); - - header->magic1 = MEM_DEBUG_MAGIC1; - header->magic2 = MEM_DEBUG_MAGIC2; - header->size = size; - MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3; - header->line_num = line; - ofs = strlen(file) - MEM_DEBUG_FILE_LEN; - strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN); - header->file_name[MEM_DEBUG_FILE_LEN] = 0; - - header->next = mem_debug_chain; - header->prev = NULL; - if (header->next) - header->next->prev = header; - mem_debug_chain = header; - - mem_cur_size += size; - if (mem_cur_size > mem_max_size) - mem_max_size = mem_cur_size; - - return MEM_USER_PTR(header); -} - -PUB_FUNC void tcc_free_debug(void *ptr) -{ - mem_debug_header_t *header; - if (!ptr) - return; - header = malloc_check(ptr, "tcc_free"); - mem_cur_size -= header->size; - header->size = (unsigned)-1; - if (header->next) - header->next->prev = header->prev; - if (header->prev) - header->prev->next = header->next; - if (header == mem_debug_chain) - mem_debug_chain = header->next; - free(header); -} - -PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line) -{ - void *ptr; - ptr = tcc_malloc_debug(size,file,line); - memset(ptr, 0, size); - return ptr; -} - -PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line) -{ - mem_debug_header_t *header; - int mem_debug_chain_update = 0; - if (!ptr) - return tcc_malloc_debug(size, file, line); - header = malloc_check(ptr, "tcc_realloc"); - mem_cur_size -= header->size; - mem_debug_chain_update = (header == mem_debug_chain); - header = realloc(header, sizeof(mem_debug_header_t) + size); - if (!header) - tcc_error("memory full (realloc)"); - header->size = size; - MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3; - if (header->next) - header->next->prev = header; - if (header->prev) - header->prev->next = header; - if (mem_debug_chain_update) - mem_debug_chain = header; - mem_cur_size += size; - if (mem_cur_size > mem_max_size) - mem_max_size = mem_cur_size; - return MEM_USER_PTR(header); -} - -PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line) -{ - char *ptr; - ptr = tcc_malloc_debug(strlen(str) + 1, file, line); - strcpy(ptr, str); - return ptr; -} - -PUB_FUNC void tcc_memcheck(void) -{ - if (mem_cur_size) { - mem_debug_header_t *header = mem_debug_chain; - fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", - mem_cur_size, mem_max_size); - while (header) { - fprintf(stderr, "%s:%u: error: %u bytes leaked\n", - header->file_name, header->line_num, header->size); - header = header->next; - } -#if MEM_DEBUG-0 == 2 - exit(2); -#endif - } -} -#endif /* MEM_DEBUG */ - -#define free(p) use_tcc_free(p) -#define malloc(s) use_tcc_malloc(s) -#define realloc(p, s) use_tcc_realloc(p, s) - -/********************************************************/ -/* dynarrays */ - -ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data) -{ - int nb, nb_alloc; - void **pp; - - nb = *nb_ptr; - pp = *(void ***)ptab; - /* every power of two we double array size */ - if ((nb & (nb - 1)) == 0) { - if (!nb) - nb_alloc = 1; - else - nb_alloc = nb * 2; - pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); - *(void***)ptab = pp; - } - pp[nb++] = data; - *nb_ptr = nb; -} - -ST_FUNC void dynarray_reset(void *pp, int *n) -{ - void **p; - for (p = *(void***)pp; *n; ++p, --*n) - if (*p) - tcc_free(*p); - tcc_free(*(void**)pp); - *(void**)pp = NULL; -} - -static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in) -{ - const char *p; - do { - int c; - CString str; - - cstr_new(&str); - for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) { - if (c == '{' && p[1] && p[2] == '}') { - c = p[1], p += 2; - if (c == 'B') - cstr_cat(&str, s->tcc_lib_path, -1); - } else { - cstr_ccat(&str, c); - } - } - if (str.size) { - cstr_ccat(&str, '\0'); - dynarray_add(p_ary, p_nb_ary, tcc_strdup(str.data)); - } - cstr_free(&str); - in = p+1; - } while (*p); -} - -/********************************************************/ - -static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) -{ - int len; - len = strlen(buf); - vsnprintf(buf + len, buf_size - len, fmt, ap); -} - -static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - strcat_vprintf(buf, buf_size, fmt, ap); - va_end(ap); -} - -static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) -{ - char buf[2048]; - BufferedFile **pf, *f; - - buf[0] = '\0'; - /* use upper file if inline ":asm:" or token ":paste:" */ - for (f = file; f && f->filename[0] == ':'; f = f->prev) - ; - if (f) { - for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) - strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", - (*pf)->filename, (*pf)->line_num); - if (f->line_num > 0) { - strcat_printf(buf, sizeof(buf), "%s:%d: ", - f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL)); - } else { - strcat_printf(buf, sizeof(buf), "%s: ", - f->filename); - } - } else { - strcat_printf(buf, sizeof(buf), "tcc: "); - } - if (is_warning) - strcat_printf(buf, sizeof(buf), "warning: "); - else - strcat_printf(buf, sizeof(buf), "error: "); - strcat_vprintf(buf, sizeof(buf), fmt, ap); - - if (!s1->error_func) { - /* default case: stderr */ - if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout) - /* print a newline during tcc -E */ - printf("\n"), fflush(stdout); - fflush(stdout); /* flush -v output */ - fprintf(stderr, "%s\n", buf); - fflush(stderr); /* print error/warning now (win32) */ - } else { - s1->error_func(s1->error_opaque, buf); - } - if (!is_warning || s1->warn_error) - s1->nb_errors++; -} - -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, - void (*error_func)(void *opaque, const char *msg)) -{ - s->error_opaque = error_opaque; - s->error_func = error_func; -} - -/* error without aborting current compilation */ -PUB_FUNC void tcc_error_noabort(const char *fmt, ...) -{ - TCCState *s1 = tcc_state; - va_list ap; - - va_start(ap, fmt); - error1(s1, 0, fmt, ap); - va_end(ap); -} - -PUB_FUNC void tcc_error(const char *fmt, ...) -{ - TCCState *s1 = tcc_state; - va_list ap; - - va_start(ap, fmt); - error1(s1, 0, fmt, ap); - va_end(ap); - /* better than nothing: in some cases, we accept to handle errors */ - if (s1->error_set_jmp_enabled) { - longjmp(s1->error_jmp_buf, 1); - } else { - /* XXX: eliminate this someday */ - exit(1); - } -} - -PUB_FUNC void tcc_warning(const char *fmt, ...) -{ - TCCState *s1 = tcc_state; - va_list ap; - - if (s1->warn_none) - return; - - va_start(ap, fmt); - error1(s1, 1, fmt, ap); - va_end(ap); -} - -/********************************************************/ -/* I/O layer */ - -ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) -{ - BufferedFile *bf; - int buflen = initlen ? initlen : IO_BUF_SIZE; - - bf = tcc_mallocz(sizeof(BufferedFile) + buflen); - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + initlen; - bf->buf_end[0] = CH_EOB; /* put eob symbol */ - pstrcpy(bf->filename, sizeof(bf->filename), filename); - bf->true_filename = bf->filename; - bf->line_num = 1; - bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; - bf->fd = -1; - bf->prev = file; - file = bf; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; -} - -ST_FUNC void tcc_close(void) -{ - BufferedFile *bf = file; - if (bf->fd > 0) { - close(bf->fd); - total_lines += bf->line_num; - } - if (bf->true_filename != bf->filename) - tcc_free(bf->true_filename); - file = bf->prev; - tcc_free(bf); -} - -ST_FUNC int tcc_open(TCCState *s1, const char *filename) -{ - int fd; - if (strcmp(filename, "-") == 0) - fd = 0, filename = ""; - else - fd = open(filename, O_RDONLY | O_BINARY); - if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) - printf("%s %*s%s\n", fd < 0 ? "nf":"->", - (int)(s1->include_stack_ptr - s1->include_stack), "", filename); - if (fd < 0) - return -1; - tcc_open_bf(s1, filename, 0); -#ifdef _WIN32 - normalize_slashes(file->filename); -#endif - file->fd = fd; - return fd; -} - -/* compile the file opened in 'file'. Return non zero if errors. */ -static int tcc_compile(TCCState *s1) -{ - Sym *define_start; - int filetype, is_asm; - - define_start = define_stack; - filetype = s1->filetype; - is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP; - - if (setjmp(s1->error_jmp_buf) == 0) { - s1->nb_errors = 0; - s1->error_set_jmp_enabled = 1; - - preprocess_start(s1, is_asm); - if (s1->output_type == TCC_OUTPUT_PREPROCESS) { - tcc_preprocess(s1); - } else if (is_asm) { -#ifdef CONFIG_TCC_ASM - tcc_assemble(s1, filetype == AFF_TYPE_ASMPP); -#else - tcc_error_noabort("asm not supported"); -#endif - } else { - tccgen_compile(s1); - } - } - s1->error_set_jmp_enabled = 0; - - preprocess_end(s1); - free_inline_functions(s1); - /* reset define stack, but keep -D and built-ins */ - free_defines(define_start); - sym_pop(&global_stack, NULL, 0); - sym_pop(&local_stack, NULL, 0); - return s1->nb_errors != 0 ? -1 : 0; -} - -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) -{ - int len, ret; - - len = strlen(str); - tcc_open_bf(s, "", len); - memcpy(file->buffer, str, len); - ret = tcc_compile(s); - tcc_close(); - return ret; -} - -/* define a preprocessor symbol. A value can also be provided with the '=' operator */ -LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) -{ - int len1, len2; - /* default value */ - if (!value) - value = "1"; - len1 = strlen(sym); - len2 = strlen(value); - - /* init file structure */ - tcc_open_bf(s1, "", len1 + len2 + 1); - memcpy(file->buffer, sym, len1); - file->buffer[len1] = ' '; - memcpy(file->buffer + len1 + 1, value, len2); - - /* parse with define parser */ - next_nomacro(); - parse_define(); - tcc_close(); -} - -/* undefine a preprocessor symbol */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) -{ - TokenSym *ts; - Sym *s; - ts = tok_alloc(sym, strlen(sym)); - s = define_find(ts->tok); - /* undefine symbol by putting an invalid name */ - if (s) - define_undef(s); -} - -/* cleanup all static data used during compilation */ -static void tcc_cleanup(void) -{ - if (NULL == tcc_state) - return; - while (file) - tcc_close(); - tccpp_delete(tcc_state); - tcc_state = NULL; - /* free sym_pools */ - dynarray_reset(&sym_pools, &nb_sym_pools); - /* reset symbol stack */ - sym_free_first = NULL; -} - -LIBTCCAPI TCCState *tcc_new(void) -{ - TCCState *s; - - tcc_cleanup(); - - s = tcc_mallocz(sizeof(TCCState)); - if (!s) - return NULL; - tcc_state = s; - ++nb_states; - - s->alacarte_link = 1; - s->nocommon = 1; - s->warn_implicit_function_declaration = 1; - s->ms_extensions = 1; - -#ifdef CHAR_IS_UNSIGNED - s->char_is_unsigned = 1; -#endif -#ifdef TCC_TARGET_I386 - s->seg_size = 32; -#endif - /* enable this if you want symbols with leading underscore on windows: */ -#if 0 /* def TCC_TARGET_PE */ - s->leading_underscore = 1; -#endif -#ifdef _WIN32 - tcc_set_lib_path_w32(s); -#else - tcc_set_lib_path(s, CONFIG_TCCDIR); -#endif - tccelf_new(s); - tccpp_new(s); - - /* we add dummy defines for some special macros to speed up tests - and to have working defined() */ - define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); - define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); - define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL); - { - /* define __TINYC__ 92X */ - char buffer[32]; int a,b,c; - sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c); - sprintf(buffer, "%d", a*10000 + b*100 + c); - tcc_define_symbol(s, "__TINYC__", buffer); - } - - /* standard defines */ - tcc_define_symbol(s, "__STDC__", NULL); - tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); - tcc_define_symbol(s, "__STDC_HOSTED__", NULL); - - /* target defines */ -#if defined(TCC_TARGET_I386) - tcc_define_symbol(s, "__i386__", NULL); - tcc_define_symbol(s, "__i386", NULL); - tcc_define_symbol(s, "i386", NULL); -#elif defined(TCC_TARGET_X86_64) - tcc_define_symbol(s, "__x86_64__", NULL); -#elif defined(TCC_TARGET_ARM) - tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); - tcc_define_symbol(s, "__arm_elf__", NULL); - tcc_define_symbol(s, "__arm_elf", NULL); - tcc_define_symbol(s, "arm_elf", NULL); - tcc_define_symbol(s, "__arm__", NULL); - tcc_define_symbol(s, "__arm", NULL); - tcc_define_symbol(s, "arm", NULL); - tcc_define_symbol(s, "__APCS_32__", NULL); - tcc_define_symbol(s, "__ARMEL__", NULL); -#if defined(TCC_ARM_EABI) - tcc_define_symbol(s, "__ARM_EABI__", NULL); -#endif -#if defined(TCC_ARM_HARDFLOAT) - s->float_abi = ARM_HARD_FLOAT; - tcc_define_symbol(s, "__ARM_PCS_VFP", NULL); -#else - s->float_abi = ARM_SOFTFP_FLOAT; -#endif -#elif defined(TCC_TARGET_ARM64) - tcc_define_symbol(s, "__aarch64__", NULL); -#elif defined TCC_TARGET_C67 - tcc_define_symbol(s, "__C67__", NULL); -#endif - -#ifdef TCC_TARGET_PE - tcc_define_symbol(s, "_WIN32", NULL); -# ifdef TCC_TARGET_X86_64 - tcc_define_symbol(s, "_WIN64", NULL); -# endif -#else - tcc_define_symbol(s, "__unix__", NULL); - tcc_define_symbol(s, "__unix", NULL); - tcc_define_symbol(s, "unix", NULL); -# if defined(__linux__) - tcc_define_symbol(s, "__linux__", NULL); - tcc_define_symbol(s, "__linux", NULL); -# endif -# if defined(__FreeBSD__) - tcc_define_symbol(s, "__FreeBSD__", "__FreeBSD__"); - /* No 'Thread Storage Local' on FreeBSD with tcc */ - tcc_define_symbol(s, "__NO_TLS", NULL); -# endif -# if defined(__FreeBSD_kernel__) - tcc_define_symbol(s, "__FreeBSD_kernel__", NULL); -# endif -# if defined(__NetBSD__) - tcc_define_symbol(s, "__NetBSD__", "__NetBSD__"); -# endif -# if defined(__OpenBSD__) - tcc_define_symbol(s, "__OpenBSD__", "__OpenBSD__"); -# endif -#endif - - /* TinyCC & gcc defines */ -#if PTR_SIZE == 4 - /* 32bit systems. */ - tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); - tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); - tcc_define_symbol(s, "__ILP32__", NULL); -#elif LONG_SIZE == 4 - /* 64bit Windows. */ - tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); - tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); - tcc_define_symbol(s, "__LLP64__", NULL); -#else - /* Other 64bit systems. */ - tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long"); - tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long"); - tcc_define_symbol(s, "__LP64__", NULL); -#endif - -#ifdef TCC_TARGET_PE - tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short"); - tcc_define_symbol(s, "__WINT_TYPE__", "unsigned short"); -#else - tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); - /* wint_t is unsigned int by default, but (signed) int on BSDs - and unsigned short on windows. Other OSes might have still - other conventions, sigh. */ -# if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) - tcc_define_symbol(s, "__WINT_TYPE__", "int"); -# ifdef __FreeBSD__ - /* define __GNUC__ to have some useful stuff from sys/cdefs.h - that are unconditionally used in FreeBSDs other system headers :/ */ - tcc_define_symbol(s, "__GNUC__", "2"); - tcc_define_symbol(s, "__GNUC_MINOR__", "7"); - tcc_define_symbol(s, "__builtin_alloca", "alloca"); -# endif -# else - tcc_define_symbol(s, "__WINT_TYPE__", "unsigned int"); - /* glibc defines */ - tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", - "name proto __asm__ (#alias)"); - tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", - "name proto __asm__ (#alias) __THROW"); -# endif -# if defined(TCC_MUSL) - tcc_define_symbol(s, "__DEFINED_va_list", ""); - tcc_define_symbol(s, "__DEFINED___isoc_va_list", ""); - tcc_define_symbol(s, "__isoc_va_list", "void *"); -# endif /* TCC_MUSL */ - /* Some GCC builtins that are simple to express as macros. */ - tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x"); -#endif /* ndef TCC_TARGET_PE */ - return s; -} - -LIBTCCAPI void tcc_delete(TCCState *s1) -{ - tcc_cleanup(); - - /* free sections */ - tccelf_delete(s1); - - /* free library paths */ - dynarray_reset(&s1->library_paths, &s1->nb_library_paths); - dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths); - - /* free include paths */ - dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes); - dynarray_reset(&s1->include_paths, &s1->nb_include_paths); - dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); - dynarray_reset(&s1->cmd_include_files, &s1->nb_cmd_include_files); - - tcc_free(s1->tcc_lib_path); - tcc_free(s1->soname); - tcc_free(s1->rpath); - tcc_free(s1->init_symbol); - tcc_free(s1->fini_symbol); - tcc_free(s1->outfile); - tcc_free(s1->deps_outfile); - dynarray_reset(&s1->files, &s1->nb_files); - dynarray_reset(&s1->target_deps, &s1->nb_target_deps); - dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs); - dynarray_reset(&s1->argv, &s1->argc); - -#ifdef TCC_IS_NATIVE - /* free runtime memory */ - tcc_run_free(s1); -#endif - - tcc_free(s1); - if (0 == --nb_states) - tcc_memcheck(); -} - -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) -{ - s->output_type = output_type; - - /* always elf for objects */ - if (output_type == TCC_OUTPUT_OBJ) - s->output_format = TCC_OUTPUT_FORMAT_ELF; - - if (s->char_is_unsigned) - tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); - - if (!s->nostdinc) { - /* default include paths */ - /* -isystem paths have already been handled */ - tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS); - } - -#ifdef CONFIG_TCC_BCHECK - if (s->do_bounds_check) { - /* if bound checking, then add corresponding sections */ - tccelf_bounds_new(s); - /* define symbol */ - tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); - } -#endif - if (s->do_debug) { - /* add debug sections */ - tccelf_stab_new(s); - } - - tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); - -#ifdef TCC_TARGET_PE -# ifdef _WIN32 - if (!s->nostdlib && output_type != TCC_OUTPUT_OBJ) - tcc_add_systemdir(s); -# endif -#else - /* paths for crt objects */ - tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); - /* add libc crt1/crti objects */ - if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && - !s->nostdlib) { - if (output_type != TCC_OUTPUT_DLL) - tcc_add_crt(s, "crt1.o"); - tcc_add_crt(s, "crti.o"); - } -#endif - return 0; -} - -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) -{ - tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname); - return 0; -} - -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) -{ - tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); - return 0; -} - -ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) -{ - int ret; - - /* open the file */ - ret = tcc_open(s1, filename); - if (ret < 0) { - if (flags & AFF_PRINT_ERROR) - tcc_error_noabort("file '%s' not found", filename); - return ret; - } - - /* update target deps */ - dynarray_add(&s1->target_deps, &s1->nb_target_deps, - tcc_strdup(filename)); - - if (flags & AFF_TYPE_BIN) { - ElfW(Ehdr) ehdr; - int fd, obj_type; - - fd = file->fd; - obj_type = tcc_object_type(fd, &ehdr); - lseek(fd, 0, SEEK_SET); - - /* do not display line number if error */ - file->line_num = 0; - -#ifdef TCC_TARGET_MACHO - if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib")) - obj_type = AFF_BINTYPE_DYN; -#endif - - switch (obj_type) { - case AFF_BINTYPE_REL: - ret = tcc_load_object_file(s1, fd, 0); - break; -#ifndef TCC_TARGET_PE - case AFF_BINTYPE_DYN: - if (s1->output_type == TCC_OUTPUT_MEMORY) { - ret = 0; -#ifdef TCC_IS_NATIVE - if (NULL == dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) - ret = -1; -#endif - } else { - ret = tcc_load_dll(s1, fd, filename, - (flags & AFF_REFERENCED_DLL) != 0); - } - break; -#endif - case AFF_BINTYPE_AR: - ret = tcc_load_archive(s1, fd); - break; -#ifdef TCC_TARGET_COFF - case AFF_BINTYPE_C67: - ret = tcc_load_coff(s1, fd); - break; -#endif - default: -#ifdef TCC_TARGET_PE - ret = pe_load_file(s1, filename, fd); -#else - /* as GNU ld, consider it is an ld script if not recognized */ - ret = tcc_load_ldscript(s1); -#endif - if (ret < 0) - tcc_error_noabort("unrecognized file type"); - break; - } - } else { - ret = tcc_compile(s1); - } - tcc_close(); - return ret; -} - -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) -{ - int filetype = s->filetype; - int flags = AFF_PRINT_ERROR; - if (filetype == 0) { - /* use a file extension to detect a filetype */ - const char *ext = tcc_fileextension(filename); - if (ext[0]) { - ext++; - if (!strcmp(ext, "S")) - filetype = AFF_TYPE_ASMPP; - else if (!strcmp(ext, "s")) - filetype = AFF_TYPE_ASM; - else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i")) - filetype = AFF_TYPE_C; - else - flags |= AFF_TYPE_BIN; - } else { - filetype = AFF_TYPE_C; - } - s->filetype = filetype; - } - return tcc_add_file_internal(s, filename, flags); -} - -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) -{ - tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname); - return 0; -} - -static int tcc_add_library_internal(TCCState *s, const char *fmt, - const char *filename, int flags, char **paths, int nb_paths) -{ - char buf[1024]; - int i; - - for(i = 0; i < nb_paths; i++) { - snprintf(buf, sizeof(buf), fmt, paths[i], filename); - if (tcc_add_file_internal(s, buf, flags | AFF_TYPE_BIN) == 0) - return 0; - } - return -1; -} - -/* find and load a dll. Return non zero if not found */ -/* XXX: add '-rpath' option support ? */ -ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) -{ - return tcc_add_library_internal(s, "%s/%s", filename, flags, - s->library_paths, s->nb_library_paths); -} - -ST_FUNC int tcc_add_crt(TCCState *s, const char *filename) -{ - if (-1 == tcc_add_library_internal(s, "%s/%s", - filename, 0, s->crt_paths, s->nb_crt_paths)) - tcc_error_noabort("file '%s' not found", filename); - return 0; -} - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) -{ -#if defined TCC_TARGET_PE - const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL }; - const char **pp = s->static_link ? libs + 4 : libs; -#elif defined TCC_TARGET_MACHO - const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL }; - const char **pp = s->static_link ? libs + 1 : libs; -#else - const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL }; - const char **pp = s->static_link ? libs + 1 : libs; -#endif - while (*pp) { - if (0 == tcc_add_library_internal(s, *pp, - libraryname, 0, s->library_paths, s->nb_library_paths)) - return 0; - ++pp; - } - return -1; -} - -PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname) -{ - int ret = tcc_add_library(s, libname); - if (ret < 0) - tcc_error_noabort("library '%s' not found", libname); - return ret; -} - -/* handle #pragma comment(lib,) */ -ST_FUNC void tcc_add_pragma_libs(TCCState *s1) -{ - int i; - for (i = 0; i < s1->nb_pragma_libs; i++) - tcc_add_library_err(s1, s1->pragma_libs[i]); -} - -LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val) -{ -#ifdef TCC_TARGET_PE - /* On x86_64 'val' might not be reachable with a 32bit offset. - So it is handled here as if it were in a DLL. */ - pe_putimport(s, 0, name, (uintptr_t)val); -#else - set_elf_sym(symtab_section, (uintptr_t)val, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_ABS, name); -#endif - return 0; -} - -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) -{ - tcc_free(s->tcc_lib_path); - s->tcc_lib_path = tcc_strdup(path); -} - -#define WD_ALL 0x0001 /* warning is activated when using -Wall */ -#define FD_INVERT 0x0002 /* invert value before storing */ - -typedef struct FlagDef { - uint16_t offset; - uint16_t flags; - const char *name; -} FlagDef; - -static int no_flag(const char **pp) -{ - const char *p = *pp; - if (*p != 'n' || *++p != 'o' || *++p != '-') - return 0; - *pp = p + 1; - return 1; -} - -ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name) -{ - int value, ret; - const FlagDef *p; - const char *r; - - value = 1; - r = name; - if (no_flag(&r)) - value = 0; - - for (ret = -1, p = flags; p->name; ++p) { - if (ret) { - if (strcmp(r, p->name)) - continue; - } else { - if (0 == (p->flags & WD_ALL)) - continue; - } - if (p->offset) { - *(int*)((char *)s + p->offset) = - p->flags & FD_INVERT ? !value : value; - if (ret) - return 0; - } else { - ret = 0; - } - } - return ret; -} - -static int strstart(const char *val, const char **str) -{ - const char *p, *q; - p = *str; - q = val; - while (*q) { - if (*p != *q) - return 0; - p++; - q++; - } - *str = p; - return 1; -} - -/* Like strstart, but automatically takes into account that ld options can - * - * - start with double or single dash (e.g. '--soname' or '-soname') - * - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so' - * or '-Wl,-soname=x.so') - * - * you provide `val` always in 'option[=]' form (no leading -) - */ -static int link_option(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - int ret; - - /* there should be 1 or 2 dashes */ - if (*str++ != '-') - return 0; - if (*str == '-') - str++; - - /* then str & val should match (potentially up to '=') */ - p = str; - q = val; - - ret = 1; - if (q[0] == '?') { - ++q; - if (no_flag(&p)) - ret = -1; - } - - while (*q != '\0' && *q != '=') { - if (*p != *q) - return 0; - p++; - q++; - } - - /* '=' near eos means ',' or '=' is ok */ - if (*q == '=') { - if (*p == 0) - *ptr = p; - if (*p != ',' && *p != '=') - return 0; - p++; - } else if (*p) { - return 0; - } - *ptr = p; - return ret; -} - -static const char *skip_linker_arg(const char **str) -{ - const char *s1 = *str; - const char *s2 = strchr(s1, ','); - *str = s2 ? s2++ : (s2 = s1 + strlen(s1)); - return s2; -} - -static void copy_linker_arg(char **pp, const char *s, int sep) -{ - const char *q = s; - char *p = *pp; - int l = 0; - if (p && sep) - p[l = strlen(p)] = sep, ++l; - skip_linker_arg(&q); - pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s); -} - -/* set linker options */ -static int tcc_set_linker(TCCState *s, const char *option) -{ - while (*option) { - - const char *p = NULL; - char *end = NULL; - int ignoring = 0; - int ret; - - if (link_option(option, "Bsymbolic", &p)) { - s->symbolic = 1; - } else if (link_option(option, "nostdlib", &p)) { - s->nostdlib = 1; - } else if (link_option(option, "fini=", &p)) { - copy_linker_arg(&s->fini_symbol, p, 0); - ignoring = 1; - } else if (link_option(option, "image-base=", &p) - || link_option(option, "Ttext=", &p)) { - s->text_addr = strtoull(p, &end, 16); - s->has_text_addr = 1; - } else if (link_option(option, "init=", &p)) { - copy_linker_arg(&s->init_symbol, p, 0); - ignoring = 1; - } else if (link_option(option, "oformat=", &p)) { -#if defined(TCC_TARGET_PE) - if (strstart("pe-", &p)) { -#elif PTR_SIZE == 8 - if (strstart("elf64-", &p)) { -#else - if (strstart("elf32-", &p)) { -#endif - s->output_format = TCC_OUTPUT_FORMAT_ELF; - } else if (!strcmp(p, "binary")) { - s->output_format = TCC_OUTPUT_FORMAT_BINARY; -#ifdef TCC_TARGET_COFF - } else if (!strcmp(p, "coff")) { - s->output_format = TCC_OUTPUT_FORMAT_COFF; -#endif - } else - goto err; - - } else if (link_option(option, "as-needed", &p)) { - ignoring = 1; - } else if (link_option(option, "O", &p)) { - ignoring = 1; - } else if (link_option(option, "export-all-symbols", &p)) { - s->rdynamic = 1; - } else if (link_option(option, "rpath=", &p)) { - copy_linker_arg(&s->rpath, p, ':'); - } else if (link_option(option, "enable-new-dtags", &p)) { - s->enable_new_dtags = 1; - } else if (link_option(option, "section-alignment=", &p)) { - s->section_align = strtoul(p, &end, 16); - } else if (link_option(option, "soname=", &p)) { - copy_linker_arg(&s->soname, p, 0); -#ifdef TCC_TARGET_PE - } else if (link_option(option, "large-address-aware", &p)) { - s->pe_characteristics |= 0x20; - } else if (link_option(option, "file-alignment=", &p)) { - s->pe_file_align = strtoul(p, &end, 16); - } else if (link_option(option, "stack=", &p)) { - s->pe_stack_size = strtoul(p, &end, 10); - } else if (link_option(option, "subsystem=", &p)) { -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - if (!strcmp(p, "native")) { - s->pe_subsystem = 1; - } else if (!strcmp(p, "console")) { - s->pe_subsystem = 3; - } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) { - s->pe_subsystem = 2; - } else if (!strcmp(p, "posix")) { - s->pe_subsystem = 7; - } else if (!strcmp(p, "efiapp")) { - s->pe_subsystem = 10; - } else if (!strcmp(p, "efiboot")) { - s->pe_subsystem = 11; - } else if (!strcmp(p, "efiruntime")) { - s->pe_subsystem = 12; - } else if (!strcmp(p, "efirom")) { - s->pe_subsystem = 13; -#elif defined(TCC_TARGET_ARM) - if (!strcmp(p, "wince")) { - s->pe_subsystem = 9; -#endif - } else - goto err; -#endif - } else if (ret = link_option(option, "?whole-archive", &p), ret) { - s->alacarte_link = ret < 0; - } else if (p) { - return 0; - } else { - err: - tcc_error("unsupported linker option '%s'", option); - } - - if (ignoring && s->warn_unsupported) - tcc_warning("unsupported linker option '%s'", option); - - option = skip_linker_arg(&p); - } - return 1; -} - -typedef struct TCCOption { - const char *name; - uint16_t index; - uint16_t flags; -} TCCOption; - -enum { - TCC_OPTION_HELP, - TCC_OPTION_HELP2, - TCC_OPTION_v, - TCC_OPTION_I, - TCC_OPTION_D, - TCC_OPTION_U, - TCC_OPTION_P, - TCC_OPTION_L, - TCC_OPTION_B, - TCC_OPTION_l, - TCC_OPTION_bench, - TCC_OPTION_bt, - TCC_OPTION_b, - TCC_OPTION_g, - TCC_OPTION_c, - TCC_OPTION_dumpversion, - TCC_OPTION_d, - TCC_OPTION_static, - TCC_OPTION_std, - TCC_OPTION_shared, - TCC_OPTION_soname, - TCC_OPTION_o, - TCC_OPTION_r, - TCC_OPTION_s, - TCC_OPTION_traditional, - TCC_OPTION_Wl, - TCC_OPTION_Wp, - TCC_OPTION_W, - TCC_OPTION_O, - TCC_OPTION_mfloat_abi, - TCC_OPTION_m, - TCC_OPTION_f, - TCC_OPTION_isystem, - TCC_OPTION_iwithprefix, - TCC_OPTION_include, - TCC_OPTION_nostdinc, - TCC_OPTION_nostdlib, - TCC_OPTION_print_search_dirs, - TCC_OPTION_rdynamic, - TCC_OPTION_param, - TCC_OPTION_pedantic, - TCC_OPTION_pthread, - TCC_OPTION_run, - TCC_OPTION_w, - TCC_OPTION_pipe, - TCC_OPTION_E, - TCC_OPTION_MD, - TCC_OPTION_MF, - TCC_OPTION_x, - TCC_OPTION_ar, - TCC_OPTION_impdef -}; - -#define TCC_OPTION_HAS_ARG 0x0001 -#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ - -static const TCCOption tcc_options[] = { - { "h", TCC_OPTION_HELP, 0 }, - { "-help", TCC_OPTION_HELP, 0 }, - { "?", TCC_OPTION_HELP, 0 }, - { "hh", TCC_OPTION_HELP2, 0 }, - { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, - { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, - { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, - { "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, - { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, - { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "bench", TCC_OPTION_bench, 0 }, -#ifdef CONFIG_TCC_BACKTRACE - { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, -#endif -#ifdef CONFIG_TCC_BCHECK - { "b", TCC_OPTION_b, 0 }, -#endif - { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "c", TCC_OPTION_c, 0 }, - { "dumpversion", TCC_OPTION_dumpversion, 0}, - { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "static", TCC_OPTION_static, 0 }, - { "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "shared", TCC_OPTION_shared, 0 }, - { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG }, - { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, - { "-param", TCC_OPTION_param, TCC_OPTION_HAS_ARG }, - { "pedantic", TCC_OPTION_pedantic, 0}, - { "pthread", TCC_OPTION_pthread, 0}, - { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "rdynamic", TCC_OPTION_rdynamic, 0 }, - { "r", TCC_OPTION_r, 0 }, - { "s", TCC_OPTION_s, 0 }, - { "traditional", TCC_OPTION_traditional, 0 }, - { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, -#ifdef TCC_TARGET_ARM - { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG }, -#endif - { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG }, - { "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG }, - { "nostdinc", TCC_OPTION_nostdinc, 0 }, - { "nostdlib", TCC_OPTION_nostdlib, 0 }, - { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, - { "w", TCC_OPTION_w, 0 }, - { "pipe", TCC_OPTION_pipe, 0}, - { "E", TCC_OPTION_E, 0}, - { "MD", TCC_OPTION_MD, 0}, - { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, - { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, - { "ar", TCC_OPTION_ar, 0}, -#ifdef TCC_TARGET_PE - { "impdef", TCC_OPTION_impdef, 0}, -#endif - { NULL, 0, 0 }, -}; - -static const FlagDef options_W[] = { - { 0, 0, "all" }, - { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, - { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, - { offsetof(TCCState, warn_error), 0, "error" }, - { offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" }, - { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, - "implicit-function-declaration" }, - { 0, 0, NULL } -}; - -static const FlagDef options_f[] = { - { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, - { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, - { offsetof(TCCState, nocommon), FD_INVERT, "common" }, - { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, - { offsetof(TCCState, ms_extensions), 0, "ms-extensions" }, - { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" }, - { 0, 0, NULL } -}; - -static const FlagDef options_m[] = { - { offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" }, -#ifdef TCC_TARGET_X86_64 - { offsetof(TCCState, nosse), FD_INVERT, "sse" }, -#endif - { 0, 0, NULL } -}; - -static void parse_option_D(TCCState *s1, const char *optarg) -{ - char *sym = tcc_strdup(optarg); - char *value = strchr(sym, '='); - if (value) - *value++ = '\0'; - tcc_define_symbol(s1, sym, value); - tcc_free(sym); -} - -static void args_parser_add_file(TCCState *s, const char* filename, int filetype) -{ - struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); - f->type = filetype; - f->alacarte = s->alacarte_link; - strcpy(f->name, filename); - dynarray_add(&s->files, &s->nb_files, f); -} - -static int args_parser_make_argv(const char *r, int *argc, char ***argv) -{ - int ret = 0, q, c; - CString str; - for(;;) { - while (c = (unsigned char)*r, c && c <= ' ') - ++r; - if (c == 0) - break; - q = 0; - cstr_new(&str); - while (c = (unsigned char)*r, c) { - ++r; - if (c == '\\' && (*r == '"' || *r == '\\')) { - c = *r++; - } else if (c == '"') { - q = !q; - continue; - } else if (q == 0 && c <= ' ') { - break; - } - cstr_ccat(&str, c); - } - cstr_ccat(&str, 0); - //printf("<%s>\n", str.data), fflush(stdout); - dynarray_add(argv, argc, tcc_strdup(str.data)); - cstr_free(&str); - ++ret; - } - return ret; -} - -/* read list file */ -static void args_parser_listfile(TCCState *s, - const char *filename, int optind, int *pargc, char ***pargv) -{ - int fd, i; - size_t len; - char *p; - int argc = 0; - char **argv = NULL; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - tcc_error("listfile '%s' not found", filename); - - len = lseek(fd, 0, SEEK_END); - p = tcc_malloc(len + 1), p[len] = 0; - lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd); - - for (i = 0; i < *pargc; ++i) - if (i == optind) - args_parser_make_argv(p, &argc, &argv); - else - dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i])); - - tcc_free(p); - dynarray_reset(&s->argv, &s->argc); - *pargc = s->argc = argc, *pargv = s->argv = argv; -} - -PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind) -{ - const TCCOption *popt; - const char *optarg, *r; - const char *run = NULL; - int last_o = -1; - int x; - CString linker_arg; /* collect -Wl options */ - int tool = 0, arg_start = 0, noaction = optind; - char **argv = *pargv; - int argc = *pargc; - - cstr_new(&linker_arg); - - while (optind < argc) { - r = argv[optind]; - if (r[0] == '@' && r[1] != '\0') { - args_parser_listfile(s, r + 1, optind, &argc, &argv); - continue; - } - optind++; - if (tool) { - if (r[0] == '-' && r[1] == 'v' && r[2] == 0) - ++s->verbose; - continue; - } -reparse: - if (r[0] != '-' || r[1] == '\0') { - if (r[0] != '@') /* allow "tcc file(s) -run @ args ..." */ - args_parser_add_file(s, r, s->filetype); - if (run) { - tcc_set_options(s, run); - arg_start = optind - 1; - break; - } - continue; - } - - /* find option in table */ - for(popt = tcc_options; ; ++popt) { - const char *p1 = popt->name; - const char *r1 = r + 1; - if (p1 == NULL) - tcc_error("invalid option -- '%s'", r); - if (!strstart(p1, &r1)) - continue; - optarg = r1; - if (popt->flags & TCC_OPTION_HAS_ARG) { - if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) { - if (optind >= argc) - arg_err: - tcc_error("argument to '%s' is missing", r); - optarg = argv[optind++]; - } - } else if (*r1 != '\0') - continue; - break; - } - - switch(popt->index) { - case TCC_OPTION_HELP: - return OPT_HELP; - case TCC_OPTION_HELP2: - return OPT_HELP2; - case TCC_OPTION_I: - tcc_add_include_path(s, optarg); - break; - case TCC_OPTION_D: - parse_option_D(s, optarg); - break; - case TCC_OPTION_U: - tcc_undefine_symbol(s, optarg); - break; - case TCC_OPTION_L: - tcc_add_library_path(s, optarg); - break; - case TCC_OPTION_B: - /* set tcc utilities path (mainly for tcc development) */ - tcc_set_lib_path(s, optarg); - break; - case TCC_OPTION_l: - args_parser_add_file(s, optarg, AFF_TYPE_LIB); - s->nb_libraries++; - break; - case TCC_OPTION_pthread: - parse_option_D(s, "_REENTRANT"); - s->option_pthread = 1; - break; - case TCC_OPTION_bench: - s->do_bench = 1; - break; -#ifdef CONFIG_TCC_BACKTRACE - case TCC_OPTION_bt: - tcc_set_num_callers(atoi(optarg)); - break; -#endif -#ifdef CONFIG_TCC_BCHECK - case TCC_OPTION_b: - s->do_bounds_check = 1; - s->do_debug = 1; - break; -#endif - case TCC_OPTION_g: - s->do_debug = 1; - break; - case TCC_OPTION_c: - x = TCC_OUTPUT_OBJ; - set_output_type: - if (s->output_type) - tcc_warning("-%s: overriding compiler action already specified", popt->name); - s->output_type = x; - break; - case TCC_OPTION_d: - if (*optarg == 'D') - s->dflag = 3; - else if (*optarg == 'M') - s->dflag = 7; - else if (*optarg == 't') - s->dflag = 16; - else if (isnum(*optarg)) - g_debug = atoi(optarg); - else - goto unsupported_option; - break; - case TCC_OPTION_static: - s->static_link = 1; - break; - case TCC_OPTION_std: - /* silently ignore, a current purpose: - allow to use a tcc as a reference compiler for "make test" */ - break; - case TCC_OPTION_shared: - x = TCC_OUTPUT_DLL; - goto set_output_type; - case TCC_OPTION_soname: - s->soname = tcc_strdup(optarg); - break; - case TCC_OPTION_o: - if (s->outfile) { - tcc_warning("multiple -o option"); - tcc_free(s->outfile); - } - s->outfile = tcc_strdup(optarg); - break; - case TCC_OPTION_r: - /* generate a .o merging several output files */ - s->option_r = 1; - x = TCC_OUTPUT_OBJ; - goto set_output_type; - case TCC_OPTION_isystem: - tcc_add_sysinclude_path(s, optarg); - break; - case TCC_OPTION_include: - dynarray_add(&s->cmd_include_files, - &s->nb_cmd_include_files, tcc_strdup(optarg)); - break; - case TCC_OPTION_nostdinc: - s->nostdinc = 1; - break; - case TCC_OPTION_nostdlib: - s->nostdlib = 1; - break; - case TCC_OPTION_run: -#ifndef TCC_IS_NATIVE - tcc_error("-run is not available in a cross compiler"); -#endif - run = optarg; - x = TCC_OUTPUT_MEMORY; - goto set_output_type; - case TCC_OPTION_v: - do ++s->verbose; while (*optarg++ == 'v'); - ++noaction; - break; - case TCC_OPTION_f: - if (set_flag(s, options_f, optarg) < 0) - goto unsupported_option; - break; -#ifdef TCC_TARGET_ARM - case TCC_OPTION_mfloat_abi: - /* tcc doesn't support soft float yet */ - if (!strcmp(optarg, "softfp")) { - s->float_abi = ARM_SOFTFP_FLOAT; - tcc_undefine_symbol(s, "__ARM_PCS_VFP"); - } else if (!strcmp(optarg, "hard")) - s->float_abi = ARM_HARD_FLOAT; - else - tcc_error("unsupported float abi '%s'", optarg); - break; -#endif - case TCC_OPTION_m: - if (set_flag(s, options_m, optarg) < 0) { - if (x = atoi(optarg), x != 32 && x != 64) - goto unsupported_option; - if (PTR_SIZE != x/8) - return x; - ++noaction; - } - break; - case TCC_OPTION_W: - if (set_flag(s, options_W, optarg) < 0) - goto unsupported_option; - break; - case TCC_OPTION_w: - s->warn_none = 1; - break; - case TCC_OPTION_rdynamic: - s->rdynamic = 1; - break; - case TCC_OPTION_Wl: - if (linker_arg.size) - --linker_arg.size, cstr_ccat(&linker_arg, ','); - cstr_cat(&linker_arg, optarg, 0); - if (tcc_set_linker(s, linker_arg.data)) - cstr_free(&linker_arg); - break; - case TCC_OPTION_Wp: - r = optarg; - goto reparse; - case TCC_OPTION_E: - x = TCC_OUTPUT_PREPROCESS; - goto set_output_type; - case TCC_OPTION_P: - s->Pflag = atoi(optarg) + 1; - break; - case TCC_OPTION_MD: - s->gen_deps = 1; - break; - case TCC_OPTION_MF: - s->deps_outfile = tcc_strdup(optarg); - break; - case TCC_OPTION_dumpversion: - printf ("%s\n", TCC_VERSION); - exit(0); - break; - case TCC_OPTION_x: - if (*optarg == 'c') - s->filetype = AFF_TYPE_C; - else if (*optarg == 'a') - s->filetype = AFF_TYPE_ASMPP; - else if (*optarg == 'n') - s->filetype = AFF_TYPE_NONE; - else - tcc_warning("unsupported language '%s'", optarg); - break; - case TCC_OPTION_O: - last_o = atoi(optarg); - break; - case TCC_OPTION_print_search_dirs: - x = OPT_PRINT_DIRS; - goto extra_action; - case TCC_OPTION_impdef: - x = OPT_IMPDEF; - goto extra_action; - case TCC_OPTION_ar: - x = OPT_AR; - extra_action: - arg_start = optind - 1; - if (arg_start != noaction) - tcc_error("cannot parse %s here", r); - tool = x; - break; - case TCC_OPTION_traditional: - case TCC_OPTION_pedantic: - case TCC_OPTION_pipe: - case TCC_OPTION_s: - /* ignored */ - break; - default: -unsupported_option: - if (s->warn_unsupported) - tcc_warning("unsupported option '%s'", r); - break; - } - } - if (last_o > 0) - tcc_define_symbol(s, "__OPTIMIZE__", NULL); - if (linker_arg.size) { - r = linker_arg.data; - goto arg_err; - } - *pargc = argc - arg_start; - *pargv = argv + arg_start; - if (tool) - return tool; - if (optind != noaction) - return 0; - if (s->verbose == 2) - return OPT_PRINT_DIRS; - if (s->verbose) - return OPT_V; - return OPT_HELP; -} - -LIBTCCAPI void tcc_set_options(TCCState *s, const char *r) -{ - char **argv = NULL; - int argc = 0; - args_parser_make_argv(r, &argc, &argv); - tcc_parse_args(s, &argc, &argv, 0); - dynarray_reset(&argv, &argc); -} - -PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time) -{ - if (total_time < 1) - total_time = 1; - if (total_bytes < 1) - total_bytes = 1; - fprintf(stderr, "* %d idents, %d lines, %d bytes\n" - "* %0.3f s, %u lines/s, %0.1f MB/s\n", - tok_ident - TOK_IDENT, total_lines, total_bytes, - (double)total_time/1000, - (unsigned)total_lines*1000/total_time, - (double)total_bytes/1000/total_time); -#ifdef MEM_DEBUG - fprintf(stderr, "* %d bytes memory used\n", mem_max_size); -#endif -} diff --git a/tinyc/libtcc.h b/tinyc/libtcc.h deleted file mode 100644 index a1b31e300..000000000 --- a/tinyc/libtcc.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef LIBTCC_H -#define LIBTCC_H - -#ifndef LIBTCCAPI -# define LIBTCCAPI -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct TCCState; - -typedef struct TCCState TCCState; - -/* create a new TCC compilation context */ -LIBTCCAPI TCCState *tcc_new(void); - -/* free a TCC compilation context */ -LIBTCCAPI void tcc_delete(TCCState *s); - -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); - -/* set error/warning display callback */ -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, - void (*error_func)(void *opaque, const char *msg)); - -/* set options as from command line (multiple supported) */ -LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); - -/*****************************/ -/* preprocessor */ - -/* add include path */ -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); - -/* add in system include path */ -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); - -/* define preprocessor symbol 'sym'. Can put optional value */ -LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); - -/* undefine preprocess symbol 'sym' */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); - -/*****************************/ -/* compiling */ - -/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); - -/* compile a string containing a C source. Return -1 if error. */ -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); - -/*****************************/ -/* linking commands */ - -/* set output type. MUST BE CALLED before any compilation */ -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); -#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ -#define TCC_OUTPUT_EXE 2 /* executable file */ -#define TCC_OUTPUT_DLL 3 /* dynamic library */ -#define TCC_OUTPUT_OBJ 4 /* object file */ -#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ - -/* equivalent to -Lpath option */ -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); - -/* add a symbol to the compiled program */ -LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); - -/* output an executable, library or object file. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); - -/* link and run main() function and return its value. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); - -/* do all relocations (needed before using tcc_get_symbol()) */ -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); -/* possible values for 'ptr': - - TCC_RELOCATE_AUTO : Allocate and manage memory internally - - NULL : return required memory size for the step below - - memory address : copy code to memory passed by the caller - returns -1 if error. */ -#define TCC_RELOCATE_AUTO (void*)1 - -/* return symbol value or NULL if not found */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tinyc/stab.def b/tinyc/stab.def deleted file mode 100644 index 48ea231e6..000000000 --- a/tinyc/stab.def +++ /dev/null @@ -1,234 +0,0 @@ -/* Table of DBX symbol codes for the GNU system. - Copyright (C) 1988, 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* This contains contribution from Cygnus Support. */ - -/* Global variable. Only the name is significant. - To find the address, look in the corresponding external symbol. */ -__define_stab (N_GSYM, 0x20, "GSYM") - -/* Function name for BSD Fortran. Only the name is significant. - To find the address, look in the corresponding external symbol. */ -__define_stab (N_FNAME, 0x22, "FNAME") - -/* Function name or text-segment variable for C. Value is its address. - Desc is supposedly starting line number, but GCC doesn't set it - and DBX seems not to miss it. */ -__define_stab (N_FUN, 0x24, "FUN") - -/* Data-segment variable with internal linkage. Value is its address. - "Static Sym". */ -__define_stab (N_STSYM, 0x26, "STSYM") - -/* BSS-segment variable with internal linkage. Value is its address. */ -__define_stab (N_LCSYM, 0x28, "LCSYM") - -/* Name of main routine. Only the name is significant. - This is not used in C. */ -__define_stab (N_MAIN, 0x2a, "MAIN") - -/* Global symbol in Pascal. - Supposedly the value is its line number; I'm skeptical. */ -__define_stab (N_PC, 0x30, "PC") - -/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ -__define_stab (N_NSYMS, 0x32, "NSYMS") - -/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ -__define_stab (N_NOMAP, 0x34, "NOMAP") - -/* New stab from Solaris. I don't know what it means, but it - don't seem to contain useful information. */ -__define_stab (N_OBJ, 0x38, "OBJ") - -/* New stab from Solaris. I don't know what it means, but it - don't seem to contain useful information. Possibly related to the - optimization flags used in this module. */ -__define_stab (N_OPT, 0x3c, "OPT") - -/* Register variable. Value is number of register. */ -__define_stab (N_RSYM, 0x40, "RSYM") - -/* Modula-2 compilation unit. Can someone say what info it contains? */ -__define_stab (N_M2C, 0x42, "M2C") - -/* Line number in text segment. Desc is the line number; - value is corresponding address. */ -__define_stab (N_SLINE, 0x44, "SLINE") - -/* Similar, for data segment. */ -__define_stab (N_DSLINE, 0x46, "DSLINE") - -/* Similar, for bss segment. */ -__define_stab (N_BSLINE, 0x48, "BSLINE") - -/* Sun's source-code browser stabs. ?? Don't know what the fields are. - Supposedly the field is "path to associated .cb file". THIS VALUE - OVERLAPS WITH N_BSLINE! */ -__define_stab (N_BROWS, 0x48, "BROWS") - -/* GNU Modula-2 definition module dependency. Value is the modification time - of the definition file. Other is non-zero if it is imported with the - GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there - are enough empty fields? */ -__define_stab(N_DEFD, 0x4a, "DEFD") - -/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 - and one is for C++. Still,... */ -/* GNU C++ exception variable. Name is variable name. */ -__define_stab (N_EHDECL, 0x50, "EHDECL") -/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ -__define_stab (N_MOD2, 0x50, "MOD2") - -/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if - this entry is immediately followed by a CAUGHT stab saying what exception - was caught. Multiple CAUGHT stabs means that multiple exceptions - can be caught here. If Desc is 0, it means all exceptions are caught - here. */ -__define_stab (N_CATCH, 0x54, "CATCH") - -/* Structure or union element. Value is offset in the structure. */ -__define_stab (N_SSYM, 0x60, "SSYM") - -/* Name of main source file. - Value is starting text address of the compilation. */ -__define_stab (N_SO, 0x64, "SO") - -/* Automatic variable in the stack. Value is offset from frame pointer. - Also used for type descriptions. */ -__define_stab (N_LSYM, 0x80, "LSYM") - -/* Beginning of an include file. Only Sun uses this. - In an object file, only the name is significant. - The Sun linker puts data into some of the other fields. */ -__define_stab (N_BINCL, 0x82, "BINCL") - -/* Name of sub-source file (#include file). - Value is starting text address of the compilation. */ -__define_stab (N_SOL, 0x84, "SOL") - -/* Parameter variable. Value is offset from argument pointer. - (On most machines the argument pointer is the same as the frame pointer. */ -__define_stab (N_PSYM, 0xa0, "PSYM") - -/* End of an include file. No name. - This and N_BINCL act as brackets around the file's output. - In an object file, there is no significant data in this entry. - The Sun linker puts data into some of the fields. */ -__define_stab (N_EINCL, 0xa2, "EINCL") - -/* Alternate entry point. Value is its address. */ -__define_stab (N_ENTRY, 0xa4, "ENTRY") - -/* Beginning of lexical block. - The desc is the nesting level in lexical blocks. - The value is the address of the start of the text for the block. - The variables declared inside the block *precede* the N_LBRAC symbol. */ -__define_stab (N_LBRAC, 0xc0, "LBRAC") - -/* Place holder for deleted include file. Replaces a N_BINCL and everything - up to the corresponding N_EINCL. The Sun linker generates these when - it finds multiple identical copies of the symbols from an include file. - This appears only in output from the Sun linker. */ -__define_stab (N_EXCL, 0xc2, "EXCL") - -/* Modula-2 scope information. Can someone say what info it contains? */ -__define_stab (N_SCOPE, 0xc4, "SCOPE") - -/* End of a lexical block. Desc matches the N_LBRAC's desc. - The value is the address of the end of the text for the block. */ -__define_stab (N_RBRAC, 0xe0, "RBRAC") - -/* Begin named common block. Only the name is significant. */ -__define_stab (N_BCOMM, 0xe2, "BCOMM") - -/* End named common block. Only the name is significant - (and it should match the N_BCOMM). */ -__define_stab (N_ECOMM, 0xe4, "ECOMM") - -/* End common (local name): value is address. - I'm not sure how this is used. */ -__define_stab (N_ECOML, 0xe8, "ECOML") - -/* These STAB's are used on Gould systems for Non-Base register symbols - or something like that. FIXME. I have assigned the values at random - since I don't have a Gould here. Fixups from Gould folk welcome... */ -__define_stab (N_NBTEXT, 0xF0, "NBTEXT") -__define_stab (N_NBDATA, 0xF2, "NBDATA") -__define_stab (N_NBBSS, 0xF4, "NBBSS") -__define_stab (N_NBSTS, 0xF6, "NBSTS") -__define_stab (N_NBLCS, 0xF8, "NBLCS") - -/* Second symbol entry containing a length-value for the preceding entry. - The value is the length. */ -__define_stab (N_LENG, 0xfe, "LENG") - -/* The above information, in matrix format. - - STAB MATRIX - _________________________________________________ - | 00 - 1F are not dbx stab symbols | - | In most cases, the low bit is the EXTernal bit| - - | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | - | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | - - | 08 BSS | 0A INDR | 0C FN_SEQ | 0E | - | 09 |EXT | 0B | 0D | 0F | - - | 10 | 12 COMM | 14 SETA | 16 SETT | - | 11 | 13 | 15 | 17 | - - | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| - | 19 | 1B | 1D | 1F FN | - - |_______________________________________________| - | Debug entries with bit 01 set are unused. | - | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | - | 28 LCSYM | 2A MAIN | 2C | 2E | - | 30 PC | 32 NSYMS | 34 NOMAP | 36 | - | 38 OBJ | 3A | 3C OPT | 3E | - | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | - | 48 BSLINE*| 4A DEFD | 4C | 4E | - | 50 EHDECL*| 52 | 54 CATCH | 56 | - | 58 | 5A | 5C | 5E | - | 60 SSYM | 62 | 64 SO | 66 | - | 68 | 6A | 6C | 6E | - | 70 | 72 | 74 | 76 | - | 78 | 7A | 7C | 7E | - | 80 LSYM | 82 BINCL | 84 SOL | 86 | - | 88 | 8A | 8C | 8E | - | 90 | 92 | 94 | 96 | - | 98 | 9A | 9C | 9E | - | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | - | A8 | AA | AC | AE | - | B0 | B2 | B4 | B6 | - | B8 | BA | BC | BE | - | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | - | C8 | CA | CC | CE | - | D0 | D2 | D4 | D6 | - | D8 | DA | DC | DE | - | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | - | E8 ECOML | EA | EC | EE | - | F0 | F2 | F4 | F6 | - | F8 | FA | FC | FE LENG | - +-----------------------------------------------+ - * 50 EHDECL is also MOD2. - * 48 BSLINE is also BROWS. - */ diff --git a/tinyc/stab.h b/tinyc/stab.h deleted file mode 100644 index 80bd594a3..000000000 --- a/tinyc/stab.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __GNU_STAB__ - -/* Indicate the GNU stab.h is in use. */ - -#define __GNU_STAB__ - -#define __define_stab(NAME, CODE, STRING) NAME=CODE, - -enum __stab_debug_code -{ -#include "stab.def" -LAST_UNUSED_STAB_CODE -}; - -#undef __define_stab - -#endif /* __GNU_STAB_ */ diff --git a/tinyc/tcc-doc.texi b/tinyc/tcc-doc.texi deleted file mode 100644 index 5e718a2c5..000000000 --- a/tinyc/tcc-doc.texi +++ /dev/null @@ -1,1326 +0,0 @@ -\input texinfo @c -*- texinfo -*- -@c %**start of header -@setfilename tcc-doc.info -@settitle Tiny C Compiler Reference Documentation -@dircategory Software development -@direntry -* TCC: (tcc-doc). The Tiny C Compiler. -@end direntry -@c %**end of header - -@include config.texi - -@iftex -@titlepage -@afourpaper -@sp 7 -@center @titlefont{Tiny C Compiler Reference Documentation} -@sp 3 -@end titlepage -@headings double -@end iftex - -@contents - -@node Top, Introduction, (dir), (dir) -@top Tiny C Compiler Reference Documentation - -This manual documents version @value{VERSION} of the Tiny C Compiler. - -@menu -* Introduction:: Introduction to tcc. -* Invoke:: Invocation of tcc (command line, options). -* Clang:: ANSI C and extensions. -* asm:: Assembler syntax. -* linker:: Output file generation and supported targets. -* Bounds:: Automatic bounds-checking of C code. -* Libtcc:: The libtcc library. -* devel:: Guide for Developers. -@end menu - - -@node Introduction -@chapter Introduction - -TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C -compilers, it is meant to be self-relying: you do not need an -external assembler or linker because TCC does that for you. - -TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may -not be necessary. - -TCC not only supports ANSI C, but also most of the new ISO C99 -standard and many GNUC extensions including inline assembly. - -TCC can also be used to make @emph{C scripts}, i.e. pieces of C source -that you run as a Perl or Python script. Compilation is so fast that -your script will be as fast as if it was an executable. - -TCC can also automatically generate memory and bound checks -(@pxref{Bounds}) while allowing all C pointers operations. TCC can do -these checks even if non patched libraries are used. - -With @code{libtcc}, you can use TCC as a backend for dynamic code -generation (@pxref{Libtcc}). - -TCC mainly supports the i386 target on Linux and Windows. There are alpha -ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets -(@code{c67-tcc}). More information about the ARM port is available at -@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}. - -For usage on Windows, see also @url{tcc-win32.txt}. - -@node Invoke -@chapter Command line invocation - -@section Quick start - -@example -@c man begin SYNOPSIS -usage: tcc [options] [@var{infile1} @var{infile2}@dots{}] [@option{-run} @var{infile} @var{args}@dots{}] -@c man end -@end example - -@noindent -@c man begin DESCRIPTION -TCC options are a very much like gcc options. The main difference is that TCC -can also execute directly the resulting program and give it runtime -arguments. - -Here are some examples to understand the logic: - -@table @code -@item @samp{tcc -run a.c} -Compile @file{a.c} and execute it directly - -@item @samp{tcc -run a.c arg1} -Compile a.c and execute it directly. arg1 is given as first argument to -the @code{main()} of a.c. - -@item @samp{tcc a.c -run b.c arg1} -Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given -as first argument to the @code{main()} of the resulting program. -@ignore -Because multiple C files are specified, @option{--} are necessary to clearly -separate the program arguments from the TCC options. -@end ignore - -@item @samp{tcc -o myprog a.c b.c} -Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}. - -@item @samp{tcc -o myprog a.o b.o} -link @file{a.o} and @file{b.o} together and generate the executable @file{myprog}. - -@item @samp{tcc -c a.c} -Compile @file{a.c} and generate object file @file{a.o}. - -@item @samp{tcc -c asmfile.S} -Preprocess with C preprocess and assemble @file{asmfile.S} and generate -object file @file{asmfile.o}. - -@item @samp{tcc -c asmfile.s} -Assemble (but not preprocess) @file{asmfile.s} and generate object file -@file{asmfile.o}. - -@item @samp{tcc -r -o ab.o a.c b.c} -Compile @file{a.c} and @file{b.c}, link them together and generate the object file @file{ab.o}. - -@end table - -Scripting: - -TCC can be invoked from @emph{scripts}, just as shell scripts. You just -need to add @code{#!/usr/local/bin/tcc -run} at the start of your C source: - -@example -#!/usr/local/bin/tcc -run -#include - -int main() -@{ - printf("Hello World\n"); - return 0; -@} -@end example - -TCC can read C source code from @emph{standard input} when @option{-} is used in -place of @option{infile}. Example: - -@example -echo 'main()@{puts("hello");@}' | tcc -run - -@end example -@c man end - -@section Option summary - -General Options: - -@c man begin OPTIONS -@table @option -@item -c -Generate an object file. - -@item -o outfile -Put object file, executable, or dll into output file @file{outfile}. - -@item -run source [args...] -Compile file @var{source} and run it with the command line arguments -@var{args}. In order to be able to give more than one argument to a -script, several TCC options can be given @emph{after} the -@option{-run} option, separated by spaces: -@example -tcc "-run -L/usr/X11R6/lib -lX11" ex4.c -@end example -In a script, it gives the following header: -@example -#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 -@end example - -@item -v -Display TCC version. - -@item -vv -Show included files. As sole argument, print search dirs. -vvv shows tries too. - -@item -bench -Display compilation statistics. - -@end table - -Preprocessor options: - -@table @option -@item -Idir -Specify an additional include path. Include paths are searched in the -order they are specified. - -System include paths are always searched after. The default system -include paths are: @file{/usr/local/include}, @file{/usr/include} -and @file{PREFIX/lib/tcc/include}. (@file{PREFIX} is usually -@file{/usr} or @file{/usr/local}). - -@item -Dsym[=val] -Define preprocessor symbol @samp{sym} to -val. If val is not present, its value is @samp{1}. Function-like macros can -also be defined: @option{-DF(a)=a+1} - -@item -Usym -Undefine preprocessor symbol @samp{sym}. - -@item -E -Preprocess only, to stdout or file (with -o). - -@end table - -Compilation flags: - -Note: each of the following options has a negative form beginning with -@option{-fno-}. - -@table @option -@item -funsigned-char -Let the @code{char} type be unsigned. - -@item -fsigned-char -Let the @code{char} type be signed. - -@item -fno-common -Do not generate common symbols for uninitialized data. - -@item -fleading-underscore -Add a leading underscore at the beginning of each C symbol. - -@item -fms-extensions -Allow a MS C compiler extensions to the language. Currently this -assumes a nested named structure declaration without an identifier -behaves like an unnamed one. - -@item -fdollars-in-identifiers -Allow dollar signs in identifiers - -@end table - -Warning options: - -@table @option -@item -w -Disable all warnings. - -@end table - -Note: each of the following warning options has a negative form beginning with -@option{-Wno-}. - -@table @option -@item -Wimplicit-function-declaration -Warn about implicit function declaration. - -@item -Wunsupported -Warn about unsupported GCC features that are ignored by TCC. - -@item -Wwrite-strings -Make string constants be of type @code{const char *} instead of @code{char -*}. - -@item -Werror -Abort compilation if warnings are issued. - -@item -Wall -Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and -@option{-Wwrite-strings}. - -@end table - -Linker options: - -@table @option -@item -Ldir -Specify an additional static library path for the @option{-l} option. The -default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}. - -@item -lxxx -Link your program with dynamic library libxxx.so or static library -libxxx.a. The library is searched in the paths specified by the -@option{-L} option and @env{LIBRARY_PATH} variable. - -@item -Bdir -Set the path where the tcc internal libraries (and include files) can be -found (default is @file{PREFIX/lib/tcc}). - -@item -shared -Generate a shared library instead of an executable. - -@item -soname name -set name for shared library to be used at runtime - -@item -static -Generate a statically linked executable (default is a shared linked -executable). - -@item -rdynamic -Export global symbols to the dynamic linker. It is useful when a library -opened with @code{dlopen()} needs to access executable symbols. - -@item -r -Generate an object file combining all input files. - -@item -Wl,-rpath=path -Put custom search path for dynamic libraries into executable. - -@item -Wl,--enable-new-dtags -When putting a custom search path for dynamic libraries into the executable, -create the new ELF dynamic tag DT_RUNPATH instead of the old legacy DT_RPATH. - -@item -Wl,--oformat=fmt -Use @var{fmt} as output format. The supported output formats are: -@table @code -@item elf32-i386 -ELF output format (default) -@item binary -Binary image (only for executable output) -@item coff -COFF output format (only for executable output for TMS320C67xx target) -@end table - -@item -Wl,-subsystem=console/gui/wince/... -Set type for PE (Windows) executables. - -@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#] -Modify executable layout. - -@item -Wl,-Bsymbolic -Set DT_SYMBOLIC tag. - -@item -Wl,-(no-)whole-archive -Turn on/off linking of all objects in archives. - -@end table - -Debugger options: - -@table @option -@item -g -Generate run time debug information so that you get clear run time -error messages: @code{ test.c:68: in function 'test5()': dereferencing -invalid pointer} instead of the laconic @code{Segmentation -fault}. - -@item -b -Generate additional support code to check -memory allocations and array/pointer bounds. @option{-g} is implied. Note -that the generated code is slower and bigger in this case. - -Note: @option{-b} is only available on i386 when using libtcc for the moment. - -@item -bt N -Display N callers in stack traces. This is useful with @option{-g} or -@option{-b}. - -@end table - -Misc options: - -@table @option -@item -MD -Generate makefile fragment with dependencies. - -@item -MF depfile -Use @file{depfile} as output for -MD. - -@item -print-search-dirs -Print the configured installation directory and a list of library -and include directories tcc will search. - -@item -dumpversion -Print version. - -@end table - -Target specific options: - -@table @option -@item -mms-bitfields -Use an algorithm for bitfield alignment consistent with MSVC. Default is -gcc's algorithm. - -@item -mfloat-abi (ARM only) -Select the float ABI. Possible values: @code{softfp} and @code{hard} - -@item -mno-sse -Do not use sse registers on x86_64 - -@item -m32, -m64 -Pass command line to the i386/x86_64 cross compiler. - -@end table - -Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are -ignored. -@c man end - -@c man begin ENVIRONMENT -Environment variables that affect how tcc operates. - -@table @option - -@item CPATH -@item C_INCLUDE_PATH -A colon-separated list of directories searched for include files, -directories given with @option{-I} are searched first. - -@item LIBRARY_PATH -A colon-separated list of directories searched for libraries for the -@option{-l} option, directories given with @option{-L} are searched first. - -@end table - -@c man end - -@ignore - -@setfilename tcc -@settitle Tiny C Compiler - -@c man begin SEEALSO -cpp(1), -gcc(1) -@c man end - -@c man begin AUTHOR -Fabrice Bellard -@c man end - -@end ignore - -@node Clang -@chapter C language support - -@section ANSI C - -TCC implements all the ANSI C standard, including structure bit fields -and floating point numbers (@code{long double}, @code{double}, and -@code{float} fully supported). - -@section ISOC99 extensions - -TCC implements many features of the new C standard: ISO C99. Currently -missing items are: complex and imaginary numbers. - -Currently implemented ISOC99 features: - -@itemize - -@item variable length arrays. - -@item 64 bit @code{long long} types are fully supported. - -@item The boolean type @code{_Bool} is supported. - -@item @code{__func__} is a string variable containing the current -function name. - -@item Variadic macros: @code{__VA_ARGS__} can be used for - function-like macros: -@example - #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__) -@end example - -@noindent -@code{dprintf} can then be used with a variable number of parameters. - -@item Declarations can appear anywhere in a block (as in C++). - -@item Array and struct/union elements can be initialized in any order by - using designators: -@example - struct @{ int x, y; @} st[10] = @{ [0].x = 1, [0].y = 2 @}; - - int tab[10] = @{ 1, 2, [5] = 5, [9] = 9@}; -@end example - -@item Compound initializers are supported: -@example - int *p = (int [])@{ 1, 2, 3 @}; -@end example -to initialize a pointer pointing to an initialized array. The same -works for structures and strings. - -@item Hexadecimal floating point constants are supported: -@example - double d = 0x1234p10; -@end example - -@noindent -is the same as writing -@example - double d = 4771840.0; -@end example - -@item @code{inline} keyword is ignored. - -@item @code{restrict} keyword is ignored. -@end itemize - -@section GNU C extensions - -TCC implements some GNU C extensions: - -@itemize - -@item array designators can be used without '=': -@example - int a[10] = @{ [0] 1, [5] 2, 3, 4 @}; -@end example - -@item Structure field designators can be a label: -@example - struct @{ int x, y; @} st = @{ x: 1, y: 1@}; -@end example -instead of -@example - struct @{ int x, y; @} st = @{ .x = 1, .y = 1@}; -@end example - -@item @code{\e} is ASCII character 27. - -@item case ranges : ranges can be used in @code{case}s: -@example - switch(a) @{ - case 1 @dots{} 9: - printf("range 1 to 9\n"); - break; - default: - printf("unexpected\n"); - break; - @} -@end example - -@cindex aligned attribute -@cindex packed attribute -@cindex section attribute -@cindex unused attribute -@cindex cdecl attribute -@cindex stdcall attribute -@cindex regparm attribute -@cindex dllexport attribute - -@item The keyword @code{__attribute__} is handled to specify variable or -function attributes. The following attributes are supported: - @itemize - - @item @code{aligned(n)}: align a variable or a structure field to n bytes -(must be a power of two). - - @item @code{packed}: force alignment of a variable or a structure field to - 1. - - @item @code{section(name)}: generate function or data in assembly section -name (name is a string containing the section name) instead of the default -section. - - @item @code{unused}: specify that the variable or the function is unused. - - @item @code{cdecl}: use standard C calling convention (default). - - @item @code{stdcall}: use Pascal-like calling convention. - - @item @code{regparm(n)}: use fast i386 calling convention. @var{n} must be -between 1 and 3. The first @var{n} function parameters are respectively put in -registers @code{%eax}, @code{%edx} and @code{%ecx}. - - @item @code{dllexport}: export function from dll/executable (win32 only) - - @end itemize - -Here are some examples: -@example - int a __attribute__ ((aligned(8), section(".mysection"))); -@end example - -@noindent -align variable @code{a} to 8 bytes and put it in section @code{.mysection}. - -@example - int my_add(int a, int b) __attribute__ ((section(".mycodesection"))) - @{ - return a + b; - @} -@end example - -@noindent -generate function @code{my_add} in section @code{.mycodesection}. - -@item GNU style variadic macros: -@example - #define dprintf(fmt, args@dots{}) printf(fmt, ## args) - - dprintf("no arg\n"); - dprintf("one arg %d\n", 1); -@end example - -@item @code{__FUNCTION__} is interpreted as C99 @code{__func__} -(so it has not exactly the same semantics as string literal GNUC -where it is a string literal). - -@item The @code{__alignof__} keyword can be used as @code{sizeof} -to get the alignment of a type or an expression. - -@item The @code{typeof(x)} returns the type of @code{x}. -@code{x} is an expression or a type. - -@item Computed gotos: @code{&&label} returns a pointer of type -@code{void *} on the goto label @code{label}. @code{goto *expr} can be -used to jump on the pointer resulting from @code{expr}. - -@item Inline assembly with asm instruction: -@cindex inline assembly -@cindex assembly, inline -@cindex __asm__ -@example -static inline void * my_memcpy(void * to, const void * from, size_t n) -@{ -int d0, d1, d2; -__asm__ __volatile__( - "rep ; movsl\n\t" - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); -return (to); -@} -@end example - -@noindent -@cindex gas -TCC includes its own x86 inline assembler with a @code{gas}-like (GNU -assembler) syntax. No intermediate files are generated. GCC 3.x named -operands are supported. - -@item @code{__builtin_types_compatible_p()} and @code{__builtin_constant_p()} -are supported. - -@item @code{#pragma pack} is supported for win32 compatibility. - -@end itemize - -@section TinyCC extensions - -@itemize - -@item @code{__TINYC__} is a predefined macro to indicate that you use TCC. - -@item @code{#!} at the start of a line is ignored to allow scripting. - -@item Binary digits can be entered (@code{0b101} instead of -@code{5}). - -@item @code{__BOUNDS_CHECKING_ON} is defined if bound checking is activated. - -@end itemize - -@node asm -@chapter TinyCC Assembler - -Since version 0.9.16, TinyCC integrates its own assembler. TinyCC -assembler supports a gas-like syntax (GNU assembler). You can -deactivate assembler support if you want a smaller TinyCC executable -(the C compiler does not rely on the assembler). - -TinyCC Assembler is used to handle files with @file{.S} (C -preprocessed assembler) and @file{.s} extensions. It is also used to -handle the GNU inline assembler with the @code{asm} keyword. - -@section Syntax - -TinyCC Assembler supports most of the gas syntax. The tokens are the -same as C. - -@itemize - -@item C and C++ comments are supported. - -@item Identifiers are the same as C, so you cannot use '.' or '$'. - -@item Only 32 bit integer numbers are supported. - -@end itemize - -@section Expressions - -@itemize - -@item Integers in decimal, octal and hexa are supported. - -@item Unary operators: +, -, ~. - -@item Binary operators in decreasing priority order: - -@enumerate -@item *, /, % -@item &, |, ^ -@item +, - -@end enumerate - -@item A value is either an absolute number or a label plus an offset. -All operators accept absolute values except '+' and '-'. '+' or '-' can be -used to add an offset to a label. '-' supports two labels only if they -are the same or if they are both defined and in the same section. - -@end itemize - -@section Labels - -@itemize - -@item All labels are considered as local, except undefined ones. - -@item Numeric labels can be used as local @code{gas}-like labels. -They can be defined several times in the same source. Use 'b' -(backward) or 'f' (forward) as suffix to reference them: - -@example - 1: - jmp 1b /* jump to '1' label before */ - jmp 1f /* jump to '1' label after */ - 1: -@end example - -@end itemize - -@section Directives -@cindex assembler directives -@cindex directives, assembler -@cindex align directive -@cindex skip directive -@cindex space directive -@cindex byte directive -@cindex word directive -@cindex short directive -@cindex int directive -@cindex long directive -@cindex quad directive -@cindex globl directive -@cindex global directive -@cindex section directive -@cindex text directive -@cindex data directive -@cindex bss directive -@cindex fill directive -@cindex org directive -@cindex previous directive -@cindex string directive -@cindex asciz directive -@cindex ascii directive - -All directives are preceded by a '.'. The following directives are -supported: - -@itemize -@item .align n[,value] -@item .skip n[,value] -@item .space n[,value] -@item .byte value1[,...] -@item .word value1[,...] -@item .short value1[,...] -@item .int value1[,...] -@item .long value1[,...] -@item .quad immediate_value1[,...] -@item .globl symbol -@item .global symbol -@item .section section -@item .text -@item .data -@item .bss -@item .fill repeat[,size[,value]] -@item .org n -@item .previous -@item .string string[,...] -@item .asciz string[,...] -@item .ascii string[,...] -@end itemize - -@section X86 Assembler -@cindex assembler - -All X86 opcodes are supported. Only ATT syntax is supported (source -then destination operand order). If no size suffix is given, TinyCC -tries to guess it from the operand sizes. - -Currently, MMX opcodes are supported but not SSE ones. - -@node linker -@chapter TinyCC Linker -@cindex linker - -@section ELF file generation -@cindex ELF - -TCC can directly output relocatable ELF files (object files), -executable ELF files and dynamic ELF libraries without relying on an -external linker. - -Dynamic ELF libraries can be output but the C compiler does not generate -position independent code (PIC). It means that the dynamic library -code generated by TCC cannot be factorized among processes yet. - -TCC linker eliminates unreferenced object code in libraries. A single pass is -done on the object and library list, so the order in which object files and -libraries are specified is important (same constraint as GNU ld). No grouping -options (@option{--start-group} and @option{--end-group}) are supported. - -@section ELF file loader - -TCC can load ELF object files, archives (.a files) and dynamic -libraries (.so). - -@section PE-i386 file generation -@cindex PE-i386 - -TCC for Windows supports the native Win32 executable file format (PE-i386). It -generates EXE files (console and gui) and DLL files. - -For usage on Windows, see also tcc-win32.txt. - -@section GNU Linker Scripts -@cindex scripts, linker -@cindex linker scripts -@cindex GROUP, linker command -@cindex FILE, linker command -@cindex OUTPUT_FORMAT, linker command -@cindex TARGET, linker command - -Because on many Linux systems some dynamic libraries (such as -@file{/usr/lib/libc.so}) are in fact GNU ld link scripts (horrible!), -the TCC linker also supports a subset of GNU ld scripts. - -The @code{GROUP} and @code{FILE} commands are supported. @code{OUTPUT_FORMAT} -and @code{TARGET} are ignored. - -Example from @file{/usr/lib/libc.so}: -@example -/* GNU ld script - Use the shared library, but some functions are only in - the static library, so try that secondarily. */ -GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a ) -@end example - -@node Bounds -@chapter TinyCC Memory and Bound checks -@cindex bound checks -@cindex memory checks - -This feature is activated with the @option{-b} (@pxref{Invoke}). - -Note that pointer size is @emph{unchanged} and that code generated -with bound checks is @emph{fully compatible} with unchecked -code. When a pointer comes from unchecked code, it is assumed to be -valid. Even very obscure C code with casts should work correctly. - -For more information about the ideas behind this method, see -@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}. - -Here are some examples of caught errors: - -@table @asis - -@item Invalid range with standard string function: -@example -@{ - char tab[10]; - memset(tab, 0, 11); -@} -@end example - -@item Out of bounds-error in global or local arrays: -@example -@{ - int tab[10]; - for(i=0;i<11;i++) @{ - sum += tab[i]; - @} -@} -@end example - -@item Out of bounds-error in malloc'ed data: -@example -@{ - int *tab; - tab = malloc(20 * sizeof(int)); - for(i=0;i<21;i++) @{ - sum += tab4[i]; - @} - free(tab); -@} -@end example - -@item Access of freed memory: -@example -@{ - int *tab; - tab = malloc(20 * sizeof(int)); - free(tab); - for(i=0;i<20;i++) @{ - sum += tab4[i]; - @} -@} -@end example - -@item Double free: -@example -@{ - int *tab; - tab = malloc(20 * sizeof(int)); - free(tab); - free(tab); -@} -@end example - -@end table - -@node Libtcc -@chapter The @code{libtcc} library - -The @code{libtcc} library enables you to use TCC as a backend for -dynamic code generation. - -Read the @file{libtcc.h} to have an overview of the API. Read -@file{libtcc_test.c} to have a very simple example. - -The idea consists in giving a C string containing the program you want -to compile directly to @code{libtcc}. Then you can access to any global -symbol (function or variable) defined. - -@node devel -@chapter Developer's guide - -This chapter gives some hints to understand how TCC works. You can skip -it if you do not intend to modify the TCC code. - -@section File reading - -The @code{BufferedFile} structure contains the context needed to read a -file, including the current line number. @code{tcc_open()} opens a new -file and @code{tcc_close()} closes it. @code{inp()} returns the next -character. - -@section Lexer - -@code{next()} reads the next token in the current -file. @code{next_nomacro()} reads the next token without macro -expansion. - -@code{tok} contains the current token (see @code{TOK_xxx}) -constants. Identifiers and keywords are also keywords. @code{tokc} -contains additional infos about the token (for example a constant value -if number or string token). - -@section Parser - -The parser is hardcoded (yacc is not necessary). It does only one pass, -except: - -@itemize - -@item For initialized arrays with unknown size, a first pass -is done to count the number of elements. - -@item For architectures where arguments are evaluated in -reverse order, a first pass is done to reverse the argument order. - -@end itemize - -@section Types - -The types are stored in a single 'int' variable. It was chosen in the -first stages of development when tcc was much simpler. Now, it may not -be the best solution. - -@example -#define VT_INT 0 /* integer type */ -#define VT_BYTE 1 /* signed byte type */ -#define VT_SHORT 2 /* short type */ -#define VT_VOID 3 /* void type */ -#define VT_PTR 4 /* pointer */ -#define VT_ENUM 5 /* enum definition */ -#define VT_FUNC 6 /* function type */ -#define VT_STRUCT 7 /* struct/union definition */ -#define VT_FLOAT 8 /* IEEE float */ -#define VT_DOUBLE 9 /* IEEE double */ -#define VT_LDOUBLE 10 /* IEEE long double */ -#define VT_BOOL 11 /* ISOC99 boolean type */ -#define VT_LLONG 12 /* 64 bit integer */ -#define VT_LONG 13 /* long integer (NEVER USED as type, only - during parsing) */ -#define VT_BTYPE 0x000f /* mask for basic type */ -#define VT_UNSIGNED 0x0010 /* unsigned type */ -#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ -#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_BITFIELD 0x0040 /* bitfield modifier */ -#define VT_CONSTANT 0x0800 /* const modifier */ -#define VT_VOLATILE 0x1000 /* volatile modifier */ -#define VT_DEFSIGN 0x2000 /* signed type */ - -#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */ -@end example - -When a reference to another type is needed (for pointers, functions and -structures), the @code{32 - VT_STRUCT_SHIFT} high order bits are used to -store an identifier reference. - -The @code{VT_UNSIGNED} flag can be set for chars, shorts, ints and long -longs. - -Arrays are considered as pointers @code{VT_PTR} with the flag -@code{VT_ARRAY} set. Variable length arrays are considered as special -arrays and have flag @code{VT_VLA} set instead of @code{VT_ARRAY}. - -The @code{VT_BITFIELD} flag can be set for chars, shorts, ints and long -longs. If it is set, then the bitfield position is stored from bits -VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored -from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11. - -@code{VT_LONG} is never used except during parsing. - -During parsing, the storage of an object is also stored in the type -integer: - -@example -#define VT_EXTERN 0x00000080 /* extern definition */ -#define VT_STATIC 0x00000100 /* static variable */ -#define VT_TYPEDEF 0x00000200 /* typedef definition */ -#define VT_INLINE 0x00000400 /* inline definition */ -#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */ -#define VT_EXPORT 0x00008000 /* win32: data exported from dll */ -#define VT_WEAK 0x00010000 /* win32: data exported from dll */ -@end example - -@section Symbols - -All symbols are stored in hashed symbol stacks. Each symbol stack -contains @code{Sym} structures. - -@code{Sym.v} contains the symbol name (remember -an identifier is also a token, so a string is never necessary to store -it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually -the register in which the corresponding variable is stored. @code{Sym.c} is -usually a constant associated to the symbol like its address for normal -symbols, and the number of entries for symbols representing arrays. -Variable length array types use @code{Sym.c} as a location on the stack -which holds the runtime sizeof for the type. - -Four main symbol stacks are defined: - -@table @code - -@item define_stack -for the macros (@code{#define}s). - -@item global_stack -for the global variables, functions and types. - -@item local_stack -for the local variables, functions and types. - -@item global_label_stack -for the local labels (for @code{goto}). - -@item label_stack -for GCC block local labels (see the @code{__label__} keyword). - -@end table - -@code{sym_push()} is used to add a new symbol in the local symbol -stack. If no local symbol stack is active, it is added in the global -symbol stack. - -@code{sym_pop(st,b)} pops symbols from the symbol stack @var{st} until -the symbol @var{b} is on the top of stack. If @var{b} is NULL, the stack -is emptied. - -@code{sym_find(v)} return the symbol associated to the identifier -@var{v}. The local stack is searched first from top to bottom, then the -global stack. - -@section Sections - -The generated code and data are written in sections. The structure -@code{Section} contains all the necessary information for a given -section. @code{new_section()} creates a new section. ELF file semantics -is assumed for each section. - -The following sections are predefined: - -@table @code - -@item text_section -is the section containing the generated code. @var{ind} contains the -current position in the code section. - -@item data_section -contains initialized data - -@item bss_section -contains uninitialized data - -@item bounds_section -@itemx lbounds_section -are used when bound checking is activated - -@item stab_section -@itemx stabstr_section -are used when debugging is active to store debug information - -@item symtab_section -@itemx strtab_section -contain the exported symbols (currently only used for debugging). - -@end table - -@section Code generation -@cindex code generation - -@subsection Introduction - -The TCC code generator directly generates linked binary code in one -pass. It is rather unusual these days (see gcc for example which -generates text assembly), but it can be very fast and surprisingly -little complicated. - -The TCC code generator is register based. Optimization is only done at -the expression level. No intermediate representation of expression is -kept except the current values stored in the @emph{value stack}. - -On x86, three temporary registers are used. When more registers are -needed, one register is spilled into a new temporary variable on the stack. - -@subsection The value stack -@cindex value stack, introduction - -When an expression is parsed, its value is pushed on the value stack -(@var{vstack}). The top of the value stack is @var{vtop}. Each value -stack entry is the structure @code{SValue}. - -@code{SValue.t} is the type. @code{SValue.r} indicates how the value is -currently stored in the generated code. It is usually a CPU register -index (@code{REG_xxx} constants), but additional values and flags are -defined: - -@example -#define VT_CONST 0x00f0 -#define VT_LLOCAL 0x00f1 -#define VT_LOCAL 0x00f2 -#define VT_CMP 0x00f3 -#define VT_JMP 0x00f4 -#define VT_JMPI 0x00f5 -#define VT_LVAL 0x0100 -#define VT_SYM 0x0200 -#define VT_MUSTCAST 0x0400 -#define VT_MUSTBOUND 0x0800 -#define VT_BOUNDED 0x8000 -#define VT_LVAL_BYTE 0x1000 -#define VT_LVAL_SHORT 0x2000 -#define VT_LVAL_UNSIGNED 0x4000 -#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) -@end example - -@table @code - -@item VT_CONST -indicates that the value is a constant. It is stored in the union -@code{SValue.c}, depending on its type. - -@item VT_LOCAL -indicates a local variable pointer at offset @code{SValue.c.i} in the -stack. - -@item VT_CMP -indicates that the value is actually stored in the CPU flags (i.e. the -value is the consequence of a test). The value is either 0 or 1. The -actual CPU flags used is indicated in @code{SValue.c.i}. - -If any code is generated which destroys the CPU flags, this value MUST be -put in a normal register. - -@item VT_JMP -@itemx VT_JMPI -indicates that the value is the consequence of a conditional jump. For VT_JMP, -it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. - -These values are used to compile the @code{||} and @code{&&} logical -operators. - -If any code is generated, this value MUST be put in a normal -register. Otherwise, the generated code won't be executed if the jump is -taken. - -@item VT_LVAL -is a flag indicating that the value is actually an lvalue (left value of -an assignment). It means that the value stored is actually a pointer to -the wanted value. - -Understanding the use @code{VT_LVAL} is very important if you want to -understand how TCC works. - -@item VT_LVAL_BYTE -@itemx VT_LVAL_SHORT -@itemx VT_LVAL_UNSIGNED -if the lvalue has an integer type, then these flags give its real -type. The type alone is not enough in case of cast optimisations. - -@item VT_LLOCAL -is a saved lvalue on the stack. @code{VT_LVAL} must also be set with -@code{VT_LLOCAL}. @code{VT_LLOCAL} can arise when a @code{VT_LVAL} in -a register has to be saved to the stack, or it can come from an -architecture-specific calling convention. - -@item VT_MUSTCAST -indicates that a cast to the value type must be performed if the value -is used (lazy casting). - -@item VT_SYM -indicates that the symbol @code{SValue.sym} must be added to the constant. - -@item VT_MUSTBOUND -@itemx VT_BOUNDED -are only used for optional bound checking. - -@end table - -@subsection Manipulating the value stack -@cindex value stack - -@code{vsetc()} and @code{vset()} pushes a new value on the value -stack. If the previous @var{vtop} was stored in a very unsafe place(for -example in the CPU flags), then some code is generated to put the -previous @var{vtop} in a safe storage. - -@code{vpop()} pops @var{vtop}. In some cases, it also generates cleanup -code (for example if stacked floating point registers are used as on -x86). - -The @code{gv(rc)} function generates code to evaluate @var{vtop} (the -top value of the stack) into registers. @var{rc} selects in which -register class the value should be put. @code{gv()} is the @emph{most -important function} of the code generator. - -@code{gv2()} is the same as @code{gv()} but for the top two stack -entries. - -@subsection CPU dependent code generation -@cindex CPU dependent -See the @file{i386-gen.c} file to have an example. - -@table @code - -@item load() -must generate the code needed to load a stack value into a register. - -@item store() -must generate the code needed to store a register into a stack value -lvalue. - -@item gfunc_start() -@itemx gfunc_param() -@itemx gfunc_call() -should generate a function call - -@item gfunc_prolog() -@itemx gfunc_epilog() -should generate a function prolog/epilog. - -@item gen_opi(op) -must generate the binary integer operation @var{op} on the two top -entries of the stack which are guaranteed to contain integer types. - -The result value should be put on the stack. - -@item gen_opf(op) -same as @code{gen_opi()} for floating point operations. The two top -entries of the stack are guaranteed to contain floating point values of -same types. - -@item gen_cvt_itof() -integer to floating point conversion. - -@item gen_cvt_ftoi() -floating point to integer conversion. - -@item gen_cvt_ftof() -floating point to floating point of different size conversion. - -@item gen_bounded_ptr_add() -@item gen_bounded_ptr_deref() -are only used for bounds checking. - -@end table - -@section Optimizations done -@cindex optimizations -@cindex constant propagation -@cindex strength reduction -@cindex comparison operators -@cindex caching processor flags -@cindex flags, caching -@cindex jump optimization -Constant propagation is done for all operations. Multiplications and -divisions are optimized to shifts when appropriate. Comparison -operators are optimized by maintaining a special cache for the -processor flags. &&, || and ! are optimized by maintaining a special -'jump target' value. No other jump optimization is currently performed -because it would require to store the code in a more abstract fashion. - -@unnumbered Concept Index -@printindex cp - -@bye - -@c Local variables: -@c fill-column: 78 -@c texinfo-column-for-description: 32 -@c End: diff --git a/tinyc/tcc.c b/tinyc/tcc.c deleted file mode 100644 index c347a06ea..000000000 --- a/tinyc/tcc.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" -#if ONE_SOURCE -# include "libtcc.c" -#endif -#include "tcctools.c" - -static const char help[] = - "Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n" - "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" - " tcc [options...] -run infile [arguments...]\n" - "General options:\n" - " -c compile only - generate an object file\n" - " -o outfile set output filename\n" - " -run run compiled source\n" - " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n" - " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" - " -w disable all warnings\n" - " -v -vv show version, show search paths or loaded files\n" - " -h -hh show this, show more help\n" - " -bench show compilation statistics\n" - " - use stdin pipe as infile\n" - " @listfile read arguments from listfile\n" - "Preprocessor options:\n" - " -Idir add include path 'dir'\n" - " -Dsym[=val] define 'sym' with value 'val'\n" - " -Usym undefine 'sym'\n" - " -E preprocess only\n" - "Linker options:\n" - " -Ldir add library path 'dir'\n" - " -llib link with dynamic or static library 'lib'\n" - " -r generate (relocatable) object file\n" - " -shared generate a shared library/dll\n" - " -rdynamic export all global symbols to dynamic linker\n" - " -soname set name for shared library to be used at runtime\n" - " -Wl,-opt[=val] set linker option (see tcc -hh)\n" - "Debugger options:\n" - " -g generate runtime debug info\n" -#ifdef CONFIG_TCC_BCHECK - " -b compile with built-in memory and bounds checker (implies -g)\n" -#endif -#ifdef CONFIG_TCC_BACKTRACE - " -bt N show N callers in stack traces\n" -#endif - "Misc. options:\n" - " -x[c|a|n] specify type of the next infile\n" - " -nostdinc do not use standard system include paths\n" - " -nostdlib do not link with standard crt and libraries\n" - " -Bdir set tcc's private include/library dir\n" - " -MD generate dependency file for make\n" - " -MF file specify dependency file name\n" - " -m32/64 defer to i386/x86_64 cross compiler\n" - "Tools:\n" - " create library : tcc -ar [rcsv] lib.a files\n" -#ifdef TCC_TARGET_PE - " create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n" -#endif - ; - -static const char help2[] = - "Tiny C Compiler "TCC_VERSION" - More Options\n" - "Special options:\n" - " -P -P1 with -E: no/alternative #line output\n" - " -dD -dM with -E: output #define directives\n" - " -pthread same as -D_REENTRANT and -lpthread\n" - " -On same as -D__OPTIMIZE__ for n > 0\n" - " -Wp,-opt same as -opt\n" - " -include file include 'file' above each input file\n" - " -isystem dir add 'dir' to system include path\n" - " -static link to static libraries (not recommended)\n" - " -dumpversion print version\n" - " -print-search-dirs print search paths\n" - " -dt with -run/-E: auto-define 'test_...' macros\n" - "Ignored options:\n" - " --param -pedantic -pipe -s -std -traditional\n" - "-W... warnings:\n" - " all turn on some (*) warnings\n" - " error stop after first warning\n" - " unsupported warn about ignored options, pragmas, etc.\n" - " write-strings strings are const\n" - " implicit-function-declaration warn for missing prototype (*)\n" - "-f[no-]... flags:\n" - " unsigned-char default char is unsigned\n" - " signed-char default char is signed\n" - " common use common section instead of bss\n" - " leading-underscore decorate extern symbols\n" - " ms-extensions allow anonymous struct in struct\n" - " dollars-in-identifiers allow '$' in C symbols\n" - "-m... target specific options:\n" - " ms-bitfields use MSVC bitfield layout\n" -#ifdef TCC_TARGET_ARM - " float-abi hard/softfp on arm\n" -#endif -#ifdef TCC_TARGET_X86_64 - " no-sse disable floats on x86_64\n" -#endif - "-Wl,... linker options:\n" - " -nostdlib do not link with standard crt/libs\n" - " -[no-]whole-archive load lib(s) fully/only as needed\n" - " -export-all-symbols same as -rdynamic\n" - " -image-base= -Ttext= set base address of executable\n" - " -section-alignment= set section alignment in executable\n" -#ifdef TCC_TARGET_PE - " -file-alignment= set PE file alignment\n" - " -stack= set PE stack reserve\n" - " -large-address-aware set related PE option\n" - " -subsystem=[console/windows] set PE subsystem\n" - " -oformat=[pe-* binary] set executable output format\n" - "Predefined macros:\n" - " tcc -E -dM - < nul\n" -#else - " -rpath= set dynamic library search path\n" - " -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n" - " -soname= set DT_SONAME elf tag\n" - " -Bsymbolic set DT_SYMBOLIC elf tag\n" - " -oformat=[elf32/64-* binary] set executable output format\n" - " -init= -fini= -as-needed -O (ignored)\n" - "Predefined macros:\n" - " tcc -E -dM - < /dev/null\n" -#endif - "See also the manual for more details.\n" - ; - -static const char version[] = - "tcc version "TCC_VERSION" (" -#ifdef TCC_TARGET_I386 - "i386" -#elif defined TCC_TARGET_X86_64 - "x86_64" -#elif defined TCC_TARGET_C67 - "C67" -#elif defined TCC_TARGET_ARM - "ARM" -#elif defined TCC_TARGET_ARM64 - "AArch64" -#endif -#ifdef TCC_ARM_HARDFLOAT - " Hard Float" -#endif -#ifdef TCC_TARGET_PE - " Windows" -#elif defined(TCC_TARGET_MACHO) - " Darwin" -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - " FreeBSD" -#else - " Linux" -#endif - ")\n" - ; - -static void print_dirs(const char *msg, char **paths, int nb_paths) -{ - int i; - printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); - for(i = 0; i < nb_paths; i++) - printf(" %s\n", paths[i]); -} - -static void print_search_dirs(TCCState *s) -{ - printf("install: %s\n", s->tcc_lib_path); - /* print_dirs("programs", NULL, 0); */ - print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths); - print_dirs("libraries", s->library_paths, s->nb_library_paths); -#ifndef TCC_TARGET_PE - print_dirs("crt", s->crt_paths, s->nb_crt_paths); - printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path); - printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s)); -#endif -} - -static void set_environment(TCCState *s) -{ - char * path; - - path = getenv("C_INCLUDE_PATH"); - if(path != NULL) { - tcc_add_sysinclude_path(s, path); - } - path = getenv("CPATH"); - if(path != NULL) { - tcc_add_include_path(s, path); - } - path = getenv("LIBRARY_PATH"); - if(path != NULL) { - tcc_add_library_path(s, path); - } -} - -static char *default_outputfile(TCCState *s, const char *first_file) -{ - char buf[1024]; - char *ext; - const char *name = "a"; - - if (first_file && strcmp(first_file, "-")) - name = tcc_basename(first_file); - snprintf(buf, sizeof(buf), "%s", name); - ext = tcc_fileextension(buf); -#ifdef TCC_TARGET_PE - if (s->output_type == TCC_OUTPUT_DLL) - strcpy(ext, ".dll"); - else - if (s->output_type == TCC_OUTPUT_EXE) - strcpy(ext, ".exe"); - else -#endif - if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r && *ext) - strcpy(ext, ".o"); - else - strcpy(buf, "a.out"); - return tcc_strdup(buf); -} - -static unsigned getclock_ms(void) -{ -#ifdef _WIN32 - return GetTickCount(); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec*1000 + (tv.tv_usec+500)/1000; -#endif -} - -int main(int argc0, char **argv0) -{ - TCCState *s; - int ret, opt, n = 0, t = 0; - unsigned start_time = 0; - const char *first_file; - int argc; char **argv; - FILE *ppfp = stdout; - -redo: - argc = argc0, argv = argv0; - s = tcc_new(); - opt = tcc_parse_args(s, &argc, &argv, 1); - - if ((n | t) == 0) { - if (opt == OPT_HELP) - return printf(help), 1; - if (opt == OPT_HELP2) - return printf(help2), 1; - if (opt == OPT_M32 || opt == OPT_M64) - tcc_tool_cross(s, argv, opt); /* never returns */ - if (s->verbose) - printf(version); - if (opt == OPT_AR) - return tcc_tool_ar(s, argc, argv); -#ifdef TCC_TARGET_PE - if (opt == OPT_IMPDEF) - return tcc_tool_impdef(s, argc, argv); -#endif - if (opt == OPT_V) - return 0; - if (opt == OPT_PRINT_DIRS) { - /* initialize search dirs */ - set_environment(s); - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - print_search_dirs(s); - return 0; - } - - n = s->nb_files; - if (n == 0) - tcc_error("no input files\n"); - - if (s->output_type == TCC_OUTPUT_PREPROCESS) { - if (s->outfile) { - ppfp = fopen(s->outfile, "w"); - if (!ppfp) - tcc_error("could not write '%s'", s->outfile); - } - } else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { - if (s->nb_libraries) - tcc_error("cannot specify libraries with -c"); - if (n > 1 && s->outfile) - tcc_error("cannot specify output file with -c many files"); - } else { - if (s->option_pthread) - tcc_set_options(s, "-lpthread"); - } - - if (s->do_bench) - start_time = getclock_ms(); - } - - set_environment(s); - if (s->output_type == 0) - s->output_type = TCC_OUTPUT_EXE; - tcc_set_output_type(s, s->output_type); - s->ppfp = ppfp; - - if ((s->output_type == TCC_OUTPUT_MEMORY - || s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16)) - s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files; - - /* compile or add each files or library */ - for (first_file = NULL, ret = 0;;) { - struct filespec *f = s->files[s->nb_files - n]; - s->filetype = f->type; - s->alacarte_link = f->alacarte; - if (f->type == AFF_TYPE_LIB) { - if (tcc_add_library_err(s, f->name) < 0) - ret = 1; - } else { - if (1 == s->verbose) - printf("-> %s\n", f->name); - if (!first_file) - first_file = f->name; - if (tcc_add_file(s, f->name) < 0) - ret = 1; - } - s->filetype = 0; - s->alacarte_link = 1; - if (--n == 0 || ret - || (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)) - break; - } - - if (s->run_test) { - t = 0; - } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { - ; - } else if (0 == ret) { - if (s->output_type == TCC_OUTPUT_MEMORY) { -#ifdef TCC_IS_NATIVE - ret = tcc_run(s, argc, argv); -#endif - } else { - if (!s->outfile) - s->outfile = default_outputfile(s, first_file); - if (tcc_output_file(s, s->outfile)) - ret = 1; - else if (s->gen_deps) - gen_makedeps(s, s->outfile, s->deps_outfile); - } - } - - if (s->do_bench && (n | t | ret) == 0) - tcc_print_stats(s, getclock_ms() - start_time); - tcc_delete(s); - if (ret == 0 && n) - goto redo; /* compile more files with -c */ - if (t) - goto redo; /* run more tests with -dt -run */ - if (ppfp && ppfp != stdout) - fclose(ppfp); - return ret; -} diff --git a/tinyc/tcc.h b/tinyc/tcc.h deleted file mode 100644 index da26298fb..000000000 --- a/tinyc/tcc.h +++ /dev/null @@ -1,1657 +0,0 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _TCC_H -#define _TCC_H - -#define _GNU_SOURCE -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -# include -# include -# ifndef CONFIG_TCC_STATIC -# include -# endif -/* XXX: need to define this to use them in non ISOC99 context */ -extern float strtof (const char *__nptr, char **__endptr); -extern long double strtold (const char *__nptr, char **__endptr); -#endif - -#ifdef _WIN32 -# include -# include /* open, close etc. */ -# include /* getcwd */ -# ifdef __GNUC__ -# include -# endif -# define inline __inline -# define snprintf _snprintf -# define vsnprintf _vsnprintf -# ifndef __GNUC__ -# define strtold (long double)strtod -# define strtof (float)strtod -# define strtoll _strtoi64 -# define strtoull _strtoui64 -# endif -# ifdef LIBTCC_AS_DLL -# define LIBTCCAPI __declspec(dllexport) -# define PUB_FUNC LIBTCCAPI -# endif -# define inp next_inp /* inp is an intrinsic on msvc/mingw */ -# ifdef _MSC_VER -# pragma warning (disable : 4244) // conversion from 'uint64_t' to 'int', possible loss of data -# pragma warning (disable : 4267) // conversion from 'size_t' to 'int', possible loss of data -# pragma warning (disable : 4996) // The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name -# pragma warning (disable : 4018) // signed/unsigned mismatch -# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned -# define ssize_t intptr_t -# endif -# undef CONFIG_TCC_STATIC -#endif - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - -#ifndef countof -#define countof(tab) (sizeof(tab) / sizeof((tab)[0])) -#endif - -#ifdef _MSC_VER -# define NORETURN __declspec(noreturn) -# define ALIGNED(x) __declspec(align(x)) -#else -# define NORETURN __attribute__((noreturn)) -# define ALIGNED(x) __attribute__((aligned(x))) -#endif - -#ifdef _WIN32 -# define IS_DIRSEP(c) (c == '/' || c == '\\') -# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2]))) -# define PATHCMP stricmp -# define PATHSEP ";" -#else -# define IS_DIRSEP(c) (c == '/') -# define IS_ABSPATH(p) IS_DIRSEP(p[0]) -# define PATHCMP strcmp -# define PATHSEP ":" -#endif - -/* -------------------------------------------- */ - -/* parser debug */ -/* #define PARSE_DEBUG */ -/* preprocessor debug */ -/* #define PP_DEBUG */ -/* include file debug */ -/* #define INC_DEBUG */ -/* memory leak debug */ -/* #define MEM_DEBUG */ -/* assembler debug */ -/* #define ASM_DEBUG */ - -/* target selection */ -/* #define TCC_TARGET_I386 *//* i386 code generator */ -/* #define TCC_TARGET_X86_64 *//* x86-64 code generator */ -/* #define TCC_TARGET_ARM *//* ARMv4 code generator */ -/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */ -/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */ - -/* default target is I386 */ -#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ - !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \ - !defined(TCC_TARGET_X86_64) -# if defined __x86_64__ || defined _AMD64_ -# define TCC_TARGET_X86_64 -# elif defined __arm__ -# define TCC_TARGET_ARM -# define TCC_ARM_EABI -# define TCC_ARM_HARDFLOAT -# elif defined __aarch64__ -# define TCC_TARGET_ARM64 -# else -# define TCC_TARGET_I386 -# endif -# ifdef _WIN32 -# define TCC_TARGET_PE 1 -# endif -#endif - -/* only native compiler supports -run */ -#if defined _WIN32 == defined TCC_TARGET_PE -# if (defined __i386__ || defined _X86_) && defined TCC_TARGET_I386 -# define TCC_IS_NATIVE -# elif (defined __x86_64__ || defined _AMD64_) && defined TCC_TARGET_X86_64 -# define TCC_IS_NATIVE -# elif defined __arm__ && defined TCC_TARGET_ARM -# define TCC_IS_NATIVE -# elif defined __aarch64__ && defined TCC_TARGET_ARM64 -# define TCC_IS_NATIVE -# endif -#endif - -#if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT -# define CONFIG_TCC_BACKTRACE -# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) \ - && !defined TCC_UCLIBC && !defined TCC_MUSL -# define CONFIG_TCC_BCHECK /* enable bound checking code */ -# endif -#endif - -/* ------------ path configuration ------------ */ - -#ifndef CONFIG_SYSROOT -# define CONFIG_SYSROOT "" -#endif -#ifndef CONFIG_TCCDIR -# define CONFIG_TCCDIR "/usr/local/lib/tcc" -#endif -#ifndef CONFIG_LDDIR -# define CONFIG_LDDIR "lib" -#endif -#ifdef CONFIG_TRIPLET -# define USE_TRIPLET(s) s "/" CONFIG_TRIPLET -# define ALSO_TRIPLET(s) USE_TRIPLET(s) ":" s -#else -# define USE_TRIPLET(s) s -# define ALSO_TRIPLET(s) s -#endif - -/* path to find crt1.o, crti.o and crtn.o */ -#ifndef CONFIG_TCC_CRTPREFIX -# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) -#endif - -/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */ - -/* system include paths */ -#ifndef CONFIG_TCC_SYSINCLUDEPATHS -# ifdef TCC_TARGET_PE -# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi" -# else -# define CONFIG_TCC_SYSINCLUDEPATHS \ - "{B}/include" \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/include") -# endif -#endif - -/* library search paths */ -#ifndef CONFIG_TCC_LIBPATHS -# ifdef TCC_TARGET_PE -# define CONFIG_TCC_LIBPATHS "{B}/lib" -# else -# define CONFIG_TCC_LIBPATHS \ - ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \ - ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR) -# endif -#endif - -/* name of ELF interpreter */ -#ifndef CONFIG_TCC_ELFINTERP -# if defined __FreeBSD__ -# define CONFIG_TCC_ELFINTERP "/libexec/ld-elf.so.1" -# elif defined __FreeBSD_kernel__ -# if defined(TCC_TARGET_X86_64) -# define CONFIG_TCC_ELFINTERP "/lib/ld-kfreebsd-x86-64.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld.so.1" -# endif -# elif defined __DragonFly__ -# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2" -# elif defined __NetBSD__ -# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld.elf_so" -# elif defined __GNU__ -# define CONFIG_TCC_ELFINTERP "/lib/ld.so" -# elif defined(TCC_TARGET_PE) -# define CONFIG_TCC_ELFINTERP "-" -# elif defined(TCC_UCLIBC) -# define CONFIG_TCC_ELFINTERP "/lib/ld-uClibc.so.0" /* is there a uClibc for x86_64 ? */ -# elif defined TCC_TARGET_ARM64 -# if defined(TCC_MUSL) -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-aarch64.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1" -# endif -# elif defined(TCC_TARGET_X86_64) -# if defined(TCC_MUSL) -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" -# endif -# elif !defined(TCC_ARM_EABI) -# if defined(TCC_MUSL) -# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1" -# else -# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2" -# endif -# endif -#endif - -/* var elf_interp dans *-gen.c */ -#ifdef CONFIG_TCC_ELFINTERP -# define DEFAULT_ELFINTERP(s) CONFIG_TCC_ELFINTERP -#else -# define DEFAULT_ELFINTERP(s) default_elfinterp(s) -#endif - -/* (target specific) libtcc1.a */ -#ifndef TCC_LIBTCC1 -# define TCC_LIBTCC1 "libtcc1.a" -#endif - -/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ -#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC -#define TCC_LIBGCC USE_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1" -#endif - -/* -------------------------------------------- */ - -#include "libtcc.h" -#include "elf.h" -#include "stab.h" - -/* -------------------------------------------- */ - -#ifndef PUB_FUNC /* functions used by tcc.c but not in libtcc.h */ -# define PUB_FUNC -#endif - -#ifndef ONE_SOURCE -# define ONE_SOURCE 1 -#endif - -#if ONE_SOURCE -#define ST_INLN static inline -#define ST_FUNC static -#define ST_DATA static -#else -#define ST_INLN -#define ST_FUNC -#define ST_DATA extern -#endif - -#ifdef TCC_PROFILE /* profile all functions */ -# define static -#endif - -/* -------------------------------------------- */ -/* include the target specific definitions */ - -#define TARGET_DEFS_ONLY -#ifdef TCC_TARGET_I386 -# include "i386-gen.c" -# include "i386-link.c" -#endif -#ifdef TCC_TARGET_X86_64 -# include "x86_64-gen.c" -# include "x86_64-link.c" -#endif -#ifdef TCC_TARGET_ARM -# include "arm-gen.c" -# include "arm-link.c" -# include "arm-asm.c" -#endif -#ifdef TCC_TARGET_ARM64 -# include "arm64-gen.c" -# include "arm64-link.c" -#endif -#ifdef TCC_TARGET_C67 -# define TCC_TARGET_COFF -# include "coff.h" -# include "c67-gen.c" -# include "c67-link.c" -#endif -#undef TARGET_DEFS_ONLY - -/* -------------------------------------------- */ - -#if PTR_SIZE == 8 -# define ELFCLASSW ELFCLASS64 -# define ElfW(type) Elf##64##_##type -# define ELFW(type) ELF##64##_##type -# define ElfW_Rel ElfW(Rela) -# define SHT_RELX SHT_RELA -# define REL_SECTION_FMT ".rela%s" -#else -# define ELFCLASSW ELFCLASS32 -# define ElfW(type) Elf##32##_##type -# define ELFW(type) ELF##32##_##type -# define ElfW_Rel ElfW(Rel) -# define SHT_RELX SHT_REL -# define REL_SECTION_FMT ".rel%s" -#endif -/* target address type */ -#define addr_t ElfW(Addr) - -#if PTR_SIZE == 8 && !defined TCC_TARGET_PE -# define LONG_SIZE 8 -#else -# define LONG_SIZE 4 -#endif - -/* -------------------------------------------- */ - -#define INCLUDE_STACK_SIZE 32 -#define IFDEF_STACK_SIZE 64 -#define VSTACK_SIZE 256 -#define STRING_MAX_SIZE 1024 -#define TOKSTR_MAX_SIZE 256 -#define PACK_STACK_SIZE 8 - -#define TOK_HASH_SIZE 16384 /* must be a power of two */ -#define TOK_ALLOC_INCR 512 /* must be a power of two */ -#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ - -/* token symbol management */ -typedef struct TokenSym { - struct TokenSym *hash_next; - struct Sym *sym_define; /* direct pointer to define */ - struct Sym *sym_label; /* direct pointer to label */ - struct Sym *sym_struct; /* direct pointer to structure */ - struct Sym *sym_identifier; /* direct pointer to identifier */ - int tok; /* token number */ - int len; - char str[1]; -} TokenSym; - -#ifdef TCC_TARGET_PE -typedef unsigned short nwchar_t; -#else -typedef int nwchar_t; -#endif - -typedef struct CString { - int size; /* size in bytes */ - void *data; /* either 'char *' or 'nwchar_t *' */ - int size_allocated; -} CString; - -/* type definition */ -typedef struct CType { - int t; - struct Sym *ref; -} CType; - -/* constant value */ -typedef union CValue { - long double ld; - double d; - float f; - uint64_t i; - struct { - int size; - const void *data; - } str; - int tab[LDOUBLE_SIZE/4]; -} CValue; - -/* value on stack */ -typedef struct SValue { - CType type; /* type */ - unsigned short r; /* register + flags */ - unsigned short r2; /* second register, used for 'long long' - type. If not used, set to VT_CONST */ - CValue c; /* constant, if VT_CONST */ - struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if - result of unary() for an identifier. */ -} SValue; - -/* symbol attributes */ -struct SymAttr { - unsigned short - aligned : 5, /* alignment as log2+1 (0 == unspecified) */ - packed : 1, - weak : 1, - visibility : 2, - dllexport : 1, - dllimport : 1, - unused : 5; -}; - -/* function attributes or temporary attributes for parsing */ -struct FuncAttr { - unsigned - func_call : 3, /* calling convention (0..5), see below */ - func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */ - func_body : 1, /* body was defined */ - func_args : 8; /* PE __stdcall args */ -}; - -/* GNUC attribute definition */ -typedef struct AttributeDef { - struct SymAttr a; - struct FuncAttr f; - struct Section *section; - int alias_target; /* token */ - int asm_label; /* associated asm label */ - char attr_mode; /* __attribute__((__mode__(...))) */ -} AttributeDef; - -/* symbol management */ -typedef struct Sym { - int v; /* symbol token */ - unsigned short r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */ - struct SymAttr a; /* symbol attributes */ - union { - struct { - int c; /* associated number or Elf symbol index */ - union { - int sym_scope; /* scope level for locals */ - int jnext; /* next jump label */ - struct FuncAttr f; /* function attributes */ - int auxtype; /* bitfield access type */ - }; - }; - long long enum_val; /* enum constant if IS_ENUM_VAL */ - int *d; /* define token stream */ - }; - CType type; /* associated type */ - union { - struct Sym *next; /* next related symbol (for fields and anoms) */ - int asm_label; /* associated asm label */ - }; - struct Sym *prev; /* prev symbol in stack */ - struct Sym *prev_tok; /* previous symbol for this token */ -} Sym; - -/* section definition */ -/* XXX: use directly ELF structure for parameters ? */ -/* special flag to indicate that the section should not be linked to - the other ones */ -#define SHF_PRIVATE 0x80000000 - -/* special flag, too */ -#define SECTION_ABS ((void *)1) - -typedef struct Section { - unsigned long data_offset; /* current data offset */ - unsigned char *data; /* section data */ - unsigned long data_allocated; /* used for realloc() handling */ - int sh_name; /* elf section name (only used during output) */ - int sh_num; /* elf section number */ - int sh_type; /* elf section type */ - int sh_flags; /* elf section flags */ - int sh_info; /* elf section info */ - int sh_addralign; /* elf section alignment */ - int sh_entsize; /* elf entry size */ - unsigned long sh_size; /* section size (only used during output) */ - addr_t sh_addr; /* address at which the section is relocated */ - unsigned long sh_offset; /* file offset */ - int nb_hashed_syms; /* used to resize the hash table */ - struct Section *link; /* link to another section */ - struct Section *reloc; /* corresponding section for relocation, if any */ - struct Section *hash; /* hash table for symbols */ - struct Section *prev; /* previous section on section stack */ - char name[1]; /* section name */ -} Section; - -typedef struct DLLReference { - int level; - void *handle; - char name[1]; -} DLLReference; - -/* -------------------------------------------------- */ - -#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ -#define SYM_FIELD 0x20000000 /* struct/union field symbol space */ -#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ - -/* stored in 'Sym->f.func_type' field */ -#define FUNC_NEW 1 /* ansi function prototype */ -#define FUNC_OLD 2 /* old function prototype */ -#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ - -/* stored in 'Sym->f.func_call' field */ -#define FUNC_CDECL 0 /* standard c call */ -#define FUNC_STDCALL 1 /* pascal c call */ -#define FUNC_FASTCALL1 2 /* first param in %eax */ -#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ -#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ -#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */ - -/* field 'Sym.t' for macros */ -#define MACRO_OBJ 0 /* object like macro */ -#define MACRO_FUNC 1 /* function like macro */ - -/* field 'Sym.r' for C labels */ -#define LABEL_DEFINED 0 /* label is defined */ -#define LABEL_FORWARD 1 /* label is forward defined */ -#define LABEL_DECLARED 2 /* label is declared but never used */ - -/* type_decl() types */ -#define TYPE_ABSTRACT 1 /* type without variable */ -#define TYPE_DIRECT 2 /* type with variable */ - -#define IO_BUF_SIZE 8192 - -typedef struct BufferedFile { - uint8_t *buf_ptr; - uint8_t *buf_end; - int fd; - struct BufferedFile *prev; - int line_num; /* current line number - here to simplify code */ - int line_ref; /* tcc -E: last printed line */ - int ifndef_macro; /* #ifndef macro / #endif search */ - int ifndef_macro_saved; /* saved ifndef_macro */ - int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ - int include_next_index; /* next search path */ - char filename[1024]; /* filename */ - char *true_filename; /* filename not modified by # line directive */ - unsigned char unget[4]; - unsigned char buffer[1]; /* extra size for CH_EOB char */ -} BufferedFile; - -#define CH_EOB '\\' /* end of buffer or '\0' char in file */ -#define CH_EOF (-1) /* end of file */ - -/* used to record tokens */ -typedef struct TokenString { - int *str; - int len; - int lastlen; - int allocated_len; - int last_line_num; - int save_line_num; - /* used to chain token-strings with begin/end_macro() */ - struct TokenString *prev; - const int *prev_ptr; - char alloc; -} TokenString; - -/* inline functions */ -typedef struct InlineFunc { - TokenString *func_str; - Sym *sym; - char filename[1]; -} InlineFunc; - -/* include file cache, used to find files faster and also to eliminate - inclusion if the include file is protected by #ifndef ... #endif */ -typedef struct CachedInclude { - int ifndef_macro; - int once; - int hash_next; /* -1 if none */ - char filename[1]; /* path specified in #include */ -} CachedInclude; - -#define CACHED_INCLUDES_HASH_SIZE 32 - -#ifdef CONFIG_TCC_ASM -typedef struct ExprValue { - uint64_t v; - Sym *sym; - int pcrel; -} ExprValue; - -#define MAX_ASM_OPERANDS 30 -typedef struct ASMOperand { - int id; /* GCC 3 optional identifier (0 if number only supported */ - char *constraint; - char asm_str[16]; /* computed asm string for operand */ - SValue *vt; /* C value of the expression */ - int ref_index; /* if >= 0, gives reference to a output constraint */ - int input_index; /* if >= 0, gives reference to an input constraint */ - int priority; /* priority, used to assign registers */ - int reg; /* if >= 0, register number used for this operand */ - int is_llong; /* true if double register value */ - int is_memory; /* true if memory operand */ - int is_rw; /* for '+' modifier */ -} ASMOperand; -#endif - -/* extra symbol attributes (not in symbol table) */ -struct sym_attr { - unsigned got_offset; - unsigned plt_offset; - int plt_sym; - int dyn_index; -#ifdef TCC_TARGET_ARM - unsigned char plt_thumb_stub:1; -#endif -}; - -struct TCCState { - - int verbose; /* if true, display some information during compilation */ - int nostdinc; /* if true, no standard headers are added */ - int nostdlib; /* if true, no standard libraries are added */ - int nocommon; /* if true, do not use common symbols for .bss data */ - int static_link; /* if true, static linking is performed */ - int rdynamic; /* if true, all symbols are exported */ - int symbolic; /* if true, resolve symbols in the current module first */ - int alacarte_link; /* if true, only link in referenced objects from archive */ - - char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */ - char *soname; /* as specified on the command line (-soname) */ - char *rpath; /* as specified on the command line (-Wl,-rpath=) */ - int enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */ - - /* output type, see TCC_OUTPUT_XXX */ - int output_type; - /* output format, see TCC_OUTPUT_FORMAT_xxx */ - int output_format; - - /* C language options */ - int char_is_unsigned; - int leading_underscore; - int ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */ - int dollars_in_identifiers; /* allows '$' char in identifiers */ - int ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ - - /* warning switches */ - int warn_write_strings; - int warn_unsupported; - int warn_error; - int warn_none; - int warn_implicit_function_declaration; - int warn_gcc_compat; - - /* compile with debug symbol (and use them if error during execution) */ - int do_debug; -#ifdef CONFIG_TCC_BCHECK - /* compile with built-in memory and bounds checker */ - int do_bounds_check; -#endif -#ifdef TCC_TARGET_ARM - enum float_abi float_abi; /* float ABI of the generated code*/ -#endif - int run_test; /* nth test to run with -dt -run */ - - addr_t text_addr; /* address of text section */ - int has_text_addr; - - unsigned section_align; /* section alignment */ - - char *init_symbol; /* symbols to call at load-time (not used currently) */ - char *fini_symbol; /* symbols to call at unload-time (not used currently) */ - -#ifdef TCC_TARGET_I386 - int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */ -#endif -#ifdef TCC_TARGET_X86_64 - int nosse; /* For -mno-sse support. */ -#endif - - /* array of all loaded dlls (including those referenced by loaded dlls) */ - DLLReference **loaded_dlls; - int nb_loaded_dlls; - - /* include paths */ - char **include_paths; - int nb_include_paths; - - char **sysinclude_paths; - int nb_sysinclude_paths; - - /* library paths */ - char **library_paths; - int nb_library_paths; - - /* crt?.o object path */ - char **crt_paths; - int nb_crt_paths; - - /* -include files */ - char **cmd_include_files; - int nb_cmd_include_files; - - /* error handling */ - void *error_opaque; - void (*error_func)(void *opaque, const char *msg); - int error_set_jmp_enabled; - jmp_buf error_jmp_buf; - int nb_errors; - - /* output file for preprocessing (-E) */ - FILE *ppfp; - enum { - LINE_MACRO_OUTPUT_FORMAT_GCC, - LINE_MACRO_OUTPUT_FORMAT_NONE, - LINE_MACRO_OUTPUT_FORMAT_STD, - LINE_MACRO_OUTPUT_FORMAT_P10 = 11 - } Pflag; /* -P switch */ - char dflag; /* -dX value */ - - /* for -MD/-MF: collected dependencies for this compilation */ - char **target_deps; - int nb_target_deps; - - /* compilation */ - BufferedFile *include_stack[INCLUDE_STACK_SIZE]; - BufferedFile **include_stack_ptr; - - int ifdef_stack[IFDEF_STACK_SIZE]; - int *ifdef_stack_ptr; - - /* included files enclosed with #ifndef MACRO */ - int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; - CachedInclude **cached_includes; - int nb_cached_includes; - - /* #pragma pack stack */ - int pack_stack[PACK_STACK_SIZE]; - int *pack_stack_ptr; - char **pragma_libs; - int nb_pragma_libs; - - /* inline functions are stored as token lists and compiled last - only if referenced */ - struct InlineFunc **inline_fns; - int nb_inline_fns; - - /* sections */ - Section **sections; - int nb_sections; /* number of sections, including first dummy section */ - - Section **priv_sections; - int nb_priv_sections; /* number of private sections */ - - /* got & plt handling */ - Section *got; - Section *plt; - - /* temporary dynamic symbol sections (for dll loading) */ - Section *dynsymtab_section; - /* exported dynamic symbol section */ - Section *dynsym; - /* copy of the global symtab_section variable */ - Section *symtab; - /* extra attributes (eg. GOT/PLT value) for symtab symbols */ - struct sym_attr *sym_attrs; - int nb_sym_attrs; - /* tiny assembler state */ - Sym *asm_labels; - -#ifdef TCC_TARGET_PE - /* PE info */ - int pe_subsystem; - unsigned pe_characteristics; - unsigned pe_file_align; - unsigned pe_stack_size; -# ifdef TCC_TARGET_X86_64 - Section *uw_pdata; - int uw_sym; - unsigned uw_offs; -# endif -#endif - -#ifdef TCC_IS_NATIVE - const char *runtime_main; - void **runtime_mem; - int nb_runtime_mem; -#endif - - /* used by main and tcc_parse_args only */ - struct filespec **files; /* files seen on command line */ - int nb_files; /* number thereof */ - int nb_libraries; /* number of libs thereof */ - int filetype; - char *outfile; /* output filename */ - int option_r; /* option -r */ - int do_bench; /* option -bench */ - int gen_deps; /* option -MD */ - char *deps_outfile; /* option -MF */ - int option_pthread; /* -pthread option */ - int argc; - char **argv; -}; - -struct filespec { - char type; - char alacarte; - char name[1]; -}; - -/* The current value can be: */ -#define VT_VALMASK 0x003f /* mask for value location, register or: */ -#define VT_CONST 0x0030 /* constant in vc (must be first non register value) */ -#define VT_LLOCAL 0x0031 /* lvalue, offset on stack */ -#define VT_LOCAL 0x0032 /* offset on stack */ -#define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ -#define VT_JMP 0x0034 /* value is the consequence of jmp true (even) */ -#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */ -#define VT_LVAL 0x0100 /* var is an lvalue */ -#define VT_SYM 0x0200 /* a symbol value is added */ -#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for - char/short stored in integer registers) */ -#define VT_MUSTBOUND 0x0800 /* bound checking must be done before - dereferencing value */ -#define VT_BOUNDED 0x8000 /* value is bounded. The address of the - bounding function call point is in vc */ -#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ -#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ -#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ -#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) - -/* types */ -#define VT_BTYPE 0x000f /* mask for basic type */ -#define VT_VOID 0 /* void type */ -#define VT_BYTE 1 /* signed byte type */ -#define VT_SHORT 2 /* short type */ -#define VT_INT 3 /* integer type */ -#define VT_LLONG 4 /* 64 bit integer */ -#define VT_PTR 5 /* pointer */ -#define VT_FUNC 6 /* function type */ -#define VT_STRUCT 7 /* struct/union definition */ -#define VT_FLOAT 8 /* IEEE float */ -#define VT_DOUBLE 9 /* IEEE double */ -#define VT_LDOUBLE 10 /* IEEE long double */ -#define VT_BOOL 11 /* ISOC99 boolean type */ -#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */ -#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */ - -#define VT_UNSIGNED 0x0010 /* unsigned type */ -#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */ -#define VT_ARRAY 0x0040 /* array type (also has VT_PTR) */ -#define VT_BITFIELD 0x0080 /* bitfield modifier */ -#define VT_CONSTANT 0x0100 /* const modifier */ -#define VT_VOLATILE 0x0200 /* volatile modifier */ -#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */ - -/* storage */ -#define VT_EXTERN 0x00001000 /* extern definition */ -#define VT_STATIC 0x00002000 /* static variable */ -#define VT_TYPEDEF 0x00004000 /* typedef definition */ -#define VT_INLINE 0x00008000 /* inline definition */ -/* currently unused: 0x000[1248]0000 */ - -#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */ -#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) -#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f) -#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f) - -#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT) -#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */ -#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */ - -#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM) -#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL) -#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION) - -/* type mask (except storage) */ -#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) -#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) - -/* token values */ - -/* warning: the following compare tokens depend on i386 asm code */ -#define TOK_ULT 0x92 -#define TOK_UGE 0x93 -#define TOK_EQ 0x94 -#define TOK_NE 0x95 -#define TOK_ULE 0x96 -#define TOK_UGT 0x97 -#define TOK_Nset 0x98 -#define TOK_Nclear 0x99 -#define TOK_LT 0x9c -#define TOK_GE 0x9d -#define TOK_LE 0x9e -#define TOK_GT 0x9f - -#define TOK_LAND 0xa0 -#define TOK_LOR 0xa1 -#define TOK_DEC 0xa2 -#define TOK_MID 0xa3 /* inc/dec, to void constant */ -#define TOK_INC 0xa4 -#define TOK_UDIV 0xb0 /* unsigned division */ -#define TOK_UMOD 0xb1 /* unsigned modulo */ -#define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */ - -/* tokens that carry values (in additional token string space / tokc) --> */ -#define TOK_CCHAR 0xb3 /* char constant in tokc */ -#define TOK_LCHAR 0xb4 -#define TOK_CINT 0xb5 /* number in tokc */ -#define TOK_CUINT 0xb6 /* unsigned int constant */ -#define TOK_CLLONG 0xb7 /* long long constant */ -#define TOK_CULLONG 0xb8 /* unsigned long long constant */ -#define TOK_STR 0xb9 /* pointer to string in tokc */ -#define TOK_LSTR 0xba -#define TOK_CFLOAT 0xbb /* float constant */ -#define TOK_CDOUBLE 0xbc /* double constant */ -#define TOK_CLDOUBLE 0xbd /* long double constant */ -#define TOK_PPNUM 0xbe /* preprocessor number */ -#define TOK_PPSTR 0xbf /* preprocessor string */ -#define TOK_LINENUM 0xc0 /* line number info */ -#define TOK_TWODOTS 0xa8 /* C++ token ? */ -/* <-- */ - -#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ -#define TOK_ADDC1 0xc3 /* add with carry generation */ -#define TOK_ADDC2 0xc4 /* add with carry use */ -#define TOK_SUBC1 0xc5 /* add with carry generation */ -#define TOK_SUBC2 0xc6 /* add with carry use */ -#define TOK_ARROW 0xc7 -#define TOK_DOTS 0xc8 /* three dots */ -#define TOK_SHR 0xc9 /* unsigned shift right */ -#define TOK_TWOSHARPS 0xca /* ## preprocessing token */ -#define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */ -#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */ -#define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */ -#define TOK_CLONG 0xce /* long constant */ -#define TOK_CULONG 0xcf /* unsigned long constant */ - -#define TOK_SHL 0x01 /* shift left */ -#define TOK_SAR 0x02 /* signed shift right */ - -/* assignment operators : normal operator or 0x80 */ -#define TOK_A_MOD 0xa5 -#define TOK_A_AND 0xa6 -#define TOK_A_MUL 0xaa -#define TOK_A_ADD 0xab -#define TOK_A_SUB 0xad -#define TOK_A_DIV 0xaf -#define TOK_A_XOR 0xde -#define TOK_A_OR 0xfc -#define TOK_A_SHL 0x81 -#define TOK_A_SAR 0x82 - -#define TOK_EOF (-1) /* end of file */ -#define TOK_LINEFEED 10 /* line feed */ - -/* all identifiers and strings have token above that */ -#define TOK_IDENT 256 - -#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) -#define TOK_ASM_int TOK_INT -#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x) -#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte -#define TOK_ASMDIR_LAST TOK_ASMDIR_section - -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -/* only used for i386 asm opcodes definitions */ -#define DEF_BWL(x) \ - DEF(TOK_ASM_ ## x ## b, #x "b") \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x, #x) -#define DEF_WL(x) \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x, #x) -#ifdef TCC_TARGET_X86_64 -# define DEF_BWLQ(x) \ - DEF(TOK_ASM_ ## x ## b, #x "b") \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x ## q, #x "q") \ - DEF(TOK_ASM_ ## x, #x) -# define DEF_WLQ(x) \ - DEF(TOK_ASM_ ## x ## w, #x "w") \ - DEF(TOK_ASM_ ## x ## l, #x "l") \ - DEF(TOK_ASM_ ## x ## q, #x "q") \ - DEF(TOK_ASM_ ## x, #x) -# define DEF_BWLX DEF_BWLQ -# define DEF_WLX DEF_WLQ -/* number of sizes + 1 */ -# define NBWLX 5 -#else -# define DEF_BWLX DEF_BWL -# define DEF_WLX DEF_WL -/* number of sizes + 1 */ -# define NBWLX 4 -#endif - -#define DEF_FP1(x) \ - DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ - DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ - DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ - DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") - -#define DEF_FP(x) \ - DEF(TOK_ASM_ ## f ## x, "f" #x ) \ - DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ - DEF_FP1(x) - -#define DEF_ASMTEST(x,suffix) \ - DEF_ASM(x ## o ## suffix) \ - DEF_ASM(x ## no ## suffix) \ - DEF_ASM(x ## b ## suffix) \ - DEF_ASM(x ## c ## suffix) \ - DEF_ASM(x ## nae ## suffix) \ - DEF_ASM(x ## nb ## suffix) \ - DEF_ASM(x ## nc ## suffix) \ - DEF_ASM(x ## ae ## suffix) \ - DEF_ASM(x ## e ## suffix) \ - DEF_ASM(x ## z ## suffix) \ - DEF_ASM(x ## ne ## suffix) \ - DEF_ASM(x ## nz ## suffix) \ - DEF_ASM(x ## be ## suffix) \ - DEF_ASM(x ## na ## suffix) \ - DEF_ASM(x ## nbe ## suffix) \ - DEF_ASM(x ## a ## suffix) \ - DEF_ASM(x ## s ## suffix) \ - DEF_ASM(x ## ns ## suffix) \ - DEF_ASM(x ## p ## suffix) \ - DEF_ASM(x ## pe ## suffix) \ - DEF_ASM(x ## np ## suffix) \ - DEF_ASM(x ## po ## suffix) \ - DEF_ASM(x ## l ## suffix) \ - DEF_ASM(x ## nge ## suffix) \ - DEF_ASM(x ## nl ## suffix) \ - DEF_ASM(x ## ge ## suffix) \ - DEF_ASM(x ## le ## suffix) \ - DEF_ASM(x ## ng ## suffix) \ - DEF_ASM(x ## nle ## suffix) \ - DEF_ASM(x ## g ## suffix) - -#endif /* defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 */ - -enum tcc_token { - TOK_LAST = TOK_IDENT - 1 -#define DEF(id, str) ,id -#include "tcctok.h" -#undef DEF -}; - -/* keywords: tok >= TOK_IDENT && tok < TOK_UIDENT */ -#define TOK_UIDENT TOK_DEFINE - -/* ------------ libtcc.c ------------ */ - -/* use GNU C extensions */ -ST_DATA int gnu_ext; -/* use Tiny C extensions */ -ST_DATA int tcc_ext; -/* XXX: get rid of this ASAP */ -ST_DATA struct TCCState *tcc_state; - -/* public functions currently used by the tcc main function */ -ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s); -ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s); -ST_FUNC char *pstrncpy(char *out, const char *in, size_t num); -PUB_FUNC char *tcc_basename(const char *name); -PUB_FUNC char *tcc_fileextension (const char *name); - -#ifndef MEM_DEBUG -PUB_FUNC void tcc_free(void *ptr); -PUB_FUNC void *tcc_malloc(unsigned long size); -PUB_FUNC void *tcc_mallocz(unsigned long size); -PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size); -PUB_FUNC char *tcc_strdup(const char *str); -#else -#define tcc_free(ptr) tcc_free_debug(ptr) -#define tcc_malloc(size) tcc_malloc_debug(size, __FILE__, __LINE__) -#define tcc_mallocz(size) tcc_mallocz_debug(size, __FILE__, __LINE__) -#define tcc_realloc(ptr,size) tcc_realloc_debug(ptr, size, __FILE__, __LINE__) -#define tcc_strdup(str) tcc_strdup_debug(str, __FILE__, __LINE__) -PUB_FUNC void tcc_free_debug(void *ptr); -PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line); -PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line); -PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line); -PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); -#endif - -#define free(p) use_tcc_free(p) -#define malloc(s) use_tcc_malloc(s) -#define realloc(p, s) use_tcc_realloc(p, s) -#undef strdup -#define strdup(s) use_tcc_strdup(s) -PUB_FUNC void tcc_memcheck(void); -PUB_FUNC void tcc_error_noabort(const char *fmt, ...); -PUB_FUNC NORETURN void tcc_error(const char *fmt, ...); -PUB_FUNC void tcc_warning(const char *fmt, ...); - -/* other utilities */ -ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data); -ST_FUNC void dynarray_reset(void *pp, int *n); -ST_INLN void cstr_ccat(CString *cstr, int ch); -ST_FUNC void cstr_cat(CString *cstr, const char *str, int len); -ST_FUNC void cstr_wccat(CString *cstr, int ch); -ST_FUNC void cstr_new(CString *cstr); -ST_FUNC void cstr_free(CString *cstr); -ST_FUNC void cstr_reset(CString *cstr); - -ST_INLN void sym_free(Sym *sym); -ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c); -ST_FUNC Sym *sym_find2(Sym *s, int v); -ST_FUNC Sym *sym_push(int v, CType *type, int r, int c); -ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep); -ST_INLN Sym *struct_find(int v); -ST_INLN Sym *sym_find(int v); -ST_FUNC Sym *global_identifier_push(int v, int t, int c); - -ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen); -ST_FUNC int tcc_open(TCCState *s1, const char *filename); -ST_FUNC void tcc_close(void); - -ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); -/* flags: */ -#define AFF_PRINT_ERROR 0x10 /* print error if file not found */ -#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */ -#define AFF_TYPE_BIN 0x40 /* file to add is binary */ -/* s->filetype: */ -#define AFF_TYPE_NONE 0 -#define AFF_TYPE_C 1 -#define AFF_TYPE_ASM 2 -#define AFF_TYPE_ASMPP 3 -#define AFF_TYPE_LIB 4 -/* values from tcc_object_type(...) */ -#define AFF_BINTYPE_REL 1 -#define AFF_BINTYPE_DYN 2 -#define AFF_BINTYPE_AR 3 -#define AFF_BINTYPE_C67 4 - - -ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); -ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); -ST_FUNC void tcc_add_pragma_libs(TCCState *s1); -PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); -PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); -PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); -#ifdef _WIN32 -ST_FUNC char *normalize_slashes(char *path); -#endif - -/* tcc_parse_args return codes: */ -#define OPT_HELP 1 -#define OPT_HELP2 2 -#define OPT_V 3 -#define OPT_PRINT_DIRS 4 -#define OPT_AR 5 -#define OPT_IMPDEF 6 -#define OPT_M32 32 -#define OPT_M64 64 - -/* ------------ tccpp.c ------------ */ - -ST_DATA struct BufferedFile *file; -ST_DATA int ch, tok; -ST_DATA CValue tokc; -ST_DATA const int *macro_ptr; -ST_DATA int parse_flags; -ST_DATA int tok_flags; -ST_DATA CString tokcstr; /* current parsed string, if any */ - -/* display benchmark infos */ -ST_DATA int total_lines; -ST_DATA int total_bytes; -ST_DATA int tok_ident; -ST_DATA TokenSym **table_ident; - -#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ -#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ -#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ -#define TOK_FLAG_EOF 0x0008 /* end of file */ - -#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ -#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ -#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a - token. line feed is also - returned at eof */ -#define PARSE_FLAG_ASM_FILE 0x0008 /* we processing an asm file: '#' can be used for line comment, etc. */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ -#define PARSE_FLAG_ACCEPT_STRAYS 0x0020 /* next() returns '\\' token */ -#define PARSE_FLAG_TOK_STR 0x0040 /* return parsed strings instead of TOK_PPSTR */ - -/* isidnum_table flags: */ -#define IS_SPC 1 -#define IS_ID 2 -#define IS_NUM 4 - -ST_FUNC TokenSym *tok_alloc(const char *str, int len); -ST_FUNC const char *get_tok_str(int v, CValue *cv); -ST_FUNC void begin_macro(TokenString *str, int alloc); -ST_FUNC void end_macro(void); -ST_FUNC int set_idnum(int c, int val); -ST_INLN void tok_str_new(TokenString *s); -ST_FUNC TokenString *tok_str_alloc(void); -ST_FUNC void tok_str_free(TokenString *s); -ST_FUNC void tok_str_free_str(int *str); -ST_FUNC void tok_str_add(TokenString *s, int t); -ST_FUNC void tok_str_add_tok(TokenString *s); -ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg); -ST_FUNC void define_undef(Sym *s); -ST_INLN Sym *define_find(int v); -ST_FUNC void free_defines(Sym *b); -ST_FUNC Sym *label_find(int v); -ST_FUNC Sym *label_push(Sym **ptop, int v, int flags); -ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep); -ST_FUNC void parse_define(void); -ST_FUNC void preprocess(int is_bof); -ST_FUNC void next_nomacro(void); -ST_FUNC void next(void); -ST_INLN void unget_tok(int last_tok); -ST_FUNC void preprocess_start(TCCState *s1, int is_asm); -ST_FUNC void preprocess_end(TCCState *s1); -ST_FUNC void tccpp_new(TCCState *s); -ST_FUNC void tccpp_delete(TCCState *s); -ST_FUNC int tcc_preprocess(TCCState *s1); -ST_FUNC void skip(int c); -ST_FUNC NORETURN void expect(const char *msg); - -/* space excluding newline */ -static inline int is_space(int ch) { - return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; -} -static inline int isid(int c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} -static inline int isnum(int c) { - return c >= '0' && c <= '9'; -} -static inline int isoct(int c) { - return c >= '0' && c <= '7'; -} -static inline int toup(int c) { - return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; -} - -/* ------------ tccgen.c ------------ */ - -#define SYM_POOL_NB (8192 / sizeof(Sym)) -ST_DATA Sym *sym_free_first; -ST_DATA void **sym_pools; -ST_DATA int nb_sym_pools; - -ST_DATA Sym *global_stack; -ST_DATA Sym *local_stack; -ST_DATA Sym *local_label_stack; -ST_DATA Sym *global_label_stack; -ST_DATA Sym *define_stack; -ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; -ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop, *pvtop; -#define vstack (__vstack + 1) -ST_DATA int rsym, anon_sym, ind, loc; - -ST_DATA int const_wanted; /* true if constant wanted */ -ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ -ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ -ST_DATA CType func_vt; /* current function return type (used by return instruction) */ -ST_DATA int func_var; /* true if current function is variadic */ -ST_DATA int func_vc; -ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ -ST_DATA const char *funcname; -ST_DATA int g_debug; - -ST_FUNC void tcc_debug_start(TCCState *s1); -ST_FUNC void tcc_debug_end(TCCState *s1); -ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym); -ST_FUNC void tcc_debug_funcend(TCCState *s1, int size); -ST_FUNC void tcc_debug_line(TCCState *s1); - -ST_FUNC int tccgen_compile(TCCState *s1); -ST_FUNC void free_inline_functions(TCCState *s); -ST_FUNC void check_vstack(void); - -ST_INLN int is_float(int t); -ST_FUNC int ieee_finite(double d); -ST_FUNC void test_lvalue(void); -ST_FUNC void vpushi(int v); -ST_FUNC Sym *external_global_sym(int v, CType *type, int r); -ST_FUNC void vset(CType *type, int r, int v); -ST_FUNC void vswap(void); -ST_FUNC void vpush_global_sym(CType *type, int v); -ST_FUNC void vrote(SValue *e, int n); -ST_FUNC void vrott(int n); -ST_FUNC void vrotb(int n); -#ifdef TCC_TARGET_ARM -ST_FUNC int get_reg_ex(int rc, int rc2); -ST_FUNC void lexpand_nr(void); -#endif -ST_FUNC void vpushv(SValue *v); -ST_FUNC void save_reg(int r); -ST_FUNC void save_reg_upstack(int r, int n); -ST_FUNC int get_reg(int rc); -ST_FUNC void save_regs(int n); -ST_FUNC void gaddrof(void); -ST_FUNC int gv(int rc); -ST_FUNC void gv2(int rc1, int rc2); -ST_FUNC void vpop(void); -ST_FUNC void gen_op(int op); -ST_FUNC int type_size(CType *type, int *a); -ST_FUNC void mk_pointer(CType *type); -ST_FUNC void vstore(void); -ST_FUNC void inc(int post, int c); -ST_FUNC void parse_mult_str (CString *astr, const char *msg); -ST_FUNC void parse_asm_str(CString *astr); -ST_FUNC int lvalue_type(int t); -ST_FUNC void indir(void); -ST_FUNC void unary(void); -ST_FUNC void expr_prod(void); -ST_FUNC void expr_sum(void); -ST_FUNC void gexpr(void); -ST_FUNC int expr_const(void); -#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 -ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); -#endif -#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE -ST_FUNC int classify_x86_64_va_arg(CType *ty); -#endif - -/* ------------ tccelf.c ------------ */ - -#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ -#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ -#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ - -#define ARMAG "!\012" /* For COFF and a.out archives */ - -typedef struct { - unsigned int n_strx; /* index into string table of name */ - unsigned char n_type; /* type of symbol */ - unsigned char n_other; /* misc info (usually empty) */ - unsigned short n_desc; /* description field */ - unsigned int n_value; /* value of symbol */ -} Stab_Sym; - -ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ -ST_DATA Section *common_section; -ST_DATA Section *cur_text_section; /* current section where function code is generated */ -#ifdef CONFIG_TCC_ASM -ST_DATA Section *last_text_section; /* to handle .previous asm directive */ -#endif -#ifdef CONFIG_TCC_BCHECK -/* bound check related sections */ -ST_DATA Section *bounds_section; /* contains global data bound description */ -ST_DATA Section *lbounds_section; /* contains local data bound description */ -ST_FUNC void tccelf_bounds_new(TCCState *s); -#endif -/* symbol sections */ -ST_DATA Section *symtab_section, *strtab_section; -/* debug sections */ -ST_DATA Section *stab_section, *stabstr_section; - -ST_FUNC void tccelf_new(TCCState *s); -ST_FUNC void tccelf_delete(TCCState *s); -ST_FUNC void tccelf_stab_new(TCCState *s); - -ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); -ST_FUNC void section_realloc(Section *sec, unsigned long new_size); -ST_FUNC size_t section_add(Section *sec, addr_t size, int align); -ST_FUNC void *section_ptr_add(Section *sec, addr_t size); -ST_FUNC void section_reserve(Section *sec, unsigned long size); -ST_FUNC Section *find_section(TCCState *s1, const char *name); -ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags); - -ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore); -ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size); -#if PTR_SIZE == 4 -ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type); -#endif -ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); - -ST_FUNC int put_elf_str(Section *s, const char *sym); -ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); -ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); -ST_FUNC int find_elf_sym(Section *s, const char *name); -ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol); -ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend); - -ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value); -ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index); -ST_FUNC void put_stabn(int type, int other, int desc, int value); -ST_FUNC void put_stabd(int type, int other, int desc); - -ST_FUNC void relocate_common_syms(void); -ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve); -ST_FUNC void relocate_section(TCCState *s1, Section *s); - -ST_FUNC void tcc_add_linker_symbols(TCCState *s1); -ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h); -ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); -ST_FUNC int tcc_load_archive(TCCState *s1, int fd); -ST_FUNC void tcc_add_bcheck(TCCState *s1); -ST_FUNC void tcc_add_runtime(TCCState *s1); - -ST_FUNC void build_got_entries(TCCState *s1); -ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc); -ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset); - -ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err); -#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE -ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name); -#endif - -#ifndef TCC_TARGET_PE -ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); -ST_FUNC int tcc_load_ldscript(TCCState *s1); -ST_FUNC uint8_t *parse_comment(uint8_t *p); -ST_FUNC void minp(void); -ST_INLN void inp(void); -ST_FUNC int handle_eob(void); -#endif - -/* ------------ xxx-link.c ------------ */ - -/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so - that unknown relocation don't create a GOT or PLT entry */ -enum gotplt_entry { - NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */ - BUILD_GOT_ONLY, /* only build GOT (eg. TPOFF relocs) */ - AUTO_GOTPLT_ENTRY, /* generate if sym is UNDEF */ - ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */ -}; - -ST_FUNC int code_reloc (int reloc_type); -ST_FUNC int gotplt_entry_type (int reloc_type); -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); -ST_FUNC void relocate_init(Section *sr); -ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val); -ST_FUNC void relocate_plt(TCCState *s1); - -/* ------------ xxx-gen.c ------------ */ - -ST_DATA const int reg_classes[NB_REGS]; - -ST_FUNC void gsym_addr(int t, int a); -ST_FUNC void gsym(int t); -ST_FUNC void load(int r, SValue *sv); -ST_FUNC void store(int r, SValue *v); -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); -ST_FUNC void gfunc_call(int nb_args); -ST_FUNC void gfunc_prolog(CType *func_type); -ST_FUNC void gfunc_epilog(void); -ST_FUNC int gjmp(int t); -ST_FUNC void gjmp_addr(int a); -ST_FUNC int gtst(int inv, int t); -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC void gtst_addr(int inv, int a); -#else -#define gtst_addr(inv, a) gsym_addr(gtst(inv, 0), a) -#endif -ST_FUNC void gen_opi(int op); -ST_FUNC void gen_opf(int op); -ST_FUNC void gen_cvt_ftoi(int t); -ST_FUNC void gen_cvt_ftof(int t); -ST_FUNC void ggoto(void); -#ifndef TCC_TARGET_C67 -ST_FUNC void o(unsigned int c); -#endif -#ifndef TCC_TARGET_ARM -ST_FUNC void gen_cvt_itof(int t); -#endif -ST_FUNC void gen_vla_sp_save(int addr); -ST_FUNC void gen_vla_sp_restore(int addr); -ST_FUNC void gen_vla_alloc(CType *type, int align); - -static inline uint16_t read16le(unsigned char *p) { - return p[0] | (uint16_t)p[1] << 8; -} -static inline void write16le(unsigned char *p, uint16_t x) { - p[0] = x & 255; p[1] = x >> 8 & 255; -} -static inline uint32_t read32le(unsigned char *p) { - return read16le(p) | (uint32_t)read16le(p + 2) << 16; -} -static inline void write32le(unsigned char *p, uint32_t x) { - write16le(p, x); write16le(p + 2, x >> 16); -} -static inline void add32le(unsigned char *p, int32_t x) { - write32le(p, read32le(p) + x); -} -static inline uint64_t read64le(unsigned char *p) { - return read32le(p) | (uint64_t)read32le(p + 4) << 32; -} -static inline void write64le(unsigned char *p, uint64_t x) { - write32le(p, x); write32le(p + 4, x >> 32); -} -static inline void add64le(unsigned char *p, int64_t x) { - write64le(p, read64le(p) + x); -} - -/* ------------ i386-gen.c ------------ */ -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC void g(int c); -ST_FUNC void gen_le16(int c); -ST_FUNC void gen_le32(int c); -ST_FUNC void gen_addr32(int r, Sym *sym, int c); -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c); -#endif - -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void gen_bounded_ptr_add(void); -ST_FUNC void gen_bounded_ptr_deref(void); -#endif - -/* ------------ x86_64-gen.c ------------ */ -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c); -ST_FUNC void gen_opl(int op); -#endif - -/* ------------ arm-gen.c ------------ */ -#ifdef TCC_TARGET_ARM -#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) -PUB_FUNC const char *default_elfinterp(struct TCCState *s); -#endif -ST_FUNC void arm_init(struct TCCState *s); -ST_FUNC void gen_cvt_itof1(int t); -#endif - -/* ------------ arm64-gen.c ------------ */ -#ifdef TCC_TARGET_ARM64 -ST_FUNC void gen_cvt_sxtw(void); -ST_FUNC void gen_opl(int op); -ST_FUNC void gfunc_return(CType *func_type); -ST_FUNC void gen_va_start(void); -ST_FUNC void gen_va_arg(CType *t); -ST_FUNC void gen_clear_cache(void); -#endif - -/* ------------ c67-gen.c ------------ */ -#ifdef TCC_TARGET_C67 -#endif - -/* ------------ tcccoff.c ------------ */ - -#ifdef TCC_TARGET_COFF -ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f); -ST_FUNC int tcc_load_coff(TCCState * s1, int fd); -#endif - -/* ------------ tccasm.c ------------ */ -ST_FUNC void asm_instr(void); -ST_FUNC void asm_global_instr(void); -#ifdef CONFIG_TCC_ASM -ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); -ST_FUNC Sym* get_asm_sym(int name, Sym *csym); -ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); -ST_FUNC int asm_int_expr(TCCState *s1); -ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess); -/* ------------ i386-asm.c ------------ */ -ST_FUNC void gen_expr32(ExprValue *pe); -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_expr64(ExprValue *pe); -#endif -ST_FUNC void asm_opcode(TCCState *s1, int opcode); -ST_FUNC int asm_parse_regvar(int t); -ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); -ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier); -ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); -ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); -#endif - -/* ------------ tccpe.c -------------- */ -#ifdef TCC_TARGET_PE -ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd); -ST_FUNC int pe_output_file(TCCState * s1, const char *filename); -ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value); -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); -#endif -#ifdef TCC_TARGET_X86_64 -ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); -#endif -PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); -/* symbol properties stored in Elf32_Sym->st_other */ -# define ST_PE_EXPORT 0x10 -# define ST_PE_IMPORT 0x20 -# define ST_PE_STDCALL 0x40 -#endif -/* ------------ tccrun.c ----------------- */ -#ifdef TCC_IS_NATIVE -#ifdef CONFIG_TCC_STATIC -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 -#define RTLD_DEFAULT NULL -/* dummy function for profiling */ -ST_FUNC void *dlopen(const char *filename, int flag); -ST_FUNC void dlclose(void *p); -ST_FUNC const char *dlerror(void); -ST_FUNC void *dlsym(void *handle, const char *symbol); -#endif -#ifdef CONFIG_TCC_BACKTRACE -ST_DATA int rt_num_callers; -ST_DATA const char **rt_bound_error_msg; -ST_DATA void *rt_prog_main; -ST_FUNC void tcc_set_num_callers(int n); -#endif -ST_FUNC void tcc_run_free(TCCState *s1); -#endif - -/* ------------ tcctools.c ----------------- */ -#if 0 /* included in tcc.c */ -ST_FUNC int tcc_tool_ar(TCCState *s, int argc, char **argv); -#ifdef TCC_TARGET_PE -ST_FUNC int tcc_tool_impdef(TCCState *s, int argc, char **argv); -#endif -ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option); -ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename); -#endif - -/********************************************************/ -#undef ST_DATA -#if ONE_SOURCE -#define ST_DATA static -#else -#define ST_DATA -#endif -/********************************************************/ -#endif /* _TCC_H */ diff --git a/tinyc/tccasm.c b/tinyc/tccasm.c deleted file mode 100644 index ac1618a52..000000000 --- a/tinyc/tccasm.c +++ /dev/null @@ -1,1303 +0,0 @@ -/* - * GAS like assembler for TCC - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" -#ifdef CONFIG_TCC_ASM - -ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) -{ - char buf[64]; - TokenSym *ts; - - snprintf(buf, sizeof(buf), "L..%u", n); - ts = tok_alloc(buf, strlen(buf)); - return ts->tok; -} - -ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); -static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); -static Sym sym_dot; - -/* Return a symbol we can use inside the assembler, having name NAME. - The assembler symbol table is different from the C symbol table - (and the Sym members are used differently). But we must be able - to look up file-global C symbols from inside the assembler, e.g. - for global asm blocks to be able to refer to defined C symbols. - - This routine gives back either an existing asm-internal - symbol, or a new one. In the latter case the new asm-internal - symbol is initialized with info from the C symbol table. - - If CSYM is non-null we take symbol info from it, otherwise - we look up NAME in the C symbol table and use that. */ -ST_FUNC Sym* get_asm_sym(int name, Sym *csym) -{ - Sym *sym = label_find(name); - if (!sym) { - sym = label_push(&tcc_state->asm_labels, name, 0); - sym->type.t = VT_VOID | VT_EXTERN; - if (!csym) { - csym = sym_find(name); - /* We might be called for an asm block from inside a C routine - and so might have local decls on the identifier stack. Search - for the first global one. */ - while (csym && csym->sym_scope) - csym = csym->prev_tok; - } - /* Now, if we have a defined global symbol copy over - section and offset. */ - if (csym && - ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) && - csym->c) { - ElfW(Sym) *esym; - esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; - sym->c = csym->c; - sym->r = esym->st_shndx; - sym->jnext = esym->st_value; - /* XXX can't yet store st_size anywhere. */ - sym->type.t &= ~VT_EXTERN; - /* Mark that this asm symbol doesn't need to be fed back. */ - sym->a.dllimport = 1; - } else { - sym->type.t |= VT_STATIC; - } - } - return sym; -} - -/* We do not use the C expression parser to handle symbols. Maybe the - C expression parser could be tweaked to do so. */ - -static void asm_expr_unary(TCCState *s1, ExprValue *pe) -{ - Sym *sym; - int op, label; - uint64_t n; - const char *p; - - switch(tok) { - case TOK_PPNUM: - p = tokc.str.data; - n = strtoull(p, (char **)&p, 0); - if (*p == 'b' || *p == 'f') { - /* backward or forward label */ - label = asm_get_local_label_name(s1, n); - sym = label_find(label); - if (*p == 'b') { - /* backward : find the last corresponding defined label */ - if (sym && sym->r == 0) - sym = sym->prev_tok; - if (!sym) - tcc_error("local label '%d' not found backward", n); - } else { - /* forward */ - if (!sym || sym->r) { - /* if the last label is defined, then define a new one */ - sym = label_push(&s1->asm_labels, label, 0); - sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; - } - } - pe->v = 0; - pe->sym = sym; - pe->pcrel = 0; - } else if (*p == '\0') { - pe->v = n; - pe->sym = NULL; - pe->pcrel = 0; - } else { - tcc_error("invalid number syntax"); - } - next(); - break; - case '+': - next(); - asm_expr_unary(s1, pe); - break; - case '-': - case '~': - op = tok; - next(); - asm_expr_unary(s1, pe); - if (pe->sym) - tcc_error("invalid operation with label"); - if (op == '-') - pe->v = -pe->v; - else - pe->v = ~pe->v; - break; - case TOK_CCHAR: - case TOK_LCHAR: - pe->v = tokc.i; - pe->sym = NULL; - pe->pcrel = 0; - next(); - break; - case '(': - next(); - asm_expr(s1, pe); - skip(')'); - break; - case '.': - pe->v = 0; - pe->sym = &sym_dot; - pe->pcrel = 0; - sym_dot.type.t = VT_VOID | VT_STATIC; - sym_dot.r = cur_text_section->sh_num; - sym_dot.jnext = ind; - next(); - break; - default: - if (tok >= TOK_IDENT) { - /* label case : if the label was not found, add one */ - sym = get_asm_sym(tok, NULL); - if (sym->r == SHN_ABS) { - /* if absolute symbol, no need to put a symbol value */ - pe->v = sym->jnext; - pe->sym = NULL; - pe->pcrel = 0; - } else { - pe->v = 0; - pe->sym = sym; - pe->pcrel = 0; - } - next(); - } else { - tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); - } - break; - } -} - -static void asm_expr_prod(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_unary(s1, pe); - for(;;) { - op = tok; - if (op != '*' && op != '/' && op != '%' && - op != TOK_SHL && op != TOK_SAR) - break; - next(); - asm_expr_unary(s1, &e2); - if (pe->sym || e2.sym) - tcc_error("invalid operation with label"); - switch(op) { - case '*': - pe->v *= e2.v; - break; - case '/': - if (e2.v == 0) { - div_error: - tcc_error("division by zero"); - } - pe->v /= e2.v; - break; - case '%': - if (e2.v == 0) - goto div_error; - pe->v %= e2.v; - break; - case TOK_SHL: - pe->v <<= e2.v; - break; - default: - case TOK_SAR: - pe->v >>= e2.v; - break; - } - } -} - -static void asm_expr_logic(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_prod(s1, pe); - for(;;) { - op = tok; - if (op != '&' && op != '|' && op != '^') - break; - next(); - asm_expr_prod(s1, &e2); - if (pe->sym || e2.sym) - tcc_error("invalid operation with label"); - switch(op) { - case '&': - pe->v &= e2.v; - break; - case '|': - pe->v |= e2.v; - break; - default: - case '^': - pe->v ^= e2.v; - break; - } - } -} - -static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_logic(s1, pe); - for(;;) { - op = tok; - if (op != '+' && op != '-') - break; - next(); - asm_expr_logic(s1, &e2); - if (op == '+') { - if (pe->sym != NULL && e2.sym != NULL) - goto cannot_relocate; - pe->v += e2.v; - if (pe->sym == NULL && e2.sym != NULL) - pe->sym = e2.sym; - } else { - pe->v -= e2.v; - /* NOTE: we are less powerful than gas in that case - because we store only one symbol in the expression */ - if (!e2.sym) { - /* OK */ - } else if (pe->sym == e2.sym) { - /* OK */ - pe->sym = NULL; /* same symbols can be subtracted to NULL */ - } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) { - /* we also accept defined symbols in the same section */ - pe->v += pe->sym->jnext - e2.sym->jnext; - pe->sym = NULL; - } else if (e2.sym->r == cur_text_section->sh_num) { - /* When subtracting a defined symbol in current section - this actually makes the value PC-relative. */ - pe->v -= e2.sym->jnext - ind - 4; - pe->pcrel = 1; - e2.sym = NULL; - } else { - cannot_relocate: - tcc_error("invalid operation with label"); - } - } - } -} - -static inline void asm_expr_cmp(TCCState *s1, ExprValue *pe) -{ - int op; - ExprValue e2; - - asm_expr_sum(s1, pe); - for(;;) { - op = tok; - if (op != TOK_EQ && op != TOK_NE - && (op > TOK_GT || op < TOK_ULE)) - break; - next(); - asm_expr_sum(s1, &e2); - if (pe->sym || e2.sym) - tcc_error("invalid operation with label"); - switch(op) { - case TOK_EQ: - pe->v = pe->v == e2.v; - break; - case TOK_NE: - pe->v = pe->v != e2.v; - break; - case TOK_LT: - pe->v = (int64_t)pe->v < (int64_t)e2.v; - break; - case TOK_GE: - pe->v = (int64_t)pe->v >= (int64_t)e2.v; - break; - case TOK_LE: - pe->v = (int64_t)pe->v <= (int64_t)e2.v; - break; - case TOK_GT: - pe->v = (int64_t)pe->v > (int64_t)e2.v; - break; - default: - break; - } - /* GAS compare results are -1/0 not 1/0. */ - pe->v = -(int64_t)pe->v; - } -} - -ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe) -{ - asm_expr_cmp(s1, pe); -} - -ST_FUNC int asm_int_expr(TCCState *s1) -{ - ExprValue e; - asm_expr(s1, &e); - if (e.sym) - expect("constant"); - return e.v; -} - -/* NOTE: the same name space as C labels is used to avoid using too - much memory when storing labels in TokenStrings */ -static Sym* asm_new_label1(TCCState *s1, int label, int is_local, - int sh_num, int value) -{ - Sym *sym; - - sym = label_find(label); - if (sym) { - /* A VT_EXTERN symbol, even if it has a section is considered - overridable. This is how we "define" .set targets. Real - definitions won't have VT_EXTERN set. */ - if (sym->r && !(sym->type.t & VT_EXTERN)) { - /* the label is already defined */ - if (!is_local) { - tcc_error("assembler label '%s' already defined", - get_tok_str(label, NULL)); - } else { - /* redefinition of local labels is possible */ - goto new_label; - } - } - } else { - new_label: - sym = label_push(&s1->asm_labels, label, 0); - /* If we need a symbol to hold a value, mark it as - tentative only (for .set). If this is for a real label - we'll remove VT_EXTERN. */ - sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; - } - sym->r = sh_num; - sym->jnext = value; - return sym; -} - -static Sym* asm_new_label(TCCState *s1, int label, int is_local) -{ - return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind); -} - -/* Set the value of LABEL to that of some expression (possibly - involving other symbols). LABEL can be overwritten later still. */ -static Sym* set_symbol(TCCState *s1, int label) -{ - long n; - ExprValue e; - next(); - asm_expr(s1, &e); - n = e.v; - if (e.sym) - n += e.sym->jnext; - return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n); -} - -static void asm_free_labels(TCCState *st) -{ - Sym *s, *s1; - Section *sec; - - for(s = st->asm_labels; s != NULL; s = s1) { - s1 = s->prev; - /* define symbol value in object file */ - s->type.t &= ~VT_EXTERN; - if (s->r && !s->a.dllimport) { - if (s->r == SHN_ABS) - sec = SECTION_ABS; - else - sec = st->sections[s->r]; - put_extern_sym2(s, sec, s->jnext, 0, 0); - } - /* remove label */ - table_ident[s->v - TOK_IDENT]->sym_label = NULL; - sym_free(s); - } - st->asm_labels = NULL; -} - -static void use_section1(TCCState *s1, Section *sec) -{ - cur_text_section->data_offset = ind; - cur_text_section = sec; - ind = cur_text_section->data_offset; -} - -static void use_section(TCCState *s1, const char *name) -{ - Section *sec; - sec = find_section(s1, name); - use_section1(s1, sec); -} - -static void push_section(TCCState *s1, const char *name) -{ - Section *sec = find_section(s1, name); - sec->prev = cur_text_section; - use_section1(s1, sec); -} - -static void pop_section(TCCState *s1) -{ - Section *prev = cur_text_section->prev; - if (!prev) - tcc_error(".popsection without .pushsection"); - cur_text_section->prev = NULL; - use_section1(s1, prev); -} - -static void asm_parse_directive(TCCState *s1, int global) -{ - int n, offset, v, size, tok1; - Section *sec; - uint8_t *ptr; - - /* assembler directive */ - sec = cur_text_section; - switch(tok) { - case TOK_ASMDIR_align: - case TOK_ASMDIR_balign: - case TOK_ASMDIR_p2align: - case TOK_ASMDIR_skip: - case TOK_ASMDIR_space: - tok1 = tok; - next(); - n = asm_int_expr(s1); - if (tok1 == TOK_ASMDIR_p2align) - { - if (n < 0 || n > 30) - tcc_error("invalid p2align, must be between 0 and 30"); - n = 1 << n; - tok1 = TOK_ASMDIR_align; - } - if (tok1 == TOK_ASMDIR_align || tok1 == TOK_ASMDIR_balign) { - if (n < 0 || (n & (n-1)) != 0) - tcc_error("alignment must be a positive power of two"); - offset = (ind + n - 1) & -n; - size = offset - ind; - /* the section must have a compatible alignment */ - if (sec->sh_addralign < n) - sec->sh_addralign = n; - } else { - if (n < 0) - n = 0; - size = n; - } - v = 0; - if (tok == ',') { - next(); - v = asm_int_expr(s1); - } - zero_pad: - if (sec->sh_type != SHT_NOBITS) { - sec->data_offset = ind; - ptr = section_ptr_add(sec, size); - memset(ptr, v, size); - } - ind += size; - break; - case TOK_ASMDIR_quad: -#ifdef TCC_TARGET_X86_64 - size = 8; - goto asm_data; -#else - next(); - for(;;) { - uint64_t vl; - const char *p; - - p = tokc.str.data; - if (tok != TOK_PPNUM) { - error_constant: - tcc_error("64 bit constant"); - } - vl = strtoll(p, (char **)&p, 0); - if (*p != '\0') - goto error_constant; - next(); - if (sec->sh_type != SHT_NOBITS) { - /* XXX: endianness */ - gen_le32(vl); - gen_le32(vl >> 32); - } else { - ind += 8; - } - if (tok != ',') - break; - next(); - } - break; -#endif - case TOK_ASMDIR_byte: - size = 1; - goto asm_data; - case TOK_ASMDIR_word: - case TOK_ASMDIR_short: - size = 2; - goto asm_data; - case TOK_ASMDIR_long: - case TOK_ASMDIR_int: - size = 4; - asm_data: - next(); - for(;;) { - ExprValue e; - asm_expr(s1, &e); - if (sec->sh_type != SHT_NOBITS) { - if (size == 4) { - gen_expr32(&e); -#ifdef TCC_TARGET_X86_64 - } else if (size == 8) { - gen_expr64(&e); -#endif - } else { - if (e.sym) - expect("constant"); - if (size == 1) - g(e.v); - else - gen_le16(e.v); - } - } else { - ind += size; - } - if (tok != ',') - break; - next(); - } - break; - case TOK_ASMDIR_fill: - { - int repeat, size, val, i, j; - uint8_t repeat_buf[8]; - next(); - repeat = asm_int_expr(s1); - if (repeat < 0) { - tcc_error("repeat < 0; .fill ignored"); - break; - } - size = 1; - val = 0; - if (tok == ',') { - next(); - size = asm_int_expr(s1); - if (size < 0) { - tcc_error("size < 0; .fill ignored"); - break; - } - if (size > 8) - size = 8; - if (tok == ',') { - next(); - val = asm_int_expr(s1); - } - } - /* XXX: endianness */ - repeat_buf[0] = val; - repeat_buf[1] = val >> 8; - repeat_buf[2] = val >> 16; - repeat_buf[3] = val >> 24; - repeat_buf[4] = 0; - repeat_buf[5] = 0; - repeat_buf[6] = 0; - repeat_buf[7] = 0; - for(i = 0; i < repeat; i++) { - for(j = 0; j < size; j++) { - g(repeat_buf[j]); - } - } - } - break; - case TOK_ASMDIR_rept: - { - int repeat; - TokenString *init_str; - next(); - repeat = asm_int_expr(s1); - init_str = tok_str_alloc(); - while (next(), tok != TOK_ASMDIR_endr) { - if (tok == CH_EOF) - tcc_error("we at end of file, .endr not found"); - tok_str_add_tok(init_str); - } - tok_str_add(init_str, -1); - tok_str_add(init_str, 0); - begin_macro(init_str, 1); - while (repeat-- > 0) { - tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS), - global); - macro_ptr = init_str->str; - } - end_macro(); - next(); - break; - } - case TOK_ASMDIR_org: - { - unsigned long n; - ExprValue e; - next(); - asm_expr(s1, &e); - n = e.v; - if (e.sym) { - if (e.sym->r != cur_text_section->sh_num) - expect("constant or same-section symbol"); - n += e.sym->jnext; - } - if (n < ind) - tcc_error("attempt to .org backwards"); - v = 0; - size = n - ind; - goto zero_pad; - } - break; - case TOK_ASMDIR_set: - next(); - tok1 = tok; - next(); - /* Also accept '.set stuff', but don't do anything with this. - It's used in GAS to set various features like '.set mips16'. */ - if (tok == ',') - set_symbol(s1, tok1); - break; - case TOK_ASMDIR_globl: - case TOK_ASMDIR_global: - case TOK_ASMDIR_weak: - case TOK_ASMDIR_hidden: - tok1 = tok; - do { - Sym *sym; - - next(); - sym = get_asm_sym(tok, NULL); - if (tok1 != TOK_ASMDIR_hidden) - sym->type.t &= ~VT_STATIC; - if (tok1 == TOK_ASMDIR_weak) - sym->a.weak = 1; - else if (tok1 == TOK_ASMDIR_hidden) - sym->a.visibility = STV_HIDDEN; - next(); - } while (tok == ','); - break; - case TOK_ASMDIR_string: - case TOK_ASMDIR_ascii: - case TOK_ASMDIR_asciz: - { - const uint8_t *p; - int i, size, t; - - t = tok; - next(); - for(;;) { - if (tok != TOK_STR) - expect("string constant"); - p = tokc.str.data; - size = tokc.str.size; - if (t == TOK_ASMDIR_ascii && size > 0) - size--; - for(i = 0; i < size; i++) - g(p[i]); - next(); - if (tok == ',') { - next(); - } else if (tok != TOK_STR) { - break; - } - } - } - break; - case TOK_ASMDIR_text: - case TOK_ASMDIR_data: - case TOK_ASMDIR_bss: - { - char sname[64]; - tok1 = tok; - n = 0; - next(); - if (tok != ';' && tok != TOK_LINEFEED) { - n = asm_int_expr(s1); - next(); - } - if (n) - sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n); - else - sprintf(sname, "%s", get_tok_str(tok1, NULL)); - use_section(s1, sname); - } - break; - case TOK_ASMDIR_file: - { - char filename[512]; - - filename[0] = '\0'; - next(); - - if (tok == TOK_STR) - pstrcat(filename, sizeof(filename), tokc.str.data); - else - pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); - - if (s1->warn_unsupported) - tcc_warning("ignoring .file %s", filename); - - next(); - } - break; - case TOK_ASMDIR_ident: - { - char ident[256]; - - ident[0] = '\0'; - next(); - - if (tok == TOK_STR) - pstrcat(ident, sizeof(ident), tokc.str.data); - else - pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); - - if (s1->warn_unsupported) - tcc_warning("ignoring .ident %s", ident); - - next(); - } - break; - case TOK_ASMDIR_size: - { - Sym *sym; - - next(); - sym = label_find(tok); - if (!sym) { - tcc_error("label not found: %s", get_tok_str(tok, NULL)); - } - - /* XXX .size name,label2-label1 */ - if (s1->warn_unsupported) - tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); - - next(); - skip(','); - while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { - next(); - } - } - break; - case TOK_ASMDIR_type: - { - Sym *sym; - const char *newtype; - - next(); - sym = get_asm_sym(tok, NULL); - next(); - skip(','); - if (tok == TOK_STR) { - newtype = tokc.str.data; - } else { - if (tok == '@' || tok == '%') - next(); - newtype = get_tok_str(tok, NULL); - } - - if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { - sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; - } - else if (s1->warn_unsupported) - tcc_warning("change type of '%s' from 0x%x to '%s' ignored", - get_tok_str(sym->v, NULL), sym->type.t, newtype); - - next(); - } - break; - case TOK_ASMDIR_pushsection: - case TOK_ASMDIR_section: - { - char sname[256]; - int old_nb_section = s1->nb_sections; - - tok1 = tok; - /* XXX: support more options */ - next(); - sname[0] = '\0'; - while (tok != ';' && tok != TOK_LINEFEED && tok != ',') { - if (tok == TOK_STR) - pstrcat(sname, sizeof(sname), tokc.str.data); - else - pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); - next(); - } - if (tok == ',') { - /* skip section options */ - next(); - if (tok != TOK_STR) - expect("string constant"); - next(); - if (tok == ',') { - next(); - if (tok == '@' || tok == '%') - next(); - next(); - } - } - last_text_section = cur_text_section; - if (tok1 == TOK_ASMDIR_section) - use_section(s1, sname); - else - push_section(s1, sname); - /* If we just allocated a new section reset its alignment to - 1. new_section normally acts for GCC compatibility and - sets alignment to PTR_SIZE. The assembler behaves different. */ - if (old_nb_section != s1->nb_sections) - cur_text_section->sh_addralign = 1; - } - break; - case TOK_ASMDIR_previous: - { - Section *sec; - next(); - if (!last_text_section) - tcc_error("no previous section referenced"); - sec = cur_text_section; - use_section1(s1, last_text_section); - last_text_section = sec; - } - break; - case TOK_ASMDIR_popsection: - next(); - pop_section(s1); - break; -#ifdef TCC_TARGET_I386 - case TOK_ASMDIR_code16: - { - next(); - s1->seg_size = 16; - } - break; - case TOK_ASMDIR_code32: - { - next(); - s1->seg_size = 32; - } - break; -#endif -#ifdef TCC_TARGET_X86_64 - /* added for compatibility with GAS */ - case TOK_ASMDIR_code64: - next(); - break; -#endif - default: - tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); - break; - } -} - - -/* assemble a file */ -static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) -{ - int opcode; - int saved_parse_flags = parse_flags; - - /* XXX: undefine C labels */ - parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; - if (do_preprocess) - parse_flags |= PARSE_FLAG_PREPROCESS; - for(;;) { - next(); - if (tok == TOK_EOF) - break; - /* generate line number info */ - if (global && s1->do_debug) - tcc_debug_line(s1); - parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ - redo: - if (tok == '#') { - /* horrible gas comment */ - while (tok != TOK_LINEFEED) - next(); - } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { - asm_parse_directive(s1, global); - } else if (tok == TOK_PPNUM) { - Sym *sym; - const char *p; - int n; - p = tokc.str.data; - n = strtoul(p, (char **)&p, 10); - if (*p != '\0') - expect("':'"); - /* new local label */ - sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1); - /* Remove the marker for tentative definitions. */ - sym->type.t &= ~VT_EXTERN; - next(); - skip(':'); - goto redo; - } else if (tok >= TOK_IDENT) { - /* instruction or label */ - opcode = tok; - next(); - if (tok == ':') { - /* handle "extern void vide(void); __asm__("vide: ret");" as - "__asm__("globl vide\nvide: ret");" */ - Sym *sym = sym_find(opcode); - if (sym && (sym->type.t & VT_EXTERN) && global) { - sym = label_find(opcode); - if (!sym) { - sym = label_push(&s1->asm_labels, opcode, 0); - sym->type.t = VT_VOID | VT_EXTERN; - } - } - /* new label */ - sym = asm_new_label(s1, opcode, 0); - sym->type.t &= ~VT_EXTERN; - next(); - goto redo; - } else if (tok == '=') { - set_symbol(s1, opcode); - goto redo; - } else { - asm_opcode(s1, opcode); - } - } - /* end of line */ - if (tok != ';' && tok != TOK_LINEFEED) - expect("end of line"); - parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ - } - - asm_free_labels(s1); - parse_flags = saved_parse_flags; - return 0; -} - -/* Assemble the current file */ -ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) -{ - int ret; - tcc_debug_start(s1); - /* default section is text */ - cur_text_section = text_section; - ind = cur_text_section->data_offset; - nocode_wanted = 0; - ret = tcc_assemble_internal(s1, do_preprocess, 1); - cur_text_section->data_offset = ind; - tcc_debug_end(s1); - return ret; -} - -/********************************************************************/ -/* GCC inline asm support */ - -/* assemble the string 'str' in the current C compilation unit without - C preprocessing. NOTE: str is modified by modifying the '\0' at the - end */ -static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global) -{ - const int *saved_macro_ptr = macro_ptr; - int dotid = set_idnum('.', IS_ID); - - tcc_open_bf(s1, ":asm:", len); - memcpy(file->buffer, str, len); - macro_ptr = NULL; - tcc_assemble_internal(s1, 0, global); - tcc_close(); - - set_idnum('.', dotid); - macro_ptr = saved_macro_ptr; -} - -/* find a constraint by its number or id (gcc 3 extended - syntax). return -1 if not found. Return in *pp in char after the - constraint */ -ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, - const char *name, const char **pp) -{ - int index; - TokenSym *ts; - const char *p; - - if (isnum(*name)) { - index = 0; - while (isnum(*name)) { - index = (index * 10) + (*name) - '0'; - name++; - } - if ((unsigned)index >= nb_operands) - index = -1; - } else if (*name == '[') { - name++; - p = strchr(name, ']'); - if (p) { - ts = tok_alloc(name, p - name); - for(index = 0; index < nb_operands; index++) { - if (operands[index].id == ts->tok) - goto found; - } - index = -1; - found: - name = p + 1; - } else { - index = -1; - } - } else { - index = -1; - } - if (pp) - *pp = name; - return index; -} - -static void subst_asm_operands(ASMOperand *operands, int nb_operands, - CString *out_str, CString *in_str) -{ - int c, index, modifier; - const char *str; - ASMOperand *op; - SValue sv; - - cstr_new(out_str); - str = in_str->data; - for(;;) { - c = *str++; - if (c == '%') { - if (*str == '%') { - str++; - goto add_char; - } - modifier = 0; - if (*str == 'c' || *str == 'n' || - *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' || - *str == 'q' || - /* P in GCC would add "@PLT" to symbol refs in PIC mode, - and make literal operands not be decorated with '$'. */ - *str == 'P') - modifier = *str++; - index = find_constraint(operands, nb_operands, str, &str); - if (index < 0) - tcc_error("invalid operand reference after %%"); - op = &operands[index]; - sv = *op->vt; - if (op->reg >= 0) { - sv.r = op->reg; - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) - sv.r |= VT_LVAL; - } - subst_asm_operand(out_str, &sv, modifier); - } else { - add_char: - cstr_ccat(out_str, c); - if (c == '\0') - break; - } - } -} - - -static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, - int is_output) -{ - ASMOperand *op; - int nb_operands; - - if (tok != ':') { - nb_operands = *nb_operands_ptr; - for(;;) { - CString astr; - if (nb_operands >= MAX_ASM_OPERANDS) - tcc_error("too many asm operands"); - op = &operands[nb_operands++]; - op->id = 0; - if (tok == '[') { - next(); - if (tok < TOK_IDENT) - expect("identifier"); - op->id = tok; - next(); - skip(']'); - } - parse_mult_str(&astr, "string constant"); - op->constraint = tcc_malloc(astr.size); - strcpy(op->constraint, astr.data); - cstr_free(&astr); - skip('('); - gexpr(); - if (is_output) { - if (!(vtop->type.t & VT_ARRAY)) - test_lvalue(); - } else { - /* we want to avoid LLOCAL case, except when the 'm' - constraint is used. Note that it may come from - register storage, so we need to convert (reg) - case */ - if ((vtop->r & VT_LVAL) && - ((vtop->r & VT_VALMASK) == VT_LLOCAL || - (vtop->r & VT_VALMASK) < VT_CONST) && - !strchr(op->constraint, 'm')) { - gv(RC_INT); - } - } - op->vt = vtop; - skip(')'); - if (tok == ',') { - next(); - } else { - break; - } - } - *nb_operands_ptr = nb_operands; - } -} - -/* parse the GCC asm() instruction */ -ST_FUNC void asm_instr(void) -{ - CString astr, astr1; - ASMOperand operands[MAX_ASM_OPERANDS]; - int nb_outputs, nb_operands, i, must_subst, out_reg; - uint8_t clobber_regs[NB_ASM_REGS]; - - next(); - /* since we always generate the asm() instruction, we can ignore - volatile */ - if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) { - next(); - } - parse_asm_str(&astr); - nb_operands = 0; - nb_outputs = 0; - must_subst = 0; - memset(clobber_regs, 0, sizeof(clobber_regs)); - if (tok == ':') { - next(); - must_subst = 1; - /* output args */ - parse_asm_operands(operands, &nb_operands, 1); - nb_outputs = nb_operands; - if (tok == ':') { - next(); - if (tok != ')') { - /* input args */ - parse_asm_operands(operands, &nb_operands, 0); - if (tok == ':') { - /* clobber list */ - /* XXX: handle registers */ - next(); - for(;;) { - if (tok != TOK_STR) - expect("string constant"); - asm_clobber(clobber_regs, tokc.str.data); - next(); - if (tok == ',') { - next(); - } else { - break; - } - } - } - } - } - } - skip(')'); - /* NOTE: we do not eat the ';' so that we can restore the current - token after the assembler parsing */ - if (tok != ';') - expect("';'"); - - /* save all values in the memory */ - save_regs(0); - - /* compute constraints */ - asm_compute_constraints(operands, nb_operands, nb_outputs, - clobber_regs, &out_reg); - - /* substitute the operands in the asm string. No substitution is - done if no operands (GCC behaviour) */ -#ifdef ASM_DEBUG - printf("asm: \"%s\"\n", (char *)astr.data); -#endif - if (must_subst) { - subst_asm_operands(operands, nb_operands, &astr1, &astr); - cstr_free(&astr); - } else { - astr1 = astr; - } -#ifdef ASM_DEBUG - printf("subst_asm: \"%s\"\n", (char *)astr1.data); -#endif - - /* generate loads */ - asm_gen_code(operands, nb_operands, nb_outputs, 0, - clobber_regs, out_reg); - - /* assemble the string with tcc internal assembler */ - tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0); - - /* restore the current C token */ - next(); - - /* store the output values if needed */ - asm_gen_code(operands, nb_operands, nb_outputs, 1, - clobber_regs, out_reg); - - /* free everything */ - for(i=0;iconstraint); - vpop(); - } - cstr_free(&astr1); -} - -ST_FUNC void asm_global_instr(void) -{ - CString astr; - int saved_nocode_wanted = nocode_wanted; - - /* Global asm blocks are always emitted. */ - nocode_wanted = 0; - next(); - parse_asm_str(&astr); - skip(')'); - /* NOTE: we do not eat the ';' so that we can restore the current - token after the assembler parsing */ - if (tok != ';') - expect("';'"); - -#ifdef ASM_DEBUG - printf("asm_global: \"%s\"\n", (char *)astr.data); -#endif - cur_text_section = text_section; - ind = cur_text_section->data_offset; - - /* assemble the string with tcc internal assembler */ - tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 1); - - cur_text_section->data_offset = ind; - - /* restore the current C token */ - next(); - - cstr_free(&astr); - nocode_wanted = saved_nocode_wanted; -} -#endif /* CONFIG_TCC_ASM */ diff --git a/tinyc/tcccoff.c b/tinyc/tcccoff.c deleted file mode 100644 index 1421ca265..000000000 --- a/tinyc/tcccoff.c +++ /dev/null @@ -1,948 +0,0 @@ -/* - * COFF file handling for TCC - * - * Copyright (c) 2003, 2004 TK - * Copyright (c) 2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -#define MAXNSCNS 255 /* MAXIMUM NUMBER OF SECTIONS */ -#define MAX_STR_TABLE 1000000 -AOUTHDR o_filehdr; /* OPTIONAL (A.OUT) FILE HEADER */ - -SCNHDR section_header[MAXNSCNS]; - -#define MAX_FUNCS 1000 -#define MAX_FUNC_NAME_LENGTH 128 - -int nFuncs; -char Func[MAX_FUNCS][MAX_FUNC_NAME_LENGTH]; -char AssociatedFile[MAX_FUNCS][MAX_FUNC_NAME_LENGTH]; -int LineNoFilePtr[MAX_FUNCS]; -int EndAddress[MAX_FUNCS]; -int LastLineNo[MAX_FUNCS]; -int FuncEntries[MAX_FUNCS]; - -int OutputTheSection(Section * sect); -short int GetCoffFlags(const char *s); -void SortSymbolTable(void); -Section *FindSection(TCCState * s1, const char *sname); - -int C67_main_entry_point; - -int FindCoffSymbolIndex(const char *func_name); -int nb_syms; - -typedef struct { - long tag; - long size; - long fileptr; - long nextsym; - short int dummy; -} AUXFUNC; - -typedef struct { - long regmask; - unsigned short lineno; - unsigned short nentries; - int localframe; - int nextentry; - short int dummy; -} AUXBF; - -typedef struct { - long dummy; - unsigned short lineno; - unsigned short dummy1; - int dummy2; - int dummy3; - unsigned short dummy4; -} AUXEF; - -ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f) -{ - Section *tcc_sect; - SCNHDR *coff_sec; - int file_pointer; - char *Coff_str_table, *pCoff_str_table; - int CoffTextSectionNo, coff_nb_syms; - FILHDR file_hdr; /* FILE HEADER STRUCTURE */ - Section *stext, *sdata, *sbss; - int i, NSectionsToOutput = 0; - - Coff_str_table = pCoff_str_table = NULL; - - stext = FindSection(s1, ".text"); - sdata = FindSection(s1, ".data"); - sbss = FindSection(s1, ".bss"); - - nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); - coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1"); - - file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */ - file_hdr.f_timdat = 0; /* time & date stamp */ - file_hdr.f_opthdr = sizeof(AOUTHDR); /* sizeof(optional hdr) */ - file_hdr.f_flags = 0x1143; /* flags (copied from what code composer does) */ - file_hdr.f_TargetID = 0x99; /* for C6x = 0x0099 */ - - o_filehdr.magic = 0x0108; /* see magic.h */ - o_filehdr.vstamp = 0x0190; /* version stamp */ - o_filehdr.tsize = stext->data_offset; /* text size in bytes, padded to FW bdry */ - o_filehdr.dsize = sdata->data_offset; /* initialized data " " */ - o_filehdr.bsize = sbss->data_offset; /* uninitialized data " " */ - o_filehdr.entrypt = C67_main_entry_point; /* entry pt. */ - o_filehdr.text_start = stext->sh_addr; /* base of text used for this file */ - o_filehdr.data_start = sdata->sh_addr; /* base of data used for this file */ - - - // create all the section headers - - file_pointer = FILHSZ + sizeof(AOUTHDR); - - CoffTextSectionNo = -1; - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - NSectionsToOutput++; - - if (CoffTextSectionNo == -1 && tcc_sect == stext) - CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is - - strcpy(coff_sec->s_name, tcc_sect->name); /* section name */ - - coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */ - coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */ - coff_sec->s_size = tcc_sect->data_offset; /* section size */ - coff_sec->s_scnptr = 0; /* file ptr to raw data for section */ - coff_sec->s_relptr = 0; /* file ptr to relocation */ - coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */ - coff_sec->s_nreloc = 0; /* number of relocation entries */ - coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */ - coff_sec->s_reserved = 0; /* reserved byte */ - coff_sec->s_page = 0; /* memory page id */ - - file_pointer += sizeof(SCNHDR); - } - } - - file_hdr.f_nscns = NSectionsToOutput; /* number of sections */ - - // now loop through and determine file pointer locations - // for the raw data - - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - // put raw data - coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */ - file_pointer += coff_sec->s_size; - } - } - - // now loop through and determine file pointer locations - // for the relocation data - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - // put relocations data - if (coff_sec->s_nreloc > 0) { - coff_sec->s_relptr = file_pointer; /* file ptr to relocation */ - file_pointer += coff_sec->s_nreloc * sizeof(struct reloc); - } - } - } - - // now loop through and determine file pointer locations - // for the line number data - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - coff_sec->s_nlnno = 0; - coff_sec->s_lnnoptr = 0; - - if (s1->do_debug && tcc_sect == stext) { - // count how many line nos data - - // also find association between source file name and function - // so we can sort the symbol table - - - Stab_Sym *sym, *sym_end; - char func_name[MAX_FUNC_NAME_LENGTH], - last_func_name[MAX_FUNC_NAME_LENGTH]; - unsigned long func_addr, last_pc, pc; - const char *incl_files[INCLUDE_STACK_SIZE]; - int incl_index, len, last_line_num; - const char *str, *p; - - coff_sec->s_lnnoptr = file_pointer; /* file ptr to linno */ - - - func_name[0] = '\0'; - func_addr = 0; - incl_index = 0; - last_func_name[0] = '\0'; - last_pc = 0xffffffff; - last_line_num = 1; - sym = (Stab_Sym *) stab_section->data + 1; - sym_end = - (Stab_Sym *) (stab_section->data + - stab_section->data_offset); - - nFuncs = 0; - while (sym < sym_end) { - switch (sym->n_type) { - /* function start or end */ - case N_FUN: - if (sym->n_strx == 0) { - // end of function - - coff_sec->s_nlnno++; - file_pointer += LINESZ; - - pc = sym->n_value + func_addr; - func_name[0] = '\0'; - func_addr = 0; - EndAddress[nFuncs] = pc; - FuncEntries[nFuncs] = - (file_pointer - - LineNoFilePtr[nFuncs]) / LINESZ - 1; - LastLineNo[nFuncs++] = last_line_num + 1; - } else { - // beginning of function - - LineNoFilePtr[nFuncs] = file_pointer; - coff_sec->s_nlnno++; - file_pointer += LINESZ; - - str = - (const char *) stabstr_section->data + - sym->n_strx; - - p = strchr(str, ':'); - if (!p) { - pstrcpy(func_name, sizeof(func_name), str); - pstrcpy(Func[nFuncs], sizeof(func_name), str); - } else { - len = p - str; - if (len > sizeof(func_name) - 1) - len = sizeof(func_name) - 1; - memcpy(func_name, str, len); - memcpy(Func[nFuncs], str, len); - func_name[len] = '\0'; - } - - // save the file that it came in so we can sort later - pstrcpy(AssociatedFile[nFuncs], sizeof(func_name), - incl_files[incl_index - 1]); - - func_addr = sym->n_value; - } - break; - - /* line number info */ - case N_SLINE: - pc = sym->n_value + func_addr; - - last_pc = pc; - last_line_num = sym->n_desc; - - /* XXX: slow! */ - strcpy(last_func_name, func_name); - - coff_sec->s_nlnno++; - file_pointer += LINESZ; - break; - /* include files */ - case N_BINCL: - str = - (const char *) stabstr_section->data + sym->n_strx; - add_incl: - if (incl_index < INCLUDE_STACK_SIZE) { - incl_files[incl_index++] = str; - } - break; - case N_EINCL: - if (incl_index > 1) - incl_index--; - break; - case N_SO: - if (sym->n_strx == 0) { - incl_index = 0; /* end of translation unit */ - } else { - str = - (const char *) stabstr_section->data + - sym->n_strx; - /* do not add path */ - len = strlen(str); - if (len > 0 && str[len - 1] != '/') - goto add_incl; - } - break; - } - sym++; - } - } - - } - - file_hdr.f_symptr = file_pointer; /* file pointer to symtab */ - - if (s1->do_debug) - file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */ - else - file_hdr.f_nsyms = 0; - - file_pointer += file_hdr.f_nsyms * SYMNMLEN; - - // OK now we are all set to write the file - - - fwrite(&file_hdr, FILHSZ, 1, f); - fwrite(&o_filehdr, sizeof(o_filehdr), 1, f); - - // write section headers - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - fwrite(coff_sec, sizeof(SCNHDR), 1, f); - } - } - - // write raw data - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f); - } - } - - // write relocation data - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (OutputTheSection(tcc_sect)) { - // put relocations data - if (coff_sec->s_nreloc > 0) { - fwrite(tcc_sect->reloc, - coff_sec->s_nreloc * sizeof(struct reloc), 1, f); - } - } - } - - - // group the symbols in order of filename, func1, func2, etc - // finally global symbols - - if (s1->do_debug) - SortSymbolTable(); - - // write line no data - - for (i = 1; i < s1->nb_sections; i++) { - coff_sec = §ion_header[i]; - tcc_sect = s1->sections[i]; - - if (s1->do_debug && tcc_sect == stext) { - // count how many line nos data - - - Stab_Sym *sym, *sym_end; - char func_name[128], last_func_name[128]; - unsigned long func_addr, last_pc, pc; - const char *incl_files[INCLUDE_STACK_SIZE]; - int incl_index, len, last_line_num; - const char *str, *p; - - LINENO CoffLineNo; - - func_name[0] = '\0'; - func_addr = 0; - incl_index = 0; - last_func_name[0] = '\0'; - last_pc = 0; - last_line_num = 1; - sym = (Stab_Sym *) stab_section->data + 1; - sym_end = - (Stab_Sym *) (stab_section->data + - stab_section->data_offset); - - while (sym < sym_end) { - switch (sym->n_type) { - /* function start or end */ - case N_FUN: - if (sym->n_strx == 0) { - // end of function - - CoffLineNo.l_addr.l_paddr = last_pc; - CoffLineNo.l_lnno = last_line_num + 1; - fwrite(&CoffLineNo, 6, 1, f); - - pc = sym->n_value + func_addr; - func_name[0] = '\0'; - func_addr = 0; - } else { - // beginning of function - - str = - (const char *) stabstr_section->data + - sym->n_strx; - - - p = strchr(str, ':'); - if (!p) { - pstrcpy(func_name, sizeof(func_name), str); - } else { - len = p - str; - if (len > sizeof(func_name) - 1) - len = sizeof(func_name) - 1; - memcpy(func_name, str, len); - func_name[len] = '\0'; - } - func_addr = sym->n_value; - last_pc = func_addr; - last_line_num = -1; - - // output a function begin - - CoffLineNo.l_addr.l_symndx = - FindCoffSymbolIndex(func_name); - CoffLineNo.l_lnno = 0; - - fwrite(&CoffLineNo, 6, 1, f); - } - break; - - /* line number info */ - case N_SLINE: - pc = sym->n_value + func_addr; - - - /* XXX: slow! */ - strcpy(last_func_name, func_name); - - // output a line reference - - CoffLineNo.l_addr.l_paddr = last_pc; - - if (last_line_num == -1) { - CoffLineNo.l_lnno = sym->n_desc; - } else { - CoffLineNo.l_lnno = last_line_num + 1; - } - - fwrite(&CoffLineNo, 6, 1, f); - - last_pc = pc; - last_line_num = sym->n_desc; - - break; - - /* include files */ - case N_BINCL: - str = - (const char *) stabstr_section->data + sym->n_strx; - add_incl2: - if (incl_index < INCLUDE_STACK_SIZE) { - incl_files[incl_index++] = str; - } - break; - case N_EINCL: - if (incl_index > 1) - incl_index--; - break; - case N_SO: - if (sym->n_strx == 0) { - incl_index = 0; /* end of translation unit */ - } else { - str = - (const char *) stabstr_section->data + - sym->n_strx; - /* do not add path */ - len = strlen(str); - if (len > 0 && str[len - 1] != '/') - goto add_incl2; - } - break; - } - sym++; - } - } - } - - // write symbol table - if (s1->do_debug) { - int k; - struct syment csym; - AUXFUNC auxfunc; - AUXBF auxbf; - AUXEF auxef; - int i; - Elf32_Sym *p; - const char *name; - int nstr; - int n = 0; - - Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE); - pCoff_str_table = Coff_str_table; - nstr = 0; - - p = (Elf32_Sym *) symtab_section->data; - - - for (i = 0; i < nb_syms; i++) { - - name = symtab_section->link->data + p->st_name; - - for (k = 0; k < 8; k++) - csym._n._n_name[k] = 0; - - if (strlen(name) <= 8) { - strcpy(csym._n._n_name, name); - } else { - if (pCoff_str_table - Coff_str_table + strlen(name) > - MAX_STR_TABLE - 1) - tcc_error("String table too large"); - - csym._n._n_n._n_zeroes = 0; - csym._n._n_n._n_offset = - pCoff_str_table - Coff_str_table + 4; - - strcpy(pCoff_str_table, name); - pCoff_str_table += strlen(name) + 1; // skip over null - nstr++; - } - - if (p->st_info == 4) { - // put a filename symbol - csym.n_value = 33; // ????? - csym.n_scnum = N_DEBUG; - csym.n_type = 0; - csym.n_sclass = C_FILE; - csym.n_numaux = 0; - fwrite(&csym, 18, 1, f); - n++; - - } else if (p->st_info == 0x12) { - // find the function data - - for (k = 0; k < nFuncs; k++) { - if (strcmp(name, Func[k]) == 0) - break; - } - - if (k >= nFuncs) { - tcc_error("debug info can't find function: %s", name); - } - // put a Function Name - - csym.n_value = p->st_value; // physical address - csym.n_scnum = CoffTextSectionNo; - csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0); - csym.n_sclass = C_EXT; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - // now put aux info - - auxfunc.tag = 0; - auxfunc.size = EndAddress[k] - p->st_value; - auxfunc.fileptr = LineNoFilePtr[k]; - auxfunc.nextsym = n + 6; // tktk - auxfunc.dummy = 0; - fwrite(&auxfunc, 18, 1, f); - - // put a .bf - - strcpy(csym._n._n_name, ".bf"); - csym.n_value = p->st_value; // physical address - csym.n_scnum = CoffTextSectionNo; - csym.n_type = 0; - csym.n_sclass = C_FCN; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - // now put aux info - - auxbf.regmask = 0; - auxbf.lineno = 0; - auxbf.nentries = FuncEntries[k]; - auxbf.localframe = 0; - auxbf.nextentry = n + 6; - auxbf.dummy = 0; - fwrite(&auxbf, 18, 1, f); - - // put a .ef - - strcpy(csym._n._n_name, ".ef"); - csym.n_value = EndAddress[k]; // physical address - csym.n_scnum = CoffTextSectionNo; - csym.n_type = 0; - csym.n_sclass = C_FCN; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - // now put aux info - - auxef.dummy = 0; - auxef.lineno = LastLineNo[k]; - auxef.dummy1 = 0; - auxef.dummy2 = 0; - auxef.dummy3 = 0; - auxef.dummy4 = 0; - fwrite(&auxef, 18, 1, f); - - n += 6; - - } else { - // try an put some type info - - if ((p->st_other & VT_BTYPE) == VT_DOUBLE) { - csym.n_type = T_DOUBLE; // int - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_FLOAT) { - csym.n_type = T_FLOAT; - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_INT) { - csym.n_type = T_INT; // int - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_SHORT) { - csym.n_type = T_SHORT; - csym.n_sclass = C_EXT; - } else if ((p->st_other & VT_BTYPE) == VT_BYTE) { - csym.n_type = T_CHAR; - csym.n_sclass = C_EXT; - } else { - csym.n_type = T_INT; // just mark as a label - csym.n_sclass = C_LABEL; - } - - - csym.n_value = p->st_value; - csym.n_scnum = 2; - csym.n_numaux = 1; - fwrite(&csym, 18, 1, f); - - auxfunc.tag = 0; - auxfunc.size = 0x20; - auxfunc.fileptr = 0; - auxfunc.nextsym = 0; - auxfunc.dummy = 0; - fwrite(&auxfunc, 18, 1, f); - n++; - n++; - - } - - p++; - } - } - - if (s1->do_debug) { - // write string table - - // first write the size - i = pCoff_str_table - Coff_str_table; - fwrite(&i, 4, 1, f); - - // then write the strings - fwrite(Coff_str_table, i, 1, f); - - tcc_free(Coff_str_table); - } - - return 0; -} - - - -// group the symbols in order of filename, func1, func2, etc -// finally global symbols - -void SortSymbolTable(void) -{ - int i, j, k, n = 0; - Elf32_Sym *p, *p2, *NewTable; - char *name, *name2; - - NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym)); - - p = (Elf32_Sym *) symtab_section->data; - - - // find a file symbol, copy it over - // then scan the whole symbol list and copy any function - // symbols that match the file association - - for (i = 0; i < nb_syms; i++) { - if (p->st_info == 4) { - name = (char *) symtab_section->link->data + p->st_name; - - // this is a file symbol, copy it over - - NewTable[n++] = *p; - - p2 = (Elf32_Sym *) symtab_section->data; - - for (j = 0; j < nb_syms; j++) { - if (p2->st_info == 0x12) { - // this is a func symbol - - name2 = - (char *) symtab_section->link->data + p2->st_name; - - // find the function data index - - for (k = 0; k < nFuncs; k++) { - if (strcmp(name2, Func[k]) == 0) - break; - } - - if (k >= nFuncs) { - tcc_error("debug (sort) info can't find function: %s", name2); - } - - if (strcmp(AssociatedFile[k], name) == 0) { - // yes they match copy it over - - NewTable[n++] = *p2; - } - } - p2++; - } - } - p++; - } - - // now all the filename and func symbols should have been copied over - // copy all the rest over (all except file and funcs) - - p = (Elf32_Sym *) symtab_section->data; - for (i = 0; i < nb_syms; i++) { - if (p->st_info != 4 && p->st_info != 0x12) { - NewTable[n++] = *p; - } - p++; - } - - if (n != nb_syms) - tcc_error("Internal Compiler error, debug info"); - - // copy it all back - - p = (Elf32_Sym *) symtab_section->data; - for (i = 0; i < nb_syms; i++) { - *p++ = NewTable[i]; - } - - tcc_free(NewTable); -} - - -int FindCoffSymbolIndex(const char *func_name) -{ - int i, n = 0; - Elf32_Sym *p; - char *name; - - p = (Elf32_Sym *) symtab_section->data; - - for (i = 0; i < nb_syms; i++) { - - name = (char *) symtab_section->link->data + p->st_name; - - if (p->st_info == 4) { - // put a filename symbol - n++; - } else if (p->st_info == 0x12) { - - if (strcmp(func_name, name) == 0) - return n; - - n += 6; - - // put a Function Name - - // now put aux info - - // put a .bf - - // now put aux info - - // put a .ef - - // now put aux info - - } else { - n += 2; - } - - p++; - } - - return n; // total number of symbols -} - -int OutputTheSection(Section * sect) -{ - const char *s = sect->name; - - if (!strcmp(s, ".text")) - return 1; - else if (!strcmp(s, ".data")) - return 1; - else - return 0; -} - -short int GetCoffFlags(const char *s) -{ - if (!strcmp(s, ".text")) - return STYP_TEXT | STYP_DATA | STYP_ALIGN | 0x400; - else if (!strcmp(s, ".data")) - return STYP_DATA; - else if (!strcmp(s, ".bss")) - return STYP_BSS; - else if (!strcmp(s, ".stack")) - return STYP_BSS | STYP_ALIGN | 0x200; - else if (!strcmp(s, ".cinit")) - return STYP_COPY | STYP_DATA | STYP_ALIGN | 0x200; - else - return 0; -} - -Section *FindSection(TCCState * s1, const char *sname) -{ - Section *s; - int i; - - for (i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - - if (!strcmp(sname, s->name)) - return s; - } - - tcc_error("could not find section %s", sname); - return 0; -} - -ST_FUNC int tcc_load_coff(TCCState * s1, int fd) -{ -// tktk TokenSym *ts; - - FILE *f; - unsigned int str_size; - char *Coff_str_table, *name; - int i, k; - struct syment csym; - char name2[9]; - FILHDR file_hdr; /* FILE HEADER STRUCTURE */ - - f = fdopen(fd, "rb"); - if (!f) { - tcc_error("Unable to open .out file for input"); - } - - if (fread(&file_hdr, FILHSZ, 1, f) != 1) - tcc_error("error reading .out file for input"); - - if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1) - tcc_error("error reading .out file for input"); - - // first read the string table - - if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET)) - tcc_error("error reading .out file for input"); - - if (fread(&str_size, sizeof(int), 1, f) != 1) - tcc_error("error reading .out file for input"); - - - Coff_str_table = (char *) tcc_malloc(str_size); - - if (fread(Coff_str_table, str_size - 4, 1, f) != 1) - tcc_error("error reading .out file for input"); - - // read/process all the symbols - - // seek back to symbols - - if (fseek(f, file_hdr.f_symptr, SEEK_SET)) - tcc_error("error reading .out file for input"); - - for (i = 0; i < file_hdr.f_nsyms; i++) { - if (fread(&csym, SYMESZ, 1, f) != 1) - tcc_error("error reading .out file for input"); - - if (csym._n._n_n._n_zeroes == 0) { - name = Coff_str_table + csym._n._n_n._n_offset - 4; - } else { - name = csym._n._n_name; - - if (name[7] != 0) { - for (k = 0; k < 8; k++) - name2[k] = name[k]; - - name2[8] = 0; - - name = name2; - } - } -// if (strcmp("_DAC_Buffer",name)==0) // tktk -// name[0]=0; - - if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) || // structures - (csym.n_type == 0x18 && csym.n_sclass == 0x2) || // pointer to structure - (csym.n_type == 0x7 && csym.n_sclass == 0x2) || // doubles - (csym.n_type == 0x6 && csym.n_sclass == 0x2)) // floats - { - // strip off any leading underscore (except for other main routine) - - if (name[0] == '_' && strcmp(name, "_main") != 0) - name++; - - tcc_add_symbol(s1, name, (void*)(uintptr_t)csym.n_value); - } - // skip any aux records - - if (csym.n_numaux == 1) { - if (fread(&csym, SYMESZ, 1, f) != 1) - tcc_error("error reading .out file for input"); - i++; - } - } - - return 0; -} diff --git a/tinyc/tccelf.c b/tinyc/tccelf.c deleted file mode 100644 index 22ce5df9c..000000000 --- a/tinyc/tccelf.c +++ /dev/null @@ -1,2994 +0,0 @@ -/* - * ELF file handling for TCC - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -/* Define this to get some debug output during relocation processing. */ -#undef DEBUG_RELOC - -/********************************************************/ -/* global variables */ - -ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ -ST_DATA Section *common_section; -ST_DATA Section *cur_text_section; /* current section where function code is generated */ -#ifdef CONFIG_TCC_ASM -ST_DATA Section *last_text_section; /* to handle .previous asm directive */ -#endif -#ifdef CONFIG_TCC_BCHECK -/* bound check related sections */ -ST_DATA Section *bounds_section; /* contains global data bound description */ -ST_DATA Section *lbounds_section; /* contains local data bound description */ -#endif -/* symbol sections */ -ST_DATA Section *symtab_section, *strtab_section; -/* debug sections */ -ST_DATA Section *stab_section, *stabstr_section; - -/* XXX: avoid static variable */ -static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ - -/* ------------------------------------------------------------------------- */ - -ST_FUNC void tccelf_new(TCCState *s) -{ - /* no section zero */ - dynarray_add(&s->sections, &s->nb_sections, NULL); - - /* create standard sections */ - text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); - common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); - common_section->sh_num = SHN_COMMON; - - /* symbols are always generated for linking stage */ - symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, - ".strtab", - ".hashtab", SHF_PRIVATE); - strtab_section = symtab_section->link; - s->symtab = symtab_section; - - /* private symbol table for dynamic symbols */ - s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, - ".dynstrtab", - ".dynhashtab", SHF_PRIVATE); - get_sym_attr(s, 0, 1); -} - -#ifdef CONFIG_TCC_BCHECK -ST_FUNC void tccelf_bounds_new(TCCState *s) -{ - /* create bounds sections */ - bounds_section = new_section(s, ".bounds", - SHT_PROGBITS, SHF_ALLOC); - lbounds_section = new_section(s, ".lbounds", - SHT_PROGBITS, SHF_ALLOC); -} -#endif - -ST_FUNC void tccelf_stab_new(TCCState *s) -{ - stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); - stab_section->sh_entsize = sizeof(Stab_Sym); - stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); - put_elf_str(stabstr_section, ""); - stab_section->link = stabstr_section; - /* put first entry */ - put_stabs("", 0, 0, 0, 0); -} - -static void free_section(Section *s) -{ - tcc_free(s->data); -} - -ST_FUNC void tccelf_delete(TCCState *s1) -{ - int i; - - /* free all sections */ - for(i = 1; i < s1->nb_sections; i++) - free_section(s1->sections[i]); - dynarray_reset(&s1->sections, &s1->nb_sections); - - for(i = 0; i < s1->nb_priv_sections; i++) - free_section(s1->priv_sections[i]); - dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); - - /* free any loaded DLLs */ -#ifdef TCC_IS_NATIVE - for ( i = 0; i < s1->nb_loaded_dlls; i++) { - DLLReference *ref = s1->loaded_dlls[i]; - if ( ref->handle ) -# ifdef _WIN32 - FreeLibrary((HMODULE)ref->handle); -# else - dlclose(ref->handle); -# endif - } -#endif - /* free loaded dlls array */ - dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); - tcc_free(s1->sym_attrs); -} - -ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) -{ - Section *sec; - - sec = tcc_mallocz(sizeof(Section) + strlen(name)); - strcpy(sec->name, name); - sec->sh_type = sh_type; - sec->sh_flags = sh_flags; - switch(sh_type) { - case SHT_HASH: - case SHT_REL: - case SHT_RELA: - case SHT_DYNSYM: - case SHT_SYMTAB: - case SHT_DYNAMIC: - sec->sh_addralign = 4; - break; - case SHT_STRTAB: - sec->sh_addralign = 1; - break; - default: - sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */ - break; - } - - if (sh_flags & SHF_PRIVATE) { - dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec); - } else { - sec->sh_num = s1->nb_sections; - dynarray_add(&s1->sections, &s1->nb_sections, sec); - } - - return sec; -} - -ST_FUNC Section *new_symtab(TCCState *s1, - const char *symtab_name, int sh_type, int sh_flags, - const char *strtab_name, - const char *hash_name, int hash_sh_flags) -{ - Section *symtab, *strtab, *hash; - int *ptr, nb_buckets; - - symtab = new_section(s1, symtab_name, sh_type, sh_flags); - symtab->sh_entsize = sizeof(ElfW(Sym)); - strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); - put_elf_str(strtab, ""); - symtab->link = strtab; - put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); - - nb_buckets = 1; - - hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); - hash->sh_entsize = sizeof(int); - symtab->hash = hash; - hash->link = symtab; - - ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); - ptr[0] = nb_buckets; - ptr[1] = 1; - memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); - return symtab; -} - -/* realloc section and set its content to zero */ -ST_FUNC void section_realloc(Section *sec, unsigned long new_size) -{ - unsigned long size; - unsigned char *data; - - size = sec->data_allocated; - if (size == 0) - size = 1; - while (size < new_size) - size = size * 2; - data = tcc_realloc(sec->data, size); - memset(data + sec->data_allocated, 0, size - sec->data_allocated); - sec->data = data; - sec->data_allocated = size; -} - -/* reserve at least 'size' bytes aligned per 'align' in section - 'sec' from current offset, and return the aligned offset */ -ST_FUNC size_t section_add(Section *sec, addr_t size, int align) -{ - size_t offset, offset1; - - offset = (sec->data_offset + align - 1) & -align; - offset1 = offset + size; - if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated) - section_realloc(sec, offset1); - sec->data_offset = offset1; - if (align > sec->sh_addralign) - sec->sh_addralign = align; - return offset; -} - -/* reserve at least 'size' bytes in section 'sec' from - sec->data_offset. */ -ST_FUNC void *section_ptr_add(Section *sec, addr_t size) -{ - size_t offset = section_add(sec, size, 1); - return sec->data + offset; -} - -/* reserve at least 'size' bytes from section start */ -ST_FUNC void section_reserve(Section *sec, unsigned long size) -{ - if (size > sec->data_allocated) - section_realloc(sec, size); - if (size > sec->data_offset) - sec->data_offset = size; -} - -/* return a reference to a section, and create it if it does not - exists */ -ST_FUNC Section *find_section(TCCState *s1, const char *name) -{ - Section *sec; - int i; - for(i = 1; i < s1->nb_sections; i++) { - sec = s1->sections[i]; - if (!strcmp(name, sec->name)) - return sec; - } - /* sections are created as PROGBITS */ - return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); -} - -/* ------------------------------------------------------------------------- */ - -ST_FUNC int put_elf_str(Section *s, const char *sym) -{ - int offset, len; - char *ptr; - - len = strlen(sym) + 1; - offset = s->data_offset; - ptr = section_ptr_add(s, len); - memcpy(ptr, sym, len); - return offset; -} - -/* elf symbol hashing function */ -static unsigned long elf_hash(const unsigned char *name) -{ - unsigned long h = 0, g; - - while (*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - if (g) - h ^= g >> 24; - h &= ~g; - } - return h; -} - -/* rebuild hash table of section s */ -/* NOTE: we do factorize the hash table code to go faster */ -static void rebuild_hash(Section *s, unsigned int nb_buckets) -{ - ElfW(Sym) *sym; - int *ptr, *hash, nb_syms, sym_index, h; - unsigned char *strtab; - - strtab = s->link->data; - nb_syms = s->data_offset / sizeof(ElfW(Sym)); - - s->hash->data_offset = 0; - ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); - ptr[0] = nb_buckets; - ptr[1] = nb_syms; - ptr += 2; - hash = ptr; - memset(hash, 0, (nb_buckets + 1) * sizeof(int)); - ptr += nb_buckets + 1; - - sym = (ElfW(Sym) *)s->data + 1; - for(sym_index = 1; sym_index < nb_syms; sym_index++) { - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - h = elf_hash(strtab + sym->st_name) % nb_buckets; - *ptr = hash[h]; - hash[h] = sym_index; - } else { - *ptr = 0; - } - ptr++; - sym++; - } -} - -/* return the symbol number */ -ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, - int info, int other, int shndx, const char *name) -{ - int name_offset, sym_index; - int nbuckets, h; - ElfW(Sym) *sym; - Section *hs; - - sym = section_ptr_add(s, sizeof(ElfW(Sym))); - if (name) - name_offset = put_elf_str(s->link, name); - else - name_offset = 0; - /* XXX: endianness */ - sym->st_name = name_offset; - sym->st_value = value; - sym->st_size = size; - sym->st_info = info; - sym->st_other = other; - sym->st_shndx = shndx; - sym_index = sym - (ElfW(Sym) *)s->data; - hs = s->hash; - if (hs) { - int *ptr, *base; - ptr = section_ptr_add(hs, sizeof(int)); - base = (int *)hs->data; - /* only add global or weak symbols */ - if (ELFW(ST_BIND)(info) != STB_LOCAL) { - /* add another hashing entry */ - nbuckets = base[0]; - h = elf_hash((unsigned char *) name) % nbuckets; - *ptr = base[2 + h]; - base[2 + h] = sym_index; - base[1]++; - /* we resize the hash table */ - hs->nb_hashed_syms++; - if (hs->nb_hashed_syms > 2 * nbuckets) { - rebuild_hash(s, 2 * nbuckets); - } - } else { - *ptr = 0; - base[1]++; - } - } - return sym_index; -} - -/* find global ELF symbol 'name' and return its index. Return 0 if not - found. */ -ST_FUNC int find_elf_sym(Section *s, const char *name) -{ - ElfW(Sym) *sym; - Section *hs; - int nbuckets, sym_index, h; - const char *name1; - - hs = s->hash; - if (!hs) - return 0; - nbuckets = ((int *)hs->data)[0]; - h = elf_hash((unsigned char *) name) % nbuckets; - sym_index = ((int *)hs->data)[2 + h]; - while (sym_index != 0) { - sym = &((ElfW(Sym) *)s->data)[sym_index]; - name1 = (char *) s->link->data + sym->st_name; - if (!strcmp(name, name1)) - return sym_index; - sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; - } - return 0; -} - -/* return elf symbol value, signal error if 'err' is nonzero */ -ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err) -{ - int sym_index; - ElfW(Sym) *sym; - - sym_index = find_elf_sym(s->symtab, name); - sym = &((ElfW(Sym) *)s->symtab->data)[sym_index]; - if (!sym_index || sym->st_shndx == SHN_UNDEF) { - if (err) - tcc_error("%s not defined", name); - return 0; - } - return sym->st_value; -} - -/* return elf symbol value */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) -{ - return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0); -} - -#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE -/* return elf symbol value or error */ -ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name) -{ - return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1); -} -#endif - -/* add an elf symbol : check if it is already defined and patch - it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ -ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, - int info, int other, int shndx, const char *name) -{ - ElfW(Sym) *esym; - int sym_bind, sym_index, sym_type, esym_bind; - unsigned char sym_vis, esym_vis, new_vis; - - sym_bind = ELFW(ST_BIND)(info); - sym_type = ELFW(ST_TYPE)(info); - sym_vis = ELFW(ST_VISIBILITY)(other); - - sym_index = find_elf_sym(s, name); - esym = &((ElfW(Sym) *)s->data)[sym_index]; - if (sym_index && esym->st_value == value && esym->st_size == size - && esym->st_info == info && esym->st_other == other - && esym->st_shndx == shndx) - return sym_index; - - if (sym_bind != STB_LOCAL) { - /* we search global or weak symbols */ - if (!sym_index) - goto do_def; - if (esym->st_shndx != SHN_UNDEF) { - esym_bind = ELFW(ST_BIND)(esym->st_info); - /* propagate the most constraining visibility */ - /* STV_DEFAULT(0)st_other); - if (esym_vis == STV_DEFAULT) { - new_vis = sym_vis; - } else if (sym_vis == STV_DEFAULT) { - new_vis = esym_vis; - } else { - new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; - } - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) - | new_vis; - other = esym->st_other; /* in case we have to patch esym */ - if (shndx == SHN_UNDEF) { - /* ignore adding of undefined symbol if the - corresponding symbol is already defined */ - } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { - /* global overrides weak, so patch */ - goto do_patch; - } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { - /* weak is ignored if already global */ - } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { - /* keep first-found weak definition, ignore subsequents */ - } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { - /* ignore hidden symbols after */ - } else if ((esym->st_shndx == SHN_COMMON - || esym->st_shndx == bss_section->sh_num) - && (shndx < SHN_LORESERVE - && shndx != bss_section->sh_num)) { - /* data symbol gets precedence over common/bss */ - goto do_patch; - } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) { - /* data symbol keeps precedence over common/bss */ - } else if (s == tcc_state->dynsymtab_section) { - /* we accept that two DLL define the same symbol */ - } else { -#if 0 - printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", - sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis); -#endif - tcc_error_noabort("'%s' defined twice", name); - } - } else { - do_patch: - esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); - esym->st_shndx = shndx; - new_undef_sym = 1; - esym->st_value = value; - esym->st_size = size; - esym->st_other = other; - } - } else { - do_def: - sym_index = put_elf_sym(s, value, size, - ELFW(ST_INFO)(sym_bind, sym_type), other, - shndx, name); - } - return sym_index; -} - -/* put relocation */ -ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, - int type, int symbol, addr_t addend) -{ - char buf[256]; - Section *sr; - ElfW_Rel *rel; - - sr = s->reloc; - if (!sr) { - /* if no relocation section, create it */ - snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); - /* if the symtab is allocated, then we consider the relocation - are also */ - sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags); - sr->sh_entsize = sizeof(ElfW_Rel); - sr->link = symtab; - sr->sh_info = s->sh_num; - s->reloc = sr; - } - rel = section_ptr_add(sr, sizeof(ElfW_Rel)); - rel->r_offset = offset; - rel->r_info = ELFW(R_INFO)(symbol, type); -#if SHT_RELX == SHT_RELA - rel->r_addend = addend; -#else - if (addend) - tcc_error("non-zero addend on REL architecture"); -#endif -} - -ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, - int type, int symbol) -{ - put_elf_reloca(symtab, s, offset, type, symbol, 0); -} - -/* Remove relocations for section S->reloc starting at oldrelocoffset - that are to the same place, retaining the last of them. As side effect - the relocations are sorted. Possibly reduces the number of relocs. */ -ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset) -{ - Section *sr = s->reloc; - ElfW_Rel *r, *dest; - ssize_t a; - ElfW(Addr) addr; - - if (oldrelocoffset + sizeof(*r) >= sr->data_offset) - return; - /* The relocs we're dealing with are the result of initializer parsing. - So they will be mostly in order and there aren't many of them. - Secondly we need a stable sort (which qsort isn't). We use - a simple insertion sort. */ - for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) { - ssize_t i = a - sizeof(*r); - addr = ((ElfW_Rel*)(sr->data + a))->r_offset; - for (; i >= (ssize_t)oldrelocoffset && - ((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) { - ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a); - *(ElfW_Rel*)(sr->data + a) = *(ElfW_Rel*)(sr->data + i); - *(ElfW_Rel*)(sr->data + i) = tmp; - } - } - - r = (ElfW_Rel*)(sr->data + oldrelocoffset); - dest = r; - for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) { - if (dest->r_offset != r->r_offset) - dest++; - *dest = *r; - } - sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r); -} - -/* put stab debug information */ - -ST_FUNC void put_stabs(const char *str, int type, int other, int desc, - unsigned long value) -{ - Stab_Sym *sym; - - sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); - if (str) { - sym->n_strx = put_elf_str(stabstr_section, str); - } else { - sym->n_strx = 0; - } - sym->n_type = type; - sym->n_other = other; - sym->n_desc = desc; - sym->n_value = value; -} - -ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, - unsigned long value, Section *sec, int sym_index) -{ - put_stabs(str, type, other, desc, value); - put_elf_reloc(symtab_section, stab_section, - stab_section->data_offset - sizeof(unsigned int), - R_DATA_32, sym_index); -} - -ST_FUNC void put_stabn(int type, int other, int desc, int value) -{ - put_stabs(NULL, type, other, desc, value); -} - -ST_FUNC void put_stabd(int type, int other, int desc) -{ - put_stabs(NULL, type, other, desc, 0); -} - -ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc) -{ - int n; - struct sym_attr *tab; - - if (index >= s1->nb_sym_attrs) { - if (!alloc) - return s1->sym_attrs; - /* find immediately bigger power of 2 and reallocate array */ - n = 1; - while (index >= n) - n *= 2; - tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); - s1->sym_attrs = tab; - memset(s1->sym_attrs + s1->nb_sym_attrs, 0, - (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); - s1->nb_sym_attrs = n; - } - return &s1->sym_attrs[index]; -} - -/* Browse each elem of type in section starting at elem - using variable */ -#define for_each_elem(sec, startoff, elem, type) \ - for (elem = (type *) sec->data + startoff; \ - elem < (type *) (sec->data + sec->data_offset); elem++) - -/* In an ELF file symbol table, the local symbols must appear below - the global and weak ones. Since TCC cannot sort it while generating - the code, we must do it after. All the relocation tables are also - modified to take into account the symbol table sorting */ -static void sort_syms(TCCState *s1, Section *s) -{ - int *old_to_new_syms; - ElfW(Sym) *new_syms; - int nb_syms, i; - ElfW(Sym) *p, *q; - ElfW_Rel *rel; - Section *sr; - int type, sym_index; - - nb_syms = s->data_offset / sizeof(ElfW(Sym)); - new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); - old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); - - /* first pass for local symbols */ - p = (ElfW(Sym) *)s->data; - q = new_syms; - for(i = 0; i < nb_syms; i++) { - if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - p++; - } - /* save the number of local symbols in section header */ - if( s->sh_size ) /* this 'if' makes IDA happy */ - s->sh_info = q - new_syms; - - /* then second pass for non local symbols */ - p = (ElfW(Sym) *)s->data; - for(i = 0; i < nb_syms; i++) { - if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - p++; - } - - /* we copy the new symbols to the old */ - memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); - tcc_free(new_syms); - - /* now we modify all the relocations */ - for(i = 1; i < s1->nb_sections; i++) { - sr = s1->sections[i]; - if (sr->sh_type == SHT_RELX && sr->link == s) { - for_each_elem(sr, 0, rel, ElfW_Rel) { - sym_index = ELFW(R_SYM)(rel->r_info); - type = ELFW(R_TYPE)(rel->r_info); - sym_index = old_to_new_syms[sym_index]; - rel->r_info = ELFW(R_INFO)(sym_index, type); - } - } - } - - tcc_free(old_to_new_syms); -} - -/* relocate common symbols in the .bss section */ -ST_FUNC void relocate_common_syms(void) -{ - ElfW(Sym) *sym; - - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_COMMON) { - /* symbol alignment is in st_value for SHN_COMMONs */ - sym->st_value = section_add(bss_section, sym->st_size, - sym->st_value); - sym->st_shndx = bss_section->sh_num; - } - } -} - -/* relocate symbol table, resolve undefined symbols if do_resolve is - true and output error if undefined symbol. */ -ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) -{ - ElfW(Sym) *sym; - int sym_bind, sh_num; - const char *name; - - for_each_elem(symtab, 1, sym, ElfW(Sym)) { - sh_num = sym->st_shndx; - if (sh_num == SHN_UNDEF) { - name = (char *) strtab_section->data + sym->st_name; - /* Use ld.so to resolve symbol for us (for tcc -run) */ - if (do_resolve) { -#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE - void *addr = dlsym(RTLD_DEFAULT, name); - if (addr) { - sym->st_value = (addr_t) addr; -#ifdef DEBUG_RELOC - printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value); -#endif - goto found; - } -#endif - /* if dynamic symbol exist, it will be used in relocate_section */ - } else if (s1->dynsym && find_elf_sym(s1->dynsym, name)) - goto found; - /* XXX: _fp_hw seems to be part of the ABI, so we ignore - it */ - if (!strcmp(name, "_fp_hw")) - goto found; - /* only weak symbols are accepted to be undefined. Their - value is zero */ - sym_bind = ELFW(ST_BIND)(sym->st_info); - if (sym_bind == STB_WEAK) - sym->st_value = 0; - else - tcc_error_noabort("undefined symbol '%s'", name); - } else if (sh_num < SHN_LORESERVE) { - /* add section base */ - sym->st_value += s1->sections[sym->st_shndx]->sh_addr; - } - found: ; - } -} - -/* relocate a given section (CPU dependent) by applying the relocations - in the associated relocation section */ -ST_FUNC void relocate_section(TCCState *s1, Section *s) -{ - Section *sr = s->reloc; - ElfW_Rel *rel; - ElfW(Sym) *sym; - int type, sym_index; - unsigned char *ptr; - addr_t tgt, addr; - - relocate_init(sr); - - for_each_elem(sr, 0, rel, ElfW_Rel) { - ptr = s->data + rel->r_offset; - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - type = ELFW(R_TYPE)(rel->r_info); - tgt = sym->st_value; -#if SHT_RELX == SHT_RELA - tgt += rel->r_addend; -#endif - addr = s->sh_addr + rel->r_offset; - relocate(s1, rel, type, ptr, addr, tgt); - } - /* if the relocation is allocated, we change its symbol table */ - if (sr->sh_flags & SHF_ALLOC) - sr->link = s1->dynsym; -} - -/* relocate relocation table in 'sr' */ -static void relocate_rel(TCCState *s1, Section *sr) -{ - Section *s; - ElfW_Rel *rel; - - s = s1->sections[sr->sh_info]; - for_each_elem(sr, 0, rel, ElfW_Rel) - rel->r_offset += s->sh_addr; -} - -/* count the number of dynamic relocations so that we can reserve - their space */ -static int prepare_dynamic_rel(TCCState *s1, Section *sr) -{ - ElfW_Rel *rel; - int sym_index, type, count; - - count = 0; - for_each_elem(sr, 0, rel, ElfW_Rel) { - sym_index = ELFW(R_SYM)(rel->r_info); - type = ELFW(R_TYPE)(rel->r_info); - switch(type) { -#if defined(TCC_TARGET_I386) - case R_386_32: - if (!get_sym_attr(s1, sym_index, 0)->dyn_index - && ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) { - /* don't fixup unresolved (weak) symbols */ - rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE); - break; - } -#elif defined(TCC_TARGET_X86_64) - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: -#endif - count++; - break; -#if defined(TCC_TARGET_I386) - case R_386_PC32: -#elif defined(TCC_TARGET_X86_64) - case R_X86_64_PC32: -#endif - if (get_sym_attr(s1, sym_index, 0)->dyn_index) - count++; - break; - default: - break; - } - } - if (count) { - /* allocate the section */ - sr->sh_flags |= SHF_ALLOC; - sr->sh_size = count * sizeof(ElfW_Rel); - } - return count; -} - -static void build_got(TCCState *s1) -{ - /* if no got, then create it */ - s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - s1->got->sh_entsize = 4; - set_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), - 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); - /* keep space for _DYNAMIC pointer and two dummy got entries */ - section_ptr_add(s1->got, 3 * PTR_SIZE); -} - -/* Create a GOT and (for function call) a PLT entry corresponding to a symbol - in s1->symtab. When creating the dynamic symbol table entry for the GOT - relocation, use 'size' and 'info' for the corresponding symbol metadata. - Returns the offset of the GOT or (if any) PLT entry. */ -static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type, - unsigned long size, - int info, int sym_index) -{ - int need_plt_entry; - const char *name; - ElfW(Sym) *sym; - struct sym_attr *attr; - unsigned got_offset; - char plt_name[100]; - int len; - - need_plt_entry = (dyn_reloc_type == R_JMP_SLOT); - attr = get_sym_attr(s1, sym_index, 1); - - /* In case a function is both called and its address taken 2 GOT entries - are created, one for taking the address (GOT) and the other for the PLT - entry (PLTGOT). */ - if (need_plt_entry ? attr->plt_offset : attr->got_offset) - return attr; - - /* create the GOT entry */ - got_offset = s1->got->data_offset; - section_ptr_add(s1->got, PTR_SIZE); - - /* Create the GOT relocation that will insert the address of the object or - function of interest in the GOT entry. This is a static relocation for - memory output (dlsym will give us the address of symbols) and dynamic - relocation otherwise (executable and DLLs). The relocation should be - done lazily for GOT entry with *_JUMP_SLOT relocation type (the one - associated to a PLT entry) but is currently done at load time for an - unknown reason. */ - - sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - name = (char *) symtab_section->link->data + sym->st_name; - - if (s1->dynsym) { - if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - /* Hack alarm. We don't want to emit dynamic symbols - and symbol based relocs for STB_LOCAL symbols, but rather - want to resolve them directly. At this point the symbol - values aren't final yet, so we must defer this. We will later - have to create a RELATIVE reloc anyway, so we misuse the - relocation slot to smuggle the symbol reference until - fill_local_got_entries. Not that the sym_index is - relative to symtab_section, not s1->dynsym! Nevertheless - we use s1->dyn_sym so that if this is the first call - that got->reloc is correctly created. Also note that - RELATIVE relocs are not normally created for the .got, - so the types serves as a marker for later (and is retained - also for the final output, which is okay because then the - got is just normal data). */ - put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE, - sym_index); - } else { - if (0 == attr->dyn_index) - attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size, - info, 0, sym->st_shndx, name); - put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type, - attr->dyn_index); - } - } else { - put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type, - sym_index); - } - - if (need_plt_entry) { - if (!s1->plt) { - s1->plt = new_section(s1, ".plt", SHT_PROGBITS, - SHF_ALLOC | SHF_EXECINSTR); - s1->plt->sh_entsize = 4; - } - - attr->plt_offset = create_plt_entry(s1, got_offset, attr); - - /* create a symbol 'sym@plt' for the PLT jump vector */ - len = strlen(name); - if (len > sizeof plt_name - 5) - len = sizeof plt_name - 5; - memcpy(plt_name, name, len); - strcpy(plt_name + len, "@plt"); - attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, sym->st_size, - ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name); - - } else { - attr->got_offset = got_offset; - } - - return attr; -} - -/* build GOT and PLT entries */ -ST_FUNC void build_got_entries(TCCState *s1) -{ - Section *s; - ElfW_Rel *rel; - ElfW(Sym) *sym; - int i, type, gotplt_entry, reloc_type, sym_index; - struct sym_attr *attr; - - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX) - continue; - /* no need to handle got relocations */ - if (s->link != symtab_section) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - type = ELFW(R_TYPE)(rel->r_info); - gotplt_entry = gotplt_entry_type(type); - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - - if (gotplt_entry == NO_GOTPLT_ENTRY) { - continue; - } - - /* Automatically create PLT/GOT [entry] if it is an undefined - reference (resolved at runtime), or the symbol is absolute, - probably created by tcc_add_symbol, and thus on 64-bit - targets might be too far from application code. */ - if (gotplt_entry == AUTO_GOTPLT_ENTRY) { - if (sym->st_shndx == SHN_UNDEF) { - ElfW(Sym) *esym; - int dynindex; - if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT) - continue; - /* Relocations for UNDEF symbols would normally need - to be transferred into the executable or shared object. - If that were done AUTO_GOTPLT_ENTRY wouldn't exist. - But TCC doesn't do that (at least for exes), so we - need to resolve all such relocs locally. And that - means PLT slots for functions in DLLs and COPY relocs for - data symbols. COPY relocs were generated in - bind_exe_dynsyms (and the symbol adjusted to be defined), - and for functions we were generated a dynamic symbol - of function type. */ - if (s1->dynsym) { - /* dynsym isn't set for -run :-/ */ - dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index; - esym = (ElfW(Sym) *)s1->dynsym->data + dynindex; - if (dynindex - && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC - || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE - && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC))) - goto jmp_slot; - } - } else if (!(sym->st_shndx == SHN_ABS -#ifndef TCC_TARGET_ARM - && PTR_SIZE == 8 -#endif - )) - continue; - } - -#ifdef TCC_TARGET_X86_64 - if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) && - (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || - ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)) { - rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); - continue; - } -#endif - if (code_reloc(type)) { - jmp_slot: - reloc_type = R_JMP_SLOT; - } else - reloc_type = R_GLOB_DAT; - - if (!s1->got) - build_got(s1); - - if (gotplt_entry == BUILD_GOT_ONLY) - continue; - - attr = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, - sym_index); - - if (reloc_type == R_JMP_SLOT) - rel->r_info = ELFW(R_INFO)(attr->plt_sym, type); - } - } -} - -/* put dynamic tag */ -static void put_dt(Section *dynamic, int dt, addr_t val) -{ - ElfW(Dyn) *dyn; - dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); - dyn->d_tag = dt; - dyn->d_un.d_val = val; -} - -#ifndef TCC_TARGET_PE -static void add_init_array_defines(TCCState *s1, const char *section_name) -{ - Section *s; - long end_offset; - char sym_start[1024]; - char sym_end[1024]; - - snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1); - snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1); - - s = find_section(s1, section_name); - if (!s) { - end_offset = 0; - s = data_section; - } else { - end_offset = s->data_offset; - } - - set_elf_sym(symtab_section, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, sym_start); - set_elf_sym(symtab_section, - end_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, sym_end); -} -#endif - -static int tcc_add_support(TCCState *s1, const char *filename) -{ - char buf[1024]; - snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename); - return tcc_add_file(s1, buf); -} - -ST_FUNC void tcc_add_bcheck(TCCState *s1) -{ -#ifdef CONFIG_TCC_BCHECK - addr_t *ptr; - int sym_index; - - if (0 == s1->do_bounds_check) - return; - /* XXX: add an object file to do that */ - ptr = section_ptr_add(bounds_section, sizeof(*ptr)); - *ptr = 0; - set_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - bounds_section->sh_num, "__bounds_start"); - /* pull bcheck.o from libtcc1.a */ - sym_index = set_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_UNDEF, "__bound_init"); - if (s1->output_type != TCC_OUTPUT_MEMORY) { - /* add 'call __bound_init()' in .init section */ - Section *init_section = find_section(s1, ".init"); - unsigned char *pinit = section_ptr_add(init_section, 5); - pinit[0] = 0xe8; - write32le(pinit + 1, -4); - put_elf_reloc(symtab_section, init_section, - init_section->data_offset - 4, R_386_PC32, sym_index); - /* R_386_PC32 = R_X86_64_PC32 = 2 */ - } -#endif -} - -/* add tcc runtime libraries */ -ST_FUNC void tcc_add_runtime(TCCState *s1) -{ - tcc_add_bcheck(s1); - tcc_add_pragma_libs(s1); - /* add libc */ - if (!s1->nostdlib) { - tcc_add_library_err(s1, "c"); -#ifdef TCC_LIBGCC - if (!s1->static_link) { - if (TCC_LIBGCC[0] == '/') - tcc_add_file(s1, TCC_LIBGCC); - else - tcc_add_dll(s1, TCC_LIBGCC, 0); - } -#endif - tcc_add_support(s1, TCC_LIBTCC1); - /* add crt end if not memory output */ - if (s1->output_type != TCC_OUTPUT_MEMORY) - tcc_add_crt(s1, "crtn.o"); - } -} - -/* add various standard linker symbols (must be done after the - sections are filled (for example after allocating common - symbols)) */ -ST_FUNC void tcc_add_linker_symbols(TCCState *s1) -{ - char buf[1024]; - int i; - Section *s; - - set_elf_sym(symtab_section, - text_section->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - text_section->sh_num, "_etext"); - set_elf_sym(symtab_section, - data_section->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - data_section->sh_num, "_edata"); - set_elf_sym(symtab_section, - bss_section->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - bss_section->sh_num, "_end"); -#ifndef TCC_TARGET_PE - /* horrible new standard ldscript defines */ - add_init_array_defines(s1, ".preinit_array"); - add_init_array_defines(s1, ".init_array"); - add_init_array_defines(s1, ".fini_array"); -#endif - - /* add start and stop symbols for sections whose name can be - expressed in C */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type == SHT_PROGBITS && - (s->sh_flags & SHF_ALLOC)) { - const char *p; - int ch; - - /* check if section name can be expressed in C */ - p = s->name; - for(;;) { - ch = *p; - if (!ch) - break; - if (!isid(ch) && !isnum(ch)) - goto next_sec; - p++; - } - snprintf(buf, sizeof(buf), "__start_%s", s->name); - set_elf_sym(symtab_section, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, buf); - snprintf(buf, sizeof(buf), "__stop_%s", s->name); - set_elf_sym(symtab_section, - s->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, buf); - } - next_sec: ; - } -} - -static void tcc_output_binary(TCCState *s1, FILE *f, - const int *sec_order) -{ - Section *s; - int i, offset, size; - - offset = 0; - for(i=1;inb_sections;i++) { - s = s1->sections[sec_order[i]]; - if (s->sh_type != SHT_NOBITS && - (s->sh_flags & SHF_ALLOC)) { - while (offset < s->sh_offset) { - fputc(0, f); - offset++; - } - size = s->sh_size; - fwrite(s->data, 1, size, f); - offset += size; - } - } -} - -ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) -{ - int sym_index = ELFW(R_SYM) (rel->r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); - unsigned offset = attr->got_offset; - - if (0 == offset) - return; - section_reserve(s1->got, offset + PTR_SIZE); -#ifdef TCC_TARGET_X86_64 - write64le(s1->got->data + offset, sym->st_value); -#else - write32le(s1->got->data + offset, sym->st_value); -#endif -} - -/* Perform relocation to GOT or PLT entries */ -ST_FUNC void fill_got(TCCState *s1) -{ - Section *s; - ElfW_Rel *rel; - int i; - - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX) - continue; - /* no need to handle got relocations */ - if (s->link != symtab_section) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - switch (ELFW(R_TYPE) (rel->r_info)) { - case R_X86_64_GOT32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PLT32: - fill_got_entry(s1, rel); - break; - } - } - } -} - -/* See put_got_entry for a description. This is the second stage - where GOT references to local defined symbols are rewritten. */ -static void fill_local_got_entries(TCCState *s1) -{ - ElfW_Rel *rel; - for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) { - if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) { - int sym_index = ELFW(R_SYM) (rel->r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); - unsigned offset = attr->got_offset; - if (offset != rel->r_offset - s1->got->sh_addr) - tcc_error_noabort("huh"); - rel->r_info = ELFW(R_INFO)(0, R_RELATIVE); -#if SHT_RELX == SHT_RELA - rel->r_addend = sym->st_value; -#else - /* All our REL architectures also happen to be 32bit LE. */ - write32le(s1->got->data + offset, sym->st_value); -#endif - } - } -} - -/* Bind symbols of executable: resolve undefined symbols from exported symbols - in shared libraries and export non local defined symbols to shared libraries - if -rdynamic switch was given on command line */ -static void bind_exe_dynsyms(TCCState *s1) -{ - const char *name; - int sym_index, index; - ElfW(Sym) *sym, *esym; - int type; - - /* Resolve undefined symbols from dynamic symbols. When there is a match: - - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT - - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (sym->st_shndx == SHN_UNDEF) { - name = (char *) symtab_section->link->data + sym->st_name; - sym_index = find_elf_sym(s1->dynsymtab_section, name); - if (sym_index) { - esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; - type = ELFW(ST_TYPE)(esym->st_info); - if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { - /* Indirect functions shall have STT_FUNC type in executable - * dynsym section. Indeed, a dlsym call following a lazy - * resolution would pick the symbol value from the - * executable dynsym entry which would contain the address - * of the function wanted by the caller of dlsym instead of - * the address of the function that would return that - * address */ - int dynindex - = put_elf_sym(s1->dynsym, 0, esym->st_size, - ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0, - name); - int index = sym - (ElfW(Sym) *) symtab_section->data; - get_sym_attr(s1, index, 1)->dyn_index = dynindex; - } else if (type == STT_OBJECT) { - unsigned long offset; - ElfW(Sym) *dynsym; - offset = bss_section->data_offset; - /* XXX: which alignment ? */ - offset = (offset + 16 - 1) & -16; - set_elf_sym (s1->symtab, offset, esym->st_size, - esym->st_info, 0, bss_section->sh_num, name); - index = put_elf_sym(s1->dynsym, offset, esym->st_size, - esym->st_info, 0, bss_section->sh_num, - name); - - /* Ensure R_COPY works for weak symbol aliases */ - if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { - for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { - if ((dynsym->st_value == esym->st_value) - && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { - char *dynname = (char *) s1->dynsymtab_section->link->data - + dynsym->st_name; - put_elf_sym(s1->dynsym, offset, dynsym->st_size, - dynsym->st_info, 0, - bss_section->sh_num, dynname); - break; - } - } - } - - put_elf_reloc(s1->dynsym, bss_section, - offset, R_COPY, index); - offset += esym->st_size; - bss_section->data_offset = offset; - } - } else { - /* STB_WEAK undefined symbols are accepted */ - /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ - if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || - !strcmp(name, "_fp_hw")) { - } else { - tcc_error_noabort("undefined symbol '%s'", name); - } - } - } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - /* if -rdynamic option, then export all non local symbols */ - name = (char *) symtab_section->link->data + sym->st_name; - set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, - 0, sym->st_shndx, name); - } - } -} - -/* Bind symbols of libraries: export all non local symbols of executable that - are referenced by shared libraries. The reason is that the dynamic loader - search symbol first in executable and then in libraries. Therefore a - reference to a symbol already defined by a library can still be resolved by - a symbol in the executable. */ -static void bind_libs_dynsyms(TCCState *s1) -{ - const char *name; - int sym_index; - ElfW(Sym) *sym, *esym; - - for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { - name = (char *) s1->dynsymtab_section->link->data + esym->st_name; - sym_index = find_elf_sym(symtab_section, name); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - if (sym_index && sym->st_shndx != SHN_UNDEF - && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, - sym->st_info, 0, sym->st_shndx, name); - } else if (esym->st_shndx == SHN_UNDEF) { - /* weak symbols can stay undefined */ - if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) - tcc_warning("undefined dynamic symbol '%s'", name); - } - } -} - -/* Export all non local symbols. This is used by shared libraries so that the - non local symbols they define can resolve a reference in another shared - library or in the executable. Correspondingly, it allows undefined local - symbols to be resolved by other shared libraries or by the executable. */ -static void export_global_syms(TCCState *s1) -{ - int dynindex, index; - const char *name; - ElfW(Sym) *sym; - - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - name = (char *) symtab_section->link->data + sym->st_name; - dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, - sym->st_info, 0, sym->st_shndx, name); - index = sym - (ElfW(Sym) *) symtab_section->data; - get_sym_attr(s1, index, 1)->dyn_index = dynindex; - } - } -} - -/* Allocate strings for section names and decide if an unallocated section - should be output. - NOTE: the strsec section comes last, so its size is also correct ! */ -static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) -{ - int i; - Section *s; - int textrel = 0; - - /* Allocate strings for section names */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - /* when generating a DLL, we include relocations but we may - patch them */ - if (file_type == TCC_OUTPUT_DLL && - s->sh_type == SHT_RELX && - !(s->sh_flags & SHF_ALLOC) && - (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) && - prepare_dynamic_rel(s1, s)) { - if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR) - textrel = 1; - } else if (s1->do_debug || - file_type == TCC_OUTPUT_OBJ || - (s->sh_flags & SHF_ALLOC) || - i == (s1->nb_sections - 1)) { - /* we output all sections if debug or object file */ - s->sh_size = s->data_offset; - } - if (s->sh_size || (s->sh_flags & SHF_ALLOC)) - s->sh_name = put_elf_str(strsec, s->name); - } - strsec->sh_size = strsec->data_offset; - return textrel; -} - -/* Info to be copied in dynamic section */ -struct dyn_inf { - Section *dynamic; - Section *dynstr; - unsigned long data_offset; - addr_t rel_addr; - addr_t rel_size; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - addr_t bss_addr; - addr_t bss_size; -#endif -}; - -/* Assign sections to segments and decide how are sections laid out when loaded - in memory. This function also fills corresponding program headers. */ -static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, - Section *interp, Section* strsec, - struct dyn_inf *dyninf, int *sec_order) -{ - int i, j, k, file_type, sh_order_index, file_offset; - unsigned long s_align; - long long tmp; - addr_t addr; - ElfW(Phdr) *ph; - Section *s; - - file_type = s1->output_type; - sh_order_index = 1; - file_offset = 0; - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) - file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - s_align = ELF_PAGE_SIZE; - if (s1->section_align) - s_align = s1->section_align; - - if (phnum > 0) { - if (s1->has_text_addr) { - int a_offset, p_offset; - addr = s1->text_addr; - /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % - ELF_PAGE_SIZE */ - a_offset = (int) (addr & (s_align - 1)); - p_offset = file_offset & (s_align - 1); - if (a_offset < p_offset) - a_offset += s_align; - file_offset += (a_offset - p_offset); - } else { - if (file_type == TCC_OUTPUT_DLL) - addr = 0; - else - addr = ELF_START_ADDR; - /* compute address after headers */ - addr += (file_offset & (s_align - 1)); - } - - ph = &phdr[0]; - /* Leave one program headers for the program interpreter and one for - the program header table itself if needed. These are done later as - they require section layout to be done first. */ - if (interp) - ph += 2; - - /* dynamic relocation table information, for .dynamic section */ - dyninf->rel_addr = dyninf->rel_size = 0; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - dyninf->bss_addr = dyninf->bss_size = 0; -#endif - - for(j = 0; j < 2; j++) { - ph->p_type = PT_LOAD; - if (j == 0) - ph->p_flags = PF_R | PF_X; - else - ph->p_flags = PF_R | PF_W; - ph->p_align = s_align; - - /* Decide the layout of sections loaded in memory. This must - be done before program headers are filled since they contain - info about the layout. We do the following ordering: interp, - symbol tables, relocations, progbits, nobits */ - /* XXX: do faster and simpler sorting */ - for(k = 0; k < 5; k++) { - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - /* compute if section should be included */ - if (j == 0) { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != - SHF_ALLOC) - continue; - } else { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != - (SHF_ALLOC | SHF_WRITE)) - continue; - } - if (s == interp) { - if (k != 0) - continue; - } else if (s->sh_type == SHT_DYNSYM || - s->sh_type == SHT_STRTAB || - s->sh_type == SHT_HASH) { - if (k != 1) - continue; - } else if (s->sh_type == SHT_RELX) { - if (k != 2) - continue; - } else if (s->sh_type == SHT_NOBITS) { - if (k != 4) - continue; - } else { - if (k != 3) - continue; - } - sec_order[sh_order_index++] = i; - - /* section matches: we align it and add its size */ - tmp = addr; - addr = (addr + s->sh_addralign - 1) & - ~(s->sh_addralign - 1); - file_offset += (int) ( addr - tmp ); - s->sh_offset = file_offset; - s->sh_addr = addr; - - /* update program header infos */ - if (ph->p_offset == 0) { - ph->p_offset = file_offset; - ph->p_vaddr = addr; - ph->p_paddr = ph->p_vaddr; - } - /* update dynamic relocation infos */ - if (s->sh_type == SHT_RELX) { -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { - dyninf->rel_addr = addr; - dyninf->rel_size += s->sh_size; /* XXX only first rel. */ - } - if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { - dyninf->bss_addr = addr; - dyninf->bss_size = s->sh_size; /* XXX only first rel. */ - } -#else - if (dyninf->rel_size == 0) - dyninf->rel_addr = addr; - dyninf->rel_size += s->sh_size; -#endif - } - addr += s->sh_size; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - } - } - if (j == 0) { - /* Make the first PT_LOAD segment include the program - headers itself (and the ELF header as well), it'll - come out with same memory use but will make various - tools like binutils strip work better. */ - ph->p_offset &= ~(ph->p_align - 1); - ph->p_vaddr &= ~(ph->p_align - 1); - ph->p_paddr &= ~(ph->p_align - 1); - } - ph->p_filesz = file_offset - ph->p_offset; - ph->p_memsz = addr - ph->p_vaddr; - ph++; - if (j == 0) { - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { - /* if in the middle of a page, we duplicate the page in - memory so that one copy is RX and the other is RW */ - if ((addr & (s_align - 1)) != 0) - addr += s_align; - } else { - addr = (addr + s_align - 1) & ~(s_align - 1); - file_offset = (file_offset + s_align - 1) & ~(s_align - 1); - } - } - } - } - - /* all other sections come after */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) - continue; - sec_order[sh_order_index++] = i; - - file_offset = (file_offset + s->sh_addralign - 1) & - ~(s->sh_addralign - 1); - s->sh_offset = file_offset; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - } - - return file_offset; -} - -static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, - Section *dynamic) -{ - ElfW(Phdr) *ph; - - /* if interpreter, then add corresponding program header */ - if (interp) { - ph = &phdr[0]; - - ph->p_type = PT_PHDR; - ph->p_offset = sizeof(ElfW(Ehdr)); - ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr)); - ph->p_vaddr = interp->sh_addr - ph->p_filesz; - ph->p_paddr = ph->p_vaddr; - ph->p_flags = PF_R | PF_X; - ph->p_align = 4; /* interp->sh_addralign; */ - ph++; - - ph->p_type = PT_INTERP; - ph->p_offset = interp->sh_offset; - ph->p_vaddr = interp->sh_addr; - ph->p_paddr = ph->p_vaddr; - ph->p_filesz = interp->sh_size; - ph->p_memsz = interp->sh_size; - ph->p_flags = PF_R; - ph->p_align = interp->sh_addralign; - } - - /* if dynamic section, then add corresponding program header */ - if (dynamic) { - ph = &phdr[phnum - 1]; - - ph->p_type = PT_DYNAMIC; - ph->p_offset = dynamic->sh_offset; - ph->p_vaddr = dynamic->sh_addr; - ph->p_paddr = ph->p_vaddr; - ph->p_filesz = dynamic->sh_size; - ph->p_memsz = dynamic->sh_size; - ph->p_flags = PF_R | PF_W; - ph->p_align = dynamic->sh_addralign; - } -} - -/* Fill the dynamic section with tags describing the address and size of - sections */ -static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) -{ - Section *dynamic = dyninf->dynamic; - - /* put dynamic section entries */ - put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); - put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); - put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); - put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); - put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); -#if PTR_SIZE == 8 - put_dt(dynamic, DT_RELA, dyninf->rel_addr); - put_dt(dynamic, DT_RELASZ, dyninf->rel_size); - put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); -#else -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); - put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); - put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); - put_dt(dynamic, DT_PLTREL, DT_REL); - put_dt(dynamic, DT_REL, dyninf->bss_addr); - put_dt(dynamic, DT_RELSZ, dyninf->bss_size); -#else - put_dt(dynamic, DT_REL, dyninf->rel_addr); - put_dt(dynamic, DT_RELSZ, dyninf->rel_size); - put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); -#endif -#endif - if (s1->do_debug) - put_dt(dynamic, DT_DEBUG, 0); - put_dt(dynamic, DT_NULL, 0); -} - -/* Relocate remaining sections and symbols (that is those not related to - dynamic linking) */ -static int final_sections_reloc(TCCState *s1) -{ - int i; - Section *s; - - relocate_syms(s1, s1->symtab, 0); - - if (s1->nb_errors != 0) - return -1; - - /* relocate sections */ - /* XXX: ignore sections with allocated relocations ? */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; -#if defined(TCC_TARGET_I386) || defined(TCC_MUSL) - if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr - /* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC - checking is removed */ -#else - if (s->reloc && s != s1->got) - /* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */ -#endif - relocate_section(s1, s); - } - - /* relocate relocation entries if the relocation tables are - allocated in the executable */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if ((s->sh_flags & SHF_ALLOC) && - s->sh_type == SHT_RELX) { - relocate_rel(s1, s); - } - } - return 0; -} - -/* Create an ELF file on disk. - This function handle ELF specific layout requirements */ -static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, - int file_offset, int *sec_order) -{ - int i, shnum, offset, size, file_type; - Section *s; - ElfW(Ehdr) ehdr; - ElfW(Shdr) shdr, *sh; - - file_type = s1->output_type; - shnum = s1->nb_sections; - - memset(&ehdr, 0, sizeof(ehdr)); - - if (phnum > 0) { - ehdr.e_phentsize = sizeof(ElfW(Phdr)); - ehdr.e_phnum = phnum; - ehdr.e_phoff = sizeof(ElfW(Ehdr)); - } - - /* align to 4 */ - file_offset = (file_offset + 3) & -4; - - /* fill header */ - ehdr.e_ident[0] = ELFMAG0; - ehdr.e_ident[1] = ELFMAG1; - ehdr.e_ident[2] = ELFMAG2; - ehdr.e_ident[3] = ELFMAG3; - ehdr.e_ident[4] = ELFCLASSW; - ehdr.e_ident[5] = ELFDATA2LSB; - ehdr.e_ident[6] = EV_CURRENT; -#if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) - /* FIXME: should set only for freebsd _target_, but we exclude only PE target */ - ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; -#endif -#ifdef TCC_TARGET_ARM -#ifdef TCC_ARM_EABI - ehdr.e_ident[EI_OSABI] = 0; - ehdr.e_flags = EF_ARM_EABI_VER4; - if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) - ehdr.e_flags |= EF_ARM_HASENTRY; - if (s1->float_abi == ARM_HARD_FLOAT) - ehdr.e_flags |= EF_ARM_VFP_FLOAT; - else - ehdr.e_flags |= EF_ARM_SOFT_FLOAT; -#else - ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; -#endif -#endif - switch(file_type) { - default: - case TCC_OUTPUT_EXE: - ehdr.e_type = ET_EXEC; - ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1); - break; - case TCC_OUTPUT_DLL: - ehdr.e_type = ET_DYN; - ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ - break; - case TCC_OUTPUT_OBJ: - ehdr.e_type = ET_REL; - break; - } - ehdr.e_machine = EM_TCC_TARGET; - ehdr.e_version = EV_CURRENT; - ehdr.e_shoff = file_offset; - ehdr.e_ehsize = sizeof(ElfW(Ehdr)); - ehdr.e_shentsize = sizeof(ElfW(Shdr)); - ehdr.e_shnum = shnum; - ehdr.e_shstrndx = shnum - 1; - - fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); - fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); - offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - - sort_syms(s1, symtab_section); - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[sec_order[i]]; - if (s->sh_type != SHT_NOBITS) { - while (offset < s->sh_offset) { - fputc(0, f); - offset++; - } - size = s->sh_size; - if (size) - fwrite(s->data, 1, size, f); - offset += size; - } - } - - /* output section headers */ - while (offset < ehdr.e_shoff) { - fputc(0, f); - offset++; - } - - for(i = 0; i < s1->nb_sections; i++) { - sh = &shdr; - memset(sh, 0, sizeof(ElfW(Shdr))); - s = s1->sections[i]; - if (s) { - sh->sh_name = s->sh_name; - sh->sh_type = s->sh_type; - sh->sh_flags = s->sh_flags; - sh->sh_entsize = s->sh_entsize; - sh->sh_info = s->sh_info; - if (s->link) - sh->sh_link = s->link->sh_num; - sh->sh_addralign = s->sh_addralign; - sh->sh_addr = s->sh_addr; - sh->sh_offset = s->sh_offset; - sh->sh_size = s->sh_size; - } - fwrite(sh, 1, sizeof(ElfW(Shdr)), f); - } -} - -/* Write an elf, coff or "binary" file */ -static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, - ElfW(Phdr) *phdr, int file_offset, int *sec_order) -{ - int fd, mode, file_type; - FILE *f; - - file_type = s1->output_type; - if (file_type == TCC_OUTPUT_OBJ) - mode = 0666; - else - mode = 0777; - unlink(filename); - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); - if (fd < 0) { - tcc_error_noabort("could not write '%s'", filename); - return -1; - } - f = fdopen(fd, "wb"); - if (s1->verbose) - printf("<- %s\n", filename); - -#ifdef TCC_TARGET_COFF - if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) - tcc_output_coff(s1, f); - else -#endif - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) - tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); - else - tcc_output_binary(s1, f, sec_order); - fclose(f); - - return 0; -} - -/* Sort section headers by assigned sh_addr, remove sections - that we aren't going to output. */ -static void tidy_section_headers(TCCState *s1, int *sec_order) -{ - int i, nnew, l, *backmap; - Section **snew, *s; - ElfW(Sym) *sym; - - snew = tcc_malloc(s1->nb_sections * sizeof(snew[0])); - backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); - for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) { - s = s1->sections[sec_order[i]]; - if (!i || s->sh_name) { - backmap[sec_order[i]] = nnew; - snew[nnew] = s; - ++nnew; - } else { - backmap[sec_order[i]] = 0; - snew[--l] = s; - } - } - for (i = 0; i < nnew; i++) { - s = snew[i]; - if (s) { - s->sh_num = i; - if (s->sh_type == SHT_RELX) - s->sh_info = backmap[s->sh_info]; - } - } - - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - sym->st_shndx = backmap[sym->st_shndx]; - if( !s1->static_link ) { - for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - sym->st_shndx = backmap[sym->st_shndx]; - } - for (i = 0; i < s1->nb_sections; i++) - sec_order[i] = i; - tcc_free(s1->sections); - s1->sections = snew; - s1->nb_sections = nnew; - tcc_free(backmap); -} - -/* Output an elf, coff or binary file */ -/* XXX: suppress unneeded sections */ -static int elf_output_file(TCCState *s1, const char *filename) -{ - int i, ret, phnum, shnum, file_type, file_offset, *sec_order; - struct dyn_inf dyninf = {0}; - ElfW(Phdr) *phdr; - ElfW(Sym) *sym; - Section *strsec, *interp, *dynamic, *dynstr; - int textrel; - - file_type = s1->output_type; - s1->nb_errors = 0; - ret = -1; - phdr = NULL; - sec_order = NULL; - interp = dynamic = dynstr = NULL; /* avoid warning */ - textrel = 0; - - if (file_type != TCC_OUTPUT_OBJ) { - /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ - tcc_add_runtime(s1); - relocate_common_syms(); - tcc_add_linker_symbols(s1); - - if (!s1->static_link) { - if (file_type == TCC_OUTPUT_EXE) { - char *ptr; - /* allow override the dynamic loader */ - const char *elfint = getenv("LD_SO"); - if (elfint == NULL) - elfint = DEFAULT_ELFINTERP(s1); - /* add interpreter section only if executable */ - interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); - interp->sh_addralign = 1; - ptr = section_ptr_add(interp, 1 + strlen(elfint)); - strcpy(ptr, elfint); - } - - /* add dynamic symbol table */ - s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, - ".dynstr", - ".hash", SHF_ALLOC); - dynstr = s1->dynsym->link; - - /* add dynamic section */ - dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, - SHF_ALLOC | SHF_WRITE); - dynamic->link = dynstr; - dynamic->sh_entsize = sizeof(ElfW(Dyn)); - - build_got(s1); - - if (file_type == TCC_OUTPUT_EXE) { - bind_exe_dynsyms(s1); - if (s1->nb_errors) - goto the_end; - bind_libs_dynsyms(s1); - } else { - /* shared library case: simply export all global symbols */ - export_global_syms(s1); - } - } - build_got_entries(s1); - } - - /* we add a section for symbols */ - strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); - put_elf_str(strsec, ""); - - /* Allocate strings for section names */ - textrel = alloc_sec_names(s1, file_type, strsec); - - if (dynamic) { - /* add a list of needed dlls */ - for(i = 0; i < s1->nb_loaded_dlls; i++) { - DLLReference *dllref = s1->loaded_dlls[i]; - if (dllref->level == 0) - put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); - } - - if (s1->rpath) - put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH, - put_elf_str(dynstr, s1->rpath)); - - if (file_type == TCC_OUTPUT_DLL) { - if (s1->soname) - put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); - /* XXX: currently, since we do not handle PIC code, we - must relocate the readonly segments */ - if (textrel) - put_dt(dynamic, DT_TEXTREL, 0); - } - - if (s1->symbolic) - put_dt(dynamic, DT_SYMBOLIC, 0); - - dyninf.dynamic = dynamic; - dyninf.dynstr = dynstr; - /* remember offset and reserve space for 2nd call below */ - dyninf.data_offset = dynamic->data_offset; - fill_dynamic(s1, &dyninf); - dynamic->sh_size = dynamic->data_offset; - dynstr->sh_size = dynstr->data_offset; - } - - /* compute number of program headers */ - if (file_type == TCC_OUTPUT_OBJ) - phnum = 0; - else if (file_type == TCC_OUTPUT_DLL) - phnum = 3; - else if (s1->static_link) - phnum = 2; - else - phnum = 5; - - /* allocate program segment headers */ - phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); - - /* compute number of sections */ - shnum = s1->nb_sections; - - /* this array is used to reorder sections in the output file */ - sec_order = tcc_malloc(sizeof(int) * shnum); - sec_order[0] = 0; - - /* compute section to program header mapping */ - file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf, - sec_order); - - /* Fill remaining program header and finalize relocation related to dynamic - linking. */ - if (file_type != TCC_OUTPUT_OBJ) { - fill_unloadable_phdr(phdr, phnum, interp, dynamic); - if (dynamic) { - dynamic->data_offset = dyninf.data_offset; - fill_dynamic(s1, &dyninf); - - /* put in GOT the dynamic section address and relocate PLT */ - write32le(s1->got->data, dynamic->sh_addr); - if (file_type == TCC_OUTPUT_EXE - || (RELOCATE_DLLPLT && file_type == TCC_OUTPUT_DLL)) - relocate_plt(s1); - - /* relocate symbols in .dynsym now that final addresses are known */ - for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) { - /* do symbol relocation */ - sym->st_value += s1->sections[sym->st_shndx]->sh_addr; - } - } - } - - /* if building executable or DLL, then relocate each section - except the GOT which is already relocated */ - ret = final_sections_reloc(s1); - if (ret) - goto the_end; - tidy_section_headers(s1, sec_order); - - /* Perform relocation to GOT or PLT entries */ - if (file_type == TCC_OUTPUT_EXE && s1->static_link) - fill_got(s1); - else if (s1->got) - fill_local_got_entries(s1); - } - - /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); - s1->nb_sections = shnum; - the_end: - tcc_free(sec_order); - tcc_free(phdr); - return ret; -} - -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) -{ - int ret; -#ifdef TCC_TARGET_PE - if (s->output_type != TCC_OUTPUT_OBJ) { - ret = pe_output_file(s, filename); - } else -#endif - ret = elf_output_file(s, filename); - return ret; -} - -static void *load_data(int fd, unsigned long file_offset, unsigned long size) -{ - void *data; - - data = tcc_malloc(size); - lseek(fd, file_offset, SEEK_SET); - read(fd, data, size); - return data; -} - -typedef struct SectionMergeInfo { - Section *s; /* corresponding existing section */ - unsigned long offset; /* offset of the new section in the existing section */ - uint8_t new_section; /* true if section 's' was added */ - uint8_t link_once; /* true if link once section */ -} SectionMergeInfo; - -ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h) -{ - int size = read(fd, h, sizeof *h); - if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) { - if (h->e_type == ET_REL) - return AFF_BINTYPE_REL; - if (h->e_type == ET_DYN) - return AFF_BINTYPE_DYN; - } else if (size >= 8) { - if (0 == memcmp(h, ARMAG, 8)) - return AFF_BINTYPE_AR; -#ifdef TCC_TARGET_COFF - if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC) - return AFF_BINTYPE_C67; -#endif - } - return 0; -} - -/* load an object file and merge it with current files */ -/* XXX: handle correctly stab (debug) info */ -ST_FUNC int tcc_load_object_file(TCCState *s1, - int fd, unsigned long file_offset) -{ - ElfW(Ehdr) ehdr; - ElfW(Shdr) *shdr, *sh; - int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed; - unsigned char *strsec, *strtab; - int *old_to_new_syms; - char *sh_name, *name; - SectionMergeInfo *sm_table, *sm; - ElfW(Sym) *sym, *symtab; - ElfW_Rel *rel; - Section *s; - - int stab_index; - int stabstr_index; - - stab_index = stabstr_index = 0; - - lseek(fd, file_offset, SEEK_SET); - if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL) - goto fail1; - /* test CPU specific stuff */ - if (ehdr.e_ident[5] != ELFDATA2LSB || - ehdr.e_machine != EM_TCC_TARGET) { - fail1: - tcc_error_noabort("invalid object file"); - return -1; - } - /* read sections */ - shdr = load_data(fd, file_offset + ehdr.e_shoff, - sizeof(ElfW(Shdr)) * ehdr.e_shnum); - sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); - - /* load section names */ - sh = &shdr[ehdr.e_shstrndx]; - strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - - /* load symtab and strtab */ - old_to_new_syms = NULL; - symtab = NULL; - strtab = NULL; - nb_syms = 0; - seencompressed = 0; - for(i = 1; i < ehdr.e_shnum; i++) { - sh = &shdr[i]; - if (sh->sh_type == SHT_SYMTAB) { - if (symtab) { - tcc_error_noabort("object must contain only one symtab"); - fail: - ret = -1; - goto the_end; - } - nb_syms = sh->sh_size / sizeof(ElfW(Sym)); - symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - sm_table[i].s = symtab_section; - - /* now load strtab */ - sh = &shdr[sh->sh_link]; - strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - } - if (sh->sh_flags & SHF_COMPRESSED) - seencompressed = 1; - } - - /* now examine each section and try to merge its content with the - ones in memory */ - for(i = 1; i < ehdr.e_shnum; i++) { - /* no need to examine section name strtab */ - if (i == ehdr.e_shstrndx) - continue; - sh = &shdr[i]; - sh_name = (char *) strsec + sh->sh_name; - /* ignore sections types we do not handle */ - if (sh->sh_type != SHT_PROGBITS && - sh->sh_type != SHT_RELX && -#ifdef TCC_ARM_EABI - sh->sh_type != SHT_ARM_EXIDX && -#endif - sh->sh_type != SHT_NOBITS && - sh->sh_type != SHT_PREINIT_ARRAY && - sh->sh_type != SHT_INIT_ARRAY && - sh->sh_type != SHT_FINI_ARRAY && - strcmp(sh_name, ".stabstr") - ) - continue; - if (seencompressed - && (!strncmp(sh_name, ".debug_", sizeof(".debug_")-1) - || (sh->sh_type == SHT_RELX - && !strncmp((char*)strsec + shdr[sh->sh_info].sh_name, - ".debug_", sizeof(".debug_")-1)))) - continue; - if (sh->sh_addralign < 1) - sh->sh_addralign = 1; - /* find corresponding section, if any */ - for(j = 1; j < s1->nb_sections;j++) { - s = s1->sections[j]; - if (!strcmp(s->name, sh_name)) { - if (!strncmp(sh_name, ".gnu.linkonce", - sizeof(".gnu.linkonce") - 1)) { - /* if a 'linkonce' section is already present, we - do not add it again. It is a little tricky as - symbols can still be defined in - it. */ - sm_table[i].link_once = 1; - goto next; - } else { - goto found; - } - } - } - /* not found: create new section */ - s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags & ~SHF_GROUP); - /* take as much info as possible from the section. sh_link and - sh_info will be updated later */ - s->sh_addralign = sh->sh_addralign; - s->sh_entsize = sh->sh_entsize; - sm_table[i].new_section = 1; - found: - if (sh->sh_type != s->sh_type) { - tcc_error_noabort("invalid section type"); - goto fail; - } - - /* align start of section */ - offset = s->data_offset; - - if (0 == strcmp(sh_name, ".stab")) { - stab_index = i; - goto no_align; - } - if (0 == strcmp(sh_name, ".stabstr")) { - stabstr_index = i; - goto no_align; - } - - size = sh->sh_addralign - 1; - offset = (offset + size) & ~size; - if (sh->sh_addralign > s->sh_addralign) - s->sh_addralign = sh->sh_addralign; - s->data_offset = offset; - no_align: - sm_table[i].offset = offset; - sm_table[i].s = s; - /* concatenate sections */ - size = sh->sh_size; - if (sh->sh_type != SHT_NOBITS) { - unsigned char *ptr; - lseek(fd, file_offset + sh->sh_offset, SEEK_SET); - ptr = section_ptr_add(s, size); - read(fd, ptr, size); - } else { - s->data_offset += size; - } - next: ; - } - - /* gr relocate stab strings */ - if (stab_index && stabstr_index) { - Stab_Sym *a, *b; - unsigned o; - s = sm_table[stab_index].s; - a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); - b = (Stab_Sym *)(s->data + s->data_offset); - o = sm_table[stabstr_index].offset; - while (a < b) - a->n_strx += o, a++; - } - - /* second short pass to update sh_link and sh_info fields of new - sections */ - for(i = 1; i < ehdr.e_shnum; i++) { - s = sm_table[i].s; - if (!s || !sm_table[i].new_section) - continue; - sh = &shdr[i]; - if (sh->sh_link > 0) - s->link = sm_table[sh->sh_link].s; - if (sh->sh_type == SHT_RELX) { - s->sh_info = sm_table[sh->sh_info].s->sh_num; - /* update backward link */ - s1->sections[s->sh_info]->reloc = s; - } - } - sm = sm_table; - - /* resolve symbols */ - old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); - - sym = symtab + 1; - for(i = 1; i < nb_syms; i++, sym++) { - if (sym->st_shndx != SHN_UNDEF && - sym->st_shndx < SHN_LORESERVE) { - sm = &sm_table[sym->st_shndx]; - if (sm->link_once) { - /* if a symbol is in a link once section, we use the - already defined symbol. It is very important to get - correct relocations */ - if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - name = (char *) strtab + sym->st_name; - sym_index = find_elf_sym(symtab_section, name); - if (sym_index) - old_to_new_syms[i] = sym_index; - } - continue; - } - /* if no corresponding section added, no need to add symbol */ - if (!sm->s) - continue; - /* convert section number */ - sym->st_shndx = sm->s->sh_num; - /* offset value */ - sym->st_value += sm->offset; - } - /* add symbol */ - name = (char *) strtab + sym->st_name; - sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size, - sym->st_info, sym->st_other, - sym->st_shndx, name); - old_to_new_syms[i] = sym_index; - } - - /* third pass to patch relocation entries */ - for(i = 1; i < ehdr.e_shnum; i++) { - s = sm_table[i].s; - if (!s) - continue; - sh = &shdr[i]; - offset = sm_table[i].offset; - switch(s->sh_type) { - case SHT_RELX: - /* take relocation offset information */ - offseti = sm_table[sh->sh_info].offset; - for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) { - int type; - unsigned sym_index; - /* convert symbol index */ - type = ELFW(R_TYPE)(rel->r_info); - sym_index = ELFW(R_SYM)(rel->r_info); - /* NOTE: only one symtab assumed */ - if (sym_index >= nb_syms) - goto invalid_reloc; - sym_index = old_to_new_syms[sym_index]; - /* ignore link_once in rel section. */ - if (!sym_index && !sm->link_once -#ifdef TCC_TARGET_ARM - && type != R_ARM_V4BX -#endif - ) { - invalid_reloc: - tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", - i, strsec + sh->sh_name, rel->r_offset); - goto fail; - } - rel->r_info = ELFW(R_INFO)(sym_index, type); - /* offset the relocation offset */ - rel->r_offset += offseti; -#ifdef TCC_TARGET_ARM - /* Jumps and branches from a Thumb code to a PLT entry need - special handling since PLT entries are ARM code. - Unconditional bl instructions referencing PLT entries are - handled by converting these instructions into blx - instructions. Other case of instructions referencing a PLT - entry require to add a Thumb stub before the PLT entry to - switch to ARM mode. We set bit plt_thumb_stub of the - attribute of a symbol to indicate such a case. */ - if (type == R_ARM_THM_JUMP24) - get_sym_attr(s1, sym_index, 1)->plt_thumb_stub = 1; -#endif - } - break; - default: - break; - } - } - - ret = 0; - the_end: - tcc_free(symtab); - tcc_free(strtab); - tcc_free(old_to_new_syms); - tcc_free(sm_table); - tcc_free(strsec); - tcc_free(shdr); - return ret; -} - -typedef struct ArchiveHeader { - char ar_name[16]; /* name of this member */ - char ar_date[12]; /* file mtime */ - char ar_uid[6]; /* owner uid; printed as decimal */ - char ar_gid[6]; /* owner gid; printed as decimal */ - char ar_mode[8]; /* file mode, printed as octal */ - char ar_size[10]; /* file size, printed as decimal */ - char ar_fmag[2]; /* should contain ARFMAG */ -} ArchiveHeader; - -static int get_be32(const uint8_t *b) -{ - return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); -} - -static long get_be64(const uint8_t *b) -{ - long long ret = get_be32(b); - ret = (ret << 32) | (unsigned)get_be32(b+4); - return (long)ret; -} - -/* load only the objects which resolve undefined symbols */ -static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) -{ - long i, bound, nsyms, sym_index, off, ret; - uint8_t *data; - const char *ar_names, *p; - const uint8_t *ar_index; - ElfW(Sym) *sym; - - data = tcc_malloc(size); - if (read(fd, data, size) != size) - goto fail; - nsyms = entrysize == 4 ? get_be32(data) : get_be64(data); - ar_index = data + entrysize; - ar_names = (char *) ar_index + nsyms * entrysize; - - do { - bound = 0; - for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { - sym_index = find_elf_sym(symtab_section, p); - if(sym_index) { - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - if(sym->st_shndx == SHN_UNDEF) { - off = (entrysize == 4 - ? get_be32(ar_index + i * 4) - : get_be64(ar_index + i * 8)) - + sizeof(ArchiveHeader); - ++bound; - if(tcc_load_object_file(s1, fd, off) < 0) { - fail: - ret = -1; - goto the_end; - } - } - } - } - } while(bound); - ret = 0; - the_end: - tcc_free(data); - return ret; -} - -/* load a '.a' file */ -ST_FUNC int tcc_load_archive(TCCState *s1, int fd) -{ - ArchiveHeader hdr; - char ar_size[11]; - char ar_name[17]; - char magic[8]; - int size, len, i; - unsigned long file_offset; - - /* skip magic which was already checked */ - read(fd, magic, sizeof(magic)); - - for(;;) { - len = read(fd, &hdr, sizeof(hdr)); - if (len == 0) - break; - if (len != sizeof(hdr)) { - tcc_error_noabort("invalid archive"); - return -1; - } - memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); - ar_size[sizeof(hdr.ar_size)] = '\0'; - size = strtol(ar_size, NULL, 0); - memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name)); - for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { - if (ar_name[i] != ' ') - break; - } - ar_name[i + 1] = '\0'; - file_offset = lseek(fd, 0, SEEK_CUR); - /* align to even */ - size = (size + 1) & ~1; - if (!strcmp(ar_name, "/")) { - /* coff symbol table : we handle it */ - if(s1->alacarte_link) - return tcc_load_alacarte(s1, fd, size, 4); - } else if (!strcmp(ar_name, "/SYM64/")) { - if(s1->alacarte_link) - return tcc_load_alacarte(s1, fd, size, 8); - } else { - ElfW(Ehdr) ehdr; - if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) { - if (tcc_load_object_file(s1, fd, file_offset) < 0) - return -1; - } - } - lseek(fd, file_offset + size, SEEK_SET); - } - return 0; -} - -#ifndef TCC_TARGET_PE -/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL - is referenced by the user (so it should be added as DT_NEEDED in - the generated ELF file) */ -ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) -{ - ElfW(Ehdr) ehdr; - ElfW(Shdr) *shdr, *sh, *sh1; - int i, j, nb_syms, nb_dts, sym_bind, ret; - ElfW(Sym) *sym, *dynsym; - ElfW(Dyn) *dt, *dynamic; - unsigned char *dynstr; - const char *name, *soname; - DLLReference *dllref; - - read(fd, &ehdr, sizeof(ehdr)); - - /* test CPU specific stuff */ - if (ehdr.e_ident[5] != ELFDATA2LSB || - ehdr.e_machine != EM_TCC_TARGET) { - tcc_error_noabort("bad architecture"); - return -1; - } - - /* read sections */ - shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); - - /* load dynamic section and dynamic symbols */ - nb_syms = 0; - nb_dts = 0; - dynamic = NULL; - dynsym = NULL; /* avoid warning */ - dynstr = NULL; /* avoid warning */ - for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { - switch(sh->sh_type) { - case SHT_DYNAMIC: - nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); - dynamic = load_data(fd, sh->sh_offset, sh->sh_size); - break; - case SHT_DYNSYM: - nb_syms = sh->sh_size / sizeof(ElfW(Sym)); - dynsym = load_data(fd, sh->sh_offset, sh->sh_size); - sh1 = &shdr[sh->sh_link]; - dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); - break; - default: - break; - } - } - - /* compute the real library name */ - soname = tcc_basename(filename); - - for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { - if (dt->d_tag == DT_SONAME) { - soname = (char *) dynstr + dt->d_un.d_val; - } - } - - /* if the dll is already loaded, do not load it */ - for(i = 0; i < s1->nb_loaded_dlls; i++) { - dllref = s1->loaded_dlls[i]; - if (!strcmp(soname, dllref->name)) { - /* but update level if needed */ - if (level < dllref->level) - dllref->level = level; - ret = 0; - goto the_end; - } - } - - /* add the dll and its level */ - dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); - dllref->level = level; - strcpy(dllref->name, soname); - dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); - - /* add dynamic symbols in dynsym_section */ - for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { - sym_bind = ELFW(ST_BIND)(sym->st_info); - if (sym_bind == STB_LOCAL) - continue; - name = (char *) dynstr + sym->st_name; - set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, - sym->st_info, sym->st_other, sym->st_shndx, name); - } - - /* load all referenced DLLs */ - for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { - switch(dt->d_tag) { - case DT_NEEDED: - name = (char *) dynstr + dt->d_un.d_val; - for(j = 0; j < s1->nb_loaded_dlls; j++) { - dllref = s1->loaded_dlls[j]; - if (!strcmp(name, dllref->name)) - goto already_loaded; - } - if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { - tcc_error_noabort("referenced dll '%s' not found", name); - ret = -1; - goto the_end; - } - already_loaded: - break; - } - } - ret = 0; - the_end: - tcc_free(dynstr); - tcc_free(dynsym); - tcc_free(dynamic); - tcc_free(shdr); - return ret; -} - -#define LD_TOK_NAME 256 -#define LD_TOK_EOF (-1) - -/* return next ld script token */ -static int ld_next(TCCState *s1, char *name, int name_size) -{ - int c; - char *q; - - redo: - switch(ch) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - case '\n': - inp(); - goto redo; - case '/': - minp(); - if (ch == '*') { - file->buf_ptr = parse_comment(file->buf_ptr); - ch = file->buf_ptr[0]; - goto redo; - } else { - q = name; - *q++ = '/'; - goto parse_name; - } - break; - case '\\': - ch = handle_eob(); - if (ch != '\\') - goto redo; - /* fall through */ - /* case 'a' ... 'z': */ - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - /* case 'A' ... 'z': */ - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case '.': - case '$': - case '~': - q = name; - parse_name: - for(;;) { - if (!((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || - strchr("/.-_+=$:\\,~", ch))) - break; - if ((q - name) < name_size - 1) { - *q++ = ch; - } - minp(); - } - *q = '\0'; - c = LD_TOK_NAME; - break; - case CH_EOF: - c = LD_TOK_EOF; - break; - default: - c = ch; - inp(); - break; - } - return c; -} - -static int ld_add_file(TCCState *s1, const char filename[]) -{ - if (filename[0] == '/') { - if (CONFIG_SYSROOT[0] == '\0' - && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0) - return 0; - filename = tcc_basename(filename); - } - return tcc_add_dll(s1, filename, 0); -} - -static inline int new_undef_syms(void) -{ - int ret = 0; - ret = new_undef_sym; - new_undef_sym = 0; - return ret; -} - -static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) -{ - char filename[1024], libname[1024]; - int t, group, nblibs = 0, ret = 0; - char **libs = NULL; - - group = !strcmp(cmd, "GROUP"); - if (!as_needed) - new_undef_syms(); - t = ld_next(s1, filename, sizeof(filename)); - if (t != '(') - expect("("); - t = ld_next(s1, filename, sizeof(filename)); - for(;;) { - libname[0] = '\0'; - if (t == LD_TOK_EOF) { - tcc_error_noabort("unexpected end of file"); - ret = -1; - goto lib_parse_error; - } else if (t == ')') { - break; - } else if (t == '-') { - t = ld_next(s1, filename, sizeof(filename)); - if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { - tcc_error_noabort("library name expected"); - ret = -1; - goto lib_parse_error; - } - pstrcpy(libname, sizeof libname, &filename[1]); - if (s1->static_link) { - snprintf(filename, sizeof filename, "lib%s.a", libname); - } else { - snprintf(filename, sizeof filename, "lib%s.so", libname); - } - } else if (t != LD_TOK_NAME) { - tcc_error_noabort("filename expected"); - ret = -1; - goto lib_parse_error; - } - if (!strcmp(filename, "AS_NEEDED")) { - ret = ld_add_file_list(s1, cmd, 1); - if (ret) - goto lib_parse_error; - } else { - /* TODO: Implement AS_NEEDED support. Ignore it for now */ - if (!as_needed) { - ret = ld_add_file(s1, filename); - if (ret) - goto lib_parse_error; - if (group) { - /* Add the filename *and* the libname to avoid future conversions */ - dynarray_add(&libs, &nblibs, tcc_strdup(filename)); - if (libname[0] != '\0') - dynarray_add(&libs, &nblibs, tcc_strdup(libname)); - } - } - } - t = ld_next(s1, filename, sizeof(filename)); - if (t == ',') { - t = ld_next(s1, filename, sizeof(filename)); - } - } - if (group && !as_needed) { - while (new_undef_syms()) { - int i; - - for (i = 0; i < nblibs; i ++) - ld_add_file(s1, libs[i]); - } - } -lib_parse_error: - dynarray_reset(&libs, &nblibs); - return ret; -} - -/* interpret a subset of GNU ldscripts to handle the dummy libc.so - files */ -ST_FUNC int tcc_load_ldscript(TCCState *s1) -{ - char cmd[64]; - char filename[1024]; - int t, ret; - - ch = handle_eob(); - for(;;) { - t = ld_next(s1, cmd, sizeof(cmd)); - if (t == LD_TOK_EOF) - return 0; - else if (t != LD_TOK_NAME) - return -1; - if (!strcmp(cmd, "INPUT") || - !strcmp(cmd, "GROUP")) { - ret = ld_add_file_list(s1, cmd, 0); - if (ret) - return ret; - } else if (!strcmp(cmd, "OUTPUT_FORMAT") || - !strcmp(cmd, "TARGET")) { - /* ignore some commands */ - t = ld_next(s1, cmd, sizeof(cmd)); - if (t != '(') - expect("("); - for(;;) { - t = ld_next(s1, filename, sizeof(filename)); - if (t == LD_TOK_EOF) { - tcc_error_noabort("unexpected end of file"); - return -1; - } else if (t == ')') { - break; - } - } - } else { - return -1; - } - } - return 0; -} -#endif /* !TCC_TARGET_PE */ diff --git a/tinyc/tccgen.c b/tinyc/tccgen.c deleted file mode 100644 index 7d554b5b1..000000000 --- a/tinyc/tccgen.c +++ /dev/null @@ -1,7369 +0,0 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -/********************************************************/ -/* global variables */ - -/* loc : local variable index - ind : output code index - rsym: return symbol - anon_sym: anonymous symbol index -*/ -ST_DATA int rsym, anon_sym, ind, loc; - -ST_DATA Sym *sym_free_first; -ST_DATA void **sym_pools; -ST_DATA int nb_sym_pools; - -ST_DATA Sym *global_stack; -ST_DATA Sym *local_stack; -ST_DATA Sym *define_stack; -ST_DATA Sym *global_label_stack; -ST_DATA Sym *local_label_stack; -static int local_scope; -static int in_sizeof; -static int section_sym; - -ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */ -ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */ -ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */ - -ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop; - -ST_DATA int const_wanted; /* true if constant wanted */ -ST_DATA int nocode_wanted; /* no code generation wanted */ -#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */ -#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */ -ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ -ST_DATA CType func_vt; /* current function return type (used by return instruction) */ -ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ -ST_DATA int func_vc; -ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ -ST_DATA const char *funcname; -ST_DATA int g_debug; - -ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; - -ST_DATA struct switch_t { - struct case_t { - int64_t v1, v2; - int sym; - } **p; int n; /* list of case ranges */ - int def_sym; /* default symbol */ -} *cur_switch; /* current switch */ - -/* ------------------------------------------------------------------------- */ - -static void gen_cast(CType *type); -static void gen_cast_s(int t); -static inline CType *pointed_type(CType *type); -static int is_compatible_types(CType *type1, CType *type2); -static int parse_btype(CType *type, AttributeDef *ad); -static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); -static void parse_expr_type(CType *type); -static void init_putv(CType *type, Section *sec, unsigned long c); -static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); -static void block(int *bsym, int *csym, int is_expr); -static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); -static void decl(int l); -static int decl0(int l, int is_for_loop_init, Sym *); -static void expr_eq(void); -static void vla_runtime_type_size(CType *type, int *a); -static void vla_sp_restore(void); -static void vla_sp_restore_root(void); -static int is_compatible_unqualified_types(CType *type1, CType *type2); -static inline int64_t expr_const64(void); -static void vpush64(int ty, unsigned long long v); -static void vpush(CType *type); -static int gvtst(int inv, int t); -static void gen_inline_functions(TCCState *s); -static void skip_or_save_block(TokenString **str); -static void gv_dup(void); - -ST_INLN int is_float(int t) -{ - int bt; - bt = t & VT_BTYPE; - return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; -} - -/* we use our own 'finite' function to avoid potential problems with - non standard math libs */ -/* XXX: endianness dependent */ -ST_FUNC int ieee_finite(double d) -{ - int p[4]; - memcpy(p, &d, sizeof(double)); - return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; -} - -/* compiling intel long double natively */ -#if (defined __i386__ || defined __x86_64__) \ - && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) -# define TCC_IS_NATIVE_387 -#endif - -ST_FUNC void test_lvalue(void) -{ - if (!(vtop->r & VT_LVAL)) - expect("lvalue"); -} - -ST_FUNC void check_vstack(void) -{ - if (pvtop != vtop) - tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop); -} - -/* ------------------------------------------------------------------------- */ -/* vstack debugging aid */ - -#if 0 -void pv (const char *lbl, int a, int b) -{ - int i; - for (i = a; i < a + b; ++i) { - SValue *p = &vtop[-i]; - printf("%s vtop[-%d] : type.t:%04x r:%04x r2:%04x c.i:%d\n", - lbl, i, p->type.t, p->r, p->r2, (int)p->c.i); - } -} -#endif - -/* ------------------------------------------------------------------------- */ -/* start of translation unit info */ -ST_FUNC void tcc_debug_start(TCCState *s1) -{ - if (s1->do_debug) { - char buf[512]; - - /* file info: full path + filename */ - section_sym = put_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - text_section->sh_num, NULL); - getcwd(buf, sizeof(buf)); -#ifdef _WIN32 - normalize_slashes(buf); -#endif - pstrcat(buf, sizeof(buf), "/"); - put_stabs_r(buf, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - put_stabs_r(file->filename, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - last_ind = 0; - last_line_num = 0; - } - - /* an elf symbol of type STT_FILE must be put so that STB_LOCAL - symbols can be safely used */ - put_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, - SHN_ABS, file->filename); -} - -/* put end of translation unit info */ -ST_FUNC void tcc_debug_end(TCCState *s1) -{ - if (!s1->do_debug) - return; - put_stabs_r(NULL, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - -} - -/* generate line number info */ -ST_FUNC void tcc_debug_line(TCCState *s1) -{ - if (!s1->do_debug) - return; - if ((last_line_num != file->line_num || last_ind != ind)) { - put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); - last_ind = ind; - last_line_num = file->line_num; - } -} - -/* put function symbol */ -ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym) -{ - char buf[512]; - - if (!s1->do_debug) - return; - - /* stabs info */ - /* XXX: we put here a dummy type */ - snprintf(buf, sizeof(buf), "%s:%c1", - funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); - put_stabs_r(buf, N_FUN, 0, file->line_num, 0, - cur_text_section, sym->c); - /* //gr gdb wants a line at the function */ - put_stabn(N_SLINE, 0, file->line_num, 0); - - last_ind = 0; - last_line_num = 0; -} - -/* put function size */ -ST_FUNC void tcc_debug_funcend(TCCState *s1, int size) -{ - if (!s1->do_debug) - return; - put_stabn(N_FUN, 0, 0, size); -} - -/* ------------------------------------------------------------------------- */ -ST_FUNC int tccgen_compile(TCCState *s1) -{ - cur_text_section = NULL; - funcname = ""; - anon_sym = SYM_FIRST_ANOM; - section_sym = 0; - const_wanted = 0; - nocode_wanted = 0x80000000; - - /* define some often used types */ - int_type.t = VT_INT; - char_pointer_type.t = VT_BYTE; - mk_pointer(&char_pointer_type); -#if PTR_SIZE == 4 - size_type.t = VT_INT | VT_UNSIGNED; - ptrdiff_type.t = VT_INT; -#elif LONG_SIZE == 4 - size_type.t = VT_LLONG | VT_UNSIGNED; - ptrdiff_type.t = VT_LLONG; -#else - size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED; - ptrdiff_type.t = VT_LONG | VT_LLONG; -#endif - func_old_type.t = VT_FUNC; - func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); - func_old_type.ref->f.func_call = FUNC_CDECL; - func_old_type.ref->f.func_type = FUNC_OLD; - - tcc_debug_start(s1); - -#ifdef TCC_TARGET_ARM - arm_init(s1); -#endif - -#ifdef INC_DEBUG - printf("%s: **** new file\n", file->filename); -#endif - - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; - next(); - decl(VT_CONST); - gen_inline_functions(s1); - check_vstack(); - /* end of translation unit info */ - tcc_debug_end(s1); - return 0; -} - -/* ------------------------------------------------------------------------- */ -/* apply storage attributes to Elf symbol */ - -static void update_storage(Sym *sym) -{ - ElfW(Sym) *esym; - if (0 == sym->c) - return; - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - if (sym->a.visibility) - esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) - | sym->a.visibility; - if (sym->a.weak) - esym->st_info = ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(esym->st_info)); -#ifdef TCC_TARGET_PE - if (sym->a.dllimport) - esym->st_other |= ST_PE_IMPORT; - if (sym->a.dllexport) - esym->st_other |= ST_PE_EXPORT; -#endif -#if 0 - printf("storage %s: vis=%d weak=%d exp=%d imp=%d\n", - get_tok_str(sym->v, NULL), - sym->a.visibility, - sym->a.weak, - sym->a.dllexport, - sym->a.dllimport - ); -#endif -} - -/* ------------------------------------------------------------------------- */ -/* update sym->c so that it points to an external symbol in section - 'section' with value 'value' */ - -ST_FUNC void put_extern_sym2(Sym *sym, Section *section, - addr_t value, unsigned long size, - int can_add_underscore) -{ - int sym_type, sym_bind, sh_num, info, other, t; - ElfW(Sym) *esym; - const char *name; - char buf1[256]; -#ifdef CONFIG_TCC_BCHECK - char buf[32]; -#endif - - if (section == NULL) - sh_num = SHN_UNDEF; - else if (section == SECTION_ABS) - sh_num = SHN_ABS; - else - sh_num = section->sh_num; - - if (!sym->c) { - name = get_tok_str(sym->v, NULL); -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) { - /* XXX: avoid doing that for statics ? */ - /* if bound checking is activated, we change some function - names by adding the "__bound" prefix */ - switch(sym->v) { -#ifdef TCC_TARGET_PE - /* XXX: we rely only on malloc hooks */ - case TOK_malloc: - case TOK_free: - case TOK_realloc: - case TOK_memalign: - case TOK_calloc: -#endif - case TOK_memcpy: - case TOK_memmove: - case TOK_memset: - case TOK_strlen: - case TOK_strcpy: - case TOK_alloca: - strcpy(buf, "__bound_"); - strcat(buf, name); - name = buf; - break; - } - } -#endif - t = sym->type.t; - if ((t & VT_BTYPE) == VT_FUNC) { - sym_type = STT_FUNC; - } else if ((t & VT_BTYPE) == VT_VOID) { - sym_type = STT_NOTYPE; - } else { - sym_type = STT_OBJECT; - } - if (t & VT_STATIC) - sym_bind = STB_LOCAL; - else - sym_bind = STB_GLOBAL; - other = 0; -#ifdef TCC_TARGET_PE - if (sym_type == STT_FUNC && sym->type.ref) { - Sym *ref = sym->type.ref; - if (ref->f.func_call == FUNC_STDCALL && can_add_underscore) { - sprintf(buf1, "_%s@%d", name, ref->f.func_args * PTR_SIZE); - name = buf1; - other |= ST_PE_STDCALL; - can_add_underscore = 0; - } - } -#endif - if (tcc_state->leading_underscore && can_add_underscore) { - buf1[0] = '_'; - pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); - name = buf1; - } - if (sym->asm_label) - name = get_tok_str(sym->asm_label, NULL); - info = ELFW(ST_INFO)(sym_bind, sym_type); - sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name); - } else { - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - esym->st_value = value; - esym->st_size = size; - esym->st_shndx = sh_num; - } - update_storage(sym); -} - -ST_FUNC void put_extern_sym(Sym *sym, Section *section, - addr_t value, unsigned long size) -{ - put_extern_sym2(sym, section, value, size, 1); -} - -/* add a new relocation entry to symbol 'sym' in section 's' */ -ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, - addr_t addend) -{ - int c = 0; - - if (nocode_wanted && s == cur_text_section) - return; - - if (sym) { - if (0 == sym->c) - put_extern_sym(sym, NULL, 0, 0); - c = sym->c; - } - - /* now we can add ELF relocation info */ - put_elf_reloca(symtab_section, s, offset, type, c, addend); -} - -#if PTR_SIZE == 4 -ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type) -{ - greloca(s, sym, offset, type, 0); -} -#endif - -/* ------------------------------------------------------------------------- */ -/* symbol allocator */ -static Sym *__sym_malloc(void) -{ - Sym *sym_pool, *sym, *last_sym; - int i; - - sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); - dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); - - last_sym = sym_free_first; - sym = sym_pool; - for(i = 0; i < SYM_POOL_NB; i++) { - sym->next = last_sym; - last_sym = sym; - sym++; - } - sym_free_first = last_sym; - return last_sym; -} - -static inline Sym *sym_malloc(void) -{ - Sym *sym; -#ifndef SYM_DEBUG - sym = sym_free_first; - if (!sym) - sym = __sym_malloc(); - sym_free_first = sym->next; - return sym; -#else - sym = tcc_malloc(sizeof(Sym)); - return sym; -#endif -} - -ST_INLN void sym_free(Sym *sym) -{ -#ifndef SYM_DEBUG - sym->next = sym_free_first; - sym_free_first = sym; -#else - tcc_free(sym); -#endif -} - -/* push, without hashing */ -ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c) -{ - Sym *s; - - s = sym_malloc(); - memset(s, 0, sizeof *s); - s->v = v; - s->type.t = t; - s->c = c; - /* add in stack */ - s->prev = *ps; - *ps = s; - return s; -} - -/* find a symbol and return its associated structure. 's' is the top - of the symbol stack */ -ST_FUNC Sym *sym_find2(Sym *s, int v) -{ - while (s) { - if (s->v == v) - return s; - else if (s->v == -1) - return NULL; - s = s->prev; - } - return NULL; -} - -/* structure lookup */ -ST_INLN Sym *struct_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_struct; -} - -/* find an identifier */ -ST_INLN Sym *sym_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_identifier; -} - -/* push a given symbol on the symbol stack */ -ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) -{ - Sym *s, **ps; - TokenSym *ts; - - if (local_stack) - ps = &local_stack; - else - ps = &global_stack; - s = sym_push2(ps, v, type->t, c); - s->type.ref = type->ref; - s->r = r; - /* don't record fields or anonymous symbols */ - /* XXX: simplify */ - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - /* record symbol in token array */ - ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; - if (v & SYM_STRUCT) - ps = &ts->sym_struct; - else - ps = &ts->sym_identifier; - s->prev_tok = *ps; - *ps = s; - s->sym_scope = local_scope; - if (s->prev_tok && s->prev_tok->sym_scope == s->sym_scope) - tcc_error("redeclaration of '%s'", - get_tok_str(v & ~SYM_STRUCT, NULL)); - } - return s; -} - -/* push a global identifier */ -ST_FUNC Sym *global_identifier_push(int v, int t, int c) -{ - Sym *s, **ps; - s = sym_push2(&global_stack, v, t, c); - /* don't record anonymous symbol */ - if (v < SYM_FIRST_ANOM) { - ps = &table_ident[v - TOK_IDENT]->sym_identifier; - /* modify the top most local identifier, so that - sym_identifier will point to 's' when popped */ - while (*ps != NULL) - ps = &(*ps)->prev_tok; - s->prev_tok = NULL; - *ps = s; - } - return s; -} - -/* pop symbols until top reaches 'b'. If KEEP is non-zero don't really - pop them yet from the list, but do remove them from the token array. */ -ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) -{ - Sym *s, *ss, **ps; - TokenSym *ts; - int v; - - s = *ptop; - while(s != b) { - ss = s->prev; - v = s->v; - /* remove symbol in token array */ - /* XXX: simplify */ - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; - if (v & SYM_STRUCT) - ps = &ts->sym_struct; - else - ps = &ts->sym_identifier; - *ps = s->prev_tok; - } - if (!keep) - sym_free(s); - s = ss; - } - if (!keep) - *ptop = b; -} - -/* ------------------------------------------------------------------------- */ - -static void vsetc(CType *type, int r, CValue *vc) -{ - int v; - - if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full (vstack)"); - /* cannot let cpu flags if other instruction are generated. Also - avoid leaving VT_JMP anywhere except on the top of the stack - because it would complicate the code generator. - - Don't do this when nocode_wanted. vtop might come from - !nocode_wanted regions (see 88_codeopt.c) and transforming - it to a register without actually generating code is wrong - as their value might still be used for real. All values - we push under nocode_wanted will eventually be popped - again, so that the VT_CMP/VT_JMP value will be in vtop - when code is unsuppressed again. - - Same logic below in vswap(); */ - if (vtop >= vstack && !nocode_wanted) { - v = vtop->r & VT_VALMASK; - if (v == VT_CMP || (v & ~1) == VT_JMP) - gv(RC_INT); - } - - vtop++; - vtop->type = *type; - vtop->r = r; - vtop->r2 = VT_CONST; - vtop->c = *vc; - vtop->sym = NULL; -} - -ST_FUNC void vswap(void) -{ - SValue tmp; - /* cannot vswap cpu flags. See comment at vsetc() above */ - if (vtop >= vstack && !nocode_wanted) { - int v = vtop->r & VT_VALMASK; - if (v == VT_CMP || (v & ~1) == VT_JMP) - gv(RC_INT); - } - tmp = vtop[0]; - vtop[0] = vtop[-1]; - vtop[-1] = tmp; -} - -/* pop stack value */ -ST_FUNC void vpop(void) -{ - int v; - v = vtop->r & VT_VALMASK; -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - /* for x86, we need to pop the FP stack */ - if (v == TREG_ST0) { - o(0xd8dd); /* fstp %st(0) */ - } else -#endif - if (v == VT_JMP || v == VT_JMPI) { - /* need to put correct jump if && or || without test */ - gsym(vtop->c.i); - } - vtop--; -} - -/* push constant of type "type" with useless value */ -ST_FUNC void vpush(CType *type) -{ - vset(type, VT_CONST, 0); -} - -/* push integer constant */ -ST_FUNC void vpushi(int v) -{ - CValue cval; - cval.i = v; - vsetc(&int_type, VT_CONST, &cval); -} - -/* push a pointer sized constant */ -static void vpushs(addr_t v) -{ - CValue cval; - cval.i = v; - vsetc(&size_type, VT_CONST, &cval); -} - -/* push arbitrary 64bit constant */ -ST_FUNC void vpush64(int ty, unsigned long long v) -{ - CValue cval; - CType ctype; - ctype.t = ty; - ctype.ref = NULL; - cval.i = v; - vsetc(&ctype, VT_CONST, &cval); -} - -/* push long long constant */ -static inline void vpushll(long long v) -{ - vpush64(VT_LLONG, v); -} - -ST_FUNC void vset(CType *type, int r, int v) -{ - CValue cval; - - cval.i = v; - vsetc(type, r, &cval); -} - -static void vseti(int r, int v) -{ - CType type; - type.t = VT_INT; - type.ref = NULL; - vset(&type, r, v); -} - -ST_FUNC void vpushv(SValue *v) -{ - if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full (vstack)"); - vtop++; - *vtop = *v; -} - -static void vdup(void) -{ - vpushv(vtop); -} - -/* rotate n first stack elements to the bottom - I1 ... In -> I2 ... In I1 [top is right] -*/ -ST_FUNC void vrotb(int n) -{ - int i; - SValue tmp; - - tmp = vtop[-n + 1]; - for(i=-n+1;i!=0;i++) - vtop[i] = vtop[i+1]; - vtop[0] = tmp; -} - -/* rotate the n elements before entry e towards the top - I1 ... In ... -> In I1 ... I(n-1) ... [top is right] - */ -ST_FUNC void vrote(SValue *e, int n) -{ - int i; - SValue tmp; - - tmp = *e; - for(i = 0;i < n - 1; i++) - e[-i] = e[-i - 1]; - e[-n + 1] = tmp; -} - -/* rotate n first stack elements to the top - I1 ... In -> In I1 ... I(n-1) [top is right] - */ -ST_FUNC void vrott(int n) -{ - vrote(vtop, n); -} - -/* push a symbol value of TYPE */ -static inline void vpushsym(CType *type, Sym *sym) -{ - CValue cval; - cval.i = 0; - vsetc(type, VT_CONST | VT_SYM, &cval); - vtop->sym = sym; -} - -/* Return a static symbol pointing to a section */ -ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) -{ - int v; - Sym *sym; - - v = anon_sym++; - sym = global_identifier_push(v, type->t | VT_STATIC, 0); - sym->type.ref = type->ref; - sym->r = VT_CONST | VT_SYM; - put_extern_sym(sym, sec, offset, size); - return sym; -} - -/* push a reference to a section offset by adding a dummy symbol */ -static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) -{ - vpushsym(type, get_sym_ref(type, sec, offset, size)); -} - -/* define a new external reference to a symbol 'v' of type 'u' */ -ST_FUNC Sym *external_global_sym(int v, CType *type, int r) -{ - Sym *s; - - s = sym_find(v); - if (!s) { - /* push forward reference */ - s = global_identifier_push(v, type->t | VT_EXTERN, 0); - s->type.ref = type->ref; - s->r = r | VT_CONST | VT_SYM; - } - return s; -} - -/* Merge some storage attributes. */ -static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) -{ - if (type && !is_compatible_types(&sym->type, type)) - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(sym->v, NULL)); -#ifdef TCC_TARGET_PE - if (sym->a.dllimport != ad->a.dllimport) - tcc_error("incompatible dll linkage for redefinition of '%s'", - get_tok_str(sym->v, NULL)); -#endif - sym->a.dllexport |= ad->a.dllexport; - sym->a.weak |= ad->a.weak; - if (ad->a.visibility) { - int vis = sym->a.visibility; - int vis2 = ad->a.visibility; - if (vis == STV_DEFAULT) - vis = vis2; - else if (vis2 != STV_DEFAULT) - vis = (vis < vis2) ? vis : vis2; - sym->a.visibility = vis; - } - if (ad->a.aligned) - sym->a.aligned = ad->a.aligned; - if (ad->asm_label) - sym->asm_label = ad->asm_label; - update_storage(sym); -} - -/* define a new external reference to a symbol 'v' */ -static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) -{ - Sym *s; - s = sym_find(v); - if (!s) { - /* push forward reference */ - s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); - s->type.t |= VT_EXTERN; - s->a = ad->a; - s->sym_scope = 0; - } else { - if (s->type.ref == func_old_type.ref) { - s->type.ref = type->ref; - s->r = r | VT_CONST | VT_SYM; - s->type.t |= VT_EXTERN; - } - patch_storage(s, ad, type); - } - return s; -} - -/* push a reference to global symbol v */ -ST_FUNC void vpush_global_sym(CType *type, int v) -{ - vpushsym(type, external_global_sym(v, type, 0)); -} - -/* save registers up to (vtop - n) stack entry */ -ST_FUNC void save_regs(int n) -{ - SValue *p, *p1; - for(p = vstack, p1 = vtop - n; p <= p1; p++) - save_reg(p->r); -} - -/* save r to the memory stack, and mark it as being free */ -ST_FUNC void save_reg(int r) -{ - save_reg_upstack(r, 0); -} - -/* save r to the memory stack, and mark it as being free, - if seen up to (vtop - n) stack entry */ -ST_FUNC void save_reg_upstack(int r, int n) -{ - int l, saved, size, align; - SValue *p, *p1, sv; - CType *type; - - if ((r &= VT_VALMASK) >= VT_CONST) - return; - if (nocode_wanted) - return; - - /* modify all stack values */ - saved = 0; - l = 0; - for(p = vstack, p1 = vtop - n; p <= p1; p++) { - if ((p->r & VT_VALMASK) == r || - ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { - /* must save value on stack if not already done */ - if (!saved) { - /* NOTE: must reload 'r' because r might be equal to r2 */ - r = p->r & VT_VALMASK; - /* store register in the stack */ - type = &p->type; - if ((p->r & VT_LVAL) || - (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) -#if PTR_SIZE == 8 - type = &char_pointer_type; -#else - type = &int_type; -#endif - size = type_size(type, &align); - loc = (loc - size) & -align; - sv.type.t = type->t; - sv.r = VT_LOCAL | VT_LVAL; - sv.c.i = loc; - store(r, &sv); -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - /* x86 specific: need to pop fp register ST0 if saved */ - if (r == TREG_ST0) { - o(0xd8dd); /* fstp %st(0) */ - } -#endif -#if PTR_SIZE == 4 - /* special long long case */ - if ((type->t & VT_BTYPE) == VT_LLONG) { - sv.c.i += 4; - store(p->r2, &sv); - } -#endif - l = loc; - saved = 1; - } - /* mark that stack entry as being saved on the stack */ - if (p->r & VT_LVAL) { - /* also clear the bounded flag because the - relocation address of the function was stored in - p->c.i */ - p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; - } else { - p->r = lvalue_type(p->type.t) | VT_LOCAL; - } - p->r2 = VT_CONST; - p->c.i = l; - } - } -} - -#ifdef TCC_TARGET_ARM -/* find a register of class 'rc2' with at most one reference on stack. - * If none, call get_reg(rc) */ -ST_FUNC int get_reg_ex(int rc, int rc2) -{ - int r; - SValue *p; - - for(r=0;rr & VT_VALMASK) == r || - (p->r2 & VT_VALMASK) == r) - n++; - } - if (n <= 1) - return r; - } - } - return get_reg(rc); -} -#endif - -/* find a free register of class 'rc'. If none, save one register */ -ST_FUNC int get_reg(int rc) -{ - int r; - SValue *p; - - /* find a free register */ - for(r=0;rr & VT_VALMASK) == r || - (p->r2 & VT_VALMASK) == r) - goto notfound; - } - return r; - } - notfound: ; - } - - /* no register left : free the first one on the stack (VERY - IMPORTANT to start from the bottom to ensure that we don't - spill registers used in gen_opi()) */ - for(p=vstack;p<=vtop;p++) { - /* look at second register (if long long) */ - r = p->r2 & VT_VALMASK; - if (r < VT_CONST && (reg_classes[r] & rc)) - goto save_found; - r = p->r & VT_VALMASK; - if (r < VT_CONST && (reg_classes[r] & rc)) { - save_found: - save_reg(r); - return r; - } - } - /* Should never comes here */ - return -1; -} - -/* move register 's' (of type 't') to 'r', and flush previous value of r to memory - if needed */ -static void move_reg(int r, int s, int t) -{ - SValue sv; - - if (r != s) { - save_reg(r); - sv.type.t = t; - sv.type.ref = NULL; - sv.r = s; - sv.c.i = 0; - load(r, &sv); - } -} - -/* get address of vtop (vtop MUST BE an lvalue) */ -ST_FUNC void gaddrof(void) -{ - vtop->r &= ~VT_LVAL; - /* tricky: if saved lvalue, then we can go back to lvalue */ - if ((vtop->r & VT_VALMASK) == VT_LLOCAL) - vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; - - -} - -#ifdef CONFIG_TCC_BCHECK -/* generate lvalue bound code */ -static void gbound(void) -{ - int lval_type; - CType type1; - - vtop->r &= ~VT_MUSTBOUND; - /* if lvalue, then use checking code before dereferencing */ - if (vtop->r & VT_LVAL) { - /* if not VT_BOUNDED value, then make one */ - if (!(vtop->r & VT_BOUNDED)) { - lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); - /* must save type because we must set it to int to get pointer */ - type1 = vtop->type; - vtop->type.t = VT_PTR; - gaddrof(); - vpushi(0); - gen_bounded_ptr_add(); - vtop->r |= lval_type; - vtop->type = type1; - } - /* then check for dereferencing */ - gen_bounded_ptr_deref(); - } -} -#endif - -static void incr_bf_adr(int o) -{ - vtop->type = char_pointer_type; - gaddrof(); - vpushi(o); - gen_op('+'); - vtop->type.t = (vtop->type.t & ~(VT_BTYPE|VT_DEFSIGN)) - | (VT_BYTE|VT_UNSIGNED); - vtop->r = (vtop->r & ~VT_LVAL_TYPE) - | (VT_LVAL_BYTE|VT_LVAL_UNSIGNED|VT_LVAL); -} - -/* single-byte load mode for packed or otherwise unaligned bitfields */ -static void load_packed_bf(CType *type, int bit_pos, int bit_size) -{ - int n, o, bits; - save_reg_upstack(vtop->r, 1); - vpush64(type->t & VT_BTYPE, 0); // B X - bits = 0, o = bit_pos >> 3, bit_pos &= 7; - do { - vswap(); // X B - incr_bf_adr(o); - vdup(); // X B B - n = 8 - bit_pos; - if (n > bit_size) - n = bit_size; - if (bit_pos) - vpushi(bit_pos), gen_op(TOK_SHR), bit_pos = 0; // X B Y - if (n < 8) - vpushi((1 << n) - 1), gen_op('&'); - gen_cast(type); - if (bits) - vpushi(bits), gen_op(TOK_SHL); - vrotb(3); // B Y X - gen_op('|'); // B X - bits += n, bit_size -= n, o = 1; - } while (bit_size); - vswap(), vpop(); - if (!(type->t & VT_UNSIGNED)) { - n = ((type->t & VT_BTYPE) == VT_LLONG ? 64 : 32) - bits; - vpushi(n), gen_op(TOK_SHL); - vpushi(n), gen_op(TOK_SAR); - } -} - -/* single-byte store mode for packed or otherwise unaligned bitfields */ -static void store_packed_bf(int bit_pos, int bit_size) -{ - int bits, n, o, m, c; - - c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - vswap(); // X B - save_reg_upstack(vtop->r, 1); - bits = 0, o = bit_pos >> 3, bit_pos &= 7; - do { - incr_bf_adr(o); // X B - vswap(); //B X - c ? vdup() : gv_dup(); // B V X - vrott(3); // X B V - if (bits) - vpushi(bits), gen_op(TOK_SHR); - if (bit_pos) - vpushi(bit_pos), gen_op(TOK_SHL); - n = 8 - bit_pos; - if (n > bit_size) - n = bit_size; - if (n < 8) { - m = ((1 << n) - 1) << bit_pos; - vpushi(m), gen_op('&'); // X B V1 - vpushv(vtop-1); // X B V1 B - vpushi(m & 0x80 ? ~m & 0x7f : ~m); - gen_op('&'); // X B V1 B1 - gen_op('|'); // X B V2 - } - vdup(), vtop[-1] = vtop[-2]; // X B B V2 - vstore(), vpop(); // X B - bits += n, bit_size -= n, bit_pos = 0, o = 1; - } while (bit_size); - vpop(), vpop(); -} - -static int adjust_bf(SValue *sv, int bit_pos, int bit_size) -{ - int t; - if (0 == sv->type.ref) - return 0; - t = sv->type.ref->auxtype; - if (t != -1 && t != VT_STRUCT) { - sv->type.t = (sv->type.t & ~VT_BTYPE) | t; - sv->r = (sv->r & ~VT_LVAL_TYPE) | lvalue_type(sv->type.t); - } - return t; -} - -/* store vtop a register belonging to class 'rc'. lvalues are - converted to values. Cannot be used if cannot be converted to - register value (such as structures). */ -ST_FUNC int gv(int rc) -{ - int r, bit_pos, bit_size, size, align, rc2; - - /* NOTE: get_reg can modify vstack[] */ - if (vtop->type.t & VT_BITFIELD) { - CType type; - - bit_pos = BIT_POS(vtop->type.t); - bit_size = BIT_SIZE(vtop->type.t); - /* remove bit field info to avoid loops */ - vtop->type.t &= ~VT_STRUCT_MASK; - - type.ref = NULL; - type.t = vtop->type.t & VT_UNSIGNED; - if ((vtop->type.t & VT_BTYPE) == VT_BOOL) - type.t |= VT_UNSIGNED; - - r = adjust_bf(vtop, bit_pos, bit_size); - - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) - type.t |= VT_LLONG; - else - type.t |= VT_INT; - - if (r == VT_STRUCT) { - load_packed_bf(&type, bit_pos, bit_size); - } else { - int bits = (type.t & VT_BTYPE) == VT_LLONG ? 64 : 32; - /* cast to int to propagate signedness in following ops */ - gen_cast(&type); - /* generate shifts */ - vpushi(bits - (bit_pos + bit_size)); - gen_op(TOK_SHL); - vpushi(bits - bit_size); - /* NOTE: transformed to SHR if unsigned */ - gen_op(TOK_SAR); - } - r = gv(rc); - } else { - if (is_float(vtop->type.t) && - (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - unsigned long offset; - /* CPUs usually cannot use float constants, so we store them - generically in data segment */ - size = type_size(&vtop->type, &align); - if (NODATA_WANTED) - size = 0, align = 1; - offset = section_add(data_section, size, align); - vpush_ref(&vtop->type, data_section, offset, size); - vswap(); - init_putv(&vtop->type, data_section, offset); - vtop->r |= VT_LVAL; - } -#ifdef CONFIG_TCC_BCHECK - if (vtop->r & VT_MUSTBOUND) - gbound(); -#endif - - r = vtop->r & VT_VALMASK; - rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; -#ifndef TCC_TARGET_ARM64 - if (rc == RC_IRET) - rc2 = RC_LRET; -#ifdef TCC_TARGET_X86_64 - else if (rc == RC_FRET) - rc2 = RC_QRET; -#endif -#endif - /* need to reload if: - - constant - - lvalue (need to dereference pointer) - - already a register, but not in the right class */ - if (r >= VT_CONST - || (vtop->r & VT_LVAL) - || !(reg_classes[r] & rc) -#if PTR_SIZE == 8 - || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) - || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) -#else - || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) -#endif - ) - { - r = get_reg(rc); -#if PTR_SIZE == 8 - if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { - int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; -#else - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - int addr_type = VT_INT, load_size = 4, load_type = VT_INT; - unsigned long long ll; -#endif - int r2, original_type; - original_type = vtop->type.t; - /* two register type load : expand to two words - temporarily */ -#if PTR_SIZE == 4 - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - /* load constant */ - ll = vtop->c.i; - vtop->c.i = ll; /* first word */ - load(r, vtop); - vtop->r = r; /* save register value */ - vpushi(ll >> 32); /* second word */ - } else -#endif - if (vtop->r & VT_LVAL) { - /* We do not want to modifier the long long - pointer here, so the safest (and less - efficient) is to save all the other registers - in the stack. XXX: totally inefficient. */ - #if 0 - save_regs(1); - #else - /* lvalue_save: save only if used further down the stack */ - save_reg_upstack(vtop->r, 1); - #endif - /* load from memory */ - vtop->type.t = load_type; - load(r, vtop); - vdup(); - vtop[-1].r = r; /* save register value */ - /* increment pointer to get second word */ - vtop->type.t = addr_type; - gaddrof(); - vpushi(load_size); - gen_op('+'); - vtop->r |= VT_LVAL; - vtop->type.t = load_type; - } else { - /* move registers */ - load(r, vtop); - vdup(); - vtop[-1].r = r; /* save register value */ - vtop->r = vtop[-1].r2; - } - /* Allocate second register. Here we rely on the fact that - get_reg() tries first to free r2 of an SValue. */ - r2 = get_reg(rc2); - load(r2, vtop); - vpop(); - /* write second register */ - vtop->r2 = r2; - vtop->type.t = original_type; - } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { - int t1, t; - /* lvalue of scalar type : need to use lvalue type - because of possible cast */ - t = vtop->type.t; - t1 = t; - /* compute memory access type */ - if (vtop->r & VT_LVAL_BYTE) - t = VT_BYTE; - else if (vtop->r & VT_LVAL_SHORT) - t = VT_SHORT; - if (vtop->r & VT_LVAL_UNSIGNED) - t |= VT_UNSIGNED; - vtop->type.t = t; - load(r, vtop); - /* restore wanted type */ - vtop->type.t = t1; - } else { - /* one register type load */ - load(r, vtop); - } - } - vtop->r = r; -#ifdef TCC_TARGET_C67 - /* uses register pairs for doubles */ - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - vtop->r2 = r+1; -#endif - } - return r; -} - -/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ -ST_FUNC void gv2(int rc1, int rc2) -{ - int v; - - /* generate more generic register first. But VT_JMP or VT_CMP - values must be generated first in all cases to avoid possible - reload errors */ - v = vtop[0].r & VT_VALMASK; - if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { - vswap(); - gv(rc1); - vswap(); - gv(rc2); - /* test if reload is needed for first register */ - if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { - vswap(); - gv(rc1); - vswap(); - } - } else { - gv(rc2); - vswap(); - gv(rc1); - vswap(); - /* test if reload is needed for first register */ - if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { - gv(rc2); - } - } -} - -#ifndef TCC_TARGET_ARM64 -/* wrapper around RC_FRET to return a register by type */ -static int rc_fret(int t) -{ -#ifdef TCC_TARGET_X86_64 - if (t == VT_LDOUBLE) { - return RC_ST0; - } -#endif - return RC_FRET; -} -#endif - -/* wrapper around REG_FRET to return a register by type */ -static int reg_fret(int t) -{ -#ifdef TCC_TARGET_X86_64 - if (t == VT_LDOUBLE) { - return TREG_ST0; - } -#endif - return REG_FRET; -} - -#if PTR_SIZE == 4 -/* expand 64bit on stack in two ints */ -static void lexpand(void) -{ - int u, v; - u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); - v = vtop->r & (VT_VALMASK | VT_LVAL); - if (v == VT_CONST) { - vdup(); - vtop[0].c.i >>= 32; - } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { - vdup(); - vtop[0].c.i += 4; - } else { - gv(RC_INT); - vdup(); - vtop[0].r = vtop[-1].r2; - vtop[0].r2 = vtop[-1].r2 = VT_CONST; - } - vtop[0].type.t = vtop[-1].type.t = VT_INT | u; -} -#endif - -#ifdef TCC_TARGET_ARM -/* expand long long on stack */ -ST_FUNC void lexpand_nr(void) -{ - int u,v; - - u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); - vdup(); - vtop->r2 = VT_CONST; - vtop->type.t = VT_INT | u; - v=vtop[-1].r & (VT_VALMASK | VT_LVAL); - if (v == VT_CONST) { - vtop[-1].c.i = vtop->c.i; - vtop->c.i = vtop->c.i >> 32; - vtop->r = VT_CONST; - } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { - vtop->c.i += 4; - vtop->r = vtop[-1].r; - } else if (v > VT_CONST) { - vtop--; - lexpand(); - } else - vtop->r = vtop[-1].r2; - vtop[-1].r2 = VT_CONST; - vtop[-1].type.t = VT_INT | u; -} -#endif - -#if PTR_SIZE == 4 -/* build a long long from two ints */ -static void lbuild(int t) -{ - gv2(RC_INT, RC_INT); - vtop[-1].r2 = vtop[0].r; - vtop[-1].type.t = t; - vpop(); -} -#endif - -/* convert stack entry to register and duplicate its value in another - register */ -static void gv_dup(void) -{ - int rc, t, r, r1; - SValue sv; - - t = vtop->type.t; -#if PTR_SIZE == 4 - if ((t & VT_BTYPE) == VT_LLONG) { - if (t & VT_BITFIELD) { - gv(RC_INT); - t = vtop->type.t; - } - lexpand(); - gv_dup(); - vswap(); - vrotb(3); - gv_dup(); - vrotb(4); - /* stack: H L L1 H1 */ - lbuild(t); - vrotb(3); - vrotb(3); - vswap(); - lbuild(t); - vswap(); - } else -#endif - { - /* duplicate value */ - rc = RC_INT; - sv.type.t = VT_INT; - if (is_float(t)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((t & VT_BTYPE) == VT_LDOUBLE) { - rc = RC_ST0; - } -#endif - sv.type.t = t; - } - r = gv(rc); - r1 = get_reg(rc); - sv.r = r; - sv.c.i = 0; - load(r1, &sv); /* move r to r1 */ - vdup(); - /* duplicates value */ - if (r != r1) - vtop->r = r1; - } -} - -/* Generate value test - * - * Generate a test for any value (jump, comparison and integers) */ -ST_FUNC int gvtst(int inv, int t) -{ - int v = vtop->r & VT_VALMASK; - if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { - vpushi(0); - gen_op(TOK_NE); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - vtop--; - return t; - } - return gtst(inv, t); -} - -#if PTR_SIZE == 4 -/* generate CPU independent (unsigned) long long operations */ -static void gen_opl(int op) -{ - int t, a, b, op1, c, i; - int func; - unsigned short reg_iret = REG_IRET; - unsigned short reg_lret = REG_LRET; - SValue tmp; - - switch(op) { - case '/': - case TOK_PDIV: - func = TOK___divdi3; - goto gen_func; - case TOK_UDIV: - func = TOK___udivdi3; - goto gen_func; - case '%': - func = TOK___moddi3; - goto gen_mod_func; - case TOK_UMOD: - func = TOK___umoddi3; - gen_mod_func: -#ifdef TCC_ARM_EABI - reg_iret = TREG_R2; - reg_lret = TREG_R3; -#endif - gen_func: - /* call generic long long function */ - vpush_global_sym(&func_old_type, func); - vrott(3); - gfunc_call(2); - vpushi(0); - vtop->r = reg_iret; - vtop->r2 = reg_lret; - break; - case '^': - case '&': - case '|': - case '*': - case '+': - case '-': - //pv("gen_opl A",0,2); - t = vtop->type.t; - vswap(); - lexpand(); - vrotb(3); - lexpand(); - /* stack: L1 H1 L2 H2 */ - tmp = vtop[0]; - vtop[0] = vtop[-3]; - vtop[-3] = tmp; - tmp = vtop[-2]; - vtop[-2] = vtop[-3]; - vtop[-3] = tmp; - vswap(); - /* stack: H1 H2 L1 L2 */ - //pv("gen_opl B",0,4); - if (op == '*') { - vpushv(vtop - 1); - vpushv(vtop - 1); - gen_op(TOK_UMULL); - lexpand(); - /* stack: H1 H2 L1 L2 ML MH */ - for(i=0;i<4;i++) - vrotb(6); - /* stack: ML MH H1 H2 L1 L2 */ - tmp = vtop[0]; - vtop[0] = vtop[-2]; - vtop[-2] = tmp; - /* stack: ML MH H1 L2 H2 L1 */ - gen_op('*'); - vrotb(3); - vrotb(3); - gen_op('*'); - /* stack: ML MH M1 M2 */ - gen_op('+'); - gen_op('+'); - } else if (op == '+' || op == '-') { - /* XXX: add non carry method too (for MIPS or alpha) */ - if (op == '+') - op1 = TOK_ADDC1; - else - op1 = TOK_SUBC1; - gen_op(op1); - /* stack: H1 H2 (L1 op L2) */ - vrotb(3); - vrotb(3); - gen_op(op1 + 1); /* TOK_xxxC2 */ - } else { - gen_op(op); - /* stack: H1 H2 (L1 op L2) */ - vrotb(3); - vrotb(3); - /* stack: (L1 op L2) H1 H2 */ - gen_op(op); - /* stack: (L1 op L2) (H1 op H2) */ - } - /* stack: L H */ - lbuild(t); - break; - case TOK_SAR: - case TOK_SHR: - case TOK_SHL: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - t = vtop[-1].type.t; - vswap(); - lexpand(); - vrotb(3); - /* stack: L H shift */ - c = (int)vtop->c.i; - /* constant: simpler */ - /* NOTE: all comments are for SHL. the other cases are - done by swapping words */ - vpop(); - if (op != TOK_SHL) - vswap(); - if (c >= 32) { - /* stack: L H */ - vpop(); - if (c > 32) { - vpushi(c - 32); - gen_op(op); - } - if (op != TOK_SAR) { - vpushi(0); - } else { - gv_dup(); - vpushi(31); - gen_op(TOK_SAR); - } - vswap(); - } else { - vswap(); - gv_dup(); - /* stack: H L L */ - vpushi(c); - gen_op(op); - vswap(); - vpushi(32 - c); - if (op == TOK_SHL) - gen_op(TOK_SHR); - else - gen_op(TOK_SHL); - vrotb(3); - /* stack: L L H */ - vpushi(c); - if (op == TOK_SHL) - gen_op(TOK_SHL); - else - gen_op(TOK_SHR); - gen_op('|'); - } - if (op != TOK_SHL) - vswap(); - lbuild(t); - } else { - /* XXX: should provide a faster fallback on x86 ? */ - switch(op) { - case TOK_SAR: - func = TOK___ashrdi3; - goto gen_func; - case TOK_SHR: - func = TOK___lshrdi3; - goto gen_func; - case TOK_SHL: - func = TOK___ashldi3; - goto gen_func; - } - } - break; - default: - /* compare operations */ - t = vtop->type.t; - vswap(); - lexpand(); - vrotb(3); - lexpand(); - /* stack: L1 H1 L2 H2 */ - tmp = vtop[-1]; - vtop[-1] = vtop[-2]; - vtop[-2] = tmp; - /* stack: L1 L2 H1 H2 */ - /* compare high */ - op1 = op; - /* when values are equal, we need to compare low words. since - the jump is inverted, we invert the test too. */ - if (op1 == TOK_LT) - op1 = TOK_LE; - else if (op1 == TOK_GT) - op1 = TOK_GE; - else if (op1 == TOK_ULT) - op1 = TOK_ULE; - else if (op1 == TOK_UGT) - op1 = TOK_UGE; - a = 0; - b = 0; - gen_op(op1); - if (op == TOK_NE) { - b = gvtst(0, 0); - } else { - a = gvtst(1, 0); - if (op != TOK_EQ) { - /* generate non equal test */ - vpushi(TOK_NE); - vtop->r = VT_CMP; - b = gvtst(0, 0); - } - } - /* compare low. Always unsigned */ - op1 = op; - if (op1 == TOK_LT) - op1 = TOK_ULT; - else if (op1 == TOK_LE) - op1 = TOK_ULE; - else if (op1 == TOK_GT) - op1 = TOK_UGT; - else if (op1 == TOK_GE) - op1 = TOK_UGE; - gen_op(op1); - a = gvtst(1, a); - gsym(b); - vseti(VT_JMPI, a); - break; - } -} -#endif - -static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) -{ - uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); - return (a ^ b) >> 63 ? -x : x; -} - -static int gen_opic_lt(uint64_t a, uint64_t b) -{ - return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); -} - -/* handle integer constant optimizations and various machine - independent opt */ -static void gen_opic(int op) -{ - SValue *v1 = vtop - 1; - SValue *v2 = vtop; - int t1 = v1->type.t & VT_BTYPE; - int t2 = v2->type.t & VT_BTYPE; - int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - uint64_t l1 = c1 ? v1->c.i : 0; - uint64_t l2 = c2 ? v2->c.i : 0; - int shm = (t1 == VT_LLONG) ? 63 : 31; - - if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) - l1 = ((uint32_t)l1 | - (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); - if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR)) - l2 = ((uint32_t)l2 | - (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000))); - - if (c1 && c2) { - switch(op) { - case '+': l1 += l2; break; - case '-': l1 -= l2; break; - case '&': l1 &= l2; break; - case '^': l1 ^= l2; break; - case '|': l1 |= l2; break; - case '*': l1 *= l2; break; - - case TOK_PDIV: - case '/': - case '%': - case TOK_UDIV: - case TOK_UMOD: - /* if division by zero, generate explicit division */ - if (l2 == 0) { - if (const_wanted) - tcc_error("division by zero in constant"); - goto general_case; - } - switch(op) { - default: l1 = gen_opic_sdiv(l1, l2); break; - case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; - case TOK_UDIV: l1 = l1 / l2; break; - case TOK_UMOD: l1 = l1 % l2; break; - } - break; - case TOK_SHL: l1 <<= (l2 & shm); break; - case TOK_SHR: l1 >>= (l2 & shm); break; - case TOK_SAR: - l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); - break; - /* tests */ - case TOK_ULT: l1 = l1 < l2; break; - case TOK_UGE: l1 = l1 >= l2; break; - case TOK_EQ: l1 = l1 == l2; break; - case TOK_NE: l1 = l1 != l2; break; - case TOK_ULE: l1 = l1 <= l2; break; - case TOK_UGT: l1 = l1 > l2; break; - case TOK_LT: l1 = gen_opic_lt(l1, l2); break; - case TOK_GE: l1 = !gen_opic_lt(l1, l2); break; - case TOK_LE: l1 = !gen_opic_lt(l2, l1); break; - case TOK_GT: l1 = gen_opic_lt(l2, l1); break; - /* logical */ - case TOK_LAND: l1 = l1 && l2; break; - case TOK_LOR: l1 = l1 || l2; break; - default: - goto general_case; - } - if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) - l1 = ((uint32_t)l1 | - (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); - v1->c.i = l1; - vtop--; - } else { - /* if commutative ops, put c2 as constant */ - if (c1 && (op == '+' || op == '&' || op == '^' || - op == '|' || op == '*')) { - vswap(); - c2 = c1; //c = c1, c1 = c2, c2 = c; - l2 = l1; //l = l1, l1 = l2, l2 = l; - } - if (!const_wanted && - c1 && ((l1 == 0 && - (op == TOK_SHL || op == TOK_SHR || op == TOK_SAR)) || - (l1 == -1 && op == TOK_SAR))) { - /* treat (0 << x), (0 >> x) and (-1 >> x) as constant */ - vtop--; - } else if (!const_wanted && - c2 && ((l2 == 0 && (op == '&' || op == '*')) || - (op == '|' && - (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))) || - (l2 == 1 && (op == '%' || op == TOK_UMOD)))) { - /* treat (x & 0), (x * 0), (x | -1) and (x % 1) as constant */ - if (l2 == 1) - vtop->c.i = 0; - vswap(); - vtop--; - } else if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || - op == TOK_PDIV) && - l2 == 1) || - ((op == '+' || op == '-' || op == '|' || op == '^' || - op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && - l2 == 0) || - (op == '&' && - (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))))) { - /* filter out NOP operations like x*1, x-0, x&-1... */ - vtop--; - } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { - /* try to use shifts instead of muls or divs */ - if (l2 > 0 && (l2 & (l2 - 1)) == 0) { - int n = -1; - while (l2) { - l2 >>= 1; - n++; - } - vtop->c.i = n; - if (op == '*') - op = TOK_SHL; - else if (op == TOK_PDIV) - op = TOK_SAR; - else - op = TOK_SHR; - } - goto general_case; - } else if (c2 && (op == '+' || op == '-') && - (((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM)) - || (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) { - /* symbol + constant case */ - if (op == '-') - l2 = -l2; - l2 += vtop[-1].c.i; - /* The backends can't always deal with addends to symbols - larger than +-1<<31. Don't construct such. */ - if ((int)l2 != l2) - goto general_case; - vtop--; - vtop->c.i = l2; - } else { - general_case: - /* call low level op generator */ - if (t1 == VT_LLONG || t2 == VT_LLONG || - (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR))) - gen_opl(op); - else - gen_opi(op); - } - } -} - -/* generate a floating point operation with constant propagation */ -static void gen_opif(int op) -{ - int c1, c2; - SValue *v1, *v2; -#if defined _MSC_VER && defined _AMD64_ - /* avoid bad optimization with f1 -= f2 for f1:-0.0, f2:0.0 */ - volatile -#endif - long double f1, f2; - - v1 = vtop - 1; - v2 = vtop; - /* currently, we cannot do computations with forward symbols */ - c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - if (c1 && c2) { - if (v1->type.t == VT_FLOAT) { - f1 = v1->c.f; - f2 = v2->c.f; - } else if (v1->type.t == VT_DOUBLE) { - f1 = v1->c.d; - f2 = v2->c.d; - } else { - f1 = v1->c.ld; - f2 = v2->c.ld; - } - - /* NOTE: we only do constant propagation if finite number (not - NaN or infinity) (ANSI spec) */ - if (!ieee_finite(f1) || !ieee_finite(f2)) - goto general_case; - - switch(op) { - case '+': f1 += f2; break; - case '-': f1 -= f2; break; - case '*': f1 *= f2; break; - case '/': - if (f2 == 0.0) { - if (const_wanted) - tcc_error("division by zero in constant"); - goto general_case; - } - f1 /= f2; - break; - /* XXX: also handles tests ? */ - default: - goto general_case; - } - /* XXX: overflow test ? */ - if (v1->type.t == VT_FLOAT) { - v1->c.f = f1; - } else if (v1->type.t == VT_DOUBLE) { - v1->c.d = f1; - } else { - v1->c.ld = f1; - } - vtop--; - } else { - general_case: - gen_opf(op); - } -} - -static int pointed_size(CType *type) -{ - int align; - return type_size(pointed_type(type), &align); -} - -static void vla_runtime_pointed_size(CType *type) -{ - int align; - vla_runtime_type_size(pointed_type(type), &align); -} - -static inline int is_null_pointer(SValue *p) -{ - if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) - return 0; - return ((p->type.t & VT_BTYPE) == VT_INT && (uint32_t)p->c.i == 0) || - ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) || - ((p->type.t & VT_BTYPE) == VT_PTR && - (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0)); -} - -static inline int is_integer_btype(int bt) -{ - return (bt == VT_BYTE || bt == VT_SHORT || - bt == VT_INT || bt == VT_LLONG); -} - -/* check types for comparison or subtraction of pointers */ -static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) -{ - CType *type1, *type2, tmp_type1, tmp_type2; - int bt1, bt2; - - /* null pointers are accepted for all comparisons as gcc */ - if (is_null_pointer(p1) || is_null_pointer(p2)) - return; - type1 = &p1->type; - type2 = &p2->type; - bt1 = type1->t & VT_BTYPE; - bt2 = type2->t & VT_BTYPE; - /* accept comparison between pointer and integer with a warning */ - if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { - if (op != TOK_LOR && op != TOK_LAND ) - tcc_warning("comparison between pointer and integer"); - return; - } - - /* both must be pointers or implicit function pointers */ - if (bt1 == VT_PTR) { - type1 = pointed_type(type1); - } else if (bt1 != VT_FUNC) - goto invalid_operands; - - if (bt2 == VT_PTR) { - type2 = pointed_type(type2); - } else if (bt2 != VT_FUNC) { - invalid_operands: - tcc_error("invalid operands to binary %s", get_tok_str(op, NULL)); - } - if ((type1->t & VT_BTYPE) == VT_VOID || - (type2->t & VT_BTYPE) == VT_VOID) - return; - tmp_type1 = *type1; - tmp_type2 = *type2; - tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); - tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); - if (!is_compatible_types(&tmp_type1, &tmp_type2)) { - /* gcc-like error if '-' is used */ - if (op == '-') - goto invalid_operands; - else - tcc_warning("comparison of distinct pointer types lacks a cast"); - } -} - -/* generic gen_op: handles types problems */ -ST_FUNC void gen_op(int op) -{ - int u, t1, t2, bt1, bt2, t; - CType type1; - -redo: - t1 = vtop[-1].type.t; - t2 = vtop[0].type.t; - bt1 = t1 & VT_BTYPE; - bt2 = t2 & VT_BTYPE; - - if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { - tcc_error("operation on a struct"); - } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { - if (bt2 == VT_FUNC) { - mk_pointer(&vtop->type); - gaddrof(); - } - if (bt1 == VT_FUNC) { - vswap(); - mk_pointer(&vtop->type); - gaddrof(); - vswap(); - } - goto redo; - } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - /* at least one operand is a pointer */ - /* relational op: must be both pointers */ - if (op >= TOK_ULT && op <= TOK_LOR) { - check_comparison_pointer_types(vtop - 1, vtop, op); - /* pointers are handled are unsigned */ -#if PTR_SIZE == 8 - t = VT_LLONG | VT_UNSIGNED; -#else - t = VT_INT | VT_UNSIGNED; -#endif - goto std_op; - } - /* if both pointers, then it must be the '-' op */ - if (bt1 == VT_PTR && bt2 == VT_PTR) { - if (op != '-') - tcc_error("cannot use pointers here"); - check_comparison_pointer_types(vtop - 1, vtop, op); - /* XXX: check that types are compatible */ - if (vtop[-1].type.t & VT_VLA) { - vla_runtime_pointed_size(&vtop[-1].type); - } else { - vpushi(pointed_size(&vtop[-1].type)); - } - vrott(3); - gen_opic(op); - vtop->type.t = ptrdiff_type.t; - vswap(); - gen_op(TOK_PDIV); - } else { - /* exactly one pointer : must be '+' or '-'. */ - if (op != '-' && op != '+') - tcc_error("cannot use pointers here"); - /* Put pointer as first operand */ - if (bt2 == VT_PTR) { - vswap(); - t = t1, t1 = t2, t2 = t; - } -#if PTR_SIZE == 4 - if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) - /* XXX: truncate here because gen_opl can't handle ptr + long long */ - gen_cast_s(VT_INT); -#endif - type1 = vtop[-1].type; - type1.t &= ~VT_ARRAY; - if (vtop[-1].type.t & VT_VLA) - vla_runtime_pointed_size(&vtop[-1].type); - else { - u = pointed_size(&vtop[-1].type); - if (u < 0) - tcc_error("unknown array element size"); -#if PTR_SIZE == 8 - vpushll(u); -#else - /* XXX: cast to int ? (long long case) */ - vpushi(u); -#endif - } - gen_op('*'); -#if 0 -/* #ifdef CONFIG_TCC_BCHECK - The main reason to removing this code: - #include - int main () - { - int v[10]; - int i = 10; - int j = 9; - fprintf(stderr, "v+i-j = %p\n", v+i-j); - fprintf(stderr, "v+(i-j) = %p\n", v+(i-j)); - } - When this code is on. then the output looks like - v+i-j = 0xfffffffe - v+(i-j) = 0xbff84000 - */ - /* if evaluating constant expression, no code should be - generated, so no bound check */ - if (tcc_state->do_bounds_check && !const_wanted) { - /* if bounded pointers, we generate a special code to - test bounds */ - if (op == '-') { - vpushi(0); - vswap(); - gen_op('-'); - } - gen_bounded_ptr_add(); - } else -#endif - { - gen_opic(op); - } - /* put again type if gen_opic() swaped operands */ - vtop->type = type1; - } - } else if (is_float(bt1) || is_float(bt2)) { - /* compute bigger type and do implicit casts */ - if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { - t = VT_LDOUBLE; - } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { - t = VT_DOUBLE; - } else { - t = VT_FLOAT; - } - /* floats can only be used for a few operations */ - if (op != '+' && op != '-' && op != '*' && op != '/' && - (op < TOK_ULT || op > TOK_GT)) - tcc_error("invalid operands for binary operation"); - goto std_op; - } else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) { - t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) - t |= VT_UNSIGNED; - t |= (VT_LONG & t1); - goto std_op; - } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { - /* cast to biggest op */ - t = VT_LLONG | VT_LONG; - if (bt1 == VT_LLONG) - t &= t1; - if (bt2 == VT_LLONG) - t &= t2; - /* convert to unsigned if it does not fit in a long long */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) - t |= VT_UNSIGNED; - goto std_op; - } else { - /* integer operations */ - t = VT_INT | (VT_LONG & (t1 | t2)); - /* convert to unsigned if it does not fit in an integer */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) - t |= VT_UNSIGNED; - std_op: - /* XXX: currently, some unsigned operations are explicit, so - we modify them here */ - if (t & VT_UNSIGNED) { - if (op == TOK_SAR) - op = TOK_SHR; - else if (op == '/') - op = TOK_UDIV; - else if (op == '%') - op = TOK_UMOD; - else if (op == TOK_LT) - op = TOK_ULT; - else if (op == TOK_GT) - op = TOK_UGT; - else if (op == TOK_LE) - op = TOK_ULE; - else if (op == TOK_GE) - op = TOK_UGE; - } - vswap(); - type1.t = t; - type1.ref = NULL; - gen_cast(&type1); - vswap(); - /* special case for shifts and long long: we keep the shift as - an integer */ - if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) - type1.t = VT_INT; - gen_cast(&type1); - if (is_float(t)) - gen_opif(op); - else - gen_opic(op); - if (op >= TOK_ULT && op <= TOK_GT) { - /* relational op: the result is an int */ - vtop->type.t = VT_INT; - } else { - vtop->type.t = t; - } - } - // Make sure that we have converted to an rvalue: - if (vtop->r & VT_LVAL) - gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT); -} - -#ifndef TCC_TARGET_ARM -/* generic itof for unsigned long long case */ -static void gen_cvt_itof1(int t) -{ -#ifdef TCC_TARGET_ARM64 - gen_cvt_itof(t); -#else - if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_LLONG | VT_UNSIGNED)) { - - if (t == VT_FLOAT) - vpush_global_sym(&func_old_type, TOK___floatundisf); -#if LDOUBLE_SIZE != 8 - else if (t == VT_LDOUBLE) - vpush_global_sym(&func_old_type, TOK___floatundixf); -#endif - else - vpush_global_sym(&func_old_type, TOK___floatundidf); - vrott(2); - gfunc_call(1); - vpushi(0); - vtop->r = reg_fret(t); - } else { - gen_cvt_itof(t); - } -#endif -} -#endif - -/* generic ftoi for unsigned long long case */ -static void gen_cvt_ftoi1(int t) -{ -#ifdef TCC_TARGET_ARM64 - gen_cvt_ftoi(t); -#else - int st; - - if (t == (VT_LLONG | VT_UNSIGNED)) { - /* not handled natively */ - st = vtop->type.t & VT_BTYPE; - if (st == VT_FLOAT) - vpush_global_sym(&func_old_type, TOK___fixunssfdi); -#if LDOUBLE_SIZE != 8 - else if (st == VT_LDOUBLE) - vpush_global_sym(&func_old_type, TOK___fixunsxfdi); -#endif - else - vpush_global_sym(&func_old_type, TOK___fixunsdfdi); - vrott(2); - gfunc_call(1); - vpushi(0); - vtop->r = REG_IRET; - vtop->r2 = REG_LRET; - } else { - gen_cvt_ftoi(t); - } -#endif -} - -/* force char or short cast */ -static void force_charshort_cast(int t) -{ - int bits, dbt; - - /* cannot cast static initializers */ - if (STATIC_DATA_WANTED) - return; - - dbt = t & VT_BTYPE; - /* XXX: add optimization if lvalue : just change type and offset */ - if (dbt == VT_BYTE) - bits = 8; - else - bits = 16; - if (t & VT_UNSIGNED) { - vpushi((1 << bits) - 1); - gen_op('&'); - } else { - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) - bits = 64 - bits; - else - bits = 32 - bits; - vpushi(bits); - gen_op(TOK_SHL); - /* result must be signed or the SAR is converted to an SHL - This was not the case when "t" was a signed short - and the last value on the stack was an unsigned int */ - vtop->type.t &= ~VT_UNSIGNED; - vpushi(bits); - gen_op(TOK_SAR); - } -} - -/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ -static void gen_cast_s(int t) -{ - CType type; - type.t = t; - type.ref = NULL; - gen_cast(&type); -} - -static void gen_cast(CType *type) -{ - int sbt, dbt, sf, df, c, p; - - /* special delayed cast for char/short */ - /* XXX: in some cases (multiple cascaded casts), it may still - be incorrect */ - if (vtop->r & VT_MUSTCAST) { - vtop->r &= ~VT_MUSTCAST; - force_charshort_cast(vtop->type.t); - } - - /* bitfields first get cast to ints */ - if (vtop->type.t & VT_BITFIELD) { - gv(RC_INT); - } - - dbt = type->t & (VT_BTYPE | VT_UNSIGNED); - sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); - - if (sbt != dbt) { - sf = is_float(sbt); - df = is_float(dbt); - c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - p = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM); -#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387 - c &= dbt != VT_LDOUBLE; -#endif - if (c) { - /* constant case: we can do it now */ - /* XXX: in ISOC, cannot do it if error in convert */ - if (sbt == VT_FLOAT) - vtop->c.ld = vtop->c.f; - else if (sbt == VT_DOUBLE) - vtop->c.ld = vtop->c.d; - - if (df) { - if ((sbt & VT_BTYPE) == VT_LLONG) { - if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63)) - vtop->c.ld = vtop->c.i; - else - vtop->c.ld = -(long double)-vtop->c.i; - } else if(!sf) { - if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 31)) - vtop->c.ld = (uint32_t)vtop->c.i; - else - vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; - } - - if (dbt == VT_FLOAT) - vtop->c.f = (float)vtop->c.ld; - else if (dbt == VT_DOUBLE) - vtop->c.d = (double)vtop->c.ld; - } else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) { - vtop->c.i = vtop->c.ld; - } else if (sf && dbt == VT_BOOL) { - vtop->c.i = (vtop->c.ld != 0); - } else { - if(sf) - vtop->c.i = vtop->c.ld; - else if (sbt == (VT_LLONG|VT_UNSIGNED)) - ; - else if (sbt & VT_UNSIGNED) - vtop->c.i = (uint32_t)vtop->c.i; -#if PTR_SIZE == 8 - else if (sbt == VT_PTR) - ; -#endif - else if (sbt != VT_LLONG) - vtop->c.i = ((uint32_t)vtop->c.i | - -(vtop->c.i & 0x80000000)); - - if (dbt == (VT_LLONG|VT_UNSIGNED)) - ; - else if (dbt == VT_BOOL) - vtop->c.i = (vtop->c.i != 0); -#if PTR_SIZE == 8 - else if (dbt == VT_PTR) - ; -#endif - else if (dbt != VT_LLONG) { - uint32_t m = ((dbt & VT_BTYPE) == VT_BYTE ? 0xff : - (dbt & VT_BTYPE) == VT_SHORT ? 0xffff : - 0xffffffff); - vtop->c.i &= m; - if (!(dbt & VT_UNSIGNED)) - vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); - } - } - } else if (p && dbt == VT_BOOL) { - vtop->r = VT_CONST; - vtop->c.i = 1; - } else { - /* non constant case: generate code */ - if (sf && df) { - /* convert from fp to fp */ - gen_cvt_ftof(dbt); - } else if (df) { - /* convert int to fp */ - gen_cvt_itof1(dbt); - } else if (sf) { - /* convert fp to int */ - if (dbt == VT_BOOL) { - vpushi(0); - gen_op(TOK_NE); - } else { - /* we handle char/short/etc... with generic code */ - if (dbt != (VT_INT | VT_UNSIGNED) && - dbt != (VT_LLONG | VT_UNSIGNED) && - dbt != VT_LLONG) - dbt = VT_INT; - gen_cvt_ftoi1(dbt); - if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { - /* additional cast for char/short... */ - vtop->type.t = dbt; - gen_cast(type); - } - } -#if PTR_SIZE == 4 - } else if ((dbt & VT_BTYPE) == VT_LLONG) { - if ((sbt & VT_BTYPE) != VT_LLONG) { - /* scalar to long long */ - /* machine independent conversion */ - gv(RC_INT); - /* generate high word */ - if (sbt == (VT_INT | VT_UNSIGNED)) { - vpushi(0); - gv(RC_INT); - } else { - if (sbt == VT_PTR) { - /* cast from pointer to int before we apply - shift operation, which pointers don't support*/ - gen_cast_s(VT_INT); - } - gv_dup(); - vpushi(31); - gen_op(TOK_SAR); - } - /* patch second register */ - vtop[-1].r2 = vtop->r; - vpop(); - } -#else - } else if ((dbt & VT_BTYPE) == VT_LLONG || - (dbt & VT_BTYPE) == VT_PTR || - (dbt & VT_BTYPE) == VT_FUNC) { - if ((sbt & VT_BTYPE) != VT_LLONG && - (sbt & VT_BTYPE) != VT_PTR && - (sbt & VT_BTYPE) != VT_FUNC) { - /* need to convert from 32bit to 64bit */ - gv(RC_INT); - if (sbt != (VT_INT | VT_UNSIGNED)) { -#if defined(TCC_TARGET_ARM64) - gen_cvt_sxtw(); -#elif defined(TCC_TARGET_X86_64) - int r = gv(RC_INT); - /* x86_64 specific: movslq */ - o(0x6348); - o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); -#else -#error -#endif - } - } -#endif - } else if (dbt == VT_BOOL) { - /* scalar to bool */ - vpushi(0); - gen_op(TOK_NE); - } else if ((dbt & VT_BTYPE) == VT_BYTE || - (dbt & VT_BTYPE) == VT_SHORT) { - if (sbt == VT_PTR) { - vtop->type.t = VT_INT; - tcc_warning("nonportable conversion from pointer to char/short"); - } - force_charshort_cast(dbt); -#if PTR_SIZE == 4 - } else if ((dbt & VT_BTYPE) == VT_INT) { - /* scalar to int */ - if ((sbt & VT_BTYPE) == VT_LLONG) { - /* from long long: just take low order word */ - lexpand(); - vpop(); - } - /* if lvalue and single word type, nothing to do because - the lvalue already contains the real type size (see - VT_LVAL_xxx constants) */ -#endif - } - } - } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) { - /* if we are casting between pointer types, - we must update the VT_LVAL_xxx size */ - vtop->r = (vtop->r & ~VT_LVAL_TYPE) - | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE); - } - vtop->type = *type; -} - -/* return type size as known at compile time. Put alignment at 'a' */ -ST_FUNC int type_size(CType *type, int *a) -{ - Sym *s; - int bt; - - bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT) { - /* struct/union */ - s = type->ref; - *a = s->r; - return s->c; - } else if (bt == VT_PTR) { - if (type->t & VT_ARRAY) { - int ts; - - s = type->ref; - ts = type_size(&s->type, a); - - if (ts < 0 && s->c < 0) - ts = -ts; - - return ts * s->c; - } else { - *a = PTR_SIZE; - return PTR_SIZE; - } - } else if (IS_ENUM(type->t) && type->ref->c == -1) { - return -1; /* incomplete enum */ - } else if (bt == VT_LDOUBLE) { - *a = LDOUBLE_ALIGN; - return LDOUBLE_SIZE; - } else if (bt == VT_DOUBLE || bt == VT_LLONG) { -#ifdef TCC_TARGET_I386 -#ifdef TCC_TARGET_PE - *a = 8; -#else - *a = 4; -#endif -#elif defined(TCC_TARGET_ARM) -#ifdef TCC_ARM_EABI - *a = 8; -#else - *a = 4; -#endif -#else - *a = 8; -#endif - return 8; - } else if (bt == VT_INT || bt == VT_FLOAT) { - *a = 4; - return 4; - } else if (bt == VT_SHORT) { - *a = 2; - return 2; - } else if (bt == VT_QLONG || bt == VT_QFLOAT) { - *a = 8; - return 16; - } else { - /* char, void, function, _Bool */ - *a = 1; - return 1; - } -} - -/* push type size as known at runtime time on top of value stack. Put - alignment at 'a' */ -ST_FUNC void vla_runtime_type_size(CType *type, int *a) -{ - if (type->t & VT_VLA) { - type_size(&type->ref->type, a); - vset(&int_type, VT_LOCAL|VT_LVAL, type->ref->c); - } else { - vpushi(type_size(type, a)); - } -} - -static void vla_sp_restore(void) { - if (vlas_in_scope) { - gen_vla_sp_restore(vla_sp_loc); - } -} - -static void vla_sp_restore_root(void) { - if (vlas_in_scope) { - gen_vla_sp_restore(vla_sp_root_loc); - } -} - -/* return the pointed type of t */ -static inline CType *pointed_type(CType *type) -{ - return &type->ref->type; -} - -/* modify type so that its it is a pointer to type. */ -ST_FUNC void mk_pointer(CType *type) -{ - Sym *s; - s = sym_push(SYM_FIELD, type, 0, -1); - type->t = VT_PTR | (type->t & VT_STORAGE); - type->ref = s; -} - -/* compare function types. OLD functions match any new functions */ -static int is_compatible_func(CType *type1, CType *type2) -{ - Sym *s1, *s2; - - s1 = type1->ref; - s2 = type2->ref; - if (!is_compatible_types(&s1->type, &s2->type)) - return 0; - /* check func_call */ - if (s1->f.func_call != s2->f.func_call) - return 0; - /* XXX: not complete */ - if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD) - return 1; - if (s1->f.func_type != s2->f.func_type) - return 0; - while (s1 != NULL) { - if (s2 == NULL) - return 0; - if (!is_compatible_unqualified_types(&s1->type, &s2->type)) - return 0; - s1 = s1->next; - s2 = s2->next; - } - if (s2) - return 0; - return 1; -} - -/* return true if type1 and type2 are the same. If unqualified is - true, qualifiers on the types are ignored. - - - enums are not checked as gcc __builtin_types_compatible_p () - */ -static int compare_types(CType *type1, CType *type2, int unqualified) -{ - int bt1, t1, t2; - - t1 = type1->t & VT_TYPE; - t2 = type2->t & VT_TYPE; - if (unqualified) { - /* strip qualifiers before comparing */ - t1 &= ~(VT_CONSTANT | VT_VOLATILE); - t2 &= ~(VT_CONSTANT | VT_VOLATILE); - } - - /* Default Vs explicit signedness only matters for char */ - if ((t1 & VT_BTYPE) != VT_BYTE) { - t1 &= ~VT_DEFSIGN; - t2 &= ~VT_DEFSIGN; - } - /* XXX: bitfields ? */ - if (t1 != t2) - return 0; - /* test more complicated cases */ - bt1 = t1 & VT_BTYPE; - if (bt1 == VT_PTR) { - type1 = pointed_type(type1); - type2 = pointed_type(type2); - return is_compatible_types(type1, type2); - } else if (bt1 == VT_STRUCT) { - return (type1->ref == type2->ref); - } else if (bt1 == VT_FUNC) { - return is_compatible_func(type1, type2); - } else { - return 1; - } -} - -/* return true if type1 and type2 are exactly the same (including - qualifiers). -*/ -static int is_compatible_types(CType *type1, CType *type2) -{ - return compare_types(type1,type2,0); -} - -/* return true if type1 and type2 are the same (ignoring qualifiers). -*/ -static int is_compatible_unqualified_types(CType *type1, CType *type2) -{ - return compare_types(type1,type2,1); -} - -/* print a type. If 'varstr' is not NULL, then the variable is also - printed in the type */ -/* XXX: union */ -/* XXX: add array and function pointers */ -static void type_to_str(char *buf, int buf_size, - CType *type, const char *varstr) -{ - int bt, v, t; - Sym *s, *sa; - char buf1[256]; - const char *tstr; - - t = type->t; - bt = t & VT_BTYPE; - buf[0] = '\0'; - - if (t & VT_EXTERN) - pstrcat(buf, buf_size, "extern "); - if (t & VT_STATIC) - pstrcat(buf, buf_size, "static "); - if (t & VT_TYPEDEF) - pstrcat(buf, buf_size, "typedef "); - if (t & VT_INLINE) - pstrcat(buf, buf_size, "inline "); - if (t & VT_VOLATILE) - pstrcat(buf, buf_size, "volatile "); - if (t & VT_CONSTANT) - pstrcat(buf, buf_size, "const "); - - if (((t & VT_DEFSIGN) && bt == VT_BYTE) - || ((t & VT_UNSIGNED) - && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG) - && !IS_ENUM(t) - )) - pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed "); - - buf_size -= strlen(buf); - buf += strlen(buf); - - switch(bt) { - case VT_VOID: - tstr = "void"; - goto add_tstr; - case VT_BOOL: - tstr = "_Bool"; - goto add_tstr; - case VT_BYTE: - tstr = "char"; - goto add_tstr; - case VT_SHORT: - tstr = "short"; - goto add_tstr; - case VT_INT: - tstr = "int"; - goto maybe_long; - case VT_LLONG: - tstr = "long long"; - maybe_long: - if (t & VT_LONG) - tstr = "long"; - if (!IS_ENUM(t)) - goto add_tstr; - tstr = "enum "; - goto tstruct; - case VT_FLOAT: - tstr = "float"; - goto add_tstr; - case VT_DOUBLE: - tstr = "double"; - goto add_tstr; - case VT_LDOUBLE: - tstr = "long double"; - add_tstr: - pstrcat(buf, buf_size, tstr); - break; - case VT_STRUCT: - tstr = "struct "; - if (IS_UNION(t)) - tstr = "union "; - tstruct: - pstrcat(buf, buf_size, tstr); - v = type->ref->v & ~SYM_STRUCT; - if (v >= SYM_FIRST_ANOM) - pstrcat(buf, buf_size, ""); - else - pstrcat(buf, buf_size, get_tok_str(v, NULL)); - break; - case VT_FUNC: - s = type->ref; - type_to_str(buf, buf_size, &s->type, varstr); - pstrcat(buf, buf_size, "("); - sa = s->next; - while (sa != NULL) { - type_to_str(buf1, sizeof(buf1), &sa->type, NULL); - pstrcat(buf, buf_size, buf1); - sa = sa->next; - if (sa) - pstrcat(buf, buf_size, ", "); - } - pstrcat(buf, buf_size, ")"); - goto no_var; - case VT_PTR: - s = type->ref; - if (t & VT_ARRAY) { - snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c); - type_to_str(buf, buf_size, &s->type, buf1); - goto no_var; - } - pstrcpy(buf1, sizeof(buf1), "*"); - if (t & VT_CONSTANT) - pstrcat(buf1, buf_size, "const "); - if (t & VT_VOLATILE) - pstrcat(buf1, buf_size, "volatile "); - if (varstr) - pstrcat(buf1, sizeof(buf1), varstr); - type_to_str(buf, buf_size, &s->type, buf1); - goto no_var; - } - if (varstr) { - pstrcat(buf, buf_size, " "); - pstrcat(buf, buf_size, varstr); - } - no_var: ; -} - -/* verify type compatibility to store vtop in 'dt' type, and generate - casts if needed. */ -static void gen_assign_cast(CType *dt) -{ - CType *st, *type1, *type2; - char buf1[256], buf2[256]; - int dbt, sbt; - - st = &vtop->type; /* source type */ - dbt = dt->t & VT_BTYPE; - sbt = st->t & VT_BTYPE; - if (sbt == VT_VOID || dbt == VT_VOID) { - if (sbt == VT_VOID && dbt == VT_VOID) - ; /* - It is Ok if both are void - A test program: - void func1() {} - void func2() { - return func1(); - } - gcc accepts this program - */ - else - tcc_error("cannot cast from/to void"); - } - if (dt->t & VT_CONSTANT) - tcc_warning("assignment of read-only location"); - switch(dbt) { - case VT_PTR: - /* special cases for pointers */ - /* '0' can also be a pointer */ - if (is_null_pointer(vtop)) - goto type_ok; - /* accept implicit pointer to integer cast with warning */ - if (is_integer_btype(sbt)) { - tcc_warning("assignment makes pointer from integer without a cast"); - goto type_ok; - } - type1 = pointed_type(dt); - /* a function is implicitly a function pointer */ - if (sbt == VT_FUNC) { - if ((type1->t & VT_BTYPE) != VT_VOID && - !is_compatible_types(pointed_type(dt), st)) - tcc_warning("assignment from incompatible pointer type"); - goto type_ok; - } - if (sbt != VT_PTR) - goto error; - type2 = pointed_type(st); - if ((type1->t & VT_BTYPE) == VT_VOID || - (type2->t & VT_BTYPE) == VT_VOID) { - /* void * can match anything */ - } else { - //printf("types %08x %08x\n", type1->t, type2->t); - /* exact type match, except for qualifiers */ - if (!is_compatible_unqualified_types(type1, type2)) { - /* Like GCC don't warn by default for merely changes - in pointer target signedness. Do warn for different - base types, though, in particular for unsigned enums - and signed int targets. */ - if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG)) - || IS_ENUM(type1->t) || IS_ENUM(type2->t) - ) - tcc_warning("assignment from incompatible pointer type"); - } - } - /* check const and volatile */ - if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || - (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) - tcc_warning("assignment discards qualifiers from pointer target type"); - break; - case VT_BYTE: - case VT_SHORT: - case VT_INT: - case VT_LLONG: - if (sbt == VT_PTR || sbt == VT_FUNC) { - tcc_warning("assignment makes integer from pointer without a cast"); - } else if (sbt == VT_STRUCT) { - goto case_VT_STRUCT; - } - /* XXX: more tests */ - break; - case VT_STRUCT: - case_VT_STRUCT: - if (!is_compatible_unqualified_types(dt, st)) { - error: - type_to_str(buf1, sizeof(buf1), st, NULL); - type_to_str(buf2, sizeof(buf2), dt, NULL); - tcc_error("cannot cast '%s' to '%s'", buf1, buf2); - } - break; - } - type_ok: - gen_cast(dt); -} - -/* store vtop in lvalue pushed on stack */ -ST_FUNC void vstore(void) -{ - int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; - - ft = vtop[-1].type.t; - sbt = vtop->type.t & VT_BTYPE; - dbt = ft & VT_BTYPE; - if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || - (sbt == VT_INT && dbt == VT_SHORT)) - && !(vtop->type.t & VT_BITFIELD)) { - /* optimize char/short casts */ - delayed_cast = VT_MUSTCAST; - vtop->type.t = ft & VT_TYPE; - /* XXX: factorize */ - if (ft & VT_CONSTANT) - tcc_warning("assignment of read-only location"); - } else { - delayed_cast = 0; - if (!(ft & VT_BITFIELD)) - gen_assign_cast(&vtop[-1].type); - } - - if (sbt == VT_STRUCT) { - /* if structure, only generate pointer */ - /* structure assignment : generate memcpy */ - /* XXX: optimize if small size */ - size = type_size(&vtop->type, &align); - - /* destination */ - vswap(); - vtop->type.t = VT_PTR; - gaddrof(); - - /* address of memcpy() */ -#ifdef TCC_ARM_EABI - if(!(align & 7)) - vpush_global_sym(&func_old_type, TOK_memcpy8); - else if(!(align & 3)) - vpush_global_sym(&func_old_type, TOK_memcpy4); - else -#endif - /* Use memmove, rather than memcpy, as dest and src may be same: */ - vpush_global_sym(&func_old_type, TOK_memmove); - - vswap(); - /* source */ - vpushv(vtop - 2); - vtop->type.t = VT_PTR; - gaddrof(); - /* type size */ - vpushi(size); - gfunc_call(3); - - /* leave source on stack */ - } else if (ft & VT_BITFIELD) { - /* bitfield store handling */ - - /* save lvalue as expression result (example: s.b = s.a = n;) */ - vdup(), vtop[-1] = vtop[-2]; - - bit_pos = BIT_POS(ft); - bit_size = BIT_SIZE(ft); - /* remove bit field info to avoid loops */ - vtop[-1].type.t = ft & ~VT_STRUCT_MASK; - - if ((ft & VT_BTYPE) == VT_BOOL) { - gen_cast(&vtop[-1].type); - vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); - } - - r = adjust_bf(vtop - 1, bit_pos, bit_size); - if (r == VT_STRUCT) { - gen_cast_s((ft & VT_BTYPE) == VT_LLONG ? VT_LLONG : VT_INT); - store_packed_bf(bit_pos, bit_size); - } else { - unsigned long long mask = (1ULL << bit_size) - 1; - if ((ft & VT_BTYPE) != VT_BOOL) { - /* mask source */ - if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG) - vpushll(mask); - else - vpushi((unsigned)mask); - gen_op('&'); - } - /* shift source */ - vpushi(bit_pos); - gen_op(TOK_SHL); - vswap(); - /* duplicate destination */ - vdup(); - vrott(3); - /* load destination, mask and or with source */ - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) - vpushll(~(mask << bit_pos)); - else - vpushi(~((unsigned)mask << bit_pos)); - gen_op('&'); - gen_op('|'); - /* store result */ - vstore(); - /* ... and discard */ - vpop(); - } - } else if (dbt == VT_VOID) { - --vtop; - } else { -#ifdef CONFIG_TCC_BCHECK - /* bound check case */ - if (vtop[-1].r & VT_MUSTBOUND) { - vswap(); - gbound(); - vswap(); - } -#endif - rc = RC_INT; - if (is_float(ft)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((ft & VT_BTYPE) == VT_LDOUBLE) { - rc = RC_ST0; - } else if ((ft & VT_BTYPE) == VT_QFLOAT) { - rc = RC_FRET; - } -#endif - } - r = gv(rc); /* generate value */ - /* if lvalue was saved on stack, must read it */ - if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { - SValue sv; - t = get_reg(RC_INT); -#if PTR_SIZE == 8 - sv.type.t = VT_PTR; -#else - sv.type.t = VT_INT; -#endif - sv.r = VT_LOCAL | VT_LVAL; - sv.c.i = vtop[-1].c.i; - load(t, &sv); - vtop[-1].r = t | VT_LVAL; - } - /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ -#if PTR_SIZE == 8 - if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { - int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; -#else - if ((ft & VT_BTYPE) == VT_LLONG) { - int addr_type = VT_INT, load_size = 4, load_type = VT_INT; -#endif - vtop[-1].type.t = load_type; - store(r, vtop - 1); - vswap(); - /* convert to int to increment easily */ - vtop->type.t = addr_type; - gaddrof(); - vpushi(load_size); - gen_op('+'); - vtop->r |= VT_LVAL; - vswap(); - vtop[-1].type.t = load_type; - /* XXX: it works because r2 is spilled last ! */ - store(vtop->r2, vtop - 1); - } else { - store(r, vtop - 1); - } - - vswap(); - vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ - vtop->r |= delayed_cast; - } -} - -/* post defines POST/PRE add. c is the token ++ or -- */ -ST_FUNC void inc(int post, int c) -{ - test_lvalue(); - vdup(); /* save lvalue */ - if (post) { - gv_dup(); /* duplicate value */ - vrotb(3); - vrotb(3); - } - /* add constant */ - vpushi(c - TOK_MID); - gen_op('+'); - vstore(); /* store value */ - if (post) - vpop(); /* if post op, return saved value */ -} - -ST_FUNC void parse_mult_str (CString *astr, const char *msg) -{ - /* read the string */ - if (tok != TOK_STR) - expect(msg); - cstr_new(astr); - while (tok == TOK_STR) { - /* XXX: add \0 handling too ? */ - cstr_cat(astr, tokc.str.data, -1); - next(); - } - cstr_ccat(astr, '\0'); -} - -/* If I is >= 1 and a power of two, returns log2(i)+1. - If I is 0 returns 0. */ -static int exact_log2p1(int i) -{ - int ret; - if (!i) - return 0; - for (ret = 1; i >= 1 << 8; ret += 8) - i >>= 8; - if (i >= 1 << 4) - ret += 4, i >>= 4; - if (i >= 1 << 2) - ret += 2, i >>= 2; - if (i >= 1 << 1) - ret++; - return ret; -} - -/* Parse __attribute__((...)) GNUC extension. */ -static void parse_attribute(AttributeDef *ad) -{ - int t, n; - CString astr; - -redo: - if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2) - return; - next(); - skip('('); - skip('('); - while (tok != ')') { - if (tok < TOK_IDENT) - expect("attribute name"); - t = tok; - next(); - switch(t) { - case TOK_SECTION1: - case TOK_SECTION2: - skip('('); - parse_mult_str(&astr, "section name"); - ad->section = find_section(tcc_state, (char *)astr.data); - skip(')'); - cstr_free(&astr); - break; - case TOK_ALIAS1: - case TOK_ALIAS2: - skip('('); - parse_mult_str(&astr, "alias(\"target\")"); - ad->alias_target = /* save string as token, for later */ - tok_alloc((char*)astr.data, astr.size-1)->tok; - skip(')'); - cstr_free(&astr); - break; - case TOK_VISIBILITY1: - case TOK_VISIBILITY2: - skip('('); - parse_mult_str(&astr, - "visibility(\"default|hidden|internal|protected\")"); - if (!strcmp (astr.data, "default")) - ad->a.visibility = STV_DEFAULT; - else if (!strcmp (astr.data, "hidden")) - ad->a.visibility = STV_HIDDEN; - else if (!strcmp (astr.data, "internal")) - ad->a.visibility = STV_INTERNAL; - else if (!strcmp (astr.data, "protected")) - ad->a.visibility = STV_PROTECTED; - else - expect("visibility(\"default|hidden|internal|protected\")"); - skip(')'); - cstr_free(&astr); - break; - case TOK_ALIGNED1: - case TOK_ALIGNED2: - if (tok == '(') { - next(); - n = expr_const(); - if (n <= 0 || (n & (n - 1)) != 0) - tcc_error("alignment must be a positive power of two"); - skip(')'); - } else { - n = MAX_ALIGN; - } - ad->a.aligned = exact_log2p1(n); - if (n != 1 << (ad->a.aligned - 1)) - tcc_error("alignment of %d is larger than implemented", n); - break; - case TOK_PACKED1: - case TOK_PACKED2: - ad->a.packed = 1; - break; - case TOK_WEAK1: - case TOK_WEAK2: - ad->a.weak = 1; - break; - case TOK_UNUSED1: - case TOK_UNUSED2: - /* currently, no need to handle it because tcc does not - track unused objects */ - break; - case TOK_NORETURN1: - case TOK_NORETURN2: - /* currently, no need to handle it because tcc does not - track unused objects */ - break; - case TOK_CDECL1: - case TOK_CDECL2: - case TOK_CDECL3: - ad->f.func_call = FUNC_CDECL; - break; - case TOK_STDCALL1: - case TOK_STDCALL2: - case TOK_STDCALL3: - ad->f.func_call = FUNC_STDCALL; - break; -#ifdef TCC_TARGET_I386 - case TOK_REGPARM1: - case TOK_REGPARM2: - skip('('); - n = expr_const(); - if (n > 3) - n = 3; - else if (n < 0) - n = 0; - if (n > 0) - ad->f.func_call = FUNC_FASTCALL1 + n - 1; - skip(')'); - break; - case TOK_FASTCALL1: - case TOK_FASTCALL2: - case TOK_FASTCALL3: - ad->f.func_call = FUNC_FASTCALLW; - break; -#endif - case TOK_MODE: - skip('('); - switch(tok) { - case TOK_MODE_DI: - ad->attr_mode = VT_LLONG + 1; - break; - case TOK_MODE_QI: - ad->attr_mode = VT_BYTE + 1; - break; - case TOK_MODE_HI: - ad->attr_mode = VT_SHORT + 1; - break; - case TOK_MODE_SI: - case TOK_MODE_word: - ad->attr_mode = VT_INT + 1; - break; - default: - tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL)); - break; - } - next(); - skip(')'); - break; - case TOK_DLLEXPORT: - ad->a.dllexport = 1; - break; - case TOK_DLLIMPORT: - ad->a.dllimport = 1; - break; - default: - if (tcc_state->warn_unsupported) - tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); - /* skip parameters */ - if (tok == '(') { - int parenthesis = 0; - do { - if (tok == '(') - parenthesis++; - else if (tok == ')') - parenthesis--; - next(); - } while (parenthesis && tok != -1); - } - break; - } - if (tok != ',') - break; - next(); - } - skip(')'); - skip(')'); - goto redo; -} - -static Sym * find_field (CType *type, int v) -{ - Sym *s = type->ref; - v |= SYM_FIELD; - while ((s = s->next) != NULL) { - if ((s->v & SYM_FIELD) && - (s->type.t & VT_BTYPE) == VT_STRUCT && - (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { - Sym *ret = find_field (&s->type, v); - if (ret) - return ret; - } - if (s->v == v) - break; - } - return s; -} - -static void struct_add_offset (Sym *s, int offset) -{ - while ((s = s->next) != NULL) { - if ((s->v & SYM_FIELD) && - (s->type.t & VT_BTYPE) == VT_STRUCT && - (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { - struct_add_offset(s->type.ref, offset); - } else - s->c += offset; - } -} - -static void struct_layout(CType *type, AttributeDef *ad) -{ - int size, align, maxalign, offset, c, bit_pos, bit_size; - int packed, a, bt, prevbt, prev_bit_size; - int pcc = !tcc_state->ms_bitfields; - int pragma_pack = *tcc_state->pack_stack_ptr; - Sym *f; - - maxalign = 1; - offset = 0; - c = 0; - bit_pos = 0; - prevbt = VT_STRUCT; /* make it never match */ - prev_bit_size = 0; - -//#define BF_DEBUG - - for (f = type->ref->next; f; f = f->next) { - if (f->type.t & VT_BITFIELD) - bit_size = BIT_SIZE(f->type.t); - else - bit_size = -1; - size = type_size(&f->type, &align); - a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; - packed = 0; - - if (pcc && bit_size == 0) { - /* in pcc mode, packing does not affect zero-width bitfields */ - - } else { - /* in pcc mode, attribute packed overrides if set. */ - if (pcc && (f->a.packed || ad->a.packed)) - align = packed = 1; - - /* pragma pack overrides align if lesser and packs bitfields always */ - if (pragma_pack) { - packed = 1; - if (pragma_pack < align) - align = pragma_pack; - /* in pcc mode pragma pack also overrides individual align */ - if (pcc && pragma_pack < a) - a = 0; - } - } - /* some individual align was specified */ - if (a) - align = a; - - if (type->ref->type.t == VT_UNION) { - if (pcc && bit_size >= 0) - size = (bit_size + 7) >> 3; - offset = 0; - if (size > c) - c = size; - - } else if (bit_size < 0) { - if (pcc) - c += (bit_pos + 7) >> 3; - c = (c + align - 1) & -align; - offset = c; - if (size > 0) - c += size; - bit_pos = 0; - prevbt = VT_STRUCT; - prev_bit_size = 0; - - } else { - /* A bit-field. Layout is more complicated. There are two - options: PCC (GCC) compatible and MS compatible */ - if (pcc) { - /* In PCC layout a bit-field is placed adjacent to the - preceding bit-fields, except if: - - it has zero-width - - an individual alignment was given - - it would overflow its base type container and - there is no packing */ - if (bit_size == 0) { - new_field: - c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align; - bit_pos = 0; - } else if (f->a.aligned) { - goto new_field; - } else if (!packed) { - int a8 = align * 8; - int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8; - if (ofs > size / align) - goto new_field; - } - - /* in pcc mode, long long bitfields have type int if they fit */ - if (size == 8 && bit_size <= 32) - f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4; - - while (bit_pos >= align * 8) - c += align, bit_pos -= align * 8; - offset = c; - - /* In PCC layout named bit-fields influence the alignment - of the containing struct using the base types alignment, - except for packed fields (which here have correct align). */ - if (f->v & SYM_FIRST_ANOM - // && bit_size // ??? gcc on ARM/rpi does that - ) - align = 1; - - } else { - bt = f->type.t & VT_BTYPE; - if ((bit_pos + bit_size > size * 8) - || (bit_size > 0) == (bt != prevbt) - ) { - c = (c + align - 1) & -align; - offset = c; - bit_pos = 0; - /* In MS bitfield mode a bit-field run always uses - at least as many bits as the underlying type. - To start a new run it's also required that this - or the last bit-field had non-zero width. */ - if (bit_size || prev_bit_size) - c += size; - } - /* In MS layout the records alignment is normally - influenced by the field, except for a zero-width - field at the start of a run (but by further zero-width - fields it is again). */ - if (bit_size == 0 && prevbt != bt) - align = 1; - prevbt = bt; - prev_bit_size = bit_size; - } - - f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) - | (bit_pos << VT_STRUCT_SHIFT); - bit_pos += bit_size; - } - if (align > maxalign) - maxalign = align; - -#ifdef BF_DEBUG - printf("set field %s offset %-2d size %-2d align %-2d", - get_tok_str(f->v & ~SYM_FIELD, NULL), offset, size, align); - if (f->type.t & VT_BITFIELD) { - printf(" pos %-2d bits %-2d", - BIT_POS(f->type.t), - BIT_SIZE(f->type.t) - ); - } - printf("\n"); -#endif - - if (f->v & SYM_FIRST_ANOM && (f->type.t & VT_BTYPE) == VT_STRUCT) { - Sym *ass; - /* An anonymous struct/union. Adjust member offsets - to reflect the real offset of our containing struct. - Also set the offset of this anon member inside - the outer struct to be zero. Via this it - works when accessing the field offset directly - (from base object), as well as when recursing - members in initializer handling. */ - int v2 = f->type.ref->v; - if (!(v2 & SYM_FIELD) && - (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - Sym **pps; - /* This happens only with MS extensions. The - anon member has a named struct type, so it - potentially is shared with other references. - We need to unshare members so we can modify - them. */ - ass = f->type.ref; - f->type.ref = sym_push(anon_sym++ | SYM_FIELD, - &f->type.ref->type, 0, - f->type.ref->c); - pps = &f->type.ref->next; - while ((ass = ass->next) != NULL) { - *pps = sym_push(ass->v, &ass->type, 0, ass->c); - pps = &((*pps)->next); - } - *pps = NULL; - } - struct_add_offset(f->type.ref, offset); - f->c = 0; - } else { - f->c = offset; - } - - f->r = 0; - } - - if (pcc) - c += (bit_pos + 7) >> 3; - - /* store size and alignment */ - a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1; - if (a < maxalign) - a = maxalign; - type->ref->r = a; - if (pragma_pack && pragma_pack < maxalign && 0 == pcc) { - /* can happen if individual align for some member was given. In - this case MSVC ignores maxalign when aligning the size */ - a = pragma_pack; - if (a < bt) - a = bt; - } - c = (c + a - 1) & -a; - type->ref->c = c; - -#ifdef BF_DEBUG - printf("struct size %-2d align %-2d\n\n", c, a), fflush(stdout); -#endif - - /* check whether we can access bitfields by their type */ - for (f = type->ref->next; f; f = f->next) { - int s, px, cx, c0; - CType t; - - if (0 == (f->type.t & VT_BITFIELD)) - continue; - f->type.ref = f; - f->auxtype = -1; - bit_size = BIT_SIZE(f->type.t); - if (bit_size == 0) - continue; - bit_pos = BIT_POS(f->type.t); - size = type_size(&f->type, &align); - if (bit_pos + bit_size <= size * 8 && f->c + size <= c) - continue; - - /* try to access the field using a different type */ - c0 = -1, s = align = 1; - for (;;) { - px = f->c * 8 + bit_pos; - cx = (px >> 3) & -align; - px = px - (cx << 3); - if (c0 == cx) - break; - s = (px + bit_size + 7) >> 3; - if (s > 4) { - t.t = VT_LLONG; - } else if (s > 2) { - t.t = VT_INT; - } else if (s > 1) { - t.t = VT_SHORT; - } else { - t.t = VT_BYTE; - } - s = type_size(&t, &align); - c0 = cx; - } - - if (px + bit_size <= s * 8 && cx + s <= c) { - /* update offset and bit position */ - f->c = cx; - bit_pos = px; - f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) - | (bit_pos << VT_STRUCT_SHIFT); - if (s != size) - f->auxtype = t.t; -#ifdef BF_DEBUG - printf("FIX field %s offset %-2d size %-2d align %-2d " - "pos %-2d bits %-2d\n", - get_tok_str(f->v & ~SYM_FIELD, NULL), - cx, s, align, px, bit_size); -#endif - } else { - /* fall back to load/store single-byte wise */ - f->auxtype = VT_STRUCT; -#ifdef BF_DEBUG - printf("FIX field %s : load byte-wise\n", - get_tok_str(f->v & ~SYM_FIELD, NULL)); -#endif - } - } -} - -/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */ -static void struct_decl(CType *type, int u) -{ - int v, c, size, align, flexible; - int bit_size, bsize, bt; - Sym *s, *ss, **ps; - AttributeDef ad, ad1; - CType type1, btype; - - memset(&ad, 0, sizeof ad); - next(); - parse_attribute(&ad); - if (tok != '{') { - v = tok; - next(); - /* struct already defined ? return it */ - if (v < TOK_IDENT) - expect("struct/union/enum name"); - s = struct_find(v); - if (s && (s->sym_scope == local_scope || tok != '{')) { - if (u == s->type.t) - goto do_decl; - if (u == VT_ENUM && IS_ENUM(s->type.t)) - goto do_decl; - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - } - } else { - v = anon_sym++; - } - /* Record the original enum/struct/union token. */ - type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u; - type1.ref = NULL; - /* we put an undefined size for struct/union */ - s = sym_push(v | SYM_STRUCT, &type1, 0, -1); - s->r = 0; /* default alignment is zero as gcc */ -do_decl: - type->t = s->type.t; - type->ref = s; - - if (tok == '{') { - next(); - if (s->c != -1) - tcc_error("struct/union/enum already defined"); - /* cannot be empty */ - /* non empty enums are not allowed */ - ps = &s->next; - if (u == VT_ENUM) { - long long ll = 0, pl = 0, nl = 0; - CType t; - t.ref = s; - /* enum symbols have static storage */ - t.t = VT_INT|VT_STATIC|VT_ENUM_VAL; - for(;;) { - v = tok; - if (v < TOK_UIDENT) - expect("identifier"); - ss = sym_find(v); - if (ss && !local_stack) - tcc_error("redefinition of enumerator '%s'", - get_tok_str(v, NULL)); - next(); - if (tok == '=') { - next(); - ll = expr_const64(); - } - ss = sym_push(v, &t, VT_CONST, 0); - ss->enum_val = ll; - *ps = ss, ps = &ss->next; - if (ll < nl) - nl = ll; - if (ll > pl) - pl = ll; - if (tok != ',') - break; - next(); - ll++; - /* NOTE: we accept a trailing comma */ - if (tok == '}') - break; - } - skip('}'); - /* set integral type of the enum */ - t.t = VT_INT; - if (nl >= 0) { - if (pl != (unsigned)pl) - t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); - t.t |= VT_UNSIGNED; - } else if (pl != (int)pl || nl != (int)nl) - t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); - s->type.t = type->t = t.t | VT_ENUM; - s->c = 0; - /* set type for enum members */ - for (ss = s->next; ss; ss = ss->next) { - ll = ss->enum_val; - if (ll == (int)ll) /* default is int if it fits */ - continue; - if (t.t & VT_UNSIGNED) { - ss->type.t |= VT_UNSIGNED; - if (ll == (unsigned)ll) - continue; - } - ss->type.t = (ss->type.t & ~VT_BTYPE) - | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); - } - } else { - c = 0; - flexible = 0; - while (tok != '}') { - if (!parse_btype(&btype, &ad1)) { - skip(';'); - continue; - } - while (1) { - if (flexible) - tcc_error("flexible array member '%s' not at the end of struct", - get_tok_str(v, NULL)); - bit_size = -1; - v = 0; - type1 = btype; - if (tok != ':') { - if (tok != ';') - type_decl(&type1, &ad1, &v, TYPE_DIRECT); - if (v == 0) { - if ((type1.t & VT_BTYPE) != VT_STRUCT) - expect("identifier"); - else { - int v = btype.ref->v; - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - if (tcc_state->ms_extensions == 0) - expect("identifier"); - } - } - } - if (type_size(&type1, &align) < 0) { - if ((u == VT_STRUCT) && (type1.t & VT_ARRAY) && c) - flexible = 1; - else - tcc_error("field '%s' has incomplete type", - get_tok_str(v, NULL)); - } - if ((type1.t & VT_BTYPE) == VT_FUNC || - (type1.t & VT_STORAGE)) - tcc_error("invalid type for '%s'", - get_tok_str(v, NULL)); - } - if (tok == ':') { - next(); - bit_size = expr_const(); - /* XXX: handle v = 0 case for messages */ - if (bit_size < 0) - tcc_error("negative width in bit-field '%s'", - get_tok_str(v, NULL)); - if (v && bit_size == 0) - tcc_error("zero width for bit-field '%s'", - get_tok_str(v, NULL)); - parse_attribute(&ad1); - } - size = type_size(&type1, &align); - if (bit_size >= 0) { - bt = type1.t & VT_BTYPE; - if (bt != VT_INT && - bt != VT_BYTE && - bt != VT_SHORT && - bt != VT_BOOL && - bt != VT_LLONG) - tcc_error("bitfields must have scalar type"); - bsize = size * 8; - if (bit_size > bsize) { - tcc_error("width of '%s' exceeds its type", - get_tok_str(v, NULL)); - } else if (bit_size == bsize - && !ad.a.packed && !ad1.a.packed) { - /* no need for bit fields */ - ; - } else if (bit_size == 64) { - tcc_error("field width 64 not implemented"); - } else { - type1.t = (type1.t & ~VT_STRUCT_MASK) - | VT_BITFIELD - | (bit_size << (VT_STRUCT_SHIFT + 6)); - } - } - if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { - /* Remember we've seen a real field to check - for placement of flexible array member. */ - c = 1; - } - /* If member is a struct or bit-field, enforce - placing into the struct (as anonymous). */ - if (v == 0 && - ((type1.t & VT_BTYPE) == VT_STRUCT || - bit_size >= 0)) { - v = anon_sym++; - } - if (v) { - ss = sym_push(v | SYM_FIELD, &type1, 0, 0); - ss->a = ad1.a; - *ps = ss; - ps = &ss->next; - } - if (tok == ';' || tok == TOK_EOF) - break; - skip(','); - } - skip(';'); - } - skip('}'); - parse_attribute(&ad); - struct_layout(type, &ad); - } - } -} - -static void sym_to_attr(AttributeDef *ad, Sym *s) -{ - if (s->a.aligned && 0 == ad->a.aligned) - ad->a.aligned = s->a.aligned; - if (s->f.func_call && 0 == ad->f.func_call) - ad->f.func_call = s->f.func_call; - if (s->f.func_type && 0 == ad->f.func_type) - ad->f.func_type = s->f.func_type; - if (s->a.packed) - ad->a.packed = 1; -} - -/* Add type qualifiers to a type. If the type is an array then the qualifiers - are added to the element type, copied because it could be a typedef. */ -static void parse_btype_qualify(CType *type, int qualifiers) -{ - while (type->t & VT_ARRAY) { - type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); - type = &type->ref->type; - } - type->t |= qualifiers; -} - -/* return 0 if no type declaration. otherwise, return the basic type - and skip it. - */ -static int parse_btype(CType *type, AttributeDef *ad) -{ - int t, u, bt, st, type_found, typespec_found, g; - Sym *s; - CType type1; - - memset(ad, 0, sizeof(AttributeDef)); - type_found = 0; - typespec_found = 0; - t = VT_INT; - bt = st = -1; - type->ref = NULL; - - while(1) { - switch(tok) { - case TOK_EXTENSION: - /* currently, we really ignore extension */ - next(); - continue; - - /* basic types */ - case TOK_CHAR: - u = VT_BYTE; - basic_type: - next(); - basic_type1: - if (u == VT_SHORT || u == VT_LONG) { - if (st != -1 || (bt != -1 && bt != VT_INT)) - tmbt: tcc_error("too many basic types"); - st = u; - } else { - if (bt != -1 || (st != -1 && u != VT_INT)) - goto tmbt; - bt = u; - } - if (u != VT_INT) - t = (t & ~(VT_BTYPE|VT_LONG)) | u; - typespec_found = 1; - break; - case TOK_VOID: - u = VT_VOID; - goto basic_type; - case TOK_SHORT: - u = VT_SHORT; - goto basic_type; - case TOK_INT: - u = VT_INT; - goto basic_type; - case TOK_LONG: - if ((t & VT_BTYPE) == VT_DOUBLE) { - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; - } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG; - } else { - u = VT_LONG; - goto basic_type; - } - next(); - break; -#ifdef TCC_TARGET_ARM64 - case TOK_UINT128: - /* GCC's __uint128_t appears in some Linux header files. Make it a - synonym for long double to get the size and alignment right. */ - u = VT_LDOUBLE; - goto basic_type; -#endif - case TOK_BOOL: - u = VT_BOOL; - goto basic_type; - case TOK_FLOAT: - u = VT_FLOAT; - goto basic_type; - case TOK_DOUBLE: - if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; - } else { - u = VT_DOUBLE; - goto basic_type; - } - next(); - break; - case TOK_ENUM: - struct_decl(&type1, VT_ENUM); - basic_type2: - u = type1.t; - type->ref = type1.ref; - goto basic_type1; - case TOK_STRUCT: - struct_decl(&type1, VT_STRUCT); - goto basic_type2; - case TOK_UNION: - struct_decl(&type1, VT_UNION); - goto basic_type2; - - /* type modifiers */ - case TOK_CONST1: - case TOK_CONST2: - case TOK_CONST3: - type->t = t; - parse_btype_qualify(type, VT_CONSTANT); - t = type->t; - next(); - break; - case TOK_VOLATILE1: - case TOK_VOLATILE2: - case TOK_VOLATILE3: - type->t = t; - parse_btype_qualify(type, VT_VOLATILE); - t = type->t; - next(); - break; - case TOK_SIGNED1: - case TOK_SIGNED2: - case TOK_SIGNED3: - if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED)) - tcc_error("signed and unsigned modifier"); - t |= VT_DEFSIGN; - next(); - typespec_found = 1; - break; - case TOK_REGISTER: - case TOK_AUTO: - case TOK_RESTRICT1: - case TOK_RESTRICT2: - case TOK_RESTRICT3: - next(); - break; - case TOK_UNSIGNED: - if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == VT_DEFSIGN) - tcc_error("signed and unsigned modifier"); - t |= VT_DEFSIGN | VT_UNSIGNED; - next(); - typespec_found = 1; - break; - - /* storage */ - case TOK_EXTERN: - g = VT_EXTERN; - goto storage; - case TOK_STATIC: - g = VT_STATIC; - goto storage; - case TOK_TYPEDEF: - g = VT_TYPEDEF; - goto storage; - storage: - if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g) - tcc_error("multiple storage classes"); - t |= g; - next(); - break; - case TOK_INLINE1: - case TOK_INLINE2: - case TOK_INLINE3: - t |= VT_INLINE; - next(); - break; - - /* GNUC attribute */ - case TOK_ATTRIBUTE1: - case TOK_ATTRIBUTE2: - parse_attribute(ad); - if (ad->attr_mode) { - u = ad->attr_mode -1; - t = (t & ~(VT_BTYPE|VT_LONG)) | u; - } - break; - /* GNUC typeof */ - case TOK_TYPEOF1: - case TOK_TYPEOF2: - case TOK_TYPEOF3: - next(); - parse_expr_type(&type1); - /* remove all storage modifiers except typedef */ - type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); - if (type1.ref) - sym_to_attr(ad, type1.ref); - goto basic_type2; - default: - if (typespec_found) - goto the_end; - s = sym_find(tok); - if (!s || !(s->type.t & VT_TYPEDEF)) - goto the_end; - t &= ~(VT_BTYPE|VT_LONG); - u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; - type->t = (s->type.t & ~VT_TYPEDEF) | u; - type->ref = s->type.ref; - if (t) - parse_btype_qualify(type, t); - t = type->t; - /* get attributes from typedef */ - sym_to_attr(ad, s); - next(); - typespec_found = 1; - st = bt = -2; - break; - } - type_found = 1; - } -the_end: - if (tcc_state->char_is_unsigned) { - if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) - t |= VT_UNSIGNED; - } - /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */ - bt = t & (VT_BTYPE|VT_LONG); - if (bt == VT_LONG) - t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT; -#ifdef TCC_TARGET_PE - if (bt == VT_LDOUBLE) - t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE; -#endif - type->t = t; - return type_found; -} - -/* convert a function parameter type (array to pointer and function to - function pointer) */ -static inline void convert_parameter_type(CType *pt) -{ - /* remove const and volatile qualifiers (XXX: const could be used - to indicate a const function parameter */ - pt->t &= ~(VT_CONSTANT | VT_VOLATILE); - /* array must be transformed to pointer according to ANSI C */ - pt->t &= ~VT_ARRAY; - if ((pt->t & VT_BTYPE) == VT_FUNC) { - mk_pointer(pt); - } -} - -ST_FUNC void parse_asm_str(CString *astr) -{ - skip('('); - parse_mult_str(astr, "string constant"); -} - -/* Parse an asm label and return the token */ -static int asm_label_instr(void) -{ - int v; - CString astr; - - next(); - parse_asm_str(&astr); - skip(')'); -#ifdef ASM_DEBUG - printf("asm_alias: \"%s\"\n", (char *)astr.data); -#endif - v = tok_alloc(astr.data, astr.size - 1)->tok; - cstr_free(&astr); - return v; -} - -static int post_type(CType *type, AttributeDef *ad, int storage, int td) -{ - int n, l, t1, arg_size, align; - Sym **plast, *s, *first; - AttributeDef ad1; - CType pt; - - if (tok == '(') { - /* function type, or recursive declarator (return if so) */ - next(); - if (td && !(td & TYPE_ABSTRACT)) - return 0; - if (tok == ')') - l = 0; - else if (parse_btype(&pt, &ad1)) - l = FUNC_NEW; - else if (td) - return 0; - else - l = FUNC_OLD; - first = NULL; - plast = &first; - arg_size = 0; - if (l) { - for(;;) { - /* read param name and compute offset */ - if (l != FUNC_OLD) { - if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') - break; - type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); - if ((pt.t & VT_BTYPE) == VT_VOID) - tcc_error("parameter declared as void"); - arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; - } else { - n = tok; - if (n < TOK_UIDENT) - expect("identifier"); - pt.t = VT_VOID; /* invalid type */ - next(); - } - convert_parameter_type(&pt); - s = sym_push(n | SYM_FIELD, &pt, 0, 0); - *plast = s; - plast = &s->next; - if (tok == ')') - break; - skip(','); - if (l == FUNC_NEW && tok == TOK_DOTS) { - l = FUNC_ELLIPSIS; - next(); - break; - } - if (l == FUNC_NEW && !parse_btype(&pt, &ad1)) - tcc_error("invalid type"); - } - } else - /* if no parameters, then old type prototype */ - l = FUNC_OLD; - skip(')'); - /* NOTE: const is ignored in returned type as it has a special - meaning in gcc / C++ */ - type->t &= ~VT_CONSTANT; - /* some ancient pre-K&R C allows a function to return an array - and the array brackets to be put after the arguments, such - that "int c()[]" means something like "int[] c()" */ - if (tok == '[') { - next(); - skip(']'); /* only handle simple "[]" */ - mk_pointer(type); - } - /* we push a anonymous symbol which will contain the function prototype */ - ad->f.func_args = arg_size; - ad->f.func_type = l; - s = sym_push(SYM_FIELD, type, 0, 0); - s->a = ad->a; - s->f = ad->f; - s->next = first; - type->t = VT_FUNC; - type->ref = s; - } else if (tok == '[') { - int saved_nocode_wanted = nocode_wanted; - /* array definition */ - next(); - if (tok == TOK_RESTRICT1) - next(); - n = -1; - t1 = 0; - if (tok != ']') { - if (!local_stack || (storage & VT_STATIC)) - vpushi(expr_const()); - else { - /* VLAs (which can only happen with local_stack && !VT_STATIC) - length must always be evaluated, even under nocode_wanted, - so that its size slot is initialized (e.g. under sizeof - or typeof). */ - nocode_wanted = 0; - gexpr(); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - n = vtop->c.i; - if (n < 0) - tcc_error("invalid array size"); - } else { - if (!is_integer_btype(vtop->type.t & VT_BTYPE)) - tcc_error("size of variable length array should be an integer"); - t1 = VT_VLA; - } - } - skip(']'); - /* parse next post type */ - post_type(type, ad, storage, 0); - if (type->t == VT_FUNC) - tcc_error("declaration of an array of functions"); - t1 |= type->t & VT_VLA; - - if (t1 & VT_VLA) { - loc -= type_size(&int_type, &align); - loc &= -align; - n = loc; - - vla_runtime_type_size(type, &align); - gen_op('*'); - vset(&int_type, VT_LOCAL|VT_LVAL, n); - vswap(); - vstore(); - } - if (n != -1) - vpop(); - nocode_wanted = saved_nocode_wanted; - - /* we push an anonymous symbol which will contain the array - element type */ - s = sym_push(SYM_FIELD, type, 0, n); - type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; - type->ref = s; - } - return 1; -} - -/* Parse a type declarator (except basic type), and return the type - in 'type'. 'td' is a bitmask indicating which kind of type decl is - expected. 'type' should contain the basic type. 'ad' is the - attribute definition of the basic type. It can be modified by - type_decl(). If this (possibly abstract) declarator is a pointer chain - it returns the innermost pointed to type (equals *type, but is a different - pointer), otherwise returns type itself, that's used for recursive calls. */ -static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) -{ - CType *post, *ret; - int qualifiers, storage; - - /* recursive type, remove storage bits first, apply them later again */ - storage = type->t & VT_STORAGE; - type->t &= ~VT_STORAGE; - post = ret = type; - - while (tok == '*') { - qualifiers = 0; - redo: - next(); - switch(tok) { - case TOK_CONST1: - case TOK_CONST2: - case TOK_CONST3: - qualifiers |= VT_CONSTANT; - goto redo; - case TOK_VOLATILE1: - case TOK_VOLATILE2: - case TOK_VOLATILE3: - qualifiers |= VT_VOLATILE; - goto redo; - case TOK_RESTRICT1: - case TOK_RESTRICT2: - case TOK_RESTRICT3: - goto redo; - /* XXX: clarify attribute handling */ - case TOK_ATTRIBUTE1: - case TOK_ATTRIBUTE2: - parse_attribute(ad); - break; - } - mk_pointer(type); - type->t |= qualifiers; - if (ret == type) - /* innermost pointed to type is the one for the first derivation */ - ret = pointed_type(type); - } - - if (tok == '(') { - /* This is possibly a parameter type list for abstract declarators - ('int ()'), use post_type for testing this. */ - if (!post_type(type, ad, 0, td)) { - /* It's not, so it's a nested declarator, and the post operations - apply to the innermost pointed to type (if any). */ - /* XXX: this is not correct to modify 'ad' at this point, but - the syntax is not clear */ - parse_attribute(ad); - post = type_decl(type, ad, v, td); - skip(')'); - } - } else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { - /* type identifier */ - *v = tok; - next(); - } else { - if (!(td & TYPE_ABSTRACT)) - expect("identifier"); - *v = 0; - } - post_type(post, ad, storage, 0); - parse_attribute(ad); - type->t |= storage; - return ret; -} - -/* compute the lvalue VT_LVAL_xxx needed to match type t. */ -ST_FUNC int lvalue_type(int t) -{ - int bt, r; - r = VT_LVAL; - bt = t & VT_BTYPE; - if (bt == VT_BYTE || bt == VT_BOOL) - r |= VT_LVAL_BYTE; - else if (bt == VT_SHORT) - r |= VT_LVAL_SHORT; - else - return r; - if (t & VT_UNSIGNED) - r |= VT_LVAL_UNSIGNED; - return r; -} - -/* indirection with full error checking and bound check */ -ST_FUNC void indir(void) -{ - if ((vtop->type.t & VT_BTYPE) != VT_PTR) { - if ((vtop->type.t & VT_BTYPE) == VT_FUNC) - return; - expect("pointer"); - } - if (vtop->r & VT_LVAL) - gv(RC_INT); - vtop->type = *pointed_type(&vtop->type); - /* Arrays and functions are never lvalues */ - if (!(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_VLA) - && (vtop->type.t & VT_BTYPE) != VT_FUNC) { - vtop->r |= lvalue_type(vtop->type.t); - /* if bound checking, the referenced pointer must be checked */ -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; -#endif - } -} - -/* pass a parameter to a function and do type checking and casting */ -static void gfunc_param_typed(Sym *func, Sym *arg) -{ - int func_type; - CType type; - - func_type = func->f.func_type; - if (func_type == FUNC_OLD || - (func_type == FUNC_ELLIPSIS && arg == NULL)) { - /* default casting : only need to convert float to double */ - if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { - gen_cast_s(VT_DOUBLE); - } else if (vtop->type.t & VT_BITFIELD) { - type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); - type.ref = vtop->type.ref; - gen_cast(&type); - } - } else if (arg == NULL) { - tcc_error("too many arguments to function"); - } else { - type = arg->type; - type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ - gen_assign_cast(&type); - } -} - -/* parse an expression and return its type without any side effect. */ -static void expr_type(CType *type, void (*expr_fn)(void)) -{ - nocode_wanted++; - expr_fn(); - *type = vtop->type; - vpop(); - nocode_wanted--; -} - -/* parse an expression of the form '(type)' or '(expr)' and return its - type */ -static void parse_expr_type(CType *type) -{ - int n; - AttributeDef ad; - - skip('('); - if (parse_btype(type, &ad)) { - type_decl(type, &ad, &n, TYPE_ABSTRACT); - } else { - expr_type(type, gexpr); - } - skip(')'); -} - -static void parse_type(CType *type) -{ - AttributeDef ad; - int n; - - if (!parse_btype(type, &ad)) { - expect("type"); - } - type_decl(type, &ad, &n, TYPE_ABSTRACT); -} - -static void parse_builtin_params(int nc, const char *args) -{ - char c, sep = '('; - CType t; - if (nc) - nocode_wanted++; - next(); - while ((c = *args++)) { - skip(sep); - sep = ','; - switch (c) { - case 'e': expr_eq(); continue; - case 't': parse_type(&t); vpush(&t); continue; - default: tcc_error("internal error"); break; - } - } - skip(')'); - if (nc) - nocode_wanted--; -} - -ST_FUNC void unary(void) -{ - int n, t, align, size, r, sizeof_caller; - CType type; - Sym *s; - AttributeDef ad; - - sizeof_caller = in_sizeof; - in_sizeof = 0; - type.ref = NULL; - /* XXX: GCC 2.95.3 does not generate a table although it should be - better here */ - tok_next: - switch(tok) { - case TOK_EXTENSION: - next(); - goto tok_next; - case TOK_LCHAR: -#ifdef TCC_TARGET_PE - t = VT_SHORT|VT_UNSIGNED; - goto push_tokc; -#endif - case TOK_CINT: - case TOK_CCHAR: - t = VT_INT; - push_tokc: - type.t = t; - vsetc(&type, VT_CONST, &tokc); - next(); - break; - case TOK_CUINT: - t = VT_INT | VT_UNSIGNED; - goto push_tokc; - case TOK_CLLONG: - t = VT_LLONG; - goto push_tokc; - case TOK_CULLONG: - t = VT_LLONG | VT_UNSIGNED; - goto push_tokc; - case TOK_CFLOAT: - t = VT_FLOAT; - goto push_tokc; - case TOK_CDOUBLE: - t = VT_DOUBLE; - goto push_tokc; - case TOK_CLDOUBLE: - t = VT_LDOUBLE; - goto push_tokc; - case TOK_CLONG: - t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG; - goto push_tokc; - case TOK_CULONG: - t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; - goto push_tokc; - case TOK___FUNCTION__: - if (!gnu_ext) - goto tok_identifier; - /* fall thru */ - case TOK___FUNC__: - { - void *ptr; - int len; - /* special function name identifier */ - len = strlen(funcname) + 1; - /* generate char[len] type */ - type.t = VT_BYTE; - mk_pointer(&type); - type.t |= VT_ARRAY; - type.ref->c = len; - vpush_ref(&type, data_section, data_section->data_offset, len); - if (!NODATA_WANTED) { - ptr = section_ptr_add(data_section, len); - memcpy(ptr, funcname, len); - } - next(); - } - break; - case TOK_LSTR: -#ifdef TCC_TARGET_PE - t = VT_SHORT | VT_UNSIGNED; -#else - t = VT_INT; -#endif - goto str_init; - case TOK_STR: - /* string parsing */ - t = VT_BYTE; - if (tcc_state->char_is_unsigned) - t = VT_BYTE | VT_UNSIGNED; - str_init: - if (tcc_state->warn_write_strings) - t |= VT_CONSTANT; - type.t = t; - mk_pointer(&type); - type.t |= VT_ARRAY; - memset(&ad, 0, sizeof(AttributeDef)); - decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); - break; - case '(': - next(); - /* cast ? */ - if (parse_btype(&type, &ad)) { - type_decl(&type, &ad, &n, TYPE_ABSTRACT); - skip(')'); - /* check ISOC99 compound literal */ - if (tok == '{') { - /* data is allocated locally by default */ - if (global_expr) - r = VT_CONST; - else - r = VT_LOCAL; - /* all except arrays are lvalues */ - if (!(type.t & VT_ARRAY)) - r |= lvalue_type(type.t); - memset(&ad, 0, sizeof(AttributeDef)); - decl_initializer_alloc(&type, &ad, r, 1, 0, 0); - } else { - if (sizeof_caller) { - vpush(&type); - return; - } - unary(); - gen_cast(&type); - } - } else if (tok == '{') { - int saved_nocode_wanted = nocode_wanted; - if (const_wanted) - tcc_error("expected constant"); - /* save all registers */ - save_regs(0); - /* statement expression : we do not accept break/continue - inside as GCC does. We do retain the nocode_wanted state, - as statement expressions can't ever be entered from the - outside, so any reactivation of code emission (from labels - or loop heads) can be disabled again after the end of it. */ - block(NULL, NULL, 1); - nocode_wanted = saved_nocode_wanted; - skip(')'); - } else { - gexpr(); - skip(')'); - } - break; - case '*': - next(); - unary(); - indir(); - break; - case '&': - next(); - unary(); - /* functions names must be treated as function pointers, - except for unary '&' and sizeof. Since we consider that - functions are not lvalues, we only have to handle it - there and in function calls. */ - /* arrays can also be used although they are not lvalues */ - if ((vtop->type.t & VT_BTYPE) != VT_FUNC && - !(vtop->type.t & VT_ARRAY)) - test_lvalue(); - mk_pointer(&vtop->type); - gaddrof(); - break; - case '!': - next(); - unary(); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - gen_cast_s(VT_BOOL); - vtop->c.i = !vtop->c.i; - } else if ((vtop->r & VT_VALMASK) == VT_CMP) - vtop->c.i ^= 1; - else { - save_regs(1); - vseti(VT_JMP, gvtst(1, 0)); - } - break; - case '~': - next(); - unary(); - vpushi(-1); - gen_op('^'); - break; - case '+': - next(); - unary(); - if ((vtop->type.t & VT_BTYPE) == VT_PTR) - tcc_error("pointer not accepted for unary plus"); - /* In order to force cast, we add zero, except for floating point - where we really need an noop (otherwise -0.0 will be transformed - into +0.0). */ - if (!is_float(vtop->type.t)) { - vpushi(0); - gen_op('+'); - } - break; - case TOK_SIZEOF: - case TOK_ALIGNOF1: - case TOK_ALIGNOF2: - t = tok; - next(); - in_sizeof++; - expr_type(&type, unary); /* Perform a in_sizeof = 0; */ - s = vtop[1].sym; /* hack: accessing previous vtop */ - size = type_size(&type, &align); - if (s && s->a.aligned) - align = 1 << (s->a.aligned - 1); - if (t == TOK_SIZEOF) { - if (!(type.t & VT_VLA)) { - if (size < 0) - tcc_error("sizeof applied to an incomplete type"); - vpushs(size); - } else { - vla_runtime_type_size(&type, &align); - } - } else { - vpushs(align); - } - vtop->type.t |= VT_UNSIGNED; - break; - - case TOK_builtin_expect: - /* __builtin_expect is a no-op for now */ - parse_builtin_params(0, "ee"); - vpop(); - break; - case TOK_builtin_types_compatible_p: - parse_builtin_params(0, "tt"); - vtop[-1].type.t &= ~(VT_CONSTANT | VT_VOLATILE); - vtop[0].type.t &= ~(VT_CONSTANT | VT_VOLATILE); - n = is_compatible_types(&vtop[-1].type, &vtop[0].type); - vtop -= 2; - vpushi(n); - break; - case TOK_builtin_choose_expr: - { - int64_t c; - next(); - skip('('); - c = expr_const64(); - skip(','); - if (!c) { - nocode_wanted++; - } - expr_eq(); - if (!c) { - vpop(); - nocode_wanted--; - } - skip(','); - if (c) { - nocode_wanted++; - } - expr_eq(); - if (c) { - vpop(); - nocode_wanted--; - } - skip(')'); - } - break; - case TOK_builtin_constant_p: - parse_builtin_params(1, "e"); - n = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - vtop--; - vpushi(n); - break; - case TOK_builtin_frame_address: - case TOK_builtin_return_address: - { - int tok1 = tok; - int level; - next(); - skip('('); - if (tok != TOK_CINT) { - tcc_error("%s only takes positive integers", - tok1 == TOK_builtin_return_address ? - "__builtin_return_address" : - "__builtin_frame_address"); - } - level = (uint32_t)tokc.i; - next(); - skip(')'); - type.t = VT_VOID; - mk_pointer(&type); - vset(&type, VT_LOCAL, 0); /* local frame */ - while (level--) { - mk_pointer(&vtop->type); - indir(); /* -> parent frame */ - } - if (tok1 == TOK_builtin_return_address) { - // assume return address is just above frame pointer on stack - vpushi(PTR_SIZE); - gen_op('+'); - mk_pointer(&vtop->type); - indir(); - } - } - break; -#ifdef TCC_TARGET_X86_64 -#ifdef TCC_TARGET_PE - case TOK_builtin_va_start: - parse_builtin_params(0, "ee"); - r = vtop->r & VT_VALMASK; - if (r == VT_LLOCAL) - r = VT_LOCAL; - if (r != VT_LOCAL) - tcc_error("__builtin_va_start expects a local variable"); - vtop->r = r; - vtop->type = char_pointer_type; - vtop->c.i += 8; - vstore(); - break; -#else - case TOK_builtin_va_arg_types: - parse_builtin_params(0, "t"); - vpushi(classify_x86_64_va_arg(&vtop->type)); - vswap(); - vpop(); - break; -#endif -#endif - -#ifdef TCC_TARGET_ARM64 - case TOK___va_start: { - parse_builtin_params(0, "ee"); - //xx check types - gen_va_start(); - vpushi(0); - vtop->type.t = VT_VOID; - break; - } - case TOK___va_arg: { - parse_builtin_params(0, "et"); - type = vtop->type; - vpop(); - //xx check types - gen_va_arg(&type); - vtop->type = type; - break; - } - case TOK___arm64_clear_cache: { - parse_builtin_params(0, "ee"); - gen_clear_cache(); - vpushi(0); - vtop->type.t = VT_VOID; - break; - } -#endif - /* pre operations */ - case TOK_INC: - case TOK_DEC: - t = tok; - next(); - unary(); - inc(0, t); - break; - case '-': - next(); - unary(); - t = vtop->type.t & VT_BTYPE; - if (is_float(t)) { - /* In IEEE negate(x) isn't subtract(0,x), but rather - subtract(-0, x). */ - vpush(&vtop->type); - if (t == VT_FLOAT) - vtop->c.f = -1.0 * 0.0; - else if (t == VT_DOUBLE) - vtop->c.d = -1.0 * 0.0; - else - vtop->c.ld = -1.0 * 0.0; - } else - vpushi(0); - vswap(); - gen_op('-'); - break; - case TOK_LAND: - if (!gnu_ext) - goto tok_identifier; - next(); - /* allow to take the address of a label */ - if (tok < TOK_UIDENT) - expect("label identifier"); - s = label_find(tok); - if (!s) { - s = label_push(&global_label_stack, tok, LABEL_FORWARD); - } else { - if (s->r == LABEL_DECLARED) - s->r = LABEL_FORWARD; - } - if (!s->type.t) { - s->type.t = VT_VOID; - mk_pointer(&s->type); - s->type.t |= VT_STATIC; - } - vpushsym(&s->type, s); - next(); - break; - - case TOK_GENERIC: - { - CType controlling_type; - int has_default = 0; - int has_match = 0; - int learn = 0; - TokenString *str = NULL; - - next(); - skip('('); - expr_type(&controlling_type, expr_eq); - controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY); - for (;;) { - learn = 0; - skip(','); - if (tok == TOK_DEFAULT) { - if (has_default) - tcc_error("too many 'default'"); - has_default = 1; - if (!has_match) - learn = 1; - next(); - } else { - AttributeDef ad_tmp; - int itmp; - CType cur_type; - parse_btype(&cur_type, &ad_tmp); - type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); - if (compare_types(&controlling_type, &cur_type, 0)) { - if (has_match) { - tcc_error("type match twice"); - } - has_match = 1; - learn = 1; - } - } - skip(':'); - if (learn) { - if (str) - tok_str_free(str); - skip_or_save_block(&str); - } else { - skip_or_save_block(NULL); - } - if (tok == ')') - break; - } - if (!str) { - char buf[60]; - type_to_str(buf, sizeof buf, &controlling_type, NULL); - tcc_error("type '%s' does not match any association", buf); - } - begin_macro(str, 1); - next(); - expr_eq(); - if (tok != TOK_EOF) - expect(","); - end_macro(); - next(); - break; - } - // special qnan , snan and infinity values - case TOK___NAN__: - vpush64(VT_DOUBLE, 0x7ff8000000000000ULL); - next(); - break; - case TOK___SNAN__: - vpush64(VT_DOUBLE, 0x7ff0000000000001ULL); - next(); - break; - case TOK___INF__: - vpush64(VT_DOUBLE, 0x7ff0000000000000ULL); - next(); - break; - - default: - tok_identifier: - t = tok; - next(); - if (t < TOK_UIDENT) - expect("identifier"); - s = sym_find(t); - if (!s) { - const char *name = get_tok_str(t, NULL); - if (tok != '(') - tcc_error("'%s' undeclared", name); - /* for simple function calls, we tolerate undeclared - external reference to int() function */ - if (tcc_state->warn_implicit_function_declaration -#ifdef TCC_TARGET_PE - /* people must be warned about using undeclared WINAPI functions - (which usually start with uppercase letter) */ - || (name[0] >= 'A' && name[0] <= 'Z') -#endif - ) - tcc_warning("implicit declaration of function '%s'", name); - s = external_global_sym(t, &func_old_type, 0); - } - - r = s->r; - /* A symbol that has a register is a local register variable, - which starts out as VT_LOCAL value. */ - if ((r & VT_VALMASK) < VT_CONST) - r = (r & ~VT_VALMASK) | VT_LOCAL; - - vset(&s->type, r, s->c); - /* Point to s as backpointer (even without r&VT_SYM). - Will be used by at least the x86 inline asm parser for - regvars. */ - vtop->sym = s; - - if (r & VT_SYM) { - vtop->c.i = 0; - } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) { - vtop->c.i = s->enum_val; - } - break; - } - - /* post operations */ - while (1) { - if (tok == TOK_INC || tok == TOK_DEC) { - inc(1, tok); - next(); - } else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) { - int qualifiers; - /* field */ - if (tok == TOK_ARROW) - indir(); - qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); - test_lvalue(); - gaddrof(); - /* expect pointer on structure */ - if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) - expect("struct or union"); - if (tok == TOK_CDOUBLE) - expect("field name"); - next(); - if (tok == TOK_CINT || tok == TOK_CUINT) - expect("field name"); - s = find_field(&vtop->type, tok); - if (!s) - tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc)); - /* add field offset to pointer */ - vtop->type = char_pointer_type; /* change type to 'char *' */ - vpushi(s->c); - gen_op('+'); - /* change type to field type, and set to lvalue */ - vtop->type = s->type; - vtop->type.t |= qualifiers; - /* an array is never an lvalue */ - if (!(vtop->type.t & VT_ARRAY)) { - vtop->r |= lvalue_type(vtop->type.t); -#ifdef CONFIG_TCC_BCHECK - /* if bound checking, the referenced pointer must be checked */ - if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL) - vtop->r |= VT_MUSTBOUND; -#endif - } - next(); - } else if (tok == '[') { - next(); - gexpr(); - gen_op('+'); - indir(); - skip(']'); - } else if (tok == '(') { - SValue ret; - Sym *sa; - int nb_args, ret_nregs, ret_align, regsize, variadic; - - /* function call */ - if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { - /* pointer test (no array accepted) */ - if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { - vtop->type = *pointed_type(&vtop->type); - if ((vtop->type.t & VT_BTYPE) != VT_FUNC) - goto error_func; - } else { - error_func: - expect("function pointer"); - } - } else { - vtop->r &= ~VT_LVAL; /* no lvalue */ - } - /* get return type */ - s = vtop->type.ref; - next(); - sa = s->next; /* first parameter */ - nb_args = regsize = 0; - ret.r2 = VT_CONST; - /* compute first implicit argument if a structure is returned */ - if ((s->type.t & VT_BTYPE) == VT_STRUCT) { - variadic = (s->f.func_type == FUNC_ELLIPSIS); - ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, - &ret_align, ®size); - if (!ret_nregs) { - /* get some space for the returned structure */ - size = type_size(&s->type, &align); -#ifdef TCC_TARGET_ARM64 - /* On arm64, a small struct is return in registers. - It is much easier to write it to memory if we know - that we are allowed to write some extra bytes, so - round the allocated space up to a power of 2: */ - if (size < 16) - while (size & (size - 1)) - size = (size | (size - 1)) + 1; -#endif - loc = (loc - size) & -align; - ret.type = s->type; - ret.r = VT_LOCAL | VT_LVAL; - /* pass it as 'int' to avoid structure arg passing - problems */ - vseti(VT_LOCAL, loc); - ret.c = vtop->c; - nb_args++; - } - } else { - ret_nregs = 1; - ret.type = s->type; - } - - if (ret_nregs) { - /* return in register */ - if (is_float(ret.type.t)) { - ret.r = reg_fret(ret.type.t); -#ifdef TCC_TARGET_X86_64 - if ((ret.type.t & VT_BTYPE) == VT_QFLOAT) - ret.r2 = REG_QRET; -#endif - } else { -#ifndef TCC_TARGET_ARM64 -#ifdef TCC_TARGET_X86_64 - if ((ret.type.t & VT_BTYPE) == VT_QLONG) -#else - if ((ret.type.t & VT_BTYPE) == VT_LLONG) -#endif - ret.r2 = REG_LRET; -#endif - ret.r = REG_IRET; - } - ret.c.i = 0; - } - if (tok != ')') { - for(;;) { - expr_eq(); - gfunc_param_typed(s, sa); - nb_args++; - if (sa) - sa = sa->next; - if (tok == ')') - break; - skip(','); - } - } - if (sa) - tcc_error("too few arguments to function"); - skip(')'); - gfunc_call(nb_args); - - /* return value */ - for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { - vsetc(&ret.type, r, &ret.c); - vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */ - } - - /* handle packed struct return */ - if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { - int addr, offset; - - size = type_size(&s->type, &align); - /* We're writing whole regs often, make sure there's enough - space. Assume register size is power of 2. */ - if (regsize > align) - align = regsize; - loc = (loc - size) & -align; - addr = loc; - offset = 0; - for (;;) { - vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); - vswap(); - vstore(); - vtop--; - if (--ret_nregs == 0) - break; - offset += regsize; - } - vset(&s->type, VT_LOCAL | VT_LVAL, addr); - } - } else { - break; - } - } -} - -ST_FUNC void expr_prod(void) -{ - int t; - - unary(); - while (tok == '*' || tok == '/' || tok == '%') { - t = tok; - next(); - unary(); - gen_op(t); - } -} - -ST_FUNC void expr_sum(void) -{ - int t; - - expr_prod(); - while (tok == '+' || tok == '-') { - t = tok; - next(); - expr_prod(); - gen_op(t); - } -} - -static void expr_shift(void) -{ - int t; - - expr_sum(); - while (tok == TOK_SHL || tok == TOK_SAR) { - t = tok; - next(); - expr_sum(); - gen_op(t); - } -} - -static void expr_cmp(void) -{ - int t; - - expr_shift(); - while ((tok >= TOK_ULE && tok <= TOK_GT) || - tok == TOK_ULT || tok == TOK_UGE) { - t = tok; - next(); - expr_shift(); - gen_op(t); - } -} - -static void expr_cmpeq(void) -{ - int t; - - expr_cmp(); - while (tok == TOK_EQ || tok == TOK_NE) { - t = tok; - next(); - expr_cmp(); - gen_op(t); - } -} - -static void expr_and(void) -{ - expr_cmpeq(); - while (tok == '&') { - next(); - expr_cmpeq(); - gen_op('&'); - } -} - -static void expr_xor(void) -{ - expr_and(); - while (tok == '^') { - next(); - expr_and(); - gen_op('^'); - } -} - -static void expr_or(void) -{ - expr_xor(); - while (tok == '|') { - next(); - expr_xor(); - gen_op('|'); - } -} - -static void expr_land(void) -{ - expr_or(); - if (tok == TOK_LAND) { - int t = 0; - for(;;) { - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - gen_cast_s(VT_BOOL); - if (vtop->c.i) { - vpop(); - } else { - nocode_wanted++; - while (tok == TOK_LAND) { - next(); - expr_or(); - vpop(); - } - nocode_wanted--; - if (t) - gsym(t); - gen_cast_s(VT_INT); - break; - } - } else { - if (!t) - save_regs(1); - t = gvtst(1, t); - } - if (tok != TOK_LAND) { - if (t) - vseti(VT_JMPI, t); - else - vpushi(1); - break; - } - next(); - expr_or(); - } - } -} - -static void expr_lor(void) -{ - expr_land(); - if (tok == TOK_LOR) { - int t = 0; - for(;;) { - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - gen_cast_s(VT_BOOL); - if (!vtop->c.i) { - vpop(); - } else { - nocode_wanted++; - while (tok == TOK_LOR) { - next(); - expr_land(); - vpop(); - } - nocode_wanted--; - if (t) - gsym(t); - gen_cast_s(VT_INT); - break; - } - } else { - if (!t) - save_regs(1); - t = gvtst(0, t); - } - if (tok != TOK_LOR) { - if (t) - vseti(VT_JMP, t); - else - vpushi(0); - break; - } - next(); - expr_land(); - } - } -} - -/* Assuming vtop is a value used in a conditional context - (i.e. compared with zero) return 0 if it's false, 1 if - true and -1 if it can't be statically determined. */ -static int condition_3way(void) -{ - int c = -1; - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - (!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) { - vdup(); - gen_cast_s(VT_BOOL); - c = vtop->c.i; - vpop(); - } - return c; -} - -static void expr_cond(void) -{ - int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g; - SValue sv; - CType type, type1, type2; - - expr_lor(); - if (tok == '?') { - next(); - c = condition_3way(); - g = (tok == ':' && gnu_ext); - if (c < 0) { - /* needed to avoid having different registers saved in - each branch */ - if (is_float(vtop->type.t)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - rc = RC_ST0; - } -#endif - } else - rc = RC_INT; - gv(rc); - save_regs(1); - if (g) - gv_dup(); - tt = gvtst(1, 0); - - } else { - if (!g) - vpop(); - tt = 0; - } - - if (1) { - if (c == 0) - nocode_wanted++; - if (!g) - gexpr(); - - type1 = vtop->type; - sv = *vtop; /* save value to handle it later */ - vtop--; /* no vpop so that FP stack is not flushed */ - skip(':'); - - u = 0; - if (c < 0) - u = gjmp(0); - gsym(tt); - - if (c == 0) - nocode_wanted--; - if (c == 1) - nocode_wanted++; - expr_cond(); - if (c == 1) - nocode_wanted--; - - type2 = vtop->type; - t1 = type1.t; - bt1 = t1 & VT_BTYPE; - t2 = type2.t; - bt2 = t2 & VT_BTYPE; - type.ref = NULL; - - /* cast operands to correct type according to ISOC rules */ - if (is_float(bt1) || is_float(bt2)) { - if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { - type.t = VT_LDOUBLE; - - } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { - type.t = VT_DOUBLE; - } else { - type.t = VT_FLOAT; - } - } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { - /* cast to biggest op */ - type.t = VT_LLONG | VT_LONG; - if (bt1 == VT_LLONG) - type.t &= t1; - if (bt2 == VT_LLONG) - type.t &= t2; - /* convert to unsigned if it does not fit in a long long */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) - type.t |= VT_UNSIGNED; - } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - /* If one is a null ptr constant the result type - is the other. */ - if (is_null_pointer (vtop)) - type = type1; - else if (is_null_pointer (&sv)) - type = type2; - /* XXX: test pointer compatibility, C99 has more elaborate - rules here. */ - else - type = type1; - } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { - /* XXX: test function pointer compatibility */ - type = bt1 == VT_FUNC ? type1 : type2; - } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { - /* XXX: test structure compatibility */ - type = bt1 == VT_STRUCT ? type1 : type2; - } else if (bt1 == VT_VOID || bt2 == VT_VOID) { - /* NOTE: as an extension, we accept void on only one side */ - type.t = VT_VOID; - } else { - /* integer operations */ - type.t = VT_INT | (VT_LONG & (t1 | t2)); - /* convert to unsigned if it does not fit in an integer */ - if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || - (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) - type.t |= VT_UNSIGNED; - } - /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so - that `(expr ? a : b).mem` does not error with "lvalue expected" */ - islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); - islv &= c < 0; - - /* now we convert second operand */ - if (c != 1) { - gen_cast(&type); - if (islv) { - mk_pointer(&vtop->type); - gaddrof(); - } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) - gaddrof(); - } - - rc = RC_INT; - if (is_float(type.t)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((type.t & VT_BTYPE) == VT_LDOUBLE) { - rc = RC_ST0; - } -#endif - } else if ((type.t & VT_BTYPE) == VT_LLONG) { - /* for long longs, we use fixed registers to avoid having - to handle a complicated move */ - rc = RC_IRET; - } - - tt = r2 = 0; - if (c < 0) { - r2 = gv(rc); - tt = gjmp(0); - } - gsym(u); - - /* this is horrible, but we must also convert first - operand */ - if (c != 0) { - *vtop = sv; - gen_cast(&type); - if (islv) { - mk_pointer(&vtop->type); - gaddrof(); - } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) - gaddrof(); - } - - if (c < 0) { - r1 = gv(rc); - move_reg(r2, r1, type.t); - vtop->r = r2; - gsym(tt); - if (islv) - indir(); - } - } - } -} - -static void expr_eq(void) -{ - int t; - - expr_cond(); - if (tok == '=' || - (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || - tok == TOK_A_XOR || tok == TOK_A_OR || - tok == TOK_A_SHL || tok == TOK_A_SAR) { - test_lvalue(); - t = tok; - next(); - if (t == '=') { - expr_eq(); - } else { - vdup(); - expr_eq(); - gen_op(t & 0x7f); - } - vstore(); - } -} - -ST_FUNC void gexpr(void) -{ - while (1) { - expr_eq(); - if (tok != ',') - break; - vpop(); - next(); - } -} - -/* parse a constant expression and return value in vtop. */ -static void expr_const1(void) -{ - const_wanted++; - nocode_wanted++; - expr_cond(); - nocode_wanted--; - const_wanted--; -} - -/* parse an integer constant and return its value. */ -static inline int64_t expr_const64(void) -{ - int64_t c; - expr_const1(); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) - expect("constant expression"); - c = vtop->c.i; - vpop(); - return c; -} - -/* parse an integer constant and return its value. - Complain if it doesn't fit 32bit (signed or unsigned). */ -ST_FUNC int expr_const(void) -{ - int c; - int64_t wc = expr_const64(); - c = wc; - if (c != wc && (unsigned)c != wc) - tcc_error("constant exceeds 32 bit"); - return c; -} - -/* return the label token if current token is a label, otherwise - return zero */ -static int is_label(void) -{ - int last_tok; - - /* fast test first */ - if (tok < TOK_UIDENT) - return 0; - /* no need to save tokc because tok is an identifier */ - last_tok = tok; - next(); - if (tok == ':') { - return last_tok; - } else { - unget_tok(last_tok); - return 0; - } -} - -#ifndef TCC_TARGET_ARM64 -static void gfunc_return(CType *func_type) -{ - if ((func_type->t & VT_BTYPE) == VT_STRUCT) { - CType type, ret_type; - int ret_align, ret_nregs, regsize; - ret_nregs = gfunc_sret(func_type, func_var, &ret_type, - &ret_align, ®size); - if (0 == ret_nregs) { - /* if returning structure, must copy it to implicit - first pointer arg location */ - type = *func_type; - mk_pointer(&type); - vset(&type, VT_LOCAL | VT_LVAL, func_vc); - indir(); - vswap(); - /* copy structure value to pointer */ - vstore(); - } else { - /* returning structure packed into registers */ - int r, size, addr, align; - size = type_size(func_type,&align); - if ((vtop->r != (VT_LOCAL | VT_LVAL) || - (vtop->c.i & (ret_align-1))) - && (align & (ret_align-1))) { - loc = (loc - size) & -ret_align; - addr = loc; - type = *func_type; - vset(&type, VT_LOCAL | VT_LVAL, addr); - vswap(); - vstore(); - vpop(); - vset(&ret_type, VT_LOCAL | VT_LVAL, addr); - } - vtop->type = ret_type; - if (is_float(ret_type.t)) - r = rc_fret(ret_type.t); - else - r = RC_IRET; - - if (ret_nregs == 1) - gv(r); - else { - for (;;) { - vdup(); - gv(r); - vpop(); - if (--ret_nregs == 0) - break; - /* We assume that when a structure is returned in multiple - registers, their classes are consecutive values of the - suite s(n) = 2^n */ - r <<= 1; - vtop->c.i += regsize; - } - } - } - } else if (is_float(func_type->t)) { - gv(rc_fret(func_type->t)); - } else { - gv(RC_IRET); - } - vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ -} -#endif - -static int case_cmp(const void *pa, const void *pb) -{ - int64_t a = (*(struct case_t**) pa)->v1; - int64_t b = (*(struct case_t**) pb)->v1; - return a < b ? -1 : a > b; -} - -static void gcase(struct case_t **base, int len, int *bsym) -{ - struct case_t *p; - int e; - int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; - gv(RC_INT); - while (len > 4) { - /* binary search */ - p = base[len/2]; - vdup(); - if (ll) - vpushll(p->v2); - else - vpushi(p->v2); - gen_op(TOK_LE); - e = gtst(1, 0); - vdup(); - if (ll) - vpushll(p->v1); - else - vpushi(p->v1); - gen_op(TOK_GE); - gtst_addr(0, p->sym); /* v1 <= x <= v2 */ - /* x < v1 */ - gcase(base, len/2, bsym); - if (cur_switch->def_sym) - gjmp_addr(cur_switch->def_sym); - else - *bsym = gjmp(*bsym); - /* x > v2 */ - gsym(e); - e = len/2 + 1; - base += e; len -= e; - } - /* linear scan */ - while (len--) { - p = *base++; - vdup(); - if (ll) - vpushll(p->v2); - else - vpushi(p->v2); - if (p->v1 == p->v2) { - gen_op(TOK_EQ); - gtst_addr(0, p->sym); - } else { - gen_op(TOK_LE); - e = gtst(1, 0); - vdup(); - if (ll) - vpushll(p->v1); - else - vpushi(p->v1); - gen_op(TOK_GE); - gtst_addr(0, p->sym); - gsym(e); - } - } -} - -static void block(int *bsym, int *csym, int is_expr) -{ - int a, b, c, d, cond; - Sym *s; - - /* generate line number info */ - if (tcc_state->do_debug) - tcc_debug_line(tcc_state); - - if (is_expr) { - /* default return value is (void) */ - vpushi(0); - vtop->type.t = VT_VOID; - } - - if (tok == TOK_IF) { - /* if test */ - int saved_nocode_wanted = nocode_wanted; - next(); - skip('('); - gexpr(); - skip(')'); - cond = condition_3way(); - if (cond == 1) - a = 0, vpop(); - else - a = gvtst(1, 0); - if (cond == 0) - nocode_wanted |= 0x20000000; - block(bsym, csym, 0); - if (cond != 1) - nocode_wanted = saved_nocode_wanted; - c = tok; - if (c == TOK_ELSE) { - next(); - d = gjmp(0); - gsym(a); - if (cond == 1) - nocode_wanted |= 0x20000000; - block(bsym, csym, 0); - gsym(d); /* patch else jmp */ - if (cond != 0) - nocode_wanted = saved_nocode_wanted; - } else - gsym(a); - } else if (tok == TOK_WHILE) { - int saved_nocode_wanted; - nocode_wanted &= ~0x20000000; - next(); - d = ind; - vla_sp_restore(); - skip('('); - gexpr(); - skip(')'); - a = gvtst(1, 0); - b = 0; - ++local_scope; - saved_nocode_wanted = nocode_wanted; - block(&a, &b, 0); - nocode_wanted = saved_nocode_wanted; - --local_scope; - gjmp_addr(d); - gsym(a); - gsym_addr(b, d); - } else if (tok == '{') { - Sym *llabel; - int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; - - next(); - /* record local declaration stack position */ - s = local_stack; - llabel = local_label_stack; - ++local_scope; - - /* handle local labels declarations */ - if (tok == TOK_LABEL) { - next(); - for(;;) { - if (tok < TOK_UIDENT) - expect("label identifier"); - label_push(&local_label_stack, tok, LABEL_DECLARED); - next(); - if (tok == ',') { - next(); - } else { - skip(';'); - break; - } - } - } - while (tok != '}') { - if ((a = is_label())) - unget_tok(a); - else - decl(VT_LOCAL); - if (tok != '}') { - if (is_expr) - vpop(); - block(bsym, csym, is_expr); - } - } - /* pop locally defined labels */ - label_pop(&local_label_stack, llabel, is_expr); - /* pop locally defined symbols */ - --local_scope; - /* In the is_expr case (a statement expression is finished here), - vtop might refer to symbols on the local_stack. Either via the - type or via vtop->sym. We can't pop those nor any that in turn - might be referred to. To make it easier we don't roll back - any symbols in that case; some upper level call to block() will - do that. We do have to remove such symbols from the lookup - tables, though. sym_pop will do that. */ - sym_pop(&local_stack, s, is_expr); - - /* Pop VLA frames and restore stack pointer if required */ - if (vlas_in_scope > saved_vlas_in_scope) { - vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc; - vla_sp_restore(); - } - vlas_in_scope = saved_vlas_in_scope; - - next(); - } else if (tok == TOK_RETURN) { - next(); - if (tok != ';') { - gexpr(); - gen_assign_cast(&func_vt); - if ((func_vt.t & VT_BTYPE) == VT_VOID) - vtop--; - else - gfunc_return(&func_vt); - } - skip(';'); - /* jump unless last stmt in top-level block */ - if (tok != '}' || local_scope != 1) - rsym = gjmp(rsym); - nocode_wanted |= 0x20000000; - } else if (tok == TOK_BREAK) { - /* compute jump */ - if (!bsym) - tcc_error("cannot break"); - *bsym = gjmp(*bsym); - next(); - skip(';'); - nocode_wanted |= 0x20000000; - } else if (tok == TOK_CONTINUE) { - /* compute jump */ - if (!csym) - tcc_error("cannot continue"); - vla_sp_restore_root(); - *csym = gjmp(*csym); - next(); - skip(';'); - } else if (tok == TOK_FOR) { - int e; - int saved_nocode_wanted; - nocode_wanted &= ~0x20000000; - next(); - skip('('); - s = local_stack; - ++local_scope; - if (tok != ';') { - /* c99 for-loop init decl? */ - if (!decl0(VT_LOCAL, 1, NULL)) { - /* no, regular for-loop init expr */ - gexpr(); - vpop(); - } - } - skip(';'); - d = ind; - c = ind; - vla_sp_restore(); - a = 0; - b = 0; - if (tok != ';') { - gexpr(); - a = gvtst(1, 0); - } - skip(';'); - if (tok != ')') { - e = gjmp(0); - c = ind; - vla_sp_restore(); - gexpr(); - vpop(); - gjmp_addr(d); - gsym(e); - } - skip(')'); - saved_nocode_wanted = nocode_wanted; - block(&a, &b, 0); - nocode_wanted = saved_nocode_wanted; - gjmp_addr(c); - gsym(a); - gsym_addr(b, c); - --local_scope; - sym_pop(&local_stack, s, 0); - - } else - if (tok == TOK_DO) { - int saved_nocode_wanted; - nocode_wanted &= ~0x20000000; - next(); - a = 0; - b = 0; - d = ind; - vla_sp_restore(); - saved_nocode_wanted = nocode_wanted; - block(&a, &b, 0); - skip(TOK_WHILE); - skip('('); - gsym(b); - gexpr(); - c = gvtst(0, 0); - gsym_addr(c, d); - nocode_wanted = saved_nocode_wanted; - skip(')'); - gsym(a); - skip(';'); - } else - if (tok == TOK_SWITCH) { - struct switch_t *saved, sw; - int saved_nocode_wanted = nocode_wanted; - SValue switchval; - next(); - skip('('); - gexpr(); - skip(')'); - switchval = *vtop--; - a = 0; - b = gjmp(0); /* jump to first case */ - sw.p = NULL; sw.n = 0; sw.def_sym = 0; - saved = cur_switch; - cur_switch = &sw; - block(&a, csym, 0); - nocode_wanted = saved_nocode_wanted; - a = gjmp(a); /* add implicit break */ - /* case lookup */ - gsym(b); - qsort(sw.p, sw.n, sizeof(void*), case_cmp); - for (b = 1; b < sw.n; b++) - if (sw.p[b - 1]->v2 >= sw.p[b]->v1) - tcc_error("duplicate case value"); - /* Our switch table sorting is signed, so the compared - value needs to be as well when it's 64bit. */ - if ((switchval.type.t & VT_BTYPE) == VT_LLONG) - switchval.type.t &= ~VT_UNSIGNED; - vpushv(&switchval); - gcase(sw.p, sw.n, &a); - vpop(); - if (sw.def_sym) - gjmp_addr(sw.def_sym); - dynarray_reset(&sw.p, &sw.n); - cur_switch = saved; - /* break label */ - gsym(a); - } else - if (tok == TOK_CASE) { - struct case_t *cr = tcc_malloc(sizeof(struct case_t)); - if (!cur_switch) - expect("switch"); - nocode_wanted &= ~0x20000000; - next(); - cr->v1 = cr->v2 = expr_const64(); - if (gnu_ext && tok == TOK_DOTS) { - next(); - cr->v2 = expr_const64(); - if (cr->v2 < cr->v1) - tcc_warning("empty case range"); - } - cr->sym = ind; - dynarray_add(&cur_switch->p, &cur_switch->n, cr); - skip(':'); - is_expr = 0; - goto block_after_label; - } else - if (tok == TOK_DEFAULT) { - next(); - skip(':'); - if (!cur_switch) - expect("switch"); - if (cur_switch->def_sym) - tcc_error("too many 'default'"); - cur_switch->def_sym = ind; - is_expr = 0; - goto block_after_label; - } else - if (tok == TOK_GOTO) { - next(); - if (tok == '*' && gnu_ext) { - /* computed goto */ - next(); - gexpr(); - if ((vtop->type.t & VT_BTYPE) != VT_PTR) - expect("pointer"); - ggoto(); - } else if (tok >= TOK_UIDENT) { - s = label_find(tok); - /* put forward definition if needed */ - if (!s) { - s = label_push(&global_label_stack, tok, LABEL_FORWARD); - } else { - if (s->r == LABEL_DECLARED) - s->r = LABEL_FORWARD; - } - vla_sp_restore_root(); - if (s->r & LABEL_FORWARD) - s->jnext = gjmp(s->jnext); - else - gjmp_addr(s->jnext); - next(); - } else { - expect("label identifier"); - } - skip(';'); - } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { - asm_instr(); - } else { - b = is_label(); - if (b) { - /* label case */ - next(); - s = label_find(b); - if (s) { - if (s->r == LABEL_DEFINED) - tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); - gsym(s->jnext); - s->r = LABEL_DEFINED; - } else { - s = label_push(&global_label_stack, b, LABEL_DEFINED); - } - s->jnext = ind; - vla_sp_restore(); - /* we accept this, but it is a mistake */ - block_after_label: - nocode_wanted &= ~0x20000000; - if (tok == '}') { - tcc_warning("deprecated use of label at end of compound statement"); - } else { - if (is_expr) - vpop(); - block(bsym, csym, is_expr); - } - } else { - /* expression case */ - if (tok != ';') { - if (is_expr) { - vpop(); - gexpr(); - } else { - gexpr(); - vpop(); - } - } - skip(';'); - } - } -} - -/* This skips over a stream of tokens containing balanced {} and () - pairs, stopping at outer ',' ';' and '}' (or matching '}' if we started - with a '{'). If STR then allocates and stores the skipped tokens - in *STR. This doesn't check if () and {} are nested correctly, - i.e. "({)}" is accepted. */ -static void skip_or_save_block(TokenString **str) -{ - int braces = tok == '{'; - int level = 0; - if (str) - *str = tok_str_alloc(); - - while ((level > 0 || (tok != '}' && tok != ',' && tok != ';' && tok != ')'))) { - int t; - if (tok == TOK_EOF) { - if (str || level > 0) - tcc_error("unexpected end of file"); - else - break; - } - if (str) - tok_str_add_tok(*str); - t = tok; - next(); - if (t == '{' || t == '(') { - level++; - } else if (t == '}' || t == ')') { - level--; - if (level == 0 && braces && t == '}') - break; - } - } - if (str) { - tok_str_add(*str, -1); - tok_str_add(*str, 0); - } -} - -#define EXPR_CONST 1 -#define EXPR_ANY 2 - -static void parse_init_elem(int expr_type) -{ - int saved_global_expr; - switch(expr_type) { - case EXPR_CONST: - /* compound literals must be allocated globally in this case */ - saved_global_expr = global_expr; - global_expr = 1; - expr_const1(); - global_expr = saved_global_expr; - /* NOTE: symbols are accepted, as well as lvalue for anon symbols - (compound literals). */ - if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST - && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL) - || vtop->sym->v < SYM_FIRST_ANOM)) -#ifdef TCC_TARGET_PE - || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport) -#endif - ) - tcc_error("initializer element is not constant"); - break; - case EXPR_ANY: - expr_eq(); - break; - } -} - -/* put zeros for variable based init */ -static void init_putz(Section *sec, unsigned long c, int size) -{ - if (sec) { - /* nothing to do because globals are already set to zero */ - } else { - vpush_global_sym(&func_old_type, TOK_memset); - vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM - vpushs(size); - vpushi(0); -#else - vpushi(0); - vpushs(size); -#endif - gfunc_call(3); - } -} - -/* t is the array or struct type. c is the array or struct - address. cur_field is the pointer to the current - field, for arrays the 'c' member contains the current start - index. 'size_only' is true if only size info is needed (only used - in arrays). al contains the already initialized length of the - current container (starting at c). This returns the new length of that. */ -static int decl_designator(CType *type, Section *sec, unsigned long c, - Sym **cur_field, int size_only, int al) -{ - Sym *s, *f; - int index, index_last, align, l, nb_elems, elem_size; - unsigned long corig = c; - - elem_size = 0; - nb_elems = 1; - if (gnu_ext && (l = is_label()) != 0) - goto struct_field; - /* NOTE: we only support ranges for last designator */ - while (nb_elems == 1 && (tok == '[' || tok == '.')) { - if (tok == '[') { - if (!(type->t & VT_ARRAY)) - expect("array type"); - next(); - index = index_last = expr_const(); - if (tok == TOK_DOTS && gnu_ext) { - next(); - index_last = expr_const(); - } - skip(']'); - s = type->ref; - if (index < 0 || (s->c >= 0 && index_last >= s->c) || - index_last < index) - tcc_error("invalid index"); - if (cur_field) - (*cur_field)->c = index_last; - type = pointed_type(type); - elem_size = type_size(type, &align); - c += index * elem_size; - nb_elems = index_last - index + 1; - } else { - next(); - l = tok; - struct_field: - next(); - if ((type->t & VT_BTYPE) != VT_STRUCT) - expect("struct/union type"); - f = find_field(type, l); - if (!f) - expect("field"); - if (cur_field) - *cur_field = f; - type = &f->type; - c += f->c; - } - cur_field = NULL; - } - if (!cur_field) { - if (tok == '=') { - next(); - } else if (!gnu_ext) { - expect("="); - } - } else { - if (type->t & VT_ARRAY) { - index = (*cur_field)->c; - if (type->ref->c >= 0 && index >= type->ref->c) - tcc_error("index too large"); - type = pointed_type(type); - c += index * type_size(type, &align); - } else { - f = *cur_field; - while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD)) - *cur_field = f = f->next; - if (!f) - tcc_error("too many field init"); - type = &f->type; - c += f->c; - } - } - /* must put zero in holes (note that doing it that way - ensures that it even works with designators) */ - if (!size_only && c - corig > al) - init_putz(sec, corig + al, c - corig - al); - decl_initializer(type, sec, c, 0, size_only); - - /* XXX: make it more general */ - if (!size_only && nb_elems > 1) { - unsigned long c_end; - uint8_t *src, *dst; - int i; - - if (!sec) { - vset(type, VT_LOCAL|VT_LVAL, c); - for (i = 1; i < nb_elems; i++) { - vset(type, VT_LOCAL|VT_LVAL, c + elem_size * i); - vswap(); - vstore(); - } - vpop(); - } else if (!NODATA_WANTED) { - c_end = c + nb_elems * elem_size; - if (c_end > sec->data_allocated) - section_realloc(sec, c_end); - src = sec->data + c; - dst = src; - for(i = 1; i < nb_elems; i++) { - dst += elem_size; - memcpy(dst, src, elem_size); - } - } - } - c += nb_elems * type_size(type, &align); - if (c - corig > al) - al = c - corig; - return al; -} - -/* store a value or an expression directly in global data or in local array */ -static void init_putv(CType *type, Section *sec, unsigned long c) -{ - int bt; - void *ptr; - CType dtype; - - dtype = *type; - dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ - - if (sec) { - int size, align; - /* XXX: not portable */ - /* XXX: generate error if incorrect relocation */ - gen_assign_cast(&dtype); - bt = type->t & VT_BTYPE; - - if ((vtop->r & VT_SYM) - && bt != VT_PTR - && bt != VT_FUNC - && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT) - || (type->t & VT_BITFIELD)) - && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM) - ) - tcc_error("initializer element is not computable at load time"); - - if (NODATA_WANTED) { - vtop--; - return; - } - - size = type_size(type, &align); - section_reserve(sec, c + size); - ptr = sec->data + c; - - /* XXX: make code faster ? */ - if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) && - vtop->sym->v >= SYM_FIRST_ANOM && - /* XXX This rejects compound literals like - '(void *){ptr}'. The problem is that '&sym' is - represented the same way, which would be ruled out - by the SYM_FIRST_ANOM check above, but also '"string"' - in 'char *p = "string"' is represented the same - with the type being VT_PTR and the symbol being an - anonymous one. That is, there's no difference in vtop - between '(void *){x}' and '&(void *){x}'. Ignore - pointer typed entities here. Hopefully no real code - will every use compound literals with scalar type. */ - (vtop->type.t & VT_BTYPE) != VT_PTR) { - /* These come from compound literals, memcpy stuff over. */ - Section *ssec; - ElfW(Sym) *esym; - ElfW_Rel *rel; - esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c]; - ssec = tcc_state->sections[esym->st_shndx]; - memmove (ptr, ssec->data + esym->st_value, size); - if (ssec->reloc) { - /* We need to copy over all memory contents, and that - includes relocations. Use the fact that relocs are - created it order, so look from the end of relocs - until we hit one before the copied region. */ - int num_relocs = ssec->reloc->data_offset / sizeof(*rel); - rel = (ElfW_Rel*)(ssec->reloc->data + ssec->reloc->data_offset); - while (num_relocs--) { - rel--; - if (rel->r_offset >= esym->st_value + size) - continue; - if (rel->r_offset < esym->st_value) - break; - /* Note: if the same fields are initialized multiple - times (possible with designators) then we possibly - add multiple relocations for the same offset here. - That would lead to wrong code, the last reloc needs - to win. We clean this up later after the whole - initializer is parsed. */ - put_elf_reloca(symtab_section, sec, - c + rel->r_offset - esym->st_value, - ELFW(R_TYPE)(rel->r_info), - ELFW(R_SYM)(rel->r_info), -#if PTR_SIZE == 8 - rel->r_addend -#else - 0 -#endif - ); - } - } - } else { - if (type->t & VT_BITFIELD) { - int bit_pos, bit_size, bits, n; - unsigned char *p, v, m; - bit_pos = BIT_POS(vtop->type.t); - bit_size = BIT_SIZE(vtop->type.t); - p = (unsigned char*)ptr + (bit_pos >> 3); - bit_pos &= 7, bits = 0; - while (bit_size) { - n = 8 - bit_pos; - if (n > bit_size) - n = bit_size; - v = vtop->c.i >> bits << bit_pos; - m = ((1 << n) - 1) << bit_pos; - *p = (*p & ~m) | (v & m); - bits += n, bit_size -= n, bit_pos = 0, ++p; - } - } else - switch(bt) { - /* XXX: when cross-compiling we assume that each type has the - same representation on host and target, which is likely to - be wrong in the case of long double */ - case VT_BOOL: - vtop->c.i = vtop->c.i != 0; - case VT_BYTE: - *(char *)ptr |= vtop->c.i; - break; - case VT_SHORT: - *(short *)ptr |= vtop->c.i; - break; - case VT_FLOAT: - *(float*)ptr = vtop->c.f; - break; - case VT_DOUBLE: - *(double *)ptr = vtop->c.d; - break; - case VT_LDOUBLE: -#if defined TCC_IS_NATIVE_387 - if (sizeof (long double) >= 10) /* zero pad ten-byte LD */ - memcpy(ptr, &vtop->c.ld, 10); -#ifdef __TINYC__ - else if (sizeof (long double) == sizeof (double)) - __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld)); -#endif - else -#endif - if (sizeof(long double) == LDOUBLE_SIZE) - *(long double*)ptr = vtop->c.ld; - else if (sizeof(double) == LDOUBLE_SIZE) - *(double *)ptr = (double)vtop->c.ld; - else - tcc_error("can't cross compile long double constants"); - break; -#if PTR_SIZE != 8 - case VT_LLONG: - *(long long *)ptr |= vtop->c.i; - break; -#else - case VT_LLONG: -#endif - case VT_PTR: - { - addr_t val = vtop->c.i; -#if PTR_SIZE == 8 - if (vtop->r & VT_SYM) - greloca(sec, vtop->sym, c, R_DATA_PTR, val); - else - *(addr_t *)ptr |= val; -#else - if (vtop->r & VT_SYM) - greloc(sec, vtop->sym, c, R_DATA_PTR); - *(addr_t *)ptr |= val; -#endif - break; - } - default: - { - int val = vtop->c.i; -#if PTR_SIZE == 8 - if (vtop->r & VT_SYM) - greloca(sec, vtop->sym, c, R_DATA_PTR, val); - else - *(int *)ptr |= val; -#else - if (vtop->r & VT_SYM) - greloc(sec, vtop->sym, c, R_DATA_PTR); - *(int *)ptr |= val; -#endif - break; - } - } - } - vtop--; - } else { - vset(&dtype, VT_LOCAL|VT_LVAL, c); - vswap(); - vstore(); - vpop(); - } -} - -/* 't' contains the type and storage info. 'c' is the offset of the - object in section 'sec'. If 'sec' is NULL, it means stack based - allocation. 'first' is true if array '{' must be read (multi - dimension implicit array init handling). 'size_only' is true if - size only evaluation is wanted (only for arrays). */ -static void decl_initializer(CType *type, Section *sec, unsigned long c, - int first, int size_only) -{ - int len, n, no_oblock, nb, i; - int size1, align1; - int have_elem; - Sym *s, *f; - Sym indexsym; - CType *t1; - - /* If we currently are at an '}' or ',' we have read an initializer - element in one of our callers, and not yet consumed it. */ - have_elem = tok == '}' || tok == ','; - if (!have_elem && tok != '{' && - /* In case of strings we have special handling for arrays, so - don't consume them as initializer value (which would commit them - to some anonymous symbol). */ - tok != TOK_LSTR && tok != TOK_STR && - !size_only) { - parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST); - have_elem = 1; - } - - if (have_elem && - !(type->t & VT_ARRAY) && - /* Use i_c_parameter_t, to strip toplevel qualifiers. - The source type might have VT_CONSTANT set, which is - of course assignable to non-const elements. */ - is_compatible_unqualified_types(type, &vtop->type)) { - init_putv(type, sec, c); - } else if (type->t & VT_ARRAY) { - s = type->ref; - n = s->c; - t1 = pointed_type(type); - size1 = type_size(t1, &align1); - - no_oblock = 1; - if ((first && tok != TOK_LSTR && tok != TOK_STR) || - tok == '{') { - if (tok != '{') - tcc_error("character array initializer must be a literal," - " optionally enclosed in braces"); - skip('{'); - no_oblock = 0; - } - - /* only parse strings here if correct type (otherwise: handle - them as ((w)char *) expressions */ - if ((tok == TOK_LSTR && -#ifdef TCC_TARGET_PE - (t1->t & VT_BTYPE) == VT_SHORT && (t1->t & VT_UNSIGNED) -#else - (t1->t & VT_BTYPE) == VT_INT -#endif - ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) { - len = 0; - while (tok == TOK_STR || tok == TOK_LSTR) { - int cstr_len, ch; - - /* compute maximum number of chars wanted */ - if (tok == TOK_STR) - cstr_len = tokc.str.size; - else - cstr_len = tokc.str.size / sizeof(nwchar_t); - cstr_len--; - nb = cstr_len; - if (n >= 0 && nb > (n - len)) - nb = n - len; - if (!size_only) { - if (cstr_len > nb) - tcc_warning("initializer-string for array is too long"); - /* in order to go faster for common case (char - string in global variable, we handle it - specifically */ - if (sec && tok == TOK_STR && size1 == 1) { - if (!NODATA_WANTED) - memcpy(sec->data + c + len, tokc.str.data, nb); - } else { - for(i=0;it & VT_ARRAY) { - ++indexsym.c; - /* special test for multi dimensional arrays (may not - be strictly correct if designators are used at the - same time) */ - if (no_oblock && len >= n*size1) - break; - } else { - if (s->type.t == VT_UNION) - f = NULL; - else - f = f->next; - if (no_oblock && f == NULL) - break; - } - - if (tok == '}') - break; - skip(','); - } - } - /* put zeros at the end */ - if (!size_only && len < n*size1) - init_putz(sec, c + len, n*size1 - len); - if (!no_oblock) - skip('}'); - /* patch type size if needed, which happens only for array types */ - if (n < 0) - s->c = size1 == 1 ? len : ((len + size1 - 1)/size1); - } else if ((type->t & VT_BTYPE) == VT_STRUCT) { - size1 = 1; - no_oblock = 1; - if (first || tok == '{') { - skip('{'); - no_oblock = 0; - } - s = type->ref; - f = s->next; - n = s->c; - goto do_init_list; - } else if (tok == '{') { - next(); - decl_initializer(type, sec, c, first, size_only); - skip('}'); - } else if (size_only) { - /* If we supported only ISO C we wouldn't have to accept calling - this on anything than an array size_only==1 (and even then - only on the outermost level, so no recursion would be needed), - because initializing a flex array member isn't supported. - But GNU C supports it, so we need to recurse even into - subfields of structs and arrays when size_only is set. */ - /* just skip expression */ - skip_or_save_block(NULL); - } else { - if (!have_elem) { - /* This should happen only when we haven't parsed - the init element above for fear of committing a - string constant to memory too early. */ - if (tok != TOK_STR && tok != TOK_LSTR) - expect("string constant"); - parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST); - } - init_putv(type, sec, c); - } -} - -/* parse an initializer for type 't' if 'has_init' is non zero, and - allocate space in local or global data space ('r' is either - VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated - variable 'v' of scope 'scope' is declared before initializers - are parsed. If 'v' is zero, then a reference to the new object - is put in the value stack. If 'has_init' is 2, a special parsing - is done to handle string constants. */ -static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, - int has_init, int v, int scope) -{ - int size, align, addr; - TokenString *init_str = NULL; - - Section *sec; - Sym *flexible_array; - Sym *sym = NULL; - int saved_nocode_wanted = nocode_wanted; -#ifdef CONFIG_TCC_BCHECK - int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED; -#endif - - if (type->t & VT_STATIC) - nocode_wanted |= NODATA_WANTED ? 0x40000000 : 0x80000000; - - flexible_array = NULL; - if ((type->t & VT_BTYPE) == VT_STRUCT) { - Sym *field = type->ref->next; - if (field) { - while (field->next) - field = field->next; - if (field->type.t & VT_ARRAY && field->type.ref->c < 0) - flexible_array = field; - } - } - - size = type_size(type, &align); - /* If unknown size, we must evaluate it before - evaluating initializers because - initializers can generate global data too - (e.g. string pointers or ISOC99 compound - literals). It also simplifies local - initializers handling */ - if (size < 0 || (flexible_array && has_init)) { - if (!has_init) - tcc_error("unknown type size"); - /* get all init string */ - if (has_init == 2) { - init_str = tok_str_alloc(); - /* only get strings */ - while (tok == TOK_STR || tok == TOK_LSTR) { - tok_str_add_tok(init_str); - next(); - } - tok_str_add(init_str, -1); - tok_str_add(init_str, 0); - } else { - skip_or_save_block(&init_str); - } - unget_tok(0); - - /* compute size */ - begin_macro(init_str, 1); - next(); - decl_initializer(type, NULL, 0, 1, 1); - /* prepare second initializer parsing */ - macro_ptr = init_str->str; - next(); - - /* if still unknown size, error */ - size = type_size(type, &align); - if (size < 0) - tcc_error("unknown type size"); - } - /* If there's a flex member and it was used in the initializer - adjust size. */ - if (flexible_array && - flexible_array->type.ref->c > 0) - size += flexible_array->type.ref->c - * pointed_size(&flexible_array->type); - /* take into account specified alignment if bigger */ - if (ad->a.aligned) { - int speca = 1 << (ad->a.aligned - 1); - if (speca > align) - align = speca; - } else if (ad->a.packed) { - align = 1; - } - - if (NODATA_WANTED) - size = 0, align = 1; - - if ((r & VT_VALMASK) == VT_LOCAL) { - sec = NULL; -#ifdef CONFIG_TCC_BCHECK - if (bcheck && (type->t & VT_ARRAY)) { - loc--; - } -#endif - loc = (loc - size) & -align; - addr = loc; -#ifdef CONFIG_TCC_BCHECK - /* handles bounds */ - /* XXX: currently, since we do only one pass, we cannot track - '&' operators, so we add only arrays */ - if (bcheck && (type->t & VT_ARRAY)) { - addr_t *bounds_ptr; - /* add padding between regions */ - loc--; - /* then add local bound info */ - bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t)); - bounds_ptr[0] = addr; - bounds_ptr[1] = size; - } -#endif - if (v) { - /* local variable */ -#ifdef CONFIG_TCC_ASM - if (ad->asm_label) { - int reg = asm_parse_regvar(ad->asm_label); - if (reg >= 0) - r = (r & ~VT_VALMASK) | reg; - } -#endif - sym = sym_push(v, type, r, addr); - sym->a = ad->a; - } else { - /* push local reference */ - vset(type, r, addr); - } - } else { - if (v && scope == VT_CONST) { - /* see if the symbol was already defined */ - sym = sym_find(v); - if (sym) { - patch_storage(sym, ad, type); - if (sym->type.t & VT_EXTERN) { - /* if the variable is extern, it was not allocated */ - sym->type.t &= ~VT_EXTERN; - /* set array size if it was omitted in extern - declaration */ - if ((sym->type.t & VT_ARRAY) && - sym->type.ref->c < 0 && - type->ref->c >= 0) - sym->type.ref->c = type->ref->c; - } else if (!has_init) { - /* we accept several definitions of the same - global variable. this is tricky, because we - must play with the SHN_COMMON type of the symbol */ - /* no init data, we won't add more to the symbol */ - goto no_alloc; - } else if (sym->c) { - ElfW(Sym) *esym; - esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; - if (esym->st_shndx == data_section->sh_num) - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - } - } - } - - /* allocate symbol in corresponding section */ - sec = ad->section; - if (!sec) { - if (has_init) - sec = data_section; - else if (tcc_state->nocommon) - sec = bss_section; - } - - if (sec) { - addr = section_add(sec, size, align); -#ifdef CONFIG_TCC_BCHECK - /* add padding if bound check */ - if (bcheck) - section_add(sec, 1, 1); -#endif - } else { - addr = align; /* SHN_COMMON is special, symbol value is align */ - sec = common_section; - } - - if (v) { - if (!sym) { - sym = sym_push(v, type, r | VT_SYM, 0); - patch_storage(sym, ad, NULL); - } - /* Local statics have a scope until now (for - warnings), remove it here. */ - sym->sym_scope = 0; - /* update symbol definition */ - put_extern_sym(sym, sec, addr, size); - } else { - /* push global reference */ - sym = get_sym_ref(type, sec, addr, size); - vpushsym(type, sym); - vtop->r |= r; - } - -#ifdef CONFIG_TCC_BCHECK - /* handles bounds now because the symbol must be defined - before for the relocation */ - if (bcheck) { - addr_t *bounds_ptr; - - greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0); - /* then add global bound info */ - bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t)); - bounds_ptr[0] = 0; /* relocated */ - bounds_ptr[1] = size; - } -#endif - } - - if (type->t & VT_VLA) { - int a; - - if (NODATA_WANTED) - goto no_alloc; - - /* save current stack pointer */ - if (vlas_in_scope == 0) { - if (vla_sp_root_loc == -1) - vla_sp_root_loc = (loc -= PTR_SIZE); - gen_vla_sp_save(vla_sp_root_loc); - } - - vla_runtime_type_size(type, &a); - gen_vla_alloc(type, a); - gen_vla_sp_save(addr); - vla_sp_loc = addr; - vlas_in_scope++; - - } else if (has_init) { - size_t oldreloc_offset = 0; - if (sec && sec->reloc) - oldreloc_offset = sec->reloc->data_offset; - decl_initializer(type, sec, addr, 1, 0); - if (sec && sec->reloc) - squeeze_multi_relocs(sec, oldreloc_offset); - /* patch flexible array member size back to -1, */ - /* for possible subsequent similar declarations */ - if (flexible_array) - flexible_array->type.ref->c = -1; - } - - no_alloc: - /* restore parse state if needed */ - if (init_str) { - end_macro(); - next(); - } - - nocode_wanted = saved_nocode_wanted; -} - -/* parse a function defined by symbol 'sym' and generate its code in - 'cur_text_section' */ -static void gen_function(Sym *sym) -{ - nocode_wanted = 0; - ind = cur_text_section->data_offset; - /* NOTE: we patch the symbol size later */ - put_extern_sym(sym, cur_text_section, ind, 0); - funcname = get_tok_str(sym->v, NULL); - func_ind = ind; - /* Initialize VLA state */ - vla_sp_loc = -1; - vla_sp_root_loc = -1; - /* put debug symbol */ - tcc_debug_funcstart(tcc_state, sym); - /* push a dummy symbol to enable local sym storage */ - sym_push2(&local_stack, SYM_FIELD, 0, 0); - local_scope = 1; /* for function parameters */ - gfunc_prolog(&sym->type); - local_scope = 0; - rsym = 0; - block(NULL, NULL, 0); - nocode_wanted = 0; - gsym(rsym); - gfunc_epilog(); - cur_text_section->data_offset = ind; - label_pop(&global_label_stack, NULL, 0); - /* reset local stack */ - local_scope = 0; - sym_pop(&local_stack, NULL, 0); - /* end of function */ - /* patch symbol size */ - ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = - ind - func_ind; - tcc_debug_funcend(tcc_state, ind - func_ind); - /* It's better to crash than to generate wrong code */ - cur_text_section = NULL; - funcname = ""; /* for safety */ - func_vt.t = VT_VOID; /* for safety */ - func_var = 0; /* for safety */ - ind = 0; /* for safety */ - nocode_wanted = 0x80000000; - check_vstack(); -} - -static void gen_inline_functions(TCCState *s) -{ - Sym *sym; - int inline_generated, i, ln; - struct InlineFunc *fn; - - ln = file->line_num; - /* iterate while inline function are referenced */ - do { - inline_generated = 0; - for (i = 0; i < s->nb_inline_fns; ++i) { - fn = s->inline_fns[i]; - sym = fn->sym; - if (sym && sym->c) { - /* the function was used: generate its code and - convert it to a normal function */ - fn->sym = NULL; - if (file) - pstrcpy(file->filename, sizeof file->filename, fn->filename); - sym->type.t &= ~VT_INLINE; - - begin_macro(fn->func_str, 1); - next(); - cur_text_section = text_section; - gen_function(sym); - end_macro(); - - inline_generated = 1; - } - } - } while (inline_generated); - file->line_num = ln; -} - -ST_FUNC void free_inline_functions(TCCState *s) -{ - int i; - /* free tokens of unused inline functions */ - for (i = 0; i < s->nb_inline_fns; ++i) { - struct InlineFunc *fn = s->inline_fns[i]; - if (fn->sym) - tok_str_free(fn->func_str); - } - dynarray_reset(&s->inline_fns, &s->nb_inline_fns); -} - -/* 'l' is VT_LOCAL or VT_CONST to define default storage type, or VT_CMP - if parsing old style parameter decl list (and FUNC_SYM is set then) */ -static int decl0(int l, int is_for_loop_init, Sym *func_sym) -{ - int v, has_init, r; - CType type, btype; - Sym *sym; - AttributeDef ad; - - while (1) { - if (!parse_btype(&btype, &ad)) { - if (is_for_loop_init) - return 0; - /* skip redundant ';' if not in old parameter decl scope */ - if (tok == ';' && l != VT_CMP) { - next(); - continue; - } - if (l != VT_CONST) - break; - if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { - /* global asm block */ - asm_global_instr(); - continue; - } - if (tok >= TOK_UIDENT) { - /* special test for old K&R protos without explicit int - type. Only accepted when defining global data */ - btype.t = VT_INT; - } else { - if (tok != TOK_EOF) - expect("declaration"); - break; - } - } - if (tok == ';') { - if ((btype.t & VT_BTYPE) == VT_STRUCT) { - int v = btype.ref->v; - if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) - tcc_warning("unnamed struct/union that defines no instances"); - next(); - continue; - } - if (IS_ENUM(btype.t)) { - next(); - continue; - } - } - while (1) { /* iterate thru each declaration */ - type = btype; - /* If the base type itself was an array type of unspecified - size (like in 'typedef int arr[]; arr x = {1};') then - we will overwrite the unknown size by the real one for - this decl. We need to unshare the ref symbol holding - that size. */ - if ((type.t & VT_ARRAY) && type.ref->c < 0) { - type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c); - } - type_decl(&type, &ad, &v, TYPE_DIRECT); -#if 0 - { - char buf[500]; - type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL)); - printf("type = '%s'\n", buf); - } -#endif - if ((type.t & VT_BTYPE) == VT_FUNC) { - if ((type.t & VT_STATIC) && (l == VT_LOCAL)) { - tcc_error("function without file scope cannot be static"); - } - /* if old style function prototype, we accept a - declaration list */ - sym = type.ref; - if (sym->f.func_type == FUNC_OLD && l == VT_CONST) - decl0(VT_CMP, 0, sym); - } - - if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { - ad.asm_label = asm_label_instr(); - /* parse one last attribute list, after asm label */ - parse_attribute(&ad); - if (tok == '{') - expect(";"); - } - -#ifdef TCC_TARGET_PE - if (ad.a.dllimport || ad.a.dllexport) { - if (type.t & (VT_STATIC|VT_TYPEDEF)) - tcc_error("cannot have dll linkage with static or typedef"); - if (ad.a.dllimport) { - if ((type.t & VT_BTYPE) == VT_FUNC) - ad.a.dllimport = 0; - else - type.t |= VT_EXTERN; - } - } -#endif - if (tok == '{') { - if (l != VT_CONST) - tcc_error("cannot use local functions"); - if ((type.t & VT_BTYPE) != VT_FUNC) - expect("function definition"); - - /* reject abstract declarators in function definition - make old style params without decl have int type */ - sym = type.ref; - while ((sym = sym->next) != NULL) { - if (!(sym->v & ~SYM_FIELD)) - expect("identifier"); - if (sym->type.t == VT_VOID) - sym->type = int_type; - } - - /* XXX: cannot do better now: convert extern line to static inline */ - if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) - type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - - sym = sym_find(v); - if (sym) { - Sym *ref; - if ((sym->type.t & VT_BTYPE) != VT_FUNC) - goto func_error1; - - ref = sym->type.ref; - - /* use func_call from prototype if not defined */ - if (ref->f.func_call != FUNC_CDECL - && type.ref->f.func_call == FUNC_CDECL) - type.ref->f.func_call = ref->f.func_call; - - /* use static from prototype */ - if (sym->type.t & VT_STATIC) - type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - - /* If the definition has no visibility use the - one from prototype. */ - if (!type.ref->a.visibility) - type.ref->a.visibility = ref->a.visibility; - /* apply other storage attributes from prototype */ - type.ref->a.dllexport |= ref->a.dllexport; - type.ref->a.weak |= ref->a.weak; - - if (!is_compatible_types(&sym->type, &type)) { - func_error1: - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); - } - if (ref->f.func_body) - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - /* if symbol is already defined, then put complete type */ - sym->type = type; - - } else { - /* put function symbol */ - sym = global_identifier_push(v, type.t, 0); - sym->type.ref = type.ref; - } - - sym->type.ref->f.func_body = 1; - sym->r = VT_SYM | VT_CONST; - patch_storage(sym, &ad, NULL); - - /* static inline functions are just recorded as a kind - of macro. Their code will be emitted at the end of - the compilation unit only if they are used */ - if ((type.t & (VT_INLINE | VT_STATIC)) == - (VT_INLINE | VT_STATIC)) { - struct InlineFunc *fn; - const char *filename; - - filename = file ? file->filename : ""; - fn = tcc_malloc(sizeof *fn + strlen(filename)); - strcpy(fn->filename, filename); - fn->sym = sym; - skip_or_save_block(&fn->func_str); - dynarray_add(&tcc_state->inline_fns, - &tcc_state->nb_inline_fns, fn); - } else { - /* compute text section */ - cur_text_section = ad.section; - if (!cur_text_section) - cur_text_section = text_section; - gen_function(sym); - } - break; - } else { - if (l == VT_CMP) { - /* find parameter in function parameter list */ - for (sym = func_sym->next; sym; sym = sym->next) - if ((sym->v & ~SYM_FIELD) == v) - goto found; - tcc_error("declaration for parameter '%s' but no such parameter", - get_tok_str(v, NULL)); -found: - if (type.t & VT_STORAGE) /* 'register' is okay */ - tcc_error("storage class specified for '%s'", - get_tok_str(v, NULL)); - if (sym->type.t != VT_VOID) - tcc_error("redefinition of parameter '%s'", - get_tok_str(v, NULL)); - convert_parameter_type(&type); - sym->type = type; - } else if (type.t & VT_TYPEDEF) { - /* save typedefed type */ - /* XXX: test storage specifiers ? */ - sym = sym_find(v); - if (sym && sym->sym_scope == local_scope) { - if (!is_compatible_types(&sym->type, &type) - || !(sym->type.t & VT_TYPEDEF)) - tcc_error("incompatible redefinition of '%s'", - get_tok_str(v, NULL)); - sym->type = type; - } else { - sym = sym_push(v, &type, 0, 0); - } - sym->a = ad.a; - sym->f = ad.f; - } else { - r = 0; - if ((type.t & VT_BTYPE) == VT_FUNC) { - /* external function definition */ - /* specific case for func_call attribute */ - type.ref->f = ad.f; - } else if (!(type.t & VT_ARRAY)) { - /* not lvalue if array */ - r |= lvalue_type(type.t); - } - has_init = (tok == '='); - if (has_init && (type.t & VT_VLA)) - tcc_error("variable length array cannot be initialized"); - if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) || - ((type.t & VT_BTYPE) == VT_FUNC) || - ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && - !has_init && l == VT_CONST && type.ref->c < 0)) { - /* external variable or function */ - /* NOTE: as GCC, uninitialized global static - arrays of null size are considered as - extern */ - sym = external_sym(v, &type, r, &ad); - if (ad.alias_target) { - Section tsec; - ElfW(Sym) *esym; - Sym *alias_target; - alias_target = sym_find(ad.alias_target); - if (!alias_target || !alias_target->c) - tcc_error("unsupported forward __alias__ attribute"); - esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c]; - tsec.sh_num = esym->st_shndx; - /* Local statics have a scope until now (for - warnings), remove it here. */ - sym->sym_scope = 0; - put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0); - } - } else { - if (type.t & VT_STATIC) - r |= VT_CONST; - else - r |= l; - if (has_init) - next(); - decl_initializer_alloc(&type, &ad, r, has_init, v, l); - } - } - if (tok != ',') { - if (is_for_loop_init) - return 1; - skip(';'); - break; - } - next(); - } - ad.a.aligned = 0; - } - } - return 0; -} - -static void decl(int l) -{ - decl0(l, 0, NULL); -} - -/* ------------------------------------------------------------------------- */ diff --git a/tinyc/tcclib.h b/tinyc/tcclib.h deleted file mode 100644 index 8d59e4c9a..000000000 --- a/tinyc/tcclib.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Simple libc header for TCC - * - * Add any function you want from the libc there. This file is here - * only for your convenience so that you do not need to put the whole - * glibc include files on your floppy disk - */ -#ifndef _TCCLIB_H -#define _TCCLIB_H - -#include -#include - -/* stdlib.h */ -void *calloc(size_t nmemb, size_t size); -void *malloc(size_t size); -void free(void *ptr); -void *realloc(void *ptr, size_t size); -int atoi(const char *nptr); -long int strtol(const char *nptr, char **endptr, int base); -unsigned long int strtoul(const char *nptr, char **endptr, int base); -void exit(int); - -/* stdio.h */ -typedef struct __FILE FILE; -#define EOF (-1) -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; -FILE *fopen(const char *path, const char *mode); -FILE *fdopen(int fildes, const char *mode); -FILE *freopen(const char *path, const char *mode, FILE *stream); -int fclose(FILE *stream); -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); -size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); -int fgetc(FILE *stream); -char *fgets(char *s, int size, FILE *stream); -int getc(FILE *stream); -int getchar(void); -char *gets(char *s); -int ungetc(int c, FILE *stream); -int fflush(FILE *stream); -int putchar (int c); - -int printf(const char *format, ...); -int fprintf(FILE *stream, const char *format, ...); -int sprintf(char *str, const char *format, ...); -int snprintf(char *str, size_t size, const char *format, ...); -int asprintf(char **strp, const char *format, ...); -int dprintf(int fd, const char *format, ...); -int vprintf(const char *format, va_list ap); -int vfprintf(FILE *stream, const char *format, va_list ap); -int vsprintf(char *str, const char *format, va_list ap); -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -int vasprintf(char **strp, const char *format, va_list ap); -int vdprintf(int fd, const char *format, va_list ap); - -void perror(const char *s); - -/* string.h */ -char *strcat(char *dest, const char *src); -char *strchr(const char *s, int c); -char *strrchr(const char *s, int c); -char *strcpy(char *dest, const char *src); -void *memcpy(void *dest, const void *src, size_t n); -void *memmove(void *dest, const void *src, size_t n); -void *memset(void *s, int c, size_t n); -char *strdup(const char *s); -size_t strlen(const char *s); - -/* dlfcn.h */ -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 - -void *dlopen(const char *filename, int flag); -const char *dlerror(void); -void *dlsym(void *handle, char *symbol); -int dlclose(void *handle); - -#endif /* _TCCLIB_H */ diff --git a/tinyc/tccpe.c b/tinyc/tccpe.c deleted file mode 100644 index a67023dd2..000000000 --- a/tinyc/tccpe.c +++ /dev/null @@ -1,2014 +0,0 @@ -/* - * TCCPE.C - PE file output for the Tiny C Compiler - * - * Copyright (c) 2005-2007 grischka - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -#define PE_MERGE_DATA -/* #define PE_PRINT_SECTIONS */ - -#ifndef _WIN32 -#define stricmp strcasecmp -#define strnicmp strncasecmp -#include /* chmod() */ -#endif - -#ifdef TCC_TARGET_X86_64 -# define ADDR3264 ULONGLONG -# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 -# define REL_TYPE_DIRECT R_X86_64_64 -# define R_XXX_THUNKFIX R_X86_64_PC32 -# define R_XXX_RELATIVE R_X86_64_RELATIVE -# define IMAGE_FILE_MACHINE 0x8664 -# define RSRC_RELTYPE 3 - -#elif defined TCC_TARGET_ARM -# define ADDR3264 DWORD -# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW -# define REL_TYPE_DIRECT R_ARM_ABS32 -# define R_XXX_THUNKFIX R_ARM_ABS32 -# define R_XXX_RELATIVE R_ARM_RELATIVE -# define IMAGE_FILE_MACHINE 0x01C0 -# define RSRC_RELTYPE 7 /* ??? (not tested) */ - -#elif defined TCC_TARGET_I386 -# define ADDR3264 DWORD -# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW -# define REL_TYPE_DIRECT R_386_32 -# define R_XXX_THUNKFIX R_386_32 -# define R_XXX_RELATIVE R_386_RELATIVE -# define IMAGE_FILE_MACHINE 0x014C -# define RSRC_RELTYPE 7 /* DIR32NB */ - -#endif - -#ifndef IMAGE_NT_SIGNATURE -/* ----------------------------------------------------------- */ -/* definitions below are from winnt.h */ - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned int DWORD; -typedef unsigned long long ULONGLONG; -#pragma pack(push, 1) - -typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ - WORD e_magic; /* Magic number */ - WORD e_cblp; /* Bytes on last page of file */ - WORD e_cp; /* Pages in file */ - WORD e_crlc; /* Relocations */ - WORD e_cparhdr; /* Size of header in paragraphs */ - WORD e_minalloc; /* Minimum extra paragraphs needed */ - WORD e_maxalloc; /* Maximum extra paragraphs needed */ - WORD e_ss; /* Initial (relative) SS value */ - WORD e_sp; /* Initial SP value */ - WORD e_csum; /* Checksum */ - WORD e_ip; /* Initial IP value */ - WORD e_cs; /* Initial (relative) CS value */ - WORD e_lfarlc; /* File address of relocation table */ - WORD e_ovno; /* Overlay number */ - WORD e_res[4]; /* Reserved words */ - WORD e_oemid; /* OEM identifier (for e_oeminfo) */ - WORD e_oeminfo; /* OEM information; e_oemid specific */ - WORD e_res2[10]; /* Reserved words */ - DWORD e_lfanew; /* File address of new exe header */ -} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; - -#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ -#define SIZE_OF_NT_SIGNATURE 4 - -typedef struct _IMAGE_FILE_HEADER { - WORD Machine; - WORD NumberOfSections; - DWORD TimeDateStamp; - DWORD PointerToSymbolTable; - DWORD NumberOfSymbols; - WORD SizeOfOptionalHeader; - WORD Characteristics; -} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; - - -#define IMAGE_SIZEOF_FILE_HEADER 20 - -typedef struct _IMAGE_DATA_DIRECTORY { - DWORD VirtualAddress; - DWORD Size; -} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; - - -typedef struct _IMAGE_OPTIONAL_HEADER { - /* Standard fields. */ - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; -#ifndef TCC_TARGET_X86_64 - DWORD BaseOfData; -#endif - /* NT additional fields. */ - ADDR3264 ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - ADDR3264 SizeOfStackReserve; - ADDR3264 SizeOfStackCommit; - ADDR3264 SizeOfHeapReserve; - ADDR3264 SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[16]; -} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER; - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ -/* IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) */ -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 /* Architecture Specific Data */ -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* RVA of GP */ -#define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ -#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 /* Delay Load Import Descriptors */ -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 /* COM Runtime descriptor */ - -/* Section header format. */ -#define IMAGE_SIZEOF_SHORT_NAME 8 - -typedef struct _IMAGE_SECTION_HEADER { - BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - DWORD PhysicalAddress; - DWORD VirtualSize; - } Misc; - DWORD VirtualAddress; - DWORD SizeOfRawData; - DWORD PointerToRawData; - DWORD PointerToRelocations; - DWORD PointerToLinenumbers; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD Characteristics; -} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -typedef struct _IMAGE_EXPORT_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; - DWORD AddressOfNames; - DWORD AddressOfNameOrdinals; -} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; - -typedef struct _IMAGE_IMPORT_DESCRIPTOR { - union { - DWORD Characteristics; - DWORD OriginalFirstThunk; - }; - DWORD TimeDateStamp; - DWORD ForwarderChain; - DWORD Name; - DWORD FirstThunk; -} IMAGE_IMPORT_DESCRIPTOR; - -typedef struct _IMAGE_BASE_RELOCATION { - DWORD VirtualAddress; - DWORD SizeOfBlock; -// WORD TypeOffset[1]; -} IMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_SECTION 6 -#define IMAGE_REL_BASED_REL32 7 -#define IMAGE_REL_BASED_DIR64 10 - -#pragma pack(pop) - -/* ----------------------------------------------------------- */ -#endif /* ndef IMAGE_NT_SIGNATURE */ -/* ----------------------------------------------------------- */ - -#ifndef IMAGE_REL_BASED_DIR64 -# define IMAGE_REL_BASED_DIR64 10 -#endif - -#pragma pack(push, 1) -struct pe_header -{ - IMAGE_DOS_HEADER doshdr; - BYTE dosstub[0x40]; - DWORD nt_sig; - IMAGE_FILE_HEADER filehdr; -#ifdef TCC_TARGET_X86_64 - IMAGE_OPTIONAL_HEADER64 opthdr; -#else -#ifdef _WIN64 - IMAGE_OPTIONAL_HEADER32 opthdr; -#else - IMAGE_OPTIONAL_HEADER opthdr; -#endif -#endif -}; - -struct pe_reloc_header { - DWORD offset; - DWORD size; -}; - -struct pe_rsrc_header { - struct _IMAGE_FILE_HEADER filehdr; - struct _IMAGE_SECTION_HEADER sectionhdr; -}; - -struct pe_rsrc_reloc { - DWORD offset; - DWORD size; - WORD type; -}; -#pragma pack(pop) - -/* ------------------------------------------------------------- */ -/* internal temporary structures */ - -/* -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_SHARED 0x10000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 -*/ - -enum { - sec_text = 0, - sec_data , - sec_bss , - sec_idata , - sec_pdata , - sec_other , - sec_rsrc , - sec_stab , - sec_reloc , - sec_last -}; - -static const DWORD pe_sec_flags[] = { - 0x60000020, /* ".text" , */ - 0xC0000040, /* ".data" , */ - 0xC0000080, /* ".bss" , */ - 0x40000040, /* ".idata" , */ - 0x40000040, /* ".pdata" , */ - 0xE0000060, /* < other > , */ - 0x40000040, /* ".rsrc" , */ - 0x42000802, /* ".stab" , */ - 0x42000040, /* ".reloc" , */ -}; - -struct section_info { - int cls, ord; - char name[32]; - DWORD sh_addr; - DWORD sh_size; - DWORD sh_flags; - unsigned char *data; - DWORD data_size; - IMAGE_SECTION_HEADER ish; -}; - -struct import_symbol { - int sym_index; - int iat_index; - int thk_offset; -}; - -struct pe_import_info { - int dll_index; - int sym_count; - struct import_symbol **symbols; -}; - -struct pe_info { - TCCState *s1; - Section *reloc; - Section *thunk; - const char *filename; - int type; - DWORD sizeofheaders; - ADDR3264 imagebase; - const char *start_symbol; - DWORD start_addr; - DWORD imp_offs; - DWORD imp_size; - DWORD iat_offs; - DWORD iat_size; - DWORD exp_offs; - DWORD exp_size; - int subsystem; - DWORD section_align; - DWORD file_align; - struct section_info *sec_info; - int sec_count; - struct pe_import_info **imp_info; - int imp_count; -}; - -#define PE_NUL 0 -#define PE_DLL 1 -#define PE_GUI 2 -#define PE_EXE 3 -#define PE_RUN 4 - -/* --------------------------------------------*/ - -static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym) -{ - const char *name = (char*)symtab_section->link->data + sym->st_name; - if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL)) - return name + 1; - return name; -} - -static int pe_find_import(TCCState * s1, ElfW(Sym) *sym) -{ - char buffer[200]; - const char *s, *p; - int sym_index = 0, n = 0; - int a, err = 0; - - do { - s = pe_export_name(s1, sym); - a = 0; - if (n) { - /* second try: */ - if (sym->st_other & ST_PE_STDCALL) { - /* try w/0 stdcall deco (windows API convention) */ - p = strrchr(s, '@'); - if (!p || s[0] != '_') - break; - strcpy(buffer, s+1)[p-s-1] = 0; - } else if (s[0] != '_') { /* try non-ansi function */ - buffer[0] = '_', strcpy(buffer + 1, s); - } else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */ - strcpy(buffer, s + 6), a = 1; - } else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */ - strcpy(buffer, s + 6), a = 1; - } else { - continue; - } - s = buffer; - } - sym_index = find_elf_sym(s1->dynsymtab_section, s); - // printf("find (%d) %d %s\n", n, sym_index, s); - if (sym_index - && ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT - && 0 == (sym->st_other & ST_PE_IMPORT) - && 0 == a - ) err = -1, sym_index = 0; - } while (0 == sym_index && ++n < 2); - return n == 2 ? err : sym_index; -} - -/*----------------------------------------------------------------------------*/ - -static int dynarray_assoc(void **pp, int n, int key) -{ - int i; - for (i = 0; i < n; ++i, ++pp) - if (key == **(int **) pp) - return i; - return -1; -} - -#if 0 -ST_FN DWORD umin(DWORD a, DWORD b) -{ - return a < b ? a : b; -} -#endif - -static DWORD umax(DWORD a, DWORD b) -{ - return a < b ? b : a; -} - -static DWORD pe_file_align(struct pe_info *pe, DWORD n) -{ - return (n + (pe->file_align - 1)) & ~(pe->file_align - 1); -} - -static DWORD pe_virtual_align(struct pe_info *pe, DWORD n) -{ - return (n + (pe->section_align - 1)) & ~(pe->section_align - 1); -} - -static void pe_align_section(Section *s, int a) -{ - int i = s->data_offset & (a-1); - if (i) - section_ptr_add(s, a - i); -} - -static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size) -{ - hdr->opthdr.DataDirectory[dir].VirtualAddress = addr; - hdr->opthdr.DataDirectory[dir].Size = size; -} - -static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum) -{ - if (psum) { - DWORD sum = *psum; - WORD *p = data; - int i; - for (i = len; i > 0; i -= 2) { - sum += (i >= 2) ? *p++ : *(BYTE*)p; - sum = (sum + (sum >> 16)) & 0xFFFF; - } - *psum = sum; - } - return len == fwrite(data, 1, len, fp) ? 0 : -1; -} - -static void pe_fpad(FILE *fp, DWORD new_pos) -{ - DWORD pos = ftell(fp); - while (++pos <= new_pos) - fputc(0, fp); -} - -/*----------------------------------------------------------------------------*/ -static int pe_write(struct pe_info *pe) -{ - static const struct pe_header pe_template = { - { - /* IMAGE_DOS_HEADER doshdr */ - 0x5A4D, /*WORD e_magic; Magic number */ - 0x0090, /*WORD e_cblp; Bytes on last page of file */ - 0x0003, /*WORD e_cp; Pages in file */ - 0x0000, /*WORD e_crlc; Relocations */ - - 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ - 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ - 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ - 0x0000, /*WORD e_ss; Initial (relative) SS value */ - - 0x00B8, /*WORD e_sp; Initial SP value */ - 0x0000, /*WORD e_csum; Checksum */ - 0x0000, /*WORD e_ip; Initial IP value */ - 0x0000, /*WORD e_cs; Initial (relative) CS value */ - 0x0040, /*WORD e_lfarlc; File address of relocation table */ - 0x0000, /*WORD e_ovno; Overlay number */ - {0,0,0,0}, /*WORD e_res[4]; Reserved words */ - 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ - 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ - {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */ - 0x00000080 /*DWORD e_lfanew; File address of new exe header */ - },{ - /* BYTE dosstub[0x40] */ - /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ - 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68, - 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f, - 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20, - 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }, - 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */ - { - /* IMAGE_FILE_HEADER filehdr */ - IMAGE_FILE_MACHINE, /*WORD Machine; */ - 0x0003, /*WORD NumberOfSections; */ - 0x00000000, /*DWORD TimeDateStamp; */ - 0x00000000, /*DWORD PointerToSymbolTable; */ - 0x00000000, /*DWORD NumberOfSymbols; */ -#if defined(TCC_TARGET_X86_64) - 0x00F0, /*WORD SizeOfOptionalHeader; */ - 0x022F /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x222E -#elif defined(TCC_TARGET_I386) - 0x00E0, /*WORD SizeOfOptionalHeader; */ - 0x030F /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x230E -#elif defined(TCC_TARGET_ARM) - 0x00E0, /*WORD SizeOfOptionalHeader; */ - 0x010F, /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x230F -#endif -},{ - /* IMAGE_OPTIONAL_HEADER opthdr */ - /* Standard fields. */ -#ifdef TCC_TARGET_X86_64 - 0x020B, /*WORD Magic; */ -#else - 0x010B, /*WORD Magic; */ -#endif - 0x06, /*BYTE MajorLinkerVersion; */ - 0x00, /*BYTE MinorLinkerVersion; */ - 0x00000000, /*DWORD SizeOfCode; */ - 0x00000000, /*DWORD SizeOfInitializedData; */ - 0x00000000, /*DWORD SizeOfUninitializedData; */ - 0x00000000, /*DWORD AddressOfEntryPoint; */ - 0x00000000, /*DWORD BaseOfCode; */ -#ifndef TCC_TARGET_X86_64 - 0x00000000, /*DWORD BaseOfData; */ -#endif - /* NT additional fields. */ -#if defined(TCC_TARGET_ARM) - 0x00100000, /*DWORD ImageBase; */ -#else - 0x00400000, /*DWORD ImageBase; */ -#endif - 0x00001000, /*DWORD SectionAlignment; */ - 0x00000200, /*DWORD FileAlignment; */ - 0x0004, /*WORD MajorOperatingSystemVersion; */ - 0x0000, /*WORD MinorOperatingSystemVersion; */ - 0x0000, /*WORD MajorImageVersion; */ - 0x0000, /*WORD MinorImageVersion; */ - 0x0004, /*WORD MajorSubsystemVersion; */ - 0x0000, /*WORD MinorSubsystemVersion; */ - 0x00000000, /*DWORD Win32VersionValue; */ - 0x00000000, /*DWORD SizeOfImage; */ - 0x00000200, /*DWORD SizeOfHeaders; */ - 0x00000000, /*DWORD CheckSum; */ - 0x0002, /*WORD Subsystem; */ - 0x0000, /*WORD DllCharacteristics; */ - 0x00100000, /*DWORD SizeOfStackReserve; */ - 0x00001000, /*DWORD SizeOfStackCommit; */ - 0x00100000, /*DWORD SizeOfHeapReserve; */ - 0x00001000, /*DWORD SizeOfHeapCommit; */ - 0x00000000, /*DWORD LoaderFlags; */ - 0x00000010, /*DWORD NumberOfRvaAndSizes; */ - - /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ - {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, - {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} - }}; - - struct pe_header pe_header = pe_template; - - int i; - FILE *op; - DWORD file_offset, sum; - struct section_info *si; - IMAGE_SECTION_HEADER *psh; - - op = fopen(pe->filename, "wb"); - if (NULL == op) { - tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); - return -1; - } - - pe->sizeofheaders = pe_file_align(pe, - sizeof (struct pe_header) - + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) - ); - - file_offset = pe->sizeofheaders; - - if (2 == pe->s1->verbose) - printf("-------------------------------" - "\n virt file size section" "\n"); - for (i = 0; i < pe->sec_count; ++i) { - DWORD addr, size; - const char *sh_name; - - si = pe->sec_info + i; - sh_name = si->name; - addr = si->sh_addr - pe->imagebase; - size = si->sh_size; - psh = &si->ish; - - if (2 == pe->s1->verbose) - printf("%6x %6x %6x %s\n", - (unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name); - - switch (si->cls) { - case sec_text: - pe_header.opthdr.BaseOfCode = addr; - break; - - case sec_data: -#ifndef TCC_TARGET_X86_64 - pe_header.opthdr.BaseOfData = addr; -#endif - break; - - case sec_bss: - break; - - case sec_reloc: - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); - break; - - case sec_rsrc: - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); - break; - - case sec_pdata: - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size); - break; - - case sec_stab: - break; - } - - if (pe->thunk == pe->s1->sections[si->ord]) { - if (pe->imp_size) { - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, - pe->imp_offs + addr, pe->imp_size); - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, - pe->iat_offs + addr, pe->iat_size); - } - if (pe->exp_size) { - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, - pe->exp_offs + addr, pe->exp_size); - } - } - - strncpy((char*)psh->Name, sh_name, sizeof psh->Name); - - psh->Characteristics = pe_sec_flags[si->cls]; - psh->VirtualAddress = addr; - psh->Misc.VirtualSize = size; - pe_header.opthdr.SizeOfImage = - umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage); - - if (si->data_size) { - psh->PointerToRawData = file_offset; - file_offset = pe_file_align(pe, file_offset + si->data_size); - psh->SizeOfRawData = file_offset - psh->PointerToRawData; - if (si->cls == sec_text) - pe_header.opthdr.SizeOfCode += psh->SizeOfRawData; - else - pe_header.opthdr.SizeOfInitializedData += psh->SizeOfRawData; - } - } - - //pe_header.filehdr.TimeDateStamp = time(NULL); - pe_header.filehdr.NumberOfSections = pe->sec_count; - pe_header.opthdr.AddressOfEntryPoint = pe->start_addr; - pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; - pe_header.opthdr.ImageBase = pe->imagebase; - pe_header.opthdr.Subsystem = pe->subsystem; - if (pe->s1->pe_stack_size) - pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size; - if (PE_DLL == pe->type) - pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL; - pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics; - - sum = 0; - pe_fwrite(&pe_header, sizeof pe_header, op, &sum); - for (i = 0; i < pe->sec_count; ++i) - pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum); - pe_fpad(op, pe->sizeofheaders); - for (i = 0; i < pe->sec_count; ++i) { - si = pe->sec_info + i; - psh = &si->ish; - if (si->data_size) { - pe_fwrite(si->data, si->data_size, op, &sum); - file_offset = psh->PointerToRawData + psh->SizeOfRawData; - pe_fpad(op, file_offset); - } - } - - pe_header.opthdr.CheckSum = sum + file_offset; - fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); - pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL); - fclose (op); -#ifndef _WIN32 - chmod(pe->filename, 0777); -#endif - - if (2 == pe->s1->verbose) - printf("-------------------------------\n"); - if (pe->s1->verbose) - printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset); - - return 0; -} - -/*----------------------------------------------------------------------------*/ - -static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index) -{ - int i; - int dll_index; - struct pe_import_info *p; - struct import_symbol *s; - ElfW(Sym) *isym; - - isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; - dll_index = isym->st_size; - - i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index); - if (-1 != i) { - p = pe->imp_info[i]; - goto found_dll; - } - p = tcc_mallocz(sizeof *p); - p->dll_index = dll_index; - dynarray_add(&pe->imp_info, &pe->imp_count, p); - -found_dll: - i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index); - if (-1 != i) - return p->symbols[i]; - - s = tcc_mallocz(sizeof *s); - dynarray_add(&p->symbols, &p->sym_count, s); - s->sym_index = sym_index; - return s; -} - -void pe_free_imports(struct pe_info *pe) -{ - int i; - for (i = 0; i < pe->imp_count; ++i) { - struct pe_import_info *p = pe->imp_info[i]; - dynarray_reset(&p->symbols, &p->sym_count); - } - dynarray_reset(&pe->imp_info, &pe->imp_count); -} - -/*----------------------------------------------------------------------------*/ -static void pe_build_imports(struct pe_info *pe) -{ - int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; - DWORD rva_base = pe->thunk->sh_addr - pe->imagebase; - int ndlls = pe->imp_count; - - for (sym_cnt = i = 0; i < ndlls; ++i) - sym_cnt += pe->imp_info[i]->sym_count; - - if (0 == sym_cnt) - return; - - pe_align_section(pe->thunk, 16); - - pe->imp_offs = dll_ptr = pe->thunk->data_offset; - pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); - pe->iat_offs = dll_ptr + pe->imp_size; - pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264); - section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); - - thk_ptr = pe->iat_offs; - ent_ptr = pe->iat_offs + pe->iat_size; - - for (i = 0; i < pe->imp_count; ++i) { - IMAGE_IMPORT_DESCRIPTOR *hdr; - int k, n, dllindex; - ADDR3264 v; - struct pe_import_info *p = pe->imp_info[i]; - const char *name; - DLLReference *dllref; - - dllindex = p->dll_index; - if (dllindex) - name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name; - else - name = "", dllref = NULL; - - /* put the dll name into the import header */ - v = put_elf_str(pe->thunk, name); - hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr); - hdr->FirstThunk = thk_ptr + rva_base; - hdr->OriginalFirstThunk = ent_ptr + rva_base; - hdr->Name = v + rva_base; - - for (k = 0, n = p->sym_count; k <= n; ++k) { - if (k < n) { - int iat_index = p->symbols[k]->iat_index; - int sym_index = p->symbols[k]->sym_index; - ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; - ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index; - const char *name = (char*)pe->s1->dynsymtab_section->link->data + imp_sym->st_name; - int ordinal; - - org_sym->st_value = thk_ptr; - org_sym->st_shndx = pe->thunk->sh_num; - - if (dllref) - v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */ - else - ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */ - -#ifdef TCC_IS_NATIVE - if (pe->type == PE_RUN) { - if (dllref) { - if ( !dllref->handle ) - dllref->handle = LoadLibrary(dllref->name); - v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name); - } - if (!v) - tcc_error_noabort("can't build symbol '%s'", name); - } else -#endif - if (ordinal) { - v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1); - } else { - v = pe->thunk->data_offset + rva_base; - section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */ - put_elf_str(pe->thunk, name); - } - - } else { - v = 0; /* last entry is zero */ - } - - *(ADDR3264*)(pe->thunk->data+thk_ptr) = - *(ADDR3264*)(pe->thunk->data+ent_ptr) = v; - thk_ptr += sizeof (ADDR3264); - ent_ptr += sizeof (ADDR3264); - } - dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR); - } -} - -/* ------------------------------------------------------------- */ - -struct pe_sort_sym -{ - int index; - const char *name; -}; - -static int sym_cmp(const void *va, const void *vb) -{ - const char *ca = (*(struct pe_sort_sym**)va)->name; - const char *cb = (*(struct pe_sort_sym**)vb)->name; - return strcmp(ca, cb); -} - -static void pe_build_exports(struct pe_info *pe) -{ - ElfW(Sym) *sym; - int sym_index, sym_end; - DWORD rva_base, func_o, name_o, ord_o, str_o; - IMAGE_EXPORT_DIRECTORY *hdr; - int sym_count, ord; - struct pe_sort_sym **sorted, *p; - - FILE *op; - char buf[260]; - const char *dllname; - const char *name; - - rva_base = pe->thunk->sh_addr - pe->imagebase; - sym_count = 0, sorted = NULL, op = NULL; - - sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - sym = (ElfW(Sym)*)symtab_section->data + sym_index; - name = pe_export_name(pe->s1, sym); - if ((sym->st_other & ST_PE_EXPORT) - /* export only symbols from actually written sections */ - && pe->s1->sections[sym->st_shndx]->sh_addr) { - p = tcc_malloc(sizeof *p); - p->index = sym_index; - p->name = name; - dynarray_add(&sorted, &sym_count, p); - } -#if 0 - if (sym->st_other & ST_PE_EXPORT) - printf("export: %s\n", name); - if (sym->st_other & ST_PE_STDCALL) - printf("stdcall: %s\n", name); -#endif - } - - if (0 == sym_count) - return; - - qsort (sorted, sym_count, sizeof *sorted, sym_cmp); - - pe_align_section(pe->thunk, 16); - dllname = tcc_basename(pe->filename); - - pe->exp_offs = pe->thunk->data_offset; - func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY); - name_o = func_o + sym_count * sizeof (DWORD); - ord_o = name_o + sym_count * sizeof (DWORD); - str_o = ord_o + sym_count * sizeof(WORD); - - hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs); - hdr->Characteristics = 0; - hdr->Base = 1; - hdr->NumberOfFunctions = sym_count; - hdr->NumberOfNames = sym_count; - hdr->AddressOfFunctions = func_o + rva_base; - hdr->AddressOfNames = name_o + rva_base; - hdr->AddressOfNameOrdinals = ord_o + rva_base; - hdr->Name = str_o + rva_base; - put_elf_str(pe->thunk, dllname); - -#if 1 - /* automatically write exports to .def */ - pstrcpy(buf, sizeof buf, pe->filename); - strcpy(tcc_fileextension(buf), ".def"); - op = fopen(buf, "w"); - if (NULL == op) { - tcc_error_noabort("could not create '%s': %s", buf, strerror(errno)); - } else { - fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); - if (pe->s1->verbose) - printf("<- %s (%d symbol%s)\n", buf, sym_count, &"s"[sym_count < 2]); - } -#endif - - for (ord = 0; ord < sym_count; ++ord) - { - p = sorted[ord], sym_index = p->index, name = p->name; - /* insert actual address later in pe_relocate_rva */ - put_elf_reloc(symtab_section, pe->thunk, - func_o, R_XXX_RELATIVE, sym_index); - *(DWORD*)(pe->thunk->data + name_o) - = pe->thunk->data_offset + rva_base; - *(WORD*)(pe->thunk->data + ord_o) - = ord; - put_elf_str(pe->thunk, name); - func_o += sizeof (DWORD); - name_o += sizeof (DWORD); - ord_o += sizeof (WORD); - if (op) - fprintf(op, "%s\n", name); - } - pe->exp_size = pe->thunk->data_offset - pe->exp_offs; - dynarray_reset(&sorted, &sym_count); - if (op) - fclose(op); -} - -/* ------------------------------------------------------------- */ -static void pe_build_reloc (struct pe_info *pe) -{ - DWORD offset, block_ptr, addr; - int count, i; - ElfW_Rel *rel, *rel_end; - Section *s = NULL, *sr; - - offset = addr = block_ptr = count = i = 0; - rel = rel_end = NULL; - - for(;;) { - if (rel < rel_end) { - int type = ELFW(R_TYPE)(rel->r_info); - addr = rel->r_offset + s->sh_addr; - ++ rel; - if (type != REL_TYPE_DIRECT) - continue; - if (count == 0) { /* new block */ - block_ptr = pe->reloc->data_offset; - section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header)); - offset = addr & 0xFFFFFFFF<<12; - } - if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */ - WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD)); - *wp = addr | PE_IMAGE_REL<<12; - ++count; - continue; - } - -- rel; - - } else if (i < pe->sec_count) { - sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc; - if (sr) { - rel = (ElfW_Rel *)sr->data; - rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); - } - continue; - } - - if (count) { - /* store the last block and ready for a new one */ - struct pe_reloc_header *hdr; - if (count & 1) /* align for DWORDS */ - section_ptr_add(pe->reloc, sizeof(WORD)), ++count; - hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); - hdr -> offset = offset - pe->imagebase; - hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); - count = 0; - } - - if (rel >= rel_end) - break; - } -} - -/* ------------------------------------------------------------- */ -static int pe_section_class(Section *s) -{ - int type, flags; - const char *name; - - type = s->sh_type; - flags = s->sh_flags; - name = s->name; - if (flags & SHF_ALLOC) { - if (type == SHT_PROGBITS) { - if (flags & SHF_EXECINSTR) - return sec_text; - if (flags & SHF_WRITE) - return sec_data; - if (0 == strcmp(name, ".rsrc")) - return sec_rsrc; - if (0 == strcmp(name, ".iedat")) - return sec_idata; - if (0 == strcmp(name, ".pdata")) - return sec_pdata; - return sec_other; - } else if (type == SHT_NOBITS) { - if (flags & SHF_WRITE) - return sec_bss; - } - } else { - if (0 == strcmp(name, ".reloc")) - return sec_reloc; - if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */ - return sec_stab; - } - return -1; -} - -static int pe_assign_addresses (struct pe_info *pe) -{ - int i, k, o, c; - DWORD addr; - int *section_order; - struct section_info *si; - Section *s; - - if (PE_DLL == pe->type) - pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0); - - // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); - - section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); - for (o = k = 0 ; k < sec_last; ++k) { - for (i = 1; i < pe->s1->nb_sections; ++i) { - s = pe->s1->sections[i]; - if (k == pe_section_class(s)) { - // printf("%s %d\n", s->name, k); - s->sh_addr = pe->imagebase; - section_order[o++] = i; - } - } - } - - pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); - addr = pe->imagebase + 1; - - for (i = 0; i < o; ++i) - { - k = section_order[i]; - s = pe->s1->sections[k]; - c = pe_section_class(s); - si = &pe->sec_info[pe->sec_count]; - -#ifdef PE_MERGE_DATA - if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { - /* append .bss to .data */ - s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1; - addr += s->data_offset; - si[-1].sh_size = addr - si[-1].sh_addr; - continue; - } -#endif - if (c == sec_stab && 0 == pe->s1->do_debug) - continue; - - strcpy(si->name, s->name); - si->cls = c; - si->ord = k; - si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr); - si->sh_flags = s->sh_flags; - - if (c == sec_data && NULL == pe->thunk) - pe->thunk = s; - - if (s == pe->thunk) { - pe_build_imports(pe); - pe_build_exports(pe); - } - - if (c == sec_reloc) - pe_build_reloc (pe); - - if (s->data_offset) - { - if (s->sh_type != SHT_NOBITS) { - si->data = s->data; - si->data_size = s->data_offset; - } - - addr += s->data_offset; - si->sh_size = s->data_offset; - ++pe->sec_count; - } - // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name); - } - -#if 0 - for (i = 1; i < pe->s1->nb_sections; ++i) { - Section *s = pe->s1->sections[i]; - int type = s->sh_type; - int flags = s->sh_flags; - printf("section %-16s %-10s %5x %s,%s,%s\n", - s->name, - type == SHT_PROGBITS ? "progbits" : - type == SHT_NOBITS ? "nobits" : - type == SHT_SYMTAB ? "symtab" : - type == SHT_STRTAB ? "strtab" : - type == SHT_RELX ? "rel" : "???", - s->data_offset, - flags & SHF_ALLOC ? "alloc" : "", - flags & SHF_WRITE ? "write" : "", - flags & SHF_EXECINSTR ? "exec" : "" - ); - } - pe->s1->verbose = 2; -#endif - - tcc_free(section_order); - return 0; -} - -/* ------------------------------------------------------------- */ -static void pe_relocate_rva (struct pe_info *pe, Section *s) -{ - Section *sr = s->reloc; - ElfW_Rel *rel, *rel_end; - rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); - for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) { - if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) { - int sym_index = ELFW(R_SYM)(rel->r_info); - DWORD addr = s->sh_addr; - if (sym_index) { - ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; - addr = sym->st_value; - } - // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name); - *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase; - } - } -} - -/*----------------------------------------------------------------------------*/ - -static int pe_isafunc(int sym_index) -{ - Section *sr = text_section->reloc; - ElfW_Rel *rel, *rel_end; - Elf32_Word info = ELF32_R_INFO(sym_index, R_386_PC32); - if (!sr) - return 0; - rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); - for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) - if (rel->r_info == info) - return 1; - return 0; -} - -/*----------------------------------------------------------------------------*/ -static int pe_check_symbols(struct pe_info *pe) -{ - ElfW(Sym) *sym; - int sym_index, sym_end; - int ret = 0; - - pe_align_section(text_section, 8); - - sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); - for (sym_index = 1; sym_index < sym_end; ++sym_index) { - - sym = (ElfW(Sym) *)symtab_section->data + sym_index; - if (sym->st_shndx == SHN_UNDEF) { - - const char *name = (char*)symtab_section->link->data + sym->st_name; - unsigned type = ELFW(ST_TYPE)(sym->st_info); - int imp_sym = pe_find_import(pe->s1, sym); - struct import_symbol *is; - - if (imp_sym <= 0) - goto not_found; - - if (type == STT_NOTYPE) { - /* symbols from assembler have no type, find out which */ - if (pe_isafunc(sym_index)) - type = STT_FUNC; - else - type = STT_OBJECT; - } - - is = pe_add_import(pe, imp_sym); - - if (type == STT_FUNC) { - unsigned long offset = is->thk_offset; - if (offset) { - /* got aliased symbol, like stricmp and _stricmp */ - - } else { - char buffer[100]; - WORD *p; - - offset = text_section->data_offset; - /* add the 'jmp IAT[x]' instruction */ -#ifdef TCC_TARGET_ARM - p = section_ptr_add(text_section, 8+4); // room for code and address - (*(DWORD*)(p)) = 0xE59FC000; // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx - (*(DWORD*)(p+2)) = 0xE59CF000; // arm code ldr pc, [ip] -#else - p = section_ptr_add(text_section, 8); - *p = 0x25FF; -#ifdef TCC_TARGET_X86_64 - *(DWORD*)(p+1) = (DWORD)-4; -#endif -#endif - /* add a helper symbol, will be patched later in - pe_build_imports */ - sprintf(buffer, "IAT.%s", name); - is->iat_index = put_elf_sym( - symtab_section, 0, sizeof(DWORD), - ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), - 0, SHN_UNDEF, buffer); -#ifdef TCC_TARGET_ARM - put_elf_reloc(symtab_section, text_section, - offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position -#else - put_elf_reloc(symtab_section, text_section, - offset + 2, R_XXX_THUNKFIX, is->iat_index); -#endif - is->thk_offset = offset; - } - - /* tcc_realloc might have altered sym's address */ - sym = (ElfW(Sym) *)symtab_section->data + sym_index; - - /* patch the original symbol */ - sym->st_value = offset; - sym->st_shndx = text_section->sh_num; - sym->st_other &= ~ST_PE_EXPORT; /* do not export */ - continue; - } - - if (type == STT_OBJECT) { /* data, ptr to that should be */ - if (0 == is->iat_index) { - /* original symbol will be patched later in pe_build_imports */ - is->iat_index = sym_index; - continue; - } - } - - not_found: - if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) - /* STB_WEAK undefined symbols are accepted */ - continue; - tcc_error_noabort("undefined symbol '%s'%s", name, - imp_sym < 0 ? ", missing __declspec(dllimport)?":""); - ret = -1; - - } else if (pe->s1->rdynamic - && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { - /* if -rdynamic option, then export all non local symbols */ - sym->st_other |= ST_PE_EXPORT; - } - } - return ret; -} - -/*----------------------------------------------------------------------------*/ -#ifdef PE_PRINT_SECTIONS -static void pe_print_section(FILE * f, Section * s) -{ - /* just if you're curious */ - BYTE *p, *e, b; - int i, n, l, m; - p = s->data; - e = s->data + s->data_offset; - l = e - p; - - fprintf(f, "section \"%s\"", s->name); - if (s->link) - fprintf(f, "\nlink \"%s\"", s->link->name); - if (s->reloc) - fprintf(f, "\nreloc \"%s\"", s->reloc->name); - fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr); - fprintf(f, "\ncontents %08X", (unsigned)l); - fprintf(f, "\n\n"); - - if (s->sh_type == SHT_NOBITS) - return; - - if (0 == l) - return; - - if (s->sh_type == SHT_SYMTAB) - m = sizeof(ElfW(Sym)); - else if (s->sh_type == SHT_RELX) - m = sizeof(ElfW_Rel); - else - m = 16; - - fprintf(f, "%-8s", "offset"); - for (i = 0; i < m; ++i) - fprintf(f, " %02x", i); - n = 56; - - if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) { - const char *fields1[] = { - "name", - "value", - "size", - "bind", - "type", - "other", - "shndx", - NULL - }; - - const char *fields2[] = { - "offs", - "type", - "symb", - NULL - }; - - const char **p; - - if (s->sh_type == SHT_SYMTAB) - p = fields1, n = 106; - else - p = fields2, n = 58; - - for (i = 0; p[i]; ++i) - fprintf(f, "%6s", p[i]); - fprintf(f, " symbol"); - } - - fprintf(f, "\n"); - for (i = 0; i < n; ++i) - fprintf(f, "-"); - fprintf(f, "\n"); - - for (i = 0; i < l;) - { - fprintf(f, "%08X", i); - for (n = 0; n < m; ++n) { - if (n + i < l) - fprintf(f, " %02X", p[i + n]); - else - fprintf(f, " "); - } - - if (s->sh_type == SHT_SYMTAB) { - ElfW(Sym) *sym = (ElfW(Sym) *) (p + i); - const char *name = s->link->data + sym->st_name; - fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"", - (unsigned)sym->st_name, - (unsigned)sym->st_value, - (unsigned)sym->st_size, - (unsigned)ELFW(ST_BIND)(sym->st_info), - (unsigned)ELFW(ST_TYPE)(sym->st_info), - (unsigned)sym->st_other, - (unsigned)sym->st_shndx, - name); - - } else if (s->sh_type == SHT_RELX) { - ElfW_Rel *rel = (ElfW_Rel *) (p + i); - ElfW(Sym) *sym = - (ElfW(Sym) *) s->link->data + ELFW(R_SYM)(rel->r_info); - const char *name = s->link->link->data + sym->st_name; - fprintf(f, " %04X %02X %04X \"%s\"", - (unsigned)rel->r_offset, - (unsigned)ELFW(R_TYPE)(rel->r_info), - (unsigned)ELFW(R_SYM)(rel->r_info), - name); - } else { - fprintf(f, " "); - for (n = 0; n < m; ++n) { - if (n + i < l) { - b = p[i + n]; - if (b < 32 || b >= 127) - b = '.'; - fprintf(f, "%c", b); - } - } - } - i += m; - fprintf(f, "\n"); - } - fprintf(f, "\n\n"); -} - -static void pe_print_sections(TCCState *s1, const char *fname) -{ - Section *s; - FILE *f; - int i; - f = fopen(fname, "w"); - for (i = 1; i < s1->nb_sections; ++i) { - s = s1->sections[i]; - pe_print_section(f, s); - } - pe_print_section(f, s1->dynsymtab_section); - fclose(f); -} -#endif - -/* ------------------------------------------------------------- */ -/* helper function for load/store to insert one more indirection */ - -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) -{ - int r2; - if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) - return sv; - if (!sv->sym->a.dllimport) - return sv; - // printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); - memset(v2, 0, sizeof *v2); - v2->type.t = VT_PTR; - v2->r = VT_CONST | VT_SYM | VT_LVAL; - v2->sym = sv->sym; - - r2 = get_reg(RC_INT); - load(r2, v2); - v2->r = r2; - if ((uint32_t)sv->c.i) { - vpushv(v2); - vpushi(sv->c.i); - gen_opi('+'); - *v2 = *vtop--; - } - v2->type.t = sv->type.t; - v2->r |= sv->r & VT_LVAL; - return v2; -} -#endif - -ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value) -{ - return set_elf_sym( - s1->dynsymtab_section, - value, - dllindex, /* st_size */ - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), - 0, - value ? SHN_ABS : SHN_UNDEF, - name - ); -} - -static int add_dllref(TCCState *s1, const char *dllname) -{ - DLLReference *dllref; - int i; - for (i = 0; i < s1->nb_loaded_dlls; ++i) - if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) - return i + 1; - dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); - strcpy(dllref->name, dllname); - dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); - return s1->nb_loaded_dlls; -} - -/* ------------------------------------------------------------- */ - -static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) -{ - lseek(fd, offset, SEEK_SET); - return len == read(fd, buffer, len); -} - -/* ------------------------------------------------------------- */ - -PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp) -{ - int l, i, n, n0, ret; - char *p; - int fd; - - IMAGE_SECTION_HEADER ish; - IMAGE_EXPORT_DIRECTORY ied; - IMAGE_DOS_HEADER dh; - IMAGE_FILE_HEADER ih; - DWORD sig, ref, addr, ptr, namep; - - int pef_hdroffset, opt_hdroffset, sec_hdroffset; - - n = n0 = 0; - p = NULL; - ret = -1; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - goto the_end_1; - ret = 1; - if (!read_mem(fd, 0, &dh, sizeof dh)) - goto the_end; - if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig)) - goto the_end; - if (sig != 0x00004550) - goto the_end; - pef_hdroffset = dh.e_lfanew + sizeof sig; - if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih)) - goto the_end; - opt_hdroffset = pef_hdroffset + sizeof ih; - if (ih.Machine == 0x014C) { - IMAGE_OPTIONAL_HEADER32 oh; - sec_hdroffset = opt_hdroffset + sizeof oh; - if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) - goto the_end; - if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) - goto the_end_0; - addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - } else if (ih.Machine == 0x8664) { - IMAGE_OPTIONAL_HEADER64 oh; - sec_hdroffset = opt_hdroffset + sizeof oh; - if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) - goto the_end; - if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) - goto the_end_0; - addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - } else - goto the_end; - - //printf("addr: %08x\n", addr); - for (i = 0; i < ih.NumberOfSections; ++i) { - if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish)) - goto the_end; - //printf("vaddr: %08x\n", ish.VirtualAddress); - if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData) - goto found; - } - goto the_end_0; - -found: - ref = ish.VirtualAddress - ish.PointerToRawData; - if (!read_mem(fd, addr - ref, &ied, sizeof ied)) - goto the_end; - - namep = ied.AddressOfNames - ref; - for (i = 0; i < ied.NumberOfNames; ++i) { - if (!read_mem(fd, namep, &ptr, sizeof ptr)) - goto the_end; - namep += sizeof ptr; - for (l = 0;;) { - if (n+1 >= n0) - p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256); - if (!read_mem(fd, ptr - ref + l++, p + n, 1)) { - tcc_free(p), p = NULL; - goto the_end; - } - if (p[n++] == 0) - break; - } - } - if (p) - p[n] = 0; -the_end_0: - ret = 0; -the_end: - close(fd); -the_end_1: - *pp = p; - return ret; -} - -/* ------------------------------------------------------------- - * This is for compiled windows resources in 'coff' format - * as generated by 'windres.exe -O coff ...'. - */ - -static int pe_load_res(TCCState *s1, int fd) -{ - struct pe_rsrc_header hdr; - Section *rsrc_section; - int i, ret = -1; - BYTE *ptr; - unsigned offs; - - if (!read_mem(fd, 0, &hdr, sizeof hdr)) - goto quit; - - if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE - || hdr.filehdr.NumberOfSections != 1 - || strcmp((char*)hdr.sectionhdr.Name, ".rsrc") != 0) - goto quit; - - rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); - ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); - offs = hdr.sectionhdr.PointerToRawData; - if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) - goto quit; - offs = hdr.sectionhdr.PointerToRelocations; - for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) - { - struct pe_rsrc_reloc rel; - if (!read_mem(fd, offs, &rel, sizeof rel)) - goto quit; - // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type); - if (rel.type != RSRC_RELTYPE) - goto quit; - put_elf_reloc(symtab_section, rsrc_section, - rel.offset, R_XXX_RELATIVE, 0); - offs += sizeof rel; - } - ret = 0; -quit: - return ret; -} - -/* ------------------------------------------------------------- */ - -static char *trimfront(char *p) -{ - while (*p && (unsigned char)*p <= ' ') - ++p; - return p; -} - -static char *trimback(char *a, char *e) -{ - while (e > a && (unsigned char)e[-1] <= ' ') - --e; - *e = 0;; - return a; -} - -/* ------------------------------------------------------------- */ -static int pe_load_def(TCCState *s1, int fd) -{ - int state = 0, ret = -1, dllindex = 0, ord; - char line[400], dllname[80], *p, *x; - FILE *fp; - - fp = fdopen(dup(fd), "rb"); - while (fgets(line, sizeof line, fp)) - { - p = trimfront(trimback(line, strchr(line, 0))); - if (0 == *p || ';' == *p) - continue; - - switch (state) { - case 0: - if (0 != strnicmp(p, "LIBRARY", 7)) - goto quit; - pstrcpy(dllname, sizeof dllname, trimfront(p+7)); - ++state; - continue; - - case 1: - if (0 != stricmp(p, "EXPORTS")) - goto quit; - ++state; - continue; - - case 2: - dllindex = add_dllref(s1, dllname); - ++state; - /* fall through */ - default: - /* get ordinal and will store in sym->st_value */ - ord = 0; - x = strchr(p, ' '); - if (x) { - *x = 0, x = strrchr(x + 1, '@'); - if (x) { - char *d; - ord = (int)strtol(x + 1, &d, 10); - if (*d) - ord = 0; - } - } - pe_putimport(s1, dllindex, p, ord); - continue; - } - } - ret = 0; -quit: - fclose(fp); - return ret; -} - -/* ------------------------------------------------------------- */ -static int pe_load_dll(TCCState *s1, const char *filename) -{ - char *p, *q; - int index, ret; - - ret = tcc_get_dllexports(filename, &p); - if (ret) { - return -1; - } else if (p) { - index = add_dllref(s1, tcc_basename(filename)); - for (q = p; *q; q += 1 + strlen(q)) - pe_putimport(s1, index, q, 0); - tcc_free(p); - } - return 0; -} - -/* ------------------------------------------------------------- */ -ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) -{ - int ret = -1; - char buf[10]; - if (0 == strcmp(tcc_fileextension(filename), ".def")) - ret = pe_load_def(s1, fd); - else if (pe_load_res(s1, fd) == 0) - ret = 0; - else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4)) - ret = pe_load_dll(s1, filename); - return ret; -} - -/* ------------------------------------------------------------- */ -#ifdef TCC_TARGET_X86_64 -static unsigned pe_add_uwwind_info(TCCState *s1) -{ - if (NULL == s1->uw_pdata) { - s1->uw_pdata = find_section(tcc_state, ".pdata"); - s1->uw_pdata->sh_addralign = 4; - s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); - } - - if (0 == s1->uw_offs) { - /* As our functions all have the same stackframe, we use one entry for all */ - static const unsigned char uw_info[] = { - 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags - 0x04, // UBYTE Size of prolog - 0x02, // UBYTE Count of unwind codes - 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) - // USHORT * n Unwind codes array - // 0x0b, 0x01, 0xff, 0xff, // stack size - 0x04, 0x03, // set frame ptr (mov rsp -> rbp) - 0x01, 0x50 // push reg (rbp) - }; - - Section *s = text_section; - unsigned char *p; - - section_ptr_add(s, -s->data_offset & 3); /* align */ - s1->uw_offs = s->data_offset; - p = section_ptr_add(s, sizeof uw_info); - memcpy(p, uw_info, sizeof uw_info); - } - - return s1->uw_offs; -} - -ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) -{ - TCCState *s1 = tcc_state; - Section *pd; - unsigned o, n, d; - struct /* _RUNTIME_FUNCTION */ { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindData; - } *p; - - d = pe_add_uwwind_info(s1); - pd = s1->uw_pdata; - o = pd->data_offset; - p = section_ptr_add(pd, sizeof *p); - - /* record this function */ - p->BeginAddress = start; - p->EndAddress = end; - p->UnwindData = d; - - /* put relocations on it */ - for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) - put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym); -} -#endif -/* ------------------------------------------------------------- */ -#ifdef TCC_TARGET_X86_64 -#define PE_STDSYM(n,s) n -#else -#define PE_STDSYM(n,s) "_" n s -#endif - -static void pe_add_runtime(TCCState *s1, struct pe_info *pe) -{ - const char *start_symbol; - int pe_type = 0; - int unicode_entry = 0; - - if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16"))) - pe_type = PE_GUI; - else - if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) { - pe_type = PE_GUI; - unicode_entry = PE_GUI; - } - else - if (TCC_OUTPUT_DLL == s1->output_type) { - pe_type = PE_DLL; - /* need this for 'tccelf.c:relocate_section()' */ - s1->output_type = TCC_OUTPUT_EXE; - } - else { - pe_type = PE_EXE; - if (find_elf_sym(symtab_section, "wmain")) - unicode_entry = PE_EXE; - } - - start_symbol = - TCC_OUTPUT_MEMORY == s1->output_type - ? PE_GUI == pe_type ? (unicode_entry ? "__runwwinmain" : "__runwinmain") - : (unicode_entry ? "__runwmain" : "__runmain") - : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12") - : PE_GUI == pe_type ? (unicode_entry ? "__wwinstart": "__winstart") - : (unicode_entry ? "__wstart" : "__start") - ; - - if (!s1->leading_underscore || strchr(start_symbol, '@')) - ++start_symbol; - - /* grab the startup code from libtcc1 */ -#ifdef TCC_IS_NATIVE - if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main) -#endif - set_elf_sym(symtab_section, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_UNDEF, start_symbol); - - tcc_add_pragma_libs(s1); - - if (0 == s1->nostdlib) { - static const char *libs[] = { - TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL - }; - const char **pp, *p; - for (pp = libs; 0 != (p = *pp); ++pp) { - if (0 == *p) { - if (PE_DLL != pe_type && PE_GUI != pe_type) - break; - } else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) { - continue; - } else { - tcc_add_library_err(s1, p); - } - } - } - - if (TCC_OUTPUT_MEMORY == s1->output_type) - pe_type = PE_RUN; - pe->type = pe_type; - pe->start_symbol = start_symbol; -} - -static void pe_set_options(TCCState * s1, struct pe_info *pe) -{ - if (PE_DLL == pe->type) { - /* XXX: check if is correct for arm-pe target */ - pe->imagebase = 0x10000000; - } else { -#if defined(TCC_TARGET_ARM) - pe->imagebase = 0x00010000; -#else - pe->imagebase = 0x00400000; -#endif - } - -#if defined(TCC_TARGET_ARM) - /* we use "console" subsystem by default */ - pe->subsystem = 9; -#else - if (PE_DLL == pe->type || PE_GUI == pe->type) - pe->subsystem = 2; - else - pe->subsystem = 3; -#endif - /* Allow override via -Wl,-subsystem=... option */ - if (s1->pe_subsystem != 0) - pe->subsystem = s1->pe_subsystem; - - /* set default file/section alignment */ - if (pe->subsystem == 1) { - pe->section_align = 0x20; - pe->file_align = 0x20; - } else { - pe->section_align = 0x1000; - pe->file_align = 0x200; - } - - if (s1->section_align != 0) - pe->section_align = s1->section_align; - if (s1->pe_file_align != 0) - pe->file_align = s1->pe_file_align; - - if ((pe->subsystem >= 10) && (pe->subsystem <= 12)) - pe->imagebase = 0; - - if (s1->has_text_addr) - pe->imagebase = s1->text_addr; -} - -ST_FUNC int pe_output_file(TCCState *s1, const char *filename) -{ - int ret; - struct pe_info pe; - int i; - - memset(&pe, 0, sizeof pe); - pe.filename = filename; - pe.s1 = s1; - - tcc_add_bcheck(s1); - pe_add_runtime(s1, &pe); - relocate_common_syms(); /* assign bss addresses */ - tcc_add_linker_symbols(s1); - pe_set_options(s1, &pe); - - ret = pe_check_symbols(&pe); - if (ret) - ; - else if (filename) { - pe_assign_addresses(&pe); - relocate_syms(s1, s1->symtab, 0); - for (i = 1; i < s1->nb_sections; ++i) { - Section *s = s1->sections[i]; - if (s->reloc) { - relocate_section(s1, s); - pe_relocate_rva(&pe, s); - } - } - pe.start_addr = (DWORD) - ((uintptr_t)tcc_get_symbol_err(s1, pe.start_symbol) - - pe.imagebase); - if (s1->nb_errors) - ret = -1; - else - ret = pe_write(&pe); - tcc_free(pe.sec_info); - } else { -#ifdef TCC_IS_NATIVE - pe.thunk = data_section; - pe_build_imports(&pe); - s1->runtime_main = pe.start_symbol; -#endif - } - - pe_free_imports(&pe); - -#ifdef PE_PRINT_SECTIONS - pe_print_sections(s1, "tcc.log"); -#endif - return ret; -} - -/* ------------------------------------------------------------- */ diff --git a/tinyc/tccpp.c b/tinyc/tccpp.c deleted file mode 100644 index 76f9e428e..000000000 --- a/tinyc/tccpp.c +++ /dev/null @@ -1,3903 +0,0 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -/********************************************************/ -/* global variables */ - -ST_DATA int tok_flags; -ST_DATA int parse_flags; - -ST_DATA struct BufferedFile *file; -ST_DATA int ch, tok; -ST_DATA CValue tokc; -ST_DATA const int *macro_ptr; -ST_DATA CString tokcstr; /* current parsed string, if any */ - -/* display benchmark infos */ -ST_DATA int total_lines; -ST_DATA int total_bytes; -ST_DATA int tok_ident; -ST_DATA TokenSym **table_ident; - -/* ------------------------------------------------------------------------- */ - -static TokenSym *hash_ident[TOK_HASH_SIZE]; -static char token_buf[STRING_MAX_SIZE + 1]; -static CString cstr_buf; -static CString macro_equal_buf; -static TokenString tokstr_buf; -static unsigned char isidnum_table[256 - CH_EOF]; -static int pp_debug_tok, pp_debug_symv; -static int pp_once; -static int pp_expr; -static int pp_counter; -static void tok_print(const char *msg, const int *str); - -static struct TinyAlloc *toksym_alloc; -static struct TinyAlloc *tokstr_alloc; -static struct TinyAlloc *cstr_alloc; - -static TokenString *macro_stack; - -static const char tcc_keywords[] = -#define DEF(id, str) str "\0" -#include "tcctok.h" -#undef DEF -; - -/* WARNING: the content of this string encodes token numbers */ -static const unsigned char tok_two_chars[] = -/* outdated -- gr - "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253" - "-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; -*/{ - '<','=', TOK_LE, - '>','=', TOK_GE, - '!','=', TOK_NE, - '&','&', TOK_LAND, - '|','|', TOK_LOR, - '+','+', TOK_INC, - '-','-', TOK_DEC, - '=','=', TOK_EQ, - '<','<', TOK_SHL, - '>','>', TOK_SAR, - '+','=', TOK_A_ADD, - '-','=', TOK_A_SUB, - '*','=', TOK_A_MUL, - '/','=', TOK_A_DIV, - '%','=', TOK_A_MOD, - '&','=', TOK_A_AND, - '^','=', TOK_A_XOR, - '|','=', TOK_A_OR, - '-','>', TOK_ARROW, - '.','.', TOK_TWODOTS, - '#','#', TOK_TWOSHARPS, - 0 -}; - -static void next_nomacro_spc(void); - -ST_FUNC void skip(int c) -{ - if (tok != c) - tcc_error("'%c' expected (got \"%s\")", c, get_tok_str(tok, &tokc)); - next(); -} - -ST_FUNC void expect(const char *msg) -{ - tcc_error("%s expected", msg); -} - -/* ------------------------------------------------------------------------- */ -/* Custom allocator for tiny objects */ - -#define USE_TAL - -#ifndef USE_TAL -#define tal_free(al, p) tcc_free(p) -#define tal_realloc(al, p, size) tcc_realloc(p, size) -#define tal_new(a,b,c) -#define tal_delete(a) -#else -#if !defined(MEM_DEBUG) -#define tal_free(al, p) tal_free_impl(al, p) -#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size) -#define TAL_DEBUG_PARAMS -#else -#define TAL_DEBUG 1 -//#define TAL_INFO 1 /* collect and dump allocators stats */ -#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__) -#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__) -#define TAL_DEBUG_PARAMS , const char *file, int line -#define TAL_DEBUG_FILE_LEN 40 -#endif - -#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */ -#define TOKSTR_TAL_SIZE (768 * 1024) /* allocator for tiny TokenString instances */ -#define CSTR_TAL_SIZE (256 * 1024) /* allocator for tiny CString instances */ -#define TOKSYM_TAL_LIMIT 256 /* prefer unique limits to distinguish allocators debug msgs */ -#define TOKSTR_TAL_LIMIT 128 /* 32 * sizeof(int) */ -#define CSTR_TAL_LIMIT 1024 - -typedef struct TinyAlloc { - unsigned limit; - unsigned size; - uint8_t *buffer; - uint8_t *p; - unsigned nb_allocs; - struct TinyAlloc *next, *top; -#ifdef TAL_INFO - unsigned nb_peak; - unsigned nb_total; - unsigned nb_missed; - uint8_t *peak_p; -#endif -} TinyAlloc; - -typedef struct tal_header_t { - unsigned size; -#ifdef TAL_DEBUG - int line_num; /* negative line_num used for double free check */ - char file_name[TAL_DEBUG_FILE_LEN + 1]; -#endif -} tal_header_t; - -/* ------------------------------------------------------------------------- */ - -static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size) -{ - TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc)); - al->p = al->buffer = tcc_malloc(size); - al->limit = limit; - al->size = size; - if (pal) *pal = al; - return al; -} - -static void tal_delete(TinyAlloc *al) -{ - TinyAlloc *next; - -tail_call: - if (!al) - return; -#ifdef TAL_INFO - fprintf(stderr, "limit=%5d, size=%5g MB, nb_peak=%6d, nb_total=%8d, nb_missed=%6d, usage=%5.1f%%\n", - al->limit, al->size / 1024.0 / 1024.0, al->nb_peak, al->nb_total, al->nb_missed, - (al->peak_p - al->buffer) * 100.0 / al->size); -#endif -#ifdef TAL_DEBUG - if (al->nb_allocs > 0) { - uint8_t *p; - fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s) (limit= %d)\n", - al->nb_allocs, al->limit); - p = al->buffer; - while (p < al->p) { - tal_header_t *header = (tal_header_t *)p; - if (header->line_num > 0) { - fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n", - header->file_name, header->line_num, header->size); - } - p += header->size + sizeof(tal_header_t); - } -#if MEM_DEBUG-0 == 2 - exit(2); -#endif - } -#endif - next = al->next; - tcc_free(al->buffer); - tcc_free(al); - al = next; - goto tail_call; -} - -static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS) -{ - if (!p) - return; -tail_call: - if (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) { -#ifdef TAL_DEBUG - tal_header_t *header = (((tal_header_t *)p) - 1); - if (header->line_num < 0) { - fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n", - file, line); - fprintf(stderr, "%s:%d: %d bytes\n", - header->file_name, (int)-header->line_num, (int)header->size); - } else - header->line_num = -header->line_num; -#endif - al->nb_allocs--; - if (!al->nb_allocs) - al->p = al->buffer; - } else if (al->next) { - al = al->next; - goto tail_call; - } - else - tcc_free(p); -} - -static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS) -{ - tal_header_t *header; - void *ret; - int is_own; - unsigned adj_size = (size + 3) & -4; - TinyAlloc *al = *pal; - -tail_call: - is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size); - if ((!p || is_own) && size <= al->limit) { - if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) { - header = (tal_header_t *)al->p; - header->size = adj_size; -#ifdef TAL_DEBUG - { int ofs = strlen(file) - TAL_DEBUG_FILE_LEN; - strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN); - header->file_name[TAL_DEBUG_FILE_LEN] = 0; - header->line_num = line; } -#endif - ret = al->p + sizeof(tal_header_t); - al->p += adj_size + sizeof(tal_header_t); - if (is_own) { - header = (((tal_header_t *)p) - 1); - memcpy(ret, p, header->size); -#ifdef TAL_DEBUG - header->line_num = -header->line_num; -#endif - } else { - al->nb_allocs++; - } -#ifdef TAL_INFO - if (al->nb_peak < al->nb_allocs) - al->nb_peak = al->nb_allocs; - if (al->peak_p < al->p) - al->peak_p = al->p; - al->nb_total++; -#endif - return ret; - } else if (is_own) { - al->nb_allocs--; - ret = tal_realloc(*pal, 0, size); - header = (((tal_header_t *)p) - 1); - memcpy(ret, p, header->size); -#ifdef TAL_DEBUG - header->line_num = -header->line_num; -#endif - return ret; - } - if (al->next) { - al = al->next; - } else { - TinyAlloc *bottom = al, *next = al->top ? al->top : al; - - al = tal_new(pal, next->limit, next->size * 2); - al->next = next; - bottom->top = al; - } - goto tail_call; - } - if (is_own) { - al->nb_allocs--; - ret = tcc_malloc(size); - header = (((tal_header_t *)p) - 1); - memcpy(ret, p, header->size); -#ifdef TAL_DEBUG - header->line_num = -header->line_num; -#endif - } else if (al->next) { - al = al->next; - goto tail_call; - } else - ret = tcc_realloc(p, size); -#ifdef TAL_INFO - al->nb_missed++; -#endif - return ret; -} - -#endif /* USE_TAL */ - -/* ------------------------------------------------------------------------- */ -/* CString handling */ -static void cstr_realloc(CString *cstr, int new_size) -{ - int size; - - size = cstr->size_allocated; - if (size < 8) - size = 8; /* no need to allocate a too small first string */ - while (size < new_size) - size = size * 2; - cstr->data = tal_realloc(cstr_alloc, cstr->data, size); - cstr->size_allocated = size; -} - -/* add a byte */ -ST_INLN void cstr_ccat(CString *cstr, int ch) -{ - int size; - size = cstr->size + 1; - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - ((unsigned char *)cstr->data)[size - 1] = ch; - cstr->size = size; -} - -ST_FUNC void cstr_cat(CString *cstr, const char *str, int len) -{ - int size; - if (len <= 0) - len = strlen(str) + 1 + len; - size = cstr->size + len; - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - memmove(((unsigned char *)cstr->data) + cstr->size, str, len); - cstr->size = size; -} - -/* add a wide char */ -ST_FUNC void cstr_wccat(CString *cstr, int ch) -{ - int size; - size = cstr->size + sizeof(nwchar_t); - if (size > cstr->size_allocated) - cstr_realloc(cstr, size); - *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch; - cstr->size = size; -} - -ST_FUNC void cstr_new(CString *cstr) -{ - memset(cstr, 0, sizeof(CString)); -} - -/* free string and reset it to NULL */ -ST_FUNC void cstr_free(CString *cstr) -{ - tal_free(cstr_alloc, cstr->data); - cstr_new(cstr); -} - -/* reset string to empty */ -ST_FUNC void cstr_reset(CString *cstr) -{ - cstr->size = 0; -} - -/* XXX: unicode ? */ -static void add_char(CString *cstr, int c) -{ - if (c == '\'' || c == '\"' || c == '\\') { - /* XXX: could be more precise if char or string */ - cstr_ccat(cstr, '\\'); - } - if (c >= 32 && c <= 126) { - cstr_ccat(cstr, c); - } else { - cstr_ccat(cstr, '\\'); - if (c == '\n') { - cstr_ccat(cstr, 'n'); - } else { - cstr_ccat(cstr, '0' + ((c >> 6) & 7)); - cstr_ccat(cstr, '0' + ((c >> 3) & 7)); - cstr_ccat(cstr, '0' + (c & 7)); - } - } -} - -/* ------------------------------------------------------------------------- */ -/* allocate a new token */ -static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) -{ - TokenSym *ts, **ptable; - int i; - - if (tok_ident >= SYM_FIRST_ANOM) - tcc_error("memory full (symbols)"); - - /* expand token table if needed */ - i = tok_ident - TOK_IDENT; - if ((i % TOK_ALLOC_INCR) == 0) { - ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); - table_ident = ptable; - } - - ts = tal_realloc(toksym_alloc, 0, sizeof(TokenSym) + len); - table_ident[i] = ts; - ts->tok = tok_ident++; - ts->sym_define = NULL; - ts->sym_label = NULL; - ts->sym_struct = NULL; - ts->sym_identifier = NULL; - ts->len = len; - ts->hash_next = NULL; - memcpy(ts->str, str, len); - ts->str[len] = '\0'; - *pts = ts; - return ts; -} - -#define TOK_HASH_INIT 1 -#define TOK_HASH_FUNC(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c)) - - -/* find a token and add it if not found */ -ST_FUNC TokenSym *tok_alloc(const char *str, int len) -{ - TokenSym *ts, **pts; - int i; - unsigned int h; - - h = TOK_HASH_INIT; - for(i=0;ilen == len && !memcmp(ts->str, str, len)) - return ts; - pts = &(ts->hash_next); - } - return tok_alloc_new(pts, str, len); -} - -/* XXX: buffer overflow */ -/* XXX: float tokens */ -ST_FUNC const char *get_tok_str(int v, CValue *cv) -{ - char *p; - int i, len; - - cstr_reset(&cstr_buf); - p = cstr_buf.data; - - switch(v) { - case TOK_CINT: - case TOK_CUINT: - case TOK_CLONG: - case TOK_CULONG: - case TOK_CLLONG: - case TOK_CULLONG: - /* XXX: not quite exact, but only useful for testing */ -#ifdef _WIN32 - sprintf(p, "%u", (unsigned)cv->i); -#else - sprintf(p, "%llu", (unsigned long long)cv->i); -#endif - break; - case TOK_LCHAR: - cstr_ccat(&cstr_buf, 'L'); - case TOK_CCHAR: - cstr_ccat(&cstr_buf, '\''); - add_char(&cstr_buf, cv->i); - cstr_ccat(&cstr_buf, '\''); - cstr_ccat(&cstr_buf, '\0'); - break; - case TOK_PPNUM: - case TOK_PPSTR: - return (char*)cv->str.data; - case TOK_LSTR: - cstr_ccat(&cstr_buf, 'L'); - case TOK_STR: - cstr_ccat(&cstr_buf, '\"'); - if (v == TOK_STR) { - len = cv->str.size - 1; - for(i=0;istr.data)[i]); - } else { - len = (cv->str.size / sizeof(nwchar_t)) - 1; - for(i=0;istr.data)[i]); - } - cstr_ccat(&cstr_buf, '\"'); - cstr_ccat(&cstr_buf, '\0'); - break; - - case TOK_CFLOAT: - cstr_cat(&cstr_buf, "", 0); - break; - case TOK_CDOUBLE: - cstr_cat(&cstr_buf, "", 0); - break; - case TOK_CLDOUBLE: - cstr_cat(&cstr_buf, "", 0); - break; - case TOK_LINENUM: - cstr_cat(&cstr_buf, "", 0); - break; - - /* above tokens have value, the ones below don't */ - case TOK_LT: - v = '<'; - goto addv; - case TOK_GT: - v = '>'; - goto addv; - case TOK_DOTS: - return strcpy(p, "..."); - case TOK_A_SHL: - return strcpy(p, "<<="); - case TOK_A_SAR: - return strcpy(p, ">>="); - case TOK_EOF: - return strcpy(p, ""); - default: - if (v < TOK_IDENT) { - /* search in two bytes table */ - const unsigned char *q = tok_two_chars; - while (*q) { - if (q[2] == v) { - *p++ = q[0]; - *p++ = q[1]; - *p = '\0'; - return cstr_buf.data; - } - q += 3; - } - if (v >= 127) { - sprintf(cstr_buf.data, "<%02x>", v); - return cstr_buf.data; - } - addv: - *p++ = v; - *p = '\0'; - } else if (v < tok_ident) { - return table_ident[v - TOK_IDENT]->str; - } else if (v >= SYM_FIRST_ANOM) { - /* special name for anonymous symbol */ - sprintf(p, "L.%u", v - SYM_FIRST_ANOM); - } else { - /* should never happen */ - return NULL; - } - break; - } - return cstr_buf.data; -} - -/* return the current character, handling end of block if necessary - (but not stray) */ -ST_FUNC int handle_eob(void) -{ - BufferedFile *bf = file; - int len; - - /* only tries to read if really end of buffer */ - if (bf->buf_ptr >= bf->buf_end) { - if (bf->fd >= 0) { -#if defined(PARSE_DEBUG) - len = 1; -#else - len = IO_BUF_SIZE; -#endif - len = read(bf->fd, bf->buffer, len); - if (len < 0) - len = 0; - } else { - len = 0; - } - total_bytes += len; - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + len; - *bf->buf_end = CH_EOB; - } - if (bf->buf_ptr < bf->buf_end) { - return bf->buf_ptr[0]; - } else { - bf->buf_ptr = bf->buf_end; - return CH_EOF; - } -} - -/* read next char from current input file and handle end of input buffer */ -ST_INLN void inp(void) -{ - ch = *(++(file->buf_ptr)); - /* end of buffer/file handling */ - if (ch == CH_EOB) - ch = handle_eob(); -} - -/* handle '\[\r]\n' */ -static int handle_stray_noerror(void) -{ - while (ch == '\\') { - inp(); - if (ch == '\n') { - file->line_num++; - inp(); - } else if (ch == '\r') { - inp(); - if (ch != '\n') - goto fail; - file->line_num++; - inp(); - } else { - fail: - return 1; - } - } - return 0; -} - -static void handle_stray(void) -{ - if (handle_stray_noerror()) - tcc_error("stray '\\' in program"); -} - -/* skip the stray and handle the \\n case. Output an error if - incorrect char after the stray */ -static int handle_stray1(uint8_t *p) -{ - int c; - - file->buf_ptr = p; - if (p >= file->buf_end) { - c = handle_eob(); - if (c != '\\') - return c; - p = file->buf_ptr; - } - ch = *p; - if (handle_stray_noerror()) { - if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) - tcc_error("stray '\\' in program"); - *--file->buf_ptr = '\\'; - } - p = file->buf_ptr; - c = *p; - return c; -} - -/* handle just the EOB case, but not stray */ -#define PEEKC_EOB(c, p)\ -{\ - p++;\ - c = *p;\ - if (c == '\\') {\ - file->buf_ptr = p;\ - c = handle_eob();\ - p = file->buf_ptr;\ - }\ -} - -/* handle the complicated stray case */ -#define PEEKC(c, p)\ -{\ - p++;\ - c = *p;\ - if (c == '\\') {\ - c = handle_stray1(p);\ - p = file->buf_ptr;\ - }\ -} - -/* input with '\[\r]\n' handling. Note that this function cannot - handle other characters after '\', so you cannot call it inside - strings or comments */ -ST_FUNC void minp(void) -{ - inp(); - if (ch == '\\') - handle_stray(); -} - -/* single line C++ comments */ -static uint8_t *parse_line_comment(uint8_t *p) -{ - int c; - - p++; - for(;;) { - c = *p; - redo: - if (c == '\n' || c == CH_EOF) { - break; - } else if (c == '\\') { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == '\\') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } - } - } else { - goto redo; - } - } else { - p++; - } - } - return p; -} - -/* C comments */ -ST_FUNC uint8_t *parse_comment(uint8_t *p) -{ - int c; - - p++; - for(;;) { - /* fast skip loop */ - for(;;) { - c = *p; - if (c == '\n' || c == '*' || c == '\\') - break; - p++; - c = *p; - if (c == '\n' || c == '*' || c == '\\') - break; - p++; - } - /* now we can handle all the cases */ - if (c == '\n') { - file->line_num++; - p++; - } else if (c == '*') { - p++; - for(;;) { - c = *p; - if (c == '*') { - p++; - } else if (c == '/') { - goto end_of_comment; - } else if (c == '\\') { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == CH_EOF) - tcc_error("unexpected end of file in comment"); - if (c == '\\') { - /* skip '\[\r]\n', otherwise just skip the stray */ - while (c == '\\') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - PEEKC_EOB(c, p); - } - } else { - goto after_star; - } - } - } - } else { - break; - } - } - after_star: ; - } else { - /* stray, eob or eof */ - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == CH_EOF) { - tcc_error("unexpected end of file in comment"); - } else if (c == '\\') { - p++; - } - } - } - end_of_comment: - p++; - return p; -} - -ST_FUNC int set_idnum(int c, int val) -{ - int prev = isidnum_table[c - CH_EOF]; - isidnum_table[c - CH_EOF] = val; - return prev; -} - -#define cinp minp - -static inline void skip_spaces(void) -{ - while (isidnum_table[ch - CH_EOF] & IS_SPC) - cinp(); -} - -static inline int check_space(int t, int *spc) -{ - if (t < 256 && (isidnum_table[t - CH_EOF] & IS_SPC)) { - if (*spc) - return 1; - *spc = 1; - } else - *spc = 0; - return 0; -} - -/* parse a string without interpreting escapes */ -static uint8_t *parse_pp_string(uint8_t *p, - int sep, CString *str) -{ - int c; - p++; - for(;;) { - c = *p; - if (c == sep) { - break; - } else if (c == '\\') { - file->buf_ptr = p; - c = handle_eob(); - p = file->buf_ptr; - if (c == CH_EOF) { - unterminated_string: - /* XXX: indicate line number of start of string */ - tcc_error("missing terminating %c character", sep); - } else if (c == '\\') { - /* escape : just skip \[\r]\n */ - PEEKC_EOB(c, p); - if (c == '\n') { - file->line_num++; - p++; - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c != '\n') - expect("'\n' after '\r'"); - file->line_num++; - p++; - } else if (c == CH_EOF) { - goto unterminated_string; - } else { - if (str) { - cstr_ccat(str, '\\'); - cstr_ccat(str, c); - } - p++; - } - } - } else if (c == '\n') { - file->line_num++; - goto add_char; - } else if (c == '\r') { - PEEKC_EOB(c, p); - if (c != '\n') { - if (str) - cstr_ccat(str, '\r'); - } else { - file->line_num++; - goto add_char; - } - } else { - add_char: - if (str) - cstr_ccat(str, c); - p++; - } - } - p++; - return p; -} - -/* skip block of text until #else, #elif or #endif. skip also pairs of - #if/#endif */ -static void preprocess_skip(void) -{ - int a, start_of_line, c, in_warn_or_error; - uint8_t *p; - - p = file->buf_ptr; - a = 0; -redo_start: - start_of_line = 1; - in_warn_or_error = 0; - for(;;) { - redo_no_start: - c = *p; - switch(c) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - p++; - goto redo_no_start; - case '\n': - file->line_num++; - p++; - goto redo_start; - case '\\': - file->buf_ptr = p; - c = handle_eob(); - if (c == CH_EOF) { - expect("#endif"); - } else if (c == '\\') { - ch = file->buf_ptr[0]; - handle_stray_noerror(); - } - p = file->buf_ptr; - goto redo_no_start; - /* skip strings */ - case '\"': - case '\'': - if (in_warn_or_error) - goto _default; - p = parse_pp_string(p, c, NULL); - break; - /* skip comments */ - case '/': - if (in_warn_or_error) - goto _default; - file->buf_ptr = p; - ch = *p; - minp(); - p = file->buf_ptr; - if (ch == '*') { - p = parse_comment(p); - } else if (ch == '/') { - p = parse_line_comment(p); - } - break; - case '#': - p++; - if (start_of_line) { - file->buf_ptr = p; - next_nomacro(); - p = file->buf_ptr; - if (a == 0 && - (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) - goto the_end; - if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) - a++; - else if (tok == TOK_ENDIF) - a--; - else if( tok == TOK_ERROR || tok == TOK_WARNING) - in_warn_or_error = 1; - else if (tok == TOK_LINEFEED) - goto redo_start; - else if (parse_flags & PARSE_FLAG_ASM_FILE) - p = parse_line_comment(p - 1); - } else if (parse_flags & PARSE_FLAG_ASM_FILE) - p = parse_line_comment(p - 1); - break; -_default: - default: - p++; - break; - } - start_of_line = 0; - } - the_end: ; - file->buf_ptr = p; -} - -#if 0 -/* return the number of additional 'ints' necessary to store the - token */ -static inline int tok_size(const int *p) -{ - switch(*p) { - /* 4 bytes */ - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: - return 1 + 1; - case TOK_STR: - case TOK_LSTR: - case TOK_PPNUM: - case TOK_PPSTR: - return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2); - case TOK_CLONG: - case TOK_CULONG: - return 1 + LONG_SIZE / 4; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: - return 1 + 2; - case TOK_CLDOUBLE: - return 1 + LDOUBLE_SIZE / 4; - default: - return 1 + 0; - } -} -#endif - -/* token string handling */ -ST_INLN void tok_str_new(TokenString *s) -{ - s->str = NULL; - s->len = s->lastlen = 0; - s->allocated_len = 0; - s->last_line_num = -1; -} - -ST_FUNC TokenString *tok_str_alloc(void) -{ - TokenString *str = tal_realloc(tokstr_alloc, 0, sizeof *str); - tok_str_new(str); - return str; -} - -ST_FUNC int *tok_str_dup(TokenString *s) -{ - int *str; - - str = tal_realloc(tokstr_alloc, 0, s->len * sizeof(int)); - memcpy(str, s->str, s->len * sizeof(int)); - return str; -} - -ST_FUNC void tok_str_free_str(int *str) -{ - tal_free(tokstr_alloc, str); -} - -ST_FUNC void tok_str_free(TokenString *str) -{ - tok_str_free_str(str->str); - tal_free(tokstr_alloc, str); -} - -ST_FUNC int *tok_str_realloc(TokenString *s, int new_size) -{ - int *str, size; - - size = s->allocated_len; - if (size < 16) - size = 16; - while (size < new_size) - size = size * 2; - if (size > s->allocated_len) { - str = tal_realloc(tokstr_alloc, s->str, size * sizeof(int)); - s->allocated_len = size; - s->str = str; - } - return s->str; -} - -ST_FUNC void tok_str_add(TokenString *s, int t) -{ - int len, *str; - - len = s->len; - str = s->str; - if (len >= s->allocated_len) - str = tok_str_realloc(s, len + 1); - str[len++] = t; - s->len = len; -} - -ST_FUNC void begin_macro(TokenString *str, int alloc) -{ - str->alloc = alloc; - str->prev = macro_stack; - str->prev_ptr = macro_ptr; - str->save_line_num = file->line_num; - macro_ptr = str->str; - macro_stack = str; -} - -ST_FUNC void end_macro(void) -{ - TokenString *str = macro_stack; - macro_stack = str->prev; - macro_ptr = str->prev_ptr; - file->line_num = str->save_line_num; - if (str->alloc == 2) { - str->alloc = 3; /* just mark as finished */ - } else { - tok_str_free(str); - } -} - -static void tok_str_add2(TokenString *s, int t, CValue *cv) -{ - int len, *str; - - len = s->lastlen = s->len; - str = s->str; - - /* allocate space for worst case */ - if (len + TOK_MAX_SIZE >= s->allocated_len) - str = tok_str_realloc(s, len + TOK_MAX_SIZE + 1); - str[len++] = t; - switch(t) { - case TOK_CINT: - case TOK_CUINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_CFLOAT: - case TOK_LINENUM: -#if LONG_SIZE == 4 - case TOK_CLONG: - case TOK_CULONG: -#endif - str[len++] = cv->tab[0]; - break; - case TOK_PPNUM: - case TOK_PPSTR: - case TOK_STR: - case TOK_LSTR: - { - /* Insert the string into the int array. */ - size_t nb_words = - 1 + (cv->str.size + sizeof(int) - 1) / sizeof(int); - if (len + nb_words >= s->allocated_len) - str = tok_str_realloc(s, len + nb_words + 1); - str[len] = cv->str.size; - memcpy(&str[len + 1], cv->str.data, cv->str.size); - len += nb_words; - } - break; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: -#if LONG_SIZE == 8 - case TOK_CLONG: - case TOK_CULONG: -#endif -#if LDOUBLE_SIZE == 8 - case TOK_CLDOUBLE: -#endif - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - break; -#if LDOUBLE_SIZE == 12 - case TOK_CLDOUBLE: - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - str[len++] = cv->tab[2]; -#elif LDOUBLE_SIZE == 16 - case TOK_CLDOUBLE: - str[len++] = cv->tab[0]; - str[len++] = cv->tab[1]; - str[len++] = cv->tab[2]; - str[len++] = cv->tab[3]; -#elif LDOUBLE_SIZE != 8 -#error add long double size support -#endif - break; - default: - break; - } - s->len = len; -} - -/* add the current parse token in token string 's' */ -ST_FUNC void tok_str_add_tok(TokenString *s) -{ - CValue cval; - - /* save line number info */ - if (file->line_num != s->last_line_num) { - s->last_line_num = file->line_num; - cval.i = s->last_line_num; - tok_str_add2(s, TOK_LINENUM, &cval); - } - tok_str_add2(s, tok, &tokc); -} - -/* get a token from an integer array and increment pointer - accordingly. we code it as a macro to avoid pointer aliasing. */ -static inline void TOK_GET(int *t, const int **pp, CValue *cv) -{ - const int *p = *pp; - int n, *tab; - - tab = cv->tab; - switch(*t = *p++) { -#if LONG_SIZE == 4 - case TOK_CLONG: -#endif - case TOK_CINT: - case TOK_CCHAR: - case TOK_LCHAR: - case TOK_LINENUM: - cv->i = *p++; - break; -#if LONG_SIZE == 4 - case TOK_CULONG: -#endif - case TOK_CUINT: - cv->i = (unsigned)*p++; - break; - case TOK_CFLOAT: - tab[0] = *p++; - break; - case TOK_STR: - case TOK_LSTR: - case TOK_PPNUM: - case TOK_PPSTR: - cv->str.size = *p++; - cv->str.data = p; - p += (cv->str.size + sizeof(int) - 1) / sizeof(int); - break; - case TOK_CDOUBLE: - case TOK_CLLONG: - case TOK_CULLONG: -#if LONG_SIZE == 8 - case TOK_CLONG: - case TOK_CULONG: -#endif - n = 2; - goto copy; - case TOK_CLDOUBLE: -#if LDOUBLE_SIZE == 16 - n = 4; -#elif LDOUBLE_SIZE == 12 - n = 3; -#elif LDOUBLE_SIZE == 8 - n = 2; -#else -# error add long double size support -#endif - copy: - do - *tab++ = *p++; - while (--n); - break; - default: - break; - } - *pp = p; -} - -static int macro_is_equal(const int *a, const int *b) -{ - CValue cv; - int t; - - if (!a || !b) - return 1; - - while (*a && *b) { - /* first time preallocate macro_equal_buf, next time only reset position to start */ - cstr_reset(¯o_equal_buf); - TOK_GET(&t, &a, &cv); - cstr_cat(¯o_equal_buf, get_tok_str(t, &cv), 0); - TOK_GET(&t, &b, &cv); - if (strcmp(macro_equal_buf.data, get_tok_str(t, &cv))) - return 0; - } - return !(*a || *b); -} - -/* defines handling */ -ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) -{ - Sym *s, *o; - - o = define_find(v); - s = sym_push2(&define_stack, v, macro_type, 0); - s->d = str; - s->next = first_arg; - table_ident[v - TOK_IDENT]->sym_define = s; - - if (o && !macro_is_equal(o->d, s->d)) - tcc_warning("%s redefined", get_tok_str(v, NULL)); -} - -/* undefined a define symbol. Its name is just set to zero */ -ST_FUNC void define_undef(Sym *s) -{ - int v = s->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; -} - -ST_INLN Sym *define_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_define; -} - -/* free define stack until top reaches 'b' */ -ST_FUNC void free_defines(Sym *b) -{ - while (define_stack != b) { - Sym *top = define_stack; - define_stack = top->prev; - tok_str_free_str(top->d); - define_undef(top); - sym_free(top); - } - - /* restore remaining (-D or predefined) symbols if they were - #undef'd in the file */ - while (b) { - int v = b->v; - if (v >= TOK_IDENT && v < tok_ident) { - Sym **d = &table_ident[v - TOK_IDENT]->sym_define; - if (!*d) - *d = b; - } - b = b->prev; - } -} - -/* label lookup */ -ST_FUNC Sym *label_find(int v) -{ - v -= TOK_IDENT; - if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) - return NULL; - return table_ident[v]->sym_label; -} - -ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) -{ - Sym *s, **ps; - s = sym_push2(ptop, v, 0, 0); - s->r = flags; - ps = &table_ident[v - TOK_IDENT]->sym_label; - if (ptop == &global_label_stack) { - /* modify the top most local identifier, so that - sym_identifier will point to 's' when popped */ - while (*ps != NULL) - ps = &(*ps)->prev_tok; - } - s->prev_tok = *ps; - *ps = s; - return s; -} - -/* pop labels until element last is reached. Look if any labels are - undefined. Define symbols if '&&label' was used. */ -ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep) -{ - Sym *s, *s1; - for(s = *ptop; s != slast; s = s1) { - s1 = s->prev; - if (s->r == LABEL_DECLARED) { - tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); - } else if (s->r == LABEL_FORWARD) { - tcc_error("label '%s' used but not defined", - get_tok_str(s->v, NULL)); - } else { - if (s->c) { - /* define corresponding symbol. A size of - 1 is put. */ - put_extern_sym(s, cur_text_section, s->jnext, 1); - } - } - /* remove label */ - table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; - if (!keep) - sym_free(s); - } - if (!keep) - *ptop = slast; -} - -/* fake the nth "#if defined test_..." for tcc -dt -run */ -static void maybe_run_test(TCCState *s) -{ - const char *p; - if (s->include_stack_ptr != s->include_stack) - return; - p = get_tok_str(tok, NULL); - if (0 != memcmp(p, "test_", 5)) - return; - if (0 != --s->run_test) - return; - fprintf(s->ppfp, "\n[%s]\n" + !(s->dflag & 32), p), fflush(s->ppfp); - define_push(tok, MACRO_OBJ, NULL, NULL); -} - -/* eval an expression for #if/#elif */ -static int expr_preprocess(void) -{ - int c, t; - TokenString *str; - - str = tok_str_alloc(); - pp_expr = 1; - while (tok != TOK_LINEFEED && tok != TOK_EOF) { - next(); /* do macro subst */ - if (tok == TOK_DEFINED) { - next_nomacro(); - t = tok; - if (t == '(') - next_nomacro(); - if (tok < TOK_IDENT) - expect("identifier"); - if (tcc_state->run_test) - maybe_run_test(tcc_state); - c = define_find(tok) != 0; - if (t == '(') { - next_nomacro(); - if (tok != ')') - expect("')'"); - } - tok = TOK_CINT; - tokc.i = c; - } else if (tok >= TOK_IDENT) { - /* if undefined macro */ - tok = TOK_CINT; - tokc.i = 0; - } - tok_str_add_tok(str); - } - pp_expr = 0; - tok_str_add(str, -1); /* simulate end of file */ - tok_str_add(str, 0); - /* now evaluate C constant expression */ - begin_macro(str, 1); - next(); - c = expr_const(); - end_macro(); - return c != 0; -} - - -/* parse after #define */ -ST_FUNC void parse_define(void) -{ - Sym *s, *first, **ps; - int v, t, varg, is_vaargs, spc; - int saved_parse_flags = parse_flags; - - v = tok; - if (v < TOK_IDENT || v == TOK_DEFINED) - tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc)); - /* XXX: should check if same macro (ANSI) */ - first = NULL; - t = MACRO_OBJ; - /* We have to parse the whole define as if not in asm mode, in particular - no line comment with '#' must be ignored. Also for function - macros the argument list must be parsed without '.' being an ID - character. */ - parse_flags = ((parse_flags & ~PARSE_FLAG_ASM_FILE) | PARSE_FLAG_SPACES); - /* '(' must be just after macro definition for MACRO_FUNC */ - next_nomacro_spc(); - if (tok == '(') { - int dotid = set_idnum('.', 0); - next_nomacro(); - ps = &first; - if (tok != ')') for (;;) { - varg = tok; - next_nomacro(); - is_vaargs = 0; - if (varg == TOK_DOTS) { - varg = TOK___VA_ARGS__; - is_vaargs = 1; - } else if (tok == TOK_DOTS && gnu_ext) { - is_vaargs = 1; - next_nomacro(); - } - if (varg < TOK_IDENT) - bad_list: - tcc_error("bad macro parameter list"); - s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); - *ps = s; - ps = &s->next; - if (tok == ')') - break; - if (tok != ',' || is_vaargs) - goto bad_list; - next_nomacro(); - } - next_nomacro_spc(); - t = MACRO_FUNC; - set_idnum('.', dotid); - } - - tokstr_buf.len = 0; - spc = 2; - parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED; - /* The body of a macro definition should be parsed such that identifiers - are parsed like the file mode determines (i.e. with '.' being an - ID character in asm mode). But '#' should be retained instead of - regarded as line comment leader, so still don't set ASM_FILE - in parse_flags. */ - while (tok != TOK_LINEFEED && tok != TOK_EOF) { - /* remove spaces around ## and after '#' */ - if (TOK_TWOSHARPS == tok) { - if (2 == spc) - goto bad_twosharp; - if (1 == spc) - --tokstr_buf.len; - spc = 3; - tok = TOK_PPJOIN; - } else if ('#' == tok) { - spc = 4; - } else if (check_space(tok, &spc)) { - goto skip; - } - tok_str_add2(&tokstr_buf, tok, &tokc); - skip: - next_nomacro_spc(); - } - - parse_flags = saved_parse_flags; - if (spc == 1) - --tokstr_buf.len; /* remove trailing space */ - tok_str_add(&tokstr_buf, 0); - if (3 == spc) -bad_twosharp: - tcc_error("'##' cannot appear at either end of macro"); - define_push(v, t, tok_str_dup(&tokstr_buf), first); -} - -static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add) -{ - const unsigned char *s; - unsigned int h; - CachedInclude *e; - int i; - - h = TOK_HASH_INIT; - s = (unsigned char *) filename; - while (*s) { -#ifdef _WIN32 - h = TOK_HASH_FUNC(h, toup(*s)); -#else - h = TOK_HASH_FUNC(h, *s); -#endif - s++; - } - h &= (CACHED_INCLUDES_HASH_SIZE - 1); - - i = s1->cached_includes_hash[h]; - for(;;) { - if (i == 0) - break; - e = s1->cached_includes[i - 1]; - if (0 == PATHCMP(e->filename, filename)) - return e; - i = e->hash_next; - } - if (!add) - return NULL; - - e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); - strcpy(e->filename, filename); - e->ifndef_macro = e->once = 0; - dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e); - /* add in hash table */ - e->hash_next = s1->cached_includes_hash[h]; - s1->cached_includes_hash[h] = s1->nb_cached_includes; -#ifdef INC_DEBUG - printf("adding cached '%s'\n", filename); -#endif - return e; -} - -static void pragma_parse(TCCState *s1) -{ - next_nomacro(); - if (tok == TOK_push_macro || tok == TOK_pop_macro) { - int t = tok, v; - Sym *s; - - if (next(), tok != '(') - goto pragma_err; - if (next(), tok != TOK_STR) - goto pragma_err; - v = tok_alloc(tokc.str.data, tokc.str.size - 1)->tok; - if (next(), tok != ')') - goto pragma_err; - if (t == TOK_push_macro) { - while (NULL == (s = define_find(v))) - define_push(v, 0, NULL, NULL); - s->type.ref = s; /* set push boundary */ - } else { - for (s = define_stack; s; s = s->prev) - if (s->v == v && s->type.ref == s) { - s->type.ref = NULL; - break; - } - } - if (s) - table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL; - else - tcc_warning("unbalanced #pragma pop_macro"); - pp_debug_tok = t, pp_debug_symv = v; - - } else if (tok == TOK_once) { - search_cached_include(s1, file->filename, 1)->once = pp_once; - - } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) { - /* tcc -E: keep pragmas below unchanged */ - unget_tok(' '); - unget_tok(TOK_PRAGMA); - unget_tok('#'); - unget_tok(TOK_LINEFEED); - - } else if (tok == TOK_pack) { - /* This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { - stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - int val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) - goto stk_error; - s1->pack_stack_ptr++; - skip(','); - } - if (tok != TOK_CINT) - goto pragma_err; - val = tokc.i; - if (val < 1 || val > 16 || (val & (val - 1)) != 0) - goto pragma_err; - next(); - } - *s1->pack_stack_ptr = val; - } - if (tok != ')') - goto pragma_err; - - } else if (tok == TOK_comment) { - char *p; int t; - next(); - skip('('); - t = tok; - next(); - skip(','); - if (tok != TOK_STR) - goto pragma_err; - p = tcc_strdup((char *)tokc.str.data); - next(); - if (tok != ')') - goto pragma_err; - if (t == TOK_lib) { - dynarray_add(&s1->pragma_libs, &s1->nb_pragma_libs, p); - } else { - if (t == TOK_option) - tcc_set_options(s1, p); - tcc_free(p); - } - - } else if (s1->warn_unsupported) { - tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc)); - } - return; - -pragma_err: - tcc_error("malformed #pragma directive"); - return; -} - -/* is_bof is true if first non space token at beginning of file */ -ST_FUNC void preprocess(int is_bof) -{ - TCCState *s1 = tcc_state; - int i, c, n, saved_parse_flags; - char buf[1024], *q; - Sym *s; - - saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS - | PARSE_FLAG_TOK_NUM - | PARSE_FLAG_TOK_STR - | PARSE_FLAG_LINEFEED - | (parse_flags & PARSE_FLAG_ASM_FILE) - ; - - next_nomacro(); - redo: - switch(tok) { - case TOK_DEFINE: - pp_debug_tok = tok; - next_nomacro(); - pp_debug_symv = tok; - parse_define(); - break; - case TOK_UNDEF: - pp_debug_tok = tok; - next_nomacro(); - pp_debug_symv = tok; - s = define_find(tok); - /* undefine symbol by putting an invalid name */ - if (s) - define_undef(s); - break; - case TOK_INCLUDE: - case TOK_INCLUDE_NEXT: - ch = file->buf_ptr[0]; - /* XXX: incorrect if comments : use next_nomacro with a special mode */ - skip_spaces(); - if (ch == '<') { - c = '>'; - goto read_name; - } else if (ch == '\"') { - c = ch; - read_name: - inp(); - q = buf; - while (ch != c && ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; - if (ch == '\\') { - if (handle_stray_noerror() == 0) - --q; - } else - inp(); - } - *q = '\0'; - minp(); -#if 0 - /* eat all spaces and comments after include */ - /* XXX: slightly incorrect */ - while (ch1 != '\n' && ch1 != CH_EOF) - inp(); -#endif - } else { - int len; - /* computed #include : concatenate everything up to linefeed, - the result must be one of the two accepted forms. - Don't convert pp-tokens to tokens here. */ - parse_flags = (PARSE_FLAG_PREPROCESS - | PARSE_FLAG_LINEFEED - | (parse_flags & PARSE_FLAG_ASM_FILE)); - next(); - buf[0] = '\0'; - while (tok != TOK_LINEFEED) { - pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); - next(); - } - len = strlen(buf); - /* check syntax and remove '<>|""' */ - if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') && - (buf[0] != '<' || buf[len-1] != '>')))) - tcc_error("'#include' expects \"FILENAME\" or "); - c = buf[len-1]; - memmove(buf, buf + 1, len - 2); - buf[len - 2] = '\0'; - } - - if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) - tcc_error("#include recursion too deep"); - /* store current file in stack, but increment stack later below */ - *s1->include_stack_ptr = file; - i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0; - n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths; - for (; i < n; ++i) { - char buf1[sizeof file->filename]; - CachedInclude *e; - const char *path; - - if (i == 0) { - /* check absolute include path */ - if (!IS_ABSPATH(buf)) - continue; - buf1[0] = 0; - - } else if (i == 1) { - /* search in file's dir if "header.h" */ - if (c != '\"') - continue; - /* https://savannah.nongnu.org/bugs/index.php?50847 */ - path = file->true_filename; - pstrncpy(buf1, path, tcc_basename(path) - path); - - } else { - /* search in all the include paths */ - int j = i - 2, k = j - s1->nb_include_paths; - path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k]; - pstrcpy(buf1, sizeof(buf1), path); - pstrcat(buf1, sizeof(buf1), "/"); - } - - pstrcat(buf1, sizeof(buf1), buf); - e = search_cached_include(s1, buf1, 0); - if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) { - /* no need to parse the include because the 'ifndef macro' - is defined (or had #pragma once) */ -#ifdef INC_DEBUG - printf("%s: skipping cached %s\n", file->filename, buf1); -#endif - goto include_done; - } - - if (tcc_open(s1, buf1) < 0) - continue; - - file->include_next_index = i + 1; -#ifdef INC_DEBUG - printf("%s: including %s\n", file->prev->filename, file->filename); -#endif - /* update target deps */ - dynarray_add(&s1->target_deps, &s1->nb_target_deps, - tcc_strdup(buf1)); - /* push current file in stack */ - ++s1->include_stack_ptr; - /* add include file debug info */ - if (s1->do_debug) - put_stabs(file->filename, N_BINCL, 0, 0, 0); - tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; - ch = file->buf_ptr[0]; - goto the_end; - } - tcc_error("include file '%s' not found", buf); -include_done: - break; - case TOK_IFNDEF: - c = 1; - goto do_ifdef; - case TOK_IF: - c = expr_preprocess(); - goto do_if; - case TOK_IFDEF: - c = 0; - do_ifdef: - next_nomacro(); - if (tok < TOK_IDENT) - tcc_error("invalid argument for '#if%sdef'", c ? "n" : ""); - if (is_bof) { - if (c) { -#ifdef INC_DEBUG - printf("#ifndef %s\n", get_tok_str(tok, NULL)); -#endif - file->ifndef_macro = tok; - } - } - c = (define_find(tok) != 0) ^ c; - do_if: - if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) - tcc_error("memory full (ifdef)"); - *s1->ifdef_stack_ptr++ = c; - goto test_skip; - case TOK_ELSE: - if (s1->ifdef_stack_ptr == s1->ifdef_stack) - tcc_error("#else without matching #if"); - if (s1->ifdef_stack_ptr[-1] & 2) - tcc_error("#else after #else"); - c = (s1->ifdef_stack_ptr[-1] ^= 3); - goto test_else; - case TOK_ELIF: - if (s1->ifdef_stack_ptr == s1->ifdef_stack) - tcc_error("#elif without matching #if"); - c = s1->ifdef_stack_ptr[-1]; - if (c > 1) - tcc_error("#elif after #else"); - /* last #if/#elif expression was true: we skip */ - if (c == 1) { - c = 0; - } else { - c = expr_preprocess(); - s1->ifdef_stack_ptr[-1] = c; - } - test_else: - if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) - file->ifndef_macro = 0; - test_skip: - if (!(c & 1)) { - preprocess_skip(); - is_bof = 0; - goto redo; - } - break; - case TOK_ENDIF: - if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) - tcc_error("#endif without matching #if"); - s1->ifdef_stack_ptr--; - /* '#ifndef macro' was at the start of file. Now we check if - an '#endif' is exactly at the end of file */ - if (file->ifndef_macro && - s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { - file->ifndef_macro_saved = file->ifndef_macro; - /* need to set to zero to avoid false matches if another - #ifndef at middle of file */ - file->ifndef_macro = 0; - while (tok != TOK_LINEFEED) - next_nomacro(); - tok_flags |= TOK_FLAG_ENDIF; - goto the_end; - } - break; - case TOK_PPNUM: - n = strtoul((char*)tokc.str.data, &q, 10); - goto _line_num; - case TOK_LINE: - next(); - if (tok != TOK_CINT) - _line_err: - tcc_error("wrong #line format"); - n = tokc.i; - _line_num: - next(); - if (tok != TOK_LINEFEED) { - if (tok == TOK_STR) { - if (file->true_filename == file->filename) - file->true_filename = tcc_strdup(file->filename); - pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data); - } else if (parse_flags & PARSE_FLAG_ASM_FILE) - break; - else - goto _line_err; - --n; - } - if (file->fd > 0) - total_lines += file->line_num - n; - file->line_num = n; - if (s1->do_debug) - put_stabs(file->filename, N_BINCL, 0, 0, 0); - break; - case TOK_ERROR: - case TOK_WARNING: - c = tok; - ch = file->buf_ptr[0]; - skip_spaces(); - q = buf; - while (ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; - if (ch == '\\') { - if (handle_stray_noerror() == 0) - --q; - } else - inp(); - } - *q = '\0'; - if (c == TOK_ERROR) - tcc_error("#error %s", buf); - else - tcc_warning("#warning %s", buf); - break; - case TOK_PRAGMA: - pragma_parse(s1); - break; - case TOK_LINEFEED: - goto the_end; - default: - /* ignore gas line comment in an 'S' file. */ - if (saved_parse_flags & PARSE_FLAG_ASM_FILE) - goto ignore; - if (tok == '!' && is_bof) - /* '!' is ignored at beginning to allow C scripts. */ - goto ignore; - tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc)); - ignore: - file->buf_ptr = parse_line_comment(file->buf_ptr - 1); - goto the_end; - } - /* ignore other preprocess commands or #! for C scripts */ - while (tok != TOK_LINEFEED) - next_nomacro(); - the_end: - parse_flags = saved_parse_flags; -} - -/* evaluate escape codes in a string. */ -static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) -{ - int c, n; - const uint8_t *p; - - p = buf; - for(;;) { - c = *p; - if (c == '\0') - break; - if (c == '\\') { - p++; - /* escape */ - c = *p; - switch(c) { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - /* at most three octal digits */ - n = c - '0'; - p++; - c = *p; - if (isoct(c)) { - n = n * 8 + c - '0'; - p++; - c = *p; - if (isoct(c)) { - n = n * 8 + c - '0'; - p++; - } - } - c = n; - goto add_char_nonext; - case 'x': - case 'u': - case 'U': - p++; - n = 0; - for(;;) { - c = *p; - if (c >= 'a' && c <= 'f') - c = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - c = c - 'A' + 10; - else if (isnum(c)) - c = c - '0'; - else - break; - n = n * 16 + c; - p++; - } - c = n; - goto add_char_nonext; - case 'a': - c = '\a'; - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'e': - if (!gnu_ext) - goto invalid_escape; - c = 27; - break; - case '\'': - case '\"': - case '\\': - case '?': - break; - default: - invalid_escape: - if (c >= '!' && c <= '~') - tcc_warning("unknown escape sequence: \'\\%c\'", c); - else - tcc_warning("unknown escape sequence: \'\\x%x\'", c); - break; - } - } else if (is_long && c >= 0x80) { - /* assume we are processing UTF-8 sequence */ - /* reference: The Unicode Standard, Version 10.0, ch3.9 */ - - int cont; /* count of continuation bytes */ - int skip; /* how many bytes should skip when error occurred */ - int i; - - /* decode leading byte */ - if (c < 0xC2) { - skip = 1; goto invalid_utf8_sequence; - } else if (c <= 0xDF) { - cont = 1; n = c & 0x1f; - } else if (c <= 0xEF) { - cont = 2; n = c & 0xf; - } else if (c <= 0xF4) { - cont = 3; n = c & 0x7; - } else { - skip = 1; goto invalid_utf8_sequence; - } - - /* decode continuation bytes */ - for (i = 1; i <= cont; i++) { - int l = 0x80, h = 0xBF; - - /* adjust limit for second byte */ - if (i == 1) { - switch (c) { - case 0xE0: l = 0xA0; break; - case 0xED: h = 0x9F; break; - case 0xF0: l = 0x90; break; - case 0xF4: h = 0x8F; break; - } - } - - if (p[i] < l || p[i] > h) { - skip = i; goto invalid_utf8_sequence; - } - - n = (n << 6) | (p[i] & 0x3f); - } - - /* advance pointer */ - p += 1 + cont; - c = n; - goto add_char_nonext; - - /* error handling */ - invalid_utf8_sequence: - tcc_warning("ill-formed UTF-8 subsequence starting with: \'\\x%x\'", c); - c = 0xFFFD; - p += skip; - goto add_char_nonext; - - } - p++; - add_char_nonext: - if (!is_long) - cstr_ccat(outstr, c); - else { -#ifdef TCC_TARGET_PE - /* store as UTF-16 */ - if (c < 0x10000) { - cstr_wccat(outstr, c); - } else { - c -= 0x10000; - cstr_wccat(outstr, (c >> 10) + 0xD800); - cstr_wccat(outstr, (c & 0x3FF) + 0xDC00); - } -#else - cstr_wccat(outstr, c); -#endif - } - } - /* add a trailing '\0' */ - if (!is_long) - cstr_ccat(outstr, '\0'); - else - cstr_wccat(outstr, '\0'); -} - -static void parse_string(const char *s, int len) -{ - uint8_t buf[1000], *p = buf; - int is_long, sep; - - if ((is_long = *s == 'L')) - ++s, --len; - sep = *s++; - len -= 2; - if (len >= sizeof buf) - p = tcc_malloc(len + 1); - memcpy(p, s, len); - p[len] = 0; - - cstr_reset(&tokcstr); - parse_escape_string(&tokcstr, p, is_long); - if (p != buf) - tcc_free(p); - - if (sep == '\'') { - int char_size, i, n, c; - /* XXX: make it portable */ - if (!is_long) - tok = TOK_CCHAR, char_size = 1; - else - tok = TOK_LCHAR, char_size = sizeof(nwchar_t); - n = tokcstr.size / char_size - 1; - if (n < 1) - tcc_error("empty character constant"); - if (n > 1) - tcc_warning("multi-character character constant"); - for (c = i = 0; i < n; ++i) { - if (is_long) - c = ((nwchar_t *)tokcstr.data)[i]; - else - c = (c << 8) | ((char *)tokcstr.data)[i]; - } - tokc.i = c; - } else { - tokc.str.size = tokcstr.size; - tokc.str.data = tokcstr.data; - if (!is_long) - tok = TOK_STR; - else - tok = TOK_LSTR; - } -} - -/* we use 64 bit numbers */ -#define BN_SIZE 2 - -/* bn = (bn << shift) | or_val */ -static void bn_lshift(unsigned int *bn, int shift, int or_val) -{ - int i; - unsigned int v; - for(i=0;i> (32 - shift); - } -} - -static void bn_zero(unsigned int *bn) -{ - int i; - for(i=0;i= 'a' && ch <= 'f') - t = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - t = ch - 'A' + 10; - else if (isnum(ch)) - t = ch - '0'; - else - break; - if (t >= b) - break; - if (q >= token_buf + STRING_MAX_SIZE) { - num_too_long: - tcc_error("number too long"); - } - *q++ = ch; - ch = *p++; - } - if (ch == '.' || - ((ch == 'e' || ch == 'E') && b == 10) || - ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { - if (b != 10) { - /* NOTE: strtox should support that for hexa numbers, but - non ISOC99 libcs do not support it, so we prefer to do - it by hand */ - /* hexadecimal or binary floats */ - /* XXX: handle overflows */ - *q = '\0'; - if (b == 16) - shift = 4; - else - shift = 1; - bn_zero(bn); - q = token_buf; - while (1) { - t = *q++; - if (t == '\0') { - break; - } else if (t >= 'a') { - t = t - 'a' + 10; - } else if (t >= 'A') { - t = t - 'A' + 10; - } else { - t = t - '0'; - } - bn_lshift(bn, shift, t); - } - frac_bits = 0; - if (ch == '.') { - ch = *p++; - while (1) { - t = ch; - if (t >= 'a' && t <= 'f') { - t = t - 'a' + 10; - } else if (t >= 'A' && t <= 'F') { - t = t - 'A' + 10; - } else if (t >= '0' && t <= '9') { - t = t - '0'; - } else { - break; - } - if (t >= b) - tcc_error("invalid digit"); - bn_lshift(bn, shift, t); - frac_bits += shift; - ch = *p++; - } - } - if (ch != 'p' && ch != 'P') - expect("exponent"); - ch = *p++; - s = 1; - exp_val = 0; - if (ch == '+') { - ch = *p++; - } else if (ch == '-') { - s = -1; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - exp_val = exp_val * 10 + ch - '0'; - ch = *p++; - } - exp_val = exp_val * s; - - /* now we can generate the number */ - /* XXX: should patch directly float number */ - d = (double)bn[1] * 4294967296.0 + (double)bn[0]; - d = ldexp(d, exp_val - frac_bits); - t = toup(ch); - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - /* float : should handle overflow */ - tokc.f = (float)d; - } else if (t == 'L') { - ch = *p++; -#ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = d; -#else - tok = TOK_CLDOUBLE; - /* XXX: not large enough */ - tokc.ld = (long double)d; -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = d; - } - } else { - /* decimal floats */ - if (ch == '.') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - float_frac_parse: - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - if (ch == 'e' || ch == 'E') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - if (ch == '-' || ch == '+') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - *q = '\0'; - t = toup(ch); - errno = 0; - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - tokc.f = strtof(token_buf, NULL); - } else if (t == 'L') { - ch = *p++; -#ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); -#else - tok = TOK_CLDOUBLE; - tokc.ld = strtold(token_buf, NULL); -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); - } - } - } else { - unsigned long long n, n1; - int lcount, ucount, ov = 0; - const char *p1; - - /* integer number */ - *q = '\0'; - q = token_buf; - if (b == 10 && *q == '0') { - b = 8; - q++; - } - n = 0; - while(1) { - t = *q++; - /* no need for checks except for base 10 / 8 errors */ - if (t == '\0') - break; - else if (t >= 'a') - t = t - 'a' + 10; - else if (t >= 'A') - t = t - 'A' + 10; - else - t = t - '0'; - if (t >= b) - tcc_error("invalid digit"); - n1 = n; - n = n * b + t; - /* detect overflow */ - if (n1 >= 0x1000000000000000ULL && n / b != n1) - ov = 1; - } - - /* Determine the characteristics (unsigned and/or 64bit) the type of - the constant must have according to the constant suffix(es) */ - lcount = ucount = 0; - p1 = p; - for(;;) { - t = toup(ch); - if (t == 'L') { - if (lcount >= 2) - tcc_error("three 'l's in integer constant"); - if (lcount && *(p - 1) != ch) - tcc_error("incorrect integer suffix: %s", p1); - lcount++; - ch = *p++; - } else if (t == 'U') { - if (ucount >= 1) - tcc_error("two 'u's in integer constant"); - ucount++; - ch = *p++; - } else { - break; - } - } - - /* Determine if it needs 64 bits and/or unsigned in order to fit */ - if (ucount == 0 && b == 10) { - if (lcount <= (LONG_SIZE == 4)) { - if (n >= 0x80000000U) - lcount = (LONG_SIZE == 4) + 1; - } - if (n >= 0x8000000000000000ULL) - ov = 1, ucount = 1; - } else { - if (lcount <= (LONG_SIZE == 4)) { - if (n >= 0x100000000ULL) - lcount = (LONG_SIZE == 4) + 1; - else if (n >= 0x80000000U) - ucount = 1; - } - if (n >= 0x8000000000000000ULL) - ucount = 1; - } - - if (ov) - tcc_warning("integer constant overflow"); - - tok = TOK_CINT; - if (lcount) { - tok = TOK_CLONG; - if (lcount == 2) - tok = TOK_CLLONG; - } - if (ucount) - ++tok; /* TOK_CU... */ - tokc.i = n; - } - if (ch) - tcc_error("invalid number\n"); -} - - -#define PARSE2(c1, tok1, c2, tok2) \ - case c1: \ - PEEKC(c, p); \ - if (c == c2) { \ - p++; \ - tok = tok2; \ - } else { \ - tok = tok1; \ - } \ - break; - -/* return next token without macro substitution */ -static inline void next_nomacro1(void) -{ - int t, c, is_long, len; - TokenSym *ts; - uint8_t *p, *p1; - unsigned int h; - - p = file->buf_ptr; - redo_no_start: - c = *p; - switch(c) { - case ' ': - case '\t': - tok = c; - p++; - if (parse_flags & PARSE_FLAG_SPACES) - goto keep_tok_flags; - while (isidnum_table[*p - CH_EOF] & IS_SPC) - ++p; - goto redo_no_start; - case '\f': - case '\v': - case '\r': - p++; - goto redo_no_start; - case '\\': - /* first look if it is in fact an end of buffer */ - c = handle_stray1(p); - p = file->buf_ptr; - if (c == '\\') - goto parse_simple; - if (c != CH_EOF) - goto redo_no_start; - { - TCCState *s1 = tcc_state; - if ((parse_flags & PARSE_FLAG_LINEFEED) - && !(tok_flags & TOK_FLAG_EOF)) { - tok_flags |= TOK_FLAG_EOF; - tok = TOK_LINEFEED; - goto keep_tok_flags; - } else if (!(parse_flags & PARSE_FLAG_PREPROCESS)) { - tok = TOK_EOF; - } else if (s1->ifdef_stack_ptr != file->ifdef_stack_ptr) { - tcc_error("missing #endif"); - } else if (s1->include_stack_ptr == s1->include_stack) { - /* no include left : end of file. */ - tok = TOK_EOF; - } else { - tok_flags &= ~TOK_FLAG_EOF; - /* pop include file */ - - /* test if previous '#endif' was after a #ifdef at - start of file */ - if (tok_flags & TOK_FLAG_ENDIF) { -#ifdef INC_DEBUG - printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); -#endif - search_cached_include(s1, file->filename, 1) - ->ifndef_macro = file->ifndef_macro_saved; - tok_flags &= ~TOK_FLAG_ENDIF; - } - - /* add end of include file debug info */ - if (tcc_state->do_debug) { - put_stabd(N_EINCL, 0, 0); - } - /* pop include stack */ - tcc_close(); - s1->include_stack_ptr--; - p = file->buf_ptr; - if (p == file->buffer) - tok_flags = TOK_FLAG_BOF|TOK_FLAG_BOL; - goto redo_no_start; - } - } - break; - - case '\n': - file->line_num++; - tok_flags |= TOK_FLAG_BOL; - p++; -maybe_newline: - if (0 == (parse_flags & PARSE_FLAG_LINEFEED)) - goto redo_no_start; - tok = TOK_LINEFEED; - goto keep_tok_flags; - - case '#': - /* XXX: simplify */ - PEEKC(c, p); - if ((tok_flags & TOK_FLAG_BOL) && - (parse_flags & PARSE_FLAG_PREPROCESS)) { - file->buf_ptr = p; - preprocess(tok_flags & TOK_FLAG_BOF); - p = file->buf_ptr; - goto maybe_newline; - } else { - if (c == '#') { - p++; - tok = TOK_TWOSHARPS; - } else { - if (parse_flags & PARSE_FLAG_ASM_FILE) { - p = parse_line_comment(p - 1); - goto redo_no_start; - } else { - tok = '#'; - } - } - } - break; - - /* dollar is allowed to start identifiers when not parsing asm */ - case '$': - if (!(isidnum_table[c - CH_EOF] & IS_ID) - || (parse_flags & PARSE_FLAG_ASM_FILE)) - goto parse_simple; - - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '_': - parse_ident_fast: - p1 = p; - h = TOK_HASH_INIT; - h = TOK_HASH_FUNC(h, c); - while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) - h = TOK_HASH_FUNC(h, c); - len = p - p1; - if (c != '\\') { - TokenSym **pts; - - /* fast case : no stray found, so we have the full token - and we have already hashed it */ - h &= (TOK_HASH_SIZE - 1); - pts = &hash_ident[h]; - for(;;) { - ts = *pts; - if (!ts) - break; - if (ts->len == len && !memcmp(ts->str, p1, len)) - goto token_found; - pts = &(ts->hash_next); - } - ts = tok_alloc_new(pts, (char *) p1, len); - token_found: ; - } else { - /* slower case */ - cstr_reset(&tokcstr); - cstr_cat(&tokcstr, (char *) p1, len); - p--; - PEEKC(c, p); - parse_ident_slow: - while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) - { - cstr_ccat(&tokcstr, c); - PEEKC(c, p); - } - ts = tok_alloc(tokcstr.data, tokcstr.size); - } - tok = ts->tok; - break; - case 'L': - t = p[1]; - if (t != '\\' && t != '\'' && t != '\"') { - /* fast case */ - goto parse_ident_fast; - } else { - PEEKC(c, p); - if (c == '\'' || c == '\"') { - is_long = 1; - goto str_const; - } else { - cstr_reset(&tokcstr); - cstr_ccat(&tokcstr, 'L'); - goto parse_ident_slow; - } - } - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': - t = c; - PEEKC(c, p); - /* after the first digit, accept digits, alpha, '.' or sign if - prefixed by 'eEpP' */ - parse_num: - cstr_reset(&tokcstr); - for(;;) { - cstr_ccat(&tokcstr, t); - if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) - || c == '.' - || ((c == '+' || c == '-') - && (((t == 'e' || t == 'E') - && !(parse_flags & PARSE_FLAG_ASM_FILE - /* 0xe+1 is 3 tokens in asm */ - && ((char*)tokcstr.data)[0] == '0' - && toup(((char*)tokcstr.data)[1]) == 'X')) - || t == 'p' || t == 'P')))) - break; - t = c; - PEEKC(c, p); - } - /* We add a trailing '\0' to ease parsing */ - cstr_ccat(&tokcstr, '\0'); - tokc.str.size = tokcstr.size; - tokc.str.data = tokcstr.data; - tok = TOK_PPNUM; - break; - - case '.': - /* special dot handling because it can also start a number */ - PEEKC(c, p); - if (isnum(c)) { - t = '.'; - goto parse_num; - } else if ((isidnum_table['.' - CH_EOF] & IS_ID) - && (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))) { - *--p = c = '.'; - goto parse_ident_fast; - } else if (c == '.') { - PEEKC(c, p); - if (c == '.') { - p++; - tok = TOK_DOTS; - } else { - *--p = '.'; /* may underflow into file->unget[] */ - tok = '.'; - } - } else { - tok = '.'; - } - break; - case '\'': - case '\"': - is_long = 0; - str_const: - cstr_reset(&tokcstr); - if (is_long) - cstr_ccat(&tokcstr, 'L'); - cstr_ccat(&tokcstr, c); - p = parse_pp_string(p, c, &tokcstr); - cstr_ccat(&tokcstr, c); - cstr_ccat(&tokcstr, '\0'); - tokc.str.size = tokcstr.size; - tokc.str.data = tokcstr.data; - tok = TOK_PPSTR; - break; - - case '<': - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_LE; - } else if (c == '<') { - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_A_SHL; - } else { - tok = TOK_SHL; - } - } else { - tok = TOK_LT; - } - break; - case '>': - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_GE; - } else if (c == '>') { - PEEKC(c, p); - if (c == '=') { - p++; - tok = TOK_A_SAR; - } else { - tok = TOK_SAR; - } - } else { - tok = TOK_GT; - } - break; - - case '&': - PEEKC(c, p); - if (c == '&') { - p++; - tok = TOK_LAND; - } else if (c == '=') { - p++; - tok = TOK_A_AND; - } else { - tok = '&'; - } - break; - - case '|': - PEEKC(c, p); - if (c == '|') { - p++; - tok = TOK_LOR; - } else if (c == '=') { - p++; - tok = TOK_A_OR; - } else { - tok = '|'; - } - break; - - case '+': - PEEKC(c, p); - if (c == '+') { - p++; - tok = TOK_INC; - } else if (c == '=') { - p++; - tok = TOK_A_ADD; - } else { - tok = '+'; - } - break; - - case '-': - PEEKC(c, p); - if (c == '-') { - p++; - tok = TOK_DEC; - } else if (c == '=') { - p++; - tok = TOK_A_SUB; - } else if (c == '>') { - p++; - tok = TOK_ARROW; - } else { - tok = '-'; - } - break; - - PARSE2('!', '!', '=', TOK_NE) - PARSE2('=', '=', '=', TOK_EQ) - PARSE2('*', '*', '=', TOK_A_MUL) - PARSE2('%', '%', '=', TOK_A_MOD) - PARSE2('^', '^', '=', TOK_A_XOR) - - /* comments or operator */ - case '/': - PEEKC(c, p); - if (c == '*') { - p = parse_comment(p); - /* comments replaced by a blank */ - tok = ' '; - goto keep_tok_flags; - } else if (c == '/') { - p = parse_line_comment(p); - tok = ' '; - goto keep_tok_flags; - } else if (c == '=') { - p++; - tok = TOK_A_DIV; - } else { - tok = '/'; - } - break; - - /* simple tokens */ - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case ',': - case ';': - case ':': - case '?': - case '~': - case '@': /* only used in assembler */ - parse_simple: - tok = c; - p++; - break; - default: - if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */ - goto parse_ident_fast; - if (parse_flags & PARSE_FLAG_ASM_FILE) - goto parse_simple; - tcc_error("unrecognized character \\x%02x", c); - break; - } - tok_flags = 0; -keep_tok_flags: - file->buf_ptr = p; -#if defined(PARSE_DEBUG) - printf("token = %d %s\n", tok, get_tok_str(tok, &tokc)); -#endif -} - -/* return next token without macro substitution. Can read input from - macro_ptr buffer */ -static void next_nomacro_spc(void) -{ - if (macro_ptr) { - redo: - tok = *macro_ptr; - if (tok) { - TOK_GET(&tok, ¯o_ptr, &tokc); - if (tok == TOK_LINENUM) { - file->line_num = tokc.i; - goto redo; - } - } - } else { - next_nomacro1(); - } - //printf("token = %s\n", get_tok_str(tok, &tokc)); -} - -ST_FUNC void next_nomacro(void) -{ - do { - next_nomacro_spc(); - } while (tok < 256 && (isidnum_table[tok - CH_EOF] & IS_SPC)); -} - - -static void macro_subst( - TokenString *tok_str, - Sym **nested_list, - const int *macro_str - ); - -/* substitute arguments in replacement lists in macro_str by the values in - args (field d) and return allocated string */ -static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) -{ - int t, t0, t1, spc; - const int *st; - Sym *s; - CValue cval; - TokenString str; - CString cstr; - - tok_str_new(&str); - t0 = t1 = 0; - while(1) { - TOK_GET(&t, ¯o_str, &cval); - if (!t) - break; - if (t == '#') { - /* stringize */ - TOK_GET(&t, ¯o_str, &cval); - if (!t) - goto bad_stringy; - s = sym_find2(args, t); - if (s) { - cstr_new(&cstr); - cstr_ccat(&cstr, '\"'); - st = s->d; - spc = 0; - while (*st >= 0) { - TOK_GET(&t, &st, &cval); - if (t != TOK_PLCHLDR - && t != TOK_NOSUBST - && 0 == check_space(t, &spc)) { - const char *s = get_tok_str(t, &cval); - while (*s) { - if (t == TOK_PPSTR && *s != '\'') - add_char(&cstr, *s); - else - cstr_ccat(&cstr, *s); - ++s; - } - } - } - cstr.size -= spc; - cstr_ccat(&cstr, '\"'); - cstr_ccat(&cstr, '\0'); -#ifdef PP_DEBUG - printf("\nstringize: <%s>\n", (char *)cstr.data); -#endif - /* add string */ - cval.str.size = cstr.size; - cval.str.data = cstr.data; - tok_str_add2(&str, TOK_PPSTR, &cval); - cstr_free(&cstr); - } else { - bad_stringy: - expect("macro parameter after '#'"); - } - } else if (t >= TOK_IDENT) { - s = sym_find2(args, t); - if (s) { - int l0 = str.len; - st = s->d; - /* if '##' is present before or after, no arg substitution */ - if (*macro_str == TOK_PPJOIN || t1 == TOK_PPJOIN) { - /* special case for var arg macros : ## eats the ',' - if empty VA_ARGS variable. */ - if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) { - if (*st <= 0) { - /* suppress ',' '##' */ - str.len -= 2; - } else { - /* suppress '##' and add variable */ - str.len--; - goto add_var; - } - } - } else { - add_var: - if (!s->next) { - /* Expand arguments tokens and store them. In most - cases we could also re-expand each argument if - used multiple times, but not if the argument - contains the __COUNTER__ macro. */ - TokenString str2; - sym_push2(&s->next, s->v, s->type.t, 0); - tok_str_new(&str2); - macro_subst(&str2, nested_list, st); - tok_str_add(&str2, 0); - s->next->d = str2.str; - } - st = s->next->d; - } - for(;;) { - int t2; - TOK_GET(&t2, &st, &cval); - if (t2 <= 0) - break; - tok_str_add2(&str, t2, &cval); - } - if (str.len == l0) /* expanded to empty string */ - tok_str_add(&str, TOK_PLCHLDR); - } else { - tok_str_add(&str, t); - } - } else { - tok_str_add2(&str, t, &cval); - } - t0 = t1, t1 = t; - } - tok_str_add(&str, 0); - return str.str; -} - -static char const ab_month_name[12][4] = -{ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2) -{ - CString cstr; - int n, ret = 1; - - cstr_new(&cstr); - if (t1 != TOK_PLCHLDR) - cstr_cat(&cstr, get_tok_str(t1, v1), -1); - n = cstr.size; - if (t2 != TOK_PLCHLDR) - cstr_cat(&cstr, get_tok_str(t2, v2), -1); - cstr_ccat(&cstr, '\0'); - - tcc_open_bf(tcc_state, ":paste:", cstr.size); - memcpy(file->buffer, cstr.data, cstr.size); - tok_flags = 0; - for (;;) { - next_nomacro1(); - if (0 == *file->buf_ptr) - break; - if (is_space(tok)) - continue; - tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid" - " preprocessing token", n, cstr.data, (char*)cstr.data + n); - ret = 0; - break; - } - tcc_close(); - //printf("paste <%s>\n", (char*)cstr.data); - cstr_free(&cstr); - return ret; -} - -/* handle the '##' operator. Return NULL if no '##' seen. Otherwise - return the resulting string (which must be freed). */ -static inline int *macro_twosharps(const int *ptr0) -{ - int t; - CValue cval; - TokenString macro_str1; - int start_of_nosubsts = -1; - const int *ptr; - - /* we search the first '##' */ - for (ptr = ptr0;;) { - TOK_GET(&t, &ptr, &cval); - if (t == TOK_PPJOIN) - break; - if (t == 0) - return NULL; - } - - tok_str_new(¯o_str1); - - //tok_print(" $$$", ptr0); - for (ptr = ptr0;;) { - TOK_GET(&t, &ptr, &cval); - if (t == 0) - break; - if (t == TOK_PPJOIN) - continue; - while (*ptr == TOK_PPJOIN) { - int t1; CValue cv1; - /* given 'a##b', remove nosubsts preceding 'a' */ - if (start_of_nosubsts >= 0) - macro_str1.len = start_of_nosubsts; - /* given 'a##b', remove nosubsts preceding 'b' */ - while ((t1 = *++ptr) == TOK_NOSUBST) - ; - if (t1 && t1 != TOK_PPJOIN) { - TOK_GET(&t1, &ptr, &cv1); - if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) { - if (paste_tokens(t, &cval, t1, &cv1)) { - t = tok, cval = tokc; - } else { - tok_str_add2(¯o_str1, t, &cval); - t = t1, cval = cv1; - } - } - } - } - if (t == TOK_NOSUBST) { - if (start_of_nosubsts < 0) - start_of_nosubsts = macro_str1.len; - } else { - start_of_nosubsts = -1; - } - tok_str_add2(¯o_str1, t, &cval); - } - tok_str_add(¯o_str1, 0); - //tok_print(" ###", macro_str1.str); - return macro_str1.str; -} - -/* peek or read [ws_str == NULL] next token from function macro call, - walking up macro levels up to the file if necessary */ -static int next_argstream(Sym **nested_list, TokenString *ws_str) -{ - int t; - const int *p; - Sym *sa; - - for (;;) { - if (macro_ptr) { - p = macro_ptr, t = *p; - if (ws_str) { - while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t) - tok_str_add(ws_str, t), t = *++p; - } - if (t == 0) { - end_macro(); - /* also, end of scope for nested defined symbol */ - sa = *nested_list; - while (sa && sa->v == 0) - sa = sa->prev; - if (sa) - sa->v = 0; - continue; - } - } else { - ch = handle_eob(); - if (ws_str) { - while (is_space(ch) || ch == '\n' || ch == '/') { - if (ch == '/') { - int c; - uint8_t *p = file->buf_ptr; - PEEKC(c, p); - if (c == '*') { - p = parse_comment(p); - file->buf_ptr = p - 1; - } else if (c == '/') { - p = parse_line_comment(p); - file->buf_ptr = p - 1; - } else - break; - ch = ' '; - } - if (ch == '\n') - file->line_num++; - if (!(ch == '\f' || ch == '\v' || ch == '\r')) - tok_str_add(ws_str, ch); - cinp(); - } - } - t = ch; - } - - if (ws_str) - return t; - next_nomacro_spc(); - return tok; - } -} - -/* do macro substitution of current token with macro 's' and add - result to (tok_str,tok_len). 'nested_list' is the list of all - macros we got inside to avoid recursing. Return non zero if no - substitution needs to be done */ -static int macro_subst_tok( - TokenString *tok_str, - Sym **nested_list, - Sym *s) -{ - Sym *args, *sa, *sa1; - int parlevel, t, t1, spc; - TokenString str; - char *cstrval; - CValue cval; - CString cstr; - char buf[32]; - - /* if symbol is a macro, prepare substitution */ - /* special macros */ - if (tok == TOK___LINE__ || tok == TOK___COUNTER__) { - t = tok == TOK___LINE__ ? file->line_num : pp_counter++; - snprintf(buf, sizeof(buf), "%d", t); - cstrval = buf; - t1 = TOK_PPNUM; - goto add_cstr1; - } else if (tok == TOK___FILE__) { - cstrval = file->filename; - goto add_cstr; - } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { - time_t ti; - struct tm *tm; - - time(&ti); - tm = localtime(&ti); - if (tok == TOK___DATE__) { - snprintf(buf, sizeof(buf), "%s %2d %d", - ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); - } else { - snprintf(buf, sizeof(buf), "%02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - } - cstrval = buf; - add_cstr: - t1 = TOK_STR; - add_cstr1: - cstr_new(&cstr); - cstr_cat(&cstr, cstrval, 0); - cval.str.size = cstr.size; - cval.str.data = cstr.data; - tok_str_add2(tok_str, t1, &cval); - cstr_free(&cstr); - } else if (s->d) { - int saved_parse_flags = parse_flags; - int *joined_str = NULL; - int *mstr = s->d; - - if (s->type.t == MACRO_FUNC) { - /* whitespace between macro name and argument list */ - TokenString ws_str; - tok_str_new(&ws_str); - - spc = 0; - parse_flags |= PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED - | PARSE_FLAG_ACCEPT_STRAYS; - - /* get next token from argument stream */ - t = next_argstream(nested_list, &ws_str); - if (t != '(') { - /* not a macro substitution after all, restore the - * macro token plus all whitespace we've read. - * whitespace is intentionally not merged to preserve - * newlines. */ - parse_flags = saved_parse_flags; - tok_str_add(tok_str, tok); - if (parse_flags & PARSE_FLAG_SPACES) { - int i; - for (i = 0; i < ws_str.len; i++) - tok_str_add(tok_str, ws_str.str[i]); - } - tok_str_free_str(ws_str.str); - return 0; - } else { - tok_str_free_str(ws_str.str); - } - do { - next_nomacro(); /* eat '(' */ - } while (tok == TOK_PLCHLDR); - - /* argument macro */ - args = NULL; - sa = s->next; - /* NOTE: empty args are allowed, except if no args */ - for(;;) { - do { - next_argstream(nested_list, NULL); - } while (is_space(tok) || TOK_LINEFEED == tok); - empty_arg: - /* handle '()' case */ - if (!args && !sa && tok == ')') - break; - if (!sa) - tcc_error("macro '%s' used with too many args", - get_tok_str(s->v, 0)); - tok_str_new(&str); - parlevel = spc = 0; - /* NOTE: non zero sa->t indicates VA_ARGS */ - while ((parlevel > 0 || - (tok != ')' && - (tok != ',' || sa->type.t)))) { - if (tok == TOK_EOF || tok == 0) - break; - if (tok == '(') - parlevel++; - else if (tok == ')') - parlevel--; - if (tok == TOK_LINEFEED) - tok = ' '; - if (!check_space(tok, &spc)) - tok_str_add2(&str, tok, &tokc); - next_argstream(nested_list, NULL); - } - if (parlevel) - expect(")"); - str.len -= spc; - tok_str_add(&str, -1); - tok_str_add(&str, 0); - sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); - sa1->d = str.str; - sa = sa->next; - if (tok == ')') { - /* special case for gcc var args: add an empty - var arg argument if it is omitted */ - if (sa && sa->type.t && gnu_ext) - goto empty_arg; - break; - } - if (tok != ',') - expect(","); - } - if (sa) { - tcc_error("macro '%s' used with too few args", - get_tok_str(s->v, 0)); - } - - parse_flags = saved_parse_flags; - - /* now subst each arg */ - mstr = macro_arg_subst(nested_list, mstr, args); - /* free memory */ - sa = args; - while (sa) { - sa1 = sa->prev; - tok_str_free_str(sa->d); - if (sa->next) { - tok_str_free_str(sa->next->d); - sym_free(sa->next); - } - sym_free(sa); - sa = sa1; - } - } - - sym_push2(nested_list, s->v, 0, 0); - parse_flags = saved_parse_flags; - joined_str = macro_twosharps(mstr); - macro_subst(tok_str, nested_list, joined_str ? joined_str : mstr); - - /* pop nested defined symbol */ - sa1 = *nested_list; - *nested_list = sa1->prev; - sym_free(sa1); - if (joined_str) - tok_str_free_str(joined_str); - if (mstr != s->d) - tok_str_free_str(mstr); - } - return 0; -} - -/* do macro substitution of macro_str and add result to - (tok_str,tok_len). 'nested_list' is the list of all macros we got - inside to avoid recursing. */ -static void macro_subst( - TokenString *tok_str, - Sym **nested_list, - const int *macro_str - ) -{ - Sym *s; - int t, spc, nosubst; - CValue cval; - - spc = nosubst = 0; - - while (1) { - TOK_GET(&t, ¯o_str, &cval); - if (t <= 0) - break; - - if (t >= TOK_IDENT && 0 == nosubst) { - s = define_find(t); - if (s == NULL) - goto no_subst; - - /* if nested substitution, do nothing */ - if (sym_find2(*nested_list, t)) { - /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ - tok_str_add2(tok_str, TOK_NOSUBST, NULL); - goto no_subst; - } - - { - TokenString str; - str.str = (int*)macro_str; - begin_macro(&str, 2); - - tok = t; - macro_subst_tok(tok_str, nested_list, s); - - if (str.alloc == 3) { - /* already finished by reading function macro arguments */ - break; - } - - macro_str = macro_ptr; - end_macro (); - } - if (tok_str->len) - spc = is_space(t = tok_str->str[tok_str->lastlen]); - } else { - if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) - tcc_error("stray '\\' in program"); -no_subst: - if (!check_space(t, &spc)) - tok_str_add2(tok_str, t, &cval); - - if (nosubst) { - if (nosubst > 1 && (spc || (++nosubst == 3 && t == '('))) - continue; - nosubst = 0; - } - if (t == TOK_NOSUBST) - nosubst = 1; - } - /* GCC supports 'defined' as result of a macro substitution */ - if (t == TOK_DEFINED && pp_expr) - nosubst = 2; - } -} - -/* return next token with macro substitution */ -ST_FUNC void next(void) -{ - redo: - if (parse_flags & PARSE_FLAG_SPACES) - next_nomacro_spc(); - else - next_nomacro(); - - if (macro_ptr) { - if (tok == TOK_NOSUBST || tok == TOK_PLCHLDR) { - /* discard preprocessor markers */ - goto redo; - } else if (tok == 0) { - /* end of macro or unget token string */ - end_macro(); - goto redo; - } - } else if (tok >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) { - Sym *s; - /* if reading from file, try to substitute macros */ - s = define_find(tok); - if (s) { - Sym *nested_list = NULL; - tokstr_buf.len = 0; - macro_subst_tok(&tokstr_buf, &nested_list, s); - tok_str_add(&tokstr_buf, 0); - begin_macro(&tokstr_buf, 2); - goto redo; - } - } - /* convert preprocessor tokens into C tokens */ - if (tok == TOK_PPNUM) { - if (parse_flags & PARSE_FLAG_TOK_NUM) - parse_number((char *)tokc.str.data); - } else if (tok == TOK_PPSTR) { - if (parse_flags & PARSE_FLAG_TOK_STR) - parse_string((char *)tokc.str.data, tokc.str.size - 1); - } -} - -/* push back current token and set current token to 'last_tok'. Only - identifier case handled for labels. */ -ST_INLN void unget_tok(int last_tok) -{ - - TokenString *str = tok_str_alloc(); - tok_str_add2(str, tok, &tokc); - tok_str_add(str, 0); - begin_macro(str, 1); - tok = last_tok; -} - -ST_FUNC void preprocess_start(TCCState *s1, int is_asm) -{ - CString cstr; - int i; - - s1->include_stack_ptr = s1->include_stack; - s1->ifdef_stack_ptr = s1->ifdef_stack; - file->ifdef_stack_ptr = s1->ifdef_stack_ptr; - pp_expr = 0; - pp_counter = 0; - pp_debug_tok = pp_debug_symv = 0; - pp_once++; - pvtop = vtop = vstack - 1; - s1->pack_stack[0] = 0; - s1->pack_stack_ptr = s1->pack_stack; - - set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0); - set_idnum('.', is_asm ? IS_ID : 0); - - cstr_new(&cstr); - cstr_cat(&cstr, "\"", -1); - cstr_cat(&cstr, file->filename, -1); - cstr_cat(&cstr, "\"", 0); - tcc_define_symbol(s1, "__BASE_FILE__", cstr.data); - - cstr_reset(&cstr); - for (i = 0; i < s1->nb_cmd_include_files; i++) { - cstr_cat(&cstr, "#include \"", -1); - cstr_cat(&cstr, s1->cmd_include_files[i], -1); - cstr_cat(&cstr, "\"\n", -1); - } - if (cstr.size) { - *s1->include_stack_ptr++ = file; - tcc_open_bf(s1, "", cstr.size); - memcpy(file->buffer, cstr.data, cstr.size); - } - cstr_free(&cstr); - - if (is_asm) - tcc_define_symbol(s1, "__ASSEMBLER__", NULL); - - parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; -} - -/* cleanup from error/setjmp */ -ST_FUNC void preprocess_end(TCCState *s1) -{ - while (macro_stack) - end_macro(); - macro_ptr = NULL; -} - -ST_FUNC void tccpp_new(TCCState *s) -{ - int i, c; - const char *p, *r; - - /* might be used in error() before preprocess_start() */ - s->include_stack_ptr = s->include_stack; - s->ppfp = stdout; - - /* init isid table */ - for(i = CH_EOF; i<128; i++) - set_idnum(i, - is_space(i) ? IS_SPC - : isid(i) ? IS_ID - : isnum(i) ? IS_NUM - : 0); - - for(i = 128; i<256; i++) - set_idnum(i, IS_ID); - - /* init allocators */ - tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE); - tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE); - tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE); - - memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); - cstr_new(&cstr_buf); - cstr_realloc(&cstr_buf, STRING_MAX_SIZE); - tok_str_new(&tokstr_buf); - tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE); - - tok_ident = TOK_IDENT; - p = tcc_keywords; - while (*p) { - r = p; - for(;;) { - c = *r++; - if (c == '\0') - break; - } - tok_alloc(p, r - p - 1); - p = r; - } -} - -ST_FUNC void tccpp_delete(TCCState *s) -{ - int i, n; - - /* free -D and compiler defines */ - free_defines(NULL); - - /* free tokens */ - n = tok_ident - TOK_IDENT; - for(i = 0; i < n; i++) - tal_free(toksym_alloc, table_ident[i]); - tcc_free(table_ident); - table_ident = NULL; - - /* free static buffers */ - cstr_free(&tokcstr); - cstr_free(&cstr_buf); - cstr_free(¯o_equal_buf); - tok_str_free_str(tokstr_buf.str); - - /* free allocators */ - tal_delete(toksym_alloc); - toksym_alloc = NULL; - tal_delete(tokstr_alloc); - tokstr_alloc = NULL; - tal_delete(cstr_alloc); - cstr_alloc = NULL; -} - -/* ------------------------------------------------------------------------- */ -/* tcc -E [-P[1]] [-dD} support */ - -static void tok_print(const char *msg, const int *str) -{ - FILE *fp; - int t, s = 0; - CValue cval; - - fp = tcc_state->ppfp; - fprintf(fp, "%s", msg); - while (str) { - TOK_GET(&t, &str, &cval); - if (!t) - break; - fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1; - } - fprintf(fp, "\n"); -} - -static void pp_line(TCCState *s1, BufferedFile *f, int level) -{ - int d = f->line_num - f->line_ref; - - if (s1->dflag & 4) - return; - - if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_NONE) { - ; - } else if (level == 0 && f->line_ref && d < 8) { - while (d > 0) - fputs("\n", s1->ppfp), --d; - } else if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_STD) { - fprintf(s1->ppfp, "#line %d \"%s\"\n", f->line_num, f->filename); - } else { - fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename, - level > 0 ? " 1" : level < 0 ? " 2" : ""); - } - f->line_ref = f->line_num; -} - -static void define_print(TCCState *s1, int v) -{ - FILE *fp; - Sym *s; - - s = define_find(v); - if (NULL == s || NULL == s->d) - return; - - fp = s1->ppfp; - fprintf(fp, "#define %s", get_tok_str(v, NULL)); - if (s->type.t == MACRO_FUNC) { - Sym *a = s->next; - fprintf(fp,"("); - if (a) - for (;;) { - fprintf(fp,"%s", get_tok_str(a->v & ~SYM_FIELD, NULL)); - if (!(a = a->next)) - break; - fprintf(fp,","); - } - fprintf(fp,")"); - } - tok_print("", s->d); -} - -static void pp_debug_defines(TCCState *s1) -{ - int v, t; - const char *vs; - FILE *fp; - - t = pp_debug_tok; - if (t == 0) - return; - - file->line_num--; - pp_line(s1, file, 0); - file->line_ref = ++file->line_num; - - fp = s1->ppfp; - v = pp_debug_symv; - vs = get_tok_str(v, NULL); - if (t == TOK_DEFINE) { - define_print(s1, v); - } else if (t == TOK_UNDEF) { - fprintf(fp, "#undef %s\n", vs); - } else if (t == TOK_push_macro) { - fprintf(fp, "#pragma push_macro(\"%s\")\n", vs); - } else if (t == TOK_pop_macro) { - fprintf(fp, "#pragma pop_macro(\"%s\")\n", vs); - } - pp_debug_tok = 0; -} - -static void pp_debug_builtins(TCCState *s1) -{ - int v; - for (v = TOK_IDENT; v < tok_ident; ++v) - define_print(s1, v); -} - -/* Add a space between tokens a and b to avoid unwanted textual pasting */ -static int pp_need_space(int a, int b) -{ - return 'E' == a ? '+' == b || '-' == b - : '+' == a ? TOK_INC == b || '+' == b - : '-' == a ? TOK_DEC == b || '-' == b - : a >= TOK_IDENT ? b >= TOK_IDENT - : a == TOK_PPNUM ? b >= TOK_IDENT - : 0; -} - -/* maybe hex like 0x1e */ -static int pp_check_he0xE(int t, const char *p) -{ - if (t == TOK_PPNUM && toup(strchr(p, 0)[-1]) == 'E') - return 'E'; - return t; -} - -/* Preprocess the current file */ -ST_FUNC int tcc_preprocess(TCCState *s1) -{ - BufferedFile **iptr; - int token_seen, spcs, level; - const char *p; - char white[400]; - - parse_flags = PARSE_FLAG_PREPROCESS - | (parse_flags & PARSE_FLAG_ASM_FILE) - | PARSE_FLAG_LINEFEED - | PARSE_FLAG_SPACES - | PARSE_FLAG_ACCEPT_STRAYS - ; - /* Credits to Fabrice Bellard's initial revision to demonstrate its - capability to compile and run itself, provided all numbers are - given as decimals. tcc -E -P10 will do. */ - if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_P10) - parse_flags |= PARSE_FLAG_TOK_NUM, s1->Pflag = 1; - -#ifdef PP_BENCH - /* for PP benchmarks */ - do next(); while (tok != TOK_EOF); - return 0; -#endif - - if (s1->dflag & 1) { - pp_debug_builtins(s1); - s1->dflag &= ~1; - } - - token_seen = TOK_LINEFEED, spcs = 0; - pp_line(s1, file, 0); - for (;;) { - iptr = s1->include_stack_ptr; - next(); - if (tok == TOK_EOF) - break; - - level = s1->include_stack_ptr - iptr; - if (level) { - if (level > 0) - pp_line(s1, *iptr, 0); - pp_line(s1, file, level); - } - if (s1->dflag & 7) { - pp_debug_defines(s1); - if (s1->dflag & 4) - continue; - } - - if (is_space(tok)) { - if (spcs < sizeof white - 1) - white[spcs++] = tok; - continue; - } else if (tok == TOK_LINEFEED) { - spcs = 0; - if (token_seen == TOK_LINEFEED) - continue; - ++file->line_ref; - } else if (token_seen == TOK_LINEFEED) { - pp_line(s1, file, 0); - } else if (spcs == 0 && pp_need_space(token_seen, tok)) { - white[spcs++] = ' '; - } - - white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0; - fputs(p = get_tok_str(tok, &tokc), s1->ppfp); - token_seen = pp_check_he0xE(tok, p); - } - return 0; -} - -/* ------------------------------------------------------------------------- */ diff --git a/tinyc/tccrun.c b/tinyc/tccrun.c deleted file mode 100644 index b9a052b19..000000000 --- a/tinyc/tccrun.c +++ /dev/null @@ -1,840 +0,0 @@ -/* - * TCC - Tiny C Compiler - Support for -run switch - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "tcc.h" - -/* only native compiler supports -run */ -#ifdef TCC_IS_NATIVE - -#ifndef _WIN32 -# include -#endif - -#ifdef CONFIG_TCC_BACKTRACE -# ifndef _WIN32 -# include -# ifndef __OpenBSD__ -# include -# endif -# else -# define ucontext_t CONTEXT -# endif -ST_DATA int rt_num_callers = 6; -ST_DATA const char **rt_bound_error_msg; -ST_DATA void *rt_prog_main; -static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level); -static void rt_error(ucontext_t *uc, const char *fmt, ...); -static void set_exception_handler(void); -#endif - -static void set_pages_executable(void *ptr, unsigned long length); -static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff); - -#ifdef _WIN64 -static void *win64_add_function_table(TCCState *s1); -static void win64_del_function_table(void *); -#endif - -/* ------------------------------------------------------------- */ -/* Do all relocations (needed before using tcc_get_symbol()) - Returns -1 on error. */ - -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr) -{ - int size; - addr_t ptr_diff = 0; - - if (TCC_RELOCATE_AUTO != ptr) - return tcc_relocate_ex(s1, ptr, 0); - - size = tcc_relocate_ex(s1, NULL, 0); - if (size < 0) - return -1; - -#ifdef HAVE_SELINUX -{ - /* Using mmap instead of malloc */ - void *prx; - char tmpfname[] = "/tmp/.tccrunXXXXXX"; - int fd = mkstemp(tmpfname); - unlink(tmpfname); - ftruncate(fd, size); - - ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); - if (ptr == MAP_FAILED || prx == MAP_FAILED) - tcc_error("tccrun: could not map memory"); - dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size); - dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx); - ptr_diff = (char*)prx - (char*)ptr; -} -#else - ptr = tcc_malloc(size); -#endif - tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */ - dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr); - return 0; -} - -ST_FUNC void tcc_run_free(TCCState *s1) -{ - int i; - - for (i = 0; i < s1->nb_runtime_mem; ++i) { -#ifdef HAVE_SELINUX - unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++]; - munmap(s1->runtime_mem[i++], size); - munmap(s1->runtime_mem[i], size); -#else -#ifdef _WIN64 - win64_del_function_table(*(void**)s1->runtime_mem[i]); -#endif - tcc_free(s1->runtime_mem[i]); -#endif - } - tcc_free(s1->runtime_mem); -} - -/* launch the compiled program with the given arguments */ -LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) -{ - int (*prog_main)(int, char **); - - s1->runtime_main = "main"; - if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main)) - return 0; - if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) - return -1; - prog_main = tcc_get_symbol_err(s1, s1->runtime_main); - -#ifdef CONFIG_TCC_BACKTRACE - if (s1->do_debug) { - set_exception_handler(); - rt_prog_main = prog_main; - } -#endif - - errno = 0; /* clean errno value */ - -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) { - void (*bound_init)(void); - void (*bound_exit)(void); - void (*bound_new_region)(void *p, addr_t size); - int (*bound_delete_region)(void *p); - int i, ret; - - /* set error function */ - rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); - /* XXX: use .init section so that it also work in binary ? */ - bound_init = tcc_get_symbol_err(s1, "__bound_init"); - bound_exit = tcc_get_symbol_err(s1, "__bound_exit"); - bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region"); - bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region"); - - bound_init(); - /* mark argv area as valid */ - bound_new_region(argv, argc*sizeof(argv[0])); - for (i=0; inb_errors = 0; -#ifdef TCC_TARGET_PE - pe_output_file(s1, NULL); -#else - tcc_add_runtime(s1); - relocate_common_syms(); - tcc_add_linker_symbols(s1); - build_got_entries(s1); -#endif - if (s1->nb_errors) - return -1; - } - - offset = 0, mem = (addr_t)ptr; - fill = -mem & RUN_SECTION_ALIGNMENT; -#ifdef _WIN64 - offset += sizeof (void*); -#endif - for (k = 0; k < 2; ++k) { - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (0 == (s->sh_flags & SHF_ALLOC)) - continue; - if (k != !(s->sh_flags & SHF_EXECINSTR)) - continue; - offset += fill; - if (!mem) - s->sh_addr = 0; - else if (s->sh_flags & SHF_EXECINSTR) - s->sh_addr = mem + offset + ptr_diff; - else - s->sh_addr = mem + offset; -#if 0 - if (mem) - printf("%-16s +%02lx %p %04x\n", - s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset); -#endif - offset += s->data_offset; - fill = -(mem + offset) & 15; - } -#if RUN_SECTION_ALIGNMENT > 15 - /* To avoid that x86 processors would reload cached instructions each time - when data is written in the near, we need to make sure that code and data - do not share the same 64 byte unit */ - fill = -(mem + offset) & RUN_SECTION_ALIGNMENT; -#endif - } - - /* relocate symbols */ - relocate_syms(s1, s1->symtab, 1); - if (s1->nb_errors) - return -1; - - if (0 == mem) - return offset + RUN_SECTION_ALIGNMENT; - - /* relocate each section */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->reloc) - relocate_section(s1, s); - } - relocate_plt(s1); - -#ifdef _WIN64 - *(void**)ptr = win64_add_function_table(s1); -#endif - - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (0 == (s->sh_flags & SHF_ALLOC)) - continue; - length = s->data_offset; - ptr = (void*)s->sh_addr; - if (s->sh_flags & SHF_EXECINSTR) - ptr = (char*)ptr - ptr_diff; - if (NULL == s->data || s->sh_type == SHT_NOBITS) - memset(ptr, 0, length); - else - memcpy(ptr, s->data, length); - /* mark executable sections as executable in memory */ - if (s->sh_flags & SHF_EXECINSTR) - set_pages_executable((char*)ptr + ptr_diff, length); - } - return 0; -} - -/* ------------------------------------------------------------- */ -/* allow to run code in memory */ - -static void set_pages_executable(void *ptr, unsigned long length) -{ -#ifdef _WIN32 - unsigned long old_protect; - VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); -#else - void __clear_cache(void *beginning, void *end); -# ifndef HAVE_SELINUX - addr_t start, end; -# ifndef PAGESIZE -# define PAGESIZE 4096 -# endif - start = (addr_t)ptr & ~(PAGESIZE - 1); - end = (addr_t)ptr + length; - end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); - if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC)) - tcc_error("mprotect failed: did you mean to configure --with-selinux?"); -# endif -# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 - __clear_cache(ptr, (char *)ptr + length); -# endif -#endif -} - -#ifdef _WIN64 -static void *win64_add_function_table(TCCState *s1) -{ - void *p = NULL; - if (s1->uw_pdata) { - p = (void*)s1->uw_pdata->sh_addr; - RtlAddFunctionTable( - (RUNTIME_FUNCTION*)p, - s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION), - text_section->sh_addr - ); - s1->uw_pdata = NULL; - } - return p;; -} - -static void win64_del_function_table(void *p) -{ - if (p) { - RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p); - } -} -#endif - -/* ------------------------------------------------------------- */ -#ifdef CONFIG_TCC_BACKTRACE - -ST_FUNC void tcc_set_num_callers(int n) -{ - rt_num_callers = n; -} - -/* print the position in the source file of PC value 'pc' by reading - the stabs debug information */ -static addr_t rt_printline(addr_t wanted_pc, const char *msg) -{ - char func_name[128], last_func_name[128]; - addr_t func_addr, last_pc, pc; - const char *incl_files[INCLUDE_STACK_SIZE]; - int incl_index, len, last_line_num, i; - const char *str, *p; - - Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym; - int stab_len = 0; - char *stab_str = NULL; - - if (stab_section) { - stab_len = stab_section->data_offset; - stab_sym = (Stab_Sym *)stab_section->data; - stab_str = (char *) stabstr_section->data; - } - - func_name[0] = '\0'; - func_addr = 0; - incl_index = 0; - last_func_name[0] = '\0'; - last_pc = (addr_t)-1; - last_line_num = 1; - - if (!stab_sym) - goto no_stabs; - - stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len); - for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) { - switch(sym->n_type) { - /* function start or end */ - case N_FUN: - if (sym->n_strx == 0) { - /* we test if between last line and end of function */ - pc = sym->n_value + func_addr; - if (wanted_pc >= last_pc && wanted_pc < pc) - goto found; - func_name[0] = '\0'; - func_addr = 0; - } else { - str = stab_str + sym->n_strx; - p = strchr(str, ':'); - if (!p) { - pstrcpy(func_name, sizeof(func_name), str); - } else { - len = p - str; - if (len > sizeof(func_name) - 1) - len = sizeof(func_name) - 1; - memcpy(func_name, str, len); - func_name[len] = '\0'; - } - func_addr = sym->n_value; - } - break; - /* line number info */ - case N_SLINE: - pc = sym->n_value + func_addr; - if (wanted_pc >= last_pc && wanted_pc < pc) - goto found; - last_pc = pc; - last_line_num = sym->n_desc; - /* XXX: slow! */ - strcpy(last_func_name, func_name); - break; - /* include files */ - case N_BINCL: - str = stab_str + sym->n_strx; - add_incl: - if (incl_index < INCLUDE_STACK_SIZE) { - incl_files[incl_index++] = str; - } - break; - case N_EINCL: - if (incl_index > 1) - incl_index--; - break; - case N_SO: - if (sym->n_strx == 0) { - incl_index = 0; /* end of translation unit */ - } else { - str = stab_str + sym->n_strx; - /* do not add path */ - len = strlen(str); - if (len > 0 && str[len - 1] != '/') - goto add_incl; - } - break; - } - } - -no_stabs: - /* second pass: we try symtab symbols (no line number info) */ - incl_index = 0; - if (symtab_section) - { - ElfW(Sym) *sym, *sym_end; - int type; - - sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); - for(sym = (ElfW(Sym) *)symtab_section->data + 1; - sym < sym_end; - sym++) { - type = ELFW(ST_TYPE)(sym->st_info); - if (type == STT_FUNC || type == STT_GNU_IFUNC) { - if (wanted_pc >= sym->st_value && - wanted_pc < sym->st_value + sym->st_size) { - pstrcpy(last_func_name, sizeof(last_func_name), - (char *) strtab_section->data + sym->st_name); - func_addr = sym->st_value; - goto found; - } - } - } - } - /* did not find any info: */ - fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc); - fflush(stderr); - return 0; - found: - i = incl_index; - if (i > 0) - fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num); - fprintf(stderr, "%s %p", msg, (void*)wanted_pc); - if (last_func_name[0] != '\0') - fprintf(stderr, " %s()", last_func_name); - if (--i >= 0) { - fprintf(stderr, " (included from "); - for (;;) { - fprintf(stderr, "%s", incl_files[i]); - if (--i < 0) - break; - fprintf(stderr, ", "); - } - fprintf(stderr, ")"); - } - fprintf(stderr, "\n"); - fflush(stderr); - return func_addr; -} - -/* emit a run time error at position 'pc' */ -static void rt_error(ucontext_t *uc, const char *fmt, ...) -{ - va_list ap; - addr_t pc; - int i; - - fprintf(stderr, "Runtime error: "); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); - - for(i=0;isi_code) { - case FPE_INTDIV: - case FPE_FLTDIV: - rt_error(uc, "division by zero"); - break; - default: - rt_error(uc, "floating point exception"); - break; - } - break; - case SIGBUS: - case SIGSEGV: - if (rt_bound_error_msg && *rt_bound_error_msg) - rt_error(uc, *rt_bound_error_msg); - else - rt_error(uc, "dereferencing invalid pointer"); - break; - case SIGILL: - rt_error(uc, "illegal instruction"); - break; - case SIGABRT: - rt_error(uc, "abort() called"); - break; - default: - rt_error(uc, "caught signal %d", signum); - break; - } - exit(255); -} - -#ifndef SA_SIGINFO -# define SA_SIGINFO 0x00000004u -#endif - -/* Generate a stack backtrace when a CPU exception occurs. */ -static void set_exception_handler(void) -{ - struct sigaction sigact; - /* install TCC signal handlers to print debug info on fatal - runtime errors */ - sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; - sigact.sa_sigaction = sig_error; - sigemptyset(&sigact.sa_mask); - sigaction(SIGFPE, &sigact, NULL); - sigaction(SIGILL, &sigact, NULL); - sigaction(SIGSEGV, &sigact, NULL); - sigaction(SIGBUS, &sigact, NULL); - sigaction(SIGABRT, &sigact, NULL); -} - -/* ------------------------------------------------------------- */ -#ifdef __i386__ - -/* fix for glibc 2.1 */ -#ifndef REG_EIP -#define REG_EIP EIP -#define REG_EBP EBP -#endif - -/* return the PC at frame level 'level'. Return negative if not found */ -static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) -{ - addr_t fp; - int i; - - if (level == 0) { -#if defined(__APPLE__) - *paddr = uc->uc_mcontext->__ss.__eip; -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - *paddr = uc->uc_mcontext.mc_eip; -#elif defined(__dietlibc__) - *paddr = uc->uc_mcontext.eip; -#elif defined(__NetBSD__) - *paddr = uc->uc_mcontext.__gregs[_REG_EIP]; -#elif defined(__OpenBSD__) - *paddr = uc->sc_eip; -#else - *paddr = uc->uc_mcontext.gregs[REG_EIP]; -#endif - return 0; - } else { -#if defined(__APPLE__) - fp = uc->uc_mcontext->__ss.__ebp; -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - fp = uc->uc_mcontext.mc_ebp; -#elif defined(__dietlibc__) - fp = uc->uc_mcontext.ebp; -#elif defined(__NetBSD__) - fp = uc->uc_mcontext.__gregs[_REG_EBP]; -#elif defined(__OpenBSD__) - *paddr = uc->sc_ebp; -#else - fp = uc->uc_mcontext.gregs[REG_EBP]; -#endif - for(i=1;i= 0xc0000000) - return -1; - fp = ((addr_t *)fp)[0]; - } - *paddr = ((addr_t *)fp)[1]; - return 0; - } -} - -/* ------------------------------------------------------------- */ -#elif defined(__x86_64__) - -/* return the PC at frame level 'level'. Return negative if not found */ -static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) -{ - addr_t fp; - int i; - - if (level == 0) { - /* XXX: only support linux */ -#if defined(__APPLE__) - *paddr = uc->uc_mcontext->__ss.__rip; -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - *paddr = uc->uc_mcontext.mc_rip; -#elif defined(__NetBSD__) - *paddr = uc->uc_mcontext.__gregs[_REG_RIP]; -#else - *paddr = uc->uc_mcontext.gregs[REG_RIP]; -#endif - return 0; - } else { -#if defined(__APPLE__) - fp = uc->uc_mcontext->__ss.__rbp; -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - fp = uc->uc_mcontext.mc_rbp; -#elif defined(__NetBSD__) - fp = uc->uc_mcontext.__gregs[_REG_RBP]; -#else - fp = uc->uc_mcontext.gregs[REG_RBP]; -#endif - for(i=1;iuc_mcontext.arm_pc; -#else - return -1; -#endif - return 0; - } else { -#if defined(__linux__) - fp = uc->uc_mcontext.arm_fp; - sp = uc->uc_mcontext.arm_sp; - if (sp < 0x1000) - sp = 0x1000; -#else - return -1; -#endif - /* XXX: specific to tinycc stack frames */ - if (fp < sp + 12 || fp & 3) - return -1; - for(i = 1; i < level; i++) { - sp = ((addr_t *)fp)[-2]; - if (sp < fp || sp - fp > 16 || sp & 3) - return -1; - fp = ((addr_t *)fp)[-3]; - if (fp <= sp || fp - sp < 12 || fp & 3) - return -1; - } - /* XXX: check address validity with program info */ - *paddr = ((addr_t *)fp)[-1]; - return 0; - } -} - -/* ------------------------------------------------------------- */ -#elif defined(__aarch64__) - -static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) -{ - if (level < 0) - return -1; - else if (level == 0) { - *paddr = uc->uc_mcontext.pc; - return 0; - } - else { - addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29]; - int i; - for (i = 1; i < level; i++) - fp = (addr_t *)fp[0]; - *paddr = fp[1]; - return 0; - } -} - -/* ------------------------------------------------------------- */ -#else - -#warning add arch specific rt_get_caller_pc() -static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) -{ - return -1; -} - -#endif /* !__i386__ */ - -/* ------------------------------------------------------------- */ -#else /* WIN32 */ - -static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) -{ - EXCEPTION_RECORD *er = ex_info->ExceptionRecord; - CONTEXT *uc = ex_info->ContextRecord; - switch (er->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - if (rt_bound_error_msg && *rt_bound_error_msg) - rt_error(uc, *rt_bound_error_msg); - else - rt_error(uc, "access violation"); - break; - case EXCEPTION_STACK_OVERFLOW: - rt_error(uc, "stack overflow"); - break; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - rt_error(uc, "division by zero"); - break; - default: - rt_error(uc, "exception caught"); - break; - } - return EXCEPTION_EXECUTE_HANDLER; -} - -/* Generate a stack backtrace when a CPU exception occurs. */ -static void set_exception_handler(void) -{ - SetUnhandledExceptionFilter(cpu_exception_handler); -} - -/* return the PC at frame level 'level'. Return non zero if not found */ -static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level) -{ - addr_t fp, pc; - int i; -#ifdef _WIN64 - pc = uc->Rip; - fp = uc->Rbp; -#else - pc = uc->Eip; - fp = uc->Ebp; -#endif - if (level > 0) { - for(i=1;i= 0xc0000000) - return -1; - fp = ((addr_t*)fp)[0]; - } - pc = ((addr_t*)fp)[1]; - } - *paddr = pc; - return 0; -} - -#endif /* _WIN32 */ -#endif /* CONFIG_TCC_BACKTRACE */ -/* ------------------------------------------------------------- */ -#ifdef CONFIG_TCC_STATIC - -/* dummy function for profiling */ -ST_FUNC void *dlopen(const char *filename, int flag) -{ - return NULL; -} - -ST_FUNC void dlclose(void *p) -{ -} - -ST_FUNC const char *dlerror(void) -{ - return "error"; -} - -typedef struct TCCSyms { - char *str; - void *ptr; -} TCCSyms; - - -/* add the symbol you want here if no dynamic linking is done */ -static TCCSyms tcc_syms[] = { -#if !defined(CONFIG_TCCBOOT) -#define TCCSYM(a) { #a, &a, }, - TCCSYM(printf) - TCCSYM(fprintf) - TCCSYM(fopen) - TCCSYM(fclose) -#undef TCCSYM -#endif - { NULL, NULL }, -}; - -ST_FUNC void *dlsym(void *handle, const char *symbol) -{ - TCCSyms *p; - p = tcc_syms; - while (p->str != NULL) { - if (!strcmp(p->str, symbol)) - return p->ptr; - p++; - } - return NULL; -} - -#endif /* CONFIG_TCC_STATIC */ -#endif /* TCC_IS_NATIVE */ -/* ------------------------------------------------------------- */ diff --git a/tinyc/tcctok.h b/tinyc/tcctok.h deleted file mode 100644 index 317f64cd7..000000000 --- a/tinyc/tcctok.h +++ /dev/null @@ -1,350 +0,0 @@ -/* keywords */ - DEF(TOK_INT, "int") - DEF(TOK_VOID, "void") - DEF(TOK_CHAR, "char") - DEF(TOK_IF, "if") - DEF(TOK_ELSE, "else") - DEF(TOK_WHILE, "while") - DEF(TOK_BREAK, "break") - DEF(TOK_RETURN, "return") - DEF(TOK_FOR, "for") - DEF(TOK_EXTERN, "extern") - DEF(TOK_STATIC, "static") - DEF(TOK_UNSIGNED, "unsigned") - DEF(TOK_GOTO, "goto") - DEF(TOK_DO, "do") - DEF(TOK_CONTINUE, "continue") - DEF(TOK_SWITCH, "switch") - DEF(TOK_CASE, "case") - - DEF(TOK_CONST1, "const") - DEF(TOK_CONST2, "__const") /* gcc keyword */ - DEF(TOK_CONST3, "__const__") /* gcc keyword */ - DEF(TOK_VOLATILE1, "volatile") - DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */ - DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */ - DEF(TOK_LONG, "long") - DEF(TOK_REGISTER, "register") - DEF(TOK_SIGNED1, "signed") - DEF(TOK_SIGNED2, "__signed") /* gcc keyword */ - DEF(TOK_SIGNED3, "__signed__") /* gcc keyword */ - DEF(TOK_AUTO, "auto") - DEF(TOK_INLINE1, "inline") - DEF(TOK_INLINE2, "__inline") /* gcc keyword */ - DEF(TOK_INLINE3, "__inline__") /* gcc keyword */ - DEF(TOK_RESTRICT1, "restrict") - DEF(TOK_RESTRICT2, "__restrict") - DEF(TOK_RESTRICT3, "__restrict__") - DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */ - - DEF(TOK_GENERIC, "_Generic") - - DEF(TOK_FLOAT, "float") - DEF(TOK_DOUBLE, "double") - DEF(TOK_BOOL, "_Bool") - DEF(TOK_SHORT, "short") - DEF(TOK_STRUCT, "struct") - DEF(TOK_UNION, "union") - DEF(TOK_TYPEDEF, "typedef") - DEF(TOK_DEFAULT, "default") - DEF(TOK_ENUM, "enum") - DEF(TOK_SIZEOF, "sizeof") - DEF(TOK_ATTRIBUTE1, "__attribute") - DEF(TOK_ATTRIBUTE2, "__attribute__") - DEF(TOK_ALIGNOF1, "__alignof") - DEF(TOK_ALIGNOF2, "__alignof__") - DEF(TOK_TYPEOF1, "typeof") - DEF(TOK_TYPEOF2, "__typeof") - DEF(TOK_TYPEOF3, "__typeof__") - DEF(TOK_LABEL, "__label__") - DEF(TOK_ASM1, "asm") - DEF(TOK_ASM2, "__asm") - DEF(TOK_ASM3, "__asm__") - -#ifdef TCC_TARGET_ARM64 - DEF(TOK_UINT128, "__uint128_t") -#endif - -/*********************************************************************/ -/* the following are not keywords. They are included to ease parsing */ -/* preprocessor only */ - DEF(TOK_DEFINE, "define") - DEF(TOK_INCLUDE, "include") - DEF(TOK_INCLUDE_NEXT, "include_next") - DEF(TOK_IFDEF, "ifdef") - DEF(TOK_IFNDEF, "ifndef") - DEF(TOK_ELIF, "elif") - DEF(TOK_ENDIF, "endif") - DEF(TOK_DEFINED, "defined") - DEF(TOK_UNDEF, "undef") - DEF(TOK_ERROR, "error") - DEF(TOK_WARNING, "warning") - DEF(TOK_LINE, "line") - DEF(TOK_PRAGMA, "pragma") - DEF(TOK___LINE__, "__LINE__") - DEF(TOK___FILE__, "__FILE__") - DEF(TOK___DATE__, "__DATE__") - DEF(TOK___TIME__, "__TIME__") - DEF(TOK___FUNCTION__, "__FUNCTION__") - DEF(TOK___VA_ARGS__, "__VA_ARGS__") - DEF(TOK___COUNTER__, "__COUNTER__") - -/* special identifiers */ - DEF(TOK___FUNC__, "__func__") - -/* special floating point values */ - DEF(TOK___NAN__, "__nan__") - DEF(TOK___SNAN__, "__snan__") - DEF(TOK___INF__, "__inf__") - -/* attribute identifiers */ -/* XXX: handle all tokens generically since speed is not critical */ - DEF(TOK_SECTION1, "section") - DEF(TOK_SECTION2, "__section__") - DEF(TOK_ALIGNED1, "aligned") - DEF(TOK_ALIGNED2, "__aligned__") - DEF(TOK_PACKED1, "packed") - DEF(TOK_PACKED2, "__packed__") - DEF(TOK_WEAK1, "weak") - DEF(TOK_WEAK2, "__weak__") - DEF(TOK_ALIAS1, "alias") - DEF(TOK_ALIAS2, "__alias__") - DEF(TOK_UNUSED1, "unused") - DEF(TOK_UNUSED2, "__unused__") - DEF(TOK_CDECL1, "cdecl") - DEF(TOK_CDECL2, "__cdecl") - DEF(TOK_CDECL3, "__cdecl__") - DEF(TOK_STDCALL1, "stdcall") - DEF(TOK_STDCALL2, "__stdcall") - DEF(TOK_STDCALL3, "__stdcall__") - DEF(TOK_FASTCALL1, "fastcall") - DEF(TOK_FASTCALL2, "__fastcall") - DEF(TOK_FASTCALL3, "__fastcall__") - DEF(TOK_REGPARM1, "regparm") - DEF(TOK_REGPARM2, "__regparm__") - - DEF(TOK_MODE, "__mode__") - DEF(TOK_MODE_QI, "__QI__") - DEF(TOK_MODE_DI, "__DI__") - DEF(TOK_MODE_HI, "__HI__") - DEF(TOK_MODE_SI, "__SI__") - DEF(TOK_MODE_word, "__word__") - - DEF(TOK_DLLEXPORT, "dllexport") - DEF(TOK_DLLIMPORT, "dllimport") - DEF(TOK_NORETURN1, "noreturn") - DEF(TOK_NORETURN2, "__noreturn__") - DEF(TOK_VISIBILITY1, "visibility") - DEF(TOK_VISIBILITY2, "__visibility__") - - DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p") - DEF(TOK_builtin_choose_expr, "__builtin_choose_expr") - DEF(TOK_builtin_constant_p, "__builtin_constant_p") - DEF(TOK_builtin_frame_address, "__builtin_frame_address") - DEF(TOK_builtin_return_address, "__builtin_return_address") - DEF(TOK_builtin_expect, "__builtin_expect") - /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ -#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 - DEF(TOK_builtin_va_start, "__builtin_va_start") -#elif defined TCC_TARGET_X86_64 - DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") -#elif defined TCC_TARGET_ARM64 - DEF(TOK___va_start, "__va_start") - DEF(TOK___va_arg, "__va_arg") -#endif - -/* pragma */ - DEF(TOK_pack, "pack") -#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) - /* already defined for assembler */ - DEF(TOK_ASM_push, "push") - DEF(TOK_ASM_pop, "pop") -#endif - DEF(TOK_comment, "comment") - DEF(TOK_lib, "lib") - DEF(TOK_push_macro, "push_macro") - DEF(TOK_pop_macro, "pop_macro") - DEF(TOK_once, "once") - DEF(TOK_option, "option") - -/* builtin functions or variables */ -#ifndef TCC_ARM_EABI - DEF(TOK_memcpy, "memcpy") - DEF(TOK_memmove, "memmove") - DEF(TOK_memset, "memset") - DEF(TOK___divdi3, "__divdi3") - DEF(TOK___moddi3, "__moddi3") - DEF(TOK___udivdi3, "__udivdi3") - DEF(TOK___umoddi3, "__umoddi3") - DEF(TOK___ashrdi3, "__ashrdi3") - DEF(TOK___lshrdi3, "__lshrdi3") - DEF(TOK___ashldi3, "__ashldi3") - DEF(TOK___floatundisf, "__floatundisf") - DEF(TOK___floatundidf, "__floatundidf") -# ifndef TCC_ARM_VFP - DEF(TOK___floatundixf, "__floatundixf") - DEF(TOK___fixunsxfdi, "__fixunsxfdi") -# endif - DEF(TOK___fixunssfdi, "__fixunssfdi") - DEF(TOK___fixunsdfdi, "__fixunsdfdi") -#endif - -#if defined TCC_TARGET_ARM -# ifdef TCC_ARM_EABI - DEF(TOK_memcpy, "__aeabi_memcpy") - DEF(TOK_memcpy4, "__aeabi_memcpy4") - DEF(TOK_memcpy8, "__aeabi_memcpy8") - DEF(TOK_memmove, "__aeabi_memmove") - DEF(TOK_memset, "__aeabi_memset") - DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod") - DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod") - DEF(TOK___aeabi_idivmod, "__aeabi_idivmod") - DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod") - DEF(TOK___divsi3, "__aeabi_idiv") - DEF(TOK___udivsi3, "__aeabi_uidiv") - DEF(TOK___floatdisf, "__aeabi_l2f") - DEF(TOK___floatdidf, "__aeabi_l2d") - DEF(TOK___fixsfdi, "__aeabi_f2lz") - DEF(TOK___fixdfdi, "__aeabi_d2lz") - DEF(TOK___ashrdi3, "__aeabi_lasr") - DEF(TOK___lshrdi3, "__aeabi_llsr") - DEF(TOK___ashldi3, "__aeabi_llsl") - DEF(TOK___floatundisf, "__aeabi_ul2f") - DEF(TOK___floatundidf, "__aeabi_ul2d") - DEF(TOK___fixunssfdi, "__aeabi_f2ulz") - DEF(TOK___fixunsdfdi, "__aeabi_d2ulz") -# else - DEF(TOK___modsi3, "__modsi3") - DEF(TOK___umodsi3, "__umodsi3") - DEF(TOK___divsi3, "__divsi3") - DEF(TOK___udivsi3, "__udivsi3") - DEF(TOK___floatdisf, "__floatdisf") - DEF(TOK___floatdidf, "__floatdidf") -# ifndef TCC_ARM_VFP - DEF(TOK___floatdixf, "__floatdixf") - DEF(TOK___fixunssfsi, "__fixunssfsi") - DEF(TOK___fixunsdfsi, "__fixunsdfsi") - DEF(TOK___fixunsxfsi, "__fixunsxfsi") - DEF(TOK___fixxfdi, "__fixxfdi") -# endif - DEF(TOK___fixsfdi, "__fixsfdi") - DEF(TOK___fixdfdi, "__fixdfdi") -# endif -#endif - -#if defined TCC_TARGET_C67 - DEF(TOK__divi, "_divi") - DEF(TOK__divu, "_divu") - DEF(TOK__divf, "_divf") - DEF(TOK__divd, "_divd") - DEF(TOK__remi, "_remi") - DEF(TOK__remu, "_remu") -#endif - -#if defined TCC_TARGET_I386 - DEF(TOK___fixsfdi, "__fixsfdi") - DEF(TOK___fixdfdi, "__fixdfdi") - DEF(TOK___fixxfdi, "__fixxfdi") -#endif - -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 - DEF(TOK_alloca, "alloca") -#endif - -#if defined TCC_TARGET_PE - DEF(TOK___chkstk, "__chkstk") -#endif -#ifdef TCC_TARGET_ARM64 - DEF(TOK___arm64_clear_cache, "__arm64_clear_cache") - DEF(TOK___addtf3, "__addtf3") - DEF(TOK___subtf3, "__subtf3") - DEF(TOK___multf3, "__multf3") - DEF(TOK___divtf3, "__divtf3") - DEF(TOK___extendsftf2, "__extendsftf2") - DEF(TOK___extenddftf2, "__extenddftf2") - DEF(TOK___trunctfsf2, "__trunctfsf2") - DEF(TOK___trunctfdf2, "__trunctfdf2") - DEF(TOK___fixtfsi, "__fixtfsi") - DEF(TOK___fixtfdi, "__fixtfdi") - DEF(TOK___fixunstfsi, "__fixunstfsi") - DEF(TOK___fixunstfdi, "__fixunstfdi") - DEF(TOK___floatsitf, "__floatsitf") - DEF(TOK___floatditf, "__floatditf") - DEF(TOK___floatunsitf, "__floatunsitf") - DEF(TOK___floatunditf, "__floatunditf") - DEF(TOK___eqtf2, "__eqtf2") - DEF(TOK___netf2, "__netf2") - DEF(TOK___lttf2, "__lttf2") - DEF(TOK___letf2, "__letf2") - DEF(TOK___gttf2, "__gttf2") - DEF(TOK___getf2, "__getf2") -#endif - -/* bound checking symbols */ -#ifdef CONFIG_TCC_BCHECK - DEF(TOK___bound_ptr_add, "__bound_ptr_add") - DEF(TOK___bound_ptr_indir1, "__bound_ptr_indir1") - DEF(TOK___bound_ptr_indir2, "__bound_ptr_indir2") - DEF(TOK___bound_ptr_indir4, "__bound_ptr_indir4") - DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8") - DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12") - DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16") - DEF(TOK___bound_main_arg, "__bound_main_arg") - DEF(TOK___bound_local_new, "__bound_local_new") - DEF(TOK___bound_local_delete, "__bound_local_delete") -# ifdef TCC_TARGET_PE - DEF(TOK_malloc, "malloc") - DEF(TOK_free, "free") - DEF(TOK_realloc, "realloc") - DEF(TOK_memalign, "memalign") - DEF(TOK_calloc, "calloc") -# endif - DEF(TOK_strlen, "strlen") - DEF(TOK_strcpy, "strcpy") -#endif - -/* Tiny Assembler */ - DEF_ASMDIR(byte) /* must be first directive */ - DEF_ASMDIR(word) - DEF_ASMDIR(align) - DEF_ASMDIR(balign) - DEF_ASMDIR(p2align) - DEF_ASMDIR(set) - DEF_ASMDIR(skip) - DEF_ASMDIR(space) - DEF_ASMDIR(string) - DEF_ASMDIR(asciz) - DEF_ASMDIR(ascii) - DEF_ASMDIR(file) - DEF_ASMDIR(globl) - DEF_ASMDIR(global) - DEF_ASMDIR(weak) - DEF_ASMDIR(hidden) - DEF_ASMDIR(ident) - DEF_ASMDIR(size) - DEF_ASMDIR(type) - DEF_ASMDIR(text) - DEF_ASMDIR(data) - DEF_ASMDIR(bss) - DEF_ASMDIR(previous) - DEF_ASMDIR(pushsection) - DEF_ASMDIR(popsection) - DEF_ASMDIR(fill) - DEF_ASMDIR(rept) - DEF_ASMDIR(endr) - DEF_ASMDIR(org) - DEF_ASMDIR(quad) -#if defined(TCC_TARGET_I386) - DEF_ASMDIR(code16) - DEF_ASMDIR(code32) -#elif defined(TCC_TARGET_X86_64) - DEF_ASMDIR(code64) -#endif - DEF_ASMDIR(short) - DEF_ASMDIR(long) - DEF_ASMDIR(int) - DEF_ASMDIR(section) /* must be last directive */ - -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -#include "i386-tok.h" -#endif diff --git a/tinyc/tcctools.c b/tinyc/tcctools.c deleted file mode 100644 index 53d88be6a..000000000 --- a/tinyc/tcctools.c +++ /dev/null @@ -1,546 +0,0 @@ -/* -------------------------------------------------------------- */ -/* - * TCC - Tiny C Compiler - * - * tcctools.c - extra tools and and -m32/64 support - * - */ - -/* -------------------------------------------------------------- */ -/* - * This program is for making libtcc1.a without ar - * tiny_libmaker - tiny elf lib maker - * usage: tiny_libmaker [lib] files... - * Copyright (c) 2007 Timppa - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "tcc.h" - -//#define ARMAG "!\n" -#define ARFMAG "`\n" - -typedef struct { - char ar_name[16]; - char ar_date[12]; - char ar_uid[6]; - char ar_gid[6]; - char ar_mode[8]; - char ar_size[10]; - char ar_fmag[2]; -} ArHdr; - -static unsigned long le2belong(unsigned long ul) { - return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) + - ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8); -} - -/* Returns 1 if s contains any of the chars of list, else 0 */ -static int contains_any(const char *s, const char *list) { - const char *l; - for (; *s; s++) { - for (l = list; *l; l++) { - if (*s == *l) - return 1; - } - } - return 0; -} - -static int ar_usage(int ret) { - fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n"); - fprintf(stderr, "create library ([abdioptxN] not supported).\n"); - return ret; -} - -ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv) -{ - static ArHdr arhdr = { - "/ ", - " ", - "0 ", - "0 ", - "0 ", - " ", - ARFMAG - }; - - static ArHdr arhdro = { - " ", - " ", - "0 ", - "0 ", - "0 ", - " ", - ARFMAG - }; - - FILE *fi, *fh = NULL, *fo = NULL; - ElfW(Ehdr) *ehdr; - ElfW(Shdr) *shdr; - ElfW(Sym) *sym; - int i, fsize, i_lib, i_obj; - char *buf, *shstr, *symtab = NULL, *strtab = NULL; - int symtabsize = 0;//, strtabsize = 0; - char *anames = NULL; - int *afpos = NULL; - int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; - char tfile[260], stmp[20]; - char *file, *name; - int ret = 2; - const char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored. - int verbose = 0; - - i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj - for (i = 1; i < argc; i++) { - const char *a = argv[i]; - if (*a == '-' && strstr(a, ".")) - ret = 1; // -x.y is always invalid (same as gnu ar) - if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument - if (contains_any(a, ops_conflict)) - ret = 1; - if (strstr(a, "v")) - verbose = 1; - } else { // lib or obj files: don't abort - keep validating all args. - if (!i_lib) // first file is the lib - i_lib = i; - else if (!i_obj) // second file is the first obj - i_obj = i; - } - } - - if (!i_obj) // i_obj implies also i_lib. we require both. - ret = 1; - - if (ret == 1) - return ar_usage(ret); - - if ((fh = fopen(argv[i_lib], "wb")) == NULL) - { - fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]); - goto the_end; - } - - sprintf(tfile, "%s.tmp", argv[i_lib]); - if ((fo = fopen(tfile, "wb+")) == NULL) - { - fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile); - goto the_end; - } - - funcmax = 250; - afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func - memcpy(&arhdro.ar_mode, "100666", 6); - - // i_obj = first input object file - while (i_obj < argc) - { - if (*argv[i_obj] == '-') { // by now, all options start with '-' - i_obj++; - continue; - } - if ((fi = fopen(argv[i_obj], "rb")) == NULL) { - fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]); - goto the_end; - } - if (verbose) - printf("a - %s\n", argv[i_obj]); - - fseek(fi, 0, SEEK_END); - fsize = ftell(fi); - fseek(fi, 0, SEEK_SET); - buf = tcc_malloc(fsize + 1); - fread(buf, fsize, 1, fi); - fclose(fi); - - // elf header - ehdr = (ElfW(Ehdr) *)buf; - if (ehdr->e_ident[4] != ELFCLASSW) - { - fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]); - goto the_end; - } - - shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize); - shstr = (char *)(buf + shdr->sh_offset); - for (i = 0; i < ehdr->e_shnum; i++) - { - shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize); - if (!shdr->sh_offset) - continue; - if (shdr->sh_type == SHT_SYMTAB) - { - symtab = (char *)(buf + shdr->sh_offset); - symtabsize = shdr->sh_size; - } - if (shdr->sh_type == SHT_STRTAB) - { - if (!strcmp(shstr + shdr->sh_name, ".strtab")) - { - strtab = (char *)(buf + shdr->sh_offset); - //strtabsize = shdr->sh_size; - } - } - } - - if (symtab && symtabsize) - { - int nsym = symtabsize / sizeof(ElfW(Sym)); - //printf("symtab: info size shndx name\n"); - for (i = 1; i < nsym; i++) - { - sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym))); - if (sym->st_shndx && - (sym->st_info == 0x10 - || sym->st_info == 0x11 - || sym->st_info == 0x12 - )) { - //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name); - istrlen = strlen(strtab + sym->st_name)+1; - anames = tcc_realloc(anames, strpos+istrlen); - strcpy(anames + strpos, strtab + sym->st_name); - strpos += istrlen; - if (++funccnt >= funcmax) { - funcmax += 250; - afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more - } - afpos[funccnt] = fpos; - } - } - } - - file = argv[i_obj]; - for (name = strchr(file, 0); - name > file && name[-1] != '/' && name[-1] != '\\'; - --name); - istrlen = strlen(name); - if (istrlen >= sizeof(arhdro.ar_name)) - istrlen = sizeof(arhdro.ar_name) - 1; - memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name)); - memcpy(arhdro.ar_name, name, istrlen); - arhdro.ar_name[istrlen] = '/'; - sprintf(stmp, "%-10d", fsize); - memcpy(&arhdro.ar_size, stmp, 10); - fwrite(&arhdro, sizeof(arhdro), 1, fo); - fwrite(buf, fsize, 1, fo); - tcc_free(buf); - i_obj++; - fpos += (fsize + sizeof(arhdro)); - } - hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int); - fpos = 0; - if ((hofs & 1)) // align - hofs++, fpos = 1; - // write header - fwrite("!\n", 8, 1, fh); - sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int))); - memcpy(&arhdr.ar_size, stmp, 10); - fwrite(&arhdr, sizeof(arhdr), 1, fh); - afpos[0] = le2belong(funccnt); - for (i=1; i<=funccnt; i++) - afpos[i] = le2belong(afpos[i] + hofs); - fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh); - fwrite(anames, strpos, 1, fh); - if (fpos) - fwrite("", 1, 1, fh); - // write objects - fseek(fo, 0, SEEK_END); - fsize = ftell(fo); - fseek(fo, 0, SEEK_SET); - buf = tcc_malloc(fsize + 1); - fread(buf, fsize, 1, fo); - fwrite(buf, fsize, 1, fh); - tcc_free(buf); - ret = 0; -the_end: - if (anames) - tcc_free(anames); - if (afpos) - tcc_free(afpos); - if (fh) - fclose(fh); - if (fo) - fclose(fo), remove(tfile); - return ret; -} - -/* -------------------------------------------------------------- */ -/* - * tiny_impdef creates an export definition file (.def) from a dll - * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]" - * - * Copyright (c) 2005,2007 grischka - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifdef TCC_TARGET_PE - -ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv) -{ - int ret, v, i; - char infile[260]; - char outfile[260]; - - const char *file; - char *p, *q; - FILE *fp, *op; - -#ifdef _WIN32 - char path[260]; -#endif - - infile[0] = outfile[0] = 0; - fp = op = NULL; - ret = 1; - p = NULL; - v = 0; - - for (i = 1; i < argc; ++i) { - const char *a = argv[i]; - if ('-' == a[0]) { - if (0 == strcmp(a, "-v")) { - v = 1; - } else if (0 == strcmp(a, "-o")) { - if (++i == argc) - goto usage; - strcpy(outfile, argv[i]); - } else - goto usage; - } else if (0 == infile[0]) - strcpy(infile, a); - else - goto usage; - } - - if (0 == infile[0]) { -usage: - fprintf(stderr, - "usage: tcc -impdef library.dll [-v] [-o outputfile]\n" - "create export definition file (.def) from dll\n" - ); - goto the_end; - } - - if (0 == outfile[0]) { - strcpy(outfile, tcc_basename(infile)); - q = strrchr(outfile, '.'); - if (NULL == q) - q = strchr(outfile, 0); - strcpy(q, ".def"); - } - - file = infile; -#ifdef _WIN32 - if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL)) - file = path; -#endif - ret = tcc_get_dllexports(file, &p); - if (ret || !p) { - fprintf(stderr, "tcc: impdef: %s '%s'\n", - ret == -1 ? "can't find file" : - ret == 1 ? "can't read symbols" : - ret == 0 ? "no symbols found in" : - "unknown file type", file); - ret = 1; - goto the_end; - } - - if (v) - printf("-> %s\n", file); - - op = fopen(outfile, "w"); - if (NULL == op) { - fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile); - goto the_end; - } - - fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file)); - for (q = p, i = 0; *q; ++i) { - fprintf(op, "%s\n", q); - q += strlen(q) + 1; - } - - if (v) - printf("<- %s (%d symbol%s)\n", outfile, i, &"s"[i<2]); - - ret = 0; - -the_end: - /* cannot free memory received from tcc_get_dllexports - if it came from a dll */ - /* if (p) - tcc_free(p); */ - if (fp) - fclose(fp); - if (op) - fclose(op); - return ret; -} - -#endif /* TCC_TARGET_PE */ - -/* -------------------------------------------------------------- */ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ - -#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64 - -ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option) -{ - tcc_error("-m%d not implemented.", option); -} - -#else -#ifdef _WIN32 -#include - -static char *str_replace(const char *str, const char *p, const char *r) -{ - const char *s, *s0; - char *d, *d0; - int sl, pl, rl; - - sl = strlen(str); - pl = strlen(p); - rl = strlen(r); - for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) { - for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) { - if (d) { - memcpy(d, s0, sl = s - s0), d += sl; - memcpy(d, r, rl), d += rl; - } else - sl += rl - pl; - } - if (d) { - strcpy(d, s0); - return d0; - } - } -} - -static int execvp_win32(const char *prog, char **argv) -{ - int ret; char **p; - /* replace all " by \" */ - for (p = argv; *p; ++p) - if (strchr(*p, '"')) - *p = str_replace(*p, "\"", "\\\""); - ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv); - if (-1 == ret) - return ret; - _cwait(&ret, ret, WAIT_CHILD); - exit(ret); -} -#define execvp execvp_win32 -#endif /* _WIN32 */ - -ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target) -{ - char program[4096]; - char *a0 = argv[0]; - int prefix = tcc_basename(a0) - a0; - - snprintf(program, sizeof program, - "%.*s%s" -#ifdef TCC_TARGET_PE - "-win32" -#endif - "-tcc" -#ifdef _WIN32 - ".exe" -#endif - , prefix, a0, target == 64 ? "x86_64" : "i386"); - - if (strcmp(a0, program)) - execvp(argv[0] = program, argv); - tcc_error("could not run '%s'", program); -} - -#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */ -/* -------------------------------------------------------------- */ -/* enable commandline wildcard expansion (tcc -o x.exe *.c) */ - -#ifdef _WIN32 -int _CRT_glob = 1; -#ifndef _CRT_glob -int _dowildcard = 1; -#endif -#endif - -/* -------------------------------------------------------------- */ -/* generate xxx.d file */ - -ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename) -{ - FILE *depout; - char buf[1024]; - int i; - - if (!filename) { - /* compute filename automatically: dir/file.o -> dir/file.d */ - snprintf(buf, sizeof buf, "%.*s.d", - (int)(tcc_fileextension(target) - target), target); - filename = buf; - } - - if (s->verbose) - printf("<- %s\n", filename); - - /* XXX return err codes instead of error() ? */ - depout = fopen(filename, "w"); - if (!depout) - tcc_error("could not open '%s'", filename); - - fprintf(depout, "%s: \\\n", target); - for (i=0; inb_target_deps; ++i) - fprintf(depout, " %s \\\n", s->target_deps[i]); - fprintf(depout, "\n"); - fclose(depout); -} - -/* -------------------------------------------------------------- */ diff --git a/tinyc/tests/42test.h b/tinyc/tests/42test.h deleted file mode 100644 index 5db7d1c47..000000000 --- a/tinyc/tests/42test.h +++ /dev/null @@ -1,13 +0,0 @@ -/* This file is to test compute #include directives. It's named so - that it starts with a pre-processing number which isn't a valid - number (42test.h). Including this must work. */ -#ifndef INC42_FIRST -int have_included_42test_h; -#define INC42_FIRST -#elif !defined INC42_SECOND -#define INC42_SECOND -int have_included_42test_h_second; -#else -#define INC42_THIRD -int have_included_42test_h_third; -#endif diff --git a/tinyc/tests/abitest.c b/tinyc/tests/abitest.c deleted file mode 100644 index 4a192bd23..000000000 --- a/tinyc/tests/abitest.c +++ /dev/null @@ -1,691 +0,0 @@ -#include -#include -#include -#include -#include - -// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC -#if defined(_WIN32) && defined(__GNUC__) -#define LONG_DOUBLE double -#define LONG_DOUBLE_LITERAL(x) x -#else -#define LONG_DOUBLE long double -#define LONG_DOUBLE_LITERAL(x) x ## L -#endif - -static int g_argc; -static char **g_argv; - -static void set_options(TCCState *s, int argc, char **argv) -{ - int i; - for (i = 1; i < argc; ++i) { - char *a = argv[i]; - if (a[0] == '-') { - if (a[1] == 'B') - tcc_set_lib_path(s, a+2); - else if (a[1] == 'I') - tcc_add_include_path(s, a+2); - else if (a[1] == 'L') - tcc_add_library_path(s, a+2); - } - } -} - -typedef int (*callback_type) (void*); - -/* - * Compile source code and call a callback with a pointer to the symbol "f". - */ -static int run_callback(const char *src, callback_type callback) { - TCCState *s; - int result; - void *ptr; - - s = tcc_new(); - if (!s) - return -1; - - set_options(s, g_argc, g_argv); - - if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1) - return -1; - if (tcc_compile_string(s, src) == -1) - return -1; - if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1) - return -1; - - ptr = tcc_get_symbol(s, "f"); - if (!ptr) - return -1; - result = callback(ptr); - - tcc_delete(s); - - return result; -} - -#define STR2(x) #x -#define STR(x) STR2(x) - -#define RET_PRIMITIVE_TEST(name, type, val) \ - static int ret_ ## name ## _test_callback(void *ptr) { \ - type (*callback) (type) = (type(*)(type))ptr; \ - type x = val; \ - type y = callback(x); \ - return (y == x+x) ? 0 : -1; \ - } \ - \ - static int ret_ ## name ## _test(void) { \ - const char *src = STR(type) " f(" STR(type) " x) {return x+x;}"; \ - return run_callback(src, ret_ ## name ## _test_callback); \ - } - -RET_PRIMITIVE_TEST(int, int, 70000) -RET_PRIMITIVE_TEST(longlong, long long, 4333369356528LL) -RET_PRIMITIVE_TEST(float, float, 63.0) -RET_PRIMITIVE_TEST(double, double, 14789798.0) -RET_PRIMITIVE_TEST(longdouble, LONG_DOUBLE, LONG_DOUBLE_LITERAL(378943892.0)) - -/* - * ret_2float_test: - * - * On x86-64, a struct with 2 floats should be packed into a single - * SSE register (VT_DOUBLE is used for this purpose). - */ -typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type; -typedef ret_2float_test_type (*ret_2float_test_function_type) (ret_2float_test_type); - -static int ret_2float_test_callback(void *ptr) { - ret_2float_test_function_type f = (ret_2float_test_function_type)ptr; - ret_2float_test_type a = {10, 35}; - ret_2float_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; -} - -static int ret_2float_test(void) { - const char *src = - "typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;" - "ret_2float_test_type f(ret_2float_test_type a) {\n" - " ret_2float_test_type r = {a.x*5, a.y*3};\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_2float_test_callback); -} - -/* - * ret_2double_test: - * - * On x86-64, a struct with 2 doubles should be passed in two SSE - * registers. - */ -typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type; -typedef ret_2double_test_type (*ret_2double_test_function_type) (ret_2double_test_type); - -static int ret_2double_test_callback(void *ptr) { - ret_2double_test_function_type f = (ret_2double_test_function_type)ptr; - ret_2double_test_type a = {10, 35}; - ret_2double_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; -} - -static int ret_2double_test(void) { - const char *src = - "typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;" - "ret_2double_test_type f(ret_2double_test_type a) {\n" - " ret_2double_test_type r = {a.x*5, a.y*3};\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_2double_test_callback); -} - -/* - * ret_8plus2double_test: - * - * This catches a corner case in the x86_64 ABI code: the first 7 - * arguments fit into registers, the 8th doesn't, but the 9th argument - * fits into the 8th XMM register. - * - * Note that the purpose of the 10th argument is to avoid a situation - * in which gcc would accidentally put the double at the right - * address, thus causing a success message even though TCC actually - * generated incorrect code. - */ -typedef ret_2double_test_type (*ret_8plus2double_test_function_type) (double, double, double, double, double, double, double, ret_2double_test_type, double, double); - -static int ret_8plus2double_test_callback(void *ptr) { - ret_8plus2double_test_function_type f = (ret_8plus2double_test_function_type)ptr; - ret_2double_test_type a = {10, 35}; - ret_2double_test_type r; - r = f(0, 0, 0, 0, 0, 0, 0, a, 37, 38); - return ((r.x == 37) && (r.y == 37)) ? 0 : -1; -} - -static int ret_8plus2double_test(void) { - const char *src = - "typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;" - "ret_2double_test_type f(double x1, double x2, double x3, double x4, double x5, double x6, double x7, ret_2double_test_type a, double x8, double x9) {\n" - " ret_2double_test_type r = { x8, x8 };\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_8plus2double_test_callback); -} - -/* - * ret_mixed_test: - * - * On x86-64, a struct with a double and a 64-bit integer should be - * passed in one SSE register and one integer register. - */ -typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type; -typedef ret_mixed_test_type (*ret_mixed_test_function_type) (ret_mixed_test_type); - -static int ret_mixed_test_callback(void *ptr) { - ret_mixed_test_function_type f = (ret_mixed_test_function_type)ptr; - ret_mixed_test_type a = {10, 35}; - ret_mixed_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; -} - -static int ret_mixed_test(void) { - const char *src = - "typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;" - "ret_mixed_test_type f(ret_mixed_test_type a) {\n" - " ret_mixed_test_type r = {a.x*5, a.y*3};\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_mixed_test_callback); -} - -/* - * ret_mixed2_test: - * - * On x86-64, a struct with two floats and two 32-bit integers should - * be passed in one SSE register and one integer register. - */ -typedef struct ret_mixed2_test_type_s {float x,x2; int y,y2;} ret_mixed2_test_type; -typedef ret_mixed2_test_type (*ret_mixed2_test_function_type) (ret_mixed2_test_type); - -static int ret_mixed2_test_callback(void *ptr) { - ret_mixed2_test_function_type f = (ret_mixed2_test_function_type)ptr; - ret_mixed2_test_type a = {10, 5, 35, 7 }; - ret_mixed2_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; -} - -static int ret_mixed2_test(void) { - const char *src = - "typedef struct ret_mixed2_test_type_s {float x, x2; int y,y2;} ret_mixed2_test_type;" - "ret_mixed2_test_type f(ret_mixed2_test_type a) {\n" - " ret_mixed2_test_type r = {a.x*5, 0, a.y*3, 0};\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_mixed2_test_callback); -} - -/* - * ret_mixed3_test: - * - * On x86-64, this struct should be passed in two integer registers. - */ -typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type; -typedef ret_mixed3_test_type (*ret_mixed3_test_function_type) (ret_mixed3_test_type); - -static int ret_mixed3_test_callback(void *ptr) { - ret_mixed3_test_function_type f = (ret_mixed3_test_function_type)ptr; - ret_mixed3_test_type a = {10, 5, 35, 7 }; - ret_mixed3_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y2 == a.y*3)) ? 0 : -1; -} - -static int ret_mixed3_test(void) { - const char *src = - "typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;" - "ret_mixed3_test_type f(ret_mixed3_test_type a) {\n" - " ret_mixed3_test_type r = {a.x*5, 0, 0, a.y*3};\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_mixed3_test_callback); -} - -/* - * reg_pack_test: return a small struct which should be packed into - * registers (Win32) during return. - */ -typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type; -typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type); - -static int reg_pack_test_callback(void *ptr) { - reg_pack_test_function_type f = (reg_pack_test_function_type)ptr; - reg_pack_test_type a = {10, 35}; - reg_pack_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; -} - -static int reg_pack_test(void) { - const char *src = - "typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;" - "reg_pack_test_type f(reg_pack_test_type a) {\n" - " reg_pack_test_type r = {a.x*5, a.y*3};\n" - " return r;\n" - "}\n"; - - return run_callback(src, reg_pack_test_callback); -} - -/* - * reg_pack_longlong_test: return a small struct which should be packed into - * registers (x86-64) during return. - */ -typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type; -typedef reg_pack_longlong_test_type (*reg_pack_longlong_test_function_type) (reg_pack_longlong_test_type); - -static int reg_pack_longlong_test_callback(void *ptr) { - reg_pack_longlong_test_function_type f = (reg_pack_longlong_test_function_type)ptr; - reg_pack_longlong_test_type a = {10, 35}; - reg_pack_longlong_test_type r; - r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; -} - -static int reg_pack_longlong_test(void) { - const char *src = - "typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;" - "reg_pack_longlong_test_type f(reg_pack_longlong_test_type a) {\n" - " reg_pack_longlong_test_type r = {a.x*5, a.y*3};\n" - " return r;\n" - "}\n"; - - return run_callback(src, reg_pack_longlong_test_callback); -} - -/* - * ret_6plus2longlong_test: - * - * This catches a corner case in the x86_64 ABI code: the first 5 - * arguments fit into registers, the 6th doesn't, but the 7th argument - * fits into the 6th argument integer register, %r9. - * - * Note that the purpose of the 10th argument is to avoid a situation - * in which gcc would accidentally put the longlong at the right - * address, thus causing a success message even though TCC actually - * generated incorrect code. - */ -typedef reg_pack_longlong_test_type (*ret_6plus2longlong_test_function_type) (long long, long long, long long, long long, long long, reg_pack_longlong_test_type, long long, long long); - -static int ret_6plus2longlong_test_callback(void *ptr) { - ret_6plus2longlong_test_function_type f = (ret_6plus2longlong_test_function_type)ptr; - reg_pack_longlong_test_type a = {10, 35}; - reg_pack_longlong_test_type r; - r = f(0, 0, 0, 0, 0, a, 37, 38); - return ((r.x == 37) && (r.y == 37)) ? 0 : -1; -} - -static int ret_6plus2longlong_test(void) { - const char *src = - "typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;" - "reg_pack_longlong_test_type f(long long x1, long long x2, long long x3, long long x4, long long x5, reg_pack_longlong_test_type a, long long x8, long long x9) {\n" - " reg_pack_longlong_test_type r = { x8, x8 };\n" - " return r;\n" - "}\n"; - - return run_callback(src, ret_6plus2longlong_test_callback); -} - -/* - * sret_test: Create a struct large enough to be returned via sret - * (hidden pointer as first function argument) - */ -typedef struct sret_test_type_s {long long a, b, c;} sret_test_type; -typedef sret_test_type (*sret_test_function_type) (sret_test_type); - -static int sret_test_callback(void *ptr) { - sret_test_function_type f = (sret_test_function_type)(ptr); - sret_test_type x = {5436LL, 658277698LL, 43878957LL}; - sret_test_type r = f(x); - return ((r.a==x.a*35)&&(r.b==x.b*19)&&(r.c==x.c*21)) ? 0 : -1; -} - -static int sret_test(void) { - const char *src = - "typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;\n" - "sret_test_type f(sret_test_type x) {\n" - " sret_test_type r = {x.a*35, x.b*19, x.c*21};\n" - " return r;\n" - "}\n"; - - return run_callback(src, sret_test_callback); -} - -/* - * one_member_union_test: - * - * In the x86-64 ABI a union should always be passed on the stack. However - * it appears that a single member union is treated by GCC as its member. - */ -typedef union one_member_union_test_type_u {int x;} one_member_union_test_type; -typedef one_member_union_test_type (*one_member_union_test_function_type) (one_member_union_test_type); - -static int one_member_union_test_callback(void *ptr) { - one_member_union_test_function_type f = (one_member_union_test_function_type)ptr; - one_member_union_test_type a, b; - a.x = 34; - b = f(a); - return (b.x == a.x*2) ? 0 : -1; -} - -static int one_member_union_test(void) { - const char *src = - "typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;\n" - "one_member_union_test_type f(one_member_union_test_type a) {\n" - " one_member_union_test_type b;\n" - " b.x = a.x * 2;\n" - " return b;\n" - "}\n"; - return run_callback(src, one_member_union_test_callback); -} - -/* - * two_member_union_test: - * - * In the x86-64 ABI a union should always be passed on the stack. - */ -typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type; -typedef two_member_union_test_type (*two_member_union_test_function_type) (two_member_union_test_type); - -static int two_member_union_test_callback(void *ptr) { - two_member_union_test_function_type f = (two_member_union_test_function_type)ptr; - two_member_union_test_type a, b; - a.x = 34; - b = f(a); - return (b.x == a.x*2) ? 0 : -1; -} - -static int two_member_union_test(void) { - const char *src = - "typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;\n" - "two_member_union_test_type f(two_member_union_test_type a) {\n" - " two_member_union_test_type b;\n" - " b.x = a.x * 2;\n" - " return b;\n" - "}\n"; - return run_callback(src, two_member_union_test_callback); -} - -/* - * Win64 calling convention test. - */ - -typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type; -typedef many_struct_test_type (*many_struct_test_function_type) (many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type); - -static int many_struct_test_callback(void *ptr) { - many_struct_test_function_type f = (many_struct_test_function_type)ptr; - many_struct_test_type v = {1, 2, 3}; - many_struct_test_type r = f(v,v,v,v,v,v); - return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1; -} - -static int many_struct_test(void) { - const char *src = - "typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n" - "many_struct_test_type f(many_struct_test_type x1, many_struct_test_type x2, many_struct_test_type x3, many_struct_test_type x4, many_struct_test_type x5, many_struct_test_type x6) {\n" - " many_struct_test_type y;\n" - " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" - " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" - " y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n" - " return y;\n" - "}\n"; - return run_callback(src, many_struct_test_callback); -} - -/* - * Win64 calling convention test. - */ - -typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type; -typedef many_struct_test_2_type (*many_struct_test_2_function_type) (many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type); - -static int many_struct_test_2_callback(void *ptr) { - many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr; - many_struct_test_2_type v = {1,2}; - many_struct_test_2_type r = f(v,v,v,v,v,v); - return ((r.a == 6) && (r.b == 12))?0:-1; -} - -static int many_struct_test_2(void) { - const char *src = - "typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n" - "many_struct_test_2_type f(many_struct_test_2_type x1, many_struct_test_2_type x2, many_struct_test_2_type x3, many_struct_test_2_type x4, many_struct_test_2_type x5, many_struct_test_2_type x6) {\n" - " many_struct_test_2_type y;\n" - " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" - " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" - " return y;\n" - "}\n"; - return run_callback(src, many_struct_test_2_callback); -} - -/* - * Win64 calling convention test. - */ - -typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type; -typedef many_struct_test_3_type (*many_struct_test_3_function_type) (many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type, ...); -typedef struct many_struct_test_3_struct_type { many_struct_test_3_function_type f; many_struct_test_3_function_type *f2; } many_struct_test_3_struct_type; - -static void many_struct_test_3_dummy(double d, ...) -{ - volatile double x = d; -} - -static int many_struct_test_3_callback(void *ptr) { - many_struct_test_3_struct_type s = { ptr, }; - many_struct_test_3_struct_type *s2 = &s; - s2->f2 = &s2->f; - many_struct_test_3_dummy(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, &s2); - many_struct_test_3_function_type f = *(s2->f2); - many_struct_test_3_type v = {1,2}; - many_struct_test_3_type r = (*((s2->f2=&f)+0))(v,v,v,v,v,v,1.0); - return ((r.a == 6) && (r.b == 12))?0:-1; -} - -static int many_struct_test_3(void) { - const char *src = - "typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;\n" - "many_struct_test_3_type f(many_struct_test_3_type x1, many_struct_test_3_type x2, many_struct_test_3_type x3, many_struct_test_3_type x4, many_struct_test_3_type x5, many_struct_test_3_type x6, ...) {\n" - " many_struct_test_3_type y;\n" - " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" - " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" - " return y;\n" - "}\n"; - return run_callback(src, many_struct_test_3_callback); -} - -/* - * stdarg_test: Test variable argument list ABI - */ - -typedef struct {long long a, b, c;} stdarg_test_struct_type; -typedef void (*stdarg_test_function_type) (int,int,int,...); - -static int stdarg_test_callback(void *ptr) { - stdarg_test_function_type f = (stdarg_test_function_type)ptr; - int x; - double y; - stdarg_test_struct_type z = {1, 2, 3}, w; - f(10, 10, 5, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x, - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y, - z, z, z, z, z, &w); - return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1; -} - -static int stdarg_test(void) { - const char *src = - "#include \n" - "typedef struct {long long a, b, c;} stdarg_test_struct_type;\n" - "void f(int n_int, int n_float, int n_struct, ...) {\n" - " int i, ti = 0;\n" - " double td = 0.0;\n" - " stdarg_test_struct_type ts = {0,0,0}, tmp;\n" - " va_list ap;\n" - " va_start(ap, n_struct);\n" - " for (i = 0, ti = 0; i < n_int; ++i)\n" - " ti += va_arg(ap, int);\n" - " *va_arg(ap, int*) = ti;\n" - " for (i = 0, td = 0; i < n_float; ++i)\n" - " td += va_arg(ap, double);\n" - " *va_arg(ap, double*) = td;\n" - " for (i = 0; i < n_struct; ++i) {\n" - " tmp = va_arg(ap, stdarg_test_struct_type);\n" - " ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;" - " }\n" - " *va_arg(ap, stdarg_test_struct_type*) = ts;\n" - " va_end(ap);" - "}\n"; - return run_callback(src, stdarg_test_callback); -} - -typedef struct {long long a, b;} stdarg_many_test_struct_type; -typedef void (*stdarg_many_test_function_type) (int, int, int, int, int, - stdarg_many_test_struct_type, - int, int, ...); - -static int stdarg_many_test_callback(void *ptr) -{ - stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr; - int x; - stdarg_many_test_struct_type l = {10, 11}; - f(1, 2, 3, 4, 5, l, 6, 7, &x, 44); - return x == 44 ? 0 : -1; -} - -static int stdarg_many_test(void) -{ - const char *src = - "#include \n" - "typedef struct {long long a, b;} stdarg_many_test_struct_type;\n" - "void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n" - " va_list ap;\n" - " int *p;\n" - " va_start (ap, g);\n" - " p = va_arg(ap, int*);\n" - " *p = va_arg(ap, int);\n" - " va_end (ap);\n" - "}\n"; - return run_callback(src, stdarg_many_test_callback); -} - -/* - * Test Win32 stdarg handling, since the calling convention will pass a pointer - * to the struct and the stdarg pointer must point to that pointer initially. - */ - -typedef struct {long long a, b, c;} stdarg_struct_test_struct_type; -typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...); - -static int stdarg_struct_test_callback(void *ptr) { - stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr; - stdarg_struct_test_struct_type v = {10, 35, 99}; - int x = f(v, 234); - return (x == 378) ? 0 : -1; -} - -static int stdarg_struct_test(void) { - const char *src = - "#include \n" - "typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n" - "int f(stdarg_struct_test_struct_type a, ...) {\n" - " va_list ap;\n" - " va_start(ap, a);\n" - " int z = va_arg(ap, int);\n" - " va_end(ap);\n" - " return z + a.a + a.b + a.c;\n" - "}\n"; - return run_callback(src, stdarg_struct_test_callback); -} - -/* Test that x86-64 arranges the stack correctly for arguments with alignment >8 bytes */ - -typedef LONG_DOUBLE (*arg_align_test_callback_type) (LONG_DOUBLE,int,LONG_DOUBLE,int,LONG_DOUBLE); - -static int arg_align_test_callback(void *ptr) { - arg_align_test_callback_type f = (arg_align_test_callback_type)ptr; - long double x = f(12, 0, 25, 0, 37); - return (x == 74) ? 0 : -1; -} - -static int arg_align_test(void) { - const char *src = - "long double f(long double a, int b, long double c, int d, long double e) {\n" - " return a + c + e;\n" - "}\n"; - return run_callback(src, arg_align_test_callback); -} - -#define RUN_TEST(t) \ - if (!testname || (strcmp(#t, testname) == 0)) { \ - fputs(#t "... ", stdout); \ - fflush(stdout); \ - if (t() == 0) { \ - fputs("success\n", stdout); \ - } else { \ - fputs("failure\n", stdout); \ - retval = EXIT_FAILURE; \ - } \ - } - -int main(int argc, char **argv) { - int i; - const char *testname = NULL; - int retval = EXIT_SUCCESS; - - /* if tcclib.h and libtcc1.a are not installed, where can we find them */ - for (i = 1; i < argc; ++i) { - if (!memcmp(argv[i], "run_test=", 9)) - testname = argv[i] + 9; - } - - g_argv = argv, g_argc = argc; - - RUN_TEST(ret_int_test); - RUN_TEST(ret_longlong_test); - RUN_TEST(ret_float_test); - RUN_TEST(ret_double_test); - RUN_TEST(ret_longdouble_test); - RUN_TEST(ret_2float_test); - RUN_TEST(ret_2double_test); - RUN_TEST(ret_8plus2double_test); - RUN_TEST(ret_6plus2longlong_test); -#if !defined __x86_64__ || defined _WIN32 - /* currently broken on x86_64 linux */ - RUN_TEST(ret_mixed_test); - RUN_TEST(ret_mixed2_test); -#endif - RUN_TEST(ret_mixed3_test); - RUN_TEST(reg_pack_test); - RUN_TEST(reg_pack_longlong_test); - RUN_TEST(sret_test); - RUN_TEST(one_member_union_test); - RUN_TEST(two_member_union_test); - RUN_TEST(many_struct_test); - RUN_TEST(many_struct_test_2); - RUN_TEST(many_struct_test_3); - RUN_TEST(stdarg_test); - RUN_TEST(stdarg_many_test); - RUN_TEST(stdarg_struct_test); - RUN_TEST(arg_align_test); - return retval; -} diff --git a/tinyc/tests/asmtest.S b/tinyc/tests/asmtest.S deleted file mode 100644 index 55787054a..000000000 --- a/tinyc/tests/asmtest.S +++ /dev/null @@ -1,975 +0,0 @@ -# gas comment with ``gnu'' style quotes - -/* some directive tests */ - - .byte 0xff - .byte 1, 2, 3 - .short 1, 2, 3 - .word 1, 2, 3 - .long 1, 2, 3 - .int 1, 2, 3 - .align 8 - .byte 1 -/* .align 16, 0x90 gas is too clever for us with 0x90 fill */ - .balign 4, 0x92 - .align 16, 0x91 /* 0x91 tests the non-clever behaviour */ - .skip 3 - .skip 15, 0x90 - .string "hello\0world" -/* Macro expansion should work like with C, the #n shouldn't be parsed - as asm line comment */ -#define __stringify(n) #n -#define stringify(n) __stringify(n) - .skip 8,0x90 - .asciz stringify(BLA) - .skip 8,0x90 - -# 28 "asmtest.S" # a line directive (and a line comment) - movl %eax, %ebx # some more asm comment -/* some label tests */ -L1: - movl %eax, %ebx - mov 0x10000, %eax -L2: - movl $L2 - L1, %ecx -var1: - nop ; nop ; nop ; nop - - mov var1, %eax - -/* instruction tests */ -movl %eax, %ebx -mov 0x10000, %eax -mov 0x10000, %ax -mov 0x10000, %al -mov %al, 0x10000 - -mov $1, %edx -mov $1, %dx -mov $1, %cl -movb $2, 0x100(%ebx,%edx,2) -movw $2, 0x100(%ebx,%edx,2) -movl $2, 0x100(%ebx,%edx,2) -movl %eax, 0x100(%ebx,%edx,2) -movl 0x100(%ebx,%edx,2), %edx -movw %ax, 0x100(%ebx,%edx,2) - -movw $0x1122,%si -movl $0x112233,%edx -movl $0x80000000, %esi -movl $-0x7fffffff, %edi -#ifdef __x86_64__ -mov $0x11223344,%rbx -movq $0x11223344,%rbx -mov $0x1122334455,%rbx -movq $0x1122334455,%rbx -movl $0x11334455,(%rbx) -#endif - -mov %eax, 0x12(,%edx,2) - -#ifdef __i386__ -mov %cr3, %edx -mov %ecx, %cr3 -movl %cr3, %eax -movl %tr3, %eax -movl %db3, %ebx -movl %dr6, %eax -#else -mov %cr3, %rdx -mov %rcx, %cr3 -movq %cr3, %rax -movq %db3, %rbx -movq %dr6, %rax -mov %cr8, %rsi -mov %rdi, %cr8 -#endif -movl %fs, %ecx -movl %ebx, %fs - -#ifdef __x86_64__ -movq %r8, %r9 -movq %r10, %r11 -movq %r12, %r13 -movq %r14, %r15 -movq %rax, %r9 -movq %r15, %rsi -inc %r9b -dec %r10w -not %r11d -negq %r12 -decb %r13b -incw %r14w -notl %r15d -#endif - - movsbl 0x1000, %eax - movsbw 0x1000, %ax - movswl 0x1000, %eax - - movzbl 0x1000, %eax - movzbw 0x1000, %ax - movzwl 0x1000, %eax - - movzb 0x1000, %eax - movzb 0x1000, %ax - - mov $0x12345678,%eax - -#ifdef __x86_64__ - movzb 0x1000, %rax - movzbq 0x1000, %rbx - movsbq 0x1000, %rdx - movzwq 0x1000, %rdi - movswq 0x1000, %rdx - movslq %eax, %rcx - mov $0x12345678,%rax - mov $0x12345678,%rdx - mov $0x12345678,%r10 - mov $0x123456789abcdef0,%rax - mov $0x123456789abcdef0,%rcx - mov $0x123456789abcdef0,%r11 -#endif - -#ifdef __i386__ - pushl %eax - push %eax - push %cs -#else - pushq %rax - push %rax -#endif - pushw %ax - push %gs - push $1 - push $100 - push 0x42(%eax) - pop 0x43(%esi) - -#ifdef __i386__ - popl %eax - pop %eax - pop %ds -#else - popq %rax - pop %rax -#endif - popw %ax - pop %fs - - xchg %eax, %ecx - xchg %edx, %eax - xchg %bx, 0x10000 - xchg 0x10000, %ebx - xchg 0x10000, %dl - - in $100, %al - in $100, %ax - in $100, %eax - in %dx, %al - in %dx, %ax - in %dx, %eax - inb %dx - inw %dx - inl %dx - - out %al, $100 - out %ax, $100 - out %eax, $100 - - /* NOTE: gas is bugged here, so size must be added */ - outb %al, %dx - outw %ax, %dx - outl %eax, %dx - - leal 0x1000(%ebx), %ecx - lea 0x1000(%ebx), %ecx - -#ifdef __i386__ - les 0x2000, %eax - lds 0x2000, %ebx - lss 0x2000, %edx -#endif - lfs 0x2000, %ecx - lgs 0x2000, %edx - -addl $0x123, %eax -add $0x123, %ebx -add $-16, %ecx -add $-0x123, %esi -add $1, %bx -add $1, %ebx -add $-1, %bx -add $-1, %ebx -add $127, %bx -addl $127, %ebx -addl $-128, %ebx -addl $-128, %ebx -addl $-129, %ebx -addl $128, %ebx -addl $255, %ebx -addl $256, %ebx -andb $0xf, %ah -andb $-15, %cl -xorb $127, %dh -cmpb $42, (%eax) -addl $0x123, 0x100 -addl $0x123, 0x100(%ebx) -addl $0x123, 0x100(%ebx,%edx,2) -addl $0x123, 0x100(%esp) -addl $0x123, (3*8)(%esp) -addl $0x123, (%ebp) -addl $0x123, (%esp) -cmpl $0x123, (%esp) - -#ifdef __x86_64__ -xor %bl,%ah -xor %bl,%r8b -xor %r9b,%bl -xor %sil,%cl -add %eax,(%r8d) -add %ebx,(%r9) -add %edx,(%r10d,%r11d) -add %ecx,(%r12,%r13) -add %esi,(%r14,%r15,4) -add %edi,0x1000(%rbx,%r12,8) -add %r11,0x1000(%ebp,%r9d,8) -movb $12, %ah -movb $13, %bpl -movb $14, %dil -movb $15, %r12b -#endif - -add %eax, (%ebx) -add (%ebx), %eax - -or %dx, (%ebx) -or (%ebx), %si - -add %cl, (%ebx) -add (%ebx), %dl - - inc %edx - incl 0x10000 - incb 0x10000 - dec %dx - - test $1, %al - test $1, %cl - - testl $1, 0x1000 - testb $1, 0x1000 - testw $1, 0x1000 - test %eax, %ebx - test %eax, 0x1000 - test 0x1000, %edx - - not %edx - notw 0x10000 - notl 0x10000 - notb 0x10000 - - neg %edx - negw 0x10000 - negl 0x10000 - negb 0x10000 - - imul %ecx - mul %edx - mulb %cl - - imul %eax, %ecx - imul 0x1000, %cx - imul $10, %eax, %ecx - imul $10, %ax, %cx - imul $10, %eax - imul $0x1100000, %eax - imul $1, %eax - - idivw 0x1000 - div %ecx - div %bl - div %ecx, %eax - -and $15,%bx -and $-20,%edx - -shl %edx -shl $10, %edx -shl %cl, %edx - -shld $1, %eax, %edx -shld %cl, %eax, %edx -shld %eax, %edx - -shrd $1, %eax, %edx -shrd %cl, %eax, %edx -shrd %eax, %edx - -L4: -call 0x1000 -call L4 -#ifdef __i386__ -call *%eax -#else -call *%rax -#endif -call *0x1000 -call func1 - -.global L5,L6 - -L5: -L6: - -#ifdef __i386__ -lcall $0x100, $0x1000 -#else -lcall *0x100 -lcall *(%rax) -#endif - -jmp 0x1000 -jmp *(%edi) -#ifdef __i386__ -jmp *%eax -#else -jmp *%rax -#endif -jmp *0x1000 - -#ifdef __i386__ -ljmp $0x100, $0x1000 -#else -ljmp *0x100 -ljmp *(%rdi) -ljmpl *(%esi) -ljmpw *(%esi) -#endif - -ret -ret $10 -#ifdef __i386__ -retl -retl $10 -#else -retq -retq $10 -#endif - -lret - -lret $10 - -enter $1234, $10 - -L3: - jo 0x1000 - jnp 0x1001 - jne 0x1002 - jg 0x1003 - - jo L3 - jnp L3 - jne L3 - jg L3 - - loopne L3 - loopnz L3 - loope L3 - loopz L3 - loop L3 - jecxz L3 - - - seto %al - setc %al - setcb %al - setnp 0x1000 - setl 0xaaaa - setg %dl - - fadd - fadd %st(1), %st - fadd %st(0), %st(1) - fadd %st(3) - - fmul %st(0),%st(0) - fmul %st(0),%st(1) - - faddp %st(5) - faddp - faddp %st(1), %st - - fadds 0x1000 - fiadds 0x1002 - faddl 0x1004 - fiaddl 0x1006 - - fmul - fmul %st(1), %st - fmul %st(3) - - fmulp %st(5) - fmulp - fmulp %st(1), %st - - fmuls 0x1000 - fimuls 0x1002 - fmull 0x1004 - fimull 0x1006 - - fsub - fsub %st(1), %st - fsub %st(3) - - fsubp %st(5) - fsubp - fsubp %st(1), %st - - fsubs 0x1000 - fisubs 0x1002 - fsubl 0x1004 - fisubl 0x1006 - - fsubr - fsubr %st(1), %st - fsubr %st(3) - - fsubrp %st(5) - fsubrp - fsubrp %st(1), %st - - fsubrs 0x1000 - fisubrs 0x1002 - fsubrl 0x1004 - fisubrl 0x1006 - - fdiv - fdiv %st(1), %st - fdiv %st(3) - - fdivp %st(5) - fdivp - fdivp %st(1), %st - - fdivs 0x1000 - fidivs 0x1002 - fdivl 0x1004 - fidivl 0x1006 - - fcom %st(3) - - fcoms 0x1000 - ficoms 0x1002 - fcoml 0x1004 - ficoml 0x1006 - - fcomp %st(5) - fcomp - fcompp - - fcomps 0x1000 - ficomps 0x1002 - fcompl 0x1004 - ficompl 0x1006 - - fld %st(5) - fldl 0x1000 - flds 0x1002 - fildl 0x1004 - fst %st(4) - fstp %st(6) - fstpt 0x1006 - fbstp 0x1008 - - fxch - fxch %st(4) - - fucom %st(6) - fucomp %st(3) - fucompp - - finit - fninit - fldcw 0x1000 - fnstcw 0x1002 - fstcw 0x1002 - fnstsw 0x1004 - fnstsw (%eax) - fstsw 0x1004 - fstsw (%eax) - fnclex - fclex - fnstenv 0x1000 - fstenv 0x1000 - fldenv 0x1000 - fnsave 0x1002 - fsave 0x1000 - frstor 0x1000 - ffree %st(7) - ffreep %st(6) - - ftst - fxam - fld1 - fldl2t - fldl2e - fldpi - fldlg2 - fldln2 - fldz - - f2xm1 - fyl2x - fptan - fpatan - fxtract - fprem1 - fdecstp - fincstp - fprem - fyl2xp1 - fsqrt - fsincos - frndint - fscale - fsin - fcos - fchs - fabs - fnop - fwait - -bswap %edx -bswapl %ecx -xadd %ecx, %edx -xaddb %dl, 0x1000 -xaddw %ax, 0x1000 -xaddl %eax, 0x1000 -cmpxchg %ecx, %edx -cmpxchgb %dl, 0x1000 -cmpxchgw %ax, 0x1000 -cmpxchgl %eax, 0x1000 -invlpg 0x1000 -cmpxchg8b 0x1002 -#ifdef __x86_64__ -cmpxchg16b (%rax) -cmpxchg16b (%r10,%r11) -#endif - -fcmovb %st(5), %st -fcmove %st(5), %st -fcmovbe %st(5), %st -fcmovu %st(5), %st -fcmovnb %st(5), %st -fcmovne %st(5), %st -fcmovnbe %st(5), %st -fcmovnu %st(5), %st -fcomi %st(5), %st -fucomi %st(5), %st -fcomip %st(5), %st -fucomip %st(5), %st - - - - cmovo 0x1000, %eax - cmovs 0x1000, %eax - cmovns %edx, %edi - cmovne %ax, %si -#ifdef __x86_64__ - bswapq %rsi - bswapq %r10 - cmovz %rdi,%rbx -#endif - -int $3 -int $0x10 - -#ifdef __i386__ - pusha - popa -#endif - clc # another comment - cld # a comment with embedded ' tick - cli - clts - cmc - lahf - sahf -#ifdef __i386__ - pushfl - popfl -#else - pushfq - popfq -#endif - pushf - popf - stc - std - sti -#ifdef __i386__ - aaa - aas - daa - das - aad - aam - into -#endif - cbw - cwd - cwde - cdq - cbtw - cwtd - cwtl - cltd - leave - int3 - iret - rsm - hlt - wait - nop - - /* XXX: handle prefixes */ -#if 0 - aword - addr16 -#endif - lock - rep - repe - repz - repne - repnz - nop - - lock ;negl (%eax) - wait ;pushf - rep ;stosb - repe ;lodsb - repz ;cmpsb - repne;movsb - repnz;outsb - - /* handle one-line prefix + ops */ - lock negl (%eax) - wait pushf - rep stosb - repe lodsb - repz cmpsb - repne movsb - repnz outsb - - invd - wbinvd - cpuid - wrmsr - rdtsc - rdmsr - rdpmc - ud2 -#ifdef __x86_64__ - syscall - sysret - sysretq - lfence - mfence - sfence - prefetchnta 0x18(%rdx) - prefetcht0 (%rcx) - prefetcht1 (%rsi) - prefetcht2 (%rdi) - prefetchw (%rdi) - clflush 0x1000(%rax,%rcx) - fxsaveq (%rdx) - fxsaveq (%r11) - fxrstorq (%rcx) - fxrstorq (%r10) - -#endif - - lar %ax,%dx - lar %eax,%dx - lar %ax,%edx - lar %eax,%edx -#ifdef __x86_64__ - lar %ax,%rdx - lar %eax,%rdx -#endif - emms - movd %edx, %mm3 - movd 0x1000, %mm2 - movd %mm4, %ecx - movd %mm5, 0x1000 - - movq 0x1000, %mm2 - movq %mm4, 0x1000 - - pand 0x1000, %mm3 - pand %mm4, %mm5 - - psllw $1, %mm6 - psllw 0x1000, %mm7 - psllw %mm2, %mm7 - - xlat - cmpsb - scmpw - insl - outsw - lodsb - slodl - movsb - movsl - smovb - scasb - sscaw - stosw - sstol - - bsf 0x1000, %ebx - bsr 0x1000, %ebx - bt %edx, 0x1000 - btl $2, 0x1000 - btc %edx, 0x1000 - btcl $2, 0x1000 - btr %edx, 0x1000 - btrl $2, 0x1000 - bts %edx, 0x1000 - btsl $2, 0x1000 - - - -#ifdef __i386__ - boundl %edx, 0x10000 - boundw %bx, 0x1000 - - arpl %bx, 0x1000 -#endif - lar 0x1000, %eax - lgdt 0x1000 - lidt 0x1000 - lldt 0x1000 - sgdt 0x1000 - sidt 0x1000 - sldt 0x1000 -#ifdef __x86_64__ - lgdtq 0x1000 - lidtq 0x1000 - sgdtq 0x1000 - sidtq 0x1000 - - swapgs - - str %rdx - str %r9 -#endif - - lmsw 0x1000 - lsl 0x1000, %ecx - ltr 0x1000 - ltr %si - smsw 0x1000 - str 0x1000 - str %ecx - str %dx - - verr 0x1000 - verw 0x1000 - -#ifdef __i386__ - push %ds - pushw %ds - pushl %ds - pop %ds - popw %ds - popl %ds -#endif - fxsave 1(%ebx) - fxrstor 1(%ecx) -#ifdef __i386__ - pushl $1 -#else - pushq $1 -#endif - pushw $1 - push $1 - -#ifdef __ASSEMBLER__ // should be defined, for S files - inc %eax -#endif - -#ifndef _WIN32 -ft1: ft2: ft3: ft4: ft5: ft6: ft7: ft8: ft9: - xor %eax, %eax - ret - -.type ft1,STT_FUNC -.type ft2,@STT_FUNC -.type ft3,%STT_FUNC -.type ft4,"STT_FUNC" -.type ft5,function -.type ft6,@function -.type ft7,%function -.type ft8,"function" -#endif - - pause -.rept 6 - nop -.endr -.fill 4,1,0x90 - -.section .text.one,"ax" -nop -.previous -.pushsection .text.one,"ax" -nop -.pushsection .text.two,"ax" -nop -.popsection -.popsection - -1: ud2 -.pushsection __bug_table,"a" -.align 8 -2: .long 1b - 2b - .long 0x600000 - 2b - .long 1b + 42 - .long 43 + 1b - .long 2b + 144 - .long 145 + 2b - .word 164, 0 - .org 2b+32 -#ifdef __x86_64__ - .quad 1b -#else - .long 1b -#endif -.popsection -3: mov %eax,%ecx -4: -.pushsection .text.three, "ax" -nop -.skip (-((4b-3b) > 0) * 2) , 0x90 -.popsection - -.globl overrideme -.weak overrideme - nop -.globl notimplemented -notimplemented: - ret -.set overrideme, notimplemented -overrideme = notimplemented -overrideme: - ret - - movd %esi, %mm1 - movd %edi, %xmm2 - movd (%ebx), %mm3 - movd (%ebx), %xmm3 - movd %mm1, %esi - movd %xmm2, %edi - movd %mm3, (%edx) - movd %xmm3, (%edx) -#ifdef __x86_64__ - movd %rsi, %mm1 - movd %rdi, %xmm2 - movd (%rbx), %mm3 - movd (%rbx), %xmm3 - movd %mm1, %r12 - movd %xmm2, %rdi - movd %mm3, (%r8) - movd %xmm3, (%r13) -#endif - - movq (%ebp), %mm1 - movq %mm2, (%edi) - movq (%edi), %xmm3 - movq %mm4, %mm5 -#ifdef __x86_64__ - movq %rcx, %mm1 - movq %rdx, %xmm2 - movq %r13, %xmm3 - /* movq mem64->xmm is encoded as f30f7e by GAS, but as - 660f6e by tcc (which really is a movd and would need - a REX.W prefix to be movq). */ - movq (%rsi), %xmm3 - movq %mm1, %rdx - movq %xmm3, %rcx - movq %xmm4, (%rsi) -#endif - -#define TEST_MMX_SSE(insn) \ - insn %mm1, %mm2; \ - insn %xmm2, %xmm3; \ - insn (%ebx), %xmm3; -#define TEST_MMX_SSE_I8(insn) \ - TEST_MMX_SSE(insn) \ - insn $0x42, %mm4; \ - insn $0x42, %xmm4; - - TEST_MMX_SSE(packssdw) - TEST_MMX_SSE(packsswb) - TEST_MMX_SSE(packuswb) - TEST_MMX_SSE(paddb) - TEST_MMX_SSE(paddw) - TEST_MMX_SSE(paddd) - TEST_MMX_SSE(paddsb) - TEST_MMX_SSE(paddsw) - TEST_MMX_SSE(paddusb) - TEST_MMX_SSE(paddusw) - TEST_MMX_SSE(pand) - TEST_MMX_SSE(pandn) - TEST_MMX_SSE(pcmpeqb) - TEST_MMX_SSE(pcmpeqw) - TEST_MMX_SSE(pcmpeqd) - TEST_MMX_SSE(pcmpgtb) - TEST_MMX_SSE(pcmpgtw) - TEST_MMX_SSE(pcmpgtd) - TEST_MMX_SSE(pmaddwd) - TEST_MMX_SSE(pmulhw) - TEST_MMX_SSE(pmullw) - TEST_MMX_SSE(por) - TEST_MMX_SSE(psllw) -TEST_MMX_SSE_I8(psllw) - TEST_MMX_SSE(pslld) -TEST_MMX_SSE_I8(pslld) - TEST_MMX_SSE(psllq) -TEST_MMX_SSE_I8(psllq) - TEST_MMX_SSE(psraw) -TEST_MMX_SSE_I8(psraw) - TEST_MMX_SSE(psrad) -TEST_MMX_SSE_I8(psrad) - TEST_MMX_SSE(psrlw) -TEST_MMX_SSE_I8(psrlw) - TEST_MMX_SSE(psrld) -TEST_MMX_SSE_I8(psrld) - TEST_MMX_SSE(psrlq) -TEST_MMX_SSE_I8(psrlq) - TEST_MMX_SSE(psubb) - TEST_MMX_SSE(psubw) - TEST_MMX_SSE(psubd) - TEST_MMX_SSE(psubsb) - TEST_MMX_SSE(psubsw) - TEST_MMX_SSE(psubusb) - TEST_MMX_SSE(psubusw) - TEST_MMX_SSE(punpckhbw) - TEST_MMX_SSE(punpckhwd) - TEST_MMX_SSE(punpckhdq) - TEST_MMX_SSE(punpcklbw) - TEST_MMX_SSE(punpcklwd) - TEST_MMX_SSE(punpckldq) - TEST_MMX_SSE(pxor) - - cvtpi2ps %mm1, %xmm2 - cvtpi2ps (%ebx), %xmm2 - TEST_MMX_SSE(pmaxsw) - TEST_MMX_SSE(pmaxub) - TEST_MMX_SSE(pminsw) - TEST_MMX_SSE(pminub) diff --git a/tinyc/tests/boundtest.c b/tinyc/tests/boundtest.c deleted file mode 100644 index 15bffb4ed..000000000 --- a/tinyc/tests/boundtest.c +++ /dev/null @@ -1,285 +0,0 @@ -#include -#include -#include - -#define NB_ITS 1000000 -//#define NB_ITS 1 -#define TAB_SIZE 100 - -int tab[TAB_SIZE]; -int ret_sum; -char tab3[256]; - -int test1(void) -{ - int i, sum = 0; - for(i=0;i= 2) - index = atoi(argv[1]) - 1; - - if ((index < 0) || (index >= index_max)) { - printf("N is outside of the valid range (%d)\n", index); - exit(2); - } - - /* well, we also use bounds on this ! */ - ftest = table_test[index]; - ftest(); - - return 0; -} - -/* - * without bound 0.77 s - * with bounds 4.73 - */ diff --git a/tinyc/tests/gcctestsuite.sh b/tinyc/tests/gcctestsuite.sh deleted file mode 100644 index f3cc538de..000000000 --- a/tinyc/tests/gcctestsuite.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture -TCC="./tcc -B. -I. -DNO_TRAMPOLINES" -rm -f tcc.sum tcc.log -nb_failed="0" - -for src in $TESTSUITE_PATH/compile/*.c ; do - echo $TCC -o /tmp/test.o -c $src - $TCC -o /tmp/test.o -c $src >> tcc.log 2>&1 - if [ "$?" = "0" ] ; then - result="PASS" - else - result="FAIL" - nb_failed=$(( $nb_failed + 1 )) - fi - echo "$result: $src" >> tcc.sum -done - -for src in $TESTSUITE_PATH/execute/*.c ; do - echo $TCC $src - $TCC $src >> tcc.log 2>&1 - if [ "$?" = "0" ] ; then - result="PASS" - else - result="FAIL" - nb_failed=$(( $nb_failed + 1 )) - fi - echo "$result: $src" >> tcc.sum -done - -echo "$nb_failed test(s) failed." >> tcc.sum -echo "$nb_failed test(s) failed." diff --git a/tinyc/tests/libtcc_test.c b/tinyc/tests/libtcc_test.c deleted file mode 100644 index 480d31488..000000000 --- a/tinyc/tests/libtcc_test.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Simple Test program for libtcc - * - * libtcc can be useful to use tcc as a "backend" for a code generator. - */ -#include -#include -#include - -#include "libtcc.h" - -/* this function is called by the generated code */ -int add(int a, int b) -{ - return a + b; -} - -/* this strinc is referenced by the generated code */ -const char hello[] = "Hello World!"; - -char my_program[] = -"#include \n" /* include the "Simple libc header for TCC" */ -"extern int add(int a, int b);\n" -"#ifdef _WIN32\n" /* dynamically linked data needs 'dllimport' */ -" __attribute__((dllimport))\n" -"#endif\n" -"extern const char hello[];\n" -"int fib(int n)\n" -"{\n" -" if (n <= 2)\n" -" return 1;\n" -" else\n" -" return fib(n-1) + fib(n-2);\n" -"}\n" -"\n" -"int foo(int n)\n" -"{\n" -" printf(\"%s\\n\", hello);\n" -" printf(\"fib(%d) = %d\\n\", n, fib(n));\n" -" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n" -" return 0;\n" -"}\n"; - -int main(int argc, char **argv) -{ - TCCState *s; - int i; - int (*func)(int); - - s = tcc_new(); - if (!s) { - fprintf(stderr, "Could not create tcc state\n"); - exit(1); - } - - /* if tcclib.h and libtcc1.a are not installed, where can we find them */ - for (i = 1; i < argc; ++i) { - char *a = argv[i]; - if (a[0] == '-') { - if (a[1] == 'B') - tcc_set_lib_path(s, a+2); - else if (a[1] == 'I') - tcc_add_include_path(s, a+2); - else if (a[1] == 'L') - tcc_add_library_path(s, a+2); - } - } - - /* MUST BE CALLED before any compilation */ - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - - if (tcc_compile_string(s, my_program) == -1) - return 1; - - /* as a test, we add symbols that the compiled program can use. - You may also open a dll with tcc_add_dll() and use symbols from that */ - tcc_add_symbol(s, "add", add); - tcc_add_symbol(s, "hello", hello); - - /* relocate the code */ - if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) - return 1; - - /* get entry symbol */ - func = tcc_get_symbol(s, "foo"); - if (!func) - return 1; - - /* run the code */ - func(32); - - /* delete the state */ - tcc_delete(s); - - return 0; -} diff --git a/tinyc/tests/pp/01.c b/tinyc/tests/pp/01.c deleted file mode 100644 index 2fc3d7960..000000000 --- a/tinyc/tests/pp/01.c +++ /dev/null @@ -1,6 +0,0 @@ -#define hash_hash # ## # -#define mkstr(a) # a -#define in_between(a) mkstr(a) -#define join(c, d) in_between(c hash_hash d) -char p[] = join(x, y); -// char p[] = "x ## y"; diff --git a/tinyc/tests/pp/01.expect b/tinyc/tests/pp/01.expect deleted file mode 100644 index cf5b15340..000000000 --- a/tinyc/tests/pp/01.expect +++ /dev/null @@ -1 +0,0 @@ -char p[] = "x ## y"; diff --git a/tinyc/tests/pp/02.c b/tinyc/tests/pp/02.c deleted file mode 100644 index feb1254e3..000000000 --- a/tinyc/tests/pp/02.c +++ /dev/null @@ -1,28 +0,0 @@ -#define x 3 -#define f(a) f(x * (a)) -#undef x -#define x 2 -#define g f -#define z z[0] -#define h g(~ -#define m(a) a(w) -#define w 0,1 -#define t(a) a -#define p() int -#define q(x) x -#define r(x,y) x ## y -#define str(x) # x -f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); -g(x+(3,4)-w) | h 5) & m -(f)^m(m); -char c[2][6] = { str(hello), str() }; -/* - * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); - * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); - * char c[2][6] = { "hello", "" }; - */ -#define L21 f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); -#define L22 g(x+(3,4)-w) | h 5) & m\ -(f)^m(m); -L21 -L22 diff --git a/tinyc/tests/pp/02.expect b/tinyc/tests/pp/02.expect deleted file mode 100644 index 8ae2eb9ea..000000000 --- a/tinyc/tests/pp/02.expect +++ /dev/null @@ -1,5 +0,0 @@ -f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); -f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); -char c[2][6] = { "hello", "" }; -f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); -f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); diff --git a/tinyc/tests/pp/03.c b/tinyc/tests/pp/03.c deleted file mode 100644 index a659245ec..000000000 --- a/tinyc/tests/pp/03.c +++ /dev/null @@ -1,15 +0,0 @@ -#define str(s) # s -#define xstr(s) str(s) -#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ - x ## s, x ## t) -#define INCFILE(n) vers ## n -#define glue(a, b) a ## b -#define xglue(a, b) glue(a, b) -#define HIGHLOW "hello" -#define LOW LOW ", world" -debug(1, 2); -fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away - == 0) str(: @\n), s); -\#include xstr(INCFILE(2).h) -glue(HIGH, LOW); -xglue(HIGH, LOW) diff --git a/tinyc/tests/pp/03.expect b/tinyc/tests/pp/03.expect deleted file mode 100644 index 44aad0ae1..000000000 --- a/tinyc/tests/pp/03.expect +++ /dev/null @@ -1,5 +0,0 @@ -printf("x" "1" "= %d, x" "2" "= %s", x1, x2); -fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); -\#include "vers2.h" -"hello"; -"hello" ", world" diff --git a/tinyc/tests/pp/04.c b/tinyc/tests/pp/04.c deleted file mode 100644 index 0068f3751..000000000 --- a/tinyc/tests/pp/04.c +++ /dev/null @@ -1,4 +0,0 @@ -#define foobar 1 -#define C(x,y) x##y -#define D(x) (C(x,bar)) -D(foo) diff --git a/tinyc/tests/pp/04.expect b/tinyc/tests/pp/04.expect deleted file mode 100644 index 7c67b0104..000000000 --- a/tinyc/tests/pp/04.expect +++ /dev/null @@ -1 +0,0 @@ -(1) diff --git a/tinyc/tests/pp/05.c b/tinyc/tests/pp/05.c deleted file mode 100644 index 72749416c..000000000 --- a/tinyc/tests/pp/05.c +++ /dev/null @@ -1,7 +0,0 @@ -#define t(x,y,z) x ## y ## z -#define xxx(s) int s[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), \ - t(10,,), t(,11,), t(,,12), t(,,) }; - -int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), - t(10,,), t(,11,), t(,,12), t(,,) }; -xxx(j) diff --git a/tinyc/tests/pp/05.expect b/tinyc/tests/pp/05.expect deleted file mode 100644 index 9f9be378f..000000000 --- a/tinyc/tests/pp/05.expect +++ /dev/null @@ -1,3 +0,0 @@ -int j[] = { 123, 45, 67, 89, - 10, 11, 12, }; -int j[] = { 123, 45, 67, 89, 10, 11, 12, }; diff --git a/tinyc/tests/pp/06.c b/tinyc/tests/pp/06.c deleted file mode 100644 index 28cfddece..000000000 --- a/tinyc/tests/pp/06.c +++ /dev/null @@ -1,5 +0,0 @@ -#define X(a,b, \ - c,d) \ - foo - -X(1,2,3,4) diff --git a/tinyc/tests/pp/06.expect b/tinyc/tests/pp/06.expect deleted file mode 100644 index 257cc5642..000000000 --- a/tinyc/tests/pp/06.expect +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/tinyc/tests/pp/07.c b/tinyc/tests/pp/07.c deleted file mode 100644 index b22b22bbc..000000000 --- a/tinyc/tests/pp/07.c +++ /dev/null @@ -1,4 +0,0 @@ -#define a() YES -#define b() a -b() -b()() diff --git a/tinyc/tests/pp/07.expect b/tinyc/tests/pp/07.expect deleted file mode 100644 index ad0e20a66..000000000 --- a/tinyc/tests/pp/07.expect +++ /dev/null @@ -1,2 +0,0 @@ -a -YES diff --git a/tinyc/tests/pp/08.c b/tinyc/tests/pp/08.c deleted file mode 100644 index 93018e11f..000000000 --- a/tinyc/tests/pp/08.c +++ /dev/null @@ -1,4 +0,0 @@ -// test macro expansion in arguments -#define s_pos s_s.s_pos -#define foo(x) (x) -foo(hej.s_pos) diff --git a/tinyc/tests/pp/08.expect b/tinyc/tests/pp/08.expect deleted file mode 100644 index 2b2e3eebd..000000000 --- a/tinyc/tests/pp/08.expect +++ /dev/null @@ -1 +0,0 @@ -(hej.s_s.s_pos) diff --git a/tinyc/tests/pp/09.c b/tinyc/tests/pp/09.c deleted file mode 100644 index 315b297cd..000000000 --- a/tinyc/tests/pp/09.c +++ /dev/null @@ -1,4 +0,0 @@ -#define C(a,b,c) a##b##c -#define N(x,y) C(x,_,y) -#define A_O aaaaoooo -N(A,O) diff --git a/tinyc/tests/pp/09.expect b/tinyc/tests/pp/09.expect deleted file mode 100644 index adce0f95e..000000000 --- a/tinyc/tests/pp/09.expect +++ /dev/null @@ -1 +0,0 @@ -aaaaoooo diff --git a/tinyc/tests/pp/10.c b/tinyc/tests/pp/10.c deleted file mode 100644 index f180eff1e..000000000 --- a/tinyc/tests/pp/10.c +++ /dev/null @@ -1,10 +0,0 @@ -#define f(x) x -#define g(x) f(x) f(x -#define i(x) g(x)) g(x -#define h(x) i(x))) i(x -#define k(x) i(x))) i(x)))) -f(x) -g(x)) -i(x))) -h(x)))) -k(x)))) diff --git a/tinyc/tests/pp/10.expect b/tinyc/tests/pp/10.expect deleted file mode 100644 index bd18e18e5..000000000 --- a/tinyc/tests/pp/10.expect +++ /dev/null @@ -1,5 +0,0 @@ -x -x x -x x x x -x x x x x x x x -x x x x x x x x)))) diff --git a/tinyc/tests/pp/11.c b/tinyc/tests/pp/11.c deleted file mode 100644 index c0edf629c..000000000 --- a/tinyc/tests/pp/11.c +++ /dev/null @@ -1,31 +0,0 @@ -#define D1(s, ...) s -#define D2(s, ...) s D1(__VA_ARGS__) -#define D3(s, ...) s D2(__VA_ARGS__) -#define D4(s, ...) s D3(__VA_ARGS__) - -D1(a) -D2(a, b) -D3(a, b, c) -D4(a, b, c, d) - -x D4(a, b, c, d) y -x D4(a, b, c) y -x D4(a, b) y -x D4(a) y -x D4() y - -#define GNU_COMMA(X,Y...) X,## Y - -x GNU_COMMA(A,B,C) y -x GNU_COMMA(A,B) y -x GNU_COMMA(A) y -x GNU_COMMA() y - -#define __sun_attr___noreturn__ __attribute__((__noreturn__)) -#define ___sun_attr_inner(__a) __sun_attr_##__a -#define __sun_attr__(__a) ___sun_attr_inner __a -#define __NORETURN __sun_attr__((__noreturn__)) -__NORETURN -#define X(...) -#define Y(...) 1 __VA_ARGS__ 2 -Y(X X() ()) diff --git a/tinyc/tests/pp/11.expect b/tinyc/tests/pp/11.expect deleted file mode 100644 index 6b9806c6c..000000000 --- a/tinyc/tests/pp/11.expect +++ /dev/null @@ -1,15 +0,0 @@ -a -a b -a b c -a b c d -x a b c d y -x a b c y -x a b y -x a y -x y -x A,B,C y -x A,B y -x A y -x y -__attribute__((__noreturn__)) -1 2 diff --git a/tinyc/tests/pp/12.S b/tinyc/tests/pp/12.S deleted file mode 100644 index 597ccb4cb..000000000 --- a/tinyc/tests/pp/12.S +++ /dev/null @@ -1,8 +0,0 @@ -#define SRC(y...) \ - 9999: y; \ - .section __ex_table, "a"; \ - .long 9999b, 6001f ; \ - // .previous - - SRC(1: movw (%esi), %bx) -6001: diff --git a/tinyc/tests/pp/12.expect b/tinyc/tests/pp/12.expect deleted file mode 100644 index 17a861c25..000000000 --- a/tinyc/tests/pp/12.expect +++ /dev/null @@ -1,2 +0,0 @@ - 9999: 1: movw (%esi), %bx; .section __ex_table, "a"; .long 9999b, 6001f ; -6001: diff --git a/tinyc/tests/pp/13.S b/tinyc/tests/pp/13.S deleted file mode 100644 index bf0b525f9..000000000 --- a/tinyc/tests/pp/13.S +++ /dev/null @@ -1,6 +0,0 @@ -# `modelist' label. Each video mode record looks like: -#ifdef AAA -# modelist' label. Each video mode record looks like: -#endif -.text -endtext: diff --git a/tinyc/tests/pp/13.expect b/tinyc/tests/pp/13.expect deleted file mode 100644 index c7a32305f..000000000 --- a/tinyc/tests/pp/13.expect +++ /dev/null @@ -1,2 +0,0 @@ -.text -endtext: diff --git a/tinyc/tests/pp/14.c b/tinyc/tests/pp/14.c deleted file mode 100644 index e15468c5f..000000000 --- a/tinyc/tests/pp/14.c +++ /dev/null @@ -1,13 +0,0 @@ -#define W Z -#define Z(X) W(X,2) -#define Y(X) Z(X) -#define X Y -return X(X(1)); - -#define P Q -#define Q(n) P(n,2) -return P(1); - -#define A (B * B) -#define B (A + A) -return A + B; diff --git a/tinyc/tests/pp/14.expect b/tinyc/tests/pp/14.expect deleted file mode 100644 index 37860440c..000000000 --- a/tinyc/tests/pp/14.expect +++ /dev/null @@ -1,3 +0,0 @@ -return Z(Z(1,2),2); -return Q(1,2); -return ((A + A) * (A + A)) + ((B * B) + (B * B)); diff --git a/tinyc/tests/pp/15.c b/tinyc/tests/pp/15.c deleted file mode 100644 index cf13f9a89..000000000 --- a/tinyc/tests/pp/15.c +++ /dev/null @@ -1,18 +0,0 @@ -// insert a space between two tokens if otherwise they -// would form a single token when read back - -#define n(x) x - -return (n(long)n(double))d; -return n(A)n(++)n(+)n(B); -return n(A)n(+)n(++)n(B); -return n(A)n(++)n(+)n(+)n(B); - -// not a hex float -return n(0x1E)n(-1); - -// unlike gcc but correct -// XXX: return n(x)+n(x)-n(1)+n(1)-2; - -// unlike gcc, but cannot appear in valid C -// XXX: return n(x)n(x)n(1)n(2)n(x); diff --git a/tinyc/tests/pp/15.expect b/tinyc/tests/pp/15.expect deleted file mode 100644 index b4f885e95..000000000 --- a/tinyc/tests/pp/15.expect +++ /dev/null @@ -1,5 +0,0 @@ -return (long double)d; -return A+++B; -return A+ ++B; -return A+++ +B; -return 0x1E -1; diff --git a/tinyc/tests/pp/16.c b/tinyc/tests/pp/16.c deleted file mode 100644 index 8b5b6428c..000000000 --- a/tinyc/tests/pp/16.c +++ /dev/null @@ -1,3 +0,0 @@ -/* The following should warn */ -#define A ... -#define A <<= diff --git a/tinyc/tests/pp/16.expect b/tinyc/tests/pp/16.expect deleted file mode 100644 index 695d6d41c..000000000 --- a/tinyc/tests/pp/16.expect +++ /dev/null @@ -1,2 +0,0 @@ - -16.c:3: warning: A redefined diff --git a/tinyc/tests/pp/17.c b/tinyc/tests/pp/17.c deleted file mode 100644 index f12196fe8..000000000 --- a/tinyc/tests/pp/17.c +++ /dev/null @@ -1,14 +0,0 @@ -#define STR1(u) # u -#define pass(a) a -#define __ASM_REG(reg) STR1(one##reg) -#define _ASM_DX __ASM_REG(tok) -X162 pass(__ASM_REG(tok)) -X161 pass(_ASM_DX) -X163 pass(STR1(one##tok)) - -X170 pass(x ## y) -X171 pass(x pass(##) y) - -#define Y(x) Z(x) -#define X Y -X180 return X(X(1)); diff --git a/tinyc/tests/pp/17.expect b/tinyc/tests/pp/17.expect deleted file mode 100644 index e95aafef8..000000000 --- a/tinyc/tests/pp/17.expect +++ /dev/null @@ -1,6 +0,0 @@ -X162 "onetok" -X161 "onetok" -X163 "one##tok" -X170 x ## y -X171 x ## y -X180 return Z(Z(1)); diff --git a/tinyc/tests/pp/18.c b/tinyc/tests/pp/18.c deleted file mode 100644 index 0961426ac..000000000 --- a/tinyc/tests/pp/18.c +++ /dev/null @@ -1,15 +0,0 @@ -#define M_RETI_ARG27(x,y,z,aa, ...) aa -#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__) -#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 0, useless) -#define M_EMPTYI_DETECT(...) 0, 1, -#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ () ) -#define EX -#define empty(x) -#define fnlike(x) yeah x -/* If the following macro is called with empty arg (X183), the use - of 'x' between fnlike and '(' doesn't hinder the recognition of this - being a further fnlike macro invocation. */ -#define usefnlike(x) fnlike x (x) -X181 M_EMPTYI_P_C1() -X182 M_EMPTYI_P_C1(x) -X183 usefnlike() diff --git a/tinyc/tests/pp/18.expect b/tinyc/tests/pp/18.expect deleted file mode 100644 index 447a9b2ed..000000000 --- a/tinyc/tests/pp/18.expect +++ /dev/null @@ -1,3 +0,0 @@ -X181 1 -X182 0 -X183 yeah diff --git a/tinyc/tests/pp/19.c b/tinyc/tests/pp/19.c deleted file mode 100644 index aa91abe0d..000000000 --- a/tinyc/tests/pp/19.c +++ /dev/null @@ -1,101 +0,0 @@ -#define M_C2I(a, ...) a ## __VA_ARGS__ -#define M_C(a, ...) M_C2I(a, __VA_ARGS__) -#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__ -#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__) - -#define M_RETI_ARG2(a, b, ...) b -#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__) -#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa -#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__) - -#define M_TOBOOLI_0 1, 0, -#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless) - -#define M_IFI_0(true_macro, ...) __VA_ARGS__ -#define M_IFI_1(true_macro, ...) true_macro -#define M_IF(c) M_C(M_IFI_, M_BOOL(c)) - -#define M_FLAT(...) __VA_ARGS__ -#define M_INVI_0 1 -#define M_INVI_1 0 -#define M_INV(x) M_C(M_INVI_, x) - -#define M_ANDI_00 0 -#define M_ANDI_01 0 -#define M_ANDI_10 0 -#define M_ANDI_11 1 -#define M_AND(x,y) M_C3(M_ANDI_, x, y) - -#define M_ORI_00 0 -#define M_ORI_01 1 -#define M_ORI_10 1 -#define M_ORI_11 1 -#define M_OR(x,y) M_C3(M_ORI_, x, y) - -#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless) - -#define M_EMPTYI_DETECT(...) 0, 1, -#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ()) -#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__) -#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () ) -#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__)))) -#define M_APPLY_FUNC2B(func, arg1, arg2) \ - M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2)) -#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \ - M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \ - M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \ - M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \ - M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \ - M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \ - M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \ - M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \ - M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \ - M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z) -#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ) -#define M_INIT_INIT(a) ,a, - -#define M_GET_METHOD(method, method_default, ...) \ - M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,) - -#define M_TEST_METHOD_P(method, oplist) \ - M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist)) - -#define TRUE 1 -#define TEST1(n) \ - M_IF(n)(ok,nok) -#define TEST2(op) \ - M_TEST_METHOD_P(INIT, op) -#define TEST3(op) \ - M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok) -#define TEST4(op) \ - TEST1(TEST2(op)) -#define KO(a) ((void)1) - -/* This checks that the various expansions that ultimately lead to - something like 'KO(arg,arg)', where 'KO' comes from a macro - expansion reducing from a large macro chain do not are regarded - as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO', - but X95 must not consume the (a,b) arguments outside the M_IF() - invocation to reduce the 'KO' macro to an invocation. Instead - X95 should reduce via M_IF(KO)(a,b) to 'a'. - - The other lines here are variations on this scheme, with X1 to - X6 coming from the bug report at - http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */ -X92 M_IF(KO) -X93 M_GET_METHOD(INIT, 0, INIT(KO)) -X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))) -X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b) -X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))) -X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok) -X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok) -X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok) -// test begins -X1 TEST1(TRUE) // ==> expect ok, get ok -// First test with a token which is not a macro -X2 TEST2((INIT(ok))) // ==> expect 1, get 1 -X3 TEST3((INIT(ok))) // ==> expect ok, get ok -// Then test with a token which is a macro, but should not be expanded. -X4 TEST2((INIT(KO))) // ==> expect 1, get 1 -X5 TEST4(INIT(KO)) -X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args" diff --git a/tinyc/tests/pp/19.expect b/tinyc/tests/pp/19.expect deleted file mode 100644 index 08c08581e..000000000 --- a/tinyc/tests/pp/19.expect +++ /dev/null @@ -1,14 +0,0 @@ -X92 M_IFI_1 -X93 KO -X94 KO -X95 a -X96 M_IFI_1 -X97 ok -X98 (1)(ok, nok) -X99 ok -X1 ok -X2 1 -X3 ok -X4 1 -X5 nok -X6 ok diff --git a/tinyc/tests/pp/20.c b/tinyc/tests/pp/20.c deleted file mode 100644 index 7944d62bc..000000000 --- a/tinyc/tests/pp/20.c +++ /dev/null @@ -1,13 +0,0 @@ -/* Various things I encountered while hacking the pre processor */ -#define wrap(x) x -#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__) -#define pr_warn(x,y) pr_warning(x,y) -#define net_ratelimited_function(function, ...) function(__VA_ARGS__) -X1 net_ratelimited_function(pr_warn, "pipapo", bla); -X2 net_ratelimited_function(wrap(pr_warn), "bla", foo); -#define two m n -#define chain4(a,b,c,d) a ## b ## c ## d -X2 chain4(two,o,p,q) -X3 chain4(o,two,p,q) -X4 chain4(o,p,two,q) -X5 chain4(o,p,q,two) diff --git a/tinyc/tests/pp/20.expect b/tinyc/tests/pp/20.expect deleted file mode 100644 index d19405d74..000000000 --- a/tinyc/tests/pp/20.expect +++ /dev/null @@ -1,6 +0,0 @@ -X1 printk(KERN_WARNING "pipapo",bla); -X2 printk(KERN_WARNING "bla",foo); -X2 twoopq -X3 otwopq -X4 optwoq -X5 opqtwo diff --git a/tinyc/tests/pp/21.c b/tinyc/tests/pp/21.c deleted file mode 100644 index 1316226a2..000000000 --- a/tinyc/tests/pp/21.c +++ /dev/null @@ -1,36 +0,0 @@ -/* accept 'defined' as result of substitution */ - ------ 1 ------ -#define AAA 2 -#define BBB -#define CCC (defined ( AAA ) && AAA > 1 && !defined BBB) -#if !CCC -OK -#else -NOT OK -#endif - ------ 2 ------ -#undef BBB -#if CCC -OK -#else -NOT OK -#endif - ------ 3 ------ -#define DEFINED defined -#define DDD (DEFINED ( AAA ) && AAA > 1 && !DEFINED BBB) -#if (DDD) -OK -#else -NOT OK -#endif - ------ 4 ------ -#undef AAA -#if !(DDD) -OK -#else -NOT OK -#endif diff --git a/tinyc/tests/pp/21.expect b/tinyc/tests/pp/21.expect deleted file mode 100644 index 5a1376bb1..000000000 --- a/tinyc/tests/pp/21.expect +++ /dev/null @@ -1,8 +0,0 @@ ------ 1 ------ -OK ------ 2 ------ -OK ------ 3 ------ -OK ------ 4 ------ -OK diff --git a/tinyc/tests/pp/pp-counter.c b/tinyc/tests/pp/pp-counter.c deleted file mode 100644 index 3978e1a7e..000000000 --- a/tinyc/tests/pp/pp-counter.c +++ /dev/null @@ -1,27 +0,0 @@ -X1 __COUNTER__ -X2 __COUNTER__ -#if __COUNTER__ -X3 __COUNTER__ -#endif -#define pass(x) x -#define a x __COUNTER__ y -#define a2 pass(__COUNTER__) -#define f(c) c __COUNTER__ -#define apply(d) d d __COUNTER__ x2 f(d) y2 __COUNTER__ -#define _paste(a,b) a ## b -#define paste(a,b) _paste(a,b) -#define _paste3(a,b,c) a ## b ## c -#define doublepaste(a,b) _paste3(a,b,b) -#define str(x) #x -X4 a -X5 f(a) -X6 f(b) -X7 f(__COUNTER__) -X8 apply(a) -X9 apply(f(a)) -X10 apply(__COUNTER__) -X11 apply(a2) -X12 str(__COUNTER__) -X13 paste(x,__COUNTER__) -X14 _paste(x,__COUNTER__) -X15 doublepaste(x,__COUNTER__) diff --git a/tinyc/tests/pp/pp-counter.expect b/tinyc/tests/pp/pp-counter.expect deleted file mode 100644 index 02fc535bc..000000000 --- a/tinyc/tests/pp/pp-counter.expect +++ /dev/null @@ -1,15 +0,0 @@ -X1 0 -X2 1 -X3 3 -X4 x 4 y -X5 x 5 y 6 -X6 b 7 -X7 8 9 -X8 x 10 y x 10 y 11 x2 x 10 y 12 y2 13 -X9 x 14 y 15 x 14 y 15 16 x2 x 14 y 15 17 y2 18 -X10 19 19 20 x2 19 21 y2 22 -X11 23 23 24 x2 23 25 y2 26 -X12 "__COUNTER__" -X13 x27 -X14 x__COUNTER__ -X15 x2828 diff --git a/tinyc/tests/tcctest.c b/tinyc/tests/tcctest.c deleted file mode 100644 index 099fc3544..000000000 --- a/tinyc/tests/tcctest.c +++ /dev/null @@ -1,3813 +0,0 @@ -/* - * TCC auto test program - */ -#include "config.h" - -#if GCC_MAJOR >= 3 - -/* Unfortunately, gcc version < 3 does not handle that! */ -#define ALL_ISOC99 - -/* only gcc 3 handles _Bool correctly */ -#define BOOL_ISOC99 - -/* gcc 2.95.3 does not handle correctly CR in strings or after strays */ -#define CORRECT_CR_HANDLING - -#endif - -#if defined(_WIN32) -#define LONG_LONG_FORMAT "%lld" -#define ULONG_LONG_FORMAT "%llu" -#else -#define LONG_LONG_FORMAT "%Ld" -#define ULONG_LONG_FORMAT "%Lu" -#endif - -// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC -#if defined(_WIN32) && defined(__GNUC__) -#define LONG_DOUBLE double -#define LONG_DOUBLE_LITERAL(x) x -#else -#define LONG_DOUBLE long double -#define LONG_DOUBLE_LITERAL(x) x ## L -#endif - -/* deprecated and no longer supported in gcc 3.3 */ -//#define ACCEPT_CR_IN_STRINGS - -/* __VA_ARGS__ and __func__ support */ -#define C99_MACROS - -/* test various include syntaxes */ - -#define TCCLIB_INC -#define TCCLIB_INC1 -#define TCCLIB_INC3 "tcclib.h" - -#include TCCLIB_INC - -#include TCCLIB_INC1.TCCLIB_INC2 - -#include TCCLIB_INC1.h> - -#include TCCLIB_INC3 - -#include - -#include "tcclib.h" - -#include "tcctest.h" - -/* Test two more ways to include a file named like a pp-number */ -#define INC(name) -#define funnyname 42test.h -#define incdir tests/ -#define incname < incdir funnyname > -#define __stringify(x) #x -#define stringify(x) __stringify(x) -#include INC(42test) -#include incname -#include stringify(funnyname) - -void intdiv_test(); -void string_test(); -void expr_test(); -void macro_test(); -void recursive_macro_test(); -void scope_test(); -void forward_test(); -void funcptr_test(); -void loop_test(); -void switch_test(); -void goto_test(); -void enum_test(); -void typedef_test(); -void struct_test(); -void array_test(); -void expr_ptr_test(); -void bool_test(); -void optimize_out(); -void expr2_test(); -void constant_expr_test(); -void expr_cmp_test(); -void char_short_test(); -void init_test(void); -void compound_literal_test(void); -int kr_test(); -void struct_assign_test(void); -void cast_test(void); -void bitfield_test(void); -void c99_bool_test(void); -void float_test(void); -void longlong_test(void); -void manyarg_test(void); -void stdarg_test(void); -void whitespace_test(void); -void relocation_test(void); -void old_style_function(void); -void alloca_test(void); -void c99_vla_test(int size1, int size2); -void sizeof_test(void); -void typeof_test(void); -void local_label_test(void); -void statement_expr_test(void); -void asm_test(void); -void builtin_test(void); -void weak_test(void); -void global_data_test(void); -void cmp_comparison_test(void); -void math_cmp_test(void); -void callsave_test(void); -void builtin_frame_address_test(void); -void attrib_test(void); - -int fib(int n); -void num(int n); -void forward_ref(void); -int isid(int c); - -/* Line joining happens before tokenization, so the following - must be parsed as ellipsis. */ -void funny_line_continuation (int, ..\ -. ); - -char via_volatile (char); - -#define A 2 -#define N 1234 + A -#define pf printf -#define M1(a, b) (a) + (b) - -#define str\ -(s) # s -#define glue(a, b) a ## b -#define xglue(a, b) glue(a, b) -#define HIGHLOW "hello" -#define LOW LOW ", world" - -static int onetwothree = 123; -#define onetwothree4 onetwothree -#define onetwothree xglue(onetwothree,4) - -#define min(a, b) ((a) < (b) ? (a) : (b)) - -#ifdef C99_MACROS -#define dprintf(level,...) printf(__VA_ARGS__) -#endif - -/* gcc vararg macros */ -#define dprintf1(level, fmt, args...) printf(fmt, ## args) - -#define MACRO_NOARGS() - -#define AAA 3 -#undef AAA -#define AAA 4 - -#if 1 -#define B3 1 -#elif 1 -#define B3 2 -#elif 0 -#define B3 3 -#else -#define B3 4 -#endif - -#ifdef __TINYC__ -/* We try to handle this syntax. Make at least sure it doesn't segfault. */ -char invalid_function_def()[] {} -#endif - -#define __INT64_C(c) c ## LL -#define INT64_MIN (-__INT64_C(9223372036854775807)-1) - -int qq(int x) -{ - return x + 40; -} -#define qq(x) x - -#define spin_lock(lock) do { } while (0) -#define wq_spin_lock spin_lock -#define TEST2() wq_spin_lock(a) - -#define UINT_MAX ((unsigned) -1) - -void intdiv_test(void) -{ - printf("18/21=%u\n", 18/21); - printf("18%%21=%u\n", 18%21); - printf("41/21=%u\n", 41/21); - printf("41%%21=%u\n", 41%21); - printf("42/21=%u\n", 42/21); - printf("42%%21=%u\n", 42%21); - printf("43/21=%u\n", 43/21); - printf("43%%21=%u\n", 43%21); - printf("126/21=%u\n", 126/21); - printf("126%%21=%u\n", 126%21); - printf("131/21=%u\n", 131/21); - printf("131%%21=%u\n", 131%21); - printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2); - printf("(UINT_MAX/2+3)%%2=%u\n", (UINT_MAX/2+3)%2); - - printf("18/-21=%u\n", 18/-21); - printf("18%%-21=%u\n", 18%-21); - printf("41/-21=%u\n", 41/-21); - printf("41%%-21=%u\n", 41%-21); - printf("42/-21=%u\n", 42/-21); - printf("42%%-21=%u\n", 42%-21); - printf("43/-21=%u\n", 43/-21); - printf("43%%-21=%u\n", 43%-21); - printf("126/-21=%u\n", 126/-21); - printf("126%%-21=%u\n", 126%-21); - printf("131/-21=%u\n", 131/-21); - printf("131%%-21=%u\n", 131%-21); - printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2); - printf("(UINT_MAX/2+3)%%-2=%u\n", (UINT_MAX/2+3)%-2); - - printf("-18/21=%u\n", -18/21); - printf("-18%%21=%u\n", -18%21); - printf("-41/21=%u\n", -41/21); - printf("-41%%21=%u\n", -41%21); - printf("-42/21=%u\n", -42/21); - printf("-42%%21=%u\n", -42%21); - printf("-43/21=%u\n", -43/21); - printf("-43%%21=%u\n", -43%21); - printf("-126/21=%u\n", -126/21); - printf("-126%%21=%u\n", -126%21); - printf("-131/21=%u\n", -131/21); - printf("-131%%21=%u\n", -131%21); - printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2); - printf("-(UINT_MAX/2+3)%%2=%u\n", (0-(UINT_MAX/2+3))%2); - - printf("-18/-21=%u\n", -18/-21); - printf("-18%%-21=%u\n", -18%-21); - printf("-41/-21=%u\n", -41/-21); - printf("-41%%-21=%u\n", -41%-21); - printf("-42/-21=%u\n", -42/-21); - printf("-42%%-21=%u\n", -42%-21); - printf("-43/-21=%u\n", -43/-21); - printf("-43%%-21=%u\n", -43%-21); - printf("-126/-21=%u\n", -126/-21); - printf("-126%%-21=%u\n", -126%-21); - printf("-131/-21=%u\n", -131/-21); - printf("-131%%-21=%u\n", -131%-21); - printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2); - printf("-(UINT_MAX/2+3)%%-2=%u\n", (0-(UINT_MAX/2+3))%-2); -} - -void macro_test(void) -{ - printf("macro:\n"); - pf("N=%d\n", N); - printf("aaa=%d\n", AAA); - - printf("min=%d\n", min(1, min(2, -1))); - - printf("s1=%s\n", glue(HIGH, LOW)); - printf("s2=%s\n", xglue(HIGH, LOW)); - printf("s3=%s\n", str("c")); - printf("s4=%s\n", str(a1)); - printf("B3=%d\n", B3); - - printf("onetwothree=%d\n", onetwothree); - -#ifdef A - printf("A defined\n"); -#endif -#ifdef B - printf("B defined\n"); -#endif -#ifdef A - printf("A defined\n"); -#else - printf("A not defined\n"); -#endif -#ifdef B - printf("B defined\n"); -#else - printf("B not defined\n"); -#endif - -#ifdef A - printf("A defined\n"); -#ifdef B - printf("B1 defined\n"); -#else - printf("B1 not defined\n"); -#endif -#else - printf("A not defined\n"); -#ifdef B - printf("B2 defined\n"); -#else - printf("B2 not defined\n"); -#endif -#endif - -#if 1+1 - printf("test true1\n"); -#endif -#if 0 - printf("test true2\n"); -#endif -#if 1-1 - printf("test true3\n"); -#endif -#if defined(A) - printf("test trueA\n"); -#endif -#if defined(B) - printf("test trueB\n"); -#endif - -#if 0 - printf("test 0\n"); -#elif 0 - printf("test 1\n"); -#elif 2 - printf("test 2\n"); -#else - printf("test 3\n"); -#endif - - MACRO_NOARGS(); - -#ifdef __LINE__ - printf("__LINE__ defined\n"); -#endif - - printf("__LINE__=%d __FILE__=%s\n", - __LINE__, __FILE__); -#if 0 -#line 200 - printf("__LINE__=%d __FILE__=%s\n", - __LINE__, __FILE__); -#line 203 "test" - printf("__LINE__=%d __FILE__=%s\n", - __LINE__, __FILE__); -#line 227 "tcctest.c" -#endif - - /* not strictly preprocessor, but we test it there */ -#ifdef C99_MACROS - printf("__func__ = %s\n", __func__); - dprintf(1, "vaarg=%d\n", 1); -#endif - dprintf1(1, "vaarg1\n"); - dprintf1(1, "vaarg1=%d\n", 2); - dprintf1(1, "vaarg1=%d %d\n", 1, 2); - - /* gcc extension */ - printf("func='%s'\n", __FUNCTION__); - - /* complicated macros in glibc */ - printf("INT64_MIN=" LONG_LONG_FORMAT "\n", INT64_MIN); - { - int a; - a = 1; - glue(a+, +); - printf("a=%d\n", a); - glue(a <, <= 2); - printf("a=%d\n", a); - } - - /* macro function with argument outside the macro string */ -#define MF_s MF_hello -#define MF_hello(msg) printf("%s\n",msg) - -#define MF_t printf("tralala\n"); MF_hello - - MF_s("hi"); - MF_t("hi"); - - /* test macro substitution inside args (should not eat stream) */ - printf("qq=%d\n", qq(qq)(2)); - - /* test zero argument case. NOTE: gcc 2.95.x does not accept a - null argument without a space. gcc 3.2 fixes that. */ - -#define qq1(x) 1 - printf("qq1=%d\n", qq1( )); - - /* comment with stray handling *\ -/ - /* this is a valid *\/ comment */ - /* this is a valid comment *\*/ - // this is a valid\ -comment - - /* test function macro substitution when the function name is - substituted */ - TEST2(); - - /* And again when the name and parentheses are separated by a - comment. */ - TEST2 /* the comment */ (); - - printf("%s\n", get_basefile_from_header()); - printf("%s\n", __BASE_FILE__); - printf("%s\n", get_file_from_header()); - printf("%s\n", __FILE__); - - /* Check that funnily named include was in fact included */ - have_included_42test_h = 1; - have_included_42test_h_second = 1; - have_included_42test_h_third = 1; -} - - -static void print_num(char *fn, int line, int num) { - printf("fn %s, line %d, num %d\n", fn, line, num); -} - -void recursive_macro_test(void) -{ - -#define ELF32_ST_TYPE(val) ((val) & 0xf) -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#define STB_WEAK 2 /* Weak symbol */ -#define ELFW(type) ELF##32##_##type - printf("%d\n", ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(123))); - -#define WRAP(x) x - -#define print_num(x) print_num(__FILE__,__LINE__,x) - print_num(123); - WRAP(print_num(123)); - WRAP(WRAP(print_num(123))); - -static struct recursive_macro { int rm_field; } G; -#define rm_field (G.rm_field) - printf("rm_field = %d\n", rm_field); - printf("rm_field = %d\n", WRAP(rm_field)); - WRAP((printf("rm_field = %d %d\n", rm_field, WRAP(rm_field)))); -} - -int op(a,b) -{ - return a / b; -} - -int ret(a) -{ - if (a == 2) - return 1; - if (a == 3) - return 2; - return 0; -} - -void ps(const char *s) -{ - int c; - while (1) { - c = *s; - if (c == 0) - break; - printf("%c", c); - s++; - } -} - -const char foo1_string[] = "\ -bar\n\ -test\14\ -1"; - -void string_test() -{ - unsigned int b; - printf("string:\n"); - printf("\141\1423\143\n");/* dezdez test */ - printf("\x41\x42\x43\x3a\n"); - printf("c=%c\n", 'r'); - printf("wc=%C 0x%lx %C\n", L'a', L'\x1234', L'c'); - printf("foo1_string='%s'\n", foo1_string); -#if 0 - printf("wstring=%S\n", L"abc"); - printf("wstring=%S\n", L"abc" L"def" "ghi"); - printf("'\\377'=%d '\\xff'=%d\n", '\377', '\xff'); - printf("L'\\377'=%d L'\\xff'=%d\n", L'\377', L'\xff'); -#endif - ps("test\n"); - b = 32; - while ((b = b + 1) < 96) { - printf("%c", b); - } - printf("\n"); - printf("fib=%d\n", fib(33)); - b = 262144; - while (b != 0x80000000) { - num(b); - b = b * 2; - } -} - -void loop_test() -{ - int i; - i = 0; - while (i < 10) - printf("%d", i++); - printf("\n"); - for(i = 0; i < 10;i++) - printf("%d", i); - printf("\n"); - i = 0; - do { - printf("%d", i++); - } while (i < 10); - printf("\n"); - - char count = 123; - /* c99 for loop init test */ - for (size_t count = 1; count < 3; count++) - printf("count=%d\n", count); - printf("count = %d\n", count); - - /* break/continue tests */ - i = 0; - while (1) { - if (i == 6) - break; - i++; - if (i == 3) - continue; - printf("%d", i); - } - printf("\n"); - - /* break/continue tests */ - i = 0; - do { - if (i == 6) - break; - i++; - if (i == 3) - continue; - printf("%d", i); - } while(1); - printf("\n"); - - for(i = 0;i < 10;i++) { - if (i == 3) - continue; - printf("%d", i); - } - printf("\n"); -} - -typedef int typedef_and_label; - -void goto_test() -{ - int i; - static void *label_table[3] = { &&label1, &&label2, &&label3 }; - - printf("goto:\n"); - i = 0; - /* This needs to parse as label, not as start of decl. */ - typedef_and_label: - s_loop: - if (i >= 10) - goto s_end; - printf("%d", i); - i++; - goto s_loop; - s_end: - printf("\n"); - - /* we also test computed gotos (GCC extension) */ - for(i=0;i<3;i++) { - goto *label_table[i]; - label1: - printf("label1\n"); - goto next; - label2: - printf("label2\n"); - goto next; - label3: - printf("label3\n"); - next: ; - } -} - -enum { - E0, - E1 = 2, - E2 = 4, - E3, - E4, -}; - -enum test { - E5 = 1000, -}; - -struct S_enum { - enum {E6 = 42, E7, E8} e:8; -}; - -enum ELong { - /* This is either 0 on L32 machines, or a large number - on L64 machines. We should be able to store this. */ - EL_large = ((unsigned long)0xf000 << 31) << 1, -}; - -enum { BIASU = -1U<<31 }; -enum { BIASS = -1 << 31 }; - -static int getint(int i) -{ - if (i) - return 0; - else - return (int)(-1U << 31); -} - -void enum_test() -{ - enum test b1; - /* The following should give no warning */ - unsigned *p = &b1; - struct S_enum s = {E7}; - printf("enum: %d\n", s.e); - printf("enum:\n%d %d %d %d %d %d\n", - E0, E1, E2, E3, E4, E5); - b1 = 1; - printf("b1=%d\n", b1); - printf("enum large: %ld\n", EL_large); - - if (getint(0) == BIASU) - printf("enum unsigned: ok\n"); - else - printf("enum unsigned: wrong\n"); - if (getint(0) == BIASS) - printf("enum unsigned: ok\n"); - else - printf("enum unsigned: wrong\n"); -} - -typedef int *my_ptr; - -typedef int mytype1; -typedef int mytype2; - -void typedef_test() -{ - my_ptr a; - mytype1 mytype2; - int b; - - a = &b; - *a = 1234; - printf("typedef:\n"); - printf("a=%d\n", *a); - mytype2 = 2; - printf("mytype2=%d\n", mytype2); -} - -void forward_test() -{ - printf("forward:\n"); - forward_ref(); - forward_ref(); -} - - -void forward_ref(void) -{ - printf("forward ok\n"); -} - -typedef struct struct1 { - int f1; - int f2, f3; - union union1 { - int v1; - int v2; - } u; - char str[3]; -} struct1; - -struct struct2 { - int a; - char b; -}; - -union union2 { - int w1; - int w2; -}; - -struct struct1 st1, st2; - -struct empty_mem { - /* nothing */ ; - int x; -}; - -int main(int argc, char **argv) -{ - string_test(); - expr_test(); - macro_test(); - recursive_macro_test(); - scope_test(); - forward_test(); - funcptr_test(); - loop_test(); - switch_test(); - goto_test(); - enum_test(); - typedef_test(); - struct_test(); - array_test(); - expr_ptr_test(); - bool_test(); - optimize_out(); - expr2_test(); - constant_expr_test(); - expr_cmp_test(); - char_short_test(); - init_test(); - compound_literal_test(); - kr_test(); - struct_assign_test(); - cast_test(); - bitfield_test(); - c99_bool_test(); - float_test(); - longlong_test(); - manyarg_test(); - stdarg_test(); - whitespace_test(); - relocation_test(); - old_style_function(); - alloca_test(); - c99_vla_test(5, 2); - sizeof_test(); - typeof_test(); - statement_expr_test(); - local_label_test(); - asm_test(); - builtin_test(); -#ifndef _WIN32 - weak_test(); -#endif - global_data_test(); - cmp_comparison_test(); - math_cmp_test(); - callsave_test(); - builtin_frame_address_test(); - intdiv_test(); - if (via_volatile (42) != 42) - printf ("via_volatile broken\n"); - attrib_test(); - return 0; -} - -int tab[3]; -int tab2[3][2]; - -int g; - -void f1(g) -{ - printf("g1=%d\n", g); -} - -void scope_test() -{ - printf("scope:\n"); - g = 2; - f1(1); - printf("g2=%d\n", g); - { - int g; - g = 3; - printf("g3=%d\n", g); - { - int g; - g = 4; - printf("g4=%d\n", g); - } - } - printf("g5=%d\n", g); -} - -void array_test() -{ - int i, j, a[4]; - - printf("array:\n"); - printf("sizeof(a) = %d\n", sizeof(a)); - printf("sizeof(\"a\") = %d\n", sizeof("a")); -#ifdef C99_MACROS - printf("sizeof(__func__) = %d\n", sizeof(__func__)); -#endif - printf("sizeof tab %d\n", sizeof(tab)); - printf("sizeof tab2 %d\n", sizeof tab2); - tab[0] = 1; - tab[1] = 2; - tab[2] = 3; - printf("%d %d %d\n", tab[0], tab[1], tab[2]); - for(i=0;i<3;i++) - for(j=0;j<2;j++) - tab2[i][j] = 10 * i + j; - for(i=0;i<3*2;i++) { - printf(" %3d", ((int *)tab2)[i]); - } - printf("\n"); - printf("sizeof(size_t)=%d\n", sizeof(size_t)); - printf("sizeof(ptrdiff_t)=%d\n", sizeof(ptrdiff_t)); -} - -void expr_test() -{ - int a, b; - a = 0; - printf("%d\n", a += 1); - printf("%d\n", a -= 2); - printf("%d\n", a *= 31232132); - printf("%d\n", a /= 4); - printf("%d\n", a %= 20); - printf("%d\n", a &= 6); - printf("%d\n", a ^= 7); - printf("%d\n", a |= 8); - printf("%d\n", a >>= 3); - printf("%d\n", a <<= 4); - - a = 22321; - b = -22321; - printf("%d\n", a + 1); - printf("%d\n", a - 2); - printf("%d\n", a * 312); - printf("%d\n", a / 4); - printf("%d\n", b / 4); - printf("%d\n", (unsigned)b / 4); - printf("%d\n", a % 20); - printf("%d\n", b % 20); - printf("%d\n", (unsigned)b % 20); - printf("%d\n", a & 6); - printf("%d\n", a ^ 7); - printf("%d\n", a | 8); - printf("%d\n", a >> 3); - printf("%d\n", b >> 3); - printf("%d\n", (unsigned)b >> 3); - printf("%d\n", a << 4); - printf("%d\n", ~a); - printf("%d\n", -a); - printf("%d\n", +a); - - printf("%d\n", 12 + 1); - printf("%d\n", 12 - 2); - printf("%d\n", 12 * 312); - printf("%d\n", 12 / 4); - printf("%d\n", 12 % 20); - printf("%d\n", 12 & 6); - printf("%d\n", 12 ^ 7); - printf("%d\n", 12 | 8); - printf("%d\n", 12 >> 2); - printf("%d\n", 12 << 4); - printf("%d\n", ~12); - printf("%d\n", -12); - printf("%d\n", +12); - printf("%d %d %d %d\n", - isid('a'), - isid('g'), - isid('T'), - isid('(')); -} - -int isid(int c) -{ - return (c >= 'a' & c <= 'z') | (c >= 'A' & c <= 'Z') | c == '_'; -} - -/**********************/ - -int vstack[10], *vstack_ptr; - -void vpush(int vt, int vc) -{ - *vstack_ptr++ = vt; - *vstack_ptr++ = vc; -} - -void vpop(int *ft, int *fc) -{ - *fc = *--vstack_ptr; - *ft = *--vstack_ptr; -} - -void expr2_test() -{ - int a, b; - - printf("expr2:\n"); - vstack_ptr = vstack; - vpush(1432432, 2); - vstack_ptr[-2] &= ~0xffffff80; - vpop(&a, &b); - printf("res= %d %d\n", a, b); -} - -void constant_expr_test() -{ - int a; - printf("constant_expr:\n"); - a = 3; - printf("%d\n", a * 16); - printf("%d\n", a * 1); - printf("%d\n", a + 0); -} - -int tab4[10]; - -void expr_ptr_test() -{ - int *p, *q; - int i = -1; - - printf("expr_ptr:\n"); - p = tab4; - q = tab4 + 10; - printf("diff=%d\n", q - p); - p++; - printf("inc=%d\n", p - tab4); - p--; - printf("dec=%d\n", p - tab4); - ++p; - printf("inc=%d\n", p - tab4); - --p; - printf("dec=%d\n", p - tab4); - printf("add=%d\n", p + 3 - tab4); - printf("add=%d\n", 3 + p - tab4); - - /* check if 64bit support is ok */ - q = p = 0; - q += i; - printf("%p %p %ld\n", q, p, p-q); - printf("%d %d %d %d %d %d\n", - p == q, p != q, p < q, p <= q, p >= q, p > q); - i = 0xf0000000; - p += i; - printf("%p %p %ld\n", q, p, p-q); - printf("%d %d %d %d %d %d\n", - p == q, p != q, p < q, p <= q, p >= q, p > q); - p = (int *)((char *)p + 0xf0000000); - printf("%p %p %ld\n", q, p, p-q); - printf("%d %d %d %d %d %d\n", - p == q, p != q, p < q, p <= q, p >= q, p > q); - p += 0xf0000000; - printf("%p %p %ld\n", q, p, p-q); - printf("%d %d %d %d %d %d\n", - p == q, p != q, p < q, p <= q, p >= q, p > q); - { - struct size12 { - int i, j, k; - }; - struct size12 s[2], *sp = s; - int i, j; - sp->i = 42; - sp++; - j = -1; - printf("%d\n", sp[j].i); - } -#ifdef __LP64__ - i = 1; - p = (int*)0x100000000UL + i; - i = ((long)p) >> 32; - printf("largeptr: %p %d\n", p, i); -#endif -} - -void expr_cmp_test() -{ - int a, b; - printf("constant_expr:\n"); - a = -1; - b = 1; - printf("%d\n", a == a); - printf("%d\n", a != a); - - printf("%d\n", a < b); - printf("%d\n", a <= b); - printf("%d\n", a <= a); - printf("%d\n", b >= a); - printf("%d\n", a >= a); - printf("%d\n", b > a); - - printf("%d\n", (unsigned)a < b); - printf("%d\n", (unsigned)a <= b); - printf("%d\n", (unsigned)a <= a); - printf("%d\n", (unsigned)b >= a); - printf("%d\n", (unsigned)a >= a); - printf("%d\n", (unsigned)b > a); -} - -struct empty { -}; - -struct aligntest1 { - char a[10]; -}; - -struct aligntest2 { - int a; - char b[10]; -}; - -struct aligntest3 { - double a, b; -}; - -struct aligntest4 { - double a[0]; -}; - -struct __attribute__((aligned(16))) aligntest5 -{ - int i; -}; -struct aligntest6 -{ - int i; -} __attribute__((aligned(16))); -struct aligntest7 -{ - int i; -}; -struct aligntest5 altest5[2]; -struct aligntest6 altest6[2]; -int pad1; -/* altest7 is correctly aligned to 16 bytes also with TCC, - but __alignof__ returns the wrong result (4) because we - can't store the alignment yet when specified on symbols - directly (it's stored in the type so we'd need to make - a copy of it). -- FIXED */ -struct aligntest7 altest7[2] __attribute__((aligned(16))); - -struct aligntest8 -{ - int i; -} __attribute__((aligned(4096))); - -struct Large { - unsigned long flags; - union { - void *u1; - int *u2; - }; - - struct { - union { - unsigned long index; - void *freelist; - }; - union { - unsigned long counters; - struct { - int bla; - }; - }; - }; - - union { - struct { - long u3; - long u4; - }; - void *u5; - struct { - unsigned long compound_head; - unsigned int compound_dtor; - unsigned int compound_order; - }; - }; -} __attribute__((aligned(2 * sizeof(long)))); - -typedef unsigned long long __attribute__((aligned(4))) unaligned_u64; - -struct aligntest9 { - unsigned int buf_nr; - unaligned_u64 start_lba; -}; - -struct aligntest10 { - unsigned int buf_nr; - unsigned long long start_lba; -}; - -void struct_test() -{ - struct1 *s; - union union2 u; - struct Large ls; - - printf("struct:\n"); - printf("sizes: %d %d %d %d\n", - sizeof(struct struct1), - sizeof(struct struct2), - sizeof(union union1), - sizeof(union union2)); - printf("offsets: %d\n", (int)((char*)&st1.u.v1 - (char*)&st1)); - st1.f1 = 1; - st1.f2 = 2; - st1.f3 = 3; - printf("st1: %d %d %d\n", - st1.f1, st1.f2, st1.f3); - st1.u.v1 = 1; - st1.u.v2 = 2; - printf("union1: %d\n", st1.u.v1); - u.w1 = 1; - u.w2 = 2; - printf("union2: %d\n", u.w1); - s = &st2; - s->f1 = 3; - s->f2 = 2; - s->f3 = 1; - printf("st2: %d %d %d\n", - s->f1, s->f2, s->f3); - printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1); - - /* align / size tests */ - printf("aligntest1 sizeof=%d alignof=%d\n", - sizeof(struct aligntest1), __alignof__(struct aligntest1)); - printf("aligntest2 sizeof=%d alignof=%d\n", - sizeof(struct aligntest2), __alignof__(struct aligntest2)); - printf("aligntest3 sizeof=%d alignof=%d\n", - sizeof(struct aligntest3), __alignof__(struct aligntest3)); - printf("aligntest4 sizeof=%d alignof=%d\n", - sizeof(struct aligntest4), __alignof__(struct aligntest4)); - printf("aligntest5 sizeof=%d alignof=%d\n", - sizeof(struct aligntest5), __alignof__(struct aligntest5)); - printf("aligntest6 sizeof=%d alignof=%d\n", - sizeof(struct aligntest6), __alignof__(struct aligntest6)); - printf("aligntest7 sizeof=%d alignof=%d\n", - sizeof(struct aligntest7), __alignof__(struct aligntest7)); - printf("aligntest8 sizeof=%d alignof=%d\n", - sizeof(struct aligntest8), __alignof__(struct aligntest8)); - printf("aligntest9 sizeof=%d alignof=%d\n", - sizeof(struct aligntest9), __alignof__(struct aligntest9)); - printf("aligntest10 sizeof=%d alignof=%d\n", - sizeof(struct aligntest10), __alignof__(struct aligntest10)); - printf("altest5 sizeof=%d alignof=%d\n", - sizeof(altest5), __alignof__(altest5)); - printf("altest6 sizeof=%d alignof=%d\n", - sizeof(altest6), __alignof__(altest6)); - printf("altest7 sizeof=%d alignof=%d\n", - sizeof(altest7), __alignof__(altest7)); - - /* empty structures (GCC extension) */ - printf("sizeof(struct empty) = %d\n", sizeof(struct empty)); - printf("alignof(struct empty) = %d\n", __alignof__(struct empty)); - - printf("Large: sizeof=%d\n", sizeof(ls)); - memset(&ls, 0, sizeof(ls)); - ls.compound_head = 42; - printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls)); -} - -/* XXX: depend on endianness */ -void char_short_test() -{ - int var1, var2; - - printf("char_short:\n"); - - var1 = 0x01020304; - var2 = 0xfffefdfc; - printf("s8=%d %d\n", - *(char *)&var1, *(char *)&var2); - printf("u8=%d %d\n", - *(unsigned char *)&var1, *(unsigned char *)&var2); - printf("s16=%d %d\n", - *(short *)&var1, *(short *)&var2); - printf("u16=%d %d\n", - *(unsigned short *)&var1, *(unsigned short *)&var2); - printf("s32=%d %d\n", - *(int *)&var1, *(int *)&var2); - printf("u32=%d %d\n", - *(unsigned int *)&var1, *(unsigned int *)&var2); - *(char *)&var1 = 0x08; - printf("var1=%x\n", var1); - *(short *)&var1 = 0x0809; - printf("var1=%x\n", var1); - *(int *)&var1 = 0x08090a0b; - printf("var1=%x\n", var1); -} - -/******************/ - -typedef struct Sym { - int v; - int t; - int c; - struct Sym *next; - struct Sym *prev; -} Sym; - -#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) - -static int toupper1(int a) -{ - return TOUPPER(a); -} - -static unsigned int calc_vm_flags(unsigned int prot) -{ - unsigned int prot_bits; - /* This used to segfault in some revisions: */ - prot_bits = ((0x1==0x00000001)?(prot&0x1):(prot&0x1)?0x00000001:0); - return prot_bits; -} - -void bool_test() -{ - int *s, a, b, t, f, i; - - a = 0; - s = (void*)0; - printf("!s=%d\n", !s); - - if (!s || !s[0]) - a = 1; - printf("a=%d\n", a); - - printf("a=%d %d %d\n", 0 || 0, 0 || 1, 1 || 1); - printf("a=%d %d %d\n", 0 && 0, 0 && 1, 1 && 1); - printf("a=%d %d\n", 1 ? 1 : 0, 0 ? 1 : 0); -#if 1 && 1 - printf("a1\n"); -#endif -#if 1 || 0 - printf("a2\n"); -#endif -#if 1 ? 0 : 1 - printf("a3\n"); -#endif -#if 0 ? 0 : 1 - printf("a4\n"); -#endif - - a = 4; - printf("b=%d\n", a + (0 ? 1 : a / 2)); - - /* test register spilling */ - a = 10; - b = 10; - a = (a + b) * ((a < b) ? - ((b - a) * (a - b)): a + b); - printf("a=%d\n", a); - - /* test complex || or && expressions */ - t = 1; - f = 0; - a = 32; - printf("exp=%d\n", f == (32 <= a && a <= 3)); - printf("r=%d\n", (t || f) + (t && f)); - - /* test ? : cast */ - { - int aspect_on; - int aspect_native = 65536; - double bfu_aspect = 1.0; - int aspect; - for(aspect_on = 0; aspect_on < 2; aspect_on++) { - aspect=aspect_on?(aspect_native*bfu_aspect+0.5):65535UL; - printf("aspect=%d\n", aspect); - } - } - - /* test ? : GCC extension */ - { - static int v1 = 34 ? : -1; /* constant case */ - static int v2 = 0 ? : -1; /* constant case */ - int a = 30; - - printf("%d %d\n", v1, v2); - printf("%d %d\n", a - 30 ? : a * 2, a + 1 ? : a * 2); - } - - /* again complex expression */ - for(i=0;i<256;i++) { - if (toupper1 (i) != TOUPPER (i)) - printf("error %d\n", i); - } - printf ("bits = 0x%x\n", calc_vm_flags (0x1)); -} - -extern int undefined_function(void); -extern int defined_function(void); - -static inline void refer_to_undefined(void) -{ - undefined_function(); -} - -void optimize_out(void) -{ - int i = 0 ? undefined_function() : defined_function(); - printf ("oo:%d\n", i); - int j = 1 ? defined_function() : undefined_function(); - printf ("oo:%d\n", j); - if (0) - printf("oo:%d\n", undefined_function()); - else - printf("oo:%d\n", defined_function()); - if (1) - printf("oo:%d\n", defined_function()); - else - printf("oo:%d\n", undefined_function()); - while (1) { - printf("oow:%d\n", defined_function()); - break; - printf("oow:%d\n", undefined_function()); - } - j = 1; - /* Following is a switch without {} block intentionally. */ - switch (j) - case 1: break; - printf ("oos:%d\n", defined_function()); - /* The following break shouldn't lead to disabled code after - the while. */ - while (1) - break; - printf ("ool1:%d\n", defined_function()); - /* Same for the other types of loops. */ - do - break; - while (1); - printf ("ool2:%d\n", defined_function()); - for (;;) - break; - printf ("ool3:%d\n", defined_function()); - /* Normal {} blocks without controlling statements - shouldn't reactivate code emission */ - while (1) { - { - break; - } - printf ("ool4:%d\n", undefined_function()); - } - j = 1; - while (j) { - if (j == 0) - break; /* this break shouldn't disable code outside the if. */ - printf("ool5:%d\n", defined_function()); - j--; - } - - j = 1; - while (j) { - if (1) - j--; - else - breakhere: break; - printf("ool6:%d\n", defined_function()); - goto breakhere; - } - - /* Test that constants in logical && are optimized: */ - i = 0 && undefined_function(); - i = defined_function() && 0 && undefined_function(); - if (0 && undefined_function()) - undefined_function(); - if (defined_function() && 0) - undefined_function(); - if (0 && 0) - undefined_function(); - if (defined_function() && 0 && undefined_function()) - undefined_function(); - /* The same for || : */ - i = 1 || undefined_function(); - i = defined_function() || 1 || undefined_function(); - if (1 || undefined_function()) - ; - else - undefined_function(); - if (defined_function() || 1) - ; - else - undefined_function(); - if (1 || 1) - ; - else - undefined_function(); - if (defined_function() || 1 || undefined_function()) - ; - else - undefined_function(); - - if (defined_function() && 0) - refer_to_undefined(); - - if (0) { - (void)sizeof( ({ - do { } while (0); - 0; - }) ); - undefined_function(); - } - - /* Leave the "if(1)return; printf()" in this order and last in the function */ - if (1) - return; - printf ("oor:%d\n", undefined_function()); -} - -int defined_function(void) -{ - static int i = 40; - return i++; -} - -/* GCC accepts that */ -static int tab_reinit[]; -static int tab_reinit[10]; - -//int cinit1; /* a global variable can be defined several times without error ! */ -int cinit1; -int cinit1; -int cinit1 = 0; -int *cinit2 = (int []){3, 2, 1}; - -void compound_literal_test(void) -{ - int *p, i; - char *q, *q3; - - printf("compound_test:\n"); - - p = (int []){1, 2, 3}; - for(i=0;i<3;i++) - printf(" %d", p[i]); - printf("\n"); - - for(i=0;i<3;i++) - printf("%d", cinit2[i]); - printf("\n"); - - q = "tralala1"; - printf("q1=%s\n", q); - - q = (char *){ "tralala2" }; - printf("q2=%s\n", q); - - q3 = (char *){ q }; - printf("q3=%s\n", q3); - - q = (char []){ "tralala3" }; - printf("q4=%s\n", q); - -#ifdef ALL_ISOC99 - p = (int []){1, 2, cinit1 + 3}; - for(i=0;i<3;i++) - printf(" %d", p[i]); - printf("\n"); - - for(i=0;i<3;i++) { - p = (int []){1, 2, 4 + i}; - printf("%d %d %d\n", - p[0], - p[1], - p[2]); - } -#endif -} - -/* K & R protos */ - -kr_func1(a, b) -{ - return a + b; -} - -int kr_func2(a, b) -{ - return a + b; -} - -kr_test() -{ - printf("kr_test:\n"); - printf("func1=%d\n", kr_func1(3, 4)); - printf("func2=%d\n", kr_func2(3, 4)); - return 0; -} - -void num(int n) -{ - char *tab, *p; - tab = (char*)malloc(20); - p = tab; - while (1) { - *p = 48 + (n % 10); - p++; - n = n / 10; - if (n == 0) - break; - } - while (p != tab) { - p--; - printf("%c", *p); - } - printf("\n"); - free(tab); -} - -/* structure assignment tests */ -struct structa1 { - int f1; - char f2; -}; - -struct structa1 ssta1; - -void struct_assign_test1(struct structa1 s1, int t, float f) -{ - printf("%d %d %d %f\n", s1.f1, s1.f2, t, f); -} - -struct structa1 struct_assign_test2(struct structa1 s1, int t) -{ - s1.f1 += t; - s1.f2 -= t; - return s1; -} - -void struct_assign_test(void) -{ - struct S { - struct structa1 lsta1, lsta2; - int i; - } s, *ps; - - ps = &s; - ps->i = 4; -#if 0 - printf("struct_assign_test:\n"); - - s.lsta1.f1 = 1; - s.lsta1.f2 = 2; - printf("%d %d\n", s.lsta1.f1, s.lsta1.f2); - s.lsta2 = s.lsta1; - printf("%d %d\n", s.lsta2.f1, s.lsta2.f2); -#else - s.lsta2.f1 = 1; - s.lsta2.f2 = 2; -#endif - struct_assign_test1(ps->lsta2, 3, 4.5); - - printf("before call: %d %d\n", s.lsta2.f1, s.lsta2.f2); - ps->lsta2 = struct_assign_test2(ps->lsta2, ps->i); - printf("after call: %d %d\n", ps->lsta2.f1, ps->lsta2.f2); - - static struct { - void (*elem)(); - } t[] = { - /* XXX: we should allow this even without braces */ - { struct_assign_test } - }; - printf("%d\n", struct_assign_test == t[0].elem); -} - -/* casts to short/char */ - -void cast1(char a, short b, unsigned char c, unsigned short d) -{ - printf("%d %d %d %d\n", a, b, c, d); -} - -char bcast; -short scast; - -void cast_test() -{ - int a; - char c; - char tab[10]; - unsigned b,d; - short s; - char *p = NULL; - p -= 0x700000000042; - - printf("cast_test:\n"); - a = 0xfffff; - cast1(a, a, a, a); - a = 0xffffe; - printf("%d %d %d %d\n", - (char)(a + 1), - (short)(a + 1), - (unsigned char)(a + 1), - (unsigned short)(a + 1)); - printf("%d %d %d %d\n", - (char)0xfffff, - (short)0xfffff, - (unsigned char)0xfffff, - (unsigned short)0xfffff); - - a = (bcast = 128) + 1; - printf("%d\n", a); - a = (scast = 65536) + 1; - printf("%d\n", a); - - printf("sizeof(c) = %d, sizeof((int)c) = %d\n", sizeof(c), sizeof((int)c)); - - /* test cast from unsigned to signed short to int */ - b = 0xf000; - d = (short)b; - printf("((unsigned)(short)0x%08x) = 0x%08x\n", b, d); - b = 0xf0f0; - d = (char)b; - printf("((unsigned)(char)0x%08x) = 0x%08x\n", b, d); - - /* test implicit int casting for array accesses */ - c = 0; - tab[1] = 2; - tab[c] = 1; - printf("%d %d\n", tab[0], tab[1]); - - /* test implicit casting on some operators */ - printf("sizeof(+(char)'a') = %d\n", sizeof(+(char)'a')); - printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a')); - printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a')); - - /* from pointer to integer types */ - printf("%d %d %ld %ld %lld %lld\n", - (int)p, (unsigned int)p, - (long)p, (unsigned long)p, - (long long)p, (unsigned long long)p); - - /* from integers to pointers */ - printf("%p %p %p %p\n", - (void *)a, (void *)b, (void *)c, (void *)d); -} - -/* initializers tests */ -struct structinit1 { - int f1; - char f2; - short f3; - int farray[3]; -}; - -int sinit1 = 2; -int sinit2 = { 3 }; -int sinit3[3] = { 1, 2, {{3}}, }; -int sinit4[3][2] = { {1, 2}, {3, 4}, {5, 6} }; -int sinit5[3][2] = { 1, 2, 3, 4, 5, 6 }; -int sinit6[] = { 1, 2, 3 }; -int sinit7[] = { [2] = 3, [0] = 1, 2 }; -char sinit8[] = "hello" "trala"; - -struct structinit1 sinit9 = { 1, 2, 3 }; -struct structinit1 sinit10 = { .f2 = 2, 3, .f1 = 1 }; -struct structinit1 sinit11 = { .f2 = 2, 3, .f1 = 1, -#ifdef ALL_ISOC99 - .farray[0] = 10, - .farray[1] = 11, - .farray[2] = 12, -#endif -}; - -char *sinit12 = "hello world"; -char *sinit13[] = { - "test1", - "test2", - "test3", -}; -char sinit14[10] = { "abc" }; -int sinit15[3] = { sizeof(sinit15), 1, 2 }; - -struct { int a[3], b; } sinit16[] = { { 1 }, 2 }; - -struct bar { - char *s; - int len; -} sinit17[] = { - "a1", 4, - "a2", 1 -}; - -int sinit18[10] = { - [2 ... 5] = 20, - 2, - [8] = 10, -}; - -struct complexinit0 { - int a; - int b; -}; - -struct complexinit { - int a; - const struct complexinit0 *b; -}; - -const static struct complexinit cix[] = { - [0] = { - .a = 2000, - .b = (const struct complexinit0[]) { - { 2001, 2002 }, - { 2003, 2003 }, - {} - } - } -}; - -struct complexinit2 { - int a; - int b[]; -}; - -struct complexinit2 cix20; - -struct complexinit2 cix21 = { - .a = 3000, - .b = { 3001, 3002, 3003 } -}; - -struct complexinit2 cix22 = { - .a = 4000, - .b = { 4001, 4002, 4003, 4004, 4005, 4006 } -}; - -typedef int arrtype1[]; -arrtype1 sinit19 = {1}; -arrtype1 sinit20 = {2,3}; -typedef int arrtype2[3]; -arrtype2 sinit21 = {4}; -arrtype2 sinit22 = {5,6,7}; - -/* Address comparisons of non-weak symbols with zero can be const-folded */ -int sinit23[2] = { "astring" ? sizeof("astring") : -1, - &sinit23 ? 42 : -1 }; - -extern int external_inited = 42; - -void init_test(void) -{ - int linit1 = 2; - int linit2 = { 3 }; - int linit4[3][2] = { {1, 2}, {3, 4}, {5, 6} }; - int linit6[] = { 1, 2, 3 }; - int i, j; - char linit8[] = "hello" "trala"; - int linit12[10] = { 1, 2 }; - int linit13[10] = { 1, 2, [7] = 3, [3] = 4, }; - char linit14[10] = "abc"; - int linit15[10] = { linit1, linit1 + 1, [6] = linit1 + 2, }; - struct linit16 { int a1, a2, a3, a4; } linit16 = { 1, .a3 = 2 }; - int linit17 = sizeof(linit17); - int zero = 0; - /* Addresses on non-weak symbols are non-zero, but not the access itself */ - int linit18[2] = {&zero ? 1 : -1, zero ? -1 : 1 }; - - printf("init_test:\n"); - - printf("sinit1=%d\n", sinit1); - printf("sinit2=%d\n", sinit2); - printf("sinit3=%d %d %d %d\n", - sizeof(sinit3), - sinit3[0], - sinit3[1], - sinit3[2] - ); - printf("sinit6=%d\n", sizeof(sinit6)); - printf("sinit7=%d %d %d %d\n", - sizeof(sinit7), - sinit7[0], - sinit7[1], - sinit7[2] - ); - printf("sinit8=%s\n", sinit8); - printf("sinit9=%d %d %d\n", - sinit9.f1, - sinit9.f2, - sinit9.f3 - ); - printf("sinit10=%d %d %d\n", - sinit10.f1, - sinit10.f2, - sinit10.f3 - ); - printf("sinit11=%d %d %d %d %d %d\n", - sinit11.f1, - sinit11.f2, - sinit11.f3, - sinit11.farray[0], - sinit11.farray[1], - sinit11.farray[2] - ); - - for(i=0;i<3;i++) - for(j=0;j<2;j++) - printf("[%d][%d] = %d %d %d\n", - i, j, sinit4[i][j], sinit5[i][j], linit4[i][j]); - printf("linit1=%d\n", linit1); - printf("linit2=%d\n", linit2); - printf("linit6=%d\n", sizeof(linit6)); - printf("linit8=%d %s\n", sizeof(linit8), linit8); - - printf("sinit12=%s\n", sinit12); - printf("sinit13=%d %s %s %s\n", - sizeof(sinit13), - sinit13[0], - sinit13[1], - sinit13[2]); - printf("sinit14=%s\n", sinit14); - - for(i=0;i<10;i++) printf(" %d", linit12[i]); - printf("\n"); - for(i=0;i<10;i++) printf(" %d", linit13[i]); - printf("\n"); - for(i=0;i<10;i++) printf(" %d", linit14[i]); - printf("\n"); - for(i=0;i<10;i++) printf(" %d", linit15[i]); - printf("\n"); - printf("%d %d %d %d\n", - linit16.a1, - linit16.a2, - linit16.a3, - linit16.a4); - /* test that initialisation is done after variable declare */ - printf("linit17=%d\n", linit17); - printf("sinit15=%d\n", sinit15[0]); - printf("sinit16=%d %d\n", sinit16[0].a[0], sinit16[1].a[0]); - printf("sinit17=%s %d %s %d\n", - sinit17[0].s, sinit17[0].len, - sinit17[1].s, sinit17[1].len); - for(i=0;i<10;i++) - printf("%x ", sinit18[i]); - printf("\n"); - /* complex init check */ - printf("cix: %d %d %d %d %d %d %d\n", - cix[0].a, - cix[0].b[0].a, cix[0].b[0].b, - cix[0].b[1].a, cix[0].b[1].b, - cix[0].b[2].a, cix[0].b[2].b); - printf("cix2: %d %d\n", cix21.b[2], cix22.b[5]); - printf("sizeof cix20 %d, cix21 %d, sizeof cix22 %d\n", sizeof cix20, sizeof cix21, sizeof cix22); - - printf("arrtype1: %d %d %d\n", sinit19[0], sinit20[0], sinit20[1]); - printf("arrtype2: %d %d\n", sizeof(sinit19), sizeof(sinit20)); - printf("arrtype3: %d %d %d\n", sinit21[0], sinit21[1], sinit21[2]); - printf("arrtype4: %d %d %d\n", sinit22[0], sinit22[1], sinit22[2]); - printf("arrtype5: %d %d\n", sizeof(sinit21), sizeof(sinit22)); - printf("arrtype6: %d\n", sizeof(arrtype2)); - - printf("sinit23= %d %d\n", sinit23[0], sinit23[1]); - printf("linit18= %d %d\n", linit18[0], linit18[1]); -} - -void switch_uc(unsigned char uc) -{ - switch (uc) { - case 0xfb ... 0xfe: - printf("ucsw:1\n"); - break; - case 0xff: - printf("ucsw:2\n"); - break; - case 0 ... 5: - printf("ucsw:3\n"); - break; - default: - printf("ucsw: broken!\n"); - } -} - -void switch_sc(signed char sc) -{ - switch (sc) { - case -5 ... -2: - printf("scsw:1\n"); - break; - case -1: - printf("scsw:2\n"); - break; - case 0 ... 5: - printf("scsw:3\n"); - break; - default: - printf("scsw: broken!\n"); - } -} - -void switch_test() -{ - int i; - unsigned long long ull; - long long ll; - - for(i=0;i<15;i++) { - switch(i) { - case 0: - case 1: - printf("a"); - break; - default: - printf("%d", i); - break; - case 8 ... 12: - printf("c"); - break; - case 3: - printf("b"); - break; - case 0xc33c6b9fU: - case 0x7c9eeeb9U: - break; - } - } - printf("\n"); - - for (i = 1; i <= 5; i++) { - ull = (unsigned long long)i << 61; - switch (ull) { - case 1ULL << 61: - printf("ullsw:1\n"); - break; - case 2ULL << 61: - printf("ullsw:2\n"); - break; - case 3ULL << 61: - printf("ullsw:3\n"); - break; - case 4ULL << 61: - printf("ullsw:4\n"); - break; - case 5ULL << 61: - printf("ullsw:5\n"); - break; - default: - printf("ullsw: broken!\n"); - } - } - - for (i = 1; i <= 5; i++) { - ll = (long long)i << 61; - switch (ll) { - case 1LL << 61: - printf("llsw:1\n"); - break; - case 2LL << 61: - printf("llsw:2\n"); - break; - case 3LL << 61: - printf("llsw:3\n"); - break; - case 4LL << 61: - printf("llsw:4\n"); - break; - case 5LL << 61: - printf("llsw:5\n"); - break; - default: - printf("llsw: broken!\n"); - } - } - - for (i = -5; i <= 5; i++) { - switch_uc((unsigned char)i); - } - - for (i = -5; i <= 5; i++) { - switch_sc ((signed char)i); - } -} - -/* ISOC99 _Bool type */ -void c99_bool_test(void) -{ -#ifdef BOOL_ISOC99 - int a; - _Bool b; - - printf("bool_test:\n"); - printf("sizeof(_Bool) = %d\n", sizeof(_Bool)); - a = 3; - printf("cast: %d %d %d\n", (_Bool)10, (_Bool)0, (_Bool)a); - b = 3; - printf("b = %d\n", b); - b++; - printf("b = %d\n", b); -#endif -} - -void bitfield_test(void) -{ - int a; - short sa; - unsigned char ca; - struct sbf1 { - int f1 : 3; - int : 2; - int f2 : 1; - int : 0; - int f3 : 5; - int f4 : 7; - unsigned int f5 : 7; - } st1; - printf("bitfield_test:"); - printf("sizeof(st1) = %d\n", sizeof(st1)); - - st1.f1 = 3; - st1.f2 = 1; - st1.f3 = 15; - a = 120; - st1.f4 = a; - st1.f5 = a; - st1.f5++; - printf("%d %d %d %d %d\n", - st1.f1, st1.f2, st1.f3, st1.f4, st1.f5); - sa = st1.f5; - ca = st1.f5; - printf("%d %d\n", sa, ca); - - st1.f1 = 7; - if (st1.f1 == -1) - printf("st1.f1 == -1\n"); - else - printf("st1.f1 != -1\n"); - if (st1.f2 == -1) - printf("st1.f2 == -1\n"); - else - printf("st1.f2 != -1\n"); - - struct sbf2 { - long long f1 : 45; - long long : 2; - long long f2 : 35; - unsigned long long f3 : 38; - } st2; - st2.f1 = 0x123456789ULL; - a = 120; - st2.f2 = (long long)a << 25; - st2.f3 = a; - st2.f2++; - printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3); - -#if 0 - Disabled for now until further clarification re GCC compatibility - struct sbf3 { - int f1 : 7; - int f2 : 1; - char f3; - int f4 : 8; - int f5 : 1; - int f6 : 16; - } st3; - printf("sizeof(st3) = %d\n", sizeof(st3)); -#endif - - struct sbf4 { - int x : 31; - char y : 2; - } st4; - st4.y = 1; - printf("st4.y == %d\n", st4.y); - struct sbf5 { - int a; - char b; - int x : 12, y : 4, : 0, : 4, z : 3; - char c; - } st5 = { 1, 2, 3, 4, -3, 6 }; - printf("st5 = %d %d %d %d %d %d\n", st5.a, st5.b, st5.x, st5.y, st5.z, st5.c); - struct sbf6 { - short x : 12; - unsigned char y : 2; - } st6; - st6.y = 1; - printf("st6.y == %d\n", st6.y); -} - -#ifdef __x86_64__ -#define FLOAT_FMT "%f\n" -#else -/* x86's float isn't compatible with GCC */ -#define FLOAT_FMT "%.5f\n" -#endif - -/* declare strto* functions as they are C99 */ -double strtod(const char *nptr, char **endptr); - -#if defined(_WIN32) -float strtof(const char *nptr, char **endptr) {return (float)strtod(nptr, endptr);} -LONG_DOUBLE strtold(const char *nptr, char **endptr) {return (LONG_DOUBLE)strtod(nptr, endptr);} -#else -float strtof(const char *nptr, char **endptr); -LONG_DOUBLE strtold(const char *nptr, char **endptr); -#endif - -#define FTEST(prefix, typename, type, fmt)\ -void prefix ## cmp(type a, type b)\ -{\ - printf("%d %d %d %d %d %d\n",\ - a == b,\ - a != b,\ - a < b,\ - a > b,\ - a >= b,\ - a <= b);\ - printf(fmt " " fmt " " fmt " " fmt " " fmt " " fmt " " fmt "\n",\ - a,\ - b,\ - a + b,\ - a - b,\ - a * b,\ - a / b,\ - -a);\ - printf(fmt "\n", ++a);\ - printf(fmt "\n", a++);\ - printf(fmt "\n", a);\ - b = 0;\ - printf("%d %d\n", !a, !b);\ -}\ -void prefix ## fcast(type a)\ -{\ - float fa;\ - double da;\ - LONG_DOUBLE la;\ - int ia;\ - long long llia;\ - unsigned int ua;\ - unsigned long long llua;\ - type b;\ - fa = a;\ - da = a;\ - la = a;\ - printf("ftof: %f %f %Lf\n", fa, da, la);\ - ia = (int)a;\ - llia = (long long)a;\ - a = (a >= 0) ? a : -a;\ - ua = (unsigned int)a;\ - llua = (unsigned long long)a;\ - printf("ftoi: %d %u %lld %llu\n", ia, ua, llia, llua);\ - ia = -1234;\ - ua = 0x81234500;\ - llia = -0x123456789012345LL;\ - llua = 0xf123456789012345LLU;\ - b = ia;\ - printf("itof: " fmt "\n", b);\ - b = ua;\ - printf("utof: " fmt "\n", b);\ - b = llia;\ - printf("lltof: " fmt "\n", b);\ - b = llua;\ - printf("ulltof: " fmt "\n", b);\ -}\ -\ -float prefix ## retf(type a) { return a; }\ -double prefix ## retd(type a) { return a; }\ -LONG_DOUBLE prefix ## retld(type a) { return a; }\ -\ -void prefix ## call(void)\ -{\ - printf("float: " FLOAT_FMT, prefix ## retf(42.123456789));\ - printf("double: %f\n", prefix ## retd(42.123456789));\ - printf("long double: %Lf\n", prefix ## retld(42.123456789));\ - printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ -}\ -\ -void prefix ## signed_zeros(void) \ -{\ - type x = 0.0, y = -0.0, n, p;\ - if (x == y)\ - printf ("Test 1.0 / x != 1.0 / y returns %d (should be 1).\n",\ - 1.0 / x != 1.0 / y);\ - else\ - printf ("x != y; this is wrong!\n");\ -\ - n = -x;\ - if (x == n)\ - printf ("Test 1.0 / x != 1.0 / -x returns %d (should be 1).\n",\ - 1.0 / x != 1.0 / n);\ - else\ - printf ("x != -x; this is wrong!\n");\ -\ - p = +y;\ - if (x == p)\ - printf ("Test 1.0 / x != 1.0 / +y returns %d (should be 1).\n",\ - 1.0 / x != 1.0 / p);\ - else\ - printf ("x != +y; this is wrong!\n");\ - p = -y;\ - if (x == p)\ - printf ("Test 1.0 / x != 1.0 / -y returns %d (should be 0).\n",\ - 1.0 / x != 1.0 / p);\ - else\ - printf ("x != -y; this is wrong!\n");\ -}\ -void prefix ## test(void)\ -{\ - printf("testing '%s'\n", #typename);\ - prefix ## cmp(1, 2.5);\ - prefix ## cmp(2, 1.5);\ - prefix ## cmp(1, 1);\ - prefix ## fcast(234.6);\ - prefix ## fcast(-2334.6);\ - prefix ## call();\ - prefix ## signed_zeros();\ -} - -FTEST(f, float, float, "%f") -FTEST(d, double, double, "%f") -FTEST(ld, long double, LONG_DOUBLE, "%Lf") - -double ftab1[3] = { 1.2, 3.4, -5.6 }; - - -void float_test(void) -{ -#if !defined(__arm__) || defined(__ARM_PCS_VFP) - float fa, fb; - double da, db; - int a; - unsigned int b; - - printf("float_test:\n"); - printf("sizeof(float) = %d\n", sizeof(float)); - printf("sizeof(double) = %d\n", sizeof(double)); - printf("sizeof(long double) = %d\n", sizeof(LONG_DOUBLE)); - ftest(); - dtest(); - ldtest(); - printf("%f %f %f\n", ftab1[0], ftab1[1], ftab1[2]); - printf("%f %f %f\n", 2.12, .5, 2.3e10); - // printf("%f %f %f\n", 0x1234p12, 0x1e23.23p10, 0x12dp-10); - da = 123; - printf("da=%f\n", da); - fa = 123; - printf("fa=%f\n", fa); - a = 4000000000; - da = a; - printf("da = %f\n", da); - b = 4000000000; - db = b; - printf("db = %f\n", db); -#endif -} - -int fib(int n) -{ - if (n <= 2) - return 1; - else - return fib(n-1) + fib(n-2); -} - -void funcptr_test() -{ - void (*func)(int); - int a; - struct { - int dummy; - void (*func)(int); - } st1; - long diff; - - printf("funcptr:\n"); - func = # - (*func)(12345); - func = num; - a = 1; - a = 1; - func(12345); - /* more complicated pointer computation */ - st1.func = num; - st1.func(12346); - printf("sizeof1 = %d\n", sizeof(funcptr_test)); - printf("sizeof2 = %d\n", sizeof funcptr_test); - printf("sizeof3 = %d\n", sizeof(&funcptr_test)); - printf("sizeof4 = %d\n", sizeof &funcptr_test); - a = 0; - func = num + a; - diff = func - num; - func(42); - (func + diff)(42); - (num + a)(43); -} - -void lloptest(long long a, long long b) -{ - unsigned long long ua, ub; - - ua = a; - ub = b; - /* arith */ - printf("arith: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", - a + b, - a - b, - a * b); - - if (b != 0) { - printf("arith1: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", - a / b, - a % b); - } - - /* binary */ - printf("bin: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", - a & b, - a | b, - a ^ b); - - /* tests */ - printf("test: %d %d %d %d %d %d\n", - a == b, - a != b, - a < b, - a > b, - a >= b, - a <= b); - - printf("utest: %d %d %d %d %d %d\n", - ua == ub, - ua != ub, - ua < ub, - ua > ub, - ua >= ub, - ua <= ub); - - /* arith2 */ - a++; - b++; - printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); - printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a++, b++); - printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", --a, --b); - printf("arith2: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); - b = ub = 0; - printf("not: %d %d %d %d\n", !a, !ua, !b, !ub); -} - -void llshift(long long a, int b) -{ - printf("shift: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", - (unsigned long long)a >> b, - a >> b, - a << b); - printf("shiftc: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", - (unsigned long long)a >> 3, - a >> 3, - a << 3); - printf("shiftc: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", - (unsigned long long)a >> 35, - a >> 35, - a << 35); -} - -void llfloat(void) -{ - float fa; - double da; - LONG_DOUBLE lda; - long long la, lb, lc; - unsigned long long ula, ulb, ulc; - la = 0x12345678; - ula = 0x72345678; - la = (la << 20) | 0x12345; - ula = ula << 33; - printf("la=" LONG_LONG_FORMAT " ula=" ULONG_LONG_FORMAT "\n", la, ula); - - fa = la; - da = la; - lda = la; - printf("lltof: %f %f %Lf\n", fa, da, lda); - - la = fa; - lb = da; - lc = lda; - printf("ftoll: " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", la, lb, lc); - - fa = ula; - da = ula; - lda = ula; - printf("ulltof: %f %f %Lf\n", fa, da, lda); - - ula = fa; - ulb = da; - ulc = lda; - printf("ftoull: " ULONG_LONG_FORMAT " " ULONG_LONG_FORMAT " " ULONG_LONG_FORMAT "\n", ula, ulb, ulc); -} - -long long llfunc1(int a) -{ - return a * 2; -} - -struct S { - int id; - char item; -}; - -long long int value(struct S *v) -{ - return ((long long int)v->item); -} - -long long llfunc2(long long x, long long y, int z) -{ - return x * y * z; -} - -void longlong_test(void) -{ - long long a, b, c; - int ia; - unsigned int ua; - printf("longlong_test:\n"); - printf("sizeof(long long) = %d\n", sizeof(long long)); - ia = -1; - ua = -2; - a = ia; - b = ua; - printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); - printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %Lx\n", - (long long)1, - (long long)-2, - 1LL, - 0x1234567812345679); - a = llfunc1(-3); - printf(LONG_LONG_FORMAT "\n", a); - - lloptest(1000, 23); - lloptest(0xff, 0x1234); - b = 0x72345678 << 10; - lloptest(-3, b); - llshift(0x123, 5); - llshift(-23, 5); - b = 0x72345678LL << 10; - llshift(b, 47); - - llfloat(); -#if 1 - b = 0x12345678; - a = -1; - c = a + b; - printf("%Lx\n", c); -#endif - - /* long long reg spill test */ - { - struct S a; - - a.item = 3; - printf("%lld\n", value(&a)); - } - lloptest(0x80000000, 0); - - { - long long *p, v, **pp; - v = 1; - p = &v; - p[0]++; - printf("another long long spill test : %lld\n", *p); - pp = &p; - - v = llfunc2(**pp, **pp, ia); - printf("a long long function (arm-)reg-args test : %lld\n", v); - } - a = 68719476720LL; - b = 4294967295LL; - printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b); - - printf(LONG_LONG_FORMAT "\n", 0x123456789LLU); - - /* long long pointer deref in argument passing test */ - a = 0x123; - long long *p = &a; - llshift(*p, 5); -} - -void manyarg_test(void) -{ - LONG_DOUBLE ld = 1234567891234LL; - printf("manyarg_test:\n"); - printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0); - printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %f %f\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - 1234567891234LL, 987654321986LL, - 42.0, 43.0); - printf("%Lf %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %f %f\n", - ld, 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - 1234567891234LL, 987654321986LL, - 42.0, 43.0); - printf("%d %d %d %d %d %d %d %d %Lf\n", - 1, 2, 3, 4, 5, 6, 7, 8, ld); - printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - LONG_LONG_FORMAT " " LONG_LONG_FORMAT "%f %f %Lf\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - 1234567891234LL, 987654321986LL, - 42.0, 43.0, ld); - printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - "%Lf " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %f %f %Lf\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - ld, 1234567891234LL, 987654321986LL, - 42.0, 43.0, ld); -} - -void vprintf1(const char *fmt, ...) -{ - va_list ap, aq; - const char *p; - int c, i; - double d; - long long ll; - LONG_DOUBLE ld; - - va_start(aq, fmt); - va_copy(ap, aq); - - p = fmt; - for(;;) { - c = *p; - if (c == '\0') - break; - p++; - if (c == '%') { - c = *p; - switch(c) { - case '\0': - goto the_end; - case 'd': - i = va_arg(ap, int); - printf("%d", i); - break; - case 'f': - d = va_arg(ap, double); - printf("%f", d); - break; - case 'l': - ll = va_arg(ap, long long); - printf(LONG_LONG_FORMAT, ll); - break; - case 'F': - ld = va_arg(ap, LONG_DOUBLE); - printf("%Lf", ld); - break; - } - p++; - } else { - putchar(c); - } - } - the_end: - va_end(aq); - va_end(ap); -} - -struct myspace { - short int profile; -}; - -void stdarg_for_struct(struct myspace bob, ...) -{ - struct myspace george, bill; - va_list ap; - short int validate; - - va_start(ap, bob); - bill = va_arg(ap, struct myspace); - george = va_arg(ap, struct myspace); - validate = va_arg(ap, int); - printf("stdarg_for_struct: %d %d %d %d\n", - bob.profile, bill.profile, george.profile, validate); - va_end(ap); -} - -void stdarg_for_libc(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); -} - -void stdarg_test(void) -{ - LONG_DOUBLE ld = 1234567891234LL; - struct myspace bob; - - vprintf1("%d %d %d\n", 1, 2, 3); - vprintf1("%f %d %f\n", 1.0, 2, 3.0); - vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0); - vprintf1("%F %F %F\n", LONG_DOUBLE_LITERAL(1.2), LONG_DOUBLE_LITERAL(2.3), LONG_DOUBLE_LITERAL(3.4)); - vprintf1("%d %f %l %F %d %f %l %F\n", - 1, 1.2, 3LL, LONG_DOUBLE_LITERAL(4.5), 6, 7.8, 9LL, LONG_DOUBLE_LITERAL(0.1)); - vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8); - vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0); - vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - "%l %l %f %f\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - 1234567891234LL, 987654321986LL, - 42.0, 43.0); - vprintf1("%F %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - "%l %l %f %f\n", - ld, 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - 1234567891234LL, 987654321986LL, - 42.0, 43.0); - vprintf1("%d %d %d %d %d %d %d %d %F\n", - 1, 2, 3, 4, 5, 6, 7, 8, ld); - vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - "%l %l %f %f %F\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - 1234567891234LL, 987654321986LL, - 42.0, 43.0, ld); - vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f " - "%F %l %l %f %f %F\n", - 1, 2, 3, 4, 5, 6, 7, 8, - 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0, - ld, 1234567891234LL, 987654321986LL, - 42.0, 43.0, ld); - - bob.profile = 42; - stdarg_for_struct(bob, bob, bob, bob.profile); - stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); -} - -void whitespace_test(void) -{ - char *str; - - #if 1 - pri\ -ntf("whitspace:\n"); -#endif - pf("N=%d\n", 2); - -#ifdef CORRECT_CR_HANDLING - pri\ -ntf("aaa=%d\n", 3); -#endif - - pri\ -\ -ntf("min=%d\n", 4); - -#ifdef ACCEPT_CR_IN_STRINGS - printf("len1=%d\n", strlen(" -")); -#ifdef CORRECT_CR_HANDLING - str = " -"; - printf("len1=%d str[0]=%d\n", strlen(str), str[0]); -#endif - printf("len1=%d\n", strlen(" a -")); -#endif /* ACCEPT_CR_IN_STRINGS */ -} - -int reltab[3] = { 1, 2, 3 }; - -int *rel1 = &reltab[1]; -int *rel2 = &reltab[2]; - -#ifdef _WIN64 -void relocation_test(void) {} -#else -void getmyaddress(void) -{ - printf("in getmyaddress\n"); -} - -#ifdef __LP64__ -long __pa_symbol(void) -{ - /* This 64bit constant was handled incorrectly, it was used as addend - (which can hold 64bit just fine) in connection with a symbol, - and TCC generates wrong code for that (displacements are 32bit only). - This effectively is "+ 0x80000000", and if addresses of globals - are below 2GB the result should be a number without high 32 bits set. */ - return ((long)(((unsigned long)(&rel1))) - (0xffffffff80000000UL)); -} -#endif - -unsigned long theaddress = (unsigned long)getmyaddress; -void relocation_test(void) -{ - void (*fptr)(void) = (void (*)(void))theaddress; - printf("*rel1=%d\n", *rel1); - printf("*rel2=%d\n", *rel2); - fptr(); -#ifdef __LP64__ - printf("pa_symbol=0x%lx\n", __pa_symbol() >> 63); -#endif -} -#endif - -void old_style_f(a,b,c) - int a, b; - double c; -{ - printf("a=%d b=%d b=%f\n", a, b, c); -} - -void decl_func1(int cmpfn()) -{ - printf("cmpfn=%lx\n", (long)cmpfn); -} - -void decl_func2(cmpfn) -int cmpfn(); -{ - printf("cmpfn=%lx\n", (long)cmpfn); -} - -void old_style_function(void) -{ - old_style_f((void *)1, 2, 3.0); - decl_func1(NULL); - decl_func2(NULL); -} - -void alloca_test() -{ -#if defined __i386__ || defined __x86_64__ || defined __arm__ - char *p = alloca(16); - strcpy(p,"123456789012345"); - printf("alloca: p is %s\n", p); - char *demo = "This is only a test.\n"; - /* Test alloca embedded in a larger expression */ - printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) ); -#endif -} - -void *bounds_checking_is_enabled() -{ - char ca[10], *cp = ca-1; - return (ca != cp + 1) ? cp : NULL; -} - -typedef int constant_negative_array_size_as_compile_time_assertion_idiom[(1 ? 2 : 0) - 1]; - -void c99_vla_test(int size1, int size2) -{ -#if defined __i386__ || defined __x86_64__ - int size = size1 * size2; - int tab1[size][2], tab2[10][2]; - void *tab1_ptr, *tab2_ptr, *bad_ptr; - - /* "size" should have been 'captured' at tab1 declaration, - so modifying it should have no effect on VLA behaviour. */ - size = size-1; - - printf("Test C99 VLA 1 (sizeof): "); - printf("%s\n", (sizeof tab1 == size1 * size2 * 2 * sizeof(int)) ? "PASSED" : "FAILED"); - tab1_ptr = tab1; - tab2_ptr = tab2; - printf("Test C99 VLA 2 (ptrs subtract): "); - printf("%s\n", (tab2 - tab1 == (tab2_ptr - tab1_ptr) / (sizeof(int) * 2)) ? "PASSED" : "FAILED"); - printf("Test C99 VLA 3 (ptr add): "); - printf("%s\n", &tab1[5][1] == (tab1_ptr + (5 * 2 + 1) * sizeof(int)) ? "PASSED" : "FAILED"); - printf("Test C99 VLA 4 (ptr access): "); - tab1[size1][1] = 42; - printf("%s\n", (*((int *) (tab1_ptr + (size1 * 2 + 1) * sizeof(int))) == 42) ? "PASSED" : "FAILED"); - - printf("Test C99 VLA 5 (bounds checking (might be disabled)): "); - if (bad_ptr = bounds_checking_is_enabled()) { - int *t1 = &tab1[size1 * size2 - 1][3]; - int *t2 = &tab2[9][3]; - printf("%s ", bad_ptr == t1 ? "PASSED" : "FAILED"); - printf("%s ", bad_ptr == t2 ? "PASSED" : "FAILED"); - - char*c1 = 1 + sizeof(tab1) + (char*)tab1; - char*c2 = 1 + sizeof(tab2) + (char*)tab2; - printf("%s ", bad_ptr == c1 ? "PASSED" : "FAILED"); - printf("%s ", bad_ptr == c2 ? "PASSED" : "FAILED"); - - int *i1 = tab1[-1]; - int *i2 = tab2[-1]; - printf("%s ", bad_ptr == i1 ? "PASSED" : "FAILED"); - printf("%s ", bad_ptr == i2 ? "PASSED" : "FAILED"); - - int *x1 = tab1[size1 * size2 + 1]; - int *x2 = tab2[10 + 1]; - printf("%s ", bad_ptr == x1 ? "PASSED" : "FAILED"); - printf("%s ", bad_ptr == x2 ? "PASSED" : "FAILED"); - } else { - printf("PASSED PASSED PASSED PASSED PASSED PASSED PASSED PASSED "); - } - printf("\n"); -#endif -} - -#ifndef __TINYC__ -typedef __SIZE_TYPE__ uintptr_t; -#endif - -void sizeof_test(void) -{ - int a; - int **ptr; - - printf("sizeof(int) = %d\n", sizeof(int)); - printf("sizeof(unsigned int) = %d\n", sizeof(unsigned int)); - printf("sizeof(long) = %d\n", sizeof(long)); - printf("sizeof(unsigned long) = %d\n", sizeof(unsigned long)); - printf("sizeof(short) = %d\n", sizeof(short)); - printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short)); - printf("sizeof(char) = %d\n", sizeof(char)); - printf("sizeof(unsigned char) = %d\n", sizeof(unsigned char)); - printf("sizeof(func) = %d\n", sizeof sizeof_test()); - a = 1; - printf("sizeof(a++) = %d\n", sizeof a++); - printf("a=%d\n", a); - ptr = NULL; - printf("sizeof(**ptr) = %d\n", sizeof (**ptr)); - - /* The type of sizeof should be as large as a pointer, actually - it should be size_t. */ - printf("sizeof(sizeof(int) = %d\n", sizeof(sizeof(int))); - uintptr_t t = 1; - uintptr_t t2; - /* Effectively <<32, but defined also on 32bit machines. */ - t <<= 16; - t <<= 16; - t++; - /* This checks that sizeof really can be used to manipulate - uintptr_t objects, without truncation. */ - t2 = t & -sizeof(uintptr_t); - printf ("%lu %lu\n", t, t2); - - /* some alignof tests */ - printf("__alignof__(int) = %d\n", __alignof__(int)); - printf("__alignof__(unsigned int) = %d\n", __alignof__(unsigned int)); - printf("__alignof__(short) = %d\n", __alignof__(short)); - printf("__alignof__(unsigned short) = %d\n", __alignof__(unsigned short)); - printf("__alignof__(char) = %d\n", __alignof__(char)); - printf("__alignof__(unsigned char) = %d\n", __alignof__(unsigned char)); - printf("__alignof__(func) = %d\n", __alignof__ sizeof_test()); - - /* sizes of VLAs need to be evaluated even inside sizeof: */ - a = 2; - printf("sizeof(char[1+2*a]) = %d\n", sizeof(char[1+2*a])); - /* And checking if sizeof compound literal works. Parenthesized: */ - printf("sizeof( (struct {int i; int j;}){4,5} ) = %d\n", - sizeof( (struct {int i; int j;}){4,5} )); - /* And as direct sizeof argument (as unary expression): */ - printf("sizeof (struct {short i; short j;}){4,5} = %d\n", - sizeof (struct {short i; short j;}){4,5} ); - - /* sizeof(x && y) should be sizeof(int), even if constant - evaluating is possible. */ - printf("sizeof(t && 0) = %d\n", sizeof(t && 0)); - printf("sizeof(1 && 1) = %d\n", sizeof(1 && 1)); - printf("sizeof(t || 1) = %d\n", sizeof(t || 1)); - printf("sizeof(0 || 0) = %d\n", sizeof(0 || 0)); -} - -void typeof_test(void) -{ - double a; - typeof(a) b; - typeof(float) c; - - a = 1.5; - b = 2.5; - c = 3.5; - printf("a=%f b=%f c=%f\n", a, b, c); -} - - -struct hlist_node; -struct hlist_head { - struct hlist_node *first, *last; -}; - -void consume_ulong (unsigned long i) -{ - i = 0; -} - -void statement_expr_test(void) -{ - int a, i; - - /* Basic stmt expr test */ - a = 0; - for(i=0;i<10;i++) { - a += 1 + - ( { int b, j; - b = 0; - for(j=0;j<5;j++) - b += j; b; - } ); - } - printf("a=%d\n", a); - - /* Test that symbols aren't freed prematurely. - With SYM_DEBUG valgrind will show a read from a freed - symbol, and tcc will show an (invalid) warning on the initialization - of 'ptr' below, if symbols are popped after the stmt expr. */ - void *v = (void*)39; - typeof(({ - (struct hlist_node *)v; - })) x; - typeof (x) - ptr = (struct hlist_node *)v; - - /* This part used to segfault when symbols were popped prematurely. - The symbols for the static local would be overwritten with - helper symbols from the pre-processor expansions in between. */ -#define some_attr __attribute__((aligned(1))) -#define tps(str) ({ \ - static const char *t some_attr = str; \ - t; \ - }) - printf ("stmtexpr: %s %s\n", - tps("somerandomlongstring"), - tps("anotherlongstring")); - - /* Test that the three decls of 't' don't interact. */ - int t = 40; - int b = ({ int t = 41; t; }); - int c = ({ int t = 42; t; }); - - /* Test that aggregate return values work. */ - struct hlist_head h - = ({ - typedef struct hlist_head T; - long pre = 48; - T t = { (void*)43, (void*)44 }; - long post = 49; - t; - }); - printf ("stmtexpr: %d %d %d\n", t, b, c); - printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last); - - /* Test that we can give out addresses of local labels. */ - consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; })); -} - -void local_label_test(void) -{ - int a; - goto l1; - l2: - a = 1 + ({ - __label__ l1, l2, l3, l4; - goto l1; - l4: - printf("aa1\n"); - goto l3; - l2: - printf("aa3\n"); - goto l4; - l1: - printf("aa2\n"); - goto l2; - l3:; - 1; - }); - printf("a=%d\n", a); - return; - l4: - printf("bb1\n"); - goto l2; - l1: - printf("bb2\n"); - goto l4; -} - -/* inline assembler test */ -#if defined(__i386__) || defined(__x86_64__) - -/* from linux kernel */ -static char * strncat1(char * dest,const char * src,size_t count) -{ -long d0, d1, d2, d3; -__asm__ __volatile__( - "repne\n\t" - "scasb\n\t" - "dec %1\n\t" - "mov %8,%3\n" - "1:\tdec %3\n\t" - "js 2f\n\t" - "lodsb\n\t" - "stosb\n\t" - "testb %%al,%%al\n\t" - "jne 1b\n" - "2:\txor %2,%2\n\t" - "stosb" - : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) - : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) - : "memory"); -return dest; -} - -static char * strncat2(char * dest,const char * src,size_t count) -{ -long d0, d1, d2, d3; -__asm__ __volatile__( - "repne scasb\n\t" /* one-line repne prefix + string op */ - "dec %1\n\t" - "mov %8,%3\n" - "1:\tdec %3\n\t" - "js 2f\n\t" - "lodsb\n\t" - "stosb\n\t" - "testb %%al,%%al\n\t" - "jne 1b\n" - "2:\txor %2,%2\n\t" - "stosb" - : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) - : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) - : "memory"); -return dest; -} - -static inline void * memcpy1(void * to, const void * from, size_t n) -{ -long d0, d1, d2; -__asm__ __volatile__( - "rep ; movsl\n\t" - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); -return (to); -} - -static inline void * memcpy2(void * to, const void * from, size_t n) -{ -long d0, d1, d2; -__asm__ __volatile__( - "rep movsl\n\t" /* one-line rep prefix + string op */ - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); -return (to); -} - -static __inline__ void sigaddset1(unsigned int *set, int _sig) -{ - __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); -} - -static __inline__ void sigdelset1(unsigned int *set, int _sig) -{ - asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc", "flags"); -} - -static __inline__ __const__ unsigned int swab32(unsigned int x) -{ - __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ - "rorl $16,%0\n\t" /* swap words */ - "xchgb %b0,%h0" /* swap higher bytes */ - :"=" "q" (x) - : "0" (x)); - return x; -} - -static __inline__ unsigned long long mul64(unsigned int a, unsigned int b) -{ - unsigned long long res; -#ifdef __x86_64__ - /* Using the A constraint is wrong (it means rdx:rax, which is too large) - but still test the 32bit->64bit mull. */ - unsigned int resh, resl; - __asm__("mull %2" : "=a" (resl), "=d" (resh) : "a" (a), "r" (b)); - res = ((unsigned long long)resh << 32) | resl; -#else - __asm__("mull %2" : "=A" (res) : "a" (a), "r" (b)); -#endif - return res; -} - -static __inline__ unsigned long long inc64(unsigned long long a) -{ - unsigned long long res; -#ifdef __x86_64__ - /* Using the A constraint is wrong, and increments are tested - elsewhere. */ - res = a + 1; -#else - __asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a)); -#endif - return res; -} - -struct struct123 { - int a; - int b; -}; -struct struct1231 { - unsigned long addr; -}; - -unsigned long mconstraint_test(struct struct1231 *r) -{ - unsigned long ret; - unsigned int a[2]; - a[0] = 0; - __asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1" - : "=&r" (ret), "=m" (a) - : "m" (*(struct struct123 *)r->addr)); - return ret + a[0]; -} - -#ifdef __x86_64__ -int fls64(unsigned long long x) -{ - int bitpos = -1; - asm("bsrq %1,%q0" - : "+r" (bitpos) - : "rm" (x)); - return bitpos + 1; -} -#endif - -void other_constraints_test(void) -{ - unsigned long ret; - int var; -#ifndef _WIN64 - __asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var)); - printf ("oc1: %d\n", ret == (unsigned long)&var); -#endif -} - -#ifndef _WIN32 -/* Test global asm blocks playing with aliases. */ -void base_func(void) -{ - printf ("asmc: base\n"); -} - -extern void override_func1 (void); -extern void override_func2 (void); - -asm(".weak override_func1\n.set override_func1, base_func"); -asm(".set override_func1, base_func"); -asm(".set override_func2, base_func"); - -void override_func2 (void) -{ - printf ("asmc: override2\n"); -} - -/* This checks a construct used by the linux kernel to encode - references to strings by PC relative references. */ -extern int bug_table[] __attribute__((section("__bug_table"))); -char * get_asm_string (void) -{ - extern int some_symbol; - asm volatile (".globl some_symbol\n" - "jmp .+6\n" - "1:\n" - "some_symbol: .long 0\n" - ".pushsection __bug_table, \"a\"\n" - ".globl bug_table\n" - "bug_table:\n" - /* The first entry (1b-2b) is unused in this test, - but we include it to check if cross-section - PC-relative references work. */ - "2:\t.long 1b - 2b, %c0 - 2b\n" - ".popsection\n" : : "i" ("A string")); - char * str = ((char*)bug_table) + bug_table[1]; - return str; -} - -/* This checks another constructs with local labels. */ -extern unsigned char alld_stuff[]; -asm(".data\n" - ".byte 41\n" - "alld_stuff:\n" - "661:\n" - ".byte 42\n" - "662:\n" - ".pushsection .data.ignore\n" - ".long 661b - .\n" /* This reference to 661 generates an external sym - which shouldn't somehow overwrite the offset that's - already determined for it. */ - ".popsection\n" - ".byte 662b - 661b\n" /* So that this value is undeniably 1. */); - -void asm_local_label_diff (void) -{ - printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); -} - -/* This checks that static local variables are available from assembler. */ -void asm_local_statics (void) -{ - static int localint = 41; - asm("incl %0" : "+m" (localint)); - printf ("asm_local_statics: %d\n", localint); -} -#endif - -static -unsigned int set; - -void fancy_copy (unsigned *in, unsigned *out) -{ - asm volatile ("" : "=r" (*out) : "0" (*in)); -} - -void fancy_copy2 (unsigned *in, unsigned *out) -{ - asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory"); -} - -#if defined __x86_64__ && !defined _WIN64 -void clobber_r12(void) -{ - asm volatile("mov $1, %%r12" ::: "r12"); -} -#endif - -void test_high_clobbers(void) -{ -#if defined __x86_64__ && !defined _WIN64 - register long val asm("r12"); - long val2; - /* This tests if asm clobbers correctly save/restore callee saved - registers if they are clobbered and if it's the high 8 x86-64 - registers. This is fragile for GCC as the constraints do not - correctly capture the data flow, but good enough for us. */ - asm volatile("mov $0x4542, %%r12" : "=r" (val):: "memory"); - clobber_r12(); - asm volatile("mov %%r12, %0" : "=r" (val2) : "r" (val): "memory"); - printf("asmhc: 0x%x\n", val2); -#endif -} - -static long cpu_number; -void trace_console(long len, long len2) -{ -#ifdef __x86_64__ - /* This generated invalid code when the emission of the switch - table isn't disabled. The asms are necessary to show the bug, - normal statements don't work (they need to generate some code - even under nocode_wanted, which normal statements don't do, - but asms do). Also at least these number of cases is necessary - to generate enough "random" bytes. They ultimately are enough - to create invalid instruction patterns to which the first - skip-to-decision-table jump jumps. If decision table emission - is disabled all of this is no problem. - - It also is necessary that the switches are in a statement expression - (which has the property of not being enterable from outside. no - matter what). */ - if (0 - && - ({ - long pscr_ret__; - switch(len) { - case 4: - { - long pfo_ret__; - switch (len2) { - case 8: printf("bla"); pfo_ret__ = 42; break; - } - pscr_ret__ = pfo_ret__; - } - break; - case 8: - { - long pfo_ret__; - switch (len2) { - case 1:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; - case 2:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; - case 4:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; - case 8:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break; - default: printf("impossible\n"); - } - pscr_ret__ = pfo_ret__; - }; - break; - } - pscr_ret__; - })) - { - printf("huh?\n"); - } -#endif -} - -void test_asm_dead_code(void) -{ - long rdi; - /* Try to make sure that xdi contains a zero, and hence will - lead to a segfault if the next asm is evaluated without - arguments being set up. */ - asm volatile ("" : "=D" (rdi) : "0" (0)); - (void)sizeof (({ - int var; - /* This shouldn't trigger a segfault, either the argument - registers need to be set up and the asm emitted despite - this being in an unevaluated context, or both the argument - setup _and_ the asm emission need to be suppressed. The latter - is better. Disabling asm code gen when suppression is on - also fixes the above trace_console bug, but that came earlier - than asm suppression. */ - asm volatile ("movl $0,(%0)" : : "D" (&var) : "memory"); - var; - })); -} - -void asm_test(void) -{ - char buf[128]; - unsigned int val, val2; - struct struct123 s1; - struct struct1231 s2 = { (unsigned long)&s1 }; - /* Hide the outer base_func, but check later that the inline - asm block gets the outer one. */ - int base_func = 42; - void override_func3 (void); - unsigned long asmret; -#ifdef BOOL_ISOC99 - _Bool somebool; -#endif - register int regvar asm("%esi"); - - printf("inline asm:\n"); - - // parse 0x1E-1 as 3 tokens in asm mode - asm volatile ("mov $0x1E-1,%eax"); - - /* test the no operand case */ - asm volatile ("xorl %eax, %eax"); - - memcpy1(buf, "hello", 6); - strncat1(buf, " worldXXXXX", 3); - printf("%s\n", buf); - - memcpy2(buf, "hello", 6); - strncat2(buf, " worldXXXXX", 3); - printf("%s\n", buf); - - /* 'A' constraint test */ - printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234)); - printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff)); - - s1.a = 42; - s1.b = 43; - printf("mconstraint: %d", mconstraint_test(&s2)); - printf(" %d %d\n", s1.a, s1.b); - other_constraints_test(); - set = 0xff; - sigdelset1(&set, 2); - sigaddset1(&set, 16); - /* NOTE: we test here if C labels are correctly restored after the - asm statement */ - goto label1; - label2: - __asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc"); - printf("set=0x%x\n", set); - val = 0x01020304; - printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); -#ifndef _WIN32 - override_func1(); - override_func2(); - /* The base_func ref from the following inline asm should find - the global one, not the local decl from this function. */ - asm volatile(".weak override_func3\n.set override_func3, base_func"); - override_func3(); - printf("asmstr: %s\n", get_asm_string()); - asm_local_label_diff(); - asm_local_statics(); -#endif - /* Check that we can also load structs of appropriate layout - into registers. */ - asm volatile("" : "=r" (asmret) : "0"(s2)); - if (asmret != s2.addr) - printf("asmstr: failed\n"); -#ifdef BOOL_ISOC99 - /* Check that the typesize correctly sets the register size to - 8 bit. */ - asm volatile("cmp %1,%2; sete %0" : "=a"(somebool) : "r"(1), "r"(2)); - if (!somebool) - printf("asmbool: failed\n"); -#endif - val = 43; - fancy_copy (&val, &val2); - printf ("fancycpy(%d)=%d\n", val, val2); - val = 44; - fancy_copy2 (&val, &val2); - printf ("fancycpy2(%d)=%d\n", val, val2); - asm volatile ("mov $0x4243, %%esi" : "=r" (regvar)); - printf ("regvar=%x\n", regvar); - test_high_clobbers(); - trace_console(8, 8); - test_asm_dead_code(); - return; - label1: - goto label2; -} - -#else - -void asm_test(void) -{ -} - -#endif - -#define COMPAT_TYPE(type1, type2) \ -{\ - printf("__builtin_types_compatible_p(%s, %s) = %d\n", #type1, #type2, \ - __builtin_types_compatible_p (type1, type2));\ -} - -int constant_p_var; - -void builtin_test(void) -{ - short s; - int i; - long long ll; -#if GCC_MAJOR >= 3 - COMPAT_TYPE(int, int); - COMPAT_TYPE(int, unsigned int); - COMPAT_TYPE(int, char); - COMPAT_TYPE(int, const int); - COMPAT_TYPE(int, volatile int); - COMPAT_TYPE(int *, int *); - COMPAT_TYPE(int *, void *); - COMPAT_TYPE(int *, const int *); - COMPAT_TYPE(char *, unsigned char *); - COMPAT_TYPE(char *, signed char *); - COMPAT_TYPE(char *, char *); -/* space is needed because tcc preprocessor introduces a space between each token */ - COMPAT_TYPE(char * *, void *); -#endif - printf("res = %d\n", __builtin_constant_p(1)); - printf("res = %d\n", __builtin_constant_p(1 + 2)); - printf("res = %d\n", __builtin_constant_p(&constant_p_var)); - printf("res = %d\n", __builtin_constant_p(constant_p_var)); - printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var)); - s = 1; - ll = 2; - i = __builtin_choose_expr (1 != 0, ll, s); - printf("bce: %d\n", i); - i = __builtin_choose_expr (1 != 1, ll, s); - printf("bce: %d\n", i); - i = sizeof (__builtin_choose_expr (1, ll, s)); - printf("bce: %d\n", i); - i = sizeof (__builtin_choose_expr (0, ll, s)); - printf("bce: %d\n", i); - - //printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); -} - -#ifndef _WIN32 -extern int __attribute__((weak)) weak_f1(void); -extern int __attribute__((weak)) weak_f2(void); -extern int weak_f3(void); -extern int __attribute__((weak)) weak_v1; -extern int __attribute__((weak)) weak_v2; -extern int weak_v3; - -extern int (*weak_fpa)() __attribute__((weak)); -extern int __attribute__((weak)) (*weak_fpb)(); -extern __attribute__((weak)) int (*weak_fpc)(); - -extern int weak_asm_f1(void) asm("weak_asm_f1x") __attribute((weak)); -extern int __attribute((weak)) weak_asm_f2(void) asm("weak_asm_f2x") ; -extern int __attribute((weak)) weak_asm_f3(void) asm("weak_asm_f3x") __attribute((weak)); -extern int weak_asm_v1 asm("weak_asm_v1x") __attribute((weak)); -extern int __attribute((weak)) weak_asm_v2 asm("weak_asm_v2x") ; -extern int __attribute((weak)) weak_asm_v3(void) asm("weak_asm_v3x") __attribute((weak)); - -static const size_t dummy = 0; -extern __typeof(dummy) weak_dummy1 __attribute__((weak, alias("dummy"))); -extern __typeof(dummy) __attribute__((weak, alias("dummy"))) weak_dummy2; -extern __attribute__((weak, alias("dummy"))) __typeof(dummy) weak_dummy3; - -int some_lib_func(void); -int dummy_impl_of_slf(void) { return 444; } -int some_lib_func(void) __attribute__((weak, alias("dummy_impl_of_slf"))); - -int weak_toolate() __attribute__((weak)); -int weak_toolate() { return 0; } - -void __attribute__((weak)) weak_test(void) -{ - printf("weak_f1=%d\n", weak_f1 ? weak_f1() : 123); - printf("weak_f2=%d\n", weak_f2 ? weak_f2() : 123); - printf("weak_f3=%d\n", weak_f3 ? weak_f3() : 123); - printf("weak_v1=%d\n",&weak_v1 ? weak_v1 : 123); - printf("weak_v2=%d\n",&weak_v2 ? weak_v2 : 123); - printf("weak_v3=%d\n",&weak_v3 ? weak_v3 : 123); - - printf("weak_fpa=%d\n",&weak_fpa ? weak_fpa() : 123); - printf("weak_fpb=%d\n",&weak_fpb ? weak_fpb() : 123); - printf("weak_fpc=%d\n",&weak_fpc ? weak_fpc() : 123); - - printf("weak_asm_f1=%d\n", weak_asm_f1 != NULL); - printf("weak_asm_f2=%d\n", weak_asm_f2 != NULL); - printf("weak_asm_f3=%d\n", weak_asm_f3 != NULL); - printf("weak_asm_v1=%d\n",&weak_asm_v1 != NULL); - printf("weak_asm_v2=%d\n",&weak_asm_v2 != NULL); - printf("weak_asm_v3=%d\n",&weak_asm_v3 != NULL); - printf("some_lib_func=%d\n", &some_lib_func ? some_lib_func() : 0); -} - -int __attribute__((weak)) weak_f2() { return 222; } -int __attribute__((weak)) weak_f3() { return 333; } -int __attribute__((weak)) weak_v2 = 222; -int __attribute__((weak)) weak_v3 = 333; -#endif - -void const_func(const int a) -{ -} - -void const_warn_test(void) -{ - const_func(1); -} - -struct condstruct { - int i; -}; - -int getme (struct condstruct *s, int i) -{ - int i1 = (i == 0 ? 0 : s)->i; - int i2 = (i == 0 ? s : 0)->i; - int i3 = (i == 0 ? (void*)0 : s)->i; - int i4 = (i == 0 ? s : (void*)0)->i; - return i1 + i2 + i3 + i4; -} - -struct global_data -{ - int a[40]; - int *b[40]; -}; - -struct global_data global_data; - -int global_data_getstuff (int *, int); - -void global_data_callit (int i) -{ - *global_data.b[i] = global_data_getstuff (global_data.b[i], 1); -} - -int global_data_getstuff (int *p, int i) -{ - return *p + i; -} - -void global_data_test (void) -{ - global_data.a[0] = 42; - global_data.b[0] = &global_data.a[0]; - global_data_callit (0); - printf ("%d\n", global_data.a[0]); -} - -struct cmpcmpS -{ - unsigned char fill : 3; - unsigned char b1 : 1; - unsigned char b2 : 1; - unsigned char fill2 : 3; -}; - -int glob1, glob2, glob3; - -void compare_comparisons (struct cmpcmpS *s) -{ - if (s->b1 != (glob1 == glob2) - || (s->b2 != (glob1 == glob3))) - printf ("comparing comparisons broken\n"); -} - -void cmp_comparison_test(void) -{ - struct cmpcmpS s; - s.b1 = 1; - glob1 = 42; glob2 = 42; - s.b2 = 0; - glob3 = 43; - compare_comparisons (&s); -} - -int fcompare (double a, double b, int code) -{ - switch (code) { - case 0: return a == b; - case 1: return a != b; - case 2: return a < b; - case 3: return a >= b; - case 4: return a > b; - case 5: return a <= b; - } -} - -void math_cmp_test(void) -{ - double nan = 0.0/0.0; - double one = 1.0; - double two = 2.0; - int comp = 0; -#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part) - - /* This asserts that "a op b" is _not_ true, but "a iop b" is true. - And it does this in various ways so that all code generation paths - are checked (generating inverted tests, or non-inverted tests, or - producing a 0/1 value without jumps (that's done in the fcompare - function). */ -#define FCMP(a,b,op,iop,code) \ - if (fcompare (a,b,code)) \ - bug (a,b,op,iop,1); \ - if (a op b) \ - bug (a,b,op,iop,2); \ - if (a iop b) \ - ; \ - else \ - bug (a,b,op,iop,3); \ - if ((a op b) || comp) \ - bug (a,b,op,iop,4); \ - if ((a iop b) || comp) \ - ; \ - else \ - bug (a,b,op,iop,5); - - /* Equality tests. */ - FCMP(nan, nan, ==, !=, 0); - FCMP(one, two, ==, !=, 0); - FCMP(one, one, !=, ==, 1); - /* Non-equality is a bit special. */ - if (!fcompare (nan, nan, 1)) - bug (nan, nan, !=, ==, 6); - - /* Relational tests on numbers. */ - FCMP(two, one, <, >=, 2); - FCMP(one, two, >=, <, 3); - FCMP(one, two, >, <=, 4); - FCMP(two, one, <=, >, 5); - - /* Relational tests on NaNs. Note that the inverse op here is - always !=, there's no operator in C that is equivalent to !(a < b), - when NaNs are involved, same for the other relational ops. */ - FCMP(nan, nan, <, !=, 2); - FCMP(nan, nan, >=, !=, 3); - FCMP(nan, nan, >, !=, 4); - FCMP(nan, nan, <=, !=, 5); -} - -double get100 () { return 100.0; } - -void callsave_test(void) -{ -#if defined __i386__ || defined __x86_64__ || defined __arm__ - int i, s; double *d; double t; - s = sizeof (double); - printf ("callsavetest: %d\n", s); - d = alloca (sizeof(double)); - d[0] = 10.0; - /* x86-64 had a bug were the next call to get100 would evict - the lvalue &d[0] as VT_LLOCAL, and the reload would be done - in int type, not pointer type. When alloca returns a pointer - with the high 32 bit set (which is likely on x86-64) the access - generates a segfault. */ - i = d[0] > get100 (); - printf ("%d\n", i); -#endif -} - - -void bfa3(ptrdiff_t str_offset) -{ - printf("bfa3: %s\n", (char *)__builtin_frame_address(3) + str_offset); -} -void bfa2(ptrdiff_t str_offset) -{ - printf("bfa2: %s\n", (char *)__builtin_frame_address(2) + str_offset); - bfa3(str_offset); -} -void bfa1(ptrdiff_t str_offset) -{ - printf("bfa1: %s\n", (char *)__builtin_frame_address(1) + str_offset); - bfa2(str_offset); -} - -void builtin_frame_address_test(void) -{ -/* builtin_frame_address fails on ARM with gcc which make test3 fail */ -#ifndef __arm__ - char str[] = "__builtin_frame_address"; - char *fp0 = __builtin_frame_address(0); - - printf("str: %s\n", str); - bfa1(str-fp0); -#endif -} - -char via_volatile (char i) -{ - char volatile vi; - vi = i; - return vi; -} - -struct __attribute__((__packed__)) Spacked { - char a; - short b; - int c; -}; -struct Spacked spacked; -typedef struct __attribute__((__packed__)) { - char a; - short b; - int c; -} Spacked2; -Spacked2 spacked2; -typedef struct Spacked3_s { - char a; - short b; - int c; -} __attribute__((__packed__)) Spacked3; -Spacked3 spacked3; -struct gate_struct64 { - unsigned short offset_low; - unsigned short segment; - unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; - unsigned short offset_middle; - unsigned offset_high; - unsigned zero1; -} __attribute__((packed)); -typedef struct gate_struct64 gate_desc; -gate_desc a_gate_desc; -void attrib_test(void) -{ -#ifndef _WIN32 - printf("attr: %d %d %d %d\n", sizeof(struct Spacked), - sizeof(spacked), sizeof(Spacked2), sizeof(spacked2)); - printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3)); - printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc)); -#endif -} -extern __attribute__((__unused__)) char * __attribute__((__unused__)) * -strange_attrib_placement (void); - -void * __attribute__((__unused__)) get_void_ptr (void *a) -{ - return a; -} - -/* This part checks for a bug in TOK_GET (used for inline expansion), - where the large long long constant left the the high bits set for - the integer constant token. */ -static inline -int __get_order(unsigned long long size) -{ - int order; - size -= 0xffff880000000000ULL; // this const left high bits set in the token - { - struct S { int i : 1; } s; // constructed for this '1' - } - order = size; - return order; -} - -/* This just forces the above inline function to be actually emitted. */ -int force_get_order(unsigned long s) -{ - return __get_order(s); -} diff --git a/tinyc/tests/tcctest.h b/tinyc/tests/tcctest.h deleted file mode 100644 index b301c7c16..000000000 --- a/tinyc/tests/tcctest.h +++ /dev/null @@ -1,9 +0,0 @@ -static inline const char *get_basefile_from_header(void) -{ - return __BASE_FILE__; -} - -static inline const char *get_file_from_header(void) -{ - return __FILE__; -} diff --git a/tinyc/tests/testfp.c b/tinyc/tests/testfp.c deleted file mode 100644 index 63342b422..000000000 --- a/tinyc/tests/testfp.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Test 128-bit floating-point arithmetic on arm64: - * build with two different compilers and compare the output. - * - * Copyright (c) 2015 Edmund Grimley Evans - * - * Copying and distribution of this file, with or without modification, - * are permitted in any medium without royalty provided the copyright - * notice and this notice are preserved. This file is offered as-is, - * without any warranty. - */ - -#include -#include -#include -#include - -#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__)) - -void check_fail(const char *assertion, const char *file, unsigned int line) -{ - printf("%s:%d: Check (%s) failed.", file, line, assertion); - exit(1); -} - -typedef struct { - unsigned long long x0, x1; -} u128_t; - -float copy_fi(uint32_t x) -{ - float f; - memcpy(&f, &x, 4); - return f; -} - -double copy_di(uint64_t x) -{ - double f; - memcpy(&f, &x, 8); - return f; -} - -long double copy_ldi(u128_t x) -{ - long double f; - memcpy(&f, &x, 16); - return f; -} - -uint32_t copy_if(float f) -{ - uint32_t x; - memcpy(&x, &f, 4); - return x; -} - -uint64_t copy_id(double f) -{ - uint64_t x; - memcpy(&x, &f, 8); - return x; -} - -u128_t copy_ild(long double f) -{ - u128_t x; - memcpy(&x, &f, 16); - return x; -} - -long double make(int sgn, int exp, uint64_t high, uint64_t low) -{ - u128_t x = { low, - (0x0000ffffffffffff & high) | - (0x7fff000000000000 & (uint64_t)exp << 48) | - (0x8000000000000000 & (uint64_t)sgn << 63) }; - return copy_ldi(x); -} - -void cmp(long double a, long double b) -{ - u128_t ax = copy_ild(a); - u128_t bx = copy_ild(b); - int eq = (a == b); - int ne = (a != b); - int lt = (a < b); - int le = (a <= b); - int gt = (a > b); - int ge = (a >= b); - - check(eq == 0 || eq == 1); - check(lt == 0 || lt == 1); - check(gt == 0 || gt == 1); - check(ne == !eq && le == (lt | eq) && ge == (gt | eq)); - check(eq + lt + gt < 2); - - printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n", - ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt); -} - -void cmps(void) -{ - int i, j; - - for (i = 0; i < 2; i++) - for (j = 0; j < 2; j++) - cmp(make(i, 0, 0, 0), make(j, 0, 0, 0)); - - for (i = 0; i < 2; i++) { - for (j = 0; j < 64; j++) { - long double f1 = make(i, 32767, (uint64_t)1 << j, 0); - long double f2 = make(i, 32767, 0, (uint64_t)1 << j); - cmp(f1, 0); - cmp(f2, 0); - cmp(0, f1); - cmp(0, f2); - } - } - - for (i = 0; i < 6; i++) - for (j = 0; j < 6; j++) - cmp(make(i & 1, i >> 1, 0, 0), - make(j & 1, j >> 1, 0, 0)); - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - int a, b; - for (a = 0; a < 2; a++) { - for (b = 0; b < 2; b++) { - cmp(make(i, j, a, b), make(i, j, 0, 0)); - cmp(make(i, j, 0, 0), make(i, j, a, b)); - } - } - } - } -} - -void xop(const char *name, long double a, long double b, long double c) -{ - u128_t ax = copy_ild(a); - u128_t bx = copy_ild(b); - u128_t cx = copy_ild(c); - printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n", - name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0); -} - -void fadd(long double a, long double b) -{ - xop("add", a, b, a + b); -} - -void fsub(long double a, long double b) -{ - xop("sub", a, b, a - b); -} - -void fmul(long double a, long double b) -{ - xop("mul", a, b, a * b); -} - -void fdiv(long double a, long double b) -{ - xop("div", a, b, a / b); -} - -void nanz(void) -{ - // Check NaNs: - { - long double x[7]; - int i, j, n = 0; - x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53); - x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac); - x[n++] = make(0, 32767, 0, 1); - x[n++] = make(0, 32767, (uint64_t)1 << 46, 0); - x[n++] = make(1, 32767, (uint64_t)1 << 47, 0); - x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9); - x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666); - check(n == sizeof(x) / sizeof(*x)); - for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { - fadd(x[i], x[j]); - fsub(x[i], x[j]); - fmul(x[i], x[j]); - fdiv(x[i], x[j]); - } - } - } - - // Check infinities and zeroes: - { - long double x[6]; - int i, j, n = 0; - x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044); - x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19); - x[n++] = make(0, 32767, 0, 0); - x[n++] = make(1, 32767, 0, 0); - x[n++] = make(0, 0, 0, 0); - x[n++] = make(1, 0, 0, 0); - check(n == sizeof(x) / sizeof(*x)); - for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { - fadd(x[i], x[j]); - fsub(x[i], x[j]); - fmul(x[i], x[j]); - fdiv(x[i], x[j]); - } - } - } -} - -void adds(void) -{ - // Check shifting and add/sub: - { - int i; - for (i = -130; i <= 130; i++) { - int s1 = (uint32_t)i % 3 < 1; - int s2 = (uint32_t)i % 5 < 2; - fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031), - make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448)); - } - } - - // Check normalisation: - { - uint64_t a0 = 0xc6bab0a6afbef5ed; - uint64_t a1 = 0x4f84136c4a2e9b52; - int ee[] = { 0, 1, 10000 }; - int e, i; - for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) { - int exp = ee[e]; - fsub(make(0, exp, a1, a0), make(0, 0, 0, 0)); - for (i = 63; i >= 0; i--) - fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0), - make(0, exp, a1 >> i << i, 0)); - for (i = 63; i >=0; i--) - fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1), - make(0, exp, a1, a0 >> i << i)); - } - } - - // Carry/overflow from rounding: - { - fadd(make(0, 114, -1, -1), make(0, 1, 0, 0)); - fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0)); - fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0)); - } -} - -void muls(void) -{ - int i, j; - - { - long double max = make(0, 32766, -1, -1); - long double min = make(0, 0, 0, 1); - fmul(max, max); - fmul(max, min); - fmul(min, min); - } - - for (i = 117; i > 0; i--) - fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a), - make(i & 1, i, 0, 0)); - - fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1)); - // Round to next exponent: - fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1)); - // Round from subnormal to normal: - fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0)); - - for (i = 0; i < 2; i++) - for (j = 0; j < 112; j++) - fmul(make(0, 16383, (uint64_t)1 << i, 0), - make(0, 16383, - j < 64 ? 0 : (uint64_t)1 << (j - 64), - j < 64 ? (uint64_t)1 << j : 0)); -} - -void divs(void) -{ - int i; - - { - long double max = make(0, 32766, -1, -1); - long double min = make(0, 0, 0, 1); - fdiv(max, max); - fdiv(max, min); - fdiv(min, max); - fdiv(min, min); - } - - for (i = 0; i < 64; i++) - fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i)); - for (i = 0; i < 48; i++) - fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0)); -} - -void cvtlsw(int32_t a) -{ - long double f = a; - u128_t x = copy_ild(f); - printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0); -} - -void cvtlsx(int64_t a) -{ - long double f = a; - u128_t x = copy_ild(f); - printf("cvtlsx %016llx %016llx%016llx\n", - (long long)(uint64_t)a, x.x1, x.x0); -} - -void cvtluw(uint32_t a) -{ - long double f = a; - u128_t x = copy_ild(f); - printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0); -} - -void cvtlux(uint64_t a) -{ - long double f = a; - u128_t x = copy_ild(f); - printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0); -} - -void cvtil(long double a) -{ - u128_t x = copy_ild(a); - int32_t b1 = a; - int64_t b2 = a; - uint32_t b3 = a; - uint64_t b4 = a; - printf("cvtswl %016llx%016llx %08lx\n", - x.x1, x.x0, (long)(uint32_t)b1); - printf("cvtsxl %016llx%016llx %016llx\n", - x.x1, x.x0, (long long)(uint64_t)b2); - printf("cvtuwl %016llx%016llx %08lx\n", - x.x1, x.x0, (long)b3); - printf("cvtuxl %016llx%016llx %016llx\n", - x.x1, x.x0, (long long)b4); -} - -void cvtlf(float a) -{ - uint32_t ax = copy_if(a); - long double b = a; - u128_t bx = copy_ild(b); - printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0); -} - -void cvtld(double a) -{ - uint64_t ax = copy_id(a); - long double b = a; - u128_t bx = copy_ild(b); - printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0); -} - -void cvtfl(long double a) -{ - u128_t ax = copy_ild(a); - float b = a; - uint32_t bx = copy_if(b); - printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx); -} - -void cvtdl(long double a) -{ - u128_t ax = copy_ild(a); - double b = a; - uint64_t bx = copy_id(b); - printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx); -} - -void cvts(void) -{ - int i, j; - - { - uint32_t x = 0xad040c5b; - cvtlsw(0); - for (i = 0; i < 31; i++) - cvtlsw(x >> (31 - i)); - for (i = 0; i < 31; i++) - cvtlsw(-(x >> (31 - i))); - cvtlsw(0x80000000); - } - { - uint64_t x = 0xb630a248cad9afd2; - cvtlsx(0); - for (i = 0; i < 63; i++) - cvtlsx(x >> (63 - i)); - for (i = 0; i < 63; i++) - cvtlsx(-(x >> (63 - i))); - cvtlsx(0x8000000000000000); - } - { - uint32_t x = 0xad040c5b; - cvtluw(0); - for (i = 0; i < 32; i++) - cvtluw(x >> (31 - i)); - } - { - uint64_t x = 0xb630a248cad9afd2; - cvtlux(0); - for (i = 0; i < 64; i++) - cvtlux(x >> (63 - i)); - } - - for (i = 0; i < 2; i++) { - cvtil(make(i, 32767, 0, 1)); - cvtil(make(i, 32767, (uint64_t)1 << 47, 0)); - cvtil(make(i, 32767, 123, 456)); - cvtil(make(i, 32767, 0, 0)); - cvtil(make(i, 16382, -1, -1)); - cvtil(make(i, 16383, -1, -1)); - cvtil(make(i, 16384, 0x7fffffffffff, -1)); - cvtil(make(i, 16384, 0x800000000000, 0)); - for (j = 0; j < 68; j++) - cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d)); - } - - cvtlf(copy_fi(0x00000000)); - cvtlf(copy_fi(0x456789ab)); - cvtlf(copy_fi(0x7f800000)); - cvtlf(copy_fi(0x7f923456)); - cvtlf(copy_fi(0x7fdbcdef)); - cvtlf(copy_fi(0x80000000)); - cvtlf(copy_fi(0xabcdef12)); - cvtlf(copy_fi(0xff800000)); - cvtlf(copy_fi(0xff923456)); - cvtlf(copy_fi(0xffdbcdef)); - - cvtld(copy_di(0x0000000000000000)); - cvtld(copy_di(0x456789abcdef0123)); - cvtld(copy_di(0x7ff0000000000000)); - cvtld(copy_di(0x7ff123456789abcd)); - cvtld(copy_di(0x7ffabcdef1234567)); - cvtld(copy_di(0x8000000000000000)); - cvtld(copy_di(0xcdef123456789abc)); - cvtld(copy_di(0xfff0000000000000)); - cvtld(copy_di(0xfff123456789abcd)); - cvtld(copy_di(0xfffabcdef1234567)); - - for (i = 0; i < 2; i++) { \ - cvtfl(make(i, 0, 0, 0)); - cvtfl(make(i, 16232, -1, -1)); - cvtfl(make(i, 16233, 0, 0)); - cvtfl(make(i, 16233, 0, 1)); - cvtfl(make(i, 16383, 0xab0ffd000000, 0)); - cvtfl(make(i, 16383, 0xab0ffd000001, 0)); - cvtfl(make(i, 16383, 0xab0ffeffffff, 0)); - cvtfl(make(i, 16383, 0xab0fff000000, 0)); - cvtfl(make(i, 16383, 0xab0fff000001, 0)); - cvtfl(make(i, 16510, 0xfffffeffffff, -1)); - cvtfl(make(i, 16510, 0xffffff000000, 0)); - cvtfl(make(i, 16511, 0, 0)); - cvtfl(make(i, 32767, 0, 0)); - cvtfl(make(i, 32767, 0, 1)); - cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); - cvtfl(make(i, 32767, 0x800000000000, 1)); - cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); - } - - for (i = 0; i < 2; i++) { - cvtdl(make(i, 0, 0, 0)); - cvtdl(make(i, 15307, -1, -1)); - cvtdl(make(i, 15308, 0, 0)); - cvtdl(make(i, 15308, 0, 1)); - cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000)); - cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001)); - cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff)); - cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000)); - cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001)); - cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff)); - cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000)); - cvtdl(make(i, 17407, 0, 0)); - cvtdl(make(i, 32767, 0, 0)); - cvtdl(make(i, 32767, 0, 1)); - cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); - cvtdl(make(i, 32767, 0x800000000000, 1)); - cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); - } -} - -void tests(void) -{ - cmps(); - nanz(); - adds(); - muls(); - divs(); - cvts(); -} - -int main() -{ -#ifdef __aarch64__ - tests(); -#else - printf("This test program is intended for a little-endian architecture\n" - "with an IEEE-standard 128-bit long double.\n"); -#endif - return 0; -} diff --git a/tinyc/tests/tests2/00_assignment.c b/tinyc/tests/tests2/00_assignment.c deleted file mode 100644 index c96109fdc..000000000 --- a/tinyc/tests/tests2/00_assignment.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -int main() -{ - int a; - a = 42; - printf("%d\n", a); - - int b = 64; - printf("%d\n", b); - - int c = 12, d = 34; - printf("%d, %d\n", c, d); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/00_assignment.expect b/tinyc/tests/tests2/00_assignment.expect deleted file mode 100644 index d4407f3fe..000000000 --- a/tinyc/tests/tests2/00_assignment.expect +++ /dev/null @@ -1,3 +0,0 @@ -42 -64 -12, 34 diff --git a/tinyc/tests/tests2/01_comment.c b/tinyc/tests/tests2/01_comment.c deleted file mode 100644 index a2e6bc63d..000000000 --- a/tinyc/tests/tests2/01_comment.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -int main() -{ - printf("Hello\n"); - printf("Hello\n"); /* this is a comment */ printf("Hello\n"); - printf("Hello\n"); - // this is also a comment sayhello(); - printf("Hello\n"); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/01_comment.expect b/tinyc/tests/tests2/01_comment.expect deleted file mode 100644 index b1387ad09..000000000 --- a/tinyc/tests/tests2/01_comment.expect +++ /dev/null @@ -1,5 +0,0 @@ -Hello -Hello -Hello -Hello -Hello diff --git a/tinyc/tests/tests2/02_printf.c b/tinyc/tests/tests2/02_printf.c deleted file mode 100644 index 4c34dd874..000000000 --- a/tinyc/tests/tests2/02_printf.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -int main() -{ - printf("Hello world\n"); - - int Count; - for (Count = -5; Count <= 5; Count++) - printf("Count = %d\n", Count); - - printf("String 'hello', 'there' is '%s', '%s'\n", "hello", "there"); - printf("Character 'A' is '%c'\n", 65); - printf("Character 'a' is '%c'\n", 'a'); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/02_printf.expect b/tinyc/tests/tests2/02_printf.expect deleted file mode 100644 index f67a0f6e3..000000000 --- a/tinyc/tests/tests2/02_printf.expect +++ /dev/null @@ -1,15 +0,0 @@ -Hello world -Count = -5 -Count = -4 -Count = -3 -Count = -2 -Count = -1 -Count = 0 -Count = 1 -Count = 2 -Count = 3 -Count = 4 -Count = 5 -String 'hello', 'there' is 'hello', 'there' -Character 'A' is 'A' -Character 'a' is 'a' diff --git a/tinyc/tests/tests2/03_struct.c b/tinyc/tests/tests2/03_struct.c deleted file mode 100644 index c5d48c5ab..000000000 --- a/tinyc/tests/tests2/03_struct.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - -struct fred -{ - int boris; - int natasha; -}; - -int main() -{ - struct fred bloggs; - - bloggs.boris = 12; - bloggs.natasha = 34; - - printf("%d\n", bloggs.boris); - printf("%d\n", bloggs.natasha); - - struct fred jones[2]; - jones[0].boris = 12; - jones[0].natasha = 34; - jones[1].boris = 56; - jones[1].natasha = 78; - - printf("%d\n", jones[0].boris); - printf("%d\n", jones[0].natasha); - printf("%d\n", jones[1].boris); - printf("%d\n", jones[1].natasha); - - return 0; -} diff --git a/tinyc/tests/tests2/03_struct.expect b/tinyc/tests/tests2/03_struct.expect deleted file mode 100644 index ecbf58937..000000000 --- a/tinyc/tests/tests2/03_struct.expect +++ /dev/null @@ -1,6 +0,0 @@ -12 -34 -12 -34 -56 -78 diff --git a/tinyc/tests/tests2/04_for.c b/tinyc/tests/tests2/04_for.c deleted file mode 100644 index 312fed855..000000000 --- a/tinyc/tests/tests2/04_for.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -int main() -{ - int Count; - - for (Count = 1; Count <= 10; Count++) - { - printf("%d\n", Count); - } - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/04_for.expect b/tinyc/tests/tests2/04_for.expect deleted file mode 100644 index f00c965d8..000000000 --- a/tinyc/tests/tests2/04_for.expect +++ /dev/null @@ -1,10 +0,0 @@ -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 diff --git a/tinyc/tests/tests2/05_array.c b/tinyc/tests/tests2/05_array.c deleted file mode 100644 index c218f3163..000000000 --- a/tinyc/tests/tests2/05_array.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main() -{ - int Count; - int Array[10]; - - for (Count = 1; Count <= 10; Count++) - { - Array[Count-1] = Count * Count; - } - - for (Count = 0; Count < 10; Count++) - { - printf("%d\n", Array[Count]); - } - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/05_array.expect b/tinyc/tests/tests2/05_array.expect deleted file mode 100644 index bc7257c0f..000000000 --- a/tinyc/tests/tests2/05_array.expect +++ /dev/null @@ -1,10 +0,0 @@ -1 -4 -9 -16 -25 -36 -49 -64 -81 -100 diff --git a/tinyc/tests/tests2/06_case.c b/tinyc/tests/tests2/06_case.c deleted file mode 100644 index c0191e2b0..000000000 --- a/tinyc/tests/tests2/06_case.c +++ /dev/null @@ -1,29 +0,0 @@ -#include - -int main() -{ - int Count; - - for (Count = 0; Count < 4; Count++) - { - printf("%d\n", Count); - switch (Count) - { - case 1: - printf("%d\n", 1); - break; - - case 2: - printf("%d\n", 2); - break; - - default: - printf("%d\n", 0); - break; - } - } - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/06_case.expect b/tinyc/tests/tests2/06_case.expect deleted file mode 100644 index fab2c201a..000000000 --- a/tinyc/tests/tests2/06_case.expect +++ /dev/null @@ -1,8 +0,0 @@ -0 -0 -1 -1 -2 -2 -3 -0 diff --git a/tinyc/tests/tests2/07_function.c b/tinyc/tests/tests2/07_function.c deleted file mode 100644 index 0477ce14e..000000000 --- a/tinyc/tests/tests2/07_function.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -int myfunc(int x) -{ - return x * x; -} - -void vfunc(int a) -{ - printf("a=%d\n", a); -} - -void qfunc() -{ - printf("qfunc()\n"); -} - -int main() -{ - printf("%d\n", myfunc(3)); - printf("%d\n", myfunc(4)); - - vfunc(1234); - - qfunc(); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/07_function.expect b/tinyc/tests/tests2/07_function.expect deleted file mode 100644 index 8ffb0a702..000000000 --- a/tinyc/tests/tests2/07_function.expect +++ /dev/null @@ -1,4 +0,0 @@ -9 -16 -a=1234 -qfunc() diff --git a/tinyc/tests/tests2/08_while.c b/tinyc/tests/tests2/08_while.c deleted file mode 100644 index 602ffc737..000000000 --- a/tinyc/tests/tests2/08_while.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -int main() -{ - int a; - int p; - int t; - - a = 1; - p = 0; - t = 0; - - while (a < 100) - { - printf("%d\n", a); - t = a; - a = t + p; - p = t; - } - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/08_while.expect b/tinyc/tests/tests2/08_while.expect deleted file mode 100644 index 702d4c0fc..000000000 --- a/tinyc/tests/tests2/08_while.expect +++ /dev/null @@ -1,11 +0,0 @@ -1 -1 -2 -3 -5 -8 -13 -21 -34 -55 -89 diff --git a/tinyc/tests/tests2/09_do_while.c b/tinyc/tests/tests2/09_do_while.c deleted file mode 100644 index 1d3315d3a..000000000 --- a/tinyc/tests/tests2/09_do_while.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -int main() -{ - int a; - int p; - int t; - - a = 1; - p = 0; - t = 0; - - do - { - printf("%d\n", a); - t = a; - a = t + p; - p = t; - } while (a < 100); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/09_do_while.expect b/tinyc/tests/tests2/09_do_while.expect deleted file mode 100644 index 702d4c0fc..000000000 --- a/tinyc/tests/tests2/09_do_while.expect +++ /dev/null @@ -1,11 +0,0 @@ -1 -1 -2 -3 -5 -8 -13 -21 -34 -55 -89 diff --git a/tinyc/tests/tests2/10_pointer.c b/tinyc/tests/tests2/10_pointer.c deleted file mode 100644 index 0177f4d81..000000000 --- a/tinyc/tests/tests2/10_pointer.c +++ /dev/null @@ -1,40 +0,0 @@ -#include - -struct ziggy -{ - int a; - int b; - int c; -} bolshevic; - -int main() -{ - int a; - int *b; - int c; - - a = 42; - b = &a; - printf("a = %d\n", *b); - - bolshevic.a = 12; - bolshevic.b = 34; - bolshevic.c = 56; - - printf("bolshevic.a = %d\n", bolshevic.a); - printf("bolshevic.b = %d\n", bolshevic.b); - printf("bolshevic.c = %d\n", bolshevic.c); - - struct ziggy *tsar = &bolshevic; - - printf("tsar->a = %d\n", tsar->a); - printf("tsar->b = %d\n", tsar->b); - printf("tsar->c = %d\n", tsar->c); - - b = &(bolshevic.b); - printf("bolshevic.b = %d\n", *b); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/10_pointer.expect b/tinyc/tests/tests2/10_pointer.expect deleted file mode 100644 index 1e3c473f0..000000000 --- a/tinyc/tests/tests2/10_pointer.expect +++ /dev/null @@ -1,8 +0,0 @@ -a = 42 -bolshevic.a = 12 -bolshevic.b = 34 -bolshevic.c = 56 -tsar->a = 12 -tsar->b = 34 -tsar->c = 56 -bolshevic.b = 34 diff --git a/tinyc/tests/tests2/11_precedence.c b/tinyc/tests/tests2/11_precedence.c deleted file mode 100644 index db2049dfe..000000000 --- a/tinyc/tests/tests2/11_precedence.c +++ /dev/null @@ -1,40 +0,0 @@ -#include - -int main() -{ - int a; - int b; - int c; - int d; - int e; - int f; - int x; - int y; - - a = 12; - b = 34; - c = 56; - d = 78; - e = 0; - f = 1; - - printf("%d\n", c + d); - printf("%d\n", (y = c + d)); - printf("%d\n", e || e && f); - printf("%d\n", e || f && f); - printf("%d\n", e && e || f); - printf("%d\n", e && f || f); - printf("%d\n", a && f | f); - printf("%d\n", a | b ^ c & d); - printf("%d, %d\n", a == a, a == b); - printf("%d, %d\n", a != a, a != b); - printf("%d\n", a != b && c != d); - printf("%d\n", a + b * c / f); - printf("%d\n", a + b * c / f); - printf("%d\n", (4 << 4)); - printf("%d\n", (64 >> 4)); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/11_precedence.expect b/tinyc/tests/tests2/11_precedence.expect deleted file mode 100644 index b6923966e..000000000 --- a/tinyc/tests/tests2/11_precedence.expect +++ /dev/null @@ -1,15 +0,0 @@ -134 -134 -0 -1 -1 -1 -1 -46 -1, 0 -0, 1 -1 -1916 -1916 -64 -4 diff --git a/tinyc/tests/tests2/12_hashdefine.c b/tinyc/tests/tests2/12_hashdefine.c deleted file mode 100644 index 5c521e02b..000000000 --- a/tinyc/tests/tests2/12_hashdefine.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#define FRED 12 -#define BLOGGS(x) (12*(x)) - -int main() -{ - printf("%d\n", FRED); - printf("%d, %d, %d\n", BLOGGS(1), BLOGGS(2), BLOGGS(3)); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/12_hashdefine.expect b/tinyc/tests/tests2/12_hashdefine.expect deleted file mode 100644 index 99f2ed5d9..000000000 --- a/tinyc/tests/tests2/12_hashdefine.expect +++ /dev/null @@ -1,2 +0,0 @@ -12 -12, 24, 36 diff --git a/tinyc/tests/tests2/13_integer_literals.c b/tinyc/tests/tests2/13_integer_literals.c deleted file mode 100644 index 7cee98b1f..000000000 --- a/tinyc/tests/tests2/13_integer_literals.c +++ /dev/null @@ -1,20 +0,0 @@ -#include - -int main() -{ - int a = 24680; - int b = 01234567; - int c = 0x2468ac; - int d = 0x2468AC; - int e = 0b010101010101; - - printf("%d\n", a); - printf("%d\n", b); - printf("%d\n", c); - printf("%d\n", d); - printf("%d\n", e); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/13_integer_literals.expect b/tinyc/tests/tests2/13_integer_literals.expect deleted file mode 100644 index f5aca06f7..000000000 --- a/tinyc/tests/tests2/13_integer_literals.expect +++ /dev/null @@ -1,5 +0,0 @@ -24680 -342391 -2386092 -2386092 -1365 diff --git a/tinyc/tests/tests2/14_if.c b/tinyc/tests/tests2/14_if.c deleted file mode 100644 index 2bd255051..000000000 --- a/tinyc/tests/tests2/14_if.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main() -{ - int a = 1; - - if (a) - printf("a is true\n"); - else - printf("a is false\n"); - - int b = 0; - if (b) - printf("b is true\n"); - else - printf("b is false\n"); - - return 0; -} - -// vim: set expandtab ts=4 sw=3 sts=3 tw=80 : diff --git a/tinyc/tests/tests2/14_if.expect b/tinyc/tests/tests2/14_if.expect deleted file mode 100644 index c32c4159c..000000000 --- a/tinyc/tests/tests2/14_if.expect +++ /dev/null @@ -1,2 +0,0 @@ -a is true -b is false diff --git a/tinyc/tests/tests2/15_recursion.c b/tinyc/tests/tests2/15_recursion.c deleted file mode 100644 index f79a00df5..000000000 --- a/tinyc/tests/tests2/15_recursion.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int factorial(int i) -{ - if (i < 2) - return i; - else - return i * factorial(i - 1); -} - -int main() -{ - int Count; - - for (Count = 1; Count <= 10; Count++) - printf("%d\n", factorial(Count)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/15_recursion.expect b/tinyc/tests/tests2/15_recursion.expect deleted file mode 100644 index db47b283d..000000000 --- a/tinyc/tests/tests2/15_recursion.expect +++ /dev/null @@ -1,10 +0,0 @@ -1 -2 -6 -24 -120 -720 -5040 -40320 -362880 -3628800 diff --git a/tinyc/tests/tests2/16_nesting.c b/tinyc/tests/tests2/16_nesting.c deleted file mode 100644 index 2b72cc028..000000000 --- a/tinyc/tests/tests2/16_nesting.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main() -{ - int x, y, z; - - for (x = 0; x < 2; x++) - { - for (y = 0; y < 3; y++) - { - for (z = 0; z < 3; z++) - { - printf("%d %d %d\n", x, y, z); - } - } - } - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/16_nesting.expect b/tinyc/tests/tests2/16_nesting.expect deleted file mode 100644 index 5a3431ee0..000000000 --- a/tinyc/tests/tests2/16_nesting.expect +++ /dev/null @@ -1,18 +0,0 @@ -0 0 0 -0 0 1 -0 0 2 -0 1 0 -0 1 1 -0 1 2 -0 2 0 -0 2 1 -0 2 2 -1 0 0 -1 0 1 -1 0 2 -1 1 0 -1 1 1 -1 1 2 -1 2 0 -1 2 1 -1 2 2 diff --git a/tinyc/tests/tests2/17_enum.c b/tinyc/tests/tests2/17_enum.c deleted file mode 100644 index e2bc73629..000000000 --- a/tinyc/tests/tests2/17_enum.c +++ /dev/null @@ -1,72 +0,0 @@ -#include - -enum fred -{ - a, - b, - c, - d, - e = 54, - f = 73, - g, - h -}; - -/* All following uses of enum efoo should compile - without warning. While forward enums aren't ISO C, - it's accepted by GCC also in strict mode, and only warned - about with -pedantic. This happens in the real world. */ -/* Strict ISO C doesn't allow this kind of forward declaration of - enums, but GCC accepts it (and gives only pedantic warning), and - it occurs in the wild. */ -enum efoo; -struct Sforward_use { - int (*fmember) (enum efoo x); -}; - -extern enum efoo it_real_fn(void); -enum efoo { - ONE, - TWO, -}; -struct S2 { - enum efoo (*f2) (void); -}; -void should_compile(struct S2 *s) -{ - s->f2 = it_real_fn; -} - -enum efoo it_real_fn(void) -{ - return TWO; -} - -static unsigned int deref_uintptr(unsigned int *p) -{ - return *p; -} - -enum Epositive { - epos_one, epos_two -}; - -int main() -{ - enum fred frod; - enum Epositive epos = epos_two; - - printf("%d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h); - /* printf("%d\n", frod); */ - frod = 12; - printf("%d\n", frod); - frod = e; - printf("%d\n", frod); - - /* Following should compile without warning. */ - printf ("enum to int: %u\n", deref_uintptr(&epos)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/17_enum.expect b/tinyc/tests/tests2/17_enum.expect deleted file mode 100644 index d453a617b..000000000 --- a/tinyc/tests/tests2/17_enum.expect +++ /dev/null @@ -1,4 +0,0 @@ -0 1 2 3 54 73 74 75 -12 -54 -enum to int: 1 diff --git a/tinyc/tests/tests2/18_include.c b/tinyc/tests/tests2/18_include.c deleted file mode 100644 index dbae3aa2e..000000000 --- a/tinyc/tests/tests2/18_include.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -int main() -{ - printf("including\n"); -#include "18_include.h" - printf("done\n"); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/18_include.expect b/tinyc/tests/tests2/18_include.expect deleted file mode 100644 index 58c6d29a0..000000000 --- a/tinyc/tests/tests2/18_include.expect +++ /dev/null @@ -1,3 +0,0 @@ -including -included -done diff --git a/tinyc/tests/tests2/18_include.h b/tinyc/tests/tests2/18_include.h deleted file mode 100644 index dc8608025..000000000 --- a/tinyc/tests/tests2/18_include.h +++ /dev/null @@ -1 +0,0 @@ -printf("included\n"); diff --git a/tinyc/tests/tests2/19_pointer_arithmetic.c b/tinyc/tests/tests2/19_pointer_arithmetic.c deleted file mode 100644 index aff65e5b5..000000000 --- a/tinyc/tests/tests2/19_pointer_arithmetic.c +++ /dev/null @@ -1,28 +0,0 @@ -#include - -int main() -{ - int a; - int *b; - int *c; - - a = 42; - b = &a; - c = NULL; - - printf("%d\n", *b); - - if (b == NULL) - printf("b is NULL\n"); - else - printf("b is not NULL\n"); - - if (c == NULL) - printf("c is NULL\n"); - else - printf("c is not NULL\n"); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/19_pointer_arithmetic.expect b/tinyc/tests/tests2/19_pointer_arithmetic.expect deleted file mode 100644 index 0cf781b9e..000000000 --- a/tinyc/tests/tests2/19_pointer_arithmetic.expect +++ /dev/null @@ -1,3 +0,0 @@ -42 -b is not NULL -c is NULL diff --git a/tinyc/tests/tests2/20_pointer_comparison.c b/tinyc/tests/tests2/20_pointer_comparison.c deleted file mode 100644 index 825f7787d..000000000 --- a/tinyc/tests/tests2/20_pointer_comparison.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -int main() -{ - int a; - int b; - int *d; - int *e; - d = &a; - e = &b; - a = 12; - b = 34; - printf("%d\n", *d); - printf("%d\n", *e); - printf("%d\n", d == e); - printf("%d\n", d != e); - d = e; - printf("%d\n", d == e); - printf("%d\n", d != e); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/20_pointer_comparison.expect b/tinyc/tests/tests2/20_pointer_comparison.expect deleted file mode 100644 index 5d1e5f5c7..000000000 --- a/tinyc/tests/tests2/20_pointer_comparison.expect +++ /dev/null @@ -1,6 +0,0 @@ -12 -34 -0 -1 -1 -0 diff --git a/tinyc/tests/tests2/21_char_array.c b/tinyc/tests/tests2/21_char_array.c deleted file mode 100644 index f22f5275c..000000000 --- a/tinyc/tests/tests2/21_char_array.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - -int main() -{ - int x = 'a'; - char y = x; - - char *a = "hello"; - - printf("%s\n", a); - - int c; - c = *a; - - char *b; - for (b = a; *b != 0; b++) - printf("%c: %d\n", *b, *b); - - char destarray[10]; - char *dest = &destarray[0]; - char *src = a; - - while (*src != 0) - *dest++ = *src++; - - *dest = 0; - - printf("copied string is %s\n", destarray); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/21_char_array.expect b/tinyc/tests/tests2/21_char_array.expect deleted file mode 100644 index dbc60683c..000000000 --- a/tinyc/tests/tests2/21_char_array.expect +++ /dev/null @@ -1,7 +0,0 @@ -hello -h: 104 -e: 101 -l: 108 -l: 108 -o: 111 -copied string is hello diff --git a/tinyc/tests/tests2/22_floating_point.c b/tinyc/tests/tests2/22_floating_point.c deleted file mode 100644 index e3491f5c6..000000000 --- a/tinyc/tests/tests2/22_floating_point.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -int main() -{ - // variables - float a = 12.34 + 56.78; - printf("%f\n", a); - - // infix operators - printf("%f\n", 12.34 + 56.78); - printf("%f\n", 12.34 - 56.78); - printf("%f\n", 12.34 * 56.78); - printf("%f\n", 12.34 / 56.78); - - // comparison operators - printf("%d %d %d %d %d %d\n", 12.34 < 56.78, 12.34 <= 56.78, 12.34 == 56.78, 12.34 >= 56.78, 12.34 > 56.78, 12.34 != 56.78); - printf("%d %d %d %d %d %d\n", 12.34 < 12.34, 12.34 <= 12.34, 12.34 == 12.34, 12.34 >= 12.34, 12.34 > 12.34, 12.34 != 12.34); - printf("%d %d %d %d %d %d\n", 56.78 < 12.34, 56.78 <= 12.34, 56.78 == 12.34, 56.78 >= 12.34, 56.78 > 12.34, 56.78 != 12.34); - - // assignment operators - a = 12.34; - a += 56.78; - printf("%f\n", a); - - a = 12.34; - a -= 56.78; - printf("%f\n", a); - - a = 12.34; - a *= 56.78; - printf("%f\n", a); - - a = 12.34; - a /= 56.78; - printf("%f\n", a); - - // prefix operators - printf("%f\n", +12.34); - printf("%f\n", -12.34); - - // type coercion - a = 2; - printf("%f\n", a); - printf("%f\n", sin(2)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/22_floating_point.expect b/tinyc/tests/tests2/22_floating_point.expect deleted file mode 100644 index 75ea3a7e2..000000000 --- a/tinyc/tests/tests2/22_floating_point.expect +++ /dev/null @@ -1,16 +0,0 @@ -69.120003 -69.120000 --44.440000 -700.665200 -0.217330 -1 1 0 0 0 1 -0 1 1 1 0 0 -0 0 0 1 1 1 -69.120003 --44.439999 -700.665222 -0.217330 -12.340000 --12.340000 -2.000000 -0.909297 diff --git a/tinyc/tests/tests2/23_type_coercion.c b/tinyc/tests/tests2/23_type_coercion.c deleted file mode 100644 index 1fcc33519..000000000 --- a/tinyc/tests/tests2/23_type_coercion.c +++ /dev/null @@ -1,54 +0,0 @@ -#include - -void charfunc(char a) -{ - printf("char: %c\n", a); -} - -void intfunc(int a) -{ - printf("int: %d\n", a); -} - -void floatfunc(float a) -{ - printf("float: %f\n", a); -} - -int main() -{ - charfunc('a'); - charfunc(98); - charfunc(99.0); - - intfunc('a'); - intfunc(98); - intfunc(99.0); - - floatfunc('a'); - floatfunc(98); - floatfunc(99.0); - - /* printf("%c %d %f\n", 'a', 'b', 'c'); */ - /* printf("%c %d %f\n", 97, 98, 99); */ - /* printf("%c %d %f\n", 97.0, 98.0, 99.0); */ - - char b = 97; - char c = 97.0; - - printf("%d %d\n", b, c); - - int d = 'a'; - int e = 97.0; - - printf("%d %d\n", d, e); - - float f = 'a'; - float g = 97; - - printf("%f %f\n", f, g); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/23_type_coercion.expect b/tinyc/tests/tests2/23_type_coercion.expect deleted file mode 100644 index d9076f018..000000000 --- a/tinyc/tests/tests2/23_type_coercion.expect +++ /dev/null @@ -1,12 +0,0 @@ -char: a -char: b -char: c -int: 97 -int: 98 -int: 99 -float: 97.000000 -float: 98.000000 -float: 99.000000 -97 97 -97 97 -97.000000 97.000000 diff --git a/tinyc/tests/tests2/24_math_library.c b/tinyc/tests/tests2/24_math_library.c deleted file mode 100644 index 514a25f63..000000000 --- a/tinyc/tests/tests2/24_math_library.c +++ /dev/null @@ -1,30 +0,0 @@ -#define _ISOC99_SOURCE 1 - -#include -#include - -int main() -{ - printf("%f\n", sin(0.12)); - printf("%f\n", cos(0.12)); - printf("%f\n", tan(0.12)); - printf("%f\n", asin(0.12)); - printf("%f\n", acos(0.12)); - printf("%f\n", atan(0.12)); - printf("%f\n", sinh(0.12)); - printf("%f\n", cosh(0.12)); - printf("%f\n", tanh(0.12)); - printf("%f\n", exp(0.12)); - printf("%f\n", fabs(-0.12)); - printf("%f\n", log(0.12)); - printf("%f\n", log10(0.12)); - printf("%f\n", pow(0.12, 0.12)); - printf("%f\n", sqrt(0.12)); - printf("%f\n", round(12.34)); - printf("%f\n", ceil(12.34)); - printf("%f\n", floor(12.34)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/24_math_library.expect b/tinyc/tests/tests2/24_math_library.expect deleted file mode 100644 index 99f7299cc..000000000 --- a/tinyc/tests/tests2/24_math_library.expect +++ /dev/null @@ -1,18 +0,0 @@ -0.119712 -0.992809 -0.120579 -0.120290 -1.450506 -0.119429 -0.120288 -1.007209 -0.119427 -1.127497 -0.120000 --2.120264 --0.920819 -0.775357 -0.346410 -12.000000 -13.000000 -12.000000 diff --git a/tinyc/tests/tests2/25_quicksort.c b/tinyc/tests/tests2/25_quicksort.c deleted file mode 100644 index 5cc08bd9d..000000000 --- a/tinyc/tests/tests2/25_quicksort.c +++ /dev/null @@ -1,83 +0,0 @@ -#include - -int array[16]; - -//Swap integer values by array indexes -void swap(int a, int b) -{ - int tmp = array[a]; - array[a] = array[b]; - array[b] = tmp; -} - -//Partition the array into two halves and return the -//index about which the array is partitioned -int partition(int left, int right) -{ - int pivotIndex = left; - int pivotValue = array[pivotIndex]; - int index = left; - int i; - - swap(pivotIndex, right); - for(i = left; i < right; i++) - { - if(array[i] < pivotValue) - { - swap(i, index); - index += 1; - } - } - swap(right, index); - - return index; -} - -//Quicksort the array -void quicksort(int left, int right) -{ - if(left >= right) - return; - - int index = partition(left, right); - quicksort(left, index - 1); - quicksort(index + 1, right); -} - -int main() -{ - int i; - - array[0] = 62; - array[1] = 83; - array[2] = 4; - array[3] = 89; - array[4] = 36; - array[5] = 21; - array[6] = 74; - array[7] = 37; - array[8] = 65; - array[9] = 33; - array[10] = 96; - array[11] = 38; - array[12] = 53; - array[13] = 16; - array[14] = 74; - array[15] = 55; - - for (i = 0; i < 16; i++) - printf("%d ", array[i]); - - printf("\n"); - - quicksort(0, 15); - - for (i = 0; i < 16; i++) - printf("%d ", array[i]); - - printf("\n"); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/25_quicksort.expect b/tinyc/tests/tests2/25_quicksort.expect deleted file mode 100644 index 2d39cd327..000000000 --- a/tinyc/tests/tests2/25_quicksort.expect +++ /dev/null @@ -1,2 +0,0 @@ -62 83 4 89 36 21 74 37 65 33 96 38 53 16 74 55 -4 16 21 33 36 37 38 53 55 62 65 74 74 83 89 96 diff --git a/tinyc/tests/tests2/26_character_constants.c b/tinyc/tests/tests2/26_character_constants.c deleted file mode 100644 index 95c442371..000000000 --- a/tinyc/tests/tests2/26_character_constants.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -int main() -{ - printf("%d\n", '\1'); - printf("%d\n", '\10'); - printf("%d\n", '\100'); - printf("%d\n", '\x01'); - printf("%d\n", '\x0e'); - printf("%d\n", '\x10'); - printf("%d\n", '\x40'); - printf("test \x40\n"); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/26_character_constants.expect b/tinyc/tests/tests2/26_character_constants.expect deleted file mode 100644 index 8f8bfa48c..000000000 --- a/tinyc/tests/tests2/26_character_constants.expect +++ /dev/null @@ -1,8 +0,0 @@ -1 -8 -64 -1 -14 -16 -64 -test @ diff --git a/tinyc/tests/tests2/27_sizeof.c b/tinyc/tests/tests2/27_sizeof.c deleted file mode 100644 index 5ae0ede54..000000000 --- a/tinyc/tests/tests2/27_sizeof.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -int main() -{ - char a; - int b; - double c; - - printf("%d\n", sizeof(a)); - printf("%d\n", sizeof(b)); - printf("%d\n", sizeof(c)); - - printf("%d\n", sizeof(!a)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/27_sizeof.expect b/tinyc/tests/tests2/27_sizeof.expect deleted file mode 100644 index a47ea3a40..000000000 --- a/tinyc/tests/tests2/27_sizeof.expect +++ /dev/null @@ -1,4 +0,0 @@ -1 -4 -8 -4 diff --git a/tinyc/tests/tests2/28_strings.c b/tinyc/tests/tests2/28_strings.c deleted file mode 100644 index 2db22986e..000000000 --- a/tinyc/tests/tests2/28_strings.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -int main() -{ - char a[10]; - - strcpy(a, "hello"); - printf("%s\n", a); - - strncpy(a, "gosh", 2); - printf("%s\n", a); - - printf("%d\n", strcmp(a, "apple") > 0); - printf("%d\n", strcmp(a, "goere") > 0); - printf("%d\n", strcmp(a, "zebra") < 0); - - printf("%d\n", strlen(a)); - - strcat(a, "!"); - printf("%s\n", a); - - printf("%d\n", strncmp(a, "apple", 2) > 0); - printf("%d\n", strncmp(a, "goere", 2) == 0); - printf("%d\n", strncmp(a, "goerg", 2) == 0); - printf("%d\n", strncmp(a, "zebra", 2) < 0); - - printf("%s\n", strchr(a, 'o')); - printf("%s\n", strrchr(a, 'l')); - printf("%d\n", strrchr(a, 'x') == NULL); - - memset(&a[1], 'r', 4); - printf("%s\n", a); - - memcpy(&a[2], a, 2); - printf("%s\n", a); - - printf("%d\n", memcmp(a, "apple", 4) > 0); - printf("%d\n", memcmp(a, "grgr", 4) == 0); - printf("%d\n", memcmp(a, "zebra", 4) < 0); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/28_strings.expect b/tinyc/tests/tests2/28_strings.expect deleted file mode 100644 index fd9217a22..000000000 --- a/tinyc/tests/tests2/28_strings.expect +++ /dev/null @@ -1,19 +0,0 @@ -hello -gollo -1 -1 -1 -5 -gollo! -1 -1 -1 -1 -ollo! -lo! -1 -grrrr! -grgrr! -1 -1 -1 diff --git a/tinyc/tests/tests2/29_array_address.c b/tinyc/tests/tests2/29_array_address.c deleted file mode 100644 index bda5ddde2..000000000 --- a/tinyc/tests/tests2/29_array_address.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -int main() -{ - char a[10]; - strcpy(a, "abcdef"); - printf("%s\n", &a[1]); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/29_array_address.expect b/tinyc/tests/tests2/29_array_address.expect deleted file mode 100644 index 9bc868324..000000000 --- a/tinyc/tests/tests2/29_array_address.expect +++ /dev/null @@ -1 +0,0 @@ -bcdef diff --git a/tinyc/tests/tests2/30_hanoi.c b/tinyc/tests/tests2/30_hanoi.c deleted file mode 100644 index 7c0893b1a..000000000 --- a/tinyc/tests/tests2/30_hanoi.c +++ /dev/null @@ -1,122 +0,0 @@ -/* example from http://barnyard.syr.edu/quickies/hanoi.c */ - -/* hanoi.c: solves the tower of hanoi problem. (Programming exercise.) */ -/* By Terry R. McConnell (12/2/97) */ -/* Compile: cc -o hanoi hanoi.c */ - -/* This program does no error checking. But then, if it's right, - it's right ... right ? */ - - -/* The original towers of hanoi problem seems to have been originally posed - by one M. Claus in 1883. There is a popular legend that goes along with - it that has been often repeated and paraphrased. It goes something like this: - In the great temple at Benares there are 3 golden spikes. On one of them, - God placed 64 disks increasing in size from bottom to top, at the beginning - of time. Since then, and to this day, the priest on duty constantly transfers - disks, one at a time, in such a way that no larger disk is ever put on top - of a smaller one. When the disks have been transferred entirely to another - spike the Universe will come to an end in a large thunderclap. - - This paraphrases the original legend due to DeParville, La Nature, Paris 1884, - Part I, 285-286. For this and further information see: Mathematical - Recreations & Essays, W.W. Rouse Ball, MacMillan, NewYork, 11th Ed. 1967, - 303-305. - * - * - */ - -#include -#include - -#define TRUE 1 -#define FALSE 0 - -/* This is the number of "disks" on tower A initially. Taken to be 64 in the - * legend. The number of moves required, in general, is 2^N - 1. For N = 64, - * this is 18,446,744,073,709,551,615 */ -#define N 4 - -/* These are the three towers. For example if the state of A is 0,1,3,4, that - * means that there are three discs on A of sizes 1, 3, and 4. (Think of right - * as being the "down" direction.) */ -int A[N], B[N], C[N]; - -void Hanoi(int,int*,int*,int*); - -/* Print the current configuration of A, B, and C to the screen */ -void PrintAll() -{ - int i; - - printf("A: "); - for(i=0;i - -int main(int argc, char **argv) -{ - int Count; - - printf("hello world %d\n", argc); - for (Count = 1; Count < argc; Count++) - printf("arg %d: %s\n", Count, argv[Count]); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/31_args.expect b/tinyc/tests/tests2/31_args.expect deleted file mode 100644 index 8c60bfc5b..000000000 --- a/tinyc/tests/tests2/31_args.expect +++ /dev/null @@ -1,6 +0,0 @@ -hello world 6 -arg 1: arg1 -arg 2: arg2 -arg 3: arg3 -arg 4: arg4 -arg 5: arg5 diff --git a/tinyc/tests/tests2/32_led.c b/tinyc/tests/tests2/32_led.c deleted file mode 100644 index 5596cbfd3..000000000 --- a/tinyc/tests/tests2/32_led.c +++ /dev/null @@ -1,266 +0,0 @@ -/* example from http://barnyard.syr.edu/quickies/led.c */ - -/* led.c: print out number as if on 7 line led display. I.e., write integer - given on command line like this: - _ _ _ - | _| _| |_| |_ - | |_ _| | _| etc. - - We assume the terminal behaves like a classical teletype. So the top - lines of all digits have to be printed first, then the middle lines of - all digits, etc. - - By Terry R. McConnell - -compile: cc -o led led.c - -If you just want to link in the subroutine print_led that does all the -work, compile with -DNO_MAIN, and declare the following in any source file -that uses the call: - -extern void print_led(unsigned long x, char *buf); - -Bug: you cannot call repeatedly to print more than one number to a line. -That would require curses or some other terminal API that allows moving the -cursor to a previous line. - -*/ - - - -#include -#include - -#define MAX_DIGITS 32 -#define NO_MAIN - - -/* Print the top line of the digit d into buffer. - Does not null terminate buffer. */ - -void topline(int d, char *p){ - - *p++ = ' '; - switch(d){ - - /* all these have _ on top line */ - - case 0: - case 2: - case 3: - case 5: - case 7: - case 8: - case 9: - *p++ = '_'; - break; - default: - *p++=' '; - - } - *p++=' '; -} - -/* Print the middle line of the digit d into the buffer. - Does not null terminate. */ - -void midline(int d, char *p){ - - switch(d){ - - /* those that have leading | on middle line */ - - case 0: - case 4: - case 5: - case 6: - case 8: - case 9: - *p++='|'; - break; - default: - *p++=' '; - } - switch(d){ - - /* those that have _ on middle line */ - - case 2: - case 3: - case 4: - case 5: - case 6: - case 8: - case 9: - *p++='_'; - break; - default: - *p++=' '; - - } - switch(d){ - - /* those that have closing | on middle line */ - - case 0: - case 1: - case 2: - case 3: - case 4: - case 7: - case 8: - case 9: - *p++='|'; - break; - default: - *p++=' '; - - } -} - -/* Print the bottom line of the digit d. Does not null terminate. */ - -void botline(int d, char *p){ - - - switch(d){ - - /* those that have leading | on bottom line */ - - case 0: - case 2: - case 6: - case 8: - *p++='|'; - break; - default: - *p++=' '; - } - switch(d){ - - /* those that have _ on bottom line */ - - case 0: - case 2: - case 3: - case 5: - case 6: - case 8: - *p++='_'; - break; - default: - *p++=' '; - - } - switch(d){ - - /* those that have closing | on bottom line */ - - case 0: - case 1: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - *p++='|'; - break; - default: - *p++=' '; - - } -} - -/* Write the led representation of integer to string buffer. */ - -void print_led(unsigned long x, char *buf) -{ - - int i=0,n; - static int d[MAX_DIGITS]; - - - /* extract digits from x */ - - n = ( x == 0L ? 1 : 0 ); /* 0 is a digit, hence a special case */ - - while(x){ - d[n++] = (int)(x%10L); - if(n >= MAX_DIGITS)break; - x = x/10L; - } - - /* print top lines of all digits */ - - for(i=n-1;i>=0;i--){ - topline(d[i],buf); - buf += 3; - *buf++=' '; - } - *buf++='\n'; /* move teletype to next line */ - - /* print middle lines of all digits */ - - for(i=n-1;i>=0;i--){ - midline(d[i],buf); - buf += 3; - *buf++=' '; - } - *buf++='\n'; - - /* print bottom lines of all digits */ - - for(i=n-1;i>=0;i--){ - botline(d[i],buf); - buf += 3; - *buf++=' '; - } - *buf++='\n'; - *buf='\0'; -} - -int main() -{ - char buf[5*MAX_DIGITS]; - print_led(1234567, buf); - printf("%s\n",buf); - - return 0; -} - -#ifndef NO_MAIN -int main(int argc, char **argv) -{ - - int i=0,n; - long x; - static int d[MAX_DIGITS]; - char buf[5*MAX_DIGITS]; - - if(argc != 2){ - fprintf(stderr,"led: usage: led integer\n"); - return 1; - } - - /* fetch argument from command line */ - - x = atol(argv[1]); - - /* sanity check */ - - if(x<0){ - fprintf(stderr,"led: %d must be non-negative\n",x); - return 1; - } - - print_led(x,buf); - printf("%s\n",buf); - - return 0; - -} -#endif - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/32_led.expect b/tinyc/tests/tests2/32_led.expect deleted file mode 100644 index c53b58ae0..000000000 --- a/tinyc/tests/tests2/32_led.expect +++ /dev/null @@ -1,4 +0,0 @@ - _ _ _ _ - | _| _| |_| |_ |_ | - | |_ _| | _| |_| | - diff --git a/tinyc/tests/tests2/33_ternary_op.c b/tinyc/tests/tests2/33_ternary_op.c deleted file mode 100644 index 8579b5029..000000000 --- a/tinyc/tests/tests2/33_ternary_op.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -int main() -{ - int Count; - - for (Count = 0; Count < 10; Count++) - { - printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3)); - } - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/33_ternary_op.expect b/tinyc/tests/tests2/33_ternary_op.expect deleted file mode 100644 index 45ea507a5..000000000 --- a/tinyc/tests/tests2/33_ternary_op.expect +++ /dev/null @@ -1,10 +0,0 @@ -0 -1 -4 -9 -16 -15 -18 -21 -24 -27 diff --git a/tinyc/tests/tests2/34_array_assignment.c b/tinyc/tests/tests2/34_array_assignment.c deleted file mode 100644 index 5885c9732..000000000 --- a/tinyc/tests/tests2/34_array_assignment.c +++ /dev/null @@ -1,23 +0,0 @@ -#include - -int main() -{ - int a[4]; - - a[0] = 12; - a[1] = 23; - a[2] = 34; - a[3] = 45; - - printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]); - - int b[4]; - - b = a; - - printf("%d %d %d %d\n", b[0], b[1], b[2], b[3]); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/34_array_assignment.expect b/tinyc/tests/tests2/34_array_assignment.expect deleted file mode 100644 index 9736bf508..000000000 --- a/tinyc/tests/tests2/34_array_assignment.expect +++ /dev/null @@ -1,2 +0,0 @@ -12 23 34 45 -12 23 34 45 diff --git a/tinyc/tests/tests2/35_sizeof.c b/tinyc/tests/tests2/35_sizeof.c deleted file mode 100644 index 672e87e7f..000000000 --- a/tinyc/tests/tests2/35_sizeof.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -int main() -{ - char a; - short b; - - printf("%d %d\n", sizeof(char), sizeof(a)); - printf("%d %d\n", sizeof(short), sizeof(b)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/35_sizeof.expect b/tinyc/tests/tests2/35_sizeof.expect deleted file mode 100644 index 534fb831b..000000000 --- a/tinyc/tests/tests2/35_sizeof.expect +++ /dev/null @@ -1,2 +0,0 @@ -1 1 -2 2 diff --git a/tinyc/tests/tests2/36_array_initialisers.c b/tinyc/tests/tests2/36_array_initialisers.c deleted file mode 100644 index 1bc8ee088..000000000 --- a/tinyc/tests/tests2/36_array_initialisers.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main() -{ - int Count; - - int Array[10] = { 12, 34, 56, 78, 90, 123, 456, 789, 8642, 9753 }; - - for (Count = 0; Count < 10; Count++) - printf("%d: %d\n", Count, Array[Count]); - - int Array2[10] = { 12, 34, 56, 78, 90, 123, 456, 789, 8642, 9753, }; - - for (Count = 0; Count < 10; Count++) - printf("%d: %d\n", Count, Array2[Count]); - - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/36_array_initialisers.expect b/tinyc/tests/tests2/36_array_initialisers.expect deleted file mode 100644 index 3ac6c7729..000000000 --- a/tinyc/tests/tests2/36_array_initialisers.expect +++ /dev/null @@ -1,20 +0,0 @@ -0: 12 -1: 34 -2: 56 -3: 78 -4: 90 -5: 123 -6: 456 -7: 789 -8: 8642 -9: 9753 -0: 12 -1: 34 -2: 56 -3: 78 -4: 90 -5: 123 -6: 456 -7: 789 -8: 8642 -9: 9753 diff --git a/tinyc/tests/tests2/37_sprintf.c b/tinyc/tests/tests2/37_sprintf.c deleted file mode 100644 index 1dd1dce28..000000000 --- a/tinyc/tests/tests2/37_sprintf.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -int main() -{ - char Buf[100]; - int Count; - - for (Count = 1; Count <= 20; Count++) - { - sprintf(Buf, "->%02d<-\n", Count); - printf("%s", Buf); - } - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/37_sprintf.expect b/tinyc/tests/tests2/37_sprintf.expect deleted file mode 100644 index a643da842..000000000 --- a/tinyc/tests/tests2/37_sprintf.expect +++ /dev/null @@ -1,20 +0,0 @@ -->01<- -->02<- -->03<- -->04<- -->05<- -->06<- -->07<- -->08<- -->09<- -->10<- -->11<- -->12<- -->13<- -->14<- -->15<- -->16<- -->17<- -->18<- -->19<- -->20<- diff --git a/tinyc/tests/tests2/38_multiple_array_index.c b/tinyc/tests/tests2/38_multiple_array_index.c deleted file mode 100644 index 4e1868efe..000000000 --- a/tinyc/tests/tests2/38_multiple_array_index.c +++ /dev/null @@ -1,32 +0,0 @@ -#include - -int main() -{ - int a[4][4]; - int b = 0; - int x; - int y; - - for (x = 0; x < 4; x++) - { - for (y = 0; y < 4; y++) - { - b++; - a[x][y] = b; - } - } - - for (x = 0; x < 4; x++) - { - printf("x=%d: ", x); - for (y = 0; y < 4; y++) - { - printf("%d ", a[x][y]); - } - printf("\n"); - } - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/38_multiple_array_index.expect b/tinyc/tests/tests2/38_multiple_array_index.expect deleted file mode 100644 index 747ad751d..000000000 --- a/tinyc/tests/tests2/38_multiple_array_index.expect +++ /dev/null @@ -1,4 +0,0 @@ -x=0: 1 2 3 4 -x=1: 5 6 7 8 -x=2: 9 10 11 12 -x=3: 13 14 15 16 diff --git a/tinyc/tests/tests2/39_typedef.c b/tinyc/tests/tests2/39_typedef.c deleted file mode 100644 index da73f71e6..000000000 --- a/tinyc/tests/tests2/39_typedef.c +++ /dev/null @@ -1,65 +0,0 @@ -#include - -typedef int MyInt; - -struct FunStruct -{ - int i; - int j; -}; - -typedef struct FunStruct MyFunStruct; - -typedef MyFunStruct *MoreFunThanEver; - -int main() -{ - MyInt a = 1; - printf("%d\n", a); - - MyFunStruct b; - b.i = 12; - b.j = 34; - printf("%d,%d\n", b.i, b.j); - - MoreFunThanEver c = &b; - printf("%d,%d\n", c->i, c->j); - - return 0; -} - -/* "If the specification of an array type includes any type qualifiers, - the element type is so-qualified, not the array type." */ - -typedef int A[3]; -extern A const ca; -extern const A ca; -extern const int ca[3]; - -typedef A B[1][2]; -extern B const cb; -extern const B cb; -extern const int cb[1][2][3]; - -extern B b; -extern int b[1][2][3]; - -/* Funny but valid function declaration. */ -typedef int functype (int); -extern functype func; -int func(int i) -{ - return i + 1; -} - -/* Even funnier function decl and definition using typeof. */ -int set_anon_super(void); -int set_anon_super(void) -{ - return 42; -} -typedef int sas_type (void); -extern typeof(set_anon_super) set_anon_super; -extern sas_type set_anon_super; - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/39_typedef.expect b/tinyc/tests/tests2/39_typedef.expect deleted file mode 100644 index b9050a9b6..000000000 --- a/tinyc/tests/tests2/39_typedef.expect +++ /dev/null @@ -1,3 +0,0 @@ -1 -12,34 -12,34 diff --git a/tinyc/tests/tests2/40_stdio.c b/tinyc/tests/tests2/40_stdio.c deleted file mode 100644 index b98609302..000000000 --- a/tinyc/tests/tests2/40_stdio.c +++ /dev/null @@ -1,52 +0,0 @@ -#include - -int main() -{ - FILE *f = fopen("fred.txt", "w"); - fwrite("hello\nhello\n", 1, 12, f); - fclose(f); - - char freddy[7]; - f = fopen("fred.txt", "r"); - if (fread(freddy, 1, 6, f) != 6) - printf("couldn't read fred.txt\n"); - - freddy[6] = '\0'; - fclose(f); - - printf("%s", freddy); - - int InChar; - char ShowChar; - f = fopen("fred.txt", "r"); - while ( (InChar = fgetc(f)) != EOF) - { - ShowChar = InChar; - if (ShowChar < ' ') - ShowChar = '.'; - - printf("ch: %d '%c'\n", InChar, ShowChar); - } - fclose(f); - - f = fopen("fred.txt", "r"); - while ( (InChar = getc(f)) != EOF) - { - ShowChar = InChar; - if (ShowChar < ' ') - ShowChar = '.'; - - printf("ch: %d '%c'\n", InChar, ShowChar); - } - fclose(f); - - f = fopen("fred.txt", "r"); - while (fgets(freddy, sizeof(freddy), f) != NULL) - printf("x: %s", freddy); - - fclose(f); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/40_stdio.expect b/tinyc/tests/tests2/40_stdio.expect deleted file mode 100644 index e08167a6e..000000000 --- a/tinyc/tests/tests2/40_stdio.expect +++ /dev/null @@ -1,27 +0,0 @@ -hello -ch: 104 'h' -ch: 101 'e' -ch: 108 'l' -ch: 108 'l' -ch: 111 'o' -ch: 10 '.' -ch: 104 'h' -ch: 101 'e' -ch: 108 'l' -ch: 108 'l' -ch: 111 'o' -ch: 10 '.' -ch: 104 'h' -ch: 101 'e' -ch: 108 'l' -ch: 108 'l' -ch: 111 'o' -ch: 10 '.' -ch: 104 'h' -ch: 101 'e' -ch: 108 'l' -ch: 108 'l' -ch: 111 'o' -ch: 10 '.' -x: hello -x: hello diff --git a/tinyc/tests/tests2/41_hashif.c b/tinyc/tests/tests2/41_hashif.c deleted file mode 100644 index cb37b9eb0..000000000 --- a/tinyc/tests/tests2/41_hashif.c +++ /dev/null @@ -1,85 +0,0 @@ -#include - -int main() -{ - printf("#include test\n"); - -#if 1 -#if 0 - printf("a\n"); -#else - printf("b\n"); -#endif -#else -#if 0 - printf("c\n"); -#else - printf("d\n"); -#endif -#endif - -#if 0 -#if 1 - printf("e\n"); -#else - printf("f\n"); -#endif -#else -#if 1 - printf("g\n"); -#else - printf("h\n"); -#endif -#endif - -#define DEF - -#ifdef DEF -#ifdef DEF - printf("i\n"); -#else - printf("j\n"); -#endif -#else -#ifdef DEF - printf("k\n"); -#else - printf("l\n"); -#endif -#endif - -#ifndef DEF -#ifndef DEF - printf("m\n"); -#else - printf("n\n"); -#endif -#else -#ifndef DEF - printf("o\n"); -#else - printf("p\n"); -#endif -#endif - -#define ONE 1 -#define ZERO 0 - -#if ONE -#if ZERO - printf("q\n"); -#else - printf("r\n"); -#endif -#else -#if ZERO - printf("s\n"); -#else - printf("t\n"); -#endif -#endif - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/41_hashif.expect b/tinyc/tests/tests2/41_hashif.expect deleted file mode 100644 index 5fd414bd0..000000000 --- a/tinyc/tests/tests2/41_hashif.expect +++ /dev/null @@ -1,6 +0,0 @@ -#include test -b -g -i -p -r diff --git a/tinyc/tests/tests2/42_function_pointer.c b/tinyc/tests/tests2/42_function_pointer.c deleted file mode 100644 index 697bd79a6..000000000 --- a/tinyc/tests/tests2/42_function_pointer.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -int fred(int p) -{ - printf("yo %d\n", p); - return 42; -} - -int (*f)(int) = &fred; - -/* To test what this is supposed to test the destination function - (fprint here) must not be called directly anywhere in the test. */ -int (*fprintfptr)(FILE *, const char *, ...) = &fprintf; - -int main() -{ - fprintfptr(stdout, "%d\n", (*f)(24)); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/42_function_pointer.expect b/tinyc/tests/tests2/42_function_pointer.expect deleted file mode 100644 index 6c8b6ce45..000000000 --- a/tinyc/tests/tests2/42_function_pointer.expect +++ /dev/null @@ -1,2 +0,0 @@ -yo 24 -42 diff --git a/tinyc/tests/tests2/43_void_param.c b/tinyc/tests/tests2/43_void_param.c deleted file mode 100644 index de17098b2..000000000 --- a/tinyc/tests/tests2/43_void_param.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -void fred(void) -{ - printf("yo\n"); -} - -int main() -{ - fred(); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/43_void_param.expect b/tinyc/tests/tests2/43_void_param.expect deleted file mode 100644 index 092bfb9bd..000000000 --- a/tinyc/tests/tests2/43_void_param.expect +++ /dev/null @@ -1 +0,0 @@ -yo diff --git a/tinyc/tests/tests2/44_scoped_declarations.c b/tinyc/tests/tests2/44_scoped_declarations.c deleted file mode 100644 index f38664fc5..000000000 --- a/tinyc/tests/tests2/44_scoped_declarations.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -int main() -{ - int a; - - for (a = 0; a < 2; a++) - { - int b = a; - } - - printf("it's all good\n"); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/44_scoped_declarations.expect b/tinyc/tests/tests2/44_scoped_declarations.expect deleted file mode 100644 index 231ccc0c5..000000000 --- a/tinyc/tests/tests2/44_scoped_declarations.expect +++ /dev/null @@ -1 +0,0 @@ -it's all good diff --git a/tinyc/tests/tests2/45_empty_for.c b/tinyc/tests/tests2/45_empty_for.c deleted file mode 100644 index 7cef513f8..000000000 --- a/tinyc/tests/tests2/45_empty_for.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -int main() -{ - int Count = 0; - - for (;;) - { - Count++; - printf("%d\n", Count); - if (Count >= 10) - break; - } - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/45_empty_for.expect b/tinyc/tests/tests2/45_empty_for.expect deleted file mode 100644 index f00c965d8..000000000 --- a/tinyc/tests/tests2/45_empty_for.expect +++ /dev/null @@ -1,10 +0,0 @@ -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 diff --git a/tinyc/tests/tests2/46_grep.c b/tinyc/tests/tests2/46_grep.c deleted file mode 100644 index 049dfb15e..000000000 --- a/tinyc/tests/tests2/46_grep.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * The information in this document is subject to change - * without notice and should not be construed as a commitment - * by Digital Equipment Corporation or by DECUS. - * - * Neither Digital Equipment Corporation, DECUS, nor the authors - * assume any responsibility for the use or reliability of this - * document or the described software. - * - * Copyright (C) 1980, DECUS - * - * General permission to copy or modify, but not for profit, is - * hereby granted, provided that the above copyright notice is - * included and reference made to the fact that reproduction - * privileges were granted by DECUS. - */ -#include -#include -#include // tolower() - -/* - * grep - * - * Runs on the Decus compiler or on vms, On vms, define as: - * grep :== "$disk:[account]grep" (native) - * grep :== "$disk:[account]grep grep" (Decus) - * See below for more information. - */ - -char *documentation[] = { - "grep searches a file for a given pattern. Execute by", - " grep [flags] regular_expression file_list\n", - "Flags are single characters preceded by '-':", - " -c Only a count of matching lines is printed", - " -f Print file name for matching lines switch, see below", - " -n Each line is preceded by its line number", - " -v Only print non-matching lines\n", - "The file_list is a list of files (wildcards are acceptable on RSX modes).", - "\nThe file name is normally printed if there is a file given.", - "The -f flag reverses this action (print name no file, not if more).\n", - 0 }; - -char *patdoc[] = { - "The regular_expression defines the pattern to search for. Upper- and", - "lower-case are always ignored. Blank lines never match. The expression", - "should be quoted to prevent file-name translation.", - "x An ordinary character (not mentioned below) matches that character.", - "'\\' The backslash quotes any character. \"\\$\" matches a dollar-sign.", - "'^' A circumflex at the beginning of an expression matches the", - " beginning of a line.", - "'$' A dollar-sign at the end of an expression matches the end of a line.", - "'.' A period matches any character except \"new-line\".", - "':a' A colon matches a class of characters described by the following", - "':d' character. \":a\" matches any alphabetic, \":d\" matches digits,", - "':n' \":n\" matches alphanumerics, \": \" matches spaces, tabs, and", - "': ' other control characters, such as new-line.", - "'*' An expression followed by an asterisk matches zero or more", - " occurrences of that expression: \"fo*\" matches \"f\", \"fo\"", - " \"foo\", etc.", - "'+' An expression followed by a plus sign matches one or more", - " occurrences of that expression: \"fo+\" matches \"fo\", etc.", - "'-' An expression followed by a minus sign optionally matches", - " the expression.", - "'[]' A string enclosed in square brackets matches any character in", - " that string, but no others. If the first character in the", - " string is a circumflex, the expression matches any character", - " except \"new-line\" and the characters in the string. For", - " example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"", - " matches \"abc\" but not \"axb\". A range of characters may be", - " specified by two characters separated by \"-\". Note that,", - " [a-z] matches alphabetics, while [z-a] never matches.", - "The concatenation of regular expressions is a regular expression.", - 0}; - -#define LMAX 512 -#define PMAX 256 - -#define CHAR 1 -#define BOL 2 -#define EOL 3 -#define ANY 4 -#define CLASS 5 -#define NCLASS 6 -#define STAR 7 -#define PLUS 8 -#define MINUS 9 -#define ALPHA 10 -#define DIGIT 11 -#define NALPHA 12 -#define PUNCT 13 -#define RANGE 14 -#define ENDPAT 15 - -int cflag=0, fflag=0, nflag=0, vflag=0, nfile=0, debug=0; - -char *pp, lbuf[LMAX], pbuf[PMAX]; - -char *cclass(); -char *pmatch(); -void store(int); -void error(char *); -void badpat(char *, char *, char *); -int match(void); - - -/*** Display a file name *******************************/ -void file(char *s) -{ - printf("File %s:\n", s); -} - -/*** Report unopenable file ****************************/ -void cant(char *s) -{ - fprintf(stderr, "%s: cannot open\n", s); -} - -/*** Give good help ************************************/ -void help(char **hp) -{ - char **dp; - - for (dp = hp; *dp; ++dp) - printf("%s\n", *dp); -} - -/*** Display usage summary *****************************/ -void usage(char *s) -{ - fprintf(stderr, "?GREP-E-%s\n", s); - fprintf(stderr, - "Usage: grep [-cfnv] pattern [file ...]. grep ? for help\n"); - exit(1); -} - -/*** Compile the pattern into global pbuf[] ************/ -void compile(char *source) -{ - char *s; /* Source string pointer */ - char *lp; /* Last pattern pointer */ - int c; /* Current character */ - int o; /* Temp */ - char *spp; /* Save beginning of pattern */ - - s = source; - if (debug) - printf("Pattern = \"%s\"\n", s); - pp = pbuf; - while (c = *s++) { - /* - * STAR, PLUS and MINUS are special. - */ - if (c == '*' || c == '+' || c == '-') { - if (pp == pbuf || - (o=pp[-1]) == BOL || - o == EOL || - o == STAR || - o == PLUS || - o == MINUS) - badpat("Illegal occurrence op.", source, s); - store(ENDPAT); - store(ENDPAT); - spp = pp; /* Save pattern end */ - while (--pp > lp) /* Move pattern down */ - *pp = pp[-1]; /* one byte */ - *pp = (c == '*') ? STAR : - (c == '-') ? MINUS : PLUS; - pp = spp; /* Restore pattern end */ - continue; - } - /* - * All the rest. - */ - lp = pp; /* Remember start */ - switch(c) { - - case '^': - store(BOL); - break; - - case '$': - store(EOL); - break; - - case '.': - store(ANY); - break; - - case '[': - s = cclass(source, s); - break; - - case ':': - if (*s) { - switch(tolower(c = *s++)) { - - case 'a': - case 'A': - store(ALPHA); - break; - - case 'd': - case 'D': - store(DIGIT); - break; - - case 'n': - case 'N': - store(NALPHA); - break; - - case ' ': - store(PUNCT); - break; - - default: - badpat("Unknown : type", source, s); - - } - break; - } - else badpat("No : type", source, s); - - case '\\': - if (*s) - c = *s++; - - default: - store(CHAR); - store(tolower(c)); - } - } - store(ENDPAT); - store(0); /* Terminate string */ - if (debug) { - for (lp = pbuf; lp < pp;) { - if ((c = (*lp++ & 0377)) < ' ') - printf("\\%o ", c); - else printf("%c ", c); - } - printf("\n"); - } -} - -/*** Compile a class (within []) ***********************/ -char *cclass(char *source, char *src) - /* char *source; // Pattern start -- for error msg. */ - /* char *src; // Class start */ -{ - char *s; /* Source pointer */ - char *cp; /* Pattern start */ - int c; /* Current character */ - int o; /* Temp */ - - s = src; - o = CLASS; - if (*s == '^') { - ++s; - o = NCLASS; - } - store(o); - cp = pp; - store(0); /* Byte count */ - while ((c = *s++) && c!=']') { - if (c == '\\') { /* Store quoted char */ - if ((c = *s++) == '\0') /* Gotta get something */ - badpat("Class terminates badly", source, s); - else store(tolower(c)); - } - else if (c == '-' && - (pp - cp) > 1 && *s != ']' && *s != '\0') { - c = pp[-1]; /* Range start */ - pp[-1] = RANGE; /* Range signal */ - store(c); /* Re-store start */ - c = *s++; /* Get end char and*/ - store(tolower(c)); /* Store it */ - } - else { - store(tolower(c)); /* Store normal char */ - } - } - if (c != ']') - badpat("Unterminated class", source, s); - if ((c = (pp - cp)) >= 256) - badpat("Class too large", source, s); - if (c == 0) - badpat("Empty class", source, s); - *cp = c; - return(s); -} - -/*** Store an entry in the pattern buffer **************/ -void store(int op) -{ - if (pp >= &pbuf[PMAX]) - error("Pattern too complex\n"); - *pp++ = op; -} - -/*** Report a bad pattern specification ****************/ -void badpat(char *message, char *source, char *stop) - /* char *message; // Error message */ - /* char *source; // Pattern start */ - /* char *stop; // Pattern end */ -{ - fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source); - fprintf(stderr, "-GREP-E-Stopped at byte %ld, '%c'\n", - stop-source, stop[-1]); - error("?GREP-E-Bad pattern\n"); -} - -/*** Scan the file for the pattern in pbuf[] ***********/ -void grep(FILE *fp, char *fn) - /* FILE *fp; // File to process */ - /* char *fn; // File name (for -f option) */ -{ - int lno, count, m; - - lno = 0; - count = 0; - while (fgets(lbuf, LMAX, fp)) { - ++lno; - m = match(); - if ((m && !vflag) || (!m && vflag)) { - ++count; - if (!cflag) { - if (fflag && fn) { - file(fn); - fn = 0; - } - if (nflag) - printf("%d\t", lno); - printf("%s\n", lbuf); - } - } - } - if (cflag) { - if (fflag && fn) - file(fn); - printf("%d\n", count); - } -} - -/*** Match line (lbuf) with pattern (pbuf) return 1 if match ***/ -int match() -{ - char *l; /* Line pointer */ - - for (l = lbuf; *l; ++l) { - if (pmatch(l, pbuf)) - return(1); - } - return(0); -} - -/*** Match partial line with pattern *******************/ -char *pmatch(char *line, char *pattern) - /* char *line; // (partial) line to match */ - /* char *pattern; // (partial) pattern to match */ -{ - char *l; /* Current line pointer */ - char *p; /* Current pattern pointer */ - char c; /* Current character */ - char *e; /* End for STAR and PLUS match */ - int op; /* Pattern operation */ - int n; /* Class counter */ - char *are; /* Start of STAR match */ - - l = line; - if (debug > 1) - printf("pmatch(\"%s\")\n", line); - p = pattern; - while ((op = *p++) != ENDPAT) { - if (debug > 1) - printf("byte[%ld] = 0%o, '%c', op = 0%o\n", - l-line, *l, *l, op); - switch(op) { - - case CHAR: - if (tolower(*l++) != *p++) - return(0); - break; - - case BOL: - if (l != lbuf) - return(0); - break; - - case EOL: - if (*l != '\0') - return(0); - break; - - case ANY: - if (*l++ == '\0') - return(0); - break; - - case DIGIT: - if ((c = *l++) < '0' || (c > '9')) - return(0); - break; - - case ALPHA: - c = tolower(*l++); - if (c < 'a' || c > 'z') - return(0); - break; - - case NALPHA: - c = tolower(*l++); - if (c >= 'a' && c <= 'z') - break; - else if (c < '0' || c > '9') - return(0); - break; - - case PUNCT: - c = *l++; - if (c == 0 || c > ' ') - return(0); - break; - - case CLASS: - case NCLASS: - c = tolower(*l++); - n = *p++ & 0377; - do { - if (*p == RANGE) { - p += 3; - n -= 2; - if (c >= p[-2] && c <= p[-1]) - break; - } - else if (c == *p++) - break; - } while (--n > 1); - if ((op == CLASS) == (n <= 1)) - return(0); - if (op == CLASS) - p += n - 2; - break; - - case MINUS: - e = pmatch(l, p); /* Look for a match */ - while (*p++ != ENDPAT); /* Skip over pattern */ - if (e) /* Got a match? */ - l = e; /* Yes, update string */ - break; /* Always succeeds */ - - case PLUS: /* One or more ... */ - if ((l = pmatch(l, p)) == 0) - return(0); /* Gotta have a match */ - case STAR: /* Zero or more ... */ - are = l; /* Remember line start */ - while (*l && (e = pmatch(l, p))) - l = e; /* Get longest match */ - while (*p++ != ENDPAT); /* Skip over pattern */ - while (l >= are) { /* Try to match rest */ - if (e = pmatch(l, p)) - return(e); - --l; /* Nope, try earlier */ - } - return(0); /* Nothing else worked */ - - default: - printf("Bad op code %d\n", op); - error("Cannot happen -- match\n"); - } - } - return(l); -} - -/*** Report an error ***********************************/ -void error(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -/*** Main program - parse arguments & grep *************/ -int main(int argc, char **argv) -{ - char *p; - int c, i; - int gotpattern; - - FILE *f; - - if (argc <= 1) - usage("No arguments"); - if (argc == 2 && argv[1][0] == '?' && argv[1][1] == 0) { - help(documentation); - help(patdoc); - return 0; - } - nfile = argc-1; - gotpattern = 0; - for (i=1; i < argc; ++i) { - p = argv[i]; - if (*p == '-') { - ++p; - while (c = *p++) { - switch(tolower(c)) { - - case '?': - help(documentation); - break; - - case 'C': - case 'c': - ++cflag; - break; - - case 'D': - case 'd': - ++debug; - break; - - case 'F': - case 'f': - ++fflag; - break; - - case 'n': - case 'N': - ++nflag; - break; - - case 'v': - case 'V': - ++vflag; - break; - - default: - usage("Unknown flag"); - } - } - argv[i] = 0; - --nfile; - } else if (!gotpattern) { - compile(p); - argv[i] = 0; - ++gotpattern; - --nfile; - } - } - if (!gotpattern) - usage("No pattern"); - if (nfile == 0) - grep(stdin, 0); - else { - fflag = fflag ^ (nfile > 0); - for (i=1; i < argc; ++i) { - if (p = argv[i]) { - if ((f=fopen(p, "r")) == NULL) - cant(p); - else { - grep(f, p); - fclose(f); - } - } - } - } - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/46_grep.expect b/tinyc/tests/tests2/46_grep.expect deleted file mode 100644 index e8a67916b..000000000 --- a/tinyc/tests/tests2/46_grep.expect +++ /dev/null @@ -1,3 +0,0 @@ -File 46_grep.c: -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ - diff --git a/tinyc/tests/tests2/47_switch_return.c b/tinyc/tests/tests2/47_switch_return.c deleted file mode 100644 index 1ec7924c4..000000000 --- a/tinyc/tests/tests2/47_switch_return.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -void fred(int x) -{ - switch (x) - { - case 1: printf("1\n"); return; - case 2: printf("2\n"); break; - case 3: printf("3\n"); return; - } - - printf("out\n"); -} - -int main() -{ - fred(1); - fred(2); - fred(3); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/47_switch_return.expect b/tinyc/tests/tests2/47_switch_return.expect deleted file mode 100644 index b6deb7e9e..000000000 --- a/tinyc/tests/tests2/47_switch_return.expect +++ /dev/null @@ -1,4 +0,0 @@ -1 -2 -out -3 diff --git a/tinyc/tests/tests2/48_nested_break.c b/tinyc/tests/tests2/48_nested_break.c deleted file mode 100644 index 5bc5ba47f..000000000 --- a/tinyc/tests/tests2/48_nested_break.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -int main() -{ - int a; - char b; - - a = 0; - while (a < 2) - { - printf("%d", a++); - break; - - b = 'A'; - while (b < 'C') - { - printf("%c", b++); - } - printf("e"); - } - printf("\n"); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/48_nested_break.expect b/tinyc/tests/tests2/48_nested_break.expect deleted file mode 100644 index 573541ac9..000000000 --- a/tinyc/tests/tests2/48_nested_break.expect +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tinyc/tests/tests2/49_bracket_evaluation.c b/tinyc/tests/tests2/49_bracket_evaluation.c deleted file mode 100644 index 0cbe57d62..000000000 --- a/tinyc/tests/tests2/49_bracket_evaluation.c +++ /dev/null @@ -1,23 +0,0 @@ -#include - -struct point -{ - double x; - double y; -}; - -struct point point_array[100]; - -int main() -{ - int my_point = 10; - - point_array[my_point].x = 12.34; - point_array[my_point].y = 56.78; - - printf("%f, %f\n", point_array[my_point].x, point_array[my_point].y); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/49_bracket_evaluation.expect b/tinyc/tests/tests2/49_bracket_evaluation.expect deleted file mode 100644 index 1da66dbeb..000000000 --- a/tinyc/tests/tests2/49_bracket_evaluation.expect +++ /dev/null @@ -1 +0,0 @@ -12.340000, 56.780000 diff --git a/tinyc/tests/tests2/50_logical_second_arg.c b/tinyc/tests/tests2/50_logical_second_arg.c deleted file mode 100644 index ddec08c87..000000000 --- a/tinyc/tests/tests2/50_logical_second_arg.c +++ /dev/null @@ -1,29 +0,0 @@ -#include - -int fred() -{ - printf("fred\n"); - return 0; -} - -int joe() -{ - printf("joe\n"); - return 1; -} - -int main() -{ - printf("%d\n", fred() && joe()); - printf("%d\n", fred() || joe()); - printf("%d\n", joe() && fred()); - printf("%d\n", joe() || fred()); - printf("%d\n", fred() && (1 + joe())); - printf("%d\n", fred() || (0 + joe())); - printf("%d\n", joe() && (0 + fred())); - printf("%d\n", joe() || (1 + fred())); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/50_logical_second_arg.expect b/tinyc/tests/tests2/50_logical_second_arg.expect deleted file mode 100644 index d6174ae7d..000000000 --- a/tinyc/tests/tests2/50_logical_second_arg.expect +++ /dev/null @@ -1,20 +0,0 @@ -fred -0 -fred -joe -1 -joe -fred -0 -joe -1 -fred -0 -fred -joe -1 -joe -fred -0 -joe -1 diff --git a/tinyc/tests/tests2/51_static.c b/tinyc/tests/tests2/51_static.c deleted file mode 100644 index d6c0917cf..000000000 --- a/tinyc/tests/tests2/51_static.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -static int fred = 1234; -static int joe; - -void henry() -{ - static int fred = 4567; - - printf("%d\n", fred); - fred++; -} - -int main() -{ - printf("%d\n", fred); - henry(); - henry(); - henry(); - henry(); - printf("%d\n", fred); - fred = 8901; - joe = 2345; - printf("%d\n", fred); - printf("%d\n", joe); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/51_static.expect b/tinyc/tests/tests2/51_static.expect deleted file mode 100644 index 18224fa3e..000000000 --- a/tinyc/tests/tests2/51_static.expect +++ /dev/null @@ -1,8 +0,0 @@ -1234 -4567 -4568 -4569 -4570 -1234 -8901 -2345 diff --git a/tinyc/tests/tests2/52_unnamed_enum.c b/tinyc/tests/tests2/52_unnamed_enum.c deleted file mode 100644 index d0395b202..000000000 --- a/tinyc/tests/tests2/52_unnamed_enum.c +++ /dev/null @@ -1,27 +0,0 @@ -#include - -enum fred { a, b, c }; - -int main() -{ - printf("a=%d\n", a); - printf("b=%d\n", b); - printf("c=%d\n", c); - - enum fred d; - - typedef enum { e, f, g } h; - typedef enum { i, j, k } m; - - printf("e=%d\n", e); - printf("f=%d\n", f); - printf("g=%d\n", g); - - printf("i=%d\n", i); - printf("j=%d\n", j); - printf("k=%d\n", k); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/52_unnamed_enum.expect b/tinyc/tests/tests2/52_unnamed_enum.expect deleted file mode 100644 index 84f2ac846..000000000 --- a/tinyc/tests/tests2/52_unnamed_enum.expect +++ /dev/null @@ -1,9 +0,0 @@ -a=0 -b=1 -c=2 -e=0 -f=1 -g=2 -i=0 -j=1 -k=2 diff --git a/tinyc/tests/tests2/54_goto.c b/tinyc/tests/tests2/54_goto.c deleted file mode 100644 index 2e151bb76..000000000 --- a/tinyc/tests/tests2/54_goto.c +++ /dev/null @@ -1,56 +0,0 @@ -#include - -void fred() -{ - printf("In fred()\n"); - goto done; - printf("In middle\n"); -done: - printf("At end\n"); -} - -void joe() -{ - int b = 5678; - - printf("In joe()\n"); - - { - int c = 1234; - printf("c = %d\n", c); - goto outer; - printf("uh-oh\n"); - } - -outer: - - printf("done\n"); -} - -void henry() -{ - int a; - - printf("In henry()\n"); - goto inner; - - { - int b; -inner: - b = 1234; - printf("b = %d\n", b); - } - - printf("done\n"); -} - -int main() -{ - fred(); - joe(); - henry(); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/54_goto.expect b/tinyc/tests/tests2/54_goto.expect deleted file mode 100644 index 8e553fa62..000000000 --- a/tinyc/tests/tests2/54_goto.expect +++ /dev/null @@ -1,8 +0,0 @@ -In fred() -At end -In joe() -c = 1234 -done -In henry() -b = 1234 -done diff --git a/tinyc/tests/tests2/55_lshift_type.c b/tinyc/tests/tests2/55_lshift_type.c deleted file mode 100644 index aa3e51a16..000000000 --- a/tinyc/tests/tests2/55_lshift_type.c +++ /dev/null @@ -1,52 +0,0 @@ -/* $Id: lshift-type.c 53089 2012-07-06 11:18:26Z vinc17/ypig $ - -Tests on left-shift type, written by Vincent Lefevre . - -ISO C99 TC3 says: [6.5.7#3] "The integer promotions are performed on -each of the operands. The type of the result is that of the promoted -left operand." -*/ - -#include - -#define PTYPE(M) ((M) < 0 || -(M) < 0 ? -1 : 1) * (int) sizeof((M)+0) -#define CHECK(X,T) check(#X, PTYPE(X), PTYPE((X) << (T) 1)) -#define TEST1(X,T) do { CHECK(X,T); CHECK(X,unsigned T); } while (0) -#define TEST2(X) \ - do \ - { \ - TEST1((X),short); \ - TEST1((X),int); \ - TEST1((X),long); \ - TEST1((X),long long); \ - } \ - while (0) -#define TEST3(X,T) do { TEST2((T)(X)); TEST2((unsigned T)(X)); } while (0) -#define TEST4(X) \ - do \ - { \ - TEST3((X),short); \ - TEST3((X),int); \ - TEST3((X),long); \ - TEST3((X),long long); \ - } \ - while (0) - -static int debug, nfailed = 0; - -static void check (const char *s, int arg1, int shift) -{ - int failed = arg1 != shift; - if (debug || failed) - printf ("%s %d %d\n", s, arg1, shift); - nfailed += failed; -} - -int main (int argc, char **argv) -{ - debug = argc > 1; - TEST4(1); - TEST4(-1); - printf ("%d test(s) failed\n", nfailed); - return nfailed != 0; -} diff --git a/tinyc/tests/tests2/55_lshift_type.expect b/tinyc/tests/tests2/55_lshift_type.expect deleted file mode 100644 index 8523767af..000000000 --- a/tinyc/tests/tests2/55_lshift_type.expect +++ /dev/null @@ -1 +0,0 @@ -0 test(s) failed diff --git a/tinyc/tests/tests2/60_errors_and_warnings.c b/tinyc/tests/tests2/60_errors_and_warnings.c deleted file mode 100644 index 0028caffb..000000000 --- a/tinyc/tests/tests2/60_errors_and_warnings.c +++ /dev/null @@ -1,51 +0,0 @@ -#if defined test_56_btype_excess_1 -struct A {} int i; - -#elif defined test_57_btype_excess_2 -char int i; - -#elif defined test_58_function_redefinition -int f(void) { return 0; } -int f(void) { return 1; } - -#elif defined test_global_redefinition -int xxx = 1; -int xxx; -int xxx = 2; - -#elif defined test_59_function_array -int (*fct)[42](int x); - -#elif defined test_60_enum_redefinition -enum color { RED, GREEN, BLUE }; -enum color { R, G, B }; -enum color c; - -#elif defined test_62_enumerator_redefinition -enum color { RED, GREEN, BLUE }; -enum rgb { RED, G, B}; -enum color c = RED; - -#elif defined test_63_local_enumerator_redefinition -enum { - FOO, - BAR -}; - -int main(void) -{ - enum { - FOO = 2, - BAR - }; - - return BAR - FOO; -} - -#elif defined test_61_undefined_enum -enum rgb3 c = 42; - -#elif defined test_74_non_const_init -int i = i++; - -#endif diff --git a/tinyc/tests/tests2/60_errors_and_warnings.expect b/tinyc/tests/tests2/60_errors_and_warnings.expect deleted file mode 100644 index ed6a69019..000000000 --- a/tinyc/tests/tests2/60_errors_and_warnings.expect +++ /dev/null @@ -1,28 +0,0 @@ -[test_56_btype_excess_1] -60_errors_and_warnings.c:2: error: too many basic types - -[test_57_btype_excess_2] -60_errors_and_warnings.c:5: error: too many basic types - -[test_58_function_redefinition] -60_errors_and_warnings.c:9: error: redefinition of 'f' - -[test_global_redefinition] -60_errors_and_warnings.c:14: error: redefinition of 'xxx' - -[test_59_function_array] -60_errors_and_warnings.c:17: error: declaration of an array of functions - -[test_60_enum_redefinition] -60_errors_and_warnings.c:21: error: struct/union/enum already defined - -[test_62_enumerator_redefinition] -60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED' - -[test_63_local_enumerator_redefinition] - -[test_61_undefined_enum] -60_errors_and_warnings.c:46: error: unknown type size - -[test_74_non_const_init] -60_errors_and_warnings.c:49: error: initializer element is not constant diff --git a/tinyc/tests/tests2/64_macro_nesting.c b/tinyc/tests/tests2/64_macro_nesting.c deleted file mode 100644 index 676e5d3ef..000000000 --- a/tinyc/tests/tests2/64_macro_nesting.c +++ /dev/null @@ -1,12 +0,0 @@ -#include // printf() - -#define CAT2(a,b) a##b -#define CAT(a,b) CAT2(a,b) -#define AB(x) CAT(x,y) - -int main(void) -{ - int xy = 42; - printf("%d\n", CAT(A,B)(x)); - return 0; -} diff --git a/tinyc/tests/tests2/64_macro_nesting.expect b/tinyc/tests/tests2/64_macro_nesting.expect deleted file mode 100644 index d81cc0710..000000000 --- a/tinyc/tests/tests2/64_macro_nesting.expect +++ /dev/null @@ -1 +0,0 @@ -42 diff --git a/tinyc/tests/tests2/67_macro_concat.c b/tinyc/tests/tests2/67_macro_concat.c deleted file mode 100644 index c580d3a64..000000000 --- a/tinyc/tests/tests2/67_macro_concat.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#define P(A,B) A ## B ; bob -#define Q(A,B) A ## B+ - -int main(void) -{ - int bob, jim = 21; - bob = P(jim,) *= 2; - printf("jim: %d, bob: %d\n", jim, bob); - jim = 60 Q(+,)3; - printf("jim: %d\n", jim); - return 0; -} diff --git a/tinyc/tests/tests2/67_macro_concat.expect b/tinyc/tests/tests2/67_macro_concat.expect deleted file mode 100644 index 8386c2d6c..000000000 --- a/tinyc/tests/tests2/67_macro_concat.expect +++ /dev/null @@ -1,2 +0,0 @@ -jim: 21, bob: 42 -jim: 63 diff --git a/tinyc/tests/tests2/70_floating_point_literals.c b/tinyc/tests/tests2/70_floating_point_literals.c deleted file mode 100644 index 012fb4fab..000000000 --- a/tinyc/tests/tests2/70_floating_point_literals.c +++ /dev/null @@ -1,77 +0,0 @@ -#include - -int main() -{ - /* decimal floating constant */ - float fa0 = .123f; - float fa1 = .123E12F; - float fa2 = .123e-12f; - float fa3 = .123e+12f; - printf("%f\n%f\n%f\n%f\n\n", fa0, fa1, fa2, fa3); - - float fb0 = 123.123f; - float fb1 = 123.123E12F; - float fb2 = 123.123e-12f; - float fb3 = 123.123e+12f; - printf("%f\n%f\n%f\n%f\n\n", fb0, fb1, fb2, fb3); - - float fc0 = 123.f; - float fc1 = 123.E12F; - float fc2 = 123.e-12f; - float fc3 = 123.e+12f; - printf("%f\n%f\n%f\n%f\n\n", fc0, fc1, fc2, fc3); - - float fd0 = 123E12F; - float fd1 = 123e-12f; - float fd2 = 123e+12f; - printf("%f\n%f\n%f\n\n", fd0, fd1, fd2); - printf("\n"); - - /* hexadecimal floating constant */ - double da0 = 0X.1ACP12; - double da1 = 0x.1acp-12; - double da2 = 0x.1acp+12; - printf("%f\n%f\n%f\n\n", da0, da1, da2); - - double db0 = 0X1AC.BDP12; - double db1 = 0x1ac.bdp-12; - double db2 = 0x1ac.dbp+12; - printf("%f\n%f\n%f\n\n", db0, db1, db2); - - double dc0 = 0X1AC.P12; - double dc1 = 0x1ac.p-12; - double dc2 = 0x1ac.p+12; - printf("%f\n%f\n%f\n\n", dc0, dc1, dc2); - - double dd0 = 0X1ACP12; - double dd1 = 0x1acp-12; - double dd2 = 0x1acp+12; - printf("%f\n%f\n%f\n\n", dd0, dd1, dd2); - printf("\n"); - -#ifdef __TINYC__ - /* TCC extension - binary floating constant */ - long double la0 = 0B.110101100P12L; - long double la1 = 0b.110101100p-12l; - long double la2 = 0b.110101100p+12l; - printf("%Lf\n%Lf\n%Lf\n\n", la0, la1, la2); - - long double lb0 = 0B110101100.10111101P12L; - long double lb1 = 0b110101100.10111101p-12l; - long double lb2 = 0b110101100.10111101p+12l; - printf("%Lf\n%Lf\n%Lf\n\n", lb0, lb1, lb2); - - long double lc0 = 0B110101100.P12L; - long double lc1 = 0b110101100.p-12l; - long double lc2 = 0b110101100.p+12l; - printf("%Lf\n%Lf\n%Lf\n\n", lc0, lc1, lc2); - - long double ld0 = 0B110101100P12L; - long double ld1 = 0b110101100p-12l; - long double ld2 = 0b110101100p+12l; - printf("%Lf\n%Lf\n%Lf\n\n", ld0, ld1, ld2); -#endif - - return 0; -} diff --git a/tinyc/tests/tests2/70_floating_point_literals.expect b/tinyc/tests/tests2/70_floating_point_literals.expect deleted file mode 100644 index 7eb1efb9e..000000000 --- a/tinyc/tests/tests2/70_floating_point_literals.expect +++ /dev/null @@ -1,53 +0,0 @@ -0.123000 -122999996416.000000 -0.000000 -122999996416.000000 - -123.123001 -123122997002240.000000 -0.000000 -123122997002240.000000 - -123.000000 -123000003231744.000000 -0.000000 -123000003231744.000000 - -123000003231744.000000 -0.000000 -123000003231744.000000 - - -428.000000 -0.000026 -428.000000 - -1756112.000000 -0.104672 -1756592.000000 - -1753088.000000 -0.104492 -1753088.000000 - -1753088.000000 -0.104492 -1753088.000000 - - -3424.000000 -0.000204 -3424.000000 - -1756112.000000 -0.104672 -1756112.000000 - -1753088.000000 -0.104492 -1753088.000000 - -1753088.000000 -0.104492 -1753088.000000 - diff --git a/tinyc/tests/tests2/71_macro_empty_arg.c b/tinyc/tests/tests2/71_macro_empty_arg.c deleted file mode 100644 index f0d3511b9..000000000 --- a/tinyc/tests/tests2/71_macro_empty_arg.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#define T(a,b,c) a b c - -int main(void) -{ - printf("%d", T(1,+,2) T(+,,) T(,2,*) T(,7,) T(,,)); - return 0; -} diff --git a/tinyc/tests/tests2/71_macro_empty_arg.expect b/tinyc/tests/tests2/71_macro_empty_arg.expect deleted file mode 100644 index 98d9bcb75..000000000 --- a/tinyc/tests/tests2/71_macro_empty_arg.expect +++ /dev/null @@ -1 +0,0 @@ -17 diff --git a/tinyc/tests/tests2/72_long_long_constant.c b/tinyc/tests/tests2/72_long_long_constant.c deleted file mode 100644 index 66082133d..000000000 --- a/tinyc/tests/tests2/72_long_long_constant.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -int main() -{ - long long int res = 0; - - if (res < -2147483648LL) { - printf("Error: 0 < -2147483648\n"); - return 1; - } - else - if (2147483647LL < res) { - printf("Error: 2147483647 < 0\n"); - return 2; - } - else - printf("long long constant test ok.\n"); - return 0; -} diff --git a/tinyc/tests/tests2/72_long_long_constant.expect b/tinyc/tests/tests2/72_long_long_constant.expect deleted file mode 100644 index dda9e660d..000000000 --- a/tinyc/tests/tests2/72_long_long_constant.expect +++ /dev/null @@ -1 +0,0 @@ -long long constant test ok. diff --git a/tinyc/tests/tests2/73_arm64.c b/tinyc/tests/tests2/73_arm64.c deleted file mode 100644 index 8de61b388..000000000 --- a/tinyc/tests/tests2/73_arm64.c +++ /dev/null @@ -1,527 +0,0 @@ -// This program is designed to test some arm64-specific things, such as the -// calling convention, but should give the same results on any architecture. - -#include -#include -#include - -struct s1 { char x[1]; } s1 = { "0" }; -struct s2 { char x[2]; } s2 = { "12" }; -struct s3 { char x[3]; } s3 = { "345" }; -struct s4 { char x[4]; } s4 = { "6789" }; -struct s5 { char x[5]; } s5 = { "abcde" }; -struct s6 { char x[6]; } s6 = { "fghijk" }; -struct s7 { char x[7]; } s7 = { "lmnopqr" }; -struct s8 { char x[8]; } s8 = { "stuvwxyz" }; -struct s9 { char x[9]; } s9 = { "ABCDEFGHI" }; -struct s10 { char x[10]; } s10 = { "JKLMNOPQRS" }; -struct s11 { char x[11]; } s11 = { "TUVWXYZ0123" }; -struct s12 { char x[12]; } s12 = { "456789abcdef" }; -struct s13 { char x[13]; } s13 = { "ghijklmnopqrs" }; -struct s14 { char x[14]; } s14 = { "tuvwxyzABCDEFG" }; -struct s15 { char x[15]; } s15 = { "HIJKLMNOPQRSTUV" }; -struct s16 { char x[16]; } s16 = { "WXYZ0123456789ab" }; -struct s17 { char x[17]; } s17 = { "cdefghijklmnopqrs" }; - -struct hfa11 { float a; } hfa11 = { 11.1 }; -struct hfa12 { float a, b; } hfa12 = { 12.1, 12.2 }; -struct hfa13 { float a, b, c; } hfa13 = { 13.1, 13.2, 13.3 }; -struct hfa14 { float a, b, c, d; } hfa14 = { 14.1, 14.2, 14.3, 14.4 }; - -struct hfa21 { double a; } hfa21 = { 21.1 }; -struct hfa22 { double a, b; } hfa22 = { 22.1, 22.2 }; -struct hfa23 { double a, b, c; } hfa23 = { 23.1, 23.2, 23.3 }; -struct hfa24 { double a, b, c, d; } hfa24 = { 24.1, 24.2, 24.3, 24.4 }; - -struct hfa31 { long double a; } hfa31 = { 31.1 }; -struct hfa32 { long double a, b; } hfa32 = { 32.1, 32.2 }; -struct hfa33 { long double a, b, c; } hfa33 = { 33.1, 33.2, 33.3 }; -struct hfa34 { long double a, b, c, d; } hfa34 = { 34.1, 34.2, 34.3, 34.4 }; - -void fa_s1(struct s1 a) { printf("%.1s\n", a.x); } -void fa_s2(struct s2 a) { printf("%.2s\n", a.x); } -void fa_s3(struct s3 a) { printf("%.3s\n", a.x); } -void fa_s4(struct s4 a) { printf("%.4s\n", a.x); } -void fa_s5(struct s5 a) { printf("%.5s\n", a.x); } -void fa_s6(struct s6 a) { printf("%.6s\n", a.x); } -void fa_s7(struct s7 a) { printf("%.7s\n", a.x); } -void fa_s8(struct s8 a) { printf("%.8s\n", a.x); } -void fa_s9(struct s9 a) { printf("%.9s\n", a.x); } -void fa_s10(struct s10 a) { printf("%.10s\n", a.x); } -void fa_s11(struct s11 a) { printf("%.11s\n", a.x); } -void fa_s12(struct s12 a) { printf("%.12s\n", a.x); } -void fa_s13(struct s13 a) { printf("%.13s\n", a.x); } -void fa_s14(struct s14 a) { printf("%.14s\n", a.x); } -void fa_s15(struct s15 a) { printf("%.15s\n", a.x); } -void fa_s16(struct s16 a) { printf("%.16s\n", a.x); } -void fa_s17(struct s17 a) { printf("%.17s\n", a.x); } - -void fa_hfa11(struct hfa11 a) -{ printf("%.1f\n", a.a); } -void fa_hfa12(struct hfa12 a) -{ printf("%.1f %.1f\n", a.a, a.a); } -void fa_hfa13(struct hfa13 a) -{ printf("%.1f %.1f %.1f\n", a.a, a.b, a.c); } -void fa_hfa14(struct hfa14 a) -{ printf("%.1f %.1f %.1f %.1f\n", a.a, a.b, a.c, a.d); } - -void fa_hfa21(struct hfa21 a) -{ printf("%.1f\n", a.a); } -void fa_hfa22(struct hfa22 a) -{ printf("%.1f %.1f\n", a.a, a.a); } -void fa_hfa23(struct hfa23 a) -{ printf("%.1f %.1f %.1f\n", a.a, a.b, a.c); } -void fa_hfa24(struct hfa24 a) -{ printf("%.1f %.1f %.1f %.1f\n", a.a, a.b, a.c, a.d); } - -void fa_hfa31(struct hfa31 a) -{ printf("%.1Lf\n", a.a); } -void fa_hfa32(struct hfa32 a) -{ printf("%.1Lf %.1Lf\n", a.a, a.a); } -void fa_hfa33(struct hfa33 a) -{ printf("%.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c); } -void fa_hfa34(struct hfa34 a) -{ printf("%.1Lf %.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c, a.d); } - -void fa1(struct s8 a, struct s9 b, struct s10 c, struct s11 d, - struct s12 e, struct s13 f) -{ - printf("%.3s %.3s %.3s %.3s %.3s %.3s\n", a.x, b.x, c.x, d.x, e.x, f.x); -} - -void fa2(struct s9 a, struct s10 b, struct s11 c, struct s12 d, - struct s13 e, struct s14 f) -{ - printf("%.3s %.3s %.3s %.3s %.3s %.3s\n", a.x, b.x, c.x, d.x, e.x, f.x); -} - -void fa3(struct hfa14 a, struct hfa23 b, struct hfa32 c) -{ - printf("%.1f %.1f %.1f %.1f %.1Lf %.1Lf\n", - a.a, a.d, b.a, b.c, c.a, c.b); -} - -void fa4(struct s1 a, struct hfa14 b, struct s2 c, struct hfa24 d, - struct s3 e, struct hfa34 f) -{ - printf("%.1s %.1f %.1f %.2s %.1f %.1f %.3s %.1Lf %.1Lf\n", - a.x, b.a, b.d, c.x, d.a, d.d, e.x, f.a, f.d); -} - -void arg(void) -{ - printf("Arguments:\n"); - fa_s1(s1); - fa_s2(s2); - fa_s3(s3); - fa_s4(s4); - fa_s5(s5); - fa_s6(s6); - fa_s7(s7); - fa_s8(s8); - fa_s9(s9); - fa_s10(s10); - fa_s11(s11); - fa_s12(s12); - fa_s13(s13); - fa_s14(s14); - fa_s15(s15); - fa_s16(s16); - fa_s17(s17); - fa_hfa11(hfa11); - fa_hfa12(hfa12); - fa_hfa13(hfa13); - fa_hfa14(hfa14); - fa_hfa21(hfa21); - fa_hfa22(hfa22); - fa_hfa23(hfa23); - fa_hfa24(hfa24); - fa_hfa31(hfa31); - fa_hfa32(hfa32); - fa_hfa33(hfa33); - fa_hfa34(hfa34); - fa1(s8, s9, s10, s11, s12, s13); - fa2(s9, s10, s11, s12, s13, s14); - fa3(hfa14, hfa23, hfa32); - fa4(s1, hfa14, s2, hfa24, s3, hfa34); -} - -struct s1 fr_s1(void) { return s1; } -struct s2 fr_s2(void) { return s2; } -struct s3 fr_s3(void) { return s3; } -struct s4 fr_s4(void) { return s4; } -struct s5 fr_s5(void) { return s5; } -struct s6 fr_s6(void) { return s6; } -struct s7 fr_s7(void) { return s7; } -struct s8 fr_s8(void) { return s8; } -struct s9 fr_s9(void) { return s9; } -struct s10 fr_s10(void) { return s10; } -struct s11 fr_s11(void) { return s11; } -struct s12 fr_s12(void) { return s12; } -struct s13 fr_s13(void) { return s13; } -struct s14 fr_s14(void) { return s14; } -struct s15 fr_s15(void) { return s15; } -struct s16 fr_s16(void) { return s16; } -struct s17 fr_s17(void) { return s17; } - -struct hfa11 fr_hfa11(void) { return hfa11; } -struct hfa12 fr_hfa12(void) { return hfa12; } -struct hfa13 fr_hfa13(void) { return hfa13; } -struct hfa14 fr_hfa14(void) { return hfa14; } - -struct hfa21 fr_hfa21(void) { return hfa21; } -struct hfa22 fr_hfa22(void) { return hfa22; } -struct hfa23 fr_hfa23(void) { return hfa23; } -struct hfa24 fr_hfa24(void) { return hfa24; } - -struct hfa31 fr_hfa31(void) { return hfa31; } -struct hfa32 fr_hfa32(void) { return hfa32; } -struct hfa33 fr_hfa33(void) { return hfa33; } -struct hfa34 fr_hfa34(void) { return hfa34; } - -void ret(void) -{ - struct s1 t1 = fr_s1(); - struct s2 t2 = fr_s2(); - struct s3 t3 = fr_s3(); - struct s4 t4 = fr_s4(); - struct s5 t5 = fr_s5(); - struct s6 t6 = fr_s6(); - struct s7 t7 = fr_s7(); - struct s8 t8 = fr_s8(); - struct s9 t9 = fr_s9(); - struct s10 t10 = fr_s10(); - struct s11 t11 = fr_s11(); - struct s12 t12 = fr_s12(); - struct s13 t13 = fr_s13(); - struct s14 t14 = fr_s14(); - struct s15 t15 = fr_s15(); - struct s16 t16 = fr_s16(); - struct s17 t17 = fr_s17(); - printf("Return values:\n"); - printf("%.1s\n", t1.x); - printf("%.2s\n", t2.x); - printf("%.3s\n", t3.x); - printf("%.4s\n", t4.x); - printf("%.5s\n", t5.x); - printf("%.6s\n", t6.x); - printf("%.7s\n", t7.x); - printf("%.8s\n", t8.x); - printf("%.9s\n", t9.x); - printf("%.10s\n", t10.x); - printf("%.11s\n", t11.x); - printf("%.12s\n", t12.x); - printf("%.13s\n", t13.x); - printf("%.14s\n", t14.x); - printf("%.15s\n", t15.x); - printf("%.16s\n", t16.x); - printf("%.17s\n", t17.x); - printf("%.1f\n", fr_hfa11().a); - printf("%.1f %.1f\n", fr_hfa12().a, fr_hfa12().b); - printf("%.1f %.1f\n", fr_hfa13().a, fr_hfa13().c); - printf("%.1f %.1f\n", fr_hfa14().a, fr_hfa14().d); - printf("%.1f\n", fr_hfa21().a); - printf("%.1f %.1f\n", fr_hfa22().a, fr_hfa22().b); - printf("%.1f %.1f\n", fr_hfa23().a, fr_hfa23().c); - printf("%.1f %.1f\n", fr_hfa24().a, fr_hfa24().d); - printf("%.1Lf\n", fr_hfa31().a); - printf("%.1Lf %.1Lf\n", fr_hfa32().a, fr_hfa32().b); - printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c); - printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d); -} - -int match(const char **s, const char *f) -{ - const char *p = *s; - for (p = *s; *f && *f == *p; f++, p++) - ; - if (!*f) { - *s = p - 1; - return 1; - } - return 0; -} - -void myprintf(const char *format, ...) -{ - const char *s; - va_list ap; - va_start(ap, format); - for (s = format; *s; s++) { - if (match(&s, "%7s")) { - struct s7 t7 = va_arg(ap, struct s7); - printf("%.7s", t7.x); - } - else if (match(&s, "%9s")) { - struct s9 t9 = va_arg(ap, struct s9); - printf("%.9s", t9.x); - } - else if (match(&s, "%hfa11")) { - struct hfa11 x = va_arg(ap, struct hfa11); - printf("%.1f,%.1f", x.a, x.a); - } - else if (match(&s, "%hfa12")) { - struct hfa12 x = va_arg(ap, struct hfa12); - printf("%.1f,%.1f", x.a, x.b); - } - else if (match(&s, "%hfa13")) { - struct hfa13 x = va_arg(ap, struct hfa13); - printf("%.1f,%.1f", x.a, x.c); - } - else if (match(&s, "%hfa14")) { - struct hfa14 x = va_arg(ap, struct hfa14); - printf("%.1f,%.1f", x.a, x.d); - } - else if (match(&s, "%hfa21")) { - struct hfa21 x = va_arg(ap, struct hfa21); - printf("%.1f,%.1f", x.a, x.a); - } - else if (match(&s, "%hfa22")) { - struct hfa22 x = va_arg(ap, struct hfa22); - printf("%.1f,%.1f", x.a, x.b); - } - else if (match(&s, "%hfa23")) { - struct hfa23 x = va_arg(ap, struct hfa23); - printf("%.1f,%.1f", x.a, x.c); - } - else if (match(&s, "%hfa24")) { - struct hfa24 x = va_arg(ap, struct hfa24); - printf("%.1f,%.1f", x.a, x.d); - } - else if (match(&s, "%hfa31")) { - struct hfa31 x = va_arg(ap, struct hfa31); - printf("%.1Lf,%.1Lf", x.a, x.a); - } - else if (match(&s, "%hfa32")) { - struct hfa32 x = va_arg(ap, struct hfa32); - printf("%.1Lf,%.1Lf", x.a, x.b); - } - else if (match(&s, "%hfa33")) { - struct hfa33 x = va_arg(ap, struct hfa33); - printf("%.1Lf,%.1Lf", x.a, x.c); - } - else if (match(&s, "%hfa34")) { - struct hfa34 x = va_arg(ap, struct hfa34); - printf("%.1Lf,%.1Lf", x.a, x.d); - } - else - putchar(*s); - } - putchar('\n'); -} - -void stdarg(void) -{ - printf("stdarg:\n"); - myprintf("%9s %9s %9s %9s %9s %9s", s9, s9, s9, s9, s9, s9); - myprintf("%7s %9s %9s %9s %9s %9s", s7, s9, s9, s9, s9, s9); - - myprintf("HFA long double:"); - myprintf("%hfa34 %hfa34 %hfa34 %hfa34", hfa34, hfa34, hfa34, hfa34); - myprintf("%hfa33 %hfa34 %hfa34 %hfa34", hfa33, hfa34, hfa34, hfa34); - myprintf("%hfa32 %hfa34 %hfa34 %hfa34", hfa32, hfa34, hfa34, hfa34); - myprintf("%hfa31 %hfa34 %hfa34 %hfa34", hfa31, hfa34, hfa34, hfa34); - - myprintf("%hfa32 %hfa33 %hfa33 %hfa33 %hfa33", - hfa32, hfa33, hfa33, hfa33, hfa33); - myprintf("%hfa31 %hfa33 %hfa33 %hfa33 %hfa33", - hfa31, hfa33, hfa33, hfa33, hfa33); - myprintf("%hfa33 %hfa33 %hfa33 %hfa33", - hfa33, hfa33, hfa33, hfa33); - - myprintf("%hfa34 %hfa32 %hfa32 %hfa32 %hfa32", - hfa34, hfa32, hfa32, hfa32, hfa32); - myprintf("%hfa33 %hfa32 %hfa32 %hfa32 %hfa32", - hfa33, hfa32, hfa32, hfa32, hfa32); - - myprintf("%hfa34 %hfa32 %hfa31 %hfa31 %hfa31 %hfa31", - hfa34, hfa32, hfa31, hfa31, hfa31, hfa31); - - myprintf("HFA double:"); - myprintf("%hfa24 %hfa24 %hfa24 %hfa24", hfa24, hfa24, hfa24, hfa24); - myprintf("%hfa23 %hfa24 %hfa24 %hfa24", hfa23, hfa24, hfa24, hfa24); - myprintf("%hfa22 %hfa24 %hfa24 %hfa24", hfa22, hfa24, hfa24, hfa24); - myprintf("%hfa21 %hfa24 %hfa24 %hfa24", hfa21, hfa24, hfa24, hfa24); - - myprintf("%hfa22 %hfa23 %hfa23 %hfa23 %hfa23", - hfa22, hfa23, hfa23, hfa23, hfa23); - myprintf("%hfa21 %hfa23 %hfa23 %hfa23 %hfa23", - hfa21, hfa23, hfa23, hfa23, hfa23); - myprintf("%hfa23 %hfa23 %hfa23 %hfa23", - hfa23, hfa23, hfa23, hfa23); - - myprintf("%hfa24 %hfa22 %hfa22 %hfa22 %hfa22", - hfa24, hfa22, hfa22, hfa22, hfa22); - myprintf("%hfa23 %hfa22 %hfa22 %hfa22 %hfa22", - hfa23, hfa22, hfa22, hfa22, hfa22); - - myprintf("%hfa24 %hfa22 %hfa21 %hfa21 %hfa21 %hfa21", - hfa24, hfa22, hfa21, hfa21, hfa21, hfa21); - - myprintf("HFA float:"); - myprintf("%hfa14 %hfa14 %hfa14 %hfa14", hfa14, hfa14, hfa14, hfa14); - myprintf("%hfa13 %hfa14 %hfa14 %hfa14", hfa13, hfa14, hfa14, hfa14); - myprintf("%hfa12 %hfa14 %hfa14 %hfa14", hfa12, hfa14, hfa14, hfa14); - myprintf("%hfa11 %hfa14 %hfa14 %hfa14", hfa11, hfa14, hfa14, hfa14); - - myprintf("%hfa12 %hfa13 %hfa13 %hfa13 %hfa13", - hfa12, hfa13, hfa13, hfa13, hfa13); - myprintf("%hfa11 %hfa13 %hfa13 %hfa13 %hfa13", - hfa11, hfa13, hfa13, hfa13, hfa13); - myprintf("%hfa13 %hfa13 %hfa13 %hfa13", - hfa13, hfa13, hfa13, hfa13); - - myprintf("%hfa14 %hfa12 %hfa12 %hfa12 %hfa12", - hfa14, hfa12, hfa12, hfa12, hfa12); - myprintf("%hfa13 %hfa12 %hfa12 %hfa12 %hfa12", - hfa13, hfa12, hfa12, hfa12, hfa12); - - myprintf("%hfa14 %hfa12 %hfa11 %hfa11 %hfa11 %hfa11", - hfa14, hfa12, hfa11, hfa11, hfa11, hfa11); -} - -void pll(unsigned long long x) -{ - printf("%llx\n", x); -} - -void movi(void) -{ - printf("MOVI:\n"); - pll(0); - pll(0xabcd); - pll(0xabcd0000); - pll(0xabcd00000000); - pll(0xabcd000000000000); - pll(0xffffabcd); - pll(0xabcdffff); - pll(0xffffffffffffabcd); - pll(0xffffffffabcdffff); - pll(0xffffabcdffffffff); - pll(0xabcdffffffffffff); - pll(0xaaaaaaaa); - pll(0x5555555555555555); - pll(0x77777777); - pll(0x3333333333333333); - pll(0xf8f8f8f8); - pll(0x1e1e1e1e1e1e1e1e); - pll(0x3f803f80); - pll(0x01ff01ff01ff01ff); - pll(0x007fffc0); - pll(0x03fff80003fff800); - pll(0x0007fffffffffe00); - - pll(0xabcd1234); - pll(0xabcd00001234); - pll(0xabcd000000001234); - pll(0xabcd12340000); - pll(0xabcd000012340000); - pll(0xabcd123400000000); - pll(0xffffffffabcd1234); - pll(0xffffabcdffff1234); - pll(0xabcdffffffff1234); - pll(0xffffabcd1234ffff); - pll(0xabcdffff1234ffff); - pll(0xabcd1234ffffffff); - - pll(0xffffef0123456789); - pll(0xabcdef012345ffff); - - pll(0xabcdef0123456789); -} - -static uint32_t addip0(uint32_t x) { return x + 0; } -static uint64_t sublp0(uint64_t x) { return x - 0; } -static uint32_t addip123(uint32_t x) { return x + 123; } -static uint64_t addlm123(uint64_t x) { return x + -123; } -static uint64_t sublp4095(uint64_t x) { return x - 4095; } -static uint32_t subim503808(uint32_t x) { return x - -503808; } -static uint64_t addp12345(uint64_t x) { return x + 12345; } -static uint32_t subp12345(uint32_t x) { return x - 12345; } - -static uint32_t mvni(uint32_t x) { return 0xffffffff - x; } -static uint64_t negl(uint64_t x) { return 0 - x; } -static uint32_t rsbi123(uint32_t x) { return 123 - x; } -static uint64_t rsbl123(uint64_t x) { return 123 - x; } - -static uint32_t andi0(uint32_t x) { return x & 0; } -static uint64_t andlm1(uint64_t x) { return x & -1; } -static uint64_t orrl0(uint64_t x) { return x | 0; } -static uint32_t orrim1(uint32_t x) { return x | -1; } -static uint32_t eori0(uint32_t x) { return x ^ 0; } -static uint64_t eorlm1(uint64_t x) { return x ^ -1; } -static uint32_t and0xf0(uint32_t x) { return x & 0xf0; } -static uint64_t orr0xf0(uint64_t x) { return x | 0xf0; } -static uint64_t eor0xf0(uint64_t x) { return x ^ 0xf0; } - -static uint32_t lsli0(uint32_t x) { return x << 0; } -static uint32_t lsri0(uint32_t x) { return x >> 0; } -static int64_t asrl0(int64_t x) { return x >> 0; } -static uint32_t lsli1(uint32_t x) { return x << 1; } -static uint32_t lsli31(uint32_t x) { return x << 31; } -static uint64_t lsll1(uint64_t x) { return x << 1; } -static uint64_t lsll63(uint64_t x) { return x << 63; } -static uint32_t lsri1(uint32_t x) { return x >> 1; } -static uint32_t lsri31(uint32_t x) { return x >> 31; } -static uint64_t lsrl1(uint64_t x) { return x >> 1; } -static uint64_t lsrl63(uint64_t x) { return x >> 63; } -static int32_t asri1(int32_t x) { return x >> 1; } -static int32_t asri31(int32_t x) { return x >> 31; } -static int64_t asrl1(int64_t x) { return x >> 1; } -static int64_t asrl63(int64_t x) { return x >> 63; } - -void opi(void) -{ - int x = 1000; - pll(addip0(x)); - pll(sublp0(x)); - pll(addip123(x)); - pll(addlm123(x)); - pll(sublp4095(x)); - pll(subim503808(x)); - pll(addp12345(x)); - pll(subp12345(x)); - pll(mvni(x)); - pll(negl(x)); - pll(rsbi123(x)); - pll(rsbl123(x)); - pll(andi0(x)); - pll(andlm1(x)); - pll(orrl0(x)); - pll(orrim1(x)); - pll(eori0(x)); - pll(eorlm1(x)); - pll(and0xf0(x)); - pll(orr0xf0(x)); - pll(eor0xf0(x)); - pll(lsli0(x)); - pll(lsri0(x)); - pll(asrl0(x)); - pll(lsli1(x)); - pll(lsli31(x)); - pll(lsll1(x)); - pll(lsll63(x)); - pll(lsri1(x)); - pll(lsri31(x)); - pll(lsrl1(x)); - pll(lsrl63(x)); - pll(asri1(x)); - pll(asri31(x)); - pll(asrl1(x)); - pll(asrl63(x)); -} - -void pcs(void) -{ - arg(); - ret(); - stdarg(); - movi(); - opi(); -} - -int main() -{ - pcs(); - return 0; -} diff --git a/tinyc/tests/tests2/73_arm64.expect b/tinyc/tests/tests2/73_arm64.expect deleted file mode 100644 index 7bdebd307..000000000 --- a/tinyc/tests/tests2/73_arm64.expect +++ /dev/null @@ -1,174 +0,0 @@ -Arguments: -0 -12 -345 -6789 -abcde -fghijk -lmnopqr -stuvwxyz -ABCDEFGHI -JKLMNOPQRS -TUVWXYZ0123 -456789abcdef -ghijklmnopqrs -tuvwxyzABCDEFG -HIJKLMNOPQRSTUV -WXYZ0123456789ab -cdefghijklmnopqrs -11.1 -12.1 12.1 -13.1 13.2 13.3 -14.1 14.2 14.3 14.4 -21.1 -22.1 22.1 -23.1 23.2 23.3 -24.1 24.2 24.3 24.4 -31.1 -32.1 32.1 -33.1 33.2 33.3 -34.1 34.2 34.3 34.4 -stu ABC JKL TUV 456 ghi -ABC JKL TUV 456 ghi tuv -14.1 14.4 23.1 23.3 32.1 32.2 -0 14.1 14.4 12 24.1 24.4 345 34.1 34.4 -Return values: -0 -12 -345 -6789 -abcde -fghijk -lmnopqr -stuvwxyz -ABCDEFGHI -JKLMNOPQRS -TUVWXYZ0123 -456789abcdef -ghijklmnopqrs -tuvwxyzABCDEFG -HIJKLMNOPQRSTUV -WXYZ0123456789ab -cdefghijklmnopqrs -11.1 -12.1 12.2 -13.1 13.3 -14.1 14.4 -21.1 -22.1 22.2 -23.1 23.3 -24.1 24.4 -31.1 -32.1 32.2 -33.1 33.3 -34.1 34.4 -stdarg: -ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI -lmnopqr ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI -HFA long double: -34.1,34.4 34.1,34.4 34.1,34.4 34.1,34.4 -33.1,33.3 34.1,34.4 34.1,34.4 34.1,34.4 -32.1,32.2 34.1,34.4 34.1,34.4 34.1,34.4 -31.1,31.1 34.1,34.4 34.1,34.4 34.1,34.4 -32.1,32.2 33.1,33.3 33.1,33.3 33.1,33.3 33.1,33.3 -31.1,31.1 33.1,33.3 33.1,33.3 33.1,33.3 33.1,33.3 -33.1,33.3 33.1,33.3 33.1,33.3 33.1,33.3 -34.1,34.4 32.1,32.2 32.1,32.2 32.1,32.2 32.1,32.2 -33.1,33.3 32.1,32.2 32.1,32.2 32.1,32.2 32.1,32.2 -34.1,34.4 32.1,32.2 31.1,31.1 31.1,31.1 31.1,31.1 31.1,31.1 -HFA double: -24.1,24.4 24.1,24.4 24.1,24.4 24.1,24.4 -23.1,23.3 24.1,24.4 24.1,24.4 24.1,24.4 -22.1,22.2 24.1,24.4 24.1,24.4 24.1,24.4 -21.1,21.1 24.1,24.4 24.1,24.4 24.1,24.4 -22.1,22.2 23.1,23.3 23.1,23.3 23.1,23.3 23.1,23.3 -21.1,21.1 23.1,23.3 23.1,23.3 23.1,23.3 23.1,23.3 -23.1,23.3 23.1,23.3 23.1,23.3 23.1,23.3 -24.1,24.4 22.1,22.2 22.1,22.2 22.1,22.2 22.1,22.2 -23.1,23.3 22.1,22.2 22.1,22.2 22.1,22.2 22.1,22.2 -24.1,24.4 22.1,22.2 21.1,21.1 21.1,21.1 21.1,21.1 21.1,21.1 -HFA float: -14.1,14.4 14.1,14.4 14.1,14.4 14.1,14.4 -13.1,13.3 14.1,14.4 14.1,14.4 14.1,14.4 -12.1,12.2 14.1,14.4 14.1,14.4 14.1,14.4 -11.1,11.1 14.1,14.4 14.1,14.4 14.1,14.4 -12.1,12.2 13.1,13.3 13.1,13.3 13.1,13.3 13.1,13.3 -11.1,11.1 13.1,13.3 13.1,13.3 13.1,13.3 13.1,13.3 -13.1,13.3 13.1,13.3 13.1,13.3 13.1,13.3 -14.1,14.4 12.1,12.2 12.1,12.2 12.1,12.2 12.1,12.2 -13.1,13.3 12.1,12.2 12.1,12.2 12.1,12.2 12.1,12.2 -14.1,14.4 12.1,12.2 11.1,11.1 11.1,11.1 11.1,11.1 11.1,11.1 -MOVI: -0 -abcd -abcd0000 -abcd00000000 -abcd000000000000 -ffffabcd -abcdffff -ffffffffffffabcd -ffffffffabcdffff -ffffabcdffffffff -abcdffffffffffff -aaaaaaaa -5555555555555555 -77777777 -3333333333333333 -f8f8f8f8 -1e1e1e1e1e1e1e1e -3f803f80 -1ff01ff01ff01ff -7fffc0 -3fff80003fff800 -7fffffffffe00 -abcd1234 -abcd00001234 -abcd000000001234 -abcd12340000 -abcd000012340000 -abcd123400000000 -ffffffffabcd1234 -ffffabcdffff1234 -abcdffffffff1234 -ffffabcd1234ffff -abcdffff1234ffff -abcd1234ffffffff -ffffef0123456789 -abcdef012345ffff -abcdef0123456789 -3e8 -3e8 -463 -36d -fffffffffffff3e9 -7b3e8 -3421 -ffffd3af -fffffc17 -fffffffffffffc18 -fffffc93 -fffffffffffffc93 -0 -3e8 -3e8 -ffffffff -3e8 -fffffffffffffc17 -e0 -3f8 -318 -3e8 -3e8 -3e8 -7d0 -0 -7d0 -0 -1f4 -0 -1f4 -0 -1f4 -0 -1f4 -0 diff --git a/tinyc/tests/tests2/75_array_in_struct_init.c b/tinyc/tests/tests2/75_array_in_struct_init.c deleted file mode 100644 index 234e3c4fa..000000000 --- a/tinyc/tests/tests2/75_array_in_struct_init.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - -/* This test is a snippet from the J interpreter */ - -typedef long I; -typedef struct{I c[4];I b,e,k;} PT; - -PT cases[] = { - ((I)4194304L +(I)2097152L +(I)67108864L), (I)262144L, (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), -1L, 1,2,1, - ((I)+4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L, (I)262144L, (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), 2,3,2, - ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)262144L, (((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), 1,3,2, - ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)524288L, -1L, 1,2,1, - ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)1048576L, (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), 1,3,1, - ((I)4194304L +(I)2097152L +(I)67108864L)+( (I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)262144L, (I)262144L, 1,3,1, - ((I)4194304L +(I)2097152L +(I)67108864L), ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), -1L, 1,2,1, - (I)33554432L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L), (I)2097152L, ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), -1L, 0,2,1, - (I)67108864L, ((I)1048576L +(I)524288L +(I)262144L +(((I)1L +(I)256L +(I)4L +(I)8L +(I)16L +(I)64L +(I)128L +(I)268435456L +(I)536870912L +(I)1024L +(I)4096L +(I)8192L +(I)16384L)+((I)2L +(I)131072L +(I)2048L)+(I)32L +(I)32768L +(I)65536L)), (I)134217728L, -1L, 0,2,0, -}; - -int main() { - int i, j; - - for(j=0; j < sizeof(cases)/sizeof(cases[0]); j++) { - for(i=0; i < sizeof(cases->c)/sizeof(cases->c[0]); i++) - printf("cases[%d].c[%d]=%ld\n", j, i, cases[j].c[i]); - - printf("cases[%d].b=%ld\n", j, cases[j].b); - printf("cases[%d].e=%ld\n", j, cases[j].e); - printf("cases[%d].k=%ld\n", j, cases[j].k); - printf("\n"); - } - return 0; -} diff --git a/tinyc/tests/tests2/75_array_in_struct_init.expect b/tinyc/tests/tests2/75_array_in_struct_init.expect deleted file mode 100644 index 2b75aa59d..000000000 --- a/tinyc/tests/tests2/75_array_in_struct_init.expect +++ /dev/null @@ -1,72 +0,0 @@ -cases[0].c[0]=73400320 -cases[0].c[1]=262144 -cases[0].c[2]=805567999 -cases[0].c[3]=-1 -cases[0].b=1 -cases[0].e=2 -cases[0].k=1 - -cases[1].c[0]=879754751 -cases[1].c[1]=262144 -cases[1].c[2]=262144 -cases[1].c[3]=805567999 -cases[1].b=2 -cases[1].e=3 -cases[1].k=2 - -cases[2].c[0]=879754751 -cases[2].c[1]=805567999 -cases[2].c[2]=262144 -cases[2].c[3]=805567999 -cases[2].b=1 -cases[2].e=3 -cases[2].k=2 - -cases[3].c[0]=879754751 -cases[3].c[1]=805830143 -cases[3].c[2]=524288 -cases[3].c[3]=-1 -cases[3].b=1 -cases[3].e=2 -cases[3].k=1 - -cases[4].c[0]=879754751 -cases[4].c[1]=805830143 -cases[4].c[2]=1048576 -cases[4].c[3]=805830143 -cases[4].b=1 -cases[4].e=3 -cases[4].k=1 - -cases[5].c[0]=879754751 -cases[5].c[1]=805830143 -cases[5].c[2]=262144 -cases[5].c[3]=262144 -cases[5].b=1 -cases[5].e=3 -cases[5].k=1 - -cases[6].c[0]=73400320 -cases[6].c[1]=807403007 -cases[6].c[2]=807403007 -cases[6].c[3]=-1 -cases[6].b=1 -cases[6].e=2 -cases[6].k=1 - -cases[7].c[0]=839122431 -cases[7].c[1]=2097152 -cases[7].c[2]=807403007 -cases[7].c[3]=-1 -cases[7].b=0 -cases[7].e=2 -cases[7].k=1 - -cases[8].c[0]=67108864 -cases[8].c[1]=807403007 -cases[8].c[2]=134217728 -cases[8].c[3]=-1 -cases[8].b=0 -cases[8].e=2 -cases[8].k=0 - diff --git a/tinyc/tests/tests2/76_dollars_in_identifiers.c b/tinyc/tests/tests2/76_dollars_in_identifiers.c deleted file mode 100644 index c5fcf99e0..000000000 --- a/tinyc/tests/tests2/76_dollars_in_identifiers.c +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#define $(x) x -#define $fred 10 -#define joe$ 20 -#define hen$y 30 - -#define $10(x) x*10 -#define _$10(x) x/10 - -int main() -{ - printf("fred=%d\n", $fred); - printf("joe=%d\n", joe$); - printf("henry=%d\n", hen$y); - - printf("fred2=%d\n", $($fred)); - printf("joe2=%d\n", $(joe$)); - printf("henry2=%d\n", $(hen$y)); - - printf("fred10=%d\n", $10($fred)); - printf("joe_10=%d\n", _$10(joe$)); - - int $ = 10; - int a100$ = 100; - int a$$ = 1000; - int a$c$b = 2121; - int $100 = 10000; - const char *$$$ = "money"; - - printf("local=%d\n", $); - printf("a100$=%d\n", a100$); - printf("a$$=%d\n", a$$); - printf("a$c$b=%d\n", a$c$b); - printf("$100=%d\n", $100); - printf("$$$=%s", $$$); - - return 0; -} - -/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/ diff --git a/tinyc/tests/tests2/76_dollars_in_identifiers.expect b/tinyc/tests/tests2/76_dollars_in_identifiers.expect deleted file mode 100644 index 4a20a52e6..000000000 --- a/tinyc/tests/tests2/76_dollars_in_identifiers.expect +++ /dev/null @@ -1,14 +0,0 @@ -fred=10 -joe=20 -henry=30 -fred2=10 -joe2=20 -henry2=30 -fred10=100 -joe_10=2 -local=10 -a100$=100 -a$$=1000 -a$c$b=2121 -$100=10000 -$$$=money diff --git a/tinyc/tests/tests2/77_push_pop_macro.c b/tinyc/tests/tests2/77_push_pop_macro.c deleted file mode 100644 index d38e0bfe3..000000000 --- a/tinyc/tests/tests2/77_push_pop_macro.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -int main() -{ - /* must not affect how #pragma ppop_macro works */ - #define pop_macro foobar1 - - /* must not affect how #pragma push_macro works */ - #define push_macro foobar2 - - #undef abort - #define abort "111" - printf("abort = %s\n", abort); - - #pragma push_macro("abort") - #undef abort - #define abort "222" - printf("abort = %s\n", abort); - - #pragma push_macro("abort") - #undef abort - #define abort "333" - printf("abort = %s\n", abort); - - #pragma pop_macro("abort") - printf("abort = %s\n", abort); - - #pragma pop_macro("abort") - printf("abort = %s\n", abort); -} diff --git a/tinyc/tests/tests2/77_push_pop_macro.expect b/tinyc/tests/tests2/77_push_pop_macro.expect deleted file mode 100644 index d8a55305a..000000000 --- a/tinyc/tests/tests2/77_push_pop_macro.expect +++ /dev/null @@ -1,5 +0,0 @@ -abort = 111 -abort = 222 -abort = 333 -abort = 222 -abort = 111 diff --git a/tinyc/tests/tests2/78_vla_label.c b/tinyc/tests/tests2/78_vla_label.c deleted file mode 100644 index 4096495d9..000000000 --- a/tinyc/tests/tests2/78_vla_label.c +++ /dev/null @@ -1,45 +0,0 @@ -#include - -/* This test segfaults as of April 27, 2015. */ -void f1(int argc) -{ - char test[argc]; - if(0) - label: - printf("boom!\n"); - if(argc-- == 0) - return; - goto label; -} - -/* This segfaulted on 2015-11-19. */ -void f2(void) -{ - goto start; - { - int a[1 && 1]; /* not a variable-length array */ - int b[1 || 1]; /* not a variable-length array */ - int c[1 ? 1 : 1]; /* not a variable-length array */ - start: - a[0] = 0; - b[0] = 0; - c[0] = 0; - } -} - -void f3(void) -{ - printf("%d\n", 0 ? printf("x1\n") : 11); - printf("%d\n", 1 ? 12 : printf("x2\n")); - printf("%d\n", 0 && printf("x3\n")); - printf("%d\n", 1 || printf("x4\n")); -} - -int main() -{ - f1(2); - f2(); - f3(); - - return 0; -} diff --git a/tinyc/tests/tests2/78_vla_label.expect b/tinyc/tests/tests2/78_vla_label.expect deleted file mode 100644 index 3f4063bec..000000000 --- a/tinyc/tests/tests2/78_vla_label.expect +++ /dev/null @@ -1,6 +0,0 @@ -boom! -boom! -11 -12 -0 -1 diff --git a/tinyc/tests/tests2/79_vla_continue.c b/tinyc/tests/tests2/79_vla_continue.c deleted file mode 100644 index 91215c99e..000000000 --- a/tinyc/tests/tests2/79_vla_continue.c +++ /dev/null @@ -1,116 +0,0 @@ -#include - -int f(void) -{ - return 5; -} - -void test1() -{ - int count = 10; - void *addr[10]; - for(;count--;) { - int a[f()]; - - addr[count] = a; - - continue; - } - - if(addr[9] == addr[0]) { - printf("OK\n"); - } else { - printf("NOT OK\n"); - } -} - -void test2() -{ - int count = 10; - void *addr[count]; - for(;count--;) { - int a[f()]; - - addr[count] = a; - - continue; - } - - if(addr[9] == addr[0]) { - printf("OK\n"); - } else { - printf("NOT OK\n"); - } -} - -void test3() -{ - int count = 10; - void *addr[count]; - while(count--) { - int a[f()]; - - addr[count] = a; - - continue; - } - - if(addr[9] == addr[0]) { - printf("OK\n"); - } else { - printf("NOT OK\n"); - } -} - -void test4() -{ - int count = 10; - void *addr[count]; - do { - int a[f()]; - - addr[--count] = a; - - continue; - } while (count); - - if(addr[9] == addr[0]) { - printf("OK\n"); - } else { - printf("NOT OK\n"); - } -} - -void test5() -{ - int count = 10; - int a[f()]; - int c[f()]; - - c[0] = 42; - - for(;count--;) { - int b[f()]; - int i; - for (i=0; i -struct wchar { - char *data; char mem[]; -}; -struct wint { - char *data; int mem[]; -}; -int f1char (void) { - char s[9]="nonono"; - struct wchar q = {"bugs"}; - return !s[0]; -} -int f1int (void) { - char s[9]="nonono"; - struct wint q = {"bugs"}; - return !s[0]; -} -int main (void) { - char s[9]="nonono"; - static struct wchar q = {"bugs", {'c'}}; - //printf ("tcc has %s %s\n", s, q.data); - if (f1char() || f1int()) - printf ("bla\n"); - return !s[0]; -} diff --git a/tinyc/tests/tests2/80_flexarray.expect b/tinyc/tests/tests2/80_flexarray.expect deleted file mode 100644 index e69de29bb..000000000 diff --git a/tinyc/tests/tests2/81_types.c b/tinyc/tests/tests2/81_types.c deleted file mode 100644 index fd6d71b0c..000000000 --- a/tinyc/tests/tests2/81_types.c +++ /dev/null @@ -1,43 +0,0 @@ -/* The following are all valid decls, even though some subtypes - are incomplete. */ -enum E *e; -const enum E *e1; -enum E const *e2; -struct S *s; -const struct S *s1; -struct S const *s2; - -/* Various strangely looking declarators, which are all valid - and have to map to the same numbered typedefs. */ -typedef int (*fptr1)(); -int f1 (int (), int); -typedef int (*fptr2)(int x); -int f2 (int (int x), int); -typedef int (*fptr3)(int); -int f3 (int (int), int); -typedef int (*fptr4[4])(int); -int f4 (int (*[4])(int), int); -typedef int (*fptr5)(fptr1); -int f5 (int (int()), fptr1); -int f1 (fptr1 fp, int i) -{ - return (*fp)(i); -} -int f2 (fptr2 fp, int i) -{ - return (*fp)(i); -} -int f3 (fptr3 fp, int i) -{ - return (*fp)(i); -} -int f4 (fptr4 fp, int i) -{ - return (*fp[i])(i); -} -int f5 (fptr5 fp, fptr1 i) -{ - return fp(i); -} -int f8 (int ([4]), int); -int main () { return 0; } diff --git a/tinyc/tests/tests2/81_types.expect b/tinyc/tests/tests2/81_types.expect deleted file mode 100644 index e69de29bb..000000000 diff --git a/tinyc/tests/tests2/82_attribs_position.c b/tinyc/tests/tests2/82_attribs_position.c deleted file mode 100644 index 7c9f98726..000000000 --- a/tinyc/tests/tests2/82_attribs_position.c +++ /dev/null @@ -1,19 +0,0 @@ -typedef unsigned short uint16_t; -typedef unsigned char uint8_t; - -typedef union Unaligned16a { - uint16_t u; - uint8_t b[2]; -} __attribute__((packed)) Unaligned16a; - -typedef union __attribute__((packed)) Unaligned16b { - uint16_t u; - uint8_t b[2]; -} Unaligned16b; - -extern void foo (void) __attribute__((stdcall)); -void __attribute__((stdcall)) foo (void) -{ -} - -int main () { return 0; } diff --git a/tinyc/tests/tests2/82_attribs_position.expect b/tinyc/tests/tests2/82_attribs_position.expect deleted file mode 100644 index e69de29bb..000000000 diff --git a/tinyc/tests/tests2/83_utf8_in_identifiers.c b/tinyc/tests/tests2/83_utf8_in_identifiers.c deleted file mode 100644 index 1f8609525..000000000 --- a/tinyc/tests/tests2/83_utf8_in_identifiers.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -double привет=0.1; -int Lefèvre=2; -int main(){ - printf("привет=%g\n",привет); - printf("Lefèvre=%d\n",Lefèvre); - return 0; -} -// pcc & tcc only diff --git a/tinyc/tests/tests2/83_utf8_in_identifiers.expect b/tinyc/tests/tests2/83_utf8_in_identifiers.expect deleted file mode 100644 index 1553f5f6f..000000000 --- a/tinyc/tests/tests2/83_utf8_in_identifiers.expect +++ /dev/null @@ -1,2 +0,0 @@ -привет=0.1 -Lefèvre=2 diff --git a/tinyc/tests/tests2/84_hex-float.c b/tinyc/tests/tests2/84_hex-float.c deleted file mode 100644 index 0ef09bfc2..000000000 --- a/tinyc/tests/tests2/84_hex-float.c +++ /dev/null @@ -1,12 +0,0 @@ -extern int printf(const char *format, ...); - -#define ACPI_TYPE_INVALID 0x1E -#define NUM_NS_TYPES ACPI_TYPE_INVALID+1 -int array[NUM_NS_TYPES]; - -#define n 0xe -int main() -{ - printf("n+1 = %d\n", n+1); -// printf("n+1 = %d\n", 0xe+1); -} diff --git a/tinyc/tests/tests2/84_hex-float.expect b/tinyc/tests/tests2/84_hex-float.expect deleted file mode 100644 index 2175385aa..000000000 --- a/tinyc/tests/tests2/84_hex-float.expect +++ /dev/null @@ -1 +0,0 @@ -n+1 = 15 diff --git a/tinyc/tests/tests2/85_asm-outside-function.c b/tinyc/tests/tests2/85_asm-outside-function.c deleted file mode 100644 index dc5639a46..000000000 --- a/tinyc/tests/tests2/85_asm-outside-function.c +++ /dev/null @@ -1,9 +0,0 @@ -extern int printf (const char *, ...); -extern void vide(void); -__asm__("vide: ret"); - -int main() { - vide(); - printf ("okay\n"); - return 0; -} diff --git a/tinyc/tests/tests2/85_asm-outside-function.expect b/tinyc/tests/tests2/85_asm-outside-function.expect deleted file mode 100644 index dcf02b2fb..000000000 --- a/tinyc/tests/tests2/85_asm-outside-function.expect +++ /dev/null @@ -1 +0,0 @@ -okay diff --git a/tinyc/tests/tests2/86_memory-model.c b/tinyc/tests/tests2/86_memory-model.c deleted file mode 100644 index 744c3e207..000000000 --- a/tinyc/tests/tests2/86_memory-model.c +++ /dev/null @@ -1,38 +0,0 @@ -#include - -int -main() -{ -#if defined(__LLP64__) - if (sizeof(short) == 2 - && sizeof(int) == 4 - && sizeof(long int) == 4 - && sizeof(long long int) == 8 - && sizeof(void*) == 8) { - (void)printf("Ok\n"); - } else { - (void)printf("KO __LLP64__\n"); - } -#elif defined(__LP64__) - if (sizeof(short) == 2 - && sizeof(int) == 4 - && sizeof(long int) == 8 - && sizeof(long long int) == 8 - && sizeof(void*) == 8) { - (void)printf("Ok\n"); - } else { - (void)printf("KO __LP64__\n"); - } -#elif defined(__ILP32__) - if (sizeof(short) == 2 - && sizeof(int) == 4 - && sizeof(long int) == 4 - && sizeof(void*) == 4) { - (void)printf("Ok\n"); - } else { - (void)printf("KO __ILP32__\n"); - } -#else - (void)printf("KO no __*LP*__ defined.\n"); -#endif -} diff --git a/tinyc/tests/tests2/86_memory-model.expect b/tinyc/tests/tests2/86_memory-model.expect deleted file mode 100644 index 7326d9603..000000000 --- a/tinyc/tests/tests2/86_memory-model.expect +++ /dev/null @@ -1 +0,0 @@ -Ok diff --git a/tinyc/tests/tests2/87_dead_code.c b/tinyc/tests/tests2/87_dead_code.c deleted file mode 100644 index 98d4566c5..000000000 --- a/tinyc/tests/tests2/87_dead_code.c +++ /dev/null @@ -1,122 +0,0 @@ -/* This checks various ways of dead code inside if statements - where there are non-obvious ways of how the code is actually - not dead due to reachable by labels. */ -extern int printf (const char *, ...); -static void kb_wait_1(void) -{ - unsigned long timeout = 2; - do { - /* Here the else arm is a statement expression that's supposed - to be suppressed. The label inside the while would unsuppress - code generation again if not handled correctly. And that - would wreak havoc to the cond-expression because there's no - jump-around emitted, the whole statement expression really - needs to not generate code (perhaps except useless forward jumps). */ - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - int i = 1; - while (1) - while (i--) - some_label: - printf("error\n"); - goto some_label; - }) - ); - timeout--; - } while (timeout); -} -int main (void) -{ - int i = 1; - kb_wait_1(); - - /* Simple test of dead code at first sight which isn't actually dead. */ - if (0) { -yeah: - printf ("yeah\n"); - } else { - printf ("boo\n"); - } - if (i--) - goto yeah; - - /* Some more non-obvious uses where the problems are loops, so that even - the first loop statements aren't actually dead. */ - i = 1; - if (0) { - while (i--) { - printf ("once\n"); -enterloop: - printf ("twice\n"); - } - } - if (i >= 0) - goto enterloop; - - /* The same with statement expressions. One might be tempted to - handle them specially by counting if inside statement exprs and - not unsuppressing code at loops at all then. - See kb_wait_1 for the other side of the medal where that wouldn't work. */ - i = ({ - int j = 1; - if (0) { - while (j--) { - printf ("SEonce\n"); - enterexprloop: - printf ("SEtwice\n"); - } - } - if (j >= 0) - goto enterexprloop; - j; }); - - /* The other two loop forms: */ - i = 1; - if (0) { - for (i = 1; i--;) { - printf ("once2\n"); -enterloop2: - printf ("twice2\n"); - } - } - if (i > 0) - goto enterloop2; - - i = 1; - if (0) { - do { - printf ("once3\n"); -enterloop3: - printf ("twice3\n"); - } while (i--); - } - if (i > 0) - goto enterloop3; - - /* And check that case and default labels have the same effect - of disabling code suppression. */ - i = 41; - switch (i) { - if (0) { - printf ("error\n"); - case 42: - printf ("error2\n"); - case 41: - printf ("caseok\n"); - } - } - - i = 41; - switch (i) { - if (0) { - printf ("error3\n"); - default: - printf ("caseok2\n"); - break; - case 42: - printf ("error4\n"); - } - } - return 0; -} diff --git a/tinyc/tests/tests2/87_dead_code.expect b/tinyc/tests/tests2/87_dead_code.expect deleted file mode 100644 index 0b3ec1d9d..000000000 --- a/tinyc/tests/tests2/87_dead_code.expect +++ /dev/null @@ -1,18 +0,0 @@ -timeout=2 -timeout=1 -boo -yeah -twice -once -twice -SEtwice -SEonce -SEtwice -twice2 -once2 -twice2 -twice3 -once3 -twice3 -caseok -caseok2 diff --git a/tinyc/tests/tests2/88_codeopt.c b/tinyc/tests/tests2/88_codeopt.c deleted file mode 100644 index 647626f9e..000000000 --- a/tinyc/tests/tests2/88_codeopt.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Check some way in where code suppression caused various - miscompilations. */ -extern int printf (const char *, ...); -typedef unsigned long size_t; - -size_t _brk_start, _brk_end; -void * extend_brk(size_t size, size_t align) -{ - size_t mask = align - 1; - void *ret = 0; - - do { - if (__builtin_expect(!!(_brk_start == 0), 0)) - do { - printf("wrong1\n"); - } while (0); - } while (0); - _brk_end = (_brk_end + mask) & ~mask; - ret = (void *)_brk_end; - _brk_end += size; - - return ret; -} - -static void get_args (int a, int b) -{ - if (a != 1) - printf("wrong2\n"); - else - printf("okay\n"); -} - -void bla(void) -{ - int __ret = 42; - ({ - if (__builtin_expect(!!(0), 0)) { - if (__builtin_expect(!!__ret, 0)) - printf("wrong3\n"); - int x = !!(__ret); - } - __ret; - }); - get_args(!!__ret, sizeof(__ret)); -} - -_Bool chk(unsigned long addr, unsigned long limit, unsigned long size) -{ - _Bool ret; - /* This just needs to compile, no runtime test. (And it doesn't compile - only with certain internal checking added that's not committed). */ - if (0) - ret = 0 != (!!(addr > limit - size)); -} - -int main() -{ - void *r; - _brk_start = 1024; - _brk_end = 1024; - r = extend_brk (4096, 16); - if (!r) - printf("wrong4\n"); - else - printf("okay\n"); - bla(); - return 0; -} diff --git a/tinyc/tests/tests2/88_codeopt.expect b/tinyc/tests/tests2/88_codeopt.expect deleted file mode 100644 index 439edfd8f..000000000 --- a/tinyc/tests/tests2/88_codeopt.expect +++ /dev/null @@ -1,2 +0,0 @@ -okay -okay diff --git a/tinyc/tests/tests2/89_nocode_wanted.c b/tinyc/tests/tests2/89_nocode_wanted.c deleted file mode 100644 index 73e0a4bc8..000000000 --- a/tinyc/tests/tests2/89_nocode_wanted.c +++ /dev/null @@ -1,112 +0,0 @@ -extern int printf(const char *format, ...); -static void kb_wait_1(void) -{ - unsigned long timeout = 2; - do { - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - while (1) - printf("error\n"); - }) - ); - timeout--; - } while (timeout); -} -static void kb_wait_2(void) -{ - unsigned long timeout = 2; - do { - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - for (;;) - printf("error\n"); - }) - ); - timeout--; - } while (timeout); -} -static void kb_wait_2_1(void) -{ - unsigned long timeout = 2; - do { - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - do { - printf("error\n"); - } while (1); - }) - ); - timeout--; - } while (timeout); -} -static void kb_wait_2_2(void) -{ - unsigned long timeout = 2; - do { - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - label: - printf("error\n"); - goto label; - }) - ); - timeout--; - } while (timeout); -} -static void kb_wait_3(void) -{ - unsigned long timeout = 2; - do { - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - int i = 1; - goto label; - i = i + 2; - label: - i = i + 3; - }) - ); - timeout--; - } while (timeout); -} -static void kb_wait_4(void) -{ - unsigned long timeout = 2; - do { - (1 ? - printf("timeout=%ld\n", timeout) : - ({ - switch(timeout) { - case 2: - printf("timeout is 2"); - break; - case 1: - printf("timeout is 1"); - break; - default: - printf("timeout is 0?"); - break; - }; - // return; - }) - ); - timeout--; - } while (timeout); -} -int main() -{ - printf("begin\n"); - kb_wait_1(); - kb_wait_2(); - kb_wait_2_1(); - kb_wait_2_2(); - kb_wait_3(); - kb_wait_4(); - printf("end\n"); - return 0; -} diff --git a/tinyc/tests/tests2/89_nocode_wanted.expect b/tinyc/tests/tests2/89_nocode_wanted.expect deleted file mode 100644 index c44d4ea6c..000000000 --- a/tinyc/tests/tests2/89_nocode_wanted.expect +++ /dev/null @@ -1,14 +0,0 @@ -begin -timeout=2 -timeout=1 -timeout=2 -timeout=1 -timeout=2 -timeout=1 -timeout=2 -timeout=1 -timeout=2 -timeout=1 -timeout=2 -timeout=1 -end diff --git a/tinyc/tests/tests2/90_struct-init.c b/tinyc/tests/tests2/90_struct-init.c deleted file mode 100644 index d931e2378..000000000 --- a/tinyc/tests/tests2/90_struct-init.c +++ /dev/null @@ -1,282 +0,0 @@ -typedef unsigned char u8; -typedef struct {} empty_s; -struct contains_empty { - u8 a; - empty_s empty; - u8 b; -}; -struct contains_empty ce = { { (1) }, (empty_s){}, 022, }; -/* The following decl of 'q' would demonstrate the TCC bug in init_putv when - handling copying compound literals. (Compound literals - aren't acceptable constant initializers in isoc99, but - we accept them like gcc, except for this case) -//char *q = (char *){ "trara" }; */ -struct SS {u8 a[3], b; }; -struct SS sinit16[] = { { 1 }, 2 }; -struct S -{ - u8 a,b; - u8 c[2]; -}; - -struct T -{ - u8 s[16]; - u8 a; -}; - -struct U -{ - u8 a; - struct S s; - u8 b; - struct T t; -}; - -struct V -{ - struct S s; - struct T t; - u8 a; -}; - -struct W -{ - struct V t; - struct S s[]; -}; - -struct S gs = ((struct S){1, 2, 3, 4}); -struct S gs2 = {1, 2, {3, 4}}; -struct T gt = {"hello", 42}; -struct U gu = {3, 5,6,7,8, 4, "huhu", 43}; -struct U gu2 = {3, {5,6,7,8}, 4, {"huhu", 43}}; -/* Optional braces around scalar initializers. Accepted, but with - a warning. */ -struct U gu3 = { {3}, {5,6,7,8,}, 4, {"huhu", 43}}; -/* Many superfluous braces and leaving out one initializer for U.s.c[1] */ -struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} }; -/* Superfluous braces and useless parens around values */ -struct S gs3 = { (1), {(2)}, {(((3))), {4}}}; -/* Superfluous braces, and leaving out braces for V.t, plus cast */ -struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46}; -/* Compound literal */ -struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48}; -/* Parens around compound literal */ -struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50}; -/* Initialization of a flex array member (warns in GCC) */ -struct W gw = {{1,2,3,4}, {1,2,3,4,5}}; - -union UU { - u8 a; - u8 b; -}; -struct SU { - union UU u; - u8 c; -}; -struct SU gsu = {5,6}; - -/* Unnamed struct/union members aren't ISO C, but it's a widely accepted - extension. See below for further extensions to that under -fms-extension.*/ -union UV { - struct {u8 a,b;}; - struct S s; -}; -union UV guv = {{6,5}}; -union UV guv2 = {{.b = 7, .a = 8}}; -union UV guv3 = {.b = 8, .a = 7}; - -/* Under -fms-extensions also the following is valid: -union UV2 { - struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ... - struct S s; -}; -struct Anon gan = { 10, 11 }; // ... which makes it available here. -union UV2 guv4 = {{4,3}}; // and the other inits from above as well -*/ - -struct in6_addr { - union { - u8 u6_addr8[16]; - unsigned short u6_addr16[8]; - } u; -}; -struct flowi6 { - struct in6_addr saddr, daddr; -}; -struct pkthdr { - struct in6_addr daddr, saddr; -}; -struct pkthdr phdr = { { { 6,5,4,3 } }, { { 9,8,7,6 } } }; - -struct Wrap { - void *func; -}; -int global; -void inc_global (void) -{ - global++; -} - -struct Wrap global_wrap[] = { - ((struct Wrap) {inc_global}), - inc_global, -}; - -#include -void print_ (const char *name, const u8 *p, long size) -{ - printf ("%s:", name); - while (size--) { - printf (" %x", *p++); - } - printf ("\n"); -} -#define print(x) print_(#x, (u8*)&x, sizeof (x)) -#if 1 -void foo (struct W *w, struct pkthdr *phdr_) -{ - struct S ls = {1, 2, 3, 4}; - struct S ls2 = {1, 2, {3, 4}}; - struct T lt = {"hello", 42}; - struct U lu = {3, 5,6,7,8, 4, "huhu", 43}; - struct U lu1 = {3, ls, 4, {"huhu", 43}}; - struct U lu2 = {3, (ls), 4, {"huhu", 43}}; - const struct S *pls = &ls; - struct S ls21 = *pls; - struct U lu22 = {3, *pls, 4, {"huhu", 43}}; - /* Incomplete bracing. */ - struct U lu21 = {3, ls, 4, "huhu", 43}; - /* Optional braces around scalar initializers. Accepted, but with - a warning. */ - struct U lu3 = { 3, {5,6,7,8,}, 4, {"huhu", 43}}; - /* Many superfluous braces and leaving out one initializer for U.s.c[1] */ - struct U lu4 = { 3, {5,6,7,}, 5, { "bla", 44} }; - /* Superfluous braces and useless parens around values */ - struct S ls3 = { (1), (2), {(((3))), 4}}; - /* Superfluous braces, and leaving out braces for V.t, plus cast */ - struct V lv = {{3,4,{5,6}}, "haha", (u8)45, 46}; - /* Compound literal */ - struct V lv2 = {(struct S)w->t.s, {"hihi", 47}, 48}; - /* Parens around compound literal */ - struct V lv3 = {((struct S){7,8,{9,10}}), ((const struct W *)w)->t.t, 50}; - const struct pkthdr *phdr = phdr_; - struct flowi6 flow = { .daddr = phdr->daddr, .saddr = phdr->saddr }; - int elt = 0x42; - /* Range init, overlapping */ - struct T lt2 = { { [1 ... 5] = 9, [6 ... 10] = elt, [4 ... 7] = elt+1 }, 1 }; - print(ls); - print(ls2); - print(lt); - print(lu); - print(lu1); - print(lu2); - print(ls21); - print(lu21); - print(lu22); - print(lu3); - print(lu4); - print(ls3); - print(lv); - print(lv2); - print(lv3); - print(lt2); - print(flow); -} -#endif - -void test_compound_with_relocs (void) -{ - struct Wrap local_wrap[] = { - ((struct Wrap) {inc_global}), - inc_global, - }; - void (*p)(void); - p = global_wrap[0].func; p(); - p = global_wrap[1].func; p(); - p = local_wrap[0].func; p(); - p = local_wrap[1].func; p(); -} - -void sys_ni(void) { printf("ni\n"); } -void sys_one(void) { printf("one\n"); } -void sys_two(void) { printf("two\n"); } -void sys_three(void) { printf("three\n"); } -typedef void (*fptr)(void); -const fptr table[3] = { - [0 ... 2] = &sys_ni, - [0] = sys_one, - [1] = sys_two, - [2] = sys_three, -}; - -void test_multi_relocs(void) -{ - int i; - for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) - table[i](); -} - -/* Following is from GCC gcc.c-torture/execute/20050613-1.c. */ - -struct SEA { int i; int j; int k; int l; }; -struct SEB { struct SEA a; int r[1]; }; -struct SEC { struct SEA a; int r[0]; }; -struct SED { struct SEA a; int r[]; }; - -static void -test_correct_filling (struct SEA *x) -{ - static int i; - if (x->i != 0 || x->j != 5 || x->k != 0 || x->l != 0) - printf("sea_fill%d: wrong\n", i); - else - printf("sea_fill%d: okay\n", i); - i++; -} - -int -test_zero_init (void) -{ - /* The peculiarity here is that only a.j is initialized. That - means that all other members must be zero initialized. TCC - once didn't do that for sub-level designators. */ - struct SEB b = { .a.j = 5 }; - struct SEC c = { .a.j = 5 }; - struct SED d = { .a.j = 5 }; - test_correct_filling (&b.a); - test_correct_filling (&c.a); - test_correct_filling (&d.a); - return 0; -} - -int main() -{ - print(ce); - print(gs); - print(gs2); - print(gt); - print(gu); - print(gu2); - print(gu3); - print(gu4); - print(gs3); - print(gv); - print(gv2); - print(gv3); - print(sinit16); - print(gw); - print(gsu); - print(guv); - print(guv.b); - print(guv2); - print(guv3); - print(phdr); - foo(&gw, &phdr); - //printf("q: %s\n", q); - test_compound_with_relocs(); - test_multi_relocs(); - test_zero_init(); - return 0; -} diff --git a/tinyc/tests/tests2/90_struct-init.expect b/tinyc/tests/tests2/90_struct-init.expect deleted file mode 100644 index e366121a5..000000000 --- a/tinyc/tests/tests2/90_struct-init.expect +++ /dev/null @@ -1,43 +0,0 @@ -ce: 1 12 -gs: 1 2 3 4 -gs2: 1 2 3 4 -gt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a -gu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -gu2: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -gu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -gu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c -gs3: 1 2 3 4 -gv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e -gv2: 7 8 9 a 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30 -gv3: 7 8 9 a 68 6f 68 6f 0 0 0 0 0 0 0 0 0 0 0 0 31 32 -sinit16: 1 0 0 0 2 0 0 0 -gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -gsu: 5 6 -guv: 6 5 0 0 -guv.b: 5 -guv2: 8 7 0 0 -guv3: 7 8 0 0 -phdr: 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 -ls: 1 2 3 4 -ls2: 1 2 3 4 -lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a -lu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -lu1: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -lu2: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -ls21: 1 2 3 4 -lu21: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -lu22: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -lu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b -lu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c -ls3: 1 2 3 4 -lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e -lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30 -lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 -lt2: 0 9 9 9 43 43 43 43 42 42 42 0 0 0 0 0 1 -flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 -one -two -three -sea_fill0: okay -sea_fill1: okay -sea_fill2: okay diff --git a/tinyc/tests/tests2/91_ptr_longlong_arith32.c b/tinyc/tests/tests2/91_ptr_longlong_arith32.c deleted file mode 100644 index bf07915ab..000000000 --- a/tinyc/tests/tests2/91_ptr_longlong_arith32.c +++ /dev/null @@ -1,15 +0,0 @@ -int printf(const char *, ...); -char t[] = "012345678"; - -int main(void) -{ - char *data = t; - unsigned long long r = 4; - unsigned a = 5; - unsigned long long b = 12; - - *(unsigned*)(data + r) += a - b; - - printf("data = \"%s\"\n", data); - return 0; -} diff --git a/tinyc/tests/tests2/91_ptr_longlong_arith32.expect b/tinyc/tests/tests2/91_ptr_longlong_arith32.expect deleted file mode 100644 index f91e4b420..000000000 --- a/tinyc/tests/tests2/91_ptr_longlong_arith32.expect +++ /dev/null @@ -1 +0,0 @@ -data = "0123-5678" diff --git a/tinyc/tests/tests2/92_enum_bitfield.c b/tinyc/tests/tests2/92_enum_bitfield.c deleted file mode 100644 index bb6dc35d2..000000000 --- a/tinyc/tests/tests2/92_enum_bitfield.c +++ /dev/null @@ -1,57 +0,0 @@ -/* This checks if enums needing 8 bit but only having positive - values are correctly zero extended (instead of sign extended) - when stored into/loaded from a 8 bit bit-field of enum type (which - itself is implementation defined, so isn't necessarily supported by all - other compilers). */ -enum tree_code { - SOME_CODE = 148, /* has bit 7 set, and hence all further enum values as well */ - LAST_AND_UNUSED_TREE_CODE -}; -typedef union tree_node *tree; -struct tree_common -{ - union tree_node *chain; - union tree_node *type; - enum tree_code code : 8; - unsigned side_effects_flag : 1; -}; -union tree_node -{ - struct tree_common common; - }; -enum c_tree_code { - C_DUMMY_TREE_CODE = LAST_AND_UNUSED_TREE_CODE, - STMT_EXPR, - LAST_C_TREE_CODE -}; -enum cplus_tree_code { - CP_DUMMY_TREE_CODE = LAST_C_TREE_CODE, - AMBIG_CONV, - LAST_CPLUS_TREE_CODE -}; - -extern int printf(const char *, ...); -int blah(){return 0;} - -int convert_like_real (tree convs) -{ - switch (((enum tree_code) (convs)->common.code)) - { - case AMBIG_CONV: /* This has bit 7 set, which must not be the sign - bit in tree_common.code, i.e. the bitfield must - be somehow marked unsigned. */ - return blah(); - default: - break; - }; - printf("unsigned enum bit-fields broken\n"); -} - -int main() -{ - union tree_node convs; - - convs.common.code = AMBIG_CONV; - convert_like_real (&convs); - return 0; -} diff --git a/tinyc/tests/tests2/92_enum_bitfield.expect b/tinyc/tests/tests2/92_enum_bitfield.expect deleted file mode 100644 index e69de29bb..000000000 diff --git a/tinyc/tests/tests2/93_integer_promotion.c b/tinyc/tests/tests2/93_integer_promotion.c deleted file mode 100644 index a1176fc6b..000000000 --- a/tinyc/tests/tests2/93_integer_promotion.c +++ /dev/null @@ -1,71 +0,0 @@ -/* integer promotion */ - -int printf(const char*, ...); -#define promote(s) printf(" %ssigned : %s\n", (s) - 100 < 0 ? " " : "un", #s); - -int main (void) -{ - struct { - unsigned ub:3; - unsigned u:32; - unsigned long long ullb:35; - unsigned long long ull:64; - unsigned char c; - } s = { 1, 1, 1 }; - - promote(s.ub); - promote(s.u); - promote(s.ullb); - promote(s.ull); - promote(s.c); - printf("\n"); - - promote((1 ? s.ub : 1)); - promote((1 ? s.u : 1)); - promote((1 ? s.ullb : 1)); - promote((1 ? s.ull : 1)); - promote((1 ? s.c : 1)); - printf("\n"); - - promote(s.ub << 1); - promote(s.u << 1); - promote(s.ullb << 1); - promote(s.ull << 1); - promote(s.c << 1); - printf("\n"); - - promote(+s.ub); - promote(+s.u); - promote(+s.ullb); - promote(+s.ull); - promote(+s.c); - printf("\n"); - - promote(-s.ub); - promote(-s.u); - promote(-s.ullb); - promote(-s.ull); - promote(-s.c); - printf("\n"); - - promote(~s.ub); - promote(~s.u); - promote(~s.ullb); - promote(~s.ull); - promote(~s.c); - printf("\n"); - - promote(!s.ub); - promote(!s.u); - promote(!s.ullb); - promote(!s.ull); - promote(!s.c); - printf("\n"); - - promote(+(unsigned)s.ub); - promote(-(unsigned)s.ub); - promote(~(unsigned)s.ub); - promote(!(unsigned)s.ub); - - return 0; -} diff --git a/tinyc/tests/tests2/93_integer_promotion.expect b/tinyc/tests/tests2/93_integer_promotion.expect deleted file mode 100644 index 34b9c145c..000000000 --- a/tinyc/tests/tests2/93_integer_promotion.expect +++ /dev/null @@ -1,46 +0,0 @@ - signed : s.ub - unsigned : s.u - signed : s.ullb - unsigned : s.ull - signed : s.c - - signed : (1 ? s.ub : 1) - unsigned : (1 ? s.u : 1) - signed : (1 ? s.ullb : 1) - unsigned : (1 ? s.ull : 1) - signed : (1 ? s.c : 1) - - signed : s.ub << 1 - unsigned : s.u << 1 - signed : s.ullb << 1 - unsigned : s.ull << 1 - signed : s.c << 1 - - signed : +s.ub - unsigned : +s.u - signed : +s.ullb - unsigned : +s.ull - signed : +s.c - - signed : -s.ub - unsigned : -s.u - signed : -s.ullb - unsigned : -s.ull - signed : -s.c - - signed : ~s.ub - unsigned : ~s.u - signed : ~s.ullb - unsigned : ~s.ull - signed : ~s.c - - signed : !s.ub - signed : !s.u - signed : !s.ullb - signed : !s.ull - signed : !s.c - - unsigned : +(unsigned)s.ub - unsigned : -(unsigned)s.ub - unsigned : ~(unsigned)s.ub - signed : !(unsigned)s.ub diff --git a/tinyc/tests/tests2/94_generic.c b/tinyc/tests/tests2/94_generic.c deleted file mode 100644 index d7fb5fc3b..000000000 --- a/tinyc/tests/tests2/94_generic.c +++ /dev/null @@ -1,64 +0,0 @@ -#include - -const int a = 0; - -struct a { - int a; -}; - -struct b { - int a; -}; - -int a_f() -{ - return 20; -} - -int b_f() -{ - return 10; -} - -typedef int int_type1; - -#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123); - -int main() -{ - int i = 0; - signed long int l = 2; - struct b titi; - const int * const ptr; - const char *ti; - int_type1 i2; - - i = _Generic(a, int: a_f, const int: b_f)(); - printf("%d\n", i); - i = _Generic(a, int: a_f() / 2, const int: b_f() / 2); - printf("%d\n", i); - i = _Generic(ptr, int *:1, int * const:2, default:20); - printf("%d\n", i); - i = gen_sw(a); - printf("%d\n", i); - i = _Generic(titi, struct a:1, struct b:2, default:20); - printf("%d\n", i); - i = _Generic(i2, char: 1, int : 0); - printf("%d\n", i); - i = _Generic(a, char:1, int[4]:2, default:5); - printf("%d\n", i); - i = _Generic(17, int :1, int **:2); - printf("%d\n", i); - i = _Generic(17L, int :1, long :2, long long : 3); - printf("%d\n", i); - i = _Generic("17, io", char *: 3, const char *: 1); - printf("%d\n", i); - i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3, - const signed char *:2); - printf("%d\n", i); - printf("%s\n", _Generic(i + 2L, long: "long", int: "int", - long long: "long long")); - i = _Generic(l, long: 1, int: 2); - printf("%d\n", i); - return 0; -} diff --git a/tinyc/tests/tests2/94_generic.expect b/tinyc/tests/tests2/94_generic.expect deleted file mode 100644 index 9aa927530..000000000 --- a/tinyc/tests/tests2/94_generic.expect +++ /dev/null @@ -1,13 +0,0 @@ -20 -10 -20 -123 -2 -0 -5 -1 -2 -3 -4 -long -1 \ No newline at end of file diff --git a/tinyc/tests/tests2/95_bitfields.c b/tinyc/tests/tests2/95_bitfields.c deleted file mode 100644 index f025c575d..000000000 --- a/tinyc/tests/tests2/95_bitfields.c +++ /dev/null @@ -1,218 +0,0 @@ -/* ----------------------------------------------------------------------- */ -#if TEST == 1 -{ - struct M P A __s - { - unsigned x : 12; - unsigned char y : 7; - unsigned z : 28; - unsigned a: 4; - unsigned b: 5; - }; - TEST_STRUCT(0x333,0x44,0x555555,6,7); -} - -/* ----------------------------------------------------------------------- */ -#elif TEST == 2 -{ - struct M P __s - { - int x: 12; - char y: 6; - long long z:63; - A char a:4; - long long b:2; - - }; - TEST_STRUCT(3,30,0x123456789abcdef0LL,5,2); -} - -/* ----------------------------------------------------------------------- */ -#elif TEST == 3 -{ - struct M P __s - { - unsigned x:5, y:5, :0, z:5; char a:5; A short b:5; - }; - TEST_STRUCT(21,23,25,6,14); -} - -/* ----------------------------------------------------------------------- */ -#elif TEST == 4 -{ - struct M P __s { - int x : 3; - int : 2; - int y : 1; - int : 0; - int z : 5; - int a : 7; - unsigned int b : 7; - }; - TEST_STRUCT(3,1,15,120,120); -} - -/* ----------------------------------------------------------------------- */ -#elif TEST == 5 -{ - struct M P __s { - long long x : 45; - long long : 2; - long long y : 30; - unsigned long long z : 38; - char a; short b; - }; - TEST_STRUCT(0x123456789ULL, 120<<25, 120, 0x44, 0x77); -} - -/* ----------------------------------------------------------------------- */ -#elif TEST == 6 -{ - struct M P __s { - int a; - signed char b; - int x : 12, y : 4, : 0, : 4, z : 3; - char d; - }; - TEST_STRUCT(1,2,3,4,-3); -} - -/* ----------------------------------------------------------------------- */ -#elif defined PACK - -#if PACK -# pragma pack(push,1) -# define P //_P -#else -# define P -#endif - -printf("\n\n" + 2*top); -#define TEST 1 -#include SELF -top = 0; -#define TEST 2 -#include SELF -#define TEST 3 -#include SELF -#define TEST 4 -#include SELF -#define TEST 5 -#include SELF -#define TEST 6 -#include SELF - -#if PACK -# pragma pack(pop) -#endif - -#undef P -#undef PACK - -/* ----------------------------------------------------------------------- */ -#elif defined ALIGN - -#if ALIGN -# define A _A(16) -#else -# define A -#endif - -#define PACK 0 -#include SELF -#define PACK 1 -#include SELF - -#undef A -#undef ALIGN - -/* ----------------------------------------------------------------------- */ -#elif defined MS_BF - -#if MS_BF -# ifdef __TINYC__ -# pragma comment(option, "-mms-bitfields") -# elif defined __GNUC__ -# define M __attribute__((ms_struct)) -# endif -#else -# ifdef __TINYC__ -# pragma comment(option, "-mno-ms-bitfields") -# elif defined __GNUC__ -# define M __attribute__((gcc_struct)) -# endif -#endif -#ifndef M -# define M -#endif - -#define ALIGN 0 -#include SELF -#define ALIGN 1 -#include SELF - -#undef M -#undef MS_BF - -/* ----------------------------------------------------------------------- */ -#else - -#include -#include -/* some gcc headers #define __attribute__ to empty if it's not gcc */ -#undef __attribute__ - -void dump(void *p, int s) -{ - int i; - for (i = s; --i >= 0;) - printf("%02X", ((unsigned char*)p)[i]); - printf("\n"); -} - -#define pv(m) \ - printf(sizeof (s->m + 0) == 8 ? " %016llx" : " %02x", s->m) - -#define TEST_STRUCT(v1,v2,v3,v4,v5) { \ - struct __s _s, *s = & _s; \ - printf("\n---- TEST %d%s%s%s ----\n" + top, \ - TEST, MS_BF?" - MS-BITFIELDS":"", \ - PACK?" - PACKED":"", \ - ALIGN?" - WITH ALIGN":""); \ - memset(s, 0, sizeof *s); \ - s->x = -1, s->y = -1, s->z = -1, s->a = -1, s->b = -1; \ - printf("bits in use : "), dump(s, sizeof *s); \ - s->x = v1, s->y = v2, s->z = v3, s->a += v4, ++s->a, s->b = v5; \ - printf("bits as set : "), dump(s, sizeof *s); \ - printf("values :"), pv(x), pv(y), pv(z), pv(a), pv(b), printf("\n"); \ - printf("align/size : %d %d\n", alignof(struct __s),sizeof(struct __s)); \ - } - -#ifdef _MSC_VER -# define _A(n) __declspec(align(n)) -# define _P -# define alignof(x) __alignof(x) -#else -# define _A(n) __attribute__((aligned(n))) -# define _P __attribute__((packed)) -# define alignof(x) __alignof__(x) -#endif - -#ifndef MS_BITFIELDS -# define MS_BITFIELDS 0 -#endif - -#define SELF "95_bitfields.c" - -int top = 1; - -int main() -{ -#define MS_BF MS_BITFIELDS -#include SELF - return 0; -} - -/* ----------------------------------------------------------------------- */ -#endif -#undef TEST diff --git a/tinyc/tests/tests2/95_bitfields.expect b/tinyc/tests/tests2/95_bitfields.expect deleted file mode 100644 index 6a8fd9abd..000000000 --- a/tinyc/tests/tests2/95_bitfields.expect +++ /dev/null @@ -1,149 +0,0 @@ ----- TEST 1 ---- -bits in use : 0000001FFFFFFFFF007F0FFF -bits as set : 000000076055555500440333 -values : 333 44 555555 06 07 -align/size : 4 12 - ----- TEST 2 ---- -bits in use : 000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF -bits as set : 0000000000000025123456789ABCDEF000000000001E0003 -values : 03 1e 123456789abcdef0 05 fffffffe -align/size : 8 24 - ----- TEST 3 ---- -bits in use : 001F1F1F000003FF -bits as set : 000E0619000002F5 -values : 15 17 19 06 0e -align/size : 4 8 - ----- TEST 4 ---- -bits in use : 0007FFFF00000027 -bits as set : 00078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 4 8 - ----- TEST 5 ---- -bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF -bits as set : 007744000000007800000000300000000000000123456789 -values : 0000000123456789 f0000000 0000000000000078 44 77 -align/size : 8 24 - ----- TEST 6 ---- -bits in use : 0000007000FFFFFFFFFFFFFF -bits as set : 00000030002001FD00000004 -values : 01 02 03 04 fffffffd -align/size : 4 12 - - - ----- TEST 1 - PACKED ---- -bits in use : FFFFFFFFFFFFFF -bits as set : 3B02AAAAAC4333 -values : 333 44 555555 06 07 -align/size : 1 7 - ----- TEST 2 - PACKED ---- -bits in use : 7FFFFFFFFFFFFFFFFFFFFF -bits as set : 4A48D159E26AF37BC1E003 -values : 03 1e 123456789abcdef0 05 fffffffe -align/size : 1 11 - ----- TEST 3 - PACKED ---- -bits in use : 7FFF000003FF -bits as set : 38D9000002F5 -values : 15 17 19 06 0e -align/size : 1 6 - ----- TEST 4 - PACKED ---- -bits in use : 07FFFF00000027 -bits as set : 078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 1 7 - ----- TEST 5 - PACKED ---- -bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF -bits as set : 007744000000000F18000000000123456789 -values : 0000000123456789 f0000000 0000000000000078 44 77 -align/size : 1 18 - ----- TEST 6 - PACKED ---- -bits in use : 007000FFFFFFFFFFFFFF -bits as set : 0030002001FD00000004 -values : 01 02 03 04 fffffffd -align/size : 1 10 - - - ----- TEST 1 - WITH ALIGN ---- -bits in use : 000000000000001FFFFFFFFF007F0FFF -bits as set : 00000000000000076055555500440333 -values : 333 44 555555 06 07 -align/size : 16 16 - ----- TEST 2 - WITH ALIGN ---- -bits in use : 0000000000000000000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF -bits as set : 00000000000000000000000000000025123456789ABCDEF000000000001E0003 -values : 03 1e 123456789abcdef0 05 fffffffe -align/size : 16 32 - ----- TEST 3 - WITH ALIGN ---- -bits in use : 0000000000000000000000000000001F000000000000000000001F1F000003FF -bits as set : 0000000000000000000000000000000E000000000000000000000619000002F5 -values : 15 17 19 06 0e -align/size : 16 32 - ----- TEST 4 - WITH ALIGN ---- -bits in use : 0007FFFF00000027 -bits as set : 00078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 4 8 - ----- TEST 5 - WITH ALIGN ---- -bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF -bits as set : 007744000000007800000000300000000000000123456789 -values : 0000000123456789 f0000000 0000000000000078 44 77 -align/size : 8 24 - ----- TEST 6 - WITH ALIGN ---- -bits in use : 0000007000FFFFFFFFFFFFFF -bits as set : 00000030002001FD00000004 -values : 01 02 03 04 fffffffd -align/size : 4 12 - - - ----- TEST 1 - PACKED - WITH ALIGN ---- -bits in use : 000000000000000000FFFFFFFFFFFFFF -bits as set : 0000000000000000003B02AAAAAC4333 -values : 333 44 555555 06 07 -align/size : 16 16 - ----- TEST 2 - PACKED - WITH ALIGN ---- -bits in use : 3F01FFFFFFFFFFFFFFFFFFFF -bits as set : 250048D159E26AF37BC1E003 -values : 03 1e 123456789abcdef0 05 fffffffe -align/size : 1 12 - ----- TEST 3 - PACKED - WITH ALIGN ---- -bits in use : 1F03FF000003FF -bits as set : 0E00D9000002F5 -values : 15 17 19 06 0e -align/size : 1 7 - ----- TEST 4 - PACKED - WITH ALIGN ---- -bits in use : 07FFFF00000027 -bits as set : 078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 1 7 - ----- TEST 5 - PACKED - WITH ALIGN ---- -bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF -bits as set : 007744000000000F18000000000123456789 -values : 0000000123456789 f0000000 0000000000000078 44 77 -align/size : 1 18 - ----- TEST 6 - PACKED - WITH ALIGN ---- -bits in use : 007000FFFFFFFFFFFFFF -bits as set : 0030002001FD00000004 -values : 01 02 03 04 fffffffd -align/size : 1 10 diff --git a/tinyc/tests/tests2/95_bitfields_ms.c b/tinyc/tests/tests2/95_bitfields_ms.c deleted file mode 100644 index b196fbd66..000000000 --- a/tinyc/tests/tests2/95_bitfields_ms.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MS_BITFIELDS 1 -#include "95_bitfields.c" diff --git a/tinyc/tests/tests2/95_bitfields_ms.expect b/tinyc/tests/tests2/95_bitfields_ms.expect deleted file mode 100644 index 8ccafb78d..000000000 --- a/tinyc/tests/tests2/95_bitfields_ms.expect +++ /dev/null @@ -1,149 +0,0 @@ ----- TEST 1 - MS-BITFIELDS ---- -bits in use : 0000001FFFFFFFFF0000007F00000FFF -bits as set : 00000007605555550000004400000333 -values : 333 44 555555 06 07 -align/size : 4 16 - ----- TEST 2 - MS-BITFIELDS ---- -bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF -bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003 -values : 03 1e 123456789abcdef0 05 fffffffffffffffe -align/size : 8 32 - ----- TEST 3 - MS-BITFIELDS ---- -bits in use : 001F001F0000001F000003FF -bits as set : 000E000600000019000002F5 -values : 15 17 19 06 0e -align/size : 4 12 - ----- TEST 4 - MS-BITFIELDS ---- -bits in use : 0007FFFF00000027 -bits as set : 00078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 4 8 - ----- TEST 5 - MS-BITFIELDS ---- -bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF -bits as set : 0000000000770044000000000000007800000000300000000000000123456789 -values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 -align/size : 8 32 - ----- TEST 6 - MS-BITFIELDS ---- -bits in use : 00000000000000700000FFFF000000FFFFFFFFFF -bits as set : 000000000000003000002001000000FD00000004 -values : 01 02 03 04 fffffffd -align/size : 4 20 - - - ----- TEST 1 - MS-BITFIELDS - PACKED ---- -bits in use : 0000001FFFFFFFFF7F00000FFF -bits as set : 00000007605555554400000333 -values : 333 44 555555 06 07 -align/size : 1 13 - ----- TEST 2 - MS-BITFIELDS - PACKED ---- -bits in use : 00000000000000030F7FFFFFFFFFFFFFFF3F00000FFF -bits as set : 000000000000000205123456789ABCDEF01E00000003 -values : 03 1e 123456789abcdef0 05 fffffffffffffffe -align/size : 1 22 - ----- TEST 3 - MS-BITFIELDS - PACKED ---- -bits in use : 001F1F0000001F000003FF -bits as set : 000E0600000019000002F5 -values : 15 17 19 06 0e -align/size : 1 11 - ----- TEST 4 - MS-BITFIELDS - PACKED ---- -bits in use : 0007FFFF00000027 -bits as set : 00078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 1 8 - ----- TEST 5 - MS-BITFIELDS - PACKED ---- -bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF -bits as set : 007744000000000000007800000000300000000000000123456789 -values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 -align/size : 1 27 - ----- TEST 6 - MS-BITFIELDS - PACKED ---- -bits in use : 00000000700000FFFFFFFFFFFFFF -bits as set : 000000003000002001FD00000004 -values : 01 02 03 04 fffffffd -align/size : 1 14 - - - ----- TEST 1 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 0000001FFFFFFFFF0000007F00000FFF -bits as set : 00000007605555550000004400000333 -values : 333 44 555555 06 07 -align/size : 16 16 - ----- TEST 2 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF -bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003 -values : 03 1e 123456789abcdef0 05 fffffffffffffffe -align/size : 16 32 - ----- TEST 3 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 0000000000000000000000000000001F000000000000001F0000001F000003FF -bits as set : 0000000000000000000000000000000E000000000000000600000019000002F5 -values : 15 17 19 06 0e -align/size : 16 32 - ----- TEST 4 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 0007FFFF00000027 -bits as set : 00078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 4 8 - ----- TEST 5 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF -bits as set : 0000000000770044000000000000007800000000300000000000000123456789 -values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 -align/size : 8 32 - ----- TEST 6 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 00000000000000700000FFFF000000FFFFFFFFFF -bits as set : 000000000000003000002001000000FD00000004 -values : 01 02 03 04 fffffffd -align/size : 4 20 - - - ----- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : 0000000000001FFFFFFFFF7F00000FFF -bits as set : 00000000000007605555554400000333 -values : 333 44 555555 06 07 -align/size : 16 16 - ----- TEST 2 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : 00000000000000030F0000007FFFFFFFFFFFFFFF3F00000FFF -bits as set : 000000000000000205000000123456789ABCDEF01E00000003 -values : 03 1e 123456789abcdef0 05 fffffffffffffffe -align/size : 16 25 - ----- TEST 3 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : 001F000000000000001F0000001F000003FF -bits as set : 000E000000000000000600000019000002F5 -values : 15 17 19 06 0e -align/size : 16 18 - ----- TEST 4 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : 0007FFFF00000027 -bits as set : 00078F0F00000023 -values : 03 ffffffff 0f fffffff8 78 -align/size : 1 8 - ----- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF -bits as set : 007744000000000000007800000000300000000000000123456789 -values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 -align/size : 1 27 - ----- TEST 6 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : 00000000700000FFFFFFFFFFFFFF -bits as set : 000000003000002001FD00000004 -values : 01 02 03 04 fffffffd -align/size : 1 14 diff --git a/tinyc/tests/tests2/96_nodata_wanted.c b/tinyc/tests/tests2/96_nodata_wanted.c deleted file mode 100644 index cc211d36b..000000000 --- a/tinyc/tests/tests2/96_nodata_wanted.c +++ /dev/null @@ -1,84 +0,0 @@ -/*****************************************************************************/ -/* test 'nodata_wanted' data output suppression */ - -#if defined test_static_data_error -void foo() { - if (1) { - static short w = (int)&foo; /* initializer not computable */ - } -} - -#elif defined test_static_nodata_error -void foo() { - if (0) { - static short w = (int)&foo; /* initializer not computable */ - } -} - -#elif defined test_global_data_error -void foo(); -static short w = (int)&foo; /* initializer not computable */ - - -#elif defined test_local_data_noerror -void foo() { - short w = &foo; /* 2 cast warnings */ -} - -#elif defined test_data_suppression_off || defined test_data_suppression_on - -#if defined test_data_suppression_on -# define SKIP 1 -#else -# define SKIP 0 -#endif - -#include -/* some gcc headers #define __attribute__ to empty if it's not gcc */ -#undef __attribute__ - -int main() -{ - __label__ ts0, te0, ts1, te1; - int tl, dl; - - static char ds0 = 0; - static char de0 = 0; - /* get reference size of empty jmp */ -ts0:; - if (!SKIP) {} -te0:; - dl = -(&de0 - &ds0); - tl = -(&&te0 - &&ts0); - - /* test data and code suppression */ - static char ds1 = 0; -ts1:; - if (!SKIP) { - static void *p = (void*)&main; - static char cc[] = "static string"; - static double d = 8.0; - - static struct __attribute__((packed)) { - unsigned x : 12; - unsigned char y : 7; - unsigned z : 28, a: 4, b: 5; - } s = { 0x333,0x44,0x555555,6,7 }; - - printf("data:\n"); - printf(" %d - %.1f - %.1f - %s - %s\n", - sizeof 8.0, 8.0, d, __FUNCTION__, cc); - printf(" %x %x %x %x %x\n", - s.x, s.y, s.z, s.a, s.b); - } -te1:; - static char de1 = 0; - - dl += &de1 - &ds1; - tl += &&te1 - &&ts1; - printf("size of data/text:\n %s/%s\n", - dl ? "non-zero":"zero", tl ? "non-zero":"zero"); - /*printf("# %d/%d\n", dl, tl);*/ -} - -#endif diff --git a/tinyc/tests/tests2/96_nodata_wanted.expect b/tinyc/tests/tests2/96_nodata_wanted.expect deleted file mode 100644 index 2749109a0..000000000 --- a/tinyc/tests/tests2/96_nodata_wanted.expect +++ /dev/null @@ -1,23 +0,0 @@ -[test_static_data_error] -96_nodata_wanted.c:7: error: initializer element is not computable at load time - -[test_static_nodata_error] -96_nodata_wanted.c:14: error: initializer element is not computable at load time - -[test_global_data_error] -96_nodata_wanted.c:20: error: initializer element is not computable at load time - -[test_local_data_noerror] -96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast -96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short - -[test_data_suppression_off] -data: - 8 - 8.0 - 8.0 - main - static string - 333 44 555555 6 7 -size of data/text: - non-zero/non-zero - -[test_data_suppression_on] -size of data/text: - zero/zero diff --git a/tinyc/tests/tests2/97_utf8_string_literal.c b/tinyc/tests/tests2/97_utf8_string_literal.c deleted file mode 100644 index 96fbab0d1..000000000 --- a/tinyc/tests/tests2/97_utf8_string_literal.c +++ /dev/null @@ -1,12 +0,0 @@ -// this file contains BMP chars encoded in UTF-8 -#include -#include - -int main() -{ - wchar_t s[] = L"hello$$你好¢¢世界€€world"; - wchar_t *p; - for (p = s; *p; p++) printf("%04X ", (unsigned) *p); - printf("\n"); - return 0; -} diff --git a/tinyc/tests/tests2/97_utf8_string_literal.expect b/tinyc/tests/tests2/97_utf8_string_literal.expect deleted file mode 100644 index 9a1593cdd..000000000 --- a/tinyc/tests/tests2/97_utf8_string_literal.expect +++ /dev/null @@ -1 +0,0 @@ -0068 0065 006C 006C 006F 0024 0024 4F60 597D 00A2 00A2 4E16 754C 20AC 20AC 0077 006F 0072 006C 0064 diff --git a/tinyc/tests/tests2/98_al_ax_extend.c b/tinyc/tests/tests2/98_al_ax_extend.c deleted file mode 100644 index 9b4e02fe7..000000000 --- a/tinyc/tests/tests2/98_al_ax_extend.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -asm ( - ".text;" - ".globl _us;.globl _ss;.globl _uc;.globl _sc;" - "_us:;_ss:;_uc:;_sc:;" - "movl $0x1234ABCD, %eax;" - "ret;" -); - -#if 1 -#define us _us -#define ss _ss -#define uc _uc -#define sc _sc -#endif - -int main() -{ - unsigned short us(void); - short ss(void); - unsigned char uc(void); - signed char sc(void); - - unsigned short (*fpus)(void) = us; - short (*fpss)(void) = ss; - unsigned char (*fpuc)(void) = uc; - signed char (*fpsc)(void) = sc; - - printf("%08X %08X\n", us() + 1, fpus() + 1); - printf("%08X %08X\n", ss() + 1, fpss() + 1); - printf("%08X %08X\n", uc() + 1, fpuc() + 1); - printf("%08X %08X\n", sc() + 1, fpsc() + 1); - printf("\n"); - printf("%08X %08X\n", fpus() + 1, us() + 1); - printf("%08X %08X\n", fpss() + 1, ss() + 1); - printf("%08X %08X\n", fpuc() + 1, uc() + 1); - printf("%08X %08X\n", fpsc() + 1, sc() + 1); - - return 0; -} diff --git a/tinyc/tests/tests2/98_al_ax_extend.expect b/tinyc/tests/tests2/98_al_ax_extend.expect deleted file mode 100644 index c5752e843..000000000 --- a/tinyc/tests/tests2/98_al_ax_extend.expect +++ /dev/null @@ -1,9 +0,0 @@ -0000ABCE 0000ABCE -FFFFABCE FFFFABCE -000000CE 000000CE -FFFFFFCE FFFFFFCE - -0000ABCE 0000ABCE -FFFFABCE FFFFABCE -000000CE 000000CE -FFFFFFCE FFFFFFCE diff --git a/tinyc/tests/tests2/99_fastcall.c b/tinyc/tests/tests2/99_fastcall.c deleted file mode 100644 index ee4b67d20..000000000 --- a/tinyc/tests/tests2/99_fastcall.c +++ /dev/null @@ -1,276 +0,0 @@ -#include -#include - -#ifndef _WIN32 -#define __fastcall __attribute((fastcall)) -#endif - -#if 1 -#define SYMBOL(x) _##x -#else -#define SYMBOL(x) x -#endif - -///////////////////////////////////////////////////////////////////////// -////////// TRAP FRAMEWORK -///////////////////////////////////////////////////////////////////////// -// if you cast 'TRAP' to a function pointer and call it, -// it will save all 8 registers, -// and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'), -// in C-code you can pop DWORDs from stack and modify registers -// - -void *SYMBOL(trap_handler); - -extern unsigned char SYMBOL(trap)[]; -asm ( - ".text;" - "_trap:;" - "pushl %esp;" - "pusha;" - "addl $0x4, 0xc(%esp);" - "pushl %esp;" - "call *_trap_handler;" - "addl $0x4, %esp;" - "movl 0xc(%esp), %eax;" - "movl %eax, 0x20(%esp);" - "popa;" - "popl %esp;" - "ret;" -); - -struct trapframe { - unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; -}; - - -#define M_FLOAT(addr) (*(float *)(addr)) -#define M_DWORD(addr) (*(unsigned *)(addr)) -#define M_WORD(addr) (*(unsigned short *)(addr)) -#define M_BYTE(addr) (*(unsigned char *)(addr)) -#define R_EAX ((tf)->eax) -#define R_ECX ((tf)->ecx) -#define R_EDX ((tf)->edx) -#define R_EBX ((tf)->ebx) -#define R_ESP ((tf)->esp) -#define R_EBP ((tf)->ebp) -#define R_ESI ((tf)->esi) -#define R_EDI ((tf)->edi) - -#define ARG(x) (M_DWORD(R_ESP + (x) * 4)) - -#define RETN(x) do { \ - M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \ - R_ESP += (x); \ -} while (0) - -#define DUMP() do { \ - unsigned i; \ - printf("EAX: %08X\n", R_EAX); \ - printf("ECX: %08X\n", R_ECX); \ - printf("EDX: %08X\n", R_EDX); \ - printf("EBX: %08X\n", R_EBX); \ - printf("ESP: %08X\n", R_ESP); \ - printf("EBP: %08X\n", R_EBP); \ - printf("ESI: %08X\n", R_ESI); \ - printf("EDI: %08X\n", R_EDI); \ - printf("\n"); \ - printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \ - for (i = 1; i <= 8; i++) { \ - printf("[ARG%4d]: %08X\n", i, ARG(i)); \ - } \ -} while (0) - -#define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x)) -#define TRAP ((void *) &SYMBOL(trap)) - - - -///////////////////////////////////////////////////////////////////////// -////////// SAFECALL FRAMEWORK -///////////////////////////////////////////////////////////////////////// -// this framework will convert any calling convention to cdecl -// usage: first set call target with 'SET_SAFECALL_TARGET(x)' -// then cast 'SAFECALL' to target function pointer type and invoke it -// after calling, 'ESPDIFF' is the difference of old and new esp - -void *SYMBOL(sc_call_target); -unsigned SYMBOL(sc_retn_addr); -unsigned SYMBOL(sc_old_esp); -unsigned SYMBOL(sc_new_esp); - -extern unsigned char SYMBOL(safecall)[]; -asm ( - ".text;" - "_safecall:;" - "popl _sc_retn_addr;" - "movl %esp, _sc_old_esp;" - "call *_sc_call_target;" - "movl %esp, _sc_new_esp;" - "movl _sc_old_esp, %esp;" - "jmp *_sc_retn_addr;" -); - -#define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x)) -#define SAFECALL ((void *) &SYMBOL(safecall)) -#define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp)) - - -///////////////////////////////////////////////////////////////////////// -////////// TEST FASTCALL INVOKE -///////////////////////////////////////////////////////////////////////// - -void check_fastcall_invoke_0(struct trapframe *tf) -{ - //DUMP(); - RETN(0); -} - -void check_fastcall_invoke_1(struct trapframe *tf) -{ - //DUMP(); - assert(R_ECX == 0x11111111); - RETN(0); -} -void check_fastcall_invoke_2(struct trapframe *tf) -{ - //DUMP(); - assert(R_ECX == 0x11111111); - assert(R_EDX == 0x22222222); - RETN(0); -} -void check_fastcall_invoke_3(struct trapframe *tf) -{ - //DUMP(); - assert(R_ECX == 0x11111111); - assert(R_EDX == 0x22222222); - assert(ARG(1) == 0x33333333); - RETN(1*4); -} -void check_fastcall_invoke_4(struct trapframe *tf) -{ - //DUMP(); - assert(R_ECX == 0x11111111); - assert(R_EDX == 0x22222222); - assert(ARG(1) == 0x33333333); - assert(ARG(2) == 0x44444444); - RETN(2*4); -} - -void check_fastcall_invoke_5(struct trapframe *tf) -{ - //DUMP(); - assert(R_ECX == 0x11111111); - assert(R_EDX == 0x22222222); - assert(ARG(1) == 0x33333333); - assert(ARG(2) == 0x44444444); - assert(ARG(3) == 0x55555555); - RETN(3*4); -} - -void test_fastcall_invoke() -{ - SET_TRAP_HANDLER(check_fastcall_invoke_0); - ((void __fastcall (*)(void)) TRAP)(); - - SET_TRAP_HANDLER(check_fastcall_invoke_1); - ((void __fastcall (*)(unsigned)) TRAP)(0x11111111); - - SET_TRAP_HANDLER(check_fastcall_invoke_2); - ((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222); - - SET_TRAP_HANDLER(check_fastcall_invoke_3); - ((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333); - - SET_TRAP_HANDLER(check_fastcall_invoke_4); - ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444); - - SET_TRAP_HANDLER(check_fastcall_invoke_5); - ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555); -} - - -///////////////////////////////////////////////////////////////////////// -////////// TEST FUNCTION CODE GENERATION -///////////////////////////////////////////////////////////////////////// - -int __fastcall check_fastcall_espdiff_0(void) -{ - return 0; -} - -int __fastcall check_fastcall_espdiff_1(int a) -{ - return a; -} - -int __fastcall check_fastcall_espdiff_2(int a, int b) -{ - return a + b; -} - -int __fastcall check_fastcall_espdiff_3(int a, int b, int c) -{ - return a + b + c; -} - -int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d) -{ - return a + b + c + d; -} - -int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e) -{ - return a + b + c + d + e; -} - -void test_fastcall_espdiff() -{ - int x; - SET_SAFECALL_TARGET(check_fastcall_espdiff_0); - x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)(); - assert(x == 0); - assert(ESPDIFF == 0); - - SET_SAFECALL_TARGET(check_fastcall_espdiff_1); - x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1); - assert(x == 1); - assert(ESPDIFF == 0); - - SET_SAFECALL_TARGET(check_fastcall_espdiff_2); - x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2); - assert(x == 1 + 2); - assert(ESPDIFF == 0); - - SET_SAFECALL_TARGET(check_fastcall_espdiff_3); - x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3); - assert(x == 1 + 2 + 3); - assert(ESPDIFF == 1*4); - - SET_SAFECALL_TARGET(check_fastcall_espdiff_4); - x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4); - assert(x == 1 + 2 + 3 + 4); - assert(ESPDIFF == 2*4); - - SET_SAFECALL_TARGET(check_fastcall_espdiff_5); - x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5); - assert(x == 1 + 2 + 3 + 4 + 5); - assert(ESPDIFF == 3*4); -} - -int main() -{ -#define N 10000 - int i; - - for (i = 1; i <= N; i++) { - test_fastcall_espdiff(); - } - - for (i = 1; i <= N; i++) { - test_fastcall_invoke(); - } - - puts("TEST OK"); - return 0; -} diff --git a/tinyc/tests/tests2/99_fastcall.expect b/tinyc/tests/tests2/99_fastcall.expect deleted file mode 100644 index 3835d63df..000000000 --- a/tinyc/tests/tests2/99_fastcall.expect +++ /dev/null @@ -1 +0,0 @@ -TEST OK diff --git a/tinyc/tests/vla_test.c b/tinyc/tests/vla_test.c deleted file mode 100644 index 3616c46d4..000000000 --- a/tinyc/tests/vla_test.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Test that allocating a variable length array in a loop - * does not use up a linear amount of memory - */ - -#include -#include -#include - -#define LOOP_COUNT 1000 -#define ARRAY_SIZE 100 - -/* Overwrite a VLA. This will overwrite the return address if SP is incorrect */ -void smash(char *p, int n) { - memset(p, 0, n); -} - -int test1(int n) { - int i; - char *array_ptrs[LOOP_COUNT]; - - for (i = 0; i < LOOP_COUNT; ++i) { - char test[n]; - smash(test, n); - array_ptrs[i] = test; - } - - return (array_ptrs[0]-array_ptrs[LOOP_COUNT-1] < n) ? 0 : 1; -} - -/* ensure goto does not circumvent array free */ -int test2(int n) { - char *array_ptrs[LOOP_COUNT]; - - int i = 0; -loop:; - char test[n]; - smash(test, n); - if (i >= LOOP_COUNT) - goto end; - array_ptrs[i] = test; - ++i; - goto loop; - -end: - smash(test, n); - char test2[n]; - smash(test2, n); - return (array_ptrs[0] - array_ptrs[LOOP_COUNT-1] < n) ? 0 : 1; -} - -int test3(int n) { - char test[n]; - smash(test, n); - goto label; -label: - smash(test, n); - char test2[n]; - smash(test2, n); - return (test-test2 >= n) ? 0 : 1; -} - -#define RUN_TEST(t) \ - if (!testname || (strcmp(#t, testname) == 0)) { \ - fputs(#t "... ", stdout); \ - fflush(stdout); \ - if (t(ARRAY_SIZE) == 0) { \ - fputs("success\n", stdout); \ - } else { \ - fputs("failure\n", stdout); \ - retval = EXIT_FAILURE; \ - } \ - } - -int main(int argc, char **argv) { - const char *testname = NULL; - int retval = EXIT_SUCCESS; - if (argc > 1) - testname = argv[1]; - RUN_TEST(test1) - RUN_TEST(test2) - RUN_TEST(test3) - return retval; -} diff --git a/tinyc/texi2pod.pl b/tinyc/texi2pod.pl deleted file mode 100644 index d86e176f1..000000000 --- a/tinyc/texi2pod.pl +++ /dev/null @@ -1,427 +0,0 @@ -#! /usr/bin/perl -w - -# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. - -# This file is part of GNU CC. - -# GNU CC is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# GNU CC is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with GNU CC; see the file COPYING. If not, write to -# the Free Software Foundation, 59 Temple Place - Suite 330, -# Boston MA 02111-1307, USA. - -# This does trivial (and I mean _trivial_) conversion of Texinfo -# markup to Perl POD format. It's intended to be used to extract -# something suitable for a manpage from a Texinfo document. - -$output = 0; -$skipping = 0; -%sects = (); -$section = ""; -@icstack = (); -@endwstack = (); -@skstack = (); -@instack = (); -$shift = ""; -%defs = (); -$fnno = 1; -$inf = ""; -$ibase = ""; - -while ($_ = shift) { - if (/^-D(.*)$/) { - if ($1 ne "") { - $flag = $1; - } else { - $flag = shift; - } - $value = ""; - ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/); - die "no flag specified for -D\n" - unless $flag ne ""; - die "flags may only contain letters, digits, hyphens, dashes and underscores\n" - unless $flag =~ /^[a-zA-Z0-9_-]+$/; - $defs{$flag} = $value; - } elsif (/^-/) { - usage(); - } else { - $in = $_, next unless defined $in; - $out = $_, next unless defined $out; - usage(); - } -} - -if (defined $in) { - $inf = gensym(); - open($inf, "<$in") or die "opening \"$in\": $!\n"; - $ibase = $1 if $in =~ m|^(.+)/[^/]+$|; -} else { - $inf = \*STDIN; -} - -if (defined $out) { - open(STDOUT, ">$out") or die "opening \"$out\": $!\n"; -} - -while(defined $inf) { -while(<$inf>) { - # Certain commands are discarded without further processing. - /^\@(?: - [a-z]+index # @*index: useful only in complete manual - |need # @need: useful only in printed manual - |(?:end\s+)?group # @group .. @end group: ditto - |page # @page: ditto - |node # @node: useful only in .info file - |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents - )\b/x and next; - - chomp; - - # Look for filename and title markers. - /^\@setfilename\s+([^.]+)/ and $fn = $1, next; - /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next; - - # Identify a man title but keep only the one we are interested in. - /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do { - if (exists $defs{$1}) { - $fn = $1; - $tl = postprocess($2); - } - next; - }; - - # Look for blocks surrounded by @c man begin SECTION ... @c man end. - # This really oughta be @ifman ... @end ifman and the like, but such - # would require rev'ing all other Texinfo translators. - /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do { - $output = 1 if exists $defs{$2}; - $sect = $1; - next; - }; - /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next; - /^\@c\s+man\s+end/ and do { - $sects{$sect} = "" unless exists $sects{$sect}; - $sects{$sect} .= postprocess($section); - $section = ""; - $output = 0; - next; - }; - - # handle variables - /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do { - $defs{$1} = $2; - next; - }; - /^\@clear\s+([a-zA-Z0-9_-]+)/ and do { - delete $defs{$1}; - next; - }; - - next unless $output; - - # Discard comments. (Can't do it above, because then we'd never see - # @c man lines.) - /^\@c\b/ and next; - - # End-block handler goes up here because it needs to operate even - # if we are skipping. - /^\@end\s+([a-z]+)/ and do { - # Ignore @end foo, where foo is not an operation which may - # cause us to skip, if we are presently skipping. - my $ended = $1; - next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/; - - die "\@end $ended without \@$ended at line $.\n" unless defined $endw; - die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw; - - $endw = pop @endwstack; - - if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) { - $skipping = pop @skstack; - next; - } elsif ($ended =~ /^(?:example|smallexample|display)$/) { - $shift = ""; - $_ = ""; # need a paragraph break - } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) { - $_ = "\n=back\n"; - $ic = pop @icstack; - } else { - die "unknown command \@end $ended at line $.\n"; - } - }; - - # We must handle commands which can cause skipping even while we - # are skipping, otherwise we will not process nested conditionals - # correctly. - /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = "ifset"; - $skipping = 1 unless exists $defs{$1}; - next; - }; - - /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = "ifclear"; - $skipping = 1 if exists $defs{$1}; - next; - }; - - /^\@(ignore|menu|iftex)\b/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = $1; - $skipping = 1; - next; - }; - - next if $skipping; - - # Character entities. First the ones that can be replaced by raw text - # or discarded outright: - s/\@copyright\{\}/(c)/g; - s/\@dots\{\}/.../g; - s/\@enddots\{\}/..../g; - s/\@([.!? ])/$1/g; - s/\@[:-]//g; - s/\@bullet(?:\{\})?/*/g; - s/\@TeX\{\}/TeX/g; - s/\@pounds\{\}/\#/g; - s/\@minus(?:\{\})?/-/g; - s/\\,/,/g; - - # Now the ones that have to be replaced by special escapes - # (which will be turned back into text by unmunge()) - s/&/&/g; - s/\@\{/{/g; - s/\@\}/}/g; - s/\@\@/&at;/g; - - # Inside a verbatim block, handle @var specially. - if ($shift ne "") { - s/\@var\{([^\}]*)\}/<$1>/g; - } - - # POD doesn't interpret E<> inside a verbatim block. - if ($shift eq "") { - s//>/g; - } else { - s//>/g; - } - - # Single line command handlers. - - /^\@include\s+(.+)$/ and do { - push @instack, $inf; - $inf = gensym(); - - # Try cwd and $ibase. - open($inf, "<" . $1) - or open($inf, "<" . $ibase . "/" . $1) - or die "cannot open $1 or $ibase/$1: $!\n"; - next; - }; - - /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/ - and $_ = "\n=head2 $1\n"; - /^\@subsection\s+(.+)$/ - and $_ = "\n=head3 $1\n"; - - # Block command handlers: - /^\@itemize\s+(\@[a-z]+|\*|-)/ and do { - push @endwstack, $endw; - push @icstack, $ic; - $ic = $1; - $_ = "\n=over 4\n"; - $endw = "itemize"; - }; - - /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do { - push @endwstack, $endw; - push @icstack, $ic; - if (defined $1) { - $ic = $1 . "."; - } else { - $ic = "1."; - } - $_ = "\n=over 4\n"; - $endw = "enumerate"; - }; - - /^\@([fv]?table)\s+(\@[a-z]+)/ and do { - push @endwstack, $endw; - push @icstack, $ic; - $endw = $1; - $ic = $2; - $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/; - $ic =~ s/\@(?:code|kbd)/C/; - $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/; - $ic =~ s/\@(?:file)/F/; - $_ = "\n=over 4\n"; - }; - - /^\@((?:small)?example|display)/ and do { - push @endwstack, $endw; - $endw = $1; - $shift = "\t"; - $_ = ""; # need a paragraph break - }; - - /^\@itemx?\s*(.+)?$/ and do { - if (defined $1) { - # Entity escapes prevent munging by the <> processing below. - $_ = "\n=item $ic\<$1\>\n"; - } else { - $_ = "\n=item $ic\n"; - $ic =~ y/A-Ya-y/B-Zb-z/; - $ic =~ s/(\d+)/$1 + 1/eg; - } - }; - - $section .= $shift.$_."\n"; -} -# End of current file. -close($inf); -$inf = pop @instack; -} - -die "No filename or title\n" unless defined $fn && defined $tl; - -$sects{NAME} = "$fn \- $tl\n"; -$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; - -for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES - BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { - if(exists $sects{$sect}) { - $head = $sect; - $head =~ s/SEEALSO/SEE ALSO/; - print "=head1 $head\n\n"; - print scalar unmunge ($sects{$sect}); - print "\n"; - } -} - -sub usage -{ - die "usage: $0 [-D toggle...] [infile [outfile]]\n"; -} - -sub postprocess -{ - local $_ = $_[0]; - - # @value{foo} is replaced by whatever 'foo' is defined as. - while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) { - if (! exists $defs{$2}) { - print STDERR "Option $2 not defined\n"; - s/\Q$1\E//; - } else { - $value = $defs{$2}; - s/\Q$1\E/$value/; - } - } - - # Formatting commands. - # Temporary escape for @r. - s/\@r\{([^\}]*)\}/R<$1>/g; - s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g; - s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g; - s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g; - s/\@sc\{([^\}]*)\}/\U$1/g; - s/\@file\{([^\}]*)\}/F<$1>/g; - s/\@w\{([^\}]*)\}/S<$1>/g; - s/\@(?:dmn|math)\{([^\}]*)\}/$1/g; - - # Cross references are thrown away, as are @noindent and @refill. - # (@noindent is impossible in .pod, and @refill is unnecessary.) - # @* is also impossible in .pod; we discard it and any newline that - # follows it. Similarly, our macro @gol must be discarded. - - s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g; - s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g; - s/;\s+\@pxref\{(?:[^\}]*)\}//g; - s/\@noindent\s*//g; - s/\@refill//g; - s/\@gol//g; - s/\@\*\s*\n?//g; - - # @uref can take one, two, or three arguments, with different - # semantics each time. @url and @email are just like @uref with - # one argument, for our purposes. - s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g; - s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g; - s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g; - - # Turn B blah> into B I B to - # match Texinfo semantics of @emph inside @samp. Also handle @r - # inside bold. - s/<//g; - 1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B]*)I<([^>]+)>/B<$1>I<$2>B]*)B<([^>]+)>/I<$1>B<$2>I//g; - s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g; - s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g; - - # Extract footnotes. This has to be done after all other - # processing because otherwise the regexp will choke on formatting - # inside @footnote. - while (/\@footnote/g) { - s/\@footnote\{([^\}]+)\}/[$fnno]/; - add_footnote($1, $fnno); - $fnno++; - } - - return $_; -} - -sub unmunge -{ - # Replace escaped symbols with their equivalents. - local $_ = $_[0]; - - s/</E/g; - s/>/E/g; - s/{/\{/g; - s/}/\}/g; - s/&at;/\@/g; - s/&/&/g; - return $_; -} - -sub add_footnote -{ - unless (exists $sects{FOOTNOTES}) { - $sects{FOOTNOTES} = "\n=over 4\n\n"; - } - - $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++; - $sects{FOOTNOTES} .= $_[0]; - $sects{FOOTNOTES} .= "\n\n"; -} - -# stolen from Symbol.pm -{ - my $genseq = 0; - sub gensym - { - my $name = "GEN" . $genseq++; - my $ref = \*{$name}; - delete $::{$name}; - return $ref; - } -} diff --git a/tinyc/win32/build-tcc.bat b/tinyc/win32/build-tcc.bat deleted file mode 100644 index ceb4411ff..000000000 --- a/tinyc/win32/build-tcc.bat +++ /dev/null @@ -1,189 +0,0 @@ -@rem ------------------------------------------------------ -@rem batch file to build tcc using mingw, msvc or tcc itself -@rem ------------------------------------------------------ - -@echo off -setlocal -if (%1)==(-clean) goto :cleanup -set CC=gcc -set /p VERSION= < ..\VERSION -set INST= -set BIN= -set DOC=no -set EXES_ONLY=no -goto :a0 -:a2 -shift -:a3 -shift -:a0 -if not (%1)==(-c) goto :a1 -set CC=%~2 -if (%2)==(cl) set CC=@call :cl -goto :a2 -:a1 -if (%1)==(-t) set T=%2&& goto :a2 -if (%1)==(-v) set VERSION=%~2&& goto :a2 -if (%1)==(-i) set INST=%2&& goto :a2 -if (%1)==(-b) set BIN=%2&& goto :a2 -if (%1)==(-d) set DOC=yes&& goto :a3 -if (%1)==(-x) set EXES_ONLY=yes&& goto :a3 -if (%1)==() goto :p1 -:usage -echo usage: build-tcc.bat [ options ... ] -echo options: -echo -c prog use prog (gcc/tcc/cl) to compile tcc -echo -c "prog options" use prog with options to compile tcc -echo -t 32/64 force 32/64 bit default target -echo -v "version" set tcc version -echo -i tccdir install tcc into tccdir -echo -b bindir optionally install binaries into bindir elsewhere -echo -d create tcc-doc.html too (needs makeinfo) -echo -x just create the executables -echo -clean delete all previously produced files and directories -exit /B 1 - -@rem ------------------------------------------------------ -@rem sub-routines - -:cleanup -set LOG=echo -%LOG% removing files: -for %%f in (*tcc.exe libtcc.dll lib\*.a) do call :del_file %%f -for %%f in (..\config.h ..\config.texi) do call :del_file %%f -for %%f in (include\*.h) do @if exist ..\%%f call :del_file %%f -for %%f in (include\tcclib.h examples\libtcc_test.c) do call :del_file %%f -for %%f in (*.o *.obj *.def *.pdb *.lib *.exp *.ilk) do call :del_file %%f -%LOG% removing directories: -for %%f in (doc libtcc) do call :del_dir %%f -%LOG% done. -exit /B 0 -:del_file -if exist %1 del %1 && %LOG% %1 -exit /B 0 -:del_dir -if exist %1 rmdir /Q/S %1 && %LOG% %1 -exit /B 0 - -:cl -@echo off -set CMD=cl -:c0 -set ARG=%1 -set ARG=%ARG:.dll=.lib% -if (%1)==(-shared) set ARG=-LD -if (%1)==(-o) shift && set ARG=-Fe%2 -set CMD=%CMD% %ARG% -shift -if not (%1)==() goto :c0 -echo on -%CMD% -O1 -W2 -Zi -MT -GS- -nologo -link -opt:ref,icf -@exit /B %ERRORLEVEL% - -@rem ------------------------------------------------------ -@rem main program - -:p1 -if not %T%_==_ goto :p2 -set T=32 -if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64 -if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64 -:p2 -if "%CC:~-3%"=="gcc" set CC=%CC% -Os -s -static -set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386 -set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64 -set P32=i386-win32 -set P64=x86_64-win32 -if %T%==64 goto :t64 -set D=%D32% -set DX=%D64% -set PX=%P64% -goto :p3 -:t64 -set D=%D64% -set DX=%D32% -set PX=%P32% -goto :p3 - -:p3 -@echo on - -:config.h -echo>..\config.h #define TCC_VERSION "%VERSION%" -echo>> ..\config.h #ifdef TCC_TARGET_X86_64 -echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-64.a" -echo>> ..\config.h #else -echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-32.a" -echo>> ..\config.h #endif - -for %%f in (*tcc.exe *tcc.dll) do @del %%f - -:compiler -%CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL -@if errorlevel 1 goto :the_end -%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0" -%CC% -o %PX%-tcc.exe ..\tcc.c %DX% - -@if (%EXES_ONLY%)==(yes) goto :files-done - -if not exist libtcc mkdir libtcc -if not exist doc mkdir doc -copy>nul ..\include\*.h include -copy>nul ..\tcclib.h include -copy>nul ..\libtcc.h libtcc -copy>nul ..\tests\libtcc_test.c examples -copy>nul tcc-win32.txt doc - -.\tcc -impdef libtcc.dll -o libtcc\libtcc.def -@if errorlevel 1 goto :the_end - -:libtcc1.a -@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o -.\tcc -m32 -c ../lib/libtcc1.c -.\tcc -m32 -c lib/crt1.c -.\tcc -m32 -c lib/crt1w.c -.\tcc -m32 -c lib/wincrt1.c -.\tcc -m32 -c lib/wincrt1w.c -.\tcc -m32 -c lib/dllcrt1.c -.\tcc -m32 -c lib/dllmain.c -.\tcc -m32 -c lib/chkstk.S -.\tcc -m32 -w -c ../lib/bcheck.c -.\tcc -m32 -c ../lib/alloca86.S -.\tcc -m32 -c ../lib/alloca86-bt.S -.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o -@if errorlevel 1 goto :the_end -.\tcc -m64 -c ../lib/libtcc1.c -.\tcc -m64 -c lib/crt1.c -.\tcc -m64 -c lib/crt1w.c -.\tcc -m64 -c lib/wincrt1.c -.\tcc -m64 -c lib/wincrt1w.c -.\tcc -m64 -c lib/dllcrt1.c -.\tcc -m64 -c lib/dllmain.c -.\tcc -m64 -c lib/chkstk.S -.\tcc -m64 -w -c ../lib/bcheck.c -.\tcc -m64 -c ../lib/alloca86_64.S -.\tcc -m64 -c ../lib/alloca86_64-bt.S -.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o -@if errorlevel 1 goto :the_end - -:tcc-doc.html -@if not (%DOC%)==(yes) goto :doc-done -echo>..\config.texi @set VERSION %VERSION% -cmd /c makeinfo --html --no-split ../tcc-doc.texi -o doc/tcc-doc.html -:doc-done - -:files-done -for %%f in (*.o *.def) do @del %%f - -:copy-install -@if (%INST%)==() goto :the_end -if not exist %INST% mkdir %INST% -@if (%BIN%)==() set BIN=%INST% -if not exist %BIN% mkdir %BIN% -for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f -@if not exist %INST%\lib mkdir %INST%\lib -for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f -for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f - -:the_end -exit /B %ERRORLEVEL% diff --git a/tinyc/win32/examples/dll.c b/tinyc/win32/examples/dll.c deleted file mode 100644 index 052a05644..000000000 --- a/tinyc/win32/examples/dll.c +++ /dev/null @@ -1,13 +0,0 @@ -//+--------------------------------------------------------------------------- -// -// dll.c - Windows DLL example - dynamically linked part -// - -#include - -__declspec(dllexport) const char *hello_data = "(not set)"; - -__declspec(dllexport) void hello_func (void) -{ - MessageBox (0, hello_data, "From DLL", MB_ICONINFORMATION); -} diff --git a/tinyc/win32/examples/fib.c b/tinyc/win32/examples/fib.c deleted file mode 100644 index 8da26bce6..000000000 --- a/tinyc/win32/examples/fib.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include // atoi() - -int fib(n) -{ - if (n <= 2) - return 1; - else - return fib(n-1) + fib(n-2); -} - -int main(int argc, char **argv) -{ - int n; - if (argc < 2) { - printf("usage: fib n\n" - "Compute nth Fibonacci number\n"); - return 1; - } - - n = atoi(argv[1]); - printf("fib(%d) = %d\n", n, fib(n)); - return 0; -} diff --git a/tinyc/win32/examples/hello_dll.c b/tinyc/win32/examples/hello_dll.c deleted file mode 100644 index 4813c5b94..000000000 --- a/tinyc/win32/examples/hello_dll.c +++ /dev/null @@ -1,20 +0,0 @@ -//+--------------------------------------------------------------------------- -// -// HELLO_DLL.C - Windows DLL example - main application part -// - -#include - -void hello_func (void); -__declspec(dllimport) extern const char *hello_data; - -int WINAPI WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - hello_data = "Hello World!"; - hello_func(); - return 0; -} diff --git a/tinyc/win32/examples/hello_win.c b/tinyc/win32/examples/hello_win.c deleted file mode 100644 index 96546e415..000000000 --- a/tinyc/win32/examples/hello_win.c +++ /dev/null @@ -1,163 +0,0 @@ -//+--------------------------------------------------------------------------- -// -// HELLO_WIN.C - Windows GUI 'Hello World!' Example -// -//+--------------------------------------------------------------------------- - -#include - -#define APPNAME "HELLO_WIN" - -char szAppName[] = APPNAME; // The name of this application -char szTitle[] = APPNAME; // The title bar text -const char *pWindowText; - -void CenterWindow(HWND hWnd); - -//+--------------------------------------------------------------------------- -// -// Function: WndProc -// -// Synopsis: very unusual type of function - gets called by system to -// process windows messages. -// -// Arguments: same as always. -//---------------------------------------------------------------------------- - -LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) { - - // ----------------------- first and last - case WM_CREATE: - CenterWindow(hwnd); - break; - - case WM_DESTROY: - PostQuitMessage(0); - break; - - // ----------------------- get out of it... - case WM_RBUTTONUP: - DestroyWindow(hwnd); - break; - - case WM_KEYDOWN: - if (VK_ESCAPE == wParam) - DestroyWindow(hwnd); - break; - - // ----------------------- display our minimal info - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc; - RECT rc; - hdc = BeginPaint(hwnd, &ps); - - GetClientRect(hwnd, &rc); - SetTextColor(hdc, RGB(240,240,96)); - SetBkMode(hdc, TRANSPARENT); - DrawText(hdc, pWindowText, -1, &rc, DT_CENTER|DT_SINGLELINE|DT_VCENTER); - - EndPaint(hwnd, &ps); - break; - } - - // ----------------------- let windows do all other stuff - default: - return DefWindowProc(hwnd, message, wParam, lParam); - } - return 0; -} - -//+--------------------------------------------------------------------------- -// -// Function: WinMain -// -// Synopsis: standard entrypoint for GUI Win32 apps -// -//---------------------------------------------------------------------------- -int APIENTRY WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow - ) -{ - MSG msg; - WNDCLASS wc; - HWND hwnd; - - pWindowText = lpCmdLine[0] ? lpCmdLine : "Hello Windows!"; - - // Fill in window class structure with parameters that describe - // the main window. - - ZeroMemory(&wc, sizeof wc); - wc.hInstance = hInstance; - wc.lpszClassName = szAppName; - wc.lpfnWndProc = (WNDPROC)WndProc; - wc.style = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW; - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - - if (FALSE == RegisterClass(&wc)) - return 0; - - // create the browser - hwnd = CreateWindow( - szAppName, - szTitle, - WS_OVERLAPPEDWINDOW|WS_VISIBLE, - CW_USEDEFAULT, - CW_USEDEFAULT, - 360,//CW_USEDEFAULT, - 240,//CW_USEDEFAULT, - 0, - 0, - hInstance, - 0); - - if (NULL == hwnd) - return 0; - - // Main message loop: - while (GetMessage(&msg, NULL, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return msg.wParam; -} - -//+--------------------------------------------------------------------------- - -//+--------------------------------------------------------------------------- - -void CenterWindow(HWND hwnd_self) -{ - HWND hwnd_parent; - RECT rw_self, rc_parent, rw_parent; - int xpos, ypos; - - hwnd_parent = GetParent(hwnd_self); - if (NULL == hwnd_parent) - hwnd_parent = GetDesktopWindow(); - - GetWindowRect(hwnd_parent, &rw_parent); - GetClientRect(hwnd_parent, &rc_parent); - GetWindowRect(hwnd_self, &rw_self); - - xpos = rw_parent.left + (rc_parent.right + rw_self.left - rw_self.right) / 2; - ypos = rw_parent.top + (rc_parent.bottom + rw_self.top - rw_self.bottom) / 2; - - SetWindowPos( - hwnd_self, NULL, - xpos, ypos, 0, 0, - SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE - ); -} - -//+--------------------------------------------------------------------------- diff --git a/tinyc/win32/include/_mingw.h b/tinyc/win32/include/_mingw.h deleted file mode 100644 index 2fc979872..000000000 --- a/tinyc/win32/include/_mingw.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * _mingw.h - * - * This file is for TinyCC and not part of the Mingw32 package. - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __MINGW_H -#define __MINGW_H - -/* some winapi files define these before including _mingw.h --> */ -#undef __cdecl -#undef _X86_ -#undef WIN32 -/* <-- */ - -#include -#include - -#define __int8 char -#define __int16 short -#define __int32 int -#define __int64 long long -#define _HAVE_INT64 - -#define __cdecl -#define __declspec(x) __attribute__((x)) -#define __unaligned __attribute__((packed)) -#define __fastcall __attribute__((fastcall)) - -#define __MSVCRT__ 1 -#undef _MSVCRT_ -#define __MINGW_IMPORT extern __declspec(dllimport) -#define __MINGW_ATTRIB_NORETURN -#define __MINGW_ATTRIB_CONST -#define __MINGW_ATTRIB_DEPRECATED -#define __MINGW_ATTRIB_MALLOC -#define __MINGW_ATTRIB_PURE -#define __MINGW_ATTRIB_NONNULL(arg) -#define __MINGW_NOTHROW -#define __GNUC_VA_LIST - -#define _CRTIMP extern -#define __CRT_INLINE extern __inline__ - -#define _CRT_ALIGN(x) __attribute__((aligned(x))) -#define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) -#define _CRT_PACKING 8 -#define __CRT_UNALIGNED -#define _CONST_RETURN - -#ifndef _TRUNCATE -#define _TRUNCATE ((size_t)-1) -#endif - -#define __CRT_STRINGIZE(_Value) #_Value -#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) -#define __CRT_WIDE(_String) L ## _String -#define _CRT_WIDE(_String) __CRT_WIDE(_String) - -#ifdef _WIN64 -#define __stdcall -#define _AMD64_ 1 -#define __x86_64 1 -#define _M_X64 100 /* Visual Studio */ -#define _M_AMD64 100 /* Visual Studio */ -#define USE_MINGW_SETJMP_TWO_ARGS -#define mingw_getsp tinyc_getbp -#define __TRY__ -#else -#define __stdcall __attribute__((__stdcall__)) -#define _X86_ 1 -#define _M_IX86 300 /* Visual Studio */ -#define WIN32 1 -#define _USE_32BIT_TIME_T -#ifdef __arm__ -#define __TRY__ -#else -#define __TRY__ void __try__(void**), *_sehrec[6]; __try__(_sehrec); -#endif -#endif - -/* in stddef.h */ -#define _SIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#define _PTRDIFF_T_DEFINED -#define _WCHAR_T_DEFINED -#define _UINTPTR_T_DEFINED -#define _INTPTR_T_DEFINED -#define _INTEGRAL_MAX_BITS 64 - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED -typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -typedef long long __time64_t; -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T -typedef __time32_t time_t; -#else -typedef __time64_t time_t; -#endif -#endif - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED -typedef wchar_t wctype_t; -#endif - -#ifndef _WINT_T -#define _WINT_T -typedef __WINT_TYPE__ wint_t; -#endif - -typedef int errno_t; -#define _ERRCODE_DEFINED - -typedef struct threadlocaleinfostruct *pthreadlocinfo; -typedef struct threadmbcinfostruct *pthreadmbcinfo; -typedef struct localeinfo_struct _locale_tstruct,*_locale_t; - -/* for winapi */ -#define _ANONYMOUS_UNION -#define _ANONYMOUS_STRUCT -#define DECLSPEC_NORETURN -#define DECLARE_STDCALL_P(type) __stdcall type -#define NOSERVICE 1 -#define NOMCX 1 -#define NOIME 1 -#define __INTRIN_H_ -#ifndef DUMMYUNIONNAME -# define DUMMYUNIONNAME -# define DUMMYUNIONNAME1 -# define DUMMYUNIONNAME2 -# define DUMMYUNIONNAME3 -# define DUMMYUNIONNAME4 -# define DUMMYUNIONNAME5 -#endif -#ifndef DUMMYSTRUCTNAME -# define DUMMYSTRUCTNAME -#endif -#ifndef WINVER -# define WINVER 0x0502 -#endif -#ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x502 -#endif - -#define __C89_NAMELESS -#define __MINGW_EXTENSION -#define WINAPI_FAMILY_PARTITION(X) 1 -#define MINGW_HAS_SECURE_API - -#endif /* __MINGW_H */ diff --git a/tinyc/win32/include/assert.h b/tinyc/win32/include/assert.h deleted file mode 100644 index 466d4571a..000000000 --- a/tinyc/win32/include/assert.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __ASSERT_H_ -#define __ASSERT_H_ - -#include <_mingw.h> -#ifdef __cplusplus -#include -#endif - -#ifdef NDEBUG -#ifndef assert -#define assert(_Expression) ((void)0) -#endif -#else - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; -#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ -/* C99 function name */ -void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; -__CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) -{ _exit(status); } -#endif - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line); -extern void __cdecl _assert(const char *, const char *, unsigned); - -#ifdef __cplusplus -} -#endif - -#ifndef assert -//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0)) -#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__)) -#endif - -#endif - -#endif diff --git a/tinyc/win32/include/conio.h b/tinyc/win32/include/conio.h deleted file mode 100644 index 39f779eb0..000000000 --- a/tinyc/win32/include/conio.h +++ /dev/null @@ -1,409 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_CONIO -#define _INC_CONIO - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP char *_cgets(char *_Buffer); - _CRTIMP int __cdecl _cprintf(const char *_Format,...); - _CRTIMP int __cdecl _cputs(const char *_Str); - _CRTIMP int __cdecl _cscanf(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _getch(void); - _CRTIMP int __cdecl _getche(void); - _CRTIMP int __cdecl _vcprintf(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_p(const char *_Format,...); - _CRTIMP int __cdecl _vcprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _kbhit(void); - -#if defined(_X86_) && !defined(__x86_64) - int __cdecl _inp(unsigned short); - unsigned short __cdecl _inpw(unsigned short); - unsigned long __cdecl _inpd(unsigned short); - int __cdecl _outp(unsigned short,int); - unsigned short __cdecl _outpw(unsigned short,unsigned short); - unsigned long __cdecl _outpd(unsigned short,unsigned long); -#endif - - _CRTIMP int __cdecl _putch(int _Ch); - _CRTIMP int __cdecl _ungetch(int _Ch); - _CRTIMP int __cdecl _getch_nolock(void); - _CRTIMP int __cdecl _getche_nolock(void); - _CRTIMP int __cdecl _putch_nolock(int _Ch); - _CRTIMP int __cdecl _ungetch_nolock(int _Ch); - -#ifndef _WCONIO_DEFINED -#define _WCONIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - - _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _getwch(void); - _CRTIMP wint_t __cdecl _getwche(void); - _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); - _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); - _CRTIMP int __cdecl _cputws(const wchar_t *_String); - _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh); - _CRTIMP wint_t __cdecl _getwch_nolock(void); - _CRTIMP wint_t __cdecl _getwche_nolock(void); - _CRTIMP wint_t __cdecl _ungetwch_nolock(wint_t _WCh); -#endif - -#ifndef NO_OLDNAMES - char *__cdecl cgets(char *_Buffer); - int __cdecl cprintf(const char *_Format,...); - int __cdecl cputs(const char *_Str); - int __cdecl cscanf(const char *_Format,...); - int __cdecl getch(void); - int __cdecl getche(void); - int __cdecl kbhit(void); - int __cdecl putch(int _Ch); - int __cdecl ungetch(int _Ch); - -#if (defined(_X86_) && !defined(__x86_64)) - int __cdecl inp(unsigned short); - unsigned short __cdecl inpw(unsigned short); - int __cdecl outp(unsigned short,int); - unsigned short __cdecl outpw(unsigned short,unsigned short); -#endif - - /* I/O intrin functions. */ - __CRT_INLINE unsigned char __inbyte(unsigned short Port) - { - unsigned char value; - __asm__ __volatile__ ("inb %w1,%b0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE unsigned short __inword(unsigned short Port) - { - unsigned short value; - __asm__ __volatile__ ("inw %w1,%w0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE unsigned long __indword(unsigned short Port) - { - unsigned long value; - __asm__ __volatile__ ("inl %w1,%0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE void __outbyte(unsigned short Port,unsigned char Data) - { - __asm__ __volatile__ ("outb %b0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __outword(unsigned short Port,unsigned short Data) - { - __asm__ __volatile__ ("outw %w0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __outdword(unsigned short Port,unsigned long Data) - { - __asm__ __volatile__ ("outl %0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __inbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insb " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __inwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insw " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __indwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insl " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - - __CRT_INLINE void __outbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsb " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __outwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsw " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __outdwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsl " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - - __CRT_INLINE unsigned __int64 __readcr0(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr0, %[value]" - : [value] "=q" (value)); - return value; - } - - /* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32 - separately. */ - -#ifdef _WIN64 - __CRT_INLINE void __writecr0(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr0" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr2(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr2, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr2(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr2" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr3(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr3, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr3(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr3" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr4(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr4, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr4(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr4" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr8(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr8, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr8(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr8" - : - : [Data] "q" (Data) - : "memory"); - } - -#elif defined(_WIN32) - - __CRT_INLINE void __writecr0(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr0" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr2(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr2, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr2(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr2" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr3(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr3, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr3(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr3" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr4(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr4, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr4(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr4" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr8(void) - { - unsigned long value; __asm__ __volatile__ ( - "mov %%cr8, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr8(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr8" - : - : [Data] "q" (Data) - : "memory"); - } - -#endif - - __CRT_INLINE unsigned __int64 __readmsr(unsigned long msr) - { - unsigned __int64 val1, val2; - __asm__ __volatile__( - "rdmsr" - : "=a" (val1), "=d" (val2) - : "c" (msr)); - return val1 | (val2 << 32); - } - - __CRT_INLINE void __writemsr (unsigned long msr, unsigned __int64 Value) - { - unsigned long val1 = Value, val2 = Value >> 32; - __asm__ __volatile__ ( - "wrmsr" - : - : "c" (msr), "a" (val1), "d" (val2)); - } - - __CRT_INLINE unsigned __int64 __rdtsc(void) - { - unsigned __int64 val1, val2; - __asm__ __volatile__ ( - "rdtsc" - : "=a" (val1), "=d" (val2)); - return val1 | (val2 << 32); - } - - __CRT_INLINE void __cpuid(int CPUInfo[4], int InfoType) - { - __asm__ __volatile__ ( - "cpuid" - : "=a" (CPUInfo [0]), "=b" (CPUInfo [1]), "=c" (CPUInfo [2]), "=d" (CPUInfo [3]) - : "a" (InfoType)); - } - -#endif - -#ifdef __cplusplus -} -#endif - -#include - -#endif diff --git a/tinyc/win32/include/ctype.h b/tinyc/win32/include/ctype.h deleted file mode 100644 index 7e9010026..000000000 --- a/tinyc/win32/include/ctype.h +++ /dev/null @@ -1,281 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_CTYPE -#define _INC_CTYPE - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif - -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif -#ifdef _MSVCRT_ -#define __pwctype_func() (_pwctype) -#ifndef _pwctype - extern unsigned short *_pwctype; -#endif -#else -#define __pwctype_func() (*_imp___pwctype) -#ifndef _pwctype - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#endif -#endif -#endif -#endif - - /* CRT stuff */ -#if 1 - extern const unsigned char __newclmap[]; - extern const unsigned char __newcumap[]; - extern pthreadlocinfo __ptlocinfo; - extern pthreadmbcinfo __ptmbcinfo; - extern int __globallocalestatus; - extern int __locale_changed; - extern struct threadlocaleinfostruct __initiallocinfo; - extern _locale_tstruct __initiallocalestructinfo; - pthreadlocinfo __cdecl __updatetlocinfo(void); - pthreadmbcinfo __cdecl __updatetmbcinfo(void); -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _CTYPE_DEFINED -#define _CTYPE_DEFINED - - _CRTIMP int __cdecl _isctype(int _C,int _Type); - _CRTIMP int __cdecl _isctype_l(int _C,int _Type,_locale_t _Locale); - _CRTIMP int __cdecl isalpha(int _C); - _CRTIMP int __cdecl _isalpha_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isupper(int _C); - _CRTIMP int __cdecl _isupper_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl islower(int _C); - _CRTIMP int __cdecl _islower_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isdigit(int _C); - _CRTIMP int __cdecl _isdigit_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isxdigit(int _C); - _CRTIMP int __cdecl _isxdigit_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isspace(int _C); - _CRTIMP int __cdecl _isspace_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl ispunct(int _C); - _CRTIMP int __cdecl _ispunct_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isalnum(int _C); - _CRTIMP int __cdecl _isalnum_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isprint(int _C); - _CRTIMP int __cdecl _isprint_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isgraph(int _C); - _CRTIMP int __cdecl _isgraph_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl iscntrl(int _C); - _CRTIMP int __cdecl _iscntrl_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl toupper(int _C); - _CRTIMP int __cdecl tolower(int _C); - _CRTIMP int __cdecl _tolower(int _C); - _CRTIMP int __cdecl _tolower_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl _toupper(int _C); - _CRTIMP int __cdecl _toupper_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl __isascii(int _C); - _CRTIMP int __cdecl __toascii(int _C); - _CRTIMP int __cdecl __iscsymf(int _C); - _CRTIMP int __cdecl __iscsym(int _C); - -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl isblank(int _C); -#endif -#endif - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t _C); - _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); - int __cdecl iswupper(wint_t _C); - _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); - int __cdecl iswlower(wint_t _C); - _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswdigit(wint_t _C); - _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswxdigit(wint_t _C); - _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswspace(wint_t _C); - _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); - int __cdecl iswpunct(wint_t _C); - _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); - int __cdecl iswalnum(wint_t _C); - _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); - int __cdecl iswprint(wint_t _C); - _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); - int __cdecl iswgraph(wint_t _C); - _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); - int __cdecl iswcntrl(wint_t _C); - _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); - int __cdecl iswascii(wint_t _C); - int __cdecl isleadbyte(int _C); - _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); - wint_t __cdecl towupper(wint_t _C); - _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); - wint_t __cdecl towlower(wint_t _C); - _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswctype(wint_t _C,wctype_t _Type); - _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsymf(wint_t _C); - _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsym(wint_t _C); - _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); - int __cdecl is_wctype(wint_t _C,wctype_t _Type); - -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl iswblank(wint_t _C); -#endif -#endif - -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef MB_CUR_MAX -#define MB_CUR_MAX ___mb_cur_max_func() -#ifndef __mb_cur_max -#ifdef _MSVCRT_ - extern int __mb_cur_max; -#else -#define __mb_cur_max (*_imp____mb_cur_max) - extern int *_imp____mb_cur_max; -#endif -#endif -#ifdef _MSVCRT_ -#define ___mb_cur_max_func() (__mb_cur_max) -#else -#define ___mb_cur_max_func() (*_imp____mb_cur_max) -#endif -#endif - -#define __chvalidchk(a,b) (__PCTYPE_FUNC[(a)] & (b)) -#define _chvalidchk_l(_Char,_Flag,_Locale) (!_Locale ? __chvalidchk(_Char,_Flag) : ((_locale_t)_Locale)->locinfo->pctype[_Char] & (_Flag)) -#define _ischartype_l(_Char,_Flag,_Locale) (((_Locale)!=NULL && (((_locale_t)(_Locale))->locinfo->mb_cur_max) > 1) ? _isctype_l(_Char,(_Flag),_Locale) : _chvalidchk_l(_Char,_Flag,_Locale)) -#define _isalpha_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA,_Locale) -#define _isupper_l(_Char,_Locale) _ischartype_l(_Char,_UPPER,_Locale) -#define _islower_l(_Char,_Locale) _ischartype_l(_Char,_LOWER,_Locale) -#define _isdigit_l(_Char,_Locale) _ischartype_l(_Char,_DIGIT,_Locale) -#define _isxdigit_l(_Char,_Locale) _ischartype_l(_Char,_HEX,_Locale) -#define _isspace_l(_Char,_Locale) _ischartype_l(_Char,_SPACE,_Locale) -#define _ispunct_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT,_Locale) -#define _isalnum_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA|_DIGIT,_Locale) -#define _isprint_l(_Char,_Locale) _ischartype_l(_Char,_BLANK|_PUNCT|_ALPHA|_DIGIT,_Locale) -#define _isgraph_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT|_ALPHA|_DIGIT,_Locale) -#define _iscntrl_l(_Char,_Locale) _ischartype_l(_Char,_CONTROL,_Locale) -#define _tolower(_Char) ((_Char)-'A'+'a') -#define _toupper(_Char) ((_Char)-'a'+'A') -#define __isascii(_Char) ((unsigned)(_Char) < 0x80) -#define __toascii(_Char) ((_Char) & 0x7f) - -#ifndef _WCTYPE_INLINE_DEFINED -#define _WCTYPE_INLINE_DEFINED - -#undef _CRT_WCTYPE_NOINLINE -#ifndef __cplusplus -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) -#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) -#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) -#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) -#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) -#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) -#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) -#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) -#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) -#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) -#endif -#endif - -#define __iscsymf(_c) (isalpha(_c) || ((_c)=='_')) -#define __iscsym(_c) (isalnum(_c) || ((_c)=='_')) -#define __iswcsymf(_c) (iswalpha(_c) || ((_c)=='_')) -#define __iswcsym(_c) (iswalnum(_c) || ((_c)=='_')) -#define _iscsymf_l(_c,_p) (_isalpha_l(_c,_p) || ((_c)=='_')) -#define _iscsym_l(_c,_p) (_isalnum_l(_c,_p) || ((_c)=='_')) -#define _iswcsymf_l(_c,_p) (_iswalpha_l(_c,_p) || ((_c)=='_')) -#define _iswcsym_l(_c,_p) (_iswalnum_l(_c,_p) || ((_c)=='_')) -#endif - -#ifndef NO_OLDNAMES -#ifndef _CTYPE_DEFINED - int __cdecl isascii(int _C); - int __cdecl toascii(int _C); - int __cdecl iscsymf(int _C); - int __cdecl iscsym(int _C); -#else -#define isascii __isascii -#define toascii __toascii -#define iscsymf __iscsymf -#define iscsym __iscsym -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/dir.h b/tinyc/win32/include/dir.h deleted file mode 100644 index f38f750d2..000000000 --- a/tinyc/win32/include/dir.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * dir.h - * - * This file OBSOLESCENT and only provided for backward compatibility. - * Please use io.h instead. - * - * This file is part of the Mingw32 package. - * - * Contributors: - * Created by Colin Peters - * Mumit Khan - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include - diff --git a/tinyc/win32/include/direct.h b/tinyc/win32/include/direct.h deleted file mode 100644 index 99ce69db7..000000000 --- a/tinyc/win32/include/direct.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_DIRECT -#define _INC_DIRECT - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DISKFREE_T_DEFINED -#define _DISKFREE_T_DEFINED - struct _diskfree_t { - unsigned total_clusters; - unsigned avail_clusters; - unsigned sectors_per_cluster; - unsigned bytes_per_sector; - }; -#endif - - _CRTIMP char *__cdecl _getcwd(char *_DstBuf,int _SizeInBytes); - _CRTIMP char *__cdecl _getdcwd(int _Drive,char *_DstBuf,int _SizeInBytes); - char *__cdecl _getdcwd_nolock(int _Drive,char *_DstBuf,int _SizeInBytes); - _CRTIMP int __cdecl _chdir(const char *_Path); - _CRTIMP int __cdecl _mkdir(const char *_Path); - _CRTIMP int __cdecl _rmdir(const char *_Path); - _CRTIMP int __cdecl _chdrive(int _Drive); - _CRTIMP int __cdecl _getdrive(void); - _CRTIMP unsigned long __cdecl _getdrives(void); - -#ifndef _GETDISKFREE_DEFINED -#define _GETDISKFREE_DEFINED - _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); -#endif - -#ifndef _WDIRECT_DEFINED -#define _WDIRECT_DEFINED - _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); -#endif - -#ifndef NO_OLDNAMES - -#define diskfree_t _diskfree_t - - char *__cdecl getcwd(char *_DstBuf,int _SizeInBytes); - int __cdecl chdir(const char *_Path); - int __cdecl mkdir(const char *_Path); - int __cdecl rmdir(const char *_Path); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/dirent.h b/tinyc/win32/include/dirent.h deleted file mode 100644 index cd31f59e0..000000000 --- a/tinyc/win32/include/dirent.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* All the headers include this file. */ -#include <_mingw.h> - -#ifndef __STRICT_ANSI__ - -#ifndef _DIRENT_H_ -#define _DIRENT_H_ - - -#pragma pack(push,_CRT_PACKING) - -#include - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif - - struct dirent - { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the - * finddata_t structure in the DIR. */ - }; - - /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ - typedef struct - { - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; - } DIR; - - DIR* __cdecl opendir (const char*); - struct dirent* __cdecl readdir (DIR*); - int __cdecl closedir (DIR*); - void __cdecl rewinddir (DIR*); - long __cdecl telldir (DIR*); - void __cdecl seekdir (DIR*, long); - - - /* wide char versions */ - - struct _wdirent - { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - wchar_t* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the * wfinddata_t structure in the _WDIR. */ - }; - - /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ - typedef struct - { - /* disk transfer area for this dir */ - struct _wfinddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; - } _WDIR; - - - - _WDIR* __cdecl _wopendir (const wchar_t*); - struct _wdirent* __cdecl _wreaddir (_WDIR*); - int __cdecl _wclosedir (_WDIR*); - void __cdecl _wrewinddir (_WDIR*); - long __cdecl _wtelldir (_WDIR*); - void __cdecl _wseekdir (_WDIR*, long); - - -#ifdef __cplusplus -} -#endif - -#endif /* Not RC_INVOKED */ - -#pragma pack(pop) - -#endif /* Not _DIRENT_H_ */ - - -#endif /* Not __STRICT_ANSI__ */ - diff --git a/tinyc/win32/include/dos.h b/tinyc/win32/include/dos.h deleted file mode 100644 index 294e8fe1b..000000000 --- a/tinyc/win32/include/dos.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_DOS -#define _INC_DOS - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DISKFREE_T_DEFINED -#define _DISKFREE_T_DEFINED - - struct _diskfree_t { - unsigned total_clusters; - unsigned avail_clusters; - unsigned sectors_per_cluster; - unsigned bytes_per_sector; - }; -#endif - -#define _A_NORMAL 0x00 -#define _A_RDONLY 0x01 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 -#define _A_SUBDIR 0x10 -#define _A_ARCH 0x20 - -#ifndef _GETDISKFREE_DEFINED -#define _GETDISKFREE_DEFINED - _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); -#endif - -#if (defined(_X86_) && !defined(__x86_64)) - void __cdecl _disable(void); - void __cdecl _enable(void); -#endif - -#ifndef NO_OLDNAMES -#define diskfree_t _diskfree_t -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/errno.h b/tinyc/win32/include/errno.h deleted file mode 100644 index c2df01581..000000000 --- a/tinyc/win32/include/errno.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_ERRNO -#define _INC_ERRNO - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRT_ERRNO_DEFINED -#define _CRT_ERRNO_DEFINED - _CRTIMP extern int *__cdecl _errno(void); -#define errno (*_errno()) - - errno_t __cdecl _set_errno(int _Value); - errno_t __cdecl _get_errno(int *_Value); -#endif - -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define EIO 5 -#define ENXIO 6 -#define E2BIG 7 -#define ENOEXEC 8 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define EBUSY 16 -#define EEXIST 17 -#define EXDEV 18 -#define ENODEV 19 -#define ENOTDIR 20 -#define EISDIR 21 -#define ENFILE 23 -#define EMFILE 24 -#define ENOTTY 25 -#define EFBIG 27 -#define ENOSPC 28 -#define ESPIPE 29 -#define EROFS 30 -#define EMLINK 31 -#define EPIPE 32 -#define EDOM 33 -#define EDEADLK 36 -#define ENAMETOOLONG 38 -#define ENOLCK 39 -#define ENOSYS 40 -#define ENOTEMPTY 41 - -#ifndef RC_INVOKED -#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) -#define _SECURECRT_ERRCODE_VALUES_DEFINED -#define EINVAL 22 -#define ERANGE 34 -#define EILSEQ 42 -#define STRUNCATE 80 -#endif -#endif - -#define EDEADLOCK EDEADLK - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/excpt.h b/tinyc/win32/include/excpt.h deleted file mode 100644 index 26cc9437c..000000000 --- a/tinyc/win32/include/excpt.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_EXCPT -#define _INC_EXCPT - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - - struct _EXCEPTION_POINTERS; - -#ifndef EXCEPTION_DISPOSITION -#define EXCEPTION_DISPOSITION int -#endif -#define ExceptionContinueExecution 0 -#define ExceptionContinueSearch 1 -#define ExceptionNestedException 2 -#define ExceptionCollidedUnwind 3 - -#if (defined(_X86_) && !defined(__x86_64)) - struct _EXCEPTION_RECORD; - struct _CONTEXT; - - EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *_ExceptionRecord,void *_EstablisherFrame,struct _CONTEXT *_ContextRecord,void *_DispatcherContext); -#elif defined(__ia64__) - - typedef struct _EXCEPTION_POINTERS *Exception_info_ptr; - struct _EXCEPTION_RECORD; - struct _CONTEXT; - struct _DISPATCHER_CONTEXT; - - _CRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler (struct _EXCEPTION_RECORD *_ExceptionRecord,unsigned __int64 _MemoryStackFp,unsigned __int64 _BackingStoreFp,struct _CONTEXT *_ContextRecord,struct _DISPATCHER_CONTEXT *_DispatcherContext,unsigned __int64 _GlobalPointer); -#elif defined(__x86_64) - - struct _EXCEPTION_RECORD; - struct _CONTEXT; -#endif - -#define GetExceptionCode _exception_code -#define exception_code _exception_code -#define GetExceptionInformation (struct _EXCEPTION_POINTERS *)_exception_info -#define exception_info (struct _EXCEPTION_POINTERS *)_exception_info -#define AbnormalTermination _abnormal_termination -#define abnormal_termination _abnormal_termination - - unsigned long __cdecl _exception_code(void); - void *__cdecl _exception_info(void); - int __cdecl _abnormal_termination(void); - -#define EXCEPTION_EXECUTE_HANDLER 1 -#define EXCEPTION_CONTINUE_SEARCH 0 -#define EXCEPTION_CONTINUE_EXECUTION -1 - - /* CRT stuff */ - typedef void (__cdecl * _PHNDLR)(int); - - struct _XCPT_ACTION { - unsigned long XcptNum; - int SigNum; - _PHNDLR XcptAction; - }; - - extern struct _XCPT_ACTION _XcptActTab[]; - extern int _XcptActTabCount; - extern int _XcptActTabSize; - extern int _First_FPE_Indx; - extern int _Num_FPE; - - int __cdecl __CppXcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); - int __cdecl _XcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); - - /* - * The type of function that is expected as an exception handler to be - * installed with _try1. - */ - typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); - -#ifndef HAVE_NO_SEH - /* - * This is not entirely necessary, but it is the structure installed by - * the _try1 primitive below. - */ - typedef struct _EXCEPTION_REGISTRATION { - struct _EXCEPTION_REGISTRATION *prev; - EXCEPTION_DISPOSITION (*handler)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); - } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; - - typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; - typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; -#endif - -#if (defined(_X86_) && !defined(__x86_64)) -#define __try1(pHandler) \ - __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler)); - -#define __except1 \ - __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" \ - : : : "%eax"); -#elif defined(__x86_64) -#define __try1(pHandler) \ - __asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (pHandler)); - -#define __except1 \ - __asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp;" \ - : : : "%rax"); -#else -#define __try1(pHandler) -#define __except1 -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/fcntl.h b/tinyc/win32/include/fcntl.h deleted file mode 100644 index 9202b08cc..000000000 --- a/tinyc/win32/include/fcntl.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#include - -#ifndef _INC_FCNTL -#define _INC_FCNTL - -#define _O_RDONLY 0x0000 -#define _O_WRONLY 0x0001 -#define _O_RDWR 0x0002 -#define _O_APPEND 0x0008 -#define _O_CREAT 0x0100 -#define _O_TRUNC 0x0200 -#define _O_EXCL 0x0400 -#define _O_TEXT 0x4000 -#define _O_BINARY 0x8000 -#define _O_WTEXT 0x10000 -#define _O_U16TEXT 0x20000 -#define _O_U8TEXT 0x40000 -#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) - -#define _O_RAW _O_BINARY -#define _O_NOINHERIT 0x0080 -#define _O_TEMPORARY 0x0040 -#define _O_SHORT_LIVED 0x1000 - -#define _O_SEQUENTIAL 0x0020 -#define _O_RANDOM 0x0010 - -#if !defined(NO_OLDNAMES) || defined(_POSIX) -#define O_RDONLY _O_RDONLY -#define O_WRONLY _O_WRONLY -#define O_RDWR _O_RDWR -#define O_APPEND _O_APPEND -#define O_CREAT _O_CREAT -#define O_TRUNC _O_TRUNC -#define O_EXCL _O_EXCL -#define O_TEXT _O_TEXT -#define O_BINARY _O_BINARY -#define O_RAW _O_BINARY -#define O_TEMPORARY _O_TEMPORARY -#define O_NOINHERIT _O_NOINHERIT -#define O_SEQUENTIAL _O_SEQUENTIAL -#define O_RANDOM _O_RANDOM -#define O_ACCMODE _O_ACCMODE -#endif -#endif diff --git a/tinyc/win32/include/fenv.h b/tinyc/win32/include/fenv.h deleted file mode 100644 index 258f3a5d9..000000000 --- a/tinyc/win32/include/fenv.h +++ /dev/null @@ -1,108 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _FENV_H_ -#define _FENV_H_ - -#include <_mingw.h> - -/* FPU status word exception flags */ -#define FE_INVALID 0x01 -#define FE_DENORMAL 0x02 -#define FE_DIVBYZERO 0x04 -#define FE_OVERFLOW 0x08 -#define FE_UNDERFLOW 0x10 -#define FE_INEXACT 0x20 -#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \ - | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) - -/* FPU control word rounding flags */ -#define FE_TONEAREST 0x0000 -#define FE_DOWNWARD 0x0400 -#define FE_UPWARD 0x0800 -#define FE_TOWARDZERO 0x0c00 - -/* The MXCSR exception flags are the same as the - FE flags. */ -#define __MXCSR_EXCEPT_FLAG_SHIFT 0 - -/* How much to shift FE status word exception flags - to get MXCSR rounding flags, */ -#define __MXCSR_ROUND_FLAG_SHIFT 3 - -#ifndef RC_INVOKED -/* - For now, support only for the basic abstraction of flags that are - either set or clear. fexcept_t could be structure that holds more - info about the fp environment. -*/ -typedef unsigned short fexcept_t; - -/* This 32-byte struct represents the entire floating point - environment as stored by fnstenv or fstenv, augmented by - the contents of the MXCSR register, as stored by stmxcsr - (if CPU supports it). */ -typedef struct -{ - unsigned short __control_word; - unsigned short __unused0; - unsigned short __status_word; - unsigned short __unused1; - unsigned short __tag_word; - unsigned short __unused2; - unsigned int __ip_offset; /* instruction pointer offset */ - unsigned short __ip_selector; - unsigned short __opcode; - unsigned int __data_offset; - unsigned short __data_selector; - unsigned short __unused3; - unsigned int __mxcsr; /* contents of the MXCSR register */ -} fenv_t; - - -/*The C99 standard (7.6.9) allows us to define implementation-specific macros for - different fp environments */ - -/* The default Intel x87 floating point environment (64-bit mantissa) */ -#define FE_PC64_ENV ((const fenv_t *)-1) - -/* The floating point environment set by MSVCRT _fpreset (53-bit mantissa) */ -#define FE_PC53_ENV ((const fenv_t *)-2) - -/* The FE_DFL_ENV macro is required by standard. - fesetenv will use the environment set at app startup.*/ -#define FE_DFL_ENV ((const fenv_t *) 0) - -#ifdef __cplusplus -extern "C" { -#endif - -/*TODO: Some of these could be inlined */ -/* 7.6.2 Exception */ - -extern int __cdecl feclearexcept (int); -extern int __cdecl fegetexceptflag (fexcept_t * flagp, int excepts); -extern int __cdecl feraiseexcept (int excepts ); -extern int __cdecl fesetexceptflag (const fexcept_t *, int); -extern int __cdecl fetestexcept (int excepts); - -/* 7.6.3 Rounding */ - -extern int __cdecl fegetround (void); -extern int __cdecl fesetround (int mode); - -/* 7.6.4 Environment */ - -extern int __cdecl fegetenv(fenv_t * envp); -extern int __cdecl fesetenv(const fenv_t * ); -extern int __cdecl feupdateenv(const fenv_t *); -extern int __cdecl feholdexcept(fenv_t *); - -#ifdef __cplusplus -} -#endif -#endif /* Not RC_INVOKED */ - -#endif /* ndef _FENV_H */ diff --git a/tinyc/win32/include/inttypes.h b/tinyc/win32/include/inttypes.h deleted file mode 100644 index 736009195..000000000 --- a/tinyc/win32/include/inttypes.h +++ /dev/null @@ -1,297 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* 7.8 Format conversion of integer types */ - -#ifndef _INTTYPES_H_ -#define _INTTYPES_H_ - -#include <_mingw.h> -#include -#define __need_wchar_t -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - intmax_t quot; - intmax_t rem; - } imaxdiv_t; - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) - -/* 7.8.1 Macros for format specifiers - * - * MS runtime does not yet understand C9x standard "ll" - * length specifier. It appears to treat "ll" as "l". - * The non-standard I64 length specifier causes warning in GCC, - * but understood by MS runtime functions. - */ - -/* fprintf macros for signed types */ -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "d" -#define PRId64 "I64d" - -#define PRIdLEAST8 "d" -#define PRIdLEAST16 "d" -#define PRIdLEAST32 "d" -#define PRIdLEAST64 "I64d" - -#define PRIdFAST8 "d" -#define PRIdFAST16 "d" -#define PRIdFAST32 "d" -#define PRIdFAST64 "I64d" - -#define PRIdMAX "I64d" - -#define PRIi8 "i" -#define PRIi16 "i" -#define PRIi32 "i" -#define PRIi64 "I64i" - -#define PRIiLEAST8 "i" -#define PRIiLEAST16 "i" -#define PRIiLEAST32 "i" -#define PRIiLEAST64 "I64i" - -#define PRIiFAST8 "i" -#define PRIiFAST16 "i" -#define PRIiFAST32 "i" -#define PRIiFAST64 "I64i" - -#define PRIiMAX "I64i" - -#define PRIo8 "o" -#define PRIo16 "o" -#define PRIo32 "o" -#define PRIo64 "I64o" - -#define PRIoLEAST8 "o" -#define PRIoLEAST16 "o" -#define PRIoLEAST32 "o" -#define PRIoLEAST64 "I64o" - -#define PRIoFAST8 "o" -#define PRIoFAST16 "o" -#define PRIoFAST32 "o" -#define PRIoFAST64 "I64o" - -#define PRIoMAX "I64o" - -/* fprintf macros for unsigned types */ -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "u" -#define PRIu64 "I64u" - - -#define PRIuLEAST8 "u" -#define PRIuLEAST16 "u" -#define PRIuLEAST32 "u" -#define PRIuLEAST64 "I64u" - -#define PRIuFAST8 "u" -#define PRIuFAST16 "u" -#define PRIuFAST32 "u" -#define PRIuFAST64 "I64u" - -#define PRIuMAX "I64u" - -#define PRIx8 "x" -#define PRIx16 "x" -#define PRIx32 "x" -#define PRIx64 "I64x" - -#define PRIxLEAST8 "x" -#define PRIxLEAST16 "x" -#define PRIxLEAST32 "x" -#define PRIxLEAST64 "I64x" - -#define PRIxFAST8 "x" -#define PRIxFAST16 "x" -#define PRIxFAST32 "x" -#define PRIxFAST64 "I64x" - -#define PRIxMAX "I64x" - -#define PRIX8 "X" -#define PRIX16 "X" -#define PRIX32 "X" -#define PRIX64 "I64X" - -#define PRIXLEAST8 "X" -#define PRIXLEAST16 "X" -#define PRIXLEAST32 "X" -#define PRIXLEAST64 "I64X" - -#define PRIXFAST8 "X" -#define PRIXFAST16 "X" -#define PRIXFAST32 "X" -#define PRIXFAST64 "I64X" - -#define PRIXMAX "I64X" - -/* - * fscanf macros for signed int types - * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t - * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have - * no length identifiers - */ - -#define SCNd16 "hd" -#define SCNd32 "d" -#define SCNd64 "I64d" - -#define SCNdLEAST16 "hd" -#define SCNdLEAST32 "d" -#define SCNdLEAST64 "I64d" - -#define SCNdFAST16 "hd" -#define SCNdFAST32 "d" -#define SCNdFAST64 "I64d" - -#define SCNdMAX "I64d" - -#define SCNi16 "hi" -#define SCNi32 "i" -#define SCNi64 "I64i" - -#define SCNiLEAST16 "hi" -#define SCNiLEAST32 "i" -#define SCNiLEAST64 "I64i" - -#define SCNiFAST16 "hi" -#define SCNiFAST32 "i" -#define SCNiFAST64 "I64i" - -#define SCNiMAX "I64i" - -#define SCNo16 "ho" -#define SCNo32 "o" -#define SCNo64 "I64o" - -#define SCNoLEAST16 "ho" -#define SCNoLEAST32 "o" -#define SCNoLEAST64 "I64o" - -#define SCNoFAST16 "ho" -#define SCNoFAST32 "o" -#define SCNoFAST64 "I64o" - -#define SCNoMAX "I64o" - -#define SCNx16 "hx" -#define SCNx32 "x" -#define SCNx64 "I64x" - -#define SCNxLEAST16 "hx" -#define SCNxLEAST32 "x" -#define SCNxLEAST64 "I64x" - -#define SCNxFAST16 "hx" -#define SCNxFAST32 "x" -#define SCNxFAST64 "I64x" - -#define SCNxMAX "I64x" - -/* fscanf macros for unsigned int types */ - -#define SCNu16 "hu" -#define SCNu32 "u" -#define SCNu64 "I64u" - -#define SCNuLEAST16 "hu" -#define SCNuLEAST32 "u" -#define SCNuLEAST64 "I64u" - -#define SCNuFAST16 "hu" -#define SCNuFAST32 "u" -#define SCNuFAST64 "I64u" - -#define SCNuMAX "I64u" - -#ifdef _WIN64 -#define PRIdPTR "I64d" -#define PRIiPTR "I64i" -#define PRIoPTR "I64o" -#define PRIuPTR "I64u" -#define PRIxPTR "I64x" -#define PRIXPTR "I64X" -#define SCNdPTR "I64d" -#define SCNiPTR "I64i" -#define SCNoPTR "I64o" -#define SCNxPTR "I64x" -#define SCNuPTR "I64u" -#else -#define PRIdPTR "d" -#define PRIiPTR "i" -#define PRIoPTR "o" -#define PRIuPTR "u" -#define PRIxPTR "x" -#define PRIXPTR "X" -#define SCNdPTR "d" -#define SCNiPTR "i" -#define SCNoPTR "o" -#define SCNxPTR "x" -#define SCNuPTR "u" -#endif - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* - * no length modifier for char types prior to C9x - * MS runtime scanf appears to treat "hh" as "h" - */ - -/* signed char */ -#define SCNd8 "hhd" -#define SCNdLEAST8 "hhd" -#define SCNdFAST8 "hhd" - -#define SCNi8 "hhi" -#define SCNiLEAST8 "hhi" -#define SCNiFAST8 "hhi" - -#define SCNo8 "hho" -#define SCNoLEAST8 "hho" -#define SCNoFAST8 "hho" - -#define SCNx8 "hhx" -#define SCNxLEAST8 "hhx" -#define SCNxFAST8 "hhx" - -/* unsigned char */ -#define SCNu8 "hhu" -#define SCNuLEAST8 "hhu" -#define SCNuFAST8 "hhu" -#endif /* __STDC_VERSION__ >= 199901 */ - -#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ - -intmax_t __cdecl imaxabs (intmax_t j); -__CRT_INLINE intmax_t __cdecl imaxabs (intmax_t j) - {return (j >= 0 ? j : -j);} -imaxdiv_t __cdecl imaxdiv (intmax_t numer, intmax_t denom); - -/* 7.8.2 Conversion functions for greatest-width integer types */ - -intmax_t __cdecl strtoimax (const char* __restrict__ nptr, - char** __restrict__ endptr, int base); -uintmax_t __cdecl strtoumax (const char* __restrict__ nptr, - char** __restrict__ endptr, int base); - -intmax_t __cdecl wcstoimax (const wchar_t* __restrict__ nptr, - wchar_t** __restrict__ endptr, int base); -uintmax_t __cdecl wcstoumax (const wchar_t* __restrict__ nptr, - wchar_t** __restrict__ endptr, int base); - -#ifdef __cplusplus -} -#endif - -#endif /* ndef _INTTYPES_H */ diff --git a/tinyc/win32/include/io.h b/tinyc/win32/include/io.h deleted file mode 100644 index e2aeec3db..000000000 --- a/tinyc/win32/include/io.h +++ /dev/null @@ -1,418 +0,0 @@ - -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _IO_H_ -#define _IO_H_ - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifndef _POSIX_ - -#ifdef __cplusplus -extern "C" { -#endif - -_CRTIMP char* __cdecl _getcwd (char*, int); -#ifndef _FSIZE_T_DEFINED - typedef unsigned long _fsize_t; -#define _FSIZE_T_DEFINED -#endif - -#ifndef _FINDDATA_T_DEFINED - - struct _finddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - char name[260]; - }; - -/*#if _INTEGRAL_MAX_BITS >= 64*/ - - struct _finddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - char name[260]; - }; - - struct _finddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - char name[260]; - }; - - struct __finddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - char name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _finddata_t _finddata32_t -#define _finddatai64_t _finddata32i64_t - -#ifdef _WIN64 -#define _findfirst _findfirst32 -#define _findnext _findnext32 -#else -#define _findfirst32 _findfirst -#define _findnext32 _findnext -#endif -#define _findfirsti64 _findfirst32i64 -#define _findnexti64 _findnext32i64 -#else -#define _finddata_t _finddata64i32_t -#define _finddatai64_t __finddata64_t - -#define _findfirst _findfirst64i32 -#define _findnext _findnext64i32 -#define _findfirsti64 _findfirst64 -#define _findnexti64 _findnext64 -#endif - -#define _FINDDATA_T_DEFINED -#endif - -#ifndef _WFINDDATA_T_DEFINED - - struct _wfinddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - -/* #if _INTEGRAL_MAX_BITS >= 64 */ - - struct _wfinddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - wchar_t name[260]; - }; - - struct _wfinddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - - struct _wfinddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - wchar_t name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _wfinddata_t _wfinddata32_t -#define _wfinddatai64_t _wfinddata32i64_t - -#define _wfindfirst _wfindfirst32 -#define _wfindnext _wfindnext32 -#define _wfindfirsti64 _wfindfirst32i64 -#define _wfindnexti64 _wfindnext32i64 -#else -#define _wfinddata_t _wfinddata64i32_t -#define _wfinddatai64_t _wfinddata64_t - -#define _wfindfirst _wfindfirst64i32 -#define _wfindnext _wfindnext64i32 -#define _wfindfirsti64 _wfindfirst64 -#define _wfindnexti64 _wfindnext64 -#endif - -#define _WFINDDATA_T_DEFINED -#endif - -#define _A_NORMAL 0x00 -#define _A_RDONLY 0x01 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 -#define _A_SUBDIR 0x10 -#define _A_ARCH 0x20 - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#undef size_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned int size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef int ssize_t; -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int _off64_t __attribute__ ((mode (DI))); -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef int off64_t __attribute__ ((mode (DI))); -#endif -#else - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif -#endif - - /* Some defines for _access nAccessMode (MS doesn't define them, but - * it doesn't seem to hurt to add them). */ -#define F_OK 0 /* Check for file existence */ -#define X_OK 1 /* Check for execute permission. */ -#define W_OK 2 /* Check for write permission */ -#define R_OK 4 /* Check for read permission */ - - _CRTIMP int __cdecl _access(const char *_Filename,int _AccessMode); - _CRTIMP int __cdecl _chmod(const char *_Filename,int _Mode); - _CRTIMP int __cdecl _chsize(int _FileHandle,long _Size); - _CRTIMP int __cdecl _close(int _FileHandle); - _CRTIMP int __cdecl _commit(int _FileHandle); - _CRTIMP int __cdecl _creat(const char *_Filename,int _PermissionMode); - _CRTIMP int __cdecl _dup(int _FileHandle); - _CRTIMP int __cdecl _dup2(int _FileHandleSrc,int _FileHandleDst); - _CRTIMP int __cdecl _eof(int _FileHandle); - _CRTIMP long __cdecl _filelength(int _FileHandle); - _CRTIMP intptr_t __cdecl _findfirst32(const char *_Filename,struct _finddata32_t *_FindData); - _CRTIMP int __cdecl _findnext32(intptr_t _FindHandle,struct _finddata32_t *_FindData); - _CRTIMP int __cdecl _findclose(intptr_t _FindHandle); - _CRTIMP int __cdecl _isatty(int _FileHandle); - _CRTIMP int __cdecl _locking(int _FileHandle,int _LockMode,long _NumOfBytes); - _CRTIMP long __cdecl _lseek(int _FileHandle,long _Offset,int _Origin); - _off64_t lseek64(int fd,_off64_t offset, int whence); - _CRTIMP char *__cdecl _mktemp(char *_TemplateName); - _CRTIMP int __cdecl _pipe(int *_PtHandles,unsigned int _PipeSize,int _TextMode); - _CRTIMP int __cdecl _read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); - -#ifndef _CRT_DIRECTORY_DEFINED -#define _CRT_DIRECTORY_DEFINED - int __cdecl remove(const char *_Filename); - int __cdecl rename(const char *_OldFilename,const char *_NewFilename); - _CRTIMP int __cdecl _unlink(const char *_Filename); -#ifndef NO_OLDNAMES - int __cdecl unlink(const char *_Filename); -#endif -#endif - - _CRTIMP int __cdecl _setmode(int _FileHandle,int _Mode); - _CRTIMP long __cdecl _tell(int _FileHandle); - _CRTIMP int __cdecl _umask(int _Mode); - _CRTIMP int __cdecl _write(int _FileHandle,const void *_Buf,unsigned int _MaxCharCount); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP __int64 __cdecl _filelengthi64(int _FileHandle); - _CRTIMP intptr_t __cdecl _findfirst32i64(const char *_Filename,struct _finddata32i64_t *_FindData); - _CRTIMP intptr_t __cdecl _findfirst64(const char *_Filename,struct __finddata64_t *_FindData); -#ifdef __cplusplus -#include -#endif - intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData); - __CRT_INLINE intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData) - { - struct __finddata64_t fd; - intptr_t ret = _findfirst64(_Filename,&fd); - _FindData->attrib=fd.attrib; - _FindData->time_create=fd.time_create; - _FindData->time_access=fd.time_access; - _FindData->time_write=fd.time_write; - _FindData->size=(_fsize_t) fd.size; - strncpy(_FindData->name,fd.name,260); - return ret; - } - _CRTIMP int __cdecl _findnext32i64(intptr_t _FindHandle,struct _finddata32i64_t *_FindData); - _CRTIMP int __cdecl _findnext64(intptr_t _FindHandle,struct __finddata64_t *_FindData); - int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData); - __CRT_INLINE int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData) - { - struct __finddata64_t fd; - int ret = _findnext64(_FindHandle,&fd); - _FindData->attrib=fd.attrib; - _FindData->time_create=fd.time_create; - _FindData->time_access=fd.time_access; - _FindData->time_write=fd.time_write; - _FindData->size=(_fsize_t) fd.size; - strncpy(_FindData->name,fd.name,260); - return ret; - } - __int64 __cdecl _lseeki64(int _FileHandle,__int64 _Offset,int _Origin); - __int64 __cdecl _telli64(int _FileHandle); -#endif -#ifndef NO_OLDNAMES - -#ifndef _UWIN - int __cdecl chdir (const char *); - char *__cdecl getcwd (char *, int); - int __cdecl mkdir (const char *); - char *__cdecl mktemp(char *); - int __cdecl rmdir (const char*); - int __cdecl chmod (const char *, int); -#endif /* _UWIN */ - -#endif /* Not NO_OLDNAMES */ - - _CRTIMP errno_t __cdecl _sopen_s(int *_FileHandle,const char *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode); - -#ifndef __cplusplus - _CRTIMP int __cdecl _open(const char *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _open(const char *_Filename,int _Openflag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _sopen(const char *_Filename,int _Openflag,int _ShareFlag,int _PermissionMode = 0); -#endif - -#ifndef _WIO_DEFINED -#define _WIO_DEFINED - _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); - _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); - _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); - _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); - _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); - _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); - intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); - _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); - _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); - int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); - _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); -#endif - - _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); - -#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); -#endif - -#endif - - int __cdecl __lock_fhandle(int _Filehandle); - void __cdecl _unlock_fhandle(int _Filehandle); - _CRTIMP intptr_t __cdecl _get_osfhandle(int _FileHandle); - _CRTIMP int __cdecl _open_osfhandle(intptr_t _OSFileHandle,int _Flags); - -#ifndef NO_OLDNAMES - int __cdecl access(const char *_Filename,int _AccessMode); - int __cdecl chmod(const char *_Filename,int _AccessMode); - int __cdecl chsize(int _FileHandle,long _Size); - int __cdecl close(int _FileHandle); - int __cdecl creat(const char *_Filename,int _PermissionMode); - int __cdecl dup(int _FileHandle); - int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst); - int __cdecl eof(int _FileHandle); - long __cdecl filelength(int _FileHandle); - int __cdecl isatty(int _FileHandle); - int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes); - long __cdecl lseek(int _FileHandle,long _Offset,int _Origin); - char *__cdecl mktemp(char *_TemplateName); - int __cdecl open(const char *_Filename,int _OpenFlag,...); - int __cdecl read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); - int __cdecl setmode(int _FileHandle,int _Mode); - int __cdecl sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); - long __cdecl tell(int _FileHandle); - int __cdecl umask(int _Mode); - int __cdecl write(int _Filehandle,const void *_Buf,unsigned int _MaxCharCount); -#endif - -#ifdef __cplusplus -} -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Misc stuff */ -char *getlogin(void); -#ifdef __USE_MINGW_ALARM -unsigned int alarm(unsigned int seconds); -#endif - -#ifdef __USE_MINGW_ACCESS -/* Old versions of MSVCRT access() just ignored X_OK, while the version - shipped with Vista, returns an error code. This will restore the - old behaviour */ -static inline int __mingw_access (const char *__fname, int __mode) { - return _access (__fname, __mode & ~X_OK); -} - -#define access(__f,__m) __mingw_access (__f, __m) -#endif - - -#ifdef __cplusplus -} -#endif - - -#pragma pack(pop) - -#include - -#endif /* End _IO_H_ */ - diff --git a/tinyc/win32/include/limits.h b/tinyc/win32/include/limits.h deleted file mode 100644 index fafb04a46..000000000 --- a/tinyc/win32/include/limits.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#ifndef _INC_LIMITS -#define _INC_LIMITS - -/* -* File system limits -* -* TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the -* same as FILENAME_MAX and FOPEN_MAX from stdio.h? -* NOTE: Apparently the actual size of PATH_MAX is 260, but a space is -* required for the NUL. TODO: Test? -*/ -#define PATH_MAX (259) - -#define CHAR_BIT 8 -#define SCHAR_MIN (-128) -#define SCHAR_MAX 127 -#define UCHAR_MAX 0xff - -#define CHAR_MIN SCHAR_MIN -#define CHAR_MAX SCHAR_MAX - -#define MB_LEN_MAX 5 -#define SHRT_MIN (-32768) -#define SHRT_MAX 32767 -#define USHRT_MAX 0xffff -#define INT_MIN (-2147483647 - 1) -#define INT_MAX 2147483647 -#define UINT_MAX 0xffffffff -#define LONG_MIN (-2147483647L - 1) -#define LONG_MAX 2147483647L -#define ULONG_MAX 0xffffffffUL -#define LLONG_MAX 9223372036854775807ll -#define LLONG_MIN (-9223372036854775807ll - 1) -#define ULLONG_MAX 0xffffffffffffffffull - -#if _INTEGRAL_MAX_BITS >= 8 -#define _I8_MIN (-127 - 1) -#define _I8_MAX 127i8 -#define _UI8_MAX 0xffu -#endif - -#if _INTEGRAL_MAX_BITS >= 16 -#define _I16_MIN (-32767 - 1) -#define _I16_MAX 32767i16 -#define _UI16_MAX 0xffffu -#endif - -#if _INTEGRAL_MAX_BITS >= 32 -#define _I32_MIN (-2147483647 - 1) -#define _I32_MAX 2147483647 -#define _UI32_MAX 0xffffffffu -#endif - -#if defined(__GNUC__) -#undef LONG_LONG_MAX -#define LONG_LONG_MAX 9223372036854775807ll -#undef LONG_LONG_MIN -#define LONG_LONG_MIN (-LONG_LONG_MAX-1) -#undef ULONG_LONG_MAX -#define ULONG_LONG_MAX (2ull * LONG_LONG_MAX + 1ull) -#endif - -#if _INTEGRAL_MAX_BITS >= 64 -#define _I64_MIN (-9223372036854775807ll - 1) -#define _I64_MAX 9223372036854775807ll -#define _UI64_MAX 0xffffffffffffffffull -#endif - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX _UI64_MAX -#else -#define SIZE_MAX UINT_MAX -#endif -#endif - -#ifdef _POSIX_ -#define _POSIX_ARG_MAX 4096 -#define _POSIX_CHILD_MAX 6 -#define _POSIX_LINK_MAX 8 -#define _POSIX_MAX_CANON 255 -#define _POSIX_MAX_INPUT 255 -#define _POSIX_NAME_MAX 14 -#define _POSIX_NGROUPS_MAX 0 -#define _POSIX_OPEN_MAX 16 -#define _POSIX_PATH_MAX 255 -#define _POSIX_PIPE_BUF 512 -#define _POSIX_SSIZE_MAX 32767 -#define _POSIX_STREAM_MAX 8 -#define _POSIX_TZNAME_MAX 3 -#define ARG_MAX 14500 -#define LINK_MAX 1024 -#define MAX_CANON _POSIX_MAX_CANON -#define MAX_INPUT _POSIX_MAX_INPUT -#define NAME_MAX 255 -#define NGROUPS_MAX 16 -#define OPEN_MAX 32 -#define PATH_MAX 512 -#define PIPE_BUF _POSIX_PIPE_BUF -#define SSIZE_MAX _POSIX_SSIZE_MAX -#define STREAM_MAX 20 -#define TZNAME_MAX 10 -#endif -#endif diff --git a/tinyc/win32/include/locale.h b/tinyc/win32/include/locale.h deleted file mode 100644 index 686aa9bae..000000000 --- a/tinyc/win32/include/locale.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_LOCALE -#define _INC_LOCALE - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define LC_ALL 0 -#define LC_COLLATE 1 -#define LC_CTYPE 2 -#define LC_MONETARY 3 -#define LC_NUMERIC 4 -#define LC_TIME 5 - -#define LC_MIN LC_ALL -#define LC_MAX LC_TIME - -#ifndef _LCONV_DEFINED -#define _LCONV_DEFINED - struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - }; -#endif - -#ifndef _CONFIG_LOCALE_SWT -#define _CONFIG_LOCALE_SWT - -#define _ENABLE_PER_THREAD_LOCALE 0x1 -#define _DISABLE_PER_THREAD_LOCALE 0x2 -#define _ENABLE_PER_THREAD_LOCALE_GLOBAL 0x10 -#define _DISABLE_PER_THREAD_LOCALE_GLOBAL 0x20 -#define _ENABLE_PER_THREAD_LOCALE_NEW 0x100 -#define _DISABLE_PER_THREAD_LOCALE_NEW 0x200 - -#endif - - int __cdecl _configthreadlocale(int _Flag); - char *__cdecl setlocale(int _Category,const char *_Locale); - _CRTIMP struct lconv *__cdecl localeconv(void); - _locale_t __cdecl _get_current_locale(void); - _locale_t __cdecl _create_locale(int _Category,const char *_Locale); - void __cdecl _free_locale(_locale_t _Locale); - _locale_t __cdecl __get_current_locale(void); - _locale_t __cdecl __create_locale(int _Category,const char *_Locale); - void __cdecl __free_locale(_locale_t _Locale); - -#ifndef _WLOCALE_DEFINED -#define _WLOCALE_DEFINED - _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/malloc.h b/tinyc/win32/include/malloc.h deleted file mode 100644 index fc783a8e3..000000000 --- a/tinyc/win32/include/malloc.h +++ /dev/null @@ -1,181 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _MALLOC_H_ -#define _MALLOC_H_ - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifndef _MM_MALLOC_H_INCLUDED -#define _MM_MALLOC_H_INCLUDED -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _WIN64 -#define _HEAP_MAXREQ 0xFFFFFFFFFFFFFFE0 -#else -#define _HEAP_MAXREQ 0xFFFFFFE0 -#endif - -#ifndef _STATIC_ASSERT -#define _STATIC_ASSERT(expr) extern void __static_assert_t(int [(expr)?1:-1]) -#endif - -/* Return codes for _heapwalk() */ -#define _HEAPEMPTY (-1) -#define _HEAPOK (-2) -#define _HEAPBADBEGIN (-3) -#define _HEAPBADNODE (-4) -#define _HEAPEND (-5) -#define _HEAPBADPTR (-6) - -/* Values for _heapinfo.useflag */ -#define _FREEENTRY 0 -#define _USEDENTRY 1 - -#ifndef _HEAPINFO_DEFINED -#define _HEAPINFO_DEFINED - /* The structure used to walk through the heap with _heapwalk. */ - typedef struct _heapinfo { - int *_pentry; - size_t _size; - int _useflag; - } _HEAPINFO; -#endif - - extern unsigned int _amblksiz; - -#define _mm_free(a) _aligned_free(a) -#define _mm_malloc(a,b) _aligned_malloc(a,b) - -#ifndef _CRT_ALLOCATION_DEFINED -#define _CRT_ALLOCATION_DEFINED - void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); - void __cdecl free(void *_Memory); - void *__cdecl malloc(size_t _Size); - void *__cdecl realloc(void *_Memory,size_t _NewSize); - _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - /* _CRTIMP void __cdecl _aligned_free(void *_Memory); - _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ - _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); -#endif - -#define _MAX_WAIT_MALLOC_CRT 60000 - - _CRTIMP int __cdecl _resetstkoflw (void); - _CRTIMP unsigned long __cdecl _set_malloc_crt_max_wait(unsigned long _NewValue); - - _CRTIMP void *__cdecl _expand(void *_Memory,size_t _NewSize); - _CRTIMP size_t __cdecl _msize(void *_Memory); -#ifdef __GNUC__ -#undef _alloca -#define _alloca(x) __builtin_alloca((x)) -#else - /* tcc implements alloca internally and exposes it (since commit d778bde7). - /* alloca is declared at include/stddef.h (which is distributed with tcc). - */ -#ifdef _alloca -#undef _alloca -#endif -#define _alloca(x) alloca((x)) -#endif - _CRTIMP size_t __cdecl _get_sbh_threshold(void); - _CRTIMP int __cdecl _set_sbh_threshold(size_t _NewValue); - _CRTIMP errno_t __cdecl _set_amblksiz(size_t _Value); - _CRTIMP errno_t __cdecl _get_amblksiz(size_t *_Value); - _CRTIMP int __cdecl _heapadd(void *_Memory,size_t _Size); - _CRTIMP int __cdecl _heapchk(void); - _CRTIMP int __cdecl _heapmin(void); - _CRTIMP int __cdecl _heapset(unsigned int _Fill); - _CRTIMP int __cdecl _heapwalk(_HEAPINFO *_EntryInfo); - _CRTIMP size_t __cdecl _heapused(size_t *_Used,size_t *_Commit); - _CRTIMP intptr_t __cdecl _get_heap_handle(void); - -#define _ALLOCA_S_THRESHOLD 1024 -#define _ALLOCA_S_STACK_MARKER 0xCCCC -#define _ALLOCA_S_HEAP_MARKER 0xDDDD - -#if(defined(_X86_) && !defined(__x86_64)) -#define _ALLOCA_S_MARKER_SIZE 8 -#elif defined(__ia64__) || defined(__x86_64) -#define _ALLOCA_S_MARKER_SIZE 16 -#endif - -#if !defined(RC_INVOKED) - static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) { - if(_Ptr) { - *((unsigned int*)_Ptr) = _Marker; - _Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE; - } - return _Ptr; - } -#endif - -#undef _malloca -#define _malloca(size) \ - ((((size) + _ALLOCA_S_MARKER_SIZE) <= _ALLOCA_S_THRESHOLD) ? \ - _MarkAllocaS(_alloca((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_STACK_MARKER) : \ - _MarkAllocaS(malloc((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_HEAP_MARKER)) -#undef _FREEA_INLINE -#define _FREEA_INLINE - -#ifndef RC_INVOKED -#undef _freea - static __inline void __cdecl _freea(void *_Memory) { - unsigned int _Marker; - if(_Memory) { - _Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE; - _Marker = *(unsigned int *)_Memory; - if(_Marker==_ALLOCA_S_HEAP_MARKER) { - free(_Memory); - } -#ifdef _ASSERTE - else if(_Marker!=_ALLOCA_S_STACK_MARKER) { - _ASSERTE(("Corrupted pointer passed to _freea",0)); - } -#endif - } - } -#endif /* RC_INVOKED */ - -#ifndef NO_OLDNAMES -#ifdef __GNUC__ -#undef alloca -#define alloca(x) __builtin_alloca((x)) -#endif -#endif - -#ifdef HEAPHOOK -#ifndef _HEAPHOOK_DEFINED -#define _HEAPHOOK_DEFINED - typedef int (__cdecl *_HEAPHOOK)(int,size_t,void *,void **); -#endif - - _CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK _NewHook); - -#define _HEAP_MALLOC 1 -#define _HEAP_CALLOC 2 -#define _HEAP_FREE 3 -#define _HEAP_REALLOC 4 -#define _HEAP_MSIZE 5 -#define _HEAP_EXPAND 6 -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#endif /* _MALLOC_H_ */ diff --git a/tinyc/win32/include/math.h b/tinyc/win32/include/math.h deleted file mode 100644 index 74add20e9..000000000 --- a/tinyc/win32/include/math.h +++ /dev/null @@ -1,737 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _MATH_H_ -#define _MATH_H_ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - -#include <_mingw.h> - -struct exception; - -#pragma pack(push,_CRT_PACKING) - -#define _DOMAIN 1 -#define _SING 2 -#define _OVERFLOW 3 -#define _UNDERFLOW 4 -#define _TLOSS 5 -#define _PLOSS 6 - -#ifndef __STRICT_ANSI__ -#ifndef NO_OLDNAMES -#define DOMAIN _DOMAIN -#define SING _SING -#define OVERFLOW _OVERFLOW -#define UNDERFLOW _UNDERFLOW -#define TLOSS _TLOSS -#define PLOSS _PLOSS -#endif -#endif - -#ifndef __STRICT_ANSI__ -#define M_E 2.71828182845904523536 -#define M_LOG2E 1.44269504088896340736 -#define M_LOG10E 0.434294481903251827651 -#define M_LN2 0.693147180559945309417 -#define M_LN10 2.30258509299404568402 -#define M_PI 3.14159265358979323846 -#define M_PI_2 1.57079632679489661923 -#define M_PI_4 0.785398163397448309616 -#define M_1_PI 0.318309886183790671538 -#define M_2_PI 0.636619772367581343076 -#define M_2_SQRTPI 1.12837916709551257390 -#define M_SQRT2 1.41421356237309504880 -#define M_SQRT1_2 0.707106781186547524401 -#endif - -#ifndef __STRICT_ANSI__ -/* See also float.h */ -#ifndef __MINGW_FPCLASS_DEFINED -#define __MINGW_FPCLASS_DEFINED 1 -#define _FPCLASS_SNAN 0x0001 /* Signaling "Not a Number" */ -#define _FPCLASS_QNAN 0x0002 /* Quiet "Not a Number" */ -#define _FPCLASS_NINF 0x0004 /* Negative Infinity */ -#define _FPCLASS_NN 0x0008 /* Negative Normal */ -#define _FPCLASS_ND 0x0010 /* Negative Denormal */ -#define _FPCLASS_NZ 0x0020 /* Negative Zero */ -#define _FPCLASS_PZ 0x0040 /* Positive Zero */ -#define _FPCLASS_PD 0x0080 /* Positive Denormal */ -#define _FPCLASS_PN 0x0100 /* Positive Normal */ -#define _FPCLASS_PINF 0x0200 /* Positive Infinity */ -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _EXCEPTION_DEFINED -#define _EXCEPTION_DEFINED - struct _exception { - int type; - char *name; - double arg1; - double arg2; - double retval; - }; -#endif - -#ifndef _COMPLEX_DEFINED -#define _COMPLEX_DEFINED - struct _complex { - double x,y; - }; -#endif - -#define EDOM 33 -#define ERANGE 34 - -#ifndef _HUGE -#ifdef _MSVCRT_ - extern double *_HUGE; -#else - extern double *_imp___HUGE; -#define _HUGE (*_imp___HUGE) -#endif -#endif - -#define HUGE_VAL _HUGE - -#ifndef _CRT_ABS_DEFINED -#define _CRT_ABS_DEFINED - int __cdecl abs(int _X); - long __cdecl labs(long _X); -#endif - double __cdecl acos(double _X); - double __cdecl asin(double _X); - double __cdecl atan(double _X); - double __cdecl atan2(double _Y,double _X); -#ifndef _SIGN_DEFINED -#define _SIGN_DEFINED - _CRTIMP double __cdecl _copysign (double _Number,double _Sign); - _CRTIMP double __cdecl _chgsign (double _X); -#endif - double __cdecl cos(double _X); - double __cdecl cosh(double _X); - double __cdecl exp(double _X); - double __cdecl expm1(double _X); - double __cdecl fabs(double _X); - double __cdecl fmod(double _X,double _Y); - double __cdecl log(double _X); - double __cdecl log10(double _X); - double __cdecl pow(double _X,double _Y); - double __cdecl sin(double _X); - double __cdecl sinh(double _X); - double __cdecl tan(double _X); - double __cdecl tanh(double _X); - double __cdecl sqrt(double _X); -#ifndef _CRT_ATOF_DEFINED -#define _CRT_ATOF_DEFINED - double __cdecl atof(const char *_String); - double __cdecl _atof_l(const char *_String,_locale_t _Locale); -#endif - - _CRTIMP double __cdecl _cabs(struct _complex _ComplexA); - double __cdecl ceil(double _X); - double __cdecl floor(double _X); - double __cdecl frexp(double _X,int *_Y); - double __cdecl _hypot(double _X,double _Y); - _CRTIMP double __cdecl _j0(double _X); - _CRTIMP double __cdecl _j1(double _X); - _CRTIMP double __cdecl _jn(int _X,double _Y); - double __cdecl ldexp(double _X,int _Y); -#ifndef _CRT_MATHERR_DEFINED -#define _CRT_MATHERR_DEFINED - int __cdecl _matherr(struct _exception *_Except); -#endif - double __cdecl modf(double _X,double *_Y); - _CRTIMP double __cdecl _y0(double _X); - _CRTIMP double __cdecl _y1(double _X); - _CRTIMP double __cdecl _yn(int _X,double _Y); - -#if(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _set_SSE2_enable(int _Flag); - /* from libmingwex */ - float __cdecl _hypotf(float _X,float _Y); -#endif - - float frexpf(float _X,int *_Y); - float __cdecl ldexpf(float _X,int _Y); - long double __cdecl ldexpl(long double _X,int _Y); - float __cdecl acosf(float _X); - float __cdecl asinf(float _X); - float __cdecl atanf(float _X); - float __cdecl atan2f(float _X,float _Y); - float __cdecl cosf(float _X); - float __cdecl sinf(float _X); - float __cdecl tanf(float _X); - float __cdecl coshf(float _X); - float __cdecl sinhf(float _X); - float __cdecl tanhf(float _X); - float __cdecl expf(float _X); - float __cdecl expm1f(float _X); - float __cdecl logf(float _X); - float __cdecl log10f(float _X); - float __cdecl modff(float _X,float *_Y); - float __cdecl powf(float _X,float _Y); - float __cdecl sqrtf(float _X); - float __cdecl ceilf(float _X); - float __cdecl floorf(float _X); - float __cdecl fmodf(float _X,float _Y); - float __cdecl _hypotf(float _X,float _Y); - float __cdecl fabsf(float _X); -#if !defined(__ia64__) - /* from libmingwex */ - float __cdecl _copysignf (float _Number,float _Sign); - float __cdecl _chgsignf (float _X); - float __cdecl _logbf(float _X); - float __cdecl _nextafterf(float _X,float _Y); - int __cdecl _finitef(float _X); - int __cdecl _isnanf(float _X); - int __cdecl _fpclassf(float _X); -#endif - -#ifndef __cplusplus - __CRT_INLINE long double __cdecl fabsl (long double x) - { - long double res; - __asm__ ("fabs;" : "=t" (res) : "0" (x)); - return res; - } -#define _hypotl(x,y) ((long double)_hypot((double)(x),(double)(y))) -#define _matherrl _matherr - __CRT_INLINE long double _chgsignl(long double _Number) { return _chgsign((double)(_Number)); } - __CRT_INLINE long double _copysignl(long double _Number,long double _Sign) { return _copysign((double)(_Number),(double)(_Sign)); } - __CRT_INLINE float frexpf(float _X,int *_Y) { return ((float)frexp((double)_X,_Y)); } - -#if !defined (__ia64__) - __CRT_INLINE float __cdecl fabsf (float x) - { - float res; - __asm__ ("fabs;" : "=t" (res) : "0" (x)); - return res; - } - - __CRT_INLINE float __cdecl ldexpf (float x, int expn) { return (float) ldexp (x, expn); } -#endif -#else - // cplusplus - __CRT_INLINE long double __cdecl fabsl (long double x) - { - long double res; - __asm__ ("fabs;" : "=t" (res) : "0" (x)); - return res; - } - __CRT_INLINE long double modfl(long double _X,long double *_Y) { - double _Di,_Df = modf((double)_X,&_Di); - *_Y = (long double)_Di; - return (_Df); - } - __CRT_INLINE long double _chgsignl(long double _Number) { return _chgsign(static_cast(_Number)); } - __CRT_INLINE long double _copysignl(long double _Number,long double _Sign) { return _copysign(static_cast(_Number),static_cast(_Sign)); } - __CRT_INLINE float frexpf(float _X,int *_Y) { return ((float)frexp((double)_X,_Y)); } -#ifndef __ia64__ - __CRT_INLINE float __cdecl fabsf (float x) - { - float res; - __asm__ ("fabs;" : "=t" (res) : "0" (x)); - return res; - } - __CRT_INLINE float __cdecl ldexpf (float x, int expn) { return (float) ldexp (x, expn); } -#ifndef __x86_64 - __CRT_INLINE float acosf(float _X) { return ((float)acos((double)_X)); } - __CRT_INLINE float asinf(float _X) { return ((float)asin((double)_X)); } - __CRT_INLINE float atanf(float _X) { return ((float)atan((double)_X)); } - __CRT_INLINE float atan2f(float _X,float _Y) { return ((float)atan2((double)_X,(double)_Y)); } - __CRT_INLINE float ceilf(float _X) { return ((float)ceil((double)_X)); } - __CRT_INLINE float cosf(float _X) { return ((float)cos((double)_X)); } - __CRT_INLINE float coshf(float _X) { return ((float)cosh((double)_X)); } - __CRT_INLINE float expf(float _X) { return ((float)exp((double)_X)); } - __CRT_INLINE float floorf(float _X) { return ((float)floor((double)_X)); } - __CRT_INLINE float fmodf(float _X,float _Y) { return ((float)fmod((double)_X,(double)_Y)); } - __CRT_INLINE float logf(float _X) { return ((float)log((double)_X)); } - __CRT_INLINE float log10f(float _X) { return ((float)log10((double)_X)); } - __CRT_INLINE float modff(float _X,float *_Y) { - double _Di,_Df = modf((double)_X,&_Di); - *_Y = (float)_Di; - return ((float)_Df); - } - __CRT_INLINE float powf(float _X,float _Y) { return ((float)pow((double)_X,(double)_Y)); } - __CRT_INLINE float sinf(float _X) { return ((float)sin((double)_X)); } - __CRT_INLINE float sinhf(float _X) { return ((float)sinh((double)_X)); } - __CRT_INLINE float sqrtf(float _X) { return ((float)sqrt((double)_X)); } - __CRT_INLINE float tanf(float _X) { return ((float)tan((double)_X)); } - __CRT_INLINE float tanhf(float _X) { return ((float)tanh((double)_X)); } -#endif -#endif -#endif - -#ifndef NO_OLDNAMES -#define matherr _matherr - -#define HUGE _HUGE - /* double __cdecl cabs(struct _complex _X); */ - double __cdecl hypot(double _X,double _Y); - _CRTIMP double __cdecl j0(double _X); - _CRTIMP double __cdecl j1(double _X); - _CRTIMP double __cdecl jn(int _X,double _Y); - _CRTIMP double __cdecl y0(double _X); - _CRTIMP double __cdecl y1(double _X); - _CRTIMP double __cdecl yn(int _X,double _Y); -#endif - -#ifndef __NO_ISOCEXT -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ - || !defined __STRICT_ANSI__ || defined __GLIBCPP__ - -#define NAN (0.0F/0.0F) -#define HUGE_VALF (1.0F/0.0F) -#define HUGE_VALL (1.0L/0.0L) -#define INFINITY (1.0F/0.0F) - - -#define FP_NAN 0x0100 -#define FP_NORMAL 0x0400 -#define FP_INFINITE (FP_NAN | FP_NORMAL) -#define FP_ZERO 0x4000 -#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) - /* 0x0200 is signbit mask */ - - - /* - We can't __CRT_INLINE float or double, because we want to ensure truncation - to semantic type before classification. - (A normal long double value might become subnormal when - converted to double, and zero when converted to float.) - */ - - extern int __cdecl __fpclassifyf (float); - extern int __cdecl __fpclassify (double); - extern int __cdecl __fpclassifyl (long double); - -/* Implemented at tcc/tcc_libm.h */ -#define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x) \ - : sizeof (x) == sizeof (double) ? __fpclassify (x) \ - : __fpclassifyl (x)) - - /* 7.12.3.2 */ -#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0) - - /* 7.12.3.3 */ -#define isinf(x) (fpclassify(x) == FP_INFINITE) - - /* 7.12.3.4 */ - /* We don't need to worry about truncation here: - A NaN stays a NaN. */ -#define isnan(x) (fpclassify(x) == FP_NAN) - - /* 7.12.3.5 */ -#define isnormal(x) (fpclassify(x) == FP_NORMAL) - - /* 7.12.3.6 The signbit macro */ - - extern int __cdecl __signbitf (float); - extern int __cdecl __signbit (double); - extern int __cdecl __signbitl (long double); - -/* Implemented at tcc/tcc_libm.h */ -#define signbit(x) (sizeof (x) == sizeof (float) ? __signbitf (x) \ - : sizeof (x) == sizeof (double) ? __signbit (x) \ - : __signbitl (x)) - - extern double __cdecl exp2(double); - extern float __cdecl exp2f(float); - extern long double __cdecl exp2l(long double); - -#define FP_ILOGB0 ((int)0x80000000) -#define FP_ILOGBNAN ((int)0x80000000) - extern int __cdecl ilogb (double); - extern int __cdecl ilogbf (float); - extern int __cdecl ilogbl (long double); - - extern double __cdecl log1p(double); - extern float __cdecl log1pf(float); - extern long double __cdecl log1pl(long double); - - extern double __cdecl log2 (double); - extern float __cdecl log2f (float); - extern long double __cdecl log2l (long double); - - extern double __cdecl logb (double); - extern float __cdecl logbf (float); - extern long double __cdecl logbl (long double); - - __CRT_INLINE double __cdecl logb (double x) - { - double res; - __asm__ ("fxtract\n\t" - "fstp %%st" : "=t" (res) : "0" (x)); - return res; - } - - __CRT_INLINE float __cdecl logbf (float x) - { - float res; - __asm__ ("fxtract\n\t" - "fstp %%st" : "=t" (res) : "0" (x)); - return res; - } - - __CRT_INLINE long double __cdecl logbl (long double x) - { - long double res; - __asm__ ("fxtract\n\t" - "fstp %%st" : "=t" (res) : "0" (x)); - return res; - } - - extern long double __cdecl modfl (long double, long double*); - - /* 7.12.6.13 */ - extern double __cdecl scalbn (double, int); - extern float __cdecl scalbnf (float, int); - extern long double __cdecl scalbnl (long double, int); - - extern double __cdecl scalbln (double, long); - extern float __cdecl scalblnf (float, long); - extern long double __cdecl scalblnl (long double, long); - - /* 7.12.7.1 */ - /* Implementations adapted from Cephes versions */ - extern double __cdecl cbrt (double); - extern float __cdecl cbrtf (float); - extern long double __cdecl cbrtl (long double); - - __CRT_INLINE float __cdecl hypotf (float x, float y) - { return (float) hypot (x, y);} - extern long double __cdecl hypotl (long double, long double); - - extern long double __cdecl powl (long double, long double); - extern long double __cdecl expl(long double); - extern long double __cdecl expm1l(long double); - extern long double __cdecl coshl(long double); - extern long double __cdecl fabsl (long double); - extern long double __cdecl acosl(long double); - extern long double __cdecl asinl(long double); - extern long double __cdecl atanl(long double); - extern long double __cdecl atan2l(long double,long double); - extern long double __cdecl sinhl(long double); - extern long double __cdecl tanhl(long double); - - /* 7.12.8.1 The erf functions */ - extern double __cdecl erf (double); - extern float __cdecl erff (float); - /* TODO - extern long double __cdecl erfl (long double); - */ - - /* 7.12.8.2 The erfc functions */ - extern double __cdecl erfc (double); - extern float __cdecl erfcf (float); - /* TODO - extern long double __cdecl erfcl (long double); - */ - - /* 7.12.8.3 The lgamma functions */ - extern double __cdecl lgamma (double); - extern float __cdecl lgammaf (float); - extern long double __cdecl lgammal (long double); - - /* 7.12.8.4 The tgamma functions */ - extern double __cdecl tgamma (double); - extern float __cdecl tgammaf (float); - extern long double __cdecl tgammal (long double); - - extern long double __cdecl ceill (long double); - extern long double __cdecl floorl (long double); - extern long double __cdecl frexpl(long double,int *); - extern long double __cdecl log10l(long double); - extern long double __cdecl logl(long double); - extern long double __cdecl cosl(long double); - extern long double __cdecl sinl(long double); - extern long double __cdecl tanl(long double); - extern long double sqrtl(long double); - - /* 7.12.9.3 */ - extern double __cdecl nearbyint ( double); - extern float __cdecl nearbyintf (float); - extern long double __cdecl nearbyintl (long double); - - /* 7.12.9.4 */ - /* round, using fpu control word settings */ - __CRT_INLINE double __cdecl rint (double x) - { - double retval; - __asm__ ( - "fldl %1\n" - "frndint \n" - "fstl %0\n" : "=m" (retval) : "m" (x)); - return retval; - } - - __CRT_INLINE float __cdecl rintf (float x) - { - float retval; - __asm__ ( - "flds %1\n" - "frndint \n" - "fsts %0\n" : "=m" (retval) : "m" (x)); - return retval; - } - - __CRT_INLINE long double __cdecl rintl (long double x) - { - long double retval; - __asm__ ( - "fldt %1\n" - "frndint \n" - "fstt %0\n" : "=m" (retval) : "m" (x)); - return retval; - } - - /* 7.12.9.5 */ - __CRT_INLINE long __cdecl lrint (double x) - { - long retval; - __asm__ __volatile__ \ - ("fldl %1\n" \ - "fistpl %0" : "=m" (retval) : "m" (x)); \ - return retval; - } - - __CRT_INLINE long __cdecl lrintf (float x) - { - long retval; - __asm__ __volatile__ \ - ("flds %1\n" \ - "fistpl %0" : "=m" (retval) : "m" (x)); \ - return retval; - } - - __CRT_INLINE long __cdecl lrintl (long double x) - { - long retval; - __asm__ __volatile__ \ - ("fldt %1\n" \ - "fistpl %0" : "=m" (retval) : "m" (x)); \ - return retval; - } - - __CRT_INLINE long long __cdecl llrint (double x) - { - long long retval; - __asm__ __volatile__ \ - ("fldl %1\n" \ - "fistpll %0" : "=m" (retval) : "m" (x)); \ - return retval; - } - - __CRT_INLINE long long __cdecl llrintf (float x) - { - long long retval; - __asm__ __volatile__ \ - ("flds %1\n" \ - "fistpll %0" : "=m" (retval) : "m" (x)); \ - return retval; - } - - __CRT_INLINE long long __cdecl llrintl (long double x) - { - long long retval; - __asm__ __volatile__ \ - ("fldt %1\n" \ - "fistpll %0" : "=m" (retval) : "m" (x)); \ - return retval; - } - - #define FE_TONEAREST 0x0000 - #define FE_DOWNWARD 0x0400 - #define FE_UPWARD 0x0800 - #define FE_TOWARDZERO 0x0c00 - - __CRT_INLINE double trunc (double _x) - { - double retval; - unsigned short saved_cw; - unsigned short tmp_cw; - __asm__ ("fnstcw %0;" : "=m" (saved_cw)); /* save FPU control word */ - tmp_cw = (saved_cw & ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)) - | FE_TOWARDZERO; - __asm__ ("fldcw %0;" : : "m" (tmp_cw)); - __asm__ ("fldl %1;" - "frndint;" - "fstl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */ - __asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */ - return retval; - } - - /* 7.12.9.6 */ - /* round away from zero, regardless of fpu control word settings */ - extern double __cdecl round (double); - extern float __cdecl roundf (float); - extern long double __cdecl roundl (long double); - - /* 7.12.9.7 */ - extern long __cdecl lround (double); - extern long __cdecl lroundf (float); - extern long __cdecl lroundl (long double); - - extern long long __cdecl llround (double); - extern long long __cdecl llroundf (float); - extern long long __cdecl llroundl (long double); - - /* 7.12.9.8 */ - /* round towards zero, regardless of fpu control word settings */ - extern double __cdecl trunc (double); - extern float __cdecl truncf (float); - extern long double __cdecl truncl (long double); - - extern long double __cdecl fmodl (long double, long double); - - /* 7.12.10.2 */ - extern double __cdecl remainder (double, double); - extern float __cdecl remainderf (float, float); - extern long double __cdecl remainderl (long double, long double); - - /* 7.12.10.3 */ - extern double __cdecl remquo(double, double, int *); - extern float __cdecl remquof(float, float, int *); - extern long double __cdecl remquol(long double, long double, int *); - - /* 7.12.11.1 */ - extern double __cdecl copysign (double, double); /* in libmoldname.a */ - extern float __cdecl copysignf (float, float); - extern long double __cdecl copysignl (long double, long double); - - /* 7.12.11.2 Return a NaN */ - extern double __cdecl nan(const char *tagp); - extern float __cdecl nanf(const char *tagp); - extern long double __cdecl nanl(const char *tagp); - -#ifndef __STRICT_ANSI__ -#define _nan() nan("") -#define _nanf() nanf("") -#define _nanl() nanl("") -#endif - - /* 7.12.11.3 */ - extern double __cdecl nextafter (double, double); /* in libmoldname.a */ - extern float __cdecl nextafterf (float, float); - extern long double __cdecl nextafterl (long double, long double); - - /* 7.12.11.4 The nexttoward functions: TODO */ - - /* 7.12.12.1 */ - /* x > y ? (x - y) : 0.0 */ - extern double __cdecl fdim (double x, double y); - extern float __cdecl fdimf (float x, float y); - extern long double __cdecl fdiml (long double x, long double y); - - /* fmax and fmin. - NaN arguments are treated as missing data: if one argument is a NaN - and the other numeric, then these functions choose the numeric - value. */ - - /* 7.12.12.2 */ - extern double __cdecl fmax (double, double); - extern float __cdecl fmaxf (float, float); - extern long double __cdecl fmaxl (long double, long double); - - /* 7.12.12.3 */ - extern double __cdecl fmin (double, double); - extern float __cdecl fminf (float, float); - extern long double __cdecl fminl (long double, long double); - - /* 7.12.13.1 */ - /* return x * y + z as a ternary op */ - extern double __cdecl fma (double, double, double); - extern float __cdecl fmaf (float, float, float); - extern long double __cdecl fmal (long double, long double, long double); - - -#if 0 // gr: duplicate, see below - /* 7.12.14 */ - /* - * With these functions, comparisons involving quiet NaNs set the FP - * condition code to "unordered". The IEEE floating-point spec - * dictates that the result of floating-point comparisons should be - * false whenever a NaN is involved, with the exception of the != op, - * which always returns true: yes, (NaN != NaN) is true). - */ - -#if __GNUC__ >= 3 - -#define isgreater(x, y) __builtin_isgreater(x, y) -#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y) -#define isless(x, y) __builtin_isless(x, y) -#define islessequal(x, y) __builtin_islessequal(x, y) -#define islessgreater(x, y) __builtin_islessgreater(x, y) -#define isunordered(x, y) __builtin_isunordered(x, y) - -#else - /* helper */ - __CRT_INLINE int __cdecl - __fp_unordered_compare (long double x, long double y){ - unsigned short retval; - __asm__ ("fucom %%st(1);" - "fnstsw;": "=a" (retval) : "t" (x), "u" (y)); - return retval; - } - -#define isgreater(x, y) ((__fp_unordered_compare(x, y) \ - & 0x4500) == 0) -#define isless(x, y) ((__fp_unordered_compare (y, x) \ - & 0x4500) == 0) -#define isgreaterequal(x, y) ((__fp_unordered_compare (x, y) \ - & FP_INFINITE) == 0) -#define islessequal(x, y) ((__fp_unordered_compare(y, x) \ - & FP_INFINITE) == 0) -#define islessgreater(x, y) ((__fp_unordered_compare(x, y) \ - & FP_SUBNORMAL) == 0) -#define isunordered(x, y) ((__fp_unordered_compare(x, y) \ - & 0x4500) == 0x4500) - -#endif -#endif //0 - - -#endif /* __STDC_VERSION__ >= 199901L */ -#endif /* __NO_ISOCEXT */ - -#ifdef __cplusplus -} -extern "C++" { - template inline _Ty _Pow_int(_Ty _X,int _Y) { - unsigned int _N; - if(_Y >= 0) _N = (unsigned int)_Y; - else _N = (unsigned int)(-_Y); - for(_Ty _Z = _Ty(1);;_X *= _X) { - if((_N & 1)!=0) _Z *= _X; - if((_N >>= 1)==0) return (_Y < 0 ? _Ty(1) / _Z : _Z); - } - } -} -#endif - -#pragma pack(pop) - -/* 7.12.14 */ -/* - * With these functions, comparisons involving quiet NaNs set the FP - * condition code to "unordered". The IEEE floating-point spec - * dictates that the result of floating-point comparisons should be - * false whenever a NaN is involved, with the exception of the != op, - * which always returns true: yes, (NaN != NaN) is true). - */ - -/* Mini libm (inline __fpclassify*, __signbit* and variants) */ -#include "tcc/tcc_libm.h" - -#endif /* End _MATH_H_ */ - diff --git a/tinyc/win32/include/mem.h b/tinyc/win32/include/mem.h deleted file mode 100644 index 255202359..000000000 --- a/tinyc/win32/include/mem.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * mem.h maps to string.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif diff --git a/tinyc/win32/include/memory.h b/tinyc/win32/include/memory.h deleted file mode 100644 index 90d88aedd..000000000 --- a/tinyc/win32/include/memory.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_MEMORY -#define _INC_MEMORY - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CONST_RETURN -#define _CONST_RETURN -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_MEMORY_DEFINED -#define _CRT_MEMORY_DEFINED - _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); - _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); - _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); - _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); - int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); - void *__cdecl memset(void *_Dst,int _Val,size_t _Size); - -#ifndef NO_OLDNAMES - void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); - int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/process.h b/tinyc/win32/include/process.h deleted file mode 100644 index dadaf2b7d..000000000 --- a/tinyc/win32/include/process.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_PROCESS -#define _INC_PROCESS - -#include <_mingw.h> - -/* Includes a definition of _pid_t and pid_t */ -#include - -#ifndef _POSIX_ -#ifdef __cplusplus -extern "C" { -#endif - -#define _P_WAIT 0 -#define _P_NOWAIT 1 -#define _OLD_P_OVERLAY 2 -#define _P_NOWAITO 3 -#define _P_DETACH 4 -#define _P_OVERLAY 2 - -#define _WAIT_CHILD 0 -#define _WAIT_GRANDCHILD 1 - - _CRTIMP uintptr_t __cdecl _beginthread(void (__cdecl *_StartAddress) (void *),unsigned _StackSize,void *_ArgList); - _CRTIMP void __cdecl _endthread(void); - _CRTIMP uintptr_t __cdecl _beginthreadex(void *_Security,unsigned _StackSize,unsigned (__stdcall *_StartAddress) (void *),void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr); - _CRTIMP void __cdecl _endthreadex(unsigned _Retval); - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - - _CRTIMP void __cdecl __MINGW_NOTHROW _cexit(void); - _CRTIMP void __cdecl __MINGW_NOTHROW _c_exit(void); - _CRTIMP int __cdecl _getpid(void); - _CRTIMP intptr_t __cdecl _cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); - _CRTIMP intptr_t __cdecl _execl(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execle(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execlp(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execlpe(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execv(const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _execve(const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _execvp(const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _execvpe(const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _spawnl(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnle(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnlp(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnlpe(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnv(int _Mode,const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _spawnve(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _spawnvp(int _Mode,const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _spawnvpe(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); - -#ifndef _CRT_SYSTEM_DEFINED -#define _CRT_SYSTEM_DEFINED - int __cdecl system(const char *_Command); -#endif - -#ifndef _WPROCESS_DEFINED -#define _WPROCESS_DEFINED - _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif -#endif - - void __cdecl __security_init_cookie(void); -#if (defined(_X86_) && !defined(__x86_64)) - void __fastcall __security_check_cookie(uintptr_t _StackCookie); - __declspec(noreturn) void __cdecl __report_gsfailure(void); -#else - void __cdecl __security_check_cookie(uintptr_t _StackCookie); - __declspec(noreturn) void __cdecl __report_gsfailure(uintptr_t _StackCookie); -#endif - extern uintptr_t __security_cookie; - - intptr_t __cdecl _loaddll(char *_Filename); - int __cdecl _unloaddll(intptr_t _Handle); - int (__cdecl *__cdecl _getdllprocaddr(intptr_t _Handle,char *_ProcedureName,intptr_t _Ordinal))(void); - -#ifdef _DECL_DLLMAIN -#ifdef _WINDOWS_ - WINBOOL WINAPI DllMain(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - WINBOOL WINAPI _CRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - WINBOOL WINAPI _wCRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - extern WINBOOL (WINAPI *const _pRawDllMain)(HANDLE,DWORD,LPVOID); -#else - int __stdcall DllMain(void *_HDllHandle,unsigned _Reason,void *_Reserved); - int __stdcall _CRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); - int __stdcall _wCRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); - extern int (__stdcall *const _pRawDllMain)(void *,unsigned,void *); -#endif -#endif - -#ifndef NO_OLDNAMES -#define P_WAIT _P_WAIT -#define P_NOWAIT _P_NOWAIT -#define P_OVERLAY _P_OVERLAY -#define OLD_P_OVERLAY _OLD_P_OVERLAY -#define P_NOWAITO _P_NOWAITO -#define P_DETACH _P_DETACH -#define WAIT_CHILD _WAIT_CHILD -#define WAIT_GRANDCHILD _WAIT_GRANDCHILD - - intptr_t __cdecl cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); -#ifdef __GNUC__ - int __cdecl execl(const char *_Filename,const char *_ArgList,...); - int __cdecl execle(const char *_Filename,const char *_ArgList,...); - int __cdecl execlp(const char *_Filename,const char *_ArgList,...); - int __cdecl execlpe(const char *_Filename,const char *_ArgList,...); -#else - intptr_t __cdecl execl(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execle(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execlp(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execlpe(const char *_Filename,const char *_ArgList,...); -#endif - intptr_t __cdecl spawnl(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnle(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnlp(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnlpe(int,const char *_Filename,const char *_ArgList,...); - int __cdecl getpid(void); -#ifdef __GNUC__ - /* Those methods are predefined by gcc builtins to return int. So to prevent - stupid warnings, define them in POSIX way. This is save, because those - methods do not return in success case, so that the return value is not - really dependent to its scalar width. */ - int __cdecl execv(const char *_Filename,const char *const _ArgList[]); - int __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - int __cdecl execvp(const char *_Filename,const char *const _ArgList[]); - int __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); -#else - intptr_t __cdecl execv(const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - intptr_t __cdecl execvp(const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); -#endif - intptr_t __cdecl spawnv(int,const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl spawnve(int,const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - intptr_t __cdecl spawnvp(int,const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl spawnvpe(int,const char *_Filename,const char *const _ArgList[],char *const _Env[]); -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/tinyc/win32/include/sec_api/conio_s.h b/tinyc/win32/include/sec_api/conio_s.h deleted file mode 100644 index 98d97ba2e..000000000 --- a/tinyc/win32/include/sec_api/conio_s.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_CONIO_S -#define _INC_CONIO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _cgets_s(char *_Buffer,size_t _Size,size_t *_SizeRead); - _CRTIMP int __cdecl _cprintf_s(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_s(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_s(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - -#ifndef _WCONIO_DEFINED_S -#define _WCONIO_DEFINED_S - _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); - _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/sec_api/crtdbg_s.h b/tinyc/win32/include/sec_api/crtdbg_s.h deleted file mode 100644 index 4598b4f7c..000000000 --- a/tinyc/win32/include/sec_api/crtdbg_s.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_CRTDBG_S -#define _INC_CRTDBG_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#define _dupenv_s_dbg(ps1,size,s2,t,f,l) _dupenv_s(ps1,size,s2) -#define _wdupenv_s_dbg(ps1,size,s2,t,f,l) _wdupenv_s(ps1,size,s2) - -#endif - -#endif diff --git a/tinyc/win32/include/sec_api/io_s.h b/tinyc/win32/include/sec_api/io_s.h deleted file mode 100644 index ec565a617..000000000 --- a/tinyc/win32/include/sec_api/io_s.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_IO_S -#define _INC_IO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _access_s(const char *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _chsize_s(int _FileHandle,__int64 _Size); - _CRTIMP errno_t __cdecl _mktemp_s(char *_TemplateName,size_t _Size); - _CRTIMP errno_t __cdecl _umask_s(int _NewMode,int *_OldMode); - -#ifndef _WIO_S_DEFINED -#define _WIO_S_DEFINED - _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/sec_api/mbstring_s.h b/tinyc/win32/include/sec_api/mbstring_s.h deleted file mode 100644 index 6b2b188f8..000000000 --- a/tinyc/win32/include/sec_api/mbstring_s.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_MBSTRING_S -#define _INC_MBSTRING_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _MBSTRING_S_DEFINED -#define _MBSTRING_S_DEFINED - _CRTIMP errno_t __cdecl _mbscat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbscat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbscpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbslwr_s(unsigned char *_Str,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _mbslwr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbcat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbcpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsncat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsncat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsncpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val); - _CRTIMP errno_t __cdecl _mbsset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,_locale_t _Locale); - _CRTIMP unsigned char *__cdecl _mbstok_s(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context); - _CRTIMP unsigned char *__cdecl _mbstok_s_l(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsupr_s(unsigned char *_Str,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _mbsupr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbccpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbccpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src,_locale_t _Locale); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/sec_api/search_s.h b/tinyc/win32/include/sec_api/search_s.h deleted file mode 100644 index cae899898..000000000 --- a/tinyc/win32/include/sec_api/search_s.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SEARCH_S -#define _INC_SEARCH_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP void *__cdecl _lfind_s(const void *_Key,const void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); - _CRTIMP void *__cdecl _lsearch_s(const void *_Key,void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/sec_api/stdio_s.h b/tinyc/win32/include/sec_api/stdio_s.h deleted file mode 100644 index c9b803b12..000000000 --- a/tinyc/win32/include/sec_api/stdio_s.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDIO_S -#define _INC_STDIO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _STDIO_S_DEFINED -#define _STDIO_S_DEFINED - _CRTIMP errno_t __cdecl clearerr_s(FILE *_File); - int __cdecl fprintf_s(FILE *_File,const char *_Format,...); - size_t __cdecl fread_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _fscanf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - int __cdecl printf_s(const char *_Format,...); - _CRTIMP int __cdecl _scanf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scanf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _snprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _vsnprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - int __cdecl sprintf_s(char *_DstBuf,size_t _DstSize,const char *_Format,...); - _CRTIMP int __cdecl _fscanf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sscanf_l(const char *_Src,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sscanf_s_l(const char *_Src,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snscanf_s(const char *_Src,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _snscanf_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snscanf_s_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - int __cdecl vfprintf_s(FILE *_File,const char *_Format,va_list _ArgList); - int __cdecl vprintf_s(const char *_Format,va_list _ArgList); - int __cdecl vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); - int __cdecl vsprintf_s(char *_DstBuf,size_t _Size,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_p(FILE *_File,const char *_Format,...); - _CRTIMP int __cdecl _printf_p(const char *_Format,...); - _CRTIMP int __cdecl _sprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _vfprintf_p(FILE *_File,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vsprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scprintf_p(const char *_Format,...); - _CRTIMP int __cdecl _vscprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _printf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _printf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _sprintf_l(char *_DstBuf,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsprintf_l(char *_DstBuf,const char *_Format,_locale_t,va_list _ArgList); - _CRTIMP int __cdecl _vsprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scprintf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scprintf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vscprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _printf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _sprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vsnprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *,_locale_t _Locale,va_list _ArgList); - -#ifndef _WSTDIO_S_DEFINED -#define _WSTDIO_S_DEFINED - _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); - int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf_s(const wchar_t *_Format,...); - int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); - int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); - int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); - _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); - _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); - _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); -#endif -#endif - - _CRTIMP size_t __cdecl _fread_nolock_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/tinyc/win32/include/sec_api/stdlib_s.h b/tinyc/win32/include/sec_api/stdlib_s.h deleted file mode 100644 index f98262ccc..000000000 --- a/tinyc/win32/include/sec_api/stdlib_s.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDLIB_S -#define _INC_STDLIB_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _dupenv_s(char **_PBuffer,size_t *_PBufferSizeInBytes,const char *_VarName); - _CRTIMP errno_t __cdecl _itoa_s(int _Value,char *_DstBuf,size_t _Size,int _Radix); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64toa_s(__int64 _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl _ui64toa_s(unsigned __int64 _Val,char *_DstBuf,size_t _Size,int _Radix); -#endif - _CRTIMP errno_t __cdecl _ltoa_s(long _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl mbstowcs_s(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbstowcs_s_l(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _ultoa_s(unsigned long _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl _wctomb_s_l(int *_SizeConverted,char *_MbCh,size_t _SizeInBytes,wchar_t _WCh,_locale_t _Locale); - _CRTIMP errno_t __cdecl wcstombs_s(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes); - _CRTIMP errno_t __cdecl _wcstombs_s_l(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes,_locale_t _Locale); - -#ifndef _WSTDLIB_S_DEFINED -#define _WSTDLIB_S_DEFINED - _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); - _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); -#endif -#endif - -#ifndef _POSIX_ - _CRTIMP errno_t __cdecl _ecvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDights,int *_PtDec,int *_PtSign); - _CRTIMP errno_t __cdecl _fcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - _CRTIMP errno_t __cdecl _gcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDigits); - _CRTIMP errno_t __cdecl _makepath_s(char *_PathResult,size_t _Size,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); - _CRTIMP errno_t __cdecl _putenv_s(const char *_Name,const char *_Value); - _CRTIMP errno_t __cdecl _searchenv_s(const char *_Filename,const char *_EnvVar,char *_ResultPath,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _splitpath_s(const char *_FullPath,char *_Drive,size_t _DriveSize,char *_Dir,size_t _DirSize,char *_Filename,size_t _FilenameSize,char *_Ext,size_t _ExtSize); - -#ifndef _WSTDLIBP_S_DEFINED -#define _WSTDLIBP_S_DEFINED - _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); - _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); - _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/sec_api/stralign_s.h b/tinyc/win32/include/sec_api/stralign_s.h deleted file mode 100644 index 5b78f5860..000000000 --- a/tinyc/win32/include/sec_api/stralign_s.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __STRALIGN_H_S_ -#define __STRALIGN_H_S_ - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(I_X86_) && defined(_WSTRING_S_DEFINED) -#if defined(__cplusplus) && defined(_WConst_Return) - static __inline PUWSTR ua_wcscpy_s(PUWSTR Destination,size_t DestinationSize,PCUWSTR Source) { - if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return (wcscpy_s((PWSTR)Destination,DestinationSize,(PCWSTR)Source)==0 ? Destination : NULL); - return uaw_wcscpy((PCUWSTR)String,Character); - } -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/tinyc/win32/include/sec_api/string_s.h b/tinyc/win32/include/sec_api/string_s.h deleted file mode 100644 index 9db70e77d..000000000 --- a/tinyc/win32/include/sec_api/string_s.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STRING_S -#define _INC_STRING_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _strset_s(char *_Dst,size_t _DstSize,int _Value); - _CRTIMP errno_t __cdecl _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg); - _CRTIMP errno_t __cdecl _strlwr_s(char *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale); - _CRTIMP errno_t __cdecl _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _strupr_s(char *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale); -#ifndef _WSTRING_S_DEFINED -#define _WSTRING_S_DEFINED - _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); - _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); - _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); - _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); - _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); - _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/tinyc/win32/include/sec_api/sys/timeb_s.h b/tinyc/win32/include/sec_api/sys/timeb_s.h deleted file mode 100644 index af5ef098f..000000000 --- a/tinyc/win32/include/sec_api/sys/timeb_s.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _TIMEB_H_S -#define _TIMEB_H_S - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef _USE_32BIT_TIME_T -#define _ftime_s _ftime32_s -#else -#define _ftime_s _ftime64_s -#endif - - _CRTIMP errno_t __cdecl _ftime32_s(struct __timeb32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _ftime64_s(struct __timeb64 *_Time); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tinyc/win32/include/sec_api/tchar_s.h b/tinyc/win32/include/sec_api/tchar_s.h deleted file mode 100644 index 343d348eb..000000000 --- a/tinyc/win32/include/sec_api/tchar_s.h +++ /dev/null @@ -1,266 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_TCHAR_S -#define _INC_TCHAR_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _UNICODE - -#define _tprintf_s wprintf_s -#define _tprintf_s_l _wprintf_s_l -#define _tcprintf_s _cwprintf_s -#define _tcprintf_s_l _cwprintf_s_l -#define _vtcprintf_s _vcwprintf_s -#define _vtcprintf_s_l _vcwprintf_s_l -#define _ftprintf_s fwprintf_s -#define _ftprintf_s_l _fwprintf_s_l -#define _stprintf_s swprintf_s -#define _stprintf_s_l _swprintf_s_l -#define _sntprintf_s _snwprintf_s -#define _sntprintf_s_l _snwprintf_s_l -#define _vtprintf_s vwprintf_s -#define _vtprintf_s_l _vwprintf_s_l -#define _vftprintf_s vfwprintf_s -#define _vftprintf_s_l _vfwprintf_s_l -#define _vstprintf_s vswprintf_s -#define _vstprintf_s_l _vswprintf_s_l -#define _vsntprintf_s _vsnwprintf_s -#define _vsntprintf_s_l _vsnwprintf_s_l - -#define _tscanf_s wscanf_s -#define _tscanf_s_l _wscanf_s_l -#define _tcscanf_s _cwscanf_s -#define _tcscanf_s_l _cwscanf_s_l -#define _ftscanf_s fwscanf_s -#define _ftscanf_s_l _fwscanf_s_l -#define _stscanf_s swscanf_s -#define _stscanf_s_l _swscanf_s_l -#define _sntscanf_s _snwscanf_s -#define _sntscanf_s_l _snwscanf_s_l - -#define _cgetts_s _cgetws_s -#define _getts_s _getws_s - -#define _itot_s _itow_s -#define _ltot_s _ltow_s -#define _ultot_s _ultow_s -#define _i64tot_s _i64tow_s -#define _ui64tot_s _ui64tow_s - -#define _tcscat_s wcscat_s -#define _tcscpy_s wcscpy_s -#define _tcsncat_s wcsncat_s -#define _tcsncat_s_l _wcsncat_s_l -#define _tcsncpy_s wcsncpy_s -#define _tcsncpy_s_l _wcsncpy_s_l -#define _tcstok_s wcstok_s -#define _tcstok_s_l _wcstok_s_l -#define _tcserror_s _wcserror_s -#define __tcserror_s __wcserror_s - -#define _tcsnset_s _wcsnset_s -#define _tcsnset_s_l _wcsnset_s_l -#define _tcsset_s _wcsset_s -#define _tcsset_s_l _wcsset_s_l - -#define _tasctime_s _wasctime_s -#define _tctime_s _wctime_s -#define _tctime32_s _wctime32_s -#define _tctime64_s _wctime64_s -#define _tstrdate_s _wstrdate_s -#define _tstrtime_s _wstrtime_s - -#define _tgetenv_s _wgetenv_s -#define _tdupenv_s _wdupenv_s -#define _tmakepath_s _wmakepath_s -#define _tputenv_s _wputenv_s -#define _tsearchenv_s _wsearchenv_s -#define _tsplitpath_s _wsplitpath_s - -#define _tfopen_s _wfopen_s -#define _tfreopen_s _wfreopen_s -#define _ttmpnam_s _wtmpnam_s -#define _taccess_s _waccess_s -#define _tmktemp_s _wmktemp_s - -#define _tcsnccat_s wcsncat_s -#define _tcsnccat_s_l _wcsncat_s_l -#define _tcsnccpy_s wcsncpy_s -#define _tcsnccpy_s_l _wcsncpy_s_l - -#define _tcslwr_s _wcslwr_s -#define _tcslwr_s_l _wcslwr_s_l -#define _tcsupr_s _wcsupr_s -#define _tcsupr_s_l _wcsupr_s_l - -#define _wcstok_s_l(_String,_Delimiters,_Current_position,_Locale) (wcstok_s(_String,_Delimiters,_Current_position)) -#define _wcsnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_wcsnset_s(_Destination,_Destination_size_chars,_Value,_Count)) -#define _wcsset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_wcsset_s(_Destination,_Destination_size_chars,_Value)) - -#else - -#define _tprintf_s printf_s -#define _tprintf_s_l _printf_s_l -#define _tcprintf_s _cprintf_s -#define _tcprintf_s_l _cprintf_s_l -#define _vtcprintf_s _vcprintf_s -#define _vtcprintf_s_l _vcprintf_s_l -#define _ftprintf_s fprintf_s -#define _ftprintf_s_l _fprintf_s_l -#define _stprintf_s sprintf_s -#define _stprintf_s_l _sprintf_s_l -#define _sntprintf_s _snprintf_s -#define _sntprintf_s_l _snprintf_s_l -#define _vtprintf_s vprintf_s -#define _vtprintf_s_l _vprintf_s_l -#define _vftprintf_s vfprintf_s -#define _vftprintf_s_l _vfprintf_s_l -#define _vstprintf_s vsprintf_s -#define _vstprintf_s_l _vsprintf_s_l -#define _vsntprintf_s _vsnprintf_s -#define _vsntprintf_s_l _vsnprintf_s_l -#define _tscanf_s scanf_s -#define _tscanf_s_l _scanf_s_l -#define _tcscanf_s _cscanf_s -#define _tcscanf_s_l _cscanf_s_l -#define _ftscanf_s fscanf_s -#define _ftscanf_s_l _fscanf_s_l -#define _stscanf_s sscanf_s -#define _stscanf_s_l _sscanf_s_l -#define _sntscanf_s _snscanf_s -#define _sntscanf_s_l _snscanf_s_l - -#define _getts_s gets_s -#define _cgetts_s _cgets_s -#define _itot_s _itoa_s -#define _ltot_s _ltoa_s -#define _ultot_s _ultoa_s -#define _i64tot_s _i64toa_s -#define _ui64tot_s _ui64toa_s - -#define _tcscat_s strcat_s -#define _tcscpy_s strcpy_s -#define _tcserror_s strerror_s -#define __tcserror_s _strerror_s - -#define _tasctime_s asctime_s -#define _tctime_s ctime_s -#define _tctime32_s _ctime32_s -#define _tctime64_s _ctime64_s -#define _tstrdate_s _strdate_s -#define _tstrtime_s _strtime_s - -#define _tgetenv_s getenv_s -#define _tdupenv_s _dupenv_s -#define _tmakepath_s _makepath_s -#define _tputenv_s _putenv_s -#define _tsearchenv_s _searchenv_s -#define _tsplitpath_s _splitpath_s - -#define _tfopen_s fopen_s -#define _tfreopen_s freopen_s -#define _ttmpnam_s tmpnam_s -#define _tmktemp_s _mktemp_s - -#ifndef _POSIX_ -#define _taccess_s _access_s -#endif - -#define _tsopen_s _sopen_s - -#ifdef _MBCS - -#ifdef _MB_MAP_DIRECT - -#define _tcsncat_s _mbsnbcat_s -#define _tcsncat_s_l _mbsnbcat_s_l -#define _tcsncpy_s _mbsnbcpy_s -#define _tcsncpy_s_l _mbsnbcpy_s_l -#define _tcstok_s _mbstok_s -#define _tcstok_s_l _mbstok_s_l - -#define _tcsnset_s _mbsnbset_s -#define _tcsnset_s_l _mbsnbset_s_l -#define _tcsset_s _mbsset_s -#define _tcsset_s_l _mbsset_s_l - -#define _tcsnccat_s _mbsncat_s -#define _tcsnccat_s_l _mbsncat_s_l -#define _tcsnccpy_s _mbsncpy_s -#define _tcsnccpy_s_l _mbsncpy_s_l -#define _tcsncset_s _mbsnset_s -#define _tcsncset_s_l _mbsnset_s_l - -#define _tcslwr_s _mbslwr_s -#define _tcslwr_s_l _mbslwr_s_l -#define _tcsupr_s _mbsupr_s -#define _tcsupr_s_l _mbsupr_s_l - -#define _tccpy_s _mbccpy_s -#define _tccpy_s_l _mbccpy_s_l -#else - - _CRTIMP char *__cdecl _tcsncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcstok_s(char *_Str,const char *_Delim,char **_Context); - _CRTIMP char *__cdecl _tcstok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale); - _CRTIMP errno_t __cdecl _tcsset_s(char *_Str,size_t _SizeInChars,unsigned int _Val); - _CRTIMP errno_t __cdecl _tcsset_s_l(char *_Str,size_t _SizeInChars,unsigned int,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcslwr_s(char *_Str,size_t _SizeInChars); - _CRTIMP char *__cdecl _tcslwr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsupr_s(char *_Str,size_t _SizeInChars); - _CRTIMP char *__cdecl _tcsupr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); - -#endif - -#else - -#define _tcsncat_s strncat_s -#define _tcsncat_s_l _strncat_s_l -#define _tcsncpy_s strncpy_s -#define _tcsncpy_s_l _strncpy_s_l -#define _tcstok_s strtok_s -#define _tcstok_s_l _strtok_s_l - -#define _tcsnset_s _strnset_s -#define _tcsnset_s_l _strnset_s_l -#define _tcsset_s _strset_s -#define _tcsset_s _strset_s -#define _tcsset_s_l _strset_s_l - -#define _tcsnccat_s strncat_s -#define _tcsnccat_s_l _strncat_s_l -#define _tcsnccpy_s strncpy_s -#define _tcsnccpy_s_l _strncpy_s_l - -#define _tcslwr_s _strlwr_s -#define _tcslwr_s_l _strlwr_s_l -#define _tcsupr_s _strupr_s -#define _tcsupr_s_l _strupr_s_l - -#define _strnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_strnset_s(_Destination,_Destination_size_chars,_Value,_Count)) -#define _strset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_strset_s(_Destination,_Destination_size_chars,_Value)) -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/tinyc/win32/include/sec_api/time_s.h b/tinyc/win32/include/sec_api/time_s.h deleted file mode 100644 index 9603b94fc..000000000 --- a/tinyc/win32/include/sec_api/time_s.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIME_H__S -#define _TIME_H__S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _ctime32_s(char *_Buf,size_t _SizeInBytes,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _gmtime32_s(struct tm *_Tm,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _localtime32_s(struct tm *_Tm,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _strdate_s(char *_Buf,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _strtime_s(char *_Buf ,size_t _SizeInBytes); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _ctime64_s(char *_Buf,size_t _SizeInBytes,const __time64_t *_Time); - _CRTIMP errno_t __cdecl _gmtime64_s(struct tm *_Tm,const __time64_t *_Time); - _CRTIMP errno_t __cdecl _localtime64_s(struct tm *_Tm,const __time64_t *_Time); -#endif - -#ifndef _WTIME_S_DEFINED -#define _WTIME_S_DEFINED - _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); - _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) -#define _INC_WTIME_S_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } -#else -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } -#endif -#endif -#endif - -#ifndef RC_INVOKED -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); } -#else -__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); } -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/sec_api/wchar_s.h b/tinyc/win32/include/sec_api/wchar_s.h deleted file mode 100644 index 94251aa8b..000000000 --- a/tinyc/win32/include/sec_api/wchar_s.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCHAR_S -#define _INC_WCHAR_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WIO_S_DEFINED -#define _WIO_S_DEFINED - _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); -#endif - -#ifndef _WCONIO_S_DEFINED -#define _WCONIO_S_DEFINED - _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); - _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); -#endif - -#ifndef _WSTDIO_S_DEFINED -#define _WSTDIO_S_DEFINED - _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); - int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf_s(const wchar_t *_Format,...); - int __cdecl vfwprintf_s(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); - int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); - int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); -#endif - -#ifndef _WSTDLIB_S_DEFINED -#define _WSTDLIB_S_DEFINED - _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); - _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); -#endif -#endif - -#ifndef _POSIX_ -#ifndef _WSTDLIBP_S_DEFINED -#define _WSTDLIBP_S_DEFINED - _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); - _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); - _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); -#endif -#endif - -#ifndef _WSTRING_S_DEFINED -#define _WSTRING_S_DEFINED - _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); - _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); - _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); - _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); - _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); - _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); -#endif - -#ifndef _WTIME_S_DEFINED -#define _WTIME_S_DEFINED - _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); - _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) -#define _INC_WTIME_S_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } -#else -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } -#endif -#endif -#endif - - _CRTIMP errno_t __cdecl mbsrtowcs_s(size_t *_Retval,wchar_t *_Dst,size_t _SizeInWords,const char **_PSrc,size_t _N,mbstate_t *_State); - _CRTIMP errno_t __cdecl wcrtomb_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,wchar_t _Ch,mbstate_t *_State); - _CRTIMP errno_t __cdecl wcsrtombs_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,const wchar_t **_Src,size_t _Size,mbstate_t *_State); - -#ifdef __cplusplus -} -#endif - -#endif -#endif diff --git a/tinyc/win32/include/setjmp.h b/tinyc/win32/include/setjmp.h deleted file mode 100644 index e4f142a3f..000000000 --- a/tinyc/win32/include/setjmp.h +++ /dev/null @@ -1,160 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SETJMP -#define _INC_SETJMP - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#if (defined(_X86_) && !defined(__x86_64)) - -#define _JBLEN 16 -#define _JBTYPE int - - typedef struct __JUMP_BUFFER { - unsigned long Ebp; - unsigned long Ebx; - unsigned long Edi; - unsigned long Esi; - unsigned long Esp; - unsigned long Eip; - unsigned long Registration; - unsigned long TryLevel; - unsigned long Cookie; - unsigned long UnwindFunc; - unsigned long UnwindData[6]; - } _JUMP_BUFFER; -#elif defined(__ia64__) - typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { - __int64 LowPart; - __int64 HighPart; - } SETJMP_FLOAT128; - -#define _JBLEN 33 - typedef SETJMP_FLOAT128 _JBTYPE; - - typedef struct __JUMP_BUFFER { - - unsigned long iAReserved[6]; - - unsigned long Registration; - unsigned long TryLevel; - unsigned long Cookie; - unsigned long UnwindFunc; - - unsigned long UnwindData[6]; - - SETJMP_FLOAT128 FltS0; - SETJMP_FLOAT128 FltS1; - SETJMP_FLOAT128 FltS2; - SETJMP_FLOAT128 FltS3; - SETJMP_FLOAT128 FltS4; - SETJMP_FLOAT128 FltS5; - SETJMP_FLOAT128 FltS6; - SETJMP_FLOAT128 FltS7; - SETJMP_FLOAT128 FltS8; - SETJMP_FLOAT128 FltS9; - SETJMP_FLOAT128 FltS10; - SETJMP_FLOAT128 FltS11; - SETJMP_FLOAT128 FltS12; - SETJMP_FLOAT128 FltS13; - SETJMP_FLOAT128 FltS14; - SETJMP_FLOAT128 FltS15; - SETJMP_FLOAT128 FltS16; - SETJMP_FLOAT128 FltS17; - SETJMP_FLOAT128 FltS18; - SETJMP_FLOAT128 FltS19; - __int64 FPSR; - __int64 StIIP; - __int64 BrS0; - __int64 BrS1; - __int64 BrS2; - __int64 BrS3; - __int64 BrS4; - __int64 IntS0; - __int64 IntS1; - __int64 IntS2; - __int64 IntS3; - __int64 RsBSP; - __int64 RsPFS; - __int64 ApUNAT; - __int64 ApLC; - __int64 IntSp; - __int64 IntNats; - __int64 Preds; - - } _JUMP_BUFFER; -#elif defined(__x86_64) - typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { - unsigned __int64 Part[2]; - } SETJMP_FLOAT128; - -#define _JBLEN 16 - typedef SETJMP_FLOAT128 _JBTYPE; - - typedef struct _JUMP_BUFFER { - unsigned __int64 Frame; - unsigned __int64 Rbx; - unsigned __int64 Rsp; - unsigned __int64 Rbp; - unsigned __int64 Rsi; - unsigned __int64 Rdi; - unsigned __int64 R12; - unsigned __int64 R13; - unsigned __int64 R14; - unsigned __int64 R15; - unsigned __int64 Rip; - unsigned __int64 Spare; - SETJMP_FLOAT128 Xmm6; - SETJMP_FLOAT128 Xmm7; - SETJMP_FLOAT128 Xmm8; - SETJMP_FLOAT128 Xmm9; - SETJMP_FLOAT128 Xmm10; - SETJMP_FLOAT128 Xmm11; - SETJMP_FLOAT128 Xmm12; - SETJMP_FLOAT128 Xmm13; - SETJMP_FLOAT128 Xmm14; - SETJMP_FLOAT128 Xmm15; - } _JUMP_BUFFER; -#endif -#ifndef _JMP_BUF_DEFINED - typedef _JBTYPE jmp_buf[_JBLEN]; -#define _JMP_BUF_DEFINED -#endif - - void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); - -#ifdef USE_MINGW_SETJMP_TWO_ARGS -#ifndef _INC_SETJMPEX -#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); -#else -#undef setjmp -#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) -#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); -#endif -#else -#ifndef _INC_SETJMPEX -#define setjmp _setjmp -#endif - int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); -#endif - - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/share.h b/tinyc/win32/include/share.h deleted file mode 100644 index 358855fe4..000000000 --- a/tinyc/win32/include/share.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SHARE -#define _INC_SHARE - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#define _SH_COMPAT 0x00 -#define _SH_DENYRW 0x10 -#define _SH_DENYWR 0x20 -#define _SH_DENYRD 0x30 -#define _SH_DENYNO 0x40 -#define _SH_SECURE 0x80 - -#ifndef NO_OLDNAMES -#define SH_COMPAT _SH_COMPAT -#define SH_DENYRW _SH_DENYRW -#define SH_DENYWR _SH_DENYWR -#define SH_DENYRD _SH_DENYRD -#define SH_DENYNO _SH_DENYNO -#endif - -#endif diff --git a/tinyc/win32/include/signal.h b/tinyc/win32/include/signal.h deleted file mode 100644 index a518f6b31..000000000 --- a/tinyc/win32/include/signal.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SIGNAL -#define _INC_SIGNAL - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _SIG_ATOMIC_T_DEFINED -#define _SIG_ATOMIC_T_DEFINED - typedef int sig_atomic_t; -#endif - -#define NSIG 23 - -#define SIGHUP 1 /* hangup */ -#define SIGINT 2 -#define SIGQUIT 3 /* quit */ -#define SIGILL 4 -#define SIGTRAP 5 /* trace trap (not reset when caught) */ -#define SIGIOT 6 /* IOT instruction */ -#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ -#define SIGEMT 7 /* EMT instruction */ -#define SIGFPE 8 -#define SIGKILL 9 /* kill (cannot be caught or ignored) */ -#define SIGBUS 10 /* bus error */ -#define SIGSEGV 11 -#define SIGSYS 12 /* bad argument to system call */ -#define SIGPIPE 13 /* write on a pipe with no one to read it */ -#ifdef __USE_MINGW_ALARM -#define SIGALRM 14 /* alarm clock */ -#endif -#define SIGTERM 15 -#define SIGBREAK 21 -#define SIGABRT2 22 - -#define SIGABRT_COMPAT 6 - - typedef void (*__p_sig_fn_t)(int); - -#define SIG_DFL (__p_sig_fn_t)0 -#define SIG_IGN (__p_sig_fn_t)1 -#define SIG_GET (__p_sig_fn_t)2 -#define SIG_SGE (__p_sig_fn_t)3 -#define SIG_ACK (__p_sig_fn_t)4 -#define SIG_ERR (__p_sig_fn_t)-1 - - extern void **__cdecl __pxcptinfoptrs(void); -#define _pxcptinfoptrs (*__pxcptinfoptrs()) - - __p_sig_fn_t __cdecl signal(int _SigNum,__p_sig_fn_t _Func); - int __cdecl raise(int _SigNum); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/stdint.h b/tinyc/win32/include/stdint.h deleted file mode 100644 index cde32b6e3..000000000 --- a/tinyc/win32/include/stdint.h +++ /dev/null @@ -1,212 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* ISO C9x 7.18 Integer types - * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * Contributor: Danny Smith - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Date: 2000-12-02 - */ - - -#ifndef _STDINT_H -#define _STDINT_H - -#include <_mingw.h> - -#define __need_wint_t -#define __need_wchar_t -#include "stddef.h" - -#ifndef __int8_t_defined -#define __int8_t_defined -/* 7.18.1.1 Exact-width integer types */ -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned uint32_t; -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif - -/* 7.18.1.2 Minimum-width integer types */ -typedef signed char int_least8_t; -typedef unsigned char uint_least8_t; -typedef short int_least16_t; -typedef unsigned short uint_least16_t; -typedef int int_least32_t; -typedef unsigned uint_least32_t; -typedef long long int_least64_t; -typedef unsigned long long uint_least64_t; - -/* 7.18.1.3 Fastest minimum-width integer types - * Not actually guaranteed to be fastest for all purposes - * Here we use the exact-width types for 8 and 16-bit ints. - */ -typedef char int_fast8_t; -typedef unsigned char uint_fast8_t; -typedef short int_fast16_t; -typedef unsigned short uint_fast16_t; -typedef int int_fast32_t; -typedef unsigned int uint_fast32_t; -typedef long long int_fast64_t; -typedef unsigned long long uint_fast64_t; - -/* 7.18.1.5 Greatest-width integer types */ -typedef long long intmax_t; -typedef unsigned long long uintmax_t; - -/* 7.18.2 Limits of specified-width integer types */ -#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) - -/* 7.18.2.1 Limits of exact-width integer types */ -#define INT8_MIN (-128) -#define INT16_MIN (-32768) -#define INT32_MIN (-2147483647 - 1) -#define INT64_MIN (-9223372036854775807LL - 1) - -#define INT8_MAX 127 -#define INT16_MAX 32767 -#define INT32_MAX 2147483647 -#define INT64_MAX 9223372036854775807LL - -#define UINT8_MAX 0xff /* 255U */ -#define UINT16_MAX 0xffff /* 65535U */ -#define UINT32_MAX 0xffffffff /* 4294967295U */ -#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ - -/* 7.18.2.2 Limits of minimum-width integer types */ -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST64_MIN INT64_MIN - -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MAX INT64_MAX - -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -/* 7.18.2.3 Limits of fastest minimum-width integer types */ -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST64_MIN INT64_MIN - -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MAX INT64_MAX - -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -/* 7.18.2.4 Limits of integer types capable of holding - object pointers */ -#ifdef _WIN64 -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX -#else -#define INTPTR_MIN INT32_MIN -#define INTPTR_MAX INT32_MAX -#define UINTPTR_MAX UINT32_MAX -#endif - -/* 7.18.2.5 Limits of greatest-width integer types */ -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -/* 7.18.3 Limits of other integer types */ -#ifdef _WIN64 -#define PTRDIFF_MIN INT64_MIN -#define PTRDIFF_MAX INT64_MAX -#else -#define PTRDIFF_MIN INT32_MIN -#define PTRDIFF_MAX INT32_MAX -#endif - -#define SIG_ATOMIC_MIN INT32_MIN -#define SIG_ATOMIC_MAX INT32_MAX - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX UINT64_MAX -#else -#define SIZE_MAX UINT32_MAX -#endif -#endif - -#ifndef WCHAR_MIN /* also in wchar.h */ -#define WCHAR_MIN 0 -#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ -#endif - -/* - * wint_t is unsigned short for compatibility with MS runtime - */ -#define WINT_MIN 0 -#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ - -#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ - - -/* 7.18.4 Macros for integer constants */ -#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) - -/* 7.18.4.1 Macros for minimum-width integer constants - - According to Douglas Gwyn : - "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC - 9899:1999 as initially published, the expansion was required - to be an integer constant of precisely matching type, which - is impossible to accomplish for the shorter types on most - platforms, because C99 provides no standard way to designate - an integer constant with width less than that of type int. - TC1 changed this to require just an integer constant - *expression* with *promoted* type." - - The trick used here is from Clive D W Feather. -*/ - -#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) -#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) -#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) -/* The 'trick' doesn't work in C89 for long long because, without - suffix, (val) will be evaluated as int, not intmax_t */ -#define INT64_C(val) val##LL - -#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) -#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) -#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) -#define UINT64_C(val) val##ULL - -/* 7.18.4.2 Macros for greatest-width integer constants */ -#define INTMAX_C(val) val##LL -#define UINTMAX_C(val) val##ULL - -#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ - -#endif diff --git a/tinyc/win32/include/stdio.h b/tinyc/win32/include/stdio.h deleted file mode 100644 index da887936a..000000000 --- a/tinyc/win32/include/stdio.h +++ /dev/null @@ -1,429 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDIO -#define _INC_STDIO - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#define BUFSIZ 512 -#define _NFILE _NSTREAM_ -#define _NSTREAM_ 512 -#define _IOB_ENTRIES 20 -#define EOF (-1) - -#ifndef _FILE_DEFINED - struct _iobuf { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; - }; - typedef struct _iobuf FILE; -#define _FILE_DEFINED -#endif - -#ifdef _POSIX_ -#define _P_tmpdir "/" -#define _wP_tmpdir L"/" -#else -#define _P_tmpdir "\\" -#define _wP_tmpdir L"\\" -#endif - -#define L_tmpnam (sizeof(_P_tmpdir) + 12) - -#ifdef _POSIX_ -#define L_ctermid 9 -#define L_cuserid 32 -#endif - -#define SEEK_CUR 1 -#define SEEK_END 2 -#define SEEK_SET 0 - -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 - -#define FILENAME_MAX 260 -#define FOPEN_MAX 20 -#define _SYS_OPEN 20 -#define TMP_MAX 32767 - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _STDIO_DEFINED -#ifdef _WIN64 - _CRTIMP FILE *__cdecl __iob_func(void); -#else -#ifdef _MSVCRT_ -extern FILE _iob[]; /* A pointer to an array of FILE */ -#define __iob_func() (_iob) -#else -extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ -#define __iob_func() (*_imp___iob) -#define _iob __iob_func() -#endif -#endif -#endif - -#ifndef _FPOS_T_DEFINED -#define _FPOS_T_DEFINED -#undef _FPOSOFF - -#if (!defined(NO_OLDNAMES) || defined(__GNUC__)) && _INTEGRAL_MAX_BITS >= 64 - typedef __int64 fpos_t; -#define _FPOSOFF(fp) ((long)(fp)) -#else - typedef long long fpos_t; -#define _FPOSOFF(fp) ((long)(fp)) -#endif - -#endif - -#ifndef _STDSTREAM_DEFINED -#define _STDSTREAM_DEFINED - -#define stdin (&__iob_func()[0]) -#define stdout (&__iob_func()[1]) -#define stderr (&__iob_func()[2]) -#endif - -#define _IOREAD 0x0001 -#define _IOWRT 0x0002 - -#define _IOFBF 0x0000 -#define _IOLBF 0x0040 -#define _IONBF 0x0004 - -#define _IOMYBUF 0x0008 -#define _IOEOF 0x0010 -#define _IOERR 0x0020 -#define _IOSTRG 0x0040 -#define _IORW 0x0080 -#ifdef _POSIX_ -#define _IOAPPEND 0x0200 -#endif - -#define _TWO_DIGIT_EXPONENT 0x1 - -#ifndef _STDIO_DEFINED - - _CRTIMP int __cdecl _filbuf(FILE *_File); - _CRTIMP int __cdecl _flsbuf(int _Ch,FILE *_File); -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode); -#else - _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode,int _ShFlag); -#endif - void __cdecl clearerr(FILE *_File); - int __cdecl fclose(FILE *_File); - _CRTIMP int __cdecl _fcloseall(void); -#ifdef _POSIX_ - FILE *__cdecl fdopen(int _FileHandle,const char *_Mode); -#else - _CRTIMP FILE *__cdecl _fdopen(int _FileHandle,const char *_Mode); -#endif - int __cdecl feof(FILE *_File); - int __cdecl ferror(FILE *_File); - int __cdecl fflush(FILE *_File); - int __cdecl fgetc(FILE *_File); - _CRTIMP int __cdecl _fgetchar(void); - int __cdecl fgetpos(FILE *_File ,fpos_t *_Pos); - char *__cdecl fgets(char *_Buf,int _MaxCount,FILE *_File); -#ifdef _POSIX_ - int __cdecl fileno(FILE *_File); -#else - _CRTIMP int __cdecl _fileno(FILE *_File); -#endif - _CRTIMP char *__cdecl _tempnam(const char *_DirName,const char *_FilePrefix); - _CRTIMP int __cdecl _flushall(void); - FILE *__cdecl fopen(const char *_Filename,const char *_Mode); - FILE *fopen64(const char *filename,const char *mode); - int __cdecl fprintf(FILE *_File,const char *_Format,...); - int __cdecl fputc(int _Ch,FILE *_File); - _CRTIMP int __cdecl _fputchar(int _Ch); - int __cdecl fputs(const char *_Str,FILE *_File); - size_t __cdecl fread(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); - FILE *__cdecl freopen(const char *_Filename,const char *_Mode,FILE *_File); - int __cdecl fscanf(FILE *_File,const char *_Format,...); - int __cdecl fsetpos(FILE *_File,const fpos_t *_Pos); - int __cdecl fseek(FILE *_File,long _Offset,int _Origin); - int fseeko64(FILE* stream, _off64_t offset, int whence); - long __cdecl ftell(FILE *_File); - _off64_t ftello64(FILE * stream); - int __cdecl _fseeki64(FILE *_File,__int64 _Offset,int _Origin); - __int64 __cdecl _ftelli64(FILE *_File); - size_t __cdecl fwrite(const void *_Str,size_t _Size,size_t _Count,FILE *_File); - int __cdecl getc(FILE *_File); - int __cdecl getchar(void); - _CRTIMP int __cdecl _getmaxstdio(void); - char *__cdecl gets(char *_Buffer); - int __cdecl _getw(FILE *_File); -#ifndef _CRT_PERROR_DEFINED -#define _CRT_PERROR_DEFINED - void __cdecl perror(const char *_ErrMsg); -#endif - _CRTIMP int __cdecl _pclose(FILE *_File); - _CRTIMP FILE *__cdecl _popen(const char *_Command,const char *_Mode); -#if !defined(NO_OLDNAMES) && !defined(popen) -#define popen _popen -#define pclose _pclose -#endif - int __cdecl printf(const char *_Format,...); - int __cdecl putc(int _Ch,FILE *_File); - int __cdecl putchar(int _Ch); - int __cdecl puts(const char *_Str); - _CRTIMP int __cdecl _putw(int _Word,FILE *_File); -#ifndef _CRT_DIRECTORY_DEFINED -#define _CRT_DIRECTORY_DEFINED - int __cdecl remove(const char *_Filename); - int __cdecl rename(const char *_OldFilename,const char *_NewFilename); - _CRTIMP int __cdecl _unlink(const char *_Filename); -#ifndef NO_OLDNAMES - int __cdecl unlink(const char *_Filename); -#endif -#endif - void __cdecl rewind(FILE *_File); - _CRTIMP int __cdecl _rmtmp(void); - int __cdecl scanf(const char *_Format,...); - void __cdecl setbuf(FILE *_File,char *_Buffer); - _CRTIMP int __cdecl _setmaxstdio(int _Max); - _CRTIMP unsigned int __cdecl _set_output_format(unsigned int _Format); - _CRTIMP unsigned int __cdecl _get_output_format(void); - int __cdecl setvbuf(FILE *_File,char *_Buf,int _Mode,size_t _Size); - _CRTIMP int __cdecl _scprintf(const char *_Format,...); - int __cdecl sscanf(const char *_Src,const char *_Format,...); - _CRTIMP int __cdecl _snscanf(const char *_Src,size_t _MaxCount,const char *_Format,...); - FILE *__cdecl tmpfile(void); - char *__cdecl tmpnam(char *_Buffer); - int __cdecl ungetc(int _Ch,FILE *_File); - int __cdecl vfprintf(FILE *_File,const char *_Format,va_list _ArgList); - int __cdecl vprintf(const char *_Format,va_list _ArgList); - /* Make sure macros are not defined. */ -#pragma push_macro("vsnprintf") -#pragma push_macro("snprintf") -# undef vsnprintf -# undef snprintf - extern - __attribute__((format(gnu_printf, 3, 0))) __attribute__((nonnull (3))) - int __mingw_vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - extern - __attribute__((format(gnu_printf, 3, 4))) __attribute__((nonnull (3))) - int __mingw_snprintf(char* s, size_t n, const char* format, ...); - int __cdecl vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snprintf(char *_Dest,size_t _Count,const char *_Format,...); - _CRTIMP int __cdecl _vsnprintf(char *_Dest,size_t _Count,const char *_Format,va_list _Args); - int __cdecl sprintf(char *_Dest,const char *_Format,...); - int __cdecl vsprintf(char *_Dest,const char *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snprintf(char* s, size_t n, const char* format, ...); - __CRT_INLINE int __cdecl vsnprintf (char* s, size_t n, const char* format,va_list arg) { - return _vsnprintf ( s, n, format, arg); - } - int __cdecl vscanf(const char * Format, va_list argp); - int __cdecl vfscanf (FILE * fp, const char * Format,va_list argp); - int __cdecl vsscanf (const char * _Str,const char * Format,va_list argp); -#endif -/* Restore may prior defined macros snprintf/vsnprintf. */ -#pragma pop_macro("snprintf") -#pragma pop_macro("vsnprintf") -/* Check if vsnprintf and snprintf are defaulting to gnu-style. */ -# if defined(USE_MINGW_GNU_SNPRINTF) && USE_MINGW_GNU_SNPRINTF -# ifndef vsnprint -# define vsnprintf __mingw_vsnprintf -# endif -# ifndef snprintf -# define snprintf __mingw_snprintf -# endif -# endif - _CRTIMP int __cdecl _vscprintf(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _set_printf_count_output(int _Value); - _CRTIMP int __cdecl _get_printf_count_output(void); - -#ifndef _WSTDIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); -#else - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); -#endif - wint_t __cdecl fgetwc(FILE *_File); - _CRTIMP wint_t __cdecl _fgetwchar(void); - wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); - wint_t __cdecl getwc(FILE *_File); - wint_t __cdecl getwchar(void); - wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); - wint_t __cdecl putwchar(wchar_t _Ch); - wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); - wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); - int __cdecl fputws(const wchar_t *_Str,FILE *_File); - _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); - _CRTIMP int __cdecl _putws(const wchar_t *_Str); - int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); - int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); - _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); - _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snwprintf (wchar_t* s, size_t n, const wchar_t* format, ...); - __CRT_INLINE int __cdecl vsnwprintf (wchar_t* s, size_t n, const wchar_t* format, va_list arg) { return _vsnwprintf(s,n,format,arg); } - int __cdecl vwscanf (const wchar_t *, va_list); - int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); - int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); -#endif - _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); - -#ifndef RC_INVOKED -#include -#endif - -#ifdef _CRT_NON_CONFORMING_SWPRINTFS -#ifndef __cplusplus -#define swprintf _swprintf -#define vswprintf _vswprintf -#define _swprintf_l __swprintf_l -#define _vswprintf_l __vswprintf_l -#endif -#endif - - _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); - _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); - int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); - int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - int __cdecl wscanf(const wchar_t *_Format,...); - _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); -#if !defined(NO_OLDNAMES) && !defined(wpopen) -#define wpopen _wpopen -#endif - _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); - _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); - _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); - -#undef _CRT_GETPUTWCHAR_NOINLINE - -#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) -#define getwchar() fgetwc(stdin) -#define putwchar(_c) fputwc((_c),stdout) -#else - __CRT_INLINE wint_t __cdecl getwchar() { return (fgetwc(stdin)); } - __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) { return (fputwc(_C,stdout)); } -#endif - -#define getwc(_stm) fgetwc(_stm) -#define putwc(_c,_stm) fputwc(_c,_stm) -#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) -#define _getwc_nolock(_stm) _fgetwc_nolock(_stm) - -#define _WSTDIO_DEFINED -#endif - -#define _STDIO_DEFINED -#endif - -#define _fgetc_nolock(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) -#define _fputc_nolock(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream))) -#define _getc_nolock(_stream) _fgetc_nolock(_stream) -#define _putc_nolock(_c,_stream) _fputc_nolock(_c,_stream) -#define _getchar_nolock() _getc_nolock(stdin) -#define _putchar_nolock(_c) _putc_nolock((_c),stdout) -#define _getwchar_nolock() _getwc_nolock(stdin) -#define _putwchar_nolock(_c) _putwc_nolock((_c),stdout) - - _CRTIMP void __cdecl _lock_file(FILE *_File); - _CRTIMP void __cdecl _unlock_file(FILE *_File); - _CRTIMP int __cdecl _fclose_nolock(FILE *_File); - _CRTIMP int __cdecl _fflush_nolock(FILE *_File); - _CRTIMP size_t __cdecl _fread_nolock(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _fseek_nolock(FILE *_File,long _Offset,int _Origin); - _CRTIMP long __cdecl _ftell_nolock(FILE *_File); - _CRTIMP int __cdecl _fseeki64_nolock(FILE *_File,__int64 _Offset,int _Origin); - _CRTIMP __int64 __cdecl _ftelli64_nolock(FILE *_File); - _CRTIMP size_t __cdecl _fwrite_nolock(const void *_DstBuf,size_t _Size,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _ungetc_nolock(int _Ch,FILE *_File); - -#if !defined(NO_OLDNAMES) || !defined(_POSIX) -#define P_tmpdir _P_tmpdir -#define SYS_OPEN _SYS_OPEN - - char *__cdecl tempnam(const char *_Directory,const char *_FilePrefix); - int __cdecl fcloseall(void); - FILE *__cdecl fdopen(int _FileHandle,const char *_Format); - int __cdecl fgetchar(void); - int __cdecl fileno(FILE *_File); - int __cdecl flushall(void); - int __cdecl fputchar(int _Ch); - int __cdecl getw(FILE *_File); - int __cdecl putw(int _Ch,FILE *_File); - int __cdecl rmtmp(void); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include - -#endif diff --git a/tinyc/win32/include/stdlib.h b/tinyc/win32/include/stdlib.h deleted file mode 100644 index 96765b29e..000000000 --- a/tinyc/win32/include/stdlib.h +++ /dev/null @@ -1,580 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDLIB -#define _INC_STDLIB - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 - -#ifndef _ONEXIT_T_DEFINED -#define _ONEXIT_T_DEFINED - - typedef int (__cdecl *_onexit_t)(void); - -#ifndef NO_OLDNAMES -#define onexit_t _onexit_t -#endif -#endif - -#ifndef _DIV_T_DEFINED -#define _DIV_T_DEFINED - - typedef struct _div_t { - int quot; - int rem; - } div_t; - - typedef struct _ldiv_t { - long quot; - long rem; - } ldiv_t; -#endif - -#ifndef _CRT_DOUBLE_DEC -#define _CRT_DOUBLE_DEC - -#pragma pack(4) - typedef struct { - unsigned char ld[10]; - } _LDOUBLE; -#pragma pack() - -#define _PTR_LD(x) ((unsigned char *)(&(x)->ld)) - - typedef struct { - double x; - } _CRT_DOUBLE; - - typedef struct { - float f; - } _CRT_FLOAT; - -#pragma push_macro("long") -#undef long - - typedef struct { - long double x; - } _LONGDOUBLE; - -#pragma pop_macro("long") - -#pragma pack(4) - typedef struct { - unsigned char ld12[12]; - } _LDBL12; -#pragma pack() -#endif - -#define RAND_MAX 0x7fff - -#ifndef MB_CUR_MAX -#define MB_CUR_MAX ___mb_cur_max_func() -#ifndef __mb_cur_max -#ifdef _MSVCRT_ - extern int __mb_cur_max; -#else -#define __mb_cur_max (*_imp____mb_cur_max) - extern int *_imp____mb_cur_max; -#endif -#endif -#ifdef _MSVCRT_ - extern int __mbcur_max; -#define ___mb_cur_max_func() (__mb_cur_max) -#else - extern int* _imp____mbcur_max; -#define ___mb_cur_max_func() (*_imp____mb_cur_max) -#endif -#endif - -#define __max(a,b) (((a) > (b)) ? (a) : (b)) -#define __min(a,b) (((a) < (b)) ? (a) : (b)) - -#define _MAX_PATH 260 -#define _MAX_DRIVE 3 -#define _MAX_DIR 256 -#define _MAX_FNAME 256 -#define _MAX_EXT 256 - -#define _OUT_TO_DEFAULT 0 -#define _OUT_TO_STDERR 1 -#define _OUT_TO_MSGBOX 2 -#define _REPORT_ERRMODE 3 - -#define _WRITE_ABORT_MSG 0x1 -#define _CALL_REPORTFAULT 0x2 - -#define _MAX_ENV 32767 - - typedef void (__cdecl *_purecall_handler)(void); - - _CRTIMP _purecall_handler __cdecl _set_purecall_handler(_purecall_handler _Handler); - _CRTIMP _purecall_handler __cdecl _get_purecall_handler(void); - - typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); - _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler _Handler); - _invalid_parameter_handler __cdecl _get_invalid_parameter_handler(void); - -#ifndef _CRT_ERRNO_DEFINED -#define _CRT_ERRNO_DEFINED - _CRTIMP extern int *__cdecl _errno(void); -#define errno (*_errno()) - errno_t __cdecl _set_errno(int _Value); - errno_t __cdecl _get_errno(int *_Value); -#endif - _CRTIMP unsigned long *__cdecl __doserrno(void); -#define _doserrno (*__doserrno()) - errno_t __cdecl _set_doserrno(unsigned long _Value); - errno_t __cdecl _get_doserrno(unsigned long *_Value); -#ifdef _MSVCRT_ - extern char *_sys_errlist[]; - extern int _sys_nerr; -#else - _CRTIMP char *_sys_errlist[1]; - _CRTIMP int _sys_nerr; -#endif -#if (defined(_X86_) && !defined(__x86_64)) - _CRTIMP int *__cdecl __p___argc(void); - _CRTIMP char ***__cdecl __p___argv(void); - _CRTIMP wchar_t ***__cdecl __p___wargv(void); - _CRTIMP char ***__cdecl __p__environ(void); - _CRTIMP wchar_t ***__cdecl __p__wenviron(void); - _CRTIMP char **__cdecl __p__pgmptr(void); - _CRTIMP wchar_t **__cdecl __p__wpgmptr(void); -#endif -#ifndef __argc -#ifdef _MSVCRT_ - extern int __argc; -#else -#define __argc (*_imp____argc) - extern int *_imp____argc; -#endif -#endif -#ifndef __argv -#ifdef _MSVCRT_ - extern char **__argv; -#else -#define __argv (*_imp____argv) - extern char ***_imp____argv; -#endif -#endif -#ifndef __wargv -#ifdef _MSVCRT_ - extern wchar_t **__wargv; -#else -#define __wargv (*_imp____wargv) - extern wchar_t ***_imp____wargv; -#endif -#endif - -#ifdef _POSIX_ - extern char **environ; -#else -#ifndef _environ -#ifdef _MSVCRT_ - extern char **_environ; -#else -#define _environ (*_imp___environ) - extern char ***_imp___environ; -#endif -#endif - -#ifndef _wenviron -#ifdef _MSVCRT_ - extern wchar_t **_wenviron; -#else -#define _wenviron (*_imp___wenviron) - extern wchar_t ***_imp___wenviron; -#endif -#endif -#endif -#ifndef _pgmptr -#ifdef _MSVCRT_ - extern char *_pgmptr; -#else -#define _pgmptr (*_imp___pgmptr) - extern char **_imp___pgmptr; -#endif -#endif - -#ifndef _wpgmptr -#ifdef _MSVCRT_ - extern wchar_t *_wpgmptr; -#else -#define _wpgmptr (*_imp___wpgmptr) - extern wchar_t **_imp___wpgmptr; -#endif -#endif - errno_t __cdecl _get_pgmptr(char **_Value); - errno_t __cdecl _get_wpgmptr(wchar_t **_Value); -#ifndef _fmode -#ifdef _MSVCRT_ - extern int _fmode; -#else -#define _fmode (*_imp___fmode) - extern int *_imp___fmode; -#endif -#endif - _CRTIMP errno_t __cdecl _set_fmode(int _Mode); - _CRTIMP errno_t __cdecl _get_fmode(int *_PMode); - -#ifndef _osplatform -#ifdef _MSVCRT_ - extern unsigned int _osplatform; -#else -#define _osplatform (*_imp___osplatform) - extern unsigned int *_imp___osplatform; -#endif -#endif - -#ifndef _osver -#ifdef _MSVCRT_ - extern unsigned int _osver; -#else -#define _osver (*_imp___osver) - extern unsigned int *_imp___osver; -#endif -#endif - -#ifndef _winver -#ifdef _MSVCRT_ - extern unsigned int _winver; -#else -#define _winver (*_imp___winver) - extern unsigned int *_imp___winver; -#endif -#endif - -#ifndef _winmajor -#ifdef _MSVCRT_ - extern unsigned int _winmajor; -#else -#define _winmajor (*_imp___winmajor) - extern unsigned int *_imp___winmajor; -#endif -#endif - -#ifndef _winminor -#ifdef _MSVCRT_ - extern unsigned int _winminor; -#else -#define _winminor (*_imp___winminor) - extern unsigned int *_imp___winminor; -#endif -#endif - - errno_t __cdecl _get_osplatform(unsigned int *_Value); - errno_t __cdecl _get_osver(unsigned int *_Value); - errno_t __cdecl _get_winver(unsigned int *_Value); - errno_t __cdecl _get_winmajor(unsigned int *_Value); - errno_t __cdecl _get_winminor(unsigned int *_Value); -#ifndef _countof -#ifndef __cplusplus -#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) -#else - extern "C++" { - template char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; -#define _countof(_Array) sizeof(*__countof_helper(_Array)) - } -#endif -#endif - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; -#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ - /* C99 function name */ - void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; - __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) - { _exit(status); } -#endif - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - - _CRTIMP unsigned int __cdecl _set_abort_behavior(unsigned int _Flags,unsigned int _Mask); - -#ifndef _CRT_ABS_DEFINED -#define _CRT_ABS_DEFINED - int __cdecl abs(int _X); - long __cdecl labs(long _X); -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - __int64 __cdecl _abs64(__int64); -#endif - int __cdecl atexit(void (__cdecl *)(void)); -#ifndef _CRT_ATOF_DEFINED -#define _CRT_ATOF_DEFINED - double __cdecl atof(const char *_String); - double __cdecl _atof_l(const char *_String,_locale_t _Locale); -#endif - int __cdecl atoi(const char *_Str); - _CRTIMP int __cdecl _atoi_l(const char *_Str,_locale_t _Locale); - long __cdecl atol(const char *_Str); - _CRTIMP long __cdecl _atol_l(const char *_Str,_locale_t _Locale); -#ifndef _CRT_ALGO_DEFINED -#define _CRT_ALGO_DEFINED - void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); - void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); -#endif - unsigned short __cdecl _byteswap_ushort(unsigned short _Short); - /*unsigned long __cdecl _byteswap_ulong (unsigned long _Long); */ -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 _Int64); -#endif - div_t __cdecl div(int _Numerator,int _Denominator); - char *__cdecl getenv(const char *_VarName); - _CRTIMP char *__cdecl _itoa(int _Value,char *_Dest,int _Radix); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP char *__cdecl _i64toa(__int64 _Val,char *_DstBuf,int _Radix); - _CRTIMP char *__cdecl _ui64toa(unsigned __int64 _Val,char *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _atoi64(const char *_String); - _CRTIMP __int64 __cdecl _atoi64_l(const char *_String,_locale_t _Locale); - _CRTIMP __int64 __cdecl _strtoi64(const char *_String,char **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _strtoi64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _strtoui64(const char *_String,char **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _strtoui64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); -#endif - ldiv_t __cdecl ldiv(long _Numerator,long _Denominator); - _CRTIMP char *__cdecl _ltoa(long _Value,char *_Dest,int _Radix); - int __cdecl mblen(const char *_Ch,size_t _MaxCount); - _CRTIMP int __cdecl _mblen_l(const char *_Ch,size_t _MaxCount,_locale_t _Locale); - _CRTIMP size_t __cdecl _mbstrlen(const char *_Str); - _CRTIMP size_t __cdecl _mbstrlen_l(const char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _mbstrnlen(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _mbstrnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); - int __cdecl mbtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes); - _CRTIMP int __cdecl _mbtowc_l(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes,_locale_t _Locale); - size_t __cdecl mbstowcs(wchar_t *_Dest,const char *_Source,size_t _MaxCount); - _CRTIMP size_t __cdecl _mbstowcs_l(wchar_t *_Dest,const char *_Source,size_t _MaxCount,_locale_t _Locale); - int __cdecl rand(void); - _CRTIMP int __cdecl _set_error_mode(int _Mode); - void __cdecl srand(unsigned int _Seed); - double __cdecl strtod(const char *_Str,char **_EndPtr); - float __cdecl strtof(const char *nptr, char **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl strtof (const char * __restrict__, char ** __restrict__); - long double __cdecl strtold(const char * __restrict__, char ** __restrict__); -#endif /* __NO_ISOCEXT */ - _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); - long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); - _CRTIMP long __cdecl _strtol_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl strtoul(const char *_Str,char **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _strtoul_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); -#ifndef _CRT_SYSTEM_DEFINED -#define _CRT_SYSTEM_DEFINED - int __cdecl system(const char *_Command); -#endif - _CRTIMP char *__cdecl _ultoa(unsigned long _Value,char *_Dest,int _Radix); - int __cdecl wctomb(char *_MbCh,wchar_t _WCh); - _CRTIMP int __cdecl _wctomb_l(char *_MbCh,wchar_t _WCh,_locale_t _Locale); - size_t __cdecl wcstombs(char *_Dest,const wchar_t *_Source,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcstombs_l(char *_Dest,const wchar_t *_Source,size_t _MaxCount,_locale_t _Locale); - -#ifndef _CRT_ALLOCATION_DEFINED -#define _CRT_ALLOCATION_DEFINED - void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); - void __cdecl free(void *_Memory); - void *__cdecl malloc(size_t _Size); - void *__cdecl realloc(void *_Memory,size_t _NewSize); - _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - //_CRTIMP void __cdecl _aligned_free(void *_Memory); - //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); -#endif - -#ifndef _WSTDLIB_DEFINED -#define _WSTDLIB_DEFINED - - _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); - double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); - float __cdecl wcstof(const wchar_t *nptr, wchar_t **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl wcstof( const wchar_t * __restrict__, wchar_t ** __restrict__); - long double __cdecl wcstold(const wchar_t * __restrict__, wchar_t ** __restrict__); -#endif /* __NO_ISOCEXT */ - _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); - long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif - _CRTIMP double __cdecl _wtof(const wchar_t *_Str); - _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); - _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP long __cdecl _wtol(const wchar_t *_Str); - _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); - _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str ,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); -#endif -#endif - -#ifndef _POSIX_ -#define _CVTBUFSIZE (309+40) - _CRTIMP char *__cdecl _fullpath(char *_FullPath,const char *_Path,size_t _SizeInBytes); - _CRTIMP char *__cdecl _ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); - _CRTIMP char *__cdecl _fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - _CRTIMP char *__cdecl _gcvt(double _Val,int _NumOfDigits,char *_DstBuf); - _CRTIMP int __cdecl _atodbl(_CRT_DOUBLE *_Result,char *_Str); - _CRTIMP int __cdecl _atoldbl(_LDOUBLE *_Result,char *_Str); - _CRTIMP int __cdecl _atoflt(_CRT_FLOAT *_Result,char *_Str); - _CRTIMP int __cdecl _atodbl_l(_CRT_DOUBLE *_Result,char *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _atoldbl_l(_LDOUBLE *_Result,char *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _atoflt_l(_CRT_FLOAT *_Result,char *_Str,_locale_t _Locale); - unsigned long __cdecl _lrotl(unsigned long _Val,int _Shift); - unsigned long __cdecl _lrotr(unsigned long _Val,int _Shift); - _CRTIMP void __cdecl _makepath(char *_Path,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); - _onexit_t __cdecl _onexit(_onexit_t _Func); - -#ifndef _CRT_PERROR_DEFINED -#define _CRT_PERROR_DEFINED - void __cdecl perror(const char *_ErrMsg); -#endif - _CRTIMP int __cdecl _putenv(const char *_EnvString); - unsigned int __cdecl _rotl(unsigned int _Val,int _Shift); -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _rotl64(unsigned __int64 _Val,int _Shift); -#endif - unsigned int __cdecl _rotr(unsigned int _Val,int _Shift); -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _rotr64(unsigned __int64 _Val,int _Shift); -#endif - _CRTIMP void __cdecl _searchenv(const char *_Filename,const char *_EnvVar,char *_ResultPath); - _CRTIMP void __cdecl _splitpath(const char *_FullPath,char *_Drive,char *_Dir,char *_Filename,char *_Ext); - _CRTIMP void __cdecl _swab(char *_Buf1,char *_Buf2,int _SizeInBytes); - -#ifndef _WSTDLIBP_DEFINED -#define _WSTDLIBP_DEFINED - _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); - _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); - _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); - _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); -#endif - - _CRTIMP void __cdecl _beep(unsigned _Frequency,unsigned _Duration) __MINGW_ATTRIB_DEPRECATED; - /* Not to be confused with _set_error_mode (int). */ - _CRTIMP void __cdecl _seterrormode(int _Mode) __MINGW_ATTRIB_DEPRECATED; - _CRTIMP void __cdecl _sleep(unsigned long _Duration) __MINGW_ATTRIB_DEPRECATED; -#endif - -#ifndef NO_OLDNAMES -#ifndef _POSIX_ -#if 0 -#ifndef __cplusplus -#ifndef NOMINMAX -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#endif -#endif -#endif - -#define sys_errlist _sys_errlist -#define sys_nerr _sys_nerr -#define environ _environ - char *__cdecl ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); - char *__cdecl fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - char *__cdecl gcvt(double _Val,int _NumOfDigits,char *_DstBuf); - char *__cdecl itoa(int _Val,char *_DstBuf,int _Radix); - char *__cdecl ltoa(long _Val,char *_DstBuf,int _Radix); - int __cdecl putenv(const char *_EnvString); - void __cdecl swab(char *_Buf1,char *_Buf2,int _SizeInBytes); - char *__cdecl ultoa(unsigned long _Val,char *_Dstbuf,int _Radix); - onexit_t __cdecl onexit(onexit_t _Func); -#endif -#endif - -#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */ - - typedef struct { long long quot, rem; } lldiv_t; - - lldiv_t __cdecl lldiv(long long, long long); - - __CRT_INLINE long long __cdecl llabs(long long _j) { return (_j >= 0 ? _j : -_j); } - - long long __cdecl strtoll(const char* __restrict__, char** __restrict, int); - unsigned long long __cdecl strtoull(const char* __restrict__, char** __restrict__, int); - - /* these are stubs for MS _i64 versions */ - long long __cdecl atoll (const char *); - -#ifndef __STRICT_ANSI__ - long long __cdecl wtoll (const wchar_t *); - char *__cdecl lltoa (long long, char *, int); - char *__cdecl ulltoa (unsigned long long , char *, int); - wchar_t *__cdecl lltow (long long, wchar_t *, int); - wchar_t *__cdecl ulltow (unsigned long long, wchar_t *, int); - - /* __CRT_INLINE using non-ansi functions */ - __CRT_INLINE long long __cdecl atoll (const char * _c) { return _atoi64 (_c); } - __CRT_INLINE char *__cdecl lltoa (long long _n, char * _c, int _i) { return _i64toa (_n, _c, _i); } - __CRT_INLINE char *__cdecl ulltoa (unsigned long long _n, char * _c, int _i) { return _ui64toa (_n, _c, _i); } - __CRT_INLINE long long __cdecl wtoll (const wchar_t * _w) { return _wtoi64 (_w); } - __CRT_INLINE wchar_t *__cdecl lltow (long long _n, wchar_t * _w, int _i) { return _i64tow (_n, _w, _i); } - __CRT_INLINE wchar_t *__cdecl ulltow (unsigned long long _n, wchar_t * _w, int _i) { return _ui64tow (_n, _w, _i); } -#endif /* (__STRICT_ANSI__) */ - -#endif /* !__NO_ISOCEXT */ - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#include - -#endif diff --git a/tinyc/win32/include/string.h b/tinyc/win32/include/string.h deleted file mode 100644 index 3249dc3ba..000000000 --- a/tinyc/win32/include/string.h +++ /dev/null @@ -1,164 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STRING -#define _INC_STRING - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _NLSCMP_DEFINED -#define _NLSCMP_DEFINED -#define _NLSCMPERROR 2147483647 -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_MEMORY_DEFINED -#define _CRT_MEMORY_DEFINED - _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); - _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); - _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); - _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); - int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); - void *__cdecl memset(void *_Dst,int _Val,size_t _Size); -#ifndef NO_OLDNAMES - void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); - int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); -#endif -#endif - char *__cdecl _strset(char *_Str,int _Val); - char *__cdecl strcpy(char *_Dest,const char *_Source); - char *__cdecl strcat(char *_Dest,const char *_Source); - int __cdecl strcmp(const char *_Str1,const char *_Str2); - size_t __cdecl strlen(const char *_Str); -#if 0 - size_t __cdecl strnlen(const char *_Str,size_t _MaxCount); -#endif - void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size); - _CRTIMP char *__cdecl _strdup(const char *_Src); - _CONST_RETURN char *__cdecl strchr(const char *_Str,int _Val); - _CRTIMP int __cdecl _stricmp(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _strcmpi(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - int __cdecl strcoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _stricoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - size_t __cdecl strcspn(const char *_Str,const char *_Control); - _CRTIMP char *__cdecl _strerror(const char *_ErrMsg); - char *__cdecl strerror(int); - _CRTIMP char *__cdecl _strlwr(char *_String); - char *strlwr_l(char *_String,_locale_t _Locale); - char *__cdecl strncat(char *_Dest,const char *_Source,size_t _Count); - int __cdecl strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - char *strncpy(char *_Dest,const char *_Source,size_t _Count); - _CRTIMP char *__cdecl _strnset(char *_Str,int _Val,size_t _MaxCount); - _CONST_RETURN char *__cdecl strpbrk(const char *_Str,const char *_Control); - _CONST_RETURN char *__cdecl strrchr(const char *_Str,int _Ch); - _CRTIMP char *__cdecl _strrev(char *_Str); - size_t __cdecl strspn(const char *_Str,const char *_Control); - _CONST_RETURN char *__cdecl strstr(const char *_Str,const char *_SubStr); - char *__cdecl strtok(char *_Str,const char *_Delim); - _CRTIMP char *__cdecl _strupr(char *_String); - _CRTIMP char *_strupr_l(char *_String,_locale_t _Locale); - size_t __cdecl strxfrm(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _strxfrm_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - char *__cdecl strdup(const char *_Src); - int __cdecl strcmpi(const char *_Str1,const char *_Str2); - int __cdecl stricmp(const char *_Str1,const char *_Str2); - char *__cdecl strlwr(char *_Str); - int __cdecl strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount); - __CRT_INLINE int __cdecl strncasecmp (const char *__sz1, const char *__sz2, size_t __sizeMaxCompare) { return _strnicmp (__sz1, __sz2, __sizeMaxCompare); } - __CRT_INLINE int __cdecl strcasecmp (const char *__sz1, const char *__sz2) { return _stricmp (__sz1, __sz2); } - char *__cdecl strnset(char *_Str,int _Val,size_t _MaxCount); - char *__cdecl strrev(char *_Str); - char *__cdecl strset(char *_Str,int _Val); - char *__cdecl strupr(char *_Str); -#endif - -#ifndef _WSTRING_DEFINED -#define _WSTRING_DEFINED - - _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); - wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); - _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); - int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); - wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); - size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); - size_t __cdecl wcslen(const wchar_t *_Str); - size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); - wchar_t *wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); - size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); - wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); - _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); - _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); - _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); - _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); - _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); - _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); - _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); - size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); - int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - wchar_t *__cdecl wcsdup(const wchar_t *_Str); -#define wcswcs wcsstr - int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - wchar_t *__cdecl wcsrev(wchar_t *_Str); - wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); - wchar_t *__cdecl wcslwr(wchar_t *_Str); - wchar_t *__cdecl wcsupr(wchar_t *_Str); - int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#include -#endif diff --git a/tinyc/win32/include/sys/fcntl.h b/tinyc/win32/include/sys/fcntl.h deleted file mode 100644 index 29fd55a1f..000000000 --- a/tinyc/win32/include/sys/fcntl.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * This fcntl.h maps to the root fcntl.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif diff --git a/tinyc/win32/include/sys/file.h b/tinyc/win32/include/sys/file.h deleted file mode 100644 index 370f352d6..000000000 --- a/tinyc/win32/include/sys/file.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * This file.h maps to the root fcntl.h - * TODO? - */ -#ifndef __STRICT_ANSI__ -#include -#endif diff --git a/tinyc/win32/include/sys/locking.h b/tinyc/win32/include/sys/locking.h deleted file mode 100644 index e3fc85b3a..000000000 --- a/tinyc/win32/include/sys/locking.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_LOCKING -#define _INC_LOCKING - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -/* All the headers include this file. */ -#include <_mingw.h> - -#define _LK_UNLCK 0 -#define _LK_LOCK 1 -#define _LK_NBLCK 2 -#define _LK_RLCK 3 -#define _LK_NBRLCK 4 - -#ifndef NO_OLDNAMES -#define LK_UNLCK _LK_UNLCK -#define LK_LOCK _LK_LOCK -#define LK_NBLCK _LK_NBLCK -#define LK_RLCK _LK_RLCK -#define LK_NBRLCK _LK_NBRLCK -#endif - -#endif diff --git a/tinyc/win32/include/sys/stat.h b/tinyc/win32/include/sys/stat.h deleted file mode 100644 index 344d4a249..000000000 --- a/tinyc/win32/include/sys/stat.h +++ /dev/null @@ -1,290 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STAT -#define _INC_STAT - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#include - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED - typedef long __time32_t; -#define _TIME32_T_DEFINED -#endif - -#ifndef _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#define _TIME64_T_DEFINED -#endif - -#ifndef _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#define _TIME_T_DEFINED -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef _STAT_DEFINED - -#ifdef _USE_32BIT_TIME_T -#ifndef _WIN64 -#define _fstat32 _fstat -#define _stat32 _stat -#define _wstat32 _wstat -#else -#define _fstat _fstat32 -#define _stat _stat32 -#define _wstat _wstat32 -#endif -#define _fstati64 _fstat32i64 -#define _stati64 _stat32i64 -#define _wstati64 _wstat32i64 -#else -#define _fstat _fstat64i32 -#define _fstati64 _fstat64 -#define _stat _stat64i32 -#define _stati64 _stat64 -#define _wstat _wstat64i32 -#define _wstati64 _wstat64 -#endif - - struct _stat32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - -#ifndef NO_OLDNAMES - struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - struct _stat32i64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - - struct _stat64i32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; - - struct _stat64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; -#endif - -#define __stat64 _stat64 - -#define _STAT_DEFINED -#endif - -#define _S_IFMT 0xF000 -#define _S_IFDIR 0x4000 -#define _S_IFCHR 0x2000 -#define _S_IFIFO 0x1000 -#define _S_IFREG 0x8000 -#define _S_IREAD 0x0100 -#define _S_IWRITE 0x0080 -#define _S_IEXEC 0x0040 - - _CRTIMP int __cdecl _fstat32(int _FileDes,struct _stat32 *_Stat); - _CRTIMP int __cdecl _stat32(const char *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _fstat64(int _FileDes,struct _stat64 *_Stat); - _CRTIMP int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat); - int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat); - __CRT_INLINE int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) - { - struct _stat64 st; - int ret=_fstat64(_FileDes,&st); - _Stat->st_dev=st.st_dev; - _Stat->st_ino=st.st_ino; - _Stat->st_mode=st.st_mode; - _Stat->st_nlink=st.st_nlink; - _Stat->st_uid=st.st_uid; - _Stat->st_gid=st.st_gid; - _Stat->st_rdev=st.st_rdev; - _Stat->st_size=(_off_t) st.st_size; - _Stat->st_atime=st.st_atime; - _Stat->st_mtime=st.st_mtime; - _Stat->st_ctime=st.st_ctime; - return ret; - } - _CRTIMP int __cdecl _stat64(const char *_Name,struct _stat64 *_Stat); - _CRTIMP int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat); - int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat); - __CRT_INLINE int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) - { - struct _stat64 st; - int ret=_stat64(_Name,&st); - _Stat->st_dev=st.st_dev; - _Stat->st_ino=st.st_ino; - _Stat->st_mode=st.st_mode; - _Stat->st_nlink=st.st_nlink; - _Stat->st_uid=st.st_uid; - _Stat->st_gid=st.st_gid; - _Stat->st_rdev=st.st_rdev; - _Stat->st_size=(_off_t) st.st_size; - _Stat->st_atime=st.st_atime; - _Stat->st_mtime=st.st_mtime; - _Stat->st_ctime=st.st_ctime; - return ret; - } -#endif - -#ifndef _WSTAT_DEFINED -#define _WSTAT_DEFINED - _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); - int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); - _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); -#endif -#endif - -#ifndef NO_OLDNAMES -#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ - -#define S_IFMT _S_IFMT -#define S_IFDIR _S_IFDIR -#define S_IFCHR _S_IFCHR -#define S_IFREG _S_IFREG -#define S_IREAD _S_IREAD -#define S_IWRITE _S_IWRITE -#define S_IEXEC _S_IEXEC -#define S_IFIFO _S_IFIFO -#define S_IFBLK _S_IFBLK - -#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) -#define _S_IXUSR _S_IEXEC -#define _S_IWUSR _S_IWRITE - -#define S_IRWXU _S_IRWXU -#define S_IXUSR _S_IXUSR -#define S_IWUSR _S_IWUSR -#define S_IRUSR _S_IRUSR -#define _S_IRUSR _S_IREAD - -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) - -#endif - -#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) -int __cdecl stat(const char *_Filename,struct stat *_Stat); -int __cdecl fstat(int _Desc,struct stat *_Stat); -int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat); -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { - return _fstat32(_Desc,(struct _stat32 *)_Stat); -} -__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { - return _stat32(_Filename,(struct _stat32 *)_Stat); -} -#else -__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { - return _fstat64i32(_Desc,(struct _stat64i32 *)_Stat); -} -__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { - return _stat64i32(_Filename,(struct _stat64i32 *)_Stat); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/sys/time.h b/tinyc/win32/include/sys/time.h deleted file mode 100644 index 8ccab8319..000000000 --- a/tinyc/win32/include/sys/time.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _SYS_TIME_H_ -#define _SYS_TIME_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __STRICT_ANSI__ -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED -struct timeval { - long tv_sec; - long tv_usec; -}; -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec != (uvp)->tv_sec) ? \ - ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ - ((tvp)->tv_usec cmp (uvp)->tv_usec)) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ -#define _TIMEZONE_DEFINED -/* Provided for compatibility with code that assumes that - the presence of gettimeofday function implies a definition - of struct timezone. */ -struct timezone -{ - int tz_minuteswest; /* of Greenwich */ - int tz_dsttime; /* type of dst correction to apply */ -}; - - extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); - -#endif - -/* - Implementation as per: - The Open Group Base Specifications, Issue 6 - IEEE Std 1003.1, 2004 Edition - - The timezone pointer arg is ignored. Errors are ignored. -*/ -#ifndef _GETTIMEOFDAY_DEFINED -#define _GETTIMEOFDAY_DEFINED -int __cdecl gettimeofday(struct timeval *__restrict__, - void *__restrict__ /* tzp (unused) */); -#endif - -#endif /* __STRICT_ANSI__ */ - -#ifdef __cplusplus -} -#endif - -/* Adding timespec definition. */ -#include - - -#endif /* _SYS_TIME_H_ */ diff --git a/tinyc/win32/include/sys/timeb.h b/tinyc/win32/include/sys/timeb.h deleted file mode 100644 index 34837738b..000000000 --- a/tinyc/win32/include/sys/timeb.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIMEB_H_ -#define _TIMEB_H_ - -#include <_mingw.h> - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED - typedef long __time32_t; -#define _TIME32_T_DEFINED -#endif - -#ifndef _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#define _TIME64_T_DEFINED -#endif - -#ifndef _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#define _TIME_T_DEFINED -#endif - -#ifndef _TIMEB_DEFINED -#define _TIMEB_DEFINED - - struct __timeb32 { - __time32_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; - -#ifndef NO_OLDNAMES - struct timeb { - time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - struct __timeb64 { - __time64_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; -#endif - -#ifdef _USE_32BIT_TIME_T -#define _timeb __timeb32 -//gr #define _ftime _ftime32 -#define _ftime32 _ftime -#else -#define _timeb __timeb64 -#define _ftime _ftime64 -#endif -#endif - - _CRTIMP void __cdecl _ftime32(struct __timeb32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP void __cdecl _ftime64(struct __timeb64 *_Time); -#endif - -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; - -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; -#endif - -#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { - _ftime32((struct __timeb32 *)_Tmb); -} -#else -__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { - _ftime64((struct __timeb64 *)_Tmb); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#endif diff --git a/tinyc/win32/include/sys/types.h b/tinyc/win32/include/sys/types.h deleted file mode 100644 index 7379b0f1e..000000000 --- a/tinyc/win32/include/sys/types.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_TYPES -#define _INC_TYPES - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED -typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 -typedef __int64 __time64_t; -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T -typedef __time32_t time_t; -#else -typedef __time64_t time_t; -#endif -#endif - -#ifndef _INO_T_DEFINED -#define _INO_T_DEFINED -typedef unsigned short _ino_t; -#ifndef NO_OLDNAMES -typedef unsigned short ino_t; -#endif -#endif - -#ifndef _DEV_T_DEFINED -#define _DEV_T_DEFINED -typedef unsigned int _dev_t; -#ifndef NO_OLDNAMES -typedef unsigned int dev_t; -#endif -#endif - -#ifndef _PID_T_ -#define _PID_T_ -#ifndef _WIN64 -typedef int _pid_t; -#else -typedef __int64 _pid_t; -#endif - -#ifndef NO_OLDNAMES -typedef _pid_t pid_t; -#endif -#endif /* Not _PID_T_ */ - -#ifndef _MODE_T_ -#define _MODE_T_ -typedef unsigned short _mode_t; - -#ifndef NO_OLDNAMES -typedef _mode_t mode_t; -#endif -#endif /* Not _MODE_T_ */ - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; - -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; -#endif - -#endif diff --git a/tinyc/win32/include/sys/unistd.h b/tinyc/win32/include/sys/unistd.h deleted file mode 100644 index 31006d325..000000000 --- a/tinyc/win32/include/sys/unistd.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * unistd.h maps (roughly) to io.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif - diff --git a/tinyc/win32/include/sys/utime.h b/tinyc/win32/include/sys/utime.h deleted file mode 100644 index fec8304ff..000000000 --- a/tinyc/win32/include/sys/utime.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_UTIME -#define _INC_UTIME - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED - typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#endif - -#ifndef _UTIMBUF_DEFINED -#define _UTIMBUF_DEFINED - - struct _utimbuf { - time_t actime; - time_t modtime; - }; - - struct __utimbuf32 { - __time32_t actime; - __time32_t modtime; - }; - -#if _INTEGRAL_MAX_BITS >= 64 - struct __utimbuf64 { - __time64_t actime; - __time64_t modtime; - }; -#endif - -#ifndef NO_OLDNAMES - struct utimbuf { - time_t actime; - time_t modtime; - }; - - struct utimbuf32 { - __time32_t actime; - __time32_t modtime; - }; -#endif -#endif - - _CRTIMP int __cdecl _utime32(const char *_Filename,struct __utimbuf32 *_Time); - _CRTIMP int __cdecl _futime32(int _FileDes,struct __utimbuf32 *_Time); - _CRTIMP int __cdecl _wutime32(const wchar_t *_Filename,struct __utimbuf32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _utime64(const char *_Filename,struct __utimbuf64 *_Time); - _CRTIMP int __cdecl _futime64(int _FileDes,struct __utimbuf64 *_Time); - _CRTIMP int __cdecl _wutime64(const wchar_t *_Filename,struct __utimbuf64 *_Time); -#endif - -#ifndef RC_INVOKED -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { - return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { - return _futime32(_Desc,(struct __utimbuf32 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { - return _wutime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -#else -__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { - return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { - return _futime64(_Desc,(struct __utimbuf64 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { - return _wutime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -#endif - -#ifndef NO_OLDNAMES -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { - return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -#else -__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { - return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -#endif -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/tcc/tcc_libm.h b/tinyc/win32/include/tcc/tcc_libm.h deleted file mode 100644 index 0a62e6fb7..000000000 --- a/tinyc/win32/include/tcc/tcc_libm.h +++ /dev/null @@ -1,201 +0,0 @@ -#ifndef _TCC_LIBM_H_ -#define _TCC_LIBM_H_ - -#include "../math.h" - -/* TCC uses 8 bytes for double and long double, so effectively the l variants - * are never used. For now, they just run the normal (double) variant. - */ - -/* - * most of the code in this file is taken from MUSL rs-1.0 (MIT license) - * - musl-libc: http://git.musl-libc.org/cgit/musl/tree/src/math?h=rs-1.0 - * - License: http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT?h=rs-1.0 - */ - -/******************************************************************************* - Start of code based on MUSL -*******************************************************************************/ -/* -musl as a whole is licensed under the following standard MIT license: - ----------------------------------------------------------------------- -Copyright © 2005-2014 Rich Felker, et al. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- -*/ - -/* fpclassify */ - -__CRT_INLINE int __cdecl __fpclassify (double x) { - union {double f; uint64_t i;} u = {x}; - int e = u.i>>52 & 0x7ff; - if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; - if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -__CRT_INLINE int __cdecl __fpclassifyf (float x) { - union {float f; uint32_t i;} u = {x}; - int e = u.i>>23 & 0xff; - if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; - if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -__CRT_INLINE int __cdecl __fpclassifyl (long double x) { - return __fpclassify(x); -} - - -/* signbit */ - -__CRT_INLINE int __cdecl __signbit (double x) { - union {double d; uint64_t i;} y = { x }; - return y.i>>63; -} - -__CRT_INLINE int __cdecl __signbitf (float x) { - union {float f; uint32_t i; } y = { x }; - return y.i>>31; -} - -__CRT_INLINE int __cdecl __signbitl (long double x) { - return __signbit(x); -} - - -/* fmin*, fmax* */ - -#define TCCFP_FMIN_EVAL (isnan(x) ? y : \ - isnan(y) ? x : \ - (signbit(x) != signbit(y)) ? (signbit(x) ? x : y) : \ - x < y ? x : y) - -__CRT_INLINE double __cdecl fmin (double x, double y) { - return TCCFP_FMIN_EVAL; -} - -__CRT_INLINE float __cdecl fminf (float x, float y) { - return TCCFP_FMIN_EVAL; -} - -__CRT_INLINE long double __cdecl fminl (long double x, long double y) { - return TCCFP_FMIN_EVAL; -} - -#define TCCFP_FMAX_EVAL (isnan(x) ? y : \ - isnan(y) ? x : \ - (signbit(x) != signbit(y)) ? (signbit(x) ? y : x) : \ - x < y ? y : x) - -__CRT_INLINE double __cdecl fmax (double x, double y) { - return TCCFP_FMAX_EVAL; -} - -__CRT_INLINE float __cdecl fmaxf (float x, float y) { - return TCCFP_FMAX_EVAL; -} - -__CRT_INLINE long double __cdecl fmaxl (long double x, long double y) { - return TCCFP_FMAX_EVAL; -} - - -/* *round* */ - -#define TCCFP_FORCE_EVAL(x) do { \ -if (sizeof(x) == sizeof(float)) { \ - volatile float __x; \ - __x = (x); \ -} else if (sizeof(x) == sizeof(double)) { \ - volatile double __x; \ - __x = (x); \ -} else { \ - volatile long double __x; \ - __x = (x); \ -} \ -} while(0) - -__CRT_INLINE double __cdecl round (double x) { - union {double f; uint64_t i;} u = {x}; - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff+52) - return x; - if (u.i >> 63) - x = -x; - if (e < 0x3ff-1) { - /* raise inexact if x!=0 */ - TCCFP_FORCE_EVAL(x + 0x1p52); - return 0*u.f; - } - y = (double)(x + 0x1p52) - 0x1p52 - x; - if (y > 0.5) - y = y + x - 1; - else if (y <= -0.5) - y = y + x + 1; - else - y = y + x; - if (u.i >> 63) - y = -y; - return y; -} - -__CRT_INLINE long __cdecl lround (double x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llround (double x) { - return round(x); -} - -__CRT_INLINE float __cdecl roundf (float x) { - return round(x); -} - -__CRT_INLINE long __cdecl lroundf (float x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llroundf (float x) { - return round(x); -} - -__CRT_INLINE long double __cdecl roundl (long double x) { - return round(x); -} - -__CRT_INLINE long __cdecl lroundl (long double x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llroundl (long double x) { - return round(x); -} - - -/******************************************************************************* - End of code based on MUSL -*******************************************************************************/ - -#endif /* _TCC_LIBM_H_ */ diff --git a/tinyc/win32/include/tchar.h b/tinyc/win32/include/tchar.h deleted file mode 100644 index cd44beca1..000000000 --- a/tinyc/win32/include/tchar.h +++ /dev/null @@ -1,1102 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#ifndef _INC_TCHAR -#define _INC_TCHAR - -#ifdef _STRSAFE_H_INCLUDED_ -#error Need to include strsafe.h after tchar.h -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define _ftcscat _tcscat -#define _ftcschr _tcschr -#define _ftcscpy _tcscpy -#define _ftcscspn _tcscspn -#define _ftcslen _tcslen -#define _ftcsncat _tcsncat -#define _ftcsncpy _tcsncpy -#define _ftcspbrk _tcspbrk -#define _ftcsrchr _tcsrchr -#define _ftcsspn _tcsspn -#define _ftcsstr _tcsstr -#define _ftcstok _tcstok - -#define _ftcsdup _tcsdup -#define _ftcsnset _tcsnset -#define _ftcsrev _tcsrev -#define _ftcsset _tcsset - -#define _ftcscmp _tcscmp -#define _ftcsicmp _tcsicmp -#define _ftcsnccmp _tcsnccmp -#define _ftcsncmp _tcsncmp -#define _ftcsncicmp _tcsncicmp -#define _ftcsnicmp _tcsnicmp - -#define _ftcscoll _tcscoll -#define _ftcsicoll _tcsicoll -#define _ftcsnccoll _tcsnccoll -#define _ftcsncoll _tcsncoll -#define _ftcsncicoll _tcsncicoll -#define _ftcsnicoll _tcsnicoll - -#define _ftcsclen _tcsclen -#define _ftcsnccat _tcsnccat -#define _ftcsnccpy _tcsnccpy -#define _ftcsncset _tcsncset - -#define _ftcsdec _tcsdec -#define _ftcsinc _tcsinc -#define _ftcsnbcnt _tcsnbcnt -#define _ftcsnccnt _tcsnccnt -#define _ftcsnextc _tcsnextc -#define _ftcsninc _tcsninc -#define _ftcsspnp _tcsspnp - -#define _ftcslwr _tcslwr -#define _ftcsupr _tcsupr - -#define _ftclen _tclen -#define _ftccpy _tccpy -#define _ftccmp _tccmp - -#ifndef _CONST_RETURN -#ifdef __cplusplus -#define _CONST_RETURN const -#define _CRT_CONST_CORRECT_OVERLOADS -#else -#define _CONST_RETURN -#endif -#endif - -#define _WConst_return _CONST_RETURN - -#ifdef _UNICODE - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#endif - -#ifndef __TCHAR_DEFINED -#define __TCHAR_DEFINED - typedef wchar_t _TCHAR; - typedef wchar_t _TSCHAR; - typedef wchar_t _TUCHAR; - typedef wchar_t _TXCHAR; - typedef wint_t _TINT; -#endif - -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef wchar_t TCHAR; -#endif -#endif - -#define _TEOF WEOF - -#define __T(x) L##x - -#define _tmain wmain -#define _tWinMain wWinMain -#define _tenviron _wenviron -#define __targv __wargv - -#define _tprintf wprintf -#define _tprintf_l _wprintf_l -#define _tprintf_p _wprintf_p -#define _tprintf_p_l _wprintf_p_l -#define _tcprintf _cwprintf -#define _tcprintf_l _cwprintf_l -#define _tcprintf_p _cwprintf_p -#define _tcprintf_p_l _cwprintf_p_l -#define _vtcprintf _vcwprintf -#define _vtcprintf_l _vcwprintf_l -#define _vtcprintf_p _vcwprintf_p -#define _vtcprintf_p_l _vcwprintf_p_l -#define _ftprintf fwprintf -#define _ftprintf_l _fwprintf_l -#define _ftprintf_p _fwprintf_p -#define _ftprintf_p_l _fwprintf_p_l -#define _stprintf swprintf -#define _stprintf_l __swprintf_l -#define _stprintf_p _swprintf_p -#define _stprintf_p_l _swprintf_p_l -#define _sctprintf _scwprintf -#define _sctprintf_l _scwprintf_l -#define _sctprintf_p _scwprintf_p -#define _sctprintf_p_l _scwprintf_p_l -#define _sntprintf _snwprintf -#define _sntprintf_l _snwprintf_l -#define _vtprintf vwprintf -#define _vtprintf_l _vwprintf_l -#define _vtprintf_p _vwprintf_p -#define _vtprintf_p_l _vwprintf_p_l -#define _vftprintf vfwprintf -#define _vftprintf_l _vfwprintf_l -#define _vftprintf_p _vfwprintf_p -#define _vftprintf_p_l _vfwprintf_p_l -#define _vstprintf vswprintf -#define _vstprintf_l _vswprintf_l -#define _vstprintf_p _vswprintf_p -#define _vstprintf_p_l _vswprintf_p_l -#define _vsctprintf _vscwprintf -#define _vsctprintf_l _vscwprintf_l -#define _vsctprintf_p _vscwprintf_p -#define _vsctprintf_p_l _vscwprintf_p_l -#define _vsntprintf _vsnwprintf -#define _vsntprintf_l _vsnwprintf_l - -#define _tscanf wscanf -#define _tscanf_l _wscanf_l -#define _tcscanf _cwscanf -#define _tcscanf_l _cwscanf_l -#define _ftscanf fwscanf -#define _ftscanf_l _fwscanf_l -#define _stscanf swscanf -#define _stscanf_l _swscanf_l -#define _sntscanf _snwscanf -#define _sntscanf_l _snwscanf_l - -#define _fgettc fgetwc -#define _fgettc_nolock _fgetwc_nolock -#define _fgettchar _fgetwchar -#define _fgetts fgetws -#define _fputtc fputwc -#define _fputtc_nolock _fputwc_nolock -#define _fputtchar _fputwchar -#define _fputts fputws -#define _cputts _cputws -#define _cgetts _cgetws -#define _gettc getwc -#define _gettc_nolock _getwc_nolock -#define _gettch _getwch -#define _gettch_nolock _getwch_nolock -#define _gettche _getwche -#define _gettche_nolock _getwche_nolock -#define _gettchar getwchar -#define _gettchar_nolock _getwchar_nolock -#define _getts _getws -#define _puttc putwc -#define _puttc_nolock _putwc_nolock -#define _puttchar putwchar -#define _puttchar_nolock _putwchar_nolock -#define _puttch _putwch -#define _puttch_nolock _putwch_nolock -#define _putts _putws -#define _ungettc ungetwc -#define _ungettc_nolock _ungetwc_nolock -#define _ungettch _ungetwch -#define _ungettch_nolock _ungetwch_nolock - -#define _tcstod wcstod -#define _tcstol wcstol -#define _tcstoul wcstoul -#define _tcstoi64 _wcstoi64 -#define _tcstoui64 _wcstoui64 -#define _tstof _wtof -#define _tstol _wtol -#define _tstoi _wtoi -#define _tstoi64 _wtoi64 -#define _tcstod_l _wcstod_l -#define _tcstol_l _wcstol_l -#define _tcstoul_l _wcstoul_l -#define _tcstoi64_l _wcstoi64_l -#define _tcstoui64_l _wcstoui64_l -#define _tstof_l _wtof_l -#define _tstol_l _wtol_l -#define _tstoi_l _wtoi_l -#define _tstoi64_l _wtoi64_l - -#define _itot _itow -#define _ltot _ltow -#define _ultot _ultow -#define _ttoi _wtoi -#define _ttol _wtol - -#define _ttoi64 _wtoi64 -#define _i64tot _i64tow -#define _ui64tot _ui64tow - -#define _tcscat wcscat -#define _tcschr wcschr -#define _tcscpy wcscpy -#define _tcscspn wcscspn -#define _tcslen wcslen -#define _tcsnlen wcsnlen -#define _tcsncat wcsncat -#define _tcsncat_l _wcsncat_l -#define _tcsncpy wcsncpy -#define _tcsncpy_l _wcsncpy_l -#define _tcspbrk wcspbrk -#define _tcsrchr wcsrchr -#define _tcsspn wcsspn -#define _tcsstr wcsstr -#define _tcstok wcstok -#define _tcstok_l _wcstok_l -#define _tcserror _wcserror -#define __tcserror __wcserror - -#define _tcsdup _wcsdup -#define _tcsnset _wcsnset -#define _tcsnset_l _wcsnset_l -#define _tcsrev _wcsrev -#define _tcsset _wcsset -#define _tcsset_l _wcsset_l - -#define _tcscmp wcscmp -#define _tcsicmp _wcsicmp -#define _tcsicmp_l _wcsicmp_l -#define _tcsnccmp wcsncmp -#define _tcsncmp wcsncmp -#define _tcsncicmp _wcsnicmp -#define _tcsncicmp_l _wcsnicmp_l -#define _tcsnicmp _wcsnicmp -#define _tcsnicmp_l _wcsnicmp_l - -#define _tcscoll wcscoll -#define _tcscoll_l _wcscoll_l -#define _tcsicoll _wcsicoll -#define _tcsicoll_l _wcsicoll_l -#define _tcsnccoll _wcsncoll -#define _tcsnccoll_l _wcsncoll_l -#define _tcsncoll _wcsncoll -#define _tcsncoll_l _wcsncoll_l -#define _tcsncicoll _wcsnicoll -#define _tcsncicoll_l _wcsnicoll_l -#define _tcsnicoll _wcsnicoll -#define _tcsnicoll_l _wcsnicoll_l - -#define _texecl _wexecl -#define _texecle _wexecle -#define _texeclp _wexeclp -#define _texeclpe _wexeclpe -#define _texecv _wexecv -#define _texecve _wexecve -#define _texecvp _wexecvp -#define _texecvpe _wexecvpe - -#define _tspawnl _wspawnl -#define _tspawnle _wspawnle -#define _tspawnlp _wspawnlp -#define _tspawnlpe _wspawnlpe -#define _tspawnv _wspawnv -#define _tspawnve _wspawnve -#define _tspawnvp _wspawnvp -#define _tspawnvp _wspawnvp -#define _tspawnvpe _wspawnvpe - -#define _tsystem _wsystem - -#define _tasctime _wasctime -#define _tctime _wctime -#define _tctime32 _wctime32 -#define _tctime64 _wctime64 -#define _tstrdate _wstrdate -#define _tstrtime _wstrtime -#define _tutime _wutime -#define _tutime32 _wutime32 -#define _tutime64 _wutime64 -#define _tcsftime wcsftime -#define _tcsftime_l _wcsftime_l - -#define _tchdir _wchdir -#define _tgetcwd _wgetcwd -#define _tgetdcwd _wgetdcwd -#define _tgetdcwd_nolock _wgetdcwd_nolock -#define _tmkdir _wmkdir -#define _trmdir _wrmdir - -#define _tfullpath _wfullpath -#define _tgetenv _wgetenv -#define _tmakepath _wmakepath -#define _tpgmptr _wpgmptr -#define _get_tpgmptr _get_wpgmptr -#define _tputenv _wputenv -#define _tsearchenv _wsearchenv -#define _tsplitpath _wsplitpath - -#define _tfdopen _wfdopen -#define _tfsopen _wfsopen -#define _tfopen _wfopen -#define _tfreopen _wfreopen -#define _tperror _wperror -#define _tpopen _wpopen -#define _ttempnam _wtempnam -#define _ttmpnam _wtmpnam - -#define _taccess _waccess -#define _tchmod _wchmod -#define _tcreat _wcreat -#define _tfindfirst _wfindfirst -#define _tfindfirst32 _wfindfirst32 -#define _tfindfirst64 _wfindfirst64 -#define _tfindfirsti64 _wfindfirsti64 -#define _tfindfirst32i64 _wfindfirst32i64 -#define _tfindfirst64i32 _wfindfirst64i32 -#define _tfindnext _wfindnext -#define _tfindnext32 _wfindnext32 -#define _tfindnext64 _wfindnext64 -#define _tfindnexti64 _wfindnexti64 -#define _tfindnext32i64 _wfindnext32i64 -#define _tfindnext64i32 _wfindnext64i32 -#define _tmktemp _wmktemp -#define _topen _wopen -#define _tremove _wremove -#define _trename _wrename -#define _tsopen _wsopen -#define _tunlink _wunlink - -#define _tfinddata_t _wfinddata_t -#define _tfinddata32_t _wfinddata32_t -#define _tfinddata64_t _wfinddata64_t -#define _tfinddatai64_t _wfinddatai64_t -#define _tfinddata32i64_t _wfinddata32i64_t -#define _tfinddata64i32_t _wfinddata64i32_t - -#define _tstat _wstat -#define _tstat32 _wstat32 -#define _tstat32i64 _wstat32i64 -#define _tstat64 _wstat64 -#define _tstat64i32 _wstat64i32 -#define _tstati64 _wstati64 - -#define _tsetlocale _wsetlocale - -#define _tcsclen wcslen -#define _tcscnlen wcsnlen -#define _tcsclen_l(_String,_Locale) wcslen(_String) -#define _tcscnlen_l(_String,_Max_count,_Locale) wcsnlen_l((_String),(_Max_count)) -#define _tcsnccat wcsncat -#define _tcsnccat_l _wcsncat_l -#define _tcsnccpy wcsncpy -#define _tcsnccpy_l _wcsncpy_l -#define _tcsncset _wcsnset - -#define _tcsdec _wcsdec -#define _tcsinc _wcsinc -#define _tcsnbcnt _wcsncnt -#define _tcsnccnt _wcsncnt -#define _tcsnextc _wcsnextc -#define _tcsninc _wcsninc -#define _tcsspnp _wcsspnp - -#define _tcslwr _wcslwr -#define _tcslwr_l _wcslwr_l -#define _tcsupr _wcsupr -#define _tcsupr_l _wcsupr_l -#define _tcsxfrm wcsxfrm -#define _tcsxfrm_l _wcsxfrm_l - -#define _tclen(_pc) (1) -#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2))) -#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2))) - -#define _istalnum iswalnum -#define _istalnum_l _iswalnum_l -#define _istalpha iswalpha -#define _istalpha_l _iswalpha_l -#define _istascii iswascii -#define _istcntrl iswcntrl -#define _istcntrl_l _iswcntrl_l -#define _istdigit iswdigit -#define _istdigit_l _iswdigit_l -#define _istgraph iswgraph -#define _istgraph_l _iswgraph_l -#define _istlower iswlower -#define _istlower_l _iswlower_l -#define _istprint iswprint -#define _istprint_l _iswprint_l -#define _istpunct iswpunct -#define _istpunct_l _iswpunct_l -#define _istspace iswspace -#define _istspace_l _iswspace_l -#define _istupper iswupper -#define _istupper_l _iswupper_l -#define _istxdigit iswxdigit -#define _istxdigit_l _iswxdigit_l - -#define _totupper towupper -#define _totupper_l _towupper_l -#define _totlower towlower -#define _totlower_l _towlower_l - -#define _istlegal(_Char) (1) -#define _istlead(_Char) (0) -#define _istleadbyte(_Char) (0) -#define _istleadbyte_l(_Char,_Locale) (0) - -#define _wcsdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) -#define _wcsinc(_pc) ((_pc)+1) -#define _wcsnextc(_cpc) ((unsigned int) *(_cpc)) -#define _wcsninc(_pc,_sz) (((_pc)+(_sz))) - _CRTIMP size_t __cdecl __wcsncnt(const wchar_t *_Str,size_t _MaxCount); -#define _wcsncnt(_cpc,_sz) (__wcsncnt(_cpc,_sz)) -#define _wcsspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)) -#define _wcsncpy_l(_Destination,_Source,_Count,_Locale) (wcsncpy(_Destination,_Source,_Count)) -#define _wcsncat_l(_Destination,_Source,_Count,_Locale) (wcsncat(_Destination,_Source,_Count)) -#define _wcstok_l(_String,_Delimiters,_Locale) (wcstok(_String,_Delimiters)) -#define _wcsnset_l(_Destination,_Value,_Count,_Locale) (_wcsnset(_Destination,_Value,_Count)) -#define _wcsset_l(_Destination,_Value,_Locale) (_wcsset(_Destination,_Value)) - - /* dirent structures and functions */ -#define _tdirent _wdirent -#define _TDIR _WDIR -#define _topendir _wopendir -#define _tclosedir _wclosedir -#define _treaddir _wreaddir -#define _trewinddir _wrewinddir -#define _ttelldir _wtelldir -#define _tseekdir _wseekdir - -#else - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define _TEOF EOF - -#define __T(x) x - -#define _tmain main -#define _tWinMain WinMain -#ifdef _POSIX_ -#define _tenviron environ -#else -#define _tenviron _environ -#endif -#define __targv __argv - -#define _tprintf printf -#define _tprintf_l _printf_l -#define _tprintf_p _printf_p -#define _tprintf_p_l _printf_p_l -#define _tcprintf _cprintf -#define _tcprintf_l _cprintf_l -#define _tcprintf_p _cprintf_p -#define _tcprintf_p_l _cprintf_p_l -#define _vtcprintf _vcprintf -#define _vtcprintf_l _vcprintf_l -#define _vtcprintf_p _vcprintf_p -#define _vtcprintf_p_l _vcprintf_p_l -#define _ftprintf fprintf -#define _ftprintf_l _fprintf_l -#define _ftprintf_p _fprintf_p -#define _ftprintf_p_l _fprintf_p_l -#define _stprintf sprintf -#define _stprintf_l _sprintf_l -#define _stprintf_p _sprintf_p -#define _stprintf_p_l _sprintf_p_l -#define _sctprintf _scprintf -#define _sctprintf_l _scprintf_l -#define _sctprintf_p _scprintf_p -#define _sctprintf_p_l _scprintf_p_l -#define _sntprintf _snprintf -#define _sntprintf_l _snprintf_l -#define _vtprintf vprintf -#define _vtprintf_l _vprintf_l -#define _vtprintf_p _vprintf_p -#define _vtprintf_p_l _vprintf_p_l -#define _vftprintf vfprintf -#define _vftprintf_l _vfprintf_l -#define _vftprintf_p _vfprintf_p -#define _vftprintf_p_l _vfprintf_p_l -#define _vstprintf vsprintf -#define _vstprintf_l _vsprintf_l -#define _vstprintf_p _vsprintf_p -#define _vstprintf_p_l _vsprintf_p_l -#define _vsctprintf _vscprintf -#define _vsctprintf_l _vscprintf_l -#define _vsctprintf_p _vscprintf_p -#define _vsctprintf_p_l _vscprintf_p_l -#define _vsntprintf _vsnprintf -#define _vsntprintf_l _vsnprintf_l - -#define _tscanf scanf -#define _tscanf_l _scanf_l -#define _tcscanf _cscanf -#define _tcscanf_l _cscanf_l -#define _ftscanf fscanf -#define _ftscanf_l _fscanf_l -#define _stscanf sscanf -#define _stscanf_l _sscanf_l -#define _sntscanf _snscanf -#define _sntscanf_l _snscanf_l - -#define _fgettc fgetc -#define _fgettc_nolock _fgetc_nolock -#define _fgettchar _fgetchar -#define _fgetts fgets -#define _fputtc fputc -#define _fputtc_nolock _fputc_nolock -#define _fputtchar _fputchar -#define _fputts fputs -#define _cputts _cputs -#define _gettc getc -#define _gettc_nolock _getc_nolock -#define _gettch _getch -#define _gettch_nolock _getch_nolock -#define _gettche _getche -#define _gettche_nolock _getche_nolock -#define _gettchar getchar -#define _gettchar_nolock _getchar_nolock -#define _getts gets -#define _cgetts _cgets -#define _puttc putc -#define _puttc_nolock _putc_nolock -#define _puttchar putchar -#define _puttchar_nolock _putchar_nolock -#define _puttch _putch -#define _puttch_nolock _putch_nolock -#define _putts puts -#define _ungettc ungetc -#define _ungettc_nolock _ungetc_nolock -#define _ungettch _ungetch -#define _ungettch_nolock _ungetch_nolock - -#define _tcstod strtod -#define _tcstol strtol -#define _tcstoul strtoul -#define _tstof atof -#define _tstol atol -#define _tstoi atoi -#define _tstoi64 _atoi64 -#define _tcstod_l _strtod_l -#define _tcstol_l _strtol_l -#define _tcstoul_l _strtoul_l -#define _tstof_l _atof_l -#define _tstol_l _atol_l -#define _tstoi_l _atoi_l -#define _tstoi64_l _atoi64_l - -#define _itot _itoa -#define _ltot _ltoa -#define _ultot _ultoa -#define _ttoi atoi -#define _ttol atol - -#define _ttoi64 _atoi64 -#define _tcstoi64 _strtoi64 -#define _tcstoi64_l _strtoi64_l -#define _tcstoui64 _strtoui64 -#define _tcstoui64_l _strtoui64_l -#define _i64tot _i64toa -#define _ui64tot _ui64toa - -#define _tcscat strcat -#define _tcscpy strcpy -#define _tcsdup _strdup -#define _tcslen strlen -#if 0 -#define _tcsnlen strnlen -#endif -#define _tcsxfrm strxfrm -#define _tcsxfrm_l _strxfrm_l -#define _tcserror strerror -#define __tcserror _strerror - -#define _texecl _execl -#define _texecle _execle -#define _texeclp _execlp -#define _texeclpe _execlpe -#define _texecv _execv -#define _texecve _execve -#define _texecvp _execvp -#define _texecvpe _execvpe - -#define _tspawnl _spawnl -#define _tspawnle _spawnle -#define _tspawnlp _spawnlp -#define _tspawnlpe _spawnlpe -#define _tspawnv _spawnv -#define _tspawnve _spawnve -#define _tspawnvp _spawnvp -#define _tspawnvpe _spawnvpe - -#define _tsystem system - -#define _tasctime asctime -#define _tctime ctime -#define _tctime32 _ctime32 -#define _tctime64 _ctime64 -#define _tstrdate _strdate -#define _tstrtime _strtime -#define _tutime _utime -#define _tutime32 _utime32 -#define _tutime64 _utime64 -#define _tcsftime strftime -#define _tcsftime_l _strftime_l - -#define _tchdir _chdir -#define _tgetcwd _getcwd -#define _tgetdcwd _getdcwd -#define _tgetdcwd_nolock _getdcwd_nolock -#define _tmkdir _mkdir -#define _trmdir _rmdir - -#define _tfullpath _fullpath -#define _tgetenv getenv -#define _tmakepath _makepath -#define _tpgmptr _pgmptr -#define _get_tpgmptr _get_pgmptr -#define _tputenv _putenv -#define _tsearchenv _searchenv -#define _tsplitpath _splitpath - -#ifdef _POSIX_ -#define _tfdopen fdopen -#else -#define _tfdopen _fdopen -#endif -#define _tfsopen _fsopen -#define _tfopen fopen -#define _tfreopen freopen -#define _tperror perror -#define _tpopen _popen -#define _ttempnam _tempnam -#define _ttmpnam tmpnam - -#define _tchmod _chmod -#define _tcreat _creat -#define _tfindfirst _findfirst -#define _tfindfirst32 _findfirst32 -#define _tfindfirst64 _findfirst64 -#define _tfindfirsti64 _findfirsti64 -#define _tfindfirst32i64 _findfirst32i64 -#define _tfindfirst64i32 _findfirst64i32 -#define _tfindnext _findnext -#define _tfindnext32 _findnext32 -#define _tfindnext64 _findnext64 -#define _tfindnexti64 _findnexti64 -#define _tfindnext32i64 _findnext32i64 -#define _tfindnext64i32 _findnext64i32 -#define _tmktemp _mktemp - -#ifdef _POSIX_ -#define _topen open -#define _taccess access -#else -#define _topen _open -#define _taccess _access -#endif - -#define _tremove remove -#define _trename rename -#define _tsopen _sopen -#define _tunlink _unlink - -#define _tfinddata_t _finddata_t -#define _tfinddata32_t _finddata32_t -#define _tfinddata64_t __finddata64_t -#define _tfinddatai64_t _finddatai64_t -#define _tfinddata32i64_t _finddata32i64_t -#define _tfinddata64i32_t _finddata64i32_t - -#define _istascii __isascii -#define _istcntrl iscntrl -#define _istcntrl_l _iscntrl_l -#define _istxdigit isxdigit -#define _istxdigit_l _isxdigit_l - -#define _tstat _stat -#define _tstat32 _stat32 -#define _tstat32i64 _stat32i64 -#define _tstat64 _stat64 -#define _tstat64i32 _stat64i32 -#define _tstati64 _stati64 - -#define _tsetlocale setlocale - -#ifdef _MBCS - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __TCHAR_DEFINED - typedef char _TCHAR; - typedef signed char _TSCHAR; - typedef unsigned char _TUCHAR; - typedef unsigned char _TXCHAR; - typedef unsigned int _TINT; -#define __TCHAR_DEFINED -#endif - -#ifndef _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef char TCHAR; -#endif -#define _TCHAR_DEFINED -#endif - -#ifdef _MB_MAP_DIRECT - -#define _tcschr _mbschr -#define _tcscspn _mbscspn -#define _tcsncat _mbsnbcat -#define _tcsncat_l _mbsnbcat_l -#define _tcsncpy _mbsnbcpy -#define _tcsncpy_l _mbsnbcpy_l -#define _tcspbrk _mbspbrk -#define _tcsrchr _mbsrchr -#define _tcsspn _mbsspn -#define _tcsstr _mbsstr -#define _tcstok _mbstok -#define _tcstok_l _mbstok_l - -#define _tcsnset _mbsnbset -#define _tcsnset_l _mbsnbset_l -#define _tcsrev _mbsrev -#define _tcsset _mbsset -#define _tcsset_l _mbsset_l - -#define _tcscmp _mbscmp -#define _tcsicmp _mbsicmp -#define _tcsicmp_l _mbsicmp_l -#define _tcsnccmp _mbsncmp -#define _tcsncmp _mbsnbcmp -#define _tcsncicmp _mbsnicmp -#define _tcsncicmp_l _mbsnicmp_l -#define _tcsnicmp _mbsnbicmp -#define _tcsnicmp_l _mbsnbicmp_l - -#define _tcscoll _mbscoll -#define _tcscoll_l _mbscoll_l -#define _tcsicoll _mbsicoll -#define _tcsicoll_l _mbsicoll_l -#define _tcsnccoll _mbsncoll -#define _tcsnccoll_l _mbsncoll_l -#define _tcsncoll _mbsnbcoll -#define _tcsncoll_l _mbsnbcoll_l -#define _tcsncicoll _mbsnicoll -#define _tcsncicoll_l _mbsnicoll_l -#define _tcsnicoll _mbsnbicoll -#define _tcsnicoll_l _mbsnbicoll_l - -#define _tcsclen _mbslen -#define _tcscnlen _mbsnlen -#define _tcsclen_l _mbslen_l -#define _tcscnlen_l _mbsnlen_l -#define _tcsnccat _mbsncat -#define _tcsnccat_l _mbsncat_l -#define _tcsnccpy _mbsncpy -#define _tcsnccpy_l _mbsncpy_l -#define _tcsncset _mbsnset -#define _tcsncset_l _mbsnset_l - -#define _tcsdec _mbsdec -#define _tcsinc _mbsinc -#define _tcsnbcnt _mbsnbcnt -#define _tcsnccnt _mbsnccnt -#define _tcsnextc _mbsnextc -#define _tcsninc _mbsninc -#define _tcsspnp _mbsspnp - -#define _tcslwr _mbslwr -#define _tcslwr_l _mbslwr_l -#define _tcsupr _mbsupr -#define _tcsupr_l _mbsupr_l - -#define _tclen _mbclen -#define _tccpy _mbccpy -#define _tccpy_l _mbccpy_l -#else - - _CRTIMP _CONST_RETURN char *__cdecl _tcschr(const char *_Str,unsigned int _Val); - _CRTIMP size_t __cdecl _tcscspn(const char *_Str,const char *_Control); - _CRTIMP char *__cdecl _tcsncat(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncpy(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP _CONST_RETURN char *__cdecl _tcspbrk(const char *_Str,const char *_Control); - _CRTIMP _CONST_RETURN char *__cdecl _tcsrchr(const char *_Str,unsigned int _Ch); - _CRTIMP size_t __cdecl _tcsspn(const char *_Str,const char *_Control); - _CRTIMP _CONST_RETURN char *__cdecl _tcsstr(const char *_Str,const char *_Substr); - _CRTIMP char *__cdecl _tcstok(char *_Str,const char *_Delim); - _CRTIMP char *__cdecl _tcstok_l(char *_Str,const char *_Delim,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnset(char *_Str,unsigned int _Val,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsrev(char *_Str); - _CRTIMP char *__cdecl _tcsset(char *_Str,unsigned int _Val); - _CRTIMP char *__cdecl _tcsset_l(char *_Str,unsigned int _Val,_locale_t _Locale); - _CRTIMP int __cdecl _tcscmp(const char *_Str1,const char *_Str); - _CRTIMP int __cdecl _tcsicmp(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcsicmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnccmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcscoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcscoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsicoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcsicoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnccoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnccoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsncoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsncicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP size_t __cdecl _tcsclen(const char *_Str); - _CRTIMP size_t __cdecl _tcscnlen(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _tcsclen_l(const char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _tcscnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccat(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccpy(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncset(char *_Str,unsigned int _Val,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsdec(const char *_Start,const char *_Pos); - _CRTIMP char *__cdecl _tcsinc(const char *_Ptr); - _CRTIMP size_t __cdecl _tcsnbcnt(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _tcsnccnt(const char *_Str,size_t _MaxCount); - _CRTIMP unsigned int __cdecl _tcsnextc (const char *_Str); - _CRTIMP char *__cdecl _tcsninc(const char *_Ptr,size_t _Count); - _CRTIMP char *__cdecl _tcsspnp(const char *_Str1,const char *_Str2); - _CRTIMP char *__cdecl _tcslwr(char *_Str); - _CRTIMP char *__cdecl _tcslwr_l(char *_Str,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsupr(char *_Str); - _CRTIMP char *__cdecl _tcsupr_l(char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _tclen(const char *_Str); - _CRTIMP void __cdecl _tccpy(char *_DstCh,const char *_SrcCh); - -#ifdef __cplusplus -#ifndef _CPP_TCHAR_INLINES_DEFINED -#define _CPP_TCHAR_INLINES_DEFINED - extern "C++" { - extern inline char *__cdecl _tcschr(char *_S,unsigned int _C) { return ((char *)_tcschr((const char *)_S,_C)); } - extern inline char *__cdecl _tcspbrk(char *_S,const char *_P) { return ((char *)_tcspbrk((const char *)_S,_P)); } - extern inline char *__cdecl _tcsrchr(char *_S,unsigned int _C) { return ((char *)_tcsrchr((const char *)_S,_C)); } - extern inline char *__cdecl _tcsstr(char *_S,const char *_P) { return ((char *)_tcsstr((const char *)_S,_P)); } - } -#endif -#endif -#endif - -#define _tccmp(_cp1,_cp2) _tcsnccmp(_cp1,_cp2,1) - -#define _istalnum _ismbcalnum -#define _istalnum_l _ismbcalnum_l -#define _istalpha _ismbcalpha -#define _istalpha_l _ismbcalpha_l -#define _istdigit _ismbcdigit -#define _istdigit_l _ismbcdigit_l -#define _istgraph _ismbcgraph -#define _istgraph_l _ismbcgraph_l -#define _istlegal _ismbclegal -#define _istlegal_l _ismbclegal_l -#define _istlower _ismbclower -#define _istlower_l _ismbclower_l -#define _istprint _ismbcprint -#define _istprint_l _ismbcprint_l -#define _istpunct _ismbcpunct -#define _istpunct_l _ismbcpunct_l -#define _istspace _ismbcspace -#define _istspace_l _ismbcspace_l -#define _istupper _ismbcupper -#define _istupper_l _ismbcupper_l - -#define _totupper _mbctoupper -#define _totupper_l _mbctoupper_l -#define _totlower _mbctolower -#define _totlower_l _mbctolower_l - -#define _istlead _ismbblead -#define _istleadbyte isleadbyte -#define _istleadbyte_l _isleadbyte_l -#else - -#ifndef __TCHAR_DEFINED -#define __TCHAR_DEFINED - typedef char _TCHAR; - typedef signed char _TSCHAR; - typedef unsigned char _TUCHAR; - typedef char _TXCHAR; - typedef int _TINT; -#endif - -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef char TCHAR; -#endif -#endif - -#define _tcschr strchr -#define _tcscspn strcspn -#define _tcsncat strncat -#define _tcsncat_l _strncat_l -#define _tcsncpy strncpy -#define _tcsncpy_l _strncpy_l -#define _tcspbrk strpbrk -#define _tcsrchr strrchr -#define _tcsspn strspn -#define _tcsstr strstr -#define _tcstok strtok -#define _tcstok_l _strtok_l - -#define _tcsnset _strnset -#define _tcsnset_l _strnset_l -#define _tcsrev _strrev -#define _tcsset _strset - -#define _tcscmp strcmp -#define _tcsicmp _stricmp -#define _tcsicmp_l _stricmp_l -#define _tcsnccmp strncmp -#define _tcsncmp strncmp -#define _tcsncicmp _strnicmp -#define _tcsncicmp_l _strnicmp_l -#define _tcsnicmp _strnicmp -#define _tcsnicmp_l _strnicmp_l - -#define _tcscoll strcoll -#define _tcscoll_l _strcoll_l -#define _tcsicoll _stricoll -#define _tcsicoll_l _stricoll_l -#define _tcsnccoll _strncoll -#define _tcsnccoll_l _strncoll_l -#define _tcsncoll _strncoll -#define _tcsncoll_l _strncoll_l -#define _tcsncicoll _strnicoll -#define _tcsncicoll_l _strnicoll_l -#define _tcsnicoll _strnicoll -#define _tcsnicoll_l _strnicoll_l - -#define _tcsclen strlen -#define _tcscnlen strnlen -#define _tcsclen_l(_String,_Locale) strlen(_String) -#define _tcscnlen_l(_String,_Max_count,_Locale) strnlen_l((_String),(_Max_count)) -#define _tcsnccat strncat -#define _tcsnccat_l _strncat_l -#define _tcsnccpy strncpy -#define _tcsnccpy_l _strncpy_l -#define _tcsncset _strnset - -#define _tcsdec _strdec -#define _tcsinc _strinc -#define _tcsnbcnt _strncnt -#define _tcsnccnt _strncnt -#define _tcsnextc _strnextc -#define _tcsninc _strninc -#define _tcsspnp _strspnp - -#define _tcslwr _strlwr -#define _tcslwr_l _strlwr_l -#define _tcsupr _strupr -#define _tcsupr_l _strupr_l -#define _tcsxfrm strxfrm -#define _tcsxfrm_l _strxfrm_l - -#define _istlead(_Char) (0) -#define _istleadbyte(_Char) (0) -#define _istleadbyte_l(_Char,_Locale) (0) - -#define _tclen(_pc) (1) -#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2)) -#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2))) - - /* dirent structures and functions */ -#define _tdirent dirent -#define _TDIR DIR -#define _topendir opendir -#define _tclosedir closedir -#define _treaddir readdir -#define _trewinddir rewinddir -#define _ttelldir telldir -#define _tseekdir seekdir - -#define _istalnum isalnum -#define _istalnum_l _isalnum_l -#define _istalpha isalpha -#define _istalpha_l _isalpha_l -#define _istdigit isdigit -#define _istdigit_l _isdigit_l -#define _istgraph isgraph -#define _istgraph_l _isgraph_l -#define _istlower islower -#define _istlower_l _islower_l -#define _istprint isprint -#define _istprint_l _isprint_l -#define _istpunct ispunct -#define _istpunct_l _ispunct_l -#define _istspace isspace -#define _istspace_l _isspace_l -#define _istupper isupper -#define _istupper_l _isupper_l - -#define _totupper toupper -#define _totupper_l _toupper_l -#define _totlower tolower -#define _totlower_l _tolower_l - -#define _istlegal(_c) (1) - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define _strdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) -#define _strinc(_pc) ((_pc)+1) -#define _strnextc(_cpc) ((unsigned int) *(const unsigned char *)(_cpc)) -#define _strninc(_pc,_sz) (((_pc)+(_sz))) - _CRTIMP size_t __cdecl __strncnt(const char *_Str,size_t _Cnt); -#define _strncnt(_cpc,_sz) (__strncnt(_cpc,_sz)) -#define _strspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)) - -#define _strncpy_l(_Destination,_Source,_Count,_Locale) (strncpy(_Destination,_Source,_Count)) -#define _strncat_l(_Destination,_Source,_Count,_Locale) (strncat(_Destination,_Source,_Count)) -#define _strtok_l(_String,_Delimiters,_Locale) (strtok(_String,_Delimiters)) -#define _strnset_l(_Destination,_Value,_Count,_Locale) (_strnset(_Destination,_Value,_Count)) -#define _strset_l(_Destination,_Value,_Locale) (_strset(_Destination,_Value)) -#endif -#endif - -#define _T(x) __T(x) -#define _TEXT(x) __T(x) - -#ifdef __cplusplus -} -#endif - -#include -#endif diff --git a/tinyc/win32/include/time.h b/tinyc/win32/include/time.h deleted file mode 100644 index 6c72e2660..000000000 --- a/tinyc/win32/include/time.h +++ /dev/null @@ -1,287 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIME_H_ -#define _TIME_H_ - -#include <_mingw.h> - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED -#define _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED - typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int _time64_t __attribute__ ((mode (DI))); -#else - typedef __int64 __time64_t; -#endif -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#endif - -#ifndef _CLOCK_T_DEFINED -#define _CLOCK_T_DEFINED - typedef long clock_t; -#endif - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#undef size_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned int size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef int ssize_t; -#endif -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifdef _USE_32BIT_TIME_T -#define _localtime32 localtime -#define _difftime32 difftime -#define _ctime32 ctime -#define _gmtime32 gmtime -#define _mktime32 mktime -#define _time32 time -#endif - -#ifndef _TM_DEFINED -#define _TM_DEFINED - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; -#endif - -#define CLOCKS_PER_SEC 1000 - - __MINGW_IMPORT int _daylight; - __MINGW_IMPORT long _dstbias; - __MINGW_IMPORT long _timezone; - __MINGW_IMPORT char * _tzname[2]; - _CRTIMP errno_t __cdecl _get_daylight(int *_Daylight); - _CRTIMP errno_t __cdecl _get_dstbias(long *_Daylight_savings_bias); - _CRTIMP errno_t __cdecl _get_timezone(long *_Timezone); - _CRTIMP errno_t __cdecl _get_tzname(size_t *_ReturnValue,char *_Buffer,size_t _SizeInBytes,int _Index); - char *__cdecl asctime(const struct tm *_Tm); - _CRTIMP char *__cdecl _ctime32(const __time32_t *_Time); - clock_t __cdecl clock(void); - _CRTIMP double __cdecl _difftime32(__time32_t _Time1,__time32_t _Time2); - _CRTIMP struct tm *__cdecl _gmtime32(const __time32_t *_Time); - _CRTIMP struct tm *__cdecl _localtime32(const __time32_t *_Time); - size_t __cdecl strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _strftime_l(char *_Buf,size_t _Max_size,const char *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP char *__cdecl _strdate(char *_Buffer); - _CRTIMP char *__cdecl _strtime(char *_Buffer); - _CRTIMP __time32_t __cdecl _time32(__time32_t *_Time); - _CRTIMP __time32_t __cdecl _mktime32(struct tm *_Tm); - _CRTIMP __time32_t __cdecl _mkgmtime32(struct tm *_Tm); -#if defined (_POSIX_) || defined(__GNUC__) - void __cdecl tzset(void); -#else - _CRTIMP void __cdecl _tzset(void); -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - double __cdecl _difftime64(__time64_t _Time1,__time64_t _Time2); - _CRTIMP char *__cdecl _ctime64(const __time64_t *_Time); - _CRTIMP struct tm *__cdecl _gmtime64(const __time64_t *_Time); - _CRTIMP struct tm *__cdecl _localtime64(const __time64_t *_Time); - _CRTIMP __time64_t __cdecl _mktime64(struct tm *_Tm); - _CRTIMP __time64_t __cdecl _mkgmtime64(struct tm *_Tm); - _CRTIMP __time64_t __cdecl _time64(__time64_t *_Time); -#endif - unsigned __cdecl _getsystime(struct tm *_Tm); - unsigned __cdecl _setsystime(struct tm *_Tm,unsigned _MilliSec); - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned long size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef long ssize_t; -#endif -#endif - -#ifndef _WTIME_DEFINED - _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); - _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); - size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); - _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) -#define _INC_WTIME_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } -#else -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } -#endif -#endif - -#define _WTIME_DEFINED -#endif - -#ifndef RC_INVOKED -double __cdecl difftime(time_t _Time1,time_t _Time2); -char *__cdecl ctime(const time_t *_Time); -struct tm *__cdecl gmtime(const time_t *_Time); -struct tm *__cdecl localtime(const time_t *_Time); -struct tm *__cdecl localtime_r(const time_t *_Time,struct tm *); - -time_t __cdecl mktime(struct tm *_Tm); -time_t __cdecl _mkgmtime(struct tm *_Tm); -time_t __cdecl time(time_t *_Time); - -#ifdef _USE_32BIT_TIME_T -#if 0 -__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime32(_Time1,_Time2); } -__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime32(_Time); } -__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime32(_Time); } -__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime32(_Time); } -__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime32(_Tm); } -__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime32(_Tm); } -__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time32(_Time); } -#endif -#else -__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime64(_Time1,_Time2); } -__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime64(_Time); } -__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime64(_Time); } -__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime64(_Time); } -__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime64(_Tm); } -__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime64(_Tm); } -__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time64(_Time); } -#endif -#endif - -#if !defined(NO_OLDNAMES) || defined(_POSIX) -#define CLK_TCK CLOCKS_PER_SEC - - __MINGW_IMPORT int daylight; - __MINGW_IMPORT long dstbias; - __MINGW_IMPORT long timezone; - __MINGW_IMPORT char *tzname[2]; - void __cdecl tzset(void); -#endif - -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED -struct timeval { - long tv_sec; - long tv_usec; -}; -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#ifndef __STRICT_ANSI__ -#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ -#define _TIMEZONE_DEFINED -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - - extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); -#endif -#endif /* __STRICT_ANSI__ */ - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include - -/* Adding timespec definition. */ -#include - -#endif /* End _TIME_H_ */ - diff --git a/tinyc/win32/include/vadefs.h b/tinyc/win32/include/vadefs.h deleted file mode 100644 index 749b0bdde..000000000 --- a/tinyc/win32/include/vadefs.h +++ /dev/null @@ -1,11 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_VADEFS -#define _INC_VADEFS - -//!__TINYC__: GNUC specific stuff removed - -#endif diff --git a/tinyc/win32/include/values.h b/tinyc/win32/include/values.h deleted file mode 100644 index 1cd643cef..000000000 --- a/tinyc/win32/include/values.h +++ /dev/null @@ -1,4 +0,0 @@ -/* - * TODO: Nothing here yet. Should provide UNIX compatibility constants - * comparable to those in limits.h and float.h. - */ diff --git a/tinyc/win32/include/wchar.h b/tinyc/win32/include/wchar.h deleted file mode 100644 index 389196faf..000000000 --- a/tinyc/win32/include/wchar.h +++ /dev/null @@ -1,873 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCHAR -#define _INC_WCHAR - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WCHAR_MIN /* also at stdint.h */ -#define WCHAR_MIN 0 -#define WCHAR_MAX ((wchar_t) -1) /* UINT16_MAX */ -#endif - -#ifndef __GNUC_VA_LIST -#define __GNUC_VA_LIST - typedef __builtin_va_list __gnuc_va_list; -#endif - -#ifndef _VA_LIST_DEFINED -#define _VA_LIST_DEFINED - typedef __gnuc_va_list va_list; -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _FILE_DEFINED - struct _iobuf { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; - }; - typedef struct _iobuf FILE; -#define _FILE_DEFINED -#endif - -#ifndef _STDIO_DEFINED -#ifdef _WIN64 - _CRTIMP FILE *__cdecl __iob_func(void); -#else -#ifdef _MSVCRT_ -extern FILE _iob[]; /* A pointer to an array of FILE */ -#define __iob_func() (_iob) -#else -extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ -#define __iob_func() (*_imp___iob) -#define _iob __iob_func() -#endif -#endif - -#define _iob __iob_func() -#endif - -#ifndef _STDSTREAM_DEFINED -#define stdin (&__iob_func()[0]) -#define stdout (&__iob_func()[1]) -#define stderr (&__iob_func()[2]) -#define _STDSTREAM_DEFINED -#endif - -#ifndef _FSIZE_T_DEFINED - typedef unsigned long _fsize_t; -#define _FSIZE_T_DEFINED -#endif - -#ifndef _WFINDDATA_T_DEFINED - struct _wfinddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - -/* #if _INTEGRAL_MAX_BITS >= 64 */ - - struct _wfinddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - wchar_t name[260]; - }; - - struct _wfinddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - - struct _wfinddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - wchar_t name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _wfinddata_t _wfinddata32_t -#define _wfinddatai64_t _wfinddata32i64_t - -#define _wfindfirst _wfindfirst32 -#define _wfindnext _wfindnext32 -#define _wfindfirsti64 _wfindfirst32i64 -#define _wfindnexti64 _wfindnext32i64 -#else -#define _wfinddata_t _wfinddata64i32_t -#define _wfinddatai64_t _wfinddata64_t - -#define _wfindfirst _wfindfirst64i32 -#define _wfindnext _wfindnext64i32 -#define _wfindfirsti64 _wfindfirst64 -#define _wfindnexti64 _wfindnext64 -#endif - -#define _WFINDDATA_T_DEFINED -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef _CONST_RETURN -#define _CONST_RETURN -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif - -#ifdef _MSVCRT_ -#define __pwctype_func() (_pwctype) -#else -#define __pwctype_func() (*_imp___pwctype) -#endif - -#ifndef _pwctype -#ifdef _MSVCRT_ - extern unsigned short *_pwctype; -#else - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#endif -#endif - -#endif -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t _C); - _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); - int __cdecl iswupper(wint_t _C); - _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); - int __cdecl iswlower(wint_t _C); - _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswdigit(wint_t _C); - _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswxdigit(wint_t _C); - _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswspace(wint_t _C); - _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); - int __cdecl iswpunct(wint_t _C); - _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); - int __cdecl iswalnum(wint_t _C); - _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); - int __cdecl iswprint(wint_t _C); - _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); - int __cdecl iswgraph(wint_t _C); - _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); - int __cdecl iswcntrl(wint_t _C); - _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); - int __cdecl iswascii(wint_t _C); - int __cdecl isleadbyte(int _C); - _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); - wint_t __cdecl towupper(wint_t _C); - _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); - wint_t __cdecl towlower(wint_t _C); - _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswctype(wint_t _C,wctype_t _Type); - _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsymf(wint_t _C); - _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsym(wint_t _C); - _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); - int __cdecl is_wctype(wint_t _C,wctype_t _Type); -#endif - -#ifndef _WDIRECT_DEFINED -#define _WDIRECT_DEFINED - - _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); -#endif - -#ifndef _WIO_DEFINED -#define _WIO_DEFINED - - _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); - _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); - _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); - _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); - _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); - _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); - intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); - _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); - _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); - int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); - _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); -#endif - _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); -#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); -#endif -#endif - -#ifndef _WLOCALE_DEFINED -#define _WLOCALE_DEFINED - _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -#endif - -#ifndef _WPROCESS_DEFINED -#define _WPROCESS_DEFINED - - _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif -#endif - -#ifndef _WCTYPE_INLINE_DEFINED -#undef _CRT_WCTYPE_NOINLINE -#if !defined(__cplusplus) || defined(_CRT_WCTYPE_NOINLINE) -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) - -#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) -#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) -#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) -#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) -#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) -#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) -#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) -#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) -#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) -#ifndef _CTYPE_DISABLE_MACROS -#define isleadbyte(_c) (__PCTYPE_FUNC[(unsigned char)(_c)] & _LEADBYTE) -#endif -#endif -#define _WCTYPE_INLINE_DEFINED -#endif - -#if !defined(_POSIX_) || defined(__GNUC__) -#ifndef _INO_T_DEFINED -#define _INO_T_DEFINED - typedef unsigned short _ino_t; -#ifndef NO_OLDNAMES - typedef unsigned short ino_t; -#endif -#endif - -#ifndef _DEV_T_DEFINED -#define _DEV_T_DEFINED - typedef unsigned int _dev_t; -#ifndef NO_OLDNAMES - typedef unsigned int dev_t; -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _STAT_DEFINED -#define _STAT_DEFINED - -#ifdef _USE_32BIT_TIME_T -#ifdef WIN64 -#define _fstat _fstat32 -#define _stat _stat32 -#define _wstat _wstat32 -#else -#define _fstat32 _fstat -#define _stat32 _stat -#define _wstat32 _wstat -#endif -#define _fstati64 _fstat32i64 -#define _stati64 _stat32i64 -#define _wstati64 _wstat32i64 -#else -#define _fstat _fstat64i32 -#define _fstati64 _fstat64 -#define _stat _stat64i32 -#define _stati64 _stat64 -#define _wstat _wstat64i32 -#define _wstati64 _wstat64 -#endif - - struct _stat32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - -#ifndef NO_OLDNAMES - struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - - struct _stat32i64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - - struct _stat64i32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; - - struct _stat64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; -#endif - -#define __stat64 _stat64 - -#endif - -#ifndef _WSTAT_DEFINED -#define _WSTAT_DEFINED - - _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); - int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); - _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); -#endif -#endif -#endif - -#ifndef _WCONIO_DEFINED -#define _WCONIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - - _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _getwch(void); - _CRTIMP wint_t __cdecl _getwche(void); - _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); - _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); - _CRTIMP int __cdecl _cputws(const wchar_t *_String); - _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); - - _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - wint_t __cdecl _putwch_nolock(wchar_t _WCh); - wint_t __cdecl _getwch_nolock(void); - wint_t __cdecl _getwche_nolock(void); - wint_t __cdecl _ungetwch_nolock(wint_t _WCh); -#endif - -#ifndef _WSTDIO_DEFINED -#define _WSTDIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); -#else - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); -#endif - - wint_t __cdecl fgetwc(FILE *_File); - _CRTIMP wint_t __cdecl _fgetwchar(void); - wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); - wint_t __cdecl getwc(FILE *_File); - wint_t __cdecl getwchar(void); - wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); - wint_t __cdecl putwchar(wchar_t _Ch); - wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); - wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); - int __cdecl fputws(const wchar_t *_Str,FILE *_File); - _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); - _CRTIMP int __cdecl _putws(const wchar_t *_Str); - int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); - int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); - _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); - _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snwprintf (wchar_t *s, size_t n, const wchar_t * format, ...); - __CRT_INLINE int __cdecl vsnwprintf (wchar_t *s, size_t n, const wchar_t *format, va_list arg) { return _vsnwprintf(s,n,format,arg); } - int __cdecl vwscanf (const wchar_t *, va_list); - int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); - int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); -#endif - _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); - _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); - _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); -#ifndef RC_INVOKED -#include -#endif - -#ifdef _CRT_NON_CONFORMING_SWPRINTFS -#ifndef __cplusplus -#define swprintf _swprintf -#define vswprintf _vswprintf -#define _swprintf_l __swprintf_l -#define _vswprintf_l __vswprintf_l -#endif -#endif - - _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); - _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); - _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - int __cdecl wscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); -#if !defined(NO_OLDNAMES) && !defined(wpopen) -#define wpopen _wpopen -#endif - _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); - _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); - _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); - -#undef _CRT_GETPUTWCHAR_NOINLINE - -#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) -#define getwchar() fgetwc(stdin) -#define putwchar(_c) fputwc((_c),stdout) -#else - __CRT_INLINE wint_t __cdecl getwchar() {return (fgetwc(stdin)); } - __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) {return (fputwc(_C,stdout)); } -#endif - -#define getwc(_stm) fgetwc(_stm) -#define putwc(_c,_stm) fputwc(_c,_stm) -#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) -#define _getwc_nolock(_c) _fgetwc_nolock(_c) -#endif - -#ifndef _WSTDLIB_DEFINED -#define _WSTDLIB_DEFINED - - _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); - double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); - _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); - float __cdecl wcstof( const wchar_t *nptr, wchar_t **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl wcstof (const wchar_t * __restrict__, wchar_t ** __restrict__); - long double __cdecl wcstold (const wchar_t * __restrict__, wchar_t ** __restrict__); -#endif /* __NO_ISOCEXT */ - long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif - _CRTIMP double __cdecl _wtof(const wchar_t *_Str); - _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); - _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP long __cdecl _wtol(const wchar_t *_Str); - _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); - _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); -#endif -#endif - -#ifndef _POSIX_ -#ifndef _WSTDLIBP_DEFINED -#define _WSTDLIBP_DEFINED - _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); - _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); - _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); - _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); -#endif -#endif - -#ifndef _WSTRING_DEFINED -#define _WSTRING_DEFINED - _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); - wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); - _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); - int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); - wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); - size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); - size_t __cdecl wcslen(const wchar_t *_Str); - size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); - wchar_t *__cdecl wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); - size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); - wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); - _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); - _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); - _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); - _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); - _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); - _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); - _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); - size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); - int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - wchar_t *__cdecl wcsdup(const wchar_t *_Str); -#define wcswcs wcsstr - int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - wchar_t *__cdecl wcsrev(wchar_t *_Str); - wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); - wchar_t *__cdecl wcslwr(wchar_t *_Str); - wchar_t *__cdecl wcsupr(wchar_t *_Str); - int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); -#endif -#endif - -#ifndef _TM_DEFINED -#define _TM_DEFINED - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; -#endif - -#ifndef _WTIME_DEFINED -#define _WTIME_DEFINED - - _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); - _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); - size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); - _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) -#define _INC_WTIME_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } -#else -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } -#endif -#endif -#endif - - typedef int mbstate_t; - typedef wchar_t _Wint_t; - - wint_t __cdecl btowc(int); - size_t __cdecl mbrlen(const char *_Ch,size_t _SizeInBytes,mbstate_t *_State); - size_t __cdecl mbrtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SizeInBytes,mbstate_t *_State); - size_t __cdecl mbsrtowcs(wchar_t *_Dest,const char **_PSrc,size_t _Count,mbstate_t *_State); - size_t __cdecl wcrtomb(char *_Dest,wchar_t _Source,mbstate_t *_State); - size_t __cdecl wcsrtombs(char *_Dest,const wchar_t **_PSource,size_t _Count,mbstate_t *_State); - int __cdecl wctob(wint_t _WCh); - -#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */ - wchar_t *__cdecl wmemset(wchar_t *s, wchar_t c, size_t n); - _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *s, wchar_t c, size_t n); - int wmemcmp(const wchar_t *s1, const wchar_t *s2,size_t n); - wchar_t *__cdecl wmemcpy(wchar_t *s1,const wchar_t *s2,size_t n); - wchar_t *__cdecl wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); - long long __cdecl wcstoll(const wchar_t *nptr,wchar_t **endptr, int base); - unsigned long long __cdecl wcstoull(const wchar_t *nptr,wchar_t **endptr, int base); -#endif /* __NO_ISOCEXT */ - - void *__cdecl memmove(void *_Dst,const void *_Src,size_t _MaxCount); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _MaxCount); - __CRT_INLINE int __cdecl fwide(FILE *_F,int _M) { (void)_F; return (_M); } - __CRT_INLINE int __cdecl mbsinit(const mbstate_t *_P) { return (!_P || *_P==0); } - __CRT_INLINE _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *_S,wchar_t _C,size_t _N) { for (;0<_N;++_S,--_N) if (*_S==_C) return (_CONST_RETURN wchar_t *)(_S); return (0); } - __CRT_INLINE int __cdecl wmemcmp(const wchar_t *_S1,const wchar_t *_S2,size_t _N) { for (; 0 < _N; ++_S1,++_S2,--_N) if (*_S1!=*_S2) return (*_S1 < *_S2 ? -1 : +1); return (0); } - __CRT_INLINE wchar_t *__cdecl wmemcpy(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memcpy(_S1,_S2,_N*sizeof(wchar_t)); } - __CRT_INLINE wchar_t *__cdecl wmemmove(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memmove(_S1,_S2,_N*sizeof(wchar_t)); } - __CRT_INLINE wchar_t *__cdecl wmemset(wchar_t *_S,wchar_t _C,size_t _N) { - wchar_t *_Su = _S; - for (;0<_N;++_Su,--_N) { - *_Su = _C; - } - return (_S); - } -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#endif diff --git a/tinyc/win32/include/wctype.h b/tinyc/win32/include/wctype.h deleted file mode 100644 index a44cb384a..000000000 --- a/tinyc/win32/include/wctype.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCTYPE -#define _INC_WCTYPE - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef _WCTYPE_T_DEFINED - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#define _WCTYPE_T_DEFINED -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif - -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif - -#ifndef _pwctype -#ifdef _MSVCRT_ - extern unsigned short *_pwctype; -#else - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#define __pwctype_func() (*_imp___pwctype) -#endif -#endif -#endif -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t); - int __cdecl iswupper(wint_t); - int __cdecl iswlower(wint_t); - int __cdecl iswdigit(wint_t); - int __cdecl iswxdigit(wint_t); - int __cdecl iswspace(wint_t); - int __cdecl iswpunct(wint_t); - int __cdecl iswalnum(wint_t); - int __cdecl iswprint(wint_t); - int __cdecl iswgraph(wint_t); - int __cdecl iswcntrl(wint_t); - int __cdecl iswascii(wint_t); - int __cdecl isleadbyte(int); - wint_t __cdecl towupper(wint_t); - wint_t __cdecl towlower(wint_t); - int __cdecl iswctype(wint_t,wctype_t); - _CRTIMP int __cdecl __iswcsymf(wint_t); - _CRTIMP int __cdecl __iswcsym(wint_t); - int __cdecl is_wctype(wint_t,wctype_t); -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl isblank(int _C); -#endif -#endif - -#ifndef _WCTYPE_INLINE_DEFINED -#define _WCTYPE_INLINE_DEFINED -#ifndef __cplusplus -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) -#define isleadbyte(c) (__pctype_func()[(unsigned char)(c)] & _LEADBYTE) -#else - __CRT_INLINE int __cdecl iswalpha(wint_t _C) {return (iswctype(_C,_ALPHA)); } - __CRT_INLINE int __cdecl iswupper(wint_t _C) {return (iswctype(_C,_UPPER)); } - __CRT_INLINE int __cdecl iswlower(wint_t _C) {return (iswctype(_C,_LOWER)); } - __CRT_INLINE int __cdecl iswdigit(wint_t _C) {return (iswctype(_C,_DIGIT)); } - __CRT_INLINE int __cdecl iswxdigit(wint_t _C) {return (iswctype(_C,_HEX)); } - __CRT_INLINE int __cdecl iswspace(wint_t _C) {return (iswctype(_C,_SPACE)); } - __CRT_INLINE int __cdecl iswpunct(wint_t _C) {return (iswctype(_C,_PUNCT)); } - __CRT_INLINE int __cdecl iswalnum(wint_t _C) {return (iswctype(_C,_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswprint(wint_t _C) {return (iswctype(_C,_BLANK|_PUNCT|_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswgraph(wint_t _C) {return (iswctype(_C,_PUNCT|_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswcntrl(wint_t _C) {return (iswctype(_C,_CONTROL)); } - __CRT_INLINE int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); } - __CRT_INLINE int __cdecl isleadbyte(int _C) {return (__pctype_func()[(unsigned char)(_C)] & _LEADBYTE); } -#endif -#endif - - typedef wchar_t wctrans_t; - wint_t __cdecl towctrans(wint_t,wctrans_t); - wctrans_t __cdecl wctrans(const char *); - wctype_t __cdecl wctype(const char *); - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/winapi/basetsd.h b/tinyc/win32/include/winapi/basetsd.h deleted file mode 100644 index 47d78c4c3..000000000 --- a/tinyc/win32/include/winapi/basetsd.h +++ /dev/null @@ -1,149 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _BASETSD_H_ -#define _BASETSD_H_ - -#if (defined(__x86_64) || defined(__ia64__)) && !defined(RC_INVOKED) -typedef unsigned __int64 POINTER_64_INT; -#else -typedef unsigned long POINTER_64_INT; -#endif - -#define POINTER_32 -#define POINTER_64 -#define FIRMWARE_PTR - -#ifdef __cplusplus -extern "C" { -#endif - - typedef signed char INT8,*PINT8; - typedef signed short INT16,*PINT16; - typedef signed int INT32,*PINT32; - typedef signed __int64 INT64,*PINT64; - typedef unsigned char UINT8,*PUINT8; - typedef unsigned short UINT16,*PUINT16; - typedef unsigned int UINT32,*PUINT32; - typedef unsigned __int64 UINT64,*PUINT64; - typedef signed int LONG32,*PLONG32; - typedef unsigned int ULONG32,*PULONG32; - typedef unsigned int DWORD32,*PDWORD32; - -#ifndef _W64 -#define _W64 -#endif - -#ifdef _WIN64 - typedef __int64 INT_PTR,*PINT_PTR; - typedef unsigned __int64 UINT_PTR,*PUINT_PTR; - typedef __int64 LONG_PTR,*PLONG_PTR; - typedef unsigned __int64 ULONG_PTR,*PULONG_PTR; -#define __int3264 __int64 -#else - typedef int INT_PTR,*PINT_PTR; - typedef unsigned int UINT_PTR,*PUINT_PTR; - typedef long LONG_PTR,*PLONG_PTR; - typedef unsigned long ULONG_PTR,*PULONG_PTR; -#define __int3264 __int32 -#endif - -#ifdef _WIN64 -#define ADDRESS_TAG_BIT 0x40000000000ULL - typedef __int64 SHANDLE_PTR; - typedef unsigned __int64 HANDLE_PTR; - typedef unsigned int UHALF_PTR,*PUHALF_PTR; - typedef int HALF_PTR,*PHALF_PTR; - - static __inline unsigned long HandleToULong(const void *h) { return((unsigned long) (ULONG_PTR) h); } - static __inline long HandleToLong(const void *h) { return((long) (LONG_PTR) h); } - static __inline void *ULongToHandle(const unsigned long h) { return((void *) (UINT_PTR) h); } - static __inline void *LongToHandle(const long h) { return((void *) (INT_PTR) h); } - static __inline unsigned long PtrToUlong(const void *p) { return((unsigned long) (ULONG_PTR) p); } - static __inline unsigned int PtrToUint(const void *p) { return((unsigned int) (UINT_PTR) p); } - static __inline unsigned short PtrToUshort(const void *p) { return((unsigned short) (unsigned long) (ULONG_PTR) p); } - static __inline long PtrToLong(const void *p) { return((long) (LONG_PTR) p); } - static __inline int PtrToInt(const void *p) { return((int) (INT_PTR) p); } - static __inline short PtrToShort(const void *p) { return((short) (long) (LONG_PTR) p); } - static __inline void *IntToPtr(const int i) { return((void *)(INT_PTR)i); } - static __inline void *UIntToPtr(const unsigned int ui) { return((void *)(UINT_PTR)ui); } - static __inline void *LongToPtr(const long l) { return((void *)(LONG_PTR)l); } - static __inline void *ULongToPtr(const unsigned long ul) { return((void *)(ULONG_PTR)ul); } - -#define PtrToPtr64(p) ((void *) p) -#define Ptr64ToPtr(p) ((void *) p) -#define HandleToHandle64(h) (PtrToPtr64(h)) -#define Handle64ToHandle(h) (Ptr64ToPtr(h)) - - static __inline void *Ptr32ToPtr(const void *p) { return (void *)p; } - static __inline void *Handle32ToHandle(const void *h) { return((void *) h); } - static __inline void *PtrToPtr32(const void *p) { return((void *) (ULONG_PTR) p); } - -#define HandleToHandle32(h) (PtrToPtr32(h)) -#else - -#define ADDRESS_TAG_BIT 0x80000000UL - - typedef unsigned short UHALF_PTR,*PUHALF_PTR; - typedef short HALF_PTR,*PHALF_PTR; - typedef long SHANDLE_PTR; - typedef unsigned long HANDLE_PTR; - -#define HandleToULong(h) ((ULONG)(ULONG_PTR)(h)) -#define HandleToLong(h) ((LONG)(LONG_PTR) (h)) -#define ULongToHandle(ul) ((HANDLE)(ULONG_PTR) (ul)) -#define LongToHandle(h) ((HANDLE)(LONG_PTR) (h)) -#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p)) -#define PtrToLong(p) ((LONG)(LONG_PTR) (p)) -#define PtrToUint(p) ((UINT)(UINT_PTR) (p)) -#define PtrToInt(p) ((INT)(INT_PTR) (p)) -#define PtrToUshort(p) ((unsigned short)(ULONG_PTR)(p)) -#define PtrToShort(p) ((short)(LONG_PTR)(p)) -#define IntToPtr(i) ((VOID *)(INT_PTR)((int)i)) -#define UIntToPtr(ui) ((VOID *)(UINT_PTR)((unsigned int)ui)) -#define LongToPtr(l) ((VOID *)(LONG_PTR)((long)l)) -#define ULongToPtr(ul) ((VOID *)(ULONG_PTR)((unsigned long)ul)) - - static __inline void *PtrToPtr64(const void *p) { return((void *) (ULONG_PTR)p); } - static __inline void *Ptr64ToPtr(const void *p) { return((void *) (ULONG_PTR) p); } - static __inline void *HandleToHandle64(const void *h) { return((void *) h); } - static __inline void *Handle64ToHandle(const void *h) { return((void *) (ULONG_PTR) h); } - -#define Ptr32ToPtr(p) ((void *) p) -#define Handle32ToHandle(h) (Ptr32ToPtr(h)) -#define PtrToPtr32(p) ((void *) p) -#define HandleToHandle32(h) (PtrToPtr32(h)) -#endif - -#define HandleToUlong(h) HandleToULong(h) -#define UlongToHandle(ul) ULongToHandle(ul) -#define UlongToPtr(ul) ULongToPtr(ul) -#define UintToPtr(ui) UIntToPtr(ui) - -#define MAXUINT_PTR (~((UINT_PTR)0)) -#define MAXINT_PTR ((INT_PTR)(MAXUINT_PTR >> 1)) -#define MININT_PTR (~MAXINT_PTR) - -#define MAXULONG_PTR (~((ULONG_PTR)0)) -#define MAXLONG_PTR ((LONG_PTR)(MAXULONG_PTR >> 1)) -#define MINLONG_PTR (~MAXLONG_PTR) - -#define MAXUHALF_PTR ((UHALF_PTR)~0) -#define MAXHALF_PTR ((HALF_PTR)(MAXUHALF_PTR >> 1)) -#define MINHALF_PTR (~MAXHALF_PTR) - - typedef ULONG_PTR SIZE_T,*PSIZE_T; - typedef LONG_PTR SSIZE_T,*PSSIZE_T; - typedef ULONG_PTR DWORD_PTR,*PDWORD_PTR; - typedef __int64 LONG64,*PLONG64; - typedef unsigned __int64 ULONG64,*PULONG64; - typedef unsigned __int64 DWORD64,*PDWORD64; - typedef ULONG_PTR KAFFINITY; - typedef KAFFINITY *PKAFFINITY; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/basetyps.h b/tinyc/win32/include/winapi/basetyps.h deleted file mode 100644 index 376665e79..000000000 --- a/tinyc/win32/include/winapi/basetyps.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !defined(_BASETYPS_H_) -#define _BASETYPS_H_ - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif - -#define STDMETHODCALLTYPE WINAPI -#define STDMETHODVCALLTYPE __cdecl - -#define STDAPICALLTYPE WINAPI -#define STDAPIVCALLTYPE __cdecl - -#define STDAPI EXTERN_C HRESULT WINAPI -#define STDAPI_(type) EXTERN_C type WINAPI - -#define STDMETHODIMP HRESULT WINAPI -#define STDMETHODIMP_(type) type WINAPI - -#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE -#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE - -#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE -#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE - -#if defined(__cplusplus) && !defined(CINTERFACE) - -#define __STRUCT__ struct -#define STDMETHOD(method) virtual HRESULT WINAPI method -#define STDMETHOD_(type,method) virtual type WINAPI method -#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method -#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method -#define PURE = 0 -#define THIS_ -#define THIS void -#define DECLARE_INTERFACE(iface) __STRUCT__ iface -#define DECLARE_INTERFACE_(iface,baseiface) __STRUCT__ iface : public baseiface -#else - -#ifndef __OBJC__ -#define interface struct -#endif - -#define STDMETHOD(method) HRESULT (WINAPI *method) -#define STDMETHOD_(type,method) type (WINAPI *method) -#define STDMETHODV(method) HRESULT (STDMETHODVCALLTYPE *method) -#define STDMETHODV_(type,method) type (STDMETHODVCALLTYPE *method) - -#define PURE -#define THIS_ INTERFACE *This, -#define THIS INTERFACE *This -#ifdef CONST_VTABLE -#define DECLARE_INTERFACE(iface) typedef struct iface { \ - const struct iface##Vtbl *lpVtbl; } iface; \ - typedef const struct iface##Vtbl iface##Vtbl; \ - const struct iface##Vtbl -#else -#define DECLARE_INTERFACE(iface) typedef struct iface { \ - struct iface##Vtbl *lpVtbl; \ - } iface; \ - typedef struct iface##Vtbl iface##Vtbl; \ - struct iface##Vtbl -#endif -#define DECLARE_INTERFACE_(iface,baseiface) DECLARE_INTERFACE(iface) -#endif - -#include - -#ifndef _ERROR_STATUS_T_DEFINED -#define _ERROR_STATUS_T_DEFINED -typedef unsigned long error_status_t; -#endif - -#ifndef _WCHAR_T_DEFINED -typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif -#endif diff --git a/tinyc/win32/include/winapi/guiddef.h b/tinyc/win32/include/winapi/guiddef.h deleted file mode 100644 index 4e7909a97..000000000 --- a/tinyc/win32/include/winapi/guiddef.h +++ /dev/null @@ -1,156 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID { - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8 ]; -} GUID; -#endif - -#ifndef UUID_DEFINED -#define UUID_DEFINED -typedef GUID UUID; -#endif - -#ifndef FAR -#define FAR -#endif - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -#ifndef EXTERN_C -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif -#endif - -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#endif - -#ifdef INITGUID -#ifdef __cplusplus -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } -#else -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } -#endif -#else -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID name -#endif - -#define DEFINE_OLEGUID(name,l,w1,w2) DEFINE_GUID(name,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) - -#ifndef _GUIDDEF_H_ -#define _GUIDDEF_H_ - -#ifndef __LPGUID_DEFINED__ -#define __LPGUID_DEFINED__ -typedef GUID *LPGUID; -#endif - -#ifndef __LPCGUID_DEFINED__ -#define __LPCGUID_DEFINED__ -typedef const GUID *LPCGUID; -#endif - -#ifndef __IID_DEFINED__ -#define __IID_DEFINED__ - -typedef GUID IID; -typedef IID *LPIID; -#define IID_NULL GUID_NULL -#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) -typedef GUID CLSID; -typedef CLSID *LPCLSID; -#define CLSID_NULL GUID_NULL -#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) -typedef GUID FMTID; -typedef FMTID *LPFMTID; -#define FMTID_NULL GUID_NULL -#define IsEqualFMTID(rfmtid1,rfmtid2) IsEqualGUID(rfmtid1,rfmtid2) - -#ifdef __midl_proxy -#define __MIDL_CONST -#else -#define __MIDL_CONST const -#endif - -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#ifdef __cplusplus -#define REFGUID const GUID & -#else -#define REFGUID const GUID *__MIDL_CONST -#endif -#endif - -#ifndef _REFIID_DEFINED -#define _REFIID_DEFINED -#ifdef __cplusplus -#define REFIID const IID & -#else -#define REFIID const IID *__MIDL_CONST -#endif -#endif - -#ifndef _REFCLSID_DEFINED -#define _REFCLSID_DEFINED -#ifdef __cplusplus -#define REFCLSID const IID & -#else -#define REFCLSID const IID *__MIDL_CONST -#endif -#endif - -#ifndef _REFFMTID_DEFINED -#define _REFFMTID_DEFINED -#ifdef __cplusplus -#define REFFMTID const IID & -#else -#define REFFMTID const IID *__MIDL_CONST -#endif -#endif -#endif - -#ifndef _SYS_GUID_OPERATORS_ -#define _SYS_GUID_OPERATORS_ -#include - -#ifdef __cplusplus -__inline int InlineIsEqualGUID(REFGUID rguid1,REFGUID rguid2) { - return (((unsigned long *) &rguid1)[0]==((unsigned long *) &rguid2)[0] && ((unsigned long *) &rguid1)[1]==((unsigned long *) &rguid2)[1] && - ((unsigned long *) &rguid1)[2]==((unsigned long *) &rguid2)[2] && ((unsigned long *) &rguid1)[3]==((unsigned long *) &rguid2)[3]); -} -__inline int IsEqualGUID(REFGUID rguid1,REFGUID rguid2) { return !memcmp(&rguid1,&rguid2,sizeof(GUID)); } -#else -#define InlineIsEqualGUID(rguid1,rguid2) (((unsigned long *) rguid1)[0]==((unsigned long *) rguid2)[0] && ((unsigned long *) rguid1)[1]==((unsigned long *) rguid2)[1] && ((unsigned long *) rguid1)[2]==((unsigned long *) rguid2)[2] && ((unsigned long *) rguid1)[3]==((unsigned long *) rguid2)[3]) -#define IsEqualGUID(rguid1,rguid2) (!memcmp(rguid1,rguid2,sizeof(GUID))) -#endif - -#ifdef __INLINE_ISEQUAL_GUID -#undef IsEqualGUID -#define IsEqualGUID(rguid1,rguid2) InlineIsEqualGUID(rguid1,rguid2) -#endif - -#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) -#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) - -#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_ -#define _SYS_GUID_OPERATOR_EQ_ -#ifdef __cplusplus -__inline int operator==(REFGUID guidOne,REFGUID guidOther) { return IsEqualGUID(guidOne,guidOther); } -__inline int operator!=(REFGUID guidOne,REFGUID guidOther) { return !(guidOne==guidOther); } -#endif -#endif -#endif -#endif diff --git a/tinyc/win32/include/winapi/poppack.h b/tinyc/win32/include/winapi/poppack.h deleted file mode 100644 index b08cba222..000000000 --- a/tinyc/win32/include/winapi/poppack.h +++ /dev/null @@ -1,8 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(pop) -#endif diff --git a/tinyc/win32/include/winapi/pshpack1.h b/tinyc/win32/include/winapi/pshpack1.h deleted file mode 100644 index d18d9e856..000000000 --- a/tinyc/win32/include/winapi/pshpack1.h +++ /dev/null @@ -1,8 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,1) -#endif diff --git a/tinyc/win32/include/winapi/pshpack2.h b/tinyc/win32/include/winapi/pshpack2.h deleted file mode 100644 index 7de16fd39..000000000 --- a/tinyc/win32/include/winapi/pshpack2.h +++ /dev/null @@ -1,8 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,2) -#endif diff --git a/tinyc/win32/include/winapi/pshpack4.h b/tinyc/win32/include/winapi/pshpack4.h deleted file mode 100644 index 1c8e61d7d..000000000 --- a/tinyc/win32/include/winapi/pshpack4.h +++ /dev/null @@ -1,8 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,4) -#endif diff --git a/tinyc/win32/include/winapi/pshpack8.h b/tinyc/win32/include/winapi/pshpack8.h deleted file mode 100644 index 70a3c7f7c..000000000 --- a/tinyc/win32/include/winapi/pshpack8.h +++ /dev/null @@ -1,8 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,8) -#endif diff --git a/tinyc/win32/include/winapi/winbase.h b/tinyc/win32/include/winapi/winbase.h deleted file mode 100644 index 4a38006ef..000000000 --- a/tinyc/win32/include/winapi/winbase.h +++ /dev/null @@ -1,2951 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINBASE_ -#define _WINBASE_ - -#define WINADVAPI DECLSPEC_IMPORT -#define WINBASEAPI DECLSPEC_IMPORT -#define ZAWPROXYAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#define DefineHandleTable(w) ((w),TRUE) -#define LimitEmsPages(dw) -#define SetSwapAreaSize(w) (w) -#define LockSegment(w) GlobalFix((HANDLE)(w)) -#define UnlockSegment(w) GlobalUnfix((HANDLE)(w)) -#define GetCurrentTime() GetTickCount() - -#define Yield() - -#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) -#define INVALID_FILE_SIZE ((DWORD)0xffffffff) -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - -#define FILE_BEGIN 0 -#define FILE_CURRENT 1 -#define FILE_END 2 - -#define TIME_ZONE_ID_INVALID ((DWORD)0xffffffff) - -#define WAIT_FAILED ((DWORD)0xffffffff) -#define WAIT_OBJECT_0 ((STATUS_WAIT_0) + 0) -#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0) + 0) -#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0) + 0) -#define WAIT_IO_COMPLETION STATUS_USER_APC -#define STILL_ACTIVE STATUS_PENDING -#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION -#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT -#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT -#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP -#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED -#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND -#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO -#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT -#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION -#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW -#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK -#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW -#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO -#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW -#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION -#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR -#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION -#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION -#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW -#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION -#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION -#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE -#define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK -#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT -#define MoveMemory RtlMoveMemory -#define CopyMemory RtlCopyMemory -#define FillMemory RtlFillMemory -#define ZeroMemory RtlZeroMemory -#define SecureZeroMemory RtlSecureZeroMemory - -#define FILE_FLAG_WRITE_THROUGH 0x80000000 -#define FILE_FLAG_OVERLAPPED 0x40000000 -#define FILE_FLAG_NO_BUFFERING 0x20000000 -#define FILE_FLAG_RANDOM_ACCESS 0x10000000 -#define FILE_FLAG_SEQUENTIAL_SCAN 0x8000000 -#define FILE_FLAG_DELETE_ON_CLOSE 0x4000000 -#define FILE_FLAG_BACKUP_SEMANTICS 0x2000000 -#define FILE_FLAG_POSIX_SEMANTICS 0x1000000 -#define FILE_FLAG_OPEN_REPARSE_POINT 0x200000 -#define FILE_FLAG_OPEN_NO_RECALL 0x100000 -#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x80000 - -#define CREATE_NEW 1 -#define CREATE_ALWAYS 2 -#define OPEN_EXISTING 3 -#define OPEN_ALWAYS 4 -#define TRUNCATE_EXISTING 5 - -#define PROGRESS_CONTINUE 0 -#define PROGRESS_CANCEL 1 -#define PROGRESS_STOP 2 -#define PROGRESS_QUIET 3 - -#define CALLBACK_CHUNK_FINISHED 0x0 -#define CALLBACK_STREAM_SWITCH 0x1 - -#define COPY_FILE_FAIL_IF_EXISTS 0x1 -#define COPY_FILE_RESTARTABLE 0x2 -#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x4 -#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x8 - -#define REPLACEFILE_WRITE_THROUGH 0x1 -#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x2 - -#define PIPE_ACCESS_INBOUND 0x1 -#define PIPE_ACCESS_OUTBOUND 0x2 -#define PIPE_ACCESS_DUPLEX 0x3 - -#define PIPE_CLIENT_END 0x0 -#define PIPE_SERVER_END 0x1 - -#define PIPE_WAIT 0x0 -#define PIPE_NOWAIT 0x1 -#define PIPE_READMODE_BYTE 0x0 -#define PIPE_READMODE_MESSAGE 0x2 -#define PIPE_TYPE_BYTE 0x0 -#define PIPE_TYPE_MESSAGE 0x4 - -#define PIPE_UNLIMITED_INSTANCES 255 - -#define SECURITY_ANONYMOUS (SecurityAnonymous << 16) -#define SECURITY_IDENTIFICATION (SecurityIdentification << 16) -#define SECURITY_IMPERSONATION (SecurityImpersonation << 16) -#define SECURITY_DELEGATION (SecurityDelegation << 16) - -#define SECURITY_CONTEXT_TRACKING 0x40000 -#define SECURITY_EFFECTIVE_ONLY 0x80000 - -#define SECURITY_SQOS_PRESENT 0x100000 -#define SECURITY_VALID_SQOS_FLAGS 0x1f0000 - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - PVOID Pointer; - }; - HANDLE hEvent; - } OVERLAPPED,*LPOVERLAPPED; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - LPVOID lpSecurityDescriptor; - WINBOOL bInheritHandle; - } SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES; - - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION,*PPROCESS_INFORMATION,*LPPROCESS_INFORMATION; - -#ifndef _FILETIME_ -#define _FILETIME_ - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME,*PFILETIME,*LPFILETIME; -#endif - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME,*PSYSTEMTIME,*LPSYSTEMTIME; - - typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - typedef VOID (WINAPI *PFIBER_START_ROUTINE)(LPVOID lpFiberParameter); - typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION; - typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION; - typedef RTL_CRITICAL_SECTION_DEBUG CRITICAL_SECTION_DEBUG; - typedef PRTL_CRITICAL_SECTION_DEBUG PCRITICAL_SECTION_DEBUG; - typedef PRTL_CRITICAL_SECTION_DEBUG LPCRITICAL_SECTION_DEBUG; - - WINBASEAPI PVOID WINAPI EncodePointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI DecodePointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI EncodeSystemPointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI DecodeSystemPointer(PVOID Ptr); - -#ifdef I_X86_ - typedef PLDT_ENTRY LPLDT_ENTRY; -#else - typedef LPVOID LPLDT_ENTRY; -#endif - -#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE -#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS - -#define SP_SERIALCOMM ((DWORD)0x1) - -#define PST_UNSPECIFIED ((DWORD)0x0) -#define PST_RS232 ((DWORD)0x1) -#define PST_PARALLELPORT ((DWORD)0x2) -#define PST_RS422 ((DWORD)0x3) -#define PST_RS423 ((DWORD)0x4) -#define PST_RS449 ((DWORD)0x5) -#define PST_MODEM ((DWORD)0x6) -#define PST_FAX ((DWORD)0x21) -#define PST_SCANNER ((DWORD)0x22) -#define PST_NETWORK_BRIDGE ((DWORD)0x100) -#define PST_LAT ((DWORD)0x101) -#define PST_TCPIP_TELNET ((DWORD)0x102) -#define PST_X25 ((DWORD)0x103) - -#define PCF_DTRDSR ((DWORD)0x1) -#define PCF_RTSCTS ((DWORD)0x2) -#define PCF_RLSD ((DWORD)0x4) -#define PCF_PARITY_CHECK ((DWORD)0x8) -#define PCF_XONXOFF ((DWORD)0x10) -#define PCF_SETXCHAR ((DWORD)0x20) -#define PCF_TOTALTIMEOUTS ((DWORD)0x40) -#define PCF_INTTIMEOUTS ((DWORD)0x80) -#define PCF_SPECIALCHARS ((DWORD)0x100) -#define PCF_16BITMODE ((DWORD)0x200) - -#define SP_PARITY ((DWORD)0x1) -#define SP_BAUD ((DWORD)0x2) -#define SP_DATABITS ((DWORD)0x4) -#define SP_STOPBITS ((DWORD)0x8) -#define SP_HANDSHAKING ((DWORD)0x10) -#define SP_PARITY_CHECK ((DWORD)0x20) -#define SP_RLSD ((DWORD)0x40) - -#define BAUD_075 ((DWORD)0x1) -#define BAUD_110 ((DWORD)0x2) -#define BAUD_134_5 ((DWORD)0x4) -#define BAUD_150 ((DWORD)0x8) -#define BAUD_300 ((DWORD)0x10) -#define BAUD_600 ((DWORD)0x20) -#define BAUD_1200 ((DWORD)0x40) -#define BAUD_1800 ((DWORD)0x80) -#define BAUD_2400 ((DWORD)0x100) -#define BAUD_4800 ((DWORD)0x200) -#define BAUD_7200 ((DWORD)0x400) -#define BAUD_9600 ((DWORD)0x800) -#define BAUD_14400 ((DWORD)0x1000) -#define BAUD_19200 ((DWORD)0x2000) -#define BAUD_38400 ((DWORD)0x4000) -#define BAUD_56K ((DWORD)0x8000) -#define BAUD_128K ((DWORD)0x10000) -#define BAUD_115200 ((DWORD)0x20000) -#define BAUD_57600 ((DWORD)0x40000) -#define BAUD_USER ((DWORD)0x10000000) - -#define DATABITS_5 ((WORD)0x1) -#define DATABITS_6 ((WORD)0x2) -#define DATABITS_7 ((WORD)0x4) -#define DATABITS_8 ((WORD)0x8) -#define DATABITS_16 ((WORD)0x10) -#define DATABITS_16X ((WORD)0x20) - -#define STOPBITS_10 ((WORD)0x1) -#define STOPBITS_15 ((WORD)0x2) -#define STOPBITS_20 ((WORD)0x4) -#define PARITY_NONE ((WORD)0x100) -#define PARITY_ODD ((WORD)0x200) -#define PARITY_EVEN ((WORD)0x400) -#define PARITY_MARK ((WORD)0x800) -#define PARITY_SPACE ((WORD)0x1000) - - typedef struct _COMMPROP { - WORD wPacketLength; - WORD wPacketVersion; - DWORD dwServiceMask; - DWORD dwReserved1; - DWORD dwMaxTxQueue; - DWORD dwMaxRxQueue; - DWORD dwMaxBaud; - DWORD dwProvSubType; - DWORD dwProvCapabilities; - DWORD dwSettableParams; - DWORD dwSettableBaud; - WORD wSettableData; - WORD wSettableStopParity; - DWORD dwCurrentTxQueue; - DWORD dwCurrentRxQueue; - DWORD dwProvSpec1; - DWORD dwProvSpec2; - WCHAR wcProvChar[1]; - } COMMPROP,*LPCOMMPROP; - -#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) - - typedef struct _COMSTAT { - DWORD fCtsHold : 1; - DWORD fDsrHold : 1; - DWORD fRlsdHold : 1; - DWORD fXoffHold : 1; - DWORD fXoffSent : 1; - DWORD fEof : 1; - DWORD fTxim : 1; - DWORD fReserved : 25; - DWORD cbInQue; - DWORD cbOutQue; - } COMSTAT,*LPCOMSTAT; - -#define DTR_CONTROL_DISABLE 0x0 -#define DTR_CONTROL_ENABLE 0x1 -#define DTR_CONTROL_HANDSHAKE 0x2 - -#define RTS_CONTROL_DISABLE 0x0 -#define RTS_CONTROL_ENABLE 0x1 -#define RTS_CONTROL_HANDSHAKE 0x2 -#define RTS_CONTROL_TOGGLE 0x3 - - typedef struct _DCB { - DWORD DCBlength; - DWORD BaudRate; - DWORD fBinary: 1; - DWORD fParity: 1; - DWORD fOutxCtsFlow:1; - DWORD fOutxDsrFlow:1; - DWORD fDtrControl:2; - DWORD fDsrSensitivity:1; - DWORD fTXContinueOnXoff: 1; - DWORD fOutX: 1; - DWORD fInX: 1; - DWORD fErrorChar: 1; - DWORD fNull: 1; - DWORD fRtsControl:2; - DWORD fAbortOnError:1; - DWORD fDummy2:17; - WORD wReserved; - WORD XonLim; - WORD XoffLim; - BYTE ByteSize; - BYTE Parity; - BYTE StopBits; - char XonChar; - char XoffChar; - char ErrorChar; - char EofChar; - char EvtChar; - WORD wReserved1; - } DCB,*LPDCB; - - typedef struct _COMMTIMEOUTS { - DWORD ReadIntervalTimeout; - DWORD ReadTotalTimeoutMultiplier; - DWORD ReadTotalTimeoutConstant; - DWORD WriteTotalTimeoutMultiplier; - DWORD WriteTotalTimeoutConstant; - } COMMTIMEOUTS,*LPCOMMTIMEOUTS; - - typedef struct _COMMCONFIG { - DWORD dwSize; - WORD wVersion; - WORD wReserved; - DCB dcb; - DWORD dwProviderSubType; - DWORD dwProviderOffset; - DWORD dwProviderSize; - WCHAR wcProviderData[1]; - } COMMCONFIG,*LPCOMMCONFIG; - - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; - struct { - WORD wProcessorArchitecture; - WORD wReserved; - }; - }; - DWORD dwPageSize; - LPVOID lpMinimumApplicationAddress; - LPVOID lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO,*LPSYSTEM_INFO; - -#define FreeModule(hLibModule) FreeLibrary((hLibModule)) -#define MakeProcInstance(lpProc,hInstance) (lpProc) -#define FreeProcInstance(lpProc) (lpProc) - -#define GMEM_FIXED 0x0 -#define GMEM_MOVEABLE 0x2 -#define GMEM_NOCOMPACT 0x10 -#define GMEM_NODISCARD 0x20 -#define GMEM_ZEROINIT 0x40 -#define GMEM_MODIFY 0x80 -#define GMEM_DISCARDABLE 0x100 -#define GMEM_NOT_BANKED 0x1000 -#define GMEM_SHARE 0x2000 -#define GMEM_DDESHARE 0x2000 -#define GMEM_NOTIFY 0x4000 -#define GMEM_LOWER GMEM_NOT_BANKED -#define GMEM_VALID_FLAGS 0x7F72 -#define GMEM_INVALID_HANDLE 0x8000 - -#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) -#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) - -#define GlobalLRUNewest(h) ((HANDLE)(h)) -#define GlobalLRUOldest(h) ((HANDLE)(h)) -#define GlobalDiscard(h) GlobalReAlloc((h),0,GMEM_MOVEABLE) - -#define GMEM_DISCARDED 0x4000 -#define GMEM_LOCKCOUNT 0xff - - typedef struct _MEMORYSTATUS { - DWORD dwLength; - DWORD dwMemoryLoad; - SIZE_T dwTotalPhys; - SIZE_T dwAvailPhys; - SIZE_T dwTotalPageFile; - SIZE_T dwAvailPageFile; - SIZE_T dwTotalVirtual; - SIZE_T dwAvailVirtual; - } MEMORYSTATUS,*LPMEMORYSTATUS; - -#define LMEM_FIXED 0x0 -#define LMEM_MOVEABLE 0x2 -#define LMEM_NOCOMPACT 0x10 -#define LMEM_NODISCARD 0x20 -#define LMEM_ZEROINIT 0x40 -#define LMEM_MODIFY 0x80 -#define LMEM_DISCARDABLE 0xf00 -#define LMEM_VALID_FLAGS 0xf72 -#define LMEM_INVALID_HANDLE 0x8000 - -#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) -#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) - -#define NONZEROLHND (LMEM_MOVEABLE) -#define NONZEROLPTR (LMEM_FIXED) - -#define LocalDiscard(h) LocalReAlloc((h),0,LMEM_MOVEABLE) - -#define LMEM_DISCARDED 0x4000 -#define LMEM_LOCKCOUNT 0xff - -#define DEBUG_PROCESS 0x1 -#define DEBUG_ONLY_THIS_PROCESS 0x2 -#define CREATE_SUSPENDED 0x4 -#define DETACHED_PROCESS 0x8 -#define CREATE_NEW_CONSOLE 0x10 -#define NORMAL_PRIORITY_CLASS 0x20 -#define IDLE_PRIORITY_CLASS 0x40 -#define HIGH_PRIORITY_CLASS 0x80 -#define REALTIME_PRIORITY_CLASS 0x100 -#define CREATE_NEW_PROCESS_GROUP 0x200 -#define CREATE_UNICODE_ENVIRONMENT 0x400 -#define CREATE_SEPARATE_WOW_VDM 0x800 -#define CREATE_SHARED_WOW_VDM 0x1000 -#define CREATE_FORCEDOS 0x2000 -#define BELOW_NORMAL_PRIORITY_CLASS 0x4000 -#define ABOVE_NORMAL_PRIORITY_CLASS 0x8000 -#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x10000 - -#define CREATE_BREAKAWAY_FROM_JOB 0x1000000 -#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x2000000 - -#define CREATE_DEFAULT_ERROR_MODE 0x4000000 -#define CREATE_NO_WINDOW 0x8000000 - -#define PROFILE_USER 0x10000000 -#define PROFILE_KERNEL 0x20000000 -#define PROFILE_SERVER 0x40000000 - -#define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000 - -#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN -#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) -#define THREAD_PRIORITY_NORMAL 0 -#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX -#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) -#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG) - -#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT -#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE - -#define EXCEPTION_DEBUG_EVENT 1 -#define CREATE_THREAD_DEBUG_EVENT 2 -#define CREATE_PROCESS_DEBUG_EVENT 3 -#define EXIT_THREAD_DEBUG_EVENT 4 -#define EXIT_PROCESS_DEBUG_EVENT 5 -#define LOAD_DLL_DEBUG_EVENT 6 -#define UNLOAD_DLL_DEBUG_EVENT 7 -#define OUTPUT_DEBUG_STRING_EVENT 8 -#define RIP_EVENT 9 - - typedef struct _EXCEPTION_DEBUG_INFO { - EXCEPTION_RECORD ExceptionRecord; - DWORD dwFirstChance; - } EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO; - - typedef struct _CREATE_THREAD_DEBUG_INFO { - HANDLE hThread; - LPVOID lpThreadLocalBase; - LPTHREAD_START_ROUTINE lpStartAddress; - } CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO; - - typedef struct _CREATE_PROCESS_DEBUG_INFO { - HANDLE hFile; - HANDLE hProcess; - HANDLE hThread; - LPVOID lpBaseOfImage; - DWORD dwDebugInfoFileOffset; - DWORD nDebugInfoSize; - LPVOID lpThreadLocalBase; - LPTHREAD_START_ROUTINE lpStartAddress; - LPVOID lpImageName; - WORD fUnicode; - } CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO; - - typedef struct _EXIT_THREAD_DEBUG_INFO { - DWORD dwExitCode; - } EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO; - - typedef struct _EXIT_PROCESS_DEBUG_INFO { - DWORD dwExitCode; - } EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO; - - typedef struct _LOAD_DLL_DEBUG_INFO { - HANDLE hFile; - LPVOID lpBaseOfDll; - DWORD dwDebugInfoFileOffset; - DWORD nDebugInfoSize; - LPVOID lpImageName; - WORD fUnicode; - } LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO; - - typedef struct _UNLOAD_DLL_DEBUG_INFO { - LPVOID lpBaseOfDll; - } UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO; - - typedef struct _OUTPUT_DEBUG_STRING_INFO { - LPSTR lpDebugStringData; - WORD fUnicode; - WORD nDebugStringLength; - } OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO; - - typedef struct _RIP_INFO { - DWORD dwError; - DWORD dwType; - } RIP_INFO,*LPRIP_INFO; - - typedef struct _DEBUG_EVENT { - DWORD dwDebugEventCode; - DWORD dwProcessId; - DWORD dwThreadId; - union { - EXCEPTION_DEBUG_INFO Exception; - CREATE_THREAD_DEBUG_INFO CreateThread; - CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; - EXIT_THREAD_DEBUG_INFO ExitThread; - EXIT_PROCESS_DEBUG_INFO ExitProcess; - LOAD_DLL_DEBUG_INFO LoadDll; - UNLOAD_DLL_DEBUG_INFO UnloadDll; - OUTPUT_DEBUG_STRING_INFO DebugString; - RIP_INFO RipInfo; - } u; - } DEBUG_EVENT,*LPDEBUG_EVENT; - - typedef PCONTEXT LPCONTEXT; - typedef PEXCEPTION_RECORD LPEXCEPTION_RECORD; - typedef PEXCEPTION_POINTERS LPEXCEPTION_POINTERS; - -#define DRIVE_UNKNOWN 0 -#define DRIVE_NO_ROOT_DIR 1 -#define DRIVE_REMOVABLE 2 -#define DRIVE_FIXED 3 -#define DRIVE_REMOTE 4 -#define DRIVE_CDROM 5 -#define DRIVE_RAMDISK 6 - -#define GetFreeSpace(w) (0x100000L) -#define FILE_TYPE_UNKNOWN 0x0 -#define FILE_TYPE_DISK 0x1 -#define FILE_TYPE_CHAR 0x2 -#define FILE_TYPE_PIPE 0x3 -#define FILE_TYPE_REMOTE 0x8000 - -#define STD_INPUT_HANDLE ((DWORD)-10) -#define STD_OUTPUT_HANDLE ((DWORD)-11) -#define STD_ERROR_HANDLE ((DWORD)-12) - -#define NOPARITY 0 -#define ODDPARITY 1 -#define EVENPARITY 2 -#define MARKPARITY 3 -#define SPACEPARITY 4 - -#define ONESTOPBIT 0 -#define ONE5STOPBITS 1 -#define TWOSTOPBITS 2 - -#define IGNORE 0 -#define INFINITE 0xffffffff - -#define CBR_110 110 -#define CBR_300 300 -#define CBR_600 600 -#define CBR_1200 1200 -#define CBR_2400 2400 -#define CBR_4800 4800 -#define CBR_9600 9600 -#define CBR_14400 14400 -#define CBR_19200 19200 -#define CBR_38400 38400 -#define CBR_56000 56000 -#define CBR_57600 57600 -#define CBR_115200 115200 -#define CBR_128000 128000 -#define CBR_256000 256000 - -#define CE_RXOVER 0x1 -#define CE_OVERRUN 0x2 -#define CE_RXPARITY 0x4 -#define CE_FRAME 0x8 -#define CE_BREAK 0x10 -#define CE_TXFULL 0x100 -#define CE_PTO 0x200 -#define CE_IOE 0x400 -#define CE_DNS 0x800 -#define CE_OOP 0x1000 -#define CE_MODE 0x8000 - -#define IE_BADID (-1) -#define IE_OPEN (-2) -#define IE_NOPEN (-3) -#define IE_MEMORY (-4) -#define IE_DEFAULT (-5) -#define IE_HARDWARE (-10) -#define IE_BYTESIZE (-11) -#define IE_BAUDRATE (-12) - -#define EV_RXCHAR 0x1 -#define EV_RXFLAG 0x2 -#define EV_TXEMPTY 0x4 -#define EV_CTS 0x8 -#define EV_DSR 0x10 -#define EV_RLSD 0x20 -#define EV_BREAK 0x40 -#define EV_ERR 0x80 -#define EV_RING 0x100 -#define EV_PERR 0x200 -#define EV_RX80FULL 0x400 -#define EV_EVENT1 0x800 -#define EV_EVENT2 0x1000 - -#define SETXOFF 1 -#define SETXON 2 -#define SETRTS 3 -#define CLRRTS 4 -#define SETDTR 5 -#define CLRDTR 6 -#define RESETDEV 7 -#define SETBREAK 8 -#define CLRBREAK 9 - -#define PURGE_TXABORT 0x1 -#define PURGE_RXABORT 0x2 -#define PURGE_TXCLEAR 0x4 -#define PURGE_RXCLEAR 0x8 - -#define LPTx 0x80 - -#define MS_CTS_ON ((DWORD)0x10) -#define MS_DSR_ON ((DWORD)0x20) -#define MS_RING_ON ((DWORD)0x40) -#define MS_RLSD_ON ((DWORD)0x80) - -#define S_QUEUEEMPTY 0 -#define S_THRESHOLD 1 -#define S_ALLTHRESHOLD 2 - -#define S_NORMAL 0 -#define S_LEGATO 1 -#define S_STACCATO 2 - -#define S_PERIOD512 0 -#define S_PERIOD1024 1 -#define S_PERIOD2048 2 -#define S_PERIODVOICE 3 -#define S_WHITE512 4 -#define S_WHITE1024 5 -#define S_WHITE2048 6 -#define S_WHITEVOICE 7 - -#define S_SERDVNA (-1) -#define S_SEROFM (-2) -#define S_SERMACT (-3) -#define S_SERQFUL (-4) -#define S_SERBDNT (-5) -#define S_SERDLN (-6) -#define S_SERDCC (-7) -#define S_SERDTP (-8) -#define S_SERDVL (-9) -#define S_SERDMD (-10) -#define S_SERDSH (-11) -#define S_SERDPT (-12) -#define S_SERDFQ (-13) -#define S_SERDDR (-14) -#define S_SERDSR (-15) -#define S_SERDST (-16) - -#define NMPWAIT_WAIT_FOREVER 0xffffffff -#define NMPWAIT_NOWAIT 0x1 -#define NMPWAIT_USE_DEFAULT_WAIT 0x0 - -#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES -#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH -#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK -#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS -#define FS_VOL_IS_COMPRESSED FILE_VOLUME_IS_COMPRESSED -#define FS_FILE_COMPRESSION FILE_FILE_COMPRESSION -#define FS_FILE_ENCRYPTION FILE_SUPPORTS_ENCRYPTION - -#define FILE_MAP_COPY SECTION_QUERY -#define FILE_MAP_WRITE SECTION_MAP_WRITE -#define FILE_MAP_READ SECTION_MAP_READ -#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS -#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT - -#define OF_READ 0x0 -#define OF_WRITE 0x1 -#define OF_READWRITE 0x2 -#define OF_SHARE_COMPAT 0x0 -#define OF_SHARE_EXCLUSIVE 0x10 -#define OF_SHARE_DENY_WRITE 0x20 -#define OF_SHARE_DENY_READ 0x30 -#define OF_SHARE_DENY_NONE 0x40 -#define OF_PARSE 0x100 -#define OF_DELETE 0x200 -#define OF_VERIFY 0x400 -#define OF_CANCEL 0x800 -#define OF_CREATE 0x1000 -#define OF_PROMPT 0x2000 -#define OF_EXIST 0x4000 -#define OF_REOPEN 0x8000 - -#define OFS_MAXPATHNAME 128 - typedef struct _OFSTRUCT { - BYTE cBytes; - BYTE fFixedDisk; - WORD nErrCode; - WORD Reserved1; - WORD Reserved2; - CHAR szPathName[OFS_MAXPATHNAME]; - } OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT; - -#ifndef NOWINBASEINTERLOCK - -#ifndef _NTOS_ - -#if defined(__ia64__) && !defined(RC_INVOKED) - -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire _InterlockedIncrement_acq -#define InterlockedIncrementRelease _InterlockedIncrement_rel -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire _InterlockedDecrement_acq -#define InterlockedDecrementRelease _InterlockedDecrement_rel -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire _InterlockedCompareExchange_acq -#define InterlockedCompareExchangeRelease _InterlockedCompareExchange_rel -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer_rel -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer_acq - -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAcquire64 _InterlockedExchange64_acq -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 _InterlockedCompareExchange64_acq -#define InterlockedCompareExchangeRelease64 _InterlockedCompareExchange64_rel - - LONGLONG __cdecl InterlockedIncrement64(LONGLONG volatile *Addend); - LONGLONG __cdecl InterlockedDecrement64(LONGLONG volatile *Addend); - LONG __cdecl InterlockedIncrementAcquire(LONG volatile *Addend); - LONG __cdecl InterlockedDecrementAcquire(LONG volatile *Addend); - LONG __cdecl InterlockedIncrementRelease(LONG volatile *Addend); - LONG __cdecl InterlockedDecrementRelease(LONG volatile *Addend); - LONGLONG __cdecl InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); - LONGLONG __cdecl InterlockedExchangeAcquire64 (LONGLONG volatile *Target,LONGLONG Value); - LONGLONG __cdecl InterlockedExchangeAdd64 (LONGLONG volatile *Addend,LONGLONG Value); - LONGLONG __cdecl InterlockedCompareExchange64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONGLONG __cdecl InterlockedCompareExchangeAcquire64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONGLONG __cdecl InterlockedCompareExchangeRelease64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONG __cdecl InterlockedIncrement(LONG volatile *lpAddend); - LONG __cdecl InterlockedDecrement(LONG volatile *lpAddend); - LONG __cdecl InterlockedExchange(LONG volatile *Target,LONG Value); - LONG __cdecl InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG __cdecl InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); - LONG __cdecl InterlockedCompareExchangeRelease(LONG volatile *Destination,LONG ExChange,LONG Comperand); - LONG __cdecl InterlockedCompareExchangeAcquire(LONG volatile *Destination,LONG ExChange,LONG Comperand); - PVOID __cdecl InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); - PVOID __cdecl InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand); - PVOID __cdecl InterlockedCompareExchangePointerAcquire(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - PVOID __cdecl InterlockedCompareExchangePointerRelease(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - -#ifndef InterlockedAnd -#define InterlockedAnd InterlockedAnd_Inline - __CRT_INLINE LONG InterlockedAnd_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i & Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef InterlockedOr -#define InterlockedOr InterlockedOr_Inline - - __CRT_INLINE LONG InterlockedOr_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i | Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef InterlockedXor -#define InterlockedXor InterlockedXor_Inline - - __CRT_INLINE LONG InterlockedXor_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i ^ Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef !defined (InterlockedAnd64) -#define InterlockedAnd64 InterlockedAnd64_Inline - - __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedOr64 -#define InterlockedOr64 InterlockedOr64_Inline - - __CRT_INLINE LONGLONG InterlockedOr64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedXor64 -#define InterlockedXor64 InterlockedXor64_Inline - - __CRT_INLINE LONGLONG InterlockedXor64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedBitTestAndSet -#define InterlockedBitTestAndSet InterlockedBitTestAndSet_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndSet_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedOr(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); - } -#endif - -#ifndef InterlockedBitTestAndReset -#define InterlockedBitTestAndReset InterlockedBitTestAndReset_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndReset_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedAnd(&Base[Bit/(sizeof(*Base)*8)],~tBit)&tBit)!=0); - } -#endif - -#ifndef InterlockedBitTestAndComplement -#define InterlockedBitTestAndComplement InterlockedBitTestAndComplement_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedXor(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); - } -#endif -#elif defined(__x86_64) && !defined(RC_INVOKED) - -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer -#define InterlockedAnd64 _InterlockedAnd64 -#define InterlockedOr64 _InterlockedOr64 -#define InterlockedXor64 _InterlockedXor64 -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 - - LONG InterlockedIncrement(LONG volatile *Addend); - LONG InterlockedDecrement(LONG volatile *Addend); - LONG InterlockedExchange(LONG volatile *Target,LONG Value); - LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); - PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); - LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedIncrement64(LONG64 volatile *Addend); - LONG64 InterlockedDecrement64(LONG64 volatile *Addend); - LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value); - LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); - LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); -#else - LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend); - LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend); - LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value); - -#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) - - LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand); - LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand); - - __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedOr64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedXor64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); - - return Old; - } - - __CRT_INLINE LONGLONG InterlockedIncrement64(LONGLONG volatile *Addend) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old + 1,Old)!=Old); - return Old + 1; - } - - __CRT_INLINE LONGLONG InterlockedDecrement64(LONGLONG volatile *Addend) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old - 1,Old)!=Old); - return Old - 1; - } - - __CRT_INLINE LONGLONG InterlockedExchange64(LONGLONG volatile *Target,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Target; - } while(InterlockedCompareExchange64(Target,Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedExchangeAdd64(LONGLONG volatile *Addend,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old + Value,Old)!=Old); - return Old; - } - -#ifdef __cplusplus - __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { - return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand)); - } -#define InterlockedCompareExchangePointer __InlineInterlockedCompareExchangePointer -#else -#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand)) -#endif - -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 -#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer -#endif - -#if defined(_SLIST_HEADER_) && !defined(_NTOSP_) - WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER ListHead); - WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER ListHead); -#endif -#endif -#endif - - WINBASEAPI WINBOOL WINAPI FreeResource(HGLOBAL hResData); - WINBASEAPI LPVOID WINAPI LockResource(HGLOBAL hResData); - -#define UnlockResource(hResData) ((hResData),0) -#define MAXINTATOM 0xC000 -#define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) -#define INVALID_ATOM ((ATOM)0) - - int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd); - WINBASEAPI WINBOOL WINAPI FreeLibrary(HMODULE hLibModule); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI DisableThreadLibraryCalls(HMODULE hLibModule); - WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName); - WINBASEAPI DWORD WINAPI GetVersion(VOID); - WINBASEAPI HGLOBAL WINAPI GlobalAlloc(UINT uFlags,SIZE_T dwBytes); - WINBASEAPI HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags); - WINBASEAPI SIZE_T WINAPI GlobalSize(HGLOBAL hMem); - WINBASEAPI UINT WINAPI GlobalFlags(HGLOBAL hMem); - WINBASEAPI LPVOID WINAPI GlobalLock(HGLOBAL hMem); - WINBASEAPI HGLOBAL WINAPI GlobalHandle(LPCVOID pMem); - WINBASEAPI WINBOOL WINAPI GlobalUnlock(HGLOBAL hMem); - WINBASEAPI HGLOBAL WINAPI GlobalFree(HGLOBAL hMem); - WINBASEAPI SIZE_T WINAPI GlobalCompact(DWORD dwMinFree); - WINBASEAPI VOID WINAPI GlobalFix(HGLOBAL hMem); - WINBASEAPI VOID WINAPI GlobalUnfix(HGLOBAL hMem); - WINBASEAPI LPVOID WINAPI GlobalWire(HGLOBAL hMem); - WINBASEAPI WINBOOL WINAPI GlobalUnWire(HGLOBAL hMem); - WINBASEAPI VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); - - typedef struct _MEMORYSTATUSEX { - DWORD dwLength; - DWORD dwMemoryLoad; - DWORDLONG ullTotalPhys; - DWORDLONG ullAvailPhys; - DWORDLONG ullTotalPageFile; - DWORDLONG ullAvailPageFile; - DWORDLONG ullTotalVirtual; - DWORDLONG ullAvailVirtual; - DWORDLONG ullAvailExtendedVirtual; - } MEMORYSTATUSEX,*LPMEMORYSTATUSEX; - - WINBASEAPI WINBOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); - WINBASEAPI HLOCAL WINAPI LocalAlloc(UINT uFlags,SIZE_T uBytes); - WINBASEAPI HLOCAL WINAPI LocalReAlloc(HLOCAL hMem,SIZE_T uBytes,UINT uFlags); - WINBASEAPI LPVOID WINAPI LocalLock(HLOCAL hMem); - WINBASEAPI HLOCAL WINAPI LocalHandle(LPCVOID pMem); - WINBASEAPI WINBOOL WINAPI LocalUnlock(HLOCAL hMem); - WINBASEAPI SIZE_T WINAPI LocalSize(HLOCAL hMem); - WINBASEAPI UINT WINAPI LocalFlags(HLOCAL hMem); - WINBASEAPI HLOCAL WINAPI LocalFree(HLOCAL hMem); - WINBASEAPI SIZE_T WINAPI LocalShrink(HLOCAL hMem,UINT cbNewSize); - WINBASEAPI SIZE_T WINAPI LocalCompact(UINT uMinFree); - WINBASEAPI WINBOOL WINAPI FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize); - WINBASEAPI LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); - WINBASEAPI WINBOOL WINAPI VirtualFree(LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); - WINBASEAPI WINBOOL WINAPI VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); - WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); - WINBASEAPI LPVOID WINAPI VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); - WINBASEAPI UINT WINAPI GetWriteWatch(DWORD dwFlags,PVOID lpBaseAddress,SIZE_T dwRegionSize,PVOID *lpAddresses,ULONG_PTR *lpdwCount,PULONG lpdwGranularity); - WINBASEAPI UINT WINAPI ResetWriteWatch(LPVOID lpBaseAddress,SIZE_T dwRegionSize); - WINBASEAPI SIZE_T WINAPI GetLargePageMinimum(VOID); - WINBASEAPI UINT WINAPI EnumSystemFirmwareTables(DWORD FirmwareTableProviderSignature,PVOID pFirmwareTableEnumBuffer,DWORD BufferSize); - WINBASEAPI UINT WINAPI GetSystemFirmwareTable(DWORD FirmwareTableProviderSignature,DWORD FirmwareTableID,PVOID pFirmwareTableBuffer,DWORD BufferSize); - WINBASEAPI WINBOOL WINAPI VirtualFreeEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); - WINBASEAPI WINBOOL WINAPI VirtualProtectEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); - WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); - WINBASEAPI HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); - WINBASEAPI WINBOOL WINAPI HeapDestroy(HANDLE hHeap); - WINBASEAPI LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); - WINBASEAPI LPVOID WINAPI HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,SIZE_T dwBytes); - WINBASEAPI WINBOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem); - WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); - WINBASEAPI WINBOOL WINAPI HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); - WINBASEAPI SIZE_T WINAPI HeapCompact(HANDLE hHeap,DWORD dwFlags); - WINBASEAPI HANDLE WINAPI GetProcessHeap(VOID); - WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps); - - typedef struct _PROCESS_HEAP_ENTRY { - PVOID lpData; - DWORD cbData; - BYTE cbOverhead; - BYTE iRegionIndex; - WORD wFlags; - union { - struct { - HANDLE hMem; - DWORD dwReserved[3]; - } Block; - struct { - DWORD dwCommittedSize; - DWORD dwUnCommittedSize; - LPVOID lpFirstBlock; - LPVOID lpLastBlock; - } Region; - }; - } PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY; - -#define PROCESS_HEAP_REGION 0x1 -#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x2 -#define PROCESS_HEAP_ENTRY_BUSY 0x4 -#define PROCESS_HEAP_ENTRY_MOVEABLE 0x10 -#define PROCESS_HEAP_ENTRY_DDESHARE 0x20 - - WINBASEAPI WINBOOL WINAPI HeapLock(HANDLE hHeap); - WINBASEAPI WINBOOL WINAPI HeapUnlock(HANDLE hHeap); - WINBASEAPI WINBOOL WINAPI HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry); - WINBASEAPI WINBOOL WINAPI HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); - WINBASEAPI WINBOOL WINAPI HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); - -#define SCS_32BIT_BINARY 0 -#define SCS_DOS_BINARY 1 -#define SCS_WOW_BINARY 2 -#define SCS_PIF_BINARY 3 -#define SCS_POSIX_BINARY 4 -#define SCS_OS216_BINARY 5 -#define SCS_64BIT_BINARY 6 - -#ifdef UNICODE -#define GetBinaryType GetBinaryTypeW -#define GetShortPathName GetShortPathNameW -#define GetLongPathName GetLongPathNameW -#define GetEnvironmentStrings GetEnvironmentStringsW -#define SetEnvironmentStrings SetEnvironmentStringsW -#define FreeEnvironmentStrings FreeEnvironmentStringsW -#else -#define GetBinaryType GetBinaryTypeA -#define GetShortPathName GetShortPathNameA -#define GetLongPathName GetLongPathNameA -#define GetEnvironmentStringsA GetEnvironmentStrings -#define SetEnvironmentStrings SetEnvironmentStringsA -#define FreeEnvironmentStrings FreeEnvironmentStringsA -#endif - -#ifdef _WIN64 -#define SCS_THIS_PLATFORM_BINARY SCS_64BIT_BINARY -#else -#define SCS_THIS_PLATFORM_BINARY SCS_32BIT_BINARY -#endif - - WINBASEAPI WINBOOL WINAPI GetBinaryTypeA(LPCSTR lpApplicationName,LPDWORD lpBinaryType); - WINBASEAPI WINBOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName,LPDWORD lpBinaryType); - WINBASEAPI DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath,LPSTR lpszShortPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath,LPWSTR lpszShortPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetLongPathNameA(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR lpszShortPath,LPWSTR lpszLongPath,DWORD cchBuffer); - WINBASEAPI WINBOOL WINAPI GetProcessAffinityMask(HANDLE hProcess,PDWORD_PTR lpProcessAffinityMask,PDWORD_PTR lpSystemAffinityMask); - WINBASEAPI WINBOOL WINAPI SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask); - WINBASEAPI WINBOOL WINAPI GetProcessHandleCount(HANDLE hProcess,PDWORD pdwHandleCount); - WINBASEAPI WINBOOL WINAPI GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI WINBOOL WINAPI GetProcessIoCounters(HANDLE hProcess,PIO_COUNTERS lpIoCounters); - WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize); - WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize,PDWORD Flags); - WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize); - WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize,DWORD Flags); - WINBASEAPI HANDLE WINAPI OpenProcess(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwProcessId); - WINBASEAPI HANDLE WINAPI GetCurrentProcess(VOID); - WINBASEAPI DWORD WINAPI GetCurrentProcessId(VOID); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode); - WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess,UINT uExitCode); - WINBASEAPI WINBOOL WINAPI GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode); - WINBASEAPI VOID WINAPI FatalExit(int ExitCode); - /* WINBASEAPI LPCH WINAPI GetEnvironmentStrings(VOID); */ - WINBASEAPI LPWCH WINAPI GetEnvironmentStringsW(VOID); - WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsA(LPCH NewEnvironment); - WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsW(LPWCH NewEnvironment); - WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsA(LPCH); - WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsW(LPWCH); - WINBASEAPI VOID WINAPI RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); - WINBASEAPI LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); - - typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); - typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; - - WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); - -#define FIBER_FLAG_FLOAT_SWITCH 0x1 - - WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); - WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); - WINBASEAPI VOID WINAPI DeleteFiber(LPVOID lpFiber); - WINBASEAPI LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); - WINBASEAPI LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI ConvertFiberToThread(VOID); - WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); - WINBASEAPI WINBOOL WINAPI SwitchToThread(VOID); - WINBASEAPI HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); - WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); - WINBASEAPI HANDLE WINAPI GetCurrentThread(VOID); - WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); - WINBASEAPI WINBOOL WINAPI SetThreadStackGuarantee (PULONG StackSizeInBytes); - WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE Thread); - WINBASEAPI DWORD WINAPI GetThreadId(HANDLE Thread); - WINBASEAPI DWORD WINAPI GetProcessId(HANDLE Process); - WINBASEAPI DWORD WINAPI GetCurrentProcessorNumber(VOID); - WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask); - WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor); - WINBASEAPI WINBOOL WINAPI SetProcessPriorityBoost(HANDLE hProcess,WINBOOL bDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI GetProcessPriorityBoost(HANDLE hProcess,PBOOL pDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI RequestWakeupLatency(LATENCY_TIME latency); - WINBASEAPI WINBOOL WINAPI IsSystemResumeAutomatic(VOID); - WINBASEAPI HANDLE WINAPI OpenThread(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwThreadId); - WINBASEAPI WINBOOL WINAPI SetThreadPriority(HANDLE hThread,int nPriority); - WINBASEAPI WINBOOL WINAPI SetThreadPriorityBoost(HANDLE hThread,WINBOOL bDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI GetThreadPriorityBoost(HANDLE hThread,PBOOL pDisablePriorityBoost); - WINBASEAPI int WINAPI GetThreadPriority(HANDLE hThread); - WINBASEAPI WINBOOL WINAPI GetThreadTimes(HANDLE hThread,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI WINBOOL WINAPI GetThreadIOPendingFlag(HANDLE hThread,PBOOL lpIOIsPending); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitThread(DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI TerminateThread(HANDLE hThread,DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); - WINBASEAPI WINBOOL WINAPI GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry); - WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags); - WINBASEAPI DWORD WINAPI GetLastError(VOID); - WINBASEAPI VOID WINAPI SetLastError(DWORD dwErrCode); - -#ifndef RC_INVOKED -#ifdef WINBASE_DECLARE_RESTORE_LAST_ERROR - WINBASEAPI VOID WINAPI RestoreLastError(DWORD dwErrCode); - - typedef VOID (WINAPI *PRESTORE_LAST_ERROR)(DWORD); - -#define RESTORE_LAST_ERROR_NAME_A "RestoreLastError" -#define RESTORE_LAST_ERROR_NAME_W L"RestoreLastError" -#define RESTORE_LAST_ERROR_NAME TEXT("RestoreLastError") -#endif -#endif - -#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal)!=STATUS_PENDING) - - WINBASEAPI WINBOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,WINBOOL bWait); - WINBASEAPI HANDLE WINAPI CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads); - WINBASEAPI WINBOOL WINAPI GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,PULONG_PTR lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds); - WINBASEAPI WINBOOL WINAPI PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,LPOVERLAPPED lpOverlapped); - -#define SEM_FAILCRITICALERRORS 0x1 -#define SEM_NOGPFAULTERRORBOX 0x2 -#define SEM_NOALIGNMENTFAULTEXCEPT 0x4 -#define SEM_NOOPENFILEERRORBOX 0x8000 - - WINBASEAPI UINT WINAPI SetErrorMode(UINT uMode); - WINBASEAPI WINBOOL WINAPI ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead); - WINBASEAPI WINBOOL WINAPI WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten); - WINBASEAPI WINBOOL WINAPI GetThreadContext(HANDLE hThread,LPCONTEXT lpContext); - WINBASEAPI WINBOOL WINAPI SetThreadContext(HANDLE hThread,CONST CONTEXT *lpContext); - WINBASEAPI DWORD WINAPI SuspendThread(HANDLE hThread); - WINBASEAPI DWORD WINAPI ResumeThread(HANDLE hThread); - - typedef VOID (WINAPI *PAPCFUNC)(ULONG_PTR dwParam); - - WINBASEAPI DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData); - WINBASEAPI WINBOOL WINAPI IsDebuggerPresent(VOID); - WINBASEAPI WINBOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess,PBOOL pbDebuggerPresent); - WINBASEAPI VOID WINAPI DebugBreak(VOID); - WINBASEAPI WINBOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds); - WINBASEAPI WINBOOL WINAPI ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadId,DWORD dwContinueStatus); - WINBASEAPI WINBOOL WINAPI DebugActiveProcess(DWORD dwProcessId); - WINBASEAPI WINBOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId); - WINBASEAPI WINBOOL WINAPI DebugSetProcessKillOnExit(WINBOOL KillOnExit); - WINBASEAPI WINBOOL WINAPI DebugBreakProcess(HANDLE Process); - WINBASEAPI VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI WINBOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); - WINBASEAPI DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); - WINBASEAPI WINBOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI WINBOOL WINAPI SetEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI ResetEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI PulseEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); - WINBASEAPI WINBOOL WINAPI ReleaseMutex(HANDLE hMutex); - WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); - WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds); - WINBASEAPI VOID WINAPI Sleep(DWORD dwMilliseconds); - WINBASEAPI HGLOBAL WINAPI LoadResource(HMODULE hModule,HRSRC hResInfo); - WINBASEAPI DWORD WINAPI SizeofResource(HMODULE hModule,HRSRC hResInfo); - WINBASEAPI ATOM WINAPI GlobalDeleteAtom(ATOM nAtom); - WINBASEAPI WINBOOL WINAPI InitAtomTable(DWORD nSize); - WINBASEAPI ATOM WINAPI DeleteAtom(ATOM nAtom); - WINBASEAPI UINT WINAPI SetHandleCount(UINT uNumber); - WINBASEAPI DWORD WINAPI GetLogicalDrives(VOID); - WINBASEAPI WINBOOL WINAPI LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh); - WINBASEAPI WINBOOL WINAPI UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh); - WINBASEAPI WINBOOL WINAPI LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped); - -#define LOCKFILE_FAIL_IMMEDIATELY 0x1 -#define LOCKFILE_EXCLUSIVE_LOCK 0x2 - - WINBASEAPI WINBOOL WINAPI UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped); - - typedef struct _BY_HANDLE_FILE_INFORMATION { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD dwVolumeSerialNumber; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD nNumberOfLinks; - DWORD nFileIndexHigh; - DWORD nFileIndexLow; - } BY_HANDLE_FILE_INFORMATION,*PBY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION; - -#ifdef UNICODE -#define SetFileShortName SetFileShortNameW -#else -#define SetFileShortName SetFileShortNameA -#endif - - WINBASEAPI WINBOOL WINAPI GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION lpFileInformation); - WINBASEAPI DWORD WINAPI GetFileType(HANDLE hFile); - WINBASEAPI DWORD WINAPI GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh); - WINBASEAPI WINBOOL WINAPI GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize); - WINBASEAPI HANDLE WINAPI GetStdHandle(DWORD nStdHandle); - WINBASEAPI WINBOOL WINAPI SetStdHandle(DWORD nStdHandle,HANDLE hHandle); - WINBASEAPI WINBOOL WINAPI WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI FlushFileBuffers(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI RequestDeviceWakeup(HANDLE hDevice); - WINBASEAPI WINBOOL WINAPI CancelDeviceWakeupRequest(HANDLE hDevice); - WINBASEAPI WINBOOL WINAPI GetDevicePowerState(HANDLE hDevice,WINBOOL *pfOn); - WINBASEAPI WINBOOL WINAPI SetMessageWaitingIndicator(HANDLE hMsgIndicator,ULONG ulMsgCount); - WINBASEAPI WINBOOL WINAPI SetEndOfFile(HANDLE hFile); - WINBASEAPI DWORD WINAPI SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); - WINBASEAPI WINBOOL WINAPI SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod); - WINBASEAPI WINBOOL WINAPI FindClose(HANDLE hFindFile); - WINBASEAPI WINBOOL WINAPI GetFileTime(HANDLE hFile,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime); - WINBASEAPI WINBOOL WINAPI SetFileTime(HANDLE hFile,CONST FILETIME *lpCreationTime,CONST FILETIME *lpLastAccessTime,CONST FILETIME *lpLastWriteTime); - WINBASEAPI WINBOOL WINAPI SetFileValidData(HANDLE hFile,LONGLONG ValidDataLength); - WINBASEAPI WINBOOL WINAPI SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName); - WINBASEAPI WINBOOL WINAPI SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName); - WINBASEAPI WINBOOL WINAPI CloseHandle(HANDLE hObject); - WINBASEAPI WINBOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle,LPHANDLE lpTargetHandle,DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwOptions); - WINBASEAPI WINBOOL WINAPI GetHandleInformation(HANDLE hObject,LPDWORD lpdwFlags); - WINBASEAPI WINBOOL WINAPI SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags); - -#define HANDLE_FLAG_INHERIT 0x1 -#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x2 - -#define HINSTANCE_ERROR 32 - - WINBASEAPI DWORD WINAPI LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock); - WINBASEAPI UINT WINAPI WinExec(LPCSTR lpCmdLine,UINT uCmdShow); - WINBASEAPI WINBOOL WINAPI ClearCommBreak(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMSTAT lpStat); - WINBASEAPI WINBOOL WINAPI SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue); - WINBASEAPI WINBOOL WINAPI EscapeCommFunction(HANDLE hFile,DWORD dwFunc); - WINBASEAPI WINBOOL WINAPI GetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI GetCommMask(HANDLE hFile,LPDWORD lpEvtMask); - WINBASEAPI WINBOOL WINAPI GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp); - WINBASEAPI WINBOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat); - WINBASEAPI WINBOOL WINAPI GetCommState(HANDLE hFile,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI PurgeComm(HANDLE hFile,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI SetCommBreak(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI SetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,DWORD dwSize); - WINBASEAPI WINBOOL WINAPI SetCommMask(HANDLE hFile,DWORD dwEvtMask); - WINBASEAPI WINBOOL WINAPI SetCommState(HANDLE hFile,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI TransmitCommChar(HANDLE hFile,char cChar); - WINBASEAPI WINBOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped); - WINBASEAPI DWORD WINAPI SetTapePosition(HANDLE hDevice,DWORD dwPositionMethod,DWORD dwPartition,DWORD dwOffsetLow,DWORD dwOffsetHigh,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI GetTapePosition(HANDLE hDevice,DWORD dwPositionType,LPDWORD lpdwPartition,LPDWORD lpdwOffsetLow,LPDWORD lpdwOffsetHigh); - WINBASEAPI DWORD WINAPI PrepareTape(HANDLE hDevice,DWORD dwOperation,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI EraseTape(HANDLE hDevice,DWORD dwEraseType,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI CreateTapePartition(HANDLE hDevice,DWORD dwPartitionMethod,DWORD dwCount,DWORD dwSize); - WINBASEAPI DWORD WINAPI WriteTapemark(HANDLE hDevice,DWORD dwTapemarkType,DWORD dwTapemarkCount,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI GetTapeStatus(HANDLE hDevice); - WINBASEAPI DWORD WINAPI GetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPDWORD lpdwSize,LPVOID lpTapeInformation); - -#define GET_TAPE_MEDIA_INFORMATION 0 -#define GET_TAPE_DRIVE_INFORMATION 1 - - WINBASEAPI DWORD WINAPI SetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPVOID lpTapeInformation); - -#define SET_TAPE_MEDIA_INFORMATION 0 -#define SET_TAPE_DRIVE_INFORMATION 1 - - WINBASEAPI WINBOOL WINAPI Beep(DWORD dwFreq,DWORD dwDuration); - WINBASEAPI int WINAPI MulDiv(int nNumber,int nNumerator,int nDenominator); - WINBASEAPI VOID WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime); - WINBASEAPI VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); - WINBASEAPI WINBOOL WINAPI SetSystemTime(CONST SYSTEMTIME *lpSystemTime); - WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime); - WINBASEAPI WINBOOL WINAPI SetLocalTime(CONST SYSTEMTIME *lpSystemTime); - WINBASEAPI VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); - WINBASEAPI WINBOOL WINAPI SetSystemFileCacheSize(SIZE_T MinimumFileCacheSize,SIZE_T MaximumFileCacheSize,DWORD Flags); - WINBASEAPI WINBOOL WINAPI GetSystemFileCacheSize(PSIZE_T lpMinimumFileCacheSize,PSIZE_T lpMaximumFileCacheSize,PDWORD lpFlags); - WINBASEAPI WINBOOL WINAPI GetSystemRegistryQuota(PDWORD pdwQuotaAllowed,PDWORD pdwQuotaUsed); - WINBOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI VOID WINAPI GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo); - WINBASEAPI WINBOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature); - - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION,*PTIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION; - -#ifdef UNICODE -#define FormatMessage FormatMessageW -#else -#define FormatMessage FormatMessageA -#endif - - WINBASEAPI WINBOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime); - WINBASEAPI WINBOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpLocalTime,LPSYSTEMTIME lpUniversalTime); - WINBASEAPI DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation); - WINBASEAPI WINBOOL WINAPI SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation); - WINBASEAPI WINBOOL WINAPI SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,LPFILETIME lpFileTime); - WINBASEAPI WINBOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *lpFileTime,LPFILETIME lpLocalFileTime); - WINBASEAPI WINBOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime,LPFILETIME lpFileTime); - WINBASEAPI WINBOOL WINAPI FileTimeToSystemTime(CONST FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime); - WINBASEAPI LONG WINAPI CompareFileTime(CONST FILETIME *lpFileTime1,CONST FILETIME *lpFileTime2); - WINBASEAPI WINBOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *lpFileTime,LPWORD lpFatDate,LPWORD lpFatTime); - WINBASEAPI WINBOOL WINAPI DosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime); - WINBASEAPI DWORD WINAPI GetTickCount(VOID); - WINBASEAPI WINBOOL WINAPI SetSystemTimeAdjustment(DWORD dwTimeAdjustment,WINBOOL bTimeAdjustmentDisabled); - WINBASEAPI WINBOOL WINAPI GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,PDWORD lpTimeIncrement,PBOOL lpTimeAdjustmentDisabled); - WINBASEAPI DWORD WINAPI FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments); - WINBASEAPI DWORD WINAPI FormatMessageW(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list *Arguments); - -#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x100 -#define FORMAT_MESSAGE_IGNORE_INSERTS 0x200 -#define FORMAT_MESSAGE_FROM_STRING 0x400 -#define FORMAT_MESSAGE_FROM_HMODULE 0x800 -#define FORMAT_MESSAGE_FROM_SYSTEM 0x1000 -#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x2000 -#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0xff - -#ifdef UNICODE -#define CreateMailslot CreateMailslotW -#define EncryptFile EncryptFileW -#define DecryptFile DecryptFileW -#define FileEncryptionStatus FileEncryptionStatusW -#else -#define CreateMailslot CreateMailslotA -#define EncryptFile EncryptFileA -#define DecryptFile DecryptFileA -#define FileEncryptionStatus FileEncryptionStatusA -#endif - - WINBASEAPI WINBOOL WINAPI CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize); - WINBASEAPI WINBOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe); - WINBASEAPI WINBOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout); - WINBASEAPI WINBOOL WINAPI GetNamedPipeInfo(HANDLE hNamedPipe,LPDWORD lpFlags,LPDWORD lpOutBufferSize,LPDWORD lpInBufferSize,LPDWORD lpMaxInstances); - WINBASEAPI WINBOOL WINAPI PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage); - WINBASEAPI WINBOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped); - WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI GetMailslotInfo(HANDLE hMailslot,LPDWORD lpMaxMessageSize,LPDWORD lpNextSize,LPDWORD lpMessageCount,LPDWORD lpReadTimeout); - WINBASEAPI WINBOOL WINAPI SetMailslotInfo(HANDLE hMailslot,DWORD lReadTimeout); - WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap); - WINBASEAPI WINBOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress,SIZE_T dwNumberOfBytesToFlush); - WINBASEAPI WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); - WINADVAPI WINBOOL WINAPI EncryptFileA(LPCSTR lpFileName); - WINADVAPI WINBOOL WINAPI EncryptFileW(LPCWSTR lpFileName); - WINADVAPI WINBOOL WINAPI DecryptFileA(LPCSTR lpFileName,DWORD dwReserved); - WINADVAPI WINBOOL WINAPI DecryptFileW(LPCWSTR lpFileName,DWORD dwReserved); - -#define FILE_ENCRYPTABLE 0 -#define FILE_IS_ENCRYPTED 1 -#define FILE_SYSTEM_ATTR 2 -#define FILE_ROOT_DIR 3 -#define FILE_SYSTEM_DIR 4 -#define FILE_UNKNOWN 5 -#define FILE_SYSTEM_NOT_SUPPORT 6 -#define FILE_USER_DISALLOWED 7 -#define FILE_READ_ONLY 8 -#define FILE_DIR_DISALLOWED 9 - - WINADVAPI WINBOOL WINAPI FileEncryptionStatusA(LPCSTR lpFileName,LPDWORD lpStatus); - WINADVAPI WINBOOL WINAPI FileEncryptionStatusW(LPCWSTR lpFileName,LPDWORD lpStatus); - -#define EFS_USE_RECOVERY_KEYS (0x1) - - typedef DWORD (WINAPI *PFE_EXPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,ULONG ulLength); - typedef DWORD (WINAPI *PFE_IMPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,PULONG ulLength); - -#define CREATE_FOR_IMPORT (1) -#define CREATE_FOR_DIR (2) -#define OVERWRITE_HIDDEN (4) - -#ifdef UNICODE -#define OpenEncryptedFileRaw OpenEncryptedFileRawW -#define lstrcmp lstrcmpW -#define lstrcmpi lstrcmpiW -#define lstrcpyn lstrcpynW -#define lstrcpy lstrcpyW -#define lstrcat lstrcatW -#define lstrlen lstrlenW -#else -#define OpenEncryptedFileRaw OpenEncryptedFileRawA -#define lstrcmp lstrcmpA -#define lstrcmpi lstrcmpiA -#define lstrcpyn lstrcpynA -#define lstrcpy lstrcpyA -#define lstrcat lstrcatA -#define lstrlen lstrlenA -#endif - - WINADVAPI DWORD WINAPI OpenEncryptedFileRawA(LPCSTR lpFileName,ULONG ulFlags,PVOID *pvContext); - WINADVAPI DWORD WINAPI OpenEncryptedFileRawW(LPCWSTR lpFileName,ULONG ulFlags,PVOID *pvContext); - WINADVAPI DWORD WINAPI ReadEncryptedFileRaw(PFE_EXPORT_FUNC pfExportCallback,PVOID pvCallbackContext,PVOID pvContext); - WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC pfImportCallback,PVOID pvCallbackContext,PVOID pvContext); - WINADVAPI VOID WINAPI CloseEncryptedFileRaw(PVOID pvContext); - WINBASEAPI int WINAPI lstrcmpA(LPCSTR lpString1,LPCSTR lpString2); - WINBASEAPI int WINAPI lstrcmpW(LPCWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI int WINAPI lstrcmpiA(LPCSTR lpString1,LPCSTR lpString2); - WINBASEAPI int WINAPI lstrcmpiW(LPCWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI LPSTR WINAPI lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength); - WINBASEAPI LPWSTR WINAPI lstrcpynW(LPWSTR lpString1,LPCWSTR lpString2,int iMaxLength); - WINBASEAPI LPSTR WINAPI lstrcpyA(LPSTR lpString1,LPCSTR lpString2); - WINBASEAPI LPWSTR WINAPI lstrcpyW(LPWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI LPSTR WINAPI lstrcatA(LPSTR lpString1,LPCSTR lpString2); - WINBASEAPI LPWSTR WINAPI lstrcatW(LPWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI int WINAPI lstrlenA(LPCSTR lpString); - WINBASEAPI int WINAPI lstrlenW(LPCWSTR lpString); - WINBASEAPI HFILE WINAPI OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle); - WINBASEAPI HFILE WINAPI _lopen(LPCSTR lpPathName,int iReadWrite); - WINBASEAPI HFILE WINAPI _lcreat(LPCSTR lpPathName,int iAttribute); - WINBASEAPI UINT WINAPI _lread(HFILE hFile,LPVOID lpBuffer,UINT uBytes); - WINBASEAPI UINT WINAPI _lwrite(HFILE hFile,LPCCH lpBuffer,UINT uBytes); - WINBASEAPI long WINAPI _hread(HFILE hFile,LPVOID lpBuffer,long lBytes); - WINBASEAPI long WINAPI _hwrite(HFILE hFile,LPCCH lpBuffer,long lBytes); - WINBASEAPI HFILE WINAPI _lclose(HFILE hFile); - WINBASEAPI LONG WINAPI _llseek(HFILE hFile,LONG lOffset,int iOrigin); - WINADVAPI WINBOOL WINAPI IsTextUnicode(CONST VOID *lpv,int iSize,LPINT lpiResult); - -#define FLS_OUT_OF_INDEXES ((DWORD)0xffffffff) - - WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); - WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); - WINBASEAPI WINBOOL WINAPI FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); - WINBASEAPI WINBOOL WINAPI FlsFree(DWORD dwFlsIndex); - -#define TLS_OUT_OF_INDEXES ((DWORD)0xffffffff) - - WINBASEAPI DWORD WINAPI TlsAlloc(VOID); - WINBASEAPI LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex); - WINBASEAPI WINBOOL WINAPI TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue); - WINBASEAPI WINBOOL WINAPI TlsFree(DWORD dwTlsIndex); - - typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped); - - WINBASEAPI DWORD WINAPI SleepEx(DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI WaitForSingleObjectEx(HANDLE hHandle,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI WINBOOL WINAPI ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI BackupRead(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); - WINBASEAPI WINBOOL WINAPI BackupSeek(HANDLE hFile,DWORD dwLowBytesToSeek,DWORD dwHighBytesToSeek,LPDWORD lpdwLowByteSeeked,LPDWORD lpdwHighByteSeeked,LPVOID *lpContext); - WINBASEAPI WINBOOL WINAPI BackupWrite(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); - - typedef struct _WIN32_STREAM_ID { - DWORD dwStreamId; - DWORD dwStreamAttributes; - LARGE_INTEGER Size; - DWORD dwStreamNameSize; - WCHAR cStreamName[ANYSIZE_ARRAY]; - } WIN32_STREAM_ID,*LPWIN32_STREAM_ID; - -#define BACKUP_INVALID 0x0 -#define BACKUP_DATA 0x1 -#define BACKUP_EA_DATA 0x2 -#define BACKUP_SECURITY_DATA 0x3 -#define BACKUP_ALTERNATE_DATA 0x4 -#define BACKUP_LINK 0x5 -#define BACKUP_PROPERTY_DATA 0x6 -#define BACKUP_OBJECT_ID 0x7 -#define BACKUP_REPARSE_DATA 0x8 -#define BACKUP_SPARSE_BLOCK 0x9 - -#define STREAM_NORMAL_ATTRIBUTE 0x0 -#define STREAM_MODIFIED_WHEN_READ 0x1 -#define STREAM_CONTAINS_SECURITY 0x2 -#define STREAM_CONTAINS_PROPERTIES 0x4 -#define STREAM_SPARSE_ATTRIBUTE 0x8 - - WINBASEAPI WINBOOL WINAPI ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); - -#define STARTF_USESHOWWINDOW 0x1 -#define STARTF_USESIZE 0x2 -#define STARTF_USEPOSITION 0x4 -#define STARTF_USECOUNTCHARS 0x8 -#define STARTF_USEFILLATTRIBUTE 0x10 -#define STARTF_RUNFULLSCREEN 0x20 -#define STARTF_FORCEONFEEDBACK 0x40 -#define STARTF_FORCEOFFFEEDBACK 0x80 -#define STARTF_USESTDHANDLES 0x100 - -#define STARTF_USEHOTKEY 0x200 - - typedef struct _STARTUPINFOA { - DWORD cb; - LPSTR lpReserved; - LPSTR lpDesktop; - LPSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOA,*LPSTARTUPINFOA; - - typedef struct _STARTUPINFOW { - DWORD cb; - LPWSTR lpReserved; - LPWSTR lpDesktop; - LPWSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW,*LPSTARTUPINFOW; - -#ifdef UNICODE - typedef STARTUPINFOW STARTUPINFO; - typedef LPSTARTUPINFOW LPSTARTUPINFO; -#else - typedef STARTUPINFOA STARTUPINFO; - typedef LPSTARTUPINFOA LPSTARTUPINFO; -#endif - -#define SHUTDOWN_NORETRY 0x1 - - typedef struct _WIN32_FIND_DATAA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - CHAR cFileName[MAX_PATH]; - CHAR cAlternateFileName[14]; - } WIN32_FIND_DATAA,*PWIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[MAX_PATH]; - WCHAR cAlternateFileName[14]; - } WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; - -#ifdef UNICODE - typedef WIN32_FIND_DATAW WIN32_FIND_DATA; - typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA; - typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA; -#else - typedef WIN32_FIND_DATAA WIN32_FIND_DATA; - typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA; - typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA; -#endif - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA; - -#ifdef UNICODE -#define CreateMutex CreateMutexW -#define OpenMutex OpenMutexW -#define CreateEvent CreateEventW -#define OpenEvent OpenEventW -#define CreateSemaphore CreateSemaphoreW -#define OpenSemaphore OpenSemaphoreW -#else -#define CreateMutex CreateMutexA -#define OpenMutex OpenMutexA -#define CreateEvent CreateEventA -#define OpenEvent OpenEventA -#define CreateSemaphore CreateSemaphoreA -#define OpenSemaphore OpenSemaphoreA -#endif - - WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenMutexA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenMutexW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenEventA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenEventW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenSemaphoreA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenSemaphoreW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - - typedef VOID (WINAPI *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue); - -#ifdef UNICODE -#define CreateWaitableTimer CreateWaitableTimerW -#define OpenWaitableTimer OpenWaitableTimerW -#define CreateFileMapping CreateFileMappingW -#define OpenFileMapping OpenFileMappingW -#define GetLogicalDriveStrings GetLogicalDriveStringsW -#define LoadLibrary LoadLibraryW -#define LoadLibraryEx LoadLibraryExW -#define GetModuleFileName GetModuleFileNameW -#define GetModuleHandle GetModuleHandleW -#else -#define CreateWaitableTimer CreateWaitableTimerA -#define OpenWaitableTimer OpenWaitableTimerA -#define CreateFileMapping CreateFileMappingA -#define OpenFileMapping OpenFileMappingA -#define GetLogicalDriveStrings GetLogicalDriveStringsA -#define LoadLibrary LoadLibraryA -#define LoadLibraryEx LoadLibraryExA -#define GetModuleFileName GetModuleFileNameA -#define GetModuleHandle GetModuleHandleA -#endif - - WINBASEAPI HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCSTR lpTimerName); - WINBASEAPI HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCWSTR lpTimerName); - WINBASEAPI HANDLE WINAPI OpenWaitableTimerA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpTimerName); - WINBASEAPI HANDLE WINAPI OpenWaitableTimerW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpTimerName); - WINBASEAPI WINBOOL WINAPI SetWaitableTimer(HANDLE hTimer,const LARGE_INTEGER *lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,WINBOOL fResume); - WINBASEAPI WINBOOL WINAPI CancelWaitableTimer(HANDLE hTimer); - WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenFileMappingW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI DWORD WINAPI GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetLogicalDriveStringsW(DWORD nBufferLength,LPWSTR lpBuffer); - - typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { - LowMemoryResourceNotification,HighMemoryResourceNotification - } MEMORY_RESOURCE_NOTIFICATION_TYPE; - - WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); - WINBASEAPI WINBOOL WINAPI QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,PBOOL ResourceState); - WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); - WINBASEAPI HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); - WINBASEAPI HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); - WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); - -#define DONT_RESOLVE_DLL_REFERENCES 0x1 -#define LOAD_LIBRARY_AS_DATAFILE 0x2 -#define LOAD_WITH_ALTERED_SEARCH_PATH 0x8 -#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x10 -#define LOAD_LINRARY_AS_IMAGE_RESOURCE 0x20 -#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40 - - WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule,LPCH lpFilename,DWORD nSize); - WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule,LPWCH lpFilename,DWORD nSize); - WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName); - WINBASEAPI HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName); - -#ifndef RC_INVOKED -#define GET_MODULE_HANDLE_EX_FLAG_PIN (0x1) -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT (0x2) -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x4) - - typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXA)(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); - typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXW)(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); - -#ifdef UNICODE -#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXW -#define GetModuleHandleEx GetModuleHandleExW -#else -#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXA -#define GetModuleHandleEx GetModuleHandleExA -#endif - - WINBASEAPI WINBOOL WINAPI GetModuleHandleExA(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); - WINBASEAPI WINBOOL WINAPI GetModuleHandleExW(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); -#endif - -#ifdef UNICODE -#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW -#define CreateProcess CreateProcessW -#define FatalAppExit FatalAppExitW -#define GetStartupInfo GetStartupInfoW -#define GetCommandLine GetCommandLineW -#define GetEnvironmentVariable GetEnvironmentVariableW -#define SetEnvironmentVariable SetEnvironmentVariableW -#define ExpandEnvironmentStrings ExpandEnvironmentStringsW -#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableW -#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableW -#define OutputDebugString OutputDebugStringW -#define FindResource FindResourceW -#define FindResourceEx FindResourceExW -#else -#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA -#define CreateProcess CreateProcessA -#define FatalAppExit FatalAppExitA -#define GetStartupInfo GetStartupInfoA -#define GetCommandLine GetCommandLineA -#define GetEnvironmentVariable GetEnvironmentVariableA -#define SetEnvironmentVariable SetEnvironmentVariableA -#define ExpandEnvironmentStrings ExpandEnvironmentStringsA -#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableA -#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableA -#define OutputDebugString OutputDebugStringA -#define FindResource FindResourceA -#define FindResourceEx FindResourceExA -#endif - - WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathA(LPCSTR ExeName); - WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathW(LPCWSTR ExeName); - WINBASEAPI WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINBASEAPI WINBOOL WINAPI CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameA(LPCSTR lpDnsFQHostname,ULONG ulFlags); - WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameW(LPCWSTR lpDnsFQHostname,ULONG ulFlags); - WINBASEAPI WINBOOL WINAPI SetProcessShutdownParameters(DWORD dwLevel,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI GetProcessShutdownParameters(LPDWORD lpdwLevel,LPDWORD lpdwFlags); - WINBASEAPI DWORD WINAPI GetProcessVersion(DWORD ProcessId); - WINBASEAPI VOID WINAPI FatalAppExitA(UINT uAction,LPCSTR lpMessageText); - WINBASEAPI VOID WINAPI FatalAppExitW(UINT uAction,LPCWSTR lpMessageText); - WINBASEAPI VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo); - WINBASEAPI VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo); - WINBASEAPI LPSTR WINAPI GetCommandLineA(VOID); - WINBASEAPI LPWSTR WINAPI GetCommandLineW(VOID); - WINBASEAPI DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize); - WINBASEAPI DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName,LPWSTR lpBuffer,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue); - WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpValue); - WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR lpSrc,LPSTR lpDst,DWORD nSize); - WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize); - WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pBuffer,DWORD nSize); - WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pBuffer,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pValue,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pValue,DWORD nSize); - WINBASEAPI VOID WINAPI OutputDebugStringA(LPCSTR lpOutputString); - WINBASEAPI VOID WINAPI OutputDebugStringW(LPCWSTR lpOutputString); - WINBASEAPI HRSRC WINAPI FindResourceA(HMODULE hModule,LPCSTR lpName,LPCSTR lpType); - WINBASEAPI HRSRC WINAPI FindResourceW(HMODULE hModule,LPCWSTR lpName,LPCWSTR lpType); - WINBASEAPI HRSRC WINAPI FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage); - WINBASEAPI HRSRC WINAPI FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage); - -#ifdef UNICODE -#define ENUMRESTYPEPROC ENUMRESTYPEPROCW -#define ENUMRESNAMEPROC ENUMRESNAMEPROCW -#define ENUMRESLANGPROC ENUMRESLANGPROCW -#define EnumResourceTypes EnumResourceTypesW -#define EnumResourceNames EnumResourceNamesW -#define EnumResourceLanguages EnumResourceLanguagesW -#define BeginUpdateResource BeginUpdateResourceW -#define UpdateResource UpdateResourceW -#define EndUpdateResource EndUpdateResourceW -#define GlobalAddAtom GlobalAddAtomW -#define GlobalFindAtom GlobalFindAtomW -#define GlobalGetAtomName GlobalGetAtomNameW -#define AddAtom AddAtomW -#define FindAtom FindAtomW -#define GetAtomName GetAtomNameW -#define GetProfileInt GetProfileIntW -#define GetProfileString GetProfileStringW -#define WriteProfileString WriteProfileStringW -#define GetProfileSection GetProfileSectionW -#define WriteProfileSection WriteProfileSectionW -#define GetPrivateProfileInt GetPrivateProfileIntW -#define GetPrivateProfileString GetPrivateProfileStringW -#define WritePrivateProfileString WritePrivateProfileStringW -#define GetPrivateProfileSection GetPrivateProfileSectionW -#define WritePrivateProfileSection WritePrivateProfileSectionW -#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW -#define GetPrivateProfileStruct GetPrivateProfileStructW -#define WritePrivateProfileStruct WritePrivateProfileStructW -#define GetDriveType GetDriveTypeW -#define GetSystemDirectory GetSystemDirectoryW -#define GetTempPath GetTempPathW -#define GetTempFileName GetTempFileNameW -#define GetWindowsDirectory GetWindowsDirectoryW -#define GetSystemWindowsDirectory GetSystemWindowsDirectoryW -#define AddLocalAlternateComputerName AddLocalAlternateComputerNameW -#else -#define ENUMRESTYPEPROC ENUMRESTYPEPROCA -#define ENUMRESNAMEPROC ENUMRESNAMEPROCA -#define ENUMRESLANGPROC ENUMRESLANGPROCA -#define EnumResourceTypes EnumResourceTypesA -#define EnumResourceNames EnumResourceNamesA -#define EnumResourceLanguages EnumResourceLanguagesA -#define BeginUpdateResource BeginUpdateResourceA -#define UpdateResource UpdateResourceA -#define EndUpdateResource EndUpdateResourceA -#define GlobalAddAtom GlobalAddAtomA -#define GlobalFindAtom GlobalFindAtomA -#define GlobalGetAtomName GlobalGetAtomNameA -#define AddAtom AddAtomA -#define FindAtom FindAtomA -#define GetAtomName GetAtomNameA -#define GetProfileInt GetProfileIntA -#define GetProfileString GetProfileStringA -#define WriteProfileString WriteProfileStringA -#define GetProfileSection GetProfileSectionA -#define WriteProfileSection WriteProfileSectionA -#define GetPrivateProfileInt GetPrivateProfileIntA -#define GetPrivateProfileString GetPrivateProfileStringA -#define WritePrivateProfileString WritePrivateProfileStringA -#define GetPrivateProfileSection GetPrivateProfileSectionA -#define WritePrivateProfileSection WritePrivateProfileSectionA -#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA -#define GetPrivateProfileStruct GetPrivateProfileStructA -#define WritePrivateProfileStruct WritePrivateProfileStructA -#define GetDriveType GetDriveTypeA -#define GetSystemDirectory GetSystemDirectoryA -#define GetTempPath GetTempPathA -#define GetTempFileName GetTempFileNameA -#define GetWindowsDirectory GetWindowsDirectoryA -#define GetSystemWindowsDirectory GetSystemWindowsDirectoryA -#define AddLocalAlternateComputerName AddLocalAlternateComputerNameA -#endif - - typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCA)(HMODULE hModule,LPSTR lpType,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCW)(HMODULE hModule,LPWSTR lpType,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCA)(HMODULE hModule,LPCSTR lpType,LPSTR lpName,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCW)(HMODULE hModule,LPCWSTR lpType,LPWSTR lpName,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESLANGPROCA)(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESLANGPROCW)(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LONG_PTR lParam); - - WINBASEAPI WINBOOL WINAPI EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceNamesA(HMODULE hModule,LPCSTR lpType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceNamesW(HMODULE hModule,LPCWSTR lpType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI HANDLE WINAPI BeginUpdateResourceA(LPCSTR pFileName,WINBOOL bDeleteExistingResources); - WINBASEAPI HANDLE WINAPI BeginUpdateResourceW(LPCWSTR pFileName,WINBOOL bDeleteExistingResources); - WINBASEAPI WINBOOL WINAPI UpdateResourceA(HANDLE hUpdate,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); - WINBASEAPI WINBOOL WINAPI UpdateResourceW(HANDLE hUpdate,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); - WINBASEAPI WINBOOL WINAPI EndUpdateResourceA(HANDLE hUpdate,WINBOOL fDiscard); - WINBASEAPI WINBOOL WINAPI EndUpdateResourceW(HANDLE hUpdate,WINBOOL fDiscard); - WINBASEAPI ATOM WINAPI GlobalAddAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI GlobalAddAtomW(LPCWSTR lpString); - WINBASEAPI ATOM WINAPI GlobalFindAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI GlobalFindAtomW(LPCWSTR lpString); - WINBASEAPI UINT WINAPI GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); - WINBASEAPI ATOM WINAPI AddAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI AddAtomW(LPCWSTR lpString); - WINBASEAPI ATOM WINAPI FindAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI FindAtomW(LPCWSTR lpString); - WINBASEAPI UINT WINAPI GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GetProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault); - WINBASEAPI UINT WINAPI GetProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault); - WINBASEAPI DWORD WINAPI GetProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize); - WINBASEAPI DWORD WINAPI GetProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize); - WINBASEAPI WINBOOL WINAPI WriteProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString); - WINBASEAPI WINBOOL WINAPI WriteProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString); - WINBASEAPI DWORD WINAPI GetProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize); - WINBASEAPI DWORD WINAPI GetProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize); - WINBASEAPI WINBOOL WINAPI WriteProfileSectionA(LPCSTR lpAppName,LPCSTR lpString); - WINBASEAPI WINBOOL WINAPI WriteProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString); - WINBASEAPI UINT WINAPI GetPrivateProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault,LPCSTR lpFileName); - WINBASEAPI UINT WINAPI GetPrivateProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString,LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionA(LPCSTR lpAppName,LPCSTR lpString,LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); - WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); - WINBASEAPI UINT WINAPI GetDriveTypeA(LPCSTR lpRootPathName); - WINBASEAPI UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName); - WINBASEAPI UINT WINAPI GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemDirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI DWORD WINAPI GetTempPathA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetTempPathW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI UINT WINAPI GetTempFileNameA(LPCSTR lpPathName,LPCSTR lpPrefixString,UINT uUnique,LPSTR lpTempFileName); - WINBASEAPI UINT WINAPI GetTempFileNameW(LPCWSTR lpPathName,LPCWSTR lpPrefixString,UINT uUnique,LPWSTR lpTempFileName); - WINBASEAPI UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); - -#ifndef RC_INVOKED -#ifdef UNICODE -#define GetSystemWow64Directory GetSystemWow64DirectoryW -#else -#define GetSystemWow64Directory GetSystemWow64DirectoryA -#endif - - WINBASEAPI UINT WINAPI GetSystemWow64DirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWow64DirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection); - WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); - WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OlValue); - - typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_A)(LPSTR lpBuffer,UINT uSize); - typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_W)(LPWSTR lpBuffer,UINT uSize); - -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A "GetSystemWow64DirectoryA" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W L"GetSystemWow64DirectoryA" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T TEXT("GetSystemWow64DirectoryA") -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A "GetSystemWow64DirectoryW" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W L"GetSystemWow64DirectoryW" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T TEXT("GetSystemWow64DirectoryW") - -#ifdef UNICODE -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T -#else -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T -#endif -#endif - -#ifdef UNICODE -#define SetCurrentDirectory SetCurrentDirectoryW -#define GetCurrentDirectory GetCurrentDirectoryW -#define SetDllDirectory SetDllDirectoryW -#define GetDllDirectory GetDllDirectoryW -#define GetDiskFreeSpace GetDiskFreeSpaceW -#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW -#define CreateDirectory CreateDirectoryW -#define CreateDirectoryEx CreateDirectoryExW -#define RemoveDirectory RemoveDirectoryW -#define GetFullPathName GetFullPathNameW -#define DefineDosDevice DefineDosDeviceW -#define QueryDosDevice QueryDosDeviceW -#define CreateFile CreateFileW -#define SetFileAttributes SetFileAttributesW -#define GetFileAttributes GetFileAttributesW -#else -#define SetCurrentDirectory SetCurrentDirectoryA -#define GetCurrentDirectory GetCurrentDirectoryA -#define SetDllDirectory SetDllDirectoryA -#define GetDllDirectory GetDllDirectoryA -#define GetDiskFreeSpace GetDiskFreeSpaceA -#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA -#define CreateDirectory CreateDirectoryA -#define CreateDirectoryEx CreateDirectoryExA -#define RemoveDirectory RemoveDirectoryA -#define GetFullPathName GetFullPathNameA -#define DefineDosDevice DefineDosDeviceA -#define QueryDosDevice QueryDosDeviceA -#define CreateFile CreateFileA -#define SetFileAttributes SetFileAttributesA -#define GetFileAttributes GetFileAttributesA -#endif - - WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetCurrentDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetCurrentDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI SetDllDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetDllDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetDllDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryExA(LPCSTR lpTemplateDirectory,LPCSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryExW(LPCWSTR lpTemplateDirectory,LPCWSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI RemoveDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI RemoveDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); - WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); - -#define DDD_RAW_TARGET_PATH 0x1 -#define DDD_REMOVE_DEFINITION 0x2 -#define DDD_EXACT_MATCH_ON_REMOVE 0x4 -#define DDD_NO_BROADCAST_SYSTEM 0x8 -#define DDD_LUID_BROADCAST_DRIVE 0x10 - - WINBASEAPI WINBOOL WINAPI DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath); - WINBASEAPI WINBOOL WINAPI DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath); - WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax); - WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax); - -#define EXPAND_LOCAL_DRIVES - - WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); - WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); - WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE hOriginalFile,DWORD dwDesiredAccess,DWORD dwShareMode,DWORD dwFlagsAndAttributes); - WINBASEAPI WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes); - WINBASEAPI WINBOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes); - WINBASEAPI DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName); - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard,GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - -#ifdef UNICODE -#define GetFileAttributesEx GetFileAttributesExW -#define GetCompressedFileSize GetCompressedFileSizeW -#define DeleteFile DeleteFileW -#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3W -#else -#define GetFileAttributesEx GetFileAttributesExA -#define GetCompressedFileSize GetCompressedFileSizeA -#define DeleteFile DeleteFileA -#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3A -#endif - - WINBASEAPI WINBOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); - WINBASEAPI WINBOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); - WINBASEAPI DWORD WINAPI GetCompressedFileSizeA(LPCSTR lpFileName,LPDWORD lpFileSizeHigh); - WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName,LPDWORD lpFileSizeHigh); - WINBASEAPI WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI DeleteFileW(LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); - WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard,FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch,FindExSearchLimitToDirectories,FindExSearchLimitToDevices,FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - -#define FIND_FIRST_EX_CASE_SENSITIVE 0x1 - -#ifdef UNICODE -#define FindFirstFileEx FindFirstFileExW -#define FindFirstFile FindFirstFileW -#define FindNextFile FindNextFileW -#define SearchPath SearchPathW -#define CopyFile CopyFileW -#define CopyFileEx CopyFileExW -#define MoveFile MoveFileW -#define MoveFileEx MoveFileExW -#define MoveFileWithProgress MoveFileWithProgressW -#define ReplaceFile ReplaceFileW -#define CreateHardLink CreateHardLinkW -#define CreateNamedPipe CreateNamedPipeW -#define GetNamedPipeHandleState GetNamedPipeHandleStateW -#define CallNamedPipe CallNamedPipeW -#define WaitNamedPipe WaitNamedPipeW -#define SetVolumeLabel SetVolumeLabelW -#define GetVolumeInformation GetVolumeInformationW -#define ClearEventLog ClearEventLogW -#define BackupEventLog BackupEventLogW -#define OpenEventLog OpenEventLogW -#define RegisterEventSource RegisterEventSourceW -#define OpenBackupEventLog OpenBackupEventLogW -#define ReadEventLog ReadEventLogW -#define ReportEvent ReportEventW -#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW -#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmW -#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmW -#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleW -#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW -#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW -#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW -#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW -#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW -#define SetFileSecurity SetFileSecurityW -#define GetFileSecurity GetFileSecurityW -#define FindFirstChangeNotification FindFirstChangeNotificationW -#define IsBadStringPtr IsBadStringPtrW -#define LookupAccountSid LookupAccountSidW -#define LookupAccountName LookupAccountNameW -#define LookupPrivilegeValue LookupPrivilegeValueW -#define LookupPrivilegeName LookupPrivilegeNameW -#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW -#define BuildCommDCB BuildCommDCBW -#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW -#define CommConfigDialog CommConfigDialogW -#define GetDefaultCommConfig GetDefaultCommConfigW -#define SetDefaultCommConfig SetDefaultCommConfigW -#define GetComputerName GetComputerNameW -#define SetComputerName SetComputerNameW -#define GetComputerNameEx GetComputerNameExW -#define SetComputerNameEx SetComputerNameExW -#define DnsHostnameToComputerName DnsHostnameToComputerNameW -#define GetUserName GetUserNameW -#else -#define FindFirstFileEx FindFirstFileExA -#define FindFirstFile FindFirstFileA -#define FindNextFile FindNextFileA -#define SearchPath SearchPathA -#define CopyFile CopyFileA -#define CopyFileEx CopyFileExA -#define MoveFile MoveFileA -#define MoveFileEx MoveFileExA -#define MoveFileWithProgress MoveFileWithProgressA -#define ReplaceFile ReplaceFileA -#define CreateHardLink CreateHardLinkA -#define CreateNamedPipe CreateNamedPipeA -#define GetNamedPipeHandleState GetNamedPipeHandleStateA -#define CallNamedPipe CallNamedPipeA -#define WaitNamedPipe WaitNamedPipeA -#define SetVolumeLabel SetVolumeLabelA -#define GetVolumeInformation GetVolumeInformationA -#define ClearEventLog ClearEventLogA -#define BackupEventLog BackupEventLogA -#define OpenEventLog OpenEventLogA -#define RegisterEventSource RegisterEventSourceA -#define OpenBackupEventLog OpenBackupEventLogA -#define ReadEventLog ReadEventLogA -#define ReportEvent ReportEventA -#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA -#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmA -#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmA -#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleA -#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA -#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA -#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA -#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA -#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA -#define SetFileSecurity SetFileSecurityA -#define GetFileSecurity GetFileSecurityA -#define FindFirstChangeNotification FindFirstChangeNotificationA -#define IsBadStringPtr IsBadStringPtrA -#define LookupAccountSid LookupAccountSidA -#define LookupAccountName LookupAccountNameA -#define LookupPrivilegeValue LookupPrivilegeValueA -#define LookupPrivilegeName LookupPrivilegeNameA -#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA -#define BuildCommDCB BuildCommDCBA -#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA -#define CommConfigDialog CommConfigDialogA -#define GetDefaultCommConfig GetDefaultCommConfigA -#define SetDefaultCommConfig SetDefaultCommConfigA -#define GetComputerName GetComputerNameA -#define SetComputerName SetComputerNameA -#define GetComputerNameEx GetComputerNameExA -#define SetComputerNameEx SetComputerNameExA -#define DnsHostnameToComputerName DnsHostnameToComputerNameA -#define GetUserName GetUserNameA -#endif - - WINBASEAPI HANDLE WINAPI FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); - WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); - WINBASEAPI HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData); - WINBASEAPI HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData); - WINBASEAPI WINBOOL WINAPI FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData); - WINBASEAPI WINBOOL WINAPI FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData); - WINBASEAPI DWORD WINAPI SearchPathA(LPCSTR lpPath,LPCSTR lpFileName,LPCSTR lpExtension,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); - WINBASEAPI DWORD WINAPI SearchPathW(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); - WINBASEAPI WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,WINBOOL bFailIfExists); - WINBASEAPI WINBOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,WINBOOL bFailIfExists); - - typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData); - - WINBASEAPI WINBOOL WINAPI CopyFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); - WINBASEAPI WINBOOL WINAPI CopyFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); - WINBASEAPI WINBOOL WINAPI MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName); - WINBASEAPI WINBOOL WINAPI MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName); - WINBASEAPI WINBOOL WINAPI MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileWithProgressA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileWithProgressW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); - -#define MOVEFILE_REPLACE_EXISTING 0x1 -#define MOVEFILE_COPY_ALLOWED 0x2 -#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 -#define MOVEFILE_WRITE_THROUGH 0x8 -#define MOVEFILE_CREATE_HARDLINK 0x10 -#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 - - WINBASEAPI WINBOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,LPCSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,LPCWSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI CreateHardLinkA(LPCSTR lpFileName,LPCSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName,LPCWSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - - typedef enum _STREAM_INFO_LEVELS { - FindStreamInfoStandard,FindStreamInfoMaxInfoLevel - } STREAM_INFO_LEVELS; - - typedef struct _WIN32_FIND_STREAM_DATA { - LARGE_INTEGER StreamSize; - WCHAR cStreamName[MAX_PATH + 36]; - } WIN32_FIND_STREAM_DATA,*PWIN32_FIND_STREAM_DATA; - - HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,STREAM_INFO_LEVELS InfoLevel,LPVOID lpFindStreamData,DWORD dwFlags); - WINBOOL WINAPI FindNextStreamW(HANDLE hFindStream,LPVOID lpFindStreamData); - WINBASEAPI HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPSTR lpUserName,DWORD nMaxUserNameSize); - WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateW(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPWSTR lpUserName,DWORD nMaxUserNameSize); - WINBASEAPI WINBOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI SetVolumeLabelA(LPCSTR lpRootPathName,LPCSTR lpVolumeName); - WINBASEAPI WINBOOL WINAPI SetVolumeLabelW(LPCWSTR lpRootPathName,LPCWSTR lpVolumeName); - WINBASEAPI VOID WINAPI SetFileApisToOEM(VOID); - WINBASEAPI VOID WINAPI SetFileApisToANSI(VOID); - WINBASEAPI WINBOOL WINAPI AreFileApisANSI(VOID); - WINBASEAPI WINBOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName,LPSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); - WINBASEAPI WINBOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName,LPWSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPWSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); - WINBASEAPI WINBOOL WINAPI CancelIo(HANDLE hFile); - WINADVAPI WINBOOL WINAPI ClearEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI ClearEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI BackupEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI BackupEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI CloseEventLog(HANDLE hEventLog); - WINADVAPI WINBOOL WINAPI DeregisterEventSource(HANDLE hEventLog); - WINADVAPI WINBOOL WINAPI NotifyChangeEventLog(HANDLE hEventLog,HANDLE hEvent); - WINADVAPI WINBOOL WINAPI GetNumberOfEventLogRecords(HANDLE hEventLog,PDWORD NumberOfRecords); - WINADVAPI WINBOOL WINAPI GetOldestEventLogRecord(HANDLE hEventLog,PDWORD OldestRecord); - WINADVAPI HANDLE WINAPI OpenEventLogA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); - WINADVAPI HANDLE WINAPI OpenEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); - WINADVAPI HANDLE WINAPI RegisterEventSourceA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); - WINADVAPI HANDLE WINAPI RegisterEventSourceW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); - WINADVAPI HANDLE WINAPI OpenBackupEventLogA(LPCSTR lpUNCServerName,LPCSTR lpFileName); - WINADVAPI HANDLE WINAPI OpenBackupEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpFileName); - WINADVAPI WINBOOL WINAPI ReadEventLogA(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); - WINADVAPI WINBOOL WINAPI ReadEventLogW(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); - WINADVAPI WINBOOL WINAPI ReportEventA(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCSTR *lpStrings,LPVOID lpRawData); - WINADVAPI WINBOOL WINAPI ReportEventW(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCWSTR *lpStrings,LPVOID lpRawData); - -#define EVENTLOG_FULL_INFO 0 - - typedef struct _EVENTLOG_FULL_INFORMATION { - DWORD dwFull; - } EVENTLOG_FULL_INFORMATION,*LPEVENTLOG_FULL_INFORMATION; - - WINADVAPI WINBOOL WINAPI GetEventLogInformation(HANDLE hEventLog,DWORD dwInfoLevel,LPVOID lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); - WINADVAPI WINBOOL WINAPI DuplicateToken(HANDLE ExistingTokenHandle,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,PHANDLE DuplicateTokenHandle); - WINADVAPI WINBOOL WINAPI GetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI ImpersonateNamedPipeClient(HANDLE hNamedPipe); - WINADVAPI WINBOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); - WINADVAPI WINBOOL WINAPI RevertToSelf(VOID); - WINADVAPI WINBOOL WINAPI SetThreadToken (PHANDLE Thread,HANDLE Token); - WINADVAPI WINBOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); - WINADVAPI WINBOOL WINAPI AccessCheckByType(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultList(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccessList,LPDWORD AccessStatusList); - WINADVAPI WINBOOL WINAPI OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI OpenThreadToken(HANDLE ThreadHandle,DWORD DesiredAccess,WINBOOL OpenAsSelf,PHANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI GetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI SetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength); - WINADVAPI WINBOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle,WINBOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle,WINBOOL ResetToDefault,PTOKEN_GROUPS NewState,DWORD BufferLength,PTOKEN_GROUPS PreviousState,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI PrivilegeCheck(HANDLE ClientToken,PPRIVILEGE_SET RequiredPrivileges,LPBOOL pfResult); - WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR SubsystemName,LPCSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR SubsystemName,LPCWSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI IsWellKnownSid(PSID pSid,WELL_KNOWN_SID_TYPE WellKnownSidType); - WINADVAPI WINBOOL WINAPI CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType,PSID DomainSid,PSID pSid,DWORD *cbSid); - WINADVAPI WINBOOL WINAPI EqualDomainSid(PSID pSid1,PSID pSid2,WINBOOL *pfEqual); - WINADVAPI WINBOOL WINAPI GetWindowsAccountDomainSid(PSID pSid,PSID pDomainSid,DWORD *cbDomainSid); - WINADVAPI WINBOOL WINAPI IsValidSid(PSID pSid); - WINADVAPI WINBOOL WINAPI EqualSid(PSID pSid1,PSID pSid2); - WINADVAPI WINBOOL WINAPI EqualPrefixSid(PSID pSid1,PSID pSid2); - WINADVAPI DWORD WINAPI GetSidLengthRequired (UCHAR nSubAuthorityCount); - WINADVAPI WINBOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD nSubAuthority0,DWORD nSubAuthority1,DWORD nSubAuthority2,DWORD nSubAuthority3,DWORD nSubAuthority4,DWORD nSubAuthority5,DWORD nSubAuthority6,DWORD nSubAuthority7,PSID *pSid); - WINADVAPI PVOID WINAPI FreeSid(PSID pSid); - WINADVAPI WINBOOL WINAPI InitializeSid(PSID Sid,PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount); - WINADVAPI PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); - WINADVAPI PDWORD WINAPI GetSidSubAuthority(PSID pSid,DWORD nSubAuthority); - WINADVAPI PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); - WINADVAPI DWORD WINAPI GetLengthSid(PSID pSid); - WINADVAPI WINBOOL WINAPI CopySid(DWORD nDestinationSidLength,PSID pDestinationSid,PSID pSourceSid); - WINADVAPI WINBOOL WINAPI AreAllAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); - WINADVAPI WINBOOL WINAPI AreAnyAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); - WINADVAPI VOID WINAPI MapGenericMask(PDWORD AccessMask,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI IsValidAcl(PACL pAcl); - WINADVAPI WINBOOL WINAPI InitializeAcl(PACL pAcl,DWORD nAclLength,DWORD dwAclRevision); - WINADVAPI WINBOOL WINAPI GetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); - WINADVAPI WINBOOL WINAPI SetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); - WINADVAPI WINBOOL WINAPI AddAce(PACL pAcl,DWORD dwAceRevision,DWORD dwStartingAceIndex,LPVOID pAceList,DWORD nAceListLength); - WINADVAPI WINBOOL WINAPI DeleteAce(PACL pAcl,DWORD dwAceIndex); - WINADVAPI WINBOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce); - WINADVAPI WINBOOL WINAPI AddAccessAllowedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessAllowedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAuditAccessAce(PACL pAcl,DWORD dwAceRevision,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI AddAuditAccessAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI AddAccessAllowedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAuditAccessObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI FindFirstFreeAce(PACL pAcl,LPVOID *pAce); - WINADVAPI WINBOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD dwRevision); - WINADVAPI WINBOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSECURITY_DESCRIPTOR_CONTROL pControl,LPDWORD lpdwRevision); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bDaclPresent,PACL pDacl,WINBOOL bDaclDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL *pDacl,LPBOOL lpbDaclDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bSaclPresent,PACL pSacl,WINBOOL bSaclDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbSaclPresent,PACL *pSacl,LPBOOL lpbSaclDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pOwner,WINBOOL bOwnerDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pOwner,LPBOOL lpbOwnerDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pGroup,WINBOOL bGroupDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pGroup,LPBOOL lpbGroupDefaulted); - WINADVAPI DWORD WINAPI SetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); - WINADVAPI DWORD WINAPI GetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,WINBOOL IsDirectoryObject,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI ConvertToAutoInheritPrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,PSECURITY_DESCRIPTOR *NewSecurityDescriptor,GUID *ObjectType,BOOLEAN IsDirectoryObject,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID *ObjectType,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID **ObjectTypes,ULONG GuidCount,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurity (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,PGENERIC_MAPPING GenericMapping,HANDLE Token); - WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurityEx (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,ULONG AutoInheritFlags,PGENERIC_MAPPING GenericMapping,HANDLE Token); - WINADVAPI WINBOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR ObjectDescriptor,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ResultantDescriptor,DWORD DescriptorLength,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor); - WINADVAPI WINBOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferLength); - WINADVAPI WINBOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,LPDWORD lpdwAbsoluteSecurityDescriptorSize,PACL pDacl,LPDWORD lpdwDaclSize,PACL pSacl,LPDWORD lpdwSaclSize,PSID pOwner,LPDWORD lpdwOwnerSize,PSID pPrimaryGroup,LPDWORD lpdwPrimaryGroupSize); - WINADVAPI WINBOOL WINAPI MakeAbsoluteSD2(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferSize); - WINADVAPI WINBOOL WINAPI SetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI SetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI GetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI GetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI SetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR SecurityDescriptor); - WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); - WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); - WINBASEAPI WINBOOL WINAPI FindNextChangeNotification(HANDLE hChangeHandle); - WINBASEAPI WINBOOL WINAPI FindCloseChangeNotification(HANDLE hChangeHandle); - WINBASEAPI WINBOOL WINAPI ReadDirectoryChangesW(HANDLE hDirectory,LPVOID lpBuffer,DWORD nBufferLength,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI VirtualLock(LPVOID lpAddress,SIZE_T dwSize); - WINBASEAPI WINBOOL WINAPI VirtualUnlock(LPVOID lpAddress,SIZE_T dwSize); - WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap,LPVOID lpBaseAddress); - WINBASEAPI WINBOOL WINAPI SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass); - WINBASEAPI DWORD WINAPI GetPriorityClass(HANDLE hProcess); - WINBASEAPI WINBOOL WINAPI IsBadReadPtr(CONST VOID *lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadWritePtr(LPVOID lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadHugeReadPtr(CONST VOID *lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadHugeWritePtr(LPVOID lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadCodePtr(FARPROC lpfn); - WINBASEAPI WINBOOL WINAPI IsBadStringPtrA(LPCSTR lpsz,UINT_PTR ucchMax); - WINBASEAPI WINBOOL WINAPI IsBadStringPtrW(LPCWSTR lpsz,UINT_PTR ucchMax); - WINADVAPI WINBOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName,PSID Sid,LPSTR Name,LPDWORD cchName,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName,PSID Sid,LPWSTR Name,LPDWORD cchName,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountNameA(LPCSTR lpSystemName,LPCSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName,LPCWSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName,LPCSTR lpName,PLUID lpLuid); - WINADVAPI WINBOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName,LPCWSTR lpName,PLUID lpLuid); - WINADVAPI WINBOOL WINAPI LookupPrivilegeNameA(LPCSTR lpSystemName,PLUID lpLuid,LPSTR lpName,LPDWORD cchName); - WINADVAPI WINBOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName,PLUID lpLuid,LPWSTR lpName,LPDWORD cchName); - WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,LPCSTR lpName,LPSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); - WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName,LPCWSTR lpName,LPWSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); - WINADVAPI WINBOOL WINAPI AllocateLocallyUniqueId(PLUID Luid); - WINBASEAPI WINBOOL WINAPI BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI BuildCommDCBW(LPCWSTR lpDef,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI CommConfigDialogA(LPCSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); - WINBASEAPI WINBOOL WINAPI CommConfigDialogW(LPCWSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); - WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); - WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); - -#define MAX_COMPUTERNAME_LENGTH 15 - - WINBASEAPI WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI GetComputerNameW(LPWSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI SetComputerNameA(LPCSTR lpComputerName); - WINBASEAPI WINBOOL WINAPI SetComputerNameW(LPCWSTR lpComputerName); - - typedef enum _COMPUTER_NAME_FORMAT { - ComputerNameNetBIOS,ComputerNameDnsHostname,ComputerNameDnsDomain,ComputerNameDnsFullyQualified,ComputerNamePhysicalNetBIOS,ComputerNamePhysicalDnsHostname,ComputerNamePhysicalDnsDomain,ComputerNamePhysicalDnsFullyQualified,ComputerNameMax - } COMPUTER_NAME_FORMAT; - - WINBASEAPI WINBOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPWSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPCSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPCWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname,LPSTR ComputerName,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname,LPWSTR ComputerName,LPDWORD nSize); - WINADVAPI WINBOOL WINAPI GetUserNameA(LPSTR lpBuffer,LPDWORD pcbBuffer); - WINADVAPI WINBOOL WINAPI GetUserNameW(LPWSTR lpBuffer,LPDWORD pcbBuffer); - -#define LOGON32_LOGON_INTERACTIVE 2 -#define LOGON32_LOGON_NETWORK 3 -#define LOGON32_LOGON_BATCH 4 -#define LOGON32_LOGON_SERVICE 5 -#define LOGON32_LOGON_UNLOCK 7 -#define LOGON32_LOGON_NETWORK_CLEARTEXT 8 -#define LOGON32_LOGON_NEW_CREDENTIALS 9 - -#define LOGON32_PROVIDER_DEFAULT 0 -#define LOGON32_PROVIDER_WINNT35 1 -#define LOGON32_PROVIDER_WINNT40 2 -#define LOGON32_PROVIDER_WINNT50 3 - -#ifdef UNICODE -#define LogonUser LogonUserW -#define LogonUserEx LogonUserExW -#define CreateProcessAsUser CreateProcessAsUserW -#else -#define LogonUser LogonUserA -#define LogonUserEx LogonUserExA -#define CreateProcessAsUser CreateProcessAsUserA -#endif - - WINADVAPI WINBOOL WINAPI LogonUserA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); - WINADVAPI WINBOOL WINAPI LogonUserW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); - WINADVAPI WINBOOL WINAPI LogonUserExA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); - WINADVAPI WINBOOL WINAPI LogonUserExW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); - WINADVAPI WINBOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); - WINADVAPI WINBOOL WINAPI CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - -#define LOGON_WITH_PROFILE 0x1 -#define LOGON_NETCREDENTIALS_ONLY 0x2 -#define LOGON_ZERO_PASSWORD_BUFFER 0x80000000 - - WINADVAPI WINBOOL WINAPI CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI ImpersonateAnonymousToken(HANDLE ThreadHandle); - WINADVAPI WINBOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpTokenAttributes,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,TOKEN_TYPE TokenType,PHANDLE phNewToken); - WINADVAPI WINBOOL WINAPI CreateRestrictedToken(HANDLE ExistingTokenHandle,DWORD Flags,DWORD DisableSidCount,PSID_AND_ATTRIBUTES SidsToDisable,DWORD DeletePrivilegeCount,PLUID_AND_ATTRIBUTES PrivilegesToDelete,DWORD RestrictedSidCount,PSID_AND_ATTRIBUTES SidsToRestrict,PHANDLE NewTokenHandle); - WINADVAPI WINBOOL WINAPI IsTokenRestricted(HANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI IsTokenUntrusted(HANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI CheckTokenMembership(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); - - typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; - - WINBASEAPI WINBOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject,HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); - WINBASEAPI HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); - WINBASEAPI WINBOOL WINAPI UnregisterWait(HANDLE WaitHandle); - WINBASEAPI WINBOOL WINAPI UnregisterWaitEx(HANDLE WaitHandle,HANDLE CompletionEvent); - WINBASEAPI WINBOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,PVOID Context,ULONG Flags); - WINBASEAPI WINBOOL WINAPI BindIoCompletionCallback(HANDLE FileHandle,LPOVERLAPPED_COMPLETION_ROUTINE Function,ULONG Flags); - WINBASEAPI HANDLE WINAPI CreateTimerQueue(VOID); - WINBASEAPI WINBOOL WINAPI CreateTimerQueueTimer(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); - WINBASEAPI WINBOOL WINAPI ChangeTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,ULONG DueTime,ULONG Period); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue,HANDLE CompletionEvent); - WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,WINBOOL PreferIo); - WINBASEAPI WINBOOL WINAPI CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueue(HANDLE TimerQueue); - -#define HW_PROFILE_GUIDLEN 39 -#define MAX_PROFILE_LEN 80 - -#define DOCKINFO_UNDOCKED (0x1) -#define DOCKINFO_DOCKED (0x2) -#define DOCKINFO_USER_SUPPLIED (0x4) -#define DOCKINFO_USER_UNDOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED) -#define DOCKINFO_USER_DOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED) - - typedef struct tagHW_PROFILE_INFOA { - DWORD dwDockInfo; - CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; - CHAR szHwProfileName[MAX_PROFILE_LEN]; - } HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA; - - typedef struct tagHW_PROFILE_INFOW { - DWORD dwDockInfo; - WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; - WCHAR szHwProfileName[MAX_PROFILE_LEN]; - } HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW; - -#ifdef UNICODE - typedef HW_PROFILE_INFOW HW_PROFILE_INFO; - typedef LPHW_PROFILE_INFOW LPHW_PROFILE_INFO; -#else - typedef HW_PROFILE_INFOA HW_PROFILE_INFO; - typedef LPHW_PROFILE_INFOA LPHW_PROFILE_INFO; -#endif - -#ifdef UNICODE -#define GetCurrentHwProfile GetCurrentHwProfileW -#define GetVersionEx GetVersionExW -#define VerifyVersionInfo VerifyVersionInfoW -#else -#define GetCurrentHwProfile GetCurrentHwProfileA -#define GetVersionEx GetVersionExA -#define VerifyVersionInfo VerifyVersionInfoA -#endif - - WINADVAPI WINBOOL WINAPI GetCurrentHwProfileA (LPHW_PROFILE_INFOA lpHwProfileInfo); - WINADVAPI WINBOOL WINAPI GetCurrentHwProfileW (LPHW_PROFILE_INFOW lpHwProfileInfo); - WINBASEAPI WINBOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); - WINBASEAPI WINBOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); - WINBASEAPI WINBOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); - WINBASEAPI WINBOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); - WINBASEAPI WINBOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); - WINBASEAPI WINBOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); - -#include - -#define TC_NORMAL 0 -#define TC_HARDERR 1 -#define TC_GP_TRAP 2 -#define TC_SIGNAL 3 - -#define AC_LINE_OFFLINE 0x0 -#define AC_LINE_ONLINE 0x1 -#define AC_LINE_BACKUP_POWER 0x2 -#define AC_LINE_UNKNOWN 0xff - -#define BATTERY_FLAG_HIGH 0x1 -#define BATTERY_FLAG_LOW 0x2 -#define BATTERY_FLAG_CRITICAL 0x4 -#define BATTERY_FLAG_CHARGING 0x8 -#define BATTERY_FLAG_NO_BATTERY 0x80 -#define BATTERY_FLAG_UNKNOWN 0xff - -#define BATTERY_PERCENTAGE_UNKNOWN 0xff - -#define BATTERY_LIFE_UNKNOWN 0xffffffff - - typedef struct _SYSTEM_POWER_STATUS { - BYTE ACLineStatus; - BYTE BatteryFlag; - BYTE BatteryLifePercent; - BYTE Reserved1; - DWORD BatteryLifeTime; - DWORD BatteryFullLifeTime; - } SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS; - -#ifdef UNICODE -#define CreateJobObject CreateJobObjectW -#define OpenJobObject OpenJobObjectW -#define FindFirstVolume FindFirstVolumeW -#define FindNextVolume FindNextVolumeW -#define FindFirstVolumeMountPoint FindFirstVolumeMountPointW -#define FindNextVolumeMountPoint FindNextVolumeMountPointW -#define SetVolumeMountPoint SetVolumeMountPointW -#define DeleteVolumeMountPoint DeleteVolumeMountPointW -#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointW -#define GetVolumePathName GetVolumePathNameW -#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameW -#else -#define CreateJobObject CreateJobObjectA -#define OpenJobObject OpenJobObjectA -#define FindFirstVolume FindFirstVolumeA -#define FindNextVolume FindNextVolumeA -#define FindFirstVolumeMountPoint FindFirstVolumeMountPointA -#define FindNextVolumeMountPoint FindNextVolumeMountPointA -#define SetVolumeMountPoint SetVolumeMountPointA -#define DeleteVolumeMountPoint DeleteVolumeMountPointA -#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointA -#define GetVolumePathName GetVolumePathNameA -#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameA -#endif - - WINBOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus); - WINBOOL WINAPI SetSystemPowerState(WINBOOL fSuspend,WINBOOL fForce); - WINBASEAPI WINBOOL WINAPI AllocateUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI FreeUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI MapUserPhysicalPages(PVOID VirtualAddress,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI MapUserPhysicalPagesScatter(PVOID *VirtualAddresses,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI HANDLE WINAPI CreateJobObjectA(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenJobObjectA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenJobObjectW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI WINBOOL WINAPI AssignProcessToJobObject(HANDLE hJob,HANDLE hProcess); - WINBASEAPI WINBOOL WINAPI TerminateJobObject(HANDLE hJob,UINT uExitCode); - WINBASEAPI WINBOOL WINAPI QueryInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength,LPDWORD lpReturnLength); - WINBASEAPI WINBOOL WINAPI SetInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength); - WINBASEAPI WINBOOL WINAPI IsProcessInJob(HANDLE ProcessHandle,HANDLE JobHandle,PBOOL Result); - WINBASEAPI WINBOOL WINAPI CreateJobSet(ULONG NumJob,PJOB_SET_ARRAY UserJobSet,ULONG Flags); - WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); - WINBASEAPI ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handle); - WINBASEAPI PVOID WINAPI AddVectoredContinueHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); - WINBASEAPI ULONG WINAPI RemoveVectoredContinueHandler(PVOID Handle); - WINBASEAPI HANDLE WINAPI FindFirstVolumeA(LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI HANDLE WINAPI FindFirstVolumeW(LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeA(HANDLE hFindVolume,LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeW(HANDLE hFindVolume,LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindVolumeClose(HANDLE hFindVolume); - WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR lpszRootPathName,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR lpszRootPathName,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointA(HANDLE hFindVolumeMountPoint,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI SetVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPCSTR lpszVolumeName); - WINBASEAPI WINBOOL WINAPI SetVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPCWSTR lpszVolumeName); - WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointW(LPCWSTR lpszVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNameA(LPCSTR lpszFileName,LPSTR lpszVolumePathName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNameW(LPCWSTR lpszFileName,LPWSTR lpszVolumePathName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName,LPCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR lpszVolumeName,LPWCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); - -#define ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID 0x1 -#define ACTCTX_FLAG_LANGID_VALID 0x2 -#define ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 0x4 -#define ACTCTX_FLAG_RESOURCE_NAME_VALID 0x8 -#define ACTCTX_FLAG_SET_PROCESS_DEFAULT 0x10 -#define ACTCTX_FLAG_APPLICATION_NAME_VALID 0x20 -#define ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF 0x40 -#define ACTCTX_FLAG_HMODULE_VALID 0x80 - - typedef struct tagACTCTXA { - ULONG cbSize; - DWORD dwFlags; - LPCSTR lpSource; - USHORT wProcessorArchitecture; - LANGID wLangId; - LPCSTR lpAssemblyDirectory; - LPCSTR lpResourceName; - LPCSTR lpApplicationName; - HMODULE hModule; - } ACTCTXA,*PACTCTXA; - - typedef struct tagACTCTXW { - ULONG cbSize; - DWORD dwFlags; - LPCWSTR lpSource; - USHORT wProcessorArchitecture; - LANGID wLangId; - LPCWSTR lpAssemblyDirectory; - LPCWSTR lpResourceName; - LPCWSTR lpApplicationName; - HMODULE hModule; - } ACTCTXW,*PACTCTXW; - - typedef const ACTCTXA *PCACTCTXA; - typedef const ACTCTXW *PCACTCTXW; - -#ifdef UNICODE - typedef ACTCTXW ACTCTX; - typedef PACTCTXW PACTCTX; - typedef PCACTCTXW PCACTCTX; -#else - typedef ACTCTXA ACTCTX; - typedef PACTCTXA PACTCTX; - typedef PCACTCTXA PCACTCTX; -#endif - -#ifdef UNICODE -#define CreateActCtx CreateActCtxW -#else -#define CreateActCtx CreateActCtxA -#endif - - WINBASEAPI HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx); - WINBASEAPI HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx); - WINBASEAPI VOID WINAPI AddRefActCtx(HANDLE hActCtx); - WINBASEAPI VOID WINAPI ReleaseActCtx(HANDLE hActCtx); - WINBASEAPI WINBOOL WINAPI ZombifyActCtx(HANDLE hActCtx); - WINBASEAPI WINBOOL WINAPI ActivateActCtx(HANDLE hActCtx,ULONG_PTR *lpCookie); - -#define DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION (0x1) - - WINBASEAPI WINBOOL WINAPI DeactivateActCtx(DWORD dwFlags,ULONG_PTR ulCookie); - WINBASEAPI WINBOOL WINAPI GetCurrentActCtx(HANDLE *lphActCtx); - - typedef struct tagACTCTX_SECTION_KEYED_DATA_2600 { - ULONG cbSize; - ULONG ulDataFormatVersion; - PVOID lpData; - ULONG ulLength; - PVOID lpSectionGlobalData; - ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; - ULONG ulSectionTotalLength; - HANDLE hActCtx; - ULONG ulAssemblyRosterIndex; - } ACTCTX_SECTION_KEYED_DATA_2600,*PACTCTX_SECTION_KEYED_DATA_2600; - - typedef const ACTCTX_SECTION_KEYED_DATA_2600 *PCACTCTX_SECTION_KEYED_DATA_2600; - - typedef struct tagACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { - PVOID lpInformation; - PVOID lpSectionBase; - ULONG ulSectionLength; - PVOID lpSectionGlobalDataBase; - ULONG ulSectionGlobalDataLength; - } ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA,*PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; - - typedef const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA *PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; - - typedef struct tagACTCTX_SECTION_KEYED_DATA { - ULONG cbSize; - ULONG ulDataFormatVersion; - PVOID lpData; - ULONG ulLength; - PVOID lpSectionGlobalData; - ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; - ULONG ulSectionTotalLength; - HANDLE hActCtx; - ULONG ulAssemblyRosterIndex; - - ULONG ulFlags; - ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; - } ACTCTX_SECTION_KEYED_DATA,*PACTCTX_SECTION_KEYED_DATA; - - typedef const ACTCTX_SECTION_KEYED_DATA *PCACTCTX_SECTION_KEYED_DATA; - -#define FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX 0x1 -#define FIND_ACTCTX_SECTION_KEY_RETURN_FLAGS 0x2 -#define FIND_ACTCTX_SECTION_KEY_RETURN_ASSEMBLY_METADATA 0x4 - -#ifdef UNICODE -#define FindActCtxSectionString FindActCtxSectionStringW -#else -#define FindActCtxSectionString FindActCtxSectionStringA -#endif - - WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCWSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - WINBASEAPI WINBOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,const GUID *lpGuidToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - -#ifndef RC_INVOKED -#ifndef ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED - - typedef struct _ACTIVATION_CONTEXT_BASIC_INFORMATION { - HANDLE hActCtx; - DWORD dwFlags; - } ACTIVATION_CONTEXT_BASIC_INFORMATION,*PACTIVATION_CONTEXT_BASIC_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_BASIC_INFORMATION *PCACTIVATION_CONTEXT_BASIC_INFORMATION; - -#define ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED 1 -#endif -#endif - -#define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x4 -#define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x8 -#define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x10 -#define QUERY_ACTCTX_FLAG_NO_ADDREF 0x80000000 - - WINBASEAPI WINBOOL WINAPI QueryActCtxW(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); - - typedef WINBOOL (WINAPI *PQUERYACTCTXW_FUNC)(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); - - WINBASEAPI WINBOOL WINAPI ProcessIdToSessionId(DWORD dwProcessId,DWORD *pSessionId); - WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(); - WINBASEAPI WINBOOL WINAPI IsWow64Process(HANDLE hProcess,PBOOL Wow64Process); - WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,PDWORD ReturnedLength); - WINBASEAPI WINBOOL WINAPI GetNumaHighestNodeNumber(PULONG HighestNodeNumber); - WINBASEAPI WINBOOL WINAPI GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber); - WINBASEAPI WINBOOL WINAPI GetNumaNodeProcessorMask(UCHAR Node,PULONGLONG ProcessorMask); - WINBASEAPI WINBOOL WINAPI GetNumaAvailableMemoryNode(UCHAR Node,PULONGLONG AvailableBytes); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/wincon.h b/tinyc/win32/include/winapi/wincon.h deleted file mode 100644 index a3501ee70..000000000 --- a/tinyc/win32/include/winapi/wincon.h +++ /dev/null @@ -1,301 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINCON_ -#define _WINCON_ - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct _COORD { - SHORT X; - SHORT Y; - } COORD,*PCOORD; - - typedef struct _SMALL_RECT { - SHORT Left; - SHORT Top; - SHORT Right; - SHORT Bottom; - } SMALL_RECT,*PSMALL_RECT; - - typedef struct _KEY_EVENT_RECORD { - WINBOOL bKeyDown; - WORD wRepeatCount; - WORD wVirtualKeyCode; - WORD wVirtualScanCode; - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } uChar; - DWORD dwControlKeyState; - } KEY_EVENT_RECORD,*PKEY_EVENT_RECORD; - -#define RIGHT_ALT_PRESSED 0x1 -#define LEFT_ALT_PRESSED 0x2 -#define RIGHT_CTRL_PRESSED 0x4 -#define LEFT_CTRL_PRESSED 0x8 -#define SHIFT_PRESSED 0x10 -#define NUMLOCK_ON 0x20 -#define SCROLLLOCK_ON 0x40 -#define CAPSLOCK_ON 0x80 -#define ENHANCED_KEY 0x100 -#define NLS_DBCSCHAR 0x10000 -#define NLS_ALPHANUMERIC 0x0 -#define NLS_KATAKANA 0x20000 -#define NLS_HIRAGANA 0x40000 -#define NLS_ROMAN 0x400000 -#define NLS_IME_CONVERSION 0x800000 -#define NLS_IME_DISABLE 0x20000000 - - typedef struct _MOUSE_EVENT_RECORD { - COORD dwMousePosition; - DWORD dwButtonState; - DWORD dwControlKeyState; - DWORD dwEventFlags; - } MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD; - -#define FROM_LEFT_1ST_BUTTON_PRESSED 0x1 -#define RIGHTMOST_BUTTON_PRESSED 0x2 -#define FROM_LEFT_2ND_BUTTON_PRESSED 0x4 -#define FROM_LEFT_3RD_BUTTON_PRESSED 0x8 -#define FROM_LEFT_4TH_BUTTON_PRESSED 0x10 - -#define MOUSE_MOVED 0x1 -#define DOUBLE_CLICK 0x2 -#define MOUSE_WHEELED 0x4 - - typedef struct _WINDOW_BUFFER_SIZE_RECORD { - COORD dwSize; - } WINDOW_BUFFER_SIZE_RECORD,*PWINDOW_BUFFER_SIZE_RECORD; - - typedef struct _MENU_EVENT_RECORD { - UINT dwCommandId; - } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; - - typedef struct _FOCUS_EVENT_RECORD { - WINBOOL bSetFocus; - } FOCUS_EVENT_RECORD,*PFOCUS_EVENT_RECORD; - - typedef struct _INPUT_RECORD { - WORD EventType; - union { - KEY_EVENT_RECORD KeyEvent; - MOUSE_EVENT_RECORD MouseEvent; - WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; - MENU_EVENT_RECORD MenuEvent; - FOCUS_EVENT_RECORD FocusEvent; - } Event; - } INPUT_RECORD,*PINPUT_RECORD; - -#define KEY_EVENT 0x1 -#define MOUSE_EVENT 0x2 -#define WINDOW_BUFFER_SIZE_EVENT 0x4 -#define MENU_EVENT 0x8 -#define FOCUS_EVENT 0x10 - - typedef struct _CHAR_INFO { - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } Char; - WORD Attributes; - } CHAR_INFO,*PCHAR_INFO; - -#define FOREGROUND_BLUE 0x1 -#define FOREGROUND_GREEN 0x2 -#define FOREGROUND_RED 0x4 -#define FOREGROUND_INTENSITY 0x8 -#define BACKGROUND_BLUE 0x10 -#define BACKGROUND_GREEN 0x20 -#define BACKGROUND_RED 0x40 -#define BACKGROUND_INTENSITY 0x80 -#define COMMON_LVB_LEADING_BYTE 0x100 -#define COMMON_LVB_TRAILING_BYTE 0x200 -#define COMMON_LVB_GRID_HORIZONTAL 0x400 -#define COMMON_LVB_GRID_LVERTICAL 0x800 -#define COMMON_LVB_GRID_RVERTICAL 0x1000 -#define COMMON_LVB_REVERSE_VIDEO 0x4000 -#define COMMON_LVB_UNDERSCORE 0x8000 - -#define COMMON_LVB_SBCSDBCS 0x300 - - typedef struct _CONSOLE_SCREEN_BUFFER_INFO { - COORD dwSize; - COORD dwCursorPosition; - WORD wAttributes; - SMALL_RECT srWindow; - COORD dwMaximumWindowSize; - } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; - - typedef struct _CONSOLE_CURSOR_INFO { - DWORD dwSize; - WINBOOL bVisible; - } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; - - typedef struct _CONSOLE_FONT_INFO { - DWORD nFont; - COORD dwFontSize; - } CONSOLE_FONT_INFO,*PCONSOLE_FONT_INFO; - - typedef struct _CONSOLE_SELECTION_INFO { - DWORD dwFlags; - COORD dwSelectionAnchor; - SMALL_RECT srSelection; - } CONSOLE_SELECTION_INFO,*PCONSOLE_SELECTION_INFO; - -#define CONSOLE_NO_SELECTION 0x0 -#define CONSOLE_SELECTION_IN_PROGRESS 0x1 -#define CONSOLE_SELECTION_NOT_EMPTY 0x2 -#define CONSOLE_MOUSE_SELECTION 0x4 -#define CONSOLE_MOUSE_DOWN 0x8 - - typedef WINBOOL (WINAPI *PHANDLER_ROUTINE)(DWORD CtrlType); - -#define CTRL_C_EVENT 0 -#define CTRL_BREAK_EVENT 1 -#define CTRL_CLOSE_EVENT 2 - -#define CTRL_LOGOFF_EVENT 5 -#define CTRL_SHUTDOWN_EVENT 6 - -#define ENABLE_PROCESSED_INPUT 0x1 -#define ENABLE_LINE_INPUT 0x2 -#define ENABLE_ECHO_INPUT 0x4 -#define ENABLE_WINDOW_INPUT 0x8 -#define ENABLE_MOUSE_INPUT 0x10 - -#define ENABLE_PROCESSED_OUTPUT 0x1 -#define ENABLE_WRAP_AT_EOL_OUTPUT 0x2 - -#ifdef UNICODE -#define PeekConsoleInput PeekConsoleInputW -#define ReadConsoleInput ReadConsoleInputW -#define WriteConsoleInput WriteConsoleInputW -#define ReadConsoleOutput ReadConsoleOutputW -#define WriteConsoleOutput WriteConsoleOutputW -#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW -#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW -#define FillConsoleOutputCharacter FillConsoleOutputCharacterW -#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW -#define GetConsoleTitle GetConsoleTitleW -#define SetConsoleTitle SetConsoleTitleW -#define ReadConsole ReadConsoleW -#define WriteConsole WriteConsoleW -#define AddConsoleAlias AddConsoleAliasW -#define GetConsoleAlias GetConsoleAliasW -#define GetConsoleAliasesLength GetConsoleAliasesLengthW -#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW -#define GetConsoleAliases GetConsoleAliasesW -#define GetConsoleAliasExes GetConsoleAliasExesW -#else -#define PeekConsoleInput PeekConsoleInputA -#define ReadConsoleInput ReadConsoleInputA -#define WriteConsoleInput WriteConsoleInputA -#define ReadConsoleOutput ReadConsoleOutputA -#define WriteConsoleOutput WriteConsoleOutputA -#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA -#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA -#define FillConsoleOutputCharacter FillConsoleOutputCharacterA -#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA -#define GetConsoleTitle GetConsoleTitleA -#define SetConsoleTitle SetConsoleTitleA -#define ReadConsole ReadConsoleA -#define WriteConsole WriteConsoleA -#define AddConsoleAlias AddConsoleAliasA -#define GetConsoleAlias GetConsoleAliasA -#define GetConsoleAliasesLength GetConsoleAliasesLengthA -#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA -#define GetConsoleAliases GetConsoleAliasesA -#define GetConsoleAliasExes GetConsoleAliasExesA -#endif - - WINBASEAPI WINBOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI WriteConsoleInputA(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleInputW(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,LPSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,LPWSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput,LPWORD lpAttribute,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfAttrsRead); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,LPCSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,LPCWSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput,CONST WORD *lpAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput,CHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,WCHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput,WORD wAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); - WINBASEAPI WINBOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle,LPDWORD lpMode); - WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput,LPDWORD lpNumberOfEvents); - WINBASEAPI WINBOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); - WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput); - WINBASEAPI WINBOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); - WINBASEAPI WINBOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput,WINBOOL bMaximumWindow,PCONSOLE_FONT_INFO lpConsoleCurrentFont); - WINBASEAPI COORD WINAPI GetConsoleFontSize(HANDLE hConsoleOutput,DWORD nFont); - WINBASEAPI WINBOOL WINAPI GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo); - WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons); - WINBASEAPI WINBOOL WINAPI SetConsoleMode(HANDLE hConsoleHandle,DWORD dwMode); - WINBASEAPI WINBOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); - WINBASEAPI WINBOOL WINAPI FlushConsoleInputBuffer(HANDLE hConsoleInput); - WINBASEAPI WINBOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput,COORD dwSize); - WINBASEAPI WINBOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition); - WINBASEAPI WINBOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); - WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); - WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); - WINBASEAPI WINBOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput,WINBOOL bAbsolute,CONST SMALL_RECT *lpConsoleWindow); - WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttributes); - WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add); - WINBASEAPI WINBOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,DWORD dwProcessGroupId); - WINBASEAPI WINBOOL WINAPI AllocConsole(VOID); - WINBASEAPI WINBOOL WINAPI FreeConsole(VOID); - WINBASEAPI WINBOOL WINAPI AttachConsole(DWORD dwProcessId); - -#define ATTACH_PARENT_PROCESS ((DWORD)-1) - - WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR lpConsoleTitle,DWORD nSize); - WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetConsoleTitleA(LPCSTR lpConsoleTitle); - WINBASEAPI WINBOOL WINAPI SetConsoleTitleW(LPCWSTR lpConsoleTitle); - WINBASEAPI WINBOOL WINAPI ReadConsoleA(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI ReadConsoleW(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); - -#define CONSOLE_TEXTMODE_BUFFER 1 - - WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess,DWORD dwShareMode,CONST SECURITY_ATTRIBUTES *lpSecurityAttributes,DWORD dwFlags,LPVOID lpScreenBufferData); - WINBASEAPI UINT WINAPI GetConsoleCP(VOID); - WINBASEAPI WINBOOL WINAPI SetConsoleCP(UINT wCodePageID); - WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); - WINBASEAPI WINBOOL WINAPI SetConsoleOutputCP(UINT wCodePageID); - -#define CONSOLE_FULLSCREEN 1 -#define CONSOLE_FULLSCREEN_HARDWARE 2 - - WINBASEAPI WINBOOL WINAPI GetConsoleDisplayMode(LPDWORD lpModeFlags); - WINBASEAPI HWND WINAPI GetConsoleWindow(VOID); - WINBASEAPI DWORD WINAPI GetConsoleProcessList(LPDWORD lpdwProcessList,DWORD dwProcessCount); - WINBASEAPI WINBOOL WINAPI AddConsoleAliasA(LPSTR Source,LPSTR Target,LPSTR ExeName); - WINBASEAPI WINBOOL WINAPI AddConsoleAliasW(LPWSTR Source,LPWSTR Target,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasA(LPSTR Source,LPSTR TargetBuffer,DWORD TargetBufferLength,LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasW(LPWSTR Source,LPWSTR TargetBuffer,DWORD TargetBufferLength,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthA(LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthA(VOID); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthW(VOID); - WINBASEAPI DWORD WINAPI GetConsoleAliasesA(LPSTR AliasBuffer,DWORD AliasBufferLength,LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesW(LPWSTR AliasBuffer,DWORD AliasBufferLength,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesA(LPSTR ExeNameBuffer,DWORD ExeNameBufferLength); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesW(LPWSTR ExeNameBuffer,DWORD ExeNameBufferLength); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/windef.h b/tinyc/win32/include/winapi/windef.h deleted file mode 100644 index d63bdef13..000000000 --- a/tinyc/win32/include/winapi/windef.h +++ /dev/null @@ -1,293 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINDEF_ -#define _WINDEF_ - -#ifndef STRICT -#define STRICT 1 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#ifndef BASETYPES -#define BASETYPES - typedef unsigned long ULONG; - typedef ULONG *PULONG; - typedef unsigned short USHORT; - typedef USHORT *PUSHORT; - typedef unsigned char UCHAR; - typedef UCHAR *PUCHAR; - typedef char *PSZ; -#endif - -#define MAX_PATH 260 - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef IN -#define IN -#endif - -#ifndef OUT -#define OUT -#endif - -#ifndef OPTIONAL -#define OPTIONAL -#endif - -#undef far -#undef near -#undef pascal - -#define far -#define near -#define pascal __stdcall - -#define cdecl -#ifndef CDECL -#define CDECL -#endif -#ifndef CALLBACK -#define CALLBACK __stdcall -#endif -#ifndef WINAPI -#define WINAPI __stdcall -#endif -#define WINAPIV __cdecl -#define APIENTRY WINAPI -#define APIPRIVATE WINAPI -#define PASCAL WINAPI -#define WINAPI_INLINE WINAPI - -#undef FAR -#undef NEAR -#define FAR -#define NEAR -#ifndef CONST -#define CONST const -#endif - - typedef unsigned long DWORD; - typedef int WINBOOL; -#define BOOL WINBOOL - typedef unsigned char BYTE; - typedef unsigned short WORD; - typedef float FLOAT; - typedef FLOAT *PFLOAT; - typedef WINBOOL *PBOOL; - typedef WINBOOL *LPBOOL; - typedef BYTE *PBYTE; - typedef BYTE *LPBYTE; - typedef int *PINT; - typedef int *LPINT; - typedef WORD *PWORD; - typedef WORD *LPWORD; - typedef long *LPLONG; - typedef DWORD *PDWORD; - typedef DWORD *LPDWORD; - typedef void *LPVOID; -# ifndef _LPCVOID_DEFINED -#define _LPCVOID_DEFINED -typedef CONST void *LPCVOID; -#endif - typedef int INT; - typedef unsigned int UINT; - typedef unsigned int *PUINT; - -#ifndef NT_INCLUDED -#include -#endif - -//gr #include - - typedef UINT_PTR WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - -#ifndef __cplusplus -#ifndef NOMINMAX -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#endif -#endif - -#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) -#define MAKELONG(a,b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) -#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) -#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) -#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) -#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) - -#ifndef WIN_INTERNAL - DECLARE_HANDLE (HWND); - DECLARE_HANDLE (HHOOK); -#ifdef WINABLE - DECLARE_HANDLE (HEVENT); -#endif -#endif - - typedef WORD ATOM; - - typedef HANDLE *SPHANDLE; - typedef HANDLE *LPHANDLE; - typedef HANDLE HGLOBAL; - typedef HANDLE HLOCAL; - typedef HANDLE GLOBALHANDLE; - typedef HANDLE LOCALHANDLE; -#ifdef _WIN64 - typedef INT_PTR (WINAPI *FARPROC)(); - typedef INT_PTR (WINAPI *NEARPROC)(); - typedef INT_PTR (WINAPI *PROC)(); -#else - typedef int (WINAPI *FARPROC)(); - typedef int (WINAPI *NEARPROC)(); - typedef int (WINAPI *PROC)(); -#endif - - typedef void *HGDIOBJ; - - DECLARE_HANDLE(HKEY); - typedef HKEY *PHKEY; - - DECLARE_HANDLE(HACCEL); - DECLARE_HANDLE(HBITMAP); - DECLARE_HANDLE(HBRUSH); - DECLARE_HANDLE(HCOLORSPACE); - DECLARE_HANDLE(HDC); - DECLARE_HANDLE(HGLRC); - DECLARE_HANDLE(HDESK); - DECLARE_HANDLE(HENHMETAFILE); - DECLARE_HANDLE(HFONT); - DECLARE_HANDLE(HICON); - DECLARE_HANDLE(HMENU); - DECLARE_HANDLE(HMETAFILE); - DECLARE_HANDLE(HINSTANCE); - typedef HINSTANCE HMODULE; - DECLARE_HANDLE(HPALETTE); - DECLARE_HANDLE(HPEN); - DECLARE_HANDLE(HRGN); - DECLARE_HANDLE(HRSRC); - DECLARE_HANDLE(HSTR); - DECLARE_HANDLE(HTASK); - DECLARE_HANDLE(HWINSTA); - DECLARE_HANDLE(HKL); - DECLARE_HANDLE(HMONITOR); - DECLARE_HANDLE(HWINEVENTHOOK); - DECLARE_HANDLE(HUMPD); - - typedef int HFILE; - typedef HICON HCURSOR; - typedef DWORD COLORREF; - typedef DWORD *LPCOLORREF; - -#define HFILE_ERROR ((HFILE)-1) - - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT,*PRECT,*NPRECT,*LPRECT; - - typedef const RECT *LPCRECT; - - typedef struct _RECTL { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECTL,*PRECTL,*LPRECTL; - - typedef const RECTL *LPCRECTL; - - typedef struct tagPOINT { - LONG x; - LONG y; - } POINT,*PPOINT,*NPPOINT,*LPPOINT; - - typedef struct _POINTL { - LONG x; - LONG y; - } POINTL,*PPOINTL; - - typedef struct tagSIZE { - LONG cx; - LONG cy; - } SIZE,*PSIZE,*LPSIZE; - - typedef SIZE SIZEL; - typedef SIZE *PSIZEL,*LPSIZEL; - - typedef struct tagPOINTS { - SHORT x; - SHORT y; - } POINTS,*PPOINTS,*LPPOINTS; - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME,*PFILETIME,*LPFILETIME; -#define _FILETIME_ - -#define DM_UPDATE 1 -#define DM_COPY 2 -#define DM_PROMPT 4 -#define DM_MODIFY 8 - -#define DM_IN_BUFFER DM_MODIFY -#define DM_IN_PROMPT DM_PROMPT -#define DM_OUT_BUFFER DM_COPY -#define DM_OUT_DEFAULT DM_UPDATE - -#define DC_FIELDS 1 -#define DC_PAPERS 2 -#define DC_PAPERSIZE 3 -#define DC_MINEXTENT 4 -#define DC_MAXEXTENT 5 -#define DC_BINS 6 -#define DC_DUPLEX 7 -#define DC_SIZE 8 -#define DC_EXTRA 9 -#define DC_VERSION 10 -#define DC_DRIVER 11 -#define DC_BINNAMES 12 -#define DC_ENUMRESOLUTIONS 13 -#define DC_FILEDEPENDENCIES 14 -#define DC_TRUETYPE 15 -#define DC_PAPERNAMES 16 -#define DC_ORIENTATION 17 -#define DC_COPIES 18 - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/windows.h b/tinyc/win32/include/winapi/windows.h deleted file mode 100644 index 2660d7f08..000000000 --- a/tinyc/win32/include/winapi/windows.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINDOWS_ -#define _WINDOWS_ - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#include <_mingw.h> - -#ifndef _INC_WINDOWS -#define _INC_WINDOWS - -#if defined(RC_INVOKED) && !defined(NOWINRES) - -#include -#else - -#ifdef RC_INVOKED -#define NOATOM -#define NOGDI -#define NOGDICAPMASKS -#define NOMETAFILE -#define NOMINMAX -#define NOMSG -#define NOOPENFILE -#define NORASTEROPS -#define NOSCROLL -#define NOSOUND -#define NOSYSMETRICS -#define NOTEXTMETRIC -#define NOWH -#define NOCOMM -#define NOKANJI -#define NOCRYPT -#define NOMCX -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) -#define I_X86_ -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) -#define _AMD64_ -#endif - -#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) -#if !defined(_IA64_) -#define _IA64_ -#endif -#endif - -#ifndef RC_INVOKED -#include -#include -#endif - -#include -#include -#include -#include -//gr #include -#include -#include -#include -//gr #include - -#ifndef WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef NOCRYPT -#include -#include -#include -#endif - -#ifndef NOUSER -#ifndef NOGDI -#include -#ifdef INC_OLE1 -#include -#else -#include -#endif -#include -#endif -#endif -#endif - -//gr #include - -#ifdef INC_OLE2 -#include -#endif - -#ifndef NOSERVICE -#include -#endif - -#ifndef NOMCX -#include -#endif - -#ifndef NOIME -#include -#endif - -#endif -#endif -#endif diff --git a/tinyc/win32/include/winapi/winerror.h b/tinyc/win32/include/winapi/winerror.h deleted file mode 100644 index 77d85edc8..000000000 --- a/tinyc/win32/include/winapi/winerror.h +++ /dev/null @@ -1,3166 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINERROR_ -#define _WINERROR_ - -#define FACILITY_WINDOWSUPDATE 36 -#define FACILITY_WINDOWS_CE 24 -#define FACILITY_WINDOWS 8 -#define FACILITY_URT 19 -#define FACILITY_UMI 22 -#define FACILITY_SXS 23 -#define FACILITY_STORAGE 3 -#define FACILITY_STATE_MANAGEMENT 34 -#define FACILITY_SSPI 9 -#define FACILITY_SCARD 16 -#define FACILITY_SETUPAPI 15 -#define FACILITY_SECURITY 9 -#define FACILITY_RPC 1 -#define FACILITY_WIN32 7 -#define FACILITY_CONTROL 10 -#define FACILITY_NULL 0 -#define FACILITY_METADIRECTORY 35 -#define FACILITY_MSMQ 14 -#define FACILITY_MEDIASERVER 13 -#define FACILITY_INTERNET 12 -#define FACILITY_ITF 4 -#define FACILITY_HTTP 25 -#define FACILITY_DPLAY 21 -#define FACILITY_DISPATCH 2 -#define FACILITY_DIRECTORYSERVICE 37 -#define FACILITY_CONFIGURATION 33 -#define FACILITY_COMPLUS 17 -#define FACILITY_CERT 11 -#define FACILITY_BACKGROUNDCOPY 32 -#define FACILITY_ACS 20 -#define FACILITY_AAF 18 -#define ERROR_SUCCESS 0L -#define NO_ERROR 0L -#define SEC_E_OK ((HRESULT)0x00000000L) -#define ERROR_INVALID_FUNCTION 1L -#define ERROR_FILE_NOT_FOUND 2L -#define ERROR_PATH_NOT_FOUND 3L -#define ERROR_TOO_MANY_OPEN_FILES 4L -#define ERROR_ACCESS_DENIED 5L -#define ERROR_INVALID_HANDLE 6L -#define ERROR_ARENA_TRASHED 7L -#define ERROR_NOT_ENOUGH_MEMORY 8L -#define ERROR_INVALID_BLOCK 9L -#define ERROR_BAD_ENVIRONMENT 10L -#define ERROR_BAD_FORMAT 11L -#define ERROR_INVALID_ACCESS 12L -#define ERROR_INVALID_DATA 13L -#define ERROR_OUTOFMEMORY 14L -#define ERROR_INVALID_DRIVE 15L -#define ERROR_CURRENT_DIRECTORY 16L -#define ERROR_NOT_SAME_DEVICE 17L -#define ERROR_NO_MORE_FILES 18L -#define ERROR_WRITE_PROTECT 19L -#define ERROR_BAD_UNIT 20L -#define ERROR_NOT_READY 21L -#define ERROR_BAD_COMMAND 22L -#define ERROR_CRC 23L -#define ERROR_BAD_LENGTH 24L -#define ERROR_SEEK 25L -#define ERROR_NOT_DOS_DISK 26L -#define ERROR_SECTOR_NOT_FOUND 27L -#define ERROR_OUT_OF_PAPER 28L -#define ERROR_WRITE_FAULT 29L -#define ERROR_READ_FAULT 30L -#define ERROR_GEN_FAILURE 31L -#define ERROR_SHARING_VIOLATION 32L -#define ERROR_LOCK_VIOLATION 33L -#define ERROR_WRONG_DISK 34L -#define ERROR_SHARING_BUFFER_EXCEEDED 36L -#define ERROR_HANDLE_EOF 38L -#define ERROR_HANDLE_DISK_FULL 39L -#define ERROR_NOT_SUPPORTED 50L -#define ERROR_REM_NOT_LIST 51L -#define ERROR_DUP_NAME 52L -#define ERROR_BAD_NETPATH 53L -#define ERROR_NETWORK_BUSY 54L -#define ERROR_DEV_NOT_EXIST 55L -#define ERROR_TOO_MANY_CMDS 56L -#define ERROR_ADAP_HDW_ERR 57L -#define ERROR_BAD_NET_RESP 58L -#define ERROR_UNEXP_NET_ERR 59L -#define ERROR_BAD_REM_ADAP 60L -#define ERROR_PRINTQ_FULL 61L -#define ERROR_NO_SPOOL_SPACE 62L -#define ERROR_PRINT_CANCELLED 63L -#define ERROR_NETNAME_DELETED 64L -#define ERROR_NETWORK_ACCESS_DENIED 65L -#define ERROR_BAD_DEV_TYPE 66L -#define ERROR_BAD_NET_NAME 67L -#define ERROR_TOO_MANY_NAMES 68L -#define ERROR_TOO_MANY_SESS 69L -#define ERROR_SHARING_PAUSED 70L -#define ERROR_REQ_NOT_ACCEP 71L -#define ERROR_REDIR_PAUSED 72L -#define ERROR_FILE_EXISTS 80L -#define ERROR_CANNOT_MAKE 82L -#define ERROR_FAIL_I24 83L -#define ERROR_OUT_OF_STRUCTURES 84L -#define ERROR_ALREADY_ASSIGNED 85L -#define ERROR_INVALID_PASSWORD 86L -#define ERROR_INVALID_PARAMETER 87L -#define ERROR_NET_WRITE_FAULT 88L -#define ERROR_NO_PROC_SLOTS 89L -#define ERROR_TOO_MANY_SEMAPHORES 100L -#define ERROR_EXCL_SEM_ALREADY_OWNED 101L -#define ERROR_SEM_IS_SET 102L -#define ERROR_TOO_MANY_SEM_REQUESTS 103L -#define ERROR_INVALID_AT_INTERRUPT_TIME 104L -#define ERROR_SEM_OWNER_DIED 105L -#define ERROR_SEM_USER_LIMIT 106L -#define ERROR_DISK_CHANGE 107L -#define ERROR_DRIVE_LOCKED 108L -#define ERROR_BROKEN_PIPE 109L -#define ERROR_OPEN_FAILED 110L -#define ERROR_BUFFER_OVERFLOW 111L -#define ERROR_DISK_FULL 112L -#define ERROR_NO_MORE_SEARCH_HANDLES 113L -#define ERROR_INVALID_TARGET_HANDLE 114L -#define ERROR_INVALID_CATEGORY 117L -#define ERROR_INVALID_VERIFY_SWITCH 118L -#define ERROR_BAD_DRIVER_LEVEL 119L -#define ERROR_CALL_NOT_IMPLEMENTED 120L -#define ERROR_SEM_TIMEOUT 121L -#define ERROR_INSUFFICIENT_BUFFER 122L -#define ERROR_INVALID_NAME 123L -#define ERROR_INVALID_LEVEL 124L -#define ERROR_NO_VOLUME_LABEL 125L -#define ERROR_MOD_NOT_FOUND 126L -#define ERROR_PROC_NOT_FOUND 127L -#define ERROR_WAIT_NO_CHILDREN 128L -#define ERROR_CHILD_NOT_COMPLETE 129L -#define ERROR_DIRECT_ACCESS_HANDLE 130L -#define ERROR_NEGATIVE_SEEK 131L -#define ERROR_SEEK_ON_DEVICE 132L -#define ERROR_IS_JOIN_TARGET 133L -#define ERROR_IS_JOINED 134L -#define ERROR_IS_SUBSTED 135L -#define ERROR_NOT_JOINED 136L -#define ERROR_NOT_SUBSTED 137L -#define ERROR_JOIN_TO_JOIN 138L -#define ERROR_SUBST_TO_SUBST 139L -#define ERROR_JOIN_TO_SUBST 140L -#define ERROR_SUBST_TO_JOIN 141L -#define ERROR_BUSY_DRIVE 142L -#define ERROR_SAME_DRIVE 143L -#define ERROR_DIR_NOT_ROOT 144L -#define ERROR_DIR_NOT_EMPTY 145L -#define ERROR_IS_SUBST_PATH 146L -#define ERROR_IS_JOIN_PATH 147L -#define ERROR_PATH_BUSY 148L -#define ERROR_IS_SUBST_TARGET 149L -#define ERROR_SYSTEM_TRACE 150L -#define ERROR_INVALID_EVENT_COUNT 151L -#define ERROR_TOO_MANY_MUXWAITERS 152L -#define ERROR_INVALID_LIST_FORMAT 153L -#define ERROR_LABEL_TOO_LONG 154L -#define ERROR_TOO_MANY_TCBS 155L -#define ERROR_SIGNAL_REFUSED 156L -#define ERROR_DISCARDED 157L -#define ERROR_NOT_LOCKED 158L -#define ERROR_BAD_THREADID_ADDR 159L -#define ERROR_BAD_ARGUMENTS 160L -#define ERROR_BAD_PATHNAME 161L -#define ERROR_SIGNAL_PENDING 162L -#define ERROR_MAX_THRDS_REACHED 164L -#define ERROR_LOCK_FAILED 167L -#define ERROR_BUSY 170L -#define ERROR_CANCEL_VIOLATION 173L -#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L -#define ERROR_INVALID_SEGMENT_NUMBER 180L -#define ERROR_INVALID_ORDINAL 182L -#define ERROR_ALREADY_EXISTS 183L -#define ERROR_INVALID_FLAG_NUMBER 186L -#define ERROR_SEM_NOT_FOUND 187L -#define ERROR_INVALID_STARTING_CODESEG 188L -#define ERROR_INVALID_STACKSEG 189L -#define ERROR_INVALID_MODULETYPE 190L -#define ERROR_INVALID_EXE_SIGNATURE 191L -#define ERROR_EXE_MARKED_INVALID 192L -#define ERROR_BAD_EXE_FORMAT 193L -#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L -#define ERROR_INVALID_MINALLOCSIZE 195L -#define ERROR_DYNLINK_FROM_INVALID_RING 196L -#define ERROR_IOPL_NOT_ENABLED 197L -#define ERROR_INVALID_SEGDPL 198L -#define ERROR_AUTODATASEG_EXCEEDS_64k 199L -#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L -#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L -#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L -#define ERROR_ENVVAR_NOT_FOUND 203L -#define ERROR_NO_SIGNAL_SENT 205L -#define ERROR_FILENAME_EXCED_RANGE 206L -#define ERROR_RING2_STACK_IN_USE 207L -#define ERROR_META_EXPANSION_TOO_LONG 208L -#define ERROR_INVALID_SIGNAL_NUMBER 209L -#define ERROR_THREAD_1_INACTIVE 210L -#define ERROR_LOCKED 212L -#define ERROR_TOO_MANY_MODULES 214L -#define ERROR_NESTING_NOT_ALLOWED 215L -#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216L -#define ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY 217L -#define ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY 218L -#define ERROR_BAD_PIPE 230L -#define ERROR_PIPE_BUSY 231L -#define ERROR_NO_DATA 232L -#define ERROR_PIPE_NOT_CONNECTED 233L -#define ERROR_MORE_DATA 234L -#define ERROR_VC_DISCONNECTED 240L -#define ERROR_INVALID_EA_NAME 254L -#define ERROR_EA_LIST_INCONSISTENT 255L -#define WAIT_TIMEOUT 258L -#define ERROR_NO_MORE_ITEMS 259L -#define ERROR_CANNOT_COPY 266L -#define ERROR_DIRECTORY 267L -#define ERROR_EAS_DIDNT_FIT 275L -#define ERROR_EA_FILE_CORRUPT 276L -#define ERROR_EA_TABLE_FULL 277L -#define ERROR_INVALID_EA_HANDLE 278L -#define ERROR_EAS_NOT_SUPPORTED 282L -#define ERROR_NOT_OWNER 288L -#define ERROR_TOO_MANY_POSTS 298L -#define ERROR_PARTIAL_COPY 299L -#define ERROR_OPLOCK_NOT_GRANTED 300L -#define ERROR_INVALID_OPLOCK_PROTOCOL 301L -#define ERROR_DISK_TOO_FRAGMENTED 302L -#define ERROR_DELETE_PENDING 303L -#define ERROR_MR_MID_NOT_FOUND 317L -#define ERROR_SCOPE_NOT_FOUND 318L -#define ERROR_INVALID_ADDRESS 487L -#define ERROR_ARITHMETIC_OVERFLOW 534L -#define ERROR_PIPE_CONNECTED 535L -#define ERROR_PIPE_LISTENING 536L -#define ERROR_EA_ACCESS_DENIED 994L -#define ERROR_OPERATION_ABORTED 995L -#define ERROR_IO_INCOMPLETE 996L -#define ERROR_IO_PENDING 997L -#define ERROR_NOACCESS 998L -#define ERROR_SWAPERROR 999L -#define ERROR_STACK_OVERFLOW 1001L -#define ERROR_INVALID_MESSAGE 1002L -#define ERROR_CAN_NOT_COMPLETE 1003L -#define ERROR_INVALID_FLAGS 1004L -#define ERROR_UNRECOGNIZED_VOLUME 1005L -#define ERROR_FILE_INVALID 1006L -#define ERROR_FULLSCREEN_MODE 1007L -#define ERROR_NO_TOKEN 1008L -#define ERROR_BADDB 1009L -#define ERROR_BADKEY 1010L -#define ERROR_CANTOPEN 1011L -#define ERROR_CANTREAD 1012L -#define ERROR_CANTWRITE 1013L -#define ERROR_REGISTRY_RECOVERED 1014L -#define ERROR_REGISTRY_CORRUPT 1015L -#define ERROR_REGISTRY_IO_FAILED 1016L -#define ERROR_NOT_REGISTRY_FILE 1017L -#define ERROR_KEY_DELETED 1018L -#define ERROR_NO_LOG_SPACE 1019L -#define ERROR_KEY_HAS_CHILDREN 1020L -#define ERROR_CHILD_MUST_BE_VOLATILE 1021L -#define ERROR_NOTIFY_ENUM_DIR 1022L -#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L -#define ERROR_INVALID_SERVICE_CONTROL 1052L -#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L -#define ERROR_SERVICE_NO_THREAD 1054L -#define ERROR_SERVICE_DATABASE_LOCKED 1055L -#define ERROR_SERVICE_ALREADY_RUNNING 1056L -#define ERROR_INVALID_SERVICE_ACCOUNT 1057L -#define ERROR_SERVICE_DISABLED 1058L -#define ERROR_CIRCULAR_DEPENDENCY 1059L -#define ERROR_SERVICE_DOES_NOT_EXIST 1060L -#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L -#define ERROR_SERVICE_NOT_ACTIVE 1062L -#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L -#define ERROR_EXCEPTION_IN_SERVICE 1064L -#define ERROR_DATABASE_DOES_NOT_EXIST 1065L -#define ERROR_SERVICE_SPECIFIC_ERROR 1066L -#define ERROR_PROCESS_ABORTED 1067L -#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L -#define ERROR_SERVICE_LOGON_FAILED 1069L -#define ERROR_SERVICE_START_HANG 1070L -#define ERROR_INVALID_SERVICE_LOCK 1071L -#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L -#define ERROR_SERVICE_EXISTS 1073L -#define ERROR_ALREADY_RUNNING_LKG 1074L -#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L -#define ERROR_BOOT_ALREADY_ACCEPTED 1076L -#define ERROR_SERVICE_NEVER_STARTED 1077L -#define ERROR_DUPLICATE_SERVICE_NAME 1078L -#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079L -#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080L -#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081L -#define ERROR_NO_RECOVERY_PROGRAM 1082L -#define ERROR_SERVICE_NOT_IN_EXE 1083L -#define ERROR_NOT_SAFEBOOT_SERVICE 1084L -#define ERROR_END_OF_MEDIA 1100L -#define ERROR_FILEMARK_DETECTED 1101L -#define ERROR_BEGINNING_OF_MEDIA 1102L -#define ERROR_SETMARK_DETECTED 1103L -#define ERROR_NO_DATA_DETECTED 1104L -#define ERROR_PARTITION_FAILURE 1105L -#define ERROR_INVALID_BLOCK_LENGTH 1106L -#define ERROR_DEVICE_NOT_PARTITIONED 1107L -#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L -#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L -#define ERROR_MEDIA_CHANGED 1110L -#define ERROR_BUS_RESET 1111L -#define ERROR_NO_MEDIA_IN_DRIVE 1112L -#define ERROR_NO_UNICODE_TRANSLATION 1113L -#define ERROR_DLL_INIT_FAILED 1114L -#define ERROR_SHUTDOWN_IN_PROGRESS 1115L -#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L -#define ERROR_IO_DEVICE 1117L -#define ERROR_SERIAL_NO_DEVICE 1118L -#define ERROR_IRQ_BUSY 1119L -#define ERROR_MORE_WRITES 1120L -#define ERROR_COUNTER_TIMEOUT 1121L -#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L -#define ERROR_FLOPPY_WRONG_CYLINDER 1123L -#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L -#define ERROR_FLOPPY_BAD_REGISTERS 1125L -#define ERROR_DISK_RECALIBRATE_FAILED 1126L -#define ERROR_DISK_OPERATION_FAILED 1127L -#define ERROR_DISK_RESET_FAILED 1128L -#define ERROR_EOM_OVERFLOW 1129L -#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L -#define ERROR_POSSIBLE_DEADLOCK 1131L -#define ERROR_MAPPED_ALIGNMENT 1132L -#define ERROR_SET_POWER_STATE_VETOED 1140L -#define ERROR_SET_POWER_STATE_FAILED 1141L -#define ERROR_TOO_MANY_LINKS 1142L -#define ERROR_OLD_WIN_VERSION 1150L -#define ERROR_APP_WRONG_OS 1151L -#define ERROR_SINGLE_INSTANCE_APP 1152L -#define ERROR_RMODE_APP 1153L -#define ERROR_INVALID_DLL 1154L -#define ERROR_NO_ASSOCIATION 1155L -#define ERROR_DDE_FAIL 1156L -#define ERROR_DLL_NOT_FOUND 1157L -#define ERROR_NO_MORE_USER_HANDLES 1158L -#define ERROR_MESSAGE_SYNC_ONLY 1159L -#define ERROR_SOURCE_ELEMENT_EMPTY 1160L -#define ERROR_DESTINATION_ELEMENT_FULL 1161L -#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162L -#define ERROR_MAGAZINE_NOT_PRESENT 1163L -#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164L -#define ERROR_DEVICE_REQUIRES_CLEANING 1165L -#define ERROR_DEVICE_DOOR_OPEN 1166L -#define ERROR_DEVICE_NOT_CONNECTED 1167L -#define ERROR_NOT_FOUND 1168L -#define ERROR_NO_MATCH 1169L -#define ERROR_SET_NOT_FOUND 1170L -#define ERROR_POINT_NOT_FOUND 1171L -#define ERROR_NO_TRACKING_SERVICE 1172L -#define ERROR_NO_VOLUME_ID 1173L -#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175L -#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L -#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L -#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178L -#define ERROR_JOURNAL_NOT_ACTIVE 1179L -#define ERROR_POTENTIAL_FILE_FOUND 1180L -#define ERROR_JOURNAL_ENTRY_DELETED 1181L -#define ERROR_BAD_DEVICE 1200L -#define ERROR_CONNECTION_UNAVAIL 1201L -#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L -#define ERROR_NO_NET_OR_BAD_PATH 1203L -#define ERROR_BAD_PROVIDER 1204L -#define ERROR_CANNOT_OPEN_PROFILE 1205L -#define ERROR_BAD_PROFILE 1206L -#define ERROR_NOT_CONTAINER 1207L -#define ERROR_EXTENDED_ERROR 1208L -#define ERROR_INVALID_GROUPNAME 1209L -#define ERROR_INVALID_COMPUTERNAME 1210L -#define ERROR_INVALID_EVENTNAME 1211L -#define ERROR_INVALID_DOMAINNAME 1212L -#define ERROR_INVALID_SERVICENAME 1213L -#define ERROR_INVALID_NETNAME 1214L -#define ERROR_INVALID_SHARENAME 1215L -#define ERROR_INVALID_PASSWORDNAME 1216L -#define ERROR_INVALID_MESSAGENAME 1217L -#define ERROR_INVALID_MESSAGEDEST 1218L -#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L -#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L -#define ERROR_DUP_DOMAINNAME 1221L -#define ERROR_NO_NETWORK 1222L -#define ERROR_CANCELLED 1223L -#define ERROR_USER_MAPPED_FILE 1224L -#define ERROR_CONNECTION_REFUSED 1225L -#define ERROR_GRACEFUL_DISCONNECT 1226L -#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L -#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L -#define ERROR_CONNECTION_INVALID 1229L -#define ERROR_CONNECTION_ACTIVE 1230L -#define ERROR_NETWORK_UNREACHABLE 1231L -#define ERROR_HOST_UNREACHABLE 1232L -#define ERROR_PROTOCOL_UNREACHABLE 1233L -#define ERROR_PORT_UNREACHABLE 1234L -#define ERROR_REQUEST_ABORTED 1235L -#define ERROR_CONNECTION_ABORTED 1236L -#define ERROR_RETRY 1237L -#define ERROR_CONNECTION_COUNT_LIMIT 1238L -#define ERROR_LOGIN_TIME_RESTRICTION 1239L -#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L -#define ERROR_INCORRECT_ADDRESS 1241L -#define ERROR_ALREADY_REGISTERED 1242L -#define ERROR_SERVICE_NOT_FOUND 1243L -#define ERROR_NOT_AUTHENTICATED 1244L -#define ERROR_NOT_LOGGED_ON 1245L -#define ERROR_CONTINUE 1246L -#define ERROR_ALREADY_INITIALIZED 1247L -#define ERROR_NO_MORE_DEVICES 1248L -#define ERROR_NO_SUCH_SITE 1249L -#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250L -#define ERROR_ONLY_IF_CONNECTED 1251L -#define ERROR_OVERRIDE_NOCHANGES 1252L -#define ERROR_BAD_USER_PROFILE 1253L -#define ERROR_NOT_SUPPORTED_ON_SBS 1254L -#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255L -#define ERROR_HOST_DOWN 1256L -#define ERROR_NON_ACCOUNT_SID 1257L -#define ERROR_NON_DOMAIN_SID 1258L -#define ERROR_APPHELP_BLOCK 1259L -#define ERROR_ACCESS_DISABLED_BY_POLICY 1260L -#define ERROR_REG_NAT_CONSUMPTION 1261L -#define ERROR_CSCSHARE_OFFLINE 1262L -#define ERROR_PKINIT_FAILURE 1263L -#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264L -#define ERROR_DOWNGRADE_DETECTED 1265L -#define ERROR_MACHINE_LOCKED 1271L -#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273L -#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274L -#define ERROR_DRIVER_BLOCKED 1275L -#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276L -#define ERROR_ACCESS_DISABLED_WEBBLADE 1277L -#define ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER 1278L -#define ERROR_RECOVERY_FAILURE 1279L -#define ERROR_ALREADY_FIBER 1280L -#define ERROR_ALREADY_THREAD 1281L -#define ERROR_STACK_BUFFER_OVERRUN 1282L -#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283L -#define ERROR_DEBUGGER_INACTIVE 1284L -#define ERROR_DELAY_LOAD_FAILED 1285L -#define ERROR_VDM_DISALLOWED 1286L -#define ERROR_UNIDENTIFIED_ERROR 1287L -#define ERROR_NOT_ALL_ASSIGNED 1300L -#define ERROR_SOME_NOT_MAPPED 1301L -#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L -#define ERROR_LOCAL_USER_SESSION_KEY 1303L -#define ERROR_NULL_LM_PASSWORD 1304L -#define ERROR_UNKNOWN_REVISION 1305L -#define ERROR_REVISION_MISMATCH 1306L -#define ERROR_INVALID_OWNER 1307L -#define ERROR_INVALID_PRIMARY_GROUP 1308L -#define ERROR_NO_IMPERSONATION_TOKEN 1309L -#define ERROR_CANT_DISABLE_MANDATORY 1310L -#define ERROR_NO_LOGON_SERVERS 1311L -#define ERROR_NO_SUCH_LOGON_SESSION 1312L -#define ERROR_NO_SUCH_PRIVILEGE 1313L -#define ERROR_PRIVILEGE_NOT_HELD 1314L -#define ERROR_INVALID_ACCOUNT_NAME 1315L -#define ERROR_USER_EXISTS 1316L -#define ERROR_NO_SUCH_USER 1317L -#define ERROR_GROUP_EXISTS 1318L -#define ERROR_NO_SUCH_GROUP 1319L -#define ERROR_MEMBER_IN_GROUP 1320L -#define ERROR_MEMBER_NOT_IN_GROUP 1321L -#define ERROR_LAST_ADMIN 1322L -#define ERROR_WRONG_PASSWORD 1323L -#define ERROR_ILL_FORMED_PASSWORD 1324L -#define ERROR_PASSWORD_RESTRICTION 1325L -#define ERROR_LOGON_FAILURE 1326L -#define ERROR_ACCOUNT_RESTRICTION 1327L -#define ERROR_INVALID_LOGON_HOURS 1328L -#define ERROR_INVALID_WORKSTATION 1329L -#define ERROR_PASSWORD_EXPIRED 1330L -#define ERROR_ACCOUNT_DISABLED 1331L -#define ERROR_NONE_MAPPED 1332L -#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L -#define ERROR_LUIDS_EXHAUSTED 1334L -#define ERROR_INVALID_SUB_AUTHORITY 1335L -#define ERROR_INVALID_ACL 1336L -#define ERROR_INVALID_SID 1337L -#define ERROR_INVALID_SECURITY_DESCR 1338L -#define ERROR_BAD_INHERITANCE_ACL 1340L -#define ERROR_SERVER_DISABLED 1341L -#define ERROR_SERVER_NOT_DISABLED 1342L -#define ERROR_INVALID_ID_AUTHORITY 1343L -#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L -#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L -#define ERROR_BAD_IMPERSONATION_LEVEL 1346L -#define ERROR_CANT_OPEN_ANONYMOUS 1347L -#define ERROR_BAD_VALIDATION_CLASS 1348L -#define ERROR_BAD_TOKEN_TYPE 1349L -#define ERROR_NO_SECURITY_ON_OBJECT 1350L -#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L -#define ERROR_INVALID_SERVER_STATE 1352L -#define ERROR_INVALID_DOMAIN_STATE 1353L -#define ERROR_INVALID_DOMAIN_ROLE 1354L -#define ERROR_NO_SUCH_DOMAIN 1355L -#define ERROR_DOMAIN_EXISTS 1356L -#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L -#define ERROR_INTERNAL_DB_CORRUPTION 1358L -#define ERROR_INTERNAL_ERROR 1359L -#define ERROR_GENERIC_NOT_MAPPED 1360L -#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L -#define ERROR_NOT_LOGON_PROCESS 1362L -#define ERROR_LOGON_SESSION_EXISTS 1363L -#define ERROR_NO_SUCH_PACKAGE 1364L -#define ERROR_BAD_LOGON_SESSION_STATE 1365L -#define ERROR_LOGON_SESSION_COLLISION 1366L -#define ERROR_INVALID_LOGON_TYPE 1367L -#define ERROR_CANNOT_IMPERSONATE 1368L -#define ERROR_RXACT_INVALID_STATE 1369L -#define ERROR_RXACT_COMMIT_FAILURE 1370L -#define ERROR_SPECIAL_ACCOUNT 1371L -#define ERROR_SPECIAL_GROUP 1372L -#define ERROR_SPECIAL_USER 1373L -#define ERROR_MEMBERS_PRIMARY_GROUP 1374L -#define ERROR_TOKEN_ALREADY_IN_USE 1375L -#define ERROR_NO_SUCH_ALIAS 1376L -#define ERROR_MEMBER_NOT_IN_ALIAS 1377L -#define ERROR_MEMBER_IN_ALIAS 1378L -#define ERROR_ALIAS_EXISTS 1379L -#define ERROR_LOGON_NOT_GRANTED 1380L -#define ERROR_TOO_MANY_SECRETS 1381L -#define ERROR_SECRET_TOO_LONG 1382L -#define ERROR_INTERNAL_DB_ERROR 1383L -#define ERROR_TOO_MANY_CONTEXT_IDS 1384L -#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L -#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L -#define ERROR_NO_SUCH_MEMBER 1387L -#define ERROR_INVALID_MEMBER 1388L -#define ERROR_TOO_MANY_SIDS 1389L -#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L -#define ERROR_NO_INHERITANCE 1391L -#define ERROR_FILE_CORRUPT 1392L -#define ERROR_DISK_CORRUPT 1393L -#define ERROR_NO_USER_SESSION_KEY 1394L -#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L -#define ERROR_WRONG_TARGET_NAME 1396L -#define ERROR_MUTUAL_AUTH_FAILED 1397L -#define ERROR_TIME_SKEW 1398L -#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399L -#define ERROR_INVALID_WINDOW_HANDLE 1400L -#define ERROR_INVALID_MENU_HANDLE 1401L -#define ERROR_INVALID_CURSOR_HANDLE 1402L -#define ERROR_INVALID_ACCEL_HANDLE 1403L -#define ERROR_INVALID_HOOK_HANDLE 1404L -#define ERROR_INVALID_DWP_HANDLE 1405L -#define ERROR_TLW_WITH_WSCHILD 1406L -#define ERROR_CANNOT_FIND_WND_CLASS 1407L -#define ERROR_WINDOW_OF_OTHER_THREAD 1408L -#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L -#define ERROR_CLASS_ALREADY_EXISTS 1410L -#define ERROR_CLASS_DOES_NOT_EXIST 1411L -#define ERROR_CLASS_HAS_WINDOWS 1412L -#define ERROR_INVALID_INDEX 1413L -#define ERROR_INVALID_ICON_HANDLE 1414L -#define ERROR_PRIVATE_DIALOG_INDEX 1415L -#define ERROR_LISTBOX_ID_NOT_FOUND 1416L -#define ERROR_NO_WILDCARD_CHARACTERS 1417L -#define ERROR_CLIPBOARD_NOT_OPEN 1418L -#define ERROR_HOTKEY_NOT_REGISTERED 1419L -#define ERROR_WINDOW_NOT_DIALOG 1420L -#define ERROR_CONTROL_ID_NOT_FOUND 1421L -#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L -#define ERROR_WINDOW_NOT_COMBOBOX 1423L -#define ERROR_INVALID_EDIT_HEIGHT 1424L -#define ERROR_DC_NOT_FOUND 1425L -#define ERROR_INVALID_HOOK_FILTER 1426L -#define ERROR_INVALID_FILTER_PROC 1427L -#define ERROR_HOOK_NEEDS_HMOD 1428L -#define ERROR_GLOBAL_ONLY_HOOK 1429L -#define ERROR_JOURNAL_HOOK_SET 1430L -#define ERROR_HOOK_NOT_INSTALLED 1431L -#define ERROR_INVALID_LB_MESSAGE 1432L -#define ERROR_SETCOUNT_ON_BAD_LB 1433L -#define ERROR_LB_WITHOUT_TABSTOPS 1434L -#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L -#define ERROR_CHILD_WINDOW_MENU 1436L -#define ERROR_NO_SYSTEM_MENU 1437L -#define ERROR_INVALID_MSGBOX_STYLE 1438L -#define ERROR_INVALID_SPI_VALUE 1439L -#define ERROR_SCREEN_ALREADY_LOCKED 1440L -#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L -#define ERROR_NOT_CHILD_WINDOW 1442L -#define ERROR_INVALID_GW_COMMAND 1443L -#define ERROR_INVALID_THREAD_ID 1444L -#define ERROR_NON_MDICHILD_WINDOW 1445L -#define ERROR_POPUP_ALREADY_ACTIVE 1446L -#define ERROR_NO_SCROLLBARS 1447L -#define ERROR_INVALID_SCROLLBAR_RANGE 1448L -#define ERROR_INVALID_SHOWWIN_COMMAND 1449L -#define ERROR_NO_SYSTEM_RESOURCES 1450L -#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L -#define ERROR_PAGED_SYSTEM_RESOURCES 1452L -#define ERROR_WORKING_SET_QUOTA 1453L -#define ERROR_PAGEFILE_QUOTA 1454L -#define ERROR_COMMITMENT_LIMIT 1455L -#define ERROR_MENU_ITEM_NOT_FOUND 1456L -#define ERROR_INVALID_KEYBOARD_HANDLE 1457L -#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458L -#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459L -#define ERROR_TIMEOUT 1460L -#define ERROR_INVALID_MONITOR_HANDLE 1461L -#define ERROR_INCORRECT_SIZE 1462L -#define ERROR_EVENTLOG_FILE_CORRUPT 1500L -#define ERROR_EVENTLOG_CANT_START 1501L -#define ERROR_LOG_FILE_FULL 1502L -#define ERROR_EVENTLOG_FILE_CHANGED 1503L -#define ERROR_INSTALL_SERVICE_FAILURE 1601L -#define ERROR_INSTALL_USEREXIT 1602L -#define ERROR_INSTALL_FAILURE 1603L -#define ERROR_INSTALL_SUSPEND 1604L -#define ERROR_UNKNOWN_PRODUCT 1605L -#define ERROR_UNKNOWN_FEATURE 1606L -#define ERROR_UNKNOWN_COMPONENT 1607L -#define ERROR_UNKNOWN_PROPERTY 1608L -#define ERROR_INVALID_HANDLE_STATE 1609L -#define ERROR_BAD_CONFIGURATION 1610L -#define ERROR_INDEX_ABSENT 1611L -#define ERROR_INSTALL_SOURCE_ABSENT 1612L -#define ERROR_INSTALL_PACKAGE_VERSION 1613L -#define ERROR_PRODUCT_UNINSTALLED 1614L -#define ERROR_BAD_QUERY_SYNTAX 1615L -#define ERROR_INVALID_FIELD 1616L -#define ERROR_DEVICE_REMOVED 1617L -#define ERROR_INSTALL_ALREADY_RUNNING 1618L -#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619L -#define ERROR_INSTALL_PACKAGE_INVALID 1620L -#define ERROR_INSTALL_UI_FAILURE 1621L -#define ERROR_INSTALL_LOG_FAILURE 1622L -#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623L -#define ERROR_INSTALL_TRANSFORM_FAILURE 1624L -#define ERROR_INSTALL_PACKAGE_REJECTED 1625L -#define ERROR_FUNCTION_NOT_CALLED 1626L -#define ERROR_FUNCTION_FAILED 1627L -#define ERROR_INVALID_TABLE 1628L -#define ERROR_DATATYPE_MISMATCH 1629L -#define ERROR_UNSUPPORTED_TYPE 1630L -#define ERROR_CREATE_FAILED 1631L -#define ERROR_INSTALL_TEMP_UNWRITABLE 1632L -#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633L -#define ERROR_INSTALL_NOTUSED 1634L -#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635L -#define ERROR_PATCH_PACKAGE_INVALID 1636L -#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637L -#define ERROR_PRODUCT_VERSION 1638L -#define ERROR_INVALID_COMMAND_LINE 1639L -#define ERROR_INSTALL_REMOTE_DISALLOWED 1640L -#define ERROR_SUCCESS_REBOOT_INITIATED 1641L -#define ERROR_PATCH_TARGET_NOT_FOUND 1642L -#define ERROR_PATCH_PACKAGE_REJECTED 1643L -#define ERROR_INSTALL_TRANSFORM_REJECTED 1644L -#define ERROR_INSTALL_REMOTE_PROHIBITED 1645L -#define RPC_S_INVALID_STRING_BINDING 1700L -#define RPC_S_WRONG_KIND_OF_BINDING 1701L -#define RPC_S_INVALID_BINDING 1702L -#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L -#define RPC_S_INVALID_RPC_PROTSEQ 1704L -#define RPC_S_INVALID_STRING_UUID 1705L -#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L -#define RPC_S_INVALID_NET_ADDR 1707L -#define RPC_S_NO_ENDPOINT_FOUND 1708L -#define RPC_S_INVALID_TIMEOUT 1709L -#define RPC_S_OBJECT_NOT_FOUND 1710L -#define RPC_S_ALREADY_REGISTERED 1711L -#define RPC_S_TYPE_ALREADY_REGISTERED 1712L -#define RPC_S_ALREADY_LISTENING 1713L -#define RPC_S_NO_PROTSEQS_REGISTERED 1714L -#define RPC_S_NOT_LISTENING 1715L -#define RPC_S_UNKNOWN_MGR_TYPE 1716L -#define RPC_S_UNKNOWN_IF 1717L -#define RPC_S_NO_BINDINGS 1718L -#define RPC_S_NO_PROTSEQS 1719L -#define RPC_S_CANT_CREATE_ENDPOINT 1720L -#define RPC_S_OUT_OF_RESOURCES 1721L -#define RPC_S_SERVER_UNAVAILABLE 1722L -#define RPC_S_SERVER_TOO_BUSY 1723L -#define RPC_S_INVALID_NETWORK_OPTIONS 1724L -#define RPC_S_NO_CALL_ACTIVE 1725L -#define RPC_S_CALL_FAILED 1726L -#define RPC_S_CALL_FAILED_DNE 1727L -#define RPC_S_PROTOCOL_ERROR 1728L -#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L -#define RPC_S_UNSUPPORTED_TYPE 1732L -#define RPC_S_INVALID_TAG 1733L -#define RPC_S_INVALID_BOUND 1734L -#define RPC_S_NO_ENTRY_NAME 1735L -#define RPC_S_INVALID_NAME_SYNTAX 1736L -#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L -#define RPC_S_UUID_NO_ADDRESS 1739L -#define RPC_S_DUPLICATE_ENDPOINT 1740L -#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L -#define RPC_S_MAX_CALLS_TOO_SMALL 1742L -#define RPC_S_STRING_TOO_LONG 1743L -#define RPC_S_PROTSEQ_NOT_FOUND 1744L -#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L -#define RPC_S_BINDING_HAS_NO_AUTH 1746L -#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L -#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L -#define RPC_S_INVALID_AUTH_IDENTITY 1749L -#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L -#define EPT_S_INVALID_ENTRY 1751L -#define EPT_S_CANT_PERFORM_OP 1752L -#define EPT_S_NOT_REGISTERED 1753L -#define RPC_S_NOTHING_TO_EXPORT 1754L -#define RPC_S_INCOMPLETE_NAME 1755L -#define RPC_S_INVALID_VERS_OPTION 1756L -#define RPC_S_NO_MORE_MEMBERS 1757L -#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L -#define RPC_S_INTERFACE_NOT_FOUND 1759L -#define RPC_S_ENTRY_ALREADY_EXISTS 1760L -#define RPC_S_ENTRY_NOT_FOUND 1761L -#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L -#define RPC_S_INVALID_NAF_ID 1763L -#define RPC_S_CANNOT_SUPPORT 1764L -#define RPC_S_NO_CONTEXT_AVAILABLE 1765L -#define RPC_S_INTERNAL_ERROR 1766L -#define RPC_S_ZERO_DIVIDE 1767L -#define RPC_S_ADDRESS_ERROR 1768L -#define RPC_S_FP_DIV_ZERO 1769L -#define RPC_S_FP_UNDERFLOW 1770L -#define RPC_S_FP_OVERFLOW 1771L -#define RPC_X_NO_MORE_ENTRIES 1772L -#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L -#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L -#define RPC_X_SS_IN_NULL_CONTEXT 1775L -#define RPC_X_SS_CONTEXT_DAMAGED 1777L -#define RPC_X_SS_HANDLES_MISMATCH 1778L -#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L -#define RPC_X_NULL_REF_POINTER 1780L -#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L -#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L -#define RPC_X_BAD_STUB_DATA 1783L -#define ERROR_INVALID_USER_BUFFER 1784L -#define ERROR_UNRECOGNIZED_MEDIA 1785L -#define ERROR_NO_TRUST_LSA_SECRET 1786L -#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L -#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L -#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L -#define ERROR_TRUST_FAILURE 1790L -#define RPC_S_CALL_IN_PROGRESS 1791L -#define ERROR_NETLOGON_NOT_STARTED 1792L -#define ERROR_ACCOUNT_EXPIRED 1793L -#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L -#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L -#define ERROR_UNKNOWN_PORT 1796L -#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L -#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L -#define ERROR_INVALID_SEPARATOR_FILE 1799L -#define ERROR_INVALID_PRIORITY 1800L -#define ERROR_INVALID_PRINTER_NAME 1801L -#define ERROR_PRINTER_ALREADY_EXISTS 1802L -#define ERROR_INVALID_PRINTER_COMMAND 1803L -#define ERROR_INVALID_DATATYPE 1804L -#define ERROR_INVALID_ENVIRONMENT 1805L -#define RPC_S_NO_MORE_BINDINGS 1806L -#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L -#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L -#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L -#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L -#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L -#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L -#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L -#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L -#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L -#define ERROR_NOT_ENOUGH_QUOTA 1816L -#define RPC_S_NO_INTERFACES 1817L -#define RPC_S_CALL_CANCELLED 1818L -#define RPC_S_BINDING_INCOMPLETE 1819L -#define RPC_S_COMM_FAILURE 1820L -#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L -#define RPC_S_NO_PRINC_NAME 1822L -#define RPC_S_NOT_RPC_ERROR 1823L -#define RPC_S_UUID_LOCAL_ONLY 1824L -#define RPC_S_SEC_PKG_ERROR 1825L -#define RPC_S_NOT_CANCELLED 1826L -#define RPC_X_INVALID_ES_ACTION 1827L -#define RPC_X_WRONG_ES_VERSION 1828L -#define RPC_X_WRONG_STUB_VERSION 1829L -#define RPC_X_INVALID_PIPE_OBJECT 1830L -#define RPC_X_WRONG_PIPE_ORDER 1831L -#define RPC_X_WRONG_PIPE_VERSION 1832L -#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L -#define EPT_S_CANT_CREATE 1899L -#define RPC_S_INVALID_OBJECT 1900L -#define ERROR_INVALID_TIME 1901L -#define ERROR_INVALID_FORM_NAME 1902L -#define ERROR_INVALID_FORM_SIZE 1903L -#define ERROR_ALREADY_WAITING 1904L -#define ERROR_PRINTER_DELETED 1905L -#define ERROR_INVALID_PRINTER_STATE 1906L -#define ERROR_PASSWORD_MUST_CHANGE 1907L -#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L -#define ERROR_ACCOUNT_LOCKED_OUT 1909L -#define OR_INVALID_OXID 1910L -#define OR_INVALID_OID 1911L -#define OR_INVALID_SET 1912L -#define RPC_S_SEND_INCOMPLETE 1913L -#define RPC_S_INVALID_ASYNC_HANDLE 1914L -#define RPC_S_INVALID_ASYNC_CALL 1915L -#define RPC_X_PIPE_CLOSED 1916L -#define RPC_X_PIPE_DISCIPLINE_ERROR 1917L -#define RPC_X_PIPE_EMPTY 1918L -#define ERROR_NO_SITENAME 1919L -#define ERROR_CANT_ACCESS_FILE 1920L -#define ERROR_CANT_RESOLVE_FILENAME 1921L -#define RPC_S_ENTRY_TYPE_MISMATCH 1922L -#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923L -#define RPC_S_INTERFACE_NOT_EXPORTED 1924L -#define RPC_S_PROFILE_NOT_ADDED 1925L -#define RPC_S_PRF_ELT_NOT_ADDED 1926L -#define RPC_S_PRF_ELT_NOT_REMOVED 1927L -#define RPC_S_GRP_ELT_NOT_ADDED 1928L -#define RPC_S_GRP_ELT_NOT_REMOVED 1929L -#define ERROR_KM_DRIVER_BLOCKED 1930L -#define ERROR_CONTEXT_EXPIRED 1931L -#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932L -#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933L -#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934L -#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935L -#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936L -#define ERROR_INVALID_PIXEL_FORMAT 2000L -#define ERROR_BAD_DRIVER 2001L -#define ERROR_INVALID_WINDOW_STYLE 2002L -#define ERROR_METAFILE_NOT_SUPPORTED 2003L -#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L -#define ERROR_CLIPPING_NOT_SUPPORTED 2005L -#define ERROR_INVALID_CMM 2010L -#define ERROR_INVALID_PROFILE 2011L -#define ERROR_TAG_NOT_FOUND 2012L -#define ERROR_TAG_NOT_PRESENT 2013L -#define ERROR_DUPLICATE_TAG 2014L -#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015L -#define ERROR_PROFILE_NOT_FOUND 2016L -#define ERROR_INVALID_COLORSPACE 2017L -#define ERROR_ICM_NOT_ENABLED 2018L -#define ERROR_DELETING_ICM_XFORM 2019L -#define ERROR_INVALID_TRANSFORM 2020L -#define ERROR_COLORSPACE_MISMATCH 2021L -#define ERROR_INVALID_COLORINDEX 2022L -#define ERROR_CONNECTED_OTHER_PASSWORD 2108L -#define ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT 2109L -#define ERROR_BAD_USERNAME 2202L -#define ERROR_NOT_CONNECTED 2250L -#define ERROR_OPEN_FILES 2401L -#define ERROR_ACTIVE_CONNECTIONS 2402L -#define ERROR_DEVICE_IN_USE 2404L -#define ERROR_UNKNOWN_PRINT_MONITOR 3000L -#define ERROR_PRINTER_DRIVER_IN_USE 3001L -#define ERROR_SPOOL_FILE_NOT_FOUND 3002L -#define ERROR_SPL_NO_STARTDOC 3003L -#define ERROR_SPL_NO_ADDJOB 3004L -#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L -#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L -#define ERROR_INVALID_PRINT_MONITOR 3007L -#define ERROR_PRINT_MONITOR_IN_USE 3008L -#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009L -#define ERROR_SUCCESS_REBOOT_REQUIRED 3010L -#define ERROR_SUCCESS_RESTART_REQUIRED 3011L -#define ERROR_PRINTER_NOT_FOUND 3012L -#define ERROR_PRINTER_DRIVER_WARNED 3013L -#define ERROR_PRINTER_DRIVER_BLOCKED 3014L -#define ERROR_WINS_INTERNAL 4000L -#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L -#define ERROR_STATIC_INIT 4002L -#define ERROR_INC_BACKUP 4003L -#define ERROR_FULL_BACKUP 4004L -#define ERROR_REC_NON_EXISTENT 4005L -#define ERROR_RPL_NOT_ALLOWED 4006L -#define ERROR_DHCP_ADDRESS_CONFLICT 4100L -#define ERROR_WMI_GUID_NOT_FOUND 4200L -#define ERROR_WMI_INSTANCE_NOT_FOUND 4201L -#define ERROR_WMI_ITEMID_NOT_FOUND 4202L -#define ERROR_WMI_TRY_AGAIN 4203L -#define ERROR_WMI_DP_NOT_FOUND 4204L -#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205L -#define ERROR_WMI_ALREADY_ENABLED 4206L -#define ERROR_WMI_GUID_DISCONNECTED 4207L -#define ERROR_WMI_SERVER_UNAVAILABLE 4208L -#define ERROR_WMI_DP_FAILED 4209L -#define ERROR_WMI_INVALID_MOF 4210L -#define ERROR_WMI_INVALID_REGINFO 4211L -#define ERROR_WMI_ALREADY_DISABLED 4212L -#define ERROR_WMI_READ_ONLY 4213L -#define ERROR_WMI_SET_FAILURE 4214L -#define ERROR_INVALID_MEDIA 4300L -#define ERROR_INVALID_LIBRARY 4301L -#define ERROR_INVALID_MEDIA_POOL 4302L -#define ERROR_DRIVE_MEDIA_MISMATCH 4303L -#define ERROR_MEDIA_OFFLINE 4304L -#define ERROR_LIBRARY_OFFLINE 4305L -#define ERROR_EMPTY 4306L -#define ERROR_NOT_EMPTY 4307L -#define ERROR_MEDIA_UNAVAILABLE 4308L -#define ERROR_RESOURCE_DISABLED 4309L -#define ERROR_INVALID_CLEANER 4310L -#define ERROR_UNABLE_TO_CLEAN 4311L -#define ERROR_OBJECT_NOT_FOUND 4312L -#define ERROR_DATABASE_FAILURE 4313L -#define ERROR_DATABASE_FULL 4314L -#define ERROR_MEDIA_INCOMPATIBLE 4315L -#define ERROR_RESOURCE_NOT_PRESENT 4316L -#define ERROR_INVALID_OPERATION 4317L -#define ERROR_MEDIA_NOT_AVAILABLE 4318L -#define ERROR_DEVICE_NOT_AVAILABLE 4319L -#define ERROR_REQUEST_REFUSED 4320L -#define ERROR_INVALID_DRIVE_OBJECT 4321L -#define ERROR_LIBRARY_FULL 4322L -#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323L -#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324L -#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325L -#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326L -#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327L -#define ERROR_TRANSPORT_FULL 4328L -#define ERROR_CONTROLLING_IEPORT 4329L -#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330L -#define ERROR_CLEANER_SLOT_SET 4331L -#define ERROR_CLEANER_SLOT_NOT_SET 4332L -#define ERROR_CLEANER_CARTRIDGE_SPENT 4333L -#define ERROR_UNEXPECTED_OMID 4334L -#define ERROR_CANT_DELETE_LAST_ITEM 4335L -#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336L -#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337L -#define ERROR_INDIGENOUS_TYPE 4338L -#define ERROR_NO_SUPPORTING_DRIVES 4339L -#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340L -#define ERROR_IEPORT_FULL 4341L -#define ERROR_FILE_OFFLINE 4350L -#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351L -#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352L -#define ERROR_NOT_A_REPARSE_POINT 4390L -#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391L -#define ERROR_INVALID_REPARSE_DATA 4392L -#define ERROR_REPARSE_TAG_INVALID 4393L -#define ERROR_REPARSE_TAG_MISMATCH 4394L -#define ERROR_VOLUME_NOT_SIS_ENABLED 4500L -#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001L -#define ERROR_DEPENDENCY_NOT_FOUND 5002L -#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003L -#define ERROR_RESOURCE_NOT_ONLINE 5004L -#define ERROR_HOST_NODE_NOT_AVAILABLE 5005L -#define ERROR_RESOURCE_NOT_AVAILABLE 5006L -#define ERROR_RESOURCE_NOT_FOUND 5007L -#define ERROR_SHUTDOWN_CLUSTER 5008L -#define ERROR_CANT_EVICT_ACTIVE_NODE 5009L -#define ERROR_OBJECT_ALREADY_EXISTS 5010L -#define ERROR_OBJECT_IN_LIST 5011L -#define ERROR_GROUP_NOT_AVAILABLE 5012L -#define ERROR_GROUP_NOT_FOUND 5013L -#define ERROR_GROUP_NOT_ONLINE 5014L -#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015L -#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016L -#define ERROR_RESMON_CREATE_FAILED 5017L -#define ERROR_RESMON_ONLINE_FAILED 5018L -#define ERROR_RESOURCE_ONLINE 5019L -#define ERROR_QUORUM_RESOURCE 5020L -#define ERROR_NOT_QUORUM_CAPABLE 5021L -#define ERROR_CLUSTER_SHUTTING_DOWN 5022L -#define ERROR_INVALID_STATE 5023L -#define ERROR_RESOURCE_PROPERTIES_STORED 5024L -#define ERROR_NOT_QUORUM_CLASS 5025L -#define ERROR_CORE_RESOURCE 5026L -#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027L -#define ERROR_QUORUMLOG_OPEN_FAILED 5028L -#define ERROR_CLUSTERLOG_CORRUPT 5029L -#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030L -#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031L -#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032L -#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033L -#define ERROR_QUORUM_OWNER_ALIVE 5034L -#define ERROR_NETWORK_NOT_AVAILABLE 5035L -#define ERROR_NODE_NOT_AVAILABLE 5036L -#define ERROR_ALL_NODES_NOT_AVAILABLE 5037L -#define ERROR_RESOURCE_FAILED 5038L -#define ERROR_CLUSTER_INVALID_NODE 5039L -#define ERROR_CLUSTER_NODE_EXISTS 5040L -#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041L -#define ERROR_CLUSTER_NODE_NOT_FOUND 5042L -#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043L -#define ERROR_CLUSTER_NETWORK_EXISTS 5044L -#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045L -#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046L -#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047L -#define ERROR_CLUSTER_INVALID_REQUEST 5048L -#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049L -#define ERROR_CLUSTER_NODE_DOWN 5050L -#define ERROR_CLUSTER_NODE_UNREACHABLE 5051L -#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052L -#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053L -#define ERROR_CLUSTER_INVALID_NETWORK 5054L -#define ERROR_CLUSTER_NODE_UP 5056L -#define ERROR_CLUSTER_IPADDR_IN_USE 5057L -#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058L -#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059L -#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060L -#define ERROR_CLUSTER_NODE_ALREADY_UP 5061L -#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062L -#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063L -#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064L -#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065L -#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066L -#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067L -#define ERROR_INVALID_OPERATION_ON_QUORUM 5068L -#define ERROR_DEPENDENCY_NOT_ALLOWED 5069L -#define ERROR_CLUSTER_NODE_PAUSED 5070L -#define ERROR_NODE_CANT_HOST_RESOURCE 5071L -#define ERROR_CLUSTER_NODE_NOT_READY 5072L -#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073L -#define ERROR_CLUSTER_JOIN_ABORTED 5074L -#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075L -#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076L -#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077L -#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078L -#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079L -#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080L -#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081L -#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082L -#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083L -#define ERROR_RESMON_INVALID_STATE 5084L -#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085L -#define ERROR_QUORUM_DISK_NOT_FOUND 5086L -#define ERROR_DATABASE_BACKUP_CORRUPT 5087L -#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088L -#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089L -#define ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE 5890L -#define ERROR_CLUSTER_QUORUMLOG_NOT_FOUND 5891L -#define ERROR_CLUSTER_MEMBERSHIP_HALT 5892L -#define ERROR_CLUSTER_INSTANCE_ID_MISMATCH 5893L -#define ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP 5894L -#define ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH 5895L -#define ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP 5896L -#define ERROR_CLUSTER_PARAMETER_MISMATCH 5897L -#define ERROR_NODE_CANNOT_BE_CLUSTERED 5898L -#define ERROR_CLUSTER_WRONG_OS_VERSION 5899L -#define ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME 5900L -#define ERROR_CLUSCFG_ALREADY_COMMITTED 5901L -#define ERROR_CLUSCFG_ROLLBACK_FAILED 5902L -#define ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT 5903L -#define ERROR_CLUSTER_OLD_VERSION 5904L -#define ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME 5905L -#define ERROR_ENCRYPTION_FAILED 6000L -#define ERROR_DECRYPTION_FAILED 6001L -#define ERROR_FILE_ENCRYPTED 6002L -#define ERROR_NO_RECOVERY_POLICY 6003L -#define ERROR_NO_EFS 6004L -#define ERROR_WRONG_EFS 6005L -#define ERROR_NO_USER_KEYS 6006L -#define ERROR_FILE_NOT_ENCRYPTED 6007L -#define ERROR_NOT_EXPORT_FORMAT 6008L -#define ERROR_FILE_READ_ONLY 6009L -#define ERROR_DIR_EFS_DISALLOWED 6010L -#define ERROR_EFS_SERVER_NOT_TRUSTED 6011L -#define ERROR_BAD_RECOVERY_POLICY 6012L -#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013L -#define ERROR_VOLUME_NOT_SUPPORT_EFS 6014L -#define ERROR_EFS_DISABLED 6015L -#define ERROR_EFS_VERSION_NOT_SUPPORT 6016L -#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L -#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200L -#define ERROR_CTX_WINSTATION_NAME_INVALID 7001L -#define ERROR_CTX_INVALID_PD 7002L -#define ERROR_CTX_PD_NOT_FOUND 7003L -#define ERROR_CTX_WD_NOT_FOUND 7004L -#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005L -#define ERROR_CTX_SERVICE_NAME_COLLISION 7006L -#define ERROR_CTX_CLOSE_PENDING 7007L -#define ERROR_CTX_NO_OUTBUF 7008L -#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009L -#define ERROR_CTX_INVALID_MODEMNAME 7010L -#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011L -#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012L -#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013L -#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014L -#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015L -#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016L -#define ERROR_CTX_TD_ERROR 7017L -#define ERROR_CTX_WINSTATION_NOT_FOUND 7022L -#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023L -#define ERROR_CTX_WINSTATION_BUSY 7024L -#define ERROR_CTX_BAD_VIDEO_MODE 7025L -#define ERROR_CTX_GRAPHICS_INVALID 7035L -#define ERROR_CTX_LOGON_DISABLED 7037L -#define ERROR_CTX_NOT_CONSOLE 7038L -#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040L -#define ERROR_CTX_CONSOLE_DISCONNECT 7041L -#define ERROR_CTX_CONSOLE_CONNECT 7042L -#define ERROR_CTX_SHADOW_DENIED 7044L -#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045L -#define ERROR_CTX_INVALID_WD 7049L -#define ERROR_CTX_SHADOW_INVALID 7050L -#define ERROR_CTX_SHADOW_DISABLED 7051L -#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052L -#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053L -#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054L -#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055L -#define ERROR_CTX_LICENSE_EXPIRED 7056L -#define ERROR_CTX_SHADOW_NOT_RUNNING 7057L -#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058L -#define ERROR_ACTIVATION_COUNT_EXCEEDED 7059L -#define FRS_ERR_INVALID_API_SEQUENCE 8001L -#define FRS_ERR_STARTING_SERVICE 8002L -#define FRS_ERR_STOPPING_SERVICE 8003L -#define FRS_ERR_INTERNAL_API 8004L -#define FRS_ERR_INTERNAL 8005L -#define FRS_ERR_SERVICE_COMM 8006L -#define FRS_ERR_INSUFFICIENT_PRIV 8007L -#define FRS_ERR_AUTHENTICATION 8008L -#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009L -#define FRS_ERR_PARENT_AUTHENTICATION 8010L -#define FRS_ERR_CHILD_TO_PARENT_COMM 8011L -#define FRS_ERR_PARENT_TO_CHILD_COMM 8012L -#define FRS_ERR_SYSVOL_POPULATE 8013L -#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014L -#define FRS_ERR_SYSVOL_IS_BUSY 8015L -#define FRS_ERR_SYSVOL_DEMOTE 8016L -#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017L -#define DS_S_SUCCESS NO_ERROR -#define ERROR_DS_NOT_INSTALLED 8200L -#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201L -#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202L -#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203L -#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204L -#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205L -#define ERROR_DS_BUSY 8206L -#define ERROR_DS_UNAVAILABLE 8207L -#define ERROR_DS_NO_RIDS_ALLOCATED 8208L -#define ERROR_DS_NO_MORE_RIDS 8209L -#define ERROR_DS_INCORRECT_ROLE_OWNER 8210L -#define ERROR_DS_RIDMGR_INIT_ERROR 8211L -#define ERROR_DS_OBJ_CLASS_VIOLATION 8212L -#define ERROR_DS_CANT_ON_NON_LEAF 8213L -#define ERROR_DS_CANT_ON_RDN 8214L -#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215L -#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216L -#define ERROR_DS_GC_NOT_AVAILABLE 8217L -#define ERROR_SHARED_POLICY 8218L -#define ERROR_POLICY_OBJECT_NOT_FOUND 8219L -#define ERROR_POLICY_ONLY_IN_DS 8220L -#define ERROR_PROMOTION_ACTIVE 8221L -#define ERROR_NO_PROMOTION_ACTIVE 8222L -#define ERROR_DS_OPERATIONS_ERROR 8224L -#define ERROR_DS_PROTOCOL_ERROR 8225L -#define ERROR_DS_TIMELIMIT_EXCEEDED 8226L -#define ERROR_DS_SIZELIMIT_EXCEEDED 8227L -#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228L -#define ERROR_DS_COMPARE_FALSE 8229L -#define ERROR_DS_COMPARE_TRUE 8230L -#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231L -#define ERROR_DS_STRONG_AUTH_REQUIRED 8232L -#define ERROR_DS_INAPPROPRIATE_AUTH 8233L -#define ERROR_DS_AUTH_UNKNOWN 8234L -#define ERROR_DS_REFERRAL 8235L -#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236L -#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237L -#define ERROR_DS_INAPPROPRIATE_MATCHING 8238L -#define ERROR_DS_CONSTRAINT_VIOLATION 8239L -#define ERROR_DS_NO_SUCH_OBJECT 8240L -#define ERROR_DS_ALIAS_PROBLEM 8241L -#define ERROR_DS_INVALID_DN_SYNTAX 8242L -#define ERROR_DS_IS_LEAF 8243L -#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244L -#define ERROR_DS_UNWILLING_TO_PERFORM 8245L -#define ERROR_DS_LOOP_DETECT 8246L -#define ERROR_DS_NAMING_VIOLATION 8247L -#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248L -#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249L -#define ERROR_DS_SERVER_DOWN 8250L -#define ERROR_DS_LOCAL_ERROR 8251L -#define ERROR_DS_ENCODING_ERROR 8252L -#define ERROR_DS_DECODING_ERROR 8253L -#define ERROR_DS_FILTER_UNKNOWN 8254L -#define ERROR_DS_PARAM_ERROR 8255L -#define ERROR_DS_NOT_SUPPORTED 8256L -#define ERROR_DS_NO_RESULTS_RETURNED 8257L -#define ERROR_DS_CONTROL_NOT_FOUND 8258L -#define ERROR_DS_CLIENT_LOOP 8259L -#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260L -#define ERROR_DS_SORT_CONTROL_MISSING 8261L -#define ERROR_DS_OFFSET_RANGE_ERROR 8262L -#define ERROR_DS_ROOT_MUST_BE_NC 8301L -#define ERROR_DS_ADD_REPLICA_INHIBITED 8302L -#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303L -#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304L -#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305L -#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306L -#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307L -#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308L -#define ERROR_DS_USER_BUFFER_TO_SMALL 8309L -#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310L -#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311L -#define ERROR_DS_OBJ_TOO_LARGE 8312L -#define ERROR_DS_BAD_INSTANCE_TYPE 8313L -#define ERROR_DS_MASTERDSA_REQUIRED 8314L -#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315L -#define ERROR_DS_MISSING_REQUIRED_ATT 8316L -#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317L -#define ERROR_DS_ATT_ALREADY_EXISTS 8318L -#define ERROR_DS_CANT_ADD_ATT_VALUES 8320L -#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321L -#define ERROR_DS_RANGE_CONSTRAINT 8322L -#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323L -#define ERROR_DS_CANT_REM_MISSING_ATT 8324L -#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325L -#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326L -#define ERROR_DS_NO_CHAINING 8327L -#define ERROR_DS_NO_CHAINED_EVAL 8328L -#define ERROR_DS_NO_PARENT_OBJECT 8329L -#define ERROR_DS_PARENT_IS_AN_ALIAS 8330L -#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331L -#define ERROR_DS_CHILDREN_EXIST 8332L -#define ERROR_DS_OBJ_NOT_FOUND 8333L -#define ERROR_DS_ALIASED_OBJ_MISSING 8334L -#define ERROR_DS_BAD_NAME_SYNTAX 8335L -#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336L -#define ERROR_DS_CANT_DEREF_ALIAS 8337L -#define ERROR_DS_OUT_OF_SCOPE 8338L -#define ERROR_DS_OBJECT_BEING_REMOVED 8339L -#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340L -#define ERROR_DS_GENERIC_ERROR 8341L -#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342L -#define ERROR_DS_CLASS_NOT_DSA 8343L -#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344L -#define ERROR_DS_ILLEGAL_SUPERIOR 8345L -#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346L -#define ERROR_DS_NAME_TOO_MANY_PARTS 8347L -#define ERROR_DS_NAME_TOO_LONG 8348L -#define ERROR_DS_NAME_VALUE_TOO_LONG 8349L -#define ERROR_DS_NAME_UNPARSEABLE 8350L -#define ERROR_DS_NAME_TYPE_UNKNOWN 8351L -#define ERROR_DS_NOT_AN_OBJECT 8352L -#define ERROR_DS_SEC_DESC_TOO_SHORT 8353L -#define ERROR_DS_SEC_DESC_INVALID 8354L -#define ERROR_DS_NO_DELETED_NAME 8355L -#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356L -#define ERROR_DS_NCNAME_MUST_BE_NC 8357L -#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358L -#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359L -#define ERROR_DS_INVALID_DMD 8360L -#define ERROR_DS_OBJ_GUID_EXISTS 8361L -#define ERROR_DS_NOT_ON_BACKLINK 8362L -#define ERROR_DS_NO_CROSSREF_FOR_NC 8363L -#define ERROR_DS_SHUTTING_DOWN 8364L -#define ERROR_DS_UNKNOWN_OPERATION 8365L -#define ERROR_DS_INVALID_ROLE_OWNER 8366L -#define ERROR_DS_COULDNT_CONTACT_FSMO 8367L -#define ERROR_DS_CROSS_NC_DN_RENAME 8368L -#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369L -#define ERROR_DS_REPLICATOR_ONLY 8370L -#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371L -#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372L -#define ERROR_DS_NAME_REFERENCE_INVALID 8373L -#define ERROR_DS_CROSS_REF_EXISTS 8374L -#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375L -#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376L -#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377L -#define ERROR_DS_DUP_RDN 8378L -#define ERROR_DS_DUP_OID 8379L -#define ERROR_DS_DUP_MAPI_ID 8380L -#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381L -#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382L -#define ERROR_DS_SEMANTIC_ATT_TEST 8383L -#define ERROR_DS_SYNTAX_MISMATCH 8384L -#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385L -#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386L -#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387L -#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388L -#define ERROR_DS_AUX_CLS_TEST_FAIL 8389L -#define ERROR_DS_NONEXISTENT_POSS_SUP 8390L -#define ERROR_DS_SUB_CLS_TEST_FAIL 8391L -#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392L -#define ERROR_DS_EXISTS_IN_AUX_CLS 8393L -#define ERROR_DS_EXISTS_IN_SUB_CLS 8394L -#define ERROR_DS_EXISTS_IN_POSS_SUP 8395L -#define ERROR_DS_RECALCSCHEMA_FAILED 8396L -#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397L -#define ERROR_DS_CANT_DELETE 8398L -#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399L -#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400L -#define ERROR_DS_CANT_CACHE_ATT 8401L -#define ERROR_DS_CANT_CACHE_CLASS 8402L -#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403L -#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404L -#define ERROR_DS_CANT_RETRIEVE_DN 8405L -#define ERROR_DS_MISSING_SUPREF 8406L -#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407L -#define ERROR_DS_CODE_INCONSISTENCY 8408L -#define ERROR_DS_DATABASE_ERROR 8409L -#define ERROR_DS_GOVERNSID_MISSING 8410L -#define ERROR_DS_MISSING_EXPECTED_ATT 8411L -#define ERROR_DS_NCNAME_MISSING_CR_REF 8412L -#define ERROR_DS_SECURITY_CHECKING_ERROR 8413L -#define ERROR_DS_SCHEMA_NOT_LOADED 8414L -#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415L -#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416L -#define ERROR_DS_GCVERIFY_ERROR 8417L -#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418L -#define ERROR_DS_CANT_FIND_DSA_OBJ 8419L -#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420L -#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421L -#define ERROR_DS_CANT_RETRIEVE_CHILD 8422L -#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423L -#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424L -#define ERROR_DS_BAD_HIERARCHY_FILE 8425L -#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426L -#define ERROR_DS_CONFIG_PARAM_MISSING 8427L -#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428L -#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429L -#define ERROR_DS_INTERNAL_FAILURE 8430L -#define ERROR_DS_UNKNOWN_ERROR 8431L -#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432L -#define ERROR_DS_REFUSING_FSMO_ROLES 8433L -#define ERROR_DS_MISSING_FSMO_SETTINGS 8434L -#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435L -#define ERROR_DS_DRA_GENERIC 8436L -#define ERROR_DS_DRA_INVALID_PARAMETER 8437L -#define ERROR_DS_DRA_BUSY 8438L -#define ERROR_DS_DRA_BAD_DN 8439L -#define ERROR_DS_DRA_BAD_NC 8440L -#define ERROR_DS_DRA_DN_EXISTS 8441L -#define ERROR_DS_DRA_INTERNAL_ERROR 8442L -#define ERROR_DS_DRA_INCONSISTENT_DIT 8443L -#define ERROR_DS_DRA_CONNECTION_FAILED 8444L -#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445L -#define ERROR_DS_DRA_OUT_OF_MEM 8446L -#define ERROR_DS_DRA_MAIL_PROBLEM 8447L -#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448L -#define ERROR_DS_DRA_REF_NOT_FOUND 8449L -#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450L -#define ERROR_DS_DRA_DB_ERROR 8451L -#define ERROR_DS_DRA_NO_REPLICA 8452L -#define ERROR_DS_DRA_ACCESS_DENIED 8453L -#define ERROR_DS_DRA_NOT_SUPPORTED 8454L -#define ERROR_DS_DRA_RPC_CANCELLED 8455L -#define ERROR_DS_DRA_SOURCE_DISABLED 8456L -#define ERROR_DS_DRA_SINK_DISABLED 8457L -#define ERROR_DS_DRA_NAME_COLLISION 8458L -#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459L -#define ERROR_DS_DRA_MISSING_PARENT 8460L -#define ERROR_DS_DRA_PREEMPTED 8461L -#define ERROR_DS_DRA_ABANDON_SYNC 8462L -#define ERROR_DS_DRA_SHUTDOWN 8463L -#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464L -#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465L -#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466L -#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467L -#define ERROR_DS_DUP_LINK_ID 8468L -#define ERROR_DS_NAME_ERROR_RESOLVING 8469L -#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470L -#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471L -#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472L -#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473L -#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474L -#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475L -#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476L -#define ERROR_DS_DRA_REPL_PENDING 8477L -#define ERROR_DS_DS_REQUIRED 8478L -#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479L -#define ERROR_DS_NON_BASE_SEARCH 8480L -#define ERROR_DS_CANT_RETRIEVE_ATTS 8481L -#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482L -#define ERROR_DS_EPOCH_MISMATCH 8483L -#define ERROR_DS_SRC_NAME_MISMATCH 8484L -#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485L -#define ERROR_DS_DST_NC_MISMATCH 8486L -#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487L -#define ERROR_DS_SRC_GUID_MISMATCH 8488L -#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489L -#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490L -#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491L -#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492L -#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493L -#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494L -#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495L -#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496L -#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497L -#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498L -#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499L -#define ERROR_DS_INVALID_SEARCH_FLAG 8500L -#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501L -#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502L -#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503L -#define ERROR_DS_SAM_INIT_FAILURE 8504L -#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505L -#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506L -#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507L -#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508L -#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509L -#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510L -#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511L -#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512L -#define ERROR_DS_INVALID_GROUP_TYPE 8513L -#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514L -#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515L -#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516L -#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517L -#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518L -#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519L -#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520L -#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521L -#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522L -#define ERROR_DS_NAMING_MASTER_GC 8523L -#define ERROR_DS_DNS_LOOKUP_FAILURE 8524L -#define ERROR_DS_COULDNT_UPDATE_SPNS 8525L -#define ERROR_DS_CANT_RETRIEVE_SD 8526L -#define ERROR_DS_KEY_NOT_UNIQUE 8527L -#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528L -#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529L -#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530L -#define ERROR_DS_CANT_START 8531L -#define ERROR_DS_INIT_FAILURE 8532L -#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533L -#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534L -#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535L -#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536L -#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537L -#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538L -#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539L -#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540L -#define ERROR_SAM_INIT_FAILURE 8541L -#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542L -#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543L -#define ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT 8544L -#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545L -#define ERROR_DS_NC_STILL_HAS_DSAS 8546L -#define ERROR_DS_GC_REQUIRED 8547L -#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548L -#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549L -#define ERROR_DS_CANT_ADD_TO_GC 8550L -#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551L -#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552L -#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553L -#define ERROR_DS_INVALID_NAME_FOR_SPN 8554L -#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555L -#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556L -#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557L -#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558L -#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559L -#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560L -#define ERROR_DS_INIT_FAILURE_CONSOLE 8561L -#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562L -#define ERROR_DS_FOREST_VERSION_TOO_HIGH 8563L -#define ERROR_DS_DOMAIN_VERSION_TOO_HIGH 8564L -#define ERROR_DS_FOREST_VERSION_TOO_LOW 8565L -#define ERROR_DS_DOMAIN_VERSION_TOO_LOW 8566L -#define ERROR_DS_INCOMPATIBLE_VERSION 8567L -#define ERROR_DS_LOW_DSA_VERSION 8568L -#define ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN 8569L -#define ERROR_DS_NOT_SUPPORTED_SORT_ORDER 8570L -#define ERROR_DS_NAME_NOT_UNIQUE 8571L -#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572L -#define ERROR_DS_OUT_OF_VERSION_STORE 8573L -#define ERROR_DS_INCOMPATIBLE_CONTROLS_USED 8574L -#define ERROR_DS_NO_REF_DOMAIN 8575L -#define ERROR_DS_RESERVED_LINK_ID 8576L -#define ERROR_DS_LINK_ID_NOT_AVAILABLE 8577L -#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578L -#define ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE 8579L -#define ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC 8580L -#define ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG 8581L -#define ERROR_DS_MODIFYDN_WRONG_GRANDPARENT 8582L -#define ERROR_DS_NAME_ERROR_TRUST_REFERRAL 8583L -#define ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER 8584L -#define ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD 8585L -#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 8586L -#define ERROR_DS_THREAD_LIMIT_EXCEEDED 8587L -#define ERROR_DS_NOT_CLOSEST 8588L -#define ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF 8589L -#define ERROR_DS_SINGLE_USER_MODE_FAILED 8590L -#define ERROR_DS_NTDSCRIPT_SYNTAX_ERROR 8591L -#define ERROR_DS_NTDSCRIPT_PROCESS_ERROR 8592L -#define ERROR_DS_DIFFERENT_REPL_EPOCHS 8593L -#define ERROR_DS_DRS_EXTENSIONS_CHANGED 8594L -#define ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR 8595L -#define ERROR_DS_NO_MSDS_INTID 8596L -#define ERROR_DS_DUP_MSDS_INTID 8597L -#define ERROR_DS_EXISTS_IN_RDNATTID 8598L -#define ERROR_DS_AUTHORIZATION_FAILED 8599L -#define ERROR_DS_INVALID_SCRIPT 8600L -#define ERROR_DS_REMOTE_CROSSREF_OP_FAILED 8601L -#define ERROR_DS_CROSS_REF_BUSY 8602L -#define ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN 8603L -#define ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC 8604L -#define ERROR_DS_DUPLICATE_ID_FOUND 8605L -#define ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT 8606L -#define ERROR_DS_GROUP_CONVERSION_ERROR 8607L -#define ERROR_DS_CANT_MOVE_APP_BASIC_GROUP 8608L -#define ERROR_DS_CANT_MOVE_APP_QUERY_GROUP 8609L -#define ERROR_DS_ROLE_NOT_VERIFIED 8610L -#define ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL 8611L -#define ERROR_DS_DOMAIN_RENAME_IN_PROGRESS 8612L -#define ERROR_DS_EXISTING_AD_CHILD_NC 8613L -#define ERROR_DS_REPL_LIFETIME_EXCEEDED 8614L -#define ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER 8615L -#define ERROR_DS_LDAP_SEND_QUEUE_FULL 8616L -#define ERROR_DS_DRA_OUT_SCHEDULE_WINDOW 8617L -#define DNS_ERROR_RESPONSE_CODES_BASE 9000 -#define DNS_ERROR_RCODE_NO_ERROR NO_ERROR -#define DNS_ERROR_MASK 0x00002328 -#define DNS_ERROR_RCODE_FORMAT_ERROR 9001L -#define DNS_ERROR_RCODE_SERVER_FAILURE 9002L -#define DNS_ERROR_RCODE_NAME_ERROR 9003L -#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004L -#define DNS_ERROR_RCODE_REFUSED 9005L -#define DNS_ERROR_RCODE_YXDOMAIN 9006L -#define DNS_ERROR_RCODE_YXRRSET 9007L -#define DNS_ERROR_RCODE_NXRRSET 9008L -#define DNS_ERROR_RCODE_NOTAUTH 9009L -#define DNS_ERROR_RCODE_NOTZONE 9010L -#define DNS_ERROR_RCODE_BADSIG 9016L -#define DNS_ERROR_RCODE_BADKEY 9017L -#define DNS_ERROR_RCODE_BADTIME 9018L -#define DNS_ERROR_RCODE_LAST DNS_ERROR_RCODE_BADTIME -#define DNS_ERROR_PACKET_FMT_BASE 9500 -#define DNS_INFO_NO_RECORDS 9501L -#define DNS_ERROR_BAD_PACKET 9502L -#define DNS_ERROR_NO_PACKET 9503L -#define DNS_ERROR_RCODE 9504L -#define DNS_ERROR_UNSECURE_PACKET 9505L -#define DNS_STATUS_PACKET_UNSECURE DNS_ERROR_UNSECURE_PACKET -#define DNS_ERROR_NO_MEMORY ERROR_OUTOFMEMORY -#define DNS_ERROR_INVALID_NAME ERROR_INVALID_NAME -#define DNS_ERROR_INVALID_DATA ERROR_INVALID_DATA -#define DNS_ERROR_GENERAL_API_BASE 9550 -#define DNS_ERROR_INVALID_TYPE 9551L -#define DNS_ERROR_INVALID_IP_ADDRESS 9552L -#define DNS_ERROR_INVALID_PROPERTY 9553L -#define DNS_ERROR_TRY_AGAIN_LATER 9554L -#define DNS_ERROR_NOT_UNIQUE 9555L -#define DNS_ERROR_NON_RFC_NAME 9556L -#define DNS_STATUS_FQDN 9557L -#define DNS_STATUS_DOTTED_NAME 9558L -#define DNS_STATUS_SINGLE_PART_NAME 9559L -#define DNS_ERROR_INVALID_NAME_CHAR 9560L -#define DNS_ERROR_NUMERIC_NAME 9561L -#define DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER 9562L -#define DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION 9563L -#define DNS_ERROR_CANNOT_FIND_ROOT_HINTS 9564L -#define DNS_ERROR_INCONSISTENT_ROOT_HINTS 9565L -#define DNS_ERROR_ZONE_BASE 9600 -#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601L -#define DNS_ERROR_NO_ZONE_INFO 9602L -#define DNS_ERROR_INVALID_ZONE_OPERATION 9603L -#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604L -#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605L -#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606L -#define DNS_ERROR_ZONE_LOCKED 9607L -#define DNS_ERROR_ZONE_CREATION_FAILED 9608L -#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609L -#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610L -#define DNS_ERROR_INVALID_ZONE_TYPE 9611L -#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612L -#define DNS_ERROR_ZONE_NOT_SECONDARY 9613L -#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614L -#define DNS_ERROR_WINS_INIT_FAILED 9615L -#define DNS_ERROR_NEED_WINS_SERVERS 9616L -#define DNS_ERROR_NBSTAT_INIT_FAILED 9617L -#define DNS_ERROR_SOA_DELETE_INVALID 9618L -#define DNS_ERROR_FORWARDER_ALREADY_EXISTS 9619L -#define DNS_ERROR_ZONE_REQUIRES_MASTER_IP 9620L -#define DNS_ERROR_ZONE_IS_SHUTDOWN 9621L -#define DNS_ERROR_DATAFILE_BASE 9650 -#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651L -#define DNS_ERROR_INVALID_DATAFILE_NAME 9652L -#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653L -#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654L -#define DNS_ERROR_DATAFILE_PARSING 9655L -#define DNS_ERROR_DATABASE_BASE 9700 -#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701L -#define DNS_ERROR_RECORD_FORMAT 9702L -#define DNS_ERROR_NODE_CREATION_FAILED 9703L -#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704L -#define DNS_ERROR_RECORD_TIMED_OUT 9705L -#define DNS_ERROR_NAME_NOT_IN_ZONE 9706L -#define DNS_ERROR_CNAME_LOOP 9707L -#define DNS_ERROR_NODE_IS_CNAME 9708L -#define DNS_ERROR_CNAME_COLLISION 9709L -#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710L -#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711L -#define DNS_ERROR_SECONDARY_DATA 9712L -#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713L -#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714L -#define DNS_WARNING_PTR_CREATE_FAILED 9715L -#define DNS_WARNING_DOMAIN_UNDELETED 9716L -#define DNS_ERROR_DS_UNAVAILABLE 9717L -#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718L -#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719L -#define DNS_ERROR_OPERATION_BASE 9750 -#define DNS_INFO_AXFR_COMPLETE 9751L -#define DNS_ERROR_AXFR 9752L -#define DNS_INFO_ADDED_LOCAL_WINS 9753L -#define DNS_ERROR_SECURE_BASE 9800 -#define DNS_STATUS_CONTINUE_NEEDED 9801L -#define DNS_ERROR_SETUP_BASE 9850 -#define DNS_ERROR_NO_TCPIP 9851L -#define DNS_ERROR_NO_DNS_SERVERS 9852L -#define DNS_ERROR_DP_BASE 9900 -#define DNS_ERROR_DP_DOES_NOT_EXIST 9901L -#define DNS_ERROR_DP_ALREADY_EXISTS 9902L -#define DNS_ERROR_DP_NOT_ENLISTED 9903L -#define DNS_ERROR_DP_ALREADY_ENLISTED 9904L -#define DNS_ERROR_DP_NOT_AVAILABLE 9905L -#define DNS_ERROR_DP_FSMO_ERROR 9906L - -#ifndef WSABASEERR -#define WSABASEERR 10000 -#define WSAEINTR 10004L -#define WSAEBADF 10009L -#define WSAEACCES 10013L -#define WSAEFAULT 10014L -#define WSAEINVAL 10022L -#define WSAEMFILE 10024L -#define WSAEWOULDBLOCK 10035L -#define WSAEINPROGRESS 10036L -#define WSAEALREADY 10037L -#define WSAENOTSOCK 10038L -#define WSAEDESTADDRREQ 10039L -#define WSAEMSGSIZE 10040L -#define WSAEPROTOTYPE 10041L -#define WSAENOPROTOOPT 10042L -#define WSAEPROTONOSUPPORT 10043L -#define WSAESOCKTNOSUPPORT 10044L -#define WSAEOPNOTSUPP 10045L -#define WSAEPFNOSUPPORT 10046L -#define WSAEAFNOSUPPORT 10047L -#define WSAEADDRINUSE 10048L -#define WSAEADDRNOTAVAIL 10049L -#define WSAENETDOWN 10050L -#define WSAENETUNREACH 10051L -#define WSAENETRESET 10052L -#define WSAECONNABORTED 10053L -#define WSAECONNRESET 10054L -#define WSAENOBUFS 10055L -#define WSAEISCONN 10056L -#define WSAENOTCONN 10057L -#define WSAESHUTDOWN 10058L -#define WSAETOOMANYREFS 10059L -#define WSAETIMEDOUT 10060L -#define WSAECONNREFUSED 10061L -#define WSAELOOP 10062L -#define WSAENAMETOOLONG 10063L -#define WSAEHOSTDOWN 10064L -#define WSAEHOSTUNREACH 10065L -#define WSAENOTEMPTY 10066L -#define WSAEPROCLIM 10067L -#define WSAEUSERS 10068L -#define WSAEDQUOT 10069L -#define WSAESTALE 10070L -#define WSAEREMOTE 10071L -#define WSASYSNOTREADY 10091L -#define WSAVERNOTSUPPORTED 10092L -#define WSANOTINITIALISED 10093L -#define WSAEDISCON 10101L -#define WSAENOMORE 10102L -#define WSAECANCELLED 10103L -#define WSAEINVALIDPROCTABLE 10104L -#define WSAEINVALIDPROVIDER 10105L -#define WSAEPROVIDERFAILEDINIT 10106L -#define WSASYSCALLFAILURE 10107L -#define WSASERVICE_NOT_FOUND 10108L -#define WSATYPE_NOT_FOUND 10109L -#define WSA_E_NO_MORE 10110L -#define WSA_E_CANCELLED 10111L -#define WSAEREFUSED 10112L -#ifndef WSAHOST_NOT_FOUND -#define WSAHOST_NOT_FOUND 11001L -#endif -#ifndef WSATRY_AGAIN -#define WSATRY_AGAIN 11002L -#endif -#ifndef WSANO_RECOVERY -#define WSANO_RECOVERY 11003L -#endif -#ifndef WSANO_DATA -#define WSANO_DATA 11004L -#endif -#ifndef WSA_QOS_RECEIVERS -#define WSA_QOS_RECEIVERS 11005L -#endif -#ifndef WSA_QOS_SENDERS -#define WSA_QOS_SENDERS 11006L -#endif -#ifndef WSA_QOS_NO_SENDERS -#define WSA_QOS_NO_SENDERS 11007L -#endif -#ifndef WSA_QOS_NO_RECEIVERS -#define WSA_QOS_NO_RECEIVERS 11008L -#endif -#ifndef WSA_QOS_REQUEST_CONFIRMED -#define WSA_QOS_REQUEST_CONFIRMED 11009L -#endif -#ifndef WSA_QOS_ADMISSION_FAILURE -#define WSA_QOS_ADMISSION_FAILURE 11010L -#endif -#ifndef WSA_QOS_POLICY_FAILURE -#define WSA_QOS_POLICY_FAILURE 11011L -#endif -#ifndef WSA_QOS_BAD_STYLE -#define WSA_QOS_BAD_STYLE 11012L -#endif -#ifndef WSA_QOS_BAD_OBJECT -#define WSA_QOS_BAD_OBJECT 11013L -#endif -#ifndef WSA_QOS_TRAFFIC_CTRL_ERROR -#define WSA_QOS_TRAFFIC_CTRL_ERROR 11014L -#endif -#ifndef WSA_QOS_GENERIC_ERROR -#define WSA_QOS_GENERIC_ERROR 11015L -#endif -#ifndef WSA_QOS_ESERVICETYPE -#define WSA_QOS_ESERVICETYPE 11016L -#endif -#ifndef WSA_QOS_EFLOWSPEC -#define WSA_QOS_EFLOWSPEC 11017L -#endif -#ifndef WSA_QOS_EPROVSPECBUF -#define WSA_QOS_EPROVSPECBUF 11018L -#endif -#ifndef WSA_QOS_EFILTERSTYLE -#define WSA_QOS_EFILTERSTYLE 11019L -#endif -#ifndef WSA_QOS_EFILTERTYPE -#define WSA_QOS_EFILTERTYPE 11020L -#endif -#ifndef WSA_QOS_EFILTERCOUNT -#define WSA_QOS_EFILTERCOUNT 11021L -#endif -#ifndef WSA_QOS_EOBJLENGTH -#define WSA_QOS_EOBJLENGTH 11022L -#endif -#ifndef WSA_QOS_EFLOWCOUNT -#define WSA_QOS_EFLOWCOUNT 11023L -#endif -#ifndef WSA_QOS_EUNKNOWNPSOBJ -#define WSA_QOS_EUNKNOWNPSOBJ 11024L -#endif -#ifndef WSA_QOS_EPOLICYOBJ -#define WSA_QOS_EPOLICYOBJ 11025L -#endif -#ifndef WSA_QOS_EFLOWDESC -#define WSA_QOS_EFLOWDESC 11026L -#endif -#ifndef WSA_QOS_EPSFLOWSPEC -#define WSA_QOS_EPSFLOWSPEC 11027L -#endif -#ifndef WSA_QOS_EPSFILTERSPEC -#define WSA_QOS_EPSFILTERSPEC 11028L -#endif -#ifndef WSA_QOS_ESDMODEOBJ -#define WSA_QOS_ESDMODEOBJ 11029L -#endif -#ifndef WSA_QOS_ESHAPERATEOBJ -#define WSA_QOS_ESHAPERATEOBJ 11030L -#endif -#ifndef WSA_QOS_RESERVED_PETYPE -#define WSA_QOS_RESERVED_PETYPE 11031L -#endif -#endif /* WSABASEERR */ - -#define ERROR_SXS_SECTION_NOT_FOUND 14000L -#define ERROR_SXS_CANT_GEN_ACTCTX 14001L -#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002L -#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003L -#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004L -#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005L -#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006L -#define ERROR_SXS_KEY_NOT_FOUND 14007L -#define ERROR_SXS_VERSION_CONFLICT 14008L -#define ERROR_SXS_WRONG_SECTION_TYPE 14009L -#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010L -#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011L -#define ERROR_SXS_UNKNOWN_ENCODING_GROUP 14012L -#define ERROR_SXS_UNKNOWN_ENCODING 14013L -#define ERROR_SXS_INVALID_XML_NAMESPACE_URI 14014L -#define ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED 14015L -#define ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED 14016L -#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE 14017L -#define ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE 14018L -#define ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE 14019L -#define ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT 14020L -#define ERROR_SXS_DUPLICATE_DLL_NAME 14021L -#define ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME 14022L -#define ERROR_SXS_DUPLICATE_CLSID 14023L -#define ERROR_SXS_DUPLICATE_IID 14024L -#define ERROR_SXS_DUPLICATE_TLBID 14025L -#define ERROR_SXS_DUPLICATE_PROGID 14026L -#define ERROR_SXS_DUPLICATE_ASSEMBLY_NAME 14027L -#define ERROR_SXS_FILE_HASH_MISMATCH 14028L -#define ERROR_SXS_POLICY_PARSE_ERROR 14029L -#define ERROR_SXS_XML_E_MISSINGQUOTE 14030L -#define ERROR_SXS_XML_E_COMMENTSYNTAX 14031L -#define ERROR_SXS_XML_E_BADSTARTNAMECHAR 14032L -#define ERROR_SXS_XML_E_BADNAMECHAR 14033L -#define ERROR_SXS_XML_E_BADCHARINSTRING 14034L -#define ERROR_SXS_XML_E_XMLDECLSYNTAX 14035L -#define ERROR_SXS_XML_E_BADCHARDATA 14036L -#define ERROR_SXS_XML_E_MISSINGWHITESPACE 14037L -#define ERROR_SXS_XML_E_EXPECTINGTAGEND 14038L -#define ERROR_SXS_XML_E_MISSINGSEMICOLON 14039L -#define ERROR_SXS_XML_E_UNBALANCEDPAREN 14040L -#define ERROR_SXS_XML_E_INTERNALERROR 14041L -#define ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE 14042L -#define ERROR_SXS_XML_E_INCOMPLETE_ENCODING 14043L -#define ERROR_SXS_XML_E_MISSING_PAREN 14044L -#define ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE 14045L -#define ERROR_SXS_XML_E_MULTIPLE_COLONS 14046L -#define ERROR_SXS_XML_E_INVALID_DECIMAL 14047L -#define ERROR_SXS_XML_E_INVALID_HEXIDECIMAL 14048L -#define ERROR_SXS_XML_E_INVALID_UNICODE 14049L -#define ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK 14050L -#define ERROR_SXS_XML_E_UNEXPECTEDENDTAG 14051L -#define ERROR_SXS_XML_E_UNCLOSEDTAG 14052L -#define ERROR_SXS_XML_E_DUPLICATEATTRIBUTE 14053L -#define ERROR_SXS_XML_E_MULTIPLEROOTS 14054L -#define ERROR_SXS_XML_E_INVALIDATROOTLEVEL 14055L -#define ERROR_SXS_XML_E_BADXMLDECL 14056L -#define ERROR_SXS_XML_E_MISSINGROOT 14057L -#define ERROR_SXS_XML_E_UNEXPECTEDEOF 14058L -#define ERROR_SXS_XML_E_BADPEREFINSUBSET 14059L -#define ERROR_SXS_XML_E_UNCLOSEDSTARTTAG 14060L -#define ERROR_SXS_XML_E_UNCLOSEDENDTAG 14061L -#define ERROR_SXS_XML_E_UNCLOSEDSTRING 14062L -#define ERROR_SXS_XML_E_UNCLOSEDCOMMENT 14063L -#define ERROR_SXS_XML_E_UNCLOSEDDECL 14064L -#define ERROR_SXS_XML_E_UNCLOSEDCDATA 14065L -#define ERROR_SXS_XML_E_RESERVEDNAMESPACE 14066L -#define ERROR_SXS_XML_E_INVALIDENCODING 14067L -#define ERROR_SXS_XML_E_INVALIDSWITCH 14068L -#define ERROR_SXS_XML_E_BADXMLCASE 14069L -#define ERROR_SXS_XML_E_INVALID_STANDALONE 14070L -#define ERROR_SXS_XML_E_UNEXPECTED_STANDALONE 14071L -#define ERROR_SXS_XML_E_INVALID_VERSION 14072L -#define ERROR_SXS_XML_E_MISSINGEQUALS 14073L -#define ERROR_SXS_PROTECTION_RECOVERY_FAILED 14074L -#define ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT 14075L -#define ERROR_SXS_PROTECTION_CATALOG_NOT_VALID 14076L -#define ERROR_SXS_UNTRANSLATABLE_HRESULT 14077L -#define ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING 14078L -#define ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE 14079L -#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME 14080L -#define ERROR_IPSEC_QM_POLICY_EXISTS 13000L -#define ERROR_IPSEC_QM_POLICY_NOT_FOUND 13001L -#define ERROR_IPSEC_QM_POLICY_IN_USE 13002L -#define ERROR_IPSEC_MM_POLICY_EXISTS 13003L -#define ERROR_IPSEC_MM_POLICY_NOT_FOUND 13004L -#define ERROR_IPSEC_MM_POLICY_IN_USE 13005L -#define ERROR_IPSEC_MM_FILTER_EXISTS 13006L -#define ERROR_IPSEC_MM_FILTER_NOT_FOUND 13007L -#define ERROR_IPSEC_TRANSPORT_FILTER_EXISTS 13008L -#define ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND 13009L -#define ERROR_IPSEC_MM_AUTH_EXISTS 13010L -#define ERROR_IPSEC_MM_AUTH_NOT_FOUND 13011L -#define ERROR_IPSEC_MM_AUTH_IN_USE 13012L -#define ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND 13013L -#define ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND 13014L -#define ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND 13015L -#define ERROR_IPSEC_TUNNEL_FILTER_EXISTS 13016L -#define ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND 13017L -#define ERROR_IPSEC_MM_FILTER_PENDING_DELETION 13018L -#define ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION 13019L -#define ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION 13020L -#define ERROR_IPSEC_MM_POLICY_PENDING_DELETION 13021L -#define ERROR_IPSEC_MM_AUTH_PENDING_DELETION 13022L -#define ERROR_IPSEC_QM_POLICY_PENDING_DELETION 13023L -#define WARNING_IPSEC_MM_POLICY_PRUNED 13024L -#define WARNING_IPSEC_QM_POLICY_PRUNED 13025L -#define ERROR_IPSEC_IKE_NEG_STATUS_BEGIN 13800L -#define ERROR_IPSEC_IKE_AUTH_FAIL 13801L -#define ERROR_IPSEC_IKE_ATTRIB_FAIL 13802L -#define ERROR_IPSEC_IKE_NEGOTIATION_PENDING 13803L -#define ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR 13804L -#define ERROR_IPSEC_IKE_TIMED_OUT 13805L -#define ERROR_IPSEC_IKE_NO_CERT 13806L -#define ERROR_IPSEC_IKE_SA_DELETED 13807L -#define ERROR_IPSEC_IKE_SA_REAPED 13808L -#define ERROR_IPSEC_IKE_MM_ACQUIRE_DROP 13809L -#define ERROR_IPSEC_IKE_QM_ACQUIRE_DROP 13810L -#define ERROR_IPSEC_IKE_QUEUE_DROP_MM 13811L -#define ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM 13812L -#define ERROR_IPSEC_IKE_DROP_NO_RESPONSE 13813L -#define ERROR_IPSEC_IKE_MM_DELAY_DROP 13814L -#define ERROR_IPSEC_IKE_QM_DELAY_DROP 13815L -#define ERROR_IPSEC_IKE_ERROR 13816L -#define ERROR_IPSEC_IKE_CRL_FAILED 13817L -#define ERROR_IPSEC_IKE_INVALID_KEY_USAGE 13818L -#define ERROR_IPSEC_IKE_INVALID_CERT_TYPE 13819L -#define ERROR_IPSEC_IKE_NO_PRIVATE_KEY 13820L -#define ERROR_IPSEC_IKE_DH_FAIL 13822L -#define ERROR_IPSEC_IKE_INVALID_HEADER 13824L -#define ERROR_IPSEC_IKE_NO_POLICY 13825L -#define ERROR_IPSEC_IKE_INVALID_SIGNATURE 13826L -#define ERROR_IPSEC_IKE_KERBEROS_ERROR 13827L -#define ERROR_IPSEC_IKE_NO_PUBLIC_KEY 13828L -#define ERROR_IPSEC_IKE_PROCESS_ERR 13829L -#define ERROR_IPSEC_IKE_PROCESS_ERR_SA 13830L -#define ERROR_IPSEC_IKE_PROCESS_ERR_PROP 13831L -#define ERROR_IPSEC_IKE_PROCESS_ERR_TRANS 13832L -#define ERROR_IPSEC_IKE_PROCESS_ERR_KE 13833L -#define ERROR_IPSEC_IKE_PROCESS_ERR_ID 13834L -#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT 13835L -#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ 13836L -#define ERROR_IPSEC_IKE_PROCESS_ERR_HASH 13837L -#define ERROR_IPSEC_IKE_PROCESS_ERR_SIG 13838L -#define ERROR_IPSEC_IKE_PROCESS_ERR_NONCE 13839L -#define ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY 13840L -#define ERROR_IPSEC_IKE_PROCESS_ERR_DELETE 13841L -#define ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR 13842L -#define ERROR_IPSEC_IKE_INVALID_PAYLOAD 13843L -#define ERROR_IPSEC_IKE_LOAD_SOFT_SA 13844L -#define ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN 13845L -#define ERROR_IPSEC_IKE_INVALID_COOKIE 13846L -#define ERROR_IPSEC_IKE_NO_PEER_CERT 13847L -#define ERROR_IPSEC_IKE_PEER_CRL_FAILED 13848L -#define ERROR_IPSEC_IKE_POLICY_CHANGE 13849L -#define ERROR_IPSEC_IKE_NO_MM_POLICY 13850L -#define ERROR_IPSEC_IKE_NOTCBPRIV 13851L -#define ERROR_IPSEC_IKE_SECLOADFAIL 13852L -#define ERROR_IPSEC_IKE_FAILSSPINIT 13853L -#define ERROR_IPSEC_IKE_FAILQUERYSSP 13854L -#define ERROR_IPSEC_IKE_SRVACQFAIL 13855L -#define ERROR_IPSEC_IKE_SRVQUERYCRED 13856L -#define ERROR_IPSEC_IKE_GETSPIFAIL 13857L -#define ERROR_IPSEC_IKE_INVALID_FILTER 13858L -#define ERROR_IPSEC_IKE_OUT_OF_MEMORY 13859L -#define ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED 13860L -#define ERROR_IPSEC_IKE_INVALID_POLICY 13861L -#define ERROR_IPSEC_IKE_UNKNOWN_DOI 13862L -#define ERROR_IPSEC_IKE_INVALID_SITUATION 13863L -#define ERROR_IPSEC_IKE_DH_FAILURE 13864L -#define ERROR_IPSEC_IKE_INVALID_GROUP 13865L -#define ERROR_IPSEC_IKE_ENCRYPT 13866L -#define ERROR_IPSEC_IKE_DECRYPT 13867L -#define ERROR_IPSEC_IKE_POLICY_MATCH 13868L -#define ERROR_IPSEC_IKE_UNSUPPORTED_ID 13869L -#define ERROR_IPSEC_IKE_INVALID_HASH 13870L -#define ERROR_IPSEC_IKE_INVALID_HASH_ALG 13871L -#define ERROR_IPSEC_IKE_INVALID_HASH_SIZE 13872L -#define ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG 13873L -#define ERROR_IPSEC_IKE_INVALID_AUTH_ALG 13874L -#define ERROR_IPSEC_IKE_INVALID_SIG 13875L -#define ERROR_IPSEC_IKE_LOAD_FAILED 13876L -#define ERROR_IPSEC_IKE_RPC_DELETE 13877L -#define ERROR_IPSEC_IKE_BENIGN_REINIT 13878L -#define ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY 13879L -#define ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN 13881L -#define ERROR_IPSEC_IKE_MM_LIMIT 13882L -#define ERROR_IPSEC_IKE_NEGOTIATION_DISABLED 13883L -#define ERROR_IPSEC_IKE_NEG_STATUS_END 13884L -#define SEVERITY_SUCCESS 0 -#define SEVERITY_ERROR 1 -#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) -#define FAILED(hr) ((HRESULT)(hr) < 0) -#define IS_ERROR(Status) ((unsigned long)(Status) >> 31==SEVERITY_ERROR) -#define HRESULT_CODE(hr) ((hr) & 0xFFFF) -#define SCODE_CODE(sc) ((sc) & 0xFFFF) -#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) -#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) -#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) -#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) -#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) -#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) -#define FACILITY_NT_BIT 0x10000000 -#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) -#ifdef INLINE_HRESULT_FROM_WIN32 -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED -typedef long HRESULT; -#endif -__CRT_INLINE HRESULT HRESULT_FROM_WIN32(long x) { return x <= 0 ? (HRESULT)x : (HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);} -#else -#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) -#endif -#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) -#define GetScode(hr) ((SCODE) (hr)) -#define ResultFromScode(sc) ((HRESULT) (sc)) -#define PropagateResult(hrPrevious,scBase) ((HRESULT) scBase) -#ifdef RC_INVOKED -#define _HRESULT_TYPEDEF_(_sc) _sc -#else -#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) -#endif -#define NOERROR 0 -#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) -#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) -#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) -#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) -#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) -#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) -#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) -#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) -#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) -#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) -#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) -#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) -#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) -#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) -#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) -#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) -#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) -#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) -#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) -#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) -#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) -#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) -#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) -#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) -#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) -#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) -#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) -#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) -#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) -#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) -#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) -#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) -#define CO_E_LAUNCH_PERMSSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) -#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) -#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) -#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) -#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) -#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) -#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) -#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) -#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) -#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) -#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) -#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) -#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) -#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) -#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) -#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) -#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) -#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) -#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) -#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) -#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) -#define S_OK ((HRESULT)0x00000000L) -#define S_FALSE ((HRESULT)0x00000001L) -#define OLE_E_FIRST ((HRESULT)0x80040000L) -#define OLE_E_LAST ((HRESULT)0x800400FFL) -#define OLE_S_FIRST ((HRESULT)0x00040000L) -#define OLE_S_LAST ((HRESULT)0x000400FFL) -#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) -#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) -#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) -#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) -#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) -#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) -#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) -#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) -#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) -#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) -#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) -#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) -#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) -#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) -#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) -#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) -#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) -#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) -#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) -#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) -#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) -#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) -#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) -#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) -#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) -#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) -#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) -#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) -#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) -#define DRAGDROP_E_FIRST 0x80040100L -#define DRAGDROP_E_LAST 0x8004010FL -#define DRAGDROP_S_FIRST 0x00040100L -#define DRAGDROP_S_LAST 0x0004010FL -#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) -#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) -#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) -#define CLASSFACTORY_E_FIRST 0x80040110L -#define CLASSFACTORY_E_LAST 0x8004011FL -#define CLASSFACTORY_S_FIRST 0x00040110L -#define CLASSFACTORY_S_LAST 0x0004011FL -#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) -#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) -#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) -#define MARSHAL_E_FIRST 0x80040120L -#define MARSHAL_E_LAST 0x8004012FL -#define MARSHAL_S_FIRST 0x00040120L -#define MARSHAL_S_LAST 0x0004012FL -#define DATA_E_FIRST 0x80040130L -#define DATA_E_LAST 0x8004013FL -#define DATA_S_FIRST 0x00040130L -#define DATA_S_LAST 0x0004013FL -#define VIEW_E_FIRST 0x80040140L -#define VIEW_E_LAST 0x8004014FL -#define VIEW_S_FIRST 0x00040140L -#define VIEW_S_LAST 0x0004014FL -#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) -#define REGDB_E_FIRST 0x80040150L -#define REGDB_E_LAST 0x8004015FL -#define REGDB_S_FIRST 0x00040150L -#define REGDB_S_LAST 0x0004015FL -#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) -#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) -#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) -#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) -#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) -#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) -#define REGDB_E_BADTHREADINGMODEL _HRESULT_TYPEDEF_(0x80040156L) -#define CAT_E_FIRST 0x80040160L -#define CAT_E_LAST 0x80040161L -#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) -#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) -#define CS_E_FIRST 0x80040164L -#define CS_E_LAST 0x8004016FL -#define CS_E_PACKAGE_NOTFOUND _HRESULT_TYPEDEF_(0x80040164L) -#define CS_E_NOT_DELETABLE _HRESULT_TYPEDEF_(0x80040165L) -#define CS_E_CLASS_NOTFOUND _HRESULT_TYPEDEF_(0x80040166L) -#define CS_E_INVALID_VERSION _HRESULT_TYPEDEF_(0x80040167L) -#define CS_E_NO_CLASSSTORE _HRESULT_TYPEDEF_(0x80040168L) -#define CS_E_OBJECT_NOTFOUND _HRESULT_TYPEDEF_(0x80040169L) -#define CS_E_OBJECT_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x8004016AL) -#define CS_E_INVALID_PATH _HRESULT_TYPEDEF_(0x8004016BL) -#define CS_E_NETWORK_ERROR _HRESULT_TYPEDEF_(0x8004016CL) -#define CS_E_ADMIN_LIMIT_EXCEEDED _HRESULT_TYPEDEF_(0x8004016DL) -#define CS_E_SCHEMA_MISMATCH _HRESULT_TYPEDEF_(0x8004016EL) -#define CS_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x8004016FL) -#define CACHE_E_FIRST 0x80040170L -#define CACHE_E_LAST 0x8004017FL -#define CACHE_S_FIRST 0x00040170L -#define CACHE_S_LAST 0x0004017FL -#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) -#define OLEOBJ_E_FIRST 0x80040180L -#define OLEOBJ_E_LAST 0x8004018FL -#define OLEOBJ_S_FIRST 0x00040180L -#define OLEOBJ_S_LAST 0x0004018FL -#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) -#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) -#define CLIENTSITE_E_FIRST 0x80040190L -#define CLIENTSITE_E_LAST 0x8004019FL -#define CLIENTSITE_S_FIRST 0x00040190L -#define CLIENTSITE_S_LAST 0x0004019FL -#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) -#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) -#define INPLACE_E_FIRST 0x800401A0L -#define INPLACE_E_LAST 0x800401AFL -#define INPLACE_S_FIRST 0x000401A0L -#define INPLACE_S_LAST 0x000401AFL -#define ENUM_E_FIRST 0x800401B0L -#define ENUM_E_LAST 0x800401BFL -#define ENUM_S_FIRST 0x000401B0L -#define ENUM_S_LAST 0x000401BFL -#define CONVERT10_E_FIRST 0x800401C0L -#define CONVERT10_E_LAST 0x800401CFL -#define CONVERT10_S_FIRST 0x000401C0L -#define CONVERT10_S_LAST 0x000401CFL -#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) -#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) -#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) -#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) -#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) -#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) -#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) -#define CLIPBRD_E_FIRST 0x800401D0L -#define CLIPBRD_E_LAST 0x800401DFL -#define CLIPBRD_S_FIRST 0x000401D0L -#define CLIPBRD_S_LAST 0x000401DFL -#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) -#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) -#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) -#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) -#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) -#define MK_E_FIRST 0x800401E0L -#define MK_E_LAST 0x800401EFL -#define MK_S_FIRST 0x000401E0L -#define MK_S_LAST 0x000401EFL -#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) -#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) -#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) -#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) -#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) -#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) -#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) -#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) -#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) -#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) -#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) -#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) -#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) -#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) -#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) -#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) -#define CO_E_FIRST 0x800401F0L -#define CO_E_LAST 0x800401FFL -#define CO_S_FIRST 0x000401F0L -#define CO_S_LAST 0x000401FFL -#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) -#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) -#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) -#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) -#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) -#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) -#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) -#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) -#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) -#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) -#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) -#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) -#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) -#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) -#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) -#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) -#define EVENT_E_FIRST 0x80040200L -#define EVENT_E_LAST 0x8004021FL -#define EVENT_S_FIRST 0x00040200L -#define EVENT_S_LAST 0x0004021FL -#define EVENT_S_SOME_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x00040200L) -#define EVENT_E_ALL_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x80040201L) -#define EVENT_S_NOSUBSCRIBERS _HRESULT_TYPEDEF_(0x00040202L) -#define EVENT_E_QUERYSYNTAX _HRESULT_TYPEDEF_(0x80040203L) -#define EVENT_E_QUERYFIELD _HRESULT_TYPEDEF_(0x80040204L) -#define EVENT_E_INTERNALEXCEPTION _HRESULT_TYPEDEF_(0x80040205L) -#define EVENT_E_INTERNALERROR _HRESULT_TYPEDEF_(0x80040206L) -#define EVENT_E_INVALID_PER_USER_SID _HRESULT_TYPEDEF_(0x80040207L) -#define EVENT_E_USER_EXCEPTION _HRESULT_TYPEDEF_(0x80040208L) -#define EVENT_E_TOO_MANY_METHODS _HRESULT_TYPEDEF_(0x80040209L) -#define EVENT_E_MISSING_EVENTCLASS _HRESULT_TYPEDEF_(0x8004020AL) -#define EVENT_E_NOT_ALL_REMOVED _HRESULT_TYPEDEF_(0x8004020BL) -#define EVENT_E_COMPLUS_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004020CL) -#define EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020DL) -#define EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020EL) -#define EVENT_E_INVALID_EVENT_CLASS_PARTITION _HRESULT_TYPEDEF_(0x8004020FL) -#define EVENT_E_PER_USER_SID_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80040210L) -#define XACT_E_FIRST 0x8004D000 -#define XACT_E_LAST 0x8004D029 -#define XACT_S_FIRST 0x0004D000 -#define XACT_S_LAST 0x0004D010 -#define XACT_E_ALREADYOTHERSINGLEPHASE _HRESULT_TYPEDEF_(0x8004D000L) -#define XACT_E_CANTRETAIN _HRESULT_TYPEDEF_(0x8004D001L) -#define XACT_E_COMMITFAILED _HRESULT_TYPEDEF_(0x8004D002L) -#define XACT_E_COMMITPREVENTED _HRESULT_TYPEDEF_(0x8004D003L) -#define XACT_E_HEURISTICABORT _HRESULT_TYPEDEF_(0x8004D004L) -#define XACT_E_HEURISTICCOMMIT _HRESULT_TYPEDEF_(0x8004D005L) -#define XACT_E_HEURISTICDAMAGE _HRESULT_TYPEDEF_(0x8004D006L) -#define XACT_E_HEURISTICDANGER _HRESULT_TYPEDEF_(0x8004D007L) -#define XACT_E_ISOLATIONLEVEL _HRESULT_TYPEDEF_(0x8004D008L) -#define XACT_E_NOASYNC _HRESULT_TYPEDEF_(0x8004D009L) -#define XACT_E_NOENLIST _HRESULT_TYPEDEF_(0x8004D00AL) -#define XACT_E_NOISORETAIN _HRESULT_TYPEDEF_(0x8004D00BL) -#define XACT_E_NORESOURCE _HRESULT_TYPEDEF_(0x8004D00CL) -#define XACT_E_NOTCURRENT _HRESULT_TYPEDEF_(0x8004D00DL) -#define XACT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004D00EL) -#define XACT_E_NOTSUPPORTED _HRESULT_TYPEDEF_(0x8004D00FL) -#define XACT_E_UNKNOWNRMGRID _HRESULT_TYPEDEF_(0x8004D010L) -#define XACT_E_WRONGSTATE _HRESULT_TYPEDEF_(0x8004D011L) -#define XACT_E_WRONGUOW _HRESULT_TYPEDEF_(0x8004D012L) -#define XACT_E_XTIONEXISTS _HRESULT_TYPEDEF_(0x8004D013L) -#define XACT_E_NOIMPORTOBJECT _HRESULT_TYPEDEF_(0x8004D014L) -#define XACT_E_INVALIDCOOKIE _HRESULT_TYPEDEF_(0x8004D015L) -#define XACT_E_INDOUBT _HRESULT_TYPEDEF_(0x8004D016L) -#define XACT_E_NOTIMEOUT _HRESULT_TYPEDEF_(0x8004D017L) -#define XACT_E_ALREADYINPROGRESS _HRESULT_TYPEDEF_(0x8004D018L) -#define XACT_E_ABORTED _HRESULT_TYPEDEF_(0x8004D019L) -#define XACT_E_LOGFULL _HRESULT_TYPEDEF_(0x8004D01AL) -#define XACT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D01BL) -#define XACT_E_CONNECTION_DOWN _HRESULT_TYPEDEF_(0x8004D01CL) -#define XACT_E_CONNECTION_DENIED _HRESULT_TYPEDEF_(0x8004D01DL) -#define XACT_E_REENLISTTIMEOUT _HRESULT_TYPEDEF_(0x8004D01EL) -#define XACT_E_TIP_CONNECT_FAILED _HRESULT_TYPEDEF_(0x8004D01FL) -#define XACT_E_TIP_PROTOCOL_ERROR _HRESULT_TYPEDEF_(0x8004D020L) -#define XACT_E_TIP_PULL_FAILED _HRESULT_TYPEDEF_(0x8004D021L) -#define XACT_E_DEST_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D022L) -#define XACT_E_TIP_DISABLED _HRESULT_TYPEDEF_(0x8004D023L) -#define XACT_E_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D024L) -#define XACT_E_PARTNER_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D025L) -#define XACT_E_XA_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D026L) -#define XACT_E_UNABLE_TO_READ_DTC_CONFIG _HRESULT_TYPEDEF_(0x8004D027L) -#define XACT_E_UNABLE_TO_LOAD_DTC_PROXY _HRESULT_TYPEDEF_(0x8004D028L) -#define XACT_E_ABORTING _HRESULT_TYPEDEF_(0x8004D029L) -#define XACT_E_CLERKNOTFOUND _HRESULT_TYPEDEF_(0x8004D080L) -#define XACT_E_CLERKEXISTS _HRESULT_TYPEDEF_(0x8004D081L) -#define XACT_E_RECOVERYINPROGRESS _HRESULT_TYPEDEF_(0x8004D082L) -#define XACT_E_TRANSACTIONCLOSED _HRESULT_TYPEDEF_(0x8004D083L) -#define XACT_E_INVALIDLSN _HRESULT_TYPEDEF_(0x8004D084L) -#define XACT_E_REPLAYREQUEST _HRESULT_TYPEDEF_(0x8004D085L) -#define XACT_S_ASYNC _HRESULT_TYPEDEF_(0x0004D000L) -#define XACT_S_DEFECT _HRESULT_TYPEDEF_(0x0004D001L) -#define XACT_S_READONLY _HRESULT_TYPEDEF_(0x0004D002L) -#define XACT_S_SOMENORETAIN _HRESULT_TYPEDEF_(0x0004D003L) -#define XACT_S_OKINFORM _HRESULT_TYPEDEF_(0x0004D004L) -#define XACT_S_MADECHANGESCONTENT _HRESULT_TYPEDEF_(0x0004D005L) -#define XACT_S_MADECHANGESINFORM _HRESULT_TYPEDEF_(0x0004D006L) -#define XACT_S_ALLNORETAIN _HRESULT_TYPEDEF_(0x0004D007L) -#define XACT_S_ABORTING _HRESULT_TYPEDEF_(0x0004D008L) -#define XACT_S_SINGLEPHASE _HRESULT_TYPEDEF_(0x0004D009L) -#define XACT_S_LOCALLY_OK _HRESULT_TYPEDEF_(0x0004D00AL) -#define XACT_S_LASTRESOURCEMANAGER _HRESULT_TYPEDEF_(0x0004D010L) -#define CONTEXT_E_FIRST 0x8004E000L -#define CONTEXT_E_LAST 0x8004E02FL -#define CONTEXT_S_FIRST 0x0004E000L -#define CONTEXT_S_LAST 0x0004E02FL -#define CONTEXT_E_ABORTED _HRESULT_TYPEDEF_(0x8004E002L) -#define CONTEXT_E_ABORTING _HRESULT_TYPEDEF_(0x8004E003L) -#define CONTEXT_E_NOCONTEXT _HRESULT_TYPEDEF_(0x8004E004L) -#define CONTEXT_E_WOULD_DEADLOCK _HRESULT_TYPEDEF_(0x8004E005L) -#define CONTEXT_E_SYNCH_TIMEOUT _HRESULT_TYPEDEF_(0x8004E006L) -#define CONTEXT_E_OLDREF _HRESULT_TYPEDEF_(0x8004E007L) -#define CONTEXT_E_ROLENOTFOUND _HRESULT_TYPEDEF_(0x8004E00CL) -#define CONTEXT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004E00FL) -#define CO_E_ACTIVATIONFAILED _HRESULT_TYPEDEF_(0x8004E021L) -#define CO_E_ACTIVATIONFAILED_EVENTLOGGED _HRESULT_TYPEDEF_(0x8004E022L) -#define CO_E_ACTIVATIONFAILED_CATALOGERROR _HRESULT_TYPEDEF_(0x8004E023L) -#define CO_E_ACTIVATIONFAILED_TIMEOUT _HRESULT_TYPEDEF_(0x8004E024L) -#define CO_E_INITIALIZATIONFAILED _HRESULT_TYPEDEF_(0x8004E025L) -#define CONTEXT_E_NOJIT _HRESULT_TYPEDEF_(0x8004E026L) -#define CONTEXT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004E027L) -#define CO_E_THREADINGMODEL_CHANGED _HRESULT_TYPEDEF_(0x8004E028L) -#define CO_E_NOIISINTRINSICS _HRESULT_TYPEDEF_(0x8004E029L) -#define CO_E_NOCOOKIES _HRESULT_TYPEDEF_(0x8004E02AL) -#define CO_E_DBERROR _HRESULT_TYPEDEF_(0x8004E02BL) -#define CO_E_NOTPOOLED _HRESULT_TYPEDEF_(0x8004E02CL) -#define CO_E_NOTCONSTRUCTED _HRESULT_TYPEDEF_(0x8004E02DL) -#define CO_E_NOSYNCHRONIZATION _HRESULT_TYPEDEF_(0x8004E02EL) -#define CO_E_ISOLEVELMISMATCH _HRESULT_TYPEDEF_(0x8004E02FL) -#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) -#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) -#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) -#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) -#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) -#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) -#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) -#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) -#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) -#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) -#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) -#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) -#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) -#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) -#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) -#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) -#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) -#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) -#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) -#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) -#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) -#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) -#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) -#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) -#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) -#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) -#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) -#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) -#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) -#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) -#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) -#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) -#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) -#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) -#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) -#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) -#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) -#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) -#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) -#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) -#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) -#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) -#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) -#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) -#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) -#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) -#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) -#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) -#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) -#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) -#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) -#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) -#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) -#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) -#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) -#define CO_S_MACHINENAMENOTFOUND _HRESULT_TYPEDEF_(0x00080013L) -#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) -#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) -#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) -#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) -#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) -#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) -#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) -#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) -#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) -#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) -#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) -#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) -#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) -#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) -#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) -#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) -#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) -#define DISP_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80020013L) -#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) -#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) -#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) -#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) -#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) -#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) -#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) -#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) -#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) -#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) -#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) -#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) -#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) -#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) -#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) -#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) -#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) -#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) -#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) -#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) -#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) -#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) -#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) -#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) -#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) -#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) -#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) -#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) -#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) -#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) -#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) -#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) -#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) -#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) -#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) -#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) -#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) -#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) -#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) -#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) -#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) -#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) -#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) -#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) -#define STG_E_PROPSETMISMATCHED _HRESULT_TYPEDEF_(0x800300F0L) -#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) -#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) -#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) -#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) -#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) -#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) -#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) -#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) -#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) -#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) -#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) -#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) -#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) -#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) -#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) -#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) -#define STG_E_BADBASEADDRESS _HRESULT_TYPEDEF_(0x80030110L) -#define STG_E_DOCFILETOOLARGE _HRESULT_TYPEDEF_(0x80030111L) -#define STG_E_NOTSIMPLEFORMAT _HRESULT_TYPEDEF_(0x80030112L) -#define STG_E_INCOMPLETE _HRESULT_TYPEDEF_(0x80030201L) -#define STG_E_TERMINATED _HRESULT_TYPEDEF_(0x80030202L) -#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) -#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) -#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) -#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) -#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) -#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) -#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) -#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) -#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) -#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) -#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) -#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) -#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) -#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) -#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) -#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) -#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) -#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) -#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) -#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) -#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) -#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) -#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) -#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) -#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) -#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) -#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) -#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) -#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) -#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) -#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) -#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) -#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) -#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) -#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) -#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) -#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) -#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) -#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) -#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) -#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) -#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) -#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) -#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) -#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) -#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) -#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) -#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) -#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) -#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) -#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) -#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) -#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) -#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) -#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) -#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) -#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) -#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) -#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) -#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) -#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) -#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) -#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) -#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) -#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) -#define RPC_E_FULLSIC_REQUIRED _HRESULT_TYPEDEF_(0x80010121L) -#define RPC_E_INVALID_STD_NAME _HRESULT_TYPEDEF_(0x80010122L) -#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80010123L) -#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80010124L) -#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80010125L) -#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80010126L) -#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80010127L) -#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80010128L) -#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80010129L) -#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x8001012AL) -#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x8001012BL) -#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x8001012CL) -#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8001012DL) -#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8001012EL) -#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8001012FL) -#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x80010130L) -#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x80010131L) -#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x80010132L) -#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80010133L) -#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80010134L) -#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80010135L) -#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80010136L) -#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80010137L) -#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80010138L) -#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80010139L) -#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x8001013AL) -#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x8001013BL) -#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x8001013CL) -#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8001013DL) -#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8001013FL) -#define CO_E_CANCEL_DISABLED _HRESULT_TYPEDEF_(0x80010140L) -#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) -#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) -#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) -#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) -#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) -#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) -#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) -#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) -#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) -#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) -#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) -#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) -#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) -#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) -#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) -#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) -#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) -#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) -#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) -#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) -#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) -#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) -#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) -#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) -#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) -#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) -#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) -#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) -#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) -#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) -#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) -#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) -#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) -#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) -#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) -#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) -#define NTE_SILENT_CONTEXT _HRESULT_TYPEDEF_(0x80090022L) -#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) -#define NTE_TEMPORARY_PROFILE _HRESULT_TYPEDEF_(0x80090024L) -#define NTE_FIXEDPARAMETER _HRESULT_TYPEDEF_(0x80090025L) -#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) -#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) -#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) -#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) -#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) -#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) -#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) -#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) -#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) -#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) -#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) -#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) -#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) -#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) -#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) -#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) -#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) -#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) -#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) -#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) -#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) -#define SEC_I_LOCAL_LOGON _HRESULT_TYPEDEF_(0x00090315L) -#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) -#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) -#define SEC_I_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x00090317L) -#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) -#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) -#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) -#define SEC_I_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x00090320L) -#define SEC_I_RENEGOTIATE _HRESULT_TYPEDEF_(0x00090321L) -#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) -#define SEC_I_NO_LSA_CONTEXT _HRESULT_TYPEDEF_(0x00090323L) -#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) -#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) -#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) -#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) -#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) -#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) -#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) -#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) -#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) -#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) -#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) -#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) -#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) -#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) -#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) -#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) -#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) -#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) -#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) -#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) -#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) -#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) -#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) -#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) -#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) -#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) -#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) -#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) -#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) -#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) -#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) -#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) -#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) -#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) -#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) -#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) -#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) -#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) -#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) -#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) -#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) -#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) -#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) -#define SEC_E_NO_SPM SEC_E_INTERNAL_ERROR -#define SEC_E_NOT_SUPPORTED SEC_E_UNSUPPORTED_FUNCTION -#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) -#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) -#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) -#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) -#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) -#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) -#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) -#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) -#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) -#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) -#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) -#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) -#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) -#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) -#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) -#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) -#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) -#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x00091012L) -#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) -#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) -#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) -#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) -#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) -#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) -#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) -#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) -#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) -#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) -#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) -#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) -#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) -#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) -#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) -#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) -#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) -#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) -#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) -#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) -#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) -#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) -#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) -#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) -#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) -#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) -#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) -#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) -#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) -#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) -#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) -#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) -#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) -#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) -#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) -#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) -#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) -#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) -#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) -#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) -#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) -#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) -#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) -#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) -#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) -#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) -#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) -#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) -#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) -#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) -#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) -#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) -#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) -#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) -#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) -#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) -#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) -#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) -#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) -#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) -#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) -#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) -#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) -#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) -#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) -#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) -#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) -#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) -#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) -#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) -#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) -#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) -#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) -#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) -#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) -#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) -#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) -#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) -#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) -#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) -#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) -#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) -#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) -#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) -#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) -#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) -#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) -#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) -#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) -#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) -#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) -#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) -#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) -#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) -#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) -#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) -#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) -#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) -#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) -#define CERTSRV_E_BAD_REQUESTSUBJECT _HRESULT_TYPEDEF_(0x80094001L) -#define CERTSRV_E_NO_REQUEST _HRESULT_TYPEDEF_(0x80094002L) -#define CERTSRV_E_BAD_REQUESTSTATUS _HRESULT_TYPEDEF_(0x80094003L) -#define CERTSRV_E_PROPERTY_EMPTY _HRESULT_TYPEDEF_(0x80094004L) -#define CERTSRV_E_INVALID_CA_CERTIFICATE _HRESULT_TYPEDEF_(0x80094005L) -#define CERTSRV_E_SERVER_SUSPENDED _HRESULT_TYPEDEF_(0x80094006L) -#define CERTSRV_E_ENCODING_LENGTH _HRESULT_TYPEDEF_(0x80094007L) -#define CERTSRV_E_ROLECONFLICT _HRESULT_TYPEDEF_(0x80094008L) -#define CERTSRV_E_RESTRICTEDOFFICER _HRESULT_TYPEDEF_(0x80094009L) -#define CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x8009400AL) -#define CERTSRV_E_NO_VALID_KRA _HRESULT_TYPEDEF_(0x8009400BL) -#define CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL _HRESULT_TYPEDEF_(0x8009400CL) -#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL) -#define CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE _HRESULT_TYPEDEF_(0x8009400EL) -#define CERTSRV_E_NO_DB_SESSIONS _HRESULT_TYPEDEF_(0x8009400FL) -#define CERTSRV_E_ALIGNMENT_FAULT _HRESULT_TYPEDEF_(0x80094010L) -#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L) -#define CERTSRV_E_TEMPLATE_DENIED _HRESULT_TYPEDEF_(0x80094012L) -#define CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE _HRESULT_TYPEDEF_(0x80094013L) -#define CERTSRV_E_UNSUPPORTED_CERT_TYPE _HRESULT_TYPEDEF_(0x80094800L) -#define CERTSRV_E_NO_CERT_TYPE _HRESULT_TYPEDEF_(0x80094801L) -#define CERTSRV_E_TEMPLATE_CONFLICT _HRESULT_TYPEDEF_(0x80094802L) -#define CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED _HRESULT_TYPEDEF_(0x80094803L) -#define CERTSRV_E_ARCHIVED_KEY_REQUIRED _HRESULT_TYPEDEF_(0x80094804L) -#define CERTSRV_E_SMIME_REQUIRED _HRESULT_TYPEDEF_(0x80094805L) -#define CERTSRV_E_BAD_RENEWAL_SUBJECT _HRESULT_TYPEDEF_(0x80094806L) -#define CERTSRV_E_BAD_TEMPLATE_VERSION _HRESULT_TYPEDEF_(0x80094807L) -#define CERTSRV_E_TEMPLATE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094808L) -#define CERTSRV_E_SIGNATURE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094809L) -#define CERTSRV_E_SIGNATURE_COUNT _HRESULT_TYPEDEF_(0x8009480AL) -#define CERTSRV_E_SIGNATURE_REJECTED _HRESULT_TYPEDEF_(0x8009480BL) -#define CERTSRV_E_ISSUANCE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x8009480CL) -#define CERTSRV_E_SUBJECT_UPN_REQUIRED _HRESULT_TYPEDEF_(0x8009480DL) -#define CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED _HRESULT_TYPEDEF_(0x8009480EL) -#define CERTSRV_E_SUBJECT_DNS_REQUIRED _HRESULT_TYPEDEF_(0x8009480FL) -#define CERTSRV_E_ARCHIVED_KEY_UNEXPECTED _HRESULT_TYPEDEF_(0x80094810L) -#define CERTSRV_E_KEY_LENGTH _HRESULT_TYPEDEF_(0x80094811L) -#define CERTSRV_E_SUBJECT_EMAIL_REQUIRED _HRESULT_TYPEDEF_(0x80094812L) -#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094813L) -#define CERTSRV_E_CERT_TYPE_OVERLAP _HRESULT_TYPEDEF_(0x80094814L) -#define XENROLL_E_KEY_NOT_EXPORTABLE _HRESULT_TYPEDEF_(0x80095000L) -#define XENROLL_E_CANNOT_ADD_ROOT_CERT _HRESULT_TYPEDEF_(0x80095001L) -#define XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND _HRESULT_TYPEDEF_(0x80095002L) -#define XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH _HRESULT_TYPEDEF_(0x80095003L) -#define XENROLL_E_RESPONSE_KA_HASH_MISMATCH _HRESULT_TYPEDEF_(0x80095004L) -#define XENROLL_E_KEYSPEC_SMIME_MISMATCH _HRESULT_TYPEDEF_(0x80095005L) -#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) -#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) -#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) -#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) -#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) -#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) -#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) -#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) -#define MSSIPOTF_E_OUTOFMEMRANGE _HRESULT_TYPEDEF_(0x80097001L) -#define MSSIPOTF_E_CANTGETOBJECT _HRESULT_TYPEDEF_(0x80097002L) -#define MSSIPOTF_E_NOHEADTABLE _HRESULT_TYPEDEF_(0x80097003L) -#define MSSIPOTF_E_BAD_MAGICNUMBER _HRESULT_TYPEDEF_(0x80097004L) -#define MSSIPOTF_E_BAD_OFFSET_TABLE _HRESULT_TYPEDEF_(0x80097005L) -#define MSSIPOTF_E_TABLE_TAGORDER _HRESULT_TYPEDEF_(0x80097006L) -#define MSSIPOTF_E_TABLE_LONGWORD _HRESULT_TYPEDEF_(0x80097007L) -#define MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT _HRESULT_TYPEDEF_(0x80097008L) -#define MSSIPOTF_E_TABLES_OVERLAP _HRESULT_TYPEDEF_(0x80097009L) -#define MSSIPOTF_E_TABLE_PADBYTES _HRESULT_TYPEDEF_(0x8009700AL) -#define MSSIPOTF_E_FILETOOSMALL _HRESULT_TYPEDEF_(0x8009700BL) -#define MSSIPOTF_E_TABLE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700CL) -#define MSSIPOTF_E_FILE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700DL) -#define MSSIPOTF_E_FAILED_POLICY _HRESULT_TYPEDEF_(0x80097010L) -#define MSSIPOTF_E_FAILED_HINTS_CHECK _HRESULT_TYPEDEF_(0x80097011L) -#define MSSIPOTF_E_NOT_OPENTYPE _HRESULT_TYPEDEF_(0x80097012L) -#define MSSIPOTF_E_FILE _HRESULT_TYPEDEF_(0x80097013L) -#define MSSIPOTF_E_CRYPT _HRESULT_TYPEDEF_(0x80097014L) -#define MSSIPOTF_E_BADVERSION _HRESULT_TYPEDEF_(0x80097015L) -#define MSSIPOTF_E_DSIG_STRUCTURE _HRESULT_TYPEDEF_(0x80097016L) -#define MSSIPOTF_E_PCONST_CHECK _HRESULT_TYPEDEF_(0x80097017L) -#define MSSIPOTF_E_STRUCTURE _HRESULT_TYPEDEF_(0x80097018L) -#define NTE_OP_OK 0 -#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) -#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) -#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) -#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) -#define DIGSIG_E_ENCODE _HRESULT_TYPEDEF_(0x800B0005L) -#define DIGSIG_E_DECODE _HRESULT_TYPEDEF_(0x800B0006L) -#define DIGSIG_E_EXTENSIBILITY _HRESULT_TYPEDEF_(0x800B0007L) -#define DIGSIG_E_CRYPTO _HRESULT_TYPEDEF_(0x800B0008L) -#define PERSIST_E_SIZEDEFINITE _HRESULT_TYPEDEF_(0x800B0009L) -#define PERSIST_E_SIZEINDEFINITE _HRESULT_TYPEDEF_(0x800B000AL) -#define PERSIST_E_NOTSELFSIZING _HRESULT_TYPEDEF_(0x800B000BL) -#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) -#define CERT_E_EXPIRED _HRESULT_TYPEDEF_(0x800B0101L) -#define CERT_E_VALIDITYPERIODNESTING _HRESULT_TYPEDEF_(0x800B0102L) -#define CERT_E_ROLE _HRESULT_TYPEDEF_(0x800B0103L) -#define CERT_E_PATHLENCONST _HRESULT_TYPEDEF_(0x800B0104L) -#define CERT_E_CRITICAL _HRESULT_TYPEDEF_(0x800B0105L) -#define CERT_E_PURPOSE _HRESULT_TYPEDEF_(0x800B0106L) -#define CERT_E_ISSUERCHAINING _HRESULT_TYPEDEF_(0x800B0107L) -#define CERT_E_MALFORMED _HRESULT_TYPEDEF_(0x800B0108L) -#define CERT_E_UNTRUSTEDROOT _HRESULT_TYPEDEF_(0x800B0109L) -#define CERT_E_CHAINING _HRESULT_TYPEDEF_(0x800B010AL) -#define TRUST_E_FAIL _HRESULT_TYPEDEF_(0x800B010BL) -#define CERT_E_REVOKED _HRESULT_TYPEDEF_(0x800B010CL) -#define CERT_E_UNTRUSTEDTESTROOT _HRESULT_TYPEDEF_(0x800B010DL) -#define CERT_E_REVOCATION_FAILURE _HRESULT_TYPEDEF_(0x800B010EL) -#define CERT_E_CN_NO_MATCH _HRESULT_TYPEDEF_(0x800B010FL) -#define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) -#define TRUST_E_EXPLICIT_DISTRUST _HRESULT_TYPEDEF_(0x800B0111L) -#define CERT_E_UNTRUSTEDCA _HRESULT_TYPEDEF_(0x800B0112L) -#define CERT_E_INVALID_POLICY _HRESULT_TYPEDEF_(0x800B0113L) -#define CERT_E_INVALID_NAME _HRESULT_TYPEDEF_(0x800B0114L) -#define HRESULT_FROM_SETUPAPI(x) ((((x) & (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR))==(APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR)) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_SETUPAPI << 16) | 0x80000000)) : HRESULT_FROM_WIN32(x)) -#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) -#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) -#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) -#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) -#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) -#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) -#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) -#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) -#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) -#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) -#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) -#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) -#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) -#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) -#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) -#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) -#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) -#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) -#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) -#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) -#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) -#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) -#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) -#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) -#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) -#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) -#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) -#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) -#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) -#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) -#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) -#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) -#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) -#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) -#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) -#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) -#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) -#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) -#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) -#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) -#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) -#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) -#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) -#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) -#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) -#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) -#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) -#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) -#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) -#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) -#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) -#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) -#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) -#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) -#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) -#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) -#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) -#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) -#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) -#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) -#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) -#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) -#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) -#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) -#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) -#define SPAPI_E_UNKNOWN_EXCEPTION _HRESULT_TYPEDEF_(0x800F0239L) -#define SPAPI_E_PNP_REGISTRY_ERROR _HRESULT_TYPEDEF_(0x800F023AL) -#define SPAPI_E_REMOTE_REQUEST_UNSUPPORTED _HRESULT_TYPEDEF_(0x800F023BL) -#define SPAPI_E_NOT_AN_INSTALLED_OEM_INF _HRESULT_TYPEDEF_(0x800F023CL) -#define SPAPI_E_INF_IN_USE_BY_DEVICES _HRESULT_TYPEDEF_(0x800F023DL) -#define SPAPI_E_DI_FUNCTION_OBSOLETE _HRESULT_TYPEDEF_(0x800F023EL) -#define SPAPI_E_NO_AUTHENTICODE_CATALOG _HRESULT_TYPEDEF_(0x800F023FL) -#define SPAPI_E_AUTHENTICODE_DISALLOWED _HRESULT_TYPEDEF_(0x800F0240L) -#define SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER _HRESULT_TYPEDEF_(0x800F0241L) -#define SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x800F0242L) -#define SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800F0243L) -#define SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH _HRESULT_TYPEDEF_(0x800F0244L) -#define SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE _HRESULT_TYPEDEF_(0x800F0245L) -#define SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW _HRESULT_TYPEDEF_(0x800F0300L) -#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) -#define SCARD_S_SUCCESS NO_ERROR -#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) -#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) -#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) -#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) -#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) -#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) -#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) -#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) -#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) -#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) -#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) -#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) -#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) -#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) -#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) -#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) -#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) -#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) -#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) -#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) -#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) -#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) -#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) -#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) -#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) -#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) -#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) -#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) -#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) -#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) -#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) -#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) -#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) -#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) -#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) -#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) -#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) -#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) -#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) -#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) -#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) -#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) -#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) -#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) -#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) -#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) -#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) -#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) -#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) -#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) -#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) -#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) -#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) -#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) -#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) -#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) -#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) -#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) -#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) -#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) -#define COMADMIN_E_OBJECTERRORS _HRESULT_TYPEDEF_(0x80110401L) -#define COMADMIN_E_OBJECTINVALID _HRESULT_TYPEDEF_(0x80110402L) -#define COMADMIN_E_KEYMISSING _HRESULT_TYPEDEF_(0x80110403L) -#define COMADMIN_E_ALREADYINSTALLED _HRESULT_TYPEDEF_(0x80110404L) -#define COMADMIN_E_APP_FILE_WRITEFAIL _HRESULT_TYPEDEF_(0x80110407L) -#define COMADMIN_E_APP_FILE_READFAIL _HRESULT_TYPEDEF_(0x80110408L) -#define COMADMIN_E_APP_FILE_VERSION _HRESULT_TYPEDEF_(0x80110409L) -#define COMADMIN_E_BADPATH _HRESULT_TYPEDEF_(0x8011040AL) -#define COMADMIN_E_APPLICATIONEXISTS _HRESULT_TYPEDEF_(0x8011040BL) -#define COMADMIN_E_ROLEEXISTS _HRESULT_TYPEDEF_(0x8011040CL) -#define COMADMIN_E_CANTCOPYFILE _HRESULT_TYPEDEF_(0x8011040DL) -#define COMADMIN_E_NOUSER _HRESULT_TYPEDEF_(0x8011040FL) -#define COMADMIN_E_INVALIDUSERIDS _HRESULT_TYPEDEF_(0x80110410L) -#define COMADMIN_E_NOREGISTRYCLSID _HRESULT_TYPEDEF_(0x80110411L) -#define COMADMIN_E_BADREGISTRYPROGID _HRESULT_TYPEDEF_(0x80110412L) -#define COMADMIN_E_AUTHENTICATIONLEVEL _HRESULT_TYPEDEF_(0x80110413L) -#define COMADMIN_E_USERPASSWDNOTVALID _HRESULT_TYPEDEF_(0x80110414L) -#define COMADMIN_E_CLSIDORIIDMISMATCH _HRESULT_TYPEDEF_(0x80110418L) -#define COMADMIN_E_REMOTEINTERFACE _HRESULT_TYPEDEF_(0x80110419L) -#define COMADMIN_E_DLLREGISTERSERVER _HRESULT_TYPEDEF_(0x8011041AL) -#define COMADMIN_E_NOSERVERSHARE _HRESULT_TYPEDEF_(0x8011041BL) -#define COMADMIN_E_DLLLOADFAILED _HRESULT_TYPEDEF_(0x8011041DL) -#define COMADMIN_E_BADREGISTRYLIBID _HRESULT_TYPEDEF_(0x8011041EL) -#define COMADMIN_E_APPDIRNOTFOUND _HRESULT_TYPEDEF_(0x8011041FL) -#define COMADMIN_E_REGISTRARFAILED _HRESULT_TYPEDEF_(0x80110423L) -#define COMADMIN_E_COMPFILE_DOESNOTEXIST _HRESULT_TYPEDEF_(0x80110424L) -#define COMADMIN_E_COMPFILE_LOADDLLFAIL _HRESULT_TYPEDEF_(0x80110425L) -#define COMADMIN_E_COMPFILE_GETCLASSOBJ _HRESULT_TYPEDEF_(0x80110426L) -#define COMADMIN_E_COMPFILE_CLASSNOTAVAIL _HRESULT_TYPEDEF_(0x80110427L) -#define COMADMIN_E_COMPFILE_BADTLB _HRESULT_TYPEDEF_(0x80110428L) -#define COMADMIN_E_COMPFILE_NOTINSTALLABLE _HRESULT_TYPEDEF_(0x80110429L) -#define COMADMIN_E_NOTCHANGEABLE _HRESULT_TYPEDEF_(0x8011042AL) -#define COMADMIN_E_NOTDELETEABLE _HRESULT_TYPEDEF_(0x8011042BL) -#define COMADMIN_E_SESSION _HRESULT_TYPEDEF_(0x8011042CL) -#define COMADMIN_E_COMP_MOVE_LOCKED _HRESULT_TYPEDEF_(0x8011042DL) -#define COMADMIN_E_COMP_MOVE_BAD_DEST _HRESULT_TYPEDEF_(0x8011042EL) -#define COMADMIN_E_REGISTERTLB _HRESULT_TYPEDEF_(0x80110430L) -#define COMADMIN_E_SYSTEMAPP _HRESULT_TYPEDEF_(0x80110433L) -#define COMADMIN_E_COMPFILE_NOREGISTRAR _HRESULT_TYPEDEF_(0x80110434L) -#define COMADMIN_E_COREQCOMPINSTALLED _HRESULT_TYPEDEF_(0x80110435L) -#define COMADMIN_E_SERVICENOTINSTALLED _HRESULT_TYPEDEF_(0x80110436L) -#define COMADMIN_E_PROPERTYSAVEFAILED _HRESULT_TYPEDEF_(0x80110437L) -#define COMADMIN_E_OBJECTEXISTS _HRESULT_TYPEDEF_(0x80110438L) -#define COMADMIN_E_COMPONENTEXISTS _HRESULT_TYPEDEF_(0x80110439L) -#define COMADMIN_E_REGFILE_CORRUPT _HRESULT_TYPEDEF_(0x8011043BL) -#define COMADMIN_E_PROPERTY_OVERFLOW _HRESULT_TYPEDEF_(0x8011043CL) -#define COMADMIN_E_NOTINREGISTRY _HRESULT_TYPEDEF_(0x8011043EL) -#define COMADMIN_E_OBJECTNOTPOOLABLE _HRESULT_TYPEDEF_(0x8011043FL) -#define COMADMIN_E_APPLID_MATCHES_CLSID _HRESULT_TYPEDEF_(0x80110446L) -#define COMADMIN_E_ROLE_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110447L) -#define COMADMIN_E_START_APP_NEEDS_COMPONENTS _HRESULT_TYPEDEF_(0x80110448L) -#define COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM _HRESULT_TYPEDEF_(0x80110449L) -#define COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY _HRESULT_TYPEDEF_(0x8011044AL) -#define COMADMIN_E_CAN_NOT_START_APP _HRESULT_TYPEDEF_(0x8011044BL) -#define COMADMIN_E_CAN_NOT_EXPORT_SYS_APP _HRESULT_TYPEDEF_(0x8011044CL) -#define COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT _HRESULT_TYPEDEF_(0x8011044DL) -#define COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER _HRESULT_TYPEDEF_(0x8011044EL) -#define COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE _HRESULT_TYPEDEF_(0x8011044FL) -#define COMADMIN_E_BASE_PARTITION_ONLY _HRESULT_TYPEDEF_(0x80110450L) -#define COMADMIN_E_START_APP_DISABLED _HRESULT_TYPEDEF_(0x80110451L) -#define COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110457L) -#define COMADMIN_E_CAT_INVALID_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110458L) -#define COMADMIN_E_CAT_PARTITION_IN_USE _HRESULT_TYPEDEF_(0x80110459L) -#define COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES _HRESULT_TYPEDEF_(0x8011045AL) -#define COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED _HRESULT_TYPEDEF_(0x8011045BL) -#define COMADMIN_E_AMBIGUOUS_APPLICATION_NAME _HRESULT_TYPEDEF_(0x8011045CL) -#define COMADMIN_E_AMBIGUOUS_PARTITION_NAME _HRESULT_TYPEDEF_(0x8011045DL) -#define COMADMIN_E_REGDB_NOTINITIALIZED _HRESULT_TYPEDEF_(0x80110472L) -#define COMADMIN_E_REGDB_NOTOPEN _HRESULT_TYPEDEF_(0x80110473L) -#define COMADMIN_E_REGDB_SYSTEMERR _HRESULT_TYPEDEF_(0x80110474L) -#define COMADMIN_E_REGDB_ALREADYRUNNING _HRESULT_TYPEDEF_(0x80110475L) -#define COMADMIN_E_MIG_VERSIONNOTSUPPORTED _HRESULT_TYPEDEF_(0x80110480L) -#define COMADMIN_E_MIG_SCHEMANOTFOUND _HRESULT_TYPEDEF_(0x80110481L) -#define COMADMIN_E_CAT_BITNESSMISMATCH _HRESULT_TYPEDEF_(0x80110482L) -#define COMADMIN_E_CAT_UNACCEPTABLEBITNESS _HRESULT_TYPEDEF_(0x80110483L) -#define COMADMIN_E_CAT_WRONGAPPBITNESS _HRESULT_TYPEDEF_(0x80110484L) -#define COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80110485L) -#define COMADMIN_E_CAT_SERVERFAULT _HRESULT_TYPEDEF_(0x80110486L) -#define COMQC_E_APPLICATION_NOT_QUEUED _HRESULT_TYPEDEF_(0x80110600L) -#define COMQC_E_NO_QUEUEABLE_INTERFACES _HRESULT_TYPEDEF_(0x80110601L) -#define COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80110602L) -#define COMQC_E_NO_IPERSISTSTREAM _HRESULT_TYPEDEF_(0x80110603L) -#define COMQC_E_BAD_MESSAGE _HRESULT_TYPEDEF_(0x80110604L) -#define COMQC_E_UNAUTHENTICATED _HRESULT_TYPEDEF_(0x80110605L) -#define COMQC_E_UNTRUSTED_ENQUEUER _HRESULT_TYPEDEF_(0x80110606L) -#define MSDTC_E_DUPLICATE_RESOURCE _HRESULT_TYPEDEF_(0x80110701L) -#define COMADMIN_E_OBJECT_PARENT_MISSING _HRESULT_TYPEDEF_(0x80110808L) -#define COMADMIN_E_OBJECT_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110809L) -#define COMADMIN_E_APP_NOT_RUNNING _HRESULT_TYPEDEF_(0x8011080AL) -#define COMADMIN_E_INVALID_PARTITION _HRESULT_TYPEDEF_(0x8011080BL) -#define COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE _HRESULT_TYPEDEF_(0x8011080DL) -#define COMADMIN_E_USER_IN_SET _HRESULT_TYPEDEF_(0x8011080EL) -#define COMADMIN_E_CANTRECYCLELIBRARYAPPS _HRESULT_TYPEDEF_(0x8011080FL) -#define COMADMIN_E_CANTRECYCLESERVICEAPPS _HRESULT_TYPEDEF_(0x80110811L) -#define COMADMIN_E_PROCESSALREADYRECYCLED _HRESULT_TYPEDEF_(0x80110812L) -#define COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED _HRESULT_TYPEDEF_(0x80110813L) -#define COMADMIN_E_CANTMAKEINPROCSERVICE _HRESULT_TYPEDEF_(0x80110814L) -#define COMADMIN_E_PROGIDINUSEBYCLSID _HRESULT_TYPEDEF_(0x80110815L) -#define COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET _HRESULT_TYPEDEF_(0x80110816L) -#define COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED _HRESULT_TYPEDEF_(0x80110817L) -#define COMADMIN_E_PARTITION_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110818L) -#define COMADMIN_E_PARTITION_MSI_ONLY _HRESULT_TYPEDEF_(0x80110819L) -#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT _HRESULT_TYPEDEF_(0x8011081AL) -#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS _HRESULT_TYPEDEF_(0x8011081BL) -#define COMADMIN_E_COMP_MOVE_SOURCE _HRESULT_TYPEDEF_(0x8011081CL) -#define COMADMIN_E_COMP_MOVE_DEST _HRESULT_TYPEDEF_(0x8011081DL) -#define COMADMIN_E_COMP_MOVE_PRIVATE _HRESULT_TYPEDEF_(0x8011081EL) -#define COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET _HRESULT_TYPEDEF_(0x8011081FL) -#define COMADMIN_E_CANNOT_ALIAS_EVENTCLASS _HRESULT_TYPEDEF_(0x80110820L) -#define COMADMIN_E_PRIVATE_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110821L) -#define COMADMIN_E_SAFERINVALID _HRESULT_TYPEDEF_(0x80110822L) -#define COMADMIN_E_REGISTRY_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110823L) -#define COMADMIN_E_PARTITIONS_DISABLED _HRESULT_TYPEDEF_(0x80110824L) -#endif /* _WINERROR_ */ diff --git a/tinyc/win32/include/winapi/wingdi.h b/tinyc/win32/include/winapi/wingdi.h deleted file mode 100644 index 63d389178..000000000 --- a/tinyc/win32/include/winapi/wingdi.h +++ /dev/null @@ -1,4080 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINGDI_ -#define _WINGDI_ - -#define WINGDIAPI DECLSPEC_IMPORT -#define WINSPOOLAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#ifndef NOGDI -#ifndef NORASTEROPS -#define R2_BLACK 1 -#define R2_NOTMERGEPEN 2 -#define R2_MASKNOTPEN 3 -#define R2_NOTCOPYPEN 4 -#define R2_MASKPENNOT 5 -#define R2_NOT 6 -#define R2_XORPEN 7 -#define R2_NOTMASKPEN 8 -#define R2_MASKPEN 9 -#define R2_NOTXORPEN 10 -#define R2_NOP 11 -#define R2_MERGENOTPEN 12 -#define R2_COPYPEN 13 -#define R2_MERGEPENNOT 14 -#define R2_MERGEPEN 15 -#define R2_WHITE 16 -#define R2_LAST 16 - -#define SRCCOPY (DWORD)0x00CC0020 -#define SRCPAINT (DWORD)0x00EE0086 -#define SRCAND (DWORD)0x008800C6 -#define SRCINVERT (DWORD)0x00660046 -#define SRCERASE (DWORD)0x00440328 -#define NOTSRCCOPY (DWORD)0x00330008 -#define NOTSRCERASE (DWORD)0x001100A6 -#define MERGECOPY (DWORD)0x00C000CA -#define MERGEPAINT (DWORD)0x00BB0226 -#define PATCOPY (DWORD)0x00F00021 -#define PATPAINT (DWORD)0x00FB0A09 -#define PATINVERT (DWORD)0x005A0049 -#define DSTINVERT (DWORD)0x00550009 -#define BLACKNESS (DWORD)0x00000042 -#define WHITENESS (DWORD)0x00FF0062 -#define NOMIRRORBITMAP (DWORD)0x80000000 -#define CAPTUREBLT (DWORD)0x40000000 -#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) -#endif - -#define GDI_ERROR (0xFFFFFFFFL) -#define HGDI_ERROR (LongToHandle(0xFFFFFFFFL)) - -#define ERROR 0 -#define NULLREGION 1 -#define SIMPLEREGION 2 -#define COMPLEXREGION 3 -#define RGN_ERROR ERROR - -#define RGN_AND 1 -#define RGN_OR 2 -#define RGN_XOR 3 -#define RGN_DIFF 4 -#define RGN_COPY 5 -#define RGN_MIN RGN_AND -#define RGN_MAX RGN_COPY - -#define BLACKONWHITE 1 -#define WHITEONBLACK 2 -#define COLORONCOLOR 3 -#define HALFTONE 4 -#define MAXSTRETCHBLTMODE 4 - -#define STRETCH_ANDSCANS BLACKONWHITE -#define STRETCH_ORSCANS WHITEONBLACK -#define STRETCH_DELETESCANS COLORONCOLOR -#define STRETCH_HALFTONE HALFTONE - -#define ALTERNATE 1 -#define WINDING 2 -#define POLYFILL_LAST 2 - -#define LAYOUT_RTL 0x00000001 -#define LAYOUT_BTT 0x00000002 -#define LAYOUT_VBH 0x00000004 -#define LAYOUT_ORIENTATIONMASK (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) -#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 - -#define TA_NOUPDATECP 0 -#define TA_UPDATECP 1 - -#define TA_LEFT 0 -#define TA_RIGHT 2 -#define TA_CENTER 6 - -#define TA_TOP 0 -#define TA_BOTTOM 8 -#define TA_BASELINE 24 -#define TA_RTLREADING 256 -#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) - -#define VTA_BASELINE TA_BASELINE -#define VTA_LEFT TA_BOTTOM -#define VTA_RIGHT TA_TOP -#define VTA_CENTER TA_CENTER -#define VTA_BOTTOM TA_RIGHT -#define VTA_TOP TA_LEFT - -#define ETO_OPAQUE 0x0002 -#define ETO_CLIPPED 0x0004 -#define ETO_GLYPH_INDEX 0x0010 -#define ETO_RTLREADING 0x0080 -#define ETO_NUMERICSLOCAL 0x0400 -#define ETO_NUMERICSLATIN 0x0800 -#define ETO_IGNORELANGUAGE 0x1000 -#define ETO_PDY 0x2000 - -#define ASPECT_FILTERING 0x0001 - -#define DCB_RESET 0x0001 -#define DCB_ACCUMULATE 0x0002 -#define DCB_DIRTY DCB_ACCUMULATE -#define DCB_SET (DCB_RESET | DCB_ACCUMULATE) -#define DCB_ENABLE 0x0004 -#define DCB_DISABLE 0x0008 - -#ifndef NOMETAFILE - -#define META_SETBKCOLOR 0x0201 -#define META_SETBKMODE 0x0102 -#define META_SETMAPMODE 0x0103 -#define META_SETROP2 0x0104 -#define META_SETRELABS 0x0105 -#define META_SETPOLYFILLMODE 0x0106 -#define META_SETSTRETCHBLTMODE 0x0107 -#define META_SETTEXTCHAREXTRA 0x0108 -#define META_SETTEXTCOLOR 0x0209 -#define META_SETTEXTJUSTIFICATION 0x020A -#define META_SETWINDOWORG 0x020B -#define META_SETWINDOWEXT 0x020C -#define META_SETVIEWPORTORG 0x020D -#define META_SETVIEWPORTEXT 0x020E -#define META_OFFSETWINDOWORG 0x020F -#define META_SCALEWINDOWEXT 0x0410 -#define META_OFFSETVIEWPORTORG 0x0211 -#define META_SCALEVIEWPORTEXT 0x0412 -#define META_LINETO 0x0213 -#define META_MOVETO 0x0214 -#define META_EXCLUDECLIPRECT 0x0415 -#define META_INTERSECTCLIPRECT 0x0416 -#define META_ARC 0x0817 -#define META_ELLIPSE 0x0418 -#define META_FLOODFILL 0x0419 -#define META_PIE 0x081A -#define META_RECTANGLE 0x041B -#define META_ROUNDRECT 0x061C -#define META_PATBLT 0x061D -#define META_SAVEDC 0x001E -#define META_SETPIXEL 0x041F -#define META_OFFSETCLIPRGN 0x0220 -#define META_TEXTOUT 0x0521 -#define META_BITBLT 0x0922 -#define META_STRETCHBLT 0x0B23 -#define META_POLYGON 0x0324 -#define META_POLYLINE 0x0325 -#define META_ESCAPE 0x0626 -#define META_RESTOREDC 0x0127 -#define META_FILLREGION 0x0228 -#define META_FRAMEREGION 0x0429 -#define META_INVERTREGION 0x012A -#define META_PAINTREGION 0x012B -#define META_SELECTCLIPREGION 0x012C -#define META_SELECTOBJECT 0x012D -#define META_SETTEXTALIGN 0x012E -#define META_CHORD 0x0830 -#define META_SETMAPPERFLAGS 0x0231 -#define META_EXTTEXTOUT 0x0a32 -#define META_SETDIBTODEV 0x0d33 -#define META_SELECTPALETTE 0x0234 -#define META_REALIZEPALETTE 0x0035 -#define META_ANIMATEPALETTE 0x0436 -#define META_SETPALENTRIES 0x0037 -#define META_POLYPOLYGON 0x0538 -#define META_RESIZEPALETTE 0x0139 -#define META_DIBBITBLT 0x0940 -#define META_DIBSTRETCHBLT 0x0b41 -#define META_DIBCREATEPATTERNBRUSH 0x0142 -#define META_STRETCHDIB 0x0f43 -#define META_EXTFLOODFILL 0x0548 -#define META_SETLAYOUT 0x0149 -#define META_DELETEOBJECT 0x01f0 -#define META_CREATEPALETTE 0x00f7 -#define META_CREATEPATTERNBRUSH 0x01F9 -#define META_CREATEPENINDIRECT 0x02FA -#define META_CREATEFONTINDIRECT 0x02FB -#define META_CREATEBRUSHINDIRECT 0x02FC -#define META_CREATEREGION 0x06FF - - typedef struct _DRAWPATRECT { - POINT ptPosition; - POINT ptSize; - WORD wStyle; - WORD wPattern; - } DRAWPATRECT,*PDRAWPATRECT; -#endif - -#define NEWFRAME 1 -#define ABORTDOC 2 -#define NEXTBAND 3 -#define SETCOLORTABLE 4 -#define GETCOLORTABLE 5 -#define FLUSHOUTPUT 6 -#define DRAFTMODE 7 -#define QUERYESCSUPPORT 8 -#define SETABORTPROC 9 -#define STARTDOC 10 -#define ENDDOC 11 -#define GETPHYSPAGESIZE 12 -#define GETPRINTINGOFFSET 13 -#define GETSCALINGFACTOR 14 -#define MFCOMMENT 15 -#define GETPENWIDTH 16 -#define SETCOPYCOUNT 17 -#define SELECTPAPERSOURCE 18 -#define DEVICEDATA 19 -#define PASSTHROUGH 19 -#define GETTECHNOLGY 20 -#define GETTECHNOLOGY 20 -#define SETLINECAP 21 -#define SETLINEJOIN 22 -#define SETMITERLIMIT 23 -#define BANDINFO 24 -#define DRAWPATTERNRECT 25 -#define GETVECTORPENSIZE 26 -#define GETVECTORBRUSHSIZE 27 -#define ENABLEDUPLEX 28 -#define GETSETPAPERBINS 29 -#define GETSETPRINTORIENT 30 -#define ENUMPAPERBINS 31 -#define SETDIBSCALING 32 -#define EPSPRINTING 33 -#define ENUMPAPERMETRICS 34 -#define GETSETPAPERMETRICS 35 -#define POSTSCRIPT_DATA 37 -#define POSTSCRIPT_IGNORE 38 -#define MOUSETRAILS 39 -#define GETDEVICEUNITS 42 - -#define GETEXTENDEDTEXTMETRICS 256 -#define GETEXTENTTABLE 257 -#define GETPAIRKERNTABLE 258 -#define GETTRACKKERNTABLE 259 -#define EXTTEXTOUT 512 -#define GETFACENAME 513 -#define DOWNLOADFACE 514 -#define ENABLERELATIVEWIDTHS 768 -#define ENABLEPAIRKERNING 769 -#define SETKERNTRACK 770 -#define SETALLJUSTVALUES 771 -#define SETCHARSET 772 - -#define STRETCHBLT 2048 -#define METAFILE_DRIVER 2049 -#define GETSETSCREENPARAMS 3072 -#define QUERYDIBSUPPORT 3073 -#define BEGIN_PATH 4096 -#define CLIP_TO_PATH 4097 -#define END_PATH 4098 -#define EXT_DEVICE_CAPS 4099 -#define RESTORE_CTM 4100 -#define SAVE_CTM 4101 -#define SET_ARC_DIRECTION 4102 -#define SET_BACKGROUND_COLOR 4103 -#define SET_POLY_MODE 4104 -#define SET_SCREEN_ANGLE 4105 -#define SET_SPREAD 4106 -#define TRANSFORM_CTM 4107 -#define SET_CLIP_BOX 4108 -#define SET_BOUNDS 4109 -#define SET_MIRROR_MODE 4110 -#define OPENCHANNEL 4110 -#define DOWNLOADHEADER 4111 -#define CLOSECHANNEL 4112 -#define POSTSCRIPT_PASSTHROUGH 4115 -#define ENCAPSULATED_POSTSCRIPT 4116 - -#define POSTSCRIPT_IDENTIFY 4117 -#define POSTSCRIPT_INJECTION 4118 - -#define CHECKJPEGFORMAT 4119 -#define CHECKPNGFORMAT 4120 - -#define GET_PS_FEATURESETTING 4121 - -#define SPCLPASSTHROUGH2 4568 - -#define PSIDENT_GDICENTRIC 0 -#define PSIDENT_PSCENTRIC 1 - - typedef struct _PSINJECTDATA { - DWORD DataBytes; - WORD InjectionPoint; - WORD PageNumber; - } PSINJECTDATA,*PPSINJECTDATA; - -#define PSINJECT_BEGINSTREAM 1 -#define PSINJECT_PSADOBE 2 -#define PSINJECT_PAGESATEND 3 -#define PSINJECT_PAGES 4 - -#define PSINJECT_DOCNEEDEDRES 5 -#define PSINJECT_DOCSUPPLIEDRES 6 -#define PSINJECT_PAGEORDER 7 -#define PSINJECT_ORIENTATION 8 -#define PSINJECT_BOUNDINGBOX 9 -#define PSINJECT_DOCUMENTPROCESSCOLORS 10 - -#define PSINJECT_COMMENTS 11 -#define PSINJECT_BEGINDEFAULTS 12 -#define PSINJECT_ENDDEFAULTS 13 -#define PSINJECT_BEGINPROLOG 14 -#define PSINJECT_ENDPROLOG 15 -#define PSINJECT_BEGINSETUP 16 -#define PSINJECT_ENDSETUP 17 -#define PSINJECT_TRAILER 18 -#define PSINJECT_EOF 19 -#define PSINJECT_ENDSTREAM 20 -#define PSINJECT_DOCUMENTPROCESSCOLORSATEND 21 - -#define PSINJECT_PAGENUMBER 100 -#define PSINJECT_BEGINPAGESETUP 101 -#define PSINJECT_ENDPAGESETUP 102 -#define PSINJECT_PAGETRAILER 103 -#define PSINJECT_PLATECOLOR 104 - -#define PSINJECT_SHOWPAGE 105 -#define PSINJECT_PAGEBBOX 106 -#define PSINJECT_ENDPAGECOMMENTS 107 - -#define PSINJECT_VMSAVE 200 -#define PSINJECT_VMRESTORE 201 - -#define FEATURESETTING_NUP 0 -#define FEATURESETTING_OUTPUT 1 -#define FEATURESETTING_PSLEVEL 2 -#define FEATURESETTING_CUSTPAPER 3 -#define FEATURESETTING_MIRROR 4 -#define FEATURESETTING_NEGATIVE 5 -#define FEATURESETTING_PROTOCOL 6 - -#define FEATURESETTING_PRIVATE_BEGIN 0x1000 -#define FEATURESETTING_PRIVATE_END 0x1FFF - - typedef struct _PSFEATURE_OUTPUT { - WINBOOL bPageIndependent; - WINBOOL bSetPageDevice; - } PSFEATURE_OUTPUT,*PPSFEATURE_OUTPUT; - - typedef struct _PSFEATURE_CUSTPAPER { - LONG lOrientation; - LONG lWidth; - LONG lHeight; - LONG lWidthOffset; - LONG lHeightOffset; - } PSFEATURE_CUSTPAPER,*PPSFEATURE_CUSTPAPER; - -#define PSPROTOCOL_ASCII 0 -#define PSPROTOCOL_BCP 1 -#define PSPROTOCOL_TBCP 2 -#define PSPROTOCOL_BINARY 3 - -#define QDI_SETDIBITS 1 -#define QDI_GETDIBITS 2 -#define QDI_DIBTOSCREEN 4 -#define QDI_STRETCHDIB 8 - -#define SP_NOTREPORTED 0x4000 -#define SP_ERROR (-1) -#define SP_APPABORT (-2) -#define SP_USERABORT (-3) -#define SP_OUTOFDISK (-4) -#define SP_OUTOFMEMORY (-5) - -#define PR_JOBSTATUS 0x0000 - -#define OBJ_PEN 1 -#define OBJ_BRUSH 2 -#define OBJ_DC 3 -#define OBJ_METADC 4 -#define OBJ_PAL 5 -#define OBJ_FONT 6 -#define OBJ_BITMAP 7 -#define OBJ_REGION 8 -#define OBJ_METAFILE 9 -#define OBJ_MEMDC 10 -#define OBJ_EXTPEN 11 -#define OBJ_ENHMETADC 12 -#define OBJ_ENHMETAFILE 13 -#define OBJ_COLORSPACE 14 - -#define MWT_IDENTITY 1 -#define MWT_LEFTMULTIPLY 2 -#define MWT_RIGHTMULTIPLY 3 - -#define MWT_MIN MWT_IDENTITY -#define MWT_MAX MWT_RIGHTMULTIPLY - -#define _XFORM_ - typedef struct tagXFORM { - FLOAT eM11; - FLOAT eM12; - FLOAT eM21; - FLOAT eM22; - FLOAT eDx; - FLOAT eDy; - } XFORM,*PXFORM,*LPXFORM; - - typedef struct tagBITMAP { - LONG bmType; - LONG bmWidth; - LONG bmHeight; - LONG bmWidthBytes; - WORD bmPlanes; - WORD bmBitsPixel; - LPVOID bmBits; - } BITMAP,*PBITMAP,*NPBITMAP,*LPBITMAP; - -#include - typedef struct tagRGBTRIPLE { - BYTE rgbtBlue; - BYTE rgbtGreen; - BYTE rgbtRed; - } RGBTRIPLE; -#include - - typedef struct tagRGBQUAD { - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; - BYTE rgbReserved; - } RGBQUAD; - typedef RGBQUAD *LPRGBQUAD; - -#define CS_ENABLE 0x00000001L -#define CS_DISABLE 0x00000002L -#define CS_DELETE_TRANSFORM 0x00000003L - -//!__TINYC__: #define LCS_SIGNATURE 'PSOC' -//!__TINYC__: #define LCS_sRGB 'sRGB' -//!__TINYC__: #define LCS_WINDOWS_COLOR_SPACE 'Win ' - - typedef LONG LCSCSTYPE; -#define LCS_CALIBRATED_RGB 0x00000000L - - typedef LONG LCSGAMUTMATCH; -#define LCS_GM_BUSINESS 0x00000001L -#define LCS_GM_GRAPHICS 0x00000002L -#define LCS_GM_IMAGES 0x00000004L -#define LCS_GM_ABS_COLORIMETRIC 0x00000008L - -#define CM_OUT_OF_GAMUT 255 -#define CM_IN_GAMUT 0 - -#define ICM_ADDPROFILE 1 -#define ICM_DELETEPROFILE 2 -#define ICM_QUERYPROFILE 3 -#define ICM_SETDEFAULTPROFILE 4 -#define ICM_REGISTERICMATCHER 5 -#define ICM_UNREGISTERICMATCHER 6 -#define ICM_QUERYMATCH 7 - -#define GetKValue(cmyk) ((BYTE)(cmyk)) -#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) -#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) -#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) - -#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) - - typedef long FXPT16DOT16,*LPFXPT16DOT16; - typedef long FXPT2DOT30,*LPFXPT2DOT30; - - typedef struct tagCIEXYZ { - FXPT2DOT30 ciexyzX; - FXPT2DOT30 ciexyzY; - FXPT2DOT30 ciexyzZ; - } CIEXYZ; - typedef CIEXYZ *LPCIEXYZ; - - typedef struct tagICEXYZTRIPLE { - CIEXYZ ciexyzRed; - CIEXYZ ciexyzGreen; - CIEXYZ ciexyzBlue; - } CIEXYZTRIPLE; - - typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE; - - typedef struct tagLOGCOLORSPACEA { - DWORD lcsSignature; - DWORD lcsVersion; - DWORD lcsSize; - LCSCSTYPE lcsCSType; - LCSGAMUTMATCH lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - DWORD lcsGammaRed; - DWORD lcsGammaGreen; - DWORD lcsGammaBlue; - CHAR lcsFilename[MAX_PATH]; - } LOGCOLORSPACEA,*LPLOGCOLORSPACEA; - - typedef struct tagLOGCOLORSPACEW { - DWORD lcsSignature; - DWORD lcsVersion; - DWORD lcsSize; - LCSCSTYPE lcsCSType; - LCSGAMUTMATCH lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - DWORD lcsGammaRed; - DWORD lcsGammaGreen; - DWORD lcsGammaBlue; - WCHAR lcsFilename[MAX_PATH]; - } LOGCOLORSPACEW,*LPLOGCOLORSPACEW; - -#ifdef UNICODE - typedef LOGCOLORSPACEW LOGCOLORSPACE; - typedef LPLOGCOLORSPACEW LPLOGCOLORSPACE; -#else - typedef LOGCOLORSPACEA LOGCOLORSPACE; - typedef LPLOGCOLORSPACEA LPLOGCOLORSPACE; -#endif - - typedef struct tagBITMAPCOREHEADER { - DWORD bcSize; - WORD bcWidth; - WORD bcHeight; - WORD bcPlanes; - WORD bcBitCount; - } BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER; - - typedef struct tagBITMAPINFOHEADER { - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; - } BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; - - typedef struct { - DWORD bV4Size; - LONG bV4Width; - LONG bV4Height; - WORD bV4Planes; - WORD bV4BitCount; - DWORD bV4V4Compression; - DWORD bV4SizeImage; - LONG bV4XPelsPerMeter; - LONG bV4YPelsPerMeter; - DWORD bV4ClrUsed; - DWORD bV4ClrImportant; - DWORD bV4RedMask; - DWORD bV4GreenMask; - DWORD bV4BlueMask; - DWORD bV4AlphaMask; - DWORD bV4CSType; - CIEXYZTRIPLE bV4Endpoints; - DWORD bV4GammaRed; - DWORD bV4GammaGreen; - DWORD bV4GammaBlue; - } BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER; - - typedef struct { - DWORD bV5Size; - LONG bV5Width; - LONG bV5Height; - WORD bV5Planes; - WORD bV5BitCount; - DWORD bV5Compression; - DWORD bV5SizeImage; - LONG bV5XPelsPerMeter; - LONG bV5YPelsPerMeter; - DWORD bV5ClrUsed; - DWORD bV5ClrImportant; - DWORD bV5RedMask; - DWORD bV5GreenMask; - DWORD bV5BlueMask; - DWORD bV5AlphaMask; - DWORD bV5CSType; - CIEXYZTRIPLE bV5Endpoints; - DWORD bV5GammaRed; - DWORD bV5GammaGreen; - DWORD bV5GammaBlue; - DWORD bV5Intent; - DWORD bV5ProfileData; - DWORD bV5ProfileSize; - DWORD bV5Reserved; - } BITMAPV5HEADER,*LPBITMAPV5HEADER,*PBITMAPV5HEADER; - -//!__TINYC__: #define PROFILE_LINKED 'LINK' -//!__TINYC__: #define PROFILE_EMBEDDED 'MBED' - -#define BI_RGB 0L -#define BI_RLE8 1L -#define BI_RLE4 2L -#define BI_BITFIELDS 3L -#define BI_JPEG 4L -#define BI_PNG 5L - - typedef struct tagBITMAPINFO { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; - } BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO; - - typedef struct tagBITMAPCOREINFO { - BITMAPCOREHEADER bmciHeader; - RGBTRIPLE bmciColors[1]; - } BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO; - -#include - typedef struct tagBITMAPFILEHEADER { - WORD bfType; - DWORD bfSize; - WORD bfReserved1; - WORD bfReserved2; - DWORD bfOffBits; - } BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; -#include - -#define MAKEPOINTS(l) (*((POINTS *)&(l))) - -#ifndef NOFONTSIG - typedef struct tagFONTSIGNATURE { - DWORD fsUsb[4]; - DWORD fsCsb[2]; - } FONTSIGNATURE,*PFONTSIGNATURE,*LPFONTSIGNATURE; - - typedef struct tagCHARSETINFO { - UINT ciCharset; - UINT ciACP; - FONTSIGNATURE fs; - } CHARSETINFO,*PCHARSETINFO,*NPCHARSETINFO,*LPCHARSETINFO; - -#define TCI_SRCCHARSET 1 -#define TCI_SRCCODEPAGE 2 -#define TCI_SRCFONTSIG 3 -#define TCI_SRCLOCALE 0x1000 - - typedef struct tagLOCALESIGNATURE { - DWORD lsUsb[4]; - DWORD lsCsbDefault[2]; - DWORD lsCsbSupported[2]; - } LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE; -#endif - - -#ifndef NOMETAFILE - typedef struct tagHANDLETABLE { - HGDIOBJ objectHandle[1]; - } HANDLETABLE,*PHANDLETABLE,*LPHANDLETABLE; - - typedef struct tagMETARECORD { - DWORD rdSize; - WORD rdFunction; - WORD rdParm[1]; - } METARECORD; - typedef struct tagMETARECORD UNALIGNED *PMETARECORD; - typedef struct tagMETARECORD UNALIGNED *LPMETARECORD; - - typedef struct tagMETAFILEPICT { - LONG mm; - LONG xExt; - LONG yExt; - HMETAFILE hMF; - } METAFILEPICT,*LPMETAFILEPICT; - -#include - typedef struct tagMETAHEADER { - WORD mtType; - WORD mtHeaderSize; - WORD mtVersion; - DWORD mtSize; - WORD mtNoObjects; - DWORD mtMaxRecord; - WORD mtNoParameters; - } METAHEADER; - typedef struct tagMETAHEADER UNALIGNED *PMETAHEADER; - typedef struct tagMETAHEADER UNALIGNED *LPMETAHEADER; - -#include - - typedef struct tagENHMETARECORD { - DWORD iType; - DWORD nSize; - DWORD dParm[1]; - } ENHMETARECORD,*PENHMETARECORD,*LPENHMETARECORD; - - typedef struct tagENHMETAHEADER { - DWORD iType; - DWORD nSize; - RECTL rclBounds; - RECTL rclFrame; - DWORD dSignature; - DWORD nVersion; - DWORD nBytes; - DWORD nRecords; - WORD nHandles; - WORD sReserved; - DWORD nDescription; - DWORD offDescription; - DWORD nPalEntries; - SIZEL szlDevice; - SIZEL szlMillimeters; - DWORD cbPixelFormat; - DWORD offPixelFormat; - DWORD bOpenGL; - SIZEL szlMicrometers; - } ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER; -#endif - -#ifndef NOTEXTMETRIC -#define TMPF_FIXED_PITCH 0x01 -#define TMPF_VECTOR 0x02 -#define TMPF_DEVICE 0x08 -#define TMPF_TRUETYPE 0x04 - -#ifdef UNICODE - typedef WCHAR BCHAR; -#else - typedef BYTE BCHAR; -#endif - -#ifndef _TEXTMETRIC_DEFINED -#define _TEXTMETRIC_DEFINED - typedef struct tagTEXTMETRICA { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - BYTE tmFirstChar; - BYTE tmLastChar; - BYTE tmDefaultChar; - BYTE tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - } TEXTMETRICA,*PTEXTMETRICA,*NPTEXTMETRICA,*LPTEXTMETRICA; - - typedef struct tagTEXTMETRICW { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - WCHAR tmFirstChar; - WCHAR tmLastChar; - WCHAR tmDefaultChar; - WCHAR tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - } TEXTMETRICW,*PTEXTMETRICW,*NPTEXTMETRICW,*LPTEXTMETRICW; -#ifdef UNICODE - typedef TEXTMETRICW TEXTMETRIC; - typedef PTEXTMETRICW PTEXTMETRIC; - typedef NPTEXTMETRICW NPTEXTMETRIC; - typedef LPTEXTMETRICW LPTEXTMETRIC; -#else - typedef TEXTMETRICA TEXTMETRIC; - typedef PTEXTMETRICA PTEXTMETRIC; - typedef NPTEXTMETRICA NPTEXTMETRIC; - typedef LPTEXTMETRICA LPTEXTMETRIC; -#endif -#endif - -#define NTM_REGULAR 0x00000040L -#define NTM_BOLD 0x00000020L -#define NTM_ITALIC 0x00000001L - -#define NTM_NONNEGATIVE_AC 0x00010000 -#define NTM_PS_OPENTYPE 0x00020000 -#define NTM_TT_OPENTYPE 0x00040000 -#define NTM_MULTIPLEMASTER 0x00080000 -#define NTM_TYPE1 0x00100000 -#define NTM_DSIG 0x00200000 - -#include - typedef struct tagNEWTEXTMETRICA { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - BYTE tmFirstChar; - BYTE tmLastChar; - BYTE tmDefaultChar; - BYTE tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - DWORD ntmFlags; - UINT ntmSizeEM; - UINT ntmCellHeight; - UINT ntmAvgWidth; - } NEWTEXTMETRICA,*PNEWTEXTMETRICA,*NPNEWTEXTMETRICA,*LPNEWTEXTMETRICA; - - typedef struct tagNEWTEXTMETRICW { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - WCHAR tmFirstChar; - WCHAR tmLastChar; - WCHAR tmDefaultChar; - WCHAR tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - DWORD ntmFlags; - UINT ntmSizeEM; - UINT ntmCellHeight; - UINT ntmAvgWidth; - } NEWTEXTMETRICW,*PNEWTEXTMETRICW,*NPNEWTEXTMETRICW,*LPNEWTEXTMETRICW; -#ifdef UNICODE - typedef NEWTEXTMETRICW NEWTEXTMETRIC; - typedef PNEWTEXTMETRICW PNEWTEXTMETRIC; - typedef NPNEWTEXTMETRICW NPNEWTEXTMETRIC; - typedef LPNEWTEXTMETRICW LPNEWTEXTMETRIC; -#else - typedef NEWTEXTMETRICA NEWTEXTMETRIC; - typedef PNEWTEXTMETRICA PNEWTEXTMETRIC; - typedef NPNEWTEXTMETRICA NPNEWTEXTMETRIC; - typedef LPNEWTEXTMETRICA LPNEWTEXTMETRIC; -#endif -#include - - typedef struct tagNEWTEXTMETRICEXA { - NEWTEXTMETRICA ntmTm; - FONTSIGNATURE ntmFontSig; - } NEWTEXTMETRICEXA; - - typedef struct tagNEWTEXTMETRICEXW { - NEWTEXTMETRICW ntmTm; - FONTSIGNATURE ntmFontSig; - } NEWTEXTMETRICEXW; -#ifdef UNICODE - typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX; -#else - typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX; -#endif -#endif - - typedef struct tagPELARRAY { - LONG paXCount; - LONG paYCount; - LONG paXExt; - LONG paYExt; - BYTE paRGBs; - } PELARRAY,*PPELARRAY,*NPPELARRAY,*LPPELARRAY; - - typedef struct tagLOGBRUSH { - UINT lbStyle; - COLORREF lbColor; - ULONG_PTR lbHatch; - } LOGBRUSH,*PLOGBRUSH,*NPLOGBRUSH,*LPLOGBRUSH; - - typedef struct tagLOGBRUSH32 { - UINT lbStyle; - COLORREF lbColor; - ULONG lbHatch; - } LOGBRUSH32,*PLOGBRUSH32,*NPLOGBRUSH32,*LPLOGBRUSH32; - - typedef LOGBRUSH PATTERN; - typedef PATTERN *PPATTERN; - typedef PATTERN *NPPATTERN; - typedef PATTERN *LPPATTERN; - - typedef struct tagLOGPEN { - UINT lopnStyle; - POINT lopnWidth; - COLORREF lopnColor; - } LOGPEN,*PLOGPEN,*NPLOGPEN,*LPLOGPEN; - - typedef struct tagEXTLOGPEN { - DWORD elpPenStyle; - DWORD elpWidth; - UINT elpBrushStyle; - COLORREF elpColor; - ULONG_PTR elpHatch; - DWORD elpNumEntries; - DWORD elpStyleEntry[1]; - } EXTLOGPEN,*PEXTLOGPEN,*NPEXTLOGPEN,*LPEXTLOGPEN; - -#ifndef _PALETTEENTRY_DEFINED -#define _PALETTEENTRY_DEFINED - typedef struct tagPALETTEENTRY { - BYTE peRed; - BYTE peGreen; - BYTE peBlue; - BYTE peFlags; - } PALETTEENTRY,*PPALETTEENTRY,*LPPALETTEENTRY; -#endif - -#ifndef _LOGPALETTE_DEFINED -#define _LOGPALETTE_DEFINED - - typedef struct tagLOGPALETTE { - WORD palVersion; - WORD palNumEntries; - PALETTEENTRY palPalEntry[1]; - } LOGPALETTE,*PLOGPALETTE,*NPLOGPALETTE,*LPLOGPALETTE; -#endif - -#define LF_FACESIZE 32 - - typedef struct tagLOGFONTA { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - CHAR lfFaceName[LF_FACESIZE]; - } LOGFONTA,*PLOGFONTA,*NPLOGFONTA,*LPLOGFONTA; - - typedef struct tagLOGFONTW { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - WCHAR lfFaceName[LF_FACESIZE]; - } LOGFONTW,*PLOGFONTW,*NPLOGFONTW,*LPLOGFONTW; -#ifdef UNICODE - typedef LOGFONTW LOGFONT; - typedef PLOGFONTW PLOGFONT; - typedef NPLOGFONTW NPLOGFONT; - typedef LPLOGFONTW LPLOGFONT; -#else - typedef LOGFONTA LOGFONT; - typedef PLOGFONTA PLOGFONT; - typedef NPLOGFONTA NPLOGFONT; - typedef LPLOGFONTA LPLOGFONT; -#endif - -#define LF_FULLFACESIZE 64 - - typedef struct tagENUMLOGFONTA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - } ENUMLOGFONTA,*LPENUMLOGFONTA; - - typedef struct tagENUMLOGFONTW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - } ENUMLOGFONTW,*LPENUMLOGFONTW; -#ifdef UNICODE - typedef ENUMLOGFONTW ENUMLOGFONT; - typedef LPENUMLOGFONTW LPENUMLOGFONT; -#else - typedef ENUMLOGFONTA ENUMLOGFONT; - typedef LPENUMLOGFONTA LPENUMLOGFONT; -#endif - - typedef struct tagENUMLOGFONTEXA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - BYTE elfScript[LF_FACESIZE]; - } ENUMLOGFONTEXA,*LPENUMLOGFONTEXA; - - typedef struct tagENUMLOGFONTEXW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - WCHAR elfScript[LF_FACESIZE]; - } ENUMLOGFONTEXW,*LPENUMLOGFONTEXW; -#ifdef UNICODE - typedef ENUMLOGFONTEXW ENUMLOGFONTEX; - typedef LPENUMLOGFONTEXW LPENUMLOGFONTEX; -#else - typedef ENUMLOGFONTEXA ENUMLOGFONTEX; - typedef LPENUMLOGFONTEXA LPENUMLOGFONTEX; -#endif - -#define OUT_DEFAULT_PRECIS 0 -#define OUT_STRING_PRECIS 1 -#define OUT_CHARACTER_PRECIS 2 -#define OUT_STROKE_PRECIS 3 -#define OUT_TT_PRECIS 4 -#define OUT_DEVICE_PRECIS 5 -#define OUT_RASTER_PRECIS 6 -#define OUT_TT_ONLY_PRECIS 7 -#define OUT_OUTLINE_PRECIS 8 -#define OUT_SCREEN_OUTLINE_PRECIS 9 -#define OUT_PS_ONLY_PRECIS 10 - -#define CLIP_DEFAULT_PRECIS 0 -#define CLIP_CHARACTER_PRECIS 1 -#define CLIP_STROKE_PRECIS 2 -#define CLIP_MASK 0xf -#define CLIP_LH_ANGLES (1<<4) -#define CLIP_TT_ALWAYS (2<<4) -#define CLIP_DFA_DISABLE (4<<4) -#define CLIP_EMBEDDED (8<<4) - -#define DEFAULT_QUALITY 0 -#define DRAFT_QUALITY 1 -#define PROOF_QUALITY 2 -#define NONANTIALIASED_QUALITY 3 -#define ANTIALIASED_QUALITY 4 - -#define CLEARTYPE_QUALITY 5 -#define CLEARTYPE_NATURAL_QUALITY 6 - -#define DEFAULT_PITCH 0 -#define FIXED_PITCH 1 -#define VARIABLE_PITCH 2 -#define MONO_FONT 8 - -#define ANSI_CHARSET 0 -#define DEFAULT_CHARSET 1 -#define SYMBOL_CHARSET 2 -#define SHIFTJIS_CHARSET 128 -#define HANGEUL_CHARSET 129 -#define HANGUL_CHARSET 129 -#define GB2312_CHARSET 134 -#define CHINESEBIG5_CHARSET 136 -#define OEM_CHARSET 255 -#define JOHAB_CHARSET 130 -#define HEBREW_CHARSET 177 -#define ARABIC_CHARSET 178 -#define GREEK_CHARSET 161 -#define TURKISH_CHARSET 162 -#define VIETNAMESE_CHARSET 163 -#define THAI_CHARSET 222 -#define EASTEUROPE_CHARSET 238 -#define RUSSIAN_CHARSET 204 - -#define MAC_CHARSET 77 -#define BALTIC_CHARSET 186 - -#define FS_LATIN1 0x00000001L -#define FS_LATIN2 0x00000002L -#define FS_CYRILLIC 0x00000004L -#define FS_GREEK 0x00000008L -#define FS_TURKISH 0x00000010L -#define FS_HEBREW 0x00000020L -#define FS_ARABIC 0x00000040L -#define FS_BALTIC 0x00000080L -#define FS_VIETNAMESE 0x00000100L -#define FS_THAI 0x00010000L -#define FS_JISJAPAN 0x00020000L -#define FS_CHINESESIMP 0x00040000L -#define FS_WANSUNG 0x00080000L -#define FS_CHINESETRAD 0x00100000L -#define FS_JOHAB 0x00200000L -#define FS_SYMBOL 0x80000000L - -#define FF_DONTCARE (0<<4) -#define FF_ROMAN (1<<4) - -#define FF_SWISS (2<<4) - -#define FF_MODERN (3<<4) - -#define FF_SCRIPT (4<<4) -#define FF_DECORATIVE (5<<4) - -#define FW_DONTCARE 0 -#define FW_THIN 100 -#define FW_EXTRALIGHT 200 -#define FW_LIGHT 300 -#define FW_NORMAL 400 -#define FW_MEDIUM 500 -#define FW_SEMIBOLD 600 -#define FW_BOLD 700 -#define FW_EXTRABOLD 800 -#define FW_HEAVY 900 - -#define FW_ULTRALIGHT FW_EXTRALIGHT -#define FW_REGULAR FW_NORMAL -#define FW_DEMIBOLD FW_SEMIBOLD -#define FW_ULTRABOLD FW_EXTRABOLD -#define FW_BLACK FW_HEAVY - -#define PANOSE_COUNT 10 -#define PAN_FAMILYTYPE_INDEX 0 -#define PAN_SERIFSTYLE_INDEX 1 -#define PAN_WEIGHT_INDEX 2 -#define PAN_PROPORTION_INDEX 3 -#define PAN_CONTRAST_INDEX 4 -#define PAN_STROKEVARIATION_INDEX 5 -#define PAN_ARMSTYLE_INDEX 6 -#define PAN_LETTERFORM_INDEX 7 -#define PAN_MIDLINE_INDEX 8 -#define PAN_XHEIGHT_INDEX 9 - -#define PAN_CULTURE_LATIN 0 - - typedef struct tagPANOSE { - BYTE bFamilyType; - BYTE bSerifStyle; - BYTE bWeight; - BYTE bProportion; - BYTE bContrast; - BYTE bStrokeVariation; - BYTE bArmStyle; - BYTE bLetterform; - BYTE bMidline; - BYTE bXHeight; - } PANOSE,*LPPANOSE; - -#define PAN_ANY 0 -#define PAN_NO_FIT 1 - -#define PAN_FAMILY_TEXT_DISPLAY 2 -#define PAN_FAMILY_SCRIPT 3 -#define PAN_FAMILY_DECORATIVE 4 -#define PAN_FAMILY_PICTORIAL 5 - -#define PAN_SERIF_COVE 2 -#define PAN_SERIF_OBTUSE_COVE 3 -#define PAN_SERIF_SQUARE_COVE 4 -#define PAN_SERIF_OBTUSE_SQUARE_COVE 5 -#define PAN_SERIF_SQUARE 6 -#define PAN_SERIF_THIN 7 -#define PAN_SERIF_BONE 8 -#define PAN_SERIF_EXAGGERATED 9 -#define PAN_SERIF_TRIANGLE 10 -#define PAN_SERIF_NORMAL_SANS 11 -#define PAN_SERIF_OBTUSE_SANS 12 -#define PAN_SERIF_PERP_SANS 13 -#define PAN_SERIF_FLARED 14 -#define PAN_SERIF_ROUNDED 15 - -#define PAN_WEIGHT_VERY_LIGHT 2 -#define PAN_WEIGHT_LIGHT 3 -#define PAN_WEIGHT_THIN 4 -#define PAN_WEIGHT_BOOK 5 -#define PAN_WEIGHT_MEDIUM 6 -#define PAN_WEIGHT_DEMI 7 -#define PAN_WEIGHT_BOLD 8 -#define PAN_WEIGHT_HEAVY 9 -#define PAN_WEIGHT_BLACK 10 -#define PAN_WEIGHT_NORD 11 - -#define PAN_PROP_OLD_STYLE 2 -#define PAN_PROP_MODERN 3 -#define PAN_PROP_EVEN_WIDTH 4 -#define PAN_PROP_EXPANDED 5 -#define PAN_PROP_CONDENSED 6 -#define PAN_PROP_VERY_EXPANDED 7 -#define PAN_PROP_VERY_CONDENSED 8 -#define PAN_PROP_MONOSPACED 9 - -#define PAN_CONTRAST_NONE 2 -#define PAN_CONTRAST_VERY_LOW 3 -#define PAN_CONTRAST_LOW 4 -#define PAN_CONTRAST_MEDIUM_LOW 5 -#define PAN_CONTRAST_MEDIUM 6 -#define PAN_CONTRAST_MEDIUM_HIGH 7 -#define PAN_CONTRAST_HIGH 8 -#define PAN_CONTRAST_VERY_HIGH 9 - -#define PAN_STROKE_GRADUAL_DIAG 2 -#define PAN_STROKE_GRADUAL_TRAN 3 -#define PAN_STROKE_GRADUAL_VERT 4 -#define PAN_STROKE_GRADUAL_HORZ 5 -#define PAN_STROKE_RAPID_VERT 6 -#define PAN_STROKE_RAPID_HORZ 7 -#define PAN_STROKE_INSTANT_VERT 8 - -#define PAN_STRAIGHT_ARMS_HORZ 2 -#define PAN_STRAIGHT_ARMS_WEDGE 3 -#define PAN_STRAIGHT_ARMS_VERT 4 -#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 -#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 -#define PAN_BENT_ARMS_HORZ 7 -#define PAN_BENT_ARMS_WEDGE 8 -#define PAN_BENT_ARMS_VERT 9 -#define PAN_BENT_ARMS_SINGLE_SERIF 10 -#define PAN_BENT_ARMS_DOUBLE_SERIF 11 - -#define PAN_LETT_NORMAL_CONTACT 2 -#define PAN_LETT_NORMAL_WEIGHTED 3 -#define PAN_LETT_NORMAL_BOXED 4 -#define PAN_LETT_NORMAL_FLATTENED 5 -#define PAN_LETT_NORMAL_ROUNDED 6 -#define PAN_LETT_NORMAL_OFF_CENTER 7 -#define PAN_LETT_NORMAL_SQUARE 8 -#define PAN_LETT_OBLIQUE_CONTACT 9 -#define PAN_LETT_OBLIQUE_WEIGHTED 10 -#define PAN_LETT_OBLIQUE_BOXED 11 -#define PAN_LETT_OBLIQUE_FLATTENED 12 -#define PAN_LETT_OBLIQUE_ROUNDED 13 -#define PAN_LETT_OBLIQUE_OFF_CENTER 14 -#define PAN_LETT_OBLIQUE_SQUARE 15 - -#define PAN_MIDLINE_STANDARD_TRIMMED 2 -#define PAN_MIDLINE_STANDARD_POINTED 3 -#define PAN_MIDLINE_STANDARD_SERIFED 4 -#define PAN_MIDLINE_HIGH_TRIMMED 5 -#define PAN_MIDLINE_HIGH_POINTED 6 -#define PAN_MIDLINE_HIGH_SERIFED 7 -#define PAN_MIDLINE_CONSTANT_TRIMMED 8 -#define PAN_MIDLINE_CONSTANT_POINTED 9 -#define PAN_MIDLINE_CONSTANT_SERIFED 10 -#define PAN_MIDLINE_LOW_TRIMMED 11 -#define PAN_MIDLINE_LOW_POINTED 12 -#define PAN_MIDLINE_LOW_SERIFED 13 - -#define PAN_XHEIGHT_CONSTANT_SMALL 2 -#define PAN_XHEIGHT_CONSTANT_STD 3 -#define PAN_XHEIGHT_CONSTANT_LARGE 4 -#define PAN_XHEIGHT_DUCKING_SMALL 5 -#define PAN_XHEIGHT_DUCKING_STD 6 -#define PAN_XHEIGHT_DUCKING_LARGE 7 - -#define ELF_VENDOR_SIZE 4 - - typedef struct tagEXTLOGFONTA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - DWORD elfVersion; - DWORD elfStyleSize; - DWORD elfMatch; - DWORD elfReserved; - BYTE elfVendorId[ELF_VENDOR_SIZE]; - DWORD elfCulture; - PANOSE elfPanose; - } EXTLOGFONTA,*PEXTLOGFONTA,*NPEXTLOGFONTA,*LPEXTLOGFONTA; - - typedef struct tagEXTLOGFONTW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - DWORD elfVersion; - DWORD elfStyleSize; - DWORD elfMatch; - DWORD elfReserved; - BYTE elfVendorId[ELF_VENDOR_SIZE]; - DWORD elfCulture; - PANOSE elfPanose; - } EXTLOGFONTW,*PEXTLOGFONTW,*NPEXTLOGFONTW,*LPEXTLOGFONTW; -#ifdef UNICODE - typedef EXTLOGFONTW EXTLOGFONT; - typedef PEXTLOGFONTW PEXTLOGFONT; - typedef NPEXTLOGFONTW NPEXTLOGFONT; - typedef LPEXTLOGFONTW LPEXTLOGFONT; -#else - typedef EXTLOGFONTA EXTLOGFONT; - typedef PEXTLOGFONTA PEXTLOGFONT; - typedef NPEXTLOGFONTA NPEXTLOGFONT; - typedef LPEXTLOGFONTA LPEXTLOGFONT; -#endif - -#define ELF_VERSION 0 -#define ELF_CULTURE_LATIN 0 - -#define RASTER_FONTTYPE 0x0001 -#define DEVICE_FONTTYPE 0x002 -#define TRUETYPE_FONTTYPE 0x004 - -#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) -#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b)) -#define PALETTEINDEX(i) ((COLORREF)(0x01000000 | (DWORD)(WORD)(i))) - -#define PC_RESERVED 0x01 -#define PC_EXPLICIT 0x02 -#define PC_NOCOLLAPSE 0x04 - -#define GetRValue(rgb) (LOBYTE(rgb)) -#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) -#define GetBValue(rgb) (LOBYTE((rgb)>>16)) - -#define TRANSPARENT 1 -#define OPAQUE 2 -#define BKMODE_LAST 2 - -#define GM_COMPATIBLE 1 -#define GM_ADVANCED 2 -#define GM_LAST 2 - -#define PT_CLOSEFIGURE 0x01 -#define PT_LINETO 0x02 -#define PT_BEZIERTO 0x04 -#define PT_MOVETO 0x06 - -#define MM_TEXT 1 -#define MM_LOMETRIC 2 -#define MM_HIMETRIC 3 -#define MM_LOENGLISH 4 -#define MM_HIENGLISH 5 -#define MM_TWIPS 6 -#define MM_ISOTROPIC 7 -#define MM_ANISOTROPIC 8 - -#define MM_MIN MM_TEXT -#define MM_MAX MM_ANISOTROPIC -#define MM_MAX_FIXEDSCALE MM_TWIPS - -#define ABSOLUTE 1 -#define RELATIVE 2 - -#define WHITE_BRUSH 0 -#define LTGRAY_BRUSH 1 -#define GRAY_BRUSH 2 -#define DKGRAY_BRUSH 3 -#define BLACK_BRUSH 4 -#define NULL_BRUSH 5 -#define HOLLOW_BRUSH NULL_BRUSH -#define WHITE_PEN 6 -#define BLACK_PEN 7 -#define NULL_PEN 8 -#define OEM_FIXED_FONT 10 -#define ANSI_FIXED_FONT 11 -#define ANSI_VAR_FONT 12 -#define SYSTEM_FONT 13 -#define DEVICE_DEFAULT_FONT 14 -#define DEFAULT_PALETTE 15 -#define SYSTEM_FIXED_FONT 16 - -#define DEFAULT_GUI_FONT 17 - -#define DC_BRUSH 18 -#define DC_PEN 19 - -#define STOCK_LAST 19 - -#define CLR_INVALID 0xFFFFFFFF - -#define BS_SOLID 0 -#define BS_NULL 1 -#define BS_HOLLOW BS_NULL -#define BS_HATCHED 2 -#define BS_PATTERN 3 -#define BS_INDEXED 4 -#define BS_DIBPATTERN 5 -#define BS_DIBPATTERNPT 6 -#define BS_PATTERN8X8 7 -#define BS_DIBPATTERN8X8 8 -#define BS_MONOPATTERN 9 - -#define HS_HORIZONTAL 0 -#define HS_VERTICAL 1 -#define HS_FDIAGONAL 2 -#define HS_BDIAGONAL 3 -#define HS_CROSS 4 -#define HS_DIAGCROSS 5 - -#define PS_SOLID 0 -#define PS_DASH 1 -#define PS_DOT 2 -#define PS_DASHDOT 3 -#define PS_DASHDOTDOT 4 -#define PS_NULL 5 -#define PS_INSIDEFRAME 6 -#define PS_USERSTYLE 7 -#define PS_ALTERNATE 8 -#define PS_STYLE_MASK 0x0000000F - -#define PS_ENDCAP_ROUND 0x00000000 -#define PS_ENDCAP_SQUARE 0x00000100 -#define PS_ENDCAP_FLAT 0x00000200 -#define PS_ENDCAP_MASK 0x00000F00 - -#define PS_JOIN_ROUND 0x00000000 -#define PS_JOIN_BEVEL 0x00001000 -#define PS_JOIN_MITER 0x00002000 -#define PS_JOIN_MASK 0x0000F000 - -#define PS_COSMETIC 0x00000000 -#define PS_GEOMETRIC 0x00010000 -#define PS_TYPE_MASK 0x000F0000 - -#define AD_COUNTERCLOCKWISE 1 -#define AD_CLOCKWISE 2 - -#define DRIVERVERSION 0 -#define TECHNOLOGY 2 -#define HORZSIZE 4 -#define VERTSIZE 6 -#define HORZRES 8 -#define VERTRES 10 -#define BITSPIXEL 12 -#define PLANES 14 -#define NUMBRUSHES 16 -#define NUMPENS 18 -#define NUMMARKERS 20 -#define NUMFONTS 22 -#define NUMCOLORS 24 -#define PDEVICESIZE 26 -#define CURVECAPS 28 -#define LINECAPS 30 -#define POLYGONALCAPS 32 -#define TEXTCAPS 34 -#define CLIPCAPS 36 -#define RASTERCAPS 38 -#define ASPECTX 40 -#define ASPECTY 42 -#define ASPECTXY 44 - -#define LOGPIXELSX 88 -#define LOGPIXELSY 90 - -#define SIZEPALETTE 104 -#define NUMRESERVED 106 -#define COLORRES 108 - -#define PHYSICALWIDTH 110 -#define PHYSICALHEIGHT 111 -#define PHYSICALOFFSETX 112 -#define PHYSICALOFFSETY 113 -#define SCALINGFACTORX 114 -#define SCALINGFACTORY 115 - -#define VREFRESH 116 - -#define DESKTOPVERTRES 117 - -#define DESKTOPHORZRES 118 - -#define BLTALIGNMENT 119 - -#define SHADEBLENDCAPS 120 -#define COLORMGMTCAPS 121 - -#ifndef NOGDICAPMASKS -#define DT_PLOTTER 0 -#define DT_RASDISPLAY 1 -#define DT_RASPRINTER 2 -#define DT_RASCAMERA 3 -#define DT_CHARSTREAM 4 -#define DT_METAFILE 5 -#define DT_DISPFILE 6 - -#define CC_NONE 0 -#define CC_CIRCLES 1 -#define CC_PIE 2 -#define CC_CHORD 4 -#define CC_ELLIPSES 8 -#define CC_WIDE 16 -#define CC_STYLED 32 -#define CC_WIDESTYLED 64 -#define CC_INTERIORS 128 -#define CC_ROUNDRECT 256 - -#define LC_NONE 0 -#define LC_POLYLINE 2 -#define LC_MARKER 4 -#define LC_POLYMARKER 8 -#define LC_WIDE 16 -#define LC_STYLED 32 -#define LC_WIDESTYLED 64 -#define LC_INTERIORS 128 - -#define PC_NONE 0 -#define PC_POLYGON 1 -#define PC_RECTANGLE 2 -#define PC_WINDPOLYGON 4 -#define PC_TRAPEZOID 4 -#define PC_SCANLINE 8 -#define PC_WIDE 16 -#define PC_STYLED 32 -#define PC_WIDESTYLED 64 -#define PC_INTERIORS 128 -#define PC_POLYPOLYGON 256 -#define PC_PATHS 512 - -#define CP_NONE 0 -#define CP_RECTANGLE 1 -#define CP_REGION 2 - -#define TC_OP_CHARACTER 0x00000001 -#define TC_OP_STROKE 0x00000002 -#define TC_CP_STROKE 0x00000004 -#define TC_CR_90 0x00000008 -#define TC_CR_ANY 0x00000010 -#define TC_SF_X_YINDEP 0x00000020 -#define TC_SA_DOUBLE 0x00000040 -#define TC_SA_INTEGER 0x00000080 -#define TC_SA_CONTIN 0x00000100 -#define TC_EA_DOUBLE 0x00000200 -#define TC_IA_ABLE 0x00000400 -#define TC_UA_ABLE 0x00000800 -#define TC_SO_ABLE 0x00001000 -#define TC_RA_ABLE 0x00002000 -#define TC_VA_ABLE 0x00004000 -#define TC_RESERVED 0x00008000 -#define TC_SCROLLBLT 0x00010000 -#endif - -#define RC_NONE -#define RC_BITBLT 1 -#define RC_BANDING 2 -#define RC_SCALING 4 -#define RC_BITMAP64 8 -#define RC_GDI20_OUTPUT 0x0010 -#define RC_GDI20_STATE 0x0020 -#define RC_SAVEBITMAP 0x0040 -#define RC_DI_BITMAP 0x0080 -#define RC_PALETTE 0x0100 -#define RC_DIBTODEV 0x0200 -#define RC_BIGFONT 0x0400 -#define RC_STRETCHBLT 0x0800 -#define RC_FLOODFILL 0x1000 -#define RC_STRETCHDIB 0x2000 -#define RC_OP_DX_OUTPUT 0x4000 -#define RC_DEVBITS 0x8000 - -#define SB_NONE 0x00000000 -#define SB_CONST_ALPHA 0x00000001 -#define SB_PIXEL_ALPHA 0x00000002 -#define SB_PREMULT_ALPHA 0x00000004 - -#define SB_GRAD_RECT 0x00000010 -#define SB_GRAD_TRI 0x00000020 - -#define CM_NONE 0x00000000 -#define CM_DEVICE_ICM 0x00000001 -#define CM_GAMMA_RAMP 0x00000002 -#define CM_CMYK_COLOR 0x00000004 - -#define DIB_RGB_COLORS 0 -#define DIB_PAL_COLORS 1 - -#define SYSPAL_ERROR 0 -#define SYSPAL_STATIC 1 -#define SYSPAL_NOSTATIC 2 -#define SYSPAL_NOSTATIC256 3 - -#define CBM_INIT 0x04L - -#define FLOODFILLBORDER 0 -#define FLOODFILLSURFACE 1 - -#define CCHDEVICENAME 32 - -#define CCHFORMNAME 32 - - typedef struct _devicemodeA { - BYTE dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - BYTE dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - DWORD dmPanningWidth; - DWORD dmPanningHeight; - } DEVMODEA,*PDEVMODEA,*NPDEVMODEA,*LPDEVMODEA; - - typedef struct _devicemodeW { - WCHAR dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - WCHAR dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - DWORD dmPanningWidth; - DWORD dmPanningHeight; - } DEVMODEW,*PDEVMODEW,*NPDEVMODEW,*LPDEVMODEW; -#ifdef UNICODE - typedef DEVMODEW DEVMODE; - typedef PDEVMODEW PDEVMODE; - typedef NPDEVMODEW NPDEVMODE; - typedef LPDEVMODEW LPDEVMODE; -#else - typedef DEVMODEA DEVMODE; - typedef PDEVMODEA PDEVMODE; - typedef NPDEVMODEA NPDEVMODE; - typedef LPDEVMODEA LPDEVMODE; -#endif - -#define DM_SPECVERSION 0x0401 - -#define DM_ORIENTATION 0x00000001L -#define DM_PAPERSIZE 0x00000002L -#define DM_PAPERLENGTH 0x00000004L -#define DM_PAPERWIDTH 0x00000008L -#define DM_SCALE 0x00000010L -#define DM_POSITION 0x00000020L -#define DM_NUP 0x00000040L -#define DM_DISPLAYORIENTATION 0x00000080L -#define DM_COPIES 0x00000100L -#define DM_DEFAULTSOURCE 0x00000200L -#define DM_PRINTQUALITY 0x00000400L -#define DM_COLOR 0x00000800L -#define DM_DUPLEX 0x00001000L -#define DM_YRESOLUTION 0x00002000L -#define DM_TTOPTION 0x00004000L -#define DM_COLLATE 0x00008000L -#define DM_FORMNAME 0x00010000L -#define DM_LOGPIXELS 0x00020000L -#define DM_BITSPERPEL 0x00040000L -#define DM_PELSWIDTH 0x00080000L -#define DM_PELSHEIGHT 0x00100000L -#define DM_DISPLAYFLAGS 0x00200000L -#define DM_DISPLAYFREQUENCY 0x00400000L -#define DM_ICMMETHOD 0x00800000L -#define DM_ICMINTENT 0x01000000L -#define DM_MEDIATYPE 0x02000000L -#define DM_DITHERTYPE 0x04000000L -#define DM_PANNINGWIDTH 0x08000000L -#define DM_PANNINGHEIGHT 0x10000000L -#define DM_DISPLAYFIXEDOUTPUT 0x20000000L - -#define DMORIENT_PORTRAIT 1 -#define DMORIENT_LANDSCAPE 2 - -#define DMPAPER_FIRST DMPAPER_LETTER -#define DMPAPER_LETTER 1 -#define DMPAPER_LETTERSMALL 2 -#define DMPAPER_TABLOID 3 -#define DMPAPER_LEDGER 4 -#define DMPAPER_LEGAL 5 -#define DMPAPER_STATEMENT 6 -#define DMPAPER_EXECUTIVE 7 -#define DMPAPER_A3 8 -#define DMPAPER_A4 9 -#define DMPAPER_A4SMALL 10 -#define DMPAPER_A5 11 -#define DMPAPER_B4 12 -#define DMPAPER_B5 13 -#define DMPAPER_FOLIO 14 -#define DMPAPER_QUARTO 15 -#define DMPAPER_10X14 16 -#define DMPAPER_11X17 17 -#define DMPAPER_NOTE 18 -#define DMPAPER_ENV_9 19 -#define DMPAPER_ENV_10 20 -#define DMPAPER_ENV_11 21 -#define DMPAPER_ENV_12 22 -#define DMPAPER_ENV_14 23 -#define DMPAPER_CSHEET 24 -#define DMPAPER_DSHEET 25 -#define DMPAPER_ESHEET 26 -#define DMPAPER_ENV_DL 27 -#define DMPAPER_ENV_C5 28 -#define DMPAPER_ENV_C3 29 -#define DMPAPER_ENV_C4 30 -#define DMPAPER_ENV_C6 31 -#define DMPAPER_ENV_C65 32 -#define DMPAPER_ENV_B4 33 -#define DMPAPER_ENV_B5 34 -#define DMPAPER_ENV_B6 35 -#define DMPAPER_ENV_ITALY 36 -#define DMPAPER_ENV_MONARCH 37 -#define DMPAPER_ENV_PERSONAL 38 -#define DMPAPER_FANFOLD_US 39 -#define DMPAPER_FANFOLD_STD_GERMAN 40 -#define DMPAPER_FANFOLD_LGL_GERMAN 41 -#define DMPAPER_ISO_B4 42 -#define DMPAPER_JAPANESE_POSTCARD 43 -#define DMPAPER_9X11 44 -#define DMPAPER_10X11 45 -#define DMPAPER_15X11 46 -#define DMPAPER_ENV_INVITE 47 -#define DMPAPER_RESERVED_48 48 -#define DMPAPER_RESERVED_49 49 -#define DMPAPER_LETTER_EXTRA 50 -#define DMPAPER_LEGAL_EXTRA 51 -#define DMPAPER_TABLOID_EXTRA 52 -#define DMPAPER_A4_EXTRA 53 -#define DMPAPER_LETTER_TRANSVERSE 54 -#define DMPAPER_A4_TRANSVERSE 55 -#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 -#define DMPAPER_A_PLUS 57 -#define DMPAPER_B_PLUS 58 -#define DMPAPER_LETTER_PLUS 59 -#define DMPAPER_A4_PLUS 60 -#define DMPAPER_A5_TRANSVERSE 61 -#define DMPAPER_B5_TRANSVERSE 62 -#define DMPAPER_A3_EXTRA 63 -#define DMPAPER_A5_EXTRA 64 -#define DMPAPER_B5_EXTRA 65 -#define DMPAPER_A2 66 -#define DMPAPER_A3_TRANSVERSE 67 -#define DMPAPER_A3_EXTRA_TRANSVERSE 68 -#define DMPAPER_DBL_JAPANESE_POSTCARD 69 -#define DMPAPER_A6 70 -#define DMPAPER_JENV_KAKU2 71 -#define DMPAPER_JENV_KAKU3 72 -#define DMPAPER_JENV_CHOU3 73 -#define DMPAPER_JENV_CHOU4 74 -#define DMPAPER_LETTER_ROTATED 75 -#define DMPAPER_A3_ROTATED 76 -#define DMPAPER_A4_ROTATED 77 -#define DMPAPER_A5_ROTATED 78 -#define DMPAPER_B4_JIS_ROTATED 79 -#define DMPAPER_B5_JIS_ROTATED 80 -#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 -#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 -#define DMPAPER_A6_ROTATED 83 -#define DMPAPER_JENV_KAKU2_ROTATED 84 -#define DMPAPER_JENV_KAKU3_ROTATED 85 -#define DMPAPER_JENV_CHOU3_ROTATED 86 -#define DMPAPER_JENV_CHOU4_ROTATED 87 -#define DMPAPER_B6_JIS 88 -#define DMPAPER_B6_JIS_ROTATED 89 -#define DMPAPER_12X11 90 -#define DMPAPER_JENV_YOU4 91 -#define DMPAPER_JENV_YOU4_ROTATED 92 -#define DMPAPER_P16K 93 -#define DMPAPER_P32K 94 -#define DMPAPER_P32KBIG 95 -#define DMPAPER_PENV_1 96 -#define DMPAPER_PENV_2 97 -#define DMPAPER_PENV_3 98 -#define DMPAPER_PENV_4 99 -#define DMPAPER_PENV_5 100 -#define DMPAPER_PENV_6 101 -#define DMPAPER_PENV_7 102 -#define DMPAPER_PENV_8 103 -#define DMPAPER_PENV_9 104 -#define DMPAPER_PENV_10 105 -#define DMPAPER_P16K_ROTATED 106 -#define DMPAPER_P32K_ROTATED 107 -#define DMPAPER_P32KBIG_ROTATED 108 -#define DMPAPER_PENV_1_ROTATED 109 -#define DMPAPER_PENV_2_ROTATED 110 -#define DMPAPER_PENV_3_ROTATED 111 -#define DMPAPER_PENV_4_ROTATED 112 -#define DMPAPER_PENV_5_ROTATED 113 -#define DMPAPER_PENV_6_ROTATED 114 -#define DMPAPER_PENV_7_ROTATED 115 -#define DMPAPER_PENV_8_ROTATED 116 -#define DMPAPER_PENV_9_ROTATED 117 -#define DMPAPER_PENV_10_ROTATED 118 - -#define DMPAPER_LAST DMPAPER_PENV_10_ROTATED - -#define DMPAPER_USER 256 - -#define DMBIN_FIRST DMBIN_UPPER -#define DMBIN_UPPER 1 -#define DMBIN_ONLYONE 1 -#define DMBIN_LOWER 2 -#define DMBIN_MIDDLE 3 -#define DMBIN_MANUAL 4 -#define DMBIN_ENVELOPE 5 -#define DMBIN_ENVMANUAL 6 -#define DMBIN_AUTO 7 -#define DMBIN_TRACTOR 8 -#define DMBIN_SMALLFMT 9 -#define DMBIN_LARGEFMT 10 -#define DMBIN_LARGECAPACITY 11 -#define DMBIN_CASSETTE 14 -#define DMBIN_FORMSOURCE 15 -#define DMBIN_LAST DMBIN_FORMSOURCE - -#define DMBIN_USER 256 - -#define DMRES_DRAFT (-1) -#define DMRES_LOW (-2) -#define DMRES_MEDIUM (-3) -#define DMRES_HIGH (-4) - -#define DMCOLOR_MONOCHROME 1 -#define DMCOLOR_COLOR 2 - -#define DMDUP_SIMPLEX 1 -#define DMDUP_VERTICAL 2 -#define DMDUP_HORIZONTAL 3 - -#define DMTT_BITMAP 1 -#define DMTT_DOWNLOAD 2 -#define DMTT_SUBDEV 3 -#define DMTT_DOWNLOAD_OUTLINE 4 - -#define DMCOLLATE_FALSE 0 -#define DMCOLLATE_TRUE 1 - -#define DMDO_DEFAULT 0 -#define DMDO_90 1 -#define DMDO_180 2 -#define DMDO_270 3 - -#define DMDFO_DEFAULT 0 -#define DMDFO_STRETCH 1 -#define DMDFO_CENTER 2 - -#define DMDISPLAYFLAGS_TEXTMODE 0x00000004 - -#define DMNUP_SYSTEM 1 -#define DMNUP_ONEUP 2 - -#define DMICMMETHOD_NONE 1 -#define DMICMMETHOD_SYSTEM 2 -#define DMICMMETHOD_DRIVER 3 -#define DMICMMETHOD_DEVICE 4 - -#define DMICMMETHOD_USER 256 - -#define DMICM_SATURATE 1 -#define DMICM_CONTRAST 2 -#define DMICM_COLORIMETRIC 3 -#define DMICM_ABS_COLORIMETRIC 4 - -#define DMICM_USER 256 - -#define DMMEDIA_STANDARD 1 -#define DMMEDIA_TRANSPARENCY 2 -#define DMMEDIA_GLOSSY 3 - -#define DMMEDIA_USER 256 - -#define DMDITHER_NONE 1 -#define DMDITHER_COARSE 2 -#define DMDITHER_FINE 3 -#define DMDITHER_LINEART 4 -#define DMDITHER_ERRORDIFFUSION 5 -#define DMDITHER_RESERVED6 6 -#define DMDITHER_RESERVED7 7 -#define DMDITHER_RESERVED8 8 -#define DMDITHER_RESERVED9 9 -#define DMDITHER_GRAYSCALE 10 - -#define DMDITHER_USER 256 - - typedef struct _DISPLAY_DEVICEA { - DWORD cb; - CHAR DeviceName[32]; - CHAR DeviceString[128]; - DWORD StateFlags; - CHAR DeviceID[128]; - CHAR DeviceKey[128]; - } DISPLAY_DEVICEA,*PDISPLAY_DEVICEA,*LPDISPLAY_DEVICEA; - typedef struct _DISPLAY_DEVICEW { - DWORD cb; - WCHAR DeviceName[32]; - WCHAR DeviceString[128]; - DWORD StateFlags; - WCHAR DeviceID[128]; - WCHAR DeviceKey[128]; - } DISPLAY_DEVICEW,*PDISPLAY_DEVICEW,*LPDISPLAY_DEVICEW; -#ifdef UNICODE - typedef DISPLAY_DEVICEW DISPLAY_DEVICE; - typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE; - typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE; -#else - typedef DISPLAY_DEVICEA DISPLAY_DEVICE; - typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE; - typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE; -#endif - -#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 -#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 -#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 -#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 -#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010 -#define DISPLAY_DEVICE_REMOVABLE 0x00000020 -#define DISPLAY_DEVICE_MODESPRUNED 0x08000000 -#define DISPLAY_DEVICE_REMOTE 0x04000000 -#define DISPLAY_DEVICE_DISCONNECT 0x02000000 - -#define DISPLAY_DEVICE_ACTIVE 0x00000001 -#define DISPLAY_DEVICE_ATTACHED 0x00000002 - -#define RDH_RECTANGLES 1 - - typedef struct _RGNDATAHEADER { - DWORD dwSize; - DWORD iType; - DWORD nCount; - DWORD nRgnSize; - RECT rcBound; - } RGNDATAHEADER,*PRGNDATAHEADER; - - typedef struct _RGNDATA { - RGNDATAHEADER rdh; - char Buffer[1]; - } RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA; - -#define SYSRGN 4 - - typedef struct _ABC { - int abcA; - UINT abcB; - int abcC; - } ABC,*PABC,*NPABC,*LPABC; - - typedef struct _ABCFLOAT { - FLOAT abcfA; - FLOAT abcfB; - FLOAT abcfC; - } ABCFLOAT,*PABCFLOAT,*NPABCFLOAT,*LPABCFLOAT; - -#ifndef NOTEXTMETRIC - - typedef struct _OUTLINETEXTMETRICA { - UINT otmSize; - TEXTMETRICA otmTextMetrics; - BYTE otmFiller; - PANOSE otmPanoseNumber; - UINT otmfsSelection; - UINT otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - UINT otmEMSquare; - int otmAscent; - int otmDescent; - UINT otmLineGap; - UINT otmsCapEmHeight; - UINT otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - UINT otmMacLineGap; - UINT otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - UINT otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PSTR otmpFamilyName; - PSTR otmpFaceName; - PSTR otmpStyleName; - PSTR otmpFullName; - } OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*NPOUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA; - - typedef struct _OUTLINETEXTMETRICW { - UINT otmSize; - TEXTMETRICW otmTextMetrics; - BYTE otmFiller; - PANOSE otmPanoseNumber; - UINT otmfsSelection; - UINT otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - UINT otmEMSquare; - int otmAscent; - int otmDescent; - UINT otmLineGap; - UINT otmsCapEmHeight; - UINT otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - UINT otmMacLineGap; - UINT otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - UINT otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PSTR otmpFamilyName; - PSTR otmpFaceName; - PSTR otmpStyleName; - PSTR otmpFullName; - } OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*NPOUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW; -#ifdef UNICODE - typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC; - typedef POUTLINETEXTMETRICW POUTLINETEXTMETRIC; - typedef NPOUTLINETEXTMETRICW NPOUTLINETEXTMETRIC; - typedef LPOUTLINETEXTMETRICW LPOUTLINETEXTMETRIC; -#else - typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC; - typedef POUTLINETEXTMETRICA POUTLINETEXTMETRIC; - typedef NPOUTLINETEXTMETRICA NPOUTLINETEXTMETRIC; - typedef LPOUTLINETEXTMETRICA LPOUTLINETEXTMETRIC; -#endif -#endif - - typedef struct tagPOLYTEXTA { - int x; - int y; - UINT n; - LPCSTR lpstr; - UINT uiFlags; - RECT rcl; - int *pdx; - } POLYTEXTA,*PPOLYTEXTA,*NPPOLYTEXTA,*LPPOLYTEXTA; - - typedef struct tagPOLYTEXTW { - int x; - int y; - UINT n; - LPCWSTR lpstr; - UINT uiFlags; - RECT rcl; - int *pdx; - } POLYTEXTW,*PPOLYTEXTW,*NPPOLYTEXTW,*LPPOLYTEXTW; -#ifdef UNICODE - typedef POLYTEXTW POLYTEXT; - typedef PPOLYTEXTW PPOLYTEXT; - typedef NPPOLYTEXTW NPPOLYTEXT; - typedef LPPOLYTEXTW LPPOLYTEXT; -#else - typedef POLYTEXTA POLYTEXT; - typedef PPOLYTEXTA PPOLYTEXT; - typedef NPPOLYTEXTA NPPOLYTEXT; - typedef LPPOLYTEXTA LPPOLYTEXT; -#endif - - typedef struct _FIXED { - WORD fract; - short value; - } FIXED; - - typedef struct _MAT2 { - FIXED eM11; - FIXED eM12; - FIXED eM21; - FIXED eM22; - } MAT2,*LPMAT2; - - typedef struct _GLYPHMETRICS { - UINT gmBlackBoxX; - UINT gmBlackBoxY; - POINT gmptGlyphOrigin; - short gmCellIncX; - short gmCellIncY; - } GLYPHMETRICS,*LPGLYPHMETRICS; - -#define GGO_METRICS 0 -#define GGO_BITMAP 1 -#define GGO_NATIVE 2 -#define GGO_BEZIER 3 - -#define GGO_GRAY2_BITMAP 4 -#define GGO_GRAY4_BITMAP 5 -#define GGO_GRAY8_BITMAP 6 -#define GGO_GLYPH_INDEX 0x0080 -#define GGO_UNHINTED 0x0100 - -#define TT_POLYGON_TYPE 24 - -#define TT_PRIM_LINE 1 -#define TT_PRIM_QSPLINE 2 -#define TT_PRIM_CSPLINE 3 - - typedef struct tagPOINTFX { - FIXED x; - FIXED y; - } POINTFX,*LPPOINTFX; - - typedef struct tagTTPOLYCURVE { - WORD wType; - WORD cpfx; - POINTFX apfx[1]; - } TTPOLYCURVE,*LPTTPOLYCURVE; - - typedef struct tagTTPOLYGONHEADER { - DWORD cb; - DWORD dwType; - POINTFX pfxStart; - } TTPOLYGONHEADER,*LPTTPOLYGONHEADER; - -#define GCP_DBCS 0x0001 -#define GCP_REORDER 0x0002 -#define GCP_USEKERNING 0x0008 -#define GCP_GLYPHSHAPE 0x0010 -#define GCP_LIGATE 0x0020 - -#define GCP_DIACRITIC 0x0100 -#define GCP_KASHIDA 0x0400 -#define GCP_ERROR 0x8000 -#define FLI_MASK 0x103B - -#define GCP_JUSTIFY 0x00010000L - -#define FLI_GLYPHS 0x00040000L -#define GCP_CLASSIN 0x00080000L -#define GCP_MAXEXTENT 0x00100000L -#define GCP_JUSTIFYIN 0x00200000L -#define GCP_DISPLAYZWG 0x00400000L -#define GCP_SYMSWAPOFF 0x00800000L -#define GCP_NUMERICOVERRIDE 0x01000000L -#define GCP_NEUTRALOVERRIDE 0x02000000L -#define GCP_NUMERICSLATIN 0x04000000L -#define GCP_NUMERICSLOCAL 0x08000000L - -#define GCPCLASS_LATIN 1 -#define GCPCLASS_HEBREW 2 -#define GCPCLASS_ARABIC 2 -#define GCPCLASS_NEUTRAL 3 -#define GCPCLASS_LOCALNUMBER 4 -#define GCPCLASS_LATINNUMBER 5 -#define GCPCLASS_LATINNUMERICTERMINATOR 6 -#define GCPCLASS_LATINNUMERICSEPARATOR 7 -#define GCPCLASS_NUMERICSEPARATOR 8 -#define GCPCLASS_PREBOUNDLTR 0x80 -#define GCPCLASS_PREBOUNDRTL 0x40 -#define GCPCLASS_POSTBOUNDLTR 0x20 -#define GCPCLASS_POSTBOUNDRTL 0x10 - -#define GCPGLYPH_LINKBEFORE 0x8000 -#define GCPGLYPH_LINKAFTER 0x4000 - - typedef struct tagGCP_RESULTSA { - DWORD lStructSize; - LPSTR lpOutString; - UINT *lpOrder; - int *lpDx; - int *lpCaretPos; - LPSTR lpClass; - LPWSTR lpGlyphs; - UINT nGlyphs; - int nMaxFit; - } GCP_RESULTSA,*LPGCP_RESULTSA; - typedef struct tagGCP_RESULTSW { - DWORD lStructSize; - LPWSTR lpOutString; - UINT *lpOrder; - int *lpDx; - int *lpCaretPos; - LPSTR lpClass; - LPWSTR lpGlyphs; - UINT nGlyphs; - int nMaxFit; - } GCP_RESULTSW,*LPGCP_RESULTSW; -#ifdef UNICODE - typedef GCP_RESULTSW GCP_RESULTS; - typedef LPGCP_RESULTSW LPGCP_RESULTS; -#else - typedef GCP_RESULTSA GCP_RESULTS; - typedef LPGCP_RESULTSA LPGCP_RESULTS; -#endif - - typedef struct _RASTERIZER_STATUS { - short nSize; - short wFlags; - short nLanguageID; - } RASTERIZER_STATUS,*LPRASTERIZER_STATUS; - -#define TT_AVAILABLE 0x0001 -#define TT_ENABLED 0x0002 - - typedef struct tagPIXELFORMATDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerType; - BYTE bReserved; - DWORD dwLayerMask; - DWORD dwVisibleMask; - DWORD dwDamageMask; - } PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR; - -#define PFD_TYPE_RGBA 0 -#define PFD_TYPE_COLORINDEX 1 - -#define PFD_MAIN_PLANE 0 -#define PFD_OVERLAY_PLANE 1 -#define PFD_UNDERLAY_PLANE (-1) - -#define PFD_DOUBLEBUFFER 0x00000001 -#define PFD_STEREO 0x00000002 -#define PFD_DRAW_TO_WINDOW 0x00000004 -#define PFD_DRAW_TO_BITMAP 0x00000008 -#define PFD_SUPPORT_GDI 0x00000010 -#define PFD_SUPPORT_OPENGL 0x00000020 -#define PFD_GENERIC_FORMAT 0x00000040 -#define PFD_NEED_PALETTE 0x00000080 -#define PFD_NEED_SYSTEM_PALETTE 0x00000100 -#define PFD_SWAP_EXCHANGE 0x00000200 -#define PFD_SWAP_COPY 0x00000400 -#define PFD_SWAP_LAYER_BUFFERS 0x00000800 -#define PFD_GENERIC_ACCELERATED 0x00001000 -#define PFD_SUPPORT_DIRECTDRAW 0x00002000 - -#define PFD_DEPTH_DONTCARE 0x20000000 -#define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 -#define PFD_STEREO_DONTCARE 0x80000000 - -#ifndef NOTEXTMETRIC - typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST TEXTMETRICA *,DWORD,LPARAM); - typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST TEXTMETRICW *,DWORD,LPARAM); -#ifdef UNICODE -#define OLDFONTENUMPROC OLDFONTENUMPROCW -#else -#define OLDFONTENUMPROC OLDFONTENUMPROCA -#endif -#else - typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST VOID *,DWORD,LPARAM); - typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST VOID *,DWORD,LPARAM); -#ifdef UNICODE -#define OLDFONTENUMPROC OLDFONTENUMPROCW -#else -#define OLDFONTENUMPROC OLDFONTENUMPROCA -#endif -#endif - - typedef OLDFONTENUMPROCA FONTENUMPROCA; - typedef OLDFONTENUMPROCW FONTENUMPROCW; -#ifdef UNICODE - typedef FONTENUMPROCW FONTENUMPROC; -#else - typedef FONTENUMPROCA FONTENUMPROC; -#endif - - typedef int (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM); - typedef VOID (CALLBACK *LINEDDAPROC)(int,int,LPARAM); - -#ifdef UNICODE -#define AddFontResource AddFontResourceW -#define CopyMetaFile CopyMetaFileW -#define CreateDC CreateDCW -#define CreateFontIndirect CreateFontIndirectW -#define CreateFont CreateFontW -#define CreateIC CreateICW -#define CreateMetaFile CreateMetaFileW -#define CreateScalableFontResource CreateScalableFontResourceW -#else -#define AddFontResource AddFontResourceA -#define CopyMetaFile CopyMetaFileA -#define CreateDC CreateDCA -#define CreateFontIndirect CreateFontIndirectA -#define CreateFont CreateFontA -#define CreateIC CreateICA -#define CreateMetaFile CreateMetaFileA -#define CreateScalableFontResource CreateScalableFontResourceA -#endif - - WINGDIAPI int WINAPI AddFontResourceA(LPCSTR); - WINGDIAPI int WINAPI AddFontResourceW(LPCWSTR); - WINGDIAPI WINBOOL WINAPI AnimatePalette(HPALETTE hPal,UINT iStartIndex,UINT cEntries,CONST PALETTEENTRY *ppe); - WINGDIAPI WINBOOL WINAPI Arc(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); - WINGDIAPI WINBOOL WINAPI BitBlt(HDC hdc,int x,int y,int cx,int cy,HDC hdcSrc,int x1,int y1,DWORD rop); - WINGDIAPI WINBOOL WINAPI CancelDC(HDC hdc); - WINGDIAPI WINBOOL WINAPI Chord(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); - WINGDIAPI int WINAPI ChoosePixelFormat(HDC hdc,CONST PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI HMETAFILE WINAPI CloseMetaFile(HDC hdc); - WINGDIAPI int WINAPI CombineRgn(HRGN hrgnDst,HRGN hrgnSrc1,HRGN hrgnSrc2,int iMode); - WINGDIAPI HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR); - WINGDIAPI HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR); - WINGDIAPI HBITMAP WINAPI CreateBitmap(int nWidth,int nHeight,UINT nPlanes,UINT nBitCount,CONST VOID *lpBits); - WINGDIAPI HBITMAP WINAPI CreateBitmapIndirect(CONST BITMAP *pbm); - WINGDIAPI HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH *plbrush); - WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC hdc,int cx,int cy); - WINGDIAPI HBITMAP WINAPI CreateDiscardableBitmap(HDC hdc,int cx,int cy); - WINGDIAPI HDC WINAPI CreateCompatibleDC(HDC hdc); - WINGDIAPI HDC WINAPI CreateDCA(LPCSTR pwszDriver,LPCSTR pwszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); - WINGDIAPI HDC WINAPI CreateDCW(LPCWSTR pwszDriver,LPCWSTR pwszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); - WINGDIAPI HBITMAP WINAPI CreateDIBitmap(HDC hdc,CONST BITMAPINFOHEADER *pbmih,DWORD flInit,CONST VOID *pjBits,CONST BITMAPINFO *pbmi,UINT iUsage); - WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage); - WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *lpPackedDIB,UINT iUsage); - WINGDIAPI HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2); - WINGDIAPI HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *lprect); - WINGDIAPI HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *lplf); - WINGDIAPI HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *lplf); - WINGDIAPI HFONT WINAPI CreateFontA(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCSTR pszFaceName); - WINGDIAPI HFONT WINAPI CreateFontW(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCWSTR pszFaceName); - WINGDIAPI HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color); - WINGDIAPI HDC WINAPI CreateICA(LPCSTR pszDriver,LPCSTR pszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); - WINGDIAPI HDC WINAPI CreateICW(LPCWSTR pszDriver,LPCWSTR pszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); - WINGDIAPI HDC WINAPI CreateMetaFileA(LPCSTR pszFile); - WINGDIAPI HDC WINAPI CreateMetaFileW(LPCWSTR pszFile); - WINGDIAPI HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal); - WINGDIAPI HPEN WINAPI CreatePen(int iStyle,int cWidth,COLORREF color); - WINGDIAPI HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen); - WINGDIAPI HRGN WINAPI CreatePolyPolygonRgn(CONST POINT *pptl,CONST INT *pc,int cPoly,int iMode); - WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm); - WINGDIAPI HRGN WINAPI CreateRectRgn(int x1,int y1,int x2,int y2); - WINGDIAPI HRGN WINAPI CreateRectRgnIndirect(CONST RECT *lprect); - WINGDIAPI HRGN WINAPI CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); - WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceA(DWORD fdwHidden,LPCSTR lpszFont,LPCSTR lpszFile,LPCSTR lpszPath); - WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceW(DWORD fdwHidden,LPCWSTR lpszFont,LPCWSTR lpszFile,LPCWSTR lpszPath); - WINGDIAPI HBRUSH WINAPI CreateSolidBrush(COLORREF color); - WINGDIAPI WINBOOL WINAPI DeleteDC(HDC hdc); - WINGDIAPI WINBOOL WINAPI DeleteMetaFile(HMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI DeleteObject(HGDIOBJ ho); - WINGDIAPI int WINAPI DescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,LPPIXELFORMATDESCRIPTOR ppfd); - - typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODE,LPSTR,LPSTR,LPDEVMODE,LPSTR,UINT); - typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODE); - -#define DM_UPDATE 1 -#define DM_COPY 2 -#define DM_PROMPT 4 -#define DM_MODIFY 8 - -#define DM_IN_BUFFER DM_MODIFY -#define DM_IN_PROMPT DM_PROMPT -#define DM_OUT_BUFFER DM_COPY -#define DM_OUT_DEFAULT DM_UPDATE - -#define DC_FIELDS 1 -#define DC_PAPERS 2 -#define DC_PAPERSIZE 3 -#define DC_MINEXTENT 4 -#define DC_MAXEXTENT 5 -#define DC_BINS 6 -#define DC_DUPLEX 7 -#define DC_SIZE 8 -#define DC_EXTRA 9 -#define DC_VERSION 10 -#define DC_DRIVER 11 -#define DC_BINNAMES 12 -#define DC_ENUMRESOLUTIONS 13 -#define DC_FILEDEPENDENCIES 14 -#define DC_TRUETYPE 15 -#define DC_PAPERNAMES 16 -#define DC_ORIENTATION 17 -#define DC_COPIES 18 -#define DC_BINADJUST 19 -#define DC_EMF_COMPLIANT 20 -#define DC_DATATYPE_PRODUCED 21 -#define DC_COLLATE 22 -#define DC_MANUFACTURER 23 -#define DC_MODEL 24 -#define DC_PERSONALITY 25 -#define DC_PRINTRATE 26 -#define DC_PRINTRATEUNIT 27 -#define PRINTRATEUNIT_PPM 1 -#define PRINTRATEUNIT_CPS 2 -#define PRINTRATEUNIT_LPM 3 -#define PRINTRATEUNIT_IPM 4 -#define DC_PRINTERMEM 28 -#define DC_MEDIAREADY 29 -#define DC_STAPLE 30 -#define DC_PRINTRATEPPM 31 -#define DC_COLORDEVICE 32 -#define DC_NUP 33 -#define DC_MEDIATYPENAMES 34 -#define DC_MEDIATYPES 35 - -#define DCTT_BITMAP 0x0000001L -#define DCTT_DOWNLOAD 0x0000002L -#define DCTT_SUBDEV 0x0000004L -#define DCTT_DOWNLOAD_OUTLINE 0x0000008L - -#define DCBA_FACEUPNONE 0x0000 -#define DCBA_FACEUPCENTER 0x0001 -#define DCBA_FACEUPLEFT 0x0002 -#define DCBA_FACEUPRIGHT 0x0003 -#define DCBA_FACEDOWNNONE 0x0100 -#define DCBA_FACEDOWNCENTER 0x0101 -#define DCBA_FACEDOWNLEFT 0x0102 -#define DCBA_FACEDOWNRIGHT 0x0103 - -#ifdef UNICODE -#define DeviceCapabilities DeviceCapabilitiesW -#define EnumFontFamiliesEx EnumFontFamiliesExW -#define EnumFontFamilies EnumFontFamiliesW -#define EnumFonts EnumFontsW -#define GetCharWidth GetCharWidthW -#define GetCharWidth32 GetCharWidth32W -#define GetCharWidthFloat GetCharWidthFloatW -#define GetCharABCWidths GetCharABCWidthsW -#define GetCharABCWidthsFloat GetCharABCWidthsFloatW -#define GetGlyphOutline GetGlyphOutlineW -#define GetMetaFile GetMetaFileW -#else -#define DeviceCapabilities DeviceCapabilitiesA -#define EnumFontFamiliesEx EnumFontFamiliesExA -#define EnumFontFamilies EnumFontFamiliesA -#define EnumFonts EnumFontsA -#define GetCharWidth GetCharWidthA -#define GetCharWidth32 GetCharWidth32A -#define GetCharWidthFloat GetCharWidthFloatA -#define GetCharABCWidths GetCharABCWidthsA -#define GetCharABCWidthsFloat GetCharABCWidthsFloatA -#define GetGlyphOutline GetGlyphOutlineA -#define GetMetaFile GetMetaFileA -#endif - - WINSPOOLAPI int WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,CONST DEVMODEA *pDevMode); - WINSPOOLAPI int WINAPI DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,CONST DEVMODEW *pDevMode); - WINGDIAPI int WINAPI DrawEscape(HDC hdc,int iEscape,int cjIn,LPCSTR lpIn); - WINGDIAPI WINBOOL WINAPI Ellipse(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI int WINAPI EnumFontFamiliesExA(HDC hdc,LPLOGFONTA lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam,DWORD dwFlags); - WINGDIAPI int WINAPI EnumFontFamiliesExW(HDC hdc,LPLOGFONTW lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam,DWORD dwFlags); - WINGDIAPI int WINAPI EnumFontFamiliesA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontFamiliesW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontsA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontsW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumObjects(HDC hdc,int nType,GOBJENUMPROC lpFunc,LPARAM lParam); - WINGDIAPI WINBOOL WINAPI EqualRgn(HRGN hrgn1,HRGN hrgn2); - WINGDIAPI int WINAPI Escape(HDC hdc,int iEscape,int cjIn,LPCSTR pvIn,LPVOID pvOut); - WINGDIAPI int WINAPI ExtEscape(HDC hdc,int iEscape,int cjInput,LPCSTR lpInData,int cjOutput,LPSTR lpOutData); - WINGDIAPI int WINAPI ExcludeClipRect(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI HRGN WINAPI ExtCreateRegion(CONST XFORM *lpx,DWORD nCount,CONST RGNDATA *lpData); - WINGDIAPI WINBOOL WINAPI ExtFloodFill(HDC hdc,int x,int y,COLORREF color,UINT type); - WINGDIAPI WINBOOL WINAPI FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbr); - WINGDIAPI WINBOOL WINAPI FloodFill(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbr,int w,int h); - WINGDIAPI int WINAPI GetROP2(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetAspectRatioFilterEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI COLORREF WINAPI GetBkColor(HDC hdc); - WINGDIAPI COLORREF WINAPI GetDCBrushColor(HDC hdc); - WINGDIAPI COLORREF WINAPI GetDCPenColor(HDC hdc); - WINGDIAPI int WINAPI GetBkMode(HDC hdc); - WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP hbit,LONG cb,LPVOID lpvBits); - WINGDIAPI WINBOOL WINAPI GetBitmapDimensionEx(HBITMAP hbit,LPSIZE lpsize); - WINGDIAPI UINT WINAPI GetBoundsRect(HDC hdc,LPRECT lprect,UINT flags); - WINGDIAPI WINBOOL WINAPI GetBrushOrgEx(HDC hdc,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI GetCharWidthA(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidth32A(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidth32W(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthFloatA(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthFloatW(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsA(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsW(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatA(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatW(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); - WINGDIAPI int WINAPI GetClipBox(HDC hdc,LPRECT lprect); - WINGDIAPI int WINAPI GetClipRgn(HDC hdc,HRGN hrgn); - WINGDIAPI int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn); - WINGDIAPI HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type); - WINGDIAPI WINBOOL WINAPI GetCurrentPositionEx(HDC hdc,LPPOINT lppt); - WINGDIAPI int WINAPI GetDeviceCaps(HDC hdc,int index); - WINGDIAPI int WINAPI GetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT usage); - WINGDIAPI DWORD WINAPI GetFontData (HDC hdc,DWORD dwTable,DWORD dwOffset,PVOID pvBuffer,DWORD cjBuffer); - WINGDIAPI DWORD WINAPI GetGlyphOutlineA(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); - WINGDIAPI DWORD WINAPI GetGlyphOutlineW(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); - WINGDIAPI int WINAPI GetGraphicsMode(HDC hdc); - WINGDIAPI int WINAPI GetMapMode(HDC hdc); - WINGDIAPI UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF,UINT cbBuffer,LPVOID lpData); - WINGDIAPI HMETAFILE WINAPI GetMetaFileA(LPCSTR lpName); - WINGDIAPI HMETAFILE WINAPI GetMetaFileW(LPCWSTR lpName); - WINGDIAPI COLORREF WINAPI GetNearestColor(HDC hdc,COLORREF color); - WINGDIAPI UINT WINAPI GetNearestPaletteIndex(HPALETTE h,COLORREF color); - WINGDIAPI DWORD WINAPI GetObjectType(HGDIOBJ h); - -#ifndef NOTEXTMETRIC -#ifdef UNICODE -#define GetOutlineTextMetrics GetOutlineTextMetricsW -#else -#define GetOutlineTextMetrics GetOutlineTextMetricsA -#endif - - WINGDIAPI UINT WINAPI GetOutlineTextMetricsA(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICA potm); - WINGDIAPI UINT WINAPI GetOutlineTextMetricsW(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICW potm); -#endif - -#ifdef UNICODE -#define GetTextExtentPoint GetTextExtentPointW -#define GetTextExtentPoint32 GetTextExtentPoint32W -#define GetTextExtentExPoint GetTextExtentExPointW -#define GetCharacterPlacement GetCharacterPlacementW -#else -#define GetTextExtentPoint GetTextExtentPointA -#define GetTextExtentPoint32 GetTextExtentPoint32A -#define GetTextExtentExPoint GetTextExtentExPointA -#define GetCharacterPlacement GetCharacterPlacementA -#endif - - WINGDIAPI UINT WINAPI GetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); - WINGDIAPI COLORREF WINAPI GetPixel(HDC hdc,int x,int y); - WINGDIAPI int WINAPI GetPixelFormat(HDC hdc); - WINGDIAPI int WINAPI GetPolyFillMode(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS lpraststat,UINT cjBytes); - WINGDIAPI int WINAPI GetRandomRgn (HDC hdc,HRGN hrgn,INT i); - WINGDIAPI DWORD WINAPI GetRegionData(HRGN hrgn,DWORD nCount,LPRGNDATA lpRgnData); - WINGDIAPI int WINAPI GetRgnBox(HRGN hrgn,LPRECT lprc); - WINGDIAPI HGDIOBJ WINAPI GetStockObject(int i); - WINGDIAPI int WINAPI GetStretchBltMode(HDC hdc); - WINGDIAPI UINT WINAPI GetSystemPaletteEntries(HDC hdc,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); - WINGDIAPI UINT WINAPI GetSystemPaletteUse(HDC hdc); - WINGDIAPI int WINAPI GetTextCharacterExtra(HDC hdc); - WINGDIAPI UINT WINAPI GetTextAlign(HDC hdc); - WINGDIAPI COLORREF WINAPI GetTextColor(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointA(HDC hdc,LPCSTR lpString,int c,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointW(HDC hdc,LPCWSTR lpString,int c,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32A(HDC hdc,LPCSTR lpString,int c,LPSIZE psizl); - WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32W(HDC hdc,LPCWSTR lpString,int c,LPSIZE psizl); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointA(HDC hdc,LPCSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointW(HDC hdc,LPCWSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI int WINAPI GetTextCharset(HDC hdc); - WINGDIAPI int WINAPI GetTextCharsetInfo(HDC hdc,LPFONTSIGNATURE lpSig,DWORD dwFlags); - WINGDIAPI WINBOOL WINAPI TranslateCharsetInfo(DWORD *lpSrc,LPCHARSETINFO lpCs,DWORD dwFlags); - WINGDIAPI DWORD WINAPI GetFontLanguageInfo(HDC hdc); - WINGDIAPI DWORD WINAPI GetCharacterPlacementA(HDC hdc,LPCSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSA lpResults,DWORD dwFlags); - WINGDIAPI DWORD WINAPI GetCharacterPlacementW(HDC hdc,LPCWSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSW lpResults,DWORD dwFlags); - - typedef struct tagWCRANGE { - WCHAR wcLow; - USHORT cGlyphs; - } WCRANGE,*PWCRANGE,*LPWCRANGE; - - typedef struct tagGLYPHSET { - DWORD cbThis; - DWORD flAccel; - DWORD cGlyphsSupported; - DWORD cRanges; - WCRANGE ranges[1]; - } GLYPHSET,*PGLYPHSET,*LPGLYPHSET; - -#define GS_8BIT_INDICES 0x00000001 - -#define GGI_MARK_NONEXISTING_GLYPHS 0X0001 - -#ifdef UNICODE -#define GetGlyphIndices GetGlyphIndicesW -#else -#define GetGlyphIndices GetGlyphIndicesA -#endif - - WINGDIAPI DWORD WINAPI GetFontUnicodeRanges(HDC hdc,LPGLYPHSET lpgs); - WINGDIAPI DWORD WINAPI GetGlyphIndicesA(HDC hdc,LPCSTR lpstr,int c,LPWORD pgi,DWORD fl); - WINGDIAPI DWORD WINAPI GetGlyphIndicesW(HDC hdc,LPCWSTR lpstr,int c,LPWORD pgi,DWORD fl); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointI(HDC hdc,LPWORD pgiIn,int cgi,LPSIZE psize); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointI (HDC hdc,LPWORD lpwszString,int cwchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI WINBOOL WINAPI GetCharWidthI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPINT piWidths); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPABC pabc); - -#define STAMP_DESIGNVECTOR (0x8000000 + 'd' + ('v' << 8)) -#define STAMP_AXESLIST (0x8000000 + 'a' + ('l' << 8)) -#define MM_MAX_NUMAXES 16 - - typedef struct tagDESIGNVECTOR { - DWORD dvReserved; - DWORD dvNumAxes; - LONG dvValues[MM_MAX_NUMAXES]; - } DESIGNVECTOR,*PDESIGNVECTOR,*LPDESIGNVECTOR; - -#ifdef UNICODE -#define AddFontResourceEx AddFontResourceExW -#define RemoveFontResourceEx RemoveFontResourceExW -#else -#define AddFontResourceEx AddFontResourceExA -#define RemoveFontResourceEx RemoveFontResourceExA -#endif - - WINGDIAPI int WINAPI AddFontResourceExA(LPCSTR name,DWORD fl,PVOID res); - WINGDIAPI int WINAPI AddFontResourceExW(LPCWSTR name,DWORD fl,PVOID res); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceExA(LPCSTR name,DWORD fl,PVOID pdv); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceExW(LPCWSTR name,DWORD fl,PVOID pdv); - WINGDIAPI HANDLE WINAPI AddFontMemResourceEx(PVOID pFileView,DWORD cjSize,PVOID pvResrved,DWORD *pNumFonts); - WINGDIAPI WINBOOL WINAPI RemoveFontMemResourceEx(HANDLE h); - -#define FR_PRIVATE 0x10 -#define FR_NOT_ENUM 0x20 - -#define MM_MAX_AXES_NAMELEN 16 - - typedef struct tagAXISINFOA { - LONG axMinValue; - LONG axMaxValue; - BYTE axAxisName[MM_MAX_AXES_NAMELEN]; - } AXISINFOA,*PAXISINFOA,*LPAXISINFOA; - - typedef struct tagAXISINFOW { - LONG axMinValue; - LONG axMaxValue; - WCHAR axAxisName[MM_MAX_AXES_NAMELEN]; - } AXISINFOW,*PAXISINFOW,*LPAXISINFOW; -#ifdef UNICODE - typedef AXISINFOW AXISINFO; - typedef PAXISINFOW PAXISINFO; - typedef LPAXISINFOW LPAXISINFO; -#else - typedef AXISINFOA AXISINFO; - typedef PAXISINFOA PAXISINFO; - typedef LPAXISINFOA LPAXISINFO; -#endif - - typedef struct tagAXESLISTA { - DWORD axlReserved; - DWORD axlNumAxes; - AXISINFOA axlAxisInfo[MM_MAX_NUMAXES]; - } AXESLISTA,*PAXESLISTA,*LPAXESLISTA; - - typedef struct tagAXESLISTW { - DWORD axlReserved; - DWORD axlNumAxes; - AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; - } AXESLISTW,*PAXESLISTW,*LPAXESLISTW; -#ifdef UNICODE - typedef AXESLISTW AXESLIST; - typedef PAXESLISTW PAXESLIST; - typedef LPAXESLISTW LPAXESLIST; -#else - typedef AXESLISTA AXESLIST; - typedef PAXESLISTA PAXESLIST; - typedef LPAXESLISTA LPAXESLIST; -#endif - - typedef struct tagENUMLOGFONTEXDVA { - ENUMLOGFONTEXA elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - } ENUMLOGFONTEXDVA,*PENUMLOGFONTEXDVA,*LPENUMLOGFONTEXDVA; - - typedef struct tagENUMLOGFONTEXDVW { - ENUMLOGFONTEXW elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - } ENUMLOGFONTEXDVW,*PENUMLOGFONTEXDVW,*LPENUMLOGFONTEXDVW; -#ifdef UNICODE - typedef ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; - typedef PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; - typedef LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; -#else - typedef ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; - typedef PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; - typedef LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; -#endif - -#ifdef UNICODE -#define CreateFontIndirectEx CreateFontIndirectExW -#else -#define CreateFontIndirectEx CreateFontIndirectExA -#endif - - WINGDIAPI HFONT WINAPI CreateFontIndirectExA(CONST ENUMLOGFONTEXDVA *); - WINGDIAPI HFONT WINAPI CreateFontIndirectExW(CONST ENUMLOGFONTEXDVW *); - -#ifndef NOTEXTMETRIC - typedef struct tagENUMTEXTMETRICA { - NEWTEXTMETRICEXA etmNewTextMetricEx; - AXESLISTA etmAxesList; - } ENUMTEXTMETRICA,*PENUMTEXTMETRICA,*LPENUMTEXTMETRICA; - typedef struct tagENUMTEXTMETRICW - { - NEWTEXTMETRICEXW etmNewTextMetricEx; - AXESLISTW etmAxesList; - } ENUMTEXTMETRICW,*PENUMTEXTMETRICW,*LPENUMTEXTMETRICW; -#ifdef UNICODE - typedef ENUMTEXTMETRICW ENUMTEXTMETRIC; - typedef PENUMTEXTMETRICW PENUMTEXTMETRIC; - typedef LPENUMTEXTMETRICW LPENUMTEXTMETRIC; -#else - typedef ENUMTEXTMETRICA ENUMTEXTMETRIC; - typedef PENUMTEXTMETRICA PENUMTEXTMETRIC; - typedef LPENUMTEXTMETRICA LPENUMTEXTMETRIC; -#endif -#endif - -#ifdef UNICODE -#define ResetDC ResetDCW -#define RemoveFontResource RemoveFontResourceW -#else -#define ResetDC ResetDCA -#define RemoveFontResource RemoveFontResourceA -#endif - - WINGDIAPI WINBOOL WINAPI GetViewportExtEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI WINBOOL WINAPI GetViewportOrgEx(HDC hdc,LPPOINT lppoint); - WINGDIAPI WINBOOL WINAPI GetWindowExtEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI WINBOOL WINAPI GetWindowOrgEx(HDC hdc,LPPOINT lppoint); - WINGDIAPI int WINAPI IntersectClipRect(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI WINBOOL WINAPI InvertRgn(HDC hdc,HRGN hrgn); - WINGDIAPI WINBOOL WINAPI LineDDA(int xStart,int yStart,int xEnd,int yEnd,LINEDDAPROC lpProc,LPARAM data); - WINGDIAPI WINBOOL WINAPI LineTo(HDC hdc,int x,int y); - WINGDIAPI WINBOOL WINAPI MaskBlt(HDC hdcDest,int xDest,int yDest,int width,int height,HDC hdcSrc,int xSrc,int ySrc,HBITMAP hbmMask,int xMask,int yMask,DWORD rop); - WINGDIAPI WINBOOL WINAPI PlgBlt(HDC hdcDest,CONST POINT *lpPoint,HDC hdcSrc,int xSrc,int ySrc,int width,int height,HBITMAP hbmMask,int xMask,int yMask); - WINGDIAPI int WINAPI OffsetClipRgn(HDC hdc,int x,int y); - WINGDIAPI int WINAPI OffsetRgn(HRGN hrgn,int x,int y); - WINGDIAPI WINBOOL WINAPI PatBlt(HDC hdc,int x,int y,int w,int h,DWORD rop); - WINGDIAPI WINBOOL WINAPI Pie(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); - WINGDIAPI WINBOOL WINAPI PlayMetaFile(HDC hdc,HMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI PaintRgn(HDC hdc,HRGN hrgn); - WINGDIAPI WINBOOL WINAPI PolyPolygon(HDC hdc,CONST POINT *apt,CONST INT *asz,int csz); - WINGDIAPI WINBOOL WINAPI PtInRegion(HRGN hrgn,int x,int y); - WINGDIAPI WINBOOL WINAPI PtVisible(HDC hdc,int x,int y); - WINGDIAPI WINBOOL WINAPI RectInRegion(HRGN hrgn,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI RectVisible(HDC hdc,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI Rectangle(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI WINBOOL WINAPI RestoreDC(HDC hdc,int nSavedDC); - WINGDIAPI HDC WINAPI ResetDCA(HDC hdc,CONST DEVMODEA *lpdm); - WINGDIAPI HDC WINAPI ResetDCW(HDC hdc,CONST DEVMODEW *lpdm); - WINGDIAPI UINT WINAPI RealizePalette(HDC hdc); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceA(LPCSTR lpFileName); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceW(LPCWSTR lpFileName); - WINGDIAPI WINBOOL WINAPI RoundRect(HDC hdc,int left,int top,int right,int bottom,int width,int height); - WINGDIAPI WINBOOL WINAPI ResizePalette(HPALETTE hpal,UINT n); - WINGDIAPI int WINAPI SaveDC(HDC hdc); - WINGDIAPI int WINAPI SelectClipRgn(HDC hdc,HRGN hrgn); - WINGDIAPI int WINAPI ExtSelectClipRgn(HDC hdc,HRGN hrgn,int mode); - WINGDIAPI int WINAPI SetMetaRgn(HDC hdc); - WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC hdc,HGDIOBJ h); - WINGDIAPI HPALETTE WINAPI SelectPalette(HDC hdc,HPALETTE hPal,WINBOOL bForceBkgd); - WINGDIAPI COLORREF WINAPI SetBkColor(HDC hdc,COLORREF color); - WINGDIAPI COLORREF WINAPI SetDCBrushColor(HDC hdc,COLORREF color); - WINGDIAPI COLORREF WINAPI SetDCPenColor(HDC hdc,COLORREF color); - WINGDIAPI int WINAPI SetBkMode(HDC hdc,int mode); - WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP hbm,DWORD cb,CONST VOID *pvBits); - WINGDIAPI UINT WINAPI SetBoundsRect(HDC hdc,CONST RECT *lprect,UINT flags); - WINGDIAPI int WINAPI SetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); - WINGDIAPI int WINAPI SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD w,DWORD h,int xSrc,int ySrc,UINT StartScan,UINT cLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); - WINGDIAPI DWORD WINAPI SetMapperFlags(HDC hdc,DWORD flags); - WINGDIAPI int WINAPI SetGraphicsMode(HDC hdc,int iMode); - WINGDIAPI int WINAPI SetMapMode(HDC hdc,int iMode); - WINGDIAPI DWORD WINAPI SetLayout(HDC hdc,DWORD l); - WINGDIAPI DWORD WINAPI GetLayout(HDC hdc); - WINGDIAPI HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer,CONST BYTE *lpData); - WINGDIAPI UINT WINAPI SetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,CONST PALETTEENTRY *pPalEntries); - WINGDIAPI COLORREF WINAPI SetPixel(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI SetPixelV(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI SetPixelFormat(HDC hdc,int format,CONST PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI int WINAPI SetPolyFillMode(HDC hdc,int mode); - WINGDIAPI WINBOOL WINAPI StretchBlt(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop); - WINGDIAPI WINBOOL WINAPI SetRectRgn(HRGN hrgn,int left,int top,int right,int bottom); - WINGDIAPI int WINAPI StretchDIBits(HDC hdc,int xDest,int yDest,int DestWidth,int DestHeight,int xSrc,int ySrc,int SrcWidth,int SrcHeight,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD rop); - WINGDIAPI int WINAPI SetROP2(HDC hdc,int rop2); - WINGDIAPI int WINAPI SetStretchBltMode(HDC hdc,int mode); - WINGDIAPI UINT WINAPI SetSystemPaletteUse(HDC hdc,UINT use); - WINGDIAPI int WINAPI SetTextCharacterExtra(HDC hdc,int extra); - WINGDIAPI COLORREF WINAPI SetTextColor(HDC hdc,COLORREF color); - WINGDIAPI UINT WINAPI SetTextAlign(HDC hdc,UINT align); - WINGDIAPI WINBOOL WINAPI SetTextJustification(HDC hdc,int extra,int count); - WINGDIAPI WINBOOL WINAPI UpdateColors(HDC hdc); - - typedef USHORT COLOR16; - - typedef struct _TRIVERTEX { - LONG x; - LONG y; - COLOR16 Red; - COLOR16 Green; - COLOR16 Blue; - COLOR16 Alpha; - } TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX; - - typedef struct _GRADIENT_TRIANGLE { - ULONG Vertex1; - ULONG Vertex2; - ULONG Vertex3; - } GRADIENT_TRIANGLE,*PGRADIENT_TRIANGLE,*LPGRADIENT_TRIANGLE; - - typedef struct _GRADIENT_RECT { - ULONG UpperLeft; - ULONG LowerRight; - } GRADIENT_RECT,*PGRADIENT_RECT,*LPGRADIENT_RECT; - - typedef struct _BLENDFUNCTION { - BYTE BlendOp; - BYTE BlendFlags; - BYTE SourceConstantAlpha; - BYTE AlphaFormat; - } BLENDFUNCTION,*PBLENDFUNCTION; - -#define AC_SRC_OVER 0x00 -#define AC_SRC_ALPHA 0x01 - - WINGDIAPI WINBOOL WINAPI AlphaBlend(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,BLENDFUNCTION ftn); - WINGDIAPI WINBOOL WINAPI TransparentBlt(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,UINT crTransparent); - -#define GRADIENT_FILL_RECT_H 0x00000000 -#define GRADIENT_FILL_RECT_V 0x00000001 -#define GRADIENT_FILL_TRIANGLE 0x00000002 -#define GRADIENT_FILL_OP_FLAG 0x000000ff - - WINGDIAPI WINBOOL WINAPI GradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode); - -#ifndef NOMETAFILE - -#ifdef UNICODE -#define CopyEnhMetaFile CopyEnhMetaFileW -#define CreateEnhMetaFile CreateEnhMetaFileW -#define GetEnhMetaFile GetEnhMetaFileW -#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW -#else -#define CopyEnhMetaFile CopyEnhMetaFileA -#define CreateEnhMetaFile CreateEnhMetaFileA -#define GetEnhMetaFile GetEnhMetaFileA -#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA -#endif - - WINGDIAPI WINBOOL WINAPI PlayMetaFileRecord(HDC hdc,LPHANDLETABLE lpHandleTable,LPMETARECORD lpMR,UINT noObjs); - - typedef int (CALLBACK *MFENUMPROC)(HDC hdc,HANDLETABLE *lpht,METARECORD *lpMR,int nObj,LPARAM param); - - WINGDIAPI WINBOOL WINAPI EnumMetaFile(HDC hdc,HMETAFILE hmf,MFENUMPROC proc,LPARAM param); - - typedef int (CALLBACK *ENHMFENUMPROC)(HDC hdc,HANDLETABLE *lpht,CONST ENHMETARECORD *lpmr,int hHandles,LPARAM data); - - WINGDIAPI HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc); - WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE hEnh,LPCSTR lpFileName); - WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE hEnh,LPCWSTR lpFileName); - WINGDIAPI HDC WINAPI CreateEnhMetaFileA(HDC hdc,LPCSTR lpFilename,CONST RECT *lprc,LPCSTR lpDesc); - WINGDIAPI HDC WINAPI CreateEnhMetaFileW(HDC hdc,LPCWSTR lpFilename,CONST RECT *lprc,LPCWSTR lpDesc); - WINGDIAPI WINBOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC proc,LPVOID param,CONST RECT *lpRect); - WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR lpName); - WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR lpName); - WINGDIAPI UINT WINAPI GetEnhMetaFileBits(HENHMETAFILE hEMF,UINT nSize,LPBYTE lpData); - WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE hemf,UINT cchBuffer,LPSTR lpDescription); - WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE hemf,UINT cchBuffer,LPWSTR lpDescription); - WINGDIAPI UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE hemf,UINT nSize,LPENHMETAHEADER lpEnhMetaHeader); - WINGDIAPI UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,UINT nNumEntries,LPPALETTEENTRY lpPaletteEntries); - WINGDIAPI UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,UINT cbBuffer,PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,UINT cbData16,LPBYTE pData16,INT iMapMode,HDC hdcRef); - WINGDIAPI WINBOOL WINAPI PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE pht,CONST ENHMETARECORD *pmr,UINT cht); - WINGDIAPI HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT nSize,CONST BYTE *pb); - WINGDIAPI HENHMETAFILE WINAPI SetWinMetaFileBits(UINT nSize,CONST BYTE *lpMeta16Data,HDC hdcRef,CONST METAFILEPICT *lpMFP); - WINGDIAPI WINBOOL WINAPI GdiComment(HDC hdc,UINT nSize,CONST BYTE *lpData); -#endif - -#ifndef NOTEXTMETRIC -#ifdef UNICODE -#define GetTextMetrics GetTextMetricsW -#else -#define GetTextMetrics GetTextMetricsA -#endif - - WINGDIAPI WINBOOL WINAPI GetTextMetricsA(HDC hdc,LPTEXTMETRICA lptm); - WINGDIAPI WINBOOL WINAPI GetTextMetricsW(HDC hdc,LPTEXTMETRICW lptm); -#endif - - typedef struct tagDIBSECTION { - BITMAP dsBm; - BITMAPINFOHEADER dsBmih; - DWORD dsBitfields[3]; - HANDLE dshSection; - DWORD dsOffset; - } DIBSECTION,*LPDIBSECTION,*PDIBSECTION; - - WINGDIAPI WINBOOL WINAPI AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT StartAngle,FLOAT SweepAngle); - WINGDIAPI WINBOOL WINAPI PolyPolyline(HDC hdc,CONST POINT *apt,CONST DWORD *asz,DWORD csz); - WINGDIAPI WINBOOL WINAPI GetWorldTransform(HDC hdc,LPXFORM lpxf); - WINGDIAPI WINBOOL WINAPI SetWorldTransform(HDC hdc,CONST XFORM *lpxf); - WINGDIAPI WINBOOL WINAPI ModifyWorldTransform(HDC hdc,CONST XFORM *lpxf,DWORD mode); - WINGDIAPI WINBOOL WINAPI CombineTransform(LPXFORM lpxfOut,CONST XFORM *lpxf1,CONST XFORM *lpxf2); - WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC hdc,CONST BITMAPINFO *lpbmi,UINT usage,VOID **ppvBits,HANDLE hSection,DWORD offset); - WINGDIAPI UINT WINAPI GetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,RGBQUAD *prgbq); - WINGDIAPI UINT WINAPI SetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,CONST RGBQUAD *prgbq); - -#define CA_NEGATIVE 0x0001 -#define CA_LOG_FILTER 0x0002 - -#define ILLUMINANT_DEVICE_DEFAULT 0 -#define ILLUMINANT_A 1 -#define ILLUMINANT_B 2 -#define ILLUMINANT_C 3 -#define ILLUMINANT_D50 4 -#define ILLUMINANT_D55 5 -#define ILLUMINANT_D65 6 -#define ILLUMINANT_D75 7 -#define ILLUMINANT_F2 8 -#define ILLUMINANT_MAX_INDEX ILLUMINANT_F2 - -#define ILLUMINANT_TUNGSTEN ILLUMINANT_A -#define ILLUMINANT_DAYLIGHT ILLUMINANT_C -#define ILLUMINANT_FLUORESCENT ILLUMINANT_F2 -#define ILLUMINANT_NTSC ILLUMINANT_C - -#define RGB_GAMMA_MIN (WORD)02500 -#define RGB_GAMMA_MAX (WORD)65000 - -#define REFERENCE_WHITE_MIN (WORD)6000 -#define REFERENCE_WHITE_MAX (WORD)10000 -#define REFERENCE_BLACK_MIN (WORD)0 -#define REFERENCE_BLACK_MAX (WORD)4000 - -#define COLOR_ADJ_MIN (SHORT)-100 -#define COLOR_ADJ_MAX (SHORT)100 - - typedef struct tagCOLORADJUSTMENT { - WORD caSize; - WORD caFlags; - WORD caIlluminantIndex; - WORD caRedGamma; - WORD caGreenGamma; - WORD caBlueGamma; - WORD caReferenceBlack; - WORD caReferenceWhite; - SHORT caContrast; - SHORT caBrightness; - SHORT caColorfulness; - SHORT caRedGreenTint; - } COLORADJUSTMENT,*PCOLORADJUSTMENT,*LPCOLORADJUSTMENT; - - WINGDIAPI WINBOOL WINAPI SetColorAdjustment(HDC hdc,CONST COLORADJUSTMENT *lpca); - WINGDIAPI WINBOOL WINAPI GetColorAdjustment(HDC hdc,LPCOLORADJUSTMENT lpca); - WINGDIAPI HPALETTE WINAPI CreateHalftonePalette(HDC hdc); - - typedef WINBOOL (CALLBACK *ABORTPROC)(HDC,int); - - typedef struct _DOCINFOA { - int cbSize; - LPCSTR lpszDocName; - LPCSTR lpszOutput; - LPCSTR lpszDatatype; - DWORD fwType; - } DOCINFOA,*LPDOCINFOA; - - typedef struct _DOCINFOW { - int cbSize; - LPCWSTR lpszDocName; - LPCWSTR lpszOutput; - LPCWSTR lpszDatatype; - DWORD fwType; - } DOCINFOW,*LPDOCINFOW; - -#ifdef UNICODE - typedef DOCINFOW DOCINFO; - typedef LPDOCINFOW LPDOCINFO; -#else - typedef DOCINFOA DOCINFO; - typedef LPDOCINFOA LPDOCINFO; -#endif - -#define DI_APPBANDING 0x00000001 -#define DI_ROPS_READ_DESTINATION 0x00000002 - -#ifdef UNICODE -#define StartDoc StartDocW -#define GetObject GetObjectW -#define TextOut TextOutW -#define ExtTextOut ExtTextOutW -#define PolyTextOut PolyTextOutW -#define GetTextFace GetTextFaceW -#else -#define StartDoc StartDocA -#define GetObject GetObjectA -#define TextOut TextOutA -#define ExtTextOut ExtTextOutA -#define PolyTextOut PolyTextOutA -#define GetTextFace GetTextFaceA -#endif - - WINGDIAPI int WINAPI StartDocA(HDC hdc,CONST DOCINFOA *lpdi); - WINGDIAPI int WINAPI StartDocW(HDC hdc,CONST DOCINFOW *lpdi); - WINGDIAPI int WINAPI EndDoc(HDC hdc); - WINGDIAPI int WINAPI StartPage(HDC hdc); - WINGDIAPI int WINAPI EndPage(HDC hdc); - WINGDIAPI int WINAPI AbortDoc(HDC hdc); - WINGDIAPI int WINAPI SetAbortProc(HDC hdc,ABORTPROC proc); - WINGDIAPI WINBOOL WINAPI AbortPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI ArcTo(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); - WINGDIAPI WINBOOL WINAPI BeginPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI CloseFigure(HDC hdc); - WINGDIAPI WINBOOL WINAPI EndPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI FillPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI FlattenPath(HDC hdc); - WINGDIAPI int WINAPI GetPath(HDC hdc,LPPOINT apt,LPBYTE aj,int cpt); - WINGDIAPI HRGN WINAPI PathToRegion(HDC hdc); - WINGDIAPI WINBOOL WINAPI PolyDraw(HDC hdc,CONST POINT *apt,CONST BYTE *aj,int cpt); - WINGDIAPI WINBOOL WINAPI SelectClipPath(HDC hdc,int mode); - WINGDIAPI int WINAPI SetArcDirection(HDC hdc,int dir); - WINGDIAPI WINBOOL WINAPI SetMiterLimit(HDC hdc,FLOAT limit,PFLOAT old); - WINGDIAPI WINBOOL WINAPI StrokeAndFillPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI StrokePath(HDC hdc); - WINGDIAPI WINBOOL WINAPI WidenPath(HDC hdc); - WINGDIAPI HPEN WINAPI ExtCreatePen(DWORD iPenStyle,DWORD cWidth,CONST LOGBRUSH *plbrush,DWORD cStyle,CONST DWORD *pstyle); - WINGDIAPI WINBOOL WINAPI GetMiterLimit(HDC hdc,PFLOAT plimit); - WINGDIAPI int WINAPI GetArcDirection(HDC hdc); - WINGDIAPI int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv); - WINGDIAPI int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv); - WINGDIAPI WINBOOL WINAPI MoveToEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI TextOutA(HDC hdc,int x,int y,LPCSTR lpString,int c); - WINGDIAPI WINBOOL WINAPI TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c); - WINGDIAPI WINBOOL WINAPI ExtTextOutA(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCSTR lpString,UINT c,CONST INT *lpDx); - WINGDIAPI WINBOOL WINAPI ExtTextOutW(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCWSTR lpString,UINT c,CONST INT *lpDx); - WINGDIAPI WINBOOL WINAPI PolyTextOutA(HDC hdc,CONST POLYTEXTA *ppt,int nstrings); - WINGDIAPI WINBOOL WINAPI PolyTextOutW(HDC hdc,CONST POLYTEXTW *ppt,int nstrings); - WINGDIAPI HRGN WINAPI CreatePolygonRgn(CONST POINT *pptl,int cPoint,int iMode); - WINGDIAPI WINBOOL WINAPI DPtoLP(HDC hdc,LPPOINT lppt,int c); - WINGDIAPI WINBOOL WINAPI LPtoDP(HDC hdc,LPPOINT lppt,int c); - WINGDIAPI WINBOOL WINAPI Polygon(HDC hdc,CONST POINT *apt,int cpt); - WINGDIAPI WINBOOL WINAPI Polyline(HDC hdc,CONST POINT *apt,int cpt); - WINGDIAPI WINBOOL WINAPI PolyBezier(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI PolyBezierTo(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI PolylineTo(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI SetViewportExtEx(HDC hdc,int x,int y,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI SetWindowExtEx(HDC hdc,int x,int y,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI OffsetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI OffsetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI ScaleViewportExtEx(HDC hdc,int xn,int dx,int yn,int yd,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI ScaleWindowExtEx(HDC hdc,int xn,int xd,int yn,int yd,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetBitmapDimensionEx(HBITMAP hbm,int w,int h,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetBrushOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI int WINAPI GetTextFaceA(HDC hdc,int c,LPSTR lpName); - WINGDIAPI int WINAPI GetTextFaceW(HDC hdc,int c,LPWSTR lpName); - -#define FONTMAPPER_MAX 10 - - typedef struct tagKERNINGPAIR { - WORD wFirst; - WORD wSecond; - int iKernAmount; - } KERNINGPAIR,*LPKERNINGPAIR; - -#ifdef UNICODE -#define GetKerningPairs GetKerningPairsW -#else -#define GetKerningPairs GetKerningPairsA -#endif - - WINGDIAPI DWORD WINAPI GetKerningPairsA(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); - WINGDIAPI DWORD WINAPI GetKerningPairsW(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); - WINGDIAPI WINBOOL WINAPI GetDCOrgEx(HDC hdc,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI FixBrushOrgEx(HDC hdc,int x,int y,LPPOINT ptl); - WINGDIAPI WINBOOL WINAPI UnrealizeObject(HGDIOBJ h); - WINGDIAPI WINBOOL WINAPI GdiFlush(); - WINGDIAPI DWORD WINAPI GdiSetBatchLimit(DWORD dw); - WINGDIAPI DWORD WINAPI GdiGetBatchLimit(); - -#define ICM_OFF 1 -#define ICM_ON 2 -#define ICM_QUERY 3 -#define ICM_DONE_OUTSIDEDC 4 - - typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM); - typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM); - -#ifdef UNICODE -#define ICMENUMPROC ICMENUMPROCW -#define EnumICMProfiles EnumICMProfilesW -#define UpdateICMRegKey UpdateICMRegKeyW -#define GetLogColorSpace GetLogColorSpaceW -#define CreateColorSpace CreateColorSpaceW -#define GetICMProfile GetICMProfileW -#define SetICMProfile SetICMProfileW -#else -#define ICMENUMPROC ICMENUMPROCA -#define EnumICMProfiles EnumICMProfilesA -#define UpdateICMRegKey UpdateICMRegKeyA -#define GetLogColorSpace GetLogColorSpaceA -#define CreateColorSpace CreateColorSpaceA -#define GetICMProfile GetICMProfileA -#define SetICMProfile SetICMProfileA -#endif - - WINGDIAPI int WINAPI SetICMMode(HDC hdc,int mode); - WINGDIAPI WINBOOL WINAPI CheckColorsInGamut(HDC hdc,LPVOID lpRGBTriple,LPVOID dlpBuffer,DWORD nCount); - WINGDIAPI HCOLORSPACE WINAPI GetColorSpace(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetLogColorSpaceA(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEA lpBuffer,DWORD nSize); - WINGDIAPI WINBOOL WINAPI GetLogColorSpaceW(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEW lpBuffer,DWORD nSize); - WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA lplcs); - WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW lplcs); - WINGDIAPI HCOLORSPACE WINAPI SetColorSpace(HDC hdc,HCOLORSPACE hcs); - WINGDIAPI WINBOOL WINAPI DeleteColorSpace(HCOLORSPACE hcs); - WINGDIAPI WINBOOL WINAPI GetICMProfileA(HDC hdc,LPDWORD pBufSize,LPSTR pszFilename); - WINGDIAPI WINBOOL WINAPI GetICMProfileW(HDC hdc,LPDWORD pBufSize,LPWSTR pszFilename); - WINGDIAPI WINBOOL WINAPI SetICMProfileA(HDC hdc,LPSTR lpFileName); - WINGDIAPI WINBOOL WINAPI SetICMProfileW(HDC hdc,LPWSTR lpFileName); - WINGDIAPI WINBOOL WINAPI GetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); - WINGDIAPI WINBOOL WINAPI SetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); - WINGDIAPI WINBOOL WINAPI ColorMatchToTarget(HDC hdc,HDC hdcTarget,DWORD action); - WINGDIAPI int WINAPI EnumICMProfilesA(HDC hdc,ICMENUMPROCA proc,LPARAM param); - WINGDIAPI int WINAPI EnumICMProfilesW(HDC hdc,ICMENUMPROCW proc,LPARAM param); - WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyA(DWORD reserved,LPSTR lpszCMID,LPSTR lpszFileName,UINT command); - WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyW(DWORD reserved,LPWSTR lpszCMID,LPWSTR lpszFileName,UINT command); - WINGDIAPI WINBOOL WINAPI ColorCorrectPalette(HDC hdc,HPALETTE hPal,DWORD deFirst,DWORD num); - -#ifndef NOMETAFILE - -#define ENHMETA_SIGNATURE 0x464D4520 -#define ENHMETA_STOCK_OBJECT 0x80000000 - -#define EMR_HEADER 1 -#define EMR_POLYBEZIER 2 -#define EMR_POLYGON 3 -#define EMR_POLYLINE 4 -#define EMR_POLYBEZIERTO 5 -#define EMR_POLYLINETO 6 -#define EMR_POLYPOLYLINE 7 -#define EMR_POLYPOLYGON 8 -#define EMR_SETWINDOWEXTEX 9 -#define EMR_SETWINDOWORGEX 10 -#define EMR_SETVIEWPORTEXTEX 11 -#define EMR_SETVIEWPORTORGEX 12 -#define EMR_SETBRUSHORGEX 13 -#define EMR_EOF 14 -#define EMR_SETPIXELV 15 -#define EMR_SETMAPPERFLAGS 16 -#define EMR_SETMAPMODE 17 -#define EMR_SETBKMODE 18 -#define EMR_SETPOLYFILLMODE 19 -#define EMR_SETROP2 20 -#define EMR_SETSTRETCHBLTMODE 21 -#define EMR_SETTEXTALIGN 22 -#define EMR_SETCOLORADJUSTMENT 23 -#define EMR_SETTEXTCOLOR 24 -#define EMR_SETBKCOLOR 25 -#define EMR_OFFSETCLIPRGN 26 -#define EMR_MOVETOEX 27 -#define EMR_SETMETARGN 28 -#define EMR_EXCLUDECLIPRECT 29 -#define EMR_INTERSECTCLIPRECT 30 -#define EMR_SCALEVIEWPORTEXTEX 31 -#define EMR_SCALEWINDOWEXTEX 32 -#define EMR_SAVEDC 33 -#define EMR_RESTOREDC 34 -#define EMR_SETWORLDTRANSFORM 35 -#define EMR_MODIFYWORLDTRANSFORM 36 -#define EMR_SELECTOBJECT 37 -#define EMR_CREATEPEN 38 -#define EMR_CREATEBRUSHINDIRECT 39 -#define EMR_DELETEOBJECT 40 -#define EMR_ANGLEARC 41 -#define EMR_ELLIPSE 42 -#define EMR_RECTANGLE 43 -#define EMR_ROUNDRECT 44 -#define EMR_ARC 45 -#define EMR_CHORD 46 -#define EMR_PIE 47 -#define EMR_SELECTPALETTE 48 -#define EMR_CREATEPALETTE 49 -#define EMR_SETPALETTEENTRIES 50 -#define EMR_RESIZEPALETTE 51 -#define EMR_REALIZEPALETTE 52 -#define EMR_EXTFLOODFILL 53 -#define EMR_LINETO 54 -#define EMR_ARCTO 55 -#define EMR_POLYDRAW 56 -#define EMR_SETARCDIRECTION 57 -#define EMR_SETMITERLIMIT 58 -#define EMR_BEGINPATH 59 -#define EMR_ENDPATH 60 -#define EMR_CLOSEFIGURE 61 -#define EMR_FILLPATH 62 -#define EMR_STROKEANDFILLPATH 63 -#define EMR_STROKEPATH 64 -#define EMR_FLATTENPATH 65 -#define EMR_WIDENPATH 66 -#define EMR_SELECTCLIPPATH 67 -#define EMR_ABORTPATH 68 - -#define EMR_GDICOMMENT 70 -#define EMR_FILLRGN 71 -#define EMR_FRAMERGN 72 -#define EMR_INVERTRGN 73 -#define EMR_PAINTRGN 74 -#define EMR_EXTSELECTCLIPRGN 75 -#define EMR_BITBLT 76 -#define EMR_STRETCHBLT 77 -#define EMR_MASKBLT 78 -#define EMR_PLGBLT 79 -#define EMR_SETDIBITSTODEVICE 80 -#define EMR_STRETCHDIBITS 81 -#define EMR_EXTCREATEFONTINDIRECTW 82 -#define EMR_EXTTEXTOUTA 83 -#define EMR_EXTTEXTOUTW 84 -#define EMR_POLYBEZIER16 85 -#define EMR_POLYGON16 86 -#define EMR_POLYLINE16 87 -#define EMR_POLYBEZIERTO16 88 -#define EMR_POLYLINETO16 89 -#define EMR_POLYPOLYLINE16 90 -#define EMR_POLYPOLYGON16 91 -#define EMR_POLYDRAW16 92 -#define EMR_CREATEMONOBRUSH 93 -#define EMR_CREATEDIBPATTERNBRUSHPT 94 -#define EMR_EXTCREATEPEN 95 -#define EMR_POLYTEXTOUTA 96 -#define EMR_POLYTEXTOUTW 97 - -#define EMR_SETICMMODE 98 -#define EMR_CREATECOLORSPACE 99 -#define EMR_SETCOLORSPACE 100 -#define EMR_DELETECOLORSPACE 101 -#define EMR_GLSRECORD 102 -#define EMR_GLSBOUNDEDRECORD 103 -#define EMR_PIXELFORMAT 104 -#define EMR_RESERVED_105 105 -#define EMR_RESERVED_106 106 -#define EMR_RESERVED_107 107 -#define EMR_RESERVED_108 108 -#define EMR_RESERVED_109 109 -#define EMR_RESERVED_110 110 -#define EMR_COLORCORRECTPALETTE 111 -#define EMR_SETICMPROFILEA 112 -#define EMR_SETICMPROFILEW 113 -#define EMR_ALPHABLEND 114 -#define EMR_SETLAYOUT 115 -#define EMR_TRANSPARENTBLT 116 -#define EMR_RESERVED_117 117 -#define EMR_GRADIENTFILL 118 -#define EMR_RESERVED_119 119 -#define EMR_RESERVED_120 120 -#define EMR_COLORMATCHTOTARGETW 121 -#define EMR_CREATECOLORSPACEW 122 - -#define EMR_MIN 1 - -#define EMR_MAX 122 - - typedef struct tagEMR { - DWORD iType; - DWORD nSize; - } EMR,*PEMR; - - typedef struct tagEMRTEXT { - POINTL ptlReference; - DWORD nChars; - DWORD offString; - DWORD fOptions; - RECTL rcl; - DWORD offDx; - } EMRTEXT,*PEMRTEXT; - - typedef struct tagABORTPATH { - EMR emr; - } EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE; - - typedef struct tagEMRSELECTCLIPPATH { - EMR emr; - DWORD iMode; - } EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETLAYOUT,*PEMRSETLAYOUT, - EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETICMMODE, - *PEMRSETICMMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN; - - typedef struct tagEMRSETMITERLIMIT { - EMR emr; - FLOAT eMiterLimit; - } EMRSETMITERLIMIT,*PEMRSETMITERLIMIT; - - typedef struct tagEMRRESTOREDC { - EMR emr; - LONG iRelative; - } EMRRESTOREDC,*PEMRRESTOREDC; - - typedef struct tagEMRSETARCDIRECTION { - EMR emr; - DWORD iArcDirection; - - } EMRSETARCDIRECTION,*PEMRSETARCDIRECTION; - - typedef struct tagEMRSETMAPPERFLAGS { - EMR emr; - DWORD dwFlags; - } EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS; - - typedef struct tagEMRSETTEXTCOLOR { - EMR emr; - COLORREF crColor; - } EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR; - - typedef struct tagEMRSELECTOBJECT { - EMR emr; - DWORD ihObject; - } EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT; - - typedef struct tagEMRSELECTPALETTE { - EMR emr; - DWORD ihPal; - } EMRSELECTPALETTE,*PEMRSELECTPALETTE; - - typedef struct tagEMRRESIZEPALETTE { - EMR emr; - DWORD ihPal; - DWORD cEntries; - } EMRRESIZEPALETTE,*PEMRRESIZEPALETTE; - - typedef struct tagEMRSETPALETTEENTRIES { - EMR emr; - DWORD ihPal; - DWORD iStart; - DWORD cEntries; - PALETTEENTRY aPalEntries[1]; - } EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES; - - typedef struct tagEMRSETCOLORADJUSTMENT { - EMR emr; - COLORADJUSTMENT ColorAdjustment; - } EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT; - - typedef struct tagEMRGDICOMMENT { - EMR emr; - DWORD cbData; - BYTE Data[1]; - } EMRGDICOMMENT,*PEMRGDICOMMENT; - - typedef struct tagEMREOF { - EMR emr; - DWORD nPalEntries; - DWORD offPalEntries; - DWORD nSizeLast; - } EMREOF,*PEMREOF; - - typedef struct tagEMRLINETO { - EMR emr; - POINTL ptl; - } EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX; - - typedef struct tagEMROFFSETCLIPRGN { - EMR emr; - POINTL ptlOffset; - } EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN; - - typedef struct tagEMRFILLPATH { - EMR emr; - RECTL rclBounds; - } EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH; - - typedef struct tagEMREXCLUDECLIPRECT { - EMR emr; - RECTL rclClip; - } EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT; - - typedef struct tagEMRSETVIEWPORTORGEX { - EMR emr; - POINTL ptlOrigin; - } EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX; - - typedef struct tagEMRSETVIEWPORTEXTEX { - EMR emr; - SIZEL szlExtent; - } EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX; - - typedef struct tagEMRSCALEVIEWPORTEXTEX { - EMR emr; - LONG xNum; - LONG xDenom; - LONG yNum; - LONG yDenom; - } EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX; - - typedef struct tagEMRSETWORLDTRANSFORM { - EMR emr; - XFORM xform; - } EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM; - - typedef struct tagEMRMODIFYWORLDTRANSFORM { - EMR emr; - XFORM xform; - DWORD iMode; - } EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM; - - typedef struct tagEMRSETPIXELV { - EMR emr; - POINTL ptlPixel; - COLORREF crColor; - } EMRSETPIXELV,*PEMRSETPIXELV; - - typedef struct tagEMREXTFLOODFILL { - EMR emr; - POINTL ptlStart; - COLORREF crColor; - DWORD iMode; - } EMREXTFLOODFILL,*PEMREXTFLOODFILL; - - typedef struct tagEMRELLIPSE { - EMR emr; - RECTL rclBox; - } EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE; - - typedef struct tagEMRROUNDRECT { - EMR emr; - RECTL rclBox; - SIZEL szlCorner; - } EMRROUNDRECT,*PEMRROUNDRECT; - - typedef struct tagEMRARC { - EMR emr; - RECTL rclBox; - POINTL ptlStart; - POINTL ptlEnd; - } EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE; - - typedef struct tagEMRANGLEARC { - EMR emr; - POINTL ptlCenter; - DWORD nRadius; - FLOAT eStartAngle; - FLOAT eSweepAngle; - } EMRANGLEARC,*PEMRANGLEARC; - - typedef struct tagEMRPOLYLINE { - EMR emr; - RECTL rclBounds; - DWORD cptl; - POINTL aptl[1]; - } EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO; - - typedef struct tagEMRPOLYLINE16 { - EMR emr; - RECTL rclBounds; - DWORD cpts; - POINTS apts[1]; - } EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16; - - typedef struct tagEMRPOLYDRAW { - EMR emr; - RECTL rclBounds; - DWORD cptl; - POINTL aptl[1]; - BYTE abTypes[1]; - } EMRPOLYDRAW,*PEMRPOLYDRAW; - - typedef struct tagEMRPOLYDRAW16 { - EMR emr; - RECTL rclBounds; - DWORD cpts; - POINTS apts[1]; - BYTE abTypes[1]; - } EMRPOLYDRAW16,*PEMRPOLYDRAW16; - - typedef struct tagEMRPOLYPOLYLINE { - EMR emr; - RECTL rclBounds; - DWORD nPolys; - DWORD cptl; - DWORD aPolyCounts[1]; - POINTL aptl[1]; - } EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON; - - typedef struct tagEMRPOLYPOLYLINE16 { - EMR emr; - RECTL rclBounds; - DWORD nPolys; - DWORD cpts; - DWORD aPolyCounts[1]; - POINTS apts[1]; - } EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16; - - typedef struct tagEMRINVERTRGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - BYTE RgnData[1]; - } EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN; - - typedef struct tagEMRFILLRGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - DWORD ihBrush; - BYTE RgnData[1]; - } EMRFILLRGN,*PEMRFILLRGN; - - typedef struct tagEMRFRAMERGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - DWORD ihBrush; - SIZEL szlStroke; - BYTE RgnData[1]; - } EMRFRAMERGN,*PEMRFRAMERGN; - - typedef struct tagEMREXTSELECTCLIPRGN { - EMR emr; - DWORD cbRgnData; - DWORD iMode; - BYTE RgnData[1]; - } EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN; - - typedef struct tagEMREXTTEXTOUTA { - EMR emr; - RECTL rclBounds; - DWORD iGraphicsMode; - FLOAT exScale; - FLOAT eyScale; - EMRTEXT emrtext; - } EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW; - - typedef struct tagEMRPOLYTEXTOUTA { - EMR emr; - RECTL rclBounds; - DWORD iGraphicsMode; - FLOAT exScale; - FLOAT eyScale; - LONG cStrings; - EMRTEXT aemrtext[1]; - } EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW; - - typedef struct tagEMRBITBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - } EMRBITBLT,*PEMRBITBLT; - - typedef struct tagEMRSTRETCHBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRSTRETCHBLT,*PEMRSTRETCHBLT; - - typedef struct tagEMRMASKBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG xMask; - LONG yMask; - DWORD iUsageMask; - DWORD offBmiMask; - DWORD cbBmiMask; - DWORD offBitsMask; - DWORD cbBitsMask; - } EMRMASKBLT,*PEMRMASKBLT; - - typedef struct tagEMRPLGBLT { - EMR emr; - RECTL rclBounds; - POINTL aptlDest[3]; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG xMask; - LONG yMask; - DWORD iUsageMask; - DWORD offBmiMask; - DWORD cbBmiMask; - DWORD offBitsMask; - DWORD cbBitsMask; - } EMRPLGBLT,*PEMRPLGBLT; - - typedef struct tagEMRSETDIBITSTODEVICE { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - DWORD iUsageSrc; - DWORD iStartScan; - DWORD cScans; - } EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE; - - typedef struct tagEMRSTRETCHDIBITS { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - DWORD iUsageSrc; - DWORD dwRop; - LONG cxDest; - LONG cyDest; - } EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS; - - typedef struct tagEMREXTCREATEFONTINDIRECTW { - EMR emr; - DWORD ihFont; - EXTLOGFONTW elfw; - } EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW; - - typedef struct tagEMRCREATEPALETTE { - EMR emr; - DWORD ihPal; - LOGPALETTE lgpl; - } EMRCREATEPALETTE,*PEMRCREATEPALETTE; - - typedef struct tagEMRCREATEPEN { - EMR emr; - DWORD ihPen; - LOGPEN lopn; - } EMRCREATEPEN,*PEMRCREATEPEN; - - typedef struct tagEMREXTCREATEPEN { - EMR emr; - DWORD ihPen; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - EXTLOGPEN elp; - } EMREXTCREATEPEN,*PEMREXTCREATEPEN; - - typedef struct tagEMRCREATEBRUSHINDIRECT { - EMR emr; - DWORD ihBrush; - LOGBRUSH32 lb; - } EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT; - - typedef struct tagEMRCREATEMONOBRUSH { - EMR emr; - DWORD ihBrush; - DWORD iUsage; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - } EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH; - - typedef struct tagEMRCREATEDIBPATTERNBRUSHPT { - EMR emr; - DWORD ihBrush; - DWORD iUsage; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - } EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT; - - typedef struct tagEMRFORMAT { - DWORD dSignature; - DWORD nVersion; - DWORD cbData; - DWORD offData; - } EMRFORMAT,*PEMRFORMAT; - - typedef struct tagEMRGLSRECORD { - EMR emr; - DWORD cbData; - BYTE Data[1]; - } EMRGLSRECORD,*PEMRGLSRECORD; - - typedef struct tagEMRGLSBOUNDEDRECORD { - EMR emr; - RECTL rclBounds; - DWORD cbData; - BYTE Data[1]; - } EMRGLSBOUNDEDRECORD,*PEMRGLSBOUNDEDRECORD; - - typedef struct tagEMRPIXELFORMAT { - EMR emr; - PIXELFORMATDESCRIPTOR pfd; - } EMRPIXELFORMAT,*PEMRPIXELFORMAT; - - typedef struct tagEMRCREATECOLORSPACE { - EMR emr; - DWORD ihCS; - LOGCOLORSPACEA lcs; - } EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE; - - typedef struct tagEMRSETCOLORSPACE { - EMR emr; - DWORD ihCS; - } EMRSETCOLORSPACE,*PEMRSETCOLORSPACE,EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE; - - typedef struct tagEMREXTESCAPE { - EMR emr; - INT iEscape; - INT cbEscData; - BYTE EscData[1]; - } EMREXTESCAPE,*PEMREXTESCAPE,EMRDRAWESCAPE,*PEMRDRAWESCAPE; - - typedef struct tagEMRNAMEDESCAPE { - EMR emr; - INT iEscape; - INT cbDriver; - INT cbEscData; - BYTE EscData[1]; - } EMRNAMEDESCAPE,*PEMRNAMEDESCAPE; - -#define SETICMPROFILE_EMBEDED 0x00000001 - - typedef struct tagEMRSETICMPROFILE { - EMR emr; - DWORD dwFlags; - DWORD cbName; - DWORD cbData; - BYTE Data[1]; - } EMRSETICMPROFILE,*PEMRSETICMPROFILE,EMRSETICMPROFILEA,*PEMRSETICMPROFILEA,EMRSETICMPROFILEW,*PEMRSETICMPROFILEW; - -#define CREATECOLORSPACE_EMBEDED 0x00000001 - - typedef struct tagEMRCREATECOLORSPACEW { - EMR emr; - DWORD ihCS; - LOGCOLORSPACEW lcs; - DWORD dwFlags; - DWORD cbData; - BYTE Data[1]; - } EMRCREATECOLORSPACEW,*PEMRCREATECOLORSPACEW; - -#define COLORMATCHTOTARGET_EMBEDED 0x00000001 - - typedef struct tagCOLORMATCHTOTARGET { - EMR emr; - DWORD dwAction; - DWORD dwFlags; - DWORD cbName; - DWORD cbData; - BYTE Data[1]; - } EMRCOLORMATCHTOTARGET,*PEMRCOLORMATCHTOTARGET; - - typedef struct tagCOLORCORRECTPALETTE { - EMR emr; - DWORD ihPalette; - DWORD nFirstEntry; - DWORD nPalEntries; - DWORD nReserved; - } EMRCOLORCORRECTPALETTE,*PEMRCOLORCORRECTPALETTE; - - typedef struct tagEMRALPHABLEND { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRALPHABLEND,*PEMRALPHABLEND; - - typedef struct tagEMRGRADIENTFILL { - EMR emr; - RECTL rclBounds; - DWORD nVer; - DWORD nTri; - ULONG ulMode; - TRIVERTEX Ver[1]; - } EMRGRADIENTFILL,*PEMRGRADIENTFILL; - - typedef struct tagEMRTRANSPARENTBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRTRANSPARENTBLT,*PEMRTRANSPARENTBLT; - -#define GDICOMMENT_IDENTIFIER 0x43494447 -#define GDICOMMENT_WINDOWS_METAFILE 0x80000001 -#define GDICOMMENT_BEGINGROUP 0x00000002 -#define GDICOMMENT_ENDGROUP 0x00000003 -#define GDICOMMENT_MULTIFORMATS 0x40000004 -#define EPS_SIGNATURE 0x46535045 -#define GDICOMMENT_UNICODE_STRING 0x00000040 -#define GDICOMMENT_UNICODE_END 0x00000080 -#endif - -#ifdef UNICODE -#define wglUseFontBitmaps wglUseFontBitmapsW -#else -#define wglUseFontBitmaps wglUseFontBitmapsA -#endif - - WINGDIAPI WINBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT); - WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); - WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC,int); - WINGDIAPI WINBOOL WINAPI wglDeleteContext(HGLRC); - WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID); - WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID); - WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); - WINGDIAPI WINBOOL WINAPI wglMakeCurrent(HDC,HGLRC); - WINGDIAPI WINBOOL WINAPI wglShareLists(HGLRC,HGLRC); - WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD); - WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD); - WINGDIAPI WINBOOL WINAPI SwapBuffers(HDC); - - typedef struct _POINTFLOAT { - FLOAT x; - FLOAT y; - } POINTFLOAT,*PPOINTFLOAT; - - typedef struct _GLYPHMETRICSFLOAT { - FLOAT gmfBlackBoxX; - FLOAT gmfBlackBoxY; - POINTFLOAT gmfptGlyphOrigin; - FLOAT gmfCellIncX; - FLOAT gmfCellIncY; - } GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT; - -#define WGL_FONT_LINES 0 -#define WGL_FONT_POLYGONS 1 - -#ifdef UNICODE -#define wglUseFontOutlines wglUseFontOutlinesW -#else -#define wglUseFontOutlines wglUseFontOutlinesA -#endif - - WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); - WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); - - typedef struct tagLAYERPLANEDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerPlane; - BYTE bReserved; - COLORREF crTransparent; - } LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR; - -#define LPD_DOUBLEBUFFER 0x00000001 -#define LPD_STEREO 0x00000002 -#define LPD_SUPPORT_GDI 0x00000010 -#define LPD_SUPPORT_OPENGL 0x00000020 -#define LPD_SHARE_DEPTH 0x00000040 -#define LPD_SHARE_STENCIL 0x00000080 -#define LPD_SHARE_ACCUM 0x00000100 -#define LPD_SWAP_EXCHANGE 0x00000200 -#define LPD_SWAP_COPY 0x00000400 -#define LPD_TRANSPARENT 0x00001000 - -#define LPD_TYPE_RGBA 0 -#define LPD_TYPE_COLORINDEX 1 - -#define WGL_SWAP_MAIN_PLANE 0x00000001 -#define WGL_SWAP_OVERLAY1 0x00000002 -#define WGL_SWAP_OVERLAY2 0x00000004 -#define WGL_SWAP_OVERLAY3 0x00000008 -#define WGL_SWAP_OVERLAY4 0x00000010 -#define WGL_SWAP_OVERLAY5 0x00000020 -#define WGL_SWAP_OVERLAY6 0x00000040 -#define WGL_SWAP_OVERLAY7 0x00000080 -#define WGL_SWAP_OVERLAY8 0x00000100 -#define WGL_SWAP_OVERLAY9 0x00000200 -#define WGL_SWAP_OVERLAY10 0x00000400 -#define WGL_SWAP_OVERLAY11 0x00000800 -#define WGL_SWAP_OVERLAY12 0x00001000 -#define WGL_SWAP_OVERLAY13 0x00002000 -#define WGL_SWAP_OVERLAY14 0x00004000 -#define WGL_SWAP_OVERLAY15 0x00008000 -#define WGL_SWAP_UNDERLAY1 0x00010000 -#define WGL_SWAP_UNDERLAY2 0x00020000 -#define WGL_SWAP_UNDERLAY3 0x00040000 -#define WGL_SWAP_UNDERLAY4 0x00080000 -#define WGL_SWAP_UNDERLAY5 0x00100000 -#define WGL_SWAP_UNDERLAY6 0x00200000 -#define WGL_SWAP_UNDERLAY7 0x00400000 -#define WGL_SWAP_UNDERLAY8 0x00800000 -#define WGL_SWAP_UNDERLAY9 0x01000000 -#define WGL_SWAP_UNDERLAY10 0x02000000 -#define WGL_SWAP_UNDERLAY11 0x04000000 -#define WGL_SWAP_UNDERLAY12 0x08000000 -#define WGL_SWAP_UNDERLAY13 0x10000000 -#define WGL_SWAP_UNDERLAY14 0x20000000 -#define WGL_SWAP_UNDERLAY15 0x40000000 - - WINGDIAPI WINBOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR); - WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,CONST COLORREF *); - WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF *); - WINGDIAPI WINBOOL WINAPI wglRealizeLayerPalette(HDC,int,WINBOOL); - WINGDIAPI WINBOOL WINAPI wglSwapLayerBuffers(HDC,UINT); - - typedef struct _WGLSWAP { - HDC hdc; - UINT uiFlags; - } WGLSWAP,*PWGLSWAP,*LPWGLSWAP; - -#define WGL_SWAPMULTIPLE_MAX 16 - - WINGDIAPI DWORD WINAPI wglSwapMultipleBuffers(UINT,CONST WGLSWAP *); -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/winnt.h b/tinyc/win32/include/winapi/winnt.h deleted file mode 100644 index 4cf685d2a..000000000 --- a/tinyc/win32/include/winapi/winnt.h +++ /dev/null @@ -1,5835 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINNT_ -#define _WINNT_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#define ANYSIZE_ARRAY 1 - -//gr #include - -#define RESTRICTED_POINTER - -#ifndef __CRT_UNALIGNED -#define __CRT_UNALIGNED -#endif - -#if defined(__ia64__) || defined(__x86_64) -#define UNALIGNED __CRT_UNALIGNED -#ifdef _WIN64 -#define UNALIGNED64 __CRT_UNALIGNED -#else -#define UNALIGNED64 -#endif -#else -#define UNALIGNED -#define UNALIGNED64 -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) -#define I_X86_ -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) -#define _AMD64_ -#endif - -#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) -#if !defined(_IA64_) -#define _IA64_ -#endif -#endif - - -#ifdef _WIN64 -#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) -#define MEMORY_ALLOCATION_ALIGNMENT 16 -#else -#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) -#define MEMORY_ALLOCATION_ALIGNMENT 8 -#endif - -#ifdef __cplusplus -#define TYPE_ALIGNMENT(t) __alignof__ (t) -#else -#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) -#endif - -#ifdef _WIN64 -#ifdef _AMD64_ -#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) -#elif defined(_IA64_) -#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD)) -#else -#error No Target Architecture -#endif -#define PROBE_ALIGNMENT32(_s) TYPE_ALIGNMENT(DWORD) -#else -#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) -#endif - -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] - -#include - -#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) -#define DECLSPEC_IMPORT __declspec(dllimport) -#else -#define DECLSPEC_IMPORT -#endif - -#ifndef DECLSPEC_NORETURN -#define DECLSPEC_NORETURN __declspec(noreturn) -#endif - -#ifndef DECLSPEC_ALIGN -#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) -#endif - -#ifndef SYSTEM_CACHE_ALIGNMENT_SIZE -#if defined(_AMD64_) || defined(I_X86_) -#define SYSTEM_CACHE_ALIGNMENT_SIZE 64 -#else -#define SYSTEM_CACHE_ALIGNMENT_SIZE 128 -#endif -#endif - -#ifndef DECLSPEC_CACHEALIGN -#define DECLSPEC_CACHEALIGN DECLSPEC_ALIGN(SYSTEM_CACHE_ALIGNMENT_SIZE) -#endif - -#ifndef DECLSPEC_UUID -#define DECLSPEC_UUID(x) -#endif - -#ifndef DECLSPEC_NOVTABLE -#define DECLSPEC_NOVTABLE -#endif - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -#ifndef NOP_FUNCTION -#define NOP_FUNCTION (void)0 -#endif - -#ifndef DECLSPEC_NOINLINE -#define DECLSPEC_NOINLINE -#endif - -#ifndef FORCEINLINE -#define FORCEINLINE static __inline__ -#endif - -#ifndef DECLSPEC_DEPRECATED -#define DECLSPEC_DEPRECATED __declspec(deprecated) -#define DEPRECATE_SUPPORTED -#endif - -#define DECLSPEC_DEPRECATED_DDK -#define PRAGMA_DEPRECATED_DDK 0 - - typedef void *PVOID; - typedef void *PVOID64; - -#define NTAPI __stdcall -#define NTSYSAPI DECLSPEC_IMPORT -#define NTSYSCALLAPI DECLSPEC_IMPORT - -#ifndef VOID -#define VOID void - typedef char CHAR; - typedef short SHORT; - typedef long LONG; -#endif - - typedef wchar_t WCHAR; - typedef WCHAR *PWCHAR,*LPWCH,*PWCH; - typedef CONST WCHAR *LPCWCH,*PCWCH; - typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR; - typedef PWSTR *PZPWSTR; - typedef CONST PWSTR *PCZPWSTR; - typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR; - typedef CONST WCHAR *LPCWSTR,*PCWSTR; - typedef PCWSTR *PZPCWSTR; - typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR; - typedef CHAR *PCHAR,*LPCH,*PCH; - typedef CONST CHAR *LPCCH,*PCCH; - typedef CHAR *NPSTR,*LPSTR,*PSTR; - typedef PSTR *PZPSTR; - typedef CONST PSTR *PCZPSTR; - typedef CONST CHAR *LPCSTR,*PCSTR; - typedef PCSTR *PZPCSTR; - -#ifdef UNICODE -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED - typedef WCHAR TCHAR,*PTCHAR; - typedef WCHAR TBYTE ,*PTBYTE; -#endif - - typedef LPWSTR LPTCH,PTCH; - typedef LPWSTR PTSTR,LPTSTR; - typedef LPCWSTR PCTSTR,LPCTSTR; - typedef LPUWSTR PUTSTR,LPUTSTR; - typedef LPCUWSTR PCUTSTR,LPCUTSTR; - typedef LPWSTR LP; -#define __TEXT(quote) L##quote -#else -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED - typedef char TCHAR,*PTCHAR; - typedef unsigned char TBYTE ,*PTBYTE; -#endif - - typedef LPSTR LPTCH,PTCH; - typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; - typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; -#define __TEXT(quote) quote -#endif - -#define TEXT(quote) __TEXT(quote) - - typedef SHORT *PSHORT; - typedef LONG *PLONG; - - typedef void *HANDLE; -#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name - typedef HANDLE *PHANDLE; - - typedef BYTE FCHAR; - typedef WORD FSHORT; - typedef DWORD FLONG; - -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED - typedef LONG HRESULT; -#endif - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif - -#define STDMETHODCALLTYPE WINAPI -#define STDMETHODVCALLTYPE __cdecl -#define STDAPICALLTYPE WINAPI -#define STDAPIVCALLTYPE __cdecl -#define STDAPI EXTERN_C HRESULT WINAPI -#define STDAPI_(type) EXTERN_C type WINAPI -#define STDMETHODIMP HRESULT WINAPI -#define STDMETHODIMP_(type) type WINAPI -#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE -#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE -#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE -#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE - - typedef char CCHAR; -#ifndef _LCID_DEFINED -#define _LCID_DEFINED -typedef DWORD LCID; -#endif - typedef PDWORD PLCID; -#ifndef _LANGID_DEFINED -#define _LANGID_DEFINED - typedef WORD LANGID; -#endif -#define APPLICATION_ERROR_MASK 0x20000000 -#define ERROR_SEVERITY_SUCCESS 0x00000000 -#define ERROR_SEVERITY_INFORMATIONAL 0x40000000 -#define ERROR_SEVERITY_WARNING 0x80000000 -#define ERROR_SEVERITY_ERROR 0xC0000000 - -#ifdef __ia64__ - __declspec(align(16)) -#endif - typedef struct _FLOAT128 { - __int64 LowPart; - __int64 HighPart; - } FLOAT128; - - typedef FLOAT128 *PFLOAT128; - -#define _ULONGLONG_ -#if((!(defined(_X86_) && !defined(__x86_64)) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))) - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - -#define MAXLONGLONG (0x7fffffffffffffff) -#else - - typedef double LONGLONG; - typedef double ULONGLONG; -#endif - - typedef LONGLONG *PLONGLONG; - typedef ULONGLONG *PULONGLONG; - - typedef LONGLONG USN; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - }; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef LARGE_INTEGER *PLARGE_INTEGER; - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - }; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef ULARGE_INTEGER *PULARGE_INTEGER; - - typedef struct _LUID { - DWORD LowPart; - LONG HighPart; - } LUID,*PLUID; - -#define _DWORDLONG_ - typedef ULONGLONG DWORDLONG; - typedef DWORDLONG *PDWORDLONG; - -#ifdef RC_INVOKED -#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) -#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) -#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) -#elif (defined(_X86_) && !defined(__x86_64)) -#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b)) -#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b)) -#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b)) -#elif defined(__ia64__) || defined(__x86_64) -#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) -#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) -#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) -#else -#error Must define a target architecture. -#endif - -#define Int64ShraMod32(a,b) ((LONGLONG)(a) >> (b)) -#define Int64ShllMod32(a,b) ((ULONGLONG)(a) << (b)) - -#ifdef __cplusplus - extern "C" { -#endif - -#ifdef __x86_64 - -#define RotateLeft8 _rotl8 -#define RotateLeft16 _rotl16 -#define RotateRight8 _rotr8 -#define RotateRight16 _rotr16 - - unsigned char __cdecl _rotl8(unsigned char Value,unsigned char Shift); - unsigned short __cdecl _rotl16(unsigned short Value,unsigned char Shift); - unsigned char __cdecl _rotr8(unsigned char Value,unsigned char Shift); - unsigned short __cdecl _rotr16(unsigned short Value,unsigned char Shift); -#endif - -#define RotateLeft32 _rotl -#define RotateLeft64 _rotl64 -#define RotateRight32 _rotr -#define RotateRight64 _rotr64 - - unsigned int __cdecl _rotl(unsigned int Value,int Shift); - unsigned __int64 __cdecl _rotl64(unsigned __int64 Value,int Shift); - unsigned int __cdecl _rotr(unsigned int Value,int Shift); - unsigned __int64 __cdecl _rotr64(unsigned __int64 Value,int Shift); -#ifdef __cplusplus - } -#endif - -#define ANSI_NULL ((CHAR)0) -#define UNICODE_NULL ((WCHAR)0) -#define UNICODE_STRING_MAX_BYTES ((WORD) 65534) -#define UNICODE_STRING_MAX_CHARS (32767) - -#ifndef _BOOLEAN_ -#define _BOOLEAN_ - typedef BYTE BOOLEAN; -#endif - typedef BOOLEAN *PBOOLEAN; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY,*PLIST_ENTRY,*RESTRICTED_POINTER PRLIST_ENTRY; - - typedef struct _SINGLE_LIST_ENTRY { - struct _SINGLE_LIST_ENTRY *Next; - } SINGLE_LIST_ENTRY,*PSINGLE_LIST_ENTRY; - - typedef struct LIST_ENTRY32 { - DWORD Flink; - DWORD Blink; - } LIST_ENTRY32; - typedef LIST_ENTRY32 *PLIST_ENTRY32; - - typedef struct LIST_ENTRY64 { - ULONGLONG Flink; - ULONGLONG Blink; - } LIST_ENTRY64; - typedef LIST_ENTRY64 *PLIST_ENTRY64; - -#include - -#ifndef __OBJECTID_DEFINED -#define __OBJECTID_DEFINED - typedef struct _OBJECTID { - GUID Lineage; - DWORD Uniquifier; - } OBJECTID; -#endif - -#define MINCHAR 0x80 -#define MAXCHAR 0x7f -#define MINSHORT 0x8000 -#define MAXSHORT 0x7fff -#define MINLONG 0x80000000 -#define MAXLONG 0x7fffffff -#define MAXBYTE 0xff -#define MAXWORD 0xffff -#define MAXDWORD 0xffffffff - -#define FIELD_OFFSET(type,field) ((LONG)(LONG_PTR)&(((type *)0)->field)) -#define RTL_FIELD_SIZE(type,field) (sizeof(((type *)0)->field)) -#define RTL_SIZEOF_THROUGH_FIELD(type,field) (FIELD_OFFSET(type,field) + RTL_FIELD_SIZE(type,field)) -#define RTL_CONTAINS_FIELD(Struct,Size,Field) ((((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size))) -#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) -#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) - -#ifdef ENABLE_RTL_NUMBER_OF_V2 -#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A) -#else -#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) -#endif - -#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) -#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) - -#define RTL_FIELD_TYPE(type,field) (((type*)0)->field) -#define RTL_NUMBER_OF_FIELD(type,field) (RTL_NUMBER_OF(RTL_FIELD_TYPE(type,field))) -#define RTL_PADDING_BETWEEN_FIELDS(T,F1,F2) ((FIELD_OFFSET(T,F2) > FIELD_OFFSET(T,F1)) ? (FIELD_OFFSET(T,F2) - FIELD_OFFSET(T,F1) - RTL_FIELD_SIZE(T,F1)) : (FIELD_OFFSET(T,F1) - FIELD_OFFSET(T,F2) - RTL_FIELD_SIZE(T,F2))) - -#ifdef __cplusplus -#define RTL_CONST_CAST(type) const_cast -#else -#define RTL_CONST_CAST(type) (type) -#endif - -#define RTL_BITS_OF(sizeOfArg) (sizeof(sizeOfArg) *8) -#define RTL_BITS_OF_FIELD(type,field) (RTL_BITS_OF(RTL_FIELD_TYPE(type,field))) -#define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) - -#define VER_SERVER_NT 0x80000000 -#define VER_WORKSTATION_NT 0x40000000 -#define VER_SUITE_SMALLBUSINESS 0x00000001 -#define VER_SUITE_ENTERPRISE 0x00000002 -#define VER_SUITE_BACKOFFICE 0x00000004 -#define VER_SUITE_COMMUNICATIONS 0x00000008 -#define VER_SUITE_TERMINAL 0x00000010 -#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020 -#define VER_SUITE_EMBEDDEDNT 0x00000040 -#define VER_SUITE_DATACENTER 0x00000080 -#define VER_SUITE_SINGLEUSERTS 0x00000100 -#define VER_SUITE_PERSONAL 0x00000200 -#define VER_SUITE_BLADE 0x00000400 -#define VER_SUITE_EMBEDDED_RESTRICTED 0x00000800 -#define VER_SUITE_SECURITY_APPLIANCE 0x00001000 -#define VER_SUITE_STORAGE_SERVER 0x00002000 -#define VER_SUITE_COMPUTE_SERVER 0x00004000 - -#define PRODUCT_UNDEFINED 0x0 - -#define PRODUCT_ULTIMATE 0x1 -#define PRODUCT_HOME_BASIC 0x2 -#define PRODUCT_HOME_PREMIUM 0x3 -#define PRODUCT_ENTERPRISE 0x4 -#define PRODUCT_HOME_BASIC_N 0x5 -#define PRODUCT_BUSINESS 0x6 -#define PRODUCT_STANDARD_SERVER 0x7 -#define PRODUCT_DATACENTER_SERVER 0x8 -#define PRODUCT_SMALLBUSINESS_SERVER 0x9 -#define PRODUCT_ENTERPRISE_SERVER 0xa -#define PRODUCT_STARTER 0xb -#define PRODUCT_DATACENTER_SERVER_CORE 0xc -#define PRODUCT_STANDARD_SERVER_CORE 0xd -#define PRODUCT_ENTERPRISE_SERVER_CORE 0xe -#define PRODUCT_ENTERPRISE_SERVER_IA64 0xf -#define PRODUCT_BUSINESS_N 0x10 -#define PRODUCT_WEB_SERVER 0x11 -#define PRODUCT_CLUSTER_SERVER 0x12 -#define PRODUCT_HOME_SERVER 0x13 -#define PRODUCT_STORAGE_EXPRESS_SERVER 0x14 -#define PRODUCT_STORAGE_STANDARD_SERVER 0x15 -#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x16 -#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x17 -#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x18 -#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19 - -#define PRODUCT_UNLICENSED 0xabcdabcd - -#define LANG_NEUTRAL 0x00 -#define LANG_INVARIANT 0x7f - -#define LANG_AFRIKAANS 0x36 -#define LANG_ALBANIAN 0x1c -#define LANG_ALSATIAN 0x84 -#define LANG_AMHARIC 0x5e -#define LANG_ARABIC 0x01 -#define LANG_ARMENIAN 0x2b -#define LANG_ASSAMESE 0x4d -#define LANG_AZERI 0x2c -#define LANG_BASHKIR 0x6d -#define LANG_BASQUE 0x2d -#define LANG_BELARUSIAN 0x23 -#define LANG_BENGALI 0x45 -#define LANG_BRETON 0x7e -#define LANG_BOSNIAN 0x1a -#define LANG_BOSNIAN_NEUTRAL 0x781a -#define LANG_BULGARIAN 0x02 -#define LANG_CATALAN 0x03 -#define LANG_CHINESE 0x04 -#define LANG_CHINESE_SIMPLIFIED 0x04 -#define LANG_CHINESE_TRADITIONAL 0x7c04 -#define LANG_CORSICAN 0x83 -#define LANG_CROATIAN 0x1a -#define LANG_CZECH 0x05 -#define LANG_DANISH 0x06 -#define LANG_DARI 0x8c -#define LANG_DIVEHI 0x65 -#define LANG_DUTCH 0x13 -#define LANG_ENGLISH 0x09 -#define LANG_ESTONIAN 0x25 -#define LANG_FAEROESE 0x38 -#define LANG_FARSI 0x29 -#define LANG_FILIPINO 0x64 -#define LANG_FINNISH 0x0b -#define LANG_FRENCH 0x0c -#define LANG_FRISIAN 0x62 -#define LANG_GALICIAN 0x56 -#define LANG_GEORGIAN 0x37 -#define LANG_GERMAN 0x07 -#define LANG_GREEK 0x08 -#define LANG_GREENLANDIC 0x6f -#define LANG_GUJARATI 0x47 -#define LANG_HAUSA 0x68 -#define LANG_HEBREW 0x0d -#define LANG_HINDI 0x39 -#define LANG_HUNGARIAN 0x0e -#define LANG_ICELANDIC 0x0f -#define LANG_IGBO 0x70 -#define LANG_INDONESIAN 0x21 -#define LANG_INUKTITUT 0x5d -#define LANG_IRISH 0x3c -#define LANG_ITALIAN 0x10 -#define LANG_JAPANESE 0x11 -#define LANG_KANNADA 0x4b -#define LANG_KASHMIRI 0x60 -#define LANG_KAZAK 0x3f -#define LANG_KHMER 0x53 -#define LANG_KICHE 0x86 -#define LANG_KINYARWANDA 0x87 -#define LANG_KONKANI 0x57 -#define LANG_KOREAN 0x12 -#define LANG_KYRGYZ 0x40 -#define LANG_LAO 0x54 -#define LANG_LATVIAN 0x26 -#define LANG_LITHUANIAN 0x27 -#define LANG_LOWER_SORBIAN 0x2e -#define LANG_LUXEMBOURGISH 0x6e -#define LANG_MACEDONIAN 0x2f -#define LANG_MALAY 0x3e -#define LANG_MALAYALAM 0x4c -#define LANG_MALTESE 0x3a -#define LANG_MANIPURI 0x58 -#define LANG_MAORI 0x81 -#define LANG_MAPUDUNGUN 0x7a -#define LANG_MARATHI 0x4e -#define LANG_MOHAWK 0x7c -#define LANG_MONGOLIAN 0x50 -#define LANG_NEPALI 0x61 -#define LANG_NORWEGIAN 0x14 -#define LANG_OCCITAN 0x82 -#define LANG_ORIYA 0x48 -#define LANG_PASHTO 0x63 -#define LANG_PERSIAN 0x29 -#define LANG_POLISH 0x15 -#define LANG_PORTUGUESE 0x16 -#define LANG_PUNJABI 0x46 -#define LANG_QUECHUA 0x6b -#define LANG_ROMANIAN 0x18 -#define LANG_RUSSIAN 0x19 -#define LANG_SAMI 0x3b -#define LANG_ROMANSH 0x17 -#define LANG_SANSKRIT 0x4f -#define LANG_SERBIAN 0x1a -#define LANG_SERBIAN_NEUTRAL 0x7c1a -#define LANG_SINDHI 0x59 -#define LANG_SINHALESE 0x5b -#define LANG_SLOVAK 0x1b -#define LANG_SLOVENIAN 0x24 -#define LANG_SOTHO 0x6c -#define LANG_SPANISH 0x0a -#define LANG_SWAHILI 0x41 -#define LANG_SWEDISH 0x1d -#define LANG_SYRIAC 0x5a -#define LANG_TAJIK 0x28 -#define LANG_TAMAZIGHT 0x5f -#define LANG_TAMIL 0x49 -#define LANG_TATAR 0x44 -#define LANG_TELUGU 0x4a -#define LANG_THAI 0x1e -#define LANG_TIBETAN 0x51 -#define LANG_TIGRIGNA 0x73 -#define LANG_TSWANA 0x32 -#define LANG_TURKISH 0x1f -#define LANG_TURKMEN 0x42 -#define LANG_UIGHUR 0x80 -#define LANG_UKRAINIAN 0x22 -#define LANG_UPPER_SORBIAN 0x2e -#define LANG_URDU 0x20 -#define LANG_UZBEK 0x43 -#define LANG_VIETNAMESE 0x2a -#define LANG_WELSH 0x52 -#define LANG_WOLOF 0x88 -#define LANG_XHOSA 0x34 -#define LANG_YAKUT 0x85 -#define LANG_YI 0x78 -#define LANG_YORUBA 0x6a -#define LANG_ZULU 0x35 - -#define SUBLANG_NEUTRAL 0x0 -#define SUBLANG_DEFAULT 0x1 -#define SUBLANG_SYS_DEFAULT 0x2 -#define SUBLANG_CUSTOM_DEFAULT 0x3 -#define SUBLANG_CUSTOM_UNSPECIFIED 0x4 -#define SUBLANG_UI_CUSTOM_DEFAULT 0x5 - -#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 -#define SUBLANG_ARABIC_IRAQ 0x02 -#define SUBLANG_ARABIC_EGYPT 0x03 -#define SUBLANG_ARABIC_LIBYA 0x04 -#define SUBLANG_ARABIC_ALGERIA 0x05 -#define SUBLANG_ARABIC_MOROCCO 0x06 -#define SUBLANG_ARABIC_TUNISIA 0x07 -#define SUBLANG_ARABIC_OMAN 0x08 -#define SUBLANG_ARABIC_YEMEN 0x09 -#define SUBLANG_ARABIC_SYRIA 0x0a -#define SUBLANG_ARABIC_JORDAN 0x0b -#define SUBLANG_ARABIC_LEBANON 0x0c -#define SUBLANG_ARABIC_KUWAIT 0x0d -#define SUBLANG_ARABIC_UAE 0x0e -#define SUBLANG_ARABIC_BAHRAIN 0x0f -#define SUBLANG_ARABIC_QATAR 0x10 -#define SUBLANG_AZERI_LATIN 0x01 -#define SUBLANG_AZERI_CYRILLIC 0x02 -#define SUBLANG_CHINESE_TRADITIONAL 0x01 -#define SUBLANG_CHINESE_SIMPLIFIED 0x02 -#define SUBLANG_CHINESE_HONGKONG 0x03 -#define SUBLANG_CHINESE_SINGAPORE 0x04 -#define SUBLANG_CHINESE_MACAU 0x05 -#define SUBLANG_DUTCH 0x01 -#define SUBLANG_DUTCH_BELGIAN 0x02 -#define SUBLANG_ENGLISH_US 0x01 -#define SUBLANG_ENGLISH_UK 0x02 -#define SUBLANG_ENGLISH_AUS 0x03 -#define SUBLANG_ENGLISH_CAN 0x04 -#define SUBLANG_ENGLISH_NZ 0x05 -#define SUBLANG_ENGLISH_EIRE 0x06 -#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 -#define SUBLANG_ENGLISH_JAMAICA 0x08 -#define SUBLANG_ENGLISH_CARIBBEAN 0x09 -#define SUBLANG_ENGLISH_BELIZE 0x0a -#define SUBLANG_ENGLISH_TRINIDAD 0x0b -#define SUBLANG_ENGLISH_ZIMBABWE 0x0c -#define SUBLANG_ENGLISH_PHILIPPINES 0x0d -#define SUBLANG_FRENCH 0x01 -#define SUBLANG_FRENCH_BELGIAN 0x02 -#define SUBLANG_FRENCH_CANADIAN 0x03 -#define SUBLANG_FRENCH_SWISS 0x04 -#define SUBLANG_FRENCH_LUXEMBOURG 0x05 -#define SUBLANG_FRENCH_MONACO 0x06 -#define SUBLANG_GERMAN 0x01 -#define SUBLANG_GERMAN_SWISS 0x02 -#define SUBLANG_GERMAN_AUSTRIAN 0x03 -#define SUBLANG_GERMAN_LUXEMBOURG 0x04 -#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 -#define SUBLANG_ITALIAN 0x01 -#define SUBLANG_ITALIAN_SWISS 0x02 -#define SUBLANG_KASHMIRI_SASIA 0x02 -#define SUBLANG_KASHMIRI_INDIA 0x02 -#define SUBLANG_KOREAN 0x01 -#define SUBLANG_LITHUANIAN 0x01 -#define SUBLANG_MALAY_MALAYSIA 0x01 -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 -#define SUBLANG_NEPALI_INDIA 0x02 -#define SUBLANG_NORWEGIAN_BOKMAL 0x01 -#define SUBLANG_NORWEGIAN_NYNORSK 0x02 -#define SUBLANG_PORTUGUESE 0x02 -#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 -#define SUBLANG_SERBIAN_LATIN 0x02 -#define SUBLANG_SERBIAN_CYRILLIC 0x03 -#define SUBLANG_SPANISH 0x01 -#define SUBLANG_SPANISH_MEXICAN 0x02 -#define SUBLANG_SPANISH_MODERN 0x03 -#define SUBLANG_SPANISH_GUATEMALA 0x04 -#define SUBLANG_SPANISH_COSTA_RICA 0x05 -#define SUBLANG_SPANISH_PANAMA 0x06 -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 -#define SUBLANG_SPANISH_VENEZUELA 0x08 -#define SUBLANG_SPANISH_COLOMBIA 0x09 -#define SUBLANG_SPANISH_PERU 0x0a -#define SUBLANG_SPANISH_ARGENTINA 0x0b -#define SUBLANG_SPANISH_ECUADOR 0x0c -#define SUBLANG_SPANISH_CHILE 0x0d -#define SUBLANG_SPANISH_URUGUAY 0x0e -#define SUBLANG_SPANISH_PARAGUAY 0x0f -#define SUBLANG_SPANISH_BOLIVIA 0x10 -#define SUBLANG_SPANISH_EL_SALVADOR 0x11 -#define SUBLANG_SPANISH_HONDURAS 0x12 -#define SUBLANG_SPANISH_NICARAGUA 0x13 -#define SUBLANG_SPANISH_PUERTO_RICO 0x14 -#define SUBLANG_SWEDISH 0x01 -#define SUBLANG_SWEDISH_FINLAND 0x02 -#define SUBLANG_URDU_PAKISTAN 0x01 -#define SUBLANG_URDU_INDIA 0x02 -#define SUBLANG_UZBEK_LATIN 0x01 -#define SUBLANG_UZBEK_CYRILLIC 0x02 - -#define SORT_DEFAULT 0x0 -#define SORT_INVARIANT_MATH 0x1 - -#define SORT_JAPANESE_XJIS 0x0 -#define SORT_JAPANESE_UNICODE 0x1 -#define SORT_JAPANESE_RADICALSTROKE 0x4 - -#define SORT_CHINESE_BIG5 0x0 -#define SORT_CHINESE_PRCP 0x0 -#define SORT_CHINESE_UNICODE 0x1 -#define SORT_CHINESE_PRC 0x2 -#define SORT_CHINESE_BOPOMOFO 0x3 - -#define SORT_KOREAN_KSC 0x0 -#define SORT_KOREAN_UNICODE 0x1 - -#define SORT_GERMAN_PHONE_BOOK 0x1 - -#define SORT_HUNGARIAN_DEFAULT 0x0 -#define SORT_HUNGARIAN_TECHNICAL 0x1 - -#define SORT_GEORGIAN_TRADITIONAL 0x0 -#define SORT_GEORGIAN_MODERN 0x1 - -#define MAKELANGID(p,s) ((((WORD)(s)) << 10) | (WORD)(p)) -#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) -#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) - -#define NLS_VALID_LOCALE_MASK 0x000fffff - -#define MAKELCID(lgid,srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) -#define MAKESORTLCID(lgid,srtid,ver) ((DWORD)((MAKELCID(lgid,srtid)) | (((DWORD)((WORD)(ver))) << 20))) -#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) -#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf)) -#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf)) - -#define LOCALE_NAME_MAX_LENGTH 85 -#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)) -#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)) - -#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT,SORT_DEFAULT)) -#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT,SORT_DEFAULT)) - -#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)) - -#define LOCALE_CUSTOM_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT)) -#define LOCALE_CUSTOM_UNSPECIFIED (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT)) -#define LOCALE_CUSTOM_UI_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT)) - -#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL),SORT_DEFAULT)) - -#define UNREFERENCED_PARAMETER(P) (P) -#define DBG_UNREFERENCED_PARAMETER(P) (P) -#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V) - -#define DEFAULT_UNREACHABLE - -#ifndef WIN32_NO_STATUS -#define STATUS_WAIT_0 ((DWORD)0x00000000L) -#define STATUS_ABANDONED_WAIT_0 ((DWORD)0x00000080L) -#define STATUS_USER_APC ((DWORD)0x000000C0L) -#define STATUS_TIMEOUT ((DWORD)0x00000102L) -#define STATUS_PENDING ((DWORD)0x00000103L) -#define DBG_EXCEPTION_HANDLED ((DWORD)0x00010001L) -#define DBG_CONTINUE ((DWORD)0x00010002L) -#define STATUS_SEGMENT_NOTIFICATION ((DWORD)0x40000005L) -#define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) -#define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) -#define DBG_CONTROL_C ((DWORD)0x40010005L) -#define DBG_CONTROL_BREAK ((DWORD)0x40010008L) -#define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) -#define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) -#define STATUS_DATATYPE_MISALIGNMENT ((DWORD)0x80000002L) -#define STATUS_BREAKPOINT ((DWORD)0x80000003L) -#define STATUS_SINGLE_STEP ((DWORD)0x80000004L) -#define DBG_EXCEPTION_NOT_HANDLED ((DWORD)0x80010001L) -#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L) -#define STATUS_IN_PAGE_ERROR ((DWORD)0xC0000006L) -#define STATUS_INVALID_HANDLE ((DWORD)0xC0000008L) -#define STATUS_NO_MEMORY ((DWORD)0xC0000017L) -#define STATUS_ILLEGAL_INSTRUCTION ((DWORD)0xC000001DL) -#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD)0xC0000025L) -#define STATUS_INVALID_DISPOSITION ((DWORD)0xC0000026L) -#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD)0xC000008CL) -#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD)0xC000008DL) -#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD)0xC000008EL) -#define STATUS_FLOAT_INEXACT_RESULT ((DWORD)0xC000008FL) -#define STATUS_FLOAT_INVALID_OPERATION ((DWORD)0xC0000090L) -#define STATUS_FLOAT_OVERFLOW ((DWORD)0xC0000091L) -#define STATUS_FLOAT_STACK_CHECK ((DWORD)0xC0000092L) -#define STATUS_FLOAT_UNDERFLOW ((DWORD)0xC0000093L) -#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD)0xC0000094L) -#define STATUS_INTEGER_OVERFLOW ((DWORD)0xC0000095L) -#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD)0xC0000096L) -#define STATUS_STACK_OVERFLOW ((DWORD)0xC00000FDL) -#define STATUS_CONTROL_C_EXIT ((DWORD)0xC000013AL) -#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD)0xC00002B4L) -#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD)0xC00002B5L) -#define STATUS_REG_NAT_CONSUMPTION ((DWORD)0xC00002C9L) -#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD)0xC015000FL) -#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD)0xC0150010L) -#endif - -#define MAXIMUM_WAIT_OBJECTS 64 -#define MAXIMUM_SUSPEND_COUNT MAXCHAR - - typedef ULONG_PTR KSPIN_LOCK; - typedef KSPIN_LOCK *PKSPIN_LOCK; - -#ifdef _AMD64_ - -#if defined(__x86_64) && !defined(RC_INVOKED) - -#ifdef __cplusplus - extern "C" { -#endif - -#define BitTest _bittest -#define BitTestAndComplement _bittestandcomplement -#define BitTestAndSet _bittestandset -#define BitTestAndReset _bittestandreset -#define InterlockedBitTestAndSet _interlockedbittestandset -#define InterlockedBitTestAndReset _interlockedbittestandreset -#define BitTest64 _bittest64 -#define BitTestAndComplement64 _bittestandcomplement64 -#define BitTestAndSet64 _bittestandset64 -#define BitTestAndReset64 _bittestandreset64 -#define InterlockedBitTestAndSet64 _interlockedbittestandset64 -#define InterlockedBitTestAndReset64 _interlockedbittestandreset64 - - __CRT_INLINE BOOLEAN _bittest(LONG const *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandcomplement(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandreset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandreset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittest64(LONG64 const *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandcomplement64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btcq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btsq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandreset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btrq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("lock ; btsq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandreset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("lock ; btrq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } -#define BitScanForward _BitScanForward -#define BitScanReverse _BitScanReverse -#define BitScanForward64 _BitScanForward64 -#define BitScanReverse64 _BitScanReverse64 - - __CRT_INLINE BOOLEAN _BitScanForward(DWORD *Index,DWORD Mask) { - __asm__ __volatile__("bsfl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanReverse(DWORD *Index,DWORD Mask) { - __asm__ __volatile__("bsrl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { - __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanReverse64(DWORD *Index,DWORD64 Mask) { - __asm__ __volatile__("bsrq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); - return Mask!=0; - } - -#define InterlockedIncrement16 _InterlockedIncrement16 -#define InterlockedDecrement16 _InterlockedDecrement16 -#define InterlockedCompareExchange16 _InterlockedCompareExchange16 - -#define InterlockedAnd _InterlockedAnd -#define InterlockedOr _InterlockedOr -#define InterlockedXor _InterlockedXor -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedAdd _InterlockedAdd -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange - -#define InterlockedAnd64 _InterlockedAnd64 -#define InterlockedAndAffinity InterlockedAnd64 -#define InterlockedOr64 _InterlockedOr64 -#define InterlockedOrAffinity InterlockedOr64 -#define InterlockedXor64 _InterlockedXor64 -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedAdd64 _InterlockedAdd64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAcquire64 InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 - -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer - -#define InterlockedExchangeAddSizeT(a,b) InterlockedExchangeAdd64((LONG64 *)a,b) -#define InterlockedIncrementSizeT(a) InterlockedIncrement64((LONG64 *)a) -#define InterlockedDecrementSizeT(a) InterlockedDecrement64((LONG64 *)a) - - __CRT_INLINE SHORT InterlockedIncrement16(SHORT volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addw $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE SHORT InterlockedDecrement16(SHORT volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subw $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE SHORT InterlockedCompareExchange16(SHORT volatile *Destination,SHORT ExChange,SHORT Comperand) { - SHORT prev; - __asm__ __volatile__("lock ; cmpxchgw %w1,%2" - :"=a"(prev) - :"q"(ExChange), "m"(*Destination), "0"(Comperand) - : "memory"); - return prev; - } - __CRT_INLINE LONG InterlockedAnd(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; andl %0,%1" - : :"r"(Value),"m"(*Destination) - : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedOr(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; orl %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedXor(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; xorl %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - // $$$$ - __CRT_INLINE LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; andq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; orq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; xorq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedIncrement(LONG volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addl $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG InterlockedDecrement(LONG volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subl $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) { - __asm__ __volatile("lock ; xchgl %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - -#ifndef _X86AMD64_ - __CRT_INLINE LONG InterlockedAdd(LONG volatile *Addend,LONG Value) { return InterlockedExchangeAdd(Addend,Value) + Value; } -#endif - __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) { - LONG prev; - __asm__ __volatile__("lock ; cmpxchgl %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE LONG64 InterlockedIncrement64(LONG64 volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addq $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG64 InterlockedDecrement64(LONG64 volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subq $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value) { - __asm__ __volatile("lock ; xchgq %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); - -#ifndef _X86AMD64_ - __CRT_INLINE LONG64 InterlockedAdd64(LONG64 volatile *Addend,LONG64 Value) { return InterlockedExchangeAdd64(Addend,Value) + Value; } -#endif - - __CRT_INLINE LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand) { - LONG64 prev; - __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { - PVOID prev; - __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) { - __asm__ __volatile("lock ; xchgq %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - -#define CacheLineFlush(Address) _mm_clflush(Address) - - VOID _ReadWriteBarrier(VOID); - -#define FastFence __faststorefence -#define LoadFence _mm_lfence -#define MemoryFence _mm_mfence -#define StoreFence _mm_sfence - - VOID __faststorefence(VOID); - VOID _m_prefetchw(volatile CONST VOID *Source); - -//!__TINYC__: #include - -#define YieldProcessor _mm_pause -#define MemoryBarrier __faststorefence -#define PreFetchCacheLine(l,a) _mm_prefetch((CHAR CONST *) a,l) -#define PrefetchForWrite(p) _m_prefetchw(p) -#define ReadForWriteAccess(p) (_m_prefetchw(p),*(p)) - -#define PF_TEMPORAL_LEVEL_1 _MM_HINT_T0 -#define PF_TEMPORAL_LEVEL_2 _MM_HINT_T1 -#define PF_TEMPORAL_LEVEL_3 _MM_HINT_T2 -#define PF_NON_TEMPORAL_LEVEL_ALL _MM_HINT_NTA - -#define ReadMxCsr _mm_getcsr -#define WriteMxCsr _mm_setcsr - - VOID __int2c(VOID); - -#define DbgRaiseAssertionFailure() __int2c() -#define GetCallersEflags() __getcallerseflags() - - unsigned __int32 __getcallerseflags(VOID); - -#define GetSegmentLimit __segmentlimit - - DWORD __segmentlimit(DWORD Selector); - -#define ReadTimeStampCounter() __rdtsc() - - DWORD64 __rdtsc(VOID); - VOID __movsb(PBYTE Destination,BYTE const *Source,SIZE_T Count); - VOID __movsw(PWORD Destination,WORD const *Source,SIZE_T Count); - VOID __movsd(PDWORD Destination,DWORD const *Source,SIZE_T Count); - VOID __movsq(PDWORD64 Destination,DWORD64 const *Source,SIZE_T Count); - VOID __stosb(PBYTE Destination,BYTE Value,SIZE_T Count); - VOID __stosw(PWORD Destination,WORD Value,SIZE_T Count); - VOID __stosd(PDWORD Destination,DWORD Value,SIZE_T Count); - VOID __stosq(PDWORD64 Destination,DWORD64 Value,SIZE_T Count); - -#define MultiplyHigh __mulh -#define UnsignedMultiplyHigh __umulh - - LONGLONG MultiplyHigh(LONGLONG Multiplier,LONGLONG Multiplicand); - ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); - -#define ShiftLeft128 __shiftleft128 -#define ShiftRight128 __shiftright128 - - DWORD64 ShiftLeft128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); - DWORD64 ShiftRight128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); - -#define Multiply128 _mul128 - - LONG64 Multiply128(LONG64 Multiplier,LONG64 Multiplicand,LONG64 *HighProduct); - -#define UnsignedMultiply128 _umul128 - - DWORD64 UnsignedMultiply128(DWORD64 Multiplier,DWORD64 Multiplicand,DWORD64 *HighProduct); - - __CRT_INLINE LONG64 MultiplyExtract128(LONG64 Multiplier,LONG64 Multiplicand,BYTE Shift) { - LONG64 extractedProduct; - LONG64 highProduct; - LONG64 lowProduct; - lowProduct = Multiply128(Multiplier,Multiplicand,&highProduct); - extractedProduct = (LONG64)ShiftRight128((LONG64)lowProduct,(LONG64)highProduct,Shift); - return extractedProduct; - } - - __CRT_INLINE DWORD64 UnsignedMultiplyExtract128(DWORD64 Multiplier,DWORD64 Multiplicand,BYTE Shift) { - DWORD64 extractedProduct; - DWORD64 highProduct; - DWORD64 lowProduct; - lowProduct = UnsignedMultiply128(Multiplier,Multiplicand,&highProduct); - extractedProduct = ShiftRight128(lowProduct,highProduct,Shift); - return extractedProduct; - } - - __CRT_INLINE BYTE __readgsbyte(DWORD Offset) { - BYTE ret; - __asm__ volatile ("movb %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE WORD __readgsword(DWORD Offset) { - WORD ret; - __asm__ volatile ("movw %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE DWORD __readgsdword(DWORD Offset) { - DWORD ret; - __asm__ volatile ("movl %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE DWORD64 __readgsqword(DWORD Offset) { - void *ret; - __asm__ volatile ("movq %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return (DWORD64) ret; - } - __CRT_INLINE VOID __writegsbyte(DWORD Offset,BYTE Data) { - __asm__ volatile ("movb %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsword(DWORD Offset,WORD Data) { - __asm__ volatile ("movw %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsdword(DWORD Offset,DWORD Data) { - __asm__ volatile ("movl %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsqword(DWORD Offset,DWORD64 Data) { - __asm__ volatile ("movq %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - -#ifdef __cplusplus - } -#endif -#endif - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 8 - -#if !defined(RC_INVOKED) - -#define CONTEXT_AMD64 0x100000 - -#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L) -#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L) -#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L) -#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) -#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) - -#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 -#define CONTEXT_SERVICE_ACTIVE 0x10000000 -#define CONTEXT_EXCEPTION_REQUEST 0x40000000 -#define CONTEXT_EXCEPTION_REPORTING 0x80000000 -#endif - -#define INITIAL_MXCSR 0x1f80 -#define INITIAL_FPCSR 0x027f - - typedef DECLSPEC_ALIGN(16) struct _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A,*PM128A; - - typedef struct _XMM_SAVE_AREA32 { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - } XMM_SAVE_AREA32,*PXMM_SAVE_AREA32; - -#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) - - typedef DECLSPEC_ALIGN(16) struct _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - union { - XMM_SAVE_AREA32 FltSave; - XMM_SAVE_AREA32 FloatSave; - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - }; - }; - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT,*PCONTEXT; - -#define RUNTIME_FUNCTION_INDIRECT 0x1 - - typedef struct _RUNTIME_FUNCTION { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindData; - } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; - - typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); - typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); - -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" - - NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); - NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); - NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); - NTSYSAPI BOOLEAN __cdecl RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); -#endif - -#ifdef I_X86_ -#if(defined(_X86_) && !defined(__x86_64)) && !defined(RC_INVOKED) -#ifdef __cplusplus - extern "C" { -#endif - - __CRT_INLINE BOOLEAN InterlockedBitTestAndSet(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - - __CRT_INLINE BOOLEAN InterlockedBitTestAndReset(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - -#ifdef _PREFIX_ - BYTE __readfsbyte(DWORD Offset); - WORD __readfsword(DWORD Offset); - DWORD __readfsdword(DWORD Offset); - VOID __writefsbyte(DWORD Offset,BYTE Data); - VOID __writefsword(DWORD Offset,WORD Data); - VOID __writefsdword(DWORD Offset,DWORD Data); -#endif - -#ifdef __cplusplus - } -#endif -#endif - -#if(defined(_X86_) && !defined(__x86_64)) - __CRT_INLINE VOID MemoryBarrier(VOID) { - LONG Barrier; - __asm__ __volatile__("xchgl %eax,%0 " - :"=r" (Barrier)); - } -#define YieldProcessor() __asm__ __volatile__("rep nop "); - -#define PreFetchCacheLine(l,a) -#define ReadForWriteAccess(p) (*(p)) - -#define PF_TEMPORAL_LEVEL_1 -#define PF_NON_TEMPORAL_LEVEL_ALL - - __CRT_INLINE VOID DbgRaiseAssertionFailure(void) { - __asm__ __volatile__("int 0x2c "); - } - PVOID GetCurrentFiber(void); - __CRT_INLINE PVOID GetCurrentFiber(void) - { - void *ret; - __asm__ volatile ("movl %%fs:0x10,%0" - : "=r" (ret)); - return ret; - } - PVOID GetFiberData(void); - __CRT_INLINE PVOID GetFiberData(void) - { - void *ret; - __asm__ volatile ("movl %%fs:0x10,%0\n" - "movl (%0),%0" - : "=r" (ret)); - return ret; - } -#endif - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 8 - -#define SIZE_OF_80387_REGISTERS 80 - -#if !defined(RC_INVOKED) - -#define CONTEXT_i386 0x00010000 -#define CONTEXT_i486 0x00010000 - -#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) -#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) -#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) -#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) -#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) -#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L) - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) - -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) -#endif - -#define MAXIMUM_SUPPORTED_EXTENSION 512 - - typedef struct _FLOATING_SAVE_AREA { - DWORD ControlWord; - DWORD StatusWord; - DWORD TagWord; - DWORD ErrorOffset; - DWORD ErrorSelector; - DWORD DataOffset; - DWORD DataSelector; - BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; - DWORD Cr0NpxState; - } FLOATING_SAVE_AREA; - - typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; - - typedef struct _CONTEXT { - DWORD ContextFlags; - DWORD Dr0; - DWORD Dr1; - DWORD Dr2; - DWORD Dr3; - DWORD Dr6; - DWORD Dr7; - FLOATING_SAVE_AREA FloatSave; - DWORD SegGs; - DWORD SegFs; - DWORD SegEs; - DWORD SegDs; - - DWORD Edi; - DWORD Esi; - DWORD Ebx; - DWORD Edx; - DWORD Ecx; - DWORD Eax; - DWORD Ebp; - DWORD Eip; - DWORD SegCs; - DWORD EFlags; - DWORD Esp; - DWORD SegSs; - BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; - } CONTEXT; - - typedef CONTEXT *PCONTEXT; -#endif - -#ifndef _LDT_ENTRY_DEFINED -#define _LDT_ENTRY_DEFINED - - typedef struct _LDT_ENTRY { - WORD LimitLow; - WORD BaseLow; - union { - struct { - BYTE BaseMid; - BYTE Flags1; - BYTE Flags2; - BYTE BaseHi; - } Bytes; - struct { - DWORD BaseMid : 8; - DWORD Type : 5; - DWORD Dpl : 2; - DWORD Pres : 1; - DWORD LimitHi : 4; - DWORD Sys : 1; - DWORD Reserved_0 : 1; - DWORD Default_Big : 1; - DWORD Granularity : 1; - DWORD BaseHi : 8; - } Bits; - } HighWord; - } LDT_ENTRY,*PLDT_ENTRY; -#endif - -#if defined(__ia64__) && !defined(RC_INVOKED) - -#ifdef __cplusplus - extern "C" { -#endif - - BOOLEAN BitScanForward64(DWORD *Index,DWORD64 Mask); - BOOLEAN BitScanReverse64(DWORD *Index,DWORD64 Mask); - -#ifdef __cplusplus - } -#endif -#endif - -#if !defined(GENUTIL) && !defined(_GENIA64_) && defined(_IA64_) - - void *_cdecl _rdteb(void); -#ifdef __ia64__ - -#define NtCurrentTeb() ((struct _TEB *)_rdteb()) -#define GetCurrentFiber() (((PNT_TIB)NtCurrentTeb())->FiberData) -#define GetFiberData() (*(PVOID *)(GetCurrentFiber())) - -#ifdef __cplusplus - extern "C" { -#endif - - void __break(int); - void __yield(void); - void __mf(void); - void __lfetch(int Level,VOID CONST *Address); - void __lfetchfault(int Level,VOID CONST *Address); - void __lfetch_excl(int Level,VOID CONST *Address); - void __lfetchfault_excl(int Level,VOID CONST *Address); - -#define MD_LFHINT_NONE 0x00 -#define MD_LFHINT_NT1 0x01 -#define MD_LFHINT_NT2 0x02 -#define MD_LFHINT_NTA 0x03 - -#ifdef __cplusplus - } -#endif - -#define YieldProcessor __yield -#define MemoryBarrier __mf -#define PreFetchCacheLine __lfetch -#define ReadForWriteAccess(p) (*(p)) -#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) - -#define PF_TEMPORAL_LEVEL_1 MD_LFHINT_NONE -#define PF_NON_TEMPORAL_LEVEL_ALL MD_LFHINT_NTA - -#define UnsignedMultiplyHigh __UMULH - - ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); -#else - struct _TEB *NtCurrentTeb(void); -#endif -#endif - -#ifdef _IA64_ - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 2 - -#if !defined(RC_INVOKED) - -#define CONTEXT_IA64 0x00080000 - -#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L) -#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L) -#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L) -#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L) -#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L) -#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) - -#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT) -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL) -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL) - -#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 -#define CONTEXT_SERVICE_ACTIVE 0x10000000 -#define CONTEXT_EXCEPTION_REQUEST 0x40000000 -#define CONTEXT_EXCEPTION_REPORTING 0x80000000 -#endif - - typedef struct _CONTEXT { - DWORD ContextFlags; - DWORD Fill1[3]; - ULONGLONG DbI0; - ULONGLONG DbI1; - ULONGLONG DbI2; - ULONGLONG DbI3; - ULONGLONG DbI4; - ULONGLONG DbI5; - ULONGLONG DbI6; - ULONGLONG DbI7; - ULONGLONG DbD0; - ULONGLONG DbD1; - ULONGLONG DbD2; - ULONGLONG DbD3; - ULONGLONG DbD4; - ULONGLONG DbD5; - ULONGLONG DbD6; - ULONGLONG DbD7; - FLOAT128 FltS0; - FLOAT128 FltS1; - FLOAT128 FltS2; - FLOAT128 FltS3; - FLOAT128 FltT0; - FLOAT128 FltT1; - FLOAT128 FltT2; - FLOAT128 FltT3; - FLOAT128 FltT4; - FLOAT128 FltT5; - FLOAT128 FltT6; - FLOAT128 FltT7; - FLOAT128 FltT8; - FLOAT128 FltT9; - FLOAT128 FltS4; - FLOAT128 FltS5; - FLOAT128 FltS6; - FLOAT128 FltS7; - FLOAT128 FltS8; - FLOAT128 FltS9; - FLOAT128 FltS10; - FLOAT128 FltS11; - FLOAT128 FltS12; - FLOAT128 FltS13; - FLOAT128 FltS14; - FLOAT128 FltS15; - FLOAT128 FltS16; - FLOAT128 FltS17; - FLOAT128 FltS18; - FLOAT128 FltS19; - FLOAT128 FltF32; - FLOAT128 FltF33; - FLOAT128 FltF34; - FLOAT128 FltF35; - FLOAT128 FltF36; - FLOAT128 FltF37; - FLOAT128 FltF38; - FLOAT128 FltF39; - FLOAT128 FltF40; - FLOAT128 FltF41; - FLOAT128 FltF42; - FLOAT128 FltF43; - FLOAT128 FltF44; - FLOAT128 FltF45; - FLOAT128 FltF46; - FLOAT128 FltF47; - FLOAT128 FltF48; - FLOAT128 FltF49; - FLOAT128 FltF50; - FLOAT128 FltF51; - FLOAT128 FltF52; - FLOAT128 FltF53; - FLOAT128 FltF54; - FLOAT128 FltF55; - FLOAT128 FltF56; - FLOAT128 FltF57; - FLOAT128 FltF58; - FLOAT128 FltF59; - FLOAT128 FltF60; - FLOAT128 FltF61; - FLOAT128 FltF62; - FLOAT128 FltF63; - FLOAT128 FltF64; - FLOAT128 FltF65; - FLOAT128 FltF66; - FLOAT128 FltF67; - FLOAT128 FltF68; - FLOAT128 FltF69; - FLOAT128 FltF70; - FLOAT128 FltF71; - FLOAT128 FltF72; - FLOAT128 FltF73; - FLOAT128 FltF74; - FLOAT128 FltF75; - FLOAT128 FltF76; - FLOAT128 FltF77; - FLOAT128 FltF78; - FLOAT128 FltF79; - FLOAT128 FltF80; - FLOAT128 FltF81; - FLOAT128 FltF82; - FLOAT128 FltF83; - FLOAT128 FltF84; - FLOAT128 FltF85; - FLOAT128 FltF86; - FLOAT128 FltF87; - FLOAT128 FltF88; - FLOAT128 FltF89; - FLOAT128 FltF90; - FLOAT128 FltF91; - FLOAT128 FltF92; - FLOAT128 FltF93; - FLOAT128 FltF94; - FLOAT128 FltF95; - FLOAT128 FltF96; - FLOAT128 FltF97; - FLOAT128 FltF98; - FLOAT128 FltF99; - FLOAT128 FltF100; - FLOAT128 FltF101; - FLOAT128 FltF102; - FLOAT128 FltF103; - FLOAT128 FltF104; - FLOAT128 FltF105; - FLOAT128 FltF106; - FLOAT128 FltF107; - FLOAT128 FltF108; - FLOAT128 FltF109; - FLOAT128 FltF110; - FLOAT128 FltF111; - FLOAT128 FltF112; - FLOAT128 FltF113; - FLOAT128 FltF114; - FLOAT128 FltF115; - FLOAT128 FltF116; - FLOAT128 FltF117; - FLOAT128 FltF118; - FLOAT128 FltF119; - FLOAT128 FltF120; - FLOAT128 FltF121; - FLOAT128 FltF122; - FLOAT128 FltF123; - FLOAT128 FltF124; - FLOAT128 FltF125; - FLOAT128 FltF126; - FLOAT128 FltF127; - ULONGLONG StFPSR; - ULONGLONG IntGp; - ULONGLONG IntT0; - ULONGLONG IntT1; - ULONGLONG IntS0; - ULONGLONG IntS1; - ULONGLONG IntS2; - ULONGLONG IntS3; - ULONGLONG IntV0; - ULONGLONG IntT2; - ULONGLONG IntT3; - ULONGLONG IntT4; - ULONGLONG IntSp; - ULONGLONG IntTeb; - ULONGLONG IntT5; - ULONGLONG IntT6; - ULONGLONG IntT7; - ULONGLONG IntT8; - ULONGLONG IntT9; - ULONGLONG IntT10; - ULONGLONG IntT11; - ULONGLONG IntT12; - ULONGLONG IntT13; - ULONGLONG IntT14; - ULONGLONG IntT15; - ULONGLONG IntT16; - ULONGLONG IntT17; - ULONGLONG IntT18; - ULONGLONG IntT19; - ULONGLONG IntT20; - ULONGLONG IntT21; - ULONGLONG IntT22; - ULONGLONG IntNats; - ULONGLONG Preds; - ULONGLONG BrRp; - ULONGLONG BrS0; - ULONGLONG BrS1; - ULONGLONG BrS2; - ULONGLONG BrS3; - ULONGLONG BrS4; - ULONGLONG BrT0; - ULONGLONG BrT1; - ULONGLONG ApUNAT; - ULONGLONG ApLC; - ULONGLONG ApEC; - ULONGLONG ApCCV; - ULONGLONG ApDCR; - ULONGLONG RsPFS; - ULONGLONG RsBSP; - ULONGLONG RsBSPSTORE; - ULONGLONG RsRSC; - ULONGLONG RsRNAT; - ULONGLONG StIPSR; - ULONGLONG StIIP; - ULONGLONG StIFS; - ULONGLONG StFCR; - ULONGLONG Eflag; - ULONGLONG SegCSD; - ULONGLONG SegSSD; - ULONGLONG Cflag; - ULONGLONG StFSR; - ULONGLONG StFIR; - ULONGLONG StFDR; - ULONGLONG UNUSEDPACK; - } CONTEXT,*PCONTEXT; - - typedef struct _PLABEL_DESCRIPTOR { - ULONGLONG EntryPoint; - ULONGLONG GlobalPointer; - } PLABEL_DESCRIPTOR,*PPLABEL_DESCRIPTOR; - - typedef struct _RUNTIME_FUNCTION { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindInfoAddress; - } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; - - typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); - typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); - -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" - - BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,ULONGLONG BaseAddress,ULONGLONG TargetGp); - BOOLEAN RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,DWORD64 TargetGp,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); - BOOLEAN RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); - VOID RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); - VOID __jump_unwind(ULONGLONG TargetMsFrame,ULONGLONG TargetBsFrame,ULONGLONG TargetPc); -#endif - -#define EXCEPTION_NONCONTINUABLE 0x1 -#define EXCEPTION_MAXIMUM_PARAMETERS 15 - - typedef struct _EXCEPTION_RECORD { - DWORD ExceptionCode; - DWORD ExceptionFlags; - struct _EXCEPTION_RECORD *ExceptionRecord; - PVOID ExceptionAddress; - DWORD NumberParameters; - ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD; - - typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; - - typedef struct _EXCEPTION_RECORD32 { - DWORD ExceptionCode; - DWORD ExceptionFlags; - DWORD ExceptionRecord; - DWORD ExceptionAddress; - DWORD NumberParameters; - DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD32,*PEXCEPTION_RECORD32; - - typedef struct _EXCEPTION_RECORD64 { - DWORD ExceptionCode; - DWORD ExceptionFlags; - DWORD64 ExceptionRecord; - DWORD64 ExceptionAddress; - DWORD NumberParameters; - DWORD __unusedAlignment; - DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD64,*PEXCEPTION_RECORD64; - - typedef struct _EXCEPTION_POINTERS { - PEXCEPTION_RECORD ExceptionRecord; - PCONTEXT ContextRecord; - } EXCEPTION_POINTERS,*PEXCEPTION_POINTERS; - -#ifdef __x86_64 - - typedef EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE (struct _EXCEPTION_RECORD *ExceptionRecord, PVOID EstablisherFrame, struct _CONTEXT *ContextRecord, PVOID DispatcherContext); -#ifndef __PEXCEPTION_ROUTINE_DEFINED -#define __PEXCEPTION_ROUTINE_DEFINED - typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; -#endif - - /* http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx */ - -#define UNWIND_HISTORY_TABLE_SIZE 12 - - typedef struct _UNWIND_HISTORY_TABLE_ENTRY { - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - } UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY; - -#define UNWIND_HISTORY_TABLE_NONE 0 -#define UNWIND_HISTORY_TABLE_GLOBAL 1 -#define UNWIND_HISTORY_TABLE_LOCAL 2 - - typedef struct _UNWIND_HISTORY_TABLE { - ULONG Count; - UCHAR Search; - ULONG64 LowAddress; - ULONG64 HighAddress; - UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; - } UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE; - - /* http://msdn.microsoft.com/en-us/library/b6sf5kbd(VS.80).aspx */ - - struct _DISPATCHER_CONTEXT; - typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; - typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; - - struct _DISPATCHER_CONTEXT { - ULONG64 ControlPc; - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - ULONG64 EstablisherFrame; - ULONG64 TargetIp; - PCONTEXT ContextRecord; - PEXCEPTION_ROUTINE LanguageHandler; - PVOID HandlerData; - /* http://www.nynaeve.net/?p=99 */ - PUNWIND_HISTORY_TABLE HistoryTable; - ULONG ScopeIndex; - ULONG Fill0; - }; - - /* http://msdn.microsoft.com/en-us/library/ms680617(VS.85).aspx */ - - typedef struct _KNONVOLATILE_CONTEXT_POINTERS - { - PM128A FloatingContext[16]; - PULONG64 IntegerContext[16]; - } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; -#endif /* defined(__x86_64) */ - - typedef PVOID PACCESS_TOKEN; - typedef PVOID PSECURITY_DESCRIPTOR; - typedef PVOID PSID; - - typedef DWORD ACCESS_MASK; - typedef ACCESS_MASK *PACCESS_MASK; - -#define DELETE (0x00010000L) -#define READ_CONTROL (0x00020000L) -#define WRITE_DAC (0x00040000L) -#define WRITE_OWNER (0x00080000L) -#define SYNCHRONIZE (0x00100000L) - -#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) -#define STANDARD_RIGHTS_READ (READ_CONTROL) -#define STANDARD_RIGHTS_WRITE (READ_CONTROL) -#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) -#define STANDARD_RIGHTS_ALL (0x001F0000L) - -#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) - -#define ACCESS_SYSTEM_SECURITY (0x01000000L) - -#define MAXIMUM_ALLOWED (0x02000000L) - -#define GENERIC_READ (0x80000000L) -#define GENERIC_WRITE (0x40000000L) -#define GENERIC_EXECUTE (0x20000000L) -#define GENERIC_ALL (0x10000000L) - - typedef struct _GENERIC_MAPPING { - ACCESS_MASK GenericRead; - ACCESS_MASK GenericWrite; - ACCESS_MASK GenericExecute; - ACCESS_MASK GenericAll; - } GENERIC_MAPPING; - typedef GENERIC_MAPPING *PGENERIC_MAPPING; - -#include - - typedef struct _LUID_AND_ATTRIBUTES { - LUID Luid; - DWORD Attributes; - } LUID_AND_ATTRIBUTES,*PLUID_AND_ATTRIBUTES; - typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; - typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY; - -#include - -#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED -#define SID_IDENTIFIER_AUTHORITY_DEFINED - typedef struct _SID_IDENTIFIER_AUTHORITY { - BYTE Value[6]; - } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; -#endif - -#ifndef SID_DEFINED -#define SID_DEFINED - typedef struct _SID { - BYTE Revision; - BYTE SubAuthorityCount; - SID_IDENTIFIER_AUTHORITY IdentifierAuthority; - DWORD SubAuthority[ANYSIZE_ARRAY]; - } SID,*PISID; -#endif - -#define SID_REVISION (1) -#define SID_MAX_SUB_AUTHORITIES (15) -#define SID_RECOMMENDED_SUB_AUTHORITIES (1) - -#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES *sizeof(DWORD))) - - typedef enum _SID_NAME_USE { - SidTypeUser = 1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown,SidTypeComputer - } SID_NAME_USE,*PSID_NAME_USE; - - typedef struct _SID_AND_ATTRIBUTES { - PSID Sid; - DWORD Attributes; - } SID_AND_ATTRIBUTES,*PSID_AND_ATTRIBUTES; - - typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; - typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY; - -#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} -#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} -#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} -#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} -#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} -#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} - -#define SECURITY_NULL_RID (0x00000000L) -#define SECURITY_WORLD_RID (0x00000000L) -#define SECURITY_LOCAL_RID (0x00000000L) - -#define SECURITY_CREATOR_OWNER_RID (0x00000000L) -#define SECURITY_CREATOR_GROUP_RID (0x00000001L) - -#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) -#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) - -#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} - -#define SECURITY_DIALUP_RID (0x00000001L) -#define SECURITY_NETWORK_RID (0x00000002L) -#define SECURITY_BATCH_RID (0x00000003L) -#define SECURITY_INTERACTIVE_RID (0x00000004L) -#define SECURITY_LOGON_IDS_RID (0x00000005L) -#define SECURITY_LOGON_IDS_RID_COUNT (3L) -#define SECURITY_SERVICE_RID (0x00000006L) -#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L) -#define SECURITY_PROXY_RID (0x00000008L) -#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L) -#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID -#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL) -#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL) -#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL) -#define SECURITY_TERMINAL_SERVER_RID (0x0000000DL) -#define SECURITY_REMOTE_LOGON_RID (0x0000000EL) -#define SECURITY_THIS_ORGANIZATION_RID (0x0000000FL) -#define SECURITY_IUSER_RID (0x00000011L) - -#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L) -#define SECURITY_LOCAL_SERVICE_RID (0x00000013L) -#define SECURITY_NETWORK_SERVICE_RID (0x00000014L) - -#define SECURITY_NT_NON_UNIQUE (0x00000015L) -#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L) - -#define SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID (0x00000016L) - -#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L) -#define SECURITY_WRITE_RESTRICTED_CODE_RID (0x00000021L) - -#define SECURITY_PACKAGE_BASE_RID (0x00000040L) -#define SECURITY_PACKAGE_RID_COUNT (2L) -#define SECURITY_PACKAGE_NTLM_RID (0x0000000AL) -#define SECURITY_PACKAGE_SCHANNEL_RID (0x0000000EL) -#define SECURITY_PACKAGE_DIGEST_RID (0x00000015L) - -#define SECURITY_SERVICE_ID_BASE_RID (0x00000050L) -#define SECURITY_SERVICE_ID_RID_COUNT (6L) - -#define SECURITY_RESERVED_ID_BASE_RID (0x00000051L) - -#define SECURITY_MAX_ALWAYS_FILTERED (0x000003E7L) -#define SECURITY_MIN_NEVER_FILTERED (0x000003E8L) - -#define SECURITY_OTHER_ORGANIZATION_RID (0x000003E8L) - -#define FOREST_USER_RID_MAX (0x000001F3L) - -#define DOMAIN_USER_RID_ADMIN (0x000001F4L) -#define DOMAIN_USER_RID_GUEST (0x000001F5L) -#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) - -#define DOMAIN_USER_RID_MAX (0x000003E7L) - -#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) -#define DOMAIN_GROUP_RID_USERS (0x00000201L) -#define DOMAIN_GROUP_RID_GUESTS (0x00000202L) -#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L) -#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L) -#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L) -#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L) -#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L) -#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L) -#define DOMAIN_GROUP_RID_READONLY_CONTROLLERS (0x00000209L) - -#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) -#define DOMAIN_ALIAS_RID_USERS (0x00000221L) -#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L) -#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L) - -#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L) -#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L) -#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L) -#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L) - -#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L) -#define DOMAIN_ALIAS_RID_RAS_SERVERS (0x00000229L) -#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS (0x0000022AL) -#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (0x0000022BL) -#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS (0x0000022CL) -#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS (0x0000022DL) - -#define DOMAIN_ALIAS_RID_MONITORING_USERS (0x0000022EL) -#define DOMAIN_ALIAS_RID_LOGGING_USERS (0x0000022FL) -#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS (0x00000230L) -#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS (0x00000231L) -#define DOMAIN_ALIAS_RID_DCOM_USERS (0x00000232L) - -#define DOMAIN_ALIAS_RID_IUSERS (0x00000238L) -#define DOMAIN_ALIAS_RID_CRYPTO_OPERATORS (0x00000239L) -#define DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP (0x0000023BL) -#define DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP (0x0000023CL) -#define DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP (0x0000023DL) - -#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} -#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) -#define SECURITY_MANDATORY_LOW_RID (0x00001000L) -#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) -#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) -#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) -#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) - -#define SECURITY_MANDATORY_MAXIMUM_USER_RID SECURITY_MANDATORY_SYSTEM_RID - -#define MANDATORY_LEVEL_TO_MANDATORY_RID(IL) (IL * 0x1000) - - typedef enum { - WinNullSid = 0,WinWorldSid = 1,WinLocalSid = 2,WinCreatorOwnerSid = 3,WinCreatorGroupSid = 4,WinCreatorOwnerServerSid = 5,WinCreatorGroupServerSid = 6,WinNtAuthoritySid = 7,WinDialupSid = 8,WinNetworkSid = 9,WinBatchSid = 10,WinInteractiveSid = 11,WinServiceSid = 12,WinAnonymousSid = 13,WinProxySid = 14,WinEnterpriseControllersSid = 15,WinSelfSid = 16,WinAuthenticatedUserSid = 17,WinRestrictedCodeSid = 18,WinTerminalServerSid = 19,WinRemoteLogonIdSid = 20,WinLogonIdsSid = 21,WinLocalSystemSid = 22,WinLocalServiceSid = 23,WinNetworkServiceSid = 24,WinBuiltinDomainSid = 25,WinBuiltinAdministratorsSid = 26,WinBuiltinUsersSid = 27,WinBuiltinGuestsSid = 28,WinBuiltinPowerUsersSid = 29,WinBuiltinAccountOperatorsSid = 30,WinBuiltinSystemOperatorsSid = 31,WinBuiltinPrintOperatorsSid = 32,WinBuiltinBackupOperatorsSid = 33,WinBuiltinReplicatorSid = 34,WinBuiltinPreWindows2000CompatibleAccessSid = 35,WinBuiltinRemoteDesktopUsersSid = 36,WinBuiltinNetworkConfigurationOperatorsSid = 37,WinAccountAdministratorSid = 38,WinAccountGuestSid = 39,WinAccountKrbtgtSid = 40,WinAccountDomainAdminsSid = 41,WinAccountDomainUsersSid = 42,WinAccountDomainGuestsSid = 43,WinAccountComputersSid = 44,WinAccountControllersSid = 45,WinAccountCertAdminsSid = 46,WinAccountSchemaAdminsSid = 47,WinAccountEnterpriseAdminsSid = 48,WinAccountPolicyAdminsSid = 49,WinAccountRasAndIasServersSid = 50,WinNTLMAuthenticationSid = 51,WinDigestAuthenticationSid = 52,WinSChannelAuthenticationSid = 53,WinThisOrganizationSid = 54,WinOtherOrganizationSid = 55,WinBuiltinIncomingForestTrustBuildersSid = 56,WinBuiltinPerfMonitoringUsersSid = 57,WinBuiltinPerfLoggingUsersSid = 58,WinBuiltinAuthorizationAccessSid = 59,WinBuiltinTerminalServerLicenseServersSid = 60,WinBuiltinDCOMUsersSid = 61 - } WELL_KNOWN_SID_TYPE; - -#define SYSTEM_LUID { 0x3E7,0x0 } -#define ANONYMOUS_LOGON_LUID { 0x3e6,0x0 } -#define LOCALSERVICE_LUID { 0x3e5,0x0 } -#define NETWORKSERVICE_LUID { 0x3e4,0x0 } -#define IUSER_LUID { 0x3e3, 0x0 } - -#define SE_GROUP_MANDATORY (0x00000001L) -#define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L) -#define SE_GROUP_ENABLED (0x00000004L) -#define SE_GROUP_OWNER (0x00000008L) -#define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L) -#define SE_GROUP_INTEGRITY (0x00000020L) -#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) -#define SE_GROUP_LOGON_ID (0xC0000000L) -#define SE_GROUP_RESOURCE (0x20000000L) - -#define ACL_REVISION (2) -#define ACL_REVISION_DS (4) - -#define ACL_REVISION1 (1) -#define MIN_ACL_REVISION ACL_REVISION2 -#define ACL_REVISION2 (2) -#define ACL_REVISION3 (3) -#define ACL_REVISION4 (4) -#define MAX_ACL_REVISION ACL_REVISION4 - - typedef struct _ACL { - BYTE AclRevision; - BYTE Sbz1; - WORD AclSize; - WORD AceCount; - WORD Sbz2; - } ACL; - typedef ACL *PACL; - - typedef struct _ACE_HEADER { - BYTE AceType; - BYTE AceFlags; - WORD AceSize; - } ACE_HEADER; - typedef ACE_HEADER *PACE_HEADER; - -#define ACCESS_MIN_MS_ACE_TYPE (0x0) -#define ACCESS_ALLOWED_ACE_TYPE (0x0) -#define ACCESS_DENIED_ACE_TYPE (0x1) -#define SYSTEM_AUDIT_ACE_TYPE (0x2) -#define SYSTEM_ALARM_ACE_TYPE (0x3) -#define ACCESS_MAX_MS_V2_ACE_TYPE (0x3) - -#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4) -#define ACCESS_MAX_MS_V3_ACE_TYPE (0x4) - -#define ACCESS_MIN_MS_OBJECT_ACE_TYPE (0x5) -#define ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5) -#define ACCESS_DENIED_OBJECT_ACE_TYPE (0x6) -#define SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7) -#define SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8) -#define ACCESS_MAX_MS_OBJECT_ACE_TYPE (0x8) - -#define ACCESS_MAX_MS_V4_ACE_TYPE (0x8) -#define ACCESS_MAX_MS_ACE_TYPE (0x8) - -#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE (0x9) -#define ACCESS_DENIED_CALLBACK_ACE_TYPE (0xA) -#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE (0xB) -#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE (0xC) -#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE (0xD) -#define SYSTEM_ALARM_CALLBACK_ACE_TYPE (0xE) -#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE (0xF) -#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE (0x10) - -#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) -#define ACCESS_MAX_MS_V5_ACE_TYPE (0x11) - -#define OBJECT_INHERIT_ACE (0x1) -#define CONTAINER_INHERIT_ACE (0x2) -#define NO_PROPAGATE_INHERIT_ACE (0x4) -#define INHERIT_ONLY_ACE (0x8) -#define INHERITED_ACE (0x10) -#define VALID_INHERIT_FLAGS (0x1F) - -#define SUCCESSFUL_ACCESS_ACE_FLAG (0x40) -#define FAILED_ACCESS_ACE_FLAG (0x80) - - typedef struct _ACCESS_ALLOWED_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } ACCESS_ALLOWED_ACE; - - typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE; - - typedef struct _ACCESS_DENIED_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } ACCESS_DENIED_ACE; - typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE; - - typedef struct _SYSTEM_AUDIT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } SYSTEM_AUDIT_ACE; - typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; - - typedef struct _SYSTEM_ALARM_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } SYSTEM_ALARM_ACE; - typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE; - - typedef struct _ACCESS_ALLOWED_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE; - - typedef struct _ACCESS_DENIED_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE; - - typedef struct _SYSTEM_AUDIT_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE; - - typedef struct _SYSTEM_ALARM_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE; - - typedef struct _ACCESS_ALLOWED_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } ACCESS_ALLOWED_CALLBACK_ACE,*PACCESS_ALLOWED_CALLBACK_ACE; - - typedef struct _ACCESS_DENIED_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } ACCESS_DENIED_CALLBACK_ACE,*PACCESS_DENIED_CALLBACK_ACE; - - typedef struct _SYSTEM_AUDIT_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } SYSTEM_AUDIT_CALLBACK_ACE,*PSYSTEM_AUDIT_CALLBACK_ACE; - - typedef struct _SYSTEM_ALARM_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } SYSTEM_ALARM_CALLBACK_ACE,*PSYSTEM_ALARM_CALLBACK_ACE; - - typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,*PACCESS_ALLOWED_CALLBACK_OBJECT_ACE; - - typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } ACCESS_DENIED_CALLBACK_OBJECT_ACE,*PACCESS_DENIED_CALLBACK_OBJECT_ACE; - - typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,*PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE; - - typedef struct _SYSTEM_ALARM_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } SYSTEM_ALARM_CALLBACK_OBJECT_ACE,*PSYSTEM_ALARM_CALLBACK_OBJECT_ACE; - -#define ACE_OBJECT_TYPE_PRESENT 0x1 -#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x2 - - typedef enum _ACL_INFORMATION_CLASS { - AclRevisionInformation = 1,AclSizeInformation - } ACL_INFORMATION_CLASS; - - typedef struct _ACL_REVISION_INFORMATION { - DWORD AclRevision; - } ACL_REVISION_INFORMATION; - typedef ACL_REVISION_INFORMATION *PACL_REVISION_INFORMATION; - - typedef struct _ACL_SIZE_INFORMATION { - DWORD AceCount; - DWORD AclBytesInUse; - DWORD AclBytesFree; - } ACL_SIZE_INFORMATION; - typedef ACL_SIZE_INFORMATION *PACL_SIZE_INFORMATION; - -#define SECURITY_DESCRIPTOR_REVISION (1) -#define SECURITY_DESCRIPTOR_REVISION1 (1) - -#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) - - typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL; - -#define SE_OWNER_DEFAULTED (0x0001) -#define SE_GROUP_DEFAULTED (0x0002) -#define SE_DACL_PRESENT (0x0004) -#define SE_DACL_DEFAULTED (0x0008) -#define SE_SACL_PRESENT (0x0010) -#define SE_SACL_DEFAULTED (0x0020) -#define SE_DACL_AUTO_INHERIT_REQ (0x0100) -#define SE_SACL_AUTO_INHERIT_REQ (0x0200) -#define SE_DACL_AUTO_INHERITED (0x0400) -#define SE_SACL_AUTO_INHERITED (0x0800) -#define SE_DACL_PROTECTED (0x1000) -#define SE_SACL_PROTECTED (0x2000) -#define SE_RM_CONTROL_VALID (0x4000) -#define SE_SELF_RELATIVE (0x8000) - - typedef struct _SECURITY_DESCRIPTOR_RELATIVE { - BYTE Revision; - BYTE Sbz1; - SECURITY_DESCRIPTOR_CONTROL Control; - DWORD Owner; - DWORD Group; - DWORD Sacl; - DWORD Dacl; - } SECURITY_DESCRIPTOR_RELATIVE,*PISECURITY_DESCRIPTOR_RELATIVE; - - typedef struct _SECURITY_DESCRIPTOR { - BYTE Revision; - BYTE Sbz1; - SECURITY_DESCRIPTOR_CONTROL Control; - PSID Owner; - PSID Group; - PACL Sacl; - PACL Dacl; - - } SECURITY_DESCRIPTOR,*PISECURITY_DESCRIPTOR; - - typedef struct _OBJECT_TYPE_LIST { - WORD Level; - WORD Sbz; - GUID *ObjectType; - } OBJECT_TYPE_LIST,*POBJECT_TYPE_LIST; - -#define ACCESS_OBJECT_GUID 0 -#define ACCESS_PROPERTY_SET_GUID 1 -#define ACCESS_PROPERTY_GUID 2 - -#define ACCESS_MAX_LEVEL 4 - - typedef enum _AUDIT_EVENT_TYPE { - AuditEventObjectAccess,AuditEventDirectoryServiceAccess - } AUDIT_EVENT_TYPE,*PAUDIT_EVENT_TYPE; - -#define AUDIT_ALLOW_NO_PRIVILEGE 0x1 - -#define ACCESS_DS_SOURCE_A "DS" -#define ACCESS_DS_SOURCE_W L"DS" -#define ACCESS_DS_OBJECT_TYPE_NAME_A "Directory Service Object" -#define ACCESS_DS_OBJECT_TYPE_NAME_W L"Directory Service Object" - -#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) -#define SE_PRIVILEGE_ENABLED (0x00000002L) -#define SE_PRIVILEGE_REMOVED (0X00000004L) -#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) - -#define PRIVILEGE_SET_ALL_NECESSARY (1) - - typedef struct _PRIVILEGE_SET { - DWORD PrivilegeCount; - DWORD Control; - LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; - } PRIVILEGE_SET,*PPRIVILEGE_SET; - -#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") -#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") -#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") -#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") -#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") -#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") -#define SE_TCB_NAME TEXT("SeTcbPrivilege") -#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") -#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") -#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") -#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") -#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") -#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") -#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") -#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") -#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") -#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") -#define SE_RESTORE_NAME TEXT("SeRestorePrivilege") -#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") -#define SE_DEBUG_NAME TEXT("SeDebugPrivilege") -#define SE_AUDIT_NAME TEXT("SeAuditPrivilege") -#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") -#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") -#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") -#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") -#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") -#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") -#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") -#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") -#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") - - typedef enum _SECURITY_IMPERSONATION_LEVEL { - SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation - } SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; - -#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation -#define SECURITY_MIN_IMPERSONATION_LEVEL SecurityAnonymous -#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation -#define VALID_IMPERSONATION_LEVEL(L) (((L) >= SECURITY_MIN_IMPERSONATION_LEVEL) && ((L) <= SECURITY_MAX_IMPERSONATION_LEVEL)) - -#define TOKEN_ASSIGN_PRIMARY (0x0001) -#define TOKEN_DUPLICATE (0x0002) -#define TOKEN_IMPERSONATE (0x0004) -#define TOKEN_QUERY (0x0008) -#define TOKEN_QUERY_SOURCE (0x0010) -#define TOKEN_ADJUST_PRIVILEGES (0x0020) -#define TOKEN_ADJUST_GROUPS (0x0040) -#define TOKEN_ADJUST_DEFAULT (0x0080) -#define TOKEN_ADJUST_SESSIONID (0x0100) - -#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) -#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID) -#define TOKEN_READ (STANDARD_RIGHTS_READ | TOKEN_QUERY) - -#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) - -#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) - - typedef enum _TOKEN_TYPE { - TokenPrimary = 1,TokenImpersonation - } TOKEN_TYPE; - typedef TOKEN_TYPE *PTOKEN_TYPE; - - typedef enum _TOKEN_INFORMATION_CLASS { - TokenUser = 1,TokenGroups,TokenPrivileges,TokenOwner,TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,TokenImpersonationLevel, - TokenStatistics,TokenRestrictedSids,TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference,TokenSandBoxInert,TokenAuditPolicy, - TokenOrigin,MaxTokenInfoClass - } TOKEN_INFORMATION_CLASS,*PTOKEN_INFORMATION_CLASS; - - typedef struct _TOKEN_USER { - SID_AND_ATTRIBUTES User; - } TOKEN_USER,*PTOKEN_USER; - - typedef struct _TOKEN_GROUPS { - DWORD GroupCount; - SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; - } TOKEN_GROUPS,*PTOKEN_GROUPS; - - typedef struct _TOKEN_PRIVILEGES { - DWORD PrivilegeCount; - LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; - } TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES; - - typedef struct _TOKEN_OWNER { - PSID Owner; - } TOKEN_OWNER,*PTOKEN_OWNER; - - typedef struct _TOKEN_PRIMARY_GROUP { - PSID PrimaryGroup; - } TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; - - typedef struct _TOKEN_DEFAULT_DACL { - PACL DefaultDacl; - } TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; - - typedef struct _TOKEN_GROUPS_AND_PRIVILEGES { - DWORD SidCount; - DWORD SidLength; - PSID_AND_ATTRIBUTES Sids; - DWORD RestrictedSidCount; - DWORD RestrictedSidLength; - PSID_AND_ATTRIBUTES RestrictedSids; - DWORD PrivilegeCount; - DWORD PrivilegeLength; - PLUID_AND_ATTRIBUTES Privileges; - LUID AuthenticationId; - } TOKEN_GROUPS_AND_PRIVILEGES,*PTOKEN_GROUPS_AND_PRIVILEGES; - -#define TOKEN_AUDIT_SUCCESS_INCLUDE 0x1 -#define TOKEN_AUDIT_SUCCESS_EXCLUDE 0x2 -#define TOKEN_AUDIT_FAILURE_INCLUDE 0x4 -#define TOKEN_AUDIT_FAILURE_EXCLUDE 0x8 - -#define VALID_AUDIT_POLICY_BITS (TOKEN_AUDIT_SUCCESS_INCLUDE | TOKEN_AUDIT_SUCCESS_EXCLUDE | TOKEN_AUDIT_FAILURE_INCLUDE | TOKEN_AUDIT_FAILURE_EXCLUDE) -#define VALID_TOKEN_AUDIT_POLICY_ELEMENT(P) ((((P).PolicyMask & ~VALID_AUDIT_POLICY_BITS)==0) && ((P).Category <= AuditEventMaxType)) - - typedef struct _TOKEN_AUDIT_POLICY_ELEMENT { - DWORD Category; - DWORD PolicyMask; - } TOKEN_AUDIT_POLICY_ELEMENT,*PTOKEN_AUDIT_POLICY_ELEMENT; - - typedef struct _TOKEN_AUDIT_POLICY { - DWORD PolicyCount; - TOKEN_AUDIT_POLICY_ELEMENT Policy[ANYSIZE_ARRAY]; - } TOKEN_AUDIT_POLICY,*PTOKEN_AUDIT_POLICY; - -#define PER_USER_AUDITING_POLICY_SIZE(p) (sizeof(TOKEN_AUDIT_POLICY) + (((p)->PolicyCount > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((p)->PolicyCount - ANYSIZE_ARRAY)) : 0)) -#define PER_USER_AUDITING_POLICY_SIZE_BY_COUNT(C) (sizeof(TOKEN_AUDIT_POLICY) + (((C) > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((C) - ANYSIZE_ARRAY)) : 0)) - -#define TOKEN_SOURCE_LENGTH 8 - - typedef struct _TOKEN_SOURCE { - CHAR SourceName[TOKEN_SOURCE_LENGTH]; - LUID SourceIdentifier; - } TOKEN_SOURCE,*PTOKEN_SOURCE; - - typedef struct _TOKEN_STATISTICS { - LUID TokenId; - LUID AuthenticationId; - LARGE_INTEGER ExpirationTime; - TOKEN_TYPE TokenType; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - DWORD DynamicCharged; - DWORD DynamicAvailable; - DWORD GroupCount; - DWORD PrivilegeCount; - LUID ModifiedId; - } TOKEN_STATISTICS,*PTOKEN_STATISTICS; - - typedef struct _TOKEN_CONTROL { - LUID TokenId; - LUID AuthenticationId; - LUID ModifiedId; - TOKEN_SOURCE TokenSource; - } TOKEN_CONTROL,*PTOKEN_CONTROL; - - typedef struct _TOKEN_ORIGIN { - LUID OriginatingLogonSession; - } TOKEN_ORIGIN,*PTOKEN_ORIGIN; - -#define SECURITY_DYNAMIC_TRACKING (TRUE) -#define SECURITY_STATIC_TRACKING (FALSE) - - typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE; - - typedef struct _SECURITY_QUALITY_OF_SERVICE { - DWORD Length; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; - BOOLEAN EffectiveOnly; - } SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; - - typedef struct _SE_IMPERSONATION_STATE { - PACCESS_TOKEN Token; - BOOLEAN CopyOnOpen; - BOOLEAN EffectiveOnly; - SECURITY_IMPERSONATION_LEVEL Level; - } SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE; - -#define DISABLE_MAX_PRIVILEGE 0x1 -#define SANDBOX_INERT 0x2 - - typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION; - -#define OWNER_SECURITY_INFORMATION (0x00000001L) -#define GROUP_SECURITY_INFORMATION (0x00000002L) -#define DACL_SECURITY_INFORMATION (0x00000004L) -#define SACL_SECURITY_INFORMATION (0x00000008L) - -#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) -#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L) -#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) -#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L) - -#define PROCESS_TERMINATE (0x0001) -#define PROCESS_CREATE_THREAD (0x0002) -#define PROCESS_SET_SESSIONID (0x0004) -#define PROCESS_VM_OPERATION (0x0008) -#define PROCESS_VM_READ (0x0010) -#define PROCESS_VM_WRITE (0x0020) -#define PROCESS_DUP_HANDLE (0x0040) -#define PROCESS_CREATE_PROCESS (0x0080) -#define PROCESS_SET_QUOTA (0x0100) -#define PROCESS_SET_INFORMATION (0x0200) -#define PROCESS_QUERY_INFORMATION (0x0400) -#define PROCESS_SUSPEND_RESUME (0x0800) -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF) - -#ifdef _WIN64 -#define MAXIMUM_PROCESSORS 64 -#else -#define MAXIMUM_PROCESSORS 32 -#endif - -#define THREAD_TERMINATE (0x0001) -#define THREAD_SUSPEND_RESUME (0x0002) -#define THREAD_GET_CONTEXT (0x0008) -#define THREAD_SET_CONTEXT (0x0010) -#define THREAD_SET_INFORMATION (0x0020) -#define THREAD_QUERY_INFORMATION (0x0040) -#define THREAD_SET_THREAD_TOKEN (0x0080) -#define THREAD_IMPERSONATE (0x0100) -#define THREAD_DIRECT_IMPERSONATION (0x0200) - -#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF) - -#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) -#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) -#define JOB_OBJECT_QUERY (0x0004) -#define JOB_OBJECT_TERMINATE (0x0008) -#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) -#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F) - - typedef struct _JOB_SET_ARRAY { - HANDLE JobHandle; - DWORD MemberLevel; - DWORD Flags; - } JOB_SET_ARRAY,*PJOB_SET_ARRAY; - -#define FLS_MAXIMUM_AVAILABLE 128 -#define TLS_MINIMUM_AVAILABLE 64 - -#ifndef _NT_TIB_DEFINED -#define _NT_TIB_DEFINED - typedef struct _NT_TIB { - struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; - PVOID StackBase; - PVOID StackLimit; - PVOID SubSystemTib; - union { - PVOID FiberData; - DWORD Version; - }; - PVOID ArbitraryUserPointer; - struct _NT_TIB *Self; - } NT_TIB; - typedef NT_TIB *PNT_TIB; -#endif - - typedef struct _NT_TIB32 { - DWORD ExceptionList; - DWORD StackBase; - DWORD StackLimit; - DWORD SubSystemTib; - union { - DWORD FiberData; - DWORD Version; - }; - DWORD ArbitraryUserPointer; - DWORD Self; - } NT_TIB32,*PNT_TIB32; - - typedef struct _NT_TIB64 { - DWORD64 ExceptionList; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD64 SubSystemTib; - union { - DWORD64 FiberData; - DWORD Version; - }; - DWORD64 ArbitraryUserPointer; - DWORD64 Self; - } NT_TIB64,*PNT_TIB64; - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) -#define WX86 -#endif - -#define THREAD_BASE_PRIORITY_LOWRT 15 -#define THREAD_BASE_PRIORITY_MAX 2 -#define THREAD_BASE_PRIORITY_MIN (-2) -#define THREAD_BASE_PRIORITY_IDLE (-15) - - typedef struct _QUOTA_LIMITS { - SIZE_T PagedPoolLimit; - SIZE_T NonPagedPoolLimit; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - SIZE_T PagefileLimit; - LARGE_INTEGER TimeLimit; - } QUOTA_LIMITS,*PQUOTA_LIMITS; - -#define QUOTA_LIMITS_HARDWS_MIN_ENABLE 0x00000001 -#define QUOTA_LIMITS_HARDWS_MIN_DISABLE 0x00000002 -#define QUOTA_LIMITS_HARDWS_MAX_ENABLE 0x00000004 -#define QUOTA_LIMITS_HARDWS_MAX_DISABLE 0x00000008 - - typedef struct _QUOTA_LIMITS_EX { - SIZE_T PagedPoolLimit; - SIZE_T NonPagedPoolLimit; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - SIZE_T PagefileLimit; - LARGE_INTEGER TimeLimit; - SIZE_T Reserved1; - SIZE_T Reserved2; - SIZE_T Reserved3; - SIZE_T Reserved4; - DWORD Flags; - DWORD Reserved5; - } QUOTA_LIMITS_EX,*PQUOTA_LIMITS_EX; - - typedef struct _IO_COUNTERS { - ULONGLONG ReadOperationCount; - ULONGLONG WriteOperationCount; - ULONGLONG OtherOperationCount; - ULONGLONG ReadTransferCount; - ULONGLONG WriteTransferCount; - ULONGLONG OtherTransferCount; - } IO_COUNTERS; - typedef IO_COUNTERS *PIO_COUNTERS; - - typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { - LARGE_INTEGER TotalUserTime; - LARGE_INTEGER TotalKernelTime; - LARGE_INTEGER ThisPeriodTotalUserTime; - LARGE_INTEGER ThisPeriodTotalKernelTime; - DWORD TotalPageFaultCount; - DWORD TotalProcesses; - DWORD ActiveProcesses; - DWORD TotalTerminatedProcesses; - } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; - - typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION { - LARGE_INTEGER PerProcessUserTimeLimit; - LARGE_INTEGER PerJobUserTimeLimit; - DWORD LimitFlags; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - DWORD ActiveProcessLimit; - ULONG_PTR Affinity; - DWORD PriorityClass; - DWORD SchedulingClass; - } JOBOBJECT_BASIC_LIMIT_INFORMATION,*PJOBOBJECT_BASIC_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { - JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; - IO_COUNTERS IoInfo; - SIZE_T ProcessMemoryLimit; - SIZE_T JobMemoryLimit; - SIZE_T PeakProcessMemoryUsed; - SIZE_T PeakJobMemoryUsed; - } JOBOBJECT_EXTENDED_LIMIT_INFORMATION,*PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST { - DWORD NumberOfAssignedProcesses; - DWORD NumberOfProcessIdsInList; - ULONG_PTR ProcessIdList[1]; - } JOBOBJECT_BASIC_PROCESS_ID_LIST,*PJOBOBJECT_BASIC_PROCESS_ID_LIST; - - typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS { - DWORD UIRestrictionsClass; - } JOBOBJECT_BASIC_UI_RESTRICTIONS,*PJOBOBJECT_BASIC_UI_RESTRICTIONS; - - typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION { - DWORD SecurityLimitFlags; - HANDLE JobToken; - PTOKEN_GROUPS SidsToDisable; - PTOKEN_PRIVILEGES PrivilegesToDelete; - PTOKEN_GROUPS RestrictedSids; - } JOBOBJECT_SECURITY_LIMIT_INFORMATION,*PJOBOBJECT_SECURITY_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION { - DWORD EndOfJobTimeAction; - } JOBOBJECT_END_OF_JOB_TIME_INFORMATION,*PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; - - typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT { - PVOID CompletionKey; - HANDLE CompletionPort; - } JOBOBJECT_ASSOCIATE_COMPLETION_PORT,*PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; - - typedef struct _JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { - JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; - IO_COUNTERS IoInfo; - } JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; - - typedef struct _JOBOBJECT_JOBSET_INFORMATION { - DWORD MemberLevel; - } JOBOBJECT_JOBSET_INFORMATION,*PJOBOBJECT_JOBSET_INFORMATION; - -#define JOB_OBJECT_TERMINATE_AT_END_OF_JOB 0 -#define JOB_OBJECT_POST_AT_END_OF_JOB 1 - -#define JOB_OBJECT_MSG_END_OF_JOB_TIME 1 -#define JOB_OBJECT_MSG_END_OF_PROCESS_TIME 2 -#define JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 3 -#define JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 4 -#define JOB_OBJECT_MSG_NEW_PROCESS 6 -#define JOB_OBJECT_MSG_EXIT_PROCESS 7 -#define JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 8 -#define JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 9 -#define JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 10 - -#define JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 -#define JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 -#define JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 -#define JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 -#define JOB_OBJECT_LIMIT_AFFINITY 0x00000010 -#define JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 -#define JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 -#define JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 - -#define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 -#define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 -#define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 -#define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 -#define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 -#define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 - -#define JOB_OBJECT_LIMIT_RESERVED2 0x00004000 -#define JOB_OBJECT_LIMIT_RESERVED3 0x00008000 -#define JOB_OBJECT_LIMIT_RESERVED4 0x00010000 -#define JOB_OBJECT_LIMIT_RESERVED5 0x00020000 -#define JOB_OBJECT_LIMIT_RESERVED6 0x00040000 - -#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff - -#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff -#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00003fff -#define JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS 0x0007ffff - -#define JOB_OBJECT_UILIMIT_NONE 0x00000000 - -#define JOB_OBJECT_UILIMIT_HANDLES 0x00000001 -#define JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 -#define JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 -#define JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 -#define JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 -#define JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 -#define JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 -#define JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 - -#define JOB_OBJECT_UILIMIT_ALL 0x000000FF - -#define JOB_OBJECT_UI_VALID_FLAGS 0x000000FF - -#define JOB_OBJECT_SECURITY_NO_ADMIN 0x00000001 -#define JOB_OBJECT_SECURITY_RESTRICTED_TOKEN 0x00000002 -#define JOB_OBJECT_SECURITY_ONLY_TOKEN 0x00000004 -#define JOB_OBJECT_SECURITY_FILTER_TOKENS 0x00000008 - -#define JOB_OBJECT_SECURITY_VALID_FLAGS 0x0000000f - - typedef enum _JOBOBJECTINFOCLASS { - JobObjectBasicAccountingInformation = 1,JobObjectBasicLimitInformation,JobObjectBasicProcessIdList,JobObjectBasicUIRestrictions, - JobObjectSecurityLimitInformation,JobObjectEndOfJobTimeInformation,JobObjectAssociateCompletionPortInformation, - JobObjectBasicAndIoAccountingInformation,JobObjectExtendedLimitInformation,JobObjectJobSetInformation,MaxJobObjectInfoClass - } JOBOBJECTINFOCLASS; - -#define EVENT_MODIFY_STATE 0x0002 -#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define MUTANT_QUERY_STATE 0x0001 - -#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| MUTANT_QUERY_STATE) -#define SEMAPHORE_MODIFY_STATE 0x0002 -#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define TIMER_QUERY_STATE 0x0001 -#define TIMER_MODIFY_STATE 0x0002 - -#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| TIMER_QUERY_STATE|TIMER_MODIFY_STATE) - -#define TIME_ZONE_ID_UNKNOWN 0 -#define TIME_ZONE_ID_STANDARD 1 -#define TIME_ZONE_ID_DAYLIGHT 2 - - typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { - RelationProcessorCore,RelationNumaNode,RelationCache - } LOGICAL_PROCESSOR_RELATIONSHIP; - -#define LTP_PC_SMT 0x1 - - typedef enum _PROCESSOR_CACHE_TYPE { - CacheUnified,CacheInstruction,CacheData,CacheTrace - } PROCESSOR_CACHE_TYPE; - -#define CACHE_FULLY_ASSOCIATIVE 0xFF - - typedef struct _CACHE_DESCRIPTOR { - BYTE Level; - BYTE Associativity; - WORD LineSize; - DWORD Size; - PROCESSOR_CACHE_TYPE Type; - } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; - - typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { - ULONG_PTR ProcessorMask; - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - union { - struct { - BYTE Flags; - } ProcessorCore; - struct { - DWORD NodeNumber; - } NumaNode; - CACHE_DESCRIPTOR Cache; - ULONGLONG Reserved[2]; - }; - } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; - -#define PROCESSOR_INTEL_386 386 -#define PROCESSOR_INTEL_486 486 -#define PROCESSOR_INTEL_PENTIUM 586 -#define PROCESSOR_INTEL_IA64 2200 -#define PROCESSOR_AMD_X8664 8664 -#define PROCESSOR_MIPS_R4000 4000 -#define PROCESSOR_ALPHA_21064 21064 -#define PROCESSOR_PPC_601 601 -#define PROCESSOR_PPC_603 603 -#define PROCESSOR_PPC_604 604 -#define PROCESSOR_PPC_620 620 -#define PROCESSOR_HITACHI_SH3 10003 -#define PROCESSOR_HITACHI_SH3E 10004 -#define PROCESSOR_HITACHI_SH4 10005 -#define PROCESSOR_MOTOROLA_821 821 -#define PROCESSOR_SHx_SH3 103 -#define PROCESSOR_SHx_SH4 104 -#define PROCESSOR_STRONGARM 2577 -#define PROCESSOR_ARM720 1824 -#define PROCESSOR_ARM820 2080 -#define PROCESSOR_ARM920 2336 -#define PROCESSOR_ARM_7TDMI 70001 -#define PROCESSOR_OPTIL 0x494f - -#define PROCESSOR_ARCHITECTURE_INTEL 0 -#define PROCESSOR_ARCHITECTURE_MIPS 1 -#define PROCESSOR_ARCHITECTURE_ALPHA 2 -#define PROCESSOR_ARCHITECTURE_PPC 3 -#define PROCESSOR_ARCHITECTURE_SHX 4 -#define PROCESSOR_ARCHITECTURE_ARM 5 -#define PROCESSOR_ARCHITECTURE_IA64 6 -#define PROCESSOR_ARCHITECTURE_ALPHA64 7 -#define PROCESSOR_ARCHITECTURE_MSIL 8 -#define PROCESSOR_ARCHITECTURE_AMD64 9 -#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 - -#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF - -#define PF_FLOATING_POINT_PRECISION_ERRATA 0 -#define PF_FLOATING_POINT_EMULATED 1 -#define PF_COMPARE_EXCHANGE_DOUBLE 2 -#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 -#define PF_PPC_MOVEMEM_64BIT_OK 4 -#define PF_ALPHA_BYTE_INSTRUCTIONS 5 -#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 -#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 -#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 -#define PF_PAE_ENABLED 9 -#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 -#define PF_SSE_DAZ_MODE_AVAILABLE 11 -#define PF_NX_ENABLED 12 - - typedef struct _MEMORY_BASIC_INFORMATION { - PVOID BaseAddress; - PVOID AllocationBase; - DWORD AllocationProtect; - SIZE_T RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; - - typedef struct _MEMORY_BASIC_INFORMATION32 { - DWORD BaseAddress; - DWORD AllocationBase; - DWORD AllocationProtect; - DWORD RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32; - - typedef DECLSPEC_ALIGN(16) struct _MEMORY_BASIC_INFORMATION64 { - ULONGLONG BaseAddress; - ULONGLONG AllocationBase; - DWORD AllocationProtect; - DWORD __alignment1; - ULONGLONG RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - DWORD __alignment2; - } MEMORY_BASIC_INFORMATION64,*PMEMORY_BASIC_INFORMATION64; - -#define SECTION_QUERY 0x0001 -#define SECTION_MAP_WRITE 0x0002 -#define SECTION_MAP_READ 0x0004 -#define SECTION_MAP_EXECUTE 0x0008 -#define SECTION_EXTEND_SIZE 0x0010 -#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 - -#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE) -#define PAGE_NOACCESS 0x01 -#define PAGE_READONLY 0x02 -#define PAGE_READWRITE 0x04 -#define PAGE_WRITECOPY 0x08 -#define PAGE_EXECUTE 0x10 -#define PAGE_EXECUTE_READ 0x20 -#define PAGE_EXECUTE_READWRITE 0x40 -#define PAGE_EXECUTE_WRITECOPY 0x80 -#define PAGE_GUARD 0x100 -#define PAGE_NOCACHE 0x200 -#define PAGE_WRITECOMBINE 0x400 -#define MEM_COMMIT 0x1000 -#define MEM_RESERVE 0x2000 -#define MEM_DECOMMIT 0x4000 -#define MEM_RELEASE 0x8000 -#define MEM_FREE 0x10000 -#define MEM_PRIVATE 0x20000 -#define MEM_MAPPED 0x40000 -#define MEM_RESET 0x80000 -#define MEM_TOP_DOWN 0x100000 -#define MEM_WRITE_WATCH 0x200000 -#define MEM_PHYSICAL 0x400000 -#define MEM_LARGE_PAGES 0x20000000 -#define MEM_4MB_PAGES 0x80000000 -#define SEC_FILE 0x800000 -#define SEC_IMAGE 0x1000000 -#define SEC_RESERVE 0x4000000 -#define SEC_COMMIT 0x8000000 -#define SEC_NOCACHE 0x10000000 -#define SEC_LARGE_PAGES 0x80000000 -#define MEM_IMAGE SEC_IMAGE -#define WRITE_WATCH_FLAG_RESET 0x01 - -#define FILE_READ_DATA (0x0001) -#define FILE_LIST_DIRECTORY (0x0001) - -#define FILE_WRITE_DATA (0x0002) -#define FILE_ADD_FILE (0x0002) - -#define FILE_APPEND_DATA (0x0004) -#define FILE_ADD_SUBDIRECTORY (0x0004) -#define FILE_CREATE_PIPE_INSTANCE (0x0004) - -#define FILE_READ_EA (0x0008) - -#define FILE_WRITE_EA (0x0010) - -#define FILE_EXECUTE (0x0020) -#define FILE_TRAVERSE (0x0020) - -#define FILE_DELETE_CHILD (0x0040) - -#define FILE_READ_ATTRIBUTES (0x0080) - -#define FILE_WRITE_ATTRIBUTES (0x0100) - -#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) -#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) -#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) -#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) - -#define FILE_SHARE_READ 0x00000001 -#define FILE_SHARE_WRITE 0x00000002 -#define FILE_SHARE_DELETE 0x00000004 -#define FILE_ATTRIBUTE_READONLY 0x00000001 -#define FILE_ATTRIBUTE_HIDDEN 0x00000002 -#define FILE_ATTRIBUTE_SYSTEM 0x00000004 -#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 -#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 -#define FILE_ATTRIBUTE_DEVICE 0x00000040 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 -#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 -#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 -#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 -#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 -#define FILE_ATTRIBUTE_OFFLINE 0x00001000 -#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 -#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 -#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 -#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 -#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 -#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 -#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 -#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 -#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 -#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 -#define FILE_ACTION_ADDED 0x00000001 -#define FILE_ACTION_REMOVED 0x00000002 -#define FILE_ACTION_MODIFIED 0x00000003 -#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 -#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 -#define MAILSLOT_NO_MESSAGE ((DWORD)-1) -#define MAILSLOT_WAIT_FOREVER ((DWORD)-1) -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_READ_ONLY_VOLUME 0x00080000 - - typedef struct _FILE_NOTIFY_INFORMATION { - DWORD NextEntryOffset; - DWORD Action; - DWORD FileNameLength; - WCHAR FileName[1]; - } FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; - - typedef union _FILE_SEGMENT_ELEMENT { - PVOID64 Buffer; - ULONGLONG Alignment; - }FILE_SEGMENT_ELEMENT,*PFILE_SEGMENT_ELEMENT; - - typedef struct _REPARSE_GUID_DATA_BUFFER { - DWORD ReparseTag; - WORD ReparseDataLength; - WORD Reserved; - GUID ReparseGuid; - struct { - BYTE DataBuffer[1]; - } GenericReparseBuffer; - } REPARSE_GUID_DATA_BUFFER,*PREPARSE_GUID_DATA_BUFFER; - -#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,GenericReparseBuffer) - -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 *1024) - -#define IO_REPARSE_TAG_RESERVED_ZERO (0) -#define IO_REPARSE_TAG_RESERVED_ONE (1) - -#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE - -#define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000)) -#define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000)) - -#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) -#define IO_REPARSE_TAG_HSM (0xC0000004L) -#define IO_REPARSE_TAG_SIS (0x80000007L) -#define IO_REPARSE_TAG_DFS (0x8000000AL) -#define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL) -#define IO_COMPLETION_MODIFY_STATE 0x0002 -#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) -#define DUPLICATE_CLOSE_SOURCE 0x00000001 -#define DUPLICATE_SAME_ACCESS 0x00000002 - - typedef enum _SYSTEM_POWER_STATE { - PowerSystemUnspecified = 0,PowerSystemWorking = 1,PowerSystemSleeping1 = 2,PowerSystemSleeping2 = 3,PowerSystemSleeping3 = 4,PowerSystemHibernate = 5,PowerSystemShutdown = 6,PowerSystemMaximum = 7 - } SYSTEM_POWER_STATE,*PSYSTEM_POWER_STATE; - -#define POWER_SYSTEM_MAXIMUM 7 - - typedef enum { - PowerActionNone = 0,PowerActionReserved,PowerActionSleep,PowerActionHibernate,PowerActionShutdown,PowerActionShutdownReset,PowerActionShutdownOff,PowerActionWarmEject - } POWER_ACTION,*PPOWER_ACTION; - - typedef enum _DEVICE_POWER_STATE { - PowerDeviceUnspecified = 0,PowerDeviceD0,PowerDeviceD1,PowerDeviceD2,PowerDeviceD3,PowerDeviceMaximum - } DEVICE_POWER_STATE,*PDEVICE_POWER_STATE; - -#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) -#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) -#define ES_USER_PRESENT ((DWORD)0x00000004) -#define ES_CONTINUOUS ((DWORD)0x80000000) - - typedef DWORD EXECUTION_STATE; - - typedef enum { - LT_DONT_CARE,LT_LOWEST_LATENCY - } LATENCY_TIME; - -#define PDCAP_D0_SUPPORTED 0x00000001 -#define PDCAP_D1_SUPPORTED 0x00000002 -#define PDCAP_D2_SUPPORTED 0x00000004 -#define PDCAP_D3_SUPPORTED 0x00000008 -#define PDCAP_WAKE_FROM_D0_SUPPORTED 0x00000010 -#define PDCAP_WAKE_FROM_D1_SUPPORTED 0x00000020 -#define PDCAP_WAKE_FROM_D2_SUPPORTED 0x00000040 -#define PDCAP_WAKE_FROM_D3_SUPPORTED 0x00000080 -#define PDCAP_WARM_EJECT_SUPPORTED 0x00000100 - - typedef struct CM_Power_Data_s { - DWORD PD_Size; - DEVICE_POWER_STATE PD_MostRecentPowerState; - DWORD PD_Capabilities; - DWORD PD_D1Latency; - DWORD PD_D2Latency; - DWORD PD_D3Latency; - DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; - SYSTEM_POWER_STATE PD_DeepestSystemWake; - } CM_POWER_DATA,*PCM_POWER_DATA; - - typedef enum { - SystemPowerPolicyAc,SystemPowerPolicyDc,VerifySystemPolicyAc,VerifySystemPolicyDc,SystemPowerCapabilities,SystemBatteryState,SystemPowerStateHandler,ProcessorStateHandler,SystemPowerPolicyCurrent,AdministratorPowerPolicy,SystemReserveHiberFile,ProcessorInformation,SystemPowerInformation,ProcessorStateHandler2,LastWakeTime,LastSleepTime,SystemExecutionState,SystemPowerStateNotifyHandler,ProcessorPowerPolicyAc,ProcessorPowerPolicyDc,VerifyProcessorPowerPolicyAc,VerifyProcessorPowerPolicyDc,ProcessorPowerPolicyCurrent,SystemPowerStateLogging,SystemPowerLoggingEntry - } POWER_INFORMATION_LEVEL; - - typedef struct { - DWORD Granularity; - DWORD Capacity; - } BATTERY_REPORTING_SCALE,*PBATTERY_REPORTING_SCALE; - - typedef struct { - POWER_ACTION Action; - DWORD Flags; - DWORD EventCode; - } POWER_ACTION_POLICY,*PPOWER_ACTION_POLICY; - -#define POWER_ACTION_QUERY_ALLOWED 0x00000001 -#define POWER_ACTION_UI_ALLOWED 0x00000002 -#define POWER_ACTION_OVERRIDE_APPS 0x00000004 -#define POWER_ACTION_LIGHTEST_FIRST 0x10000000 -#define POWER_ACTION_LOCK_CONSOLE 0x20000000 -#define POWER_ACTION_DISABLE_WAKES 0x40000000 -#define POWER_ACTION_CRITICAL 0x80000000 - -#define POWER_LEVEL_USER_NOTIFY_TEXT 0x00000001 -#define POWER_LEVEL_USER_NOTIFY_SOUND 0x00000002 -#define POWER_LEVEL_USER_NOTIFY_EXEC 0x00000004 -#define POWER_USER_NOTIFY_BUTTON 0x00000008 -#define POWER_USER_NOTIFY_SHUTDOWN 0x00000010 -#define POWER_FORCE_TRIGGER_RESET 0x80000000 - - typedef struct { - BOOLEAN Enable; - BYTE Spare[3]; - DWORD BatteryLevel; - POWER_ACTION_POLICY PowerPolicy; - SYSTEM_POWER_STATE MinSystemState; - } SYSTEM_POWER_LEVEL,*PSYSTEM_POWER_LEVEL; - -#define NUM_DISCHARGE_POLICIES 4 -#define DISCHARGE_POLICY_CRITICAL 0 -#define DISCHARGE_POLICY_LOW 1 - -#define PO_THROTTLE_NONE 0 -#define PO_THROTTLE_CONSTANT 1 -#define PO_THROTTLE_DEGRADE 2 -#define PO_THROTTLE_ADAPTIVE 3 -#define PO_THROTTLE_MAXIMUM 4 - - typedef struct _SYSTEM_POWER_POLICY { - DWORD Revision; - POWER_ACTION_POLICY PowerButton; - POWER_ACTION_POLICY SleepButton; - POWER_ACTION_POLICY LidClose; - SYSTEM_POWER_STATE LidOpenWake; - DWORD Reserved; - POWER_ACTION_POLICY Idle; - DWORD IdleTimeout; - BYTE IdleSensitivity; - BYTE DynamicThrottle; - BYTE Spare2[2]; - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - SYSTEM_POWER_STATE ReducedLatencySleep; - DWORD WinLogonFlags; - DWORD Spare3; - DWORD DozeS4Timeout; - DWORD BroadcastCapacityResolution; - SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; - DWORD VideoTimeout; - BOOLEAN VideoDimDisplay; - DWORD VideoReserved[3]; - DWORD SpindownTimeout; - BOOLEAN OptimizeForPower; - BYTE FanThrottleTolerance; - BYTE ForcedThrottle; - BYTE MinThrottle; - POWER_ACTION_POLICY OverThrottled; - } SYSTEM_POWER_POLICY,*PSYSTEM_POWER_POLICY; - - typedef struct _PROCESSOR_POWER_POLICY_INFO { - DWORD TimeCheck; - DWORD DemoteLimit; - DWORD PromoteLimit; - BYTE DemotePercent; - BYTE PromotePercent; - BYTE Spare[2]; - DWORD AllowDemotion:1; - DWORD AllowPromotion:1; - DWORD Reserved:30; - } PROCESSOR_POWER_POLICY_INFO,*PPROCESSOR_POWER_POLICY_INFO; - - typedef struct _PROCESSOR_POWER_POLICY { - DWORD Revision; - BYTE DynamicThrottle; - BYTE Spare[3]; - DWORD DisableCStates:1; - DWORD Reserved:31; - DWORD PolicyCount; - PROCESSOR_POWER_POLICY_INFO Policy[3]; - } PROCESSOR_POWER_POLICY,*PPROCESSOR_POWER_POLICY; - - typedef struct _ADMINISTRATOR_POWER_POLICY { - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - DWORD MinVideoTimeout; - DWORD MaxVideoTimeout; - DWORD MinSpindownTimeout; - DWORD MaxSpindownTimeout; - } ADMINISTRATOR_POWER_POLICY,*PADMINISTRATOR_POWER_POLICY; - - typedef struct { - BOOLEAN PowerButtonPresent; - BOOLEAN SleepButtonPresent; - BOOLEAN LidPresent; - BOOLEAN SystemS1; - BOOLEAN SystemS2; - BOOLEAN SystemS3; - BOOLEAN SystemS4; - BOOLEAN SystemS5; - BOOLEAN HiberFilePresent; - BOOLEAN FullWake; - BOOLEAN VideoDimPresent; - BOOLEAN ApmPresent; - BOOLEAN UpsPresent; - BOOLEAN ThermalControl; - BOOLEAN ProcessorThrottle; - BYTE ProcessorMinThrottle; - BYTE ProcessorMaxThrottle; - BYTE spare2[4]; - BOOLEAN DiskSpinDown; - BYTE spare3[8]; - BOOLEAN SystemBatteriesPresent; - BOOLEAN BatteriesAreShortTerm; - BATTERY_REPORTING_SCALE BatteryScale[3]; - SYSTEM_POWER_STATE AcOnLineWake; - SYSTEM_POWER_STATE SoftLidWake; - SYSTEM_POWER_STATE RtcWake; - SYSTEM_POWER_STATE MinDeviceWakeState; - SYSTEM_POWER_STATE DefaultLowLatencyWake; - } SYSTEM_POWER_CAPABILITIES,*PSYSTEM_POWER_CAPABILITIES; - - typedef struct { - BOOLEAN AcOnLine; - BOOLEAN BatteryPresent; - BOOLEAN Charging; - BOOLEAN Discharging; - BOOLEAN Spare1[4]; - DWORD MaxCapacity; - DWORD RemainingCapacity; - DWORD Rate; - DWORD EstimatedTime; - DWORD DefaultAlert1; - DWORD DefaultAlert2; - } SYSTEM_BATTERY_STATE,*PSYSTEM_BATTERY_STATE; - -#include "pshpack4.h" - -#define IMAGE_DOS_SIGNATURE 0x5A4D -#define IMAGE_OS2_SIGNATURE 0x454E -#define IMAGE_OS2_SIGNATURE_LE 0x454C -#define IMAGE_VXD_SIGNATURE 0x454C -#define IMAGE_NT_SIGNATURE 0x00004550 - -#include "pshpack2.h" - - typedef struct _IMAGE_DOS_HEADER { - WORD e_magic; - WORD e_cblp; - WORD e_cp; - WORD e_crlc; - WORD e_cparhdr; - WORD e_minalloc; - WORD e_maxalloc; - WORD e_ss; - WORD e_sp; - WORD e_csum; - WORD e_ip; - WORD e_cs; - WORD e_lfarlc; - WORD e_ovno; - WORD e_res[4]; - WORD e_oemid; - WORD e_oeminfo; - WORD e_res2[10]; - LONG e_lfanew; - } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; - - typedef struct _IMAGE_OS2_HEADER { - WORD ne_magic; - CHAR ne_ver; - CHAR ne_rev; - WORD ne_enttab; - WORD ne_cbenttab; - LONG ne_crc; - WORD ne_flags; - WORD ne_autodata; - WORD ne_heap; - WORD ne_stack; - LONG ne_csip; - LONG ne_sssp; - WORD ne_cseg; - WORD ne_cmod; - WORD ne_cbnrestab; - WORD ne_segtab; - WORD ne_rsrctab; - WORD ne_restab; - WORD ne_modtab; - WORD ne_imptab; - LONG ne_nrestab; - WORD ne_cmovent; - WORD ne_align; - WORD ne_cres; - BYTE ne_exetyp; - BYTE ne_flagsothers; - WORD ne_pretthunks; - WORD ne_psegrefbytes; - WORD ne_swaparea; - WORD ne_expver; - } IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; - - typedef struct _IMAGE_VXD_HEADER { - WORD e32_magic; - BYTE e32_border; - BYTE e32_worder; - DWORD e32_level; - WORD e32_cpu; - WORD e32_os; - DWORD e32_ver; - DWORD e32_mflags; - DWORD e32_mpages; - DWORD e32_startobj; - DWORD e32_eip; - DWORD e32_stackobj; - DWORD e32_esp; - DWORD e32_pagesize; - DWORD e32_lastpagesize; - DWORD e32_fixupsize; - DWORD e32_fixupsum; - DWORD e32_ldrsize; - DWORD e32_ldrsum; - DWORD e32_objtab; - DWORD e32_objcnt; - DWORD e32_objmap; - DWORD e32_itermap; - DWORD e32_rsrctab; - DWORD e32_rsrccnt; - DWORD e32_restab; - DWORD e32_enttab; - DWORD e32_dirtab; - DWORD e32_dircnt; - DWORD e32_fpagetab; - DWORD e32_frectab; - DWORD e32_impmod; - DWORD e32_impmodcnt; - DWORD e32_impproc; - DWORD e32_pagesum; - DWORD e32_datapage; - DWORD e32_preload; - DWORD e32_nrestab; - DWORD e32_cbnrestab; - DWORD e32_nressum; - DWORD e32_autodata; - DWORD e32_debuginfo; - DWORD e32_debuglen; - DWORD e32_instpreload; - DWORD e32_instdemand; - DWORD e32_heapsize; - BYTE e32_res3[12]; - DWORD e32_winresoff; - DWORD e32_winreslen; - WORD e32_devid; - WORD e32_ddkver; - } IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER; - -#include "poppack.h" - - typedef struct _IMAGE_FILE_HEADER { - WORD Machine; - WORD NumberOfSections; - DWORD TimeDateStamp; - DWORD PointerToSymbolTable; - DWORD NumberOfSymbols; - WORD SizeOfOptionalHeader; - WORD Characteristics; - } IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; - -#define IMAGE_SIZEOF_FILE_HEADER 20 - -#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 -#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 -#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 -#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 -#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 -#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 -#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 -#define IMAGE_FILE_32BIT_MACHINE 0x0100 -#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 -#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 -#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 -#define IMAGE_FILE_SYSTEM 0x1000 -#define IMAGE_FILE_DLL 0x2000 -#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 -#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 - -#define IMAGE_FILE_MACHINE_UNKNOWN 0 -#define IMAGE_FILE_MACHINE_I386 0x014c -#define IMAGE_FILE_MACHINE_R3000 0x0162 -#define IMAGE_FILE_MACHINE_R4000 0x0166 -#define IMAGE_FILE_MACHINE_R10000 0x0168 -#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 -#define IMAGE_FILE_MACHINE_ALPHA 0x0184 -#define IMAGE_FILE_MACHINE_SH3 0x01a2 -#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 -#define IMAGE_FILE_MACHINE_SH3E 0x01a4 -#define IMAGE_FILE_MACHINE_SH4 0x01a6 -#define IMAGE_FILE_MACHINE_SH5 0x01a8 -#define IMAGE_FILE_MACHINE_ARM 0x01c0 -#define IMAGE_FILE_MACHINE_THUMB 0x01c2 -#define IMAGE_FILE_MACHINE_AM33 0x01d3 -#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 -#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 -#define IMAGE_FILE_MACHINE_IA64 0x0200 -#define IMAGE_FILE_MACHINE_MIPS16 0x0266 -#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 -#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 -#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 -#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 -#define IMAGE_FILE_MACHINE_TRICORE 0x0520 -#define IMAGE_FILE_MACHINE_CEF 0x0CEF -#define IMAGE_FILE_MACHINE_EBC 0x0EBC -#define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define IMAGE_FILE_MACHINE_M32R 0x9041 -#define IMAGE_FILE_MACHINE_CEE 0xC0EE - - typedef struct _IMAGE_DATA_DIRECTORY { - DWORD VirtualAddress; - DWORD Size; - } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 - - typedef struct _IMAGE_OPTIONAL_HEADER { - - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - DWORD SizeOfStackReserve; - DWORD SizeOfStackCommit; - DWORD SizeOfHeapReserve; - DWORD SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; - - typedef struct _IMAGE_ROM_OPTIONAL_HEADER { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD BaseOfBss; - DWORD GprMask; - DWORD CprMask[4]; - DWORD GpValue; - } IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER; - - typedef struct _IMAGE_OPTIONAL_HEADER64 { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - ULONGLONG ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - ULONGLONG SizeOfStackReserve; - ULONGLONG SizeOfStackCommit; - ULONGLONG SizeOfHeapReserve; - ULONGLONG SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; - -#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 -#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 -#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 -#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 - -#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b -#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b -#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 - -#ifdef _WIN64 - typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; - typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER -#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC -#else - typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; - typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER -#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC -#endif - - typedef struct _IMAGE_NT_HEADERS64 { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER64 OptionalHeader; - } IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; - - typedef struct _IMAGE_NT_HEADERS { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER32 OptionalHeader; - } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; - - typedef struct _IMAGE_ROM_HEADERS { - IMAGE_FILE_HEADER FileHeader; - IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; - } IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS; - -#ifdef _WIN64 - typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; - typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; -#else - typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; - typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; -#endif - -#define IMAGE_FIRST_SECTION(ntheader) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)ntheader + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader) + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) - -#define IMAGE_SUBSYSTEM_UNKNOWN 0 -#define IMAGE_SUBSYSTEM_NATIVE 1 -#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 -#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 -#define IMAGE_SUBSYSTEM_OS2_CUI 5 -#define IMAGE_SUBSYSTEM_POSIX_CUI 7 -#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 -#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 -#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 -#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -#define IMAGE_SUBSYSTEM_EFI_ROM 13 -#define IMAGE_SUBSYSTEM_XBOX 14 - -#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 -#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 -#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 -#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 -#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 - -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 -#define IMAGE_DIRECTORY_ENTRY_TLS 9 -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 -#define IMAGE_DIRECTORY_ENTRY_IAT 12 -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 - - typedef struct ANON_OBJECT_HEADER { - WORD Sig1; - WORD Sig2; - WORD Version; - WORD Machine; - DWORD TimeDateStamp; - CLSID ClassID; - DWORD SizeOfData; - } ANON_OBJECT_HEADER; - -#define IMAGE_SIZEOF_SHORT_NAME 8 - - typedef struct _IMAGE_SECTION_HEADER { - BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - DWORD PhysicalAddress; - DWORD VirtualSize; - } Misc; - DWORD VirtualAddress; - DWORD SizeOfRawData; - DWORD PointerToRawData; - DWORD PointerToRelocations; - DWORD PointerToLinenumbers; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD Characteristics; - } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#define IMAGE_SCN_LNK_OTHER 0x00000100 -#define IMAGE_SCN_LNK_INFO 0x00000200 -#define IMAGE_SCN_LNK_REMOVE 0x00000800 -#define IMAGE_SCN_LNK_COMDAT 0x00001000 -#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 -#define IMAGE_SCN_GPREL 0x00008000 -#define IMAGE_SCN_MEM_FARDATA 0x00008000 -#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 -#define IMAGE_SCN_MEM_16BIT 0x00020000 -#define IMAGE_SCN_MEM_LOCKED 0x00040000 -#define IMAGE_SCN_MEM_PRELOAD 0x00080000 - -#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 -#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 -#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 -#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 -#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 -#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 -#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 -#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 -#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 -#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 -#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 -#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 -#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 -#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 - -#define IMAGE_SCN_ALIGN_MASK 0x00F00000 - -#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 -#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 -#define IMAGE_SCN_MEM_SHARED 0x10000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 - -#define IMAGE_SCN_SCALE_INDEX 0x00000001 - -#include "pshpack2.h" - - typedef struct _IMAGE_SYMBOL { - union { - BYTE ShortName[8]; - struct { - DWORD Short; - DWORD Long; - } Name; - DWORD LongName[2]; - } N; - DWORD Value; - SHORT SectionNumber; - WORD Type; - BYTE StorageClass; - BYTE NumberOfAuxSymbols; - } IMAGE_SYMBOL; - typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; - -#define IMAGE_SIZEOF_SYMBOL 18 - -#define IMAGE_SYM_UNDEFINED (SHORT)0 -#define IMAGE_SYM_ABSOLUTE (SHORT)-1 -#define IMAGE_SYM_DEBUG (SHORT)-2 -#define IMAGE_SYM_SECTION_MAX 0xFEFF - -#define IMAGE_SYM_TYPE_NULL 0x0000 -#define IMAGE_SYM_TYPE_VOID 0x0001 -#define IMAGE_SYM_TYPE_CHAR 0x0002 -#define IMAGE_SYM_TYPE_SHORT 0x0003 -#define IMAGE_SYM_TYPE_INT 0x0004 -#define IMAGE_SYM_TYPE_LONG 0x0005 -#define IMAGE_SYM_TYPE_FLOAT 0x0006 -#define IMAGE_SYM_TYPE_DOUBLE 0x0007 -#define IMAGE_SYM_TYPE_STRUCT 0x0008 -#define IMAGE_SYM_TYPE_UNION 0x0009 -#define IMAGE_SYM_TYPE_ENUM 0x000A -#define IMAGE_SYM_TYPE_MOE 0x000B -#define IMAGE_SYM_TYPE_BYTE 0x000C -#define IMAGE_SYM_TYPE_WORD 0x000D -#define IMAGE_SYM_TYPE_UINT 0x000E -#define IMAGE_SYM_TYPE_DWORD 0x000F -#define IMAGE_SYM_TYPE_PCODE 0x8000 - -#define IMAGE_SYM_DTYPE_NULL 0 -#define IMAGE_SYM_DTYPE_POINTER 1 -#define IMAGE_SYM_DTYPE_FUNCTION 2 -#define IMAGE_SYM_DTYPE_ARRAY 3 - -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE)-1 -#define IMAGE_SYM_CLASS_NULL 0x0000 -#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 -#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 -#define IMAGE_SYM_CLASS_STATIC 0x0003 -#define IMAGE_SYM_CLASS_REGISTER 0x0004 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 -#define IMAGE_SYM_CLASS_LABEL 0x0006 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 -#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 -#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B -#define IMAGE_SYM_CLASS_UNION_TAG 0x000C -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E -#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 -#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 -#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 -#define IMAGE_SYM_CLASS_BLOCK 0x0064 -#define IMAGE_SYM_CLASS_FUNCTION 0x0065 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 -#define IMAGE_SYM_CLASS_FILE 0x0067 -#define IMAGE_SYM_CLASS_SECTION 0x0068 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 -#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B - -#define N_BTMASK 0x000F -#define N_TMASK 0x0030 -#define N_TMASK1 0x00C0 -#define N_TMASK2 0x00F0 -#define N_BTSHFT 4 -#define N_TSHIFT 2 - -#define BTYPE(x) ((x) & N_BTMASK) - -#ifndef ISPTR -#define ISPTR(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) -#endif - -#ifndef ISFCN -#define ISFCN(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) -#endif - -#ifndef ISARY -#define ISARY(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) -#endif - -#ifndef ISTAG -#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) -#endif - -#ifndef INCREF -#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) -#endif - - typedef union _IMAGE_AUX_SYMBOL { - struct { - DWORD TagIndex; - union { - struct { - WORD Linenumber; - WORD Size; - } LnSz; - DWORD TotalSize; - } Misc; - union { - struct { - DWORD PointerToLinenumber; - DWORD PointerToNextFunction; - } Function; - struct { - WORD Dimension[4]; - } Array; - } FcnAry; - WORD TvIndex; - } Sym; - struct { - BYTE Name[IMAGE_SIZEOF_SYMBOL]; - } File; - struct { - DWORD Length; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD CheckSum; - SHORT Number; - BYTE Selection; - } Section; - } IMAGE_AUX_SYMBOL; - typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL; - -#define IMAGE_SIZEOF_AUX_SYMBOL 18 - - typedef enum IMAGE_AUX_SYMBOL_TYPE { - IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 - } IMAGE_AUX_SYMBOL_TYPE; - -#include - - typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF { - BYTE bAuxType; - BYTE bReserved; - DWORD SymbolTableIndex; - BYTE rgbReserved[12]; - } IMAGE_AUX_SYMBOL_TOKEN_DEF; - - typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF; - -#include - -#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 -#define IMAGE_COMDAT_SELECT_ANY 2 -#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 -#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 -#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 -#define IMAGE_COMDAT_SELECT_LARGEST 6 -#define IMAGE_COMDAT_SELECT_NEWEST 7 - -#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 -#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 -#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 - - typedef struct _IMAGE_RELOCATION { - union { - DWORD VirtualAddress; - DWORD RelocCount; - }; - DWORD SymbolTableIndex; - WORD Type; - } IMAGE_RELOCATION; - typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION; - -#define IMAGE_SIZEOF_RELOCATION 10 - -#define IMAGE_REL_I386_ABSOLUTE 0x0000 -#define IMAGE_REL_I386_DIR16 0x0001 -#define IMAGE_REL_I386_REL16 0x0002 -#define IMAGE_REL_I386_DIR32 0x0006 -#define IMAGE_REL_I386_DIR32NB 0x0007 -#define IMAGE_REL_I386_SEG12 0x0009 -#define IMAGE_REL_I386_SECTION 0x000A -#define IMAGE_REL_I386_SECREL 0x000B -#define IMAGE_REL_I386_TOKEN 0x000C -#define IMAGE_REL_I386_SECREL7 0x000D -#define IMAGE_REL_I386_REL32 0x0014 - -#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 -#define IMAGE_REL_MIPS_REFHALF 0x0001 -#define IMAGE_REL_MIPS_REFWORD 0x0002 -#define IMAGE_REL_MIPS_JMPADDR 0x0003 -#define IMAGE_REL_MIPS_REFHI 0x0004 -#define IMAGE_REL_MIPS_REFLO 0x0005 -#define IMAGE_REL_MIPS_GPREL 0x0006 -#define IMAGE_REL_MIPS_LITERAL 0x0007 -#define IMAGE_REL_MIPS_SECTION 0x000A -#define IMAGE_REL_MIPS_SECREL 0x000B -#define IMAGE_REL_MIPS_SECRELLO 0x000C -#define IMAGE_REL_MIPS_SECRELHI 0x000D -#define IMAGE_REL_MIPS_TOKEN 0x000E -#define IMAGE_REL_MIPS_JMPADDR16 0x0010 -#define IMAGE_REL_MIPS_REFWORDNB 0x0022 -#define IMAGE_REL_MIPS_PAIR 0x0025 - -#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 -#define IMAGE_REL_ALPHA_REFLONG 0x0001 -#define IMAGE_REL_ALPHA_REFQUAD 0x0002 -#define IMAGE_REL_ALPHA_GPREL32 0x0003 -#define IMAGE_REL_ALPHA_LITERAL 0x0004 -#define IMAGE_REL_ALPHA_LITUSE 0x0005 -#define IMAGE_REL_ALPHA_GPDISP 0x0006 -#define IMAGE_REL_ALPHA_BRADDR 0x0007 -#define IMAGE_REL_ALPHA_HINT 0x0008 -#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 -#define IMAGE_REL_ALPHA_REFHI 0x000A -#define IMAGE_REL_ALPHA_REFLO 0x000B -#define IMAGE_REL_ALPHA_PAIR 0x000C -#define IMAGE_REL_ALPHA_MATCH 0x000D -#define IMAGE_REL_ALPHA_SECTION 0x000E -#define IMAGE_REL_ALPHA_SECREL 0x000F -#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 -#define IMAGE_REL_ALPHA_SECRELLO 0x0011 -#define IMAGE_REL_ALPHA_SECRELHI 0x0012 -#define IMAGE_REL_ALPHA_REFQ3 0x0013 -#define IMAGE_REL_ALPHA_REFQ2 0x0014 -#define IMAGE_REL_ALPHA_REFQ1 0x0015 -#define IMAGE_REL_ALPHA_GPRELLO 0x0016 -#define IMAGE_REL_ALPHA_GPRELHI 0x0017 - -#define IMAGE_REL_PPC_ABSOLUTE 0x0000 -#define IMAGE_REL_PPC_ADDR64 0x0001 -#define IMAGE_REL_PPC_ADDR32 0x0002 -#define IMAGE_REL_PPC_ADDR24 0x0003 -#define IMAGE_REL_PPC_ADDR16 0x0004 -#define IMAGE_REL_PPC_ADDR14 0x0005 -#define IMAGE_REL_PPC_REL24 0x0006 -#define IMAGE_REL_PPC_REL14 0x0007 -#define IMAGE_REL_PPC_TOCREL16 0x0008 -#define IMAGE_REL_PPC_TOCREL14 0x0009 -#define IMAGE_REL_PPC_ADDR32NB 0x000A -#define IMAGE_REL_PPC_SECREL 0x000B -#define IMAGE_REL_PPC_SECTION 0x000C -#define IMAGE_REL_PPC_IFGLUE 0x000D -#define IMAGE_REL_PPC_IMGLUE 0x000E -#define IMAGE_REL_PPC_SECREL16 0x000F -#define IMAGE_REL_PPC_REFHI 0x0010 -#define IMAGE_REL_PPC_REFLO 0x0011 -#define IMAGE_REL_PPC_PAIR 0x0012 -#define IMAGE_REL_PPC_SECRELLO 0x0013 -#define IMAGE_REL_PPC_SECRELHI 0x0014 -#define IMAGE_REL_PPC_GPREL 0x0015 -#define IMAGE_REL_PPC_TOKEN 0x0016 -#define IMAGE_REL_PPC_TYPEMASK 0x00FF -#define IMAGE_REL_PPC_NEG 0x0100 -#define IMAGE_REL_PPC_BRTAKEN 0x0200 -#define IMAGE_REL_PPC_BRNTAKEN 0x0400 -#define IMAGE_REL_PPC_TOCDEFN 0x0800 - -#define IMAGE_REL_SH3_ABSOLUTE 0x0000 -#define IMAGE_REL_SH3_DIRECT16 0x0001 -#define IMAGE_REL_SH3_DIRECT32 0x0002 -#define IMAGE_REL_SH3_DIRECT8 0x0003 -#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 -#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 -#define IMAGE_REL_SH3_DIRECT4 0x0006 -#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 -#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 -#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 -#define IMAGE_REL_SH3_PCREL8_LONG 0x000A -#define IMAGE_REL_SH3_PCREL12_WORD 0x000B -#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C -#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D -#define IMAGE_REL_SH3_SECTION 0x000E -#define IMAGE_REL_SH3_SECREL 0x000F -#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 -#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 -#define IMAGE_REL_SH3_TOKEN 0x0012 - -#define IMAGE_REL_SHM_PCRELPT 0x0013 -#define IMAGE_REL_SHM_REFLO 0x0014 -#define IMAGE_REL_SHM_REFHALF 0x0015 -#define IMAGE_REL_SHM_RELLO 0x0016 -#define IMAGE_REL_SHM_RELHALF 0x0017 -#define IMAGE_REL_SHM_PAIR 0x0018 - -#define IMAGE_REL_SH_NOMODE 0x8000 - -#define IMAGE_REL_ARM_ABSOLUTE 0x0000 -#define IMAGE_REL_ARM_ADDR32 0x0001 -#define IMAGE_REL_ARM_ADDR32NB 0x0002 -#define IMAGE_REL_ARM_BRANCH24 0x0003 -#define IMAGE_REL_ARM_BRANCH11 0x0004 -#define IMAGE_REL_ARM_TOKEN 0x0005 -#define IMAGE_REL_ARM_GPREL12 0x0006 -#define IMAGE_REL_ARM_GPREL7 0x0007 -#define IMAGE_REL_ARM_BLX24 0x0008 -#define IMAGE_REL_ARM_BLX11 0x0009 -#define IMAGE_REL_ARM_SECTION 0x000E -#define IMAGE_REL_ARM_SECREL 0x000F - -#define IMAGE_REL_AM_ABSOLUTE 0x0000 -#define IMAGE_REL_AM_ADDR32 0x0001 -#define IMAGE_REL_AM_ADDR32NB 0x0002 -#define IMAGE_REL_AM_CALL32 0x0003 -#define IMAGE_REL_AM_FUNCINFO 0x0004 -#define IMAGE_REL_AM_REL32_1 0x0005 -#define IMAGE_REL_AM_REL32_2 0x0006 -#define IMAGE_REL_AM_SECREL 0x0007 -#define IMAGE_REL_AM_SECTION 0x0008 -#define IMAGE_REL_AM_TOKEN 0x0009 - -#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 -#define IMAGE_REL_AMD64_ADDR64 0x0001 -#define IMAGE_REL_AMD64_ADDR32 0x0002 -#define IMAGE_REL_AMD64_ADDR32NB 0x0003 -#define IMAGE_REL_AMD64_REL32 0x0004 -#define IMAGE_REL_AMD64_REL32_1 0x0005 -#define IMAGE_REL_AMD64_REL32_2 0x0006 -#define IMAGE_REL_AMD64_REL32_3 0x0007 -#define IMAGE_REL_AMD64_REL32_4 0x0008 -#define IMAGE_REL_AMD64_REL32_5 0x0009 -#define IMAGE_REL_AMD64_SECTION 0x000A -#define IMAGE_REL_AMD64_SECREL 0x000B -#define IMAGE_REL_AMD64_SECREL7 0x000C -#define IMAGE_REL_AMD64_TOKEN 0x000D -#define IMAGE_REL_AMD64_SREL32 0x000E -#define IMAGE_REL_AMD64_PAIR 0x000F -#define IMAGE_REL_AMD64_SSPAN32 0x0010 - -#define IMAGE_REL_IA64_ABSOLUTE 0x0000 -#define IMAGE_REL_IA64_IMM14 0x0001 -#define IMAGE_REL_IA64_IMM22 0x0002 -#define IMAGE_REL_IA64_IMM64 0x0003 -#define IMAGE_REL_IA64_DIR32 0x0004 -#define IMAGE_REL_IA64_DIR64 0x0005 -#define IMAGE_REL_IA64_PCREL21B 0x0006 -#define IMAGE_REL_IA64_PCREL21M 0x0007 -#define IMAGE_REL_IA64_PCREL21F 0x0008 -#define IMAGE_REL_IA64_GPREL22 0x0009 -#define IMAGE_REL_IA64_LTOFF22 0x000A -#define IMAGE_REL_IA64_SECTION 0x000B -#define IMAGE_REL_IA64_SECREL22 0x000C -#define IMAGE_REL_IA64_SECREL64I 0x000D -#define IMAGE_REL_IA64_SECREL32 0x000E - -#define IMAGE_REL_IA64_DIR32NB 0x0010 -#define IMAGE_REL_IA64_SREL14 0x0011 -#define IMAGE_REL_IA64_SREL22 0x0012 -#define IMAGE_REL_IA64_SREL32 0x0013 -#define IMAGE_REL_IA64_UREL32 0x0014 -#define IMAGE_REL_IA64_PCREL60X 0x0015 -#define IMAGE_REL_IA64_PCREL60B 0x0016 -#define IMAGE_REL_IA64_PCREL60F 0x0017 -#define IMAGE_REL_IA64_PCREL60I 0x0018 -#define IMAGE_REL_IA64_PCREL60M 0x0019 -#define IMAGE_REL_IA64_IMMGPREL64 0x001A -#define IMAGE_REL_IA64_TOKEN 0x001B -#define IMAGE_REL_IA64_GPREL32 0x001C -#define IMAGE_REL_IA64_ADDEND 0x001F - -#define IMAGE_REL_CEF_ABSOLUTE 0x0000 -#define IMAGE_REL_CEF_ADDR32 0x0001 -#define IMAGE_REL_CEF_ADDR64 0x0002 -#define IMAGE_REL_CEF_ADDR32NB 0x0003 -#define IMAGE_REL_CEF_SECTION 0x0004 -#define IMAGE_REL_CEF_SECREL 0x0005 -#define IMAGE_REL_CEF_TOKEN 0x0006 - -#define IMAGE_REL_CEE_ABSOLUTE 0x0000 -#define IMAGE_REL_CEE_ADDR32 0x0001 -#define IMAGE_REL_CEE_ADDR64 0x0002 -#define IMAGE_REL_CEE_ADDR32NB 0x0003 -#define IMAGE_REL_CEE_SECTION 0x0004 -#define IMAGE_REL_CEE_SECREL 0x0005 -#define IMAGE_REL_CEE_TOKEN 0x0006 - -#define IMAGE_REL_M32R_ABSOLUTE 0x0000 -#define IMAGE_REL_M32R_ADDR32 0x0001 -#define IMAGE_REL_M32R_ADDR32NB 0x0002 -#define IMAGE_REL_M32R_ADDR24 0x0003 -#define IMAGE_REL_M32R_GPREL16 0x0004 -#define IMAGE_REL_M32R_PCREL24 0x0005 -#define IMAGE_REL_M32R_PCREL16 0x0006 -#define IMAGE_REL_M32R_PCREL8 0x0007 -#define IMAGE_REL_M32R_REFHALF 0x0008 -#define IMAGE_REL_M32R_REFHI 0x0009 -#define IMAGE_REL_M32R_REFLO 0x000A -#define IMAGE_REL_M32R_PAIR 0x000B -#define IMAGE_REL_M32R_SECTION 0x000C -#define IMAGE_REL_M32R_SECREL32 0x000D -#define IMAGE_REL_M32R_TOKEN 0x000E - -#define EXT_IMM64(Value,Address,Size,InstPos,ValPos) Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) -#define INS_IMM64(Value,Address,Size,InstPos,ValPos) *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) - -#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 -#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 -#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 - -#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 -#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 -#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 - -#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 -#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 -#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 - -#define EMARCH_ENC_I17_IC_INST_WORD_X 3 -#define EMARCH_ENC_I17_IC_SIZE_X 1 -#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 -#define EMARCH_ENC_I17_IC_VAL_POS_X 21 - -#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 -#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 -#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 -#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 - -#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 -#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 -#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 -#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 - -#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 -#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 -#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 -#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 - -#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 -#define EMARCH_ENC_I17_SIGN_SIZE_X 1 -#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 -#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 - -#define X3_OPCODE_INST_WORD_X 3 -#define X3_OPCODE_SIZE_X 4 -#define X3_OPCODE_INST_WORD_POS_X 28 -#define X3_OPCODE_SIGN_VAL_POS_X 0 - -#define X3_I_INST_WORD_X 3 -#define X3_I_SIZE_X 1 -#define X3_I_INST_WORD_POS_X 27 -#define X3_I_SIGN_VAL_POS_X 59 - -#define X3_D_WH_INST_WORD_X 3 -#define X3_D_WH_SIZE_X 3 -#define X3_D_WH_INST_WORD_POS_X 24 -#define X3_D_WH_SIGN_VAL_POS_X 0 - -#define X3_IMM20_INST_WORD_X 3 -#define X3_IMM20_SIZE_X 20 -#define X3_IMM20_INST_WORD_POS_X 4 -#define X3_IMM20_SIGN_VAL_POS_X 0 - -#define X3_IMM39_1_INST_WORD_X 2 -#define X3_IMM39_1_SIZE_X 23 -#define X3_IMM39_1_INST_WORD_POS_X 0 -#define X3_IMM39_1_SIGN_VAL_POS_X 36 - -#define X3_IMM39_2_INST_WORD_X 1 -#define X3_IMM39_2_SIZE_X 16 -#define X3_IMM39_2_INST_WORD_POS_X 16 -#define X3_IMM39_2_SIGN_VAL_POS_X 20 - -#define X3_P_INST_WORD_X 3 -#define X3_P_SIZE_X 4 -#define X3_P_INST_WORD_POS_X 0 -#define X3_P_SIGN_VAL_POS_X 0 - -#define X3_TMPLT_INST_WORD_X 0 -#define X3_TMPLT_SIZE_X 4 -#define X3_TMPLT_INST_WORD_POS_X 0 -#define X3_TMPLT_SIGN_VAL_POS_X 0 - -#define X3_BTYPE_QP_INST_WORD_X 2 -#define X3_BTYPE_QP_SIZE_X 9 -#define X3_BTYPE_QP_INST_WORD_POS_X 23 -#define X3_BTYPE_QP_INST_VAL_POS_X 0 - -#define X3_EMPTY_INST_WORD_X 1 -#define X3_EMPTY_SIZE_X 2 -#define X3_EMPTY_INST_WORD_POS_X 14 -#define X3_EMPTY_INST_VAL_POS_X 0 - - typedef struct _IMAGE_LINENUMBER { - union { - DWORD SymbolTableIndex; - DWORD VirtualAddress; - } Type; - WORD Linenumber; - } IMAGE_LINENUMBER; - typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER; - -#define IMAGE_SIZEOF_LINENUMBER 6 - -#include "poppack.h" - - typedef struct _IMAGE_BASE_RELOCATION { - DWORD VirtualAddress; - DWORD SizeOfBlock; - - } IMAGE_BASE_RELOCATION; - typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 -#define IMAGE_REL_BASED_IA64_IMM64 9 -#define IMAGE_REL_BASED_DIR64 10 - -#define IMAGE_ARCHIVE_START_SIZE 8 -#define IMAGE_ARCHIVE_START "!\n" -#define IMAGE_ARCHIVE_END "`\n" -#define IMAGE_ARCHIVE_PAD "\n" -#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " -#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " - - typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { - BYTE Name[16]; - BYTE Date[12]; - BYTE UserID[6]; - BYTE GroupID[6]; - BYTE Mode[8]; - BYTE Size[10]; - BYTE EndHeader[2]; - } IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER; - -#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 - - typedef struct _IMAGE_EXPORT_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; - DWORD AddressOfNames; - DWORD AddressOfNameOrdinals; - } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; - - typedef struct _IMAGE_IMPORT_BY_NAME { - WORD Hint; - BYTE Name[1]; - } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; - -#include "pshpack8.h" - - typedef struct _IMAGE_THUNK_DATA64 { - union { - ULONGLONG ForwarderString; - ULONGLONG Function; - ULONGLONG Ordinal; - ULONGLONG AddressOfData; - } u1; - } IMAGE_THUNK_DATA64; - typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; - -#include "poppack.h" - - typedef struct _IMAGE_THUNK_DATA32 { - union { - DWORD ForwarderString; - DWORD Function; - DWORD Ordinal; - DWORD AddressOfData; - } u1; - } IMAGE_THUNK_DATA32; - typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; - -#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull -#define IMAGE_ORDINAL_FLAG32 0x80000000 -#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffffull) -#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) -#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64)!=0) -#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32)!=0) - - typedef VOID - (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle,DWORD Reason,PVOID Reserved); - - typedef struct _IMAGE_TLS_DIRECTORY64 { - ULONGLONG StartAddressOfRawData; - ULONGLONG EndAddressOfRawData; - ULONGLONG AddressOfIndex; - ULONGLONG AddressOfCallBacks; - DWORD SizeOfZeroFill; - DWORD Characteristics; - } IMAGE_TLS_DIRECTORY64; - typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; - - typedef struct _IMAGE_TLS_DIRECTORY32 { - DWORD StartAddressOfRawData; - DWORD EndAddressOfRawData; - DWORD AddressOfIndex; - DWORD AddressOfCallBacks; - DWORD SizeOfZeroFill; - DWORD Characteristics; - } IMAGE_TLS_DIRECTORY32; - typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; - -#ifdef _WIN64 -#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 -#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal) - typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; - typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal) - typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; - typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; -#else -#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 -#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal) - typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; - typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal) - typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; - typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; -#endif - - typedef struct _IMAGE_IMPORT_DESCRIPTOR { - union { - DWORD Characteristics; - DWORD OriginalFirstThunk; - }; - DWORD TimeDateStamp; - - DWORD ForwarderChain; - DWORD Name; - DWORD FirstThunk; - } IMAGE_IMPORT_DESCRIPTOR; - typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; - - typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { - DWORD TimeDateStamp; - WORD OffsetModuleName; - WORD NumberOfModuleForwarderRefs; - } IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR; - - typedef struct _IMAGE_BOUND_FORWARDER_REF { - DWORD TimeDateStamp; - WORD OffsetModuleName; - WORD Reserved; - } IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF; - - typedef struct _IMAGE_RESOURCE_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - WORD NumberOfNamedEntries; - WORD NumberOfIdEntries; - } IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; - -#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 -#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 - - typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { - union { - struct { - DWORD NameOffset:31; - DWORD NameIsString:1; - }; - DWORD Name; - WORD Id; - }; - union { - DWORD OffsetToData; - struct { - DWORD OffsetToDirectory:31; - DWORD DataIsDirectory:1; - }; - }; - } IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; - - typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { - WORD Length; - CHAR NameString[1]; - } IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; - - typedef struct _IMAGE_RESOURCE_DIR_STRING_U { - WORD Length; - WCHAR NameString[1]; - } IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; - - typedef struct _IMAGE_RESOURCE_DATA_ENTRY { - DWORD OffsetToData; - DWORD Size; - DWORD CodePage; - DWORD Reserved; - } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; - - typedef struct { - DWORD Size; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD GlobalFlagsClear; - DWORD GlobalFlagsSet; - DWORD CriticalSectionDefaultTimeout; - DWORD DeCommitFreeBlockThreshold; - DWORD DeCommitTotalFreeThreshold; - DWORD LockPrefixTable; - DWORD MaximumAllocationSize; - DWORD VirtualMemoryThreshold; - DWORD ProcessHeapFlags; - DWORD ProcessAffinityMask; - WORD CSDVersion; - WORD Reserved1; - DWORD EditList; - DWORD SecurityCookie; - DWORD SEHandlerTable; - DWORD SEHandlerCount; - } IMAGE_LOAD_CONFIG_DIRECTORY32,*PIMAGE_LOAD_CONFIG_DIRECTORY32; - - typedef struct { - DWORD Size; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD GlobalFlagsClear; - DWORD GlobalFlagsSet; - DWORD CriticalSectionDefaultTimeout; - ULONGLONG DeCommitFreeBlockThreshold; - ULONGLONG DeCommitTotalFreeThreshold; - ULONGLONG LockPrefixTable; - ULONGLONG MaximumAllocationSize; - ULONGLONG VirtualMemoryThreshold; - ULONGLONG ProcessAffinityMask; - DWORD ProcessHeapFlags; - WORD CSDVersion; - WORD Reserved1; - ULONGLONG EditList; - ULONGLONG SecurityCookie; - ULONGLONG SEHandlerTable; - ULONGLONG SEHandlerCount; - } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64; - -#ifdef _WIN64 - typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; - typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; -#else - typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; - typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; -#endif - - typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY { - DWORD FuncStart; - DWORD PrologLen : 8; - DWORD FuncLen : 22; - DWORD ThirtyTwoBit : 1; - DWORD ExceptionFlag : 1; - } IMAGE_CE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { - ULONGLONG BeginAddress; - ULONGLONG EndAddress; - ULONGLONG ExceptionHandler; - ULONGLONG HandlerData; - ULONGLONG PrologEndAddress; - } IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { - DWORD BeginAddress; - DWORD EndAddress; - DWORD ExceptionHandler; - DWORD HandlerData; - DWORD PrologEndAddress; - } IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindInfoAddress; - } _IMAGE_RUNTIME_FUNCTION_ENTRY,*_PIMAGE_RUNTIME_FUNCTION_ENTRY; - - typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY; - typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY; - - typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY; - typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_DEBUG_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Type; - DWORD SizeOfData; - DWORD AddressOfRawData; - DWORD PointerToRawData; - } IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY; - -#define IMAGE_DEBUG_TYPE_UNKNOWN 0 -#define IMAGE_DEBUG_TYPE_COFF 1 -#define IMAGE_DEBUG_TYPE_CODEVIEW 2 -#define IMAGE_DEBUG_TYPE_FPO 3 -#define IMAGE_DEBUG_TYPE_MISC 4 -#define IMAGE_DEBUG_TYPE_EXCEPTION 5 -#define IMAGE_DEBUG_TYPE_FIXUP 6 -#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 -#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 -#define IMAGE_DEBUG_TYPE_BORLAND 9 -#define IMAGE_DEBUG_TYPE_RESERVED10 10 -#define IMAGE_DEBUG_TYPE_CLSID 11 - - typedef struct _IMAGE_COFF_SYMBOLS_HEADER { - DWORD NumberOfSymbols; - DWORD LvaToFirstSymbol; - DWORD NumberOfLinenumbers; - DWORD LvaToFirstLinenumber; - DWORD RvaToFirstByteOfCode; - DWORD RvaToLastByteOfCode; - DWORD RvaToFirstByteOfData; - DWORD RvaToLastByteOfData; - } IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER; - -#define FRAME_FPO 0 -#define FRAME_TRAP 1 -#define FRAME_TSS 2 -#define FRAME_NONFPO 3 - - typedef struct _FPO_DATA { - DWORD ulOffStart; - DWORD cbProcSize; - DWORD cdwLocals; - WORD cdwParams; - WORD cbProlog : 8; - WORD cbRegs : 3; - WORD fHasSEH : 1; - WORD fUseBP : 1; - WORD reserved : 1; - WORD cbFrame : 2; - } FPO_DATA,*PFPO_DATA; -#define SIZEOF_RFPO_DATA 16 - -#define IMAGE_DEBUG_MISC_EXENAME 1 - - typedef struct _IMAGE_DEBUG_MISC { - DWORD DataType; - DWORD Length; - BOOLEAN Unicode; - BYTE Reserved[3]; - BYTE Data[1]; - } IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC; - - typedef struct _IMAGE_FUNCTION_ENTRY { - DWORD StartingAddress; - DWORD EndingAddress; - DWORD EndOfPrologue; - } IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY; - - typedef struct _IMAGE_FUNCTION_ENTRY64 { - ULONGLONG StartingAddress; - ULONGLONG EndingAddress; - union { - ULONGLONG EndOfPrologue; - ULONGLONG UnwindInfoAddress; - }; - } IMAGE_FUNCTION_ENTRY64,*PIMAGE_FUNCTION_ENTRY64; - - typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { - WORD Signature; - WORD Flags; - WORD Machine; - WORD Characteristics; - DWORD TimeDateStamp; - DWORD CheckSum; - DWORD ImageBase; - DWORD SizeOfImage; - DWORD NumberOfSections; - DWORD ExportedNamesSize; - DWORD DebugDirectorySize; - DWORD SectionAlignment; - DWORD Reserved[2]; - } IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; - - typedef struct _NON_PAGED_DEBUG_INFO { - WORD Signature; - WORD Flags; - DWORD Size; - WORD Machine; - WORD Characteristics; - DWORD TimeDateStamp; - DWORD CheckSum; - DWORD SizeOfImage; - ULONGLONG ImageBase; - - } NON_PAGED_DEBUG_INFO,*PNON_PAGED_DEBUG_INFO; - -#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 -#define NON_PAGED_DEBUG_SIGNATURE 0x494E - -#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000 -#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 - - typedef struct _ImageArchitectureHeader { - unsigned int AmaskValue: 1; - int Adummy1 :7; - unsigned int AmaskShift: 8; - int Adummy2 :16; - DWORD FirstEntryRVA; - } IMAGE_ARCHITECTURE_HEADER,*PIMAGE_ARCHITECTURE_HEADER; - - typedef struct _ImageArchitectureEntry { - DWORD FixupInstRVA; - DWORD NewInst; - } IMAGE_ARCHITECTURE_ENTRY,*PIMAGE_ARCHITECTURE_ENTRY; - -#include "poppack.h" - -#define IMPORT_OBJECT_HDR_SIG2 0xffff - - typedef struct IMPORT_OBJECT_HEADER { - WORD Sig1; - WORD Sig2; - WORD Version; - WORD Machine; - DWORD TimeDateStamp; - DWORD SizeOfData; - union { - WORD Ordinal; - WORD Hint; - }; - WORD Type : 2; - WORD NameType : 3; - WORD Reserved : 11; - } IMPORT_OBJECT_HEADER; - - typedef enum IMPORT_OBJECT_TYPE { - IMPORT_OBJECT_CODE = 0,IMPORT_OBJECT_DATA = 1,IMPORT_OBJECT_CONST = 2 - } IMPORT_OBJECT_TYPE; - - typedef enum IMPORT_OBJECT_NAME_TYPE { - IMPORT_OBJECT_ORDINAL = 0,IMPORT_OBJECT_NAME = 1,IMPORT_OBJECT_NAME_NO_PREFIX = 2,IMPORT_OBJECT_NAME_UNDECORATE = 3 - } IMPORT_OBJECT_NAME_TYPE; - -#ifndef __IMAGE_COR20_HEADER_DEFINED__ -#define __IMAGE_COR20_HEADER_DEFINED__ - typedef enum ReplacesCorHdrNumericDefines { - COMIMAGE_FLAGS_ILONLY =0x00000001,COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, - COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,COR_VERSION_MAJOR_V2 =2, - COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,COR_VERSION_MINOR =0,COR_DELETED_NAME_LENGTH =8,COR_VTABLEGAP_NAME_LENGTH =8, - NATIVE_TYPE_MAX_CB =1,COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,IMAGE_COR_MIH_METHODRVA =0x01,IMAGE_COR_MIH_EHRVA =0x02, - IMAGE_COR_MIH_BASICBLOCK =0x08,COR_VTABLE_32BIT =0x01,COR_VTABLE_64BIT =0x02,COR_VTABLE_FROM_UNMANAGED =0x04, - COR_VTABLE_CALL_MOST_DERIVED =0x10,IMAGE_COR_EATJ_THUNK_SIZE =32,MAX_CLASS_NAME =1024,MAX_PACKAGE_NAME =1024 - } ReplacesCorHdrNumericDefines; - - typedef struct IMAGE_COR20_HEADER { - DWORD cb; - WORD MajorRuntimeVersion; - WORD MinorRuntimeVersion; - IMAGE_DATA_DIRECTORY MetaData; - DWORD Flags; - DWORD EntryPointToken; - IMAGE_DATA_DIRECTORY Resources; - IMAGE_DATA_DIRECTORY StrongNameSignature; - IMAGE_DATA_DIRECTORY CodeManagerTable; - IMAGE_DATA_DIRECTORY VTableFixups; - IMAGE_DATA_DIRECTORY ExportAddressTableJumps; - IMAGE_DATA_DIRECTORY ManagedNativeHeader; - } IMAGE_COR20_HEADER,*PIMAGE_COR20_HEADER; -#endif - -#if defined (__x86_64) - NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable); - NTSYSAPI VOID NTAPI RtlUnwindEx (PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable); -#endif - -#include - -#ifndef _SLIST_HEADER_ -#define _SLIST_HEADER_ - -#ifdef _WIN64 - typedef struct _SLIST_ENTRY *PSLIST_ENTRY; - typedef DECLSPEC_ALIGN(16) struct _SLIST_ENTRY { - PSLIST_ENTRY Next; - } SLIST_ENTRY; -#else - -#define SLIST_ENTRY SINGLE_LIST_ENTRY -#define _SLIST_ENTRY _SINGLE_LIST_ENTRY -#define PSLIST_ENTRY PSINGLE_LIST_ENTRY -#endif - -#if defined(_WIN64) - - typedef DECLSPEC_ALIGN(16) struct _SLIST_HEADER { - ULONGLONG Alignment; - ULONGLONG Region; - } SLIST_HEADER; - - typedef struct _SLIST_HEADER *PSLIST_HEADER; -#else - - typedef union _SLIST_HEADER { - ULONGLONG Alignment; - struct { - SLIST_ENTRY Next; - WORD Depth; - WORD Sequence; - }; - } SLIST_HEADER,*PSLIST_HEADER; -#endif -#endif - - NTSYSAPI VOID NTAPI RtlInitializeSListHead(PSLIST_HEADER ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlFirstEntrySList(const SLIST_HEADER *ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPopEntrySList(PSLIST_HEADER ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedFlushSList(PSLIST_HEADER ListHead); - NTSYSAPI WORD NTAPI RtlQueryDepthSList(PSLIST_HEADER ListHead); - -#define HEAP_NO_SERIALIZE 0x00000001 -#define HEAP_GROWABLE 0x00000002 -#define HEAP_GENERATE_EXCEPTIONS 0x00000004 -#define HEAP_ZERO_MEMORY 0x00000008 -#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 -#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 -#define HEAP_FREE_CHECKING_ENABLED 0x00000040 -#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 -#define HEAP_CREATE_ALIGN_16 0x00010000 -#define HEAP_CREATE_ENABLE_TRACING 0x00020000 -#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 -#define HEAP_MAXIMUM_TAG 0x0FFF -#define HEAP_PSEUDO_TAG_FLAG 0x8000 -#define HEAP_TAG_SHIFT 18 -#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b) + ((o) << 18))) - - NTSYSAPI VOID NTAPI RtlCaptureContext(PCONTEXT ContextRecord); - -#define IS_TEXT_UNICODE_ASCII16 0x0001 -#define IS_TEXT_UNICODE_REVERSE_ASCII16 0x0010 - -#define IS_TEXT_UNICODE_STATISTICS 0x0002 -#define IS_TEXT_UNICODE_REVERSE_STATISTICS 0x0020 - -#define IS_TEXT_UNICODE_CONTROLS 0x0004 -#define IS_TEXT_UNICODE_REVERSE_CONTROLS 0x0040 - -#define IS_TEXT_UNICODE_SIGNATURE 0x0008 -#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 0x0080 - -#define IS_TEXT_UNICODE_ILLEGAL_CHARS 0x0100 -#define IS_TEXT_UNICODE_ODD_LENGTH 0x0200 -#define IS_TEXT_UNICODE_DBCS_LEADBYTE 0x0400 -#define IS_TEXT_UNICODE_NULL_BYTES 0x1000 - -#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F -#define IS_TEXT_UNICODE_REVERSE_MASK 0x00F0 -#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 0x0F00 -#define IS_TEXT_UNICODE_NOT_ASCII_MASK 0xF000 - -#define COMPRESSION_FORMAT_NONE (0x0000) -#define COMPRESSION_FORMAT_DEFAULT (0x0001) -#define COMPRESSION_FORMAT_LZNT1 (0x0002) -#define COMPRESSION_ENGINE_STANDARD (0x0000) -#define COMPRESSION_ENGINE_MAXIMUM (0x0100) -#define COMPRESSION_ENGINE_HIBER (0x0200) - -#if _DBG_MEMCPY_INLINE_ && !defined(_MEMCPY_INLINE_) && !defined(_CRTBLD) -#define _MEMCPY_INLINE_ - __CRT_INLINE PVOID __cdecl memcpy_inline(void *dst,const void *src,size_t size) { - if(((char *)dst > (char *)src) && ((char *)dst < ((char *)src + size))) { - __debugbreak(); - } - return memcpy(dst,src,size); - } -#define memcpy memcpy_inline -#endif - - NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const VOID *Source1,const VOID *Source2,SIZE_T Length); - -#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) -#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) -#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) -#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) -#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) - - __CRT_INLINE PVOID RtlSecureZeroMemory(PVOID ptr,SIZE_T cnt) { - volatile char *vptr =(volatile char *)ptr; -#ifdef __x86_64 - __stosb((PBYTE)((DWORD64)vptr),0,cnt); -#else - while(cnt) { - *vptr = 0; - vptr++; - cnt--; - } -#endif - return ptr; - } - - typedef struct _MESSAGE_RESOURCE_ENTRY { - WORD Length; - WORD Flags; - BYTE Text[1]; - } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; - -#define MESSAGE_RESOURCE_UNICODE 0x0001 - - typedef struct _MESSAGE_RESOURCE_BLOCK { - DWORD LowId; - DWORD HighId; - DWORD OffsetToEntries; - } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; - - typedef struct _MESSAGE_RESOURCE_DATA { - DWORD NumberOfBlocks; - MESSAGE_RESOURCE_BLOCK Blocks[1]; - } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; - - typedef struct _OSVERSIONINFOA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[128]; - } OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA; - - typedef struct _OSVERSIONINFOW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[128]; - } OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW; - -#ifdef UNICODE - typedef OSVERSIONINFOW OSVERSIONINFO; - typedef POSVERSIONINFOW POSVERSIONINFO; - typedef LPOSVERSIONINFOW LPOSVERSIONINFO; -#else - typedef OSVERSIONINFOA OSVERSIONINFO; - typedef POSVERSIONINFOA POSVERSIONINFO; - typedef LPOSVERSIONINFOA LPOSVERSIONINFO; -#endif - - typedef struct _OSVERSIONINFOEXA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[128]; - WORD wServicePackMajor; - WORD wServicePackMinor; - WORD wSuiteMask; - BYTE wProductType; - BYTE wReserved; - } OSVERSIONINFOEXA,*POSVERSIONINFOEXA,*LPOSVERSIONINFOEXA; - - typedef struct _OSVERSIONINFOEXW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[128]; - WORD wServicePackMajor; - WORD wServicePackMinor; - WORD wSuiteMask; - BYTE wProductType; - BYTE wReserved; - } OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW,RTL_OSVERSIONINFOEXW,*PRTL_OSVERSIONINFOEXW; -#ifdef UNICODE - typedef OSVERSIONINFOEXW OSVERSIONINFOEX; - typedef POSVERSIONINFOEXW POSVERSIONINFOEX; - typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX; -#else - typedef OSVERSIONINFOEXA OSVERSIONINFOEX; - typedef POSVERSIONINFOEXA POSVERSIONINFOEX; - typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX; -#endif - -#define VER_EQUAL 1 -#define VER_GREATER 2 -#define VER_GREATER_EQUAL 3 -#define VER_LESS 4 -#define VER_LESS_EQUAL 5 -#define VER_AND 6 -#define VER_OR 7 - -#define VER_CONDITION_MASK 7 -#define VER_NUM_BITS_PER_CONDITION_MASK 3 - -#define VER_MINORVERSION 0x0000001 -#define VER_MAJORVERSION 0x0000002 -#define VER_BUILDNUMBER 0x0000004 -#define VER_PLATFORMID 0x0000008 -#define VER_SERVICEPACKMINOR 0x0000010 -#define VER_SERVICEPACKMAJOR 0x0000020 -#define VER_SUITENAME 0x0000040 -#define VER_PRODUCT_TYPE 0x0000080 - -#define VER_NT_WORKSTATION 0x0000001 -#define VER_NT_DOMAIN_CONTROLLER 0x0000002 -#define VER_NT_SERVER 0x0000003 - -#define VER_PLATFORM_WIN32s 0 -#define VER_PLATFORM_WIN32_WINDOWS 1 -#define VER_PLATFORM_WIN32_NT 2 - -#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) - - NTSYSAPI ULONGLONG NTAPI VerSetConditionMask(ULONGLONG ConditionMask,DWORD TypeMask,BYTE Condition); - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Spare[2]; - } RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*PRTL_RESOURCE_DEBUG; - -#define RTL_CRITSECT_TYPE 0 -#define RTL_RESOURCE_TYPE 1 - - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; - HANDLE LockSemaphore; - ULONG_PTR SpinCount; - } RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION; - - typedef VOID (NTAPI *RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); - typedef VOID (NTAPI *RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); - typedef VOID (NTAPI *RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK)(PVOID AllocationBase,SIZE_T AllocationSize); - - typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { - PCHAR ThunkName; - PVOID ThunkOldAddress; - PVOID ThunkNewAddress; - } RTL_VERIFIER_THUNK_DESCRIPTOR,*PRTL_VERIFIER_THUNK_DESCRIPTOR; - - typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { - PWCHAR DllName; - DWORD DllFlags; - PVOID DllAddress; - PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; - } RTL_VERIFIER_DLL_DESCRIPTOR,*PRTL_VERIFIER_DLL_DESCRIPTOR; - - typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { - DWORD Length; - PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; - RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; - RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; - PWSTR VerifierImage; - DWORD VerifierFlags; - DWORD VerifierDebug; - PVOID RtlpGetStackTraceAddress; - PVOID RtlpDebugPageHeapCreate; - PVOID RtlpDebugPageHeapDestroy; - RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; - } RTL_VERIFIER_PROVIDER_DESCRIPTOR,*PRTL_VERIFIER_PROVIDER_DESCRIPTOR; - -#define RTL_VRF_FLG_FULL_PAGE_HEAP 0x00000001 -#define RTL_VRF_FLG_RESERVED_DONOTUSE 0x00000002 -#define RTL_VRF_FLG_HANDLE_CHECKS 0x00000004 -#define RTL_VRF_FLG_STACK_CHECKS 0x00000008 -#define RTL_VRF_FLG_APPCOMPAT_CHECKS 0x00000010 -#define RTL_VRF_FLG_TLS_CHECKS 0x00000020 -#define RTL_VRF_FLG_DIRTY_STACKS 0x00000040 -#define RTL_VRF_FLG_RPC_CHECKS 0x00000080 -#define RTL_VRF_FLG_COM_CHECKS 0x00000100 -#define RTL_VRF_FLG_DANGEROUS_APIS 0x00000200 -#define RTL_VRF_FLG_RACE_CHECKS 0x00000400 -#define RTL_VRF_FLG_DEADLOCK_CHECKS 0x00000800 -#define RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS 0x00001000 -#define RTL_VRF_FLG_VIRTUAL_MEM_CHECKS 0x00002000 -#define RTL_VRF_FLG_ENABLE_LOGGING 0x00004000 -#define RTL_VRF_FLG_FAST_FILL_HEAP 0x00008000 -#define RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING 0x00010000 -#define RTL_VRF_FLG_ENABLED_SYSTEM_WIDE 0x00020000 -#define RTL_VRF_FLG_MISCELLANEOUS_CHECKS 0x00020000 -#define RTL_VRF_FLG_LOCK_CHECKS 0x00040000 - -#define APPLICATION_VERIFIER_INTERNAL_ERROR 0x80000000 -#define APPLICATION_VERIFIER_INTERNAL_WARNING 0x40000000 -#define APPLICATION_VERIFIER_NO_BREAK 0x20000000 -#define APPLICATION_VERIFIER_CONTINUABLE_BREAK 0x10000000 - -#define APPLICATION_VERIFIER_UNKNOWN_ERROR 0x0001 -#define APPLICATION_VERIFIER_ACCESS_VIOLATION 0x0002 -#define APPLICATION_VERIFIER_UNSYNCHRONIZED_ACCESS 0x0003 -#define APPLICATION_VERIFIER_EXTREME_SIZE_REQUEST 0x0004 -#define APPLICATION_VERIFIER_BAD_HEAP_HANDLE 0x0005 -#define APPLICATION_VERIFIER_SWITCHED_HEAP_HANDLE 0x0006 -#define APPLICATION_VERIFIER_DOUBLE_FREE 0x0007 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK 0x0008 -#define APPLICATION_VERIFIER_DESTROY_PROCESS_HEAP 0x0009 -#define APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION 0x000A -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_HEADER 0x000B -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING 0x000C -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_HEADER 0x000D -#define APPLICATION_VERIFIER_CORRUPTED_FREED_HEAP_BLOCK 0x000E -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_SUFFIX 0x000F -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_START_STAMP 0x0010 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_END_STAMP 0x0011 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_PREFIX 0x0012 -#define APPLICATION_VERIFIER_FIRST_CHANCE_ACCESS_VIOLATION 0x0013 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_LIST 0x0014 - -#define APPLICATION_VERIFIER_TERMINATE_THREAD_CALL 0x0100 -#define APPLICATION_VERIFIER_STACK_OVERFLOW 0x0101 -#define APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL 0x0102 - -#define APPLICATION_VERIFIER_EXIT_THREAD_OWNS_LOCK 0x0200 -#define APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL 0x0201 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP 0x0202 -#define APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE 0x0203 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY 0x0204 -#define APPLICATION_VERIFIER_LOCK_CORRUPTED 0x0205 -#define APPLICATION_VERIFIER_LOCK_INVALID_OWNER 0x0206 -#define APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT 0x0207 -#define APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT 0x0208 -#define APPLICATION_VERIFIER_LOCK_OVER_RELEASED 0x0209 -#define APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED 0x0210 -#define APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED 0x0211 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_VMEM 0x0212 -#define APPLICATION_VERIFIER_LOCK_IN_UNMAPPED_MEM 0x0213 -#define APPLICATION_VERIFIER_THREAD_NOT_LOCK_OWNER 0x0214 - -#define APPLICATION_VERIFIER_INVALID_HANDLE 0x0300 -#define APPLICATION_VERIFIER_INVALID_TLS_VALUE 0x0301 -#define APPLICATION_VERIFIER_INCORRECT_WAIT_CALL 0x0302 -#define APPLICATION_VERIFIER_NULL_HANDLE 0x0303 -#define APPLICATION_VERIFIER_WAIT_IN_DLLMAIN 0x0304 - -#define APPLICATION_VERIFIER_COM_ERROR 0x0400 -#define APPLICATION_VERIFIER_COM_API_IN_DLLMAIN 0x0401 -#define APPLICATION_VERIFIER_COM_UNHANDLED_EXCEPTION 0x0402 -#define APPLICATION_VERIFIER_COM_UNBALANCED_COINIT 0x0403 -#define APPLICATION_VERIFIER_COM_UNBALANCED_OLEINIT 0x0404 -#define APPLICATION_VERIFIER_COM_UNBALANCED_SWC 0x0405 -#define APPLICATION_VERIFIER_COM_NULL_DACL 0x0406 -#define APPLICATION_VERIFIER_COM_UNSAFE_IMPERSONATION 0x0407 -#define APPLICATION_VERIFIER_COM_SMUGGLED_WRAPPER 0x0408 -#define APPLICATION_VERIFIER_COM_SMUGGLED_PROXY 0x0409 -#define APPLICATION_VERIFIER_COM_CF_SUCCESS_WITH_NULL 0x040A -#define APPLICATION_VERIFIER_COM_GCO_SUCCESS_WITH_NULL 0x040B -#define APPLICATION_VERIFIER_COM_OBJECT_IN_FREED_MEMORY 0x040C -#define APPLICATION_VERIFIER_COM_OBJECT_IN_UNLOADED_DLL 0x040D -#define APPLICATION_VERIFIER_COM_VTBL_IN_FREED_MEMORY 0x040E -#define APPLICATION_VERIFIER_COM_VTBL_IN_UNLOADED_DLL 0x040F -#define APPLICATION_VERIFIER_COM_HOLDING_LOCKS_ON_CALL 0x0410 - -#define APPLICATION_VERIFIER_RPC_ERROR 0x0500 - -#define APPLICATION_VERIFIER_INVALID_FREEMEM 0x0600 -#define APPLICATION_VERIFIER_INVALID_ALLOCMEM 0x0601 -#define APPLICATION_VERIFIER_INVALID_MAPVIEW 0x0602 -#define APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS 0x0603 -#define APPLICATION_VERIFIER_PROBE_FREE_MEM 0x0604 -#define APPLICATION_VERIFIER_PROBE_GUARD_PAGE 0x0605 -#define APPLICATION_VERIFIER_PROBE_NULL 0x0606 -#define APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE 0x0607 -#define APPLICATION_VERIFIER_SIZE_HEAP_UNEXPECTED_EXCEPTION 0x0618 - -#define VERIFIER_STOP(Code,Msg,P1,S1,P2,S2,P3,S3,P4,S4) { RtlApplicationVerifierStop ((Code),(Msg),(ULONG_PTR)(P1),(S1),(ULONG_PTR)(P2),(S2),(ULONG_PTR)(P3),(S3),(ULONG_PTR)(P4),(S4)); } - - VOID NTAPI RtlApplicationVerifierStop(ULONG_PTR Code,PSTR Message,ULONG_PTR Param1,PSTR Description1,ULONG_PTR Param2,PSTR Description2,ULONG_PTR Param3,PSTR Description3,ULONG_PTR Param4,PSTR Description4); - - typedef LONG (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo); -#define SEF_DACL_AUTO_INHERIT 0x01 -#define SEF_SACL_AUTO_INHERIT 0x02 -#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 0x04 -#define SEF_AVOID_PRIVILEGE_CHECK 0x08 -#define SEF_AVOID_OWNER_CHECK 0x10 -#define SEF_DEFAULT_OWNER_FROM_PARENT 0x20 -#define SEF_DEFAULT_GROUP_FROM_PARENT 0x40 - - typedef enum _HEAP_INFORMATION_CLASS { - HeapCompatibilityInformation - } HEAP_INFORMATION_CLASS; - - NTSYSAPI DWORD NTAPI RtlSetHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); - NTSYSAPI DWORD NTAPI RtlQueryHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); - DWORD NTAPI RtlMultipleAllocateHeap(PVOID HeapHandle,DWORD Flags,SIZE_T Size,DWORD Count,PVOID *Array); - DWORD NTAPI RtlMultipleFreeHeap(PVOID HeapHandle,DWORD Flags,DWORD Count,PVOID *Array); - -#define WT_EXECUTEDEFAULT 0x00000000 -#define WT_EXECUTEINIOTHREAD 0x00000001 -#define WT_EXECUTEINUITHREAD 0x00000002 -#define WT_EXECUTEINWAITTHREAD 0x00000004 -#define WT_EXECUTEONLYONCE 0x00000008 -#define WT_EXECUTEINTIMERTHREAD 0x00000020 -#define WT_EXECUTELONGFUNCTION 0x00000010 -#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040 -#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080 -#define WT_TRANSFER_IMPERSONATION 0x00000100 -#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags) |= (Limit)<<16) - typedef VOID (NTAPI *WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN); - typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID); - typedef VOID (NTAPI *APC_CALLBACK_FUNCTION)(DWORD ,PVOID,PVOID); - typedef - VOID - (NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); -#define WT_EXECUTEINLONGTHREAD 0x00000010 -#define WT_EXECUTEDELETEWAIT 0x00000008 - - typedef enum _ACTIVATION_CONTEXT_INFO_CLASS { - ActivationContextBasicInformation = 1,ActivationContextDetailedInformation = 2,AssemblyDetailedInformationInActivationContext = 3,FileInformationInAssemblyOfAssemblyInActivationContext = 4,MaxActivationContextInfoClass,AssemblyDetailedInformationInActivationContxt = 3,FileInformationInAssemblyOfAssemblyInActivationContxt = 4 - } ACTIVATION_CONTEXT_INFO_CLASS; - -#define ACTIVATIONCONTEXTINFOCLASS ACTIVATION_CONTEXT_INFO_CLASS - - typedef struct _ACTIVATION_CONTEXT_QUERY_INDEX { - DWORD ulAssemblyIndex; - DWORD ulFileIndexInAssembly; - } ACTIVATION_CONTEXT_QUERY_INDEX,*PACTIVATION_CONTEXT_QUERY_INDEX; - - typedef const struct _ACTIVATION_CONTEXT_QUERY_INDEX *PCACTIVATION_CONTEXT_QUERY_INDEX; - -#define ACTIVATION_CONTEXT_PATH_TYPE_NONE (1) -#define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE (2) -#define ACTIVATION_CONTEXT_PATH_TYPE_URL (3) -#define ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF (4) - - typedef struct _ASSEMBLY_FILE_DETAILED_INFORMATION { - DWORD ulFlags; - DWORD ulFilenameLength; - DWORD ulPathLength; - - PCWSTR lpFileName; - PCWSTR lpFilePath; - } ASSEMBLY_FILE_DETAILED_INFORMATION,*PASSEMBLY_FILE_DETAILED_INFORMATION; - typedef const ASSEMBLY_FILE_DETAILED_INFORMATION *PCASSEMBLY_FILE_DETAILED_INFORMATION; - -#define _ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION _ASSEMBLY_FILE_DETAILED_INFORMATION -#define ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION ASSEMBLY_FILE_DETAILED_INFORMATION -#define PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PASSEMBLY_FILE_DETAILED_INFORMATION -#define PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PCASSEMBLY_FILE_DETAILED_INFORMATION - - typedef struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { - DWORD ulFlags; - DWORD ulEncodedAssemblyIdentityLength; - DWORD ulManifestPathType; - DWORD ulManifestPathLength; - LARGE_INTEGER liManifestLastWriteTime; - DWORD ulPolicyPathType; - DWORD ulPolicyPathLength; - LARGE_INTEGER liPolicyLastWriteTime; - DWORD ulMetadataSatelliteRosterIndex; - DWORD ulManifestVersionMajor; - DWORD ulManifestVersionMinor; - DWORD ulPolicyVersionMajor; - DWORD ulPolicyVersionMinor; - DWORD ulAssemblyDirectoryNameLength; - PCWSTR lpAssemblyEncodedAssemblyIdentity; - PCWSTR lpAssemblyManifestPath; - PCWSTR lpAssemblyPolicyPath; - PCWSTR lpAssemblyDirectoryName; - DWORD ulFileCount; - } ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; - - typedef struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION { - DWORD dwFlags; - DWORD ulFormatVersion; - DWORD ulAssemblyCount; - DWORD ulRootManifestPathType; - DWORD ulRootManifestPathChars; - DWORD ulRootConfigurationPathType; - DWORD ulRootConfigurationPathChars; - DWORD ulAppDirPathType; - DWORD ulAppDirPathChars; - PCWSTR lpRootManifestPath; - PCWSTR lpRootConfigurationPath; - PCWSTR lpAppDirPath; - } ACTIVATION_CONTEXT_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_DETAILED_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_DETAILED_INFORMATION; - -#define DLL_PROCESS_ATTACH 1 -#define DLL_THREAD_ATTACH 2 -#define DLL_THREAD_DETACH 3 -#define DLL_PROCESS_DETACH 0 -#define DLL_PROCESS_VERIFIER 4 - -#define EVENTLOG_SEQUENTIAL_READ 0x0001 -#define EVENTLOG_SEEK_READ 0x0002 -#define EVENTLOG_FORWARDS_READ 0x0004 -#define EVENTLOG_BACKWARDS_READ 0x0008 - -#define EVENTLOG_SUCCESS 0x0000 -#define EVENTLOG_ERROR_TYPE 0x0001 -#define EVENTLOG_WARNING_TYPE 0x0002 -#define EVENTLOG_INFORMATION_TYPE 0x0004 -#define EVENTLOG_AUDIT_SUCCESS 0x0008 -#define EVENTLOG_AUDIT_FAILURE 0x0010 - -#define EVENTLOG_START_PAIRED_EVENT 0x0001 -#define EVENTLOG_END_PAIRED_EVENT 0x0002 -#define EVENTLOG_END_ALL_PAIRED_EVENTS 0x0004 -#define EVENTLOG_PAIRED_EVENT_ACTIVE 0x0008 -#define EVENTLOG_PAIRED_EVENT_INACTIVE 0x0010 - - typedef struct _EVENTLOGRECORD { - DWORD Length; - DWORD Reserved; - DWORD RecordNumber; - DWORD TimeGenerated; - DWORD TimeWritten; - DWORD EventID; - WORD EventType; - WORD NumStrings; - WORD EventCategory; - WORD ReservedFlags; - DWORD ClosingRecordNumber; - DWORD StringOffset; - DWORD UserSidLength; - DWORD UserSidOffset; - DWORD DataLength; - DWORD DataOffset; - } EVENTLOGRECORD,*PEVENTLOGRECORD; - -#define MAXLOGICALLOGNAMESIZE 256 - - typedef struct _EVENTSFORLOGFILE{ - DWORD ulSize; - WCHAR szLogicalLogFile[MAXLOGICALLOGNAMESIZE]; - DWORD ulNumRecords; - EVENTLOGRECORD pEventLogRecords[]; - } EVENTSFORLOGFILE,*PEVENTSFORLOGFILE; - - typedef struct _PACKEDEVENTINFO{ - DWORD ulSize; - DWORD ulNumEventsForLogFile; - DWORD ulOffsets[]; - } PACKEDEVENTINFO,*PPACKEDEVENTINFO; - -#define KEY_QUERY_VALUE (0x0001) -#define KEY_SET_VALUE (0x0002) -#define KEY_CREATE_SUB_KEY (0x0004) -#define KEY_ENUMERATE_SUB_KEYS (0x0008) -#define KEY_NOTIFY (0x0010) -#define KEY_CREATE_LINK (0x0020) -#define KEY_WOW64_32KEY (0x0200) -#define KEY_WOW64_64KEY (0x0100) -#define KEY_WOW64_RES (0x0300) - -#define KEY_READ ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE)) -#define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) -#define KEY_EXECUTE ((KEY_READ) & (~SYNCHRONIZE)) -#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE)) -#define REG_OPTION_RESERVED (0x00000000L) - -#define REG_OPTION_NON_VOLATILE (0x00000000L) -#define REG_OPTION_VOLATILE (0x00000001L) -#define REG_OPTION_CREATE_LINK (0x00000002L) -#define REG_OPTION_BACKUP_RESTORE (0x00000004L) -#define REG_OPTION_OPEN_LINK (0x00000008L) -#define REG_LEGAL_OPTION (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK) -#define REG_CREATED_NEW_KEY (0x00000001L) -#define REG_OPENED_EXISTING_KEY (0x00000002L) -#define REG_STANDARD_FORMAT 1 -#define REG_LATEST_FORMAT 2 -#define REG_NO_COMPRESSION 4 -#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) -#define REG_REFRESH_HIVE (0x00000002L) -#define REG_NO_LAZY_FLUSH (0x00000004L) -#define REG_FORCE_RESTORE (0x00000008L) -#define REG_FORCE_UNLOAD 1 - -#define REG_NOTIFY_CHANGE_NAME (0x00000001L) -#define REG_NOTIFY_CHANGE_ATTRIBUTES (0x00000002L) -#define REG_NOTIFY_CHANGE_LAST_SET (0x00000004L) -#define REG_NOTIFY_CHANGE_SECURITY (0x00000008L) - -#define REG_LEGAL_CHANGE_FILTER (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY) - -#define REG_NONE (0) -#define REG_SZ (1) -#define REG_EXPAND_SZ (2) - -#define REG_BINARY (3) -#define REG_DWORD (4) -#define REG_DWORD_LITTLE_ENDIAN (4) -#define REG_DWORD_BIG_ENDIAN (5) -#define REG_LINK (6) -#define REG_MULTI_SZ (7) -#define REG_RESOURCE_LIST (8) -#define REG_FULL_RESOURCE_DESCRIPTOR (9) -#define REG_RESOURCE_REQUIREMENTS_LIST (10) -#define REG_QWORD (11) -#define REG_QWORD_LITTLE_ENDIAN (11) - -#define SERVICE_KERNEL_DRIVER 0x00000001 -#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 -#define SERVICE_ADAPTER 0x00000004 -#define SERVICE_RECOGNIZER_DRIVER 0x00000008 - -#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER) - -#define SERVICE_WIN32_OWN_PROCESS 0x00000010 -#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 -#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) - -#define SERVICE_INTERACTIVE_PROCESS 0x00000100 - -#define SERVICE_TYPE_ALL (SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS) - -#define SERVICE_BOOT_START 0x00000000 -#define SERVICE_SYSTEM_START 0x00000001 -#define SERVICE_AUTO_START 0x00000002 -#define SERVICE_DEMAND_START 0x00000003 -#define SERVICE_DISABLED 0x00000004 - -#define SERVICE_ERROR_IGNORE 0x00000000 -#define SERVICE_ERROR_NORMAL 0x00000001 -#define SERVICE_ERROR_SEVERE 0x00000002 -#define SERVICE_ERROR_CRITICAL 0x00000003 - - typedef enum _CM_SERVICE_NODE_TYPE { - DriverType = SERVICE_KERNEL_DRIVER,FileSystemType = SERVICE_FILE_SYSTEM_DRIVER,Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, - Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS,AdapterType = SERVICE_ADAPTER,RecognizerType = SERVICE_RECOGNIZER_DRIVER - } SERVICE_NODE_TYPE; - - typedef enum _CM_SERVICE_LOAD_TYPE { - BootLoad = SERVICE_BOOT_START,SystemLoad = SERVICE_SYSTEM_START,AutoLoad = SERVICE_AUTO_START,DemandLoad = SERVICE_DEMAND_START, - DisableLoad = SERVICE_DISABLED - } SERVICE_LOAD_TYPE; - - typedef enum _CM_ERROR_CONTROL_TYPE { - IgnoreError = SERVICE_ERROR_IGNORE,NormalError = SERVICE_ERROR_NORMAL,SevereError = SERVICE_ERROR_SEVERE,CriticalError = SERVICE_ERROR_CRITICAL - } SERVICE_ERROR_TYPE; - -#define TAPE_ERASE_SHORT 0L -#define TAPE_ERASE_LONG 1L - - typedef struct _TAPE_ERASE { - DWORD Type; - BOOLEAN Immediate; - } TAPE_ERASE,*PTAPE_ERASE; - -#define TAPE_LOAD 0L -#define TAPE_UNLOAD 1L -#define TAPE_TENSION 2L -#define TAPE_LOCK 3L -#define TAPE_UNLOCK 4L -#define TAPE_FORMAT 5L - - typedef struct _TAPE_PREPARE { - DWORD Operation; - BOOLEAN Immediate; - } TAPE_PREPARE,*PTAPE_PREPARE; - -#define TAPE_SETMARKS 0L -#define TAPE_FILEMARKS 1L -#define TAPE_SHORT_FILEMARKS 2L -#define TAPE_LONG_FILEMARKS 3L - - typedef struct _TAPE_WRITE_MARKS { - DWORD Type; - DWORD Count; - BOOLEAN Immediate; - } TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS; - -#define TAPE_ABSOLUTE_POSITION 0L -#define TAPE_LOGICAL_POSITION 1L -#define TAPE_PSEUDO_LOGICAL_POSITION 2L - - typedef struct _TAPE_GET_POSITION { - DWORD Type; - DWORD Partition; - LARGE_INTEGER Offset; - } TAPE_GET_POSITION,*PTAPE_GET_POSITION; - -#define TAPE_REWIND 0L -#define TAPE_ABSOLUTE_BLOCK 1L -#define TAPE_LOGICAL_BLOCK 2L -#define TAPE_PSEUDO_LOGICAL_BLOCK 3L -#define TAPE_SPACE_END_OF_DATA 4L -#define TAPE_SPACE_RELATIVE_BLOCKS 5L -#define TAPE_SPACE_FILEMARKS 6L -#define TAPE_SPACE_SEQUENTIAL_FMKS 7L -#define TAPE_SPACE_SETMARKS 8L -#define TAPE_SPACE_SEQUENTIAL_SMKS 9L - - typedef struct _TAPE_SET_POSITION { - DWORD Method; - DWORD Partition; - LARGE_INTEGER Offset; - BOOLEAN Immediate; - } TAPE_SET_POSITION,*PTAPE_SET_POSITION; - -#define TAPE_DRIVE_FIXED 0x00000001 -#define TAPE_DRIVE_SELECT 0x00000002 -#define TAPE_DRIVE_INITIATOR 0x00000004 - -#define TAPE_DRIVE_ERASE_SHORT 0x00000010 -#define TAPE_DRIVE_ERASE_LONG 0x00000020 -#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 -#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 - -#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 -#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 -#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 -#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 - -#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 -#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 - -#define TAPE_DRIVE_ECC 0x00010000 -#define TAPE_DRIVE_COMPRESSION 0x00020000 -#define TAPE_DRIVE_PADDING 0x00040000 -#define TAPE_DRIVE_REPORT_SMKS 0x00080000 - -#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 -#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 -#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 - -#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 -#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 -#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 - -#define TAPE_DRIVE_RESERVED_BIT 0x80000000 - -#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 -#define TAPE_DRIVE_TENSION 0x80000002 -#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 -#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 - -#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 -#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 -#define TAPE_DRIVE_TENSION_IMMED 0x80000040 -#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 - -#define TAPE_DRIVE_SET_ECC 0x80000100 -#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 -#define TAPE_DRIVE_SET_PADDING 0x80000400 -#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 - -#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 -#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 -#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 -#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 - -#define TAPE_DRIVE_END_OF_DATA 0x80010000 -#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 -#define TAPE_DRIVE_FILEMARKS 0x80040000 -#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 - -#define TAPE_DRIVE_SETMARKS 0x80100000 -#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 -#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 -#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 - -#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 -#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 -#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 -#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 - -#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 -#define TAPE_DRIVE_FORMAT 0xA0000000 -#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 -#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 - - typedef struct _TAPE_GET_DRIVE_PARAMETERS { - BOOLEAN ECC; - BOOLEAN Compression; - BOOLEAN DataPadding; - BOOLEAN ReportSetmarks; - DWORD DefaultBlockSize; - DWORD MaximumBlockSize; - DWORD MinimumBlockSize; - DWORD MaximumPartitionCount; - DWORD FeaturesLow; - DWORD FeaturesHigh; - DWORD EOTWarningZoneSize; - } TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS; - - typedef struct _TAPE_SET_DRIVE_PARAMETERS { - BOOLEAN ECC; - BOOLEAN Compression; - BOOLEAN DataPadding; - BOOLEAN ReportSetmarks; - DWORD EOTWarningZoneSize; - } TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS; - - typedef struct _TAPE_GET_MEDIA_PARAMETERS { - LARGE_INTEGER Capacity; - LARGE_INTEGER Remaining; - DWORD BlockSize; - DWORD PartitionCount; - BOOLEAN WriteProtected; - } TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS; - - typedef struct _TAPE_SET_MEDIA_PARAMETERS { - DWORD BlockSize; - } TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS; - -#define TAPE_FIXED_PARTITIONS 0L -#define TAPE_SELECT_PARTITIONS 1L -#define TAPE_INITIATOR_PARTITIONS 2L - - typedef struct _TAPE_CREATE_PARTITION { - DWORD Method; - DWORD Count; - DWORD Size; - } TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION; - -#define TAPE_QUERY_DRIVE_PARAMETERS 0L -#define TAPE_QUERY_MEDIA_CAPACITY 1L -#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L -#define TAPE_QUERY_IO_ERROR_DATA 3L -#define TAPE_QUERY_DEVICE_ERROR_DATA 4L - - typedef struct _TAPE_WMI_OPERATIONS { - DWORD Method; - DWORD DataBufferSize; - PVOID DataBuffer; - } TAPE_WMI_OPERATIONS,*PTAPE_WMI_OPERATIONS; - - typedef enum _TAPE_DRIVE_PROBLEM_TYPE { - TapeDriveProblemNone,TapeDriveReadWriteWarning,TapeDriveReadWriteError,TapeDriveReadWarning,TapeDriveWriteWarning,TapeDriveReadError,TapeDriveWriteError,TapeDriveHardwareError,TapeDriveUnsupportedMedia,TapeDriveScsiConnectionError,TapeDriveTimetoClean,TapeDriveCleanDriveNow,TapeDriveMediaLifeExpired,TapeDriveSnappedTape - } TAPE_DRIVE_PROBLEM_TYPE; - -#if defined(__x86_64) - __CRT_INLINE struct _TEB *NtCurrentTeb(VOID) { return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB,Self)); } - __CRT_INLINE PVOID GetCurrentFiber(VOID) { return(PVOID)__readgsqword(FIELD_OFFSET(NT_TIB,FiberData)); } - __CRT_INLINE PVOID GetFiberData(VOID) { - return *(PVOID *)GetCurrentFiber(); - } -#endif - -#if(defined(_X86_) && !defined(__x86_64)) -#define PcTeb 0x18 - __CRT_INLINE struct _TEB *NtCurrentTeb(void) { - struct _TEB *ret; - __asm__ volatile ("movl %%fs:0x18,%0" - : "=r" (ret)); - return ret; - } -#endif - -#define ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION (1) -#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2) -#define ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION (3) -#define ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION (4) -#define ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION (5) -#define ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION (6) -#define ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION (7) -#define ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE (8) -#define ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES (9) -#define ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS (10) - -#ifdef __cplusplus - } -#endif -#endif diff --git a/tinyc/win32/include/winapi/winreg.h b/tinyc/win32/include/winapi/winreg.h deleted file mode 100644 index f158d2820..000000000 --- a/tinyc/win32/include/winapi/winreg.h +++ /dev/null @@ -1,272 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINREG_ -#define _WINREG_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#define RRF_RT_REG_NONE 0x00000001 -#define RRF_RT_REG_SZ 0x00000002 -#define RRF_RT_REG_EXPAND_SZ 0x00000004 -#define RRF_RT_REG_BINARY 0x00000008 -#define RRF_RT_REG_DWORD 0x00000010 -#define RRF_RT_REG_MULTI_SZ 0x00000020 -#define RRF_RT_REG_QWORD 0x00000040 - -#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) -#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) -#define RRF_RT_ANY 0x0000ffff - -#define RRF_NOEXPAND 0x10000000 -#define RRF_ZEROONFAILURE 0x20000000 - - typedef ACCESS_MASK REGSAM; - -#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) -#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) -#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) -#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) -#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) -#define HKEY_PERFORMANCE_TEXT ((HKEY) (ULONG_PTR)((LONG)0x80000050)) -#define HKEY_PERFORMANCE_NLSTEXT ((HKEY) (ULONG_PTR)((LONG)0x80000060)) -#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) -#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) - -#define REG_SECURE_CONNECTION 1 - -#ifndef _PROVIDER_STRUCTS_DEFINED -#define _PROVIDER_STRUCTS_DEFINED - -#define PROVIDER_KEEPS_VALUE_LENGTH 0x1 - struct val_context { - int valuelen; - LPVOID value_context; - LPVOID val_buff_ptr; - }; - - typedef struct val_context *PVALCONTEXT; - - typedef struct pvalueA { - LPSTR pv_valuename; - int pv_valuelen; - LPVOID pv_value_context; - DWORD pv_type; - }PVALUEA,*PPVALUEA; - - typedef struct pvalueW { - LPWSTR pv_valuename; - int pv_valuelen; - LPVOID pv_value_context; - DWORD pv_type; - }PVALUEW,*PPVALUEW; - -#ifdef UNICODE - typedef PVALUEW PVALUE; - typedef PPVALUEW PPVALUE; -#else - typedef PVALUEA PVALUE; - typedef PPVALUEA PPVALUE; -#endif - - typedef DWORD __cdecl QUERYHANDLER(LPVOID keycontext,PVALCONTEXT val_list,DWORD num_vals,LPVOID outputbuffer,DWORD *total_outlen,DWORD input_blen); - - typedef QUERYHANDLER *PQUERYHANDLER; - - typedef struct provider_info { - PQUERYHANDLER pi_R0_1val; - PQUERYHANDLER pi_R0_allvals; - PQUERYHANDLER pi_R3_1val; - PQUERYHANDLER pi_R3_allvals; - DWORD pi_flags; - LPVOID pi_key_context; - } REG_PROVIDER; - - typedef struct provider_info *PPROVIDER; - - typedef struct value_entA { - LPSTR ve_valuename; - DWORD ve_valuelen; - DWORD_PTR ve_valueptr; - DWORD ve_type; - } VALENTA,*PVALENTA; - - typedef struct value_entW { - LPWSTR ve_valuename; - DWORD ve_valuelen; - DWORD_PTR ve_valueptr; - DWORD ve_type; - } VALENTW,*PVALENTW; - -#ifdef UNICODE - typedef VALENTW VALENT; - typedef PVALENTW PVALENT; -#else - typedef VALENTA VALENT; - typedef PVALENTA PVALENT; -#endif -#endif - -#define WIN31_CLASS NULL - -#ifdef UNICODE -#define RegConnectRegistry RegConnectRegistryW -#define RegConnectRegistryEx RegConnectRegistryExW -#define RegCreateKey RegCreateKeyW -#define RegCreateKeyEx RegCreateKeyExW -#define RegDeleteKey RegDeleteKeyW -#define RegDeleteKeyEx RegDeleteKeyExW -#define RegDeleteValue RegDeleteValueW -#define RegEnumKey RegEnumKeyW -#define RegEnumKeyEx RegEnumKeyExW -#define RegEnumValue RegEnumValueW -#define RegLoadKey RegLoadKeyW -#define RegOpenKey RegOpenKeyW -#define RegOpenKeyEx RegOpenKeyExW -#define RegQueryInfoKey RegQueryInfoKeyW -#define RegQueryValue RegQueryValueW -#define RegQueryMultipleValues RegQueryMultipleValuesW -#define RegQueryValueEx RegQueryValueExW -#define RegReplaceKey RegReplaceKeyW -#define RegRestoreKey RegRestoreKeyW -#define RegSaveKey RegSaveKeyW -#define RegSetValue RegSetValueW -#define RegSetValueEx RegSetValueExW -#define RegUnLoadKey RegUnLoadKeyW -#define RegGetValue RegGetValueW -#define InitiateSystemShutdown InitiateSystemShutdownW -#define AbortSystemShutdown AbortSystemShutdownW -#else -#define RegConnectRegistry RegConnectRegistryA -#define RegConnectRegistryEx RegConnectRegistryExA -#define RegCreateKey RegCreateKeyA -#define RegCreateKeyEx RegCreateKeyExA -#define RegDeleteKey RegDeleteKeyA -#define RegDeleteKeyEx RegDeleteKeyExA -#define RegDeleteValue RegDeleteValueA -#define RegEnumKey RegEnumKeyA -#define RegEnumKeyEx RegEnumKeyExA -#define RegEnumValue RegEnumValueA -#define RegLoadKey RegLoadKeyA -#define RegOpenKey RegOpenKeyA -#define RegOpenKeyEx RegOpenKeyExA -#define RegQueryInfoKey RegQueryInfoKeyA -#define RegQueryValue RegQueryValueA -#define RegQueryMultipleValues RegQueryMultipleValuesA -#define RegQueryValueEx RegQueryValueExA -#define RegReplaceKey RegReplaceKeyA -#define RegRestoreKey RegRestoreKeyA -#define RegSaveKey RegSaveKeyA -#define RegSetValue RegSetValueA -#define RegSetValueEx RegSetValueExA -#define RegUnLoadKey RegUnLoadKeyA -#define RegGetValue RegGetValueA -#define InitiateSystemShutdown InitiateSystemShutdownA -#define AbortSystemShutdown AbortSystemShutdownA -#endif - - WINADVAPI LONG WINAPI RegCloseKey(HKEY hKey); - WINADVAPI LONG WINAPI RegOverridePredefKey(HKEY hKey,HKEY hNewHKey); - WINADVAPI LONG WINAPI RegOpenUserClassesRoot(HANDLE hToken,DWORD dwOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenCurrentUser(REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegDisablePredefinedCache(); - WINADVAPI LONG WINAPI RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryExA(LPCSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryExW(LPCWSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); - WINADVAPI LONG WINAPI RegCreateKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); - WINADVAPI LONG WINAPI RegDeleteKeyA(HKEY hKey,LPCSTR lpSubKey); - WINADVAPI LONG WINAPI RegDeleteKeyW(HKEY hKey,LPCWSTR lpSubKey); - WINADVAPI LONG WINAPI RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); - WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved); - WINADVAPI LONG WINAPI RegDisableReflectionKey(HKEY hBase); - WINADVAPI LONG WINAPI RegEnableReflectionKey(HKEY hBase); - WINADVAPI LONG WINAPI RegQueryReflectionKey(HKEY hBase,WINBOOL *bIsReflectionDisabled); - WINADVAPI LONG WINAPI RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); - WINADVAPI LONG WINAPI RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName); - WINADVAPI LONG WINAPI RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cchName); - WINADVAPI LONG WINAPI RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cchName); - WINADVAPI LONG WINAPI RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegEnumKeyExW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegEnumValueW(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegFlushKey(HKEY hKey); - WINADVAPI LONG WINAPI RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor); - WINADVAPI LONG WINAPI RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile); - WINADVAPI LONG WINAPI RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile); - WINADVAPI LONG WINAPI RegNotifyChangeKeyValue(HKEY hKey,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,WINBOOL fAsynchronous); - WINADVAPI LONG WINAPI RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegQueryValueA(HKEY hKey,LPCSTR lpSubKey,LPSTR lpData,PLONG lpcbData); - WINADVAPI LONG WINAPI RegQueryValueW(HKEY hKey,LPCWSTR lpSubKey,LPWSTR lpData,PLONG lpcbData); - WINADVAPI LONG WINAPI RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize); - WINADVAPI LONG WINAPI RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize); - WINADVAPI LONG WINAPI RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile); - WINADVAPI LONG WINAPI RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile); - WINADVAPI LONG WINAPI RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags); - WINADVAPI LONG WINAPI RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags); - WINADVAPI LONG WINAPI RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINADVAPI LONG WINAPI RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINADVAPI LONG WINAPI RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI LONG WINAPI RegSetValueA(HKEY hKey,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueW(HKEY hKey,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueExW(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey); - WINADVAPI LONG WINAPI RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey); - WINADVAPI LONG WINAPI RegGetValueA(HKEY hkey,LPCSTR lpSubKey,LPCSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); - WINADVAPI LONG WINAPI RegGetValueW(HKEY hkey,LPCWSTR lpSubKey,LPCWSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); - WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName); - WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName); - -//gr #include - -#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION -#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION -#define REASON_SERVICEHANG SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_HUNG -#define REASON_UNSTABLE SHTDN_REASON_MAJOR_SYSTEM|SHTDN_REASON_MINOR_UNSTABLE -#define REASON_SWHWRECONF SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_RECONFIG -#define REASON_OTHER SHTDN_REASON_MAJOR_OTHER|SHTDN_REASON_MINOR_OTHER -#define REASON_UNKNOWN SHTDN_REASON_UNKNOWN -#define REASON_LEGACY_API SHTDN_REASON_LEGACY_API -#define REASON_PLANNED_FLAG SHTDN_REASON_FLAG_PLANNED - -#define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) - -#ifdef UNICODE -#define InitiateSystemShutdownEx InitiateSystemShutdownExW -#define RegSaveKeyEx RegSaveKeyExW -#else -#define InitiateSystemShutdownEx InitiateSystemShutdownExA -#define RegSaveKeyEx RegSaveKeyExA -#endif - - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); - WINADVAPI LONG WINAPI RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); - WINADVAPI LONG WINAPI RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); - WINADVAPI LONG WINAPI Wow64Win32ApiEntry (DWORD dwFuncNumber,DWORD dwFlag,DWORD dwRes); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/winuser.h b/tinyc/win32/include/winapi/winuser.h deleted file mode 100644 index 4cd9ffb56..000000000 --- a/tinyc/win32/include/winapi/winuser.h +++ /dev/null @@ -1,5651 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINUSER_ -#define _WINUSER_ - -#define WINUSERAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#include - -#ifndef NOUSER - typedef HANDLE HDWP; - typedef VOID MENUTEMPLATEA; - typedef VOID MENUTEMPLATEW; - typedef PVOID LPMENUTEMPLATEA; - typedef PVOID LPMENUTEMPLATEW; - -#ifdef UNICODE - typedef MENUTEMPLATEW MENUTEMPLATE; - typedef LPMENUTEMPLATEW LPMENUTEMPLATE; -#else - typedef MENUTEMPLATEA MENUTEMPLATE; - typedef LPMENUTEMPLATEA LPMENUTEMPLATE; -#endif - - typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM); - typedef INT_PTR (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); - typedef VOID (CALLBACK *TIMERPROC)(HWND,UINT,UINT_PTR,DWORD); - typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int); - typedef WINBOOL (CALLBACK *WNDENUMPROC)(HWND,LPARAM); - typedef LRESULT (CALLBACK *HOOKPROC)(int code,WPARAM wParam,LPARAM lParam); - typedef VOID (CALLBACK *SENDASYNCPROC)(HWND,UINT,ULONG_PTR,LRESULT); - typedef WINBOOL (CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE); - typedef WINBOOL (CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); - typedef WINBOOL (CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,ULONG_PTR); - typedef WINBOOL (CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,ULONG_PTR); - typedef int (CALLBACK *EDITWORDBREAKPROCA)(LPSTR lpch,int ichCurrent,int cch,int code); - typedef int (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR lpch,int ichCurrent,int cch,int code); - typedef WINBOOL (CALLBACK *DRAWSTATEPROC)(HDC hdc,LPARAM lData,WPARAM wData,int cx,int cy); - -#ifdef UNICODE - typedef PROPENUMPROCW PROPENUMPROC; - typedef PROPENUMPROCEXW PROPENUMPROCEX; - typedef EDITWORDBREAKPROCW EDITWORDBREAKPROC; -#else - typedef PROPENUMPROCA PROPENUMPROC; - typedef PROPENUMPROCEXA PROPENUMPROCEX; - typedef EDITWORDBREAKPROCA EDITWORDBREAKPROC; -#endif - - typedef WINBOOL (CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM); - typedef WINBOOL (CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM); - typedef NAMEENUMPROCA WINSTAENUMPROCA; - typedef NAMEENUMPROCA DESKTOPENUMPROCA; - typedef NAMEENUMPROCW WINSTAENUMPROCW; - typedef NAMEENUMPROCW DESKTOPENUMPROCW; - -#ifdef UNICODE - typedef WINSTAENUMPROCW WINSTAENUMPROC; - typedef DESKTOPENUMPROCW DESKTOPENUMPROC; -#else - typedef WINSTAENUMPROCA WINSTAENUMPROC; - typedef DESKTOPENUMPROCA DESKTOPENUMPROC; -#endif - -#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16)==0) -#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) -#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) -#ifdef UNICODE -#define MAKEINTRESOURCE MAKEINTRESOURCEW -#else -#define MAKEINTRESOURCE MAKEINTRESOURCEA -#endif - -#ifndef NORESOURCE - -#define RT_CURSOR MAKEINTRESOURCE(1) -#define RT_BITMAP MAKEINTRESOURCE(2) -#define RT_ICON MAKEINTRESOURCE(3) -#define RT_MENU MAKEINTRESOURCE(4) -#define RT_DIALOG MAKEINTRESOURCE(5) -#define RT_STRING MAKEINTRESOURCE(6) -#define RT_FONTDIR MAKEINTRESOURCE(7) -#define RT_FONT MAKEINTRESOURCE(8) -#define RT_ACCELERATOR MAKEINTRESOURCE(9) -#define RT_RCDATA MAKEINTRESOURCE(10) -#define RT_MESSAGETABLE MAKEINTRESOURCE(11) - -#define DIFFERENCE 11 -#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)RT_CURSOR + DIFFERENCE) -#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)RT_ICON + DIFFERENCE) -#define RT_VERSION MAKEINTRESOURCE(16) -#define RT_DLGINCLUDE MAKEINTRESOURCE(17) -#define RT_PLUGPLAY MAKEINTRESOURCE(19) -#define RT_VXD MAKEINTRESOURCE(20) -#define RT_ANICURSOR MAKEINTRESOURCE(21) -#define RT_ANIICON MAKEINTRESOURCE(22) -#define RT_HTML MAKEINTRESOURCE(23) -#ifdef RC_INVOKED -#define RT_MANIFEST 24 -#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 -#else -#define RT_MANIFEST MAKEINTRESOURCE(24) -#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2) -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16) -#endif -#endif - -#ifdef UNICODE -#define wvsprintf wvsprintfW -#define wsprintf wsprintfW -#else -#define wvsprintf wvsprintfA -#define wsprintf wsprintfA -#endif - - WINUSERAPI int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist); - WINUSERAPI int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist); - WINUSERAPI int WINAPIV wsprintfA(LPSTR,LPCSTR,...); - WINUSERAPI int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...); - -#define SETWALLPAPER_DEFAULT ((LPWSTR)-1) - -#ifndef NOSCROLL -#define SB_HORZ 0 -#define SB_VERT 1 -#define SB_CTL 2 -#define SB_BOTH 3 - -#define SB_LINEUP 0 -#define SB_LINELEFT 0 -#define SB_LINEDOWN 1 -#define SB_LINERIGHT 1 -#define SB_PAGEUP 2 -#define SB_PAGELEFT 2 -#define SB_PAGEDOWN 3 -#define SB_PAGERIGHT 3 -#define SB_THUMBPOSITION 4 -#define SB_THUMBTRACK 5 -#define SB_TOP 6 -#define SB_LEFT 6 -#define SB_BOTTOM 7 -#define SB_RIGHT 7 -#define SB_ENDSCROLL 8 -#endif - -#ifndef NOSHOWWINDOW -#define SW_HIDE 0 -#define SW_SHOWNORMAL 1 -#define SW_NORMAL 1 -#define SW_SHOWMINIMIZED 2 -#define SW_SHOWMAXIMIZED 3 -#define SW_MAXIMIZE 3 -#define SW_SHOWNOACTIVATE 4 -#define SW_SHOW 5 -#define SW_MINIMIZE 6 -#define SW_SHOWMINNOACTIVE 7 -#define SW_SHOWNA 8 -#define SW_RESTORE 9 -#define SW_SHOWDEFAULT 10 -#define SW_FORCEMINIMIZE 11 -#define SW_MAX 11 - -#define HIDE_WINDOW 0 -#define SHOW_OPENWINDOW 1 -#define SHOW_ICONWINDOW 2 -#define SHOW_FULLSCREEN 3 -#define SHOW_OPENNOACTIVATE 4 - -#define SW_PARENTCLOSING 1 -#define SW_OTHERZOOM 2 -#define SW_PARENTOPENING 3 -#define SW_OTHERUNZOOM 4 -#endif - -#define AW_HOR_POSITIVE 0x00000001 -#define AW_HOR_NEGATIVE 0x00000002 -#define AW_VER_POSITIVE 0x00000004 -#define AW_VER_NEGATIVE 0x00000008 -#define AW_CENTER 0x00000010 -#define AW_HIDE 0x00010000 -#define AW_ACTIVATE 0x00020000 -#define AW_SLIDE 0x00040000 -#define AW_BLEND 0x00080000 - -#define KF_EXTENDED 0x0100 -#define KF_DLGMODE 0x0800 -#define KF_MENUMODE 0x1000 -#define KF_ALTDOWN 0x2000 -#define KF_REPEAT 0x4000 -#define KF_UP 0x8000 - -#ifndef NOVIRTUALKEYCODES - -#define VK_LBUTTON 0x01 -#define VK_RBUTTON 0x02 -#define VK_CANCEL 0x03 -#define VK_MBUTTON 0x04 -#define VK_XBUTTON1 0x05 -#define VK_XBUTTON2 0x06 -#define VK_BACK 0x08 -#define VK_TAB 0x09 -#define VK_CLEAR 0x0C -#define VK_RETURN 0x0D -#define VK_SHIFT 0x10 -#define VK_CONTROL 0x11 -#define VK_MENU 0x12 -#define VK_PAUSE 0x13 -#define VK_CAPITAL 0x14 -#define VK_KANA 0x15 -#define VK_HANGEUL 0x15 -#define VK_HANGUL 0x15 -#define VK_JUNJA 0x17 -#define VK_FINAL 0x18 -#define VK_HANJA 0x19 -#define VK_KANJI 0x19 -#define VK_ESCAPE 0x1B -#define VK_CONVERT 0x1C -#define VK_NONCONVERT 0x1D -#define VK_ACCEPT 0x1E -#define VK_MODECHANGE 0x1F -#define VK_SPACE 0x20 -#define VK_PRIOR 0x21 -#define VK_NEXT 0x22 -#define VK_END 0x23 -#define VK_HOME 0x24 -#define VK_LEFT 0x25 -#define VK_UP 0x26 -#define VK_RIGHT 0x27 -#define VK_DOWN 0x28 -#define VK_SELECT 0x29 -#define VK_PRINT 0x2A -#define VK_EXECUTE 0x2B -#define VK_SNAPSHOT 0x2C -#define VK_INSERT 0x2D -#define VK_DELETE 0x2E -#define VK_HELP 0x2F - -#define VK_LWIN 0x5B -#define VK_RWIN 0x5C -#define VK_APPS 0x5D -#define VK_SLEEP 0x5F -#define VK_NUMPAD0 0x60 -#define VK_NUMPAD1 0x61 -#define VK_NUMPAD2 0x62 -#define VK_NUMPAD3 0x63 -#define VK_NUMPAD4 0x64 -#define VK_NUMPAD5 0x65 -#define VK_NUMPAD6 0x66 -#define VK_NUMPAD7 0x67 -#define VK_NUMPAD8 0x68 -#define VK_NUMPAD9 0x69 -#define VK_MULTIPLY 0x6A -#define VK_ADD 0x6B -#define VK_SEPARATOR 0x6C -#define VK_SUBTRACT 0x6D -#define VK_DECIMAL 0x6E -#define VK_DIVIDE 0x6F -#define VK_F1 0x70 -#define VK_F2 0x71 -#define VK_F3 0x72 -#define VK_F4 0x73 -#define VK_F5 0x74 -#define VK_F6 0x75 -#define VK_F7 0x76 -#define VK_F8 0x77 -#define VK_F9 0x78 -#define VK_F10 0x79 -#define VK_F11 0x7A -#define VK_F12 0x7B -#define VK_F13 0x7C -#define VK_F14 0x7D -#define VK_F15 0x7E -#define VK_F16 0x7F -#define VK_F17 0x80 -#define VK_F18 0x81 -#define VK_F19 0x82 -#define VK_F20 0x83 -#define VK_F21 0x84 -#define VK_F22 0x85 -#define VK_F23 0x86 -#define VK_F24 0x87 -#define VK_NUMLOCK 0x90 -#define VK_SCROLL 0x91 -#define VK_OEM_NEC_EQUAL 0x92 -#define VK_OEM_FJ_JISHO 0x92 -#define VK_OEM_FJ_MASSHOU 0x93 -#define VK_OEM_FJ_TOUROKU 0x94 -#define VK_OEM_FJ_LOYA 0x95 -#define VK_OEM_FJ_ROYA 0x96 -#define VK_LSHIFT 0xA0 -#define VK_RSHIFT 0xA1 -#define VK_LCONTROL 0xA2 -#define VK_RCONTROL 0xA3 -#define VK_LMENU 0xA4 -#define VK_RMENU 0xA5 -#define VK_BROWSER_BACK 0xA6 -#define VK_BROWSER_FORWARD 0xA7 -#define VK_BROWSER_REFRESH 0xA8 -#define VK_BROWSER_STOP 0xA9 -#define VK_BROWSER_SEARCH 0xAA -#define VK_BROWSER_FAVORITES 0xAB -#define VK_BROWSER_HOME 0xAC -#define VK_VOLUME_MUTE 0xAD -#define VK_VOLUME_DOWN 0xAE -#define VK_VOLUME_UP 0xAF -#define VK_MEDIA_NEXT_TRACK 0xB0 -#define VK_MEDIA_PREV_TRACK 0xB1 -#define VK_MEDIA_STOP 0xB2 -#define VK_MEDIA_PLAY_PAUSE 0xB3 -#define VK_LAUNCH_MAIL 0xB4 -#define VK_LAUNCH_MEDIA_SELECT 0xB5 -#define VK_LAUNCH_APP1 0xB6 -#define VK_LAUNCH_APP2 0xB7 -#define VK_OEM_1 0xBA -#define VK_OEM_PLUS 0xBB -#define VK_OEM_COMMA 0xBC -#define VK_OEM_MINUS 0xBD -#define VK_OEM_PERIOD 0xBE -#define VK_OEM_2 0xBF -#define VK_OEM_3 0xC0 -#define VK_OEM_4 0xDB -#define VK_OEM_5 0xDC -#define VK_OEM_6 0xDD -#define VK_OEM_7 0xDE -#define VK_OEM_8 0xDF -#define VK_OEM_AX 0xE1 -#define VK_OEM_102 0xE2 -#define VK_ICO_HELP 0xE3 -#define VK_ICO_00 0xE4 -#define VK_PROCESSKEY 0xE5 -#define VK_ICO_CLEAR 0xE6 -#define VK_PACKET 0xE7 -#define VK_OEM_RESET 0xE9 -#define VK_OEM_JUMP 0xEA -#define VK_OEM_PA1 0xEB -#define VK_OEM_PA2 0xEC -#define VK_OEM_PA3 0xED -#define VK_OEM_WSCTRL 0xEE -#define VK_OEM_CUSEL 0xEF -#define VK_OEM_ATTN 0xF0 -#define VK_OEM_FINISH 0xF1 -#define VK_OEM_COPY 0xF2 -#define VK_OEM_AUTO 0xF3 -#define VK_OEM_ENLW 0xF4 -#define VK_OEM_BACKTAB 0xF5 -#define VK_ATTN 0xF6 -#define VK_CRSEL 0xF7 -#define VK_EXSEL 0xF8 -#define VK_EREOF 0xF9 -#define VK_PLAY 0xFA -#define VK_ZOOM 0xFB -#define VK_NONAME 0xFC -#define VK_PA1 0xFD -#define VK_OEM_CLEAR 0xFE -#endif - -#ifndef NOWH - -#define WH_MIN (-1) -#define WH_MSGFILTER (-1) -#define WH_JOURNALRECORD 0 -#define WH_JOURNALPLAYBACK 1 -#define WH_KEYBOARD 2 -#define WH_GETMESSAGE 3 -#define WH_CALLWNDPROC 4 -#define WH_CBT 5 -#define WH_SYSMSGFILTER 6 -#define WH_MOUSE 7 -#define WH_HARDWARE 8 -#define WH_DEBUG 9 -#define WH_SHELL 10 -#define WH_FOREGROUNDIDLE 11 -#define WH_CALLWNDPROCRET 12 - -#define WH_KEYBOARD_LL 13 -#define WH_MOUSE_LL 14 - -#define WH_MAX 14 - -#define WH_MINHOOK WH_MIN -#define WH_MAXHOOK WH_MAX - -#define HC_ACTION 0 -#define HC_GETNEXT 1 -#define HC_SKIP 2 -#define HC_NOREMOVE 3 -#define HC_NOREM HC_NOREMOVE -#define HC_SYSMODALON 4 -#define HC_SYSMODALOFF 5 - -#define HCBT_MOVESIZE 0 -#define HCBT_MINMAX 1 -#define HCBT_QS 2 -#define HCBT_CREATEWND 3 -#define HCBT_DESTROYWND 4 -#define HCBT_ACTIVATE 5 -#define HCBT_CLICKSKIPPED 6 -#define HCBT_KEYSKIPPED 7 -#define HCBT_SYSCOMMAND 8 -#define HCBT_SETFOCUS 9 - - typedef struct tagCBT_CREATEWNDA { - struct tagCREATESTRUCTA *lpcs; - HWND hwndInsertAfter; - } CBT_CREATEWNDA,*LPCBT_CREATEWNDA; - - typedef struct tagCBT_CREATEWNDW { - struct tagCREATESTRUCTW *lpcs; - HWND hwndInsertAfter; - } CBT_CREATEWNDW,*LPCBT_CREATEWNDW; -#ifdef UNICODE - typedef CBT_CREATEWNDW CBT_CREATEWND; - typedef LPCBT_CREATEWNDW LPCBT_CREATEWND; -#else - typedef CBT_CREATEWNDA CBT_CREATEWND; - typedef LPCBT_CREATEWNDA LPCBT_CREATEWND; -#endif - - typedef struct tagCBTACTIVATESTRUCT - { - WINBOOL fMouse; - HWND hWndActive; - } CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT; - - typedef struct tagWTSSESSION_NOTIFICATION { - DWORD cbSize; - DWORD dwSessionId; - - } WTSSESSION_NOTIFICATION,*PWTSSESSION_NOTIFICATION; - -#define WTS_CONSOLE_CONNECT 0x1 -#define WTS_CONSOLE_DISCONNECT 0x2 -#define WTS_REMOTE_CONNECT 0x3 -#define WTS_REMOTE_DISCONNECT 0x4 -#define WTS_SESSION_LOGON 0x5 -#define WTS_SESSION_LOGOFF 0x6 -#define WTS_SESSION_LOCK 0x7 -#define WTS_SESSION_UNLOCK 0x8 -#define WTS_SESSION_REMOTE_CONTROL 0x9 - -#define MSGF_DIALOGBOX 0 -#define MSGF_MESSAGEBOX 1 -#define MSGF_MENU 2 -#define MSGF_SCROLLBAR 5 -#define MSGF_NEXTWINDOW 6 -#define MSGF_MAX 8 -#define MSGF_USER 4096 - -#define HSHELL_WINDOWCREATED 1 -#define HSHELL_WINDOWDESTROYED 2 -#define HSHELL_ACTIVATESHELLWINDOW 3 - -#define HSHELL_WINDOWACTIVATED 4 -#define HSHELL_GETMINRECT 5 -#define HSHELL_REDRAW 6 -#define HSHELL_TASKMAN 7 -#define HSHELL_LANGUAGE 8 -#define HSHELL_SYSMENU 9 -#define HSHELL_ENDTASK 10 -#define HSHELL_ACCESSIBILITYSTATE 11 -#define HSHELL_APPCOMMAND 12 -#define HSHELL_WINDOWREPLACED 13 -#define HSHELL_WINDOWREPLACING 14 -#define HSHELL_HIGHBIT 0x8000 -#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) -#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) - -#define ACCESS_STICKYKEYS 0x0001 -#define ACCESS_FILTERKEYS 0x0002 -#define ACCESS_MOUSEKEYS 0x0003 - -#define APPCOMMAND_BROWSER_BACKWARD 1 -#define APPCOMMAND_BROWSER_FORWARD 2 -#define APPCOMMAND_BROWSER_REFRESH 3 -#define APPCOMMAND_BROWSER_STOP 4 -#define APPCOMMAND_BROWSER_SEARCH 5 -#define APPCOMMAND_BROWSER_FAVORITES 6 -#define APPCOMMAND_BROWSER_HOME 7 -#define APPCOMMAND_VOLUME_MUTE 8 -#define APPCOMMAND_VOLUME_DOWN 9 -#define APPCOMMAND_VOLUME_UP 10 -#define APPCOMMAND_MEDIA_NEXTTRACK 11 -#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 -#define APPCOMMAND_MEDIA_STOP 13 -#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 -#define APPCOMMAND_LAUNCH_MAIL 15 -#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 -#define APPCOMMAND_LAUNCH_APP1 17 -#define APPCOMMAND_LAUNCH_APP2 18 -#define APPCOMMAND_BASS_DOWN 19 -#define APPCOMMAND_BASS_BOOST 20 -#define APPCOMMAND_BASS_UP 21 -#define APPCOMMAND_TREBLE_DOWN 22 -#define APPCOMMAND_TREBLE_UP 23 -#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 -#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 -#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 -#define APPCOMMAND_HELP 27 -#define APPCOMMAND_FIND 28 -#define APPCOMMAND_NEW 29 -#define APPCOMMAND_OPEN 30 -#define APPCOMMAND_CLOSE 31 -#define APPCOMMAND_SAVE 32 -#define APPCOMMAND_PRINT 33 -#define APPCOMMAND_UNDO 34 -#define APPCOMMAND_REDO 35 -#define APPCOMMAND_COPY 36 -#define APPCOMMAND_CUT 37 -#define APPCOMMAND_PASTE 38 -#define APPCOMMAND_REPLY_TO_MAIL 39 -#define APPCOMMAND_FORWARD_MAIL 40 -#define APPCOMMAND_SEND_MAIL 41 -#define APPCOMMAND_SPELL_CHECK 42 -#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 -#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 -#define APPCOMMAND_CORRECTION_LIST 45 -#define APPCOMMAND_MEDIA_PLAY 46 -#define APPCOMMAND_MEDIA_PAUSE 47 -#define APPCOMMAND_MEDIA_RECORD 48 -#define APPCOMMAND_MEDIA_FAST_FORWARD 49 -#define APPCOMMAND_MEDIA_REWIND 50 -#define APPCOMMAND_MEDIA_CHANNEL_UP 51 -#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 - -#define FAPPCOMMAND_MOUSE 0x8000 -#define FAPPCOMMAND_KEY 0 -#define FAPPCOMMAND_OEM 0x1000 -#define FAPPCOMMAND_MASK 0xF000 - -#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) -#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) -#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM -#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) -#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) - - typedef struct { - HWND hwnd; - RECT rc; - } SHELLHOOKINFO,*LPSHELLHOOKINFO; - - typedef struct tagEVENTMSG { - UINT message; - UINT paramL; - UINT paramH; - DWORD time; - HWND hwnd; - } EVENTMSG,*PEVENTMSGMSG,*NPEVENTMSGMSG,*LPEVENTMSGMSG; - - typedef struct tagEVENTMSG *PEVENTMSG,*NPEVENTMSG,*LPEVENTMSG; - - typedef struct tagCWPSTRUCT { - LPARAM lParam; - WPARAM wParam; - UINT message; - HWND hwnd; - } CWPSTRUCT,*PCWPSTRUCT,*NPCWPSTRUCT,*LPCWPSTRUCT; - - typedef struct tagCWPRETSTRUCT { - LRESULT lResult; - LPARAM lParam; - WPARAM wParam; - UINT message; - HWND hwnd; - } CWPRETSTRUCT,*PCWPRETSTRUCT,*NPCWPRETSTRUCT,*LPCWPRETSTRUCT; - -#define LLKHF_EXTENDED (KF_EXTENDED >> 8) -#define LLKHF_INJECTED 0x00000010 -#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) -#define LLKHF_UP (KF_UP >> 8) - -#define LLMHF_INJECTED 0x00000001 - - typedef struct tagKBDLLHOOKSTRUCT { - DWORD vkCode; - DWORD scanCode; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - } KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT; - - typedef struct tagMSLLHOOKSTRUCT { - POINT pt; - DWORD mouseData; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - } MSLLHOOKSTRUCT,*LPMSLLHOOKSTRUCT,*PMSLLHOOKSTRUCT; - - typedef struct tagDEBUGHOOKINFO { - DWORD idThread; - DWORD idThreadInstaller; - LPARAM lParam; - WPARAM wParam; - int code; - } DEBUGHOOKINFO,*PDEBUGHOOKINFO,*NPDEBUGHOOKINFO,*LPDEBUGHOOKINFO; - - typedef struct tagMOUSEHOOKSTRUCT { - POINT pt; - HWND hwnd; - UINT wHitTestCode; - ULONG_PTR dwExtraInfo; - } MOUSEHOOKSTRUCT,*LPMOUSEHOOKSTRUCT,*PMOUSEHOOKSTRUCT; - -#ifdef __cplusplus - typedef struct tagMOUSEHOOKSTRUCTEX : public tagMOUSEHOOKSTRUCT { - DWORD mouseData; - } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; -#else - typedef struct tagMOUSEHOOKSTRUCTEX { - MOUSEHOOKSTRUCT _unnamed; - DWORD mouseData; - } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; -#endif - - typedef struct tagHARDWAREHOOKSTRUCT { - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - } HARDWAREHOOKSTRUCT,*LPHARDWAREHOOKSTRUCT,*PHARDWAREHOOKSTRUCT; -#endif - -#define HKL_PREV 0 -#define HKL_NEXT 1 - -#define KLF_ACTIVATE 0x00000001 -#define KLF_SUBSTITUTE_OK 0x00000002 -#define KLF_REORDER 0x00000008 -#define KLF_REPLACELANG 0x00000010 -#define KLF_NOTELLSHELL 0x00000080 -#define KLF_SETFORPROCESS 0x00000100 -#define KLF_SHIFTLOCK 0x00010000 -#define KLF_RESET 0x40000000 - -#define INPUTLANGCHANGE_SYSCHARSET 0x0001 -#define INPUTLANGCHANGE_FORWARD 0x0002 -#define INPUTLANGCHANGE_BACKWARD 0x0004 - -#define KL_NAMELENGTH 9 - -#ifdef UNICODE -#define LoadKeyboardLayout LoadKeyboardLayoutW -#define GetKeyboardLayoutName GetKeyboardLayoutNameW -#else -#define LoadKeyboardLayout LoadKeyboardLayoutA -#define GetKeyboardLayoutName GetKeyboardLayoutNameA -#endif - - WINUSERAPI HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID,UINT Flags); - WINUSERAPI HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID,UINT Flags); - WINUSERAPI HKL WINAPI ActivateKeyboardLayout(HKL hkl,UINT Flags); - WINUSERAPI int WINAPI ToUnicodeEx(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags,HKL dwhkl); - WINUSERAPI WINBOOL WINAPI UnloadKeyboardLayout(HKL hkl); - WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID); - WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID); - WINUSERAPI int WINAPI GetKeyboardLayoutList(int nBuff,HKL *lpList); - WINUSERAPI HKL WINAPI GetKeyboardLayout(DWORD idThread); - - typedef struct tagMOUSEMOVEPOINT { - int x; - int y; - DWORD time; - ULONG_PTR dwExtraInfo; - } MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; - -#define GMMP_USE_DISPLAY_POINTS 1 -#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 - - WINUSERAPI int WINAPI GetMouseMovePointsEx(UINT cbSize,LPMOUSEMOVEPOINT lppt,LPMOUSEMOVEPOINT lpptBuf,int nBufPoints,DWORD resolution); - -#ifndef NODESKTOP - -#define DESKTOP_READOBJECTS 0x0001L -#define DESKTOP_CREATEWINDOW 0x0002L -#define DESKTOP_CREATEMENU 0x0004L -#define DESKTOP_HOOKCONTROL 0x0008L -#define DESKTOP_JOURNALRECORD 0x0010L -#define DESKTOP_JOURNALPLAYBACK 0x0020L -#define DESKTOP_ENUMERATE 0x0040L -#define DESKTOP_WRITEOBJECTS 0x0080L -#define DESKTOP_SWITCHDESKTOP 0x0100L - -#define DF_ALLOWOTHERACCOUNTHOOK 0x0001L - -#ifdef _WINGDI_ -#ifndef NOGDI -#ifdef UNICODE -#define CreateDesktop CreateDesktopW -#else -#define CreateDesktop CreateDesktopA -#endif - - WINUSERAPI HDESK WINAPI CreateDesktopA(LPCSTR lpszDesktop,LPCSTR lpszDevice,LPDEVMODEA pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HDESK WINAPI CreateDesktopW(LPCWSTR lpszDesktop,LPCWSTR lpszDevice,LPDEVMODEW pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); -#endif -#endif - -#ifdef UNICODE -#define OpenDesktop OpenDesktopW -#define EnumDesktops EnumDesktopsW -#else -#define OpenDesktop OpenDesktopA -#define EnumDesktops EnumDesktopsA -#endif - - WINUSERAPI HDESK WINAPI OpenDesktopA(LPCSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HDESK WINAPI OpenDesktopW(LPCWSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HDESK WINAPI OpenInputDesktop(DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI WINBOOL WINAPI EnumDesktopsA(HWINSTA hwinsta,DESKTOPENUMPROCA lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumDesktopsW(HWINSTA hwinsta,DESKTOPENUMPROCW lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SwitchDesktop(HDESK hDesktop); - WINUSERAPI WINBOOL WINAPI SetThreadDesktop(HDESK hDesktop); - WINUSERAPI WINBOOL WINAPI CloseDesktop(HDESK hDesktop); - WINUSERAPI HDESK WINAPI GetThreadDesktop(DWORD dwThreadId); -#endif - -#ifndef NOWINDOWSTATION -#define WINSTA_ENUMDESKTOPS 0x0001L -#define WINSTA_READATTRIBUTES 0x0002L -#define WINSTA_ACCESSCLIPBOARD 0x0004L -#define WINSTA_CREATEDESKTOP 0x0008L -#define WINSTA_WRITEATTRIBUTES 0x0010L -#define WINSTA_ACCESSGLOBALATOMS 0x0020L -#define WINSTA_EXITWINDOWS 0x0040L -#define WINSTA_ENUMERATE 0x0100L -#define WINSTA_READSCREEN 0x0200L -#define WINSTA_ALL_ACCESS (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN) - -#define CWF_CREATE_ONLY 0x0001L - -#define WSF_VISIBLE 0x0001L - -#ifdef UNICODE -#define CreateWindowStation CreateWindowStationW -#define OpenWindowStation OpenWindowStationW -#define EnumWindowStations EnumWindowStationsW -#else -#define CreateWindowStation CreateWindowStationA -#define OpenWindowStation OpenWindowStationA -#define EnumWindowStations EnumWindowStationsA -#endif - - WINUSERAPI HWINSTA WINAPI CreateWindowStationA(LPCSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HWINSTA WINAPI CreateWindowStationW(LPCWSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HWINSTA WINAPI OpenWindowStationA(LPCSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HWINSTA WINAPI OpenWindowStationW(LPCWSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI WINBOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI CloseWindowStation(HWINSTA hWinSta); - WINUSERAPI WINBOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta); - WINUSERAPI HWINSTA WINAPI GetProcessWindowStation(VOID); -#endif - -#ifndef NOSECURITY - WINUSERAPI WINBOOL WINAPI SetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID); - WINUSERAPI WINBOOL WINAPI GetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID,DWORD nLength,LPDWORD lpnLengthNeeded); - -#define UOI_FLAGS 1 -#define UOI_NAME 2 -#define UOI_TYPE 3 -#define UOI_USER_SID 4 - - typedef struct tagUSEROBJECTFLAGS { - WINBOOL fInherit; - WINBOOL fReserved; - DWORD dwFlags; - } USEROBJECTFLAGS,*PUSEROBJECTFLAGS; - -#ifdef UNICODE -#define GetUserObjectInformation GetUserObjectInformationW -#define SetUserObjectInformation SetUserObjectInformationW -#else -#define GetUserObjectInformation GetUserObjectInformationA -#define SetUserObjectInformation SetUserObjectInformationA -#endif - - WINUSERAPI WINBOOL WINAPI GetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); - WINUSERAPI WINBOOL WINAPI GetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); - WINUSERAPI WINBOOL WINAPI SetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); - WINUSERAPI WINBOOL WINAPI SetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); -#endif - - typedef struct tagWNDCLASSEXA { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCSTR lpszMenuName; - LPCSTR lpszClassName; - HICON hIconSm; - } WNDCLASSEXA,*PWNDCLASSEXA,*NPWNDCLASSEXA,*LPWNDCLASSEXA; - - typedef struct tagWNDCLASSEXW { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCWSTR lpszMenuName; - LPCWSTR lpszClassName; - - HICON hIconSm; - } WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; - -#ifdef UNICODE - typedef WNDCLASSEXW WNDCLASSEX; - typedef PWNDCLASSEXW PWNDCLASSEX; - typedef NPWNDCLASSEXW NPWNDCLASSEX; - typedef LPWNDCLASSEXW LPWNDCLASSEX; -#else - typedef WNDCLASSEXA WNDCLASSEX; - typedef PWNDCLASSEXA PWNDCLASSEX; - typedef NPWNDCLASSEXA NPWNDCLASSEX; - typedef LPWNDCLASSEXA LPWNDCLASSEX; -#endif - - typedef struct tagWNDCLASSA { - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCSTR lpszMenuName; - LPCSTR lpszClassName; - } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; - - typedef struct tagWNDCLASSW { - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCWSTR lpszMenuName; - LPCWSTR lpszClassName; - } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW; - -#ifdef UNICODE - typedef WNDCLASSW WNDCLASS; - typedef PWNDCLASSW PWNDCLASS; - typedef NPWNDCLASSW NPWNDCLASS; - typedef LPWNDCLASSW LPWNDCLASS; -#else - typedef WNDCLASSA WNDCLASS; - typedef PWNDCLASSA PWNDCLASS; - typedef NPWNDCLASSA NPWNDCLASS; - typedef LPWNDCLASSA LPWNDCLASS; -#endif - - WINUSERAPI WINBOOL WINAPI IsHungAppWindow(HWND hwnd); - WINUSERAPI VOID WINAPI DisableProcessWindowsGhosting(VOID); - -#ifndef NOMSG - typedef struct tagMSG { - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - DWORD time; - POINT pt; - } MSG,*PMSG,*NPMSG,*LPMSG; - -#define POINTSTOPOINT(pt,pts) { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } - -#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x),(short)((pt).y))) -#define MAKEWPARAM(l,h) ((WPARAM)(DWORD)MAKELONG(l,h)) -#define MAKELPARAM(l,h) ((LPARAM)(DWORD)MAKELONG(l,h)) -#define MAKELRESULT(l,h) ((LRESULT)(DWORD)MAKELONG(l,h)) -#endif - -#ifndef NOWINOFFSETS -#define GWL_WNDPROC (-4) -#define GWL_HINSTANCE (-6) -#define GWL_HWNDPARENT (-8) -#define GWL_STYLE (-16) -#define GWL_EXSTYLE (-20) -#define GWL_USERDATA (-21) -#define GWL_ID (-12) - -#ifdef _WIN64 -#undef GWL_WNDPROC -#undef GWL_HINSTANCE -#undef GWL_HWNDPARENT -#undef GWL_USERDATA -#endif - -#define GWLP_WNDPROC (-4) -#define GWLP_HINSTANCE (-6) -#define GWLP_HWNDPARENT (-8) -#define GWLP_USERDATA (-21) -#define GWLP_ID (-12) - -#define GCL_MENUNAME (-8) -#define GCL_HBRBACKGROUND (-10) -#define GCL_HCURSOR (-12) -#define GCL_HICON (-14) -#define GCL_HMODULE (-16) -#define GCL_CBWNDEXTRA (-18) -#define GCL_CBCLSEXTRA (-20) -#define GCL_WNDPROC (-24) -#define GCL_STYLE (-26) -#define GCW_ATOM (-32) -#define GCL_HICONSM (-34) - -#ifdef _WIN64 - -#undef GCL_MENUNAME -#undef GCL_HBRBACKGROUND -#undef GCL_HCURSOR -#undef GCL_HICON -#undef GCL_HMODULE -#undef GCL_WNDPROC -#undef GCL_HICONSM -#endif - -#define GCLP_MENUNAME (-8) -#define GCLP_HBRBACKGROUND (-10) -#define GCLP_HCURSOR (-12) -#define GCLP_HICON (-14) -#define GCLP_HMODULE (-16) -#define GCLP_WNDPROC (-24) -#define GCLP_HICONSM (-34) -#endif - -#ifndef NOWINMESSAGES - -#define WM_NULL 0x0000 -#define WM_CREATE 0x0001 -#define WM_DESTROY 0x0002 -#define WM_MOVE 0x0003 -#define WM_SIZE 0x0005 - -#define WM_ACTIVATE 0x0006 - -#define WA_INACTIVE 0 -#define WA_ACTIVE 1 -#define WA_CLICKACTIVE 2 - -#define WM_SETFOCUS 0x0007 -#define WM_KILLFOCUS 0x0008 -#define WM_ENABLE 0x000A -#define WM_SETREDRAW 0x000B -#define WM_SETTEXT 0x000C -#define WM_GETTEXT 0x000D -#define WM_GETTEXTLENGTH 0x000E -#define WM_PAINT 0x000F -#define WM_CLOSE 0x0010 -#ifndef _WIN32_WCE -#define WM_QUERYENDSESSION 0x0011 -#define WM_QUERYOPEN 0x0013 -#define WM_ENDSESSION 0x0016 -#endif -#define WM_QUIT 0x0012 -#define WM_ERASEBKGND 0x0014 -#define WM_SYSCOLORCHANGE 0x0015 -#define WM_SHOWWINDOW 0x0018 -#define WM_WININICHANGE 0x001A -#define WM_SETTINGCHANGE WM_WININICHANGE -#define WM_DEVMODECHANGE 0x001B -#define WM_ACTIVATEAPP 0x001C -#define WM_FONTCHANGE 0x001D -#define WM_TIMECHANGE 0x001E -#define WM_CANCELMODE 0x001F -#define WM_SETCURSOR 0x0020 -#define WM_MOUSEACTIVATE 0x0021 -#define WM_CHILDACTIVATE 0x0022 -#define WM_QUEUESYNC 0x0023 - -#define WM_GETMINMAXINFO 0x0024 - - typedef struct tagMINMAXINFO { - POINT ptReserved; - POINT ptMaxSize; - POINT ptMaxPosition; - POINT ptMinTrackSize; - POINT ptMaxTrackSize; - } MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO; - -#define WM_PAINTICON 0x0026 -#define WM_ICONERASEBKGND 0x0027 -#define WM_NEXTDLGCTL 0x0028 -#define WM_SPOOLERSTATUS 0x002A -#define WM_DRAWITEM 0x002B -#define WM_MEASUREITEM 0x002C -#define WM_DELETEITEM 0x002D -#define WM_VKEYTOITEM 0x002E -#define WM_CHARTOITEM 0x002F -#define WM_SETFONT 0x0030 -#define WM_GETFONT 0x0031 -#define WM_SETHOTKEY 0x0032 -#define WM_GETHOTKEY 0x0033 -#define WM_QUERYDRAGICON 0x0037 -#define WM_COMPAREITEM 0x0039 -#ifndef _WIN32_WCE -#define WM_GETOBJECT 0x003D -#endif -#define WM_COMPACTING 0x0041 -#define WM_COMMNOTIFY 0x0044 -#define WM_WINDOWPOSCHANGING 0x0046 -#define WM_WINDOWPOSCHANGED 0x0047 - -#define WM_POWER 0x0048 - -#define PWR_OK 1 -#define PWR_FAIL (-1) -#define PWR_SUSPENDREQUEST 1 -#define PWR_SUSPENDRESUME 2 -#define PWR_CRITICALRESUME 3 - -#define WM_COPYDATA 0x004A -#define WM_CANCELJOURNAL 0x004B - - typedef struct tagCOPYDATASTRUCT { - ULONG_PTR dwData; - DWORD cbData; - PVOID lpData; - } COPYDATASTRUCT,*PCOPYDATASTRUCT; - - typedef struct tagMDINEXTMENU { - HMENU hmenuIn; - HMENU hmenuNext; - HWND hwndNext; - } MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU; - -#define WM_NOTIFY 0x004E -#define WM_INPUTLANGCHANGEREQUEST 0x0050 -#define WM_INPUTLANGCHANGE 0x0051 -#define WM_TCARD 0x0052 -#define WM_HELP 0x0053 -#define WM_USERCHANGED 0x0054 -#define WM_NOTIFYFORMAT 0x0055 - -#define NFR_ANSI 1 -#define NFR_UNICODE 2 -#define NF_QUERY 3 -#define NF_REQUERY 4 - -#define WM_CONTEXTMENU 0x007B -#define WM_STYLECHANGING 0x007C -#define WM_STYLECHANGED 0x007D -#define WM_DISPLAYCHANGE 0x007E -#define WM_GETICON 0x007F -#define WM_SETICON 0x0080 - -#define WM_NCCREATE 0x0081 -#define WM_NCDESTROY 0x0082 -#define WM_NCCALCSIZE 0x0083 -#define WM_NCHITTEST 0x0084 -#define WM_NCPAINT 0x0085 -#define WM_NCACTIVATE 0x0086 -#define WM_GETDLGCODE 0x0087 -#ifndef _WIN32_WCE -#define WM_SYNCPAINT 0x0088 -#endif -#define WM_NCMOUSEMOVE 0x00A0 -#define WM_NCLBUTTONDOWN 0x00A1 -#define WM_NCLBUTTONUP 0x00A2 -#define WM_NCLBUTTONDBLCLK 0x00A3 -#define WM_NCRBUTTONDOWN 0x00A4 -#define WM_NCRBUTTONUP 0x00A5 -#define WM_NCRBUTTONDBLCLK 0x00A6 -#define WM_NCMBUTTONDOWN 0x00A7 -#define WM_NCMBUTTONUP 0x00A8 -#define WM_NCMBUTTONDBLCLK 0x00A9 - -#define WM_NCXBUTTONDOWN 0x00AB -#define WM_NCXBUTTONUP 0x00AC -#define WM_NCXBUTTONDBLCLK 0x00AD -#define WM_INPUT 0x00FF -#define WM_KEYFIRST 0x0100 -#define WM_KEYDOWN 0x0100 -#define WM_KEYUP 0x0101 -#define WM_CHAR 0x0102 -#define WM_DEADCHAR 0x0103 -#define WM_SYSKEYDOWN 0x0104 -#define WM_SYSKEYUP 0x0105 -#define WM_SYSCHAR 0x0106 -#define WM_SYSDEADCHAR 0x0107 -#define WM_UNICHAR 0x0109 -#define WM_KEYLAST 0x0109 -#define UNICODE_NOCHAR 0xFFFF -#define WM_IME_STARTCOMPOSITION 0x010D -#define WM_IME_ENDCOMPOSITION 0x010E -#define WM_IME_COMPOSITION 0x010F -#define WM_IME_KEYLAST 0x010F -#define WM_INITDIALOG 0x0110 -#define WM_COMMAND 0x0111 -#define WM_SYSCOMMAND 0x0112 -#define WM_TIMER 0x0113 -#define WM_HSCROLL 0x0114 -#define WM_VSCROLL 0x0115 -#define WM_INITMENU 0x0116 -#define WM_INITMENUPOPUP 0x0117 -#define WM_MENUSELECT 0x011F -#define WM_MENUCHAR 0x0120 -#define WM_ENTERIDLE 0x0121 -#ifndef _WIN32_WCE -#define WM_MENURBUTTONUP 0x0122 -#define WM_MENUDRAG 0x0123 -#define WM_MENUGETOBJECT 0x0124 -#define WM_UNINITMENUPOPUP 0x0125 -#define WM_MENUCOMMAND 0x0126 - -#ifndef _WIN32_WCE -#define WM_CHANGEUISTATE 0x0127 -#define WM_UPDATEUISTATE 0x0128 -#define WM_QUERYUISTATE 0x0129 - -#define UIS_SET 1 -#define UIS_CLEAR 2 -#define UIS_INITIALIZE 3 - -#define UISF_HIDEFOCUS 0x1 -#define UISF_HIDEACCEL 0x2 -#define UISF_ACTIVE 0x4 -#endif -#endif - -#define WM_CTLCOLORMSGBOX 0x0132 -#define WM_CTLCOLOREDIT 0x0133 -#define WM_CTLCOLORLISTBOX 0x0134 -#define WM_CTLCOLORBTN 0x0135 -#define WM_CTLCOLORDLG 0x0136 -#define WM_CTLCOLORSCROLLBAR 0x0137 -#define WM_CTLCOLORSTATIC 0x0138 -#define MN_GETHMENU 0x01E1 - -#define WM_MOUSEFIRST 0x0200 -#define WM_MOUSEMOVE 0x0200 -#define WM_LBUTTONDOWN 0x0201 -#define WM_LBUTTONUP 0x0202 -#define WM_LBUTTONDBLCLK 0x0203 -#define WM_RBUTTONDOWN 0x0204 -#define WM_RBUTTONUP 0x0205 -#define WM_RBUTTONDBLCLK 0x0206 -#define WM_MBUTTONDOWN 0x0207 -#define WM_MBUTTONUP 0x0208 -#define WM_MBUTTONDBLCLK 0x0209 -#define WM_MOUSEWHEEL 0x020A -#define WM_XBUTTONDOWN 0x020B -#define WM_XBUTTONUP 0x020C -#define WM_XBUTTONDBLCLK 0x020D -#define WM_MOUSELAST 0x020D - -#define WHEEL_DELTA 120 -#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) - -#define WHEEL_PAGESCROLL (UINT_MAX) - -#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) -#define GET_NCHITTEST_WPARAM(wParam) ((short)LOWORD(wParam)) -#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) - -#define XBUTTON1 0x0001 -#define XBUTTON2 0x0002 - -#define WM_PARENTNOTIFY 0x0210 -#define WM_ENTERMENULOOP 0x0211 -#define WM_EXITMENULOOP 0x0212 - -#define WM_NEXTMENU 0x0213 -#define WM_SIZING 0x0214 -#define WM_CAPTURECHANGED 0x0215 -#define WM_MOVING 0x0216 - -#define WM_POWERBROADCAST 0x0218 - -#ifndef _WIN32_WCE -#define PBT_APMQUERYSUSPEND 0x0000 -#define PBT_APMQUERYSTANDBY 0x0001 - -#define PBT_APMQUERYSUSPENDFAILED 0x0002 -#define PBT_APMQUERYSTANDBYFAILED 0x0003 - -#define PBT_APMSUSPEND 0x0004 -#define PBT_APMSTANDBY 0x0005 - -#define PBT_APMRESUMECRITICAL 0x0006 -#define PBT_APMRESUMESUSPEND 0x0007 -#define PBT_APMRESUMESTANDBY 0x0008 - -#define PBTF_APMRESUMEFROMFAILURE 0x00000001 - -#define PBT_APMBATTERYLOW 0x0009 -#define PBT_APMPOWERSTATUSCHANGE 0x000A - -#define PBT_APMOEMEVENT 0x000B -#define PBT_APMRESUMEAUTOMATIC 0x0012 -#endif - -#define WM_DEVICECHANGE 0x0219 - -#define WM_MDICREATE 0x0220 -#define WM_MDIDESTROY 0x0221 -#define WM_MDIACTIVATE 0x0222 -#define WM_MDIRESTORE 0x0223 -#define WM_MDINEXT 0x0224 -#define WM_MDIMAXIMIZE 0x0225 -#define WM_MDITILE 0x0226 -#define WM_MDICASCADE 0x0227 -#define WM_MDIICONARRANGE 0x0228 -#define WM_MDIGETACTIVE 0x0229 - -#define WM_MDISETMENU 0x0230 -#define WM_ENTERSIZEMOVE 0x0231 -#define WM_EXITSIZEMOVE 0x0232 -#define WM_DROPFILES 0x0233 -#define WM_MDIREFRESHMENU 0x0234 - -#define WM_IME_SETCONTEXT 0x0281 -#define WM_IME_NOTIFY 0x0282 -#define WM_IME_CONTROL 0x0283 -#define WM_IME_COMPOSITIONFULL 0x0284 -#define WM_IME_SELECT 0x0285 -#define WM_IME_CHAR 0x0286 -#define WM_IME_REQUEST 0x0288 -#define WM_IME_KEYDOWN 0x0290 -#define WM_IME_KEYUP 0x0291 - -#define WM_MOUSEHOVER 0x02A1 -#define WM_MOUSELEAVE 0x02A3 -#define WM_NCMOUSEHOVER 0x02A0 -#define WM_NCMOUSELEAVE 0x02A2 -#define WM_WTSSESSION_CHANGE 0x02B1 -#define WM_TABLET_FIRST 0x02c0 -#define WM_TABLET_LAST 0x02df -#define WM_CUT 0x0300 -#define WM_COPY 0x0301 -#define WM_PASTE 0x0302 -#define WM_CLEAR 0x0303 -#define WM_UNDO 0x0304 -#define WM_RENDERFORMAT 0x0305 -#define WM_RENDERALLFORMATS 0x0306 -#define WM_DESTROYCLIPBOARD 0x0307 -#define WM_DRAWCLIPBOARD 0x0308 -#define WM_PAINTCLIPBOARD 0x0309 -#define WM_VSCROLLCLIPBOARD 0x030A -#define WM_SIZECLIPBOARD 0x030B -#define WM_ASKCBFORMATNAME 0x030C -#define WM_CHANGECBCHAIN 0x030D -#define WM_HSCROLLCLIPBOARD 0x030E -#define WM_QUERYNEWPALETTE 0x030F -#define WM_PALETTEISCHANGING 0x0310 -#define WM_PALETTECHANGED 0x0311 -#define WM_HOTKEY 0x0312 -#define WM_PRINT 0x0317 -#define WM_PRINTCLIENT 0x0318 -#define WM_APPCOMMAND 0x0319 -#define WM_THEMECHANGED 0x031A -#define WM_HANDHELDFIRST 0x0358 -#define WM_HANDHELDLAST 0x035F -#define WM_AFXFIRST 0x0360 -#define WM_AFXLAST 0x037F -#define WM_PENWINFIRST 0x0380 -#define WM_PENWINLAST 0x038F -#define WM_APP 0x8000 -#define WM_USER 0x0400 - -#define WMSZ_LEFT 1 -#define WMSZ_RIGHT 2 -#define WMSZ_TOP 3 -#define WMSZ_TOPLEFT 4 -#define WMSZ_TOPRIGHT 5 -#define WMSZ_BOTTOM 6 -#define WMSZ_BOTTOMLEFT 7 -#define WMSZ_BOTTOMRIGHT 8 - -#ifndef NONCMESSAGES - -#define HTERROR (-2) -#define HTTRANSPARENT (-1) -#define HTNOWHERE 0 -#define HTCLIENT 1 -#define HTCAPTION 2 -#define HTSYSMENU 3 -#define HTGROWBOX 4 -#define HTSIZE HTGROWBOX -#define HTMENU 5 -#define HTHSCROLL 6 -#define HTVSCROLL 7 -#define HTMINBUTTON 8 -#define HTMAXBUTTON 9 -#define HTLEFT 10 -#define HTRIGHT 11 -#define HTTOP 12 -#define HTTOPLEFT 13 -#define HTTOPRIGHT 14 -#define HTBOTTOM 15 -#define HTBOTTOMLEFT 16 -#define HTBOTTOMRIGHT 17 -#define HTBORDER 18 -#define HTREDUCE HTMINBUTTON -#define HTZOOM HTMAXBUTTON -#define HTSIZEFIRST HTLEFT -#define HTSIZELAST HTBOTTOMRIGHT -#define HTOBJECT 19 -#define HTCLOSE 20 -#define HTHELP 21 - -#define SMTO_NORMAL 0x0000 -#define SMTO_BLOCK 0x0001 -#define SMTO_ABORTIFHUNG 0x0002 -#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 -#endif - -#define MA_ACTIVATE 1 -#define MA_ACTIVATEANDEAT 2 -#define MA_NOACTIVATE 3 -#define MA_NOACTIVATEANDEAT 4 - -#define ICON_SMALL 0 -#define ICON_BIG 1 -#define ICON_SMALL2 2 - -#ifdef UNICODE -#define RegisterWindowMessage RegisterWindowMessageW -#else -#define RegisterWindowMessage RegisterWindowMessageA -#endif - - WINUSERAPI UINT WINAPI RegisterWindowMessageA(LPCSTR lpString); - WINUSERAPI UINT WINAPI RegisterWindowMessageW(LPCWSTR lpString); - -#define SIZE_RESTORED 0 -#define SIZE_MINIMIZED 1 -#define SIZE_MAXIMIZED 2 -#define SIZE_MAXSHOW 3 -#define SIZE_MAXHIDE 4 - -#define SIZENORMAL SIZE_RESTORED -#define SIZEICONIC SIZE_MINIMIZED -#define SIZEFULLSCREEN SIZE_MAXIMIZED -#define SIZEZOOMSHOW SIZE_MAXSHOW -#define SIZEZOOMHIDE SIZE_MAXHIDE - - typedef struct tagWINDOWPOS { - HWND hwnd; - HWND hwndInsertAfter; - int x; - int y; - int cx; - int cy; - UINT flags; - } WINDOWPOS,*LPWINDOWPOS,*PWINDOWPOS; - - typedef struct tagNCCALCSIZE_PARAMS { - RECT rgrc[3]; - PWINDOWPOS lppos; - } NCCALCSIZE_PARAMS,*LPNCCALCSIZE_PARAMS; - -#define WVR_ALIGNTOP 0x0010 -#define WVR_ALIGNLEFT 0x0020 -#define WVR_ALIGNBOTTOM 0x0040 -#define WVR_ALIGNRIGHT 0x0080 -#define WVR_HREDRAW 0x0100 -#define WVR_VREDRAW 0x0200 -#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) -#define WVR_VALIDRECTS 0x0400 - -#ifndef NOKEYSTATES - -#define MK_LBUTTON 0x0001 -#define MK_RBUTTON 0x0002 -#define MK_SHIFT 0x0004 -#define MK_CONTROL 0x0008 -#define MK_MBUTTON 0x0010 -#define MK_XBUTTON1 0x0020 -#define MK_XBUTTON2 0x0040 -#endif - -#ifndef NOTRACKMOUSEEVENT -#define TME_HOVER 0x00000001 -#define TME_LEAVE 0x00000002 -#define TME_NONCLIENT 0x00000010 -#define TME_QUERY 0x40000000 -#define TME_CANCEL 0x80000000 - -#define HOVER_DEFAULT 0xFFFFFFFF -#endif - - typedef struct tagTRACKMOUSEEVENT { - DWORD cbSize; - DWORD dwFlags; - HWND hwndTrack; - DWORD dwHoverTime; - } TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT; - - WINUSERAPI WINBOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); -#endif - -#ifndef NOWINSTYLES - -#define WS_OVERLAPPED 0x00000000L -#define WS_POPUP 0x80000000L -#define WS_CHILD 0x40000000L -#define WS_MINIMIZE 0x20000000L -#define WS_VISIBLE 0x10000000L -#define WS_DISABLED 0x08000000L -#define WS_CLIPSIBLINGS 0x04000000L -#define WS_CLIPCHILDREN 0x02000000L -#define WS_MAXIMIZE 0x01000000L -#define WS_CAPTION 0x00C00000L -#define WS_BORDER 0x00800000L -#define WS_DLGFRAME 0x00400000L -#define WS_VSCROLL 0x00200000L -#define WS_HSCROLL 0x00100000L -#define WS_SYSMENU 0x00080000L -#define WS_THICKFRAME 0x00040000L -#define WS_GROUP 0x00020000L -#define WS_TABSTOP 0x00010000L -#define WS_MINIMIZEBOX 0x00020000L -#define WS_MAXIMIZEBOX 0x00010000L -#define WS_TILED WS_OVERLAPPED -#define WS_ICONIC WS_MINIMIZE -#define WS_SIZEBOX WS_THICKFRAME -#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW -#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) -#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) -#define WS_CHILDWINDOW (WS_CHILD) - -#define WS_EX_DLGMODALFRAME 0x00000001L -#define WS_EX_NOPARENTNOTIFY 0x00000004L -#define WS_EX_TOPMOST 0x00000008L -#define WS_EX_ACCEPTFILES 0x00000010L -#define WS_EX_TRANSPARENT 0x00000020L -#define WS_EX_MDICHILD 0x00000040L -#define WS_EX_TOOLWINDOW 0x00000080L -#define WS_EX_WINDOWEDGE 0x00000100L -#define WS_EX_CLIENTEDGE 0x00000200L -#define WS_EX_CONTEXTHELP 0x00000400L -#define WS_EX_RIGHT 0x00001000L -#define WS_EX_LEFT 0x00000000L -#define WS_EX_RTLREADING 0x00002000L -#define WS_EX_LTRREADING 0x00000000L -#define WS_EX_LEFTSCROLLBAR 0x00004000L -#define WS_EX_RIGHTSCROLLBAR 0x00000000L -#define WS_EX_CONTROLPARENT 0x00010000L -#define WS_EX_STATICEDGE 0x00020000L -#define WS_EX_APPWINDOW 0x00040000L -#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) -#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) -#define WS_EX_LAYERED 0x00080000 -#define WS_EX_NOINHERITLAYOUT 0x00100000L -#define WS_EX_LAYOUTRTL 0x00400000L -#define WS_EX_COMPOSITED 0x02000000L -#define WS_EX_NOACTIVATE 0x08000000L - -#define CS_VREDRAW 0x0001 -#define CS_HREDRAW 0x0002 -#define CS_DBLCLKS 0x0008 -#define CS_OWNDC 0x0020 -#define CS_CLASSDC 0x0040 -#define CS_PARENTDC 0x0080 -#define CS_NOCLOSE 0x0200 -#define CS_SAVEBITS 0x0800 -#define CS_BYTEALIGNCLIENT 0x1000 -#define CS_BYTEALIGNWINDOW 0x2000 -#define CS_GLOBALCLASS 0x4000 -#define CS_IME 0x00010000 -#define CS_DROPSHADOW 0x00020000 -#endif - -#define PRF_CHECKVISIBLE 0x00000001L -#define PRF_NONCLIENT 0x00000002L -#define PRF_CLIENT 0x00000004L -#define PRF_ERASEBKGND 0x00000008L -#define PRF_CHILDREN 0x00000010L -#define PRF_OWNED 0x00000020L - -#define BDR_RAISEDOUTER 0x0001 -#define BDR_SUNKENOUTER 0x0002 -#define BDR_RAISEDINNER 0x0004 -#define BDR_SUNKENINNER 0x0008 - -#define BDR_OUTER (BDR_RAISEDOUTER | BDR_SUNKENOUTER) -#define BDR_INNER (BDR_RAISEDINNER | BDR_SUNKENINNER) -#define BDR_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) -#define BDR_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) - -#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) -#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) -#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) -#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) - -#define BF_LEFT 0x0001 -#define BF_TOP 0x0002 -#define BF_RIGHT 0x0004 -#define BF_BOTTOM 0x0008 - -#define BF_TOPLEFT (BF_TOP | BF_LEFT) -#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) -#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) -#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) -#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) - -#define BF_DIAGONAL 0x0010 - -#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) -#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) -#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) -#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) - -#define BF_MIDDLE 0x0800 -#define BF_SOFT 0x1000 -#define BF_ADJUST 0x2000 -#define BF_FLAT 0x4000 -#define BF_MONO 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawEdge(HDC hdc,LPRECT qrc,UINT edge,UINT grfFlags); - -#define DFC_CAPTION 1 -#define DFC_MENU 2 -#define DFC_SCROLL 3 -#define DFC_BUTTON 4 -#define DFC_POPUPMENU 5 - -#define DFCS_CAPTIONCLOSE 0x0000 -#define DFCS_CAPTIONMIN 0x0001 -#define DFCS_CAPTIONMAX 0x0002 -#define DFCS_CAPTIONRESTORE 0x0003 -#define DFCS_CAPTIONHELP 0x0004 - -#define DFCS_MENUARROW 0x0000 -#define DFCS_MENUCHECK 0x0001 -#define DFCS_MENUBULLET 0x0002 -#define DFCS_MENUARROWRIGHT 0x0004 -#define DFCS_SCROLLUP 0x0000 -#define DFCS_SCROLLDOWN 0x0001 -#define DFCS_SCROLLLEFT 0x0002 -#define DFCS_SCROLLRIGHT 0x0003 -#define DFCS_SCROLLCOMBOBOX 0x0005 -#define DFCS_SCROLLSIZEGRIP 0x0008 -#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 - -#define DFCS_BUTTONCHECK 0x0000 -#define DFCS_BUTTONRADIOIMAGE 0x0001 -#define DFCS_BUTTONRADIOMASK 0x0002 -#define DFCS_BUTTONRADIO 0x0004 -#define DFCS_BUTTON3STATE 0x0008 -#define DFCS_BUTTONPUSH 0x0010 - -#define DFCS_INACTIVE 0x0100 -#define DFCS_PUSHED 0x0200 -#define DFCS_CHECKED 0x0400 - -#define DFCS_TRANSPARENT 0x0800 -#define DFCS_HOT 0x1000 - -#define DFCS_ADJUSTRECT 0x2000 -#define DFCS_FLAT 0x4000 -#define DFCS_MONO 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT); - -#define DC_ACTIVE 0x0001 -#define DC_SMALLCAP 0x0002 -#define DC_ICON 0x0004 -#define DC_TEXT 0x0008 -#define DC_INBUTTON 0x0010 -#define DC_GRADIENT 0x0020 -#define DC_BUTTONS 0x1000 - - WINUSERAPI WINBOOL WINAPI DrawCaption(HWND hwnd,HDC hdc,CONST RECT *lprect,UINT flags); - -#define IDANI_OPEN 1 -#define IDANI_CAPTION 3 - - WINUSERAPI WINBOOL WINAPI DrawAnimatedRects(HWND hwnd,int idAni,CONST RECT *lprcFrom,CONST RECT *lprcTo); - -#ifndef NOCLIPBOARD - -#define CF_TEXT 1 -#define CF_BITMAP 2 -#define CF_METAFILEPICT 3 -#define CF_SYLK 4 -#define CF_DIF 5 -#define CF_TIFF 6 -#define CF_OEMTEXT 7 -#define CF_DIB 8 -#define CF_PALETTE 9 -#define CF_PENDATA 10 -#define CF_RIFF 11 -#define CF_WAVE 12 -#define CF_UNICODETEXT 13 -#define CF_ENHMETAFILE 14 -#define CF_HDROP 15 -#define CF_LOCALE 16 -#define CF_DIBV5 17 -#define CF_MAX 18 - -#define CF_OWNERDISPLAY 0x0080 -#define CF_DSPTEXT 0x0081 -#define CF_DSPBITMAP 0x0082 -#define CF_DSPMETAFILEPICT 0x0083 -#define CF_DSPENHMETAFILE 0x008E - -#define CF_PRIVATEFIRST 0x0200 -#define CF_PRIVATELAST 0x02FF - -#define CF_GDIOBJFIRST 0x0300 -#define CF_GDIOBJLAST 0x03FF -#endif - -#define FVIRTKEY TRUE -#define FNOINVERT 0x02 -#define FSHIFT 0x04 -#define FCONTROL 0x08 -#define FALT 0x10 - - typedef struct tagACCEL { - BYTE fVirt; - WORD key; - WORD cmd; - } ACCEL,*LPACCEL; - - typedef struct tagPAINTSTRUCT { - HDC hdc; - WINBOOL fErase; - RECT rcPaint; - WINBOOL fRestore; - WINBOOL fIncUpdate; - BYTE rgbReserved[32]; - } PAINTSTRUCT,*PPAINTSTRUCT,*NPPAINTSTRUCT,*LPPAINTSTRUCT; - - typedef struct tagCREATESTRUCTA { - LPVOID lpCreateParams; - HINSTANCE hInstance; - HMENU hMenu; - HWND hwndParent; - int cy; - int cx; - int y; - int x; - LONG style; - LPCSTR lpszName; - LPCSTR lpszClass; - DWORD dwExStyle; - } CREATESTRUCTA,*LPCREATESTRUCTA; - - typedef struct tagCREATESTRUCTW { - LPVOID lpCreateParams; - HINSTANCE hInstance; - HMENU hMenu; - HWND hwndParent; - int cy; - int cx; - int y; - int x; - LONG style; - LPCWSTR lpszName; - LPCWSTR lpszClass; - DWORD dwExStyle; - } CREATESTRUCTW,*LPCREATESTRUCTW; - -#ifdef UNICODE - typedef CREATESTRUCTW CREATESTRUCT; - typedef LPCREATESTRUCTW LPCREATESTRUCT; -#else - typedef CREATESTRUCTA CREATESTRUCT; - typedef LPCREATESTRUCTA LPCREATESTRUCT; -#endif - - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT,*LPWINDOWPLACEMENT; - -#define WPF_SETMINPOSITION 0x0001 -#define WPF_RESTORETOMAXIMIZED 0x0002 -#define WPF_ASYNCWINDOWPLACEMENT 0x0004 - - typedef struct tagNMHDR { - HWND hwndFrom; - UINT_PTR idFrom; - UINT code; - } NMHDR; - - typedef NMHDR *LPNMHDR; - - typedef struct tagSTYLESTRUCT { - DWORD styleOld; - DWORD styleNew; - } STYLESTRUCT,*LPSTYLESTRUCT; - -#define ODT_MENU 1 -#define ODT_LISTBOX 2 -#define ODT_COMBOBOX 3 -#define ODT_BUTTON 4 -#define ODT_STATIC 5 - -#define ODA_DRAWENTIRE 0x0001 -#define ODA_SELECT 0x0002 -#define ODA_FOCUS 0x0004 - -#define ODS_SELECTED 0x0001 -#define ODS_GRAYED 0x0002 -#define ODS_DISABLED 0x0004 -#define ODS_CHECKED 0x0008 -#define ODS_FOCUS 0x0010 -#define ODS_DEFAULT 0x0020 -#define ODS_COMBOBOXEDIT 0x1000 -#define ODS_HOTLIGHT 0x0040 -#define ODS_INACTIVE 0x0080 -#define ODS_NOACCEL 0x0100 -#define ODS_NOFOCUSRECT 0x0200 - - typedef struct tagMEASUREITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - UINT itemWidth; - UINT itemHeight; - ULONG_PTR itemData; - } MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT; - - typedef struct tagDRAWITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - UINT itemAction; - UINT itemState; - HWND hwndItem; - HDC hDC; - RECT rcItem; - ULONG_PTR itemData; - } DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,*LPDRAWITEMSTRUCT; - - typedef struct tagDELETEITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - HWND hwndItem; - ULONG_PTR itemData; - } DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT; - - typedef struct tagCOMPAREITEMSTRUCT { - UINT CtlType; - UINT CtlID; - HWND hwndItem; - UINT itemID1; - ULONG_PTR itemData1; - UINT itemID2; - ULONG_PTR itemData2; - DWORD dwLocaleId; - } COMPAREITEMSTRUCT,*PCOMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT; - -#ifndef NOMSG -#ifdef UNICODE -#define GetMessage GetMessageW -#define DispatchMessage DispatchMessageW -#define PeekMessage PeekMessageW -#else -#define GetMessage GetMessageA -#define DispatchMessage DispatchMessageA -#define PeekMessage PeekMessageA -#endif - - WINUSERAPI WINBOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); - WINUSERAPI WINBOOL WINAPI GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); - WINUSERAPI WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); - WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); - WINUSERAPI LRESULT WINAPI DispatchMessageW(CONST MSG *lpMsg); - WINUSERAPI WINBOOL WINAPI SetMessageQueue(int cMessagesMax); - WINUSERAPI WINBOOL WINAPI PeekMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); - WINUSERAPI WINBOOL WINAPI PeekMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); - -#define PM_NOREMOVE 0x0000 -#define PM_REMOVE 0x0001 -#define PM_NOYIELD 0x0002 -#define PM_QS_INPUT (QS_INPUT << 16) -#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) -#define PM_QS_PAINT (QS_PAINT << 16) -#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) -#endif - - WINUSERAPI WINBOOL WINAPI RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk); - WINUSERAPI WINBOOL WINAPI UnregisterHotKey(HWND hWnd,int id); - -#define MOD_ALT 0x0001 -#define MOD_CONTROL 0x0002 -#define MOD_SHIFT 0x0004 -#define MOD_WIN 0x0008 - -#define IDHOT_SNAPWINDOW (-1) -#define IDHOT_SNAPDESKTOP (-2) - -#ifdef WIN_INTERNAL -#ifndef LSTRING -#define NOLSTRING -#endif -#ifndef LFILEIO -#define NOLFILEIO -#endif -#endif - -#define ENDSESSION_LOGOFF 0x80000000 - -#define EWX_LOGOFF 0 -#define EWX_SHUTDOWN 0x00000001 -#define EWX_REBOOT 0x00000002 -#define EWX_FORCE 0x00000004 -#define EWX_POWEROFF 0x00000008 -#define EWX_FORCEIFHUNG 0x00000010 - -#define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) - -#ifdef UNICODE -#define SendMessage SendMessageW -#define SendMessageTimeout SendMessageTimeoutW -#define SendNotifyMessage SendNotifyMessageW -#define SendMessageCallback SendMessageCallbackW -#else -#define SendMessage SendMessageA -#define SendMessageTimeout SendMessageTimeoutA -#define SendNotifyMessage SendNotifyMessageA -#define SendMessageCallback SendMessageCallbackA -#endif - - WINUSERAPI WINBOOL WINAPI ExitWindowsEx(UINT uFlags,DWORD dwReason); - WINUSERAPI WINBOOL WINAPI SwapMouseButton(WINBOOL fSwap); - WINUSERAPI DWORD WINAPI GetMessagePos(VOID); - WINUSERAPI LONG WINAPI GetMessageTime(VOID); - WINUSERAPI LPARAM WINAPI GetMessageExtraInfo(VOID); - WINUSERAPI WINBOOL WINAPI IsWow64Message(VOID); - WINUSERAPI LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageTimeoutA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); - WINUSERAPI LRESULT WINAPI SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); - WINUSERAPI WINBOOL WINAPI SendNotifyMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SendNotifyMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SendMessageCallbackA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); - WINUSERAPI WINBOOL WINAPI SendMessageCallbackW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); - - typedef struct { - UINT cbSize; - HDESK hdesk; - HWND hwnd; - LUID luid; - } BSMINFO,*PBSMINFO; - -#ifdef UNICODE -#define BroadcastSystemMessageEx BroadcastSystemMessageExW -#define BroadcastSystemMessage BroadcastSystemMessageW -#else -#define BroadcastSystemMessageEx BroadcastSystemMessageExA -#define BroadcastSystemMessage BroadcastSystemMessageA -#endif - - WINUSERAPI long WINAPI BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); - WINUSERAPI long WINAPI BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); - WINUSERAPI long WINAPI BroadcastSystemMessageA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI long WINAPI BroadcastSystemMessageW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); - -#define BSM_ALLCOMPONENTS 0x00000000 -#define BSM_VXDS 0x00000001 -#define BSM_NETDRIVER 0x00000002 -#define BSM_INSTALLABLEDRIVERS 0x00000004 -#define BSM_APPLICATIONS 0x00000008 -#define BSM_ALLDESKTOPS 0x00000010 - -#define BSF_QUERY 0x00000001 -#define BSF_IGNORECURRENTTASK 0x00000002 -#define BSF_FLUSHDISK 0x00000004 -#define BSF_NOHANG 0x00000008 -#define BSF_POSTMESSAGE 0x00000010 -#define BSF_FORCEIFHUNG 0x00000020 -#define BSF_NOTIMEOUTIFNOTHUNG 0x00000040 -#define BSF_ALLOWSFW 0x00000080 -#define BSF_SENDNOTIFYMESSAGE 0x00000100 -#define BSF_RETURNHDESK 0x00000200 -#define BSF_LUID 0x00000400 - -#define BROADCAST_QUERY_DENY 0x424D5144 - - typedef PVOID HDEVNOTIFY; - typedef HDEVNOTIFY *PHDEVNOTIFY; - -#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 -#define DEVICE_NOTIFY_SERVICE_HANDLE 0x00000001 -#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 - -#ifdef UNICODE -#define RegisterDeviceNotification RegisterDeviceNotificationW -#define PostMessage PostMessageW -#define PostThreadMessage PostThreadMessageW -#define PostAppMessage PostAppMessageW -#define DefWindowProc DefWindowProcW -#define CallWindowProc CallWindowProcW -#define RegisterClass RegisterClassW -#define UnregisterClass UnregisterClassW -#define GetClassInfo GetClassInfoW -#define RegisterClassEx RegisterClassExW -#define GetClassInfoEx GetClassInfoExW -#else -#define RegisterDeviceNotification RegisterDeviceNotificationA -#define PostMessage PostMessageA -#define PostThreadMessage PostThreadMessageA -#define PostAppMessage PostAppMessageA -#define DefWindowProc DefWindowProcA -#define CallWindowProc CallWindowProcA -#define RegisterClass RegisterClassA -#define UnregisterClass UnregisterClassA -#define GetClassInfo GetClassInfoA -#define RegisterClassEx RegisterClassExA -#define GetClassInfoEx GetClassInfoExA -#endif - - WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); - WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); - WINUSERAPI WINBOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); - WINUSERAPI WINBOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostThreadMessageA(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostThreadMessageW(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); -#define PostAppMessageA(idThread,wMsg,wParam,lParam) PostThreadMessageA((DWORD)idThread,wMsg,wParam,lParam) -#define PostAppMessageW(idThread,wMsg,wParam,lParam) PostThreadMessageW((DWORD)idThread,wMsg,wParam,lParam) - -#define HWND_BROADCAST ((HWND)0xffff) -#define HWND_MESSAGE ((HWND)-3) - - WINUSERAPI WINBOOL WINAPI AttachThreadInput(DWORD idAttach,DWORD idAttachTo,WINBOOL fAttach); - WINUSERAPI WINBOOL WINAPI ReplyMessage(LRESULT lResult); - WINUSERAPI WINBOOL WINAPI WaitMessage(VOID); - WINUSERAPI DWORD WINAPI WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds); - WINUSERAPI LRESULT WINAPI DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI VOID WINAPI PostQuitMessage(int nExitCode); - WINUSERAPI LRESULT WINAPI CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI CallWindowProcW(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI InSendMessage(VOID); - WINUSERAPI DWORD WINAPI InSendMessageEx(LPVOID lpReserved); - -#define ISMEX_NOSEND 0x00000000 -#define ISMEX_SEND 0x00000001 -#define ISMEX_NOTIFY 0x00000002 -#define ISMEX_CALLBACK 0x00000004 -#define ISMEX_REPLIED 0x00000008 - - WINUSERAPI UINT WINAPI GetDoubleClickTime(VOID); - WINUSERAPI WINBOOL WINAPI SetDoubleClickTime(UINT); - WINUSERAPI ATOM WINAPI RegisterClassA(CONST WNDCLASSA *lpWndClass); - WINUSERAPI ATOM WINAPI RegisterClassW(CONST WNDCLASSW *lpWndClass); - WINUSERAPI WINBOOL WINAPI UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance); - WINUSERAPI WINBOOL WINAPI UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance); - WINUSERAPI WINBOOL WINAPI GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); - WINUSERAPI WINBOOL WINAPI GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass); - WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *); - WINUSERAPI ATOM WINAPI RegisterClassExW(CONST WNDCLASSEXW *); - WINUSERAPI WINBOOL WINAPI GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx); - WINUSERAPI WINBOOL WINAPI GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx); - -#define CW_USEDEFAULT ((int)0x80000000) - -#define HWND_DESKTOP ((HWND)0) - - typedef BOOLEAN (WINAPI *PREGISTERCLASSNAMEW)(LPCWSTR); - -#ifdef UNICODE -#define CreateWindowEx CreateWindowExW -#define CreateWindow CreateWindowW -#else -#define CreateWindowEx CreateWindowExA -#define CreateWindow CreateWindowA -#endif - - WINUSERAPI HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); - WINUSERAPI HWND WINAPI CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); -#define CreateWindowA(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExA(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) -#define CreateWindowW(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExW(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) - WINUSERAPI WINBOOL WINAPI IsWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsMenu(HMENU hMenu); - WINUSERAPI WINBOOL WINAPI IsChild(HWND hWndParent,HWND hWnd); - WINUSERAPI WINBOOL WINAPI DestroyWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ShowWindow(HWND hWnd,int nCmdShow); - WINUSERAPI WINBOOL WINAPI AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags); - -#if defined(_WINGDI_) && !defined(NOGDI) - WINUSERAPI WINBOOL WINAPI UpdateLayeredWindow(HWND hWnd,HDC hdcDst,POINT *pptDst,SIZE *psize,HDC hdcSrc,POINT *pptSrc,COLORREF crKey,BLENDFUNCTION *pblend,DWORD dwFlags); - - typedef struct tagUPDATELAYEREDWINDOWINFO { - DWORD cbSize; - HDC hdcDst; - POINT CONST *pptDst; - SIZE CONST *psize; - HDC hdcSrc; - POINT CONST *pptSrc; - COLORREF crKey; - BLENDFUNCTION CONST *pblend; - DWORD dwFlags; - RECT CONST *prcDirty; - } UPDATELAYEREDWINDOWINFO,*PUPDATELAYEREDWINDOWINFO; - - WINUSERAPI WINBOOL WINAPI UpdateLayeredWindowIndirect(HWND hWnd,UPDATELAYEREDWINDOWINFO CONST *pULWInfo); - WINUSERAPI WINBOOL WINAPI GetLayeredWindowAttributes(HWND hwnd,COLORREF *pcrKey,BYTE *pbAlpha,DWORD *pdwFlags); - -#define PW_CLIENTONLY 0x00000001 - - WINUSERAPI WINBOOL WINAPI PrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags); - WINUSERAPI WINBOOL WINAPI SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags); - -#define LWA_COLORKEY 0x00000001 -#define LWA_ALPHA 0x00000002 - -#define ULW_COLORKEY 0x00000001 -#define ULW_ALPHA 0x00000002 -#define ULW_OPAQUE 0x00000004 - -#define ULW_EX_NORESIZE 0x00000008 - - WINUSERAPI WINBOOL WINAPI ShowWindowAsync(HWND hWnd,int nCmdShow); - WINUSERAPI WINBOOL WINAPI FlashWindow(HWND hWnd,WINBOOL bInvert); - - typedef struct { - UINT cbSize; - HWND hwnd; - DWORD dwFlags; - UINT uCount; - DWORD dwTimeout; - } FLASHWINFO,*PFLASHWINFO; - - WINUSERAPI WINBOOL WINAPI FlashWindowEx(PFLASHWINFO pfwi); - -#define FLASHW_STOP 0 -#define FLASHW_CAPTION 0x00000001 -#define FLASHW_TRAY 0x00000002 -#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) -#define FLASHW_TIMER 0x00000004 -#define FLASHW_TIMERNOFG 0x0000000C - - WINUSERAPI WINBOOL WINAPI ShowOwnedPopups(HWND hWnd,WINBOOL fShow); - WINUSERAPI WINBOOL WINAPI OpenIcon(HWND hWnd); - WINUSERAPI WINBOOL WINAPI CloseWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI MoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,WINBOOL bRepaint); - WINUSERAPI WINBOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI GetWindowPlacement(HWND hWnd,WINDOWPLACEMENT *lpwndpl); - WINUSERAPI WINBOOL WINAPI SetWindowPlacement(HWND hWnd,CONST WINDOWPLACEMENT *lpwndpl); - -#ifndef NODEFERWINDOWPOS - WINUSERAPI HDWP WINAPI BeginDeferWindowPos(int nNumWindows); - WINUSERAPI HDWP WINAPI DeferWindowPos(HDWP hWinPosInfo,HWND hWnd,HWND hWndInsertAfter,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo); -#endif - - WINUSERAPI WINBOOL WINAPI IsWindowVisible(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsIconic(HWND hWnd); - WINUSERAPI WINBOOL WINAPI AnyPopup(VOID); - WINUSERAPI WINBOOL WINAPI BringWindowToTop(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsZoomed(HWND hWnd); - -#define SWP_NOSIZE 0x0001 -#define SWP_NOMOVE 0x0002 -#define SWP_NOZORDER 0x0004 -#define SWP_NOREDRAW 0x0008 -#define SWP_NOACTIVATE 0x0010 -#define SWP_FRAMECHANGED 0x0020 -#define SWP_SHOWWINDOW 0x0040 -#define SWP_HIDEWINDOW 0x0080 -#define SWP_NOCOPYBITS 0x0100 -#define SWP_NOOWNERZORDER 0x0200 -#define SWP_NOSENDCHANGING 0x0400 - -#define SWP_DRAWFRAME SWP_FRAMECHANGED -#define SWP_NOREPOSITION SWP_NOOWNERZORDER -#define SWP_DEFERERASE 0x2000 -#define SWP_ASYNCWINDOWPOS 0x4000 - -#define HWND_TOP ((HWND)0) -#define HWND_BOTTOM ((HWND)1) -#define HWND_TOPMOST ((HWND)-1) -#define HWND_NOTOPMOST ((HWND)-2) - -#ifndef NOCTLMGR - -#include - - typedef struct { - DWORD style; - DWORD dwExtendedStyle; - WORD cdit; - short x; - short y; - short cx; - short cy; - } DLGTEMPLATE; - - typedef DLGTEMPLATE *LPDLGTEMPLATEA; - typedef DLGTEMPLATE *LPDLGTEMPLATEW; - -#ifdef UNICODE - typedef LPDLGTEMPLATEW LPDLGTEMPLATE; -#else - typedef LPDLGTEMPLATEA LPDLGTEMPLATE; -#endif - - typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEA; - typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEW; - -#ifdef UNICODE - typedef LPCDLGTEMPLATEW LPCDLGTEMPLATE; -#else - typedef LPCDLGTEMPLATEA LPCDLGTEMPLATE; -#endif - - typedef struct { - DWORD style; - DWORD dwExtendedStyle; - short x; - short y; - short cx; - short cy; - WORD id; - } DLGITEMTEMPLATE; - - typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEA; - typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEW; - -#ifdef UNICODE - typedef PDLGITEMTEMPLATEW PDLGITEMTEMPLATE; -#else - typedef PDLGITEMTEMPLATEA PDLGITEMTEMPLATE; -#endif - - typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; - typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; - -#ifdef UNICODE - typedef LPDLGITEMTEMPLATEW LPDLGITEMTEMPLATE; -#else - typedef LPDLGITEMTEMPLATEA LPDLGITEMTEMPLATE; -#endif - -#include - -#ifdef UNICODE -#define CreateDialogParam CreateDialogParamW -#define CreateDialogIndirectParam CreateDialogIndirectParamW -#define CreateDialog CreateDialogW -#define CreateDialogIndirect CreateDialogIndirectW -#define DialogBoxParam DialogBoxParamW -#define DialogBoxIndirectParam DialogBoxIndirectParamW -#define DialogBox DialogBoxW -#define DialogBoxIndirect DialogBoxIndirectW -#define SetDlgItemText SetDlgItemTextW -#define GetDlgItemText GetDlgItemTextW -#define SendDlgItemMessage SendDlgItemMessageW -#define DefDlgProc DefDlgProcW -#else -#define CreateDialogParam CreateDialogParamA -#define CreateDialogIndirectParam CreateDialogIndirectParamA -#define CreateDialog CreateDialogA -#define CreateDialogIndirect CreateDialogIndirectA -#define DialogBoxParam DialogBoxParamA -#define DialogBoxIndirectParam DialogBoxIndirectParamA -#define DialogBox DialogBoxA -#define DialogBoxIndirect DialogBoxIndirectA -#define SetDlgItemText SetDlgItemTextA -#define GetDlgItemText GetDlgItemTextA -#define SendDlgItemMessage SendDlgItemMessageA -#define DefDlgProc DefDlgProcA -#endif - - WINUSERAPI HWND WINAPI CreateDialogParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); -#define CreateDialogA(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamA(hInstance,lpName,hWndParent,lpDialogFunc,0L) -#define CreateDialogW(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamW(hInstance,lpName,hWndParent,lpDialogFunc,0L) -#define CreateDialogIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define CreateDialogIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) - WINUSERAPI INT_PTR WINAPI DialogBoxParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); -#define DialogBoxA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) - WINUSERAPI WINBOOL WINAPI EndDialog(HWND hDlg,INT_PTR nResult); - WINUSERAPI HWND WINAPI GetDlgItem(HWND hDlg,int nIDDlgItem); - WINUSERAPI WINBOOL WINAPI SetDlgItemInt(HWND hDlg,int nIDDlgItem,UINT uValue,WINBOOL bSigned); - WINUSERAPI UINT WINAPI GetDlgItemInt(HWND hDlg,int nIDDlgItem,WINBOOL *lpTranslated,WINBOOL bSigned); - WINUSERAPI WINBOOL WINAPI SetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPCSTR lpString); - WINUSERAPI WINBOOL WINAPI SetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPCWSTR lpString); - WINUSERAPI UINT WINAPI GetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPSTR lpString,int cchMax); - WINUSERAPI UINT WINAPI GetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPWSTR lpString,int cchMax); - WINUSERAPI WINBOOL WINAPI CheckDlgButton(HWND hDlg,int nIDButton,UINT uCheck); - WINUSERAPI WINBOOL WINAPI CheckRadioButton(HWND hDlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); - WINUSERAPI UINT WINAPI IsDlgButtonChecked(HWND hDlg,int nIDButton); - WINUSERAPI LRESULT WINAPI SendDlgItemMessageA(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendDlgItemMessageW(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI HWND WINAPI GetNextDlgGroupItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); - WINUSERAPI HWND WINAPI GetNextDlgTabItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); - WINUSERAPI int WINAPI GetDlgCtrlID(HWND hWnd); - WINUSERAPI long WINAPI GetDialogBaseUnits(VOID); - WINUSERAPI LRESULT WINAPI DefDlgProcA(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefDlgProcW(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); - -#define DLGWINDOWEXTRA 30 -#endif - -#ifndef NOMSG - -#ifdef UNICODE -#define CallMsgFilter CallMsgFilterW -#else -#define CallMsgFilter CallMsgFilterA -#endif - - WINUSERAPI WINBOOL WINAPI CallMsgFilterA(LPMSG lpMsg,int nCode); - WINUSERAPI WINBOOL WINAPI CallMsgFilterW(LPMSG lpMsg,int nCode); -#endif - -#ifndef NOCLIPBOARD - -#ifdef UNICODE -#define RegisterClipboardFormat RegisterClipboardFormatW -#define GetClipboardFormatName GetClipboardFormatNameW -#else -#define RegisterClipboardFormat RegisterClipboardFormatA -#define GetClipboardFormatName GetClipboardFormatNameA -#endif - - WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); - WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); - WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); - WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); - WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); - WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); - WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove,HWND hWndNewNext); - WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat,HANDLE hMem); - WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); - WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); - WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); - WINUSERAPI int WINAPI CountClipboardFormats(VOID); - WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); - WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount); - WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format,LPWSTR lpszFormatName,int cchMaxCount); - WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); - WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); - WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList,int cFormats); - WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); -#endif - -#ifdef UNICODE -#define CharToOem CharToOemW -#define OemToChar OemToCharW -#define CharToOemBuff CharToOemBuffW -#define OemToCharBuff OemToCharBuffW -#define CharUpper CharUpperW -#define CharUpperBuff CharUpperBuffW -#define CharLower CharLowerW -#define CharLowerBuff CharLowerBuffW -#define CharNext CharNextW -#define CharPrev CharPrevW -#else -#define CharToOem CharToOemA -#define OemToChar OemToCharA -#define CharToOemBuff CharToOemBuffA -#define OemToCharBuff OemToCharBuffA -#define CharUpper CharUpperA -#define CharUpperBuff CharUpperBuffA -#define CharLower CharLowerA -#define CharLowerBuff CharLowerBuffA -#define CharNext CharNextA -#define CharPrev CharPrevA -#endif - - WINUSERAPI WINBOOL WINAPI CharToOemA(LPCSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI CharToOemW(LPCWSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI OemToCharA(LPCSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI OemToCharW(LPCSTR lpszSrc,LPWSTR lpszDst); - WINUSERAPI WINBOOL WINAPI CharToOemBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI CharToOemBuffW(LPCWSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI OemToCharBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI OemToCharBuffW(LPCSTR lpszSrc,LPWSTR lpszDst,DWORD cchDstLength); - WINUSERAPI LPSTR WINAPI CharUpperA(LPSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharUpperW(LPWSTR lpsz); - WINUSERAPI DWORD WINAPI CharUpperBuffA(LPSTR lpsz,DWORD cchLength); - WINUSERAPI DWORD WINAPI CharUpperBuffW(LPWSTR lpsz,DWORD cchLength); - WINUSERAPI LPSTR WINAPI CharLowerA(LPSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharLowerW(LPWSTR lpsz); - WINUSERAPI DWORD WINAPI CharLowerBuffA(LPSTR lpsz,DWORD cchLength); - WINUSERAPI DWORD WINAPI CharLowerBuffW(LPWSTR lpsz,DWORD cchLength); - WINUSERAPI LPSTR WINAPI CharNextA(LPCSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharNextW(LPCWSTR lpsz); - WINUSERAPI LPSTR WINAPI CharPrevA(LPCSTR lpszStart,LPCSTR lpszCurrent); - WINUSERAPI LPWSTR WINAPI CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); - WINUSERAPI LPSTR WINAPI CharNextExA(WORD CodePage,LPCSTR lpCurrentChar,DWORD dwFlags); - WINUSERAPI LPSTR WINAPI CharPrevExA(WORD CodePage,LPCSTR lpStart,LPCSTR lpCurrentChar,DWORD dwFlags); - -#define AnsiToOem CharToOemA -#define OemToAnsi OemToCharA -#define AnsiToOemBuff CharToOemBuffA -#define OemToAnsiBuff OemToCharBuffA -#define AnsiUpper CharUpperA -#define AnsiUpperBuff CharUpperBuffA -#define AnsiLower CharLowerA -#define AnsiLowerBuff CharLowerBuffA -#define AnsiNext CharNextA -#define AnsiPrev CharPrevA - -#ifndef NOLANGUAGE - -#ifdef UNICODE -#define IsCharAlpha IsCharAlphaW -#define IsCharAlphaNumeric IsCharAlphaNumericW -#define IsCharUpper IsCharUpperW -#define IsCharLower IsCharLowerW -#else -#define IsCharAlpha IsCharAlphaA -#define IsCharAlphaNumeric IsCharAlphaNumericA -#define IsCharUpper IsCharUpperA -#define IsCharLower IsCharLowerA -#endif - - WINUSERAPI WINBOOL WINAPI IsCharAlphaA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharUpperA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharUpperW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharLowerA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharLowerW(WCHAR ch); -#endif - -#ifdef UNICODE -#define GetKeyNameText GetKeyNameTextW -#define VkKeyScan VkKeyScanW -#define VkKeyScanEx VkKeyScanExW -#else -#define GetKeyNameText GetKeyNameTextA -#define VkKeyScan VkKeyScanA -#define VkKeyScanEx VkKeyScanExA -#endif - - WINUSERAPI HWND WINAPI SetFocus(HWND hWnd); - WINUSERAPI HWND WINAPI GetActiveWindow(VOID); - WINUSERAPI HWND WINAPI GetFocus(VOID); - WINUSERAPI UINT WINAPI GetKBCodePage(VOID); - WINUSERAPI SHORT WINAPI GetKeyState(int nVirtKey); - WINUSERAPI SHORT WINAPI GetAsyncKeyState(int vKey); - WINUSERAPI WINBOOL WINAPI GetKeyboardState(PBYTE lpKeyState); - WINUSERAPI WINBOOL WINAPI SetKeyboardState(LPBYTE lpKeyState); - WINUSERAPI int WINAPI GetKeyNameTextA(LONG lParam,LPSTR lpString,int cchSize); - WINUSERAPI int WINAPI GetKeyNameTextW(LONG lParam,LPWSTR lpString,int cchSize); - WINUSERAPI int WINAPI GetKeyboardType(int nTypeFlag); - WINUSERAPI int WINAPI ToAscii(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags); - WINUSERAPI int WINAPI ToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags,HKL dwhkl); - WINUSERAPI int WINAPI ToUnicode(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags); - WINUSERAPI DWORD WINAPI OemKeyScan(WORD wOemChar); - WINUSERAPI SHORT WINAPI VkKeyScanA(CHAR ch); - WINUSERAPI SHORT WINAPI VkKeyScanW(WCHAR ch); - WINUSERAPI SHORT WINAPI VkKeyScanExA(CHAR ch,HKL dwhkl); - WINUSERAPI SHORT WINAPI VkKeyScanExW(WCHAR ch,HKL dwhkl); - -#define KEYEVENTF_EXTENDEDKEY 0x0001 -#define KEYEVENTF_KEYUP 0x0002 -#define KEYEVENTF_UNICODE 0x0004 -#define KEYEVENTF_SCANCODE 0x0008 - - WINUSERAPI VOID WINAPI keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,ULONG_PTR dwExtraInfo); - -#define MOUSEEVENTF_MOVE 0x0001 -#define MOUSEEVENTF_LEFTDOWN 0x0002 -#define MOUSEEVENTF_LEFTUP 0x0004 -#define MOUSEEVENTF_RIGHTDOWN 0x0008 -#define MOUSEEVENTF_RIGHTUP 0x0010 -#define MOUSEEVENTF_MIDDLEDOWN 0x0020 -#define MOUSEEVENTF_MIDDLEUP 0x0040 -#define MOUSEEVENTF_XDOWN 0x0080 -#define MOUSEEVENTF_XUP 0x0100 -#define MOUSEEVENTF_WHEEL 0x0800 -#define MOUSEEVENTF_VIRTUALDESK 0x4000 -#define MOUSEEVENTF_ABSOLUTE 0x8000 - - WINUSERAPI VOID WINAPI mouse_event(DWORD dwFlags,DWORD dx,DWORD dy,DWORD dwData,ULONG_PTR dwExtraInfo); - - typedef struct tagMOUSEINPUT { - LONG dx; - LONG dy; - DWORD mouseData; - DWORD dwFlags; - DWORD time; - ULONG_PTR dwExtraInfo; - } MOUSEINPUT,*PMOUSEINPUT,*LPMOUSEINPUT; - - typedef struct tagKEYBDINPUT { - WORD wVk; - WORD wScan; - DWORD dwFlags; - DWORD time; - ULONG_PTR dwExtraInfo; - } KEYBDINPUT,*PKEYBDINPUT,*LPKEYBDINPUT; - - typedef struct tagHARDWAREINPUT { - DWORD uMsg; - WORD wParamL; - WORD wParamH; - } HARDWAREINPUT,*PHARDWAREINPUT,*LPHARDWAREINPUT; - -#define INPUT_MOUSE 0 -#define INPUT_KEYBOARD 1 -#define INPUT_HARDWARE 2 - - typedef struct tagINPUT { - DWORD type; - union { - MOUSEINPUT mi; - KEYBDINPUT ki; - HARDWAREINPUT hi; - }; - } INPUT,*PINPUT,*LPINPUT; - - WINUSERAPI UINT WINAPI SendInput(UINT cInputs,LPINPUT pInputs,int cbSize); - - typedef struct tagLASTINPUTINFO { - UINT cbSize; - DWORD dwTime; - } LASTINPUTINFO,*PLASTINPUTINFO; - -#ifdef UNICODE -#define MapVirtualKey MapVirtualKeyW -#define MapVirtualKeyEx MapVirtualKeyExW -#else -#define MapVirtualKey MapVirtualKeyA -#define MapVirtualKeyEx MapVirtualKeyExA -#endif - - WINUSERAPI WINBOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii); - WINUSERAPI UINT WINAPI MapVirtualKeyA(UINT uCode,UINT uMapType); - WINUSERAPI UINT WINAPI MapVirtualKeyW(UINT uCode,UINT uMapType); - WINUSERAPI UINT WINAPI MapVirtualKeyExA(UINT uCode,UINT uMapType,HKL dwhkl); - WINUSERAPI UINT WINAPI MapVirtualKeyExW(UINT uCode,UINT uMapType,HKL dwhkl); - WINUSERAPI WINBOOL WINAPI GetInputState(VOID); - WINUSERAPI DWORD WINAPI GetQueueStatus(UINT flags); - WINUSERAPI HWND WINAPI GetCapture(VOID); - WINUSERAPI HWND WINAPI SetCapture(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ReleaseCapture(VOID); - WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *pHandles,WINBOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask); - WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *pHandles,DWORD dwMilliseconds,DWORD dwWakeMask,DWORD dwFlags); - -#define MWMO_WAITALL 0x0001 -#define MWMO_ALERTABLE 0x0002 -#define MWMO_INPUTAVAILABLE 0x0004 - -#define QS_KEY 0x0001 -#define QS_MOUSEMOVE 0x0002 -#define QS_MOUSEBUTTON 0x0004 -#define QS_POSTMESSAGE 0x0008 -#define QS_TIMER 0x0010 -#define QS_PAINT 0x0020 -#define QS_SENDMESSAGE 0x0040 -#define QS_HOTKEY 0x0080 -#define QS_ALLPOSTMESSAGE 0x0100 -#define QS_RAWINPUT 0x0400 -#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) -#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) -#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) -#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) - -#define USER_TIMER_MAXIMUM 0x7FFFFFFF -#define USER_TIMER_MINIMUM 0x0000000A - -#ifdef UNICODE -#define LoadAccelerators LoadAcceleratorsW -#define CreateAcceleratorTable CreateAcceleratorTableW -#define CopyAcceleratorTable CopyAcceleratorTableW -#else -#define LoadAccelerators LoadAcceleratorsA -#define CreateAcceleratorTable CreateAcceleratorTableA -#define CopyAcceleratorTable CopyAcceleratorTableA -#endif - - WINUSERAPI UINT_PTR WINAPI SetTimer(HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc); - WINUSERAPI WINBOOL WINAPI KillTimer(HWND hWnd,UINT_PTR uIDEvent); - WINUSERAPI WINBOOL WINAPI IsWindowUnicode(HWND hWnd); - WINUSERAPI WINBOOL WINAPI EnableWindow(HWND hWnd,WINBOOL bEnable); - WINUSERAPI WINBOOL WINAPI IsWindowEnabled(HWND hWnd); - WINUSERAPI HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance,LPCSTR lpTableName); - WINUSERAPI HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance,LPCWSTR lpTableName); - WINUSERAPI HACCEL WINAPI CreateAcceleratorTableA(LPACCEL paccel,int cAccel); - WINUSERAPI HACCEL WINAPI CreateAcceleratorTableW(LPACCEL paccel,int cAccel); - WINUSERAPI WINBOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel); - WINUSERAPI int WINAPI CopyAcceleratorTableA(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); - WINUSERAPI int WINAPI CopyAcceleratorTableW(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); - -#ifndef NOMSG - -#ifdef UNICODE -#define TranslateAccelerator TranslateAcceleratorW -#else -#define TranslateAccelerator TranslateAcceleratorA -#endif - - WINUSERAPI int WINAPI TranslateAcceleratorA(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); - WINUSERAPI int WINAPI TranslateAcceleratorW(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); -#endif - -#ifndef NOSYSMETRICS - -#define SM_CXSCREEN 0 -#define SM_CYSCREEN 1 -#define SM_CXVSCROLL 2 -#define SM_CYHSCROLL 3 -#define SM_CYCAPTION 4 -#define SM_CXBORDER 5 -#define SM_CYBORDER 6 -#define SM_CXDLGFRAME 7 -#define SM_CYDLGFRAME 8 -#define SM_CYVTHUMB 9 -#define SM_CXHTHUMB 10 -#define SM_CXICON 11 -#define SM_CYICON 12 -#define SM_CXCURSOR 13 -#define SM_CYCURSOR 14 -#define SM_CYMENU 15 -#define SM_CXFULLSCREEN 16 -#define SM_CYFULLSCREEN 17 -#define SM_CYKANJIWINDOW 18 -#define SM_MOUSEPRESENT 19 -#define SM_CYVSCROLL 20 -#define SM_CXHSCROLL 21 -#define SM_DEBUG 22 -#define SM_SWAPBUTTON 23 -#define SM_RESERVED1 24 -#define SM_RESERVED2 25 -#define SM_RESERVED3 26 -#define SM_RESERVED4 27 -#define SM_CXMIN 28 -#define SM_CYMIN 29 -#define SM_CXSIZE 30 -#define SM_CYSIZE 31 -#define SM_CXFRAME 32 -#define SM_CYFRAME 33 -#define SM_CXMINTRACK 34 -#define SM_CYMINTRACK 35 -#define SM_CXDOUBLECLK 36 -#define SM_CYDOUBLECLK 37 -#define SM_CXICONSPACING 38 -#define SM_CYICONSPACING 39 -#define SM_MENUDROPALIGNMENT 40 -#define SM_PENWINDOWS 41 -#define SM_DBCSENABLED 42 -#define SM_CMOUSEBUTTONS 43 - -#define SM_CXFIXEDFRAME SM_CXDLGFRAME -#define SM_CYFIXEDFRAME SM_CYDLGFRAME -#define SM_CXSIZEFRAME SM_CXFRAME -#define SM_CYSIZEFRAME SM_CYFRAME - -#define SM_SECURE 44 -#define SM_CXEDGE 45 -#define SM_CYEDGE 46 -#define SM_CXMINSPACING 47 -#define SM_CYMINSPACING 48 -#define SM_CXSMICON 49 -#define SM_CYSMICON 50 -#define SM_CYSMCAPTION 51 -#define SM_CXSMSIZE 52 -#define SM_CYSMSIZE 53 -#define SM_CXMENUSIZE 54 -#define SM_CYMENUSIZE 55 -#define SM_ARRANGE 56 -#define SM_CXMINIMIZED 57 -#define SM_CYMINIMIZED 58 -#define SM_CXMAXTRACK 59 -#define SM_CYMAXTRACK 60 -#define SM_CXMAXIMIZED 61 -#define SM_CYMAXIMIZED 62 -#define SM_NETWORK 63 -#define SM_CLEANBOOT 67 -#define SM_CXDRAG 68 -#define SM_CYDRAG 69 -#define SM_SHOWSOUNDS 70 -#define SM_CXMENUCHECK 71 -#define SM_CYMENUCHECK 72 -#define SM_SLOWMACHINE 73 -#define SM_MIDEASTENABLED 74 -#define SM_MOUSEWHEELPRESENT 75 -#define SM_XVIRTUALSCREEN 76 -#define SM_YVIRTUALSCREEN 77 -#define SM_CXVIRTUALSCREEN 78 -#define SM_CYVIRTUALSCREEN 79 -#define SM_CMONITORS 80 -#define SM_SAMEDISPLAYFORMAT 81 -#define SM_IMMENABLED 82 -#define SM_CXFOCUSBORDER 83 -#define SM_CYFOCUSBORDER 84 -#define SM_TABLETPC 86 -#define SM_MEDIACENTER 87 -#define SM_STARTER 88 -#define SM_SERVERR2 89 -#define SM_CMETRICS 90 -#define SM_REMOTESESSION 0x1000 -#define SM_SHUTTINGDOWN 0x2000 -#define SM_REMOTECONTROL 0x2001 -#define SM_CARETBLINKINGENABLED 0x2002 - - WINUSERAPI int WINAPI GetSystemMetrics(int nIndex); -#endif - -#ifndef NOMENUS - -#ifdef UNICODE -#define LoadMenu LoadMenuW -#define LoadMenuIndirect LoadMenuIndirectW -#define ChangeMenu ChangeMenuW -#define GetMenuString GetMenuStringW -#define InsertMenu InsertMenuW -#define AppendMenu AppendMenuW -#define ModifyMenu ModifyMenuW -#else -#define LoadMenu LoadMenuA -#define LoadMenuIndirect LoadMenuIndirectA -#define ChangeMenu ChangeMenuA -#define GetMenuString GetMenuStringA -#define InsertMenu InsertMenuA -#define AppendMenu AppendMenuA -#define ModifyMenu ModifyMenuA -#endif - - WINUSERAPI HMENU WINAPI LoadMenuA(HINSTANCE hInstance,LPCSTR lpMenuName); - WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance,LPCWSTR lpMenuName); - WINUSERAPI HMENU WINAPI LoadMenuIndirectA(CONST MENUTEMPLATEA *lpMenuTemplate); - WINUSERAPI HMENU WINAPI LoadMenuIndirectW(CONST MENUTEMPLATEW *lpMenuTemplate); - WINUSERAPI HMENU WINAPI GetMenu(HWND hWnd); - WINUSERAPI WINBOOL WINAPI SetMenu(HWND hWnd,HMENU hMenu); - WINUSERAPI WINBOOL WINAPI ChangeMenuA(HMENU hMenu,UINT cmd,LPCSTR lpszNewItem,UINT cmdInsert,UINT flags); - WINUSERAPI WINBOOL WINAPI ChangeMenuW(HMENU hMenu,UINT cmd,LPCWSTR lpszNewItem,UINT cmdInsert,UINT flags); - WINUSERAPI WINBOOL WINAPI HiliteMenuItem(HWND hWnd,HMENU hMenu,UINT uIDHiliteItem,UINT uHilite); - WINUSERAPI int WINAPI GetMenuStringA(HMENU hMenu,UINT uIDItem,LPSTR lpString,int cchMax,UINT flags); - WINUSERAPI int WINAPI GetMenuStringW(HMENU hMenu,UINT uIDItem,LPWSTR lpString,int cchMax,UINT flags); - WINUSERAPI UINT WINAPI GetMenuState(HMENU hMenu,UINT uId,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DrawMenuBar(HWND hWnd); - -#define PMB_ACTIVE 0x00000001 - - WINUSERAPI HMENU WINAPI GetSystemMenu(HWND hWnd,WINBOOL bRevert); - WINUSERAPI HMENU WINAPI CreateMenu(VOID); - WINUSERAPI HMENU WINAPI CreatePopupMenu(VOID); - WINUSERAPI WINBOOL WINAPI DestroyMenu(HMENU hMenu); - WINUSERAPI DWORD WINAPI CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck); - WINUSERAPI WINBOOL WINAPI EnableMenuItem(HMENU hMenu,UINT uIDEnableItem,UINT uEnable); - WINUSERAPI HMENU WINAPI GetSubMenu(HMENU hMenu,int nPos); - WINUSERAPI UINT WINAPI GetMenuItemID(HMENU hMenu,int nPos); - WINUSERAPI int WINAPI GetMenuItemCount(HMENU hMenu); - WINUSERAPI WINBOOL WINAPI InsertMenuA(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI InsertMenuW(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI AppendMenuA(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI AppendMenuW(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI ModifyMenuA(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI ModifyMenuW(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI RemoveMenu(HMENU hMenu,UINT uPosition,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DeleteMenu(HMENU hMenu,UINT uPosition,UINT uFlags); - WINUSERAPI WINBOOL WINAPI SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked); - WINUSERAPI LONG WINAPI GetMenuCheckMarkDimensions(VOID); - WINUSERAPI WINBOOL WINAPI TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT *prcRect); - -#define MNC_IGNORE 0 -#define MNC_CLOSE 1 -#define MNC_EXECUTE 2 -#define MNC_SELECT 3 - - typedef struct tagTPMPARAMS { - UINT cbSize; - RECT rcExclude; - } TPMPARAMS; - - typedef TPMPARAMS *LPTPMPARAMS; - - WINUSERAPI WINBOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS); - -#define MNS_NOCHECK 0x80000000 -#define MNS_MODELESS 0x40000000 -#define MNS_DRAGDROP 0x20000000 -#define MNS_AUTODISMISS 0x10000000 -#define MNS_NOTIFYBYPOS 0x08000000 -#define MNS_CHECKORBMP 0x04000000 - -#define MIM_MAXHEIGHT 0x00000001 -#define MIM_BACKGROUND 0x00000002 -#define MIM_HELPID 0x00000004 -#define MIM_MENUDATA 0x00000008 -#define MIM_STYLE 0x00000010 -#define MIM_APPLYTOSUBMENUS 0x80000000 - - typedef struct tagMENUINFO { - DWORD cbSize; - DWORD fMask; - DWORD dwStyle; - UINT cyMax; - HBRUSH hbrBack; - DWORD dwContextHelpID; - ULONG_PTR dwMenuData; - } MENUINFO,*LPMENUINFO; - - typedef MENUINFO CONST *LPCMENUINFO; - - WINUSERAPI WINBOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO); - WINUSERAPI WINBOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO); - WINUSERAPI WINBOOL WINAPI EndMenu(VOID); - -#define MND_CONTINUE 0 -#define MND_ENDMENU 1 - - typedef struct tagMENUGETOBJECTINFO { - DWORD dwFlags; - UINT uPos; - HMENU hmenu; - PVOID riid; - PVOID pvObj; - } MENUGETOBJECTINFO,*PMENUGETOBJECTINFO; - -#define MNGOF_TOPGAP 0x00000001 -#define MNGOF_BOTTOMGAP 0x00000002 - -#define MNGO_NOINTERFACE 0x00000000 -#define MNGO_NOERROR 0x00000001 - -#define MIIM_STATE 0x00000001 -#define MIIM_ID 0x00000002 -#define MIIM_SUBMENU 0x00000004 -#define MIIM_CHECKMARKS 0x00000008 -#define MIIM_TYPE 0x00000010 -#define MIIM_DATA 0x00000020 - -#define MIIM_STRING 0x00000040 -#define MIIM_BITMAP 0x00000080 -#define MIIM_FTYPE 0x00000100 - -#define HBMMENU_CALLBACK ((HBITMAP) -1) -#define HBMMENU_SYSTEM ((HBITMAP) 1) -#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) -#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) -#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) -#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) -#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) -#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) -#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) -#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) -#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) - - typedef struct tagMENUITEMINFOA { - UINT cbSize; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - LPSTR dwTypeData; - UINT cch; - HBITMAP hbmpItem; - } MENUITEMINFOA,*LPMENUITEMINFOA; - - typedef struct tagMENUITEMINFOW { - UINT cbSize; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - LPWSTR dwTypeData; - UINT cch; - HBITMAP hbmpItem; - } MENUITEMINFOW,*LPMENUITEMINFOW; - -#ifdef UNICODE - typedef MENUITEMINFOW MENUITEMINFO; - typedef LPMENUITEMINFOW LPMENUITEMINFO; -#else - typedef MENUITEMINFOA MENUITEMINFO; - typedef LPMENUITEMINFOA LPMENUITEMINFO; -#endif - typedef MENUITEMINFOA CONST *LPCMENUITEMINFOA; - typedef MENUITEMINFOW CONST *LPCMENUITEMINFOW; -#ifdef UNICODE - typedef LPCMENUITEMINFOW LPCMENUITEMINFO; -#else - typedef LPCMENUITEMINFOA LPCMENUITEMINFO; -#endif - -#ifdef UNICODE -#define InsertMenuItem InsertMenuItemW -#define GetMenuItemInfo GetMenuItemInfoW -#define SetMenuItemInfo SetMenuItemInfoW -#else -#define InsertMenuItem InsertMenuItemA -#define GetMenuItemInfo GetMenuItemInfoA -#define SetMenuItemInfo SetMenuItemInfoA -#endif - - WINUSERAPI WINBOOL WINAPI InsertMenuItemA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOA lpmi); - WINUSERAPI WINBOOL WINAPI InsertMenuItemW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOW lpmi); - WINUSERAPI WINBOOL WINAPI GetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOA lpmii); - WINUSERAPI WINBOOL WINAPI GetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOW lpmii); - WINUSERAPI WINBOOL WINAPI SetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOA lpmii); - WINUSERAPI WINBOOL WINAPI SetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOW lpmii); - -#define GMDI_USEDISABLED 0x0001L -#define GMDI_GOINTOPOPUPS 0x0002L - - WINUSERAPI UINT WINAPI GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmdiFlags); - WINUSERAPI WINBOOL WINAPI SetMenuDefaultItem(HMENU hMenu,UINT uItem,UINT fByPos); - WINUSERAPI WINBOOL WINAPI GetMenuItemRect(HWND hWnd,HMENU hMenu,UINT uItem,LPRECT lprcItem); - WINUSERAPI int WINAPI MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen); - -#define TPM_LEFTBUTTON 0x0000L -#define TPM_RIGHTBUTTON 0x0002L -#define TPM_LEFTALIGN 0x0000L -#define TPM_CENTERALIGN 0x0004L -#define TPM_RIGHTALIGN 0x0008L -#define TPM_TOPALIGN 0x0000L -#define TPM_VCENTERALIGN 0x0010L -#define TPM_BOTTOMALIGN 0x0020L - -#define TPM_HORIZONTAL 0x0000L -#define TPM_VERTICAL 0x0040L -#define TPM_NONOTIFY 0x0080L -#define TPM_RETURNCMD 0x0100L -#define TPM_RECURSE 0x0001L -#define TPM_HORPOSANIMATION 0x0400L -#define TPM_HORNEGANIMATION 0x0800L -#define TPM_VERPOSANIMATION 0x1000L -#define TPM_VERNEGANIMATION 0x2000L -#define TPM_NOANIMATION 0x4000L -#define TPM_LAYOUTRTL 0x8000L -#endif - - typedef struct tagDROPSTRUCT { - HWND hwndSource; - HWND hwndSink; - DWORD wFmt; - ULONG_PTR dwData; - POINT ptDrop; - DWORD dwControlData; - } DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT; - -#define DOF_EXECUTABLE 0x8001 -#define DOF_DOCUMENT 0x8002 -#define DOF_DIRECTORY 0x8003 -#define DOF_MULTIPLE 0x8004 -#define DOF_PROGMAN 0x0001 -#define DOF_SHELLDATA 0x0002 - -#define DO_DROPFILE 0x454C4946L -#define DO_PRINTFILE 0x544E5250L - - WINUSERAPI DWORD WINAPI DragObject(HWND hwndParent,HWND hwndFrom,UINT fmt,ULONG_PTR data,HCURSOR hcur); - WINUSERAPI WINBOOL WINAPI DragDetect(HWND hwnd,POINT pt); - WINUSERAPI WINBOOL WINAPI DrawIcon(HDC hDC,int X,int Y,HICON hIcon); - -#ifndef NODRAWTEXT - -#define DT_TOP 0x00000000 -#define DT_LEFT 0x00000000 -#define DT_CENTER 0x00000001 -#define DT_RIGHT 0x00000002 -#define DT_VCENTER 0x00000004 -#define DT_BOTTOM 0x00000008 -#define DT_WORDBREAK 0x00000010 -#define DT_SINGLELINE 0x00000020 -#define DT_EXPANDTABS 0x00000040 -#define DT_TABSTOP 0x00000080 -#define DT_NOCLIP 0x00000100 -#define DT_EXTERNALLEADING 0x00000200 -#define DT_CALCRECT 0x00000400 -#define DT_NOPREFIX 0x00000800 -#define DT_INTERNAL 0x00001000 - -#define DT_EDITCONTROL 0x00002000 -#define DT_PATH_ELLIPSIS 0x00004000 -#define DT_END_ELLIPSIS 0x00008000 -#define DT_MODIFYSTRING 0x00010000 -#define DT_RTLREADING 0x00020000 -#define DT_WORD_ELLIPSIS 0x00040000 -#define DT_NOFULLWIDTHCHARBREAK 0x00080000 -#define DT_HIDEPREFIX 0x00100000 -#define DT_PREFIXONLY 0x00200000 - - typedef struct tagDRAWTEXTPARAMS { - UINT cbSize; - int iTabLength; - int iLeftMargin; - int iRightMargin; - UINT uiLengthDrawn; - } DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; - -#ifdef UNICODE -#define DrawText DrawTextW -#define DrawTextEx DrawTextExW -#else -#define DrawText DrawTextA -#define DrawTextEx DrawTextExA -#endif - - WINUSERAPI int WINAPI DrawTextA(HDC hdc,LPCSTR lpchText,int cchText,LPRECT lprc,UINT format); - WINUSERAPI int WINAPI DrawTextW(HDC hdc,LPCWSTR lpchText,int cchText,LPRECT lprc,UINT format); - WINUSERAPI int WINAPI DrawTextExA(HDC hdc,LPSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); - WINUSERAPI int WINAPI DrawTextExW(HDC hdc,LPWSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); -#endif - -#ifdef UNICODE -#define GrayString GrayStringW -#define DrawState DrawStateW -#define TabbedTextOut TabbedTextOutW -#define GetTabbedTextExtent GetTabbedTextExtentW -#else -#define GrayString GrayStringA -#define DrawState DrawStateA -#define TabbedTextOut TabbedTextOutA -#define GetTabbedTextExtent GetTabbedTextExtentA -#endif - - WINUSERAPI WINBOOL WINAPI GrayStringA(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); - WINUSERAPI WINBOOL WINAPI GrayStringW(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); - -#define DST_COMPLEX 0x0000 -#define DST_TEXT 0x0001 -#define DST_PREFIXTEXT 0x0002 -#define DST_ICON 0x0003 -#define DST_BITMAP 0x0004 - -#define DSS_NORMAL 0x0000 -#define DSS_UNION 0x0010 -#define DSS_DISABLED 0x0020 -#define DSS_MONO 0x0080 -#define DSS_HIDEPREFIX 0x0200 -#define DSS_PREFIXONLY 0x0400 -#define DSS_RIGHT 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawStateA(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DrawStateW(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI LONG WINAPI TabbedTextOutA(HDC hdc,int x,int y,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); - WINUSERAPI LONG WINAPI TabbedTextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); - WINUSERAPI DWORD WINAPI GetTabbedTextExtentA(HDC hdc,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); - WINUSERAPI DWORD WINAPI GetTabbedTextExtentW(HDC hdc,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); - WINUSERAPI WINBOOL WINAPI UpdateWindow(HWND hWnd); - WINUSERAPI HWND WINAPI SetActiveWindow(HWND hWnd); - WINUSERAPI HWND WINAPI GetForegroundWindow(VOID); - WINUSERAPI WINBOOL WINAPI PaintDesktop(HDC hdc); - WINUSERAPI VOID WINAPI SwitchToThisWindow(HWND hwnd,WINBOOL fUnknown); - WINUSERAPI WINBOOL WINAPI SetForegroundWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI AllowSetForegroundWindow(DWORD dwProcessId); - -#define ASFW_ANY ((DWORD)-1) - - WINUSERAPI WINBOOL WINAPI LockSetForegroundWindow(UINT uLockCode); - -#define LSFW_LOCK 1 -#define LSFW_UNLOCK 2 - - WINUSERAPI HWND WINAPI WindowFromDC(HDC hDC); - WINUSERAPI HDC WINAPI GetDC(HWND hWnd); - WINUSERAPI HDC WINAPI GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags); - -#define DCX_WINDOW 0x00000001L -#define DCX_CACHE 0x00000002L -#define DCX_NORESETATTRS 0x00000004L -#define DCX_CLIPCHILDREN 0x00000008L -#define DCX_CLIPSIBLINGS 0x00000010L -#define DCX_PARENTCLIP 0x00000020L -#define DCX_EXCLUDERGN 0x00000040L -#define DCX_INTERSECTRGN 0x00000080L -#define DCX_EXCLUDEUPDATE 0x00000100L -#define DCX_INTERSECTUPDATE 0x00000200L -#define DCX_LOCKWINDOWUPDATE 0x00000400L - -#define DCX_VALIDATE 0x00200000L - - WINUSERAPI HDC WINAPI GetWindowDC(HWND hWnd); - WINUSERAPI int WINAPI ReleaseDC(HWND hWnd,HDC hDC); - WINUSERAPI HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint); - WINUSERAPI WINBOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint); - WINUSERAPI WINBOOL WINAPI GetUpdateRect(HWND hWnd,LPRECT lpRect,WINBOOL bErase); - WINUSERAPI int WINAPI GetUpdateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); - WINUSERAPI int WINAPI SetWindowRgn(HWND hWnd,HRGN hRgn,WINBOOL bRedraw); - WINUSERAPI int WINAPI GetWindowRgn(HWND hWnd,HRGN hRgn); - WINUSERAPI int WINAPI GetWindowRgnBox(HWND hWnd,LPRECT lprc); - WINUSERAPI int WINAPI ExcludeUpdateRgn(HDC hDC,HWND hWnd); - WINUSERAPI WINBOOL WINAPI InvalidateRect(HWND hWnd,CONST RECT *lpRect,WINBOOL bErase); - WINUSERAPI WINBOOL WINAPI ValidateRect(HWND hWnd,CONST RECT *lpRect); - WINUSERAPI WINBOOL WINAPI InvalidateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); - WINUSERAPI WINBOOL WINAPI ValidateRgn(HWND hWnd,HRGN hRgn); - WINUSERAPI WINBOOL WINAPI RedrawWindow(HWND hWnd,CONST RECT *lprcUpdate,HRGN hrgnUpdate,UINT flags); - -#define RDW_INVALIDATE 0x0001 -#define RDW_INTERNALPAINT 0x0002 -#define RDW_ERASE 0x0004 - -#define RDW_VALIDATE 0x0008 -#define RDW_NOINTERNALPAINT 0x0010 -#define RDW_NOERASE 0x0020 - -#define RDW_NOCHILDREN 0x0040 -#define RDW_ALLCHILDREN 0x0080 - -#define RDW_UPDATENOW 0x0100 -#define RDW_ERASENOW 0x0200 - -#define RDW_FRAME 0x0400 -#define RDW_NOFRAME 0x0800 - - WINUSERAPI WINBOOL WINAPI LockWindowUpdate(HWND hWndLock); - WINUSERAPI WINBOOL WINAPI ScrollWindow(HWND hWnd,int XAmount,int YAmount,CONST RECT *lpRect,CONST RECT *lpClipRect); - WINUSERAPI WINBOOL WINAPI ScrollDC(HDC hDC,int dx,int dy,CONST RECT *lprcScroll,CONST RECT *lprcClip,HRGN hrgnUpdate,LPRECT lprcUpdate); - WINUSERAPI int WINAPI ScrollWindowEx(HWND hWnd,int dx,int dy,CONST RECT *prcScroll,CONST RECT *prcClip,HRGN hrgnUpdate,LPRECT prcUpdate,UINT flags); - -#define SW_SCROLLCHILDREN 0x0001 -#define SW_INVALIDATE 0x0002 -#define SW_ERASE 0x0004 -#define SW_SMOOTHSCROLL 0x0010 - -#ifndef NOSCROLL - WINUSERAPI int WINAPI SetScrollPos(HWND hWnd,int nBar,int nPos,WINBOOL bRedraw); - WINUSERAPI int WINAPI GetScrollPos(HWND hWnd,int nBar); - WINUSERAPI WINBOOL WINAPI SetScrollRange(HWND hWnd,int nBar,int nMinPos,int nMaxPos,WINBOOL bRedraw); - WINUSERAPI WINBOOL WINAPI GetScrollRange(HWND hWnd,int nBar,LPINT lpMinPos,LPINT lpMaxPos); - WINUSERAPI WINBOOL WINAPI ShowScrollBar(HWND hWnd,int wBar,WINBOOL bShow); - WINUSERAPI WINBOOL WINAPI EnableScrollBar(HWND hWnd,UINT wSBflags,UINT wArrows); - -#define ESB_ENABLE_BOTH 0x0000 -#define ESB_DISABLE_BOTH 0x0003 - -#define ESB_DISABLE_LEFT 0x0001 -#define ESB_DISABLE_RIGHT 0x0002 - -#define ESB_DISABLE_UP 0x0001 -#define ESB_DISABLE_DOWN 0x0002 - -#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT -#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT -#endif - -#ifdef UNICODE -#define SetProp SetPropW -#define GetProp GetPropW -#define RemoveProp RemovePropW -#define EnumPropsEx EnumPropsExW -#define EnumProps EnumPropsW -#define SetWindowText SetWindowTextW -#define GetWindowText GetWindowTextW -#define GetWindowTextLength GetWindowTextLengthW -#else -#define SetProp SetPropA -#define GetProp GetPropA -#define RemoveProp RemovePropA -#define EnumPropsEx EnumPropsExA -#define EnumProps EnumPropsA -#define SetWindowText SetWindowTextA -#define GetWindowText GetWindowTextA -#define GetWindowTextLength GetWindowTextLengthA -#endif - - WINUSERAPI WINBOOL WINAPI SetPropA(HWND hWnd,LPCSTR lpString,HANDLE hData); - WINUSERAPI WINBOOL WINAPI SetPropW(HWND hWnd,LPCWSTR lpString,HANDLE hData); - WINUSERAPI HANDLE WINAPI GetPropA(HWND hWnd,LPCSTR lpString); - WINUSERAPI HANDLE WINAPI GetPropW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI HANDLE WINAPI RemovePropA(HWND hWnd,LPCSTR lpString); - WINUSERAPI HANDLE WINAPI RemovePropW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI int WINAPI EnumPropsExA(HWND hWnd,PROPENUMPROCEXA lpEnumFunc,LPARAM lParam); - WINUSERAPI int WINAPI EnumPropsExW(HWND hWnd,PROPENUMPROCEXW lpEnumFunc,LPARAM lParam); - WINUSERAPI int WINAPI EnumPropsA(HWND hWnd,PROPENUMPROCA lpEnumFunc); - WINUSERAPI int WINAPI EnumPropsW(HWND hWnd,PROPENUMPROCW lpEnumFunc); - WINUSERAPI WINBOOL WINAPI SetWindowTextA(HWND hWnd,LPCSTR lpString); - WINUSERAPI WINBOOL WINAPI SetWindowTextW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI int WINAPI GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); - WINUSERAPI int WINAPI GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount); - WINUSERAPI int WINAPI GetWindowTextLengthA(HWND hWnd); - WINUSERAPI int WINAPI GetWindowTextLengthW(HWND hWnd); - WINUSERAPI WINBOOL WINAPI GetClientRect(HWND hWnd,LPRECT lpRect); - WINUSERAPI WINBOOL WINAPI GetWindowRect(HWND hWnd,LPRECT lpRect); - WINUSERAPI WINBOOL WINAPI AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu); - WINUSERAPI WINBOOL WINAPI AdjustWindowRectEx(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu,DWORD dwExStyle); - -#define HELPINFO_WINDOW 0x0001 -#define HELPINFO_MENUITEM 0x0002 - - typedef struct tagHELPINFO { - UINT cbSize; - int iContextType; - int iCtrlId; - HANDLE hItemHandle; - DWORD_PTR dwContextId; - POINT MousePos; - } HELPINFO,*LPHELPINFO; - - WINUSERAPI WINBOOL WINAPI SetWindowContextHelpId(HWND,DWORD); - WINUSERAPI DWORD WINAPI GetWindowContextHelpId(HWND); - WINUSERAPI WINBOOL WINAPI SetMenuContextHelpId(HMENU,DWORD); - WINUSERAPI DWORD WINAPI GetMenuContextHelpId(HMENU); - -#ifndef NOMB - -#define MB_OK 0x00000000L -#define MB_OKCANCEL 0x00000001L -#define MB_ABORTRETRYIGNORE 0x00000002L -#define MB_YESNOCANCEL 0x00000003L -#define MB_YESNO 0x00000004L -#define MB_RETRYCANCEL 0x00000005L -#define MB_CANCELTRYCONTINUE 0x00000006L -#define MB_ICONHAND 0x00000010L -#define MB_ICONQUESTION 0x00000020L -#define MB_ICONEXCLAMATION 0x00000030L -#define MB_ICONASTERISK 0x00000040L -#define MB_USERICON 0x00000080L -#define MB_ICONWARNING MB_ICONEXCLAMATION -#define MB_ICONERROR MB_ICONHAND -#define MB_ICONINFORMATION MB_ICONASTERISK -#define MB_ICONSTOP MB_ICONHAND -#define MB_DEFBUTTON1 0x00000000L -#define MB_DEFBUTTON2 0x00000100L -#define MB_DEFBUTTON3 0x00000200L -#define MB_DEFBUTTON4 0x00000300L -#define MB_APPLMODAL 0x00000000L -#define MB_SYSTEMMODAL 0x00001000L -#define MB_TASKMODAL 0x00002000L -#define MB_HELP 0x00004000L -#define MB_NOFOCUS 0x00008000L -#define MB_SETFOREGROUND 0x00010000L -#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L -#define MB_TOPMOST 0x00040000L -#define MB_RIGHT 0x00080000L -#define MB_RTLREADING 0x00100000L -#define MB_SERVICE_NOTIFICATION 0x00200000L -#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L -#define MB_TYPEMASK 0x0000000FL -#define MB_ICONMASK 0x000000F0L -#define MB_DEFMASK 0x00000F00L -#define MB_MODEMASK 0x00003000L -#define MB_MISCMASK 0x0000C000L - -#ifdef UNICODE -#define MessageBox MessageBoxW -#define MessageBoxEx MessageBoxExW -#else -#define MessageBox MessageBoxA -#define MessageBoxEx MessageBoxExA -#endif - - WINUSERAPI int WINAPI MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); - WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); - WINUSERAPI int WINAPI MessageBoxExA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,WORD wLanguageId); - WINUSERAPI int WINAPI MessageBoxExW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,WORD wLanguageId); - - typedef VOID (CALLBACK *MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); - - typedef struct tagMSGBOXPARAMSA { - UINT cbSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCSTR lpszText; - LPCSTR lpszCaption; - DWORD dwStyle; - LPCSTR lpszIcon; - DWORD_PTR dwContextHelpId; - MSGBOXCALLBACK lpfnMsgBoxCallback; - DWORD dwLanguageId; - } MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA; - - typedef struct tagMSGBOXPARAMSW { - UINT cbSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCWSTR lpszText; - LPCWSTR lpszCaption; - DWORD dwStyle; - LPCWSTR lpszIcon; - DWORD_PTR dwContextHelpId; - MSGBOXCALLBACK lpfnMsgBoxCallback; - DWORD dwLanguageId; - } MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW; - -#ifdef UNICODE - typedef MSGBOXPARAMSW MSGBOXPARAMS; - typedef PMSGBOXPARAMSW PMSGBOXPARAMS; - typedef LPMSGBOXPARAMSW LPMSGBOXPARAMS; -#else - typedef MSGBOXPARAMSA MSGBOXPARAMS; - typedef PMSGBOXPARAMSA PMSGBOXPARAMS; - typedef LPMSGBOXPARAMSA LPMSGBOXPARAMS; -#endif - -#ifdef UNICODE -#define MessageBoxIndirect MessageBoxIndirectW -#else -#define MessageBoxIndirect MessageBoxIndirectA -#endif - - WINUSERAPI int WINAPI MessageBoxIndirectA(CONST MSGBOXPARAMSA *lpmbp); - WINUSERAPI int WINAPI MessageBoxIndirectW(CONST MSGBOXPARAMSW *lpmbp); - WINUSERAPI WINBOOL WINAPI MessageBeep(UINT uType); -#endif - - WINUSERAPI int WINAPI ShowCursor(WINBOOL bShow); - WINUSERAPI WINBOOL WINAPI SetCursorPos(int X,int Y); - WINUSERAPI HCURSOR WINAPI SetCursor(HCURSOR hCursor); - WINUSERAPI WINBOOL WINAPI GetCursorPos(LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ClipCursor(CONST RECT *lpRect); - WINUSERAPI WINBOOL WINAPI GetClipCursor(LPRECT lpRect); - WINUSERAPI HCURSOR WINAPI GetCursor(VOID); - WINUSERAPI WINBOOL WINAPI CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight); - WINUSERAPI UINT WINAPI GetCaretBlinkTime(VOID); - WINUSERAPI WINBOOL WINAPI SetCaretBlinkTime(UINT uMSeconds); - WINUSERAPI WINBOOL WINAPI DestroyCaret(VOID); - WINUSERAPI WINBOOL WINAPI HideCaret(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ShowCaret(HWND hWnd); - WINUSERAPI WINBOOL WINAPI SetCaretPos(int X,int Y); - WINUSERAPI WINBOOL WINAPI GetCaretPos(LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ClientToScreen(HWND hWnd,LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ScreenToClient(HWND hWnd,LPPOINT lpPoint); - WINUSERAPI int WINAPI MapWindowPoints(HWND hWndFrom,HWND hWndTo,LPPOINT lpPoints,UINT cPoints); - WINUSERAPI HWND WINAPI WindowFromPoint(POINT Point); - WINUSERAPI HWND WINAPI ChildWindowFromPoint(HWND hWndParent,POINT Point); - -#define CWP_ALL 0x0000 -#define CWP_SKIPINVISIBLE 0x0001 -#define CWP_SKIPDISABLED 0x0002 -#define CWP_SKIPTRANSPARENT 0x0004 - - WINUSERAPI HWND WINAPI ChildWindowFromPointEx(HWND hwnd,POINT pt,UINT flags); - -#ifndef NOCOLOR - -#define CTLCOLOR_MSGBOX 0 -#define CTLCOLOR_EDIT 1 -#define CTLCOLOR_LISTBOX 2 -#define CTLCOLOR_BTN 3 -#define CTLCOLOR_DLG 4 -#define CTLCOLOR_SCROLLBAR 5 -#define CTLCOLOR_STATIC 6 -#define CTLCOLOR_MAX 7 - -#define COLOR_SCROLLBAR 0 -#define COLOR_BACKGROUND 1 -#define COLOR_ACTIVECAPTION 2 -#define COLOR_INACTIVECAPTION 3 -#define COLOR_MENU 4 -#define COLOR_WINDOW 5 -#define COLOR_WINDOWFRAME 6 -#define COLOR_MENUTEXT 7 -#define COLOR_WINDOWTEXT 8 -#define COLOR_CAPTIONTEXT 9 -#define COLOR_ACTIVEBORDER 10 -#define COLOR_INACTIVEBORDER 11 -#define COLOR_APPWORKSPACE 12 -#define COLOR_HIGHLIGHT 13 -#define COLOR_HIGHLIGHTTEXT 14 -#define COLOR_BTNFACE 15 -#define COLOR_BTNSHADOW 16 -#define COLOR_GRAYTEXT 17 -#define COLOR_BTNTEXT 18 -#define COLOR_INACTIVECAPTIONTEXT 19 -#define COLOR_BTNHIGHLIGHT 20 - -#define COLOR_3DDKSHADOW 21 -#define COLOR_3DLIGHT 22 -#define COLOR_INFOTEXT 23 -#define COLOR_INFOBK 24 - -#define COLOR_HOTLIGHT 26 -#define COLOR_GRADIENTACTIVECAPTION 27 -#define COLOR_GRADIENTINACTIVECAPTION 28 -#define COLOR_MENUHILIGHT 29 -#define COLOR_MENUBAR 30 - -#define COLOR_DESKTOP COLOR_BACKGROUND -#define COLOR_3DFACE COLOR_BTNFACE -#define COLOR_3DSHADOW COLOR_BTNSHADOW -#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT -#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT -#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT - - WINUSERAPI DWORD WINAPI GetSysColor(int nIndex); - WINUSERAPI HBRUSH WINAPI GetSysColorBrush(int nIndex); - WINUSERAPI WINBOOL WINAPI SetSysColors(int cElements,CONST INT *lpaElements,CONST COLORREF *lpaRgbValues); -#endif - - WINUSERAPI WINBOOL WINAPI DrawFocusRect(HDC hDC,CONST RECT *lprc); - WINUSERAPI int WINAPI FillRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); - WINUSERAPI int WINAPI FrameRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); - WINUSERAPI WINBOOL WINAPI InvertRect(HDC hDC,CONST RECT *lprc); - WINUSERAPI WINBOOL WINAPI SetRect(LPRECT lprc,int xLeft,int yTop,int xRight,int yBottom); - WINUSERAPI WINBOOL WINAPI SetRectEmpty(LPRECT lprc); - WINUSERAPI WINBOOL WINAPI CopyRect(LPRECT lprcDst,CONST RECT *lprcSrc); - WINUSERAPI WINBOOL WINAPI InflateRect(LPRECT lprc,int dx,int dy); - WINUSERAPI WINBOOL WINAPI IntersectRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI UnionRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI SubtractRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI OffsetRect(LPRECT lprc,int dx,int dy); - WINUSERAPI WINBOOL WINAPI IsRectEmpty(CONST RECT *lprc); - WINUSERAPI WINBOOL WINAPI EqualRect(CONST RECT *lprc1,CONST RECT *lprc2); - WINUSERAPI WINBOOL WINAPI PtInRect(CONST RECT *lprc,POINT pt); - -#ifndef NOWINOFFSETS - -#ifdef UNICODE -#define GetWindowLong GetWindowLongW -#define SetWindowLong SetWindowLongW -#else -#define GetWindowLong GetWindowLongA -#define SetWindowLong SetWindowLongA -#endif - - WINUSERAPI WORD WINAPI GetWindowWord(HWND hWnd,int nIndex); - WINUSERAPI WORD WINAPI SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord); - WINUSERAPI LONG WINAPI GetWindowLongA(HWND hWnd,int nIndex); - WINUSERAPI LONG WINAPI GetWindowLongW(HWND hWnd,int nIndex); - WINUSERAPI LONG WINAPI SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong); - WINUSERAPI LONG WINAPI SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong); - -#ifdef _WIN64 - -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#define SetWindowLongPtr SetWindowLongPtrA -#endif - - WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrA(HWND hWnd,int nIndex); - WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrW(HWND hWnd,int nIndex); - WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); - WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); -#else - -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#define SetWindowLongPtr SetWindowLongPtrA -#endif - -#define GetWindowLongPtrA GetWindowLongA -#define GetWindowLongPtrW GetWindowLongW -#define SetWindowLongPtrA SetWindowLongA -#define SetWindowLongPtrW SetWindowLongW -#endif - -#ifdef UNICODE -#define GetClassLong GetClassLongW -#define SetClassLong SetClassLongW -#else -#define GetClassLong GetClassLongA -#define SetClassLong SetClassLongA -#endif - - WINUSERAPI WORD WINAPI GetClassWord(HWND hWnd,int nIndex); - WINUSERAPI WORD WINAPI SetClassWord(HWND hWnd,int nIndex,WORD wNewWord); - WINUSERAPI DWORD WINAPI GetClassLongA(HWND hWnd,int nIndex); - WINUSERAPI DWORD WINAPI GetClassLongW(HWND hWnd,int nIndex); - WINUSERAPI DWORD WINAPI SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong); - WINUSERAPI DWORD WINAPI SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong); - -#ifdef _WIN64 - -#ifdef UNICODE -#define GetClassLongPtr GetClassLongPtrW -#define SetClassLongPtr SetClassLongPtrW -#else -#define GetClassLongPtr GetClassLongPtrA -#define SetClassLongPtr SetClassLongPtrA -#endif - - WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrA(HWND hWnd,int nIndex); - WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrW(HWND hWnd,int nIndex); - WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); - WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); -#else -#ifdef UNICODE -#define GetClassLongPtr GetClassLongPtrW -#define SetClassLongPtr SetClassLongPtrW -#else -#define GetClassLongPtr GetClassLongPtrA -#define SetClassLongPtr SetClassLongPtrA -#endif - -#define GetClassLongPtrA GetClassLongA -#define GetClassLongPtrW GetClassLongW -#define SetClassLongPtrA SetClassLongA -#define SetClassLongPtrW SetClassLongW -#endif -#endif - -#ifdef UNICODE -#define FindWindow FindWindowW -#define FindWindowEx FindWindowExW -#define GetClassName GetClassNameW -#else -#define FindWindow FindWindowA -#define FindWindowEx FindWindowExA -#define GetClassName GetClassNameA -#endif - - WINUSERAPI WINBOOL WINAPI GetProcessDefaultLayout(DWORD *pdwDefaultLayout); - WINUSERAPI WINBOOL WINAPI SetProcessDefaultLayout(DWORD dwDefaultLayout); - WINUSERAPI HWND WINAPI GetDesktopWindow(VOID); - WINUSERAPI HWND WINAPI GetParent(HWND hWnd); - WINUSERAPI HWND WINAPI SetParent(HWND hWndChild,HWND hWndNewParent); - WINUSERAPI WINBOOL WINAPI EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAM lParam); - WINUSERAPI HWND WINAPI FindWindowA(LPCSTR lpClassName,LPCSTR lpWindowName); - WINUSERAPI HWND WINAPI FindWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName); - WINUSERAPI HWND WINAPI FindWindowExA(HWND hWndParent,HWND hWndChildAfter,LPCSTR lpszClass,LPCSTR lpszWindow); - WINUSERAPI HWND WINAPI FindWindowExW(HWND hWndParent,HWND hWndChildAfter,LPCWSTR lpszClass,LPCWSTR lpszWindow); - WINUSERAPI HWND WINAPI GetShellWindow(VOID); - WINUSERAPI WINBOOL WINAPI RegisterShellHookWindow(HWND hwnd); - WINUSERAPI WINBOOL WINAPI DeregisterShellHookWindow(HWND hwnd); - WINUSERAPI WINBOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumThreadWindows(DWORD dwThreadId,WNDENUMPROC lpfn,LPARAM lParam); - -#define EnumTaskWindows(hTask,lpfn,lParam) EnumThreadWindows(HandleToUlong(hTask),lpfn,lParam) - - WINUSERAPI int WINAPI GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); - WINUSERAPI int WINAPI GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount); - WINUSERAPI HWND WINAPI GetTopWindow(HWND hWnd); - -#define GetNextWindow(hWnd,wCmd) GetWindow(hWnd,wCmd) -#define GetSysModalWindow() (NULL) -#define SetSysModalWindow(hWnd) (NULL) - - WINUSERAPI DWORD WINAPI GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); - WINUSERAPI WINBOOL WINAPI IsGUIThread(WINBOOL bConvert); - -#define GetWindowTask(hWnd) ((HANDLE)(DWORD_PTR)GetWindowThreadProcessId(hWnd,NULL)) - - WINUSERAPI HWND WINAPI GetLastActivePopup(HWND hWnd); - -#define GW_HWNDFIRST 0 -#define GW_HWNDLAST 1 -#define GW_HWNDNEXT 2 -#define GW_HWNDPREV 3 -#define GW_OWNER 4 -#define GW_CHILD 5 -#define GW_ENABLEDPOPUP 6 -#define GW_MAX 6 - - WINUSERAPI HWND WINAPI GetWindow(HWND hWnd,UINT uCmd); - -#ifndef NOWH - -#ifdef UNICODE -#define SetWindowsHook SetWindowsHookW -#define SetWindowsHookEx SetWindowsHookExW -#else -#define SetWindowsHook SetWindowsHookA -#define SetWindowsHookEx SetWindowsHookExA -#endif - - WINUSERAPI HHOOK WINAPI SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc); - WINUSERAPI HHOOK WINAPI SetWindowsHookW(int nFilterType,HOOKPROC pfnFilterProc); - WINUSERAPI WINBOOL WINAPI UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc); - WINUSERAPI HHOOK WINAPI SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); - WINUSERAPI HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); - WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx(HHOOK hhk); - WINUSERAPI LRESULT WINAPI CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam); -#define DefHookProc(nCode,wParam,lParam,phhk) CallNextHookEx(*phhk,nCode,wParam,lParam) -#endif - -#ifndef NOMENUS - -#define MF_INSERT 0x00000000L -#define MF_CHANGE 0x00000080L -#define MF_APPEND 0x00000100L -#define MF_DELETE 0x00000200L -#define MF_REMOVE 0x00001000L -#define MF_BYCOMMAND 0x00000000L -#define MF_BYPOSITION 0x00000400L -#define MF_SEPARATOR 0x00000800L -#define MF_ENABLED 0x00000000L -#define MF_GRAYED 0x00000001L -#define MF_DISABLED 0x00000002L -#define MF_UNCHECKED 0x00000000L -#define MF_CHECKED 0x00000008L -#define MF_USECHECKBITMAPS 0x00000200L -#define MF_STRING 0x00000000L -#define MF_BITMAP 0x00000004L -#define MF_OWNERDRAW 0x00000100L -#define MF_POPUP 0x00000010L -#define MF_MENUBARBREAK 0x00000020L -#define MF_MENUBREAK 0x00000040L -#define MF_UNHILITE 0x00000000L -#define MF_HILITE 0x00000080L -#define MF_DEFAULT 0x00001000L -#define MF_SYSMENU 0x00002000L -#define MF_HELP 0x00004000L -#define MF_RIGHTJUSTIFY 0x00004000L -#define MF_MOUSESELECT 0x00008000L -#define MF_END 0x00000080L - -#define MFT_STRING MF_STRING -#define MFT_BITMAP MF_BITMAP -#define MFT_MENUBARBREAK MF_MENUBARBREAK -#define MFT_MENUBREAK MF_MENUBREAK -#define MFT_OWNERDRAW MF_OWNERDRAW -#define MFT_RADIOCHECK 0x00000200L -#define MFT_SEPARATOR MF_SEPARATOR -#define MFT_RIGHTORDER 0x00002000L -#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY - -#define MFS_GRAYED 0x00000003L -#define MFS_DISABLED MFS_GRAYED -#define MFS_CHECKED MF_CHECKED -#define MFS_HILITE MF_HILITE -#define MFS_ENABLED MF_ENABLED -#define MFS_UNCHECKED MF_UNCHECKED -#define MFS_UNHILITE MF_UNHILITE -#define MFS_DEFAULT MF_DEFAULT - - WINUSERAPI WINBOOL WINAPI CheckMenuRadioItem(HMENU hmenu,UINT first,UINT last,UINT check,UINT flags); - - typedef struct { - WORD versionNumber; - WORD offset; - } MENUITEMTEMPLATEHEADER,*PMENUITEMTEMPLATEHEADER; - - typedef struct { - WORD mtOption; - WORD mtID; - WCHAR mtString[1]; - } MENUITEMTEMPLATE,*PMENUITEMTEMPLATE; -#define MF_END 0x00000080L -#endif - -#ifndef NOSYSCOMMANDS - -#define SC_SIZE 0xF000 -#define SC_MOVE 0xF010 -#define SC_MINIMIZE 0xF020 -#define SC_MAXIMIZE 0xF030 -#define SC_NEXTWINDOW 0xF040 -#define SC_PREVWINDOW 0xF050 -#define SC_CLOSE 0xF060 -#define SC_VSCROLL 0xF070 -#define SC_HSCROLL 0xF080 -#define SC_MOUSEMENU 0xF090 -#define SC_KEYMENU 0xF100 -#define SC_ARRANGE 0xF110 -#define SC_RESTORE 0xF120 -#define SC_TASKLIST 0xF130 -#define SC_SCREENSAVE 0xF140 -#define SC_HOTKEY 0xF150 -#define SC_DEFAULT 0xF160 -#define SC_MONITORPOWER 0xF170 -#define SC_CONTEXTHELP 0xF180 -#define SC_SEPARATOR 0xF00F -#define SC_ICON SC_MINIMIZE -#define SC_ZOOM SC_MAXIMIZE -#endif - -#ifdef UNICODE -#define LoadBitmap LoadBitmapW -#define LoadCursor LoadCursorW -#define LoadCursorFromFile LoadCursorFromFileW -#else -#define LoadBitmap LoadBitmapA -#define LoadCursor LoadCursorA -#define LoadCursorFromFile LoadCursorFromFileA -#endif - - WINUSERAPI HBITMAP WINAPI LoadBitmapA(HINSTANCE hInstance,LPCSTR lpBitmapName); - WINUSERAPI HBITMAP WINAPI LoadBitmapW(HINSTANCE hInstance,LPCWSTR lpBitmapName); - WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance,LPCSTR lpCursorName); - WINUSERAPI HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); - WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA(LPCSTR lpFileName); - WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR lpFileName); - WINUSERAPI HCURSOR WINAPI CreateCursor(HINSTANCE hInst,int xHotSpot,int yHotSpot,int nWidth,int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane); - WINUSERAPI WINBOOL WINAPI DestroyCursor(HCURSOR hCursor); - -#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur))) - -#define IDC_ARROW MAKEINTRESOURCE(32512) -#define IDC_IBEAM MAKEINTRESOURCE(32513) -#define IDC_WAIT MAKEINTRESOURCE(32514) -#define IDC_CROSS MAKEINTRESOURCE(32515) -#define IDC_UPARROW MAKEINTRESOURCE(32516) -#define IDC_SIZE MAKEINTRESOURCE(32640) -#define IDC_ICON MAKEINTRESOURCE(32641) -#define IDC_SIZENWSE MAKEINTRESOURCE(32642) -#define IDC_SIZENESW MAKEINTRESOURCE(32643) -#define IDC_SIZEWE MAKEINTRESOURCE(32644) -#define IDC_SIZENS MAKEINTRESOURCE(32645) -#define IDC_SIZEALL MAKEINTRESOURCE(32646) -#define IDC_NO MAKEINTRESOURCE(32648) -#define IDC_HAND MAKEINTRESOURCE(32649) -#define IDC_APPSTARTING MAKEINTRESOURCE(32650) -#define IDC_HELP MAKEINTRESOURCE(32651) - - WINUSERAPI WINBOOL WINAPI SetSystemCursor(HCURSOR hcur,DWORD id); - - typedef struct _ICONINFO { - WINBOOL fIcon; - DWORD xHotspot; - DWORD yHotspot; - HBITMAP hbmMask; - HBITMAP hbmColor; - } ICONINFO; - typedef ICONINFO *PICONINFO; - -#ifdef UNICODE -#define LoadIcon LoadIconW -#define PrivateExtractIcons PrivateExtractIconsW -#else -#define LoadIcon LoadIconA -#define PrivateExtractIcons PrivateExtractIconsA -#endif - - WINUSERAPI HICON WINAPI LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName); - WINUSERAPI HICON WINAPI LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); - WINUSERAPI UINT WINAPI PrivateExtractIconsA(LPCSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); - WINUSERAPI UINT WINAPI PrivateExtractIconsW(LPCWSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); - WINUSERAPI HICON WINAPI CreateIcon(HINSTANCE hInstance,int nWidth,int nHeight,BYTE cPlanes,BYTE cBitsPixel,CONST BYTE *lpbANDbits,CONST BYTE *lpbXORbits); - WINUSERAPI WINBOOL WINAPI DestroyIcon(HICON hIcon); - WINUSERAPI int WINAPI LookupIconIdFromDirectory(PBYTE presbits,WINBOOL fIcon); - WINUSERAPI int WINAPI LookupIconIdFromDirectoryEx(PBYTE presbits,WINBOOL fIcon,int cxDesired,int cyDesired,UINT Flags); - WINUSERAPI HICON WINAPI CreateIconFromResource(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer); - WINUSERAPI HICON WINAPI CreateIconFromResourceEx(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer,int cxDesired,int cyDesired,UINT Flags); - - typedef struct tagCURSORSHAPE { - int xHotSpot; - int yHotSpot; - int cx; - int cy; - int cbWidth; - BYTE Planes; - BYTE BitsPixel; - } CURSORSHAPE,*LPCURSORSHAPE; - -#define IMAGE_BITMAP 0 -#define IMAGE_ICON 1 -#define IMAGE_CURSOR 2 -#define IMAGE_ENHMETAFILE 3 - -#define LR_DEFAULTCOLOR 0x0000 -#define LR_MONOCHROME 0x0001 -#define LR_COLOR 0x0002 -#define LR_COPYRETURNORG 0x0004 -#define LR_COPYDELETEORG 0x0008 -#define LR_LOADFROMFILE 0x0010 -#define LR_LOADTRANSPARENT 0x0020 -#define LR_DEFAULTSIZE 0x0040 -#define LR_VGACOLOR 0x0080 -#define LR_LOADMAP3DCOLORS 0x1000 -#define LR_CREATEDIBSECTION 0x2000 -#define LR_COPYFROMRESOURCE 0x4000 -#define LR_SHARED 0x8000 - -#ifdef UNICODE -#define LoadImage LoadImageW -#else -#define LoadImage LoadImageA -#endif - - WINUSERAPI HANDLE WINAPI LoadImageA(HINSTANCE hInst,LPCSTR name,UINT type,int cx,int cy,UINT fuLoad); - WINUSERAPI HANDLE WINAPI LoadImageW(HINSTANCE hInst,LPCWSTR name,UINT type,int cx,int cy,UINT fuLoad); - WINUSERAPI HANDLE WINAPI CopyImage(HANDLE h,UINT type,int cx,int cy,UINT flags); - -#define DI_MASK 0x0001 -#define DI_IMAGE 0x0002 -#define DI_NORMAL 0x0003 -#define DI_COMPAT 0x0004 -#define DI_DEFAULTSIZE 0x0008 -#define DI_NOMIRROR 0x0010 - - WINUSERAPI WINBOOL WINAPI DrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags); - WINUSERAPI HICON WINAPI CreateIconIndirect(PICONINFO piconinfo); - WINUSERAPI HICON WINAPI CopyIcon(HICON hIcon); - WINUSERAPI WINBOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO piconinfo); - -#define RES_ICON 1 -#define RES_CURSOR 2 - -#ifdef OEMRESOURCE - -#define OBM_CLOSE 32754 -#define OBM_UPARROW 32753 -#define OBM_DNARROW 32752 -#define OBM_RGARROW 32751 -#define OBM_LFARROW 32750 -#define OBM_REDUCE 32749 -#define OBM_ZOOM 32748 -#define OBM_RESTORE 32747 -#define OBM_REDUCED 32746 -#define OBM_ZOOMD 32745 -#define OBM_RESTORED 32744 -#define OBM_UPARROWD 32743 -#define OBM_DNARROWD 32742 -#define OBM_RGARROWD 32741 -#define OBM_LFARROWD 32740 -#define OBM_MNARROW 32739 -#define OBM_COMBO 32738 -#define OBM_UPARROWI 32737 -#define OBM_DNARROWI 32736 -#define OBM_RGARROWI 32735 -#define OBM_LFARROWI 32734 - -#define OBM_OLD_CLOSE 32767 -#define OBM_SIZE 32766 -#define OBM_OLD_UPARROW 32765 -#define OBM_OLD_DNARROW 32764 -#define OBM_OLD_RGARROW 32763 -#define OBM_OLD_LFARROW 32762 -#define OBM_BTSIZE 32761 -#define OBM_CHECK 32760 -#define OBM_CHECKBOXES 32759 -#define OBM_BTNCORNERS 32758 -#define OBM_OLD_REDUCE 32757 -#define OBM_OLD_ZOOM 32756 -#define OBM_OLD_RESTORE 32755 - -#define OCR_NORMAL 32512 -#define OCR_IBEAM 32513 -#define OCR_WAIT 32514 -#define OCR_CROSS 32515 -#define OCR_UP 32516 -#define OCR_SIZE 32640 -#define OCR_ICON 32641 -#define OCR_SIZENWSE 32642 -#define OCR_SIZENESW 32643 -#define OCR_SIZEWE 32644 -#define OCR_SIZENS 32645 -#define OCR_SIZEALL 32646 -#define OCR_ICOCUR 32647 -#define OCR_NO 32648 -#define OCR_HAND 32649 -#define OCR_APPSTARTING 32650 - -#define OIC_SAMPLE 32512 -#define OIC_HAND 32513 -#define OIC_QUES 32514 -#define OIC_BANG 32515 -#define OIC_NOTE 32516 -#define OIC_WINLOGO 32517 -#define OIC_WARNING OIC_BANG -#define OIC_ERROR OIC_HAND -#define OIC_INFORMATION OIC_NOTE -#endif - -#define ORD_LANGDRIVER 1 - -#ifndef NOICONS - -#ifdef RC_INVOKED -#define IDI_APPLICATION 32512 -#define IDI_HAND 32513 -#define IDI_QUESTION 32514 -#define IDI_EXCLAMATION 32515 -#define IDI_ASTERISK 32516 -#define IDI_WINLOGO 32517 -#else -#define IDI_APPLICATION MAKEINTRESOURCE(32512) -#define IDI_HAND MAKEINTRESOURCE(32513) -#define IDI_QUESTION MAKEINTRESOURCE(32514) -#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) -#define IDI_ASTERISK MAKEINTRESOURCE(32516) -#define IDI_WINLOGO MAKEINTRESOURCE(32517) -#endif - -#define IDI_WARNING IDI_EXCLAMATION -#define IDI_ERROR IDI_HAND -#define IDI_INFORMATION IDI_ASTERISK -#endif - -#ifdef UNICODE -#define LoadString LoadStringW -#else -#define LoadString LoadStringA -#endif - - WINUSERAPI int WINAPI LoadStringA(HINSTANCE hInstance,UINT uID,LPSTR lpBuffer,int cchBufferMax); - WINUSERAPI int WINAPI LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax); - -#define IDOK 1 -#define IDCANCEL 2 -#define IDABORT 3 -#define IDRETRY 4 -#define IDIGNORE 5 -#define IDYES 6 -#define IDNO 7 -#define IDCLOSE 8 -#define IDHELP 9 -#define IDTRYAGAIN 10 -#define IDCONTINUE 11 - -#ifndef IDTIMEOUT -#define IDTIMEOUT 32000 -#endif - -#ifndef NOCTLMGR - -#ifndef NOWINSTYLES -#define ES_LEFT 0x0000L -#define ES_CENTER 0x0001L -#define ES_RIGHT 0x0002L -#define ES_MULTILINE 0x0004L -#define ES_UPPERCASE 0x0008L -#define ES_LOWERCASE 0x0010L -#define ES_PASSWORD 0x0020L -#define ES_AUTOVSCROLL 0x0040L -#define ES_AUTOHSCROLL 0x0080L -#define ES_NOHIDESEL 0x0100L -#define ES_OEMCONVERT 0x0400L -#define ES_READONLY 0x0800L -#define ES_WANTRETURN 0x1000L -#define ES_NUMBER 0x2000L -#endif - -#define EN_SETFOCUS 0x0100 -#define EN_KILLFOCUS 0x0200 -#define EN_CHANGE 0x0300 -#define EN_UPDATE 0x0400 -#define EN_ERRSPACE 0x0500 -#define EN_MAXTEXT 0x0501 -#define EN_HSCROLL 0x0601 -#define EN_VSCROLL 0x0602 -#define EN_ALIGN_LTR_EC 0x0700 -#define EN_ALIGN_RTL_EC 0x0701 - -#define EC_LEFTMARGIN 0x0001 -#define EC_RIGHTMARGIN 0x0002 -#define EC_USEFONTINFO 0xffff - -#define EMSIS_COMPOSITIONSTRING 0x0001 - -#define EIMES_GETCOMPSTRATONCE 0x0001 -#define EIMES_CANCELCOMPSTRINFOCUS 0x0002 -#define EIMES_COMPLETECOMPSTRKILLFOCUS 0x0004 - -#ifndef NOWINMESSAGES - -#define EM_GETSEL 0x00B0 -#define EM_SETSEL 0x00B1 -#define EM_GETRECT 0x00B2 -#define EM_SETRECT 0x00B3 -#define EM_SETRECTNP 0x00B4 -#define EM_SCROLL 0x00B5 -#define EM_LINESCROLL 0x00B6 -#define EM_SCROLLCARET 0x00B7 -#define EM_GETMODIFY 0x00B8 -#define EM_SETMODIFY 0x00B9 -#define EM_GETLINECOUNT 0x00BA -#define EM_LINEINDEX 0x00BB -#define EM_SETHANDLE 0x00BC -#define EM_GETHANDLE 0x00BD -#define EM_GETTHUMB 0x00BE -#define EM_LINELENGTH 0x00C1 -#define EM_REPLACESEL 0x00C2 -#define EM_GETLINE 0x00C4 -#define EM_LIMITTEXT 0x00C5 -#define EM_CANUNDO 0x00C6 -#define EM_UNDO 0x00C7 -#define EM_FMTLINES 0x00C8 -#define EM_LINEFROMCHAR 0x00C9 -#define EM_SETTABSTOPS 0x00CB -#define EM_SETPASSWORDCHAR 0x00CC -#define EM_EMPTYUNDOBUFFER 0x00CD -#define EM_GETFIRSTVISIBLELINE 0x00CE -#define EM_SETREADONLY 0x00CF -#define EM_SETWORDBREAKPROC 0x00D0 -#define EM_GETWORDBREAKPROC 0x00D1 -#define EM_GETPASSWORDCHAR 0x00D2 -#define EM_SETMARGINS 0x00D3 -#define EM_GETMARGINS 0x00D4 -#define EM_SETLIMITTEXT EM_LIMITTEXT -#define EM_GETLIMITTEXT 0x00D5 -#define EM_POSFROMCHAR 0x00D6 -#define EM_CHARFROMPOS 0x00D7 -#define EM_SETIMESTATUS 0x00D8 -#define EM_GETIMESTATUS 0x00D9 -#endif - -#define WB_LEFT 0 -#define WB_RIGHT 1 -#define WB_ISDELIMITER 2 - -#define BS_PUSHBUTTON 0x00000000L -#define BS_DEFPUSHBUTTON 0x00000001L -#define BS_CHECKBOX 0x00000002L -#define BS_AUTOCHECKBOX 0x00000003L -#define BS_RADIOBUTTON 0x00000004L -#define BS_3STATE 0x00000005L -#define BS_AUTO3STATE 0x00000006L -#define BS_GROUPBOX 0x00000007L -#define BS_USERBUTTON 0x00000008L -#define BS_AUTORADIOBUTTON 0x00000009L -#define BS_PUSHBOX 0x0000000AL -#define BS_OWNERDRAW 0x0000000BL -#define BS_TYPEMASK 0x0000000FL -#define BS_LEFTTEXT 0x00000020L -#define BS_TEXT 0x00000000L -#define BS_ICON 0x00000040L -#define BS_BITMAP 0x00000080L -#define BS_LEFT 0x00000100L -#define BS_RIGHT 0x00000200L -#define BS_CENTER 0x00000300L -#define BS_TOP 0x00000400L -#define BS_BOTTOM 0x00000800L -#define BS_VCENTER 0x00000C00L -#define BS_PUSHLIKE 0x00001000L -#define BS_MULTILINE 0x00002000L -#define BS_NOTIFY 0x00004000L -#define BS_FLAT 0x00008000L -#define BS_RIGHTBUTTON BS_LEFTTEXT - -#define BN_CLICKED 0 -#define BN_PAINT 1 -#define BN_HILITE 2 -#define BN_UNHILITE 3 -#define BN_DISABLE 4 -#define BN_DOUBLECLICKED 5 -#define BN_PUSHED BN_HILITE -#define BN_UNPUSHED BN_UNHILITE -#define BN_DBLCLK BN_DOUBLECLICKED -#define BN_SETFOCUS 6 -#define BN_KILLFOCUS 7 - -#define BM_GETCHECK 0x00F0 -#define BM_SETCHECK 0x00F1 -#define BM_GETSTATE 0x00F2 -#define BM_SETSTATE 0x00F3 -#define BM_SETSTYLE 0x00F4 -#define BM_CLICK 0x00F5 -#define BM_GETIMAGE 0x00F6 -#define BM_SETIMAGE 0x00F7 - -#define BST_UNCHECKED 0x0000 -#define BST_CHECKED 0x0001 -#define BST_INDETERMINATE 0x0002 -#define BST_PUSHED 0x0004 -#define BST_FOCUS 0x0008 - -#define SS_LEFT 0x00000000L -#define SS_CENTER 0x00000001L -#define SS_RIGHT 0x00000002L -#define SS_ICON 0x00000003L -#define SS_BLACKRECT 0x00000004L -#define SS_GRAYRECT 0x00000005L -#define SS_WHITERECT 0x00000006L -#define SS_BLACKFRAME 0x00000007L -#define SS_GRAYFRAME 0x00000008L -#define SS_WHITEFRAME 0x00000009L -#define SS_USERITEM 0x0000000AL -#define SS_SIMPLE 0x0000000BL -#define SS_LEFTNOWORDWRAP 0x0000000CL -#define SS_OWNERDRAW 0x0000000DL -#define SS_BITMAP 0x0000000EL -#define SS_ENHMETAFILE 0x0000000FL -#define SS_ETCHEDHORZ 0x00000010L -#define SS_ETCHEDVERT 0x00000011L -#define SS_ETCHEDFRAME 0x00000012L -#define SS_TYPEMASK 0x0000001FL -#define SS_REALSIZECONTROL 0x00000040L -#define SS_NOPREFIX 0x00000080L -#define SS_NOTIFY 0x00000100L -#define SS_CENTERIMAGE 0x00000200L -#define SS_RIGHTJUST 0x00000400L -#define SS_REALSIZEIMAGE 0x00000800L -#define SS_SUNKEN 0x00001000L -#define SS_EDITCONTROL 0x00002000L -#define SS_ENDELLIPSIS 0x00004000L -#define SS_PATHELLIPSIS 0x00008000L -#define SS_WORDELLIPSIS 0x0000C000L -#define SS_ELLIPSISMASK 0x0000C000L - -#ifndef NOWINMESSAGES - -#define STM_SETICON 0x0170 -#define STM_GETICON 0x0171 -#define STM_SETIMAGE 0x0172 -#define STM_GETIMAGE 0x0173 -#define STN_CLICKED 0 -#define STN_DBLCLK 1 -#define STN_ENABLE 2 -#define STN_DISABLE 3 -#define STM_MSGMAX 0x0174 -#endif - -#define WC_DIALOG (MAKEINTATOM(0x8002)) - -#define DWL_MSGRESULT 0 -#define DWL_DLGPROC 4 -#define DWL_USER 8 - -#ifdef _WIN64 - -#undef DWL_MSGRESULT -#undef DWL_DLGPROC -#undef DWL_USER -#endif - -#define DWLP_MSGRESULT 0 -#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) - -#ifndef NOMSG - -#ifdef UNICODE -#define IsDialogMessage IsDialogMessageW -#else -#define IsDialogMessage IsDialogMessageA -#endif - - WINUSERAPI WINBOOL WINAPI IsDialogMessageA(HWND hDlg,LPMSG lpMsg); - WINUSERAPI WINBOOL WINAPI IsDialogMessageW(HWND hDlg,LPMSG lpMsg); -#endif - -#ifdef UNICODE -#define DlgDirList DlgDirListW -#define DlgDirSelectEx DlgDirSelectExW -#define DlgDirListComboBox DlgDirListComboBoxW -#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW -#else -#define DlgDirList DlgDirListA -#define DlgDirSelectEx DlgDirSelectExA -#define DlgDirListComboBox DlgDirListComboBoxA -#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA -#endif - - WINUSERAPI WINBOOL WINAPI MapDialogRect(HWND hDlg,LPRECT lpRect); - WINUSERAPI int WINAPI DlgDirListA(HWND hDlg,LPSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); - WINUSERAPI int WINAPI DlgDirListW(HWND hDlg,LPWSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); - -#define DDL_READWRITE 0x0000 -#define DDL_READONLY 0x0001 -#define DDL_HIDDEN 0x0002 -#define DDL_SYSTEM 0x0004 -#define DDL_DIRECTORY 0x0010 -#define DDL_ARCHIVE 0x0020 - -#define DDL_POSTMSGS 0x2000 -#define DDL_DRIVES 0x4000 -#define DDL_EXCLUSIVE 0x8000 - - WINUSERAPI WINBOOL WINAPI DlgDirSelectExA(HWND hwndDlg,LPSTR lpString,int chCount,int idListBox); - WINUSERAPI WINBOOL WINAPI DlgDirSelectExW(HWND hwndDlg,LPWSTR lpString,int chCount,int idListBox); - WINUSERAPI int WINAPI DlgDirListComboBoxA(HWND hDlg,LPSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); - WINUSERAPI int WINAPI DlgDirListComboBoxW(HWND hDlg,LPWSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); - WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExA(HWND hwndDlg,LPSTR lpString,int cchOut,int idComboBox); - WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExW(HWND hwndDlg,LPWSTR lpString,int cchOut,int idComboBox); - -#define DS_ABSALIGN 0x01L -#define DS_SYSMODAL 0x02L -#define DS_LOCALEDIT 0x20L -#define DS_SETFONT 0x40L -#define DS_MODALFRAME 0x80L -#define DS_NOIDLEMSG 0x100L -#define DS_SETFOREGROUND 0x200L - -#define DS_3DLOOK 0x0004L -#define DS_FIXEDSYS 0x0008L -#define DS_NOFAILCREATE 0x0010L -#define DS_CONTROL 0x0400L -#define DS_CENTER 0x0800L -#define DS_CENTERMOUSE 0x1000L -#define DS_CONTEXTHELP 0x2000L - -#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) - -#if(_WIN32_WCE >= 0x0500) -#define DS_USEPIXELS 0x8000L -#endif - -#define DM_GETDEFID (WM_USER+0) -#define DM_SETDEFID (WM_USER+1) -#define DM_REPOSITION (WM_USER+2) - -#define DC_HASDEFID 0x534B - -#define DLGC_WANTARROWS 0x0001 -#define DLGC_WANTTAB 0x0002 -#define DLGC_WANTALLKEYS 0x0004 -#define DLGC_WANTMESSAGE 0x0004 -#define DLGC_HASSETSEL 0x0008 -#define DLGC_DEFPUSHBUTTON 0x0010 -#define DLGC_UNDEFPUSHBUTTON 0x0020 -#define DLGC_RADIOBUTTON 0x0040 -#define DLGC_WANTCHARS 0x0080 -#define DLGC_STATIC 0x0100 -#define DLGC_BUTTON 0x2000 - -#define LB_CTLCODE 0L - -#define LB_OKAY 0 -#define LB_ERR (-1) -#define LB_ERRSPACE (-2) - -#define LBN_ERRSPACE (-2) -#define LBN_SELCHANGE 1 -#define LBN_DBLCLK 2 -#define LBN_SELCANCEL 3 -#define LBN_SETFOCUS 4 -#define LBN_KILLFOCUS 5 - -#ifndef NOWINMESSAGES - -#define LB_ADDSTRING 0x0180 -#define LB_INSERTSTRING 0x0181 -#define LB_DELETESTRING 0x0182 -#define LB_SELITEMRANGEEX 0x0183 -#define LB_RESETCONTENT 0x0184 -#define LB_SETSEL 0x0185 -#define LB_SETCURSEL 0x0186 -#define LB_GETSEL 0x0187 -#define LB_GETCURSEL 0x0188 -#define LB_GETTEXT 0x0189 -#define LB_GETTEXTLEN 0x018A -#define LB_GETCOUNT 0x018B -#define LB_SELECTSTRING 0x018C -#define LB_DIR 0x018D -#define LB_GETTOPINDEX 0x018E -#define LB_FINDSTRING 0x018F -#define LB_GETSELCOUNT 0x0190 -#define LB_GETSELITEMS 0x0191 -#define LB_SETTABSTOPS 0x0192 -#define LB_GETHORIZONTALEXTENT 0x0193 -#define LB_SETHORIZONTALEXTENT 0x0194 -#define LB_SETCOLUMNWIDTH 0x0195 -#define LB_ADDFILE 0x0196 -#define LB_SETTOPINDEX 0x0197 -#define LB_GETITEMRECT 0x0198 -#define LB_GETITEMDATA 0x0199 -#define LB_SETITEMDATA 0x019A -#define LB_SELITEMRANGE 0x019B -#define LB_SETANCHORINDEX 0x019C -#define LB_GETANCHORINDEX 0x019D -#define LB_SETCARETINDEX 0x019E -#define LB_GETCARETINDEX 0x019F -#define LB_SETITEMHEIGHT 0x01A0 -#define LB_GETITEMHEIGHT 0x01A1 -#define LB_FINDSTRINGEXACT 0x01A2 -#define LB_SETLOCALE 0x01A5 -#define LB_GETLOCALE 0x01A6 -#define LB_SETCOUNT 0x01A7 -#define LB_INITSTORAGE 0x01A8 -#define LB_ITEMFROMPOINT 0x01A9 -#if(_WIN32_WCE >= 0x0400) -#define LB_MULTIPLEADDSTRING 0x01B1 -#endif -#define LB_GETLISTBOXINFO 0x01B2 -#define LB_MSGMAX 0x01B3 -#endif - -#ifndef NOWINSTYLES - -#define LBS_NOTIFY 0x0001L -#define LBS_SORT 0x0002L -#define LBS_NOREDRAW 0x0004L -#define LBS_MULTIPLESEL 0x0008L -#define LBS_OWNERDRAWFIXED 0x0010L -#define LBS_OWNERDRAWVARIABLE 0x0020L -#define LBS_HASSTRINGS 0x0040L -#define LBS_USETABSTOPS 0x0080L -#define LBS_NOINTEGRALHEIGHT 0x0100L -#define LBS_MULTICOLUMN 0x0200L -#define LBS_WANTKEYBOARDINPUT 0x0400L -#define LBS_EXTENDEDSEL 0x0800L -#define LBS_DISABLENOSCROLL 0x1000L -#define LBS_NODATA 0x2000L -#define LBS_NOSEL 0x4000L -#define LBS_COMBOBOX 0x8000L - -#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) -#endif - -#define CB_OKAY 0 -#define CB_ERR (-1) -#define CB_ERRSPACE (-2) - -#define CBN_ERRSPACE (-1) -#define CBN_SELCHANGE 1 -#define CBN_DBLCLK 2 -#define CBN_SETFOCUS 3 -#define CBN_KILLFOCUS 4 -#define CBN_EDITCHANGE 5 -#define CBN_EDITUPDATE 6 -#define CBN_DROPDOWN 7 -#define CBN_CLOSEUP 8 -#define CBN_SELENDOK 9 -#define CBN_SELENDCANCEL 10 - -#ifndef NOWINSTYLES - -#define CBS_SIMPLE 0x0001L -#define CBS_DROPDOWN 0x0002L -#define CBS_DROPDOWNLIST 0x0003L -#define CBS_OWNERDRAWFIXED 0x0010L -#define CBS_OWNERDRAWVARIABLE 0x0020L -#define CBS_AUTOHSCROLL 0x0040L -#define CBS_OEMCONVERT 0x0080L -#define CBS_SORT 0x0100L -#define CBS_HASSTRINGS 0x0200L -#define CBS_NOINTEGRALHEIGHT 0x0400L -#define CBS_DISABLENOSCROLL 0x0800L -#define CBS_UPPERCASE 0x2000L -#define CBS_LOWERCASE 0x4000L -#endif - -#ifndef NOWINMESSAGES -#define CB_GETEDITSEL 0x0140 -#define CB_LIMITTEXT 0x0141 -#define CB_SETEDITSEL 0x0142 -#define CB_ADDSTRING 0x0143 -#define CB_DELETESTRING 0x0144 -#define CB_DIR 0x0145 -#define CB_GETCOUNT 0x0146 -#define CB_GETCURSEL 0x0147 -#define CB_GETLBTEXT 0x0148 -#define CB_GETLBTEXTLEN 0x0149 -#define CB_INSERTSTRING 0x014A -#define CB_RESETCONTENT 0x014B -#define CB_FINDSTRING 0x014C -#define CB_SELECTSTRING 0x014D -#define CB_SETCURSEL 0x014E -#define CB_SHOWDROPDOWN 0x014F -#define CB_GETITEMDATA 0x0150 -#define CB_SETITEMDATA 0x0151 -#define CB_GETDROPPEDCONTROLRECT 0x0152 -#define CB_SETITEMHEIGHT 0x0153 -#define CB_GETITEMHEIGHT 0x0154 -#define CB_SETEXTENDEDUI 0x0155 -#define CB_GETEXTENDEDUI 0x0156 -#define CB_GETDROPPEDSTATE 0x0157 -#define CB_FINDSTRINGEXACT 0x0158 -#define CB_SETLOCALE 0x0159 -#define CB_GETLOCALE 0x015A -#define CB_GETTOPINDEX 0x015b -#define CB_SETTOPINDEX 0x015c -#define CB_GETHORIZONTALEXTENT 0x015d -#define CB_SETHORIZONTALEXTENT 0x015e -#define CB_GETDROPPEDWIDTH 0x015f -#define CB_SETDROPPEDWIDTH 0x0160 -#define CB_INITSTORAGE 0x0161 -#if(_WIN32_WCE >= 0x0400) -#define CB_MULTIPLEADDSTRING 0x0163 -#endif -#define CB_GETCOMBOBOXINFO 0x0164 -#define CB_MSGMAX 0x0165 -#endif - -#ifndef NOWINSTYLES - -#define SBS_HORZ 0x0000L -#define SBS_VERT 0x0001L -#define SBS_TOPALIGN 0x0002L -#define SBS_LEFTALIGN 0x0002L -#define SBS_BOTTOMALIGN 0x0004L -#define SBS_RIGHTALIGN 0x0004L -#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L -#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L -#define SBS_SIZEBOX 0x0008L -#define SBS_SIZEGRIP 0x0010L -#endif - -#ifndef NOWINMESSAGES -#define SBM_SETPOS 0x00E0 -#define SBM_GETPOS 0x00E1 -#define SBM_SETRANGE 0x00E2 -#define SBM_SETRANGEREDRAW 0x00E6 -#define SBM_GETRANGE 0x00E3 -#define SBM_ENABLE_ARROWS 0x00E4 -#define SBM_SETSCROLLINFO 0x00E9 -#define SBM_GETSCROLLINFO 0x00EA -#define SBM_GETSCROLLBARINFO 0x00EB - -#define SIF_RANGE 0x0001 -#define SIF_PAGE 0x0002 -#define SIF_POS 0x0004 -#define SIF_DISABLENOSCROLL 0x0008 -#define SIF_TRACKPOS 0x0010 -#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) - - typedef struct tagSCROLLINFO { - UINT cbSize; - UINT fMask; - int nMin; - int nMax; - UINT nPage; - int nPos; - int nTrackPos; - } SCROLLINFO,*LPSCROLLINFO; - typedef SCROLLINFO CONST *LPCSCROLLINFO; - - WINUSERAPI int WINAPI SetScrollInfo(HWND hwnd,int nBar,LPCSCROLLINFO lpsi,WINBOOL redraw); - WINUSERAPI WINBOOL WINAPI GetScrollInfo(HWND hwnd,int nBar,LPSCROLLINFO lpsi); -#endif -#endif - -#ifndef NOMDI - -#define MDIS_ALLCHILDSTYLES 0x0001 - -#define MDITILE_VERTICAL 0x0000 -#define MDITILE_HORIZONTAL 0x0001 -#define MDITILE_SKIPDISABLED 0x0002 -#define MDITILE_ZORDER 0x0004 - - typedef struct tagMDICREATESTRUCTA { - LPCSTR szClass; - LPCSTR szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - DWORD style; - LPARAM lParam; - } MDICREATESTRUCTA,*LPMDICREATESTRUCTA; - - typedef struct tagMDICREATESTRUCTW { - LPCWSTR szClass; - LPCWSTR szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - DWORD style; - LPARAM lParam; - } MDICREATESTRUCTW,*LPMDICREATESTRUCTW; - -#ifdef UNICODE - typedef MDICREATESTRUCTW MDICREATESTRUCT; - typedef LPMDICREATESTRUCTW LPMDICREATESTRUCT; -#else - typedef MDICREATESTRUCTA MDICREATESTRUCT; - typedef LPMDICREATESTRUCTA LPMDICREATESTRUCT; -#endif - - typedef struct tagCLIENTCREATESTRUCT { - HANDLE hWindowMenu; - UINT idFirstChild; - } CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT; - -#ifdef UNICODE -#define DefFrameProc DefFrameProcW -#define DefMDIChildProc DefMDIChildProcW -#define CreateMDIWindow CreateMDIWindowW -#else -#define DefFrameProc DefFrameProcA -#define DefMDIChildProc DefMDIChildProcA -#define CreateMDIWindow CreateMDIWindowA -#endif - - WINUSERAPI LRESULT WINAPI DefFrameProcA(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefFrameProcW(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefMDIChildProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefMDIChildProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - -#ifndef NOMSG - WINUSERAPI WINBOOL WINAPI TranslateMDISysAccel(HWND hWndClient,LPMSG lpMsg); -#endif - - WINUSERAPI UINT WINAPI ArrangeIconicWindows(HWND hWnd); - WINUSERAPI HWND WINAPI CreateMDIWindowA(LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); - WINUSERAPI HWND WINAPI CreateMDIWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); - WINUSERAPI WORD WINAPI TileWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); - WINUSERAPI WORD WINAPI CascadeWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); -#endif -#endif - -#ifndef NOHELP - - typedef DWORD HELPPOLY; - typedef struct tagMULTIKEYHELPA { - DWORD mkSize; - CHAR mkKeylist; - CHAR szKeyphrase[1]; - } MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA; - - typedef struct tagMULTIKEYHELPW { - DWORD mkSize; - WCHAR mkKeylist; - WCHAR szKeyphrase[1]; - } MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW; - -#ifdef UNICODE - typedef MULTIKEYHELPW MULTIKEYHELP; - typedef PMULTIKEYHELPW PMULTIKEYHELP; - typedef LPMULTIKEYHELPW LPMULTIKEYHELP; -#else - typedef MULTIKEYHELPA MULTIKEYHELP; - typedef PMULTIKEYHELPA PMULTIKEYHELP; - typedef LPMULTIKEYHELPA LPMULTIKEYHELP; -#endif - - typedef struct tagHELPWININFOA { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - CHAR rgchMember[2]; - } HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA; - - typedef struct tagHELPWININFOW { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - WCHAR rgchMember[2]; - } HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW; - -#ifdef UNICODE - typedef HELPWININFOW HELPWININFO; - typedef PHELPWININFOW PHELPWININFO; - typedef LPHELPWININFOW LPHELPWININFO; -#else - typedef HELPWININFOA HELPWININFO; - typedef PHELPWININFOA PHELPWININFO; - typedef LPHELPWININFOA LPHELPWININFO; -#endif - -#define HELP_CONTEXT 0x0001L -#define HELP_QUIT 0x0002L -#define HELP_INDEX 0x0003L -#define HELP_CONTENTS 0x0003L -#define HELP_HELPONHELP 0x0004L -#define HELP_SETINDEX 0x0005L -#define HELP_SETCONTENTS 0x0005L -#define HELP_CONTEXTPOPUP 0x0008L -#define HELP_FORCEFILE 0x0009L -#define HELP_KEY 0x0101L -#define HELP_COMMAND 0x0102L -#define HELP_PARTIALKEY 0x0105L -#define HELP_MULTIKEY 0x0201L -#define HELP_SETWINPOS 0x0203L -#define HELP_CONTEXTMENU 0x000a -#define HELP_FINDER 0x000b -#define HELP_WM_HELP 0x000c -#define HELP_SETPOPUP_POS 0x000d - -#define HELP_TCARD 0x8000 -#define HELP_TCARD_DATA 0x0010 -#define HELP_TCARD_OTHER_CALLER 0x0011 - -#define IDH_NO_HELP 28440 -#define IDH_MISSING_CONTEXT 28441 -#define IDH_GENERIC_HELP_BUTTON 28442 -#define IDH_OK 28443 -#define IDH_CANCEL 28444 -#define IDH_HELP 28445 - -#ifdef UNICODE -#define WinHelp WinHelpW -#else -#define WinHelp WinHelpA -#endif - - WINUSERAPI WINBOOL WINAPI WinHelpA(HWND hWndMain,LPCSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); - WINUSERAPI WINBOOL WINAPI WinHelpW(HWND hWndMain,LPCWSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); -#endif - -#define GR_GDIOBJECTS 0 -#define GR_USEROBJECTS 1 - - WINUSERAPI DWORD WINAPI GetGuiResources(HANDLE hProcess,DWORD uiFlags); - -#ifndef NOSYSPARAMSINFO - -#define SPI_GETBEEP 0x0001 -#define SPI_SETBEEP 0x0002 -#define SPI_GETMOUSE 0x0003 -#define SPI_SETMOUSE 0x0004 -#define SPI_GETBORDER 0x0005 -#define SPI_SETBORDER 0x0006 -#define SPI_GETKEYBOARDSPEED 0x000A -#define SPI_SETKEYBOARDSPEED 0x000B -#define SPI_LANGDRIVER 0x000C -#define SPI_ICONHORIZONTALSPACING 0x000D -#define SPI_GETSCREENSAVETIMEOUT 0x000E -#define SPI_SETSCREENSAVETIMEOUT 0x000F -#define SPI_GETSCREENSAVEACTIVE 0x0010 -#define SPI_SETSCREENSAVEACTIVE 0x0011 -#define SPI_GETGRIDGRANULARITY 0x0012 -#define SPI_SETGRIDGRANULARITY 0x0013 -#define SPI_SETDESKWALLPAPER 0x0014 -#define SPI_SETDESKPATTERN 0x0015 -#define SPI_GETKEYBOARDDELAY 0x0016 -#define SPI_SETKEYBOARDDELAY 0x0017 -#define SPI_ICONVERTICALSPACING 0x0018 -#define SPI_GETICONTITLEWRAP 0x0019 -#define SPI_SETICONTITLEWRAP 0x001A -#define SPI_GETMENUDROPALIGNMENT 0x001B -#define SPI_SETMENUDROPALIGNMENT 0x001C -#define SPI_SETDOUBLECLKWIDTH 0x001D -#define SPI_SETDOUBLECLKHEIGHT 0x001E -#define SPI_GETICONTITLELOGFONT 0x001F -#define SPI_SETDOUBLECLICKTIME 0x0020 -#define SPI_SETMOUSEBUTTONSWAP 0x0021 -#define SPI_SETICONTITLELOGFONT 0x0022 -#define SPI_GETFASTTASKSWITCH 0x0023 -#define SPI_SETFASTTASKSWITCH 0x0024 -#define SPI_SETDRAGFULLWINDOWS 0x0025 -#define SPI_GETDRAGFULLWINDOWS 0x0026 -#define SPI_GETNONCLIENTMETRICS 0x0029 -#define SPI_SETNONCLIENTMETRICS 0x002A -#define SPI_GETMINIMIZEDMETRICS 0x002B -#define SPI_SETMINIMIZEDMETRICS 0x002C -#define SPI_GETICONMETRICS 0x002D -#define SPI_SETICONMETRICS 0x002E -#define SPI_SETWORKAREA 0x002F -#define SPI_GETWORKAREA 0x0030 -#define SPI_SETPENWINDOWS 0x0031 - -#define SPI_GETHIGHCONTRAST 0x0042 -#define SPI_SETHIGHCONTRAST 0x0043 -#define SPI_GETKEYBOARDPREF 0x0044 -#define SPI_SETKEYBOARDPREF 0x0045 -#define SPI_GETSCREENREADER 0x0046 -#define SPI_SETSCREENREADER 0x0047 -#define SPI_GETANIMATION 0x0048 -#define SPI_SETANIMATION 0x0049 -#define SPI_GETFONTSMOOTHING 0x004A -#define SPI_SETFONTSMOOTHING 0x004B -#define SPI_SETDRAGWIDTH 0x004C -#define SPI_SETDRAGHEIGHT 0x004D -#define SPI_SETHANDHELD 0x004E -#define SPI_GETLOWPOWERTIMEOUT 0x004F -#define SPI_GETPOWEROFFTIMEOUT 0x0050 -#define SPI_SETLOWPOWERTIMEOUT 0x0051 -#define SPI_SETPOWEROFFTIMEOUT 0x0052 -#define SPI_GETLOWPOWERACTIVE 0x0053 -#define SPI_GETPOWEROFFACTIVE 0x0054 -#define SPI_SETLOWPOWERACTIVE 0x0055 -#define SPI_SETPOWEROFFACTIVE 0x0056 -#define SPI_SETCURSORS 0x0057 -#define SPI_SETICONS 0x0058 -#define SPI_GETDEFAULTINPUTLANG 0x0059 -#define SPI_SETDEFAULTINPUTLANG 0x005A -#define SPI_SETLANGTOGGLE 0x005B -#define SPI_GETWINDOWSEXTENSION 0x005C -#define SPI_SETMOUSETRAILS 0x005D -#define SPI_GETMOUSETRAILS 0x005E -#define SPI_SETSCREENSAVERRUNNING 0x0061 -#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING -#define SPI_GETFILTERKEYS 0x0032 -#define SPI_SETFILTERKEYS 0x0033 -#define SPI_GETTOGGLEKEYS 0x0034 -#define SPI_SETTOGGLEKEYS 0x0035 -#define SPI_GETMOUSEKEYS 0x0036 -#define SPI_SETMOUSEKEYS 0x0037 -#define SPI_GETSHOWSOUNDS 0x0038 -#define SPI_SETSHOWSOUNDS 0x0039 -#define SPI_GETSTICKYKEYS 0x003A -#define SPI_SETSTICKYKEYS 0x003B -#define SPI_GETACCESSTIMEOUT 0x003C -#define SPI_SETACCESSTIMEOUT 0x003D -#define SPI_GETSERIALKEYS 0x003E -#define SPI_SETSERIALKEYS 0x003F -#define SPI_GETSOUNDSENTRY 0x0040 -#define SPI_SETSOUNDSENTRY 0x0041 -#define SPI_GETSNAPTODEFBUTTON 0x005F -#define SPI_SETSNAPTODEFBUTTON 0x0060 -#define SPI_GETMOUSEHOVERWIDTH 0x0062 -#define SPI_SETMOUSEHOVERWIDTH 0x0063 -#define SPI_GETMOUSEHOVERHEIGHT 0x0064 -#define SPI_SETMOUSEHOVERHEIGHT 0x0065 -#define SPI_GETMOUSEHOVERTIME 0x0066 -#define SPI_SETMOUSEHOVERTIME 0x0067 -#define SPI_GETWHEELSCROLLLINES 0x0068 -#define SPI_SETWHEELSCROLLLINES 0x0069 -#define SPI_GETMENUSHOWDELAY 0x006A -#define SPI_SETMENUSHOWDELAY 0x006B -#define SPI_GETSHOWIMEUI 0x006E -#define SPI_SETSHOWIMEUI 0x006F -#define SPI_GETMOUSESPEED 0x0070 -#define SPI_SETMOUSESPEED 0x0071 -#define SPI_GETSCREENSAVERRUNNING 0x0072 -#define SPI_GETDESKWALLPAPER 0x0073 - -#define SPI_GETACTIVEWINDOWTRACKING 0x1000 -#define SPI_SETACTIVEWINDOWTRACKING 0x1001 -#define SPI_GETMENUANIMATION 0x1002 -#define SPI_SETMENUANIMATION 0x1003 -#define SPI_GETCOMBOBOXANIMATION 0x1004 -#define SPI_SETCOMBOBOXANIMATION 0x1005 -#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 -#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 -#define SPI_GETGRADIENTCAPTIONS 0x1008 -#define SPI_SETGRADIENTCAPTIONS 0x1009 -#define SPI_GETKEYBOARDCUES 0x100A -#define SPI_SETKEYBOARDCUES 0x100B -#define SPI_GETMENUUNDERLINES SPI_GETKEYBOARDCUES -#define SPI_SETMENUUNDERLINES SPI_SETKEYBOARDCUES -#define SPI_GETACTIVEWNDTRKZORDER 0x100C -#define SPI_SETACTIVEWNDTRKZORDER 0x100D -#define SPI_GETHOTTRACKING 0x100E -#define SPI_SETHOTTRACKING 0x100F -#define SPI_GETMENUFADE 0x1012 -#define SPI_SETMENUFADE 0x1013 -#define SPI_GETSELECTIONFADE 0x1014 -#define SPI_SETSELECTIONFADE 0x1015 -#define SPI_GETTOOLTIPANIMATION 0x1016 -#define SPI_SETTOOLTIPANIMATION 0x1017 -#define SPI_GETTOOLTIPFADE 0x1018 -#define SPI_SETTOOLTIPFADE 0x1019 -#define SPI_GETCURSORSHADOW 0x101A -#define SPI_SETCURSORSHADOW 0x101B -#define SPI_GETMOUSESONAR 0x101C -#define SPI_SETMOUSESONAR 0x101D -#define SPI_GETMOUSECLICKLOCK 0x101E -#define SPI_SETMOUSECLICKLOCK 0x101F -#define SPI_GETMOUSEVANISH 0x1020 -#define SPI_SETMOUSEVANISH 0x1021 -#define SPI_GETFLATMENU 0x1022 -#define SPI_SETFLATMENU 0x1023 -#define SPI_GETDROPSHADOW 0x1024 -#define SPI_SETDROPSHADOW 0x1025 -#define SPI_GETBLOCKSENDINPUTRESETS 0x1026 -#define SPI_SETBLOCKSENDINPUTRESETS 0x1027 -#define SPI_GETUIEFFECTS 0x103E -#define SPI_SETUIEFFECTS 0x103F -#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 -#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 -#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 -#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 -#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 -#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 -#define SPI_GETCARETWIDTH 0x2006 -#define SPI_SETCARETWIDTH 0x2007 -#define SPI_GETMOUSECLICKLOCKTIME 0x2008 -#define SPI_SETMOUSECLICKLOCKTIME 0x2009 -#define SPI_GETFONTSMOOTHINGTYPE 0x200A -#define SPI_SETFONTSMOOTHINGTYPE 0x200B - -#define FE_FONTSMOOTHINGSTANDARD 0x0001 -#define FE_FONTSMOOTHINGCLEARTYPE 0x0002 -#define FE_FONTSMOOTHINGDOCKING 0x8000 - -#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C -#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D -#define SPI_GETFOCUSBORDERWIDTH 0x200E -#define SPI_SETFOCUSBORDERWIDTH 0x200F -#define SPI_GETFOCUSBORDERHEIGHT 0x2010 -#define SPI_SETFOCUSBORDERHEIGHT 0x2011 -#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012 -#define SPI_SETFONTSMOOTHINGORIENTATION 0x2013 - -#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000 -#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001 - -#define SPIF_UPDATEINIFILE 0x0001 -#define SPIF_SENDWININICHANGE 0x0002 -#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE - -#define METRICS_USEDEFAULT -1 -#ifdef _WINGDI_ -#ifndef NOGDI - typedef struct tagNONCLIENTMETRICSA { - UINT cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTA lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTA lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTA lfMenuFont; - LOGFONTA lfStatusFont; - LOGFONTA lfMessageFont; - } NONCLIENTMETRICSA,*PNONCLIENTMETRICSA,*LPNONCLIENTMETRICSA; - - typedef struct tagNONCLIENTMETRICSW { - UINT cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTW lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTW lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTW lfMenuFont; - LOGFONTW lfStatusFont; - LOGFONTW lfMessageFont; - } NONCLIENTMETRICSW,*PNONCLIENTMETRICSW,*LPNONCLIENTMETRICSW; - -#ifdef UNICODE - typedef NONCLIENTMETRICSW NONCLIENTMETRICS; - typedef PNONCLIENTMETRICSW PNONCLIENTMETRICS; - typedef LPNONCLIENTMETRICSW LPNONCLIENTMETRICS; -#else - typedef NONCLIENTMETRICSA NONCLIENTMETRICS; - typedef PNONCLIENTMETRICSA PNONCLIENTMETRICS; - typedef LPNONCLIENTMETRICSA LPNONCLIENTMETRICS; -#endif -#endif -#endif - -#define ARW_BOTTOMLEFT 0x0000L -#define ARW_BOTTOMRIGHT 0x0001L -#define ARW_TOPLEFT 0x0002L -#define ARW_TOPRIGHT 0x0003L -#define ARW_STARTMASK 0x0003L -#define ARW_STARTRIGHT 0x0001L -#define ARW_STARTTOP 0x0002L - -#define ARW_LEFT 0x0000L -#define ARW_RIGHT 0x0000L -#define ARW_UP 0x0004L -#define ARW_DOWN 0x0004L -#define ARW_HIDE 0x0008L - - typedef struct tagMINIMIZEDMETRICS { - UINT cbSize; - int iWidth; - int iHorzGap; - int iVertGap; - int iArrange; - } MINIMIZEDMETRICS,*PMINIMIZEDMETRICS,*LPMINIMIZEDMETRICS; - -#ifdef _WINGDI_ -#ifndef NOGDI - typedef struct tagICONMETRICSA { - UINT cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTA lfFont; - } ICONMETRICSA,*PICONMETRICSA,*LPICONMETRICSA; - - typedef struct tagICONMETRICSW { - UINT cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTW lfFont; - } ICONMETRICSW,*PICONMETRICSW,*LPICONMETRICSW; - -#ifdef UNICODE - typedef ICONMETRICSW ICONMETRICS; - typedef PICONMETRICSW PICONMETRICS; - typedef LPICONMETRICSW LPICONMETRICS; -#else - typedef ICONMETRICSA ICONMETRICS; - typedef PICONMETRICSA PICONMETRICS; - typedef LPICONMETRICSA LPICONMETRICS; -#endif -#endif -#endif - - typedef struct tagANIMATIONINFO { - UINT cbSize; - int iMinAnimate; - } ANIMATIONINFO,*LPANIMATIONINFO; - - typedef struct tagSERIALKEYSA { - UINT cbSize; - DWORD dwFlags; - LPSTR lpszActivePort; - LPSTR lpszPort; - UINT iBaudRate; - UINT iPortState; - UINT iActive; - } SERIALKEYSA,*LPSERIALKEYSA; - - typedef struct tagSERIALKEYSW { - UINT cbSize; - DWORD dwFlags; - LPWSTR lpszActivePort; - LPWSTR lpszPort; - UINT iBaudRate; - UINT iPortState; - UINT iActive; - } SERIALKEYSW,*LPSERIALKEYSW; - -#ifdef UNICODE - typedef SERIALKEYSW SERIALKEYS; - typedef LPSERIALKEYSW LPSERIALKEYS; -#else - typedef SERIALKEYSA SERIALKEYS; - typedef LPSERIALKEYSA LPSERIALKEYS; -#endif - -#define SERKF_SERIALKEYSON 0x00000001 -#define SERKF_AVAILABLE 0x00000002 -#define SERKF_INDICATOR 0x00000004 - - typedef struct tagHIGHCONTRASTA { - UINT cbSize; - DWORD dwFlags; - LPSTR lpszDefaultScheme; - } HIGHCONTRASTA,*LPHIGHCONTRASTA; - - typedef struct tagHIGHCONTRASTW { - UINT cbSize; - DWORD dwFlags; - LPWSTR lpszDefaultScheme; - } HIGHCONTRASTW,*LPHIGHCONTRASTW; - -#ifdef UNICODE - typedef HIGHCONTRASTW HIGHCONTRAST; - typedef LPHIGHCONTRASTW LPHIGHCONTRAST; -#else - typedef HIGHCONTRASTA HIGHCONTRAST; - typedef LPHIGHCONTRASTA LPHIGHCONTRAST; -#endif - -#define HCF_HIGHCONTRASTON 0x00000001 -#define HCF_AVAILABLE 0x00000002 -#define HCF_HOTKEYACTIVE 0x00000004 -#define HCF_CONFIRMHOTKEY 0x00000008 -#define HCF_HOTKEYSOUND 0x00000010 -#define HCF_INDICATOR 0x00000020 -#define HCF_HOTKEYAVAILABLE 0x00000040 -#define HCF_LOGONDESKTOP 0x00000100 -#define HCF_DEFAULTDESKTOP 0x00000200 - -#define CDS_UPDATEREGISTRY 0x00000001 -#define CDS_TEST 0x00000002 -#define CDS_FULLSCREEN 0x00000004 -#define CDS_GLOBAL 0x00000008 -#define CDS_SET_PRIMARY 0x00000010 -#define CDS_VIDEOPARAMETERS 0x00000020 -#define CDS_RESET 0x40000000 -#define CDS_NORESET 0x10000000 - -//gr #include - -#define DISP_CHANGE_SUCCESSFUL 0 -#define DISP_CHANGE_RESTART 1 -#define DISP_CHANGE_FAILED -1 -#define DISP_CHANGE_BADMODE -2 -#define DISP_CHANGE_NOTUPDATED -3 -#define DISP_CHANGE_BADFLAGS -4 -#define DISP_CHANGE_BADPARAM -5 -#define DISP_CHANGE_BADDUALVIEW -6 - -#ifdef _WINGDI_ -#ifndef NOGDI - -#ifdef UNICODE -#define ChangeDisplaySettings ChangeDisplaySettingsW -#define ChangeDisplaySettingsEx ChangeDisplaySettingsExW -#define EnumDisplaySettings EnumDisplaySettingsW -#define EnumDisplaySettingsEx EnumDisplaySettingsExW -#define EnumDisplayDevices EnumDisplayDevicesW -#else -#define ChangeDisplaySettings ChangeDisplaySettingsA -#define ChangeDisplaySettingsEx ChangeDisplaySettingsExA -#define EnumDisplaySettings EnumDisplaySettingsA -#define EnumDisplaySettingsEx EnumDisplaySettingsExA -#define EnumDisplayDevices EnumDisplayDevicesA -#endif - - WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA lpDevMode,DWORD dwFlags); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW lpDevMode,DWORD dwFlags); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsExA(LPCSTR lpszDeviceName,LPDEVMODEA lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName,LPDEVMODEW lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); - -#define ENUM_CURRENT_SETTINGS ((DWORD)-1) -#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) - - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode,DWORD dwFlags); - -#define EDS_RAWMODE 0x00000002 - - WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesA(LPCSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesW(LPCWSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags); -#endif -#endif - -#ifdef UNICODE -#define SystemParametersInfo SystemParametersInfoW -#else -#define SystemParametersInfo SystemParametersInfoA -#endif - - WINUSERAPI WINBOOL WINAPI SystemParametersInfoA(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); - WINUSERAPI WINBOOL WINAPI SystemParametersInfoW(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); -#endif - - typedef struct tagFILTERKEYS { - UINT cbSize; - DWORD dwFlags; - DWORD iWaitMSec; - DWORD iDelayMSec; - DWORD iRepeatMSec; - DWORD iBounceMSec; - } FILTERKEYS,*LPFILTERKEYS; - -#define FKF_FILTERKEYSON 0x00000001 -#define FKF_AVAILABLE 0x00000002 -#define FKF_HOTKEYACTIVE 0x00000004 -#define FKF_CONFIRMHOTKEY 0x00000008 -#define FKF_HOTKEYSOUND 0x00000010 -#define FKF_INDICATOR 0x00000020 -#define FKF_CLICKON 0x00000040 - - typedef struct tagSTICKYKEYS { - UINT cbSize; - DWORD dwFlags; - } STICKYKEYS,*LPSTICKYKEYS; - -#define SKF_STICKYKEYSON 0x00000001 -#define SKF_AVAILABLE 0x00000002 -#define SKF_HOTKEYACTIVE 0x00000004 -#define SKF_CONFIRMHOTKEY 0x00000008 -#define SKF_HOTKEYSOUND 0x00000010 -#define SKF_INDICATOR 0x00000020 -#define SKF_AUDIBLEFEEDBACK 0x00000040 -#define SKF_TRISTATE 0x00000080 -#define SKF_TWOKEYSOFF 0x00000100 -#define SKF_LALTLATCHED 0x10000000 -#define SKF_LCTLLATCHED 0x04000000 -#define SKF_LSHIFTLATCHED 0x01000000 -#define SKF_RALTLATCHED 0x20000000 -#define SKF_RCTLLATCHED 0x08000000 -#define SKF_RSHIFTLATCHED 0x02000000 -#define SKF_LWINLATCHED 0x40000000 -#define SKF_RWINLATCHED 0x80000000 -#define SKF_LALTLOCKED 0x00100000 -#define SKF_LCTLLOCKED 0x00040000 -#define SKF_LSHIFTLOCKED 0x00010000 -#define SKF_RALTLOCKED 0x00200000 -#define SKF_RCTLLOCKED 0x00080000 -#define SKF_RSHIFTLOCKED 0x00020000 -#define SKF_LWINLOCKED 0x00400000 -#define SKF_RWINLOCKED 0x00800000 - - typedef struct tagMOUSEKEYS { - UINT cbSize; - DWORD dwFlags; - DWORD iMaxSpeed; - DWORD iTimeToMaxSpeed; - DWORD iCtrlSpeed; - DWORD dwReserved1; - DWORD dwReserved2; - } MOUSEKEYS,*LPMOUSEKEYS; - -#define MKF_MOUSEKEYSON 0x00000001 -#define MKF_AVAILABLE 0x00000002 -#define MKF_HOTKEYACTIVE 0x00000004 -#define MKF_CONFIRMHOTKEY 0x00000008 -#define MKF_HOTKEYSOUND 0x00000010 -#define MKF_INDICATOR 0x00000020 -#define MKF_MODIFIERS 0x00000040 -#define MKF_REPLACENUMBERS 0x00000080 -#define MKF_LEFTBUTTONSEL 0x10000000 -#define MKF_RIGHTBUTTONSEL 0x20000000 -#define MKF_LEFTBUTTONDOWN 0x01000000 -#define MKF_RIGHTBUTTONDOWN 0x02000000 -#define MKF_MOUSEMODE 0x80000000 - - typedef struct tagACCESSTIMEOUT { - UINT cbSize; - DWORD dwFlags; - DWORD iTimeOutMSec; - } ACCESSTIMEOUT,*LPACCESSTIMEOUT; - -#define ATF_TIMEOUTON 0x00000001 -#define ATF_ONOFFFEEDBACK 0x00000002 - -#define SSGF_NONE 0 -#define SSGF_DISPLAY 3 - -#define SSTF_NONE 0 -#define SSTF_CHARS 1 -#define SSTF_BORDER 2 -#define SSTF_DISPLAY 3 - -#define SSWF_NONE 0 -#define SSWF_TITLE 1 -#define SSWF_WINDOW 2 -#define SSWF_DISPLAY 3 -#define SSWF_CUSTOM 4 - - typedef struct tagSOUNDSENTRYA { - UINT cbSize; - DWORD dwFlags; - DWORD iFSTextEffect; - DWORD iFSTextEffectMSec; - DWORD iFSTextEffectColorBits; - DWORD iFSGrafEffect; - DWORD iFSGrafEffectMSec; - DWORD iFSGrafEffectColor; - DWORD iWindowsEffect; - DWORD iWindowsEffectMSec; - LPSTR lpszWindowsEffectDLL; - DWORD iWindowsEffectOrdinal; - } SOUNDSENTRYA,*LPSOUNDSENTRYA; - - typedef struct tagSOUNDSENTRYW { - UINT cbSize; - DWORD dwFlags; - DWORD iFSTextEffect; - DWORD iFSTextEffectMSec; - DWORD iFSTextEffectColorBits; - DWORD iFSGrafEffect; - DWORD iFSGrafEffectMSec; - DWORD iFSGrafEffectColor; - DWORD iWindowsEffect; - DWORD iWindowsEffectMSec; - LPWSTR lpszWindowsEffectDLL; - DWORD iWindowsEffectOrdinal; - } SOUNDSENTRYW,*LPSOUNDSENTRYW; - -#ifdef UNICODE - typedef SOUNDSENTRYW SOUNDSENTRY; - typedef LPSOUNDSENTRYW LPSOUNDSENTRY; -#else - typedef SOUNDSENTRYA SOUNDSENTRY; - typedef LPSOUNDSENTRYA LPSOUNDSENTRY; -#endif - -#define SSF_SOUNDSENTRYON 0x00000001 -#define SSF_AVAILABLE 0x00000002 -#define SSF_INDICATOR 0x00000004 - - typedef struct tagTOGGLEKEYS { - UINT cbSize; - DWORD dwFlags; - } TOGGLEKEYS,*LPTOGGLEKEYS; - -#define TKF_TOGGLEKEYSON 0x00000001 -#define TKF_AVAILABLE 0x00000002 -#define TKF_HOTKEYACTIVE 0x00000004 -#define TKF_CONFIRMHOTKEY 0x00000008 -#define TKF_HOTKEYSOUND 0x00000010 -#define TKF_INDICATOR 0x00000020 - - WINUSERAPI VOID WINAPI SetDebugErrorLevel(DWORD dwLevel); - -#define SLE_ERROR 0x00000001 -#define SLE_MINORERROR 0x00000002 -#define SLE_WARNING 0x00000003 - - WINUSERAPI VOID WINAPI SetLastErrorEx(DWORD dwErrCode,DWORD dwType); - WINUSERAPI int WINAPI InternalGetWindowText(HWND hWnd,LPWSTR pString,int cchMaxCount); - -#ifdef WINNT - WINUSERAPI WINBOOL WINAPI EndTask(HWND hWnd,WINBOOL fShutDown,WINBOOL fForce); -#endif - -#define MONITOR_DEFAULTTONULL 0x00000000 -#define MONITOR_DEFAULTTOPRIMARY 0x00000001 -#define MONITOR_DEFAULTTONEAREST 0x00000002 - - WINUSERAPI HMONITOR WINAPI MonitorFromPoint(POINT pt,DWORD dwFlags); - WINUSERAPI HMONITOR WINAPI MonitorFromRect(LPCRECT lprc,DWORD dwFlags); - WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd,DWORD dwFlags); - -#define MONITORINFOF_PRIMARY 0x00000001 - -#ifndef CCHDEVICENAME -#define CCHDEVICENAME 32 -#endif - - typedef struct tagMONITORINFO { - DWORD cbSize; - RECT rcMonitor; - RECT rcWork; - DWORD dwFlags; - } MONITORINFO,*LPMONITORINFO; - -#ifdef __cplusplus - typedef struct tagMONITORINFOEXA : public tagMONITORINFO { - CHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXA,*LPMONITORINFOEXA; - - typedef struct tagMONITORINFOEXW : public tagMONITORINFO { - WCHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXW,*LPMONITORINFOEXW; - -#ifdef UNICODE - typedef MONITORINFOEXW MONITORINFOEX; - typedef LPMONITORINFOEXW LPMONITORINFOEX; -#else - typedef MONITORINFOEXA MONITORINFOEX; - typedef LPMONITORINFOEXA LPMONITORINFOEX; -#endif -#else - typedef struct tagMONITORINFOEXA { - MONITORINFO mi; - CHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXA,*LPMONITORINFOEXA; - - typedef struct tagMONITORINFOEXW { - MONITORINFO mi; - WCHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXW,*LPMONITORINFOEXW; -#ifdef UNICODE - typedef MONITORINFOEXW MONITORINFOEX; - typedef LPMONITORINFOEXW LPMONITORINFOEX; -#else - typedef MONITORINFOEXA MONITORINFOEX; - typedef LPMONITORINFOEXA LPMONITORINFOEX; -#endif -#endif - -#ifdef UNICODE -#define GetMonitorInfo GetMonitorInfoW -#else -#define GetMonitorInfo GetMonitorInfoA -#endif - - WINUSERAPI WINBOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor,LPMONITORINFO lpmi); - WINUSERAPI WINBOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor,LPMONITORINFO lpmi); - - typedef WINBOOL (CALLBACK *MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); - - WINUSERAPI WINBOOL WINAPI EnumDisplayMonitors(HDC hdc,LPCRECT lprcClip,MONITORENUMPROC lpfnEnum,LPARAM dwData); - -#ifndef NOWINABLE - WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD event,HWND hwnd,LONG idObject,LONG idChild); - - typedef VOID (CALLBACK *WINEVENTPROC)(HWINEVENTHOOK hWinEventHook,DWORD event,HWND hwnd,LONG idObject,LONG idChild,DWORD idEventThread,DWORD dwmsEventTime); - - WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook(DWORD eventMin,DWORD eventMax,HMODULE hmodWinEventProc,WINEVENTPROC pfnWinEventProc,DWORD idProcess,DWORD idThread,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI IsWinEventHookInstalled(DWORD event); - -#define WINEVENT_OUTOFCONTEXT 0x0000 -#define WINEVENT_SKIPOWNTHREAD 0x0001 -#define WINEVENT_SKIPOWNPROCESS 0x0002 -#define WINEVENT_INCONTEXT 0x0004 - - WINUSERAPI WINBOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hWinEventHook); - -#define CHILDID_SELF 0 -#define INDEXID_OBJECT 0 -#define INDEXID_CONTAINER 0 - -#define OBJID_WINDOW ((LONG)0x00000000) -#define OBJID_SYSMENU ((LONG)0xFFFFFFFF) -#define OBJID_TITLEBAR ((LONG)0xFFFFFFFE) -#define OBJID_MENU ((LONG)0xFFFFFFFD) -#define OBJID_CLIENT ((LONG)0xFFFFFFFC) -#define OBJID_VSCROLL ((LONG)0xFFFFFFFB) -#define OBJID_HSCROLL ((LONG)0xFFFFFFFA) -#define OBJID_SIZEGRIP ((LONG)0xFFFFFFF9) -#define OBJID_CARET ((LONG)0xFFFFFFF8) -#define OBJID_CURSOR ((LONG)0xFFFFFFF7) -#define OBJID_ALERT ((LONG)0xFFFFFFF6) -#define OBJID_SOUND ((LONG)0xFFFFFFF5) -#define OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4) -#define OBJID_NATIVEOM ((LONG)0xFFFFFFF0) - -#define EVENT_MIN 0x00000001 -#define EVENT_MAX 0x7FFFFFFF - -#define EVENT_SYSTEM_SOUND 0x0001 -#define EVENT_SYSTEM_ALERT 0x0002 -#define EVENT_SYSTEM_FOREGROUND 0x0003 -#define EVENT_SYSTEM_MENUSTART 0x0004 -#define EVENT_SYSTEM_MENUEND 0x0005 -#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006 -#define EVENT_SYSTEM_MENUPOPUPEND 0x0007 -#define EVENT_SYSTEM_CAPTURESTART 0x0008 -#define EVENT_SYSTEM_CAPTUREEND 0x0009 -#define EVENT_SYSTEM_MOVESIZESTART 0x000A -#define EVENT_SYSTEM_MOVESIZEEND 0x000B -#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C -#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D -#define EVENT_SYSTEM_DRAGDROPSTART 0x000E -#define EVENT_SYSTEM_DRAGDROPEND 0x000F -#define EVENT_SYSTEM_DIALOGSTART 0x0010 -#define EVENT_SYSTEM_DIALOGEND 0x0011 -#define EVENT_SYSTEM_SCROLLINGSTART 0x0012 -#define EVENT_SYSTEM_SCROLLINGEND 0x0013 -#define EVENT_SYSTEM_SWITCHSTART 0x0014 -#define EVENT_SYSTEM_SWITCHEND 0x0015 -#define EVENT_SYSTEM_MINIMIZESTART 0x0016 -#define EVENT_SYSTEM_MINIMIZEEND 0x0017 - -#define EVENT_CONSOLE_CARET 0x4001 -#define EVENT_CONSOLE_UPDATE_REGION 0x4002 -#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 -#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 -#define EVENT_CONSOLE_LAYOUT 0x4005 -#define EVENT_CONSOLE_START_APPLICATION 0x4006 -#define EVENT_CONSOLE_END_APPLICATION 0x4007 - -#define CONSOLE_APPLICATION_16BIT 0x0001 - -#define CONSOLE_CARET_SELECTION 0x0001 -#define CONSOLE_CARET_VISIBLE 0x0002 - -#define EVENT_OBJECT_CREATE 0x8000 -#define EVENT_OBJECT_DESTROY 0x8001 -#define EVENT_OBJECT_SHOW 0x8002 -#define EVENT_OBJECT_HIDE 0x8003 -#define EVENT_OBJECT_REORDER 0x8004 - -#define EVENT_OBJECT_FOCUS 0x8005 -#define EVENT_OBJECT_SELECTION 0x8006 -#define EVENT_OBJECT_SELECTIONADD 0x8007 -#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 -#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 - -#define EVENT_OBJECT_STATECHANGE 0x800A - -#define EVENT_OBJECT_LOCATIONCHANGE 0x800B - -#define EVENT_OBJECT_NAMECHANGE 0x800C -#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D -#define EVENT_OBJECT_VALUECHANGE 0x800E -#define EVENT_OBJECT_PARENTCHANGE 0x800F -#define EVENT_OBJECT_HELPCHANGE 0x8010 -#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 -#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 - -#define SOUND_SYSTEM_STARTUP 1 -#define SOUND_SYSTEM_SHUTDOWN 2 -#define SOUND_SYSTEM_BEEP 3 -#define SOUND_SYSTEM_ERROR 4 -#define SOUND_SYSTEM_QUESTION 5 -#define SOUND_SYSTEM_WARNING 6 -#define SOUND_SYSTEM_INFORMATION 7 -#define SOUND_SYSTEM_MAXIMIZE 8 -#define SOUND_SYSTEM_MINIMIZE 9 -#define SOUND_SYSTEM_RESTOREUP 10 -#define SOUND_SYSTEM_RESTOREDOWN 11 -#define SOUND_SYSTEM_APPSTART 12 -#define SOUND_SYSTEM_FAULT 13 -#define SOUND_SYSTEM_APPEND 14 -#define SOUND_SYSTEM_MENUCOMMAND 15 -#define SOUND_SYSTEM_MENUPOPUP 16 -#define CSOUND_SYSTEM 16 - -#define ALERT_SYSTEM_INFORMATIONAL 1 -#define ALERT_SYSTEM_WARNING 2 -#define ALERT_SYSTEM_ERROR 3 -#define ALERT_SYSTEM_QUERY 4 -#define ALERT_SYSTEM_CRITICAL 5 -#define CALERT_SYSTEM 6 - - typedef struct tagGUITHREADINFO { - DWORD cbSize; - DWORD flags; - HWND hwndActive; - HWND hwndFocus; - HWND hwndCapture; - HWND hwndMenuOwner; - HWND hwndMoveSize; - HWND hwndCaret; - RECT rcCaret; - } GUITHREADINFO,*PGUITHREADINFO,*LPGUITHREADINFO; - -#define GUI_CARETBLINKING 0x00000001 -#define GUI_INMOVESIZE 0x00000002 -#define GUI_INMENUMODE 0x00000004 -#define GUI_SYSTEMMENUMODE 0x00000008 -#define GUI_POPUPMENUMODE 0x00000010 -#define GUI_16BITTASK 0x00000020 - -#ifdef UNICODE -#define GetWindowModuleFileName GetWindowModuleFileNameW -#else -#define GetWindowModuleFileName GetWindowModuleFileNameA -#endif - - WINUSERAPI WINBOOL WINAPI GetGUIThreadInfo(DWORD idThread,PGUITHREADINFO pgui); - WINUSERAPI UINT WINAPI GetWindowModuleFileNameA(HWND hwnd,LPSTR pszFileName,UINT cchFileNameMax); - WINUSERAPI UINT WINAPI GetWindowModuleFileNameW(HWND hwnd,LPWSTR pszFileName,UINT cchFileNameMax); - -#ifndef NO_STATE_FLAGS -#define STATE_SYSTEM_UNAVAILABLE 0x00000001 -#define STATE_SYSTEM_SELECTED 0x00000002 -#define STATE_SYSTEM_FOCUSED 0x00000004 -#define STATE_SYSTEM_PRESSED 0x00000008 -#define STATE_SYSTEM_CHECKED 0x00000010 -#define STATE_SYSTEM_MIXED 0x00000020 -#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED -#define STATE_SYSTEM_READONLY 0x00000040 -#define STATE_SYSTEM_HOTTRACKED 0x00000080 -#define STATE_SYSTEM_DEFAULT 0x00000100 -#define STATE_SYSTEM_EXPANDED 0x00000200 -#define STATE_SYSTEM_COLLAPSED 0x00000400 -#define STATE_SYSTEM_BUSY 0x00000800 -#define STATE_SYSTEM_FLOATING 0x00001000 -#define STATE_SYSTEM_MARQUEED 0x00002000 -#define STATE_SYSTEM_ANIMATED 0x00004000 -#define STATE_SYSTEM_INVISIBLE 0x00008000 -#define STATE_SYSTEM_OFFSCREEN 0x00010000 -#define STATE_SYSTEM_SIZEABLE 0x00020000 -#define STATE_SYSTEM_MOVEABLE 0x00040000 -#define STATE_SYSTEM_SELFVOICING 0x00080000 -#define STATE_SYSTEM_FOCUSABLE 0x00100000 -#define STATE_SYSTEM_SELECTABLE 0x00200000 -#define STATE_SYSTEM_LINKED 0x00400000 -#define STATE_SYSTEM_TRAVERSED 0x00800000 -#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 -#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 -#define STATE_SYSTEM_ALERT_LOW 0x04000000 -#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 -#define STATE_SYSTEM_ALERT_HIGH 0x10000000 -#define STATE_SYSTEM_PROTECTED 0x20000000 -#define STATE_SYSTEM_VALID 0x3FFFFFFF -#endif - -#define CCHILDREN_TITLEBAR 5 -#define CCHILDREN_SCROLLBAR 5 - - typedef struct tagCURSORINFO { - DWORD cbSize; - DWORD flags; - HCURSOR hCursor; - POINT ptScreenPos; - } CURSORINFO,*PCURSORINFO,*LPCURSORINFO; - -#define CURSOR_SHOWING 0x00000001 - - WINUSERAPI WINBOOL WINAPI GetCursorInfo(PCURSORINFO pci); - - typedef struct tagWINDOWINFO { - DWORD cbSize; - RECT rcWindow; - RECT rcClient; - DWORD dwStyle; - DWORD dwExStyle; - DWORD dwWindowStatus; - UINT cxWindowBorders; - UINT cyWindowBorders; - ATOM atomWindowType; - WORD wCreatorVersion; - } WINDOWINFO,*PWINDOWINFO,*LPWINDOWINFO; - -#define WS_ACTIVECAPTION 0x0001 - - WINUSERAPI WINBOOL WINAPI GetWindowInfo(HWND hwnd,PWINDOWINFO pwi); - - typedef struct tagTITLEBARINFO { - DWORD cbSize; - RECT rcTitleBar; - DWORD rgstate[CCHILDREN_TITLEBAR + 1]; - } TITLEBARINFO,*PTITLEBARINFO,*LPTITLEBARINFO; - - WINUSERAPI WINBOOL WINAPI GetTitleBarInfo(HWND hwnd,PTITLEBARINFO pti); - - typedef struct tagMENUBARINFO { - DWORD cbSize; - RECT rcBar; - HMENU hMenu; - HWND hwndMenu; - WINBOOL fBarFocused:1; - WINBOOL fFocused:1; - } MENUBARINFO,*PMENUBARINFO,*LPMENUBARINFO; - - WINUSERAPI WINBOOL WINAPI GetMenuBarInfo(HWND hwnd,LONG idObject,LONG idItem,PMENUBARINFO pmbi); - - typedef struct tagSCROLLBARINFO { - DWORD cbSize; - RECT rcScrollBar; - int dxyLineButton; - int xyThumbTop; - int xyThumbBottom; - int reserved; - DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; - } SCROLLBARINFO,*PSCROLLBARINFO,*LPSCROLLBARINFO; - - WINUSERAPI WINBOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi); - - typedef struct tagCOMBOBOXINFO { - DWORD cbSize; - RECT rcItem; - RECT rcButton; - DWORD stateButton; - HWND hwndCombo; - HWND hwndItem; - HWND hwndList; - } COMBOBOXINFO,*PCOMBOBOXINFO,*LPCOMBOBOXINFO; - - WINUSERAPI WINBOOL WINAPI GetComboBoxInfo(HWND hwndCombo,PCOMBOBOXINFO pcbi); - -#define GA_PARENT 1 -#define GA_ROOT 2 -#define GA_ROOTOWNER 3 - - WINUSERAPI HWND WINAPI GetAncestor(HWND hwnd,UINT gaFlags); - WINUSERAPI HWND WINAPI RealChildWindowFromPoint(HWND hwndParent,POINT ptParentClientCoords); - WINUSERAPI UINT WINAPI RealGetWindowClassA(HWND hwnd,LPSTR ptszClassName,UINT cchClassNameMax); - WINUSERAPI UINT WINAPI RealGetWindowClassW(HWND hwnd,LPWSTR ptszClassName,UINT cchClassNameMax); -#ifdef UNICODE -#define RealGetWindowClass RealGetWindowClassW -#else -#define RealGetWindowClass RealGetWindowClassA -#endif - - typedef struct tagALTTABINFO { - DWORD cbSize; - int cItems; - int cColumns; - int cRows; - int iColFocus; - int iRowFocus; - int cxItem; - int cyItem; - POINT ptStart; - } ALTTABINFO,*PALTTABINFO,*LPALTTABINFO; - -#ifdef UNICODE -#define GetAltTabInfo GetAltTabInfoW -#else -#define GetAltTabInfo GetAltTabInfoA -#endif - - WINUSERAPI WINBOOL WINAPI GetAltTabInfoA(HWND hwnd,int iItem,PALTTABINFO pati,LPSTR pszItemText,UINT cchItemText); - WINUSERAPI WINBOOL WINAPI GetAltTabInfoW(HWND hwnd,int iItem,PALTTABINFO pati,LPWSTR pszItemText,UINT cchItemText); - WINUSERAPI DWORD WINAPI GetListBoxInfo(HWND hwnd); -#endif - - WINUSERAPI WINBOOL WINAPI LockWorkStation(VOID); - WINUSERAPI WINBOOL WINAPI UserHandleGrantAccess(HANDLE hUserHandle,HANDLE hJob,WINBOOL bGrant); - - DECLARE_HANDLE(HRAWINPUT); - -#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) - -#define RIM_INPUT 0 -#define RIM_INPUTSINK 1 - - typedef struct tagRAWINPUTHEADER { - DWORD dwType; - DWORD dwSize; - HANDLE hDevice; - WPARAM wParam; - } RAWINPUTHEADER,*PRAWINPUTHEADER,*LPRAWINPUTHEADER; - -#define RIM_TYPEMOUSE 0 -#define RIM_TYPEKEYBOARD 1 -#define RIM_TYPEHID 2 - - typedef struct tagRAWMOUSE { - USHORT usFlags; - union { - ULONG ulButtons; - struct { - USHORT usButtonFlags; - USHORT usButtonData; - }; - }; - ULONG ulRawButtons; - LONG lLastX; - LONG lLastY; - ULONG ulExtraInformation; - } RAWMOUSE,*PRAWMOUSE,*LPRAWMOUSE; - -#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001 -#define RI_MOUSE_LEFT_BUTTON_UP 0x0002 -#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004 -#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008 -#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010 -#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020 - -#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN -#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP -#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN -#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP -#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN -#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP - -#define RI_MOUSE_BUTTON_4_DOWN 0x0040 -#define RI_MOUSE_BUTTON_4_UP 0x0080 -#define RI_MOUSE_BUTTON_5_DOWN 0x0100 -#define RI_MOUSE_BUTTON_5_UP 0x0200 - -#define RI_MOUSE_WHEEL 0x0400 - -#define MOUSE_MOVE_RELATIVE 0 -#define MOUSE_MOVE_ABSOLUTE 1 -#define MOUSE_VIRTUAL_DESKTOP 0x02 -#define MOUSE_ATTRIBUTES_CHANGED 0x04 - - typedef struct tagRAWKEYBOARD { - USHORT MakeCode; - USHORT Flags; - USHORT Reserved; - USHORT VKey; - UINT Message; - ULONG ExtraInformation; - } RAWKEYBOARD,*PRAWKEYBOARD,*LPRAWKEYBOARD; - -#define KEYBOARD_OVERRUN_MAKE_CODE 0xFF - -#define RI_KEY_MAKE 0 -#define RI_KEY_BREAK 1 -#define RI_KEY_E0 2 -#define RI_KEY_E1 4 -#define RI_KEY_TERMSRV_SET_LED 8 -#define RI_KEY_TERMSRV_SHADOW 0x10 - - typedef struct tagRAWHID { - DWORD dwSizeHid; - DWORD dwCount; - BYTE bRawData[1]; - } RAWHID,*PRAWHID,*LPRAWHID; - - typedef struct tagRAWINPUT { - RAWINPUTHEADER header; - union { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - } data; - } RAWINPUT,*PRAWINPUT,*LPRAWINPUT; - -#ifdef _WIN64 -#define RAWINPUT_ALIGN(x) (((x) + sizeof(QWORD) - 1) & ~(sizeof(QWORD) - 1)) -#else -#define RAWINPUT_ALIGN(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1)) -#endif - -#define NEXTRAWINPUTBLOCK(ptr) ((PRAWINPUT)RAWINPUT_ALIGN((ULONG_PTR)((PBYTE)(ptr) + (ptr)->header.dwSize))) - -#define RID_INPUT 0x10000003 -#define RID_HEADER 0x10000005 - - WINUSERAPI UINT WINAPI GetRawInputData(HRAWINPUT hRawInput,UINT uiCommand,LPVOID pData,PUINT pcbSize,UINT cbSizeHeader); - -#define RIDI_PREPARSEDDATA 0x20000005 -#define RIDI_DEVICENAME 0x20000007 -#define RIDI_DEVICEINFO 0x2000000b - - typedef struct tagRID_DEVICE_INFO_MOUSE { - DWORD dwId; - DWORD dwNumberOfButtons; - DWORD dwSampleRate; - } RID_DEVICE_INFO_MOUSE,*PRID_DEVICE_INFO_MOUSE; - - typedef struct tagRID_DEVICE_INFO_KEYBOARD { - DWORD dwType; - DWORD dwSubType; - DWORD dwKeyboardMode; - DWORD dwNumberOfFunctionKeys; - DWORD dwNumberOfIndicators; - DWORD dwNumberOfKeysTotal; - } RID_DEVICE_INFO_KEYBOARD,*PRID_DEVICE_INFO_KEYBOARD; - - typedef struct tagRID_DEVICE_INFO_HID { - DWORD dwVendorId; - DWORD dwProductId; - DWORD dwVersionNumber; - USHORT usUsagePage; - USHORT usUsage; - } RID_DEVICE_INFO_HID,*PRID_DEVICE_INFO_HID; - - typedef struct tagRID_DEVICE_INFO { - DWORD cbSize; - DWORD dwType; - union { - RID_DEVICE_INFO_MOUSE mouse; - RID_DEVICE_INFO_KEYBOARD keyboard; - RID_DEVICE_INFO_HID hid; - }; - } RID_DEVICE_INFO,*PRID_DEVICE_INFO,*LPRID_DEVICE_INFO; - -#ifdef UNICODE -#define GetRawInputDeviceInfo GetRawInputDeviceInfoW -#else -#define GetRawInputDeviceInfo GetRawInputDeviceInfoA -#endif - - WINUSERAPI UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); - WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); - WINUSERAPI UINT WINAPI GetRawInputBuffer(PRAWINPUT pData,PUINT pcbSize,UINT cbSizeHeader); - - typedef struct tagRAWINPUTDEVICE { - USHORT usUsagePage; - USHORT usUsage; - DWORD dwFlags; - HWND hwndTarget; - } RAWINPUTDEVICE,*PRAWINPUTDEVICE,*LPRAWINPUTDEVICE; - - typedef CONST RAWINPUTDEVICE *PCRAWINPUTDEVICE; - -#define RIDEV_REMOVE 0x00000001 -#define RIDEV_EXCLUDE 0x00000010 -#define RIDEV_PAGEONLY 0x00000020 -#define RIDEV_NOLEGACY 0x00000030 -#define RIDEV_INPUTSINK 0x00000100 -#define RIDEV_CAPTUREMOUSE 0x00000200 -#define RIDEV_NOHOTKEYS 0x00000200 -#define RIDEV_APPKEYS 0x00000400 -#define RIDEV_EXMODEMASK 0x000000F0 -#define RIDEV_EXMODE(mode) ((mode) & RIDEV_EXMODEMASK) - - WINUSERAPI WINBOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices,UINT uiNumDevices,UINT cbSize); - WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices,PUINT puiNumDevices,UINT cbSize); - - typedef struct tagRAWINPUTDEVICELIST { - HANDLE hDevice; - DWORD dwType; - } RAWINPUTDEVICELIST,*PRAWINPUTDEVICELIST; - - WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList,PUINT puiNumDevices,UINT cbSize); - WINUSERAPI LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput,INT nInput,UINT cbSizeHeader); - -#endif /* NOUSER */ - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/include/winapi/winver.h b/tinyc/win32/include/winapi/winver.h deleted file mode 100644 index 5c0f036bc..000000000 --- a/tinyc/win32/include/winapi/winver.h +++ /dev/null @@ -1,160 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef VER_H -#define VER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define VS_FILE_INFO RT_VERSION -#define VS_VERSION_INFO 1 -#define VS_USER_DEFINED 100 - -#define VS_FFI_SIGNATURE 0xFEEF04BDL -#define VS_FFI_STRUCVERSION 0x00010000L -#define VS_FFI_FILEFLAGSMASK 0x0000003FL - -#define VS_FF_DEBUG 0x00000001L -#define VS_FF_PRERELEASE 0x00000002L -#define VS_FF_PATCHED 0x00000004L -#define VS_FF_PRIVATEBUILD 0x00000008L -#define VS_FF_INFOINFERRED 0x00000010L -#define VS_FF_SPECIALBUILD 0x00000020L - -#define VOS_UNKNOWN 0x00000000L -#define VOS_DOS 0x00010000L -#define VOS_OS216 0x00020000L -#define VOS_OS232 0x00030000L -#define VOS_NT 0x00040000L -#define VOS_WINCE 0x00050000L - -#define VOS__BASE 0x00000000L -#define VOS__WINDOWS16 0x00000001L -#define VOS__PM16 0x00000002L -#define VOS__PM32 0x00000003L -#define VOS__WINDOWS32 0x00000004L - -#define VOS_DOS_WINDOWS16 0x00010001L -#define VOS_DOS_WINDOWS32 0x00010004L -#define VOS_OS216_PM16 0x00020002L -#define VOS_OS232_PM32 0x00030003L -#define VOS_NT_WINDOWS32 0x00040004L - -#define VFT_UNKNOWN 0x00000000L -#define VFT_APP 0x00000001L -#define VFT_DLL 0x00000002L -#define VFT_DRV 0x00000003L -#define VFT_FONT 0x00000004L -#define VFT_VXD 0x00000005L -#define VFT_STATIC_LIB 0x00000007L - -#define VFT2_UNKNOWN 0x00000000L -#define VFT2_DRV_PRINTER 0x00000001L -#define VFT2_DRV_KEYBOARD 0x00000002L -#define VFT2_DRV_LANGUAGE 0x00000003L -#define VFT2_DRV_DISPLAY 0x00000004L -#define VFT2_DRV_MOUSE 0x00000005L -#define VFT2_DRV_NETWORK 0x00000006L -#define VFT2_DRV_SYSTEM 0x00000007L -#define VFT2_DRV_INSTALLABLE 0x00000008L -#define VFT2_DRV_SOUND 0x00000009L -#define VFT2_DRV_COMM 0x0000000AL -#define VFT2_DRV_INPUTMETHOD 0x0000000BL -#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL - -#define VFT2_FONT_RASTER 0x00000001L -#define VFT2_FONT_VECTOR 0x00000002L -#define VFT2_FONT_TRUETYPE 0x00000003L - -#define VFFF_ISSHAREDFILE 0x0001 - -#define VFF_CURNEDEST 0x0001 -#define VFF_FILEINUSE 0x0002 -#define VFF_BUFFTOOSMALL 0x0004 - -#define VIFF_FORCEINSTALL 0x0001 -#define VIFF_DONTDELETEOLD 0x0002 - -#define VIF_TEMPFILE 0x00000001L -#define VIF_MISMATCH 0x00000002L -#define VIF_SRCOLD 0x00000004L - -#define VIF_DIFFLANG 0x00000008L -#define VIF_DIFFCODEPG 0x00000010L -#define VIF_DIFFTYPE 0x00000020L - -#define VIF_WRITEPROT 0x00000040L -#define VIF_FILEINUSE 0x00000080L -#define VIF_OUTOFSPACE 0x00000100L -#define VIF_ACCESSVIOLATION 0x00000200L -#define VIF_SHARINGVIOLATION 0x00000400L -#define VIF_CANNOTCREATE 0x00000800L -#define VIF_CANNOTDELETE 0x00001000L -#define VIF_CANNOTRENAME 0x00002000L -#define VIF_CANNOTDELETECUR 0x00004000L -#define VIF_OUTOFMEMORY 0x00008000L - -#define VIF_CANNOTREADSRC 0x00010000L -#define VIF_CANNOTREADDST 0x00020000L - -#define VIF_BUFFTOOSMALL 0x00040000L -#define VIF_CANNOTLOADLZ32 0x00080000L -#define VIF_CANNOTLOADCABINET 0x00100000L - -#ifndef RC_INVOKED - - typedef struct tagVS_FIXEDFILEINFO - { - DWORD dwSignature; - DWORD dwStrucVersion; - DWORD dwFileVersionMS; - DWORD dwFileVersionLS; - DWORD dwProductVersionMS; - DWORD dwProductVersionLS; - DWORD dwFileFlagsMask; - DWORD dwFileFlags; - DWORD dwFileOS; - DWORD dwFileType; - DWORD dwFileSubtype; - DWORD dwFileDateMS; - DWORD dwFileDateLS; - } VS_FIXEDFILEINFO; - -#ifdef UNICODE -#define VerFindFile VerFindFileW -#define VerInstallFile VerInstallFileW -#define GetFileVersionInfoSize GetFileVersionInfoSizeW -#define GetFileVersionInfo GetFileVersionInfoW -#define VerLanguageName VerLanguageNameW -#define VerQueryValue VerQueryValueW -#else -#define VerFindFile VerFindFileA -#define VerInstallFile VerInstallFileA -#define GetFileVersionInfoSize GetFileVersionInfoSizeA -#define GetFileVersionInfo GetFileVersionInfoA -#define VerLanguageName VerLanguageNameA -#define VerQueryValue VerQueryValueA -#endif - - DWORD WINAPI VerFindFileA(DWORD uFlags,LPSTR szFileName,LPSTR szWinDir,LPSTR szAppDir,LPSTR szCurDir,PUINT lpuCurDirLen,LPSTR szDestDir,PUINT lpuDestDirLen); - DWORD WINAPI VerFindFileW(DWORD uFlags,LPWSTR szFileName,LPWSTR szWinDir,LPWSTR szAppDir,LPWSTR szCurDir,PUINT lpuCurDirLen,LPWSTR szDestDir,PUINT lpuDestDirLen); - DWORD WINAPI VerInstallFileA(DWORD uFlags,LPSTR szSrcFileName,LPSTR szDestFileName,LPSTR szSrcDir,LPSTR szDestDir,LPSTR szCurDir,LPSTR szTmpFile,PUINT lpuTmpFileLen); - DWORD WINAPI VerInstallFileW(DWORD uFlags,LPWSTR szSrcFileName,LPWSTR szDestFileName,LPWSTR szSrcDir,LPWSTR szDestDir,LPWSTR szCurDir,LPWSTR szTmpFile,PUINT lpuTmpFileLen); - DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename,LPDWORD lpdwHandle); - DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); - WINBOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); - WINBOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); - DWORD WINAPI VerLanguageNameA(DWORD wLang,LPSTR szLang,DWORD nSize); - DWORD WINAPI VerLanguageNameW(DWORD wLang,LPWSTR szLang,DWORD nSize); - WINBOOL WINAPI VerQueryValueA(const LPVOID pBlock,LPSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); - WINBOOL WINAPI VerQueryValueW(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tinyc/win32/lib/chkstk.S b/tinyc/win32/lib/chkstk.S deleted file mode 100644 index ec5c07ff8..000000000 --- a/tinyc/win32/lib/chkstk.S +++ /dev/null @@ -1,191 +0,0 @@ -/* ---------------------------------------------- */ -/* chkstk86.s */ - -/* ---------------------------------------------- */ -#ifndef __x86_64__ -/* ---------------------------------------------- */ - -.globl __chkstk - -__chkstk: - xchg (%esp),%ebp /* store ebp, get ret.addr */ - push %ebp /* push ret.addr */ - lea 4(%esp),%ebp /* setup frame ptr */ - push %ecx /* save ecx */ - mov %ebp,%ecx -P0: - sub $4096,%ecx - test %eax,(%ecx) - sub $4096,%eax - cmp $4096,%eax - jge P0 - sub %eax,%ecx - test %eax,(%ecx) - - mov %esp,%eax - mov %ecx,%esp - mov (%eax),%ecx /* restore ecx */ - jmp *4(%eax) - -/* ---------------------------------------------- */ -#else -/* ---------------------------------------------- */ - -.globl __chkstk - -__chkstk: - xchg (%rsp),%rbp /* store ebp, get ret.addr */ - push %rbp /* push ret.addr */ - lea 8(%rsp),%rbp /* setup frame ptr */ - push %rcx /* save ecx */ - mov %rbp,%rcx - movslq %eax,%rax -P0: - sub $4096,%rcx - test %rax,(%rcx) - sub $4096,%rax - cmp $4096,%rax - jge P0 - sub %rax,%rcx - test %rax,(%rcx) - - mov %rsp,%rax - mov %rcx,%rsp - mov (%rax),%rcx /* restore ecx */ - jmp *8(%rax) - -/* ---------------------------------------------- */ -/* setjmp/longjmp support */ - -.globl tinyc_getbp -tinyc_getbp: - mov %rbp,%rax - ret - -/* ---------------------------------------------- */ -#endif -/* ---------------------------------------------- */ - - -/* ---------------------------------------------- */ -#ifndef __x86_64__ -/* ---------------------------------------------- */ - -/* - int _except_handler3( - PEXCEPTION_RECORD exception_record, - PEXCEPTION_REGISTRATION registration, - PCONTEXT context, - PEXCEPTION_REGISTRATION dispatcher - ); - - int __cdecl _XcptFilter( - unsigned long xcptnum, - PEXCEPTION_POINTERS pxcptinfoptrs - ); - - struct _sehrec { - void *esp; // 0 - void *exception_pointers; // 1 - void *prev; // 2 - void *handler; // 3 - void *scopetable; // 4 - int trylevel; // 5 - void *ebp // 6 - }; - - // this is what the assembler code below means: - __try - { - // ... - } - __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation())) - { - exit(GetExceptionCode()); - } -*/ - -.globl _exception_info -_exception_info: - mov 1*4-24(%ebp),%eax - ret - -.globl _exception_code -_exception_code: - call _exception_info - mov (%eax),%eax - mov (%eax),%eax - ret - -seh_filter: - call _exception_info - push %eax - call _exception_code - push %eax - call _XcptFilter - add $ 8,%esp - ret - -seh_except: - mov 0*4-24(%ebp),%esp - call _exception_code - push %eax - call _exit - -// msvcrt wants scopetables aligned and in read-only segment (using .text) -.align 4 -seh_scopetable: - .long -1 - .long seh_filter - .long seh_except - -seh_handler: - jmp _except_handler3 - -.globl ___try__ -___try__: -.globl __try__ -__try__: - push %ebp - mov 8(%esp),%ebp - -// void *esp; - lea 12(%esp),%eax - mov %eax,0*4(%ebp) - -// void *exception_pointers; - xor %eax,%eax - mov %eax,1*4(%ebp) - -// void *prev; - mov %fs:0,%eax - mov %eax,2*4(%ebp) - -// void *handler; - mov $ seh_handler,%eax - mov %eax,3*4(%ebp) - -// void *scopetable; - mov $ seh_scopetable,%eax - mov %eax,4*4(%ebp) - -// int trylevel; - xor %eax,%eax - mov %eax,5*4(%ebp) - -// register new SEH - lea 2*4(%ebp),%eax - mov %eax,%fs:0 - - pop %ebp - ret - -/* ---------------------------------------------- */ -#else -/* ---------------------------------------------- */ - -/* SEH on x86-64 not implemented */ - -/* ---------------------------------------------- */ -#endif -/* ---------------------------------------------- */ diff --git a/tinyc/win32/lib/crt1.c b/tinyc/win32/lib/crt1.c deleted file mode 100644 index 0e04fc012..000000000 --- a/tinyc/win32/lib/crt1.c +++ /dev/null @@ -1,79 +0,0 @@ -// ============================================= -// crt1.c - -// _UNICODE for tchar.h, UNICODE for API -#include - -#include -#include - -#define _UNKNOWN_APP 0 -#define _CONSOLE_APP 1 -#define _GUI_APP 2 - -#define _MCW_PC 0x00030000 // Precision Control -#define _PC_24 0x00020000 // 24 bits -#define _PC_53 0x00010000 // 53 bits -#define _PC_64 0x00000000 // 64 bits - -#ifdef _UNICODE -#define __tgetmainargs __wgetmainargs -#define _tstart _wstart -#define _tmain wmain -#define _runtmain _runwmain -#else -#define __tgetmainargs __getmainargs -#define _tstart _start -#define _tmain main -#define _runtmain _runmain -#endif - -typedef struct { int newmode; } _startupinfo; -int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*); -void __cdecl __set_app_type(int apptype); -unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask); -extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]); - -/* Allow command-line globbing with "int _dowildcard = 1;" in the user source */ -int _dowildcard; - -void _tstart(void) -{ - __TRY__ - _startupinfo start_info = {0}; - - // Sets the current application type - __set_app_type(_CONSOLE_APP); - - // Set default FP precision to 53 bits (8-byte double) - // _MCW_PC (Precision control) is not supported on ARM -#if defined __i386__ || defined __x86_64__ - _controlfp(_PC_53, _MCW_PC); -#endif - - __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info); - exit(_tmain(__argc, __targv, _tenviron)); -} - -int _runtmain(int argc, /* as tcc passed in */ char **argv) -{ -#ifdef UNICODE - _startupinfo start_info = {0}; - - __tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info); - /* may be wrong when tcc has received wildcards (*.c) */ - if (argc < __argc) { - __targv += __argc - argc; - __argc = argc; - } -#else - __argc = argc; - __targv = argv; -#endif -#if defined __i386__ || defined __x86_64__ - _controlfp(_PC_53, _MCW_PC); -#endif - return _tmain(__argc, __targv, _tenviron); -} - -// ============================================= diff --git a/tinyc/win32/lib/crt1w.c b/tinyc/win32/lib/crt1w.c deleted file mode 100644 index 2b8bbc8bc..000000000 --- a/tinyc/win32/lib/crt1w.c +++ /dev/null @@ -1,3 +0,0 @@ -#define _UNICODE 1 -#define UNICODE 1 -#include "crt1.c" diff --git a/tinyc/win32/lib/dllcrt1.c b/tinyc/win32/lib/dllcrt1.c deleted file mode 100644 index ba1dbd048..000000000 --- a/tinyc/win32/lib/dllcrt1.c +++ /dev/null @@ -1,13 +0,0 @@ -//+--------------------------------------------------------------------------- - -#include - -BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved); - -BOOL WINAPI _dllstart(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) -{ - BOOL bRet; - bRet = DllMain (hDll, dwReason, lpReserved); - return bRet; -} - diff --git a/tinyc/win32/lib/dllmain.c b/tinyc/win32/lib/dllmain.c deleted file mode 100644 index 2c25b98b8..000000000 --- a/tinyc/win32/lib/dllmain.c +++ /dev/null @@ -1,9 +0,0 @@ -//+--------------------------------------------------------------------------- - -#include - -BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) -{ - return TRUE; -} - diff --git a/tinyc/win32/lib/gdi32.def b/tinyc/win32/lib/gdi32.def deleted file mode 100644 index 02766da43..000000000 --- a/tinyc/win32/lib/gdi32.def +++ /dev/null @@ -1,337 +0,0 @@ -LIBRARY gdi32.dll - -EXPORTS -AbortDoc -AbortPath -AddFontResourceA -AddFontResourceW -AngleArc -AnimatePalette -Arc -ArcTo -BeginPath -BitBlt -ByeByeGDI -CancelDC -CheckColorsInGamut -ChoosePixelFormat -Chord -CloseEnhMetaFile -CloseFigure -CloseMetaFile -ColorCorrectPalette -ColorMatchToTarget -CombineRgn -CombineTransform -CopyEnhMetaFileA -CopyEnhMetaFileW -CopyMetaFileA -CopyMetaFileW -CreateBitmap -CreateBitmapIndirect -CreateBrushIndirect -CreateColorSpaceA -CreateColorSpaceW -CreateCompatibleBitmap -CreateCompatibleDC -CreateDCA -CreateDCW -CreateDIBPatternBrush -CreateDIBPatternBrushPt -CreateDIBSection -CreateDIBitmap -CreateDiscardableBitmap -CreateEllipticRgn -CreateEllipticRgnIndirect -CreateEnhMetaFileA -CreateEnhMetaFileW -CreateFontA -CreateFontIndirectA -CreateFontIndirectW -CreateFontW -CreateHalftonePalette -CreateHatchBrush -CreateICA -CreateICW -CreateMetaFileA -CreateMetaFileW -CreatePalette -CreatePatternBrush -CreatePen -CreatePenIndirect -CreatePolyPolygonRgn -CreatePolygonRgn -CreateRectRgn -CreateRectRgnIndirect -CreateRoundRectRgn -CreateScalableFontResourceA -CreateScalableFontResourceW -CreateSolidBrush -DPtoLP -DeleteColorSpace -DeleteDC -DeleteEnhMetaFile -DeleteMetaFile -DeleteObject -DescribePixelFormat -DeviceCapabilitiesEx -DeviceCapabilitiesExA -DeviceCapabilitiesExW -DrawEscape -Ellipse -EnableEUDC -EndDoc -EndPage -EndPath -EnumEnhMetaFile -EnumFontFamiliesA -EnumFontFamiliesExA -EnumFontFamiliesExW -EnumFontFamiliesW -EnumFontsA -EnumFontsW -EnumICMProfilesA -EnumICMProfilesW -EnumMetaFile -EnumObjects -EqualRgn -Escape -ExcludeClipRect -ExtCreatePen -ExtCreateRegion -ExtEscape -ExtFloodFill -ExtSelectClipRgn -ExtTextOutA -ExtTextOutW -FillPath -FillRgn -FixBrushOrgEx -FlattenPath -FloodFill -FrameRgn -GdiComment -GdiFlush -GdiGetBatchLimit -GdiPlayDCScript -GdiPlayJournal -GdiPlayScript -GdiSetBatchLimit -GetArcDirection -GetAspectRatioFilterEx -GetBitmapBits -GetBitmapDimensionEx -GetBkColor -GetBkMode -GetBoundsRect -GetBrushOrgEx -GetCharABCWidthsA -GetCharABCWidthsFloatA -GetCharABCWidthsFloatW -GetCharABCWidthsW -GetCharWidth32A -GetCharWidth32W -GetCharWidthA -GetCharWidthFloatA -GetCharWidthFloatW -GetCharWidthW -GetCharacterPlacementA -GetCharacterPlacementW -GetClipBox -GetClipRgn -GetColorAdjustment -GetColorSpace -GetCurrentObject -GetCurrentPositionEx -GetDCOrgEx -GetDIBColorTable -GetDIBits -GetDeviceCaps -GetDeviceGammaRamp -GetEnhMetaFileA -GetEnhMetaFileBits -GetEnhMetaFileDescriptionA -GetEnhMetaFileDescriptionW -GetEnhMetaFileHeader -GetEnhMetaFilePaletteEntries -GetEnhMetaFileW -GetFontData -GetFontLanguageInfo -GetFontResourceInfo -GetGlyphOutline -GetGlyphOutlineA -GetGlyphOutlineW -GetGraphicsMode -GetICMProfileA -GetICMProfileW -GetKerningPairs -GetKerningPairsA -GetKerningPairsW -GetLayout -GetLogColorSpaceA -GetLogColorSpaceW -GetMapMode -GetMetaFileA -GetMetaFileBitsEx -GetMetaFileW -GetMetaRgn -GetMiterLimit -GetNearestColor -GetNearestPaletteIndex -GetObjectA -GetObjectType -GetObjectW -GetOutlineTextMetricsA -GetOutlineTextMetricsW -GetPaletteEntries -GetPath -GetPixel -GetPixelFormat -GetPolyFillMode -GetROP2 -GetRandomRgn -GetRasterizerCaps -GetRegionData -GetRgnBox -GetStockObject -GetStretchBltMode -GetSystemPaletteEntries -GetSystemPaletteUse -GetTextAlign -GetTextCharacterExtra -GetTextCharset -GetTextCharsetInfo -GetTextColor -GetTextExtentExPointA -GetTextExtentExPointW -GetTextExtentPoint32A -GetTextExtentPoint32W -GetTextExtentPointA -GetTextExtentPointW -GetTextFaceA -GetTextFaceW -GetTextMetricsA -GetTextMetricsW -GetViewportExtEx -GetViewportOrgEx -GetWinMetaFileBits -GetWindowExtEx -GetWindowOrgEx -GetWorldTransform -IntersectClipRect -InvertRgn -LPtoDP -LineDDA -LineTo -MaskBlt -ModifyWorldTransform -MoveToEx -OffsetClipRgn -OffsetRgn -OffsetViewportOrgEx -OffsetWindowOrgEx -PaintRgn -PatBlt -PathToRegion -Pie -PlayEnhMetaFile -PlayEnhMetaFileRecord -PlayMetaFile -PlayMetaFileRecord -PlgBlt -PolyBezier -PolyBezierTo -PolyDraw -PolyPolygon -PolyPolyline -PolyTextOutA -PolyTextOutW -Polygon -Polyline -PolylineTo -PtInRegion -PtVisible -RealizePalette -RectInRegion -RectVisible -Rectangle -RemoveFontResourceA -RemoveFontResourceW -ResetDCA -ResetDCW -ResizePalette -RestoreDC -RoundRect -SaveDC -ScaleViewportExtEx -ScaleWindowExtEx -SelectClipPath -SelectClipRgn -SelectObject -SelectPalette -SetAbortProc -SetArcDirection -SetBitmapBits -SetBitmapDimensionEx -SetBkColor -SetBkMode -SetBoundsRect -SetBrushOrgEx -SetColorAdjustment -SetColorSpace -SetDIBColorTable -SetDIBits -SetDIBitsToDevice -SetDeviceGammaRamp -SetEnhMetaFileBits -SetFontEnumeration -SetGraphicsMode -SetICMMode -SetICMProfileA -SetICMProfileW -SetLayout -SetMagicColors -SetMapMode -SetMapperFlags -SetMetaFileBitsEx -SetMetaRgn -SetMiterLimit -SetObjectOwner -SetPaletteEntries -SetPixel -SetPixelFormat -SetPixelV -SetPolyFillMode -SetROP2 -SetRectRgn -SetStretchBltMode -SetSystemPaletteUse -SetTextAlign -SetTextCharacterExtra -SetTextColor -SetTextJustification -SetViewportExtEx -SetViewportOrgEx -SetWinMetaFileBits -SetWindowExtEx -SetWindowOrgEx -SetWorldTransform -StartDocA -StartDocW -StartPage -StretchBlt -StretchDIBits -StrokeAndFillPath -StrokePath -SwapBuffers -TextOutA -TextOutW -TranslateCharsetInfo -UnrealizeObject -UpdateColors -UpdateICMRegKeyA -UpdateICMRegKeyW -WidenPath -gdiPlaySpoolStream -pfnRealizePalette -pfnSelectPalette diff --git a/tinyc/win32/lib/kernel32.def b/tinyc/win32/lib/kernel32.def deleted file mode 100644 index f03e17ba4..000000000 --- a/tinyc/win32/lib/kernel32.def +++ /dev/null @@ -1,770 +0,0 @@ -LIBRARY kernel32.dll - -EXPORTS -AddAtomA -AddAtomW -AllocConsole -AllocLSCallback -AllocSLCallback -AreFileApisANSI -BackupRead -BackupSeek -BackupWrite -Beep -BeginUpdateResourceA -BeginUpdateResourceW -BuildCommDCBA -BuildCommDCBAndTimeoutsA -BuildCommDCBAndTimeoutsW -BuildCommDCBW -CallNamedPipeA -CallNamedPipeW -Callback12 -Callback16 -Callback20 -Callback24 -Callback28 -Callback32 -Callback36 -Callback4 -Callback40 -Callback44 -Callback48 -Callback52 -Callback56 -Callback60 -Callback64 -Callback8 -CancelDeviceWakeupRequest -CancelIo -CancelWaitableTimer -ClearCommBreak -ClearCommError -CloseHandle -CloseProfileUserMapping -CloseSystemHandle -CommConfigDialogA -CommConfigDialogW -CompareFileTime -CompareStringA -CompareStringW -ConnectNamedPipe -ContinueDebugEvent -ConvertDefaultLocale -ConvertThreadToFiber -ConvertToGlobalHandle -CopyFileA -CopyFileExA -CopyFileExW -CopyFileW -CreateConsoleScreenBuffer -CreateDirectoryA -CreateDirectoryExA -CreateDirectoryExW -CreateDirectoryW -CreateEventA -CreateEventW -CreateFiber -CreateFileA -CreateFileMappingA -CreateFileMappingW -CreateFileW -CreateIoCompletionPort -CreateKernelThread -CreateMailslotA -CreateMailslotW -CreateMutexA -CreateMutexW -CreateNamedPipeA -CreateNamedPipeW -CreatePipe -CreateProcessA -CreateProcessW -CreateRemoteThread -CreateSemaphoreA -CreateSemaphoreW -CreateSocketHandle -CreateTapePartition -CreateThread -CreateToolhelp32Snapshot -CreateWaitableTimerA -CreateWaitableTimerW -DebugActiveProcess -DebugBreak -DefineDosDeviceA -DefineDosDeviceW -DeleteAtom -DeleteCriticalSection -DeleteFiber -DeleteFileA -DeleteFileW -DeviceIoControl -DisableThreadLibraryCalls -DisconnectNamedPipe -DosDateTimeToFileTime -DuplicateHandle -EndUpdateResourceA -EndUpdateResourceW -EnterCriticalSection -EnumCalendarInfoA -EnumCalendarInfoExA -EnumCalendarInfoExW -EnumCalendarInfoW -EnumDateFormatsA -EnumDateFormatsExA -EnumDateFormatsExW -EnumDateFormatsW -EnumLanguageGroupLocalesA -EnumLanguageGroupLocalesW -EnumResourceLanguagesA -EnumResourceLanguagesW -EnumResourceNamesA -EnumResourceNamesW -EnumResourceTypesA -EnumResourceTypesW -EnumSystemCodePagesA -EnumSystemCodePagesW -EnumSystemGeoID -EnumSystemLanguageGroupsA -EnumSystemLanguageGroupsW -EnumSystemLocalesA -EnumSystemLocalesW -EnumTimeFormatsA -EnumTimeFormatsW -EnumUILanguagesA -EnumUILanguagesW -EraseTape -EscapeCommFunction -ExitProcess -ExitThread -ExpandEnvironmentStringsA -ExpandEnvironmentStringsW -FT_Exit0 -FT_Exit12 -FT_Exit16 -FT_Exit20 -FT_Exit24 -FT_Exit28 -FT_Exit32 -FT_Exit36 -FT_Exit4 -FT_Exit40 -FT_Exit44 -FT_Exit48 -FT_Exit52 -FT_Exit56 -FT_Exit8 -FT_Prolog -FT_Thunk -FatalAppExitA -FatalAppExitW -FatalExit -FileTimeToDosDateTime -FileTimeToLocalFileTime -FileTimeToSystemTime -FillConsoleOutputAttribute -FillConsoleOutputCharacterA -FillConsoleOutputCharacterW -FindAtomA -FindAtomW -FindClose -FindCloseChangeNotification -FindFirstChangeNotificationA -FindFirstChangeNotificationW -FindFirstFileA -FindFirstFileExA -FindFirstFileExW -FindFirstFileW -FindNextChangeNotification -FindNextFileA -FindNextFileW -FindResourceA -FindResourceExA -FindResourceExW -FindResourceW -FlushConsoleInputBuffer -FlushFileBuffers -FlushInstructionCache -FlushViewOfFile -FoldStringA -FoldStringW -FormatMessageA -FormatMessageW -FreeConsole -FreeEnvironmentStringsA -FreeEnvironmentStringsW -FreeLSCallback -FreeLibrary -FreeLibraryAndExitThread -FreeResource -FreeSLCallback -GenerateConsoleCtrlEvent -GetACP -GetAtomNameA -GetAtomNameW -GetBinaryType -GetBinaryTypeA -GetBinaryTypeW -GetCPInfo -GetCPInfoExA -GetCPInfoExW -GetCalendarInfoA -GetCalendarInfoW -GetCommConfig -GetCommMask -GetCommModemStatus -GetCommProperties -GetCommState -GetCommTimeouts -GetCommandLineA -GetCommandLineW -GetCompressedFileSizeA -GetCompressedFileSizeW -GetComputerNameA -GetComputerNameW -GetConsoleCP -GetConsoleCursorInfo -GetConsoleMode -GetConsoleOutputCP -GetConsoleScreenBufferInfo -GetConsoleTitleA -GetConsoleTitleW -GetCurrencyFormatA -GetCurrencyFormatW -GetCurrentDirectoryA -GetCurrentDirectoryW -GetCurrentProcess -GetCurrentProcessId -GetCurrentThread -GetCurrentThreadId -GetDateFormatA -GetDateFormatW -GetDaylightFlag -GetDefaultCommConfigA -GetDefaultCommConfigW -GetDevicePowerState -GetDiskFreeSpaceA -GetDiskFreeSpaceExA -GetDiskFreeSpaceExW -GetDiskFreeSpaceW -GetDriveTypeA -GetDriveTypeW -GetEnvironmentStrings -GetEnvironmentStringsA -GetEnvironmentStringsW -GetEnvironmentVariableA -GetEnvironmentVariableW -GetErrorMode -GetExitCodeProcess -GetExitCodeThread -GetFileAttributesA -GetFileAttributesExA -GetFileAttributesExW -GetFileAttributesW -GetFileInformationByHandle -GetFileSize -GetFileTime -GetFileType -GetFullPathNameA -GetFullPathNameW -GetGeoInfoA -GetGeoInfoW -GetHandleContext -GetHandleInformation -GetLSCallbackTarget -GetLSCallbackTemplate -GetLargestConsoleWindowSize -GetLastError -GetLocalTime -GetLocaleInfoA -GetLocaleInfoW -GetLogicalDriveStringsA -GetLogicalDriveStringsW -GetLogicalDrives -GetLongPathNameA -GetLongPathNameW -GetMailslotInfo -GetModuleFileNameA -GetModuleFileNameW -GetModuleHandleA -GetModuleHandleW -GetModuleHandleExA -GetModuleHandleExW -GetNamedPipeHandleStateA -GetNamedPipeHandleStateW -GetNamedPipeInfo -GetNumberFormatA -GetNumberFormatW -GetNumberOfConsoleInputEvents -GetNumberOfConsoleMouseButtons -GetOEMCP -GetOverlappedResult -GetPriorityClass -GetPrivateProfileIntA -GetPrivateProfileIntW -GetPrivateProfileSectionA -GetPrivateProfileSectionNamesA -GetPrivateProfileSectionNamesW -GetPrivateProfileSectionW -GetPrivateProfileStringA -GetPrivateProfileStringW -GetPrivateProfileStructA -GetPrivateProfileStructW -GetProcAddress -GetProcessAffinityMask -GetProcessFlags -GetProcessHeap -GetProcessHeaps -GetProcessPriorityBoost -GetProcessShutdownParameters -GetProcessTimes -GetProcessVersion -GetProcessWorkingSetSize -GetProductName -GetProfileIntA -GetProfileIntW -GetProfileSectionA -GetProfileSectionW -GetProfileStringA -GetProfileStringW -GetQueuedCompletionStatus -GetSLCallbackTarget -GetSLCallbackTemplate -GetShortPathNameA -GetShortPathNameW -GetStartupInfoA -GetStartupInfoW -GetStdHandle -GetStringTypeA -GetStringTypeExA -GetStringTypeExW -GetStringTypeW -GetSystemDefaultLCID -GetSystemDefaultLangID -GetSystemDefaultUILanguage -GetSystemDirectoryA -GetSystemDirectoryW -GetSystemInfo -GetSystemPowerStatus -GetSystemTime -GetSystemTimeAdjustment -GetSystemTimeAsFileTime -GetTapeParameters -GetTapePosition -GetTapeStatus -GetTempFileNameA -GetTempFileNameW -GetTempPathA -GetTempPathW -GetThreadContext -GetThreadLocale -GetThreadPriority -GetThreadPriorityBoost -GetThreadSelectorEntry -GetThreadTimes -GetTickCount -GetTimeFormatA -GetTimeFormatW -GetTimeZoneInformation -GetUserDefaultLCID -GetUserDefaultLangID -GetUserDefaultUILanguage -GetUserGeoID -GetVersion -GetVersionExA -GetVersionExW -GetVolumeInformationA -GetVolumeInformationW -GetWindowsDirectoryA -GetWindowsDirectoryW -GetWriteWatch -GlobalAddAtomA -GlobalAddAtomW -GlobalAlloc -GlobalCompact -GlobalDeleteAtom -GlobalFindAtomA -GlobalFindAtomW -GlobalFix -GlobalFlags -GlobalFree -GlobalGetAtomNameA -GlobalGetAtomNameW -GlobalHandle -GlobalLock -GlobalMemoryStatus -GlobalReAlloc -GlobalSize -GlobalUnWire -GlobalUnfix -GlobalUnlock -GlobalWire -Heap32First -Heap32ListFirst -Heap32ListNext -Heap32Next -HeapAlloc -HeapCompact -HeapCreate -HeapDestroy -HeapFree -HeapLock -HeapReAlloc -HeapSetFlags -HeapSize -HeapUnlock -HeapValidate -HeapWalk -InitAtomTable -InitializeCriticalSection -InitializeCriticalSectionAndSpinCount -InterlockedCompareExchange -InterlockedDecrement -InterlockedExchange -InterlockedExchangeAdd -InterlockedIncrement -InvalidateNLSCache -IsBadCodePtr -IsBadHugeReadPtr -IsBadHugeWritePtr -IsBadReadPtr -IsBadStringPtrA -IsBadStringPtrW -IsBadWritePtr -IsDBCSLeadByte -IsDBCSLeadByteEx -IsDebuggerPresent -IsLSCallback -IsProcessorFeaturePresent -IsSLCallback -IsSystemResumeAutomatic -IsValidCodePage -IsValidLanguageGroup -IsValidLocale -K32Thk1632Epilog -K32Thk1632Prolog -K32_NtCreateFile -K32_RtlNtStatusToDosError -LCMapStringA -LCMapStringW -LeaveCriticalSection -LoadLibraryA -LoadLibraryExA -LoadLibraryExW -LoadLibraryW -LoadModule -LoadResource -LocalAlloc -LocalCompact -LocalFileTimeToFileTime -LocalFlags -LocalFree -LocalHandle -LocalLock -LocalReAlloc -LocalShrink -LocalSize -LocalUnlock -LockFile -LockFileEx -LockResource -MakeCriticalSectionGlobal -MapHInstLS -MapHInstLS_PN -MapHInstSL -MapHInstSL_PN -MapHModuleLS -MapHModuleSL -MapLS -MapSL -MapSLFix -MapViewOfFile -MapViewOfFileEx -Module32First -Module32Next -MoveFileA -MoveFileExA -MoveFileExW -MoveFileW -MulDiv -MultiByteToWideChar -NotifyNLSUserCache -OpenEventA -OpenEventW -OpenFile -OpenFileMappingA -OpenFileMappingW -OpenMutexA -OpenMutexW -OpenProcess -OpenProfileUserMapping -OpenSemaphoreA -OpenSemaphoreW -OpenThread -OpenVxDHandle -OpenWaitableTimerA -OpenWaitableTimerW -OutputDebugStringA -OutputDebugStringW -PeekConsoleInputA -PeekConsoleInputW -PeekNamedPipe -PostQueuedCompletionStatus -PrepareTape -Process32First -Process32Next -PulseEvent -PurgeComm -QT_Thunk -QueryDosDeviceA -QueryDosDeviceW -QueryNumberOfEventLogRecords -QueryOldestEventLogRecord -QueryPerformanceCounter -QueryPerformanceFrequency -QueueUserAPC -RaiseException -ReadConsoleA -ReadConsoleInputA -ReadConsoleInputW -ReadConsoleOutputA -ReadConsoleOutputAttribute -ReadConsoleOutputCharacterA -ReadConsoleOutputCharacterW -ReadConsoleOutputW -ReadConsoleW -ReadDirectoryChangesW -ReadFile -ReadFileEx -ReadFileScatter -ReadProcessMemory -RegisterServiceProcess -RegisterSysMsgHandler -ReinitializeCriticalSection -ReleaseMutex -ReleaseSemaphore -RemoveDirectoryA -RemoveDirectoryW -RequestDeviceWakeup -RequestWakeupLatency -ResetEvent -ResetNLSUserInfoCache -ResetWriteWatch -ResumeThread -RtlAddFunctionTable -RtlDeleteFunctionTable -RtlFillMemory -RtlInstallFunctionTableCallback -RtlMoveMemory -RtlUnwind -RtlUnwindEx -RtlZeroMemory -SMapLS -SMapLS_IP_EBP_12 -SMapLS_IP_EBP_16 -SMapLS_IP_EBP_20 -SMapLS_IP_EBP_24 -SMapLS_IP_EBP_28 -SMapLS_IP_EBP_32 -SMapLS_IP_EBP_36 -SMapLS_IP_EBP_40 -SMapLS_IP_EBP_8 -SUnMapLS -SUnMapLS_IP_EBP_12 -SUnMapLS_IP_EBP_16 -SUnMapLS_IP_EBP_20 -SUnMapLS_IP_EBP_24 -SUnMapLS_IP_EBP_28 -SUnMapLS_IP_EBP_32 -SUnMapLS_IP_EBP_36 -SUnMapLS_IP_EBP_40 -SUnMapLS_IP_EBP_8 -ScrollConsoleScreenBufferA -ScrollConsoleScreenBufferW -SearchPathA -SearchPathW -SetCalendarInfoA -SetCalendarInfoW -SetCommBreak -SetCommConfig -SetCommMask -SetCommState -SetCommTimeouts -SetComputerNameA -SetComputerNameW -SetConsoleActiveScreenBuffer -SetConsoleCP -SetConsoleCtrlHandler -SetConsoleCursorInfo -SetConsoleCursorPosition -SetConsoleMode -SetConsoleOutputCP -SetConsoleScreenBufferSize -SetConsoleTextAttribute -SetConsoleTitleA -SetConsoleTitleW -SetConsoleWindowInfo -SetCriticalSectionSpinCount -SetCurrentDirectoryA -SetCurrentDirectoryW -SetDaylightFlag -SetDefaultCommConfigA -SetDefaultCommConfigW -SetEndOfFile -SetEnvironmentVariableA -SetEnvironmentVariableW -SetErrorMode -SetEvent -SetFileApisToANSI -SetFileApisToOEM -SetFileAttributesA -SetFileAttributesW -SetFilePointer -SetFilePointerEx -SetFileTime -SetHandleContext -SetHandleCount -SetHandleInformation -SetLastError -SetLocalTime -SetLocaleInfoA -SetLocaleInfoW -SetMailslotInfo -SetMessageWaitingIndicator -SetNamedPipeHandleState -SetPriorityClass -SetProcessAffinityMask -SetProcessPriorityBoost -SetProcessShutdownParameters -SetProcessWorkingSetSize -SetStdHandle -SetSystemPowerState -SetSystemTime -SetSystemTimeAdjustment -SetTapeParameters -SetTapePosition -SetThreadAffinityMask -SetThreadContext -SetThreadExecutionState -SetThreadIdealProcessor -SetThreadLocale -SetThreadPriority -SetThreadPriorityBoost -SetTimeZoneInformation -SetUnhandledExceptionFilter -SetUserGeoID -SetVolumeLabelA -SetVolumeLabelW -SetWaitableTimer -SetupComm -SignalObjectAndWait -SignalSysMsgHandlers -SizeofResource -Sleep -SleepEx -SuspendThread -SwitchToFiber -SwitchToThread -SystemTimeToFileTime -SystemTimeToTzSpecificLocalTime -TerminateProcess -TerminateThread -Thread32First -Thread32Next -ThunkConnect32 -TlsAlloc -TlsAllocInternal -TlsFree -TlsFreeInternal -TlsGetValue -TlsSetValue -Toolhelp32ReadProcessMemory -TransactNamedPipe -TransmitCommChar -TryEnterCriticalSection -UTRegister -UTUnRegister -UnMapLS -UnMapSLFixArray -UnhandledExceptionFilter -UninitializeCriticalSection -UnlockFile -UnlockFileEx -UnmapViewOfFile -UpdateResourceA -UpdateResourceW -VerLanguageNameA -VerLanguageNameW -VirtualAlloc -VirtualAllocEx -VirtualFree -VirtualFreeEx -VirtualLock -VirtualProtect -VirtualProtectEx -VirtualQuery -VirtualQueryEx -VirtualUnlock -WaitCommEvent -WaitForDebugEvent -WaitForMultipleObjects -WaitForMultipleObjectsEx -WaitForSingleObject -WaitForSingleObjectEx -WaitNamedPipeA -WaitNamedPipeW -WideCharToMultiByte -WinExec -WriteConsoleA -WriteConsoleInputA -WriteConsoleInputW -WriteConsoleOutputA -WriteConsoleOutputAttribute -WriteConsoleOutputCharacterA -WriteConsoleOutputCharacterW -WriteConsoleOutputW -WriteConsoleW -WriteFile -WriteFileEx -WriteFileGather -WritePrivateProfileSectionA -WritePrivateProfileSectionW -WritePrivateProfileStringA -WritePrivateProfileStringW -WritePrivateProfileStructA -WritePrivateProfileStructW -WriteProcessMemory -WriteProfileSectionA -WriteProfileSectionW -WriteProfileStringA -WriteProfileStringW -WriteTapemark -_DebugOut -_DebugPrintf -_hread -_hwrite -_lclose -_lcreat -_llseek -_lopen -_lread -_lwrite -dprintf -lstrcat -lstrcatA -lstrcatW -lstrcmp -lstrcmpA -lstrcmpW -lstrcmpi -lstrcmpiA -lstrcmpiW -lstrcpy -lstrcpyA -lstrcpyW -lstrcpyn -lstrcpynA -lstrcpynW -lstrlen -lstrlenA -lstrlenW diff --git a/tinyc/win32/lib/msvcrt.def b/tinyc/win32/lib/msvcrt.def deleted file mode 100644 index 742acb8bb..000000000 --- a/tinyc/win32/lib/msvcrt.def +++ /dev/null @@ -1,1399 +0,0 @@ -LIBRARY msvcrt.dll - -EXPORTS -$I10_OUTPUT -??0__non_rtti_object@@QAE@ABV0@@Z -??0__non_rtti_object@@QAE@PBD@Z -??0bad_cast@@AAE@PBQBD@Z -??0bad_cast@@QAE@ABQBD@Z -??0bad_cast@@QAE@ABV0@@Z -??0bad_cast@@QAE@PBD@Z -??0bad_typeid@@QAE@ABV0@@Z -??0bad_typeid@@QAE@PBD@Z -??0exception@@QAE@ABQBD@Z -??0exception@@QAE@ABQBDH@Z -??0exception@@QAE@ABV0@@Z -??0exception@@QAE@XZ -??1__non_rtti_object@@UAE@XZ -??1bad_cast@@UAE@XZ -??1bad_typeid@@UAE@XZ -??1exception@@UAE@XZ -??1type_info@@UAE@XZ -??2@YAPAXI@Z -??2@YAPAXIHPBDH@Z -??3@YAXPAX@Z -??4__non_rtti_object@@QAEAAV0@ABV0@@Z -??4bad_cast@@QAEAAV0@ABV0@@Z -??4bad_typeid@@QAEAAV0@ABV0@@Z -??4exception@@QAEAAV0@ABV0@@Z -??8type_info@@QBEHABV0@@Z -??9type_info@@QBEHABV0@@Z -??_7__non_rtti_object@@6B@ -??_7bad_cast@@6B@ -??_7bad_typeid@@6B@ -??_7exception@@6B@ -??_E__non_rtti_object@@UAEPAXI@Z -??_Ebad_cast@@UAEPAXI@Z -??_Ebad_typeid@@UAEPAXI@Z -??_Eexception@@UAEPAXI@Z -??_Fbad_cast@@QAEXXZ -??_Fbad_typeid@@QAEXXZ -??_G__non_rtti_object@@UAEPAXI@Z -??_Gbad_cast@@UAEPAXI@Z -??_Gbad_typeid@@UAEPAXI@Z -??_Gexception@@UAEPAXI@Z -??_U@YAPAXI@Z -??_U@YAPAXIHPBDH@Z -??_V@YAXPAX@Z -?_query_new_handler@@YAP6AHI@ZXZ -?_query_new_mode@@YAHXZ -?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z -?_set_new_mode@@YAHH@Z -?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z -?before@type_info@@QBEHABV1@@Z -?name@type_info@@QBEPBDXZ -?raw_name@type_info@@QBEPBDXZ -?set_new_handler@@YAP6AXXZP6AXXZ@Z -?set_terminate@@YAP6AXXZP6AXXZ@Z -?set_unexpected@@YAP6AXXZP6AXXZ@Z -?terminate@@YAXXZ -?unexpected@@YAXXZ -?what@exception@@UBEPBDXZ -_CIacos -_CIasin -_CIatan -_CIatan2 -_CIcos -_CIcosh -_CIexp -_CIfmod -_CIlog -_CIlog10 -_CIpow -_CIsin -_CIsinh -_CIsqrt -_CItan -_CItanh -_CrtCheckMemory -_CrtDbgBreak -_CrtDbgReport -_CrtDbgReportV -_CrtDbgReportW -_CrtDbgReportWV -_CrtDoForAllClientObjects -_CrtDumpMemoryLeaks -_CrtIsMemoryBlock -_CrtIsValidHeapPointer -_CrtIsValidPointer -_CrtMemCheckpoint -_CrtMemDifference -_CrtMemDumpAllObjectsSince -_CrtMemDumpStatistics -_CrtReportBlockType -_CrtSetAllocHook -_CrtSetBreakAlloc -_CrtSetDbgBlockType -_CrtSetDbgFlag -_CrtSetDumpClient -_CrtSetReportFile -_CrtSetReportHook -_CrtSetReportHook2 -_CrtSetReportMode -_CxxThrowException -_EH_prolog -_Getdays -_Getmonths -_Gettnames -_HUGE -_Strftime -_XcptFilter -__CppXcptFilter -__CxxCallUnwindDelDtor -__CxxCallUnwindDtor -__CxxCallUnwindVecDtor -__CxxDetectRethrow -__CxxExceptionFilter -__CxxFrameHandler -__CxxFrameHandler2 -__CxxFrameHandler3 -__CxxLongjmpUnwind -__CxxQueryExceptionSize -__CxxRegisterExceptionObject -__CxxUnregisterExceptionObject -__DestructExceptionObject -__RTCastToVoid -__RTDynamicCast -__RTtypeid -__STRINGTOLD -___lc_codepage_func -___lc_collate_cp_func -___lc_handle_func -___mb_cur_max_func -___setlc_active_func -___unguarded_readlc_active_add_func -__argc -__argv -__badioinfo -__crtCompareStringA -__crtCompareStringW -__crtGetLocaleInfoW -__crtGetStringTypeW -__crtLCMapStringA -__crtLCMapStringW -__daylight -__dllonexit -__doserrno -__dstbias -__fpecode -__getmainargs -__initenv -__iob_func -__isascii -__iscsym -__iscsymf -__lc_codepage -__lc_collate_cp -__lc_handle -__lconv_init -__libm_sse2_acos -__libm_sse2_acosf -__libm_sse2_asin -__libm_sse2_asinf -__libm_sse2_atan -__libm_sse2_atan2 -__libm_sse2_atanf -__libm_sse2_cos -__libm_sse2_cosf -__libm_sse2_exp -__libm_sse2_expf -__libm_sse2_log -__libm_sse2_log10 -__libm_sse2_log10f -__libm_sse2_logf -__libm_sse2_pow -__libm_sse2_powf -__libm_sse2_sin -__libm_sse2_sinf -__libm_sse2_tan -__libm_sse2_tanf -__mb_cur_max -__p___argc -__p___argv -__p___initenv -__p___mb_cur_max -__p___wargv -__p___winitenv -__p__acmdln -__p__amblksiz -__p__commode -__p__daylight -__p__dstbias -__p__environ -__p__fileinfo -__p__fmode -__p__iob -__p__mbcasemap -__p__mbctype -__p__osver -__p__pctype -__p__pgmptr -__p__pwctype -__p__timezone -__p__tzname -__p__wcmdln -__p__wenviron -__p__winmajor -__p__winminor -__p__winver -__p__wpgmptr -__pctype_func -__pioinfo -__pwctype_func -__pxcptinfoptrs -__set_app_type -__setlc_active -__setusermatherr -__strncnt -__threadhandle -__threadid -__toascii -__unDName -__unDNameEx -__uncaught_exception -__unguarded_readlc_active -__wargv -__wcserror -__wcserror_s -__wcsncnt -__wgetmainargs -__winitenv -_abnormal_termination -_abs64 -_access -_access_s -_acmdln -_adj_fdiv_m16i -_adj_fdiv_m32 -_adj_fdiv_m32i -_adj_fdiv_m64 -_adj_fdiv_r -_adj_fdivr_m16i -_adj_fdivr_m32 -_adj_fdivr_m32i -_adj_fdivr_m64 -_adj_fpatan -_adj_fprem -_adj_fprem1 -_adj_fptan -_adjust_fdiv -_aexit_rtn -_aligned_free -_aligned_free_dbg -_aligned_malloc -_aligned_malloc_dbg -_aligned_offset_malloc -_aligned_offset_malloc_dbg -_aligned_offset_realloc -_aligned_offset_realloc_dbg -_aligned_realloc -_aligned_realloc_dbg -_amsg_exit -_assert -_atodbl -_atodbl_l -_atof_l -_atoflt_l -_atoi64 -_atoi64_l -_atoi_l -_atol_l -_atoldbl -_atoldbl_l -_beep -_beginthread -_beginthreadex -_c_exit -_cabs -_callnewh -_calloc_dbg -_cexit -_cgets -_cgets_s -_cgetws -_cgetws_s -_chdir -_chdrive -_chgsign -_chkesp -_chmod -_chsize -_chsize_s -_chvalidator -_chvalidator_l -_clearfp -_close -_commit -_commode -_control87 -_controlfp -_controlfp_s -_copysign -_cprintf -_cprintf_l -_cprintf_p -_cprintf_p_l -_cprintf_s -_cprintf_s_l -_cputs -_cputws -_creat -_crtAssertBusy -_crtBreakAlloc -_crtDbgFlag -_cscanf -_cscanf_l -_cscanf_s -_cscanf_s_l -_ctime32 -_ctime32_s -_ctime64 -_ctime64_s -_ctype -_cwait -_cwprintf -_cwprintf_l -_cwprintf_p -_cwprintf_p_l -_cwprintf_s -_cwprintf_s_l -_cwscanf -_cwscanf_l -_cwscanf_s -_cwscanf_s_l -_daylight -_difftime32 -_difftime64 -_dstbias -_dup -_dup2 -_ecvt -_ecvt_s -_endthread -_endthreadex -_environ -_eof -_errno -_except_handler2 -_except_handler3 -_except_handler4_common -_execl -_execle -_execlp -_execlpe -_execv -_execve -_execvp -_execvpe -_exit -_expand -_expand_dbg -_fcloseall -_fcvt -_fcvt_s -_fdopen -_fgetchar -_fgetwchar -_filbuf -_fileinfo -_filelength -_filelengthi64 -_fileno -_findclose -_findfirst -_findfirst64 -_findfirsti64 -_findnext -_findnext64 -_findnexti64 -_finite -_flsbuf -_flushall -_fmode -_fpclass -_fpieee_flt -_fpreset -_fprintf_l -_fprintf_p -_fprintf_p_l -_fprintf_s_l -_fputchar -_fputwchar -_free_dbg -_freea -_freea_s -_fscanf_l -_fscanf_s_l -_fseeki64 -_fsopen -_fstat -_fstat64 -_fstati64 -_ftime -_ftime32 -_ftime32_s -_ftime64 -_ftime64_s -_ftol -_ftol2 -_ftol2_sse -_ftol2_sse_excpt -_fullpath -_fullpath_dbg -_futime -_futime32 -_futime64 -_fwprintf_l -_fwprintf_p -_fwprintf_p_l -_fwprintf_s_l -_fwscanf_l -_fwscanf_s_l -_gcvt -_gcvt_s -_get_doserrno -_get_environ -_get_errno -_get_fileinfo -_get_fmode -_get_heap_handle -_get_osfhandle -_get_osplatform -_get_osver -_get_output_format -_get_pgmptr -_get_sbh_threshold -_get_wenviron -_get_winmajor -_get_winminor -_get_winver -_get_wpgmptr -_getch -_getche -_getcwd -_getdcwd -_getdiskfree -_getdllprocaddr -_getdrive -_getdrives -_getmaxstdio -_getmbcp -_getpid -_getsystime -_getw -_getwch -_getwche -_getws -_global_unwind2 -_gmtime32 -_gmtime32_s -_gmtime64 -_gmtime64_s -_heapadd -_heapchk -_heapmin -_heapset -_heapused -_heapwalk -_hypot -_i64toa -_i64toa_s -_i64tow -_i64tow_s -_initterm -_initterm_e -_inp -_inpd -_inpw -_invalid_parameter -_iob -_isalnum_l -_isalpha_l -_isatty -_iscntrl_l -_isctype -_isctype_l -_isdigit_l -_isgraph_l -_isleadbyte_l -_islower_l -_ismbbalnum -_ismbbalnum_l -_ismbbalpha -_ismbbalpha_l -_ismbbgraph -_ismbbgraph_l -_ismbbkalnum -_ismbbkalnum_l -_ismbbkana -_ismbbkana_l -_ismbbkprint -_ismbbkprint_l -_ismbbkpunct -_ismbbkpunct_l -_ismbblead -_ismbblead_l -_ismbbprint -_ismbbprint_l -_ismbbpunct -_ismbbpunct_l -_ismbbtrail -_ismbbtrail_l -_ismbcalnum -_ismbcalnum_l -_ismbcalpha -_ismbcalpha_l -_ismbcdigit -_ismbcdigit_l -_ismbcgraph -_ismbcgraph_l -_ismbchira -_ismbchira_l -_ismbckata -_ismbckata_l -_ismbcl0 -_ismbcl0_l -_ismbcl1 -_ismbcl1_l -_ismbcl2 -_ismbcl2_l -_ismbclegal -_ismbclegal_l -_ismbclower -_ismbclower_l -_ismbcprint -_ismbcprint_l -_ismbcpunct -_ismbcpunct_l -_ismbcspace -_ismbcspace_l -_ismbcsymbol -_ismbcsymbol_l -_ismbcupper -_ismbcupper_l -_ismbslead -_ismbslead_l -_ismbstrail -_ismbstrail_l -_isnan -_isprint_l -_isspace_l -_isupper_l -_iswalnum_l -_iswalpha_l -_iswcntrl_l -_iswctype_l -_iswdigit_l -_iswgraph_l -_iswlower_l -_iswprint_l -_iswpunct_l -_iswspace_l -_iswupper_l -_iswxdigit_l -_isxdigit_l -_itoa -_itoa_s -_itow -_itow_s -_j0 -_j1 -_jn -_kbhit -_lfind -_lfind_s -_loaddll -_local_unwind2 -_local_unwind4 -_localtime32 -_localtime32_s -_localtime64 -_localtime64_s -_lock -_locking -_logb -_longjmpex -_lrotl -_lrotr -_lsearch -_lsearch_s -_lseek -_lseeki64 -_ltoa -_ltoa_s -_ltow -_ltow_s -_makepath -_makepath_s -_malloc_dbg -_mbbtombc -_mbbtombc_l -_mbbtype -_mbcasemap -_mbccpy -_mbccpy_l -_mbccpy_s -_mbccpy_s_l -_mbcjistojms -_mbcjistojms_l -_mbcjmstojis -_mbcjmstojis_l -_mbclen -_mbclen_l -_mbctohira -_mbctohira_l -_mbctokata -_mbctokata_l -_mbctolower -_mbctolower_l -_mbctombb -_mbctombb_l -_mbctoupper -_mbctoupper_l -_mbctype -_mblen_l -_mbsbtype -_mbsbtype_l -_mbscat -_mbscat_s -_mbscat_s_l -_mbschr -_mbschr_l -_mbscmp -_mbscmp_l -_mbscoll -_mbscoll_l -_mbscpy -_mbscpy_s -_mbscpy_s_l -_mbscspn -_mbscspn_l -_mbsdec -_mbsdec_l -_mbsdup -_mbsicmp -_mbsicmp_l -_mbsicoll -_mbsicoll_l -_mbsinc -_mbsinc_l -_mbslen -_mbslen_l -_mbslwr -_mbslwr_l -_mbslwr_s -_mbslwr_s_l -_mbsnbcat -_mbsnbcat_l -_mbsnbcat_s -_mbsnbcat_s_l -_mbsnbcmp -_mbsnbcmp_l -_mbsnbcnt -_mbsnbcnt_l -_mbsnbcoll -_mbsnbcoll_l -_mbsnbcpy -_mbsnbcpy_l -_mbsnbcpy_s -_mbsnbcpy_s_l -_mbsnbicmp -_mbsnbicmp_l -_mbsnbicoll -_mbsnbicoll_l -_mbsnbset -_mbsnbset_l -_mbsnbset_s -_mbsnbset_s_l -_mbsncat -_mbsncat_l -_mbsncat_s -_mbsncat_s_l -_mbsnccnt -_mbsnccnt_l -_mbsncmp -_mbsncmp_l -_mbsncoll -_mbsncoll_l -_mbsncpy -_mbsncpy_l -_mbsncpy_s -_mbsncpy_s_l -_mbsnextc -_mbsnextc_l -_mbsnicmp -_mbsnicmp_l -_mbsnicoll -_mbsnicoll_l -_mbsninc -_mbsninc_l -_mbsnlen -_mbsnlen_l -_mbsnset -_mbsnset_l -_mbsnset_s -_mbsnset_s_l -_mbspbrk -_mbspbrk_l -_mbsrchr -_mbsrchr_l -_mbsrev -_mbsrev_l -_mbsset -_mbsset_l -_mbsset_s -_mbsset_s_l -_mbsspn -_mbsspn_l -_mbsspnp -_mbsspnp_l -_mbsstr -_mbsstr_l -_mbstok -_mbstok_l -_mbstok_s -_mbstok_s_l -_mbstowcs_l -_mbstowcs_s_l -_mbstrlen -_mbstrlen_l -_mbstrnlen -_mbstrnlen_l -_mbsupr -_mbsupr_l -_mbsupr_s -_mbsupr_s_l -_mbtowc_l -_memccpy -_memicmp -_memicmp_l -_mkdir -_mkgmtime -_mkgmtime32 -_mkgmtime64 -_mktemp -_mktemp_s -_mktime32 -_mktime64 -_msize -_msize_debug -_nextafter -_onexit -_open -_open_osfhandle -_osplatform -_osver -_outp -_outpd -_outpw -_pclose -_pctype -_pgmptr -_pipe -_popen -_printf_l -_printf_p -_printf_p_l -_printf_s_l -_purecall -_putch -_putenv -_putenv_s -_putw -_putwch -_putws -_pwctype -_read -_realloc_dbg -_resetstkoflw -_rmdir -_rmtmp -_rotl -_rotl64 -_rotr -_rotr64 -_safe_fdiv -_safe_fdivr -_safe_fprem -_safe_fprem1 -_scalb -_scanf_l -_scanf_s_l -_scprintf -_scprintf_l -_scprintf_p_l -_scwprintf -_scwprintf_l -_scwprintf_p_l -_searchenv -_searchenv_s -_seh_longjmp_unwind -_seh_longjmp_unwind4 -_set_SSE2_enable -_set_controlfp -_set_doserrno -_set_errno -_set_error_mode -_set_fileinfo -_set_fmode -_set_output_format -_set_sbh_threshold -_seterrormode -_setjmp -_setjmp3 -_setmaxstdio -_setmbcp -_setmode -_setsystime -_sleep -_snprintf -_snprintf_c -_snprintf_c_l -_snprintf_l -_snprintf_s -_snprintf_s_l -_snscanf -_snscanf_l -_snscanf_s -_snscanf_s_l -_snwprintf -_snwprintf_l -_snwprintf_s -_snwprintf_s_l -_snwscanf -_snwscanf_l -_snwscanf_s -_snwscanf_s_l -_sopen -_sopen_s -_spawnl -_spawnle -_spawnlp -_spawnlpe -_spawnv -_spawnve -_spawnvp -_spawnvpe -_splitpath -_splitpath_s -_sprintf_l -_sprintf_p_l -_sprintf_s_l -_sscanf_l -_sscanf_s_l -_stat -_stat64 -_stati64 -_statusfp -_strcmpi -_strcoll_l -_strdate -_strdate_s -_strdup -_strdup_dbg -_strerror -_strerror_s -_stricmp -_stricmp_l -_stricoll -_stricoll_l -_strlwr -_strlwr_l -_strlwr_s -_strlwr_s_l -_strncoll -_strncoll_l -_strnicmp -_strnicmp_l -_strnicoll -_strnicoll_l -_strnset -_strnset_s -_strrev -_strset -_strset_s -_strtime -_strtime_s -_strtod_l -_strtoi64 -_strtoi64_l -_strtol_l -_strtoui64 -_strtoui64_l -_strtoul_l -_strupr -_strupr_l -_strupr_s -_strupr_s_l -_strxfrm_l -_swab -_swprintf -_swprintf_c -_swprintf_c_l -_swprintf_p_l -_swprintf_s_l -_swscanf_l -_swscanf_s_l -_sys_errlist -_sys_nerr -_tell -_telli64 -_tempnam -_tempnam_dbg -_time32 -_time64 -_timezone -_tolower -_tolower_l -_toupper -_toupper_l -_towlower_l -_towupper_l -_tzname -_tzset -_ui64toa -_ui64toa_s -_ui64tow -_ui64tow_s -_ultoa -_ultoa_s -_ultow -_ultow_s -_umask -_umask_s -_ungetch -_ungetwch -_unlink -_unloaddll -_unlock -_utime -_utime32 -_utime64 -_vcprintf -_vcprintf_l -_vcprintf_p -_vcprintf_p_l -_vcprintf_s -_vcprintf_s_l -_vcwprintf -_vcwprintf_l -_vcwprintf_p -_vcwprintf_p_l -_vcwprintf_s -_vcwprintf_s_l -_vfprintf_l -_vfprintf_p -_vfprintf_p_l -_vfprintf_s_l -_vfwprintf_l -_vfwprintf_p -_vfwprintf_p_l -_vfwprintf_s_l -_vprintf_l -_vprintf_p -_vprintf_p_l -_vprintf_s_l -_vscprintf -_vscprintf_l -_vscprintf_p_l -_vscwprintf -_vscwprintf_l -_vscwprintf_p_l -_vsnprintf -_vsnprintf_c -_vsnprintf_c_l -_vsnprintf_l -_vsnprintf_s -_vsnprintf_s_l -_vsnwprintf -_vsnwprintf_l -_vsnwprintf_s -_vsnwprintf_s_l -_vsprintf_l -_vsprintf_p -_vsprintf_p_l -_vsprintf_s_l -_vswprintf -_vswprintf_c -_vswprintf_c_l -_vswprintf_l -_vswprintf_p_l -_vswprintf_s_l -_vwprintf_l -_vwprintf_p -_vwprintf_p_l -_vwprintf_s_l -_waccess -_waccess_s -_wasctime -_wasctime_s -_wassert -_wchdir -_wchmod -_wcmdln -_wcreat -_wcscoll_l -_wcsdup -_wcsdup_dbg -_wcserror -_wcserror_s -_wcsftime_l -_wcsicmp -_wcsicmp_l -_wcsicoll -_wcsicoll_l -_wcslwr -_wcslwr_l -_wcslwr_s -_wcslwr_s_l -_wcsncoll -_wcsncoll_l -_wcsnicmp -_wcsnicmp_l -_wcsnicoll -_wcsnicoll_l -_wcsnset -_wcsnset_s -_wcsrev -_wcsset -_wcsset_s -_wcstoi64 -_wcstoi64_l -_wcstol_l -_wcstombs_l -_wcstombs_s_l -_wcstoui64 -_wcstoui64_l -_wcstoul_l -_wcsupr -_wcsupr_l -_wcsupr_s -_wcsupr_s_l -_wcsxfrm_l -_wctime -_wctime32 -_wctime32_s -_wctime64 -_wctime64_s -_wctomb_l -_wctomb_s_l -_wctype -_wenviron -_wexecl -_wexecle -_wexeclp -_wexeclpe -_wexecv -_wexecve -_wexecvp -_wexecvpe -_wfdopen -_wfindfirst -_wfindfirst64 -_wfindfirsti64 -_wfindnext -_wfindnext64 -_wfindnexti64 -_wfopen -_wfopen_s -_wfreopen -_wfreopen_s -_wfsopen -_wfullpath -_wfullpath_dbg -_wgetcwd -_wgetdcwd -_wgetenv -_wgetenv_s -_winmajor -_winminor -_winput_s -_winver -_wmakepath -_wmakepath_s -_wmkdir -_wmktemp -_wmktemp_s -_wopen -_woutput_s -_wperror -_wpgmptr -_wpopen -_wprintf_l -_wprintf_p -_wprintf_p_l -_wprintf_s_l -_wputenv -_wputenv_s -_wremove -_wrename -_write -_wrmdir -_wscanf_l -_wscanf_s_l -_wsearchenv -_wsearchenv_s -_wsetlocale -_wsopen -_wsopen_s -_wspawnl -_wspawnle -_wspawnlp -_wspawnlpe -_wspawnv -_wspawnve -_wspawnvp -_wspawnvpe -_wsplitpath -_wsplitpath_s -_wstat -_wstat64 -_wstati64 -_wstrdate -_wstrdate_s -_wstrtime -_wstrtime_s -_wsystem -_wtempnam -_wtempnam_dbg -_wtmpnam -_wtmpnam_s -_wtof -_wtof_l -_wtoi -_wtoi64 -_wtoi64_l -_wtoi_l -_wtol -_wtol_l -_wunlink -_wutime -_wutime32 -_wutime64 -_y0 -_y1 -_yn -abort -abs -acos -asctime -asctime_s -asin -atan -atan2 -atexit -atof -atoi -atol -bsearch -bsearch_s -btowc -calloc -ceil -clearerr -clearerr_s -clock -cos -cosh -ctime -difftime -div -exit -exp -fabs -fclose -feof -ferror -fflush -fgetc -fgetpos -fgets -fgetwc -fgetws -floor -fmod -fopen -fopen_s -fprintf -fprintf_s -fputc -fputs -fputwc -fputws -fread -free -freopen -freopen_s -frexp -fscanf -fscanf_s -fseek -fsetpos -ftell -fwprintf -fwprintf_s -fwrite -fwscanf -fwscanf_s -getc -getchar -getenv -getenv_s -gets -getwc -getwchar -gmtime -is_wctype -isalnum -isalpha -iscntrl -isdigit -isgraph -isleadbyte -islower -isprint -ispunct -isspace -isupper -iswalnum -iswalpha -iswascii -iswcntrl -iswctype -iswdigit -iswgraph -iswlower -iswprint -iswpunct -iswspace -iswupper -iswxdigit -isxdigit -labs -ldexp -ldiv -localeconv -localtime -log -log10 -longjmp -malloc -mblen -mbrlen -mbrtowc -mbsdup_dbg -mbsrtowcs -mbsrtowcs_s -mbstowcs -mbstowcs_s -mbtowc -memchr -memcmp -memcpy -memcpy_s -memmove -memmove_s -memset -mktime -modf -perror -pow -printf -printf_s -putc -putchar -puts -putwc -putwchar -qsort -qsort_s -raise -rand -rand_s -realloc -remove -rename -rewind -scanf -scanf_s -setbuf -setlocale -setvbuf -signal -sin -sinh -sprintf -sprintf_s -sqrt -srand -sscanf -sscanf_s -strcat -strcat_s -strchr -strcmp -strcoll -strcpy -strcpy_s -strcspn -strerror -strerror_s -strftime -strlen -strncat -strncat_s -strncmp -strncpy -strncpy_s -strnlen -strpbrk -strrchr -strspn -strstr -strtod -strtok -strtok_s -strtol -strtoul -strxfrm -swprintf -swprintf_s -swscanf -swscanf_s -system -tan -tanh -time -tmpfile -tmpfile_s -tmpnam -tmpnam_s -tolower -toupper -towlower -towupper -ungetc -ungetwc -utime -vfprintf -vfprintf_s -vfwprintf -vfwprintf_s -vprintf -vprintf_s -vsnprintf -vsprintf -vsprintf_s -vswprintf -vswprintf_s -vwprintf -vwprintf_s -wcrtomb -wcrtomb_s -wcscat -wcscat_s -wcschr -wcscmp -wcscoll -wcscpy -wcscpy_s -wcscspn -wcsftime -wcslen -wcsncat -wcsncat_s -wcsncmp -wcsncpy -wcsncpy_s -wcsnlen -wcspbrk -wcsrchr -wcsrtombs -wcsrtombs_s -wcsspn -wcsstr -wcstod -wcstok -wcstok_s -wcstol -wcstombs -wcstombs_s -wcstoul -wcsxfrm -wctob -wctomb -wctomb_s -wprintf -wprintf_s -wscanf -wscanf_s diff --git a/tinyc/win32/lib/user32.def b/tinyc/win32/lib/user32.def deleted file mode 100644 index a034dac20..000000000 --- a/tinyc/win32/lib/user32.def +++ /dev/null @@ -1,658 +0,0 @@ -LIBRARY user32.dll - -EXPORTS -ActivateKeyboardLayout -AdjustWindowRect -AdjustWindowRectEx -AlignRects -AllowSetForegroundWindow -AnimateWindow -AnyPopup -AppendMenuA -AppendMenuW -ArrangeIconicWindows -AttachThreadInput -BeginDeferWindowPos -BeginPaint -BlockInput -BringWindowToTop -BroadcastSystemMessage -BroadcastSystemMessageA -BroadcastSystemMessageW -CalcChildScroll -CallMsgFilter -CallMsgFilterA -CallMsgFilterW -CallNextHookEx -CallWindowProcA -CallWindowProcW -CascadeChildWindows -CascadeWindows -ChangeClipboardChain -ChangeDisplaySettingsA -ChangeDisplaySettingsExA -ChangeDisplaySettingsExW -ChangeDisplaySettingsW -ChangeMenuA -ChangeMenuW -CharLowerA -CharLowerBuffA -CharLowerBuffW -CharLowerW -CharNextA -CharNextExA -CharNextExW -CharNextW -CharPrevA -CharPrevExA -CharPrevExW -CharPrevW -CharToOemA -CharToOemBuffA -CharToOemBuffW -CharToOemW -CharUpperA -CharUpperBuffA -CharUpperBuffW -CharUpperW -CheckDlgButton -CheckMenuItem -CheckMenuRadioItem -CheckRadioButton -ChildWindowFromPoint -ChildWindowFromPointEx -ClientThreadConnect -ClientToScreen -ClipCursor -CloseClipboard -CloseDesktop -CloseWindow -CloseWindowStation -CopyAcceleratorTableA -CopyAcceleratorTableW -CopyIcon -CopyImage -CopyRect -CountClipboardFormats -CreateAcceleratorTableA -CreateAcceleratorTableW -CreateCaret -CreateCursor -CreateDesktopA -CreateDesktopW -CreateDialogIndirectParamA -CreateDialogIndirectParamW -CreateDialogParamA -CreateDialogParamW -CreateIcon -CreateIconFromResource -CreateIconFromResourceEx -CreateIconIndirect -CreateMDIWindowA -CreateMDIWindowW -CreateMenu -CreatePopupMenu -CreateWindowExA -CreateWindowExW -CreateWindowStationA -CreateWindowStationW -DdeAbandonTransaction -DdeAccessData -DdeAddData -DdeClientTransaction -DdeCmpStringHandles -DdeConnect -DdeConnectList -DdeCreateDataHandle -DdeCreateStringHandleA -DdeCreateStringHandleW -DdeDisconnect -DdeDisconnectList -DdeEnableCallback -DdeFreeDataHandle -DdeFreeStringHandle -DdeGetData -DdeGetLastError -DdeImpersonateClient -DdeInitializeA -DdeInitializeW -DdeKeepStringHandle -DdeNameService -DdePostAdvise -DdeQueryConvInfo -DdeQueryNextServer -DdeQueryStringA -DdeQueryStringW -DdeReconnect -DdeSetQualityOfService -DdeSetUserHandle -DdeUnaccessData -DdeUninitialize -DefDlgProcA -DefDlgProcW -DefFrameProcA -DefFrameProcW -DefMDIChildProcA -DefMDIChildProcW -DefWindowProcA -DefWindowProcW -DeferWindowPos -DeleteMenu -DestroyAcceleratorTable -DestroyCaret -DestroyCursor -DestroyIcon -DestroyMenu -DestroyWindow -DialogBoxIndirectParamA -DialogBoxIndirectParamW -DialogBoxParamA -DialogBoxParamW -DispatchMessageA -DispatchMessageW -DlgDirListA -DlgDirListComboBoxA -DlgDirListComboBoxW -DlgDirListW -DlgDirSelectComboBoxExA -DlgDirSelectComboBoxExW -DlgDirSelectExA -DlgDirSelectExW -DragDetect -DragObject -DrawAnimatedRects -DrawCaption -DrawCaptionTempA -DrawCaptionTempW -DrawEdge -DrawFocusRect -DrawFrame -DrawFrameControl -DrawIcon -DrawIconEx -DrawMenuBar -DrawMenuBarTemp -DrawStateA -DrawStateW -DrawTextA -DrawTextExA -DrawTextExW -DrawTextW -EditWndProc -EmptyClipboard -EnableMenuItem -EnableScrollBar -EnableWindow -EndDeferWindowPos -EndDialog -EndMenu -EndPaint -EndTask -EnumChildWindows -EnumClipboardFormats -EnumDesktopWindows -EnumDesktopsA -EnumDesktopsW -EnumDisplayDevicesA -EnumDisplayDevicesW -EnumDisplayMonitors -EnumDisplaySettingsA -EnumDisplaySettingsExA -EnumDisplaySettingsExW -EnumDisplaySettingsW -EnumPropsA -EnumPropsExA -EnumPropsExW -EnumPropsW -EnumThreadWindows -EnumWindowStationsA -EnumWindowStationsW -EnumWindows -EqualRect -ExcludeUpdateRgn -ExitWindowsEx -FillRect -FindWindowA -FindWindowExA -FindWindowExW -FindWindowW -FlashWindow -FlashWindowEx -FrameRect -FreeDDElParam -GetActiveWindow -GetAltTabInfo -GetAncestor -GetAsyncKeyState -GetCapture -GetCaretBlinkTime -GetCaretPos -GetClassInfoA -GetClassInfoExA -GetClassInfoExW -GetClassInfoW -GetClassLongA -GetClassLongW -GetClassNameA -GetClassNameW -GetClassWord -GetClientRect -GetClipCursor -GetClipboardData -GetClipboardFormatNameA -GetClipboardFormatNameW -GetClipboardOwner -GetClipboardSequenceNumber -GetClipboardViewer -GetComboBoxInfo -GetCursor -GetCursorInfo -GetCursorPos -GetDC -GetDCEx -GetDesktopWindow -GetDialogBaseUnits -GetDlgCtrlID -GetDlgItem -GetDlgItemInt -GetDlgItemTextA -GetDlgItemTextW -GetDoubleClickTime -GetFocus -GetForegroundWindow -GetGUIThreadInfo -GetGuiResources -GetIconInfo -GetInputDesktop -GetInputState -GetInternalWindowPos -GetKBCodePage -GetKeyNameTextA -GetKeyNameTextW -GetKeyState -GetKeyboardLayout -GetKeyboardLayoutList -GetKeyboardLayoutNameA -GetKeyboardLayoutNameW -GetKeyboardState -GetKeyboardType -GetLastActivePopup -GetListBoxInfo -GetMenu -GetMenuBarInfo -GetMenuCheckMarkDimensions -GetMenuContextHelpId -GetMenuDefaultItem -GetMenuInfo -GetMenuItemCount -GetMenuItemID -GetMenuItemInfoA -GetMenuItemInfoW -GetMenuItemRect -GetMenuState -GetMenuStringA -GetMenuStringW -GetMessageA -GetMessageExtraInfo -GetMessagePos -GetMessageTime -GetMessageW -GetMonitorInfoA -GetMonitorInfoW -GetMouseMovePoints -GetMouseMovePointsEx -GetNextDlgGroupItem -GetNextDlgTabItem -GetNextQueueWindow -GetOpenClipboardWindow -GetParent -GetPriorityClipboardFormat -GetProcessDefaultLayout -GetProcessWindowStation -GetPropA -GetPropW -GetQueueStatus -GetScrollBarInfo -GetScrollInfo -GetScrollPos -GetScrollRange -GetShellWindow -GetSubMenu -GetSysColor -GetSysColorBrush -GetSystemMenu -GetSystemMetrics -GetTabbedTextExtentA -GetTabbedTextExtentW -GetThreadDesktop -GetTitleBarInfo -GetTopWindow -GetUpdateRect -GetUpdateRgn -GetUserObjectInformationA -GetUserObjectInformationW -GetUserObjectSecurity -GetWindow -GetWindowContextHelpId -GetWindowDC -GetWindowInfo -GetWindowLongPtrA -GetWindowLongPtrW -SetWindowLongPtrA -SetWindowLongPtrW -GetWindowLongA -GetWindowLongW -GetWindowModuleFileNameA -GetWindowModuleFileNameW -GetWindowPlacement -GetWindowRect -GetWindowRgn -GetWindowTextA -GetWindowTextLengthA -GetWindowTextLengthW -GetWindowTextW -GetWindowThreadProcessId -GetWindowWord -GrayStringA -GrayStringW -HasSystemSleepStarted -HideCaret -HiliteMenuItem -IMPGetIMEA -IMPGetIMEW -IMPQueryIMEA -IMPQueryIMEW -IMPSetIMEA -IMPSetIMEW -ImpersonateDdeClientWindow -InSendMessage -InSendMessageEx -InflateRect -InitSharedTable -InitTask -InsertMenuA -InsertMenuItemA -InsertMenuItemW -InsertMenuW -InternalGetWindowText -IntersectRect -InvalidateRect -InvalidateRgn -InvertRect -IsCharAlphaA -IsCharAlphaNumericA -IsCharAlphaNumericW -IsCharAlphaW -IsCharLowerA -IsCharLowerW -IsCharUpperA -IsCharUpperW -IsChild -IsClipboardFormatAvailable -IsDialogMessage -IsDialogMessageA -IsDialogMessageW -IsDlgButtonChecked -IsHungThread -IsIconic -IsMenu -IsRectEmpty -IsWindow -IsWindowEnabled -IsWindowUnicode -IsWindowVisible -IsZoomed -KillTimer -LoadAcceleratorsA -LoadAcceleratorsW -LoadBitmapA -LoadBitmapW -LoadCursorA -LoadCursorFromFileA -LoadCursorFromFileW -LoadCursorW -LoadIconA -LoadIconW -LoadImageA -LoadImageW -LoadKeyboardLayoutA -LoadKeyboardLayoutW -LoadMenuA -LoadMenuIndirectA -LoadMenuIndirectW -LoadMenuW -LoadStringA -LoadStringW -LockSetForegroundWindow -LockWindowStation -LockWindowUpdate -LookupIconIdFromDirectory -LookupIconIdFromDirectoryEx -MapDialogRect -MapVirtualKeyA -MapVirtualKeyExA -MapVirtualKeyExW -MapVirtualKeyW -MapWindowPoints -MenuItemFromPoint -MessageBeep -MessageBoxA -MessageBoxExA -MessageBoxExW -MessageBoxIndirectA -MessageBoxIndirectW -MessageBoxW -ModifyAccess -ModifyMenuA -ModifyMenuW -MonitorFromPoint -MonitorFromRect -MonitorFromWindow -MoveWindow -MsgWaitForMultipleObjects -MsgWaitForMultipleObjectsEx -NotifyWinEvent -OemKeyScan -OemToCharA -OemToCharBuffA -OemToCharBuffW -OemToCharW -OffsetRect -OpenClipboard -OpenDesktopA -OpenDesktopW -OpenIcon -OpenInputDesktop -OpenWindowStationA -OpenWindowStationW -PackDDElParam -PaintDesktop -PeekMessageA -PeekMessageW -PlaySoundEvent -PostMessageA -PostMessageW -PostQuitMessage -PostThreadMessageA -PostThreadMessageW -PtInRect -RealChildWindowFromPoint -RealGetWindowClass -RedrawWindow -RegisterClassA -RegisterClassExA -RegisterClassExW -RegisterClassW -RegisterClipboardFormatA -RegisterClipboardFormatW -RegisterDeviceNotificationA -RegisterDeviceNotificationW -RegisterHotKey -RegisterLogonProcess -RegisterNetworkCapabilities -RegisterSystemThread -RegisterTasklist -RegisterWindowMessageA -RegisterWindowMessageW -ReleaseCapture -ReleaseDC -RemoveMenu -RemovePropA -RemovePropW -ReplyMessage -ReuseDDElParam -ScreenToClient -ScrollDC -ScrollWindow -ScrollWindowEx -SendDlgItemMessageA -SendDlgItemMessageW -SendIMEMessageExA -SendIMEMessageExW -SendInput -SendMessageA -SendMessageCallbackA -SendMessageCallbackW -SendMessageTimeoutA -SendMessageTimeoutW -SendMessageW -SendNotifyMessageA -SendNotifyMessageW -SetActiveWindow -SetCapture -SetCaretBlinkTime -SetCaretPos -SetClassLongA -SetClassLongW -SetClassWord -SetClipboardData -SetClipboardViewer -SetCursor -SetCursorPos -SetDebugErrorLevel -SetDeskWallpaper -SetDesktopBitmap -SetDlgItemInt -SetDlgItemTextA -SetDlgItemTextW -SetDoubleClickTime -SetFocus -SetForegroundWindow -SetInternalWindowPos -SetKeyboardState -SetLastErrorEx -SetLogonNotifyWindow -SetMenu -SetMenuContextHelpId -SetMenuDefaultItem -SetMenuInfo -SetMenuItemBitmaps -SetMenuItemInfoA -SetMenuItemInfoW -SetMessageExtraInfo -SetMessageQueue -SetParent -SetProcessDefaultLayout -SetProcessWindowStation -SetPropA -SetPropW -SetRect -SetRectEmpty -SetScrollInfo -SetScrollPos -SetScrollRange -SetShellWindow -SetSysColors -SetSysColorsTemp -SetSystemCursor -SetThreadDesktop -SetTimer -SetUserObjectInformationA -SetUserObjectInformationW -SetUserObjectSecurity -SetWinEventHook -SetWindowContextHelpId -SetWindowFullScreenState -SetWindowLongA -SetWindowLongW -SetWindowPlacement -SetWindowPos -SetWindowRgn -SetWindowTextA -SetWindowTextW -SetWindowWord -SetWindowsHookA -SetWindowsHookExA -SetWindowsHookExW -SetWindowsHookW -ShowCaret -ShowCursor -ShowOwnedPopups -ShowScrollBar -ShowWindow -ShowWindowAsync -SubtractRect -SwapMouseButton -SwitchDesktop -SwitchToThisWindow -SysErrorBox -SystemParametersInfoA -SystemParametersInfoW -TabbedTextOutA -TabbedTextOutW -TileChildWindows -TileWindows -ToAscii -ToAsciiEx -ToUnicode -ToUnicodeEx -TrackMouseEvent -TrackPopupMenu -TrackPopupMenuEx -TranslateAccelerator -TranslateAcceleratorA -TranslateAcceleratorW -TranslateMDISysAccel -TranslateMessage -UnhookWinEvent -UnhookWindowsHook -UnhookWindowsHookEx -UnionRect -UnloadKeyboardLayout -UnlockWindowStation -UnpackDDElParam -UnregisterClassA -UnregisterClassW -UnregisterDeviceNotification -UnregisterHotKey -UpdateWindow -UserClientDllInitialize -UserIsSystemResumeAutomatic -UserSetDeviceHoldState -UserSignalProc -UserTickleTimer -ValidateRect -ValidateRgn -VkKeyScanA -VkKeyScanExA -VkKeyScanExW -VkKeyScanW -WINNLSEnableIME -WINNLSGetEnableStatus -WINNLSGetIMEHotkey -WNDPROC_CALLBACK -WaitForInputIdle -WaitMessage -WinHelpA -WinHelpW -WinOldAppHackoMatic -WindowFromDC -WindowFromPoint -YieldTask -_SetProcessDefaultLayout -keybd_event -mouse_event -wsprintfA -wsprintfW -wvsprintfA -wvsprintfW diff --git a/tinyc/win32/lib/wincrt1.c b/tinyc/win32/lib/wincrt1.c deleted file mode 100644 index ce3a63f13..000000000 --- a/tinyc/win32/lib/wincrt1.c +++ /dev/null @@ -1,75 +0,0 @@ -//+--------------------------------------------------------------------------- - -// _UNICODE for tchar.h, UNICODE for API -#include - -#include -#include - -#define __UNKNOWN_APP 0 -#define __CONSOLE_APP 1 -#define __GUI_APP 2 -void __set_app_type(int); -void _controlfp(unsigned a, unsigned b); - -#ifdef _UNICODE -#define __tgetmainargs __wgetmainargs -#define _twinstart _wwinstart -#define _runtwinmain _runwwinmain -int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); -#else -#define __tgetmainargs __getmainargs -#define _twinstart _winstart -#define _runtwinmain _runwinmain -#endif - -typedef struct { int newmode; } _startupinfo; -int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*); - -static int go_winmain(TCHAR *arg1) -{ - STARTUPINFO si; - _TCHAR *szCmd, *p; - int fShow; - - GetStartupInfo(&si); - if (si.dwFlags & STARTF_USESHOWWINDOW) - fShow = si.wShowWindow; - else - fShow = SW_SHOWDEFAULT; - - szCmd = NULL, p = GetCommandLine(); - if (arg1) - szCmd = _tcsstr(p, arg1); - if (NULL == szCmd) - szCmd = _tcsdup(__T("")); - else if (szCmd > p && szCmd[-1] == __T('"')) - --szCmd; -#if defined __i386__ || defined __x86_64__ - _controlfp(0x10000, 0x30000); -#endif - return _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow); -} - -int _twinstart(void) -{ - __TRY__ - _startupinfo start_info_con = {0}; - __set_app_type(__GUI_APP); - __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info_con); - exit(go_winmain(__argc > 1 ? __targv[1] : NULL)); -} - -int _runtwinmain(int argc, /* as tcc passed in */ char **argv) -{ -#ifdef UNICODE - _startupinfo start_info = {0}; - __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info); - /* may be wrong when tcc has received wildcards (*.c) */ - if (argc < __argc) - __targv += __argc - argc, __argc = argc; -#else - __argc = argc, __targv = argv; -#endif - return go_winmain(__argc > 1 ? __targv[1] : NULL); -} diff --git a/tinyc/win32/lib/wincrt1w.c b/tinyc/win32/lib/wincrt1w.c deleted file mode 100644 index a7d349e10..000000000 --- a/tinyc/win32/lib/wincrt1w.c +++ /dev/null @@ -1,3 +0,0 @@ -#define _UNICODE 1 -#define UNICODE 1 -#include "wincrt1.c" diff --git a/tinyc/win32/tcc-win32.txt b/tinyc/win32/tcc-win32.txt deleted file mode 100644 index 751a8e074..000000000 --- a/tinyc/win32/tcc-win32.txt +++ /dev/null @@ -1,168 +0,0 @@ - - TinyCC - ====== - - This file contains specific information for usage of TinyCC - under MS-Windows. See tcc-doc.html to have all the features. - - - Installation from the binary ZIP package: - ----------------------------------------- - Unzip the package to a directory of your choice. - - - Set the system PATH: - -------------------- - To be able to invoke the compiler from everywhere on your computer by - just typing "tcc", please add the directory containing tcc.exe to your - system PATH. - - - Include and library search paths - -------------------------------- - On windows, the standard "include" and "lib" directories are searched - relatively from the location of the executables (tcc.exe, libtcc.dll). - - - Examples: - --------- - Open a console window (DOS box) and 'cd' to the examples directory. - - For the 'Fibonacci' example type: - - tcc fib.c - - For the 'Hello Windows' GUI example type: - - tcc hello_win.c - - For the 'Hello DLL' example type - - tcc -shared dll.c - tcc -impdef dll.dll (optional) - tcc hello_dll.c dll.def - - - Using libtcc as JIT compiler in your program - -------------------------------------------- - Check out the 'libtcc_test' example: - - - Running it from source: - tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c - - - Compiling with TCC: - tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def - - - Compiling with MinGW: - gcc examples/libtcc_test.c -I libtcc libtcc.dll -o libtcc_test.exe - - - Compiling with MSVC: - lib /def:libtcc\libtcc.def /out:libtcc.lib - cl /MD examples/libtcc_test.c -I libtcc libtcc.lib - - - Import Definition Files: - ------------------------ - To link with Windows system DLLs, TCC uses import definition - files (.def) instead of libraries. - - The now built-in 'tiny_impdef' program may be used to make - additional .def files for any DLL. For example - - tcc -impdef [-v] opengl32.dll [-o opengl32.def] - - Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at - the TCC commandline to link a program that uses opengl32.dll. - - - Header Files: - ------------- - The system header files (except _mingw.h) are from the MinGW - distribution: - - http://www.mingw.org/ - - From the windows headers, only a minimal set is included. If you need - more, get MinGW's "w32api" package. Extract the files from "include" - into your "tcc/include/winapi" directory. - - - Resource Files: - --------------- - TCC can link windows resources in coff format as generated by MinGW's - windres.exe. For example: - - windres -O coff app.rc -o appres.o - tcc app.c appres.o -o app.exe - - - Tiny Libmaker: - -------------- - The now built-in tiny_libmaker tool by Timovj Lahde can be used as - 'ar' replacement to make a library from several object files: - - tcc -ar [rcsv] library objectfiles ... - - - Compilation from source: - ------------------------ - * You can use the MinGW and MSYS tools available at - http://www.mingw.org - http://www.mingw-w64.org - http://www.msys2.org - - Untar the TCC archive and type in the MSYS shell: - ./configure [--prefix installpath] - make - make install - - The default install location is c:\Program Files\tcc - - Cygwin can be used too with its mingw cross-compiler installed: - ./configure --cross-prefix=i686-w64-mingw32- - (the prefix may vary) - - * Alternatively you can compile TCC with just GCC from MinGW using - > build-tcc.bat (from the win32 directory) - - Also MSVC can be used with the "VSTools Developer Command Prompt": - > build-tcc.bat -c cl - - or with an existing tcc (needs to be in a different directory) - > build-tcc.bat -c some-tcc-dir\tcc.exe - - Also you can copy/install everything into another directory: - > build-tcc.bat -i - - Limitations: - ------------ - - On the object file level, currently TCC supports only the ELF format, - not COFF as used by MinGW and MSVC. It is not possible to exchange - object files or libraries between TCC and these compilers. - - However libraries for TCC from objects by TCC can be made using - tcc -ar lib.a files.o ,,, - - - No leading underscore is generated in the ELF symbols. - - Documentation and License: - -------------------------- - TCC is distributed under the GNU Lesser General Public License. (See - COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html) - - TinyCC homepage is at: - - http://fabrice.bellard.free.fr/tcc/ - - - WinAPI Help and 3rd-party tools: - -------------------------------- - The Windows API documentation (Win95) in a single .hlp file is - available on the lcc-win32 site as "win32hlp.exe" or from other - locations as "win32hlp_big.zip". - - A nice RAD tool to create windows resources (dialog boxes etc.) is - "ResEd", available at the RadASM website. - - - --- grischka diff --git a/tinyc/x86_64-asm.h b/tinyc/x86_64-asm.h deleted file mode 100644 index cb9eb16c8..000000000 --- a/tinyc/x86_64-asm.h +++ /dev/null @@ -1,525 +0,0 @@ - DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ - DEF_ASM_OP0(cld, 0xfc) - DEF_ASM_OP0(cli, 0xfa) - DEF_ASM_OP0(clts, 0x0f06) - DEF_ASM_OP0(cmc, 0xf5) - DEF_ASM_OP0(lahf, 0x9f) - DEF_ASM_OP0(sahf, 0x9e) - DEF_ASM_OP0(pushfq, 0x9c) - DEF_ASM_OP0(popfq, 0x9d) - DEF_ASM_OP0(pushf, 0x9c) - DEF_ASM_OP0(popf, 0x9d) - DEF_ASM_OP0(stc, 0xf9) - DEF_ASM_OP0(std, 0xfd) - DEF_ASM_OP0(sti, 0xfb) - DEF_ASM_OP0(aaa, 0x37) - DEF_ASM_OP0(aas, 0x3f) - DEF_ASM_OP0(daa, 0x27) - DEF_ASM_OP0(das, 0x2f) - DEF_ASM_OP0(aad, 0xd50a) - DEF_ASM_OP0(aam, 0xd40a) - DEF_ASM_OP0(cbw, 0x6698) - DEF_ASM_OP0(cwd, 0x6699) - DEF_ASM_OP0(cwde, 0x98) - DEF_ASM_OP0(cdq, 0x99) - DEF_ASM_OP0(cbtw, 0x6698) - DEF_ASM_OP0(cwtl, 0x98) - DEF_ASM_OP0(cwtd, 0x6699) - DEF_ASM_OP0(cltd, 0x99) - DEF_ASM_OP0(cqto, 0x4899) - DEF_ASM_OP0(int3, 0xcc) - DEF_ASM_OP0(into, 0xce) - DEF_ASM_OP0(iret, 0xcf) - DEF_ASM_OP0(rsm, 0x0faa) - DEF_ASM_OP0(hlt, 0xf4) - DEF_ASM_OP0(wait, 0x9b) - DEF_ASM_OP0(nop, 0x90) - DEF_ASM_OP0(pause, 0xf390) - DEF_ASM_OP0(xlat, 0xd7) - - /* strings */ -ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL)) -ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL)) - -ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) - -ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX)) -ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX)) - - /* bits */ - -ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - -ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - -ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) - - /* prefixes */ - DEF_ASM_OP0(lock, 0xf0) - DEF_ASM_OP0(rep, 0xf3) - DEF_ASM_OP0(repe, 0xf3) - DEF_ASM_OP0(repz, 0xf3) - DEF_ASM_OP0(repne, 0xf2) - DEF_ASM_OP0(repnz, 0xf2) - - DEF_ASM_OP0(invd, 0x0f08) - DEF_ASM_OP0(wbinvd, 0x0f09) - DEF_ASM_OP0(cpuid, 0x0fa2) - DEF_ASM_OP0(wrmsr, 0x0f30) - DEF_ASM_OP0(rdtsc, 0x0f31) - DEF_ASM_OP0(rdmsr, 0x0f32) - DEF_ASM_OP0(rdpmc, 0x0f33) - - DEF_ASM_OP0(syscall, 0x0f05) - DEF_ASM_OP0(sysret, 0x0f07) - DEF_ASM_OP0L(sysretq, 0x480f07, 0, 0) - DEF_ASM_OP0(ud2, 0x0f0b) - - /* NOTE: we took the same order as gas opcode definition order */ -/* Right now we can't express the fact that 0xa1/0xa3 can't use $eax and a - 32 bit moffset as operands. -ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX)) -ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR)) */ -ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) -/* The moves are special: the 0xb8 form supports IM64 (the only insn that - does) with REG64. It doesn't support IM32 with REG64, it would use - the full movabs form (64bit immediate). For IM32->REG64 we prefer - the 0xc7 opcode. So disallow all 64bit forms and code the rest by hand. */ -ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG)) -ALT(DEF_ASM_OP2(mov, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64)) -ALT(DEF_ASM_OP2(movq, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64)) -ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG)) - -ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG64)) -ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG64)) -ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_CR)) -ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_DB)) - -ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16)) -ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movsbq, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movswq, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG)) -ALT(DEF_ASM_OP2(movslq, 0x63, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG)) -ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(movzwq, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG)) - -ALT(DEF_ASM_OP1(pushq, 0x6a, 0, 0, OPT_IM8S)) -ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S)) -ALT(DEF_ASM_OP1(pushw, 0x666a, 0, 0, OPT_IM8S)) -ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG64)) -ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG16)) -ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REG64 | OPT_EA)) -ALT(DEF_ASM_OP1(pushw, 0x6668, 0, 0, OPT_IM16)) -ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32)) -ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG)) - -ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REG64)) -ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REG16)) -ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) -ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG)) - -ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX)) -ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW)) -ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) - -ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX)) -ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8)) -ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) -ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) - -ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) -ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8)) -ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX)) -ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX)) - -ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG)) - -ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) -ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) - - /* arith */ -ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ -ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) -ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX)) -ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) - -ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) -ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX)) -ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) - -ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) - -ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) -ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW)) -ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW)) -ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW)) - -ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) -ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) -ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) - - /* shifts */ -ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG)) -ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG)) - -ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) -ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) - -ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR)) -ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP)) -ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) -ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8)) - -ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(ljmpw, 0x66ff, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(ljmpl, 0xff, 5, OPC_MODRM, OPT_EA) - -ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8)) -ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) -ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) - DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8) - DEF_ASM_OP0(leave, 0xc9) - DEF_ASM_OP0(ret, 0xc3) - DEF_ASM_OP0(retq, 0xc3) -ALT(DEF_ASM_OP1(retq, 0xc2, 0, 0, OPT_IM16)) -ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) - DEF_ASM_OP0(lret, 0xcb) -ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16)) - -ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8)) - DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8) - DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8) - DEF_ASM_OP1(jecxz, 0x67e3, 0, 0, OPT_DISP8) - - /* float */ - /* specific fcomp handling */ -ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) - -ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) -ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) -ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) -ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) -ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) - - DEF_ASM_OP0(fucompp, 0xdae9) - DEF_ASM_OP0(ftst, 0xd9e4) - DEF_ASM_OP0(fxam, 0xd9e5) - DEF_ASM_OP0(fld1, 0xd9e8) - DEF_ASM_OP0(fldl2t, 0xd9e9) - DEF_ASM_OP0(fldl2e, 0xd9ea) - DEF_ASM_OP0(fldpi, 0xd9eb) - DEF_ASM_OP0(fldlg2, 0xd9ec) - DEF_ASM_OP0(fldln2, 0xd9ed) - DEF_ASM_OP0(fldz, 0xd9ee) - - DEF_ASM_OP0(f2xm1, 0xd9f0) - DEF_ASM_OP0(fyl2x, 0xd9f1) - DEF_ASM_OP0(fptan, 0xd9f2) - DEF_ASM_OP0(fpatan, 0xd9f3) - DEF_ASM_OP0(fxtract, 0xd9f4) - DEF_ASM_OP0(fprem1, 0xd9f5) - DEF_ASM_OP0(fdecstp, 0xd9f6) - DEF_ASM_OP0(fincstp, 0xd9f7) - DEF_ASM_OP0(fprem, 0xd9f8) - DEF_ASM_OP0(fyl2xp1, 0xd9f9) - DEF_ASM_OP0(fsqrt, 0xd9fa) - DEF_ASM_OP0(fsincos, 0xd9fb) - DEF_ASM_OP0(frndint, 0xd9fc) - DEF_ASM_OP0(fscale, 0xd9fd) - DEF_ASM_OP0(fsin, 0xd9fe) - DEF_ASM_OP0(fcos, 0xd9ff) - DEF_ASM_OP0(fchs, 0xd9e0) - DEF_ASM_OP0(fabs, 0xd9e1) - DEF_ASM_OP0(fninit, 0xdbe3) - DEF_ASM_OP0(fnclex, 0xdbe2) - DEF_ASM_OP0(fnop, 0xd9d0) - DEF_ASM_OP0(fwait, 0x9b) - - /* fp load */ - DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) - DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) - - /* fp store */ - DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) -ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) - DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) - - DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) - DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) - - /* exchange */ - DEF_ASM_OP0(fxch, 0xd9c9) -ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) - - /* misc FPU */ - DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) - - DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) - DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP0(fnstsw, 0xdfe0) -ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) -ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) - DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) -ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) -ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) - DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) - DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) - DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) - DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) - DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) - /* The *q forms of fxrstor/fxsave use a REX prefix. - If the operand would use extended registers we would have to modify - it instead of generating a second one. Currently that's no - problem with TCC, we don't use extended registers. */ - DEF_ASM_OP1(fxsaveq, 0x0fae, 0, OPC_MODRM | OPC_48, OPT_EA ) - DEF_ASM_OP1(fxrstorq, 0x0fae, 1, OPC_MODRM | OPC_48, OPT_EA ) - - /* segments */ - DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) -ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) - DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lgdtq, 0x0f01, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lidtq, 0x0f01, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG) - DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG) -ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)) - DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG16) - DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sgdtq, 0x0f01, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sidtq, 0x0f01, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG32 | OPT_EA) -ALT(DEF_ASM_OP1(str, 0x660f00, 1, OPC_MODRM, OPT_REG16)) -ALT(DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM | OPC_48, OPT_REG64)) - DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) - DEF_ASM_OP0L(swapgs, 0x0f01, 7, OPC_MODRM) - - /* 486 */ - /* bswap can't be applied to 16bit regs */ - DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) - DEF_ASM_OP1(bswapl, 0x0fc8, 0, OPC_REG, OPT_REG32 ) - DEF_ASM_OP1(bswapq, 0x0fc8, 0, OPC_REG | OPC_48, OPT_REG64 ) - -ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) -ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) - DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA ) - - /* pentium */ - DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA ) - - /* AMD 64 */ - DEF_ASM_OP1(cmpxchg16b, 0x0fc7, 1, OPC_MODRM | OPC_48, OPT_EA ) - - /* pentium pro */ -ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) - - DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) - DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) - - /* mmx */ - DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ - DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE ) - /* movd shouldn't accept REG64, but AMD64 spec uses it for 32 and 64 bit - moves, so let's be compatible. */ -ALT(DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG64, OPT_MMXSSE )) -ALT(DEF_ASM_OP2(movq, 0x0f6e, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_MMXSSE )) -ALT(DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )) -ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 )) -ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 )) -ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX )) -ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE )) -ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )) -ALT(DEF_ASM_OP2(movq, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 )) - - DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) -ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) - DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - - /* sse */ - DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) -ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) - DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) -ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) - DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) -ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) - DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE ) - DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) - DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) - DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) - DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) - - DEF_ASM_OP1(prefetchnta, 0x0f18, 0, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetcht0, 0x0f18, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetcht1, 0x0f18, 2, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetcht2, 0x0f18, 3, OPC_MODRM, OPT_EA) - DEF_ASM_OP1(prefetchw, 0x0f0d, 1, OPC_MODRM, OPT_EA) - DEF_ASM_OP0L(lfence, 0x0fae, 5, OPC_MODRM) - DEF_ASM_OP0L(mfence, 0x0fae, 6, OPC_MODRM) - DEF_ASM_OP0L(sfence, 0x0fae, 7, OPC_MODRM) - DEF_ASM_OP1(clflush, 0x0fae, 7, OPC_MODRM, OPT_EA) -#undef ALT -#undef DEF_ASM_OP0 -#undef DEF_ASM_OP0L -#undef DEF_ASM_OP1 -#undef DEF_ASM_OP2 -#undef DEF_ASM_OP3 diff --git a/tinyc/x86_64-gen.c b/tinyc/x86_64-gen.c deleted file mode 100644 index f4d86e1b7..000000000 --- a/tinyc/x86_64-gen.c +++ /dev/null @@ -1,2229 +0,0 @@ -/* - * x86-64 code generator for TCC - * - * Copyright (c) 2008 Shinichiro Hamaji - * - * Based on i386-gen.c by Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef TARGET_DEFS_ONLY - -/* number of available registers */ -#define NB_REGS 25 -#define NB_ASM_REGS 16 -#define CONFIG_TCC_ASM - -/* a register can belong to several classes. The classes must be - sorted from more general to more precise (see gv2() code which does - assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_RAX 0x0004 -#define RC_RCX 0x0008 -#define RC_RDX 0x0010 -#define RC_ST0 0x0080 /* only for long double */ -#define RC_R8 0x0100 -#define RC_R9 0x0200 -#define RC_R10 0x0400 -#define RC_R11 0x0800 -#define RC_XMM0 0x1000 -#define RC_XMM1 0x2000 -#define RC_XMM2 0x4000 -#define RC_XMM3 0x8000 -#define RC_XMM4 0x10000 -#define RC_XMM5 0x20000 -#define RC_XMM6 0x40000 -#define RC_XMM7 0x80000 -#define RC_IRET RC_RAX /* function return: integer register */ -#define RC_LRET RC_RDX /* function return: second integer register */ -#define RC_FRET RC_XMM0 /* function return: float register */ -#define RC_QRET RC_XMM1 /* function return: second float register */ - -/* pretty names for the registers */ -enum { - TREG_RAX = 0, - TREG_RCX = 1, - TREG_RDX = 2, - TREG_RSP = 4, - TREG_RSI = 6, - TREG_RDI = 7, - - TREG_R8 = 8, - TREG_R9 = 9, - TREG_R10 = 10, - TREG_R11 = 11, - - TREG_XMM0 = 16, - TREG_XMM1 = 17, - TREG_XMM2 = 18, - TREG_XMM3 = 19, - TREG_XMM4 = 20, - TREG_XMM5 = 21, - TREG_XMM6 = 22, - TREG_XMM7 = 23, - - TREG_ST0 = 24, - - TREG_MEM = 0x20 -}; - -#define REX_BASE(reg) (((reg) >> 3) & 1) -#define REG_VALUE(reg) ((reg) & 7) - -/* return registers for function */ -#define REG_IRET TREG_RAX /* single word int return register */ -#define REG_LRET TREG_RDX /* second word return register (for long long) */ -#define REG_FRET TREG_XMM0 /* float return register */ -#define REG_QRET TREG_XMM1 /* second float return register */ - -/* defined if function parameters must be evaluated in reverse order */ -#define INVERT_FUNC_PARAMS - -/* pointer size, in bytes */ -#define PTR_SIZE 8 - -/* long double size and alignment, in bytes */ -#define LDOUBLE_SIZE 16 -#define LDOUBLE_ALIGN 16 -/* maximum alignment (for aligned attribute support) */ -#define MAX_ALIGN 16 - -/******************************************************/ -#else /* ! TARGET_DEFS_ONLY */ -/******************************************************/ -#include "tcc.h" -#include - -ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_RAX, - /* ecx */ RC_INT | RC_RCX, - /* edx */ RC_INT | RC_RDX, - 0, - 0, - 0, - 0, - 0, - RC_R8, - RC_R9, - RC_R10, - RC_R11, - 0, - 0, - 0, - 0, - /* xmm0 */ RC_FLOAT | RC_XMM0, - /* xmm1 */ RC_FLOAT | RC_XMM1, - /* xmm2 */ RC_FLOAT | RC_XMM2, - /* xmm3 */ RC_FLOAT | RC_XMM3, - /* xmm4 */ RC_FLOAT | RC_XMM4, - /* xmm5 */ RC_FLOAT | RC_XMM5, - /* xmm6 an xmm7 are included so gv() can be used on them, - but they are not tagged with RC_FLOAT because they are - callee saved on Windows */ - RC_XMM6, - RC_XMM7, - /* st0 */ RC_ST0 -}; - -static unsigned long func_sub_sp_offset; -static int func_ret_sub; - -/* XXX: make it faster ? */ -ST_FUNC void g(int c) -{ - int ind1; - if (nocode_wanted) - return; - ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) - section_realloc(cur_text_section, ind1); - cur_text_section->data[ind] = c; - ind = ind1; -} - -ST_FUNC void o(unsigned int c) -{ - while (c) { - g(c); - c = c >> 8; - } -} - -ST_FUNC void gen_le16(int v) -{ - g(v); - g(v >> 8); -} - -ST_FUNC void gen_le32(int c) -{ - g(c); - g(c >> 8); - g(c >> 16); - g(c >> 24); -} - -ST_FUNC void gen_le64(int64_t c) -{ - g(c); - g(c >> 8); - g(c >> 16); - g(c >> 24); - g(c >> 32); - g(c >> 40); - g(c >> 48); - g(c >> 56); -} - -static void orex(int ll, int r, int r2, int b) -{ - if ((r & VT_VALMASK) >= VT_CONST) - r = 0; - if ((r2 & VT_VALMASK) >= VT_CONST) - r2 = 0; - if (ll || REX_BASE(r) || REX_BASE(r2)) - o(0x40 | REX_BASE(r) | (REX_BASE(r2) << 2) | (ll << 3)); - o(b); -} - -/* output a symbol and patch all calls to it */ -ST_FUNC void gsym_addr(int t, int a) -{ - while (t) { - unsigned char *ptr = cur_text_section->data + t; - uint32_t n = read32le(ptr); /* next value */ - write32le(ptr, a - t - 4); - t = n; - } -} - -void gsym(int t) -{ - gsym_addr(t, ind); -} - - -static int is64_type(int t) -{ - return ((t & VT_BTYPE) == VT_PTR || - (t & VT_BTYPE) == VT_FUNC || - (t & VT_BTYPE) == VT_LLONG); -} - -/* instruction + 4 bytes data. Return the address of the data */ -static int oad(int c, int s) -{ - int t; - if (nocode_wanted) - return s; - o(c); - t = ind; - gen_le32(s); - return t; -} - -/* generate jmp to a label */ -#define gjmp2(instr,lbl) oad(instr,lbl) - -ST_FUNC void gen_addr32(int r, Sym *sym, int c) -{ - if (r & VT_SYM) - greloca(cur_text_section, sym, ind, R_X86_64_32S, c), c=0; - gen_le32(c); -} - -/* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c) -{ - if (r & VT_SYM) - greloca(cur_text_section, sym, ind, R_X86_64_64, c), c=0; - gen_le64(c); -} - -/* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) -{ - greloca(cur_text_section, sym, ind, R_X86_64_PC32, 0); - gen_le32(c-4); -} - -/* output got address with relocation */ -static void gen_gotpcrel(int r, Sym *sym, int c) -{ -#ifdef TCC_TARGET_PE - tcc_error("internal error: no GOT on PE: %s %x %x | %02x %02x %02x\n", - get_tok_str(sym->v, NULL), c, r, - cur_text_section->data[ind-3], - cur_text_section->data[ind-2], - cur_text_section->data[ind-1] - ); -#endif - greloca(cur_text_section, sym, ind, R_X86_64_GOTPCREL, -4); - gen_le32(0); - if (c) { - /* we use add c, %xxx for displacement */ - orex(1, r, 0, 0x81); - o(0xc0 + REG_VALUE(r)); - gen_le32(c); - } -} - -static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) -{ - op_reg = REG_VALUE(op_reg) << 3; - if ((r & VT_VALMASK) == VT_CONST) { - /* constant memory reference */ - o(0x05 | op_reg); - if (is_got) { - gen_gotpcrel(r, sym, c); - } else { - gen_addrpc32(r, sym, c); - } - } else if ((r & VT_VALMASK) == VT_LOCAL) { - /* currently, we use only ebp as base */ - if (c == (char)c) { - /* short reference */ - o(0x45 | op_reg); - g(c); - } else { - oad(0x85 | op_reg, c); - } - } else if ((r & VT_VALMASK) >= TREG_MEM) { - if (c) { - g(0x80 | op_reg | REG_VALUE(r)); - gen_le32(c); - } else { - g(0x00 | op_reg | REG_VALUE(r)); - } - } else { - g(0x00 | op_reg | REG_VALUE(r)); - } -} - -/* generate a modrm reference. 'op_reg' contains the additional 3 - opcode bits */ -static void gen_modrm(int op_reg, int r, Sym *sym, int c) -{ - gen_modrm_impl(op_reg, r, sym, c, 0); -} - -/* generate a modrm reference. 'op_reg' contains the additional 3 - opcode bits */ -static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c) -{ - int is_got; - is_got = (op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC); - orex(1, r, op_reg, opcode); - gen_modrm_impl(op_reg, r, sym, c, is_got); -} - - -/* load 'r' from value 'sv' */ -void load(int r, SValue *sv) -{ - int v, t, ft, fc, fr; - SValue v1; - -#ifdef TCC_TARGET_PE - SValue v2; - sv = pe_getimport(sv, &v2); -#endif - - fr = sv->r; - ft = sv->type.t & ~VT_DEFSIGN; - fc = sv->c.i; - if (fc != sv->c.i && (fr & VT_SYM)) - tcc_error("64 bit addend in load"); - - ft &= ~(VT_VOLATILE | VT_CONSTANT); - -#ifndef TCC_TARGET_PE - /* we use indirect access via got */ - if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) && - (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) { - /* use the result register as a temporal register */ - int tr = r | TREG_MEM; - if (is_float(ft)) { - /* we cannot use float registers as a temporal register */ - tr = get_reg(RC_INT) | TREG_MEM; - } - gen_modrm64(0x8b, tr, fr, sv->sym, 0); - - /* load from the temporal register */ - fr = tr | VT_LVAL; - } -#endif - - v = fr & VT_VALMASK; - if (fr & VT_LVAL) { - int b, ll; - if (v == VT_LLOCAL) { - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - fr = r; - if (!(reg_classes[fr] & (RC_INT|RC_R11))) - fr = get_reg(RC_INT); - load(fr, &v1); - } - ll = 0; - /* Like GCC we can load from small enough properly sized - structs and unions as well. - XXX maybe move to generic operand handling, but should - occur only with asm, so tccasm.c might also be a better place */ - if ((ft & VT_BTYPE) == VT_STRUCT) { - int align; - switch (type_size(&sv->type, &align)) { - case 1: ft = VT_BYTE; break; - case 2: ft = VT_SHORT; break; - case 4: ft = VT_INT; break; - case 8: ft = VT_LLONG; break; - default: - tcc_error("invalid aggregate type for register load"); - break; - } - } - if ((ft & VT_BTYPE) == VT_FLOAT) { - b = 0x6e0f66; - r = REG_VALUE(r); /* movd */ - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - b = 0x7e0ff3; /* movq */ - r = REG_VALUE(r); - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { - b = 0xdb, r = 5; /* fldt */ - } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { - b = 0xbe0f; /* movsbl */ - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { - b = 0xb60f; /* movzbl */ - } else if ((ft & VT_TYPE) == VT_SHORT) { - b = 0xbf0f; /* movswl */ - } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { - b = 0xb70f; /* movzwl */ - } else { - assert(((ft & VT_BTYPE) == VT_INT) - || ((ft & VT_BTYPE) == VT_LLONG) - || ((ft & VT_BTYPE) == VT_PTR) - || ((ft & VT_BTYPE) == VT_FUNC) - ); - ll = is64_type(ft); - b = 0x8b; - } - if (ll) { - gen_modrm64(b, r, fr, sv->sym, fc); - } else { - orex(ll, fr, r, b); - gen_modrm(r, fr, sv->sym, fc); - } - } else { - if (v == VT_CONST) { - if (fr & VT_SYM) { -#ifdef TCC_TARGET_PE - orex(1,0,r,0x8d); - o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ - gen_addrpc32(fr, sv->sym, fc); -#else - if (sv->sym->type.t & VT_STATIC) { - orex(1,0,r,0x8d); - o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ - gen_addrpc32(fr, sv->sym, fc); - } else { - orex(1,0,r,0x8b); - o(0x05 + REG_VALUE(r) * 8); /* mov xx(%rip), r */ - gen_gotpcrel(r, sv->sym, fc); - } -#endif - } else if (is64_type(ft)) { - orex(1,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le64(sv->c.i); - } else { - orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le32(fc); - } - } else if (v == VT_LOCAL) { - orex(1,0,r,0x8d); /* lea xxx(%ebp), r */ - gen_modrm(r, VT_LOCAL, sv->sym, fc); - } else if (v == VT_CMP) { - orex(0,r,0,0); - if ((fc & ~0x100) != TOK_NE) - oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ - else - oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */ - if (fc & 0x100) - { - /* This was a float compare. If the parity bit is - set the result was unordered, meaning false for everything - except TOK_NE, and true for TOK_NE. */ - fc &= ~0x100; - o(0x037a + (REX_BASE(r) << 8)); - } - orex(0,r,0, 0x0f); /* setxx %br */ - o(fc); - o(0xc0 + REG_VALUE(r)); - } else if (v == VT_JMP || v == VT_JMPI) { - t = v & 1; - orex(0,r,0,0); - oad(0xb8 + REG_VALUE(r), t); /* mov $1, r */ - o(0x05eb + (REX_BASE(r) << 8)); /* jmp after */ - gsym(fc); - orex(0,r,0,0); - oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ - } else if (v != r) { - if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { - if (v == TREG_ST0) { - /* gen_cvt_ftof(VT_DOUBLE); */ - o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmmN */ - o(0x100ff2); - o(0x44 + REG_VALUE(r)*8); /* %xmmN */ - o(0xf024); - } else { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); - if ((ft & VT_BTYPE) == VT_FLOAT) { - o(0x100ff3); - } else { - assert((ft & VT_BTYPE) == VT_DOUBLE); - o(0x100ff2); - } - o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); - } - } else if (r == TREG_ST0) { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); - /* gen_cvt_ftof(VT_LDOUBLE); */ - /* movsd %xmmN,-0x10(%rsp) */ - o(0x110ff2); - o(0x44 + REG_VALUE(r)*8); /* %xmmN */ - o(0xf024); - o(0xf02444dd); /* fldl -0x10(%rsp) */ - } else { - orex(1,r,v, 0x89); - o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */ - } - } - } -} - -/* store register 'r' in lvalue 'v' */ -void store(int r, SValue *v) -{ - int fr, bt, ft, fc; - int op64 = 0; - /* store the REX prefix in this variable when PIC is enabled */ - int pic = 0; - -#ifdef TCC_TARGET_PE - SValue v2; - v = pe_getimport(v, &v2); -#endif - - fr = v->r & VT_VALMASK; - ft = v->type.t; - fc = v->c.i; - if (fc != v->c.i && (fr & VT_SYM)) - tcc_error("64 bit addend in store"); - ft &= ~(VT_VOLATILE | VT_CONSTANT); - bt = ft & VT_BTYPE; - -#ifndef TCC_TARGET_PE - /* we need to access the variable via got */ - if (fr == VT_CONST && (v->r & VT_SYM)) { - /* mov xx(%rip), %r11 */ - o(0x1d8b4c); - gen_gotpcrel(TREG_R11, v->sym, v->c.i); - pic = is64_type(bt) ? 0x49 : 0x41; - } -#endif - - /* XXX: incorrect if float reg to reg */ - if (bt == VT_FLOAT) { - o(0x66); - o(pic); - o(0x7e0f); /* movd */ - r = REG_VALUE(r); - } else if (bt == VT_DOUBLE) { - o(0x66); - o(pic); - o(0xd60f); /* movq */ - r = REG_VALUE(r); - } else if (bt == VT_LDOUBLE) { - o(0xc0d9); /* fld %st(0) */ - o(pic); - o(0xdb); /* fstpt */ - r = 7; - } else { - if (bt == VT_SHORT) - o(0x66); - o(pic); - if (bt == VT_BYTE || bt == VT_BOOL) - orex(0, 0, r, 0x88); - else if (is64_type(bt)) - op64 = 0x89; - else - orex(0, 0, r, 0x89); - } - if (pic) { - /* xxx r, (%r11) where xxx is mov, movq, fld, or etc */ - if (op64) - o(op64); - o(3 + (r << 3)); - } else if (op64) { - if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) { - gen_modrm64(op64, r, v->r, v->sym, fc); - } else if (fr != r) { - /* XXX: don't we really come here? */ - abort(); - o(0xc0 + fr + r * 8); /* mov r, fr */ - } - } else { - if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) { - gen_modrm(r, v->r, v->sym, fc); - } else if (fr != r) { - /* XXX: don't we really come here? */ - abort(); - o(0xc0 + fr + r * 8); /* mov r, fr */ - } - } -} - -/* 'is_jmp' is '1' if it is a jump */ -static void gcall_or_jmp(int is_jmp) -{ - int r; - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && - ((vtop->r & VT_SYM) || (vtop->c.i-4) == (int)(vtop->c.i-4))) { - /* constant case */ - if (vtop->r & VT_SYM) { - /* relocation case */ -#ifdef TCC_TARGET_PE - greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4)); -#else - greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4)); -#endif - } else { - /* put an empty PC32 relocation */ - put_elf_reloca(symtab_section, cur_text_section, - ind + 1, R_X86_64_PC32, 0, (int)(vtop->c.i-4)); - } - oad(0xe8 + is_jmp, 0); /* call/jmp im */ - } else { - /* otherwise, indirect call */ - r = TREG_R11; - load(r, vtop); - o(0x41); /* REX */ - o(0xff); /* call/jmp *r */ - o(0xd0 + REG_VALUE(r) + (is_jmp << 4)); - } -} - -#if defined(CONFIG_TCC_BCHECK) -#ifndef TCC_TARGET_PE -static addr_t func_bound_offset; -static unsigned long func_bound_ind; -#endif - -static void gen_static_call(int v) -{ - Sym *sym = external_global_sym(v, &func_old_type, 0); - oad(0xe8, 0); - greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); -} - -/* generate a bounded pointer addition */ -ST_FUNC void gen_bounded_ptr_add(void) -{ - /* save all temporary registers */ - save_regs(0); - - /* prepare fast x86_64 function call */ - gv(RC_RAX); - o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size - vtop--; - - gv(RC_RAX); - o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr - vtop--; - - /* do a fast function call */ - gen_static_call(TOK___bound_ptr_add); - - /* returned pointer is in rax */ - vtop++; - vtop->r = TREG_RAX | VT_BOUNDED; - - - /* relocation offset of the bounding function call point */ - vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela))); -} - -/* patch pointer addition in vtop so that pointer dereferencing is - also tested */ -ST_FUNC void gen_bounded_ptr_deref(void) -{ - addr_t func; - int size, align; - ElfW(Rela) *rel; - Sym *sym; - - size = 0; - /* XXX: put that code in generic part of tcc */ - if (!is_float(vtop->type.t)) { - if (vtop->r & VT_LVAL_BYTE) - size = 1; - else if (vtop->r & VT_LVAL_SHORT) - size = 2; - } - if (!size) - size = type_size(&vtop->type, &align); - switch(size) { - case 1: func = TOK___bound_ptr_indir1; break; - case 2: func = TOK___bound_ptr_indir2; break; - case 4: func = TOK___bound_ptr_indir4; break; - case 8: func = TOK___bound_ptr_indir8; break; - case 12: func = TOK___bound_ptr_indir12; break; - case 16: func = TOK___bound_ptr_indir16; break; - default: - tcc_error("unhandled size when dereferencing bounded pointer"); - func = 0; - break; - } - - sym = external_global_sym(func, &func_old_type, 0); - if (!sym->c) - put_extern_sym(sym, NULL, 0, 0); - - /* patch relocation */ - /* XXX: find a better solution ? */ - - rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i); - rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info)); -} -#endif - -#ifdef TCC_TARGET_PE - -#define REGN 4 -static const uint8_t arg_regs[REGN] = { - TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 -}; - -/* Prepare arguments in R10 and R11 rather than RCX and RDX - because gv() will not ever use these */ -static int arg_prepare_reg(int idx) { - if (idx == 0 || idx == 1) - /* idx=0: r10, idx=1: r11 */ - return idx + 10; - else - return arg_regs[idx]; -} - -static int func_scratch, func_alloca; - -/* Generate function call. The function address is pushed first, then - all the parameters in call order. This functions pops all the - parameters and the function address. */ - -static void gen_offs_sp(int b, int r, int d) -{ - orex(1,0,r & 0x100 ? 0 : r, b); - if (d == (char)d) { - o(0x2444 | (REG_VALUE(r) << 3)); - g(d); - } else { - o(0x2484 | (REG_VALUE(r) << 3)); - gen_le32(d); - } -} - -static int using_regs(int size) -{ - return !(size > 8 || (size & (size - 1))); -} - -/* Return the number of registers needed to return the struct, or 0 if - returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) -{ - int size, align; - *ret_align = 1; // Never have to re-align return values for x86-64 - *regsize = 8; - size = type_size(vt, &align); - if (!using_regs(size)) - return 0; - if (size == 8) - ret->t = VT_LLONG; - else if (size == 4) - ret->t = VT_INT; - else if (size == 2) - ret->t = VT_SHORT; - else - ret->t = VT_BYTE; - ret->ref = NULL; - return 1; -} - -static int is_sse_float(int t) { - int bt; - bt = t & VT_BTYPE; - return bt == VT_DOUBLE || bt == VT_FLOAT; -} - -static int gfunc_arg_size(CType *type) { - int align; - if (type->t & (VT_ARRAY|VT_BITFIELD)) - return 8; - return type_size(type, &align); -} - -void gfunc_call(int nb_args) -{ - int size, r, args_size, i, d, bt, struct_size; - int arg; - - args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; - arg = nb_args; - - /* for struct arguments, we need to call memcpy and the function - call breaks register passing arguments we are preparing. - So, we process arguments which will be passed by stack first. */ - struct_size = args_size; - for(i = 0; i < nb_args; i++) { - SValue *sv; - - --arg; - sv = &vtop[-i]; - bt = (sv->type.t & VT_BTYPE); - size = gfunc_arg_size(&sv->type); - - if (using_regs(size)) - continue; /* arguments smaller than 8 bytes passed in registers or on stack */ - - if (bt == VT_STRUCT) { - /* align to stack align size */ - size = (size + 15) & ~15; - /* generate structure store */ - r = get_reg(RC_INT); - gen_offs_sp(0x8d, r, struct_size); - struct_size += size; - - /* generate memcpy call */ - vset(&sv->type, r | VT_LVAL, 0); - vpushv(sv); - vstore(); - --vtop; - } else if (bt == VT_LDOUBLE) { - gv(RC_ST0); - gen_offs_sp(0xdb, 0x107, struct_size); - struct_size += 16; - } - } - - if (func_scratch < struct_size) - func_scratch = struct_size; - - arg = nb_args; - struct_size = args_size; - - for(i = 0; i < nb_args; i++) { - --arg; - bt = (vtop->type.t & VT_BTYPE); - - size = gfunc_arg_size(&vtop->type); - if (!using_regs(size)) { - /* align to stack align size */ - size = (size + 15) & ~15; - if (arg >= REGN) { - d = get_reg(RC_INT); - gen_offs_sp(0x8d, d, struct_size); - gen_offs_sp(0x89, d, arg*8); - } else { - d = arg_prepare_reg(arg); - gen_offs_sp(0x8d, d, struct_size); - } - struct_size += size; - } else { - if (is_sse_float(vtop->type.t)) { - if (tcc_state->nosse) - tcc_error("SSE disabled"); - gv(RC_XMM0); /* only use one float register */ - if (arg >= REGN) { - /* movq %xmm0, j*8(%rsp) */ - gen_offs_sp(0xd60f66, 0x100, arg*8); - } else { - /* movaps %xmm0, %xmmN */ - o(0x280f); - o(0xc0 + (arg << 3)); - d = arg_prepare_reg(arg); - /* mov %xmm0, %rxx */ - o(0x66); - orex(1,d,0, 0x7e0f); - o(0xc0 + REG_VALUE(d)); - } - } else { - if (bt == VT_STRUCT) { - vtop->type.ref = NULL; - vtop->type.t = size > 4 ? VT_LLONG : size > 2 ? VT_INT - : size > 1 ? VT_SHORT : VT_BYTE; - } - - r = gv(RC_INT); - if (arg >= REGN) { - gen_offs_sp(0x89, r, arg*8); - } else { - d = arg_prepare_reg(arg); - orex(1,d,r,0x89); /* mov */ - o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); - } - } - } - vtop--; - } - save_regs(0); - - /* Copy R10 and R11 into RCX and RDX, respectively */ - if (nb_args > 0) { - o(0xd1894c); /* mov %r10, %rcx */ - if (nb_args > 1) { - o(0xda894c); /* mov %r11, %rdx */ - } - } - - gcall_or_jmp(0); - - if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) { - /* need to add the "func_scratch" area after alloca */ - o(0x0548), gen_le32(func_alloca), func_alloca = ind - 4; - } - - /* other compilers don't clear the upper bits when returning char/short */ - bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED); - if (bt == (VT_BYTE | VT_UNSIGNED)) - o(0xc0b60f); /* movzbl %al, %eax */ - else if (bt == VT_BYTE) - o(0xc0be0f); /* movsbl %al, %eax */ - else if (bt == VT_SHORT) - o(0x98); /* cwtl */ - else if (bt == (VT_SHORT | VT_UNSIGNED)) - o(0xc0b70f); /* movzbl %al, %eax */ -#if 0 /* handled in gen_cast() */ - else if (bt == VT_INT) - o(0x9848); /* cltq */ - else if (bt == (VT_INT | VT_UNSIGNED)) - o(0xc089); /* mov %eax,%eax */ -#endif - vtop--; -} - - -#define FUNC_PROLOG_SIZE 11 - -/* generate function prolog of type 't' */ -void gfunc_prolog(CType *func_type) -{ - int addr, reg_param_index, bt, size; - Sym *sym; - CType *type; - - func_ret_sub = 0; - func_scratch = 0; - func_alloca = 0; - loc = 0; - - addr = PTR_SIZE * 2; - ind += FUNC_PROLOG_SIZE; - func_sub_sp_offset = ind; - reg_param_index = 0; - - sym = func_type->ref; - - /* if the function returns a structure, then add an - implicit pointer parameter */ - func_vt = sym->type; - func_var = (sym->f.func_type == FUNC_ELLIPSIS); - size = gfunc_arg_size(&func_vt); - if (!using_regs(size)) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - func_vc = addr; - reg_param_index++; - addr += 8; - } - - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - bt = type->t & VT_BTYPE; - size = gfunc_arg_size(type); - if (!using_regs(size)) { - if (reg_param_index < REGN) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - } - sym_push(sym->v & ~SYM_FIELD, type, VT_LLOCAL | VT_LVAL, addr); - } else { - if (reg_param_index < REGN) { - /* save arguments passed by register */ - if ((bt == VT_FLOAT) || (bt == VT_DOUBLE)) { - if (tcc_state->nosse) - tcc_error("SSE disabled"); - o(0xd60f66); /* movq */ - gen_modrm(reg_param_index, VT_LOCAL, NULL, addr); - } else { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - } - } - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); - } - addr += 8; - reg_param_index++; - } - - while (reg_param_index < REGN) { - if (func_type->ref->f.func_type == FUNC_ELLIPSIS) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - addr += 8; - } - reg_param_index++; - } -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - int v, saved_ind; - - o(0xc9); /* leave */ - if (func_ret_sub == 0) { - o(0xc3); /* ret */ - } else { - o(0xc2); /* ret n */ - g(func_ret_sub); - g(func_ret_sub >> 8); - } - - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; - /* align local size to word & save local variables */ - v = (func_scratch + -loc + 15) & -16; - - if (v >= 4096) { - Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); - oad(0xb8, v); /* mov stacksize, %eax */ - oad(0xe8, 0); /* call __chkstk, (does the stackframe too) */ - greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); - o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */ - } else { - o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ - o(0xec8148); /* sub rsp, stacksize */ - gen_le32(v); - } - - /* add the "func_scratch" area after each alloca seen */ - while (func_alloca) { - unsigned char *ptr = cur_text_section->data + func_alloca; - func_alloca = read32le(ptr); - write32le(ptr, func_scratch); - } - - cur_text_section->data_offset = saved_ind; - pe_add_unwind_data(ind, saved_ind, v); - ind = cur_text_section->data_offset; -} - -#else - -static void gadd_sp(int val) -{ - if (val == (char)val) { - o(0xc48348); - g(val); - } else { - oad(0xc48148, val); /* add $xxx, %rsp */ - } -} - -typedef enum X86_64_Mode { - x86_64_mode_none, - x86_64_mode_memory, - x86_64_mode_integer, - x86_64_mode_sse, - x86_64_mode_x87 -} X86_64_Mode; - -static X86_64_Mode classify_x86_64_merge(X86_64_Mode a, X86_64_Mode b) -{ - if (a == b) - return a; - else if (a == x86_64_mode_none) - return b; - else if (b == x86_64_mode_none) - return a; - else if ((a == x86_64_mode_memory) || (b == x86_64_mode_memory)) - return x86_64_mode_memory; - else if ((a == x86_64_mode_integer) || (b == x86_64_mode_integer)) - return x86_64_mode_integer; - else if ((a == x86_64_mode_x87) || (b == x86_64_mode_x87)) - return x86_64_mode_memory; - else - return x86_64_mode_sse; -} - -static X86_64_Mode classify_x86_64_inner(CType *ty) -{ - X86_64_Mode mode; - Sym *f; - - switch (ty->t & VT_BTYPE) { - case VT_VOID: return x86_64_mode_none; - - case VT_INT: - case VT_BYTE: - case VT_SHORT: - case VT_LLONG: - case VT_BOOL: - case VT_PTR: - case VT_FUNC: - return x86_64_mode_integer; - - case VT_FLOAT: - case VT_DOUBLE: return x86_64_mode_sse; - - case VT_LDOUBLE: return x86_64_mode_x87; - - case VT_STRUCT: - f = ty->ref; - - mode = x86_64_mode_none; - for (f = f->next; f; f = f->next) - mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); - - return mode; - } - assert(0); - return 0; -} - -static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) -{ - X86_64_Mode mode; - int size, align, ret_t = 0; - - if (ty->t & (VT_BITFIELD|VT_ARRAY)) { - *psize = 8; - *palign = 8; - *reg_count = 1; - ret_t = ty->t; - mode = x86_64_mode_integer; - } else { - size = type_size(ty, &align); - *psize = (size + 7) & ~7; - *palign = (align + 7) & ~7; - - if (size > 16) { - mode = x86_64_mode_memory; - } else { - mode = classify_x86_64_inner(ty); - switch (mode) { - case x86_64_mode_integer: - if (size > 8) { - *reg_count = 2; - ret_t = VT_QLONG; - } else { - *reg_count = 1; - ret_t = (size > 4) ? VT_LLONG : VT_INT; - } - break; - - case x86_64_mode_x87: - *reg_count = 1; - ret_t = VT_LDOUBLE; - break; - - case x86_64_mode_sse: - if (size > 8) { - *reg_count = 2; - ret_t = VT_QFLOAT; - } else { - *reg_count = 1; - ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT; - } - break; - default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ - } - } - } - - if (ret) { - ret->ref = NULL; - ret->t = ret_t; - } - - return mode; -} - -ST_FUNC int classify_x86_64_va_arg(CType *ty) -{ - /* This definition must be synced with stdarg.h */ - enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack - }; - int size, align, reg_count; - X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count); - switch (mode) { - default: return __va_stack; - case x86_64_mode_integer: return __va_gen_reg; - case x86_64_mode_sse: return __va_float_reg; - } -} - -/* Return the number of registers needed to return the struct, or 0 if - returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) -{ - int size, align, reg_count; - *ret_align = 1; // Never have to re-align return values for x86-64 - *regsize = 8; - return (classify_x86_64_arg(vt, ret, &size, &align, ®_count) != x86_64_mode_memory); -} - -#define REGN 6 -static const uint8_t arg_regs[REGN] = { - TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 -}; - -static int arg_prepare_reg(int idx) { - if (idx == 2 || idx == 3) - /* idx=2: r10, idx=3: r11 */ - return idx + 8; - else - return arg_regs[idx]; -} - -/* Generate function call. The function address is pushed first, then - all the parameters in call order. This functions pops all the - parameters and the function address. */ -void gfunc_call(int nb_args) -{ - X86_64_Mode mode; - CType type; - int size, align, r, args_size, stack_adjust, i, reg_count; - int nb_reg_args = 0; - int nb_sse_args = 0; - int sse_reg, gen_reg; - char _onstack[nb_args], *onstack = _onstack; - - /* calculate the number of integer/float register arguments, remember - arguments to be passed via stack (in onstack[]), and also remember - if we have to align the stack pointer to 16 (onstack[i] == 2). Needs - to be done in a left-to-right pass over arguments. */ - stack_adjust = 0; - for(i = nb_args - 1; i >= 0; i--) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) { - nb_sse_args += reg_count; - onstack[i] = 0; - } else if (mode == x86_64_mode_integer && nb_reg_args + reg_count <= REGN) { - nb_reg_args += reg_count; - onstack[i] = 0; - } else if (mode == x86_64_mode_none) { - onstack[i] = 0; - } else { - if (align == 16 && (stack_adjust &= 15)) { - onstack[i] = 2; - stack_adjust = 0; - } else - onstack[i] = 1; - stack_adjust += size; - } - } - - if (nb_sse_args && tcc_state->nosse) - tcc_error("SSE disabled but floating point arguments passed"); - - /* fetch cpu flag before generating any code */ - if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) - gv(RC_INT); - - /* for struct arguments, we need to call memcpy and the function - call breaks register passing arguments we are preparing. - So, we process arguments which will be passed by stack first. */ - gen_reg = nb_reg_args; - sse_reg = nb_sse_args; - args_size = 0; - stack_adjust &= 15; - for (i = 0; i < nb_args;) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - if (!onstack[i]) { - ++i; - continue; - } - /* Possibly adjust stack to align SSE boundary. We're processing - args from right to left while allocating happens left to right - (stack grows down), so the adjustment needs to happen _after_ - an argument that requires it. */ - if (stack_adjust) { - o(0x50); /* push %rax; aka sub $8,%rsp */ - args_size += 8; - stack_adjust = 0; - } - if (onstack[i] == 2) - stack_adjust = 1; - - vrotb(i+1); - - switch (vtop->type.t & VT_BTYPE) { - case VT_STRUCT: - /* allocate the necessary size on stack */ - o(0x48); - oad(0xec81, size); /* sub $xxx, %rsp */ - /* generate structure store */ - r = get_reg(RC_INT); - orex(1, r, 0, 0x89); /* mov %rsp, r */ - o(0xe0 + REG_VALUE(r)); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - break; - - case VT_LDOUBLE: - gv(RC_ST0); - oad(0xec8148, size); /* sub $xxx, %rsp */ - o(0x7cdb); /* fstpt 0(%rsp) */ - g(0x24); - g(0x00); - break; - - case VT_FLOAT: - case VT_DOUBLE: - assert(mode == x86_64_mode_sse); - r = gv(RC_FLOAT); - o(0x50); /* push $rax */ - /* movq %xmmN, (%rsp) */ - o(0xd60f66); - o(0x04 + REG_VALUE(r)*8); - o(0x24); - break; - - default: - assert(mode == x86_64_mode_integer); - /* simple type */ - /* XXX: implicit cast ? */ - r = gv(RC_INT); - orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */ - break; - } - args_size += size; - - vpop(); - --nb_args; - onstack++; - } - - /* XXX This should be superfluous. */ - save_regs(0); /* save used temporary registers */ - - /* then, we prepare register passing arguments. - Note that we cannot set RDX and RCX in this loop because gv() - may break these temporary registers. Let's use R10 and R11 - instead of them */ - assert(gen_reg <= REGN); - assert(sse_reg <= 8); - for(i = 0; i < nb_args; i++) { - mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); - /* Alter stack entry type so that gv() knows how to treat it */ - vtop->type = type; - if (mode == x86_64_mode_sse) { - if (reg_count == 2) { - sse_reg -= 2; - gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ - if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ - /* movaps %xmm0, %xmmN */ - o(0x280f); - o(0xc0 + (sse_reg << 3)); - /* movaps %xmm1, %xmmN */ - o(0x280f); - o(0xc1 + ((sse_reg+1) << 3)); - } - } else { - assert(reg_count == 1); - --sse_reg; - /* Load directly to register */ - gv(RC_XMM0 << sse_reg); - } - } else if (mode == x86_64_mode_integer) { - /* simple type */ - /* XXX: implicit cast ? */ - int d; - gen_reg -= reg_count; - r = gv(RC_INT); - d = arg_prepare_reg(gen_reg); - orex(1,d,r,0x89); /* mov */ - o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); - if (reg_count == 2) { - d = arg_prepare_reg(gen_reg+1); - orex(1,d,vtop->r2,0x89); /* mov */ - o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); - } - } - vtop--; - } - assert(gen_reg == 0); - assert(sse_reg == 0); - - /* We shouldn't have many operands on the stack anymore, but the - call address itself is still there, and it might be in %eax - (or edx/ecx) currently, which the below writes would clobber. - So evict all remaining operands here. */ - save_regs(0); - - /* Copy R10 and R11 into RDX and RCX, respectively */ - if (nb_reg_args > 2) { - o(0xd2894c); /* mov %r10, %rdx */ - if (nb_reg_args > 3) { - o(0xd9894c); /* mov %r11, %rcx */ - } - } - - if (vtop->type.ref->f.func_type != FUNC_NEW) /* implies FUNC_OLD or FUNC_ELLIPSIS */ - oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ - gcall_or_jmp(0); - if (args_size) - gadd_sp(args_size); - vtop--; -} - - -#define FUNC_PROLOG_SIZE 11 - -static void push_arg_reg(int i) { - loc -= 8; - gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, loc); -} - -/* generate function prolog of type 't' */ -void gfunc_prolog(CType *func_type) -{ - X86_64_Mode mode; - int i, addr, align, size, reg_count; - int param_addr = 0, reg_param_index, sse_param_index; - Sym *sym; - CType *type; - - sym = func_type->ref; - addr = PTR_SIZE * 2; - loc = 0; - ind += FUNC_PROLOG_SIZE; - func_sub_sp_offset = ind; - func_ret_sub = 0; - - if (sym->f.func_type == FUNC_ELLIPSIS) { - int seen_reg_num, seen_sse_num, seen_stack_size; - seen_reg_num = seen_sse_num = 0; - /* frame pointer and return address */ - seen_stack_size = PTR_SIZE * 2; - /* count the number of seen parameters */ - sym = func_type->ref; - while ((sym = sym->next) != NULL) { - type = &sym->type; - mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); - switch (mode) { - default: - stack_arg: - seen_stack_size = ((seen_stack_size + align - 1) & -align) + size; - break; - - case x86_64_mode_integer: - if (seen_reg_num + reg_count > REGN) - goto stack_arg; - seen_reg_num += reg_count; - break; - - case x86_64_mode_sse: - if (seen_sse_num + reg_count > 8) - goto stack_arg; - seen_sse_num += reg_count; - break; - } - } - - loc -= 16; - /* movl $0x????????, -0x10(%rbp) */ - o(0xf045c7); - gen_le32(seen_reg_num * 8); - /* movl $0x????????, -0xc(%rbp) */ - o(0xf445c7); - gen_le32(seen_sse_num * 16 + 48); - /* movl $0x????????, -0x8(%rbp) */ - o(0xf845c7); - gen_le32(seen_stack_size); - - /* save all register passing arguments */ - for (i = 0; i < 8; i++) { - loc -= 16; - if (!tcc_state->nosse) { - o(0xd60f66); /* movq */ - gen_modrm(7 - i, VT_LOCAL, NULL, loc); - } - /* movq $0, loc+8(%rbp) */ - o(0x85c748); - gen_le32(loc + 8); - gen_le32(0); - } - for (i = 0; i < REGN; i++) { - push_arg_reg(REGN-1-i); - } - } - - sym = func_type->ref; - reg_param_index = 0; - sse_param_index = 0; - - /* if the function returns a structure, then add an - implicit pointer parameter */ - func_vt = sym->type; - mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, ®_count); - if (mode == x86_64_mode_memory) { - push_arg_reg(reg_param_index); - func_vc = loc; - reg_param_index++; - } - /* define parameters */ - while ((sym = sym->next) != NULL) { - type = &sym->type; - mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); - switch (mode) { - case x86_64_mode_sse: - if (tcc_state->nosse) - tcc_error("SSE disabled but floating point arguments used"); - if (sse_param_index + reg_count <= 8) { - /* save arguments passed by register */ - loc -= reg_count * 8; - param_addr = loc; - for (i = 0; i < reg_count; ++i) { - o(0xd60f66); /* movq */ - gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8); - ++sse_param_index; - } - } else { - addr = (addr + align - 1) & -align; - param_addr = addr; - addr += size; - } - break; - - case x86_64_mode_memory: - case x86_64_mode_x87: - addr = (addr + align - 1) & -align; - param_addr = addr; - addr += size; - break; - - case x86_64_mode_integer: { - if (reg_param_index + reg_count <= REGN) { - /* save arguments passed by register */ - loc -= reg_count * 8; - param_addr = loc; - for (i = 0; i < reg_count; ++i) { - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8); - ++reg_param_index; - } - } else { - addr = (addr + align - 1) & -align; - param_addr = addr; - addr += size; - } - break; - } - default: break; /* nothing to be done for x86_64_mode_none */ - } - sym_push(sym->v & ~SYM_FIELD, type, - VT_LOCAL | VT_LVAL, param_addr); - } - -#ifdef CONFIG_TCC_BCHECK - /* leave some room for bound checking code */ - if (tcc_state->do_bounds_check) { - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - oad(0xb8, 0); /* lbound section pointer */ - o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */ - oad(0xb8, 0); /* call to function */ - } -#endif -} - -/* generate function epilog */ -void gfunc_epilog(void) -{ - int v, saved_ind; - -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check - && func_bound_offset != lbounds_section->data_offset) - { - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - /* generate bound local allocation */ - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); - saved_ind = ind; - ind = func_bound_ind; - greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0); - ind = ind + 5 + 3; - gen_static_call(TOK___bound_local_new); - ind = saved_ind; - - /* generate bound check local freeing */ - o(0x5250); /* save returned value, if any */ - greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0); - oad(0xb8, 0); /* mov xxx, %rax */ - o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */ - gen_static_call(TOK___bound_local_delete); - o(0x585a); /* restore returned value, if any */ - } -#endif - o(0xc9); /* leave */ - if (func_ret_sub == 0) { - o(0xc3); /* ret */ - } else { - o(0xc2); /* ret n */ - g(func_ret_sub); - g(func_ret_sub >> 8); - } - /* align local size to word & save local variables */ - v = (-loc + 15) & -16; - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; - o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ - o(0xec8148); /* sub rsp, stacksize */ - gen_le32(v); - ind = saved_ind; -} - -#endif /* not PE */ - -/* generate a jump to a label */ -int gjmp(int t) -{ - return gjmp2(0xe9, t); -} - -/* generate a jump to a fixed address */ -void gjmp_addr(int a) -{ - int r; - r = a - ind - 2; - if (r == (char)r) { - g(0xeb); - g(r); - } else { - oad(0xe9, a - ind - 5); - } -} - -ST_FUNC void gtst_addr(int inv, int a) -{ - int v = vtop->r & VT_VALMASK; - if (v == VT_CMP) { - inv ^= (vtop--)->c.i; - a -= ind + 2; - if (a == (char)a) { - g(inv - 32); - g(a); - } else { - g(0x0f); - oad(inv - 16, a - 4); - } - } else if ((v & ~1) == VT_JMP) { - if ((v & 1) != inv) { - gjmp_addr(a); - gsym(vtop->c.i); - } else { - gsym(vtop->c.i); - o(0x05eb); - gjmp_addr(a); - } - vtop--; - } -} - -/* generate a test. set 'inv' to invert test. Stack entry is popped */ -ST_FUNC int gtst(int inv, int t) -{ - int v = vtop->r & VT_VALMASK; - - if (nocode_wanted) { - ; - } else if (v == VT_CMP) { - /* fast case : can jump directly since flags are set */ - if (vtop->c.i & 0x100) - { - /* This was a float compare. If the parity flag is set - the result was unordered. For anything except != this - means false and we don't jump (anding both conditions). - For != this means true (oring both). - Take care about inverting the test. We need to jump - to our target if the result was unordered and test wasn't NE, - otherwise if unordered we don't want to jump. */ - vtop->c.i &= ~0x100; - if (inv == (vtop->c.i == TOK_NE)) - o(0x067a); /* jp +6 */ - else - { - g(0x0f); - t = gjmp2(0x8a, t); /* jp t */ - } - } - g(0x0f); - t = gjmp2((vtop->c.i - 16) ^ inv, t); - } else if (v == VT_JMP || v == VT_JMPI) { - /* && or || optimization */ - if ((v & 1) == inv) { - /* insert vtop->c jump list in t */ - uint32_t n1, n = vtop->c.i; - if (n) { - while ((n1 = read32le(cur_text_section->data + n))) - n = n1; - write32le(cur_text_section->data + n, t); - t = vtop->c.i; - } - } else { - t = gjmp(t); - gsym(vtop->c.i); - } - } - vtop--; - return t; -} - -/* generate an integer binary operation */ -void gen_opi(int op) -{ - int r, fr, opc, c; - int ll, uu, cc; - - ll = is64_type(vtop[-1].type.t); - uu = (vtop[-1].type.t & VT_UNSIGNED) != 0; - cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - - switch(op) { - case '+': - case TOK_ADDC1: /* add with carry generation */ - opc = 0; - gen_op8: - if (cc && (!ll || (int)vtop->c.i == vtop->c.i)) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - c = vtop->c.i; - if (c == (char)c) { - /* XXX: generate inc and dec for smaller code ? */ - orex(ll, r, 0, 0x83); - o(0xc0 | (opc << 3) | REG_VALUE(r)); - g(c); - } else { - orex(ll, r, 0, 0x81); - oad(0xc0 | (opc << 3) | REG_VALUE(r), c); - } - } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - orex(ll, r, fr, (opc << 3) | 0x01); - o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8); - } - vtop--; - if (op >= TOK_ULT && op <= TOK_GT) { - vtop->r = VT_CMP; - vtop->c.i = op; - } - break; - case '-': - case TOK_SUBC1: /* sub with carry generation */ - opc = 5; - goto gen_op8; - case TOK_ADDC2: /* add with carry use */ - opc = 2; - goto gen_op8; - case TOK_SUBC2: /* sub with carry use */ - opc = 3; - goto gen_op8; - case '&': - opc = 4; - goto gen_op8; - case '^': - opc = 6; - goto gen_op8; - case '|': - opc = 1; - goto gen_op8; - case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - orex(ll, fr, r, 0xaf0f); /* imul fr, r */ - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r) * 8); - vtop--; - break; - case TOK_SHL: - opc = 4; - goto gen_shift; - case TOK_SHR: - opc = 5; - goto gen_shift; - case TOK_SAR: - opc = 7; - gen_shift: - opc = 0xc0 | (opc << 3); - if (cc) { - /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); - orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ - o(opc | REG_VALUE(r)); - g(vtop->c.i & (ll ? 63 : 31)); - } else { - /* we generate the shift in ecx */ - gv2(RC_INT, RC_RCX); - r = vtop[-1].r; - orex(ll, r, 0, 0xd3); /* shl/shr/sar %cl, r */ - o(opc | REG_VALUE(r)); - } - vtop--; - break; - case TOK_UDIV: - case TOK_UMOD: - uu = 1; - goto divmod; - case '/': - case '%': - case TOK_PDIV: - uu = 0; - divmod: - /* first operand must be in eax */ - /* XXX: need better constraint for second operand */ - gv2(RC_RAX, RC_RCX); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - save_reg(TREG_RDX); - orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cqto */ - orex(ll, fr, 0, 0xf7); /* div fr, %eax */ - o((uu ? 0xf0 : 0xf8) + REG_VALUE(fr)); - if (op == '%' || op == TOK_UMOD) - r = TREG_RDX; - else - r = TREG_RAX; - vtop->r = r; - break; - default: - opc = 7; - goto gen_op8; - } -} - -void gen_opl(int op) -{ - gen_opi(op); -} - -/* generate a floating point operation 'v = t1 op t2' instruction. The - two operands are guaranteed to have the same floating point type */ -/* XXX: need to use ST1 too */ -void gen_opf(int op) -{ - int a, ft, fc, swapped, r; - int float_type = - (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; - - /* convert constants to memory references */ - if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - vswap(); - gv(float_type); - vswap(); - } - if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) - gv(float_type); - - /* must put at least one value in the floating point register */ - if ((vtop[-1].r & VT_LVAL) && - (vtop[0].r & VT_LVAL)) { - vswap(); - gv(float_type); - vswap(); - } - swapped = 0; - /* swap the stack if needed so that t1 is the register and t2 is - the memory reference */ - if (vtop[-1].r & VT_LVAL) { - vswap(); - swapped = 1; - } - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - if (op >= TOK_ULT && op <= TOK_GT) { - /* load on stack second operand */ - load(TREG_ST0, vtop); - save_reg(TREG_RAX); /* eax is used by FP comparison code */ - if (op == TOK_GE || op == TOK_GT) - swapped = !swapped; - else if (op == TOK_EQ || op == TOK_NE) - swapped = 0; - if (swapped) - o(0xc9d9); /* fxch %st(1) */ - if (op == TOK_EQ || op == TOK_NE) - o(0xe9da); /* fucompp */ - else - o(0xd9de); /* fcompp */ - o(0xe0df); /* fnstsw %ax */ - if (op == TOK_EQ) { - o(0x45e480); /* and $0x45, %ah */ - o(0x40fC80); /* cmp $0x40, %ah */ - } else if (op == TOK_NE) { - o(0x45e480); /* and $0x45, %ah */ - o(0x40f480); /* xor $0x40, %ah */ - op = TOK_NE; - } else if (op == TOK_GE || op == TOK_LE) { - o(0x05c4f6); /* test $0x05, %ah */ - op = TOK_EQ; - } else { - o(0x45c4f6); /* test $0x45, %ah */ - op = TOK_EQ; - } - vtop--; - vtop->r = VT_CMP; - vtop->c.i = op; - } else { - /* no memory reference possible for long double operations */ - load(TREG_ST0, vtop); - swapped = !swapped; - - switch(op) { - default: - case '+': - a = 0; - break; - case '-': - a = 4; - if (swapped) - a++; - break; - case '*': - a = 1; - break; - case '/': - a = 6; - if (swapped) - a++; - break; - } - ft = vtop->type.t; - fc = vtop->c.i; - o(0xde); /* fxxxp %st, %st(1) */ - o(0xc1 + (a << 3)); - vtop--; - } - } else { - if (op >= TOK_ULT && op <= TOK_GT) { - /* if saved lvalue, then we must reload it */ - r = vtop->r; - fc = vtop->c.i; - if ((r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - load(r, &v1); - fc = 0; - } - - if (op == TOK_EQ || op == TOK_NE) { - swapped = 0; - } else { - if (op == TOK_LE || op == TOK_LT) - swapped = !swapped; - if (op == TOK_LE || op == TOK_GE) { - op = 0x93; /* setae */ - } else { - op = 0x97; /* seta */ - } - } - - if (swapped) { - gv(RC_FLOAT); - vswap(); - } - assert(!(vtop[-1].r & VT_LVAL)); - - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - o(0x66); - if (op == TOK_EQ || op == TOK_NE) - o(0x2e0f); /* ucomisd */ - else - o(0x2f0f); /* comisd */ - - if (vtop->r & VT_LVAL) { - gen_modrm(vtop[-1].r, r, vtop->sym, fc); - } else { - o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); - } - - vtop--; - vtop->r = VT_CMP; - vtop->c.i = op | 0x100; - } else { - assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); - switch(op) { - default: - case '+': - a = 0; - break; - case '-': - a = 4; - break; - case '*': - a = 1; - break; - case '/': - a = 6; - break; - } - ft = vtop->type.t; - fc = vtop->c.i; - assert((ft & VT_BTYPE) != VT_LDOUBLE); - - r = vtop->r; - /* if saved lvalue, then we must reload it */ - if ((vtop->r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.i = fc; - load(r, &v1); - fc = 0; - } - - assert(!(vtop[-1].r & VT_LVAL)); - if (swapped) { - assert(vtop->r & VT_LVAL); - gv(RC_FLOAT); - vswap(); - } - - if ((ft & VT_BTYPE) == VT_DOUBLE) { - o(0xf2); - } else { - o(0xf3); - } - o(0x0f); - o(0x58 + a); - - if (vtop->r & VT_LVAL) { - gen_modrm(vtop[-1].r, r, vtop->sym, fc); - } else { - o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); - } - - vtop--; - } - } -} - -/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' - and 'long long' cases. */ -void gen_cvt_itof(int t) -{ - if ((t & VT_BTYPE) == VT_LDOUBLE) { - save_reg(TREG_ST0); - gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - /* signed long long to float/double/long double (unsigned case - is handled generically) */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%rsp) */ - o(0x08c48348); /* add $8, %rsp */ - } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED)) { - /* unsigned int to float/double/long double */ - o(0x6a); /* push $0 */ - g(0x00); - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x242cdf); /* fildll (%rsp) */ - o(0x10c48348); /* add $16, %rsp */ - } else { - /* int to float/double/long double */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ - o(0x2404db); /* fildl (%rsp) */ - o(0x08c48348); /* add $8, %rsp */ - } - vtop->r = TREG_ST0; - } else { - int r = get_reg(RC_FLOAT); - gv(RC_INT); - o(0xf2 + ((t & VT_BTYPE) == VT_FLOAT?1:0)); - if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED) || - (vtop->type.t & VT_BTYPE) == VT_LLONG) { - o(0x48); /* REX */ - } - o(0x2a0f); - o(0xc0 + (vtop->r & VT_VALMASK) + REG_VALUE(r)*8); /* cvtsi2sd */ - vtop->r = r; - } -} - -/* convert from one floating point type to another */ -void gen_cvt_ftof(int t) -{ - int ft, bt, tbt; - - ft = vtop->type.t; - bt = ft & VT_BTYPE; - tbt = t & VT_BTYPE; - - if (bt == VT_FLOAT) { - gv(RC_FLOAT); - if (tbt == VT_DOUBLE) { - o(0x140f); /* unpcklps */ - o(0xc0 + REG_VALUE(vtop->r)*9); - o(0x5a0f); /* cvtps2pd */ - o(0xc0 + REG_VALUE(vtop->r)*9); - } else if (tbt == VT_LDOUBLE) { - save_reg(RC_ST0); - /* movss %xmm0,-0x10(%rsp) */ - o(0x110ff3); - o(0x44 + REG_VALUE(vtop->r)*8); - o(0xf024); - o(0xf02444d9); /* flds -0x10(%rsp) */ - vtop->r = TREG_ST0; - } - } else if (bt == VT_DOUBLE) { - gv(RC_FLOAT); - if (tbt == VT_FLOAT) { - o(0x140f66); /* unpcklpd */ - o(0xc0 + REG_VALUE(vtop->r)*9); - o(0x5a0f66); /* cvtpd2ps */ - o(0xc0 + REG_VALUE(vtop->r)*9); - } else if (tbt == VT_LDOUBLE) { - save_reg(RC_ST0); - /* movsd %xmm0,-0x10(%rsp) */ - o(0x110ff2); - o(0x44 + REG_VALUE(vtop->r)*8); - o(0xf024); - o(0xf02444dd); /* fldl -0x10(%rsp) */ - vtop->r = TREG_ST0; - } - } else { - int r; - gv(RC_ST0); - r = get_reg(RC_FLOAT); - if (tbt == VT_DOUBLE) { - o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmm0 */ - o(0x100ff2); - o(0x44 + REG_VALUE(r)*8); - o(0xf024); - vtop->r = r; - } else if (tbt == VT_FLOAT) { - o(0xf0245cd9); /* fstps -0x10(%rsp) */ - /* movss -0x10(%rsp),%xmm0 */ - o(0x100ff3); - o(0x44 + REG_VALUE(r)*8); - o(0xf024); - vtop->r = r; - } - } -} - -/* convert fp to int 't' type */ -void gen_cvt_ftoi(int t) -{ - int ft, bt, size, r; - ft = vtop->type.t; - bt = ft & VT_BTYPE; - if (bt == VT_LDOUBLE) { - gen_cvt_ftof(VT_DOUBLE); - bt = VT_DOUBLE; - } - - gv(RC_FLOAT); - if (t != VT_INT) - size = 8; - else - size = 4; - - r = get_reg(RC_INT); - if (bt == VT_FLOAT) { - o(0xf3); - } else if (bt == VT_DOUBLE) { - o(0xf2); - } else { - assert(0); - } - orex(size == 8, r, 0, 0x2c0f); /* cvttss2si or cvttsd2si */ - o(0xc0 + REG_VALUE(vtop->r) + REG_VALUE(r)*8); - vtop->r = r; -} - -/* computed goto support */ -void ggoto(void) -{ - gcall_or_jmp(1); - vtop--; -} - -/* Save the stack pointer onto the stack and return the location of its address */ -ST_FUNC void gen_vla_sp_save(int addr) { - /* mov %rsp,addr(%rbp)*/ - gen_modrm64(0x89, TREG_RSP, VT_LOCAL, NULL, addr); -} - -/* Restore the SP from a location on the stack */ -ST_FUNC void gen_vla_sp_restore(int addr) { - gen_modrm64(0x8b, TREG_RSP, VT_LOCAL, NULL, addr); -} - -/* Subtract from the stack pointer, and push the resulting value onto the stack */ -ST_FUNC void gen_vla_alloc(CType *type, int align) { -#ifdef TCC_TARGET_PE - /* alloca does more than just adjust %rsp on Windows */ - vpush_global_sym(&func_old_type, TOK_alloca); - vswap(); /* Move alloca ref past allocation size */ - gfunc_call(1); -#else - int r; - r = gv(RC_INT); /* allocation size */ - /* sub r,%rsp */ - o(0x2b48); - o(0xe0 | REG_VALUE(r)); - /* We align to 16 bytes rather than align */ - /* and ~15, %rsp */ - o(0xf0e48348); - vpop(); -#endif -} - - -/* end of x86-64 code generator */ -/*************************************************************/ -#endif /* ! TARGET_DEFS_ONLY */ -/******************************************************/ diff --git a/tinyc/x86_64-link.c b/tinyc/x86_64-link.c deleted file mode 100644 index c0c5e13bf..000000000 --- a/tinyc/x86_64-link.c +++ /dev/null @@ -1,295 +0,0 @@ -#ifdef TARGET_DEFS_ONLY - -#define EM_TCC_TARGET EM_X86_64 - -/* relocation type for 32 bit data relocation */ -#define R_DATA_32 R_X86_64_32S -#define R_DATA_PTR R_X86_64_64 -#define R_JMP_SLOT R_X86_64_JUMP_SLOT -#define R_GLOB_DAT R_X86_64_GLOB_DAT -#define R_COPY R_X86_64_COPY -#define R_RELATIVE R_X86_64_RELATIVE - -#define R_NUM R_X86_64_NUM - -#define ELF_START_ADDR 0x400000 -#define ELF_PAGE_SIZE 0x200000 - -#define PCRELATIVE_DLLPLT 1 -#define RELOCATE_DLLPLT 1 - -#else /* !TARGET_DEFS_ONLY */ - -#include "tcc.h" - -/* Returns 1 for a code relocation, 0 for a data relocation. For unknown - relocations, returns -1. */ -int code_reloc (int reloc_type) -{ - switch (reloc_type) { - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPC64: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_GOTTPOFF: - case R_X86_64_GOT32: - case R_X86_64_GOT64: - case R_X86_64_GLOB_DAT: - case R_X86_64_COPY: - case R_X86_64_RELATIVE: - case R_X86_64_GOTOFF64: - return 0; - - case R_X86_64_PC32: - case R_X86_64_PC64: - case R_X86_64_PLT32: - case R_X86_64_PLTOFF64: - case R_X86_64_JUMP_SLOT: - return 1; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -/* Returns an enumerator to describe whether and when the relocation needs a - GOT and/or PLT entry to be created. See tcc.h for a description of the - different values. */ -int gotplt_entry_type (int reloc_type) -{ - switch (reloc_type) { - case R_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: - case R_X86_64_COPY: - case R_X86_64_RELATIVE: - return NO_GOTPLT_ENTRY; - - /* The following relocs wouldn't normally need GOT or PLT - slots, but we need them for simplicity in the link - editor part. See our caller for comments. */ - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_PC32: - case R_X86_64_PC64: - return AUTO_GOTPLT_ENTRY; - - case R_X86_64_GOTTPOFF: - return BUILD_GOT_ONLY; - - case R_X86_64_GOT32: - case R_X86_64_GOT64: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPC64: - case R_X86_64_GOTOFF64: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PLT32: - case R_X86_64_PLTOFF64: - return ALWAYS_GOTPLT_ENTRY; - } - - tcc_error ("Unknown relocation type: %d", reloc_type); - return -1; -} - -ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) -{ - Section *plt = s1->plt; - uint8_t *p; - int modrm; - unsigned plt_offset, relofs; - - modrm = 0x25; - - /* empty PLT: create PLT0 entry that pushes the library identifier - (GOT + PTR_SIZE) and jumps to ld.so resolution routine - (GOT + 2 * PTR_SIZE) */ - if (plt->data_offset == 0) { - p = section_ptr_add(plt, 16); - p[0] = 0xff; /* pushl got + PTR_SIZE */ - p[1] = modrm + 0x10; - write32le(p + 2, PTR_SIZE); - p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ - p[7] = modrm; - write32le(p + 8, PTR_SIZE * 2); - } - plt_offset = plt->data_offset; - - /* The PLT slot refers to the relocation entry it needs via offset. - The reloc entry is created below, so its offset is the current - data_offset */ - relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; - - /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ - p = section_ptr_add(plt, 16); - p[0] = 0xff; /* jmp *(got + x) */ - p[1] = modrm; - write32le(p + 2, got_offset); - p[6] = 0x68; /* push $xxx */ - /* On x86-64, the relocation is referred to by _index_ */ - write32le(p + 7, relofs / sizeof (ElfW_Rel)); - p[11] = 0xe9; /* jmp plt_start */ - write32le(p + 12, -(plt->data_offset)); - return plt_offset; -} - -/* relocate the PLT: compute addresses and offsets in the PLT now that final - address for PLT and GOT are known (see fill_program_header) */ -ST_FUNC void relocate_plt(TCCState *s1) -{ - uint8_t *p, *p_end; - - if (!s1->plt) - return; - - p = s1->plt->data; - p_end = p + s1->plt->data_offset; - - if (p < p_end) { - int x = s1->got->sh_addr - s1->plt->sh_addr - 6; - add32le(p + 2, x); - add32le(p + 8, x - 6); - p += 16; - while (p < p_end) { - add32le(p + 2, x + s1->plt->data - p); - p += 16; - } - } -} - -static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ - -void relocate_init(Section *sr) -{ - qrel = (ElfW_Rel *) sr->data; -} - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) -{ - int sym_index, esym_index; - - sym_index = ELFW(R_SYM)(rel->r_info); - - switch (type) { - case R_X86_64_64: - if (s1->output_type == TCC_OUTPUT_DLL) { - esym_index = s1->sym_attrs[sym_index].dyn_index; - qrel->r_offset = rel->r_offset; - if (esym_index) { - qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); - qrel->r_addend = rel->r_addend; - qrel++; - break; - } else { - qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); - qrel->r_addend = read64le(ptr) + val; - qrel++; - } - } - add64le(ptr, val); - break; - case R_X86_64_32: - case R_X86_64_32S: - if (s1->output_type == TCC_OUTPUT_DLL) { - /* XXX: this logic may depend on TCC's codegen - now TCC uses R_X86_64_32 even for a 64bit pointer */ - qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); - /* Use sign extension! */ - qrel->r_addend = (int)read32le(ptr) + val; - qrel++; - } - add32le(ptr, val); - break; - - case R_X86_64_PC32: - if (s1->output_type == TCC_OUTPUT_DLL) { - /* DLL relocation */ - esym_index = s1->sym_attrs[sym_index].dyn_index; - if (esym_index) { - qrel->r_offset = rel->r_offset; - qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); - /* Use sign extension! */ - qrel->r_addend = (int)read32le(ptr) + rel->r_addend; - qrel++; - break; - } - } - goto plt32pc32; - - case R_X86_64_PLT32: - /* fallthrough: val already holds the PLT slot address */ - - plt32pc32: - { - long long diff; - diff = (long long)val - addr; - if (diff < -2147483648LL || diff > 2147483647LL) { - tcc_error("internal error: relocation failed"); - } - add32le(ptr, diff); - } - break; - - case R_X86_64_PLTOFF64: - add64le(ptr, val - s1->got->sh_addr + rel->r_addend); - break; - - case R_X86_64_PC64: - if (s1->output_type == TCC_OUTPUT_DLL) { - /* DLL relocation */ - esym_index = s1->sym_attrs[sym_index].dyn_index; - if (esym_index) { - qrel->r_offset = rel->r_offset; - qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC64); - qrel->r_addend = read64le(ptr) + rel->r_addend; - qrel++; - break; - } - } - add64le(ptr, val - addr); - break; - - case R_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: - /* They don't need addend */ - write64le(ptr, val - rel->r_addend); - break; - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - add32le(ptr, s1->got->sh_addr - addr + - s1->sym_attrs[sym_index].got_offset - 4); - break; - case R_X86_64_GOTPC32: - add32le(ptr, s1->got->sh_addr - addr + rel->r_addend); - break; - case R_X86_64_GOTPC64: - add64le(ptr, s1->got->sh_addr - addr + rel->r_addend); - break; - case R_X86_64_GOTTPOFF: - add32le(ptr, val - s1->got->sh_addr); - break; - case R_X86_64_GOT32: - /* we load the got offset */ - add32le(ptr, s1->sym_attrs[sym_index].got_offset); - break; - case R_X86_64_GOT64: - /* we load the got offset */ - add64le(ptr, s1->sym_attrs[sym_index].got_offset); - break; - case R_X86_64_GOTOFF64: - add64le(ptr, val - s1->got->sh_addr); - break; - case R_X86_64_RELATIVE: - /* do nothing */ - break; - } -} - -#endif /* !TARGET_DEFS_ONLY */ diff --git a/tools/deps.nim b/tools/deps.nim new file mode 100644 index 000000000..888237761 --- /dev/null +++ b/tools/deps.nim @@ -0,0 +1,22 @@ +import os, uri, strformat + +proc exec(cmd: string) = + echo "deps.cmd: " & cmd + let status = execShellCmd(cmd) + doAssert status == 0, cmd + +const commitHead* = "HEAD" + +proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, appendRepoName = true) = + let destDirBase = destDirBase.absolutePath + let p = url.parseUri.path + let name = p.splitFile.name + var destDir = destDirBase + if appendRepoName: destDir = destDir / name + let destDir2 = destDir.quoteShell + if not dirExists(destDir): + # note: old code used `destDir / .git` but that wouldn't prevent git clone + # from failing + exec fmt"git clone -q {url} {destDir2}" + exec fmt"git -C {destDir2} fetch -q" + exec fmt"git -C {destDir2} checkout -q {commit}" From 87e6b88f3bbb64898e30033da974fcef751375c4 Mon Sep 17 00:00:00 2001 From: itsumura-h <39766805+itsumura-h@users.noreply.github.com> Date: Fri, 3 Apr 2020 16:38:05 +0900 Subject: [PATCH 0281/4254] fix #7241 (#13779) finalize() should run in insert() --- lib/impure/db_sqlite.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 74ba169aa..810638fb8 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -184,6 +184,9 @@ proc tryExec*(db: DbConn, query: SqlQuery, let x = step(stmt) if x in {SQLITE_DONE, SQLITE_ROW}: result = finalize(stmt) == SQLITE_OK + else: + discard finalize(stmt) + result = false proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {. tags: [ReadDbEffect, WriteDbEffect].} = @@ -531,6 +534,8 @@ proc tryInsertID*(db: DbConn, query: SqlQuery, result = last_insert_rowid(db) if finalize(stmt) != SQLITE_OK: result = -1 + else: + discard finalize(stmt) proc insertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect].} = From 2b3b24a8048364eb9dbd52e5a898c948b35501d8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 3 Apr 2020 10:25:15 +0200 Subject: [PATCH 0282/4254] make bootstrapping more robust for people who have Nim inside /usr/bin (#13855) --- compiler/vmops.nim | 60 ++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 8cb2a0552..0ee137178 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -102,34 +102,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode = result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord), newStrNode(nkStrLit, f)) -from std / compilesettings import SingleValueSetting, MultipleValueSetting +when defined(nimHasInvariant): + from std / compilesettings import SingleValueSetting, MultipleValueSetting -proc querySettingImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): string = - case SingleValueSetting(switch) - of arguments: result = conf.arguments - of outFile: result = conf.outFile.string - of outDir: result = conf.outDir.string - of nimcacheDir: result = conf.nimcacheDir.string - of projectName: result = conf.projectName - of projectPath: result = conf.projectPath.string - of projectFull: result = conf.projectFull.string - of command: result = conf.command - of commandLine: result = conf.commandLine - of linkOptions: result = conf.linkOptions - of compileOptions: result = conf.compileOptions - of ccompilerPath: result = conf.cCompilerPath + proc querySettingImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): string = + case SingleValueSetting(switch) + of arguments: result = conf.arguments + of outFile: result = conf.outFile.string + of outDir: result = conf.outDir.string + of nimcacheDir: result = conf.nimcacheDir.string + of projectName: result = conf.projectName + of projectPath: result = conf.projectPath.string + of projectFull: result = conf.projectFull.string + of command: result = conf.command + of commandLine: result = conf.commandLine + of linkOptions: result = conf.linkOptions + of compileOptions: result = conf.compileOptions + of ccompilerPath: result = conf.cCompilerPath -proc querySettingSeqImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): seq[string] = - template copySeq(field: untyped): untyped = - for i in field: result.add i.string + proc querySettingSeqImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): seq[string] = + template copySeq(field: untyped): untyped = + for i in field: result.add i.string - case MultipleValueSetting(switch) - of nimblePaths: copySeq(conf.nimblePaths) - of searchPaths: copySeq(conf.searchPaths) - of lazyPaths: copySeq(conf.lazyPaths) - of commandArgs: result = conf.commandArgs - of cincludes: copySeq(conf.cIncludes) - of clibs: copySeq(conf.cLibs) + case MultipleValueSetting(switch) + of nimblePaths: copySeq(conf.nimblePaths) + of searchPaths: copySeq(conf.searchPaths) + of lazyPaths: copySeq(conf.lazyPaths) + of commandArgs: result = conf.commandArgs + of cincludes: copySeq(conf.cIncludes) + of clibs: copySeq(conf.cLibs) proc registerAdditionalOps*(c: PCtx) = proc gorgeExWrapper(a: VmArgs) = @@ -181,10 +182,11 @@ proc registerAdditionalOps*(c: PCtx) = systemop getCurrentException registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) - registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} = - setResult(a, querySettingImpl(a, c.config, getInt(a, 0))) - registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} = - setResult(a, querySettingSeqImpl(a, c.config, getInt(a, 0))) + when defined(nimHasInvariant): + registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} = + setResult(a, querySettingImpl(a, c.config, getInt(a, 0))) + registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} = + setResult(a, querySettingSeqImpl(a, c.config, getInt(a, 0))) if defined(nimsuggest) or c.config.cmd == cmdCheck: discard "don't run staticExec for 'nim suggest'" From 920add5880e74695025d2383dd6806c51bd831b5 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Fri, 3 Apr 2020 13:06:23 +0300 Subject: [PATCH 0283/4254] sourcemaps for the JS codegen (#7508) --- compiler/commands.nim | 4 + compiler/jsgen.nim | 42 ++++- compiler/options.nim | 2 + compiler/sourcemap.nim | 385 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+), 9 deletions(-) create mode 100644 compiler/sourcemap.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 4caccd165..babdd5871 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -890,6 +890,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optPanics}, arg, pass, info) if optPanics in conf.globalOptions: defineSymbol(conf.symbols, "nimPanics") + of "sourcemap": + conf.globalOptions.incl optSourcemap + conf.options.incl optLineDir + # processOnOffSwitchG(conf, {optSourcemap, opt}, arg, pass, info) of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) handleStdinInput(conf) else: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index e63ce7489..c41f89a88 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -33,7 +33,7 @@ import nversion, msgs, idents, types, tables, ropes, math, passes, ccgutils, wordrecg, renderer, intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - transf, injectdestructors + transf, injectdestructors, sourcemap, json, sets from modulegraphs import ModuleGraph, PPassContext @@ -205,6 +205,8 @@ proc mapType(typ: PType): TJSTypeKind = proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) +var mangled = initSet[string]() + proc mangleName(m: BModule, s: PSym): Rope = proc validJsName(name: string): bool = result = true @@ -259,6 +261,11 @@ proc mangleName(m: BModule, s: PSym): Rope = result.add(rope(s.id)) s.loc.r = result + # TODO: optimize + let s = $result + if '_' in s: + mangled.incl(s) + proc escapeJSString(s: string): string = result = newStringOfCap(s.len + s.len shr 2) result.add("\"") @@ -641,11 +648,16 @@ proc hasFrameInfo(p: PProc): bool = ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and ((p.prc == nil) or not (sfPure in p.prc.flags)) +proc lineDir(config: ConfigRef, info: TLineInfo, line: int): Rope = + ropes.`%`("// line $2 \"$1\"$n", + [rope(toFullPath(config, info)), rope(line)]) + proc genLineDir(p: PProc, n: PNode) = let line = toLinenumber(n.info) - if optLineDir in p.options: - lineF(p, "// line $2 \"$1\"$n", - [rope(toFilename(p.config, n.info)), rope(line)]) + if line < 0: + return + if optLineDir in p.options or optLineDir in p.config.options: + lineF(p, "$1", [lineDir(p.config, n.info, line)]) if hasFrameInfo(p): lineF(p, "F.line = $1;$n", [rope(line)]) @@ -2241,6 +2253,10 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = p.nested: genStmt(p, transformedBody) + + if optLineDir in p.config.options: + result = lineDir(p.config, prc.info, toLinenumber(prc.info)) + var def: Rope if not prc.constraint.isNil: def = runtimeFormat(prc.constraint.strVal & " {$n$#$#$#$#$#", @@ -2253,7 +2269,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = optionalLine(genProcBody(p, prc)), optionalLine(p.indentLine(returnStmt))]) else: - result = ~"\L" + # if optLineDir in p.config.options: + # result.add(~"\L") if p.config.hcrOn: # Here, we introduce thunks that create the equivalent of a jump table @@ -2336,6 +2353,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = if r.kind != resCallee: r.kind = resNone #r.address = nil r.res = nil + case n.kind of nkSym: genSym(p, n, r) @@ -2382,14 +2400,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = else: r.res = rope(f.toStrMaxPrecision) r.kind = resExpr of nkCallKinds: - if isEmptyType(n.typ): genLineDir(p, n) + if isEmptyType(n.typ): + genLineDir(p, n) if (n[0].kind == nkSym) and (n[0].sym.magic != mNone): genMagic(p, n, r) elif n[0].kind == nkSym and sfInfixCall in n[0].sym.flags and n.len >= 1: genInfixCall(p, n, r) else: - genCall(p, n, r) + genCall(p, n, r) of nkClosure: gen(p, n[0], r) of nkCurly: genSetConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r) @@ -2585,10 +2604,15 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = n.add destructorCall if passes.skipCodegen(m.config, n): return n if sfMainModule in m.module.flags: - let code = wholeCode(graph, m) + var code = genHeader() & wholeCode(graph, m) let outFile = m.config.prepareToWriteOutput() - discard writeRopeIfNotEqual(genHeader() & code, outFile) + if optSourcemap in m.config.globalOptions: + var map: SourceMap + (code, map) = genSourceMap($(code), mangled, outFile.string) + writeFile(outFile.string & ".map", $(%map)) + discard writeRopeIfNotEqual(code, outFile) + proc myOpen(graph: ModuleGraph; s: PSym): PPassContext = result = newModule(graph, s) diff --git a/compiler/options.nim b/compiler/options.nim index 8b2523478..013c12b50 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -44,6 +44,7 @@ type # please make sure we have under 32 options optOldAst, optSinkInference # 'sink T' inference + TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** gloptNone, optForceFullMake, @@ -94,6 +95,7 @@ type # please make sure we have under 32 options optProduceAsm # produce assembler code optPanics # turn panics (sysFatal) into a process termination optNimV1Emulation # emulate Nim v1.0 + optSourcemap TGlobalOptions* = set[TGlobalOption] diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim new file mode 100644 index 000000000..1aa294371 --- /dev/null +++ b/compiler/sourcemap.nim @@ -0,0 +1,385 @@ +import os, strformat, strutils, tables, sets, ropes, json, algorithm + +type + SourceNode* = ref object + line*: int + column*: int + source*: string + name*: string + children*: seq[Child] + + C = enum cSourceNode, cString + + Child* = ref object + case kind*: C: + of cSourceNode: + node*: SourceNode + of cString: + s*: string + + SourceMap* = ref object + version*: int + sources*: seq[string] + names*: seq[string] + mappings*: string + file*: string + # sourceRoot*: string + # sourcesContent*: string + + SourceMapGenerator = ref object + file: string + sourceRoot: string + skipValidation: bool + sources: seq[string] + names: seq[string] + mappings: seq[Mapping] + + Mapping* = ref object + source*: string + original*: tuple[line: int, column: int] + generated*: tuple[line: int, column: int] + name*: string + noSource*: bool + noName*: bool + + +proc child*(s: string): Child = + Child(kind: cString, s: s) + + +proc child*(node: SourceNode): Child = + Child(kind: cSourceNode, node: node) + + +proc newSourceNode(line: int, column: int, path: string, node: SourceNode, name: string = ""): SourceNode = + SourceNode(line: line, column: column, source: path, name: name, children: @[child(node)]) + + +proc newSourceNode(line: int, column: int, path: string, s: string, name: string = ""): SourceNode = + SourceNode(line: line, column: column, source: path, name: name, children: @[child(s)]) + + +proc newSourceNode(line: int, column: int, path: string, children: seq[Child], name: string = ""): SourceNode = + SourceNode(line: line, column: column, source: path, name: name, children: children) + + + + +# debugging + + +proc text*(sourceNode: SourceNode, depth: int): string = + let empty = " " + result = &"{repeat(empty, depth)}SourceNode({sourceNode.source}:{sourceNode.line}:{sourceNode.column}):\n" + for child in sourceNode.children: + if child.kind == cString: + result.add(&"{repeat(empty, depth + 1)}{child.s}\n") + else: + result.add(child.node.text(depth + 1)) + + +proc `$`*(sourceNode: SourceNode): string = + text(sourceNode, 0) + + +# base64_VLQ + + +let integers = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + + +proc encode*(i: int): string = + result = "" + var n = i + if n < 0: + n = (-n shl 1) or 1 + else: + n = n shl 1 + + var z = 0 + while z == 0 or n > 0: + var e = n and 31 + n = n shr 5 + if n > 0: + e = e or 32 + + result.add(integers[e]) + z += 1 + + +type + TokenState = enum Normal, String, Ident, Mangled + +iterator tokenize*(line: string): (bool, string) = + # result = @[] + var state = Normal + var token = "" + var isMangled = false + for z, ch in line: + if ch.isAlphaAscii: + if state == Normal: + state = Ident + if token.len > 0: + yield (isMangled, token) + token = $ch + isMangled = false + else: + token.add(ch) + elif ch == '_': + if state == Ident: + state = Mangled + isMangled = true + token.add($ch) + elif ch != '"' and not ch.isAlphaNumeric: + if state in {Ident, Mangled}: + state = Normal + if token.len > 0: + yield (isMangled, token) + token = $ch + isMangled = false + else: + token.add($ch) + elif ch == '"': + if state != String: + state = String + if token.len > 0: + yield (isMangled, token) + token = $ch + isMangled = false + else: + state = Normal + token.add($ch) + if token.len > 0: + yield (isMangled, token) + isMangled = false + token = "" + else: + token.add($ch) + if token.len > 0: + yield (isMangled, token) + +proc parse*(source: string, path: string, mangled: HashSet[string]): SourceNode = + let lines = source.splitLines() + var lastLocation: SourceNode = nil + result = newSourceNode(0, 0, path, @[]) + + # we just use one single parent and add all nim lines + # as its children, I guess in typical codegen + # that happens recursively on ast level + # we also don't have column info, but I doubt more one nim lines can compile to one js + # maybe in macros? + + for i, originalLine in lines: + let line = originalLine.strip + if line.len == 0: + continue + + # this shouldn't be a problem: + # jsgen doesn't generate comments + # and if you emit // line you probably know what you're doing + if line.startsWith("// line"): + if result.children.len > 0: + result.children[^1].node.children.add(child(line & "\n")) + let pos = line.find(" ", 8) + let lineNumber = line[8 .. pos - 1].parseInt + let linePath = line[pos + 2 .. ^2] # quotes + + lastLocation = newSourceNode( + lineNumber, + 0, + linePath, + @[]) + result.children.add(child(lastLocation)) + else: + var last: SourceNode + for token in line.tokenize(): + var name = "" + if token[0]: + name = token[1].split('_', 1)[0] + + + if result.children.len > 0: + result.children[^1].node.children.add( + child( + newSourceNode( + result.children[^1].node.line, + 0, + result.children[^1].node.source, + token[1], + name))) + last = result.children[^1].node.children[^1].node + else: + result.children.add( + child( + newSourceNode(i + 1, 0, path, token[1], name))) + last = result.children[^1].node + let nl = "\n" + if not last.isNil: + last.source.add(nl) + +proc cmp(a: Mapping, b: Mapping): int = + var c = cmp(a.generated, b.generated) + if c != 0: + return c + + c = cmp(a.source, b.source) + if c != 0: + return c + + c = cmp(a.original, b.original) + if c != 0: + return c + + return cmp(a.name, b.name) + + +proc index*[T](elements: seq[T], element: T): int = + for z in 0 ..< elements.len: + if elements[z] == element: + return z + return -1 + + +proc serializeMappings(map: SourceMapGenerator, mappings: seq[Mapping]): string = + var previous = Mapping(generated: (line: 1, column: 0), original: (line: 0, column: 0), name: "", source: "") + var previousSourceId = 0 + var previousNameId = 0 + result = "" + var next = "" + var nameId = 0 + var sourceId = 0 + + for z, mapping in mappings: + next = "" + + if mapping.generated.line != previous.generated.line: + previous.generated.column = 0 + + while mapping.generated.line != previous.generated.line: + next.add(";") + previous.generated.line += 1 + + else: + if z > 0: + if cmp(mapping, mappings[z - 1]) == 0: + continue + next.add(",") + + next.add(encode(mapping.generated.column - previous.generated.column)) + previous.generated.column = mapping.generated.column + + if not mapping.noSource and mapping.source.len > 0: + sourceId = map.sources.index(mapping.source) + next.add(encode(sourceId - previousSourceId)) + previousSourceId = sourceId + next.add(encode(mapping.original.line - 1 - previous.original.line)) + previous.original.line = mapping.original.line - 1 + next.add(encode(mapping.original.column - previous.original.column)) + previous.original.column = mapping.original.column + + if not mapping.noName and mapping.name.len > 0: + nameId = map.names.index(mapping.name) + next.add(encode(nameId - previousNameId)) + previousNameId = nameId + + result.add(next) + + +proc gen*(map: SourceMapGenerator): SourceMap = + var mappings = map.mappings.sorted do (a: Mapping, b: Mapping) -> int: + cmp(a, b) + result = SourceMap( + file: map.file, + version: 3, + sources: map.sources[0..^1], + names: map.names[0..^1], + mappings: map.serializeMappings(mappings)) + + + +proc addMapping*(map: SourceMapGenerator, mapping: Mapping) = + if not mapping.noSource and mapping.source notin map.sources: + map.sources.add(mapping.source) + + if not mapping.noName and mapping.name.len > 0 and mapping.name notin map.names: + map.names.add(mapping.name) + + # echo "map ", mapping.source, " ", mapping.original, " ", mapping.generated, " ", mapping.name + map.mappings.add(mapping) + + +proc walk*(node: SourceNode, fn: proc(line: string, original: SourceNode)) = + for child in node.children: + if child.kind == cString and child.s.len > 0: + fn(child.s, node) + else: + child.node.walk(fn) + + +proc toSourceMap*(node: SourceNode, file: string): SourceMapGenerator = + var map = SourceMapGenerator(file: file, sources: @[], names: @[], mappings: @[]) + + var generated = (line: 1, column: 0) + var sourceMappingActive = false + var lastOriginal = SourceNode(source: "", line: -1, column: 0, name: "", children: @[]) + + node.walk do (line: string, original: SourceNode): + if original.source.endsWith(".js"): + # ignore it + discard + else: + if original.line != -1: + if lastOriginal.source != original.source or + lastOriginal.line != original.line or + lastOriginal.column != original.column or + lastOriginal.name != original.name: + map.addMapping( + Mapping( + source: original.source, + original: (line: original.line, column: original.column), + generated: (line: generated.line, column: generated.column), + name: original.name)) + + lastOriginal = SourceNode( + source: original.source, + line: original.line, + column: original.column, + name: original.name, + children: lastOriginal.children) + sourceMappingActive = true + elif sourceMappingActive: + map.addMapping( + Mapping( + noSource: true, + noName: true, + generated: (line: generated.line, column: generated.column), + original: (line: -1, column: -1))) + lastOriginal.line = -1 + sourceMappingActive = false + + for z in 0 ..< line.len: + if line[z] in Newlines: + generated.line += 1 + generated.column = 0 + + if z == line.len - 1: + lastOriginal.line = -1 + sourceMappingActive = false + elif sourceMappingActive: + map.addMapping( + Mapping( + source: original.source, + original: (line: original.line, column: original.column), + generated: (line: generated.line, column: generated.column), + name: original.name)) + else: + generated.column += 1 + + map + + +proc genSourceMap*(source: string, mangled: HashSet[string], outFile: string): (Rope, SourceMap) = + let node = parse(source, outFile, mangled) + let map = node.toSourceMap(file = outFile) + ((&"{source}\n//# sourceMappingURL={outFile}.map").rope, map.gen) + From cec320b56938cac42c2457dd4d362419b554d456 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Fri, 3 Apr 2020 21:22:03 +0300 Subject: [PATCH 0284/4254] Remove my wrongly written mangled-related code, not needed anymore (#13858) --- compiler/jsgen.nim | 9 +-------- compiler/sourcemap.nim | 6 +++--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c41f89a88..eabc8306d 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -205,8 +205,6 @@ proc mapType(typ: PType): TJSTypeKind = proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) -var mangled = initSet[string]() - proc mangleName(m: BModule, s: PSym): Rope = proc validJsName(name: string): bool = result = true @@ -261,11 +259,6 @@ proc mangleName(m: BModule, s: PSym): Rope = result.add(rope(s.id)) s.loc.r = result - # TODO: optimize - let s = $result - if '_' in s: - mangled.incl(s) - proc escapeJSString(s: string): string = result = newStringOfCap(s.len + s.len shr 2) result.add("\"") @@ -2609,7 +2602,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if optSourcemap in m.config.globalOptions: var map: SourceMap - (code, map) = genSourceMap($(code), mangled, outFile.string) + (code, map) = genSourceMap($(code), outFile.string) writeFile(outFile.string & ".map", $(%map)) discard writeRopeIfNotEqual(code, outFile) diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim index 1aa294371..90e34eb73 100644 --- a/compiler/sourcemap.nim +++ b/compiler/sourcemap.nim @@ -158,7 +158,7 @@ iterator tokenize*(line: string): (bool, string) = if token.len > 0: yield (isMangled, token) -proc parse*(source: string, path: string, mangled: HashSet[string]): SourceNode = +proc parse*(source: string, path: string): SourceNode = let lines = source.splitLines() var lastLocation: SourceNode = nil result = newSourceNode(0, 0, path, @[]) @@ -378,8 +378,8 @@ proc toSourceMap*(node: SourceNode, file: string): SourceMapGenerator = map -proc genSourceMap*(source: string, mangled: HashSet[string], outFile: string): (Rope, SourceMap) = - let node = parse(source, outFile, mangled) +proc genSourceMap*(source: string, outFile: string): (Rope, SourceMap) = + let node = parse(source, outFile) let map = node.toSourceMap(file = outFile) ((&"{source}\n//# sourceMappingURL={outFile}.map").rope, map.gen) From ed44e524b055b985b0941227a61f84dd8fdfcb37 Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 3 Apr 2020 21:28:11 +0200 Subject: [PATCH 0285/4254] bump devel version to 1.3.1 --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 469821fab..f9ebe26b4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2049,7 +2049,7 @@ const NimMajor* {.intdefine.}: int = 1 ## is the major number of Nim's version. - NimMinor* {.intdefine.}: int = 1 + NimMinor* {.intdefine.}: int = 3 ## is the minor number of Nim's version. NimPatch* {.intdefine.}: int = 1 From 9c46927fad6535cf7e172f5af5e93d179cec1020 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Apr 2020 22:56:03 +0200 Subject: [PATCH 0286/4254] new feature: ability to turn specific warnings to errors --- changelog.md | 1 + compiler/commands.nim | 17 ++++++++++++----- compiler/msgs.nim | 7 ++++--- compiler/options.nim | 1 + compiler/pragmas.nim | 35 ++++++++++++++++------------------- compiler/semdata.nim | 4 ++++ compiler/wordrecg.nim | 5 +++-- doc/advopt.txt | 2 ++ 8 files changed, 43 insertions(+), 29 deletions(-) diff --git a/changelog.md b/changelog.md index 139bdc832..77a757b1d 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,7 @@ ## Compiler changes +- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index babdd5871..47dbcfa90 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -209,12 +209,18 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, incl(conf.modifiedyNotes, n) case val of "on": - incl(conf.notes, n) - incl(conf.mainPackageNotes, n) + if state == wWarningAsError: + incl(conf.warningAsErrors, n) + else: + incl(conf.notes, n) + incl(conf.mainPackageNotes, n) of "off": - excl(conf.notes, n) - excl(conf.mainPackageNotes, n) - excl(conf.foreignPackageNotes, n) + if state == wWarningAsError: + excl(conf.warningAsErrors, n) + else: + excl(conf.notes, n) + excl(conf.mainPackageNotes, n) + excl(conf.foreignPackageNotes, n) proc processCompile(conf: ConfigRef; filename: string) = var found = findFile(conf, filename) @@ -528,6 +534,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf) + of "warningaserror": processSpecificNote(arg, wWarningAsError, pass, info, switch, conf) of "hints": if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6d1ecb2b1..6fdd4931b 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -354,7 +354,8 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) if msg >= fatalMin and msg <= fatalMax: if conf.cmd == cmdIdeTools: log(s) quit(conf, msg) - if msg >= errMin and msg <= errMax: + if msg >= errMin and msg <= errMax or + (msg in warnMin..warnMax and msg in conf.warningAsErrors): inc(conf.errorCounter) conf.exitcode = 1'i8 if conf.errorCounter >= conf.errorMax: @@ -412,7 +413,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = sev = Severity.Warning if not conf.hasWarn(msg): return writeContext(conf, unknownLineInfo) - title = WarningTitle + title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(conf.warnCounter) @@ -500,7 +501,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, sev = Severity.Warning ignoreMsg = not conf.hasWarn(msg) if not ignoreMsg: writeContext(conf, info) - title = WarningTitle + title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(conf.warnCounter) diff --git a/compiler/options.nim b/compiler/options.nim index 013c12b50..038e83eb0 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -237,6 +237,7 @@ type cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline foreignPackageNotes*: TNoteKinds notes*: TNoteKinds # notes after resolving all logic(defaults, verbosity)/cmdline/configs + warningAsErrors*: TNoteKinds mainPackageNotes*: TNoteKinds mainPackageId*: int errorCounter*: int diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 4b0cf406d..674673443 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -330,31 +330,28 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = + template handleNote(toStrArray, msgMin, notes) = + let x = findStr(toStrArray, n[0][1].ident.s) + if x >= 0: + nk = TNoteKind(x + ord(msgMin)) + let x = c.semConstBoolExpr(c, n[1]) + n[1] = x + if x.kind == nkIntLit and x.intVal != 0: incl(notes, nk) + else: excl(notes, nk) + else: + invalidPragma(c, n) + if n.kind in nkPragmaCallKinds and n.len == 2 and n[0].kind == nkBracketExpr and n[0].len == 2 and n[0][1].kind == nkIdent and n[0][0].kind == nkIdent: var nk: TNoteKind case whichKeyword(n[0][0].ident) - of wHint: - var x = findStr(HintsToStr, n[0][1].ident.s) - if x >= 0: nk = TNoteKind(x + ord(hintMin)) - else: invalidPragma(c, n); return - of wWarning: - var x = findStr(WarningsToStr, n[0][1].ident.s) - if x >= 0: nk = TNoteKind(x + ord(warnMin)) - else: invalidPragma(c, n); return - else: - invalidPragma(c, n) - return - - let x = c.semConstBoolExpr(c, n[1]) - n[1] = x - if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk) - else: excl(c.config.notes, nk) - # checkme: honor cmdlineNotes with: c.setNote(nk, x.kind == nkIntLit and x.intVal != 0) - else: - invalidPragma(c, n) + of wHint: handleNote(HintsToStr, hintMin, c.config.notes) + of wWarning: handleNote(WarningsToStr, warnMin, c.config.notes) + of wWarningAsError: handleNote(WarningsToStr, warnMin, c.config.warningAsErrors) + else: invalidPragma(c, n) + else: invalidPragma(c, n) proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} = case w diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 7ec4c423f..4d836d8f2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -21,6 +21,7 @@ type notes*: TNoteKinds features*: set[Feature] otherPragmas*: PNode # every pragma can be pushed + warningAsErrors*: TNoteKinds POptionEntry* = ref TOptionEntry PProcCon* = ref TProcCon @@ -213,6 +214,7 @@ proc newOptionEntry*(conf: ConfigRef): POptionEntry = result.defaultCC = ccDefault result.dynlib = nil result.notes = conf.notes + result.warningAsErrors = conf.warningAsErrors proc pushOptionEntry*(c: PContext): POptionEntry = new(result) @@ -221,12 +223,14 @@ proc pushOptionEntry*(c: PContext): POptionEntry = result.defaultCC = prev.defaultCC result.dynlib = prev.dynlib result.notes = c.config.notes + result.warningAsErrors = c.config.warningAsErrors result.features = c.features c.optionStack.add(result) proc popOptionEntry*(c: PContext) = c.config.options = c.optionStack[^1].options c.config.notes = c.optionStack[^1].notes + c.config.warningAsErrors = c.optionStack[^1].warningAsErrors c.features = c.optionStack[^1].features c.optionStack.setLen(c.optionStack.len - 1) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 55c38b76a..30a003dee 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -44,7 +44,7 @@ type wAlign, wNodecl, wPure, wSideEffect, wHeader, wNoSideEffect, wGcSafe, wNoreturn, wNosinks, wMerge, wLib, wDynlib, wCompilerProc, wCore, wProcVar, wBase, wUsed, - wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, + wFatal, wError, wWarning, wHint, wWarningAsError, wLine, wPush, wPop, wDefine, wUndef, wLineDir, wStackTrace, wLineTrace, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wCallconv, wDebugger, wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, @@ -131,7 +131,7 @@ const "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "nosinks", "merge", "lib", "dynlib", "compilerproc", "core", "procvar", "base", "used", - "fatal", "error", "warning", "hint", "line", + "fatal", "error", "warning", "hint", "warningaserror", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", "callconv", "debugger", "nimcall", "stdcall", @@ -212,4 +212,5 @@ proc canonPragmaSpelling*(w: TSpecialWord): string = of wCodegenDecl: "codegenDecl" of wLiftLocals: "liftLocals" of wLocalPassc: "localPassc" + of wWarningAsError: "warningAsError" else: specialWords[w] diff --git a/doc/advopt.txt b/doc/advopt.txt index 157208a05..bc5f9948c 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -38,6 +38,8 @@ Advanced options: --warning[X]:on|off turn specific warning X on|off --hints:on|off|list turn all hints on|off or list all available --hint[X]:on|off turn specific hint X on|off + --warningAsError[X]:on|off + turn specific warning X into an error on|off --styleCheck:off|hint|error produce hints or errors for Nim identifiers that do not adhere to Nim's official style guide From a890aa75aa8a03171a5c2cd4ef675b3b85562955 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Apr 2020 23:12:24 +0200 Subject: [PATCH 0287/4254] finally de-deprecate the .define and .undef pragmas --- changelog.md | 1 + compiler/pragmas.nim | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 77a757b1d..b960f5213 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. +- The `define` and `undef` pragmas have been de-deprecated. ## Tool changes diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 674673443..4504d1cc5 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -470,14 +470,12 @@ proc processPop(c: PContext, n: PNode) = proc processDefine(c: PContext, n: PNode) = if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): defineSymbol(c.config.symbols, n[1].ident.s) - message(c.config, n.info, warnDeprecated, "define is deprecated") else: invalidPragma(c, n) proc processUndef(c: PContext, n: PNode) = if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): undefSymbol(c.config.symbols, n[1].ident.s) - message(c.config, n.info, warnDeprecated, "undef is deprecated") else: invalidPragma(c, n) From 813ed358bfe7c282e9adc81bdd7f8a9ff2dc17b9 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 5 Apr 2020 06:39:43 +0000 Subject: [PATCH 0288/4254] asyncdispatch: get rid of erroneous set constructions (#13877) Ref #13764 --- lib/pure/asyncdispatch.nim | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5d34f9fca..5fd5a45fd 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1351,7 +1351,8 @@ else: flags.toOSFlags()) if res < 0: let lastError = osLastError() - if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: + if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and + lastError.int32 != EAGAIN: if flags.isDisconnectionError(lastError): retFuture.complete("") else: @@ -1379,7 +1380,8 @@ else: flags.toOSFlags()) if res < 0: let lastError = osLastError() - if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: + if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and + lastError.int32 != EAGAIN: if flags.isDisconnectionError(lastError): retFuture.complete(0) else: @@ -1447,7 +1449,8 @@ else: cast[ptr SockAddr](addr(staddr[0])), stalen) if res < 0: let lastError = osLastError() - if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: + if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and + lastError.int32 != EAGAIN: retFuture.fail(newException(OSError, osErrorMsg(lastError))) else: result = false # We still want this callback to be called. @@ -1472,7 +1475,8 @@ else: saddr, saddrLen) if res < 0: let lastError = osLastError() - if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: + if lastError.int32 != EINTR and lastError.int32 != EWOULDBLOCK and + lastError.int32 != EAGAIN: retFuture.fail(newException(OSError, osErrorMsg(lastError))) else: result = false @@ -1493,7 +1497,7 @@ else: cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if client == osInvalidSocket: let lastError = osLastError() - assert lastError.int32 notin {EWOULDBLOCK, EAGAIN} + assert lastError.int32 != EWOULDBLOCK and lastError.int32 != EAGAIN if lastError.int32 == EINTR: return false else: From 09ca19208f7c9aa52e71b50cf53cc369612e3fce Mon Sep 17 00:00:00 2001 From: supakeen <39536295+supakeen@users.noreply.github.com> Date: Sun, 5 Apr 2020 09:02:30 +0200 Subject: [PATCH 0289/4254] Add isNil check to custom Content-Length. (#13867) [backport:1.2] Related to #13866. --- lib/pure/asynchttpserver.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index a9ea4780f..7fbbf38ea 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -99,8 +99,9 @@ proc respond*(req: Request, code: HttpCode, content: string, if headers != nil: msg.addHeaders(headers) - - if not headers.hasKey("Content-Length"): + + # If the headers did not contain a Content-Length use our own + if headers.isNil() or not headers.hasKey("Content-Length"): msg.add("Content-Length: ") # this particular way saves allocations: msg.addInt content.len From 6d4f07f2ead4f8800efdc26476768b30b0bb04bc Mon Sep 17 00:00:00 2001 From: cooldome Date: Sun, 5 Apr 2020 15:44:15 +0100 Subject: [PATCH 0290/4254] Fix sym owner in wrapper proc (#13878) Co-authored-by: cooldome --- compiler/spawn.nim | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 2c206b599..d566e0bd9 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -116,24 +116,22 @@ stmtList: proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; varSection, varInit, call, barrier, fv: PNode; - spawnKind: TSpawnResult): PSym = + spawnKind: TSpawnResult, result: PSym) = var body = newNodeI(nkStmtList, f.info) - body.flags.incl nfTransf # do not transform further - var threadLocalBarrier: PSym if barrier != nil: var varSection2 = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner, + threadLocalBarrier = addLocalVar(g, varSection2, nil, result, barrier.typ, barrier) body.add varSection2 body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.info, threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: - threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) + threadLocalProm = addLocalVar(g, varSection, nil, result, fv.typ, fv) elif fv != nil: internalAssert g.config, fv.typ.kind == tyGenericInst - threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) + threadLocalProm = addLocalVar(g, varSection, nil, result, fv.typ, fv) body.add varSection body.add varInit if fv != nil and spawnKind != srByVar: @@ -184,9 +182,6 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; t.n.add threadParam.newSymNode t.n.add argsParam.newSymNode - let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper" - result = newSym(skProc, getIdent(g.cache, name), argsParam.owner, f.info, - argsParam.options) let emptyNode = newNodeI(nkEmpty, f.info) result.ast = newProcNode(nkProcDef, f.info, body = body, params = params, name = newSymNode(result), pattern = emptyNode, @@ -201,7 +196,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode = result.typ = newType(tyPtr, objType.owner) result.typ.rawAddSon(objType) -proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym, +proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; + owner: PSym; scratchObj: PSym, castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n @@ -221,7 +217,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb objType.addField(field, g.cache) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) - let temp = addLocalVar(g, varSection, varInit, objType.owner, argType, + let temp = addLocalVar(g, varSection, varInit, owner, argType, indirectAccess(castExpr, field, n.info)) call.add(newSymNode(temp)) @@ -242,7 +238,8 @@ proc getRoot*(n: PNode): PSym = if getMagic(n) == mSlice: result = getRoot(n[1]) else: discard -proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym; +proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; + owner: PSym; scratchObj: PSym; castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n @@ -281,7 +278,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) - let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ, + let threadLocal = addLocalVar(g, varSection,nil, owner, fieldA.typ, indirectAccess(castExpr, fieldA, n.info), useShallowCopy=true) slice[2] = threadLocal.newSymNode @@ -296,7 +293,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb # the array itself does not need to go through a thread local variable: slice[1] = genDeref(indirectAccess(castExpr, field, n.info)) - let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ, + let threadLocal = addLocalVar(g, varSection,nil, owner, fieldB.typ, indirectAccess(castExpr, fieldB, n.info), useShallowCopy=true) slice[3] = threadLocal.newSymNode @@ -308,7 +305,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb field.typ = a.typ objType.addField(field, g.cache) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ, + let threadLocal = addLocalVar(g, varSection,nil, owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(genDeref(threadLocal.newSymNode)) @@ -318,7 +315,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb objType.addField(field, g.cache) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) let threadLocal = addLocalVar(g, varSection, varInit, - objType.owner, field.typ, + owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(threadLocal.newSymNode) @@ -346,9 +343,13 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P if optThreadAnalysis in g.config.globalOptions: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: localError(g.config, n.info, "'spawn' takes a GC safe call expression") - var - threadParam = newSym(skParam, getIdent(g.cache, "thread"), owner, n.info, g.config.options) - argsParam = newSym(skParam, getIdent(g.cache, "args"), owner, n.info, g.config.options) + + var fn = n[0] + let + name = (if fn.kind == nkSym: fn.sym.name.s else: genPrefix) & "Wrapper" + wrapperProc = newSym(skProc, getIdent(g.cache, name), owner, fn.info, g.config.options) + threadParam = newSym(skParam, getIdent(g.cache, "thread"), wrapperProc, n.info, g.config.options) + argsParam = newSym(skParam, getIdent(g.cache, "args"), wrapperProc, n.info, g.config.options) block: let ptrType = getSysType(g, n.info, tyPointer) threadParam.typ = ptrType @@ -368,7 +369,6 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P result.add varSectionB var call = newNodeIT(nkCall, n.info, n.typ) - var fn = n[0] # templates and macros are in fact valid here due to the nature of # the transformation: if fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure): @@ -391,10 +391,10 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P var varSection = newNodeI(nkVarSection, n.info) var varInit = newNodeI(nkStmtList, n.info) if barrier.isNil: - setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call, + setupArgsForConcurrency(g, n, objType, wrapperProc, scratchObj, castExpr, call, varSection, varInit, result) else: - setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call, + setupArgsForParallelism(g, n, objType, wrapperProc, scratchObj, castExpr, call, varSection, varInit, result) var barrierAsExpr: PNode = nil @@ -428,11 +428,11 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P fvAsExpr = indirectAccess(castExpr, field, n.info) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) - let wrapper = createWrapperProc(g, fn, threadParam, argsParam, - varSection, varInit, call, - barrierAsExpr, fvAsExpr, spawnKind) - result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.info, - wrapper.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr) + createWrapperProc(g, fn, threadParam, argsParam, + varSection, varInit, call, + barrierAsExpr, fvAsExpr, spawnKind, wrapperProc) + result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapperProc.info, + wrapperProc.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr) if spawnKind == srFlowVar: result.add fvField From 29734b73ff7db82d623986ebb8bcb04289e5b270 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 5 Apr 2020 07:44:34 -0700 Subject: [PATCH 0291/4254] add nimPath to nim dump (#13876) * add nimPath to nim dump * rename --- compiler/main.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/main.nim b/compiler/main.nim index 217858137..1a776d516 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -13,7 +13,7 @@ when not defined(nimcore): {.error: "nimcore MUST be defined for Nim's core tooling".} import - llstream, strutils, ast, lexer, syntaxes, options, msgs, + llstream, strutils, os, ast, lexer, syntaxes, options, msgs, condsyms, times, sem, idents, passes, extccomp, cgen, json, nversion, @@ -315,6 +315,7 @@ proc mainCommand*(graph: ModuleGraph) = var dumpdata = %[ (key: "version", val: %VersionAsString), + (key: "nimExe", val: %(getAppFilename())), (key: "prefixdir", val: %conf.getPrefixDir().string), (key: "libpath", val: %conf.libpath.string), (key: "project_path", val: %conf.projectFull.string), From b6814be65349d22fd12944c7c3d19fd8eb44683d Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sun, 5 Apr 2020 23:44:55 +0900 Subject: [PATCH 0292/4254] doc: fix comment for repr*(x: char): string (#13873) replace `$` with `repr`. --- lib/system/repr_v2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 6bf45b4ce..3e35b32c3 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -27,7 +27,7 @@ proc repr*(x: char): string {.magic: "CharToStr", noSideEffect.} ## converted to a string. ## ## .. code-block:: Nim - ## assert $'c' == "c" + ## assert repr('c') == "c" proc repr*(x: cstring): string {.magic: "CStrToStr", noSideEffect.} ## repr for a CString argument. Returns `x` From 87847150bfc89b9b1823c3dfe2b37ebaeadc9ba0 Mon Sep 17 00:00:00 2001 From: supakeen <39536295+supakeen@users.noreply.github.com> Date: Sun, 5 Apr 2020 21:16:13 +0200 Subject: [PATCH 0293/4254] Add barebones asynchttpserver tests (#13883) * Add isNil check to custom Content-Length. Related to #13866. * Setup barebones asynchttpserver tests. --- tests/stdlib/tasynchttpserver.nim | 119 ++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 tests/stdlib/tasynchttpserver.nim diff --git a/tests/stdlib/tasynchttpserver.nim b/tests/stdlib/tasynchttpserver.nim new file mode 100644 index 000000000..77ad7a071 --- /dev/null +++ b/tests/stdlib/tasynchttpserver.nim @@ -0,0 +1,119 @@ +discard """ + cmd: "nim c --threads:on $file" + exitcode: 0 + output: "OK" + disabled: false +""" + +import strutils +from net import TimeoutError + +import httpclient, asynchttpserver, asyncdispatch, asyncfutures + +template runTest( + handler: proc (request: Request): Future[void] {.gcsafe.}, + request: proc (server: AsyncHttpServer): Future[AsyncResponse], + test: proc (response: AsyncResponse, body: string): Future[void]) = + + let server = newAsyncHttpServer() + + discard server.serve(Port(64123), handler) + + let + response = waitFor(request(server)) + body = waitFor(response.body) + + discard test(response, body) + +proc test200() {.async.} = + proc handler(request: Request) {.async.} = + await request.respond(Http200, "Hello World, 200") + + proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = + let + client = newAsyncHttpClient() + clientResponse = await client.request("http://localhost:64123/") + + server.close() + + return clientResponse + + proc test(response: AsyncResponse, body: string) {.async.} = + doAssert(response.status == Http200) + doAssert(body == "Hello World, 200") + doAssert(response.headers.hasKey("Content-Length")) + doAssert(response.headers["Content-Length"] == "16") + + runTest(handler, request, test) + +proc test404() {.async.} = + proc handler(request: Request) {.async.} = + await request.respond(Http404, "Hello World, 404") + + proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = + let + client = newAsyncHttpClient() + clientResponse = await client.request("http://localhost:64123/") + + server.close() + + return clientResponse + + proc test(response: AsyncResponse, body: string) {.async.} = + doAssert(response.status == Http404) + doAssert(body == "Hello World, 404") + doAssert(response.headers.hasKey("Content-Length")) + doAssert(response.headers["Content-Length"] == "16") + + runTest(handler, request, test) + +proc testCustomEmptyHeaders() {.async.} = + proc handler(request: Request) {.async.} = + await request.respond(Http200, "Hello World, 200", newHttpHeaders()) + + proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = + let + client = newAsyncHttpClient() + clientResponse = await client.request("http://localhost:64123/") + + server.close() + + return clientResponse + + proc test(response: AsyncResponse, body: string) {.async.} = + doAssert(response.status == Http200) + doAssert(body == "Hello World, 200") + doAssert(response.headers.hasKey("Content-Length")) + doAssert(response.headers["Content-Length"] == "16") + + runTest(handler, request, test) + +proc testCustomContentLength() {.async.} = + proc handler(request: Request) {.async.} = + let headers = newHttpHeaders() + headers["Content-Length"] = "0" + await request.respond(Http200, "Hello World, 200", headers) + + proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} = + let + client = newAsyncHttpClient() + clientResponse = await client.request("http://localhost:64123/") + + server.close() + + return clientResponse + + proc test(response: AsyncResponse, body: string) {.async.} = + doAssert(response.status == Http200) + doAssert(body == "") + doAssert(response.headers.hasKey("Content-Length")) + doAssert(response.headers["Content-Length"] == "0") + + runTest(handler, request, test) + +waitfor(test200()) +waitfor(test404()) +waitfor(testCustomEmptyHeaders()) +waitfor(testCustomContentLength()) + +echo "OK" From f1fd3ef7f419e2e2e9675df04aedecef4872f3e9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 5 Apr 2020 15:24:35 -0700 Subject: [PATCH 0294/4254] fix https://github.com/timotheecour/Nim/issues/88 (#13865) [backport:1.2] --- compiler/vm.nim | 53 ++++++++++++++++++++--------------------------- tests/vm/tref.nim | 11 +++++++++- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index a2c6e686d..37d5a609e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -510,6 +510,23 @@ const "if you are sure this is not a bug in your code, compile with `--maxLoopIterationsVM:number` (current value: $1)" errFieldXNotFound = "node lacks field: " + +template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool = + let node = node2 # prevent double evaluation + if node.kind == nkNilLit: + stackTrace(c, tos, pc, errNilAccess) + let typ = node.typ + if nfIsPtr in node.flags or (typ != nil and typ.kind == tyPtr): + assert node.kind == nkIntLit, $(node.kind) + assert typ != nil + let typ2 = if typ.kind == tyPtr: typ[0] else: typ + if not derefPtrToReg(node.intVal, typ2, reg, isAssign = isAssign2): + # tyObject not supported in this context + stackTrace(c, tos, pc, "deref unsupported ptr type: " & $(typeToString(typ), typ.kind)) + true + else: + false + proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -755,26 +772,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = ensureKind(regs[rb].regAddr.kind) regs[ra] = regs[rb].regAddr[] of rkNode: - if regs[rb].node.kind == nkNilLit: - stackTrace(c, tos, pc, errNilAccess) if regs[rb].node.kind == nkRefTy: regs[ra].node = regs[rb].node[0] - else: - let node = regs[rb].node - let typ = node.typ - # see also `nfIsPtr` - if node.kind == nkIntLit: - var typ2 = typ - doAssert typ != nil - if typ.kind == tyPtr: - typ2 = typ2[0] - if not derefPtrToReg(node.intVal, typ2, regs[ra], isAssign = false): - # tyObject not supported in this context - stackTrace(c, tos, pc, "opcLdDeref unsupported ptr type: " & $(typeToString(typ), typ.kind)) - else: - ## eg: typ.kind = tyObject - ensureKind(rkNode) - regs[ra].node = regs[rb].node + elif not maybeHandlePtr(regs[rb].node, regs[ra], false): + ## eg: typ.kind = tyObject + ensureKind(rkNode) + regs[ra].node = regs[rb].node else: stackTrace(c, tos, pc, errNilAccess & " kind: " & $regs[rb].kind) of opcWrDeref: @@ -795,18 +798,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].nodeAddr[] = n of rkRegisterAddr: regs[ra].regAddr[] = regs[rc] of rkNode: - if regs[ra].node.kind == nkNilLit: - stackTrace(c, tos, pc, errNilAccess) - let node = regs[ra].node - let typ = node.typ - if nfIsPtr in node.flags or (typ != nil and typ.kind == tyPtr): - assert node.kind == nkIntLit, $(node.kind) - var typ2 = typ - if typ.kind == tyPtr: - typ2 = typ2[0] - if not derefPtrToReg(node.intVal, typ2, regs[rc], isAssign = true): - stackTrace(c, tos, pc, "opcWrDeref unsupported ptr type: " & $(typeToString(typ), typ.kind)) - else: + # xxx: also check for nkRefTy as in opcLdDeref? + if not maybeHandlePtr(regs[ra].node, regs[rc], true): regs[ra].node[] = regs[rc].regToNode[] regs[ra].node.flags.incl nfIsRef else: stackTrace(c, tos, pc, errNilAccess) diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim index f5cd23da5..e70305225 100644 --- a/tests/vm/tref.nim +++ b/tests/vm/tref.nim @@ -59,4 +59,13 @@ static: static: # bug #8402 type R = ref object var empty: R - let otherEmpty = empty \ No newline at end of file + let otherEmpty = empty + +block: + # fix https://github.com/timotheecour/Nim/issues/88 + template fun() = + var s = @[10,11,12] + var a = s[0].addr + a[] += 100 # was giving SIGSEGV + doAssert a[] == 110 + static: fun() From e6d870896b88c30ac11174b34449a19ff1333235 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 5 Apr 2020 23:26:12 -0700 Subject: [PATCH 0295/4254] openDefaultBrowser now works on OSX (#13892) [backport] --- lib/pure/browsers.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 85b229983..a70b767b7 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -21,9 +21,9 @@ else: import os, osproc const osOpenCmd* = - when defined(macos) or defined(windows): "open" else: "xdg-open" ## \ + when defined(macos) or defined(macosx) or defined(windows): "open" else: "xdg-open" ## \ ## Alias for the operating system specific *"open"* command, - ## ``"open"`` on MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc. + ## ``"open"`` on OSX, MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc. template openDefaultBrowserImpl(url: string) = From 1e25e16c8834324006e8ce00e20e6d59e6c5cf6f Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 6 Apr 2020 15:35:27 +0200 Subject: [PATCH 0296/4254] Fix #13872 (#13898) --- lib/system/repr_v2.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 3e35b32c3..fa04ba5a9 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -14,6 +14,11 @@ proc repr*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## repr for an integer argument. Returns `x` ## converted to a decimal string. +proc repr*(x: uint64): string {.noSideEffect.} = + ## repr for an unsigned integer argument. Returns `x` + ## converted to a decimal string. + $x #Calls `$` from system/strmantle.nim + proc repr*(x: float): string {.magic: "FloatToStr", noSideEffect.} ## repr for a float argument. Returns `x` ## converted to a decimal string. From 92c4aad2059a350e95bc7a64932873b41b085976 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 6 Apr 2020 16:25:24 +0200 Subject: [PATCH 0297/4254] Fix #13889 with testcase (#13896) [backport] * Fix https://github.com/nim-lang/Nim/issues/13889 * Add testcase * Reduce test time Co-authored-by: Elie Zedeck RANDRIAMIANDRIRAY --- lib/pure/asyncmacro.nim | 2 +- tests/async/t13889.nim | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/async/t13889.nim diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index c6f4ae04a..4faddb4f8 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -46,7 +46,7 @@ template createCb(retFutureSym, iteratorNameSym, else: {.gcsafe.}: {.push hint[ConvFromXtoItselfNotNeeded]: off.} - next.callback = cast[proc() {.closure, gcsafe.}](identName) + next.addCallback cast[proc() {.closure, gcsafe.}](identName) {.pop.} except: futureVarCompletions diff --git a/tests/async/t13889.nim b/tests/async/t13889.nim new file mode 100644 index 000000000..fe75fe38a --- /dev/null +++ b/tests/async/t13889.nim @@ -0,0 +1,27 @@ +discard """ + output: ''' +believer Foo is saved:true +believer Bar is saved:true +believer Baz is saved:true +''' +""" + +import asyncdispatch + +var + promise = newFuture[bool]() + +proc believers(name: string) {.async.} = + let v = await promise + echo "believer " & name & " is saved:" & $v + +asyncCheck believers("Foo") +asyncCheck believers("Bar") +asyncCheck believers("Baz") + +proc savior() {.async.} = + await sleepAsync(50) + complete(promise, true) + await sleepAsync(50) # give enough time to see who was saved + +waitFor(savior()) From 37692baf49370d096e0d9ac2c8bf51ed7bd8cf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Tue, 7 Apr 2020 14:42:59 +0200 Subject: [PATCH 0298/4254] fix #13739 (#13742) --- compiler/transf.nim | 9 ++++----- tests/iter/titer_issues.nim | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 18d9b9130..cbf904255 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -560,8 +560,8 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = of nkBracket: return paFastAsgnTakeTypeFromArg else: - return paDirectMapping # XXX really correct? - # what if ``arg`` has side-effects? + # XXX incorrect, causes #13417 when `arg` has side effects. + return paDirectMapping case arg.kind of nkEmpty..nkNilLit: result = paDirectMapping @@ -671,9 +671,8 @@ proc transformFor(c: PTransf, n: PNode): PNode = idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! of paComplexOpenarray: - let typ = newType(tySequence, formal.owner) - addSonSkipIntLit(typ, formal.typ[0]) - var temp = newTemp(c, typ, formal.info) + # arrays will deep copy here (pretty bad). + var temp = newTemp(c, arg.typ, formal.info) addVar(v, temp) stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg)) idNodeTablePut(newC.mapping, formal, temp) diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index a7830dfab..872ebe2b7 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -18,6 +18,15 @@ end 1 2 7 +9002 +9004 +9006 +9008 +9010 +9012 +9014 +9016 +9018 ''' """ @@ -213,3 +222,21 @@ block t2023_objiter: var o = init() echo(o.iter()) + + +block: + # issue #13739 + iterator myIter(arg: openarray[int]): int = + var tmp = 0 + let len = arg.len + while tmp < len: + yield arg[tmp] * 2 + inc tmp + + proc someProc() = + var data = [4501,4502,4503,4504,4505,4506,4507,4508,4509] + # StmtListExpr should not get special treatment. + for x in myIter((discard;data)): + echo x + + someProc() From b41931bf67136f50cf8fb11442a7e614da00a0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20S=C3=B8borg?= Date: Tue, 7 Apr 2020 15:14:25 +0200 Subject: [PATCH 0299/4254] json doc: Note about Option and reserved keywords (#13895) --- lib/pure/json.nim | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index beb3f7049..7921c0c05 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -102,16 +102,23 @@ ## In addition to reading dynamic data, Nim can also unmarshal JSON directly ## into a type with the ``to`` macro. ## +## Note: Use `Option `_ for keys sometimes missing in json +## responses, and backticks around keys with a reserved keyword as name. +## ## .. code-block:: Nim ## import json +## import options ## ## type ## User = object ## name: string ## age: int +## `type`: Option[string] ## ## let userJson = parseJson("""{ "name": "Nim", "age": 12 }""") ## let user = to(userJson, User) +## if user.`type`.isSome(): +## assert user.`type`.get() != "robot" ## ## Creating JSON ## ============= From ab5e26c53cf34a1839dd92d247b5e0a5cde432a0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 7 Apr 2020 06:17:30 -0700 Subject: [PATCH 0300/4254] fix some codegen bugs: NIM_BOOL, NIM_STATIC_ASSERT, --passc:-std=... (etc) (#13798) * fix cgen bool D20200328T203812 * --passc:std=c++17 (etc) now works instead of silently ignored * document caveats for NIM_NIL --- compiler/extccomp.nim | 8 ++-- lib/nimbase.h | 65 +++++++++++++++++++----------- tests/ccgbugs/mstatic_assert.nim | 6 +++ tests/ccgbugs/tcodegenbug_bool.nim | 11 +++++ tests/trunner.nim | 46 +++++++++++++++++++++ tests/vm/tevalffi.nim | 28 ------------- 6 files changed, 110 insertions(+), 54 deletions(-) create mode 100644 tests/ccgbugs/mstatic_assert.nim create mode 100644 tests/ccgbugs/tcodegenbug_bool.nim create mode 100644 tests/trunner.nim delete mode 100644 tests/vm/tevalffi.nim diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 307be249e..9e89b5aa4 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -612,6 +612,11 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, # We produce files like module.nim.cpp, so the absolute Nim filename is not # cfile.name but `cfile.cname.changeFileExt("")`: var options = cFileSpecificOptions(conf, cfile.nimname, cfile.cname.changeFileExt("").string) + if useCpp(conf, cfile.cname): + # needs to be prepended so that --passc:-std=c++17 can override default. + # we could avoid allocation by making cFileSpecificOptions inplace + options = CC[c].cppXsupport & ' ' & options + var exe = getConfigVar(conf, c, ".exe") if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname) @@ -620,9 +625,6 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, ospNeedsPIC in platform.OS[conf.target.targetOS].props: options.add(' ' & CC[c].pic) - if useCpp(conf, cfile.cname): - options.add(' ' & CC[c].cppXsupport) - var compilePattern: string # compute include paths: var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath) diff --git a/lib/nimbase.h b/lib/nimbase.h index 5b0dcc2c8..597a5317f 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -262,6 +262,21 @@ __AVR__ #include #include +// define NIM_STATIC_ASSERT +// example use case: CT sizeof for importc types verification +// where we have {.completeStruct.} (or lack of {.incompleteStruct.}) +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) +#define NIM_STATIC_ASSERT(x, msg) _Static_assert((x), msg) +#elif defined(__cplusplus) +#define NIM_STATIC_ASSERT(x, msg) static_assert((x), msg) +#else +#define NIM_STATIC_ASSERT(x, msg) typedef int NIM_STATIC_ASSERT_AUX[(x) ? 1 : -1]; +// On failure, your C compiler will say something like: +// "error: 'NIM_STATIC_ASSERT_AUX' declared as an array with a negative size" +// we could use a better fallback to also show line number, using: +// http://www.pixelbeat.org/programming/gcc/static_assert.html +#endif + /* C99 compiler? */ #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) # define HAVE_STDINT_H @@ -288,34 +303,40 @@ __AVR__ namespace USE_NIM_NAMESPACE { #endif +// preexisting check, seems paranoid, maybe remove +#if defined(NIM_TRUE) || defined(NIM_FALSE) || defined(NIM_BOOL) +#error "nim reserved preprocessor macros clash" +#endif + /* bool types (C++ has it): */ #ifdef __cplusplus -# ifndef NIM_TRUE -# define NIM_TRUE true -# endif -# ifndef NIM_FALSE -# define NIM_FALSE false -# endif -# define NIM_BOOL bool +#define NIM_BOOL bool +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +// see #13798: to avoid conflicts for code emitting `#include ` +#define NIM_BOOL _Bool +#else +typedef unsigned char NIM_BOOL; // best effort +#endif + +NIM_STATIC_ASSERT(sizeof(NIM_BOOL) == 1, ""); // check whether really needed + +#define NIM_TRUE true +#define NIM_FALSE false + +#ifdef __cplusplus # if __cplusplus >= 201103L # /* nullptr is more type safe (less implicit conversions than 0) */ # define NIM_NIL nullptr # else -# /* consider using NULL if comment below for NIM_NIL doesn't apply to C++ */ +# // both `((void*)0)` and `NULL` would cause codegen to emit +# // error: assigning to 'Foo *' from incompatible type 'void *' +# // but codegen could be fixed if need. See also potential caveat regarding +# // NULL. +# // However, `0` causes other issues, see #13798 # define NIM_NIL 0 # endif #else -# ifdef bool -# define NIM_BOOL bool -# else - typedef unsigned char NIM_BOOL; -# endif -# ifndef NIM_TRUE -# define NIM_TRUE ((NIM_BOOL) 1) -# endif -# ifndef NIM_FALSE -# define NIM_FALSE ((NIM_BOOL) 0) -# endif +# include # define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so the generated code does not rely on it anymore */ #endif @@ -516,10 +537,8 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); } # define GC_GUARD #endif -/* Test to see if Nim and the C compiler agree on the size of a pointer. - On disagreement, your C compiler will say something like: - "error: 'Nim_and_C_compiler_disagree_on_target_architecture' declared as an array with a negative size" */ -typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1]; +// Test to see if Nim and the C compiler agree on the size of a pointer. +NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, ""); #ifdef USE_NIM_NAMESPACE } diff --git a/tests/ccgbugs/mstatic_assert.nim b/tests/ccgbugs/mstatic_assert.nim new file mode 100644 index 000000000..dbf9c03d1 --- /dev/null +++ b/tests/ccgbugs/mstatic_assert.nim @@ -0,0 +1,6 @@ +{.emit:""" +NIM_STATIC_ASSERT(sizeof(bool) == 1, ""); +#warning "foo2" +NIM_STATIC_ASSERT(sizeof(bool) == 2, ""); +#warning "foo3" +""".} diff --git a/tests/ccgbugs/tcodegenbug_bool.nim b/tests/ccgbugs/tcodegenbug_bool.nim new file mode 100644 index 000000000..a0dbf4eb2 --- /dev/null +++ b/tests/ccgbugs/tcodegenbug_bool.nim @@ -0,0 +1,11 @@ +discard """ +""" + +# issue #13798 +{.emit:""" +#include +void fun(bool a){} +""".} + +proc fun(a: bool) {.importc.} +fun(true) diff --git a/tests/trunner.nim b/tests/trunner.nim new file mode 100644 index 000000000..7e1468e84 --- /dev/null +++ b/tests/trunner.nim @@ -0,0 +1,46 @@ +discard """ + joinable: false +""" + +## tests that don't quite fit the mold and are easier to handle via `execCmdEx` +## A few others could be added to here to simplify code. + +import std/[strformat,os,osproc,strutils] + +proc runCmd(file, options = ""): auto = + let mode = if existsEnv("NIM_COMPILE_TO_CPP"): "cpp" else: "c" + const nim = getCurrentCompilerExe() + const testsDir = currentSourcePath().parentDir + let fileabs = testsDir / file.unixToNativePath + doAssert fileabs.existsFile, fileabs + let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs}" + result = execCmdEx(cmd) + when false: # uncomment if you need to debug + echo result[0] + echo result[1] + +proc testCodegenStaticAssert() = + let (output, exitCode) = runCmd("ccgbugs/mstatic_assert.nim") + doAssert "sizeof(bool) == 2" in output + doAssert exitCode != 0 + +proc testCTFFI() = + let (output, exitCode) = runCmd("vm/mevalffi.nim", "--experimental:compiletimeFFI") + let expected = """ +hello world stderr +hi stderr +foo +foo:100 +foo:101 +foo:102:103 +foo:102:103:104 +foo:0.03:asdf:103:105 +ret={s1:foobar s2:foobar age:25 pi:3.14} +""" + doAssert output == expected, output + doAssert exitCode == 0 + +when defined(nimHasLibFFIEnabled): + testCTFFI() +else: # don't run twice the same test + testCodegenStaticAssert() diff --git a/tests/vm/tevalffi.nim b/tests/vm/tevalffi.nim deleted file mode 100644 index 02374869e..000000000 --- a/tests/vm/tevalffi.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - joinable: false -""" - -import std/[strformat,os,osproc] - -proc main() = - const nim = getCurrentCompilerExe() - const file = currentSourcePath().parentDir / "mevalffi.nim" - # strangely, --hint:cc:off was needed - let cmd = fmt"{nim} c -f --experimental:compiletimeFFI --hints:off --hint:cc:off {file}" - let (output, exitCode) = execCmdEx(cmd) - let expected = """ -hello world stderr -hi stderr -foo -foo:100 -foo:101 -foo:102:103 -foo:102:103:104 -foo:0.03:asdf:103:105 -ret={s1:foobar s2:foobar age:25 pi:3.14} -""" - doAssert output == expected, output - doAssert exitCode == 0 - -when defined(nimHasLibFFIEnabled): - main() From c835c8c4e78cbe3451c2ccdfffe9663f1b428728 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 7 Apr 2020 18:40:14 +0100 Subject: [PATCH 0301/4254] fix #13910 (#13917) Co-authored-by: cooldome --- compiler/extccomp.nim | 4 ++-- lib/nimbase.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 9e89b5aa4..f846f9683 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -143,8 +143,8 @@ compiler vcc: result = ( name: "vcc", objExt: "obj", - optSpeed: " /Ogityb2 /G7 ", - optSize: " /O1 /G7 ", + optSpeed: " /Ogityb2 ", + optSize: " /O1 ", compilerExe: "cl", cppCompiler: "cl", compileTmpl: "/c$vccplatform $options $include /Fo$objfile $file", diff --git a/lib/nimbase.h b/lib/nimbase.h index 597a5317f..04cf146a8 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -569,7 +569,7 @@ NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, "" #define nimModInt(a, b, res) (((*res) = (a) % (b)), 0) #define nimModInt64(a, b, res) (((*res) = (a) % (b)), 0) -#if !defined(_MSC_VER) && !defined(NIM_EmulateOverflowChecks) +#if (!defined(_MSC_VER) || defined(__clang__)) && !defined(NIM_EmulateOverflowChecks) /* these exist because we cannot have .compilerProcs that are importc'ed by a different name */ From 3036ec9c4456f6a5edb0a5bbfbb3e3c79fba7d23 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 7 Apr 2020 16:32:07 +0200 Subject: [PATCH 0302/4254] fix #13894, httpclient hang on Http204 --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index e3e5a5c11..5c53c1a39 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -818,7 +818,7 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, if not fullyRead: httpError("Connection was closed before full request has been made") - if getBody: + if getBody and result.code != Http204: when client is HttpClient: client.bodyStream = newStringStream() result.bodyStream = client.bodyStream From 95fd8ae93ce8732eb5a979d4cd63e0350594318d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 8 Apr 2020 00:56:16 -0700 Subject: [PATCH 0303/4254] fix #13902 distinct uint64 type corruption on 32-bit with borrow (#13907) [backport:1.2] * fix #13902 distinct uint64 type corruption on 32-bit with borrow Co-authored-by: Timothee Cour --- compiler/ccgexprs.nim | 2 +- tests/ccgbugs/t13902.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/ccgbugs/t13902.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index fcedcf001..d8f5d016b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2156,7 +2156,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const opr: array[mInc..mDec, string] = ["+=", "-="] const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] - let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange}) + let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: diff --git a/tests/ccgbugs/t13902.nim b/tests/ccgbugs/t13902.nim new file mode 100644 index 000000000..fd4f76d15 --- /dev/null +++ b/tests/ccgbugs/t13902.nim @@ -0,0 +1,12 @@ + +#issue #13902 +block: + type Slot = distinct uint64 + var s = Slot(1) + proc `$`(x: Slot): string {.borrow.} + proc `+=`(x: var Slot, y: uint64) {.borrow.} + # test was failing with either 0 or 2 echos but not with 1 echo + # echo "s = ", s + s += 1 + # echo "s = ", s + doAssert s.uint64 == 2, $s # was failing, showing 18419607611339964418 From f86fc5316af480336a2dcd899b3f7288819914e7 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 8 Apr 2020 10:28:09 +0100 Subject: [PATCH 0304/4254] fix #13909 (#13914) [backport:1.2] Co-authored-by: cooldome --- compiler/semstmts.nim | 11 ++++++-- compiler/semtypes.nim | 48 ++++++++++++++++++-------------- tests/pragmas/tcustom_pragma.nim | 11 ++++++++ 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 215d554fb..992f05e32 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1472,9 +1472,14 @@ proc semProcAnnotation(c: PContext, prc: PNode; if whichPragma(it) != wInvalid: # Not a custom pragma continue - elif strTableGet(c.userPragmas, considerQuotedIdent(c, key)) != nil: - # User-defined pragma - continue + else: + let ident = considerQuotedIdent(c, key) + if strTableGet(c.userPragmas, ident) != nil: + continue # User defined pragma + else: + let sym = searchInScopes(c, ident) + if sym != nil and sfCustomPragma in sym.flags: + continue # User custom pragma # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and # let the semantic checker deal with it: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 21b95d3f6..7fe23eb8e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1576,28 +1576,34 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode = if p.kind == nkEmpty or whichPragma(p) != wInvalid: discard "builtin pragma" - elif strTableGet(c.userPragmas, considerQuotedIdent(c, key)) != nil: - discard "User-defined pragma" else: - # we transform ``(arg1, arg2: T) {.m, rest.}`` into ``m((arg1, arg2: T) {.rest.})`` and - # let the semantic checker deal with it: - var x = newNodeI(nkCall, key.info) - x.add(key) - if p.kind in nkPragmaCallKinds and p.len > 1: - # pass pragma arguments to the macro too: - for i in 1 ..< p.len: - x.add(p[i]) - # Also pass the node the pragma has been applied to - x.add(operand.copyTreeWithoutNode(p)) - # recursion assures that this works for multiple macro annotations too: - var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared}) - if r != nil: - doAssert r[0].kind == nkSym - let m = r[0].sym - case m.kind - of skMacro: return semMacroExpr(c, r, r, m, {efNoSemCheck}) - of skTemplate: return semTemplateExpr(c, r, m, {efNoSemCheck}) - else: doAssert(false, "cannot happen") + let ident = considerQuotedIdent(c, key) + if strTableGet(c.userPragmas, ident) != nil: + discard "User-defined pragma" + else: + let sym = searchInScopes(c, ident) + if sym != nil and sfCustomPragma in sym.flags: + discard "Custom user pragma" + else: + # we transform ``(arg1, arg2: T) {.m, rest.}`` into ``m((arg1, arg2: T) {.rest.})`` and + # let the semantic checker deal with it: + var x = newNodeI(nkCall, key.info) + x.add(key) + if p.kind in nkPragmaCallKinds and p.len > 1: + # pass pragma arguments to the macro too: + for i in 1 ..< p.len: + x.add(p[i]) + # Also pass the node the pragma has been applied to + x.add(operand.copyTreeWithoutNode(p)) + # recursion assures that this works for multiple macro annotations too: + var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared}) + if r != nil: + doAssert r[0].kind == nkSym + let m = r[0].sym + case m.kind + of skMacro: return semMacroExpr(c, r, r, m, {efNoSemCheck}) + of skTemplate: return semTemplateExpr(c, r, m, {efNoSemCheck}) + else: doAssert(false, "cannot happen") proc semProcTypeWithScope(c: PContext, n: PNode, prev: PType, kind: TSymKind): PType = diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 2d970aba1..b306045e0 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -335,3 +335,14 @@ ProcDef static: assert bar("x") == "x" +#------------------------------------------------------ +# issue #13909 + +template dependency*(id: string, weight = 0.0) {.pragma.} + +type + MyObject* = object + provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.} + +proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} = + result = obj \ No newline at end of file From b4e9f8e814373fc38741736197d88475663ce758 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 8 Apr 2020 13:16:25 +0100 Subject: [PATCH 0305/4254] fix ICE in isUnresolvedSym (#13925) Co-authored-by: cooldome --- compiler/semexprs.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5f82eb1e7..826cf51ba 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -622,11 +622,12 @@ proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr) proc isUnresolvedSym(s: PSym): bool = - return s.kind == skGenericParam or - tfInferrableStatic in s.typ.flags or - (s.kind == skParam and s.typ.isMetaType) or - (s.kind == skType and - s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {}) + result = s.kind == skGenericParam + if not result and s.typ != nil: + result = tfInferrableStatic in s.typ.flags or + (s.kind == skParam and s.typ.isMetaType) or + (s.kind == skType and + s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {}) proc hasUnresolvedArgs(c: PContext, n: PNode): bool = # Checks whether an expression depends on generic parameters that From 3dc8068075bd4c5eee88eef348b51f83b50ff13d Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 8 Apr 2020 14:34:08 +0200 Subject: [PATCH 0306/4254] Test packages on Linux (#13921) * test important packages on Linux * enable chronos --- azure-pipelines.yml | 4 ++-- testament/important_packages.nim | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 310feb8f7..d02ac1091 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,8 +30,8 @@ jobs: Windows_amd64: vmImage: 'windows-2019' CPU: amd64 - Windows_amd64_pkg: - vmImage: 'windows-2019' + Linux_amd64_pkg: + vmImage: 'ubuntu-16.04' CPU: amd64 NIM_TEST_PACKAGES: true diff --git a/testament/important_packages.nim b/testament/important_packages.nim index f4976de26..21a40257f 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -17,8 +17,7 @@ pkg "c2nim", false, "nim c testsuite/tester.nim" pkg "cascade" pkg "chroma" pkg "chronicles", true, "nim c -o:chr -r chronicles.nim" -# disable until my chronos fix was merged -#pkg "chronos", true +pkg "chronos", true pkg "cligen", false, "nim c -o:cligenn -r cligen.nim" pkg "coco", true pkg "combparser" From 350ee0308aafc27d4261e4c18b9faad0942d42a1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 8 Apr 2020 13:37:00 +0100 Subject: [PATCH 0307/4254] Fixes issues with dynamic loading OpenSSL. Fixes #13903. (#13919) [backport] This fixes at least a couple of issues: * Procs loaded from the DLL being used even when the pointer is nil. * The actual issue (#13903) which appeared to cause stack corruption on Android 7.1.1 with OpenSSL 1.1.1f. The change that fixed this was the move to loading the procs in `sslSym`. --- lib/wrappers/openssl.nim | 58 +++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 9dafe2300..32e3b9e3a 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -244,7 +244,7 @@ proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} # and support SSLv3, TLSv1, TLSv1.1 and TLSv1.2 # SSLv23_method(), SSLv23_server_method(), SSLv23_client_method() are removed in 1.1.0 -when compileOption("dynlibOverride", "ssl"): +when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): # Static linking when defined(openssl10): @@ -285,40 +285,59 @@ else: proc thisModule(): LibHandle {.inline.} = var thisMod {.global.}: LibHandle if thisMod.isNil: thisMod = loadLib() + result = thisMod proc sslModule(): LibHandle {.inline.} = var sslMod {.global.}: LibHandle if sslMod.isNil: sslMod = loadLibPattern(DLLSSLName) + result = sslMod - proc sslSym(name: string): pointer = - var dl = thisModule() - if not dl.isNil: - result = symAddr(dl, name) + proc sslSymNullable(name: string, alternativeName = ""): pointer = + # Load from DLL. + var sslDynlib = sslModule() + if not sslDynlib.isNil: + result = symAddr(sslDynlib, name) + if result.isNil and alternativeName.len > 0: + result = symAddr(sslDynlib, alternativeName) + + # Attempt to load from current exe. if result.isNil: - dl = sslModule() - if not dl.isNil: - result = symAddr(dl, name) + let thisDynlib = thisModule() + if thisDynlib.isNil: return nil + result = symAddr(thisDynlib, name) + if result.isNil and alternativeName.len > 0: + result = symAddr(sslDynlib, alternativeName) + + proc sslSymThrows(name: string, alternativeName = ""): pointer = + result = sslSymNullable(name, alternativeName) + if result.isNil: raiseInvalidLibrary(name) proc loadPSSLMethod(method1, method2: string): PSSL_METHOD = ## Load from OpenSSL if available, otherwise - let m1 = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method1)) - if not m1.isNil: - return m1() - cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method2))() + ## + let methodSym = sslSymNullable(method1, method2) + if methodSym.isNil: + raise newException(LibraryError, "Could not load " & method1 & " nor " & method2) + + let method2Proc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](methodSym) + return method2Proc() proc SSL_library_init*(): cint {.discardable.} = ## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0 otherwise ## SSL_library_init - let theProc = cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](sslSym("OPENSSL_init_ssl")) - if not theProc.isNil: - return theProc(0, 0) - let olderProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init")) + let newInitSym = sslSymNullable("OPENSSL_init_ssl") + if not newInitSym.isNil: + let newInitProc = + cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](newInitSym) + return newInitProc(0, 0) + let olderProc = cast[proc(): cint {.cdecl.}](sslSymThrows("SSL_library_init")) if not olderProc.isNil: result = olderProc() proc SSL_load_error_strings*() = - let theProc = cast[proc() {.cdecl.}](sslSym("SSL_load_error_strings")) + # TODO: Are we ignoring this on purpose? SSL GitHub CI fails otherwise. + let theProc = cast[proc() {.cdecl.}](sslSymNullable("SSL_load_error_strings")) if not theProc.isNil: theProc() proc SSLv23_client_method*(): PSSL_METHOD = @@ -343,12 +362,13 @@ else: loadPSSLMethod("TLS_server_method", "SSLv23_server_method") proc OpenSSL_add_all_algorithms*() = - let theProc = cast[proc() {.cdecl.}](sslSym("OPENSSL_add_all_algorithms_conf")) + # TODO: Are we ignoring this on purpose? SSL GitHub CI fails otherwise. + let theProc = cast[proc() {.cdecl.}](sslSymNullable("OPENSSL_add_all_algorithms_conf")) if not theProc.isNil: theProc() proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long or 0 if not available - let theProc = cast[proc(): culong {.cdecl.}](sslSym("OpenSSL_version_num")) + let theProc = cast[proc(): culong {.cdecl.}](sslSymNullable("OpenSSL_version_num")) result = if theProc.isNil: 0.culong else: theProc() From bff742cd8b15556dd7bc7efd3a4ef258f5e0a2a1 Mon Sep 17 00:00:00 2001 From: Hessam Mehr Date: Wed, 8 Apr 2020 14:24:14 +0100 Subject: [PATCH 0308/4254] Add support for `zig cc` as C compiler. (#13757) --- compiler/extccomp.nim | 11 +++++++++++ compiler/options.nim | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f846f9683..aad3ddfab 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -138,6 +138,16 @@ compiler clang: result.compilerExe = "clang" result.cppCompiler = "clang++" +# Zig cc (Clang) C/C++ Compiler +compiler zig: + result = clang() # Uses settings from llvmGcc + + result.name = "zig" + result.compilerExe = "zig" + result.cppCompiler = "zig" + result.compileTmpl = "cc " & result.compileTmpl + result.linkTmpl = "cc " & result.linkTmpl + # Microsoft Visual C/C++ Compiler compiler vcc: result = ( @@ -375,6 +385,7 @@ const nintendoSwitchGCC(), llvmGcc(), clang(), + zig(), lcc(), bcc(), dmc(), diff --git a/compiler/options.nim b/compiler/options.nim index 038e83eb0..813d2d6e5 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -162,7 +162,7 @@ type disabledSf, writeOnlySf, readOnlySf, v2Sf TSystemCC* = enum - ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, + ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccZig, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, ccTcc, ccPcc, ccUcc, ccIcl, ccIcc, ccClangCl ExceptionSystem* = enum From 7b582fd6a63e9fc62afbbcde2fc54192c199f04f Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 8 Apr 2020 18:51:23 +0100 Subject: [PATCH 0309/4254] fixes #13863 (#13929) Co-authored-by: cooldome --- lib/pure/marshal.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index cf262b5f0..daf313b5c 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -50,6 +50,11 @@ ## * `streams module `_ ## * `json module `_ +when defined(nimV2): + {.error: """marshal module is not supported in new runtime. +Please use alternative packages for serialization. +It is possible to reimplement this module using generics and type traits. +Please contribute new implementation.""".} import streams, typeinfo, json, intsets, tables, unicode From cc3f5d21b249fe8f96f61369e53e794bf34e65a5 Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 9 Apr 2020 13:56:08 +0000 Subject: [PATCH 0310/4254] posix: add full Haiku support (#13931) * posix: add full Haiku support This commit provides a posix_haiku derived from posix_other, with types following Haiku's definition. This fixes cases where the compiler generates type check for the wrong types (ie. checks where generated for an int-derived type but it's actually implemented as an uint instead). * tools/kochdocs: welcome posix_haiku to the blacklist --- lib/posix/posix.nim | 7 +- lib/posix/posix_haiku.nim | 603 ++++++++++++++++++++++++++++++++++++++ tools/kochdocs.nim | 1 + 3 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 lib/posix/posix_haiku.nim diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index dbc9f5109..d1f2faca5 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -88,7 +88,7 @@ const type Sighandler = proc (a: cint) {.noconv.} const StatHasNanoseconds* = defined(linux) or defined(freebsd) or - defined(osx) or defined(openbsd) or defined(dragonfly) ## \ + defined(osx) or defined(openbsd) or defined(dragonfly) or defined(haiku) ## \ ## Boolean flag that indicates if the system supports nanosecond time ## resolution in the fields of ``Stat``. Note that the nanosecond based fields ## (``Stat.st_atim``, ``Stat.st_mtim`` and ``Stat.st_ctim``) can be accessed @@ -105,6 +105,8 @@ elif (defined(macos) or defined(macosx) or defined(bsd)) and defined(cpu64): include posix_macos_amd64 elif defined(nintendoswitch): include posix_nintendoswitch +elif defined(haiku): + include posix_haiku else: include posix_other @@ -636,7 +638,8 @@ proc posix_madvise*(a1: pointer, a2: int, a3: cint): cint {. importc, header: "".} proc posix_mem_offset*(a1: pointer, a2: int, a3: var Off, a4: var int, a5: var cint): cint {.importc, header: "".} -when not (defined(linux) and defined(amd64)) and not defined(nintendoswitch): +when not (defined(linux) and defined(amd64)) and not defined(nintendoswitch) and + not defined(haiku): proc posix_typed_mem_get_info*(a1: cint, a2: var Posix_typed_mem_info): cint {.importc, header: "".} proc posix_typed_mem_open*(a1: cstring, a2, a3: cint): cint {. diff --git a/lib/posix/posix_haiku.nim b/lib/posix/posix_haiku.nim new file mode 100644 index 000000000..bb430a8f3 --- /dev/null +++ b/lib/posix/posix_haiku.nim @@ -0,0 +1,603 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +const + hasSpawnH = true # should exist for every Posix system nowadays + hasAioH = defined(linux) + +when defined(linux) and not defined(android): + # On Linux: + # timer_{create,delete,settime,gettime}, + # clock_{getcpuclockid, getres, gettime, nanosleep, settime} lives in librt + {.passl: "-lrt".} +when defined(solaris): + # On Solaris hstrerror lives in libresolv + {.passl: "-lresolv".} + +type + DIR* {.importc: "DIR", header: "", + incompleteStruct.} = object + ## A type representing a directory stream. + +type + SocketHandle* = distinct cint # The type used to represent socket descriptors + +type + Time* {.importc: "time_t", header: "".} = distinct ( + when defined(i386): + int32 + else: + int64 + ) + Timespec* {.importc: "struct timespec", + header: "", final, pure.} = object ## struct timespec + tv_sec*: Time ## Seconds. + tv_nsec*: int ## Nanoseconds. + + Dirent* {.importc: "struct dirent", + header: "", final, pure.} = object ## dirent_t struct + when defined(haiku): + d_dev*: Dev ## Device (not POSIX) + d_pdev*: Dev ## Parent device (only for queries) (not POSIX) + d_ino*: Ino ## File serial number. + when defined(dragonfly): + # DragonflyBSD doesn't have `d_reclen` field. + d_type*: uint8 + elif defined(linux) or defined(macosx) or defined(freebsd) or + defined(netbsd) or defined(openbsd) or defined(genode): + d_reclen*: cshort ## Length of this record. (not POSIX) + d_type*: int8 ## Type of file; not supported by all filesystem types. + ## (not POSIX) + when defined(linux) or defined(openbsd): + d_off*: Off ## Not an offset. Value that ``telldir()`` would return. + elif defined(haiku): + d_pino*: Ino ## Parent inode (only for queries) (not POSIX) + d_reclen*: cushort ## Length of this record. (not POSIX) + + when not defined(haiku): + d_name*: array[0..255, char] ## Name of entry. + else: + d_name*: UncheckedArray[char] ## Name of entry (NUL terminated). + + Tflock* {.importc: "struct flock", final, pure, + header: "".} = object ## flock type + l_type*: cshort ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK. + l_whence*: cshort ## Flag for starting offset. + l_start*: Off ## Relative offset in bytes. + l_len*: Off ## Size; if 0 then until EOF. + l_pid*: Pid ## Process ID of the process holding the lock; + ## returned with F_GETLK. + + FTW* {.importc: "struct FTW", header: "", final, pure.} = object + base*: cint + level*: cint + + Glob* {.importc: "glob_t", header: "", + final, pure.} = object ## glob_t + gl_pathc*: int ## Count of paths matched by pattern. + gl_pathv*: cstringArray ## Pointer to a list of matched pathnames. + gl_offs*: int ## Slots to reserve at the beginning of gl_pathv. + + Group* {.importc: "struct group", header: "", + final, pure.} = object ## struct group + gr_name*: cstring ## The name of the group. + gr_gid*: Gid ## Numerical group ID. + gr_mem*: cstringArray ## Pointer to a null-terminated array of character + ## pointers to member names. + + Iconv* {.importc: "iconv_t", header: "", final, pure.} = + object ## Identifies the conversion from one codeset to another. + + Lconv* {.importc: "struct lconv", header: "", final, + pure.} = object + currency_symbol*: cstring + decimal_point*: cstring + frac_digits*: char + grouping*: cstring + int_curr_symbol*: cstring + int_frac_digits*: char + int_n_cs_precedes*: char + int_n_sep_by_space*: char + int_n_sign_posn*: char + int_p_cs_precedes*: char + int_p_sep_by_space*: char + int_p_sign_posn*: char + mon_decimal_point*: cstring + mon_grouping*: cstring + mon_thousands_sep*: cstring + negative_sign*: cstring + n_cs_precedes*: char + n_sep_by_space*: char + n_sign_posn*: char + positive_sign*: cstring + p_cs_precedes*: char + p_sep_by_space*: char + p_sign_posn*: char + thousands_sep*: cstring + + Mqd* {.importc: "mqd_t", header: "", final, pure.} = object + MqAttr* {.importc: "struct mq_attr", + header: "", + final, pure.} = object ## message queue attribute + mq_flags*: int ## Message queue flags. + mq_maxmsg*: int ## Maximum number of messages. + mq_msgsize*: int ## Maximum message size. + mq_curmsgs*: int ## Number of messages currently queued. + + Passwd* {.importc: "struct passwd", header: "", + final, pure.} = object ## struct passwd + pw_name*: cstring ## User's login name. + pw_uid*: Uid ## Numerical user ID. + pw_gid*: Gid ## Numerical group ID. + pw_dir*: cstring ## Initial working directory. + pw_shell*: cstring ## Program to use as shell. + + Blkcnt* {.importc: "blkcnt_t", header: "".} = int64 + ## used for file block counts + Blksize* {.importc: "blksize_t", header: "".} = int32 + ## used for block sizes + Clock* {.importc: "clock_t", header: "".} = int32 + ClockId* {.importc: "clockid_t", header: "".} = int32 + Dev* {.importc: "dev_t", header: "".} = int32 + Fsblkcnt* {.importc: "fsblkcnt_t", header: "".} = int64 + Fsfilcnt* {.importc: "fsfilcnt_t", header: "".} = int64 + Gid* {.importc: "gid_t", header: "".} = uint32 + Id* {.importc: "id_t", header: "".} = int32 + Ino* {.importc: "ino_t", header: "".} = int64 + Key* {.importc: "key_t", header: "".} = int32 + Mode* {.importc: "mode_t", header: "".} = ( + when defined(android) or defined(macos) or defined(macosx) or + (defined(bsd) and not defined(openbsd) and not defined(netbsd)): + uint16 + else: + uint32 + ) + Nlink* {.importc: "nlink_t", header: "".} = int32 + Off* {.importc: "off_t", header: "".} = int64 + Pid* {.importc: "pid_t", header: "".} = int32 + Pthread_attr* {.importc: "pthread_attr_t", header: "".} = object + Pthread_barrier* {.importc: "pthread_barrier_t", + header: "".} = object + Pthread_barrierattr* {.importc: "pthread_barrierattr_t", + header: "".} = object + Pthread_cond* {.importc: "pthread_cond_t", header: "".} = object + Pthread_condattr* {.importc: "pthread_condattr_t", + header: "".} = object + Pthread_key* {.importc: "pthread_key_t", header: "".} = object + Pthread_mutex* {.importc: "pthread_mutex_t", header: "".} = object + Pthread_mutexattr* {.importc: "pthread_mutexattr_t", + header: "".} = object + Pthread_once* {.importc: "pthread_once_t", header: "".} = object + Pthread_rwlock* {.importc: "pthread_rwlock_t", + header: "".} = object + Pthread_rwlockattr* {.importc: "pthread_rwlockattr_t", + header: "".} = object + Pthread_spinlock* {.importc: "pthread_spinlock_t", + header: "".} = object + Pthread* {.importc: "pthread_t", header: "".} = object + Suseconds* {.importc: "suseconds_t", header: "".} = int32 + #Ttime* {.importc: "time_t", header: "".} = int + Timer* {.importc: "timer_t", header: "".} = object + Uid* {.importc: "uid_t", header: "".} = uint32 + Useconds* {.importc: "useconds_t", header: "".} = uint32 + + Utsname* {.importc: "struct utsname", + header: "", + final, pure.} = object ## struct utsname + sysname*, ## Name of this implementation of the operating system. + nodename*, ## Name of this node within the communications + ## network to which this node is attached, if any. + release*, ## Current release level of this implementation. + version*, ## Current version level of this release. + machine*: array[32, char] ## Name of the hardware type on which the + ## system is running. + + Sem* {.importc: "sem_t", header: "", final, pure.} = object + Ipc_perm* {.importc: "struct ipc_perm", + header: "", final, pure.} = object ## struct ipc_perm + uid*: Uid ## Owner's user ID. + gid*: Gid ## Owner's group ID. + cuid*: Uid ## Creator's user ID. + cgid*: Gid ## Creator's group ID. + mode*: Mode ## Read/write permission. + + Stat* {.importc: "struct stat", + header: "", final, pure.} = object ## struct stat + st_dev*: Dev ## Device ID of device containing file. + st_ino*: Ino ## File serial number. + st_mode*: Mode ## Mode of file (see below). + st_nlink*: Nlink ## Number of hard links to the file. + st_uid*: Uid ## User ID of file. + st_gid*: Gid ## Group ID of file. + st_rdev*: Dev ## Device ID (if file is character or block special). + st_size*: Off ## For regular files, the file size in bytes. + ## For symbolic links, the length in bytes of the + ## pathname contained in the symbolic link. + ## For a shared memory object, the length in bytes. + ## For a typed memory object, the length in bytes. + ## For other file types, the use of this field is + ## unspecified. + when StatHasNanoseconds: + st_atim*: Timespec ## Time of last access. + st_mtim*: Timespec ## Time of last data modification. + st_ctim*: Timespec ## Time of last status change. + else: + st_atime*: Time ## Time of last access. + st_mtime*: Time ## Time of last data modification. + st_ctime*: Time ## Time of last status change. + st_blksize*: Blksize ## A file system-specific preferred I/O block size + ## for this object. In some file system types, this + ## may vary from file to file. + st_blocks*: Blkcnt ## Number of blocks allocated for this object. + + + Statvfs* {.importc: "struct statvfs", header: "", + final, pure.} = object ## struct statvfs + f_bsize*: culong ## File system block size. + f_frsize*: culong ## Fundamental file system block size. + f_blocks*: Fsblkcnt ## Total number of blocks on file system + ## in units of f_frsize. + f_bfree*: Fsblkcnt ## Total number of free blocks. + f_bavail*: Fsblkcnt ## Number of free blocks available to + ## non-privileged process. + f_files*: Fsfilcnt ## Total number of file serial numbers. + f_ffree*: Fsfilcnt ## Total number of free file serial numbers. + f_favail*: Fsfilcnt ## Number of file serial numbers available to + ## non-privileged process. + f_fsid*: culong ## File system ID. + f_flag*: culong ## Bit mask of f_flag values. + f_namemax*: culong ## Maximum filename length. + + Tm* {.importc: "struct tm", header: "", + final, pure.} = object ## struct tm + tm_sec*: cint ## Seconds [0,60]. + tm_min*: cint ## Minutes [0,59]. + tm_hour*: cint ## Hour [0,23]. + tm_mday*: cint ## Day of month [1,31]. + tm_mon*: cint ## Month of year [0,11]. + tm_year*: cint ## Years since 1900. + tm_wday*: cint ## Day of week [0,6] (Sunday =0). + tm_yday*: cint ## Day of year [0,365]. + tm_isdst*: cint ## Daylight Savings flag. + Itimerspec* {.importc: "struct itimerspec", header: "", + final, pure.} = object ## struct itimerspec + it_interval*: Timespec ## Timer period. + it_value*: Timespec ## Timer expiration. + + Sig_atomic* {.importc: "sig_atomic_t", header: "".} = cint + ## Possibly volatile-qualified integer type of an object that can be + ## accessed as an atomic entity, even in the presence of asynchronous + ## interrupts. + Sigset* {.importc: "sigset_t", header: "".} = uint64 + + SigEvent* {.importc: "struct sigevent", + header: "", final, pure.} = object ## struct sigevent + sigev_notify*: cint ## Notification type. + sigev_signo*: cint ## Signal number. + sigev_value*: SigVal ## Signal value. + sigev_notify_function*: proc (x: SigVal) {.noconv.} ## Notification func. + sigev_notify_attributes*: ptr Pthread_attr ## Notification attributes. + + SigVal* {.importc: "union sigval", + header: "", final, pure.} = object ## struct sigval + sival_ptr*: pointer ## pointer signal value; + ## integer signal value not defined! + Sigaction* {.importc: "struct sigaction", + header: "", final, pure.} = object ## struct sigaction + sa_handler*: proc (x: cint) {.noconv.} ## Pointer to a signal-catching + ## function or one of the macros + ## SIG_IGN or SIG_DFL. + sa_mask*: Sigset ## Set of signals to be blocked during execution of + ## the signal handling function. + sa_flags*: cint ## Special flags. + sa_sigaction*: proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.} + + Stack* {.importc: "stack_t", + header: "", final, pure.} = object ## stack_t + ss_sp*: pointer ## Stack base or pointer. + ss_size*: csize ## Stack size. + ss_flags*: cint ## Flags. + + SigInfo* {.importc: "siginfo_t", + header: "", final, pure.} = object ## siginfo_t + si_signo*: cint ## Signal number. + si_code*: cint ## Signal code. + si_errno*: cint ## If non-zero, an errno value associated with + ## this signal, as defined in . + si_pid*: Pid ## Sending process ID. + si_uid*: Uid ## Real user ID of sending process. + si_addr*: pointer ## Address of faulting instruction. + si_status*: cint ## Exit value or signal. + si_band*: int ## Band event for SIGPOLL. + si_value*: SigVal ## Signal value. + + Nl_item* {.importc: "nl_item", header: "".} = cint + Nl_catd* {.importc: "nl_catd", header: "".} = cint + + Sched_param* {.importc: "struct sched_param", + header: "", + final, pure.} = object ## struct sched_param + sched_priority*: cint + + Timeval* {.importc: "struct timeval", header: "", + final, pure.} = object ## struct timeval + tv_sec*: Time ## Seconds. + tv_usec*: Suseconds ## Microseconds. + TFdSet* {.importc: "fd_set", header: "", + final, pure.} = object + Mcontext* {.importc: "mcontext_t", header: "", + final, pure.} = object + Ucontext* {.importc: "ucontext_t", header: "", + final, pure.} = object ## ucontext_t + uc_link*: ptr Ucontext ## Pointer to the context that is resumed + ## when this context returns. + uc_sigmask*: Sigset ## The set of signals that are blocked when this + ## context is active. + uc_stack*: Stack ## The stack used by this context. + uc_mcontext*: Mcontext ## A machine-specific representation of the saved + ## context. + +when hasAioH: + type + Taiocb* {.importc: "struct aiocb", header: "", + final, pure.} = object ## struct aiocb + aio_fildes*: cint ## File descriptor. + aio_offset*: Off ## File offset. + aio_buf*: pointer ## Location of buffer. + aio_nbytes*: int ## Length of transfer. + aio_reqprio*: cint ## Request priority offset. + aio_sigevent*: SigEvent ## Signal number and value. + aio_lio_opcode: cint ## Operation to be performed. + +when hasSpawnH: + type + Tposix_spawnattr* {.importc: "posix_spawnattr_t", + header: "", final, pure.} = object + Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", + header: "", final, pure.} = object + +when defined(linux): + # from sys/un.h + const Sockaddr_un_path_length* = 108 +elif defined(haiku): + # from sys/un.h + const Sockaddr_un_path_length* = 126 +else: + # according to http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html + # this is >=92 + const Sockaddr_un_path_length* = 92 + +type + SockLen* {.importc: "socklen_t", header: "".} = uint32 + TSa_Family* {.importc: "sa_family_t", header: "".} = uint8 + + SockAddr* {.importc: "struct sockaddr", header: "", + pure, final.} = object ## struct sockaddr + sa_family*: TSa_Family ## Address family. + sa_data*: array[0..255, char] ## Socket address (variable-length data). + + Sockaddr_un* {.importc: "struct sockaddr_un", header: "", + pure, final.} = object ## struct sockaddr_un + sun_family*: TSa_Family ## Address family. + sun_path*: array[0..Sockaddr_un_path_length-1, char] ## Socket path + + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + ss_family*: TSa_Family ## Address family. + + Tif_nameindex* {.importc: "struct if_nameindex", final, + pure, header: "".} = object ## struct if_nameindex + if_index*: cuint ## Numeric index of the interface. + if_name*: cstring ## Null-terminated name of the interface. + + + IOVec* {.importc: "struct iovec", pure, final, + header: "".} = object ## struct iovec + iov_base*: pointer ## Base address of a memory region for input or output. + iov_len*: csize ## The size of the memory pointed to by iov_base. + + Tmsghdr* {.importc: "struct msghdr", pure, final, + header: "".} = object ## struct msghdr + msg_name*: pointer ## Optional address. + msg_namelen*: SockLen ## Size of address. + msg_iov*: ptr IOVec ## Scatter/gather array. + msg_iovlen*: cint ## Members in msg_iov. + msg_control*: pointer ## Ancillary data; see below. + msg_controllen*: SockLen ## Ancillary data buffer len. + msg_flags*: cint ## Flags on received message. + + + Tcmsghdr* {.importc: "struct cmsghdr", pure, final, + header: "".} = object ## struct cmsghdr + cmsg_len*: SockLen ## Data byte count, including the cmsghdr. + cmsg_level*: cint ## Originating protocol. + cmsg_type*: cint ## Protocol-specific type. + + TLinger* {.importc: "struct linger", pure, final, + header: "".} = object ## struct linger + l_onoff*: cint ## Indicates whether linger option is enabled. + l_linger*: cint ## Linger time, in seconds. + + InPort* = uint16 + InAddrScalar* = uint32 + + InAddrT* {.importc: "in_addr_t", pure, final, + header: "".} = uint32 + + InAddr* {.importc: "struct in_addr", pure, final, + header: "".} = object ## struct in_addr + s_addr*: InAddrScalar + + Sockaddr_in* {.importc: "struct sockaddr_in", pure, final, + header: "".} = object ## struct sockaddr_in + sin_family*: TSa_Family ## AF_INET. + sin_port*: InPort ## Port number. + sin_addr*: InAddr ## IP address. + + In6Addr* {.importc: "struct in6_addr", pure, final, + header: "".} = object ## struct in6_addr + s6_addr*: array[0..15, char] + + Sockaddr_in6* {.importc: "struct sockaddr_in6", pure, final, + header: "".} = object ## struct sockaddr_in6 + sin6_family*: TSa_Family ## AF_INET6. + sin6_port*: InPort ## Port number. + sin6_flowinfo*: int32 ## IPv6 traffic class and flow information. + sin6_addr*: In6Addr ## IPv6 address. + sin6_scope_id*: int32 ## Set of interfaces for a scope. + + Tipv6_mreq* {.importc: "struct ipv6_mreq", pure, final, + header: "".} = object ## struct ipv6_mreq + ipv6mr_multiaddr*: In6Addr ## IPv6 multicast address. + ipv6mr_interface*: cuint ## Interface index. + + Hostent* {.importc: "struct hostent", pure, final, + header: "".} = object ## struct hostent + h_name*: cstring ## Official name of the host. + h_aliases*: cstringArray ## A pointer to an array of pointers to + ## alternative host names, terminated by a + ## null pointer. + h_addrtype*: cint ## Address type. + h_length*: cint ## The length, in bytes, of the address. + h_addr_list*: cstringArray ## A pointer to an array of pointers to network + ## addresses (in network byte order) for the + ## host, terminated by a null pointer. + + Tnetent* {.importc: "struct netent", pure, final, + header: "".} = object ## struct netent + n_name*: cstring ## Official, fully-qualified (including the + ## domain) name of the host. + n_aliases*: cstringArray ## A pointer to an array of pointers to + ## alternative network names, terminated by a + ## null pointer. + n_addrtype*: cint ## The address type of the network. + n_net*: InAddrT ## The network number, in host byte order. + + Protoent* {.importc: "struct protoent", pure, final, + header: "".} = object ## struct protoent + p_name*: cstring ## Official name of the protocol. + p_aliases*: cstringArray ## A pointer to an array of pointers to + ## alternative protocol names, terminated by + ## a null pointer. + p_proto*: cint ## The protocol number. + + Servent* {.importc: "struct servent", pure, final, + header: "".} = object ## struct servent + s_name*: cstring ## Official name of the service. + s_aliases*: cstringArray ## A pointer to an array of pointers to + ## alternative service names, terminated by + ## a null pointer. + s_port*: cint ## The port number at which the service + ## resides, in network byte order. + s_proto*: cstring ## The name of the protocol to use when + ## contacting the service. + + AddrInfo* {.importc: "struct addrinfo", pure, final, + header: "".} = object ## struct addrinfo + ai_flags*: cint ## Input flags. + ai_family*: cint ## Address family of socket. + ai_socktype*: cint ## Socket type. + ai_protocol*: cint ## Protocol of socket. + ai_addrlen*: SockLen ## Length of socket address. + ai_addr*: ptr SockAddr ## Socket address of socket. + ai_canonname*: cstring ## Canonical name of service location. + ai_next*: ptr AddrInfo ## Pointer to next in list. + + TPollfd* {.importc: "struct pollfd", pure, final, + header: "".} = object ## struct pollfd + fd*: cint ## The following descriptor being polled. + events*: cshort ## The input event flags (see below). + revents*: cshort ## The output event flags (see below). + + Tnfds* {.importc: "nfds_t", header: "".} = culong + +var + errno* {.importc, header: "".}: cint ## error variable + h_errno* {.importc, header: "".}: cint + daylight* {.importc, header: "".}: cint + timezone* {.importc, header: "".}: int + +# Regenerate using detect.nim! +include posix_other_consts + +when defined(linux): + var + MAP_POPULATE* {.importc, header: "".}: cint + ## Populate (prefault) page tables for a mapping. +else: + var + MAP_POPULATE*: cint = 0 + +when defined(linux) or defined(nimdoc): + when defined(alpha) or defined(mips) or defined(mipsel) or + defined(mips64) or defined(mips64el) or defined(parisc) or + defined(sparc) or defined(sparc64) or defined(nimdoc): + const SO_REUSEPORT* = cint(0x0200) + ## Multiple binding: load balancing on incoming TCP connections + ## or UDP packets. (Requires Linux kernel > 3.9) + else: + const SO_REUSEPORT* = cint(15) +else: + var SO_REUSEPORT* {.importc, header: "".}: cint + +when defined(macosx): + # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect + # Instead we should use SO_NOSIGPIPE in setsockopt + const + MSG_NOSIGNAL* = 0'i32 + var + SO_NOSIGPIPE* {.importc, header: "".}: cint +elif defined(solaris): + # Solaris doesn't have MSG_NOSIGNAL + const + MSG_NOSIGNAL* = 0'i32 +else: + var + MSG_NOSIGNAL* {.importc, header: "".}: cint + ## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected. + +when defined(haiku): + const + SIGKILLTHR* = 21 ## BeOS specific: Kill just the thread, not team + +when hasSpawnH: + when defined(linux): + # better be safe than sorry; Linux has this flag, macosx doesn't, don't + # know about the other OSes + + # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we + # can't get the magic number from spawn.h + const POSIX_SPAWN_USEVFORK* = cint(0x40) + else: + # macosx lacks this, so we define the constant to be 0 to not affect + # OR'ing of flags: + const POSIX_SPAWN_USEVFORK* = cint(0) + +# +proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} + ## Exit code, iff WIFEXITED(s) +proc WTERMSIG*(s: cint): cint {.importc, header: "".} + ## Termination signal, iff WIFSIGNALED(s) +proc WSTOPSIG*(s: cint): cint {.importc, header: "".} + ## Stop signal, iff WIFSTOPPED(s) +proc WIFEXITED*(s: cint): bool {.importc, header: "".} + ## True if child exited normally. +proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} + ## True if child exited due to uncaught signal. +proc WIFSTOPPED*(s: cint): bool {.importc, header: "".} + ## True if child is currently stopped. +proc WIFCONTINUED*(s: cint): bool {.importc, header: "".} + ## True if child has been continued. + +when defined(nimHasStyleChecks): + {.pop.} diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index a23d17b21..ba60a3749 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -170,6 +170,7 @@ lib/posix/posix_linux_amd64.nim lib/posix/posix_linux_amd64_consts.nim lib/posix/posix_other_consts.nim lib/posix/posix_openbsd_amd64.nim +lib/posix/posix_haiku.nim """.splitWhitespace() when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): From 5f6962337de94b524afbb4f41b79eae362af67c8 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 10 Apr 2020 07:34:52 +0000 Subject: [PATCH 0311/4254] osproc: added a better version of waitForExit for Haiku (#13938) Also modified tosprocterminate to verify waitForExit implementations. --- lib/pure/osproc.nim | 61 +++++++++++++++++++++++++++++++ tests/stdlib/tosprocterminate.nim | 28 +++++++++++--- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 1472d4e3d..ed5ab7b97 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1167,6 +1167,67 @@ elif not defined(useNimRtl): discard posix.close(kqFD) result = exitStatusLikeShell(p.exitStatus) + elif defined(haiku): + const + B_OBJECT_TYPE_THREAD = 3 + B_EVENT_INVALID = 0x1000 + B_RELATIVE_TIMEOUT = 0x8 + + type + ObjectWaitInfo {.importc: "object_wait_info", header: "OS.h".} = object + obj {.importc: "object".}: int32 + typ {.importc: "type".}: uint16 + events: uint16 + + proc waitForObjects(infos: ptr ObjectWaitInfo, numInfos: cint, flags: uint32, + timeout: int64): clong + {.importc: "wait_for_objects_etc", header: "OS.h".} + + proc waitForExit(p: Process, timeout: int = -1): int = + if p.exitFlag: + return exitStatusLikeShell(p.exitStatus) + + if timeout == -1: + var status: cint = 1 + if waitpid(p.id, status, 0) < 0: + raiseOSError(osLastError()) + p.exitFlag = true + p.exitStatus = status + else: + var info = ObjectWaitInfo( + obj: p.id, # Haiku's PID is actually the main thread ID. + typ: B_OBJECT_TYPE_THREAD, + events: B_EVENT_INVALID # notify when the thread die. + ) + + while true: + var status: cint = 1 + let count = waitForObjects(addr info, 1, B_RELATIVE_TIMEOUT, timeout) + + if count < 0: + let err = count.cint + if err == ETIMEDOUT: + # timeout expired, so we try to kill the process + if posix.kill(p.id, SIGKILL) == -1: + raiseOSError(osLastError()) + if waitpid(p.id, status, 0) < 0: + raiseOSError(osLastError()) + p.exitFlag = true + p.exitStatus = status + break + elif err != EINTR: + raiseOSError(err.OSErrorCode) + elif count > 0: + if waitpid(p.id, status, 0) < 0: + raiseOSError(osLastError()) + p.exitFlag = true + p.exitStatus = status + break + else: + doAssert false, "unreachable!" + + result = exitStatusLikeShell(p.exitStatus) + else: import times diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim index a46d91d68..d487b5e60 100644 --- a/tests/stdlib/tosprocterminate.nim +++ b/tests/stdlib/tosprocterminate.nim @@ -1,8 +1,10 @@ discard """ -outputsub: "SUCCESS" + cmd: "nim $target $options -r $file" + targets: "c cpp" + matrix: "--threads:on; " """ -import os, osproc +import os, osproc, times, std / monotimes when defined(Windows): const ProgramWhichDoesNotEnd = "notepad" @@ -19,7 +21,21 @@ while process.running() and TimeToWait > 0: sleep(100) TimeToWait = TimeToWait - 100 -if process.running(): - echo("FAILED") -else: - echo("SUCCESS") +doAssert not process.running() +echo("stopped process") + +process.close() + +echo("starting " & ProgramWhichDoesNotEnd) +process = startProcess(ProgramWhichDoesNotEnd) +echo("process should be stopped after 2s") + +let start = getMonoTime() +discard process.waitForExit(2000) +let took = getMonoTime() - start + +doAssert not process.running() +# some additional time to account for overhead +doAssert took < initDuration(seconds = 3) + +echo("stopped process after ", took) From 7238b968f3820331eb342b3e14283f03c71df035 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 11 Apr 2020 17:16:26 -0300 Subject: [PATCH 0312/4254] Make unused code into actual test, replace echo with doassert (#13952) --- lib/std/varints.nim | 33 --------------- tests/stdlib/tvarints.nim | 84 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 33 deletions(-) create mode 100644 tests/stdlib/tvarints.nim diff --git a/lib/std/varints.nim b/lib/std/varints.nim index fe06b478a..0d18b9069 100644 --- a/lib/std/varints.nim +++ b/lib/std/varints.nim @@ -119,36 +119,3 @@ proc encodeZigzag*(x: int64): uint64 {.inline.} = proc decodeZigzag*(x: uint64): int64 {.inline.} = let casted = cast[int64](x) result = (`shr`(casted, 1)) xor (-(casted and 1)) - -when isMainModule: - #import random - - var dest: array[50, byte] - var got: uint64 - - for test in [0xFFFF_FFFF_FFFFF_FFFFu64, 77u64, 0u64, 10_000_000u64, uint64(high(int64)), - uint64(high(int32)),uint64(low(int32)),uint64(low(int64))]: - let wrLen = writeVu64(dest, test) - let rdLen = readVu64(dest, got) - assert wrLen == rdLen - echo(if got == test: "YES" else: "NO") - echo "number is ", got - - if encodeZigzag(decodeZigzag(test)) != test: - echo "Failure for ", test, " ", encodeZigzag(decodeZigzag(test)), " ", decodeZigzag(test) - - for test in 0u64..300u64: - let wrLen = writeVu64(dest, test) - let rdLen = readVu64(dest, got) - assert wrLen == rdLen - if got != test: - echo "BUG! expected: ", test, " got: ", got, " z0: ", dest[0] - - # check this also works for floats: - for test in [0.0, 0.1, 2.0, +Inf, Nan, NegInf]: - let t = cast[uint64](test) - let wrLenB = writeVu64(dest, t) - let rdLenB = readVu64(dest, got) - assert wrLenB == rdLenB - echo rdLenB - echo(if cast[float64](got) == test: "YES" else: "NO") diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim new file mode 100644 index 000000000..dcdb756ce --- /dev/null +++ b/tests/stdlib/tvarints.nim @@ -0,0 +1,84 @@ +discard """ + cmd: "nim c -r --styleCheck:hint --panics:on $options $file" + matrix: "-d:danger; -d:release" + targets: "c cpp" + nimout: "" + action: "run" + exitcode: 0 + timeout: 60.0 +""" + +import std/varints + + +block: + var dest: array[50, byte] + var got: uint64 + + for test in [0xFFFF_FFFF_FFFFF_FFFFu64, 77u64, 0u64, 10_000_000u64, uint64(high(int64)), + uint64(high(int32)), uint64(high(int32)), uint64(high(int64))]: + let wrLen = writeVu64(dest, test) + let rdLen = readVu64(dest, got) + doAssert wrLen == rdLen + doAssert got == test + + for test in 0u64..300u64: + let wrLen = writeVu64(dest, test) + let rdLen = readVu64(dest, got) + doAssert wrLen == rdLen + doAssert got == test + + # check this also works for floats: + for test in [0.0, 0.1, 2.0, +Inf, NegInf]: + let t = cast[uint64](test) + let wrLenB = writeVu64(dest, t) + let rdLenB = readVu64(dest, got) + doAssert wrLenB == rdLenB + doAssert cast[float64](got) == test + +block: + var hugeIntArray: array[50, byte] + var readedInt: uint64 + doAssert writeVu64(hugeIntArray, 0.uint64) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == 0.uint64 + doAssert writeVu64(hugeIntArray, uint64.high) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == uint64.high + doAssert writeVu64(hugeIntArray, uint64(int64.high)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == uint64(int64.high) + doAssert writeVu64(hugeIntArray, uint64(int32.high)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == uint64(int32.high) + doAssert writeVu64(hugeIntArray, uint64(int16.high)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == uint64(int16.high) + doAssert writeVu64(hugeIntArray, uint64(int8.high)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == uint64(int8.high) + doAssert writeVu64(hugeIntArray, cast[uint64](0.0)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](0.0) + doAssert writeVu64(hugeIntArray, cast[uint64](-0.0)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](-0.0) + doAssert writeVu64(hugeIntArray, cast[uint64](0.1)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](0.1) + doAssert writeVu64(hugeIntArray, cast[uint64](0.9555555555555555555555501)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](0.9555555555555555555555501) + doAssert writeVu64(hugeIntArray, cast[uint64](+Inf)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](+Inf) + doAssert writeVu64(hugeIntArray, cast[uint64](NegInf)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](NegInf) + doAssert writeVu64(hugeIntArray, cast[uint64](Nan)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](Nan) + doAssert writeVu64(hugeIntArray, cast[uint64](3.1415926535897932384626433)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](3.1415926535897932384626433) + doAssert writeVu64(hugeIntArray, cast[uint64](2.71828182845904523536028747)) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == cast[uint64](2.71828182845904523536028747) + +block: + doAssert encodeZigzag(decodeZigzag(0.uint64)) == 0.uint64 + doAssert encodeZigzag(decodeZigzag(uint64(uint32.high))) == uint64(uint32.high) + doAssert encodeZigzag(decodeZigzag(uint64(int32.high))) == uint64(int32.high) + doAssert encodeZigzag(decodeZigzag(uint64(int16.high))) == uint64(int16.high) + doAssert encodeZigzag(decodeZigzag(uint64(int8.high))) == uint64(int8.high) + doAssert encodeZigzag(decodeZigzag(cast[uint64](0.0))) == cast[uint64](0.0) + doAssert encodeZigzag(decodeZigzag(cast[uint64](0.1))) == cast[uint64](0.1) + doAssert encodeZigzag(decodeZigzag(cast[uint64](0.9555555555555555555555501))) == cast[uint64](0.9555555555555555555555501) + doAssert encodeZigzag(decodeZigzag(cast[uint64](+Inf))) == cast[uint64](+Inf) + doAssert encodeZigzag(decodeZigzag(cast[uint64](3.1415926535897932384626433))) == cast[uint64](3.1415926535897932384626433) + doAssert encodeZigzag(decodeZigzag(cast[uint64](2.71828182845904523536028747))) == cast[uint64](2.71828182845904523536028747) From 35b046373abfae8e37d0731855b8b5b49ccbfcfc Mon Sep 17 00:00:00 2001 From: genotrance Date: Sun, 12 Apr 2020 14:08:16 -0500 Subject: [PATCH 0313/4254] Improve #12920 fix (#13958) --- tools/nimgrep.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 26e219330..42b192f24 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -44,7 +44,7 @@ Options: --color[:always] force color even if output is redirected --colorTheme:THEME select color THEME from 'simple' (default), 'bnw' (black and white) ,'ack', or 'gnu' (GNU grep) - --afterContext:N, + --afterContext:N, -a:N print N lines of trailing context after every match --beforeContext:N, -b:N print N lines of leading context before every match @@ -412,6 +412,8 @@ proc processFile(pattern; filename: string; counter: var int, errors: var int) = else: printContextBetween(si, prevMi, curMi) printMatch(si.fileName, curMi) + if t.last == buffer.len - 1: + stdout.write("\n") stdout.flushFile() else: let r = replace(curMi.match, pattern, replacement % matches) @@ -659,8 +661,6 @@ else: walker(rep, f, counter, errors) if errors != 0: printError $errors & " errors" - if counter == 1: - stdout.write("\n") stdout.write($counter & " matches\n") if errors != 0: quit(1) From 2ef39081e1d502d99364d95649bfcaf6cb88b767 Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 13 Apr 2020 08:12:27 +0200 Subject: [PATCH 0314/4254] minor fixes in 1.2 changelog [ci skip] --- changelogs/changelog_1_2_0.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/changelogs/changelog_1_2_0.md b/changelogs/changelog_1_2_0.md index 6a5a6c586..54ead0087 100644 --- a/changelogs/changelog_1_2_0.md +++ b/changelogs/changelog_1_2_0.md @@ -33,7 +33,7 @@ - Added `expectIdent` to the `macros` module. - Added `os.isValidFilename` that returns `true` if `filename` argument is valid for cross-platform use. -- Added `times.isLeapDay` +- Added `times.isLeapDay`. - `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. - Added a new module, `std / compilesettings` for querying the compiler about diverse configuration settings. @@ -53,6 +53,8 @@ was designed for it. For example: ```nim +import std/with + type Foo = object col, pos: string @@ -113,8 +115,6 @@ echo f usage. The `$` operator can be used to obtain the string form of `HttpCode` for comparison if desired. - `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs. -- `net.newContext` now performs SSL Certificate checking on Linux and OSX. - Define `nimDisableCertificateValidation` to disable it globally. - `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false). If it is set to true, it will throw if input dir is invalid instead of a noop (which is the default behaviour, as it was before this change), @@ -128,8 +128,8 @@ echo f of children nodes. - `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" as the dir component of `/root_sub_dir` instead of the empty string. -- The deprecated `lc` macro has been removed from `sugar`. It is now replaced with the - more powerful `collect` macro. +- The deprecated `lc` macro has been removed from `sugar`. It is now replaced + with the more powerful `collect` macro. - `os.relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid path and shouldn't be conflated with `"."`; use `-d:nimOldRelativePathBehavior` to restore the old behavior. @@ -138,25 +138,33 @@ echo f Use `base64.encodeMime` instead. +### Breaking changes + +- `net.newContext` now performs SSL Certificate checking on Linux and OSX. + Define `nimDisableCertificateValidation` to disable it globally. + + + ## Language changes - An `align` pragma can now be used for variables and object fields, similar to the `alignas` declaration modifier in C/C++. -- `=sink` type bound operator is now optional. Compiler can now use combination - of `=destroy` and `copyMem` to move objects efficiently. +- The `=sink` type bound operator is now optional. The compiler can now use a + combination of `=destroy` and `copyMem` to move objects efficiently. - Unsigned integer operators have been fixed to allow promotion of the first operand. - Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim versions. The documentation was improved to acknowledge this special case. See https://github.com/nim-lang/RFCs/issues/175 for more details. -- New syntax for lvalue references: `var b {.byaddr.} = expr` enabled by +- There is a new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by `import std/decls`. - `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for non-builtin pragmas, enabling things like lvalue references (see `decls.byaddr`). + ## Compiler changes -- Generated JS code uses spaces, instead of mixed spaces and tabs. +- The generated JS code uses spaces, instead of mixing spaces and tabs. - The Nim compiler now supports the ``--asm`` command option for easier inspection of the produced assembler code. - The Nim compiler now supports a new pragma called ``.localPassc`` to @@ -192,10 +200,6 @@ echo f with `-d:nimEmulateOverflowChecks`. -## Tool changes - -- Nimpretty doesn't accept negative indentation argument anymore, because it was - breaking files. ## Bugfixes From 814f15018432f7657ed12277790bd444b09a2edc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 13 Apr 2020 05:16:06 -0700 Subject: [PATCH 0315/4254] fix #13848: make var result work with nim cpp (#13959) * fix #13848 * add exhaustive tests for var result --- compiler/semexprs.nim | 6 ++- tests/varres/tvarres0.nim | 108 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 826cf51ba..5c00ce1f8 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1577,9 +1577,13 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) case n.kind of nkHiddenAddr, nkAddr: return n - of nkHiddenDeref, nkDerefExpr: return n[0] + of nkDerefExpr: return n[0] of nkBracketExpr: if n.len == 1: return n[0] + of nkHiddenDeref: + # issue #13848 + # `proc fun(a: var int): var int = a` + discard else: discard let valid = isAssignable(c, n, isLent) if valid != arLValue: diff --git a/tests/varres/tvarres0.nim b/tests/varres/tvarres0.nim index fd10a73bd..0f89c7e71 100644 --- a/tests/varres/tvarres0.nim +++ b/tests/varres/tvarres0.nim @@ -28,3 +28,111 @@ getF().a = 1234 echo getF().a getF() = Foo(a: 12345) echo getF().a + + +block: # #13848 + template fun() = + block: + var m = 1 + + proc identity(o: var int): var int = + result = o + result += 5 + + identity(m) += 3 + doAssert m == 5+4 + + block: + var m = 10 + proc identity2(o: var int): var int = + result = m + result += 100 + + var ignored = 27 + identity2(ignored) += 7 + doAssert m == 10 + 100 + 7 + + block: + iterator test3(o: var int): var int = yield o + var m = 1 + for m2 in test3(m): m2+=3 + doAssert m == 4 + + static: fun() + fun() + + template fun2() = + block: + var m = 1 + var m2 = 1 + iterator test3(o: var int): (var int, var int) = + yield (o, m2) + + for ti in test3(m): + ti[0]+=3 + ti[1]+=4 + + doAssert (m, m2) == (4, 5) + fun2() + # static: fun2() # BUG: Error: attempt to access a nil address kind: rkInt + + template fun3() = + block: + proc test4[T1](o: var T1): var int = o[1] + block: + var m = @[1,2] + test4(m) += 10 + doAssert m[1] == 2+10 + block: + var m = [1,2] + test4(m) += 10 + doAssert m[1] == 2+10 + block: + var m = (1, 2) + test4(m) += 10 + doAssert m[1] == 2+10 + + proc test5[T1](o: var T1): var int = o.x + block: + type Foo = object + x: int + var m = Foo(x: 2) + test5(m) += 10 + doAssert m.x == 2+10 + block: + type Foo = ref object + x: int + var m = Foo(x: 2) + test5(m) += 10 + doAssert m.x == 2+10 + + proc test6[T1](o: T1): var int = o.x + block: + type Foo = ref object + x: int + var m = Foo(x: 2) + test6(m) += 10 + doAssert m.x == 2+10 + + fun3() + static: fun3() + + when false: + # BUG: + # c: SIGSEGV + # cpp: error: call to implicitly-deleted default constructor of 'tyTuple__ILZebuYefUeQLAzY85QkHA' + proc test7[T](o: var T): (var int,) = + (o[1], ) + var m = @[1,2] + test7(m)[0] += 10 + +block: + # example from #13848 + type + MyType[T] = object + a,b: T + MyTypeAlias = MyType[float32] + + var m: MyTypeAlias + proc identity(o: var MyTypeAlias): var MyTypeAlias = o + discard identity(m) From 8ba915e4498be3d17af894f5fb46c7b621ef5abb Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 13 Apr 2020 13:17:22 +0100 Subject: [PATCH 0316/4254] error msg for #13864 (#13962) Co-authored-by: cooldome --- compiler/semexprs.nim | 5 +++++ tests/arc/tref_cast_error.nim | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/arc/tref_cast_error.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5c00ce1f8..3d41b592c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -189,6 +189,11 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = return false if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc: return false + if conf.selectedGC in {gcArc, gcOrc}: + let d = skipTypes(dst, abstractInst) + let s = skipTypes(src, abstractInst) + if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal: + return false var dstSize, srcSize: BiggestInt dstSize = computeSize(conf, dst) diff --git a/tests/arc/tref_cast_error.nim b/tests/arc/tref_cast_error.nim new file mode 100644 index 000000000..b0d2faf77 --- /dev/null +++ b/tests/arc/tref_cast_error.nim @@ -0,0 +1,15 @@ +discard """ + cmd: "nim c --gc:arc $file" + errormsg: "expression cannot be cast to ref RootObj" + joinable: false +""" + +type Variant* = object + refval: ref RootObj + +proc newVariant*[T](val: T): Variant = + let pt = T.new() + pt[] = val + result = Variant(refval: cast[ref RootObj](pt)) + +var v = newVariant(@[1, 2, 3]) From 40b64ccd7b2d6c42ebe3c3ad1e7fdfa3fa7a00dd Mon Sep 17 00:00:00 2001 From: jiro Date: Mon, 13 Apr 2020 21:21:45 +0900 Subject: [PATCH 0317/4254] Add runnableExamples to bitops module (#13951) * doc: bitops: add runnableExamples * doc: bitops: add notes to documentation comments of macros * doc: bitops: add periods to documentation comments * doc: bitops: add static * Revert "doc: bitops: add static" This reverts commit 595ee134abcd451e73ddde963c1b3e49a275f2e5. * doc: bitops: add `var` to arguments of macros * doc: bitops: remove examples of testBit --- lib/pure/bitops.nim | 158 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 15 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 9ebdabb7b..cf6013c77 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -68,55 +68,109 @@ when defined(nimHasalignOf): import macros type BitsRange*[T] = range[0..sizeof(T)*8-1] - ## Returns a range with all bit positions for type ``T`` + ## Returns a range with all bit positions for type ``T``. proc setMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = - ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1 + ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1. + runnableExamples: + var v = 0b0000_0011'u8 + v.setMask(0b0000_1010'u8) + doAssert v == 0b0000_1011'u8 + v = v or mask proc clearMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = - ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0 + ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0. + runnableExamples: + var v = 0b0000_0011'u8 + v.clearMask(0b0000_1010'u8) + doAssert v == 0b0000_0001'u8 + v = v and not mask proc flipMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = - ## Returns ``v``, with all the ``1`` bits from ``mask`` flipped + ## Returns ``v``, with all the ``1`` bits from ``mask`` flipped. + runnableExamples: + var v = 0b0000_0011'u8 + v.flipMask(0b0000_1010'u8) + doAssert v == 0b0000_1001'u8 + v = v xor mask proc setBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = - ## Returns ``v``, with the bit at position ``bit`` set to 1 + ## Returns ``v``, with the bit at position ``bit`` set to 1. + runnableExamples: + var v = 0b0000_0011'u8 + v.setBit(5'u8) + doAssert v == 0b0010_0011'u8 + v.setMask(1.T shl bit) proc clearBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = - ## Returns ``v``, with the bit at position ``bit`` set to 0 + ## Returns ``v``, with the bit at position ``bit`` set to 0. + runnableExamples: + var v = 0b0000_0011'u8 + v.clearBit(1'u8) + doAssert v == 0b0000_0001'u8 + v.clearMask(1.T shl bit) proc flipBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = - ## Returns ``v``, with the bit at position ``bit`` flipped + ## Returns ``v``, with the bit at position ``bit`` flipped. + runnableExamples: + var v = 0b0000_0011'u8 + v.flipBit(1'u8) + doAssert v == 0b0000_0001'u8 + + v = 0b0000_0011'u8 + v.flipBit(2'u8) + doAssert v == 0b0000_0111'u8 + v.flipMask(1.T shl bit) - macro setBits*(v: typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 1 + macro setBits*(v: var typed, bits: varargs[typed]): untyped = + ## Returns ``v``, with the bits at positions ``bits`` set to 1. + runnableExamples: + var v = 0b0000_0011'u8 + v.setBits(3, 5, 7) + doAssert v == 0b1010_1011'u8 + bits.expectKind(nnkBracket) result = newStmtList() for bit in bits: result.add newCall("setBit", v, bit) - macro clearBits*(v: typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 0 + macro clearBits*(v: var typed, bits: varargs[typed]): untyped = + ## Returns ``v``, with the bits at positions ``bits`` set to 0. + runnableExamples: + var v = 0b1111_1111'u8 + v.clearBits(1, 3, 5, 7) + doAssert v == 0b0101_0101'u8 + bits.expectKind(nnkBracket) result = newStmtList() for bit in bits: result.add newCall("clearBit", v, bit) - macro flipBits*(v: typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 0 + macro flipBits*(v: var typed, bits: varargs[typed]): untyped = + ## Returns ``v``, with the bits at positions ``bits`` set to 0. + runnableExamples: + var v = 0b0000_1111'u8 + v.flipBits(1, 3, 5, 7) + doAssert v == 0b1010_0101'u8 + bits.expectKind(nnkBracket) result = newStmtList() for bit in bits: result.add newCall("flipBit", v, bit) proc testBit*[T: SomeInteger](v: T, bit: BitsRange[T]): bool {.inline.} = - ## Returns true if the bit in ``v`` at positions ``bit`` is set to 1 + ## Returns true if the bit in ``v`` at positions ``bit`` is set to 1. + runnableExamples: + var v = 0b0000_1111'u8 + doAssert v.testBit(0) + doAssert not v.testBit(7) + let mask = 1.T shl bit return (v and mask) == mask @@ -272,6 +326,10 @@ elif useICC_builtins: proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Counts the set bits in integer. (also called `Hamming weight`:idx:.) + runnableExamples: + doAssert countSetBits(0b0000_0011'u8) == 2 + doAssert countSetBits(0b1010_1010'u8) == 4 + # TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT. # like GCC and MSVC when x is SomeSignedInt: @@ -298,12 +356,18 @@ proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} = else: result = countSetBitsNim(x.uint64) proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} = - ## Alias for for countSetBits (Hamming weight.) + ## Alias for for `countSetBits <#countSetBits,SomeInteger>`_. (Hamming weight.) result = countSetBits(x) proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Calculate the bit parity in integer. If number of 1-bit ## is odd parity is 1, otherwise 0. + runnableExamples: + doAssert parityBits(0b0000_0000'u8) == 0 + doAssert parityBits(0b0101_0001'u8) == 1 + doAssert parityBits(0b0110_1001'u8) == 0 + doAssert parityBits(0b0111_1111'u8) == 1 + # Can be used a base if creating ASM version. # https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd when x is SomeSignedInt: @@ -322,6 +386,13 @@ proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} = ## Returns the 1-based index of the least significant set bit of x. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, ## otherwise result is undefined. + runnableExamples: + doAssert firstSetBit(0b0000_0001'u8) == 1 + doAssert firstSetBit(0b0000_0010'u8) == 2 + doAssert firstSetBit(0b0000_0100'u8) == 3 + doAssert firstSetBit(0b0000_1000'u8) == 4 + doAssert firstSetBit(0b0000_1111'u8) == 1 + # GCC builtin 'builtin_ffs' already handle zero input. when x is SomeSignedInt: let x = x.toUnsigned @@ -359,6 +430,13 @@ proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} = ## Quickly find the log base 2 of an integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1, ## otherwise result is undefined. + runnableExamples: + doAssert fastLog2(0b0000_0001'u8) == 0 + doAssert fastLog2(0b0000_0010'u8) == 1 + doAssert fastLog2(0b0000_0100'u8) == 2 + doAssert fastLog2(0b0000_1000'u8) == 3 + doAssert fastLog2(0b0000_1111'u8) == 3 + when x is SomeSignedInt: let x = x.toUnsigned when noUndefined: @@ -392,6 +470,16 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Returns the number of leading zero bits in integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, ## otherwise result is undefined. + ## + ## See also: + ## * `countTrailingZeroBits proc <#countTrailingZeroBits,SomeInteger>`_ + runnableExamples: + doAssert countLeadingZeroBits(0b0000_0001'u8) == 7 + doAssert countLeadingZeroBits(0b0000_0010'u8) == 6 + doAssert countLeadingZeroBits(0b0000_0100'u8) == 5 + doAssert countLeadingZeroBits(0b0000_1000'u8) == 4 + doAssert countLeadingZeroBits(0b0000_1111'u8) == 4 + when x is SomeSignedInt: let x = x.toUnsigned when noUndefined: @@ -411,6 +499,16 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Returns the number of trailing zeros in integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, ## otherwise result is undefined. + ## + ## See also: + ## * `countLeadingZeroBits proc <#countLeadingZeroBits,SomeInteger>`_ + runnableExamples: + doAssert countTrailingZeroBits(0b0000_0001'u8) == 0 + doAssert countTrailingZeroBits(0b0000_0010'u8) == 1 + doAssert countTrailingZeroBits(0b0000_0100'u8) == 2 + doAssert countTrailingZeroBits(0b0000_1000'u8) == 3 + doAssert countTrailingZeroBits(0b0000_1111'u8) == 0 + when x is SomeSignedInt: let x = x.toUnsigned when noUndefined: @@ -429,6 +527,12 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = proc rotateLeftBits*(value: uint8; amount: range[0..8]): uint8 {.inline, noSideEffect.} = ## Left-rotate bits in a 8-bits value. + runnableExamples: + doAssert rotateLeftBits(0b0000_0001'u8, 1) == 0b0000_0010'u8 + doAssert rotateLeftBits(0b0000_0001'u8, 2) == 0b0000_0100'u8 + doAssert rotateLeftBits(0b0100_0001'u8, 1) == 0b1000_0010'u8 + doAssert rotateLeftBits(0b0100_0001'u8, 2) == 0b0000_0101'u8 + # using this form instead of the one below should handle any value # out of range as well as negative values. # result = (value shl amount) or (value shr (8 - amount)) @@ -439,18 +543,27 @@ proc rotateLeftBits*(value: uint8; proc rotateLeftBits*(value: uint16; amount: range[0..16]): uint16 {.inline, noSideEffect.} = ## Left-rotate bits in a 16-bits value. + ## + ## See also: + ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ let amount = amount and 15 result = (value shl amount) or (value shr ( (-amount) and 15)) proc rotateLeftBits*(value: uint32; amount: range[0..32]): uint32 {.inline, noSideEffect.} = ## Left-rotate bits in a 32-bits value. + ## + ## See also: + ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ let amount = amount and 31 result = (value shl amount) or (value shr ( (-amount) and 31)) proc rotateLeftBits*(value: uint64; amount: range[0..64]): uint64 {.inline, noSideEffect.} = ## Left-rotate bits in a 64-bits value. + ## + ## See also: + ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ let amount = amount and 63 result = (value shl amount) or (value shr ( (-amount) and 63)) @@ -458,24 +571,39 @@ proc rotateLeftBits*(value: uint64; proc rotateRightBits*(value: uint8; amount: range[0..8]): uint8 {.inline, noSideEffect.} = ## Right-rotate bits in a 8-bits value. + runnableExamples: + doAssert rotateRightBits(0b0000_0001'u8, 1) == 0b1000_0000'u8 + doAssert rotateRightBits(0b0000_0001'u8, 2) == 0b0100_0000'u8 + doAssert rotateRightBits(0b0100_0001'u8, 1) == 0b1010_0000'u8 + doAssert rotateRightBits(0b0100_0001'u8, 2) == 0b0101_0000'u8 + let amount = amount and 7 result = (value shr amount) or (value shl ( (-amount) and 7)) proc rotateRightBits*(value: uint16; amount: range[0..16]): uint16 {.inline, noSideEffect.} = ## Right-rotate bits in a 16-bits value. + ## + ## See also: + ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ let amount = amount and 15 result = (value shr amount) or (value shl ( (-amount) and 15)) proc rotateRightBits*(value: uint32; amount: range[0..32]): uint32 {.inline, noSideEffect.} = ## Right-rotate bits in a 32-bits value. + ## + ## See also: + ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ let amount = amount and 31 result = (value shr amount) or (value shl ( (-amount) and 31)) proc rotateRightBits*(value: uint64; amount: range[0..64]): uint64 {.inline, noSideEffect.} = ## Right-rotate bits in a 64-bits value. + ## + ## See also: + ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ let amount = amount and 63 result = (value shr amount) or (value shl ( (-amount) and 63)) From 255698deee403ae80b26baa567043a07dc3c7404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 13 Apr 2020 14:22:33 +0200 Subject: [PATCH 0318/4254] Fix semfold handling of {.str/int/bool-define.} (#13964) --- compiler/semfold.nim | 6 ++++++ tests/misc/tdefine.nim | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index f0971bf09..5e2c2bccc 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -549,9 +549,13 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = localError(g.config, s.info, "{.intdefine.} const was set to an invalid integer: '" & g.config.symbols[s.name.s] & "'") + else: + result = copyTree(s.ast) of mStrDefine: if isDefined(g.config, s.name.s): result = newStrNodeT(g.config.symbols[s.name.s], n, g) + else: + result = copyTree(s.ast) of mBoolDefine: if isDefined(g.config, s.name.s): try: @@ -560,6 +564,8 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = localError(g.config, s.info, "{.booldefine.} const was set to an invalid bool: '" & g.config.symbols[s.name.s] & "'") + else: + result = copyTree(s.ast) else: result = copyTree(s.ast) of skProc, skFunc, skMethod: diff --git a/tests/misc/tdefine.nim b/tests/misc/tdefine.nim index 1378b8901..f1c6e7a96 100644 --- a/tests/misc/tdefine.nim +++ b/tests/misc/tdefine.nim @@ -16,3 +16,15 @@ doAssert booldef doAssert not booldef2 doAssert intdef == 2 doAssert strdef == "foobar" + +# Intentionally not defined from command line +const booldef3 {.booldefine.} = true +const intdef2 {.intdefine.} = 1 +const strdef2 {.strdefine.} = "abc" +type T = object + when booldef3: + field1: int + when intdef2 == 1: + field2: int + when strdef2 == "abc": + field3: int \ No newline at end of file From 0a84219b3ec3b2deccc141bed4aee0252bc12ca7 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 13 Apr 2020 10:07:52 -0300 Subject: [PATCH 0319/4254] Add jsdomparser (#13920) * Add jsdomparser * Add jsdomparser * Add jsdomparser * https://github.com/nim-lang/Nim/pull/13920#issuecomment-610727142 * https://github.com/nim-lang/Nim/pull/13920#issuecomment-610727142 * https://github.com/nim-lang/Nim/pull/13920#issuecomment-610727142 * https://github.com/nim-lang/Nim/pull/13920#discussion_r405932909 * https://github.com/nim-lang/Nim/pull/13920#discussion_r406502592 --- changelog.md | 2 ++ lib/js/dom.nim | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index b960f5213..62db91622 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,8 @@ ## Standard library additions and changes +- Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) + to the `dom` module for the JavaScript target. ## Language changes diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 92cc038c9..280e47d82 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -9,7 +9,7 @@ ## Declaration of the Document Object Model for the `JavaScript backend ## `_. - +include "system/inclrtl" when not defined(js) and not defined(Nimdoc): {.error: "This module only works on the JavaScript platform".} @@ -985,6 +985,16 @@ type once*: bool passive*: bool +since (1, 3): + type DomParser* = ref object ## \ + ## DOM Parser object (defined on browser only, may not be on NodeJS). + ## * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser + ## + ## .. code-block:: nim + ## let prsr = newDomParser() + ## discard prsr.parseFromString("Hello World".cstring, "text/html".cstring) + + proc id*(n: Node): cstring {.importcpp: "#.id", nodecl.} proc `id=`*(n: Node; x: cstring) {.importcpp: "#.id = #", nodecl.} proc class*(n: Node): cstring {.importcpp: "#.className", nodecl.} @@ -1297,3 +1307,10 @@ proc offsetHeight*(e: Node): int {.importcpp: "#.offsetHeight", nodecl.} proc offsetWidth*(e: Node): int {.importcpp: "#.offsetWidth", nodecl.} proc offsetTop*(e: Node): int {.importcpp: "#.offsetTop", nodecl.} proc offsetLeft*(e: Node): int {.importcpp: "#.offsetLeft", nodecl.} + +since (1, 3): + func newDomParser*(): DOMParser {.importcpp: "(new DOMParser()​​)".} + ## DOM Parser constructor. + + func parseFromString*(this: DOMParser; str: cstring; mimeType: cstring): Document {.importcpp.} + ## Parse from string to `Document`. From c2699648604cc57cd55ecd7d88ccd55ed38099fb Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 13 Apr 2020 10:15:45 -0300 Subject: [PATCH 0320/4254] Add Data URI Base64, implements RFC-2397 (#13759) * Add Data URI Base64, implements RFC-2397 * Add Data URI Base64, implements RFC-2397 * Add Data URI Base64, implements RFC-2397 * https://github.com/nim-lang/Nim/pull/13759#issuecomment-611498420 * https://github.com/nim-lang/Nim/pull/13759#issuecomment-611498420 * ReSync changelog * https://github.com/nim-lang/Nim/pull/13759#issuecomment-611498420 Co-authored-by: Dominik Picheta --- changelog.md | 1 + lib/pure/uri.nim | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 62db91622..1fc6d19c2 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ ## Standard library additions and changes +- `uri` adds Data URI Base64, implements RFC-2397. - Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) to the `dom` module for the JavaScript target. diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 9112671c7..27fbf2db2 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -36,8 +36,17 @@ ## assert res.port == "4343" ## else: ## echo "Wrong format" +## +## Data URI Base64 +## --------------- +## +## .. code-block::nim +## doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" +## doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" -import strutils, parseutils +include "system/inclrtl" + +import strutils, parseutils, base64 type Url* = distinct string @@ -466,6 +475,18 @@ proc `$`*(u: Uri): string = result.add("#") result.add(u.anchor) +proc getDataUri*(data, mime: string, encoding = "utf-8"): string {.since: (1, 3).} = + ## Convenience proc for `base64.encode` returns a standard Base64 Data URI (RFC-2397) + ## + ## **See also:** + ## * `mimetypes `_ for `mime` argument + ## * https://tools.ietf.org/html/rfc2397 + ## * https://en.wikipedia.org/wiki/Data_URI_scheme + runnableExamples: static: doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" + assert encoding.len > 0 and mime.len > 0 # Must *not* be URL-Safe, see RFC-2397 + result = "data:" & mime & ";charset=" & encoding & ";base64," & base64.encode(data) + + when isMainModule: block: const test1 = "abc\L+def xyz" @@ -735,4 +756,17 @@ when isMainModule: var foo1 = parseUri("http://example.com/foo?do=do&bar") doAssert foo == foo1 + block dataUriBase64: + doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64," + doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA==" + doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+" + doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" + doAssert getDataUri("leasure.", "text/plain") == "data:text/plain;charset=utf-8;base64,bGVhc3VyZS4=" + doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r" + doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") == + "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==") + doAssert(getDataUri("""The present is theirs + The future, for which I really worked, is mine.""", "text/plain") == + "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu") + echo("All good!") From 10eabec6d442cb32c2c74f7c56cc9fff3be40104 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 14 Apr 2020 06:00:02 -0700 Subject: [PATCH 0321/4254] fix #12864 static params were mutating arg types during sigmatch; fix #12713 ; refs #13529 (#13976) * fix #12864 static params were mutating arg types during sigmatch * fix test * fix StaticParam * also fixes #12713; added test case --- compiler/sigmatch.nim | 1 + lib/pure/typetraits.nim | 9 +++--- tests/metatype/tstaticparams.nim | 24 ++++++++++++++++ tests/metatype/ttypetraits.nim | 1 + tests/statictypes/t9255.nim | 2 +- tests/statictypes/tstatictypes.nim | 46 ++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 6 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 04ceb47b8..d819afb42 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2004,6 +2004,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, let typ = newTypeS(tyStatic, c) typ.sons = @[evaluated.typ] typ.n = evaluated + arg = copyTree(arg) # fix #12864 arg.typ = typ a = typ else: diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 8f83a9dda..84d57a45e 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -93,7 +93,7 @@ since (1, 1): # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` type(default(T)[i]) - type StaticParam*[value] = object + type StaticParam*[value: static type] = object ## used to wrap a static value in `genericParams` # NOTE: See https://github.com/nim-lang/Nim/issues/13758 - `import std/macros` does not work on OpenBSD @@ -118,13 +118,12 @@ macro genericParamsImpl(T: typedesc): untyped = let ai = impl[i] var ret: NimNode case ai.typeKind - of ntyStatic: - since (1, 1): - ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai]) of ntyTypeDesc: ret = ai + of ntyStatic: doAssert false else: - assert false, $(ai.typeKind, ai.kind) + since (1, 1): + ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai]) result.add ret break else: diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim index 09d505f94..de80d46ae 100644 --- a/tests/metatype/tstaticparams.nim +++ b/tests/metatype/tstaticparams.nim @@ -171,3 +171,27 @@ echo inSize([ [1, 2, 3], [4, 5, 6] ]) + +block: # #12864 + template fun() = + type Object = object + proc fun(f: Object): int = 1 + proc fun(f: static[int]): int = 2 + doAssert fun(Object()) == 1 + + var a: Object + doAssert fun(a) == 1 + + proc fun2(f: Object): int = 1 + proc fun2(f: static[Object]): int = 2 + doAssert fun2(Object()) == 2 + doAssert fun2(a) == 1 + const a2 = Object() + doAssert fun2(a2) == 2 + + fun() + static: fun() + +when true: #12864 original snippet + import times + discard times.format(initDateTime(30, mMar, 2017, 0, 0, 0, 0, utc()), TimeFormat()) diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index db8c8e5de..eb2384afb 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -145,6 +145,7 @@ block genericParams: doAssert genericParams(Bar3).get(0) is StaticParam doAssert genericParams(Bar3).get(0).value == 3 doAssert genericParams(Bar[3, float]).get(0).value == 3 + static: doAssert genericParams(Bar[3, float]).get(0).value == 3 type VectorElementType = SomeNumber | bool diff --git a/tests/statictypes/t9255.nim b/tests/statictypes/t9255.nim index 86bc8c7f1..99ca2a23c 100644 --- a/tests/statictypes/t9255.nim +++ b/tests/statictypes/t9255.nim @@ -1,6 +1,6 @@ discard """ errormsg: ''' -type mismatch: got +type mismatch: got ''' line: 13 """ diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index afd15b67d..1aab6e124 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -170,3 +170,49 @@ var s: StringValue16 echo s + +block: #13529 + block: + type Foo[T: static type] = object + var foo: Foo["test"] + doAssert $foo == "()" + doAssert foo.T is string + static: doAssert foo.T == "test" + doAssert not compiles( + block: + type Foo2[T: static type] = object + x: T) + + block: + type Foo[T: static[float]] = object + var foo: Foo[1.2] + doAssert $foo == "()" + doAssert foo.T == 1.2 + + block: # routines also work + proc fun(a: static) = (const a2 = a) + fun(1) + fun(1.2) + block: # routines also work + proc fun(a: static type) = (const a2 = a) + fun(1) + fun(1.2) + + block: # this also works + proc fun[T](a: static[T]) = (const a2 = a) + fun(1) + fun(1.2) + +block: # #12713 + block: + type Cell = object + c: int + proc test(c: static string) = discard #Remove this and it compiles + proc test(c: Cell) = discard + test Cell(c: 0) + block: + type Cell = object + c: int + proc test(c: static string) = discard #Remove this and it compiles + proc test(c: Cell) = discard + test Cell() From 2c93d1684e44dcec160083eafd1144e4ddeb0ad8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 14 Apr 2020 06:00:35 -0700 Subject: [PATCH 0322/4254] enable important_pkg on OSX (#13954) * enable important_pkg on OSX * disable some important_packages on OSX * fixup * enable nigui by installing dependency --- azure-pipelines.yml | 4 ++++ testament/important_packages.nim | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d02ac1091..57b494bac 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -34,6 +34,10 @@ jobs: vmImage: 'ubuntu-16.04' CPU: amd64 NIM_TEST_PACKAGES: true + OSX_amd64_pkg: + vmImage: 'macOS-10.15' + CPU: amd64 + NIM_TEST_PACKAGES: true pool: vmImage: $(vmImage) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 21a40257f..a78f79b7d 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -1,3 +1,4 @@ +import os template pkg(name: string; hasDeps = false; cmd = "nimble test"; url = ""): untyped = packages.add((name, cmd, hasDeps, url)) @@ -17,7 +18,8 @@ pkg "c2nim", false, "nim c testsuite/tester.nim" pkg "cascade" pkg "chroma" pkg "chronicles", true, "nim c -o:chr -r chronicles.nim" -pkg "chronos", true +when not defined(osx): # testdatagram.nim(560, 54): Check failed + pkg "chronos", true pkg "cligen", false, "nim c -o:cligenn -r cligen.nim" pkg "coco", true pkg "combparser" @@ -46,7 +48,13 @@ pkg "nake", false, "nim c nakefile.nim" pkg "neo", true, "nim c -d:blas=openblas tests/all.nim" # pkg "nico", true pkg "nicy", false, "nim c src/nicy.nim" + +when defined(osx): + # do this more generally by installing non-nim dependencies automatically + # as specified in nimble file + doAssert execShellCmd("brew install gtk+3") == 0 pkg "nigui", false, "nim c -o:niguii -r src/nigui.nim" + pkg "nimcrypto", false, "nim c -r tests/testall.nim" pkg "NimData", true, "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", true, "nim c src/nimes.nim" From 4764220cfbee11a556dde0b9f53b2f90607297eb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 15 Apr 2020 04:07:18 -0700 Subject: [PATCH 0323/4254] Fix https://github.com/inim-repl/INim/issues/66 (#13984) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index a78f79b7d..7eb94a5c1 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -37,7 +37,7 @@ pkg "glob" pkg "gnuplot" pkg "hts", false, "nim c -o:htss src/hts.nim" pkg "illwill", false, "nimble examples" -pkg "inim" +pkg "inim", true pkg "itertools", false, "nim doc src/itertools.nim" pkg "iterutils" pkg "jstin" From 04b6e9cf3e6e1113cb5989a82878e525a7f0891f Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 15 Apr 2020 17:33:16 +0200 Subject: [PATCH 0324/4254] add timezones package to important_packages (#13987) --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 7eb94a5c1..257272aa1 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -92,6 +92,7 @@ pkg "strunicode", true, "nim c -r src/strunicode.nim" pkg "telebot", true, "nim c -o:tbot -r src/telebot.nim" pkg "tempdir" pkg "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" +pkg "timezones" pkg "tiny_sqlite" pkg "unicodedb" pkg "unicodeplus", true From 3a2697dd731cb8fcfd0d279bb856090eca5028ee Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 15 Apr 2020 20:03:25 +0200 Subject: [PATCH 0325/4254] drnim: tiny progress (#13882) * drnim: tiny progress * refactoring complete * drnim: prove .ensures annotations * Moved code around to avoid code duplication * drnim: first implementation of the 'old' property * drnim: be precise about the assignment statement * first implementation of --assumeUnique * progress on forall/exists handling --- compiler/ast.nim | 2 +- compiler/cmdlinehelper.nim | 16 +- compiler/guards.nim | 17 +- compiler/modulegraphs.nim | 4 +- compiler/nim.nim | 14 - compiler/pragmas.nim | 2 +- compiler/semmagic.nim | 30 +- compiler/semparallel.nim | 2 +- compiler/sempass2.nim | 83 +--- compiler/spawn.nim | 25 +- compiler/trees.nim | 21 + doc/contributing.rst | 8 +- doc/drnim.rst | 3 +- drnim/drnim.nim | 720 +++++++++++++++++++++++----- drnim/tests/tbasic_array_index.nim | 8 + drnim/tests/tensures.nim | 51 +- drnim/tests/tsetlen_invalidates.nim | 8 +- 17 files changed, 755 insertions(+), 259 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d7d0ef224..110ee79e3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -218,7 +218,7 @@ type nkEnumFieldDef, # `ident = expr` in an enumeration nkArgList, # argument list nkPattern, # a special pattern; used for matching - nkHiddenTryStmt, # token used for interpretation + nkHiddenTryStmt, # a hidden try statement nkClosure, # (prc, env)-pair (internally used for code gen) nkGotoState, # used for the state machine (for iterators) nkState, # give a label to a code section (for iterators) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index a03899071..d5c743fc6 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -11,10 +11,24 @@ import options, idents, nimconf, extccomp, commands, msgs, - lineinfos, modulegraphs, condsyms, os, pathutils + lineinfos, modulegraphs, condsyms, os, pathutils, parseopt from strutils import normalize +proc prependCurDir*(f: AbsoluteFile): AbsoluteFile = + when defined(unix): + if os.isAbsolute(f.string): result = f + else: result = AbsoluteFile("./" & f.string) + else: + result = f + +proc addCmdPrefix*(result: var string, kind: CmdLineKind) = + # consider moving this to std/parseopt + case kind + of cmdLongOption: result.add "--" + of cmdShortOption: result.add "-" + of cmdArgument, cmdEnd: discard + type NimProg* = ref object suggestMode*: bool diff --git a/compiler/guards.nim b/compiler/guards.nim index 88441eb96..e4f87bae4 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -84,8 +84,8 @@ proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true) type Operators* = object - opNot, opContains, opLe, opLt, opAnd, opOr, opIsNil, opEq: PSym - opAdd, opSub, opMul, opDiv, opLen: PSym + opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym + opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym proc initOperators*(g: ModuleGraph): Operators = result.opLe = createMagic(g, "<=", mLeI) @@ -156,12 +156,12 @@ proc neg(n: PNode; o: Operators): PNode = result[0] = newSymNode(o.opNot) result[1] = n -proc buildCall(op: PSym; a: PNode): PNode = +proc buildCall*(op: PSym; a: PNode): PNode = result = newNodeI(nkCall, a.info, 2) result[0] = newSymNode(op) result[1] = a -proc buildCall(op: PSym; a, b: PNode): PNode = +proc buildCall*(op: PSym; a, b: PNode): PNode = result = newNodeI(nkInfix, a.info, 3) result[0] = newSymNode(op) result[1] = a @@ -464,7 +464,7 @@ proc hasSubTree(n, x: PNode): bool = for i in 0..n.safeLen-1: if hasSubTree(n[i], x): return true -proc invalidateFacts*(m: var TModel, n: PNode) = +proc invalidateFacts*(s: var seq[PNode], n: PNode) = # We are able to guard local vars (as opposed to 'let' variables)! # 'while p != nil: f(p); p = p.next' # This is actually quite easy to do: @@ -482,8 +482,11 @@ proc invalidateFacts*(m: var TModel, n: PNode) = # The same mechanism could be used for more complex data stored on the heap; # procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we # could CSE these expressions then and help C's optimizer. - for i in 0..high(m.s): - if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil + for i in 0..high(s): + if s[i] != nil and s[i].hasSubTree(n): s[i] = nil + +proc invalidateFacts*(m: var TModel, n: PNode) = + invalidateFacts(m.s, n) proc valuesUnequal(a, b: PNode): bool = if a.isValue and b.isValue: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index db4c28af7..da2a222a4 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -72,9 +72,7 @@ type onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} globalDestructors*: seq[PNode] - proofEngine*: proc (graph: ModuleGraph; assumptions: seq[PNode]; toProve: PNode): (bool, string) {.nimcall.} - requirementsCheck*: proc (graph: ModuleGraph; assumptions: seq[PNode]; - call, requirement: PNode): (bool, string) {.nimcall.} + strongSemCheck*: proc (graph: ModuleGraph; owner: PSym; body: PNode) {.nimcall.} compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {.nimcall.} TPassContext* = object of RootObj # the pass's context diff --git a/compiler/nim.nim b/compiler/nim.nim index 4bcb1b510..997888cb8 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -33,20 +33,6 @@ when defined(profiler) or defined(memProfiler): {.hint: "Profiling support is turned on!".} import nimprof -proc prependCurDir(f: AbsoluteFile): AbsoluteFile = - when defined(unix): - if os.isAbsolute(f.string): result = f - else: result = AbsoluteFile("./" & f.string) - else: - result = f - -proc addCmdPrefix*(result: var string, kind: CmdLineKind) = - # consider moving this to std/parseopt - case kind - of cmdLongOption: result.add "--" - of cmdShortOption: result.add "-" - of cmdArgument, cmdEnd: discard - proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) var argsCount = 0 diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 4504d1cc5..1a9f5a991 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -53,7 +53,7 @@ const wDeprecated, wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto, - wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume} + wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert} lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader, wThread, wAsmNoStackFrame, diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 783846650..53a19fae6 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -429,15 +429,29 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym result.typ.addParam newParam proc semQuantifier(c: PContext; n: PNode): PNode = - checkMinSonsLen(n, 2, c.config) + checkSonsLen(n, 2, c.config) openScope(c) - for i in 0..n.len-2: - let v = newSymS(skForVar, n[i], c) - styleCheckDef(c.config, v) - onDef(n.info, v) - n[i] = newSymNode(v) - addDecl(c, v) - n[^1] = forceBool(c, semExprWithType(c, n[^1])) + result = newNodeIT(n.kind, n.info, n.typ) + result.add n[0] + let args = n[1] + assert args.kind == nkArgList + for i in 0..args.len-2: + let it = args[i] + var valid = false + if it.kind == nkInfix: + let op = considerQuotedIdent(c, it[0]) + if op.id == ord(wIn): + let v = newSymS(skForVar, it[1], c) + styleCheckDef(c.config, v) + onDef(it[1].info, v) + let domain = semExprWithType(c, it[2], {efWantIterator}) + v.typ = domain.typ + valid = true + addDecl(c, v) + result.add newTree(nkInfix, it[0], newSymNode(v), domain) + if not valid: + localError(c.config, n.info, " 'in' expected") + result.add forceBool(c, semExprWithType(c, args[^1])) closeScope(c) proc semOld(c: PContext; n: PNode): PNode = diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 5614f9ee3..e27e85e04 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -25,7 +25,7 @@ import ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs, renderer, types, modulegraphs, options, spawn, lineinfos -from trees import getMagic +from trees import getMagic, isTrue, getRoot from strutils import `%` discard """ diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index efc19952c..55888a3eb 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -433,7 +433,8 @@ proc isForwardedProc(n: PNode): bool = proc trackPragmaStmt(tracked: PEffects, n: PNode) = for i in 0.. " & $b) + case proveLe(c.guards, a, b) + of impUnknown: + #for g in c.guards.s: + # if g != nil: echo "I Know ", g + message(c.config, a.info, warnStaticIndexCheck, + "cannot prove: " & $a & " <= " & $b) + of impYes: + discard + of impNo: + message(c.config, a.info, warnStaticIndexCheck, + "can prove: " & $a & " > " & $b) proc checkBounds(c: PEffects; arr, idx: PNode) = checkLe(c, lowBound(c.config, arr), idx) @@ -831,7 +793,6 @@ proc track(tracked: PEffects, n: PNode) = mergeEffects(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) gcsafeAndSideeffectCheck() - requiresCheck(tracked, n, op) if a.kind != nkSym or a.sym.magic != mNBindSym: for i in 1.. (a[i] > 3))' -- forall/exists need syntactic sugar as the manual - We need teach DrNim what 'inc', 'dec' and 'swap' mean, for example 'x in n..m; inc x' implies 'x in n+1..m+1' -- We need an ``old`` annotation: - -proc f(x: var int; y: var int) {.ensures: x == old(x)+1 and y == old(y)+1 .} = - inc x - inc y - -var x = 3 -var y: range[N..M] -f(x, y) -{.assume: y in N+1 .. M+1.} -# --> y in N+1..M+1 - -proc myinc(x: var int) {.ensures: x-1 == old(x).} = - inc x - -facts(x) # x < 3 -myinc x -facts(x+1) - -We handle state transitions in this way: - - for every f in facts: - replace 'x' by 'old(x)' - facts.add ensuresClause - - # then we know: old(x) < 3; x-1 == old(x) - # we can conclude: x-1 < 3 but leave this task to Z3 - ]# import std / [ - parseopt, strutils, os, tables, times + parseopt, strutils, os, tables, times, intsets, hashes ] import ".." / compiler / [ - ast, types, renderer, + ast, astalgo, types, renderer, commands, options, msgs, - platform, + platform, trees, wordrecg, guards, idents, lineinfos, cmdlinehelper, modulegraphs, condsyms, pathutils, passes, passaux, sem, modules ] @@ -91,42 +59,174 @@ proc helpOnError(conf: ConfigRef) = type CannotMapToZ3Error = object of ValueError Z3Exception = object of ValueError + VersionScope = distinct int + DrnimContext = ref object + z3: Z3_context + graph: ModuleGraph + facts: seq[(PNode, VersionScope)] + varVersions: seq[int] # this maps variable IDs to their current version. + o: Operators + hasUnstructedCf: int + currOptions: TOptions + owner: PSym + mangler: seq[PSym] DrCon = object - z3: Z3_context graph: ModuleGraph mapping: Table[string, Z3_ast] canonParameterNames: bool + assumeUniqueness: bool + up: DrnimContext -proc stableName(result: var string; n: PNode) = +var + assumeUniqueness: bool + +proc echoFacts(c: DrnimContext) = + echo "FACTS:" + for i in 0 ..< c.facts.len: + let f = c.facts[i] + echo f[0], " version ", int(f[1]) + +proc isLoc(m: PNode; assumeUniqueness: bool): bool = + # We can reason about "locations" and map them to Z3 constants. + # For code that is full of "ref" (e.g. the Nim compiler itself) that + # is too limiting + proc isLet(n: PNode): bool = + if n.kind == nkSym: + if n.sym.kind in {skLet, skTemp, skForVar}: + result = true + elif n.sym.kind == skParam and skipTypes(n.sym.typ, + abstractInst).kind != tyVar: + result = true + + var n = m + while true: + case n.kind + of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv, nkHiddenDeref: + n = n[0] + of nkDerefExpr: + n = n[0] + if not assumeUniqueness: return false + of nkBracketExpr: + if isConstExpr(n[1]) or isLet(n[1]) or isConstExpr(n[1].skipConv): + n = n[0] + else: return + of nkHiddenStdConv, nkHiddenSubConv, nkConv: + n = n[1] + else: + break + if n.kind == nkSym: + case n.sym.kind + of skLet, skTemp, skForVar, skParam: + result = true + #of skParam: + # result = skipTypes(n.sym.typ, abstractInst).kind != tyVar + of skResult, skVar: + result = {sfAddrTaken} * n.sym.flags == {} + else: + discard + +proc varVersion(c: DrnimContext; s: PSym; begin: VersionScope): int = + result = 0 + for i in countdown(int(begin)-1, 0): + if c.varVersions[i] == s.id: inc result + +proc disamb(c: DrnimContext; s: PSym): int = + # we group by 's.name.s' to compute the stable name ID. + result = 0 + for i in 0 ..< c.mangler.len: + if s == c.mangler[i]: return result + if s.name.s == c.mangler[i].name.s: inc result + c.mangler.add s + +proc stableName(result: var string; c: DrnimContext; n: PNode; version: VersionScope; + isOld: bool) = # we can map full Nim expressions like 'f(a, b, c)' to Z3 variables. - # We must be carefult to select a unique, stable name for these expressions + # We must be careful to select a unique, stable name for these expressions # based on structural equality. 'stableName' helps us with this problem. + # In the future we will also use this string for the caching mechanism. case n.kind of nkEmpty, nkNilLit, nkType: discard of nkIdent: result.add n.ident.s of nkSym: result.add n.sym.name.s - result.add '_' - result.addInt n.sym.id + if n.sym.magic == mNone: + let d = disamb(c, n.sym) + if d != 0: + result.add "`scope=" + result.addInt d + let v = c.varVersion(n.sym, version) - ord(isOld) + assert v >= 0 + if v > 0: + result.add '`' + result.addInt v + else: + result.add "`magic=" + result.addInt ord(n.sym.magic) + of nkCharLit..nkUInt64Lit: result.addInt n.intVal of nkFloatLit..nkFloat64Lit: result.addFloat n.floatVal of nkStrLit..nkTripleStrLit: result.add strutils.escape n.strVal + of nkDotExpr: + stableName(result, c, n[0], version, isOld) + result.add '.' + stableName(result, c, n[1], version, isOld) + of nkBracketExpr: + stableName(result, c, n[0], version, isOld) + result.add '[' + stableName(result, c, n[1], version, isOld) + result.add ']' + of nkCallKinds: + if n.len == 2: + stableName(result, c, n[1], version, isOld) + result.add '.' + case getMagic(n) + of mLengthArray, mLengthOpenArray, mLengthSeq, mLengthStr: + result.add "len" + of mHigh: + result.add "high" + of mLow: + result.add "low" + else: + stableName(result, c, n[0], version, isOld) + elif n.kind == nkInfix and n.len == 3: + result.add '(' + stableName(result, c, n[1], version, isOld) + result.add ' ' + stableName(result, c, n[0], version, isOld) + result.add ' ' + stableName(result, c, n[2], version, isOld) + result.add ')' + else: + stableName(result, c, n[0], version, isOld) + result.add '(' + for i in 1.. 1: result.add ", " + stableName(result, c, n[i], version, isOld) + result.add ')' else: result.add $n.kind result.add '(' for i in 0.. 0: result.add ", " - stableName(result, n[i]) + stableName(result, c, n[i], version, isOld) result.add ')' -proc stableName(n: PNode): string = stableName(result, n) +proc stableName(c: DrnimContext; n: PNode; version: VersionScope; + isOld = false): string = + stableName(result, c, n, version, isOld) + +template allScopes(c): untyped = VersionScope(c.varVersions.len) +template currentScope(c): untyped = VersionScope(c.varVersions.len) proc notImplemented(msg: string) {.noinline.} = + when defined(debug): + writeStackTrace() + echo msg raise newException(CannotMapToZ3Error, "; cannot map to Z3: " & msg) proc translateEnsures(e, x: PNode): PNode = @@ -138,7 +238,7 @@ proc translateEnsures(e, x: PNode): PNode = result[i] = translateEnsures(e[i], x) proc typeToZ3(c: DrCon; t: PType): Z3_sort = - template ctx: untyped = c.z3 + template ctx: untyped = c.up.z3 case t.skipTypes(abstractInst+{tyVar}).kind of tyEnum, tyInt..tyInt64: result = Z3_mk_int_sort(ctx) @@ -156,42 +256,64 @@ template binary(op, a, b): untyped = var arr = [a, b] op(ctx, cuint(2), addr(arr[0])) -proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast +proc nodeToZ3(c: var DrCon; n: PNode; scope: VersionScope; vars: var seq[PNode]): Z3_ast + +proc nodeToDomain(c: var DrCon; n, q: PNode; opAnd: PSym): PNode = + assert n.kind == nkInfix + let opLe = createMagic(c.graph, "<=", mLeI) + case $n[0] + of "..": + result = buildCall(opAnd, buildCall(opLe, n[1], q), buildCall(opLe, q, n[2])) + of "..<": + let opLt = createMagic(c.graph, "<", mLtI) + result = buildCall(opAnd, buildCall(opLe, n[1], q), buildCall(opLt, q, n[2])) + else: + notImplemented($n) template quantorToZ3(fn) {.dirty.} = - template ctx: untyped = c.z3 + template ctx: untyped = c.up.z3 - var bound = newSeq[Z3_app](n.len-1) - for i in 0..n.len-2: - doAssert n[i].kind == nkSym - let v = n[i].sym + var bound = newSeq[Z3_app](n.len-2) + let opAnd = createMagic(c.graph, "and", mAnd) + var known: PNode + for i in 1..n.len-2: + let it = n[i] + doAssert it.kind == nkInfix + let v = it[1].sym let name = Z3_mk_string_symbol(ctx, v.name.s) let vz3 = Z3_mk_const(ctx, name, typeToZ3(c, v.typ)) - c.mapping[stableName(n[i])] = vz3 - bound[i] = Z3_to_app(ctx, vz3) + c.mapping[stableName(c.up, it[1], allScopes(c.up))] = vz3 + bound[i-1] = Z3_to_app(ctx, vz3) + let domain = nodeToDomain(c, it[2], it[1], opAnd) + if known == nil: + known = domain + else: + known = buildCall(opAnd, known, domain) var dummy: seq[PNode] - let x = nodeToZ3(c, n[^1], dummy) + assert known != nil + let x = nodeToZ3(c, buildCall(createMagic(c.graph, "->", mImplies), + known, n[^1]), scope, dummy) result = fn(ctx, 0, bound.len.cuint, addr(bound[0]), 0, nil, x) -proc forallToZ3(c: var DrCon; n: PNode): Z3_ast = quantorToZ3(Z3_mk_forall_const) -proc existsToZ3(c: var DrCon; n: PNode): Z3_ast = quantorToZ3(Z3_mk_exists_const) +proc forallToZ3(c: var DrCon; n: PNode; scope: VersionScope): Z3_ast = quantorToZ3(Z3_mk_forall_const) +proc existsToZ3(c: var DrCon; n: PNode; scope: VersionScope): Z3_ast = quantorToZ3(Z3_mk_exists_const) -proc paramName(n: PNode): string = +proc paramName(c: DrnimContext; n: PNode): string = case n.sym.kind of skParam: result = "arg" & $n.sym.position of skResult: result = "result" - else: result = stableName(n) + else: result = stableName(c, n, allScopes(c)) -proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = - template ctx: untyped = c.z3 - template rec(n): untyped = nodeToZ3(c, n, vars) +proc nodeToZ3(c: var DrCon; n: PNode; scope: VersionScope; vars: var seq[PNode]): Z3_ast = + template ctx: untyped = c.up.z3 + template rec(n): untyped = nodeToZ3(c, n, scope, vars) case n.kind of nkSym: - let key = if c.canonParameterNames: paramName(n) else: stableName(n) + let key = if c.canonParameterNames: paramName(c.up, n) else: stableName(c.up, n, scope) result = c.mapping.getOrDefault(key) if pointer(result) == nil: - let name = Z3_mk_string_symbol(ctx, n.sym.name.s) + let name = Z3_mk_string_symbol(ctx, key) result = Z3_mk_const(ctx, name, typeToZ3(c, n.sym.typ)) c.mapping[key] = result vars.add n @@ -222,17 +344,23 @@ proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = result = Z3_mk_lt(ctx, rec n[1], rec n[2]) of mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq: # len(x) needs the same logic as 'x' itself - if n[1].kind == nkSym: - let key = stableName(n) - let sym = n[1].sym + if isLoc(n[1], c.assumeUniqueness): + let key = stableName(c.up, n, scope) result = c.mapping.getOrDefault(key) if pointer(result) == nil: - let name = Z3_mk_string_symbol(ctx, sym.name.s & ".len") + let name = Z3_mk_string_symbol(ctx, key) result = Z3_mk_const(ctx, name, Z3_mk_int_sort(ctx)) c.mapping[key] = result vars.add n else: notImplemented(renderTree(n)) + of mHigh: + let addOpr = createMagic(c.graph, "+", mAddI) + let lenOpr = createMagic(c.graph, "len", mLengthOpenArray) + let asLenExpr = addOpr.buildCall(lenOpr.buildCall(n[1]), nkIntLit.newIntNode(-1)) + result = rec asLenExpr + of mLow: + result = rec lowBound(c.graph.config, n[1]) of mAddI, mSucc: result = binary(Z3_mk_add, rec n[1], rec n[2]) of mSubI, mPred: @@ -256,9 +384,12 @@ proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = of mLtU: result = Z3_mk_bvult(ctx, rec n[1], rec n[2]) of mAnd: - result = binary(Z3_mk_and, rec n[1], rec n[2]) + # 'a and b' <=> ite(a, b, false) + result = Z3_mk_ite(ctx, rec n[1], rec n[2], Z3_mk_false(ctx)) + #result = binary(Z3_mk_and, rec n[1], rec n[2]) of mOr: - result = binary(Z3_mk_or, rec n[1], rec n[2]) + result = Z3_mk_ite(ctx, rec n[1], Z3_mk_true(ctx), rec n[2]) + #result = binary(Z3_mk_or, rec n[1], rec n[2]) of mXor: result = Z3_mk_xor(ctx, rec n[1], rec n[2]) of mNot: @@ -268,9 +399,9 @@ proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = of mIff: result = Z3_mk_iff(ctx, rec n[1], rec n[2]) of mForall: - result = forallToZ3(c, n) + result = forallToZ3(c, n, scope) of mExists: - result = existsToZ3(c, n) + result = existsToZ3(c, n, scope) of mLeF64: result = Z3_mk_fpa_leq(ctx, rec n[1], rec n[2]) of mLtF64: @@ -299,11 +430,12 @@ proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = of mOrd, mChr: result = rec n[1] of mOld: - let key = (if c.canonParameterNames: paramName(n[1]) else: stableName(n[1])) & ".old" + let key = if c.canonParameterNames: (paramName(c.up, n[1]) & ".old") + else: stableName(c.up, n[1], scope, isOld = true) result = c.mapping.getOrDefault(key) if pointer(result) == nil: - let name = Z3_mk_string_symbol(ctx, $n) - result = Z3_mk_const(ctx, name, typeToZ3(c, n.typ)) + let name = Z3_mk_string_symbol(ctx, key) + result = Z3_mk_const(ctx, name, typeToZ3(c, n[1].typ)) c.mapping[key] = result # XXX change the logic in `addRangeInfo` for this #vars.add n @@ -318,10 +450,10 @@ proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = ensuresEffects < op.n[0].len: let ensures = op.n[0][ensuresEffects] if ensures != nil and ensures.kind != nkEmpty: - let key = stableName(n) + let key = stableName(c.up, n, scope) result = c.mapping.getOrDefault(key) if pointer(result) == nil: - let name = Z3_mk_string_symbol(ctx, $n) + let name = Z3_mk_string_symbol(ctx, key) result = Z3_mk_const(ctx, name, typeToZ3(c, n.typ)) c.mapping[key] = result vars.add n @@ -333,15 +465,24 @@ proc nodeToZ3(c: var DrCon; n: PNode; vars: var seq[PNode]): Z3_ast = for i in 0..n.len-2: isTrivial = isTrivial and n[i].kind in {nkEmpty, nkCommentStmt} if isTrivial: - result = nodeToZ3(c, n[^1], vars) + result = rec n[^1] else: notImplemented(renderTree(n)) of nkHiddenDeref: result = rec n[0] else: - notImplemented(renderTree(n)) + if isLoc(n, c.assumeUniqueness): + let key = stableName(c.up, n, scope) + result = c.mapping.getOrDefault(key) + if pointer(result) == nil: + let name = Z3_mk_string_symbol(ctx, key) + result = Z3_mk_const(ctx, name, typeToZ3(c, n.typ)) + c.mapping[key] = result + vars.add n + else: + notImplemented(renderTree(n)) -proc addRangeInfo(c: var DrCon, n: PNode, res: var seq[Z3_ast]) = +proc addRangeInfo(c: var DrCon, n: PNode; scope: VersionScope, res: var seq[Z3_ast]) = var cmpOp = mLeI if n.typ != nil: cmpOp = @@ -393,15 +534,15 @@ proc addRangeInfo(c: var DrCon, n: PNode, res: var seq[Z3_ast]) = let ensures = op.n[0][ensuresEffects] if ensures != nil and ensures.kind != nkEmpty: var dummy: seq[PNode] - res.add nodeToZ3(c, translateEnsures(ensures, n), dummy) + res.add nodeToZ3(c, translateEnsures(ensures, n), scope, dummy) return let x = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), lowBound, n) let y = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), n, highBound) var dummy: seq[PNode] - res.add nodeToZ3(c, x, dummy) - res.add nodeToZ3(c, y, dummy) + res.add nodeToZ3(c, x, scope, dummy) + res.add nodeToZ3(c, y, scope, dummy) proc on_err(ctx: Z3_context, e: Z3_error_code) {.nimcall.} = #writeStackTrace() @@ -423,18 +564,18 @@ proc conj(ctx: Z3_context; conds: seq[Z3_ast]): Z3_ast = else: result = Z3_mk_true(ctx) -proc proofEngineAux(c: var DrCon; assumptions: seq[PNode]; toProve: PNode): (bool, string) = - c.mapping = initTable[string, Z3_ast]() +proc setupZ3(): Z3_context = let cfg = Z3_mk_config() - Z3_set_param_value(cfg, "model", "true"); - let ctx = Z3_mk_context(cfg) - c.z3 = ctx - Z3_del_config(cfg) - Z3_set_error_handler(ctx, on_err) - when false: Z3_set_param_value(cfg, "timeout", "1000") + Z3_set_param_value(cfg, "model", "true") + result = Z3_mk_context(cfg) + Z3_del_config(cfg) + Z3_set_error_handler(result, on_err) +proc proofEngineAux(c: var DrCon; assumptions: seq[(PNode, VersionScope)]; + toProve: (PNode, VersionScope)): (bool, string) = + c.mapping = initTable[string, Z3_ast]() try: #[ @@ -455,20 +596,21 @@ proc proofEngineAux(c: var DrCon; assumptions: seq[PNode]; toProve: PNode): (boo var collectedVars: seq[PNode] + template ctx(): untyped = c.up.z3 + let solver = Z3_mk_solver(ctx) var lhs: seq[Z3_ast] - for assumption in assumptions: - if assumption != nil: - try: - let za = nodeToZ3(c, assumption, collectedVars) - #Z3_solver_assert ctx, solver, za - lhs.add za - except CannotMapToZ3Error: - discard "ignore a fact we cannot map to Z3" + for assumption in items(assumptions): + try: + let za = nodeToZ3(c, assumption[0], assumption[1], collectedVars) + #Z3_solver_assert ctx, solver, za + lhs.add za + except CannotMapToZ3Error: + discard "ignore a fact we cannot map to Z3" - let z3toProve = nodeToZ3(c, toProve, collectedVars) + let z3toProve = nodeToZ3(c, toProve[0], toProve[1], collectedVars) for v in collectedVars: - addRangeInfo(c, v, lhs) + addRangeInfo(c, v, toProve[1], lhs) # to make Z3 produce nice counterexamples, we try to prove the # negation of our conjecture and see if it's Z3_L_FALSE @@ -476,7 +618,8 @@ proc proofEngineAux(c: var DrCon; assumptions: seq[PNode]; toProve: PNode): (boo #Z3_mk_not(ctx, forall(ctx, collectedVars, conj(ctx, lhs), z3toProve)) - #echo "toProve: ", Z3_ast_to_string(ctx, fa), " ", c.graph.config $ toProve.info + when defined(dz3): + echo "toProve: ", Z3_ast_to_string(ctx, fa), " ", c.graph.config $ toProve[0].info, " ", int(toProve[1]) Z3_solver_assert ctx, solver, fa let z3res = Z3_solver_check(ctx, solver) @@ -489,18 +632,22 @@ proc proofEngineAux(c: var DrCon; assumptions: seq[PNode]; toProve: PNode): (boo except ValueError: result[0] = false result[1] = getCurrentExceptionMsg() - finally: - Z3_del_context(ctx) -proc proofEngine(graph: ModuleGraph; assumptions: seq[PNode]; toProve: PNode): (bool, string) = +proc proofEngine(ctx: DrnimContext; assumptions: seq[(PNode, VersionScope)]; + toProve: (PNode, VersionScope)): (bool, string) = var c: DrCon - c.graph = graph + c.graph = ctx.graph + c.assumeUniqueness = assumeUniqueness + c.up = ctx result = proofEngineAux(c, assumptions, toProve) +proc skipAddr(n: PNode): PNode {.inline.} = + (if n.kind == nkHiddenAddr: n[0] else: n) + proc translateReq(r, call: PNode): PNode = if r.kind == nkSym and r.sym.kind == skParam: if r.sym.position+1 < call.len: - result = call[r.sym.position+1] + result = call[r.sym.position+1].skipAddr else: notImplemented("no argument given for formal parameter: " & r.sym.name.s) else: @@ -508,11 +655,11 @@ proc translateReq(r, call: PNode): PNode = for i in 0 ..< safeLen(r): result[i] = translateReq(r[i], call) -proc requirementsCheck(graph: ModuleGraph; assumptions: seq[PNode]; - call, requirement: PNode): (bool, string) {.nimcall.} = +proc requirementsCheck(ctx: DrnimContext; assumptions: seq[(PNode, VersionScope)]; + call, requirement: PNode): (bool, string) = try: let r = translateReq(requirement, call) - result = proofEngine(graph, assumptions, r) + result = proofEngine(ctx, assumptions, (r, ctx.currentScope)) except ValueError: result[0] = false result[1] = getCurrentExceptionMsg() @@ -552,24 +699,347 @@ proc compatibleProps(graph: ModuleGraph; formal, actual: PType): bool {.nimcall. var c: DrCon c.graph = graph c.canonParameterNames = true - if not frequires.isEmpty: - result = not arequires.isEmpty and proofEngineAux(c, @[frequires], arequires)[0] + try: + c.up = DrnimContext(z3: setupZ3(), o: initOperators(graph), graph: graph, owner: nil) + template zero: untyped = VersionScope(0) + if not frequires.isEmpty: + result = not arequires.isEmpty and proofEngineAux(c, @[(frequires, zero)], (arequires, zero))[0] - if result: - if not fensures.isEmpty: - result = not aensures.isEmpty and proofEngineAux(c, @[aensures], fensures)[0] + if result: + if not fensures.isEmpty: + result = not aensures.isEmpty and proofEngineAux(c, @[(aensures, zero)], (fensures, zero))[0] + finally: + Z3_del_context(c.up.z3) else: # formal has requirements but 'actual' has none, so make it # incompatible. XXX What if the requirement only mentions that # we already know from the type system? result = frequires.isEmpty and fensures.isEmpty +template config(c: typed): untyped = c.graph.config + +proc addFact(c: DrnimContext; n: PNode) = + let v = c.currentScope + if n[0].kind == nkSym and n[0].sym.magic in {mOr, mAnd}: + c.facts.add((n[1], v)) + c.facts.add((n, v)) + +proc addFactNeg(c: DrnimContext; n: PNode) = + var neg = newNodeI(nkCall, n.info, 2) + neg[0] = newSymNode(c.o.opNot) + neg[1] = n + addFact(c, neg) + +proc prove(c: DrnimContext; prop: PNode): bool = + let (success, m) = proofEngine(c, c.facts, (prop, c.currentScope)) + if not success: + message(c.config, prop.info, warnStaticIndexCheck, "cannot prove: " & $prop & m) + result = success + +proc traversePragmaStmt(c: DrnimContext, n: PNode) = + for it in n: + if it.kind == nkExprColonExpr: + let pragma = whichPragma(it) + if pragma == wAssume: + addFact(c, it[1]) + elif pragma == wInvariant or pragma == wAssert: + if prove(c, it[1]): + addFact(c, it[1]) + +proc requiresCheck(c: DrnimContext, call: PNode; op: PType) = + assert op.n[0].kind == nkEffectList + if requiresEffects < op.n[0].len: + let requires = op.n[0][requiresEffects] + if requires != nil and requires.kind != nkEmpty: + # we need to map the call arguments to the formal parameters used inside + # 'requires': + let (success, m) = requirementsCheck(c, c.facts, call, requires) + if not success: + message(c.config, call.info, warnStaticIndexCheck, "cannot prove: " & $requires & m) + +proc freshVersion(c: DrnimContext; arg: PNode) = + let v = getRoot(arg) + if v != nil: + c.varVersions.add v.id + +proc translateEnsuresFromCall(c: DrnimContext, e, call: PNode): PNode = + if e.kind in nkCallKinds and e[0].kind == nkSym and e[0].sym.magic == mOld: + assert e[1].kind == nkSym and e[1].sym.kind == skParam + let param = e[1].sym + let arg = call[param.position+1].skipAddr + result = buildCall(e[0].sym, arg) + elif e.kind == nkSym and e.sym.kind == skParam: + let param = e.sym + let arg = call[param.position+1].skipAddr + result = arg + else: + result = shallowCopy(e) + for i in 0 ..< safeLen(e): result[i] = translateEnsuresFromCall(c, e[i], call) + +proc collectEnsuredFacts(c: DrnimContext, call: PNode; op: PType) = + assert op.n[0].kind == nkEffectList + for i in 1 ..< min(call.len, op.len): + if op[i].kind == tyVar: + freshVersion(c, call[i].skipAddr) + + if ensuresEffects < op.n[0].len: + let ensures = op.n[0][ensuresEffects] + if ensures != nil and ensures.kind != nkEmpty: + addFact(c, translateEnsuresFromCall(c, ensures, call)) + +proc checkLe(c: DrnimContext, a, b: PNode) = + var cmpOp = mLeI + if a.typ != nil: + case a.typ.skipTypes(abstractInst).kind + of tyFloat..tyFloat128: cmpOp = mLeF64 + of tyChar, tyUInt..tyUInt64: cmpOp = mLeU + else: discard + + let cmp = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), a, b) + cmp.info = a.info + discard prove(c, cmp) + +proc checkBounds(c: DrnimContext; arr, idx: PNode) = + checkLe(c, lowBound(c.config, arr), idx) + checkLe(c, idx, highBound(c.config, arr, c.o)) + +proc checkRange(c: DrnimContext; value: PNode; typ: PType) = + let t = typ.skipTypes(abstractInst - {tyRange}) + if t.kind == tyRange: + let lowBound = copyTree(t.n[0]) + lowBound.info = value.info + let highBound = copyTree(t.n[1]) + highBound.info = value.info + checkLe(c, lowBound, value) + checkLe(c, value, highBound) + +proc addAsgnFact*(c: DrnimContext, key, value: PNode) = + var fact = newNodeI(nkCall, key.info, 3) + fact[0] = newSymNode(c.o.opEq) + fact[1] = key + fact[2] = value + c.facts.add((fact, c.currentScope)) + +proc traverse(c: DrnimContext; n: PNode) + +proc traverseTryStmt(c: DrnimContext; n: PNode) = + traverse(c, n[0]) + let oldFacts = c.facts.len + for i in 1 ..< n.len: + traverse(c, n[i].lastSon) + setLen(c.facts, oldFacts) + +proc traverseCase(c: DrnimContext; n: PNode) = + traverse(c, n[0]) + let oldFacts = c.facts.len + for i in 1 ..< n.len: + traverse(c, n[i].lastSon) + # XXX make this as smart as 'if elif' + setLen(c.facts, oldFacts) + +proc traverseIf(c: DrnimContext; n: PNode) = + traverse(c, n[0][0]) + let oldFacts = c.facts.len + addFact(c, n[0][0]) + + traverse(c, n[0][1]) + + for i in 1.. 1: + addFact(c, branch[0]) + for i in 0.. 0 and n[0].kind == nkEffectList and ensuresEffects < n[0].len: + let ensures = n[0][ensuresEffects] + if ensures != nil and ensures.kind != nkEmpty: + discard prove(c, ensures) + +proc traverseAsgn(c: DrnimContext; n: PNode) = + traverse(c, n[0]) + traverse(c, n[1]) + + proc replaceByOldParams(fact, le: PNode): PNode = + if guards.sameTree(fact, le): + result = newNodeIT(nkCall, fact.info, fact.typ) + result.add newSymNode createMagic(c.graph, "old", mOld) + result.add fact + else: + result = shallowCopy(fact) + for i in 0 ..< safeLen(fact): + result[i] = replaceByOldParams(fact[i], le) + + freshVersion(c, n[0]) + addAsgnFact(c, n[0], replaceByOldParams(n[1], n[0])) + when defined(debug): + echoFacts(c) + +proc traverse(c: DrnimContext; n: PNode) = + case n.kind + of nkEmpty..nkNilLit: + discard "nothing to do" + of nkRaiseStmt, nkBreakStmt, nkContinueStmt: + inc c.hasUnstructedCf + for i in 0.. 2 +a`2 -> 4 +a`1 -> 3 +a -> 2 [IndexCheck] +tensures.nim(69, 17) Warning: cannot prove: a < 4; counter example: y -> 2 +a`1 -> 4 +a -> 2 [IndexCheck] +tensures.nim(73, 10) Warning: END [User]''' cmd: "drnim $file" action: "compile" """ - +import std/logic {.push staticBoundChecks: defined(nimDrNim).} {.warning: "BEGIN".} @@ -27,5 +34,41 @@ proc main = main() +proc myinc(x: var int) {.ensures: x == old(x)+1.} = + inc x + {.assume: old(x)+1 == x.} + +proc mainB(y: int) = + var a = y + if a < 3: + myinc a + {.assert: a < 4.} + myinc a + {.assert: a < 4.} # now this is wrong! + +mainB(3) + +proc a(yy, z: int) {.requires: (yy - z) > 6.} = discard +# 'requires' must be weaker (or equal) +# 'ensures' must be stronger (or equal) + +# a 'is weaker than' b iff b -> a +# a 'is stronger than' b iff a -> b +# --> We can use Z3 to compute whether 'var x: T = q' is valid + +type + F = proc (yy, z3: int) {.requires: z3 < 5 and z3 > -5 and yy > 10.} + +var + x: F = a # valid? + +proc testAsgn(y: int) = + var a = y + if a < 3: + a = a + 2 + {.assert: a < 4.} + +testAsgn(3) + {.warning: "END".} {.pop.} diff --git a/drnim/tests/tsetlen_invalidates.nim b/drnim/tests/tsetlen_invalidates.nim index 03620af10..f3e595744 100644 --- a/drnim/tests/tsetlen_invalidates.nim +++ b/drnim/tests/tsetlen_invalidates.nim @@ -1,12 +1,15 @@ discard """ - nimout: ''' -tsetlen_invalidates.nim(15, 12) Warning: cannot prove: 0 <= len(a) + -1; counter example: a.len -> 0 [IndexCheck] + nimout: '''tsetlen_invalidates.nim(12, 10) Warning: BEGIN [User] +tsetlen_invalidates.nim(18, 12) Warning: cannot prove: 0 <= len(a) + -1; counter example: a`1.len -> 0 +a.len -> 1 [IndexCheck] +tsetlen_invalidates.nim(26, 10) Warning: END [User] ''' cmd: "drnim $file" action: "compile" """ {.push staticBoundChecks: defined(nimDrNim).} +{.warning: "BEGIN".} proc p() = var a = newSeq[int](3) @@ -20,3 +23,4 @@ proc p() = {.pop.} p() +{.warning: "END".} From a0b33f9408cd732bffd3779167842bff568eab85 Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 15 Apr 2020 14:11:18 -0400 Subject: [PATCH 0326/4254] Add `hashWangYi1` (#13823) * Unwind just the "pseudorandom probing" (whole hash-code-keyed variable stride double hashing) part of recent sets & tables changes (which has still been causing bugs over a month later (e.g., two days ago https://github.com/nim-lang/Nim/issues/13794) as well as still having several "figure this out" implementation question comments in them (see just diffs of this PR). This topic has been discussed in many places: https://github.com/nim-lang/Nim/issues/13393 https://github.com/nim-lang/Nim/pull/13418 https://github.com/nim-lang/Nim/pull/13440 https://github.com/nim-lang/Nim/issues/13794 Alternative/non-mandatory stronger integer hashes (or vice-versa opt-in identity hashes) are a better solution that is more general (no illusion of one hard-coded sequence solving all problems) while retaining the virtues of linear probing such as cache obliviousness and age-less tables under delete-heavy workloads (still untested after a month of this change). The only real solution for truly adversarial keys is a hash keyed off of data unobservable to attackers. That all fits better with a few families of user-pluggable/define-switchable hashes which can be provided in a separate PR more about `hashes.nim`. This PR carefully preserves the better (but still hard coded!) probing of the `intsets` and other recent fixes like `move` annotations, hash order invariant tests, `intsets.missingOrExcl` fixing, and the move of `rightSize` into `hashcommon.nim`. * Fix `data.len` -> `dataLen` problem. * This is an alternate resolution to https://github.com/nim-lang/Nim/issues/13393 (which arguably could be resolved outside the stdlib). Add version1 of Wang Yi's hash specialized to 8 byte integers. This gives simple help to users having trouble with overly colliding hash(key)s. I.e., A) `import hashes; proc hash(x: myInt): Hash = hashWangYi1(int(x))` in the instantiation context of a `HashSet` or `Table` or B) more globally, compile with `nim c -d:hashWangYi1`. No hash can be all things to all use cases, but this one is A) vetted to scramble well by the SMHasher test suite (a necessarily limited but far more thorough test than prior proposals here), B) only a few ALU ops on many common CPUs, and C) possesses an easy via "grade school multi-digit multiplication" fall back for weaker deployment contexts. Some people might want to stampede ahead unbridled, but my view is that a good plan is to A) include this in the stdlib for a release or three to let people try it on various key sets nim-core could realistically never access/test (maybe mentioning it in the changelog so people actually try it out), B) have them report problems (if any), C) if all seems good, make the stdlib more novice friendly by adding `hashIdentity(x)=x` and changing the default `hash() = hashWangYi1` with some `when defined` rearranging so users can `-d:hashIdentity` if they want the old behavior back. This plan is compatible with any number of competing integer hashes if people want to add them. I would strongly recommend they all *at least* pass the SMHasher suite since the idea here is to become more friendly to novices who do not generally understand hashing failure modes. * Re-organize to work around `when nimvm` limitations; Add some tests; Add a changelog.md entry. * Add less than 64-bit CPU when fork. * Fix decl instead of call typo. * First attempt at fixing range error on 32-bit platforms; Still do the arithmetic in doubled up 64-bit, but truncate the hash to the lower 32-bits, but then still return `uint64` to be the same. So, type correct but truncated hash value. Update `thashes.nim` as well. * A second try at making 32-bit mode CI work. * Use a more systematic identifier convention than Wang Yi's code. * Fix test that was wrong for as long as `toHashSet` used `rightSize` (a very long time, I think). `$a`/`$b` depend on iteration order which varies with table range reduced hash order which varies with range for some `hash()`. With 3 elements, 3!=6 is small and we've just gotten lucky with past experimental `hash()` changes. An alternate fix here would be to not stringify but use the HashSet operators, but it is not clear that doesn't alter the "spirit" of the test. * Fix another stringified test depending upon hash order. * Oops - revert the string-keyed test. * Fix another stringify test depending on hash order. * Add a better than always zero `defined(js)` branch. * It turns out to be easy to just work all in `BigInt` inside JS and thus guarantee the same low order bits of output hashes (for `isSafeInteger` input numbers). Since `hashWangYi1` output bits are equally random in all their bits, this means that tables will be safely scrambled for table sizes up to 2**32 or 4 gigaentries which is probably fine, as long as the integer keys are all < 2**53 (also likely fine). (I'm unsure why the infidelity with C/C++ back ends cut off is 32, not 53 bits.) Since HashSet & Table only use the low order bits, a quick corollary of this is that `$` on most int-keyed sets/tables will be the same in all the various back ends which seems a nice-to-have trait. * These string hash tests fail for me locally. Maybe this is what causes the CI hang for testament pcat collections? * Oops. That failure was from me manually patching string hash in hashes. Revert. * Import more test improvements from https://github.com/nim-lang/Nim/pull/13410 * Fix bug where I swapped order when reverting the test. Ack. * Oh, just accept either order like more and more hash tests. * Iterate in the same order. * `return` inside `emit` made us skip `popFrame` causing weird troubles. * Oops - do Windows branch also. * `nimV1hash` -> multiply-mnemonic, type-scoped `nimIntHash1` (mnemonic resolutions are "1 == identity", 1 for Nim Version 1, 1 for first/simplest/fastest in a series of possibilities. Should be very easy to remember.) * Re-organize `when nimvm` logic to be a strict `when`-`else`. * Merge other changes. * Lift constants to a common area. * Fall back to identity hash when `BigInt` is unavailable. * Increase timeout slightly (probably just real-time perturbation of CI system performance). --- changelog.md | 3 + lib/pure/collections/sets.nim | 5 +- lib/pure/hashes.nim | 73 +++++++++++++++++++- lib/pure/sugar.nim | 6 +- tests/collections/tcollections.nim | 8 ++- tests/collections/tcollections_to_string.nim | 5 +- tests/stdlib/thashes.nim | 17 +++++ tests/vm/tslow_tables.nim | 2 +- 8 files changed, 107 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 1fc6d19c2..d75e8d17b 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,9 @@ - `uri` adds Data URI Base64, implements RFC-2397. - Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) to the `dom` module for the JavaScript target. +- The default hash for `Ordinal` has changed to something more bit-scrambling. + `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old + one in an instantiation context while `-d:nimIntHash1` recovers it globally. ## Language changes diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 8c04a05e3..11639df3b 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -334,8 +334,7 @@ proc pop*[A](s: var HashSet[A]): A = ## * `clear proc <#clear,HashSet[A]>`_ runnableExamples: var s = toHashSet([2, 1]) - assert s.pop == 1 - assert s.pop == 2 + assert [s.pop, s.pop] in [[1, 2], [2,1]] # order unspecified doAssertRaises(KeyError, echo s.pop) for h in 0 .. high(s.data): @@ -1008,7 +1007,7 @@ when isMainModule and not defined(release): block toSeqAndString: var a = toHashSet([2, 7, 5]) - var b = initHashSet[int]() + var b = initHashSet[int](rightSize(a.len)) for x in [2, 7, 5]: b.incl(x) assert($a == $b) #echo a diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index d799fb062..d6a7c7e41 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -70,6 +70,66 @@ proc `!$`*(h: Hash): Hash {.inline.} = res = res + res shl 15 result = cast[Hash](res) +proc hiXorLoFallback64(a, b: uint64): uint64 {.inline.} = + let # Fall back in 64-bit arithmetic + aH = a shr 32 + aL = a and 0xFFFFFFFF'u64 + bH = b shr 32 + bL = b and 0xFFFFFFFF'u64 + rHH = aH * bH + rHL = aH * bL + rLH = aL * bH + rLL = aL * bL + t = rLL + (rHL shl 32) + var c = if t < rLL: 1'u64 else: 0'u64 + let lo = t + (rLH shl 32) + c += (if lo < t: 1'u64 else: 0'u64) + let hi = rHH + (rHL shr 32) + (rLH shr 32) + c + return hi xor lo + +proc hiXorLo(a, b: uint64): uint64 {.inline.} = + # Xor of high & low 8B of full 16B product + when nimvm: + result = hiXorLoFallback64(a, b) # `result =` is necessary here. + else: + when Hash.sizeof < 8: + result = hiXorLoFallback64(a, b) + elif defined(gcc) or defined(llvm_gcc) or defined(clang): + {.emit: """__uint128_t r = a; r *= b; `result` = (r >> 64) ^ r;""".} + elif defined(windows) and not defined(tcc): + {.emit: """a = _umul128(a, b, &b); `result` = a ^ b;""".} + else: + result = hiXorLoFallback64(a, b) + +proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} = + ## Wang Yi's hash_v1 for 8B int. https://github.com/rurban/smhasher has more + ## details. This passed all scrambling tests in Spring 2019 and is simple. + ## NOTE: It's ok to define ``proc(x: int16): Hash = hashWangYi1(Hash(x))``. + const P0 = 0xa0761d6478bd642f'u64 + const P1 = 0xe7037ed1a0b428db'u64 + const P58 = 0xeb44accab455d165'u64 xor 8'u64 + when nimvm: + cast[Hash](hiXorLo(hiXorLo(P0, uint64(x) xor P1), P58)) + else: + when defined(js): + asm """ + if (typeof BigInt == 'undefined') { + `result` = `x`; // For Node < 10.4, etc. we do the old identity hash + } else { // Otherwise we match the low 32-bits of C/C++ hash + function hi_xor_lo_js(a, b) { + const prod = BigInt(a) * BigInt(b); + const mask = (BigInt(1) << BigInt(64)) - BigInt(1); + return (prod >> BigInt(64)) ^ (prod & mask); + } + const P0 = BigInt(0xa0761d64)< Date: Wed, 15 Apr 2020 23:35:10 +0200 Subject: [PATCH 0327/4254] added a .since annotation to hashIdentity --- lib/pure/hashes.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index d6a7c7e41..287b152d2 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -44,6 +44,8 @@ ## * `std/sha1 module `_ for a sha1 encoder and decoder ## * `tables module `_ for hash tables +include "system/inclrtl" + type Hash* = int ## A hash value. Hash tables using these values should ## always have a size of a power of two and can use the ``and`` @@ -172,14 +174,14 @@ proc hash*[T: proc](x: T): Hash {.inline.} = else: result = hash(pointer(x)) -proc hashIdentity*[T: Ordinal](x: T): Hash {.inline.} = +proc hashIdentity*[T: Ordinal](x: T): Hash {.inline, since: (1, 3).} = ## The identity hash. I.e. ``hashIdentity(x) = x``. cast[Hash](ord(x)) when defined(nimIntHash1): proc hash*[T: Ordinal](x: T): Hash {.inline.} = ## Efficient hashing of integers. - hashIdentity(x) + cast[Hash](ord(x)) else: proc hash*[T: Ordinal](x: T): Hash {.inline.} = ## Efficient hashing of integers. From d72808520b248d72913d8f9e57acdddc95c84465 Mon Sep 17 00:00:00 2001 From: Adam Weber Date: Wed, 15 Apr 2020 23:39:44 -0500 Subject: [PATCH 0328/4254] Grammar correction in backends.rst (#13989) I hate to be the guy that submits a couple grammatical/spelling corrections. --- doc/backends.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/backends.rst b/doc/backends.rst index 7abb786aa..1a6729ee6 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -265,7 +265,7 @@ Create a ``maths.c`` file with the following content: } Now you can run the following Unix like commands to first generate C sources -form the Nim code, then link them into a static binary along your main C +from the Nim code, then link them into a static binary along your main C program:: $ nim c --noMain --noLinking --header:fib.h fib.nim @@ -276,7 +276,7 @@ generating a ``main()`` function in the generated files, avoid linking the object files into a final binary, and explicitly generate a header file for C integration. All the generated files are placed into the ``nimcache`` directory. That's why the next command compiles the ``maths.c`` source plus -all the ``.c`` files form ``nimcache``. In addition to this path, you also +all the ``.c`` files from ``nimcache``. In addition to this path, you also have to tell the C compiler where to find Nim's ``nimbase.h`` header file. Instead of depending on the generation of the individual ``.c`` files you can From 6914de0d8dfb14e4ebe0448c558466c9bb80d833 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 15 Apr 2020 23:59:54 -0700 Subject: [PATCH 0329/4254] fix newDomParser (#13981) --- lib/js/dom.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 280e47d82..a0df4b7b9 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1309,7 +1309,7 @@ proc offsetTop*(e: Node): int {.importcpp: "#.offsetTop", nodecl.} proc offsetLeft*(e: Node): int {.importcpp: "#.offsetLeft", nodecl.} since (1, 3): - func newDomParser*(): DOMParser {.importcpp: "(new DOMParser()​​)".} + func newDomParser*(): DOMParser {.importcpp: "new DOMParser()".} ## DOM Parser constructor. func parseFromString*(this: DOMParser; str: cstring; mimeType: cstring): Document {.importcpp.} From 06e0c75ba9cd46cbbb09deb91db6f746fb62a820 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 16 Apr 2020 20:22:32 +0200 Subject: [PATCH 0330/4254] make fuzzy search a bit less fuzzy (#13996) [backport:1.2] --- tools/dochack/dochack.nim | 2 +- tools/dochack/fuzzysearch.nim | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 2f8465a63..4c4db4638 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -303,7 +303,7 @@ proc dosearch(value: cstring): Element = matches.add((db[i], score)) matches.sort(proc(a, b: auto): int = b[1] - a[1]) - for i in 0 ..< min(matches.len, 19): + for i in 0 ..< min(matches.len, 29): matches[i][0].innerHTML = matches[i][0].getAttribute("data-doc-search-tag") ul.add(tree("LI", cast[Element](matches[i][0]))) if ul.len == 0: diff --git a/tools/dochack/fuzzysearch.nim b/tools/dochack/fuzzysearch.nim index 05f61bc11..fecbaf4f0 100644 --- a/tools/dochack/fuzzysearch.nim +++ b/tools/dochack/fuzzysearch.nim @@ -132,6 +132,9 @@ proc fuzzyMatch*(pattern, str: cstring) : tuple[score: int, matched: bool] = strIndex += 1 + if patIndex == pattern.len and (strIndex == str.len or str[strIndex] notin Letters): + score += 10 + result = ( score: max(0, score), matched: (score > 0), From b6f99409a967baebfda056a46f236643837e483b Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Thu, 16 Apr 2020 13:23:54 -0500 Subject: [PATCH 0331/4254] added extended msg for failed library loads w/ incorrect DLL formats (#13950) * added extended msg for failed library loads w/ incorrect DLL formats * missing colon * fix GetLastError() * make GetLastError() available for windows console apps * remove premature nullchar if outputting extra message * if-protect nullchar detection * better fix for message box code --- lib/system/dyncalls.nim | 36 ++++++++++++++++++++++++++---------- lib/system/excpt.nim | 6 ++++-- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index d16dbdf92..fe4797c5f 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -19,18 +19,34 @@ const proc nimLoadLibraryError(path: string) = # carefully written to avoid memory allocation: - cstderr.rawWrite("could not load: ") + const prefix = "could not load: " + cstderr.rawWrite(prefix) cstderr.rawWrite(path) - cstderr.rawWrite("\n") when not defined(nimDebugDlOpen) and not defined(windows): - cstderr.rawWrite("compile with -d:nimDebugDlOpen for more information\n") - when defined(windows) and defined(guiapp): - # Because console output is not shown in GUI apps, display error as message box: - const prefix = "could not load: " - var msg: array[1000, char] - copyMem(msg[0].addr, prefix.cstring, prefix.len) - copyMem(msg[prefix.len].addr, path.cstring, min(path.len + 1, 1000 - prefix.len)) - discard MessageBoxA(nil, msg[0].addr, nil, 0) + cstderr.rawWrite("\n(compile with -d:nimDebugDlOpen for more information)") + when defined(windows): + const badExe = "\n(bad format; library may be wrong architecture)" + let loadError = GetLastError() + if loadError == ERROR_BAD_EXE_FORMAT: + cstderr.rawWrite(badExe) + when defined(guiapp): + # Because console output is not shown in GUI apps, display the error as a + # message box instead: + var + msg: array[1000, char] + msgLeft = msg.len - 1 # leave (at least) one for nullchar + msgIdx = 0 + copyMem(msg[msgIdx].addr, prefix.cstring, prefix.len) + msgLeft -= prefix.len + msgIdx += prefix.len + let pathLen = min(path.len, msgLeft) + copyMem(msg[msgIdx].addr, path.cstring, pathLen) + msgLeft -= pathLen + msgIdx += pathLen + if loadError == ERROR_BAD_EXE_FORMAT and msgLeft >= badExe.len: + copyMem(msg[msgIdx].addr, badExe.cstring, badExe.len) + discard MessageBoxA(nil, msg[0].addr, nil, 0) + cstderr.rawWrite("\n") quit(1) proc procAddrError(name: cstring) {.compilerproc, nonReloadable, hcrInline.} = diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 76d188ea6..aa3667226 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -17,13 +17,15 @@ var ## instead of `stdmsg.write` when printing stacktrace. ## Unstable API. +when defined(windows): + proc GetLastError(): int32 {.header: "", nodecl.} + const ERROR_BAD_EXE_FORMAT = 193 + when not defined(windows) or not defined(guiapp): proc writeToStdErr(msg: cstring) = rawWrite(cstderr, msg) - else: proc MessageBoxA(hWnd: pointer, lpText, lpCaption: cstring, uType: int): int32 {. header: "", nodecl.} - proc writeToStdErr(msg: cstring) = discard MessageBoxA(nil, msg, nil, 0) From 9295251e68ee86b512de51a2f650729ac6893104 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 16 Apr 2020 20:04:05 +0100 Subject: [PATCH 0332/4254] Implements RFCs #209 (#13995) * add test * add changelod entry Co-authored-by: cooldome --- changelog.md | 27 ++++ compiler/astalgo.nim | 4 + compiler/ccgstmts.nim | 31 ++--- compiler/injectdestructors.nim | 73 ++++++++--- compiler/liftdestructors.nim | 174 +++++++++++++++++--------- compiler/magicsys.nim | 25 ++++ compiler/semdata.nim | 7 +- tests/arc/tcaseobj.nim | 49 ++++++++ tests/destructor/tgotoexceptions7.nim | 10 +- 9 files changed, 292 insertions(+), 108 deletions(-) diff --git a/changelog.md b/changelog.md index d75e8d17b..90e014556 100644 --- a/changelog.md +++ b/changelog.md @@ -12,7 +12,34 @@ one in an instantiation context while `-d:nimIntHash1` recovers it globally. ## Language changes +- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: + ```nim + type + MyObj = object + case kind: bool + of true: y: ptr UncheckedArray[float] + of false: z: seq[int] + proc `=destroy`(x: MyObj) = + if x.kind and x.y != nil: + deallocShared(x.y) + x.y = nil + ``` + Refactor into: + ```nim + type + MySubObj = object + val: ptr UncheckedArray[float] + MyObj = object + case kind: bool + of true: y: MySubObj + of false: z: seq[int] + + proc `=destroy`(x: MySubObj) = + if x.val != nil: + deallocShared(x.val) + x.val = nil + ``` ## Compiler changes diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 47cf83715..5e23d2284 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -1048,3 +1048,7 @@ proc listSymbolNames*(symbols: openArray[PSym]): string = result.add ", " result.add sym.name.s +proc isDiscriminantField*(n: PNode): bool = + if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags + elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags + else: false diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index bb9d30b8f..e2bcf3a74 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1489,15 +1489,6 @@ proc genPragma(p: BProc, n: PNode) = p.module.injectStmt = p.s(cpsStmts) else: discard -proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool = - if optFieldCheck in p.options: - var le = asgn[0] - if le.kind == nkCheckedFieldExpr: - var field = le[0][1].sym - result = sfDiscriminant in field.flags - elif le.kind == nkDotExpr: - var field = le[1].sym - result = sfDiscriminant in field.flags proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType, field: PSym) = @@ -1534,24 +1525,20 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = initLocExpr(p, e[0], a) getTemp(p, a.t, tmp) expr(p, e[1], tmp) - let field = dotExpr[1].sym - if optTinyRtti in p.config.globalOptions: - let t = dotExpr[0].typ.skipTypes(abstractInst) - var oldVal, newVal: TLoc - genCaseObjDiscMapping(p, e[0], t, field, oldVal) - genCaseObjDiscMapping(p, e[1], t, field, newVal) - lineCg(p, cpsStmts, - "if ($1 != $2) { #raiseObjectCaseTransition(); $3}$n", - [rdLoc(oldVal), rdLoc(newVal), raiseInstr(p)]) - else: + if optTinyRtti notin p.config.globalOptions: + let field = dotExpr[1].sym genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field) + message(p.config, e.info, warnCaseTransition) genAssignment(p, a, tmp, {}) proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = if e[0].kind == nkSym and sfGoto in e[0].sym.flags: genLineDir(p, e) genGotoVar(p, e[1]) - elif not fieldDiscriminantCheckNeeded(p, e): + elif optFieldCheck in p.options and isDiscriminantField(e[0]): + genLineDir(p, e) + asgnFieldDiscriminant(p, e) + else: let le = e[0] let ri = e[1] var a: TLoc @@ -1565,10 +1552,6 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = assert(a.t != nil) genLineDir(p, ri) loadInto(p, le, ri, a) - else: - genLineDir(p, e) - asgnFieldDiscriminant(p, e) - message(p.config, e.info, warnCaseTransition) proc genStmts(p: BProc, t: PNode) = var a: TLoc diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 29199aa41..07ab2730d 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -22,9 +22,9 @@ # - eliminate 'wasMoved(x); destroy(x)' pairs as a post processing step. import - intsets, ast, msgs, renderer, magicsys, types, idents, + intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, strutils, options, dfa, lowerings, tables, modulegraphs, msgs, - lineinfos, parampatterns, sighashes + lineinfos, parampatterns, sighashes, liftdestructors from trees import exprStructuralEquivalent from algorithm import reverse @@ -49,6 +49,12 @@ type uninit: IntSet # set of uninit'ed vars uninitComputed: bool + ProcessMode = enum + normal + consumed + sinkArg + + const toDebug {.strdefine.} = "" template dbg(body) = @@ -56,6 +62,9 @@ template dbg(body) = if c.owner.name.s == toDebug or toDebug == "always": body +proc p(n: PNode; c: var Con; mode: ProcessMode): PNode +proc moveOrCopy(dest, ri: PNode; c: var Con): PNode + proc isLastRead(location: PNode; c: var Con; pc, comesFrom: int): int = var pc = pc while pc < c.g.len: @@ -220,16 +229,19 @@ proc makePtrType(c: Con, baseType: PType): PType = result = newType(tyPtr, c.owner) addSonSkipIntLit(result, baseType) +proc genOp(c: Con; op: PSym; dest: PNode): PNode = + let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) + addrExp.add(dest) + result = newTree(nkCall, newSymNode(op), addrExp) + proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = var op = t.attachedOps[kind] - if op == nil or op.ast[genericParamsPos].kind != nkEmpty: # give up and find the canonical type instead: let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.graph.canonTypes.getOrDefault(h) if canon != nil: op = canon.attachedOps[kind] - if op == nil: #echo dest.typ.id globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] & @@ -241,9 +253,7 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = if kind == attachedDestructor: echo "destructor is ", op.id, " ", op.ast if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind]) - let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) - addrExp.add(dest) - result = newTree(nkCall, newSymNode(op), addrExp) + genOp(c, op, dest) proc genDestroy(c: Con; dest: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) @@ -300,6 +310,44 @@ proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = sym.typ = typ result = newSymNode(sym) +proc genDiscriminantAsgn(c: var Con; n: PNode): PNode = + # discriminator is ordinal value that doesn't need sink destroy + # but fields within active case branch might need destruction + + # tmp to support self assignments + let tmp = getTemp(c, n[1].typ, n.info) + c.addTopVar(tmp) + + result = newTree(nkStmtList) + result.add newTree(nkFastAsgn, tmp, p(n[1], c, consumed)) + result.add p(n[0], c, normal) + + let le = p(n[0], c, normal) + let leDotExpr = if le.kind == nkCheckedFieldExpr: le[0] else: le + let objType = leDotExpr[0].typ + + if hasDestructor(objType): + if objType.attachedOps[attachedDestructor] != nil and + sfOverriden in objType.attachedOps[attachedDestructor].flags: + localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for object's with user defined destructor is not supported, object must have default destructor. +It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""") + result.add newTree(nkFastAsgn, le, tmp) + return + + # generate: if le != tmp: `=destroy`(le) + let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info) + let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool)) + cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info)) + cond.add le + cond.add tmp + let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool)) + notExpr.add newSymNode(createMagic(c.graph, "not", mNot)) + notExpr.add cond + result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, genOp(c, branchDestructor, le))) + result.add newTree(nkFastAsgn, le, tmp) + else: + result.add newTree(nkFastAsgn, le, tmp) + proc genWasMoved(n: PNode; c: var Con): PNode = result = newNodeI(nkCall, n.info) result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved))) @@ -338,15 +386,6 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) -type - ProcessMode = enum - normal - consumed - sinkArg - -proc p(n: PNode; c: var Con; mode: ProcessMode): PNode -proc moveOrCopy(dest, ri: PNode; c: var Con): PNode - proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':' proc passCopyToSink(n: PNode; c: var Con): PNode = @@ -867,6 +906,8 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = cycleCheck(n, c) assert n[1].kind notin {nkAsgn, nkFastAsgn} result = moveOrCopy(p(n[0], c, mode), n[1], c) + elif isDiscriminantField(n[0]): + result = genDiscriminantAsgn(c, n) else: result = copyNode(n) result.add p(n[0], c, mode) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 9e19b9bc2..a64857765 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -26,6 +26,8 @@ type fn: PSym asgnForType: PType recurse: bool + filterDiscriminator: PSym # we generating destructor for case branch + addMemReset: bool # add wasMoved() call after destructor call c: PContext # c can be nil, then we are called from lambdalifting! proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) @@ -72,14 +74,62 @@ proc genAddr(g: ModuleGraph; x: PNode): PNode = result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ)) result.add x -proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode = - result = newNodeIT(nkCall, x.info, op.typ[0]) - result.add(newSymNode(op)) - result.add genAddr(g, x) + +proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = + result = newNodeI(nkCall, i.info) + result.add createMagic(g, name, magic).newSymNode + result.add i + +proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = + result = newNodeI(nkWhileStmt, c.info, 2) + let cmp = genBuiltin(c.g, mLtI, "<", i) + cmp.add genLen(c.g, dest) + cmp.typ = getSysType(c.g, c.info, tyBool) + result[0] = cmp + result[1] = newNodeI(nkStmtList, c.info) + +proc genIf(c: var TLiftCtx; cond, action: PNode): PNode = + result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action)) + +proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode = + # generate: cast[ptr ObjType](cast[int](addr(x)) - offsetOf(objType.field)) + let intType = getSysType(c.g, unknownLineInfo, tyInt) + + let addrOf = newNodeIT(nkAddr, c.info, makePtrType(x.owner, x.typ)) + addrOf.add newDeref(newSymNode(x)) + let castExpr1 = newNodeIT(nkCast, c.info, intType) + castExpr1.add newNodeIT(nkType, c.info, intType) + castExpr1.add addrOf + + let dotExpr = newNodeIT(nkDotExpr, c.info, x.typ) + dotExpr.add newNodeIT(nkType, c.info, objType) + dotExpr.add newSymNode(field) + + let offsetOf = genBuiltin(c.g, mOffsetOf, "offsetof", dotExpr) + offsetOf.typ = intType + + let minusExpr = genBuiltin(c.g, mSubI, "-", castExpr1) + minusExpr.typ = intType + minusExpr.add offsetOf + + let objPtr = makePtrType(objType.owner, objType) + result = newNodeIT(nkCast, c.info, objPtr) + result.add newNodeIT(nkType, c.info, objPtr) + result.add minusExpr + +proc destructorCall(c: TLiftCtx; op: PSym; x: PNode): PNode = + var destroy = newNodeIT(nkCall, x.info, op.typ[0]) + destroy.add(newSymNode(op)) + destroy.add genAddr(c.g, x) + if c.addMemReset: + result = newTree(nkStmtList, destroy, genBuiltin(c.g, mWasMoved, "wasMoved", x)) + else: + result = destroy proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) = case n.kind of nkSym: + if c.filterDiscriminator != nil: return let f = n.sym let b = if c.kind == attachedTrace: y else: y.dotField(f) if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and @@ -90,6 +140,9 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) fillBody(c, f.typ, body, x.dotField(f), b) of nkNilLit: discard of nkRecCase: + let oldfilterDiscriminator = c.filterDiscriminator + if c.filterDiscriminator == n[0].sym: + c.filterDiscriminator = nil # we have found the case part, proceed as normal # XXX This is only correct for 'attachedSink'! var localEnforceDefaultOp = enforceDefaultOp if c.kind == attachedSink: @@ -121,6 +174,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) caseStmt.add(branch) if emptyBranches != n.len-1: body.add(caseStmt) + c.filterDiscriminator = oldfilterDiscriminator of nkRecList: for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp) else: @@ -275,7 +329,7 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) = if op != nil: #markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add destructorCall(c.g, op, x) + body.add destructorCall(c, op, x) elif useNoGc(c, t): internalError(c.g.config, c.info, "type-bound operator could not be resolved") @@ -293,7 +347,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = #markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add destructorCall(c.g, op, x) + body.add destructorCall(c, op, x) result = true #result = addDestructorCall(c, t, body, x) of attachedAsgn, attachedSink, attachedTrace: @@ -318,22 +372,6 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = v.addVar(result, lowerings.newIntLit(c.g, body.info, first)) body.add v -proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = - result = newNodeI(nkCall, i.info) - result.add createMagic(g, name, magic).newSymNode - result.add i - -proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = - result = newNodeI(nkWhileStmt, c.info, 2) - let cmp = genBuiltin(c.g, mLtI, "<", i) - cmp.add genLen(c.g, dest) - cmp.typ = getSysType(c.g, c.info, tyBool) - result[0] = cmp - result[1] = newNodeI(nkStmtList, c.info) - -proc genIf(c: var TLiftCtx; cond, action: PNode): PNode = - result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action)) - proc addIncStmt(c: var TLiftCtx; body, i: PNode) = let incCall = genBuiltin(c.g, mInc, "inc", i) incCall.add lowerings.newIntLit(c.g, c.info, 1) @@ -382,7 +420,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let moveCall = genBuiltin(c.g, mMove, "move", x) moveCall.add y doAssert t.destructor != nil - moveCall.add destructorCall(c.g, t.destructor, x) + moveCall.add destructorCall(c, t.destructor, x) body.add moveCall of attachedDestructor: # destroy all elements: @@ -413,7 +451,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let moveCall = genBuiltin(c.g, mMove, "move", x) moveCall.add y doAssert t.destructor != nil - moveCall.add destructorCall(c.g, t.destructor, x) + moveCall.add destructorCall(c, t.destructor, x) body.add moveCall # alternatively we could do this: when false: @@ -421,7 +459,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newHookCall(c.g, t.asink, x, y) of attachedDestructor: doAssert t.destructor != nil - body.add destructorCall(c.g, t.destructor, x) + body.add destructorCall(c, t.destructor, x) of attachedTrace: body.add newHookCall(c.g, t.attachedOps[c.kind], x, y) of attachedDispose: @@ -435,7 +473,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let moveCall = genBuiltin(c.g, mMove, "move", x) moveCall.add y doAssert t.destructor != nil - moveCall.add destructorCall(c.g, t.destructor, x) + moveCall.add destructorCall(c, t.destructor, x) body.add moveCall of attachedDestructor, attachedDispose: body.add genBuiltin(c.g, mDestroy, "destroy", x) @@ -738,33 +776,14 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; typ.attachedOps[kind] = baseType.attachedOps[kind] result = typ.attachedOps[kind] -proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; +proc symPrototype(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = - if typ.kind == tyDistinct: - return produceSymDistinctType(g, c, typ, kind, info) - var a: TLiftCtx - a.info = info - a.g = g - a.kind = kind - a.c = c - let body = newNodeI(nkStmtList, info) let procname = getIdent(g.cache, AttachedOpToStr[kind]) - result = newSym(skProc, procname, typ.owner, info) - a.fn = result - a.asgnForType = typ - let dest = newSym(skParam, getIdent(g.cache, "dest"), result, info) let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), result, info) - var d: PNode - #if kind notin {attachedTrace, attachedDispose}: dest.typ = makeVarType(typ.owner, typ) - d = newDeref(newSymNode(dest)) - #else: - # dest.typ = typ - # d = newSymNode(dest) - if kind == attachedTrace: src.typ = getSysType(g, info, tyPointer) else: @@ -775,6 +794,30 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; if kind notin {attachedDestructor, attachedDispose}: result.typ.addParam src + var n = newNodeI(nkProcDef, info, bodyPos+1) + for i in 0.. Date: Thu, 16 Apr 2020 22:27:08 +0100 Subject: [PATCH 0333/4254] Step2: fixes #13781, fixes #13805 (#13897) * Fix sym owner in wrapper proc * threadpool changes * revert lowerings * add newFastMoveStmt * try fixing test by switching to cpp Co-authored-by: cooldome --- compiler/injectdestructors.nim | 13 ++++-- compiler/lowerings.nim | 7 ++++ compiler/spawn.nim | 24 +++++------ lib/pure/concurrency/threadpool.nim | 49 ++++++++++------------ tests/arc/tthread.nim | 63 +++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 tests/arc/tthread.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 07ab2730d..680a38397 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -44,7 +44,7 @@ type graph: ModuleGraph emptyNode: PNode otherRead: PNode - inLoop, hasUnstructuredCf, inDangerousBranch: int + inLoop, inSpawn, hasUnstructuredCf, inDangerousBranch: int declaredVars: IntSet # variables we already moved to the top level uninit: IntSet # set of uninit'ed vars uninitComputed: bool @@ -398,7 +398,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = var m = genCopy(c, tmp, n) m.add p(n, c, normal) result.add m - if isLValue(n) and not isClosureEnv(n) and n.typ.skipTypes(abstractInst).kind != tyRef: + if isLValue(n) and not isClosureEnv(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & "use 'move($1)' to prevent it") % $n) @@ -830,6 +830,12 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = if mode == normal and isRefConstr: result = ensureDestruction(result, c) of nkCallKinds: + let inSpawn = c.inSpawn + if n[0].kind == nkSym and n[0].sym.magic == mSpawn: + c.inSpawn.inc + elif c.inSpawn > 0: + c.inSpawn.dec + let parameters = n[0].typ let L = if parameters != nil: parameters.len else: 0 @@ -840,7 +846,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = result = shallowCopy(n) for i in 1.. 0): result[i] = p(n[i], c, sinkArg) else: result[i] = p(n[i], c, normal) @@ -1085,7 +1091,6 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = let t = params[i].sym.typ if isSinkTypeForParam(t) and hasDestructor(t.skipTypes({tySink})): c.destroys.add genDestroy(c, params[i]) - #if optNimV2 in c.graph.config.globalOptions: # injectDefaultCalls(n, c) let body = p(n, c, normal) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 091b291c2..575bfe8aa 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -59,6 +59,13 @@ proc newFastAsgnStmt*(le, ri: PNode): PNode = result[0] = le result[1] = ri +proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode = + result = newNodeI(nkFastAsgn, le.info, 2) + result[0] = le + result[1] = newNodeIT(nkCall, ri.info, ri.typ) + result[1].add newSymNode(getSysMagic(g, ri.info, "move", mMove)) + result[1].add ri + proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode = assert n.kind == nkVarTuple let value = n.lastSon diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 2f078309b..c60dd934c 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -10,7 +10,7 @@ ## This module implements threadpool's ``spawn``. import ast, types, idents, magicsys, msgs, options, modulegraphs, - lowerings + lowerings, liftdestructors from trees import getMagic, getRoot proc callProc(a: PNode): PNode = @@ -36,8 +36,9 @@ proc spawnResult*(t: PType; inParallel: bool): TSpawnResult = elif inParallel and not containsGarbageCollectedRef(t): srByVar else: srFlowVar -proc flowVarKind(t: PType): TFlowVarKind = - if t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC +proc flowVarKind(c: ConfigRef, t: PType): TFlowVarKind = + if c.selectedGC in {gcArc, gcOrc}: fvBlob + elif t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC elif containsGarbageCollectedRef(t): fvInvalid else: fvBlob @@ -66,17 +67,11 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: P varSection.add vpart if varInit != nil: if g.config.selectedGC in {gcArc, gcOrc}: - if typ.attachedOps[attachedAsgn] != nil: - var call = newNode(nkCall) - call.add newSymNode(typ.attachedOps[attachedAsgn]) - call.add genAddrOf(newSymNode(result), tyVar) - call.add v - varInit.add call - else: - varInit.add newFastAsgnStmt(newSymNode(result), v) + # inject destructors pass will do its own analysis + varInit.add newFastMoveStmt(g, newSymNode(result), v) else: if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions: - varInit.add newFastAsgnStmt(newSymNode(result), v) + varInit.add newFastMoveStmt(g, newSymNode(result), v) else: let deepCopyCall = newNodeI(nkCall, varInit.info, 3) deepCopyCall[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy)) @@ -145,7 +140,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; if spawnKind == srByVar: body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) elif fv != nil: - let fk = fv.typ[1].flowVarKind + let fk = flowVarKind(g.config, fv.typ[1]) if fk == fvInvalid: localError(g.config, f.info, "cannot create a flowVar of type: " & typeToString(fv.typ[1])) @@ -333,6 +328,8 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P wrapperProc = newSym(skProc, getIdent(g.cache, name), owner, fn.info, g.config.options) threadParam = newSym(skParam, getIdent(g.cache, "thread"), wrapperProc, n.info, g.config.options) argsParam = newSym(skParam, getIdent(g.cache, "args"), wrapperProc, n.info, g.config.options) + + wrapperProc.flags.incl sfInjectDestructors block: let ptrType = getSysType(g, n.info, tyPointer) threadParam.typ = ptrType @@ -411,6 +408,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P fvAsExpr = indirectAccess(castExpr, field, n.info) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) + createTypeBoundOps(g, nil, objType, n.info) createWrapperProc(g, fn, threadParam, argsParam, varSection, varInit, call, barrierAsExpr, fvAsExpr, spawnKind, wrapperProc) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index ec950aa19..2abcafb80 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -137,7 +137,7 @@ type const threadpoolWaitMs {.intdefine.}: int = 100 -proc blockUntil*(fv: FlowVarBase) = +proc blockUntil*(fv: var FlowVarBaseObj) = ## Waits until the value for the ``fv`` arrives. ## ## Usually it is not necessary to call this explicitly. @@ -185,7 +185,7 @@ proc attach(fv: FlowVarBase; i: int): bool = result = false release(fv.cv.L) -proc finished(fv: FlowVarBase) = +proc finished(fv: var FlowVarBaseObj) = doAssert fv.ai.isNil, "flowVar is still attached to an 'blockUntilAny'" # we have to protect against the rare cases where the owner of the flowVar # simply disregards the flowVar and yet the "flowVar" has not yet written @@ -208,10 +208,12 @@ proc finished(fv: FlowVarBase) = # the worker thread waits for "data" to be set to nil before shutting down owner.data = nil -proc fvFinalizer[T](fv: FlowVar[T]) = finished(fv) +proc `=destroy`[T](fv: var FlowVarObj[T]) = + finished(fv) + `=destroy`(fv.blob) proc nimCreateFlowVar[T](): FlowVar[T] {.compilerProc.} = - new(result, fvFinalizer) + new(result) proc nimFlowVarCreateSemaphore(fv: FlowVarBase) {.compilerProc.} = fv.cv.initSemaphore() @@ -234,43 +236,34 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = ## Note that due to Nim's parameter passing semantics this ## means that ``T`` doesn't need to be copied so ``awaitAndThen`` can ## sometimes be more efficient than `^ proc <#^,FlowVar[T]>`_. - blockUntil(fv) - when T is string or T is seq: + blockUntil(fv[]) + when defined(nimV2): + action(fv.blob) + elif T is string or T is seq: action(cast[T](fv.data)) elif T is ref: {.error: "'awaitAndThen' not available for FlowVar[ref]".} else: action(fv.blob) - finished(fv) + finished(fv[]) proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T = ## Blocks until the value is available and then returns this value. - blockUntil(fv) - result = cast[ptr T](fv.data) - finished(fv) - -proc `^`*[T](fv: FlowVar[ref T]): ref T = - ## Blocks until the value is available and then returns this value. - blockUntil(fv) - let src = cast[ref T](fv.data) + blockUntil(fv[]) when defined(nimV2): - result = src + result = cast[ptr T](fv.blob) else: - deepCopy result, src - finished(fv) + result = cast[ptr T](fv.data) + finished(fv[]) proc `^`*[T](fv: FlowVar[T]): T = ## Blocks until the value is available and then returns this value. - blockUntil(fv) - when T is string or T is seq: - let src = cast[T](fv.data) - when defined(nimV2): - result = src - else: - deepCopy result, src + blockUntil(fv[]) + when not defined(nimV2) and (T is string or T is seq or T is ref): + deepCopy result, cast[T](fv.data) else: result = fv.blob - finished(fv) + finished(fv[]) proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int = ## Awaits any of the given ``flowVars``. Returns the index of one ``flowVar`` @@ -457,14 +450,14 @@ proc preferSpawn*(): bool = ## <#spawnX.t>`_ instead. result = gSomeReady.counter > 0 -proc spawn*(call: typed): void {.magic: "Spawn".} +proc spawn*(call: sink typed): void {.magic: "Spawn".} ## Always spawns a new task, so that the ``call`` is never executed on ## the calling thread. ## ## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a ## return type that is either ``void`` or compatible with ``FlowVar[T]``. -proc pinnedSpawn*(id: ThreadId; call: typed): void {.magic: "Spawn".} +proc pinnedSpawn*(id: ThreadId; call: sink typed): void {.magic: "Spawn".} ## Always spawns a new task on the worker thread with ``id``, so that ## the ``call`` is **always** executed on the thread. ## diff --git a/tests/arc/tthread.nim b/tests/arc/tthread.nim new file mode 100644 index 000000000..c653c753f --- /dev/null +++ b/tests/arc/tthread.nim @@ -0,0 +1,63 @@ +discard """ + cmd: "nim cpp --gc:arc --threads:on $file" + output: '''ok1 +ok2 +destroyed +destroyed +destroyed +''' +""" +import threadpool, os + +type + MyObj = object + p: int + MyObjRef = ref MyObj + +proc `=destroy`(x: var MyObj) = + if x.p != 0: + echo "destroyed" + +proc thread1(): string = + os.sleep(1000) + return "ok1" + +proc thread2(): ref string = + os.sleep(1000) + new(result) + result[] = "ok2" + +proc thread3(): ref MyObj = + os.sleep(1000) + new(result) + result[].p = 2 + +var fv1 = spawn thread1() +var fv2 = spawn thread2() +var fv3 = spawn thread3() +sync() +echo ^fv1 +echo (^fv2)[] + + +proc thread4(x: MyObjRef): MyObjRef {.nosinks.} = + os.sleep(1000) + result = x + +proc thread5(x: sink MyObjRef): MyObjRef = + os.sleep(1000) + result = x + +proc ref_forwarding_test = + var x = new(MyObj) + x[].p = 2 + var y = spawn thread4(x) + +proc ref_sink_forwarding_test = + var x = new(MyObj) + x[].p = 2 + var y = spawn thread5(x) + +ref_forwarding_test() +ref_sink_forwarding_test() +sync() From f10689d3d40d67b185c918440ceef6a6bcee9999 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 17 Apr 2020 12:23:04 +0100 Subject: [PATCH 0334/4254] fixes #14003 (#14006) [backport:1.2] Co-authored-by: cooldome --- compiler/ccgcalls.nim | 18 ++++++++++++------ tests/arc/tarcmisc.nim | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 9155064a5..893d597bd 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -113,7 +113,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, proc genBoundsCheck(p: BProc; arr, a, b: TLoc) -proc openArrayLoc(p: BProc, n: PNode): Rope = +proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = var a: TLoc var q = skipConv(n) @@ -149,8 +149,11 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString: result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar and - not compileToCpp(p.module): + let atyp = skipTypes(a.t, abstractInst) + if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and + optSeqDestructors in p.config.globalOptions: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + if atyp.kind == tyVar and not compileToCpp(p.module): result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] else: result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] @@ -162,8 +165,11 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = of tyOpenArray, tyVarargs: result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar and - not compileToCpp(p.module): + let ntyp = skipTypes(n.typ, abstractInst) + if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and + optSeqDestructors in p.config.globalOptions: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + if ntyp.kind == tyVar and not compileToCpp(p.module): var t: TLoc t.r = "(*$1)" % [a.rdLoc] result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] @@ -194,7 +200,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = result = genArgStringToCString(p, n) elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n[0] - result = openArrayLoc(p, n) + result = openArrayLoc(p, param.typ, n) elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): initLocExpr(p, n, a) result = addrLoc(p.config, a) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 687254794..963ae9806 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -48,3 +48,20 @@ proc `=destroy`(x: var AObj) = echo "closed" var x = B(io: newStringStream("thestream")) + + +#------------------------------------------------------------------------------ +# issue #14003 + +proc cryptCTR*(nonce: var openArray[char]) = + nonce[1] = 'A' + +proc main() = + var nonce1 = "0123456701234567" + cryptCTR(nonce1) + doAssert(nonce1 == "0A23456701234567") + var nonce2 = "01234567" + cryptCTR(nonce2.toOpenArray(0, nonce2.len-1)) + doAssert(nonce2 == "0A234567") + +main() \ No newline at end of file From d839eb9352a6711fcdee23457605a1fa2e41f7d6 Mon Sep 17 00:00:00 2001 From: cooldome Date: Sat, 18 Apr 2020 15:15:17 +0100 Subject: [PATCH 0335/4254] fix #14007 (#14012) [backport] Co-authored-by: cooldome --- compiler/semfold.nim | 8 ++++++-- tests/types/tyet_another_generic_regression.nim | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 5e2c2bccc..931ff5554 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -722,7 +722,11 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = of nkBracketExpr: result = foldArrayAccess(m, n, g) of nkDotExpr: result = foldFieldAccess(m, n, g) of nkStmtListExpr: - if n.len == 2 and n[0].kind == nkComesFrom: - result = getConstExpr(m, n[1], g) + var i = 0 + while i <= n.len - 2: + if n[i].kind in {nkComesFrom, nkCommentStmt, nkEmpty}: i.inc + else: break + if i == n.len - 1: + result = getConstExpr(m, n[i], g) else: discard diff --git a/tests/types/tyet_another_generic_regression.nim b/tests/types/tyet_another_generic_regression.nim index 083993757..2e5f9bb23 100644 --- a/tests/types/tyet_another_generic_regression.nim +++ b/tests/types/tyet_another_generic_regression.nim @@ -30,3 +30,12 @@ const }.toTable #map["test"]() + +#------------------------------------------------------------------- +# bug +const val = 10 + +type + t = object + when val >= 10: + a: int From e3919b658fb6abaf3b58bbf813bed6f59bd4d1c9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 18 Apr 2020 07:22:03 -0700 Subject: [PATCH 0336/4254] fix https://github.com/nim-lang/RFCs/issues/211: `var a: DateTime` compiles and is usable (#14002) [backport:1.2] * fix https://github.com/nim-lang/RFCs/issues/211: `var a: DateTime` works * assertValidDate checks for sentinel month --- lib/pure/times.nim | 13 ++++++++++--- tests/stdlib/ttimes.nim | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index b9410e14c..2313afbff 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -260,6 +260,7 @@ type Month* = enum ## Represents a month. Note that the enum starts at ``1``, ## so ``ord(month)`` will give the month number in the ## range ``1..12``. + # mInvalid = (0, "Invalid") # intentionally left out so `items` works mJan = (1, "January") mFeb = "February" mMar = "March" @@ -296,7 +297,8 @@ when defined(nimHasStyleChecks): {.pop.} type - MonthdayRange* = range[1..31] + MonthdayRange* = range[0..31] + ## 0 represents an invalid day of the month HourRange* = range[0..23] MinuteRange* = range[0..59] SecondRange* = range[0..60] @@ -670,7 +672,7 @@ proc getDaysInYear*(year: int): int = proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline.} = - assert monthday <= getDaysInMonth(month, year), + assert monthday > 0 and monthday <= getDaysInMonth(month, year), $year & "-" & intToStr(ord(month), 2) & "-" & $monthday & " is not a valid date" @@ -1576,9 +1578,14 @@ proc `<=`*(a, b: DateTime): bool = ## Returns true if ``a`` happened before or at the same time as ``b``. return a.toTime <= b.toTime +proc isDefault[T](a: T): bool = + system.`==`(a, default(T)) + proc `==`*(a, b: DateTime): bool = ## Returns true if ``a`` and ``b`` represent the same point in time. - return a.toTime == b.toTime + if a.isDefault: b.isDefault + elif b.isDefault: false + else: a.toTime == b.toTime proc isStaticInterval(interval: TimeInterval): bool = interval.years == 0 and interval.months == 0 and diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 60e2ffdbe..a8da15f3d 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -614,6 +614,21 @@ suite "ttimes": doAssert x + between(x, y) == y doAssert between(x, y) == 1.months + 1.weeks + test "default DateTime": # https://github.com/nim-lang/RFCs/issues/211 + var num = 0 + for ai in Month: num.inc + doAssert num == 12 + + var a: DateTime + doAssert a == DateTime.default + doAssert ($a).len > 0 # no crash + doAssert a.month.Month.ord == 0 + doAssert a.month.Month == cast[Month](0) + doAssert a.monthday == 0 + + doAssertRaises(AssertionError): discard getDayOfWeek(a.monthday, a.month, a.year) + doAssertRaises(AssertionError): discard a.toTime + test "inX procs": doAssert initDuration(seconds = 1).inSeconds == 1 doAssert initDuration(seconds = -1).inSeconds == -1 From f46803b225afed53488ef69f84d8775fe8b3fbd3 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sat, 18 Apr 2020 18:41:03 +0300 Subject: [PATCH 0337/4254] Fix unused warning for `$` for empty tuple/objects (#13991) --- lib/system/dollars.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 664f1c30d..3414c6db1 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -75,7 +75,8 @@ proc `$`*[T: tuple|object](x: T): string = ## $(a: 23, b: 45) == "(a: 23, b: 45)" ## $() == "()" result = "(" - var firstElement = true + # when x is empty, this gives an unused warning + var firstElement {.used.} = true const isNamed = T is object or isNamedTuple(T) when not isNamed: var count = 0 From f1ee817627d10b246bc797420587f4d774b6ae29 Mon Sep 17 00:00:00 2001 From: jiro Date: Sun, 19 Apr 2020 03:06:20 +0900 Subject: [PATCH 0338/4254] Add runnableExamples to critbits module (#13994) * doc: critbit: add runnableExamples * doc: critbit: change to upper --- lib/pure/collections/critbits.nim | 244 +++++++++++++++++++++++++++--- 1 file changed, 219 insertions(+), 25 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 250042e7a..21354e0a8 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -34,7 +34,13 @@ type count: int proc len*[T](c: CritBitTree[T]): int = - ## returns the number of elements in `c` in O(1). + ## Returns the number of elements in `c` in O(1). + runnableExamples: + var c: CritBitTree[void] + incl(c, "key1") + incl(c, "key2") + doAssert c.len == 2 + result = c.count proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = @@ -48,11 +54,16 @@ proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = return if it.key == key: it else: nil proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = - ## returns true iff `c` contains the given `key`. + ## Returns true iff `c` contains the given `key`. + runnableExamples: + var c: CritBitTree[void] + incl(c, "key") + doAssert c.contains("key") + result = rawGet(c, key) != nil proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} = - ## alias for `contains`. + ## Alias for `contains <#contains,CritBitTree[T],string>`_. result = rawGet(c, key) != nil proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = @@ -130,20 +141,62 @@ proc exclImpl[T](c: var CritBitTree[T], key: string): int = return c.count proc excl*[T](c: var CritBitTree[T], key: string) = - ## removes `key` (and its associated value) from the set `c`. + ## Removes `key` (and its associated value) from the set `c`. ## If the `key` does not exist, nothing happens. + ## + ## See also: + ## * `incl proc <#incl,CritBitTree[void],string>`_ + ## * `incl proc <#incl,CritBitTree[T],string,T>`_ + runnableExamples: + var c: CritBitTree[void] + incl(c, "key") + excl(c, "key") + doAssert not c.contains("key") + discard exclImpl(c, key) proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = ## Returns true iff `c` does not contain the given `key`. If the key ## does exist, c.excl(key) is performed. + ## + ## See also: + ## * `excl proc <#excl,CritBitTree[T],string>`_ + ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ + ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ + runnableExamples: + block: + var c: CritBitTree[void] + doAssert c.missingOrExcl("key") + block: + var c: CritBitTree[void] + incl(c, "key") + doAssert not c.missingOrExcl("key") + doAssert not c.contains("key") + let oldCount = c.count discard exclImpl(c, key) result = c.count == oldCount proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = - ## returns true iff `c` contains the given `key`. If the key does not exist + ## Returns true iff `c` contains the given `key`. If the key does not exist ## ``c[key] = val`` is performed. + ## + ## See also: + ## * `incl proc <#incl,CritBitTree[void],string>`_ + ## * `incl proc <#incl,CritBitTree[T],string,T>`_ + ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ + ## * `missingOrExcl proc <#missingOrExcl,CritBitTree[T],string>`_ + runnableExamples: + block: + var c: CritBitTree[int] + doAssert not c.containsOrIncl("key", 42) + doAssert c.contains("key") + block: + var c: CritBitTree[int] + incl(c, "key", 21) + doAssert c.containsOrIncl("key", 42) + doAssert c["key"] == 21 + let oldCount = c.count var n = rawInsert(c, key) result = c.count == oldCount @@ -151,28 +204,77 @@ proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = if not result: n.val = val proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = - ## returns true iff `c` contains the given `key`. If the key does not exist + ## Returns true iff `c` contains the given `key`. If the key does not exist ## it is inserted into `c`. + ## + ## See also: + ## * `incl proc <#incl,CritBitTree[void],string>`_ + ## * `incl proc <#incl,CritBitTree[T],string,T>`_ + ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ + ## * `missingOrExcl proc <#missingOrExcl,CritBitTree[T],string>`_ + runnableExamples: + block: + var c: CritBitTree[void] + doAssert not c.containsOrIncl("key") + doAssert c.contains("key") + block: + var c: CritBitTree[void] + incl(c, "key") + doAssert c.containsOrIncl("key") + let oldCount = c.count discard rawInsert(c, key) result = c.count == oldCount proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = - ## increments `c[key]` by `val`. + ## Increments `c[key]` by `val`. + runnableExamples: + var c: CritBitTree[int] + c["key"] = 1 + inc(c, "key") + doAssert c["key"] == 2 + var n = rawInsert(c, key) inc n.val, val proc incl*(c: var CritBitTree[void], key: string) = - ## includes `key` in `c`. + ## Includes `key` in `c`. + ## + ## See also: + ## * `excl proc <#excl,CritBitTree[T],string>`_ + ## * `incl proc <#incl,CritBitTree[T],string,T>`_ + runnableExamples: + var c: CritBitTree[void] + incl(c, "key") + doAssert c.hasKey("key") + discard rawInsert(c, key) proc incl*[T](c: var CritBitTree[T], key: string, val: T) = - ## inserts `key` with value `val` into `c`. + ## Inserts `key` with value `val` into `c`. + ## + ## See also: + ## * `excl proc <#excl,CritBitTree[T],string>`_ + ## * `incl proc <#incl,CritBitTree[void],string>`_ + runnableExamples: + var c: CritBitTree[int] + incl(c, "key", 42) + doAssert c["key"] == 42 + var n = rawInsert(c, key) n.val = val proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = - ## puts a (key, value)-pair into `t`. + ## Puts a (key, value)-pair into `t`. + ## + ## See also: + ## * `[] proc <#[],CritBitTree[T],string>`_ + ## * `[] proc <#[],CritBitTree[T],string_2>`_ + runnableExamples: + var c: CritBitTree[int] + c["key"] = 42 + doAssert c["key"] == 42 + var n = rawInsert(c, key) n.val = val @@ -187,14 +289,22 @@ template get[T](c: CritBitTree[T], key: string): T = n.val proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = - ## retrieves the value at ``c[key]``. If `key` is not in `t`, the + ## Retrieves the value at ``c[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. + ## + ## See also: + ## * `[] proc <#[],CritBitTree[T],string_2>`_ + ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = - ## retrieves the value at ``c[key]``. The value can be modified. + ## Retrieves the value at ``c[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## + ## See also: + ## * `[] proc <#[],CritBitTree[T],string>`_ + ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) iterator leaves[T](n: Node[T]): Node[T] = @@ -211,29 +321,71 @@ iterator leaves[T](n: Node[T]): Node[T] = yield it iterator keys*[T](c: CritBitTree[T]): string = - ## yields all keys in lexicographical order. + ## Yields all keys in lexicographical order. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 1 + c["key2"] = 2 + var keys: seq[string] + for key in c.keys: + keys.add(key) + doAssert keys == @["key1", "key2"] + for x in leaves(c.root): yield x.key iterator values*[T](c: CritBitTree[T]): T = - ## yields all values of `c` in the lexicographical order of the + ## Yields all values of `c` in the lexicographical order of the ## corresponding keys. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 1 + c["key2"] = 2 + var vals: seq[int] + for val in c.values: + vals.add(val) + doAssert vals == @[1, 2] + for x in leaves(c.root): yield x.val iterator mvalues*[T](c: var CritBitTree[T]): var T = - ## yields all values of `c` in the lexicographical order of the + ## Yields all values of `c` in the lexicographical order of the ## corresponding keys. The values can be modified. + ## + ## See also: + ## * `values iterator <#values.i,CritBitTree[T]>`_ for x in leaves(c.root): yield x.val iterator items*[T](c: CritBitTree[T]): string = - ## yields all keys in lexicographical order. + ## Yields all keys in lexicographical order. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 1 + c["key2"] = 2 + var keys: seq[string] + for key in c.items: + keys.add(key) + doAssert keys == @["key1", "key2"] + for x in leaves(c.root): yield x.key iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] = - ## yields all (key, value)-pairs of `c`. + ## Yields all (key, value)-pairs of `c`. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 1 + c["key2"] = 2 + var ps: seq[tuple[key: string, val: int]] + for p in c.pairs: + ps.add(p) + doAssert ps == @[(key: "key1", val: 1), (key: "key2", val: 2)] + for x in leaves(c.root): yield (x.key, x.val) iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] = - ## yields all (key, value)-pairs of `c`. The yielded values can be modified. + ## Yields all (key, value)-pairs of `c`. The yielded values can be modified. + ## + ## See also: + ## * `pairs iterator <#pairs.i,CritBitTree[T]>`_ for x in leaves(c.root): yield (x.key, x.val) proc allprefixedAux[T](c: CritBitTree[T], key: string; @@ -254,48 +406,90 @@ proc allprefixedAux[T](c: CritBitTree[T], key: string; iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): string = - ## yields all keys starting with `prefix`. If `longestMatch` is true, + ## Yields all keys starting with `prefix`. If `longestMatch` is true, ## the longest match is returned, it doesn't have to be a complete match then. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 42 + c["key2"] = 43 + var keys: seq[string] + for key in c.itemsWithPrefix("key"): + keys.add(key) + doAssert keys == @["key1", "key2"] + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.key iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): string = - ## yields all keys starting with `prefix`. + ## Yields all keys starting with `prefix`. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 42 + c["key2"] = 43 + var keys: seq[string] + for key in c.keysWithPrefix("key"): + keys.add(key) + doAssert keys == @["key1", "key2"] + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.key iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): T = - ## yields all values of `c` starting with `prefix` of the + ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 42 + c["key2"] = 43 + var vals: seq[int] + for val in c.valuesWithPrefix("key"): + vals.add(val) + doAssert vals == @[42, 43] + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.val iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string; longestMatch = false): var T = - ## yields all values of `c` starting with `prefix` of the + ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. The values can be modified. + ## + ## See also: + ## * `valuesWithPrefix iterator <#valuesWithPrefix.i,CritBitTree[T],string>`_ let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.val iterator pairsWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): tuple[key: string, val: T] = - ## yields all (key, value)-pairs of `c` starting with `prefix`. + ## Yields all (key, value)-pairs of `c` starting with `prefix`. + runnableExamples: + var c: CritBitTree[int] + c["key1"] = 42 + c["key2"] = 43 + var ps: seq[tuple[key: string, val: int]] + for p in c.pairsWithPrefix("key"): + ps.add(p) + doAssert ps == @[(key: "key1", val: 42), (key: "key2", val: 43)] + let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) iterator mpairsWithPrefix*[T](c: var CritBitTree[T], prefix: string; longestMatch = false): tuple[key: string, val: var T] = - ## yields all (key, value)-pairs of `c` starting with `prefix`. + ## Yields all (key, value)-pairs of `c` starting with `prefix`. ## The yielded values can be modified. + ## + ## See also: + ## * `pairsWithPrefix iterator <#pairsWithPrefix.i,CritBitTree[T],string>`_ let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) proc `$`*[T](c: CritBitTree[T]): string = - ## turns `c` into a string representation. Example outputs: + ## Turns `c` into a string representation. Example outputs: ## ``{keyA: value, keyB: value}``, ``{:}`` ## If `T` is void the outputs look like: ## ``{keyA, keyB}``, ``{}``. From a8f030fea21894e51c188a5804b0bbf787335f4d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Apr 2020 02:41:16 +0200 Subject: [PATCH 0339/4254] drnim: phi nodes for 'if' statements (#13990) --- drnim/drnim.nim | 164 +++++++++++++++++++++++++++++++++++++++---- drnim/tests/tphi.nim | 23 ++++++ 2 files changed, 172 insertions(+), 15 deletions(-) create mode 100644 drnim/tests/tphi.nim diff --git a/drnim/drnim.nim b/drnim/drnim.nim index 7c79add26..6c08bed42 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -65,11 +65,13 @@ type graph: ModuleGraph facts: seq[(PNode, VersionScope)] varVersions: seq[int] # this maps variable IDs to their current version. + varSyms: seq[PSym] # mirrors 'varVersions' o: Operators hasUnstructedCf: int currOptions: TOptions owner: PSym mangler: seq[PSym] + opImplies: PSym DrCon = object graph: ModuleGraph @@ -126,8 +128,17 @@ proc isLoc(m: PNode; assumeUniqueness: bool): bool = else: discard -proc varVersion(c: DrnimContext; s: PSym; begin: VersionScope): int = +proc currentVarVersion(c: DrnimContext; s: PSym; begin: VersionScope): int = + # we need to take into account both en- and disabled var bindings here, + # hence the 'abs' call: result = 0 + for i in countdown(int(begin)-1, 0): + if abs(c.varVersions[i]) == s.id: inc result + +proc previousVarVersion(c: DrnimContext; s: PSym; begin: VersionScope): int = + # we need to ignore currently disabled var bindings here, + # hence no 'abs' call here. + result = -1 for i in countdown(int(begin)-1, 0): if c.varVersions[i] == s.id: inc result @@ -156,15 +167,30 @@ proc stableName(result: var string; c: DrnimContext; n: PNode; version: VersionS if d != 0: result.add "`scope=" result.addInt d - let v = c.varVersion(n.sym, version) - ord(isOld) - assert v >= 0 + let v = if isOld: c.previousVarVersion(n.sym, version) + else: c.currentVarVersion(n.sym, version) if v > 0: result.add '`' result.addInt v else: result.add "`magic=" result.addInt ord(n.sym.magic) - + of nkBindStmt: + # we use 'bind x 3' to use the 3rd version of variable 'x'. This + # is easier than using 'old' which is position relative. + assert n.len == 2 + assert n[0].kind == nkSym + assert n[1].kind == nkIntLit + let s = n[0].sym + let v = int(n[1].intVal) + result.add s.name.s + let d = disamb(c, s) + if d != 0: + result.add "`scope=" + result.addInt d + if v > 0: + result.add '`' + result.addInt v of nkCharLit..nkUInt64Lit: result.addInt n.intVal of nkFloatLit..nkFloat64Lit: @@ -700,7 +726,8 @@ proc compatibleProps(graph: ModuleGraph; formal, actual: PType): bool {.nimcall. c.graph = graph c.canonParameterNames = true try: - c.up = DrnimContext(z3: setupZ3(), o: initOperators(graph), graph: graph, owner: nil) + c.up = DrnimContext(z3: setupZ3(), o: initOperators(graph), graph: graph, owner: nil, + opImplies: createMagic(graph, "->", mImplies)) template zero: untyped = VersionScope(0) if not frequires.isEmpty: result = not arequires.isEmpty and proofEngineAux(c, @[(frequires, zero)], (arequires, zero))[0] @@ -721,14 +748,22 @@ template config(c: typed): untyped = c.graph.config proc addFact(c: DrnimContext; n: PNode) = let v = c.currentScope if n[0].kind == nkSym and n[0].sym.magic in {mOr, mAnd}: - c.facts.add((n[1], v)) + c.addFact(n[1]) c.facts.add((n, v)) +proc neg(c: DrnimContext; n: PNode): PNode = + result = newNodeI(nkCall, n.info, 2) + result[0] = newSymNode(c.o.opNot) + result[1] = n + proc addFactNeg(c: DrnimContext; n: PNode) = - var neg = newNodeI(nkCall, n.info, 2) - neg[0] = newSymNode(c.o.opNot) - neg[1] = n - addFact(c, neg) + addFact(c, neg(c, n)) + +proc combineFacts(c: DrnimContext; a, b: PNode): PNode = + if a == nil: + result = b + else: + result = buildCall(c.o.opAnd, a, b) proc prove(c: DrnimContext; prop: PNode): bool = let (success, m) = proofEngine(c, c.facts, (prop, c.currentScope)) @@ -745,6 +780,8 @@ proc traversePragmaStmt(c: DrnimContext, n: PNode) = elif pragma == wInvariant or pragma == wAssert: if prove(c, it[1]): addFact(c, it[1]) + else: + echoFacts(c) proc requiresCheck(c: DrnimContext, call: PNode; op: PType) = assert op.n[0].kind == nkEffectList @@ -761,6 +798,7 @@ proc freshVersion(c: DrnimContext; arg: PNode) = let v = getRoot(arg) if v != nil: c.varVersions.add v.id + c.varSyms.add v proc translateEnsuresFromCall(c: DrnimContext, e, call: PNode): PNode = if e.kind in nkCallKinds and e[0].kind == nkSym and e[0].sym.magic == mOld: @@ -837,23 +875,118 @@ proc traverseCase(c: DrnimContext; n: PNode) = # XXX make this as smart as 'if elif' setLen(c.facts, oldFacts) +proc disableVarVersions(c: DrnimContext; until: int) = + for i in until.. (x'3 == x'1)) and + ((not a and b) -> (x'3 == x'2)) and + ((not a and not b) -> (x'3 == x'0)) + + (Where ``->`` is the logical implication.) + + In addition to the Phi information we also know the 'facts' + computed by the branches, for example:: + + if a: + factA + elif b: + factB + else: + factC + + (a -> factA) and + ((not a and b) -> factB) and + ((not a and not b) -> factC) + + We can combine these two aspects by producing the following facts + after each branch:: + + var x = y # x'0 + if a: + inc x # x'1 == x'0 + 1 + # also: x'1 == x'final + elif b: + inc x, 2 # x'2 == x'0 + 2 + # also: x'2 == x'final + else: + # also: x'0 == x'final + + ]# let oldFacts = c.facts.len - addFact(c, n[0][0]) + let oldVars = c.varVersions.len + var newFacts: seq[PNode] + var branches = newSeq[(PNode, int)](n.len) # (cond, newVars) pairs + template condVersion(): untyped = VersionScope(oldVars) - traverse(c, n[0][1]) - - for i in 1.. 1: addFact(c, branch[0]) + cond = combineFacts(c, cond, branch[0]) + for i in 0..", mImplies) try: traverse(c, n) ensuresCheck(c, owner) diff --git a/drnim/tests/tphi.nim b/drnim/tests/tphi.nim new file mode 100644 index 000000000..7ff49f4dc --- /dev/null +++ b/drnim/tests/tphi.nim @@ -0,0 +1,23 @@ +discard """ + nimout: '''tphi.nim(9, 10) Warning: BEGIN [User] +tphi.nim(22, 10) Warning: END [User]''' + cmd: "drnim $file" + action: "compile" +""" +import std/logic +{.push staticBoundChecks: defined(nimDrNim).} +{.warning: "BEGIN".} + +proc testAsgn(y: int) = + var a = y + if a > 0: + if a > 3: + a = a + 2 + else: + a = a + 1 + {.assert: a > 1.} + +testAsgn(3) + +{.warning: "END".} +{.pop.} From 4005f0d0e40fb57efd8144c065a7ba56d940b572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Sun, 19 Apr 2020 07:52:01 +0200 Subject: [PATCH 0340/4254] forward type alignment information to seqs (#12430) --- compiler/ccgexprs.nim | 20 +++++------ compiler/ccgtypes.nim | 16 ++++----- compiler/condsyms.nim | 1 + lib/core/typeinfo.nim | 17 ++++++---- lib/nimbase.h | 3 +- lib/pure/includes/osenv.nim | 3 +- lib/system.nim | 12 +++++-- lib/system/alloc.nim | 17 ++++++---- lib/system/assign.nim | 11 +++--- lib/system/channels.nim | 11 +++--- lib/system/deepcopy.nim | 5 ++- lib/system/gc.nim | 15 ++++---- lib/system/gc2.nim | 13 +++---- lib/system/gc_common.nim | 7 ++-- lib/system/gc_ms.nim | 15 ++++---- lib/system/gc_regions.nim | 5 +-- lib/system/hti.nim | 1 + lib/system/mm/boehm.nim | 6 ++-- lib/system/mm/go.nim | 11 +++--- lib/system/mm/none.nim | 2 +- lib/system/mmdisp.nim | 4 +-- lib/system/repr.nim | 4 +-- lib/system/seqs_v2.nim | 16 ++++----- lib/system/sysstr.nim | 34 ++++++++----------- .../collections/thardalignmentconstraint.nim | 17 ++++++++++ 25 files changed, 152 insertions(+), 114 deletions(-) create mode 100644 tests/collections/thardalignmentconstraint.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index d8f5d016b..6c70ce798 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1301,9 +1301,10 @@ proc genNewSeq(p: BProc, e: PNode) = initLocExpr(p, e[2], b) if optSeqDestructors in p.config.globalOptions: let seqtype = skipTypes(e[1].typ, abstractVarRange) - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", - [a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype)]) + linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", + [a.rdLoc, b.rdLoc, + getTypeDesc(p.module, seqtype.lastSon), + getSeqPayloadType(p.module, seqtype)]) else: let lenIsZero = optNilSeqs notin p.options and e[2].kind == nkIntLit and e[2].intVal == 0 @@ -1316,9 +1317,10 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = initLocExpr(p, e[1], a) if optSeqDestructors in p.config.globalOptions: if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) - linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", + linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype)]) + getSeqPayloadType(p.module, seqtype), + ]) else: putIntoDest(p, d, e, ropecg(p.module, "($1)#nimNewSeqOfCap($2, $3)", [ @@ -1425,7 +1427,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = let l = intLiteral(n.len) if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", + linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", [rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon), getSeqPayloadType(p.module, seqtype)]) else: @@ -1456,7 +1458,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = let L = toInt(lengthOrd(p.config, n[1].typ)) if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", + linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", [rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon), getSeqPayloadType(p.module, seqtype)]) else: @@ -2224,9 +2226,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)]) of mAlignOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - if not p.module.compileToCpp: - p.module.includeHeader("") - putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)]) + putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)]) of mOffsetOf: var dotExpr: PNode block findDotExpr: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index f939eb326..b116a9aa6 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -999,11 +999,14 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; let nameHcr = tiNameForHcr(m, name) var size: Rope - if tfIncompleteStruct in typ.flags: size = rope"void*" - else: size = getTypeDesc(m, origType) + if tfIncompleteStruct in typ.flags: + size = rope"void*" + else: + size = getTypeDesc(m, origType) m.s[cfsTypeInit3].addf( - "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", - [nameHcr, size, rope(nimtypeKind), base]) + "$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($2);$n$1.kind = $3;$n$1.base = $4;$n", + [nameHcr, size, rope(nimtypeKind), base] + ) # compute type flags for GC optimization var flags = 0 if not containsGarbageCollectedRef(typ): flags = flags or 1 @@ -1313,10 +1316,7 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) let traceImpl = genHook(m, t, info, attachedTrace) let disposeImpl = genHook(m, t, info, attachedDispose) - m.s[cfsTypeInit3].addf("$1.destructor = (void*)$2; $1.size = sizeof($3);$n" & - "$1.name = $4;$n" & - "$1.traceImpl = (void*)$5;$n" & - "$1.disposeImpl = (void*)$6;$n", [ + addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6;", [ name, destroyImpl, getTypeDesc(m, t), typeName, traceImpl, disposeImpl]) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 4fc882ab7..5333e639c 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -102,6 +102,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimnomagic64") defineSymbol("nimNewShiftOps") defineSymbol("nimHasCursor") + defineSymbol("nimAlignPragma") defineSymbol("nimHasExceptionsQuery") defineSymbol("nimHasIsNamedTuple") defineSymbol("nimHashOrdinalFixed") diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index d8bbfb642..7321c8570 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -12,15 +12,15 @@ ## what this module allows you to do. ## ## Note that even though ``Any`` and its operations hide the nasty low level -## details from its clients, it remains inherently unsafe! Also, Nim's +## details from its clients, it remains inherently unsafe! Also, Nim's ## runtime type information will evolve and may eventually be deprecated. ## As an alternative approach to programmatically understanding and ## manipulating types, consider using the `macros `_ package to ## work with the types' AST representation at compile time. See, for example, -## the `getTypeImpl proc`_. As an alternative +## the `getTypeImpl proc`_. As an alternative ## approach to storing arbitrary types at runtime, consider using generics. ## -## +## {.push hints: off.} @@ -98,7 +98,7 @@ else: proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.} proc genericShallowAssign(dest, src: pointer, mt: PNimType) {. importCompilerProc.} -proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importCompilerProc.} +proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.} proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.} proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.} proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.} @@ -180,7 +180,7 @@ proc extendSeq*(x: Any) = ## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``. assert x.rawType.kind == tySequence var y = cast[ptr PGenSeq](x.value)[] - var z = incrSeq(y, x.rawType.base.size) + var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align) # 'incrSeq' already freed the memory for us and copied over the RC! # So we simply copy the raw pointer into 'x.value': cast[ppointer](x.value)[] = z @@ -195,6 +195,9 @@ proc skipRange(x: PNimType): PNimType {.inline.} = result = x if result.kind == tyRange: result = result.base +proc align(address, alignment: int): int = + result = (address + (alignment - 1)) and not (alignment - 1) + proc `[]`*(x: Any, i: int): Any = ## accessor for an any `x` that represents an array or a sequence. case x.rawType.kind @@ -209,7 +212,7 @@ proc `[]`*(x: Any, i: int): Any = var bs = x.rawType.base.size if i >=% cast[PGenSeq](s).len: raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1)) - return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base) + return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base) else: assert false proc `[]=`*(x: Any, i: int, y: Any) = @@ -228,7 +231,7 @@ proc `[]=`*(x: Any, i: int, y: Any) = if i >=% cast[PGenSeq](s).len: raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1)) assert y.rawType == x.rawType.base - genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType) + genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType) else: assert false proc len*(x: Any): int = diff --git a/lib/nimbase.h b/lib/nimbase.h index 04cf146a8..d4fa10050 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -477,7 +477,6 @@ typedef char* NCSTRING; #define ALLOC_0(size) calloc(1, size) #define DL_ALLOC_0(size) dlcalloc(1, size) -#define GenericSeqSize sizeof(TGenericSeq) #define paramCount() cmdCount // NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0 @@ -546,8 +545,10 @@ NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, "" #if defined(_MSC_VER) # define NIM_ALIGN(x) __declspec(align(x)) +# define NIM_ALIGNOF(x) __alignof(x) #else # define NIM_ALIGN(x) __attribute__((aligned(x))) +# define NIM_ALIGNOF(x) __alignof__(x) #endif /* ---------------- platform specific includes ----------------------- */ diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index e06c4bc49..01abf12df 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -93,8 +93,7 @@ else: when useNSGetEnviron: var gEnv = NSGetEnviron()[] var i = 0 - while true: - if gEnv[i] == nil: break + while gEnv[i] != nil: add environment, $gEnv[i] inc(i) envComputed = true diff --git a/lib/system.nim b/lib/system.nim index f9ebe26b4..221a538b1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -514,6 +514,7 @@ when not defined(js) and not defined(nimSeqsV2): len, reserved: int when defined(gogc): elemSize: int + elemAlign: int PGenericSeq {.exportc.} = ptr TGenericSeq # len and space without counting the terminating zero: NimStringDesc {.compilerproc, final.} = object of TGenericSeq @@ -1123,6 +1124,13 @@ elif hostOS != "standalone": var programResult* {.compilerproc, exportc: "nim_program_result".}: int ## deprecated, prefer ``quit`` +proc align(address, alignment: int): int = + if alignment == 0: # Actually, this is illegal. This branch exists to actively + # hide problems. + result = address + else: + result = (address + (alignment - 1)) and not (alignment - 1) + when defined(nimdoc): proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} ## Stops the program immediately with an exit code. @@ -1698,6 +1706,7 @@ when not defined(js) and defined(nimV2): TNimType {.compilerproc.} = object destructor: pointer size: int + align: int name: cstring traceImpl: pointer disposeImpl: pointer @@ -1709,7 +1718,6 @@ when notJSnotNims and defined(nimSeqsV2): {.pop.} - when notJSnotNims: proc writeStackTrace*() {.tags: [], gcsafe, raises: [].} ## Writes the current stack trace to ``stderr``. This is only works @@ -1988,8 +1996,8 @@ proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} = result = if x < 0: -x else: x {.pop.} - when not defined(js): + proc likelyProc(val: bool): bool {.importc: "NIM_LIKELY", nodecl, noSideEffect.} proc unlikelyProc(val: bool): bool {.importc: "NIM_UNLIKELY", nodecl, noSideEffect.} diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 95d5ae7ee..7ace0d536 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -45,7 +45,6 @@ type data: TrunkBuckets type - AlignType = BiggestFloat FreeCell {.final, pure.} = object next: ptr FreeCell # next free cell in chunk (overlaid with refcount) when not defined(gcDestructors): @@ -68,16 +67,20 @@ type freeList: ptr FreeCell free: int # how many bytes remain acc: int # accumulator for small object allocation - when defined(cpu32): - align: int - data: AlignType # start of usable memory + when defined(nimAlignPragma): + data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory + else: + data: UncheckedArray[byte] BigChunk = object of BaseChunk # not necessarily > PageSize! next, prev: PBigChunk # chunks of the same (or bigger) size - data: AlignType # start of usable memory + when defined(nimAlignPragma): + data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory + else: + data: UncheckedArray[byte] -template smallChunkOverhead(): untyped = sizeof(SmallChunk)-sizeof(AlignType) -template bigChunkOverhead(): untyped = sizeof(BigChunk)-sizeof(AlignType) +template smallChunkOverhead(): untyped = sizeof(SmallChunk) +template bigChunkOverhead(): untyped = sizeof(BigChunk) # ------------- chunk table --------------------------------------------------- # We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 39ff9d743..eed7bc6db 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -66,17 +66,16 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = cast[PGenericSeq](ss).len = seq.len unsureAsgnRef(x, ss) var dst = cast[ByteAddress](cast[PPointer](dest)[]) - copyMem(cast[pointer](dst +% GenericSeqSize), - cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize), - seq.len * mt.base.size) + copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)), + seq.len *% mt.base.size) else: unsureAsgnRef(x, newSeq(mt, seq.len)) var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericAssignAux( - cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), - cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% - GenericSeqSize), + cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), mt.base, shallow) of tyObject: var it = mt.base diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 65398d65c..5966d9fee 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -214,7 +214,7 @@ when not usesDestructors: x[] = nil else: var ss = cast[NimString](s2) - var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize)) + var ns = cast[NimString](alloc(t.region, GenericSeqSize + ss.len+1)) copyMem(ns, ss, ss.len+1 + GenericSeqSize) x[] = ns else: @@ -239,7 +239,7 @@ when not usesDestructors: else: sysAssert(dest != nil, "dest == nil") if mode == mStore: - x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize) + x[] = alloc0(t.region, align(GenericSeqSize, mt.base.align) +% seq.len *% mt.base.size) else: unsureAsgnRef(x, newSeq(mt, seq.len)) var dst = cast[ByteAddress](cast[PPointer](dest)[]) @@ -248,9 +248,9 @@ when not usesDestructors: dstseq.reserved = seq.len for i in 0..seq.len-1: storeAux( - cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), - cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% - GenericSeqSize), + cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i*% mt.base.size), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% + i *% mt.base.size), mt.base, t, mode) if mode != mStore: dealloc(t.region, s2) of tyObject: @@ -452,4 +452,3 @@ proc ready*[TMsg](c: var Channel[TMsg]): bool = ## new messages. var q = cast[PRawChannel](addr(c)) result = q.ready - diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 66a65cd34..801821d26 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -108,9 +108,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericDeepCopyAux( - cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), - cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% - GenericSeqSize), + cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), mt.base, tab) of tyObject: # we need to copy m_type field for tyObject, as it could be empty for diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 15f316ccc..690230767 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -339,8 +339,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% - GenericSeqSize), cell.typ.base, op) + forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) else: discard proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} = @@ -444,7 +443,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = len * typ.base.size + GenericSeqSize + let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len @@ -480,7 +479,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = {.push overflowChecks: on.} proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = len * typ.base.size + GenericSeqSize + let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size result = newObjRC1(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len @@ -495,11 +494,13 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = sysAssert(allocInv(gch.region), "growObj begin") var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize = 1 - if ol.typ.kind != tyString: elemSize = ol.typ.base.size + var elemSize,elemAlign = 1 + if ol.typ.kind != tyString: + elemSize = ol.typ.base.size + elemAlign = ol.typ.base.align incTypeSize ol.typ, newsize - var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len * elemSize copyMem(res, ol, oldsize + sizeof(Cell)) zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)), newsize-oldsize) diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index 4da9b4f94..09388b6e8 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -291,8 +291,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% - GenericSeqSize), cell.typ.base, op) + forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) else: discard {.push stackTrace: off, profiler:off.} @@ -359,7 +358,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + let size = addInt(align(GenericSeqSize, typ.base.align), mulInt(len, typ.base.size)) result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len @@ -378,11 +377,13 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize = 1 - if ol.typ.kind != tyString: elemSize = ol.typ.base.size + var elemSize, elemAlign = 1 + if ol.typ.kind != tyString: + elemSize = ol.typ.base.size + elemAlign = ol.typ.base.align incTypeSize ol.typ, newsize - var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize copyMem(res, ol, oldsize + sizeof(Cell)) zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), newsize-oldsize) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index ff2b6ad6a..d75ada791 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -78,8 +78,11 @@ template decTypeSize(cell, t) = when defined(nimTypeNames): if t.kind in {tyString, tySequence}: let cap = cast[PGenericSeq](cellToUsr(cell)).space - let size = if t.kind == tyString: cap+1+GenericSeqSize - else: cap * t.base.size + GenericSeqSize + let size = + if t.kind == tyString: + cap + 1 + GenericSeqSize + else: + align(GenericSeqSize, t.base.align) + cap * t.base.size atomicDec t.sizes, size+sizeof(Cell) else: atomicDec t.sizes, t.base.size+sizeof(Cell) diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index a026b404b..a3b163a67 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -259,8 +259,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% - GenericSeqSize), cell.typ.base, op) + forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) else: discard proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = @@ -308,14 +307,14 @@ when not defined(nimSeqsV2): {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. - let size = len * typ.base.size + GenericSeqSize + let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = len * typ.base.size + GenericSeqSize + let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size result = newObj(typ, size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len @@ -329,11 +328,13 @@ when not defined(nimSeqsV2): gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize = 1 - if ol.typ.kind != tyString: elemSize = ol.typ.base.size + var elemSize, elemAlign = 1 + if ol.typ.kind != tyString: + elemSize = ol.typ.base.size + elemAlign = ol.typ.base.align incTypeSize ol.typ, newsize - var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize copyMem(res, ol, oldsize + sizeof(Cell)) zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), newsize-oldsize) diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index 7dab50072..4f802c812 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -321,7 +321,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = roundup(len * typ.base.size + GenericSeqSize, MemAlign) + let size = roundup(align(GenericSeqSize, typ.base.align) + len * typ.base.size, MemAlign) result = rawNewSeq(tlRegion, typ, size) zeroMem(result, size) cast[PGenericSeq](result).len = len @@ -348,7 +348,8 @@ proc growObj(regionUnused: var MemRegion; old: pointer, newsize: int): pointer = result = rawNewSeq(sh.region[], typ, roundup(newsize, MemAlign)) let elemSize = if typ.kind == tyString: 1 else: typ.base.size - let oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + let elemAlign = if typ.kind == tyString: 1 else: typ.base.align + let oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize zeroMem(result +! oldsize, newsize-oldsize) copyMem(result, old, oldsize) dealloc(sh.region[], old, roundup(oldsize, MemAlign)) diff --git a/lib/system/hti.nim b/lib/system/hti.nim index c20f132fb..63c1a5448 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -90,6 +90,7 @@ type when defined(gcHooks): head*: pointer size*: int + align*: int kind: TNimKind flags: set[TNimTypeFlag] base*: ptr TNimType diff --git a/lib/system/mm/boehm.nim b/lib/system/mm/boehm.nim index a8b0e17b4..b1afe59fc 100644 --- a/lib/system/mm/boehm.nim +++ b/lib/system/mm/boehm.nim @@ -1,4 +1,6 @@ + + proc boehmGCinit {.importc: "GC_init", boehmGC.} proc boehmGC_disable {.importc: "GC_disable", boehmGC.} proc boehmGC_enable {.importc: "GC_enable", boehmGC.} @@ -96,6 +98,7 @@ proc initGC() = proc boehmgc_finalizer(obj: pointer, typedFinalizer: (proc(x: pointer) {.cdecl.})) = typedFinalizer(obj) + proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = if ntfNoRefs in typ.flags: result = allocAtomic(size) else: result = alloc(size) @@ -103,7 +106,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = boehmRegisterFinalizer(result, boehmgc_finalizer, typ.finalizer, nil, nil) {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, len * typ.base.size + GenericSeqSize) + result = newObj(typ, align(GenericSeqSize, typ.base.align) + len * typ.base.size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len {.pop.} @@ -135,4 +138,3 @@ proc deallocOsPages(r: var MemRegion) {.inline.} = discard proc deallocOsPages() {.inline.} = discard include "system/cellsets" - diff --git a/lib/system/mm/go.nim b/lib/system/mm/go.nim index 8e8558bea..b6d5a1a44 100644 --- a/lib/system/mm/go.nim +++ b/lib/system/mm/go.nim @@ -101,28 +101,32 @@ proc newObjNoInit(typ: PNimType, size: int): pointer = writebarrierptr(addr(result), newObj(typ, size)) proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - writebarrierptr(addr(result), newObj(typ, len * typ.base.size + GenericSeqSize)) + writebarrierptr(addr(result), newObj(typ, align(GenericSeqSize, typ.base.align) + len * typ.base.size)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len cast[PGenericSeq](result).elemSize = typ.base.size + cast[PGenericSeq](result).elemAlign = typ.base.align proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = writebarrierptr(addr(result), newSeq(typ, len)) proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = - result = newObj(typ, cap * typ.base.size + GenericSeqSize) + result = newObj(typ, align(GenericSeqSize, typ.base.align) + cap * typ.base.size) cast[PGenericSeq](result).len = 0 cast[PGenericSeq](result).reserved = cap cast[PGenericSeq](result).elemSize = typ.base.size + cast[PGenericSeq](result).elemAlign = typ.base.align proc typedMemMove(dest: pointer, src: pointer, size: uint) {.importc: "typedmemmove", dynlib: goLib.} proc growObj(old: pointer, newsize: int): pointer = # the Go GC doesn't have a realloc + let old = cast[PGenericSeq](old) var metadataOld = cast[PGenericSeq](old) if metadataOld.elemSize == 0: metadataOld.elemSize = 1 - let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize + + let oldsize = align(GenericSeqSize, old.elemAlign) + old.len * old.elemSize writebarrierptr(addr(result), goMalloc(newsize.uint)) typedMemMove(result, old, oldsize.uint) @@ -149,4 +153,3 @@ proc alloc0(r: var MemRegion, size: int): pointer = proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) proc deallocOsPages(r: var MemRegion) {.inline.} = discard proc deallocOsPages() {.inline.} = discard - diff --git a/lib/system/mm/none.nim b/lib/system/mm/none.nim index 0079daac3..7818a0805 100644 --- a/lib/system/mm/none.nim +++ b/lib/system/mm/none.nim @@ -21,7 +21,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer = {.push overflowChecks: on.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, len * typ.base.size + GenericSeqSize) + result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len {.pop.} diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 2c3394df9..1cdf37604 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -46,7 +46,7 @@ const PageSize = 1 shl PageShift PageMask = PageSize-1 - MemAlign = 8 # also minimal allocatable memory block + MemAlign = 16 # also minimal allocatable memory block BitsPerPage = PageSize div MemAlign UnitsPerPage = BitsPerPage div (sizeof(int)*8) @@ -108,7 +108,7 @@ when not declared(nimNewSeqOfCap) and not defined(nimSeqsV2): let s = cap * typ.base.size # newStr already adds GenericSeqSize result = newStr(typ, s, ntfNoRefs notin typ.base.flags) else: - let s = cap * typ.base.size + GenericSeqSize + let s = align(GenericSeqSize, typ.base.align) + cap * typ.base.size when declared(newObjNoInit): result = if ntfNoRefs in typ.base.flags: newObjNoInit(typ, s) else: newObj(typ, s) else: diff --git a/lib/system/repr.nim b/lib/system/repr.nim index cc5ba2fee..526839aa2 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -172,7 +172,7 @@ when not defined(useNimRtl): template payloadPtr(x: untyped): untyped = cast[PGenericSeq](x).p else: - const payloadOffset = GenericSeqSize + const payloadOffset = GenericSeqSize ## the payload offset always depends on the alignment of the member type. template payloadPtr(x: untyped): untyped = x proc reprSequence(result: var string, p: pointer, typ: PNimType, @@ -185,7 +185,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..cast[PGenericSeq](p).len-1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[ByteAddress](payloadPtr(p)) + payloadOffset + i*bs), + reprAux(result, cast[pointer](cast[ByteAddress](payloadPtr(p)) + align(payloadOffset, typ.align) + i*bs), typ.base, cl) add result, "]" diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 3bd5e291b..097ab269c 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -31,27 +31,27 @@ const nimSeqVersion {.core.} = 2 # XXX make code memory safe for overflows in '*' -proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} = +proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises: [].} = # we have to use type erasure here as Nim does not support generic # compilerProcs. Oh well, this will all be inlined anyway. if cap > 0: - var p = cast[ptr NimSeqPayloadBase](allocShared0(cap * elemSize + sizeof(NimSeqPayloadBase))) + var p = cast[ptr NimSeqPayloadBase](allocShared0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize)) p.cap = cap result = p else: result = nil -proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {. +proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. noSideEffect, raises: [].} = {.noSideEffect.}: template `+!`(p: pointer, s: int): pointer = cast[pointer](cast[int](p) +% s) - const headerSize = sizeof(NimSeqPayloadBase) + let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign) if addlen <= 0: result = p elif p == nil: - result = newSeqPayload(len+addlen, elemSize) + result = newSeqPayload(len+addlen, elemSize, elemAlign) else: # Note: this means we cannot support things that have internal pointers as # they get reallocated here. This needs to be documented clearly. @@ -87,7 +87,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = if newLen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr x) if xu.p == nil or xu.p.cap < newLen: - xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T))) + xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T), alignof(T))) xu.len = newLen for i in oldLen .. newLen-1: xu.p.data[i] = value @@ -102,7 +102,7 @@ proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffec let oldLen = x.len var xu = cast[ptr NimSeqV2[T]](addr x) if xu.p == nil or xu.p.cap < oldLen+1: - xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T))) + xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T), alignof(T))) xu.len = oldLen+1 # .nodestroy means `xu.p.data[oldLen] = value` is compiled into a # copyMem(). This is fine as know by construction that @@ -119,5 +119,5 @@ proc setLen[T](s: var seq[T], newlen: Natural) = if newlen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr s) if xu.p == nil or xu.p.cap < newlen: - xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T))) + xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T))) xu.len = newlen diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 853397e0a..dbf9bcf06 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -245,7 +245,7 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = # ----------------- sequences ---------------------------------------------- -proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} = +proc incrSeq(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} = # increments the length by one: # this is needed for supporting ``add``; # @@ -255,18 +255,16 @@ proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} = result = seq if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, elemSize * r + - GenericSeqSize)) + result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) result.reserved = r inc(result.len) -proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} = +proc incrSeqV2(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} = # incrSeq version 2 result = seq if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, elemSize * r + - GenericSeqSize)) + result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) result.reserved = r template `+!`(p: pointer, s: int): pointer = @@ -283,21 +281,19 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} = when defined(nimIncrSeqV3): result = cast[PGenericSeq](newSeq(typ, r)) result.len = s.len - copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size) + copyMem(result +! align(GenericSeqSize, typ.base.align), s +! align(GenericSeqSize, typ.base.align), s.len * typ.base.size) # since we steal the content from 's', it's crucial to set s's len to 0. s.len = 0 else: - result = cast[PGenericSeq](growObj(result, typ.base.size * r + - GenericSeqSize)) + result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, typ.base.align) + typ.base.size * r)) result.reserved = r -proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. +proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericSeq {. compilerRtl, inl.} = result = seq if result.space < newLen: let r = max(resize(result.space), newLen) - result = cast[PGenericSeq](growObj(result, elemSize * r + - GenericSeqSize)) + result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) result.reserved = r elif newLen < result.len: # we need to decref here, otherwise the GC leaks! @@ -307,8 +303,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. when false: # compileOption("gc", "v2"): for i in newLen..result.len-1: let len0 = gch.tempStack.len - forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% - GenericSeqSize +% (i*%elemSize)), + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% (i*%elemSize)), extGetCellType(result).base, waPush) let len1 = gch.tempStack.len for i in len0 ..< len1: @@ -318,7 +313,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. if ntfNoRefs notin extGetCellType(result).base.flags: for i in newLen..result.len-1: forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% - GenericSeqSize +% (i*%elemSize)), + align(GenericSeqSize, elemAlign) +% (i*%elemSize)), extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out @@ -327,7 +322,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destroy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + zeroMem(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% (newLen*%elemSize)), (result.len-%newLen) *% elemSize) result.len = newLen @@ -339,10 +334,11 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. else: when defined(nimIncrSeqV3): let elemSize = typ.base.size + let elemAlign = typ.base.align if s.space < newLen: let r = max(resize(s.space), newLen) result = cast[PGenericSeq](newSeq(typ, r)) - copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * elemSize) + copyMem(result +! align(GenericSeqSize, elemAlign), s +! align(GenericSeqSize, elemAlign), s.len * elemSize) # since we steal the content from 's', it's crucial to set s's len to 0. s.len = 0 elif newLen < s.len: @@ -354,7 +350,7 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. if ntfNoRefs notin typ.base.flags: for i in newLen..result.len-1: forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% - GenericSeqSize +% (i*%elemSize)), + align(GenericSeqSize, elemAlign) +% (i*%elemSize)), extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out @@ -363,7 +359,7 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destroy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + zeroMem(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% (newLen*%elemSize)), (result.len-%newLen) *% elemSize) else: result = s diff --git a/tests/collections/thardalignmentconstraint.nim b/tests/collections/thardalignmentconstraint.nim new file mode 100644 index 000000000..e3a3081b9 --- /dev/null +++ b/tests/collections/thardalignmentconstraint.nim @@ -0,0 +1,17 @@ +discard """ +disabled: true +""" + +# does not yet work + +{.passC: "-march=native".} + +type + m256d {.importc: "__m256d", header: "immintrin.h".} = object + +proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".} + +for _ in 1..1000: + var x = newSeq[m256d](1) + x[0] = set1(1.0) # test if operation causes segfault + doAssert (cast[uint](x[0].addr) and 31) == 0 From 9874981e757f0e2658baa3a871450509cee9204c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Apr 2020 10:01:04 +0200 Subject: [PATCH 0341/4254] fixes #14001 (#14004) --- compiler/sigmatch.nim | 2 +- compiler/types.nim | 2 +- drnim/drnim.nim | 1 + lib/system/iterators_1.nim | 10 +++++----- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d819afb42..6c8f926dd 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1276,7 +1276,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyNil: result = allowsNilDeprecated(c, f) else: discard of tyOrdinal: - if isOrdinalType(a): + if isOrdinalType(a, allowEnumWithHoles = optNimV1Emulation in c.c.config.globalOptions): var x = if a.kind == tyOrdinal: a[0] else: a if f[0].kind == tyNone: result = isGeneric diff --git a/compiler/types.nim b/compiler/types.nim index ecbe371e2..c55ecd2aa 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -161,7 +161,7 @@ proc enumHasHoles*(t: PType): bool = proc isOrdinalType*(t: PType, allowEnumWithHoles: bool = false): bool = assert(t != nil) const - baseKinds = {tyChar,tyInt..tyInt64,tyUInt..tyUInt64,tyBool,tyEnum} + baseKinds = {tyChar, tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyEnum} parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tySink, tyDistinct} result = (t.kind in baseKinds and (not t.enumHasHoles or allowEnumWithHoles)) or (t.kind in parentKinds and isOrdinalType(t.lastSon, allowEnumWithHoles)) diff --git a/drnim/drnim.nim b/drnim/drnim.nim index 6c08bed42..789cf74cf 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -9,6 +9,7 @@ #[ +- introduce Phi nodes to complete the SSA representation - the analysis has to take 'break', 'continue' and 'raises' into account - We need to map arrays to Z3 and test for something like 'forall(i, (i in 3..4) -> (a[i] > 3))' - We need teach DrNim what 'inc', 'dec' and 'swap' mean, for example diff --git a/lib/system/iterators_1.nim b/lib/system/iterators_1.nim index 07c731c3b..262bd6aab 100644 --- a/lib/system/iterators_1.nim +++ b/lib/system/iterators_1.nim @@ -24,7 +24,7 @@ iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = yield res if res == b: break dec(res, step) - elif T is IntLikeForCount: + elif T is IntLikeForCount and T is Ordinal: var res = int(a) while res >= int(b): yield T(res) @@ -52,7 +52,7 @@ when defined(nimNewRoof): ## for i in countup(2, 9, 3): ## echo i # => 2; 5; 8 mixin inc - when T is IntLikeForCount: + when T is IntLikeForCount and T is Ordinal: var res = int(a) while res <= int(b): yield T(res) @@ -73,7 +73,7 @@ when defined(nimNewRoof): ## for i in 3 .. 7: ## echo i # => 3; 4; 5; 6; 7 mixin inc - when T is IntLikeForCount: + when T is IntLikeForCount and T is Ordinal: var res = int(a) while res <= int(b): yield T(res) @@ -138,7 +138,7 @@ else: # not defined(nimNewRoof) ## ## for i in countup(2, 9, 3): ## echo i # => 2; 5; 8 - when T is IntLikeForCount: + when T is IntLikeForCount and T is Ordinal: var res = int(a) while res <= int(b): yield T(res) @@ -159,7 +159,7 @@ else: # not defined(nimNewRoof) ## for i in 3 .. 7: ## echo i # => 3; 4; 5; 6; 7 mixin inc - when T is IntLikeForCount: + when T is IntLikeForCount and T is Ordinal: var res = int(a) while res <= int(b): yield T(res) From 73eff1f4579c62a083886d78980ecdc805990041 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Apr 2020 11:59:01 +0200 Subject: [PATCH 0342/4254] fixes #12741 (#14005) * fixes #12741 * updated tests --- compiler/semexprs.nim | 16 ++++---- compiler/semstmts.nim | 4 +- tests/concepts/texplain.nim | 80 +++++++++++++++++++----------------- tests/errmsgs/tsigmatch2.nim | 2 +- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3d41b592c..b6a69ebee 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -62,12 +62,18 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = renderTree(result, {renderNoComments})) result.typ = errorType(c) -proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = +proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode = rejectEmptyNode(n) result = semExpr(c, n, flags+{efWantValue}) if result.kind == nkEmpty: + # bug #12741, redundant error messages are the lesser evil here: + localError(c.config, n.info, errExprXHasNoType % + renderTree(result, {renderNoComments})) # do not produce another redundant error message: result = errorNode(c, n) + +proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = + result = semExprCheck(c, n, flags) if result.typ == nil or result.typ == c.enforceVoidContext: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) @@ -76,11 +82,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = - rejectEmptyNode(n) - result = semExpr(c, n, flags+{efWantValue}) - if result.kind == nkEmpty: - # do not produce another redundant error message: - result = errorNode(c, n) + result = semExprCheck(c, n, flags) if result.typ == nil: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) @@ -192,7 +194,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = if conf.selectedGC in {gcArc, gcOrc}: let d = skipTypes(dst, abstractInst) let s = skipTypes(src, abstractInst) - if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal: + if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal: return false var dstSize, srcSize: BiggestInt diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 992f05e32..986953ab2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1476,9 +1476,9 @@ proc semProcAnnotation(c: PContext, prc: PNode; let ident = considerQuotedIdent(c, key) if strTableGet(c.userPragmas, ident) != nil: continue # User defined pragma - else: + else: let sym = searchInScopes(c, ident) - if sym != nil and sfCustomPragma in sym.flags: + if sym != nil and sfCustomPragma in sym.flags: continue # User custom pragma # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim index 344b6d53f..de3d540cd 100644 --- a/tests/concepts/texplain.nim +++ b/tests/concepts/texplain.nim @@ -1,41 +1,45 @@ discard """ cmd: "nim c --verbosity:0 --colors:off $file" nimout: ''' -texplain.nim(158, 10) Hint: Non-matching candidates for e(y) +texplain.nim(164, 10) Hint: Non-matching candidates for e(y) proc e(i: int): int first type mismatch at position: 1 required type for i: int but expression 'y' is of type: MatchingType -texplain.nim(161, 7) Hint: Non-matching candidates for e(10) +texplain.nim(167, 7) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression '10' is of type: int literal(10) -texplain.nim(124, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(124, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(124, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(124, 5) ExplainedConcept: concept predicate failed -texplain.nim(125, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(125, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(125, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(130, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(130, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(130, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(130, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(130, 5) ExplainedConcept: concept predicate failed +texplain.nim(131, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(131, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(131, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(131, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(130, 5) ExplainedConcept: concept predicate failed -texplain.nim(164, 10) Hint: Non-matching candidates for e(10) +texplain.nim(170, 10) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression '10' is of type: int literal(10) -texplain.nim(124, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(124, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(124, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(124, 5) ExplainedConcept: concept predicate failed -texplain.nim(125, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(125, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(125, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(130, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(130, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(130, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(130, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(130, 5) ExplainedConcept: concept predicate failed +texplain.nim(131, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(131, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(131, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(131, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(130, 5) ExplainedConcept: concept predicate failed -texplain.nim(168, 20) Error: type mismatch: got +texplain.nim(174, 20) Error: type mismatch: got but expected one of: proc e(i: int): int first type mismatch at position: 1 @@ -45,11 +49,11 @@ proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression 'n' is of type: NonMatchingType -texplain.nim(168, 9) template/generic instantiation of `assert` from here -texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(174, 9) template/generic instantiation of `assert` from here +texplain.nim(130, 5) ExplainedConcept: concept predicate failed expression: e(n) -texplain.nim(169, 20) Error: type mismatch: got +texplain.nim(175, 20) Error: type mismatch: got but expected one of: proc r(i: string): int first type mismatch at position: 1 @@ -59,15 +63,15 @@ proc r(o: RegularConcept): int first type mismatch at position: 1 required type for o: RegularConcept but expression 'n' is of type: NonMatchingType -texplain.nim(169, 9) template/generic instantiation of `assert` from here -texplain.nim(128, 5) RegularConcept: concept predicate failed +texplain.nim(175, 9) template/generic instantiation of `assert` from here +texplain.nim(134, 5) RegularConcept: concept predicate failed proc r[T](a: SomeNumber; b: T; c: auto) first type mismatch at position: 1 required type for a: SomeNumber but expression 'n' is of type: NonMatchingType expression: r(n) -texplain.nim(170, 20) Hint: Non-matching candidates for r(y) +texplain.nim(176, 20) Hint: Non-matching candidates for r(y) proc r(i: string): int first type mismatch at position: 1 required type for i: string @@ -77,25 +81,27 @@ proc r[T](a: SomeNumber; b: T; c: auto) required type for a: SomeNumber but expression 'y' is of type: MatchingType -texplain.nim(178, 2) Error: type mismatch: got +texplain.nim(184, 2) Error: type mismatch: got but expected one of: proc f(o: NestedConcept) first type mismatch at position: 1 required type for o: NestedConcept but expression 'y' is of type: MatchingType -texplain.nim(128, 6) RegularConcept: undeclared field: 'foo' -texplain.nim(128, 6) RegularConcept: undeclared field: '.' -texplain.nim(128, 6) RegularConcept: expression '.' cannot be called -texplain.nim(128, 5) RegularConcept: concept predicate failed -texplain.nim(129, 6) RegularConcept: undeclared field: 'bar' -texplain.nim(129, 6) RegularConcept: undeclared field: '.' -texplain.nim(129, 6) RegularConcept: expression '.' cannot be called -texplain.nim(128, 5) RegularConcept: concept predicate failed -texplain.nim(132, 5) NestedConcept: concept predicate failed +texplain.nim(134, 6) RegularConcept: undeclared field: 'foo' +texplain.nim(134, 6) RegularConcept: undeclared field: '.' +texplain.nim(134, 6) RegularConcept: expression '.' cannot be called +texplain.nim(134, 6) RegularConcept: expression '' has no type (or is ambiguous) +texplain.nim(134, 5) RegularConcept: concept predicate failed +texplain.nim(135, 6) RegularConcept: undeclared field: 'bar' +texplain.nim(135, 6) RegularConcept: undeclared field: '.' +texplain.nim(135, 6) RegularConcept: expression '.' cannot be called +texplain.nim(135, 6) RegularConcept: expression '' has no type (or is ambiguous) +texplain.nim(134, 5) RegularConcept: concept predicate failed +texplain.nim(138, 5) NestedConcept: concept predicate failed expression: f(y)''' errormsg: "type mismatch: got " - line: 178 + line: 184 """ diff --git a/tests/errmsgs/tsigmatch2.nim b/tests/errmsgs/tsigmatch2.nim index 580743f3e..4996634c9 100644 --- a/tests/errmsgs/tsigmatch2.nim +++ b/tests/errmsgs/tsigmatch2.nim @@ -13,6 +13,7 @@ proc foo(i: Foo): string but expression '1.2' is of type: float64 expression: foo(1.2) +tsigmatch2.nim(40, 14) Error: expression '' has no type (or is ambiguous) tsigmatch2.nim(46, 7) Error: type mismatch: got but expected one of: proc foo(args: varargs[string, myproc]) @@ -26,7 +27,6 @@ expression: foo 1 """ - # line 30 type Foo = object block: # issue #13182 From 242d39d27f672a0f3b21f5e8f1752218d1f480f2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Apr 2020 14:42:45 +0200 Subject: [PATCH 0343/4254] fixes #12834 (#14017) --- lib/pure/hashes.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 287b152d2..f7b4e907b 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -174,16 +174,16 @@ proc hash*[T: proc](x: T): Hash {.inline.} = else: result = hash(pointer(x)) -proc hashIdentity*[T: Ordinal](x: T): Hash {.inline, since: (1, 3).} = +proc hashIdentity*[T: Ordinal|enum](x: T): Hash {.inline, since: (1, 3).} = ## The identity hash. I.e. ``hashIdentity(x) = x``. cast[Hash](ord(x)) when defined(nimIntHash1): - proc hash*[T: Ordinal](x: T): Hash {.inline.} = + proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} = ## Efficient hashing of integers. cast[Hash](ord(x)) else: - proc hash*[T: Ordinal](x: T): Hash {.inline.} = + proc hash*[T: Ordinal|enum](x: T): Hash {.inline.} = ## Efficient hashing of integers. hashWangYi1(uint64(ord(x))) From e6cf11351d10e38ec58faeb3cb0a134f616a2ba3 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 20 Apr 2020 08:42:08 +0200 Subject: [PATCH 0344/4254] unicode: minor documention improvement --- lib/pure/unicode.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 65509b2b2..2d54aaf31 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -28,6 +28,7 @@ type ## Type that can hold a single Unicode code point. ## ## A Rune may be composed with other Runes to a character on the screen. + ## `RuneImpl` is the underlying type used to store Runes, currently `int32`. template ones(n: untyped): untyped = ((1 shl n)-1) From 77834f0fdabc9d39cf111c4c94e717bd2c4f00d2 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 20 Apr 2020 09:54:53 +0000 Subject: [PATCH 0345/4254] compiler/suggest: highlight squashed operators (#11796) The operator fetching proc is greedy, so operators such as `%*` in expression `%*{}` can't be highlighted. This commit fixes that. --- compiler/suggest.nim | 10 +++++++--- nimsuggest/tests/top_highlight.nim | 11 +++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 nimsuggest/tests/top_highlight.nim diff --git a/compiler/suggest.nim b/compiler/suggest.nim index d8da2a7a4..58b54cc03 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -106,11 +106,15 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0: result = 0 else: - result = skipWhile(line, OpChars + {'[', '(', '{', ']', ')', '}'}, column) + var sourceIdent: string + result = parseWhile(line, sourceIdent, + OpChars + {'[', '(', '{', ']', ')', '}'}, column) if ident[^1] == '=' and ident[0] in linter.Letters: - if line[column..column + result - 1] != "=": + if sourceIdent != "=": result = 0 - elif line[column..column + result - 1] != ident: + elif sourceIdent.len > ident.len and sourceIdent[..ident.high] == ident: + result = ident.len + elif sourceIdent != ident: result = 0 proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; diff --git a/nimsuggest/tests/top_highlight.nim b/nimsuggest/tests/top_highlight.nim new file mode 100644 index 000000000..c3f6bb61d --- /dev/null +++ b/nimsuggest/tests/top_highlight.nim @@ -0,0 +1,11 @@ +import json + +%*{}#[!]# + +discard """ +$nimsuggest --tester $file +>highlight $1 +highlight;;skModule;;1;;7;;4 +highlight;;skMacro;;3;;0;;2 +highlight;;skMacro;;3;;0;;2 +""" From b2720317fa3b31aed298398696124b439fcfa907 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 20 Apr 2020 03:00:00 -0700 Subject: [PATCH 0346/4254] add `--experimental:vmopsDanger`; add generic conversion for vmops (#13813) * add --experimental:vmopsDanger; vmops cleanups --- compiler/options.nim | 1 + compiler/vmconv.nim | 41 +++++++++++++++++++++++++++++++++++++++++ compiler/vmops.nim | 33 ++++++++++++++++++++++++--------- 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 compiler/vmconv.nim diff --git a/compiler/options.nim b/compiler/options.nim index 813d2d6e5..b9aca23a1 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -147,6 +147,7 @@ type ## This requires building nim with `-d:nimHasLibFFI` ## which itself requires `nimble install libffi`, see #10150 ## Note: this feature can't be localized with {.push.} + vmopsDanger, LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/vmconv.nim b/compiler/vmconv.nim new file mode 100644 index 000000000..7db3906c2 --- /dev/null +++ b/compiler/vmconv.nim @@ -0,0 +1,41 @@ +import ast + +template elementType*(T: typedesc): typedesc = + typeof(block: + var a: T + for ai in a: ai) + +proc fromLit*(a: PNode, T: typedesc): auto = + ## generic PNode => type + ## see also reverse operation `toLit` + when T is set: + result = default(T) + type Ti = elementType(T) + for ai in a: + result.incl Ti(ai.intVal) + else: + static: doAssert false, "not yet supported: " & $T # add as needed + +proc toLit*[T](a: T): PNode = + ## generic type => PNode + ## see also reverse operation `fromLit` + when T is string: newStrNode(nkStrLit, a) + elif T is Ordinal: newIntNode(nkIntLit, a.ord) + elif T is (proc): newNode(nkNilLit) + elif T is ref: + if a == nil: newNode(nkNilLit) + else: toLit(a[]) + elif T is tuple: + result = newTree(nkTupleConstr) + for ai in fields(a): result.add toLit(ai) + elif T is object: + result = newTree(nkObjConstr) + result.add(newNode(nkEmpty)) + for k, ai in fieldPairs(a): + let reti = newNode(nkExprColonExpr) + reti.add k.toLit + reti.add ai.toLit + result.add reti + else: + static: doAssert false, "not yet supported: " & $T # add as needed + diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 0ee137178..ef36419a7 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -19,6 +19,9 @@ from sighashes import symBodyDigest from times import cpuTime from hashes import hash +from osproc import nil + +import vmconv template mathop(op) {.dirty.} = registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) @@ -99,13 +102,12 @@ proc getCurrentExceptionWrapper(a: VmArgs) {.nimcall.} = proc staticWalkDirImpl(path: string, relative: bool): PNode = result = newNode(nkBracket) for k, f in walkDir(path, relative): - result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord), - newStrNode(nkStrLit, f)) + result.add toLit((k, f)) when defined(nimHasInvariant): from std / compilesettings import SingleValueSetting, MultipleValueSetting - proc querySettingImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): string = + proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string = case SingleValueSetting(switch) of arguments: result = conf.arguments of outFile: result = conf.outFile.string @@ -120,7 +122,7 @@ when defined(nimHasInvariant): of compileOptions: result = conf.compileOptions of ccompilerPath: result = conf.cCompilerPath - proc querySettingSeqImpl(a: VmArgs, conf: ConfigRef, switch: BiggestInt): seq[string] = + proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = for i in field: result.add i.string @@ -134,9 +136,9 @@ when defined(nimHasInvariant): proc registerAdditionalOps*(c: PCtx) = proc gorgeExWrapper(a: VmArgs) = - let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), + let ret = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), a.currentLineInfo, c.config) - setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e)) + setResult a, ret.toLit proc getProjectPathWrapper(a: VmArgs) = setResult a, c.config.projectPath.string @@ -184,9 +186,9 @@ proc registerAdditionalOps*(c: PCtx) = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) when defined(nimHasInvariant): registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} = - setResult(a, querySettingImpl(a, c.config, getInt(a, 0))) + setResult(a, querySettingImpl(c.config, getInt(a, 0))) registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} = - setResult(a, querySettingSeqImpl(a, c.config, getInt(a, 0))) + setResult(a, querySettingSeqImpl(c.config, getInt(a, 0))) if defined(nimsuggest) or c.config.cmd == cmdCheck: discard "don't run staticExec for 'nim suggest'" @@ -238,8 +240,21 @@ proc registerAdditionalOps*(c: PCtx) = registerCallback c, "stdlib.hashes.hashVmImplByte", hashVmImplByte registerCallback c, "stdlib.hashes.hashVmImplChar", hashVmImplByte - if optBenchmarkVM in c.config.globalOptions: + if optBenchmarkVM in c.config.globalOptions or vmopsDanger in c.config.features: wrap0(cpuTime, timesop) else: proc cpuTime(): float = 5.391245e-44 # Randomly chosen wrap0(cpuTime, timesop) + + if vmopsDanger in c.config.features: + ## useful procs but these should be opt-in because they may impact + ## reproducible builds and users need to understand that this runs at CT. + ## Note that `staticExec` can already do equal amount of damage so it's more + ## of a semantic issue than a security issue. + registerCallback c, "stdlib.os.getCurrentDir", proc (a: VmArgs) {.nimcall.} = + setResult(a, os.getCurrentDir()) + registerCallback c, "stdlib.osproc.execCmdEx", proc (a: VmArgs) {.nimcall.} = + let options = getNode(a, 1).fromLit(set[osproc.ProcessOption]) + a.setResult osproc.execCmdEx(getString(a, 0), options).toLit + registerCallback c, "stdlib.times.getTime", proc (a: VmArgs) {.nimcall.} = + setResult(a, times.getTime().toLit) From 17f222613a90b0113277baaaa87b856bea74f209 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 20 Apr 2020 10:33:07 +0200 Subject: [PATCH 0347/4254] refactor system.$ for objects a little; refs #13398 --- lib/system/dollars.nim | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 3414c6db1..8e10dae4b 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -75,28 +75,22 @@ proc `$`*[T: tuple|object](x: T): string = ## $(a: 23, b: 45) == "(a: 23, b: 45)" ## $() == "()" result = "(" - # when x is empty, this gives an unused warning - var firstElement {.used.} = true const isNamed = T is object or isNamedTuple(T) - when not isNamed: - var count = 0 + var count = 0 for name, value in fieldPairs(x): - if not firstElement: result.add(", ") + if count > 0: result.add(", ") when isNamed: result.add(name) result.add(": ") - else: - count.inc + count.inc when compiles($value): when value isnot string and value isnot seq and compiles(value.isNil): if value.isNil: result.add "nil" else: result.addQuoted(value) else: result.addQuoted(value) - firstElement = false else: result.add("...") - firstElement = false when not isNamed: if count == 1: result.add(",") # $(1,) should print as the semantically legal (1,) From 4d1149cffd56f0e316af892d54fc9da1d4fd8769 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 20 Apr 2020 10:59:17 +0200 Subject: [PATCH 0348/4254] fix for asm statement; refs #12650 --- compiler/ccgstmts.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e2bcf3a74..c7c1569b0 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1440,7 +1440,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = else: # ignore empty lines result.add("\"") - result.add(x) + result.add(x.replace("\"", "\\\"")) result.add("\\n\"\n") else: res.add("\L") From 59f1462b95279dd16f9de5cb7b3de501b33756b7 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 20 Apr 2020 11:12:09 +0200 Subject: [PATCH 0349/4254] remove the nilChecks switch; refs #11570 --- compiler/cgen.nim | 2 -- compiler/commands.nim | 4 ++-- compiler/options.nim | 6 +++--- compiler/pragmas.nim | 1 - doc/advopt.txt | 1 - 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a8045e054..7fe33fc59 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -406,8 +406,6 @@ proc resetLoc(p: BProc, loc: var TLoc) = else: linefmt(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)]) else: - if optNilCheck in p.options: - linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", [addrLoc(p.config, loc)]) if loc.storage != OnStack and containsGcRef: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)]) diff --git a/compiler/commands.nim b/compiler/commands.nim index 47dbcfa90..949d6cae1 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -297,7 +297,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} of "infchecks": result = contains(conf.options, optInfCheck) of "nanchecks": result = contains(conf.options, optNaNCheck) - of "nilchecks": result = contains(conf.options, optNilCheck) + of "nilchecks": result = false # not a thing of "objchecks": result = contains(conf.options, optObjCheck) of "fieldchecks": result = contains(conf.options, optFieldCheck) of "rangechecks": result = contains(conf.options, optRangeCheck) @@ -594,7 +594,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info) of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info) - of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info) + of "nilchecks": discard "no such thing anymore" of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info) of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info) of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info) diff --git a/compiler/options.nim b/compiler/options.nim index b9aca23a1..6105fcdb3 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -25,7 +25,7 @@ type # please make sure we have under 32 options # (improves code efficiency a lot!) TOption* = enum # **keep binary compatible** optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, - optOverflowCheck, optNilCheck, optRefCheck, + optOverflowCheck, optRefCheck, optNaNCheck, optInfCheck, optStaticBoundsCheck, optStyleCheck, optAssert, optLineDir, optWarns, optHints, optOptimizeSpeed, optOptimizeSize, @@ -325,14 +325,14 @@ template depConfigFields*(fn) {.dirty.} = const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} const - ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, + ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck, optStyleCheck} DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` - optTrMacros, optNilCheck, optStyleCheck, optSinkInference} + optTrMacros, optStyleCheck, optSinkInference} DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, optListFullPaths} diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1a9f5a991..ffe93a9f3 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -361,7 +361,6 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} = of wRangeChecks: {optRangeCheck} of wBoundChecks: {optBoundsCheck} of wOverflowChecks: {optOverflowCheck} - of wNilChecks: {optNilCheck} of wFloatChecks: {optNaNCheck, optInfCheck} of wNanChecks: {optNaNCheck} of wInfChecks: {optInfCheck} diff --git a/doc/advopt.txt b/doc/advopt.txt index bc5f9948c..c877b02e9 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -24,7 +24,6 @@ Runtime checks (see -x): --floatChecks:on|off turn all floating point (NaN/Inf) checks on|off --nanChecks:on|off turn NaN checks on|off --infChecks:on|off turn Inf checks on|off - --nilChecks:on|off turn nil checks on|off --refChecks:on|off turn ref checks on|off (only for --newruntime) Advanced options: From 59aeaa1c98d4546aeb784864fcc660d43fb3da1b Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Mon, 20 Apr 2020 07:48:37 -0500 Subject: [PATCH 0350/4254] Make bitand, bitor, bitxor varargs-friendly (#13985) * made bitand, bitor, bitxor varargs friendly * changed new bitops to macros * changed macro signature for consistency (this technically doesn't matter) * added tests * removed redundant assert * fix literal --- lib/pure/bitops.nim | 35 ++++++++++++++++++++++++++--------- tests/stdlib/tbitops.nim | 8 ++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index cf6013c77..439f6be03 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -25,17 +25,37 @@ ## At this time only `fastLog2`, `firstSetBit, `countLeadingZeroBits`, `countTrailingZeroBits` ## may return undefined and/or platform dependent value if given invalid input. +import macros + proc bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. -proc bitand*[T: SomeInteger](x, y: T): T {.magic: "BitandI", noSideEffect.} - ## Computes the `bitwise and` of numbers `x` and `y`. +func internalBitand[T: SomeInteger](x, y: T): T {.magic: "BitandI".} -proc bitor*[T: SomeInteger](x, y: T): T {.magic: "BitorI", noSideEffect.} - ## Computes the `bitwise or` of numbers `x` and `y`. +func internalBitor[T: SomeInteger](x, y: T): T {.magic: "BitorI".} -proc bitxor*[T: SomeInteger](x, y: T): T {.magic: "BitxorI", noSideEffect.} - ## Computes the `bitwise xor` of numbers `x` and `y`. +func internalBitxor[T: SomeInteger](x, y: T): T {.magic: "BitxorI".} + +macro bitand*[T: SomeInteger](x, y: T; z: varargs[T]): T = + ## Computes the `bitwise and` of all arguments collectively. + let fn = bindSym("internalBitand") + result = newCall(fn, x, y) + for extra in z: + result = newCall(fn, result, extra) + +macro bitor*[T: SomeInteger](x, y: T; z: varargs[T]): T = + ## Computes the `bitwise or` of all arguments collectively. + let fn = bindSym("internalBitor") + result = newCall(fn, x, y) + for extra in z: + result = newCall(fn, result, extra) + +macro bitxor*[T: SomeInteger](x, y: T; z: varargs[T]): T = + ## Computes the `bitwise xor` of all arguments collectively. + let fn = bindSym("internalBitxor") + result = newCall(fn, x, y) + for extra in z: + result = newCall(fn, result, extra) const useBuiltins = not defined(noIntrinsicsBitOpts) const noUndefined = defined(noUndefinedBitOpts) @@ -64,9 +84,6 @@ template forwardImpl(impl, arg) {.dirty.} = impl(x.uint64) when defined(nimHasalignOf): - - import macros - type BitsRange*[T] = range[0..sizeof(T)*8-1] ## Returns a range with all bit positions for type ``T``. diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index 3826cb1f9..d611ce4cc 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -18,6 +18,8 @@ proc main1() = const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64 const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64 const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64 + const U64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'u64 + const I64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'i64 doAssert( (U8 and U8) == bitand(U8,U8) ) doAssert( (I8 and I8) == bitand(I8,I8) ) @@ -27,6 +29,8 @@ proc main1() = doAssert( (I32 and I32) == bitand(I32,I32) ) doAssert( (U64A and U64B) == bitand(U64A,U64B) ) doAssert( (I64A and I64B) == bitand(I64A,I64B) ) + doAssert( (U64A and U64B and U64C) == bitand(U64A,U64B,U64C) ) + doAssert( (I64A and I64B and I64C) == bitand(I64A,I64B,I64C) ) doAssert( (U8 or U8) == bitor(U8,U8) ) doAssert( (I8 or I8) == bitor(I8,I8) ) @@ -36,6 +40,8 @@ proc main1() = doAssert( (I32 or I32) == bitor(I32,I32) ) doAssert( (U64A or U64B) == bitor(U64A,U64B) ) doAssert( (I64A or I64B) == bitor(I64A,I64B) ) + doAssert( (U64A or U64B or U64C) == bitor(U64A,U64B,U64C) ) + doAssert( (I64A or I64B or I64C) == bitor(I64A,I64B,I64C) ) doAssert( (U8 xor U8) == bitxor(U8,U8) ) doAssert( (I8 xor I8) == bitxor(I8,I8) ) @@ -45,6 +51,8 @@ proc main1() = doAssert( (I32 xor I32) == bitxor(I32,I32) ) doAssert( (U64A xor U64B) == bitxor(U64A,U64B) ) doAssert( (I64A xor I64B) == bitxor(I64A,I64B) ) + doAssert( (U64A xor U64B xor U64C) == bitxor(U64A,U64B,U64C) ) + doAssert( (I64A xor I64B xor I64C) == bitxor(I64A,I64B,I64C) ) doAssert( not(U8) == bitnot(U8) ) doAssert( not(I8) == bitnot(I8) ) From 4476d8a2e06418d2ee9e2a4c80e760f27890d295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C6=B0u=20Danh=2C=20Hi=E1=BA=BFu?= Date: Mon, 20 Apr 2020 19:49:05 +0700 Subject: [PATCH 0351/4254] Update code example to match new sdl2.nim syntax (#13924) * Update code example to match new sdl2.nim syntax Signed-off-by: Hieu Luu Danh * Modify on recommendation of @alaviss - Removed trailing whitespaces - Detailed how to compile libnimhcr and libnimrtl - Fixed some logic in example code * Modify following recommendations of @alaviss - Rewording so that it conforms to Windows/Linux/MacOS Signed-off-by: Hieu Luu Danh --- doc/hcr.rst | 68 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/doc/hcr.rst b/doc/hcr.rst index e04fce618..9bf88f6ef 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -26,39 +26,40 @@ To install SDL2 you can use ``nimble install sdl2``. .. code-block:: nim # logic.nim - import sdl2/sdl + import sdl2 #*** import the hotcodereloading stdlib module *** import hotcodereloading var runGame*: bool = true - var window: Window - var renderer: Renderer + var window: WindowPtr + var renderer: RendererPtr + var evt = sdl2.defaultEvent proc init*() = - discard sdl.init(INIT_EVERYTHING) - window = createWindow("testing", WINDOWPOS_UNDEFINED.cint, WINDOWPOS_UNDEFINED.cint, 640, 480, 0'u32) - assert(window != nil, $sdl.getError()) + discard sdl2.init(INIT_EVERYTHING) + window = createWindow("testing", SDL_WINDOWPOS_UNDEFINED.cint, SDL_WINDOWPOS_UNDEFINED.cint, 640, 480, 0'u32) + assert(window != nil, $sdl2.getError()) renderer = createRenderer(window, -1, RENDERER_SOFTWARE) - assert(renderer != nil, $sdl.getError()) + assert(renderer != nil, $sdl2.getError()) proc destroy*() = destroyRenderer(renderer) destroyWindow(window) - var posX = 1 - var posY = 0 - var dX = 1 - var dY = 1 + var posX: cint = 1 + var posY: cint = 0 + var dX: cint = 1 + var dY: cint = 1 proc update*() = - for evt in events(): - if evt.kind == QUIT: + while pollEvent(evt): + if evt.kind == QuitEvent: runGame = false break - if evt.kind == KEY_DOWN: - if evt.key.keysym.scancode == SCANCODE_ESCAPE: runGame = false - elif evt.key.keysym.scancode == SCANCODE_F9: + if evt.kind == KeyDown: + if evt.key.keysym.scancode == SDL_SCANCODE_ESCAPE: runGame = false + elif evt.key.keysym.scancode == SDL_SCANCODE_F9: #*** reload this logic.nim module on the F9 keypress *** performCodeReload() @@ -71,14 +72,14 @@ To install SDL2 you can use ``nimble install sdl2``. if posY >= 480: dY = -2 if posY <= 0: dY = +2 - discard renderer.setRenderDrawColor(0, 0, 255, 255) - discard renderer.renderClear() - discard renderer.setRenderDrawColor(255, 128, 128, 0) + discard renderer.setDrawColor(0, 0, 255, 255) + discard renderer.clear() + discard renderer.setDrawColor(255, 128, 128, 0) - var rect: Rect(x: posX - 25, y: posY - 25, w: 50, h: 50) - discard renderer.renderFillRect(rect.addr) + var rect: Rect = (x: posX - 25, y: posY - 25, w: 50.cint, h: 50.cint) + discard renderer.fillRect(rect) delay(16) - renderer.renderPresent() + renderer.present() .. code-block:: nim @@ -111,11 +112,11 @@ Now start the program and KEEP it running! For example, change the line:: - discard renderer.setRenderDrawColor(255, 128, 128, 0) + discard renderer.setDrawColor(255, 128, 128, 0) into:: - discard renderer.setRenderDrawColor(255, 255, 128, 0) + discard renderer.setDrawColor(255, 255, 128, 0) (This will change the color of the rectangle.) @@ -187,7 +188,24 @@ Native code targets Native projects using the hot code reloading option will be implicitly compiled with the `-d:useNimRtl` option and they will depend on both the ``nimrtl`` library and the ``nimhcr`` library which implements the -hot code reloading run-time. +hot code reloading run-time. Both libraries can be found in the ``lib`` +folder of Nim and can be compiled into dynamic libraries to satisfy +runtime demands of the example code above. An example of compiling +``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed +with choosenim follows. + +:: + + # Unix/MacOS + # Make sure you are in the directory containing your .nim files + $ cd your-source-directory + + # Compile two required files and set their output directory to current dir + $ nim c --outdir:$PWD ~/.choosenim/toolchains/nim-#devel/lib/nimhcr.nim + $ nim c --outdir:$PWD ~/.choosenim/toolchains/nim-#devel/lib/nimrtl.nim + + # verify that you have two files named libnimhcr and libnimrtl in your + # source directory (.dll for Windows, .so for Unix, .dylib for MacOS) All modules of the project will be compiled to separate dynamic link libraries placed in the ``nimcache`` directory. Please note that during From ba0af0f827d97532516e4c2acc1fdbb9cdba7b61 Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Mon, 20 Apr 2020 06:36:57 -0700 Subject: [PATCH 0352/4254] allow generic typedesc field access (#12220) Co-authored-by: Clyybber --- compiler/semexprs.nim | 108 ++++++++++++++++------------------ tests/metatype/ttypedesc3.nim | 9 +++ 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b6a69ebee..56b6076d5 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1271,6 +1271,54 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = onUse(info, s) result = newSymNode(s, info) +proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode = + case t.kind + of tyTypeParamsHolders: + result = readTypeParameter(c, t, i, n.info) + if result == c.graph.emptyNode: + result = n + n.typ = makeTypeFromExpr(c, n.copyTree) + of tyUserTypeClasses: + if t.isResolvedUserTypeClass: + result = readTypeParameter(c, t, i, n.info) + else: + n.typ = makeTypeFromExpr(c, copyTree(n)) + result = n + of tyGenericParam, tyAnything: + n.typ = makeTypeFromExpr(c, copyTree(n)) + result = n + else: + discard + +proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode = + var ty = ty.skipTypes(tyDotOpTransparent) + case ty.kind + of tyEnum: + # look up if the identifier belongs to the enum: + var f = PSym(nil) + while ty != nil: + f = getSymFromList(ty.n, i) + if f != nil: break + ty = ty.sons[0] # enum inheritance + if f != nil: + result = newSymNode(f) + result.info = n.info + result.typ = ty + markUsed(c, n.info, f) + onUse(n.info, f) + of tyObject, tyTuple: + if ty.n != nil and ty.n.kind == nkRecList: + let field = lookupInRecord(ty.n, i) + if field != nil: + n.typ = makeTypeDesc(c, field.typ) + result = n + of tyGenericInst: + result = tryReadingTypeField(c, n, i, ty.lastSon) + if result == nil: + result = tryReadingGenericParam(c, n, i, ty) + else: + result = tryReadingGenericParam(c, n, i, ty) + proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access checkSonsLen(n, 2, c.config) @@ -1301,28 +1349,6 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = var f: PSym = nil result = nil - template tryReadingGenericParam(t: PType) = - case t.kind - of tyTypeParamsHolders: - result = readTypeParameter(c, t, i, n.info) - if result == c.graph.emptyNode: - result = n - n.typ = makeTypeFromExpr(c, n.copyTree) - return - of tyUserTypeClasses: - if t.isResolvedUserTypeClass: - return readTypeParameter(c, t, i, n.info) - else: - n.typ = makeTypeFromExpr(c, copyTree(n)) - return n - of tyGenericParam, tyAnything: - n.typ = makeTypeFromExpr(c, copyTree(n)) - return n - else: - discard - - var argIsType = false - if ty.kind == tyTypeDesc: if ty.base.kind == tyNone: # This is a still unresolved typedesc parameter. @@ -1335,40 +1361,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = else: return nil else: - ty = ty.base - argIsType = true - else: - argIsType = isTypeExpr(n[0]) + return tryReadingTypeField(c, n, i, ty.base) + elif isTypeExpr(n.sons[0]): + return tryReadingTypeField(c, n, i, ty) - if argIsType: - ty = ty.skipTypes(tyDotOpTransparent) - case ty.kind - of tyEnum: - # look up if the identifier belongs to the enum: - while ty != nil: - f = getSymFromList(ty.n, i) - if f != nil: break - ty = ty[0] # enum inheritance - if f != nil: - result = newSymNode(f) - result.info = n.info - result.typ = ty - markUsed(c, n.info, f) - onUse(n.info, f) - return - of tyObject, tyTuple: - if ty.n != nil and ty.n.kind == nkRecList: - let field = lookupInRecord(ty.n, i) - if field != nil: - n.typ = makeTypeDesc(c, field.typ) - return n - else: - tryReadingGenericParam(ty) - return - # XXX: This is probably not relevant any more - # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim": - ty = n[0].typ - return nil if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass: ty = ty.lastSon ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink}) @@ -1412,7 +1408,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # we didn't find any field, let's look for a generic param if result == nil: let t = n[0].typ.skipTypes(tyDotOpTransparent) - tryReadingGenericParam(t) + result = tryReadingGenericParam(c, n, i, t) proc dotTransformation(c: PContext, n: PNode): PNode = if isSymChoice(n[1]): diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim index ff6e22718..b691d3488 100644 --- a/tests/metatype/ttypedesc3.nim +++ b/tests/metatype/ttypedesc3.nim @@ -6,6 +6,7 @@ method Base yield Base yield Child 12 +1 ''' """ @@ -41,3 +42,11 @@ type MyRefType = ref MyType echo sizeof(default(MyRefType)[]) + +type + Foo[T] = object + val: T + +var x: Foo[int].val +inc(x) +echo x From 65c5367dc1c29d01f00dbc2bcfb574af5f3334fa Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 20 Apr 2020 14:57:36 +0100 Subject: [PATCH 0353/4254] Fixes #14014 (#14029) * add test * improve test * progress * fix #14014 * fix bug Co-authored-by: cooldome --- compiler/spawn.nim | 9 +++++++-- tests/parallel/tsysspawn.nim | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/compiler/spawn.nim b/compiler/spawn.nim index c60dd934c..8b1f89e15 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -201,8 +201,11 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; # we pick n's type here, which hopefully is 'tyArray' and not # 'tyOpenArray': var argType = n[i].typ.skipTypes(abstractInst) - if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}: - localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") + if i < formals.len: + if formals[i].typ.kind in {tyVar, tyLent}: + localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") + if formals[i].typ.kind in {tyTypeDesc, tyStatic}: + continue #elif containsTyRef(argType): # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") @@ -226,6 +229,8 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; # for correctness: These are called 'threadLocal' here. for i in 1.. Date: Mon, 20 Apr 2020 17:06:44 +0200 Subject: [PATCH 0354/4254] Fix #13972 (#14034) --- doc/nimdoc.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 4ee73eaf9..72b6734ab 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -644,7 +644,7 @@ div.topic { margin: 2em; } div.search_results { - background-color: antiquewhite; + background-color: var(--third-background); margin: 3em; padding: 1em; border: 1px solid #4d4d4d; @@ -888,4 +888,4 @@ span.pragmawrap { span.attachedType { display: none; visibility: hidden; -} \ No newline at end of file +} From 1bdc30bdb13422bd5eff830327582a938e7b76ac Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 20 Apr 2020 15:09:59 +0000 Subject: [PATCH 0355/4254] Make file descriptors from stdlib non-inheritable by default (#13201) * io: make file descriptors non-inheritable by default This prevents file descriptors/handles leakage to child processes that might cause issues like running out of file descriptors, or potential security issues like leaking a file descriptor to a restricted file. While this breaks backward compatibility, I'm rather certain that not many programs (if any) actually make use of this implementation detail. A new API `setInheritable` is provided for the few that actually want to use this functionality. * io: disable inheritance at file creation time for supported platforms Some platforms provide extension to fopen-family of functions to allow for disabling descriptor inheritance atomically during File creation. This guards against possible leaks when a child process is spawned before we managed to disable the file descriptor inheritance (ie. in a multi-threaded program). * net, nativesockets: make sockets non inheritable by default With this commit, sockets will no longer leak to child processes when you don't want it to. Should solves a lot of "address in use" that might occur when your server has just restarted. All APIs that create sockets in these modules now expose a `inheritable` flag that allow users to toggle inheritance for the resulting sockets. An implementation of `setInheritance()` is also provided for SocketHandle. While atomically disabling inheritance at creation time is supported on Windows, it's only implemented by native winsock2, which is too much for now. This support can be implemented in a future patch. * posix: add F_DUPFD_CLOEXEC This command duplicates file descriptor with close-on-exec flag set. Defined in POSIX.1-2008. * ioselectors_kqueue: don't leak file descriptors File descriptors internally used by ioselectors on BSD/OSX are now shielded from leakage. * posix: add O_CLOEXEC This flag allows file descriptors to be open() with close-on-exec flag set atomically. This flag is specified in POSIX.1-2008 * tfdleak: test for selectors leakage Also simplified the test by using handle-type agnostic APIs to test for validity. * ioselectors_epoll: mark all fd created close-on-exec File descriptors from ioselectors should no longer leaks on Linux. * tfdleak: don't check for selector leakage on Windows The getFd proc for ioselectors_select returns a hardcoded -1 * io: add NoInheritFlag at compile time * io: add support for ioctl-based close-on-exec This allows for the flag to be set/unset in one syscall. While the performance gains might be negliable, we have one less failure point to deal with. * tfdleak: add a test for setInheritable * stdlib: add nimInheritHandles to restore old behaviors * memfiles: make file handle not inheritable by default for posix * io: setInheritable now operates on OS file handle On Windows, the native handle is the only thing that's inheritable, thus we can assume that users of this function will already have the handle available to them. This also allows users to pass down file descriptors from memfiles on Windows with ease, should that be desired. With this, nativesockets.setInheritable can be made much simpler. * changelog: clarify * nativesockets: document setInheritable return value * posix_utils: atomically disable fd inheritance for mkstemp --- changelog.md | 19 +++++ lib/posix/posix.nim | 7 ++ lib/posix/posix_linux_amd64_consts.nim | 3 + lib/posix/posix_macos_amd64.nim | 3 + lib/posix/posix_openbsd_amd64.nim | 2 + lib/posix/posix_other.nim | 3 + lib/posix/posix_other_consts.nim | 2 + lib/posix/posix_utils.nim | 6 +- lib/pure/ioselects/ioselectors_epoll.nim | 10 +-- lib/pure/ioselects/ioselectors_kqueue.nim | 8 +- lib/pure/memfiles.nim | 2 +- lib/pure/nativesockets.nim | 76 ++++++++++++++----- lib/pure/net.nim | 37 ++++++++-- lib/system/io.nim | 90 +++++++++++++++++++++-- lib/windows/winlean.nim | 5 ++ tests/stdlib/tfdleak.nim | 85 +++++++++++++++++++++ tools/detect/detect.nim | 3 + 17 files changed, 317 insertions(+), 44 deletions(-) create mode 100644 tests/stdlib/tfdleak.nim diff --git a/changelog.md b/changelog.md index 90e014556..dbe1f89cc 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,25 @@ - The default hash for `Ordinal` has changed to something more bit-scrambling. `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old one in an instantiation context while `-d:nimIntHash1` recovers it globally. +- File handles created from high-level abstractions in the stdlib will no longer + be inherited by child processes. In particular, these modules are affected: + `system`, `nativesockets`, `net` and `selectors`. + + For `net` and `nativesockets`, an `inheritable` flag has been added to all + `proc`s that create sockets, allowing the user to control whether the + resulting socket is inheritable. This flag is provided to ease the writing of + multi-process servers, where sockets inheritance is desired. + + For a transistion period, define `nimInheritHandles` to enable file handle + inheritance by default. This flag does **not** affect the `selectors` module + due to the differing semantics between operating systems. + + `system.setInheritable` and `nativesockets.setInheritable` is also introduced + for setting file handle or socket inheritance. Not all platform have these + `proc`s defined. + +- The file descriptors created for internal bookkeeping by `ioselector_kqueue` + and `ioselector_epoll` will no longer be leaked to child processes. ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index d1f2faca5..3e423c64b 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -896,6 +896,10 @@ proc `==`*(x, y: SocketHandle): bool {.borrow.} proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen): SocketHandle {. importc, header: "", sideEffect.} +when defined(linux) or defined(bsd): + proc accept4*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen, + flags: cint): SocketHandle {.importc, header: "".} + proc bindSocket*(a1: SocketHandle, a2: ptr SockAddr, a3: SockLen): cint {. importc: "bind", header: "".} ## is Posix's ``bind``, because ``bind`` is a reserved word @@ -1036,6 +1040,9 @@ proc mkstemp*(tmpl: cstring): cint {.importc, header: "", sideEffect.} proc mkdtemp*(tmpl: cstring): pointer {.importc, header: "", sideEffect.} +when defined(linux) or defined(bsd): + proc mkostemp*(tmpl: cstring, oflags: cint): cint {.importc, header: "", sideEffect.} + proc utimes*(path: cstring, times: ptr array[2, Timeval]): int {. importc: "utimes", header: "", sideEffect.} ## Sets file access and modification times. diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 7352e8e35..84296eb9b 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -100,6 +100,7 @@ const EXDEV* = cint(18) # const F_DUPFD* = cint(0) +const F_DUPFD_CLOEXEC* = cint(1030) const F_GETFD* = cint(1) const F_SETFD* = cint(2) const F_GETFL* = cint(3) @@ -126,6 +127,7 @@ const O_ACCMODE* = cint(3) const O_RDONLY* = cint(0) const O_RDWR* = cint(2) const O_WRONLY* = cint(1) +const O_CLOEXEC* = cint(524288) const POSIX_FADV_NORMAL* = cint(0) const POSIX_FADV_SEQUENTIAL* = cint(2) const POSIX_FADV_RANDOM* = cint(1) @@ -469,6 +471,7 @@ const SOCK_DGRAM* = cint(2) const SOCK_RAW* = cint(3) const SOCK_SEQPACKET* = cint(5) const SOCK_STREAM* = cint(1) +const SOCK_CLOEXEC* = cint(524288) const SOL_SOCKET* = cint(1) const SOMAXCONN* = cint(128) const SO_REUSEPORT* = cint(15) diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 536d51be5..304993dcb 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -557,6 +557,9 @@ when defined(linux) or defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "".}: cint +when defined(linux) or defined(bsd): + var SOCK_CLOEXEC* {.importc, header: "".}: cint + when defined(macosx): # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # Instead we should use SO_NOSIGPIPE in setsockopt diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 408e42255..1ff636517 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -532,6 +532,8 @@ when defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "".}: cint +var SOCK_CLOEXEC* {.importc, header: "".}: cint + var MSG_NOSIGNAL* {.importc, header: "".}: cint when hasSpawnH: diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 8213f796c..204cc3d9a 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -562,6 +562,9 @@ when defined(linux) or defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "".}: cint +when defined(linux) or defined(bsd): + var SOCK_CLOEXEC* {.importc, header: "".}: cint + when defined(macosx): # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # Instead we should use SO_NOSIGPIPE in setsockopt diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 9fcbe425d..f43407b40 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -99,6 +99,7 @@ var EXDEV* {.importc: "EXDEV", header: "".}: cint # var F_DUPFD* {.importc: "F_DUPFD", header: "".}: cint +var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD", header: "".}: cint var F_GETFD* {.importc: "F_GETFD", header: "".}: cint var F_SETFD* {.importc: "F_SETFD", header: "".}: cint var F_GETFL* {.importc: "F_GETFL", header: "".}: cint @@ -125,6 +126,7 @@ var O_ACCMODE* {.importc: "O_ACCMODE", header: "".}: cint var O_RDONLY* {.importc: "O_RDONLY", header: "".}: cint var O_RDWR* {.importc: "O_RDWR", header: "".}: cint var O_WRONLY* {.importc: "O_WRONLY", header: "".}: cint +var O_CLOEXEC* {.importc: "O_CLOEXEC", header: "".}: cint var POSIX_FADV_NORMAL* {.importc: "POSIX_FADV_NORMAL", header: "".}: cint var POSIX_FADV_SEQUENTIAL* {.importc: "POSIX_FADV_SEQUENTIAL", header: "".}: cint var POSIX_FADV_RANDOM* {.importc: "POSIX_FADV_RANDOM", header: "".}: cint diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 5dbb163ca..2d0288187 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -83,7 +83,11 @@ proc mkstemp*(prefix: string): (string, File) = ## The file is created with perms 0600. ## Returns the filename and a file opened in r/w mode. var tmpl = cstring(prefix & "XXXXXX") - let fd = mkstemp(tmpl) + let fd = + when declared(mkostemp): + mkostemp(tmpl, O_CLOEXEC) + else: + mkstemp(tmpl) var f: File if open(f, fd, fmReadWrite): return ($tmpl, f) diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index bf13cc83e..83f6001ea 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -81,7 +81,7 @@ proc newSelector*[T](): Selector[T] = # Start with a reasonable size, checkFd() will grow this on demand const numFD = 1024 - var epollFD = epoll_create(MAX_EPOLL_EVENTS) + var epollFD = epoll_create1(O_CLOEXEC) if epollFD < 0: raiseOSError(osLastError()) @@ -110,7 +110,7 @@ proc close*[T](s: Selector[T]) = raiseIOSelectorsError(osLastError()) proc newSelectEvent*(): SelectEvent = - let fdci = eventfd(0, 0) + let fdci = eventfd(0, O_CLOEXEC) if fdci == -1: raiseIOSelectorsError(osLastError()) setNonBlocking(fdci) @@ -269,7 +269,7 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool, var newTs: Itimerspec oldTs: Itimerspec - let fdi = timerfd_create(CLOCK_MONOTONIC, 0).int + let fdi = timerfd_create(CLOCK_MONOTONIC, O_CLOEXEC).int if fdi == -1: raiseIOSelectorsError(osLastError()) setNonBlocking(fdi.cint) @@ -314,7 +314,7 @@ when not defined(android): discard sigaddset(nmask, cint(signal)) blockSignals(nmask, omask) - let fdi = signalfd(-1, nmask, 0).int + let fdi = signalfd(-1, nmask, O_CLOEXEC).int if fdi == -1: raiseIOSelectorsError(osLastError()) setNonBlocking(fdi.cint) @@ -341,7 +341,7 @@ when not defined(android): discard sigaddset(nmask, posix.SIGCHLD) blockSignals(nmask, omask) - let fdi = signalfd(-1, nmask, 0).int + let fdi = signalfd(-1, nmask, O_CLOEXEC).int if fdi == -1: raiseIOSelectorsError(osLastError()) setNonBlocking(fdi.cint) diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 83e15d479..7635a04d5 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -9,7 +9,7 @@ # This module implements BSD kqueue(). -import posix, times, kqueue +import posix, times, kqueue, nativesockets const # Maximum number of events that can be returned. @@ -76,7 +76,7 @@ type proc getUnique[T](s: Selector[T]): int {.inline.} = # we create duplicated handles to get unique indexes for our `fds` array. - result = posix.fcntl(s.sock, F_DUPFD, s.sock) + result = posix.fcntl(s.sock, F_DUPFD_CLOEXEC, s.sock) if result == -1: raiseIOSelectorsError(osLastError()) @@ -96,8 +96,8 @@ proc newSelector*[T](): owned(Selector[T]) = # we allocating empty socket to duplicate it handle in future, to get unique # indexes for `fds` array. This is needed to properly identify # {Event.Timer, Event.Signal, Event.Process} events. - let usock = posix.socket(posix.AF_INET, posix.SOCK_STREAM, - posix.IPPROTO_TCP).cint + let usock = createNativeSocket(posix.AF_INET, posix.SOCK_STREAM, + posix.IPPROTO_TCP).cint if usock == -1: let err = osLastError() discard posix.close(kqFD) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 152b03ec6..dab5483e4 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -228,7 +228,7 @@ proc open*(filename: string, mode: FileMode = fmRead, if result.handle != -1: discard close(result.handle) raiseOSError(errCode) - var flags = if readonly: O_RDONLY else: O_RDWR + var flags = (if readonly: O_RDONLY else: O_RDWR) or O_CLOEXEC if newFileSize != -1: flags = flags or O_CREAT or O_TRUNC diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index d9256a921..8d0d6426d 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -185,19 +185,53 @@ proc toSockType*(protocol: Protocol): SockType = of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6: SOCK_RAW -proc createNativeSocket*(domain: Domain = AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP): SocketHandle = - ## Creates a new socket; returns `osInvalidSocket` if an error occurs. - socket(toInt(domain), toInt(sockType), toInt(protocol)) +proc close*(socket: SocketHandle) = + ## closes a socket. + when useWinVersion: + discard winlean.closesocket(socket) + else: + discard posix.close(socket) + # TODO: These values should not be discarded. An OSError should be raised. + # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times -proc createNativeSocket*(domain: cint, sockType: cint, - protocol: cint): SocketHandle = +when declared(setInheritable) or defined(nimdoc): + proc setInheritable*(s: SocketHandle, inheritable: bool): bool {.inline.} = + ## Set whether a socket is inheritable by child processes. Returns `true` + ## on success. + ## + ## This function is not implemented on all platform, test for availability + ## with `declared() `. + setInheritable(FileHandle s, inheritable) + +proc createNativeSocket*(domain: cint, sockType: cint, protocol: cint, + inheritable: bool = defined(nimInheritHandles)): SocketHandle = ## Creates a new socket; returns `osInvalidSocket` if an error occurs. ## + ## `inheritable` decides if the resulting SocketHandle can be inherited + ## by child processes. + ## ## Use this overload if one of the enums specified above does ## not contain what you need. - socket(domain, sockType, protocol) + let sockType = + when (defined(linux) or defined(bsd)) and not defined(nimdoc): + if inheritable: sockType and not SOCK_CLOEXEC else: sockType or SOCK_CLOEXEC + else: + sockType + result = socket(domain, sockType, protocol) + when declared(setInheritable) and not (defined(linux) or defined(bsd)): + if not setInheritable(result, inheritable): + close result + return osInvalidSocket + +proc createNativeSocket*(domain: Domain = AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, + inheritable: bool = defined(nimInheritHandles)): SocketHandle = + ## Creates a new socket; returns `osInvalidSocket` if an error occurs. + ## + ## `inheritable` decides if the resulting SocketHandle can be inherited + ## by child processes. + createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol)) proc newNativeSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, @@ -215,15 +249,6 @@ proc newNativeSocket*(domain: cint, sockType: cint, ## not contain what you need. createNativeSocket(domain, sockType, protocol) -proc close*(socket: SocketHandle) = - ## closes a socket. - when useWinVersion: - discard winlean.closesocket(socket) - else: - discard posix.close(socket) - # TODO: These values should not be discarded. An OSError should be raised. - # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times - proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint = result = bindSocket(socket, name, namelen) @@ -652,14 +677,25 @@ proc selectWrite*(writefds: var seq[SocketHandle], pruneSocketSet(writefds, (wr)) -proc accept*(fd: SocketHandle): (SocketHandle, string) = +proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (SocketHandle, string) = ## Accepts a new client connection. ## + ## `inheritable` decides if the resulting SocketHandle can be inherited by + ## child processes. + ## ## Returns (osInvalidSocket, "") if an error occurred. var sockAddress: Sockaddr_in var addrLen = sizeof(sockAddress).SockLen - var sock = accept(fd, cast[ptr SockAddr](addr(sockAddress)), - addr(addrLen)) + var sock = + when (defined(linux) or defined(bsd)) and not defined(nimdoc): + accept4(fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen), + if inheritable: 0 else: SOCK_CLOEXEC) + else: + accept(fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) + when declared(setInheritable) and not (defined(linux) or defined(bsd)): + if not setInheritable(sock, inheritable): + close sock + sock = osInvalidSocket if sock == osInvalidSocket: return (osInvalidSocket, "") else: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 593e5c76e..30355226c 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -212,22 +212,32 @@ proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET, when defined(macosx) and not defined(nimdoc): setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1) -proc newSocket*(domain, sockType, protocol: cint, buffered = true): owned(Socket) = +proc newSocket*(domain, sockType, protocol: cint, buffered = true, + inheritable = defined(nimInheritHandles)): owned(Socket) = ## Creates a new socket. ## + ## The SocketHandle associated with the resulting Socket will not be + ## inheritable by child processes by default. This can be changed via + ## the `inheritable` parameter. + ## ## If an error occurs OSError will be raised. - let fd = createNativeSocket(domain, sockType, protocol) + let fd = createNativeSocket(domain, sockType, protocol, inheritable) if fd == osInvalidSocket: raiseOSError(osLastError()) result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol, buffered) proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, buffered = true): owned(Socket) = + protocol: Protocol = IPPROTO_TCP, buffered = true, + inheritable = defined(nimInheritHandles)): owned(Socket) = ## Creates a new socket. ## + ## The SocketHandle associated with the resulting Socket will not be + ## inheritable by child processes by default. This can be changed via + ## the `inheritable` parameter. + ## ## If an error occurs OSError will be raised. - let fd = createNativeSocket(domain, sockType, protocol) + let fd = createNativeSocket(domain, sockType, protocol, inheritable) if fd == osInvalidSocket: raiseOSError(osLastError()) result = newSocket(fd, domain, sockType, protocol, buffered) @@ -872,7 +882,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. freeaddrinfo(aiList) proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, - flags = {SocketFlag.SafeDisconn}) {. + flags = {SocketFlag.SafeDisconn}, + inheritable = defined(nimInheritHandles)) {. tags: [ReadIOEffect], gcsafe, locks: 0.} = ## Blocks until a connection is being made from a client. When a connection ## is made sets ``client`` to the client socket and ``address`` to the address @@ -882,19 +893,23 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, ## The resulting client will inherit any properties of the server socket. For ## example: whether the socket is buffered or not. ## + ## The SocketHandle associated with the resulting client will not be + ## inheritable by child processes by default. This can be changed via + ## the `inheritable` parameter. + ## ## The ``accept`` call may result in an error if the connecting socket ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead ## accept will be called again. if client.isNil: new(client) - let ret = accept(server.fd) + let ret = accept(server.fd, inheritable) let sock = ret[0] if sock == osInvalidSocket: let err = osLastError() if flags.isDisconnectionError(err): - acceptAddr(server, client, address, flags) + acceptAddr(server, client, address, flags, inheritable) raiseOSError(err) else: address = ret[1] @@ -964,10 +979,16 @@ when false: #defineSsl: doHandshake() proc accept*(server: Socket, client: var owned(Socket), - flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} = + flags = {SocketFlag.SafeDisconn}, + inheritable = defined(nimInheritHandles)) + {.tags: [ReadIOEffect].} = ## Equivalent to ``acceptAddr`` but doesn't return the address, only the ## socket. ## + ## The SocketHandle associated with the resulting client will not be + ## inheritable by child processes by default. This can be changed via + ## the `inheritable` parameter. + ## ## The ``accept`` call may result in an error if the connecting socket ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead diff --git a/lib/system/io.nim b/lib/system/io.nim index 9a4502cba..f8358962f 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -259,6 +259,31 @@ else: IOFBF {.importc: "_IOFBF", nodecl.}: cint IONBF {.importc: "_IONBF", nodecl.}: cint +const SupportIoctlInheritCtl = (defined(linux) or defined(bsd)) and + not defined(nimscript) +when SupportIoctlInheritCtl: + var + FIOCLEX {.importc, header: "".}: cint + FIONCLEX {.importc, header: "".}: cint + + proc c_ioctl(fd: cint, request: cint): cint {. + importc: "ioctl", header: "", varargs.} +elif defined(posix) and not defined(nimscript): + var + F_GETFD {.importc, header: "".}: cint + F_SETFD {.importc, header: "".}: cint + FD_CLOEXEC {.importc, header: "".}: cint + + proc c_fcntl(fd: cint, cmd: cint): cint {. + importc: "fcntl", header: "", varargs.} +elif defined(windows): + const HANDLE_FLAG_INHERIT = culong 0x1 + proc getOsfhandle(fd: cint): FileHandle {. + importc: "_get_osfhandle", header: "".} + + proc setHandleInformation(handle: FileHandle, mask, flags: culong): cint {. + importc: "SetHandleInformation", header: "".} + const BufSize = 4000 @@ -292,12 +317,29 @@ proc getOsFileHandle*(f: File): FileHandle = ## returns the OS file handle of the file ``f``. This is only useful for ## platform specific programming. when defined(windows): - proc getOsfhandle(fd: cint): FileHandle {. - importc: "_get_osfhandle", header: "".} result = getOsfhandle(getFileHandle(f)) else: result = c_fileno(f) +when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(windows): + proc setInheritable*(f: FileHandle, inheritable: bool): bool = + ## control whether a file handle can be inherited by child processes. Returns + ## ``true`` on success. This requires the OS file handle, which can be + ## retrieved via `getOsFileHandle <#getOsFileHandle,File>`_. + ## + ## This procedure is not guaranteed to be available for all platforms. Test for + ## availability with `declared() `. + when SupportIoctlInheritCtl: + result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1 + elif defined(posix): + var flags = c_fcntl(f, F_GETFD) + if flags == -1: + return false + flags = if inheritable: flags and not FD_CLOEXEC else: flags or FD_CLOEXEC + result = c_fcntl(f, F_SETFD, flags) != -1 + else: + result = setHandleInformation(f, HANDLE_FLAG_INHERIT, culong inheritable) != 0 + proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} = ## reads a line of text from the file `f` into `line`. May throw an IO @@ -501,7 +543,21 @@ else: importc: "freopen", nodecl.} const - FormatOpen: array[FileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"] + NoInheritFlag = + # Platform specific flag for creating a File without inheritance. + when not defined(nimInheritHandles): + when defined(windows): + "N" + elif defined(linux) or defined(bsd): + "e" + else: + "" + else: + "" + FormatOpen: array[FileMode, string] = [ + "rb" & NoInheritFlag, "wb" & NoInheritFlag, "w+b" & NoInheritFlag, + "r+b" & NoInheritFlag, "ab" & NoInheritFlag + ] #"rt", "wt", "w+t", "r+t", "at" # we always use binary here as for Nim the OS line ending # should not be translated. @@ -544,17 +600,25 @@ proc open*(f: var File, filename: string, ## ## Default mode is readonly. Returns true iff the file could be opened. ## This throws no exception if the file could not be opened. + ## + ## The file handle associated with the resulting ``File`` is not inheritable. var p = fopen(filename, FormatOpen[mode]) if p != nil: + var f2 = cast[File](p) when defined(posix) and not defined(nimscript): # How `fopen` handles opening a directory is not specified in ISO C and # POSIX. We do not want to handle directories as regular files that can # be opened. - var f2 = cast[File](p) var res: Stat if c_fstat(getFileHandle(f2), res) >= 0'i32 and modeIsDir(res.st_mode): close(f2) return false + when not defined(nimInheritHandles) and declared(setInheritable) and + NoInheritFlag.len == 0: + if not setInheritable(getOsFileHandle(f2), false): + close(f2) + return false + result = true f = cast[File](p) if bufSize > 0 and bufSize <= high(cint).int: @@ -569,13 +633,27 @@ proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. ## file variables. ## ## Default mode is readonly. Returns true iff the file could be reopened. - result = freopen(filename, FormatOpen[mode], f) != nil + ## + ## The file handle associated with `f` won't be inheritable. + if freopen(filename, FormatOpen[mode], f) != nil: + when not defined(nimInheritHandles) and declared(setInheritable) and + NoInheritFlag.len == 0: + if not setInheritable(getOsFileHandle(f), false): + close(f) + return false + result = true proc open*(f: var File, filehandle: FileHandle, mode: FileMode = fmRead): bool {.tags: [], raises: [], benign.} = ## Creates a ``File`` from a `filehandle` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. + ## + ## The passed file handle will no longer be inheritable. + when not defined(nimInheritHandles) and declared(setInheritable): + let oshandle = when defined(windows): getOsfhandle(filehandle) else: filehandle + if not setInheritable(oshandle, false): + return false f = c_fdopen(filehandle, FormatOpen[mode]) result = f != nil @@ -585,6 +663,8 @@ proc open*(filename: string, ## ## Default mode is readonly. Raises an ``IOError`` if the file ## could not be opened. + ## + ## The file handle associated with the resulting ``File`` is not inheritable. if not open(result, filename, mode, bufSize): sysFatal(IOError, "cannot open: " & filename) diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index ee8c2343a..f749c508d 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -126,6 +126,8 @@ const CREATE_NO_WINDOW* = 0x08000000'i32 + HANDLE_FLAG_INHERIT* = 0x00000001'i32 + proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. stdcall, dynlib: "kernel32", importc: "GetVersionExW", sideEffect.} proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {. @@ -708,6 +710,9 @@ proc duplicateHandle*(hSourceProcessHandle: Handle, hSourceHandle: Handle, dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "DuplicateHandle".} +proc getHandleInformation*(hObject: Handle, lpdwFlags: ptr DWORD): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "GetHandleInformation".} + proc setHandleInformation*(hObject: Handle, dwMask: DWORD, dwFlags: DWORD): WINBOOL {.stdcall, dynlib: "kernel32", importc: "SetHandleInformation".} diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim new file mode 100644 index 000000000..08ef06da3 --- /dev/null +++ b/tests/stdlib/tfdleak.nim @@ -0,0 +1,85 @@ +discard """ + exitcode: 0 + output: "" + matrix: "; -d:nimInheritHandles" +""" + +import os, osproc, strutils, nativesockets, net, selectors, memfiles +when defined(windows): + import winlean +else: + import posix + +proc leakCheck(f: int | FileHandle | SocketHandle, msg: string, expectLeak = defined(nimInheritHandles)) = + discard startProcess( + getAppFilename(), + args = @[$f.int, msg, $expectLeak], + options = {poParentStreams} + ).waitForExit -1 + +proc isValidHandle(f: int): bool = + ## Check if a handle is valid. Requires OS-native handles. + when defined(windows): + var flags: DWORD + result = getHandleInformation(f.Handle, addr flags) != 0 + else: + result = fcntl(f.cint, F_GETFD) != -1 + +proc main() = + if paramCount() == 0: + # Parent process + let f = system.open("__test_fdleak", fmReadWrite) + defer: close f + + leakCheck(f.getOsFileHandle, "system.open()") + + doAssert f.reopen("__test_fdleak2", fmReadWrite), "reopen failed" + + leakCheck(f.getOsFileHandle, "reopen") + + let sock = createNativeSocket() + defer: close sock + leakCheck(sock, "createNativeSocket()") + if sock.setInheritable(true): + leakCheck(sock, "createNativeSocket()", true) + else: + raiseOSError osLastError() + + let server = newSocket() + defer: close server + server.bindAddr() + server.listen() + let (_, port) = server.getLocalAddr + + leakCheck(server.getFd, "newSocket()") + + let client = newSocket() + defer: close client + client.connect("127.0.0.1", port) + + var input: Socket + server.accept(input) + + leakCheck(input.getFd, "accept()") + + # ioselectors_select doesn't support returning a handle. + when not defined(windows): + let selector = newSelector[int]() + leakCheck(selector.getFd, "selector()", false) + + var mf = memfiles.open("__test_fdleak3", fmReadWrite, newFileSize = 1) + defer: close mf + when defined(windows): + leakCheck(mf.fHandle, "memfiles.open().fHandle", false) + leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false) + else: + leakCheck(mf.handle, "memfiles.open().handle", false) + else: + let + fd = parseInt(paramStr 1) + expectLeak = parseBool(paramStr 3) + msg = (if expectLeak: "not " else: "") & "leaked " & paramStr 2 + if expectLeak xor fd.isValidHandle: + echo msg + +when isMainModule: main() diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index fcbedcfcd..0a19a7951 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -228,6 +228,7 @@ v("EXDEV") header("") v("F_DUPFD") +v("F_DUPFD_CLOEXEC") v("F_GETFD") v("F_SETFD") v("F_GETFL") @@ -254,6 +255,7 @@ v("O_ACCMODE") v("O_RDONLY") v("O_RDWR") v("O_WRONLY") +v("O_CLOEXEC") v("POSIX_FADV_NORMAL") v("POSIX_FADV_SEQUENTIAL") v("POSIX_FADV_RANDOM") @@ -621,6 +623,7 @@ v("SOCK_DGRAM") v("SOCK_RAW") v("SOCK_SEQPACKET") v("SOCK_STREAM") +v("SOCK_CLOEXEC", no_other = true) v("SOL_SOCKET") v("SOMAXCONN") v("SO_REUSEPORT", no_other = true) From 67d71bb76d4c3d78302a452623d4507c783c6cc9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Apr 2020 23:44:29 +0200 Subject: [PATCH 0356/4254] fixes #14038 --- lib/system/seqs_v2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 097ab269c..175056f48 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -75,7 +75,7 @@ proc shrink*[T](x: var seq[T]; newLen: Natural) = setLen(x, newLen) else: mixin `=destroy` - sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" + #sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" when not supportsCopyMem(T): for i in countdown(x.len - 1, newLen): `=destroy`(x[i]) From 42a64245f81c1975845f1f4e8018f97ef350c153 Mon Sep 17 00:00:00 2001 From: Tristram Oaten Date: Mon, 20 Apr 2020 17:44:25 +0100 Subject: [PATCH 0357/4254] Fix broken async httpclient example As the async httpclient is almost certainly the first async example beginners will want to try, we OWE it to them to give them a real example. Example repeated here for clarity: ```nim import asyncdispatch, httpclient proc asyncProc(): Future[string] {.async.} = var client = newAsyncHttpClient() return await client.getContent("http://example.com") echo waitFor asyncProc() ``` This is my first Nim contribution, please let me know if the code is right. (it runs on my machine, but may not be the best example) --- lib/pure/httpclient.nim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 5c53c1a39..5d44fce7a 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -25,15 +25,19 @@ ## ``AsyncHttpClient``: ## ## .. code-block:: Nim -## import httpClient +## import asyncdispatch, httpclient +## +## proc asyncProc(): Future[string] {.async.} = ## var client = newAsyncHttpClient() -## echo await client.getContent("http://google.com") +## return await client.getContent("http://example.com") +## +## echo waitFor asyncProc() ## ## The functionality implemented by ``HttpClient`` and ``AsyncHttpClient`` ## is the same, so you can use whichever one suits you best in the examples ## shown here. ## -## **Note:** You will need to run asynchronous examples in an async proc +## **Note:** You need to run asynchronous examples in an async proc ## otherwise you will get an ``Undeclared identifier: 'await'`` error. ## ## Using HTTP POST From 3fe3db3c0d235f49f714a2b747b458282955d279 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Tue, 21 Apr 2020 12:21:12 +0300 Subject: [PATCH 0358/4254] clarify tuples and objects in manual, fixes #12486 (#14044) --- doc/manual.rst | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 84cf1d8c9..695e23ef0 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1482,8 +1482,8 @@ Tuples and object types A variable of a tuple or object type is a heterogeneous storage container. A tuple or object defines various named *fields* of a type. A tuple also -defines an *order* of the fields. Tuples are meant for heterogeneous storage -types with no overhead and few abstraction possibilities. The constructor ``()`` +defines a lexicographic *order* of the fields. Tuples are meant to be +heterogeneous storage types with few abstractions. The ``()`` syntax can be used to construct tuples. The order of the fields in the constructor must match the order of the tuple's definition. Different tuple-types are *equivalent* if they specify the same fields of the same type in the same @@ -1503,8 +1503,10 @@ of the assignment operator is described `here var person: Person person = (name: "Peter", age: 30) + echo person.name # the same, but less readable: person = ("Peter", 30) + echo person[0] A tuple with one unnamed field can be constructed with the parentheses and a trailing comma: @@ -1528,11 +1530,12 @@ can also be defined with indentation instead of ``[]``: type Person = tuple # type representing a person name: string # a person consists of a name - age: natural # and an age + age: Natural # and an age Objects provide many features that tuples do not. Object provide inheritance and -information hiding. Objects have access to their type during at runtime, so that -the ``of`` operator can be used to determine the object's type. The ``of`` +the ability to hide fields from other modules. Objects with inheritance enabled +have information about their type at runtime, so that the ``of`` operator can be +used to determine the object's type. The ``of`` operator is similar to the ``instanceof`` operator in Java. .. code-block:: nim @@ -1552,10 +1555,20 @@ operator is similar to the ``instanceof`` operator in Java. Object fields that should be visible from outside the defining module, have to be marked by ``*``. In contrast to tuples, different object types are -never *equivalent*. Objects that have no ancestor are implicitly ``final`` -and thus have no hidden type field. One can use the ``inheritable`` pragma to +never *equivalent*, they are nominal types whereas tuples are structural. +Objects that have no ancestor are implicitly ``final`` and thus have no hidden +type information. One can use the ``inheritable`` pragma to introduce new object roots apart from ``system.RootObj``. +.. code-block:: nim + type + Person = object # example of a final object + name*: string + age: int + + Student = ref object of Person # Error: inheritance only works with non-final objects + id: int + Object construction ------------------- From 7beed44fc9e80882ba54f222994e522377c1ad1d Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 21 Apr 2020 09:21:36 +0000 Subject: [PATCH 0359/4254] asyncdispatch: export Callback (#14042) [backport] This let us see the definition of `Callback` in docs, which is required to even make use of asyncdispatch. Ref #13539. --- lib/pure/asyncdispatch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5fd5a45fd..87c6aa7e2 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -267,7 +267,7 @@ when defined(windows) or defined(nimdoc): pcd: PostCallbackDataPtr AsyncEvent* = ptr AsyncEventImpl - Callback = proc (fd: AsyncFD): bool {.closure, gcsafe.} + Callback* = proc (fd: AsyncFD): bool {.closure, gcsafe.} proc hash(x: AsyncFD): Hash {.borrow.} proc `==`*(x: AsyncFD, y: AsyncFD): bool {.borrow.} @@ -1098,7 +1098,7 @@ else: # queue. type AsyncFD* = distinct cint - Callback = proc (fd: AsyncFD): bool {.closure, gcsafe.} + Callback* = proc (fd: AsyncFD): bool {.closure, gcsafe.} AsyncData = object readList: seq[Callback] From 1a44b7e3ced0e2d092f2c607d61a6b28c1ca339c Mon Sep 17 00:00:00 2001 From: Tristram Oaten Date: Tue, 21 Apr 2020 13:47:06 +0100 Subject: [PATCH 0360/4254] New runnableExample for `newAsyncHttpClient()` (#14045) --- lib/pure/httpclient.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 5d44fce7a..a1a2d9129 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -573,6 +573,17 @@ proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, ## ``TimeoutError`` is raised. ## ## ``headers`` specifies the HTTP Headers. + runnableExamples: + import asyncdispatch, httpclient, strutils + + proc asyncProc(): Future[string] {.async.} = + var client = newAsyncHttpClient() + return await client.getContent("http://example.com") + + let exampleHtml = waitFor asyncProc() + assert "Example Domain" in exampleHtml + assert not ("Pizza" in exampleHtml) + new result result.headers = headers result.userAgent = userAgent From 04c326569bdafa619d6596d2d674d3acbcc1ecf3 Mon Sep 17 00:00:00 2001 From: Judd Date: Tue, 21 Apr 2020 20:50:16 +0800 Subject: [PATCH 0361/4254] fix mapIt issues #12625 & #12639 (#14041) * fix mapIt issues #12625 & #12639: 1. fallback to call `map` when the result of `op` is a closure; 2. use `items(s)` in the for loop. * fix test errors. * add comments and InType is moved. * fix ident. --- lib/pure/collections/sequtils.nim | 50 ++++++++++++++++++++++--------- tests/collections/tseq.nim | 3 ++ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index ea02ff1fd..02d48973e 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -924,24 +924,46 @@ template mapIt*(s: typed, op: untyped): untyped = block: var it{.inject.}: type(items(s)); op)) - when compiles(s.len): - block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 + when OutType is not (proc): + # Here, we avoid to create closures in loops. + # This avoids https://github.com/nim-lang/Nim/issues/12625 + when compiles(s.len): + block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 - # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors - # (`error: use of undeclared identifier`) instead of Nim compile errors - evalOnceAs(s2, s, compiles((let _ = s))) + # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors + # (`error: use of undeclared identifier`) instead of Nim compile errors + evalOnceAs(s2, s, compiles((let _ = s))) - var i = 0 - var result = newSeq[OutType](s2.len) - for it {.inject.} in s2: - result[i] = op - i += 1 + var i = 0 + var result = newSeq[OutType](s2.len) + for it {.inject.} in s2: + result[i] = op + i += 1 + result + else: + var result: seq[OutType] = @[] + # use `items` to avoid https://github.com/nim-lang/Nim/issues/12639 + for it {.inject.} in items(s): + result.add(op) result else: - var result: seq[OutType] = @[] - for it {.inject.} in s: - result.add(op) - result + # `op` is going to create closures in loops, let's fallback to `map`. + # NOTE: Without this fallback, developers have to define a helper function and + # call `map`: + # [1, 2].map((it) => ((x: int) => it + x)) + # With this fallback, above code can be simplified to: + # [1, 2].mapIt((x: int) => it + x) + # In this case, `mapIt` is just syntax sugar for `map`. + + when defined(nimHasTypeof): + type InType = typeof(items(s), typeOfIter) + else: + type InType = type(items(s)) + # Use a help proc `f` to create closures for each element in `s` + let f = proc (x: InType): OutType = + let it {.inject.} = x + op + map(s, f) template applyIt*(varSeq, op: untyped) = ## Convenience template around the mutable ``apply`` proc to reduce typing. diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim index 6a28bc8e6..ac68e5636 100644 --- a/tests/collections/tseq.nim +++ b/tests/collections/tseq.nim @@ -204,3 +204,6 @@ block ttoseq: var y: type("a b c".split) y = "xzy" stdout.write("\n") + +block tseqmapitchain: + doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100)) \ No newline at end of file From b8b0e9b21d0b6da8c807efc6bbb339cd89c6236f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Tue, 21 Apr 2020 08:54:43 -0400 Subject: [PATCH 0362/4254] docs: move `not nil` to the experimental page (#14027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When I heard that this feature existed, and found the 2018 changelog entry that said `not nil` was made experimental (https://github.com/nim-lang/Nim/blob/devel/changelogs/changelog_0_19_0.md#changes-affecting-backwards-compatibility), I looked for `not nil` documentation in https://nim-lang.org/docs/manual_experimental.html. When I didn’t find it there, I initially assumed the feature had no documentation. This change moves the documentation to where readers will expect it. As well as moving the text to another file, I added instructions for enabling the experimental feature and tweaked some wording. --- doc/manual.rst | 26 -------------------------- doc/manual_experimental.rst | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 695e23ef0..595ddfcef 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1851,32 +1851,6 @@ details like this when mixing garbage collected data with unmanaged memory. .. XXX finalizers for traced objects -Not nil annotation ------------------- - -All types for which ``nil`` is a valid value can be annotated to -exclude ``nil`` as a valid value with the ``not nil`` annotation: - -.. code-block:: nim - type - PObject = ref TObj not nil - TProc = (proc (x, y: int)) not nil - - proc p(x: PObject) = - echo "not nil" - - # compiler catches this: - p(nil) - - # and also this: - var x: PObject - p(x) - -The compiler ensures that every code path initializes variables which contain -non nilable pointers. The details of this analysis are still to be specified -here. - - Procedural type --------------- A procedural type is internally a pointer to a procedure. ``nil`` is diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 8c61c1217..f65c0933b 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -340,6 +340,36 @@ This operator will be matched against assignments to missing fields. a.b = c # becomes `.=`(a, b, c) +Not nil annotation +================== + +**Note:** This is an experimental feature. It can be enabled with +``{.experimental: "notnil"}``. + +All types for which ``nil`` is a valid value can be annotated with the ``not +nil`` annotation to exclude ``nil`` as a valid value: + +.. code-block:: nim + {.experimental: "notnil"} + + type + PObject = ref TObj not nil + TProc = (proc (x, y: int)) not nil + + proc p(x: PObject) = + echo "not nil" + + # compiler catches this: + p(nil) + + # and also this: + var x: PObject + p(x) + +The compiler ensures that every code path initializes variables which contain +non-nilable pointers. The details of this analysis are still to be specified +here. + Concepts ======== From 89e6a7ab48584e2bcfc4a5c1997c292671d2bb6c Mon Sep 17 00:00:00 2001 From: treeform Date: Tue, 21 Apr 2020 05:57:19 -0700 Subject: [PATCH 0363/4254] Fix the getSelection method. (#13632) --- lib/js/dom.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index a0df4b7b9..a6fdf3326 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -103,6 +103,8 @@ type memory*: PerformanceMemory timing*: PerformanceTiming + Selection* {.importc.} = ref object ## see `docs`_ + LocalStorage* {.importc.} = ref object Window* = ref WindowObj @@ -1155,7 +1157,7 @@ proc createAttribute*(d: Document, identifier: cstring): Node proc getElementsByName*(d: Document, name: cstring): seq[Element] proc getElementsByTagName*(d: Document, name: cstring): seq[Element] proc getElementsByClassName*(d: Document, name: cstring): seq[Element] -proc getSelection*(d: Document): cstring +proc getSelection*(d: Document): Selection proc handleEvent*(d: Document, event: Event) proc open*(d: Document) proc releaseEvents*(d: Document, eventMask: int) {.deprecated.} @@ -1245,6 +1247,11 @@ proc slice*(e: Blob, startindex: int = 0, endindex: int = e.size, contentType: c # Performance "methods" proc now*(p: Performance): float +# Selection "methods" +proc removeAllRanges*(s: Selection) +converter toString*(s: Selection): cstring +proc `$`*(s: Selection): string = $(s.toString()) + # LocalStorage "methods" proc getItem*(ls: LocalStorage, key: cstring): cstring proc setItem*(ls: LocalStorage, key, value: cstring) From 7828199827cac4056a008d679cb5c45ff3d34f6e Mon Sep 17 00:00:00 2001 From: Euan Date: Tue, 21 Apr 2020 14:05:21 +0100 Subject: [PATCH 0364/4254] #12103 - CI for OpenBSD (#12105) * Working on OpenBSD CI * Condense steps into 2 steps to make output easier to follow. * Move up one directory after csources build. * Remove FreeBSD build manifest and add OpenBSD test ignores for coroutines and hot code reloading. * If runCI fails, run the test results script. * Add email trigger for build failure * Remove .git from repository URL * Disable SFML test on OpenBSD * Disable tgetaddrinfo on OpenBSD as only UDP and TCP protocols are supported. * Remove getFilePermissions as it causes CI test failures with NimScript. * Set clang as cc in nim.cfg and use gmake to build csources. * Add getCurrentDir to nimscript. * Remove duplicate getCurrentDir and check for not weirdTarget. * Add CI badge for OpenBSD. * Disable tests which allocate lots of memory for OpenBSD. * Use `CORO_BACKEND_SETJMP` on OpenBSD rather than ucontext. * Simplify building of koch * Disable t8657 on OpenBSD. See issue #13760. * Fix #12142 - tarray_of_channels fails on OpenBSD * Disable thhtpclient_ssl and tosprocterminate on OpenBSD. These tests can be enabled at a later date after fixing them. * Install libffi. * Set path to libc for openbsd. * Disable tevalffi for now. * Remove tevalffi.nim. * Use ncpuonline sysctl rather than ncpu. * Disable tacceptcloserace and tasynchttpserver on OpenBSD. * Enable tacceptcloserace and tasynchttpserver. * Fix #13775 as suggested by @alaviss - use /bin/cat on OpenBSD rather than /bin/sh. * Enable test on OpenBSD. * Disable tflowvar on OpenBSD. --- .builds/openbsd.yml | 31 +++++++++++++++++++ compiler/evalffi.nim | 2 ++ config/nim.cfg | 2 +- lib/pure/coro.nim | 2 +- lib/pure/os.nim | 13 ++------ readme.md | 2 +- testament/specs.nim | 2 ++ tests/coroutines/tgc.nim | 1 + tests/coroutines/twait.nim | 1 + tests/dll/nimhcr_integration.nim | 3 +- tests/dll/nimhcr_unit.nim | 1 + tests/exception/t9657.nim | 1 + tests/niminaction/Chapter8/sfml/sfml_test.nim | 1 + tests/parallel/tarray_of_channels.nim | 1 + tests/parallel/tflowvar.nim | 1 + tests/stdlib/tgetaddrinfo.nim | 2 +- tests/stdlib/thttpclient_ssl.nim | 1 + tests/stdlib/tosprocterminate.nim | 2 ++ tests/system/talloc2.nim | 1 + tests/system/trealloc.nim | 1 + 20 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 .builds/openbsd.yml diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml new file mode 100644 index 000000000..c4db2f621 --- /dev/null +++ b/.builds/openbsd.yml @@ -0,0 +1,31 @@ +image: openbsd/latest +packages: +- gmake +- sqlite3 +- node +- boehm-gc +- pcre +- sfml +- sdl2 +- libffi +sources: +- https://github.com/nim-lang/Nim +environment: + CC: /usr/bin/clang +tasks: +- setup: | + cd Nim + git clone --depth 1 -q https://github.com/nim-lang/csources.git + gmake -C csources -j $(sysctl -n hw.ncpuonline) + bin/nim c koch + echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv +- test: | + cd Nim + if ! ./koch runCI; then + nim c -r tools/ci_testresults.nim + exit 1 + fi +triggers: +- action: email + condition: failure + to: Andreas Rumpf diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 58c505a5b..f89451f51 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -17,6 +17,8 @@ when defined(windows): const libcDll = "msvcrt.dll" elif defined(linux): const libcDll = "libc.so(.6|.5|)" +elif defined(openbsd): + const libcDll = "/usr/lib/libc.so(.95.1|)" elif defined(bsd): const libcDll = "/lib/libc.so.7" elif defined(osx): diff --git a/config/nim.cfg b/config/nim.cfg index 9f152b879..eea04ec11 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -167,7 +167,7 @@ path="$lib/pure" @end @end -@if macosx or freebsd: +@if macosx or freebsd or openbsd: cc = clang tlsEmulation:on gcc.options.always = "-w" diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 350b9f187..ead3849c6 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -48,7 +48,7 @@ when defined(windows): {.warning: "ucontext coroutine backend is not available on windows, defaulting to fibers.".} when defined(nimCoroutinesSetjmp): {.warning: "setjmp coroutine backend is not available on windows, defaulting to fibers.".} -elif defined(haiku): +elif defined(haiku) or defined(openbsd): const coroBackend = CORO_BACKEND_SETJMP when defined(nimCoroutinesUcontext): {.warning: "ucontext coroutine backend is not available on haiku, defaulting to setjmp".} diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 98143bc1a..e1e5f31b4 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2818,11 +2818,7 @@ when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or len = readlink(procPath, result, len) setLen(result, len) -when defined(openbsd): - proc isExecutable(path: string): bool = - let p = getFilePermissions(path) - result = fpUserExec in p and fpGroupExec in p and fpOthersExec in p - +when not weirdTarget and defined(openbsd): proc getApplOpenBsd(): string = # similar to getApplHeuristic, but checks current working directory when declared(paramStr): @@ -2846,15 +2842,12 @@ when defined(openbsd): break if len(result) > 0: - if isExecutable(result): - return expandFilename(result) - - return "" + return expandFilename(result) # search in path for p in split(string(getEnv("PATH")), {PathSep}): var x = joinPath(p, exePath) - if existsFile(x) and isExecutable(x): + if existsFile(x): return expandFilename(x) else: result = "" diff --git a/readme.md b/readme.md index 59107af34..575d856bb 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# Nim [![Build Status][badge-nim-travisci]][nim-travisci] [![builds.sr.ht freebsd status](https://builds.sr.ht/~araq/nim/freebsd.yml.svg)](https://builds.sr.ht/~araq/nim/freebsd.yml?) +# Nim [![Build Status][badge-nim-travisci]][nim-travisci] [![builds.sr.ht freebsd status](https://builds.sr.ht/~araq/nim/freebsd.yml.svg)](https://builds.sr.ht/~araq/nim/freebsd.yml?) [![builds.sr.ht openbsd status](https://builds.sr.ht/~araq/nim/openbsd.yml.svg)](https://builds.sr.ht/~araq/nim/openbsd.yml?) This repository contains the Nim compiler, Nim's stdlib, tools and documentation. For more information about Nim, including downloads and documentation for diff --git a/testament/specs.nim b/testament/specs.nim index d0770d03e..c988222f4 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -237,6 +237,8 @@ proc parseSpec*(filename: string): TSpec = when defined(freebsd): result.err = reDisabled of "arm64": when defined(arm64): result.err = reDisabled + of "openbsd": + when defined(openbsd): result.err = reDisabled else: result.parseErrors.addLine "cannot interpret as a bool: ", e.value of "cmd": diff --git a/tests/coroutines/tgc.nim b/tests/coroutines/tgc.nim index 46f4f8e83..86b625370 100644 --- a/tests/coroutines/tgc.nim +++ b/tests/coroutines/tgc.nim @@ -1,5 +1,6 @@ discard """ target: "c" + disabled: "openbsd" """ import coro diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim index 1769966ab..2563ad7d3 100644 --- a/tests/coroutines/twait.nim +++ b/tests/coroutines/twait.nim @@ -1,6 +1,7 @@ discard """ output: "Exit 1\nExit 2" disabled: "macosx" + disabled: "openbsd" target: "c" """ import coro diff --git a/tests/dll/nimhcr_integration.nim b/tests/dll/nimhcr_integration.nim index 64f6bb708..3f73341be 100644 --- a/tests/dll/nimhcr_integration.nim +++ b/tests/dll/nimhcr_integration.nim @@ -1,4 +1,5 @@ discard """ + disabled: "openbsd" disabled: "macosx" output: ''' main: HELLO! @@ -151,4 +152,4 @@ update 0 update 1 update 2 -echo "done" +echo "done" \ No newline at end of file diff --git a/tests/dll/nimhcr_unit.nim b/tests/dll/nimhcr_unit.nim index f539a53c8..31f398258 100644 --- a/tests/dll/nimhcr_unit.nim +++ b/tests/dll/nimhcr_unit.nim @@ -1,4 +1,5 @@ discard """ +disabled: "openbsd" output: ''' fastcall_proc implementation #1 10 11 diff --git a/tests/exception/t9657.nim b/tests/exception/t9657.nim index 0b6e128e0..1023f9593 100644 --- a/tests/exception/t9657.nim +++ b/tests/exception/t9657.nim @@ -2,6 +2,7 @@ discard """ action: run exitcode: 1 target: "c" + disabled: "openbsd" """ # todo: remove `target: "c"` workaround once #10343 is properly fixed close stdmsg diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim index 3c158d1de..5280196c2 100644 --- a/tests/niminaction/Chapter8/sfml/sfml_test.nim +++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim @@ -2,6 +2,7 @@ discard """ action: compile disabled: "windows" disabled: "freebsd" +disabled: "openbsd" """ import sfml, os diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim index 5139920ea..9479227aa 100644 --- a/tests/parallel/tarray_of_channels.nim +++ b/tests/parallel/tarray_of_channels.nim @@ -8,6 +8,7 @@ test test test ''' +disabled: "openbsd" """ # bug #2257 diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim index fd3aa326e..9d93bc7c8 100644 --- a/tests/parallel/tflowvar.nim +++ b/tests/parallel/tflowvar.nim @@ -4,6 +4,7 @@ bazbearbazbear 1''' cmd: "nim $target --threads:on $options $file" + disabled: "openbsd" """ import threadpool diff --git a/tests/stdlib/tgetaddrinfo.nim b/tests/stdlib/tgetaddrinfo.nim index 225546aa9..1c9d020a1 100644 --- a/tests/stdlib/tgetaddrinfo.nim +++ b/tests/stdlib/tgetaddrinfo.nim @@ -15,7 +15,7 @@ block DGRAM_UDP: doAssert aiList.ai_next == nil freeAddrInfo aiList -when defined(posix) and not defined(haiku) and not defined(freebsd): +when defined(posix) and not defined(haiku) and not defined(freebsd) and not defined(openbsd): block RAW_ICMP: # the port will be ignored diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index f247ae442..aa278c811 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -1,5 +1,6 @@ discard """ cmd: "nim $target --threads:on -d:ssl $options $file" + disabled: "openbsd" """ # Nim - Basic SSL integration tests diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim index d487b5e60..c02e0a8da 100644 --- a/tests/stdlib/tosprocterminate.nim +++ b/tests/stdlib/tosprocterminate.nim @@ -8,6 +8,8 @@ import os, osproc, times, std / monotimes when defined(Windows): const ProgramWhichDoesNotEnd = "notepad" +elif defined(openbsd): + const ProgramWhichDoesNotEnd = "/bin/cat" else: const ProgramWhichDoesNotEnd = "/bin/sh" diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim index a321fe741..c498a3f4b 100644 --- a/tests/system/talloc2.nim +++ b/tests/system/talloc2.nim @@ -1,5 +1,6 @@ discard """ disabled: "windows" +disabled: "openbsd" joinable: false disabled: 32bit """ diff --git a/tests/system/trealloc.nim b/tests/system/trealloc.nim index e8d772dbd..1d3e00aff 100644 --- a/tests/system/trealloc.nim +++ b/tests/system/trealloc.nim @@ -1,6 +1,7 @@ discard """ output: '''success''' joinable: false + disabled: "openbsd" """ # bug #4818 From 218cbf0e090cb8de1b859fcd4f9c54eec69e5437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Tue, 21 Apr 2020 17:07:37 +0200 Subject: [PATCH 0365/4254] Times refactorings (#13949) --- lib/pure/times.nim | 1573 ++++++++++++++++++++++---------------------- 1 file changed, 799 insertions(+), 774 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 2313afbff..23854fea7 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -283,19 +283,6 @@ type dSat = "Saturday" dSun = "Sunday" -when defined(nimHasStyleChecks): - {.push styleChecks: off.} - -type - DateTimeLocale* = object - MMM*: array[mJan..mDec, string] - MMMM*: array[mJan..mDec, string] - ddd*: array[dMon..dSun, string] - dddd*: array[dMon..dSun, string] - -when defined(nimHasStyleChecks): - {.pop.} - type MonthdayRange* = range[0..31] ## 0 represents an invalid day of the month @@ -414,7 +401,6 @@ type DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts - TimesMutableTypes = DateTime | Time | Duration | TimeInterval const secondsInMin = 60 @@ -436,15 +422,11 @@ const unitWeights: array[FixedTimeUnit, int64] = [ 7 * secondsInDay * 1e9.int64, ] -const DefaultLocale* = DateTimeLocale( - MMM: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", - "Nov", "Dec"], - MMMM: ["January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December"], - ddd: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - dddd: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", - "Sunday"], -) +# +# Helper procs +# + +{.pragma: operator, rtl, noSideEffect, benign.} proc convert*[T: SomeInteger](unitFrom, unitTo: FixedTimeUnit, quantity: T): T {.inline.} = @@ -470,20 +452,161 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T = result.seconds -= 1 result.nanosecond = nanosecond.int -# Forward declarations -proc utcTzInfo(time: Time): ZonedTime - {.tags: [], raises: [], benign.} -proc localZonedTimeFromTime(time: Time): ZonedTime - {.tags: [], raises: [], benign.} -proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime - {.tags: [], raises: [], benign.} -proc initTime*(unix: int64, nanosecond: NanosecondRange): Time - {.tags: [], raises: [], benign, noSideEffect.} +proc isLeapYear*(year: int): bool = + ## Returns true if ``year`` is a leap year. + runnableExamples: + doAssert isLeapYear(2000) + doAssert not isLeapYear(1900) + year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0) -proc nanosecond*(time: Time): NanosecondRange = - ## Get the fractional part of a ``Time`` as the number - ## of nanoseconds of the second. - time.nanosecond +proc getDaysInMonth*(month: Month, year: int): int = + ## Get the number of days in ``month`` of ``year``. + # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month + runnableExamples: + doAssert getDaysInMonth(mFeb, 2000) == 29 + doAssert getDaysInMonth(mFeb, 2001) == 28 + case month + of mFeb: result = if isLeapYear(year): 29 else: 28 + of mApr, mJun, mSep, mNov: result = 30 + else: result = 31 + +proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) + {.inline.} = + assert monthday > 0 and monthday <= getDaysInMonth(month, year), + $year & "-" & intToStr(ord(month), 2) & "-" & $monthday & + " is not a valid date" + +proc toEpochDay(monthday: MonthdayRange, month: Month, year: int): int64 = + ## Get the epoch day from a year/month/day date. + ## The epoch day is the number of days since 1970/01/01 + ## (it might be negative). + # Based on http://howardhinnant.github.io/date_algorithms.html + assertValidDate monthday, month, year + var (y, m, d) = (year, ord(month), monthday.int) + if m <= 2: + y.dec + + let era = (if y >= 0: y else: y-399) div 400 + let yoe = y - era * 400 + let doy = (153 * (m + (if m > 2: -3 else: 9)) + 2) div 5 + d-1 + let doe = yoe * 365 + yoe div 4 - yoe div 100 + doy + return era * 146097 + doe - 719468 + +proc fromEpochDay(epochday: int64): + tuple[monthday: MonthdayRange, month: Month, year: int] = + ## Get the year/month/day date from a epoch day. + ## The epoch day is the number of days since 1970/01/01 + ## (it might be negative). + # Based on http://howardhinnant.github.io/date_algorithms.html + var z = epochday + z.inc 719468 + let era = (if z >= 0: z else: z - 146096) div 146097 + let doe = z - era * 146097 + let yoe = (doe - doe div 1460 + doe div 36524 - doe div 146096) div 365 + let y = yoe + era * 400; + let doy = doe - (365 * yoe + yoe div 4 - yoe div 100) + let mp = (5 * doy + 2) div 153 + let d = doy - (153 * mp + 2) div 5 + 1 + let m = mp + (if mp < 10: 3 else: -9) + return (d.MonthdayRange, m.Month, (y + ord(m <= 2)).int) + +proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): + YeardayRange {.tags: [], raises: [], benign.} = + ## Returns the day of the year. + ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``. + runnableExamples: + doAssert getDayOfYear(1, mJan, 2000) == 0 + doAssert getDayOfYear(10, mJan, 2000) == 9 + doAssert getDayOfYear(10, mFeb, 2000) == 40 + + assertValidDate monthday, month, year + const daysUntilMonth: array[Month, int] = + [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] + const daysUntilMonthLeap: array[Month, int] = + [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335] + + if isLeapYear(year): + result = daysUntilMonthLeap[month] + monthday - 1 + else: + result = daysUntilMonth[month] + monthday - 1 + +proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay + {.tags: [], raises: [], benign.} = + ## Returns the day of the week enum from day, month and year. + ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).weekday``. + runnableExamples: + doAssert getDayOfWeek(13, mJun, 1990) == dWed + doAssert $getDayOfWeek(13, mJun, 1990) == "Wednesday" + + assertValidDate monthday, month, year + # 1970-01-01 is a Thursday, we adjust to the previous Monday + let days = toEpochDay(monthday, month, year) - 3 + let weeks = floorDiv(days, 7) + let wd = days - weeks * 7 + # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. + # so we must correct for the WeekDay type. + result = if wd == 0: dSun else: WeekDay(wd - 1) + +proc getDaysInYear*(year: int): int = + ## Get the number of days in a ``year`` + runnableExamples: + doAssert getDaysInYear(2000) == 366 + doAssert getDaysInYear(2001) == 365 + result = 365 + (if isLeapYear(year): 1 else: 0) + +proc stringifyUnit(value: int | int64, unit: TimeUnit): string = + ## Stringify time unit with it's name, lowercased + let strUnit = $unit + result = "" + result.add($value) + result.add(" ") + if abs(value) != 1: + result.add(strUnit.toLowerAscii()) + else: + result.add(strUnit[0..^2].toLowerAscii()) + +proc humanizeParts(parts: seq[string]): string = + ## Make date string parts human-readable + result = "" + if parts.len == 0: + result.add "0 nanoseconds" + elif parts.len == 1: + result = parts[0] + elif parts.len == 2: + result = parts[0] & " and " & parts[1] + else: + for i in 0..high(parts)-1: + result.add parts[i] & ", " + result.add "and " & parts[high(parts)] + +template subImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = + normalize[T](a.seconds - b.seconds, a.nanosecond - b.nanosecond) + +template addImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = + normalize[T](a.seconds + b.seconds, a.nanosecond + b.nanosecond) + +template ltImpl(a: Duration|Time, b: Duration|Time): bool = + a.seconds < b.seconds or ( + a.seconds == b.seconds and a.nanosecond < b.nanosecond) + +template lqImpl(a: Duration|Time, b: Duration|Time): bool = + a.seconds < b.seconds or ( + a.seconds == b.seconds and a.nanosecond <= b.nanosecond) + +template eqImpl(a: Duration|Time, b: Duration|Time): bool = + a.seconds == b.seconds and a.nanosecond == b.nanosecond + +# +# Duration +# + +const DurationZero* = Duration() ## \ + ## Zero value for durations. Useful for comparisons. + ## + ## .. code-block:: nim + ## + ## doAssert initDuration(seconds = 1) > DurationZero + ## doAssert initDuration(seconds = 0) == DurationZero proc initDuration*(nanoseconds, microseconds, milliseconds, seconds, minutes, hours, days, weeks: int64 = 0): Duration = @@ -582,197 +705,6 @@ proc inNanoseconds*(dur: Duration): int64 = doAssert dur.inNanoseconds == -2000000000 dur.convert(Nanoseconds) -proc fromUnix*(unix: int64): Time - {.benign, tags: [], raises: [], noSideEffect.} = - ## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``) - ## to a ``Time``. - runnableExamples: - doAssert $fromUnix(0).utc == "1970-01-01T00:00:00Z" - initTime(unix, 0) - -proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} = - ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``). - ## See also `toUnixFloat` for subsecond resolution. - runnableExamples: - doAssert fromUnix(0).toUnix() == 0 - t.seconds - -proc fromUnixFloat(seconds: float): Time {.benign, tags: [], raises: [], noSideEffect.} = - ## Convert a unix timestamp in seconds to a `Time`; same as `fromUnix` - ## but with subsecond resolution. - runnableExamples: - doAssert fromUnixFloat(123456.0) == fromUnixFloat(123456) - doAssert fromUnixFloat(-123456.0) == fromUnixFloat(-123456) - let secs = seconds.floor - let nsecs = (seconds - secs) * 1e9 - initTime(secs.int64, nsecs.NanosecondRange) - -proc toUnixFloat(t: Time): float {.benign, tags: [], raises: [].} = - ## Same as `toUnix` but using subsecond resolution. - runnableExamples: - let t = getTime() - # `<` because of rounding errors - doAssert abs(t.toUnixFloat().fromUnixFloat - t) < initDuration(nanoseconds = 1000) - t.seconds.float + t.nanosecond / convert(Seconds, Nanoseconds, 1) - -since((1, 1)): - export fromUnixFloat - export toUnixFloat - -proc fromWinTime*(win: int64): Time = - ## Convert a Windows file time (100-nanosecond intervals since - ## ``1601-01-01T00:00:00Z``) to a ``Time``. - const hnsecsPerSec = convert(Seconds, Nanoseconds, 1) div 100 - let nanos = floorMod(win, hnsecsPerSec) * 100 - let seconds = floorDiv(win - epochDiff, hnsecsPerSec) - result = initTime(seconds, nanos) - -proc toWinTime*(t: Time): int64 = - ## Convert ``t`` to a Windows file time (100-nanosecond intervals - ## since ``1601-01-01T00:00:00Z``). - result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100 - -proc isLeapYear*(year: int): bool = - ## Returns true if ``year`` is a leap year. - runnableExamples: - doAssert isLeapYear(2000) - doAssert not isLeapYear(1900) - year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0) - -proc isLeapDay*(t: DateTime): bool {.since: (1,1).} = - ## returns whether `t` is a leap day, ie, Feb 29 in a leap year. This matters - ## as it affects time offset calculations. - runnableExamples: - let t = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) - doAssert t.isLeapDay - doAssert t+1.years-1.years != t - let t2 = initDateTime(28, mFeb, 2020, 00, 00, 00, utc()) - doAssert not t2.isLeapDay - doAssert t2+1.years-1.years == t2 - doAssertRaises(Exception): discard initDateTime(29, mFeb, 2021, 00, 00, 00, utc()) - t.year.isLeapYear and t.month == mFeb and t.monthday == 29 - -proc getDaysInMonth*(month: Month, year: int): int = - ## Get the number of days in ``month`` of ``year``. - # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month - runnableExamples: - doAssert getDaysInMonth(mFeb, 2000) == 29 - doAssert getDaysInMonth(mFeb, 2001) == 28 - case month - of mFeb: result = if isLeapYear(year): 29 else: 28 - of mApr, mJun, mSep, mNov: result = 30 - else: result = 31 - -proc getDaysInYear*(year: int): int = - ## Get the number of days in a ``year`` - runnableExamples: - doAssert getDaysInYear(2000) == 366 - doAssert getDaysInYear(2001) == 365 - result = 365 + (if isLeapYear(year): 1 else: 0) - -proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) - {.inline.} = - assert monthday > 0 and monthday <= getDaysInMonth(month, year), - $year & "-" & intToStr(ord(month), 2) & "-" & $monthday & - " is not a valid date" - -proc toEpochDay(monthday: MonthdayRange, month: Month, year: int): int64 = - ## Get the epoch day from a year/month/day date. - ## The epoch day is the number of days since 1970/01/01 - ## (it might be negative). - # Based on http://howardhinnant.github.io/date_algorithms.html - assertValidDate monthday, month, year - var (y, m, d) = (year, ord(month), monthday.int) - if m <= 2: - y.dec - - let era = (if y >= 0: y else: y-399) div 400 - let yoe = y - era * 400 - let doy = (153 * (m + (if m > 2: -3 else: 9)) + 2) div 5 + d-1 - let doe = yoe * 365 + yoe div 4 - yoe div 100 + doy - return era * 146097 + doe - 719468 - -proc fromEpochDay(epochday: int64): - tuple[monthday: MonthdayRange, month: Month, year: int] = - ## Get the year/month/day date from a epoch day. - ## The epoch day is the number of days since 1970/01/01 - ## (it might be negative). - # Based on http://howardhinnant.github.io/date_algorithms.html - var z = epochday - z.inc 719468 - let era = (if z >= 0: z else: z - 146096) div 146097 - let doe = z - era * 146097 - let yoe = (doe - doe div 1460 + doe div 36524 - doe div 146096) div 365 - let y = yoe + era * 400; - let doy = doe - (365 * yoe + yoe div 4 - yoe div 100) - let mp = (5 * doy + 2) div 153 - let d = doy - (153 * mp + 2) div 5 + 1 - let m = mp + (if mp < 10: 3 else: -9) - return (d.MonthdayRange, m.Month, (y + ord(m <= 2)).int) - -proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): - YeardayRange {.tags: [], raises: [], benign.} = - ## Returns the day of the year. - ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).yearday``. - runnableExamples: - doAssert getDayOfYear(1, mJan, 2000) == 0 - doAssert getDayOfYear(10, mJan, 2000) == 9 - doAssert getDayOfYear(10, mFeb, 2000) == 40 - - assertValidDate monthday, month, year - const daysUntilMonth: array[Month, int] = - [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] - const daysUntilMonthLeap: array[Month, int] = - [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335] - - if isLeapYear(year): - result = daysUntilMonthLeap[month] + monthday - 1 - else: - result = daysUntilMonth[month] + monthday - 1 - -proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay - {.tags: [], raises: [], benign.} = - ## Returns the day of the week enum from day, month and year. - ## Equivalent with ``initDateTime(monthday, month, year, 0, 0, 0).weekday``. - runnableExamples: - doAssert getDayOfWeek(13, mJun, 1990) == dWed - doAssert $getDayOfWeek(13, mJun, 1990) == "Wednesday" - - assertValidDate monthday, month, year - # 1970-01-01 is a Thursday, we adjust to the previous Monday - let days = toEpochDay(monthday, month, year) - 3 - let weeks = floorDiv(days, 7) - let wd = days - weeks * 7 - # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. - # so we must correct for the WeekDay type. - result = if wd == 0: dSun else: WeekDay(wd - 1) - -{.pragma: operator, rtl, noSideEffect, benign.} - -template subImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = - normalize[T](a.seconds - b.seconds, a.nanosecond - b.nanosecond) - -template addImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = - normalize[T](a.seconds + b.seconds, a.nanosecond + b.nanosecond) - -template ltImpl(a: Duration|Time, b: Duration|Time): bool = - a.seconds < b.seconds or ( - a.seconds == b.seconds and a.nanosecond < b.nanosecond) - -template lqImpl(a: Duration|Time, b: Duration|Time): bool = - a.seconds < b.seconds or ( - a.seconds == b.seconds and a.nanosecond <= b.nanosecond) - -template eqImpl(a: Duration|Time, b: Duration|Time): bool = - a.seconds == b.seconds and a.nanosecond == b.nanosecond -const DurationZero* = initDuration() ## \ - ## Zero value for durations. Useful for comparisons. - ## - ## .. code-block:: nim - ## - ## doAssert initDuration(seconds = 1) > DurationZero - ## doAssert initDuration(seconds = 0) == DurationZero - proc toParts*(dur: Duration): DurationParts = ## Converts a duration into an array consisting of fixed time units. ## @@ -808,31 +740,6 @@ proc toParts*(dur: Duration): DurationParts = result[unit] = quantity -proc stringifyUnit(value: int | int64, unit: TimeUnit): string = - ## Stringify time unit with it's name, lowercased - let strUnit = $unit - result = "" - result.add($value) - result.add(" ") - if abs(value) != 1: - result.add(strUnit.toLowerAscii()) - else: - result.add(strUnit[0..^2].toLowerAscii()) - -proc humanizeParts(parts: seq[string]): string = - ## Make date string parts human-readable - result = "" - if parts.len == 0: - result.add "0 nanoseconds" - elif parts.len == 1: - result = parts[0] - elif parts.len == 2: - result = parts[0] & " and " & parts[1] - else: - for i in 0..high(parts)-1: - result.add parts[i] & ", " - result.add "and " & parts[high(parts)] - proc `$`*(dur: Duration): string = ## Human friendly string representation of a ``Duration``. runnableExamples: @@ -911,6 +818,15 @@ proc `*`*(a: Duration, b: int64): Duration {.operator, doAssert initDuration(minutes = 45) * 3 == initDuration(hours = 2, minutes = 15) b * a +proc `+=`*(d1: var Duration, d2: Duration) = + d1 = d1 + d2 + +proc `-=`*(dt: var Duration, ti: Duration) = + dt = dt - ti + +proc `*=`*(a: var Duration, b: int) = + a = a * b + proc `div`*(a: Duration, b: int64): Duration {.operator, extern: "ntDivDuration".} = ## Integer division for durations. @@ -924,11 +840,106 @@ proc `div`*(a: Duration, b: int64): Duration {.operator, let carryOver = convert(Seconds, Nanoseconds, a.seconds mod b) normalize[Duration](a.seconds div b, (a.nanosecond + carryOver) div b) +proc high*(typ: typedesc[Duration]): Duration = + ## Get the longest representable duration. + initDuration(seconds = high(int64), nanoseconds = high(NanosecondRange)) + +proc low*(typ: typedesc[Duration]): Duration = + ## Get the longest representable duration of negative direction. + initDuration(seconds = low(int64)) + +proc abs*(a: Duration): Duration = + runnableExamples: + doAssert initDuration(milliseconds = -1500).abs == + initDuration(milliseconds = 1500) + initDuration(seconds = abs(a.seconds), nanoseconds = -a.nanosecond) + +# +# Time +# + proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = ## Create a `Time <#Time>`_ from a unix timestamp and a nanosecond part. result.seconds = unix result.nanosecond = nanosecond +proc nanosecond*(time: Time): NanosecondRange = + ## Get the fractional part of a ``Time`` as the number + ## of nanoseconds of the second. + time.nanosecond + +proc fromUnix*(unix: int64): Time + {.benign, tags: [], raises: [], noSideEffect.} = + ## Convert a unix timestamp (seconds since ``1970-01-01T00:00:00Z``) + ## to a ``Time``. + runnableExamples: + doAssert $fromUnix(0).utc == "1970-01-01T00:00:00Z" + initTime(unix, 0) + +proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} = + ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``). + ## See also `toUnixFloat` for subsecond resolution. + runnableExamples: + doAssert fromUnix(0).toUnix() == 0 + t.seconds + +proc fromUnixFloat(seconds: float): Time {.benign, tags: [], raises: [], noSideEffect.} = + ## Convert a unix timestamp in seconds to a `Time`; same as `fromUnix` + ## but with subsecond resolution. + runnableExamples: + doAssert fromUnixFloat(123456.0) == fromUnixFloat(123456) + doAssert fromUnixFloat(-123456.0) == fromUnixFloat(-123456) + let secs = seconds.floor + let nsecs = (seconds - secs) * 1e9 + initTime(secs.int64, nsecs.NanosecondRange) + +proc toUnixFloat(t: Time): float {.benign, tags: [], raises: [].} = + ## Same as `toUnix` but using subsecond resolution. + runnableExamples: + let t = getTime() + # `<` because of rounding errors + doAssert abs(t.toUnixFloat().fromUnixFloat - t) < initDuration(nanoseconds = 1000) + t.seconds.float + t.nanosecond / convert(Seconds, Nanoseconds, 1) + +since((1, 1)): + export fromUnixFloat + export toUnixFloat + +proc fromWinTime*(win: int64): Time = + ## Convert a Windows file time (100-nanosecond intervals since + ## ``1601-01-01T00:00:00Z``) to a ``Time``. + const hnsecsPerSec = convert(Seconds, Nanoseconds, 1) div 100 + let nanos = floorMod(win, hnsecsPerSec) * 100 + let seconds = floorDiv(win - epochDiff, hnsecsPerSec) + result = initTime(seconds, nanos) + +proc toWinTime*(t: Time): int64 = + ## Convert ``t`` to a Windows file time (100-nanosecond intervals + ## since ``1601-01-01T00:00:00Z``). + result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100 + +proc getTime*(): Time {.tags: [TimeEffect], benign.} = + ## Gets the current time as a ``Time`` with up to nanosecond resolution. + when defined(js): + let millis = newDate().getTime() + let seconds = convert(Milliseconds, Seconds, millis) + let nanos = convert(Milliseconds, Nanoseconds, + millis mod convert(Seconds, Milliseconds, 1).int) + result = initTime(seconds, nanos) + elif defined(macosx): + var a: Timeval + gettimeofday(a) + result = initTime(a.tv_sec.int64, + convert(Microseconds, Nanoseconds, a.tv_usec.int)) + elif defined(posix): + var ts: Timespec + discard clock_gettime(CLOCK_REALTIME, ts) + result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) + elif defined(windows): + var f: FILETIME + getSystemTimeAsFileTime(f) + result = fromWinTime(rdFileTime(f)) + proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = ## Computes the duration between two points in time. runnableExamples: @@ -962,25 +973,34 @@ proc `==`*(a, b: Time): bool {.operator, extern: "ntEqTime".} = ## Returns true if ``a == b``, that is if both times represent the same point in time. eqImpl(a, b) +proc `+=`*(t: var Time, b: Duration) = + t = t + b + +proc `-=`*(t: var Time, b: Duration) = + t = t - b + proc high*(typ: typedesc[Time]): Time = initTime(high(int64), high(NanosecondRange)) proc low*(typ: typedesc[Time]): Time = initTime(low(int64), 0) -proc high*(typ: typedesc[Duration]): Duration = - ## Get the longest representable duration. - initDuration(seconds = high(int64), nanoseconds = high(NanosecondRange)) +# +# DateTime & Timezone +# -proc low*(typ: typedesc[Duration]): Duration = - ## Get the longest representable duration of negative direction. - initDuration(seconds = low(int64)) - -proc abs*(a: Duration): Duration = +proc isLeapDay*(t: DateTime): bool {.since: (1,1).} = + ## returns whether `t` is a leap day, ie, Feb 29 in a leap year. This matters + ## as it affects time offset calculations. runnableExamples: - doAssert initDuration(milliseconds = -1500).abs == - initDuration(milliseconds = 1500) - initDuration(seconds = abs(a.seconds), nanoseconds = -a.nanosecond) + let t = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) + doAssert t.isLeapDay + doAssert t+1.years-1.years != t + let t2 = initDateTime(28, mFeb, 2020, 00, 00, 00, utc()) + doAssert not t2.isLeapDay + doAssert t2+1.years-1.years == t2 + doAssertRaises(Exception): discard initDateTime(29, mFeb, 2021, 00, 00, 00, utc()) + t.year.isLeapYear and t.month == mFeb and t.monthday == 29 proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = ## Converts a ``DateTime`` to a ``Time`` representing the same point in time. @@ -1109,14 +1129,14 @@ proc toAdjTime(dt: DateTime): Time = result = initTime(seconds, dt.nanosecond) when defined(js): - proc localZonedTimeFromTime(time: Time): ZonedTime = + proc localZonedTimeFromTime(time: Time): ZonedTime {.benign.} = let jsDate = newDate(time.seconds * 1000) let offset = jsDate.getTimezoneOffset() * secondsInMin result.time = time result.utcOffset = offset result.isDst = false - proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime = + proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.benign.} = let utcDate = newDate(adjTime.seconds * 1000) let localDate = newDate(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(), utcDate.getUTCHours(), utcDate.getUTCMinutes(), @@ -1163,13 +1183,13 @@ else: return ((a.int64 - tm.toAdjUnix).int, tm.tm_isdst > 0) return (0, false) - proc localZonedTimeFromTime(time: Time): ZonedTime = + proc localZonedTimeFromTime(time: Time): ZonedTime {.benign.} = let (offset, dst) = getLocalOffsetAndDst(time.seconds) result.time = time result.utcOffset = offset result.isDst = dst - proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime = + proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.benign.} = var adjUnix = adjTime.seconds let past = adjUnix - secondsInDay let (pastOffset, _) = getLocalOffsetAndDst(past) @@ -1236,243 +1256,12 @@ proc local*(t: Time): DateTime = ## Shorthand for ``t.inZone(local())``. t.inZone(local()) -proc getTime*(): Time {.tags: [TimeEffect], benign.} = - ## Gets the current time as a ``Time`` with up to nanosecond resolution. - when defined(js): - let millis = newDate().getTime() - let seconds = convert(Milliseconds, Seconds, millis) - let nanos = convert(Milliseconds, Nanoseconds, - millis mod convert(Seconds, Milliseconds, 1).int) - result = initTime(seconds, nanos) - elif defined(macosx): - var a: Timeval - gettimeofday(a) - result = initTime(a.tv_sec.int64, - convert(Microseconds, Nanoseconds, a.tv_usec.int)) - elif defined(posix): - var ts: Timespec - discard clock_gettime(CLOCK_REALTIME, ts) - result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) - elif defined(windows): - var f: FILETIME - getSystemTimeAsFileTime(f) - result = fromWinTime(rdFileTime(f)) - proc now*(): DateTime {.tags: [TimeEffect], benign.} = ## Get the current time as a ``DateTime`` in the local timezone. ## ## Shorthand for ``getTime().local``. getTime().local -proc initTimeInterval*(nanoseconds, microseconds, milliseconds, - seconds, minutes, hours, - days, weeks, months, years: int = 0): TimeInterval = - ## Creates a new `TimeInterval <#TimeInterval>`_. - ## - ## This proc doesn't perform any normalization! For example, - ## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are - ## not equal. - ## - ## You can also use the convenience procedures called ``milliseconds``, - ## ``seconds``, ``minutes``, ``hours``, ``days``, ``months``, and ``years``. - runnableExamples: - let day = initTimeInterval(hours = 24) - let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) - doAssert $(dt + day) == "2000-01-02T12:00:00Z" - doAssert initTimeInterval(hours = 24) != initTimeInterval(days = 1) - result.nanoseconds = nanoseconds - result.microseconds = microseconds - result.milliseconds = milliseconds - result.seconds = seconds - result.minutes = minutes - result.hours = hours - result.days = days - result.weeks = weeks - result.months = months - result.years = years - -proc `+`*(ti1, ti2: TimeInterval): TimeInterval = - ## Adds two ``TimeInterval`` objects together. - result.nanoseconds = ti1.nanoseconds + ti2.nanoseconds - result.microseconds = ti1.microseconds + ti2.microseconds - result.milliseconds = ti1.milliseconds + ti2.milliseconds - result.seconds = ti1.seconds + ti2.seconds - result.minutes = ti1.minutes + ti2.minutes - result.hours = ti1.hours + ti2.hours - result.days = ti1.days + ti2.days - result.weeks = ti1.weeks + ti2.weeks - result.months = ti1.months + ti2.months - result.years = ti1.years + ti2.years - -proc `-`*(ti: TimeInterval): TimeInterval = - ## Reverses a time interval - runnableExamples: - let day = -initTimeInterval(hours = 24) - doAssert day.hours == -24 - - result = TimeInterval( - nanoseconds: -ti.nanoseconds, - microseconds: -ti.microseconds, - milliseconds: -ti.milliseconds, - seconds: -ti.seconds, - minutes: -ti.minutes, - hours: -ti.hours, - days: -ti.days, - weeks: -ti.weeks, - months: -ti.months, - years: -ti.years - ) - -proc `-`*(ti1, ti2: TimeInterval): TimeInterval = - ## Subtracts TimeInterval ``ti1`` from ``ti2``. - ## - ## Time components are subtracted one-by-one, see output: - runnableExamples: - let ti1 = initTimeInterval(hours = 24) - let ti2 = initTimeInterval(hours = 4) - doAssert (ti1 - ti2) == initTimeInterval(hours = 20) - - result = ti1 + (-ti2) - -proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = - ## Gets the current local date as a string of the format ``YYYY-MM-DD``. - runnableExamples: - echo getDateStr(now() - 1.months) - result = $dt.year & '-' & intToStr(ord(dt.month), 2) & - '-' & intToStr(dt.monthday, 2) - -proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = - ## Gets the current local clock time as a string of the format ``HH:mm:ss``. - runnableExamples: - echo getClockStr(now() - 1.hours) - result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & - ':' & intToStr(dt.second, 2) - -proc toParts*(ti: TimeInterval): TimeIntervalParts = - ## Converts a ``TimeInterval`` into an array consisting of its time units, - ## starting with nanoseconds and ending with years. - ## - ## This procedure is useful for converting ``TimeInterval`` values to strings. - ## E.g. then you need to implement custom interval printing - runnableExamples: - var tp = toParts(initTimeInterval(years = 1, nanoseconds = 123)) - doAssert tp[Years] == 1 - doAssert tp[Nanoseconds] == 123 - - var index = 0 - for name, value in fieldPairs(ti): - result[index.TimeUnit()] = value - index += 1 - -proc `$`*(ti: TimeInterval): string = - ## Get string representation of ``TimeInterval``. - runnableExamples: - doAssert $initTimeInterval(years = 1, nanoseconds = 123) == - "1 year and 123 nanoseconds" - doAssert $initTimeInterval() == "0 nanoseconds" - - var parts: seq[string] = @[] - var tiParts = toParts(ti) - for unit in countdown(Years, Nanoseconds): - if tiParts[unit] != 0: - parts.add(stringifyUnit(tiParts[unit], unit)) - - result = humanizeParts(parts) - -proc nanoseconds*(nanos: int): TimeInterval {.inline.} = - ## TimeInterval of ``nanos`` nanoseconds. - initTimeInterval(nanoseconds = nanos) - -proc microseconds*(micros: int): TimeInterval {.inline.} = - ## TimeInterval of ``micros`` microseconds. - initTimeInterval(microseconds = micros) - -proc milliseconds*(ms: int): TimeInterval {.inline.} = - ## TimeInterval of ``ms`` milliseconds. - initTimeInterval(milliseconds = ms) - -proc seconds*(s: int): TimeInterval {.inline.} = - ## TimeInterval of ``s`` seconds. - ## - ## ``echo getTime() + 5.seconds`` - initTimeInterval(seconds = s) - -proc minutes*(m: int): TimeInterval {.inline.} = - ## TimeInterval of ``m`` minutes. - ## - ## ``echo getTime() + 5.minutes`` - initTimeInterval(minutes = m) - -proc hours*(h: int): TimeInterval {.inline.} = - ## TimeInterval of ``h`` hours. - ## - ## ``echo getTime() + 2.hours`` - initTimeInterval(hours = h) - -proc days*(d: int): TimeInterval {.inline.} = - ## TimeInterval of ``d`` days. - ## - ## ``echo getTime() + 2.days`` - initTimeInterval(days = d) - -proc weeks*(w: int): TimeInterval {.inline.} = - ## TimeInterval of ``w`` weeks. - ## - ## ``echo getTime() + 2.weeks`` - initTimeInterval(weeks = w) - -proc months*(m: int): TimeInterval {.inline.} = - ## TimeInterval of ``m`` months. - ## - ## ``echo getTime() + 2.months`` - initTimeInterval(months = m) - -proc years*(y: int): TimeInterval {.inline.} = - ## TimeInterval of ``y`` years. - ## - ## ``echo getTime() + 2.years`` - initTimeInterval(years = y) - -proc evaluateInterval(dt: DateTime, interval: TimeInterval): - tuple[adjDur, absDur: Duration] = - ## Evaluates how many nanoseconds the interval is worth - ## in the context of ``dt``. - ## The result in split into an adjusted diff and an absolute diff. - var months = interval.years * 12 + interval.months - var curYear = dt.year - var curMonth = dt.month - # Subtracting - if months < 0: - for mth in countdown(-1 * months, 1): - if curMonth == mJan: - curMonth = mDec - curYear.dec - else: - curMonth.dec() - let days = getDaysInMonth(curMonth, curYear) - result.adjDur = result.adjDur - initDuration(days = days) - # Adding - else: - for mth in 1 .. months: - let days = getDaysInMonth(curMonth, curYear) - result.adjDur = result.adjDur + initDuration(days = days) - if curMonth == mDec: - curMonth = mJan - curYear.inc - else: - curMonth.inc() - - result.adjDur = result.adjDur + initDuration( - days = interval.days, - weeks = interval.weeks) - result.absDur = initDuration( - nanoseconds = interval.nanoseconds, - microseconds = interval.microseconds, - milliseconds = interval.milliseconds, - seconds = interval.seconds, - minutes = interval.minutes, - hours = interval.hours) - proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, hour: HourRange, minute: MinuteRange, second: SecondRange, nanosecond: NanosecondRange, @@ -1503,47 +1292,6 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, doAssert $dt1 == "2017-03-30T00:00:00Z" initDateTime(monthday, month, year, hour, minute, second, 0, zone) - -proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = - ## Adds ``interval`` to ``dt``. Components from ``interval`` are added - ## in the order of their size, i.e. first the ``years`` component, then the - ## ``months`` component and so on. The returned ``DateTime`` will have the - ## same timezone as the input. - ## - ## Note that when adding months, monthday overflow is allowed. This means that - ## if the resulting month doesn't have enough days it, the month will be - ## incremented and the monthday will be set to the number of days overflowed. - ## So adding one month to `31 October` will result in `31 November`, which - ## will overflow and result in `1 December`. - runnableExamples: - let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) - doAssert $(dt + 1.months) == "2017-04-30T00:00:00Z" - # This is correct and happens due to monthday overflow. - doAssert $(dt - 1.months) == "2017-03-02T00:00:00Z" - let (adjDur, absDur) = evaluateInterval(dt, interval) - - if adjDur != DurationZero: - var zt = dt.timezone.zonedTimeFromAdjTime(dt.toAdjTime + adjDur) - if absDur != DurationZero: - zt = dt.timezone.zonedTimeFromTime(zt.time + absDur) - result = initDateTime(zt, dt.timezone) - else: - result = initDateTime(zt, dt.timezone) - else: - var zt = dt.timezone.zonedTimeFromTime(dt.toTime + absDur) - result = initDateTime(zt, dt.timezone) - -proc `-`*(dt: DateTime, interval: TimeInterval): DateTime = - ## Subtract ``interval`` from ``dt``. Components from ``interval`` are - ## subtracted in the order of their size, i.e. first the ``years`` component, - ## then the ``months`` component and so on. The returned ``DateTime`` will - ## have the same timezone as the input. - runnableExamples: - let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) - doAssert $(dt - 5.days) == "2017-03-25T00:00:00Z" - - dt + (-interval) - proc `+`*(dt: DateTime, dur: Duration): DateTime = runnableExamples: let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) @@ -1587,178 +1335,43 @@ proc `==`*(a, b: DateTime): bool = elif b.isDefault: false else: a.toTime == b.toTime -proc isStaticInterval(interval: TimeInterval): bool = - interval.years == 0 and interval.months == 0 and - interval.days == 0 and interval.weeks == 0 - -proc evaluateStaticInterval(interval: TimeInterval): Duration = - assert interval.isStaticInterval - initDuration(nanoseconds = interval.nanoseconds, - microseconds = interval.microseconds, - milliseconds = interval.milliseconds, - seconds = interval.seconds, - minutes = interval.minutes, - hours = interval.hours) - -proc between*(startDt, endDt: DateTime): TimeInterval = - ## Gives the difference between ``startDt`` and ``endDt`` as a - ## ``TimeInterval``. The following guarantees about the result is given: - ## - ## - All fields will have the same sign. - ## - If `startDt.timezone == endDt.timezone`, it is guaranteed that - ## `startDt + between(startDt, endDt) == endDt`. - ## - If `startDt.timezone != endDt.timezone`, then the result will be - ## equivalent to `between(startDt.utc, endDt.utc)`. - runnableExamples: - var a = initDateTime(25, mMar, 2015, 12, 0, 0, utc()) - var b = initDateTime(1, mApr, 2017, 15, 0, 15, utc()) - var ti = initTimeInterval(years = 2, weeks = 1, hours = 3, seconds = 15) - doAssert between(a, b) == ti - doAssert between(a, b) == -between(b, a) - - if startDt.timezone != endDt.timezone: - return between(startDt.utc, endDt.utc) - elif endDt < startDt: - return -between(endDt, startDt) - - type Date = tuple[year, month, monthday: int] - var startDate: Date = (startDt.year, startDt.month.ord, startDt.monthday) - var endDate: Date = (endDt.year, endDt.month.ord, endDt.monthday) - - # Subtract one day from endDate if time of day is earlier than startDay - # The subtracted day will be counted by fixed units (hour and lower) - # at the end of this proc - if (endDt.hour, endDt.minute, endDt.second, endDt.nanosecond) < - (startDt.hour, startDt.minute, startDt.second, startDt.nanosecond): - if endDate.month == 1 and endDate.monthday == 1: - endDate.year.dec - endDate.monthday = 31 - endDate.month = 12 - elif endDate.monthday == 1: - endDate.month.dec - endDate.monthday = getDaysInMonth(endDate.month.Month, endDate.year) - else: - endDate.monthday.dec - - # Years - result.years.inc endDate.year - startDate.year - 1 - if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday): - result.years.inc - startDate.year.inc result.years - - # Months - if startDate.year < endDate.year: - result.months.inc 12 - startDate.month # Move to dec - if endDate.month != 1 or (startDate.monthday <= endDate.monthday): - result.months.inc - startDate.year = endDate.year - startDate.month = 1 - else: - startDate.month = 12 - if startDate.year == endDate.year: - if (startDate.monthday <= endDate.monthday): - result.months.inc endDate.month - startDate.month - startDate.month = endDate.month - elif endDate.month != 1: - let month = endDate.month - 1 - let daysInMonth = getDaysInMonth(month.Month, startDate.year) - if daysInMonth < startDate.monthday: - if startDate.monthday - daysInMonth < endDate.monthday: - result.months.inc endDate.month - startDate.month - 1 - startDate.month = endDate.month - startDate.monthday = startDate.monthday - daysInMonth - else: - result.months.inc endDate.month - startDate.month - 2 - startDate.month = endDate.month - 2 - else: - result.months.inc endDate.month - startDate.month - 1 - startDate.month = endDate.month - 1 - - # Days - # This means that start = dec and end = jan - if startDate.year < endDate.year: - result.days.inc 31 - startDate.monthday + endDate.monthday - startDate = endDate - else: - while startDate.month < endDate.month: - let daysInMonth = getDaysInMonth(startDate.month.Month, startDate.year) - result.days.inc daysInMonth - startDate.monthday + 1 - startDate.month.inc - startDate.monthday = 1 - result.days.inc endDate.monthday - startDate.monthday - result.weeks = result.days div 7 - result.days = result.days mod 7 - startDate = endDate - - # Handle hours, minutes, seconds, milliseconds, microseconds and nanoseconds - let newStartDt = initDateTime(startDate.monthday, startDate.month.Month, - startDate.year, startDt.hour, startDt.minute, startDt.second, - startDt.nanosecond, startDt.timezone) - let dur = endDt - newStartDt - let parts = toParts(dur) - # There can still be a full day in `parts` since `Duration` and `TimeInterval` - # models days differently. - result.hours = parts[Hours].int + parts[Days].int * 24 - result.minutes = parts[Minutes].int - result.seconds = parts[Seconds].int - result.milliseconds = parts[Milliseconds].int - result.microseconds = parts[Microseconds].int - result.nanoseconds = parts[Nanoseconds].int - -proc `+`*(time: Time, interval: TimeInterval): Time = - ## Adds `interval` to `time`. - ## If `interval` contains any years, months, weeks or days the operation - ## is performed in the local timezone. - runnableExamples: - let tm = fromUnix(0) - doAssert tm + 5.seconds == fromUnix(5) - - if interval.isStaticInterval: - time + evaluateStaticInterval(interval) - else: - toTime(time.local + interval) - -proc `-`*(time: Time, interval: TimeInterval): Time = - ## Subtracts `interval` from Time `time`. - ## If `interval` contains any years, months, weeks or days the operation - ## is performed in the local timezone. - runnableExamples: - let tm = fromUnix(5) - doAssert tm - 5.seconds == fromUnix(0) - - if interval.isStaticInterval: - time - evaluateStaticInterval(interval) - else: - toTime(time.local - interval) - -proc `+=`*[T, U: TimesMutableTypes](a: var T, b: U) = - ## Modify ``a`` in place by adding ``b``. - runnableExamples: - var tm = fromUnix(0) - tm += initDuration(seconds = 1) - doAssert tm == fromUnix(1) +proc `+=`*(a: var DateTime, b: Duration) = a = a + b -proc `-=`*[T, U: TimesMutableTypes](a: var T, b: U) = - ## Modify ``a`` in place by subtracting ``b``. - runnableExamples: - var tm = fromUnix(5) - tm -= initDuration(seconds = 5) - doAssert tm == fromUnix(0) +proc `-=`*(a: var DateTime, b: Duration) = a = a - b -proc `*=`*[T: TimesMutableTypes, U](a: var T, b: U) = - # Mutable type is often multiplied by number +proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = + ## Gets the current local date as a string of the format ``YYYY-MM-DD``. runnableExamples: - var dur = initDuration(seconds = 1) - dur *= 5 - doAssert dur == initDuration(seconds = 5) - a = a * b + echo getDateStr(now() - 1.months) + result = $dt.year & '-' & intToStr(ord(dt.month), 2) & + '-' & intToStr(dt.monthday, 2) + +proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = + ## Gets the current local clock time as a string of the format ``HH:mm:ss``. + runnableExamples: + echo getClockStr(now() - 1.hours) + result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & + ':' & intToStr(dt.second, 2) # -# Parse & format implementation +# TimeFormat # +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +type + DateTimeLocale* = object + MMM*: array[mJan..mDec, string] + MMMM*: array[mJan..mDec, string] + ddd*: array[dMon..dSun, string] + dddd*: array[dMon..dSun, string] + +when defined(nimHasStyleChecks): + {.pop.} + type AmPm = enum apUnknown, apAm, apPm @@ -1821,7 +1434,18 @@ type TimeFormatParseError* = object of ValueError ## \ ## Raised when parsing a ``TimeFormat`` string fails. -const FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ','} +const + DefaultLocale* = DateTimeLocale( + MMM: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec"], + MMMM: ["January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December"], + ddd: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + dddd: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", + "Sunday"], + ) + + FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ','} proc `$`*(f: TimeFormat): string = ## Returns the format string that was used to construct ``f``. @@ -2460,10 +2084,6 @@ proc parseTime*(input: string, f: static[string], zone: Timezone): Time const f2 = initTimeFormat(f) result = input.parse(f2, zone).toTime() -# -# End of parse & format implementation -# - proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} = ## Converts a `DateTime` object to a string representation. ## It uses the format ``yyyy-MM-dd'T'HH:mm:sszzz``. @@ -2481,6 +2101,478 @@ proc `$`*(time: Time): string {.tags: [], raises: [], benign.} = doAssert $tm == "1970-01-01T00:00:00" & format(dt, "zzz") $time.local +# +# TimeInterval +# + +proc initTimeInterval*(nanoseconds, microseconds, milliseconds, + seconds, minutes, hours, + days, weeks, months, years: int = 0): TimeInterval = + ## Creates a new `TimeInterval <#TimeInterval>`_. + ## + ## This proc doesn't perform any normalization! For example, + ## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are + ## not equal. + ## + ## You can also use the convenience procedures called ``milliseconds``, + ## ``seconds``, ``minutes``, ``hours``, ``days``, ``months``, and ``years``. + runnableExamples: + let day = initTimeInterval(hours = 24) + let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) + doAssert $(dt + day) == "2000-01-02T12:00:00Z" + doAssert initTimeInterval(hours = 24) != initTimeInterval(days = 1) + result.nanoseconds = nanoseconds + result.microseconds = microseconds + result.milliseconds = milliseconds + result.seconds = seconds + result.minutes = minutes + result.hours = hours + result.days = days + result.weeks = weeks + result.months = months + result.years = years + +proc `+`*(ti1, ti2: TimeInterval): TimeInterval = + ## Adds two ``TimeInterval`` objects together. + result.nanoseconds = ti1.nanoseconds + ti2.nanoseconds + result.microseconds = ti1.microseconds + ti2.microseconds + result.milliseconds = ti1.milliseconds + ti2.milliseconds + result.seconds = ti1.seconds + ti2.seconds + result.minutes = ti1.minutes + ti2.minutes + result.hours = ti1.hours + ti2.hours + result.days = ti1.days + ti2.days + result.weeks = ti1.weeks + ti2.weeks + result.months = ti1.months + ti2.months + result.years = ti1.years + ti2.years + +proc `-`*(ti: TimeInterval): TimeInterval = + ## Reverses a time interval + runnableExamples: + let day = -initTimeInterval(hours = 24) + doAssert day.hours == -24 + + result = TimeInterval( + nanoseconds: -ti.nanoseconds, + microseconds: -ti.microseconds, + milliseconds: -ti.milliseconds, + seconds: -ti.seconds, + minutes: -ti.minutes, + hours: -ti.hours, + days: -ti.days, + weeks: -ti.weeks, + months: -ti.months, + years: -ti.years + ) + +proc `-`*(ti1, ti2: TimeInterval): TimeInterval = + ## Subtracts TimeInterval ``ti1`` from ``ti2``. + ## + ## Time components are subtracted one-by-one, see output: + runnableExamples: + let ti1 = initTimeInterval(hours = 24) + let ti2 = initTimeInterval(hours = 4) + doAssert (ti1 - ti2) == initTimeInterval(hours = 20) + + result = ti1 + (-ti2) + +proc `+=`*(a: var TimeInterval, b: TimeInterval) = + a = a + b + +proc `-=`*(a: var TimeInterval, b: TimeInterval) = + a = a - b + +proc isStaticInterval(interval: TimeInterval): bool = + interval.years == 0 and interval.months == 0 and + interval.days == 0 and interval.weeks == 0 + +proc evaluateStaticInterval(interval: TimeInterval): Duration = + assert interval.isStaticInterval + initDuration(nanoseconds = interval.nanoseconds, + microseconds = interval.microseconds, + milliseconds = interval.milliseconds, + seconds = interval.seconds, + minutes = interval.minutes, + hours = interval.hours) + +proc between*(startDt, endDt: DateTime): TimeInterval = + ## Gives the difference between ``startDt`` and ``endDt`` as a + ## ``TimeInterval``. The following guarantees about the result is given: + ## + ## - All fields will have the same sign. + ## - If `startDt.timezone == endDt.timezone`, it is guaranteed that + ## `startDt + between(startDt, endDt) == endDt`. + ## - If `startDt.timezone != endDt.timezone`, then the result will be + ## equivalent to `between(startDt.utc, endDt.utc)`. + runnableExamples: + var a = initDateTime(25, mMar, 2015, 12, 0, 0, utc()) + var b = initDateTime(1, mApr, 2017, 15, 0, 15, utc()) + var ti = initTimeInterval(years = 2, weeks = 1, hours = 3, seconds = 15) + doAssert between(a, b) == ti + doAssert between(a, b) == -between(b, a) + + if startDt.timezone != endDt.timezone: + return between(startDt.utc, endDt.utc) + elif endDt < startDt: + return -between(endDt, startDt) + + type Date = tuple[year, month, monthday: int] + var startDate: Date = (startDt.year, startDt.month.ord, startDt.monthday) + var endDate: Date = (endDt.year, endDt.month.ord, endDt.monthday) + + # Subtract one day from endDate if time of day is earlier than startDay + # The subtracted day will be counted by fixed units (hour and lower) + # at the end of this proc + if (endDt.hour, endDt.minute, endDt.second, endDt.nanosecond) < + (startDt.hour, startDt.minute, startDt.second, startDt.nanosecond): + if endDate.month == 1 and endDate.monthday == 1: + endDate.year.dec + endDate.monthday = 31 + endDate.month = 12 + elif endDate.monthday == 1: + endDate.month.dec + endDate.monthday = getDaysInMonth(endDate.month.Month, endDate.year) + else: + endDate.monthday.dec + + # Years + result.years.inc endDate.year - startDate.year - 1 + if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday): + result.years.inc + startDate.year.inc result.years + + # Months + if startDate.year < endDate.year: + result.months.inc 12 - startDate.month # Move to dec + if endDate.month != 1 or (startDate.monthday <= endDate.monthday): + result.months.inc + startDate.year = endDate.year + startDate.month = 1 + else: + startDate.month = 12 + if startDate.year == endDate.year: + if (startDate.monthday <= endDate.monthday): + result.months.inc endDate.month - startDate.month + startDate.month = endDate.month + elif endDate.month != 1: + let month = endDate.month - 1 + let daysInMonth = getDaysInMonth(month.Month, startDate.year) + if daysInMonth < startDate.monthday: + if startDate.monthday - daysInMonth < endDate.monthday: + result.months.inc endDate.month - startDate.month - 1 + startDate.month = endDate.month + startDate.monthday = startDate.monthday - daysInMonth + else: + result.months.inc endDate.month - startDate.month - 2 + startDate.month = endDate.month - 2 + else: + result.months.inc endDate.month - startDate.month - 1 + startDate.month = endDate.month - 1 + + # Days + # This means that start = dec and end = jan + if startDate.year < endDate.year: + result.days.inc 31 - startDate.monthday + endDate.monthday + startDate = endDate + else: + while startDate.month < endDate.month: + let daysInMonth = getDaysInMonth(startDate.month.Month, startDate.year) + result.days.inc daysInMonth - startDate.monthday + 1 + startDate.month.inc + startDate.monthday = 1 + result.days.inc endDate.monthday - startDate.monthday + result.weeks = result.days div 7 + result.days = result.days mod 7 + startDate = endDate + + # Handle hours, minutes, seconds, milliseconds, microseconds and nanoseconds + let newStartDt = initDateTime(startDate.monthday, startDate.month.Month, + startDate.year, startDt.hour, startDt.minute, startDt.second, + startDt.nanosecond, startDt.timezone) + let dur = endDt - newStartDt + let parts = toParts(dur) + # There can still be a full day in `parts` since `Duration` and `TimeInterval` + # models days differently. + result.hours = parts[Hours].int + parts[Days].int * 24 + result.minutes = parts[Minutes].int + result.seconds = parts[Seconds].int + result.milliseconds = parts[Milliseconds].int + result.microseconds = parts[Microseconds].int + result.nanoseconds = parts[Nanoseconds].int + +proc toParts*(ti: TimeInterval): TimeIntervalParts = + ## Converts a ``TimeInterval`` into an array consisting of its time units, + ## starting with nanoseconds and ending with years. + ## + ## This procedure is useful for converting ``TimeInterval`` values to strings. + ## E.g. then you need to implement custom interval printing + runnableExamples: + var tp = toParts(initTimeInterval(years = 1, nanoseconds = 123)) + doAssert tp[Years] == 1 + doAssert tp[Nanoseconds] == 123 + + var index = 0 + for name, value in fieldPairs(ti): + result[index.TimeUnit()] = value + index += 1 + +proc `$`*(ti: TimeInterval): string = + ## Get string representation of ``TimeInterval``. + runnableExamples: + doAssert $initTimeInterval(years = 1, nanoseconds = 123) == + "1 year and 123 nanoseconds" + doAssert $initTimeInterval() == "0 nanoseconds" + + var parts: seq[string] = @[] + var tiParts = toParts(ti) + for unit in countdown(Years, Nanoseconds): + if tiParts[unit] != 0: + parts.add(stringifyUnit(tiParts[unit], unit)) + + result = humanizeParts(parts) + +proc nanoseconds*(nanos: int): TimeInterval {.inline.} = + ## TimeInterval of ``nanos`` nanoseconds. + initTimeInterval(nanoseconds = nanos) + +proc microseconds*(micros: int): TimeInterval {.inline.} = + ## TimeInterval of ``micros`` microseconds. + initTimeInterval(microseconds = micros) + +proc milliseconds*(ms: int): TimeInterval {.inline.} = + ## TimeInterval of ``ms`` milliseconds. + initTimeInterval(milliseconds = ms) + +proc seconds*(s: int): TimeInterval {.inline.} = + ## TimeInterval of ``s`` seconds. + ## + ## ``echo getTime() + 5.seconds`` + initTimeInterval(seconds = s) + +proc minutes*(m: int): TimeInterval {.inline.} = + ## TimeInterval of ``m`` minutes. + ## + ## ``echo getTime() + 5.minutes`` + initTimeInterval(minutes = m) + +proc hours*(h: int): TimeInterval {.inline.} = + ## TimeInterval of ``h`` hours. + ## + ## ``echo getTime() + 2.hours`` + initTimeInterval(hours = h) + +proc days*(d: int): TimeInterval {.inline.} = + ## TimeInterval of ``d`` days. + ## + ## ``echo getTime() + 2.days`` + initTimeInterval(days = d) + +proc weeks*(w: int): TimeInterval {.inline.} = + ## TimeInterval of ``w`` weeks. + ## + ## ``echo getTime() + 2.weeks`` + initTimeInterval(weeks = w) + +proc months*(m: int): TimeInterval {.inline.} = + ## TimeInterval of ``m`` months. + ## + ## ``echo getTime() + 2.months`` + initTimeInterval(months = m) + +proc years*(y: int): TimeInterval {.inline.} = + ## TimeInterval of ``y`` years. + ## + ## ``echo getTime() + 2.years`` + initTimeInterval(years = y) + +proc evaluateInterval(dt: DateTime, interval: TimeInterval): + tuple[adjDur, absDur: Duration] = + ## Evaluates how many nanoseconds the interval is worth + ## in the context of ``dt``. + ## The result in split into an adjusted diff and an absolute diff. + var months = interval.years * 12 + interval.months + var curYear = dt.year + var curMonth = dt.month + # Subtracting + if months < 0: + for mth in countdown(-1 * months, 1): + if curMonth == mJan: + curMonth = mDec + curYear.dec + else: + curMonth.dec() + let days = getDaysInMonth(curMonth, curYear) + result.adjDur = result.adjDur - initDuration(days = days) + # Adding + else: + for mth in 1 .. months: + let days = getDaysInMonth(curMonth, curYear) + result.adjDur = result.adjDur + initDuration(days = days) + if curMonth == mDec: + curMonth = mJan + curYear.inc + else: + curMonth.inc() + + result.adjDur = result.adjDur + initDuration( + days = interval.days, + weeks = interval.weeks) + result.absDur = initDuration( + nanoseconds = interval.nanoseconds, + microseconds = interval.microseconds, + milliseconds = interval.milliseconds, + seconds = interval.seconds, + minutes = interval.minutes, + hours = interval.hours) + +proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = + ## Adds ``interval`` to ``dt``. Components from ``interval`` are added + ## in the order of their size, i.e. first the ``years`` component, then the + ## ``months`` component and so on. The returned ``DateTime`` will have the + ## same timezone as the input. + ## + ## Note that when adding months, monthday overflow is allowed. This means that + ## if the resulting month doesn't have enough days it, the month will be + ## incremented and the monthday will be set to the number of days overflowed. + ## So adding one month to `31 October` will result in `31 November`, which + ## will overflow and result in `1 December`. + runnableExamples: + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + doAssert $(dt + 1.months) == "2017-04-30T00:00:00Z" + # This is correct and happens due to monthday overflow. + doAssert $(dt - 1.months) == "2017-03-02T00:00:00Z" + let (adjDur, absDur) = evaluateInterval(dt, interval) + + if adjDur != DurationZero: + var zt = dt.timezone.zonedTimeFromAdjTime(dt.toAdjTime + adjDur) + if absDur != DurationZero: + zt = dt.timezone.zonedTimeFromTime(zt.time + absDur) + result = initDateTime(zt, dt.timezone) + else: + result = initDateTime(zt, dt.timezone) + else: + var zt = dt.timezone.zonedTimeFromTime(dt.toTime + absDur) + result = initDateTime(zt, dt.timezone) + +proc `-`*(dt: DateTime, interval: TimeInterval): DateTime = + ## Subtract ``interval`` from ``dt``. Components from ``interval`` are + ## subtracted in the order of their size, i.e. first the ``years`` component, + ## then the ``months`` component and so on. The returned ``DateTime`` will + ## have the same timezone as the input. + runnableExamples: + let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + doAssert $(dt - 5.days) == "2017-03-25T00:00:00Z" + + dt + (-interval) + +proc `+`*(time: Time, interval: TimeInterval): Time = + ## Adds `interval` to `time`. + ## If `interval` contains any years, months, weeks or days the operation + ## is performed in the local timezone. + runnableExamples: + let tm = fromUnix(0) + doAssert tm + 5.seconds == fromUnix(5) + + if interval.isStaticInterval: + time + evaluateStaticInterval(interval) + else: + toTime(time.local + interval) + +proc `-`*(time: Time, interval: TimeInterval): Time = + ## Subtracts `interval` from Time `time`. + ## If `interval` contains any years, months, weeks or days the operation + ## is performed in the local timezone. + runnableExamples: + let tm = fromUnix(5) + doAssert tm - 5.seconds == fromUnix(0) + + if interval.isStaticInterval: + time - evaluateStaticInterval(interval) + else: + toTime(time.local - interval) + +proc `+=`*(a: var DateTime, b: TimeInterval) = + a = a + b + +proc `-=`*(a: var DateTime, b: TimeInterval) = + a = a - b + +proc `+=`*(t: var Time, b: TimeInterval) = + t = t + b + +proc `-=`*(t: var Time, b: TimeInterval) = + t = t - b + +# +# Other +# + +proc epochTime*(): float {.tags: [TimeEffect].} = + ## gets time after the UNIX epoch (1970) in seconds. It is a float + ## because sub-second resolution is likely to be supported (depending + ## on the hardware/OS). + ## + ## ``getTime`` should generally be preferred over this proc. + when defined(macosx): + var a: Timeval + gettimeofday(a) + result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat( + a.tv_usec)*0.00_0001 + elif defined(posix): + var ts: Timespec + discard clock_gettime(CLOCK_REALTIME, ts) + result = toBiggestFloat(ts.tv_sec.int64) + + toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 + elif defined(windows): + var f: winlean.FILETIME + getSystemTimeAsFileTime(f) + var i64 = rdFileTime(f) - epochDiff + var secs = i64 div rateDiff + var subsecs = i64 mod rateDiff + result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001 + elif defined(js): + result = newDate().getTime() / 1000 + else: + {.error: "unknown OS".} + +when not defined(js): + type + Clock {.importc: "clock_t".} = distinct int + + proc getClock(): Clock + {.importc: "clock", header: "", tags: [TimeEffect], used, sideEffect.} + + var + clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl, used.}: int + + proc cpuTime*(): float {.tags: [TimeEffect].} = + ## gets time spent that the CPU spent to run the current process in + ## seconds. This may be more useful for benchmarking than ``epochTime``. + ## However, it may measure the real time instead (depending on the OS). + ## The value of the result has no meaning. + ## To generate useful timing values, take the difference between + ## the results of two ``cpuTime`` calls: + runnableExamples: + var t0 = cpuTime() + # some useless work here (calculate fibonacci) + var fib = @[0, 1, 1] + for i in 1..10: + fib.add(fib[^1] + fib[^2]) + echo "CPU time [s] ", cpuTime() - t0 + echo "Fib is [s] ", fib + when defined(posix) and not defined(osx) and declared(CLOCK_THREAD_CPUTIME_ID): + # 'clocksPerSec' is a compile-time constant, possibly a + # rather awful one, so use clock_gettime instead + var ts: Timespec + discard clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts) + result = toFloat(ts.tv_sec.int) + + toFloat(ts.tv_nsec.int) / 1_000_000_000 + else: + result = toFloat(int(getClock())) / toFloat(clocksPerSec) + +# +# Deprecations +# + proc countLeapYears*(yearSpan: int): int {.deprecated.} = ## Returns the number of leap years spanned by a given number of years. @@ -2532,73 +2624,6 @@ proc toTimeInterval*(time: Time): TimeInterval initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour, dt.monthday, 0, dt.month.ord - 1, dt.year) -when not defined(js): - type - Clock {.importc: "clock_t".} = distinct int - - proc getClock(): Clock - {.importc: "clock", header: "", tags: [TimeEffect], used, sideEffect.} - - var - clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl, used.}: int - - proc cpuTime*(): float {.tags: [TimeEffect].} = - ## gets time spent that the CPU spent to run the current process in - ## seconds. This may be more useful for benchmarking than ``epochTime``. - ## However, it may measure the real time instead (depending on the OS). - ## The value of the result has no meaning. - ## To generate useful timing values, take the difference between - ## the results of two ``cpuTime`` calls: - runnableExamples: - var t0 = cpuTime() - # some useless work here (calculate fibonacci) - var fib = @[0, 1, 1] - for i in 1..10: - fib.add(fib[^1] + fib[^2]) - echo "CPU time [s] ", cpuTime() - t0 - echo "Fib is [s] ", fib - when defined(posix) and not defined(osx) and declared(CLOCK_THREAD_CPUTIME_ID): - # 'clocksPerSec' is a compile-time constant, possibly a - # rather awful one, so use clock_gettime instead - var ts: Timespec - discard clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts) - result = toFloat(ts.tv_sec.int) + - toFloat(ts.tv_nsec.int) / 1_000_000_000 - else: - result = toFloat(int(getClock())) / toFloat(clocksPerSec) - - proc epochTime*(): float {.tags: [TimeEffect].} = - ## gets time after the UNIX epoch (1970) in seconds. It is a float - ## because sub-second resolution is likely to be supported (depending - ## on the hardware/OS). - ## - ## ``getTime`` should generally be preferred over this proc. - when defined(macosx): - var a: Timeval - gettimeofday(a) - result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat( - a.tv_usec)*0.00_0001 - elif defined(posix): - var ts: Timespec - discard clock_gettime(CLOCK_REALTIME, ts) - result = toBiggestFloat(ts.tv_sec.int64) + - toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 - elif defined(windows): - var f: winlean.FILETIME - getSystemTimeAsFileTime(f) - var i64 = rdFileTime(f) - epochDiff - var secs = i64 div rateDiff - var subsecs = i64 mod rateDiff - result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001 - else: - {.error: "unknown OS".} - -when defined(js): - proc epochTime*(): float {.tags: [TimeEffect].} = - newDate().getTime() / 1000 - -# Deprecated procs - proc weeks*(dur: Duration): int64 {.inline, deprecated: "Use `inWeeks` instead".} = ## Number of whole weeks represented by the duration. From 5db0bb744c08feb0c2c17ecd9cba12c276cde374 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 21 Apr 2020 19:12:32 +0100 Subject: [PATCH 0366/4254] Replace enum fields idents with syms (#14048) * replace enum fields idents with syms * Trigger build Co-authored-by: cooldome --- changelog.md | 4 ++++ compiler/semtypes.nim | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index dbe1f89cc..c30abab9f 100644 --- a/changelog.md +++ b/changelog.md @@ -60,6 +60,10 @@ x.val = nil ``` +- getImpl() on enum type symbols now returns field syms instead of idents. This helps + with writing typed macros. Old behavior for backwards compatiblity can be restored + with command line switch `--oldast`. + ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7fe23eb8e..7ede8e792 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -62,6 +62,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = counter, x: BiggestInt e: PSym base: PType + identToReplace: ptr PNode counter = 0 base = nil result = newOrPrevType(tyEnum, prev, c) @@ -83,9 +84,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = of nkEnumFieldDef: if n[i][0].kind == nkPragmaExpr: e = newSymS(skEnumField, n[i][0][0], c) + identToReplace = addr n[i][0][0] pragma(c, e, n[i][0][1], enumFieldPragmas) else: e = newSymS(skEnumField, n[i][0], c) + identToReplace = addr n[i][0] var v = semConstExpr(c, n[i][1]) var strVal: PNode = nil case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind @@ -118,19 +121,24 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e = n[i].sym of nkIdent, nkAccQuoted: e = newSymS(skEnumField, n[i], c) + identToReplace = addr n[i] of nkPragmaExpr: e = newSymS(skEnumField, n[i][0], c) pragma(c, e, n[i][1], enumFieldPragmas) + identToReplace = addr n[i][0] else: illFormedAst(n[i], c.config) e.typ = result e.position = int(counter) + let symNode = newSymNode(e) + if optOldAst notin c.config.options and identToReplace != nil: + identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: incl(e.flags, sfUsed) incl(e.flags, sfExported) if not isPure: strTableAdd(c.module.tab, e) - result.n.add newSymNode(e) + result.n.add symNode styleCheckDef(c.config, e) onDef(e.info, e) if sfGenSym notin e.flags: From cb2b9bd797b4ea8765eda302f66cd13907f28bd6 Mon Sep 17 00:00:00 2001 From: Arnaud Moura Date: Tue, 21 Apr 2020 22:07:19 +0200 Subject: [PATCH 0367/4254] Add package install command for FreeBSD and OpenBSD. (#14051) --- lib/pure/distros.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 8d4fbc857..a8f0946e1 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -231,8 +231,10 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = result = ("netpkg install " & p, true) elif detectOs(NixOS): result = ("nix-env -i " & p, false) - elif detectOs(Solaris): + elif detectOs(Solaris) or detectOs(FreeBSD): result = ("pkg install " & p, true) + elif detectOs(OpenBSD): + result = ("pkg_add " & p, true) elif detectOs(PCLinuxOS): result = ("rpm -ivh " & p, true) elif detectOs(ArchLinux) or detectOs(Manjaro): From 5608a4e57b521f2a31b35b4c7f905a87b6e7b0aa Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Tue, 21 Apr 2020 23:09:19 +0300 Subject: [PATCH 0368/4254] Add deques.peekFirst/Last(var Deque[T]) -> var T (#13542) * Add deques.peekFirst/Last(var Deque[T]) -> var T * Add changelog entry for deques.peekFirst/Last var T overloads * Add since annotation to peekFirst/peekLast Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/pure/collections/deques.nim | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/changelog.md b/changelog.md index c30abab9f..69e7ebfb8 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,7 @@ - The default hash for `Ordinal` has changed to something more bit-scrambling. `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old one in an instantiation context while `-d:nimIntHash1` recovers it globally. +- `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads. - File handles created from high-level abstractions in the stdlib will no longer be inherited by child processes. In particular, these modules are affected: `system`, `nativesockets`, `net` and `selectors`. diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 77579a52b..1f34c3e18 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -51,6 +51,7 @@ ## * `lists module `_ for singly and doubly linked lists and rings ## * `channels module `_ for inter-thread communication +include system/inclrtl import math @@ -363,6 +364,46 @@ proc peekLast*[T](deq: Deque[T]): T {.inline.} = emptyCheck(deq) result = deq.data[(deq.tail - 1) and deq.mask] +proc peekFirst*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = + ## Returns the first element of `deq`, but does not remove it from the deque. + ## + ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],T>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ + runnableExamples: + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) + assert $a == "[10, 20, 30, 40, 50]" + assert a.peekFirst == 10 + assert len(a) == 5 + + emptyCheck(deq) + result = deq.data[deq.head] + +proc peekLast*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = + ## Returns the last element of `deq`, but does not remove it from the deque. + ## + ## See also: + ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],T>`_ + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ + runnableExamples: + var a = initDeque[int]() + for i in 1 .. 5: + a.addLast(10*i) + assert $a == "[10, 20, 30, 40, 50]" + assert a.peekLast == 50 + assert len(a) == 5 + + emptyCheck(deq) + result = deq.data[(deq.tail - 1) and deq.mask] + template destroy(x: untyped) = reset(x) From 1b6c4ed2ba29f855b47ff295515b54c9ae4edafa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 21 Apr 2020 23:19:34 +0200 Subject: [PATCH 0369/4254] fixes #14052 [backport:1.2] (#14055) --- compiler/lineinfos.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 658863676..9c10105b1 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -87,7 +87,8 @@ const warnWriteToForeignHeap: "write to foreign heap", warnUnsafeCode: "unsafe code: '$1'", warnUnusedImportX: "imported and not used: '$1'", - warnInheritFromException: "inherit from a more precise exception type like ValueError, IOError or OSError", + warnInheritFromException: "inherit from a more precise exception type like ValueError, " & + "IOError or OSError. If these don't suit, inherit from CatchableError or Defect.", warnEachIdentIsTuple: "each identifier is a tuple", warnUnsafeSetLen: "setLen can potentially expand the sequence, " & "but the element type '$1' doesn't have a valid default value", From dd24004fabaf315463b89d38ac553b20080fd1cd Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 21 Apr 2020 23:27:19 +0200 Subject: [PATCH 0370/4254] cleanup PR #14048 --- changelog.md | 6 +++--- compiler/semtypes.nim | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 69e7ebfb8..4db405013 100644 --- a/changelog.md +++ b/changelog.md @@ -32,7 +32,7 @@ and `ioselector_epoll` will no longer be leaked to child processes. ## Language changes -- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: +- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: ```nim type MyObj = object @@ -62,8 +62,8 @@ ``` - getImpl() on enum type symbols now returns field syms instead of idents. This helps - with writing typed macros. Old behavior for backwards compatiblity can be restored - with command line switch `--oldast`. + with writing typed macros. Old behavior for backwards compatiblity can be restored + with command line switch `--useVersion:1.0`. ## Compiler changes diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7ede8e792..96fd6be05 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -131,7 +131,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e.typ = result e.position = int(counter) let symNode = newSymNode(e) - if optOldAst notin c.config.options and identToReplace != nil: + if optNimV1Emulation notin c.config.options and identToReplace != nil: identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: @@ -1590,7 +1590,7 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode = discard "User-defined pragma" else: let sym = searchInScopes(c, ident) - if sym != nil and sfCustomPragma in sym.flags: + if sym != nil and sfCustomPragma in sym.flags: discard "Custom user pragma" else: # we transform ``(arg1, arg2: T) {.m, rest.}`` into ``m((arg1, arg2: T) {.rest.})`` and From 7ce0358351d8e241463e744d75e78c4cd810d19f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 21 Apr 2020 14:53:55 -0700 Subject: [PATCH 0371/4254] fix #13222: make relativePath more robust and flexible (#13451) * * relativePath(foo) now works * relativePath(rel, abs) and relativePath(abs, rel) now work (fixes #13222) * relativePath, absolutePath, getCurrentDir now available in more targets (eg: vm, nodejs etc) * fix bug: isAbsolutePath now works with -d:js; add tests * workaround https://github.com/nim-lang/Nim/issues/13469 * remove `relativePath(path)` overload for now * add back changelog after rebase --- changelog.md | 6 ++ lib/pure/os.nim | 158 ++++++++++++++++++++++++------------------- tests/js/tos.nim | 14 ++++ tests/stdlib/tos.nim | 3 + 4 files changed, 113 insertions(+), 68 deletions(-) diff --git a/changelog.md b/changelog.md index 4db405013..fc409c8aa 100644 --- a/changelog.md +++ b/changelog.md @@ -31,6 +31,12 @@ - The file descriptors created for internal bookkeeping by `ioselector_kqueue` and `ioselector_epoll` will no longer be leaked to child processes. +- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results + (see #13222); instead they now use `getCurrentDir` to resolve those cases, + and this can now throw in edge cases where `getCurrentDir` throws. + `relativePath` also now works for js with `-d:nodejs`. + + ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: ```nim diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e1e5f31b4..2c3e91be8 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -98,6 +98,8 @@ type include "includes/osseps" +proc absolutePathInternal(path: string): string {.gcsafe.} + proc normalizePathEnd(path: var string, trailingSep = false) = ## Ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on ## ``trailingSep``, and taking care of edge cases: it preservers whether @@ -297,8 +299,12 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raise result = path[0] != ':' elif defined(RISCOS): result = path[0] == '$' - elif defined(posix): + elif defined(posix) or defined(js): + # `or defined(js)` wouldn't be needed pending https://github.com/nim-lang/Nim/issues/13469 + # This works around the problem for posix, but windows is still broken with nim js -d:nodejs result = path[0] == '/' + else: + doAssert false # if ever hits here, adapt as needed when FileSystemCaseSensitive: template `!=?`(a, b: char): bool = a != b @@ -360,8 +366,8 @@ when doslikeFileSystem: else: return false -proc relativePath*(path, base: string; sep = DirSep): string {. - noSideEffect, rtl, extern: "nos$1", raises: [].} = +proc relativePath*(path, base: string, sep = DirSep): string {. + rtl, extern: "nos$1".} = ## Converts `path` to a path relative to `base`. ## ## The `sep` (default: `DirSep <#DirSep>`_) is used for the path normalizations, @@ -390,6 +396,12 @@ proc relativePath*(path, base: string; sep = DirSep): string {. var path = path path.normalizePathAux base.normalizePathAux + let a1 = isAbsolute(path) + let a2 = isAbsolute(base) + if a1 and not a2: + base = absolutePathInternal(base) + elif a2 and not a1: + path = absolutePathInternal(path) when doslikeFileSystem: if isAbsolute(path) and isAbsolute(base): @@ -1293,60 +1305,67 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noNimScript.} = else: result = getLastModificationTime(a) > getLastModificationTime(b) -proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [], noNimScript.} = - ## Returns the `current working directory`:idx: i.e. where the built - ## binary is run. - ## - ## So the path returned by this proc is determined at run time. - ## - ## See also: - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getConfigDir proc <#getConfigDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ - ## * `currentSourcePath template `_ - ## * `getProjectPath proc `_ - when defined(windows): - var bufsize = MAX_PATH.int32 - when useWinUnicode: - var res = newWideCString("", bufsize) - while true: - var L = getCurrentDirectoryW(bufsize, res) - if L == 0'i32: - raiseOSError(osLastError()) - elif L > bufsize: - res = newWideCString("", L) - bufsize = L - else: - result = res$L - break +when not defined(nimscript): + proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} = + ## Returns the `current working directory`:idx: i.e. where the built + ## binary is run. + ## + ## So the path returned by this proc is determined at run time. + ## + ## See also: + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getConfigDir proc <#getConfigDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `currentSourcePath template `_ + ## * `getProjectPath proc `_ + when defined(nodejs): + var ret: cstring + {.emit: "`ret` = process.cwd();".} + return $ret + elif defined(js): + doAssert false, "use -d:nodejs to have `getCurrentDir` defined" + elif defined(windows): + var bufsize = MAX_PATH.int32 + when useWinUnicode: + var res = newWideCString("", bufsize) + while true: + var L = getCurrentDirectoryW(bufsize, res) + if L == 0'i32: + raiseOSError(osLastError()) + elif L > bufsize: + res = newWideCString("", L) + bufsize = L + else: + result = res$L + break + else: + result = newString(bufsize) + while true: + var L = getCurrentDirectoryA(bufsize, result) + if L == 0'i32: + raiseOSError(osLastError()) + elif L > bufsize: + result = newString(L) + bufsize = L + else: + setLen(result, L) + break else: + var bufsize = 1024 # should be enough result = newString(bufsize) while true: - var L = getCurrentDirectoryA(bufsize, result) - if L == 0'i32: - raiseOSError(osLastError()) - elif L > bufsize: - result = newString(L) - bufsize = L - else: - setLen(result, L) + if getcwd(result, bufsize) != nil: + setLen(result, c_strlen(result)) break - else: - var bufsize = 1024 # should be enough - result = newString(bufsize) - while true: - if getcwd(result, bufsize) != nil: - setLen(result, c_strlen(result)) - break - else: - let err = osLastError() - if err.int32 == ERANGE: - bufsize = bufsize shl 1 - doAssert(bufsize >= 0) - result = newString(bufsize) else: - raiseOSError(osLastError()) + let err = osLastError() + if err.int32 == ERANGE: + bufsize = bufsize shl 1 + doAssert(bufsize >= 0) + result = newString(bufsize) + else: + raiseOSError(osLastError()) proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} = ## Sets the `current working directory`:idx:; `OSError` @@ -1366,23 +1385,26 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} = else: if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir) -when not weirdTarget: - proc absolutePath*(path: string, root = getCurrentDir()): string {.noNimScript.} = - ## Returns the absolute path of `path`, rooted at `root` (which must be absolute; - ## default: current directory). - ## If `path` is absolute, return it, ignoring `root`. - ## - ## See also: - ## * `normalizedPath proc <#normalizedPath,string>`_ - ## * `normalizePath proc <#normalizePath,string>`_ - runnableExamples: - assert absolutePath("a") == getCurrentDir() / "a" - if isAbsolute(path): path - else: - if not root.isAbsolute: - raise newException(ValueError, "The specified root is not absolute: " & root) - joinPath(root, path) +proc absolutePath*(path: string, root = getCurrentDir()): string = + ## Returns the absolute path of `path`, rooted at `root` (which must be absolute; + ## default: current directory). + ## If `path` is absolute, return it, ignoring `root`. + ## + ## See also: + ## * `normalizedPath proc <#normalizedPath,string>`_ + ## * `normalizePath proc <#normalizePath,string>`_ + runnableExamples: + assert absolutePath("a") == getCurrentDir() / "a" + + if isAbsolute(path): path + else: + if not root.isAbsolute: + raise newException(ValueError, "The specified root is not absolute: " & root) + joinPath(root, path) + +proc absolutePathInternal(path: string): string = + absolutePath(path, getCurrentDir()) proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## Normalize a path. diff --git a/tests/js/tos.nim b/tests/js/tos.nim index 7395a0ad7..30c19c1ae 100644 --- a/tests/js/tos.nim +++ b/tests/js/tos.nim @@ -5,3 +5,17 @@ import os block: doAssert "./foo//./bar/".normalizedPath == "foo/bar" doAssert relativePath(".//foo/bar", "foo") == "bar" + doAssert "/".isAbsolute + doAssert not "".isAbsolute + doAssert not ".".isAbsolute + doAssert not "foo".isAbsolute + doAssert relativePath("", "bar") == "" + doAssert normalizedPath(".///foo//./") == "foo" + let cwd = getCurrentDir() + + let isWindows = '\\' in cwd + # defined(windows) doesn't work with -d:nodejs but should + # these actually break because of that (see https://github.com/nim-lang/Nim/issues/13469) + if not isWindows: + doAssert cwd.isAbsolute + doAssert relativePath(getCurrentDir() / "foo", "bar") == "../foo" diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index be5384015..20e82173d 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -348,6 +348,9 @@ block ospaths: doAssert relativePath("", "foo") == "" doAssert relativePath("././/foo", "foo//./") == "." + doAssert relativePath(getCurrentDir() / "bar", "foo") == "../bar".unixToNativePath + doAssert relativePath("bar", getCurrentDir() / "foo") == "../bar".unixToNativePath + when doslikeFileSystem: doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim" doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim" From 9604a5a97af45fa601d8d38827eb1462642e2c16 Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Tue, 21 Apr 2020 23:23:15 -0400 Subject: [PATCH 0372/4254] fix typo (#14063) --- compiler/semtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 96fd6be05..ec53e14a4 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -131,7 +131,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e.typ = result e.position = int(counter) let symNode = newSymNode(e) - if optNimV1Emulation notin c.config.options and identToReplace != nil: + if optNimV1Emulation notin c.config.globalOptions and identToReplace != nil: identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: From dc40fb805f82bad83d5892e1c5734942a2ceade7 Mon Sep 17 00:00:00 2001 From: Arnaud Moura Date: Wed, 22 Apr 2020 07:49:42 +0200 Subject: [PATCH 0373/4254] Fix OS detection in a docker container (#13172) * Support detection in docker container. * Get only ID information in os-release. * Add test to distros module. * Fix Linux OS detection in Windows. * Fix OS detection for FreeBSD and OpenBSD. --- lib/pure/distros.nim | 78 ++++++++++++++++++------------- tests/distros/tdistros_detect.nim | 21 +++++++++ 2 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 tests/distros/tdistros_detect.nim diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index a8f0946e1..ae2248b40 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -136,18 +136,24 @@ const LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, Distribution.ArchLinux} -# we cache the result of the 'uname -a' +# we cache the result of the 'cmdRelease' # execution for faster platform detections. -var unameRes, releaseRes, hostnamectlRes: string +var unameRes, osReleaseIDRes, releaseRes, hostnamectlRes: string -template unameRelease(cmd, cache): untyped = +template cmdRelease(cmd, cache): untyped = if cache.len == 0: cache = (when defined(nimscript): gorge(cmd) else: execProcess(cmd)) cache -template uname(): untyped = unameRelease("uname -a", unameRes) -template release(): untyped = unameRelease("lsb_release -d", releaseRes) -template hostnamectl(): untyped = unameRelease("hostnamectl", hostnamectlRes) +template uname(): untyped = cmdRelease("uname -a", unameRes) +template osReleaseID(): untyped = cmdRelease("cat /etc/os-release | grep ^ID=", osReleaseIDRes) +template release(): untyped = cmdRelease("lsb_release -d", releaseRes) +template hostnamectl(): untyped = cmdRelease("hostnamectl", hostnamectlRes) + +proc detectOsWithAllCmd(d: Distribution): bool = + let dd = toLowerAscii($d) + result = dd in toLowerAscii(osReleaseID()) or dd in toLowerAscii(release()) or + dd in toLowerAscii(uname()) or ("operating system: " & dd) in toLowerAscii(hostnamectl()) proc detectOsImpl(d: Distribution): bool = case d @@ -156,34 +162,42 @@ proc detectOsImpl(d: Distribution): bool = of Distribution.Posix: result = defined(posix) of Distribution.MacOSX: result = defined(macosx) of Distribution.Linux: result = defined(linux) - of Distribution.Ubuntu: - result = "Ubuntu" in release() or ("-" & $d & " ") in uname() - of Distribution.Gentoo, Distribution.FreeBSD, - Distribution.OpenBSD: - result = ("-" & $d & " ") in uname() - of Distribution.RedHat: - result = "Red Hat" in uname() of Distribution.BSD: result = defined(bsd) - of Distribution.ArchLinux: - result = "arch" in toLowerAscii(uname()) - of Distribution.NixOS: - result = existsEnv("NIX_BUILD_TOP") or existsEnv("__NIXOS_SET_ENVIRONMENT_DONE") - # Check if this is a Nix build or NixOS environment - of Distribution.OpenSUSE: - result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release()) - of Distribution.GoboLinux: - result = "-Gobo " in uname() - of Distribution.OpenMandriva: - result = "mandriva" in toLowerAscii(uname()) - of Distribution.Solaris: - let uname = toLowerAscii(uname()) - result = ("sun" in uname) or ("solaris" in uname) - of Distribution.Haiku: - result = defined(haiku) else: - let dd = toLowerAscii($d) - result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release()) or - ("operating system: " & dd) in toLowerAscii(hostnamectl()) + when defined(bsd): + case d + of Distribution.FreeBSD, Distribution.OpenBSD: + result = $d in uname() + else: + result = false + elif defined(linux): + case d + of Distribution.Gentoo: + result = ("-" & $d & " ") in uname() + of Distribution.Elementary, Distribution.Ubuntu, Distribution.Debian, Distribution.Fedora, + Distribution.OpenMandriva, Distribution.CentOS, Distribution.Alpine, + Distribution.Mageia, Distribution.Zorin: + result = toLowerAscii($d) in osReleaseID() + of Distribution.RedHat: + result = "rhel" in osReleaseID() + of Distribution.ArchLinux: + result = "arch" in osReleaseID() + of Distribution.NixOS: + result = existsEnv("NIX_BUILD_TOP") or existsEnv("__NIXOS_SET_ENVIRONMENT_DONE") + # Check if this is a Nix build or NixOS environment + of Distribution.OpenSUSE: + result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release()) + of Distribution.GoboLinux: + result = "-Gobo " in uname() + of Distribution.Solaris: + let uname = toLowerAscii(uname()) + result = ("sun" in uname) or ("solaris" in uname) + of Distribution.Haiku: + result = defined(haiku) + else: + result = detectOsWithAllCmd(d) + else: + result = false template detectOs*(d: untyped): bool = ## Distro/OS detection. For convenience the diff --git a/tests/distros/tdistros_detect.nim b/tests/distros/tdistros_detect.nim new file mode 100644 index 000000000..793a9edd3 --- /dev/null +++ b/tests/distros/tdistros_detect.nim @@ -0,0 +1,21 @@ +import distros + +discard """ + exitcode: 0 + output: "" +""" + +when defined(windows): + doAssert detectOs(Windows) == true + doAssert detectOs(Ubuntu) == false + doAssert detectOs(MacOSX) == false + +when defined(linux): + doAssert detectOs(Ubuntu) == true + doAssert detectOs(Windows) == false + doAssert detectOs(MacOSX) == false + +when defined(macosx): + doAssert detectOs(MacOSX) == true + doAssert detectOs(Windows) == false + doAssert detectOs(Ubuntu) == false \ No newline at end of file From eb6f5237339e4f246118df750bc89624c4c42884 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 21 Apr 2020 22:50:38 -0700 Subject: [PATCH 0374/4254] fix globalOptions (#14059) From 22418ce8fb07d6fd706b16656fba5e8c0e8ba2f4 Mon Sep 17 00:00:00 2001 From: alaviss Date: Wed, 22 Apr 2020 05:51:18 +0000 Subject: [PATCH 0375/4254] tools/finish: don't quote path with space (#14058) [backport] Path with spaces should be added as is, quoting them makes utilities treat the quotes as part of the path. This makes `nim` unable to be used from the command line even if it appears to be added to user's Path environment variable. Even more confusing, Windows 10's PATH editor shows the path without any quotes, you only see them when you use "Edit text". Took me a good 15 minutes to figure out why couldn't I run `nim` despite it being in Path. --- tools/finish.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/finish.nim b/tools/finish.nim index ccbb698f4..4b5131045 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -123,12 +123,11 @@ when defined(windows): proc addToPathEnv*(e: string) = var p = tryGetUnicodeValue(r"Environment", "Path", HKEY_CURRENT_USER) - let x = if e.contains(Whitespace): "\"" & e & "\"" else: e if p.len > 0: p.add ";" - p.add x + p.add e else: - p = x + p = e setUnicodeValue(r"Environment", "Path", p, HKEY_CURRENT_USER) proc createShortcut(src, dest: string; icon = "") = From c3f4b93060b5e72b5ee1a4e37d5c69e63e7d8bb8 Mon Sep 17 00:00:00 2001 From: Hessam Mehr Date: Wed, 22 Apr 2020 07:31:24 +0100 Subject: [PATCH 0376/4254] Treat zig like clang/gcc wrt integer arithmetic. (#13957) --- lib/system/integerops.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/integerops.nim b/lib/system/integerops.nim index 6f3be4c89..d0bea5f09 100644 --- a/lib/system/integerops.nim +++ b/lib/system/integerops.nim @@ -19,7 +19,7 @@ proc raiseDivByZero {.compilerproc, noinline.} = {.pragma: nimbaseH, importc, nodecl, noSideEffect, compilerproc.} -when (defined(gcc) or defined(clang)) and not defined(nimEmulateOverflowChecks): +when (defined(gcc) or defined(clang) or defined(zig)) and not defined(nimEmulateOverflowChecks): # take the #define from nimbase.h proc nimAddInt(a, b: int, res: ptr int): bool {.nimbaseH.} From d42c5a575dfaa6df363fd47c95d13c70aa60729c Mon Sep 17 00:00:00 2001 From: Vindaar Date: Wed, 22 Apr 2020 10:41:56 +0200 Subject: [PATCH 0377/4254] base `parseEnum` on a case statement, fixes #14030 (#14046) * base `parseEnum` on a case statement, fixes #14030 * apply simplifactions / clean up, remove `norm` node, use strVal * export `normalize` in json.nim * cmp using nimIdentNormalize, error at CT if ambiguous enum found `nimIdentNormalize` provided by @cooldome. We track all names of the branches we have created so far and error if a duplicate is found. Dummy change to make github react... * fix docstring of `nimIdentNormalize` * make `typ` arg `typedesc`, add lineinfo, call norm. only once --- lib/pure/json.nim | 2 +- lib/pure/strutils.nim | 93 ++++++++++++++++++++++++++++++++++----- tests/stdlib/tstrutil.nim | 87 ++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 11 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 7921c0c05..20608edef 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -158,7 +158,7 @@ export export parsejson.JsonEventKind, parsejson.JsonError, JsonParser, JsonKindError, open, close, str, getInt, getFloat, kind, getColumn, getLine, getFilename, - errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr + errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr, nimIdentNormalize type JsonNodeKind* = enum ## possible JSON node types diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 535af2b31..ff76fa94f 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -75,6 +75,7 @@ import parseutils from math import pow, floor, log10 from algorithm import reverse +import macros # for `parseEnum` when defined(nimVmExportFixed): from unicode import toLower, toUpper @@ -278,6 +279,26 @@ proc capitalizeAscii*(s: string): string {.noSideEffect, procvar, if s.len == 0: result = "" else: result = toUpperAscii(s[0]) & substr(s, 1) +proc nimIdentNormalize*(s: string): string = + ## Normalizes the string `s` as a Nim identifier. + ## + ## That means to convert to lower case and remove any '_' on all characters + ## except first one. + runnableExamples: + doAssert nimIdentNormalize("Foo_bar") == "Foobar" + result = newString(s.len) + if s.len > 0: + result[0] = s[0] + var j = 1 + for i in 1..len(s) - 1: + if s[i] in {'A'..'Z'}: + result[j] = chr(ord(s[i]) + (ord('a') - ord('A'))) + inc j + elif s[i] != '_': + result[j] = s[i] + inc j + if j != s.len: setLen(result, j) + proc normalize*(s: string): string {.noSideEffect, procvar, rtl, extern: "nsuNormalize".} = ## Normalizes the string `s`. @@ -1229,8 +1250,65 @@ proc parseBool*(s: string): bool = of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) +proc addOfBranch(s: string, field, enumType: NimNode): NimNode = + result = nnkOfBranch.newTree( + newLit s, + nnkCall.newTree(enumType, field) # `T()` + ) + +macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = + # generates a case stmt, which assigns the correct enum field given + # a normalized string comparison to the `argSym` input. + # NOTE: for an enum with fields Foo, Bar, ... we cannot generate + # `of "Foo".nimIdentNormalize: Foo`. + # This will fail, if the enum is not defined at top level (e.g. in a block). + # Thus we check for the field value of the (possible holed enum) and convert + # the integer value to the generic argument `typ`. + let typ = typ.getTypeInst[1] + let impl = typ.getImpl[2] + expectKind impl, nnkEnumTy + result = nnkCaseStmt.newTree(nnkDotExpr.newTree(argSym, + bindSym"nimIdentNormalize")) + # stores all processed field strings to give error msg for ambiguous enums + var foundFields: seq[string] + var fStr: string # string of current field + var fNum: BiggestInt # int value of current field + for f in impl: + case f.kind + of nnkEmpty: continue # skip first node of `enumTy` + of nnkSym, nnkIdent: fStr = f.strVal + of nnkEnumFieldDef: + case f[1].kind + of nnkStrLit: fStr = f[1].strVal + of nnkTupleConstr: + fStr = f[1][1].strVal + fNum = f[1][0].intVal + of nnkIntLit: + fStr = f[0].strVal + fNum = f[1].intVal + else: error("Invalid tuple syntax!", f[1]) + else: error("Invalid node for enum type!", f) + # add field if string not already added + fStr = nimIdentNormalize(fStr) + if fStr notin foundFields: + result.add addOfBranch(fStr, newLit fNum, typ) + foundFields.add fStr + else: + error("Ambiguous enums cannot be parsed, field " & $fStr & + " appears multiple times!") + inc fNum + # finally add else branch to raise or use default + if default == nil: + let raiseStmt = quote do: + raise newException(ValueError, "Invalid enum value: " & $`argSym`) + result.add nnkElse.newTree(raiseStmt) + else: + expectKind(default, nnkSym) + result.add nnkElse.newTree(default) + proc parseEnum*[T: enum](s: string): T = - ## Parses an enum ``T``. + ## Parses an enum ``T``. This errors at compile time, if the given enum + ## type contains multiple fields with the same string value. ## ## Raises ``ValueError`` for an invalid value in `s`. The comparison is ## done in a style insensitive way. @@ -1246,13 +1324,11 @@ proc parseEnum*[T: enum](s: string): T = doAssertRaises(ValueError): echo parseEnum[MyEnum]("third") - for e in low(T)..high(T): - if cmpIgnoreStyle(s, $e) == 0: - return e - raise newException(ValueError, "invalid enum value: " & s) + genEnumStmt(T, s, default = nil) proc parseEnum*[T: enum](s: string, default: T): T = - ## Parses an enum ``T``. + ## Parses an enum ``T``. This errors at compile time, if the given enum + ## type contains multiple fields with the same string value. ## ## Uses `default` for an invalid value in `s`. The comparison is done in a ## style insensitive way. @@ -1267,10 +1343,7 @@ proc parseEnum*[T: enum](s: string, default: T): T = doAssert parseEnum[MyEnum]("second") == second doAssert parseEnum[MyEnum]("last", third) == third - for e in low(T)..high(T): - if cmpIgnoreStyle(s, $e) == 0: - return e - result = default + genEnumStmt(T, s, default) proc repeat*(c: char, count: Natural): string {.noSideEffect, rtl, extern: "nsuRepeatChar".} = diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 9dbc98912..eb0fdbfa5 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -348,3 +348,90 @@ when true: main() #OUT ha/home/a1xyz/usr/bin + + +# `parseEnum`, ref issue #14030 +# check enum defined at top level +type + Foo = enum + A + B = "bb" + C = (5, "ccc") + D = 15 + E = "ee" # check that we count enum fields correctly + +block: + let a = parseEnum[Foo]("A") + let b = parseEnum[Foo]("bb") + let c = parseEnum[Foo]("ccc") + let d = parseEnum[Foo]("D") + let e = parseEnum[Foo]("ee") + doAssert a == A + doAssert b == B + doAssert c == C + doAssert d == D + doAssert e == E + try: + let f = parseEnum[Foo]("Bar") + doAssert false + except ValueError: + discard + + # finally using default + let g = parseEnum[Foo]("Bar", A) + doAssert g == A + +block: + # check enum defined in block + type + Bar = enum + V + W = "ww" + X = (3, "xx") + Y = 10 + Z = "zz" # check that we count enum fields correctly + + let a = parseEnum[Bar]("V") + let b = parseEnum[Bar]("ww") + let c = parseEnum[Bar]("xx") + let d = parseEnum[Bar]("Y") + let e = parseEnum[Bar]("zz") + doAssert a == V + doAssert b == W + doAssert c == X + doAssert d == Y + doAssert e == Z + try: + let f = parseEnum[Bar]("Baz") + doAssert false + except ValueError: + discard + + # finally using default + let g = parseEnum[Bar]("Baz", V) + doAssert g == V + +block: + # check ambiguous enum fails to parse + type + Ambig = enum + f1 = "A" + f2 = "B" + f3 = "A" + + doAssert not compiles((let a = parseEnum[Ambig]("A"))) + +block: + # check almost ambiguous enum + type + AlmostAmbig = enum + f1 = "someA" + f2 = "someB" + f3 = "SomeA" + + let a = parseEnum[AlmostAmbig]("someA") + let b = parseEnum[AlmostAmbig]("someB") + let c = parseEnum[AlmostAmbig]("SomeA") + doAssert a == f1 + doAssert b == f2 + doAssert c == f3 From 5c26a83a4a3b8cf3d77773709e84afd8ec512f51 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 22 Apr 2020 11:38:33 +0200 Subject: [PATCH 0378/4254] use newer nodejs on Azure Pipelines (#14065) --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 57b494bac..c6d0d5e50 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -57,8 +57,8 @@ jobs: - task: NodeTool@0 inputs: - versionSpec: '8.x' - displayName: 'Install node.js 8.x' + versionSpec: '12.x' + displayName: 'Install node.js 12.x' - bash: | sudo apt-fast update -qq From 01523b2b58c8007cc2595f6bcf33cf2ba1d9e38a Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 22 Apr 2020 17:49:41 +0300 Subject: [PATCH 0379/4254] change some Exceptions to CatchableError or Defect, fixes #10288 (#14069) --- lib/impure/nre.nim | 2 +- lib/pure/asyncfutures.nim | 2 +- lib/pure/net.nim | 4 ++-- lib/pure/selectors.nim | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 1d0952274..24b6ff0c7 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -198,7 +198,7 @@ type Captures* = distinct RegexMatch CaptureBounds* = distinct RegexMatch - RegexError* = ref object of Exception + RegexError* = ref object of CatchableError RegexInternalError* = ref object of RegexError ## Internal error in the module, this probably means that there is a bug diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 236a829e3..c1e2770bb 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -33,7 +33,7 @@ type FutureVar*[T] = distinct Future[T] - FutureError* = object of Exception + FutureError* = object of Defect cause*: FutureBase when not defined(release): diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 30355226c..ee00878d3 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -83,7 +83,7 @@ when defineSsl: type Certificate* = string ## DER encoded certificate - SslError* = object of Exception + SslError* = object of CatchableError SslCVerifyMode* = enum CVerifyNone, CVerifyPeer, CVerifyPeerUseEnvVars @@ -146,7 +146,7 @@ type ReadLineResult* = enum ## result for readLineAsync ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone - TimeoutError* = object of Exception + TimeoutError* = object of CatchableError SocketFlag* {.pure.} = enum Peek, diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 743a92dd0..a2329a2dc 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -252,7 +252,7 @@ else: VnodeRename, VnodeRevoke type - IOSelectorsException* = object of Exception + IOSelectorsException* = object of CatchableError ReadyKey* = object fd* : int From 269a458d74e9abbc126d96c506b730c37af0932a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 22 Apr 2020 17:34:35 +0200 Subject: [PATCH 0380/4254] cycle collector (#14071) * figured out the wrong cycle trace proc problem * cycle collector/break refactorings and minor improvements --- compiler/ccgtypes.nim | 3 +- compiler/liftdestructors.nim | 6 +- lib/system/cellseqs_v2.nim | 55 ++++++++++ lib/system/cyclebreaker.nim | 50 +-------- lib/system/cyclicrefs_v2.nim | 75 +++----------- tests/arc/thamming_thinout.nim | 183 +++++++++++++++++++++++++++++++++ 6 files changed, 262 insertions(+), 110 deletions(-) create mode 100644 lib/system/cellseqs_v2.nim create mode 100644 tests/arc/thamming_thinout.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index b116a9aa6..46949831e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1297,7 +1297,8 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = if op == attachedTrace and m.config.selectedGC == gcOrc and containsGarbageCollectedRef(t): when false: - # re-enable this check + # unfortunately this check is wrong for an object type that only contains + # .cursor fields like 'Node' inside 'cycleleak'. internalError(m.config, info, "no attached trace proc found") result = rope("NIM_NIL") diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index a64857765..61034ef03 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -91,7 +91,7 @@ proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = proc genIf(c: var TLiftCtx; cond, action: PNode): PNode = result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action)) -proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode = +proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode = # generate: cast[ptr ObjType](cast[int](addr(x)) - offsetOf(objType.field)) let intType = getSysType(c.g, unknownLineInfo, tyInt) @@ -104,7 +104,7 @@ proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode = let dotExpr = newNodeIT(nkDotExpr, c.info, x.typ) dotExpr.add newNodeIT(nkType, c.info, objType) dotExpr.add newSymNode(field) - + let offsetOf = genBuiltin(c.g, mOffsetOf, "offsetof", dotExpr) offsetOf.typ = intType @@ -174,7 +174,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) caseStmt.add(branch) if emptyBranches != n.len-1: body.add(caseStmt) - c.filterDiscriminator = oldfilterDiscriminator + c.filterDiscriminator = oldfilterDiscriminator of nkRecList: for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp) else: diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim new file mode 100644 index 000000000..c71ba9726 --- /dev/null +++ b/lib/system/cellseqs_v2.nim @@ -0,0 +1,55 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2019 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Cell seqs for cyclebreaker and cyclicrefs_v2. + +type + CellTuple = (ptr pointer, PNimType) + CellArray = ptr UncheckedArray[CellTuple] + CellSeq = object + len, cap: int + d: CellArray + +proc add(s: var CellSeq, c: ptr pointer; t: PNimType) {.inline.} = + if s.len >= s.cap: + s.cap = s.cap * 3 div 2 + when defined(useMalloc): + var d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + else: + var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + copyMem(d, s.d, s.len * sizeof(CellTuple)) + when defined(useMalloc): + c_free(s.d) + else: + dealloc(s.d) + s.d = d + # XXX: realloc? + s.d[s.len] = (c, t) + inc(s.len) + +proc init(s: var CellSeq, cap: int = 1024) = + s.len = 0 + s.cap = cap + when defined(useMalloc): + s.d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + else: + s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + +proc deinit(s: var CellSeq) = + when defined(useMalloc): + c_free(s.d) + else: + dealloc(s.d) + s.d = nil + s.len = 0 + s.cap = 0 + +proc pop(s: var CellSeq): (ptr pointer, PNimType) = + result = s.d[s.len-1] + dec s.len diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim index e036acb53..1f320b30e 100644 --- a/lib/system/cyclebreaker.nim +++ b/lib/system/cyclebreaker.nim @@ -52,6 +52,8 @@ That seems acceptable, no leak is produced. This implies that the standard depth-first traversal suffices. ]# +include cellseqs_v2 + const colGreen = 0b000 colYellow = 0b001 @@ -72,57 +74,9 @@ proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = inc h.rc, rcIncrement type - CellTuple = (ptr pointer, PNimType) - CellArray = ptr UncheckedArray[CellTuple] - CellSeq = object - len, cap: int - d: CellArray - GcEnv = object traceStack: CellSeq -# ------------------- cell seq handling -------------------------------------- - -proc add(s: var CellSeq, c: ptr pointer; t: PNimType) {.inline.} = - if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - when defined(useMalloc): - var d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) - else: - var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) - copyMem(d, s.d, s.len * sizeof(CellTuple)) - when defined(useMalloc): - c_free(s.d) - else: - dealloc(s.d) - s.d = d - # XXX: realloc? - s.d[s.len] = (c, t) - inc(s.len) - -proc init(s: var CellSeq, cap: int = 1024) = - s.len = 0 - s.cap = cap - when defined(useMalloc): - s.d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) - else: - s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) - -proc deinit(s: var CellSeq) = - when defined(useMalloc): - c_free(s.d) - else: - dealloc(s.d) - s.d = nil - s.len = 0 - s.cap = 0 - -proc pop(s: var CellSeq): (ptr pointer, PNimType) = - result = s.d[s.len-1] - dec s.len - -# ---------------------------------------------------------------------------- - proc trace(p: pointer; desc: PNimType; j: var GcEnv) {.inline.} = when false: cprintf("[Trace] desc: %p %p\n", desc, p) diff --git a/lib/system/cyclicrefs_v2.nim b/lib/system/cyclicrefs_v2.nim index 0dd669925..819cb2bd0 100644 --- a/lib/system/cyclicrefs_v2.nim +++ b/lib/system/cyclicrefs_v2.nim @@ -14,6 +14,8 @@ # "Cyclic reference counting" by Rafael Dueire Lins # R.D. Lins / Information Processing Letters 109 (2008) 71–78 +include cellseqs_v2 + const colGreen = 0b000 colYellow = 0b001 @@ -45,58 +47,10 @@ proc markCyclic*[T](x: ref T) {.inline.} = h.setColor colYellow type - CellTuple = (Cell, PNimType) - CellArray = ptr UncheckedArray[CellTuple] - CellSeq = object - len, cap: int - d: CellArray - GcEnv = object traceStack: CellSeq jumpStack: CellSeq -# ------------------- cell seq handling -------------------------------------- - -proc add(s: var CellSeq, c: Cell; t: PNimType) {.inline.} = - if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - when defined(useMalloc): - var d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) - else: - var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) - copyMem(d, s.d, s.len * sizeof(CellTuple)) - when defined(useMalloc): - c_free(s.d) - else: - dealloc(s.d) - s.d = d - # XXX: realloc? - s.d[s.len] = (c, t) - inc(s.len) - -proc init(s: var CellSeq, cap: int = 1024) = - s.len = 0 - s.cap = cap - when defined(useMalloc): - s.d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) - else: - s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) - -proc deinit(s: var CellSeq) = - when defined(useMalloc): - c_free(s.d) - else: - dealloc(s.d) - s.d = nil - s.len = 0 - s.cap = 0 - -proc pop(s: var CellSeq): (Cell, PNimType) = - result = s.d[s.len-1] - dec s.len - -# ---------------------------------------------------------------------------- - proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} = if desc.traceImpl != nil: var p = s +! sizeof(RefHeader) @@ -116,7 +70,10 @@ proc collect(s: Cell; desc: PNimType; j: var GcEnv) = s.setColor colGreen trace(s, desc, j) while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() + let (p, desc) = j.traceStack.pop() + let t = head(p[]) + #Remove(): + p[] = nil if t.color == colRed: t.setColor colGreen trace(t, desc, j) @@ -129,7 +86,8 @@ proc markRed(s: Cell; desc: PNimType; j: var GcEnv) = s.setColor colRed trace(s, desc, j) while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() + let (p, desc) = j.traceStack.pop() + let t = head(p[]) when traceCollector: cprintf("[Cycle dec] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) dec t.rc, rcIncrement @@ -137,7 +95,7 @@ proc markRed(s: Cell; desc: PNimType; j: var GcEnv) = t.rc = t.rc or jumpStackFlag when traceCollector: cprintf("[Now in jumpstack] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) - j.jumpStack.add(t, desc) + j.jumpStack.add(p, desc) if t.color != colRed: t.setColor colRed trace(t, desc, j) @@ -146,7 +104,8 @@ proc scanGreen(s: Cell; desc: PNimType; j: var GcEnv) = s.setColor colGreen trace(s, desc, j) while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() + let (p, desc) = j.traceStack.pop() + let t = head(p[]) if t.color != colGreen: t.setColor colGreen trace(t, desc, j) @@ -158,15 +117,13 @@ proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) - var t = head(p[]) - j.traceStack.add(t, desc) + j.traceStack.add(p, desc) proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) - var t = head(p[]) - j.traceStack.add(t, cast[ptr PNimType](p[])[]) + j.traceStack.add(p, cast[ptr PNimType](p[])[]) proc scan(s: Cell; desc: PNimType; j: var GcEnv) = when traceCollector: @@ -181,7 +138,8 @@ proc scan(s: Cell; desc: PNimType; j: var GcEnv) = # that are still alive; we also need to mark what they # refer to as alive: while j.jumpStack.len > 0: - let (t, desc) = j.jumpStack.pop + let (p, desc) = j.jumpStack.pop + let t = head(p[]) # not in jump stack anymore! t.rc = t.rc and not jumpStackFlag if t.color == colRed and (t.rc and not rcMask) >= 0: @@ -202,7 +160,8 @@ proc traceCycle(s: Cell; desc: PNimType) {.noinline.} = markRed(s, desc, j) scan(s, desc, j) while j.jumpStack.len > 0: - let (t, desc) = j.jumpStack.pop + let (p, desc) = j.jumpStack.pop + let t = head(p[]) # not in jump stack anymore! t.rc = t.rc and not jumpStackFlag deinit j.jumpStack diff --git a/tests/arc/thamming_thinout.nim b/tests/arc/thamming_thinout.nim new file mode 100644 index 000000000..65c34ef49 --- /dev/null +++ b/tests/arc/thamming_thinout.nim @@ -0,0 +1,183 @@ +discard """ + cmd: "nim c --gc:orc -d:nimThinout -r $file" + output: '''The first 20 hammings are: 1 2 3 4 5 MEM IS 0''' +""" + +# test Nim Hamming Number Lazy List algo with reference counts and not... +# compile with "-d:release -d:danger" and test with various +# memory managment GC's, allocators, threading, etc. + +from times import epochTime +from math import log2 + +# implement our own basic BigInt so the bigints library isn't necessary... +type + BigInt = object + digits: seq[uint32] +let zeroBigInt = BigInt(digits: @[ 0'u32 ]) +let oneBigInt = BigInt(digits: @[ 1'u32 ]) + +proc shladd(bi: var BigInt; n: int; a: BigInt) = + var cry = 0'u64 + for i in 0 ..< min(bi.digits.len, a.digits.len): + cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64 + bi.digits[i] = cry.uint32 + cry = cry shr 32 + if cry > 0'u64: + bi.digits.add cry.uint32 + +proc `$`(x: BigInt): string = + if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32): + return "0" + var n = x + var msd = n.digits.high + result = "" + while msd >= 0: + if n.digits[msd] == 0'u32: msd.dec; continue + var brw = 0.uint64 + for i in countdown(msd, 0): + let dvdnd = n.digits[i].uint64 + (brw shl 32) + let q = dvdnd div 10'u64; brw = dvdnd - q*10'u64; n.digits[i] = q.uint32 + result &= $brw + for i in 0 .. result.high shr 1: + let tmp = result[^(i + 1)] + result[^(i + 1)] = result[i] + result[i] = tmp + +proc convertTrival2BigInt(tpl: (uint32, uint32, uint32)): BigInt = + result = oneBigInt + let (x2, x3, x5) = tpl + for _ in 1 .. x2: result.shladd 1, zeroBigInt + for _ in 1 .. x3: result.shladd 1, result + for _ in 1 .. x5: result.shladd 2, result + +type LogRep = (float64, (uint32, uint32, uint32)) +type LogRepf = proc(x: LogRep): LogRep +const one: LogRep = (0.0f64, (0u32, 0u32, 0u32)) +proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0] + +const lb2 = 1.0'f64 +const lb3 = 3.0'f64.log2 +const lb5 = 5.0'f64.log2 + +proc mul2(me: LogRep): LogRep = + let (lr, tpl) = me; let (x2, x3, x5) = tpl + (lr + lb2, (x2 + 1, x3, x5)) + +proc mul3(me: LogRep): LogRep = + let (lr, tpl) = me; let (x2, x3, x5) = tpl + (lr + lb3, (x2, x3 + 1, x5)) + +proc mul5(me: LogRep): LogRep = + let (lr, tpl) = me; let (x2, x3, x5) = tpl + (lr + lb5, (x2, x3, x5 + 1)) + +type + LazyList = ref object + hd: LogRep + tlf: proc(): LazyList {.closure.} + tl: LazyList + +proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk + if ll.tlf != nil: + ll.tl = ll.tlf() + ll.tlf = nil + ll.tl + +iterator hamming(until: int): (uint32, uint32, uint32) = + proc merge(x, y: LazyList): LazyList = + let xh = x.hd + let yh = y.hd + if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y) + else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest) + proc smult(mltf: LogRepf; s: LazyList): LazyList = + proc smults(ss: LazyList): LazyList = + LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults) + s.smults + proc unnsm(s: LazyList, mltf: LogRepf): LazyList = + var r: LazyList = nil + let frst = LazyList(hd: one, tlf: proc(): LazyList = r) + r = if s == nil: smult mltf, frst else: s.merge smult(mltf, frst) + r + var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2 + # var hmpll: LazyList = nil; for m in [mul5, mul3, mul2]: echo one.m # ; hmpll = unnsm(hmpll, m) + yield one[1] + var cnt = 1 + while hmpll != nil: + yield hmpll.hd[1] + hmpll = hmpll.rest # almost forever + cnt.inc + if cnt > until: break + #when declared(thinout): + thinout(hmpll) + +proc main = + stdout.write "The first 20 hammings are: " + for h in hamming(4): + write stdout, h.convertTrival2BigInt, " " + + for h in hamming(200): + discard h.convertTrival2BigInt + +let mem = getOccupiedMem() +main() +echo "MEM IS ", getOccupiedMem() - mem + +#[ +result = (smults, :envP.:up)(rest(:envP.ss2)) + +proc anon = + var + :tmpD_284230 + :tmpD_284233 + :tmpD_284236 + try: + `=sink_283407`(result_283502, + `=sink_283927`(:tmpD_284236, (smults_283495, + wasMoved_284234(:tmpD_284233) + `=_284014`(:tmpD_284233, :envP_283898.:up_283899) + :tmpD_284233)) + :tmpD_284236( + `=sink_283407`(:tmpD_284230, rest_283366(:envP_283898.ss2_-283497)) + :tmpD_284230)) + finally: + `=destroy_283914`(:tmpD_284236) + `=destroy_283388`(:tmpD_284230) + +proc smuls(ss: LazyList_283350; :envP_283891): LazyList_283350 = + var :env_283913 + try: + `=destroy_283951`(:env_283913) + internalNew_43643(:env_283913) + `=_283401`(:env_283913.ss2_-283497, ss_283497) + :env_283913.:up_283899 = :envP_283891 + `=sink_283407`(result_283498, LazyList_283350(hd_283353: :envP_283891.mltf1_-283492( + :env_283913.ss2_-283497.hd_283353), tlf_283356: (:anonymous_283499, + let blitTmp_284227 = :env_283913 + wasMoved_284228(:env_283913) + blitTmp_284227))) + finally: + `=destroy_283951`(:env_283913) + +proc smul = + var + :env_283969 + :tmpD_284220 + try: + `=destroy_284008`(:env_283969) + internalNew_43643(:env_283969) + `=_283976`(:env_283969.mltf1_-283492, mltf_283492) + proc smults(ss: LazyList_283350; :envP_283891): LazyList_283350 = + result_283498 = LazyList_283350(hd_283353: mltf_283492(ss_283497.hd_283353), tlf_283356: proc ( + :envP_283898): auto_43100 = result_283502 = smults_283495(rest_283366(ss_283497))) + + `=sink_283407`(result_283494, + `=sink_283927`(:tmpD_284220, (smults_283495, + let blitTmp_284218 = :env_283969 + wasMoved_284219(:env_283969) + blitTmp_284218)) + :tmpD_284220(s_283493)) + finally: + `=destroy_283914`(:tmpD_284220) + `=destroy_284008`(:env_283969) +]# From 5571d48c327e8bc9667d95b46f87e73c643a94a6 Mon Sep 17 00:00:00 2001 From: wonderix Date: Wed, 22 Apr 2020 17:43:39 +0200 Subject: [PATCH 0381/4254] Add the ability to pass title case headers to an HTTP server (#13968) * Add the ability to pass title case headers to an HTTP server * Remove unnecessary type spec of titleCase * Replace convert member proc by isTitleCase Co-authored-by: wonderix --- lib/pure/httpcore.nim | 50 ++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 8916aa17d..78cb66ded 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -17,6 +17,7 @@ import tables, strutils, parseutils type HttpHeaders* = ref object table*: TableRef[string, seq[string]] + isTitleCase: bool HttpHeaderValues* = distinct seq[string] @@ -100,16 +101,32 @@ const const httpNewLine* = "\c\L" const headerLimit* = 10_000 -proc newHttpHeaders*(): HttpHeaders = +proc toTitleCase(s: string): string = + result = newString(len(s)) + var upper = true + for i in 0..len(s) - 1: + result[i] = if upper: toUpperAscii(s[i]) else: toLowerAscii(s[i]) + upper = s[i] == '-' + +proc toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = + return if headers.isTitleCase: toTitleCase(s) else: toLowerAscii(s) + +proc newHttpHeaders*(titleCase=false): HttpHeaders = + ## Returns a new ``HttpHeaders`` object. if ``titleCase`` is set to true, + ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() + result.isTitleCase = titleCase proc newHttpHeaders*(keyValuePairs: - openArray[tuple[key: string, val: string]]): HttpHeaders = + openArray[tuple[key: string, val: string]], titleCase=false): HttpHeaders = + ## Returns a new ``HttpHeaders`` object from an array. if ``titleCase`` is set to true, + ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() + result.isTitleCase = titleCase for pair in keyValuePairs: - let key = pair.key.toLowerAscii() + let key = result.toCaseInsensitive(pair.key) if key in result.table: result.table[key].add(pair.val) else: @@ -130,7 +147,7 @@ proc `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = ## ## To access multiple values of a key, use the overloaded ``[]`` below or ## to get all of them access the ``table`` field directly. - return headers.table[key.toLowerAscii].HttpHeaderValues + return headers.table[headers.toCaseInsensitive(key)].HttpHeaderValues converter toString*(values: HttpHeaderValues): string = return seq[string](values)[0] @@ -139,30 +156,30 @@ proc `[]`*(headers: HttpHeaders, key: string, i: int): string = ## Returns the ``i``'th value associated with the given key. If there are ## no values associated with the key or the ``i``'th value doesn't exist, ## an exception is raised. - return headers.table[key.toLowerAscii][i] + return headers.table[headers.toCaseInsensitive(key)][i] proc `[]=`*(headers: HttpHeaders, key, value: string) = ## Sets the header entries associated with ``key`` to the specified value. ## Replaces any existing values. - headers.table[key.toLowerAscii] = @[value] + headers.table[headers.toCaseInsensitive(key)] = @[value] proc `[]=`*(headers: HttpHeaders, key: string, value: seq[string]) = ## Sets the header entries associated with ``key`` to the specified list of ## values. ## Replaces any existing values. - headers.table[key.toLowerAscii] = value + headers.table[headers.toCaseInsensitive(key)] = value proc add*(headers: HttpHeaders, key, value: string) = ## Adds the specified value to the specified key. Appends to any existing ## values associated with the key. - if not headers.table.hasKey(key.toLowerAscii): - headers.table[key.toLowerAscii] = @[value] + if not headers.table.hasKey(headers.toCaseInsensitive(key)): + headers.table[headers.toCaseInsensitive(key)] = @[value] else: - headers.table[key.toLowerAscii].add(value) + headers.table[headers.toCaseInsensitive(key)].add(value) proc del*(headers: HttpHeaders, key: string) = ## Delete the header entries associated with ``key`` - headers.table.del(key.toLowerAscii) + headers.table.del(headers.toCaseInsensitive(key)) iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = ## Yields each key, value pair. @@ -177,7 +194,7 @@ proc contains*(values: HttpHeaderValues, value: string): bool = if val.toLowerAscii == value.toLowerAscii: return true proc hasKey*(headers: HttpHeaders, key: string): bool = - return headers.table.hasKey(key.toLowerAscii()) + return headers.table.hasKey(headers.toCaseInsensitive(key)) proc getOrDefault*(headers: HttpHeaders, key: string, default = @[""].HttpHeaderValues): HttpHeaderValues = @@ -336,3 +353,12 @@ when isMainModule: doAssert test["foobar"] == "" doAssert parseHeader("foobar:") == ("foobar", @[""]) + + block: # test title case + var testTitleCase = newHttpHeaders(titleCase=true) + testTitleCase.add("content-length", "1") + doAssert testTitleCase.hasKey("Content-Length") + for key, val in testTitleCase: + doAssert key == "Content-Length" + + From 6c0c8825094453af6f189bda9a7cd2f9551693a6 Mon Sep 17 00:00:00 2001 From: Chris Heller Date: Wed, 22 Apr 2020 08:45:31 -0700 Subject: [PATCH 0382/4254] Make debugSend/debugRecv procs public. Fixes #12189 (#12190) * Make debugSend/debugRecv procs public. Fixes #12189 * Make checkReply proc public. Part of #12189 * Add doc comments for debugSend,debugRecv and checkReply --- lib/pure/smtp.nim | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 1a9e22029..f24815a1d 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -65,12 +65,36 @@ type Smtp* = SmtpBase[Socket] AsyncSmtp* = SmtpBase[AsyncSocket] -proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = +proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = + ## Sends ``cmd`` on the socket connected to the SMTP server. + ## + ## If the ``smtp`` object was created with ``debug`` enabled, + ## debugSend will invoke ``echo("C:" & cmd)`` before sending. + ## + ## This is a lower level proc and not something that you typically + ## would need to call when using this module. One exception to + ## this is if you are implementing any + ## `SMTP extensions`_. + if smtp.debug: echo("C:" & cmd) await smtp.sock.send(cmd) -proc debugRecv(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = +proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = + ## Receives a line of data from the socket connected to the + ## SMTP server. + ## + ## If the ``smtp`` object was created with ``debug`` enabled, + ## debugRecv will invoke ``echo("S:" & result.string)`` after + ## the data is received. + ## + ## This is a lower level proc and not something that you typically + ## would need to call when using this module. One exception to + ## this is if you are implementing any + ## `SMTP extensions`_. + ## + ## See `checkReply(reply)<#checkReply,,string>`_. + result = await smtp.sock.recvLine() if smtp.debug: echo("S:" & result.string) @@ -166,7 +190,17 @@ proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = retFuture.fail(newException(ReplyError, msg)) return retFuture -proc checkReply(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = +proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = + ## Calls `debugRecv<#debugRecv>`_ and checks that the received + ## data starts with ``reply``. If the received data does not start + ## with ``reply``, then a ``QUIT`` command will be sent to the SMTP + ## server and a ``ReplyError`` exception will be raised. + ## + ## This is a lower level proc and not something that you typically + ## would need to call when using this module. One exception to + ## this is if you are implementing any + ## `SMTP extensions`_. + var line = await smtp.debugRecv() if not line.startswith(reply): await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line) From e1cc0219de5a51adb68479aa8923e7151003d95d Mon Sep 17 00:00:00 2001 From: Bung <535670947@qq.com> Date: Thu, 23 Apr 2020 01:46:55 +0800 Subject: [PATCH 0383/4254] =?UTF-8?q?fix=20#14064=20xmltree=20should=20all?= =?UTF-8?q?ow=20create=20text=20node=20with=20raw=20text(non-es=E2=80=A6?= =?UTF-8?q?=20(#14070)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix #14064 xmltree should allow create text node with raw text(non-escaped) eg. html style element's text * change xnRawText to VerbatimText,newRawText to newVerbatimText ,add since anotation * change changelog_1_2_0.md latest date * move change log Co-authored-by: bung87 --- changelog.md | 2 +- changelogs/changelog_1_2_0.md | 1 - lib/pure/xmltree.nim | 12 +++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index fc409c8aa..86d2e181c 100644 --- a/changelog.md +++ b/changelog.md @@ -3,7 +3,7 @@ ## Standard library additions and changes - +- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. - `uri` adds Data URI Base64, implements RFC-2397. - Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) to the `dom` module for the JavaScript target. diff --git a/changelogs/changelog_1_2_0.md b/changelogs/changelog_1_2_0.md index 54ead0087..1f76df0b4 100644 --- a/changelogs/changelog_1_2_0.md +++ b/changelogs/changelog_1_2_0.md @@ -2,7 +2,6 @@ ## Standard library additions and changes - - Added overloaded `strformat.fmt` macro that use specified characters as delimiter instead of '{' and '}'. - Added new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index fbb0ab13a..35010e602 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -35,6 +35,7 @@ ## * `htmlgen module `_ for html code generator import macros, strtabs, strutils +include "system/inclrtl" type XmlNode* = ref XmlNodeObj ## An XML tree consisting of XML nodes. @@ -44,6 +45,7 @@ type XmlNodeKind* = enum ## Different kinds of XML nodes. xnText, ## a text element + xnVerbatimText, ## xnElement, ## an element with 0 or more children xnCData, ## a CDATA node xnEntity, ## an entity (like ``&thing;``) @@ -56,7 +58,7 @@ type XmlNodeObj {.acyclic.} = object case k: XmlNodeKind # private, use the kind() proc to read this field. - of xnText, xnComment, xnCData, xnEntity: + of xnText, xnVerbatimText, xnComment, xnCData, xnEntity: fText: string of xnElement: fTag: string @@ -101,6 +103,12 @@ proc newText*(text: string): XmlNode = result = newXmlNode(xnText) result.fText = text +proc newVerbatimText*(text: string): XmlNode {.since:(1, 3).} = + ## Creates a new ``XmlNode`` of kind ``xnVerbatimText`` with the text `text`. + ## **Since**: Version 1.3. + result = newXmlNode(xnVerbatimText) + result.fText = text + proc newComment*(comment: string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnComment`` with the text `comment`. runnableExamples: @@ -646,6 +654,8 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2, result.add(">") of xnText: result.addEscaped(n.fText) + of xnVerbatimText: + result.add(n.fText) of xnComment: result.add(" Test failure at example.nim:20 with 'tester(1)' proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} = @@ -2493,7 +2493,7 @@ proc `[]=`*[Idx, T, U, V](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T] if L == b.len: for i in 0.. 0.0: - sysFatal(FloatOverflowError, "FPU operation caused an overflow") + sysFatal(FloatOverflowDefect, "FPU operation caused an overflow") else: - sysFatal(FloatUnderflowError, "FPU operations caused an underflow") + sysFatal(FloatUnderflowDefect, "FPU operations caused an underflow") proc infCheck(x: float64) {.compilerproc, inline.} = if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x) diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index 710566a6d..8d176985d 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -2,7 +2,7 @@ proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} ## Returns the ``y``-th successor (default: 1) of the value ``x``. ## ``T`` has to be an `ordinal type <#Ordinal>`_. ## - ## If such a value does not exist, ``OverflowError`` is raised + ## If such a value does not exist, ``OverflowDefect`` is raised ## or a compile time error occurs. ## ## .. code-block:: Nim @@ -14,7 +14,7 @@ proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} ## Returns the ``y``-th predecessor (default: 1) of the value ``x``. ## ``T`` has to be an `ordinal type <#Ordinal>`_. ## - ## If such a value does not exist, ``OverflowError`` is raised + ## If such a value does not exist, ``OverflowDefect`` is raised ## or a compile time error occurs. ## ## .. code-block:: Nim @@ -25,7 +25,7 @@ proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} proc inc*[T: Ordinal](x: var T, y = 1) {.magic: "Inc", noSideEffect.} ## Increments the ordinal ``x`` by ``y``. ## - ## If such a value does not exist, ``OverflowError`` is raised or a compile + ## If such a value does not exist, ``OverflowDefect`` is raised or a compile ## time error occurs. This is a short notation for: ``x = succ(x, y)``. ## ## .. code-block:: Nim @@ -36,7 +36,7 @@ proc inc*[T: Ordinal](x: var T, y = 1) {.magic: "Inc", noSideEffect.} proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} ## Decrements the ordinal ``x`` by ``y``. ## - ## If such a value does not exist, ``OverflowError`` is raised or a compile + ## If such a value does not exist, ``OverflowDefect`` is raised or a compile ## time error occurs. This is a short notation for: ``x = pred(x, y)``. ## ## .. code-block:: Nim diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 64ed44ea7..9a1bdc7bc 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -19,10 +19,10 @@ when not defined(nimHasSinkInference): {.pragma: nosinks.} proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = - sysFatal(AssertionError, msg) + sysFatal(AssertionDefect, msg) proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = - # trick the compiler to not list ``AssertionError`` when called + # trick the compiler to not list ``AssertionDefect`` when called # by ``assert``. type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} @@ -40,9 +40,9 @@ template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool] failedAssertImpl(ploc & " `" & expr & "` " & msg) template assert*(cond: untyped, msg = "") = - ## Raises ``AssertionError`` with `msg` if `cond` is false. Note - ## that ``AssertionError`` is hidden from the effect system, so it doesn't - ## produce ``{.raises: [AssertionError].}``. This exception is only supposed + ## Raises ``AssertionDefect`` with `msg` if `cond` is false. Note + ## that ``AssertionDefect`` is hidden from the effect system, so it doesn't + ## produce ``{.raises: [AssertionDefect].}``. This exception is only supposed ## to be caught by unit testing frameworks. ## ## The compiler may not generate any code at all for ``assert`` if it is @@ -80,7 +80,7 @@ template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = code template doAssertRaises*(exception: typedesc, code: untyped) = - ## Raises ``AssertionError`` if specified ``code`` does not raise the + ## Raises ``AssertionDefect`` if specified ``code`` does not raise the ## specified exception. Example: ## ## .. code-block:: nim diff --git a/lib/system/assign.nim b/lib/system/assign.nim index eed7bc6db..ff4ac021e 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -233,10 +233,10 @@ proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int, let newBranch = selectBranch(newDiscVal, L, a) when defined(nimOldCaseObjects): if newBranch != oldBranch and oldDiscVal != 0: - sysFatal(FieldError, "assignment to discriminant changes object branch") + sysFatal(FieldDefect, "assignment to discriminant changes object branch") else: if newBranch != oldBranch: if oldDiscVal != 0: - sysFatal(FieldError, "assignment to discriminant changes object branch") + sysFatal(FieldDefect, "assignment to discriminant changes object branch") else: - sysFatal(FieldError, "assignment to discriminant changes object branch; compile with -d:nimOldCaseObjects for a transition period") + sysFatal(FieldDefect, "assignment to discriminant changes object branch; compile with -d:nimOldCaseObjects for a transition period") diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 5966d9fee..834694626 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -347,7 +347,7 @@ template lockChannel(q, action): untyped = proc sendImpl(q: PRawChannel, typ: PNimType, msg: pointer, noBlock: bool): bool = if q.mask == ChannelDeadMask: - sysFatal(DeadThreadError, "cannot send message; thread died") + sysFatal(DeadThreadDefect, "cannot send message; thread died") acquireSys(q.lock) if q.maxItems > 0: # Wait until count is less than maxItems diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 117543fcd..0b6a75b1f 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -12,34 +12,34 @@ include system/indexerrors proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": - sysFatal(RangeError, "value out of range") + sysFatal(RangeDefect, "value out of range") else: - sysFatal(RangeError, "value out of range: ", $val) + sysFatal(RangeDefect, "value out of range: ", $val) proc raiseIndexError3(i, a, b: int) {.compilerproc, noinline.} = - sysFatal(IndexError, formatErrorIndexBound(i, a, b)) + sysFatal(IndexDefect, formatErrorIndexBound(i, a, b)) proc raiseIndexError2(i, n: int) {.compilerproc, noinline.} = - sysFatal(IndexError, formatErrorIndexBound(i, n)) + sysFatal(IndexDefect, formatErrorIndexBound(i, n)) proc raiseIndexError() {.compilerproc, noinline.} = - sysFatal(IndexError, "index out of bounds") + sysFatal(IndexDefect, "index out of bounds") proc raiseFieldError(f: string) {.compilerproc, noinline.} = - sysFatal(FieldError, f) + sysFatal(FieldDefect, f) proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} = - sysFatal(RangeError, "value out of range: " & $i & " notin " & $a & " .. " & $b) + sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} = - sysFatal(RangeError, "value out of range: " & $i & " notin " & $a & " .. " & $b) + sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} = # todo: better error reporting - sysFatal(RangeError, "value out of range") + sysFatal(RangeDefect, "value out of range") proc raiseObjectConversionError() {.compilerproc, noinline.} = - sysFatal(ObjectConversionError, "invalid object conversion") + sysFatal(ObjectConversionDefect, "invalid object conversion") proc chckIndx(i, a, b: int): int = if i >= a and i <= b: @@ -63,24 +63,24 @@ proc chckRangeU(i, a, b: uint64): uint64 {.compilerproc.} = if i >= a and i <= b: return i else: - sysFatal(RangeError, "value out of range") + sysFatal(RangeDefect, "value out of range") proc chckRangeF(x, a, b: float): float = if x >= a and x <= b: return x else: when hostOS == "standalone": - sysFatal(RangeError, "value out of range") + sysFatal(RangeDefect, "value out of range") else: - sysFatal(RangeError, "value out of range: ", $x) + sysFatal(RangeDefect, "value out of range: ", $x) proc chckNil(p: pointer) = if p == nil: - sysFatal(NilAccessError, "attempt to write to a nil address") + sysFatal(NilAccessDefect, "attempt to write to a nil address") proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: - sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") + sysFatal(NilAccessDefect, "cannot dispatch; dispatcher is nil") when not defined(nimV2): @@ -90,12 +90,12 @@ when not defined(nimV2): if x == subclass: return # optimized fast path while x != subclass: if x == nil: - sysFatal(ObjectConversionError, "invalid object conversion") + sysFatal(ObjectConversionDefect, "invalid object conversion") x = x.base proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = if a != b: - sysFatal(ObjectAssignmentError, "invalid object assignment") + sysFatal(ObjectAssignmentDefect, "invalid object assignment") type ObjCheckCache = array[0..1, PNimType] @@ -130,4 +130,4 @@ when not defined(nimV2): when defined(nimV2): proc raiseObjectCaseTransition() {.compilerproc.} = - sysFatal(FieldError, "assignment to discriminant changes object branch") + sysFatal(FieldDefect, "assignment to discriminant changes object branch") diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index d1e05dad5..c4f15a336 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -32,10 +32,10 @@ const proc quitOrDebug() {.noreturn, importc: "abort", header: "", nodecl.} proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = - sysFatal(ReraiseError, "exception handling is not available") + sysFatal(ReraiseDefect, "exception handling is not available") proc reraiseException() {.compilerRtl.} = - sysFatal(ReraiseError, "no exception to reraise") + sysFatal(ReraiseDefect, "no exception to reraise") proc writeStackTrace() = discard @@ -43,4 +43,4 @@ proc unsetControlCHook() = discard proc setControlCHook(hook: proc () {.noconv.}) = discard proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = - sysFatal(ReraiseError, "exception handling is not available") + sysFatal(ReraiseDefect, "exception handling is not available") diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index 516de8252..ab092647c 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -62,19 +62,19 @@ type ## Raised if a dynamic library could not be loaded. ResourceExhaustedError* = object of CatchableError ## \ ## Raised if a resource request could not be fulfilled. - ArithmeticError* = object of Defect ## \ + ArithmeticDefect* = object of Defect ## \ ## Raised if any kind of arithmetic error occurred. - DivByZeroError* = object of ArithmeticError ## \ + DivByZeroDefect* = object of ArithmeticDefect ## \ ## Raised for runtime integer divide-by-zero errors. - OverflowError* = object of ArithmeticError ## \ + OverflowDefect* = object of ArithmeticDefect ## \ ## Raised for runtime integer overflows. ## ## This happens for calculations whose results are too large to fit in the ## provided bits. - AccessViolationError* = object of Defect ## \ + AccessViolationDefect* = object of Defect ## \ ## Raised for invalid memory access errors - AssertionError* = object of Defect ## \ + AssertionDefect* = object of Defect ## \ ## Raised when assertion is proved wrong. ## ## Usually the result of using the `assert() template @@ -87,54 +87,77 @@ type ## Mostly used by the `tables `_ module, it can also be raised ## by other collection modules like `sets `_ or `strtabs ## `_. - OutOfMemError* = object of Defect ## \ + OutOfMemDefect* = object of Defect ## \ ## Raised for unsuccessful attempts to allocate memory. - IndexError* = object of Defect ## \ + IndexDefect* = object of Defect ## \ ## Raised if an array index is out of bounds. - FieldError* = object of Defect ## \ + FieldDefect* = object of Defect ## \ ## Raised if a record field is not accessible because its discriminant's ## value does not fit. - RangeError* = object of Defect ## \ + RangeDefect* = object of Defect ## \ ## Raised if a range check error occurred. - StackOverflowError* = object of Defect ## \ + StackOverflowDefect* = object of Defect ## \ ## Raised if the hardware stack used for subroutine calls overflowed. - ReraiseError* = object of Defect ## \ + ReraiseDefect* = object of Defect ## \ ## Raised if there is no exception to reraise. - ObjectAssignmentError* = object of Defect ## \ + ObjectAssignmentDefect* = object of Defect ## \ ## Raised if an object gets assigned to its parent's object. - ObjectConversionError* = object of Defect ## \ + ObjectConversionDefect* = object of Defect ## \ ## Raised if an object is converted to an incompatible object type. ## You can use ``of`` operator to check if conversion will succeed. - FloatingPointError* = object of Defect ## \ + FloatingPointDefect* = object of Defect ## \ ## Base class for floating point exceptions. - FloatInvalidOpError* = object of FloatingPointError ## \ + FloatInvalidOpDefect* = object of FloatingPointDefect ## \ ## Raised by invalid operations according to IEEE. ## ## Raised by ``0.0/0.0``, for example. - FloatDivByZeroError* = object of FloatingPointError ## \ + FloatDivByZeroDefect* = object of FloatingPointDefect ## \ ## Raised by division by zero. ## ## Divisor is zero and dividend is a finite nonzero number. - FloatOverflowError* = object of FloatingPointError ## \ + FloatOverflowDefect* = object of FloatingPointDefect ## \ ## Raised for overflows. ## ## The operation produced a result that exceeds the range of the exponent. - FloatUnderflowError* = object of FloatingPointError ## \ + FloatUnderflowDefect* = object of FloatingPointDefect ## \ ## Raised for underflows. ## ## The operation produced a result that is too small to be represented as a ## normal number. - FloatInexactError* = object of FloatingPointError ## \ + FloatInexactDefect* = object of FloatingPointDefect ## \ ## Raised for inexact results. ## ## The operation produced a result that cannot be represented with infinite ## precision -- for example: ``2.0 / 3.0, log(1.1)`` ## ## **Note**: Nim currently does not detect these! - DeadThreadError* = object of Defect ## \ + DeadThreadDefect* = object of Defect ## \ ## Raised if it is attempted to send a message to a dead thread. - NilAccessError* = object of Defect ## \ + NilAccessDefect* = object of Defect ## \ ## Raised on dereferences of ``nil`` pointers. ## ## This is only raised if the `segfaults module `_ was imported! + + ArithmeticError* {.deprecated: "See corresponding Defect".} = ArithmeticDefect + DivByZeroError* {.deprecated: "See corresponding Defect".} = ArithmeticDefect + OverflowError* {.deprecated: "See corresponding Defect".} = OverflowDefect + AccessViolationError* {.deprecated: "See corresponding Defect".} = AccessViolationDefect + AssertionError* {.deprecated: "See corresponding Defect".} = AssertionDefect + OutOfMemError* {.deprecated: "See corresponding Defect".} = OutOfMemDefect + IndexError* {.deprecated: "See corresponding Defect".} = IndexDefect + + FieldError* {.deprecated: "See corresponding Defect".} = FieldDefect + RangeError* {.deprecated: "See corresponding Defect".} = RangeDefect + StackOverflowError* {.deprecated: "See corresponding Defect".} = StackOverflowDefect + ReraiseError* {.deprecated: "See corresponding Defect".} = ReraiseDefect + ObjectAssignmentError* {.deprecated: "See corresponding Defect".} = ObjectAssignmentDefect + ObjectConversionError* {.deprecated: "See corresponding Defect".} = ObjectConversionDefect + FloatingPointError* {.deprecated: "See corresponding Defect".} = FloatingPointDefect + FloatInvalidOpError* {.deprecated: "See corresponding Defect".} = FloatInvalidOpDefect + FloatDivByZeroError* {.deprecated: "See corresponding Defect".} = FloatDivByZeroDefect + FloatOverflowError* {.deprecated: "See corresponding Defect".} = FloatOverflowDefect + FloatUnderflowError* {.deprecated: "See corresponding Defect".} = FloatUnderflowDefect + FloatInexactError* {.deprecated: "See corresponding Defect".} = FloatInexactDefect + DeadThreadError* {.deprecated: "See corresponding Defect".} = DeadThreadDefect + NilAccessError* {.deprecated: "See corresponding Defect".} = NilAccessDefect diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index aa3667226..f85c10598 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -483,7 +483,7 @@ proc raiseException(e: sink(ref Exception), ename: cstring) {.compilerRtl.} = proc reraiseException() {.compilerRtl.} = if currException == nil: - sysFatal(ReraiseError, "no exception to reraise") + sysFatal(ReraiseDefect, "no exception to reraise") else: when gotoBasedExceptions: inc nimInErrorMode diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 690230767..2be16ef90 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -844,7 +844,7 @@ when not defined(useNimRtl): inc(gch.recGcLock) proc GC_enable() = if gch.recGcLock <= 0: - raise newException(AssertionError, + raise newException(AssertionDefect, "API usage error: GC_enable called but GC is already enabled") dec(gch.recGcLock) diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index a3b163a67..eda220901 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -496,7 +496,7 @@ when not defined(useNimRtl): inc(gch.recGcLock) proc GC_enable() = if gch.recGcLock <= 0: - raise newException(AssertionError, + raise newException(AssertionDefect, "API usage error: GC_enable called but GC is already enabled") dec(gch.recGcLock) diff --git a/lib/system/integerops.nim b/lib/system/integerops.nim index d0bea5f09..ff744edde 100644 --- a/lib/system/integerops.nim +++ b/lib/system/integerops.nim @@ -12,10 +12,10 @@ proc raiseOverflow {.compilerproc, noinline.} = # a single proc to reduce code size to a minimum - sysFatal(OverflowError, "over- or underflow") + sysFatal(OverflowDefect, "over- or underflow") proc raiseDivByZero {.compilerproc, noinline.} = - sysFatal(DivByZeroError, "division by zero") + sysFatal(DivByZeroDefect, "division by zero") {.pragma: nimbaseH, importc, nodecl, noSideEffect, compilerproc.} @@ -123,10 +123,10 @@ divImplFallback(nimDivInt, int) divImplFallback(nimDivInt64, int64) proc raiseFloatInvalidOp {.compilerproc, noinline.} = - sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") + sysFatal(FloatInvalidOpDefect, "FPU operation caused a NaN result") proc raiseFloatOverflow(x: float64) {.compilerproc, noinline.} = if x > 0.0: - sysFatal(FloatOverflowError, "FPU operation caused an overflow") + sysFatal(FloatOverflowDefect, "FPU operation caused an overflow") else: - sysFatal(FloatUnderflowError, "FPU operations caused an underflow") + sysFatal(FloatUnderflowDefect, "FPU operations caused an underflow") diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index b16f2cbbc..98a7a2032 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -142,7 +142,7 @@ proc raiseException(e: ref Exception, ename: cstring) {. proc reraiseException() {.compilerproc, asmNoStackFrame.} = if lastJSError == nil: - raise newException(ReraiseError, "no exception to reraise") + raise newException(ReraiseDefect, "no exception to reraise") else: if excHandler == 0: if isNimException(): @@ -151,19 +151,19 @@ proc reraiseException() {.compilerproc, asmNoStackFrame.} = asm "throw lastJSError;" proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerproc.} = - raise newException(OverflowError, "over- or underflow") + raise newException(OverflowDefect, "over- or underflow") proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerproc.} = - raise newException(DivByZeroError, "division by zero") + raise newException(DivByZeroDefect, "division by zero") proc raiseRangeError() {.compilerproc, noreturn.} = - raise newException(RangeError, "value out of range") + raise newException(RangeDefect, "value out of range") proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} = - raise newException(IndexError, formatErrorIndexBound(int(i), int(a), int(b))) + raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b))) proc raiseFieldError(f: string) {.compilerproc, noreturn.} = - raise newException(FieldError, f) + raise newException(FieldDefect, f) proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = asm """ @@ -524,7 +524,7 @@ proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: - sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") + sysFatal(NilAccessDefect, "cannot dispatch; dispatcher is nil") include "system/hti" @@ -663,7 +663,7 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} = if x == subclass: return # optimized fast path while x != subclass: if x == nil: - raise newException(ObjectConversionError, "invalid object conversion") + raise newException(ObjectConversionDefect, "invalid object conversion") x = x.base proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = diff --git a/lib/system/refs_v2.nim b/lib/system/refs_v2.nim index b47b4ec46..8e5e03d3d 100644 --- a/lib/system/refs_v2.nim +++ b/lib/system/refs_v2.nim @@ -191,4 +191,4 @@ proc isObj(obj: PNimType, subclass: cstring): bool {.compilerRtl, inl.} = proc chckObj(obj: PNimType, subclass: cstring) {.compilerRtl.} = # checks if obj is of type subclass: - if not isObj(obj, subclass): sysFatal(ObjectConversionError, "invalid object conversion") + if not isObj(obj, subclass): sysFatal(ObjectConversionDefect, "invalid object conversion") diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index 91ab530e4..d61820f7a 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''ObjectAssignmentError''' + outputsub: '''ObjectAssignmentDefect''' exitcode: "1" """ diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim index 3c2355707..e120cf019 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''ObjectAssignmentError''' + outputsub: '''ObjectAssignmentDefect''' exitcode: "1" """ diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim index 71f3960ef..99ea19fa2 100644 --- a/tests/arc/tcaseobj.nim +++ b/tests/arc/tcaseobj.nim @@ -154,16 +154,16 @@ type x1: string case kind1: bool of false: y1: string - of true: + of true: y2: seq[string] case kind2: bool of true: z1: string - of false: + of false: z2: seq[string] flag: bool x2: string - -proc test_myobject = + +proc test_myobject = var x: MyObject x.x1 = "x1" x.x2 = "x2" @@ -183,7 +183,7 @@ proc test_myobject = try: x.kind1 = x.flag # flag is not accesible - except FieldError: + except FieldDefect: echo "prevented" doAssert(x.x1 == "x1") diff --git a/tests/assert/tassert.nim b/tests/assert/tassert.nim index 99929f080..a14fec317 100644 --- a/tests/assert/tassert.nim +++ b/tests/assert/tassert.nim @@ -10,7 +10,7 @@ proc callC() = callA() try: callC() -except AssertionError: +except AssertionDefect: write(stdout, "assertion failure!") except: write(stdout, "unknown exception!") diff --git a/tests/assert/tassert2.nim b/tests/assert/tassert2.nim index 3cff47a24..5d849aaad 100644 --- a/tests/assert/tassert2.nim +++ b/tests/assert/tassert2.nim @@ -18,12 +18,12 @@ type try: doAssert(false, "msg1") # doAssert test -except AssertionError as e: +except AssertionDefect as e: assert e.msg.endsWith "tassert2.nim(20, 11) `false` msg1" try: assert false # assert test with no msg -except AssertionError as e: +except AssertionDefect as e: assert e.msg.endsWith "tassert2.nim(25, 10) `false` " try: @@ -31,13 +31,13 @@ try: doAssert(a+a==1) # assert test with Ast expression # BUG: const folding would make "1+1==1" appear as `false` in # assert message -except AssertionError as e: +except AssertionDefect as e: assert e.msg.endsWith "`a + a == 1` " try: let a = 1 doAssert a+a==1 # ditto with `doAssert` and no parens -except AssertionError as e: +except AssertionDefect as e: assert e.msg.endsWith "`a + a == 1` " proc fooStatic() = @@ -91,14 +91,14 @@ block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518 try: doAssert fun("foo1") == fun("foo2"), "mymsg" - except AssertionError as e: + except AssertionDefect as e: # used to expand out the template instantiaiton, sometimes filling hundreds of lines assert e.msg.endsWith "" block: ## checks for issue https://github.com/nim-lang/Nim/issues/9301 try: doAssert 1 + 1 == 3 - except AssertionError as e: + except AssertionDefect as e: # used to const fold as false assert e.msg.endsWith "tassert2.nim(100, 14) `1 + 1 == 3` " @@ -106,6 +106,6 @@ block: ## checks AST isn't transformed as it used to let a = 1 try: doAssert a > 1 - except AssertionError as e: + except AssertionDefect as e: # used to rewrite as `1 < a` assert e.msg.endsWith "tassert2.nim(108, 14) `a > 1` " diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index 4357e0584..cbb565f84 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -33,7 +33,7 @@ try: proc foo() = assert(false) foo() -except AssertionError: +except AssertionDefect: let e = getCurrentException() let trace = e.getStackTrace if tmatch(trace, expected): echo true else: echo "wrong trace:\n" & trace diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim index a7cb5223d..fa3493616 100644 --- a/tests/async/tasynctry.nim +++ b/tests/async/tasynctry.nim @@ -14,7 +14,7 @@ import asyncdispatch, strutils proc foobar() {.async.} = if 5 == 5: - raise newException(IndexError, "Test") + raise newException(IndexDefect, "Test") proc catch() {.async.} = # TODO: Create a test for when exceptions are not caught. @@ -25,26 +25,26 @@ proc catch() {.async.} = try: await foobar() - except IndexError: + except IndexDefect: echo("Specific except") try: await foobar() - except OSError, FieldError, IndexError: + except OSError, FieldDefect, IndexDefect: echo("Multiple idents in except") try: await foobar() - except OSError, FieldError: + except OSError, FieldDefect: assert false - except IndexError: + except IndexDefect: echo("Multiple except branches") try: await foobar() - except IndexError: + except IndexDefect: echo("Multiple except branches 2") - except OSError, FieldError: + except OSError, FieldDefect: assert false waitFor catch() diff --git a/tests/async/tupcoming_async.nim b/tests/async/tupcoming_async.nim index da98fc4d8..0b6e53454 100644 --- a/tests/async/tupcoming_async.nim +++ b/tests/async/tupcoming_async.nim @@ -45,7 +45,7 @@ when defined(upcoming): poll() proc eventTest5298() = - # Event must raise `AssertionError` if event was unregistered twice. + # Event must raise `AssertionDefect` if event was unregistered twice. # Issue #5298. let e = newAsyncEvent() var eventReceived = false @@ -57,7 +57,7 @@ when defined(upcoming): poll() try: e.unregister() - except AssertionError: + except AssertionDefect: discard e.close() diff --git a/tests/compiler/tunittest_light.nim b/tests/compiler/tunittest_light.nim index 422474002..5cad6997f 100644 --- a/tests/compiler/tunittest_light.nim +++ b/tests/compiler/tunittest_light.nim @@ -2,7 +2,7 @@ import compiler/unittest_light proc testAssertEquals() = assertEquals("foo", "foo") - doAssertRaises(AssertionError): + doAssertRaises(AssertionDefect): assertEquals("foo", "foo ") proc testMismatch() = diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim index 6b959eff2..cc99737df 100644 --- a/tests/concepts/tmapconcept.nim +++ b/tests/concepts/tmapconcept.nim @@ -78,7 +78,7 @@ proc getFirstValue[K,V](m : Map[K,V]): V = for i in m.valuesSeq: return i - raise newException(RangeError, "no values") + raise newException(RangeDefect, "no values") proc useConceptProcInGeneric[K, V](t: Table[K, V]): V = return t.getFirstValue diff --git a/tests/destructor/tgotoexceptions5.nim b/tests/destructor/tgotoexceptions5.nim index 41e62aba0..0e538d89e 100644 --- a/tests/destructor/tgotoexceptions5.nim +++ b/tests/destructor/tgotoexceptions5.nim @@ -13,7 +13,7 @@ proc main() = try: echo "before" raise newException(CatchableError, "foo") - except AssertionError: + except AssertionDefect: echo "caught" echo "after" @@ -27,7 +27,7 @@ proc mainB() = echo "before" raise newException(CatchableError, "foo") # except CatchableError: # would work - except AssertionError: + except AssertionDefect: echo "caught" except: raise diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim index 0f88caaa4..6e564a044 100644 --- a/tests/destructor/tgotoexceptions7.nim +++ b/tests/destructor/tgotoexceptions7.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim c --gc:arc --exceptions:goto --panics:off $file" output: '''prevented! caught -AssertionError +AssertionDefect 900''' """ @@ -30,18 +30,18 @@ proc main(i: int) = try: var objA = ObjA() bplease(ObjB(objA)) - except ObjectConversionError: + except ObjectConversionDefect: echo "prevented!" try: takeRange(i) - except RangeError: + except RangeDefect: echo "caught" try: helper() - except AssertionError: - echo "AssertionError" + except AssertionDefect: + echo "AssertionDefect" echo i * i diff --git a/tests/destructor/tsetjmp_raise.nim b/tests/destructor/tsetjmp_raise.nim index b6078ada2..3a9803f39 100644 --- a/tests/destructor/tsetjmp_raise.nim +++ b/tests/destructor/tsetjmp_raise.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "index 2 not in 0 .. 0 [IndexError]" + outputsub: "index 2 not in 0 .. 0 [IndexDefect]" exitcode: 1 cmd: "nim c --gc:arc --exceptions:setjmp $file" """ diff --git a/tests/effects/teffects7.nim b/tests/effects/teffects7.nim index 1cd144459..aee5e027d 100644 --- a/tests/effects/teffects7.nim +++ b/tests/effects/teffects7.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "can raise an unlisted exception: ref FloatingPointError" + errormsg: "can raise an unlisted exception: ref FloatingPointDefect" line: 10 """ @@ -7,7 +7,7 @@ proc foo() {.raises: [].} = try: discard except KeyError: - raise newException(FloatingPointError, "foo") + raise newException(FloatingPointDefect, "foo") except Exception: discard diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim index 7bce32837..5d4d0fa9e 100644 --- a/tests/exception/texceptions.nim +++ b/tests/exception/texceptions.nim @@ -89,10 +89,10 @@ block: result.add(1212) try: try: - raise newException(AssertionError, "a") + raise newException(AssertionDefect, "a") finally: result.add(42) - except AssertionError: + except AssertionDefect: result.add(99) finally: result.add(10) @@ -104,7 +104,7 @@ block: result.add(-1) except ValueError: result.add(-1) - except IndexError: + except IndexDefect: result.add(2) except: result.add(3) diff --git a/tests/exception/twrongexc.nim b/tests/exception/twrongexc.nim index 9c656f3d9..d229c5749 100644 --- a/tests/exception/twrongexc.nim +++ b/tests/exception/twrongexc.nim @@ -4,5 +4,5 @@ discard """ """ try: raise newException(ValueError, "") -except OverflowError: +except OverflowDefect: echo("Error caught") diff --git a/tests/float/tfloat1.nim b/tests/float/tfloat1.nim index 54d49a7c1..d3497f24c 100644 --- a/tests/float/tfloat1.nim +++ b/tests/float/tfloat1.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowError]" + outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowDefect]" exitcode: "1" """ # Test new floating point exceptions diff --git a/tests/float/tfloat2.nim b/tests/float/tfloat2.nim index 130c71087..1de63dde3 100644 --- a/tests/float/tfloat2.nim +++ b/tests/float/tfloat2.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpError]" + outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpDefect]" exitcode: "1" """ # Test new floating point exceptions diff --git a/tests/js/temptyseq.nim b/tests/js/temptyseq.nim index df4b3e8da..6489cf817 100644 --- a/tests/js/temptyseq.nim +++ b/tests/js/temptyseq.nim @@ -2,7 +2,7 @@ proc foo = var x: seq[int] - doAssertRaises(IndexError): + doAssertRaises(IndexDefect): inc x[0] foo() diff --git a/tests/js/tfieldchecks.nim b/tests/js/tfieldchecks.nim index 77759a75a..3916cae74 100644 --- a/tests/js/tfieldchecks.nim +++ b/tests/js/tfieldchecks.nim @@ -24,7 +24,7 @@ var obj = X(f0: "foo", f1: C, f3: 3.14) block: echo obj.f0 echo obj.f1 - doAssertRaises(FieldError): echo obj.f2 + doAssertRaises(FieldDefect): echo obj.f2 echo obj.f3 block: @@ -32,7 +32,7 @@ block: echo a0[] # let a1 = unsafeAddr(obj.f1) # echo a1[] - doAssertRaises(FieldError): + doAssertRaises(FieldDefect): let a2 = addr(obj.f2) echo a2[] let a3 = addr(obj.f3) diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 9cea59477..9448fa7e5 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -251,8 +251,8 @@ proc parse_parameter(quit_on_failure: bool, param, value: string, case param_kind: of PK_INT: try: result.int_val = value.parseInt - except OverflowError: - raise_or_quit(OverflowError, ("parameter $1 requires an " & + except OverflowDefect: + raise_or_quit(OverflowDefect, ("parameter $1 requires an " & "integer, but $2 is too large to fit into one") % [param, escape(value)]) except ValueError: diff --git a/tests/metatype/tunresolved_return_type.nim b/tests/metatype/tunresolved_return_type.nim index f67e065ea..637a9b733 100644 --- a/tests/metatype/tunresolved_return_type.nim +++ b/tests/metatype/tunresolved_return_type.nim @@ -11,7 +11,7 @@ type proc toNumber[T: int|uint|int64|uint64](v: ResultValue): T = if v < low(T) or v > high(T): - raise newException(RangeError, "protocol error") + raise newException(RangeDefect, "protocol error") return T(v) #proc toNumber[T](v: int32): T = diff --git a/tests/method/tnildispatcher.nim b/tests/method/tnildispatcher.nim index 017e8155f..219d2b29f 100644 --- a/tests/method/tnildispatcher.nim +++ b/tests/method/tnildispatcher.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''Error: unhandled exception: cannot dispatch; dispatcher is nil [NilAccessError]''' + outputsub: '''Error: unhandled exception: cannot dispatch; dispatcher is nil [NilAccessDefect]''' exitcode: 1 """ # bug #5599 diff --git a/tests/misc/trangechecks.nim b/tests/misc/trangechecks.nim index 2c6f0f66d..ac09e558c 100644 --- a/tests/misc/trangechecks.nim +++ b/tests/misc/trangechecks.nim @@ -14,14 +14,14 @@ var x: range[1..10] = 10 try: x += 1 echo x -except OverflowError, RangeError: +except OverflowDefect, RangeDefect: expected += 1 echo x try: inc x echo x -except OverflowError, RangeError: +except OverflowDefect, RangeDefect: expected += 1 echo x @@ -29,14 +29,14 @@ x = 1 try: x -= 1 echo x -except OverflowError, RangeError: +except OverflowDefect, RangeDefect: expected += 1 echo x try: dec x echo x -except OverflowError, RangeError: +except OverflowDefect, RangeDefect: expected += 1 echo x diff --git a/tests/misc/tsemfold.nim b/tests/misc/tsemfold.nim index 486ddc5a6..2ce8d9560 100644 --- a/tests/misc/tsemfold.nim +++ b/tests/misc/tsemfold.nim @@ -2,25 +2,25 @@ discard """ action: run """ -doAssertRaises(OverflowError): discard low(int8) - 1'i8 -doAssertRaises(OverflowError): discard high(int8) + 1'i8 -doAssertRaises(OverflowError): discard abs(low(int8)) -doAssertRaises(DivByZeroError): discard 1 mod 0 -doAssertRaises(DivByZeroError): discard 1 div 0 -doAssertRaises(OverflowError): discard low(int8) div -1'i8 +doAssertRaises(OverflowDefect): discard low(int8) - 1'i8 +doAssertRaises(OverflowDefect): discard high(int8) + 1'i8 +doAssertRaises(OverflowDefect): discard abs(low(int8)) +doAssertRaises(DivByZeroDefect): discard 1 mod 0 +doAssertRaises(DivByZeroDefect): discard 1 div 0 +doAssertRaises(OverflowDefect): discard low(int8) div -1'i8 -doAssertRaises(OverflowError): discard -low(int64) -doAssertRaises(OverflowError): discard low(int64) - 1'i64 -doAssertRaises(OverflowError): discard high(int64) + 1'i64 +doAssertRaises(OverflowDefect): discard -low(int64) +doAssertRaises(OverflowDefect): discard low(int64) - 1'i64 +doAssertRaises(OverflowDefect): discard high(int64) + 1'i64 type E = enum eA, eB -doAssertRaises(OverflowError): discard eA.pred -doAssertRaises(OverflowError): discard eB.succ +doAssertRaises(OverflowDefect): discard eA.pred +doAssertRaises(OverflowDefect): discard eB.succ -doAssertRaises(OverflowError): discard low(int8) * -1 -doAssertRaises(OverflowError): discard low(int64) * -1 -doAssertRaises(OverflowError): discard high(int8) * 2 -doAssertRaises(OverflowError): discard high(int64) * 2 +doAssertRaises(OverflowDefect): discard low(int8) * -1 +doAssertRaises(OverflowDefect): discard low(int64) * -1 +doAssertRaises(OverflowDefect): discard high(int8) * 2 +doAssertRaises(OverflowDefect): discard high(int64) * 2 doAssert abs(-1) == 1 doAssert 2 div 2 == 1 diff --git a/tests/misc/tunsignedinc.nim b/tests/misc/tunsignedinc.nim index 6d1b627d6..9d1a4bbb4 100644 --- a/tests/misc/tunsignedinc.nim +++ b/tests/misc/tunsignedinc.nim @@ -1,8 +1,8 @@ block: # bug #2427 var x = 0'u8 - dec x # OverflowError - x -= 1 # OverflowError + dec x # OverflowDefect + x -= 1 # OverflowDefect x = x - 1 # No error doAssert(x == 253'u8) diff --git a/tests/niminaction/Chapter2/various2.nim b/tests/niminaction/Chapter2/various2.nim index dddbdb472..488c361a2 100644 --- a/tests/niminaction/Chapter2/various2.nim +++ b/tests/niminaction/Chapter2/various2.nim @@ -179,13 +179,13 @@ for i in list4.low .. list4.high: echo(list4[i]) var list5: seq[int] = @[] -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): list5[0] = 1 list5.add(1) assert list5[0] == 1 -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): echo list5[42] # -- Errata: var list: seq[int]; echo(list[0]). This now creates an exception, diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim index 711740da8..849ea71d8 100644 --- a/tests/niminaction/Chapter3/various3.nim +++ b/tests/niminaction/Chapter3/various3.nim @@ -22,7 +22,7 @@ block: assert obj.contents == "Hello" var obj2 = Box(empty: true) - doAssertRaises(FieldError): + doAssertRaises(FieldDefect): echo(obj2.contents) import json diff --git a/tests/objects/tobj_asgn_dont_slice.nim b/tests/objects/tobj_asgn_dont_slice.nim index 866b5aecc..2e36b65a3 100644 --- a/tests/objects/tobj_asgn_dont_slice.nim +++ b/tests/objects/tobj_asgn_dont_slice.nim @@ -1,5 +1,5 @@ discard """ - outputsub: '''ObjectAssignmentError''' + outputsub: '''ObjectAssignmentDefect''' exitcode: "1" """ diff --git a/tests/overflw/toverflw.nim b/tests/overflw/toverflw.nim index d96231900..164e16e5c 100644 --- a/tests/overflw/toverflw.nim +++ b/tests/overflw/toverflw.nim @@ -13,7 +13,7 @@ var try: writeLine(stdout, b - a) -except OverflowError: +except OverflowDefect: overflowDetected = true {.pop.} # overflow check @@ -33,7 +33,7 @@ block: # Overflow checks in a proc try: foo() - except OverflowError: + except OverflowDefect: overflowDetected = true doAssert(overflowDetected) @@ -53,7 +53,7 @@ block: # Overflow checks in a forward declared proc try: foo() - except OverflowError: + except OverflowDefect: overflowDetected = true doAssert(overflowDetected) @@ -73,7 +73,7 @@ block: # Overflow checks doesn't affect fwd declaration try: foo() - except OverflowError: + except OverflowDefect: overflowDetected = true doAssert(not overflowDetected) diff --git a/tests/overflw/toverflw2.nim b/tests/overflw/toverflw2.nim index 91b900ca4..c06b35c6d 100644 --- a/tests/overflw/toverflw2.nim +++ b/tests/overflw/toverflw2.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "Error: unhandled exception: over- or underflow [OverflowError]" + outputsub: "Error: unhandled exception: over- or underflow [OverflowDefect]" exitcode: "1" """ var a : int32 = 2147483647 diff --git a/tests/range/tsubrange2.nim b/tests/range/tsubrange2.nim index 1b90b52c7..fbd1ca760 100644 --- a/tests/range/tsubrange2.nim +++ b/tests/range/tsubrange2.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "value out of range: 50 notin 0 .. 40 [RangeError]" + outputsub: "value out of range: 50 notin 0 .. 40 [RangeDefect]" exitcode: "1" """ diff --git a/tests/range/tsubrange3.nim b/tests/range/tsubrange3.nim index ba9e6a143..55eb4618b 100644 --- a/tests/range/tsubrange3.nim +++ b/tests/range/tsubrange3.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "value out of range: 50 notin 0 .. 40 [RangeError]" + outputsub: "value out of range: 50 notin 0 .. 40 [RangeDefect]" exitcode: "1" """ diff --git a/tests/rational/trat_init.nim b/tests/rational/trat_init.nim index 360a48537..2be0c0099 100644 --- a/tests/rational/trat_init.nim +++ b/tests/rational/trat_init.nim @@ -10,5 +10,5 @@ var try: var r = initRational(1, 0) # this fails - no zero denominator -except AssertionError: +except AssertionDefect: echo "true" diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim index 812a7f384..6f3436410 100644 --- a/tests/stdlib/nre/replace.nim +++ b/tests/stdlib/nre/replace.nim @@ -16,7 +16,7 @@ suite "replace": check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") test "replacing missing captures should throw instead of segfaulting": - expect IndexError: discard "ab".replace(re"(a)|(b)", "$1$2") - expect IndexError: discard "b".replace(re"(a)?(b)", "$1$2") + expect IndexDefect: discard "ab".replace(re"(a)|(b)", "$1$2") + expect IndexDefect: discard "b".replace(re"(a)?(b)", "$1$2") expect KeyError: discard "b".replace(re"(a)?", "${foo}") expect KeyError: discard "b".replace(re"(?a)?", "${foo}") diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index d611ce4cc..1bd4da5c4 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -266,7 +266,7 @@ block: # not ready for vm because exception is compile error var i = 32 v.setBit(i) doAssert false - except RangeError: + except RangeDefect: discard except: doAssert false diff --git a/tests/stdlib/tstdlib_issues.nim b/tests/stdlib/tstdlib_issues.nim index b5a1c8206..323bf09c6 100644 --- a/tests/stdlib/tstdlib_issues.nim +++ b/tests/stdlib/tstdlib_issues.nim @@ -43,7 +43,7 @@ block tcount: # bubble sort for i in low(arr)..high(arr): - for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeError] + for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeDefect] if arr[i] > arr[j]: let tmp = arr[i] arr[i] = arr[j] diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim index 6856fcd79..42ed4fda2 100644 --- a/tests/stdlib/tstdlib_various.nim +++ b/tests/stdlib/tstdlib_various.nim @@ -169,7 +169,7 @@ block tsegfaults: raise newException(ValueError, "not a crash") except ValueError: discard - except NilAccessError: + except NilAccessDefect: echo "caught a crash!" for i in 0..5: main() @@ -212,7 +212,7 @@ block tsplit2: try: discard "hello".split("") echo "false" - except AssertionError: + except AssertionDefect: echo "true" diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 36a2e9800..0a7bf0511 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -52,7 +52,7 @@ proc test_string_slice() = doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz" # bug #6223 - doAssertRaises(IndexError): + doAssertRaises(IndexDefect): discard s[0..999] echo("OK") diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index eb0fdbfa5..6c82fc0ca 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -11,7 +11,7 @@ import macros template rejectParse(e) = try: discard e - raise newException(AssertionError, "This was supposed to fail: $#!" % astToStr(e)) + raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e)) except ValueError: discard proc testStrip() = diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index a8da15f3d..590018c6d 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -626,8 +626,8 @@ suite "ttimes": doAssert a.month.Month == cast[Month](0) doAssert a.monthday == 0 - doAssertRaises(AssertionError): discard getDayOfWeek(a.monthday, a.month, a.year) - doAssertRaises(AssertionError): discard a.toTime + doAssertRaises(AssertionDefect): discard getDayOfWeek(a.monthday, a.month, a.year) + doAssertRaises(AssertionDefect): discard a.toTime test "inX procs": doAssert initDuration(seconds = 1).inSeconds == 1 diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 65baefef0..b0efdb617 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -56,7 +56,7 @@ proc defectiveRobot() = of 3: raise newException(IOError, "I can't do that Dave.") else: assert 2 + 2 == 5 test "unittest expect": - expect IOError, OSError, ValueError, AssertionError: + expect IOError, OSError, ValueError, AssertionDefect: defectiveRobot() var diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index b20c67479..c56a65d11 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -68,8 +68,8 @@ proc main() = # shows that checkNotZero won't be called if a nil is found earlier in chain doAssert ?.a.x1.checkNotZero == 0.0 - # checks that a chain without nil but with an empty seq still throws IndexError - doAssertRaises(IndexError): discard ?.a2.x8[3] + # checks that a chain without nil but with an empty seq still throws IndexDefect + doAssertRaises(IndexDefect): discard ?.a2.x8[3] # make sure no double evaluation bug doAssert witness == 0 diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index fff8b7022..508715905 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -81,13 +81,13 @@ foo(toOpenArray(seqq, 1, 3)) # empty openArray issue #7904 foo(toOpenArray(seqq, 0, -1)) foo(toOpenArray(seqq, 1, 0)) -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): foo(toOpenArray(seqq, 0, -2)) foo(toOpenArray(arr, 9, 8)) foo(toOpenArray(arr, 0, -1)) foo(toOpenArray(arr, 1, 0)) -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): foo(toOpenArray(arr, 10, 8)) # test openArray of openArray @@ -106,11 +106,11 @@ var arrNeg: array[-3 .. -1, int] = [1, 2, 3] foo(toOpenArray(arrNeg, -3, -1)) foo(toOpenArray(arrNeg, 0, -1)) foo(toOpenArray(arrNeg, -3, -4)) -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): foo(toOpenArray(arrNeg, -4, -1)) -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): foo(toOpenArray(arrNeg, -1, 0)) -doAssertRaises(IndexError): +doAssertRaises(IndexDefect): foo(toOpenArray(arrNeg, -1, -3)) doAssertRaises(Exception): raise newException(Exception, "foo") @@ -118,9 +118,9 @@ doAssertRaises(Exception): block: var didThrow = false try: - doAssertRaises(IndexError): # should fail since it's wrong exception - raise newException(FieldError, "foo") - except AssertionError: + doAssertRaises(IndexDefect): # should fail since it's wrong exception + raise newException(FieldDefect, "foo") + except AssertionDefect: # ok, throwing was correct behavior didThrow = true doAssert didThrow diff --git a/tests/typerel/t4799_1.nim b/tests/typerel/t4799_1.nim index e66aa1a9a..74012190b 100644 --- a/tests/typerel/t4799_1.nim +++ b/tests/typerel/t4799_1.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp" - outputsub: '''ObjectAssignmentError''' + outputsub: '''ObjectAssignmentDefect''' exitcode: "1" """ diff --git a/tests/typerel/t4799_2.nim b/tests/typerel/t4799_2.nim index ff20c2426..f97b89622 100644 --- a/tests/typerel/t4799_2.nim +++ b/tests/typerel/t4799_2.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp" - outputsub: '''ObjectAssignmentError''' + outputsub: '''ObjectAssignmentDefect''' exitcode: "1" """ diff --git a/tests/typerel/t4799_3.nim b/tests/typerel/t4799_3.nim index 4a8a158dd..6102b69cc 100644 --- a/tests/typerel/t4799_3.nim +++ b/tests/typerel/t4799_3.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp" - outputsub: '''ObjectAssignmentError''' + outputsub: '''ObjectAssignmentDefect''' exitcode: "1" """ From 3b5a504692495324afdb7c20159122e66100f767 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 28 Apr 2020 18:56:50 +0100 Subject: [PATCH 0427/4254] parseEnum_regression (#14150) Co-authored-by: cooldome --- compiler/semtypes.nim | 2 ++ lib/core/macros.nim | 2 +- tests/stdlib/tstrutil.nim | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index ec53e14a4..e6cbe56e8 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -99,6 +99,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if not isOrdinalType(v[0].typ, allowEnumWithHoles=true): localError(c.config, v[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v[0].typ, preferDesc)) x = toInt64(getOrdValue(v[0])) # first tuple part is the ordinal + n[i][1][0] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt)) else: localError(c.config, strVal.info, errStringLiteralExpected) else: @@ -110,6 +111,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if not isOrdinalType(v.typ, allowEnumWithHoles=true): localError(c.config, v.info, errOrdinalTypeExpected & "; given: " & typeToString(v.typ, preferDesc)) x = toInt64(getOrdValue(v)) + n[i][1] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt)) if i != 1: if x != counter: incl(result.flags, tfEnumHasHoles) if x < counter: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index d94371d21..6e02ae42c 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -478,7 +478,7 @@ type proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {. magic: "NBindSym", noSideEffect.} - ## Ceates a node that binds `ident` to a symbol node. The bound symbol + ## Creates a node that binds `ident` to a symbol node. The bound symbol ## may be an overloaded symbol. ## if `ident` is a NimNode, it must have ``nnkIdent`` kind. ## If ``rule == brClosed`` either an ``nnkClosedSymChoice`` tree is diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 6c82fc0ca..cb6985a6e 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -354,9 +354,9 @@ main() # check enum defined at top level type Foo = enum - A + A = -10 B = "bb" - C = (5, "ccc") + C = (-5, "ccc") D = 15 E = "ee" # check that we count enum fields correctly From 800ce5b9507469d1d8e87d4e7730e2f1750dc8d7 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 29 Apr 2020 09:59:08 +0300 Subject: [PATCH 0428/4254] Fix negative indexed arrays for JS, refs #13966 (#14152) * Fix negative arrays for JS, refs #13966 * small extra fix: no need to .slice() cstring in JS --- compiler/jsgen.nim | 8 ++++---- tests/js/tarrayboundscheck.nim | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 27c4e0e2a..751c043c5 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1161,9 +1161,9 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = first = firstOrd(p.config, typ[0]) if optBoundsCheck in p.options: useMagic(p, "chckIndx") - r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-$2" % [b.res, rope(first), tmp] + r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-($2)" % [b.res, rope(first), tmp] elif first != 0: - r.res = "($1)-$2" % [b.res, rope(first)] + r.res = "($1)-($2)" % [b.res, rope(first)] else: r.res = b.res r.kind = resExpr @@ -1897,8 +1897,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = let rhsIsLit = n[2].kind in nkStrKinds let (a, tmp) = maybeMakeTemp(p, n[1], lhs) if skipTypes(n[1].typ, abstractVarRange).kind == tyCString: - r.res = "if ($1 != null) { $4 += $2; } else { $4 = $2$3; }" % [ - a, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp] + r.res = "if ($1 != null) { $3 += $2; } else { $3 = $2; }" % [ + a, rhs.rdLoc, tmp] else: r.res = "if ($1 != null) { $4 = ($4).concat($2); } else { $4 = $2$3; }" % [ lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp] diff --git a/tests/js/tarrayboundscheck.nim b/tests/js/tarrayboundscheck.nim index f0eaeb89d..d8bf8de97 100644 --- a/tests/js/tarrayboundscheck.nim +++ b/tests/js/tarrayboundscheck.nim @@ -39,6 +39,12 @@ proc test_arrayboundscheck() = echo "month out of bounds: ", idx except: echo "idx out of bounds: ", i + + # #13966 + var negativeIndexed: array[-2..2, int] = [0, 1, 2, 3, 4] + negativeIndexed[-1] = 2 + negativeIndexed[1] = 2 + doAssert negativeIndexed == [0, 2, 2, 2, 4] test_arrayboundscheck() {.pop.} \ No newline at end of file From a297c016fab069665aeb1125ff1c85b5e25e6a01 Mon Sep 17 00:00:00 2001 From: Tristram Oaten Date: Wed, 29 Apr 2020 16:06:14 +0100 Subject: [PATCH 0429/4254] Remove travis ci badge (#14062) --- readme.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.md b/readme.md index 4ae21cabc..d43217215 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,6 @@ devel: [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=devel)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=devel) 1.0: [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=version-1-0)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=version-1-0) 1.2: [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=version-1-2)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=version-1-2) -travis: [![Build Status][badge-nim-travisci]][nim-travisci] freebsd: [![builds.sr.ht freebsd status](https://builds.sr.ht/~araq/nim/freebsd.yml.svg)](https://builds.sr.ht/~araq/nim/freebsd.yml?) openbsd: [![builds.sr.ht openbsd status](https://builds.sr.ht/~araq/nim/openbsd.yml.svg)](https://builds.sr.ht/~araq/nim/openbsd.yml?) ssl: ![](https://github.com/nim-lang/Nim/workflows/Nim%20SSL%20CI/badge.svg) @@ -204,7 +203,6 @@ Copyright © 2006-2020 Andreas Rumpf, all rights reserved. [nim-issues]: https://github.com/nim-lang/Nim/issues [nim-issues-easy]: https://github.com/nim-lang/Nim/labels/Easy [nim-irc]: https://webchat.freenode.net/?channels=nim -[nim-travisci]: https://travis-ci.org/nim-lang/Nim [nim-twitter]: https://twitter.com/nim_lang [nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim-lang [nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim-lang?sort=newest&pageSize=15 From 707367e1ca231d964ba82a92b642eb5efdc1aa7c Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 29 Apr 2020 21:55:09 +0300 Subject: [PATCH 0430/4254] many bugfixes for js (#14158) * many bugfixes for js fixes #12672, fixes #14153, closes #14123, closes #11331, fixes #11783, fixes #13966, fixes #14087, fixes #14117, closes #12256. mostly fixes the fact that it was allowed to assign to newly created temp variables. additionally attempts to get rid of null initialized seqs/strings (though they might pop up here and there); this simplifies a lot of things and makes code size smaller. even if null seqs/strings pop up here and there it's still better than all those bugs existing. * formatting fixes * CI fixes * more CI fixes --- compiler/jsgen.nim | 120 +++++++++++++++++++++++-------- lib/system/jssys.nim | 25 ++++--- lib/system/reprjs.nim | 14 ---- tests/js/t12672.nim | 12 ++++ tests/js/t14153.nim | 22 ++++++ tests/js/tjshello.nim | 2 +- tests/js/tjshello_stacktrace.nim | 9 +++ tests/js/tmangle.nim | 4 +- tests/js/trepr.nim | 18 ++--- tests/js/ttempgen.nim | 79 ++++++++++++++++++++ 10 files changed, 240 insertions(+), 65 deletions(-) create mode 100644 tests/js/t12672.nim create mode 100644 tests/js/t14153.nim create mode 100644 tests/js/tjshello_stacktrace.nim create mode 100644 tests/js/ttempgen.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 751c043c5..eb9e97fac 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -86,6 +86,7 @@ type generatedSyms: IntSet typeInfoGenerated: IntSet unique: int # for temp identifier generation + inSystem: bool PProc = ref TProc TProc = object @@ -159,6 +160,14 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode, extraIndent: int(procDef != nil)) if procDef != nil: result.prc = procDef[namePos].sym +proc initProcOptions(module: BModule): TOptions = + result = module.config.options + if PGlobals(module.graph.backend).inSystem: + result.excl(optStackTrace) + +proc newInitProc(globals: PGlobals, module: BModule): PProc = + result = newProc(globals, module, nil, initProcOptions(module)) + proc declareGlobal(p: PProc; id: int; r: Rope) = if p.prc != nil and not p.declaredGlobals.containsOrIncl(id): p.locals.addf("global $1;$n", [r]) @@ -455,7 +464,48 @@ proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] = else: (a: a, tmp: b) -template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = +proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] = + var + a = x.rdLoc + b = a + if needsTemp(p, n): + # if we have tmp just use it + if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}): + b = "$1[0][$1[1]]" % [x.tmpLoc] + result = (a: a, tmp: b) + elif x.tmpLoc != nil and n.kind == nkBracketExpr: + # genArrayAddr + var + address, index: TCompRes + first: Int128 + gen(p, n[0], address) + gen(p, n[1], index) + let (m1, tmp1) = maybeMakeTemp(p, n[0], address) + let typ = skipTypes(n[0].typ, abstractPtrs) + if typ.kind == tyArray: + first = firstOrd(p.config, typ[0]) + if optBoundsCheck in p.options: + useMagic(p, "chckIndx") + if first == 0: # save a couple chars + index.res = "chckIndx($1, 0, ($2).length-1)" % [index.res, tmp1] + else: + index.res = "chckIndx($1, $2, ($3).length+($2)-1)-($2)" % [ + index.res, rope(first), tmp1] + elif first != 0: + index.res = "($1)-($2)" % [index.res, rope(first)] + else: + discard # index.res = index.res + let (n1, tmp2) = maybeMakeTemp(p, n[1], index) + result = (a: "$1[$2]" % [m1, n1], tmp: "$1[$2]" % [tmp1, tmp2]) + # could also put here: nkDotExpr -> genFieldAccess, nkCheckedFieldExpr -> genCheckedFieldOp + # but the uses of maybeMakeTempAssignable don't need them + else: + result = (a: a, tmp: b) + else: + result = (a: a, tmp: b) + +template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string, + reassign = false) = # $1 and $2 in the `frmt` string bind to lhs and rhs of the expr, # if $3 or $4 are present they will be substituted with temps for # lhs and rhs respectively @@ -467,8 +517,11 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = var a, tmp = x.rdLoc b, tmp2 = y.rdLoc - when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x) - when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y) + when reassign: + (a, tmp) = maybeMakeTempAssignable(p, n[1], x) + else: + when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x) + when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y) r.res = frmt % [a, b, tmp, tmp2] r.kind = resExpr @@ -485,13 +538,13 @@ template unsignedTrimmer(size: BiggestInt): Rope = size.unsignedTrimmerJS proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, - reassign = false) = + reassign: static[bool] = false) = var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size) - if reassign: - let (a, tmp) = maybeMakeTemp(p, n[1], x) + when reassign: + let (a, tmp) = maybeMakeTempAssignable(p, n[1], x) r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp] else: r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer] @@ -1161,7 +1214,11 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = first = firstOrd(p.config, typ[0]) if optBoundsCheck in p.options: useMagic(p, "chckIndx") - r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-($2)" % [b.res, rope(first), tmp] + if first == 0: # save a couple chars + r.res = "chckIndx($1, 0, ($2).length-1)" % [b.res, tmp] + else: + r.res = "chckIndx($1, $2, ($3).length+($2)-1)-($2)" % [ + b.res, rope(first), tmp] elif first != 0: r.res = "($1)-($2)" % [b.res, rope(first)] else: @@ -1631,7 +1688,11 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("[null, 0]", indirect) else: result = putToSeq("null", indirect) - of tySequence, tyOpt, tyString, tyCString, tyProc: + of tySequence, tyString: + result = putToSeq("[]", indirect) + of tyCString: + result = putToSeq("\"\"", indirect) + of tyOpt, tyProc: result = putToSeq("null", indirect) of tyStatic: if t.n != nil: @@ -1862,7 +1923,7 @@ proc genReset(p: PProc, n: PNode) = if x.typ == etyBaseIndex: lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res]) else: - let (a, tmp) = maybeMakeTemp(p, n[1], x) + let (a, tmp) = maybeMakeTempAssignable(p, n[1], x) lineF(p, "$1 = genericReset($3, $2);$n", [a, genTypeInfo(p, n[1].typ), tmp]) @@ -1888,37 +1949,33 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mSwap: genSwap(p, n) of mAppendStrCh: binaryExpr(p, n, r, "addChar", - "if ($1 != null) { addChar($3, $2); } else { $3 = [$2]; }") + "addChar($1, $2);") of mAppendStrStr: var lhs, rhs: TCompRes gen(p, n[1], lhs) gen(p, n[2], rhs) - let rhsIsLit = n[2].kind in nkStrKinds - let (a, tmp) = maybeMakeTemp(p, n[1], lhs) if skipTypes(n[1].typ, abstractVarRange).kind == tyCString: - r.res = "if ($1 != null) { $3 += $2; } else { $3 = $2; }" % [ - a, rhs.rdLoc, tmp] + r.res = "$1 += $2;" % [lhs.rdLoc, rhs.rdLoc] else: - r.res = "if ($1 != null) { $4 = ($4).concat($2); } else { $4 = $2$3; }" % [ - lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp] + let (a, tmp) = maybeMakeTemp(p, n[1], lhs) + r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp] r.kind = resExpr of mAppendSeqElem: var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) - let (a, tmp) = maybeMakeTemp(p, n[1], x) if mapType(n[2].typ) == etyBaseIndex: let c = "[$1, $2]" % [y.address, y.res] - r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp] + r.res = "$1.push($2);" % [x.rdLoc, c] elif needsNoCopy(p, n[2]): - r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, y.rdLoc, tmp] + r.res = "$1.push($2);" % [x.rdLoc, y.rdLoc] else: useMagic(p, "nimCopy") let c = getTemp(p, defineInLocals=false) lineF(p, "var $1 = nimCopy(null, $2, $3);$n", [c, y.rdLoc, genTypeInfo(p, n[2].typ)]) - r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp] + r.res = "$1.push($2);" % [x.rdLoc, c] r.kind = resExpr of mConStrStr: genConStrStr(p, n, r) @@ -1950,23 +2007,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mDestroy: discard "ignore calls to the default destructor" of mOrd: genOrd(p, n, r) of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: - unaryExpr(p, n, r, "", "($1 != null ? $2.length : 0)") + unaryExpr(p, n, r, "", "($1).length") of mHigh: - unaryExpr(p, n, r, "", "($1 != null ? ($2.length-1) : -1)") + unaryExpr(p, n, r, "", "(($1).length-1)") of mInc: if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: binaryUintExpr(p, n, r, "+", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2") - else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)") + else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true) of ast.mDec: if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: binaryUintExpr(p, n, r, "-", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") - else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)") + else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true) of mSetLengthStr: - binaryExpr(p, n, r, "mnewString", "($1 == null ? $3 = mnewString($2) : $3.length = $2)") + binaryExpr(p, n, r, "mnewString", "($1.length = $2)") of mSetLengthSeq: var x, y: TCompRes gen(p, n[1], x) @@ -1974,8 +2031,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = let t = skipTypes(n[1].typ, abstractVar)[0] let (a, tmp) = maybeMakeTemp(p, n[1], x) let (b, tmp2) = maybeMakeTemp(p, n[2], y) - r.res = """if ($1 === null) $4 = []; - if ($4.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); } + r.res = """if ($1.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); } else { $4.length = $5; }""" % [a, b, createVar(p, t, false), tmp, tmp2] r.kind = resExpr of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)") @@ -2482,6 +2538,8 @@ proc newModule(g: ModuleGraph; module: PSym): BModule = g.backend = newGlobals() result.graph = g result.config = g.config + if sfSystemModule in module.flags: + PGlobals(g.backend).inSystem = true proc genHeader(): Rope = result = rope("""/* Generated by the Nim Compiler v$1 */ @@ -2555,7 +2613,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode = if passes.skipCodegen(m.config, n): return n if m.module == nil: internalError(m.config, n.info, "myProcess") let globals = PGlobals(m.graph.backend) - var p = newProc(globals, m, nil, m.module.options) + var p = newInitProc(globals, m) p.unique = globals.unique genModule(p, n) p.g.code.add(p.locals) @@ -2565,14 +2623,14 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope = let globals = PGlobals(graph.backend) for prc in globals.forwarded: if not globals.generatedSyms.containsOrIncl(prc.id): - var p = newProc(globals, m, nil, m.module.options) + var p = newInitProc(globals, m) attachProc(p, prc) var disp = generateMethodDispatchers(graph) for i in 0.. 2147483647 || `a` < -2147483648) `raiseOverflow`(); + """ + proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` + `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + `checkOverflowInt`(result); return result; """ proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` - `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + `checkOverflowInt`(result); return result; """ proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` * `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + `checkOverflowInt`(result); return result; """ @@ -432,27 +437,29 @@ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = return Math.trunc(`a` % `b`); """ +proc checkOverflowInt64(a: int) {.asmNoStackFrame, compilerproc.} = + asm """ + if (`a` > 9223372036854775807 || `a` < -9223372036854775808) `raiseOverflow`(); + """ + proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` + `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); + `checkOverflowInt64`(result); return result; """ proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` - `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); + `checkOverflowInt64`(result); return result; """ proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` * `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); + `checkOverflowInt64`(result); return result; """ diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index c45053537..c3f3199a4 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -130,20 +130,6 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) proc reprArray(a: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} = - var isNilArrayOrSeq: bool - # isnil is not enough here as it would try to deref `a` without knowing what's inside - {. emit: """ - if (`a` == null) { - `isNilArrayOrSeq` = true; - } else if (`a`[0] == null) { - `isNilArrayOrSeq` = true; - } else { - `isNilArrayOrSeq` = false; - }; - """ .} - if typ.kind == tySequence and isNilArrayOrSeq: - return "nil" - # We prepend @ to seq, the C backend prepends the pointer to the seq. result = if typ.kind == tySequence: "@[" else: "[" var len: int = 0 diff --git a/tests/js/t12672.nim b/tests/js/t12672.nim new file mode 100644 index 000000000..a658fbcbe --- /dev/null +++ b/tests/js/t12672.nim @@ -0,0 +1,12 @@ +discard """ + output: "" +""" + +proc foo = + var x: seq[seq[int]] + for row in x.mitems: + let i = 1 + echo row + inc row[i-1] + +foo() diff --git a/tests/js/t14153.nim b/tests/js/t14153.nim new file mode 100644 index 000000000..350bbd83b --- /dev/null +++ b/tests/js/t14153.nim @@ -0,0 +1,22 @@ +discard """ + output: ''' +index 5 not in 0 .. 2 +index 5 not in 0 .. 2 +''' +""" + +var x = @[1, 2, 3] + +try: + echo x[5] +except IndexError: + echo getCurrentExceptionMsg() +except: + doAssert false + +try: + x[5] = 8 +except IndexError: + echo getCurrentExceptionMsg() +except: + doAssert false diff --git a/tests/js/tjshello.nim b/tests/js/tjshello.nim index 19e0b90ae..8e090b3d2 100644 --- a/tests/js/tjshello.nim +++ b/tests/js/tjshello.nim @@ -1,4 +1,5 @@ discard """ + cmd: "nim $target $options --stackTrace:off --lineTrace:off $file" output: "Hello World" maxcodesize: 1000 ccodecheck: "!@'function'" @@ -7,4 +8,3 @@ discard """ import jsconsole console.log "Hello World" - diff --git a/tests/js/tjshello_stacktrace.nim b/tests/js/tjshello_stacktrace.nim new file mode 100644 index 000000000..d5e1c36eb --- /dev/null +++ b/tests/js/tjshello_stacktrace.nim @@ -0,0 +1,9 @@ +discard """ + output: "Hello World" + maxcodesize: 4500 + ccodecheck: "!@'function'" +""" + +import jsconsole + +console.log "Hello World" diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim index c97bf7029..393043722 100644 --- a/tests/js/tmangle.nim +++ b/tests/js/tmangle.nim @@ -62,8 +62,8 @@ block: result = result and obj1.`&&`.addr[] == "bar".cstring result = result and obj2.`if` == 0 result = result and obj2.`for` == 0 - result = result and obj2.`==`.isNil() - result = result and obj2.`&&`.isNil() + result = result and obj2.`==`.len == 0 + result = result and obj2.`&&`.len == 0 echo test() # Test codegen for fields with uppercase letters: diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim index 366d247c5..ffa9d4de0 100644 --- a/tests/js/trepr.nim +++ b/tests/js/trepr.nim @@ -308,21 +308,21 @@ b = 0, c = 0.0, d = '\0', e = eA, -f = nil, +f = "", g = {}, h = {}, -i = [nil, nil, nil], -j = nil, +i = ["", "", ""], +j = @[], k = 0, -l = [a = nil, -b = nil], +l = [a = "", +b = @[]], m = nil, n = nil, -o = [Field0 = [a = nil, -b = nil], -Field1 = nil], +o = [Field0 = [a = "", +b = @[]], +Field1 = ""], p = nil, -q = nil] +q = ""] """) doAssert(repr(cc) == """ [a = 12, diff --git a/tests/js/ttempgen.nim b/tests/js/ttempgen.nim new file mode 100644 index 000000000..badc66c1b --- /dev/null +++ b/tests/js/ttempgen.nim @@ -0,0 +1,79 @@ +discard """ + output: ''' +foo +''' +""" + +block: # #12672 + var a = @[1] + let i = 1 + inc a[i-1] + + var b: seq[int] + doAssertRaises(IndexDefect): inc b[0] + doAssertRaises(IndexDefect): inc b[i-1] + + var x: seq[seq[int]] + doAssertRaises(IndexDefect): # not TypeError + inc x[0][i-1] + +block: # #14087 + type Obj = object + str: string + + var s = @[Obj(str: "abc"), Obj(str: "def")] + s[1].str.add("ghi") + s[s.len - 1].str.add("jkl") + s[^1].str.add("mno") + s[s.high].str.add("pqr") + + let slen = s.len + s[slen - 1].str.add("stu") + + let shigh = s.high + s[shigh].str.add("vwx") + + proc foo(): int = + echo "foo" + shigh + s[foo()].str.add("yz") + doAssert s[1].str == "defghijklmnopqrstuvwxyz" + +block: # #14117 + type + A = object + case kind: bool + of true: + sons: seq[int] + else: discard + + var a = A(kind: true) + doAssert a.sons.len == 0 + a.sons.add(1) + doAssert a.sons.len == 1 + +import tables + +block: # #13966 + var t: Table[int8, array[int8, seq[tuple[]]]] + + t[0] = default(array[int8, seq[tuple[]]]) + t[0][0].add () + +block: # #11783 + proc fun(): string = + discard + + var ret: string + ret.add fun() + doAssert ret == "" + +block: # #12256 + var x: bool + + doAssert x == false + + reset x + + doAssert x == false + doAssert x != true From d9e907c0e2a58630f7b57c0afbe51c05fcf6b3ab Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 29 Apr 2020 21:58:59 +0200 Subject: [PATCH 0431/4254] fixes #14079 [backport:1.2] (#14163) --- compiler/sempass2.nim | 3 ++- compiler/sigmatch.nim | 3 ++- compiler/sinkparameter_inference.nim | 3 +-- lib/pure/algorithm.nim | 2 +- tests/arc/tarcmisc.nim | 14 ++++++++++++-- tests/arc/twrong_sinkinference.nim | 18 ++++++++++++++++++ 6 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 tests/arc/twrong_sinkinference.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b801f4531..0fdf25850 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -854,7 +854,8 @@ proc track(tracked: PEffects, n: PNode) = when false: cstringCheck(tracked, n) if tracked.owner.kind != skMacro: createTypeBoundOps(tracked, n[0].typ, n.info) - checkForSink(tracked.config, tracked.owner, n[1]) + if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym): + checkForSink(tracked.config, tracked.owner, n[1]) of nkVarSection, nkLetSection: for child in n: let last = lastSon(child) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6c8f926dd..e209f5d78 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -548,7 +548,8 @@ proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation = result = isNone proc inconsistentVarTypes(f, a: PType): bool {.inline.} = - result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent}) + result = f.kind != a.kind and + (f.kind in {tyVar, tyLent, tySink} or a.kind in {tyVar, tyLent, tySink}) proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = ## For example we have: diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim index 1becc250e..182e44324 100644 --- a/compiler/sinkparameter_inference.nim +++ b/compiler/sinkparameter_inference.nim @@ -48,8 +48,7 @@ proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) = # we only report every potential 'sink' parameter only once: incl arg.sym.flags, sfWasForwarded message(config, arg.info, hintPerformance, - ("could not turn '$1' to a sink parameter " & - "because '$2' was forward declared") % [arg.sym.name.s, owner.name.s]) + "could not turn '$1' to a sink parameter" % [arg.sym.name.s]) #echo config $ arg.info, " candidate for a sink parameter here" of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr: if not isEmptyType(arg.typ): diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index ed1ca893d..91f2f41b8 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -504,7 +504,7 @@ template sortedByIt*(seq1, op: untyped): untyped = # Nested sort assert people.sortedByIt((it.age, it.name)) == @[(name: "p2", age: 20), (name: "p3", age: 30), (name: "p4", age: 30), (name: "p1", age: 60)] - var result = sorted(seq1, proc(x, y: type(seq1[0])): int = + var result = sorted(seq1, proc(x, y: typeof(seq1[0])): int = var it {.inject.} = x let a = op it = y diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 963ae9806..ce8e902c6 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -46,7 +46,7 @@ type proc `=destroy`(x: var AObj) = close(x.io) echo "closed" - + var x = B(io: newStringStream("thestream")) @@ -64,4 +64,14 @@ proc main() = cryptCTR(nonce2.toOpenArray(0, nonce2.len-1)) doAssert(nonce2 == "0A234567") -main() \ No newline at end of file +main() + +# bug #14079 +import std/algorithm + +let + n = @["c", "b"] + q = @[("c", "2"), ("b", "1")] + +assert n.sortedByIt(it) == @["b", "c"], "fine" +assert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" diff --git a/tests/arc/twrong_sinkinference.nim b/tests/arc/twrong_sinkinference.nim new file mode 100644 index 000000000..59930a9fa --- /dev/null +++ b/tests/arc/twrong_sinkinference.nim @@ -0,0 +1,18 @@ +discard """ + cmd: "nim c --gc:arc $file" + errormsg: "type mismatch: got " + line: 18 +""" + +type + Foo = proc (a, b: string) + +proc take(x: Foo) = + x("a", "b") + +proc willSink(a, b: string) = # {.nosinks.} = + var arr: array[3, string] + var x = a + arr[0] = b + +take willSink From bd57f0cd3268843808c52614864a609703d9e611 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 29 Apr 2020 22:13:45 +0200 Subject: [PATCH 0432/4254] fixes another silly arc/orc bug [backport:1.2] --- compiler/ccgtypes.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index c4836c447..1e82a9725 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1322,6 +1322,7 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) else: typeName = rope("NIM_NIL") + discard cgsym(m, "TNimType") m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) let destroyImpl = genHook(m, t, info, attachedDestructor) let traceImpl = genHook(m, t, info, attachedTrace) From d6e1b5c070bf58449bf4af210ec099418d496aa5 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 30 Apr 2020 02:01:07 +0200 Subject: [PATCH 0433/4254] Fix #14160 (#14161) * Fix #14160 * Add testcase --- compiler/ccgexprs.nim | 8 +++++++- tests/ccgbugs/t14160.nim | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/ccgbugs/t14160.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 806eca744..0b9958ee4 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2450,6 +2450,8 @@ proc genStmtList(p: BProc, n: PNode) = genStmtListExprImpl: genStmts(p, n[^1]) +from parampatterns import isLValue + proc upConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, n[0], a) @@ -2468,7 +2470,11 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); $3}$n", [r, checkFor, raiseInstr(p)]) if n[0].typ.kind != tyObject: - putIntoDest(p, d, n, + if n.isLValue: + putIntoDest(p, d, n, + "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) + else: + putIntoDest(p, d, n, "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) else: putIntoDest(p, d, n, "(*($1*) ($2))" % diff --git a/tests/ccgbugs/t14160.nim b/tests/ccgbugs/t14160.nim new file mode 100644 index 000000000..be7088e29 --- /dev/null +++ b/tests/ccgbugs/t14160.nim @@ -0,0 +1,15 @@ +type + TPassContext = object of RootObj + PPassContext = ref TPassContext + + PCtx = ref object of TPassContext + a: int + + ModuleGraph = object + vm: RootRef + +proc main() = + var g = ModuleGraph(vm: new(Pctx)) + PCtx(g.vm) = nil #This generates invalid C code + +main() From cc60caedb3a1c7043b0f7ef2db5c741ecaa1482f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Apr 2020 06:48:57 +0200 Subject: [PATCH 0434/4254] fixes #14054 [backport:1.2] (#14061) * fixes #14054 * make tests green again * more tests are green * maybe now --- changelog.md | 4 +++ lib/pure/strformat.nim | 4 +-- lib/pure/strutils.nim | 7 ++--- tests/destructor/tnewruntime_strutils.nim | 2 +- tests/stdlib/tstrformat.nim | 31 +++++++++++++++++++++++ 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index e7ab1a298..4aa22b9d7 100644 --- a/changelog.md +++ b/changelog.md @@ -31,7 +31,11 @@ - The file descriptors created for internal bookkeeping by `ioselector_kqueue` and `ioselector_epoll` will no longer be leaked to child processes. +- `strutils.formatFloat` with `precision = 0` has been restored to the version + 1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)` + is now `3.`, not `3`. - `critbits` adds `commonPrefixLen`. + - `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results (see #13222); instead they now use `getCurrentDir` to resolve those cases, and this can now throw in edge cases where `getCurrentDir` throws. diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 838baaf02..5f7ef380d 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -692,11 +692,11 @@ when isMainModule: check &"{-123.456:.3f}", "-123.456" check &"{123.456:1g}", "123.456" check &"{123.456:.1f}", "123.5" - check &"{123.456:.0f}", "123" + check &"{123.456:.0f}", "123." check &"{123.456:>9.3f}", " 123.456" check &"{123.456:9.3f}", " 123.456" check &"{123.456:>9.4f}", " 123.4560" - check &"{123.456:>9.0f}", " 123" + check &"{123.456:>9.0f}", " 123." check &"{123.456:<9.4f}", "123.4560 " # Float (scientific) tests diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index ff76fa94f..a1f80ad76 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2430,10 +2430,6 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, # but nothing else is possible: if buf[i] in {'.', ','}: result[i] = decimalSep else: result[i] = buf[i] - since (1, 1): - # remove trailing dot, compatible with Python's formatter and JS backend - if result[^1] == decimalSep: - result.setLen(len(result)-1) when defined(windows): # VS pre 2015 violates the C standard: "The exponent always contains at # least two digits, and only as many more digits as necessary to @@ -2936,7 +2932,8 @@ proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, when isMainModule: proc nonStaticTests = doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235" # bugs 8242, 12586 + when not defined(js): + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 9afb507f7..b0bceb4b5 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -37,7 +37,7 @@ bug12899() proc nonStaticTests = doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235" # bugs 8242, 12586 + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 403372aed..7db001979 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -173,3 +173,34 @@ block: y = 234 z = true """ + + +# tests from the very own strformat documentation! + +let msg = "hello" +doAssert fmt"{msg}\n" == "hello\\n" + +doAssert &"{msg}\n" == "hello\n" + +doAssert fmt"{msg}{'\n'}" == "hello\n" +doAssert fmt("{msg}\n") == "hello\n" +doAssert "{msg}\n".fmt == "hello\n" + +doAssert &"""{"abc":>4}""" == " abc" +doAssert &"""{"abc":<4}""" == "abc " + +doAssert fmt"{-12345:08}" == "-0012345" +doAssert fmt"{-1:3}" == " -1" +doAssert fmt"{-1:03}" == "-01" +doAssert fmt"{16:#X}" == "0x10" + +doAssert fmt"{123.456}" == "123.456" +doAssert fmt"{123.456:>9.3f}" == " 123.456" +doAssert fmt"{123.456:9.3f}" == " 123.456" +doAssert fmt"{123.456:9.4f}" == " 123.4560" +doAssert fmt"{123.456:>9.0f}" == " 123." +doAssert fmt"{123.456:<9.4f}" == "123.4560 " + +doAssert fmt"{123.456:e}" == "1.234560e+02" +doAssert fmt"{123.456:>13e}" == " 1.234560e+02" +doAssert fmt"{123.456:13e}" == " 1.234560e+02" From f1068c01a88548b773971c94a2df5e9372392e28 Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 30 Apr 2020 10:11:18 +0200 Subject: [PATCH 0435/4254] [ci skip] prevent fail-fast on packages CI --- .github/workflows/ci_packages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 1958d4b8d..26445cee4 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -4,6 +4,7 @@ on: [push, pull_request] jobs: build: strategy: + fail-fast: false matrix: os: [ubuntu-18.04, macos-10.15] cpu: [amd64] From d844d10e8e1aea9d9995c954553b8982f3b3f031 Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 30 Apr 2020 10:19:18 +0200 Subject: [PATCH 0436/4254] [ci skip] clean-up CI badges --- readme.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/readme.md b/readme.md index d43217215..d34b78548 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,6 @@ # Nim -devel: [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=devel)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=devel) -1.0: [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=version-1-0)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=version-1-0) -1.2: [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=version-1-2)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=version-1-2) -freebsd: [![builds.sr.ht freebsd status](https://builds.sr.ht/~araq/nim/freebsd.yml.svg)](https://builds.sr.ht/~araq/nim/freebsd.yml?) -openbsd: [![builds.sr.ht openbsd status](https://builds.sr.ht/~araq/nim/openbsd.yml.svg)](https://builds.sr.ht/~araq/nim/openbsd.yml?) -ssl: ![](https://github.com/nim-lang/Nim/workflows/Nim%20SSL%20CI/badge.svg) -docs: ![](https://github.com/nim-lang/Nim/workflows/Nim%20Docs%20CI/badge.svg) +[![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=devel)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=devel) This repository contains the Nim compiler, Nim's stdlib, tools and documentation. For more information about Nim, including downloads and documentation for From 4d799f88200aaaf35d9275b64d2c23611b943769 Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 30 Apr 2020 13:03:48 +0200 Subject: [PATCH 0437/4254] test even more packages --- .github/workflows/ci_packages.yml | 2 +- testament/important_packages.nim | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 26445cee4..9d2d044ff 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -33,7 +33,7 @@ jobs: DEBIAN_FRONTEND='noninteractive' \ sudo apt-fast install --no-install-recommends -yq \ libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ - valgrind libc6-dbg + valgrind libc6-dbg libblas-dev - name: 'Install dependencies (macOS)' if: runner.os == 'macOS' run: brew install boehmgc make sfml diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 237e4b9e4..db6d686e5 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -5,17 +5,22 @@ template pkg(name: string; hasDeps = false; cmd = "nimble test"; url = ""): unty var packages*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[] - +pkg "alea", true pkg "argparse" pkg "arraymancer", true, "nim c tests/tests_cpu.nim" pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" pkg "asyncmysql", true +pkg "awk", true pkg "bigints" pkg "binaryheap", false, "nim c -r binaryheap.nim" +pkg "BipBuffer" # pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39 pkg "bncurve", true +pkg "brainfuck", true +pkg "bump", true, "nimble test", "https://github.com/disruptek/bump" pkg "c2nim", false, "nim c testsuite/tester.nim" pkg "cascade" +pkg "cello", true pkg "chroma" pkg "chronicles", true, "nim c -o:chr -r chronicles.nim" when not defined(osx): # testdatagram.nim(560, 54): Check failed @@ -27,6 +32,7 @@ pkg "compactdict" pkg "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" pkg "criterion" pkg "dashing", false, "nim c tests/functional.nim" +pkg "delaunay" pkg "docopt" pkg "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" @@ -34,17 +40,22 @@ pkg "fidget", true, "nim c -r tests/runNative.nim" pkg "fragments", false, "nim c -r fragments/dsl.nim" pkg "gara" pkg "ggplotnim", true, "nimble testCI" +# pkg "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" pkg "glob" pkg "gnuplot" pkg "hts", false, "nim c -o:htss src/hts.nim" +# pkg "httpauth", true pkg "illwill", false, "nimble examples" # pkg "inim", true # pending https://github.com/inim-repl/INim/issues/74 pkg "itertools", false, "nim doc src/itertools.nim" pkg "iterutils" pkg "jstin" pkg "karax", false, "nim c -r tests/tester.nim" +pkg "kdtree", false, "nimble test", "https://github.com/jblindsay/kdtree" pkg "loopfusion" pkg "macroutils" +pkg "markdown" +pkg "memo" pkg "msgpack4nim" pkg "nake", false, "nim c nakefile.nim" pkg "neo", true, "nim c -d:blas=openblas tests/all.nim" @@ -74,10 +85,12 @@ pkg "nimquery" pkg "nimsl", true pkg "nimsvg" # pkg "nimterop", true +pkg "nimwc", true, "nim c nimwc.nim" pkg "nimx", true, "nim c --threads:on test/main.nim" pkg "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" pkg "norm", true, "nim c -r tests/tsqlite.nim" pkg "npeg" +pkg "numericalnim", true pkg "optionsutils" pkg "ormin", true, "nim c -o:orminn ormin.nim" pkg "parsetoml" @@ -92,16 +105,21 @@ pkg "rbtree" pkg "react", false, "nimble example" pkg "regex", true, "nim c src/regex" pkg "result", false, "nim c -r result.nim" +pkg "RollingHash" pkg "rosencrantz", false, "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", false, "nim c -r src/sdl.nim" pkg "sdl2_nim", false, "nim c -r sdl2/sdl.nim" +pkg "sigv4", true, "nimble test", "https://github.com/disruptek/sigv4" pkg "snip", false, "nimble test", "https://github.com/genotrance/snip" pkg "stint", false, "nim c -o:stintt -r stint.nim" +pkg "strslice" pkg "strunicode", true, "nim c -r src/strunicode.nim" +pkg "synthesis" pkg "telebot", true, "nim c -o:tbot -r src/telebot.nim" pkg "tempdir" pkg "templates" pkg "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" +pkg "terminaltables", false, "nim c src/terminaltables.nim" pkg "termstyle" pkg "timeit" pkg "timezones" From 0aefebb728622dfda05db68e2d04ba7c47405444 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Thu, 30 Apr 2020 19:04:53 +0300 Subject: [PATCH 0438/4254] JS unittest stacktrace fix, cleanup js repr and inclrtl includes (#14168) --- lib/pure/asyncdispatch.nim | 2 -- lib/pure/collections/sharedtables.nim | 2 -- lib/pure/unittest.nim | 17 +++++----- lib/system/reprjs.nim | 46 +++++++-------------------- tests/js/tunittest_error.nim | 22 +++++++++++++ 5 files changed, 43 insertions(+), 46 deletions(-) create mode 100644 tests/js/tunittest_error.nim diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 87c6aa7e2..1421db2e8 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -166,8 +166,6 @@ ## ## * The effect system (``raises: []``) does not work with async procedures. -include "system/inclrtl" - import os, tables, strutils, times, heapqueue, options, asyncstreams import options, math, std/monotimes import asyncfutures except callSoon diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 2a1c0543f..cad9ca2c1 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -17,8 +17,6 @@ import hashes, math, locks -include "system/inclrtl" - type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] KeyValuePairSeq[A, B] = ptr UncheckedArray[KeyValuePair[A, B]] diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 6e0147595..6c434bb19 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -101,7 +101,9 @@ include "system/inclrtl" when declared(stdout): import os -when not defined(ECMAScript): +const useTerminal = not defined(js) + +when useTerminal: import terminal type @@ -224,7 +226,7 @@ proc defaultConsoleFormatter*(): ConsoleOutputFormatter = method suiteStarted*(formatter: ConsoleOutputFormatter, suiteName: string) = template rawPrint() = echo("\n[Suite] ", suiteName) - when not defined(ECMAScript): + when useTerminal: if formatter.colorOutput: styledEcho styleBright, fgBlue, "\n[Suite] ", resetStyle, suiteName else: rawPrint() @@ -250,7 +252,7 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) = let prefix = if testResult.suiteName.len > 0: " " else: "" template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName) - when not defined(ECMAScript): + when useTerminal: if formatter.colorOutput: var color = case testResult.status of TestStatus.OK: fgGreen @@ -515,11 +517,10 @@ template test*(name, body) {.dirty.} = body except: - when not defined(js): - let e = getCurrentException() - let eTypeDesc = "[" & exceptionTypeName(e) & "]" - checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " " & eTypeDesc) - var stackTrace {.inject.} = e.getStackTrace() + let e = getCurrentException() + let eTypeDesc = "[" & exceptionTypeName(e) & "]" + checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " " & eTypeDesc) + var stackTrace {.inject.} = e.getStackTrace() fail() finally: diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index c3f3199a4..9c27a4721 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -8,34 +8,25 @@ # # The generic ``repr`` procedure for the javascript backend. -proc reprInt(x: int64): string {.compilerproc.} = return $x -proc reprFloat(x: float): string {.compilerproc.} = - # Js toString doesn't differentiate between 1.0 and 1, - # but we do. - if $x == $(x.int): $x & ".0" - else: $x +proc reprInt(x: int64): string {.compilerproc.} = $x +proc reprFloat(x: float): string {.compilerproc.} = $x proc reprPointer(p: pointer): string {.compilerproc.} = # Do we need to generate the full 8bytes ? In js a pointer is an int anyway var tmp: int - {. emit: """ - if (`p`_Idx == null) { - `tmp` = 0; - } else { - `tmp` = `p`_Idx; - } - """ .} + {.emit: "`tmp` = `p`_Idx || 0;".} result = $tmp proc reprBool(x: bool): string {.compilerRtl.} = if x: result = "true" else: result = "false" -proc isUndefined[T](x: T): bool {.inline.} = {.emit: "`result` = `x` === undefined;"} - proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = - if not typ.node.sons[e].isUndefined: - result = makeNimstrLit(typ.node.sons[e].name) + var tmp: bool + let item = typ.node.sons[e] + {.emit: "`tmp` = `item` !== undefined".} + if tmp: + result = makeNimstrLit(item.name) else: result = $e & " (invalid data!)" @@ -48,7 +39,7 @@ proc reprChar(x: char): string {.compilerRtl.} = else: add(result, x) add(result, "\'") -proc reprStrAux(result: var string, s: cstring, len: int) = +proc reprStrAux(result: var string, s: cstring | string, len: int) = add(result, "\"") for i in 0 .. len-1: let c = s[i] @@ -63,17 +54,7 @@ proc reprStrAux(result: var string, s: cstring, len: int) = add(result, "\"") proc reprStr(s: string): string {.compilerRtl.} = - result = "" - var sIsNil = false - asm """`sIsNil` = `s` === null""" - if sIsNil: # cast[pointer](s).isNil: - # Handle nil strings here because they don't have a length field in js - # TODO: check for null/undefined before generating call to length in js? - # Also: c backend repr of a nil string is "", but repr of an - # array of string that is not initialized is [nil, nil, ...] ?? - add(result, "nil") - else: - reprStrAux(result, s, s.len) + reprStrAux(result, s, s.len) proc addSetElem(result: var string, elem: int, typ: PNimType) = # Dispatch each set element to the correct repr proc @@ -114,7 +95,6 @@ proc reprSetAux(result: var string, s: int, typ: PNimType) = add(result, "}") proc reprSet(e: int, typ: PNimType): string {.compilerRtl.} = - result = "" reprSetAux(result, e, typ) type @@ -149,7 +129,7 @@ proc reprArray(a: pointer, typ: PNimType, add(result, "]") -proc isPointedToNil(p: pointer): bool {.inline.}= +proc isPointedToNil(p: pointer): bool = {. emit: "if (`p` === null) {`result` = true};\n" .} proc reprRef(result: var string, p: pointer, typ: PNimType, @@ -191,7 +171,6 @@ proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprCl add(result, "]") proc reprRecord(o: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} = - result = "" reprRecordAux(result, o, typ, cl) @@ -257,6 +236,5 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} = var cl: ReprClosure initReprClosure(cl) - result = "" reprAux(result, p, typ, cl) - add(result, "\n") \ No newline at end of file + add(result, "\n") diff --git a/tests/js/tunittest_error.nim b/tests/js/tunittest_error.nim new file mode 100644 index 000000000..ab736bf59 --- /dev/null +++ b/tests/js/tunittest_error.nim @@ -0,0 +1,22 @@ +discard """ + exitcode: 1 + outputsub: "[FAILED] with exception" +""" + +import unittest + +proc ddd() = + raise newException(IOError, "didn't do stuff") + +proc ccc() = + ddd() + +proc bbb() = + ccc() + +proc aaa() = + bbb() + +test "with exception": + check 3 == 3 + aaa() From cf3e0008b9725b5cc0b51b2605bc8ecb36fa449e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Apr 2020 19:32:03 +0200 Subject: [PATCH 0439/4254] fixes #13986 [backport:1.2] (#14173) --- compiler/docgen.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index fbdfbc884..a42be9a9c 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -86,11 +86,14 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re result = relativeTo(file, conf.docRoot.AbsoluteDir) else: bail() + if isAbsolute(result.string): + result = file.string.splitPath()[1].RelativeFile if isTitle: result = result.string.nativeToUnix.RelativeFile else: result = result.string.replace("..", "@@").RelativeFile ## refs #13223 doAssert not result.isEmpty + doAssert not isAbsolute(result.string) proc whichType(d: PDoc; n: PNode): PSym = if n.kind == nkSym: @@ -1140,7 +1143,10 @@ proc generateIndex*(d: PDoc) = proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html if d.conf.outDir.isEmpty: d.conf.outDir = d.conf.docOutDir - if d.conf.outFile.isEmpty: d.conf.outFile = outfile.relativeTo(d.conf.outDir) + if d.conf.outFile.isEmpty: + d.conf.outFile = outfile.relativeTo(d.conf.outDir) + if isAbsolute(d.conf.outFile.string): + d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile proc writeOutput*(d: PDoc, useWarning = false) = runAllExamples(d) From 3d2459bdc0b6d6236a2cd9209ed81c965ee411a5 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 30 Apr 2020 20:23:42 +0200 Subject: [PATCH 0440/4254] fixes the regression #12860 caused; hotfix --- lib/pure/os.nim | 2 +- lib/system/nimscript.nim | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index da84df791..b46205419 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -3119,7 +3119,7 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = assert(path != "") # symlinks can't occur for file handles formalInfo.kind = getSymlinkFileKind(path) -when defined(js): +when defined(js) or defined(nimscript): when not declared(FileHandle): type FileHandle = distinct int32 when not declared(File): diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index e0c400f05..5b8622182 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -272,6 +272,9 @@ proc selfExec*(command: string) {. raise newException(OSError, "FAILED: " & c) checkOsError() +from os import paramCount, paramStr +export paramCount, paramStr + proc put*(key, value: string) = ## Sets a configuration 'key' like 'gcc.options.always' to its value. builtin From 89be5be03e316193126cca637b326358489be908 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Apr 2020 22:45:02 +0200 Subject: [PATCH 0441/4254] fixes #13698 [backport:1.2] (#14175) --- lib/system/memory.nim | 4 ++-- tests/misc/trangechecks.nim | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/system/memory.nim b/lib/system/memory.nim index 8d190e5f9..50faa3d86 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -45,9 +45,9 @@ proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadabl if d != 0: return d inc i -proc nimCStrLen*(a: cstring): csize_t {.compilerproc, nonReloadable, inline.} = +proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline.} = when useLibC: - c_strlen(a) + cast[int](c_strlen(a)) else: var a = cast[ptr byte](a) while a[] != 0: diff --git a/tests/misc/trangechecks.nim b/tests/misc/trangechecks.nim index ac09e558c..e48b1272b 100644 --- a/tests/misc/trangechecks.nim +++ b/tests/misc/trangechecks.nim @@ -41,3 +41,8 @@ except OverflowDefect, RangeDefect: echo x echo expected == 4 + +# bug #13698 +var + x45 = "hello".cstring + p = x45.len.int32 From 6b39b47abcf5c528dbaf84ca75b693d1fc4da004 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 30 Apr 2020 22:47:59 +0200 Subject: [PATCH 0442/4254] hotfix: make tcompilerapi green again --- tests/compilerapi/tcompilerapi.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/compilerapi/tcompilerapi.nim b/tests/compilerapi/tcompilerapi.nim index edeaa2ba5..9d5e0e3f2 100644 --- a/tests/compilerapi/tcompilerapi.nim +++ b/tests/compilerapi/tcompilerapi.nim @@ -17,7 +17,8 @@ import std / [os] proc main() = let std = findNimStdLibCompileTime() - var intr = createInterpreter("myscript.nim",[std, parentDir(currentSourcePath)]) + var intr = createInterpreter("myscript.nim", [std, parentDir(currentSourcePath), + std / "pure", std / "core"]) intr.implementRoutine("*", "exposed", "addFloats", proc (a: VmArgs) = setResult(a, getFloat(a, 0) + getFloat(a, 1) + getFloat(a, 2)) ) @@ -46,7 +47,7 @@ block issue9180: proc evalString(code: string, moduleName = "script.nim") = let stream = llStreamOpen(code) let std = findNimStdLibCompileTime() - var intr = createInterpreter(moduleName, [std]) + var intr = createInterpreter(moduleName, [std, std / "pure", std / "core"]) intr.evalScript(stream) destroyInterpreter(intr) llStreamClose(stream) From 33e9ac7cd3796e26ea95bb755f9a732a24366161 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Thu, 30 Apr 2020 17:50:37 -0300 Subject: [PATCH 0443/4254] fix sendTo and recvFrom in asyncnet (#14154) * added high level sendTo and recvFrom to std/asyncnet; tests were also added. * add .since annotation, a changelog entry and fixed to standard library style guide. * Improved asserts msgs and added notes for use with UDP sockets * pointers removed in parameters and fixes * added .since annotation * minor fixes --- lib/pure/asyncnet.nim | 120 ++++++++++++----------------------- tests/async/tasyncnetudp.nim | 25 +++----- 2 files changed, 50 insertions(+), 95 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index ddfab3416..1e7c13413 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -780,8 +780,8 @@ proc isClosed*(socket: AsyncSocket): bool = ## Determines whether the socket has been closed. return socket.closed -proc sendTo*(socket: AsyncSocket, data: pointer, dataSize: int, address: string, - port: Port, flags = {SocketFlag.SafeDisconn}): owned(Future[void]) +proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string, + flags = {SocketFlag.SafeDisconn}): owned(Future[void]) {.async, since: (1, 3).} = ## This proc sends ``data`` to the specified ``address``, which may be an IP ## address or a hostname. If a hostname is specified this function will try @@ -792,13 +792,11 @@ proc sendTo*(socket: AsyncSocket, data: pointer, dataSize: int, address: string, ## ## This proc is normally used with connectionless sockets (UDP sockets). assert(socket.protocol != IPPROTO_TCP, - "Cannot `sendTo` on a TCP socket. Use `send` instead.") - assert(not socket.closed, "Cannot `sendTo` on a closed socket.") + "Cannot `sendTo` on a TCP socket. Use `send` instead") + assert(not socket.closed, "Cannot `sendTo` on a closed socket") - let - aiList = getAddrInfo(address, port, socket.domain, socket.sockType, - socket.protocol) - retFuture = newFuture[void]("sendTo") + let aiList = getAddrInfo(address, port, socket.domain, socket.sockType, + socket.protocol) var it = aiList @@ -806,7 +804,7 @@ proc sendTo*(socket: AsyncSocket, data: pointer, dataSize: int, address: string, lastException: ref Exception while it != nil: - let fut = sendTo(socket.fd.AsyncFD, data, dataSize, it.ai_addr, + let fut = sendTo(socket.fd.AsyncFD, cstring(data), len(data), it.ai_addr, it.ai_addrlen.SockLen, flags) yield fut @@ -824,88 +822,54 @@ proc sendTo*(socket: AsyncSocket, data: pointer, dataSize: int, address: string, if not success: if lastException != nil: - retFuture.fail(lastException) - + raise lastException else: - retFuture.fail(newException( - IOError, "Couldn't resolve address: " & address)) + raise newException(IOError, "Couldn't resolve address: " & address) - else: - retFuture.complete() - -proc sendTo*(socket: AsyncSocket, data, address: string, port: Port): - owned(Future[void]) {.async, since: (1, 3).} = - ## This proc sends ``data`` to the specified ``address``, which may be an IP - ## address or a hostname. If a hostname is specified this function will try - ## each IP of that hostname. The returned future will complete once all data - ## has been sent. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This proc is normally used with connectionless sockets (UDP sockets). - await sendTo(socket, cstring(data), len(data), address, port) - -proc recvFrom*(socket: AsyncSocket, data: pointer, size: int, - address: FutureVar[string], port: FutureVar[Port], - flags = {SocketFlag.SafeDisconn}): owned(Future[int]) +proc recvFrom*(socket: AsyncSocket, size: int, + flags = {SocketFlag.SafeDisconn}): + owned(Future[tuple[data: string, address: string, port: Port]]) {.async, since: (1, 3).} = - ## Receives a datagram data from ``socket`` into ``data``, which must be at - ## least of size ``size``. The address and port of datagram's sender will be - ## stored into ``address`` and ``port``, respectively. Returned future will - ## complete once one datagram has been received, and will return size of - ## packet received. + ## Receives a datagram data from ``socket``, which must be at least of size + ## ``size``. Returned future will complete once one datagram has been received + ## and will return tuple with: data of packet received; and address and port + ## of datagram's sender. ## ## If an error occurs an OSError exception will be raised. ## ## This proc is normally used with connectionless sockets (UDP sockets). - template awaitRecvFromInto() = + template adaptRecvFromToDomain(domain: Domain) = var lAddr = sizeof(sAddr).SockLen - result = await recvFromInto(AsyncFD(getFd(socket)), data, size, - cast[ptr SockAddr](addr sAddr), addr lAddr) - - address.mget.add(getAddrString(cast[ptr SockAddr](addr sAddr))) - - address.complete() + let fut = await recvFromInto(AsyncFD(getFd(socket)), cstring(data), size, + cast[ptr SockAddr](addr sAddr), addr lAddr, + flags) + data.setLen(fut) + + result.data = data + result.address = getAddrString(cast[ptr SockAddr](addr sAddr)) + + when domain == AF_INET6: + result.port = ntohs(sAddr.sin6_port).Port + else: + result.port = ntohs(sAddr.sin_port).Port + assert(socket.protocol != IPPROTO_TCP, - "Cannot `recvFrom` on a TCP socket. Use `recv` or `recvInto` instead.") - assert(not socket.closed, "Cannot `recvFrom` on a closed socket.") + "Cannot `recvFrom` on a TCP socket. Use `recv` or `recvInto` instead") + assert(not socket.closed, "Cannot `recvFrom` on a closed socket") - var readSize: int - - if socket.domain == AF_INET6: - var sAddr: Sockaddr_in6 - - awaitRecvFromInto() - - port.complete(ntohs(sAddr.sin6_port).Port) - - else: - var sAddr: Sockaddr_in - - awaitRecvFromInto() - - port.complete(ntohs(sAddr.sin_port).Port) - -proc recvFrom*(socket: AsyncSocket, data: pointer, size: int): - owned(Future[tuple[size: int, address: string, port: Port]]) - {.async, since: (1, 3).} = - ## Receives a datagram data from ``socket`` into ``data``, which must be at - ## least of size ``size``. Returned future will complete once one datagram has - ## been received and will return tuple with: size of packet received; and - ## address and port of datagram's sender. - ## - ## If an error occurs an OSError exception will be raised. - ## - ## This proc is normally used with connectionless sockets (UDP sockets). - var - fromIp = newFutureVar[string]() - fromPort = newFutureVar[Port]() + var data = newString(size) - result.size = await recvFrom(socket, data, size, fromIp, fromPort) - result.address = fromIp.mget() - result.port = fromPort.mget() + case socket.domain + of AF_INET6: + var sAddr: Sockaddr_in6 + adaptRecvFromToDomain(AF_INET6) + of AF_INET: + var sAddr: Sockaddr_in + adaptRecvFromToDomain(AF_INET) + else: + raise newException(ValueError, "Unknown socket address family") when not defined(testing) and isMainModule: type diff --git a/tests/async/tasyncnetudp.nim b/tests/async/tasyncnetudp.nim index bb0f244e5..3494def37 100644 --- a/tests/async/tasyncnetudp.nim +++ b/tests/async/tasyncnetudp.nim @@ -21,9 +21,7 @@ proc saveReceivedPort(port: Port) = recvports = recvports + int(port) proc launchSwarm(serverIp: string, serverPort: Port) {.async.} = - var - buffer = newString(16384) - i = 0 + var i = 0 while i < swarmSize: var sock = newAsyncSocket(nativesockets.AF_INET, nativesockets.SOCK_DGRAM, @@ -36,16 +34,13 @@ proc launchSwarm(serverIp: string, serverPort: Port) {.async.} = var k = 0 while k < messagesToSend: - zeroMem(addr(buffer[0]), 16384) - let message = "Message " & $(i * messagesToSend + k) - await sendTo(sock, message, serverIp, serverPort) + await asyncnet.sendTo(sock, serverIp, serverPort, message) - let (size, fromIp, fromPort) = await recvFrom(sock, addr buffer[0], - 16384) + let (data, fromIp, fromPort) = await recvFrom(sock, 16384) - if buffer[0 .. (size - 1)] == message: + if data == message: saveSendingPort(localPort) inc(recvCount) @@ -59,17 +54,13 @@ proc launchSwarm(serverIp: string, serverPort: Port) {.async.} = proc readMessages(server: AsyncSocket) {.async.} = let maxResponses = (swarmSize * messagesToSend) - var - buffer = newString(16384) - i = 0 + var i = 0 while i < maxResponses: - zeroMem(addr(buffer[0]), 16384) - - let (size, fromIp, fromPort) = await recvFrom(server, addr buffer[0], 16384) + let (data, fromIp, fromPort) = await recvFrom(server, 16384) - if buffer.startswith("Message ") and fromIp == "127.0.0.1": - await sendTo(server, buffer[0 .. (size - 1)], fromIp, fromPort) + if data.startswith("Message ") and fromIp == "127.0.0.1": + await sendTo(server, fromIp, fromPort, data) inc(msgCount) From d5fc35c968c49c6f5529624108ed327095a548c4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 1 May 2020 09:15:46 +0200 Subject: [PATCH 0444/4254] arc: do not unload globals when building a library [backport:1.2] (#14180) --- compiler/cgen.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 274f01ad7..a5ee6c7ca 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2019,8 +2019,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil: discard cgsym(m, "nimTestErrorFlag") - for i in countdown(high(graph.globalDestructors), 0): - n.add graph.globalDestructors[i] + if {optGenStaticLib, optGenDynLib} * m.config.globalOptions == {}: + for i in countdown(high(graph.globalDestructors), 0): + n.add graph.globalDestructors[i] if passes.skipCodegen(m.config, n): return if moduleHasChanged(graph, m.module): # if the module is cached, we don't regenerate the main proc From 9b01c6cf48de5bac8abd32f0327c729d177be653 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Fri, 1 May 2020 10:49:13 +0300 Subject: [PATCH 0445/4254] discardable async procs are now an error (#14176) * add discard warning in manual --- doc/manual.rst | 3 ++- lib/pure/asyncmacro.nim | 22 ++++++++++++++-------- tests/async/tdiscardableproc.nim | 9 +++++++++ tests/vm/tslow_tables.nim | 2 +- 4 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 tests/async/tdiscardableproc.nim diff --git a/doc/manual.rst b/doc/manual.rst index 3933a9297..f1b0ae77a 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2568,7 +2568,8 @@ Example: discard p(3, 4) # discard the return value of `p` The ``discard`` statement evaluates its expression for side-effects and -throws the expression's resulting value away. +throws the expression's resulting value away, and should only be used +when ignoring this value is known not to cause problems. Ignoring the return value of a procedure without using a discard statement is a static error. diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 9b05c65dc..afc28bbdf 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -112,7 +112,7 @@ proc getName(node: NimNode): string {.compileTime.} = of nnkEmpty: return "anonymous" else: - error("Unknown name.") + error("Unknown name.", node) proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} = result = @[] @@ -125,10 +125,10 @@ proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} = proc isInvalidReturnType(typeName: string): bool = return typeName notin ["Future"] #, "FutureStream"] -proc verifyReturnType(typeName: string) {.compileTime.} = +proc verifyReturnType(typeName: string, node: NimNode = nil) {.compileTime.} = if typeName.isInvalidReturnType: error("Expected return type of 'Future' got '$1'" % - typeName) + typeName, node) proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. @@ -141,7 +141,13 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: error("Cannot transform this node kind into an async proc." & - " proc/method definition or lambda node expected.") + " proc/method definition or lambda node expected.", prc) + + if prc[4].kind != nnkEmpty: + for prag in prc[4]: + if prag.eqIdent("discardable"): + error("Cannot make async proc discardable. Futures have to be " & + "checked with `asyncCheck` instead of discarded", prag) let prcName = prc.name.getName @@ -153,16 +159,16 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # Verify that the return type is a Future[T] if returnType.kind == nnkBracketExpr: let fut = repr(returnType[0]) - verifyReturnType(fut) + verifyReturnType(fut, returnType[0]) baseType = returnType[1] elif returnType.kind in nnkCallKinds and returnType[0].eqIdent("[]"): let fut = repr(returnType[1]) - verifyReturnType(fut) + verifyReturnType(fut, returnType[0]) baseType = returnType[2] elif returnType.kind == nnkEmpty: baseType = returnType else: - verifyReturnType(repr(returnType)) + verifyReturnType(repr(returnType), returntype) let subtypeIsVoid = returnType.kind == nnkEmpty or (baseType.kind == nnkIdent and returnType[1].eqIdent("void")) @@ -303,7 +309,7 @@ proc stripReturnType(returnType: NimNode): NimNode = result = returnType if returnType.kind == nnkBracketExpr: let fut = repr(returnType[0]) - verifyReturnType(fut) + verifyReturnType(fut, returnType) result = returnType[1] proc splitProc(prc: NimNode): (NimNode, NimNode) = diff --git a/tests/async/tdiscardableproc.nim b/tests/async/tdiscardableproc.nim new file mode 100644 index 000000000..80286ece0 --- /dev/null +++ b/tests/async/tdiscardableproc.nim @@ -0,0 +1,9 @@ +discard """ + errmsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded" +""" + +import async + +proc foo {.async, discardable.} = discard + +foo() diff --git a/tests/vm/tslow_tables.nim b/tests/vm/tslow_tables.nim index a933021e0..37351bfe2 100644 --- a/tests/vm/tslow_tables.nim +++ b/tests/vm/tslow_tables.nim @@ -26,5 +26,5 @@ proc hop(): bool = echo "done" -const r = hop() +const r {.used.} = hop() From 9c33bcac5c73f8188e1c017ba8b2a14db5d5a4fe Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 1 May 2020 15:54:03 +0200 Subject: [PATCH 0446/4254] change 'iff' to 'if' to stop "corrections" once and for all (#14182) --- lib/posix/posix_haiku.nim | 6 +++--- lib/posix/posix_macos_amd64.nim | 6 +++--- lib/posix/posix_openbsd_amd64.nim | 6 +++--- lib/posix/posix_other.nim | 6 +++--- lib/pure/collections/critbits.nim | 8 ++++---- lib/pure/collections/sharedtables.nim | 2 +- lib/pure/cstrutils.nim | 16 ++++++++-------- lib/pure/os.nim | 10 +++++----- lib/pure/osproc.nim | 2 +- lib/pure/typetraits.nim | 2 +- lib/system/channels.nim | 2 +- lib/system/io.nim | 8 ++++---- 12 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/posix/posix_haiku.nim b/lib/posix/posix_haiku.nim index bb430a8f3..eaf2cfb85 100644 --- a/lib/posix/posix_haiku.nim +++ b/lib/posix/posix_haiku.nim @@ -585,11 +585,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, iff WIFEXITED(s) + ## Exit code, if WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, iff WIFSIGNALED(s) + ## Termination signal, if WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, iff WIFSTOPPED(s) + ## Stop signal, if WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 304993dcb..33f2c5c41 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -595,11 +595,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, iff WIFEXITED(s) + ## Exit code, if WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, iff WIFSIGNALED(s) + ## Termination signal, if WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, iff WIFSTOPPED(s) + ## Stop signal, if WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 1ff636517..4f34791fe 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -543,11 +543,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, iff WIFEXITED(s) + ## Exit code, if WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, iff WIFSIGNALED(s) + ## Termination signal, if WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, iff WIFSTOPPED(s) + ## Stop signal, if WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 204cc3d9a..919d564d3 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -600,11 +600,11 @@ when hasSpawnH: # proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} - ## Exit code, iff WIFEXITED(s) + ## Exit code, if WIFEXITED(s) proc WTERMSIG*(s: cint): cint {.importc, header: "".} - ## Termination signal, iff WIFSIGNALED(s) + ## Termination signal, if WIFSIGNALED(s) proc WSTOPSIG*(s: cint): cint {.importc, header: "".} - ## Stop signal, iff WIFSTOPPED(s) + ## Stop signal, if WIFSTOPPED(s) proc WIFEXITED*(s: cint): bool {.importc, header: "".} ## True if child exited normally. proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 8128877bd..21c749afe 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -54,7 +54,7 @@ proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = return if it.key == key: it else: nil proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = - ## Returns true iff `c` contains the given `key`. + ## Returns true if `c` contains the given `key`. runnableExamples: var c: CritBitTree[void] incl(c, "key") @@ -156,7 +156,7 @@ proc excl*[T](c: var CritBitTree[T], key: string) = discard exclImpl(c, key) proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = - ## Returns true iff `c` does not contain the given `key`. If the key + ## Returns true if `c` does not contain the given `key`. If the key ## does exist, c.excl(key) is performed. ## ## See also: @@ -178,7 +178,7 @@ proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = result = c.count == oldCount proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = - ## Returns true iff `c` contains the given `key`. If the key does not exist + ## Returns true if `c` contains the given `key`. If the key does not exist ## ``c[key] = val`` is performed. ## ## See also: @@ -204,7 +204,7 @@ proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = if not result: n.val = val proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = - ## Returns true iff `c` contains the given `key`. If the key does not exist + ## Returns true if `c` contains the given `key`. If the key does not exist ## it is inserted into `c`. ## ## See also: diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index cad9ca2c1..23b653c82 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -134,7 +134,7 @@ proc mgetOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): var B = mgetOrPutImpl(enlarge) proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool = - ## returns true iff `key` is in the table, otherwise inserts `value`. + ## returns true if `key` is in the table, otherwise inserts `value`. withLock t: hasKeyOrPutImpl(enlarge) diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index a2a8fbc2f..345a9be7f 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -31,7 +31,7 @@ when defined(js): else: proc startsWith*(s, prefix: cstring): bool {.noSideEffect, rtl, extern: "csuStartsWith".} = - ## Returns true iff ``s`` starts with ``prefix``. + ## Returns true if ``s`` starts with ``prefix``. ## ## If ``prefix == ""`` true is returned. ## @@ -44,7 +44,7 @@ else: proc endsWith*(s, suffix: cstring): bool {.noSideEffect, rtl, extern: "csuEndsWith".} = - ## Returns true iff ``s`` ends with ``suffix``. + ## Returns true if ``s`` ends with ``suffix``. ## ## If ``suffix == ""`` true is returned. ## @@ -64,9 +64,9 @@ proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, ## NOT be used to compare Nim identifier names. use `macros.eqIdent` ## for that. Returns: ## - ## | 0 iff a == b - ## | < 0 iff a < b - ## | > 0 iff a > b + ## | 0 if a == b + ## | < 0 if a < b + ## | > 0 if a > b ## ## Not supported for JS backend, use `strutils.cmpIgnoreStyle ## `_ instead. @@ -86,9 +86,9 @@ proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, rtl, extern: "csuCmpIgnoreCase".} = ## Compares two strings in a case insensitive manner. Returns: ## - ## | 0 iff a == b - ## | < 0 iff a < b - ## | > 0 iff a > b + ## | 0 if a == b + ## | < 0 if a < b + ## | > 0 if a > b ## ## Not supported for JS backend, use `strutils.cmpIgnoreCase ## `_ instead. diff --git a/lib/pure/os.nim b/lib/pure/os.nim index b46205419..73fa76fbb 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -797,9 +797,9 @@ proc cmpPaths*(pathA, pathB: string): int {. ## On a case-sensitive filesystem this is done ## case-sensitively otherwise case-insensitively. Returns: ## - ## | 0 iff pathA == pathB - ## | < 0 iff pathA < pathB - ## | > 0 iff pathA > pathB + ## | 0 if pathA == pathB + ## | < 0 if pathA < pathB + ## | > 0 if pathA > pathB runnableExamples: when defined(macosx): assert cmpPaths("foo", "Foo") == 0 @@ -1108,7 +1108,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], noNimScript.} = - ## Returns true iff the directory `dir` exists. If `dir` is a file, false + ## Returns true if the directory `dir` exists. If `dir` is a file, false ## is returned. Follows symlinks. ## ## See also: @@ -1128,7 +1128,7 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect] proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], noNimScript.} = - ## Returns true iff the symlink `link` exists. Will return true + ## Returns true if the symlink `link` exists. Will return true ## regardless of whether the link points to a directory or file. ## ## See also: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index ed5ab7b97..b0f15e38e 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -199,7 +199,7 @@ proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## * `terminate proc <#terminate,Process>`_ proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} - ## Returns true iff the process `p` is still running. Returns immediately. + ## Returns true if the process `p` is still running. Returns immediately. proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = ## Returns `p`'s process ID. diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 2570afbf8..280233912 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -59,7 +59,7 @@ proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} ## them unmodified. proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".} - ## This trait returns true iff the type ``t`` is safe to use for + ## This trait returns true if the type ``t`` is safe to use for ## `copyMem`:idx:. ## ## Other languages name a type like these `blob`:idx:. diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 834694626..e4b172c16 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -448,7 +448,7 @@ proc close*[TMsg](c: var Channel[TMsg]) = deinitRawChannel(addr(c)) proc ready*[TMsg](c: var Channel[TMsg]): bool = - ## Returns true iff some thread is waiting on the channel `c` for + ## Returns true if some thread is waiting on the channel `c` for ## new messages. var q = cast[PRawChannel](addr(c)) result = q.ready diff --git a/lib/system/io.nim b/lib/system/io.nim index f8358962f..efa2f9475 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -460,7 +460,7 @@ proc rawFileSize(file: File): int64 = discard c_fseek(file, oldPos, 0) proc endOfFile*(f: File): bool {.tags: [], benign.} = - ## Returns true iff `f` is at the end. + ## Returns true if `f` is at the end. var c = c_fgetc(f) discard c_ungetc(c, f) return c < 0'i32 @@ -598,7 +598,7 @@ proc open*(f: var File, filename: string, bufSize: int = -1): bool {.tags: [], raises: [], benign.} = ## Opens a file named `filename` with given `mode`. ## - ## Default mode is readonly. Returns true iff the file could be opened. + ## Default mode is readonly. Returns true if the file could be opened. ## This throws no exception if the file could not be opened. ## ## The file handle associated with the resulting ``File`` is not inheritable. @@ -632,7 +632,7 @@ proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. ## is often used to redirect the `stdin`, `stdout` or `stderr` ## file variables. ## - ## Default mode is readonly. Returns true iff the file could be reopened. + ## Default mode is readonly. Returns true if the file could be reopened. ## ## The file handle associated with `f` won't be inheritable. if freopen(filename, FormatOpen[mode], f) != nil: @@ -647,7 +647,7 @@ proc open*(f: var File, filehandle: FileHandle, mode: FileMode = fmRead): bool {.tags: [], raises: [], benign.} = ## Creates a ``File`` from a `filehandle` with given `mode`. ## - ## Default mode is readonly. Returns true iff the file could be opened. + ## Default mode is readonly. Returns true if the file could be opened. ## ## The passed file handle will no longer be inheritable. when not defined(nimInheritHandles) and declared(setInheritable): From 1f1e4de3bc45382ef6674706ef5292bd3c8215a1 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 1 May 2020 20:25:18 +0200 Subject: [PATCH 0447/4254] Make ./koch temp --gc:arc work (#14186) --- compiler/cgen.nim | 5 ++++- compiler/depends.nim | 5 ++++- compiler/sem.nim | 7 +++++-- compiler/semcall.nim | 2 +- compiler/seminst.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/sigmatch.nim | 5 ++++- compiler/vm.nim | 9 ++++++--- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a5ee6c7ca..9e356206f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1824,7 +1824,10 @@ template injectG() {.dirty.} = graph.backend = newModuleList(graph) let g = BModuleList(graph.backend) -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = +when not defined(nimHasSinkInference): + {.pragma: nosinks.} + +proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = injectG() result = newModule(g, module, graph.config) if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: diff --git a/compiler/depends.nim b/compiler/depends.nim index 3d252c2a2..cc385da4b 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -51,7 +51,10 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) = rope(project.splitFile.name), b.dotGraph], changeFileExt(project, "dot")) -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = +when not defined(nimHasSinkInference): + {.pragma: nosinks.} + +proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = var g: PGen new(g) g.module = module diff --git a/compiler/sem.nim b/compiler/sem.nim index aa5928c18..62e3ca8db 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -377,6 +377,9 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode = evaluated = evalAtCompileTime(c, result) if evaluated != nil: return evaluated +when not defined(nimHasSinkInference): + {.pragma: nosinks.} + include hlo, seminst, semcall when false: @@ -501,7 +504,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) = n.add prc.ast c.lastGenericIdx = c.generics.len -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = var c = newContext(graph, module) if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") c.semConstExpr = semConstExpr @@ -592,7 +595,7 @@ proc recoverContext(c: PContext) = while getCurrOwner(c).kind != skModule: popOwner(c) while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next -proc myProcess(context: PPassContext, n: PNode): PNode = +proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = var c = PContext(context) # no need for an expensive 'try' if we stop after the first error anyway: if c.config.errorMax <= 1: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index ab28c21b2..c6e12facf 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -549,7 +549,7 @@ proc tryDeref(n: PNode): PNode = result.add n proc semOverloadedCall(c: PContext, n, nOrig: PNode, - filter: TSymKinds, flags: TExprFlags): PNode = + filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} = var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) if r.state == csMatch: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 605ddfafa..fa338956d 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -320,7 +320,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, popInfoContext(c.config) proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, - info: TLineInfo): PSym = + info: TLineInfo): PSym {.nosinks.} = ## Generates a new instance of a generic procedure. ## The `pt` parameter is a type-unsafe mapping table used to link generic ## parameters to their concrete types within the generic instance. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 986953ab2..6ebe5723e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1594,7 +1594,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) -proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = +proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} = var n = n let original = n[namePos].sym diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e209f5d78..a581e20f9 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2584,8 +2584,11 @@ proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool = # pattern templates do not allow for conversions except from int literal res != nil and m.convMatches == 0 and m.intConvMatches in [0, 256] +when not defined(nimHasSinkInference): + {.pragma: nosinks.} + proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; - op: TTypeAttachedOp; col: int): PSym = + op: TTypeAttachedOp; col: int): PSym {.nosinks.} = var m = newCandidate(c, dc.typ) if col >= dc.typ.len: localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") diff --git a/compiler/vm.nim b/compiler/vm.nim index 37d5a609e..3ac075f81 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -527,6 +527,9 @@ template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool = else: false +when not defined(nimHasSinkInference): + {.pragma: nosinks.} + proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -1722,7 +1725,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var error: string let ast = parseString(regs[rb].node.strVal, c.cache, c.config, toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, - proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = + proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) if error.len > 0: @@ -1737,7 +1740,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var error: string let ast = parseString(regs[rb].node.strVal, c.cache, c.config, toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, - proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = + proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) if error.len > 0: @@ -2137,7 +2140,7 @@ proc setupGlobalCtx*(module: PSym; graph: ModuleGraph) = else: refresh(PCtx graph.vm, module) -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = #var c = newEvalContext(module, emRepl) #c.features = {allowCast, allowInfiniteLoops} #pushStackFrame(c, newStackFrame()) From 83547ec769d9c55b47a8d7a9e3cfc79aab09f977 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 2 May 2020 16:09:02 +0200 Subject: [PATCH 0448/4254] Make unreachable else in case statements a warning instead of an error (#14190) * Fix #14019 by making trailing else a warning * Rename to UnreachableElse --- compiler/lineinfos.nim | 5 +++-- compiler/semstmts.nim | 2 +- compiler/semtypes.nim | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 9c10105b1..eea55defc 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -39,7 +39,7 @@ type warnEachIdentIsTuple, warnUnsafeSetLen, warnUnsafeDefault, - warnProveInit, warnProveField, warnProveIndex, + warnProveInit, warnProveField, warnProveIndex, warnUnreachableElse, warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser, @@ -96,6 +96,7 @@ const warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", warnProveField: "cannot prove that field '$1' is accessible", warnProveIndex: "cannot prove index '$1' is valid", + warnUnreachableElse: "unreachable else, all cases are already covered", warnStaticIndexCheck: "$1", warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", @@ -153,7 +154,7 @@ const "UnsafeCode", "UnusedImport", "InheritFromException", "EachIdentIsTuple", "UnsafeSetLen", "UnsafeDefault", - "ProveInit", "ProveField", "ProveIndex", + "ProveInit", "ProveField", "ProveIndex", "UnreachableElse", "IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "ResultShadowed", "Spacing", "CaseTransition", "CycleCreated", "User"] diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6ebe5723e..22055a33d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -998,7 +998,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode = x[0] = semExprBranchScope(c, x[0]) typ = commonType(typ, x[0]) if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse: - localError(c.config, x.info, "invalid else, all cases are already covered") + message(c.config, x.info, warnUnreachableElse) hasElse = true chckCovered = false else: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e6cbe56e8..a069fba60 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -695,7 +695,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, of nkElse: checkSonsLen(b, 1, c.config) if chckCovered and covered == toCover(c, a[0].typ): - localError(c.config, b.info, "invalid else, all cases are already covered") + message(c.config, b.info, warnUnreachableElse) chckCovered = false else: illFormedAst(n, c.config) delSon(b, b.len - 1) From 0880f118d377f05067ddcdcf7788d2706c5f0c3a Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Sat, 2 May 2020 11:50:27 -0400 Subject: [PATCH 0449/4254] Document that proc named fooTask is created for every foo task [backport] (#14187) Ref: https://irclogs.nim-lang.org/01-05-2020.html#15:18:03 --- lib/system/nimscript.nim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 5b8622182..da5c291fa 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -379,11 +379,26 @@ when not defined(nimble): template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 template task*(name: untyped; description: string; body: untyped): untyped = ## Defines a task. Hidden tasks are supported via an empty description. + ## ## Example: ## ## .. code-block:: nim ## task build, "default build is via the C backend": ## setCommand "c" + ## + ## For a task named ``foo``, this template generates a ``proc`` named + ## ``fooTask``. This is useful if you need to call one task in + ## another in your Nimscript. + ## + ## Example: + ## + ## .. code-block:: nim + ## task foo, "foo": # > nim foo + ## echo "Running foo" # Running foo + ## + ## task bar, "bar": # > nim bar + ## echo "Running bar" # Running bar + ## fooTask() # Running foo proc `name Task`*() = setCommand "nop" body From f50377986a6ed9d63a91daf9395fb210021fbc6f Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sat, 2 May 2020 23:30:08 +0300 Subject: [PATCH 0450/4254] exp. features now in correct manual, closes #11932 (#14195) --- doc/manual.rst | 170 +------------------- doc/manual_experimental.rst | 185 +++++++++++++++++++++- tests/overload/tnamedparamoverloading.nim | 14 ++ 3 files changed, 198 insertions(+), 171 deletions(-) create mode 100644 tests/overload/tnamedparamoverloading.nim diff --git a/doc/manual.rst b/doc/manual.rst index f1b0ae77a..85b307c80 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1734,22 +1734,9 @@ dereferencing operations for reference types: n.data = 9 # no need to write n[].data; in fact n[].data is highly discouraged! -Automatic dereferencing is also performed for the first argument of a routine -call. But currently this feature has to be only enabled -via ``{.experimental: "implicitDeref".}``: - -.. code-block:: nim - {.experimental: "implicitDeref".} - - proc depth(x: NodeObj): int = ... - - var - n: Node - new(n) - echo n.depth - # no need to write n[].depth either - - +Automatic dereferencing can be performed for the first argument of a routine +call, but this is an experimental feature and is described `here +`_. In order to simplify structural type checking, recursive tuples are not valid: @@ -5341,52 +5328,6 @@ powerful programming construct that still suffices. So the "check list" is: (4) Else: Use a macro. -For Loop Macro --------------- - -A macro that takes as its only input parameter an expression of the special -type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: - -.. code-block:: nim - :test: "nim c $1" - - import macros - {.experimental: "forLoopMacros".} - - macro enumerate(x: ForLoopStmt): untyped = - expectKind x, nnkForStmt - # we strip off the first for loop variable and use - # it as an integer counter: - result = newStmtList() - result.add newVarStmt(x[0], newLit(0)) - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - body.add newCall(bindSym"inc", x[0]) - var newFor = newTree(nnkForStmt) - for i in 1..x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][1] - newFor.add body - result.add newFor - # now wrap the whole macro in a block to create a new scope - result = quote do: - block: `result` - - for a, b in enumerate(items([1, 2, 3])): - echo a, " ", b - - # without wrapping the macro in a block, we'd need to choose different - # names for `a` and `b` here to avoid redefinition errors - for a, b in enumerate([1, 2, 3, 5]): - echo a, " ", b - - -Currently for loop macros must be enabled explicitly -via ``{.experimental: "forLoopMacros".}``. - - Special Types ============= @@ -5822,111 +5763,6 @@ iterator in which case the overloading resolution takes place: var x = 4 write(stdout, x) # not ambiguous: uses the module C's x -Code reordering -~~~~~~~~~~~~~~~ - -**Note**: Code reordering is experimental and must be enabled via the -``{.experimental.}`` pragma. - -The code reordering feature can implicitly rearrange procedure, template, and -macro definitions along with variable declarations and initializations at the top -level scope so that, to a large extent, a programmer should not have to worry -about ordering definitions correctly or be forced to use forward declarations to -preface definitions inside a module. - -.. - NOTE: The following was documentation for the code reordering precursor, - which was {.noForward.}. - - In this mode, procedure definitions may appear out of order and the compiler - will postpone their semantic analysis and compilation until it actually needs - to generate code using the definitions. In this regard, this mode is similar - to the modus operandi of dynamic scripting languages, where the function - calls are not resolved until the code is executed. Here is the detailed - algorithm taken by the compiler: - - 1. When a callable symbol is first encountered, the compiler will only note - the symbol callable name and it will add it to the appropriate overload set - in the current scope. At this step, it won't try to resolve any of the type - expressions used in the signature of the symbol (so they can refer to other - not yet defined symbols). - - 2. When a top level call is encountered (usually at the very end of the - module), the compiler will try to determine the actual types of all of the - symbols in the matching overload set. This is a potentially recursive process - as the signatures of the symbols may include other call expressions, whose - types will be resolved at this point too. - - 3. Finally, after the best overload is picked, the compiler will start - compiling the body of the respective symbol. This in turn will lead the - compiler to discover more call expressions that need to be resolved and steps - 2 and 3 will be repeated as necessary. - - Please note that if a callable symbol is never used in this scenario, its - body will never be compiled. This is the default behavior leading to best - compilation times, but if exhaustive compilation of all definitions is - required, using ``nim check`` provides this option as well. - -Example: - -.. code-block:: nim - - {.experimental: "codeReordering".} - - proc foo(x: int) = - bar(x) - - proc bar(x: int) = - echo(x) - - foo(10) - -Variables can also be reordered as well. Variables that are *initialized* (i.e. -variables that have their declaration and assignment combined in a single -statement) can have their entire initialization statement reordered. Be wary of -what code is executed at the top level: - -.. code-block:: nim - {.experimental: "codeReordering".} - - proc a() = - echo(foo) - - var foo = 5 - - a() # outputs: "5" - -.. - TODO: Let's table this for now. This is an *experimental feature* and so the - specific manner in which ``declared`` operates with it can be decided in - eventuality, because right now it works a bit weirdly. - - The values of expressions involving ``declared`` are decided *before* the - code reordering process, and not after. As an example, the output of this - code is the same as it would be with code reordering disabled. - - .. code-block:: nim - {.experimental: "codeReordering".} - - proc x() = - echo(declared(foo)) - - var foo = 4 - - x() # "false" - -It is important to note that reordering *only* works for symbols at top level -scope. Therefore, the following will *fail to compile:* - -.. code-block:: nim - {.experimental: "codeReordering".} - - proc a() = - b() - proc b() = - echo("Hello!") - - a() Compiler Messages ================= diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 70bb225fa..45732fae2 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -203,10 +203,122 @@ useful only when interfacing with imported types having such semantics. Automatic dereferencing ======================= -If the `experimental mode `_ is active -and no other match is found, the first argument ``a`` is dereferenced -automatically if it's a pointer type and overloading resolution is tried -with ``a[]`` instead. +Automatic dereferencing is performed for the first argument of a routine call. +This feature has to be only enabled via ``{.experimental: "implicitDeref".}``: + +.. code-block:: nim + {.experimental: "implicitDeref".} + + proc depth(x: NodeObj): int = ... + + var + n: Node + new(n) + echo n.depth + # no need to write n[].depth either + +Code reordering +=============== + +The code reordering feature can implicitly rearrange procedure, template, and +macro definitions along with variable declarations and initializations at the top +level scope so that, to a large extent, a programmer should not have to worry +about ordering definitions correctly or be forced to use forward declarations to +preface definitions inside a module. + +.. + NOTE: The following was documentation for the code reordering precursor, + which was {.noForward.}. + + In this mode, procedure definitions may appear out of order and the compiler + will postpone their semantic analysis and compilation until it actually needs + to generate code using the definitions. In this regard, this mode is similar + to the modus operandi of dynamic scripting languages, where the function + calls are not resolved until the code is executed. Here is the detailed + algorithm taken by the compiler: + + 1. When a callable symbol is first encountered, the compiler will only note + the symbol callable name and it will add it to the appropriate overload set + in the current scope. At this step, it won't try to resolve any of the type + expressions used in the signature of the symbol (so they can refer to other + not yet defined symbols). + + 2. When a top level call is encountered (usually at the very end of the + module), the compiler will try to determine the actual types of all of the + symbols in the matching overload set. This is a potentially recursive process + as the signatures of the symbols may include other call expressions, whose + types will be resolved at this point too. + + 3. Finally, after the best overload is picked, the compiler will start + compiling the body of the respective symbol. This in turn will lead the + compiler to discover more call expressions that need to be resolved and steps + 2 and 3 will be repeated as necessary. + + Please note that if a callable symbol is never used in this scenario, its + body will never be compiled. This is the default behavior leading to best + compilation times, but if exhaustive compilation of all definitions is + required, using ``nim check`` provides this option as well. + +Example: + +.. code-block:: nim + + {.experimental: "codeReordering".} + + proc foo(x: int) = + bar(x) + + proc bar(x: int) = + echo(x) + + foo(10) + +Variables can also be reordered as well. Variables that are *initialized* (i.e. +variables that have their declaration and assignment combined in a single +statement) can have their entire initialization statement reordered. Be wary of +what code is executed at the top level: + +.. code-block:: nim + {.experimental: "codeReordering".} + + proc a() = + echo(foo) + + var foo = 5 + + a() # outputs: "5" + +.. + TODO: Let's table this for now. This is an *experimental feature* and so the + specific manner in which ``declared`` operates with it can be decided in + eventuality, because right now it works a bit weirdly. + + The values of expressions involving ``declared`` are decided *before* the + code reordering process, and not after. As an example, the output of this + code is the same as it would be with code reordering disabled. + + .. code-block:: nim + {.experimental: "codeReordering".} + + proc x() = + echo(declared(foo)) + + var foo = 4 + + x() # "false" + +It is important to note that reordering *only* works for symbols at top level +scope. Therefore, the following will *fail to compile:* + +.. code-block:: nim + {.experimental: "codeReordering".} + + proc a() = + b() + proc b() = + echo("Hello!") + + a() Automatic self insertions @@ -245,6 +357,25 @@ if no other interpretation of the call is possible: echo self, self.childField, " ", sumFields(self) +Named argument overloading +========================== + +Routines with the same type signature can be called differently if a parameter +has different names. This does not need an ``experimental`` switch, but is an +unstable feature. + +.. code-block::nim + proc foo(x: int) = + echo "Using x: ", x + proc foo(y: int) = + echo "Using y: ", y + + foo(x = 2) + # Using x: 2 + foo(y = 2) + # Using y: 2 + + Do notation =========== @@ -899,6 +1030,52 @@ but only the statement's selector expression is used to determine which macro to call. +For loop macros +--------------- + +A macro that takes as its only input parameter an expression of the special +type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: + +.. code-block:: nim + :test: "nim c $1" + + import macros + {.experimental: "forLoopMacros".} + + macro enumerate(x: ForLoopStmt): untyped = + expectKind x, nnkForStmt + # we strip off the first for loop variable and use + # it as an integer counter: + result = newStmtList() + result.add newVarStmt(x[0], newLit(0)) + var body = x[^1] + if body.kind != nnkStmtList: + body = newTree(nnkStmtList, body) + body.add newCall(bindSym"inc", x[0]) + var newFor = newTree(nnkForStmt) + for i in 1..x.len-3: + newFor.add x[i] + # transform enumerate(X) to 'X' + newFor.add x[^2][1] + newFor.add body + result.add newFor + # now wrap the whole macro in a block to create a new scope + result = quote do: + block: `result` + + for a, b in enumerate(items([1, 2, 3])): + echo a, " ", b + + # without wrapping the macro in a block, we'd need to choose different + # names for `a` and `b` here to avoid redefinition errors + for a, b in enumerate([1, 2, 3, 5]): + echo a, " ", b + + +Currently for loop macros must be enabled explicitly +via ``{.experimental: "forLoopMacros".}``. + + Term rewriting macros ===================== diff --git a/tests/overload/tnamedparamoverloading.nim b/tests/overload/tnamedparamoverloading.nim new file mode 100644 index 000000000..a7c37ba52 --- /dev/null +++ b/tests/overload/tnamedparamoverloading.nim @@ -0,0 +1,14 @@ +discard """ + output: ''' +Using x: 2 +Using y: 2 +''' +""" + +proc foo(x: int) = + echo "Using x: ", x +proc foo(y: int) = + echo "Using y: ", y + +foo(x = 2) +foo(y = 2) \ No newline at end of file From 15f54728ef3ac639a96c917799b194418dff3874 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 1 May 2020 10:28:54 +0200 Subject: [PATCH 0451/4254] fixes a bug encountered when running 'nim check posix_haiku.nim' --- compiler/semtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index a069fba60..275ad8a07 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -723,7 +723,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, checkSonsLen(it, 2, c.config) if c.inGenericContext == 0: var e = semConstBoolExpr(c, it[0]) - if e.kind != nkIntLit: internalError(c.config, e.info, "semRecordNodeAux") + if e.kind != nkIntLit: discard "don't report followup error" elif e.intVal != 0 and branch == nil: branch = it[1] else: it[0] = forceBool(c, semExprWithType(c, it[0])) From 8e04ef3c0fd1316f1a59c6a6379645e0365a52f2 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 1 May 2020 15:49:05 +0200 Subject: [PATCH 0452/4254] closes #14142 --- tests/test_nimscript.nims | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 0b454ad1c..2325d96cb 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -11,7 +11,7 @@ import std/[ # Algorithms: algorithm, sequtils, - + # Collections: critbits, deques, heapqueue, intsets, lists, options, sets, sharedlist, tables, @@ -40,7 +40,7 @@ import std/[ # fails: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, # asyncnet, cgi, cookies, httpclient, nativesockets, net, selectors, smtp # works but shouldn't test: asyncstreams, asyncfutures - + # Threading: # fails: threadpool @@ -73,4 +73,11 @@ import std/[ block: doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath +block: # #14142 + discard existsDir("/usr") + discard dirExists("/usr") + discard existsFile("/usr/foo") + discard fileExists("/usr/foo") + discard findExe("nim") + echo "Nimscript imports are successful." From 7bac6f5f9af3c5c8190b81d5eded9df6b11cf5cb Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 1 May 2020 18:20:36 +0200 Subject: [PATCH 0453/4254] don't close #14142 --- tests/test_nimscript.nims | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 2325d96cb..a2e8ac945 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -73,7 +73,7 @@ import std/[ block: doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath -block: # #14142 +when false: # #14142 discard existsDir("/usr") discard dirExists("/usr") discard existsFile("/usr/foo") From 4301a7bdf06159501f8affc3e7f8de80a196cd4f Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 1 May 2020 18:57:45 +0200 Subject: [PATCH 0454/4254] fixes #14177 --- compiler/sempass2.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 0fdf25850..e1521475a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -829,8 +829,9 @@ proc track(tracked: PEffects, n: PNode) = if op != nil: n[0].sym = op - for i in 0.. Date: Sat, 2 May 2020 13:37:57 +0200 Subject: [PATCH 0455/4254] fixes #14159 [backport:1.2] --- compiler/dfa.nim | 4 +++- tests/destructor/tcycle3.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index e4cadde5b..0cefec285 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -639,8 +639,10 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = of nkHiddenDeref, nkDerefExpr: # We "own" sinkparam[].loc but not ourVar[].location as it is a nasty # pointer indirection. + # bug #14159, we cannot reason about sinkParam[].location as it can + # still be shared for tyRef. n = n[0] - return n.kind == nkSym and n.sym.owner == owner and (isSinkParam(n.sym) or + return n.kind == nkSym and n.sym.owner == owner and ( n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned}) else: break diff --git a/tests/destructor/tcycle3.nim b/tests/destructor/tcycle3.nim index 584321bab..8662136e7 100644 --- a/tests/destructor/tcycle3.nim +++ b/tests/destructor/tcycle3.nim @@ -2,6 +2,8 @@ discard """ output: '''BEGIN END END 2 +cpu.nes false +cpu step nes is nil? - false 0''' cmd: '''nim c --gc:orc $file''' """ @@ -59,7 +61,38 @@ proc main = c.run echo "END 2" +# bug #14159 +type + NES = ref object + cpu: CPU + apu: APU + + CPU = ref object + nes: NES + + APU = object + nes: NES + cpu: CPU + +proc initAPU(nes: sink NES): APU {.nosinks.} = + result.nes = nes + result.cpu = nes.cpu + +proc step(cpu: CPU): int = + echo "cpu.nes ", cpu.isNil + echo "cpu step nes is nil? - ", cpu.nes.isNil() + +proc newNES(): NES = + new result + result.cpu = CPU(nes: result) + result.apu = initAPU(result) + +proc bug14159 = + var nesConsole = newNES() + discard nesConsole.cpu.step() + let mem = getOccupiedMem() main() +bug14159() GC_fullCollect() echo getOccupiedMem() - mem From 7f1d2489ad79d09c649e37b6d2db12f5fdbd86d7 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 2 May 2020 14:37:16 +0200 Subject: [PATCH 0456/4254] improve the 'has to be discarded' error message --- compiler/semstmts.nim | 4 ++-- tests/discard/tneedsdiscard.nim | 2 +- tests/discard/tneedsdiscard_in_for.nim | 2 +- tests/discard/tvoidcontext.nim | 2 +- tests/errmsgs/tdont_show_system.nim | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 22055a33d..0e018dd0b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -12,7 +12,7 @@ const errNoSymbolToBorrowFromFound = "no symbol to borrow from found" - errDiscardValueX = "value of type '$1' has to be discarded" + errDiscardValueX = "value of type '$1' has to be used (or discarded)" errInvalidDiscard = "statement returns no value that can be discarded" errInvalidControlFlowX = "invalid control flow: $1" errSelectorMustBeOfCertainTypes = "selector must be of an ordinal type, float or string" @@ -144,7 +144,7 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) = var n = result while n.kind in skipForDiscardable: n = n.lastSon var s = "expression '" & $n & "' is of type '" & - result.typ.typeToString & "' and has to be discarded" + result.typ.typeToString & "' and has to be used (or discarded)" if result.info.line != n.info.line or result.info.fileIndex != n.info.fileIndex: s.add "; start of expression here: " & c.config$result.info diff --git a/tests/discard/tneedsdiscard.nim b/tests/discard/tneedsdiscard.nim index d9483947f..75cd9d2df 100644 --- a/tests/discard/tneedsdiscard.nim +++ b/tests/discard/tneedsdiscard.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded; start of expression here: tneedsdiscard.nim(7, 3)''' + errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be used (or discarded); start of expression here: tneedsdiscard.nim(7, 3)''' line: 10 """ diff --git a/tests/discard/tneedsdiscard_in_for.nim b/tests/discard/tneedsdiscard_in_for.nim index ab5216150..7685bd577 100644 --- a/tests/discard/tneedsdiscard_in_for.nim +++ b/tests/discard/tneedsdiscard_in_for.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''expression 'premultiply(app.gradient[i])' is of type 'Rgba8' and has to be discarded''' + errormsg: '''expression 'premultiply(app.gradient[i])' is of type 'Rgba8' and has to be used (or discarded)''' line: 22 """ diff --git a/tests/discard/tvoidcontext.nim b/tests/discard/tvoidcontext.nim index 25e0d4fdf..9e2b913ad 100644 --- a/tests/discard/tvoidcontext.nim +++ b/tests/discard/tvoidcontext.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''expression '"invalid"' is of type 'string' and has to be discarded''' + errormsg: '''expression '"invalid"' is of type 'string' and has to be used (or discarded)''' line: 12 """ diff --git a/tests/errmsgs/tdont_show_system.nim b/tests/errmsgs/tdont_show_system.nim index 830113218..164fdd801 100644 --- a/tests/errmsgs/tdont_show_system.nim +++ b/tests/errmsgs/tdont_show_system.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression 'true' is of type 'bool' and has to be discarded" + errormsg: "expression 'true' is of type 'bool' and has to be used (or discarded)" line: 13 file: "tdont_show_system.nim" """ From ff1c0bae4c9d375b6f68ab37d3eb24e4e5d15198 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 2 May 2020 21:16:08 +0200 Subject: [PATCH 0457/4254] update tests that tested for the 'discard' error messages --- tests/exprs/texprstmt.nim | 2 +- tests/exprs/tstmtexp.nim | 2 +- tests/macros/tmacro6.nim | 16 ++++++++-------- tests/niminaction/Chapter2/explicit_discard.nim | 2 +- tests/niminaction/Chapter2/resultreject.nim | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim index 742670cc1..3c9704650 100644 --- a/tests/exprs/texprstmt.nim +++ b/tests/exprs/texprstmt.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be discarded" + errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be used (or discarded)" line: 10 """ diff --git a/tests/exprs/tstmtexp.nim b/tests/exprs/tstmtexp.nim index 75d8dd081..0ae866497 100644 --- a/tests/exprs/tstmtexp.nim +++ b/tests/exprs/tstmtexp.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "expression '5' is of type 'int literal(5)' and has to be discarded" + errormsg: "expression '5' is of type 'int literal(5)' and has to be used (or discarded)" file: "tstmtexp.nim" line: 8 """ diff --git a/tests/macros/tmacro6.nim b/tests/macros/tmacro6.nim index 0b6423100..c65d34b6d 100644 --- a/tests/macros/tmacro6.nim +++ b/tests/macros/tmacro6.nim @@ -1,22 +1,22 @@ discard """ -errormsg: "expression '123' is of type 'int literal(123)' and has to be discarded" +errormsg: "expression '123' is of type 'int literal(123)' and has to be used (or discarded)" line: 71 """ import macros -proc foo(a,b,c: int): int = +proc foo(a, b, c: int): int = result += a result += b result += c -macro bar(a,b,c: int): int = +macro bar(a, b, c: int): int = result = newCall(ident"echo") result.add a result.add b result.add c -macro baz(a,b,c: int): int = +macro baz(a, b, c: int): int = let stmt = nnkStmtListExpr.newTree() stmt.add newCall(ident"echo", a) stmt.add newCall(ident"echo", b) @@ -26,7 +26,7 @@ macro baz(a,b,c: int): int = # test no result type with explicit return -macro baz2(a,b,c: int) = +macro baz2(a, b, c: int) = let stmt = nnkStmtListExpr.newTree() stmt.add newCall(ident"echo", a) stmt.add newCall(ident"echo", b) @@ -35,7 +35,7 @@ macro baz2(a,b,c: int) = # test explicit void type with explicit return -macro baz3(a,b,c: int): void = +macro baz3(a, b, c: int): void = let stmt = nnkStmtListExpr.newTree() stmt.add newCall(ident"echo", a) stmt.add newCall(ident"echo", b) @@ -44,7 +44,7 @@ macro baz3(a,b,c: int): void = # test no result type with result variable -macro baz4(a,b,c: int) = +macro baz4(a, b, c: int) = result = nnkStmtListExpr.newTree() result.add newCall(ident"echo", a) result.add newCall(ident"echo", b) @@ -52,7 +52,7 @@ macro baz4(a,b,c: int) = # test explicit void type with result variable -macro baz5(a,b,c: int): void = +macro baz5(a, b, c: int): void = let result = nnkStmtListExpr.newTree() result.add newCall(ident"echo", a) result.add newCall(ident"echo", b) diff --git a/tests/niminaction/Chapter2/explicit_discard.nim b/tests/niminaction/Chapter2/explicit_discard.nim index 9a3b4407e..7f3b3395e 100644 --- a/tests/niminaction/Chapter2/explicit_discard.nim +++ b/tests/niminaction/Chapter2/explicit_discard.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "has to be discarded" + errormsg: "has to be used (or discarded)" line: 7 """ diff --git a/tests/niminaction/Chapter2/resultreject.nim b/tests/niminaction/Chapter2/resultreject.nim index 87c84bf0a..145345072 100644 --- a/tests/niminaction/Chapter2/resultreject.nim +++ b/tests/niminaction/Chapter2/resultreject.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "has to be discarded" + errormsg: "has to be used (or discarded)" line: 27 """ From 3be669be3255c6b47dd2542af9d2055a7d1207e3 Mon Sep 17 00:00:00 2001 From: Dien Tran Date: Sat, 2 May 2020 16:49:08 -0500 Subject: [PATCH 0458/4254] Move generated tex file to doc to correct location (#14191) --- tools/kochdocs.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index ba60a3749..4f2062d92 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -271,6 +271,9 @@ proc buildPdfDoc*(nimArgs, destPath: string) = const pdflatexcmd = "pdflatex -interaction=nonstopmode " for d in items(pdf): exec(findNim().quoteShell() & " rst2tex $# $#" % [nimArgs, d]) + let tex = splitFile(d).name & ".tex" + removeFile("doc" / tex) + moveFile(tex, "doc" / tex) # call LaTeX twice to get cross references right: exec(pdflatexcmd & changeFileExt(d, "tex")) exec(pdflatexcmd & changeFileExt(d, "tex")) From fbc97e712a67f30076f7633880383c8c4ae7866f Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 3 May 2020 00:51:59 +0300 Subject: [PATCH 0459/4254] move since from inclrtl to std/private/since (#14188) * move since from inclrtl to std/private/since * move since import in system below for HCR --- lib/core/macros.nim | 1 + lib/js/dom.nim | 2 +- lib/pure/asyncnet.nim | 8 ++------ lib/pure/browsers.nim | 3 ++- lib/pure/collections/critbits.nim | 2 +- lib/pure/collections/deques.nim | 2 +- lib/pure/collections/sequtils.nim | 2 +- lib/pure/collections/tables.nim | 4 ++-- lib/pure/hashes.nim | 2 +- lib/pure/httpclient.nim | 2 +- lib/pure/math.nim | 2 +- lib/pure/net.nim | 2 +- lib/pure/os.nim | 1 + lib/pure/streams.nim | 2 +- lib/pure/strtabs.nim | 1 + lib/pure/sugar.nim | 3 +-- lib/pure/times.nim | 3 ++- lib/pure/typetraits.nim | 9 +++------ lib/pure/unittest.nim | 4 ++-- lib/pure/uri.nim | 2 +- lib/pure/xmltree.nim | 4 ++-- lib/std/private/since.nim | 19 +++++++++++++++++++ lib/system.nim | 6 ++++-- lib/system/dollars.nim | 2 +- lib/system/inclrtl.nim | 18 ------------------ lib/system/io.nim | 1 + tests/stdlib/{tinclrtl.nim => tsince.nim} | 12 ++++++------ 27 files changed, 60 insertions(+), 59 deletions(-) create mode 100644 lib/std/private/since.nim rename tests/stdlib/{tinclrtl.nim => tsince.nim} (67%) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 6e02ae42c..9e17b665a 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -8,6 +8,7 @@ # include "system/inclrtl" +import std/private/since ## This module contains the interface to the compiler's abstract syntax ## tree (`AST`:idx:). Macros operate on this tree. diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 5a24ca38a..4a33668cd 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -9,7 +9,7 @@ ## Declaration of the Document Object Model for the `JavaScript backend ## `_. -include "system/inclrtl" +import std/private/since when not defined(js) and not defined(Nimdoc): {.error: "This module only works on the JavaScript platform".} diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 1e7c13413..93334d0e2 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -95,12 +95,8 @@ ## runForever() ## -include "system/inclrtl" - -import asyncdispatch -import nativesockets -import net -import os +import std/private/since +import asyncdispatch, nativesockets, net, os export SOBool diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index a70b767b7..2dc14b895 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -12,8 +12,9 @@ ## ## Unstable API. +import std/private/since + import strutils -include "system/inclrtl" when defined(windows): import winlean diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 21c749afe..91c113988 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -12,7 +12,7 @@ ## by Adam Langley. ## (A crit bit tree is a form of `radix tree`:idx: or `patricia trie`:idx:.) -include "system/inclrtl" +import std/private/since type NodeObj[T] {.acyclic.} = object diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 69a68c8f0..d096874a3 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -51,7 +51,7 @@ ## * `lists module `_ for singly and doubly linked lists and rings ## * `channels module `_ for inter-thread communication -include system/inclrtl +import std/private/since import math diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 02d48973e..94bce265a 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -73,7 +73,7 @@ ## heterogeneous members -include "system/inclrtl" +import std/private/since import macros diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 131e0ad80..2ea58ce1f 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -217,9 +217,9 @@ ## * `hashes module`_ for helper functions for hashing -import hashes, math, algorithm +import std/private/since -include "system/inclrtl" +import hashes, math, algorithm type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 9fd2a74d0..cd0841d2e 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -44,7 +44,7 @@ ## * `std/sha1 module `_ for a sha1 encoder and decoder ## * `tables module `_ for hash tables -include "system/inclrtl" +import std/private/since type Hash* = int ## A hash value. Hash tables using these values should diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index baf81d77f..42735ad4e 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -200,7 +200,7 @@ ## let client = newHttpClient(maxRedirects = 0) ## -include "system/inclrtl" +import std/private/since import net, strutils, uri, parseutils, base64, os, mimetypes, streams, math, random, httpcore, times, tables, streams, std/monotimes diff --git a/lib/pure/math.nim b/lib/pure/math.nim index a718c3338..6291cddf1 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -52,7 +52,7 @@ ## are on system directly, to name a few ``shr``, ``shl``, ``xor``, ``clamp``, etc. -include "system/inclrtl" +import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9fa019b95..fad6e897d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -64,7 +64,7 @@ ## socket.acceptAddr(client, address) ## echo("Client connected from: ", address) -include "system/inclrtl" +import std/private/since import nativesockets, os, strutils, times, sets, options, std/monotimes from ssl_certs import scanSSLCertificates diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 73fa76fbb..f267e4d01 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -42,6 +42,7 @@ ## * `streams module `_ include "system/inclrtl" +import std/private/since import strutils, pathnorm diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 8efe5b227..77f384a79 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -94,7 +94,7 @@ ## * `asyncstreams module `_ ## * `io module `_ for `FileMode enum `_ -include "system/inclrtl" +import std/private/since const taintMode = compileOption("taintmode") diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 11aa851a1..375f212cd 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -48,6 +48,7 @@ runnableExamples: ## * `json module`_ for table-like structure which allows ## heterogeneous members +import std/private/since import hashes, strutils diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 4b3db6782..062341ccb 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -10,8 +10,7 @@ ## This module implements nice syntactic sugar based on Nim's ## macro system. -include system/inclrtl - +import std/private/since import macros import typetraits diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 8a4c9cd20..2b98e5971 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -194,6 +194,7 @@ import strutils, math, options +import std/private/since include "system/inclrtl" when defined(js): @@ -980,7 +981,7 @@ proc low*(typ: typedesc[Time]): Time = # DateTime & Timezone # -proc isLeapDay*(t: DateTime): bool {.since: (1,1).} = +proc isLeapDay*(t: DateTime): bool {.since: (1, 1).} = ## returns whether `t` is a leap day, ie, Feb 29 in a leap year. This matters ## as it affects time offset calculations. runnableExamples: diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 280233912..06bd1487f 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -12,10 +12,9 @@ ## ## Unstable API. +import std/private/since export system.`$` # for backward compatibility -include "system/inclrtl" - proc name*(t: typedesc): string {.magic: "TypeTrait".} ## Returns the name of the given type. ## @@ -79,15 +78,13 @@ since (1, 1): doAssert 12.MyInt.distinctBase == 12 distinctBase(type(a))(a) -proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait", since: (1, 1).} - ## Return number of elements of `T` + proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait".} + ## Return number of elements of `T` -since (1, 1): template tupleLen*(t: tuple): int = ## Return number of elements of `t` tupleLen(type(t)) -since (1, 1): template get*(T: typedesc[tuple], i: static int): untyped = ## Return `i`\th element of `T` # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 6c434bb19..bb4e2867c 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -93,11 +93,11 @@ ## ## echo "suite teardown: run once after the tests" +import std/private/since + import macros, strutils, streams, times, sets, sequtils -include "system/inclrtl" - when declared(stdout): import os diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 27fbf2db2..b163a2ab4 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -44,7 +44,7 @@ ## doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" ## doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" -include "system/inclrtl" +import std/private/since import strutils, parseutils, base64 type diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 35010e602..9d2e4317e 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -34,8 +34,8 @@ ## * `parsexml module `_ for low-level XML parsing ## * `htmlgen module `_ for html code generator +import std/private/since import macros, strtabs, strutils -include "system/inclrtl" type XmlNode* = ref XmlNodeObj ## An XML tree consisting of XML nodes. @@ -103,7 +103,7 @@ proc newText*(text: string): XmlNode = result = newXmlNode(xnText) result.fText = text -proc newVerbatimText*(text: string): XmlNode {.since:(1, 3).} = +proc newVerbatimText*(text: string): XmlNode {.since: (1, 3).} = ## Creates a new ``XmlNode`` of kind ``xnVerbatimText`` with the text `text`. ## **Since**: Version 1.3. result = newXmlNode(xnVerbatimText) diff --git a/lib/std/private/since.nim b/lib/std/private/since.nim new file mode 100644 index 000000000..e4aecb61a --- /dev/null +++ b/lib/std/private/since.nim @@ -0,0 +1,19 @@ +template since*(version: (int, int), body: untyped) {.dirty.} = + ## Evaluates `body` if the ``(NimMajor, NimMinor)`` is greater than + ## or equal to `version`. Usage: + ## + ## .. code-block:: Nim + ## proc fun*() {.since: (1, 3).} + ## since (1, 3): fun() + when (NimMajor, NimMinor) >= version: + body + +template since*(version: (int, int, int), body: untyped) {.dirty.} = + ## Evaluates `body` if ``(NimMajor, NimMinor, NimPatch)`` is greater than + ## or equal to `version`. Usage: + ## + ## .. code-block:: Nim + ## proc fun*() {.since: (1, 3, 1).} + ## since (1, 3, 1): fun() + when (NimMajor, NimMinor, NimPatch) >= version: + body \ No newline at end of file diff --git a/lib/system.nim b/lib/system.nim index 3698dc8de..6a22fe19b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1124,6 +1124,8 @@ elif hostOS != "standalone": var programResult* {.compilerproc, exportc: "nim_program_result".}: int ## deprecated, prefer ``quit`` +import std/private/since + proc align(address, alignment: int): int = if alignment == 0: # Actually, this is illegal. This branch exists to actively # hide problems. @@ -2054,8 +2056,8 @@ const ## is the major number of Nim's version. Example: ## ## .. code-block:: Nim - ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard - # See also private symbol `since: (1, 3)` reserved for stdlib + ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard + # see also std/private/since NimMinor* {.intdefine.}: int = 3 ## is the minor number of Nim's version. diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 836d5764c..b2f0186b3 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -1,4 +1,4 @@ -include system/inclrtl +import std/private/since proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 37cdb74d8..4193f2bdd 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -48,21 +48,3 @@ when defined(nimlocks): {.pragma: benign, gcsafe, locks: 0.} else: {.pragma: benign, gcsafe.} - -template isSince(version: (int, int)): bool = - (NimMajor, NimMinor) >= version -template isSince(version: (int, int, int)): bool = - (NimMajor, NimMinor, NimPatch) >= version - -template since(version, body: untyped) {.dirty, used.} = - ## Usage: - ## - ## .. code-block:: Nim - ## proc fun*() {since: (1, 3).} - ## proc fun*() {since: (1, 3, 1).} - ## - ## Limitation: can't be used to annotate a template (eg typetraits.get), would - ## error: cannot attach a custom pragma. - # `dirty` needed because `NimMajor` may not yet be defined in caller. - when isSince(version): - body diff --git a/lib/system/io.nim b/lib/system/io.nim index efa2f9475..ab415f40c 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -11,6 +11,7 @@ include inclrtl +import std/private/since import formatfloat # ----------------- IO Part ------------------------------------------------ diff --git a/tests/stdlib/tinclrtl.nim b/tests/stdlib/tsince.nim similarity index 67% rename from tests/stdlib/tinclrtl.nim rename to tests/stdlib/tsince.nim index 2d4c34a90..14dd09c15 100644 --- a/tests/stdlib/tinclrtl.nim +++ b/tests/stdlib/tsince.nim @@ -1,9 +1,9 @@ -include system/inclrtl +import std/private/since -proc fun1(): int {.since: (1,3).} = 12 -proc fun1Bad(): int {.since: (99,3).} = 12 -proc fun2(): int {.since: (1,3,1).} = 12 -proc fun2Bad(): int {.since: (99,3,1).} = 12 +proc fun1(): int {.since: (1, 3).} = 12 +proc fun1Bad(): int {.since: (99, 3).} = 12 +proc fun2(): int {.since: (1, 3, 1).} = 12 +proc fun2Bad(): int {.since: (99, 3, 1).} = 12 doAssert fun1() == 12 doAssert declared(fun1) @@ -23,7 +23,7 @@ since (1, 3, 1): ok = true doAssert ok -since (99,3): +since (99, 3): doAssert false when false: From 49b28f19978b45e4a8868e68a07b8f28807e4705 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 3 May 2020 00:12:52 +0200 Subject: [PATCH 0460/4254] fixes #14136 (#14198) --- compiler/sigmatch.nim | 8 ++++--- tests/metatype/tshacontext.nim | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/metatype/tshacontext.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index a581e20f9..077b4b269 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1823,9 +1823,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): result = isNone else: - localError(c.c.graph.config, f.n.info, "type expected") - result = isNone - + # bug #14136: other types are just like 'tyStatic' here: + result = typeRel(c, a, reevaluated.typ) + if result != isNone and reevaluated.typ.n != nil: + if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): + result = isNone of tyNone: if a.kind == tyNone: result = isEqual else: diff --git a/tests/metatype/tshacontext.nim b/tests/metatype/tshacontext.nim new file mode 100644 index 000000000..7f649d202 --- /dev/null +++ b/tests/metatype/tshacontext.nim @@ -0,0 +1,44 @@ + +# bug #14136 + +type + MDigest*[bits: static[int]] = object + ## Message digest type + data*: array[bits div 8, byte] + + Sha2Context*[bits: static[int], + bsize: static[int], + T: uint32|uint64] = object + count: array[2, T] + state: array[8, T] + buffer: array[bsize, byte] + + sha256* = Sha2Context[256, 64, uint32] + +template hmacSizeBlock*(h: typedesc): int = + when (h is Sha2Context): + int(h.bsize) + else: + {.fatal: "Choosen hash primitive is not yet supported!".} + +type + HMAC*[HashType] = object + ## HMAC context object. + mdctx: HashType + opadctx: HashType + ipad: array[HashType.hmacSizeBlock, byte] + opad: array[HashType.hmacSizeBlock, byte] + +func hkdfExtract*[T;S,I: char|byte](ctx: var HMAC[T], + prk: var MDigest[T.bits], # <------- error here "Error: type expected" + salt: openArray[S], + ikm: openArray[I] + ) = + discard + +var ctx: HMAC[sha256] +var prk: MDigest[sha256.bits] +let salt = [byte 0x00, 0x01, 0x02] +let ikm = "CompletelyRandomInput" + +ctx.hkdfExtract(prk, salt, ikm) From b447ff78604a7177744341cdf8758a4d25dc72be Mon Sep 17 00:00:00 2001 From: slangmgh <37659406+slangmgh@users.noreply.github.com> Date: Sun, 3 May 2020 15:46:42 +0800 Subject: [PATCH 0461/4254] Fix #14201 (#14202) --- lib/pure/os.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index f267e4d01..449ae1d84 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1079,7 +1079,7 @@ when defined(windows) and not weirdTarget: template findNextFile(a, b: untyped): untyped = findNextFileA(a, b) template getCommandLine(): untyped = getCommandLineA() - template getFilename(f: untyped): untyped = $f.cFileName + template getFilename(f: untyped): untyped = $cstring(addr f.cFileName) proc skipFindData(f: WIN32_FIND_DATA): bool {.inline.} = # Note - takes advantage of null delimiter in the cstring From d5c014e59b0af47a1d7e5cf1dc7c732ada3c10c5 Mon Sep 17 00:00:00 2001 From: slangmgh <37659406+slangmgh@users.noreply.github.com> Date: Sun, 3 May 2020 15:47:21 +0800 Subject: [PATCH 0462/4254] Fix #14151 (#14205) [backport] --- lib/system/atomics.nim | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index 146bb859f..15e8a56a7 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -281,10 +281,7 @@ static int __tcc_cas(int *ptr, int oldVal, int newVal) : "r" (newVal), "m" (*ptr), "a" (oldVal) : "memory"); - if (ret) - return 0; - else - return 1; + return ret; } """.} else: @@ -301,10 +298,7 @@ static int __tcc_cas(int *ptr, int oldVal, int newVal) : "r" (newVal), "m" (*ptr), "a" (oldVal) : "memory"); - if (ret) - return 0; - else - return 1; + return ret; } """.} From b56432bd8a56864679b21f4176717ad2f30e7b79 Mon Sep 17 00:00:00 2001 From: slangmgh <37659406+slangmgh@users.noreply.github.com> Date: Sun, 3 May 2020 15:50:08 +0800 Subject: [PATCH 0463/4254] fix #14203 (#14204) --- lib/pure/osproc.nim | 5 ++++- lib/windows/winlean.nim | 30 ++++++++++++++---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index b0f15e38e..5839349fe 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -626,8 +626,11 @@ when defined(Windows) and not defined(useNimRtl): success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags, ee, wwd, si, procInfo) else: + var ee = + if e.str.isNil: cstring(nil) + else: cstring(e.str) success = winlean.createProcessA(nil, - cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo) + cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, ee, wd, si, procInfo) let lastError = osLastError() if poParentStreams notin options: diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index f749c508d..9beccc0eb 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -720,22 +720,20 @@ proc setHandleInformation*(hObject: Handle, dwMask: DWORD, proc getCurrentProcess*(): Handle{.stdcall, dynlib: "kernel32", importc: "GetCurrentProcess".} -when useWinUnicode: - proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD, - lpSecurityAttributes: pointer, - dwCreationDisposition, dwFlagsAndAttributes: DWORD, - hTemplateFile: Handle): Handle {. - stdcall, dynlib: "kernel32", importc: "CreateFileW".} - proc deleteFileW*(pathName: WideCString): int32 {. - importc: "DeleteFileW", dynlib: "kernel32", stdcall.} -else: - proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, - lpSecurityAttributes: pointer, - dwCreationDisposition, dwFlagsAndAttributes: DWORD, - hTemplateFile: Handle): Handle {. - stdcall, dynlib: "kernel32", importc: "CreateFileA".} - proc deleteFileA*(pathName: cstring): int32 {. - importc: "DeleteFileA", dynlib: "kernel32", stdcall.} +proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD, + lpSecurityAttributes: pointer, + dwCreationDisposition, dwFlagsAndAttributes: DWORD, + hTemplateFile: Handle): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateFileW".} +proc deleteFileW*(pathName: WideCString): int32 {. + importc: "DeleteFileW", dynlib: "kernel32", stdcall.} +proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, + lpSecurityAttributes: pointer, + dwCreationDisposition, dwFlagsAndAttributes: DWORD, + hTemplateFile: Handle): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateFileA".} +proc deleteFileA*(pathName: cstring): int32 {. + importc: "DeleteFileA", dynlib: "kernel32", stdcall.} proc setEndOfFile*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32", importc: "SetEndOfFile".} From 3e060cfb0ab6b1affe26a7b09e6b4192e0d68a7f Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 3 May 2020 11:22:49 +0300 Subject: [PATCH 0464/4254] => supports pragmas & names (+ changed behavior) (#14200) * => supports pragmas & names (+ changed behavior) (x, y: int) is now parsed as (x: int, y: int) instead of (x: auto, y: int) inside => and ->. * fix pragma check * fixes, use since & LHS of -> supports pragmas --- changelog.md | 16 ++++++ lib/pure/htmlgen.nim | 8 +-- lib/pure/strutils.nim | 2 +- lib/pure/sugar.nim | 92 ++++++++++++++++++++++------------ lib/pure/typetraits.nim | 2 +- tests/macros/tclosuremacro.nim | 31 ++++++------ 6 files changed, 96 insertions(+), 55 deletions(-) diff --git a/changelog.md b/changelog.md index 4aa22b9d7..165518bd7 100644 --- a/changelog.md +++ b/changelog.md @@ -61,6 +61,22 @@ - `paramCount` & `paramStr` are now defined in os.nim instead of nimscript.nim for nimscript/nimble. - `dollars.$` now works for unsigned ints with `nim js` +- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed + into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency + with regular proc definitions (although you cannot use semicolons). + + Pragmas and using a name are now allowed on the lefthand side of `=>`. Here + is an aggregate example of these changes: + ```nim + import sugar + + foo(x, y: int) {.noSideEffect.} => x + y + + # is transformed into + + proc foo(x: int, y: int): auto {.noSideEffect.} = x + y + ``` + ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: ```nim diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index e0518f5ee..99af26c99 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -64,7 +64,7 @@ proc getIdent(e: NimNode): string {.compileTime.} = result = getIdent(e[0]) for i in 1 .. e.len-1: result.add getIdent(e[i]) - else: error("cannot extract identifier from node: " & toStrLit(e).strVal) + else: error("cannot extract identifier from node: " & toStrLit(e).strVal, e) proc delete[T](s: var seq[T], attr: T): bool = var idx = find(s, attr) @@ -96,14 +96,14 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", result.add(argsList[i][1]) result.add(newStrLitNode("\"")) else: - error("invalid attribute for '" & tag & "' element: " & name) + error("invalid attribute for '" & tag & "' element: " & name, argsList[i]) # check each required attribute exists: if req.len > 0: - error(req[0] & " attribute for '" & tag & "' element expected") + error(req[0] & " attribute for '" & tag & "' element expected", argsList) if isLeaf: for i in 0 ..< argsList.len: if argsList[i].kind != nnkExprEqExpr: - error("element " & tag & " cannot be nested") + error("element " & tag & " cannot be nested", argsList[i]) result.add(newStrLitNode(" />")) else: result.add(newStrLitNode(">")) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a1f80ad76..bb68085aa 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1295,7 +1295,7 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = foundFields.add fStr else: error("Ambiguous enums cannot be parsed, field " & $fStr & - " appears multiple times!") + " appears multiple times!", f) inc fNum # finally add else branch to raise or use default if default == nil: diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 062341ccb..dbc60b8a9 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -11,16 +11,25 @@ ## macro system. import std/private/since -import macros -import typetraits +import macros, typetraits + +proc checkPragma(ex, prag: var NimNode) = + since (1, 3): + if ex.kind == nnkPragmaExpr: + prag = ex[1] + if ex[0].kind == nnkPar and ex[0].len == 1: + ex = ex[0][0] + else: + ex = ex[0] proc createProcType(p, b: NimNode): NimNode {.compileTime.} = - #echo treeRepr(p) - #echo treeRepr(b) result = newNimNode(nnkProcTy) - var formalParams = newNimNode(nnkFormalParams) + var + formalParams = newNimNode(nnkFormalParams).add(b) + p = p + prag = newEmptyNode() - formalParams.add b + checkPragma(p, prag) case p.kind of nnkPar, nnkTupleConstr: @@ -44,9 +53,7 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} = formalParams.add identDefs result.add formalParams - result.add newEmptyNode() - #echo(treeRepr(result)) - #echo(result.toStrLit()) + result.add prag macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. @@ -58,56 +65,75 @@ macro `=>`*(p, b: untyped): untyped = ## ## passTwoAndTwo((x, y) => x + y) # 4 - #echo treeRepr(p) - #echo(treeRepr(b)) - var params: seq[NimNode] = @[newIdentNode("auto")] + var + params = @[ident"auto"] + name = newEmptyNode() + kind = nnkLambda + pragma = newEmptyNode() + p = p + + checkPragma(p, pragma) + + if p.kind == nnkInfix and p[0].kind == nnkIdent and p[0].eqIdent"->": + params[0] = p[2] + p = p[1] + + checkPragma(p, pragma) # check again after -> transform + + since (1, 3): + if p.kind == nnkCall: + # foo(x, y) => x + y + kind = nnkProcDef + name = p[0] + let newP = newNimNode(nnkPar) + for i in 1..": + if c[0].kind == nnkIdent and c[0].eqIdent"->": var procTy = createProcType(c[1], c[2]) params[0] = procTy[0][0] for i in 1 ..< procTy[0].len: params.add(procTy[0][i]) else: - error("Expected proc type (->) got (" & $c[0].ident & ").") + error("Expected proc type (->) got (" & c[0].strVal & ").", c) break else: - echo treeRepr c - error("Incorrect procedure parameter list.") + error("Incorrect procedure parameter list.", c) params.add(identDefs) of nnkIdent: var identDefs = newNimNode(nnkIdentDefs) identDefs.add(p) - identDefs.add(newIdentNode("auto")) + identDefs.add(ident"auto") identDefs.add(newEmptyNode()) params.add(identDefs) - of nnkInfix: - if p[0].kind == nnkIdent and p[0].ident == !"->": - var procTy = createProcType(p[1], p[2]) - params[0] = procTy[0][0] - for i in 1 ..< procTy[0].len: - params.add(procTy[0][i]) - else: - error("Expected proc type (->) got (" & $p[0].ident & ").") else: - error("Incorrect procedure parameter list.") - result = newProc(params = params, body = b, procType = nnkLambda) - #echo(result.treeRepr) - #echo(result.toStrLit()) - #return result # TODO: Bug? + error("Incorrect procedure parameter list.", p) + result = newProc(body = b, params = params, + pragmas = pragma, name = name, + procType = kind) macro `->`*(p, b: untyped): untyped = ## Syntax sugar for procedure types. @@ -190,7 +216,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} result.add(newProc(newEmptyNode(), params, body, nnkProcDef)) for arg in locals: result.add(arg) -when (NimMajor, NimMinor) >= (1, 1): +since (1, 1): import std / private / underscored_calls macro dup*[T](arg: T, calls: varargs[untyped]): T = diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 06bd1487f..0ac6d0d1c 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -124,7 +124,7 @@ macro genericParamsImpl(T: typedesc): untyped = result.add ret break else: - error "wrong kind: " & $impl.kind + error "wrong kind: " & $impl.kind, impl since (1, 1): template genericParams*(T: typedesc): untyped = diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim index 9f2137dec..5c41c317a 100644 --- a/tests/macros/tclosuremacro.nim +++ b/tests/macros/tclosuremacro.nim @@ -1,19 +1,16 @@ discard """ - output: '''10 -10 -10 -3 -3 + output: ''' noReturn -6 calling mystuff yes calling mystuff yes +calling sugarWithPragma +sugarWithPragma called ''' """ -import future, macros +import sugar, macros proc twoParams(x: (int, int) -> int): int = result = x(5, 5) @@ -30,23 +27,23 @@ proc noReturn(x: () -> void) = proc doWithOneAndTwo(f: (int, int) -> int): int = f(1,2) -echo twoParams(proc (a, b: auto): auto = a + b) -echo twoParams((x, y) => x + y) - -echo oneParam(x => x+5) - -echo noParams(() => 3) - -echo doWithOneAndTwo((x, y) => x + y) +doAssert twoParams(proc (a, b: auto): auto = a + b) == 10 +doAssert twoParams((x, y) => x + y) == 10 +doAssert oneParam(x => x+5) == 10 +doAssert noParams(() => 3) == 3 +doAssert doWithOneAndTwo((x, y) => x + y) == 3 noReturn((() -> void) => echo("noReturn")) proc pass2(f: (int, int) -> int): (int) -> int = ((x: int) -> int) => f(2, x) -echo pass2((x, y) => x + y)(4) +doAssert pass2((x, y) => x + y)(4) == 6 +fun(x, y: int) {.noSideEffect.} => x + y +doAssert typeof(fun) is (proc (x, y: int): int {.nimcall.}) +doAssert fun(3, 4) == 7 proc register(name: string; x: proc()) = echo "calling ", name @@ -72,3 +69,5 @@ macro m(x: untyped): untyped = m: proc mystuff() = echo "yes" + +sugarWithPragma() {.m.} => echo "sugarWithPragma called" From b6fb609e0d263a209c6db48dd367f13eb7f4ff87 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 May 2020 07:43:22 +0200 Subject: [PATCH 0465/4254] destructors: don't produce stupid code for 'cast' (#14208) [backport:1.2] * destructors: don't produce stupid code for 'cast' * fixes #14207 --- compiler/dfa.nim | 4 ++-- compiler/injectdestructors.nim | 8 ++++++-- tests/arc/tarcmisc.nim | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0cefec285..7db5f5f65 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -541,8 +541,8 @@ template genNoReturn(c: var Con; n: PNode) = c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len) proc genRaise(c: var Con; n: PNode) = - genJoins(c, n) gen(c, n[0]) + genJoins(c, n) if c.inTryStmt > 0: c.tryStmtFixups.add c.gotoI(n) else: @@ -553,11 +553,11 @@ proc genImplicitReturn(c: var Con) = gen(c, c.owner.ast[resultPos]) proc genReturn(c: var Con; n: PNode) = - genJoins(c, n) if n[0].kind != nkEmpty: gen(c, n[0]) else: genImplicitReturn(c) + genJoins(c, n) genNoReturn(c, n) const diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 680a38397..9e5207437 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -314,7 +314,7 @@ proc genDiscriminantAsgn(c: var Con; n: PNode): PNode = # discriminator is ordinal value that doesn't need sink destroy # but fields within active case branch might need destruction - # tmp to support self assignments + # tmp to support self assignments let tmp = getTemp(c, n[1].typ, n.info) c.addTopVar(tmp) @@ -329,7 +329,7 @@ proc genDiscriminantAsgn(c: var Con; n: PNode): PNode = if hasDestructor(objType): if objType.attachedOps[attachedDestructor] != nil and sfOverriden in objType.attachedOps[attachedDestructor].flags: - localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for object's with user defined destructor is not supported, object must have default destructor. + localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for object's with user defined destructor is not supported, object must have default destructor. It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""") result.add newTree(nkFastAsgn, le, tmp) return @@ -957,6 +957,10 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = for i in 0.. Date: Mon, 4 May 2020 11:18:29 +0200 Subject: [PATCH 0466/4254] sequtils refactoring: prefer typeof over type (#14212) --- lib/pure/collections/sequtils.nim | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 94bce265a..afb225884 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -566,7 +566,7 @@ template filterIt*(s, pred: untyped): untyped = assert acceptable == @[-2.0, 24.5, 44.31] assert notAcceptable == @[-272.15, 99.9, -113.44] - var result = newSeq[type(s[0])]() + var result = newSeq[typeof(s[0])]() for it {.inject.} in items(s): if pred: result.add(it) result @@ -705,7 +705,7 @@ template anyIt*(s, pred: untyped): bool = template toSeq1(s: not iterator): untyped = # overload for typed but not iterator - type OutType = type(items(s)) + type OutType = typeof(items(s)) when compiles(s.len): block: evalOnceAs(s2, s, compiles((let _ = s))) @@ -726,13 +726,13 @@ template toSeq2(iter: iterator): untyped = evalOnceAs(iter2, iter(), false) when compiles(iter2.len): var i = 0 - var result = newSeq[type(iter2)](iter2.len) + var result = newSeq[typeof(iter2)](iter2.len) for x in iter2: result[i] = x inc i result else: - type OutType = type(iter2()) + type OutType = typeof(iter2()) var result: seq[OutType] = @[] when compiles(iter2()): evalOnceAs(iter4, iter, false) @@ -752,8 +752,8 @@ template toSeq*(iter: untyped): untyped = let myRange = 1..5 mySet: set[int8] = {5'i8, 3, 1} - assert type(myRange) is HSlice[system.int, system.int] - assert type(mySet) is set[int8] + assert typeof(myRange) is HSlice[system.int, system.int] + assert typeof(mySet) is set[int8] let mySeq1 = toSeq(myRange) @@ -770,14 +770,14 @@ template toSeq*(iter: untyped): untyped = when compiles(iter.len): block: evalOnceAs(iter2, iter, true) - var result = newSeq[type(iter)](iter2.len) + var result = newSeq[typeof(iter)](iter2.len) var i = 0 for x in iter2: result[i] = x inc i result else: - var result: seq[type(iter)] = @[] + var result: seq[typeof(iter)] = @[] for x in iter: result.add(x) result @@ -815,7 +815,7 @@ template foldl*(sequence, operation: untyped): untyped = let s = sequence assert s.len > 0, "Can't fold empty sequences" - var result: type(s[0]) + var result: typeof(s[0]) result = s[0] for i in 1.. 0, "Can't fold empty sequences" - var result: type(s[0]) + var result: typeof(s[0]) result = sequence[s.len - 1] for i in countdown(s.len - 2, 0): let @@ -920,9 +920,9 @@ template mapIt*(s: typed, op: untyped): untyped = var it{.inject.}: typeof(items(s), typeOfIter); op), typeOfProc) else: - type OutType = type(( + type OutType = typeof(( block: - var it{.inject.}: type(items(s)); + var it{.inject.}: typeof(items(s)); op)) when OutType is not (proc): # Here, we avoid to create closures in loops. @@ -958,7 +958,7 @@ template mapIt*(s: typed, op: untyped): untyped = when defined(nimHasTypeof): type InType = typeof(items(s), typeOfIter) else: - type InType = type(items(s)) + type InType = typeof(items(s)) # Use a help proc `f` to create closures for each element in `s` let f = proc (x: InType): OutType = let it {.inject.} = x @@ -1004,7 +1004,7 @@ template newSeqWith*(len: int, init: untyped): untyped = import random var seqRand = newSeqWith(20, rand(10)) - var result = newSeq[type(init)](len) + var result = newSeq[typeof(init)](len) for i in 0 ..< len: result[i] = init result From f115e40e6a5721b34d41d4ad58e47e194f0e7788 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 4 May 2020 02:27:59 -0700 Subject: [PATCH 0467/4254] `echo cmd | nim r - -arg1 -arg2` now works (#14210) --- compiler/nim.nim | 2 +- tests/trunner.nim | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/compiler/nim.nim b/compiler/nim.nim index 7fe0db5cf..80d9b66b6 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -52,7 +52,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = config.commandLine.add ':' config.commandLine.add p.val.quoteShell - if p.key == " ": + if p.key == "": # `-` was passed to indicate main project is stdin p.key = "-" if processArgument(pass, p, argsCount, config): break else: diff --git a/tests/trunner.nim b/tests/trunner.nim index 263184571..65016d2f1 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -7,9 +7,10 @@ discard """ import std/[strformat,os,osproc,strutils] +const nim = getCurrentCompilerExe() + proc runCmd(file, options = ""): auto = let mode = if existsEnv("NIM_COMPILE_TO_CPP"): "cpp" else: "c" - const nim = getCurrentCompilerExe() const testsDir = currentSourcePath().parentDir let fileabs = testsDir / file.unixToNativePath doAssert fileabs.existsFile, fileabs @@ -60,3 +61,32 @@ else: # don't run twice the same test check "sizeof(Foo5) == 3" check "sizeof(struct Foo6) == " doAssert exitCode != 0 + + import streams + block: # stdin input + let nimcmd = fmt"{nim} r --hints:off - -firstparam '-second param'" + let inputcmd = "import os; echo commandLineParams()" + let expected = """@["-firstparam", "-second param"]""" + block: + let p = startProcess(nimcmd, options = {poEvalCommand}) + p.inputStream.write("import os; echo commandLineParams()") + p.inputStream.close + var output = p.outputStream.readAll + let error = p.errorStream.readAll + doAssert p.waitForExit == 0 + when false: # https://github.com/timotheecour/Nim/issues/152 + # bug: `^[[0m` is being inserted somehow with `-` (regarless of --run) + doAssert error.len == 0, $(error,) + output.stripLineEnd + doAssert output == expected + p.errorStream.close + p.outputStream.close + + block: + when defined(posix): + let cmd = fmt"echo 'import os; echo commandLineParams()' | {nimcmd}" + # avoid https://github.com/timotheecour/Nim/issues/152 by + # making sure `poStdErrToStdOut` isn't passed + var (output, exitCode) = execCmdEx(cmd, options = {poEvalCommand}) + output.stripLineEnd + doAssert output == expected From 603010f8c9d9655bb0fa3f91dc0bd1b76d3a0bd3 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Mon, 4 May 2020 06:54:08 -0300 Subject: [PATCH 0468/4254] Fixes net.recvFrom to work correctly with IPv6 (#14131) * added high level sendTo and recvFrom to std/asyncnet; tests were also added. * add .since annotation, a changelog entry and fixed to standard library style guide. * fixes net.recvFrom to work correctly with IPv6 * raise if domain is not AF_INET or AF_INET6 * renamed template to adaptRecvFromToDomain() --- lib/pure/net.nim | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index fad6e897d..10589ac12 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1425,21 +1425,33 @@ proc recvFrom*(socket: Socket, data: var string, length: int, ## so when ``socket`` is buffered the non-buffered implementation will be ## used. Therefore if ``socket`` contains something in its buffer this ## function will make no effort to return it. + template adaptRecvFromToDomain(domain: Domain) = + var addrLen = sizeof(sockAddress).SockLen + result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) + + if result != -1: + data.setLen(result) + address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) + when domain == AF_INET6: + port = ntohs(sockAddress.sin6_port).Port + else: + port = ntohs(sockAddress.sin_port).Port + else: + raiseOSError(osLastError()) assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") # TODO: Buffered sockets data.setLen(length) - var sockAddress: Sockaddr_in - var addrLen = sizeof(sockAddress).SockLen - result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, - cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) - - if result != -1: - data.setLen(result) - address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) - port = ntohs(sockAddress.sin_port).Port + case socket.domain + of AF_INET6: + var sockAddress: Sockaddr_in6 + adaptRecvFromToDomain(AF_INET6) + of AF_INET: + var sockAddress: Sockaddr_in + adaptRecvFromToDomain(AF_INET) else: - raiseOSError(osLastError()) + raise newException(ValueError, "Unknown socket address family") proc skip*(socket: Socket, size: int, timeout = -1) = ## Skips ``size`` amount of bytes. From 927737975cc02992ea3ce598e3d15970c991a5d8 Mon Sep 17 00:00:00 2001 From: Tristram Oaten Date: Mon, 4 May 2020 14:07:04 +0100 Subject: [PATCH 0469/4254] Re-enabling INim (#14215) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index db6d686e5..02cb3e3fe 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -46,7 +46,7 @@ pkg "gnuplot" pkg "hts", false, "nim c -o:htss src/hts.nim" # pkg "httpauth", true pkg "illwill", false, "nimble examples" -# pkg "inim", true # pending https://github.com/inim-repl/INim/issues/74 +pkg "inim", true pkg "itertools", false, "nim doc src/itertools.nim" pkg "iterutils" pkg "jstin" From a23302ef560743295be4576c3b9e3301709e8390 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 4 May 2020 06:07:32 -0700 Subject: [PATCH 0470/4254] fix https://github.com/timotheecour/Nim/issues/152: avoid writing spurious `^[[0m` to stderr when callStyledWriteLineStderr not called (#14214) * fix https://github.com/timotheecour/Nim/issues/152 `^[[0m` is inserted in stderr for `echo code | nim c -` * resetAttributes not even needed, already handled in styledWriteLine * simplify tests in tests/trunner.nim thanks to this fix --- compiler/main.nim | 2 -- compiler/msgs.nim | 7 +++---- tests/trunner.nim | 8 ++------ 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 66ae830d2..a609d26bc 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -405,5 +405,3 @@ proc mainCommand*(graph: ModuleGraph) = echo " int tries: ", gCacheIntTries echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3) - - resetAttributes(conf) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6fdd4931b..c0d98007b 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -298,6 +298,9 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped = result.add(bindSym"stderr") for arg in children(args[0][1]): result.add(arg) + when false: + # not needed because styledWriteLine already ends with resetAttributes + result = newStmtList(result, newCall(bindSym"resetAttributes", bindSym"stderr")) template callWritelnHook(args: varargs[string, `$`]) = conf.writelnHook concat(args) @@ -441,10 +444,6 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = rawMessage(conf, msg, [arg]) -proc resetAttributes*(conf: ConfigRef) = - if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}: - terminal.resetAttributes(stderr) - proc addSourceLine(conf: ConfigRef; fileIdx: FileIndex, line: string) = conf.m.fileInfos[fileIdx.int32].lines.add line diff --git a/tests/trunner.nim b/tests/trunner.nim index 65016d2f1..265a3712d 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -74,9 +74,7 @@ else: # don't run twice the same test var output = p.outputStream.readAll let error = p.errorStream.readAll doAssert p.waitForExit == 0 - when false: # https://github.com/timotheecour/Nim/issues/152 - # bug: `^[[0m` is being inserted somehow with `-` (regarless of --run) - doAssert error.len == 0, $(error,) + doAssert error.len == 0, $error output.stripLineEnd doAssert output == expected p.errorStream.close @@ -85,8 +83,6 @@ else: # don't run twice the same test block: when defined(posix): let cmd = fmt"echo 'import os; echo commandLineParams()' | {nimcmd}" - # avoid https://github.com/timotheecour/Nim/issues/152 by - # making sure `poStdErrToStdOut` isn't passed - var (output, exitCode) = execCmdEx(cmd, options = {poEvalCommand}) + var (output, exitCode) = execCmdEx(cmd) output.stripLineEnd doAssert output == expected From 44f377ff5e2d2d41ce615bcb1044c2dcf7d3acce Mon Sep 17 00:00:00 2001 From: PMunch Date: Mon, 4 May 2020 19:23:11 +0200 Subject: [PATCH 0471/4254] Add procedures to read RSA keys from BIO format (#14223) --- lib/wrappers/openssl.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index e76aabc8f..5aaa0a0e8 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -602,6 +602,10 @@ proc PEM_read_RSAPrivateKey*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: p dynlib: DLLSSLName, importc.} proc PEM_read_RSAPublicKey*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: pointer): PRSA {.cdecl, dynlib: DLLSSLName, importc.} +proc PEM_read_bio_RSAPublicKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, + dynlib: DLLSSLName, importc.} +proc PEM_read_bio_RSAPrivateKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, + dynlib: DLLSSLName, importc.} proc RSA_private_encrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, dynlib: DLLSSLName, importc.} proc RSA_public_encrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, From c817e85f4cddeddf534ea2890f7f741388ed1ff8 Mon Sep 17 00:00:00 2001 From: wltsmrz Date: Tue, 5 May 2020 02:23:49 +0900 Subject: [PATCH 0472/4254] Linux updates (#14170) * Add posix_memalign() * Add linux-specific open() flags O_TMPFILE: since Linux 3.11 O_PATH: since Linux 2.6.39 O_NOATIME: since Linux 2.6.8 O_DIRECT: since Linux 2.4.10 * Fix Stat type * Fix POSIX AF_INET* const generation --- lib/posix/posix.nim | 2 ++ lib/posix/posix_linux_amd64.nim | 9 +-------- lib/posix/posix_linux_amd64_consts.nim | 15 ++++++++++++++- tools/detect/detect.nim | 21 ++++++++++++++++----- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 3e423c64b..96203b736 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1043,6 +1043,8 @@ proc mkdtemp*(tmpl: cstring): pointer {.importc, header: "", sideEffec when defined(linux) or defined(bsd): proc mkostemp*(tmpl: cstring, oflags: cint): cint {.importc, header: "", sideEffect.} + proc posix_memalign*(memptr: pointer, alignment: csize_t, size: csize_t): cint {.importc, header: "".} + proc utimes*(path: cstring, times: ptr array[2, Timeval]): int {. importc: "utimes", header: "", sideEffect.} ## Sets file access and modification times. diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index bb82d9e5e..7f6a589f0 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -34,9 +34,6 @@ type type SocketHandle* = distinct cint # The type used to represent socket descriptors -# not detected by detect.nim, guarded by #ifdef __USE_UNIX98 in glibc -const SIG_HOLD* = cast[Sighandler](2) - type Time* {.importc: "time_t", header: "".} = distinct clong @@ -228,7 +225,7 @@ type st_mode*: Mode ## Mode of file (see below). st_uid*: Uid ## User ID of file. st_gid*: Gid ## Group ID of file. - pad0: cint + pad0 {.importc: "__pad0".}: cint st_rdev*: Dev ## Device ID (if file is character or block special). st_size*: Off ## For regular files, the file size in bytes. ## For symbolic links, the length in bytes of the @@ -244,8 +241,6 @@ type st_atim*: Timespec ## Time of last access. st_mtim*: Timespec ## Time of last data modification. st_ctim*: Timespec ## Time of last status change. - reserved: array[3, clong] - Statvfs* {.importc: "struct statvfs", header: "", final, pure.} = object ## struct statvfs @@ -573,8 +568,6 @@ var # Regenerate using detect.nim! include posix_linux_amd64_consts -const POSIX_SPAWN_USEVFORK* = cint(0x40) # needs _GNU_SOURCE! - # proc WEXITSTATUS*(s: cint): cint = (s and 0xff00) shr 8 proc WTERMSIG*(s:cint): cint = s and 0x7f diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 84296eb9b..f3230f71d 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -128,6 +128,10 @@ const O_RDONLY* = cint(0) const O_RDWR* = cint(2) const O_WRONLY* = cint(1) const O_CLOEXEC* = cint(524288) +const O_DIRECT* = cint(16384) +const O_PATH* = cint(2097152) +const O_NOATIME* = cint(262144) +const O_TMPFILE* = cint(4259840) const POSIX_FADV_NORMAL* = cint(0) const POSIX_FADV_SEQUENTIAL* = cint(2) const POSIX_FADV_RANDOM* = cint(1) @@ -174,13 +178,20 @@ const FNM_NOMATCH* = cint(1) const FNM_PATHNAME* = cint(1) const FNM_PERIOD* = cint(4) const FNM_NOESCAPE* = cint(2) +const FNM_NOSYS* = cint(-1) # const FTW_F* = cint(0) const FTW_D* = cint(1) const FTW_DNR* = cint(2) +const FTW_DP* = cint(5) const FTW_NS* = cint(3) const FTW_SL* = cint(4) +const FTW_SLN* = cint(6) +const FTW_PHYS* = cint(1) +const FTW_MOUNT* = cint(2) +const FTW_DEPTH* = cint(8) +const FTW_CHDIR* = cint(4) # const GLOB_APPEND* = cint(32) @@ -402,6 +413,7 @@ const SS_ONSTACK* = cint(1) const SS_DISABLE* = cint(2) const MINSIGSTKSZ* = cint(2048) const SIGSTKSZ* = cint(8192) +const SIG_HOLD* = cast[Sighandler](2) const SIG_DFL* = cast[Sighandler](0) const SIG_ERR* = cast[Sighandler](-1) const SIG_IGN* = cast[Sighandler](1) @@ -473,7 +485,7 @@ const SOCK_SEQPACKET* = cint(5) const SOCK_STREAM* = cint(1) const SOCK_CLOEXEC* = cint(524288) const SOL_SOCKET* = cint(1) -const SOMAXCONN* = cint(128) +const SOMAXCONN* = cint(4096) const SO_REUSEPORT* = cint(15) const MSG_NOSIGNAL* = cint(16384) const MSG_PEEK* = cint(2) @@ -531,6 +543,7 @@ const POSIX_SPAWN_SETSCHEDPARAM* = cint(16) const POSIX_SPAWN_SETSCHEDULER* = cint(32) const POSIX_SPAWN_SETSIGDEF* = cint(4) const POSIX_SPAWN_SETSIGMASK* = cint(8) +const POSIX_SPAWN_USEVFORK* = cint(64) # const IOFBF* = cint(0) diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index 0a19a7951..720e24975 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -20,6 +20,8 @@ const cfile = """ /* Generated by detect.nim */ +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200809L #include #include @@ -119,10 +121,14 @@ proc v(name: string, typ = "cint", no_other = false) = addf(tl, "#ifdef $3\n fprintf(f, \"const $1* = $2(%ld)\\n\", $3);\n#endif\n", n, t, name) - of "cint", "cshort", "InAddrScalar", "TSa_Family": + of "cint", "cshort", "TSa_Family": addf(tl, "#ifdef $3\n fprintf(f, \"const $1* = $2(%d)\\n\", $3);\n#endif\n", n, t, name) + of "InAddrScalar": + addf(tl, + "#ifdef $3\n fprintf(f, \"const $1* = $2(%u)\\n\", $3);\n#endif\n", + n, t, name) else: addf(tl, "#ifdef $3\n fprintf(f, \"const $1* = cast[$2](%d)\\n\", $3);\n#endif\n", @@ -256,6 +262,10 @@ v("O_RDONLY") v("O_RDWR") v("O_WRONLY") v("O_CLOEXEC") +v("O_DIRECT") +v("O_PATH") +v("O_NOATIME") +v("O_TMPFILE") v("POSIX_FADV_NORMAL") v("POSIX_FADV_SEQUENTIAL") v("POSIX_FADV_RANDOM") @@ -433,6 +443,7 @@ header("") v("IPPROTO_IP") v("IPPROTO_IPV6") v("IPPROTO_ICMP") +v("IPPROTO_ICMPV6") v("IPPROTO_RAW") v("IPPROTO_TCP") v("IPPROTO_UDP") @@ -631,10 +642,10 @@ v("MSG_NOSIGNAL", no_other = true) v("MSG_PEEK") v("MSG_TRUNC") v("MSG_WAITALL") -v("AF_INET", "TSa_Family") -v("AF_INET6", "TSa_Family") -v("AF_UNIX", "TSa_Family") -v("AF_UNSPEC", "TSa_Family") +v("AF_INET") +v("AF_INET6") +v("AF_UNIX") +v("AF_UNSPEC") v("SHUT_RD") v("SHUT_RDWR") v("SHUT_WR") From e86a6d24d5ffe43e9dc7f230b80c274167376225 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 4 May 2020 18:42:29 +0100 Subject: [PATCH 0473/4254] vcc fix (#14222) Co-authored-by: cooldome --- compiler/extccomp.nim | 2 +- config/nim.cfg | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 37b33bf64..0faf3230b 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -162,7 +162,7 @@ compiler vcc: buildDll: " /LD", buildLib: "lib /OUT:$libfile $objfiles", linkerExe: "cl", - linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui /link /nologo $options", + linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui /nologo $options", includeCmd: " /I", linkDirCmd: " /LIBPATH:", linkLibCmd: " $1.lib", diff --git a/config/nim.cfg b/config/nim.cfg index 21d976982..b43dfd80b 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -320,13 +320,13 @@ tcc.options.always = "-w" @if lto_incremental: vcc.options.always%= "${vcc.options.always} /GL /Gw /Gy" vcc.cpp.options.always%= "${vcc.cpp.options.always} /GL /Gw /Gy" - vcc.options.linker %= "${vcc.options.linker} /LTCG:incremental" - vcc.cpp.options.linker %= "${vcc.cpp.options.linker} /LTCG:incremental" + vcc.options.linker %= "${vcc.options.linker} /link /LTCG:incremental" + vcc.cpp.options.linker %= "${vcc.cpp.options.linker} /link /LTCG:incremental" @else: vcc.options.always%= "${vcc.options.always} /GL" vcc.cpp.options.always%= "${vcc.cpp.options.always} /GL" - vcc.options.linker %= "${vcc.options.linker} /LTCG" - vcc.cpp.options.linker %= "${vcc.cpp.options.linker} /LTCG" + vcc.options.linker %= "${vcc.options.linker} /link /LTCG" + vcc.cpp.options.linker %= "${vcc.cpp.options.linker} /link /LTCG" @end clang_cl.options.always%= "${clang_cl.options.always} -flto" clang_cl.cpp.options.always%= "${clang.cpp.options.always} -flto" From 64e839d5fdb0a334c516f107cab91da14f7c3251 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 5 May 2020 00:48:13 +0200 Subject: [PATCH 0474/4254] fixes #14209 [backport:1.2] (#14213) * fixes #14209 [backport:1.2] * improve stability --- compiler/extccomp.nim | 28 ++++++++++++++++++++++++++++ compiler/main.nim | 3 +++ lib/system/integerops.nim | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 0faf3230b..fe48093dd 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -613,6 +613,34 @@ proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): "Compiler '$1' doesn't support the requested target" % CC[compiler].name) +proc ccHasSaneOverflow*(conf: ConfigRef): bool = + if conf.cCompiler == ccGcc: + result = false # assume an old or crappy GCC + var exe = getConfigVar(conf, conf.cCompiler, ".exe") + if exe.len == 0: exe = CC[conf.cCompiler].compilerExe + let (s, exitCode) = try: execCmdEx(exe & " --version") except: ("", 1) + if exitCode == 0: + var i = 0 + var j = 0 + # the version is the last part of the first line: + while i < s.len and s[i] != '\n': + if s[i] in {' ', '\t'}: j = i+1 + inc i + if j > 0: + var major = 0 + while j < s.len and s[j] in {'0'..'9'}: + major = major * 10 + (ord(s[j]) - ord('0')) + inc j + if i < s.len and s[j] == '.': inc j + while j < s.len and s[j] in {'0'..'9'}: + inc j + if j+1 < s.len and s[j] == '.' and s[j+1] in {'0'..'9'}: + # we found a third version number, chances are high + # we really parsed the version: + result = major >= 5 + else: + result = conf.cCompiler == ccCLang + proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler diff --git a/compiler/main.nim b/compiler/main.nim index a609d26bc..c94af24d5 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -95,6 +95,9 @@ proc commandCompileToC(graph: ModuleGraph) = graph.config.notes = graph.config.mainPackageNotes return + if not extccomp.ccHasSaneOverflow(conf): + conf.symbols.defineSymbol("nimEmulateOverflowChecks") + compileProject(graph) if graph.config.errorCounter > 0: return # issue #9933 diff --git a/lib/system/integerops.nim b/lib/system/integerops.nim index ff744edde..4ef3594f1 100644 --- a/lib/system/integerops.nim +++ b/lib/system/integerops.nim @@ -19,7 +19,7 @@ proc raiseDivByZero {.compilerproc, noinline.} = {.pragma: nimbaseH, importc, nodecl, noSideEffect, compilerproc.} -when (defined(gcc) or defined(clang) or defined(zig)) and not defined(nimEmulateOverflowChecks): +when not defined(nimEmulateOverflowChecks): # take the #define from nimbase.h proc nimAddInt(a, b: int, res: ptr int): bool {.nimbaseH.} From eefada8a8816873c6c9c3e1e7c479fefae96c93b Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 5 May 2020 06:26:32 +0100 Subject: [PATCH 0475/4254] fix #14217 (#14218) * fix #14217 Co-authored-by: cooldome --- lib/system.nim | 2 +- tests/concepts/t3330.nim | 4 ++-- tests/destructor/trecursive.nim | 26 ++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 6a22fe19b..da44baa10 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1193,7 +1193,7 @@ when notJSnotNims and hasAlloc and not defined(nimSeqsV2): proc addChar(s: NimString, c: char): NimString {.compilerproc, benign.} when defined(nimscript) or not defined(nimSeqsV2): - proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} + proc add*[T](x: var seq[T], y: sink T) {.magic: "AppendSeqElem", noSideEffect.} ## Generic proc for adding a data item `y` to a container `x`. ## ## For containers that have an order, `add` means *append*. New generic diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index 9de71f3ac..6faa79c9d 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -28,11 +28,11 @@ proc add(x: var string; y: string) first type mismatch at position: 1 required type for x: var string but expression 'k' is of type: Alias -proc add[T](x: var seq[T]; y: T) +proc add[T](x: var seq[T]; y: openArray[T]) first type mismatch at position: 1 required type for x: var seq[T] but expression 'k' is of type: Alias -proc add[T](x: var seq[T]; y: openArray[T]) +proc add[T](x: var seq[T]; y: sink T) first type mismatch at position: 1 required type for x: var seq[T] but expression 'k' is of type: Alias diff --git a/tests/destructor/trecursive.nim b/tests/destructor/trecursive.nim index 55e67f52a..17a40e5a9 100644 --- a/tests/destructor/trecursive.nim +++ b/tests/destructor/trecursive.nim @@ -32,3 +32,29 @@ proc test1() = echo "test1 OK" test1() + +#------------------------------------------------------------------------------ +# issue #14217 + +type + MyObject = object + p: ptr int + +proc `=destroy`(x: var MyObject) = + if x.p != nil: + deallocShared(x.p) + +proc `=`(x: var MyObject, y: MyObject) {.error.} + +proc newMyObject(i: int): MyObject = + result.p = create(int) + result.p[] = i + +proc test: seq[MyObject] = + for i in 0..3: + let x = newMyObject(i) + result.add x + +var x = test() +for i in 0..3: + doAssert(x[i].p[] == i) From 6b7b5fb4fa7865d17f2433ddc49bac1483b19a01 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Tue, 5 May 2020 11:34:37 +0300 Subject: [PATCH 0476/4254] Clarify JS cstring len (#14184) --- doc/backends.rst | 2 +- lib/pure/cstrutils.nim | 4 ++-- lib/system.nim | 13 +++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/backends.rst b/doc/backends.rst index 52c16b9f7..d34a06238 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -82,7 +82,7 @@ available. This includes: * proper 64 bit integer arithmetic To compensate, the standard library has modules `catered to the JS backend -`_ +`_ and more support will come in the future (for instance, Node.js bindings to get OS info). diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index 345a9be7f..601508e2e 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -69,7 +69,7 @@ proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, ## | > 0 if a > b ## ## Not supported for JS backend, use `strutils.cmpIgnoreStyle - ## `_ instead. + ## `_ instead. var i = 0 var j = 0 while true: @@ -91,7 +91,7 @@ proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, ## | > 0 if a > b ## ## Not supported for JS backend, use `strutils.cmpIgnoreCase - ## `_ instead. + ## `_ instead. var i = 0 while true: var aa = toLowerAscii(a[i]) diff --git a/lib/system.nim b/lib/system.nim index da44baa10..3f5015542 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -692,6 +692,11 @@ proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} ## Returns the length of a compatible string. This is sometimes ## an O(n) operation. + ## + ## **Note:** On the JS backend this currently counts UTF-16 code points + ## instead of bytes at runtime (not at compile time). For now, if you + ## need the byte length of the UTF-8 encoding, convert to string with + ## `$` first then call `len`. ## ## .. code-block:: Nim ## var str: cstring = "Hello world!" @@ -2137,16 +2142,12 @@ when notJSnotNims: when not defined(js): proc cmp(x, y: string): int = - when defined(nimscript): + when nimvm: if x < y: result = -1 elif x > y: result = 1 else: result = 0 else: - when nimvm: - if x < y: result = -1 - elif x > y: result = 1 - else: result = 0 - else: + when not defined(nimscript): # avoid semantic checking let minlen = min(x.len, y.len) result = int(nimCmpMem(x.cstring, y.cstring, cast[csize_t](minlen))) if result == 0: From c28a057a6bd5f20445e11d82c4028762ae1bf1b6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 5 May 2020 05:56:15 -0700 Subject: [PATCH 0477/4254] fix js stacktraces, unify all file,line,col formatting into a single function (#14230) * fix https://github.com/timotheecour/Nim/issues/135 ; unify all file,line,col formatting into a single function --- compiler/jsgen.nim | 4 +- compiler/msgs.nim | 65 ++++++++++++++++++--------------- lib/std/private/miscdollars.nim | 15 ++++++++ lib/system/assertions.nim | 4 +- lib/system/excpt.nim | 8 ++-- lib/system/jssys.nim | 9 +++-- tests/js/t7224.nim | 9 +++-- 7 files changed, 68 insertions(+), 46 deletions(-) create mode 100644 lib/std/private/miscdollars.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index eb9e97fac..c4ee36dbf 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2243,7 +2243,7 @@ proc genProcBody(p: PProc, prc: PSym): Rope = if hasFrameInfo(p): result = frameCreate(p, makeJSString(prc.owner.name.s & '.' & prc.name.s), - makeJSString(toFilename(p.config, prc.info))) + makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace))) else: result = nil if p.beforeRetNeeded: @@ -2583,7 +2583,7 @@ proc genModule(p: PProc, n: PNode) = if optStackTrace in p.options: p.body.add(frameCreate(p, makeJSString("module " & p.module.module.name.s), - makeJSString(toFilename(p.config, p.module.module.info)))) + makeJSString(toFilenameOption(p.config, p.module.module.info.fileIndex, foStacktrace)))) var transformedN = transformStmt(p.module.graph, p.module.module, n) if sfInjectDestructors in p.module.module.flags: transformedN = injectDestructorCalls(p.module.graph, p.module.module, transformedN) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index c0d98007b..43ed8f2a8 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -10,6 +10,7 @@ import options, strutils, os, tables, ropes, terminal, macros, lineinfos, pathutils +import std/private/miscdollars proc toCChar*(c: char; result: var string) = case c @@ -132,7 +133,6 @@ proc suggestQuit*() = # this format is understood by many text editors: it is the same that # Borland and Freepascal use const - PosFormat = "$1($2, $3) " KindFormat = " [$1]" KindColor = fgCyan ErrorTitle = "Error: " @@ -213,16 +213,38 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string = template toFullPathConsiderDirty*(conf: ConfigRef; info: TLineInfo): string = string toFullPathConsiderDirty(conf, info.fileIndex) +type FilenameOption* = enum + foAbs # absolute path, eg: /pathto/bar/foo.nim + foRelProject # relative to project path, eg: ../foo.nim + foMagicSauce # magic sauce, shortest of (foAbs, foRelProject) + foName # lastPathPart, eg: foo.nim + foShort # foName without extension, eg: foo + foStacktrace # if optExcessiveStackTrace: foAbs else: foName + +proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption): string = + case opt + of foAbs: result = toFullPath(conf, fileIdx) + of foRelProject: result = toProjPath(conf, fileIdx) + of foMagicSauce: + let + absPath = toFullPath(conf, fileIdx) + relPath = toProjPath(conf, fileIdx) + result = if (optListFullPaths in conf.globalOptions) or + (relPath.len > absPath.len) or + (relPath.count("..") > 2): + absPath + else: + relPath + of foName: result = toProjPath(conf, fileIdx).lastPathPart + of foShort: result = toFilename(conf, fileIdx) + of foStacktrace: + if optExcessiveStackTrace in conf.globalOptions: + result = toFilenameOption(conf, fileIdx, foAbs) + else: + result = toFilenameOption(conf, fileIdx, foName) + proc toMsgFilename*(conf: ConfigRef; info: FileIndex): string = - let - absPath = toFullPath(conf, info) - relPath = toProjPath(conf, info) - result = if (optListFullPaths in conf.globalOptions) or - (relPath.len > absPath.len) or - (relPath.count("..") > 2): - absPath - else: - relPath + toFilenameOption(conf, info, foMagicSauce) template toMsgFilename*(conf: ConfigRef; info: TLineInfo): string = toMsgFilename(conf, info.fileIndex) @@ -234,9 +256,7 @@ proc toColumn*(info: TLineInfo): int {.inline.} = result = info.col proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} = - # consider calling `helpers.lineInfoToString` instead - result = toMsgFilename(conf, info) & "(" & $info.line & ", " & - $(info.col + ColOffset) & ")" + result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset) proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info) @@ -322,10 +342,6 @@ template styledMsgWriteln*(args: varargs[typed]) = when defined(windows): flushFile(stderr) -proc coordToStr(coord: int): string = - if coord == -1: result = "???" - else: result = $coord - proc msgKindToString*(kind: TMsgKind): string = # later versions may provide translated error messages result = MsgKindToStr[kind] @@ -389,12 +405,7 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = instantiationFrom else: instantiationOfFrom.format(context.detail) - styledMsgWriteln(styleBright, - PosFormat % [toMsgFilename(conf, context.info), - coordToStr(context.info.line.int), - coordToStr(context.info.col+ColOffset)], - resetStyle, - message) + styledMsgWriteln(styleBright, conf.toFileLineCol(context.info), " ", resetStyle, message) info = context.info proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = @@ -473,10 +484,7 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s of warnMin..warnMax: WarningTitle of hintMin..hintMax: HintTitle else: ErrorTitle - result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int), - coordToStr(info.col+ColOffset)] & - title & - getMessageStr(msg, arg) + conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg) proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, eh: TErrorHandling) = @@ -511,8 +519,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] inc(conf.hintCounter) - let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int), - coordToStr(info.col+ColOffset)] + let x = conf.toFileLineCol(info) & " " let s = getMessageStr(msg, arg) if not ignoreMsg: diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim new file mode 100644 index 000000000..a41cf1bc1 --- /dev/null +++ b/lib/std/private/miscdollars.nim @@ -0,0 +1,15 @@ +template toLocation*(result: var string, file: string | cstring, line: int, col: int) = + ## avoids spurious allocations + # Hopefully this can be re-used everywhere so that if a user needs to customize, + # it can be done in a single place. + result.add file + if line > 0: + result.add "(" + # simplify this after moving moving `include strmantle` above import assertions` + when declared(addInt): result.addInt line + else: result.add $line + if col > 0: + result.add ", " + when declared(addInt): result.addInt col + else: result.add $col + result.add ")" diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 9a1bdc7bc..ca3bd7bc1 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -1,17 +1,17 @@ when not declared(sysFatal): include "system/fatal" +import std/private/miscdollars # --------------------------------------------------------------------------- # helpers type InstantiationInfo = tuple[filename: string, line: int, column: int] proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.} - proc `$`(info: InstantiationInfo): string = # The +1 is needed here # instead of overriding `$` (and changing its meaning), consider explicit name. - info.filename & "(" & $info.line & ", " & $(info.column+1) & ")" + result.toLocation(info.filename, info.line, info.column+1) # --------------------------------------------------------------------------- diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index f85c10598..747b145ae 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -10,6 +10,8 @@ # Exception handling code. Carefully coded so that tiny programs which do not # use the heap (and nor exceptions) do not include the GC or memory allocator. +import std/private/miscdollars + var errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign, nimcall.}) @@ -240,11 +242,7 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) = template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) = var oldLen = s.len - add(s, f.filename) - if f.line > 0: - add(s, '(') - add(s, $f.line) - add(s, ')') + s.toLocation(f.filename, f.line, 0) for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ') add(s, f.procname) when NimStackTraceMsgs: diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 106283490..705a6a208 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -8,6 +8,7 @@ # include system/indexerrors +import std/private/miscdollars proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.} @@ -70,7 +71,7 @@ proc getCurrentExceptionMsg*(): string = proc auxWriteStackTrace(f: PCallFrame): string = type - TempFrame = tuple[procname: cstring, line: int] + TempFrame = tuple[procname: cstring, line: int, filename: cstring] var it = f i = 0 @@ -79,6 +80,7 @@ proc auxWriteStackTrace(f: PCallFrame): string = while it != nil and i <= high(tempFrames): tempFrames[i].procname = it.procname tempFrames[i].line = it.line + tempFrames[i].filename = it.filename inc(i) inc(total) it = it.prev @@ -92,10 +94,9 @@ proc auxWriteStackTrace(f: PCallFrame): string = add(result, $(total-i)) add(result, " calls omitted) ...\n") for j in countdown(i-1, 0): + result.toLocation($tempFrames[j].filename, tempFrames[j].line, 0) + add(result, " at ") add(result, tempFrames[j].procname) - if tempFrames[j].line > 0: - add(result, ", line: ") - add(result, $tempFrames[j].line) add(result, "\n") proc rawWriteStackTrace(): string = diff --git a/tests/js/t7224.nim b/tests/js/t7224.nim index be9d0ae9c..77fef10a7 100644 --- a/tests/js/t7224.nim +++ b/tests/js/t7224.nim @@ -1,10 +1,11 @@ discard """ cmd: "nim $target $options --stackTrace:on --lineTrace:on $file" outputsub: ''' -t7224.aaa, line: 21 -t7224.bbb, line: 18 -t7224.ccc, line: 15 -t7224.ddd, line: 12 +t7224.nim(25) at module t7224 +t7224.nim(22) at t7224.aaa +t7224.nim(19) at t7224.bbb +t7224.nim(16) at t7224.ccc +t7224.nim(13) at t7224.ddd ''' """ From 48e7775ad14bc33f5b60225157fb0725d0384675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Wed, 6 May 2020 12:20:34 +0200 Subject: [PATCH 0478/4254] Make the fields of `times.DateTime` private (#14197) * Make the fields of `times.DateTime` private * PR fixes --- changelog.md | 5 + lib/pure/times.nim | 256 +++++++++++++++++++++++++----------- tests/closure/ttimeinfo.nim | 8 +- tests/stdlib/ttimes.nim | 27 ++-- 4 files changed, 208 insertions(+), 88 deletions(-) diff --git a/changelog.md b/changelog.md index 165518bd7..082fe5690 100644 --- a/changelog.md +++ b/changelog.md @@ -76,6 +76,11 @@ proc foo(x: int, y: int): auto {.noSideEffect.} = x + y ``` +- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters. + +- The `times` module now handles the default value for `DateTime` more consistently. Most procs raise an assertion error when given + an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). The proc `times.isInitialized` + has been added which can be used to check if a `DateTime` has been initialized. ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 2b98e5971..1fff3d99b 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -252,7 +252,6 @@ type Month* = enum ## Represents a month. Note that the enum starts at ``1``, ## so ``ord(month)`` will give the month number in the ## range ``1..12``. - # mInvalid = (0, "Invalid") # intentionally left out so `items` works mJan = (1, "January") mFeb = "February" mMar = "March" @@ -276,11 +275,12 @@ type dSun = "Sunday" type - MonthdayRange* = range[0..31] - ## 0 represents an invalid day of the month + MonthdayRange* = range[1..31] HourRange* = range[0..23] MinuteRange* = range[0..59] - SecondRange* = range[0..60] + SecondRange* = range[0..60] ## \ + ## Includes the value 60 to allow for a leap second. Note however + ## that the `second` of a `DateTime` will never be a leap second. YeardayRange* = range[0..365] NanosecondRange* = range[0..999_999_999] @@ -289,46 +289,22 @@ type nanosecond: NanosecondRange DateTime* = object of RootObj ## \ - ## Represents a time in different parts. Although this type can represent - ## leap seconds, they are generally not supported in this module. They are - ## not ignored, but the ``DateTime``'s returned by procedures in this - ## module will never have a leap second. - ## - ## **Warning**: even though the fields of ``DateTime`` are exported, - ## they should never be mutated directly. Doing so is unsafe and will - ## result in the ``DateTime`` ending up in an invalid state. - ## - ## Instead of mutating the fields directly, use the `Duration <#Duration>`_ - ## and `TimeInterval <#TimeInterval>`_ types for arithmetic and use the - ## `initDateTime proc <#initDateTime,MonthdayRange,Month,int,HourRange,MinuteRange,SecondRange,NanosecondRange,Timezone>`_ - ## for changing a specific field. - nanosecond*: NanosecondRange ## The number of nanoseconds after the second, - ## in the range 0 to 999_999_999. - second*: SecondRange ## The number of seconds after the minute, - ## normally in the range 0 to 59, but can - ## be up to 60 to allow for a leap second. - minute*: MinuteRange ## The number of minutes after the hour, - ## in the range 0 to 59. - hour*: HourRange ## The number of hours past midnight, - ## in the range 0 to 23. - monthday*: MonthdayRange ## The day of the month, in the range 1 to 31. - month*: Month ## The month. - year*: int ## The year, using astronomical year numbering - ## (meaning that before year 1 is year 0, - ## then year -1 and so on). - weekday*: WeekDay ## The day of the week. - yearday*: YeardayRange ## The number of days since January 1, - ## in the range 0 to 365. - isDst*: bool ## Determines whether DST is in effect. - ## Always false for the JavaScript backend. - timezone*: Timezone ## The timezone represented as an implementation - ## of ``Timezone``. - utcOffset*: int ## The offset in seconds west of UTC, including - ## any offset due to DST. Note that the sign of - ## this number is the opposite of the one in a - ## formatted offset string like ``+01:00`` (which - ## would be equivalent to the UTC offset - ## ``-3600``). + ## Represents a time in different parts. Although this type can represent + ## leap seconds, they are generally not supported in this module. They are + ## not ignored, but the ``DateTime``'s returned by procedures in this + ## module will never have a leap second. + nanosecond: NanosecondRange + second: SecondRange + minute: MinuteRange + hour: HourRange + monthdayZero: int + monthZero: int + year: int + weekday: WeekDay + yearday: YeardayRange + isDst: bool + timezone: Timezone + utcOffset: int Duration* = object ## Represents a fixed duration of time, meaning a duration ## that has constant length independent of the context. @@ -464,7 +440,7 @@ proc getDaysInMonth*(month: Month, year: int): int = proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline.} = - assert monthday > 0 and monthday <= getDaysInMonth(month, year), + assert monthday <= getDaysInMonth(month, year), $year & "-" & intToStr(ord(month), 2) & "-" & $monthday & " is not a valid date" @@ -981,21 +957,114 @@ proc low*(typ: typedesc[Time]): Time = # DateTime & Timezone # -proc isLeapDay*(t: DateTime): bool {.since: (1, 1).} = +template assertDateTimeInitialized(dt: DateTime) = + assert dt.monthdayZero != 0, "Uninitialized datetime" + +proc nanosecond*(dt: DateTime): NanosecondRange {.inline.} = + ## The number of nanoseconds after the second, + ## in the range 0 to 999_999_999. + assertDateTimeInitialized(dt) + dt.nanosecond + +proc second*(dt: DateTime): SecondRange {.inline.} = + ## The number of seconds after the minute, + ## in the range 0 to 59. + assertDateTimeInitialized(dt) + dt.second + +proc minute*(dt: DateTime): MinuteRange {.inline.} = + ## The number of minutes after the hour, + ## in the range 0 to 59. + assertDateTimeInitialized(dt) + dt.minute + +proc hour*(dt: DateTime): HourRange {.inline.} = + ## The number of hours past midnight, + ## in the range 0 to 23. + assertDateTimeInitialized(dt) + dt.hour + +proc monthday*(dt: DateTime): MonthdayRange {.inline.} = + ## The day of the month, in the range 1 to 31. + assertDateTimeInitialized(dt) + # 'cast' to avoid extra range check + cast[MonthdayRange](dt.monthdayZero) + +proc month*(dt: DateTime): Month = + ## The month as an enum, the ordinal value + ## is in the range 1 to 12. + assertDateTimeInitialized(dt) + # 'cast' to avoid extra range check + cast[Month](dt.monthZero) + +proc year*(dt: DateTime): int {.inline.} = + ## The year, using astronomical year numbering + ## (meaning that before year 1 is year 0, + ## then year -1 and so on). + assertDateTimeInitialized(dt) + dt.year + +proc weekday*(dt: DateTime): WeekDay {.inline.} = + ## The day of the week as an enum, the ordinal + ## value is in the range 0 (monday) to 6 (sunday). + assertDateTimeInitialized(dt) + dt.weekday + +proc yearday*(dt: DateTime): YeardayRange {.inline.} = + ## The number of days since January 1, + ## in the range 0 to 365. + assertDateTimeInitialized(dt) + dt.yearday + +proc isDst*(dt: DateTime): bool {.inline.} = + ## Determines whether DST is in effect. + ## Always false for the JavaScript backend. + assertDateTimeInitialized(dt) + dt.isDst + +proc timezone*(dt: DateTime): Timezone {.inline.} = + ## The timezone represented as an implementation + ## of ``Timezone``. + assertDateTimeInitialized(dt) + dt.timezone + +proc utcOffset*(dt: DateTime): int {.inline.} = + ## The offset in seconds west of UTC, including + ## any offset due to DST. Note that the sign of + ## this number is the opposite of the one in a + ## formatted offset string like ``+01:00`` (which + ## would be equivalent to the UTC offset + ## ``-3600``). + assertDateTimeInitialized(dt) + dt.utcOffset + +proc isInitialized(dt: DateTime): bool = + # Returns true if `dt` is not the (invalid) default value for `DateTime`. + runnableExamples: + doAssert now().isInitialized + doAssert not default(DateTime).isInitialized + dt.monthZero != 0 + +since((1, 3)): + export isInitialized + +proc isLeapDay*(dt: DateTime): bool {.since: (1, 1).} = ## returns whether `t` is a leap day, ie, Feb 29 in a leap year. This matters ## as it affects time offset calculations. runnableExamples: - let t = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) - doAssert t.isLeapDay - doAssert t+1.years-1.years != t - let t2 = initDateTime(28, mFeb, 2020, 00, 00, 00, utc()) - doAssert not t2.isLeapDay - doAssert t2+1.years-1.years == t2 + let dt = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) + doAssert dt.isLeapDay + doAssert dt+1.years-1.years != dt + let dt2 = initDateTime(28, mFeb, 2020, 00, 00, 00, utc()) + doAssert not dt2.isLeapDay + doAssert dt2+1.years-1.years == dt2 doAssertRaises(Exception): discard initDateTime(29, mFeb, 2021, 00, 00, 00, utc()) - t.year.isLeapYear and t.month == mFeb and t.monthday == 29 + assertDateTimeInitialized dt + dt.year.isLeapYear and dt.month == mFeb and dt.monthday == 29 proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = ## Converts a ``DateTime`` to a ``Time`` representing the same point in time. + assertDateTimeInitialized dt let epochDay = toEpochDay(dt.monthday, dt.month, dt.year) var seconds = epochDay * secondsInDay seconds.inc dt.hour * secondsInHour @@ -1020,8 +1089,8 @@ proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime = DateTime( year: y, - month: m, - monthday: d, + monthZero: m.int, + monthdayZero: d, hour: hour, minute: minute, second: second, @@ -1091,14 +1160,13 @@ proc `$`*(zone: Timezone): string = proc `==`*(zone1, zone2: Timezone): bool = ## Two ``Timezone``'s are considered equal if their name is equal. + runnableExamples: + doAssert local() == local() + doAssert local() != utc() if system.`==`(zone1, zone2): return true if zone1.isNil or zone2.isNil: return false - - runnableExamples: - doAssert local() == local() - doAssert local() != utc() zone1.name == zone2.name proc inZone*(time: Time, zone: Timezone): DateTime @@ -1110,6 +1178,7 @@ proc inZone*(dt: DateTime, zone: Timezone): DateTime {.tags: [], raises: [], benign.} = ## Returns a ``DateTime`` representing the same point in time as ``dt`` but ## using ``zone`` as the timezone. + assertDateTimeInitialized dt dt.toTime.inZone(zone) proc toAdjTime(dt: DateTime): Time = @@ -1265,9 +1334,9 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, assertValidDate monthday, month, year let dt = DateTime( - monthday: monthday, + monthdayZero: monthday, year: year, - month: month, + monthZero: month.int, hour: hour, minute: minute, second: second, @@ -1318,13 +1387,10 @@ proc `<=`*(a, b: DateTime): bool = ## Returns true if ``a`` happened before or at the same time as ``b``. return a.toTime <= b.toTime -proc isDefault[T](a: T): bool = - system.`==`(a, default(T)) - proc `==`*(a, b: DateTime): bool = ## Returns true if ``a`` and ``b`` represent the same point in time. - if a.isDefault: b.isDefault - elif b.isDefault: false + if not a.isInitialized: not b.isInitialized + elif not b.isInitialized: false else: a.toTime == b.toTime proc `+=`*(a: var DateTime, b: Duration) = @@ -1337,13 +1403,15 @@ proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} ## Gets the current local date as a string of the format ``YYYY-MM-DD``. runnableExamples: echo getDateStr(now() - 1.months) - result = $dt.year & '-' & intToStr(ord(dt.month), 2) & + assertDateTimeInitialized dt + result = $dt.year & '-' & intToStr(dt.monthZero, 2) & '-' & intToStr(dt.monthday, 2) proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = ## Gets the current local clock time as a string of the format ``HH:mm:ss``. runnableExamples: echo getClockStr(now() - 1.hours) + assertDateTimeInitialized dt result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & ':' & intToStr(dt.second, 2) @@ -1914,18 +1982,13 @@ proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, $year & "-" & ord(month).intToStr(2) & "-" & $monthday & " is not a valid date") - result = DateTime( - year: year, month: month, monthday: monthday, - hour: hour, minute: minute, second: second, nanosecond: nanosecond - ) - if p.utcOffset.isNone: # No timezone parsed - assume timezone is `zone` - result = initDateTime(zone.zonedTimeFromAdjTime(result.toAdjTime), zone) + result = initDateTime(monthday, month, year, hour, minute, second, nanosecond, zone) else: # Otherwise convert to `zone` - result.utcOffset = p.utcOffset.get() - result = result.toTime.inZone(zone) + result = (initDateTime(monthday, month, year, hour, minute, second, nanosecond, utc()).toTime + + initDuration(seconds = p.utcOffset.get())).inZone(zone) proc format*(dt: DateTime, f: TimeFormat, loc: DateTimeLocale = DefaultLocale): string {.raises: [].} = @@ -1934,6 +1997,7 @@ proc format*(dt: DateTime, f: TimeFormat, let f = initTimeFormat("yyyy-MM-dd") let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert "2000-01-01" == dt.format(f) + assertDateTimeInitialized dt var idx = 0 while idx <= f.patterns.high: case f.patterns[idx].FormatPattern @@ -2082,7 +2146,11 @@ proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} = runnableExamples: let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) doAssert $dt == "2000-01-01T12:00:00Z" - result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") + doAssert $default(DateTime) == "Uninitialized DateTime" + if not dt.isInitialized: + result = "Uninitialized DateTime" + else: + result = format(dt, "yyyy-MM-dd'T'HH:mm:sszzz") proc `$`*(time: Time): string {.tags: [], raises: [], benign.} = ## Converts a `Time` value to a string representation. It will use the local @@ -2721,3 +2789,39 @@ proc getGMTime*(time: Time): DateTime ## expressed in Coordinated Universal Time (UTC). # Deprecated since v0.18.0 time.utc + +proc `nanosecond=`*(dt: var DateTime, value: NanosecondRange) {.deprecated: "Deprecated since v1.3.1".} = + dt.nanosecond = value + +proc `second=`*(dt: var DateTime, value: SecondRange) {.deprecated: "Deprecated since v1.3.1".} = + dt.second = value + +proc `minute=`*(dt: var DateTime, value: MinuteRange) {.deprecated: "Deprecated since v1.3.1".} = + dt.minute = value + +proc `hour=`*(dt: var DateTime, value: HourRange) {.deprecated: "Deprecated since v1.3.1".} = + dt.hour = value + +proc `monthdayZero=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = + dt.monthdayZero = value + +proc `monthZero=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = + dt.monthZero = value + +proc `year=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = + dt.year = value + +proc `weekday=`*(dt: var DateTime, value: WeekDay) {.deprecated: "Deprecated since v1.3.1".} = + dt.weekday = value + +proc `yearday=`*(dt: var DateTime, value: YeardayRange) {.deprecated: "Deprecated since v1.3.1".} = + dt.yearday = value + +proc `isDst=`*(dt: var DateTime, value: bool) {.deprecated: "Deprecated since v1.3.1".} = + dt.isDst = value + +proc `timezone=`*(dt: var DateTime, value: Timezone) {.deprecated: "Deprecated since v1.3.1".} = + dt.timezone = value + +proc `utcOffset=`*(dt: var DateTime, value: int) {.deprecated: "Deprecated since v1.3.1".} = + dt.utcOffset = value diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim index 7416c0d31..24d535cbf 100644 --- a/tests/closure/ttimeinfo.nim +++ b/tests/closure/ttimeinfo.nim @@ -1,7 +1,7 @@ discard """ output: ''' -@[2000-01-01T00:00:00+00:00, 2001-01-01T00:00:00+00:00, 2002-01-01T00:00:00+00:00, 2003-01-01T00:00:00+00:00, 2004-01-01T00:00:00+00:00, 2005-01-01T00:00:00+00:00, 2006-01-01T00:00:00+00:00, 2007-01-01T00:00:00+00:00, 2008-01-01T00:00:00+00:00, 2009-01-01T00:00:00+00:00, 2010-01-01T00:00:00+00:00, 2011-01-01T00:00:00+00:00, 2012-01-01T00:00:00+00:00, 2013-01-01T00:00:00+00:00, 2014-01-01T00:00:00+00:00, 2015-01-01T00:00:00+00:00] -@[2000-01-01T00:00:00+00:00, 2001-01-01T00:00:00+00:00, 2002-01-01T00:00:00+00:00, 2003-01-01T00:00:00+00:00, 2004-01-01T00:00:00+00:00, 2005-01-01T00:00:00+00:00, 2006-01-01T00:00:00+00:00, 2007-01-01T00:00:00+00:00, 2008-01-01T00:00:00+00:00, 2009-01-01T00:00:00+00:00, 2010-01-01T00:00:00+00:00, 2011-01-01T00:00:00+00:00, 2012-01-01T00:00:00+00:00, 2013-01-01T00:00:00+00:00, 2014-01-01T00:00:00+00:00, 2015-01-01T00:00:00+00:00] +@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z] +@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z] ''' """ @@ -12,11 +12,11 @@ import times # 1 proc f(n: int): DateTime = - DateTime(year: n, month: mJan, monthday: 1) + initDateTime(1, mJan, n, 0, 0, 0, utc()) echo toSeq(2000 || 2015).map(f) # 2 echo toSeq(2000 || 2015).map(proc (n: int): DateTime = - DateTime(year: n, month: mJan, monthday: 1) + initDateTime(1, mJan, n, 0, 0, 0, utc()) ) diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 590018c6d..e6305b2d0 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -617,17 +617,28 @@ suite "ttimes": test "default DateTime": # https://github.com/nim-lang/RFCs/issues/211 var num = 0 for ai in Month: num.inc - doAssert num == 12 + check num == 12 var a: DateTime - doAssert a == DateTime.default - doAssert ($a).len > 0 # no crash - doAssert a.month.Month.ord == 0 - doAssert a.month.Month == cast[Month](0) - doAssert a.monthday == 0 + check a == DateTime.default + check not a.isInitialized + check $a == "Uninitialized DateTime" - doAssertRaises(AssertionDefect): discard getDayOfWeek(a.monthday, a.month, a.year) - doAssertRaises(AssertionDefect): discard a.toTime + expect(AssertionDefect): discard getDayOfWeek(a.monthday, a.month, a.year) + expect(AssertionDefect): discard a.toTime + expect(AssertionDefect): discard a.utc() + expect(AssertionDefect): discard a.local() + expect(AssertionDefect): discard a.inZone(utc()) + expect(AssertionDefect): discard a + initDuration(seconds = 1) + expect(AssertionDefect): discard a + initTimeInterval(seconds = 1) + expect(AssertionDefect): discard a.isLeapDay + expect(AssertionDefect): discard a < a + expect(AssertionDefect): discard a <= a + expect(AssertionDefect): discard getDateStr(a) + expect(AssertionDefect): discard getClockStr(a) + expect(AssertionDefect): discard a.format "yyyy" + expect(AssertionDefect): discard a.format initTimeFormat("yyyy") + expect(AssertionDefect): discard between(a, a) test "inX procs": doAssert initDuration(seconds = 1).inSeconds == 1 From b8e6ea7547344389b5e45c3af249fee9642f028e Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Wed, 6 May 2020 05:21:49 -0500 Subject: [PATCH 0479/4254] Added bitslice operations for bitops (#14016) * added bit operations based on bit slices, clarified documentation, made non-mutating versions of mask ops * Added since annotations, some runnable examples * Added mask()/masked() functions, changed internal workings of mask ops to use new bit* funcs * Changelog updated for new bitops improvements * Reorganization, added runnable examples * Documentation adjustments * Add incltrl for since annotation * Fix masked() impl * Fix mask() return type * Don't call toUnsigned on already unsigned types * Remove improper `var T` for flipMasked() * Fix return types for flipMasked() * Slight syntactic cleanup for *masked ops * Added tests for bitslice operations, new mask() operation, non-mutating mask ops * Fix setmasked() var T issue * More comprehensive tests * Fix runnable example for bitsliced() * Fix runnable example for mask() --- changelog.md | 4 + lib/pure/bitops.nim | 227 +++++++++++++++++++++++++++++++++++---- tests/stdlib/tbitops.nim | 71 +++++++++++- 3 files changed, 280 insertions(+), 22 deletions(-) diff --git a/changelog.md b/changelog.md index 082fe5690..9ae50f1f3 100644 --- a/changelog.md +++ b/changelog.md @@ -61,6 +61,10 @@ - `paramCount` & `paramStr` are now defined in os.nim instead of nimscript.nim for nimscript/nimble. - `dollars.$` now works for unsigned ints with `nim js` +- Improvements to the `bitops` module, including bitslices, non-mutating versions + of the original masking functions, `mask`/`masked`, and varargs support for + `bitand`, `bitor`, and `bitxor`. + - `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency with regular proc definitions (although you cannot use semicolons). diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 439f6be03..6aeec3092 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -26,6 +26,7 @@ ## may return undefined and/or platform dependent value if given invalid input. import macros +import std/private/since proc bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. @@ -85,37 +86,220 @@ template forwardImpl(impl, arg) {.dirty.} = when defined(nimHasalignOf): type BitsRange*[T] = range[0..sizeof(T)*8-1] - ## Returns a range with all bit positions for type ``T``. + ## A range with all bit positions for type ``T`` - proc setMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = + func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = + ## Returns an extracted (and shifted) slice of bits from ``v``. + runnableExamples: + doAssert 0b10111.bitsliced(2 .. 4) == 0b101 + doAssert 0b11100.bitsliced(0 .. 2) == 0b100 + doAssert 0b11100.bitsliced(0 ..< 3) == 0b100 + + let + upmost = sizeof(T) * 8 - 1 + uv = when v is SomeUnsignedInt: v else: v.toUnsigned + (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + + proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = + ## Mutates ``v`` into an extracted (and shifted) slice of bits from ``v``. + runnableExamples: + var x = 0b101110 + x.bitslice(2 .. 4) + doAssert x == 0b011 + + let + upmost = sizeof(T) * 8 - 1 + uv = when v is SomeUnsignedInt: v else: v.toUnsigned + v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + + func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = + ## Creates a bitmask based on a slice of bits. + runnableExamples: + doAssert toMask[int32](1 .. 3) == 0b1110'i32 + doAssert toMask[int32](0 .. 3) == 0b1111'i32 + + let + upmost = sizeof(T) * 8 - 1 + bitmask = when T is SomeUnsignedInt: + bitnot(0.T) + else: + bitnot(0.T).toUnsigned + (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T + + proc masked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = + ## Returns ``v``, with only the ``1`` bits from ``mask`` matching those of + ## ``v`` set to 1. + ## + ## Effectively maps to a `bitand` operation. + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.masked(0b0000_1010'u8) == 0b0000_0010'u8 + + bitand(v, mask) + + func masked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = + ## Mutates ``v``, with only the ``1`` bits in the range of ``slice`` + ## matching those of ``v`` set to 1. + ## + ## Effectively maps to a `bitand` operation. + runnableExamples: + var v = 0b0000_1011'u8 + doAssert v.masked(1 .. 3) == 0b0000_1010'u8 + + bitand(v, toMask[T](slice)) + + proc mask*[T: SomeInteger](v: var T; mask: T) {.inline, since: (1, 3).} = + ## Mutates ``v``, with only the ``1`` bits from ``mask`` matching those of + ## ``v`` set to 1. + ## + ## Effectively maps to a `bitand` operation. + runnableExamples: + var v = 0b0000_0011'u8 + v.mask(0b0000_1010'u8) + doAssert v == 0b0000_1010'u8 + + v = bitand(v, mask) + + proc mask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = + ## Mutates ``v``, with only the ``1`` bits in the range of ``slice`` + ## matching those of ``v`` set to 1. + ## + ## Effectively maps to a `bitand` operation. + runnableExamples: + var v = 0b0000_1011'u8 + v.mask(1 .. 3) + doAssert v == 0b0000_1010'u8 + + v = bitand(v, toMask[T](slice)) + + func setMasked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1. + ## + ## Effectively maps to a `bitor` operation. + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.setMasked(0b0000_1010'u8) == 0b0000_1011'u8 + + bitor(v, mask) + + func setMasked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = + ## Returns ``v``, with all the ``1`` bits in the range of ``slice`` set to 1. + ## + ## Effectively maps to a `bitor` operation. + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.setMasked(2 .. 3) == 0b0000_1111'u8 + + bitor(v, toMask[T](slice)) + + proc setMask*[T: SomeInteger](v: var T; mask: T) {.inline.} = + ## Mutates ``v``, with all the ``1`` bits from ``mask`` set to 1. + ## + ## Effectively maps to a `bitor` operation. runnableExamples: var v = 0b0000_0011'u8 v.setMask(0b0000_1010'u8) doAssert v == 0b0000_1011'u8 - v = v or mask + v = bitor(v, mask) - proc clearMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = + proc setMask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = + ## Mutates ``v``, with all the ``1`` bits in the range of ``slice`` set to 1. + ## + ## Effectively maps to a `bitor` operation. + runnableExamples: + var v = 0b0000_0011'u8 + v.setMask(2 .. 3) + doAssert v == 0b0000_1111'u8 + + v = bitor(v, toMask[T](slice)) + + func clearMasked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = ## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0. + ## + ## Effectively maps to a `bitand` operation with an *inverted mask.* + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.clearMasked(0b0000_1010'u8) == 0b0000_0001'u8 + + bitand(v, bitnot(mask)) + + func clearMasked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = + ## Returns ``v``, with all the ``1`` bits in the range of ``slice`` set to 0. + ## + ## Effectively maps to a `bitand` operation with an *inverted mask.* + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.clearMasked(1 .. 3) == 0b0000_0001'u8 + + bitand(v, bitnot(toMask[T](slice))) + + proc clearMask*[T: SomeInteger](v: var T; mask: T) {.inline.} = + ## Mutates ``v``, with all the ``1`` bits from ``mask`` set to 0. + ## + ## Effectively maps to a `bitand` operation with an *inverted mask.* runnableExamples: var v = 0b0000_0011'u8 v.clearMask(0b0000_1010'u8) doAssert v == 0b0000_0001'u8 - v = v and not mask + v = bitand(v, bitnot(mask)) - proc flipMask*[T: SomeInteger](v: var T, mask: T) {.inline.} = + proc clearMask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = + ## Mutates ``v``, with all the ``1`` bits in the range of ``slice`` set to 0. + ## + ## Effectively maps to a `bitand` operation with an *inverted mask.* + runnableExamples: + var v = 0b0000_0011'u8 + v.clearMask(1 .. 3) + doAssert v == 0b0000_0001'u8 + + v = bitand(v, bitnot(toMask[T](slice))) + + func flipMasked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = ## Returns ``v``, with all the ``1`` bits from ``mask`` flipped. + ## + ## Effectively maps to a `bitxor` operation. + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.flipMasked(0b0000_1010'u8) == 0b0000_1001'u8 + + bitxor(v, mask) + + func flipMasked*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = + ## Returns ``v``, with all the ``1`` bits in the range of ``slice`` flipped. + ## + ## Effectively maps to a `bitxor` operation. + runnableExamples: + var v = 0b0000_0011'u8 + doAssert v.flipMasked(1 .. 3) == 0b0000_1001'u8 + + bitxor(v, toMask[T](slice)) + + proc flipMask*[T: SomeInteger](v: var T; mask: T) {.inline.} = + ## Mutates ``v``, with all the ``1`` bits from ``mask`` flipped. + ## + ## Effectively maps to a `bitxor` operation. runnableExamples: var v = 0b0000_0011'u8 v.flipMask(0b0000_1010'u8) doAssert v == 0b0000_1001'u8 - v = v xor mask + v = bitxor(v, mask) - proc setBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = - ## Returns ``v``, with the bit at position ``bit`` set to 1. + proc flipMask*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = + ## Mutates ``v``, with all the ``1`` bits in the range of ``slice`` flipped. + ## + ## Effectively maps to a `bitxor` operation. + runnableExamples: + var v = 0b0000_0011'u8 + v.flipMask(1 .. 3) + doAssert v == 0b0000_1001'u8 + + v = bitxor(v, toMask[T](slice)) + + proc setBit*[T: SomeInteger](v: var T; bit: BitsRange[T]) {.inline.} = + ## Mutates ``v``, with the bit at position ``bit`` set to 1 runnableExamples: var v = 0b0000_0011'u8 v.setBit(5'u8) @@ -123,8 +307,8 @@ when defined(nimHasalignOf): v.setMask(1.T shl bit) - proc clearBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = - ## Returns ``v``, with the bit at position ``bit`` set to 0. + proc clearBit*[T: SomeInteger](v: var T; bit: BitsRange[T]) {.inline.} = + ## Mutates ``v``, with the bit at position ``bit`` set to 0 runnableExamples: var v = 0b0000_0011'u8 v.clearBit(1'u8) @@ -132,8 +316,8 @@ when defined(nimHasalignOf): v.clearMask(1.T shl bit) - proc flipBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} = - ## Returns ``v``, with the bit at position ``bit`` flipped. + proc flipBit*[T: SomeInteger](v: var T; bit: BitsRange[T]) {.inline.} = + ## Mutates ``v``, with the bit at position ``bit`` flipped runnableExamples: var v = 0b0000_0011'u8 v.flipBit(1'u8) @@ -145,8 +329,8 @@ when defined(nimHasalignOf): v.flipMask(1.T shl bit) - macro setBits*(v: var typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 1. + macro setBits*(v: typed; bits: varargs[typed]): untyped = + ## Mutates ``v``, with the bits at positions ``bits`` set to 1 runnableExamples: var v = 0b0000_0011'u8 v.setBits(3, 5, 7) @@ -157,8 +341,8 @@ when defined(nimHasalignOf): for bit in bits: result.add newCall("setBit", v, bit) - macro clearBits*(v: var typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 0. + macro clearBits*(v: typed; bits: varargs[typed]): untyped = + ## Mutates ``v``, with the bits at positions ``bits`` set to 0 runnableExamples: var v = 0b1111_1111'u8 v.clearBits(1, 3, 5, 7) @@ -169,8 +353,8 @@ when defined(nimHasalignOf): for bit in bits: result.add newCall("clearBit", v, bit) - macro flipBits*(v: var typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 0. + macro flipBits*(v: typed; bits: varargs[typed]): untyped = + ## Mutates ``v``, with the bits at positions ``bits`` set to 0 runnableExamples: var v = 0b0000_1111'u8 v.flipBits(1, 3, 5, 7) @@ -181,8 +365,9 @@ when defined(nimHasalignOf): for bit in bits: result.add newCall("flipBit", v, bit) - proc testBit*[T: SomeInteger](v: T, bit: BitsRange[T]): bool {.inline.} = - ## Returns true if the bit in ``v`` at positions ``bit`` is set to 1. + + proc testBit*[T: SomeInteger](v: T; bit: BitsRange[T]): bool {.inline.} = + ## Returns true if the bit in ``v`` at positions ``bit`` is set to 1 runnableExamples: var v = 0b0000_1111'u8 doAssert v.testBit(0) diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index 1bd4da5c4..2baa1c718 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -171,7 +171,7 @@ proc main1() = doAssert( U64A.rotateRightBits(64) == U64A) block: - # mask operations + # basic mask operations (mutating) var v: uint8 v.setMask(0b1100_0000) v.setMask(0b0000_1100) @@ -182,6 +182,75 @@ proc main1() = doAssert(v == 0b0001_0001) v.clearMask(0b0001_0001) doAssert(v == 0b0000_0000) + v.setMask(0b0001_1110) + doAssert(v == 0b0001_1110) + v.mask(0b0101_0100) + doAssert(v == 0b0001_0100) + block: + # basic mask operations (non-mutating) + let v = 0b1100_0000'u8 + doAssert(v.masked(0b0000_1100) == 0b0000_0000) + doAssert(v.masked(0b1000_1100) == 0b1000_0000) + doAssert(v.setMasked(0b0000_1100) == 0b1100_1100) + doAssert(v.setMasked(0b1000_1110) == 0b1100_1110) + doAssert(v.flipMasked(0b1100_1000) == 0b0000_1000) + doAssert(v.flipMasked(0b0000_1100) == 0b1100_1100) + let t = 0b1100_0110'u8 + doAssert(t.clearMasked(0b0100_1100) == 0b1000_0010) + doAssert(t.clearMasked(0b1100_0000) == 0b0000_0110) + block: + # basic bitslice opeartions + let a = 0b1111_1011'u8 + doAssert(a.bitsliced(0 .. 3) == 0b1011) + doAssert(a.bitsliced(2 .. 3) == 0b10) + doAssert(a.bitsliced(4 .. 7) == 0b1111) + + # same thing, but with exclusive ranges. + doAssert(a.bitsliced(0 ..< 4) == 0b1011) + doAssert(a.bitsliced(2 ..< 4) == 0b10) + doAssert(a.bitsliced(4 ..< 8) == 0b1111) + + # mutating + var b = 0b1111_1011'u8 + b.bitslice(1 .. 3) + doAssert(b == 0b101) + + # loop test: + let c = 0b1111_1111'u8 + for i in 0 .. 7: + doAssert(c.bitsliced(i .. 7) == c shr i) + block: + # bitslice versions of mask operations (mutating) + var a = 0b1100_1100'u8 + let b = toMask[uint8](2 .. 3) + a.mask(b) + doAssert(a == 0b0000_1100) + a.setMask(4 .. 7) + doAssert(a == 0b1111_1100) + a.flipMask(1 .. 3) + doAssert(a == 0b1111_0010) + a.flipMask(2 .. 4) + doAssert(a == 0b1110_1110) + a.clearMask(2 .. 4) + doAssert(a == 0b1110_0010) + a.mask(0 .. 3) + doAssert(a == 0b0000_0010) + + # composition of mask from slices: + let c = bitor(toMask[uint8](2 .. 3), toMask[uint8](5 .. 7)) + doAssert(c == 0b1110_1100'u8) + block: + # bitslice versions of mask operations (non-mutating) + let a = 0b1100_1100'u8 + doAssert(a.masked(toMask[uint8](2 .. 3)) == 0b0000_1100) + doAssert(a.masked(2 .. 3) == 0b0000_1100) + doAssert(a.setMasked(0 .. 3) == 0b1100_1111) + doAssert(a.setMasked(3 .. 4) == 0b1101_1100) + doAssert(a.flipMasked(0 .. 3) == 0b1100_0011) + doAssert(a.flipMasked(0 .. 7) == 0b0011_0011) + doAssert(a.flipMasked(2 .. 3) == 0b1100_0000) + doAssert(a.clearMasked(2 .. 3) == 0b1100_0000) + doAssert(a.clearMasked(3 .. 6) == 0b1000_0100) block: # single bit operations var v: uint8 From 330b3c4453bbff572987ad7fe2f435b353529964 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 6 May 2020 08:16:54 -0700 Subject: [PATCH 0480/4254] fix regression: -d:nimHasLibFFI was not being tested anymore (#14234) * * fix regression: -d:nimHasLibFFI was not being tested anymore, in part because testament was silently treating some errors as easy to overlook messages * turned that message into an error * -d:nimHasLibFFI is now being tested with nim cpp * use correct signatures for importc procs * workaround for openbsd to unblock ctffi testing --- koch.nim | 9 ++++++--- testament/categories.nim | 2 +- tests/trunner.nim | 35 ++++++++++++++++++++++++++--------- tests/vm/mevalffi.nim | 30 +++++++++++++++++------------- 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/koch.nim b/koch.nim index 9193cb43e..017db8678 100644 --- a/koch.nim +++ b/koch.nim @@ -289,11 +289,13 @@ proc findStartNim: string = proc thVersion(i: int): string = result = ("compiler" / "nim" & $i).exe +template doUseCpp(): bool = getEnv("NIM_COMPILE_TO_CPP", "false") == "true" + proc boot(args: string) = var output = "compiler" / "nim".exe var finalDest = "bin" / "nim".exe # default to use the 'c' command: - let useCpp = getEnv("NIM_COMPILE_TO_CPP", "false") == "true" + let useCpp = doUseCpp() let smartNimcache = (if "release" in args or "danger" in args: "nimcache/r_" else: "nimcache/d_") & hostOS & "_" & hostCPU @@ -542,8 +544,9 @@ proc runCI(cmd: string) = execFold("nimble install -y libffi", "nimble install -y libffi") const nimFFI = "./bin/nim.ctffi" # no need to bootstrap with koch boot (would be slower) - execFold("build with -d:nimHasLibFFI", "nim c -d:release -d:nimHasLibFFI -o:$1 compiler/nim.nim" % [nimFFI]) - execFold("test with -d:nimHasLibFFI", "$1 c -r testament/testament --nim:$1 r tests/vm/tevalffi.nim" % [nimFFI]) + let backend = if doUseCpp(): "cpp" else: "c" + execFold("build with -d:nimHasLibFFI", "nim $1 -d:release -d:nimHasLibFFI -o:$2 compiler/nim.nim" % [backend, nimFFI]) + execFold("test with -d:nimHasLibFFI", "$1 $2 -r testament/testament --nim:$1 r tests/trunner.nim" % [nimFFI, backend]) execFold("Run nimdoc tests", "nim c -r nimdoc/tester") execFold("Run nimpretty tests", "nim c -r nimpretty/tester.nim") diff --git a/testament/categories.nim b/testament/categories.nim index e1519468f..3affe0699 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -545,7 +545,7 @@ proc processSingleTest(r: var TResults, cat: Category, options, test: string) = if existsFile(test): testSpec r, makeTest(test, options, cat), {target} else: - echo "[Warning] - ", test, " test does not exist" + doAssert false, test & " test does not exist" proc isJoinableSpec(spec: TSpec): bool = result = not spec.sortoutput and diff --git a/tests/trunner.nim b/tests/trunner.nim index 265a3712d..f71c324a2 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -1,43 +1,60 @@ discard """ + targets: "c cpp" joinable: false """ ## tests that don't quite fit the mold and are easier to handle via `execCmdEx` ## A few others could be added to here to simplify code. -import std/[strformat,os,osproc,strutils] +import std/[strformat,os,osproc] const nim = getCurrentCompilerExe() +const mode = + when defined(c): "c" + elif defined(cpp): "cpp" + else: static: doAssert false + proc runCmd(file, options = ""): auto = - let mode = if existsEnv("NIM_COMPILE_TO_CPP"): "cpp" else: "c" const testsDir = currentSourcePath().parentDir let fileabs = testsDir / file.unixToNativePath doAssert fileabs.existsFile, fileabs let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs}" result = execCmdEx(cmd) - when false: # uncomment if you need to debug - echo result[0] - echo result[1] + when false: echo result[0] & "\n" & result[1] # for debugging when defined(nimHasLibFFIEnabled): block: # mevalffi - let (output, exitCode) = runCmd("vm/mevalffi.nim", "--experimental:compiletimeFFI") - let expected = """ + when defined(openbsd): + #[ + openbsd defines `#define stderr (&__sF[2])` which makes it cumbersome + for dlopen'ing inside `importcSymbol`. Instead of adding special rules + inside `importcSymbol` to handle this, we disable just the part that's + not working and will provide a more general, clean fix in future PR. + ]# + var opt = "-d:nimEvalffiStderrWorkaround" + let prefix = "" + else: + var opt = "" + let prefix = """ hello world stderr hi stderr -foo +""" + let (output, exitCode) = runCmd("vm/mevalffi.nim", fmt"{opt} --experimental:compiletimeFFI") + let expected = fmt""" +{prefix}foo foo:100 foo:101 foo:102:103 foo:102:103:104 foo:0.03:asdf:103:105 -ret={s1:foobar s2:foobar age:25 pi:3.14} +ret=[s1:foobar s2:foobar age:25 pi:3.14] """ doAssert output == expected, output doAssert exitCode == 0 else: # don't run twice the same test + import std/[strutils] template check(msg) = doAssert msg in output, output block: # mstatic_assert diff --git a/tests/vm/mevalffi.nim b/tests/vm/mevalffi.nim index e15ed8f74..ad8f8b62b 100644 --- a/tests/vm/mevalffi.nim +++ b/tests/vm/mevalffi.nim @@ -8,9 +8,9 @@ proc c_exp(a: float64): float64 {.importc: "exp", header: "".} proc c_printf(frmt: cstring): cint {.importc: "printf", header: "", varargs, discardable.} const snprintfName = when defined(windows): "_snprintf" else: "snprintf" -proc c_snprintf*(buffer: pointer, buf_size: uint, format: cstring): cint {.importc: snprintfName, header: "", varargs .} +proc c_snprintf*(str: cstring, size: csize_t, format: cstring): cint {.importc: snprintfName, header: "", varargs .} -proc c_malloc(size:uint):pointer {.importc:"malloc", header: "".} +proc c_malloc(size: csize_t): pointer {.importc:"malloc", header: "".} proc c_free(p: pointer) {.importc:"free", header: "".} proc fun() = @@ -35,12 +35,15 @@ proc fun() = block: # c_snprintf, c_malloc, c_free let n: uint = 50 - var buffer2: pointer = c_malloc(n) + var buffer2 = cstring(cast[ptr char](c_malloc(n))) + var s: cstring = "foobar" var age: cint = 25 - discard c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14) - c_printf("ret={%s}\n", buffer2) - c_free(buffer2) # not sure it has an effect + let num = c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14) + let numExp = 34 + doAssert num == numExp + c_printf("ret=[%s]\n", buffer2) + c_free(buffer2) block: # c_printf bug var a = 123 @@ -58,10 +61,11 @@ static: fun() fun() -import system/ansi_c -block: - proc fun2()= - c_fprintf(cstderr, "hello world stderr\n") - write(stderr, "hi stderr\n") - static: fun2() - fun2() +when not defined nimEvalffiStderrWorkaround: + import system/ansi_c + block: + proc fun2()= + c_fprintf(cstderr, "hello world stderr\n") + write(stderr, "hi stderr\n") + static: fun2() + fun2() From 1b2b32169a5d8089a50509136a31b5ceb3773994 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 6 May 2020 15:37:26 +0200 Subject: [PATCH 0481/4254] cleanup the CC setting, only leave in there what is at least semi-officially supported --- compiler/extccomp.nim | 120 ------------------------------------------ compiler/options.nim | 4 +- 2 files changed, 2 insertions(+), 122 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index fe48093dd..23cbc482c 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -138,16 +138,6 @@ compiler clang: result.compilerExe = "clang" result.cppCompiler = "clang++" -# Zig cc (Clang) C/C++ Compiler -compiler zig: - result = clang() # Uses settings from llvmGcc - - result.name = "zig" - result.compilerExe = "zig" - result.cppCompiler = "zig" - result.compileTmpl = "cc " & result.compileTmpl - result.linkTmpl = "cc " & result.linkTmpl - # Microsoft Visual C/C++ Compiler compiler vcc: result = ( @@ -196,32 +186,6 @@ compiler icc: result.compilerExe = "icc" result.linkerExe = "icc" -# Local C Compiler -compiler lcc: - result = ( - name: "lcc", - objExt: "obj", - optSpeed: " -O -p6 ", - optSize: " -O -p6 ", - compilerExe: "lcc", - cppCompiler: "", - compileTmpl: "$options $include -Fo$objfile $file", - buildGui: " -subsystem windows", - buildDll: " -dll", - buildLib: "", # XXX: not supported yet - linkerExe: "lcclnk", - linkTmpl: "$options $buildgui $builddll -O $exefile $objfiles", - includeCmd: " -I", - linkDirCmd: "", # XXX: not supported yet - linkLibCmd: "", # XXX: not supported yet - debug: " -g5 ", - pic: "", - asmStmtFrmt: "_asm{$n$1$n}$n", - structStmtFmt: "$1 $2", - produceAsm: "", - cppXsupport: "", - props: {}) - # Borland C Compiler compiler bcc: result = ( @@ -249,58 +213,6 @@ compiler bcc: props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasAttribute}) -# Digital Mars C Compiler -compiler dmc: - result = ( - name: "dmc", - objExt: "obj", - optSpeed: " -ff -o -6 ", - optSize: " -ff -o -6 ", - compilerExe: "dmc", - cppCompiler: "", - compileTmpl: "-c $options $include -o$objfile $file", - buildGui: " -L/exet:nt/su:windows", - buildDll: " -WD", - buildLib: "", # XXX: not supported yet - linkerExe: "dmc", - linkTmpl: "$options $buildgui $builddll -o$exefile $objfiles", - includeCmd: " -I", - linkDirCmd: "", # XXX: not supported yet - linkLibCmd: "", # XXX: not supported yet - debug: " -g ", - pic: "", - asmStmtFrmt: "__asm{$n$1$n}$n", - structStmtFmt: "$3$n$1 $2", - produceAsm: "", - cppXsupport: "", - props: {hasCpp}) - -# Watcom C Compiler -compiler wcc: - result = ( - name: "wcc", - objExt: "obj", - optSpeed: " -ox -on -6 -d0 -fp6 -zW ", - optSize: "", - compilerExe: "wcl386", - cppCompiler: "", - compileTmpl: "-c $options $include -fo=$objfile $file", - buildGui: " -bw", - buildDll: " -bd", - buildLib: "", # XXX: not supported yet - linkerExe: "wcl386", - linkTmpl: "$options $buildgui $builddll -fe=$exefile $objfiles ", - includeCmd: " -i=", - linkDirCmd: "", # XXX: not supported yet - linkLibCmd: "", # XXX: not supported yet - debug: " -d2 ", - pic: "", - asmStmtFrmt: "__asm{$n$1$n}$n", - structStmtFmt: "$1 $2", - produceAsm: "", - cppXsupport: "", - props: {hasCpp}) - # Tiny C Compiler compiler tcc: result = ( @@ -327,33 +239,6 @@ compiler tcc: cppXsupport: "", props: {hasSwitchRange, hasComputedGoto, hasGnuAsm}) -# Pelles C Compiler -compiler pcc: - # Pelles C - result = ( - name: "pcc", - objExt: "obj", - optSpeed: " -Ox ", - optSize: " -Os ", - compilerExe: "cc", - cppCompiler: "", - compileTmpl: "-c $options $include -Fo$objfile $file", - buildGui: " -SUBSYSTEM:WINDOWS", - buildDll: " -DLL", - buildLib: "", # XXX: not supported yet - linkerExe: "cc", - linkTmpl: "$options $buildgui $builddll -OUT:$exefile $objfiles", - includeCmd: " -I", - linkDirCmd: "", # XXX: not supported yet - linkLibCmd: "", # XXX: not supported yet - debug: " -Zi ", - pic: "", - asmStmtFrmt: "__asm{$n$1$n}$n", - structStmtFmt: "$1 $2", - produceAsm: "", - cppXsupport: "", - props: {}) - # Your C Compiler compiler ucc: result = ( @@ -386,14 +271,9 @@ const nintendoSwitchGCC(), llvmGcc(), clang(), - zig(), - lcc(), bcc(), - dmc(), - wcc(), vcc(), tcc(), - pcc(), ucc(), icl(), icc(), diff --git a/compiler/options.nim b/compiler/options.nim index 97cf435c5..caf3f65bd 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -164,8 +164,8 @@ type disabledSf, writeOnlySf, readOnlySf, v2Sf TSystemCC* = enum - ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccZig, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, - ccTcc, ccPcc, ccUcc, ccIcl, ccIcc, ccClangCl + ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc, + ccTcc, ccUcc, ccIcl, ccIcc, ccClangCl ExceptionSystem* = enum excNone, # no exception system selected yet From c64db68f0b2ff8e0f94baa583b94fd9409c77057 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 6 May 2020 17:14:38 +0200 Subject: [PATCH 0482/4254] added a new feature: --cc:env so that you can use any C compiler as long as it works like GCC --- compiler/extccomp.nim | 38 ++++++++++++++++++++++++++------------ compiler/options.nim | 2 +- doc/nimc.rst | 4 ++++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 23cbc482c..7c255484d 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -240,15 +240,15 @@ compiler tcc: props: {hasSwitchRange, hasComputedGoto, hasGnuAsm}) # Your C Compiler -compiler ucc: +compiler envcc: result = ( - name: "ucc", + name: "env", objExt: "o", optSpeed: " -O3 ", optSize: " -O1 ", - compilerExe: "cc", + compilerExe: "", cppCompiler: "", - compileTmpl: "-c $options $include -o $objfile $file", + compileTmpl: "-c $ccenvflags $options $include -o $objfile $file", buildGui: "", buildDll: " -shared ", buildLib: "", # XXX: not supported yet @@ -263,7 +263,7 @@ compiler ucc: structStmtFmt: "$1 $2", produceAsm: "", cppXsupport: "", - props: {}) + props: {hasGnuAsm}) const CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [ @@ -274,7 +274,7 @@ const bcc(), vcc(), tcc(), - ucc(), + envcc(), icl(), icc(), clangcl()] @@ -483,11 +483,23 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} = proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool = conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c") +proc envFlags(conf: ConfigRef): string = + result = if conf.cmd == cmdCompileToCpp: + getEnv("CXXFLAGS") + else: + getEnv("CFLAGS") + proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string = - result = if useCpp(conf, cfile): - CC[compiler].cppCompiler - else: - CC[compiler].compilerExe + if compiler == ccEnv: + result = if useCpp(conf, cfile): + getEnv("CXX") + else: + getEnv("CC") + else: + result = if useCpp(conf, cfile): + CC[compiler].cppCompiler + else: + CC[compiler].compilerExe if result.len == 0: rawMessage(conf, errGenerated, "Compiler '$1' doesn't support the requested target" % @@ -581,7 +593,8 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, "dfile", dfile, "file", cfsh, "objfile", quoteShell(objfile), "options", options, "include", includeCmd, "nim", getPrefixDir(conf).string, - "lib", conf.libpath.string]) + "lib", conf.libpath.string, + "ccenvflags", envFlags(conf)]) if optProduceAsm in conf.globalOptions: if CC[conf.cCompiler].produceAsm.len > 0: @@ -601,7 +614,8 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, "options", options, "include", includeCmd, "nim", quoteShell(getPrefixDir(conf)), "lib", quoteShell(conf.libpath), - "vccplatform", vccplatform(conf)]) + "vccplatform", vccplatform(conf), + "ccenvflags", envFlags(conf)]) proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = result = secureHash( diff --git a/compiler/options.nim b/compiler/options.nim index caf3f65bd..5475bc07b 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -165,7 +165,7 @@ type TSystemCC* = enum ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc, - ccTcc, ccUcc, ccIcl, ccIcc, ccClangCl + ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl ExceptionSystem* = enum excNone, # no exception system selected yet diff --git a/doc/nimc.rst b/doc/nimc.rst index 7fdceacf5..59289a7c8 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -240,6 +240,10 @@ add the ``-f`` flag to force all files to be recompiled. The default compiler is defined at the top of ``config\nim.cfg``. Changing this setting affects the compiler used by ``koch`` to (re)build Nim. +To use the ``CC`` environment variable, use ``nim c --cc:env myfile.nim``. To use the +``CXX`` environment variable, use ``nim cpp --cc:env myfile.nim``. ``--cc:env`` is available +since Nim version 1.4. + Cross compilation ================= From b70b8a7cdd8c82b3d7e87d767899327304d05d57 Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Wed, 6 May 2020 12:29:36 -0500 Subject: [PATCH 0483/4254] Fix runnable examples for bitops (#14247) --- lib/pure/bitops.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 6aeec3092..7dd171a38 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -156,7 +156,7 @@ when defined(nimHasalignOf): runnableExamples: var v = 0b0000_0011'u8 v.mask(0b0000_1010'u8) - doAssert v == 0b0000_1010'u8 + doAssert v == 0b0000_0010'u8 v = bitand(v, mask) @@ -272,7 +272,7 @@ when defined(nimHasalignOf): ## Effectively maps to a `bitxor` operation. runnableExamples: var v = 0b0000_0011'u8 - doAssert v.flipMasked(1 .. 3) == 0b0000_1001'u8 + doAssert v.flipMasked(1 .. 3) == 0b0000_1101'u8 bitxor(v, toMask[T](slice)) @@ -294,7 +294,7 @@ when defined(nimHasalignOf): runnableExamples: var v = 0b0000_0011'u8 v.flipMask(1 .. 3) - doAssert v == 0b0000_1001'u8 + doAssert v == 0b0000_1101'u8 v = bitxor(v, toMask[T](slice)) From 6dba06f9e63083d4cbcd09b10aaf2342b70821b0 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 6 May 2020 19:43:18 +0100 Subject: [PATCH 0484/4254] fixes #14244 (#14248) Co-authored-by: cooldome --- compiler/liftdestructors.nim | 12 ++++++------ tests/arc/tcaseobj.nim | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 5959e24c5..f2a7ba3c9 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -780,11 +780,11 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; typ.attachedOps[kind] = baseType.attachedOps[kind] result = typ.attachedOps[kind] -proc symPrototype(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp; +proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp; info: TLineInfo): PSym = let procname = getIdent(g.cache, AttachedOpToStr[kind]) - result = newSym(skProc, procname, typ.owner, info) + result = newSym(skProc, procname, owner, info) let dest = newSym(skParam, getIdent(g.cache, "dest"), result, info) let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), result, info) dest.typ = makeVarType(typ.owner, typ) @@ -793,7 +793,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp; else: src.typ = typ - result.typ = newProcType(info, typ.owner) + result.typ = newProcType(info, owner) result.typ.addParam dest if kind notin {attachedDestructor, attachedDispose}: result.typ.addParam src @@ -813,7 +813,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; if typ.kind == tyDistinct: return produceSymDistinctType(g, c, typ, kind, info) - result = symPrototype(g, typ, kind, info) + result = symPrototype(g, typ, typ.owner, kind, info) var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType:typ) a.fn = result @@ -847,8 +847,8 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, info: TLineInfo): PSym = - assert(typ.kind == tyObject) - result = symPrototype(g, field.typ, attachedDestructor, info) + assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject) + result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info) var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ) a.fn = result a.asgnForType = typ diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim index 99ea19fa2..dd02675cc 100644 --- a/tests/arc/tcaseobj.nim +++ b/tests/arc/tcaseobj.nim @@ -9,6 +9,7 @@ B begin end prevented +(ok: true, value: "ok") myobj destroyed ''' """ @@ -193,3 +194,21 @@ proc test_myobject = test_myobject() + + +#------------------------------------------------ +# bug #14244 + +type + RocksDBResult*[T] = object + case ok*: bool + of true: + value*: T + else: + error*: string + +proc init(): RocksDBResult[string] = + result.ok = true + result.value = "ok" + +echo init() From 0d8507cd3da4f8c5ec3d7a627bb2c8918ff804c8 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 6 May 2020 23:13:59 +0100 Subject: [PATCH 0485/4254] fix #14236 (#14250) Co-authored-by: cooldome --- compiler/liftdestructors.nim | 6 +++--- tests/arc/tarcmisc.nim | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index f2a7ba3c9..6f4e5828d 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -764,11 +764,11 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped, - tyTypeDesc, tyGenericInvocation, tyForward: + tyTypeDesc, tyGenericInvocation, tyForward, tyStatic: #internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t)) discard of tyOrdinal, tyRange, tyInferred, - tyGenericInst, tyStatic, tyAlias, tySink: + tyGenericInst, tyAlias, tySink: fillBody(c, lastSon(t), body, x, y) proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; @@ -916,7 +916,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf incl orig.flags, tfCheckedForDestructor let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink}) - if isEmptyContainer(skipped): return + if isEmptyContainer(skipped) or skipped.kind == tyStatic: return let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct}) var canon = g.canonTypes.getOrDefault(h) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index c0583a640..953e2f3a7 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -89,3 +89,19 @@ let assert n.sortedByIt(it) == @["b", "c"], "fine" assert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" + + +#------------------------------------------------------------------------------ +# issue #14236 + +type + MyType = object + a: seq[int] + +proc re(x: static[string]): static MyType = + MyType() + +proc match(inp: string, rg: static MyType) = + doAssert rg.a.len == 0 + +match("ac", re"a(b|c)") \ No newline at end of file From 5a9b3c27c1882eb1b7ab8845e4ff0c8a3c9f5835 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 7 May 2020 10:08:05 +0200 Subject: [PATCH 0486/4254] Split testing important packages into two jobs (#14256) * split testing packages in two separate jobs * speed-up the slowest tests * special treatment for two packages --- .github/workflows/ci_packages.yml | 2 +- koch.nim | 6 +- testament/categories.nim | 26 ++- testament/important_packages.nim | 257 ++++++++++++++++-------------- 4 files changed, 157 insertions(+), 134 deletions(-) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 9d2d044ff..53e698022 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -8,7 +8,7 @@ jobs: matrix: os: [ubuntu-18.04, macos-10.15] cpu: [amd64] - pkg: [true] + pkg: [1, 2] name: '${{ matrix.os }} (pkg: ${{ matrix.pkg }})' runs-on: ${{ matrix.os }} env: diff --git a/koch.nim b/koch.nim index 017db8678..8b7eecf7c 100644 --- a/koch.nim +++ b/koch.nim @@ -526,8 +526,10 @@ proc runCI(cmd: string) = ## build nimble early on to enable remainder to depend on it if needed kochExecFold("Build Nimble", "nimble") - if getEnv("NIM_TEST_PACKAGES", "false") == "true": - execFold("Test selected Nimble packages", "nim c -r testament/testament cat nimble-packages") + if getEnv("NIM_TEST_PACKAGES", "0") == "1": + execFold("Test selected Nimble packages (1)", "nim c -r testament/testament cat nimble-packages-1") + elif getEnv("NIM_TEST_PACKAGES", "0") == "2": + execFold("Test selected Nimble packages (2)", "nim c -r testament/testament cat nimble-packages-2") else: buildTools() diff --git a/testament/categories.nim b/testament/categories.nim index 3affe0699..d60b89e33 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -29,7 +29,8 @@ const "lib", "longgc", "manyloc", - "nimble-packages", + "nimble-packages-1", + "nimble-packages-2", "niminaction", "rodfiles", "threads", @@ -448,9 +449,18 @@ let nimbleExe = findExe("nimble") packageIndex = nimbleDir / "packages_official.json" -iterator listPackages(): tuple[name, url, cmd: string, hasDeps: bool] = +type + PkgPart = enum + ppOne + ppTwo + +iterator listPackages(part: PkgPart): tuple[name, url, cmd: string, hasDeps: bool] = let packageList = parseFile(packageIndex) - for n, cmd, hasDeps, url in important_packages.packages.items: + let importantList = + case part + of ppOne: important_packages.packages1 + of ppTwo: important_packages.packages2 + for n, cmd, hasDeps, url in importantList.items: if url.len != 0: yield (n, url, cmd, hasDeps) else: @@ -471,7 +481,7 @@ proc makeSupTest(test, options: string, cat: Category): TTest = result.options = options result.startTime = epochTime() -proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = +proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string, part: PkgPart) = if nimbleExe == "": echo "[Warning] - Cannot run nimble tests: Nimble binary not found." return @@ -483,7 +493,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = let packagesDir = "pkgstemp" var errors = 0 try: - for name, url, cmd, hasDep in listPackages(): + for name, url, cmd, hasDep in listPackages(part): if packageFilter notin name: continue inc r.total @@ -700,8 +710,10 @@ proc processCategory(r: var TResults, cat: Category, compileExample(r, "examples/*.nim", options, cat) compileExample(r, "examples/gtk/*.nim", options, cat) compileExample(r, "examples/talk/*.nim", options, cat) - of "nimble-packages": - testNimblePackages(r, cat, options) + of "nimble-packages-1": + testNimblePackages(r, cat, options, ppOne) + of "nimble-packages-2": + testNimblePackages(r, cat, options, ppTwo) of "niminaction": testNimInAction(r, cat, options) of "untestable": diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 02cb3e3fe..243856d5e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -1,135 +1,144 @@ import os -template pkg(name: string; hasDeps = false; cmd = "nimble test"; url = ""): untyped = - packages.add((name, cmd, hasDeps, url)) +template pkg1(name: string; hasDeps = false; cmd = "nimble test"; url = ""): untyped = + packages1.add((name, cmd, hasDeps, url)) -var packages*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[] +template pkg2(name: string; hasDeps = false; cmd = "nimble test"; url = ""): untyped = + packages2.add((name, cmd, hasDeps, url)) -pkg "alea", true -pkg "argparse" -pkg "arraymancer", true, "nim c tests/tests_cpu.nim" -pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" -pkg "asyncmysql", true -pkg "awk", true -pkg "bigints" -pkg "binaryheap", false, "nim c -r binaryheap.nim" -pkg "BipBuffer" -# pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39 -pkg "bncurve", true -pkg "brainfuck", true -pkg "bump", true, "nimble test", "https://github.com/disruptek/bump" -pkg "c2nim", false, "nim c testsuite/tester.nim" -pkg "cascade" -pkg "cello", true -pkg "chroma" -pkg "chronicles", true, "nim c -o:chr -r chronicles.nim" +var packages1*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[] +var packages2*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[] + + +# packages A-M +pkg1 "alea", true +pkg1 "argparse" +pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" +pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" +pkg1 "asyncmysql", true +pkg1 "awk", true +pkg1 "bigints" +pkg1 "binaryheap", false, "nim c -r binaryheap.nim" +pkg1 "BipBuffer" +# pkg1 "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39 +pkg1 "bncurve", true, "nim c -r tests/tvectors.nim" +pkg1 "brainfuck", true, "nim c -r tests/compile.nim" +pkg1 "bump", true, "nim c --gc:arc -r tests/tbump.nim", "https://github.com/disruptek/bump" +pkg1 "c2nim", false, "nim c testsuite/tester.nim" +pkg1 "cascade" +pkg1 "cello", true +pkg1 "chroma" +pkg1 "chronicles", true, "nim c -o:chr -r chronicles.nim" when not defined(osx): # testdatagram.nim(560, 54): Check failed - pkg "chronos", true -pkg "cligen", false, "nim c -o:cligenn -r cligen.nim" -pkg "coco", true -pkg "combparser" -pkg "compactdict" -pkg "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" -pkg "criterion" -pkg "dashing", false, "nim c tests/functional.nim" -pkg "delaunay" -pkg "docopt" -pkg "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" -pkg "elvis" -pkg "fidget", true, "nim c -r tests/runNative.nim" -pkg "fragments", false, "nim c -r fragments/dsl.nim" -pkg "gara" -pkg "ggplotnim", true, "nimble testCI" -# pkg "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" -pkg "glob" -pkg "gnuplot" -pkg "hts", false, "nim c -o:htss src/hts.nim" -# pkg "httpauth", true -pkg "illwill", false, "nimble examples" -pkg "inim", true -pkg "itertools", false, "nim doc src/itertools.nim" -pkg "iterutils" -pkg "jstin" -pkg "karax", false, "nim c -r tests/tester.nim" -pkg "kdtree", false, "nimble test", "https://github.com/jblindsay/kdtree" -pkg "loopfusion" -pkg "macroutils" -pkg "markdown" -pkg "memo" -pkg "msgpack4nim" -pkg "nake", false, "nim c nakefile.nim" -pkg "neo", true, "nim c -d:blas=openblas tests/all.nim" -pkg "nesm" -# pkg "nico", true -pkg "nicy", false, "nim c -r src/nicy.nim" + pkg1 "chronos", true, "nim c -r -d:release tests/testall" +pkg1 "cligen", false, "nim c -o:cligenn -r cligen.nim" +pkg1 "coco", true +pkg1 "combparser" +pkg1 "compactdict" +pkg1 "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" +pkg1 "criterion" +pkg1 "dashing", false, "nim c tests/functional.nim" +pkg1 "delaunay" +pkg1 "docopt" +pkg1 "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" +pkg1 "elvis" +pkg1 "fidget", true, "nim c -r tests/runNative.nim" +pkg1 "fragments", false, "nim c -r fragments/dsl.nim" +pkg1 "gara" +pkg1 "ggplotnim", true, "nim c -d:noCairo -r tests/tests.nim" +# pkg1 "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" +pkg1 "glob" +pkg1 "gnuplot" +pkg1 "hts", false, "nim c -o:htss src/hts.nim" +# pkg1 "httpauth", true +pkg1 "illwill", false, "nimble examples" +pkg1 "inim", true # pending https://github.com/inim-repl/INim/issues/74 +pkg1 "itertools", false, "nim doc src/itertools.nim" +pkg1 "iterutils" +pkg1 "jstin" +pkg1 "karax", false, "nim c -r tests/tester.nim" +pkg1 "kdtree", false, "nimble test", "https://github.com/jblindsay/kdtree" +pkg1 "loopfusion" +pkg1 "macroutils" +pkg1 "markdown" +pkg1 "memo" +pkg1 "msgpack4nim", false, "nim c -r tests/test_spec.nim" +# these two are special snowflakes +pkg1 "nimcrypto", false, "nim c -r tests/testall.nim" +pkg1 "stint", false, "nim c -o:stintt -r stint.nim" + + +# packages N-Z +pkg2 "nake", false, "nim c nakefile.nim" +pkg2 "neo", true, "nim c -d:blas=openblas tests/all.nim" +pkg2 "nesm" +# pkg2 "nico", true +pkg2 "nicy", false, "nim c -r src/nicy.nim" when defined(osx): # xxx: do this more generally by installing non-nim dependencies automatically # as specified in nimble file and calling `distros.foreignDepInstallCmd`, but # it currently would fail work if a package is already installed. doAssert execShellCmd("brew ls --versions gtk+3 || brew install gtk+3") == 0 -pkg "nigui", false, "nim c -o:niguii -r src/nigui.nim" - -pkg "nimcrypto", false, "nim c -r tests/testall.nim" -pkg "NimData", true, "nim c -o:nimdataa src/nimdata.nim" -pkg "nimes", true, "nim c src/nimes.nim" -pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim" -pkg "nimgame2", true, "nim c nimgame2/nimgame.nim" -pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim" -pkg "nimlsp", true -pkg "nimly", true -# pkg "nimongo", true, "nimble test_ci" -# pkg "nimph", true, "nimble test", "https://github.com/disruptek/nimph" -pkg "nimpy", false, "nim c -r tests/nimfrompy.nim" -pkg "nimquery" -pkg "nimsl", true -pkg "nimsvg" -# pkg "nimterop", true -pkg "nimwc", true, "nim c nimwc.nim" -pkg "nimx", true, "nim c --threads:on test/main.nim" -pkg "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" -pkg "norm", true, "nim c -r tests/tsqlite.nim" -pkg "npeg" -pkg "numericalnim", true -pkg "optionsutils" -pkg "ormin", true, "nim c -o:orminn ormin.nim" -pkg "parsetoml" -pkg "patty" -pkg "plotly", true, "nim c --oldgensym:on examples/all.nim" -pkg "pnm" -pkg "polypbren" -pkg "prologue", true, "nim c -r tests/test_compile/test_compile.nim" -pkg "protobuf", true, "nim c -o:protobuff -r src/protobuf.nim" -pkg "pylib" -pkg "rbtree" -pkg "react", false, "nimble example" -pkg "regex", true, "nim c src/regex" -pkg "result", false, "nim c -r result.nim" -pkg "RollingHash" -pkg "rosencrantz", false, "nim c -o:rsncntz -r rosencrantz.nim" -pkg "sdl1", false, "nim c -r src/sdl.nim" -pkg "sdl2_nim", false, "nim c -r sdl2/sdl.nim" -pkg "sigv4", true, "nimble test", "https://github.com/disruptek/sigv4" -pkg "snip", false, "nimble test", "https://github.com/genotrance/snip" -pkg "stint", false, "nim c -o:stintt -r stint.nim" -pkg "strslice" -pkg "strunicode", true, "nim c -r src/strunicode.nim" -pkg "synthesis" -pkg "telebot", true, "nim c -o:tbot -r src/telebot.nim" -pkg "tempdir" -pkg "templates" -pkg "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" -pkg "terminaltables", false, "nim c src/terminaltables.nim" -pkg "termstyle" -pkg "timeit" -pkg "timezones" -pkg "tiny_sqlite" -pkg "unicodedb" -pkg "unicodeplus", true -pkg "unpack" -pkg "websocket", false, "nim c websocket.nim" -# pkg "winim", true -pkg "with" -pkg "ws" -pkg "yaml" -pkg "zero_functional", false, "nim c -r test.nim" +pkg2 "nigui", false, "nim c -o:niguii -r src/nigui.nim" +pkg2 "NimData", true, "nim c -o:nimdataa src/nimdata.nim" +pkg2 "nimes", true, "nim c src/nimes.nim" +pkg2 "nimfp", true, "nim c -o:nfp -r src/fp.nim" +pkg2 "nimgame2", true, "nim c nimgame2/nimgame.nim" +pkg2 "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim" +pkg2 "nimlsp", true +pkg2 "nimly", true, "nim c -r tests/test_readme_example.nim" +# pkg2 "nimongo", true, "nimble test_ci" +# pkg2 "nimph", true, "nimble test", "https://github.com/disruptek/nimph" +pkg2 "nimpy", false, "nim c -r tests/nimfrompy.nim" +pkg2 "nimquery" +pkg2 "nimsl", true +pkg2 "nimsvg" +# pkg2 "nimterop", true +pkg2 "nimwc", true, "nim c nimwc.nim" +pkg2 "nimx", true, "nim c --threads:on test/main.nim" +pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" +pkg2 "norm", true, "nim c -r tests/tsqlite.nim" +pkg2 "npeg", false, "nimble testarc" +pkg2 "numericalnim", true, "nim c -r tests/test_integrate.nim" +pkg2 "optionsutils" +pkg2 "ormin", true, "nim c -o:orminn ormin.nim" +pkg2 "parsetoml" +pkg2 "patty" +pkg2 "plotly", true, "nim c --oldgensym:on examples/all.nim" +pkg2 "pnm" +pkg2 "polypbren" +pkg2 "prologue", true, "nim c -r tests/test_compile/test_compile.nim" +pkg2 "protobuf", true, "nim c -o:protobuff -r src/protobuf.nim" +pkg2 "pylib" +pkg2 "rbtree" +pkg2 "react", false, "nimble example" +pkg2 "regex", true, "nim c src/regex" +pkg2 "result", false, "nim c -r result.nim" +pkg2 "RollingHash", false, "nim c -r tests/test_cyclichash.nim" +pkg2 "rosencrantz", false, "nim c -o:rsncntz -r rosencrantz.nim" +pkg2 "sdl1", false, "nim c -r src/sdl.nim" +pkg2 "sdl2_nim", false, "nim c -r sdl2/sdl.nim" +pkg2 "sigv4", true, "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" +pkg2 "snip", false, "nimble test", "https://github.com/genotrance/snip" +pkg2 "strslice" +pkg2 "strunicode", true, "nim c -r src/strunicode.nim" +pkg2 "synthesis" +pkg2 "telebot", true, "nim c -o:tbot -r src/telebot.nim" +pkg2 "tempdir" +pkg2 "templates" +pkg2 "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" +pkg2 "terminaltables", false, "nim c src/terminaltables.nim" +pkg2 "termstyle" +pkg2 "timeit" +pkg2 "timezones" +pkg2 "tiny_sqlite" +pkg2 "unicodedb" +pkg2 "unicodeplus", true +pkg2 "unpack" +pkg2 "websocket", false, "nim c websocket.nim" +# pkg2 "winim", true +pkg2 "with" +pkg2 "ws" +pkg2 "yaml" +pkg2 "zero_functional", false, "nim c -r test.nim" From 1a1e9986a34822d16cd20ec5b2a908a10677f4fd Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 7 May 2020 11:37:54 +0000 Subject: [PATCH 0487/4254] net: remove more erroneous set constructions (#14252) [backport] Refs #13764 --- lib/pure/net.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 10589ac12..b08629a96 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -180,11 +180,16 @@ proc isDisconnectionError*(flags: set[SocketFlag], ## if flags contains ``SafeDisconn``. when useWinVersion: SocketFlag.SafeDisconn in flags and - lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET, - WSAEDISCON, ERROR_NETNAME_DELETED} + (lastError.int32 == WSAECONNRESET or + lastError.int32 == WSAECONNABORTED or + lastError.int32 == WSAENETRESET or + lastError.int32 == WSAEDISCON or + lastError.int32 == ERROR_NETNAME_DELETED) else: SocketFlag.SafeDisconn in flags and - lastError.int32 in {ECONNRESET, EPIPE, ENETRESET} + (lastError.int32 == ECONNRESET or + lastError.int32 == EPIPE or + lastError.int32 == ENETRESET) proc toOSFlags*(socketFlags: set[SocketFlag]): cint = ## Converts the flags into the underlying OS representation. From 42db75c9707d6501cb1ef1908e7092286b25ac45 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 7 May 2020 21:41:55 +0200 Subject: [PATCH 0488/4254] Fix the DFA for "unstructured controlflow" (#14263) * Fix the DFA for "unstructured controlflow" * Add testcase from #14233 --- compiler/dfa.nim | 191 ++++++++++++++++++++------------- compiler/injectdestructors.nim | 8 +- tests/arc/tcontrolflow.nim | 24 +++++ 3 files changed, 142 insertions(+), 81 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 7db5f5f65..f6566f77b 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -45,16 +45,22 @@ type ControlFlowGraph* = seq[Instr] TPosition = distinct int + TBlock = object - label: PSym - fixups: seq[TPosition] + joins: seq[Instr] + forks: seq[TPosition] + case isTryBlock: bool + of false: + label: PSym + breakFixups: seq[(TPosition, seq[PNode])] #Contains the gotos for the breaks along with their pending finales + of true: + finale: PNode + raiseFixups: seq[TPosition] #Contains the gotos for the raises Con = object code: ControlFlowGraph inCall, inTryStmt: int blocks: seq[TBlock] - tryStmtFixups: seq[TPosition] - forks: seq[TPosition] owner: PSym proc debugInfo(info: TLineInfo): string = @@ -96,7 +102,7 @@ proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} = proc forkI(c: var Con; n: PNode): TPosition = result = TPosition(c.code.len) c.code.add Instr(n: n, kind: fork, dest: 0) - c.forks.add result + c.blocks[^1].forks.add result proc gotoI(c: var Con; n: PNode): TPosition = result = TPosition(c.code.len) @@ -271,14 +277,27 @@ proc patch(c: var Con, p: TPosition) = doAssert(low(int) div 2 + 1 < diff and diff < high(int) div 2) c.code[p].dest = diff +proc gen(c: var Con; n: PNode) # {.noSideEffect.} + proc popBlock(c: var Con; oldLen: int) = - for f in c.blocks[oldLen].fixups: - c.patch(f) + var exits: seq[TPosition] + exits.add c.gotoI(newNode(nkEmpty)) + for f in c.blocks[oldLen].breakFixups: + c.patch(f[0]) + for finale in f[1]: + c.gen(finale) + exits.add c.gotoI(newNode(nkEmpty)) + for e in exits: + c.patch e + for j in c.blocks[oldLen].joins: + var patchedJ = j + patchedJ.dest -= c.code.len + c.code.add patchedJ c.blocks.setLen(oldLen) template withBlock(labl: PSym; body: untyped) {.dirty.} = var oldLen {.gensym.} = c.blocks.len - c.blocks.add TBlock(label: labl, fixups: @[]) + c.blocks.add TBlock(isTryBlock: false, label: labl) body popBlock(c, oldLen) @@ -286,8 +305,6 @@ proc isTrue(n: PNode): bool = n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or n.kind == nkIntLit and n.intVal != 0 -proc gen(c: var Con; n: PNode) # {.noSideEffect.} - when true: proc genWhile(c: var Con; n: PNode) = # We unroll every loop 3 times. We emulate 0, 1, 2 iterations @@ -299,12 +316,13 @@ when true: Becomes: - if cond: - body + block: if cond: body if cond: body + if cond: + body We still need to ensure 'break' resolves properly, so an AST to AST translation is impossible. @@ -330,22 +348,22 @@ when true: if isTrue(n[0]): # 'while true' is an idiom in Nim and so we produce # better code for it: - for i in 0..2: - withBlock(nil): + withBlock(nil): + for i in 0..2: c.gen(n[1]) else: - let oldForksLen = c.forks.len - var endings: array[3, TPosition] - for i in 0..2: - withBlock(nil): + withBlock(nil): + let oldForksLen = c.blocks[^1].forks.len + var endings: array[3, TPosition] + for i in 0..2: c.gen(n[0]) endings[i] = c.forkI(n) c.gen(n[1]) - for i in countdown(endings.high, 0): - let endPos = endings[i] - c.patch(endPos) - c.joinI(c.forks.pop(), n) - doAssert(c.forks.len == oldForksLen) + for i in countdown(endings.high, 0): + let endPos = endings[i] + c.patch(endPos) + c.joinI(c.blocks[^1].forks.pop(), n) + doAssert(c.blocks[^1].forks.len == oldForksLen) else: @@ -356,7 +374,7 @@ else: # body # jmp lab1 # lab2: - let oldForksLen = c.forks.len + let oldForksLen = c.blocks[^1].forks.len let lab1 = c.genLabel withBlock(nil): if isTrue(n[0]): @@ -368,35 +386,15 @@ else: c.gen(n[1]) c.jmpBack(n, lab1) c.patch(lab2) - setLen(c.forks, oldForksLen) - -proc genBlock(c: var Con; n: PNode) = - withBlock(n[0].sym): - c.gen(n[1]) - -proc genJoins(c: var Con; n: PNode) = - for i in countdown(c.forks.high, 0): joinI(c, c.forks[i], n) - -proc genBreak(c: var Con; n: PNode) = - genJoins(c, n) - let lab1 = c.gotoI(n) - if n[0].kind == nkSym: - #echo cast[int](n[0].sym) - for i in countdown(c.blocks.len-1, 0): - if c.blocks[i].label == n[0].sym: - c.blocks[i].fixups.add lab1 - return - #globalError(n.info, "VM problem: cannot find 'break' target") - else: - c.blocks[c.blocks.high].fixups.add lab1 + setLen(c.blocks[^1].forks, oldForksLen) template forkT(n, body) = - let oldLen = c.forks.len + let oldLen = c.blocks[^1].forks.len let lab1 = c.forkI(n) body c.patch(lab1) c.joinI(lab1, n) - setLen(c.forks, oldLen) + setLen(c.blocks[^1].forks, oldLen) proc genIf(c: var Con, n: PNode) = #[ @@ -435,7 +433,7 @@ proc genIf(c: var Con, n: PNode) = join F1 ]# - let oldLen = c.forks.len + let oldLen = c.blocks[^1].forks.len var endings: seq[TPosition] = @[] for i in 0.. 0: #Ok, we are in a try, lets see which (if any) try's we break out from: + for b in countdown(c.blocks.high, i): + if c.blocks[b].isTryBlock: + trailingFinales.add c.blocks[b].finale + + c.blocks[i].breakFixups.add (lab1, trailingFinales) + + for b in countdown(c.blocks.high, i): + for f in countdown(c.blocks[b].forks.high, 0): + c.blocks[i].joins.add Instr(n: n, kind: join, dest: c.blocks[b].forks[f].int) + +proc genBreak(c: var Con; n: PNode) = + if n[0].kind == nkSym: + #echo cast[int](n[0].sym) + for i in countdown(c.blocks.high, 0): + if not c.blocks[i].isTryBlock and c.blocks[i].label == n[0].sym: + genBreakOrRaiseAux(c, i, n) + return + #globalError(n.info, "VM problem: cannot find 'break' target") + else: + for i in countdown(c.blocks.high, 0): + if not c.blocks[i].isTryBlock: + genBreakOrRaiseAux(c, i, n) + return proc genTry(c: var Con; n: PNode) = - let oldLen = c.forks.len + let oldForksLen = c.blocks[^1].forks.len var endings: seq[TPosition] = @[] - inc c.inTryStmt - let oldFixups = c.tryStmtFixups.len + let oldLen = c.blocks.len + c.blocks.add TBlock(isTryBlock: true, finale: if n[^1].kind == nkFinally: n[^1] else: newNode(nkEmpty)) + + inc c.inTryStmt #let elsePos = c.forkI(n) c.gen(n[0]) dec c.inTryStmt - for i in oldFixups..c.tryStmtFixups.high: - let f = c.tryStmtFixups[i] - c.patch(f) - # we also need to produce join instructions - # for the 'fork' that might precede the goto instruction - if f.int-1 >= 0 and c.code[f.int-1].kind == fork: - c.joinI(TPosition(f.int-1), n) - setLen(c.tryStmtFixups, oldFixups) + for f in c.blocks[oldLen].raiseFixups: + c.patch(f) + for j in c.blocks[oldLen].joins: + var patchedJ = j + patchedJ.dest -= c.code.len + c.code.add patchedJ + + c.blocks.setLen oldLen #c.patch(elsePos) for i in 1.. 0: - c.tryStmtFixups.add c.gotoI(n) + for i in countdown(c.blocks.high, 0): + if c.blocks[i].isTryBlock: + genBreakOrRaiseAux(c, i, n) + return + assert false #Unreachable else: genNoReturn(c, n) @@ -557,8 +595,7 @@ proc genReturn(c: var Con; n: PNode) = gen(c, n[0]) else: genImplicitReturn(c) - genJoins(c, n) - genNoReturn(c, n) + genBreakOrRaiseAux(c, 0, n) const InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp} @@ -708,9 +745,12 @@ proc genCall(c: var Con; n: PNode) = # lab1: # join F1 let endGoto = c.forkI(n) - c.tryStmtFixups.add c.gotoI(n) + for i in countdown(c.blocks.high, 0): + if c.blocks[i].isTryBlock: + genBreakOrRaiseAux(c, i, n) + break c.patch(endGoto) - c.joinI(c.forks.pop(), n) + c.joinI(c.blocks[^1].forks.pop(), n) dec c.inCall proc genMagic(c: var Con; n: PNode; m: TMagic) = @@ -784,6 +824,7 @@ proc gen(c: var Con; n: PNode) = proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = ## constructs a control flow graph for ``body``. var c = Con(code: @[], blocks: @[], owner: s) - gen(c, body) - genImplicitReturn(c) + withBlock(s): + gen(c, body) + genImplicitReturn(c) shallowCopy(result, c.code) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 9e5207437..ea1a97e24 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -87,9 +87,7 @@ proc isLastRead(location: PNode; c: var Con; pc, comesFrom: int): int = if variantA < 0: return -1 var variantB = isLastRead(location, c, pc + c.g[pc].dest, pc) if variantB < 0: return -1 - elif variantB == high(int): - variantB = variantA - pc = variantB + pc = min(variantA, variantB) of InstrKind.join: let dest = pc + c.g[pc].dest if dest == comesFrom: return pc + 1 @@ -140,9 +138,7 @@ proc isFirstWrite(location: PNode; c: var Con; pc, comesFrom: int; instr: int): if variantA < 0: return -1 var variantB = isFirstWrite(location, c, pc + c.g[pc].dest, pc, instr + c.g[pc].dest) if variantB < 0: return -1 - elif variantB == high(int): - variantB = variantA - pc = variantB + pc = min(variantA, variantB) of InstrKind.join: let dest = pc + c.g[pc].dest if dest == comesFrom: return pc + 1 diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim index 8fc9bf61d..efe51cc32 100644 --- a/tests/arc/tcontrolflow.nim +++ b/tests/arc/tcontrolflow.nim @@ -10,6 +10,7 @@ end false begin true if end true +7 ''' cmd: "nim c --gc:arc -d:danger $file" disabled: "true" @@ -53,3 +54,26 @@ proc orIsHard(cond: bool) = orIsHard(false) orIsHard(true) + +type + Control = ref object + x: int + + MouseEvent = ref object + control: Control + button: int + +proc run(data: Control) = + var evt = MouseEvent(button: 1) + evt.control = data + if evt.button == 1: + discard + else: + return + + echo data.x + +var c = Control(x: 7) + +run(c) + From 73a42ce9410a0cc0c4a91469e6ace2858e26355d Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 7 May 2020 14:43:53 -0500 Subject: [PATCH 0489/4254] nativesockets: add missing inheritable pass-through --- lib/pure/nativesockets.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 8d0d6426d..45ea93235 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -231,7 +231,7 @@ proc createNativeSocket*(domain: Domain = AF_INET, ## ## `inheritable` decides if the resulting SocketHandle can be inherited ## by child processes. - createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol)) + createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol), inheritable) proc newNativeSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, From 83435fe6968884d916db79b51ca0e510e67d87c7 Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 7 May 2020 20:07:08 +0000 Subject: [PATCH 0490/4254] tslow_tables: wait for an additional 2 seconds (#14266) This test runtime tends to hover around the 5s mark depending on how loaded the system currently is. This causes the test to fail a lot during CI, per analytics: https://dev.azure.com/nim-lang/Nim/_test/analytics?definitionId=1&contextType=build Give the test an extra 2 seconds to account for unrelated overhead. --- tests/vm/tslow_tables.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/vm/tslow_tables.nim b/tests/vm/tslow_tables.nim index 37351bfe2..e40187f18 100644 --- a/tests/vm/tslow_tables.nim +++ b/tests/vm/tslow_tables.nim @@ -1,5 +1,5 @@ discard """ - timeout: "5" + timeout: "7" action: "compile" nimout: '''create search From 5fa7d374c4cb777372cf5b967575f228bda23c2b Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 7 May 2020 21:15:25 +0100 Subject: [PATCH 0491/4254] fix #14243 (#14257) * fix #14243 Co-authored-by: cooldome --- compiler/semmagic.nim | 14 +++++++++----- tests/arc/tarcmisc.nim | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 53a19fae6..438f2dbc7 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -402,14 +402,18 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym # Replace nkDerefExpr by nkHiddenDeref # nkDeref is for 'ref T': x[].field # nkHiddenDeref is for 'var T': x.field - proc transform(n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode = + proc transform(procSym: PSym; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode = result = shallowCopy(n) if sameTypeOrNil(n.typ, old): result.typ = fresh - if n.kind == nkSym and n.sym == oldParam: - result.sym = newParam + if n.kind == nkSym: + if n.sym == oldParam: + result.sym = newParam + elif n.sym.owner == orig: + result.sym = copySym(n.sym) + result.sym.owner = procSym for i in 0 ..< safeLen(n): - result[i] = transform(n[i], old, fresh, oldParam, newParam) + result[i] = transform(procSym, n[i], old, fresh, oldParam, newParam) #if n.kind == nkDerefExpr and sameType(n[0].typ, old): # result = @@ -423,7 +427,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym let newParam = newSym(skParam, oldParam.name, result, result.info) newParam.typ = newParamType # proc body: - result.ast = transform(orig.ast, origParamType, newParamType, oldParam, newParam) + result.ast = transform(result, orig.ast, origParamType, newParamType, oldParam, newParam) # proc signature: result.typ = newProcType(result.info, result) result.typ.addParam newParam diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 953e2f3a7..79c947e82 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -104,4 +104,18 @@ proc re(x: static[string]): static MyType = proc match(inp: string, rg: static MyType) = doAssert rg.a.len == 0 -match("ac", re"a(b|c)") \ No newline at end of file +match("ac", re"a(b|c)") + +#------------------------------------------------------------------------------ +# issue #14243 + +type + Game* = ref object + +proc free*(game: Game) = + let a = 5 + +proc newGame*(): Game = + new(result, free) + +var game*: Game \ No newline at end of file From ee15437aedcf7c4f29f75101a6af7bc454830cda Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 7 May 2020 15:01:46 -0700 Subject: [PATCH 0492/4254] fix root cause of https://github.com/dom96/choosenim/issues/193; config/config.nims should get installed --- compiler/installer.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index 939b328d0..fdb717b61 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -35,9 +35,8 @@ App: Console License: "copying.txt" [Config] -Files: "config/nim.cfg" -Files: "config/nimdoc.cfg" -Files: "config/nimdoc.tex.cfg" +Files: "config/*.cfg" +Files: "config/config.nims" [Documentation] ; Files: "doc/*.html" From de27910ab72dca681188953ae963802520271e43 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Fri, 8 May 2020 08:54:46 +0300 Subject: [PATCH 0493/4254] make `from` an operator (#14241) --- changelog.md | 2 ++ compiler/layouter.nim | 2 +- compiler/lexer.nim | 2 +- compiler/parser.nim | 8 ++++--- doc/grammar.txt | 2 +- doc/manual.rst | 32 ++++++++++++++-------------- tests/parser/tstatementoperators.nim | 12 +++++++++++ 7 files changed, 38 insertions(+), 22 deletions(-) create mode 100644 tests/parser/tstatementoperators.nim diff --git a/changelog.md b/changelog.md index 9ae50f1f3..32d7eba55 100644 --- a/changelog.md +++ b/changelog.md @@ -120,6 +120,8 @@ with writing typed macros. Old behavior for backwards compatiblity can be restored with command line switch `--useVersion:1.0`. +- The keyword `from` is now usable as an operator. + ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. diff --git a/compiler/layouter.nim b/compiler/layouter.nim index e137ee8a0..2477458f1 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -327,7 +327,7 @@ const splitters = openPars + {tkComma, tkSemiColon} # do not add 'tkColon' here! oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} + tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, tkOr, tkXor} template goodCol(col): bool = col >= em.maxLineLen div 2 diff --git a/compiler/lexer.nim b/compiler/lexer.nim index e91a6415a..bd71a6ad5 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -967,7 +967,7 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int = of '?': result = 2 else: considerAsgn(2) of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5 + of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs, tkFrom: result = 5 of tkDotDot: result = 6 of tkAnd: result = 4 of tkOr, tkXor, tkPtr, tkRef: result = 3 diff --git a/compiler/parser.nim b/compiler/parser.nim index 4ea751057..9d1f6f97a 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -269,7 +269,8 @@ proc isRightAssociative(tok: TToken): bool {.inline.} = proc isOperator(tok: TToken): bool = ## Determines if the given token is an operator type token. tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} + tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, + tkOr, tkXor} proc isUnary(p: TParser): bool = ## Check if the current parser token is a unary operator @@ -294,7 +295,7 @@ proc checkBinary(p: TParser) {.inline.} = #| #| operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 #| | 'or' | 'xor' | 'and' -#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' +#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' | 'from' #| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' #| #| prefixOperator = operator @@ -555,7 +556,7 @@ proc parsePar(p: var TParser): PNode = optInd(p, result) flexComment(p, result) if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, - tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, + tkTry, tkDefer, tkFinally, tkExcept, tkBlock, tkConst, tkLet, tkWhen, tkVar, tkFor, tkMixin}: # XXX 'bind' used to be an expression, so we exclude it here; @@ -2193,6 +2194,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode = #| | blockStmt | staticStmt | deferStmt | asmStmt #| | 'proc' routine #| | 'method' routine + #| | 'func' routine #| | 'iterator' routine #| | 'macro' routine #| | 'template' routine diff --git a/doc/grammar.txt b/doc/grammar.txt index 06eebbc1b..9d952d372 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -6,7 +6,7 @@ colon = ':' COMMENT? colcom = ':' COMMENT? operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | 'or' | 'xor' | 'and' - | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' + | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' | 'from' | | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' prefixOperator = operator optInd = COMMENT? IND? diff --git a/doc/manual.rst b/doc/manual.rst index 85b307c80..02ccace2c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -565,7 +565,7 @@ following characters:: defined here.) These keywords are also operators: -``and or not xor shl shr div mod in notin is isnot of as``. +``and or not xor shl shr div mod in notin is isnot of as from``. `.`:tok: `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they are used for other notational purposes. @@ -638,21 +638,21 @@ has the second lowest precedence. Otherwise precedence is determined by the first character. -================ ================================================== ================== =============== -Precedence level Operators First character Terminal symbol -================ ================================================== ================== =============== - 10 (highest) ``$ ^`` OP10 - 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 - 8 ``+ -`` ``+ - ~ |`` OP8 - 7 ``&`` ``&`` OP7 - 6 ``..`` ``.`` OP6 - 5 ``== <= < >= > != in notin is isnot not of as`` ``= < > !`` OP5 - 4 ``and`` OP4 - 3 ``or xor`` OP3 - 2 ``@ : ?`` OP2 - 1 *assignment operator* (like ``+=``, ``*=``) OP1 - 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 -================ ================================================== ================== =============== +================ ======================================================= ================== =============== +Precedence level Operators First character Terminal symbol +================ ======================================================= ================== =============== + 10 (highest) ``$ ^`` OP10 + 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 + 8 ``+ -`` ``+ - ~ |`` OP8 + 7 ``&`` ``&`` OP7 + 6 ``..`` ``.`` OP6 + 5 ``== <= < >= > != in notin is isnot not of as from`` ``= < > !`` OP5 + 4 ``and`` OP4 + 3 ``or xor`` OP3 + 2 ``@ : ?`` OP2 + 1 *assignment operator* (like ``+=``, ``*=``) OP1 + 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 +================ ======================================================= ================== =============== Whether an operator is used a prefix operator is also affected by preceding diff --git a/tests/parser/tstatementoperators.nim b/tests/parser/tstatementoperators.nim new file mode 100644 index 000000000..d2b85bb4b --- /dev/null +++ b/tests/parser/tstatementoperators.nim @@ -0,0 +1,12 @@ +discard """ + nimout: ''' +Infix + Ident "from" + Ident "a" + Ident "b" +''' +""" + +from macros import dumpTree + +dumpTree(a from b) \ No newline at end of file From 120ea906fbd0fc70b366a85c25713bd28673872c Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 8 May 2020 15:54:34 +0200 Subject: [PATCH 0494/4254] Fix #14270 and add testcases (#14276) --- lib/system/repr_v2.nim | 8 ++++++-- tests/arc/trepr.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index fa04ba5a9..407a06844 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -106,8 +106,12 @@ proc repr*[T: tuple|object](x: T): string = proc repr*[T](x: ref T | ptr T): string = if isNil(x): return "nil" - result = $typeof(x) - reprObject(result, x[]) + when T is object: + result = $typeof(x) + reprObject(result, x[]) + else: + result = when typeof(x) is ref: "ref " else: "ptr " + result.add repr(x[]) proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string = result = prefix diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index 7a92112ed..e24c112ac 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -3,6 +3,12 @@ discard """ nimout: '''(a: true, n: doAssert) Table[system.string, trepr.MyType](data: @[], counter: 0) nil +''' + output: ''' +nil +2 +Obj(member: ref @[hello]) +ref (member: ref @[hello]) ''' """ import tables @@ -32,3 +38,27 @@ macro dumpSym(a: typed) = dumpSym(doAssert) +# bug 13731 + +import os +var a: File +echo repr a + +# bug 13872 + +echo repr(2'u16) + +# bug 14270 + +type + Obj = ref object + member: ref seq[string] + +var c = Obj(member: new seq[string]) +c.member[] = @["hello"] +echo c.repr + +var c2 = new tuple[member: ref seq[string]] +c2.member = new seq[string] +c2.member[] = @["hello"] +echo c2.repr From 363b7ff3b80d2b50cda901d1f6e6b01e67747ed2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 8 May 2020 07:13:07 -0700 Subject: [PATCH 0495/4254] fix https://github.com/nim-lang/Nim/issues/14275 querySetting(nimcacheDir) works even if implicitly set (#14277) --- compiler/vmops.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index ef36419a7..54b2877e7 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -112,7 +112,7 @@ when defined(nimHasInvariant): of arguments: result = conf.arguments of outFile: result = conf.outFile.string of outDir: result = conf.outDir.string - of nimcacheDir: result = conf.nimcacheDir.string + of nimcacheDir: result = conf.getNimcacheDir().string of projectName: result = conf.projectName of projectPath: result = conf.projectPath.string of projectFull: result = conf.projectFull.string From 4bd77cf045e5563ea1150d5106fec1f6f66d5e2d Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 8 May 2020 16:13:53 +0200 Subject: [PATCH 0496/4254] Fix typo --- doc/manual_experimental.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 45732fae2..1398d1a9b 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -104,7 +104,7 @@ cannot have the type ``void``. Covariance ========== -Covariance in Nim can be introduced only though pointer-like types such +Covariance in Nim can be introduced only through pointer-like types such as ``ptr`` and ``ref``. Sequence, Array and OpenArray types, instantiated with pointer-like types will be considered covariant if and only if they are also immutable. The introduction of a ``var`` modifier or additional From 411be506a30a701ab30138c576e21bd15dfaffe4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 8 May 2020 09:54:16 -0700 Subject: [PATCH 0497/4254] --hint:processing (+friends) is now supported and means `--hint:processing:on`, like all other bool flags (#14271) --- changelog.md | 3 +++ compiler/commands.nim | 8 +++++--- lib/system.nim | 2 +- tests/newconfig/tfoo.nim | 2 +- tests/newconfig/tfoo.nims | 21 ++++++++++++++++++++- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 32d7eba55..cdd6c031a 100644 --- a/changelog.md +++ b/changelog.md @@ -137,6 +137,9 @@ nim r compiler/nim.nim --fullhelp # no recompilation nim r --nimcache:/tmp main # binary saved to /tmp/main ``` +- `--hint:processing` is now supported and means `--hint:processing:on` + (likewise with other hints and warnings), which is consistent with all other bool flags. + (since 1.3.3). ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index 949d6cae1..e980d64fc 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -176,7 +176,7 @@ proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, info: TLineInfo; orig: string; conf: ConfigRef) = - var id = "" # arg = key:val or [key]:val; with val=on|off + var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off var i = 0 var n = hintMin var isBracket = false @@ -190,7 +190,8 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, if i < arg.len and arg[i] == ']': inc(i) else: invalidCmdLineOption(conf, pass, orig, info) - if i < arg.len and (arg[i] in {':', '='}): inc(i) + if i == arg.len: discard + elif i < arg.len and (arg[i] in {':', '='}): inc(i) else: invalidCmdLineOption(conf, pass, orig, info) if state == wHint: let x = findStr(lineinfos.HintsToStr, id) @@ -201,7 +202,8 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, if x >= 0: n = TNoteKind(x + ord(warnMin)) else: localError(conf, info, "unknown warning: " & id) - let val = substr(arg, i).normalize + var val = substr(arg, i).normalize + if val == "": val = "on" if val notin ["on", "off"]: localError(conf, info, errOnOrOffExpectedButXFound % arg) elif n notin conf.cmdlineNotes or pass == passCmd1: diff --git a/lib/system.nim b/lib/system.nim index 3f5015542..8878277b7 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2068,7 +2068,7 @@ const ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 1 + NimPatch* {.intdefine.}: int = 3 ## is the patch number of Nim's version. import system/dollars diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim index f332cd6d4..6654202c5 100644 --- a/tests/newconfig/tfoo.nim +++ b/tests/newconfig/tfoo.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim default $file" + cmd: "nim default --hint:cc:off --hint:cc $file" output: '''hello world! 0.5''' nimout: '''[NimScript] exec: gcc -v''' """ diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index 9e6405a27..4186ee047 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -7,7 +7,26 @@ exec "gcc -v" --path: "../friends" warning("uninit", off) -hint("processing", off) + +block: # supported syntaxes for hint,warning,switch + --hint:processing + hint("processing", on) + hint("processing", off) + switch("hint", "processing") + switch("hint", "processing:on") + switch("hint", "processing:off") + switch("hint", "[processing]") + switch("hint", "[processing]:on") + switch("hint", "[processing]:off") # leave it off + + --warning:UnusedImport + switch("warning", "UnusedImport:off") + switch("warning", "UnusedImport:on") + switch("warning", "[UnusedImport]:off") + switch("warning", "[UnusedImport]:on") + switch("warning", "[UnusedImport]") + switch("warning", "UnusedImport") # leave it on + #--verbosity:2 patchFile("stdlib", "math", "mymath") From 8e93105606c198fdb0d0e1e3553c1cc14579cf7d Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 9 May 2020 18:22:25 +0200 Subject: [PATCH 0498/4254] Fix #14269 (#14286) --- compiler/dfa.nim | 3 +- tests/arc/tmovebug.nim | 104 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index f6566f77b..0db89579b 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -635,7 +635,8 @@ proc genUse(c: var Con; orig: PNode) = proc aliases*(obj, field: PNode): bool = var n = field var obj = obj - while obj.kind in {nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv}: + while obj.kind in {nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv, + nkAddr, nkHiddenAddr, nkDerefExpr, nkHiddenDeref}: obj = obj[0] while true: if sameTrees(obj, n): return true diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 95bfb8202..6ed10c403 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -3,6 +3,22 @@ discard """ output: '''5 (w: 5) (w: -5) +c.text = hello +c.text = hello +p.text = hello +p.toks = @["hello"] +c.text = hello +c[].text = hello +pA.text = hello +pA.toks = @["hello"] +c.text = hello +c.text = hello +pD.text = hello +pD.toks = @["hello"] +c.text = hello +c.text = hello +pOD.text = hello +pOD.toks = @["hello"] ''' """ @@ -96,4 +112,90 @@ proc procStat() = let cols = line.splitWhitespace(maxSplit=1) let x = cols[0] let (nm, rest) = (cols[0], cols[1]) -procStat() \ No newline at end of file +procStat() + + +# bug #14269 + +import sugar, strutils + +type + Cursor = object + text: string + Parsed = object + text: string + toks: seq[string] + +proc tokenize(c: var Cursor): seq[string] = + dump c.text + return c.text.splitWhitespace() + +proc parse(): Parsed = + var c = Cursor(text: "hello") + dump c.text + return Parsed(text: c.text, toks: c.tokenize) # note: c.tokenized uses c.text + +let p = parse() +dump p.text +dump p.toks + + +proc tokenizeA(c: ptr Cursor): seq[string] = + dump c[].text + return c[].text.splitWhitespace() + +proc parseA(): Parsed = + var c = Cursor(text: "hello") + dump c.text + return Parsed(text: c.text, toks: c.addr.tokenizeA) # note: c.tokenized uses c.text + +let pA = parseA() +dump pA.text +dump pA.toks + + +proc tokenizeD(c: Cursor): seq[string] = + dump c.text + return c.text.splitWhitespace() + +proc parseD(): Parsed = + var c = cast[ptr Cursor](alloc0(sizeof(Cursor))) + c[] = Cursor(text: "hello") + dump c.text + return Parsed(text: c.text, toks: c[].tokenizeD) # note: c.tokenized uses c.text + +let pD = parseD() +dump pD.text +dump pD.toks + +# Bug would only pop up with owned refs +proc tokenizeOD(c: Cursor): seq[string] = + dump c.text + return c.text.splitWhitespace() + +proc parseOD(): Parsed = + var c = new Cursor + c[] = Cursor(text: "hello") + dump c.text + return Parsed(text: c.text, toks: c[].tokenizeOD) # note: c.tokenized uses c.text + +let pOD = parseOD() +dump pOD.text +dump pOD.toks + +when false: + # Bug would only pop up with owned refs and implicit derefs, but since they don't work together.. + {.experimental: "implicitDeref".} + proc tokenizeOHD(c: Cursor): seq[string] = + dump c.text + return c.text.splitWhitespace() + + proc parseOHD(): Parsed = + var c = new Cursor + c[] = Cursor(text: "hello") + dump c.text + return Parsed(text: c.text, toks: c.tokenizeOHD) # note: c.tokenized uses c.text + + let pOHD = parseOHD() + dump pOHD.text + dump pOHD.toks From dda6f3f6d42ec95a287f2467b976d8cbbc9c1624 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 10 May 2020 00:23:01 -0700 Subject: [PATCH 0499/4254] `nim doc -r main` and `nim rst2html -r main` now call openDefaultBrowser (#14285) --- changelog.md | 1 + compiler/nim.nim | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index cdd6c031a..7907432a7 100644 --- a/changelog.md +++ b/changelog.md @@ -140,6 +140,7 @@ - `--hint:processing` is now supported and means `--hint:processing:on` (likewise with other hints and warnings), which is consistent with all other bool flags. (since 1.3.3). +- `nim doc -r main` and `nim rst2html -r main` now call openDefaultBrowser ## Tool changes diff --git a/compiler/nim.nim b/compiler/nim.nim index 80d9b66b6..dba5b8bc3 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -24,7 +24,8 @@ import idents, lineinfos, cmdlinehelper, pathutils -include nodejs +from browsers import openDefaultBrowser +from nodejs import findNodeJs when hasTinyCBackend: import tccgen @@ -86,11 +87,21 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = if conf.cmd == cmdRun: tccgen.run(conf, conf.arguments) if optRun in conf.globalOptions: - var ex = quoteShell conf.absOutFile - if conf.cmd == cmdCompileToJS: + let output = conf.absOutFile + let ex = quoteShell output + case conf.cmd + of cmdCompileToJS: execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments) - else: + of cmdDoc, cmdRst2html: + if conf.arguments.len > 0: + # reserved for future use + rawMessage(conf, errGenerated, "'$1 cannot handle arguments" % [$conf.cmd]) + openDefaultBrowser($output) + of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC: execExternalProgram(conf, ex & ' ' & conf.arguments) + else: + # support as needed + rawMessage(conf, errGenerated, "'$1 cannot handle --run" % [$conf.cmd]) when declared(GC_setMaxPause): GC_setMaxPause 2_000 From 7c24250a575b4d441ba6d7301714cbb246425fb6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 10 May 2020 15:56:00 -0700 Subject: [PATCH 0500/4254] diable nimx (CI failure) refs https://github.com/timotheecour/Nim/issues/167 (#14293) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 243856d5e..4186ce30d 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -96,7 +96,7 @@ pkg2 "nimsl", true pkg2 "nimsvg" # pkg2 "nimterop", true pkg2 "nimwc", true, "nim c nimwc.nim" -pkg2 "nimx", true, "nim c --threads:on test/main.nim" +# pkg2 "nimx", true, "nim c --threads:on test/main.nim" pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" pkg2 "norm", true, "nim c -r tests/tsqlite.nim" pkg2 "npeg", false, "nimble testarc" From 8018449319746f04a0c6436f1a0a3a5c6798d95c Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Mon, 11 May 2020 02:59:31 -0400 Subject: [PATCH 0501/4254] simple typo in locks.nim (#14297) --- lib/core/locks.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 42d67388f..7e2f4ad34 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -50,7 +50,7 @@ proc initCond*(cond: var Cond) {.inline.} = initSysCond(cond) proc deinitCond*(cond: var Cond) {.inline.} = - ## Frees the resources associated with the lock. + ## Frees the resources associated with the condition variable. deinitSysCond(cond) proc wait*(cond: var Cond, lock: var Lock) {.inline.} = From d11cb9d49596957e9fa097110cf19e9caf085592 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 11 May 2020 02:14:21 -0700 Subject: [PATCH 0502/4254] fix a critical bug in windows.osproc leading to resource leaks and blocking IO [backport] (#14296) --- changelog.md | 3 +++ lib/pure/osproc.nim | 6 +++++- lib/windows/winlean.nim | 2 ++ tests/stdlib/tosproc.nim | 26 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 7907432a7..f1ffb4a3a 100644 --- a/changelog.md +++ b/changelog.md @@ -86,6 +86,9 @@ an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). The proc `times.isInitialized` has been added which can be used to check if a `DateTime` has been initialized. +- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to + hangs if a process had both reads from stdin and writes (eg to stdout). + ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: ```nim diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 5839349fe..f90b310ea 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -441,7 +441,11 @@ when defined(Windows) and not defined(useNimRtl): handle: Handle atTheEnd: bool - proc hsClose(s: Stream) = discard # nothing to do here + proc hsClose(s: Stream) = + # xxx here + elsewhere: check instead of discard; ignoring errors leads to + # hard to track bugs + discard FileHandleStream(s).handle.closeHandle + proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int = diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 9beccc0eb..bd4cfdca7 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -31,6 +31,8 @@ type ULONG* = int32 PULONG* = ptr int WINBOOL* = int32 + ## `WINBOOL` uses opposite convention as posix, !=0 meaning success. + # xxx this should be distinct int32, distinct would make code less error prone DWORD* = int32 PDWORD* = ptr DWORD LPINT* = ptr int32 diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index fc65606f6..73cec0cb7 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -93,3 +93,29 @@ else: removeFile(exePath) except OSError: discard + + import std/streams + block: # test for startProcess (more tests needed) + # bugfix: windows stdin.close was a noop and led to blocking reads + proc startProcessTest(command: string, options: set[ProcessOption] = { + poStdErrToStdOut, poUsePath}, input = ""): tuple[ + output: TaintedString, + exitCode: int] {.tags: + [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = + var p = startProcess(command, options = options + {poEvalCommand}) + var outp = outputStream(p) + if input.len > 0: inputStream(p).write(input) + close inputStream(p) + result = (TaintedString"", -1) + var line = newStringOfCap(120).TaintedString + while true: + if outp.readLine(line): + result[0].string.add(line.string) + result[0].string.add("\n") + else: + result[1] = peekExitCode(p) + if result[1] != -1: break + close(p) + + var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4") + doAssert result == ("12\n", 0) From 9502e39b634eea8e04f07ddc110b466387f42322 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 11 May 2020 03:01:18 -0700 Subject: [PATCH 0503/4254] `nim doc --backend:js`, `nim doc --doccmd:-d:foo`, `nim r --backend:js`, `--doccmd:skip` + other improvements (#14278) * `nim doc --backend:js|cpp...` `nim doc --doccmd:'-d:foo --threads:on'` `nim r --backend:cpp...` (implies --run --usenimcache) * --usenimcache works with all targets * --docCmd:skip now skips compiling snippets; 50X speedup for doc/manual.rst --- compiler/ccgthreadvars.nim | 2 +- compiler/cgen.nim | 8 ++-- compiler/cmdlinehelper.nim | 3 +- compiler/commands.nim | 11 ++++- compiler/docgen.nim | 29 +++++++++----- compiler/extccomp.nim | 24 +++++------ compiler/lambdalifting.nim | 6 +-- compiler/main.nim | 69 ++++++++++++++++++-------------- compiler/nim.nim | 12 +++--- compiler/options.nim | 32 ++++++++++++--- compiler/pragmas.nim | 8 ++-- compiler/semexprs.nim | 2 +- compiler/sizealignoffsetimpl.nim | 2 +- compiler/transf.nim | 4 +- compiler/vmops.nim | 5 ++- doc/advopt.txt | 11 ++++- doc/basicopt.txt | 6 ++- lib/std/compilesettings.nim | 2 + tests/nimdoc/m13129.nim | 36 +++++++++++++++++ tests/nimdoc/readme.md | 2 + tests/trunner.nim | 37 ++++++++++++----- tests/vm/tcompilesetting.nim | 1 + 22 files changed, 213 insertions(+), 99 deletions(-) create mode 100644 tests/nimdoc/m13129.nim create mode 100644 tests/nimdoc/readme.md diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 3701f337d..8bf5e573f 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -46,7 +46,7 @@ proc generateThreadLocalStorage(m: BModule) = proc generateThreadVarsSize(m: BModule) = if m.g.nimtv != nil: - let externc = if m.config.cmd == cmdCompileToCpp or + let externc = if m.config.backend == backendCpp or sfCompileToCpp in m.module.flags: "extern \"C\" " else: "" m.s[cfsProcs].addf( diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 9e356206f..c32e86a88 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -279,7 +279,7 @@ proc genProc(m: BModule, prc: PSym) proc raiseInstr(p: BProc): Rope template compileToCpp(m: BModule): untyped = - m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags + m.config.backend == backendCpp or sfCompileToCpp in m.module.flags proc getTempName(m: BModule): Rope = result = m.tmpBase & rope(m.labels) @@ -1066,11 +1066,11 @@ proc genProcAux(m: BModule, prc: PSym) = proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = result = (sfCompileToCpp in m.module.flags and sfCompileToCpp notin sym.getModule().flags and - m.config.cmd != cmdCompileToCpp) or ( + m.config.backend != backendCpp) or ( sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and sym.flags * {sfImportc, sfExportc} != {} and sym.magic == mNone and - m.config.cmd == cmdCompileToCpp) + m.config.backend == backendCpp) proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) @@ -1867,7 +1867,7 @@ proc writeHeader(m: BModule) = proc getCFile(m: BModule): AbsoluteFile = let ext = if m.compileToCpp: ".nim.cpp" - elif m.config.cmd == cmdCompileToOC or sfCompileToObjc in m.module.flags: ".nim.m" + elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m" else: ".nim.c" result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index d5c743fc6..dd74f54dc 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -78,7 +78,8 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi # XXX This is hacky. We need to find a better way. case conf.command of "cpp", "compiletocpp": - conf.cmd = cmdCompileToCpp + conf.backend = backendCpp + conf.cmd = cmdCompileToBackend else: discard diff --git a/compiler/commands.nim b/compiler/commands.nim index e980d64fc..2ab79f14a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -434,11 +434,18 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "outdir": expectArg(conf, switch, arg, pass, info) conf.outDir = processPath(conf, arg, info, notRelativeToProj=true) + of "usenimcache": + processOnOffSwitchG(conf, {optUseNimcache}, arg, pass, info) of "docseesrcurl": expectArg(conf, switch, arg, pass, info) conf.docSeeSrcUrl = arg of "docroot": conf.docRoot = if arg.len == 0: "@default" else: arg + of "backend", "b": + let backend = parseEnum(arg.normalize, TBackend.default) + if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg) + conf.backend = backend + of "doccmd": conf.docCmd = arg of "mainmodule", "m": discard "allow for backwards compatibility, but don't do anything" of "define", "d": @@ -495,7 +502,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "gcmarkandsweep") of "destructors", "arc": conf.selectedGC = gcArc - if conf.cmd != cmdCompileToCpp: + if conf.backend != backendCpp: conf.exc = excGoto defineSymbol(conf.symbols, "gcdestructors") defineSymbol(conf.symbols, "gcarc") @@ -506,7 +513,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "nimV2") of "orc": conf.selectedGC = gcOrc - if conf.cmd != cmdCompileToCpp: + if conf.backend != backendCpp: conf.exc = excGoto defineSymbol(conf.symbols, "gcdestructors") defineSymbol(conf.symbols, "gcorc") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a42be9a9c..c01d5633f 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -22,6 +22,7 @@ import const exportSection = skField htmldocsDir = RelativeDir"htmldocs" + docCmdSkip = "skip" type TSections = array[TSymKind, Rope] @@ -196,6 +197,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, initStrTable result.types result.onTestSnippet = proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) = + if conf.docCmd == docCmdSkip: return inc(gen.id) var d = TDocumentor(gen) var outp: AbsoluteFile @@ -444,21 +446,26 @@ proc testExample(d: PDoc; ex: PNode) = d.examples.add "import r\"" & outp.string & "\"\n" proc runAllExamples(d: PDoc) = - if d.examples.len == 0: return + let docCmd = d.conf.docCmd + let backend = d.conf.backend + # This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however + # using `-d:js` (etc) cannot work properly, eg would fail with `importjs` + # since semantics are affected by `config.backend`, not by isDefined(d.conf, "js") + if d.examples.len == 0 or docCmd == docCmdSkip: return let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples" let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" & "_examples.nim")) writeFile(outp, d.examples) - let backend = if isDefined(d.conf, "js"): "js" - elif isDefined(d.conf, "cpp"): "cpp" - elif isDefined(d.conf, "objc"): "objc" - else: "c" - if os.execShellCmd(os.getAppFilename() & " " & backend & - " --warning[UnusedImport]:off" & - " --path:" & quoteShell(d.conf.projectPath) & - " --nimcache:" & quoteShell(outputDir) & - " -r " & quoteShell(outp)) != 0: - quit "[Examples] failed: see " & outp.string + let cmd = "$nim $backend -r --warning:UnusedImport:off --path:$path --nimcache:$nimcache $docCmd $file" % [ + "nim", os.getAppFilename(), + "backend", $d.conf.backend, + "path", quoteShell(d.conf.projectPath), + "nimcache", quoteShell(outputDir), + "file", quoteShell(outp), + "docCmd", docCmd, + ] + if os.execShellCmd(cmd) != 0: + quit "[runnableExamples] failed: generated file: '$1' cmd: $2" % [outp.string, cmd] else: # keep generated source file `outp` to allow inspection. rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string]) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 7c255484d..3c2435bec 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -307,14 +307,12 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given # for niminst support let fullSuffix = - if conf.cmd == cmdCompileToCpp: - ".cpp" & suffix - elif conf.cmd == cmdCompileToOC: - ".objc" & suffix - elif conf.cmd == cmdCompileToJS: - ".js" & suffix + case conf.backend + of backendCpp, backendJs, backendObjc: "." & $conf.backend & suffix + of backendC: suffix else: - suffix + doAssert false + "" if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and optCompileOnly notin conf.globalOptions: @@ -481,10 +479,10 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} = (conf.target.hostOS == osWindows) proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool = - conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c") + conf.backend == backendCpp and not cfile.string.endsWith(".c") proc envFlags(conf: ConfigRef): string = - result = if conf.cmd == cmdCompileToCpp: + result = if conf.backend == backendCpp: getEnv("CXXFLAGS") else: getEnv("CFLAGS") @@ -535,7 +533,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool = proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe - elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler + elif optMixedMode in conf.globalOptions and conf.backend != backendCpp: CC[compiler].cppCompiler else: getCompilerExe(conf, compiler, AbsoluteFile"") proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, @@ -626,8 +624,10 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = getCompileCFileCmd(conf, cfile)) proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = - if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM, cmdNone}: - return false + case conf.backend + of backendInvalid: doAssert false + of backendJs: return false # pre-existing behavior, but not sure it's good + else: discard var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") var currentHash = footprint(conf, cfile) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 01def12ad..fc1ad5e40 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -235,7 +235,7 @@ template isIterator*(owner: PSym): bool = proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = ## lambda lifting can be harmful for JS-like code generators. let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro - result = conf.cmd == cmdCompileToJS and not isCompileTime + result = conf.backend == backendJs and not isCompileTime proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; owner: PSym) = createTypeBoundOps(g, nil, refType.lastSon, info) @@ -846,14 +846,14 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo fn.typ.callConv = oldCC proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode = - # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs + # XXX backend == backendJs does not suffice! The compiletime stuff needs # the transformation even when compiling to JS ... # However we can do lifting for the stuff which is *only* compiletime. let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro if body.kind == nkEmpty or ( - g.config.cmd == cmdCompileToJS and not isCompileTime) or + g.config.backend == backendJs and not isCompileTime) or fn.skipGenericOwner.kind != skModule: # ignore forward declaration: diff --git a/compiler/main.nim b/compiler/main.nim index c94af24d5..00bc579df 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -119,8 +119,7 @@ when not defined(leanCompiler): let conf = graph.config conf.exc = excCpp - if conf.outDir.isEmpty: - conf.outDir = conf.projectPath + setOutDir(conf) if conf.outFile.isEmpty: conf.outFile = RelativeFile(conf.projectName & ".js") @@ -128,7 +127,6 @@ when not defined(leanCompiler): setTarget(graph.config.target, osJS, cpuJS) #initDefines() defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility - defineSymbol(graph.config.symbols, "js") semanticPasses(graph) registerPass(graph, JSgenPass) compileProject(graph) @@ -190,25 +188,46 @@ proc mainCommand*(graph: ModuleGraph) = conf.lastCmdTime = epochTime() conf.searchPaths.add(conf.libpath) setId(100) - template handleC() = - conf.cmd = cmdCompileToC - if conf.exc == excNone: conf.exc = excSetjmp - defineSymbol(graph.config.symbols, "c") - commandCompileToC(graph) + + ## Calling `setOutDir(conf)` unconditionally would fix regression + ## https://github.com/nim-lang/Nim/issues/6583#issuecomment-625711125 + when false: setOutDir(conf) + if optUseNimcache in conf.globalOptions: setOutDir(conf) + + template handleBackend(backend2: TBackend) = + conf.backend = backend2 + conf.cmd = cmdCompileToBackend + defineSymbol(graph.config.symbols, $backend2) + case backend2 + of backendC: + if conf.exc == excNone: conf.exc = excSetjmp + commandCompileToC(graph) + of backendCpp: + if conf.exc == excNone: conf.exc = excCpp + commandCompileToC(graph) + of backendObjc: + commandCompileToC(graph) + of backendJs: + when defined(leanCompiler): + globalError(conf, unknownLineInfo, "compiler wasn't built with JS code generator") + else: + if conf.hcrOn: + # XXX: At the moment, system.nim cannot be compiled in JS mode + # with "-d:useNimRtl". The HCR option has been processed earlier + # and it has added this define implictly, so we must undo that here. + # A better solution might be to fix system.nim + undefSymbol(conf.symbols, "useNimRtl") + commandCompileToJS(graph) + of backendInvalid: doAssert false + case conf.command.normalize - of "c", "cc", "compile", "compiletoc": handleC() # compile means compileToC currently - of "cpp", "compiletocpp": - conf.cmd = cmdCompileToCpp - if conf.exc == excNone: conf.exc = excCpp - defineSymbol(graph.config.symbols, "cpp") - commandCompileToC(graph) - of "objc", "compiletooc": - conf.cmd = cmdCompileToOC - defineSymbol(graph.config.symbols, "objc") - commandCompileToC(graph) + of "c", "cc", "compile", "compiletoc": handleBackend(backendC) # compile means compileToC currently + of "cpp", "compiletocpp": handleBackend(backendCpp) + of "objc", "compiletooc": handleBackend(backendObjc) + of "js", "compiletojs": handleBackend(backendJs) of "r": # different from `"run"`! conf.globalOptions.incl {optRun, optUseNimcache} - handleC() + handleBackend(conf.backend) of "run": conf.cmd = cmdRun when hasTinyCBackend: @@ -216,18 +235,6 @@ proc mainCommand*(graph: ModuleGraph) = commandCompileToC(graph) else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") - of "js", "compiletojs": - when defined(leanCompiler): - quit "compiler wasn't built with JS code generator" - else: - conf.cmd = cmdCompileToJS - if conf.hcrOn: - # XXX: At the moment, system.nim cannot be compiled in JS mode - # with "-d:useNimRtl". The HCR option has been processed earlier - # and it has added this define implictly, so we must undo that here. - # A better solution might be to fix system.nim - undefSymbol(conf.symbols, "useNimRtl") - commandCompileToJS(graph) of "doc0": when defined(leanCompiler): quit "compiler wasn't built with documentation generator" diff --git a/compiler/nim.nim b/compiler/nim.nim index dba5b8bc3..b48fce0b8 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -88,17 +88,19 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = tccgen.run(conf, conf.arguments) if optRun in conf.globalOptions: let output = conf.absOutFile - let ex = quoteShell output case conf.cmd - of cmdCompileToJS: - execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments) + of cmdCompileToBackend: + var cmdPrefix = "" + case conf.backend + of backendC, backendCpp, backendObjc: discard + of backendJs: cmdPrefix = findNodeJs() & " " + else: doAssert false, $conf.backend + execExternalProgram(conf, cmdPrefix & output.quoteShell & ' ' & conf.arguments) of cmdDoc, cmdRst2html: if conf.arguments.len > 0: # reserved for future use rawMessage(conf, errGenerated, "'$1 cannot handle arguments" % [$conf.cmd]) openDefaultBrowser($output) - of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC: - execExternalProgram(conf, ex & ' ' & conf.arguments) else: # support as needed rawMessage(conf, errGenerated, "'$1 cannot handle --run" % [$conf.cmd]) diff --git a/compiler/options.nim b/compiler/options.nim index 5475bc07b..3e6c7989f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -104,12 +104,26 @@ const harmlessOptions* = {optForceFullMake, optNoLinking, optRun, optUseColors, optStdout} +type + TBackend* = enum + backendInvalid = "" # for parseEnum + backendC = "c" + backendCpp = "cpp" # was cmdCompileToCpp + backendJs = "js" # was cmdCompileToJS + backendObjc = "objc" # was cmdCompileToOC + # backendNimscript = "nimscript" # this could actually work + # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM + type TCommands* = enum # Nim's commands # **keep binary compatible** - cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, - cmdCompileToJS, - cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, + cmdNone, + cmdCompileToC, # deadcode + cmdCompileToCpp, # deadcode + cmdCompileToOC, # deadcode + cmdCompileToJS, # deadcode + cmdCompileToLLVM, # deadcode + cmdInterpret, cmdPretty, cmdDoc, cmdGenDepend, cmdDump, cmdCheck, # semantic checking for whole project cmdParse, # parse a single file (for debugging) @@ -121,6 +135,7 @@ type cmdInteractive, # start interactive session cmdRun, # run the project via TCC backend cmdJsonScript # compile a .json build file + cmdCompileToBackend, # compile to backend in TBackend TStringSeq* = seq[string] TGCMode* = enum # the selected GC gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcArc, gcOrc, @@ -208,6 +223,7 @@ type ## fields marked with '*' are subject to ## the incremental compilation mechanisms ## (+) means "part of the dependency" + backend*: TBackend target*: Target # (+) linesCompiled*: int # all lines that have been compiled options*: TOptions # (+) @@ -274,6 +290,7 @@ type docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \ # The string uses the formatting variables `path` and `line`. docRoot*: string ## see nim --fullhelp for --docRoot + docCmd*: string ## see nim --fullhelp for --docCmd # the used compiler cIncludes*: seq[AbsoluteDir] # directories to search for included files @@ -402,7 +419,7 @@ proc newConfigRef*(): ConfigRef = cIncludes: @[], # directories to search for included files cLibs: @[], # directories to search for lib files cLinkedLibs: @[], # libraries to link - + backend: backendC, externalToLink: @[], linkOptionsCmd: "", compileOptionsCmd: @[], @@ -522,7 +539,10 @@ proc setConfigVar*(conf: ConfigRef; key, val: string) = conf.configVars[key] = val proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): AbsoluteFile = - conf.outDir / changeFileExt(filename, ext) + # explains regression https://github.com/nim-lang/Nim/issues/6583#issuecomment-625711125 + # Yet another reason why "" should not mean "."; `""/something` should raise + # instead of implying "" == "." as it's bug prone. + result = conf.outDir / changeFileExt(filename, ext) proc absOutFile*(conf: ConfigRef): AbsoluteFile = if false: @@ -615,7 +635,7 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir = # XXX projectName should always be without a file extension! result = if not conf.nimcacheDir.isEmpty: conf.nimcacheDir - elif conf.cmd == cmdCompileToJS: + elif conf.backend == backendJs: conf.projectPath / genSubDir else: AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name & diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 465608b10..021a8b339 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -179,7 +179,7 @@ proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) = incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) - if c.config.cmd == cmdCompileToC: + if c.config.backend == backendC: let m = s.getModule() incl(m.flags, sfCompileToCpp) incl c.config.globalOptions, optMixedMode @@ -797,8 +797,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wExportc, wExportCpp: makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) if k == wExportCpp: - if c.config.cmd != cmdCompileToCpp: - localError(c.config, it.info, "exportcpp requires `nim cpp`, got " & $c.config.cmd) + if c.config.backend != backendCpp: + localError(c.config, it.info, "exportcpp requires `cpp` backend, got " & $c.config.backend) else: incl(sym.flags, sfMangleCpp) incl(sym.flags, sfUsed) # avoid wrong hints @@ -819,7 +819,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wImportCpp: processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info) of wImportJs: - if c.config.cmd != cmdCompileToJS: + if c.config.backend != backendJs: localError(c.config, it.info, "`importjs` pragma requires the JavaScript target") let name = getOptionalStr(c, it, "$1") incl(sym.flags, sfImportc) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 56b6076d5..43fd1b69c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -660,7 +660,7 @@ proc hasUnresolvedArgs(c: PContext, n: PNode): bool = return false proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = - if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or + if n.kind == nkHiddenDeref and not (c.config.backend == backendCpp or sfCompileToCpp in c.module.flags): checkSonsLen(n, 1, c.config) result = n[0] diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index dc3fefeea..9d12297ea 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -346,7 +346,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = while st.kind in skipPtrs: st = st[^1] computeSizeAlign(conf, st) - if conf.cmd == cmdCompileToCpp: + if conf.backend == backendCpp: OffsetAccum( offset: int(st.size) - int(st.paddingAtEnd), maxAlign: st.align diff --git a/compiler/transf.nim b/compiler/transf.nim index cbf904255..bd9f567ed 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -411,7 +411,7 @@ proc transformYield(c: PTransf, n: PNode): PNode = proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = transformSons(c, n) - if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return + if c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags: return var n = result case n[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: @@ -447,7 +447,7 @@ proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode = # we cannot generate a proper thunk here for GC-safety reasons # (see internal documentation): - if c.graph.config.cmd == cmdCompileToJS: return prc + if c.graph.config.backend == backendJs: return prc result = newNodeIT(nkClosure, prc.info, dest) var conv = newNodeIT(nkHiddenSubConv, prc.info, dest) conv.add(newNodeI(nkEmpty, prc.info)) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 54b2877e7..27d1ef479 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -121,6 +121,7 @@ when defined(nimHasInvariant): of linkOptions: result = conf.linkOptions of compileOptions: result = conf.compileOptions of ccompilerPath: result = conf.cCompilerPath + of backend: result = $conf.backend proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = @@ -215,7 +216,7 @@ proc registerAdditionalOps*(c: PCtx) = proc hashVmImpl(a: VmArgs) = var res = hashes.hash(a.getString(0), a.getInt(1).int, a.getInt(2).int) - if c.config.cmd == cmdCompileToJS: + if c.config.backend == backendJs: # emulate JS's terrible integers: res = cast[int32](res) setResult(a, res) @@ -232,7 +233,7 @@ proc registerAdditionalOps*(c: PCtx) = bytes[i] = byte(arr[i].intVal and 0xff) var res = hashes.hash(bytes, sPos, ePos) - if c.config.cmd == cmdCompileToJS: + if c.config.backend == backendJs: # emulate JS's terrible integers: res = cast[int32](res) setResult(a, res) diff --git a/doc/advopt.txt b/doc/advopt.txt index c877b02e9..a668be5c0 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -5,6 +5,7 @@ Advanced commands: //js compile project to Javascript //e run a Nimscript file //rst2html convert a reStructuredText file to HTML + use `--docCmd:skip` to skip compiling snippets //rst2tex convert a reStructuredText file to TeX //jsondoc extract the documentation to a json file //ctags create a tags file @@ -29,6 +30,8 @@ Runtime checks (see -x): Advanced options: -o:FILE, --out:FILE set the output filename --outdir:DIR set the path where the output file will be written + --usenimcache will use `outdir=$$nimcache`, whichever it resolves + to after all options have been processed --stdout:on|off output to stdout --colors:on|off turn compiler messages coloring on|off --listFullPaths:on|off list full paths in messages @@ -69,13 +72,17 @@ Advanced options: --clib:LIBNAME link an additional C library (you should omit platform-specific extensions) --project document the whole project (doc2) - --docRoot:path nim doc --docRoot:/foo --project --outdir:docs /foo/sub/main.nim + --docRoot:path `nim doc --docRoot:/foo --project --outdir:docs /foo/sub/main.nim` generates: docs/sub/main.html if path == @pkg, will use nimble file enclosing dir - if path == @path, will use first matching dir in --path + if path == @path, will use first matching dir in `--path` if path == @default (the default and most useful), will use best match among @pkg,@path. if these are nonexistant, will use project path + -b, --backend:c|cpp|js|objc sets backend to use with commands like `nim doc` or `nim r` + --docCmd:cmd if `cmd == skip`, skips runnableExamples + else, runs runnableExamples with given options, eg: + `--docCmd:"-d:foo --threads:on"` --docSeeSrcUrl:url activate 'see source' for doc and doc2 commands (see doc.item.seesrc in config/nimdoc.cfg) --docInternal also generate documentation for non-exported symbols diff --git a/doc/basicopt.txt b/doc/basicopt.txt index cc808a077..cdd8ab9be 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -4,8 +4,10 @@ Command: //compile, c compile project with default code generator (C) - //r compile & run $nimcach/projname [arguments] - //doc generate the documentation for inputfile + //r compile to $nimcache/projname, run with [arguments] + using backend specified by `--backend` (default: c) + //doc generate the documentation for inputfile for + backend specified by `--backend` (default: c) Arguments: arguments are passed to the program being run (if --run option is selected) diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim index 12204658d..b9b13175d 100644 --- a/lib/std/compilesettings.nim +++ b/lib/std/compilesettings.nim @@ -29,6 +29,8 @@ type linkOptions, ## additional options passed to the linker compileOptions, ## additional options passed to the C/C++ compiler ccompilerPath ## the path to the C/C++ compiler + backend ## the backend (eg: c|cpp|objc|js); both `nim doc --backend:js` + ## and `nim js` would imply backend=js MultipleValueSetting* {.pure.} = enum ## \ ## settings resulting in a seq of string values diff --git a/tests/nimdoc/m13129.nim b/tests/nimdoc/m13129.nim new file mode 100644 index 000000000..df4b5a3f5 --- /dev/null +++ b/tests/nimdoc/m13129.nim @@ -0,0 +1,36 @@ +when defined(cpp): + {.push header: "".} + type + Vector[T] {.importcpp: "std::vector".} = object +elif defined(js): + proc endsWith*(s, suffix: cstring): bool {.noSideEffect,importjs: "#.endsWith(#)".} +elif defined(c): + proc c_printf*(frmt: cstring): cint {. + importc: "printf", header: "", varargs, discardable.} + +proc main*() = + runnableExamples: + import std/compilesettings + doAssert not defined(m13129Foo1) + doAssert defined(m13129Foo2) + doAssert not defined(nimdoc) + echo "ok2: backend: " & querySetting(backend) + # echo defined(c), defined(js), + +import std/compilesettings +when defined nimdoc: + # import std/compilesettings + static: + doAssert defined(m13129Foo1) + doAssert not defined(m13129Foo2) + echo "ok1:" & querySetting(backend) + +when isMainModule: + when not defined(js): + import std/os + let cache = querySetting(nimcacheDir) + doAssert cache.len > 0 + let app = getAppFilename() + doAssert app.isRelativeTo(cache) + doAssert querySetting(projectFull) == currentSourcePath + echo "ok3" diff --git a/tests/nimdoc/readme.md b/tests/nimdoc/readme.md new file mode 100644 index 000000000..64b16c2a5 --- /dev/null +++ b/tests/nimdoc/readme.md @@ -0,0 +1,2 @@ +the html validation is tested by nimdoc/tester.nim +the runnableExamples + nim doc logic (across backend) is tested here diff --git a/tests/trunner.nim b/tests/trunner.nim index f71c324a2..e6a8a2077 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -6,7 +6,7 @@ discard """ ## tests that don't quite fit the mold and are easier to handle via `execCmdEx` ## A few others could be added to here to simplify code. -import std/[strformat,os,osproc] +import std/[strformat,os,osproc,unittest] const nim = getCurrentCompilerExe() @@ -15,8 +15,9 @@ const mode = elif defined(cpp): "cpp" else: static: doAssert false +const testsDir = currentSourcePath().parentDir + proc runCmd(file, options = ""): auto = - const testsDir = currentSourcePath().parentDir let fileabs = testsDir / file.unixToNativePath doAssert fileabs.existsFile, fileabs let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs}" @@ -55,11 +56,11 @@ ret=[s1:foobar s2:foobar age:25 pi:3.14] else: # don't run twice the same test import std/[strutils] - template check(msg) = doAssert msg in output, output + template check2(msg) = doAssert msg in output, output block: # mstatic_assert let (output, exitCode) = runCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad") - check "sizeof(bool) == 2" + check2 "sizeof(bool) == 2" doAssert exitCode != 0 block: # ABI checks @@ -72,11 +73,11 @@ else: # don't run twice the same test # on platforms that support _StaticAssert natively, errors will show full context, eg: # error: static_assert failed due to requirement 'sizeof(unsigned char) == 8' # "backend & Nim disagree on size for: BadImportcType{int64} [declared in mabi_check.nim(1, 6)]" - check "sizeof(unsigned char) == 8" - check "sizeof(struct Foo2) == 1" - check "sizeof(Foo5) == 16" - check "sizeof(Foo5) == 3" - check "sizeof(struct Foo6) == " + check2 "sizeof(unsigned char) == 8" + check2 "sizeof(struct Foo2) == 1" + check2 "sizeof(Foo5) == 16" + check2 "sizeof(Foo5) == 3" + check2 "sizeof(struct Foo6) == " doAssert exitCode != 0 import streams @@ -103,3 +104,21 @@ else: # don't run twice the same test var (output, exitCode) = execCmdEx(cmd) output.stripLineEnd doAssert output == expected + + block: # nim doc --backend:$backend --doccmd:$cmd + # test for https://github.com/nim-lang/Nim/issues/13129 + # test for https://github.com/nim-lang/Nim/issues/13891 + const buildDir = testsDir.parentDir / "build" + const nimcache = buildDir / "nimcacheTrunner" + # `querySetting(nimcacheDir)` would also be possible, but we thus + # avoid stomping on other parallel tests + let file = testsDir / "nimdoc/m13129.nim" + for backend in fmt"{mode} js".split: + let cmd = fmt"{nim} doc -b:{backend} --nimcache:{nimcache} -d:m13129Foo1 --doccmd:'-d:m13129Foo2 --hints:off' --usenimcache --hints:off {file}" + check execCmdEx(cmd) == (&"ok1:{backend}\nok2: backend: {backend}\n", 0) + # checks that --usenimcache works with `nim doc` + check fileExists(nimcache / "m13129.html") + + block: # mak sure --backend works with `nim r` + let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("ok3\n", 0) diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim index 79527d584..98565ab94 100644 --- a/tests/vm/tcompilesetting.nim +++ b/tests/vm/tcompilesetting.nim @@ -17,3 +17,4 @@ static: doAssert "myNimCache" in nc doAssert "myNimblePath" in np[0] +doAssert querySetting(backend) == "c" From 14f76f721da663c9ef15d4adf51ab4c87eda8366 Mon Sep 17 00:00:00 2001 From: Jovial Joe Jayarson Date: Mon, 11 May 2020 17:20:40 +0530 Subject: [PATCH 0504/4254] refactor: renamed readme to readme.md (#14283) --- compiler/readme.md | 7 +++++++ compiler/readme.txt | 5 ----- 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 compiler/readme.md delete mode 100644 compiler/readme.txt diff --git a/compiler/readme.md b/compiler/readme.md new file mode 100644 index 000000000..ac47508dc --- /dev/null +++ b/compiler/readme.md @@ -0,0 +1,7 @@ +## Nim Compiler + +- This directory contains the Nim compiler written in Nim. +- Note that this code has been translated from a bootstrapping version written in Pascal. +- So the code is **not** a poster child of good Nim code. + +See [Internals of the Nim Compiler](https://nim-lang.org/docs/intern.html) for more information. diff --git a/compiler/readme.txt b/compiler/readme.txt deleted file mode 100644 index ccfad7748..000000000 --- a/compiler/readme.txt +++ /dev/null @@ -1,5 +0,0 @@ -This directory contains the Nim compiler written in Nim. Note that this -code has been translated from a bootstrapping version written in Pascal, so -the code is **not** a poster child of good Nim code. - -See https://nim-lang.org/docs/intern.html for more information. From 73c9d2c9d745e4396dbfc9e9422acdfa7809b705 Mon Sep 17 00:00:00 2001 From: Antonis Date: Mon, 11 May 2020 12:45:55 +0300 Subject: [PATCH 0505/4254] Fix for --styleCheck:error --- lib/system/mm/boehm.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/system/mm/boehm.nim b/lib/system/mm/boehm.nim index b1afe59fc..362d2d470 100644 --- a/lib/system/mm/boehm.nim +++ b/lib/system/mm/boehm.nim @@ -53,14 +53,14 @@ when not defined(useNimRtl): proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer = result = boehmRealloc(p, newSize) if result == nil: raiseOutOfMem() - if newsize > oldsize: - zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize) + if newSize > oldSize: + zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize) proc deallocImpl(p: pointer) = boehmDealloc(p) proc allocSharedImpl(size: Natural): pointer = allocImpl(size) proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size) - proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize) - proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize) + proc reallocSharedImpl(p: pointer, newSize: Natural): pointer = reallocImpl(p, newSize) + proc reallocShared0Impl(p: pointer, oldSize, newSize: Natural): pointer = realloc0Impl(p, oldSize, newSize) proc deallocSharedImpl(p: pointer) = deallocImpl(p) when hasThreadSupport: From 3616b0698baf230fec7a60cd90c72b979e582179 Mon Sep 17 00:00:00 2001 From: Antonis Date: Mon, 11 May 2020 14:51:50 +0300 Subject: [PATCH 0506/4254] fix closure env check --- compiler/injectdestructors.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index ea1a97e24..9ed3d4189 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -382,7 +382,8 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) -proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':' +proc isClosureEnv(n: PNode): bool = + n.kind == nkDotExpr and n[0].kind == nkHiddenDeref and n[0][0].typ.kind == tyRef proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) From 517dd800f8e621aae0221f15c4ad7ad011c910b5 Mon Sep 17 00:00:00 2001 From: Antonis Date: Mon, 11 May 2020 14:59:51 +0300 Subject: [PATCH 0507/4254] better error message --- compiler/injectdestructors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 9ed3d4189..09c072da7 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -398,7 +398,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = if isLValue(n) and not isClosureEnv(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & - "use 'move($1)' to prevent it") % $n) + "if possible, rearrange your program's control flow to prevent it") % $n) else: if c.graph.config.selectedGC in {gcArc, gcOrc}: assert(not containsGarbageCollectedRef(n.typ)) From 03c146cd93ba48f7e8cab05e6214c8675d0dd1f9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 11 May 2020 16:25:56 +0200 Subject: [PATCH 0508/4254] do not track 'raise Defect' in the .raises: [] clause anymore (#14298) * do not track 'raise Defect' in the .raises: [] clause anymore * --panics:on maps 'raise Defect' to an unrecoverable fatal error * make tests green again * update the documentation too --- changelog.md | 33 +++++++++++++++++++++++++++++---- compiler/sempass2.nim | 5 ++++- compiler/types.nim | 11 +++++++++++ doc/manual.rst | 22 ++++++++++++++++++++++ lib/system/excpt.nim | 7 ++++++- tests/effects/teffects7.nim | 4 ++-- 6 files changed, 74 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index f1ffb4a3a..9bf372dc4 100644 --- a/changelog.md +++ b/changelog.md @@ -46,11 +46,11 @@ used must be castable to `ptr string`, any incompatible pointer type will not work. The `lexbase` and `streams` modules used to fail to compile on NimScript due to a bug, but this has been fixed. - + The following modules now compile on both JS and NimScript: `parsecsv`, `parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for - NimScript: `json`, `parsejson`, `strtabs` and `unidecode`. + NimScript: `json`, `parsejson`, `strtabs` and `unidecode`. - Added `streams.readStr` and `streams.peekStr` overloads to accept an existing string to modify, which avoids memory @@ -68,7 +68,7 @@ - `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency with regular proc definitions (although you cannot use semicolons). - + Pragmas and using a name are now allowed on the lefthand side of `=>`. Here is an aggregate example of these changes: ```nim @@ -90,7 +90,8 @@ hangs if a process had both reads from stdin and writes (eg to stdout). ## Language changes -- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: +- In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: + ```nim type MyObj = object @@ -124,6 +125,30 @@ with command line switch `--useVersion:1.0`. - The keyword `from` is now usable as an operator. +- Exceptions inheriting from `system.Defect` are no longer tracked with + the `.raises: []` exception tracking mechanism. This is more consistent with the + built-in operations. The following always used to compile (and still does): + +```nim + +proc mydiv(a, b): int {.raises: [].} = + a div b # can raise an DivByZeroDefect + +``` + + Now also this compiles: + +```nim + +proc mydiv(a, b): int {.raises: [].} = + if b == 0: raise newException(DivByZeroDefect, "division by zero") + else: result = a div b + +``` + + The reason for this is that `DivByZeroDefect` inherits from `Defect` and + with `--panics:on` `Defects` become unrecoverable errors. + ## Compiler changes diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e1521475a..a7b01a75e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -315,7 +315,10 @@ proc addEffect(a: PEffects, e, comesFrom: PNode) = # we only track the first node that can have the effect E in order # to safe space and time. if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): return - throws(a.exc, e, comesFrom) + + if e.typ != nil: + if optNimV1Emulation in a.config.globalOptions or not isDefectException(e.typ): + throws(a.exc, e, comesFrom) proc addTag(a: PEffects, e, comesFrom: PNode) = var aa = a.tags diff --git a/compiler/types.nim b/compiler/types.nim index 241229df6..709e5bb2e 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1672,6 +1672,17 @@ proc isException*(t: PType): bool = t = skipTypes(t[0], abstractPtrs) return false +proc isDefectException*(t: PType): bool = + var t = t.skipTypes(abstractPtrs) + while t.kind == tyObject: + if t.sym != nil and t.sym.owner != nil and + sfSystemModule in t.sym.owner.flags and + t.sym.name.s == "Defect": + return true + if t[0] == nil: break + t = skipTypes(t[0], abstractPtrs) + return false + proc isSinkTypeForParam*(t: PType): bool = # a parameter like 'seq[owned T]' must not be used only once, but its # elements must, so we detect this case here: diff --git a/doc/manual.rst b/doc/manual.rst index 02ccace2c..6feb8aebb 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4338,6 +4338,28 @@ Rules 1-2 ensure the following works: So in many cases a callback does not cause the compiler to be overly conservative in its effect analysis. +Exceptions inheriting from ``system.Defect`` are not tracked with +the ``.raises: []`` exception tracking mechanism. This is more consistent with the +built-in operations. The following code is valid:: + +.. code-block:: nim + + proc mydiv(a, b): int {.raises: [].} = + a div b # can raise an DivByZeroDefect + +And so is:: + +.. code-block:: nim + + proc mydiv(a, b): int {.raises: [].} = + if b == 0: raise newException(DivByZeroDefect, "division by zero") + else: result = a div b + + +The reason for this is that ``DivByZeroDefect`` inherits from ``Defect`` and +with ``--panics:on`` Defects become unrecoverable errors. +(Since version 1.4 of the language.) + Tag tracking ------------ diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 747b145ae..bbb890cd4 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -406,7 +406,7 @@ proc reportUnhandledError(e: ref Exception) {.nodestroy.} = when hostOS != "any": reportUnhandledErrorAux(e) else: - discard() + discard () proc nimLeaveFinally() {.compilerRtl.} = when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions: @@ -434,6 +434,11 @@ when gotoBasedExceptions: quit(1) proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = + when defined(nimPanics): + if e of Defect: + reportUnhandledError(e) + quit(1) + if localRaiseHook != nil: if not localRaiseHook(e): return if globalRaiseHook != nil: diff --git a/tests/effects/teffects7.nim b/tests/effects/teffects7.nim index aee5e027d..73865b18d 100644 --- a/tests/effects/teffects7.nim +++ b/tests/effects/teffects7.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "can raise an unlisted exception: ref FloatingPointDefect" + errormsg: "can raise an unlisted exception: ref ValueError" line: 10 """ @@ -7,7 +7,7 @@ proc foo() {.raises: [].} = try: discard except KeyError: - raise newException(FloatingPointDefect, "foo") + raise newException(ValueError, "foo") except Exception: discard From fee71d466cdb7cda96b55592abbf7d433639ab51 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 11 May 2020 18:10:54 +0100 Subject: [PATCH 0509/4254] fix #14294 (#14301) * fix #14294 * fix orc as well Co-authored-by: cooldome --- compiler/liftdestructors.nim | 7 ++++++- tests/destructor/tarc.nim | 26 +++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 6f4e5828d..d70b968a8 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -448,7 +448,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind of attachedAsgn, attachedDeepCopy: - doAssert t.assignment != nil + if t.assignment == nil: + return # protect from recursion body.add newHookCall(c.g, t.assignment, x, y) of attachedSink: # we always inline the move for better performance: @@ -465,8 +466,12 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = doAssert t.destructor != nil body.add destructorCall(c, t.destructor, x) of attachedTrace: + if t.attachedOps[c.kind] == nil: + return # protect from recursion body.add newHookCall(c.g, t.attachedOps[c.kind], x, y) of attachedDispose: + if t.attachedOps[c.kind] == nil: + return # protect from recursion body.add newHookCall(c.g, t.attachedOps[c.kind], x, nil) proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = diff --git a/tests/destructor/tarc.nim b/tests/destructor/tarc.nim index 1acc95fad..12ea46b2c 100644 --- a/tests/destructor/tarc.nim +++ b/tests/destructor/tarc.nim @@ -6,7 +6,9 @@ Success Hello 1 2 -0''' +0 +List +''' cmd: '''nim c --gc:arc $file''' """ @@ -145,3 +147,25 @@ proc bug13105 = bug13105() echo getOccupiedMem() - startMem + + +#------------------------------------------------------------------------------ +# issue #14294 + +import tables + +type + TagKind = enum + List = 0, Compound + + Tag = object + case kind: TagKind + of List: + values: seq[Tag] + of Compound: + compound: Table[string, Tag] + +var a = Tag(kind: List) +var b = a +echo a.kind +var c = a From a081b10b54ff78539e49d320ca12aabc20fc3ad8 Mon Sep 17 00:00:00 2001 From: b3liever <43617260+b3liever@users.noreply.github.com> Date: Mon, 11 May 2020 20:12:25 +0300 Subject: [PATCH 0510/4254] small refactoring (#14303) Co-authored-by: Antonis --- compiler/injectdestructors.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 09c072da7..009c683ae 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -382,8 +382,9 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) -proc isClosureEnv(n: PNode): bool = - n.kind == nkDotExpr and n[0].kind == nkHiddenDeref and n[0][0].typ.kind == tyRef +proc isCapturedVar(n: PNode): bool = + n.kind == nkDotExpr and n[0].kind == nkHiddenDeref and + n[0][0].kind == nkSym and n[0][0].sym.name.s[0] == ':' proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -395,7 +396,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = var m = genCopy(c, tmp, n) m.add p(n, c, normal) result.add m - if isLValue(n) and not isClosureEnv(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: + if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & "if possible, rearrange your program's control flow to prevent it") % $n) From 0f344a70c992594c7d6b794a6c2dd6c4b5b14685 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 11 May 2020 19:12:40 +0200 Subject: [PATCH 0511/4254] fixes #13946 (#14302) --- lib/pure/parsexml.nim | 14 ++++---------- lib/pure/strtabs.nim | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index a8e7aaab8..6ec77ebdb 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -299,21 +299,15 @@ template piRest*(my: XmlParser): string = assert(my.kind == xmlPI) my.b -proc rawData*(my: var XmlParser): string {.inline.} = +proc rawData*(my: var XmlParser): lent string {.inline.} = ## returns the underlying 'data' string by reference. ## This is only used for speed hacks. - when defined(gcDestructors): - result = move(my.a) - else: - shallowCopy(result, my.a) + result = my.a -proc rawData2*(my: var XmlParser): string {.inline.} = +proc rawData2*(my: var XmlParser): lent string {.inline.} = ## returns the underlying second 'data' string by reference. ## This is only used for speed hacks. - when defined(gcDestructors): - result = move(my.b) - else: - shallowCopy(result, my.b) + result = my.b proc getColumn*(my: XmlParser): int {.inline.} = ## get the current column the parser has arrived at. diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 375f212cd..26811cc65 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -228,7 +228,7 @@ proc enlarge(t: StringTableRef) = var n: KeyValuePairSeq newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): - if t.data[i].hasValue: rawInsert(t, n, t.data[i].key, t.data[i].val) + if t.data[i].hasValue: rawInsert(t, n, move t.data[i].key, move t.data[i].val) swap(t.data, n) proc `[]=`*(t: StringTableRef, key, val: string) {. From 76f7e958141eabc6dc317189fa12c123584e1b6e Mon Sep 17 00:00:00 2001 From: slangmgh <37659406+slangmgh@users.noreply.github.com> Date: Tue, 12 May 2020 01:17:37 +0800 Subject: [PATCH 0512/4254] Fix #14289 (#14304) [backport] --- lib/pure/asyncdispatch.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 1421db2e8..91778a5bc 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1000,10 +1000,11 @@ when defined(windows) or defined(nimdoc): proc addProcess*(pid: int, cb: Callback) = ## Registers callback ``cb`` to be called when process with process ID ## ``pid`` exited. + const NULL = Handle(0) let p = getGlobalDispatcher() let procFlags = SYNCHRONIZE var hProcess = openProcess(procFlags, 0, pid.DWORD) - if hProcess == INVALID_HANDLE_VALUE: + if hProcess == NULL: raiseOSError(osLastError()) var pcd = cast[PostCallbackDataPtr](allocShared0(sizeof(PostCallbackData))) From 86669ef5b4c9711d81e961c2f68a05aa4f4d9ece Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Mon, 11 May 2020 14:45:35 -0400 Subject: [PATCH 0513/4254] Make --backend:cpp|js work for :test: code-blocks as well (#14306) Continues https://github.com/nim-lang/Nim/commit/9502e39b634eea8e04f07ddc110b466387f42322 Ref: - https://github.com/nim-lang/Nim/commit/9502e39b634eea8e04f07ddc110b466387f42322#commitcomment-39087584 - https://github.com/nim-lang/Nim/pull/14278 Fixes https://github.com/nim-lang/Nim/issues/13129 . --- compiler/docgen.nim | 3 ++- lib/packages/docutils/rstgen.nim | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index c01d5633f..d774fd508 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -216,7 +216,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, # Include the current file if we're parsing a nim file let importStmt = if d.isPureRst: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")] writeFile(outp, importStmt & content) - let c = if cmd.startsWith("nim "): os.getAppFilename() & cmd.substr(3) + let c = if cmd.startsWith("nim "): os.getAppFilename() & " " & $conf.backend & cmd.substr("nim ".len) + elif cmd.startsWith("nim "): os.getAppFilename() & cmd.substr("nim".len) else: cmd let c2 = c % quoteShell(outp) rawMessage(conf, hintExecuting, c2) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 13dff68e9..edd987a76 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -865,7 +865,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = of "test": params.testCmd = n.getFieldValue.strip if params.testCmd.len == 0: - params.testCmd = "nim c -r $1" + params.testCmd = "nim -r $1" # The nim backend is auto-set in docgen.nim else: params.testCmd = unescape(params.testCmd) of "status", "exitcode": From a39123c93c9d2976300f1b8eba09d40b16f1c46c Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 11 May 2020 22:11:20 +0100 Subject: [PATCH 0514/4254] fix #14219 (#14225) Co-authored-by: cooldome --- compiler/injectdestructors.nim | 2 +- tests/arc/amodule.nim | 10 ++++++++++ tests/arc/tamodule.nim | 6 ++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/arc/amodule.nim create mode 100644 tests/arc/tamodule.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 009c683ae..431f9539f 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1064,7 +1064,7 @@ proc injectDefaultCalls(n: PNode, c: var Con) = proc extractDestroysForTemporaries(c: Con, destroys: PNode): PNode = result = newNodeI(nkStmtList, destroys.info) for i in 0.. Date: Mon, 11 May 2020 23:27:47 -0700 Subject: [PATCH 0515/4254] properly fixes #13758 so that `import std/macros` stays legal (#14291) * properly fix https://github.com/nim-lang/Nim/issues/12389 * use --lib:lib in koch.nim.cfg instead * third time is the charm --- compiler/nim.nim | 2 +- koch.nim | 12 +++++++++--- koch.nim.cfg | 8 +++++++- lib/pure/typetraits.nim | 3 +-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/compiler/nim.nim b/compiler/nim.nim index b48fce0b8..2b0d78dd4 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -24,7 +24,7 @@ import idents, lineinfos, cmdlinehelper, pathutils -from browsers import openDefaultBrowser +from std/browsers import openDefaultBrowser from nodejs import findNodeJs when hasTinyCBackend: diff --git a/koch.nim b/koch.nim index 8b7eecf7c..3ec40534b 100644 --- a/koch.nim +++ b/koch.nim @@ -27,8 +27,10 @@ when defined(amd64) and defined(windows) and defined(vcc): when defined(i386) and defined(windows) and defined(vcc): {.link: "icons/koch-i386-windows-vcc.res".} -import - os, strutils, parseopt, osproc +import std/[os, strutils, parseopt, osproc] + # Using `std/os` instead of `os` to fail early if config isn't set up properly. + # If this fails with: `Error: cannot open file: std/os`, see + # https://github.com/nim-lang/Nim/pull/14291 for explanation + how to fix. import tools / kochdocs import tools / deps @@ -318,9 +320,13 @@ proc boot(args: string) = let ret = execCmdEx(nimStart & " --version") doAssert ret.exitCode == 0 let version = ret.output.splitLines[0] + # remove these when csources get updated + template addLib() = + extraOption.add " --lib:lib" # see https://github.com/nim-lang/Nim/pull/14291 if version.startsWith "Nim Compiler Version 0.19.0": extraOption.add " -d:nimBoostrapCsources0_19_0" - # remove this when csources get updated + addLib() + elif version.startsWith "Nim Compiler Version 0.20.0": addLib() # in order to use less memory, we split the build into two steps: # --compileOnly produces a $project.json file and does not run GCC/Clang. diff --git a/koch.nim.cfg b/koch.nim.cfg index 1d7acf579..c624b9577 100644 --- a/koch.nim.cfg +++ b/koch.nim.cfg @@ -1 +1,7 @@ --d:booting \ No newline at end of file +-d:booting + +@if openbsd: + # because openbsd getAppFilename was broken in v0.20.0 + # workaround see https://github.com/nim-lang/Nim/pull/14291 + --lib:lib +@end diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 0ac6d0d1c..9a215a353 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -93,8 +93,7 @@ since (1, 1): type StaticParam*[value: static type] = object ## used to wrap a static value in `genericParams` -# NOTE: See https://github.com/nim-lang/Nim/issues/13758 - `import std/macros` does not work on OpenBSD -import macros +import std/macros macro genericParamsImpl(T: typedesc): untyped = # auxiliary macro needed, can't do it directly in `genericParams` From 55446c05a4ed726a6aa26bdf5f0da1db5ad7d5f1 Mon Sep 17 00:00:00 2001 From: Avahe Kellenberger Date: Tue, 12 May 2020 02:28:10 -0400 Subject: [PATCH 0516/4254] Added a reference to ternary operators. (#14309) `if expressions` are similar to ternary operators in other languages. In order to make this easier to find in the manual, I've added a sentence about it. --- doc/manual.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/manual.rst b/doc/manual.rst index 6feb8aebb..82678f40e 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3128,6 +3128,7 @@ If expression ------------- An `if expression` is almost like an if statement, but it is an expression. +This feature is similar to `ternary operators` in other languages. Example: .. code-block:: nim From 2d7ccf09282ba7f7156b2f2d9893cb083cd18549 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 12 May 2020 10:23:05 +0100 Subject: [PATCH 0517/4254] fix #14312 --- compiler/liftdestructors.nim | 15 +++++++++------ tests/arc/tcaseobj.nim | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index d70b968a8..2a7301f24 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -62,9 +62,18 @@ proc newAsgnStmt(le, ri: PNode): PNode = result[0] = le result[1] = ri +proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = + result = newNodeI(nkCall, i.info) + result.add createMagic(g, name, magic).newSymNode + result.add i + proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}: body.add newAsgnStmt(x, y) + elif c.kind == attachedDestructor and c.addMemReset: + let call = genBuiltin(c.g, mDefault, "default", x) + call.typ = t + body.add newAsgnStmt(x, call) proc genAddr(g: ModuleGraph; x: PNode): PNode = if x.kind == nkHiddenDeref: @@ -74,12 +83,6 @@ proc genAddr(g: ModuleGraph; x: PNode): PNode = result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ)) result.add x - -proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = - result = newNodeI(nkCall, i.info) - result.add createMagic(g, name, magic).newSymNode - result.add i - proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = result = newNodeI(nkWhileStmt, c.info, 2) let cmp = genBuiltin(c.g, mLtI, "<", i) diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim index dd02675cc..107cf9fc1 100644 --- a/tests/arc/tcaseobj.nim +++ b/tests/arc/tcaseobj.nim @@ -194,8 +194,6 @@ proc test_myobject = test_myobject() - - #------------------------------------------------ # bug #14244 @@ -212,3 +210,16 @@ proc init(): RocksDBResult[string] = result.value = "ok" echo init() + + +#------------------------------------------------ +# bug #14312 + +type MyObj = object + case kind: bool + of false: x0: int # would work with a type like seq[int]; value would be reset + of true: x1: string + +var a = MyObj(kind: false, x0: 1234) +a.kind = true +doAssert(a.x1 == "") From dfae796ac3e0db69af40bec11a7d7ad7c4d00b4b Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 12 May 2020 11:45:14 +0100 Subject: [PATCH 0518/4254] fix test --- compiler/liftdestructors.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 2a7301f24..6f7b285ed 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -143,9 +143,6 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) fillBody(c, f.typ, body, x.dotField(f), b) of nkNilLit: discard of nkRecCase: - let oldfilterDiscriminator = c.filterDiscriminator - if c.filterDiscriminator == n[0].sym: - c.filterDiscriminator = nil # we have found the case part, proceed as normal # XXX This is only correct for 'attachedSink'! var localEnforceDefaultOp = enforceDefaultOp if c.kind == attachedSink: @@ -159,6 +156,11 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) # copy the selector: fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false) + + let oldfilterDiscriminator = c.filterDiscriminator + if c.filterDiscriminator == n[0].sym: + c.filterDiscriminator = nil # we have found the case part, proceed as normal + # we need to generate a case statement: var caseStmt = newNodeI(nkCaseStmt, c.info) # XXX generate 'if' that checks same branches From 4277ab470a20f429605fbf238e485ea24b01706a Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 12 May 2020 12:45:34 +0100 Subject: [PATCH 0519/4254] fix one motr dicriminator bug --- compiler/liftdestructors.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 6f7b285ed..5faba79f9 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -154,8 +154,9 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) c.kind = prevKind localEnforceDefaultOp = true - # copy the selector: - fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false) + if c.kind != attachedDestructor: + # copy the selector before case stmt, but destroy after case stmt + fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false) let oldfilterDiscriminator = c.filterDiscriminator if c.filterDiscriminator == n[0].sym: @@ -179,6 +180,10 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) caseStmt.add(branch) if emptyBranches != n.len-1: body.add(caseStmt) + + if c.kind == attachedDestructor: + # destructor for selector is done after case stmt + fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false) c.filterDiscriminator = oldfilterDiscriminator of nkRecList: for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp) From 06dfd316127fb2ec05ff69942abd1e279156ac5c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 May 2020 15:46:24 +0200 Subject: [PATCH 0520/4254] fixes #13881 * fixes #13881 * documented changed requirements for system.onThreadDestruction * destructors.rst: update the documentation --- changelog.md | 3 +++ compiler/condsyms.nim | 1 + doc/destructors.rst | 47 ++++++++++++++++++++++++++++++++++--- lib/system.nim | 4 ++-- lib/system/excpt.nim | 8 +++++++ lib/system/gc.nim | 7 +++--- lib/system/gc_interface.nim | 6 ++--- lib/system/gc_ms.nim | 7 +++--- lib/system/threads.nim | 24 ++++++++++++------- 9 files changed, 84 insertions(+), 23 deletions(-) diff --git a/changelog.md b/changelog.md index 9bf372dc4..af6217324 100644 --- a/changelog.md +++ b/changelog.md @@ -89,6 +89,9 @@ - Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to hangs if a process had both reads from stdin and writes (eg to stdout). +- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. + + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 5333e639c..7b05faa87 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -117,3 +117,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNewIntegerOps") defineSymbol("nimHasInvariant") defineSymbol("nimHasStacktraceMsgs") + defineSymbol("nimDoesntTrackDefects") diff --git a/doc/destructors.rst b/doc/destructors.rst index 2b1222778..e7ebd93ea 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -469,10 +469,51 @@ for expressions of type ``lent T`` or of type ``var T``. echo t[0] # accessor does not copy the element! +The .cursor annotation +====================== + +Under the ``--gc:arc|orc`` modes Nim's `ref` type is implemented via the same runtime +"hooks" and thus via reference counting. This means that cyclic structures cannot be freed +immediately (``--gc:orc`` ships with a cycle collector). With the ``.cursor`` annotation +one can break up cycles declaratively: + +.. code-block:: nim + + type + Node = ref object + left: Node # owning ref + right {.cursor.}: Node # non-owning ref + +But please notice that this is not C++'s weak_ptr, it means the right field is not +involved in the reference counting, it is a raw pointer without runtime checks. + +Automatic reference counting also has the disadvantage that it introduces overhead +when iterating over linked structures. The ``.cursor`` annotation can also be used +to avoid this overhead: + +.. code-block:: nim + + var it {.cursor.} = listRoot + while it != nil: + use(it) + it = it.next + + +In fact, ``.cursor`` more generally prevents object construction/destruction pairs +and so can also be useful in other contexts. The alternative solution would be to +use raw pointers (``ptr``) instead which is more cumbersome and also more dangerous +for Nim's evolution: Later on the compiler can try to prove ``.cursor`` annotations +to be safe, but for ``ptr`` the compiler has to remain silent about possible +problems. + Owned refs ========== +**Note**: The ``owned`` type constructor is only available with +the ``--newruntime`` compiler switch and is experimental. + + Let ``W`` be an ``owned ref`` type. Conceptually its hooks look like: .. code-block:: nim @@ -568,14 +609,14 @@ used to specialize the object traversal in order to avoid deep recursions: type Node = ref object x, y: int32 - left, right: owned Node + left, right: Node type Tree = object - root: owned Node + root: Node proc `=destroy`(t: var Tree) {.nodestroy.} = # use an explicit stack so that we do not get stack overflows: - var s: seq[owned Node] = @[t.root] + var s: seq[Node] = @[t.root] while s.len > 0: let x = s.pop if x.left != nil: s.add(x.left) diff --git a/lib/system.nim b/lib/system.nim index 8878277b7..8ce79aa2f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -692,7 +692,7 @@ proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} ## Returns the length of a compatible string. This is sometimes ## an O(n) operation. - ## + ## ## **Note:** On the JS backend this currently counts UTF-16 code points ## instead of bytes at runtime (not at compile time). For now, if you ## need the byte length of the UTF-8 encoding, convert to string with @@ -2093,7 +2093,7 @@ when not defined(js): when hasAlloc: when not defined(gcRegions) and not usesDestructors: - proc initGC() {.gcsafe.} + proc initGC() {.gcsafe, raises: [].} proc initStackBottom() {.inline, compilerproc.} = # WARNING: This is very fragile! An array size of 8 does not work on my diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index bbb890cd4..fd1a73b2d 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -493,6 +493,14 @@ proc reraiseException() {.compilerRtl.} = else: raiseExceptionAux(currException) +proc threadTrouble() = + # also forward declared, it is 'raises: []' hence the try-except. + try: + if currException != nil: reportUnhandledError(currException) + except: + discard + quit 1 + proc writeStackTrace() = when hasSomeStackTrace: var s = "" diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 2be16ef90..304eda19a 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -843,9 +843,10 @@ when not defined(useNimRtl): proc GC_disable() = inc(gch.recGcLock) proc GC_enable() = - if gch.recGcLock <= 0: - raise newException(AssertionDefect, - "API usage error: GC_enable called but GC is already enabled") + when defined(nimDoesntTrackDefects): + if gch.recGcLock <= 0: + raise newException(AssertionDefect, + "API usage error: GC_enable called but GC is already enabled") dec(gch.recGcLock) proc GC_setStrategy(strategy: GC_Strategy) = diff --git a/lib/system/gc_interface.nim b/lib/system/gc_interface.nim index 9183e6d48..84145f33a 100644 --- a/lib/system/gc_interface.nim +++ b/lib/system/gc_interface.nim @@ -14,7 +14,7 @@ when hasAlloc: gcOptimizeSpace ## optimize for memory footprint when hasAlloc and not defined(js) and not usesDestructors: - proc GC_disable*() {.rtl, inl, benign.} + proc GC_disable*() {.rtl, inl, benign, raises: [].} ## Disables the GC. If called `n` times, `n` calls to `GC_enable` ## are needed to reactivate the GC. ## @@ -22,7 +22,7 @@ when hasAlloc and not defined(js) and not usesDestructors: ## the mark and sweep phase with ## `GC_disableMarkAndSweep <#GC_disableMarkAndSweep>`_. - proc GC_enable*() {.rtl, inl, benign.} + proc GC_enable*() {.rtl, inl, benign, raises: [].} ## Enables the GC again. proc GC_fullCollect*() {.rtl, benign.} @@ -54,7 +54,7 @@ when hasAlloc and not defined(js) and not usesDestructors: proc GC_unref*(x: string) {.magic: "GCunref", benign.} ## See the documentation of `GC_ref <#GC_ref,string>`_. - proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.} + proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign, raises: [].} ## Expands operating GC stack range to `theStackBottom`. Does nothing ## if current stack bottom is already lower than `theStackBottom`. diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index eda220901..0b9745f1e 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -495,9 +495,10 @@ when not defined(useNimRtl): proc GC_disable() = inc(gch.recGcLock) proc GC_enable() = - if gch.recGcLock <= 0: - raise newException(AssertionDefect, - "API usage error: GC_enable called but GC is already enabled") + when defined(nimDoesntTrackDefects): + if gch.recGcLock <= 0: + raise newException(AssertionDefect, + "API usage error: GC_enable called but GC is already enabled") dec(gch.recGcLock) proc GC_setStrategy(strategy: GC_Strategy) = discard diff --git a/lib/system/threads.nim b/lib/system/threads.nim index b3a4e32e4..34a2d2ccf 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -89,9 +89,9 @@ type data: TArg var - threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe.}] + threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}] -proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) = +proc onThreadDestruction*(handler: proc () {.closure, gcsafe, raises: [].}) = ## Registers a *thread local* handler that is called at the thread's ## destruction. ## @@ -105,7 +105,10 @@ template afterThreadRuns() = threadDestructionHandlers[i]() when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions): - proc deallocOsPages() {.rtl.} + proc deallocOsPages() {.rtl, raises: [].} + +proc threadTrouble() {.raises: [].} + ## defined in system/excpt.nim when defined(boehmgc): type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.} @@ -116,7 +119,7 @@ when defined(boehmgc): proc boehmGC_unregister_my_thread() {.importc: "GC_unregister_my_thread", boehmGC.} - proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} = + proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv, raises: [].} = boehmGC_register_my_thread(sb) try: let thrd = cast[ptr Thread[TArg]](thrd) @@ -124,11 +127,13 @@ when defined(boehmgc): thrd.dataFn() else: thrd.dataFn(thrd.data) + except: + threadTrouble() finally: afterThreadRuns() boehmGC_unregister_my_thread() else: - proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) = + proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) {.raises: [].} = try: when TArg is void: thrd.dataFn() @@ -139,21 +144,22 @@ else: var x: TArg deepCopy(x, thrd.data) thrd.dataFn(x) + except: + threadTrouble() finally: afterThreadRuns() -proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = +proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) {.raises: [].} = when defined(boehmgc): boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd) elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not usesDestructors: - var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall, gcsafe.} = - threadProcWrapDispatch[TArg] + var p {.volatile.}: pointer # init the GC for refc/markandsweep nimGC_setStackBottom(addr(p)) initGC() when declared(threadType): threadType = ThreadType.NimThread - p(thrd) + threadProcWrapDispatch[TArg](thrd) when declared(deallocOsPages): deallocOsPages() else: threadProcWrapDispatch(thrd) From de74362213baeb28d52c05c71cd9b8389ae69060 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 12 May 2020 07:19:03 -0700 Subject: [PATCH 0521/4254] fix #14314 do not analyze importc procs for effects (#14319) --- compiler/lineinfos.nim | 4 ++-- compiler/sempass2.nim | 7 ++++++- tests/misc/mimportc.nim | 26 ++++++++++++++++++++++++++ tests/trunner.nim | 14 ++++++++++---- 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 tests/misc/mimportc.nim diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index eea55defc..d6c863842 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -23,7 +23,7 @@ type errGeneralParseError, errNewSectionExpected, errInvalidDirectiveX, - errProveInit, + errProveInit, # deadcode errGenerated, errUser, warnCannotOpenFile, @@ -66,7 +66,7 @@ const errGeneralParseError: "general parse error", errNewSectionExpected: "new section expected", errInvalidDirectiveX: "invalid directive: '$1'", - errProveInit: "Cannot prove that '$1' is initialized.", + errProveInit: "Cannot prove that '$1' is initialized.", # deadcode errGenerated: "$1", errUser: "$1", warnCannotOpenFile: "cannot open '$1'", diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index a7b01a75e..862123eab 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1151,12 +1151,17 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PC t.config = g.config t.c = c +proc hasRealBody(s: PSym): bool = + ## also handles importc procs with runnableExamples, which requires `=`, + ## which is not a real implementation, refs #14314 + result = {sfForward, sfImportc} * s.flags == {} + proc trackProc*(c: PContext; s: PSym, body: PNode) = let g = c.graph var effects = s.typ.n[0] if effects.kind != nkEffectList: return # effects already computed? - if sfForward in s.flags: return + if not s.hasRealBody: return if effects.len == effectListLen: return var t: TEffects diff --git a/tests/misc/mimportc.nim b/tests/misc/mimportc.nim new file mode 100644 index 000000000..602c6372d --- /dev/null +++ b/tests/misc/mimportc.nim @@ -0,0 +1,26 @@ +#[ +this test will grow with more importc+importcpp tests; see driver in trunner.nim +]# + +{.emit:""" +struct A { + static int fun0(int a){ + return a; + } + static int& fun1(int& a){ + return a; + } +}; +""".} + +proc fun0*(a: cint): int {.importcpp:"A::$1(@)".} +proc fun1*(a: var cint): var int {.importcpp:"A::$1(@)".} = + ## some comment; this test is for #14314 + runnableExamples: discard + +proc main()= + var a = 10.cint + doAssert fun0(a) == a + doAssert fun1(a).addr == a.addr + echo "witness" +main() diff --git a/tests/trunner.nim b/tests/trunner.nim index e6a8a2077..bd74a8405 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -16,6 +16,10 @@ const mode = else: static: doAssert false const testsDir = currentSourcePath().parentDir +const buildDir = testsDir.parentDir / "build" +const nimcache = buildDir / "nimcacheTrunner" + # `querySetting(nimcacheDir)` would also be possible, but we thus + # avoid stomping on other parallel tests proc runCmd(file, options = ""): auto = let fileabs = testsDir / file.unixToNativePath @@ -108,10 +112,6 @@ else: # don't run twice the same test block: # nim doc --backend:$backend --doccmd:$cmd # test for https://github.com/nim-lang/Nim/issues/13129 # test for https://github.com/nim-lang/Nim/issues/13891 - const buildDir = testsDir.parentDir / "build" - const nimcache = buildDir / "nimcacheTrunner" - # `querySetting(nimcacheDir)` would also be possible, but we thus - # avoid stomping on other parallel tests let file = testsDir / "nimdoc/m13129.nim" for backend in fmt"{mode} js".split: let cmd = fmt"{nim} doc -b:{backend} --nimcache:{nimcache} -d:m13129Foo1 --doccmd:'-d:m13129Foo2 --hints:off' --usenimcache --hints:off {file}" @@ -122,3 +122,9 @@ else: # don't run twice the same test block: # mak sure --backend works with `nim r` let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}" check execCmdEx(cmd) == ("ok3\n", 0) + + block: # some importc tests + # issue #14314 + let file = testsDir / "misc/mimportc.nim" + let cmd = fmt"{nim} r -b:cpp --hints:off --nimcache:{nimcache} --warningAsError:ProveInit {file}" + check execCmdEx(cmd) == ("witness\n", 0) From dddfbcf211cd46453b78a9d207347a158311f85e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 12 May 2020 10:19:31 -0700 Subject: [PATCH 0522/4254] close #13071 by adding test: nim cpp -r --gc:arc` segfaults on caught AssertionError (#14323) --- tests/arc/texceptions.nim | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/arc/texceptions.nim diff --git a/tests/arc/texceptions.nim b/tests/arc/texceptions.nim new file mode 100644 index 000000000..c55b463fc --- /dev/null +++ b/tests/arc/texceptions.nim @@ -0,0 +1,16 @@ +discard """ + cmd: "nim cpp --gc:arc $file" +""" + +block: # issue #13071 + type MyExcept = object of CatchableError + proc gun()= + raise newException(MyExcept, "foo:") + proc fun()= + var a = "" + try: + gun() + except Exception as e: + a = e.msg & $e.name # was segfaulting here for `nim cpp --gc:arc` + doAssert a == "foo:MyExcept" + fun() From 09ea8f9cf8ee796bdd5f8a803d30216e7aefa6ba Mon Sep 17 00:00:00 2001 From: b3liever <43617260+b3liever@users.noreply.github.com> Date: Tue, 12 May 2020 21:09:56 +0300 Subject: [PATCH 0523/4254] fix detecting closure env for nested asts (#14326) Co-authored-by: b3liever --- compiler/injectdestructors.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 431f9539f..44409c760 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -26,7 +26,7 @@ import strutils, options, dfa, lowerings, tables, modulegraphs, msgs, lineinfos, parampatterns, sighashes, liftdestructors -from trees import exprStructuralEquivalent +from trees import exprStructuralEquivalent, getRoot from algorithm import reverse const @@ -383,8 +383,8 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) proc isCapturedVar(n: PNode): bool = - n.kind == nkDotExpr and n[0].kind == nkHiddenDeref and - n[0][0].kind == nkSym and n[0][0].sym.name.s[0] == ':' + let root = getRoot(n) + if root != nil: result = root.name.s[0] == ':' proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) From 82f008158cbc023c5e20103bfb4bda317be52fb2 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 12 May 2020 20:12:55 +0200 Subject: [PATCH 0524/4254] cycle collector: make it threadsafe --- lib/system/cyclicrefs_bacon.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/system/cyclicrefs_bacon.nim b/lib/system/cyclicrefs_bacon.nim index aeee6e3d9..5f0197384 100644 --- a/lib/system/cyclicrefs_bacon.nim +++ b/lib/system/cyclicrefs_bacon.nim @@ -89,15 +89,15 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = j.traceStack.add(head p[], cast[ptr PNimType](p[])[]) var - roots: CellSeq + roots {.threadvar.}: CellSeq proc unregisterCycle(s: Cell) = # swap with the last element. O(1) let idx = s.rootIdx - if idx >= roots.len or idx < 0: - cprintf("[Bug!] %ld\n", idx) - quit 1 - + when false: + if idx >= roots.len or idx < 0: + cprintf("[Bug!] %ld\n", idx) + quit 1 roots.d[idx] = roots.d[roots.len-1] roots.d[idx][0].rootIdx = idx dec roots.len From 9acbf99efb42d7d3f98f3d1d6677923fc4dd3a28 Mon Sep 17 00:00:00 2001 From: PMunch Date: Tue, 12 May 2020 20:28:18 +0200 Subject: [PATCH 0525/4254] Allow let to not have value when using importc (#14258) * Allow let to not have value when using importc This allows a let statement with the `{.importc.}` pragma to not be initialised with a value. This allows us to declare C constants as Nim lets without putting the value in the Nim code (which can lead to errors, and requires us to go looking for the value). Fixes #14253 * Proper fix and documentation + changelog entry * Improve testcase with one from timotheecour * Add test to verify it working with macros --- changelog.md | 5 ++--- compiler/semstmts.nim | 5 +++-- doc/manual.rst | 15 +++++++++++++++ tests/let/timportc.nim | 24 ++++++++++++++++++++++++ tests/let/timportc2.nim | 8 ++++++++ 5 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tests/let/timportc.nim create mode 100644 tests/let/timportc2.nim diff --git a/changelog.md b/changelog.md index af6217324..d54ed4c8c 100644 --- a/changelog.md +++ b/changelog.md @@ -122,11 +122,11 @@ deallocShared(x.val) x.val = nil ``` - - getImpl() on enum type symbols now returns field syms instead of idents. This helps with writing typed macros. Old behavior for backwards compatiblity can be restored with command line switch `--useVersion:1.0`. - +- ``let`` statements can now be used without a value if declared with + ``importc``/``importcpp``/``importjs``/``importobjc``. - The keyword `from` is now usable as an operator. - Exceptions inheriting from `system.Defect` are no longer tracked with the `.raises: []` exception tracking mechanism. This is more consistent with the @@ -152,7 +152,6 @@ proc mydiv(a, b): int {.raises: [].} = The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. - ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0e018dd0b..3faa32808 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -531,8 +531,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = # special type inference rule: 'var it = ownedPointer' is turned # into an unowned pointer. typ = typ.lastSon - else: - if symkind == skLet: localError(c.config, a.info, errLetNeedsInit) # this can only happen for errornous var statements: if typ == nil: continue @@ -620,6 +618,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = defaultConstructionError(c, v.typ, v.info) else: checkNilable(c, v) + # allow let to not be initialised if imported from C: + if v.kind == skLet and sfImportc notin v.flags: + localError(c.config, a.info, errLetNeedsInit) if sfCompileTime in v.flags: var x = newNodeI(result.kind, v.info) x.add result[i] diff --git a/doc/manual.rst b/doc/manual.rst index 82678f40e..8d4439644 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2679,6 +2679,11 @@ nor can their address be taken. They cannot be assigned new values. For let variables the same pragmas are available as for ordinary variables. +As ``let`` statements are immutable after creation they need to define a value +when they are declared. The only exception to this is if the ``{.importc.}`` +pragma (or any of the other ``importX`` pragmas) is applied, in this case the +value is expected to come from native code, typically a C/C++ ``const``. + Tuple unpacking --------------- @@ -7090,6 +7095,16 @@ spelled*: .. code-block:: proc printf(formatstr: cstring) {.header: "", importc: "printf", varargs.} +When ``importc`` is applied to a ``let`` statement it can omit its value which +will then be expected to come from C. This can be used to import a C ``const``: + +.. code-block:: + {.emit: "const int cconst = 42;".} + + let cconst {.importc, nodecl.}: cint + + assert cconst == 42 + Note that this pragma has been abused in the past to also work in the js backend for js objects and functions. : Other backends do provide the same feature under the same name. Also, when the target language diff --git a/tests/let/timportc.nim b/tests/let/timportc.nim new file mode 100644 index 000000000..85244da9f --- /dev/null +++ b/tests/let/timportc.nim @@ -0,0 +1,24 @@ +discard """ +targets: "c cpp js" +""" + +when defined(c) or defined(cpp): + {.emit:""" + const int TEST1 = 123; + #define TEST2 321 + """.} + +when defined(js): + {.emit:""" + const TEST1 = 123; + const TEST2 = 321; // JS doesn't have macros, so we just duplicate + """.} + +let + TEST0 = 1 + TEST1 {.importc, nodecl.}: cint + TEST2 {.importc, nodecl.}: cint + +doAssert TEST0 == 1 +doAssert TEST1 == 123 +doAssert TEST2 == 321 diff --git a/tests/let/timportc2.nim b/tests/let/timportc2.nim new file mode 100644 index 000000000..964305923 --- /dev/null +++ b/tests/let/timportc2.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "'let' symbol requires an initialization" + line: "7" +""" + +# Test that this still works when not annotated with importc +let test: cint +echo test From 1648f1dd9955c848f8fbaf46a89798ece21460cc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 13 May 2020 02:05:47 -0700 Subject: [PATCH 0526/4254] fix #14320 (tasyncawait.nim is recently very flaky) + avoid hardcoding service ports everywhere + flakyAssert (#14327) * hotfix #14320 tasyncawait.nim is recently very flaky * fix #14327 * add flakyAssert --- testament/lib/readme.md | 4 ++++ testament/lib/stdtest/netutils.nim | 12 ++++++++++ testament/lib/stdtest/testutils.nim | 25 ++++++++++++++++++++ tests/arc/tasyncawait.nim | 21 ++++++----------- tests/async/tasyncawait.nim | 27 +++++++-------------- tests/async/tasyncawait_cyclebreaker.nim | 21 ++++++----------- tests/async/tasyncsend4757.nim | 20 ++++++++-------- tests/async/tasyncssl.nim | 30 ++++++++++++++---------- tests/async/twinasyncrw.nim | 29 +++++++---------------- tests/config.nims | 5 +++- 10 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 testament/lib/readme.md create mode 100644 testament/lib/stdtest/netutils.nim create mode 100644 testament/lib/stdtest/testutils.nim diff --git a/testament/lib/readme.md b/testament/lib/readme.md new file mode 100644 index 000000000..20e866338 --- /dev/null +++ b/testament/lib/readme.md @@ -0,0 +1,4 @@ +This directory contains helper files used by several tests, to avoid +code duplication, akin to a std extension tailored for testament. + +Some of these could later migrate to stdlib. diff --git a/testament/lib/stdtest/netutils.nim b/testament/lib/stdtest/netutils.nim new file mode 100644 index 000000000..eb913a56a --- /dev/null +++ b/testament/lib/stdtest/netutils.nim @@ -0,0 +1,12 @@ +import std/[nativesockets, asyncdispatch, os] + +proc bindAvailablePort*(handle: SocketHandle, port = Port(0)): Port = + block: + var name: Sockaddr_in + name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) + name.sin_port = htons(uint16(port)) + name.sin_addr.s_addr = htonl(INADDR_ANY) + if bindAddr(handle, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) + result = getLocalAddr(handle, AF_INET)[1] diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim new file mode 100644 index 000000000..8083a63e8 --- /dev/null +++ b/testament/lib/stdtest/testutils.nim @@ -0,0 +1,25 @@ +import std/private/miscdollars + +template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = + ## API to deal with flaky or failing tests. This avoids disabling entire tests + ## altogether so that at least the parts that are working are kept being + ## tested. This also avoids making CI fail periodically for tests known to + ## be flaky. Finally, for known failures, passing `notifySuccess = true` will + ## log that the test succeeded, which may indicate that a bug was fixed + ## "by accident" and should be looked into. + const info = instantiationInfo(-1, true) + const expr = astToStr(cond) + if cond and not notifySuccess: + discard # silent success + else: + var msg2 = "" + toLocation(msg2, info.filename, info.line, info.column) + if cond: + # a flaky test is failing, we still report it but we don't fail CI + msg2.add " FLAKY_SUCCESS " + else: + # a previously failing test is now passing, a pre-existing bug might've been + # fixed by accidend + msg2.add " FLAKY_FAILURE " + msg2.add $expr & " " & msg + echo msg2 diff --git a/tests/arc/tasyncawait.nim b/tests/arc/tasyncawait.nim index 7135f4173..f29b8d2b2 100644 --- a/tests/arc/tasyncawait.nim +++ b/tests/arc/tasyncawait.nim @@ -3,7 +3,8 @@ discard """ cmd: "nim c --gc:orc $file" """ -import asyncdispatch, asyncnet, nativesockets, net, strutils, os +import asyncdispatch, asyncnet, nativesockets, net, strutils +from stdtest/netutils import bindAvailablePort var msgCount = 0 @@ -44,24 +45,16 @@ proc readMessages(client: AsyncFD) {.async.} = else: doAssert false -proc createServer(port: Port) {.async.} = - var server = createAsyncNativeSocket() - block: - var name: Sockaddr_in - name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) - name.sin_port = htons(uint16(port)) - name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), - sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError()) - +proc createServer(server: AsyncFD) {.async.} = discard server.SocketHandle.listen() while true: asyncCheck readMessages(await accept(server)) proc main = - asyncCheck createServer(Port(10335)) - asyncCheck launchSwarm(Port(10335)) + let server = createAsyncNativeSocket() + let port = bindAvailablePort(server.SocketHandle) + asyncCheck createServer(server) + asyncCheck launchSwarm(port) while true: poll() if clientCount == swarmSize: break diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index a52b0953d..aec4ce523 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -1,8 +1,5 @@ -discard """ - output: "2000" -""" -import asyncdispatch, asyncnet, nativesockets, net, strutils, os - +import asyncdispatch, asyncnet, nativesockets, net, strutils +from stdtest/netutils import bindAvailablePort var msgCount = 0 const @@ -42,26 +39,18 @@ proc readMessages(client: AsyncFD) {.async.} = else: doAssert false -proc createServer(port: Port) {.async.} = - var server = createAsyncNativeSocket() - block: - var name: Sockaddr_in - name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) - name.sin_port = htons(uint16(port)) - name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), - sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError()) - +proc createServer(server: AsyncFD) {.async.} = discard server.SocketHandle.listen() while true: asyncCheck readMessages(await accept(server)) -asyncCheck createServer(Port(10335)) -asyncCheck launchSwarm(Port(10335)) +let server = createAsyncNativeSocket() +let port = bindAvailablePort(server.SocketHandle) +asyncCheck createServer(server) +asyncCheck launchSwarm(port) while true: poll() if clientCount == swarmSize: break assert msgCount == swarmSize * messagesToSend -echo msgCount +doAssert msgCount == 2000 diff --git a/tests/async/tasyncawait_cyclebreaker.nim b/tests/async/tasyncawait_cyclebreaker.nim index 0304d4b82..2229d99c0 100644 --- a/tests/async/tasyncawait_cyclebreaker.nim +++ b/tests/async/tasyncawait_cyclebreaker.nim @@ -2,7 +2,8 @@ discard """ output: "20000" cmd: "nim c -d:nimTypeNames -d:nimCycleBreaker $file" """ -import asyncdispatch, asyncnet, nativesockets, net, strutils, os +import asyncdispatch, asyncnet, nativesockets, net, strutils +from stdtest/netutils import bindAvailablePort var msgCount = 0 @@ -43,23 +44,15 @@ proc readMessages(client: AsyncFD) {.async.} = else: doAssert false -proc createServer(port: Port) {.async.} = - var server = createAsyncNativeSocket() - block: - var name: Sockaddr_in - name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) - name.sin_port = htons(uint16(port)) - name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), - sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError()) - +proc createServer(server: AsyncFD) {.async.} = discard server.SocketHandle.listen() while true: asyncCheck readMessages(await accept(server)) -asyncCheck createServer(Port(10335)) -asyncCheck launchSwarm(Port(10335)) +let server = createAsyncNativeSocket() +let port = bindAvailablePort(server.SocketHandle) +asyncCheck createServer(server) +asyncCheck launchSwarm(port) while true: poll() GC_collectZct() diff --git a/tests/async/tasyncsend4757.nim b/tests/async/tasyncsend4757.nim index a87c5df95..29873a905 100644 --- a/tests/async/tasyncsend4757.nim +++ b/tests/async/tasyncsend4757.nim @@ -1,24 +1,24 @@ -discard """ -output: "Finished" -""" - import asyncdispatch, asyncnet -proc createServer(port: Port) {.async.} = +var port: Port +proc createServer() {.async.} = var server = newAsyncSocket() server.setSockOpt(OptReuseAddr, true) - bindAddr(server, port) + bindAddr(server) + port = getLocalAddr(server)[1] server.listen() while true: let client = await server.accept() discard await client.recvLine() -asyncCheck createServer(10335.Port) +asyncCheck createServer() +var done = false proc f(): Future[void] {.async.} = - let s = newAsyncNativeSocket() - await s.connect("localhost", 10335.Port) + let s = createAsyncNativeSocket() + await s.connect("localhost", port) await s.send("123") - echo "Finished" + done = true waitFor f() +doAssert done diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index 88a5eb32e..c948ee9b7 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -1,16 +1,12 @@ discard """ cmd: "nim $target --hints:on --define:ssl $options $file" - output: "500" - disabled: "windows" - target: c - action: compile """ -# XXX, deactivated - -import asyncdispatch, asyncnet, net, strutils, os +import asyncdispatch, asyncnet, net, strutils +import stdtest/testutils when defined(ssl): + var port0: Port var msgCount = 0 const @@ -45,25 +41,33 @@ when defined(ssl): else: doAssert false - proc createServer(port: Port) {.async.} = + proc createServer() {.async.} = let serverContext = newContext(verifyMode = CVerifyNone, certFile = "tests/testdata/mycert.pem", keyFile = "tests/testdata/mycert.pem") var server = newAsyncSocket() serverContext.wrapSocket(server) server.setSockOpt(OptReuseAddr, true) - bindAddr(server, port) + bindAddr(server) + port0 = getLocalAddr(server)[1] server.listen() while true: let client = await accept(server) serverContext.wrapConnectedSocket(client, handshakeAsServer) asyncCheck readMessages(client) - asyncCheck createServer(Port(10335)) - asyncCheck launchSwarm(Port(10335)) + asyncCheck createServer() + asyncCheck launchSwarm(port0) while true: poll() if clientCount == swarmSize: break - assert msgCount == swarmSize * messagesToSend - echo msgCount + template cond(): bool = msgCount == swarmSize * messagesToSend + when defined(windows): + # currently: msgCount == 0 + flakyAssert cond() + elif defined(linux) and int.sizeof == 8: + # currently: msgCount == 10 + flakyAssert cond() + assert msgCount > 0 + else: assert cond(), $msgCount diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim index 352c53b41..69b092607 100644 --- a/tests/async/twinasyncrw.nim +++ b/tests/async/twinasyncrw.nim @@ -1,9 +1,6 @@ -discard """ - output: "5000" -""" when defined(windows): import asyncdispatch, nativesockets, net, strutils, os, winlean - + from stdtest/netutils import bindAvailablePort var msgCount = 0 const @@ -228,29 +225,19 @@ when defined(windows): else: doAssert false - proc createServer(port: Port) {.async.} = - var server = createNativeSocket() - setBlocking(server, false) - block: - var name = Sockaddr_in() - name.sin_family = toInt(Domain.AF_INET).uint16 - name.sin_port = htons(uint16(port)) - name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(server, cast[ptr SockAddr](addr(name)), - sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError()) - + proc createServer(server: SocketHandle) {.async.} = discard server.listen() while true: asyncCheck readMessages(await winAccept(AsyncFD(server))) - asyncCheck createServer(Port(10335)) - asyncCheck launchSwarm(Port(10335)) + var server = createNativeSocket() + setBlocking(server, false) + let port = bindAvailablePort(server) + asyncCheck createServer(server) + asyncCheck launchSwarm(port) while true: poll() if clientCount == swarmSize: break assert msgCount == swarmSize * messagesToSend - echo msgCount -else: - echo(5000) + doAssert msgCount == 5000 diff --git a/tests/config.nims b/tests/config.nims index cd4ee4b08..e91c3aa4f 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -1,4 +1,7 @@ -switch("path", "$nim/testament/lib") # so we can `import stdtest/foo` in this dir +switch("path", "$lib/../testament/lib") + # so we can `import stdtest/foo` inside tests + # Using $lib/../ instead of $nim/ so you can use a different nim to run tests + # during local testing, eg nim --lib:lib. ## prevent common user config settings to interfere with testament expectations ## Indifidual tests can override this if needed to test for these options. From 041ee92bba0ba3f361218eb20ceeeee6eec85f91 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 13 May 2020 04:45:36 -0700 Subject: [PATCH 0527/4254] `osproc.execCmdEx` now takes an optional `input` for stdin, `env`, workingDir (#14211) * `osproc.execCmdEx` now takes an optional `input` for stdin * execCmdEx now also takes an optional ``workingDir` and `env` --- changelog.md | 4 ++++ lib/pure/osproc.nim | 41 +++++++++++++++++++++++++++++----------- lib/system.nim | 3 ++- tests/stdlib/tosproc.nim | 15 ++++++++++++++- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/changelog.md b/changelog.md index d54ed4c8c..d6be5a9b7 100644 --- a/changelog.md +++ b/changelog.md @@ -92,6 +92,10 @@ - The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. +- `osproc.execCmdEx` now takes an optional `input` for stdin. +- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` + parameters. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index f90b310ea..3e3391d52 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1438,12 +1438,16 @@ elif not defined(useNimRtl): proc execCmdEx*(command: string, options: set[ProcessOption] = { - poStdErrToStdOut, poUsePath}): tuple[ + poStdErrToStdOut, poUsePath}, env: StringTableRef = nil, + workingDir = "", input = ""): tuple[ output: TaintedString, exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = - ## A convenience proc that runs the `command`, grabs all its output and - ## exit code and returns both. + ## A convenience proc that runs the `command`, and returns its `output` and + ## `exitCode`. `env` and `workingDir` params behave as for `startProcess`. + ## If `input.len > 0`, it is passed as stdin. + ## Note: this could block if `input.len` is greater than your OS's maximum + ## pipe buffer size. ## ## See also: ## * `execCmd proc <#execCmd,string>`_ @@ -1452,17 +1456,32 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## * `execProcess proc ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## - ## Example: - ## - ## .. code-block:: Nim - ## let (outp, errC) = execCmdEx("nim c -r mytestfile.nim") + runnableExamples: + var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") + import strutils, strtabs + stripLineEnd(result[0]) ## portable way to remove trailing newline, if any + doAssert result == ("12", 0) + doAssert execCmdEx("ls --nonexistant").exitCode != 0 + when defined(posix): + assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) + assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) - var p = startProcess(command, options = options + {poEvalCommand}) + when (NimMajor, NimMinor, NimPatch) < (1, 3, 5): + doAssert input.len == 0 + doAssert workingDir.len == 0 + doAssert env == nil + + var p = startProcess(command, options = options + {poEvalCommand}, + workingDir = workingDir, env = env) var outp = outputStream(p) - # There is no way to provide input for the child process - # anymore. Closing it will create EOF on stdin instead of eternal - # blocking. + if input.len > 0: + # There is no way to provide input for the child process + # anymore. Closing it will create EOF on stdin instead of eternal + # blocking. + # Writing in chunks would require a selectors (eg kqueue/epoll) to avoid + # blocking on io. + inputStream(p).write(input) close inputStream(p) result = (TaintedString"", -1) diff --git a/lib/system.nim b/lib/system.nim index 8ce79aa2f..6b24bdcb8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2068,8 +2068,9 @@ const ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 3 + NimPatch* {.intdefine.}: int = 5 ## is the patch number of Nim's version. + ## Odd for devel, even for releases. import system/dollars export dollars diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index 73cec0cb7..36afd6a23 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -1,7 +1,7 @@ # test the osproc module import stdtest/specialpaths -import "../.." / compiler/unittest_light +import "$nim" / compiler/unittest_light when defined(case_testfile): # compiled test file for child process from posix import exitnow @@ -119,3 +119,16 @@ else: var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4") doAssert result == ("12\n", 0) + + import std/strtabs + block execProcessTest: + var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") + stripLineEnd(result[0]) + doAssert result == ("12", 0) + doAssert execCmdEx("ls --nonexistant").exitCode != 0 + when false: + # bug: on windows, this raises; on posix, passes + doAssert execCmdEx("nonexistant").exitCode != 0 + when defined(posix): + doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) + doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) From a3719df8b327ce33d4fdbfc7be06b058e9a2ea48 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 13 May 2020 14:29:37 +0200 Subject: [PATCH 0528/4254] fixes #14331 --- lib/pure/quitprocs.nim | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 lib/pure/quitprocs.nim diff --git a/lib/pure/quitprocs.nim b/lib/pure/quitprocs.nim new file mode 100644 index 000000000..76bbcdb2b --- /dev/null +++ b/lib/pure/quitprocs.nim @@ -0,0 +1,28 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## ``system.addQuitProc`` is nice and very useful but due to its C-based +## implementation it doesn't support closures which limits its usefulness. +## This module fixes this. Later versions of this module will also +## support the JavaScript backend. + +var + gClosures: seq[proc () {.closure.}] + +proc callClosures() {.noconv.} = + for i in countdown(gClosures.len-1, 0): + gClosures[i]() + +proc addQuitClosure*(cl: proc () {.closure.}) = + ## Like ``system.addQuitProc`` but it supports closures. + if gClosures.len == 0: + addQuitProc(callClosures) + gClosures = @[cl] + else: + gClosures.add(cl) From 3573a4f9c13ff2f68afbd1931fc06cc463eb1748 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 13 May 2020 08:19:44 -0700 Subject: [PATCH 0529/4254] no more guessing where compiler msgs came from (#14317) --- changelog.md | 3 +++ compiler/lineinfos.nim | 8 ++++--- compiler/msgs.nim | 48 ++++++++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/changelog.md b/changelog.md index d6be5a9b7..a93a7e651 100644 --- a/changelog.md +++ b/changelog.md @@ -175,6 +175,9 @@ proc mydiv(a, b): int {.raises: [].} = (likewise with other hints and warnings), which is consistent with all other bool flags. (since 1.3.3). - `nim doc -r main` and `nim rst2html -r main` now call openDefaultBrowser +- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) was generated; this + helps in particular when it's non obvious where it came from either because multiple locations generate + the same message, or because the message involves runtime formatting. ## Tool changes diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index d6c863842..2fd5a5a60 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -53,7 +53,8 @@ type hintSource, hintPerformance, hintStackTrace, hintGCStats, hintGlobalVar, hintExpandMacro, hintUser, hintUserRaw, - hintExtendedContext + hintExtendedContext, + hintMsgOrigin, # since 1.3.5 const MsgKindToStr*: array[TMsgKind, string] = [ @@ -140,6 +141,7 @@ const hintUser: "$1", hintUserRaw: "$1", hintExtendedContext: "$1", + hintMsgOrigin: "$1", ] const @@ -166,7 +168,7 @@ const "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency", "Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro", - "User", "UserRaw", "ExtendedContext", + "User", "UserRaw", "ExtendedContext", "MsgOrigin", ] const @@ -192,7 +194,7 @@ proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, - hintSource, hintGlobalVar, hintGCStats} + hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin} result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC} diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 43ed8f2a8..a43977606 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -12,6 +12,8 @@ import lineinfos, pathutils import std/private/miscdollars +type InstantiationInfo = typeof(instantiationInfo()) + proc toCChar*(c: char; result: var string) = case c of '\0'..'\x1F', '\x7F'..'\xFF': @@ -255,6 +257,9 @@ proc toLinenumber*(info: TLineInfo): int {.inline.} = proc toColumn*(info: TLineInfo): int {.inline.} = result = info.col +proc toFileLineCol(info: InstantiationInfo): string {.inline.} = + result.toLocation(info.filename, info.line, info.column + ColOffset) + proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} = result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset) @@ -487,7 +492,7 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg) proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, - eh: TErrorHandling) = + eh: TErrorHandling, info2: InstantiationInfo) {.noinline.} = var title: string color: ForegroundColor @@ -533,36 +538,47 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) if conf.hasHint(hintSource): conf.writeSurroundingSrc(info) + if conf.hasHint(hintMsgOrigin): + styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, KindFormat % HintsToStr[ord(hintMsgOrigin) - ord(hintMin)], resetStyle) + handleError(conf, msg, eh, s) -proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = +template fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = # this fixes bug #7080 so that it is at least obvious 'fatal' # was executed. conf.m.errorOutputs = {eStdOut, eStdErr} - liMessage(conf, info, msg, arg, doAbort) + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, msg, arg, doAbort, info2) -proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - liMessage(conf, info, msg, arg, doRaise) +template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, msg, arg, doRaise, info2) -proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = - liMessage(conf, info, errGenerated, arg, doRaise) +template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, errGenerated, arg, doRaise, info2) -proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - liMessage(conf, info, msg, arg, doNothing) +template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, msg, arg, doNothing, info2) -proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) = - liMessage(conf, info, errGenerated, arg, doNothing) +template localError*(conf: ConfigRef; info: TLineInfo, arg: string) = + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, errGenerated, arg, doNothing, info2) -proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) = - localError(conf, info, format % params) +template localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) = + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, errGenerated, format % params, doNothing, info2) -proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - liMessage(conf, info, msg, arg, doNothing) +template message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + const info2 = instantiationInfo(-1, fullPaths = true) + liMessage(conf, info, msg, arg, doNothing, info2) proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) = if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return + const info2 = instantiationInfo(-1, fullPaths = true) writeContext(conf, info) - liMessage(conf, info, errInternal, errMsg, doAbort) + liMessage(conf, info, errInternal, errMsg, doAbort, info2) proc internalError*(conf: ConfigRef; errMsg: string) = if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return From 79fe87500ff550bba5a2145d2cc405c9e0c944af Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 May 2020 22:17:38 +0200 Subject: [PATCH 0530/4254] fixes #13935 --- lib/system/mm/malloc.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 0525b0951..883baaeb4 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -1,4 +1,6 @@ +{.push stackTrace: off.} + proc allocImpl(size: Natural): pointer = c_malloc(size.csize_t) @@ -81,3 +83,4 @@ proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) proc deallocOsPages(r: var MemRegion) = discard proc deallocOsPages() = discard +{.pop.} From f3e17e7c776dff9c4557fabe97694612fa86d237 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 May 2020 22:29:02 +0200 Subject: [PATCH 0531/4254] fixes #13104 [backport] --- compiler/installer.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/installer.ini b/compiler/installer.ini index fdb717b61..ed815d2eb 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -88,6 +88,7 @@ Files: "bin/vccexe.exe" Files: "bin/nimgrab.exe" Files: "bin/nimpretty.exe" Files: "bin/testament.exe" +Files: "bin/nim-gdb.bat" Files: "koch.exe" Files: "finish.exe" @@ -111,6 +112,8 @@ Files: "bin/*.dll" [UnixBin] Files: "bin/nim" +Files: "bin/nim-gdb" +Files: "bin/nim-gdb.bash" [Unix] From 8a339d11787ab782557cf87fc2e4709fbff96a01 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 13 May 2020 18:01:00 +0200 Subject: [PATCH 0532/4254] fixes #13862 --- lib/system/mmdisp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 1cdf37604..5cdac2991 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -83,7 +83,7 @@ else: when not usesDestructors: include "system/cellsets" - when not leakDetector and not useCellIds: + when not leakDetector and not useCellIds and not defined(nimV2): sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell") when compileOption("gc", "v2"): include "system/gc2" From 82870e0737678256c83f8fc0f2d92293f9f214fe Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 May 2020 22:53:41 +0200 Subject: [PATCH 0533/4254] fixes #13998 [backport:1.2] --- compiler/ccgstmts.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c7c1569b0..20780f734 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -981,7 +981,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = inc(p.labels, 2) let etmp = p.labels - lineCg(p, cpsStmts, "std::exception_ptr T$1_ = nullptr;", [etmp]) + p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp])) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) From 5fb40af57ef66618d2003dae1091d80e8f026a1c Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 13 May 2020 22:57:05 +0100 Subject: [PATCH 0534/4254] fix #14333 (#14336) Co-authored-by: cooldome --- compiler/semtypes.nim | 6 ++---- tests/arc/tarcmisc.nim | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 275ad8a07..1aabe435f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -942,10 +942,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = t.rawAddSonNoPropagationOfTypeFlags result result = t else: discard - #if result.kind == tyRef and c.config.selectedGC == gcDestructors: - # result.flags.incl tfHasAsgn - # XXX Something like this is a good idea but it should be done - # in sempass2! + if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc}: + result.flags.incl tfHasAsgn proc findEnforcedStaticType(t: PType): PType = # This handles types such as `static[T] and Foo`, diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 79c947e82..24f02959c 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -3,6 +3,7 @@ discard """ 123xyzabc destroyed: false destroyed: false +1 closed destroying variable ''' @@ -118,4 +119,19 @@ proc free*(game: Game) = proc newGame*(): Game = new(result, free) -var game*: Game \ No newline at end of file +var game*: Game + + +#------------------------------------------------------------------------------ +# issue #14333 + +type + SimpleLoop = object + + Lsg = object + loops: seq[ref SimpleLoop] + root: ref SimpleLoop + +var lsg: Lsg +lsg.loops.add lsg.root +echo lsg.loops.len \ No newline at end of file From a2a3fa10397bc96020a19936daf76b12e9ba9763 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Thu, 14 May 2020 01:27:57 -0400 Subject: [PATCH 0535/4254] Fail quickly if re or nre module is attempted to be compiled with js [backport] (#14341) Fixes https://github.com/nim-lang/Nim/issues/14338 . --- lib/impure/nre.nim | 3 +++ lib/impure/re.nim | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 31ceede50..98965d8d2 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -6,6 +6,9 @@ # distribution, for details about the copyright. # +when defined(js): + {.error: "This library needs to be compiled with a c-like backend, and depends on PCRE.".} + ## What is NRE? ## ============ ## diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 809180774..0ad4e3727 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -7,6 +7,9 @@ # distribution, for details about the copyright. # +when defined(js): + {.error: "This library needs to be compiled with a c-like backend, and depends on PCRE.".} + ## Regular expression support for Nim. ## ## This module is implemented by providing a wrapper around the @@ -678,4 +681,3 @@ when isMainModule: doAssert replace("bar", re"^", "foo") == "foobar" doAssert replace("foo", re"", "-") == "-foo" doAssert replace("foo", re"$", "bar") == "foobar" - From 278b4582f5c7cc3471bccc4ba587030edf7a50e2 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 14 May 2020 08:51:47 +0200 Subject: [PATCH 0536/4254] fixes #14340 --- compiler/vm.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 3ac075f81..c15f9e268 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -453,7 +453,7 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): dest.intVal = cast[BiggestInt](value) of tyBool: dest.ensureKind(rkInt) - dest.intVal = + dest.intVal = case skipTypes(srctyp, abstractRange).kind of tyFloat..tyFloat64: int(src.floatVal != 0.0) else: int(src.intVal != 0) @@ -668,7 +668,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = elif src.kind notin {nkEmpty..nkFloat128Lit} and idx <% src.len: regs[ra].node = src[idx] else: - stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1)) + stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1)) of opcLdArrAddr: # a = addr(b[c]) decodeBC(rkNodeAddr) @@ -679,7 +679,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len: regs[ra].nodeAddr = addr src.sons[idx] else: - stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1)) + stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1)) of opcLdStrIdx: decodeBC(rkInt) let idx = regs[rc].intVal.int @@ -703,7 +703,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = elif idx <% arr.len: writeField(arr[idx], regs[rc]) else: - stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.len-1)) + stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.safeLen-1)) of opcLdObj: # a = b.c decodeBC(rkNode) From 80c360fceb367e8b39dd8534313001e5cef4fa7f Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Fri, 15 May 2020 11:07:30 +0300 Subject: [PATCH 0537/4254] fix #14350, cstrings in JS init as null (#14355) * fix #14350, cstrings in JS init as null --- compiler/jsgen.nim | 4 +--- tests/js/tmangle.nim | 4 ++-- tests/js/trepr.nim | 2 +- tests/system/tdollars.nim | 7 +++++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c4ee36dbf..6aacf818a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1690,9 +1690,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("null", indirect) of tySequence, tyString: result = putToSeq("[]", indirect) - of tyCString: - result = putToSeq("\"\"", indirect) - of tyOpt, tyProc: + of tyCString, tyOpt, tyProc: result = putToSeq("null", indirect) of tyStatic: if t.n != nil: diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim index 393043722..caaa15fa1 100644 --- a/tests/js/tmangle.nim +++ b/tests/js/tmangle.nim @@ -62,8 +62,8 @@ block: result = result and obj1.`&&`.addr[] == "bar".cstring result = result and obj2.`if` == 0 result = result and obj2.`for` == 0 - result = result and obj2.`==`.len == 0 - result = result and obj2.`&&`.len == 0 + result = result and obj2.`==`.isNil + result = result and obj2.`&&`.isNil echo test() # Test codegen for fields with uppercase letters: diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim index ffa9d4de0..eb285f70d 100644 --- a/tests/js/trepr.nim +++ b/tests/js/trepr.nim @@ -322,7 +322,7 @@ o = [Field0 = [a = "", b = @[]], Field1 = ""], p = nil, -q = ""] +q = nil] """) doAssert(repr(cc) == """ [a = 12, diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 478a11b94..6ddec911f 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -70,3 +70,10 @@ block: # `$`(SomeInteger) testType uint64 testType int64 testType BiggestInt + +block: # #14350 for JS + var cstr: cstring + doAssert cstr == cstring(nil) + doAssert cstr == nil + doAssert cstr.isNil + doAssert cstr != cstring("") From 105079e88ab88626ab663fa6674e9a5f08c71084 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev <21169548+Yardanico@users.noreply.github.com> Date: Fri, 15 May 2020 17:26:03 +0300 Subject: [PATCH 0538/4254] Speed up testing of some packages (#14358) --- testament/important_packages.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 4186ce30d..cdb98745c 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -21,8 +21,8 @@ pkg1 "bigints" pkg1 "binaryheap", false, "nim c -r binaryheap.nim" pkg1 "BipBuffer" # pkg1 "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39 -pkg1 "bncurve", true, "nim c -r tests/tvectors.nim" -pkg1 "brainfuck", true, "nim c -r tests/compile.nim" +pkg1 "bncurve", true +pkg1 "brainfuck", true, "nim c -d:release -r tests/compile.nim" pkg1 "bump", true, "nim c --gc:arc -r tests/tbump.nim", "https://github.com/disruptek/bump" pkg1 "c2nim", false, "nim c testsuite/tester.nim" pkg1 "cascade" @@ -42,7 +42,7 @@ pkg1 "delaunay" pkg1 "docopt" pkg1 "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg1 "elvis" -pkg1 "fidget", true, "nim c -r tests/runNative.nim" +pkg1 "fidget", true, "nim c -d:release -r tests/runNative.nim" pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "ggplotnim", true, "nim c -d:noCairo -r tests/tests.nim" @@ -108,7 +108,7 @@ pkg2 "patty" pkg2 "plotly", true, "nim c --oldgensym:on examples/all.nim" pkg2 "pnm" pkg2 "polypbren" -pkg2 "prologue", true, "nim c -r tests/test_compile/test_compile.nim" +pkg2 "prologue", true, "nim c -d:release -r tests/test_compile/test_compile.nim" pkg2 "protobuf", true, "nim c -o:protobuff -r src/protobuf.nim" pkg2 "pylib" pkg2 "rbtree" @@ -133,8 +133,8 @@ pkg2 "termstyle" pkg2 "timeit" pkg2 "timezones" pkg2 "tiny_sqlite" -pkg2 "unicodedb" -pkg2 "unicodeplus", true +pkg2 "unicodedb", false, "nim c -d:release -r tests/tests.nim" +pkg2 "unicodeplus", true, "nim c -d:release -r tests/tests.nim" pkg2 "unpack" pkg2 "websocket", false, "nim c websocket.nim" # pkg2 "winim", true From 13cfaf5fd55796bc671737a73f35643626c98b6e Mon Sep 17 00:00:00 2001 From: PMunch Date: Fri, 15 May 2020 19:32:52 +0200 Subject: [PATCH 0539/4254] Improve nimeval, changes some defaults (#14351) * Improve nimeval, changes some defaults This improves nimeval to make it easier to use NimScript as an embedded scripting languages. It does change some of the defaults, so in case anything used the old version and depended on the old behaviour these would have to be changed. * Remove dependency on nimhcr for nimscript --- compiler/nimeval.nim | 10 +++++++--- lib/system.nim | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 882e10fbb..09d1eb1da 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -99,14 +99,16 @@ proc findNimStdLibCompileTime*(): string = proc createInterpreter*(scriptName: string; searchPaths: openArray[string]; - flags: TSandboxFlags = {}): Interpreter = + flags: TSandboxFlags = {}, + defines = @[("nimscript", "true")], + registerOps = true): Interpreter = var conf = newConfigRef() var cache = newIdentCache() var graph = newModuleGraph(cache, conf) connectCallbacks(graph) initDefines(conf.symbols) - defineSymbol(conf.symbols, "nimscript") - defineSymbol(conf.symbols, "nimconfig") + for define in defines: + defineSymbol(conf.symbols, define[0], define[1]) registerPass(graph, semPass) registerPass(graph, evalPass) @@ -119,6 +121,8 @@ proc createInterpreter*(scriptName: string; var vm = newCtx(m, cache, graph) vm.mode = emRepl vm.features = flags + if registerOps: + vm.registerAdditionalOps() # Required to register parts of stdlib modules graph.vm = vm graph.compileSystemModule() result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName) diff --git a/lib/system.nim b/lib/system.nim index 6b24bdcb8..098ad08be 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3026,5 +3026,5 @@ export widestrs import system/io export io -when not defined(createNimHcr): +when not defined(createNimHcr) and not defined(nimscript): include nimhcr From 9f78f116b2276a367f371ece550f669d64dbe594 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 15 May 2020 20:24:43 +0200 Subject: [PATCH 0540/4254] New "ping-pong" DFA (#14322) * New ping-pong analysis * Add testcase for #13456 * Remove debugging leftover * Unquote "unstructured controlflow" * Fix typo * Fix exponential complexity in edge cases * Add sanity testcase * Fix --- compiler/dfa.nim | 63 +++++++------------- compiler/injectdestructors.nim | 70 ++++++++++++---------- tests/arc/tmovebug.nim | 103 +++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 73 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0db89579b..67a9e26d8 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -35,11 +35,11 @@ from patterns import sameTrees type InstrKind* = enum - goto, fork, join, def, use + goto, fork, def, use Instr* = object n*: PNode # contains the def/use location. case kind*: InstrKind - of goto, fork, join: dest*: int + of goto, fork: dest*: int else: discard ControlFlowGraph* = seq[Instr] @@ -47,8 +47,6 @@ type TPosition = distinct int TBlock = object - joins: seq[Instr] - forks: seq[TPosition] case isTryBlock: bool of false: label: PSym @@ -72,7 +70,7 @@ proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) = var jumpTargets = initIntSet() let last = if last < 0: c.len-1 else: min(last, c.len-1) for i in start..last: - if c[i].kind in {goto, fork, join}: + if c[i].kind in {goto, fork}: jumpTargets.incl(i+c[i].dest) var i = start while i <= last: @@ -83,7 +81,7 @@ proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) = case c[i].kind of def, use: result.add renderTree(c[i].n) - of goto, fork, join: + of goto, fork: result.add "L" result.addInt c[i].dest+i result.add("\t#") @@ -102,7 +100,6 @@ proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} = proc forkI(c: var Con; n: PNode): TPosition = result = TPosition(c.code.len) c.code.add Instr(n: n, kind: fork, dest: 0) - c.blocks[^1].forks.add result proc gotoI(c: var Con; n: PNode): TPosition = result = TPosition(c.code.len) @@ -110,6 +107,24 @@ proc gotoI(c: var Con; n: PNode): TPosition = #[ +Join is no more +=============== +Instead of generating join instructions we adapt our traversal of the CFG. + +When encountering a fork we split into two paths, we follow the path +starting at "pc + 1" until it encounters the joinpoint: "pc + forkInstr.dest". +If we encounter gotos that would jump further than the current joinpoint, +as can happen with gotos generated by unstructured controlflow such as break, raise or return, +we simply suspend following the current path, and follow the other path until the new joinpoint +which is simply the instruction pointer returned to us by the now suspended path. +If the path we are following now, also encounters a goto that exceeds the joinpoint +we repeat the process; suspending the current path and evaluating the other one with a new joinpoint. +If we eventually reach a common joinpoint we join the two paths. +This new "ping-pong" approach has the obvious advantage of not requiring join instructions, as such +cutting down on the CFG size but is also mandatory for correctly handling complicated cases +of unstructured controlflow. + + Design of join ============== @@ -258,10 +273,6 @@ duplicate the 'join' instructions on breaks and return exits! ]# -proc joinI(c: var Con; fromFork: TPosition; n: PNode) = - let dist = fromFork.int - c.code.len - c.code.add Instr(n: n, kind: join, dest: dist) - proc genLabel(c: Con): TPosition = result = TPosition(c.code.len) @@ -289,10 +300,6 @@ proc popBlock(c: var Con; oldLen: int) = exits.add c.gotoI(newNode(nkEmpty)) for e in exits: c.patch e - for j in c.blocks[oldLen].joins: - var patchedJ = j - patchedJ.dest -= c.code.len - c.code.add patchedJ c.blocks.setLen(oldLen) template withBlock(labl: PSym; body: untyped) {.dirty.} = @@ -353,7 +360,6 @@ when true: c.gen(n[1]) else: withBlock(nil): - let oldForksLen = c.blocks[^1].forks.len var endings: array[3, TPosition] for i in 0..2: c.gen(n[0]) @@ -362,8 +368,6 @@ when true: for i in countdown(endings.high, 0): let endPos = endings[i] c.patch(endPos) - c.joinI(c.blocks[^1].forks.pop(), n) - doAssert(c.blocks[^1].forks.len == oldForksLen) else: @@ -374,7 +378,6 @@ else: # body # jmp lab1 # lab2: - let oldForksLen = c.blocks[^1].forks.len let lab1 = c.genLabel withBlock(nil): if isTrue(n[0]): @@ -386,15 +389,11 @@ else: c.gen(n[1]) c.jmpBack(n, lab1) c.patch(lab2) - setLen(c.blocks[^1].forks, oldForksLen) template forkT(n, body) = - let oldLen = c.blocks[^1].forks.len let lab1 = c.forkI(n) body c.patch(lab1) - c.joinI(lab1, n) - setLen(c.blocks[^1].forks, oldLen) proc genIf(c: var Con, n: PNode) = #[ @@ -433,7 +432,6 @@ proc genIf(c: var Con, n: PNode) = join F1 ]# - let oldLen = c.blocks[^1].forks.len var endings: seq[TPosition] = @[] for i in 0..= c.g.len or min(variantA, variantB) >= until: + break + if variantA < variantB: + variantA = isLastRead(location, c, variantA, min(variantB, until)) + else: + variantB = isLastRead(location, c, variantB, min(variantA, until)) pc = min(variantA, variantB) - of InstrKind.join: - let dest = pc + c.g[pc].dest - if dest == comesFrom: return pc + 1 - inc pc return pc proc isLastRead(n: PNode; c: var Con): bool = @@ -114,12 +116,12 @@ proc isLastRead(n: PNode; c: var Con): bool = # ensure that we don't find another 'use X' instruction. if instr+1 >= c.g.len: return true - result = isLastRead(n, c, instr+1, -1) >= 0 + result = isLastRead(n, c, instr+1, int.high) >= 0 dbg: echo "ugh ", c.otherRead.isNil, " ", result -proc isFirstWrite(location: PNode; c: var Con; pc, comesFrom: int; instr: int): int = +proc isFirstWrite(location: PNode; c: var Con; pc, until: int): int = var pc = pc - while pc < instr: + while pc < until: case c.g[pc].kind of def: if defInstrTargets(c.g[pc], location): @@ -134,15 +136,17 @@ proc isFirstWrite(location: PNode; c: var Con; pc, comesFrom: int; instr: int): pc = pc + c.g[pc].dest of fork: # every branch must not contain a def/use of our location: - let variantA = isFirstWrite(location, c, pc+1, pc, instr) - if variantA < 0: return -1 - var variantB = isFirstWrite(location, c, pc + c.g[pc].dest, pc, instr + c.g[pc].dest) - if variantB < 0: return -1 + var variantA = pc + 1 + var variantB = pc + c.g[pc].dest + while variantA != variantB: + if min(variantA, variantB) < 0: return -1 + if max(variantA, variantB) > until: + break + if variantA < variantB: + variantA = isFirstWrite(location, c, variantA, min(variantB, until)) + else: + variantB = isFirstWrite(location, c, variantB, min(variantA, until)) pc = min(variantA, variantB) - of InstrKind.join: - let dest = pc + c.g[pc].dest - if dest == comesFrom: return pc + 1 - inc pc return pc proc isFirstWrite(n: PNode; c: var Con): bool = @@ -161,10 +165,10 @@ proc isFirstWrite(n: PNode; c: var Con): bool = # ensure that we don't find another 'def/use X' instruction. if instr == 0: return true - result = isFirstWrite(n, c, 0, -1, instr) >= 0 + result = isFirstWrite(n, c, 0, instr) >= 0 proc initialized(code: ControlFlowGraph; pc: int, - init, uninit: var IntSet; comesFrom: int): int = + init, uninit: var IntSet; until: int): int = ## Computes the set of definitely initialized variables across all code paths ## as an IntSet of IDs. var pc = pc @@ -173,20 +177,22 @@ proc initialized(code: ControlFlowGraph; pc: int, of goto: pc = pc + code[pc].dest of fork: - let target = pc + code[pc].dest var initA = initIntSet() var initB = initIntSet() - let pcA = initialized(code, pc+1, initA, uninit, pc) - discard initialized(code, target, initB, uninit, pc) + var variantA = pc + 1 + var variantB = pc + code[pc].dest + while variantA != variantB: + if max(variantA, variantB) > until: + break + if variantA < variantB: + variantA = initialized(code, variantA, initA, uninit, min(variantB, until)) + else: + variantB = initialized(code, variantB, initB, uninit, min(variantA, until)) + pc = min(variantA, variantB) # we add vars if they are in both branches: for v in initA: if v in initB: init.incl v - pc = pcA+1 - of InstrKind.join: - let target = pc + code[pc].dest - if comesFrom == target: return pc - inc pc of use: let v = code[pc].n.sym if v.kind != skParam and v.id notin init: @@ -1040,7 +1046,7 @@ proc computeUninit(c: var Con) = c.uninitComputed = true c.uninit = initIntSet() var init = initIntSet() - discard initialized(c.g, pc = 0, init, c.uninit, comesFrom = -1) + discard initialized(c.g, pc = 0, init, c.uninit, int.high) proc injectDefaultCalls(n: PNode, c: var Con) = case n.kind diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 6ed10c403..39f1c8bf4 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -19,6 +19,23 @@ c.text = hello c.text = hello pOD.text = hello pOD.toks = @["hello"] +fff +fff +2 +fff +fff +2 +fff +fff +2 +mmm +fff +fff +fff +3 +mmm +sink me (sink) +assign me (not sink) ''' """ @@ -199,3 +216,89 @@ when false: let pOHD = parseOHD() dump pOHD.text dump pOHD.toks + +# bug #13456 + +iterator combinations[T](s: openarray[T], k: int): seq[T] = + let n = len(s) + assert k >= 0 and k <= n + var pos = newSeq[int](k) + var current = newSeq[T](k) + for i in 0..k-1: + pos[k-i-1] = i + var done = false + while not done: + for i in 0..k-1: + current[i] = s[pos[k-i-1]] + yield current + var i = 0 + while i < k: + pos[i] += 1 + if pos[i] < n-i: + for j in 0..i-1: + pos[j] = pos[i] + i - j + break + i += 1 + if i >= k: + break + +type + UndefEx = object of Exception + +proc main2 = + var delayedSyms = @[1, 2, 3] + var unp: seq[int] + block myb: + for a in 1 .. 2: + if delayedSyms.len > a: + unp = delayedSyms + for t in unp.combinations(a + 1): + try: + var h = false + for k in t: + echo "fff" + if h: continue + if true: + raise newException(UndefEx, "forward declaration") + break myb + except UndefEx: + echo t.len + echo "mmm" + +main2() + + + +type ME = object + who: string + +proc `=`(x: var ME, y: ME) = + if x.who.len > 0: echo "assign ",x.who + +proc `=sink`(x: var ME, y: ME) = + if x.who.len > 0: echo "sink ",x.who + +var dump: ME +template use(x) = dump = x +template def(x) = x = dump + +var c = true + +proc shouldSink() = + var x = ME(who: "me (sink)") + use(x) # we analyse this + if c: def(x) + else: def(x) + use(x) # ok, with the [else] part. + +shouldSink() + +dump = ME() + +proc shouldNotSink() = + var x = ME(who: "me (not sink)") + use(x) # we analyse this + if c: def(x) + use(x) # Not ok without the '[else]' + +shouldNotSink() From ce0552c1008c8292c550e7a973c580f416c005ca Mon Sep 17 00:00:00 2001 From: Bung <535670947@qq.com> Date: Sat, 16 May 2020 03:00:06 +0800 Subject: [PATCH 0541/4254] fix #9771 (#14357) * fix #9771 * map SQLLEN SQLULEN * fix proc params take TSqlLen Co-authored-by: bung87 --- lib/impure/db_odbc.nim | 10 +++++----- lib/wrappers/odbcsql.nim | 26 ++++++++++++++------------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 7370adbf3..9ff050bfa 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -242,7 +242,7 @@ proc tryExec*(db: var DbConn, query: SqlQuery, args: varargs[string, `$`]): bool try: db.prepareFetchDirect(query, args) var - rCnt = -1 + rCnt:TSqlLen = -1 res = SQLRowCount(db.stmt, rCnt) properFreeResult(SQL_HANDLE_STMT, db.stmt) if res != SQL_SUCCESS: dbError(db) @@ -461,10 +461,10 @@ proc execAffectedRows*(db: var DbConn, query: SqlQuery, var q = dbFormat(query, args) db.sqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)) rawExec(db, query, args) - var rCnt = -1 + var rCnt:TSqlLen = -1 db.sqlCheck(SQLRowCount(db.hDb, rCnt)) properFreeResult(SQL_HANDLE_STMT, db.stmt) - result = rCnt + result = rCnt.int64 proc close*(db: var DbConn) {. tags: [WriteDbEffect], raises: [].} = @@ -489,7 +489,7 @@ proc open*(connection, user, password, database: string): DbConn {. ## Currently the database parameter is ignored, ## but included to match ``open()`` in the other db_xxxxx library modules. var - val: TSqlInteger = SQL_OV_ODBC3 + val = SQL_OV_ODBC3 resLen = 0 result = (hDb: nil, env: nil, stmt: nil) # allocate environment handle @@ -497,7 +497,7 @@ proc open*(connection, user, password, database: string): DbConn {. if res != SQL_SUCCESS: dbError("Error: unable to initialise ODBC environment.") res = SQLSetEnvAttr(result.env, SQL_ATTR_ODBC_VERSION.TSqlInteger, - val, resLen.TSqlInteger) + cast[SqlPointer](val.addr), resLen.TSqlInteger) if res != SQL_SUCCESS: dbError("Error: unable to set ODBC driver version.") # allocate hDb handle res = SQLAllocHandle(SQL_HANDLE_DBC, result.env, result.hDb) diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim index be56b75d3..393f29ad0 100644 --- a/lib/wrappers/odbcsql.nim +++ b/lib/wrappers/odbcsql.nim @@ -45,8 +45,10 @@ type SqlHDBC* = SqlHandle SqlHStmt* = SqlHandle SqlHDesc* = SqlHandle - TSqlInteger* = int - SqlUInteger* = int + TSqlInteger* = int32 + SqlUInteger* = int32 + TSqlLen* = int64 + TSqlULen* = uint64 SqlPointer* = pointer TSqlReal* = cfloat TSqlDouble* = cdouble @@ -666,7 +668,7 @@ proc SQLAllocHandle*(HandleType: TSqlSmallInt, InputHandle: SqlHandle, OutputHandlePtr: var SqlHandle): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLSetEnvAttr*(EnvironmentHandle: SqlHEnv, Attribute: TSqlInteger, - Value: TSqlInteger, StringLength: TSqlInteger): TSqlSmallInt{. + Value: SqlPointer, StringLength: TSqlInteger): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLGetEnvAttr*(EnvironmentHandle: SqlHEnv, Attribute: TSqlInteger, Value: SqlPointer, BufferLength: TSqlInteger, @@ -716,14 +718,14 @@ proc SQLNumResultCols*(StatementHandle: SqlHStmt, ColumnCount: var TSqlSmallInt) proc SQLDescribeCol*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, ColumnName: PSQLCHAR, BufferLength: TSqlSmallInt, NameLength: var TSqlSmallInt, DataType: var TSqlSmallInt, - ColumnSize: var SqlUInteger, + ColumnSize: var TSQLULEN, DecimalDigits: var TSqlSmallInt, Nullable: var TSqlSmallInt): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLFetchScroll*(StatementHandle: SqlHStmt, FetchOrientation: TSqlSmallInt, FetchOffset: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} proc SQLExtendedFetch*(hstmt: SqlHStmt, fFetchType: SqlUSmallInt, - irow: TSqlInteger, pcrow: PSQLUINTEGER, + irow: TSqlInteger, pcrow: var TSQLULEN, rgfRowStatus: PSQLUSMALLINT): TSqlSmallInt{.dynlib: odbclib, importc.} proc SQLGetData*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, @@ -741,13 +743,13 @@ proc SQLGetInfo*(ConnectionHandle: SqlHDBC, InfoType: SqlUSmallInt, InfoValue: SqlPointer, BufferLength: TSqlSmallInt, StringLength: PSQLSMALLINT): TSqlSmallInt{.dynlib: odbclib, importc.} -proc SQLBulkOperations*(StatementHandle: SqlHStmt, Operation: TSqlSmallInt): TSqlSmallInt{. +proc SQLBulkOperations*(StatementHandle: SqlHStmt, Operation: SqlUSmallInt): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLPutData*(StatementHandle: SqlHStmt, Data: SqlPointer, - StrLen_or_Ind: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.} + StrLen_or_Ind: TSQLLEN): TSqlSmallInt{.dynlib: odbclib, importc.} proc SQLBindCol*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, TargetType: TSqlSmallInt, TargetValue: SqlPointer, - BufferLength: TSqlInteger, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{. + BufferLength: TSqlLEN, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLSetPos*(hstmt: SqlHStmt, irow: SqlUSmallInt, fOption: SqlUSmallInt, fLock: SqlUSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} @@ -770,13 +772,13 @@ proc SQLGetCursorName*(StatementHandle: SqlHStmt, CursorName: PSQLCHAR, proc SQLSetCursorName*(StatementHandle: SqlHStmt, CursorName: PSQLCHAR, NameLength: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.} -proc SQLRowCount*(StatementHandle: SqlHStmt, RowCount: var TSqlInteger): TSqlSmallInt{. +proc SQLRowCount*(StatementHandle: SqlHStmt, RowCount: var TSQLLEN): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLBindParameter*(hstmt: SqlHStmt, ipar: SqlUSmallInt, fParamType: TSqlSmallInt, fCType: TSqlSmallInt, - fSqlType: TSqlSmallInt, cbColDef: SqlUInteger, + fSqlType: TSqlSmallInt, cbColDef: TSQLULEN, ibScale: TSqlSmallInt, rgbValue: SqlPointer, - cbValueMax: TSqlInteger, pcbValue: PSQLINTEGER): TSqlSmallInt{. + cbValueMax: TSQLLEN, pcbValue: var TSQLLEN): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLFreeStmt*(StatementHandle: SqlHStmt, Option: SqlUSmallInt): TSqlSmallInt{. dynlib: odbclib, importc.} @@ -784,7 +786,7 @@ proc SQLColAttribute*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, FieldIdentifier: SqlUSmallInt, CharacterAttribute: PSQLCHAR, BufferLength: TSqlSmallInt, StringLength: PSQLSMALLINT, - NumericAttribute: SqlPointer): TSqlSmallInt{. + NumericAttribute: TSQLLEN): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLEndTran*(HandleType: TSqlSmallInt, Handle: SqlHandle, CompletionType: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, From bf0e1c696f6be96026d72838010ef8e63bd13238 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Fri, 15 May 2020 17:37:24 -0400 Subject: [PATCH 0542/4254] Remove the uses of {.procvar.} pragma (#14359) This pragma did nothing. Ref: - https://github.com/nim-lang/Nim/issues/2172#issuecomment-383276469 - https://github.com/nim-lang/Nim/issues/12975 --- lib/packages/docutils/rst.nim | 4 +- lib/pure/asyncftpclient.nim | 4 +- lib/pure/rationals.nim | 2 +- lib/pure/strmisc.nim | 7 ++- lib/pure/strutils.nim | 48 +++++++++---------- lib/pure/unicode.nim | 36 +++++++------- lib/system.nim | 4 +- nimsuggest/sexp.nim | 14 +++--- tests/generics/t6137.nim | 2 +- .../argument_parser/argument_parser.nim | 4 +- .../keineschweine/lib/client_helpers.nim | 6 +-- tools/nimgrab.nim | 2 +- tools/urldownloader.nim | 2 +- 13 files changed, 67 insertions(+), 68 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 50b855662..07cb3eccc 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -305,14 +305,14 @@ proc whichMsgClass*(k: MsgKind): MsgClass = else: assert false, "msgkind does not fit naming scheme" proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind, - arg: string) {.procvar.} = + arg: string) = let mc = msgkind.whichMsgClass let a = messages[msgkind] % arg let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a] if mc == mcError: raise newException(EParseError, message) else: writeLine(stdout, message) -proc defaultFindFile*(filename: string): string {.procvar.} = +proc defaultFindFile*(filename: string): string = if existsFile(filename): result = filename else: result = "" diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 7bbfc2a35..132682b23 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -322,7 +322,7 @@ proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt, assertReply(await(ftp.expectReply()), "226") proc defaultOnProgressChanged*(total, progress: BiggestInt, - speed: float): Future[void] {.nimcall, gcsafe, procvar.} = + speed: float): Future[void] {.nimcall, gcsafe.} = ## Default FTP ``onProgressChanged`` handler. Does nothing. result = newFuture[void]() #echo(total, " ", progress, " ", speed) @@ -358,7 +358,7 @@ proc doUpload(ftp: AsyncFtpClient, file: File, var countdownFut = sleepAsync(1000) var sendFut: Future[void] = nil while ftp.dsockConnected: - if sendFut == nil or sendFut.finished: + if sendFut == nil or sendFut.finished: # TODO: Async file reading. let len = file.readBuffer(addr(data[0]), 4000) setLen(data, len) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index d4b1485f5..c7af91edd 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -225,7 +225,7 @@ proc `/=`*[T](x: var Rational[T], y: T) = x.den *= y reduce(x) -proc cmp*(x, y: Rational): int {.procvar.} = +proc cmp*(x, y: Rational): int = ## Compares two rationals. (x - y).num diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 02bbdbcf4..061c2063b 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -12,8 +12,7 @@ import strutils -proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, - procvar.} = +proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = ## Expand tab characters in `s` replacing them by spaces. ## ## The amount of inserted spaces for each tab character is the difference @@ -53,7 +52,7 @@ proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, proc partition*(s: string, sep: string, right: bool = false): (string, string, string) - {.noSideEffect, procvar.} = + {.noSideEffect.} = ## Split the string at the first or last occurrence of `sep` into a 3-tuple ## ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or @@ -72,7 +71,7 @@ proc partition*(s: string, sep: string, return if right: ("", "", s) else: (s, "", "") proc rpartition*(s: string, sep: string): (string, string, string) - {.noSideEffect, procvar.} = + {.noSideEffect.} = ## Split the string at the last occurrence of `sep` into a 3-tuple ## ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index bb68085aa..7c00de2d2 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -119,7 +119,7 @@ const ## doAssert "01234".find(invalid) == -1 ## doAssert "01A34".find(invalid) == 2 -proc isAlphaAscii*(c: char): bool {.noSideEffect, procvar, +proc isAlphaAscii*(c: char): bool {.noSideEffect, rtl, extern: "nsuIsAlphaAsciiChar".} = ## Checks whether or not character `c` is alphabetical. ## @@ -131,7 +131,7 @@ proc isAlphaAscii*(c: char): bool {.noSideEffect, procvar, doAssert isAlphaAscii('8') == false return c in Letters -proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar, +proc isAlphaNumeric*(c: char): bool {.noSideEffect, rtl, extern: "nsuIsAlphaNumericChar".} = ## Checks whether or not `c` is alphanumeric. ## @@ -142,7 +142,7 @@ proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar, doAssert isAlphaNumeric(' ') == false return c in Letters+Digits -proc isDigit*(c: char): bool {.noSideEffect, procvar, +proc isDigit*(c: char): bool {.noSideEffect, rtl, extern: "nsuIsDigitChar".} = ## Checks whether or not `c` is a number. ## @@ -152,7 +152,7 @@ proc isDigit*(c: char): bool {.noSideEffect, procvar, doAssert isDigit('8') == true return c in Digits -proc isSpaceAscii*(c: char): bool {.noSideEffect, procvar, +proc isSpaceAscii*(c: char): bool {.noSideEffect, rtl, extern: "nsuIsSpaceAsciiChar".} = ## Checks whether or not `c` is a whitespace character. runnableExamples: @@ -161,7 +161,7 @@ proc isSpaceAscii*(c: char): bool {.noSideEffect, procvar, doAssert isSpaceAscii('\t') == true return c in Whitespace -proc isLowerAscii*(c: char): bool {.noSideEffect, procvar, +proc isLowerAscii*(c: char): bool {.noSideEffect, rtl, extern: "nsuIsLowerAsciiChar".} = ## Checks whether or not `c` is a lower case character. ## @@ -176,7 +176,7 @@ proc isLowerAscii*(c: char): bool {.noSideEffect, procvar, doAssert isLowerAscii('7') == false return c in {'a'..'z'} -proc isUpperAscii*(c: char): bool {.noSideEffect, procvar, +proc isUpperAscii*(c: char): bool {.noSideEffect, rtl, extern: "nsuIsUpperAsciiChar".} = ## Checks whether or not `c` is an upper case character. ## @@ -192,7 +192,7 @@ proc isUpperAscii*(c: char): bool {.noSideEffect, procvar, return c in {'A'..'Z'} -proc toLowerAscii*(c: char): char {.noSideEffect, procvar, +proc toLowerAscii*(c: char): char {.noSideEffect, rtl, extern: "nsuToLowerAsciiChar".} = ## Returns the lower case version of character ``c``. ## @@ -216,7 +216,7 @@ template toImpl(call) = for i in 0..len(s) - 1: result[i] = call(s[i]) -proc toLowerAscii*(s: string): string {.noSideEffect, procvar, +proc toLowerAscii*(s: string): string {.noSideEffect, rtl, extern: "nsuToLowerAsciiStr".} = ## Converts string `s` into lower case. ## @@ -230,7 +230,7 @@ proc toLowerAscii*(s: string): string {.noSideEffect, procvar, doAssert toLowerAscii("FooBar!") == "foobar!" toImpl toLowerAscii -proc toUpperAscii*(c: char): char {.noSideEffect, procvar, +proc toUpperAscii*(c: char): char {.noSideEffect, rtl, extern: "nsuToUpperAsciiChar".} = ## Converts character `c` into upper case. ## @@ -250,7 +250,7 @@ proc toUpperAscii*(c: char): char {.noSideEffect, procvar, else: result = c -proc toUpperAscii*(s: string): string {.noSideEffect, procvar, +proc toUpperAscii*(s: string): string {.noSideEffect, rtl, extern: "nsuToUpperAsciiStr".} = ## Converts string `s` into upper case. ## @@ -264,7 +264,7 @@ proc toUpperAscii*(s: string): string {.noSideEffect, procvar, doAssert toUpperAscii("FooBar!") == "FOOBAR!" toImpl toUpperAscii -proc capitalizeAscii*(s: string): string {.noSideEffect, procvar, +proc capitalizeAscii*(s: string): string {.noSideEffect, rtl, extern: "nsuCapitalizeAscii".} = ## Converts the first character of string `s` into upper case. ## @@ -299,7 +299,7 @@ proc nimIdentNormalize*(s: string): string = inc j if j != s.len: setLen(result, j) -proc normalize*(s: string): string {.noSideEffect, procvar, +proc normalize*(s: string): string {.noSideEffect, rtl, extern: "nsuNormalize".} = ## Normalizes the string `s`. ## @@ -323,7 +323,7 @@ proc normalize*(s: string): string {.noSideEffect, procvar, if j != s.len: setLen(result, j) proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreCase", procvar.} = + rtl, extern: "nsuCmpIgnoreCase".} = ## Compares two strings in a case insensitive manner. Returns: ## ## | 0 if a == b @@ -345,7 +345,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, # thus we compile without checks here proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreStyle", procvar.} = + rtl, extern: "nsuCmpIgnoreStyle".} = ## Semantically the same as ``cmp(normalize(a), normalize(b))``. It ## is just optimized to not allocate temporary strings. This should ## NOT be used to compare Nim identifier names. @@ -1096,7 +1096,7 @@ proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect, if x < 0: result = '-' & result -proc parseInt*(s: string): int {.noSideEffect, procvar, +proc parseInt*(s: string): int {.noSideEffect, rtl, extern: "nsuParseInt".} = ## Parses a decimal integer value contained in `s`. ## @@ -1107,7 +1107,7 @@ proc parseInt*(s: string): int {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) -proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar, +proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, rtl, extern: "nsuParseBiggestInt".} = ## Parses a decimal integer value contained in `s`. ## @@ -1116,7 +1116,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) -proc parseUInt*(s: string): uint {.noSideEffect, procvar, +proc parseUInt*(s: string): uint {.noSideEffect, rtl, extern: "nsuParseUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## @@ -1125,7 +1125,7 @@ proc parseUInt*(s: string): uint {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar, +proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, rtl, extern: "nsuParseBiggestUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## @@ -1134,7 +1134,7 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -proc parseFloat*(s: string): float {.noSideEffect, procvar, +proc parseFloat*(s: string): float {.noSideEffect, rtl, extern: "nsuParseFloat".} = ## Parses a decimal floating point value contained in `s`. ## @@ -1147,7 +1147,7 @@ proc parseFloat*(s: string): float {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid float: " & s) -proc parseBinInt*(s: string): int {.noSideEffect, procvar, +proc parseBinInt*(s: string): int {.noSideEffect, rtl, extern: "nsuParseBinInt".} = ## Parses a binary integer value contained in `s`. ## @@ -1176,7 +1176,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid oct integer: " & s) -proc parseHexInt*(s: string): int {.noSideEffect, procvar, +proc parseHexInt*(s: string): int {.noSideEffect, rtl, extern: "nsuParseHexInt".} = ## Parses a hexadecimal integer value contained in `s`. ## @@ -1202,7 +1202,7 @@ proc generateHexCharToValueMap(): string = const hexCharToValueMap = generateHexCharToValueMap() -proc parseHexStr*(s: string): string {.noSideEffect, procvar, +proc parseHexStr*(s: string): string {.noSideEffect, rtl, extern: "nsuParseHexStr".} = ## Convert hex-encoded string to byte string, e.g.: ## @@ -2918,12 +2918,12 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ break i = j -proc isEmptyOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, +proc isEmptyOrWhitespace*(s: string): bool {.noSideEffect, rtl, extern: "nsuIsEmptyOrWhitespace".} = ## Checks if `s` is empty or consists entirely of whitespace characters. result = s.allCharsInSet(Whitespace) -proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, +proc isNilOrWhitespace*(s: string): bool {.noSideEffect, rtl, extern: "nsuIsNilOrWhitespace", deprecated: "use isEmptyOrWhitespace instead".} = ## Alias for isEmptyOrWhitespace diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 2d54aaf31..497d5e465 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -470,7 +470,7 @@ proc binarySearch(c: RuneImpl, tab: openArray[int], len, stride: int): int = return t return -1 -proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = +proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1".} = ## Converts ``c`` into lower case. This works for any rune. ## ## If possible, prefer ``toLower`` over ``toUpper``. @@ -488,7 +488,7 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = return Rune(c + toLowerSinglets[p+1] - 500) return Rune(c) -proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = +proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1".} = ## Converts ``c`` into upper case. This works for any rune. ## ## If possible, prefer ``toLower`` over ``toUpper``. @@ -506,7 +506,7 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = return Rune(c + toUpperSinglets[p+1] - 500) return Rune(c) -proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = +proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1".} = ## Converts ``c`` to title case. ## ## See also: @@ -519,7 +519,7 @@ proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = return Rune(c + toTitleSinglets[p+1] - 500) return Rune(c) -proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## Returns true if ``c`` is a lower case rune. ## ## If possible, prefer ``isLower`` over ``isUpper``. @@ -537,7 +537,7 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c == toUpperSinglets[p]: return true -proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## Returns true if ``c`` is a upper case rune. ## ## If possible, prefer ``isLower`` over ``isUpper``. @@ -557,7 +557,7 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c == toLowerSinglets[p]: return true -proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## Returns true if ``c`` is an *alpha* rune (i.e., a letter). ## ## See also: @@ -576,7 +576,7 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c == alphaSinglets[p]: return true -proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## Returns true if ``c`` is a Unicode titlecase code point. ## ## See also: @@ -587,7 +587,7 @@ proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## * `isWhiteSpace proc <#isWhiteSpace,Rune>`_ return isUpper(c) and isLower(c) -proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## Returns true if ``c`` is a Unicode whitespace code point. ## ## See also: @@ -600,7 +600,7 @@ proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]: return true -proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1".} = ## Returns true if ``c`` is a Unicode combining code unit. ## ## See also: @@ -627,7 +627,7 @@ template runeCheck(s, runeProc) = fastRuneAt(s, i, rune, doInc = true) result = runeProc(rune) and result -proc isAlpha*(s: string): bool {.noSideEffect, procvar, +proc isAlpha*(s: string): bool {.noSideEffect, rtl, extern: "nuc$1Str".} = ## Returns true if ``s`` contains all alphabetic runes. runnableExamples: @@ -635,7 +635,7 @@ proc isAlpha*(s: string): bool {.noSideEffect, procvar, doAssert a.isAlpha runeCheck(s, isAlpha) -proc isSpace*(s: string): bool {.noSideEffect, procvar, +proc isSpace*(s: string): bool {.noSideEffect, rtl, extern: "nuc$1Str".} = ## Returns true if ``s`` contains all whitespace runes. runnableExamples: @@ -656,21 +656,21 @@ template convertRune(s, runeProc) = rune = runeProc(rune) fastToUTF8Copy(rune, result, resultIndex, doInc = true) -proc toUpper*(s: string): string {.noSideEffect, procvar, +proc toUpper*(s: string): string {.noSideEffect, rtl, extern: "nuc$1Str".} = ## Converts ``s`` into upper-case runes. runnableExamples: doAssert toUpper("abγ") == "ABΓ" convertRune(s, toUpper) -proc toLower*(s: string): string {.noSideEffect, procvar, +proc toLower*(s: string): string {.noSideEffect, rtl, extern: "nuc$1Str".} = ## Converts ``s`` into lower-case runes. runnableExamples: doAssert toLower("ABΓ") == "abγ" convertRune(s, toLower) -proc swapCase*(s: string): string {.noSideEffect, procvar, +proc swapCase*(s: string): string {.noSideEffect, rtl, extern: "nuc$1".} = ## Swaps the case of runes in ``s``. ## @@ -692,7 +692,7 @@ proc swapCase*(s: string): string {.noSideEffect, procvar, rune = rune.toUpper() fastToUTF8Copy(rune, result, resultIndex, doInc = true) -proc capitalize*(s: string): string {.noSideEffect, procvar, +proc capitalize*(s: string): string {.noSideEffect, rtl, extern: "nuc$1".} = ## Converts the first character of ``s`` into an upper-case rune. runnableExamples: @@ -759,7 +759,7 @@ proc translate*(s: string, replacements: proc(key: string): string): string {. let word = s[wordStart .. ^1] result.add(replacements(word)) -proc title*(s: string): string {.noSideEffect, procvar, +proc title*(s: string): string {.noSideEffect, rtl, extern: "nuc$1".} = ## Converts ``s`` to a unicode title. ## @@ -821,7 +821,7 @@ proc toRunes*(s: string): seq[Rune] = for r in s.runes: result.add(r) -proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = +proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1".} = ## Compares two UTF-8 strings and ignores the case. Returns: ## ## | 0 if a == b @@ -1226,7 +1226,7 @@ proc isUpper*(s: string, skipNonAlpha: bool): bool {. ## an empty string. runeCaseCheck(s, isUpper, skipNonAlpha) -proc isTitle*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nuc$1Str", +proc isTitle*(s: string): bool {.noSideEffect, rtl, extern: "nuc$1Str", deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = ## **Deprecated since version 0.20 since its semantics are unclear** ## diff --git a/lib/system.nim b/lib/system.nim index 098ad08be..e5b359c70 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -876,7 +876,7 @@ proc `of`*[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.} ## assert(FloatingPointDefect of Exception) ## assert(DivByZeroDefect of Exception) -proc cmp*[T](x, y: T): int {.procvar.} = +proc cmp*[T](x, y: T): int = ## Generic compare proc. ## ## Returns: @@ -894,7 +894,7 @@ proc cmp*[T](x, y: T): int {.procvar.} = if x < y: return -1 return 1 -proc cmp*(x, y: string): int {.noSideEffect, procvar.} +proc cmp*(x, y: string): int {.noSideEffect.} ## Compare proc for strings. More efficient than the generic version. ## ## **Note**: The precise result values depend on the used C runtime library and diff --git a/nimsuggest/sexp.nim b/nimsuggest/sexp.nim index 654640309..a4368a558 100644 --- a/nimsuggest/sexp.nim +++ b/nimsuggest/sexp.nim @@ -290,7 +290,7 @@ proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} = ## raises an `ESexpParsingError` exception. raise newException(SexpParsingError, errorMsgExpected(p, msg)) -proc newSString*(s: string): SexpNode {.procvar.}= +proc newSString*(s: string): SexpNode = ## Creates a new `SString SexpNode`. result = SexpNode(kind: SString, str: s) @@ -298,27 +298,27 @@ proc newSStringMove(s: string): SexpNode = result = SexpNode(kind: SString) shallowCopy(result.str, s) -proc newSInt*(n: BiggestInt): SexpNode {.procvar.} = +proc newSInt*(n: BiggestInt): SexpNode = ## Creates a new `SInt SexpNode`. result = SexpNode(kind: SInt, num: n) -proc newSFloat*(n: float): SexpNode {.procvar.} = +proc newSFloat*(n: float): SexpNode = ## Creates a new `SFloat SexpNode`. result = SexpNode(kind: SFloat, fnum: n) -proc newSNil*(): SexpNode {.procvar.} = +proc newSNil*(): SexpNode = ## Creates a new `SNil SexpNode`. result = SexpNode(kind: SNil) -proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} = +proc newSCons*(car, cdr: SexpNode): SexpNode = ## Creates a new `SCons SexpNode` result = SexpNode(kind: SCons, car: car, cdr: cdr) -proc newSList*(): SexpNode {.procvar.} = +proc newSList*(): SexpNode = ## Creates a new `SList SexpNode` result = SexpNode(kind: SList, elems: @[]) -proc newSSymbol*(s: string): SexpNode {.procvar.} = +proc newSSymbol*(s: string): SexpNode = result = SexpNode(kind: SSymbol, symbol: s) proc newSSymbolMove(s: string): SexpNode = diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim index abf02a756..991f39dd1 100644 --- a/tests/generics/t6137.nim +++ b/tests/generics/t6137.nim @@ -16,7 +16,7 @@ let # define a vector of length 3 x: vector[3] = [1.0, 3.0, 5.0] -proc vectFunc[T](x: vector[T]): vector[T] {.procvar.} = +proc vectFunc[T](x: vector[T]): vector[T] = # Define a vector function result = 2.0*x diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 9448fa7e5..459e38674 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -102,7 +102,7 @@ type # - Tparam_kind procs -proc `$`*(value: Tparam_kind): string {.procvar.} = +proc `$`*(value: Tparam_kind): string = ## Stringifies the type, used to generate help texts. case value: of PK_EMPTY: result = "" @@ -137,7 +137,7 @@ proc new_parameter_specification*(consumes = PK_EMPTY, # - Tparsed_parameter procs -proc `$`*(data: Tparsed_parameter): string {.procvar.} = +proc `$`*(data: Tparsed_parameter): string = ## Stringifies the value, mostly for debug purposes. ## ## The proc will display the value followed by non string type in brackets. diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim index 0ebb4ade1..5f74aef85 100644 --- a/tests/manyloc/keineschweine/lib/client_helpers.nim +++ b/tests/manyloc/keineschweine/lib/client_helpers.nim @@ -69,7 +69,7 @@ proc updateFileProgress*() = downloadProgress.setString($currentFileTransfer.pos & '/' & $currentFileTransfer.fullLen) ## HFileTransfer -proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) {.procvar.} = +proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) = var f = readScFileTransfer(buffer) updateFileProgress() @@ -110,7 +110,7 @@ proc saveCurrentFile() = echo "Write file" ## HChallengeResult -proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) {.procvar.} = +proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) = var res = readScChallengeResult(buffer).status echo "got challnege result: ", res if res and currentFileTransfer.readyToSave: @@ -122,7 +122,7 @@ proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) {.procvar.} = echo "REsetting current file" ## HFileCHallenge -proc handleFileChallenge*(serv: PServer; buffer: PBuffer) {.procvar.} = +proc handleFileChallenge*(serv: PServer; buffer: PBuffer) = var challenge = readScFileChallenge(buffer) path = expandPath(challenge) diff --git a/tools/nimgrab.nim b/tools/nimgrab.nim index 937a5dcd4..ee5eced1e 100644 --- a/tools/nimgrab.nim +++ b/tools/nimgrab.nim @@ -5,7 +5,7 @@ when defined(windows): proc syncDownload(url, file: string) = proc progress(status: DownloadStatus, progress: uint, total: uint, - message: string) {.procvar, gcsafe.} = + message: string) {.gcsafe.} = echo "Downloading " & url let t = total.BiggestInt if t != 0: diff --git a/tools/urldownloader.nim b/tools/urldownloader.nim index b29a6c138..73e4034c9 100644 --- a/tools/urldownloader.nim +++ b/tools/urldownloader.nim @@ -418,7 +418,7 @@ proc downloadToFile*(szUrl: string, szFileName: string, when isMainModule: proc progress(status: DownloadStatus, progress: uint, progressMax: uint, - message: string) {.procvar,gcsafe.} = + message: string) {.gcsafe.} = const downset: set[DownloadStatus] = {statusBeginDownloading, statusDownloading, statusEndDownloading} if status in downset: From c32e1378eb7d62d59c9e24322c282556c821030a Mon Sep 17 00:00:00 2001 From: Bung <535670947@qq.com> Date: Sat, 16 May 2020 18:04:39 +0800 Subject: [PATCH 0543/4254] docfix: fix wrong link in doc/manual.rst (#14367) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 8d4439644..4e477f6ff 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6801,7 +6801,7 @@ Produces: ImportJs pragma --------------- -Similar to the `importcpp pragma for C++ <#foreign-function-interface-importc-pragma>`_, +Similar to the `importcpp pragma for C++ <#implementation-specific-pragmas-importcpp-pragma>`_, the ``importjs`` pragma can be used to import Javascript methods or symbols in general. The generated code then uses the Javascript method calling syntax: ``obj.method(arg)``. From c777f2fb608e1f42daf31d314dda0050f6354acd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 16 May 2020 04:09:18 -0700 Subject: [PATCH 0544/4254] fix some issues with --backend (#14363) * fix some issues with --backend * fix https://github.com/timotheecour/Nim/issues/175; improve upon #14306 --- changelog.md | 10 ++++- compiler/cmdlinehelper.nim | 8 ---- compiler/commands.nim | 4 -- compiler/docgen.nim | 21 ++++++--- compiler/extccomp.nim | 15 ++++--- compiler/main.nim | 77 ++++++++++++++++++++------------ compiler/options.nim | 4 +- lib/packages/docutils/rstgen.nim | 2 +- tests/misc/mbackend.nim | 31 +++++++++++++ tests/nimdoc/m13129.nim | 2 + tests/trunner.nim | 10 +++++ 11 files changed, 125 insertions(+), 59 deletions(-) create mode 100644 tests/misc/mbackend.nim diff --git a/changelog.md b/changelog.md index a93a7e651..986186356 100644 --- a/changelog.md +++ b/changelog.md @@ -160,8 +160,8 @@ proc mydiv(a, b): int {.raises: [].} = - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. - The `define` and `undef` pragmas have been de-deprecated. -- New command: `nim r main.nim [args...]` which compiles and runs main.nim, saving - the binary to $nimcache/main$exeExt, using the same logic as `nim c -r` to +- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache` + so that output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to avoid recompiling when sources don't change. This is now the preferred way to run tests, avoiding the usual pain of clobbering your repo with binaries or using tricky gitignore rules on posix. Example: @@ -178,6 +178,12 @@ proc mydiv(a, b): int {.raises: [].} = - new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) was generated; this helps in particular when it's non obvious where it came from either because multiple locations generate the same message, or because the message involves runtime formatting. +- new flag `--backend:js|c|cpp|objc (or -b:js etc), to change backend; can be used with any command + (eg nim r, doc, check etc); safe to re-assign. +- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, eg: `--doccmd:-d:foo --threads` + use `--doccmd:skip` to skip runnableExamples and rst test snippets. +- new flag `--usenimcache` to output to nimcache (whatever it resolves to after all commands are processed) + and avoids polluting both $pwd and $projectdir. It can be used with any command. ## Tool changes diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index dd74f54dc..4777af8df 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -75,14 +75,6 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi # now process command line arguments again, because some options in the # command line can overwrite the config file's settings extccomp.initVars(conf) - # XXX This is hacky. We need to find a better way. - case conf.command - of "cpp", "compiletocpp": - conf.backend = backendCpp - conf.cmd = cmdCompileToBackend - else: - discard - self.processCmdLine(passCmd2, "", conf) if conf.command == "": rawMessage(conf, errGenerated, "command missing") diff --git a/compiler/commands.nim b/compiler/commands.nim index 2ab79f14a..340180378 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -502,8 +502,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "gcmarkandsweep") of "destructors", "arc": conf.selectedGC = gcArc - if conf.backend != backendCpp: - conf.exc = excGoto defineSymbol(conf.symbols, "gcdestructors") defineSymbol(conf.symbols, "gcarc") incl conf.globalOptions, optSeqDestructors @@ -513,8 +511,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "nimV2") of "orc": conf.selectedGC = gcOrc - if conf.backend != backendCpp: - conf.exc = excGoto defineSymbol(conf.symbols, "gcdestructors") defineSymbol(conf.symbols, "gcorc") incl conf.globalOptions, optSeqDestructors diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d774fd508..b594921ae 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -216,13 +216,20 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, # Include the current file if we're parsing a nim file let importStmt = if d.isPureRst: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")] writeFile(outp, importStmt & content) - let c = if cmd.startsWith("nim "): os.getAppFilename() & " " & $conf.backend & cmd.substr("nim ".len) - elif cmd.startsWith("nim "): os.getAppFilename() & cmd.substr("nim".len) - else: cmd - let c2 = c % quoteShell(outp) - rawMessage(conf, hintExecuting, c2) - if execShellCmd(c2) != status: - rawMessage(conf, errGenerated, "executing of external program failed: " & c2) + + proc interpSnippetCmd(cmd: string): string = + # backward compatibility hacks; interpolation commands should explicitly use `$` + if cmd.startsWith "nim ": result = "$nim " & cmd[4..^1] + else: result = cmd + result = result.replace("$1", "$options") % [ + "nim", os.getAppFilename().quoteShell, + "backend", $d.conf.backend, + "options", outp.quoteShell, + ] + let cmd = cmd.interpSnippetCmd + rawMessage(conf, hintExecuting, cmd) + if execShellCmd(cmd) != status: + rawMessage(conf, errGenerated, "executing of external program failed: " & cmd) result.emitted = initIntSet() result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, htmldocsDir, false) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 3c2435bec..4c5b195ab 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -306,13 +306,14 @@ proc isVSCompatible*(conf: ConfigRef): bool = proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given # for niminst support - let fullSuffix = - case conf.backend - of backendCpp, backendJs, backendObjc: "." & $conf.backend & suffix - of backendC: suffix - else: - doAssert false - "" + var fullSuffix = suffix + case conf.backend + of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix + of backendC: discard + of backendInvalid: + # during parsing of cfg files; we don't know the backend yet, no point in + # guessing wrong thing + return "" if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and optCompileOnly notin conf.globalOptions: diff --git a/compiler/main.nim b/compiler/main.nim index 00bc579df..21c0695f6 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -114,8 +114,10 @@ proc commandJsonScript(graph: ModuleGraph) = let proj = changeFileExt(graph.config.projectFull, "") extccomp.runJsonBuildInstructions(graph.config, proj) -when not defined(leanCompiler): - proc commandCompileToJS(graph: ModuleGraph) = +proc commandCompileToJS(graph: ModuleGraph) = + when defined(leanCompiler): + globalError(graph.config, unknownLineInfo, "compiler wasn't built with JS code generator") + else: let conf = graph.config conf.exc = excCpp @@ -194,47 +196,65 @@ proc mainCommand*(graph: ModuleGraph) = when false: setOutDir(conf) if optUseNimcache in conf.globalOptions: setOutDir(conf) - template handleBackend(backend2: TBackend) = - conf.backend = backend2 - conf.cmd = cmdCompileToBackend - defineSymbol(graph.config.symbols, $backend2) - case backend2 + proc customizeForBackend(backend: TBackend) = + ## Sets backend specific options but don't compile to backend yet in + ## case command doesn't require it. This must be called by all commands. + if conf.backend == backendInvalid: + # only set if wasn't already set, to allow override via `nim c -b:cpp` + conf.backend = backend + + defineSymbol(graph.config.symbols, $conf.backend) + case conf.backend of backendC: if conf.exc == excNone: conf.exc = excSetjmp - commandCompileToC(graph) of backendCpp: if conf.exc == excNone: conf.exc = excCpp - commandCompileToC(graph) - of backendObjc: - commandCompileToC(graph) + of backendObjc: discard of backendJs: - when defined(leanCompiler): - globalError(conf, unknownLineInfo, "compiler wasn't built with JS code generator") - else: - if conf.hcrOn: - # XXX: At the moment, system.nim cannot be compiled in JS mode - # with "-d:useNimRtl". The HCR option has been processed earlier - # and it has added this define implictly, so we must undo that here. - # A better solution might be to fix system.nim - undefSymbol(conf.symbols, "useNimRtl") - commandCompileToJS(graph) + if conf.hcrOn: + # XXX: At the moment, system.nim cannot be compiled in JS mode + # with "-d:useNimRtl". The HCR option has been processed earlier + # and it has added this define implictly, so we must undo that here. + # A better solution might be to fix system.nim + undefSymbol(conf.symbols, "useNimRtl") + of backendInvalid: doAssert false + if conf.selectedGC in {gcArc, gcOrc} and conf.backend != backendCpp: + conf.exc = excGoto + + var commandAlreadyProcessed = false + + proc compileToBackend(backend: TBackend, cmd = cmdCompileToBackend) = + commandAlreadyProcessed = true + conf.cmd = cmd + customizeForBackend(backend) + case conf.backend + of backendC: commandCompileToC(graph) + of backendCpp: commandCompileToC(graph) + of backendObjc: commandCompileToC(graph) + of backendJs: commandCompileToJS(graph) of backendInvalid: doAssert false + ## process all backend commands case conf.command.normalize - of "c", "cc", "compile", "compiletoc": handleBackend(backendC) # compile means compileToC currently - of "cpp", "compiletocpp": handleBackend(backendCpp) - of "objc", "compiletooc": handleBackend(backendObjc) - of "js", "compiletojs": handleBackend(backendJs) + of "c", "cc", "compile", "compiletoc": compileToBackend(backendC) # compile means compileToC currently + of "cpp", "compiletocpp": compileToBackend(backendCpp) + of "objc", "compiletooc": compileToBackend(backendObjc) + of "js", "compiletojs": compileToBackend(backendJs) of "r": # different from `"run"`! conf.globalOptions.incl {optRun, optUseNimcache} - handleBackend(conf.backend) + compileToBackend(backendC) of "run": - conf.cmd = cmdRun when hasTinyCBackend: extccomp.setCC(conf, "tcc", unknownLineInfo) - commandCompileToC(graph) + if conf.backend notin {backendC, backendInvalid}: + rawMessage(conf, errGenerated, "'run' requires c backend, got: '$1'" % $conf.backend) + compileToBackend(backendC, cmd = cmdRun) else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") + else: customizeForBackend(backendC) # fallback for other commands + + ## process all other commands + case conf.command.normalize of "doc0": when defined(leanCompiler): quit "compiler wasn't built with documentation generator" @@ -383,6 +403,7 @@ proc mainCommand*(graph: ModuleGraph) = of "jsonscript": conf.cmd = cmdJsonScript commandJsonScript(graph) + elif commandAlreadyProcessed: discard # already handled else: rawMessage(conf, errGenerated, "invalid command: " & conf.command) diff --git a/compiler/options.nim b/compiler/options.nim index 3e6c7989f..194d635b1 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -223,7 +223,7 @@ type ## fields marked with '*' are subject to ## the incremental compilation mechanisms ## (+) means "part of the dependency" - backend*: TBackend + backend*: TBackend # set via `nim x` or `nim --backend:x` target*: Target # (+) linesCompiled*: int # all lines that have been compiled options*: TOptions # (+) @@ -419,7 +419,7 @@ proc newConfigRef*(): ConfigRef = cIncludes: @[], # directories to search for included files cLibs: @[], # directories to search for lib files cLinkedLibs: @[], # libraries to link - backend: backendC, + backend: backendInvalid, externalToLink: @[], linkOptionsCmd: "", compileOptionsCmd: @[], diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index edd987a76..816d724ef 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -865,7 +865,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = of "test": params.testCmd = n.getFieldValue.strip if params.testCmd.len == 0: - params.testCmd = "nim -r $1" # The nim backend is auto-set in docgen.nim + params.testCmd = "$nim r --backend:$backend $options" # see `interpSnippetCmd` else: params.testCmd = unescape(params.testCmd) of "status", "exitcode": diff --git a/tests/misc/mbackend.nim b/tests/misc/mbackend.nim new file mode 100644 index 000000000..e38eb2d3e --- /dev/null +++ b/tests/misc/mbackend.nim @@ -0,0 +1,31 @@ +#[ +We can't merge this test inside a `when defined(cpp)` because some bug that was +fixed would not trigger in that case. +]# + +import std/compilesettings +import std/unittest + +static: + ## bugfix 1: this used to CT error with: Error: unhandled exception: mimportcpp.nim(6, 18) `defined(cpp)` + doAssert defined(cpp) + doAssert querySetting(backend) == "cpp" + + ## checks that `--backend:c` has no side effect (ie, can be overridden by subsequent commands) + doAssert not defined(c) + doAssert not defined(js) + doAssert not defined(js) + +type + std_exception {.importcpp: "std::exception", header: "".} = object +proc what(s: std_exception): cstring {.importcpp: "((char *)#.what())".} + +var isThrown = false +try: + ## bugfix 2: this used to CT error with: Error: only a 'ref object' can be raised + raise std_exception() +except std_exception as ex: + doAssert ex.what().len > 0 + isThrown = true + +doAssert isThrown diff --git a/tests/nimdoc/m13129.nim b/tests/nimdoc/m13129.nim index df4b5a3f5..95d072d52 100644 --- a/tests/nimdoc/m13129.nim +++ b/tests/nimdoc/m13129.nim @@ -1,3 +1,5 @@ +# issue #13129 + when defined(cpp): {.push header: "".} type diff --git a/tests/trunner.nim b/tests/trunner.nim index bd74a8405..e89606bf7 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -123,6 +123,16 @@ else: # don't run twice the same test let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}" check execCmdEx(cmd) == ("ok3\n", 0) + block: # further issues with `--backend` + let file = testsDir / "misc/mbackend.nim" + var cmd = fmt"{nim} doc -b:cpp --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("", 0) + cmd = fmt"{nim} check -b:c -b:cpp --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("", 0) + # issue https://github.com/timotheecour/Nim/issues/175 + cmd = fmt"{nim} c -b:js -b:cpp --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("", 0) + block: # some importc tests # issue #14314 let file = testsDir / "misc/mimportc.nim" From 390ff428f0787ea882b0b7e4dbefa37e0b676804 Mon Sep 17 00:00:00 2001 From: Bung <535670947@qq.com> Date: Sat, 16 May 2020 21:50:04 +0800 Subject: [PATCH 0545/4254] add SqlPrepared api fix #13559 (#14365) Co-authored-by: bung87 --- lib/impure/db_sqlite.nim | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 810638fb8..c7ace0171 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -124,6 +124,7 @@ type ## converted to an empty string. InstantRow* = PStmt ## A handle that can be used to get a row's column ## text on demand. + SqlPrepared* = distinct PStmt ## a identifier for the prepared queries proc dbError*(db: DbConn) {.noreturn.} = ## Raises a `DbError` exception. @@ -164,6 +165,11 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = else: add(result, c) +proc prepare*(db: DbConn; q: string): SqlPrepared = + if prepare_v2(db, q, q.len.cint,result.PStmt, nil) != SQLITE_OK: + discard finalize(result.PStmt) + dbError(db) + proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {. tags: [ReadDbEffect, WriteDbEffect].} = @@ -188,6 +194,16 @@ proc tryExec*(db: DbConn, query: SqlQuery, discard finalize(stmt) result = false +proc tryExec*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): bool {. + tags: [ReadDbEffect, WriteDbEffect].} = + let x = step(stmtName.PStmt) + if x in {SQLITE_DONE, SQLITE_ROW}: + result = true + else: + discard finalize(stmtName.PStmt) + result = false + proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {. tags: [ReadDbEffect, WriteDbEffect].} = ## Executes the query and raises a `DbError` exception if not successful. @@ -206,6 +222,10 @@ proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {. ## db.close() if not tryExec(db, query, args): dbError(db) +proc exec*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string]) {.tags: [ReadDbEffect, WriteDbEffect].} = + if not tryExec(db, stmtName, args): dbError(db) + proc newRow(L: int): Row = newSeq(result, L) for i in 0..L-1: result[i] = "" @@ -216,6 +236,11 @@ proc setupQuery(db: DbConn, query: SqlQuery, var q = dbFormat(query, args) if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db) +proc setupQuery(db: DbConn, stmtName: SqlPrepared, + args: varargs[string]): PStmt = + assert(not db.isNil, "Database not connected.") + if not tryExec(db, stmtName, args): dbError(db) + proc setRow(stmt: PStmt, r: var Row, cols: cint) = for col in 0'i32..cols-1: setLen(r[col], column_bytes(stmt, col)) # set capacity @@ -264,6 +289,18 @@ iterator fastRows*(db: DbConn, query: SqlQuery, finally: if finalize(stmt) != SQLITE_OK: dbError(db) +iterator fastRows*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): Row {.tags: [ReadDbEffect,WriteDbEffect].} = + var stmt = setupQuery(db, stmtName, args) + var L = (column_count(stmt)) + var result = newRow(L) + try: + while step(stmt) == SQLITE_ROW: + setRow(stmt, result, L) + yield result + except: + dbError(db) + iterator instantRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): InstantRow {.tags: [ReadDbEffect].} = @@ -304,6 +341,16 @@ iterator instantRows*(db: DbConn, query: SqlQuery, finally: if finalize(stmt) != SQLITE_OK: dbError(db) +iterator instantRows*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): InstantRow + {.tags: [ReadDbEffect,WriteDbEffect].} = + var stmt = setupQuery(db, stmtName, args) + try: + while step(stmt) == SQLITE_ROW: + yield stmt + except: + dbError(db) + proc toTypeKind(t: var DbType; x: int32) = case x of SQLITE_INTEGER: @@ -446,6 +493,12 @@ proc getAllRows*(db: DbConn, query: SqlQuery, for r in fastRows(db, query, args): result.add(r) +proc getAllRows*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): seq[Row] {.tags: [ReadDbEffect,WriteDbEffect].} = + result = @[] + for r in fastRows(db, stmtName, args): + result.add(r) + iterator rows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = ## Similar to `fastRows iterator <#fastRows.i,DbConn,SqlQuery,varargs[string,]>`_, @@ -473,6 +526,10 @@ iterator rows*(db: DbConn, query: SqlQuery, ## db.close() for r in fastRows(db, query, args): yield r +iterator rows*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): Row {.tags: [ReadDbEffect,WriteDbEffect].} = + for r in fastRows(db, stmtName, args): yield r + proc getValue*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): string {.tags: [ReadDbEffect].} = ## Executes the query and returns the first column of the first row of the @@ -509,6 +566,19 @@ proc getValue*(db: DbConn, query: SqlQuery, result = "" if finalize(stmt) != SQLITE_OK: dbError(db) +proc getValue*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): string {.tags: [ReadDbEffect,WriteDbEffect].} = + var stmt = setupQuery(db, stmtName, args) + if step(stmt) == SQLITE_ROW: + let cb = column_bytes(stmt, 0) + if cb == 0: + result = "" + else: + result = newStringOfCap(cb) + add(result, column_text(stmt, 0)) + else: + result = "" + proc tryInsertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect], raises: [].} = @@ -590,6 +660,12 @@ proc execAffectedRows*(db: DbConn, query: SqlQuery, exec(db, query, args) result = changes(db) +proc execAffectedRows*(db: DbConn, stmtName: SqlPrepared, + args: varargs[string, `$`]): int64 {. + tags: [ReadDbEffect, WriteDbEffect].} = + exec(db, stmtName, args) + result = changes(db) + proc close*(db: DbConn) {.tags: [DbEffect].} = ## Closes the database connection. ## @@ -637,11 +713,23 @@ proc setEncoding*(connection: DbConn, encoding: string): bool {. exec(connection, sql"PRAGMA encoding = ?", [encoding]) result = connection.getValue(sql"PRAGMA encoding") == encoding +proc finalize*(sqlPrepared:SqlPrepared){.discardable.} = + discard finalize(sqlPrepared.PStmt) + when not defined(testing) and isMainModule: var db = open("db.sql", "", "", "") exec(db, sql"create table tbl1(one varchar(10), two smallint)", []) exec(db, sql"insert into tbl1 values('hello!',10)", []) exec(db, sql"insert into tbl1 values('goodbye', 20)", []) + var p1 = db.prepare "create table tbl2(one varchar(10), two smallint)" + exec(db, p1, []) + finalize(p1) + var p2 = db.prepare "insert into tbl2 values('hello!',10)" + exec(db, p2, []) + finalize(p2) + var p3 = db.prepare "insert into tbl2 values('goodbye', 20)" + exec(db, p3, []) + finalize(p3) #db.query("create table tbl1(one varchar(10), two smallint)") #db.query("insert into tbl1 values('hello!',10)") #db.query("insert into tbl1 values('goodbye', 20)") @@ -649,5 +737,18 @@ when not defined(testing) and isMainModule: echo(r[0], r[1]) for r in db.instantRows(sql"select * from tbl1", []): echo(r[0], r[1]) + var p4 = db.prepare "select * from tbl2" + for r in db.rows(p4, []): + echo(r[0], r[1]) + finalize(p4) + var p5 = db.prepare "select * from tbl2" + for r in db.instantRows(p5, []): + echo(r[0], r[1]) + finalize(p5) + + for r in db.rows(sql"select * from tbl2", []): + echo(r[0], r[1]) + for r in db.instantRows(sql"select * from tbl2", []): + echo(r[0], r[1]) db_sqlite.close(db) From 7361e2627ba91fcb92f37720047a80c231832f22 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 16 May 2020 14:50:41 +0100 Subject: [PATCH 0546/4254] Emscripten: disable epoll (#14361) Epoll is not supported by epoll. --- lib/pure/selectors.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index a2329a2dc..c475c1b4f 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -34,7 +34,7 @@ const hasThreadSupport = compileOption("threads") and defined(threadsafe) const ioselSupportedPlatform* = defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or defined(dragonfly) or - (defined(linux) and not defined(android)) + (defined(linux) and not defined(android) and not defined(emscripten)) ## This constant is used to determine whether the destination platform is ## fully supported by ``ioselectors`` module. @@ -320,7 +320,7 @@ else: # Anything higher is the time to wait in milliseconds. doAssert(timeout >= -1, "Cannot select with a negative value, got " & $timeout) - when defined(linux): + when defined(linux) and not defined(emscripten): include ioselects/ioselectors_epoll elif bsdPlatform: include ioselects/ioselectors_kqueue From 7f377da1d2191bdf73e4ce8961fb982b2da253cb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 16 May 2020 17:03:25 +0200 Subject: [PATCH 0547/4254] fixes #14370 (#14371) --- changelog.md | 2 +- lib/system/excpt.nim | 2 +- lib/system/threads.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 986186356..bb87f817c 100644 --- a/changelog.md +++ b/changelog.md @@ -90,7 +90,7 @@ hangs if a process had both reads from stdin and writes (eg to stdout). - The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. - +- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. - `osproc.execCmdEx` now takes an optional `input` for stdin. - `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index fd1a73b2d..089048163 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -345,7 +345,7 @@ else: proc stackTraceAvailable*(): bool = result = false var onUnhandledException*: (proc (errorMsg: string) {. - nimcall.}) ## Set this error \ + nimcall, gcsafe.}) ## Set this error \ ## handler to override the existing behaviour on an unhandled exception. ## ## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``. diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 34a2d2ccf..6b858c4bb 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -107,7 +107,7 @@ template afterThreadRuns() = when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions): proc deallocOsPages() {.rtl, raises: [].} -proc threadTrouble() {.raises: [].} +proc threadTrouble() {.raises: [], gcsafe.} ## defined in system/excpt.nim when defined(boehmgc): From 40ac19572a86b5bfa7b57cf0482ae3a30432176a Mon Sep 17 00:00:00 2001 From: John <50754967+j-bm@users.noreply.github.com> Date: Sat, 16 May 2020 12:56:52 -0700 Subject: [PATCH 0548/4254] add OpenBSD MAP_STACK for coroutines (#14353) --- lib/system/osalloc.nim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index aa86ee379..32d3b166d 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -196,7 +196,13 @@ elif defined(posix) and not defined(StandaloneHeapSize): PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written - when defined(macosx) or defined(bsd): + when defined(netbsd) or defined(openbsd): + # OpenBSD security for setjmp/longjmp coroutines + var MAP_STACK {.importc: "MAP_STACK", header: "".}: cint + else: + const MAP_STACK = 0 # avoid sideeffects + + when defined(macosx) or defined(freebsd): const MAP_ANONYMOUS = 0x1000 const MAP_PRIVATE = 0x02 # Changes are private elif defined(solaris): @@ -210,7 +216,7 @@ elif defined(posix) and not defined(StandaloneHeapSize): elif defined(haiku): const MAP_ANONYMOUS = 0x08 const MAP_PRIVATE = 0x02 - else: + else: # posix including netbsd or openbsd var MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "".}: cint MAP_PRIVATE {.importc: "MAP_PRIVATE", header: "".}: cint @@ -222,13 +228,13 @@ elif defined(posix) and not defined(StandaloneHeapSize): proc osAllocPages(size: int): pointer {.inline.} = result = mmap(nil, cast[csize_t](size), PROT_READ or PROT_WRITE, - MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) + MAP_ANONYMOUS or MAP_PRIVATE or MAP_STACK, -1, 0) if result == nil or result == cast[pointer](-1): raiseOutOfMem() proc osTryAllocPages(size: int): pointer {.inline.} = result = mmap(nil, cast[csize_t](size), PROT_READ or PROT_WRITE, - MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) + MAP_ANONYMOUS or MAP_PRIVATE or MAP_STACK, -1, 0) if result == cast[pointer](-1): result = nil proc osDeallocPages(p: pointer, size: int) {.inline.} = From 42e80829c7de260b1c88032b1428ade59c4b18d0 Mon Sep 17 00:00:00 2001 From: Frank Schmitt Date: Sun, 17 May 2020 12:44:36 +0200 Subject: [PATCH 0549/4254] docs: fix syntax error in hotCodeReloading example (fixes #14380) (#14381) Co-authored-by: Frank Schmitt --- doc/hcr.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/hcr.rst b/doc/hcr.rst index 9bf88f6ef..f6db0ddfd 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -76,7 +76,7 @@ To install SDL2 you can use ``nimble install sdl2``. discard renderer.clear() discard renderer.setDrawColor(255, 128, 128, 0) - var rect: Rect = (x: posX - 25, y: posY - 25, w: 50.cint, h: 50.cint) + var rect = Rect(x: posX - 25, y: posY - 25, w: 50.cint, h: 50.cint) discard renderer.fillRect(rect) delay(16) renderer.present() From 51578be296ef06013993b4377bde7a0322c0ccb7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 17 May 2020 04:28:18 -0700 Subject: [PATCH 0550/4254] close #12746; minor cleanup (#14379) --- tests/nimdoc/readme.md | 5 +++-- .../{magics => nimdoc}/trunnableexamples.nim | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) rename tests/{magics => nimdoc}/trunnableexamples.nim (74%) diff --git a/tests/nimdoc/readme.md b/tests/nimdoc/readme.md index 64b16c2a5..40b5841eb 100644 --- a/tests/nimdoc/readme.md +++ b/tests/nimdoc/readme.md @@ -1,2 +1,3 @@ -the html validation is tested by nimdoc/tester.nim -the runnableExamples + nim doc logic (across backend) is tested here +## links +* $nim/nimdoc/tester.nim: tests html validation +* $nim/tests/nimdoc/: tests `runnableExamples` + `nim doc` logic diff --git a/tests/magics/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim similarity index 74% rename from tests/magics/trunnableexamples.nim rename to tests/nimdoc/trunnableexamples.nim index e6b2b70f8..e3ae6b9cb 100644 --- a/tests/magics/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -47,6 +47,25 @@ proc fun*() = doAssert declared(isAlphaAscii) echo "foo7" +when true: # issue #12746 + # this proc on its own works fine with `nim doc` + proc goodProc*() = + runnableExamples: + try: + discard + except: + # just the general except will work + discard + + # FIXED: this proc fails with `nim doc` + proc badProc*() = + runnableExamples: + try: + discard + except IOError: + # specifying Error is culprit + discard + # also check for runnableExamples at module scope runnableExamples: block: From 69cc1ddc4d6aa55e717ef6d57401577d4825def8 Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 18 May 2020 09:03:01 +0200 Subject: [PATCH 0551/4254] install gtk3 on osx for package testing (#14388) --- .github/workflows/ci_packages.yml | 2 +- testament/important_packages.nim | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 53e698022..6cf41aa8e 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -36,7 +36,7 @@ jobs: valgrind libc6-dbg libblas-dev - name: 'Install dependencies (macOS)' if: runner.os == 'macOS' - run: brew install boehmgc make sfml + run: brew install boehmgc make sfml gtk+3 - name: 'Install dependencies (Windows)' if: runner.os == 'Windows' shell: bash diff --git a/testament/important_packages.nim b/testament/important_packages.nim index cdb98745c..1d3b1917c 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -1,5 +1,3 @@ -import os - template pkg1(name: string; hasDeps = false; cmd = "nimble test"; url = ""): untyped = packages1.add((name, cmd, hasDeps, url)) @@ -75,11 +73,6 @@ pkg2 "neo", true, "nim c -d:blas=openblas tests/all.nim" pkg2 "nesm" # pkg2 "nico", true pkg2 "nicy", false, "nim c -r src/nicy.nim" -when defined(osx): - # xxx: do this more generally by installing non-nim dependencies automatically - # as specified in nimble file and calling `distros.foreignDepInstallCmd`, but - # it currently would fail work if a package is already installed. - doAssert execShellCmd("brew ls --versions gtk+3 || brew install gtk+3") == 0 pkg2 "nigui", false, "nim c -o:niguii -r src/nigui.nim" pkg2 "NimData", true, "nim c -o:nimdataa src/nimdata.nim" pkg2 "nimes", true, "nim c src/nimes.nim" From b11ff518faec4efe4d5b6e2151d07bf19e26eae0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 18 May 2020 00:38:12 -0700 Subject: [PATCH 0552/4254] fix #12293 findNimStdLibCompileTime should not break with nimble install compiler (#14334) * fix #12293 findNimStdLibCompileTime should not break with nimble install compiler * address comment to unblock PR --- compiler/nimeval.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 09d1eb1da..11e899cae 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -81,6 +81,9 @@ proc findNimStdLib*(): string = ## Returns "" on failure. try: let nimexe = os.findExe("nim") + # this can't work with choosenim shims, refs https://github.com/dom96/choosenim/issues/189 + # it'd need `nim dump --dump.format:json . | jq -r .libpath` + # which we should simplify as `nim dump --key:libpath` if nimexe.len == 0: return "" result = nimexe.splitPath()[0] /../ "lib" if not fileExists(result / "system.nim"): @@ -93,8 +96,8 @@ proc findNimStdLib*(): string = proc findNimStdLibCompileTime*(): string = ## Same as ``findNimStdLib`` but uses source files used at compile time, ## and asserts on error. - const sourcePath = currentSourcePath() - result = sourcePath.parentDir.parentDir / "lib" + const exe = getCurrentCompilerExe() + result = exe.splitFile.dir.parentDir / "lib" doAssert fileExists(result / "system.nim"), "result:" & result proc createInterpreter*(scriptName: string; From bc42e9aa9877e341668f5278bddda73f403d01e4 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 18 May 2020 08:38:36 +0100 Subject: [PATCH 0553/4254] fix #14369 (#14386) * fix #14369 * empty commit --- compiler/ccgstmts.nim | 1 + tests/exception/tcpp_imported_exc2.nim | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/exception/tcpp_imported_exc2.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 20780f734..ca6e51f29 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -727,6 +727,7 @@ proc genRaiseStmt(p: BProc, t: PNode) = initLocExprSingleUse(p, t[0], a) finallyActions(p) var e = rdLoc(a) + discard getTypeDesc(p.module, t[0].typ) var typ = skipTypes(t[0].typ, abstractPtrs) # XXX For reasons that currently escape me, this is only required by the new # C++ based exception handling: diff --git a/tests/exception/tcpp_imported_exc2.nim b/tests/exception/tcpp_imported_exc2.nim new file mode 100644 index 000000000..ff299ea3d --- /dev/null +++ b/tests/exception/tcpp_imported_exc2.nim @@ -0,0 +1,10 @@ +discard """ +targets: "cpp" +output: "" +""" +#issue #14369 case 2 +type RuntimeError {.requiresInit, importcpp: "std::runtime_error", header: "".} = object + +proc initRuntimeError(a: cstring): RuntimeError {.importcpp: "std::runtime_error(@)", constructor.} +try: raise initRuntimeError("foo2") +except: discard From 5beed56d0a5d9827680b34e7964da2031611dd6d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 18 May 2020 02:03:34 -0700 Subject: [PATCH 0554/4254] fix #14174 do not collapse pragma inside runnableExamples (#14385) --- compiler/docgen.nim | 39 ++++++++++++++++++++------------------- compiler/renderer.nim | 2 +- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index b594921ae..6123d49cf 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -370,6 +370,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe var kind = tkEof var tokenPos = 0 var procTokenPos = 0 + template escLit(): untyped = rope(esc(d.target, literal)) while true: getNextTok(r, kind, literal) inc tokenPos @@ -378,7 +379,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe break of tkComment: dispA(d.conf, result, "$1", "\\spanComment{$1}", - [rope(esc(d.target, literal))]) + [escLit]) of tokKeywordLow..tokKeywordHigh: if kind in {tkProc, tkMethod, tkIterator, tkMacro, tkTemplate, tkFunc, tkConverter}: procTokenPos = tokenPos @@ -386,53 +387,53 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe [rope(literal)]) of tkOpr: dispA(d.conf, result, "$1", "\\spanOperator{$1}", - [rope(esc(d.target, literal))]) + [escLit]) of tkStrLit..tkTripleStrLit: dispA(d.conf, result, "$1", - "\\spanStringLit{$1}", [rope(esc(d.target, literal))]) + "\\spanStringLit{$1}", [escLit]) of tkCharLit: dispA(d.conf, result, "$1", "\\spanCharLit{$1}", - [rope(esc(d.target, literal))]) + [escLit]) of tkIntLit..tkUInt64Lit: dispA(d.conf, result, "$1", - "\\spanDecNumber{$1}", [rope(esc(d.target, literal))]) + "\\spanDecNumber{$1}", [escLit]) of tkFloatLit..tkFloat128Lit: dispA(d.conf, result, "$1", - "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))]) + "\\spanFloatNumber{$1}", [escLit]) of tkSymbol: let s = getTokSym(r) # -2 because of the whitespace in between: if procTokenPos == tokenPos-2 and procLink != nil: dispA(d.conf, result, "$1", - "\\spanIdentifier{$1}", [rope(esc(d.target, literal)), procLink]) + "\\spanIdentifier{$1}", [escLit, procLink]) elif s != nil and s.kind in {skType, skVar, skLet, skConst} and sfExported in s.flags and s.owner != nil and belongsToPackage(d.conf, s.owner) and d.target == outHtml: let external = externalDep(d, s.owner) result.addf "$3", [rope changeFileExt(external, "html"), rope literal, - rope(esc(d.target, literal))] + escLit] else: dispA(d.conf, result, "$1", - "\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) + "\\spanIdentifier{$1}", [escLit]) of tkSpaces, tkInvalid: result.add(literal) of tkCurlyDotLe: - dispA(d.conf, result, "" & # This span is required for the JS to work properly + template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit]) + if renderRunnableExamples in renderFlags: fun "$1" + else: fun: "" & # This span is required for the JS to work properly """{...} $1 -""".replace("\n", ""), # Must remove newlines because wrapped in a
-                    "\\spanOther{$1}",
-                  [rope(esc(d.target, literal))])
+""".replace("\n", "")  # Must remove newlines because wrapped in a 
     of tkCurlyDotRi:
-      dispA(d.conf, result, """
+      template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit])
+      if renderRunnableExamples in renderFlags: fun "$1"
+      else: fun """
 
 $1
-""".replace("\n", ""),
-                    "\\spanOther{$1}",
-                  [rope(esc(d.target, literal))])
+""".replace("\n", "")
     of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
        tkBracketDotLe, tkBracketDotRi, tkParDotLe,
        tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
@@ -440,7 +441,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
        tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
        tkBracketLeColon:
       dispA(d.conf, result, "$1", "\\spanOther{$1}",
-            [rope(esc(d.target, literal))])
+            [escLit])
 
 proc testExample(d: PDoc; ex: PNode) =
   if d.conf.errorCounter > 0: return
@@ -525,7 +526,7 @@ proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
       for b in body:
         if i > 0: dest.add "\n"
         inc i
-        nodeToHighlightedHtml(d, b, dest, {}, nil)
+        nodeToHighlightedHtml(d, b, dest, {renderRunnableExamples}, nil)
       dest.add(d.config.getOrDefault"doc.listing_end" % id)
   else: discard
   for i in 0..
Date: Mon, 18 May 2020 16:15:10 +0100
Subject: [PATCH 0555/4254] docs:getCurrentException() and
 getCurrentExceptionMsg() are not available for imported exceptions (#14392)

---
 doc/manual.rst | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/doc/manual.rst b/doc/manual.rst
index 4e477f6ff..80029fca4 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -4258,7 +4258,9 @@ caught by reference. Example:
   except std_exception as ex:
     echo ex.what()
 
-
+**Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available 
+for imported exceptions. You need to use `except ImportedException as x:` syntax 
+and rely on functionality of `x` object to get exception details.
 
 Effect system
 =============

From 2627e1e9459379c9bc180890980e571ad7adf203 Mon Sep 17 00:00:00 2001
From: Timothee Cour 
Date: Mon, 18 May 2020 09:10:30 -0700
Subject: [PATCH 0556/4254] refs #14369 improve docs for importcpp exceptions
 (#14391)

* refs #14369 improve docs for importcpp exceptions

* address comments
---
 doc/manual.rst | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/doc/manual.rst b/doc/manual.rst
index 80029fca4..759042078 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -4247,16 +4247,38 @@ It is possible to raise/catch imported C++ exceptions. Types imported using
 caught by reference. Example:
 
 .. code-block:: nim
+    :test: "nim cpp -r $1"
 
   type
-    std_exception {.importcpp: "std::exception", header: "".} = object
+    CStdException {.importcpp: "std::exception", header: "", inheritable.} = object
+      ## does not inherit from `RootObj`, so we use `inheritable` instead
+    CRuntimeError {.requiresInit, importcpp: "std::runtime_error", header: "".} = object of CStdException
+      ## `CRuntimeError` has no default constructor => `requiresInit`
+  proc what(s: CStdException): cstring {.importcpp: "((char *)#.what())".}
+  proc initRuntimeError(a: cstring): CRuntimeError {.importcpp: "std::runtime_error(@)", constructor.}
+  proc initStdException(): CStdException {.importcpp: "std::exception()", constructor.}
 
-  proc what(s: std_exception): cstring {.importcpp: "((char *)#.what())".}
+  proc fn() =
+    let a = initRuntimeError("foo")
+    doAssert $a.what == "foo"
+    var b: cstring
+    try: raise initRuntimeError("foo2")
+    except CStdException as e:
+      doAssert e is CStdException
+      b = e.what()
+    doAssert $b == "foo2"
 
-  try:
-    raise std_exception()
-  except std_exception as ex:
-    echo ex.what()
+    try: raise initStdException()
+    except CStdException: discard
+
+    try: raise initRuntimeError("foo3")
+    except CRuntimeError as e:
+      b = e.what()
+    except CStdException:
+      doAssert false
+    doAssert $b == "foo3"
+
+  fn()
 
 **Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available 
 for imported exceptions. You need to use `except ImportedException as x:` syntax 

From ac65986aae77e47d4f2ae99acc8048fe3d637921 Mon Sep 17 00:00:00 2001
From: Clyybber 
Date: Mon, 18 May 2020 18:43:06 +0200
Subject: [PATCH 0557/4254] Fix #14394 (#14395)

---
 lib/pure/hashes.nim | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index cd0841d2e..1024ce26f 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -97,7 +97,7 @@ proc hiXorLo(a, b: uint64): uint64 {.inline.} =
     when Hash.sizeof < 8:
       result = hiXorLoFallback64(a, b)
     elif defined(gcc) or defined(llvm_gcc) or defined(clang):
-      {.emit: """__uint128_t r = a; r *= b; `result` = (r >> 64) ^ r;""".}
+      {.emit: """__uint128_t r = `a`; r *= `b`; `result` = (r >> 64) ^ r;""".}
     elif defined(windows) and not defined(tcc):
       proc umul128(a, b: uint64, c: ptr uint64): uint64 {.importc: "_umul128", header: "intrin.h".}
       var b = b

From 27741d6a5c9ec87a6938b2928ae54b22bc93d9be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= 
Date: Mon, 18 May 2020 23:44:04 +0200
Subject: [PATCH 0558/4254] fix #14364 (#14372) [backport:1.2]

Turn on the TLS emulation when using Boehm, since it doesn't scan the
real TLS.
---
 compiler/commands.nim | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compiler/commands.nim b/compiler/commands.nim
index 340180378..e2e1a4558 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -493,6 +493,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
       of "boehm":
         conf.selectedGC = gcBoehm
         defineSymbol(conf.symbols, "boehmgc")
+        incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS
       of "refc":
         conf.selectedGC = gcRefc
       of "v2":

From e909486e5cde5a4a77cd6f21b42fc9ab38ec2ae6 Mon Sep 17 00:00:00 2001
From: Timothee Cour 
Date: Tue, 19 May 2020 00:41:31 -0700
Subject: [PATCH 0559/4254] trunner was not actually being tested in non-CTFFI
 mode; minor testament cleanups (#14377)

* use check
* trunner now works with cpp
* cleanup: move compiler/unittest_light => stdtest/unittest_light
* fix tests/readme.md
* remove deadcode references to rodfiles
* fix for windows
---
 compiler/rodimpl.nim                          |  2 ++
 koch.nim                                      |  2 +-
 lib/system/io.nim                             |  2 +-
 testament/categories.nim                      |  5 ----
 .../lib/stdtest}/unittest_light.nim           |  0
 tests/compiler/tasciitables.nim               |  2 +-
 tests/compiler/tunittest_light.nim            |  2 +-
 tests/misc/mbackend.nim                       |  1 -
 tests/misc/msizeof5.nim                       |  2 +-
 tests/misc/tparseopt.nim                      |  2 +-
 tests/{ => misc}/trunner.nim                  | 26 +++++++++++--------
 tests/readme.md                               | 13 ++++------
 tests/stdlib/tosproc.nim                      |  3 +--
 tests/stdlib/tstackframes.nim                 |  2 +-
 14 files changed, 30 insertions(+), 34 deletions(-)
 rename {compiler => testament/lib/stdtest}/unittest_light.nim (100%)
 rename tests/{ => misc}/trunner.nim (84%)

diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index 8ee7ae564..417241930 100644
--- a/compiler/rodimpl.nim
+++ b/compiler/rodimpl.nim
@@ -916,6 +916,8 @@ proc loadNode*(g: ModuleGraph; module: PSym): PNode =
   replay(g, module, result)
 
 proc setupModuleCache*(g: ModuleGraph) =
+  ## historical note: there used to be a `rodfiles` dir with special tests
+  ## for incremental compilation via symbol files. This was likely replaced by ic.
   if g.config.symbolFiles == disabledSf: return
   g.recordStmt = recordStmt
   let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"
diff --git a/koch.nim b/koch.nim
index 3ec40534b..0391c3c4a 100644
--- a/koch.nim
+++ b/koch.nim
@@ -554,7 +554,7 @@ proc runCI(cmd: string) =
         # no need to bootstrap with koch boot (would be slower)
         let backend = if doUseCpp(): "cpp" else: "c"
         execFold("build with -d:nimHasLibFFI", "nim $1 -d:release -d:nimHasLibFFI -o:$2 compiler/nim.nim" % [backend, nimFFI])
-        execFold("test with -d:nimHasLibFFI", "$1 $2 -r testament/testament --nim:$1 r tests/trunner.nim" % [nimFFI, backend])
+        execFold("test with -d:nimHasLibFFI", "$1 $2 -r testament/testament --nim:$1 r tests/misc/trunner.nim -d:nimTrunnerFfi" % [nimFFI, backend])
 
     execFold("Run nimdoc tests", "nim c -r nimdoc/tester")
     execFold("Run nimpretty tests", "nim c -r nimpretty/tester.nim")
diff --git a/lib/system/io.nim b/lib/system/io.nim
index ab415f40c..84bebba28 100644
--- a/lib/system/io.nim
+++ b/lib/system/io.nim
@@ -733,7 +733,7 @@ when declared(stdout):
         releaseSys echoLock
 
 
-when defined(windows) and not defined(nimscript):
+when defined(windows) and not defined(nimscript) and not defined(js):
   # work-around C's sucking abstraction:
   # BUGFIX: stdin and stdout should be binary files!
   proc c_setmode(handle, mode: cint) {.
diff --git a/testament/categories.nim b/testament/categories.nim
index d60b89e33..114949ce8 100644
--- a/testament/categories.nim
+++ b/testament/categories.nim
@@ -32,7 +32,6 @@ const
     "nimble-packages-1",
     "nimble-packages-2",
     "niminaction",
-    "rodfiles",
     "threads",
     "untestable",
     "stdlib",
@@ -671,10 +670,6 @@ proc processCategory(r: var TResults, cat: Category,
                      options, testsDir: string,
                      runJoinableTests: bool) =
   case cat.string.normalize
-  of "rodfiles":
-    when false:
-      compileRodFiles(r, cat, options)
-      runRodFiles(r, cat, options)
   of "ic":
     when false:
       icTests(r, testsDir, cat, options)
diff --git a/compiler/unittest_light.nim b/testament/lib/stdtest/unittest_light.nim
similarity index 100%
rename from compiler/unittest_light.nim
rename to testament/lib/stdtest/unittest_light.nim
diff --git a/tests/compiler/tasciitables.nim b/tests/compiler/tasciitables.nim
index 0a5ee0f05..80d648508 100644
--- a/tests/compiler/tasciitables.nim
+++ b/tests/compiler/tasciitables.nim
@@ -1,4 +1,4 @@
-import compiler/unittest_light
+import stdtest/unittest_light
 import compiler/asciitables
 
 import strformat
diff --git a/tests/compiler/tunittest_light.nim b/tests/compiler/tunittest_light.nim
index 5cad6997f..2951cc664 100644
--- a/tests/compiler/tunittest_light.nim
+++ b/tests/compiler/tunittest_light.nim
@@ -1,4 +1,4 @@
-import compiler/unittest_light
+import stdtest/unittest_light
 
 proc testAssertEquals() =
   assertEquals("foo", "foo")
diff --git a/tests/misc/mbackend.nim b/tests/misc/mbackend.nim
index e38eb2d3e..b6578a212 100644
--- a/tests/misc/mbackend.nim
+++ b/tests/misc/mbackend.nim
@@ -4,7 +4,6 @@ fixed would not trigger in that case.
 ]#
 
 import std/compilesettings
-import std/unittest
 
 static:
   ## bugfix 1: this used to CT error with: Error: unhandled exception: mimportcpp.nim(6, 18) `defined(cpp)`
diff --git a/tests/misc/msizeof5.nim b/tests/misc/msizeof5.nim
index c833d1e43..63573a705 100644
--- a/tests/misc/msizeof5.nim
+++ b/tests/misc/msizeof5.nim
@@ -116,7 +116,7 @@ when defined caseBad:
     ensureCgen Foo5
 
   block:
-    type Foo6{.importc, completeStruct.} = object
+    type Foo6{.importc:"struct Foo6", completeStruct.} = object
       a1: cint
       # a2: bool # missing this should trigger assert fail
       a3: cfloat
diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim
index 25ce77816..a3dfcbb26 100644
--- a/tests/misc/tparseopt.nim
+++ b/tests/misc/tparseopt.nim
@@ -71,7 +71,7 @@ else:
 
   import osproc, os, strutils
   from stdtest/specialpaths import buildDir
-  import "../.." / compiler/unittest_light
+  import stdtest/unittest_light
 
   block: # fix #9951
     template runTest(parseoptCustom) =
diff --git a/tests/trunner.nim b/tests/misc/trunner.nim
similarity index 84%
rename from tests/trunner.nim
rename to tests/misc/trunner.nim
index e89606bf7..bfe331c9c 100644
--- a/tests/trunner.nim
+++ b/tests/misc/trunner.nim
@@ -5,6 +5,7 @@ discard """
 
 ## tests that don't quite fit the mold and are easier to handle via `execCmdEx`
 ## A few others could be added to here to simplify code.
+## Note: this test is a bit slow but tests a lot of things; please don't disable.
 
 import std/[strformat,os,osproc,unittest]
 
@@ -15,7 +16,7 @@ const mode =
   elif defined(cpp): "cpp"
   else: static: doAssert false
 
-const testsDir = currentSourcePath().parentDir
+const testsDir = currentSourcePath.parentDir.parentDir
 const buildDir = testsDir.parentDir / "build"
 const nimcache = buildDir / "nimcacheTrunner"
   # `querySetting(nimcacheDir)` would also be possible, but we thus
@@ -28,7 +29,7 @@ proc runCmd(file, options = ""): auto =
   result = execCmdEx(cmd)
   when false:  echo result[0] & "\n" & result[1] # for debugging
 
-when defined(nimHasLibFFIEnabled):
+when defined(nimTrunnerFfi):
   block: # mevalffi
     when defined(openbsd):
       #[
@@ -65,7 +66,7 @@ else: # don't run twice the same test
   block: # mstatic_assert
     let (output, exitCode) = runCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad")
     check2 "sizeof(bool) == 2"
-    doAssert exitCode != 0
+    check exitCode != 0
 
   block: # ABI checks
     let file = "misc/msizeof5.nim"
@@ -82,12 +83,11 @@ else: # don't run twice the same test
       check2 "sizeof(Foo5) == 16"
       check2 "sizeof(Foo5) == 3"
       check2 "sizeof(struct Foo6) == "
-      doAssert exitCode != 0
+      check exitCode != 0
 
   import streams
   block: # stdin input
-    let nimcmd = fmt"{nim} r --hints:off - -firstparam '-second param'"
-    let inputcmd = "import os; echo commandLineParams()"
+    let nimcmd = fmt"""{nim} r --hints:off - -firstparam "-second param" """
     let expected = """@["-firstparam", "-second param"]"""
     block:
       let p = startProcess(nimcmd, options = {poEvalCommand})
@@ -98,23 +98,27 @@ else: # don't run twice the same test
       doAssert p.waitForExit == 0
       doAssert error.len == 0, $error
       output.stripLineEnd
-      doAssert output == expected
+      check output == expected
       p.errorStream.close
       p.outputStream.close
 
     block:
-      when defined(posix):
-        let cmd = fmt"echo 'import os; echo commandLineParams()' | {nimcmd}"
+      when defined posix:
+        # xxx on windows, `poEvalCommand` should imply `/cmd`, (which should
+        # make this work), but currently doesn't
+        let cmd = fmt"""echo "import os; echo commandLineParams()" | {nimcmd}"""
         var (output, exitCode) = execCmdEx(cmd)
         output.stripLineEnd
-        doAssert output == expected
+        check output == expected
+        doAssert exitCode == 0
 
   block: # nim doc --backend:$backend --doccmd:$cmd
     # test for https://github.com/nim-lang/Nim/issues/13129
     # test for https://github.com/nim-lang/Nim/issues/13891
     let file = testsDir / "nimdoc/m13129.nim"
     for backend in fmt"{mode} js".split:
-      let cmd = fmt"{nim} doc -b:{backend} --nimcache:{nimcache} -d:m13129Foo1 --doccmd:'-d:m13129Foo2 --hints:off' --usenimcache --hints:off {file}"
+      # pending #14343 this fails on windows: --doccmd:"-d:m13129Foo2 --hints:off"
+      let cmd = fmt"""{nim} doc -b:{backend} --nimcache:{nimcache} -d:m13129Foo1 "--doccmd:-d:m13129Foo2 --hints:off" --usenimcache --hints:off {file}"""
       check execCmdEx(cmd) == (&"ok1:{backend}\nok2: backend: {backend}\n", 0)
     # checks that --usenimcache works with `nim doc`
     check fileExists(nimcache / "m13129.html")
diff --git a/tests/readme.md b/tests/readme.md
index b9b8abd39..234ee4efe 100644
--- a/tests/readme.md
+++ b/tests/readme.md
@@ -2,9 +2,8 @@ This directory contains the test cases.
 
 Each test must have a filename of the form: ``t*.nim``
 
-**Note:** Tests are only compiled by default. In order to get the tester to
-execute the compiled binary, you need to specify a spec with an ``action`` key
-(see below for details).
+**Note:** Testament is only aware of tests under a directory (eg `tests/foo/`) and will ignore
+top-level tests like `tests/tbar.nim`.
 
 # Specs
 
@@ -16,7 +15,7 @@ Each test can contain a spec in a ``discard """ ... """`` block.
 
 Specifies what action this test should take.
 
-**Default: compile**
+**Default: run**
 
 Options:
 
@@ -50,10 +49,8 @@ discard """
 # Categories
 
 Each folder under this directory represents a test category, which can be
-tested by running `koch tests cat `.
-
-The folder ``rodfiles`` contains special tests that test incremental
-compilation via symbol files.
+tested by running `koch tests pcat ` (or `cat` to avoid parallel
+testing, which is slower).
 
 The folder ``dll`` contains simple DLL tests.
 
diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim
index 36afd6a23..b5328c9eb 100644
--- a/tests/stdlib/tosproc.nim
+++ b/tests/stdlib/tosproc.nim
@@ -1,7 +1,6 @@
 # test the osproc module
 
-import stdtest/specialpaths
-import "$nim" / compiler/unittest_light
+import stdtest/[specialpaths, unittest_light]
 
 when defined(case_testfile): # compiled test file for child process
   from posix import exitnow
diff --git a/tests/stdlib/tstackframes.nim b/tests/stdlib/tstackframes.nim
index be66eb836..618ff7b92 100644
--- a/tests/stdlib/tstackframes.nim
+++ b/tests/stdlib/tstackframes.nim
@@ -1,5 +1,5 @@
 import std/[strformat,os,osproc]
-import "$nim/compiler/unittest_light" # works even if moved by megatest
+import stdtest/unittest_light
 
 proc main(opt: string, expected: string) =
   const nim = getCurrentCompilerExe()

From b35d370d885b07d3f4eca527197f42f532bdcf64 Mon Sep 17 00:00:00 2001
From: Andreas Rumpf 
Date: Tue, 19 May 2020 21:42:53 +0200
Subject: [PATCH 0560/4254] specialize genericReset (#14398)

* progress
* make tests green
* maybe we also want to reset pointers, dunno
* progress
* cleanup; fixes #13879 [backport:1.2]
---
 compiler/ccgexprs.nim | 46 ++++++++++-----------
 compiler/ccgreset.nim | 94 +++++++++++++++++++++++++++++++++++++++++++
 compiler/cgen.nim     |  8 +++-
 lib/system/gc_ms.nim  |  2 +-
 4 files changed, 124 insertions(+), 26 deletions(-)
 create mode 100644 compiler/ccgreset.nim

diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 0b9958ee4..ec54081a2 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1194,9 +1194,11 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
 proc genReset(p: BProc, n: PNode) =
   var a: TLoc
   initLocExpr(p, n[1], a)
-  linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
-          [addrLoc(p.config, a),
-          genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
+  specializeReset(p, a)
+  when false:
+    linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
+            [addrLoc(p.config, a),
+            genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
 
 proc genDefault(p: BProc; n: PNode; d: var TLoc) =
   if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
@@ -2793,6 +2795,21 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
   else:
     globalError(p.config, info, "cannot create null element for: " & $t.kind)
 
+proc caseObjDefaultBranch(obj: PNode; branch: Int128): int =
+  for i in 1 ..< obj.len:
+    for j in 0 .. obj[i].len - 2:
+      if obj[i][j].kind == nkRange:
+        let x = getOrdValue(obj[i][j][0])
+        let y = getOrdValue(obj[i][j][1])
+        if branch >= x and branch <= y:
+          return i
+      elif getOrdValue(obj[i][j]) == branch:
+        return i
+    if obj[i].len == 1:
+      # else branch
+      return i
+  assert(false, "unreachable")
+
 proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
                      result: var Rope; count: var int;
                      isConst: bool, info: TLineInfo) =
@@ -2815,31 +2832,14 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
           branch = getOrdValue(constOrNil[i])
           break
 
-    var selectedBranch = -1
-    block branchSelection:
-      for i in 1 ..< obj.len:
-        for j in 0 .. obj[i].len - 2:
-          if obj[i][j].kind == nkRange:
-              let x = getOrdValue(obj[i][j][0])
-              let y = getOrdValue(obj[i][j][1])
-              if branch >= x and branch <= y:
-                selectedBranch = i
-                break branchSelection
-          elif getOrdValue(obj[i][j]) == branch:
-            selectedBranch = i
-            break branchSelection
-        if obj[i].len == 1:
-          # else branch
-          selectedBranch = i
-    assert(selectedBranch >= 1)
-
+    let selectedBranch = caseObjDefaultBranch(obj, branch)
     result.add "{"
     var countB = 0
     let b = lastSon(obj[selectedBranch])
     # designated initilization is the only way to init non first element of unions
     # branches are allowed to have no members (b.len == 0), in this case they don't need initializer
-    if  b.kind == nkRecList and b.len > 0:
-      result.add "._" &  mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
+    if b.kind == nkRecList and b.len > 0:
+      result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
       getNullValueAux(p, t,  b, constOrNil, result, countB, isConst, info)
       result.add "}"
     elif b.kind == nkSym:
diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim
new file mode 100644
index 000000000..ef1505f57
--- /dev/null
+++ b/compiler/ccgreset.nim
@@ -0,0 +1,94 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2020 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# included from cgen.nim
+
+## Code specialization instead of the old, incredibly slow 'genericReset'
+## implementation.
+
+proc specializeResetT(p: BProc, accessor: Rope, typ: PType)
+
+proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
+                     typ: PType) =
+  if n == nil: return
+  case n.kind
+  of nkRecList:
+    for i in 0..
Date: Wed, 20 May 2020 00:41:57 +0200
Subject: [PATCH 0561/4254] fixes #14126 [backport:1.2] (#14390)

* fixes #14126 [backport:1.2]

* used more logic to optimize it further; updated Nimble version
---
 compiler/ccgcalls.nim          | 29 ++++++++++++++++----
 koch.nim                       |  2 +-
 tests/ccgbugs/tcodegenbug1.nim | 48 +++++++++++++++++++++++++++++++---
 3 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 893d597bd..8f9d879df 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -21,11 +21,30 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
     # we have to be *very* conservative:
     result = canRaiseConservative(n)
 
-proc leftAppearsOnRightSide(le, ri: PNode): bool =
+proc preventNrvo(p: BProc; le, ri: PNode): bool =
+  proc locationEscapes(p: BProc; le: PNode): bool =
+    var n = le
+    while true:
+      # do NOT follow nkHiddenDeref here!
+      case n.kind
+      of nkSym:
+        # we don't own the location so it escapes:
+        return n.sym.owner != p.prc
+      of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
+          nkCheckedFieldExpr:
+        n = n[0]
+      of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+        n = n[1]
+      else:
+        # cannot analyse the location; assume the worst
+        return true
+
   if le != nil:
     for i in 1.. 0 or locationEscapes(p, le))
 
 proc hasNoInit(call: PNode): bool {.inline.} =
   result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
@@ -51,7 +70,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
     if isInvalidReturnType(p.config, typ[0]):
       if params != nil: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
-      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+      if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
         # Great, we can use 'd':
         if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
         elif d.k notin {locTemp} and not hasNoInit(ri):
@@ -150,7 +169,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
       result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
     of tyString, tySequence:
       let atyp = skipTypes(a.t, abstractInst)
-      if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and 
+      if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and
           optSeqDestructors in p.config.globalOptions:
         linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
       if atyp.kind == tyVar and not compileToCpp(p.module):
@@ -166,7 +185,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
       result = "$1, $1Len_0" % [rdLoc(a)]
     of tyString, tySequence:
       let ntyp = skipTypes(n.typ, abstractInst)
-      if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and 
+      if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and
           optSeqDestructors in p.config.globalOptions:
         linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
       if ntyp.kind == tyVar and not compileToCpp(p.module):
@@ -292,7 +311,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
     if isInvalidReturnType(p.config, typ[0]):
       if ri.len > 1: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
-      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+      if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
         # Great, we can use 'd':
         if d.k == locNone:
           getTemp(p, typ[0], d, needsInit=true)
diff --git a/koch.nim b/koch.nim
index 0391c3c4a..ee7c8006a 100644
--- a/koch.nim
+++ b/koch.nim
@@ -10,7 +10,7 @@
 #
 
 const
-  NimbleStableCommit = "6f2b1ace922e565f7f48a69648e16a002a5d15e3" # master
+  NimbleStableCommit = "63695f490728e3935692c29f3d71944d83bb1e83" # master
 
 when not defined(windows):
   const
diff --git a/tests/ccgbugs/tcodegenbug1.nim b/tests/ccgbugs/tcodegenbug1.nim
index ebdc57144..11846ff95 100644
--- a/tests/ccgbugs/tcodegenbug1.nim
+++ b/tests/ccgbugs/tcodegenbug1.nim
@@ -3,7 +3,10 @@ discard """
 obj.inner.id = 7
 id = 7
 obj = (inner: (kind: Just, id: 7))
-2'''
+2
+(a: "1", b: "2", c: "3")
+caught
+(a: "1", b: "", c: "3")'''
 """
 
 # bug #6960
@@ -129,12 +132,51 @@ import macros
 func myfunc(obj: MyObject): MyResult {.raises: [].} =
   template index: auto =
     case obj.kind:
-      of Float: $obj.index 
+      of Float: $obj.index
       of Fixed: "Fixed"
   macro to_str(a: untyped): string =
-    result = newStrLitNode(a.repr)  
+    result = newStrLitNode(a.repr)
   result.val[0] = index
   result.val[1] = to_str(obj.kind + Ola)
 
 let x = MyObject(someInt: 10, kind: Fixed)
 echo myfunc(x).val.len
+
+# bug #14126
+
+type X = object
+  a, b, c: string
+
+proc f(): X =
+  result.a = "a"
+  result.b = "b"
+  raise (ref ValueError)()
+
+proc ohmanNoNRVO =
+  var x: X
+  x.a = "1"
+  x.b = "2"
+  x.c = "3"
+
+  try:
+    x = f()
+  except:
+    discard
+
+  echo x
+  doAssert x.c == "3", "shouldn't modify x if f raises"
+
+ohmanNoNRVO()
+
+proc ohmanNoNRVO2(x: var X) =
+  x.a = "1"
+  x.c = "3"
+  x = f()
+
+var xgg: X
+try:
+  ohmanNoNRVO2(xgg)
+except:
+  echo "caught"
+echo xgg
+doAssert xgg.c == "3", "this assert will fail"

From 1450924b1e68ad3cd2dc8db2c54f9741315ca212 Mon Sep 17 00:00:00 2001
From: Danil Yarantsev <21169548+Yardanico@users.noreply.github.com>
Date: Wed, 20 May 2020 10:28:47 +0300
Subject: [PATCH 0562/4254] Fix some typos in the manual [backport] (#14399)

---
 doc/manual.rst | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/doc/manual.rst b/doc/manual.rst
index 759042078..8b27c7819 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -148,7 +148,7 @@ It is mostly accurate to picture semantic analysis proceeding top to bottom and
 left to right in the source code, with compile-time code execution interleaved
 when necessary to compute values that are required for subsequent semantic
 analysis. We will see much later in this document that macro invocation not only
-requires this interleaving, but also creates a situation where semantic analyis
+requires this interleaving, but also creates a situation where semantic analysis
 does not entirely proceed top to bottom and left to right.
 
 
@@ -792,7 +792,7 @@ features supported at compile time (as detailed in the next section below).
 Within such a code block, it is possible to declare variables and then later
 read and update them, or declare variables and pass them to procedures that
 modify them. However, the code in such a block must still adhere to the
-retrictions listed above for referencing values and operations outside the
+restrictions listed above for referencing values and operations outside the
 block.
 
 The ability to access and modify compile-time variables adds flexibility to
@@ -1296,7 +1296,7 @@ A parameter ``A`` may be an *open array*, in which case it is indexed by
 integers from 0 to ``len(A)-1``. An array expression may be constructed by the
 array constructor ``[]``. The element type of this array expression is
 inferred from the type of the first element. All other elements need to be
-implicitly convertable to this type.
+implicitly convertible to this type.
 
 Sequences are similar to arrays but of dynamic length which may change
 during runtime (like strings). Sequences are implemented as growable arrays,
@@ -3837,7 +3837,7 @@ 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
+Implicit items/pairs invocations
 -------------------------------
 
 If the for loop expression ``e`` does not denote an iterator and the for loop
@@ -4231,7 +4231,7 @@ Exception hierarchy
 The exception tree is defined in the `system `_ module.
 Every exception inherits from ``system.Exception``. Exceptions that indicate
 programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``)
-and are stricly speaking not catchable as they can also be mapped to an operation
+and are strictly speaking not catchable as they can also be mapped to an operation
 that terminates the whole process. If panics are turned into exceptions, these
 exceptions inherit from `Defect`.
 
@@ -4566,8 +4566,8 @@ more complex type classes:
 
 Whilst the syntax of type classes appears to resemble that of ADTs/algebraic data
 types in ML-like languages, it should be understood that type classes are static
-constraints to be enforced at type instantations. Type classes are not really
-types in themsleves, but are instead a system of providing generic "checks" that
+constraints to be enforced at type instantiations. Type classes are not really
+types in themselves, but are instead a system of providing generic "checks" that
 ultimately *resolve* to some singular type. Type classes do not allow for
 runtime type dynamism, unlike object variants or methods.
 
@@ -4729,7 +4729,7 @@ instantiation. The following is not allowed:
   # not valid: 'T' is not inferred to be of type 'var int'
   g(v, i)
 
-  # also not allowed: explict instantiation via 'var int'
+  # also not allowed: explicit instantiation via 'var int'
   g[var int](v, i)
 
 
@@ -5219,7 +5219,7 @@ tree (AST) of the code that is passed to it. The macro can then do
 transformations on it and return the transformed AST. This can be used to
 add custom language features and implement `domain specific languages`:idx:.
 
-Macro invocation is a case where semantic analyis does **not** entirely proceed
+Macro invocation is a case where semantic analysis does **not** entirely proceed
 top to bottom and left to right. Instead, semantic analysis happens at least
 twice:
 
@@ -6452,7 +6452,7 @@ and instead the generated code should contain an ``#include``:
     PFile {.importc: "FILE*", header: "".} = distinct pointer
       # import C's FILE* type; Nim will treat it as a new pointer type
 
-The ``header`` pragma always expects a string constant. The string contant
+The ``header`` pragma always expects a string constant. The string constant
 contains the header file: As usual for C, a system header file is enclosed
 in angle brackets: ``<>``. If no angle brackets are given, Nim
 encloses the header file in ``""`` in the generated C code.

From 4ae341353de5c58dc339e47b0eec2bbb4649dc10 Mon Sep 17 00:00:00 2001
From: alaviss 
Date: Wed, 20 May 2020 07:42:55 +0000
Subject: [PATCH 0563/4254] asyncdispatch, asyncnet: add inheritance control
 (#14362)

* asyncdispatch, asyncnet: add inheritance control

* asyncnet, asyncdispatch: cleanup
---
 changelog.md               | 17 ++++-----
 lib/pure/asyncdispatch.nim | 71 ++++++++++++++++++++++++++++++--------
 lib/pure/asyncnet.nim      | 44 +++++++++++++++++------
 tests/stdlib/tfdleak.nim   | 36 ++++++++++++++++---
 4 files changed, 130 insertions(+), 38 deletions(-)

diff --git a/changelog.md b/changelog.md
index bb87f817c..88619b1c2 100644
--- a/changelog.md
+++ b/changelog.md
@@ -13,20 +13,21 @@
 - `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads.
 - File handles created from high-level abstractions in the stdlib will no longer
   be inherited by child processes. In particular, these modules are affected:
-  `system`, `nativesockets`, `net` and `selectors`.
+  `asyncdispatch`, `asyncnet`, `system`, `nativesockets`, `net` and `selectors`.
 
-  For `net` and `nativesockets`, an `inheritable` flag has been added to all
-  `proc`s that create sockets, allowing the user to control whether the
-  resulting socket is inheritable. This flag is provided to ease the writing of
-  multi-process servers, where sockets inheritance is desired.
+  For `asyncdispatch`, `asyncnet`, `net` and `nativesockets`, an `inheritable`
+  flag has been added to all `proc`s that create sockets, allowing the user to
+  control whether the resulting socket is inheritable. This flag is provided to
+  ease the writing of multi-process servers, where sockets inheritance is
+  desired.
 
   For a transistion period, define `nimInheritHandles` to enable file handle
   inheritance by default. This flag does **not** affect the `selectors` module
   due to the differing semantics between operating systems.
 
-  `system.setInheritable` and `nativesockets.setInheritable` is also introduced
-  for setting file handle or socket inheritance. Not all platform have these
-  `proc`s defined.
+  `asyncdispatch.setInheritable`, `system.setInheritable` and
+  `nativesockets.setInheritable` is also introduced for setting file handle or
+  socket inheritance. Not all platform have these `proc`s defined.
 
 - The file descriptors created for internal bookkeeping by `ioselector_kqueue`
   and `ioselector_epoll` will no longer be leaked to child processes.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 91778a5bc..0800cb638 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -228,6 +228,16 @@ proc initCallSoonProc =
   if asyncfutures.getCallSoonProc().isNil:
     asyncfutures.setCallSoonProc(callSoon)
 
+template implementSetInheritable() {.dirty.} =
+  when declared(setInheritable):
+    proc setInheritable*(fd: AsyncFD, inheritable: bool): bool =
+      ## Control whether a file handle can be inherited by child processes.
+      ## Returns ``true`` on success.
+      ##
+      ## This procedure is not guaranteed to be available for all platforms.
+      ## Test for availability with `declared()`_.
+      fd.FileHandle.setInheritable(inheritable)
+
 when defined(windows) or defined(nimdoc):
   import winlean, sets, hashes
   type
@@ -695,7 +705,8 @@ when defined(windows) or defined(nimdoc):
           retFuture.complete(bytesReceived)
     return retFuture
 
-  proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
+  proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
+                   inheritable = defined(nimInheritHandles)):
       owned(Future[tuple[address: string, client: AsyncFD]]) =
     ## Accepts a new connection. Returns a future containing the client socket
     ## corresponding to that connection and the remote address of the client.
@@ -704,6 +715,9 @@ when defined(windows) or defined(nimdoc):
     ## The resulting client socket is automatically registered to the
     ## dispatcher.
     ##
+    ## If ``inheritable`` is false (the default), the resulting client socket will
+    ## not be inheritable by child processes.
+    ##
     ## The ``accept`` call may result in an error if the connecting socket
     ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
     ## flag is specified then this error will not be raised and instead
@@ -711,7 +725,7 @@ when defined(windows) or defined(nimdoc):
     verifyPresence(socket)
     var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr")
 
-    var clientSock = createNativeSocket()
+    var clientSock = createNativeSocket(inheritable = inheritable)
     if clientSock == osInvalidSocket: raiseOSError(osLastError())
 
     const lpOutputLen = 1024
@@ -788,6 +802,8 @@ when defined(windows) or defined(nimdoc):
 
     return retFuture
 
+  implementSetInheritable()
+
   proc closeSocket*(socket: AsyncFD) =
     ## Closes a socket and ensures that it is unregistered.
     socket.SocketHandle.close()
@@ -1090,6 +1106,9 @@ else:
   import selectors
   from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
                     MSG_NOSIGNAL
+  when declared(posix.accept4):
+    from posix import accept4, SOCK_CLOEXEC
+
   const
     InitCallbackListSize = 4         # initial size of callbacks sequence,
                                      # associated with file/socket descriptor.
@@ -1263,6 +1282,8 @@ else:
       # descriptor was unregistered in callback via `unregister()`.
       discard
 
+  implementSetInheritable()
+
   proc closeSocket*(sock: AsyncFD) =
     let selector = getGlobalDispatcher().selector
     if sock.SocketHandle notin selector:
@@ -1484,7 +1505,8 @@ else:
     addRead(socket, cb)
     return retFuture
 
-  proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
+  proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
+                   inheritable = defined(nimInheritHandles)):
       owned(Future[tuple[address: string, client: AsyncFD]]) =
     var retFuture = newFuture[tuple[address: string,
         client: AsyncFD]]("acceptAddr")
@@ -1492,8 +1514,21 @@ else:
       result = true
       var sockAddress: Sockaddr_storage
       var addrLen = sizeof(sockAddress).SockLen
-      var client = accept(sock.SocketHandle,
-                          cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
+      var client =
+        when declared(accept4):
+          accept4(sock.SocketHandle, cast[ptr SockAddr](addr(sockAddress)),
+                  addr(addrLen), if inheritable: 0 else: SOCK_CLOEXEC)
+        else:
+          accept(sock.SocketHandle, cast[ptr SockAddr](addr(sockAddress)),
+                 addr(addrLen))
+      when declared(setInheritable) and not declared(accept4):
+        if client != osInvalidSocket and not setInheritable(client, inheritable):
+          # Set failure first because close() itself can fail,
+          # altering osLastError().
+          retFuture.fail(newOSError(osLastError()))
+          close client
+          return false
+
       if client == osInvalidSocket:
         let lastError = osLastError()
         assert lastError.int32 != EWOULDBLOCK and lastError.int32 != EAGAIN
@@ -1578,8 +1613,9 @@ proc poll*(timeout = 500) =
   ## `epoll`:idx: or `kqueue`:idx: primitive only once.
   discard runOnce(timeout)
 
-template createAsyncNativeSocketImpl(domain, sockType, protocol) =
-  let handle = createNativeSocket(domain, sockType, protocol)
+template createAsyncNativeSocketImpl(domain, sockType, protocol: untyped,
+                                     inheritable = defined(nimInheritHandles)) =
+  let handle = createNativeSocket(domain, sockType, protocol, inheritable)
   if handle == osInvalidSocket:
     return osInvalidSocket.AsyncFD
   handle.setBlocking(false)
@@ -1589,13 +1625,15 @@ template createAsyncNativeSocketImpl(domain, sockType, protocol) =
   register(result)
 
 proc createAsyncNativeSocket*(domain: cint, sockType: cint,
-                           protocol: cint): AsyncFD =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
+                              protocol: cint,
+                              inheritable = defined(nimInheritHandles)): AsyncFD =
+  createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable)
 
 proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
-                           sockType: SockType = SOCK_STREAM,
-                           protocol: Protocol = IPPROTO_TCP): AsyncFD =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
+                              sockType: SockType = SOCK_STREAM,
+                              protocol: Protocol = IPPROTO_TCP,
+                              inheritable = defined(nimInheritHandles)): AsyncFD =
+  createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable)
 
 proc newAsyncNativeSocket*(domain: cint, sockType: cint,
     protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
@@ -1824,12 +1862,17 @@ proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) =
   return retFuture
 
 proc accept*(socket: AsyncFD,
-    flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncFD]) =
+             flags = {SocketFlag.SafeDisconn},
+             inheritable = defined(nimInheritHandles)): owned(Future[AsyncFD]) =
   ## Accepts a new connection. Returns a future containing the client socket
   ## corresponding to that connection.
+  ##
+  ## If ``inheritable`` is false (the default), the resulting client socket
+  ## will not be inheritable by child processes.
+  ##
   ## The future will complete when the connection is successfully accepted.
   var retFut = newFuture[AsyncFD]("accept")
-  var fut = acceptAddr(socket, flags)
+  var fut = acceptAddr(socket, flags, inheritable)
   fut.callback =
     proc (future: Future[tuple[address: string, client: AsyncFD]]) =
       assert future.finished
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 93334d0e2..7ccb469cf 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -129,12 +129,17 @@ type
   AsyncSocket* = ref AsyncSocketDesc
 
 proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
-    sockType: SockType = SOCK_STREAM,
-    protocol: Protocol = IPPROTO_TCP, buffered = true): owned(AsyncSocket) =
+                     sockType: SockType = SOCK_STREAM,
+                     protocol: Protocol = IPPROTO_TCP,
+                     buffered = true,
+                     inheritable = defined(nimInheritHandles)): owned(AsyncSocket) =
   ## Creates a new ``AsyncSocket`` based on the supplied params.
   ##
   ## The supplied ``fd``'s non-blocking state will be enabled implicitly.
   ##
+  ## If ``inheritable`` is false (the default), the supplied ``fd`` will not
+  ## be inheritable by child processes.
+  ##
   ## **Note**: This procedure will **NOT** register ``fd`` with the global
   ## async dispatcher. You need to do this manually. If you have used
   ## ``newAsyncNativeSocket`` to create ``fd`` then it's already registered.
@@ -142,6 +147,8 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
   new(result)
   result.fd = fd.SocketHandle
   fd.SocketHandle.setBlocking(false)
+  if not fd.SocketHandle.setInheritable(inheritable):
+    raiseOSError(osLastError())
   result.isBuffered = buffered
   result.domain = domain
   result.sockType = sockType
@@ -150,15 +157,19 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
     result.currPos = 0
 
 proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
-    protocol: Protocol = IPPROTO_TCP, buffered = true): owned(AsyncSocket) =
+                     protocol: Protocol = IPPROTO_TCP, buffered = true,
+                     inheritable = defined(nimInheritHandles)): owned(AsyncSocket) =
   ## Creates a new asynchronous socket.
   ##
   ## This procedure will also create a brand new file descriptor for
   ## this socket.
-  let fd = createAsyncNativeSocket(domain, sockType, protocol)
+  ##
+  ## If ``inheritable`` is false (the default), the new file descriptor will not
+  ## be inheritable by child processes.
+  let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable)
   if fd.SocketHandle == osInvalidSocket:
     raiseOSError(osLastError())
-  result = newAsyncSocket(fd, domain, sockType, protocol, buffered)
+  result = newAsyncSocket(fd, domain, sockType, protocol, buffered, inheritable)
 
 proc getLocalAddr*(socket: AsyncSocket): (string, Port) =
   ## Get the socket's local address and port number.
@@ -173,16 +184,20 @@ proc getPeerAddr*(socket: AsyncSocket): (string, Port) =
   getPeerAddr(socket.fd, socket.domain)
 
 proc newAsyncSocket*(domain, sockType, protocol: cint,
-    buffered = true): owned(AsyncSocket) =
+                     buffered = true,
+                     inheritable = defined(nimInheritHandles)): owned(AsyncSocket) =
   ## Creates a new asynchronous socket.
   ##
   ## This procedure will also create a brand new file descriptor for
   ## this socket.
-  let fd = createAsyncNativeSocket(domain, sockType, protocol)
+  ##
+  ## If ``inheritable`` is false (the default), the new file descriptor will not
+  ## be inheritable by child processes.
+  let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable)
   if fd.SocketHandle == osInvalidSocket:
     raiseOSError(osLastError())
   result = newAsyncSocket(fd, Domain(domain), SockType(sockType),
-                          Protocol(protocol), buffered)
+                          Protocol(protocol), buffered, inheritable)
 
 when defineSsl:
   proc getSslError(handle: SslPtr, err: cint): cint =
@@ -443,13 +458,18 @@ proc send*(socket: AsyncSocket, data: string,
   else:
     await send(socket.fd.AsyncFD, data, flags)
 
-proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
+proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn},
+                 inheritable = defined(nimInheritHandles)):
       owned(Future[tuple[address: string, client: AsyncSocket]]) =
   ## Accepts a new connection. Returns a future containing the client socket
   ## corresponding to that connection and the remote address of the client.
+  ##
+  ## If ``inheritable`` is false (the default), the resulting client socket will
+  ## not be inheritable by child processes.
+  ##
   ## The future will complete when the connection is successfully accepted.
   var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
-  var fut = acceptAddr(socket.fd.AsyncFD, flags)
+  var fut = acceptAddr(socket.fd.AsyncFD, flags, inheritable)
   fut.callback =
     proc (future: Future[tuple[address: string, client: AsyncFD]]) =
       assert future.finished
@@ -458,7 +478,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
       else:
         let resultTup = (future.read.address,
                          newAsyncSocket(future.read.client, socket.domain,
-                         socket.sockType, socket.protocol, socket.isBuffered))
+                         socket.sockType, socket.protocol, socket.isBuffered, inheritable))
         retFuture.complete(resultTup)
   return retFuture
 
@@ -466,6 +486,8 @@ proc accept*(socket: AsyncSocket,
     flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncSocket]) =
   ## Accepts a new connection. Returns a future containing the client socket
   ## corresponding to that connection.
+  ## If ``inheritable`` is false (the default), the resulting client socket will
+  ## not be inheritable by child processes.
   ## The future will complete when the connection is successfully accepted.
   var retFut = newFuture[AsyncSocket]("asyncnet.accept")
   var fut = acceptAddr(socket, flags)
diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim
index 08ef06da3..c4f144db5 100644
--- a/tests/stdlib/tfdleak.nim
+++ b/tests/stdlib/tfdleak.nim
@@ -4,13 +4,15 @@ discard """
   matrix: "; -d:nimInheritHandles"
 """
 
-import os, osproc, strutils, nativesockets, net, selectors, memfiles
+import os, osproc, strutils, nativesockets, net, selectors, memfiles,
+       asyncdispatch, asyncnet
 when defined(windows):
   import winlean
 else:
   import posix
 
-proc leakCheck(f: int | FileHandle | SocketHandle, msg: string, expectLeak = defined(nimInheritHandles)) =
+proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string,
+               expectLeak = defined(nimInheritHandles)) =
   discard startProcess(
     getAppFilename(),
     args = @[$f.int, msg, $expectLeak],
@@ -40,14 +42,14 @@ proc main() =
     let sock = createNativeSocket()
     defer: close sock
     leakCheck(sock, "createNativeSocket()")
-    if sock.setInheritable(true):
-      leakCheck(sock, "createNativeSocket()", true)
+    if sock.setInheritable(not defined(nimInheritHandles)):
+      leakCheck(sock, "createNativeSocket()", not defined(nimInheritHandles))
     else:
       raiseOSError osLastError()
 
     let server = newSocket()
     defer: close server
-    server.bindAddr()
+    server.bindAddr(address = "127.0.0.1")
     server.listen()
     let (_, port) = server.getLocalAddr
 
@@ -74,6 +76,30 @@ proc main() =
       leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false)
     else:
       leakCheck(mf.handle, "memfiles.open().handle", false)
+
+    let sockAsync = createAsyncNativeSocket()
+    defer: closeSocket sockAsync
+    leakCheck(sockAsync, "createAsyncNativeSocket()")
+    if sockAsync.setInheritable(not defined(nimInheritHandles)):
+      leakCheck(sockAsync, "createAsyncNativeSocket()", not defined(nimInheritHandles))
+    else:
+      raiseOSError osLastError()
+
+    let serverAsync = newAsyncSocket()
+    defer: close serverAsync
+    serverAsync.bindAddr(address = "127.0.0.1")
+    serverAsync.listen()
+    let (_, portAsync) = serverAsync.getLocalAddr
+
+    leakCheck(serverAsync.getFd, "newAsyncSocket()")
+
+    let clientAsync = newAsyncSocket()
+    defer: close clientAsync
+    waitFor clientAsync.connect("127.0.0.1", portAsync)
+
+    let inputAsync = waitFor serverAsync.accept()
+
+    leakCheck(inputAsync.getFd, "accept() async")
   else:
     let
       fd = parseInt(paramStr 1)

From 3d20f141939b0cb76079a9b0ae7784f7877f1698 Mon Sep 17 00:00:00 2001
From: Timothee Cour 
Date: Wed, 20 May 2020 00:45:34 -0700
Subject: [PATCH 0564/4254] fix #10731 ; `runnableExamples "-b:cpp --run:off":
 code` works (#14384)

* runnableExamples "-b:cpp -r:off": code
---
 changelog.md                                 |  2 +
 compiler/docgen.nim                          | 86 +++++++++++++-------
 lib/system.nim                               | 11 ++-
 nimdoc/tester.nim                            |  5 +-
 nimdoc/testproject/expected/testproject.html |  2 +-
 tests/nimdoc/trunnableexamples.nim           | 35 +++++++-
 6 files changed, 104 insertions(+), 37 deletions(-)

diff --git a/changelog.md b/changelog.md
index 88619b1c2..0e1af73c1 100644
--- a/changelog.md
+++ b/changelog.md
@@ -185,6 +185,8 @@ proc mydiv(a, b): int {.raises: [].} =
   use `--doccmd:skip` to skip runnableExamples and rst test snippets.
 - new flag `--usenimcache` to output to nimcache (whatever it resolves to after all commands are processed)
   and avoids polluting both $pwd and $projectdir. It can be used with any command.
+- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override how an example is compiled and run,
+  for example to change backend or compile only.
 
 ## Tool changes
 
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 6123d49cf..8b5201029 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -17,7 +17,7 @@ import
   packages/docutils/rst, packages/docutils/rstgen,
   json, xmltree, cgi, trees, types,
   typesrenderer, astalgo, lineinfos, intsets,
-  pathutils, trees
+  pathutils, trees, tables
 
 const
   exportSection = skField
@@ -26,6 +26,12 @@ const
 
 type
   TSections = array[TSymKind, Rope]
+  ExampleGroup = ref object
+    ## a group of runnableExamples with same rdoccmd
+    rdoccmd: string ## from 1st arg in `runnableExamples(rdoccmd): body`
+    docCmd: string ## from user config, eg --doccmd:-d:foo
+    code: string ## contains imports; each import contains `body`
+    index: int ## group index
   TDocumentor = object of rstgen.RstGenerator
     modDesc: Rope       # module description
     module: PSym
@@ -44,7 +50,7 @@ type
                     # already. See bug #3655
     destFile*: AbsoluteFile
     thisDir*: AbsoluteDir
-    examples: string
+    exampleGroups: OrderedTable[string, ExampleGroup]
     wroteCss*: bool
 
   PDoc* = ref TDocumentor ## Alias to type less.
@@ -443,54 +449,72 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
       dispA(d.conf, result, "$1", "\\spanOther{$1}",
             [escLit])
 
-proc testExample(d: PDoc; ex: PNode) =
+proc exampleOutputDir(d: PDoc): AbsoluteDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
+
+proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) =
   if d.conf.errorCounter > 0: return
-  let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
+  let outputDir = d.exampleOutputDir
   createDir(outputDir)
   inc d.exampleCounter
+  # PRTEMP
   let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
       "_examples" & $d.exampleCounter & ".nim"))
   #let nimcache = outp.changeFileExt"" & "_nimcache"
   renderModule(ex, d.filename, outp.string, conf = d.conf)
-  d.examples.add "import r\"" & outp.string & "\"\n"
+  if rdoccmd notin d.exampleGroups: d.exampleGroups[rdoccmd] = ExampleGroup(rdoccmd: rdoccmd, docCmd: d.conf.docCmd, index: d.exampleGroups.len)
+  d.exampleGroups[rdoccmd].code.add "import r\"$1\"\n" % outp.string
 
 proc runAllExamples(d: PDoc) =
-  let docCmd = d.conf.docCmd
   let backend = d.conf.backend
   # This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however
   # using `-d:js` (etc) cannot work properly, eg would fail with `importjs`
   # since semantics are affected by `config.backend`, not by isDefined(d.conf, "js")
-  if d.examples.len == 0 or docCmd == docCmdSkip: return
-  let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
-  let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
-      "_examples.nim"))
-  writeFile(outp, d.examples)
-  let cmd = "$nim $backend -r --warning:UnusedImport:off --path:$path --nimcache:$nimcache $docCmd $file" % [
-    "nim", os.getAppFilename(),
-    "backend", $d.conf.backend,
-    "path", quoteShell(d.conf.projectPath),
-    "nimcache", quoteShell(outputDir),
-    "file", quoteShell(outp),
-    "docCmd", docCmd,
-  ]
-  if os.execShellCmd(cmd) != 0:
-    quit "[runnableExamples] failed: generated file: '$1' cmd: $2" % [outp.string, cmd]
-  else:
-    # keep generated source file `outp` to allow inspection.
-    rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
-    removeFile(outp.changeFileExt(ExeExt))
+  let outputDir = d.exampleOutputDir
+  for _, group in d.exampleGroups:
+    if group.docCmd == docCmdSkip: continue
+    let outp = outputDir / RelativeFile("$1_group$2_examples.nim" % [d.filename.splitFile.name, $group.index])
+    group.code = "# autogenerated by docgen\n# source: $1\n# rdoccmd: $2\n$3" % [d.filename, group.rdoccmd, group.code]
+    writeFile(outp, group.code)
+    # most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
+    # via command line
+    let cmd = "$nim $backend -r --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
+      "nim", os.getAppFilename(),
+      "backend", $d.conf.backend,
+      "path", quoteShell(d.conf.projectPath),
+      "nimcache", quoteShell(outputDir),
+      "file", quoteShell(outp),
+      "rdoccmd", group.rdoccmd,
+      "docCmd", group.docCmd,
+    ]
+    if os.execShellCmd(cmd) != 0:
+      quit "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, $group[], cmd]
+    else:
+      # keep generated source file `outp` to allow inspection.
+      rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
+      # removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
 
+proc prepareExample(d: PDoc; n: PNode): string =
+  ## returns `rdoccmd` for this runnableExamples
+  var rdoccmd = ""
+  if n.len < 2 or n.len > 3: globalError(d.conf, n.info, "runnableExamples invalid")
+  if n.len == 3:
+    let n1 = n[1]
+    # xxx this should be evaluated during sempass
+    if n1.kind notin nkStrKinds: globalError(d.conf, n1.info, "string litteral expected")
+    rdoccmd = n1.strVal
 
-proc prepareExamples(d: PDoc; n: PNode) =
   var docComment = newTree(nkCommentStmt)
   let loc = d.conf.toFileLineCol(n.info)
-  docComment.comment = "autogenerated by docgen from " & loc
+
+  docComment.comment = "autogenerated by docgen\nloc: $1\nrdoccmd: $2" % [loc, rdoccmd]
   var runnableExamples = newTree(nkStmtList,
       docComment,
       newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
   runnableExamples.info = n.info
+
   for a in n.lastSon: runnableExamples.add a
-  testExample(d, runnableExamples)
+  writeExample(d, runnableExamples, rdoccmd)
+  result = rdoccmd
   when false:
     proc extractImports(n: PNode; result: PNode) =
       if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
@@ -510,9 +534,11 @@ proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
   of nkCallKinds:
     if isRunnableExamples(n[0]) and
         n.len >= 2 and n.lastSon.kind == nkStmtList:
-      prepareExamples(d, n)
+      let rdoccmd = prepareExample(d, n)
+      var msg = "Example:"
+      if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
       dispA(d.conf, dest, "\n

$1

\n", - "\n\\textbf{$1}\n", [rope"Examples:"]) + "\n\\textbf{$1}\n", [msg.rope]) inc d.listingCounter let id = $d.listingCounter dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"]) diff --git a/lib/system.nim b/lib/system.nim index e5b359c70..85be43cba 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -117,7 +117,7 @@ else: Ordinal* = OrdinalImpl | uint | uint64 when defined(nimHasRunnableExamples): - proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".} + proc runnableExamples*(rdoccmd = "", body: untyped) {.magic: "RunnableExamples".} ## A section you should use to mark `runnable example`:idx: code with. ## ## - In normal debug and release builds code within @@ -139,10 +139,15 @@ when defined(nimHasRunnableExamples): ## assert double(5) == 10 ## block: ## at block scope ## defer: echo "done" - ## ## result = 2 * x + ## runnableExamples "-d:foo -b:cpp": + ## import std/compilesettings + ## doAssert querySetting(backend) == "cpp" + ## runnableExamples "-r:off": ## this one is only compiled + ## import std/browsers + ## openDefaultBrowser "https://forum.nim-lang.org/" else: - template runnableExamples*(body: untyped) = + template runnableExamples*(doccmd = "", body: untyped) = discard proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index a1500455e..58272a9b6 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -24,12 +24,13 @@ proc testNimDoc(prjDir, docsDir: string; switches: NimSwitches; fixup = false) = nimBuildIndexSwitches = switches.buildIndex.join(" ") putEnv("SOURCE_DATE_EPOCH", "100000") + const nimExe = getCurrentCompilerExe() # so that `bin/nim_temp r nimdoc/tester.nim` works if nimDocSwitches != "": - exec("nim doc $1" % [nimDocSwitches]) + exec("$1 doc $2" % [nimExe, nimDocSwitches]) if nimBuildIndexSwitches != "": - exec("nim buildIndex $1" % [nimBuildIndexSwitches]) + exec("$1 buildIndex $2" % [nimExe, nimBuildIndexSwitches]) for expected in walkDirRec(prjDir / "expected/"): let produced = expected.replace('\\', '/').replace("/expected/", "/$1/" % [docsDir]) diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 77f178265..4eb8ed44c 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -183,7 +183,7 @@ function main() {

This is the top level module. -

Examples:

+

Example:

import
   subdir / subdir_b / utils
 
diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim
index e3ae6b9cb..73cfacd43 100644
--- a/tests/nimdoc/trunnableexamples.nim
+++ b/tests/nimdoc/trunnableexamples.nim
@@ -1,5 +1,5 @@
 discard """
-cmd: "nim doc $file"
+cmd: "nim doc --doccmd:-d:testFooExternal --hints:off $file"
 action: "compile"
 nimout: '''
 foo1
@@ -66,6 +66,39 @@ when true: # issue #12746
         # specifying Error is culprit
         discard
 
+when true: # runnableExamples with rdoccmd
+  runnableExamples "-d:testFoo -d:testBar":
+    doAssert defined(testFoo) and defined(testBar)
+    doAssert defined(testFooExternal)
+  runnableExamples "-d:testFoo2":
+    doAssert defined(testFoo2)
+    doAssert not defined(testFoo) # doesn't get confused by other examples
+
+  ## all these syntaxes work too
+  runnableExamples("-d:testFoo2"): discard
+  runnableExamples(): discard
+  runnableExamples: discard
+  runnableExamples "-r:off": # issue #10731
+    doAssert false ## we compile only (-r:off), so this won't be run
+  runnableExamples "-b:js":
+    import std/compilesettings
+    proc startsWith*(s, prefix: cstring): bool {.noSideEffect, importjs: "#.startsWith(#)".}
+    doAssert querySetting(backend) == "js"
+  runnableExamples "-b:cpp":
+    static: doAssert defined(cpp)
+    type std_exception {.importcpp: "std::exception", header: "".} = object
+
+  proc fun2*() =
+    runnableExamples "-d:foo": discard # checks that it also works inside procs
+
+  when false: # future work
+    # passing non-string-litterals (for reuse)
+    const a = "-b:cpp"
+    runnableExamples(a): discard
+
+    # passing seq (to run with multiple compilation options)
+    runnableExamples(@["-b:cpp", "-b:js"]): discard
+
 # also check for runnableExamples at module scope
 runnableExamples:
   block:

From 7fe4c66f3598d9c87fe93e60f5f123857779980c Mon Sep 17 00:00:00 2001
From: Clyybber 
Date: Wed, 20 May 2020 12:54:04 +0200
Subject: [PATCH 0565/4254] Small improvements for string and char repr with
 gc:arc (#14400)

* Small improvements for string and char repr with gc:arc

* Fix test
---
 lib/system/repr_v2.nim          | 14 ++++++++------
 tests/arc/trepr.nim             |  4 ++--
 tests/destructor/tfinalizer.nim |  2 +-
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim
index 407a06844..be1a4cf3a 100644
--- a/lib/system/repr_v2.nim
+++ b/lib/system/repr_v2.nim
@@ -27,21 +27,23 @@ proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
   ## repr for a boolean argument. Returns `x`
   ## converted to the string "false" or "true".
 
-proc repr*(x: char): string {.magic: "CharToStr", noSideEffect.}
+proc repr*(x: char): string {.noSideEffect.} =
   ## repr for a character argument. Returns `x`
   ## converted to a string.
   ##
   ## .. code-block:: Nim
   ##   assert repr('c') == "c"
+  '\'' & $x & '\''
 
-proc repr*(x: cstring): string {.magic: "CStrToStr", noSideEffect.}
+proc repr*(x: cstring): string {.noSideEffect.} =
   ## repr for a CString argument. Returns `x`
-  ## converted to a string.
+  ## converted to a quoted string.
+  '"' & $x & '"'
 
-proc repr*(x: string): string {.magic: "StrToStr", noSideEffect.}
+proc repr*(x: string): string {.noSideEffect.} =
   ## repr for a string argument. Returns `x`
-  ## as it is. This operator is useful for generic code, so
-  ## that ``$expr`` also works if ``expr`` is already a string.
+  ## but quoted.
+  '"' & x & '"'
 
 proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
   ## repr for an enumeration argument. This works for
diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim
index e24c112ac..a870b40b7 100644
--- a/tests/arc/trepr.nim
+++ b/tests/arc/trepr.nim
@@ -7,8 +7,8 @@ nil
   output: '''
 nil
 2
-Obj(member: ref @[hello])
-ref (member: ref @[hello])
+Obj(member: ref @["hello"])
+ref (member: ref @["hello"])
 '''
 """
 import tables
diff --git a/tests/destructor/tfinalizer.nim b/tests/destructor/tfinalizer.nim
index 02a5cef7e..eb2cd09af 100644
--- a/tests/destructor/tfinalizer.nim
+++ b/tests/destructor/tfinalizer.nim
@@ -1,6 +1,6 @@
 discard """
   cmd: "nim c --gc:arc $file"
-  output: '''Foo(field: Dick Laurent, k: ka, x: 0.0)
+  output: '''Foo(field: "Dick Laurent", k: ka, x: 0.0)
 Nobody is dead
 Dick Laurent is dead'''
 """

From 6969a468ceaab7384d7448bfd88e47a5b24c3a97 Mon Sep 17 00:00:00 2001
From: Clyybber 
Date: Wed, 20 May 2020 13:04:52 +0200
Subject: [PATCH 0566/4254] Remove #PRTEMP leftover comment

---
 compiler/docgen.nim | 1 -
 1 file changed, 1 deletion(-)

diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 8b5201029..a67dc48ec 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -456,7 +456,6 @@ proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) =
   let outputDir = d.exampleOutputDir
   createDir(outputDir)
   inc d.exampleCounter
-  # PRTEMP
   let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
       "_examples" & $d.exampleCounter & ".nim"))
   #let nimcache = outp.changeFileExt"" & "_nimcache"

From e600ddc555201f29576397d560aab5350456c650 Mon Sep 17 00:00:00 2001
From: Timothee Cour 
Date: Wed, 20 May 2020 18:34:14 -0700
Subject: [PATCH 0567/4254] fix comment from
 https://github.com/nim-lang/Nim/commit/e909486e5cde5a4a77cd6f21b42fc9ab38ec2ae6#r39287564
 (#14412)

---
 compiler/rodimpl.nim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index 417241930..52b4d1f85 100644
--- a/compiler/rodimpl.nim
+++ b/compiler/rodimpl.nim
@@ -916,8 +916,8 @@ proc loadNode*(g: ModuleGraph; module: PSym): PNode =
   replay(g, module, result)
 
 proc setupModuleCache*(g: ModuleGraph) =
-  ## historical note: there used to be a `rodfiles` dir with special tests
-  ## for incremental compilation via symbol files. This was likely replaced by ic.
+  # historical note: there used to be a `rodfiles` dir with special tests
+  # for incremental compilation via symbol files. This was likely replaced by ic.
   if g.config.symbolFiles == disabledSf: return
   g.recordStmt = recordStmt
   let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"

From 5caaa4bf6fd95cf8252dd86669b67d02aec903db Mon Sep 17 00:00:00 2001
From: Timothee Cour 
Date: Thu, 21 May 2020 02:01:43 -0700
Subject: [PATCH 0568/4254] fix #14404 foldr had the classic multiple
 evaluation bug (#14413)

---
 lib/pure/collections/sequtils.nim | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index afb225884..a89d2c572 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -843,8 +843,7 @@ template foldl*(sequence, operation, first): untyped =
       digits = foldl(numbers, a & (chr(b + ord('0'))), "")
     assert digits == "0815"
 
-  var result: typeof(first)
-  result = first
+  var result: typeof(first) = first
   for x in items(sequence):
     let
       a {.inject.} = result
@@ -883,11 +882,11 @@ template foldr*(sequence, operation: untyped): untyped =
     assert multiplication == 495, "Multiplication is (5*(9*(11)))"
     assert concatenation == "nimiscool"
 
-  let s = sequence
-  assert s.len > 0, "Can't fold empty sequences"
-  var result: typeof(s[0])
-  result = sequence[s.len - 1]
-  for i in countdown(s.len - 2, 0):
+  let s = sequence # xxx inefficient, use {.evalonce.} pending #13750
+  let n = s.len
+  assert n > 0, "Can't fold empty sequences"
+  var result = s[n - 1]
+  for i in countdown(n - 2, 0):
     let
       a {.inject.} = s[i]
       b {.inject.} = result
@@ -1436,6 +1435,7 @@ when isMainModule:
     assert subtraction == 7, "Subtraction is (5-(9-(11)))"
     assert multiplication == 495, "Multiplication is (5*(9*(11)))"
     assert concatenation == "nimiscool"
+    doAssert toSeq(1..3).foldr(a + b) == 6 # issue #14404
 
   block: # mapIt + applyIt test
     counter = 0

From f71f8b0239e3d6aff75390075bba13a62c292422 Mon Sep 17 00:00:00 2001
From: Mamy Ratsimbazafy 
Date: Thu, 21 May 2020 17:52:40 +0200
Subject: [PATCH 0569/4254] The whole options module should be inline (#14417)
 [backport:1.2]

* The whole options module should be inline

* Use inline per proc and tag `lent` where appropriate

* Remove lent annotation (failing at compiletime)
---
 build.out            | Bin 0 -> 430264 bytes
 lib/pure/options.nim |  29 ++++++++++++++---------------
 2 files changed, 14 insertions(+), 15 deletions(-)
 create mode 100755 build.out

diff --git a/build.out b/build.out
new file mode 100755
index 0000000000000000000000000000000000000000..9edb996b0c494271d8d4f910ce04ee6ae72f2b6d
GIT binary patch
literal 430264
zcmeFad3;n=(l_2g8qoneE@;$I<2HgTDyXPPTv{6yjSB7xiXe=rh>4~
z;+}CM;~Ez<`Ur$&(otu$-Nv{_1idk+(LsqTzwfu|oV#>)BJcCp@BMsUXGq_BYB^PP
z>eQ*T+UxT*+eo0qv;JLqlHhA{eO2}W*b@$)t{S{(=L&bVex-c)zeeUmq)0C_I
zwQ#q-sixMP-_|xV4TbElpN_T}caGE=8h3Hv%4ujt()?$Zp!yWc`5$o{QLg0aBn@8uO2Tv}NnjHg}|x^P0pgiEeqA#pFRyo5DSyh|<(O}uj27J%NI;X8eHHrPCl90_k{Tnv2hyd`W1c
z1)$E!(;zGmE@ogofLGHhc)2exFPNg?mJAer%<&_SICAWMd+$3WWG}s|eGhaC_uG3Y
zU8k4)Pk%SSb#GIm)&v
zz&8lpW$r7tnYvd$Do>N};4=s=9lsB33
zbWZt-rxbr)PWdWRUYAq8+LSlsl&>-6jXCANoARcd^8O84Z{M7LX75`s)&9+~Q8C4A
zp*COnCR!wa9bft8zVc3AIb*KC%=D(7u
zD*uMKH%%^(QeU~v1qc}EE8jpc_0M2mxpLI?nZ5{sG^#k5Bq_$_}{w>}!l(sj?{j0oZ2yJhW`=z|+5Yk>J
z_b>6Dp|m|M_s{U2A+$X%_mA?Pp|gFe+&{p3hRpVHa(@@^87kY$<^C4lGeowR$^8wy
zXJ~96Ece&)o*}WlRPL|lJwsu8vD{DNJ%_UPklg>3_Y8^coxh`C*YkPLP}trk_h<5+
zA+S9w_b2n7p|8D3?vLd?hrsp*xj%yU41w)+a(^)I8T#7Oa=#z%8S>iWa=$z88S2`n
z%Kc8fXNYSbC->X%o}sP19QSO`eZL-=c=Oy?VnwWaWoP;5<5S`1$Mg=xQvFBB&+w;L
z_X@2WumUR#YtpgQ@X25hONFUdY*<&t0Jy>;z~~Aat!sfSz
z9!qq_mV7fJwxnx=SW$EA&EG4w0E4-PLEm+46C*nu<wDZ|{QW9u{kcLNZ4p=_t>rlQ1B0Vc|KiX{hBlK{A}M6v#a
zFEb^?o;Wr_yqxG@mn7Y`YENW$-JDg&svcz!P%M>>i-oQt|$t;RG&l1gBAtJ<#*2RV`joi{y8(r)?3Hr$M(Z#uf
z{{D+k&~n(cG2fn_DOcL_OItxfAwT#{?3rDz(!6AmX`nmd+6VV3edKM(34X_AXW((`j
z@BQ@0l5XQk+H{8T!-A4Ni)Nmq_xnF
zw|Es62nqvKIsSD5720|4gRGD%w_>dRZlaSXN>b5MQWz
z2n>>A8e)kfN@CSjjiCz0PIL`*6PjdSHA&~`wjW0u4sX=L{vWb1HQ=A}GjtQFFyky~
zL2t^!k@BpvbC<8py6M`jS`n@Ck*%{}o2`S1DIkYUAU|c1jr<%)&G^twP0PHRrdi^G
zHO)0Oaqfzmq88cIw5K-`4MwtvFJb9aO4U
zm&zEHsO$u#0}A{b)d>oWO+s-uD)F$3UF_p-LnQt~
zu^+-JFtMg7);Jdn6(bW7)kd`iD*lxzCrD3Zc;v83DRYPUt=9Nr!8rJHeSRBv2qS4@
zM=!f+<6~7tiI5c5wDGf+2;=-{wDEpxjGRCjr~0HVN`4zxT2O&DKI_wf#*czKHRgzi
zK12~r8xOWj*if9|5N*34^=d=CgN~QBjen5hoHkzZNuc7(4CzWUfSERa$&%)@@dLIz
z*v3s;1={!;7t7bilYR*7#++x_y6A4#)H>0Hr@v!bj1HVV&mawbrTy0
z0#GP67LyLW5!
zjf6nf<5-W#=EDDr
zDaQq0|8dLg<4O8%xv@e)Npq$g^&YY-A%}|fpK>&>&XulkZ@XV>qAimr_9Wq^I;N;N
z(BV-G_aHjeNA#o?9chbfk1NV@mf;*m4)pt+wTNx~qIT2Yeo>wj^G3_QpdtT?nFa@3
z$_eDL7Fp``X4Rid9x?`Vn_kW%g(fH0b*!KLCVPVY_k^D8_okUPe5-;rTjc7hx=_Vm
zAhM<_Toge=|H3iU&gF3biI*;RDuWu!Ksztj>IQ*}=Ppd1GtM*02u9b5+%sqdlapX2
zizYfWzzA_XQS96bVbdT9tbSbnRjx_$L(%!ljO}!RISWdrW&S~-3%djaC!(M-l+oi
zGsv0fZK6UlTFZu>>#SRsh~8FRbz3Mh`*`+5kldvt?;r1a<~*UvMCbi8b`V_314}_Dp
zVu(QdRAoaI2LUt7`FBmzReNd?+m}VQDPO`&n*Ysod(v}XLDNjs5sih7p(*JI|Bsph
z9AMI2Ko(0Z0Yg;zfmw-IzNc!KV;Q~W1*w5fU)R1G&CV%uQ>#k4mn&&nB?*6c6m7ml
z_-W@!4S$?&@cl}PBE;`2apy5sO%of#_X%;vxk7MnV?`e-?s9`0ONOs9Nc(<{>FXVs
zal*Hvj(_F{b|yC6&=`m*yi7$l=FBe(?C!e3kQM^VXyqc&=3dfx$5@c-ZQ>}2?}yCA&wPd-hk%McRA~RN!Dhf-v}!KJABPyOoWtA2+!E4tU?
zS)hfEds|w_jsvdh90MWHI7^%gSB_#7Q|;RodW3~q*P|5>Vka2oq~VI9_0Dgaw?hA*
z!+rLNUky53zA8I;s+h}e!cqJ!QN>k(2Oglp*WL^Y?yQMav4Y<6K(H{54n!L(Mz94p
zRroUjcp0;f27-As0-SFRfTe47JePKgZIYg&?3$1NSlMc2$((wq<&FwbU(VXmt#1aE
z<>?C$g*>7LbaF`x&5qJ4JDrgrtajj;3{bu5fm}P3QPC2GKN^6Sl~_CQ$Og!hK`=(j
zXk*8-X=g*7FE`}2ddEjTLzJV{3#?CFuRLjpLwlTD+yLWH)N3^4MJ%$!jClP(K;e;h
zNm_y_v`Z`Axnp_Xc(*S|8A>VgDS81rlmR7KW&AI#yOlG(T
z%z-;FXA1vv(S
z_^o1AhWh!4%*xPDnt->$qY=xZbuqItv>ilMdj-RE(RzydrB+2zzwp%xqvUk^d;aa&
z%$!nL;3F_g#t+ycE2eu&r2$xd$b#*DYj(A4DdES?5)q4(A1rCtGtRE!_G;JZXQ?gtnVuV`PrBM{3U6Y>Cj!
zk>|6J3oYIovp6>^=0NH;3$i@~L?a$~Dr$8Z_;k5=3>1GqYn
zJRu0jD8ev{U{=|j$8}`@)(JXX`aPd@rXpHkj#8PQei1v_jnZ1z7F6j%CKY
zV-$Y4rKAy;boJ4yuwJvYS1h>&8>O+jZ3L!hZ-1rJGcF>`#nQr49VKGF)0EFoN9&3S
zHF2h5a*RIkRIcqt|Ho&$ZX)e>+7Ptc!-gl-$?vHDeMS0!8)@%TL8e+Fy3>-be$?0b
z^uIQG1Owf&cXI_Q?CKLep^7d4f+n6kblXv)8<h6?M&)M
zs^jydD(rUKdy;*2WKY)mvN_m*|5524_Yr-dMR(dF5qMOcuE?zY4xL*XcL7^j8n=>3
z(hz%k?#{Pz4Ov*^OVnp*%o)};1&uibBHIRjR)?=qK7s{Wbg(V*jkCAQY0!QUw9q))
z`KC|M9^&&W%9(=hWo=SW&?HvQ(0ARjb|;mr>j={zzSZNM74)$OvdMmAHscfn*)EFn
zqQPm7KB?V4iOElLOxncwTM-;;qfbJ?Cv}zf&)O*ECHS>SeK4W}Nmp|Xo;Us-C*gTl
zt?pR2It(<@yn*UoMk;`i9(jHYVm1bX@o(9YxcxxPanjCx*mDIWZ#29%>sou(YIb8R
zupY!&QDVVh{Nx9KGu75KdvjS&F1^Ka+N&l8E?_IBi|d@?CPUX;a|D60hdKQ`8DP^1S?r6(cp5lLcB~ma;n1ijb@k9tg|-0A(yuQ%;sZyjBsnaqB!%>r@2b
z_rnydwuYtgg#wGz^fHxHEA1yERL|y`qjG335L%W(O8yuryVzGz`D|ryuVDZcMXW^4
z>A)pIjUrs*AyAE7*C7TiDwEd8ICHQG4TZ)TlIxXZq$^Yu02onuCd&uoQgAidcmP9r
zZ4GfCB7cmCBaMhRD7&8z^V%}0MPK@g4AwhtQOzXQN(oKH)lFrRdYHOp4E!5M?S!CG
zS;KdZ$7E^_lVo|{p!9cYV-gR(G~Gp?D<7Bea%4tU5y5cnR=UR
zjwT=UhB!{gVk+Le7`DKU1Ej4L7%W8;?YP`=&8C#aJHy?W5l3D0?e>pAn{NM){ACA{
zUYl0@hg^Kq@Yu%#x0@AuoeM>AbyF$gw-Dc=;0q17xu(p>o5rRB{Ud@1Duob~Fcow=
zXp|0U^auueMU)WZ!xg1&)q2()>MDi6q)KrWGTr`^{QU?2QtaCm{|y)4^f|2k1A2!-
zpEl6un!{CU?bTR1N{+D!@D-Rl*9sg85KR@p0~!XIZs6|v#awLF!X=2*YzWa<_gz}|
zP*1Xhz%`cC#SO3GM>uKM{m<;(N>gNMxWVZ~`Fj-l`5~@t>R{Sp5Oa$(d#{3*Td*Bo
zI4C2g?8=#$-QYI)`u$3Bvmt4&IY#XR3cnYA-$~mL2HWsQZNt+8**ax$f~{3*lLqV9
zFx}BR4f{9?u;U0j(lv8a&f8ygV}14N^1_QsX>~e=_xG%2P&52GXPP|}6KTpM!(uA@
zs702s$vcEG9S5z@@|dvpa<+kJaM0l5O_5)yaa_D9oR|Er6;Lp9+0A72o`oWqJFWN=
zL-*UfTRRWfC1-wNCoNkC_RXxtgdZnzB`&WH{W&=OTj31MGNpZ3
zr9Iw5u15)D`8=#nqvy%OWX?H;YDYIJISF2YJb6(Fc3?NXj!T}ln^rqTbOF}#h}QDO
zfv!!!y;%H0JO**Bn0WIQZ&3lfwb|H?+|RJ66cbwB8bA#(c^?rQE`K8@(7YD^ABsOd
zh!2^k>oP4OwLB~IsNx+Gz@w;X*aM1F=bt$@NR_vtwAM)en3DDO$cPW5pM@01gD%Eq
zD$0VLb#$}WwyO(wgGTi`Ht8b=^wbU3;A9Pq=yn5h^yM-`1Q%S}x-Gqy{eR`B{bdG#%D=78mP}eCiBGA(Hu~|!dW4}2$
zI^7$$;)qKc5r5ak-fr75n}|L~U*X{hkl$j-eVUt9$}0`1y6U-5#RSqIl9A?I14u@n
zgEeO8(mNbQ9Kft+9&Gt?aYDp`92`ZlhO#0YD|!_|Zo<(rc~llDPqeZ912C6>(WJF>
z4RIB#Pc{@IqJSE_LfGkliQ3rivtuWu=u$VVGg2&39?y9^NQvqFj7lo9RKart;DGIp
zO7{lW2b8PTZJCmtn@9Esx^WzQ0vokZpfQ#VhNqjC`Fy1mzQU6?ov4V;*d@Q_jLvDm
zgr&N`r3=5E`0aF`r&LNj_hX5wtJ*>pn*yhek>wt?exkV}%;te1`E(BbDkHyvSok(`6%o0$?$o5
zVy_b0v44ss!((v0E(@!X$>EB+wTC)mXP~Brj+By&^D`X~h({=5r|~>ZqW6RJ<{_+c
z?1=fYZ|ccD)H-cJ+26(z0_t%CM4Q$ZvPAIh!_h}Wp~I!Ky~ug}OURHy%;;I}ELb8f
zC^3Bn0jcm(<4dx}#}#QgQ1wE*>V;5cf1H(RT&D$+YDQns_XaB$!|7h}T;VAXW*wq`U+EB5&!99%v-(cy8*2S?hHqYf2Sqz$vm!ed1
z4vwXbv4oU3Z+={0Y-(KW6Kya%cA|1+?o)ZmQ7gg7(dXhG0R=m_*VT$ahQ5wx@{(iN
z-@CN?qC-D~4&4KuS@l^Ez~V?W58MiDE(}rA(?0Qida}>!&xn0A%YmJKQac@Ih?=AG
zX&}VI_;lLJ91xrzubLmK#F;V=f@nM}nvUF$wYT}|-1Eh`BQqSB
znf%GD6Xy#HklB$}TVoF{2NtuYzFO05g-BvL*|k-H2BUQXQ((|-q;zMybbxY9*Cmfj
zU^{2|2hvqBiwsU#>R)#I!>rW}Y`Mh3N$^js?2VJ3xu@eNKR*9myC7Y2)t)`M=Kf$x
z8FyD18!fU~l?jIiu})or*~92>aGGmoqHdl|jEA@xCAXOGvQ$IvmQXX!6r#FoJ36g^
z#BY5_9BzRWcgP(zb#S>W;fdlXWzZ{Uy?yC$Abs11ldG%HM-=UP4V}Hdd@o-=>+Dn{yh(dqf
z-POs6(BO&Ch$=zDT(Yek%X<+h~2Pp<3I=>{RLzVfxE^}>DeP}t3zTxy~EfC7T
ze$jPZ^X7_tH@!jIk8XOHWe$gfiNjt2Je}j7JMBhA4>11_~qSHa2RsknjI$actJRg5$U??=ZDN?f|5rFuNB8~_m
zqCdgC4vzi`tbp=X@!(w;Dl6*a|%X?f%X{bj(_)xSiV^-?e%2S)pz
zYikSe$eTO+sZD@?Ss85SG2rqkL}KV;4GR_F*WH4uCsoQ}f;ZzBVlr!oEN@v%|7x`9
zsu`yj&m82eK}*}VGkX*ZHYuMQTt3mbF`pRS)QpT{sqkWl!9Q<5V~NrqYw4>OmP40N
z<=GT+sRH-1Krgn5!r(fN$KDeNX%g0SRT_lLlyJ>o0(NK?mn-TRB$EGAak4=ixSKSW
zXVZ-0)w_5y(73HD+dD5&In>*txYxM2+K9Q_B#O9idZCoh_;VVjbq)TWj!O9*u
zTXcE-!B1UU*V{@`?2;Jm%ZjA|!1Nu(_-0qv3c@W@#>_%I@?FLFR}Mx}Yd3@Tdx|u_
z8zeEnIF8z8Sb1OZuXOP_kYEUaL}t_XYzxXn>qHbLc4*D_e-|39R1kVT3xq
z@&<xWriK>I_U{>*w*8bBjR%s4CA#Tq9$@sOVLh`N%5`3ZrEiQp+vv^%8
zjD#uWR#uLr7U|wqM?ZLx><-ED8yJ16jAnX_wDIQZ2qbp81>4qksQOItPjvB_2x(@z
zLP0|esJZ3@v4;)&oI=1{kLvP2hBFn}wG+lGvC|hgyjLr`5zf1%Wy(T6yOw5
zz?zVFhzHOtVf-*%
zho*2I&BAu3nw;b?`HVNhE=PFjX_5AE?Jyk6-r33M1QF>gUi%|WvSi1eOcKF@
zHH1_BAtYbu4Wb(@5x1te%BJQR*=o!I%;OaEe2dA0VUe18+7VEB_z&%Gp`N4HFDfSv
zy!{FsUV(9GIVi6EWR!C4XX#*6J-JtB4vV3m6tjX86!G&?>%>09Q9$aKCDw_Gwa~*t
zH_=R$b{_OP9gtloI5p|tu>Ph#M!PgkeX6YnHPfMj-uKXhYML`ura=~&eq)c|je?pC
z8Zs_y%5^Mbm$Q^;%?_Trfx~uZEBqY~o`2YGNS2nyVLPTRA+uWgrdZ#c%iHKXu?COk
z!GO-j|1RK$-#zKsX89lV%)#3IX`6$sWCd+g`+(S{j#gv4ZLWPK>=DtiOb;D{-Xi_%
zWt?(?fiSa_KwC%3EtK-L?Oj8mPa`nyVfz?-S*NZgiurdB6AZkuc54M+8w9%p?Y0UY
z?*}I-nRw?83XKM!oRf@#G#nbGfw#ly49Z-p*jstnz#=adbVmhuZRd7m8?K;>bQ@iQ
zG=s=X+8W
z@cD*1RE|e(+%v*Mcvb`|n*&+9SZcH&BEq4cOM^BL0}G0bM7=zW25c8WlX`c{sM;xo
z0c7>moaTDx&u+8hgsIbq_HmBH4zBpMSRuIDzBBeR*Jr&juDz8SPqlSGNXVGe%NN}b
zu>rY9#Xr&_qj7YHuDWdpSzxCYU*NTs8!_-VV5WHwws7ekfky|bAM?q_pby_Ev|jh6
z_7uvO-PZM!0`hHdpAU>33atsgPBijdEZputyawQp_XdO%Orl2Q)C
zm6w>Q*ea#JrDyuo4Z2CiRg%#yvIJ(9y3gtbQVG@f>*6s
zSNu}z-NqwFuT8t#TN>%kVvqe>rhtQ-|BoC80sro@g15CV(McZLx+f?33EoSa?xK-r
zhDDZaATUO)u^B6{cUA0i51T`~)%PH((1`unJRiTm-lsx2d>o!uXw7~HPyE#-J&Av?
z5g)G35VF`JciRWoW@Rs&y>QDy68<*dC*e3NAyO|WH>$wPRcC0gr=gFqmBT=EhG0&R
zzFQ6bo=Q5vA~TdH(IeRFlA}<|>#-$Ypzpx;Mc>6{EfFWQ4%n*1ty{UC4X=PzY{b?yRqjLLR}}NpEq#i+UB~*}L-0G(#XnN~r#yU&G~V3#V+E&!
z;9``9oOReX%yZl?9`@W~c^qz03&)M;50}?z-=;h4Z<#}UG7h@KtUJXWG}i&f@!F$)
zAK)s8S`aKV(Rn1sZ=Lzgo}j32ThtUHZfX=l31h2_`Wt_&CNEdaf8=7yf{S3D@~I5N
z66{Y>?7vxTKCK_AS*x{YPgdwT7RpFIeBHVYLo-LSflg8IVIH^^8&-Wo9A!?#%Wdq4
zGFtJrbn&>00Jrx<+7_u&$4qLTJynt0x3ET$EeDuh9IFd2h_P%>SIosOCW4Wj-wj(j
zLwx8A#kt$X$*Z~!YZ&b}K;d-zZ2qMTXDQVLmx@7=Q>98HbjEqzBzI>k>cK85Oq5FV
z0IdW^=BC4zR_#fy=O}8#Ma`3C3&>)ed8{I@*xZ@{%IV5FS)H%Y*L+9WZ9w2vDc*e^9+R8~
zXHyj#F*taR=ZC-hgzjOaG7(1NzvW#}@H7s?QD8ZboeB@I$P)7y{u^v!^pj5T{=2E$
z+-NLW&DwjDnmUlsQ|9+dQ
zi!a_V#Q()2i@MzZZKxbWZHg4$$AhCO%y6g^tPK=nWpSQ4xaTIOF_FFF{B*}y>9l>6
zrop2D*Rm2cGJa1kwwB&d(Go$lVkVm0^dn8Np(z24HEv%eJK0a>n@(<|;QfPOnNB(n
zEG%IB#Qi>Bo7#Qmf2u|c8vj3$o;t}cII9Wc*4a)nQ6>7jN94`15ue|~B9;VF4HXL0=s^E@I
z+=d5p*-#|$RE7TALTyZtC9M3gcQDQnLPv(ZZl=mzn6Em$UX~b!5FeZ>e{rv`iN>Lc
z3Y;cdu3ehVbD$?xff!bEvouemZJvJGS$kO`Hbb~|Adt+Ix4$BM*59>+i3pW4ACeRi
z=ZOMfo_Z*zp(0BBP#(0rFBis&|3@?i!=T1%?(sBUj$EXtW!ZPM_fqrWwi?t-{esau
znHJ66tYJ(w%MTWTZo{Fw@y>6g)f##^6|9Lh5Z5yuAmW
z$JFT2-;7%V<dpwhVY#>@9moF{W}U>yz;+7j;HukqREdzo1FW*><7c|yjrCgRnX=25`3Vk>Ss>!gm
z)_#f<&qcy$M`Ni=?XO5@M9;|8a!ZuM&a3;LA=lY^D)Ktt9XT?FQ)4#{HB%VorT1OtCjWYcb^vAhSaxJkKXz9!iSDSBDn}^Iazi7}z1k`zU9nZ}FI6t)gRNTS5LS7l
zlGo%^nVJfpLsqZ5KvE~)3uI;>M=Mdep9oSdF%zF-6ufT^_|;!AqBcBNpxy7d-EH?-
zt1%`Z=yvxmJ$=jBP1>i}@E`W+so@7<`UW*?!BaX*r=|&ySR#GRox4aK`Ip4sI$Gwx
ziuyN;I;*Nq9>AV6dIRP4gCd-15oq;Pc?3gMED~Faot@rxtoTte2fLW&S->&%`Z5H0
zGljI~TE*;RF{`W6m~_V&%^^~kLY=Vn5A!e~zSF`Mvh++>g=ppq3o^D~I8h0|iZ%gA%5aCv|A5!5v47
zI1xoI4j@Auo`wOh%@q9I20oQ2t%NP|DJ9nCiuGC$YhZ!K*-A10o{KpwS~ue`vf5e^
z;vT{u+y4#h>6-Acy^J`SusBE
zWvqdIiDn%!1COy|<;y-_D^a#ld&N9+j$s$2{D-B?!{0+5)J4(>8|IB#=fE;)BPHA!5{*IF4%?V((@vRpFenF3i`fi^l=ypFLF
z+9M~&)}T=^)gW)jN{&LQ8wJd3jk9|y+omGxFgXo?aSSKw_xQQ4B8^&%%28W2EXlwV%=>S}avE&hKnQL9oXT5li8PWHLl%rY(voeu+t5Jl
z1&X~QWVPe;uBcVPO3okliOkBNg
zgAnRzMLh^8Xhn>>Bk{^jYJqJDcmsc<=m?@&Jq`A6C4D+b>aJ^$4{Xg0=j0MZ6T7Z~
z7i+P`tAk`E2$HfKLb4J=Rtz$Gbo~t_JJKVYCq2{Ml)%HS!A%LC{;y#UMPX?I)Y{u4
zM@1%g;x350Ap$me8zOHiaprf|NPko}9!scsl2oYL>}VuB>h;>sJ9HJy5AwIP@?$MI
zip-A2fwo8{wCLA?9gU$RenpA<`!Q3wn}Kg()xv$AnpAHq)qB6W`eHos_BGy7aAOc$
zjM9*^8}^rB+2E%0CMlo0kFyDQ{=UZk8nEcSXIbVDhm3%1@U^Pw&e*4vECWnk>VO6&hYN22kI23cf!WUaO7>?JX$88b&NA63h
z3Z9e6#@1%}B4HoFj)BuMoX)(D&DcC^HYHtay3aYBE@Qxga{T0*^)rnGG;41wXF;=`
zJX7s3Q1htwezEOuPVVV}XOQl$2+w;6B7l2}RUW%=2LlyOPq>134<)|JBUW@g`p|~&
zZt~!tKDJRzU))QvkITn4=d6LVx8m$(ajF+`bjQmL_`xbN*+&ujScJe?X02Ucu%W}k
zCNO&}=TvhvPDcAGqlG`KWtwZwXGI7^aY(It%D{3K<|DNN#JNi1=-de35CtE^)>@1d
z3P&^hQ6e>Rm=IO%uT`DwRyCegHP=kk8kNsG!iPm*!XJ6p87hlBj}x1uh(FA~xR*N>
zV`~wE?K2#(!}#(ifvPOT7raQ#YNTh#cvD*aa`0$&E7_wBUGG_
z5hq{ed-xU;$bFOZq4mo1RL`rzHVhwe%y7S40{v#eBE1btDQOG4?UgwWmtKh%^e~T%_
z>pxgS6!78(5IKV%EHF@QRpSm+=JhLu&*7Y)A&%qI1-2&W$W9*|_Me%qekDmA_CG8#
z$Izs#zN39$P#HLO(~)_z01|fQbeZ0nf&JpVp>@J+pTtvbqEh%s^n8sgl=?nfM?tB7
zy;7w8>|*i1M7j}kJ-Wg1inP5!3aruv76wxo
z(E^{(m6xrIQu0sN*ydGPxa
zpInGV({?_FBaM2RlDzl5>K0gEMkB~dyVg`zic_#f+*P>;rdkxQS`?~0luDegEN(L_
zwBWxUQMlQ)!usK8Oke`%gf_a{gtfvv*I%qdE4%hMFt3tQ!#Qv=PadY|1P&B
zjf#-?
z8>^Vd`Z2-ibHiwyg7@%)z3LVMt3%(5b??0e0^IDGz5rK_0M}SJB)_gbk-_avd^iHR
zLn}>zx^qJE4wq{r`dY<$$RcY}WE491Q;N!mO$>2|3rlMW0L-YO?*-
zm<>Q_gl=pcSUBU%S_bEH4=&`s+V_Y~bEf?#&p~wZj%z&fn_^w5Sa$}oP_0<&
zRD^t|2z$b5kOq#XJJ)!vxI7M1)xuN-PCuThU7e;HYU?Q2iq%uqREOx&U0;iA=3tlM
z5H569afgf?ks3L*f*KD~q6R~x1kpO0e}sbO
zdLRTB^mUVimnrxP4_s@XV%~#(MVE*6y0Q&+QN=&n!-svO6|*B1w1)>madLp4S0gdtpA^+;MW4+vVj;b>t|d^`co9)Q4gU$cfTsI
z$pXb>3Rq_n-``u+ZAL4f^F2P4bRaB&B{>=d1my$US3xrg%cm;-em&z;!qXJ9ZvYc2
z=$nsgZec$F+Ubh+*;lS1{?8QIh0{OqIYar}>G6R}phb$cnllxAwF~C<0$W?U$FARC
zV8*wKaX55SJ3ODK6fu{Aj){~Pb)B!Ey*v;c$!>@sDTd1p%5|m*O7l~@t0yYQOUFKh
z`0|vHn{P~1%r`vDM%}DXmUtG337-frdEzoYYYnL`RJuF-bQDD<)-wj67KrAm{3*|%
z?j~(INeRz&2?K~5@$6JHHg)qt#}m`N(4l8c5IPE+qu*V_Aw$Q{j!_@-vadavaf*Zo+xNP9e09bp4sK~>MWNLAgRdZogfS!DJ*Sy13FhwjLn
zHADdub0p(SFQ_Og-nxhP9Ps-W*r)z#1h3wN@bng_uJh!fTFqmY)*G0>13t2(Z3B8^
z+ZXvpJwQpPT2he^GTSf3QP3Du@&*(U%fEgpsv2`YA@MPj#Mi8XBwa#d;HgX3&>CprjBjYN0uSd!uSm
zDvW+oMss-we&lYHDZYy=2?tC57?!i7RTPsGS7RLs5x+<>RWlG=jOoa55mpDJ=FPNb
zf__~BPq2hf+~!QTzQOY`6h0&qBX4*$6U_~1Nv
zWdMFq9(;@kUsPsneB~XUjq72ibaTxwYS_7A*nn%Cb3a{!a2S<8+G!89rq304B}R_i
zM(yKO*l{acG|kTH|Ip)2m-%AKIF1>)ofPk!`BKJ1ju&ry-qX;y*93MqZ;FJp2TV#pY7-~!gU8mrL2ZmTk53vqCJ4xj*;yt1`6I`6|2cO`a0NxZDON8Ix
zC6MMTQkg~a=2#g0GR`$CedVs`hkk+eH>xBo9^Nome=EQcj_-
zQjB|o7_sUWoKmBD4Q7^cwc=H{c$i^`@)GU#T8kkC+O^+UK)dWEx!UD>Z_`RwvrTOk
z1vR_$eAR5Z%CoY~IFQJ~V;3)dge>c6G?jC9Az_a63)78*4)=taZTS}zX2p3b%quF)
zX%<;iibXbR&x9c8C~zW4EM8UYK?d6_`Z5V|DegmN5m@fsk!|&w5_W#->MVZw0F&$Uju*k^pvw{T`%uHB#EBfG-zFR1f3<3wkT5x_9ZU3Xg|(KCy5su$BocCekJ
zb?i3IziyD2f&LRbN7OK7{X|@#RZzs=KI%!t<8nk?sL6bbB?>P89Kv~%nT{<|%=?0v
z=#Ap#4UfaC`gEhkR~PxTC`BK3&}3a`F^tIeNYEu8z&AI?V2%2^P#ioGgvP9dr3$^i
zWr_9)s=i;3-J=}ML07@_haod;k>!L5L#F2PNnGxjwOU`S$gQ6HHu{os98AnI{lfX4
z!DM}@Vn6C(!*yi^+uG?SW(BZl#{!uYV!?~DT;&nuu%}G(&^eq(YYTYr&42X_yF3oV
z7I-cDGs>Ix+00f`(0d1C9hXW}s7$N8u2gH*cj^ePRB&@HnC^@jlD>_{qWFabco
z78Pwgz>i>jdb)ys{=|(MkgB`{65yl@CTni%${9~H9{j5(>|*p_Mt>MUmJRqMKLQZt
zDA&q{S~;qt^NQL>F;gYf3?i2Xn3t7saDBxrQT|OC93McD)vOXHd0hebm^LZbJo7n*W%%*Bre+=)I|a=Ds-Qt`Q7dB6~>p$E)rSRqiV8z_6n8
zV^oP?ljY;T)m)kP^|Ai%m?;742$^EOH>Pgw*#d
zXsicnh%IsO0Yx39)LVDt9L>bCIwjcKMN+K%n#+Nd*GX~tO^qjuVPATBD-MU+6^Ci#d_GYsc{e_C0j5qYl}_&gE6P%<
ztbA@St1r(d>x({=^6dbNn2=&X&d#44_Xv#-nuXdK9paSlN0
z18?kt1y*7}tr&V_Xl}hx2B??ZopYsLCFBCK7Vn*xGsyO2lZM^)i
zG~JhqFeQK>yUG4piy87AMIK?1nLJmPq9MUlXq36X-!^m%O?T`kF{wkTi!61IWKN%}
z3mf;VvvQ2v2;(*+vbE92#iJ6~y+Jrtw_;8_``e;Wh!=DCK1X`zIrtNqvpMd#bh)vV
z7UAQbxPVEzXn(RW<9~|@ni&q35*o&^CV*uR4SiWAXFO-p&QINdMXRvLMB6-8=0F&?
zq%zSaQ{IHhWm{y9ywO!QuH?ZYRy+_jw0g4_XmcneloLQISq=ibYUFwTYht#Am$Prm
z_Z)g(_LkQ-IG#MYHRLG!!Aw!s!FOY+tb-n*L&x*jgicFOWt(=cH^YQ7>@*B%J)a6K
z>~U((PGirVVakr()7|3tg;;2MvHdsn`08j=QTu#^SbX{pDLZN)T*kZ0G_}PtSyeVv
zv9V}0WfMEX%b>>%9H_dg1tZ*W)R0D5
z6Fg*7@sJ`oe$60Otfk^NPVefjlF0P~P>g74-=UZa-}A->p(H-@hc~qhNaGqodtDoB
z$ZA?$$G8_WH~Dm!fi$5#OH~kQqhrwq?Ql$*qs^GZ`Xg{5$r$|L3Ap6Ou{&dHf0FZ)
z33#4~h+vgPcX4JicgR9Jb|mY6pezGrF+gpm%@2ep0IL&NrbmzI1i00Jf4WA%80bY0
zFo=NxM`n@sVNzG)g-A>v>?brm*C>X$fm%t9aOo^5)zxmt3cZI{8pxB(VkBgR^Nz8C
z;>0m0ie0LLTYQUGTmKGC2){NPfeFrpFk-X6WoO@ZD^G9Mmna%Y3hn
zDohP0|Fb6_%HU-nY@t;&5!Np}WbGsD3^2sGSBV;EaEwB+M-DNy1%KLf6YVJAca~|6j0Ci*o
z485qxSh2$Zd0F^Ha03dyN6XnQIzbCw>_5AyBJ7MMEj-*1peGb%1Ne18{CxyJic-3M
zG%LAWD*P3WwxI}3i&IXNQRDnTPI1jCRWqnJxtOrIEGZU~kNGak19{N$zRr%=kOotr
z2j7kzKFMnYT_nuk%DquT7+vH^+o@3<%@d574;=+V_;Qfh$W%del_e4vVeFXmEF8X<
zI((y3gB@JR2Bm{X4=>-X!qjM-_TACMnn2%F!YYF9j
zs)%#|nJ-g?EXcln=!*0oFqD+^M&uv0(VMW&aFZ_7mjD5N
z!0sss7bybb1#xPlbDTBUzs2>O-0<0Yg4-ZHzVl#;hGsU$0MB#<9Om*P;2^M=tfQsE
zj;qC!?4{^t8Rs|T%eB!b<5f@M{Wy=X3j+Ta{-(l>)+T&=P6fYD-XM+2aSEhwYxB^m
z4ZN?xLb;h~uTutBx)na96|xb{xxLXyfC8WR;0Nn%sMF@oI8(I>+FPPs<)=2gryUo>DJ(5wRt2e~%I4~WXRpsy$+DvX1Io!X*
zxY4l#_;I)>eB_g9U$o23%*GWS4VpAovgOWN+*3z-u}oS*?G070Q-l7+BeJHdr|DzN
zbQtcWn=|g>$WaRWz$ifb1pEDE$Gc{jwYrmx6AR@)U1C8glhTA9+seonbO6R`k-$Th
z*zlCk&P!p^p6*g2@%5WzC&zr6UVjq8rX5e@bL_4W<%B+*;pc>eAfqPawbi`@)L`U(o*{+HQ%?+?1P^^
z?HXiH%YN((V=io^pBV}~UXSS<0A}EOW_#LK-y4&O#?^94WM5<>mfH{P&}wn`b*(`P
z@cFCo!Kh^;tJQZ*t%)<89D?*QacNETwa8QEJqB2#8^!JrH;MG8c*P*0DO;;v>8u^jU`FE8-
z3iLS@O*ZT^yT+#HZbzF&8NN+GGIb#CYRp~9A&&vy4JmUm*s(Vt=!v~Q`&KZRAT+6*
z64epN1pJ^fXacxJ!CD2pX&cOc!Mg>_@J}Y2O)tSn5J{55{W}4#7Ojffw?nOR<`jL{
z@Ch{Qt$!9(vZ$xkUr%yO)=09oO5$bGNu!FfqKLb>YSRWbjbwu9)IXE#h*-bsyJHwCOcaFtHXR22*Av
zrFqXSNFsx1X4{6lK^2?H!VoG(lw>fZZdww_JD86v73JOIvMH+YoJVEsey||
zvdY=Sn0eukRE4Y8bw-P8yP(BIWZEO6Rw#~ts2L|g)Tz}Ocx**ha5t0BfFqS18h(_M
z*EgJ-u-X=^Yyc_)6L>5XqJov%eZ-;k7x7Nyi5GhN`718GO1h==Ln@RQ}y(s&=
zfZ4XKrZO0l7HQ%P!%k&oNQH^T{3ay5hQuCB%RCxW4tQry02RKgH2A^NsAm`~9vOu{?t)pyY39)Y9d1x1^=MPG52
z%u0n%d%+EEr|4xj!EG2G4ur|F<{81iSY)$00EKaYAcBNuI-3Kx{!F8el;)Aa)m|{F
zgSVFYNYtUe#{^t517)R!UCige1g9-v+VFhK#7+(XGS3FyXhHf0UNjJ!I%^&Pyu?CL
zgm6t>XW1go2wu8yqW*{Fw%A&3GU8osy<$s#8WBsp8XE-1Kr9CBFs0qWrA6^Y*&ktl
ze9E4uXJ+igYiU<}T`tjr)9ghpMNPQO4r-}x8k|_t0oCz|x}}LMVOhY~t@x{fI088hT{@w*xW$Y#`
zpUwr(kuHM1MeQp28uVcb+|vSmO)a0QfpD)f6v>xKM=0{T=X}zc(XC8DD=kR3_(2Wz
zUGLFW|5BDB-EuAb`fG882C$(=YJh<7M=0MLUA|n=^go5FnJF@WXcl{yR5bgHJD$%o
z?Ce451s22^(jn2t$ee#^eYT!myn5!rzzt-3q_W+}fSRM%qaV0B$qo*7Z;M`yJP$k7
zMz42)=*qIa11q%Py}Avt)KqjLkFpA_KMIsTMV=qMUvcf|z98_RuK8nofPLy%tfh^)
zUXUPDxyrQaX}2YCp87B7q-m$>i~>2p1&8=@fN>a63#{Q^{H!ozO0=C`b`v!=*eBRV
z<^@QOG4A402|meZQz7`g
z+;v-Xs(x{HL)3b**2>=8gi7g3nub?b%?nj*gc{}rVptX>-t5MmXrrwTiMB-M$a@AQ
zm5Vl^tw4)SUw3KDOfssQN*EfeyMCH?cI0nbLaC^+o#3q7g_^Ts{7VhJ?|#*|1_#Q~5^X>Sez#HxUl?eNj1?GnC7Yop
zZ9Yx7?5qjv&HmcFS;$tX4W{*pHOY^d8hW7->lO%ea$N3(FL#t?B+GTQHN805LXVPeq)XV=$nZm
z!S6AF12#crm3L`J_$5L2l2WuQLyAaY5>lC=513KM$qc6y6bnD$DJZdeCBx?m9L5Td
z_LW;h6sL6Lboh=Ke!3yNT)h3_{D8__t^<
zn<+K?sXL+Fx2#<^l`skoI16QJX5QT{JjkRztMrh7=+Ndmsu*4B1XlX2Q
zaoq~RKjYMY1`tNGeWkwehE_swIlNH|`+xs9G)N8jNPdRyDkwO_8b+|c6LIRgC&L%t2Wjz0Yd>gn_&pnh968|;ONK`i0139|dcC`yQ4Ax(yTYf=1=L&dc?(&#
zwe+mj#pvbOO5iI5a)u)3VF_IFVuI$H2)q>wW#KpP6&WJ4ncKutx;22R4<)j>MV>Fx
zKz1BkN|@DY{ek%S2B$28YJZTo7ZCkES)$bi(&T{2tj8`o|YeclXBhv3Kt(o(4|x>oDzk2ECun0RkjM}JnsqYf~W_9(Z_%Ft#lISrw?z|p!|
z+zQeb^t4jcQ^Dz?-uQ<`S;PocZW2o|#AlokM%j*YS*PNn=xPp$IxTD?qx?|`l(LNS
zi!R%vTA9b8SbFiS6TtxMo8*5jmq{^iU4&(Eal?#D0|8P)x4ctB`6$w;5b_>%D}6~|
zIJ6aC>oI}Y^2~;F+KXcjp}-vEs;fFRjp{5Y
z!a7~&r^%^*r_sHJY^krU{yjflYUmZF`f~&?{GRq&EQKcryvA#C
zwEqsx(ceKf;6vU^qz83v^!Iqx@1cq-giZJb50~%X7%)GGyDna}4vRI4`#%PkS%Zv%
z$8)JH8GexE@OwAKx*GaWNkQ5bT~n9As#y$Hp2X$o7%&wUT@qXwAJufc24yr18WmAx
z6L4WG0YTr!FSlMlA!4bonVHJS*v&;6oYib9rJ3Gvkb2HQOoUM3ujh$%BD1G3NLqfW
zp{s62Igm3zmQ?^tFJ0q=uhc!XJ|v>YVyV6_#O_oUTuvATUuxkVHKtPLyf&kOT`w#M
zE&&)x6U_R*N)zF7MMxL~n*}3Hc8V?w>%0Sp
zgUYl7%aIPJNXsCJ#fI0sOhnA+&-R2JZQh9lRV
zvXMFeRQ_-~cH;St{ZB_5rj
z&^J9OmeyU7}lSiZ#ag|K8A4BQ87qiUQ02u##*x7$pOL|z;!g&4!J?*xl9!ZP(3wO}2j
z*I;*|5NH}{HcbcgzwYaPq$^izjJWEDvCZo9)(rGVatVI7MyZqI<13O{R+&D4Asb_9TTQ1ERz;F%Z>
zoXraf`SUJ5A*EZW(c&%KSVP)*2H5JFEZB=JlHqq3A%E~rwV=j-~
zB?;8^CK4aD4Cb%K6Ji}peJOo6QD&4nIHSz3xAxTL$8N=Q%ZsJm@6d*Q%@Sy&>5ECM
zPAK-ru#Q(vIeQ;2r+62`?dgo}8{IbB+1Jif;f(VNXHXB!6^SU^9GT|9%%QPUktu$d*0C8(*CVV**|Jm1cL-u_O-
zdB=zIzj)rhqeLR<-OB8G!%UuEe|>~~em%HG`^=6$`xe8#U9hh@4kGI_4N#E7oQ_kS
zX6@mQhY&VQh?upyj@2a=PQr)m9Yu-;L%TQzCl?&7b4`VvBtMAM{L0S3sI#OEZykxYG}l}PAd8SmWt<0&
zBN>b03k49V;lobNHPif9#m5tiMPSY!!(6_{E}XFS#OGjMf)RF13OaUnrQB_~r(VE*K+gPI@H9j}Cc26)*-@EAU{9
z=+v+sGcu%8_dw1xz%3~2#4nbZxUN8&D)^INg30G{PJV8}jXg1p~~xeqn)(^XwX^8U3{56SYZLOpo#nyQIH^
zunY_^VAurS8+`~H>>GO8U|G6An>+Nhxi&5|^q_v3O}z3ls;Z8*ap(~_QT<-FdR*TR
zOImf@+QUaa&J}=Y7fHP50|rA`9a+1V8}J_F=8kIja-+(ObIg-g;8$2XhL^Iz)ZGeM
zy;{XEhlZVJ4iyiC!!p&4PvwY>qeMIj1Q+LVjaIy(Uy6BI-86}{3>zUW08qyH^bvEN
zOiw4ZFoF{9XE4aXgTzlKlJ1oe!rSKPmr4hAi@s;0e~Agjm!|jP&<`-aVC3thDpG?H
zWWg{Izthyp7x8pP?!{MIzKBFmU*
zzMYvBHDQUMEW}s5<8NeCR+-6hJyxy{GxN<)#UhsUG&Fz)sLadQQShnKhC?%7QtYcr^}d!n*-8Lw;$w6
z4{nI8!|-+#nrE#VWi1%$)sMB&AL3O%h{=91Ci|f_x&{@jQOoh|EMzi{LlM6rv_>fn
zc(8z>*jzO%QA@B!`O+E=AH(IZS`2XKZY)e)dXdbM5;lzv)W<@Al*glC}W
z1)iFm3a84uK-MW)qx8DwXdBIkQrtE#?hB(h9~@1u!h`S8Hr0mNr(jg)Otl?ZQFWP`
z9?+}(YSf(uk%f2WR{B|9r4yvm&rs=S>shH`>Q)-gsT4*HYPuq?(oT+n(G{q4#d=n1
zn7Wmwdj&OZ%dPbDyh{Hjm41#&KVQ#E4O6$$ZF4F`cM58{GOyA;Qt3)mx^g`$HB8+~
z`NCs=n`Uz>U6ohq%^0z3qpMKqs`aeYFm)^4H>c8;+)5GYa=iD?Qt20{)I_mA^j^c%
zt@LGd0>7qBxs^%)4s@CMn9%wIaU~zz?y<`lrnb_KV_9Ps9kc|$2zrux>~0Wt>Z`xNTqp018Mv3B>l0D1FnF{Y}iM;nCthkm5hMcFCw>MxO;@q;Ih}g(X&ObN3
zVhi8g$qxSBK+60H(RF>Eseilzn;rd-HM(}QX(}_`9!{-$@!hsp@O<-F<>|D)X56$j
zCJO*r>lGZjum&#w;fcT&9#!Z5FIp|?v~z;YDW#_r@v%x}@!>-mr|X|0I2+z$U-;Pb
z8#?H-g$*jyqa)$Y%U$$&8jiKarY)|)GBB_}r)S%FU2p=LSTGKR-cN3k?6XwkPBCD$W96&1ER?a>2i^~L*Tz!)xU>$D2c)mz`VcBg^xjnR
zcKk{6BOP&F8I5<`m{vHpN?5Brdlkg^l18o*hO?^Daa_!}3^ZvR=fo`5*#V7F2aG1c
zz#JRy%R1|kbJxiUFm#Y;6S(8_AzN>rRy_~0Lz;R$0Y<6ag{Kex2B|Z>F*bk`XB$9m
zu9;~}GcUw1AIdFE!&0AVW{PQ8sHXA2%%c6KsbnRx@nlWo6YXZ|oU=kF+G1DM%viY=
zBcIr=eUte~;q|#ZR7mvN6ja+5wNX6tqBeky}|0^^UL-{dC0y0H5vm8!x&F;|D(9r4Lv
zg?sobgl+D8n~XKUYI7hoblV(naPZ0%W5wct7!qiuISzvu=&^aqBnol4C&(o=^fIGN
z*Z;@do4`j|B=6(lcm)qkJW#{~6b}SZJXk?M5gg5`xVVbP5R2wo5`j3N+}ok3BF;(>R(-xyrcRf!k;o~Nq&z2=>OyX^P>=c9Sw>8`G>uCA`G
zuCDI4r;HD@N0p~%TwA>PJEtd?qWK~~F^z^IK%2+oTCYScm;wE3aeHx~U6#eP++B!7
z2@IW2%@pj|7q0N6puI(>^Ym(B@+%MxgpL^fQ%nUDS%C+O9=>L@_VB0Jti?G<1dZ+v
z;SSgy(DM=!w+-uu_Z}yS#3EXV03sO-TiAL$!(lh6MD3<@pO-Gv8m>bPO((Kh%@Bx%
zyP4vz(6c}Z@QQ!BfHd0To10!6Oad#Mo5qk0-htdHs60q)bU(!Qahiq?bOlr+P|N#i
z@37*myXQ&~s_;%rA58f=i@7scCOxoC5-|fmziq>9w(a0W4_FR;TcR9dbYt`R*+FPw
z(++5_vl1DFPY>D+=VrB`=ck74hH#)d7Laxq>BE_0QV4zi!1{J2?cA}b9@^YrI1WRH
zK&awA19HwdvYKM!Ou0s0^H^Pjfz%zocTB?vY;GG~?8iJ^z%h=#=L80;z&RPeoBFb8
zLzx5L$>_Z`i=yuIWuo;T_(!aqt}G_;RY1ZchJ{FQ_W&(^>xx?JL83Rk$5Qwa+8-Og
zS%CNv`K{B<%RD~)I=&@7bzY0UhgE70$t<_PoZwC55poZsD5ssrg1LGHcY78dq}jLF
zY-{b(CCbG-WbnhgD2vb)M6BD3Meb93#WeBGO#@BrjV8hzEUC}OG_~cP0Ra>=n3myq
z5V7$5c#sd@2NmMT#cb-^exAWwLS`RiW5~A-QZg(`LE5?YdXLE`U)>UuYaA?vMkz-TyePLT#%pp?F>J6
zOD+4jpZi`Qw@`DZ___ZK
zY<`y#DCR~`bRo>621RFusjw)F7^_7A{dkR2;GRd4RE}%a6Ycz)5%OQ{9wW-HZQ_Y?
zg|lQ-+k%DCUlgo)j?$6!=_PJ>%z{9RstD3qy
z;??J1SLg|h^^ykAjwh#9{*MKteVVO-L
z^_&+jv%-}5sw>LWnKJE78HB`0J-x$aJ~CzIv5eeOhULhWfX
zWv)k=rqe4)SqD=B`~6blrErN;FIEl=V~M>vc2+MeG@$o{K`$|&djOPhWZd=3S%20&
z?p2JB%b}2TxSZR@GuV1_OaUQ#`v7(q*V^v$t%dG-WUe%s9htc~GiPchHB5uaY$obW
zm|3ow4an3LQo7H3%!F&Jz`aN_{SCWxpM}ii{No;{nX6G!9sKD&GnfgDgiA3sv)Pxo
z5j1Hc0tfYTx6X+)`@a4Md6!QU9`gg5=x_Pgr%(+F)%u0Zq8U~QIQT9M5Fo1sXYoJ2
zgxU;a1s87Z)CK7hUl#Vd6}0k{k+mIL);VWCD2SS6MEk0!*iR1Xoc;aepw8)xa{ACX4Raf3+;KYRdg9)RfEG>Goj5(;cTEP1O{C^_2Np)Rg5Q07Xrad&13E
z9%f^Q*Tfuyn(>HKYL7t`SPD^-GcCA)y5B@2rBzaUWl
zfT2~3^lq9CA_C`AitGtOnG|?n2QBej5pui2HY~i$d_jsvp<(Gh?_8+*r+!By^9&1<
zb*a5Tk_2jnfqF=xlt&6R-9o7^r-5~xiDCUaZZl3iz`98+&utY
zfaLX#j0v*7mXT4euX#qsmfwOTqde@$IPP4Gj8|E^KQey)OK@cDET&P*BjbtL!sxh>
zF_EJV+S(it{6f4H5QX5#c#Vnaj`QWw=MgcIvhJFfss201jEqxpCvejYSGiii_*31nSI_d!-AI(iW9~hOYN8uOL3WsXhlAYCLe9r1zo@Vxs!gqQOR6n-^
z`9YlgG9>$huj>X_
z;K%!jIt51YA%1eO+HQVwu-Yv`)sBca7%Igjr+y-R%`@gZe+^DV#{BIgFy`N7?f#fQ
z5^4TyI7DQ-yok|r?RGI^
z{;xQ#YlcpGVC{L~<3AhHIZsxT-W-K|m!BN$oE!Y)VCP(lWM3vmq?+*!kX+rft+YmZ
zXByTw()L*0b4`;l%F{jk0tFP-Ii`@>y@`1Mq7erayDPvTixoNsCp{i1A6DcRca-+!
z=$w7lc#I3jlj?R}F7@a7vNf_r*;+{BA`ov1`Ua~#+S``1j_N_^A#6YaVu(U)8HVt#
z=WNTJrq2lj*drA76JLJHF{05Q1;rH%U()DCx%`LrMtwrzA2;w`Kp{5!aOP>Tdsw-I
z7-HLv@q@bUwx{Pz2aOdxrwC|OX8(p2pe1xO&M$O0YdcbFJ0e7#9C)b|uOI`$K`1m3
z6xdS>*@+Te*!VivgpGsvmw5iDcz*T!R9mU{idG|+%$RMS_2#OUSHj?3P1xXUVl=nt
z+<1{Ed!@FtIU{kY&Ei&Sf1J^pT%*-k^q2VPOVM@JM0*TD(#{EfR<*ZprDxT&!3fxr
zo+%MF9jm2wUSBC;)1(DHn;u3%VbCzeFds&y45hL}X{*M;=t0RfEn0Ai*H|`%EHj3@
zN(uU)u9nC#kR*Pbu5b(%`dctR))ui0fL72KA$k#^(OfC0EF`x=vMe0>Ts?v{W!=kd
zl6I?`mEY#}pYXgt``>{vSSK|tI7Mdmr-sR6Dx#R9cM*Wq-L+9PVg}mQqa%PIas=kU
zFF~F?p$3Rbta(wWy(y%eC|khF5CZr|bJ=b}y7gv-eP7IBXz4N`tza~k3Fd-h@tria
zE2ck$Y!GUT`_&g0{^@x=e%Lcn9X!`)Sl+%kRd0_r4#}{jWM~n%*g{1{5jD>Ydqs-0
z2s5-u5?8ep^Qsn+@>`Vd-95U;%`UhSam>hlmUQCZc+X{24%dxjq2s=Mg8-8&dMJPwsep5J?78R34iR9L=k5qtWi3;*
zy&oAe%tiy&xZK-_Y&MkAK=3ykE?WW=R#+XD;ARD?2M7ZY+4S1A(V
zF_j2$C0A>dk{gF=a77mm9u$?!$JU3DlWFIEu^8%sU~mdWI`a22Zwv;4rG`vHy8aJ@1(Q){RClp_|s)kjj)-!b7{pJ1|jDLoHsfR|=Pc
z-*rI1p^G70oThTgx??{@-N?zx=7BTZ0{i?lkp`B%{sNd&s%Z!@EL9BK7!0;AE73Jn
zFOlvvV>H;K_drSjJd(ihDePk3bB9yEfBTRX(oe+|{$0ZT{s9*{?h+m>HYP(9gm&%U
z%snXTtEy^pgw(%i+W%MK+fqxk9>k)esx#Bt6Ute#v(y$glR%Zt(rFD}(SBG*lf}L!
z2mloj;1R}CSl;#e^pMD3yI7iSdjcJU3obml4~xDQhx8+czym=EL?nAZQ6fAFOr0_i
zlJu1FdpV~2`aOSnXZxUCz~BvxBfSItX=I42{G6
zF`J-0V<~MsfpL@!#p|#G42ey+*s0Wmk@&F6$W?3C6<@c6!|(LN&+sme8HUACZLR_P
zlN~~7=TB!E^(sRyI&1#+ku;)yIfW$c>}G*0oOU;0ITYAes#k~tAL8>QApCu$FZh!N
z1tZl^nfdn7@-s~R70#1{(0!!`@mlFl-&9)~*Z{ZtN-MOwoBh%^9LwtZ94t-4H3{97
z@;4N4qyf|g!y(|7+o#E@uHv#K(5?ACs745EQtUcte;H)eQvhuY
ziq91CA`cSNzW-63&oy^wPA)#G^Kv_>6X4=TkSWRFsV7aMtTMel(bKBegXeviJA=J!m&)F=F
zq5g@Q@grEyU?1;c7rO?%Z|UqV!eH*(;SPXNxI%a@s9a((TKrU7g#@imt88QdKJytV
zgRa@Zt3_v)5U%klVG*tB`lSlrc#dha*sM?qGMTBum--)tPo42ZDDt8fnP-b+6V*t8
zIM<;XkBkk2LHlh}{F*=IB_*?fiu&+8ZXy=PFTLhHdB5
zS5NxFzT`(3k%q>|m9%N6(GE+?C^P`Mud-cfXPKX?qO9LiHQ&VS4k=F6VX{uL8i20?
zxcw$(1B)
zKst;d{u#m*`iN)H4|4r!h7dno-7dc_uvt2&;0JkB>$Y|7>D4I%tC~!FSIODjX4z$=
z6;)1tL1FB2qev^qxp7Iz`pOFP$L%E>8rX_D%F~jNAtE=aqEa(N=bdVY6i=}x(9xAm
zy-C#jO4OLMJf>^UMn-(L8%nr4VV}1Wl>|%=$8GbeH!R9liD?xdqnOnyI2vYKYCr($
zkBo-9-%@#Kt&`N%7MNS8egnV6BEhXFh#~0mPXYvW#q8;#q0OuZ#wd0-_+4`sb_TL=
z*V`=NVsq1`9AgTF1{#-fg|jmaD45^it+N&1;r8)jsa@0remDip0J6%*u!Rp{EO7sY
z9NBm<@i*Q#;cW~KZlK_S%{8r>dI?9Nnj1#%1Ol7oRN|Tfz45MD9f8=NeHT~HtdYZ=
zYdk|XpCkEvRmf!ZP|LkoRv*X^dMjRl=*p3lb~>3tID_?wx;wYVZf%d_Fq_~1u}WRj
zR+UIPm`OLAq)PYKwXnC@MUhiE4Gn=F89{r77ed{iYl1(kRuT!HaI!c0Vr1kh#OP3b
zGn)y)CmUc8d_O-M?6xawzM^pAZwT`VDMQ+5RvDhnx~wwHDxN}Hsaitb@)EmfTJPqITxtSb-aE6budKdlVn>~C-m
zCeEk1$_36B73T$ca9){%b8-l0JA?CI*a>aK7OvoYNpWtI2j?C+IQxfit~gfPemij%
z8l1}%=OP$@m~dAbPI+yA?WJhjznmOw`#lEdk;FM4y~wt|tT->qgL7OC&Rat`FETj4
z!)9tD{8obV6~(!I9-MpU;5;mZ^I(JXZsOd=;CxkazHnlE+uy`qRalmqCI#Ex#^5}f
zI2obDwl7zlm*&BFT@KFaA)L#P(LVa|XW+cZ;H+1iJLbXJD+lM05Y9Uc&U=Y-dxP^e
z#hE=JzU}WUjkf)pbg=Cg7@Wru=L^P;cwKS+!{97jIQ)JiPdXG|rB5Nng9LVP-VUUV
z6HM_pwD>`JNIEiyq%%S!eSfsFZvIcuZRm-&6y4{4))pF#10kF-sLBO$Wq-oZ{7A!}`hIWtz3d&KvRx4u(&l!Ct_Tkqu+r
zFSD@R7NYAueYKI)@0Ii$hnac=8C~{72BK{^1`8UOJw98?WxD``U4nqo_LaQL_6=tb
zz!6?g0|v|A^299CzecOv-c(sSZdSqAy_nIg8EgNfv|!N90)i?1w
zT>w7gn)&p=Y3N?}c9pOzTk>0mpF
z44)X+$S1KS>uwv@$Y0(JG&1H`OedXZ*|^y<#pi3>-JE#s;xJ&G!zia3Qac7$YPT1`
zAK2}DoWB?{p5&ts!4#}b2{*)6B5S5ZO{IG#Xh%oaM9uTVgOqob1yjr6yVc`_HO=a<
z^}b?|@{{2g@RBe0le-6!Pe*bfCWfnm+y%i$+6Xf3Q`??cvA>YhxM7+NQrvqW0+#l^
zRyc!3qu~gn9l)hpk@;0F0@rfD(w3!cEY_ZS${_d^gHMp>tUS3QAVx*t3S;uHDCCC>s)j&&Eu+fv8Mh(*wfbr{At#3E
z9X~nPU(fr=!Tx#}$$qsX;`?hqG2kSG=|Fv5Ne1Prsb@G3NBXND`o_KT8f5qZW}o*D
z_LnR3RLlK!7CSt?zYgFi@%!s$8Z^-Wvul``?s&dD`dlFu;@&rU8+KkD(_d|0_xcO#
z;lb!2ST>=xKjJiTHSQXyN^v`MLX{Xf_@7Juy|j1v36zzf+J$TqwrO`!qTcF%Ie)Ii
zu3vk>l4>1w2BZf*0-fkS&p!`=x9%Aj5N=x>iLld4)|q-h+X7JnsIK$8@8UD
zN<8^5<6Mt7ToCA-e#k!tRtSP
z{G1~dx{&zOPJ>K#&ZhdSGao5ubFK6gK$^x6H?JAzB)shmj3?m9e;Fr%w>BB)gM?P~
zE}lim0P-D?19Wd71;4J*s$SJ!AMufLX8#e7thC)!)dPi;F+K6N6EeHwsa18xTkDK-
zFUqo2_u$z{t6IIkRCSvo-%hK#Re#;jN6JZPRjq+T3T2&jD5O;tAaQG8{0%8u)i-#<
zywCX&hzvlCia#j^f8(%cFp?t=?W}GbE
zx*%l!P*ujc96wl=d8R8W
zdrR316}r8aJ(s_-PW=&10VY5cd=PJx+5<>&%6S1l@oNenDd%gV$U1{Th3Trp%xlIO
zgttxreNd}81V1y*KKM&)LlDk~@&hGtJ0K%%+u+$1l_LLpE!074E0HO|X{Wzd@{w|G
zK8o#n2|rjii)VK&J9a;5*J6b}Ov}#audLI4h*Q9R$~Yen)^_y(8esbcKT+??e59O?
zM3HqK0u^R#&cdt8#caHBY`(UyRC6yW%{r5TpZ_w>NW8I$=di|
zs77mk3J;bC=ndvI<4nXGbx3c*q@3&cz-_@L(qk3;1wDs{p&^Y|rC}1@NW&G{0p$wn
zcr<(n=94pT;|av0G(Ty|1MBtXHRF`wjWp~-n3OY)4}|qh6&gq&pxH)4gKbAf*i9P#
zt-UirK_5en+B-KI8p@Q0ziU3*X!vlgdCfRvH)-fjn3QuRA8E&Bpjk=?1PyE>)}17W
z?ci%hSV@^=Bed2MytP5fZFm}zr{PuE#%?FcgOp_UDM0u2NN#6HE>Mz%j;upw84
zii#{D$$f|;C4}JDgW`jdJ_F*Z$TKuhXtdz1cq0wZ^^$_@Q-HpU(Vz`@!i<(jbbPQq
z$fs-@8rUa_iYy@w`x7Q5eTrX)iSO6SCEI9du{HZngGa;JhK5s=
zhRaO8kBa*I%*4f^pVfEoU8XEBgs=sLd6{b8uIYt!~*-aXD
zAxz4-ln>0)N`sLHw$adF+mUguK_Y3`Lr3Ho7R)*?phoT1I}Hs}m4>r4pKUaJ;22dJ
z$ZpcmnJ_8mB0lg@512;yW#oZvGzD!tG7eeEf*<#gf|uiG#yJmvWmZ`oEpOToF3&dX
zs$#+NXv2P98`_&Tw9+=5rupQNA%$aH+i)@7NXmAENjVqrfe*Vf8WZ*ye`Ou=$P~1E
z$VgZ0j!eQR=g!3&M>OT$kW8V|dZ-FW@+I12qqiR!WZ9m?8(V)Zo|cZRbe5@^eX6L)
zQj**aPk@Tv#)QELK$UB2m|Ay;n8|B#(285eJ%Z__pFT;~I2HzY;T%lbaKA~;%`KGIxSLxxVFB9i
zvV_FL`JMubl)%j`3!jlF0=rnMaOwqyT*%+Chunt
z*v4)=p3I~xvLcQr`;EaeJ}#r*7475;rA>~Et8$^TbS7!#C39i2=R#3Xa6VF2ym7d)
z0)09H@PXTJ8Wi9O1K{1_w|?2d3Z1;-bfPx1#CEz-HqfGy#~u9;USFXsJc>
z_-{O}H>_())EL%{7+$u(D=(aBbcjf%p_HyB-H
zVk)mQRa=p&C{Q9Us@p77byaw{_7&vAZSXamo#DXiM0L2~?G?V-R+B1f>Mp*16O#G!
zp<&5hs4M^vQoT6jR+sYp390~@Ry8{kV@?94Gc;m
z-LyR=(mf;#5w!dGXlH{s_g3skLENxwF^;<~1MFQ@=P&fUbN)9V5AU95*6)stxLLo5
z1wym_+P!jS{iO*00V)2h|E|Ck6sMeeyxCd5Y}F{ZPOEZf`1=M38#u#P>ua7FeqV4A
z?5n|`5=GsEPwWf$g+$Af!#y=?n9Yj)7CQGJCp~Ml{yth_mr#k=V?(ue4>EYcX=EO+
zHG7cXE@1aCj8jIf*@K)=H`Ws*Y(%xZ?RSU`I)NH%Tm-!%K1+@{T^}$
z$C6v;Is-N-2~pfSB%|0l3W|QY4HY599W2HBD#Z&9*{Bp(J{QN}I=AhBEyEPIX^G;u
zCYe!0icd#KhwykmrFip=OYw*E<0)=4V3#n(ZCj#v_aMa&LeUDvvaCrvr}o>ZJl-b{
z#jOV%8m8E3iQ>y`bP0L92CNl|%?{G6z8jU|t8fAA^hcrg0F{WJ4pwUIWU$^bJSKpO>ghnm^H>DWdP4yA_3_j+?#1cEEr$sLDr=%g
zDgIg;m;gp_(<**{{T!u%+IKfY4k-kIk^S|WpHNX?SJvDC`Sl;Xp7YK-MV3F+R$&4l
z&shtaFtV2}XO3kT9!cJ+2MV(T>xP^cG(Kj>=OFx|{@=J1914>VvV$2lNP+4=Ap+GG
zH11=GI9!SN0v0hBPFSID3^qLTbUYDMYeED){f)EixF4)UoU?I>I4BPh)Ko$QJu8j7
zSt5og5$_+gQ8_VpUOXqLe1r&kXd3Ur9~q%XC=n-bTq1hJ5+V9zGs-0|MQhqg2uLUa
zZyjj3V5HV<_>t{^6%e`NX2Fx*IJJi>^ypb}YU)@RJh}GLGm4rcc9dUB%!pn41FFm>
zszH(1OM}o;DAeCCr5ATt0kL;*fNz;Cov
zs*&sEW^7*yg(ZtIhTh1@^V*n`=UZa@*<+^AYPqYO%J6EZvxciw!ku-c<8EPpnKj4}
zO4(7CGF+#x*ZhWrMZi&t?NNhGba*OJUFpvIUcj+@3m=ZV_3?nDuv3fmLwC6na68rk%;Yc!&Mof+p_F38s&@x+~w*D4)j_
z+q?Tkc(n0+U^B4Rifxe0PlZW)Zb|MQO*_N>ca&_OkCFk4uizwKBho$@E^!$JCla{~#B17`?>w#~5@>WH=
zWrN(dz%JHH>lz^w%RP}fi59MNHyO}c910{>9SR=VCH;dWhgVe*kvo7S8>ek$6t(Fkm4Qe&ISXwRLJdPV>vJ5Lso(x-wgY9XhWd1%@
z2Ck+I7}tA#K4AI?ib9X;gb(GOC`29d>VOX73tw*$5v_L_%eFqI(4Dtoq5$l|lr@hE
znFwEs69v+&qQJNEBsl?b<|B_dhh-xo&f9HB8-BkyAE<4}BhDmN+u)I1avb}aUKr^0
z6+N_{gFO*mg-0ZO*!ZA?Gh9ei2aN%sn_$p+y5&F%zzP6xt_4_MXa0T(@9_vJi7!3Gs@Ya+AO}6OV^`oxcy{Cxoy@06`bn5a+?+I
z{m8)Ic|)4@`v?9Z4@z(48Th1Mo8`5nR)n2dk%50Q6o@yqH4Tta
zzesUSGPvxhZyF@Ii#2ytGNwNoYW|_VSyjEuMeE%+1I|y
ze9Nu!xXgbjig%fRfOHVs>~EAWGbw?M@~O8A2Yr|MEP*K~PC0ksE#fkdKOi(g8%85P
z<+m|r8Q24@&LrlD&KZK0Dhiz97w}x>M`+eSKdU~WNj+>*z7r9rCUC!ec5GwDu1(yT--s#-ZadQg_lS|lT8^@D9_5qG}d|!KX>^UOO
zDc-_4qFST6dJ$FBhhKzsJVrfNr%PeH@?=rp=lP+s#9SE~iMhIQg~*IK1x?2ZTaHq;
zytjLJc;tEyVORw%p1$w{pem%ob9&xdgg0k?qmEC^iHh*3`+X5!QksGgmXww!ZpvLD
z-lQ~8c#bvXZ~%k<5wG9ZzoPEI3h@}YTTp0wTS)d-v+iqu0hnG3V^@rxU>&PPKI;~4
zc4_pAIP95*nteC}PPvn6){{eZK)-MBfU0Vwh*%%TXWCh8vuGw$wk9t%0EUJUK>&IP
z@_XyVNZ{pgEjTUFBQm*djzbN`WhkK<_#P#C=cdrLYkNeRU!Ak$iKzC$W2E^=O;k5>
z3|G3#f03jd&2{Cyez&)D%*fqMx`4g@g}&z5X4I?$}lUiY`h!xOdL24$kNW{R{TBijHm?`Nfn`9lk*qy%x
zgLRR6HOiy27DWl&BS`2l_|I!|M^Rs&$U|)fu|&>N-+8?#xU{pC1*ZPc??M&g1jr`)
zV`w)4l!_&EhOVkQ%C%f#e%{sV+{g4aPv>?v#Js43W`YHl9xTw)RfuiiT{9xoDY-rH
zC51l8Knu$wCH91B0!ztFRerltr!3QgI|r))dWbBI2=|xfnD)-TXZ`KnN)b|+7k5?F
z!s<|4M1}Q04al*2ss4H;=qA6Asw%W*VG;8{T@BS9^^Wuqz5sC|kx&OmZg^OG_xdTl
zOlu;g+xwNqP+Gc1D6RioDg3I7*DQ}h689Nc=M#tD=qdLJl+BTw5joVwZvuU+HIc$s
zcJV5Wq3}a`u>*?XA=Ls^fkJaMDQT1Jh{I+M80v1$Hj=9mKloF31sIuUybbipeAS|l
z?ec?_OuG`DVS%MyU&L{N3q>4bu(kUS6v^RV*C0_N@^7L&tQC-deQaH^gx#$!`TB3P
zhud4=vT@Y~qxbZrRNOpS_ZO8y2puPXd^AnR48?r4BFOG+dP|2QeBk&lo$Vi!hJufW
z#2LS#oiX@`=vzf}Z3q$cc&f-9A*OUh6?M2X*iX4?Xtp9EE56&YB~iMSZf-Ly?ZL&G
zHc*43a7zzFMO&Tjcm~qcnC3CYGX;H~gK+7A%RA#7+VG>KTfwryoiKq14=$cSMv$9j
zfzKoDL@@v>lJrYsf5egvxWj8TvBREBOm}=~CqDYT%?J28;UbK@erQOJ`SQ=A{@i3P5e{J!=b*SlD-hfp5EML9rzV5k8LCX_QH|;1R
z!d%~VP@qC&x_<`QpzG@KTDa>rRFR94^
zY4_(RO%OzAQ3S<;V5T6LSpedBOA@{SFtc#p>#$VORoKd;jbE6gS&*N`@xAjhW<0lm
zrMH>}Q-H+H&~z|yVRae369dZ}j?pNQ4K*Gom--$kDnlEQd
zO0AqhFO=uX+F2@Kl(mbuYf09&WMzTn-8fZ&ef>gK{OYgOtetHZV_|tAV?V^jr{%&!
z4A$`q)ZEcjYBzv!?aTI%m2zI+D-x*-r`M-R_13z9f;ZoQ=CTiBCD+2ClVp{3o1Mg{
z(o6UOry6#j*_JB!sezm_XL|;wtyt+p$8#0;Ghw-g_CycEIO!uk{0b`
zie{4Au_PR;ih&!Q1_Si6cWsN_-wc=WfgWU005TjqsleLhk53`Drz%R#@RiN(vZ+P_
z;8W#8_0qYf>lHk*ubAu#xUc}cdp=TZ129?G1~loJ0aPz#`qj(6BkK|M=GR!5{Be8b
z&Sd4z&s%E`wn#|#972u{5|WRTQfxyxsddQU87Z;ZNl8(L>QzSb>SSgtoV+dCFt8LN
zQkcGYYhDO@b>W2h*uCY;O_U8x6}>i5emC)0*Nbo1~0Q>KnQ85Ytf$0RG^p
znA)D5=-n41dkio~Dw2|}6}B5pki7Uf4ipQF1L>*WKcWB{d8;<^(V|#k3h6Yxu0G^E
zYkQtlTP#whLjgFaD9%$OI7bjFI#Pz^2x!f@f>Sf3MU88=)y|uyhzks2zflW!he**>
z-gPJnN15~0AS8mW=~{eo;Rdudm#$7Bx=sPzjb|IWZd1e~4PtzKXC$(%BD`I5kB+Z4
zv}>H~ox_e9^m$g843EWkD9#_ZG-7NuOTGb3a=DxKdsX9f39`_XJw?wv}~
zxrQWYOXjGy9MYna%H{PV=SZWC43Ky;ChyWp)*{{;Qz;JAZI3*EW{6R&{e@?uRS65S
z_zb*s{Aug^ynv%hsbUmxG$ktSK$3ZvPeJ$U#GKnV~d3wV54A
zok%14h4tu1xtLPAK+;QgK#rLx3Bc{NBy-eA;hPThc5X3DS2I}e)jEzhbwC6Jxxth>
zfl97UPhI5JKqaQ72~>*20_2}SpD3YBMJCY9A;Ro@_;M%EZ_v)hv$oX1cfYpuf=y#(
zDLjkz1+&6~Z{ZnIw`S-?@aUnLigO!-6P;FSXOssttGT^ax88v}mQ`-3_7`C7h1*gj
z%xW;n@C{?t{<{!0sGX%G{nd~JHOric_7@E6A6s)y7k&&AMhQQRK+V=l3T(RrH-|r{
zS)aGF^1K5|`?@`LVjwv(F%T9M^YMEo25HWJz}CU#`Pqtdo`H!W!t!yWBL|I1ap_F{
zH4{Ui30IhSxQCQ8%QpER3(ManCOVI>>{och<(#PU2~)qqiGMZ|*~3cjj)q>N@DO?w
zoyBx+2yS7QoC?OS&lLJkd+nwhq}QZYZx+)IvU~ISW-*<4g0tANQ$)m>5kHHm@CO@L
zrA0IY?7*OVL|L`Et?gQbox^2;VF6wiGIH+)@h%08}jFcCKbUYO?I~BJEoL
zNNpRWNk(ep_3)p_ELfwMPq39DCLZ7UkT39n^v5)}kI5}vKy^`2GSKht^-qvDoGeT<
z9I0$NEHXPLO4l%R*edak43~Ws?BN$0_ES
z{%>Xbe@D>I{-5oAtduF3E%?wb_WDg7m9q=)gmuJhl?4y5Fxd{{(n>fy!r=oQ$=or2
z|B0Z?d=X6gN*a)BIcZ6emd_<{S#iaR1UB#JdXOTq0QoJaEB{VLMJ%VA5KqtozFe_+
z>T_^r2a%blmD~FjD7W3sKLaj|!dgw=-lSVu+CZ&z$q7D1DOvtCK7}Y=B7Rm8FI?AJ
z){hpk5z_Elyf1n%Y^Zfq#G1hmq$KL+E5eHn!c1}}lxo@TNK}c@K|qKRAI9i7lr!LZ
zrZ3bAiv!yP#urNV7LZWcfD3(8(t5O4jAyo)m{Hz0;YN&s3o9<;s=^zlVOYgy4jO~i
zKwPQQ#$b;iE@QuZCHjpyAhrY!&g7}%?2?EHME;e|X~c?>NXWQSVS1`M@+#|MNa
zQPp_BS~HJ5r#)Qp+XjeCu3q~D<19c%{f_U
z>-U8K)KW+nXcLzHs!hlwcLuwt)M`DY#uP{+AF)cUR+JjERjGM^VWpN6Wf-H>mj5Zh
zX)2TTE489=evw$6^xKmEJ`V@Kz(-~|5wow;`QQ$0Qpb4R7yYX!$
zE4{t3vQ@pYbLpl^K8uDzR1EzLJr@y&XSHS9QxhANzXELn+E9AD+fnB$Jb{&J0hNoC!0`{14G1*Dt1`)_PEtw|?V
zd*ORape2PGlyNaVqYMH-$h(r+#rTvi<2NzWX5HdX5yMi#CUZkIvgzDqtk-qdtr`ZI
z`L1xQ7EWkrM
zAXy}@#p&c~0)nv1>+#GcUHl|SHu;8mLn6yvxT%chn|y?sWDlh8Ve}t;=)VtJp;}?a)E+-2tNLh5^maa^TN*(#X7*p8YJ|tA1t9{jv;i67TMG%K_F5!a0xQTbgWR=s)hW?0dao`n?s1=s=|2_9Cq%2
zeMfJbleSOEH74!cddR$tAfAJemiy`nU!=d{ATPhj&u5f|_Yri9-K=@LfCz{gaoU{1
zd1;RP@?%>U$rmsy|7VroJK7VyQf1zxe+M|+67w!VQJ>(Ogn5y6umM)EwW~)3u~Qm~
z%_VGDAks2PCmWa;+6KAtNHRz>D3aqTlVJ6=xawX~IbYzoUi~$WdzKHI5>aY==r>NI
zUn~cV+L?*~x~ESsHLPUTYPzV{P~F}k;x5ROSKavj;*mj$V|b2My#
znESw{%XkoCYrbuX*yEL0Z=N<^K)Tu%3eMAZN|s2o#hUw#jB?@upEdCa}xkfQrW
zc|2qIs0kaD4=R-5bB^5NO{^&$x2B*3A64fU78tyssj?DCtkLyC2dK64M3C_{#SWDM
zixW%euV%bAo4aBC%STeH&DA4_RvHD_El*6yoz%Bggfyl$w+)OnrXE>})>&T=Aj)wr
z9fjWd#&D%<0qZCz*%je(xSE4k2b8lZ@YqlV)ye2#nAaAdT(_O{oKgKG#dMRwWY==D
zaf=@8opqsZtqgbT7ZQ|V_v|9x9vc5a8F)s4k*ZeLWUY5wuLa|33JNEEK#hU+Rch{!
z|FZ34tDt+eRl%Sr5=oaquSm;-$`?%*FtzCKyOfeLyrytrVnT66T5{5tL2(Z)FK+cM
zKU%chee@FZ=^xN?v(oZ6pBBVIA3`c`(VSs6hvY#XCqw(lii_hwoK~|qpy8rx>RJh*
zV$o?@w4*JGzGWX(y8CBIU4jD6!z%~bs|eq_*pp*l$e^)GjhN*M*K;aS6s|d6x1<67
zlwm0GbYcAUH0jdLIKP0W7|Jy3FE*=e0a>R3Z^A^+Vy6;gBjp=nI2dKZH+-&PsgPQ&G7QVc_(55HgZj5UJwF~R#MwdRi-F6O5_5Uq;~DZ
zCKVH_1ZtvwC9Ks#gZi^WrCy{W>~m-9QMy5~^)uMK?q=oFE8RaWp(`daJu2Zp{VgEj
zbyNhY1*bs5utd_e^HjQ%a^?I36)(zp=Bt+E{DK#NEU>4FooCAW&9+e40@hP7n*Aa*
z%3LshOME)%x5m~5?hF_WX86w4CZ1%A`dF($xQwJ*734r4q|#_7uJ?fi@?!Pk|dEwsRwHmOV)qeD+v>
zY$z(e(wRhOJe)pe5zgC`(y!dGa3bbAyuW}w!;o+uH9&+Dsfo%)dQC;~-mcj0G}tg~
zt7O{D&ruXNy^eqv_RI)d7M*p6q8pk^T*MVR3Iv4do7G>$vEE?a%wn}+BtzjC33Bm3
zn(f@@LA5nn?OR_O8KDMD_c?eK5BX%>+jbR5C`Fww)5SQsG8}W$W++dq%7%&q0$(O8
zd%ksXMcaDh!QupdU^rzPU|^Aop~zp{x;WMLC9o=Z22Ee^eadH8Sos`a%jGJc?M;@|AM3$P`IG{BT+UFy)aT^{(v`fRKnRhERNj=9pt|b++3!?WRdh7VMF5bx
zuk2iE)YaFYn!f%$>I&SYx_Zo(_0`qgCdrOQ=+ek&%vD#-e-J6GH&{=%So5i?3FxYb
zy4uStBkHRBOI252K{*5Rzfe~XZb{y?sIKnO$=|B0J3k39v~a>b7&t+7HO^#P25pGC
zdbbgl#84WbnYM|}rvw~a=RCi8519635wW}2^6<)23
z#)UYO3L0;;V{@eP=;IHyx9!-3ff6wU(S-KJsd{^k_0R)Mm0YE)q-&5IzfiH=YOtaE
zv<(zm(+0bues>#zl~C$$N3iq#aDWq~ooj;$C}4AnbZEJY4E*&;c7UA>Er&fUe__DqjU|Ft{r
zL?t7?JMM(yvQ?*8H)&7}y8G9m%^kITEneUJNMvd$8d+zW4>lBIhmY3qUYL!UbD=hW
zwgr~m%9GJg)#^69miKqnU7}FehoH=!W~U~Hx7)Fcp+d4QKB$b<)YkfeR-DeSFrV3MkE<^!MFXqQ$CdGiSpQ(jNIR>osK@s4V0x|W(f|;!
z;%Ggz(ehk|dioy0M$B?8KK1967pCPRSd^WpEEw+rV3om%3z1!M2Uxc{1631=7yF<_
z7nKdyB)D5bf(b+~b<@tM$M7W)=bAb;SR3@-S1JR)p$!ff83o0RCr3~U
zCO@<8T=2%Naau^810TM&qcH32^hVo)Q%G&r*#WOO4u}uIb;cV%l{REP
zW5b+n@iXIWg1@bhxb`htM$QF%Xn7XODUYxUXL}Ukzl^gf-te*1#VEv&FfPPXN~N8T
zRtUOUqDwntq*2b}`s)QgQchbwvd*`FG*$h}yk?wl@W!fE;i*-9h&NPq0}9Fa9`P(f
z4v;^I9H1LVbQob;)fM`yoR5?<<4vh514vWV3+6TBEWsPAT8yVw^#tBf)iEf`s*3UK
zq*bMm19XEG`IGOn=bQohYbYNn=TNQc4nUf!s?2M~xeafuY8sweRXN^JRT0Xvst$N|
z)vC@y4$!qz>92G6NI8$AaKMFC&|ky(!1n-A7KNSw
zq#?7$yk?xo@J2G{;K_d(ry6e{vlGg)s*c2=RgFOo&=o53+INNdo9eI5e59Nmh0HDR
zgJqdFOv_$XFZpd0`bI7Lo6kRleW31tqlVV#*qgMb4kSG7e5k*+CyK1I4}O_u>}_5%
zP7l2Cdx$HROEtT*MA|8XXAMN{i(gjX*h^BlnZ@8A@2iDfF;O51_otXFJh68*s67;H
zgR#z>wVYifxlV?xRhovw&D&))4!nNeLKY+rYmQGQ{=}7?BgaSq7Bpb#g%q
zq**MGOIFHsLj&v|`YP^TNJ_*2!<@D5{K9YQxKmw=skr`1N7U^=Q%drR3wtDH3xtbp
zhIQW+7A0!2vwUqGx{Q<7w$_H2e8O6ZXQ{JB#HvxbwC(KE)}=+-Zo!0XX~U$MsPXRq
z8fK>I?I8PT;>x$BwJWoUDQuxySD8h8ci;arVpS4T*tG2x`XK{tQCFik#2R~$^+~gg
zGqjTyxH3`zCMnI)tc&O?uK@T{L?#t=cnRR&6`r*i??bD2?{RKWF6VYrLfEUHzokuPyV%aKS$zskuJpj?U|6_E9V73{_}(AyuEa1<0)y7y
zo5y?R2ELOHbSa^v
zMZeUuTIxPktt$;E5WMM?dJAuzk+Q;+$~gbT8&vB!l%;yS3Qt4C9moL@qlq=`IKmg_
z68$xvkCe<=DD)^Gjrx1Yyk?w-@kVoL+sDORnu(toXFC3}nhH}5KCg>6s@F3W;|%~n
zKI=9ZtIR9rf4otl4kk>>xs{K!^UTkpQ18O8jPu27ivLqQrF_~sQK3IT3ZN5j$_()~
zf8o2uc);a`f96Os
z?8W$%apvF$%RY>!bYc3GOsHt26WwH!qeLn
zdX|>GmA_y|pb%FA8D|H)u}z;Sl?UP{ezoNz<($dtv(DwnGmO5}yk?wHcq5~CP!j*f
z@@eM+33hQt01ZDHCcI^+ZtNxMIQEgWy_DocV
zf;ylg+XtK_TVe00BJl{OjOx^D#VZ;R4*@lrdLC)1*H*Zju1+PMbP=BepeLj8Ne2)0
zw3GLBVsW+W4sNcdoTlWlb;lS=<25A^b8%XY20+dd_HM`RY#|#(jb$`)zaUiFX?{%`
zkE9w7GG=|LSs&P}GK8I!IBsWb(G;hRM-p3JvL2Vc%fCQJ%g0HZy8y(CovF-$N8{uBaQScp_i+YOis
zebAp3boUVGg>|>~nYg15^s54`TdwqLrTa@yk*41?yTQw57cT6e)mOv5rGIj
zWkIJhBUQh+p>?bJUUyD;c!!i=ZR`cXtjvb)Lusw9gsV(ZY@3RRJuL@tAfWuRI1HKk
z;*@cYhqesbXz2ldX>6xX60rqYZ8dinlWT=3XL};L7v6to=^aRz?xQ-2=dD+BJDLZm
zLc61pj$XZ!?P#7U$s=wkBjR@O(To=z3EnMkXrDp>3JBa?x&zm0DfZM51F&g*N?;nX
zjib)lO_aVr82S{2l^&vFAMvyy`e>^Vkd>Z$F_9})f=Z-1?rVO<3I=gl>9P2D6b1Me
zhk$(P*+R4LHQ8v(Y(KMuW+uI|l$XVBkq@z@LYy0dxUlY`mzt6)OQf?ZsLCt1iFhxw?Ynr7GYnelc{gj@BEhJH=XOPG0S{*$M;|Q0C9}!6Et4Um+
z2^5c~V&fO_j?aVnj1EHqbHc=n4ufiR+&j+9mrYN0+4DubPdfFsyT6Ud9YAuqoQRz4
zNF3?$1lCI?fiI6F)*|eZk)^!paV<8K*6M~59iJ}uS&O^ji3k{mL#>5*K#=mpIzHF6
zuvpI~RvTu?vuR(h>VR`Kw?B#(H?-A*k66vaF!2`j2mK2x=d#3VT#h)dS-F8i9yj_Y
zR*!$$+eq;DEzX>q#~wNY8FBW|J}eNjhdP^-fIakC--tc*;~bWvJ+umM)(#ZuYA#NF
zTbz1{A{oDVaeyys`&p@p6*U+%-c6~0(Jk?{%XDCX;%an-2uXE-E%Z7w+C}>CY49n`^?sh^$))dj!{m
zmyTOhP{PQxb6-ScTDxPt$TVC)$D)6?^>A!t2hk{(aW+P?e|yO=fLj=HVyZgk&7daM0V$xPyxg8Zc`Av7pmHttsqGXDi+{o)}SWp{0IS#qj2i_&tIZDFjm
z6vJYXuYw@Ald`0jEf9N4tOkG8@1U@)eAt*9R?QB3XN7$eQih=j4#5z_<*Oy9P-&Zf
zsI{45>0qODZmXt#Vg&A_rKei}+M#-9G8{$4RNOTbCInpLK5U3Jzxv@ez^4gb&5d^9
zJA(pUI0F2G1ja3yF45Y^zlBQ;*|Gdc1$7>g*Hf0J~<0|JO0}|anuw?pBg5{9f
zErFqe^BcPmvCJ0X8FYKU1=p>rW^Jj}e@rzWo5~!UT8_buNY_!ExNP`_ekv=K=1yv^
zoJ>+W+0M7JEw!^NeHz(B6)F@Ra2TIyXNE1L))kdY7n$bt9>|n@u;7mhTVi3s$U&O)
z7n@|RWrP~XMmNs;CF&1Xh(QsEY{870XSPNc6UKbVd?z19nhs?gvjNYTRnF!mU0Kw8
zQT*eK*XSxRXkFuPQ0{`ex7J^00nDlmxFK?Ob3b}Eq6S%HH0Psk>|%5#D%)Rijn2iz
zPz#}%6IdX8TjIfS?q4$_l}4f>ATMGk7aqo;JQ-TZtU*zEU|MGlxNjc)SRRN`DNHV+
z)dV8{phPbJr*cF>cKrG`CZXpaN)E*nN##ekZzf?NPZIm5Fgck-{%@$NADEY_
zvO2Yh%vcg`j}=BvQrk<(Q^`75`8aWjkt~`ASTQx;hjfvwz6x-@2N2uIF!F+@Zfc>)
z@IP@$_5Ebi2H&IMwz8n@r)UceTGc$})K1Tczos&*e9kFk)49Hf^Li!^mCDDV!na=E
z-QQE4_V9>jUug^SeI~iLl0+qQ*$duyi!tcu%r)X-4x&I=VQe?7H5ss-Zi*aD|9&zSrydYU9sqdSdPWe*D@E?wfM2P
z)g1^=4+@sj5OW@4nN&J%Qb7q+v?mU+L_r87=*jq1U}Q$Z-5?=FfpE8^R0X*yYi=W7
z__87kE#N-$y-bsnqj5-&_Y3rOH97a+OfvnI=hFY^6-Zeg`)vNd!Ir=zWAys~TWCG3
ziP7(^Y*AoE=d5eQiN=tAZ>Y1w)MNXG==WUZK0O!F#?+Yy^xFXC{wBIJtlZ_>P`+~i
zZc(iCZ%jf{eJR@U%DtetpD6eLOSS%!gha>E6Q|Z^2n+2P(N(t?3`VWjEVS~HN3Box
z05(LRqH6sw(15fW8lQ@&^}Yt}?@{YFZpyAOYW>yK@}ny1eaQClhI)(Z&k0HZ2k|ww
zi4ZL4hKN_@$8S(kz#=wZEITStNTf3D9AuNk_u_xCtecVw-h^kMoi>ovZa%5I+A3m6
zJqD!O^`QA;+3E$pf?^;7n)`uGvfoegzF2k@%IiWgOz1xj3h;CoRvERqmiMcQmHd3e
zRuD_%1OF0!)-O?NW?5j_nC6=L%zN>rofC1(i2D^lIj4kH&|hFT+FLS?;F2eom`b0R
zqb&YdVs3
z>*v@FptPM&>7(;~(PX9JIDql1R7^fs3QK)pk3!o2v0p5E9A$IlX3qYWk0%sgw~7lt
z$WA$y%cbE%>Bp*vJSbEe8he(Kz|h#;o)OaXgvKsu64L98E8vG(1I&XgvLcjI+w$&v
z9l5lkdm(XR*j@4jTv@H~Aux4ifiq&5&-hsJ`ov>))rN%Ec(Pl;i26P@
zUzd3vYY)I*0OSzZkSD2e#|F8^~P`Eklxxt<4*ZxUQi@*TgF`^
zSw`dYai2G;FozrfzjlKW}r
zKwHQ^C5FDGm30biP|9>rj?3*bqddCIFnx{=s4r`1B|FITS`mR};GQa6YpU=t;5@Ma8`$nJ_HqjH0c!VBYLib1bJ;`=B@pM4$$eP+YdFTeNcbYkyqXn6
zL(RbPS8bm4-T6E1>}%1MjVsmLBp{U7)(Ed_DTolML^TQOt0f1hJcA%vQCYlZfxC;%
zH4DD}iR!}1M
zOz#CNB8eOFczPLJ;+ifn<~ZuJ?jewrask5eWx^VV#z9z*knkQ#+D}gy!Z!|SzwQHR
z**K^kBPu%+#x)ZzlHA6N!r^#T!S5}hqNz353~=xM76{=@j##vza0WA|g9G3xi7qu6
zSp9-`J(YJ09^a_Et3x!*M&exwQN?hlqD7uPr98vo8)YB7yp*KBHH-1XhWFQoZ(-!w
z=n)MCfCL5uLt;32kp$$L3@Ow&8@mCO?tP!dm;?9hZOwt=vL#RjY6|4)&WuVhO{@27
zJjD{TPIwi!-LVm7k-yFY%i%=&fn~ZWk7`S^sb**WdNb?Snc}<~L}&enKjExDt#sTp
zo%MH_i&=j+7&XQrWM=(|!Fsd)CYNy#k2KkK)*t&Yl<4MfQHh#J1ks5Pzhm)Qb!eTw
zds+Nxxpau?0c{Engx;2kxk+TNnz?pTJ5ldV})_o81#q2(seSw#qkN!7l-eMpd
zz8XLBex_VY!y8&Z}2sNa3yV#HE^
zvq73s%N#c6N_Hjg*Rh3kLacRn0$Csv!#})Z+|j2j>zp^+i^M$#uiT@}IDf$#<9E--
zlm9Z#@pxn4Ycw^zeYvCX8$T(-=FJnMY
z$CLk%KcE~t@hN9G!Eld?2!Qh^{WXG*l(QI*jPqywWm)F2Qb3nZl(Iq}u2a#nLs%&5
zG_ZbvWt?XWC6_ZJ<*dL@l)ayil(S%#K);TMAk8|<&1=S~$6F_WUP+jg^Aa8z=Q;dk
zyI%Q_0_?mZiF*PWY3qh3{~>>Z7TQ^B`&Gow*
z%Osvfmn7;3Z!TT_j4i;y2n(|W$B3V8)mVnIve`03!EP~NnZ$fpw)}W0H>~EDj+aNWD|5lfjzvOj;c#0mnpk3hTyrfanC8b
zXWcL100F{hqaL!KclDGOrR2Z5sP5ZGM2Y1;8HG$e2l?67RuD_%8L;6f$xA3mY3FS%w-WMHt1&pe
zCc$60dky@B)in1w7K0Ht^KfK1IPt~#3+sGhuCVxHiCM1U5%tDjc(etU9`wC`@&3Y{
z473SdLZAC3TJ#rw`jBTCU<~>G!WvMM)85Q3>u>Mdijd5oXmQ83_ahCHsG*p%6O6y`
z&we4D_R;?Q{=!W)^rI#^@$a+&lpgF;`oV)OSs{ItQX2(d;{$sXl6A5E!jUMO!^dlP
zj`A^HEzi=L$je)2w?yHs44e!ohKJNnIxA3UjwT&rlkAAYW$aW8bsB}5qZn4;JM*51
z=NWHpd@`q4^s!yO%Gk?f8`^Y%1s2QA7uZjsveBU!gRR}}peu)ehX#piL9t$@6_9_w
z%xZ~$Cm6!MQNmuez?_yw?+MPTlvX6F+0nmHZ7{e?;;FJOoIG}=v|16QEdm|9T%qml
z^^ZvdqQ?~xm`;U*-;idrH278#9T7qVJ)SCZJA&98mh{}w_7iVm7#mz{s*Cwz#Y7kL
zrTUu3#eCEnk)^uRm4d+rxNx2`@t(E?6Y2_+%XC3icZNcAwdg9GivhvL;xvSF4&TwJ
zD@4gU$Kfacfem$MYr!uckUk+Dl{RaHX1#2(GKq3kq(!3yTk
zCwMbb+;W*eog{PNHclUn5a{+;#v$YCmq+}w=+LYo$-uZY*rYkJ#j{GNAZw4gQ
zc7+&3zR&mwoeJvyqRm(|Q~6|^7H~91S8nCumD_Wxh+YqeG(H3AqybfTu422)V9Pl3
z?t%@@Rox3%EmERFe&BaH5sBvqHb;lWoJJTY5H@RjbK*D$?Ld|Vzk|?K4B%ABYH-R$
zyYc_f)u^x8M1I}@tI{59wn5Q^E*rPHVD!-d1TZ>f7_QaBt41<5OVX$!LDLGD<@itq
zFiDDhgk6fYqVoYY6``fJ64>LZ)#Zur6_iF~Gj53fUhdK+uvc4i=7^#q}1e=T-U0}k*nz`at$KL6mbpBqU%*{=A@|GMAgE9L=I3mXvjq5L*H4swmJ~R
zjZ`AKTOul)k~=USFz(SC&V_tu^QhqW^H>r3d!CLkQyeCVQPGjIa966H-7$--us
zQoXC8I{zpy4Uh7-Tp8s^#SM0Em{DGTv0|&3;fY&0YKE)wLpqVg{}VR-zunf(9GEyp
zVWd{&%JIvJjT7ksKH_>*6O*hM&c)EZmrF&aGWY%tbdx`f>^)LOfxX+4PYLz{zby7org>bj+nb!LVaBT
zbxF&ptBKkwkP7E0f%b>YGwePQdrt-Ja<4Ea5LOtS@}QmC2R8d&{G5XUS5a3u?ldw4
z*SYc{)rz)D&1gKmyP&LYq{fticZ2eE#NFYJaT%3^4jQ?Y2&U|tOjOW52GsbDYdu-L
z4Z$8Ew=r+GhcMw2@>^@QO}k5-)bQx(Rd;!HLMdk5tKXHns@=Yf8ljyTx%TuJ5aZk7
zxg)f{Qby?s=B7}E)9)d$&wepNj(8Qzyw!$eim+h8YYEZb!@
z$V7Eane4q`ly+iy1LfJJ?94eUr86rVF^7qy$sE0~H;G9PJiG)xg~MT$fhiDI{Gaal
z^=P_uY0L1}(|1xhh82mXw}XIm$K&PE=L9}L&J`cPx%C2LGiXOeyn=6S;f>6)RWUcO
z{8f<1M^BbP1|SZ39GCxgQ9*j(Yk0V?IQVnCi9F#jc3WcL~Rf^D2I3oI3pFj=(0YB;~w@pVmCz!26E2M8zQfKe+FxH|zy>1J*?Qub?MWMja#LJsQv>X1c1>XGl@7xs-sJ{S_T9%?g%bA
zet<^+BDQU<(Vbm3UAImG2=FWlUUp$jpL*uw>^EFi?jb$(2s
zka3;&wMh}zc`qdwb9I>1Dks39WuF~r1lexD=A4}$`hM62}Xw$D#O;@P(;e9|e
z=sKT@BAC*{TUKp?M77ZE?`Q?&-ymC8EMc;75a6FV!?1avklB-Lp5oCAqX=FSvnTm=
zo~?&d+6MS1q~`Lkk56W!MITG%4!T29Ljgc{+uf!o{X(k7AdB8^6GE407SITTB1zP^
zLzGeqX2^vwr%ja7__1`e)<&jQ_!Y+pVbAPP?_G0iV&00=s*9p#>Ih(PRG2D6Dk8xCI90W}qiW6vwuXaxJ%ipHigc
z*rpbLZ2$H%#Js4idH`Mwg$3Xw?-P4j_HL#}dg~Y(daXW*W
zoc5NtincdiN|q{8wz;FlAKT^xkDnsP>{_`un>NSqT0NnDF$ga-D`-6zYKsd8AXu$z
zm}L=AA;VFcXV>a)K?fTU9iojUBC~6CRtOROp+#;x5Szo2k^;*T9-NR{gHj7HNn+SN
zRUnV4&A^^oTAutK&!BwhuGalpQ!RM)jK1dC)!Kn;taPGuVRyC_RByxO6m~_f*4gQ5
zQ#z9}Qz@63wCrBRqb~ec5;&s9gRDE
za+A+0X(yW;O^#^ra%pktOt#y6;EJz?1@d_$^hc@oM{=?ZnWY}#`I;y_w4qHDU~S?9
zSoFZ!Q?4n~y|15_!wd&0*C{DKPf}7^?4Z7AN!a3htv(?kcDAN6Bt
z%2Chl(qAy}{vd&c+_Q-3bbcJmE1ZuDQ{km
zOtUqmGx^uZG+#~gK4$aK9}`rN9=qv(EYq+5lE1}9G|UGM_cWxmDAQc-hGqJtlzaUDls4zgoRx2@qZx~kNljUO9OhfAQwGbkc+NSUB}jx&g5Ss
z7lGzkxiH^axb4ROv0Oa+Q~nm0C$6W6rc^|?G^G4ax%hlp9=WJcv`?q3T;>x(I{4DycqZj6ByQXug`qDn3%`)<;9E-yFjOq3ynI#HL_}o&5LvugllL*nEs9C5=5Mo9h}I05(v2*d
z4=lc!G&-zes!YK!=n)Ro9t|o0p(X}s=)Qc_Z@gl3n6JOyZi*T=pq4iuV+=b3jfq+m
z*zdfE-cDnC`bPa!ZR;R|Ig{K2L~N+qAuJ?_kN*o9-x=$tylQ7(k#UluG9DnR$ru;r
ztCS~B&<<#^UvnkBXT}#spMU0axdjF%$P09;w}jBZuCY8*nbI8qbgKEB?mx?voJgk*
zLrWsp>c+U+r~NZW*mmM_xXye8a->0yq)H%^b)5P7>QIxFN%B)&8`|ZBMVIqoy4?L=
zTBbd|YoW^rjmd9)o;D`G)jDEKx4dF>RaA$trKL0Z*XWQy(?2$XWj|k4H*83Vv_}XJ(hqR?x$1
zHNC^uOiy=gx|WYVhX_>GUA;gyN8OLL=JrDG&{D+TV($n(pi?l%4TbycOzeu`BG1$*
zAc}sqVO`g-
zu%n`4iGmPBbTt+f3yKBBf{OSmDkv5-8Wysw3sDJTkD`DbMIj<3Sh9#MHbk*tzai+0
zohJN0pP6&+J$H8#ec$i*`Tu^;kLMwG_RgGhX6DSy>F3&XrSn;0-pKtBA!@f*in(bdP0r#+>??R$di}20
z`YnpkNf03k=l{a{*LT!{r`;raSY{&`B`MxV+$^%LT+H{8g~S^cNH9}`ZiIsPvIRHg
zon*2FFQcfNTSPaVw9Er7GL&Ga`cOA(aQlSJId@j_%?x=>{1|3cGN1L@OZp>xQ8Hg%
zkK9HPa;Q%zwWC6$X-dDOR>9-Wn(ve1e3
zgrLMy)bW`ystKEevg^Rv6jY`=h03Cvf{^^&X;cGxtjP+kIDi^&+JAwJ<$KD(tETdb
zKPC3mRhzl7+Few>H*e6YRlS^B5PyyDA^)yMeuFPgRrIH{x}$0Va>--p>xMaexg_O|
zc~a3rV?HIZo8~ao=3tlcOGlUM-hlEPx@-BP=&q8w4s?fG8%1%Qj}paIT00c|?-MJJ
z7~w#&88O1&Ul!g3VJ>hHcrGaUFTB8IBE8RUBGWw=mI-0tp(BL>-g=1L0_NkOVVyPX
zQaC)oy|`J|+G7$ITD<*H6f3*<5Q}BUf=rthe@2DdN=C$%w+G5wIZkh1b&^-y>7bRo
z9Lf{t*h8z}`%zlS5KR{@|A7&Yp|hFwSgQlqh$rV&JQjk~HY*s5
zvO|3Cd+Gc6U(P
zKjwR?LZv~*Yn1RnLx?792EMg{j@TH6y3#e*6pU$4lCYa&J6l)wLuYIMiIUr;UXz-VX7yl5`D>(THvBx9ih|@1cVA%F+IoBPBheO5e9^&-baegXB?o
zxKO42-(Rrzfz)o)^#2}dB;tmU(lwh3#(YbIKmnVS;2lfg+@%s_BYGd3tj&HZ%(?kpK6_?l@Qg0)t
z1bLxB2aL>oIcBI$guDH>
zyP4m9*z+pvb8fNnFS~4Bpw`&OA>6WHqMRx~Hs;GQyBMt4%S+v8gKR1C7rTugL!`UX
zyBu_t4QQk(F<+j!?`k!r
zn%MNblF^e!@kGt^^Xt8GJdS`tO)r>TYi3c%UG$SgGZ=#si%ZSLYJ-%!8R`P1e)Gme
z>Gsb>dBdC+P*FzH?;wi*_D856+2<79!Pb36V0yQ%>d(4J%*Xs861`Y0kBTZhvJK;B
zR3kE`VZ;?|V07@^hcpbCT7)(w0QJ@??`P8`<65GQw@~YcD?!(gpc&)uBLDERIJS36
znCzo8%?u5O?8N8*UalMJs{}s`*E&-@n=#$6>P@b?%|-*)cosZQi?BNoSiFfUM`^a@
zCR>Qs3P>wjOtDv6Y%)&u70m9lndxD3`v8Nm+^2;5ak2EmnxL5
zxw2qPxdA3VFTlVN%}du@Fk(R6RFmH^TJYK{O|VN9?e{M@8jn>YFp|akn^Kk&Vs9THPc+JdGr_ej1WYZ2g}~Cd4Y)M%g%R
z_vwhp;XWPFs`Vge9}K+17@sDv8@P?HS;`bEMUIxE#>~#{`-f_k+R)yCHIlgl3@gPM
zYWwCXQJW&fX6mZ3qfsJ@oEA-a&tDc8i;3S&P5d5WtZJYdO~Me?#BnBI6Z)3Y3YE#P
zlKJvZ=Ale3O?vIiZ$1fHCtpZX7XOk=La;M6*Mp+P%guVW(%{fW!`qlMRNCW+ew87v
z*5Y;qmYLSEo7qE}84(4uE69FME>y>E!izPbQGPMYhTLbV
z+&xW&fSYOOTdDEQth$R_3H6zwDWf7wK~0{5-5s2op66*_HHb
zcyq0pqA!&JvpVKL(Tp?0(U8ybHVyO}U%3m#nB_G)R4~VFB$keRlbW{v(Vw}iN!`5)?Z@G)|riUs#>}Mk$H;71cD<`s2}eXp$3aC
zbj+11dn__$7wE3b8nU0#Ju5w(Iaq}mgJ|6Qb9
z-YfOalSQ@@lHaRWL0r1p&NPA@=p*3}O?bXd=!7xN+?jdD*dHlOqrdP%qYya)E;|v4
zHI4qm0ah512-!o3ZrZ%Ot_3=ZBsPVAdy&mbvoX^eAh=k$do?7`O2_OgXLM-3s+B?I
zqE4}Aq%#fB4u%Wc0ClFe|GojbfOFWv*n)}b4#pobhf9^C1EL)L@3a6bACq#mX}}CT
z1R1Kuy%JR?#w+=~Fde>xSWsQ2RQFq|RE4w%IN}@htz}UsW@p49QRZ~GHZyJq=zGpK8{M1fa3RWW
zG)g`a24;vWCQVP?n7!~JJdDRu3%ZpJPKwiFa&_~H8=n-vE``FgC&dqX-SJvZc}u&p
zqr8nwiZ_>6GAT|D>e!A-UHnVy;=S{YOO#@st6;(>3^%B$D-=7+VuLAjP|1{>o^wZz
z&bq-FABv)M>L;V7%Cx2~;)T?hhG=NMykRX#!#ebK(MINc`R=c|+L&pyQ6O(+zMR>j
zo8{NaD-&-r=0Dzb=09X`{?De&KOZa#l=%+@8=C)k6-+|4kE?12T4K{}8NoXeiovIz
z6)A{6XsY4~rSD?t&5|0Z`;!{xzk_r)xRUly<|CEnuHjM+Sf
zI)vh$){;8elC-^VZq#Is73LeP%*N}2!D6Jt!a>>Npp?0kN&yBI+G{+xE;gzjo6K^6{+lare2#bCi!(NL44@FOWQ^BqO3E
z7%}A4^&|=;&nwBvQIcjP=^!M*`h#8An0zo6Hcr2mwWqDJ*=Cw*+Y1<7*pT)+)%F0%
zRTnm9YeD{?fZb8hG0MqXI0%3Iwh76RFQIUGqzcEMMe4NwX0^MpL8L~S-@g!QElw6T
zB%w|vT%uh&LAnbYC-FT*e?d7q-EyRI98sn3TlVJrRNFD~D7;vx(tgMLgN2Pbn!cS)
zZ+jUjv7FXk-HE|%p2z}gyVF(kG+mA>764qFktT#Kvv!6D&FiV
z?6&8KYcPawuV4cq91Bx4;9zZIl^WuAXIs~b)wb2OrshsQhH9aqTDTXz?x8rX41o>j
zx3$-pDl8O=w11RrTf&t~0Zyk1&oc*R7ob@2&aqq#U?yDCNENm<>388If~+QEE7W2k
zsq%3p3twWHIeOZ*&*H#LgB75Q6S{7lre7sIG_(Y?1&ZRz2z`BbvYPS^Gs5H5
zOyM4=Jrvc+qHtRR7JOvK39x%AHs8VK-Mj@{c;=R7;bu!v1gcp6=EhA0a|TSJ+?+V~
z^GjD0Bo=+JQodk=vzIrM8?zF4uw|bYG&GXwSY*l!%VN`+x{229A7=*DEtbIb9>&VM
zc^Z~|8(qw|ow6b9(`I)59PsLBXA
zBWj$w9L!q?5HTmVN{9M8kjGH{P?q$G7ku&8CjVQU&dmzYN5Af9tAFkr1wPgCsG&_~1l68H
zL))SR>R`Esg!e5mJuX#vpZrYw2Y?w;eWp}TS*oGYJBn(>~Mw6c{%2ZLW@opm_Jnt9++7
z#`Bx@bNr#m4|XyqGwv(~WpD*spKOM&(?Y5F`00&l{vJlfRM8V_&=4=2hvV^o;zd?v
zpBWaH_PP`|%|rhcGJ3lMWI(F%_5j4sPwa{(|J8VHNrv)qyy8IKz8OZ?@h7Cyt1
z|9~&*!tR&1lw>I{E!=vw`s*t`65a)P)Oa7@FVhmoLP4FcX_t^Jojc@f2mv)vBukYj9%#UF`me+gHqS&ufBYwy)*D&
z*Aw7r2CVT00BVPfHy$ksPr}a{?+EcUjn-X`lo2
zKmDjg8x-*$d{n}7*;_U=WH0HhJJ#WRzJm(yaoS>^2Kp{P?VY>tvJ~%&BYl_G%p0fg
zG679ELR{E)sT3O4)MP+bx23BjK;epmnc1%Ln6@W$l_zY=hA@Kq%n0LqqyOSh!k;Yn
zI1CFPfj2f%)Gc9Ahc{Z(Li7Rry>b=x?n0-i!3?{UisQX($vTF`)i&Bd^=EMy*k(&M
z*e$MsDF1rc4i0U!m^!q&{;9c&S-ZfIs)1rI4U1{gXfe03m{qx2_&eQVx%aZ-Rh28nuX)HksG>iYmZEUO?1o~Xp7#*ao2``H1ZW|UH`5*)M#s(~p
zU01ddRoZc={+_I*ycU)icVb{}v6)#*%V&d!^h>q9=@(FWx9zl9*vC6VZuax8z&q(l
zEZBv)qLk(gMo9mImhzZwI+9*r(4zf)`DC^rY5%#U(*9P@(t^GX3AZC5D1J0q8CG5i
zDgNA%?#yEX(yzGKWc96Pbx%n64hfOfBPOdlr3f0dr1umlQiUhh1Nr3W%fiZ@~m73`Un<EiG#S-i`FMs>cjs&WI)vVT^ChRUoN={qAC7NrGc^g#p
z(I=szyJ;yyBQ!Pt&auD2d9hUxSQKj>#Ih}$Q9l8rHn1SOQ
zajcSZ(z%dwW567y7JK4jm#OQFpZ=x6(fdq5
zsoph@law|yY@7@){}(s;T^X2ns!^ZoChgc0m$jm_|BGG>OE)Q}n|!Umqi!mb9>3MXocrKoGkTYsuO)`=y*hH
zRQ$jCq2hl=i(Gdro0_^C`Pcsp;UufwzO5?olhW5p5U|U#8_^$55iQMtY)J*Hz~D^q
z$6#Gep<@z6T4=zU$%X{P=UQSc@4!=OcQe;1>PUmCiB%vb#>!y0TlQ+g9SyMxboMLM
zh+|B#UQ@IVQcMm~;OiIsNR|0gBGPs4m9KBmBf`(g$W0;5ups^iLn$)dpqb8-0Ll?}
ztQGH9!dYwpa@W$$^q>zhYV?1S`MlT^^`I$8DOs=s4k51(v!E2VMe^0sXG+Ti|1wnM
zQMTnZ8PTzHO_N(XqR=f$*W{0AR^J-8Sa+^(fxn&VJ^bC7hB|Yp#{L_FQoNb%ofa*Q
zZBO`A!rjG5ZwlUv$!W8F=xSQAcN^ZK(Xn$0KVy-C*?P+SJTwJxTFCF6Ny1cN6G%)$
zUu+0X`RgrVn6|`uWvD(fuZ)z)?#Lo`{c&&b0){iJ8F)XpW8)?*;6+hp_O}@(y|+k|
zDy+bS08{rggr?QKA|#wDx#8YiN*k){gn(i|2b4KFEOYfcssPjK?ivt!15H+4O;)DW
z%?~LKQLf%SR=Ii%S=CL0HAqD@Q;lARm@67h;ggs$T?77K<6dxykBIXxN?@;rbxp=>
zh+nS1+4jx+ORaJblSin=4LwzjPuNyFRdhWQpQ?#{WZr>_I#Pe*qZ}yRV{Ul40DQs=
z{Lk=Fi){aYA@qM8B4qpj&nJpZ=uCJ?1siCoTj*yqYFnx<&b7qSQa8`@&&tI?p38ys
zNYP(dk=Z51c}oUi-&`s%42hs-r&HP)v1<)du0~4ex>iFHYDMbM&Xoj`%8@$ed;xafEG%Bo1DGAevn^SlaMQ(-k)SbAjN$@a)%J
zvti$jq<}$wdxf~bl$zK?M$+0PYWDA1M$)lLyb;u!e5Sk?EUK}L(EuVdxm_yd-DXp;
zf7=s-h149(W{{w@8s{R3EwaZ{rDNa2NEhjQ;KYjdJ(P@n4@;KO_oy^+t&i;Z)>G6h
zKHRz(n@A4K8GyqL2XOO=GUL2U>6(rOzT%`BW|mb{E0{a16alg
zvw(9-bo!^T+J%=>BgHG3I`e7#hXr`A79gx1Ara#n8zq#Rm)qN5Ek2mRym|phyA-$a6N_l@uJT~&%
z^iM_8?_=dh->zdorCDo&!2=%-;qG!s~^wY(J58W|?N&B*D!f!YC`xj?>>&C28p
zE;Y!(N8}Lhz-G%XCx~9=6u<8CU=g;#-wH{~>-T08Rcp>ar;F8I3Kk5QNJ?#tUsv{~
z2&L?h!@Q&s-S%WFGkdb^6uaHn_tD=(mUtVhWQp%m_LTR#DY3D*03VgU>w8C`T`Qc8
zru7Kab$MM+{`EWmXj;&WbBeFx`-{P})8K~Z8(uv|WM+_DtY8C8Sg~FkP6sxU(#3a*jG~N
znD8+-E1%6Aa_Dd46Pc`L_rY3(Y%a9f=VWtSo#@Yos@mJs1;>YpR08l8OblUzoMXJW
zS@}6;!Z?+&)_YnOr@5#1F45Ac)bqoFa~S0(e%8&(-JAsGX5}62D{GL!&C1QdC<5`q
z%*(!?eB4oK117n3$mHb`jI|Q8J?CIB$r^u6Re882W>t!-S77Yq-`)dDN25TRWr{nw
z%t(;RuHU3)N{xMq2nc^`AV5v$o?$TahBEWKB^F!zyPK8A80wnXLJp!4lEM^wzzE7>
z3#m;VeecX-Ob6_Ew-|&wd$V#GxXF@tzZs75Mc&+2@}Oo)nd=cO8(7(S~`QS)KoZ4;Wj|8(>D%oMWqY|-4s3gZq%-|z}
zcB-?24VXbCcFD4S4$+YFYagRO2`_zGX^WjI+;txvICedYy#tKD*-5ExWjd;7((jSU
zp_<7v(M&oAD{+?(aZ`6Tsdq4`yKCy5fDx7@LV
zDl-RL*Y`H{j#JTjBhEqnqQ}o2QaAS}RUa+rBTHqQf3f>Ms7Q8H*;h>a7hwfV%1ZR@
zjJ_r=qi8MG0@OfMv>qezr$B-%UG;wSpX=&1wG#ULLThedG&|@n
zlPK(x?h~8R*lv)+ucKUCOrrI3Fn2ZXtpo4%L1D7iaCdgg6jCo@3Jki$6W_e_=T
zR8&=T$M4Zo1G#Tq)tRbJ%;%Q)Yzuj;NUEs}QXi|}6v$R?q^?9tUY!V4zacju#mbM=
zitA{IFE03Z^)Cgj<+P}O%t_Y2%<<8roYDHFpjB}P{1KvG3eH)?1l=$;XG!L)@msxw
z57>xc=I#d$q)W9B<>kR?uc-FF+aF1SGmYgj<>XGAG8L-|I$^75&zx#%h16t!xf*!6
zIg>odCNk4g`^u;MaCA7ljOY%zZ$TP6ThyL56>^@7p(=7_e|l68^rtrpbF2zImzI<+
zb(Pzt{wAg(n{&*c^i+}2uGyK_9We7+FtI5Nir0ax#|jK*V0+d50*J~wUPXS$q;$&C
za#DpIH!@R9JEE+*mrXKrDEU&8tR{|oOmX@%;IuQ_8GMS_a^Bf^YQ{~UOjYt2|K{U}
z7N6Q2pF-Bm+2*EMtjY8>f`!c-U=T^nG1$`ieP9iFa-}P?m6`FdfP(lq>KcWdWaK~0
z7)x5Vl>_Mr(^z@Q3ON{(Jf#%_m#G^JQs4ELaUg5%0u48-Ly_BZd}j_ctwuo{g_fJc
z+3hVKj&RUqgTnTw&6m#S0|yc&7@^Er?j^7yggttIGTBEY;okY+w*=6U-Q8CxuZ{bg
zqx;AQb!!$f4mVm|GkQW3G4z#OA~_#5E_iyI2m>a(bNE
zQW@s(adV4x3TaFk163J(rgLEB=AiQY?wQIE8--z739OB_bZ#f8-wL%OoA4Pl
z$lDoeFjwTvu3*glB+JaQU_#uaHV0t4Wu)r|`#MsP%*(XpjIqaiBW8>@JueC&f!Q4Rz#is_{2CMtm;p#vt`>P@m`&hzFyl-&biNI(
zCl)Xji@l)MI>kUT{W3Z!tI2eVYX;{eox_DrKFJDJK)6bb?;(R{s9dIc8<}-ZR*1+t
z2Y2W=M+s*BS9PHb+@fQ*^8Q+X8;z}5`;pqoTr1AD;(u}aJbLJF9k==*o>RkvRl{E$
z9MrneFnzmV%vD4Ok{kanm~a+fBlY>3da6yGid6^A{a?$W5_hG16<^rPp40y8It96c
z`Iy6~XWM+75@8U#Q4tBO=7c34U@1|6)9UYXAOdBxE<#=%^4$y*Y1MA4|6>tIklTgI
z|2GF2>8(j$hqO{tV$!$ZXs6jTRBjHWK4(*;Vv7TbTd07xic>`&8~}Dc>Llzejb*Gz><6(0CIQE5MpWd5BW=NJWapAz(j
z&1S>we(-cHU@@ZG5ehaiQd*>!K-FHZ)!D`p>+m+<>e1hntAF9aG^Bw`zqu?>M-k(4#D^?41aE=QO{>eA60RgGGGHr+8p;o$;aa{XzQSg8fg_Jqf`!b(f<&sf#Sfkf`0$UKYW!U^x!dN#kl2OY7tqY``>8Wp-^
z!_mZptrV{FHKRrJSJ7bboA+Eje-O7%L08YBMrdGdcIV>$2+u#FA}}ypeHo{;aBL{C
z4!5EWc&aRxV~gqop-=3)zxZDRihcS632`$~E<<%~jf$~mzaWuVp$^7UMP(hE=J}WQ
zmbg&`nXsj;?ZJ2_=lo(-1+&3Vf7S)T8D;&O2@MX2__J6Lm5{O6a{8n|RGjq5Hjy6@
zdJsOuk3yzu$uIT^tpL|(P3REcyf2c>Acm5dWupB|BAs_i745MvLfJ33fR;y;K*y|L
zf1BIPlipMl0Q$Vkin@zL?0?PgMi8;lC#)EE=JuZf;Ai7W@-
zc15b;%7GZ(2TC`_(5YGrKL;7*nvLls9jtA~Og~iOGXhTT%BwFH3;akiMbT_#n{2L(
zX0ud@TZP&1-thVpB&UxR`Ku(QwAdY$D!QF~SB<8$lVP-z9j2CPf>(kBU`jd;wVxSWq*4F+^{<$W9+)0j$42k(dF%u1@{uI%?EY7C99>y3=CoYz~
zMv8#yu8}@-k#LQ-vC6vj2r%}R$uG5-E&&4r?t%=HUOT1el;Z=|{9jheX
zAEPR$WQ`Xm+g?u`zR+tba{_vl#*U|I@hkSS0bnfF>b;?$$8tSvHMogCHnwEQSWL3S
z#;SjGuZfL=RBiWT)=6)FJ`x|J0RO_{=t|>2Ixaf{6dUAG5I>NmLw}Dd7iSqR7W9D(
z@XYtyL%hYv4m39Y1rdF^rrE=!@$ZKRqt+$%nL*(aV;x9d4r(dN3`s==Iy&o=G{wR{@)BUTAH
zjr+2JmJTU{jRU1b(kZS&7<>-Je~xx2sBM
zb-&qa$XT_&y%C;>{8O2FHB2B?ioH1ZBcwC9p-9;pf_^2PUtRCdTDh|{HmBTg3*J!+
zI1d?Z0jkDl@ZLa2{tMLy*`B{!U|2aUvPjr|Oe}G@hKbv40$x5Z-+_m}GO~~CNR7+f
zLdv_?P}Rg9%ddMDGx$;+*Ju{U21uOmmTcGuWj6JmS~qXy;k@zQv<6PByzAqb9^&ux
zlF`%6mmfxGW*c_35sf!Da3M>Kc|YtkEsH%?hY^65eXWwe9gxS$WnjBN%fJrfT}9av
zX|Ge_N=uw`;}t6gt7Q4|^{v|LHOapsNzhKhtW`Z-K#c8M+!`jYa!wvM8!zqv0$jWi
zN>ljtMv-O+3K31-sHJV%#R#8Ei|RWWlaZNzv+Fr1Fz1+zi;g{NM@y~Vq{Wq+;!vx3
zb?hq&FE=alngBVCwF*)HW9ggo8WB-XMEXN8Z3UAw$cMLRkEsb=GW=IKK|1X@!hY}=3E@-FT7+d
z5HF*5L*%3;J1~-rBBP5dk%e`OPd?Cf}7YD{3slV;24!u7IkE#ihC@tGGvo38sL3_PVRKl3w>qd}yz`#~`sTGqezcy<3wv
zHOY}{e%+JC^eZK!9Np@*ECA=SY`jc*C$JD*HuL&Oxrkbk^*qz=MmyjAtdXMgZ3?S3
zo$tVYse9>suP3XhU{iX+`m|IIOc|(k%GebF%A3_f8N+6DZ#rT4fU^jKWLN)WJ|ed?lF!
zllQ2~@91dV$lKbKO(vU|vU4)|UGq@QpAbe_4KTSCm;{5fgeuA)Zh#UdW0hp*US+3=
zVMm8-*m;#S-zd`+8|^}IQ?41dsmF;8-KRNJ?_k4cJiq=jI|%QuRdS&*Fxv(F+Y!yO
z)5QPEiaDbB6J0k6p$}+L1Hz*6%Kg)-#R21)+e!W`u?~1@ap|f{*}S-&PXB;v81d~I
zCwM+})Al03VrZorTys2uUL5AwX0k$WSqSF=2HhY?$lg9&8}(e#{W)#wA%ONu(qqLN;Fieu(GT8L;t7nRpEN>3fSMp{}4vfVmJ3mq^9
zq~v~h5Im=L(9bfP^yY4%nbU`!A)MjpQ>>%kVF>ByaYLBlL$=$y_!jEiJ5Q)^Fd(cQ
z@f>qu+~N+_kz=U9Rn0by?2Ip*Z5oMoGwok|DI_Up0Ab@S?ZZH+WHT~$}v5?w=%%?>b3TbSn+6IV1n-c&%Wn65(X&6lja34A2HJ*mmG*9#A$
zv>pbm@eTt-r5%bV|J8VV0ix2@@TXPU8Ys=np|s1PVWYHMBvjhTAc070idAVKEB54f
zDB|fKHK;V&mQh-c0`R?6aBGwXe4wea4
z@R!CD+D?sx0~+C<8Xf4!__dZbl<;;T>##FCOsqKAfHhtrAjXO>RG<5kH0AxgLSjV^
z{z`kj@#sKq(q2!1S`obf@uoD=@E;Toh&)UcyYX%ZD>YsPeo&%2@#H_?w_PT+aJ%xj
zppE<*tH18%BjF8{v
zI6|q<)U;RdSK3=n&l4$L07NO?)_QqIjNE%jH93%4N_+ppqYH&edzS%Jg$x5k%RFtp
z6f=aR2%gM8;XQ=hYP@3nAX70sjX<0KEYydSEaknqt%%n{e;vn1!W$-Od*KJu5@!Tz
zzE;w*0YTcynwISce)Z-f;T^$<!SRsmMn)w-_~u^LczEypvED_FA)~_b`k<
zSP?#|V|XW9c=6f<@|)|@*pWcwx-@nW6G-f1R7VK(jyG?di`Uv-l5z3co6eka>JCnJN%vBaW0G2^Dr0qMZ)rJVRm70O96tQ5JGB`(eE5}pC6hrI
zfSJRGXD|oZJ{4Uyxb^CwlhG)vwVE$kea9A&lT{2tFx`OjWx$%=;R8+r))n#?Z(n5{
z>BFap%;H;=(PdXTjP}RqxGGzpH-=2!Y75B8D!5&Nt%H>NzVIka`A=
zypr`LN_~%^{*RCJ4R(t`kKP{X+YiNL$$R#2NBIrNdzxlQ3u$We&Z+!C*xv#PW>OQB
z7;hdKO)3jOb~Um;76+lJinx{_qub;~kCjgL1rcqF|g=$-`OZAg1J
zyh%0Wjw|04iYh7Kdj|(v%^~3X>!d1zxMB{4-|r+c1HgoRWgXTW3g5&Wa>SLru5jw1
z0e3wjWb=KSeNKznN7=OVH;-9jDK|XA>K+Qe1WB^gKj~i%Q;q2FSuKG2>tV~v$=IEk
zU#AJ1lc`%-;?mLhuyxkS)Ol*eGsSLUH~bPArskQ!YW0CP4>Gl-zR!t-TqjeniFiZW
zzXrBuGBWqk-4@9R%>YiOo(5*KRC4R(j!L>AlKFpkA>@@v0atYH-f4woXeDv?PI3VL
z$JPWE`zTr+do?L`1!o7ze#$2`eT-!}r>47byAb9!gNRUqto>X0R-*u>1fmVb^kIQy
zN$*~C8Un6%Y~%V-1I9Tk+?Q$gMK{nkPvEU*w8T_l8|hW0{We&Q@xR0SEOl?=GPR@2
zRN1yJQ!q|w^ylKl5~v!rm+NxV<3bKwDA)jptNsX^`&Yn@FwNr3KI<&-w44w-JHu`
zqofopAci}#KnQiQ5lj^wwgRALWrZy%XT-V|yHFzRzoV^KCD_DX*@@EkDN~-OhB-|k
zn&KoBRc29*oI>Jy1X7IG6sOx1I-`ucuVf1c2+WfB=i$ENDH2|QN^08eZCYCzrkaEM
zuG~dFnQHD9+~@-r2*?_kXxaxGSh)7~ksk6{iTH1RO0
zgOT!mV6#5IbI3cwV%o>PS9PMqfU3F*2qDes?JCU)hWH;(OSi@)9x#=1Xk`jDn$mol
z+Cr^X;Ad9cdQW>#_5!2T9z1gdIvRC1apX{k@9kj4Vi_-A3v4jD>ulpifen_f>c%D*
zZ7D)!^ipQH+6v?VoNNypIwZ3d?i{qj|Cii=hjsSfomO}HR{v=O_kOr}a&Nm$6P1EG
z$rwSkz_u1U<}BALTWfY7vo*uDCjJ>9$<=nB)
z3z$T|9PP^?A&cYee&?JlUW&8tHL>~P+2$@
z7JI2=^h)*UL!k>Y3q3~iT!5SwL^eRrD;YA6JE-Sr{s-zPG{O#Q9qcRw(ZcMc
zTKqf|uh2_nvHAW}a;a%-erDsc^n9nP2LFQ&(*5BM&6VLU&>Z&jCXb)nh8ER#iH4#V
zO(OZ6MYI+ULD<39DInDx5xpQjmUf41l({v+v^C(j%9=U
z<-Lt>$RKA8Y<7+Ll9ddGWv1;bAZ?PQcaU4k#ZDu1(!Fw?-G&xZgf#sL{P(B)Tt5F
zAQ#o$LCMVKn!g)QT^MfJeA(<$rXOaT&;7V{ETg#@ZxSFNNOR+Zgds1}Y_=H`=-N!T
zX7@1rhkP8=C?9Q5h^=^XdZmV*jdmL{UYU*3_2!jEGPEU;G0QRu(Q`^h&&eCPH3ka&vgD)3{ez0`|WD_B3t+V!^$h&2+C>X9iW6^iHpL
zLfKwT+)#F;i`qJZ>gJ+;#R@52$FKaMwSr+@RMlbUv>3=eM`3YCJLB_1nONRl0vH!E~$QQcBnKjha>~_xG
z9cihT#s!{eMlXK`yN>ZOzUb)X2TTYzI(m88q(x_-Z1@RoGRe^ynRRNQ
zWW@jPo!GF~2G^B`xu~rpsKGAk*Y$3y0WNA;1l89?&5xk=cTtZ-P#s;=xCm-X7j=0A
z^~ZOPTqj3R-?*qlfI=Ml*nPK4g#1GnwM7KA$VIKf1w*D8D1g2Y&%wKPyKV*35b<2P8wo~xg92f;2GHbos5|lcGG+H
zt?-8af;Z_+@1v>pw?*-M6B#x2IWY*i=umR}mp!8WQyHaz=i9P#4p;hqssdK&NcLb$
z%ut{3T7HdHvk4%{V&Y}&p)t1@CB2`%a*XYOKf-D&eXRuiMFN%X!#X46Z&91ZD&Ub%
zls_JXgfNpF;#qpoMt6onx46G%6Pm29xJ!Vl$Br1LSZ5@{zGrYLBiEjaSz$2#q4Oj~
zCF)8h6xpsLWl31p6pPX|J8y_ZCA|wi!id=%KRBJRyK5dnP6qQc$q?5>knLVUTG)ad
zKaguTLC{;givK4Kj^DW
zyc%%Xa+FZUDs@dq7elr>SXE{An+@1j>+l~h`)uEdOoYom=EzD*lMnc7ZY09OkGJuI
z483A<5cX+LBfPs3)qV{+B6Tw`uToyeja4!w8&g^SG`ZqZl1Gt~y64u&clHZS^3XK>
z`*>I^Yv>rIPlsIG#FC-cj-Vb+804)bCU}GJlmFX8B2$iYT;zi<92eR8*U&|h
zUbTz*^%ocQw2N96LEY=3=0{KyUDP8$f%#JR-Gm5viHo|%L5cTfF3+HS=Z$3p;Mo0g
zIQ9)VK2)q%Qu(bKbL=;8YZ>O?!|f$If3ALOKD79RliGah>u&QZM^~i7cZ|MHSLA%w
z=aw2Y&I_~R&I`CGx+EqFmmubrsU>o<3Q-v6o*|reWH!AIS&S2>{mHV?8gngJ`K;er
zET)B)@K=F~>W}#hLU2Y0B>n)37%V|XC-H794veG0X~_dy2fDo96hNscLUcdl=nqA8
z!FXi8a&?JGWW91m@v!R1jjiOf8BQydnuBCxaKpSX%<0FwnW^;nql>4DjtMwVdLuq_
z%=*yPq3t#()F7=4woK`*8#9m@diz=+6qjO<=uVU99}D&D_Kr}m=uK;gA5o!J9qkA;
zeYqpl1^*6(N_vxA)G-m%tuCr-1a*arY8^qH?V|qp$t|ncMJ)#kZrsa#myVG4a8XY=
zsQ<=|*Q%CTOFOr0td^SaW;xf5&oT|R`AESxTZO63HQ%-7RZZ*}xME~PaWV$hWwB>4
zntw*4^w~0%YWx)+i|m)>uXf{9ecOoN+Sj;Dkkgith0te8hCIU?-NIsap=CuYFG(WF}t1o}%u3|51TGHRuVas$!|*`7J^%WxMx-wc+Z=
zB4zS+n*g^L+$amn3;pjw29XwmANCi6&0?)WUXtFCpE$NXc2#I^4YK)^>Vs^yv!&*Y
zLVw~SGrLIhin94#b0e3-=HU&nIrPXtWmpHr#o56u~X@ZZV7r-neFZ*n58{|pk7i%&DWxnQM(9Lj{HpD@|7Rl8io3uD<2lTN-`qMkE}F&gfgN3NwG48KMS&(6^k^SNfJG3RQ!B%S!?#T6Pr5Xy0h%%AZl68cx4dQrs=fWO4fZYXGa5(VvKTpqeao|+kiO+z
zN5FPj@uqJ%ET|!`v*Ch$%Ql43w|o)KfrB~u_{o3lTNdDwHn{b~%qFWxAID#A!ayPL
zmuLOZUy|NX7d0t@;&>%Ub$tYNq>DN?g6ig?j*OsocTrt{f@s^h@7hGj+qtNkc~0NH0yn$aKvYh@OL^y*1W;sWZcdsDl3cO!+ungv5fHQEiy!i^
zWurW-%$ukF22z%_{R8le#80(_LY%w3+fYJ@(ek{%rqu
z=9la@1p-w9fmL&yS3bF!$d@<*x{1!4G=qG2Hzj)ca&{f>qvcVa-EGl1?QHW*dCrCR
z`se*;TwUEO!qu&-*uO8iDUPe?41I*Ip}-xULM?wtKG
zl;rHq8mpOJi!*9w5}HTWj2VpW=%hA-vF7HL?5j;y43a8t5wPLLlm4Y
zv&iC^S;FZwn89#iS<1*Z;N!JwXuucc
zH&*R2T)S4Bij@aPJRU$>!y4LNW5^y(>Oy_Bt$mfEWabJWy|yX|?%Tc`h_f>18tcIjdq~V?hytfF1F@6YA{S|h;rVP*O;7xaN`@~
z4CfkNG;@S$6{@#QEgLjWrv?@)W;cUrxbuOi)65w{AA!v-kO^;bw@WRGjRxl>n(f<|
zs03!2e;OIF!FhMG83gC(0QLCpfj*Mn*6%p&_M#PGyP5QMby3qIsO~N*8A0vqqJ}%D
zoDK0)%02bo)CfYA!Mig8{&%?fETbX*0IQ0W+&07qyq3EmKKsx>-Ude|XKUq1{hMra
z^Dzi~5M$cjlN@5x_VzNbgxg5l`+Ly#I&=H`pqg5-ijO=L)t%sOC)Bv?c6tll7~JpP
zfv<4Kdwpk#DW*~W=r5IC>C=8anqz-Ia0efVHdbe2zpKUqb2nAE{#S|hKa>{zFrKde
zEz5VYj7>&z73)@R&#}d4Q!ma
zmZLMySfvW*y{bZOI1zi#-p2bZ1+P2UD!90zV2j2koa#J5KTVSzZOg1SQr;i9f{wKhKRX;WvLS32ntnHf10u_V&{8^uCQOM0`-%8haFNi(D~ojaUh`%VnE
zseUu{Ov4eIYU}YeA5N<9HP1EaBxrDI1eCH8guVGS{uK!6^}D)lq-P5@hcjRd-QX|&
z*$_2L<7Ef^FKK*OXb@x8HKy?)3svK$IXlB4HqF^l_7$45pj&#kG>dXKu(W8!$1uElv+Ok|@i814nH=+-X_6TCju
z3_92hbcNF24{GwSLh)HbK6pSNB<|-*JB?Kv+yfA<=`M9qYd>*OZ@Q>29Mu2JS(mE}
zRO_*88dK}u^CQmM(IGa@x}|xQ!&%p2tk5RmM-$qiQTMowZ<$d=8Rc
ziK84C4BbfQ{ZuLMx0Kd-#l6ETdaLv6y(*9*P~aN^D+7;a3v4}lgbYljdHlSNT&Df=
zt?V|D{sLfo|
z_aC{b)}T!fGJG?F`q4$rjG#VsQ56wX+C|+ELA~Ij&WoTPc2P$~P?KHMUO*M&-dOit
z+X(qM7q#v~SJn|O>PrXJU}yN5U&Zj~XICoNKsTg+RoE$)5jpN3auQ6_KHfg|73~qL
zCzGlIR}oyp-`&ufVtY0J0K?g)7tZu
z!SOb|9WZInv)^ZbZSp@u>MY~jGUPGob$rFKrCUA-Ro|d~=V*D20g21
zhx#?Mk6-*8%6gBo|E7Iq^jjhN-4%@I(r>@L1N|nwOBXr3zxsa2d(s==qGm);eO*+_
zK{Y7xtWe?|Ew?!(-uR+KwP2+d+c7vy@K>wUcI+&dAiJOH%v^r<{-Ve5Eta19Dj(D+MKLE#k}%AA*r2udV(3*NSd*hUAw!Z{$cYS^&kC?
ztNu|gYM%&dh>L0!L7n2Fet+A|@NgIPX#~~PMJ%J?GkZ2i?dp;lXi0|;I?^A1-$-N
zs4wwdOuaUKg^j~uaibjW1r9SpV|$YTJ}O5pM}j1mzdp2U!0$g}YDlQIS!g_9l?|wE
z(z9aTK}%x}UfgUFtsoy2QPj<
zPCF!*Db-r(Q-gCv-vxLj9qh?lo7@PwU`ad1G-sG9;dP{L5zds%C
zvs~}P&W@I^bD26W!qnh@a5;j*;oCnnX64U3mF0T(n*`SN)`29K>+Kfu`_Ei&rDn{g
zrhB7IZHE%!6Pd2JnMw5DxL*2uqXm3F6B~y7Ke#D4>Uxh_lBnyQR~&J@n*%Dx^>%0x
zalPYE0$uM43|ynG*T<$#6~(>*8&?`O{E8=YyWYZ`9HY2wj$^5XY1fF)a8cVwP)E6_
zO*L++16Wv7hg^PLyD7fCH*$!*>M#wj~s9PLVgV%}WVSaFhnHxNj34-1K
zRc>AfMe^#88FWlPr-1qtQ9q~Tv
zd*44HxRk{HrrPCyY)}E}^xY`o4b%*S;k5;RGO3_DH
zwA?dyn)U%Ou5MfT2)v+2?Z_ka2D)7WOyO8!kW)8Y9w&P)@VV?(43)gHPD+v0x!#v=
z+EjNRO2J2Vc!%A|K@M%lJgj;5&dU2TVvzTT@I9ON3%I2yBk!xvMtJROGVT#(y#9G4
zPZfUqkmiDo=H|oA+_vj7w{Rdbz_zyzP!?+~a`Y*-o#T&<1ec}oe-m8Rebtyx9{E_L
zN(N~<>BCXjUCo@+Gg>9j*t{~Uq@__?c9r~EsRBQMHBzg#(X8mG)Tdt6V3qt#m7%(`
ztK?&&%p;tjtW1)N@iLCqJkhmf0%fMq6f6-Xgv_=VR
zQcV!sN7Dr!^Yal}H7{z_++_2TsyR25ZutYMy5qA{w}=?{-mrs0)g8|YXXU$FGf1==
zmBaO$x@W@*Iy)@oMJf*!RGd}HeMYUGQ_6R;dpSobC!V9F@DuPN$dO?Yr#yoqQiUz<
zQ?C1B*-gEuQ%;6=A7HXVh%09u7iPL0HHNx5
zG%M3h_o^<3I+-5pWV-NN7<*5XBfiat8bfQJYWwk1QWYilX!1FK+N!`=KW$>SK26=^
z<%e=;-rvS*-k(^F0b$e4vCh@d@pH^|M!Y3Q(Idk?l+aOASu??X0I_%01>vm?s)
zTjGU(VHN(&W}a8A!k_J#@vhAH4rJ^vxBzO$w`?}mX0>+%LYD5L5*y^fA50E#`M6=k
z@-PMWPBf7B+SXQFcva`b=nd#-f$st6PmzDG$CI1oC1V>BUKap(hmM%HFF^l#mXY+X
zzp+VPuv@Wum%O}ewUjKULB-ds7T%UElV8n##;G{
zijsKvf9yt$7M+W*oF
z*_V?4me1k+WTknO@OXtU#AK*{v%*&szFOf&2w$x5>x9oz_(Q@cD*O%Mz6yVjB@F)%
zg?}f!x57>50NzRAZ3%Cq@GgWmSNH(J>o^ycD(XY{CxuTU{I$YY6JDzDt%R2-+!3pE
z{sM*fA^g0;hY_Bp@UevNRd^ub2?}3A_%?;FC48;Ial)4=JcIDL3eO>Yio!L7k5+gk
z)+zkM6kbbsKZToNvw^>h!tDvSQ+N-;%@r;rypa=NsUm(F&i_T>Qwe{s@CAfFRro5x
z?kh5HizTH%ukFI9Lj;Ux-RNqB+6cM^VH;RPQ8o~H2Igzr`OGr|)Tt|xq(!abJ*
zzE#X@Job0Rd_MscNFgU72sDCev9yIg_je4LgAH!A2jecfbUfJUfdey
zk5%|_!Z#>fMfeJZ(}XWjcq!r275OR)h~xn75kxdn>#j
z;hhvNBD{^lg9&f0a3$e&JBsW(;(A{HCxyEb{#xOlgqJFO9N{GjpGkOu!j}?$p0GB#
zW>3$z@4Ibr=dZObMyvj+^u6MI1Fa8u9P?-|zlbTEg!ecxrSpZBhX$1ft#$srpw-;b
zFGWYp8yn{Ce>y6_VyHmur6Cq=erGiPZ1c}#F6Jk0Dd(#>TcY48Xs^4FCaDkXMTvJj
z6WnWwoR3DHAJ)3^tbjwXZ((R&Qkt0#4er0V1L9zp70*^aNZ2_881F*yQ6L|QcsD+@
zIPPUYaYNj!;w-MXr;rt-X;#;}ycquvX7OL_;Ia(V1>4=vX{cBz@+o708BZ*FK?
z0bW-wJmUL;o9eeHPQS7V|G=V@t<#u?ZHZb=dhZEgg&=|t($=6dS5HCb?W(Y{Fc>F$
zpSZGkZ-NNJnRBL-=d`~OW@tn=SAAUeZXk`>*r7aRe4{o#>T{%w9F5pxIi~^*LKCT;
z%;g`g!ki&SbBbZ=XXC_-`suFqBM())e7m-08qD>w0vy)7cq4l3b%XiWus=?vJ@uV{
zeg9+XBH^vL8@VUie#M6}RHn3hhO|)M8^HUA-52Nsd;X}tdqb}MpGF4Q@rwQS?Vvc5
zH#QtI*@a=Un)r#(6%5cjnk=LWpM@Ay{#UnR?NX2hv*jTJ%Yyj(?U03Xie19Yt!a$R5T1m)5d$cz7^Pm
z^&TxM`i19sNtXBcAB*=WLgkEj&--r%IYZvJZdX0AeyRz(_0wPLM;@wp@t(4&@Sd()
z<@6q$`l7T?hwLL(=luflU|SDP!qfaTp?kw-CUiF=O)@SIhVFw~2F6#Wd7kOysS=f|
zYG*77BwBEx#NDD7p;*6~KA4F2LCc1daK(J2<1>FWAwOjhY5%l)gpL?+pbuD!*Lf23
zp(Q<{EG%_&r-+9XG2cNXy&vvE!cu%9b<8|?k;!7JQr_iIrizNl=Tx|_A-Y5p
zV}>_Az_%5Wl|ib_Umyr2M<&0N1Pq%C4(5kdP~&}kr`&NMBX@I!)&n8l|9N>V4u!-2ycS^mV{liU97^%BN4CVFRd)oDD%u7G$!*4NhuCtg=7V(
zNwg>>HkWLD6DjwBgqF*&atGmzutMJXeRwv?R~cG{l_7>UBdiFys`#;d2`jyXutE@#
zuyP-oc>l9I16lg2r5xq5*Yb}tvgBO}T8$cdsC69rwMHrvUfxazDzM>2i_8cwWm(}R
zfjzLW97U+|R9~iXz9!5WocxOnnR+^3n9GAPO2dNL6|EGCL?!H1qJ`W`)!GNCS+FKG(mm*NAhrbrWNx`a7{
z%jYY>W%tp6C74jNnM0J0uRxVha%ALNFxhrbDc|cN<;$7v*7s9dp+V3QQVBYQ=o6*Y
zEl|%bm=n~RnkzwvnZtDCkt%!y{1CZ0qi?c8Qz}wD;>Rf=Ip{{;grA5GmaTMrjRli!
zW74(oj^;zJS-et%KWV_BkP3(LLO9$C9BySetba*3Wai*d9;w0-!{J53NQI_Uq;hz?
zawz2BaQThGAtx+NSez!?xFpilc-81J;B=%L7RQEo|I=YXY7-W_ycU=mlC8-Z7MnUW
zxc_bp$2DK%TlVs
z8xC4GEDpz%hN%w|7H7W_sKACrEixl4mS=^dg3Jr_9EebSeRQkMz>Zy+4s*&duF+N1p#IMu1*LJ?N<=z55
z)Q`tbV5B3yWWG=p#9M@&Ds%l(?=UY!I{$uX>cnt5!8qe~AyJKY5K72!#Uv)&l6+xV&2bqb3>l_-i|F?#fJcO|8j2*O+<&lVY<}cNbamKE0R`EO(2WKQ%
zE@wPE
z?qVzw<%}~{y0Wx9MN)h9=nc5e_zgpZs=zqoUJC<_TW8cFGn{csmNR}QJ4)k9X)CwXWEh%?3~!^HO5w4sqc$`c{`aK_V+u`c)WKGBN@
zi!(m-XO=UL2vdP>55pRraeKmW#+S!ZQQj8#89JlC1BUH&hj@8;erpckle%;T@h8C!u^{dmy?${#9i`ec&c45`W@oEgc_a8{c%i#DYn0M|Px=
zePmXyc7e31#G(ZjB58r;g|xs;&;lcG5o_r4Ld|T!y*yHd6YgO}rTwqV`L;q+DpD=-
z4MAA)TMYRu=dDOIVJswiXj~u>?iHg%TSO!(vtp#<dcP1Pfk$g?D9mR-0Co-}i(EK89}KHDKjnMYrP{M7n!)f}a6J>RwdVaxz@Q(I&FA<7zxH~!UPW#Yvqe11AF
zNLJ(hhW0oke9jH={?-=;g_`hr&dWh+aMLVj`0Vb`VE*%_P@{Vg4mFyHPf;z&BN4CU
zFO|`R&mZT8#bHuG!zalKQt({s1!jns7jh0in|q^{%kcRO;f(MpnVIl8!O${%-ezbs
z!l#gH&Afu!d_j1o5LO5x5>+5`1Ep6YF?n2A0Bops-{?b9-BcBEd
zO#t;@3Y1_2s1}+LKr6EX=%cu|09K_4RbM24P6%^`KxH?m#yE#`6JfWeW@t^xqo>rA
z1kj`IKmhgEB7ovEP?&)|J$sNhG^|4e&~1@%7(jPFTLS30zhni_gTho`=ez5bHO_E;
zLKv2QgG{%0HTcPY{s-Zp8u#GRL;f9#hmyBMx2ISBNPII~+yU3plIG2j2GRJAvzp|=
zu6PfhA;XotBzx2$OBKE|3M{0G+9OAQd~-NlI^GQp4A}sKdD7jIH~4h{y9{7=$o&i&
z-Z%VNI$y|TRfQ1oPnJl%cMtQamXvY6L1E)DOXhdhOr~ijLMxdF4KleHnLyN?fG_jP
zNTtH!_H|0}MO9!)va_m?{h3XLXUN}U@z<}r5{2>3CQa8~(@k^ICB1=^9$iaT#tDQ`
z@Q=5Ud#?w6sut`FAasWP^1y{~{H4X2
z==ko74!3a@ht4I*a?PuM9Vz$zYgIHx$8y3M(NQup(Q&w;WpupA&}KwOA=l{m=uZ+I
zdkSHNAR^JR3F^jQE?N{n+@$q*WQ4uXZw5=L!aopQsPy%6HMEeMnE2rff#^0SYEc<6
zaYj~5EU%WBs0dY>D%Er)JZ5_aq7Qmr3(sNy9icEggO|KV?liP@`C
zW?p@OQ*){K3Nx>M^k~$e`Dy0WA6>OUmqdM?SCxCgi(a&PvcFt_C()!17LLdik*
z@X&x^)7!c{)P0S&5siIDZ|j5*?^m7~q&D&7r{{v2gC08Mj3-MRnxyyI)ezpyNK_Ga
z?RB;CFAwa}<1ei&6Hjh&vy$QvPe_()uzKh7A#Z30Ou39FeYD)j%n^CFGe?~bE#pZW
zLz@v#gj`j8+DeHh^;c1t3PD8T$t&nk_{ng}&J0$6b!BP!n56b5gI2?Z_O%XqFHnJr
zD>uyyq_S~Ei_C~CGqd7K_jwXm6rsvf<(jy%OPDj{?ns7AJ+%_%oSCCM?Q6+HD?sAP
zvT^WlZ((uayo{fwk+AimY`4{4c^V?5$-M#ybl?
z`7bhaWWvvFP9`e&JsN)AdnQmRg4>!ffsmw7|_$XpM^LY|Hk3m?*UUnNA&FuYUPO?DE)*E}MDi)kRbJW_>E8@8@uA351}nxs^udeuNdm^W$PzbN3y1g=?O
zt<`ujq|XRkcZGQWhtq=8CU6x#?JBWz&cM~$p-Flzu28FEL%Zo;fZf2=S%s4ab_elS
zByiO{6&8nmO4<=3S+2nKNu=DnSQf0Efoq(W8wp&Jndt~!VrW?zXB*m#z$N6W;`_dn
zz;&PyRtO>zxVA$N$$$UaKo%3Y4s+RSx$1JN!ut_j4>xd)ek(|30@tfg1}dy|kZxD=tviv+HrVb0*>LNa6m*BQc`6S%r*J;|e|)RP3RPNgvVSL+)KTt|g9
zh`{yJFgI}J^^?HWV{lc7T;v-NsY~zF)
zb7zuBmg)AsnFAQ&OXdqzuF3QKFfR-j>#?WFZ+(7XCdREl3x%!muDB-4t>=Y!ztzb>
zYU9@DhVnsGU2?khVGd2wJNUBDT)Gf;-MYJ)i#)KuBg?J-JtI&jLK}-ie}rVY+`37~
zIqHAjP%W2kJ(F<8_(n1_Ze4C@>DFTmZH8M5xw`dhUx{0vErb<pR1oA@}W<
zhV@iJ*sZ5xttWYC1&CW0-vSd`^+RKB{jabF;nwYuaX9z0*RkT(7p%x~>qEm-V6E;F
zWo<{mpA&{#-^^)>w6_F5#jS(sn)}qJ2g!~)-5R1&8=wBnkvihjuVx`kR@*pPrQ#)S
z_vJj+vcA*q%j7Z8$f+DPMe@ER%)2H&(s(&@f>oD=UOuaYUQT?;e4)za1@9*6&NNv1))MJ6oL5^-Yz5FzX2J62Uht|`Vuxma2
z)q3QSh!5m1)ea51IOT2WW+lbJ%So2Y%R7dg!yJ|l(Q@hKO9*FpIeE9Ej{lFZD-X14
z`u>VT$s=?tV^N5tzPMy~NrpnmP%=biN=O+K@l;pux$aNC+$7%yAt4H-!mA9umpK^<
zMTm~E$Pkr&pU+zBoW0MzSN+l6=d88YUVE**KYQ)rp7*5ja+HrZ-hxps>^jOnUoNBk
z24Tz#Au-CYLbwv9q!-GzgpKl{ep|}gO6i~@c>Pg6|Ml1eHp;htG`4s&%C*XZQNFNf
zl)uVFZZ@L?HJ%#RRvl9xi6x`mlP__88q2)zr{3x(Nz?%{%KP4eF19u1-haQwGt#M#
zQT`tYcBA|_T=l_#y>(g9C_lrMf@)iuY8>T%UJTVxXpCH?2v*|JMtQg%6RMt%{lcl$
zosTuq6(ILV$ZK89&d0uWRtTGsQ4UC^BYX+ZxH@)*osZ3N%#gx+`6h5ml*PRsiG1{Y
zZ2BW`K~;uSEHQ*h_8H^_I^^*A{`uHR4+uBKLVHPa=>fOVOSR#vyic6XYe^+)cYHz!
z5&K2PexLVNTJ$Z#obdLm;uhKY*s4jc6X51#)C}B6v~2jS#wmP88|1Z|kI4)Fd~Afp
zSPat#Gw*tkJ0H7rw6u{Gp^cK{(w`31HhzA+v{5B1QQNpc2od{d#y(BnrnZy1eD={E
zJ50B4&$!igKK2W)b8)eVXbZ}|#^3{d!~dXeydM7w-h^km+d77wFS=qiL09k;EPTc~
zdiZnaxKhK;qbIsbYcuUjVrNs2CmZb42Z~uhy*2aBqE(ssYC=h>G7I^Xz|MCjxazV}
z9k7#ZrOwAzB>Oac#Lm9PTY#Oyu8y3v6ei9FM+jqH2np=$
zhTtds#BG(?`Pi|(dZ`u?A(j1j5j6|;;FIpz44W4l!O(Nz_}B;$dTONw=((r}Jx4rA
zO*2YR^Ci%8fRhX*`cW72)CHoKxAa-0o{~geAn4ihMxf`y&w-x*dOmiN^C8f4?S(#i
z2Cxk}ZHFaA=()2i1=SXy6jkGq%pB%X=)B8ls9-W4`7eClZFSiB*n6&dsJRb%$LYcu^Yy9kcr_X85d$s4FE@dDI6;SLVW
z;5ZV8R|~uB)G){9WOdVIpp(;F=zQ!>uUs~0&(@nW4rCq`zatwg!7g}I
zD`adZALnE3ewAJry{H#1nNZ?u4=VMIleC)to;)!&S~_Y8e*ba4R>AouWZp-|fqMQT3I19GpR_uQET{RRGOP~h
zNVZbvW3PI;;r!d`B{~k&dK241BFxs0-Hey$c)alzprf!WI*yQw*THVWm={6<9s9yJ
z;Y)5mZj)NRMMAxDb>JW9^ECQrv*V^4CeFa-t64F^M6Id-6PFfY;=sqGH!4Amrbe}h
z@;oOQ?LGTE=btXj`~Im=|45>S7fft82qSgIC&0viJs(SZp37zCuSN6F%zgVJwMRQ2
z8}YuKk1Zq*0%0aRAN#)@;=T)L;t)9r$6-;&%4H`0rZN|Ei^LvHX1hq{6!K&Lp78Wz;?gz%$2ol=woAzYc(cco4X*3y9DF(R
zzJuHAq$deBa9oRQ03PIvlIpmD1GZ92yJJ27WP|nRXuTYOtC=qdPpEqop1fzg9DuJG
zZ@~Z*b{&9Q;`_&794m}@AtVOicW`rfq}w^OrQIaIEoEm*>7W|CI=(bG`R0Y#;x-Ul
zkB)mtG!V7Qf`PcAXdte7SO%gJ)Od-3_&%=eTHix+-s<7}G>>`TPhHeclBfe@Adb8m
zU99!Tn_JpVb?Rf@>;b`UY1a>35~K3rcZ-6P8(k@=*2+|4aI!n|C{*2xh6?KAk^jOL
zS7Tkr$uZmoISjg`UmyYFF?bAh5x^=&Hwq7*kd-r<~XLB;4MT?1q*-&9X=fN
zcs$u)$L`K^0rS4+nyTj{!TsW*5%#uRaj`{?REH5pwo)VPi$uK-o~`wAgyono7-7^s
z8evx(FGpA(<1H9r!mcCiVSJ?+jO~RnFNDMhy9bUAmr4)tH%~hH>XrR^7F7x^2CqND
zhCd%$+(y_N_(hM6gJ^_ll?5X#EE-{%@iM}cpvFs#uxp%TXmSM=vhcr`DCdR$t<+DF
zr~_n#?b9D!?2W~n8(}9q4`PJRarjtEGXbC&N$Q2Px)Ur{rsIWIZ
zjoY0%F;3Bm(K`g`;)K*>u7j80_q=dJT`44oAjjiUSf$V_s)ei6_UHz$3AysEuZ8)y
z>k{`E8{tbFQ%&$4qLzXYKFiU=2JPe0Hp0(!O@ozsmK@<}j|bn0Kg0E$7R>u2yqoqM
zNw7UyG{V2XC$=Qq$LcV`$yREFZ%ouXtDDx#5&jhO1tVO9SrD5wUXJkFjkjQg3%ic+
zc?)HP_YlUs5E3JN=D8T*f4KWBHius5t5?=gN(WWo^+))_(_)L;2w(Mou?eCPu2mL{
z@HIsv{E@LT!j+)LON{WGlZZ5Kj%S=
z@SPyo&7m#Z$q4UNTQtHCcBP=&%F|ReZjUZy9wYqb9yC<20FV6VZdBThj5S{4wAI+U
z;y6Dh7uyq|?{o~Y_(sOv^qIb66-Nn(2uPdIhdiO#Jj)`fI#_RIUlmMMzYDNBcQ?c*`LWrUo=TdL!$+
zS)1uy5|1A9c(TESuG*QnsJ@SRzn>3gt8n_vq$*RvM62V_L+3fq7bVpJkH}UEkFJ(`
zDA6A5epWB>Xg94lv8bl*QN*$S6xESN1qX3VDT}|9pzdBqajCmm>@FWeK6rgR+VQElnBmbmcf}Tu@JOpHz@v3Vc(gNj#_^*}A*k`xxVE_7
zSQSe~yZ=1d`RNDdeLq#IpCnNS2p&D(2czPgH#dhzOP%@{3&SAT;nDrA1&`i&wFr+U
zxl&N=Y*Vcn@?Dt60QgSs3j}FA@}J(d2v5RFN>6N#;hM@t_Lu4siz{}rTQ9Q{n?qe~
z;nif6E&Cf0c7+qpiv3|HHrqI6NLleiEHI3++2AON*!0BapDG#jq+-wulim#F3mNqO
ziOmB;g_~lby(IX1qnGHQZ+HRU=0%hdwMYJWzR&)&v482kl@?7!cox2MCU~_U*ojTr
z>j(I)bkq#|df2kzCZY{4aZ)S%E}F09#718DCpITrY{$82kRlzL9fAHnms+9iM%r5bRBDczp-(X{+tT<`~>rL7VKv
zriud4t=?Zo-FRX%5^utZ?pBJyXFXS}CfF4`1@IY;jKzjW9~4(=@OjsrF%{bMD+!;M
zc|6#^?hM6jA#gVH&Z1SBEp%8)f~FL~=Wf0zsSfZ-wo)fH2RY5*z3@b>m+-lad306(
zTR7A`g3p(Ym+(2=cnjcD*wvA1_!B?GKf;(7LIOS;BT@_Z>lT~NPHgV++miZDBBrt<
zMM&^9pLA1X(PMEz1JK5q*ya&{YNZ7Ly2a-xnfRvE;!)HzqXacy0zh9L5lcpcUN}K5
z#=id~^S-AVs;4AT7YKk}djSBn@d5zozn<7U;M50z9t*(^K+oD&0QBzaA^`2nsI2|Pu=HsvnvuS#e+up~Nm
z@py2aXH{^_9mc#r<|_3>KoV?~^GU0-;BsSyr)`GS0UgO!>cpmDqG@j)t4$+1&Sky;
z9YvTecE=kp(eb~=TY!$juIRXUj-cZe!k8CA0v(&fH(`D4>~yf5*bGXTWj%wWTzW=d
zb>RLJ;-(uW)^$yfFj1>2z{Gk*m^e2pn5YCbni|!D$|<*dMhzx)R6Ef>qnY>pGe-R*
zi5gxo@xpU3QtQqKCjRS*&2Xna){hmxqj~6C*K_a19_@5x@hm&BsU#0Bz%k+J%JGfj
zzH4jEw!X~t8z<3%3r=MqP#$y{S2YzSp#
zQ@2P`et{(EUQF~;J-=ZUS1H^T)l#O^r+S7u$xwAwZ|If7P_<5OE7YDI6N0<%<8XCd
zl+C7=b)h!Fawhr#jg}GxXUM~VkE{~3$_oivx5r9#dkkS3{;O+=%_5uu9Sh~sOP~*l
z=QD)L=Cz~}wWoIyg1xB?7ayvs{}5|fFUn?9C##01I1PvO20LON@IXUh6%FM@k%k>r
z!!5{-37ttUoi+{UFxJTCwWJbN!-+z$H~7ORrXfb11%vB{#+|(;7>ekuAQ;qpMS4Eg
zwk2vwz}?VW9^o-Ar)_Mtd?=fEhcho%!2B#S>;qDRREr2^=R}+6dL*Q0y3b$_|y%K^nY@W*Q1EcqlGru-D+0*y0iFX_W=A*RTloYBA@c=O{sqmw>%z
zhs2W6?x&7&ewx6%@2BSKCrQ)+0(+OAiSgUurOmCS?{?}VN;wRIT`1UPcL@dWc)lnU
z?BPm5wR)ynGvqfM3Dqz}$91Big75Iie~I5M7&`9ggv{FpJmIR7P^Kz)AK@cDUA7pB
z{s`ecegB5Of0KzC%5ZX_XDB5YPEK=#n#@4M$zd#?O%0c%{1QphmoibD-1#)(B)Jiq
zFtO02_`7D^oOpockPBe!-tFT4VPM(XW5Q1k;3(Py4QLl-v#Bo_vf=kp61mA)!4W(+
z#~C~QiXYpPRiH>-2o(8W4V!tjfF*^aLrIcL_lG|8#6ey8Hm@a>sN*Ch1bb5(KGqg|
zxbhdNRh#J;WwWVMRm0Pqh7Z6@(2zXPP*_Dnc~PX{&Z;4WLqkb&>F|8j@a|LiHm@a>
zs2W};1bc&@^QwjnQ4B2K#T^48Hr~_(-4Lu5faNoej&F3M7VRDu8+N-XE)7CONw7T7
zmb)_V55g|mI7#s1WIkzi78`zvt8}I;Y{2ROmSighmcJ$HedchjmtZ-G
z`2w&MVHO(>GhTw_jmBF5mcp(kenIYE2d4^SUI+=WyaYjG_*2KYEe4j|ef7$=kfrU)$eccq}(XK7Wf8S?Kj
zk0Cm+oQ4Ws#v}ig0?Udqt8f^OONfrzE>OW$ve;4
zyp~j=4uwDn_NF$>9{@g_x!Ll6bhg$CC{jAAadJb
zJS1BwJY1Qmcl^OxFY)ld%opIH2s1pq)_94BmlfpIT6LQUpc!?4%vp#x=t!Y^88lR7;ssYvVpnGT`lpvtXV<`^FwMcstr-s?CgnY1smFmWfd|
zn`$og2YX5V0&gdu06Dl}LQf2@7FGcdc_HB8hkG>_3%pS{x_~6P^!X>VE8)Hw18-bE
z@rc^9_Z5P&gYSiXz=z9cky`j&O_a^1Zqo_
z4h<#ArRSWa8jd@bZ}VDGiK^iUA=sPRu#sx$g?nGfNwtN0ePF%9YT{bC935OJjCmm>;B6c{9{zJ!
z+!lkk%Y3txHI>rAAn^L|_Qc(BF@v|&SH>oY;7zM6fVWmf@b=VA0&hxC<0arN?%bPi+p~209M{-gbpx7w#QcCh&IYqebv`q$>s0
zer&C(HA8*{^B8(}$Q6j-9X#@%!dv(y#;2Y$FVT@2-5}k_N6g3AXC%AzGCOB}+ZiGZ
zcril`8b3!Q86NI7?(Cd-f@6l1+1!Ftf%Bs*_E#8_+Ltp&UnxLCDh9nU$)J}P0!#im
zbK8rAn_@BOCBc2y6Lru}Dd*d~mQh^%6d>*LoA@%+x*FT0Gl$
z37=hzw*WqcT^(6Dk+2jr6UMv{67YE&!p3mkf8w^-IrDzLdZ{xcwk%t`A1xA`!YAEa
z>^CwlXaM@mWwAXY0M$wh0JL2ZfcEF^bT*>|HD3Zi&vufb#A(#U;=@j&mlq#~>M2Ro
z1p=Vkb^w4rGZ_H-ujkBdoeu$^pX}=c=nvZnfVP}a1fYKMY7dmRrJ-{(Ld9Bg{G5O>szfBikST>AcfphB*E
z93+O__~98q4JH_>0R``r09M}MsTD&8sN4D^f<|x!iNmXfU5<#EBYjXCQGcnEbE3-O
z8&uY@Gc5gW7ZGxx3K3orB0LasAcUZ)UEA`Ud3$oHzwMm)(M#i=q`wUO0gRi{%jN&~
z@P9aMcT`q%&U}?u4(I4>y*Xni=27wU2U7cBQ%iLQI-Q+};hecK|KNgqQ7^2$y6@3mS+m81y}()H5%3nroB(R>J#omaNfW=1hz9XJD4bIm|m)yimE*n=r5^
z5t|oGZ1dtqd^XPvv|gnRchcaxG+Glibbsa{>&@2E(8f_iRT)FatrA*JEQyXQ-xI6UX+6`$L3@T2%oiwlBiO9^8b+?z66$rH~rc_7FQd$!NxrdprLe
z#JumH>FOUz)bN6df3(L)9s4ja@n6rGck?`lFUS2s2V;&u0I5CNIdlI9?VPzEd2s!f
z3D23A){FbDout%yiffCesc9R_aisRRTxR~y-bLw)=?8tMG2@#EOTu#`^vIDDRW4+b
zODzJWOVxW|3wP%Zlmuk2A$kozq}p1et;>%tQpNTjTX=+QkYOmCOZO1TwP72Cd!@fV
z_oLr}@*An+hQ@KFw&9#2Gqu(pjK^$h=>aUMMD6LH3c=pghW(vJ7Ha7^u&q=_qI^N9m2w(~S8N@($G~LP
zg>e^$b*GdBllwd#{Qjw#Hk4p;2lIYs9mrN;myrp6X3Qi3CS80{QXRmAY^7GJ=U?P>
z!{5KMdI=`=wcZ4nQ1>X*`fg9vk^J-h;Wdo#i&(ZY^6;VP^e2ql+)A~^sgD?7AOyRW>ac(6@K=s6
z<%X)KqTGSNGaTl2)C^I+_Y9~N7^1xI5wgK?3|n*Qtwb_@QI0Ld(ugwF
zE0!zYsuPU+2g#<;=_zwv#HTiQi-;*5Q4p_4VyZR3{k#z=Bx?QC|`gmuQ__yq;A|ELzGL;i~Bdm
z{`8WFa;(RL`{ui$akeCA%e>!HM``0E!F5PJB@pG0b6s`#fDS?6C}AswDD|D@FzRc&
zYQ031Sh!bysQ(QTqF4
zDcfC22g?xz`iS!M&9Mm#QP$%4s{m27$^t~`QiLeeE)hggf*LP@C=WWxX!m{i!EofK
zk<9ykny7w~L>(ZAa(X*-`n6*=hbY%O4+2s4gkXm#?GS*YFJEzQ5u$W(rJ&lHrm7kd
zWhL_{lxa>w1@GgL|7`E;8=UOx-q&Y5<9ENYsH68O82gajdYSEgEpmnk>yuGnk5pLzh_=Cz~}wMX73goynlV;}0hl@?VX`V6nwD{hhPeZ4Qog$l5^tbwYn
zMO`c#K15^U58C1xZIIWp_a!gc+jV
z^YJD;T6&o*G7LT+b;W9eKbjZ8=Lkm+mu`^1h~b@#?%O>c%+O|bN%*Ym@!%d*O8Y(o
zvNg>6!?K&2P!jxPmQM-zoOQOV4m+s|pJXew_w{C?-Vs(W;d8Lon}AOdX7Jh5cnP0f
zjkf?kg2V=B)jVR
zxS#>(b2wlt08p*806@DH0q6j3L}xQfQ1c}Kw5O8{CC;QSHqo6ZdU<{Y}LSlIKqp&g7
zCa?(AfP#NZ%qVa0bRa_psN4214$NRViTJo6*=5^`Inr;~Rs25P$$3%b@C_>4>Tp>4
z`?Ls|s6vESga{9Ww1W^dwK?dO!7y^Ezisbp%9(Lb(!H;Xz_KZQhWvjV{tut8kIIVn
zz6N^bvccYLy*Z;X^Qd^1+@T1z#G_gvTBT#}Yghh3hIrY2eZBA%EH#VvzP599guU0r
zxbvLG&^@|2&9zCGdf|iMqcdVcP3A1@YtaLDwlx_-k#iKM-m9gNmUP89NA7;`4@D1<`Ra^FBJx
z*1Z);sxtHWq}4ItLfaqoMP*nWf=jZM+WVU7>4y6sRxi=Fpp8#=H;`=(quKWB8c6a$|d6WeN3`Fu2U6J07MET!2rk!!$
z_xWu8fb>P!%8EY{a5?>;?=)z5_h9ILK0^-`VQbrKJlWYiML?IOO!QL38FA3L4~AY?
z!-l8;Te}|Q2~dKqT~i(bf2WFz`w0sKlj^I-VglY&s)Zo+S+xF$An)K
ze-|Tkg~j9S(bqFCVQdquU7K)Z!4+2>OQ4l9XeoZH>NhNCEe_IIl
zrZ&95X=K6IeoiBNucS#)@U@Mjhv%=2LD1mkiBp^-amHH`UNRmJzW=eE>%P}9?|0vj
zt;%L3!4FLMq^>b|Inoy;)d60}R%-2fYFDQleg|pw5?xBa7hzWu?=V8(WwJ2lg^+-kryHaHo#?K-*xL0Ozb$3GrF3uyc>T5OFa2W^7|a|l
zcZnp%j$lTsEP$EbMKH6ryTFVR)Oc!KgPG-W2Plf(mu&0&^cM5JpVq0LBvA(l%-pvZ
zI{o2yZEo#4+o_MJpf3cwwd?giNa*$Su%ggwm@5UB9BQgHL%tRB7yxhVNJ9lFJn~+F~nlW0Fb;_2Aqr>}mj!kcfvB5J?0x`b!2>4zq1Jzvm+txZX
zf5KI%(z{(#y<)lY#{YrwUfvXsFhh)y9uq2cvDk$c8?%#2oGggp|JkV{%LOr527^kH
zT)Hi)p~0SKteQY+MUM=!QSA{Q#p+cF@BfxJLxAi!7RkO1-o4zIeNJN>bO0I
z7&pn`k@hm2&z3}tvpk+`aB4l+(-r~8GVk}qdfGTisxl4vlt7Gnz9^{}ulWw+muiFN}F1BoHHuP8l|m9_@d_
z>{h=mWd}*=;3Dw)h%xW7*aU_c!HF>rMu?$R79d8yBE)#*3_%PfsPPhr@sym!M2PX&
z*3M54GVlATsrpG0b$}p7pFPm&14I=6{)MAEo%%qGb`b0kqthxuj9YFiLX2*%6kJl*
zR3l>i5kNHzfCpszBKR7Q4l%+%ani24T|e>6-R*YmyocD8(GJ~_hEqTQ|&ju38&
zh4zx*_eRZi(9dNQgzKFiQG4WLLWtPUH}-qHx6-1zY|$;-Lx}bR+wJ=L__&9GFgt2S
zZDzh@!>4IXEErfZZmaRN>~_fuf46I*7v0{UjBed-SD*IMMplG2N|H-|+)Uf}DG&T`
zo6RF?8($GZ#Jf5%8>yInsW=USZ&zSv&7)$L=b8+W^w
z<4t&)+axpie8Cl~2?m3w06s@Mdiec!ais>I?d7l{g3qNT;j@v)gTITor5l!YnfHg~
zLbZ}4xQNH61bn_BM>aOXGpr8qNw!kEUCR>nj;^cq5bIW72EC7a~^9;>KHI}$(Dt6m;^`gNq4($>k}Kn
z0QB{av7;jZ)k+HhbYKyHR&eVXr@KN>^CbYZzmp6lE}M2Ro1p=VW
zn*u;zuh`sf*9p#t0MON2_yAhxD*@0WZ!QAR9b74>_6kZ-HSTuJWF8};M?D%Un1o0E
z3#YjiwC#4i<(h|@a|m&Zce@^UJP>yEm;bWcRpGJa(ob%xix8{)K1d8NyB9XD%{0dZ
zBRGohYcrO{2Tf(l2|6%jfV#)F;J^$nB5`=Nu**i3uz@~u8}WN9C+BFD!#Akx#C>7u
z4SS1_y;X?tiV)#}kWLVSrcOc_S{ZCbF7>zVcD;B^+>>;->q{_hN`D~#FTnrdf~@ie-7Y4!+cgef
z6fgs=*J>Vg(jexPe_TV4VIHzp1k&pc#G^D+l`(YOHKFB-lIZxy(Xqm)V$DXag1cQS
znfK9gk?y8Qf?KhC(&`8UU2?%wzNieV13Hqe)Na>YPdDuUTfIcbtF+$4ZkGr%bnI%p
zM8}TCTY!$juIN~C1HBzI5yrd_66kmv#zQ#E-D}yTmT#6&?_3U=T)GqXjcD{G?)w*p
ziPMjYtr%gVR#kwBgNrcns?O3Im7qpbquMgGhm(wEblc$kb3F6De^#h}BvHc)CT_Pg
zM(XriHn-dLAJ22SO!IZ{9GbZ|c4e{mB#*Y+RdJo|cC{i;HX{jlyEbhV_ubiQ!4r;*
zO)~Embdd1*Z7DXhLN=xHA(LEY4U%}XYY5$t3x@Jw8~YvPz-QQyNY}=}uxd;dLwG(grNA$i96P
zc7-K@Wt_*84IcQ*b=)lTe#fm~tFjqM@bgPPC4l8jUsQ(G0a(aZYSnt_5plo6fN5s+
z5?FTDdK17R!VFl}u2UTeEUTD@GYWu3*ww`Q4H96PD~x#|B!DHo6@cZ!x^Y`#OXI}Zq>TTsgHPI2n4%T>)lHw=vr`1QP4Hkm4ZvU
znrh9E@5np`z?c89YX)ub$bX4_t``-Ds?)LMfHzyL_V8v~dM6h=-5d!%CkPVyT|Fc+
zc(F&sH~2J;B;}15TV&IWDeSkHOZUVF^FPFrMwiHMa&hC9$ZK@1Lx>c4YIR#8&vRA}
z*O5`yNc9oJhX-sSdJx5IiTq#33k>`6(sm*kW
znt`wQTQCLAER!{atNp-+#vXxpQ&+&A_-#@W>iPe{Dy$P(Q?$HioXX7PS
zA7#7+SS{@8$Xod9K-{Yq#=H;`Sp5XT=kPgqm&TUJyZY*-Ze_@wEnDy_li)@Pz~7|<
z&p$IZf}!=pva6gxYpt{Ztt*Srx)(R8aTikvYQ6+ocXpDY#Ie-HJe3x`yd`o!^^_#)
z0zvDI^?=q758B)kd2i=Kp!M6o_-Ot4VnORB{fp50$AoI*Q7T%M{g-(d>X5$#t#8L8
z|AlumBGl&D5_yV~fto)>gj>8s9^rTZ{U<{o0DbX=kX{~JE1?l%_@g)P}$DA
zz|x=WEJ7|)A;K#{ga<;JK?s_+4u{!^Us>uOs$#=$(6$n`VQ3oW|G5_$T;C6>tR+s3+u
zr+*yd&dV169~4uqNq;Nhbyut=)7_THk8?uLrQ5+|RIbxkTq2W*B{CCRA`ja+US_OU
zX*W7)aAYgACTi&J%tKZ+_Ym;+Z=!~(eGMJ|Y~yRWt|U5s;PGUGcYf9?IN!X&ypN8d
zF2N+h3WiTwoh^|oeNh=!2XrJ`sU`A5o&~c(cdM7^c#_teKt~Z~k?j7)OLW}Bcni=`
z*cBanT}E#Qzx~9<4u5917k}^
zOJuF8024L-^OEP>us5~gJY9B&ky;4eqHH$RSvBn9G<=ppHZVsu
z6jsqtUWkVNccw=r9UesH__;O*)3n2l<7ybq?-sacXbhfQ5@lG<@J!X~j)7{MbeyT^$04SNL0|b=M{s$=X3~s<276f&nn^VB7%w9%@dW&wDVEDA9osaLBPXTd}C8ly}d(q
zd4u0;2&$J~D^q>?IwlI6qj+lvpS~o$D&IxRb2OPw?VV0FnE{H$dEv$?SqjNrphMB$
zDurHAEnKDk9@vk5Gs<7UYB}8SS=>(zAZi^G{{9XY0tIW?#~nRf|5jYu0OF*Uad*W~
zu2&Ku_VIYI|M!i0m(kkJ%=;a$p>{k;@XcU8B>>`6*=CIZg4LmalC2a#{FJEo@s(OH
z0pcO%3jjidS+sVG@e&}eG2Q}z5OxKKX%`4UoG6TWAtV6e1jP5@w?DO!ysh(@mqK%9Dh5kTziNww+|Td5xo`RAbHKc^%N9lIV*%~$S4~@
zRT#nH-ap1Zw0*$495bX$jG_VDnu)UbK8j#~?gQQ-$Fo93&>~C{5-`UOIefnV!?0Z&
z!(sTco6ee&H6Qjs8+90oGACS4kK432|?mr_L_q%<-!&1^lRs;`8l1o3eLEAWu
z_j$8{E@sLf)pn`H{WVXTRKIM_>8VEsbp-@YUw7)!E>G6ac=nc~U9H
z8jCk!3%7k}*qL?3YJxq$Q-GaUI(j&-CN{NUXIV2>X>F!qN$mV?PsfuDzWzcxKCyEN
z^ZuBeuO^hFDzlJJ3G5v2i<0Vqon$Mu5BRL7TQ<1T>Lqqwr1d6(E9xEvSH~DHvGWk)
zEx=A;S4UoV4lya%Rv7a_NMPswKfv%$hOy~vA8;pMz0`*9X^OJy&zS^&@JUZ?&gu{w
z!O-);Jz{%C=&6+!py!k#^z6ug2|YQ6+|9^)iKi6f|sg~4q^FK^AeNIfNqx&t!g{20LtI_(ZUiqLaqLbcH-7468}#XJhNmirXJO?c$L
zaD?p8$lk&Z3X2n+4AguuBKzWfz*`*;Vzo}t2a#FvK45o`EtkH18C1xXcY(z4r~$As
z7Ri`hs0Qr#A1)!PTG;iL3#TQ}FIXuZrk#`X3*&FZYh=Lh
zJhw(D^!_Gn3seP5NWo{)$tyyH2SS=a2%6d%^vYlkxzyi{)gbrm9`_`@Dl-}^o6?o?
z{}B8ij{N{y6zv0^b*v4?e@*R!@A0Tsh;}Tn4_HUeIO7-f!YNob
z7G0HDyIZVV*!k6X@XXghxqR1{YE80zz?WUInoJMd2bjRQKbNkz4GYzVN50FzlSJ$T
zGO>L?{tU#V**@R^Ck?J^&c<0o8(BkVVownbtrIm=?Q7_`S~eb|aK33tbbQO>!M*lR
zwF;u+9Oiv=+~R9^9tVg_u)JcDK*tJSREE_79m!T|AMifUg1G-}^%5PA)p`@?D8ekV
z+{<{0jw$0UKu2L$bnJenpyQ99urYZdB+&5?EQi9orMvk1fWP@|3AX1F3g?G`I&kXY
zanlVGGfm_E5MiQLRe*`pi!kxnmV${&P@^RHN0Tr
zm#cwBnVy^52i)3gZ7#FI_5uIoPKZ6)K4AB5whtKUKAm?x38@dqKH%XHMfj@SmNSP4
z2O6*r42=!Yhs2KGK@|Sl1>YJ`$KifLPFlAmI6_)k{RP+o|J{yyM7sv(6#2}yG47fr+QjD&Fb?-5nQj1ZI^8m3f3?kiZR
zx~+VBAIZ
zmjq*nPudfRKNu@(aX}6i<0cqv!0G_TWGl7I-`Z(TyML(l5{zdsU$D#SUH!Y7%*GUJ}<-S?Uc9GJ-li*dX)j;)0_q|mE
z?f4`YQhZk1*zikN}Ryum%Wg
zK8a0dz;TeTUfGKGXo}!w@cO_psBPRq3^-=t?w?_21RPpr0dUMO0*>o;72r^U8ZQAH
zy_{rdat;+TfImf)^P;(d>L*E#5)6Q(yuzHCOy|ms0I#Bm$2dvz9i4OlU-U4(Gc14Fl#|t{t6UMv{66kQx
zQlP_>k7CmqIyCgvD|_`Vnj*LuygoXdC0`wurD3%HwQX$82pzP_0(4kdgbv-g8I8}n
zYFHtK66kP@lMGFcphAWYZA3W_9V*pNlBff8|LaS1u?J7y96IdkJP34n{Y@VoK7LB~
zzm6+Hhm{G{Mx#`O4tFsRbZEVp_6=^rBmV&%!vDimucrqiIO)67gD3e|o8jt_yoMI_
zG{(5uRTVx*M%h0803$eD$?YIDS$$>h>X<=Tvnm$2F3RGZRxm(M502BN0jXF>2$L)%
z|xqG4^y`*$&P}aN>KA9(6f${j0UY=;5@aOdEZmb
z)l-tF3j{r9EdzRM@cLeI&r
z6jbYJs_}=mU71Hu|4DWmf+O(Af8mK(d|1tPdeGO&K+V^`U+VOrgW~}dZv}l2nR$WQ
zj@pPO9$PMb?CVe=S3VXJ!;RfxWBhR@*oSIB!Qps~F~T=^l6V2?E?p%X|Cfwj8TUW&qF&g4>k_92Gq;R&3+q1_yK;dB%A4xMRBMu*9^B@N)nv}G-NQbd
z`*Z0}f6;kl!%POAB;xddiJczo+Xi$skewd1bJEbbuU>Tx{g`<)^rknZp|9al8mh$&
z9iL5T*|8)#<~$z!{VS`2k>xGS`(v)D?oLaByPSN|>I@w_`Jytc4(Ld>Ql|&qWiu~A
z#~rL*qT`lYZvq`fn5{d%enrhdbX>wbCjElQQrHz8n;a?V_>3^-g^)nU4Aw&7Y0_Q%
z(}NfMwgkPoe#)hHS)&ddz|VDQ(+v|lW0=}J6k(!PRe*_0i!gD^?W8vA^zsAP{E4(}T(uao@Ea`RhHI+M>60?7W687HiQwf?N2X_fQW$JEH5k
zg-q~iIVAClaUFYkE?B{vsQ3T|IdDf7i4AUflg;xD_LD?VcBTl@72`u2STJ~k%ZsYi
zlT1`4({-UU@;nZta6At9P@qx^RJj6^6uBO71x%8i9^B>#HJM9n{2$Bm*;FS<%3Da1
zZplQ|`wD?~rEphNOPNxq2Q8gs!0$6ZLCZq{Bv$>ks@EoGTM$Nl8;71_qHH$xh^$0{
zN15m?;<69LuH?a7AgmHn%L@sq_rdAGJ}?ZsMb)noZc;dUfF!x}TGR5fEYXYZk{2kPmI*U20)a}rgl^fcXAqD$sikl#zi$0R?$#ih=%@;lUMyB8d5l_
zlq8qFz%=YFisZGV5>>;_s-dt$!zFH^ZlUTVxkV(9RTCVKRZ>ByI?U0-j~|itd8Y?0
zH^ki@uIW+|jJNQ3@IBa<;UQZ-{>;2T*r#jbB&o{G=96}51LK+4s({7p^nld?jLBAN
znZGbm?=Y*EV0@$2n*d`GW?5u0sWk_Y%gu5E5YA>J5PLD+^-N
zb<$qFzpq}|XD`td!G?v&W&Tz2Szmvd|J>iP2_jI|Dhoh)MG+_uKtzC^qXhAl8P`C$
zr;`j#&ZI)-rxQgvZ<#+|{UnJxKtOr>#TdWO9l5z>{vpnTh@qCh=m)B+ACf?|)geWJ
z>c)g>(@=`4HG`UuFprLXyxfHdM&XhF5~l}-hqFB)+N<7C?B3?D*rfAVIK1Hv8JH`G
zyjA&-3BI0yB*yNe>CRlxlD|sBLYy4ys$1ivbrz+Tk
zYoe;uo=g(hy`9rFT=%;0%KE7)RoC$vY_D+Yn-GKTT1TkKTxziWqAZ3|FG*7VKS|Q#
zn5bs0ad=xP+!fVQrW9;n?IZ)X{|sTXq0^wHw!vV#i^qfybfU|Maq#86D4R{~F7*d{
zNd2;b*+V8N;Q?$5tAHYN42p)&_hEbSj{=Gm4y#L&OKF>!ht0;vuCW;UYW%7w
z!cqJVyd-R&G0sqGzBFtcWg7Ffz?=#*4*cNs*@dt8eI_NKqc_AcV`(Z4z!fofrrZd>S
z);CL8ODP@P0Nxj+ckBMbO!vvvmk9{DU_EXCn#GmT>@d6lw!HKsL^S+O2V8-WP)1{zCiF0^5Vy
z6v6h1t`t;TH$zoxhWwArqhse@rhS7?@W_9qV7rbdL>vCD!gjZ{u}L-LmNN|e_-GCK
zUsb*ylU$}Dk{Gr#^H5zbxSBud!7u#CQJZOsgq6d{@&?zjNXS-;pzKT$q~O@<7b)1B
z^s0O-CioEvlDLKzT0;Y^fh5$>9*NZ;Z}1}$60+4IC_7UGX$>`NSVM3qS9VpYG!t#K
zO=4@kM)Tum;TxRzs)C)hKqFVcW`|c@0h462!xN5Blex@hhqq<W;dCb%v%@D}L(7YvfR@@2n;j1Dm_UfO#c_8(%4SmsN&P`vsb8?S
zJy&lC0Ck^SSOt6Kh0G2e5Y%^|H_^Lhd@Hj9g~Pd$DqtTRU1=LPkr%Z`9X*|nLT
zC1;1$9uMySJ&X3+?63>-KI$}A{UyQuEIw&ZAP{0SuE3@neX3W2SRI0TvXz=0)+XwG
zdb-xj+2LX43uXrqX0yW`#>?5^2II|j+w{XWU20$5gnzKVu&aq@wvwQ}t1#w;keD5w
zug2`~$QlnzFM*Pk68*daE7%?`_dj!h8F4q9cw?69V2c6jh_baBL+
zIy*=qHLlGL!<}Tbd+0Rhr$Nm7erl(Fl0+RKv%?WJ7{AL8+T84Lq4OYShk6j~W`|uz
z$?R~}enqoGD_07tefo^5)(rV~nMcRI<^|d}cnOdES88_n+H0RS{9~OR4wjX%^eUYl
zCRRfj?&=YF@$)<;xlA`CF?L^0cjkiq)(Rs@=%_uBuyPn#-emK91MC(-*_jm7H5WY3
zC6Z#~SDYkN7X$4Mo|5=`DP+x+*I5C({zE)dUc>91JYFRjUjOA9RFk>f@Vcw4%u=UH
zQhtym>9$N%m&S;uD}}qFTFR8d>j_RW^s4#-dQEdHeZ%V^9usCX^cArRE=We%Z0Z><
z#)5A0V8+RFt<|p9N
zUId`EncgMw`WBA|`1ceXWq5rB^F9vrRQ)BvSBLnd9ntW*oi9qN174G@6kZ?aG)K?a
z_@vfLy#9sx0=%Z~(Rtzf#!I|jV7vu*E$nLIfS*{!@4JLCFN6eM9|EI>N9+C^4R3h;
zsNa^d9#T5k2E0CAui`arHG$!E8(CorxI}oZRTkj&x+1*(?l-|}C8+UKvf=dyvNE*E
zFnH$)=ciYg_x;pQ{UnJxK=8V1KE`jG{Wpi#&p7pg*F7QF;dTGJ1g{_2s|c?LyHc?9
z0j63rM8Bi{DWM{IDld2XPbnf;e
zrDsO@LQc>cpOYY6NT_iPIHX2w1dF^p-$1O^HM0^=m?2)_YD`i2YWJrJY=+p~b9*j5
znXI|;W}m^6%Vc9qb^vXLSmP{Zz0zigC5}*&>1Q*LoKO9
z)o`K^><#{MnQG|G5bNc3kKjU0Fz&gc8R9cX58K`yyT)dSp|a*tRKYJ)O3o1HdOX?S
ztjFLen;|+g?<3DBZJZ?dk{6$}ClCxVBDeQNNp+YZ$X05G*vn~-p7GhES}$ja_n0r3
zA*g#aLrgPX&Jd3nZ@~;9>}uk#cb6Grh%n}bkeDHkg;B#@-A0?u5X1bolpQLigA{n#
zR&+c0D&2xDV-wg6(LmO4i5WtxESMp-_yQ%X>UF7FG<-#!5j@GS{aI!RC8+TdGsLrB
zvD#>ccK`*)@aj2xa(JYKGX+6QT|OLT8BHU&ale$HL*e&q7#LW+KtH
zDnEruE;AiTJVWH421hRFzDgKLLPwpAgyq3J-)HV8%sIZp$Q5S%KwX}yrH<@O*5PJ|
zzrLaL%pzY%3$1a~_fjKCsBtM0sWB_ez$m`K454++T!<&k5btqCrl@?%cPOu|w;AGZ
z*Lpzk46uebur6h?so^7!NeMPJyzB@ynJa8+xJFihsezJ|pCL*5OeU(tC$DhvK<t$0zxyOV
z-w}zj+0-$rVMnLo<+AxEJkU^BMMLIP!yPd-?8wdr;rpnD6b=m~$)(4dhU1?T4Yi~a
zRl|%B>1|MG{>Km09&c4VQZ&3ddB?mS}&)D8O#?<
z4I<1od+s-0P7RgDTQD^UyP9~RT!0QP62`m`5>rDD7&YAVcx*bG8ZP(EQnrhf4h{gX
zKQ%nb>m6zWn;OhTS08O$}{sld0jdRMFIMlq&_*e)^xP)(rVCnaAiD
z_9zV%yo*Qv)2Si+3gc7nYA@B1x>T%E8~(#b94q3k4%yAb^-vgq|Bf?6xHT7ja#{BQ
zEbqehlVg9>SLTV18B%)URKx`Kj!3DA&=K`%@)=;ejLlK-Wbc8i3Y
zVln6?$)&r`Vi&;qAH$7oUP~%bd*mn~MC>OT`w;J~w214&@Uq9^7Hz97dKU`^0H^Gz
zBHW9bf#Gf0a15=7HIueMUdvr=dEwvHzLHBjivurW-gP2(SG((b(neNSBHWIMK_y0#m7;l0;n~
z0NP+00CZXt0O$q({L5YKcFu7~A_BkXl+JO;jmJ21nY^`X;Tn`C#j7fU=T*k6|fVWtv
zHtbf(z@9|h)n+0yIHLPKL04&ZS9^q$21g#2cMUy&dB}Q8wkm=qc$9`}aYM%-p=Cu$
zbo}xI*AlG%@7F4L7x+EqeROQ6cY!6T%CzT`R!10sQAYcsGOP~hNVZaUwV&{G!|&^?
zUZUeUT5kd!MVJMbhZ`@^v9<9Qprf!WI$kMvp@X`@m={6<9Z$mAEu7?b(>AGtw@s+m
z5=?O5({HE)Uv)=JFKg2u!qq#B4NmzHCTdj$nAo%k6VLfvFi{C=G&QOPmB%{CXzx+?
zIsdd}-uF*O^^YWKc)`R!pTJ0cXeVIezuwi}-Sb>7GjTmUhrU(z5W2lR+Fk7{w}rN2
z(9$X7$!fy8+HW?30aWp?)q?Hbk4<6(?AoxKO!Hc#C2(Xd{ildvqP|(=MB!V|u;JW#
zv^#V>n4ZJ^u!(d~o}@17_ZODOW7fnU?!?z*dh5^>VU+XjGLA{Ut*91SsUPnC?lmb_
zKCc#b4KS9id53E&7CEMx;47eQ!PT(ojvj6`I4*5N_Drv-_`E^MA$yR=gYUrK>$=45
z%==wp`ZwYxNpPc=Pl+M>^?S~;_)`ozWXV=)J@`kW-sz*XUJltunJ-umiZC0pBaD|r
zcChgl3|V1U*UhdcTZN|!V_pb}Av+mMy>Rt|vFU6*c#f}LS$!!T3<0l>NDXJky1joJ
zx+~s|O%M%Tt+HU~wkjIB|KnbBHlqYJUSjCp=_I4w756wlUC+Glr}^q9NpPbVPcn3m
zo{TQGV*Aal2m3e=Vy0~X!EQac$3O{ZdTdh^&a`%=pxW~PQ`Pvh{`Z;3fVfsRI)b@)
zT`LL3^gh~iF=iyMja=LR!*{QXOB-tJ
z?ll!Z(I|-;>m>S!Hm-lYTV2kH{#)k#-ndYEqa@fx;!^@Op7upab=*Y)TPf6-@9CBe
zhFHBsjR9J3Vxp(+(K6^X<0WczGTs8z5Ozh4VOt4m>>`YLAtX>^@K~V6oP2CLLyf(B
z^~yfT(iA~g@cO86$q#WcLyafjjQeSX8d_xmYP2sxjmth3)KG#NFM%4}oMdQnG8M8#
zPzO=YTLdjtKS`nv5Y*Uu61v!vn5qB$Piwb!9t3K9beE4BtF9E(Xuf3;YW$v1?QxW%
zYDA5Pm|rN<1b}W0el?-6VpFI^joL)#cLPGC|=jKaQ=8c#9Fi2(Lml66RA9
zuJj1mRJt#IDTnx&$q}#aFyid3z@+?Gd654ok3Ux)yaEHA;x-d(o4m2dgcTHw%Qiqz
z7-jMIP5baid9~rh1q3jmaOFb=*@a?`Ga=$7Y&|z*d2l~jE!-4|2}6=xdeeL*wqOXK
z&1*>|YLDJl2==Bn9DBQ%XHBFGe(?}xv%!(3S3T8>6zC-kqL;i7y&6F;1Z$$#PO2A0
zLN7^j>Bmj4EW4>YWG;BYnB$&1KcyRx*QhOr7Y!~KzFxx_R3M7F}MSD6caKSFB4qtlG5QuE0z-(=z
z-ls=uy#%v|nJ)-|L|AnH(Rc}FHyCdLm!smZ
zFGu_|<_ktVb&tZAdyJPOez@@#jCf(!5&znH8S&={V_pb}5&sF6cH!UdYKe{bzP?$?
z8cFHkY4G|Z{;{uOi`$6*0W)C1h}S9$MtrxT5&!r*GUAn>##7_ke#N~`GTNOT=KOR!
z^S+;2sh=cK2gr!;{2;p64|O&-;;(WZ#E5SU!EVI2x>!bhpTCPn{9&#XR15D=)fm1k
zV;%!yXcY|=yn#m<@pYo_eEg{6_=5Sd*}!%rmYDo!z3V6CY47vM_OFfgS)OGQV|08G
z!9@Ku&sB&0I4&BYWT=;VdlrrL9!^e8=3*P`!iG{8FXC9|+lp$Tl^W}foCNMC&w(Ra
z-W2y88|$lG18aghP^w^df6vjw7MI7RZLAOS+Jw6ZCCB=y9uM}fE7VaO>qjx~_n~&$
zha|zCWYJi!>x+`=xF`89V?E_GM_upTuJv-Pzs7vQSf}pMSbxNLIo2OA-h#0%>^jz$
z{3&C7fH3BTkQnQ~=P=f{m%b<+$j17Oep|{~N$KDX@cLtY&gZekZLDv?$SfG^T4ljl
z?_D(3UwT8vx)RiQiLw5elZ^RA{py9{82R4Pj;oC+J>R38prw?<}o1d&B$0^jz|9Em&ty+KRWIH9yvtB
zOT{Eu=j*bOo1Wyg0bdU#F`azjtPnOOqa1f0fputj^2pd3cG~@%V}_K$Q2<|?sfe=K
z;2&A%>1p>98ljVlcwU$!o|hNskjcMm(&a_clM7{U1F6<2uJ4b50iESPcW-Fu1jhEPYzVQ}dr?9JM9^#imvcbW^
zm={6Q*X*?WNMF6wR9PgJeRDG{5=`ckZV%t$_Wuk$UxDq-2oQn1S)%Z|
zP`@Jd9QwMTrxMhB3G}?&Nrn=AsEcj%bQirmPfbxzNun+g^xR_<(DRjbK+g;Q?Xo&*!{$baEfcOPU29U%){
z^HB4rSd|r@c0cNP5Kr}oK6N0>?KSVHqK0~G*q^uwD&)$y!0I--
z@3^kSN=W7#jTfM9hldD^!P_JbuNHPWs1`QRN9Z0#Hz(%_mBTlv?D?nB#=pjjkb6{!
z@QM)OfskV$1WjFy^s$4AV{OH(S#eL&)9%wCXj8hQ{C_b14__UC5npuLeY;l<
z-#umP%^CYJkBVzZLQC=Gr7X?OrLjhIFGRbFN05K`rP0TzV9)VoV$xR&4^+zna<(eX>>
zeRS-ir>Tu>WKA5*@G5dK2gjSIiSkRDv2!B_k}N56^Ov(cV+9cm6q+dEY-h)jyJ`;RO@xXE9Qr
zUJFe8*VFEUJkQ~0N*mxgG_%>QXr?{dY4^|{*6V3^C3z4aFyU$UpE!OtldRDp(&@R_
zBu21R-z#2=w5hhkGo^@NqW*j~78N$*Pt9?6hxgU-DI6vVAs0I#HJJ-_0Oo}opRABV
za+UicAXBB#E2@R7)Z(v+lLf@9GZl8+4`bIVJX}HSSJ%#(;C`%=3l@Ki9X;Il+_>bTJZwo)5CO`YcGdW#2X
zy&R%7%oi;FsC%^dn{2!sqGOG>V2BF44$)7)lOZ}t81q6%4AE{_;)XlA9X4D1-R!re
zthJO5T7p+cpoT9mW07zEvY}dcdfb_!p{i9D4AsF!Lv`*;GE|kI#!C#bd^UBHB;`FNNuSF^e+be9(QKt~S5!-xQa=Pa*Gb0c
zeQgR%d&Q-3Z@|c5vkvu`@L71cg{_C~?W1fqwUq1QZ19OJlLb9GjbLkq2f>rD${Lh8
zj*H>*{oiQMorHdaKO3Yzmn4@yWCFWkZFu+{5QXorctjl)dkR5If$y11MD>o5S_tu?
zY&LbGYS`InIFa!_fs2biX
z1bb5(Zl@Z0r(R2BzO+-Xn{O?G##xRYHaJ__=lu}mT;MI5V3)=hmW0N%$CC}(UJXat
zilGJb{*ddYjgzD*)00oy5s3m_a>4gcx$1BiQll5Lm4e2NiF#*UrS%dTpJKiM8bz2z
zFInRyG~RB!1<)w$YT|h-1sZz@V_paeXzYd6Z1~3wvFQvNFZ9(bYbd3I|A5zr#)tXQ
zF*Sifj)O$
zk^k(6AfI4->JLHQ(~%l&js4C??E4@zBDSQ!fpqb%-;%F0-`#{Ta~0UA;<=!HoJy}Xb?@Ba{FzwyFNu^9A{;gE=
zXY7X~c#o((a-DeQ+jW08#z;V7u)HXgMgou5P
zvFGG%>TfPFO_s7>@3F&lTU`|U(YD6k6C{lSgJ*4x+GitmtHInf4R6ABZb!``%Q3E4
zO>iW53L?wFjvl^!T3o3`mb*Ugn|e`6`1}L6=^}{5KJew*_i53U%sY$XBW5}*B>^ZG
z!RJ%Hs0^z^WJ$JCTVr!Q-EjZW>Lq+$rS&Eje+l){na#7FanSK7vAfZ+dC*OJndwl
z=F_pVE#4Zday$@rI`k>IHP+W-%cbwW1S;gpFNMUg%O9{Yetrh~Pz~7eG%lg>$Gya2
zL34%-P`3r38?o$vNE}`*?6RvRY@lCpmH2(2le4|b;Tu#oWgOc0`A8A++jSyDctwct
zKuAjnK~paQy)yWiTS3ig8o#rHJ0;5
zNp(O+vX$Bzo9J0E8=PnL5*<&|dK2hK-J^B)LB>mT+}n5y&{5bG9s9~{?clFIY)oDV
z33Tj+C3X0qyPINLV|5bh$+|n2ZuviT;GB7Je=tn^@5I>B5hiL?1(-Oh2oq16D!ow&
zYBcqs1(ofcWVH8SHp4J+Uulwui38O?lBnSY6Mw!5BlW*4Hn%mlv*$VdwcU*{Hu~09
z+y=5o+ZyY;)V9X@kq5sNWx}noK3m0o_s=@W;)8Co_S1MESN<24+~LOOV!PRbd#vBO
z)Q4a~BR^uIUo!h$elg4NVIc+l;x?uxVPvD0b3FlSH(PRd^a$DDE{e>h9~nzG)rKb{
zk{bc7$88yF{fNq|?-k3H-v|D17YtV$mbRW==`{^sQ?RHGnzvvza1Xm?6Xqoz^}i?o
zz-STPWruWSiaOZQ
z!#huiOB+snD8LjgLRXZ;iRm5>e&>6kHk3Fqo_QZ9W^1e|3H}xXpVT!R8t~brzNieV
z15S{w)FO27c)BbKD-X7Mi4*&3y$PHUVHQPgZM<~G-@Vis1vnw>YT_g1es=J_Fy@7j
z#0kus;UIUfrIYrTPyDu&WuJ+qzsBxIm2J
z3)Ld@z!kC^3zpfFj3gJKGN8#K^xhj~Y>_P5OW=F6(?$E(+;FUT`p5YU7pYogiX^P)
z>vi-!Vw$NFktN#9ioIcnvn{0;p;>o0{f2eARSeE&=*x!I(kSwtGRRsq`|DhefI~9MKA&;8BUT^i
zL!3DG`R#3Xvi$iQJ5%jGmo2whv}s7_KBu|jEDTJ&$g$`|aqU=?FMBB~NmwvqNmJydp!s9-BmSXr`lWo)KMdf=CjN!W3qm-d$q^wz&MaiHan6zUwWRTJkk4ine3^d~MA77myf
zC}T~{Ri@7o;HRQ8(tKD%#A-e
zfqkSOO}bYf#*dmRo{9MdX%da@-N5TMHI8o68Y~n
z{M*p!JdE085&GUTcRRUh9O*KeiOQHOuF3cmsePcDTV(}ny38VU!M|lI)bnS~XY^Q}
zU=ezSlSjkf&a^v^UTePedq)FRBu(TvV)b(;yn|KIs
z)N$jyql~V+<2!#9wH=7ah|475@s4M*d~ay48oPKnq!*#H++_(IDVF?;``mqls=(fl
z+3i95#Dj0PE6VbTDyul3xVni?d|B)uFPy6gWi*dZeBvfMWs33eSY;$UUi!qcGJ5L4uP0lC-r%Uus*_O`*T5KmF~!ukdJ+20%X$$yLd4;N&;sHXp+Bib
z=)JPFTZ_=$te6|V{iAI+y$C(RmGQzO{vwyvfsF#xBJ{J>NXY5K6C#0fu_vX>qZgsu
zUFK1QUW7jDA~^pel3d*9_{FLMUt*S%co90sCAN4_TjDn?rMv1(^&)hlD-zF19T(YF
zWTO|MDdJkrN8QhA51T98u9OkxlfJZ1XRX#kF*{m##Fj}yQjw|=S4%>N@cy5pQ9m`b
zyy_U6zrTxo+$`#0hi_=n&n}Pl6Qgf*+8B>Y68eeLTyc2+Z;UFaXop9OYj-;wBTB{B
z;|1^}RDh})(KT>OyJR=g>q?m&enLb`v+L0OLu;KZ~8n
zq|y$<=ma}hmyCyUhe0hu=PZ`pSg=fdWF)x=l>xHTyPt#}ceRWyl0|z7i~9^NRlevJ
z@i>n^dg3Bgi@Z`2R`fG;^eL`TS)#{Tu{Y#78)bSC`s^ZipAK5Z*gQ8wUpCB@Mv?cF
zK?ci3sJQYx2_2)i3q)tn5!X&5au%TjIMqjQ7a37T35)wYGDVf~aWOYuxJ;$2NL9w$
zBwAq{W4c{n#+&bc0KAv=u4bML<{w&RRTAP1c-N`{38ZpD|0a+
z4W~5O!@I!|s}BT;6X!lF9lqg(o_40%eYU&a$&|kMf!%n-e1db`!sqQ-;Kbqk59gqm
z-W&RtxOObcIUZ#~37i2EcOLh7k2@)u9qv;^OSA}G=hBVuKj?gg`<$%u_3YsZ-7WVy
zSjQFav#*XD=RRe0Rgu$Q5N;`Ou#C7&5+3*2@nQ`BaGq^Cy$C(Rt=HgrPLC$?x?>Ak9UggAL5jqron9{k9>>a9-8t;m>
zxX(4iQDO0*GfA=GthcZ+PeQSePy+?i#l`|puB62RM~W!}>K;8+IE_FnLGmP2L|0Ej
zMKt({qow*)PCC2gYJ08-A+xsEQpW9<$wXce%(c(Sxavu$PUIL8p{VD;&kw8-u~dEQ
zMd;1f*)2&u30*)Gv(FXs-wOV1xbrNuXtD^s*d@0x&_+y~%{f!KfFIAL
zZRuOR2p#{dUW8_dI1A@W5R1@%IL{PQR2Ml;wstii*gSU^x(R>O@SHgIxIo?`FM=_w
z+*hDA|FFXDXsIfdH>Js~RK%$MxFRla*+m)bF+~h=i2Avg=pHyi>_L!0=uXk~MCk12
zB$w#jfT&CJ#e-hD3at;K%j&M#Pi6Cl6RAG1gZ+TGdCOA{-_W{?EvMYKfAzL+Q9r?OSP
zqGvuRuH%+{GBMpVuh(%!&-|T^8`m>sbk#He{3qEn$H|DxB;o0qE6%59e&-xQ(aXL|
z-0B^Ch?EXg5m$9QHEUV9(zdwnp&wI?aXnOJ8P`L%H0h!DE|fh~5z2U;9=ga$nR3r#
zdS%tq<>K01Py19oNl+Cad+6W`X<{G$CE2oXic^COsE3lUv+O(RL^*3ISl?vU($kSb
zwGYo$s-3{~o8p=dQ788^0-LxMKfUbR!J0-b`(6{P8)wE|T71VcyVfq+K6+*>{T*nN(I|7@go+>vCb>Ub&`M%f7`|NxvajrW!JmT=vO;
zCduqy7;YC
z@i+a>ZebAXtzz)%kG^cUK^jHgQwA9Ov+R4!wRdozckjSi_6@FWI|`ZX-^d`<&tM4Szk!&Q!b4qh~pp@;6cwy3g;faN;oj
zXFA>TLviiymRpnwCGfOH+?IhSq=12c5K!hKFv`FbWcLU(J~
zcdm{r+~?UkZk+p+(N#rWwGI<=4p2s1CJB%GyfPQVKjoZy(aXN$-Rd1NhDbbneECcP
zfpf&2a-b9Mux+j#=zW*l_EesBp|V8$;f-xg9BAP@q3K*jC?SsnJ=aMYC58%J^b}`+
z)XO!+*`aDmf~o@PKwFH(f!_B_vSr^XP95Svw+(bV&<~E44)oY3nmEv}JgVJ`lu%79
z`)(1}^oV|gg`oo1aw~ofOPq!FA<8eTanc~?M_8seUG~j);*i)V^l3q2&YN0#*;nX_
zwz$v20jRKe&?-`F7%rZ*U{z3aJXA6#rSTxm@=Slr%Ob~3{(m7+UI0+xnh&i
z;7irMPMVX>c`6+dLS{#CSfSya0-4AeDiIl1CL-gI$VntZQD0=yK0k1Th^6XVFZ=G8
zX}2V`?E8j@W}n^i-#7TT;r<>NwaK!t$R)QhaD*tmu8af4H5orBPbmbx@2@I@MyDsJ
zEc*_AO}0WSAgy8D6>{0v@EMEL&)PTa77Jcyq-!l4pHf?Y1a^0wt#-qiy=3GJ=A%M~
zK*OWzOHoe11*G0^UFJ`GiEZJ~eZ?bAYk6`8RZ7%#k4DXxUmQ1L!AGLq3`#ND5zggo
zF4MTI4_wXFVTAk+6uIU_EI*aVz*SX6UE);Knx*~Nqyj-;)>XhfTZ@N
zfW?80>h3M!j5Y_p0D6c-HwQlBQWa_sSBDbyJEh{sD(V@eFMjobHe88>10u%-f!7o-
ze6`eXb6}UgtPi};)saNKUc^}tcv}F6BXX#d1%Z#m-R8i*feuQCPqFwVQ6_`$y?Jkf%{4prO_XArm`@VdSeupp2wWrcl&tl(tD
zE)Jv~E)Ba?#ePW1){DE%fg(T|Hd9=Y(?4Z@3tXULcNVZ9kcFDW9tUV^jMbO*fjq86
zp~isXS05P6RSN9`S=l~7@gwoNBUJlPiFZ`0OjUQe0u}_0K$z4{1$4vg%%!ql23I1h
zlR@#T4;;mn&^oMyGh}BEoUSEwI!gF7Ei4jI!p8{V`oLslg`N{Z@guoyZKa+UiBuN{
zX5nBU_+C#oiZ@vQyOEY5@xZqF(9)w{s(8
zZw0meI<%Ad-lSr0RI&@j-R8hP_NYWA^?|>OEA(nDO1mKNnb^x(9M~XWL13K7eskbK
zKqk65@JD@FA6U(mu-|>4_|*q)zKq
zFKr_=@250xtu*hc?hX^MAaDi3q_zamnl09s^?@6>5-zEqh_fItAD{#BuPEmm3#DgT
zC8tpLhgcZau88R
z2^49HnBxAo-)|Q9%>ut!;5Q5WW`W-<@S6piYk?MWc4!!yYa*eF?uFH5k
z8!?Pbot)9k^oqh2Ris%Hu2kt&N6NE{i!UCMZJ^8I#)e9a+M4S8@Q_e>
zxq;5ZhtyV9he}3;hs-Q04;d6}SYf2FTxZzK{7OU;GRy3mnoxD5EL@orDhU-ujOxO&
znve<@za=

FMe)pXdJNe8EXx`FQ)r(Z;bly2h-c!ph2UBshcq5(?Hts>>>;1S8>K3H2sp{?-rU z`r&CO8)cQUw-(k+sT93d_MD+3M@xG(vwf6>Wv3iDdT4cZxY{Tx4HZr0(lA0ey}@Ob zd4(maKAM|;Bvf4(3F{Wv+L#iG45Nxi6jm1Niq`GoI4@?63ezeIi>3x6)rCc&$>OST zI=#AZa(Sq=j_U@~Xwf2tU#kAKjQa)l^E=?b{I&XD{#my8o`<92XWhr+3Pm^J57iMh zW=)t-P0it&i-RTA;fjIrHc!>@HD+CMi8n^PKlr8oHeO!r=(>OLe7rx6=e^pwQ&QI* zb&$p^*&hZ5Yb#4-Q!NgL>WV^DV%$8Ew3?4#;gg3E6O5~P;r-Fw{G3yB)r<3pl>y1<&7LZa#a4n;K)imNOf%$ zi3BIl3=WA@m!Cc)K~jUXyhb6PH+1*~Bv4)+no?MfHwjl4P6-7Ii;6-uHQj<4*(g>~ z6;Z}5RLwkCSyp~_e9>ge3G~YzJQfABCs&56E64ynE6OShMH5M&-!WQ0jY7X+V}>Gb zPZ)!gGhCfOR7%E=pTa)5xlZxIRl?CG&RZmqsq@z;@*g}d&yoKx&0`#?)7L1{A2U)E za7ugOwDV|${sT^SX(11RGMvI zaQKjkp-M42$d)HsOKpU}U|CJDu)I1{SUfYR_+p)s7f#c+8nepiHg&-;X@pCHlf(3) zny$e}DXE7mBP;+y)goolfOu5JFMj@}ky5J?C+6@FJGj()-xXu=-3*wN(#$s+!5l(2h0Ci znZ*0=fa2k4n!`1;Exi~nZlsRyam5*@QEPTXZ&26$WSmx7c zt)Gg^YN`q&MWts3tt;i27{|P+9j$LQ(!W&i3{Sp{Rk-kK=pZ`0j>klObWu@lRavO` zyii5+*X8BqVYStu7j(_Ed!ao{s-Nxq8O$D>*wry8fG4e!Z_m$?`&x;h~73hszqH zim`g67*u6x#2l=Q!CD5hqa~J}4Ef_KYndkyBaazX`4ACgoJ?^CiN)_&(Ro0OhWWBZ z%PM4AI3`j}pj;VOi*dTPN)(})`iE=CSGU-Tn#uIZio&WYswXd0SY1?Vl*_OZM)$nh zvWS>&3?}+iwH6;;8yQ_9drPzPuc#3HST-L$_oxU}gsW$^Ho`Ts#A7gH4LAAKGhO$T ze@Jb0waB}?T!tHk#l<5+g;lv_n6NrDtu|B>8C@eST4U5!F(`+|REMU^E~IK}Ol?Hi zvD~PsDld!3n7yphkE|4%cA|+6#v~*y>HP3{h3wqaxg-p>3=6A8q-yk@9+L5fv4B)D zdx@4kxNM3H7T2zNE-$Nz&=L%RW2LZ&FoN!A#~vJxM8Xw@tfK7c<)gyI>`zV&%}@#m zy{L#8y8NOZ6Ki3xmMb?(=%=`?XV+&{K`qKeJE7=p2 zUar~gRE=Hi>rCt^8>>!Pv>|=z?);;1dRUz5%qgoWsxA}jq)Ij1HLst_JZnPb3|)hn z9MdsRJ=riG?GZCed;a|YMf@A}|8BWjosNZq6LH0TWoX9e$(I=l#t!M3V8U1PFX`Vg0Gr_39q~&VlVJsu9{BRzw z@z>tJAFH;7^zOYenrVaBUC{T;_@`9T56UWW0rDTw9B9#FL;QnHM7g!~MukU;Sn8+u zTjc&iF&izV!E&03*mo#oQ?fY7+NLmA9GYA^g@s*Nd2x`*SC1aSlG;kfNtP)>u%=75 z;6>qDuDO>}EhbgL89b2*o?bid2~VL|#ENnaA0ldgY-kGJDpZ|cDpr`e3`phY6;@9TRT~qA54l7r zB9?j8Iu=tw5iN*gV!vQIa~d&#oJp49Ahk!{iTD~L{*j5j)I}3A7n{LFjC>J8j<32V z-TDsv&r2O;KT0h|#x@Eqder zKg7%*`G3@^n0YV%f6xEt+!r(N;{U7v_{;zQCV|{w(h>iE!3TS-YYT5r5N2`zr{b{x z50y#uz-G2zdwiBnm`-AhDl5;HTc5huGm0^K4zbsLI#?`H@Feo#V@1srW**@pc~j1w zmmwa{$vgQ}hIu6O_v)HZUSXt`rEI8pl)Mm2PnX_fs>4&N3o97(r*t31Lv-=Kcw}D1 zpx9l?*G9_9^)t%q+R9LFsPbpa*H)GlF%6W()Uw%3K1pSCNr@P8iJyiJL%)7eV?Ml!4tjDzO`uhL(d5NaaX?0U#=}${yj1`Oh z3&i%WobwowaBg@;s5-l*h!1uZRaA|f!UF{s{xew}i-qPW`FMe?j$*OE5!-zI_r%Qa z`15oBNNG&^|6;zu>5e1r_xHa$e*AU6pJL|!#Q!H7s@JhPW3d|>EMKo2pP~s(oYI zK~g2Yr3qDqi%Rp$)HxZKeUjQaLVRUqd1VYM3zZl5P|(x3 zJX{$n7D<$JKt=)_> z&gdE(fCXDey2-T?+vJ(SNVj4-2h$D5d}TGb=Ca~n-0o%jh^s%@ekY6@~1KJ`m(FFV<=a}o&z6Q zT3(|qA7KwU$mXbLoht71lC>+x$f}rAu!Y*WrgK-h+c||jNu8Vx*5iGRKO=oM2`7iD zUFkD73yKHco$JV_^LX*kWbse2_$S=i%32jG{(M0XYl5ORYQj&pRh1V___z})@$>&4 zUhyV(!*z(pELS^7+MXEblf*+s9u&a}ch_ibU;={mm&m#7O@e!rmI zDZeICXr6qN^?bK(29BZm>BW!3xCe1mx!L;Z@sf#w^MqQC?aeH&|G2Inp;?b(WDn%= zO=WRmb@4E@bf+Jcm6WNG(Ut$tZy)YuzkE`n=307fEB6G9im5qeQkq`U3eUo4D&&iSj*H2p;I=N`U_Z|~mHG<}~Zt~)e2KW7`# zZ4}paeEl7mNo$GJh&l+0ZHz&k(tCC~%MpmT_bKI(Gac4wQXi*G@$vy3S!32Ig%wrq z1P;)=#;jAO@kGiMp$T7D6|Qmd@%B6AB)4`=ub1i|jlWL&_#Zr<7u5P|%sNn2U{PU> zU4JKa3bLgmYVss^O)9~Iw7kZw%$liXRXpkoc2|`izy8YSRH0}gLG`Mee9A3P4An-e zY9sPgAy2{Oj8vw4qE25U`W=`l*&zFE;vBV7EB&O*?lRcb)THF`T3(}+S99OfiGP-m zbKUC5E|8N7?lnqzp*qiinrfg4w+;vEv@{C)b{FLr1{U#}@QRilNbrYgd5u|?e;hq7 zf6Tc2iMbb84{&t6c!*Emk{>cUSGv{s{#41Ep>9_l-(L#LXB5tKEfU)43^m&NjT$}C z%EF^keE%9aP|>o$%vx^{WsUGt$aW+V{T?S{;!!Y zvrQfM!lGK)G|w(p>u9!J6R+WoO=vnk?Rh;$$ADEO=c>yeZ1fq)N7eCTRf;|F6vNdiL)5Gw1*61@m9< z{za-l!$-7FtN;x!kVCxiC;f(w6VfTt?8BCrZO}(vwXd&t^rNT z#~PXEgyQ8HoWv;FPSfm-`1!Gxu?rMG|H|X@9qxCITj(@3X2rjd7Qg-#YD_>KtK4n0 zyhip%rKUkkfr~V+v6=SigMIq@*r!`rjmtLi<(Uv?vv}SrM_e@fHvat6IKLO4wM2aS zK|3XN5#PRQsE@cPp4&_HoyKO`uYXr|U7OfX%5&riK^cyOl2?dAA&*XIF-C@_q21Ffk5S=IT z-CQbIgM-FjH-AoRS`Vr0&n!sK>ge(7)KA}p^&@Q0X_`nEuZwk+-Y~4uUt=@NFOGNi zYSKQ$I|5P%X0#j*6l#c`@5#S|zSEeMAig~oc?9)MnisQpBa9~y`sH=F$(q;Lyz=#; z|MhBGKHC?FA>O{x8ERlSXUSL|FCpL8D&4QtzIri!B(=XNfox;Ke4Yw8MBi!5a-yjU_;u{dA*=-U zwdPXECV=tnpEmqy3%H zbpGnJB~>(AtDjpq^gLecs?pUx$S7bSUW5#hz>>C_w!8gA$~fpw^v)rs_+L&8&YhzBZkIql@iyRMFht zTa_w){_T}Xs=CxX{`ncNZCn09zRjoBi%xmtuYQ&Jr`V22;NPlvhlbbjL~G}(74bQ% z`}py}lCesDz82Hiy!z=)|Lom#e2f1!ipWaudsvu-J+%gjVZIL5*i8NCAAOqcf5_f} z<+^l3iwt3zV8--;VzYpunty|XS_gyEgQo_2iPpt+P|Y%W^>#*T>->*K8eR4Kv(rpk%?ayQ}vGCxk_KXkS>%+psIn`s~NPtbm>_P-zN z$OjQ@s`5H|)0JNQe6ggwFmj&D=UJc6)7U)y`%=HXo7zvce`;6dnZavbqj`acPw+;> zYua+ilyQ0`Sa@i=p6o^4{*$B`*V^O9ADy3W-G(t!r?0V@2wpeAKN=NJulTWPTyape~Ht#y~X~P_xVYD|EegQIXNWXsTaE~Vp=9+bn4m3-;5_| zeKj_*UtF3^j1=F#>>PFbieIl->p9CzDf&WVR?oNyH)vjC^V(-W_RstJ^iNm&^p@3b zDKdB{pVlcXt8iQOL}AteT0f2Zv7b+xO{{8Jr|I`2wSCE38TeP}zx~Ag#m7D_U-NVA zBYlio8u>RouiY#=D*OG?Jd@b(P@RuP&;Fu42sq|$a&?dn(U_IT`dNSBOfrR<*Vw%F z*nhPbZGw-^JjhXbMhC3*X6a~GJT=3ndKMHw-T(6I6x9E$%s@` zscxrkt0H_;&>k?`>HIZj)wpDmGz&}pCf_I3@>VAMZ6cTIlr%Q4`~$@Lx~YHH^P0x#nzCIz}|0(RRqo3G+X{w*ho2GC{hEM0fLdCj%G&Zw- zc)pQf|5^Gu(GrzH%DIvanx}xp3ZHWZppI@g3`6!flIf?_{;sa3K;@$;!=Pj<| z{nsc_U*fb;v8uCQ!#;g_@cb>o{!n^lcygHU6JwoDu6#Y)eev@vOUCNEzU5cN7p2cg zHps-MFZCG1CqcuN(g4=pxW;C+k3RDGXw&CIl!dQXlapfsowH+t`1z9~qbzWou279x zymch2Ulm_`V3n^(aB4L;Y0#iaI<6be(>EHMRlc4*@z3&g1o1?VBT-@*URFLSNZR>2 zeT~gZzfVtbKBQ^?u5vvvv_8nTf2Axu*Ig$uB>*X}v$nwvO|6GW7Fb-g!mlYO?seLS|A`NW@(6`wKVh~|tYB@x@o0}H8RR`yJH1>n)D%J;HnmQ^%O2Z2J9jTCEt;y1zy9L0 z^!h}g_;8i@w21x`m;Q4=MvG%p&s=eoVSK|vu&z(k+{SfAzo@w$Jh6Y&+y^cJJMh4C zHP|1_8xS?egE6oUTredKLV@3 z!_VeVm4kKQTJRHa8)$-Gfgff^&2}6J+B_s`_5fStAP;s2tH7n;5-@cr^5C)HHn1N2 z3JecJ{#f({dw_d}BM;s(0(r3aNaVryz_noH9OS|4&P5)4JQw+nhH={{(AVD~)A50-)Zz+1r%3?wnIKiEDW`+=*$Ixue>_5;UWfIN8gg~)>k zj7J_k%dVHkOzMN*Ms*KAP?qVf;@QHrO5LKC+?q!JlJm% z^5EBC9XO{Dd9cG|$gOIr88u70844hmi*d zRUr?SRU^;-!XLo?VA~qx!Fn(Pz8=AT;2&$F<~nfj^r*QVoC)p)?*ZF0bZ-WGgJWk# z&3y3SS;&KTflI;gwaA0l%t0Rfd@l0ff!86=M$4!3kq6&gfIK+kdgQ_7i;xE=EJhw| z1h<3jmmm+0`91PH@C__Q9^4D&gVSz79&EoHdGLVSkOx1#9eME37082A??j#r#iF~B z2UG4t9&7|7V7L2`2lw!2ZP$SVA4DGfa4quSvd54=#W1Eng*=%1H1gmlU<5quPsoGk zJ%>DagXNo$2akLSc`&ygdGOTD$b(OV+rd9>K^{EkW#lvX zTMn-v4`ze;VA)@h2j{u8W;g{ zzC|9KxEFcwb#Ob_>O17Yyzh}e9e?v9^5Ezw^5CkUkOv=rR|9r!4?9o!D?1&!30*}gmJg1x~dftZ;Oz5+(T zSqC5w&Q3!fyyZaT!TZ6lzylA8neBQQ#+PkkW)JYwgJb3xu;`GOSp`mL7c-ZD#-TBD zEjaqHn7IvX0KWo9v`3x|+TVdaz{5Kr4}JhvfyU9ugV%v;!H&lw4<6GId2m<|`Cf+c z4%h>nb0YHKk6;yOc0wL}Ap?0Z+y!~?CGab7H`s>f{!CbKCX)&`LyaHSV zUfMNgt^pgstzeh#F>?=?1Gec+`{aAgUBP)^F4zc`gYWV^=SASMGh*gya8&P@xdr?Y zYyhYAiJ57AC|}>0nE|%$7c)nI?fb{fVsIfi2fSxM%v=RtJTPW%0&hAqX6^#hGGnH} z8RM(KAh>K$%*+Ds0}H^8XT{7};A`LtaO~iixdCiFEN1QmSBylyANDv0dGMTE?}l1UL)aH5z&FKVy*x=jS00ZUJLp>-?D6p+Da}1N(!=jEkA$!P6(i%sTM+OJnA8 zun)Li@DpR^4$uVmfq$BW`~bt~QHVS^Y%=m-8CVDI0+)l|7au*9Hy!!XZgI$**pJ^EX1p9-Nmmv?1y#;wN1}+D0zZH3K=yK%2e}VhJ&u>G1 z5cPfs^57_NJU9!i1K$UigFmf69xUP8y*t2`_aF}jHz0qOVO$9I2d@IhgKs~FJXrA} z^599EkOwb(33>1ta36TW7Ua)n{`6Pm!S#Pb9vrwGd2r*K$b;Q?AP)`)cYq&*`@oTJ zA)jR!r~NBtW`a+>P5T311!sYScE!w@eOH}ZpNmmeb!mVSaf_$D|B{1TiEzSw{~cn{yD+z3ATCGud4 zuaF2^|FZ~vIa5=aOd>=G&(EB^&!4JVKu;54J!4Wa! z!843Tb0zpLxDmXrMWeY3Y|nQ!jiJjBj99a50z*egl?+XCB{Z zE&>lcvC&*3uv4SC6?`=50DE79JUAKba6a;2 zf3V%P$bvx)XVD{9VX{--C5vkGqivXM*d&KkptYcqgNvj-Urr!^BzPV9Q+XSBK#5L!D}8v9!z}_`EiU>Pc@pE;E?r=W&v3GOrtpq zZ2xSdxdQC^0)7J=4(C0mdOXTFR)xE5Rq?f^G}d9NT3R)WTO=0ji*O#LhJ;B(+4u=iHv z!OgEC57xbgJQ&-CJlOZ|$X~>I5e$MagIVBia1uE4b>zYH?Z|@*{)s%e3fu+$1vD%WN_&&G` zjDf~P_9xy$9_$5XfgkKb9vuDw^5A4}C3q#c5nK-L0-pelN$3v-!B4>~u;quygC~Hq z!GYjPungP?&H;CUcY{VD^RC^EW;(bQ%mM!j7K0yybHElKG46pK!A)R4a5p#>Y&jV} z38sT9z#Q;tuo!$DoCAIit^(6OMjku~+zp-uwk$G?i@_Hy9>T~450bd{=Vm<_>gKfV= z9_#`ZgE`ey!312!GD9|!`*>zkOyx9SAlE5P2lt2 zArI~ZTTWp-1k=I8zDFKB9V`Y%fOEhZ;41KDa1(gse~gG z;N3Cg!ABdB2VVgEPX9jzAN6aGvp#IUh7y{A8{Mt5be5w}3NJ ze=-}uf|fs-X_s*iW`H+?Bfy8jQt*TWkO$LSArI!KArFSZ2Jm_?Z7Tj4%m6onBfz)8 zQt*3lK6vPX$b((ME#Ppl0h|t|m1AEp16%`+0MBcUJoq&@A8d0F^5DbZ7H|vL0DcIj zRbU1%16f;`v@ECma}`QR*Y zHF#<}@MQuv}z|Ho&S6D|H|Xo%O;-Dw%xF{9nLxApc!eijkAwA^VBoaI}vIK zS%xU%#9-8-=8`~%?CaFeKwy7KjfsSd6$R3&E^Z> zpNBsZw9B7*XbTZRlzA56Pp3ysT#3VTDY)fufs>nZ9pTo&<-rZ)+D^AtW-INs9lip- zo0~6l_`UE~z%v9m@+p&Sz1yeI2jTtdtvCE3r})=fK71?q-Q;8Im-?P8x6nTV|JTm` z{8IQEyZD!H9sC3Ee&yQ^|1`W``S!xc;Qh+iK9x1{ss82b4L=0luU+QDzXtEuE+g<4 zp61^!m%?v?_iLBy;FoswZ`O`E{;6tADoqo6iegnLpf7}4S4t}Xe{zhBBo$%sW zt6x3G;GcjuJ@P-=@*NLgPQ)|W%^v;*o6m$FFd%Av?%^A3z5xD!fl>27Pd&G^>v(h`;@2 z!T%e+(o_C2r~L5!hepjkv{T1Ep9Dk(qJM6HZ+Wi2pV|pO6aIdWe)rh=#o$eNKR?y+ zK<3WpMa`Wa{ob_o%Y?7zS^ce^^l!G)FMuC3I%;-x`hi z)c%D}*Z}_s{Cao(TnpRmfIDYw)NJF?y_K!|KKQ!hUoB~w|9JQ-;WONPk;B))&xJq5%@;cSa`=Vt3q7`*XWMQ){P!0`&1XIQ zQ#QW?{-%rk`_4Z2l#8S0-|+!X+uC}7&_LL)!$J7QN&aJ8fB5?gsT+@dOKkg&hyQwV z)a>ZtkFxnX_|J=?<}MHaw#_exe>fC1zi`_pt8edxxXulb-a~+UYNce;NKu5C3nQUk|^$Dr#Qov0t5Sza8-3O^cd;@bGup z{66@)nyC4WC;iXu^gA3(|A|D+4?Xhl+VcJ351vl@_V6d!{CM~yW-y2G@Z)U04t{hU z=T|)Zw>G~VzVqc#^KOstyWRGE>*4ReDr!bO`hRchzXSg2*-^8nn=hBNwEsT%o8kZL zslPwj_1B>-`_|V+%~2lxM%w!Ihrg6_Fb{b8&nmnBjEDc^`l$K1JO7l2ZT;%tXD*DI z?=uf`+Q-h8B7$fi%i#wuiJEVCvH(HocDRi z(|_)_`_Fp#c6a*EJ$As~4&T>Pe?9H`+Xuh)uBiF0C;zwX@^xUfUwOCx+^RqP+wgvC zl=1Knt)%~X(!a}2zYf0JJyEmX!#{8H%i*`f`?cTo@E^hZ^}ikPpWhobPw=$wW9;_5 z4}Q<8s5!!8-yybrI~>X$$ZCK4^@l(80spznc=);pIalM!{}4O>I{5N6j9;GeKjoAk zzSYA~^Bxbs!sge*&xik;r+#0t>vsoyzel6yB_4jf&F_PctcCaJH{RB-!(r?vJsvgJ zc=G?FoqvD$K~J!T_N0HAo&I?EMeCA`|L{xUXL!XuL0V(Y&T{tNhvJo@L``gb@S|NFH6_|qT$dw9RSpYiaK^{hQS>Cd*) zuY-S!b9E~``rT^lw;X=lGt6H+@{4Tw_3-u2M$JhceuB;KfIr~5sL5j*$G@grWT(Fm zJ_p{<|8!tu@KyL(9{)JQ_K*GHyS%{M)06)bcK+kxpMNoGp6t$FEp27})xp=p-|3NG zZp$x+AM%p_{A)dY-+Ja3?(}Ck?PCZ0Sa`Y3Y41HwbIK3D8va;M{zuyRcQ}IQIGj_g zai^bBY0LMA{~o@No3C>69}j=fmZ+KQNq@MVejR+jm!swokA2Uw?YkWQ;#Z^QpWNxE zth4i95C1LvIFJ7tWBaci@EL!PnoRSY`XA=#w-5es`0;K&MQy%{{@3A1_Q2o^Jp6@r z{{7*vgHLz!6P@(O!!LyQ+q(_yb+q5IG zeMFu1=bvZZ;@rABeXfP>`EZZG6?w{jshxHN{_B55&5u3&`!>H6{%OwY{^(9SvnH@y=zFZamT+Vb1sKYN$CwMYJ2TYfM6i|_gG>$N|cXD_>==4em)=h*3scMN8{ zA2o0Dq`%ZoKOg=pct779f$#Ala|^e;a!t~HOW}vXFZ1;6C3fFl2mkEHjQwu;lvnKh zx5Hn?8RX;LymI|A{k`y|@YlKdlxuAH_Q!BG3x1iW{7anj!{>Y&HGlHR|6t4K!*}{O zZQtYDI@`W20^f}@(6@Tzoqdy~@b|(0(ZkzDq%eLMU$@BxqhhOPfz_$gnp z_Vui-{%o(U+8@il&-YRDVNd?6?fiSg-wJ<$hgZ&tre);AzY6b}yAUqgZWY`%xUfgo zc_y|5{)GP|-t!UiYvC`0_ZyeC!9NFojwk)0w(eiSe**uZhkw`R#d|0Z?u(k&d-%CF zFWygS|3lQw_V|rV+b@atR{C)MoNOGweSs8L<%jP9-^Eim>2}>Lfgccynlw>IKHrgF z3*QTVhMP}u=8fCn7r?*o;djaeMBRJ^e@qvRto)xmvd);>75;ao z|C~4%zO@na)vX-95Z-UhSpC;#8sy03wM2EKIy-M7H4PVvvX0p5i7%R3Ec z@m*>xVcCV96&6 ze>EsXW`~%0lw1GQ!<_QNpK)x=_ZdVM{3`e?gP%1|xnd_`^MWP;Ko!sGaZ+cZ!)`d&<7YE_)3AcPCSJgP*1Q zSf#tjzvGFV35Ng3&8O^=5d@zJKkyWPz5w2Yf5s#4JfE2be_Ln&wz~rUEBHkHLgc>z z{$t)rImw;=rH=kP;Xj4<>l-onEZ$v7l)k9Dj-6Oz@h(fEcGVy5RJd|?-YHXT+l+^w z4i7lC)%#;Xg6bgZ;BR9e-nM<}($-3Q)jn1b=kwk%a~e_XI4NoqQe-iJ=_@!R}e=Pjvo_R*CJ`Vw-2BOQ``rNFY6R~Hh((^&ep4qLWa+;Xet4e0{xSGl z;QjRP$l~q>_)Jg!{p|cR;U63qGyl`Vo&PuXSY7~s^@TCt=c}{e+l-I-?m?`8Uk1OJ z z&98ueeqqdfx}{tH$L)302KezyV&*j-{z{wQDe~uCvU#a)`KxXJ5`zye_xBGSF?<-_ z&p%|sPl3PNW53&N`xU@{3}58o)c_SFY!-YM-dX#=&5Lt7J7f~F4Xh;2C&XFkse^fT z9c+Xjdq?6iT;#C}ek6RA$3|17jYPJho?3Rn&+sms-#j24ei8g6Az-!RlnHh@bKtka z`>lD3;WsDY=fJ-J@7E7j!M_DhQJnmX92;$de;?j&O}QJs$4dWtY^^i!N? z$?5Q`;Rkx^ppRV#Iq)ys6Em;y$WOQJQw)FHy)pB3Pdk6rZs&90|F+71oL>bWywAUU zo8ZIne(iKO{1o`@9{v7i>(}x$#_9WG=DQw0@s{l;(&68Fh<8Ih z{%||}V)!56{pMkF;Kw}dU%plFcf?2*6DmQRPj1%9BLua&gyKRNJg;YYgplpI^W82&BzEKmMt+WF6c|6y&+_Z-+N z_&XkpnKM0oIAZ&`P4Ii4bKrNvKj^WaGf!CsU-IX~^OPVmo8WiD|J~icMqHbkx=D61 zSw{`Tx#{_sd6uV*53t*K8k2}e>(SAjM(SsFAI*Tj>gAYuyGO@mvW|rgBjA64|JqXr zdt@C55#eXciBr$J!4)FF_M@eCJ6QyO_*Q>Ex(2>2yq}-j3V#W_Uq9IcKTf3Y(b0M4 z)22K9@YTfQmC(N{{O{o(^62l(2Xo<%f6c$0l*9iKez8a1na?hQZ~r&{cCrS3H@sgv z*$Q8|Epa;$`tO0?1MjDQn;znsiT`}IEBqe#MDy7o>F2_~_j=5{z}THDchZkMzG#{4ieRAW_fTi8Glve)EaF@H654<`eCEv2KI+^Y^{s?|}EKqkQ-W z;Qi_-0{;bk*i!~)4}2;7p!faz@jCcE@HHMAR@ye)4nLoF`k(fs|F~TTd*M&`$iE-7 zKZA8G{4$Tc>-;mwzkV8l@BN9tpI8e29K4^OSOQL>giZ;9){-9QkzUi-rFMx0D>4yQkAMSu3b|CME9_lJ%YP6jwV344F@TVNp zXrAwxQ{;Nq1s(hFp3U)%zUzWa_;cX>=KTfmL*f1U(Jc6h@P7Sh1$+g(Uq9La|2Vu~ zKiUc3;so9er@VGOyZ67~e?b03x35d>XwREE@__P3n!l!7qgO z%fDlP_OIZlc+#J2r=JObVrPH80KOESY@GJz+TWQ4e-*snIJ5%(I`~viAOFd&-wp7W zb!jx`xzkU%+SYF;{5JRukB>RY9w%b(JG$Z{JU$?5^Bo6JzkKWC8c+IH+UaM)AJfyn ze;2^_hWG2=v)~8A`}OY?@Ylin&1E*guZ8dI@v)t3AG;I&>AsETzdZW?)7C!*KdoP* z?|iT$jw=Sg%p>oNgPHKt`uocl2zhwFac~y=yaA2=`@isq3~clr2RFdag8#~+pKJdY zKKIPVgyWzXV`A`UXZrIU&*WM2phn;Q;Y|3o@P21}3g9=K#Wy-U`Z?!NX2CB#yU}cW z5D~0#IQ2k#|9%DhHRm+?zJId;ejof@p7d|C>vt#o^mF~&XAFJ`ykGn3n92LE@P6y| zO!&8Q{rzVF{5JUQ9{rqsms#+0&g0u8p8k2O-Tzj=8|OEgZ+ZIvc6*H90RJbxm9xl` zzO!$!6aM7$%!S^D&S78aw@T__gqJ zJbmmcyN~6-x3BZ}v&Hb;;Qi(SbKo=K{pJCy;ID@Fv+pMOS@3@CV>kTQ@DH`1fOa3h z-zooKzDGXZJ%QJ z$KhY`@Gsf?9QcCY`S+hy@YCV_<|&)t?}qoAr|gFR%T@mM+j1!5M-o0A{>dbK4*c3A zd@=k(N%%SN_b1_3!QYdF-vqw`-miV^-cSB5hb7NH9bV+`*MD;051#FB-(vW*B>Wus z)Fk{W_@9!MAO43V{BHQYN%)p*rhb`(Plx|Eyq|q@;FINF44*9jIs3_fmCj#&Z^!oE z583{C6a3|T6VcCq?}q=&HU9O}as=%^37-!CWD-6Her*!I82+Io{2ciElkltH?@7XM zf?tt@-wl6j622vla|37-K!CJ8?R{@f&dDf}>aKO4{APyVa-lmC|e0fVty~I!!FB%f^Wo1=!mozUO~P-1AD)D7 zfFBI+XTP-blINcRFY=$_nIliOeeekQ-_Q47qm;s*z932Y;WOa<);O!-Uq~Xq1^&4t zd;|RYBz)Q^_NtTc8SsxJ;YYwf0PkntQut)~&)4~1<+1POwtZK_AGXkc4zdOQckq7g zvjKi)68W^zy!(+vJ_CLi{1Kk^-Og^`BjEpegMa>|@Y|B`^Wp!RgkKF`pM>86|9ld@ z0e%B~cX$7Hts&CJB+owsUgST=EuV6g?LS7qpL%1X>E~Zc;SX5CcRM}u@7eP6;a`Ej z#lzoZ^Q+;rZfZ1Jr4YgPFDdpKd<%T%-}4=CPy1S0&-M!cR@Y?}0B#!neui{j?-}SNMV?d@lTj@P0m~96nk8i}sWM8lC?=?lzv{ zd=q0U{5#~o%ERAn`;a{%{k#0@ugy5h2k)1DSNM05$mhcENWz!H|04;%2>vyAzd67f z_|m)m_1g;nDZHN#-2*>yWs>q=z#0MGxBT#LCy~#EeR-M0}{rAA%l0?5Y z7js4!-p~GB;SX5lZ~t8QbMN!Fe>wcHB>W=y>?Hge_{=2yR``BN_&xBw;Qj31W!k1Z9B(W9(AEC@9{BYS zH2QuMu+1fW8~&k2^WhdKV6QP&JM%yIEo<;^9^U!xNG^P*NBrxj9R4`?I#2m(?D8#w zuZ3^p=7&pKwy!nth43t89Q{(xwdJ?M-vpoK=C4rlLBjUHKL#I|OaZL&wKTYM;@dQ$4R7*0$Y^DI?o?}eX9wv7xc=?;n+1Ne zz;71#%>ut!;5Q5WW`W-<@S6pGv%qf__}{X?#=}(3RT^inZYcv+KA>=;MoYgB9#!EV zY22gH;`i$NpEMr4R>c=fN%5PYFRXicmWOcbzABEtLf^}^qDVk2sQ4YMz*s#+rGK=( zpH!h%S;y-8G>yk-EY*C+IR3kz)Uj^)Tp!L_tF0I7Lw*{JEb&~FUuy-%V_Lt1^nC}7 zM`*M_i}7GXr7RxriC>kzXs>RKRvM4e*q}4A!qW~^gjKFxI)5E3|E89R!C$)x>m+2< zpY;8DEoka{EpB|J?=RE*5BlD=yH4zX8n)>AiqE&NZU@6OUZAl=<8+PlG~S}|evMCQ ztk?L4#*a0AuknCGRnA9hJVj$)jl(ovps_^bbdB>g-lFk-jZbN;*BD>E`1`bJR*Up9 zRy(jlJ6a9P3fK=?@)iysGGt&dWB90XU4lJ(bnDrz$A07m&3hbtld);UR3pXMlrTKi zXh;~|(y;oUJGE4Lqt)-c;RhI2|MZ5pGOTv&4No(y_U{cp(6IWIH@vlB^*?Voyz)rAvgx**Sz8FjMe{26n>~N;+sU_hZ&YX^rmyTVfjIC zczdHNL4Qj%jxZAS!&Ku)V@J4YyG%9kUfR!j)5kj|Xve9>(Z=kA;g;8SQW5^DrSY}t zgs3ageiMZsPI!tKE%f+i$qD}~!h6JpXXtQiJhbBTY7MRYXk&}k)AE}fw1KC$Pyh4Ycc%%w=P>0{5!~d$o@6zF`b$FQ`(BwB5;r>B* zqVhHn-oiM<*fmYHXRBOk_zMwkRC~iSba*f>e1s0qiVH8*;gjOR=j-sM^LBbbLMDsKc%DeoQ)v?DIY0(hfCVJBagI zB0Lxu-dl%f#f9hT@JTw{^7B@C!^bPdswcyqPDcbmGhVkPf%XYqi@K zb$EQctqiJk;@j;}C#vxHcDqW4$G6+1omBkzc6-)ID%@(f)!0YWqxiO@_*wegt;4TN zSK;y*BA1(Vc*m1fxO_*A%dI;6jxH*^NP+PV;fd<^Yr;i6&aPGUYt>6TZbkUU>E3$p zuETf5g^$wV{LyEbqws6uSE<8$=y1#aH|X#&ap8~X@T$1**L3)jxbQD@_}aMewhR+O z|7~&M-E_E7haf+zyrXn@4;^mlS*gRv#D(9W!)NPotGtis@Qrcdujz0@er${H{L9?= zUW*RT(&1J*ZCL=wdePyQp51i#Mjbvzr!z{22QT-Qt5SzgiVMF%hp&tae?*7x(&1M6 zuj%lt|A(^k0F$h!`hKg3D2j`(A}GS3AczW`gCb7n?&%z7x>b5Q=bT4{HKQOdBFO-& z0-`9chzN+fhyhV_6+}c{T?4NefE5)nf9Kx%*X(vN-Pdm(9%lA;PoFw<>eQ)l@2!3# z)6eaE7<@bU66`sQ77&vCJHff0Q@~a77oezA%iMnOW$;b^gRg^g{pW#i2j})&3%*Ox z^F8oA0)H4>_2$`n(XBMu{$+um0=`|~LGWGRoA!h65%_uF`viV1__i~dJzUTCz|{hO z7(6WS!)Spf`M)FZQ^0o!JP5u^;4Sby0zVIYpTMsL-*%Q@Ke$@p4}*sVei*GoW%~tw z3iwX&lX(1q?*+dayv60WGkbWyJCDnQ^Zv!hqaVMLDGHc9_`y%6?hWrKKYd0}42EQ5n`{0<)svZD; zSdi!IrVS}U(GQ=0KI3p!uaj?M9L>Br&ph$FjPrIs74omTlW}xol>_|H`xrl-{Zd82 zPX*`sFaz!ee-Y#>;05p_z`NiZ;KzZ#1N=ka+&`ZJf6h;tAYTvidGgi&%Q(VU^#jPC z^s8CReyNV7b+XjozxEgd@^|ylpF!}SJe36$(uC>^@PnVm_+U_(PP-j+`xb75rj&+=lbuO zqo3gSG>M2q7EzZW$<;_$;)k5w=VZ*;Jn;#qFyhP zzs!99y7*D>yTN&W=6U$dZKhw$!_UACpM9{0&wu_7&hz<2^l{0bS9F;ko+tVI$|k=I zv)>**4|xduLg?q~^tbkz9-cq>JoA%YY0c^-~}j|I;C|9)^2^l<-w8=U)}`|Xe5qTkkUVdZkabx`gEd?)l@MqJ82 z>*pi?u#c&}0N({G=I{)0IiFm_;_z(fc@y|v@Ezcnf^WZgR{jR!l0BcigV{fZJa3n!?`&PK z_kq*L<)6LKvvDVrKNtL98lWZp2Y-)o-mkZTFN1p_ZvlTd_%i#L$`1bR?=!&HcNOq+ z_AriZAk_}=gMP&LAD~Ct7nbbVcMk*dS?yFd&#OPZkMV0@56`Rb{3+vNUOn}G#>KpP z3%Hn9KmETpE1t!>H}n_6wiAvVDY)cE~^fD0pq*Dx53U6z*QH{#dUeLwhi@FmE9j=1E{GvVMS`2FC&2j_W%$JN0Pu?mU(WeCp8 z{X6u$7yO0r1J9pVKgeA?qoUK}3{;Cy^M zmKs8`^Ml~L-US6nS2NQGVl&KZ{IJ2?-2O? z;JXC=5AZz#f5FkrPSs9UF1N=5z7EdI<>S;_scb+N z{qF_m{^#+3Ew~u}FFKg%;dZW({Ze}wz~!^Z$){(6U;T6@|3&zj$6H1|u=i~A9)s&7yHr4hcV9k5uXRX;Mt7xIOp+s z&Py2Q@yW;EyTSSRdnNqvi2Mb{bbA|q_#F89DNGOCp}L>=R&o9)aVgH1KF;EY`+plP zz~ymP;HQAE3takcPRVaya32-s4ZUz_Q z>Sb=Ghu7!C#ctU1S@0!rF8>4KTlwubvOL`vyMp1;M@;)fiL5^K{NdGD3=H4{y&`lc#>-Wb0&vC zUM+LFKLz<^@DTW3L4ON;3C}00A^%?Rb#QLar@{Gijr33X=R5R=WX}Z8y>NSeCv%D` z=%IhgKTki7$!{0rPm(!3w*YzGj&AU!PtC?*349rx$KgA`*99)!&z9PKJ2=;W8~83k z{+Gn1Jn+#V>vz1rt6t3bE#N#qycGN{a6XR;gD;0>^|ZiWCvZN#jKIY_@BlckFCPcD zMVWpR{LI&DZg5^-p07UkdL}RCtNX#leD#bsFnOM@c%E;A^E}VTubc8ro{vX-zEmhM zE{@FJ|pt zXfXab`1Rnb>8w0oH(dtK{mj=*_kwf3@paR28%)pglUM;?gZ}Ir8RzlF*K4=Fm2tja z`yJ#1Z)03O)0$Kr_7Z0QDeqwX7T9kjF0E6xU&_XjFzaTjq|BeI+JSz`<82K2Js)B6 zoPQAVy9D_!L4Kbg|1tUl>w>(S_*UcE>t%VG59~Tf*39*6 zfG>kzjdCvm-zUg_k?Z*!(_@DGJ>cu$T+d&?w_V5NdAZL$f#siN@Co$jz;}c5JRAkz zC+O*dFMXcr??BHE@SWgG;GgCC!MQ!(1K%s~hrm_WGyPo8GhfQ=UlRDs!I#0gJuBe5 zz` zoR^yg-wnPU^4qzdFEahS9WMvp4$kfQ3b^VWaRxgQ<_-viFu<%pA+ z{rd!N1Yi0JEB9>pEeXCG+zdVfSABI>{vz<5;M|@Y!1sW2d+yXFGTjd^r5d;`}5z6AaEfbRsafIkMl?KY-| z*Y}85F#DImcS7C>z8BmBp5*dhpY_iOd>woT2hPjA0etBjOb;*j9`N1ZyxhmQ z{5NOIJ>r$HAN&$-Klom7?uR7!`nQ-KErL*{}LO<0r{iRVpL+GWZgB5_}ze0zLxYEAWfB{2r!%JLGTR z^5DGOd%%}|Fl*0aTn~5$dXCUA`}Ydm2p;|+)3fP+@a^DS&j?&~7nA4px`@kzb31PU z-!1TaxSqS2o+a4%82A!6*MEeT*}qeeH-hg5=jA5BRX>{5KLTF@=lU<=`UUwLxPEYQ zul#cl*MASwzYhKw_&Rt6{0N<7|52)KpE_73+rVEAz9jHvaJ9e_;L8H9frkZt7IA5P zefNjidW5g9`TF+}@HXuEGX0k1&-e(F=kf4O@Dcbmkbe~XxXYOQC&7=Vb(N&&4)FJa z^XHmYFK6=m!1+4Vy_4}zf%A3ZAHn%Lkv}i=zK=5b<01bM)c5n?yuN(B{5^1PKVL6T zKgRU%^)lagJ?!I*^K~oV2RQBu#>IVrHEUxGc`!QTiwe*yjvaBk;+z>m0+>ED3- z@p|UZ9pGHv4t@>z&5*Bw7q4P^#^5`^?+3pC>)-3a+tS7b{d^Acd>`YAYZ&M2YkoiF zXW*3f<)5FBnAGmi{4|pUuiEC2B4$36^Bj{(R(Z-@Tt1pOZezZ3ji$bS($^|@I)?*Six z?}GfZjI6%LUpFiN3h>tooIlT&20spZe2{-5I1Oj=PYwK2f}VGSe?#C`gYOmix4{1a zej)Tf1inKG4Ep&Y_zS3mNbR1xp7A@t`M%97zQ8z-E52`20{23m@7sJ9d>QfZTIhe| zhFQOz0sf3H&hj^dpCEAQyB#Gvmj(VM@Yf0aKJbyi{|0`(z>hRD{htQs?P3D|sUV*O ze@x&*@WXFp_2TjNKJbr#^L}wH_>BU;6Z|fL{{j4AfgfsN_CNimS%01ke!RfF;I9>U z1w0MT{qQdEcMI}YfnOo;Z-9SQ;17V`2fhn&awr9u)V`10GHd_K!JqNvS?&WrLEv@p zWr3dq{yKqQ13nV?cfijV`0v3#E$~BM&Fue{z+VpjOK|Q_ANb*4nXOkH{1pN}2iy(* z82a5V@Yj5GR?i;rHG%H~?+bj}Y0Uof1g-}Eq`<@AUl(`>{O1DS0sePz?uT9AFWW8H z5AG27KJbjdx4nkhzaeln_=N%wgYOb}2mCt%-vR!A0^bGxq+131!H)*#_1y>V6Xds@ z&g?IN{}b)22mj62X7$IxpYhFEJ^(*K;2!{A7WnnxuM_y);3IHu|DVCH6y%@#T4w)l zaQS;5s17FZU)(-x=PLLO-=5`T@E-{LV(>o*{EOgEyJJ?*kHKFo@V|n;2AtRH`OD1y zh9GYOe;2s?eG62tGr-^f-Pv-_1h?Ed%P#}3?wRFZ0e`!|e+GWJ!2b{8iv@SFxWf!M_6jPw+dzZ~h_E^K0-wfnRnP;}?M+X=8Tk z?`B;7egeAo8t_-&!#ICmrUbrvFXJzSo_B)x1b!9xdjf8e))^ZGu^&g^vm zwT@OKOR0q`pX{!|aM^Q!_s0sKC2-i}W2r~hu&o+9}1 z;MbyE&H?|SAb$<`LjwN}_#wZa)&G0&mk9h&S`bO|*wY36a`2SEec%IdUava%#|8Ow zz`r8!Yrua3&hyVb;ITi<+W#1M3!JYLk6vN+S00{~KMnkC0)IXDWdeT__)P-;F!@Zw9p-5q|aEPvqtwvxYu>Zq6jSha_$>hbnsZrszc`5fu7ZE|`|RI-lsf|N#aV&xWS3PR z0^fEa8NtHt6{!_~ox;{Cx1IhFN|8{W1n_ z1wS5K^K}N^gmQJ@$Nz%ygHWym{3Qo7{l9{q9Qb>_!~~1%vg)nif4P_mejD;12fr)K z#?Sa4cHzkpW`8@%_*2*~)rsJ@)R^39XfGdl^efDeH$r~~{G3}Dcm%u& zzVBfMjNli8zX9*pP+E|Gz6}2R_cKFIfIYtif68xIx%7RC!VeSh&)m-BZ-o9U zz_qVr{7UvqbqDxOBL>ot|2_Dba6FI0L*vZOb*C}~$ z|C^Y@J`DRW0RO}bn1Wx!o-cscka!~S&wb!O`WMqPLAk#K|Fxch_kuq?!R){K_Y8!f zUjzP$e=&X={QL&+3;xdZe+Kf~!B77+livpY=Yd<@O#V1-Klp2oWPr>=p+ z4fsFyFknZ04^A@sf1YFd?}Pj+z`yk|rXR~NRT$j+T*hyL{2Acixr}i=`=#oFfA?CZ zpSSz@;CJFZ;`Y;+qTS%;z3ktwg8qHrqdOTGf&UBKvYUbPQSPy;tX?<1ft7nA{BHyQ z^c$Jr(O6)tfai8HUSuCrCBYwf9pfj1Z-C$DXMpF)^TA69%s%YA3jEQJGw@CD+rh7_ zFz|fnf1LB}jPv+Eni7#T{=R07*>g4G{B-bd;K9<LqPwbY0RO<-m|T#3Om#Q-*DMS?z%Hx)3jUSL8Q}ATV^geN zpS+UEeZo=x>2P$HKsAu;+a6mttVK5PCij{*;GUy?A`y z4SwN(DL^`=FA!sPo{fg8bp2HxAtz;)nHrw>Z;<~V*< z|8d}V+{y&kQSPbW51z#g=i5~&aPPO7Akv3w3|_pM=|MQE&IDijB-8VD_~FCgU%7%cpw;+B3;6F03 zdSMx+YJ*?6&J4k@s(LT@wOYo}Y^u+LKi*{g3+$KbKJY*Nmg)Z>_+#LQU&X+&sKzmG zVD|s7naT5hw+wz;l<^JZ2Osz+@ZRzD(BA+LVm!*TkEzZDKk_R~@Ezb6fM1J*_bc$5 zz?(R4>R9OiEx4AVOZxdB{CVgZ%>F6H**fG;1wU+qDaJ6PN`k-c^Gxs!C|CM!A}Ma~ z!1{|nx9~CWV~b4wIQZ>5;NAcONUy2~z@HEMX}FPp4$Cn8XWz#D{Ymf_f$w;T0p2f8 z2S0R!@yp@=47mCx#!rHt8u(v-#6SZ6IS2e&EKpjg?=J9vz)tSBd%!>Y6Q+m4M*jH~ z_!oAt`WoSfr>?VlxoG^6etvK;`+e#<L&2J zu4nul_Dgj?_&G;21-}OWC-|RtGX68@e_@{4{}jxJuLQS&|Lz^Ez&!l94*s<7GeJII zdNcUNzhNBBrur!OA3x6w`6cv!75shgXMnG#egppA-!b_=!v24OzX|dA3hH+e z7a{$_E~JH{-Z{rD}s;^FGF(0sZd>e>FBv+|Yj&`0JZY{;)&Yh1g?_&Qnx{vOop80dK&xVg^C<#G5<@aJKmy8-eSf}c$JTl%S^ zUS9-nM;JecsZ-qx{_r|$aQS-yN#u9nCt&@;^VOlW4w3Bt3?{tWm^#%9!B4!H75I9T zdn$2hekGpAZi9U7DNOJ)(9;C3-^TdQp2{w~AN(H}DEZnEL^V`@CNAyfis$4%jRq{Ky`KC$rpE+3 zj|9J^#|nHD<-QvH1z6v`7~D(zNn4z6pMm^)?qGr+;eG)Bp9$j_##HYFe;pilEaX29 z{<#O3{QrU90e&MUo>;D{{sjK_7?a2LrRqp(IH|tss~Pto51$79cQxbRV!u>pfPVrT z&o_f_fIs^TX2|-X?7~j)%T8yU$N!hW-*yS(??>GJ0Q@6gWuN~r^#2L`&aW`}A0i%} z(O~u$?_h!_K;8iUn!}hppC^>SZ~Y<@Y_rR%*g2A(L-%j+L(ln;zh^rGcsxsWE4cM# zjHe<0Ao#VYFa1;gIgHjJlApB=R^VSz?$O}C73NDW@a2E9it=%x27V|e2(N@6J_7y@ zOmIGdaz6#W?{Ox`=aY94Km5sbZqGRf%aY5Gf0Xm980YQvf|it(o~7DZW_b_Ir8=3o zr042SFnLr-$6S_1^;RpZH@YF8OmO7L;6meUAK@kl**Q+4^1qz76MNa6Pwz?}Z;Ye~k0@F+IyL?YUi* zYUzn)s?@{}m)@tw_grv24vCZf%O9Wh^GDw%>7gJOzQ3a=%RgIn(he3^NI$Ccq305z z9lr>^e(tQD_Yjxj;WI)!s3>1c_Uu9Ya61j)dxiK+aK2+!e;@o_!JZ4iw+sHfiR&59 z#>0=n*9WuwG4R{bkGP$$pb5NW|2CoAb>h$2qFn}%-`k(n|9(lH{1d=D_L=zX<#Y6W z9(o=}zrgfXbqo0N&RPH52VTLsUfljC4Ve8M^dsKCwBV}CXZ3`^w+s54;ExObc@J@^ zUdR57<$(uKug^h#8TM}jzgv>u!fy{l{t(D>`(H9-_U{nlc?G;9@Fw^^2jg5Fy@v1io8n zmq)?(3HkYXV`k6UA7$;!%QX|w`YLw5cIzVeECSGf1SoH>E{FB z6Cr=z1imEn>wCbr3vqQQ&BNq=C$!^hIfp!tt1|fGLVeExe^AH|yTL0$JN^b-E%^V1 zQ)bV0!Jgygaqx-X4`n0yt>QchJsx3PJ5%OIs+Q0$%d$6Bs-2KugFU?eeiwYNApd*t zlTcqS|NISR|4t$A>A`ovZ`_}8@I6Aibck4PmsSA{6T^L1$?j2UN3(mvvXaD zpVNtNRc@HePiEt`34Rj#FZaWx;2j|zzQDO)=l$Tjgns%s_}N07Join^{)&({)Zj-# z54Y#_;7iEcyxljzw+s3CQt+L^yzvI`icqiLfv*ew?vOVlo-dxw|0jT}gnFgH)q?)B zh)a3(Dm*87GvfAY$S(kkDzDwxWmxDhjlzSI= zM=1AcXEA$Jm(2R-rQkbx%^YNqkZ9rBhfCe0N)AyoX5cT3jL@Dz61KX{H0uvFn_xldow#ot##&o<;q zuID@8D#356cQAW)3+?z)@LhtupK~D(_qZNG{*%O)wy^U?$nO>M-aha(!EYzLli9gP z@Z0H^s#M3(I&>%IAw1q*2l?%S{`blJNR{|KsUIf3l|Qe8o*jaod%-7yAO1Z@&*ASP z`|11;{(YSX!6!=+r+D5j^j{ZosohV!owYk3*E*0lBTk+KJs$xN3-jb}fG@*No}V8A z-z((vL(gXRm=OMrozIG=49{{J5M?LxUveh;%}9rG)0 z=ZWAdLEZuO3i2HxpPVPlL+F5CAA|huLj3<2{3Ibx{ssQHz+XZefKq>n-^u!m z^gWl-Pk^{&|88L(RRcdn@XzJoR||ROCN7WoKZL1Q{Ty6{bIzB+{|UZVm{%P2US`jd zFz+&g?-b_Aaqw-hljrjZ_&y>3e1_{0_VM<;P8!!}9|_N~!%Wqc^7ys?dxuZOh3}9a zseMz}FA9U-1^qjOarQ5gJo!I|_gE>7%Rk4Q$Ld=V`rWH#PUk5NkqOZ;vXI{`tVhlS ze_V*qE5XA;e!Crfr_f&i2A>G=`NH=xJNLlPyr0^@*M)e z&)dPxLL5HA^}ugj|8sV*b`4yykO@yiEouB?~^%w zF9YIa8SVaa=m`t@pLag9b6Mz*TF!;~rond#`F{+q7V3Kq_~SzR{t$e-&`%#BzE!;r zdOx#sx6tk{2frQphsVh(_?jSp9{AOWPcDBm_+B9o+zYM}?Eeq=y@Edt7ce`|7V(ps3;Fq8@V$aPe+GY0$j{q8!0bFy z;I9C`8hW^$Yv7Ly^%@YD?Ej}QFWL$DC1D=&Rq#Eqe;ew%7yL${UQfM{**Ou~@zvn> z3h~wk-y_uP1K{g|{oe-PCHU=O@O?sl`=5)LJxjv4uL0jH?3V_?w+r)=2KchDpYv|c zg?@1r_}N09{{i^AFs?lezEkk?|6I)MU&s7```-fI5%O~r{A!`x^TAbuKfeLKL+CGm zllhUVim)zt(Iw2Dj-cNKz8CGz$Jr+MHi3TtdZ_vli#-1q z#=B#{mxT5`P2yXucVfh!gV;XsR|R_Zz)tS}cX9o~{?!%W4+`;l#~l6lLw*&-n)UHlg4B16(EC&pPTdmFmS?#Djsj)K7N`{Uru|yAbDRgD(s5 za4q;Q*w4qid%3(|=f61@{CxD~%${ZBRj$Vleu%J+&VZ|gy!2-9C1D@+L&T+V_Pf7e z^8_^txRuKb?f4t;eFA^hPWVm8V=tFD<+0sDe|#S0zBRh!lZJ=deQ75gTT3jWh7_(!YYAFV?Dv<7j9Rj zzwDJ_zD_d(Qb7Y>G3W6)TybqEoO32qdXvkN<8#1Hwp{eK3dKn#lMjSUJ?m;j?b}GL zg_C8QIvv&VlB#`cK40wjtGPxolX0f|o$`iRuj{N>vW1pIo$joJjC^({>7|-9uyfxwX)Z@?6)R?Y z`AQ};QMWBwe_!33=BkF+v>EDK^3}MXw^(D5#!UlhT~de*tAi}Hm#xvxlgqOGWKb6f z1>D-6&DxEbVojfVb1fjvKWS#=FSb;@?0B_T9TZjVzO_Lg4O4UWGZ{}HR9Wq%G?74- z=Gj_Xeq|hUq`6h?e!MsRFT^(uq?w<6*z3t*z7kF}%pJW>Yfk$uxwV#akjtj?+=XOX ztT>PbHzp;YE!7$fEqPnEQ?K;wp}MA2ZWfzuT6&RSy4Y)zq-ulx&SYHuQKb~<=K5o2 zyg3c54zf*0k%!a)!S67qSJlmFx?pl;jjg<6v`P`15Af;@JB93^815BEvFZkO087qb zqnNIbP0?(_Vb@ptHhmL-llsCG)uB~jz z=CeLtAxSPuZW~c$=80}9EflHawe!|dBiJs`2Rh|)CD?QXR>NAIzdH$bE!jcc#4AsW zMWvSA)ZFenm~I4FAsTQF2jQ5to{L&?mRuv)jBkwE-0G}UGisS=snRleMy*IZY|WXo zwYFx++q9eyWP23t6GJTL59)?Vo4xPM8cjj1x)tU^d0L~!+lfAuy3;t z_10Fq7`E;gl{NOvZkuy;Iu5E$HeED3&}BDb`iQDm?8~8>57`~7J&iHt(ARVYS}Nx} zx+!;XXV|YujYseRp+gq(!J`gYSdDR6BRP{HCjl&i(t@;=C< z-ZiIlD?LljoA7ypmb_0th#P`jT-w5k4YK*VtvwjDo2o4RubTI^@|n!Y*bPPdwAS8e zcs!MmU$c_3+N1n~(t>>M!b)pax$T)kwJ#;>OeWe-X^Yl6)y_F;I4U_)dKz_^dGDI_ zWz6hI8Y`uI*>1_Jz12kD+Ky^1`G};j*jlJ>vk%T{jIOjip&Y45>RQDhsddz&<-l}& zK>OH|+0}AAk~HP|X;ZgcPfcjsMa`=^tFEx(FGr@SrZt(0ta_@Un9UZSS`Sd>o0u)x zMxgBqcUF5&O8*mWe!7z6J!@8*C*VyMQnf-lwc4-8oAF4pZLmdz_;2S1U014K9vEDu z6>n_ZX*Fx(1BNS1|aShBWOEk3C_Om)g+gLJZB$p)&m11sXTWGjQ=25s4m?Q6!-&>600ht;hk zCF`?J+J1F|B1s)i2TL@Bhi#n$yPb7l?M*1+yNO}eSx+P^`SH-(tMisv7{cmP6eh>| zjNuf8`L!XVqit5~?$NZiUmOmq4ZguggS(?TqG>Ld7`Cc;8jY~+gOBwGy#qfa*}USW zS(znQ(K>Xkcp(ur#og1cIcv?Z<;2{}v|QY;w3uyjLnNJvqG`~w<@RL6DE1G;X!dM*}S%Wp59m~5Yb2O;Q0}Be!XEbVZBkUSfn?-KbY>0XK zE7e3IPveTmR!C6l^Nj1UxHwQ)vWAg96bU!n-M&?8sJ4UViYsN64KN0Cj`6r=aHZ4+ zOHNbX&|3S}bR@&pIP&siKRnYbjh<(9P4J%V_rpR3+Q5YkEOptVW9REo&GW1c20wREvd_lmOJYR8gqM!dsfDeNm0 zw1)A}>EubB-9?bbFdpudK}+o(1^og0>0QU#M!#B$M+z4aw;D3<;vY$EnJ$~ zHCkOFrr|?yp*^7gNNPeG0Jfwpu(}bW1@2lfP^~woelE5-w$T<_v+k&trS)JST#Xow zbxS_4t2Pb6ysNGWlxa-fY#`oZwB1AZ2eXX>8q6Nl^|Cfvl?`ikXEofJq^yNTnP=~L zS6Nb;clCg*Bv0c@jo^yEXAPzYRpTm6(Eag-+sy`#c`Dcj&AC3Nl z0Sz+;R65br*&|^}N?yO!+is*o{YlVEH+@*O=3Qk$IPWUklAL#yMd-Y%xF0n4G7G`E zmswhxdwH?ln#G1|6f9?bYhKw}%u(j}8~1VMetL1mv@A&GetL0h;vUc3PcN>wcCpux zQ|2kh{h7I!7h8_IGjl(^*mB&vnfGbjdYN|_cW&lg#*LY|mlroEZp+O5G)uK}FE93* zVR6~o{llr8vqFWQ+tbS#2ccRvNITLiy(CS}511DpFz8lBt-ODAC9NNIriI8_-d;7? zS$dmi>*C1O?;kU|)-{^(Omqfc!j&>vvTNq>if%$PB=!Uc4F`BSB5KzNHEwHpXf1Ib9u&hJ%Po+VQ2QCp6=LAyK6*tXiuVF+?2tc6buv3(N`cEs6RLT&RG+fAmuU2-DC8y`CGy41syCgY5Ee$#vDn`R zbw-c5-Mp$8O!APjsJ2E)%jT-IEpLb&I1AJ}f_;51kf`^^mDRkytuF*DIqAt6d3HAM zD)ZpHs~9-uUS_VDdzpEE?q!9tS)Q5uX*M#~q{$pZn>>KF4kCd7suVu9$wYa>L>lGc0Z~1MB7UOv4TJxtAB4 zhTGZmK8?G%b1yHB7SrOg&1~42r`)`_-sZ(+TNZy>qh=Gwd4+4#i;dH$7q_WKz1TdB zdT}&s)QcldqfxLA&pFMlA6A`nuPfvU4W@B(Kd;c&HF%C^{^u3^i@DnT&nx&(ui$^o ziRS88=+hd7POZUnEc5j*?mHSh$1(Twc#dNJb%p*xU(G9x=yN}BR`8!?aZ=ML^-s&< z{-agszgmUiU#k%RTCDx%)nALn-`wj;gSbNf($ej$MgG?+#J^TyK-1zmt-1E=75r~t z%h$P|H!RMtT7~|l#dBcu^(*)X&wJ+A>Iy~n%w|;m|aQ^kh^8=m2_@^@~eBQjc z|LdrK1gp(Vs3bomn6X>!9;eQ-1=LfdKS5GY!`Bv2yA@n)=;CRhLDixcbLh#r72Vnj z-N5M4?Z=B=<6&x0@uk*U_D&>Q{%=%hG<1tC zC|hFcjDosmz0fSvO;c^zVW-<%(fF8a*}QQh?=-De41+gxhDN1ykYmL>3$tO zFq6sD1~sE;)mky=%gJynYfafSbxUs3o_?F&Aj&i~p_#am zF|?>add_`|j|BSkuxrgf&`~(&%c%kF!X))cdd$JlEc3fvi?m{kbY8E;9_ZZ5i$h&u z%AznMp$P|X&zP-~wj2D~R=J(1PSurGsqIZ|Hq)@xr^mG9`>=s_qwJhUsyf$IT4;1F`Eo-2Uxk^%JO_`f&+{0bHlKTW@gRz4 z$>)B0@erf10#TR%DdcyP{4$rV-Rrf-|6g&fFfUR_`wFWXg-MaZoJe6xWLccb6&6$q z>m?eQ7WG>V4N^#A)5b93HwH&0pSRnJw952krG7+D#Ia3V1ucswO&Ya=6*NvPv{GSG zrcqe5Y4GyYynxr>p4|NF3ic^1`ZNlAvl`rZn_s?#4So5rHB1jZ(n2RH%q%qu+prqk=bCGzLXy|u4W#*>UpxwE6jrtxg_WyDVJ}ysuyWNX%zQNp z8C|20(lrWOvKob)ufZEebN#C@^VTS=j5W0KrFShdnYDVG9*!`!t=>{8YEEc1O{*^7 z{O=M4y`{4-Mio}C8im!XMj_2>%nFH0VRKnSs{`2wdS||zP3NXDXMdz0nXNj1GvwNw zf-bD0W%1~$RoH;msux#5tFVC9Dr`_|6*j1~3b|ZMxx7@R_krlS-eP}B&pwsa*~rSI zS4i3{dAG?N+nn<+a+6jeWoz-I!@OwM;(gS)*A@1uwF)zDE#5bsuV0~=6tb2oT$5@TD(F}s#V&xl+U%&w%PrT&2dKV z1NO0h5Hk&G{!zV8kGwbO4UnKw-QE9=6 zc^K)8P5RBKW^QhG3a*gb)b4Z#p`6t;Y^g2T6}#Z&{=m?#^6j4iowaYF5@ z+bmM{v$Yl7nB*ws#%wEv9zC28@daud_RRt}{oKs1_G9j0(3dQ@eWjwF9(k`6r~jRs z6_x~Ag&Trela3`ub9~@cH)@fAwK3^W=|R@2$(q$Y(bifo;IOuvBifuWYKqQeVxy*} zr(yq_*``+E7KK(}5YQ^zVALvX0cjN`>{^8xyH?>Ah*n`ruT>gB6z2RogTupgts$KH9n$A$XS=DTIN?vPi!>|&W zwxg+(ezHMNum_?;dS&3ht2K>o+{JTB`!B1lu=3C;tUPoIx1)3lD-)fTi|MM2zPg`B;RIS@Cgle?q+Dhj_HLKaSvYBTWt699) zr=uOU#h+KW;h}ItQm3%-rc+q5>1atdyZKKOB~m&yg{u1Qz*}|1niG4}l4Vbi&TVnp z!DBP8N-gTFyWB>*J?EUX>E)QU@oGD^8MfTz4x1(%(L~*$gm2BJ9fxCUp@iwb%Qgzz zeL98tfzGmcqeG`Kf6yt+A9OT75MH%itqv*_Z1kqC^p`!GuM`&sg&I$X&hxgJUi?v5 z-x#HLe-`g->I@o^S-iETGg?SSIzP@8wFaCSXOLbSQT6F;hN6=W-k@i8YkHF}SF8?o zqY}Lg)yoYdx(&ClOfJaNd1%=U51n6?GIaZvoYqO{G1f2YOU<-ZRqV9$l{mcwD7{M6 zF4%jkYyEu4T?{5G+I(l2uG8yb^qK^{3Y^I{lMUJqt##9CjnGA@eXW@(%qTCs|m~=;(!FcKjWG zlfz4Av^BcJ zSinrBVkR@<_E`+1 z$&7sgohjY+8&?P6P=a24GbYL!vsJ~;p`&+vijlS8Bv&wX%+vem}0SCkHZp%?GTVN*-CJWWNbuAx8LubK0c zoGGBC_eSM+V#%$oLbg|+GhgT>tyrg+ua>IPRz)&t_j&atpV6HPPa^c*cBkfzNv~Q< zk+#_w(WW~dYib&1ZMrllmUI;<;mfxr>Ag*yt)dYM#A&9}BHGEx9PY7nwI#v$7H*k0BX)Tp_Kqm=D9eQsf5u!s26Ln`{u+kr`Ib~IH zFNp_&vFS+PHBY0yhR0CUBhAbp8ZavI*=<%?|_zL!Hv2; z8*eA=vA9#y?v$J(3i@KVKtbGV)6ox^LQG?G>5`KgouRQ3Xf`X!6<@3qp(vzRFY^QW z1VehJe$7*D)0rWimcQ*Wxu^D;hF(T0(tSxCV#*uJWYVd+Mqk&_SuE*f!43C1*I;7KhEIHR&+`3}UXG4Cyw>{Oibv7LZ0WUK?zdTl&e5#L=?n3qC zPL6XnG8vy~7%^t!zR{{N)Cwid&OkdDj8KrX1BB!=T&?s@@;w$UAfn&y==UiaqtT8H{=wp-|ZzHhG6u6`h_bA0i{4mJsh{rQ<8| zPFp1$)94Cx{*ZUA9Wqoq32R3VK6;6@=%K)t&OfMx#{OKuR9wrZ%g&XaXVqV<2I-7L zsnMk80ovxyBwbi@TD@7*xbA7t3lSmdXur*lSj$#}$&K3TaA>6rsUKx04qcW^-fZDoN#~68l5{s*I&Z1ci2J+s>RQV08zTJboddSe-o@yMv!$RvyCCS!)mAZ>@;0tXi^$g4Z14Lj*C8HL`8?u1n6B3 z>9&eBKd6qRJ}w>e(;S9Ot8TYRrw+$gRy*xPt1X%fcgyFSE{atBmJMg0I8C8w zI9Ok^(7OrKCg}$DUFR;D27JGUa8ThV-s5a zYHToV6z%dkGM0SOTS_>c#&pSO(-mR~_t>2G(@`Z-2Bx?DZBywy9~FJlogJ3R7bDv5 z)2Q9uQLwmXrDG#v-GW5@y^9lf6!jEga!fnvt=Sq`rY#Pfy<{NP3`gjuxM?gEP5GqSq=Jn4cw0&& zlwDYRhv+a)t8@zN{?-lDM$t8Iz*lUg1G=?Z#9gk};$pb+VxR2L)Tjz3K}4 zQqjI6pK{r2X@7u@>q(RUXprv>60M5dISO)rrjt&yX1lqQpvizgvYH&%b%usvRFXOY z4d-;A2_lo`OD#l2rx9wn`Vp&jlus3OEtkPxTHP3{Cd~#r$Aa>pHkD7&2HtesDi+=8 zWHr$=X{p~)9j%1|oxVwRrB{sPcZGYyRxwm6QLdt`lU9#5bpz^LyBp~it==fD-wI9g zIfe_ooytcHav)7e=##Qx{2UeOcp){tb2J&`)4E7#&DXb?nt^;}k|@yw2~xe}vx?-L z?dr9gfh-OF6UyFeuF}A2UFlh)+2+I@q8F+na@@%sd2v5hNwuIkiFKFxS-qNV|;*rFq5rNE2n%}I5!>Ksn(*+#`QZnre4RZ17qc|=}!GSHt+D(+IK zP;>MPd8a$np$u4HzG5$R9WakMa8&b7VlHpdn$-7w$)VpkEanDPZ&_8GNHaegzgD}Q zvR4z#RVry+J{k5@yarh_pYfDkW!EqtX{^x6DS2Zm78~~pJwrr=gW)!lerZ%`k>3ns zXK7<Gaz{un8}z&p}=?)w3%}aekdtDJ zT6gPt%FO&@!xr!Rw1Mz2n9loB#)PqHDy&GUYJYzVwxuAKeJag;*`$Nw-CxX(iqv-~ zCgnrQqBwp!Ug;IH1%EqFCo;%qLa_x7OMm3^P)R#Syzj`Cn2ss#1tZv(c?5UMhBkgE4GR(Ybc^ zV1;sIE9!4`SAF#{#g%-h65dH16*TlznXzuO76x5?+*(K{YKh6_%$W7kMsr;D^b3`E zzZaof39j1EJeCJbO0ASC=^Uy|rY{{-QSrC(u417)-WVCC;lOdp z8n3ov$(5L=jN_*HSM2A$4YgIj@Go#YsM4_mOX;=Ll zu|kX{X$LGd^oCM+;HsqbuIwn9O^qFuXo;phY{@o=wMy}|k;y$-YdfYcN7IrUZFI}3 zO0`^37|AHr(SUy7Nr&p{#Aa*wY=%gX)@GAlb7K%~+Q+Jfbi=Hl476h-b8WJgUYXF4 z=E~O!dg_OCzFCaMFP^?=VjZT*yes8x72BRhZDJ0sjk+_LB=57@z0tvN%@m9UyndSU z>XKF(?}mA#NeWJykyI%n+zx-RJ56ki=>)D^Z{%v^UC*5Yk8 zsAV##*h+e(Tuc}e32ioOb_Yj&-Rctt)B{Eod3`I7r39q2 z6u1K$Dc#Z0bFrREiRR&S2X{5P5*+)6K3W9z2XxYWu-c^G2ln=M&A;l&c6@$Kt>c=k zBx_AyIZ>v`1D&APAB6g{qiO!T^$M5z-ps~DsS+|4X}cik&K6QbdhR%Ept+)fwl1iP zdT2r_tDCEhR(+JY4ouMU0(t*B+Z!JBd(&>cPoY1VWXn2lq^Fg(eFoHbWjBR%u4r%7 z=Svi-=3zAMo>apHnjXND(fwODSxrCbiAS?=-qxlaN7ErX|njg3{J5&|-J)z|7~Cv;{|d9hJH@>yL(d1+_;?sL{~s zKts(Z*Vih4p#jY(JMI;?!QPH+IF0&#-9_Vg*ln`1QCC{5SX%`?CQ+j#jB(S->cHXe ztyTuj%37>VGdZK=4{6<(qWc2*NX4-ljg?b%Psz8M@46cO2raHD2yN{)9q35i9}{%; zx73@d?n&u{Hhn#>&rde`c2hQ`@rHbZkUP6U8IXndoQdabJoG~LH99*f-*H=W!+Ld9 zH*vOX)>#?p34+$N8uA6p3A1LyS#p)5x)B9`C0`F#8;)wfBSjChs!uy}2D4gkG;O3> zI<3`7XWP-njo$CKvOOz*ReA(o>uWpGYb!RrzeyVlVUOS4q?vzte~+_j$K6^rT6K2D z*;QN7<}`bQRe89Q4>e2~>A-`Ot5zPbsA;FezoF0N)ohTU?j~kD-3cHx22qs{`^P z4e4Wf#T1~Ei|G_wc`q_bPeJzzzDb{E%${B(U+~1}xqO=U#M^#pPs-ZQSF7?W=Ls8g zZR?sXZAyimXtuy|AdPzzd-8e9ol>=5AJpmK#9nJ9ykW@ez5YS8ERX6^ z%p*f5;?qgMtf!+_y}q$6Y|^J)^feb~cB(>_TwbB6iFz2D>Y|-+qDuDxY`PVivr9RO zue#~<|o?pKW^-7rzsm&?^?jAl2oSEWuMtr%(hS6g?Kx`kL?Q%sfAY5Qu(U8Ua2 z_8G8nrW1_m%QNZ`bGK%m7!AF`P?|qej+J&90`0<(zNLdN7i9NP7*jasdo(_`veM$) zy`5m!+i~h0(_+6w$69XKYaL^Qx&uv8 z^7W2%1~*NU@>5T=77nI$&0ZnvX;!^G=i25lPAA{)-`YN)NjLn1{7Sc3t5A>frs>S$ zbihrM7kPSPr&Fg%u|HLhw#I=vO>*LP+Wj)n@us76p9W8C%2nNEb=2$27o($olQwW& z2~Wr=Y%A$DYBXi;~2N-sjw<{%wxscA(ubU)kEP341m zhxLj3)<(Kd5o!BN`9?kGNcVer51j^Qqz4M5xM8s-p9+W(Et2NrTZ8R|NXphFaU|@Bvm{vz<`_Y~1YMffyM!`+>1AIuwrw#@*fKm5ejnX-y zqfj+l^cFV;MyqpUt&6Rw{kx))QEW*YqmJ7sIvaF6-po>>FRkLFInWb!GX1G=N;@jJ z%;99Oq>09SPC5pa2DV|3{`1I(+u5u3YMS;A>9F-|qvz60lDddPlci~>lm*x+(#cRl zN6$d#2A)95R<$Q>hCyIWLs3pUIK{3M({en?UAUAmrW-5P0o@Jn71etBejb0p-KP}? z9n5~f?qA**^m|h)5rf0)8$`O%6^}V)5~rdqAMH!ip`z7%sWtGro5{3s)wzF$$?wP< z;9Tk_a(APf6XwRMmWF6;%aHbDCmu`ATGG>JtF36ZC8b!Kx2tRD+O|>8R!qfKU2#Ko zjrKJ8Tr)&R)k~Wj-OAML&aP#{bX&{c?HQA1J9*0`P1dL|>wwZ}Zb zDQeEs;c5Pjc+5;s{~5?lbY?l7T*t=xrsOm^2U8=ugNcmOgBxxhN0iM=WCP{#z$=A0 z+k2uTbDG^&(&l#zQk8Udqe~C5jXZP?qI5ey|vg>)8goFCmShb8e#QgeH`mM_2K6=m=etw$V*= zbB#f(KXujUPTQ6nne*0sG_#RMavObfnRJhj7PEuoY9gPU`aHBIvW4{yb=Z=pd8~YE zoPuKPR<+*zSX|9GQQwr1C;&(^$gjaNEf{E0i&i*}@> ziMzZ@gl)4Y%(i+lqa|NoacH~AVBcrfYr5XPKSEQIxR>rF(Mh2tdeXG6Pq`z;R?$h{ zfaVYT#u;fn({AN8blWa%HJQ_E(px4pL&~StNSsFWqQg!nSDGkG(3h{}Gx`2d{t`Dn zjUNpA-ay!&$%JB^GHru|I=xl1wDySozt*lD)_o?chvzOJV4(pCicexCX!b8V@#{(y zn|GY|!*SwBkj=x1llT=sk~kFwLQ8|Tph6T|p|6AnZAn3~1qBV#ifS9gRumvnA(r3x zac^!uC)a<8NcWBt`^=1I&YU^#q0G7r{o8g9N4&5Pk1{mRb6c_ick4Pa>LEusW=>nP zj8Pp+^_A?;+GS1IdPr~|vW2R7`u4Z$ZLw4){szd5mF*4U=N9nd2@J~zp`5eqMb*5e z&U$@u?KR|0rxO&wlw=waY&MymD}2sKu`!Pco(Uaf*)hLmuG+pKzbwllryA0>vU`=F zvJ8D88u~|B^XECsd^46L8SLltC6d#h2fEanY3;LGsT8<9@~3Tc8{dR_;{bPm^==Me zi+}Y2Al6v9uU4A6B7xoxiuTOjG=%eh3oKF{$F%0CB~((ruO+0QF~?8q&Z?|1CB6Y6 zZ_%p_uA3FpKVuneOLcOlpP?R1yD@RR^Rd&cqY*52a9N2xamrCp&%1$<=XuDC>IR*zbzLsOXth;+D9G0ti_EYgdM;ghy;Y@4L)`c468w)YheHFY$#QcM?o@B5AWEGw zIRjB5+2RTDw0!UVTSRz~M|&gd%#Veui34gb7t_5?0;VdXk0jS~#7p6TwlE?3L>5PV z-!06JWqITyKK%NB6I{E74u~Er)JNd z!}emWz-j>LJb^w}_g3YISPP#T_?599?oS_&fDpA|7K+SvKXhudlHWBYx@RhL+1)b<68)eB7hs%w*1CIOPRST1RFho5dn>)ucjqpfJ zL)S2YOHS!*L8`aT3RVfwdJw<(ScP?;=!YZeEtJ!t*AoN9F&ebuKnT|_O7*PFAX$XH ze-OSO4}7tHG-!2vz%iMZtEuQbUvg%oOW-_@3sa-ctzE6=4@*1Ec1m4lK(-8H5iHe^ zR}I^zS`M~lea{?lDwAAgDXb5#0+z~xy~8Cc>N?nmu~RmX(_5-@vy;EHwcH)}Dh?b;CbG}Rk3FUWSZq(; zKV*=5rYhpZPmfsju^U+MrYV+=<2Br5pa@y{aLui?u_=B;aFAO)Q>P2hdX#aWz1hKT zC@}jHlaTyup<2`Y9+}G>=e#>C*&;Q7WhG@Mc$R0mkZiv!^5vI>ou~T~ryta>GrvDck%MOf89fSjduB^46_BO)AG^J{9QJ^6;yz)O!=1F+#9E{gIym3|#x;1X=Un{=j znk^Pv@?2d*2^F>U=tz)+*LuqeNcoE&%j3(?%wd$uc z&i#s7J~?c~lIXqImg?)FuAJzeV&fgtM)w7g;31wHhdtc$#^Yj;<9 zt)X~4_Kg(`J!zfhUnq(v<2UW^3L_nRP?y`nt!X&icHtrp4}^~^o+GwAt!|Es2c#qy z*KK#C9j3fHI7w~4U>;zN%v3c|tvWC@zLA-bLw!|qfvZ~{S*<-(dcjUwDFLK9aOD-^ z#ZN>rCmNIrHNF;^t6T9|Z)-OPcxa_h``gdpC1a)_@Pb{rd2BIoodV{H&=L$~y9l-> zw%uglBIDgP{h%Zw)O+19AaX0!t3s%OA~;WRb`sqf0AJ;$~g zoY`mS%3uI~Fl2D%EA22R63yGVrBBiehg})+@tmGfd8pKVZMqx`h4Rs#nau(Y<4Bv? z7nWs0px}C(wvLoD=B`Um<8~ut{B5UW8iP2(koYJU$S^h|FKZeEhiPTZffp|pLf57_ zc$Y2q$vKoTaB0gK2;X~q12Xd==?Sc^UaDWHO5PjpuHsr7_|-0!W%e0(wpV0YO*jbU z32|qh+~c0ydo=)NKq4j@iwB1@#GC@UKFzrQua{MyQWCyg~EFwWaUGFQA|tk@n$#vRof%b#qd99BZ;44ZYJvNQ@kz z(*D6_H@{(=9ycFLp3aahT^+i@9-ND1(cM)yPzhU`GGziK#4NYnbDfPw+l~CO4>lHV z6VhPD!AUF?Do@59Z`8V!Il3J*nVLPYx5FZwx5m@-)y?s2#HM%6WogtLjnA6v!H%_C zI(-V~RfWjGk2jJd_FXvR*DL*V1DeBg6Q}&d$oS|iv3br=4d`Uw69OXe>WCbGJ9_Bb z+xDP%hhDj?a$;X=7RI%1yNlH7Vap?soHA70=0cg7^~q{4t>NJYwEU3MLo&Ru2C1QJ z{UU_#(RR09U1x>hTopSIbv~|v3h5HeoSrW&$@W;> zpGSvyMMUt!#*kQz@Nm#I>n{u1*TMS_o0DA!7hO~AoRSs$;M6XlTe{jJtTp|BJq(qx zCI;n98-G3<>w_EynOLMeO*HPvjJ6^stV~J(Oh^_Egi~V9Ug$&Oml5%w z&1H}FcFeeaan8`uG1qQ?iIo|v2Z7%>!P9^V^ga5Ms*St7F^g&g`21Cl7*43!h9pLt zU3=#AO~lz*PzS8(j?trrt7{DlnK;(&@B5WPWC-6GsgMfh?5Z-y7PmFpQiGWthm;5< zD?CtN_1@00tt;#jtHrCF^S!BZY*tO!U&wa<5vIpfGyUK`^mk6g48k+P(w3z@mhhBc z8Tqs~WD|M7E>=`Z4H#WfF7C|fTq^YobY!nEk4ZiTk3Yo z^GIz@k*yx`l&~xx+oe2&jQ(MGY>O{2N0E4g*IB)3odL4v`H)304#;jN2HLi^P|wbJ zRpvCrhot}s)JrTGcEloFtIN*bZ*Brfhm+zsFAkoE72+ZN&`d?;wh{s;z$qMTsP5dBr{*16XV~E6 z9z-}wgzcxFc=}myd_x0n(3#D%6i-&%_}sXPCX%5PkF|2MqguOSH4k1CqOzlIU@U7p zJ$`x|`C?s#J<|1Nb%ioOeqdNJt@j8XcDYKmsdHVyQEB~(K+A2{>-O>q*8`1$QWI;w zSHZcImX8BcXa1!4K(EarO)W#@BD!Sl*V^QAG)~N=v{=@?w&=hG(ma(d1Mv&QeYo8Y zYM?#t+NWpJPUTcog$g`evh2QTRDx%?m?V{}k|5v^TyNjy_W{)(?!bUR_$S{7q|;e z+z(<*x=8s=VPiu+;i1=mSx!!tR39`5XYpn(CEg5aO$g98MNRCW$)Mr5zGT+p4c}`r z_S>fK;&_JJEb#SR<^$$3qt@ zwr`1Bx)~LQx)5{g)ze5GUDo}{WZS8C7y*)q@&Gp(Cf-E!qhKAqGNNHi{z*9)r@kUN z@E3z3$!XLC&I*(XHR>&?Sx;Q$14IR9>3ggRE?0z#eM0oMQ5>ndyy%WB?wYJ6c>&L= z7PYh$<0uX&qqS;m2Iy}1F4JnTa>}lONE^7{Oo~c%wJs$$9~>f^Ny14(4_?60A~;V8 z#4Ip-6Xr4=6p)lw6E~G<%`5;t!amgm#2o85ow<(i=v@nbXPa_GCPHdtID$_owyH2X zwK3etokn4=sHNtW8*oS##`V2eYkNDR57@CMnjol`Hf|dVYTphGqcF#qY+jt5jtb-I zK?xBL=X!S-n_AP)LQI5Hg2+#N5rlYud!j}UJxrpo(i`e5u<>#`E?30W#F>GbA~5#aMXb}zup+xMS38atz~0xiU;UUqFSE3e`0<5 zU?h`wdQ#I12-(tgV~N9dps?=*B}Mhs!+BC__ID0zwn`FQ=hNsCRx_37FrB;3uBsmp zz05FL(}yXu%2q*^QehG`yk>G9b?C3BB)ZccvGClq3;V>z@TAWy91G#wdM9lXnKZRQ z2HpXY{z%itcBg!Dryd;Ugtl&R2w;FaX1LDm$y%n(3Q}YFM%%eizS?Tmu=X=eDY8F> zm82h!p3c4tFH~gyLNwL5v7!yB*w;Eean~7F_k2cEM@)p%PeYy~RM^~pMgGmgDbJ0mn2=(r{IeN8SZotAC6agt$vQRBOYI#H)cDnb&IK3PfnX(LOB1+A(z+qk0Kl!ZZXN=IWJo&ceF4MF?RW%mo0r9u*m z%Lv*U3cV%_$=L^xO`_K$FMvoUj`a)tGs;uGwqS~8xw}86OU3*P19qF>&Pq8q8Yh{Tn*6oRiov-imEhd| zif@m*b7Ovf>kiK|v2DCNY45a)j{ujG>e-DEJIG(;-i@^VxaJ!f=J7-EW&~+ft2yn3 zHgwy0gsW|a71`4h)@R*pZwG;56lG-q_x|3fRFYmDe@-pBb=@c%x>9fN#-iPZK7B-C zvckD6J4L5BR;f*=RqUzjAtNlS*QDNoI?=fjx7mysd(2JX>$P$!U~NJtnm9-$bT)Uu zF-*-9)eM}8T4+dXia*;UhmYCxzNcLJhQdy%wdHJ1mtt+%w9yE3V{k5sjF0N=}WBeDbE+3d}mPz3i4YUoh+=*lVkQGm|%yBrvdO5H-$h zN_Az5Z)~~+WOeCE^>W9zki=vKH@lcOvpfcQaQ4RoygX``x)$vBdl?SDuNZPuFLG5x zv_(D^PwQ6E^9O^oTXnjl)3kC)g%PMky?3e=`E|YEi<)ieLkN|}t$}<*AMzBSj-d_X zMipEYPaUn;EuD}K#Lic*Cl6r{ML6Y z|IxITVfY|7VEW^;R4xq;;#D~86}dOf#~g>%4lHfJ_wrCt*3FIHb6uf|b(3X(2F1PX z?o3ecWL}~}Ps1$^=h=lg+aMV=_S%5t1nx6NZNawWU3~%)8oF4&e;q^-cgk_9E(8JC zAzs7Rfj3Kv=;X(4WmvV9K%cdkjh{^%#j#Bxfp~a=Z${P&nf^lu&csRmo%?1c<_#G) z{nvydiH~e#3>h}zZ9^ z_6lr6s~%K6Mi}^a$Om~(AA9Gmp6BhB6i}`MyiJ>EC?YwU@a8=*N+lRZ^mQJpqnXM! zs&*0kiIZ&|$9wWvC{DVwX`>`}CZ%l=8WBcZsaO?RXaUjM5Y6trXJi)Gc!Pq+fHX$f z+slF<>muA46=Ti%3pd$H4m-}K2f?OyXtoD9-RR7AMe31`j7yZ+#dATR534e>Dzy&5 zaRdWoZG>3R*8zRJab~1%>DxO4C&WDA8>TaMxH=BI60bOwR*!+$;Xz^#SH{t4k1Cd$ zw@Oy=*!7yQ5v)BE1md-KH+zPVkN1pO$5jy*q3qjzy4#axJmjjQjR2Ie&XU&Yz%^EJ z+q+Jups3Q)la*~q+*X$b@%#@%{ok+t5Yk838_)K}{b9B1mWncD2Hfom>Lb_gG;mH7hhG%`I`r<9*!J+5#++vB;LcJ*3260=SS{U!n zD`r5$T5sjMOc`+xV?+ej;GVwa&x}-9m`m;is+Xe_Hy84B~B_`~Ud-4l4N>{QYcP*_ZJ} zQvU8;BjnlJ&+p;O*YKCX|6_cSl;6C47}r04_npJ{Tlk;E@Jac_-ShYG72N;tpZ?TJ z+W-2`MF2@D#PGimmtT*|r0C+}SMZm>e>;Xx%1iwH7x4^v_XPg8aZNrl{>UQ<{13>3 z_$1}u-3{2?*W4fD*`MC@e;+rHl+CcVTrTN<(oRwyaQ}aA;C~RqCuKi|zwdwibMA@@ zGNws=U;m}(PE!6j?r_rn{rmrE3}1@CazFXy=prfYxMBkTTll+&{|o#^nuv!jm-`03 zkWX9^{Jj0#&;Os}<}LgeF|K&D% zJ}G}Sc`z>D*OtqDKZZ}nKWE2J#O2@Y-&gR(`>(k#@8G}u*SP(-{A)7kH=q0V{~q_q z5GCz5{xf*AzVk;>dH;O!Jt_YQu)lr-uf_0M zM))5Amh?Yq-;Uw!7=DU-x1am@`#0PqxR=2HFoyqO4F8RIU=sXH`kmDCAAr4W|3_Bz z-and0hAXh{x|P_Ping@6WqIf^t*BU(?5%TCHv6t12vOz uOXx2lS4rP*;eY(^(fe1vfBS3H*V|vna!-T*=69nR|3=c$80hY6?*9NLkB?RW literal 0 HcmV?d00001 diff --git a/lib/pure/options.nim b/lib/pure/options.nim index ad98e626b..0a20d3d73 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -77,7 +77,7 @@ type UnpackDefect* = object of Defect UnpackError* {.deprecated: "See corresponding Defect".} = UnpackDefect -proc option*[T](val: T): Option[T] = +proc option*[T](val: T): Option[T] {.inline.} = ## Can be used to convert a pointer type (`ptr` or `ref` or `proc`) to an option type. ## It converts `nil` to `None`. ## @@ -98,7 +98,7 @@ proc option*[T](val: T): Option[T] = when T isnot SomePointer: result.has = true -proc some*[T](val: T): Option[T] = +proc some*[T](val: T): Option[T] {.inline.} = ## Returns an `Option` that has the value `val`. ## ## See also: @@ -121,7 +121,7 @@ proc some*[T](val: T): Option[T] = result.has = true result.val = val -proc none*(T: typedesc): Option[T] = +proc none*(T: typedesc): Option[T] {.inline.} = ## Returns an `Option` for this type that has no value. ## ## See also: @@ -136,7 +136,7 @@ proc none*(T: typedesc): Option[T] = # the default is the none type discard -proc none*[T]: Option[T] = +proc none*[T]: Option[T] {.inline.} = ## Alias for `none(T) proc <#none,typedesc>`_. none(T) @@ -167,7 +167,7 @@ proc isNone*[T](self: Option[T]): bool {.inline.} = else: not self.has -proc get*[T](self: Option[T]): T = +proc get*[T](self: Option[T]): T {.inline.} = ## Returns contents of an `Option`. If it is `None`, then an exception is ## thrown. ## @@ -185,7 +185,7 @@ proc get*[T](self: Option[T]): T = raise newException(UnpackError, "Can't obtain a value from a `none`") self.val -proc get*[T](self: Option[T], otherwise: T): T = +proc get*[T](self: Option[T], otherwise: T): T {.inline.} = ## Returns the contents of the `Option` or an `otherwise` value if ## the `Option` is `None`. runnableExamples: @@ -200,7 +200,7 @@ proc get*[T](self: Option[T], otherwise: T): T = else: otherwise -proc get*[T](self: var Option[T]): var T = +proc get*[T](self: var Option[T]): var T {.inline.} = ## Returns contents of the `var Option`. If it is `None`, then an exception ## is thrown. runnableExamples: @@ -215,7 +215,7 @@ proc get*[T](self: var Option[T]): var T = raise newException(UnpackError, "Can't obtain a value from a `none`") return self.val -proc map*[T](self: Option[T], callback: proc (input: T)) = +proc map*[T](self: Option[T], callback: proc (input: T)) {.inline.} = ## Applies a `callback` function to the value of the `Option`, if it has one. ## ## See also: @@ -239,7 +239,7 @@ proc map*[T](self: Option[T], callback: proc (input: T)) = if self.isSome: callback(self.val) -proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] = +proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] {.inline.} = ## Applies a `callback` function to the value of the `Option` and returns an ## `Option` containing the new value. ## @@ -266,7 +266,7 @@ proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] = else: none(R) -proc flatten*[A](self: Option[Option[A]]): Option[A] = +proc flatten*[A](self: Option[Option[A]]): Option[A] {.inline.} = ## Remove one level of structure in a nested `Option`. runnableExamples: let a = some(some(42)) @@ -278,7 +278,7 @@ proc flatten*[A](self: Option[Option[A]]): Option[A] = none(A) proc flatMap*[A, B](self: Option[A], - callback: proc (input: A): Option[B]): Option[B] = + callback: proc (input: A): Option[B]): Option[B] {.inline.} = ## Applies a `callback` function to the value of the `Option` and returns an ## `Option` containing the new value. ## @@ -308,7 +308,7 @@ proc flatMap*[A, B](self: Option[A], map(self, callback).flatten() -proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] = +proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] {.inline.} = ## Applies a `callback` to the value of the `Option`. ## ## If the `callback` returns `true`, the option is returned as `Some`. @@ -333,7 +333,7 @@ proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] = else: self -proc `==`*(a, b: Option): bool = +proc `==`*(a, b: Option): bool {.inline.} = ## Returns `true` if both `Option`s are `None`, ## or if they are both `Some` and have equal values. runnableExamples: @@ -363,7 +363,7 @@ proc `$`*[T](self: Option[T]): string = else: result = "None[" & name(T) & "]" -proc unsafeGet*[T](self: Option[T]): T = +proc unsafeGet*[T](self: Option[T]): T {.inline.}= ## Returns the value of a `some`. Behavior is undefined for `none`. ## ## **Note:** Use it only when you are **absolutely sure** the value is present @@ -513,4 +513,3 @@ when isMainModule: test "Ref type with overloaded `==`": let p = some(RefPerson.new()) check p.isSome - From 063229a301837484699fb2b8cdd02c16f9c37781 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 21 May 2020 22:18:58 +0200 Subject: [PATCH 0570/4254] fixes a bug reported in https://forum.nim-lang.org/t/6361 (#14422) --- lib/js/dom.nim | 62 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 4a33668cd..950a5065b 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -19,29 +19,29 @@ const type EventTarget* = ref EventTargetObj EventTargetObj {.importc.} = object of RootObj - onabort*: proc (event: Event) {.nimcall.} - onblur*: proc (event: Event) {.nimcall.} - onchange*: proc (event: Event) {.nimcall.} - onclick*: proc (event: Event) {.nimcall.} - ondblclick*: proc (event: Event) {.nimcall.} - onerror*: proc (event: Event) {.nimcall.} - onfocus*: proc (event: Event) {.nimcall.} - onkeydown*: proc (event: Event) {.nimcall.} - onkeypress*: proc (event: Event) {.nimcall.} - onkeyup*: proc (event: Event) {.nimcall.} - onload*: proc (event: Event) {.nimcall.} - onmousedown*: proc (event: Event) {.nimcall.} - onmousemove*: proc (event: Event) {.nimcall.} - onmouseout*: proc (event: Event) {.nimcall.} - onmouseover*: proc (event: Event) {.nimcall.} - onmouseup*: proc (event: Event) {.nimcall.} - onreset*: proc (event: Event) {.nimcall.} - onselect*: proc (event: Event) {.nimcall.} - onsubmit*: proc (event: Event) {.nimcall.} - onunload*: proc (event: Event) {.nimcall.} - onloadstart*: proc (event: Event) {.nimcall.} - onprogress*: proc (event: Event) {.nimcall.} - onloadend*: proc (event: Event) {.nimcall.} + onabort*: proc (event: Event) {.closure.} + onblur*: proc (event: Event) {.closure.} + onchange*: proc (event: Event) {.closure.} + onclick*: proc (event: Event) {.closure.} + ondblclick*: proc (event: Event) {.closure.} + onerror*: proc (event: Event) {.closure.} + onfocus*: proc (event: Event) {.closure.} + onkeydown*: proc (event: Event) {.closure.} + onkeypress*: proc (event: Event) {.closure.} + onkeyup*: proc (event: Event) {.closure.} + onload*: proc (event: Event) {.closure.} + onmousedown*: proc (event: Event) {.closure.} + onmousemove*: proc (event: Event) {.closure.} + onmouseout*: proc (event: Event) {.closure.} + onmouseover*: proc (event: Event) {.closure.} + onmouseup*: proc (event: Event) {.closure.} + onreset*: proc (event: Event) {.closure.} + onselect*: proc (event: Event) {.closure.} + onsubmit*: proc (event: Event) {.closure.} + onunload*: proc (event: Event) {.closure.} + onloadstart*: proc (event: Event) {.closure.} + onprogress*: proc (event: Event) {.closure.} + onloadend*: proc (event: Event) {.closure.} DomEvent* {.pure.} = enum ## see `docs`_ @@ -991,7 +991,7 @@ type passive*: bool since (1, 3): - type + type DomParser* = ref object ## DOM Parser object (defined on browser only, may not be on NodeJS). ## * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser @@ -1001,17 +1001,17 @@ since (1, 3): ## discard prsr.parseFromString("Hello World".cstring, "text/html".cstring) DomException* = ref DOMExceptionObj - ## The DOMException interface represents an abnormal event (called an exception) - ## which occurs as a result of calling a method or accessing a property of a web API. - ## Each exception has a name, which is a short "CamelCase" style string identifying + ## The DOMException interface represents an abnormal event (called an exception) + ## which occurs as a result of calling a method or accessing a property of a web API. + ## Each exception has a name, which is a short "CamelCase" style string identifying ## the error or abnormal condition. ## https://developer.mozilla.org/en-US/docs/Web/API/DOMException - DOMExceptionObj {.importc.} = object + DOMExceptionObj {.importc.} = object FileReader* = ref FileReaderObj - ## The FileReader object lets web applications asynchronously read the contents of files - ## (or raw data buffers) stored on the user's computer, using File or Blob objects to specify + ## The FileReader object lets web applications asynchronously read the contents of files + ## (or raw data buffers) stored on the user's computer, using File or Blob objects to specify ## the file or data to read. ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader @@ -1019,7 +1019,7 @@ since (1, 3): FileReaderState* = distinct range[0'u16..2'u16] - const + const fileReaderEmpty* = 0.FileReaderState fileReaderLoading* = 1.FileReaderState fileReaderDone* = 2.FileReaderState From ddee8a362a6590d8e590e6804e31b79bdb9ab7e6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 21 May 2020 22:36:34 +0200 Subject: [PATCH 0571/4254] change the [Processing] messages into dots (#14418) * change the [Processing] messages into dots * better implementation * maybe I should work on something else... --- compiler/lineinfos.nim | 2 +- compiler/msgs.nim | 40 +++++++++++++++++++++++++++++----- compiler/options.nim | 1 + compiler/sigmatch.nim | 2 +- tests/pragmas/twarning_off.nim | 3 +-- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 2fd5a5a60..331268d6a 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -112,7 +112,7 @@ const warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` - hintSuccessX: "$loc LOC; $sec sec; $mem; $build build; proj: $project; out: $output", + hintSuccessX: "${loc} lines; ${sec}s; $mem; $build build; proj: $project; out: $output", hintCC: "CC: $1", hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", diff --git a/compiler/msgs.nim b/compiler/msgs.nim index a43977606..7523d2d8b 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -277,6 +277,11 @@ type msgSkipHook ## skip message hook even if it is present MsgFlags* = set[MsgFlag] +template flushDot(stdorr) = + if conf.lastMsgWasDot: + write(stdorr, "\n") + conf.lastMsgWasDot = false + proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## Writes given message string to stderr by default. ## If ``--stdout`` option is given, writes to stdout instead. If message hook @@ -286,15 +291,16 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## This is used for 'nim dump' etc. where we don't have nimsuggest ## support. #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - if not isNil(conf.writelnHook) and msgSkipHook notin flags: conf.writelnHook(s) elif optStdout in conf.globalOptions or msgStdout in flags: if eStdOut in conf.m.errorOutputs: + flushDot(stdout) writeLine(stdout, s) flushFile(stdout) else: if eStdErr in conf.m.errorOutputs: + flushDot(stderr) writeLine(stderr, s) # On Windows stderr is fully-buffered when piped, regardless of C std. when defined(windows): @@ -330,15 +336,27 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped = template callWritelnHook(args: varargs[string, `$`]) = conf.writelnHook concat(args) +proc msgWrite(conf: ConfigRef; s: string) = + if conf.m.errorOutputs != {}: + let stdOrr = + if optStdout in conf.globalOptions: + stdout + else: + stderr + write(stdOrr, s) + flushFile(stdOrr) + template styledMsgWriteln*(args: varargs[typed]) = if not isNil(conf.writelnHook): callIgnoringStyle(callWritelnHook, nil, args) elif optStdout in conf.globalOptions: if eStdOut in conf.m.errorOutputs: + flushDot(stdout) callIgnoringStyle(writeLine, stdout, args) flushFile(stdout) else: if eStdErr in conf.m.errorOutputs: + flushDot(stderr) if optUseColors in conf.globalOptions: callStyledWriteLineStderr(args) else: @@ -450,11 +468,18 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = s & (if kind.len > 0: KindFormat % kind else: ""), sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): - if kind.len > 0: - styledMsgWriteln(color, title, resetStyle, s, - KindColor, `%`(KindFormat, kind)) + if msg == hintProcessing: + msgWrite(conf, ".") + conf.lastMsgWasDot = true else: - styledMsgWriteln(color, title, resetStyle, s) + if conf.lastMsgWasDot: + msgWrite(conf, "\n") + conf.lastMsgWasDot = false + if kind.len > 0: + styledMsgWriteln(color, title, resetStyle, s, + KindColor, `%`(KindFormat, kind)) + else: + styledMsgWriteln(color, title, resetStyle, s) handleError(conf, msg, doAbort, s) proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = @@ -539,7 +564,10 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, if conf.hasHint(hintSource): conf.writeSurroundingSrc(info) if conf.hasHint(hintMsgOrigin): - styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, KindFormat % HintsToStr[ord(hintMsgOrigin) - ord(hintMin)], resetStyle) + styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, + " compiler msg initiated here", KindColor, + KindFormat % HintsToStr[ord(hintMsgOrigin) - ord(hintMin)], + resetStyle) handleError(conf, msg, eh, s) diff --git a/compiler/options.nim b/compiler/options.nim index 194d635b1..1418fff63 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -279,6 +279,7 @@ type projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/ projectFull*: AbsoluteFile # projectPath/projectName projectIsStdin*: bool # whether we're compiling from stdin + lastMsgWasDot*: bool # the last compiler message was a single '.' projectMainIdx*: FileIndex # the canonical path id of the main module command*: string # the main command (e.g. cc, check, scan, etc) commandArgs*: seq[string] # any arguments after the main command diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 077b4b269..401d160fa 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -742,7 +742,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = addDecl(c, param) var - oldWriteHook: type(m.c.config.writelnHook) + oldWriteHook: typeof(m.c.config.writelnHook) diagnostics: seq[string] errorPrefix: string flags: TExprFlags = {} diff --git a/tests/pragmas/twarning_off.nim b/tests/pragmas/twarning_off.nim index f1de9076f..d5d31d4c2 100644 --- a/tests/pragmas/twarning_off.nim +++ b/tests/pragmas/twarning_off.nim @@ -1,8 +1,7 @@ discard """ nimout: ''' compile start -Hint: warn_module [Processing] -Hint: hashes [Processing] +.. warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] compile end ''' From 3eaa870c0a3ac0a97c1726278412141140d35b9b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 21 May 2020 22:38:13 +0200 Subject: [PATCH 0572/4254] ARC/ORC: optimize s.setLen(0) to match the old runtime's behaviour (#14423) --- lib/system/strs_v2.nim | 3 +-- tests/destructor/tgcdestructors.nim | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 3beb14382..aa644522f 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -107,8 +107,7 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} = proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} = if newLen == 0: - frees(s) - s.p = nil + discard "do not free the buffer here, pattern 's.setLen 0' is common for avoiding allocations" else: if newLen > s.len or isLiteral(s): prepareAdd(s, newLen - s.len) diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index e089aedd1..61d296d2e 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -10,7 +10,7 @@ a: @[4, 2, 3] 0 30 true -(allocCount: 40, deallocCount: 40)''' +(allocCount: 36, deallocCount: 36)''' """ include system / ansi_c From 149251cab96741dfd2dd6edd4715589ba92b8480 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 21 May 2020 23:28:47 -0700 Subject: [PATCH 0573/4254] [cleanup] fix UnusedImport sempass2 compiler/semparallel.nim (#14426) --- compiler/semparallel.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index e27e85e04..578687e6c 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -22,7 +22,7 @@ # - output slices need special logic (+) import - ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs, + ast, astalgo, idents, lowerings, magicsys, guards, msgs, renderer, types, modulegraphs, options, spawn, lineinfos from trees import getMagic, isTrue, getRoot From f7b73e6bfd45ed7c1f09defc8e896137d22e7f17 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 22 May 2020 09:55:10 +0200 Subject: [PATCH 0574/4254] make malloc.nim consistent in style (#14427) --- lib/system/mm/malloc.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 883baaeb4..3dad98e93 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -7,13 +7,13 @@ proc allocImpl(size: Natural): pointer = proc alloc0Impl(size: Natural): pointer = c_calloc(size.csize_t, 1) -proc reallocImpl(p: pointer, newsize: Natural): pointer = +proc reallocImpl(p: pointer, newSize: Natural): pointer = c_realloc(p, newSize.csize_t) -proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer = - result = realloc(p, newsize.csize_t) - if newsize > oldsize: - zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize) +proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = + result = realloc(p, newSize.csize_t) + if newSize > oldSize: + zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize) proc deallocImpl(p: pointer) = c_free(p) @@ -27,11 +27,11 @@ proc allocSharedImpl(size: Natural): pointer = proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size) -proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = - reallocImpl(p, newsize) +proc reallocSharedImpl(p: pointer, newSize: Natural): pointer = + reallocImpl(p, newSize) -proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = - realloc0Impl(p, oldsize, newsize) +proc reallocShared0Impl(p: pointer, oldsize, newSize: Natural): pointer = + realloc0Impl(p, oldSize, newSize) proc deallocSharedImpl(p: pointer) = deallocImpl(p) From 0d0ea3a11ef0bb7d0d2f5dbd84782dee12810c2c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 22 May 2020 03:02:10 -0700 Subject: [PATCH 0575/4254] no more code duplication bw liMessage and rawMessage + several bug fixes (#14415) * no more code duplication bw rawMessage and liMessage; fixes some bugs in rawMessage * all compiler messages work with hint:msgorigin --- compiler/lineinfos.nim | 6 ++ compiler/main.nim | 6 +- compiler/modules.nim | 2 +- compiler/msgs.nim | 222 +++++++++++++++-------------------------- compiler/semdata.nim | 3 +- compiler/syntaxes.nim | 4 +- 6 files changed, 91 insertions(+), 152 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 331268d6a..e1e0a4bc8 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -181,6 +181,12 @@ const hintMin* = hintSuccess hintMax* = high(TMsgKind) +proc msgToStr*(msg: TMsgKind): string = + case msg + of warnMin..warnMax: WarningsToStr[ord(msg) - ord(warnMin)] + of hintMin..hintMax: HintsToStr[ord(msg) - ord(hintMin)] + else: "" # we could at least do $msg - prefix `err` + static: doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1 doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1 diff --git a/compiler/main.nim b/compiler/main.nim index 21c0695f6..88f1890de 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -345,12 +345,10 @@ proc mainCommand*(graph: ModuleGraph) = var hints = newJObject() # consider factoring with `listHints` for a in hintMin..hintMax: - let key = lineinfos.HintsToStr[ord(a) - ord(hintMin)] - hints[key] = %(a in conf.notes) + hints[a.msgToStr] = %(a in conf.notes) var warnings = newJObject() for a in warnMin..warnMax: - let key = lineinfos.WarningsToStr[ord(a) - ord(warnMin)] - warnings[key] = %(a in conf.notes) + warnings[a.msgToStr] = %(a in conf.notes) var dumpdata = %[ (key: "version", val: %VersionAsString), diff --git a/compiler/modules.nim b/compiler/modules.nim index 47d946a01..d6e82d694 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -125,7 +125,7 @@ proc compileSystemModule*(graph: ModuleGraph) = proc wantMainModule*(conf: ConfigRef) = if conf.projectFull.isEmpty: - fatal(conf, newLineInfo(conf, AbsoluteFile"command line", 1, 1), errGenerated, + fatal(conf, newLineInfo(conf, AbsoluteFile(commandLineDesc), 1, 1), errGenerated, "command expects a filename") conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt)) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 7523d2d8b..6bf4d82d2 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -13,6 +13,13 @@ import import std/private/miscdollars type InstantiationInfo = typeof(instantiationInfo()) +template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) + +template flushDot(conf, stdorr) = + ## safe to call multiple times + if conf.lastMsgWasDot: + conf.lastMsgWasDot = false + write(stdorr, "\n") proc toCChar*(c: char; result: var string) = case c @@ -37,7 +44,6 @@ proc makeCString*(s: string): Rope = res.add('\"') result.add(rope(res)) - proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo = result.fullPath = fullPath #shallow(result.fullPath) @@ -111,7 +117,6 @@ proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = proc newLineInfo*(conf: ConfigRef; filename: AbsoluteFile, line, col: int): TLineInfo {.inline.} = result = newLineInfo(fileInfoIdx(conf, filename), line, col) - proc concat(strings: openArray[string]): string = var totalLen = 0 for s in strings: totalLen += s.len @@ -147,6 +152,7 @@ const # but column numbers start with 0, however most editors expect # first column to be 1, so we need to +1 here ColOffset* = 1 + commandLineDesc* = "command line" proc getInfoContextLen*(conf: ConfigRef): int = return conf.m.msgContext.len proc setInfoContextLen*(conf: ConfigRef; L: int) = setLen(conf.m.msgContext, L) @@ -162,9 +168,6 @@ proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo = if i >=% conf.m.msgContext.len: result = unknownLineInfo else: result = conf.m.msgContext[i].info -const - commandLineDesc = "command line" - template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string = if fileIdx.int32 < 0 or conf == nil: (if fileIdx == commandLineIdx: commandLineDesc else: "???") @@ -277,11 +280,6 @@ type msgSkipHook ## skip message hook even if it is present MsgFlags* = set[MsgFlag] -template flushDot(stdorr) = - if conf.lastMsgWasDot: - write(stdorr, "\n") - conf.lastMsgWasDot = false - proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## Writes given message string to stderr by default. ## If ``--stdout`` option is given, writes to stdout instead. If message hook @@ -295,12 +293,12 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = conf.writelnHook(s) elif optStdout in conf.globalOptions or msgStdout in flags: if eStdOut in conf.m.errorOutputs: - flushDot(stdout) + flushDot(conf, stdout) writeLine(stdout, s) flushFile(stdout) else: if eStdErr in conf.m.errorOutputs: - flushDot(stderr) + flushDot(conf, stderr) writeLine(stderr, s) # On Windows stderr is fully-buffered when piped, regardless of C std. when defined(windows): @@ -345,25 +343,25 @@ proc msgWrite(conf: ConfigRef; s: string) = stderr write(stdOrr, s) flushFile(stdOrr) + conf.lastMsgWasDot = true # subsequent writes need `flushDot` template styledMsgWriteln*(args: varargs[typed]) = if not isNil(conf.writelnHook): callIgnoringStyle(callWritelnHook, nil, args) elif optStdout in conf.globalOptions: if eStdOut in conf.m.errorOutputs: - flushDot(stdout) + flushDot(conf, stdout) callIgnoringStyle(writeLine, stdout, args) flushFile(stdout) - else: - if eStdErr in conf.m.errorOutputs: - flushDot(stderr) - if optUseColors in conf.globalOptions: - callStyledWriteLineStderr(args) - else: - callIgnoringStyle(writeLine, stderr, args) - # On Windows stderr is fully-buffered when piped, regardless of C std. - when defined(windows): - flushFile(stderr) + elif eStdErr in conf.m.errorOutputs: + flushDot(conf, stderr) + if optUseColors in conf.globalOptions: + callStyledWriteLineStderr(args) + else: + callIgnoringStyle(writeLine, stderr, args) + # On Windows stderr is fully-buffered when piped, regardless of C std. + when defined(windows): + flushFile(stderr) proc msgKindToString*(kind: TMsgKind): string = # later versions may provide translated error messages @@ -434,57 +432,6 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions -proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = - var - title: string - color: ForegroundColor - kind: string - sev: Severity - case msg - of errMin..errMax: - sev = Severity.Error - writeContext(conf, unknownLineInfo) - title = ErrorTitle - color = ErrorColor - of warnMin..warnMax: - sev = Severity.Warning - if not conf.hasWarn(msg): return - writeContext(conf, unknownLineInfo) - title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle - color = WarningColor - kind = WarningsToStr[ord(msg) - ord(warnMin)] - inc(conf.warnCounter) - of hintMin..hintMax: - sev = Severity.Hint - if not conf.hasHint(msg): return - title = HintTitle - color = HintColor - if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] - inc(conf.hintCounter) - let s = msgKindToString(msg) % args - - if conf.structuredErrorHook != nil: - conf.structuredErrorHook(conf, unknownLineInfo, - s & (if kind.len > 0: KindFormat % kind else: ""), sev) - - if not ignoreMsgBecauseOfIdeTools(conf, msg): - if msg == hintProcessing: - msgWrite(conf, ".") - conf.lastMsgWasDot = true - else: - if conf.lastMsgWasDot: - msgWrite(conf, "\n") - conf.lastMsgWasDot = false - if kind.len > 0: - styledMsgWriteln(color, title, resetStyle, s, - KindColor, `%`(KindFormat, kind)) - else: - styledMsgWriteln(color, title, resetStyle, s) - handleError(conf, msg, doAbort, s) - -proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = - rawMessage(conf, msg, [arg]) - proc addSourceLine(conf: ConfigRef; fileIdx: FileIndex, line: string) = conf.m.fileInfos[fileIdx.int32].lines.add line @@ -517,108 +464,111 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg) proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, - eh: TErrorHandling, info2: InstantiationInfo) {.noinline.} = + eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.noinline.} = var title: string color: ForegroundColor - kind: string ignoreMsg = false sev: Severity + let kind = if msg != hintUserRaw: msg.msgToStr else: "" # xxx not sure why hintUserRaw is special case msg of errMin..errMax: sev = Severity.Error writeContext(conf, info) title = ErrorTitle color = ErrorColor - # we try to filter error messages so that not two error message - # in the same file and line are produced: - #ignoreMsg = lastError == info and eh != doAbort - conf.m.lastError = info + when false: + # we try to filter error messages so that not two error message + # in the same file and line are produced: + # xxx `lastError` is only used in this disabled code; but could be useful to revive + ignoreMsg = conf.m.lastError == info and info != unknownLineInfo and eh != doAbort + if info != unknownLineInfo: conf.m.lastError = info of warnMin..warnMax: sev = Severity.Warning ignoreMsg = not conf.hasWarn(msg) if not ignoreMsg: writeContext(conf, info) title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor - kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint ignoreMsg = not conf.hasHint(msg) title = HintTitle color = HintColor - if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] inc(conf.hintCounter) - let x = conf.toFileLineCol(info) & " " - let s = getMessageStr(msg, arg) + let s = if isRaw: arg else: getMessageStr(msg, arg) if not ignoreMsg: + let loc = if info != unknownLineInfo: conf.toFileLineCol(info) & " " else: "" + var kindmsg = if kind.len > 0: KindFormat % kind else: "" if conf.structuredErrorHook != nil: - conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev) + conf.structuredErrorHook(conf, info, s & kindmsg, sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): - if kind.len > 0: - styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, - KindColor, `%`(KindFormat, kind)) + if msg == hintProcessing: + msgWrite(conf, ".") else: - styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) - if conf.hasHint(hintSource): - conf.writeSurroundingSrc(info) - if conf.hasHint(hintMsgOrigin): - styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, - " compiler msg initiated here", KindColor, - KindFormat % HintsToStr[ord(hintMsgOrigin) - ord(hintMin)], - resetStyle) - + styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg) + if conf.hasHint(hintSource) and info != unknownLineInfo: + conf.writeSurroundingSrc(info) + if conf.hasHint(hintMsgOrigin): + styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, + " compiler msg initiated here", KindColor, + KindFormat % hintMsgOrigin.msgToStr, + resetStyle) handleError(conf, msg, eh, s) +template rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = + let arg = msgKindToString(msg) % args + liMessage(conf, unknownLineInfo, msg, arg, eh = doAbort, instLoc(), isRaw = true) + +template rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = + liMessage(conf, unknownLineInfo, msg, arg, eh = doAbort, instLoc()) + template fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - # this fixes bug #7080 so that it is at least obvious 'fatal' - # was executed. + # this fixes bug #7080 so that it is at least obvious 'fatal' was executed. conf.m.errorOutputs = {eStdOut, eStdErr} - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, msg, arg, doAbort, info2) + liMessage(conf, info, msg, arg, doAbort, instLoc()) template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, msg, arg, doRaise, info2) + liMessage(conf, info, msg, arg, doRaise, instLoc()) template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, errGenerated, arg, doRaise, info2) + liMessage(conf, info, errGenerated, arg, doRaise, instLoc()) template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, msg, arg, doNothing, info2) + liMessage(conf, info, msg, arg, doNothing, instLoc()) template localError*(conf: ConfigRef; info: TLineInfo, arg: string) = - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, errGenerated, arg, doNothing, info2) + liMessage(conf, info, errGenerated, arg, doNothing, instLoc()) template localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) = - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, errGenerated, format % params, doNothing, info2) + liMessage(conf, info, errGenerated, format % params, doNothing, instLoc()) template message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - const info2 = instantiationInfo(-1, fullPaths = true) - liMessage(conf, info, msg, arg, doNothing, info2) + liMessage(conf, info, msg, arg, doNothing, instLoc()) -proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) = +proc internalErrorImpl(conf: ConfigRef; info: TLineInfo, errMsg: string, info2: InstantiationInfo) = if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return - const info2 = instantiationInfo(-1, fullPaths = true) writeContext(conf, info) liMessage(conf, info, errInternal, errMsg, doAbort, info2) -proc internalError*(conf: ConfigRef; errMsg: string) = - if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return - writeContext(conf, unknownLineInfo) - rawMessage(conf, errInternal, errMsg) +template internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) = + internalErrorImpl(conf, info, errMsg, instLoc()) -template assertNotNil*(conf: ConfigRef; e): untyped = - if e == nil: internalError(conf, $instantiationInfo()) - e +template internalError*(conf: ConfigRef; errMsg: string) = + internalErrorImpl(conf, unknownLineInfo, errMsg, instLoc()) template internalAssert*(conf: ConfigRef, e: bool) = - if not e: internalError(conf, $instantiationInfo()) + # xxx merge with globalAssert from PR #14324 + if not e: + const info2 = instLoc() + let arg = info2.toFileLineCol + internalErrorImpl(conf, unknownLineInfo, arg, info2) + +template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) = + let m = "'$2' should be: '$1'" % [beau, got] + let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName + liMessage(conf, info, msg, m, doNothing, instLoc()) proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = if i.fileIndex.int32 < 0: @@ -628,25 +578,9 @@ proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = else: result = conf.m.fileInfos[i.fileIndex.int32].quotedName -proc listWarnings*(conf: ConfigRef) = - msgWriteln(conf, "Warnings:") - for warn in warnMin..warnMax: - msgWriteln(conf, " [$1] $2" % [ - if warn in conf.notes: "x" else: " ", - lineinfos.WarningsToStr[ord(warn) - ord(warnMin)] - ]) +template listMsg(title, r) = + msgWriteln(conf, title) + for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", a.msgToStr]) -proc listHints*(conf: ConfigRef) = - msgWriteln(conf, "Hints:") - for hint in hintMin..hintMax: - msgWriteln(conf, " [$1] $2" % [ - if hint in conf.notes: "x" else: " ", - lineinfos.HintsToStr[ord(hint) - ord(hintMin)] - ]) - -proc lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) = - let m = "'$2' should be: '$1'" % [beau, got] - if optStyleError in conf.globalOptions: - localError(conf, info, m) - else: - message(conf, info, hintName, m) +proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax) +proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 278384fc4..5a2c08de2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -321,7 +321,8 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = newTypeS(tyTypeDesc, c) incl typedesc.flags, tfCheckedForDestructor - typedesc.addSonSkipIntLit(assertNotNil(c.config, typ)) + internalAssert(c.config, typ != nil) + typedesc.addSonSkipIntLit(typ) let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info, c.config.options).linkTo(typedesc) return newSymNode(sym, info) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 29ccf4794..c3f3bc0dc 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -121,9 +121,9 @@ proc applyFilter(p: var TParsers, n: PNode, filename: AbsoluteFile, if f != filtNone: assert p.config != nil if p.config.hasHint(hintCodeBegin): - rawMessage(p.config, hintCodeBegin, []) + rawMessage(p.config, hintCodeBegin, "") msgWriteln(p.config, result.s) - rawMessage(p.config, hintCodeEnd, []) + rawMessage(p.config, hintCodeEnd, "") proc evalPipe(p: var TParsers, n: PNode, filename: AbsoluteFile, start: PLLStream): PLLStream = From 7b3dcfde20e2cebdf5902a01e71c695ff7f507e8 Mon Sep 17 00:00:00 2001 From: Mildred Ki'Lya Date: Fri, 22 May 2020 14:34:20 +0200 Subject: [PATCH 0576/4254] Add missing attributes and methods to JavaScript DOM (#14428) - content attribute to access HTML template element: https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content - ownerDocument to access the owning document from a DOM Node: https://developer.mozilla.org/en-US/docs/Web/API/Node/ownerDocument - outerHTML to get/set the outer HTML representation of a Node: https://developer.mozilla.org/en-US/docs/Web/API/Node/ownerDocument - createComment() to create comment Nodes: https://developer.mozilla.org/en-US/docs/Web/API/Document/createComment - querySelector() and querySelectorAll() on Nodes: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll --- lib/js/dom.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 950a5065b..d425b62c5 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -171,8 +171,11 @@ type nodeType*: NodeType nodeValue*: cstring parentNode*: Node + content*: Node previousSibling*: Node + ownerDocument*: Document innerHTML*: cstring + outerHTML*: cstring innerText*: cstring textContent*: cstring style*: Style @@ -1042,6 +1045,7 @@ when defined(nodejs): result = cast[Element](x.childNodes[idx]) var document* = Document(nodeType: DocumentNode) + document.ownerDocument = document proc getElem(x: Element; id: cstring): Element = if x.id == id: return x @@ -1055,6 +1059,7 @@ when defined(nodejs): proc appendChild*(parent, n: Node) = n.parentNode = parent + n.ownerDocument = parent.ownerDocument parent.childNodes.add n proc replaceChild*(parent, newNode, oldNode: Node) = @@ -1101,6 +1106,12 @@ when defined(nodejs): result.nodeValue = identifier result.nodeType = NodeType.TextNode + proc createComment*(d: Document, data: cstring): Node = + new(result) + result.nodeName = "#comment" + result.nodeValue = data + result.nodeType = NodeType.CommentNode + else: proc len*(x: Node): int {.importcpp: "#.childNodes.length".} proc `[]`*(x: Node; idx: int): Element {.importcpp: "#.childNodes[#]".} @@ -1112,6 +1123,7 @@ else: proc getElementById*(d: Document, id: cstring): Element {.importcpp.} proc createElement*(d: Document, identifier: cstring): Element {.importcpp.} proc createTextNode*(d: Document, identifier: cstring): Node {.importcpp.} + proc createComment*(d: Document, data: cstring): Node {.importcpp.} proc setTimeout*(action: proc(); ms: int): Timeout {.importc, nodecl.} proc clearTimeout*(t: Timeout) {.importc, nodecl.} @@ -1177,6 +1189,8 @@ proc replaceData*(n: Node, start, len: int, text: cstring) proc scrollIntoView*(n: Node) proc setAttribute*(n: Node, name, value: cstring) proc setAttributeNode*(n: Node, attr: Node) +proc querySelector*(n: Node, selectors: cstring): Element +proc querySelectorAll*(n: Node, selectors: cstring): seq[Element] # Document "methods" proc captureEvents*(d: Document, eventMask: int) {.deprecated.} From 6668b4340919fb021b2a607c22ae27f5dcf052f6 Mon Sep 17 00:00:00 2001 From: Bung <535670947@qq.com> Date: Sat, 23 May 2020 01:24:52 +0800 Subject: [PATCH 0577/4254] add insert,tryInsert unify for postgres that need pk name (#14416) * add insert,tryInsert unify for postgres that need pk name * add ReadDbEffect to new procs * add .since and changelog * change since to 1.3 * Update lib/impure/db_postgres.nim Co-authored-by: bung87 Co-authored-by: Andreas Rumpf Co-authored-by: alaviss --- changelog.md | 1 + lib/impure/db_mysql.nim | 15 +++++++++++++++ lib/impure/db_odbc.nim | 15 +++++++++++++++ lib/impure/db_postgres.nim | 22 ++++++++++++++++++++++ lib/impure/db_sqlite.nim | 15 +++++++++++++++ 5 files changed, 68 insertions(+) diff --git a/changelog.md b/changelog.md index 0e1af73c1..0d4fb6af9 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## Standard library additions and changes +- Add `tryInsert`,`insert` procs to db_* libs accept primary key column name. - Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. - `uri` adds Data URI Base64, implements RFC-2397. - Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 510503a63..c96829830 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -88,6 +88,8 @@ import strutils, mysql import db_common export db_common +import std/private/since + type DbConn* = distinct PMySQL ## encapsulates a database connection Row* = seq[string] ## a row of a dataset. NULL database values will be @@ -359,6 +361,19 @@ proc insertId*(db: DbConn, query: SqlQuery, result = tryInsertID(db, query, args) if result < 0: dbError(db) +proc tryInsert*(db: DbConn, query: SqlQuery, pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [WriteDbEffect], raises: [], since: (1, 3).} = + ## same as tryInsertID + tryInsertID(db, query, args) + +proc insert*(db: DbConn, query: SqlQuery, pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [WriteDbEffect], since: (1, 3).} = + ## same as insertId + result = tryInsert(db, query,pkName, args) + if result < 0: dbError(db) + proc execAffectedRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {. tags: [ReadDbEffect, WriteDbEffect].} = diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 9ff050bfa..863cf6c8c 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -92,6 +92,8 @@ import strutils, odbcsql import db_common export db_common +import std/private/since + type OdbcConnTyp = tuple[hDb: SqlHDBC, env: SqlHEnv, stmt: SqlHStmt] DbConn* = OdbcConnTyp ## encapsulates a database connection @@ -451,6 +453,19 @@ proc insertId*(db: var DbConn, query: SqlQuery, result = tryInsertID(db, query, args) if result < 0: dbError(db) +proc tryInsert*(db: var DbConn, query: SqlQuery,pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [ReadDbEffect, WriteDbEffect], raises: [], since: (1, 3).} = + ## same as tryInsertID + tryInsertID(db, query, args) + +proc insert*(db: var DbConn, query: SqlQuery, pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [ReadDbEffect, WriteDbEffect], since: (1, 3).} = + ## same as insertId + result = tryInsert(db, query,pkName, args) + if result < 0: dbError(db) + proc execAffectedRows*(db: var DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {. tags: [ReadDbEffect, WriteDbEffect], raises: [DbError].} = diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 57c61fa23..9e8075450 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -68,6 +68,8 @@ import strutils, postgres import db_common export db_common +import std/private/since + type DbConn* = PPGconn ## encapsulates a database connection Row* = seq[string] ## a row of a dataset. NULL database values will be @@ -485,6 +487,26 @@ proc insertID*(db: DbConn, query: SqlQuery, result = tryInsertID(db, query, args) if result < 0: dbError(db) +proc tryInsert*(db: DbConn, query: SqlQuery,pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [WriteDbEffect], since: (1, 3).}= + ## executes the query (typically "INSERT") and returns the + ## generated ID for the row or -1 in case of an error. + var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName), + args), 0, 0) + if not isNil(x): + result = parseBiggestInt($x) + else: + result = -1 + +proc insert*(db: DbConn, query: SqlQuery, pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [WriteDbEffect], since: (1, 3).} = + ## executes the query (typically "INSERT") and returns the + ## generated ID + result = tryInsertID(db, query, args) + if result < 0: dbError(db) + proc execAffectedRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {.tags: [ ReadDbEffect, WriteDbEffect].} = diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index c7ace0171..ff00dd86e 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -118,6 +118,8 @@ import sqlite3 import db_common export db_common +import std/private/since + type DbConn* = PSqlite3 ## Encapsulates a database connection. Row* = seq[string] ## A row of a dataset. `NULL` database values will be @@ -636,6 +638,19 @@ proc insertID*(db: DbConn, query: SqlQuery, result = tryInsertID(db, query, args) if result < 0: dbError(db) +proc tryInsert*(db: DbConn, query: SqlQuery, pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [WriteDbEffect], raises: [], since: (1, 3).} = + ## same as tryInsertID + tryInsertID(db, query, args) + +proc insert*(db: DbConn, query: SqlQuery, pkName: string, + args: varargs[string, `$`]): int64 + {.tags: [WriteDbEffect], since: (1, 3).} = + ## same as insertId + result = tryInsert(db, query,pkName, args) + if result < 0: dbError(db) + proc execAffectedRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {. tags: [ReadDbEffect, WriteDbEffect].} = From c61f7466292cb19c910f4a2f2976f738796e6bdf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 22 May 2020 20:24:37 +0200 Subject: [PATCH 0578/4254] avoid unsafe Nim features in preparation for --gc:arc (#14431) --- compiler/seminst.nim | 8 ++++---- compiler/semtypinst.nim | 25 +++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index fa338956d..1a7bd9b6b 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -178,13 +178,13 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, internalAssert c.config, header.kind == tyGenericInvocation var - typeMap: LayeredIdTable cl: TReplTypeVars initIdTable(cl.symMap) initIdTable(cl.localCache) - initIdTable(typeMap.topLayer) - cl.typeMap = addr(typeMap) + cl.typeMap = LayeredIdTable() + initIdTable(cl.typeMap.topLayer) + cl.info = info cl.c = c cl.allowMetaTypes = allowMetaTypes @@ -244,7 +244,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, #addDecl(c, prc) pushInfoContext(c.config, info) var typeMap = initLayeredTypeMap(pt) - var cl = initTypeVars(c, addr(typeMap), info, nil) + var cl = initTypeVars(c, typeMap, info, nil) var result = instCopyType(cl, prc.typ) let originalParams = result.n result.n = originalParams.shallowCopy diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 08ea85708..257094289 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -68,13 +68,13 @@ proc cacheTypeInst*(inst: PType) = gt.sym.typeInstCache.add(inst) type - LayeredIdTable* = object + LayeredIdTable* = ref object topLayer*: TIdTable - nextLayer*: ptr LayeredIdTable + nextLayer*: LayeredIdTable TReplTypeVars* = object c*: PContext - typeMap*: ptr LayeredIdTable # map PType to PType + typeMap*: LayeredIdTable # map PType to PType symMap*: TIdTable # map PSym to PSym localCache*: TIdTable # local cache for remembering already replaced # types during instantiation of meta types @@ -92,20 +92,22 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable = + result = LayeredIdTable() copyIdTable(result.topLayer, pt) proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable = + result = LayeredIdTable() result.nextLayer = cl.typeMap initIdTable(result.topLayer) -proc lookup(typeMap: ptr LayeredIdTable, key: PType): PType = +proc lookup(typeMap: LayeredIdTable, key: PType): PType = var tm = typeMap while tm != nil: result = PType(idTableGet(tm.topLayer, key)) if result != nil: return tm = tm.nextLayer -template put(typeMap: ptr LayeredIdTable, key, value: PType) = +template put(typeMap: LayeredIdTable, key, value: PType) = idTablePut(typeMap.topLayer, key, value) template checkMetaInvariants(cl: TReplTypeVars, t: PType) = @@ -369,8 +371,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = let oldSkipTypedesc = cl.skipTypedesc cl.skipTypedesc = true - var typeMapLayer = newTypeMapLayer(cl) - cl.typeMap = addr(typeMapLayer) + cl.typeMap = newTypeMapLayer(cl) for i in 1.. int ----> proc (x: int = 0) var typeMap = initLayeredTypeMap(pt) - var cl = initTypeVars(p, addr(typeMap), info, nil) + var cl = initTypeVars(p, typeMap, info, nil) pushInfoContext(p.config, info) result = replaceTypeVarsT(cl, t) popInfoContext(p.config) @@ -714,7 +715,7 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo, proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo, t: PType): PType = var typeMap = initLayeredTypeMap(pt) - var cl = initTypeVars(p, addr(typeMap), info, nil) + var cl = initTypeVars(p, typeMap, info, nil) cl.allowMetaTypes = true pushInfoContext(p.config, info) result = replaceTypeVarsT(cl, t) From b012205b2e1a78b3cf336934f289891477b8c414 Mon Sep 17 00:00:00 2001 From: genotrance Date: Sat, 23 May 2020 11:06:04 -0500 Subject: [PATCH 0579/4254] Fix #14057 - moveFile should overwrite on Windows (#14433) --- lib/pure/os.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 449ae1d84..fbd722863 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1801,9 +1801,9 @@ proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} = when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) - if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) == 0'i32: raiseOSError(osLastError(), $(source, dest)) else: - if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) == 0'i32: raiseOSError(osLastError(), $(source, dest)) else: if c_rename(source, dest) != 0'i32: let err = osLastError() From f70d01a7d512ef305cb457db71b35995b3720a1d Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 24 May 2020 07:26:49 +0300 Subject: [PATCH 0580/4254] fix repr(char) example assert (#14437) --- lib/system/repr_v2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index be1a4cf3a..fcc187a42 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -32,7 +32,7 @@ proc repr*(x: char): string {.noSideEffect.} = ## converted to a string. ## ## .. code-block:: Nim - ## assert repr('c') == "c" + ## assert repr('c') == "'c'" '\'' & $x & '\'' proc repr*(x: cstring): string {.noSideEffect.} = From acae3b02c7d3b7d916430223c5a2948e68d83ea4 Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 23 May 2020 22:32:24 -0700 Subject: [PATCH 0581/4254] Add clipPath to dom.nim. (#14435) Just adds a single new css atribute, see: https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path . --- lib/js/dom.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index d425b62c5..65f9a946b 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -398,6 +398,7 @@ type captionSide*: cstring clear*: cstring clip*: cstring + clipPath*: cstring color*: cstring cursor*: cstring direction*: cstring @@ -1384,4 +1385,4 @@ since (1, 3): proc readAsDataURL*(f: FileReader, b: Blob) {.importcpp: "#.readAsDataURL(#)".} ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL proc readAsText*(f: FileReader, b: Blob, encoding = cstring"UTF-8") {.importcpp: "#.readAsText(#, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText \ No newline at end of file + ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText From a008f591e2b318c2c9e12b8923210435d22e8280 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 25 May 2020 02:17:25 -0700 Subject: [PATCH 0582/4254] add test for `define`, `undef` (#14443) --- tests/pragmas/tpragmas_misc.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/pragmas/tpragmas_misc.nim diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim new file mode 100644 index 000000000..247fa471e --- /dev/null +++ b/tests/pragmas/tpragmas_misc.nim @@ -0,0 +1,12 @@ +##[ +tests for misc pragmas that don't need a separate file +]## + +block: + static: doAssert not defined(tpragmas_misc_def) + {.undef(tpragmas_misc_def).} # works even if not set + static: doAssert not defined(tpragmas_misc_def) + {.define(tpragmas_misc_def).} + static: doAssert defined(tpragmas_misc_def) + {.undef(tpragmas_misc_def).} + static: doAssert not defined(tpragmas_misc_def) From 79e85cb0b55437d8a5990f66c760fb98998de372 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 25 May 2020 12:16:32 +0200 Subject: [PATCH 0583/4254] manual.rst: updates [backport] (#14445) --- doc/manual.rst | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 8b27c7819..2c39b3e73 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1802,7 +1802,7 @@ Mixing GC'ed memory with ``ptr`` Special care has to be taken if an untraced object contains traced objects like traced references, strings or sequences: in order to free everything properly, -the built-in procedure ``GCunref`` has to be called before freeing the untraced +the built-in procedure ``reset`` has to be called before freeing the untraced memory manually: .. code-block:: nim @@ -1816,12 +1816,12 @@ memory manually: d.s = "abc" # tell the GC that the string is not needed anymore: - GCunref(d.s) + reset(d.s) # free the memory: dealloc(d) -Without the ``GCunref`` call the memory allocated for the ``d.s`` string would +Without the ``reset`` call the memory allocated for the ``d.s`` string would never be freed. The example also demonstrates two important features for low level programming: the ``sizeof`` proc returns the size of a type or value in bytes. The ``cast`` operator can circumvent the type system: the compiler @@ -2336,7 +2336,7 @@ The convertible relation can be relaxed by a user-defined type # implicit conversion magic happens here x = chr echo x # => 97 - # you can use the explicit form too + # one can use the explicit form too x = chr.toInt echo x # => 97 @@ -4280,9 +4280,10 @@ caught by reference. Example: fn() -**Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available -for imported exceptions. You need to use `except ImportedException as x:` syntax -and rely on functionality of `x` object to get exception details. +**Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available +for imported exceptions. One needs to use the `except ImportedException as x:` syntax +and rely on functionality of the `x` object to get exception details. + Effect system ============= @@ -4885,7 +4886,7 @@ compiler. Explicit immediate templates are now deprecated. Passing a code block to a template ---------------------------------- -You can pass a block of statements as the last argument to a template +One can pass a block of statements as the last argument to a template following the special ``:`` syntax: .. code-block:: nim @@ -5425,7 +5426,7 @@ generic type ``static[T]``. The type param can be omitted to obtain the type class of all constant expressions. A more specific type class can be created by instantiating ``static`` with another type class. -You can force an expression to be evaluated at compile time as a constant +One can force an expression to be evaluated at compile time as a constant expression by coercing it to a corresponding ``static`` type: .. code-block:: nim @@ -5439,14 +5440,14 @@ possible type mismatch error. typedesc[T] ----------- -In many contexts, Nim allows you to treat the names of types as regular +In many contexts, Nim allows to treat the names of types as regular values. These values exists only during the compilation phase, but since all values must have a type, ``typedesc`` is considered their special type. ``typedesc`` acts like a generic type. For instance, the type of the symbol ``int`` is ``typedesc[int]``. Just like with regular generic types, when the generic param is omitted, ``typedesc`` denotes the type class of all types. -As a syntactic convenience, you can also use ``typedesc`` as a modifier. +As a syntactic convenience, one can also use ``typedesc`` as a modifier. Procs featuring ``typedesc`` params are considered implicitly generic. They will be instantiated for each unique combination of supplied types @@ -5524,7 +5525,7 @@ typeof operator **Note**: ``typeof(x)`` can for historical reasons also be written as ``type(x)`` but ``type(x)`` is discouraged. -You can obtain the type of a given expression by constructing a ``typeof`` +One can obtain the type of a given expression by constructing a ``typeof`` value from it (in many other languages this is known as the `typeof`:idx: operator): @@ -5751,9 +5752,9 @@ modules don't need to import a module's dependencies: echo $x When the exported symbol is another module, all of its definitions will -be forwarded. You can use an ``except`` list to exclude some of the symbols. +be forwarded. One can use an ``except`` list to exclude some of the symbols. -Notice that when exporting, you need to specify only the module name: +Notice that when exporting, one needs to specify only the module name: .. code-block:: nim import foo/bar/baz @@ -6480,7 +6481,7 @@ with the project: {.compile: "myfile.cpp".} **Note**: Nim computes a SHA1 checksum and only recompiles the file if it -has changed. You can use the ``-f`` command line option to force recompilation +has changed. One can use the ``-f`` command line option to force recompilation of the file. @@ -6495,12 +6496,12 @@ The ``link`` pragma can be used to link an additional file with the project: PassC pragma ------------ The ``passc`` pragma can be used to pass additional parameters to the C -compiler like you would using the commandline switch ``--passc``: +compiler like one would using the commandline switch ``--passc``: .. code-block:: Nim {.passc: "-Wall -Werror".} -Note that you can use ``gorge`` from the `system module `_ to +Note that one can use ``gorge`` from the `system module `_ to embed parameters from an external command that will be executed during semantic analysis: @@ -6523,12 +6524,12 @@ the pragma resides in: PassL pragma ------------ The ``passL`` pragma can be used to pass additional parameters to the linker -like you would using the commandline switch ``--passL``: +like one would using the commandline switch ``--passL``: .. code-block:: Nim {.passL: "-lSDLmain -lSDL".} -Note that you can use ``gorge`` from the `system module `_ to +Note that one can use ``gorge`` from the `system module `_ to embed parameters from an external command that will be executed during semantic analysis: @@ -6783,7 +6784,7 @@ Importcpp for objects ~~~~~~~~~~~~~~~~~~~~~ Generic ``importcpp``'ed objects are mapped to C++ templates. This means that -you can import C++'s templates rather easily without the need for a pattern +one can import C++'s templates rather easily without the need for a pattern language for object types: .. code-block:: nim @@ -7032,9 +7033,9 @@ specified. It is possible to annotate procs, templates, type and variable definitions, statements, etc. Macros module includes helpers which can be used to simplify custom pragma -access `hasCustomPragma`, `getCustomPragmaVal`. Please consult macros module -documentation for details. These macros are no magic, they don't do anything -you cannot do yourself by walking AST object representation. +access `hasCustomPragma`, `getCustomPragmaVal`. Please consult the macros module +documentation for details. These macros are not magic, everything they do can +also be achieved by walking the AST of the object representation. More examples with custom pragmas: From cbfe9325c5c1851630ce10cf780d1af27c57d19a Mon Sep 17 00:00:00 2001 From: Max Grender-Jones Date: Mon, 25 May 2020 11:18:35 +0100 Subject: [PATCH 0584/4254] Add support for mktemps (#14347) --- lib/posix/posix.nim | 13 +++++++++++-- lib/posix/posix_utils.nim | 19 +++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 96203b736..d3d9728ab 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1036,12 +1036,21 @@ proc mkstemp*(tmpl: cstring): cint {.importc, header: "", sideEffect.} ## Creates a unique temporary file. ## ## **Warning**: The `tmpl` argument is written to by `mkstemp` and thus - ## can't be a string literal. If in doubt copy the string before passing it. + ## can't be a string literal. If in doubt make a copy of the cstring before + ## passing it in. + +proc mkstemps*(tmpl: cstring, suffixlen: int): cint {.importc, header: "", sideEffect.} + ## Creates a unique temporary file. + ## + ## **Warning**: The `tmpl` argument is written to by `mkstemps` and thus + ## can't be a string literal. If in doubt make a copy of the cstring before + ## passing it in. proc mkdtemp*(tmpl: cstring): pointer {.importc, header: "", sideEffect.} -when defined(linux) or defined(bsd): +when defined(linux) or defined(bsd) or defined(osx): proc mkostemp*(tmpl: cstring, oflags: cint): cint {.importc, header: "", sideEffect.} + proc mkostemps*(tmpl: cstring, suffixlen: cint, oflags: cint): cint {.importc, header: "", sideEffect.} proc posix_memalign*(memptr: pointer, alignment: csize_t, size: csize_t): cint {.importc, header: "".} diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 2d0288187..d083e20b9 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -78,16 +78,23 @@ proc sendSignal*(pid: Pid, signal: int) = if kill(pid, signal.cint) != 0: raise newException(OSError, $strerror(errno)) -proc mkstemp*(prefix: string): (string, File) = - ## Creates a unique temporary file from a prefix string. Adds a six chars suffix. +proc mkstemp*(prefix: string, suffix=""): (string, File) = + ## Creates a unique temporary file from a prefix string. A six-character string + ## will be added. If suffix is provided it will be added to the string ## The file is created with perms 0600. ## Returns the filename and a file opened in r/w mode. - var tmpl = cstring(prefix & "XXXXXX") + var tmpl = cstring(prefix & "XXXXXX" & suffix) let fd = - when declared(mkostemp): - mkostemp(tmpl, O_CLOEXEC) + if len(suffix)==0: + when declared(mkostemp): + mkostemp(tmpl, O_CLOEXEC) + else: + mkstemp(tmpl) else: - mkstemp(tmpl) + when declared(mkostemps): + mkostemps(tmpl, cint(len(suffix)), O_CLOEXEC) + else: + mkstemps(tmpl, cint(len(suffix))) var f: File if open(f, fd, fmReadWrite): return ($tmpl, f) From 58282547f6d3fe4ce3fa2efe4f6afe07bc5de662 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 25 May 2020 04:25:40 -0700 Subject: [PATCH 0585/4254] fix #6583, fix #14376, index+search now generated for all projects, many bug fixes with nim doc (#14324) * refs #6583 fix nim doc output * changelog * change default for outDir when unspecified * cleanups * --project implies --index --- .gitignore | 5 +- changelog.md | 4 +- compiler/commands.nim | 4 +- compiler/docgen.nim | 64 +++++----- compiler/main.nim | 116 +++++++----------- compiler/msgs.nim | 10 +- compiler/nimpaths.nim | 44 +++++++ compiler/options.nim | 8 +- config/nimdoc.cfg | 9 +- doc/docgen.rst | 12 +- .../expected/index.html | 3 + .../expected/subdir/subdir_b/utils.html | 5 +- nimdoc/testproject/expected/testproject.html | 3 + testament/lib/stdtest/specialpaths.nim | 28 ++--- testament/lib/stdtest/unittest_light.nim | 6 +- tests/misc/trunner.nim | 101 +++++++++++++-- tests/nimdoc/imp.nim | 1 + tests/nimdoc/m13129.nim | 4 +- tests/nimdoc/sub/imp.nim | 1 + tests/nimdoc/sub/imp2.nim | 1 + tests/nimdoc/sub/mmain.nim | 8 ++ tools/kochdocs.nim | 18 ++- 22 files changed, 294 insertions(+), 161 deletions(-) create mode 100644 compiler/nimpaths.nim create mode 100644 tests/nimdoc/imp.nim create mode 100644 tests/nimdoc/sub/imp.nim create mode 100644 tests/nimdoc/sub/imp2.nim create mode 100644 tests/nimdoc/sub/mmain.nim diff --git a/.gitignore b/.gitignore index b967707d8..cf0bcfbd6 100644 --- a/.gitignore +++ b/.gitignore @@ -92,7 +92,8 @@ megatest.nim # ignore debug dirs generated by dsymutil on OSX *.dSYM -nimdoc.out.css - # for `nim c -r nimdoc/tester` etc; this can be in multiple places htmldocs + +## these are not needed anymore unless checkout old older versions +nimdoc.out.css diff --git a/changelog.md b/changelog.md index 0d4fb6af9..8eeebf9ac 100644 --- a/changelog.md +++ b/changelog.md @@ -94,7 +94,6 @@ - The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. - The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. -- `osproc.execCmdEx` now takes an optional `input` for stdin. - `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` parameters. @@ -188,6 +187,9 @@ proc mydiv(a, b): int {.raises: [].} = and avoids polluting both $pwd and $projectdir. It can be used with any command. - `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override how an example is compiled and run, for example to change backend or compile only. +- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified (with or without `--project`); + passing `--project` now automatically generates an index and enables search. + See [docgen](docgen.html#introduction-quick-start) for details. ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index e2e1a4558..ce4f7cc0f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -440,7 +440,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectArg(conf, switch, arg, pass, info) conf.docSeeSrcUrl = arg of "docroot": - conf.docRoot = if arg.len == 0: "@default" else: arg + conf.docRoot = if arg.len == 0: docRootDefault else: arg of "backend", "b": let backend = parseEnum(arg.normalize, TBackend.default) if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg) @@ -485,7 +485,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "forcebuild", "f": processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info) of "project": - processOnOffSwitchG(conf, {optWholeProject}, arg, pass, info) + processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) of "gc": expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a67dc48ec..bd967d403 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -17,11 +17,10 @@ import packages/docutils/rst, packages/docutils/rstgen, json, xmltree, cgi, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, trees, tables + pathutils, trees, tables, nimpaths const exportSection = skField - htmldocsDir = RelativeDir"htmldocs" docCmdSkip = "skip" type @@ -51,7 +50,7 @@ type destFile*: AbsoluteFile thisDir*: AbsoluteDir exampleGroups: OrderedTable[string, ExampleGroup] - wroteCss*: bool + wroteSupportFiles*: bool PDoc* = ref TDocumentor ## Alias to type less. @@ -72,7 +71,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re proc nimbleDir(): AbsoluteDir = getNimbleFile(conf, file2).parentDir.AbsoluteDir case conf.docRoot: - of "@default": # using `@` instead of `$` to avoid shell quoting complications + of docRootDefault: result = getRelativePathFromConfigPath(conf, file) let dir = nimbleDir() if not dir.isEmpty: @@ -88,9 +87,12 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re result = getRelativePathFromConfigPath(conf, file) if result.isEmpty: bail() elif conf.docRoot.len > 0: - doAssert conf.docRoot.isAbsolute, conf.docRoot # or globalError - doAssert conf.docRoot.existsDir, conf.docRoot - result = relativeTo(file, conf.docRoot.AbsoluteDir) + # we're (currently) requiring `isAbsolute` to avoid confusion when passing + # a relative path (would it be relative wrt $PWD or to projectfile) + conf.globalAssert conf.docRoot.isAbsolute, arg=conf.docRoot + conf.globalAssert conf.docRoot.existsDir, arg=conf.docRoot + # needed because `canonicalizePath` called on `file` + result = file.relativeTo conf.docRoot.expandFilename.AbsoluteDir else: bail() if isAbsolute(result.string): @@ -1125,11 +1127,8 @@ proc genSection(d: PDoc, kind: TSymKind) = "sectionid", "sectionTitle", "sectionTitleID", "content"], [ ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]]) -const nimdocOutCss = "nimdoc.out.css" - # `out` to make it easier to use with gitignore in user's repos - -proc cssHref(outDir: AbsoluteDir, destFile: AbsoluteFile): Rope = - rope($relativeTo(outDir / nimdocOutCss.RelativeFile, destFile.splitFile().dir, '/')) +proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): Rope = + rope($relativeTo(outDir / linkto, destFile.splitFile().dir, '/')) proc genOutFile(d: PDoc): Rope = var @@ -1160,15 +1159,17 @@ proc genOutFile(d: PDoc): Rope = elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", - "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg"], + "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref"], [title.rope, toc, d.modDesc, rope(getDateStr()), - rope(getClockStr()), code, d.modDeprecationMsg]) + rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile)]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ - "nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time", + "nimdoccss", "dochackjs", "title", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics", "deprecationMsg"], - [cssHref(d.conf.outDir, d.destFile), title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), + [relLink(d.conf.outDir, d.destFile, nimdocOutCss.RelativeFile), + relLink(d.conf.outDir, d.destFile, docHackJsFname.RelativeFile), + title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), content, d.meta[metaAuthor].rope, d.meta[metaVersion].rope, d.analytics.rope, d.modDeprecationMsg]) else: code = content @@ -1203,11 +1204,13 @@ proc writeOutput*(d: PDoc, useWarning = false) = if not writeRope(content, outfile): rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile.string) - elif not d.wroteCss: - let cssSource = $d.conf.getPrefixDir() / "doc" / "nimdoc.css" - let cssDest = $dir / nimdocOutCss - copyFile(cssSource, cssDest) - d.wroteCss = true + elif not d.wroteSupportFiles: # nimdoc.css + dochack.js + let nimr = $d.conf.getPrefixDir() + copyFile(docCss.interp(nimr = nimr), $d.conf.outDir / nimdocOutCss) + if optGenIndex in d.conf.globalOptions: + let docHackJs2 = getDocHacksJs(nimr, nim = getAppFilename()) + copyFile(docHackJs2, $d.conf.outDir / docHackJs2.lastPathPart) + d.wroteSupportFiles = true proc writeOutputJson*(d: PDoc, useWarning = false) = runAllExamples(d) @@ -1234,6 +1237,8 @@ proc writeOutputJson*(d: PDoc, useWarning = false) = proc handleDocOutputOptions*(conf: ConfigRef) = if optWholeProject in conf.globalOptions: # Backward compatibility with previous versions + # xxx this is buggy when user provides `nim doc --project -o:sub/bar.html main`, + # it'd write to `sub/bar.html/main.html` conf.outDir = AbsoluteDir(conf.outDir / conf.outFile) proc commandDoc*(cache: IdentCache, conf: ConfigRef) = @@ -1308,20 +1313,23 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) = if not writeRope(content, filename): rawMessage(conf, errCannotOpenFile, filename.string) -proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) = - var content = mergeIndexes(conf.projectFull.string).rope +proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") = + var content = mergeIndexes(dir).rope - var outFile = RelativeFile"theindex" - if conf.outFile != RelativeFile"": - outFile = conf.outFile + var outFile = outFile + if outFile.isEmpty: outFile = theindexFname.RelativeFile.changeFileExt("") let filename = getOutFile(conf, outFile, HtmlExt) let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), [ - "nimdoccss", "title", "tableofcontents", "moduledesc", "date", "time", + "nimdoccss", "dochackjs", + "title", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics"], - [cssHref(conf.outDir, filename), rope"Index", nil, nil, rope(getDateStr()), + [relLink(conf.outDir, filename, nimdocOutCss.RelativeFile), + relLink(conf.outDir, filename, docHackJsFname.RelativeFile), + rope"Index", nil, nil, rope(getDateStr()), rope(getClockStr()), content, nil, nil, nil]) # no analytics because context is not available if not writeRope(code, filename): rawMessage(conf, errCannotOpenFile, filename.string) + diff --git a/compiler/main.nim b/compiler/main.nim index 88f1890de..55b2f2899 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -66,16 +66,8 @@ when not defined(leanCompiler): compileProject(graph) finishDoc2Pass(graph.config.projectName) -proc setOutDir(conf: ConfigRef) = - if conf.outDir.isEmpty: - if optUseNimcache in conf.globalOptions: - conf.outDir = getNimcacheDir(conf) - else: - conf.outDir = conf.projectPath - proc commandCompileToC(graph: ModuleGraph) = let conf = graph.config - setOutDir(conf) if conf.outFile.isEmpty: let base = conf.projectName let targetName = if optGenDynLib in conf.globalOptions: @@ -121,7 +113,6 @@ proc commandCompileToJS(graph: ModuleGraph) = let conf = graph.config conf.exc = excCpp - setOutDir(conf) if conf.outFile.isEmpty: conf.outFile = RelativeFile(conf.projectName & ".js") @@ -191,11 +182,6 @@ proc mainCommand*(graph: ModuleGraph) = conf.searchPaths.add(conf.libpath) setId(100) - ## Calling `setOutDir(conf)` unconditionally would fix regression - ## https://github.com/nim-lang/Nim/issues/6583#issuecomment-625711125 - when false: setOutDir(conf) - if optUseNimcache in conf.globalOptions: setOutDir(conf) - proc customizeForBackend(backend: TBackend) = ## Sets backend specific options but don't compile to backend yet in ## case command doesn't require it. This must be called by all commands. @@ -234,15 +220,40 @@ proc mainCommand*(graph: ModuleGraph) = of backendJs: commandCompileToJS(graph) of backendInvalid: doAssert false + template docLikeCmd(body) = + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + wantMainModule(conf) + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + defineSymbol(conf.symbols, "nimdoc") + body + + block: ## command prepass + var docLikeCmd2 = false # includes what calls `docLikeCmd` + some more + case conf.command.normalize + of "r": conf.globalOptions.incl {optRun, optUseNimcache} + of "doc0", "doc2", "doc", "rst2html", "rst2tex", "jsondoc0", "jsondoc2", + "jsondoc", "ctags", "buildindex": docLikeCmd2 = true + else: discard + if conf.outDir.isEmpty: + # doc like commands can generate a lot of files (especially with --project) + # so by default should not end up in $PWD nor in $projectPath. + conf.outDir = block: + var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) + else: conf.projectPath + doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee + if docLikeCmd2: ret = ret / htmldocsDir + ret + ## process all backend commands case conf.command.normalize of "c", "cc", "compile", "compiletoc": compileToBackend(backendC) # compile means compileToC currently of "cpp", "compiletocpp": compileToBackend(backendCpp) of "objc", "compiletooc": compileToBackend(backendObjc) of "js", "compiletojs": compileToBackend(backendJs) - of "r": # different from `"run"`! - conf.globalOptions.incl {optRun, optUseNimcache} - compileToBackend(backendC) + of "r": compileToBackend(backendC) # different from `"run"`! of "run": when hasTinyCBackend: extccomp.setCC(conf, "tcc", unknownLineInfo) @@ -254,29 +265,19 @@ proc mainCommand*(graph: ModuleGraph) = else: customizeForBackend(backendC) # fallback for other commands ## process all other commands - case conf.command.normalize - of "doc0": - when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" - else: - wantMainModule(conf) - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - commandDoc(cache, conf) + case conf.command.normalize # synchronize with `cmdUsingHtmlDocs` + of "doc0": docLikeCmd commandDoc(cache, conf) of "doc2", "doc": - conf.setNoteDefaults(warnLockLevel, false) # issue #13218 - conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 - # because currently generates lots of false positives due to conflation - # of labels links in doc comments, eg for random.rand: - # ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer - # ## * `rand proc<#rand,Rand,range[]>`_ that returns a float - when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" - else: - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - defineSymbol(conf.symbols, "nimdoc") + docLikeCmd(): + conf.setNoteDefaults(warnLockLevel, false) # issue #13218 + conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 + # because currently generates lots of false positives due to conflation + # of labels links in doc comments, eg for random.rand: + # ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer + # ## * `rand proc<#rand,Rand,range[]>`_ that returns a float commandDoc2(graph, false) + if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions: + commandBuildIndex(conf, $conf.outDir) of "rst2html": conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218 when defined(leanCompiler): @@ -292,41 +293,10 @@ proc mainCommand*(graph: ModuleGraph) = conf.cmd = cmdRst2tex loadConfigs(DocTexConfig, cache, conf) commandRst2TeX(cache, conf) - of "jsondoc0": - when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" - else: - wantMainModule(conf) - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - wantMainModule(conf) - defineSymbol(conf.symbols, "nimdoc") - commandJson(cache, conf) - of "jsondoc2", "jsondoc": - when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" - else: - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - wantMainModule(conf) - defineSymbol(conf.symbols, "nimdoc") - commandDoc2(graph, true) - of "ctags": - when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" - else: - wantMainModule(conf) - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - defineSymbol(conf.symbols, "nimdoc") - commandTags(cache, conf) - of "buildindex": - when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" - else: - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - commandBuildIndex(cache, conf) + of "jsondoc0": docLikeCmd commandJson(cache, conf) + of "jsondoc2", "jsondoc": docLikeCmd commandDoc2(graph, true) + of "ctags": docLikeCmd commandTags(cache, conf) + of "buildindex": docLikeCmd commandBuildIndex(conf, $conf.projectFull, conf.outFile) of "gendepend": conf.cmd = cmdGenDepend commandGenDepend(graph) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6bf4d82d2..a26aa0a3c 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -510,7 +510,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg) if conf.hasHint(hintSource) and info != unknownLineInfo: conf.writeSurroundingSrc(info) - if conf.hasHint(hintMsgOrigin): + if hintMsgOrigin in conf.mainPackageNotes: styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, KindFormat % hintMsgOrigin.msgToStr, @@ -529,6 +529,14 @@ template fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = conf.m.errorOutputs = {eStdOut, eStdErr} liMessage(conf, info, msg, arg, doAbort, instLoc()) +template globalAssert*(conf: ConfigRef; cond: untyped, info: TLineInfo = unknownLineInfo, arg = "") = + ## avoids boilerplate + if not cond: + const info2 = instantiationInfo(-1, fullPaths = true) + var arg2 = "'$1' failed" % [astToStr(cond)] + if arg.len > 0: arg2.add "; " & astToStr(arg) & ": " & arg + liMessage(conf, info, errGenerated, arg2, doRaise, info2) + template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(conf, info, msg, arg, doRaise, instLoc()) diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim new file mode 100644 index 000000000..2d7fa53cb --- /dev/null +++ b/compiler/nimpaths.nim @@ -0,0 +1,44 @@ +##[ +Represents absolute paths, but using a symbolic variables (eg $nimr) which can be +resolved at runtime; this avoids hardcoding at compile time absolute paths so +that the project root can be relocated. + +xxx consider some refactoring with $nim/testament/lib/stdtest/specialpaths.nim; +specialpaths is simpler because it doesn't need variables to be relocatable at +runtime (eg for use in testament) + +interpolation variables: + $nimr: such that `$nimr/lib/system.nim` exists (avoids confusion with $nim binary) + in compiler, it's obtainable via getPrefixDir(); for other tools (eg koch), + this could be getCurrentDir() or getAppFilename().parentDir.parentDir, + depending on use case + +Unstable API +]## + +import std/[os,strutils] + +const + docCss* = "$nimr/doc/nimdoc.css" + docHackNim* = "$nimr/tools/dochack/dochack.nim" + docHackJs* = docHackNim.changeFileExt("js") + docHackJsFname* = docHackJs.lastPathPart + theindexFname* = "theindex.html" + nimdocOutCss* = "nimdoc.out.css" + # `out` to make it easier to use with gitignore in user's repos + htmldocsDirname* = "htmldocs" + +proc interp*(path: string, nimr: string): string = + result = path % ["nimr", nimr] + doAssert '$' notin result, $(path, nimr, result) # avoids un-interpolated variables in output + +proc getDocHacksJs*(nimr: string, nim = getCurrentCompilerExe(), forceRebuild = false): string = + ## return absolute path to dochhack.js, rebuilding if it doesn't exist or if + ## `forceRebuild`. + let docHackJs2 = docHackJs.interp(nimr = nimr) + if forceRebuild or not docHackJs2.fileExists: + let cmd = "$nim js $file" % ["nim", nim.quoteShell, "file", docHackNim.interp(nimr = nimr).quoteShell] + echo "getDocHacksJs: cmd: " & cmd + doAssert execShellCmd(cmd) == 0, $(cmd) + doAssert docHackJs2.fileExists + result = docHackJs2 diff --git a/compiler/options.nim b/compiler/options.nim index 1418fff63..d990f2fd4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -9,7 +9,7 @@ import os, strutils, strtabs, sets, lineinfos, platform, - prefixmatches, pathutils + prefixmatches, pathutils, nimpaths from terminal import isatty from times import utc, fromUnix, local, getTime, format, DateTime @@ -518,8 +518,9 @@ const DefaultConfigNims* = RelativeFile"config.nims" DocConfig* = RelativeFile"nimdoc.cfg" DocTexConfig* = RelativeFile"nimdoc.tex.cfg" - -const oKeepVariableNames* = true + htmldocsDir* = htmldocsDirname.RelativeDir + docRootDefault* = "@default" # using `@` instead of `$` to avoid shell quoting complications + oKeepVariableNames* = true proc mainCommandArg*(conf: ConfigRef): string = ## This is intended for commands like check or parse @@ -543,6 +544,7 @@ proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): Absolute # explains regression https://github.com/nim-lang/Nim/issues/6583#issuecomment-625711125 # Yet another reason why "" should not mean "."; `""/something` should raise # instead of implying "" == "." as it's bug prone. + doAssert conf.outDir.string.len > 0 result = conf.outDir / changeFileExt(filename, ext) proc absOutFile*(conf: ConfigRef): AbsoluteFile = diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 4faebdf72..836b19ab6 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -100,7 +100,7 @@ doc.body_toc = """ Standard library

  • - Index + Index
  • @@ -143,7 +143,7 @@ doc.body_toc_group = """ Standard library
  • - Index + Index
  • @@ -183,6 +183,9 @@ doc.body_toc_group = """
    @@ -239,7 +242,7 @@ doc.file = """ $title - + + + 5: Date: Fri, 29 May 2020 15:18:15 +0530 Subject: [PATCH 0603/4254] disallow typedesc in arrays & move existing checks to `types.typeAllowedAux` (#13261) * disallow typedesc in arrays and move previous checks to types.typeAllowedAux --- compiler/sem.nim | 12 ++++---- compiler/semstmts.nim | 45 +++++++++++++--------------- compiler/types.nim | 32 +++++++++++++------- tests/array/t9932.nim | 11 +++++++ tests/errmsgs/t10489_a.nim | 2 +- tests/errmsgs/t10489_b.nim | 2 +- tests/errmsgs/t12844.nim | 6 ++-- tests/errmsgs/t5870.nim | 2 +- tests/errmsgs/t8610.nim | 2 +- tests/errmsgs/ttypeAllowed.nim | 2 +- tests/metatype/typedesc_as_value.nim | 2 +- tests/typerel/typedescs2.nim | 2 +- 12 files changed, 70 insertions(+), 50 deletions(-) create mode 100644 tests/array/t9932.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index 62e3ca8db..683c67254 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -233,13 +233,15 @@ proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKi flags: TTypeAllowedFlags = {}) = let t = typeAllowed(typ, kind, flags) if t != nil: + var err: string if t == typ: - localError(conf, info, "invalid type: '" & typeToString(typ) & - "' for " & substr($kind, 2).toLowerAscii) + err = "invalid type: '$1' for $2" % [typeToString(typ), toHumanStr(kind)] + if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags: + err &= ". Did you mean to call the $1 with '()'?" % [toHumanStr(typ.owner.kind)] else: - localError(conf, info, "invalid type: '" & typeToString(t) & - "' in this context: '" & typeToString(typ) & - "' for " & substr($kind, 2).toLowerAscii) + err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t), + typeToString(typ), toHumanStr(kind)] + localError(conf, info, err) proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = typeAllowedCheck(c.config, typ.n.info, typ, skProc) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 3faa32808..a4b4c9362 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -36,8 +36,6 @@ const errRecursiveDependencyX = "recursive dependency: '$1'" errRecursiveDependencyIteratorX = "recursion is not supported in iterators: '$1'" errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1" - errCannotAssignMacroSymbol = "cannot assign $1 '$2' to '$3'. Did you mean to call the $1 with '()'?" - errInvalidTypeDescAssign = "'typedesc' metatype is not valid here; typed '=' instead of ':'?" proc semDiscard(c: PContext, n: PNode): PNode = result = n @@ -491,19 +489,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if a[^2].kind != nkEmpty: typ = semTypeNode(c, a[^2], nil) + var typFlags: TTypeAllowedFlags + var def: PNode = c.graph.emptyNode if a[^1].kind != nkEmpty: def = semExprWithType(c, a[^1], {efAllowDestructor}) - if def.typ.kind == tyProc and def.kind == nkSym: - if def.sym.kind in {skMacro, skTemplate}: - localError(c.config, def.info, errCannotAssignMacroSymbol % [ - if def.sym.kind == skMacro: "macro" else: "template", - def.sym.name.s, a[0].ident.s]) - def.typ = errorType(c) + + if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}: + typFlags.incl taIsTemplateOrMacro elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: - # prevent the all too common 'var x = int' bug: - localError(c.config, def.info, errInvalidTypeDescAssign) - def.typ = errorType(c) + typFlags.incl taProcContextIsNotMacro if typ != nil: if typ.isMetaType: @@ -534,7 +529,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = # this can only happen for errornous var statements: if typ == nil: continue - typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) + + if c.matchedConcept != nil: + typFlags.incl taConcept + typeAllowedCheck(c.config, a.info, typ, symkind, typFlags) + when false: liftTypeBoundOps(c, typ, a.info) instAllTypeBoundOp(c, a.info) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) @@ -642,18 +641,15 @@ proc semConst(c: PContext, n: PNode): PNode = if a[^2].kind != nkEmpty: typ = semTypeNode(c, a[^2], nil) + var typFlags: TTypeAllowedFlags + # don't evaluate here since the type compatibility check below may add a converter var def = semExprWithType(c, a[^1]) - if def.typ.kind == tyProc and def.kind == nkSym: - if def.sym.kind in {skMacro, skTemplate}: - localError(c.config, def.info, errCannotAssignMacroSymbol % [ - if def.sym.kind == skMacro: "macro" else: "template", - def.sym.name.s, a[0].ident.s]) - def.typ = errorType(c) + + if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}: + typFlags.incl taIsTemplateOrMacro elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: - # prevent the all too common 'const x = int' bug: - localError(c.config, def.info, errInvalidTypeDescAssign) - def.typ = errorType(c) + typFlags.incl taProcContextIsNotMacro # check type compatibility between def.typ and typ: if typ != nil: @@ -670,9 +666,10 @@ proc semConst(c: PContext, n: PNode): PNode = if def == nil: localError(c.config, a[^1].info, errConstExprExpected) continue - if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: - localError(c.config, a.info, "invalid type for const: " & typeToString(typ)) - continue + if def.kind != nkNilLit: + if c.matchedConcept != nil: + typFlags.incl taConcept + typeAllowedCheck(c.config, a.info, typ, skConst, typFlags) var b: PNode if a.kind == nkVarTuple: diff --git a/compiler/types.nim b/compiler/types.nim index 709e5bb2e..e1b283f87 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1246,6 +1246,8 @@ type taConcept, taIsOpenArray, taNoUntyped + taIsTemplateOrMacro + taProcContextIsNotMacro TTypeAllowedFlags* = set[TTypeAllowedFlag] @@ -1307,18 +1309,24 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if kind notin {skParam, skResult}: result = t else: result = typeAllowedAux(marker, t2, kind, flags) of tyProc: - if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}: - # only closure iterators my be assigned to anything. + if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags: result = t - let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags - for i in 1.. Date: Fri, 29 May 2020 12:08:17 +0200 Subject: [PATCH 0604/4254] more checking for --gc:arc, no need for valgrind (#14467) * sigmatch: removed dead code --- compiler/cgen.nim | 3 +- compiler/dfa.nim | 5 ++- compiler/injectdestructors.nim | 2 + compiler/sigmatch.nim | 6 ++- lib/system/bitmasks.nim | 30 ++++++++++++++ lib/system/cellseqs_v1.nim | 43 ++++++++++++++++++++ lib/system/cellsets.nim | 70 ++++++++++++--------------------- lib/system/cyclebreaker.nim | 1 - lib/system/cyclicrefs_bacon.nim | 1 - lib/system/mmdisp.nim | 25 ++---------- lib/system/refs_v2.nim | 45 ++++++++++++++++++++- lib/system/seqs_v2.nim | 1 - 12 files changed, 159 insertions(+), 73 deletions(-) create mode 100644 lib/system/bitmasks.nim create mode 100644 lib/system/cellseqs_v1.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 8fa824fcc..338b337f2 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2067,7 +2067,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = let disp = generateMethodDispatchers(graph) for x in disp: genProcAux(m, x.sym) - m.g.modulesClosed.add m + let mm = m + m.g.modulesClosed.add mm proc genForwardedProcs(g: BModuleList) = # Forward declared proc:s lack bodies when first encountered, so they're given diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 67a9e26d8..a0ec31ac6 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -809,4 +809,7 @@ proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = withBlock(s): gen(c, body) genImplicitReturn(c) - shallowCopy(result, c.code) + when defined(gcArc) or defined(gcOrc): + result = c.code # will move + else: + shallowCopy(result, c.code) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 5785df6d6..9cb777f2c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -354,6 +354,8 @@ proc genWasMoved(n: PNode; c: var Con): PNode = result = newNodeI(nkCall, n.info) result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved))) result.add copyTree(n) #mWasMoved does not take the address + #if n.kind != nkSym: + # message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")") proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = result = newNodeI(nkCall, info) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 401d160fa..e99269c41 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -993,6 +993,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNone assert(f != nil) + when declared(deallocatedRefId): + let corrupt = deallocatedRefId(cast[pointer](f)) + if corrupt != 0: + quit "it's corrupt " & $corrupt + if f.kind == tyUntyped: if aOrig != nil: put(c, f, aOrig) return isGeneric @@ -1409,7 +1414,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let roota = a.skipGenericAlias let rootf = f.skipGenericAlias - var m = c if a.kind == tyGenericInst: if roota.base == rootf.base: let nextFlags = flags + {trNoCovariance} diff --git a/lib/system/bitmasks.nim b/lib/system/bitmasks.nim new file mode 100644 index 000000000..922ad5fb7 --- /dev/null +++ b/lib/system/bitmasks.nim @@ -0,0 +1,30 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Page size of the system; in most cases 4096 bytes. For exotic OS or +# CPU this needs to be changed: +const + PageShift = when defined(cpu16): 8 else: 12 # \ + # my tests showed no improvements for using larger page sizes. + PageSize = 1 shl PageShift + PageMask = PageSize-1 + + MemAlign = 16 # also minimal allocatable memory block + + BitsPerPage = PageSize div MemAlign + UnitsPerPage = BitsPerPage div (sizeof(int)*8) + # how many ints do we need to describe a page: + # on 32 bit systems this is only 16 (!) + + TrunkShift = 9 + BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64 + TrunkMask = BitsPerTrunk - 1 + IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8) + IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width + IntMask = 1 shl IntShift - 1 diff --git a/lib/system/cellseqs_v1.nim b/lib/system/cellseqs_v1.nim new file mode 100644 index 000000000..1952491b3 --- /dev/null +++ b/lib/system/cellseqs_v1.nim @@ -0,0 +1,43 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2019 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# ------------------- cell seq handling --------------------------------------- + +type + PCellArray = ptr UncheckedArray[PCell] + CellSeq {.final, pure.} = object + len, cap: int + d: PCellArray + +proc contains(s: CellSeq, c: PCell): bool {.inline.} = + for i in 0 .. s.len-1: + if s.d[i] == c: return true + return false + +proc add(s: var CellSeq, c: PCell) {.inline.} = + if s.len >= s.cap: + s.cap = s.cap * 3 div 2 + var d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) + copyMem(d, s.d, s.len * sizeof(PCell)) + dealloc(s.d) + s.d = d + # XXX: realloc? + s.d[s.len] = c + inc(s.len) + +proc init(s: var CellSeq, cap: int = 1024) = + s.len = 0 + s.cap = cap + s.d = cast[PCellArray](alloc0(cap * sizeof(PCell))) + +proc deinit(s: var CellSeq) = + dealloc(s.d) + s.d = nil + s.len = 0 + s.cap = 0 diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index c73c84f52..ea00176b5 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -9,20 +9,28 @@ # Efficient set of pointers for the GC (and repr) +when defined(gcOrc) or defined(gcArc): + type + PCell = Cell + + include bitmasks + +else: + type + RefCount = int + + Cell {.pure.} = object + refcount: RefCount # the refcount and some flags + typ: PNimType + when trackAllocationSource: + filename: cstring + line: int + when useCellIds: + id: int + + PCell = ptr Cell + type - RefCount = int - - Cell {.pure.} = object - refcount: RefCount # the refcount and some flags - typ: PNimType - when trackAllocationSource: - filename: cstring - line: int - when useCellIds: - id: int - - PCell = ptr Cell - PPageDesc = ptr PageDesc BitIndex = range[0..UnitsPerPage-1] PageDesc {.final, pure.} = object @@ -35,39 +43,11 @@ type counter, max: int head: PPageDesc data: PPageDescArray - PCellArray = ptr UncheckedArray[PCell] - CellSeq {.final, pure.} = object - len, cap: int - d: PCellArray -# ------------------- cell seq handling --------------------------------------- - -proc contains(s: CellSeq, c: PCell): bool {.inline.} = - for i in 0 .. s.len-1: - if s.d[i] == c: return true - return false - -proc add(s: var CellSeq, c: PCell) {.inline.} = - if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - var d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) - copyMem(d, s.d, s.len * sizeof(PCell)) - dealloc(s.d) - s.d = d - # XXX: realloc? - s.d[s.len] = c - inc(s.len) - -proc init(s: var CellSeq, cap: int = 1024) = - s.len = 0 - s.cap = cap - s.d = cast[PCellArray](alloc0(cap * sizeof(PCell))) - -proc deinit(s: var CellSeq) = - dealloc(s.d) - s.d = nil - s.len = 0 - s.cap = 0 +when defined(gcOrc) or defined(gcArc): + discard +else: + include cellseqs_v1 # ------------------- cell set handling --------------------------------------- diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim index 4b7f8db5a..3d01eeb9d 100644 --- a/lib/system/cyclebreaker.nim +++ b/lib/system/cyclebreaker.nim @@ -60,7 +60,6 @@ const colGreen = 0b000 colYellow = 0b001 colRed = 0b010 - rcShift = 3 # shift by rcShift to get the reference counter colorMask = 0b011 type diff --git a/lib/system/cyclicrefs_bacon.nim b/lib/system/cyclicrefs_bacon.nim index 5f0197384..b9c820e4a 100644 --- a/lib/system/cyclicrefs_bacon.nim +++ b/lib/system/cyclicrefs_bacon.nim @@ -24,7 +24,6 @@ const colPurple = 0b011 isCycleCandidate = 0b100 # cell is marked as a cycle candidate jumpStackFlag = 0b1000 - rcShift = 4 # shift by rcShift to get the reference counter colorMask = 0b011 type diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 5cdac2991..5fe1960d1 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -38,27 +38,10 @@ type PByte = ptr ByteArray PString = ptr string -# Page size of the system; in most cases 4096 bytes. For exotic OS or -# CPU this needs to be changed: -const - PageShift = when defined(cpu16): 8 else: 12 # \ - # my tests showed no improvements for using larger page sizes. - PageSize = 1 shl PageShift - PageMask = PageSize-1 - - MemAlign = 16 # also minimal allocatable memory block - - BitsPerPage = PageSize div MemAlign - UnitsPerPage = BitsPerPage div (sizeof(int)*8) - # how many ints do we need to describe a page: - # on 32 bit systems this is only 16 (!) - - TrunkShift = 9 - BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64 - TrunkMask = BitsPerTrunk - 1 - IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8) - IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width - IntMask = 1 shl IntShift - 1 +when declared(IntsPerTrunk): + discard +else: + include bitmasks proc raiseOutOfMem() {.noinline.} = if outOfMemHook != nil: outOfMemHook() diff --git a/lib/system/refs_v2.nim b/lib/system/refs_v2.nim index 8e5e03d3d..df1248586 100644 --- a/lib/system/refs_v2.nim +++ b/lib/system/refs_v2.nim @@ -38,11 +38,13 @@ when defined(gcOrc): const rcIncrement = 0b10000 # so that lowest 4 bits are not touched rcMask = 0b1111 + rcShift = 4 # shift by rcShift to get the reference counter else: const rcIncrement = 0b1000 # so that lowest 3 bits are not touched rcMask = 0b111 + rcShift = 3 # shift by rcShift to get the reference counter type RefHeader = object @@ -52,6 +54,8 @@ type when defined(gcOrc): rootIdx: int # thanks to this we can delete potential cycle roots # in O(1) without doubly linked lists + when defined(nimArcDebug): + refId: int Cell = ptr RefHeader @@ -67,6 +71,14 @@ template head(p: pointer): Cell = const traceCollector = defined(traceArc) +when defined(nimArcDebug): + include cellsets + + const traceId = 7739 # 1037 + + var gRefId: int + var freedCells: CellSet + proc nimNewObj(size: int): pointer {.compilerRtl.} = let s = size + sizeof(RefHeader) when defined(nimscript): @@ -79,6 +91,9 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = result = allocShared0(s) +! sizeof(RefHeader) else: result = alloc0(s) +! sizeof(RefHeader) + when defined(nimArcDebug): + head(result).refId = gRefId + atomicInc gRefId when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) @@ -98,6 +113,9 @@ proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = when defined(gcOrc): orig.rootIdx = 0 result = orig +! sizeof(RefHeader) + when defined(nimArcDebug): + head(result).refId = gRefId + atomicInc gRefId when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) @@ -105,10 +123,25 @@ proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = dec head(p).rc, rcIncrement proc nimIncRef(p: pointer) {.compilerRtl, inl.} = + when defined(nimArcDebug): + if head(p).refId == traceId: + writeStackTrace() + cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).rc shr rcShift) + inc head(p).rc, rcIncrement when traceCollector: cprintf("[INCREF] %p\n", head(p)) +when not defined(nimscript) and defined(nimArcDebug): + proc deallocatedRefId*(p: pointer): int = + ## Returns the ref's ID if the ref was already deallocated. This + ## is a memory corruption check. Returns 0 if there is no error. + let c = head(p) + if freedCells.data != nil and freedCells.contains(c): + result = c.refId + else: + result = 0 + proc nimRawDispose(p: pointer) {.compilerRtl.} = when not defined(nimscript): when traceCollector: @@ -117,7 +150,11 @@ proc nimRawDispose(p: pointer) {.compilerRtl.} = if head(p).rc >= rcIncrement: cstderr.rawWrite "[FATAL] dangling references exist\n" quit 1 - when defined(useMalloc): + when defined(nimArcDebug): + # we do NOT really free the memory here in order to reliably detect use-after-frees + if freedCells.data == nil: init(freedCells) + freedCells.incl head(p) + elif defined(useMalloc): c_free(p -! sizeof(RefHeader)) elif compileOption("threads"): deallocShared(p -! sizeof(RefHeader)) @@ -150,6 +187,12 @@ when defined(gcOrc): proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = if p != nil: var cell = head(p) + + when defined(nimArcDebug): + if cell.refId == traceId: + writeStackTrace() + cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.rc shr rcShift) + if (cell.rc and not rcMask) == 0: result = true when traceCollector: diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 175056f48..1b40c00ab 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -15,7 +15,6 @@ proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".} ## Default seq implementation used by Nim's core. type - NimSeqPayloadBase = object cap: int From e646c16e06e95855a92c1d2453f6f927555aed7e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 29 May 2020 05:30:36 -0700 Subject: [PATCH 0605/4254] hotfix doc comments for procs without body (#14494) --- compiler/docgen.nim | 1 + lib/system/io.nim | 5 -- nimdoc/testproject/expected/testproject.html | 48 ++++++++++++++++++++ nimdoc/testproject/expected/testproject.idx | 4 ++ nimdoc/testproject/expected/theindex.html | 16 +++++++ nimdoc/testproject/testproject.nim | 30 ++++++++++++ 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f2dec41b3..ffafb1fcb 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -642,6 +642,7 @@ proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var Rope) = var state = rsStart template fn(n2) = state = getAllRunnableExamplesImpl(d, n2, dest, state) + dest.add genComment(d, n).rope case n.kind of routineDefs: n = n.getRoutineBody diff --git a/lib/system/io.nim b/lib/system/io.nim index 84bebba28..b1f6bb61b 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -501,11 +501,6 @@ proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} = else: result = readAllBuffer(file).TaintedString -proc writeLn[Ty](f: File, x: varargs[Ty, `$`]) = - for i in items(x): - write(f, i) - write(f, "\n") - proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, tags: [WriteIOEffect], benign.} = ## writes the values `x` to `f` and then writes "\\n". diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index b8d252cfb..4fd5d8ad3 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -190,6 +190,14 @@ function main() { title="p1()">p1
  • addfBug14485
  • +
  • c_printf
  • +
  • c_nonexistant
  • +
  • low
  • +
  • low2
  • @@ -546,6 +554,46 @@ Some proc 7: end of broken html ]#
    + + +
    proc c_printf(frmt: cstring): cint {...}{.importc: "printf", header: "<stdio.h>", varargs,
    +                                 discardable.}
    +
    + +the c printf. etc. + +
    + +
    proc c_nonexistant(frmt: cstring): cint {...}{.importc: "nonexistant", header: "<stdio.h>",
    +                                      varargs, discardable.}
    +
    + + + +
    + +
    proc low[T: Ordinal | enum | range](x: T): T {...}{.magic: "Low", noSideEffect.}
    +
    + +

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    +

    See also:

    + +
    low(2) # => -9223372036854775808
    + +
    + +
    proc low2[T: Ordinal | enum | range](x: T): T {...}{.magic: "Low", noSideEffect.}
    +
    + +

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    +

    See also:

    + +
    low2(2) # => -9223372036854775808
    +

    Example:

    +
    discard "in low2"
    +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 447e9ff59..dd26c03d9 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -33,6 +33,10 @@ baz testproject.html#baz testproject: baz() z17 testproject.html#z17 testproject: z17() p1 testproject.html#p1 testproject: p1() addfBug14485 testproject.html#addfBug14485 testproject: addfBug14485() +c_printf testproject.html#c_printf,cstring testproject: c_printf(frmt: cstring): cint +c_nonexistant testproject.html#c_nonexistant,cstring testproject: c_nonexistant(frmt: cstring): cint +low testproject.html#low,T testproject: low[T: Ordinal | enum | range](x: T): T +low2 testproject.html#low2,T testproject: low2[T: Ordinal | enum | range](x: T): T bar testproject.html#bar.m testproject: bar(): untyped z16 testproject.html#z16.m testproject: z16() z18 testproject.html#z18.m testproject: z18(): int diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 3ecf7aab7..1e9e4374f 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -129,6 +129,14 @@ function main() {
  • testproject: C_D
  • +
    c_nonexistant:
    +
    c_printf:
    enumValueA:
    +
    low:
    +
    low2:
    myfn:
    • testproject: myfn()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 90b173403..45bbca223 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -177,6 +177,36 @@ when true: # issue #14485 7: end of broken html ]# +when true: # procs without `=` (using comment field) + proc c_printf*(frmt: cstring): cint {.importc: "printf", header: "", varargs, discardable.} + ## the c printf. + ## etc. + + proc c_nonexistant*(frmt: cstring): cint {.importc: "nonexistant", header: "", varargs, discardable.} + +when true: # tests RST inside comments + proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect.} + ## Returns the lowest possible value of an ordinal value `x`. As a special + ## semantic rule, `x` may also be a type identifier. + ## + ## See also: + ## * `low2(T) <#low2,T>`_ + ## + ## .. code-block:: Nim + ## low(2) # => -9223372036854775808 + + proc low2*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect.} = + ## Returns the lowest possible value of an ordinal value `x`. As a special + ## semantic rule, `x` may also be a type identifier. + ## + ## See also: + ## * `low(T) <#low,T>`_ + ## + ## .. code-block:: Nim + ## low2(2) # => -9223372036854775808 + runnableExamples: + discard "in low2" + when true: # (most) macros macro bar*(): untyped = result = newStmtList() From 63d1a0289e872212e836559f92a785df51f4faac Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 29 May 2020 08:10:59 -0700 Subject: [PATCH 0606/4254] fix #14421 items uses lent T (#14447) * fix #14421 items uses lent T for seq + openArray * add -d:nimWorkaround14447 * fix test --- compiler/condsyms.nim | 1 + compiler/lambdalifting.nim | 3 ++- lib/system/iterators.nim | 31 ++++++++++++++++++++++--- testament/important_packages.nim | 4 ++-- tests/destructor/tbintree2.nim | 2 +- tests/destructor/tgcdestructors.nim | 2 +- tests/destructor/tnewruntime_misc.nim | 2 +- tests/destructor/towned_binary_tree.nim | 2 +- tests/destructor/tsimpleclosure.nim | 2 +- tests/destructor/tv2_raise.nim | 2 +- tests/destructor/twidgets_unown.nim | 2 +- 11 files changed, 40 insertions(+), 13 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 7b05faa87..b7f7100f1 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -118,3 +118,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasInvariant") defineSymbol("nimHasStacktraceMsgs") defineSymbol("nimDoesntTrackDefects") + defineSymbol("nimHasLentIterators") diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index fc1ad5e40..c1cd07583 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -291,7 +291,8 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = if illegalCapture(s): localError(g.config, n.info, ("'$1' is of type <$2> which cannot be captured as it would violate memory" & - " safety, declared here: $3") % [s.name.s, typeToString(s.typ), g.config$s.info]) + " safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") % + [s.name.s, typeToString(s.typ), g.config$s.info]) elif owner.typ.callConv notin {ccClosure, ccDefault}: localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 53b287db0..5d8685e40 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -1,7 +1,32 @@ -iterator items*[T](a: openArray[T]): T {.inline.} = +when defined(nimHasLentIterators) and not defined(nimWorkaround14447): + template lent2(T): untyped = + # xxx this should actually depend on T.sizeof >= thresLentSizeof + # with for example `thresLentSizeof ~= int.sizeof`: + # it may be faster to return by value for small sizes compared to + # forcing a deref; this could be adjusted using profiling. + # However, `simply using `when T.sizeof >= thresLentSizeof: lent T else: T` + # does not work, for a few reasons (eg importc types would cause CT error + # and we can't filter them out without compiles() or some magic. + lent T +else: + template lent2(T): untyped = T + +iterator items*[T: not char](a: openArray[T]): lent2 T {.inline.} = ## Iterates over each item of `a`. var i = 0 - while i < len(a): + let n = len(a) + while i < n: + yield a[i] + inc(i) + +iterator items*[T: char](a: openArray[T]): T {.inline.} = + ## Iterates over each item of `a`. + # a VM bug currently prevents taking address of openArray[char] + # elements converted from a string (would fail in `tests/misc/thallo.nim`) + # in any case there's no performance advantage of returning char by address. + var i = 0 + let n = len(a) + while i < n: yield a[i] inc(i) @@ -179,7 +204,7 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = yield (i, a[i]) inc(i) -iterator items*[T](a: seq[T]): T {.inline.} = +iterator items*[T](a: seq[T]): lent2 T {.inline.} = ## Iterates over each item of `a`. var i = 0 let L = len(a) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 1d3b1917c..cb436bfb2 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -43,7 +43,7 @@ pkg1 "elvis" pkg1 "fidget", true, "nim c -d:release -r tests/runNative.nim" pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" -pkg1 "ggplotnim", true, "nim c -d:noCairo -r tests/tests.nim" +pkg1 "ggplotnim", true, "nim c -d:noCairo -r -d:nimWorkaround14447 tests/tests.nim" # pkg1 "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" pkg1 "glob" pkg1 "gnuplot" @@ -134,4 +134,4 @@ pkg2 "websocket", false, "nim c websocket.nim" pkg2 "with" pkg2 "ws" pkg2 "yaml" -pkg2 "zero_functional", false, "nim c -r test.nim" +pkg2 "zero_functional", false, "nim c -r -d:nimWorkaround14447 test.nim" diff --git a/tests/destructor/tbintree2.nim b/tests/destructor/tbintree2.nim index e910f430a..6fdda6e54 100644 --- a/tests/destructor/tbintree2.nim +++ b/tests/destructor/tbintree2.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''0 -(allocCount: 6, deallocCount: 6)''' +(allocCount: 5, deallocCount: 5)''' """ import system / ansi_c diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index 61d296d2e..4731bf694 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -10,7 +10,7 @@ a: @[4, 2, 3] 0 30 true -(allocCount: 36, deallocCount: 36)''' +(allocCount: 27, deallocCount: 27)''' """ include system / ansi_c diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index f6e2a6157..1a5b0e3b0 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -7,7 +7,7 @@ axc ... destroying GenericObj[T] GenericObj[system.int] test -(allocCount: 17, deallocCount: 15) +(allocCount: 13, deallocCount: 11) 3''' """ diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim index 72f7cae0c..320e33759 100644 --- a/tests/destructor/towned_binary_tree.nim +++ b/tests/destructor/towned_binary_tree.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''31665 -(allocCount: 33335, deallocCount: 33335)''' +(allocCount: 33334, deallocCount: 33334)''' """ # bug #11053 diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim index 4916f4bab..35c57a634 100644 --- a/tests/destructor/tsimpleclosure.nim +++ b/tests/destructor/tsimpleclosure.nim @@ -5,7 +5,7 @@ discard """ hello hello hello -(allocCount: 4, deallocCount: 4)''' +(allocCount: 3, deallocCount: 3)''' """ import system / ansi_c diff --git a/tests/destructor/tv2_raise.nim b/tests/destructor/tv2_raise.nim index 4ea94a864..66b0aec30 100644 --- a/tests/destructor/tv2_raise.nim +++ b/tests/destructor/tv2_raise.nim @@ -2,7 +2,7 @@ discard """ valgrind: true cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''OK 3 -(allocCount: 8, deallocCount: 5)''' +(allocCount: 7, deallocCount: 4)''' """ import strutils, math diff --git a/tests/destructor/twidgets_unown.nim b/tests/destructor/twidgets_unown.nim index 3a3c4c665..8653d5c28 100644 --- a/tests/destructor/twidgets_unown.nim +++ b/tests/destructor/twidgets_unown.nim @@ -2,7 +2,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''button clicked! -(allocCount: 7, deallocCount: 7)''' +(allocCount: 6, deallocCount: 6)''' """ import system / ansi_c From cb6eb5268fffea891501c0aed7510d7354c16159 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 29 May 2020 13:11:41 -0700 Subject: [PATCH 0607/4254] enable compiler docs with their own index+search (#14493) * enable compiler docs (with its own index) --- tools/kochdocs.nim | 47 ++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index bedfcda4a..c39a9c448 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -5,8 +5,7 @@ import "../compiler/nimpaths" const gaCode* = " --doc.googleAnalytics:UA-48159761-1" - # --warning[LockLevel]:off pending #13218 - nimArgs = "--warning[LockLevel]:off --hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot --putenv:nimversion=$#" % system.NimVersion + nimArgs = "--hint:Conf:off --hint:Path:off --hint:Processing:off -d:boot --putenv:nimversion=$#" % system.NimVersion gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" webUploadOutput = "web/upload" @@ -231,6 +230,15 @@ proc buildDocSamples(nimArgs, destPath: string) = exec(findNim().quoteShell() & " doc $# -o:$# $#" % [nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) +proc buildDocPackages(nimArgs, destPath: string) = + # compiler docs, and later, other packages (perhaps tools, testament etc) + let nim = findNim().quoteShell() + let extra = "-u:boot" + # to avoid broken links to manual from compiler dir, but a multi-package + # structure could be supported later + exec("$1 doc --project --outdir:$2/compiler $3 --git.url:$4 $5 compiler/nim.nim" % + [nim, destPath, nimArgs, gitUrl, extra]) + proc buildDoc(nimArgs, destPath: string) = # call nim for the documentation: var @@ -249,8 +257,7 @@ proc buildDoc(nimArgs, destPath: string) = i.inc for d in items(doc): var nimArgs2 = nimArgs - if d.isRelativeTo("compiler"): - nimArgs2.add " --docroot" + if d.isRelativeTo("compiler"): doAssert false commands[i] = nim & " doc $# --git.url:$# --outdir:$# --index:on $#" % [nimArgs2, gitUrl, destPath, d] i.inc @@ -262,6 +269,11 @@ proc buildDoc(nimArgs, destPath: string) = mexec(commands) exec(nim & " buildIndex -o:$1/theindex.html $1" % [destPath]) + # caveat: this works so long it's called before `buildDocPackages` which + # populates `compiler/` with unrelated idx files that shouldn't be in index, + # so should work in CI but you may need to remove your generated html files + # locally after calling `./koch docs`. The clean fix would be for `idx` files + # to be transient with `--project` (eg all in memory). proc buildPdfDoc*(nimArgs, destPath: string) = createDir(destPath) @@ -296,20 +308,15 @@ proc buildJS(): string = result = getDocHacksJs(nimr = getCurrentDir(), nim) proc buildDocs*(args: string) = - let - a = nimArgs & " " & args - docHackJsSource = buildJS() - docHackJs = docHackJsSource.lastPathPart + let docHackJsSource = buildJS() + template fn(args, dir) = + let dir2 = dir + let args2 = args + createDir(dir2) + buildDocSamples(args2, dir2) + buildDoc(args2, dir2) + buildDocPackages(args2, dir2) + copyFile(docHackJsSource, dir2 / docHackJsSource.lastPathPart) - let docup = webUploadOutput / NimVersion - createDir(docup) - buildDocSamples(a, docup) - buildDoc(a, docup) - - # 'nimArgs' instead of 'a' is correct here because we don't want - # that the offline docs contain the 'gaCode'! - createDir(docHtmlOutput) - buildDocSamples(nimArgs, docHtmlOutput) - buildDoc(nimArgs, docHtmlOutput) - copyFile(docHackJsSource, docHtmlOutput / docHackJs) - copyFile(docHackJsSource, docup / docHackJs) + fn(nimArgs & " " & args, webUploadOutput / NimVersion) + fn(nimArgs, docHtmlOutput) # no `args` to avoid offline docs containing the 'gaCode'! From 3105909f887f2240c2a7a7071b37e1253a70e3e2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 29 May 2020 23:35:57 +0200 Subject: [PATCH 0608/4254] fixes #14495 [backport:1.2] (#14496) --- compiler/liftdestructors.nim | 8 +++--- tests/arc/tarcmisc.nim | 48 ++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 5faba79f9..2d8655cae 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -534,8 +534,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) of attachedDestructor: - actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: if isFinal(elemType): @@ -583,8 +583,8 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) of attachedDestructor: - actions.add newAsgnStmt(xenv, newNodeIT(nkNilLit, body.info, xenv.typ)) body.add genIf(c, cond, actions) + body.add newAsgnStmt(xenv, newNodeIT(nkNilLit, body.info, xenv.typ)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv), y) @@ -641,8 +641,8 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, x, actions) body.add newAsgnStmt(x, y) of attachedDestructor: - actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) body.add genIf(c, x, actions) + body.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace, attachedDispose: discard @@ -694,8 +694,8 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, actions) body.add newAsgnStmt(x, y) of attachedDestructor: - actions.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ)) body.add genIf(c, xx, actions) + body.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace, attachedDispose: discard diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 24f02959c..898efd138 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -4,6 +4,17 @@ discard """ destroyed: false destroyed: false 1 +(x: "0") +(x: "1") +(x: "2") +(x: "3") +(x: "4") +(x: "5") +(x: "6") +(x: "7") +(x: "8") +(x: "9") +(x: "10") closed destroying variable ''' @@ -99,10 +110,10 @@ type MyType = object a: seq[int] -proc re(x: static[string]): static MyType = +proc re(x: static[string]): static MyType = MyType() -proc match(inp: string, rg: static MyType) = +proc match(inp: string, rg: static MyType) = doAssert rg.a.len == 0 match("ac", re"a(b|c)") @@ -125,13 +136,40 @@ var game*: Game #------------------------------------------------------------------------------ # issue #14333 -type +type SimpleLoop = object - + Lsg = object loops: seq[ref SimpleLoop] root: ref SimpleLoop var lsg: Lsg lsg.loops.add lsg.root -echo lsg.loops.len \ No newline at end of file +echo lsg.loops.len + +# bug #14495 +type + Gah = ref object + x: string + +proc bug14495 = + var owners: seq[Gah] + for i in 0..10: + owners.add Gah(x: $i) + + var x: seq[Gah] + for i in 0..10: + x.add owners[i] + + for i in 0..100: + setLen(x, 0) + setLen(x, 10) + + for i in 0..x.len-1: + if x[i] != nil: + echo x[i][] + + for o in owners: + echo o[] + +bug14495() From 7ccc7d7e93e0fdfcf72aed239cf8b5d4c04e7de5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 30 May 2020 15:32:31 +0200 Subject: [PATCH 0609/4254] fixes #14498 [backport:1.2] (#14503) --- compiler/parampatterns.nim | 12 +++++++++--- compiler/semexprs.nim | 2 +- tests/lent/tnot_allowed_lent.nim | 4 ++-- tests/lent/tnot_allowed_lent2.nim | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 tests/lent/tnot_allowed_lent2.nim diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 486f8ff54..33881a7b3 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -176,6 +176,7 @@ type arLocalLValue, # is an l-value, but local var; must not escape # its stack frame! arDiscriminant, # is a discriminant + arLentValue, # lent value arStrange # it is a strange beast like 'typedesc[var T]' proc exprRoot*(n: PNode): PSym = @@ -260,9 +261,14 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult # types that are equal modulo distinction preserve l-value: result = isAssignable(owner, n[1], isUnsafeAddr) of nkHiddenDeref: - if isUnsafeAddr and n[0].typ.kind == tyLent: result = arLValue - elif n[0].typ.kind == tyLent: result = arDiscriminant - else: result = arLValue + let n0 = n[0] + if n0.typ.kind == tyLent: + if isUnsafeAddr or (n0.kind == nkSym and n0.sym.kind == skResult): + result = arLValue + else: + result = arLentValue + else: + result = arLValue of nkDerefExpr, nkHiddenAddr: result = arLValue of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e29101385..c5b864d1f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1712,7 +1712,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if le == nil: localError(c.config, a.info, "expression has no type") elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and - isAssignable(c, a) == arNone) or + isAssignable(c, a) in {arNone, arLentValue}) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! localError(c.config, a.info, errXCannotBeAssignedTo % diff --git a/tests/lent/tnot_allowed_lent.nim b/tests/lent/tnot_allowed_lent.nim index b144ce36b..2de18d4af 100644 --- a/tests/lent/tnot_allowed_lent.nim +++ b/tests/lent/tnot_allowed_lent.nim @@ -7,10 +7,10 @@ type proc mytest1(s: MyObject, i: int): lent string = ## works fine - if i < s.x.len - 1 and s.x[i] != "": + if i < s.x.len - 1 and s.x[i] != "": result = s.x[i] else: raise newException(KeyError, "err1") - + proc mytest2(s: MyObject, i: int): lent string = ## reject due to if expr if i < s.x.len - 1 and s.x[i] != "": s.x[i] diff --git a/tests/lent/tnot_allowed_lent2.nim b/tests/lent/tnot_allowed_lent2.nim new file mode 100644 index 000000000..e61cae922 --- /dev/null +++ b/tests/lent/tnot_allowed_lent2.nim @@ -0,0 +1,14 @@ +discard """ + errmsg: "'x' cannot be assigned to" + line: 10 +""" + +proc bug14498 = + var a = @['a', 'b', 'c', 'd', 'e', 'f'] + + for x in a: + x = 'c' + + echo a + +bug14498() From 52c3633223005f70bb4ecffa9f86b2e4e845e4a3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 30 May 2020 19:38:51 +0200 Subject: [PATCH 0610/4254] warn about observerable stores but don't prevent them for 1.2.2 [backport:1.2]; refs https://github.com/nim-lang/RFCs/issues/230 (#14510) --- compiler/ccgcalls.nim | 5 +++-- compiler/lineinfos.nim | 8 ++++++-- tests/ccgbugs/tcodegenbug1.nim | 10 ++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 8f9d879df..e19e96503 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -43,8 +43,9 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool = for i in 1.. 0 or locationEscapes(p, le)) + if canRaiseDisp(p, ri[0]) and + (p.nestedTryStmts.len > 0 or locationEscapes(p, le)): + message(p.config, le.info, warnObservableStores, $le) proc hasNoInit(call: PNode): bool {.inline.} = result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index bb47e947f..bc3c51d53 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -52,7 +52,9 @@ type warnProveInit, warnProveField, warnProveIndex, warnUnreachableElse, warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, - warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser, + warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, + warnObservableStores, + warnUser, hintSuccess, hintSuccessX, hintCC, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, @@ -119,6 +121,7 @@ const warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", warnCaseTransition: "Potential object case transition, instantiate new object instead", warnCycleCreated: "$1", + warnObservableStores: "observable stores to '$1'", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` @@ -169,7 +172,8 @@ const "ProveInit", "ProveField", "ProveIndex", "UnreachableElse", "IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "ResultShadowed", - "Spacing", "CaseTransition", "CycleCreated", "User"] + "Spacing", "CaseTransition", "CycleCreated", + "ObservableStores", "User"] HintsToStr* = [ "Success", "SuccessX", "CC", "LineTooLong", diff --git a/tests/ccgbugs/tcodegenbug1.nim b/tests/ccgbugs/tcodegenbug1.nim index 11846ff95..c62bae1ef 100644 --- a/tests/ccgbugs/tcodegenbug1.nim +++ b/tests/ccgbugs/tcodegenbug1.nim @@ -4,9 +4,9 @@ obj.inner.id = 7 id = 7 obj = (inner: (kind: Just, id: 7)) 2 -(a: "1", b: "2", c: "3") +(a: "a", b: "b", c: "") caught -(a: "1", b: "", c: "3")''' +(a: "a", b: "b", c: "")''' """ # bug #6960 @@ -164,7 +164,8 @@ proc ohmanNoNRVO = discard echo x - doAssert x.c == "3", "shouldn't modify x if f raises" + # once NVRO is sorted out, x.c == "3" + doAssert x.c == "", "shouldn't modify x if f raises" ohmanNoNRVO() @@ -179,4 +180,5 @@ try: except: echo "caught" echo xgg -doAssert xgg.c == "3", "this assert will fail" +# once NVRO is sorted out, xgg.c == "3" +doAssert xgg.c == "", "this assert will fail" From 984af3d64e875016cf00dd2580b0b51f192e1fcd Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 25 May 2020 15:46:55 +0200 Subject: [PATCH 0611/4254] document NVRO and exception handling --- doc/manual.rst | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index 1472dd4e6..2b9c2b65c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3711,6 +3711,71 @@ location is derived from the second parameter (called ``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``. +NRVO +---- + +The return value is represented inside the body of a routine as the special +`result`:idx: variable. This allows for a mechanism much like C++'s +"named return value optimization" (`NRVO`:idx:). NRVO means that the stores +to ``result`` inside ``p`` directly affect the destination ``dest`` +in ``let/var dest = p(args)`` (definition of ``dest``) and also in ``dest = p(args)`` +(assignment to ``dest``). This is achieved by rewriting ``dest = p(args)`` +to ``p'(args, dest)`` where ``p'`` is a variation of ``p`` that returns ``void`` and +receives a hidden mutable parameter representing ``result``. + +Informally: + +.. code-block:: nim + proc p(): BigT = ... + + var x = p() + x = p() + + # is roughly turned into: + + proc p(result: var BigT) = ... + + var x; p(x) + p(x) + + +Let ``T``'s be ``p``'s return type. NRVO applies for ``T`` +if ``sizeof(T) >= N`` (where ``N`` is implementation dependent), +in other words, it applies for "big" structures. + +If ``p`` can raise an exception, NRVO applies regardless. This can produce +observable differences in behavior: + +.. code-block:: nim + + type + BigT = array[16, int] + + proc p(raiseAt: int): BigT = + for i in 0..high(result): + if i == raiseAt: raise newException(ValueError, "interception") + result[i] = i + + proc main = + var x: BigT + try: + x = p(8) + except ValueError: + doAssert x == [0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0] + + main() + + +However, the current implementation produces a warning in these cases. +There are different ways to deal with this warning: + +1. Disable the warning via ``{.push warning[ObservableStores]: off.}`` ... ``{.pop.}``. + Then one may need to ensure that ``p`` only raises *before* any stores to ``result`` + happen. + +2. One can use a temporary helper variable, for example instead of ``x = p(8)`` + use ``let tmp = p(8); x = tmp``. + Overloading of the subscript operator ------------------------------------- From 177c7f96e93c6b8d9d206cd13f22c0d0d7d4192e Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 30 May 2020 19:55:01 +0200 Subject: [PATCH 0612/4254] spec: be explicit that NRVO will evolve further --- doc/manual.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index 2b9c2b65c..f70c484a2 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3714,6 +3714,10 @@ location is derived from the second parameter (called NRVO ---- +**Note**: This section describes the current implementation. This part +of the language specification will be changed. +See https://github.com/nim-lang/RFCs/issues/230 for more information. + The return value is represented inside the body of a routine as the special `result`:idx: variable. This allows for a mechanism much like C++'s "named return value optimization" (`NRVO`:idx:). NRVO means that the stores From 5150186c68af1fbcc1185d815f52024c4647fe0b Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Sun, 31 May 2020 13:43:27 +0300 Subject: [PATCH 0613/4254] Disable unused warnings for await in async macro (#14517) * Disable unused warnings for await in async macro * Remove used for the error template --- lib/pure/asyncmacro.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index afc28bbdf..77db80bc6 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -267,7 +267,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = static: error "await expects Future[T], got " & $typeof(f) - template await[T](f: Future[T]): auto = + template await[T](f: Future[T]): auto {.used.} = var internalTmpFuture: FutureBase = f yield internalTmpFuture (cast[type(f)](internalTmpFuture)).read() @@ -355,4 +355,4 @@ macro multisync*(prc: untyped): untyped = # overload for await as a fallback handler, based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 # template await*(f: typed): untyped = # static: - # error "await only available within {.async.}" \ No newline at end of file + # error "await only available within {.async.}" From 004b0759c5743f4b50766a14b0a47477b72bbac9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 31 May 2020 14:57:16 -0700 Subject: [PATCH 0614/4254] fix CI doc windows: style error in lib/std/time_t.nim (#14523) --- lib/std/time_t.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim index 37918ee6c..5fd2752c7 100644 --- a/lib/std/time_t.nim +++ b/lib/std/time_t.nim @@ -9,8 +9,8 @@ when defined(nimdoc): type - impl = distinct int64 - Time* = impl ## \ + Impl = distinct int64 + Time* = Impl ## \ ## Wrapper for ``time_t``. On posix, this is an alias to ``posix.Time``. elif defined(windows): when defined(i386) and defined(gcc): From 5d0cf883c15b6bd348ecfe7865cb85ca05e341de Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 1 Jun 2020 12:56:07 +0300 Subject: [PATCH 0615/4254] Disable unused warnings for error await template too (#14531) --- lib/pure/asyncmacro.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 77db80bc6..cbed6372c 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -263,7 +263,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 # however here the overloads are placed inside each expanded async var awaitDefinition = quote: - template await(f: typed): untyped = + template await(f: typed): untyped {.used.} = static: error "await expects Future[T], got " & $typeof(f) From 8710395a0f7b57bab755ea826a82e3ceef85aa52 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 1 Jun 2020 12:33:13 +0200 Subject: [PATCH 0616/4254] fixes #14514 [backport:1.2] (#14533) --- compiler/ccgcalls.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index e19e96503..10f5ef638 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -43,7 +43,9 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool = for i in 1.. 0 or locationEscapes(p, le)): message(p.config, le.info, warnObservableStores, $le) From 0489e76da768502aa7bddea1cbab3bfa5f6b22a2 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Mon, 1 Jun 2020 14:02:17 +0200 Subject: [PATCH 0617/4254] manual: removed subjective phrase from 'macros' section (#14536) Removed phrase "However, this is no real restriction because Nim's syntax is flexible enough anyway." from the manual - I find it very subjective, and I sometimes *do* find myself restricted by Nim's syntax when writing DSLs --- doc/manual.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index f70c484a2..451359dca 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5305,8 +5305,7 @@ twice: this process iterates. While macros enable advanced compile-time code transformations, they -cannot change Nim's syntax. However, this is no real restriction because -Nim's syntax is flexible enough anyway. +cannot change Nim's syntax. Debug Example ------------- From 5900d8442c6bf41bfaab02ae877ebf23680680bb Mon Sep 17 00:00:00 2001 From: Khronos <39792509+Khronos31@users.noreply.github.com> Date: Mon, 1 Jun 2020 21:06:25 +0900 Subject: [PATCH 0618/4254] Fix a problem with extra build commands. (#14528) When --compileOnly is on, extraCmds are not added to JsonBuildInstructions. ``` $ echo 'echo 123'>test.nim $ nim c --debuginfo --nimcache:cache test $ ls cache test test.dSYM test.nim $ tail -n3 cache/test.json "extraCmds": ["dsymutil /Users/khronos31/src/tmp/test"], "stdinInput": false } ``` ``` $ echo 'echo 123'>test.nim $ nim c --debuginfo --nimcache:cache --compileOnly test $ nim jsonscript --nimcache:cache test $ ls cache test test.nim $ tail -n3 cache/test.json "extraCmds": [], "stdinInput": false } ``` --- compiler/extccomp.nim | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 4c5b195ab..7757a9f9d 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -767,19 +767,16 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body (ose.msg & " " & $ose.errorCode)) raise +proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] = + when defined(macosx): + if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions: + # if needed, add an option to skip or override location + result.add "dsymutil " & $(output).quoteShell + proc execLinkCmd(conf: ConfigRef; linkCmd: string) = tryExceptOSErrorMessage(conf, "invocation of external linker program failed."): execExternalProgram(conf, linkCmd, hintLinking) -proc maybeRunDsymutil(conf: ConfigRef; exe: AbsoluteFile) = - when defined(osx): - if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions: - # if needed, add an option to skip or override location - let cmd = "dsymutil " & $(exe).quoteShell - conf.extraCmds.add cmd - tryExceptOSErrorMessage(conf, "invocation of dsymutil failed."): - execExternalProgram(conf, cmd, hintExecuting) - proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) = let runCb = proc (idx: int, p: Process) = let exitCode = p.peekExitCode @@ -850,6 +847,7 @@ proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string = proc callCCompiler*(conf: ConfigRef) = var linkCmd: string + extraCmds: seq[string] if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: return # speed up that call if only compiling and no script shall be # generated @@ -920,6 +918,7 @@ proc callCCompiler*(conf: ConfigRef) = let mainOutput = if optGenScript notin conf.globalOptions: conf.prepareToWriteOutput else: AbsoluteFile(conf.projectName) linkCmd = getLinkCmd(conf, mainOutput, objfiles) + extraCmds = getExtraCmds(conf, mainOutput) if optCompileOnly notin conf.globalOptions: const MaxCmdLen = when defined(windows): 8_000 else: 32_000 if linkCmd.len > MaxCmdLen: @@ -929,7 +928,8 @@ proc callCCompiler*(conf: ConfigRef) = linkViaResponseFile(conf, linkCmd) else: execLinkCmd(conf, linkCmd) - maybeRunDsymutil(conf, mainOutput) + for cmd in extraCmds: + execExternalProgram(conf, cmd, hintExecuting) else: linkCmd = "" if optGenScript in conf.globalOptions: @@ -1017,7 +1017,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = str getLinkCmd(conf, conf.absOutFile, objfiles) lit ",\L\"extraCmds\": " - lit $(%* conf.extraCmds) + lit $(%* getExtraCmds(conf, conf.absOutFile)) lit ",\L\"stdinInput\": " lit $(%* conf.projectIsStdin) From 00ec43305e51c4b3c0fc4f288a775f90189a4a7c Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 1 Jun 2020 16:06:45 +0300 Subject: [PATCH 0619/4254] Fix `compiles` for nimsuggest [backport] (#14527) * Handle nimsuggest in tryExpr * Added test --- compiler/semexprs.nim | 7 +++++++ nimsuggest/tests/tchk_compiles.nim | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 nimsuggest/tests/tchk_compiles.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c5b864d1f..72d407cf7 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2062,6 +2062,10 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # watch out, hacks ahead: + when defined(nimsuggest): + # Remove the error hook so nimsuggest doesn't report errors there + let tempHook = c.graph.config.structuredErrorHook + c.graph.config.structuredErrorHook = nil let oldErrorCount = c.config.errorCounter let oldErrorMax = c.config.errorMax let oldCompilesId = c.compilesContextId @@ -2111,6 +2115,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = c.config.m.errorOutputs = oldErrorOutputs c.config.errorCounter = oldErrorCount c.config.errorMax = oldErrorMax + when defined(nimsuggest): + # Restore the error hook + c.graph.config.structuredErrorHook = tempHook proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = # we replace this node by a 'true' or 'false' node: diff --git a/nimsuggest/tests/tchk_compiles.nim b/nimsuggest/tests/tchk_compiles.nim new file mode 100644 index 000000000..887a947b5 --- /dev/null +++ b/nimsuggest/tests/tchk_compiles.nim @@ -0,0 +1,8 @@ +discard compiles(2 + "hello") + +#[!]# +discard """ +$nimsuggest --tester $file +>chk $1 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tchk_compiles [Processing]";;0 +""" From 0db148163b3c3eef6206ea08a94fea06c4d226a6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 1 Jun 2020 15:41:14 +0200 Subject: [PATCH 0620/4254] fixes --warningAsError implementation (#14538) --- compiler/msgs.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 0e64d9327..c4658abcf 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -494,8 +494,12 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, of warnMin..warnMax: sev = Severity.Warning ignoreMsg = not conf.hasWarn(msg) + if msg in conf.warningAsErrors: + ignoreMsg = false + title = ErrorTitle + else: + title = WarningTitle if not ignoreMsg: writeContext(conf, info) - title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor inc(conf.warnCounter) of hintMin..hintMax: From 0a27cca4b50e73beff5dbef84e6de6ab9a4f9f21 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 1 Jun 2020 06:56:29 -0700 Subject: [PATCH 0621/4254] runnableExamples: correctly handle multiline string litterals (#14492) * runnableExamples: correctly handle multiline string litterals * address comments: improve doc comments + variable namings --- compiler/renderverbatim.nim | 83 ++++++++++++++++++-- nimdoc/testproject/expected/testproject.html | 45 +++++++++++ nimdoc/testproject/expected/testproject.idx | 1 + nimdoc/testproject/expected/theindex.html | 4 + nimdoc/testproject/testproject.nim | 40 ++++++++++ 5 files changed, 168 insertions(+), 5 deletions(-) diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index 974454456..d20ee1549 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -4,8 +4,10 @@ from xmltree import addEscaped import ast, options, msgs import packages/docutils/highlite -# import compiler/renderer -import renderer +const isDebug = false +when isDebug: + import renderer + import astalgo proc lastNodeRec(n: PNode): PNode = result = n @@ -23,6 +25,66 @@ proc isInIndentationBlock(src: string, indent: int): bool = if src[j] != ' ': return false return true +type LineData = object + ## keep track of which lines are starting inside a multiline doc comment. + ## We purposefully avoid re-doing parsing which is already done (we get a PNode) + ## so we don't worry about whether we're inside (nested) doc comments etc. + ## But we sill need some logic to disambiguate different multiline styles. + conf: ConfigRef + lineFirst: int + lines: seq[bool] + ## lines[index] is true if line `lineFirst+index` starts inside a multiline string + ## Using a HashSet (extra dependency) would simplify but not by much. + +proc tripleStrLitStartsAtNextLine(conf: ConfigRef, n: PNode): bool = + # enabling TLineInfo.offsetA,offsetB would probably make this easier + const tripleQuote = "\"\"\"" + let src = sourceLine(conf, n.info) + let col = n.info.col + doAssert src.continuesWith(tripleQuote, col) # sanity check + var i = col + 3 + var onlySpace = true + while true: + if src.len <= i: + doAssert src.len == i + return onlySpace + elif src.continuesWith(tripleQuote, i) and (src.len == i+3 or src[i+3] != '\"'): + return false # triple lit is in 1 line + elif src[i] != ' ': onlySpace = false + i.inc + +proc visitMultilineStrings(ldata: var LineData, n: PNode) = + var cline = ldata.lineFirst + + template setLine() = + let index = cline - ldata.lineFirst + if ldata.lines.len < index+1: ldata.lines.setLen index+1 + ldata.lines[index] = true + + case n.kind + of nkTripleStrLit: + # same logic should be applied for any multiline token + # we could also consider nkCommentStmt but right now we just assume doc comments, + # unlike triple string litterals, don't de-indent from runnableExamples. + cline = n.info.line.int + if tripleStrLitStartsAtNextLine(ldata.conf, n): + cline.inc + setLine() + for ai in n.strVal: + case ai + of '\n': + cline.inc + setLine() + else: discard + else: + for i in 0..= ldata.lines.len: false + else: ldata.lines[index] + proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = ## TLineInfo.offsetA,offsetB would be cleaner but it's only enabled for nimpretty, ## we'd need to check performance impact to enable it for nimdoc. @@ -39,20 +101,31 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = assert true ]# first.line = n[0].info.line + 1 - # first.col = n[0].info.col + 1 # anything with `col > n[0].col` is part of runnableExamples let last = n.lastNodeRec.info var info = first var indent = info.col let numLines = numLines(conf, info.fileIndex).uint16 var lastNonemptyPos = 0 + + var ldata = LineData(lineFirst: first.line.int, conf: conf) + visitMultilineStrings(ldata, n[^1]) + when isDebug: + debug(n) + for i in 0.. last.line and not isInIndentationBlock(src, indent): + let special = startOfLineInsideTriple(ldata, line.int) + if line > last.line and not special and not isInIndentationBlock(src, indent): break if line > first.line: result.add "\n" - if src.len > indent: + if special: + result.add src + lastNonemptyPos = result.len + elif src.len > indent: result.add src[indent..^1] lastNonemptyPos = result.len result.setLen lastNonemptyPos diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 4fd5d8ad3..7bd2e64a3 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -198,6 +198,8 @@ function main() { title="low[T: Ordinal | enum | range](x: T): T">low
    • low2
    • +
    • tripleStrLitTest
    @@ -594,6 +596,49 @@ the c printf. etc.

    Example:

    discard "in low2"
    +
    + +
    proc tripleStrLitTest() {...}{.raises: [], tags: [].}
    +
    + + +

    Example:

    +
    ## mullitline string litterals are tricky as their indentation can span
    +## below that of the runnableExamples
    +let s1a = """
    +should appear at indent 0
    +  at indent 2
    +at indent 0
    +"""
    +# make sure this works too
    +let s1b = """start at same line
    +  at indent 2
    +at indent 0
    +""" # comment after
    +let s2 = """sandwich """
    +let s3 = """"""
    +when false:
    +  let s5 = """
    +        in s5 """
    +
    +let s3b = ["""
    +%!? #[...] # inside a multiline ...
    +""", "foo"]
    +
    +## make sure handles trailing spaces
    +let s4 = """ 
    +"""
    +
    +let s5 = """ x
    +"""
    +let s6 = """ ""
    +"""
    +let s7 = """"""""""
    +let s8 = ["""""""""", """
    +  """ ]
    +discard
    +# should be in
    +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index dd26c03d9..46798f314 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -37,6 +37,7 @@ c_printf testproject.html#c_printf,cstring testproject: c_printf(frmt: cstring): c_nonexistant testproject.html#c_nonexistant,cstring testproject: c_nonexistant(frmt: cstring): cint low testproject.html#low,T testproject: low[T: Ordinal | enum | range](x: T): T low2 testproject.html#low2,T testproject: low2[T: Ordinal | enum | range](x: T): T +tripleStrLitTest testproject.html#tripleStrLitTest testproject: tripleStrLitTest() bar testproject.html#bar.m testproject: bar(): untyped z16 testproject.html#z16.m testproject: z16() z18 testproject.html#z18.m testproject: z18(): int diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 1e9e4374f..14d07bfd9 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -213,6 +213,10 @@ function main() {
  • testproject: testNimDocTrailingExample()
  • +
    tripleStrLitTest:
    z1:
    • testproject: z1(): Foo
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 45bbca223..b05754d51 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -207,6 +207,46 @@ when true: # tests RST inside comments runnableExamples: discard "in low2" +when true: # multiline string litterals + proc tripleStrLitTest*() = + runnableExamples: + ## mullitline string litterals are tricky as their indentation can span + ## below that of the runnableExamples + let s1a = """ +should appear at indent 0 + at indent 2 +at indent 0 +""" + # make sure this works too + let s1b = """start at same line + at indent 2 +at indent 0 +""" # comment after + let s2 = """sandwich """ + let s3 = """""" + when false: + let s5 = """ + in s5 """ + + let s3b = [""" +%!? #[...] # inside a multiline ... +""", "foo"] + + ## make sure handles trailing spaces + let s4 = """ +""" + + let s5 = """ x +""" + let s6 = """ "" +""" + let s7 = """""""""" + let s8 = ["""""""""", """ + """ ] + discard + # should be in + # should be out + when true: # (most) macros macro bar*(): untyped = result = newStmtList() From 4bb301dbe2a8fcb9e019e286fdc0cbf622e84434 Mon Sep 17 00:00:00 2001 From: Frank Paulo Filho Date: Mon, 1 Jun 2020 09:57:16 -0400 Subject: [PATCH 0622/4254] Make build_all.sh file executable (#14518) --- build_all.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build_all.sh diff --git a/build_all.sh b/build_all.sh old mode 100644 new mode 100755 From 3698f197f10b775cbe0824936637b7e7d294eb19 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 1 Jun 2020 18:07:01 +0300 Subject: [PATCH 0623/4254] Change severity of template instantiation message [backport] (#14526) * Change severity of template instatiation msg * Add a test * Trailing newline argh --- compiler/msgs.nim | 2 +- nimsuggest/tests/ttempl_inst.nim | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 nimsuggest/tests/ttempl_inst.nim diff --git a/compiler/msgs.nim b/compiler/msgs.nim index c4658abcf..eca3b0276 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -421,7 +421,7 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = if context.info != lastinfo and context.info != info: if conf.structuredErrorHook != nil: conf.structuredErrorHook(conf, context.info, instantiationFrom, - Severity.Error) + Severity.Hint) else: let message = if context.detail == "": instantiationFrom diff --git a/nimsuggest/tests/ttempl_inst.nim b/nimsuggest/tests/ttempl_inst.nim new file mode 100644 index 000000000..ed04a67ce --- /dev/null +++ b/nimsuggest/tests/ttempl_inst.nim @@ -0,0 +1,13 @@ +template foo() = + {.warning: "foo".} + +foo() + +#[!]# +discard """ +$nimsuggest --tester $file +>chk $1 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;"ttempl_inst [Processing]";;0 +chk;;skUnknown;;;;Hint;;$file;;4;;3;;"template/generic instantiation from here";;0 +chk;;skUnknown;;;;Warning;;$file;;2;;11;;"foo [User]";;0 +""" From 75e579ff8ec3b5b3659612ea24f8d2b8c0e20230 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 1 Jun 2020 19:04:28 +0200 Subject: [PATCH 0624/4254] parser.nim: minor refactorings (#14540) --- compiler/parser.nim | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 9d1f6f97a..8f7eb1226 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -740,10 +740,6 @@ proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): P result.add(parseExpr(p)) isFirstParam = false -const - tkTypeClasses = {tkRef, tkPtr, tkVar, tkStatic, tkType, - tkEnum, tkTuple, tkObject, tkProc} - proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode = result = newNodeP(nkCommand, p) result.add(r) @@ -797,7 +793,8 @@ proc primarySuffix(p: var TParser, r: PNode, break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, - tkOpr, tkDotDot, tkTypeClasses - {tkRef, tkPtr}: + tkOpr, tkDotDot, tkVar, tkStatic, tkType, tkEnum, tkTuple, + tkObject, tkProc: # XXX: In type sections we allow the free application of the # command syntax, with the exception of expressions such as # `foo ref` or `foo ptr`. Unfortunately, these two are also @@ -1270,7 +1267,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = result.add(primary(p, pmNormal)) return - case p.tok.tokType: + case p.tok.tokType of tkTuple: result = parseTuple(p, mode == pmTypeDef) of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda) of tkFunc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef) @@ -1392,7 +1389,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode = getTok(p) nextBlock = parseDoBlock(p, info) else: - case nextToken: + case nextToken of tkOf: nextBlock = newNodeP(nkOfBranch, p) exprList(p, tkColon, nextBlock) @@ -1990,8 +1987,8 @@ proc parseObject(p: var TParser): PNode = # an initial IND{>} HAS to follow: if not realInd(p): result.add(p.emptyNode) - return - result.add(parseObjectPart(p)) + else: + result.add(parseObjectPart(p)) proc parseTypeClassParam(p: var TParser): PNode = let modifier = case p.tok.tokType From 3cf88c2b4955f330e147c98064969626719790de Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 1 Jun 2020 10:21:41 -0700 Subject: [PATCH 0625/4254] walkDirRecFilter, update doc CI filter, compiler/index.nim for docs + various other fixes (#14501) * update doc CI filter to include the files mostly likely to require doc rebuild * remove code duplication in ./config/nimdoc.cfg; show link to compiler docs, various fixes * walkDirRecFilter, factor nativeToUnixPath workaround * glob for getRst2html * docslocal: 40s to build all docs * revert code dedup in github actions which did not work alas... * fixups --- .github/workflows/ci_docs.yml | 24 ++++---- compiler/docgen.nim | 21 ++++--- compiler/index.nim | 18 ++++++ config/nimdoc.cfg | 55 +++++------------- doc/idetools.rst | 2 + koch.nim | 7 +++ lib/std/private/globs.nim | 54 +++++++++++++++++ tests/misc/trunner.nim | 7 +-- tools/kochdocs.nim | 105 ++++++++++++++++------------------ tools/nimblepkglist.nim | 3 + 10 files changed, 170 insertions(+), 126 deletions(-) create mode 100644 compiler/index.nim create mode 100644 lib/std/private/globs.nim diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index a1e0920b6..c5e23fbed 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -1,18 +1,27 @@ name: Nim Docs CI on: push: - # Run only on changes on these files paths: - - 'lib/**.nim' + - 'compiler/docgen.nim' + - 'compiler/renderverbatim.nim' - 'doc/**.rst' - 'doc/nimdoc.css' + - 'lib/**.nim' + - 'nimdoc/testproject/expected/testproject.html' + - 'tools/dochack/dochack.nim' + - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' - pull_request: # Run only on changes on these files paths: - - 'lib/**.nim' + - 'compiler/docgen.nim' + - 'compiler/renderverbatim.nim' - 'doc/**.rst' + - 'doc/nimdoc.css' + - 'lib/**.nim' + - 'nimdoc/testproject/expected/testproject.html' + - 'tools/dochack/dochack.nim' + - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' jobs: @@ -115,13 +124,6 @@ jobs: shell: bash run: ./koch doc --git.commit:devel - - name: 'Prepare documentation for deployment' - if: | - github.event_name == 'push' && github.ref == 'refs/heads/devel' && - matrix.target == 'linux' - shell: bash - run: cp -f doc/html/{overview,index}.html - - name: 'Publish documentation to Github Pages' if: | github.event_name == 'push' && github.ref == 'refs/heads/devel' && diff --git a/compiler/docgen.nim b/compiler/docgen.nim index ffafb1fcb..535b11ce7 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -19,6 +19,8 @@ import typesrenderer, astalgo, lineinfos, intsets, pathutils, trees, tables, nimpaths, renderverbatim +from std/private/globs import nativeToUnixPath + const exportSection = skField docCmdSkip = "skip" @@ -53,12 +55,6 @@ type PDoc* = ref TDocumentor ## Alias to type less. -proc nativeToUnix(path: string): string = - doAssert not path.isAbsolute # absolute files need more care for the drive - when DirSep == '\\': - result = replace(path, '\\', '/') - else: result = path - proc docOutDir(conf: ConfigRef, subdir: RelativeDir = RelativeDir""): AbsoluteDir = if not conf.outDir.isEmpty: conf.outDir else: conf.projectPath / subdir @@ -97,7 +93,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re if isAbsolute(result.string): result = file.string.splitPath()[1].RelativeFile if isTitle: - result = result.string.nativeToUnix.RelativeFile + result = result.string.nativeToUnixPath.RelativeFile else: result = result.string.replace("..", dotdotMangle).RelativeFile doAssert not result.isEmpty @@ -1244,20 +1240,23 @@ proc genOutFile(d: PDoc): Rope = # Extract the title. Non API modules generate an entry in the index table. if d.meta[metaTitle].len != 0: title = d.meta[metaTitle] - let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnix + let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnixPath setIndexTerm(d[], external, "", title) else: # Modules get an automatic title for the HTML, but no entry in the index. # better than `extractFilename(changeFileExt(d.filename, ""))` as it disambiguates dups title = $presentationPath(d.conf, AbsoluteFile d.filename, isTitle = true).changeFileExt("") - let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group" + var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection") + let bodyname = if d.hasToc and not d.isPureRst: + groupsection.setLen 0 + "doc.body_toc_group" elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", - "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref"], + "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection"], [title.rope, toc, d.modDesc, rope(getDateStr()), - rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile)]) + rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile), groupsection.rope]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ diff --git a/compiler/index.nim b/compiler/index.nim new file mode 100644 index 000000000..2c2a34fb5 --- /dev/null +++ b/compiler/index.nim @@ -0,0 +1,18 @@ +##[ +This module only exists to generate docs for the compiler. + +## links +* [main docs](../lib.html) +* [compiler user guide](../nimc.html) +* [Internals of the Nim Compiler](../intern.html) +]## + +#[ +note: this is named `index` so that navigating to https://nim-lang.github.io/Nim/compiler/ +will work. + +xxx this should also import other modules, not transitively imported by `compiler/nim.nim`, +eg `evalffi`, otherwise these aren't shown. A glob could be used at CT. +]# + +import nim diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 836b19ab6..945a3dc6c 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -81,42 +81,14 @@ $content
    """ -doc.body_toc = """ -
    -
    -
    - -     Dark Mode +doc.body_toc_groupsection = """ +
    + Group by: +
    - -
    - Search: -
    - $tableofcontents -
    -
    -
    - $deprecationMsg -

    $moduledesc

    - $content -
    -
    """ @if boot: @@ -145,19 +117,16 @@ doc.body_toc_group = """
  • Index
  • +
  • + Compiler docs +
  • Search:
    -
    - Group by: - -
    + $body_toc_groupsection $tableofcontents
    @@ -211,6 +180,8 @@ doc.body_toc_group = """ """ @end +doc.body_toc %= "${doc.body_toc_group}" # should only be used for boot + doc.body_no_toc = """ $moduledesc $content diff --git a/doc/idetools.rst b/doc/idetools.rst index ebb140c5c..e83bfe935 100644 --- a/doc/idetools.rst +++ b/doc/idetools.rst @@ -13,6 +13,8 @@ "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.

    +Note: this is mostly outdated, see instead `nimsuggest `_ + Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the diff --git a/koch.nim b/koch.nim index ee7c8006a..c1d8df8da 100644 --- a/koch.nim +++ b/koch.nim @@ -651,6 +651,13 @@ when isMainModule: of "latest": latest = true of "stable": latest = false of "nim": nimExe = op.val.absolutePath # absolute so still works with changeDir + of "docslocal": + # undocumented for now, allows to rebuild local docs in < 40s as follows: + # `./koch --nim:$nimb --docslocal:htmldocs2 --doccmd:skip --warnings:off --hints:off` + # whereas `./koch docs` takes 190s; useful for development. + doAssert op.val.len > 0 + buildDocsDir(op.cmdLineRest, op.val) + break else: showHelp() of cmdArgument: case normalize(op.key) diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim new file mode 100644 index 000000000..e697ca91c --- /dev/null +++ b/lib/std/private/globs.nim @@ -0,0 +1,54 @@ +##[ +unstable API, internal use only for now. +this can eventually be moved to std/os and `walkDirRec` can be implemented in terms of this +to avoid duplication +]## + +import std/[os,strutils] + +type + PathEntry* = object + kind*: PathComponent + path*: string + +iterator walkDirRecFilter*(dir: string, follow: proc(entry: PathEntry): bool = nil, + relative = false, checkDir = true): PathEntry {.tags: [ReadDirEffect].} = + ## Improved `os.walkDirRec`. + #[ + note: a yieldFilter isn't needed because caller can filter at call site, without + loss of generality, unlike `follow`. + + Future work: + * need to document + * add a `sort` option, which can be implemented efficiently only here, not at call site. + * provide a way to do error reporting, which is tricky because iteration cannot be resumed + ]# + var stack = @["."] + var checkDir = checkDir + var entry: PathEntry + while stack.len > 0: + let d = stack.pop() + for k, p in walkDir(dir / d, relative = true, checkDir = checkDir): + let rel = d / p + entry.kind = k + if relative: entry.path = rel + else: entry.path = dir / rel + if k in {pcDir, pcLinkToDir}: + if follow == nil or follow(entry): stack.add rel + yield entry + checkDir = false + # We only check top-level dir, otherwise if a subdir is invalid (eg. wrong + # permissions), it'll abort iteration and there would be no way to + # continue iteration. + +proc nativeToUnixPath*(path: string): string = + # pending https://github.com/nim-lang/Nim/pull/13265 + doAssert not path.isAbsolute # not implemented here; absolute files need more care for the drive + when DirSep == '\\': + result = replace(path, '\\', '/') + else: result = path + +when isMainModule: + import sugar + for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", ".csources", "bin"]): + echo a diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 566f9f033..382fd35ae 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -11,6 +11,7 @@ import std/[strformat,os,osproc,unittest] from std/sequtils import toSeq,mapIt from std/algorithm import sorted import stdtest/[specialpaths, unittest_light] +from std/private/globs import nativeToUnixPath import "$lib/../compiler/nimpaths" @@ -90,11 +91,7 @@ else: # don't run twice the same test removeDir(htmldocsDir) let (outp, exitCode) = execCmdEx(cmd) check exitCode == 0 - proc nativeToUnixPathWorkaround(a: string): string = - # xxx pending https://github.com/nim-lang/Nim/pull/13265 `nativeToUnixPath` - a.replace(DirSep, '/') - - let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPathWorkaround).sorted.join("\n") + let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPath).sorted.join("\n") let context = $(i, ret, cmd) var expected = "" case i diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index c39a9c448..80aad4fb6 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,6 +1,7 @@ ## Part of 'koch' responsible for the documentation generation. import os, strutils, osproc, sets, pathnorm +from std/private/globs import nativeToUnixPath, walkDirRecFilter, PathEntry import "../compiler/nimpaths" const @@ -85,6 +86,16 @@ proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options let cmd = findNim().quoteShell() & " " & mode & " -o:" & output & " " & options & " " & input execFold(desc, cmd) +proc getRst2html(): seq[string] = + for a in walkDirRecFilter("doc"): + let path = a.path + if a.kind == pcFile and path.splitFile.ext == ".rst" and path.lastPathPart notin + ["docs.rst", "nimfix.rst"]: + # maybe we should still show nimfix, could help reviving it + # `docs` is redundant with `overview`, might as well remove that file? + result.add path + doAssert "doc/manual/var_t_return.rst".unixToNativePath in result # sanity check + const pdf = """ doc/manual.rst @@ -95,39 +106,6 @@ doc/tut3.rst doc/nimc.rst doc/niminst.rst doc/gc.rst -""".splitWhitespace() - - rst2html = """ -doc/intern.rst -doc/apis.rst -doc/lib.rst -doc/manual.rst -doc/manual_experimental.rst -doc/destructors.rst -doc/tut1.rst -doc/tut2.rst -doc/tut3.rst -doc/nimc.rst -doc/hcr.rst -doc/drnim.rst -doc/overview.rst -doc/filters.rst -doc/tools.rst -doc/niminst.rst -doc/nimgrep.rst -doc/gc.rst -doc/estp.rst -doc/idetools.rst -doc/docgen.rst -doc/koch.rst -doc/backends.rst -doc/nimsuggest.rst -doc/nep1.rst -doc/nims.rst -doc/contributing.rst -doc/codeowners.rst -doc/packaging.rst -doc/manual/var_t_return.rst """.splitWhitespace() doc0 = """ @@ -185,7 +163,7 @@ proc getDocList(): seq[string] = for a in withoutIndex: docIgnore.incl a for a in ignoredModules: docIgnore.incl a - # don't ignore these even though in lib/system + # don't ignore these even though in lib/system (not include files) const goodSystem = """ lib/system/io.nim lib/system/nimscript.nim @@ -194,14 +172,14 @@ lib/system/iterators.nim lib/system/dollars.nim lib/system/widestrs.nim """.splitWhitespace() - - for a in walkDirRec("lib"): - if a.splitFile.ext != ".nim" or - a.isRelativeTo("lib/pure/includes") or - a.isRelativeTo("lib/genode") or - a.isRelativeTo("lib/deprecated") or - (a.isRelativeTo("lib/system") and a.replace('\\', '/') notin goodSystem) or - a.replace('\\', '/') in docIgnore: + + proc follow(a: PathEntry): bool = + a.path.lastPathPart notin ["nimcache", "htmldocs", "includes", "deprecated", "genode"] + for entry in walkDirRecFilter("lib", follow = follow): + let a = entry.path + if entry.kind != pcFile or a.splitFile.ext != ".nim" or + (a.isRelativeTo("lib/system") and a.nativeToUnixPath notin goodSystem) or + a.nativeToUnixPath in docIgnore: continue result.add a result.add normalizePath("nimsuggest/sexp.nim") @@ -231,16 +209,28 @@ proc buildDocSamples(nimArgs, destPath: string) = [nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) proc buildDocPackages(nimArgs, destPath: string) = - # compiler docs, and later, other packages (perhaps tools, testament etc) + # compiler docs; later, other packages (perhaps tools, testament etc) let nim = findNim().quoteShell() - let extra = "-u:boot" # to avoid broken links to manual from compiler dir, but a multi-package # structure could be supported later - exec("$1 doc --project --outdir:$2/compiler $3 --git.url:$4 $5 compiler/nim.nim" % - [nim, destPath, nimArgs, gitUrl, extra]) + + proc docProject(outdir, options, mainproj: string) = + exec("$nim doc --project --outdir:$outdir $nimArgs --git.url:$gitUrl $options $mainproj" % [ + "nim", nim, + "outdir", outdir, + "nimArgs", nimArgs, + "gitUrl", gitUrl, + "options", options, + "mainproj", mainproj, + ]) + let extra = "-u:boot" + # xxx keep in sync with what's in $nim_prs_D/config/nimdoc.cfg, or, rather, + # start using nims instead of nimdoc.cfg + docProject(destPath/"compiler", extra, "compiler/index.nim") proc buildDoc(nimArgs, destPath: string) = # call nim for the documentation: + let rst2html = getRst2html() var commands = newSeq[string](rst2html.len + len(doc0) + len(doc) + withoutIndex.len) i = 0 @@ -305,18 +295,19 @@ proc buildJS(): string = let nim = findNim() exec(nim.quoteShell() & " js -d:release --out:$1 tools/nimblepkglist.nim" % [webUploadOutput / "nimblepkglist.js"]) + # xxx deadcode? and why is it only for webUploadOutput, not for local docs? result = getDocHacksJs(nimr = getCurrentDir(), nim) -proc buildDocs*(args: string) = +proc buildDocsDir*(args: string, dir: string) = + let args = nimArgs & " " & args let docHackJsSource = buildJS() - template fn(args, dir) = - let dir2 = dir - let args2 = args - createDir(dir2) - buildDocSamples(args2, dir2) - buildDoc(args2, dir2) - buildDocPackages(args2, dir2) - copyFile(docHackJsSource, dir2 / docHackJsSource.lastPathPart) + createDir(dir) + buildDocSamples(args, dir) + buildDoc(args, dir) # bottleneck + copyFile(dir / "overview.html", dir / "index.html") + buildDocPackages(args, dir) + copyFile(docHackJsSource, dir / docHackJsSource.lastPathPart) - fn(nimArgs & " " & args, webUploadOutput / NimVersion) - fn(nimArgs, docHtmlOutput) # no `args` to avoid offline docs containing the 'gaCode'! +proc buildDocs*(args: string) = + buildDocsDir(args, webUploadOutput / NimVersion) + buildDocsDir("", docHtmlOutput) # no `args` to avoid offline docs containing the 'gaCode'! diff --git a/tools/nimblepkglist.nim b/tools/nimblepkglist.nim index 870944ab0..c4bec4485 100644 --- a/tools/nimblepkglist.nim +++ b/tools/nimblepkglist.nim @@ -1,3 +1,6 @@ +#[ +deadcode? +]# import base64, strutils, json, htmlgen, dom, algorithm type From e5b64af8317eb0f5e8b9912691b69aab4cd26adf Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 1 Jun 2020 18:56:17 +0100 Subject: [PATCH 0626/4254] Implement rendering of `[]=`, `{}`, `{}=` braces (#14539) * render curly braces * fix typo * fix test Co-authored-by: cooldome --- compiler/renderer.nim | 70 +++++++++++++++++++++++++++-------- tests/errmsgs/twrongcolon.nim | 6 +-- tests/macros/tmacrostmt.nim | 15 +++++++- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 29ff80ca9..6c953dc18 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -874,12 +874,23 @@ proc gsub(g: var TSrcGen; n: PNode; i: int) = else: put(g, tkOpr, "<<" & $i & "th child missing for " & $n.kind & " >>") -proc isBracket*(n: PNode): bool = - case n.kind - of nkClosedSymChoice, nkOpenSymChoice: - if n.len > 0: result = isBracket(n[0]) - of nkSym: result = n.sym.name.s == "[]" - else: result = false +type + BracketKind = enum + bkNone, bkBracket, bkBracketAsgn, bkCurly, bkCurlyAsgn + +proc bracketKind*(g: TSrcGen, n: PNode): BracketKind = + if renderIds notin g.flags: + case n.kind + of nkClosedSymChoice, nkOpenSymChoice: + if n.len > 0: result = bracketKind(g, n[0]) + of nkSym: + result = case n.sym.name.s + of "[]": bkBracket + of "[]=": bkBracketAsgn + of "{}": bkCurly + of "{}=": bkCurlyAsgn + else: bkNone + else: result = bkNone proc skipHiddenNodes(n: PNode): PNode = result = n @@ -892,10 +903,11 @@ proc skipHiddenNodes(n: PNode): PNode = else: break proc accentedName(g: var TSrcGen, n: PNode) = + const backticksNeeded = OpChars + {'[', '{'} if n == nil: return let isOperator = - if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in OpChars: true - elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in OpChars: true + if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in backticksNeeded: true + elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in backticksNeeded: true else: false if isOperator: @@ -954,12 +966,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkCharLit: put(g, tkCharLit, atom(g, n)) of nkNilLit: put(g, tkNil, atom(g, n)) # complex expressions of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr: - if renderIds notin g.flags and n.len > 0 and isBracket(n[0]): - gsub(g, n, 1) - put(g, tkBracketLe, "[") - gcomma(g, n, 2) - put(g, tkBracketRi, "]") - elif n.len > 1 and n.lastSon.kind == nkStmtList: + if n.len > 1 and n.lastSon.kind in {nkStmtList, nkStmtListExpr}: accentedName(g, n[0]) if n.len > 2: put(g, tkParLe, "(") @@ -967,10 +974,41 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParRi, ")") put(g, tkColon, ":") gsub(g, n, n.len-1) + elif n.len >= 1: + case bracketKind(g, n[0]) + of bkBracket: + gsub(g, n, 1) + put(g, tkBracketLe, "[") + gcomma(g, n, 2) + put(g, tkBracketRi, "]") + of bkBracketAsgn: + gsub(g, n, 1) + put(g, tkBracketLe, "[") + gcomma(g, n, 2, -2) + put(g, tkBracketRi, "]") + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + gsub(g, n, n.len - 1) + of bkCurly: + gsub(g, n, 1) + put(g, tkCurlyLe, "{") + gcomma(g, n, 2) + put(g, tkCurlyRi, "}") + of bkCurlyAsgn: + gsub(g, n, 1) + put(g, tkCurlyLe, "{") + gcomma(g, n, 2, -2) + put(g, tkCurlyRi, "}") + put(g, tkSpaces, Space) + putWithSpace(g, tkEquals, "=") + gsub(g, n, n.len - 1) + of bkNone: + accentedName(g, n[0]) + put(g, tkParLe, "(") + gcomma(g, n, 1) + put(g, tkParRi, ")") else: - if n.len >= 1: accentedName(g, n[0]) put(g, tkParLe, "(") - gcomma(g, n, 1) put(g, tkParRi, ")") of nkCallStrLit: if n.len > 0: accentedName(g, n[0]) diff --git a/tests/errmsgs/twrongcolon.nim b/tests/errmsgs/twrongcolon.nim index 6f5cc3e5d..e59e37660 100644 --- a/tests/errmsgs/twrongcolon.nim +++ b/tests/errmsgs/twrongcolon.nim @@ -1,8 +1,8 @@ discard """ -errormsg: "in expression '(" +errormsg: "in expression ':" nimout: ''' -Error: in expression '( - 890)': identifier expected, but found '' +Error: in expression ': + 890': identifier expected, but found '' ''' line: 11 diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim index 56a0bf840..79be5f764 100644 --- a/tests/macros/tmacrostmt.nim +++ b/tests/macros/tmacrostmt.nim @@ -100,18 +100,30 @@ proc fn4(x: int): int = proc fn5(a, b: float): float = result = - a * a / (b * b) +proc `{}`(x: seq[float], i: int, j: int): float = + x[i + 0 * j] + +proc `{}=`(x: var seq[float], i: int, val: float) = + x[i] = val + +proc fn6() = + var a = @[1.0, 2.0] + let z = a{0, 1} + a{2} = 5.0 + + #------------------------------------ # bug #10807 proc fn_unsafeaddr(x: int): int = cast[int](unsafeAddr(x)) static: - echo fn_unsafeaddr.repr_to_string let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n" let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2 * x) / (x - y)\n" let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n" let fn4s = "proc fn4(x: int): int =\n if x mod 2 == 0:\n return x + 2\n else:\n return 0\n" let fn5s = "proc fn5(a, b: float): float =\n result = -a * a / (b * b)\n" + let fn6s = "proc fn6() =\n var a = @[1.0, 2.0]\n let z = a{0, 1}\n a{2} = 5.0\n" let fnAddr = "proc fn_unsafeaddr(x: int): int =\n result = cast[int](unsafeAddr(x))\n" doAssert fn1.repr_to_string == fn1s @@ -119,6 +131,7 @@ static: doAssert fn3.repr_to_string == fn3s doAssert fn4.repr_to_string == fn4s doAssert fn5.repr_to_string == fn5s + doAssert fn6.repr_to_string == fn6s doAssert fn_unsafeaddr.repr_to_string == fnAddr #------------------------------------ From 621384b8efce7def08faeb9bc63289a4a88c3a59 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 2 Jun 2020 01:47:19 -0700 Subject: [PATCH 0627/4254] fix https://github.com/timotheecour/Nim/issues/266 retry on failure to avoid common 503 github errors (#14547) --- lib/std/private/nimbleutils.nim | 32 ++++++++++++++++++++++++++++++++ testament/categories.nim | 7 ++++--- 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 lib/std/private/nimbleutils.nim diff --git a/lib/std/private/nimbleutils.nim b/lib/std/private/nimbleutils.nim new file mode 100644 index 000000000..297fb9695 --- /dev/null +++ b/lib/std/private/nimbleutils.nim @@ -0,0 +1,32 @@ +##[ +internal API for now, API subject to change +]## + +import std/[os,osproc,sugar,strutils] + +proc actionRetry*(maxRetry: int, backoffDuration: float, action: proc(): bool): bool = + ## retry `action` up to `maxRetry` times with exponential backoff and initial + ## duraton of `backoffDuration` seconds + var t = backoffDuration + for i in 0.. Date: Tue, 2 Jun 2020 09:54:33 -0700 Subject: [PATCH 0628/4254] * honor --errorMax even for tools (eg drnim, nim doc) (#14546) * fix a bug that prevented nim doc compiler/nim on windows --- compiler/main.nim | 6 +++--- compiler/nimeval.nim | 3 ++- compiler/options.nim | 8 ++++++++ compiler/sem.nim | 2 +- compiler/semexprs.nim | 3 +-- drnim/drnim.nim | 2 +- nimsuggest/nimsuggest.nim | 6 ++---- tools/kochdocs.nim | 4 +++- tools/nimfind.nim | 3 +-- 9 files changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 55b2f2899..52fc62650 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -51,7 +51,7 @@ proc commandGenDepend(graph: ModuleGraph) = ' ' & changeFileExt(project, "dot").string) proc commandCheck(graph: ModuleGraph) = - graph.config.errorMax = high(int) # do not stop after first error + graph.config.setErrorMaxHighMaybe defineSymbol(graph.config.symbols, "nimcheck") semanticPasses(graph) # use an empty backend for semantic checking only compileProject(graph) @@ -59,7 +59,7 @@ proc commandCheck(graph: ModuleGraph) = when not defined(leanCompiler): proc commandDoc2(graph: ModuleGraph; json: bool) = handleDocOutputOptions graph.config - graph.config.errorMax = high(int) # do not stop after first error + graph.config.setErrorMaxHighMaybe semanticPasses(graph) if json: registerPass(graph, docgen2JsonPass) else: registerPass(graph, docgen2Pass) @@ -136,7 +136,7 @@ proc interactivePasses(graph: ModuleGraph) = registerPass(graph, evalPass) proc commandInteractive(graph: ModuleGraph) = - graph.config.errorMax = high(int) # do not stop after first error + graph.config.setErrorMaxHighMaybe interactivePasses(graph) compileSystemModule(graph) if graph.config.commandArgs.len > 0: diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 11e899cae..df3cb2079 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -137,6 +137,7 @@ proc destroyInterpreter*(i: Interpreter) = proc runRepl*(r: TLLRepl; searchPaths: openArray[string]; supportNimscript: bool) = + ## deadcode but please don't remove... might be revived var conf = newConfigRef() var cache = newIdentCache() var graph = newModuleGraph(cache, conf) @@ -146,7 +147,7 @@ proc runRepl*(r: TLLRepl; if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p conf.cmd = cmdInteractive - conf.errorMax = high(int) + conf.setErrorMaxHighMaybe initDefines(conf.symbols) defineSymbol(conf.symbols, "nimscript") if supportNimscript: defineSymbol(conf.symbols, "nimconfig") diff --git a/compiler/options.nim b/compiler/options.nim index d990f2fd4..31c0765a7 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -315,6 +315,14 @@ type severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string +proc assignIfDefault*[T](result: var T, val: T, def = default(T)) = + ## if `result` was already assigned to a value (that wasn't `def`), this is a noop. + if result == def: result = val + +template setErrorMaxHighMaybe*(conf: ConfigRef) = + ## do not stop after first error (but honor --errorMax if provided) + assignIfDefault(conf.errorMax, high(int)) + proc setNoteDefaults*(conf: ConfigRef, note: TNoteKind, enabled = true) = template fun(op) = conf.notes.op note diff --git a/compiler/sem.nim b/compiler/sem.nim index 683c67254..ca5d9c448 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -325,7 +325,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = let oldErrorOutputs = c.config.m.errorOutputs c.config.m.errorOutputs = {} - c.config.errorMax = high(int) + c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here try: result = evalConstExpr(c.module, c.graph, e) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 72d407cf7..200d1d60a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2074,8 +2074,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if c.compilesContextId == 0: inc c.compilesContextIdGenerator c.compilesContextId = c.compilesContextIdGenerator - # do not halt after first error: - c.config.errorMax = high(int) + c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here # open a scope for temporary symbol inclusions: let oldScope = c.currentScope diff --git a/drnim/drnim.nim b/drnim/drnim.nim index d48c35b3f..e17667ec7 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1192,7 +1192,7 @@ proc mainCommand(graph: ModuleGraph) = graph.strongSemCheck = strongSemCheck graph.compatibleProps = compatibleProps - graph.config.errorMax = high(int) # do not stop after first error + graph.config.setErrorMaxHighMaybe defineSymbol(graph.config.symbols, "nimcheck") defineSymbol(graph.config.symbols, "nimDrNim") diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 56646db35..9a0962df3 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -525,8 +525,7 @@ proc mainCommand(graph: ModuleGraph) = add(conf.searchPaths, conf.libpath) - # do not stop after the first error: - conf.errorMax = high(int) + conf.setErrorMaxHighMaybe # honor --errorMax even if it may not make sense here # do not print errors, but log them conf.writelnHook = myLog conf.structuredErrorHook = nil @@ -674,8 +673,7 @@ else: add(conf.searchPaths, conf.libpath) - # do not stop after the first error: - conf.errorMax = high(int) + conf.setErrorMaxHighMaybe # do not print errors, but log them conf.writelnHook = myLog conf.structuredErrorHook = nil diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 80aad4fb6..4f39463e1 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -6,7 +6,9 @@ import "../compiler/nimpaths" const gaCode* = " --doc.googleAnalytics:UA-48159761-1" - nimArgs = "--hint:Conf:off --hint:Path:off --hint:Processing:off -d:boot --putenv:nimversion=$#" % system.NimVersion + # errormax: subsequent errors are probably consequences of 1st one; a simple + # bug could cause unlimited number of errors otherwise, hard to debug in CI. + nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off -d:boot --putenv:nimversion=$#" % system.NimVersion gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" webUploadOutput = "web/upload" diff --git a/tools/nimfind.nim b/tools/nimfind.nim index eca3d8eb2..05980d740 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -169,8 +169,7 @@ proc mainCommand(graph: ModuleGraph) = if not fileExists(conf.projectFull): quit "cannot find file: " & conf.projectFull.string add(conf.searchPaths, conf.libpath) - # do not stop after the first error: - conf.errorMax = high(int) + conf.setErrorMaxHighMaybe try: compileProject(graph) finally: From 55f0df164befdf2304841c74daeaacc5391e08fd Mon Sep 17 00:00:00 2001 From: alaviss Date: Wed, 3 Jun 2020 11:17:06 -0500 Subject: [PATCH 0629/4254] io: correct signature for some win32 apis (#14551) See https://github.com/nim-lang/Nim/pull/14550#issuecomment-637937649 --- lib/system/io.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index b1f6bb61b..d1a7f1fc7 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -279,10 +279,10 @@ elif defined(posix) and not defined(nimscript): importc: "fcntl", header: "", varargs.} elif defined(windows): const HANDLE_FLAG_INHERIT = culong 0x1 - proc getOsfhandle(fd: cint): FileHandle {. + proc getOsfhandle(fd: cint): int {. importc: "_get_osfhandle", header: "".} - proc setHandleInformation(handle: FileHandle, mask, flags: culong): cint {. + proc setHandleInformation(handle: int, mask, flags: culong): cint {. importc: "SetHandleInformation", header: "".} const @@ -318,7 +318,7 @@ proc getOsFileHandle*(f: File): FileHandle = ## returns the OS file handle of the file ``f``. This is only useful for ## platform specific programming. when defined(windows): - result = getOsfhandle(getFileHandle(f)) + result = FileHandle getOsfhandle(cint getFileHandle(f)) else: result = c_fileno(f) @@ -339,7 +339,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w flags = if inheritable: flags and not FD_CLOEXEC else: flags or FD_CLOEXEC result = c_fcntl(f, F_SETFD, flags) != -1 else: - result = setHandleInformation(f, HANDLE_FLAG_INHERIT, culong inheritable) != 0 + result = setHandleInformation(f.int, HANDLE_FLAG_INHERIT, culong inheritable) != 0 proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} = @@ -647,7 +647,7 @@ proc open*(f: var File, filehandle: FileHandle, ## ## The passed file handle will no longer be inheritable. when not defined(nimInheritHandles) and declared(setInheritable): - let oshandle = when defined(windows): getOsfhandle(filehandle) else: filehandle + let oshandle = when defined(windows): FileHandle getOsfhandle(filehandle) else: filehandle if not setInheritable(oshandle, false): return false f = c_fdopen(filehandle, FormatOpen[mode]) From 4ba34522f6f64f66df849368d3aad1c434ae1403 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 3 Jun 2020 19:20:41 -0700 Subject: [PATCH 0630/4254] [cleanup] docgen: remove docOutdir now that outDir is always set (#14554) --- compiler/docgen.nim | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 535b11ce7..0263b36eb 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -55,9 +55,6 @@ type PDoc* = ref TDocumentor ## Alias to type less. -proc docOutDir(conf: ConfigRef, subdir: RelativeDir = RelativeDir""): AbsoluteDir = - if not conf.outDir.isEmpty: conf.outDir else: conf.projectPath / subdir - proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): RelativeFile = ## returns a relative file that will be appended to outDir let file2 = $file @@ -154,13 +151,9 @@ proc parseRst(text, filename: string, docgenFindFile, compilerMsgHandler) proc getOutFile2(conf: ConfigRef; filename: RelativeFile, - ext: string, dir: RelativeDir; guessTarget: bool): AbsoluteFile = - if optWholeProject in conf.globalOptions: - let d = conf.docOutDir(dir) - createDir(d) - result = d / changeFileExt(filename, ext) - elif guessTarget: - let d = conf.docOutDir + ext: string, guessTarget: bool): AbsoluteFile = + if optWholeProject in conf.globalOptions or guessTarget: + let d = conf.outDir createDir(d) result = d / changeFileExt(filename, ext) elif not conf.outFile.isEmpty: @@ -235,8 +228,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, if execShellCmd(cmd) != status: rawMessage(conf, errGenerated, "executing of external program failed: " & cmd) result.emitted = initIntSet() - result.destFile = getOutFile2(conf, presentationPath(conf, filename), - outExt, htmldocsDir, false) + result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false) result.thisDir = result.destFile.splitFile.dir template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) = @@ -364,8 +356,7 @@ proc belongsToPackage(conf: ConfigRef; module: PSym): bool = proc externalDep(d: PDoc; module: PSym): string = if optWholeProject in d.conf.globalOptions or d.conf.docRoot.len > 0: let full = AbsoluteFile toFullPath(d.conf, FileIndex module.position) - let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt, - htmldocsDir, sfMainModule notin module.flags) + let tmp = getOutFile2(d.conf, presentationPath(d.conf, full), HtmlExt, sfMainModule notin module.flags) result = relativeTo(tmp, d.thisDir, '/').string else: result = extractFilename toFullPath(d.conf, FileIndex module.position) @@ -1272,14 +1263,13 @@ proc genOutFile(d: PDoc): Rope = proc generateIndex*(d: PDoc) = if optGenIndex in d.conf.globalOptions: - let dir = d.conf.docOutDir(htmldocsDir) + let dir = d.conf.outDir createDir(dir) let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt) writeIndexFile(d[], dest.string) proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html - if d.conf.outDir.isEmpty: d.conf.outDir = d.conf.docOutDir if d.conf.outFile.isEmpty: d.conf.outFile = outfile.relativeTo(d.conf.outDir) if isAbsolute(d.conf.outFile.string): @@ -1292,7 +1282,7 @@ proc writeOutput*(d: PDoc, useWarning = false) = writeRope(stdout, content) else: template outfile: untyped = d.destFile - #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, htmldocsDir) + #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt) let dir = outfile.splitFile.dir createDir(dir) updateOutfile(d, outfile) From 01f6e505c8b23fa55506d39864f6353e2a10a276 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 4 Jun 2020 01:40:17 -0700 Subject: [PATCH 0631/4254] bug fixes with sfMainModule, hints, mainPackageNotes, mainPackageId, hintSuccessX (#14555) * SuccessX `out` now works with --compileOnly and jsonscript; fix bugs in jsonscript * several bug fixes; eg: `nim doc lib/system/io` now is sane * dummy edit to force docs CI --- .github/workflows/ci_docs.yml | 2 +- compiler/commands.nim | 2 -- compiler/extccomp.nim | 21 +++++++++++++++++++-- compiler/main.nim | 17 ++++++++++++++--- compiler/modules.nim | 33 +++++++++++++++++++++++++-------- compiler/msgs.nim | 2 ++ compiler/options.nim | 14 ++++++++------ compiler/passes.nim | 4 +--- 8 files changed, 70 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index c5e23fbed..2fbf7e7dc 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -12,7 +12,7 @@ on: - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' pull_request: - # Run only on changes on these files + # Run only on changes on these files. paths: - 'compiler/docgen.nim' - 'compiler/renderverbatim.nim' diff --git a/compiler/commands.nim b/compiler/commands.nim index ce4f7cc0f..2d8418139 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -913,8 +913,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) -template gCmdLineInfo*(): untyped = newLineInfo(commandLineIdx, 1, 1) - proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 7757a9f9d..6feb68f81 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1003,10 +1003,16 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = var buf = newStringOfCap(50) let jsonFile = conf.getNimcacheDir / RelativeFile(conf.projectName & ".json") + conf.jsonBuildFile = jsonFile + let output = conf.absOutFile var f: File if open(f, jsonFile.string, fmWrite): - lit "{\"compile\":[\L" + lit "{\L" + lit "\"outputFile\": " + str $output + + lit ",\L\"compile\":[\L" cfiles(conf, f, buf, conf.toCompile, false) lit "],\L\"link\":[\L" var objfiles = "" @@ -1014,7 +1020,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink) lit "],\L\"linkcmd\": " - str getLinkCmd(conf, conf.absOutFile, objfiles) + str getLinkCmd(conf, output, objfiles) lit ",\L\"extraCmds\": " lit $(%* getExtraCmds(conf, conf.absOutFile)) @@ -1074,6 +1080,17 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = let jsonFile = toGeneratedFile(conf, projectfile, "json") try: let data = json.parseFile(jsonFile.string) + + let output = data["outputFile"].getStr + createDir output.parentDir + let outputCurrent = $conf.absOutFile + if output != outputCurrent: + # previously, any specified output file would be silently ignored; + # simply copying won't work in some cases, for example with `extraCmds`, + # so we just make it an error, user should use same command for jsonscript + # as was used with --compileOnly. + globalError(conf, gCmdLineInfo, "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " % [outputCurrent, output, jsonFile.string]) + let toCompile = data["compile"] doAssert toCompile.kind == JArray var cmds: TStringSeq diff --git a/compiler/main.nim b/compiler/main.nim index 52fc62650..e498dc6b9 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -66,8 +66,7 @@ when not defined(leanCompiler): compileProject(graph) finishDoc2Pass(graph.config.projectName) -proc commandCompileToC(graph: ModuleGraph) = - let conf = graph.config +proc setOutFile(conf: ConfigRef) = if conf.outFile.isEmpty: let base = conf.projectName let targetName = if optGenDynLib in conf.globalOptions: @@ -76,6 +75,9 @@ proc commandCompileToC(graph: ModuleGraph) = base & platform.OS[conf.target.targetOS].exeExt conf.outFile = RelativeFile targetName +proc commandCompileToC(graph: ModuleGraph) = + let conf = graph.config + setOutFile(conf) extccomp.initVars(conf) semanticPasses(graph) registerPass(graph, cgenPass) @@ -370,6 +372,7 @@ proc mainCommand*(graph: ModuleGraph) = conf.cmd = cmdDump of "jsonscript": conf.cmd = cmdJsonScript + setOutFile(graph.config) commandJsonScript(graph) elif commandAlreadyProcessed: discard # already handled else: @@ -386,7 +389,15 @@ proc mainCommand*(graph: ModuleGraph) = else: "Debug" let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName - var output = $conf.absOutFile + + var output: string + if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonScript: + output = $conf.jsonBuildFile + elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonScript, cmdCompileToBackend, cmdDoc}: + # for some cmd we expect a valid absOutFile + output = "unknownOutput" + else: + output = $conf.absOutFile if optListFullPaths notin conf.globalOptions: output = output.AbsoluteFile.extractFilename rawMessage(conf, hintSuccessX, [ "loc", loc, diff --git a/compiler/modules.nim b/compiler/modules.nim index d6e82d694..383858026 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -17,22 +17,29 @@ import proc resetSystemArtifacts*(g: ModuleGraph) = magicsys.resetSysTypes(g) -proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = +template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent = + getIdent(graph.cache, splitFile(filename).name) + +proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym = + ## returns package symbol (skPackage) for yet to be defined module for fileIdx + let filename = AbsoluteFile toFullPath(graph.config, fileIdx) + let name = getModuleIdent(graph, filename) + let info = newLineInfo(fileIdx, 1, 1) let pck = getPackageName(graph.config, filename.string) pck2 = if pck.len > 0: pck else: "unknown" pack = getIdent(graph.cache, pck2) var packSym = graph.packageSyms.strTableGet(pack) if packSym == nil: - packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, result.info) + packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, info) initStrTable(packSym.tab) graph.packageSyms.strTableAdd(packSym) else: - let existing = strTableGet(packSym.tab, result.name) - if existing != nil and existing.info.fileIndex != result.info.fileIndex: + let existing = strTableGet(packSym.tab, name) + if existing != nil and existing.info.fileIndex != info.fileIndex: when false: # we used to produce an error: - localError(graph.config, result.info, + localError(graph.config, info, "module names need to be unique per Nimble package; module clashes with " & toFullPath(graph.config, existing.info.fileIndex)) else: @@ -40,10 +47,13 @@ proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; fil # to resolve the conflicts: let pck3 = fakePackageName(graph.config, filename) # this makes the new `packSym`'s owner be the original `packSym` - packSym = newSym(skPackage, getIdent(graph.cache, pck3), packSym, result.info) + packSym = newSym(skPackage, getIdent(graph.cache, pck3), packSym, info) initStrTable(packSym.tab) graph.packageSyms.strTableAdd(packSym) + result = packSym +proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = + let packSym = getPackage(graph, fileIdx) result.owner = packSym result.position = int fileIdx @@ -60,13 +70,15 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = # We cannot call ``newSym`` here, because we have to circumvent the ID # mechanism, which we do in order to assign each module a persistent ID. result = PSym(kind: skModule, id: -1, # for better error checking - name: getIdent(graph.cache, splitFile(filename).name), + name: getModuleIdent(graph, filename), info: newLineInfo(fileIdx, 1, 1)) if not isNimIdentifier(result.name.s): rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s) partialInitModule(result, graph, fileIdx, filename) proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym = + var flags = flags + if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule result = graph.getModule(fileIdx) if result == nil: let filename = AbsoluteFile toFullPath(graph.config, fileIdx) @@ -104,7 +116,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = # localError(result.info, errAttemptToRedefine, result.name.s) # restore the notes for outer module: graph.config.notes = - if s.owner.id == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes + if s.getnimblePkgId == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes else: graph.config.foreignPackageNotes proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode = @@ -135,7 +147,12 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = wantMainModule(conf) let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim") let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx + conf.projectMainIdx2 = projectFile + + let packSym = getPackage(graph, projectFile) + graph.config.mainPackageId = packSym.getnimblePkgId graph.importStack.add projectFile + if projectFile == systemFileIdx: discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule}) else: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index eca3b0276..a0fc9b08d 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -117,6 +117,8 @@ proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = proc newLineInfo*(conf: ConfigRef; filename: AbsoluteFile, line, col: int): TLineInfo {.inline.} = result = newLineInfo(fileInfoIdx(conf, filename), line, col) +const gCmdLineInfo* = newLineInfo(commandLineIdx, 1, 1) + proc concat(strings: openArray[string]): string = var totalLen = 0 for s in strings: totalLen += s.len diff --git a/compiler/options.nim b/compiler/options.nim index 31c0765a7..289509c16 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -273,6 +273,7 @@ type lazyPaths*: seq[AbsoluteDir] outFile*: RelativeFile outDir*: AbsoluteDir + jsonBuildFile*: AbsoluteFile prefixDir*, libpath*, nimcacheDir*: AbsoluteDir dllOverrides, moduleOverrides*, cfileSpecificOptions*: StringTableRef projectName*: string # holds a name like 'nim' @@ -281,6 +282,7 @@ type projectIsStdin*: bool # whether we're compiling from stdin lastMsgWasDot*: bool # the last compiler message was a single '.' projectMainIdx*: FileIndex # the canonical path id of the main module + projectMainIdx2*: FileIndex # consider merging with projectMainIdx command*: string # the main command (e.g. cc, check, scan, etc) commandArgs*: seq[string] # any arguments after the main command commandLine*: string @@ -336,7 +338,10 @@ proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) = if enabled: incl(conf.notes, note) else: excl(conf.notes, note) proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = - optHints in conf.options and note in conf.notes + if optHints notin conf.options: false + elif note in {hintConf}: # could add here other special notes like hintSource + note in conf.mainPackageNotes + else: note in conf.notes proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool = optWarns in conf.options and note in conf.notes @@ -556,11 +561,8 @@ proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): Absolute result = conf.outDir / changeFileExt(filename, ext) proc absOutFile*(conf: ConfigRef): AbsoluteFile = - if false: - doAssert not conf.outDir.isEmpty - doAssert not conf.outFile.isEmpty - # xxx: fix this pre-existing bug causing `SuccessX` error messages to lie - # for `jsonscript` + doAssert not conf.outDir.isEmpty + doAssert not conf.outFile.isEmpty result = conf.outDir / conf.outFile when defined(posix): if dirExists(result.string): result.string.add ".out" diff --git a/compiler/passes.nim b/compiler/passes.nim index 9f562d615..615b9ac88 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -113,10 +113,8 @@ const nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt} proc prepareConfigNotes(graph: ModuleGraph; module: PSym) = - if sfMainModule in module.flags: - graph.config.mainPackageId = module.owner.id # don't be verbose unless the module belongs to the main package: - if module.owner.id == graph.config.mainPackageId: + if module.getnimblePkgId == graph.config.mainPackageId: graph.config.notes = graph.config.mainPackageNotes else: if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes From c1ca06b4525b12022a5f8368582549e5bb01a438 Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 4 Jun 2020 06:25:38 -0500 Subject: [PATCH 0632/4254] tfdleak: fix flakyness on Windows (#14550) * tfdleak_multiple: introduce stress tester for tfdleak Imported from #14548 and tweaked for consumption by testament. This test seems to be really good at bringing out the flakyness of tfdleadk. Co-authored-by: Timothee Cour * tfdleak: increase accuracy of the test on Windows This commit implements a new testing strategy for Windows: 1. We duplicate the handle that will be tested and enable inheritance. This duplicate will serve as a reference handle. 2. In addition to checking whether the handle is valid, we also verify whether the handle is the same as the reference. This gives us complete certainty on whether the handle in question is inherited from the parent. A side effect is that this uses Windows 10+ APIs. But since this is just for the test, we don't have to be picky about it. Ideally we would want to do something like this for other POSIX-based system, but most of them lack a facility to do this, and as of writing there isn't any false positive for them, so we won't need the additional checks. MemFile.fHandle will also no longer be tested, as this handle defaults to being invalid. Co-authored-by: Timothee Cour --- tests/stdlib/tfdleak.nim | 45 ++++++++++++++++++++++++++++--- tests/stdlib/tfdleak_multiple.nim | 23 ++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 tests/stdlib/tfdleak_multiple.nim diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim index c4f144db5..5931be8c1 100644 --- a/tests/stdlib/tfdleak.nim +++ b/tests/stdlib/tfdleak.nim @@ -8,16 +8,41 @@ import os, osproc, strutils, nativesockets, net, selectors, memfiles, asyncdispatch, asyncnet when defined(windows): import winlean + + # Note: Windows 10-only API + proc compareObjectHandles(first, second: Handle): WINBOOL + {.stdcall, dynlib: "kernelbase", + importc: "CompareObjectHandles".} else: import posix proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string, expectLeak = defined(nimInheritHandles)) = + var args = @[$f.int, msg, $expectLeak] + + when defined(windows): + var refFd: Handle + # NOTE: This function shouldn't be used to duplicate sockets, + # as this function may mess with the socket internal refcounting. + # but due to the lack of type segmentation in the stdlib for + # Windows (AsyncFD can be a file or a socket), we will have to + # settle with this. + # + # Now, as a poor solution for the refcounting problem, we just + # simply let the duplicated handle leak. This should not interfere + # with the test since new handles can't occupy the slot held by + # the leaked ones. + if duplicateHandle(getCurrentProcess(), f.Handle, + getCurrentProcess(), addr refFd, + 0, 1, DUPLICATE_SAME_ACCESS) == 0: + raiseOSError osLastError(), "Couldn't create the reference handle" + args.add $refFd + discard startProcess( getAppFilename(), - args = @[$f.int, msg, $expectLeak], + args = args, options = {poParentStreams} - ).waitForExit -1 + ).waitForExit proc isValidHandle(f: int): bool = ## Check if a handle is valid. Requires OS-native handles. @@ -72,7 +97,6 @@ proc main() = var mf = memfiles.open("__test_fdleak3", fmReadWrite, newFileSize = 1) defer: close mf when defined(windows): - leakCheck(mf.fHandle, "memfiles.open().fHandle", false) leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false) else: leakCheck(mf.handle, "memfiles.open().handle", false) @@ -105,7 +129,20 @@ proc main() = fd = parseInt(paramStr 1) expectLeak = parseBool(paramStr 3) msg = (if expectLeak: "not " else: "") & "leaked " & paramStr 2 - if expectLeak xor fd.isValidHandle: + let validHandle = + when defined(windows): + # On Windows, due to the use of winlean, causes the program to open + # a handle to the various dlls that's loaded. This handle might + # collide with the handle sent for testing. + # + # As a walkaround, we pass an another handle that's purposefully leaked + # as a reference so that we can verify whether the "leaked" handle + # is the right one. + let refFd = parseInt(paramStr 4) + fd.isValidHandle and compareObjectHandles(fd, refFd) != 0 + else: + fd.isValidHandle + if expectLeak xor validHandle: echo msg when isMainModule: main() diff --git a/tests/stdlib/tfdleak_multiple.nim b/tests/stdlib/tfdleak_multiple.nim new file mode 100644 index 000000000..51d291284 --- /dev/null +++ b/tests/stdlib/tfdleak_multiple.nim @@ -0,0 +1,23 @@ +import os, osproc, strutils + +const Iterations = 200 + +proc testFdLeak() = + var count = 0 + let + test = getAppDir() / "tfdleak" + exe = test.addFileExt(ExeExt).quoteShell + options = ["", "-d:nimInheritHandles"] + for opt in options: + let + run = "nim c $1 $2" % [opt, quoteShell test] + (output, status) = execCmdEx run + doAssert status == 0, "Test complination failed:\n$1\n$2" % [run, output] + for i in 1..Iterations: + let (output, status) = execCmdEx exe + doAssert status == 0, "Execution of " & exe & " failed" + if "leaked" in output: + count.inc + doAssert count == 0, "Leaked " & $count & " times" + +when isMainModule: testFdLeak() From 7cb4ef26addb3bb5ce2405d8396df6fd41664dae Mon Sep 17 00:00:00 2001 From: PMunch Date: Fri, 5 Jun 2020 10:54:38 +0200 Subject: [PATCH 0633/4254] Improve JSON serialisation of strtabs (#14549) This creates a more compact serialisation of strtabs that is more in line with the normal tables. --- lib/pure/json.nim | 35 +++++++++++++++++++++++++++++------ lib/pure/strtabs.nim | 2 +- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index ab03370b5..04e169d30 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -149,7 +149,7 @@ runnableExamples: doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" import - hashes, tables, strutils, lexbase, streams, macros, parsejson, + hashes, tables, strtabs, strutils, lexbase, streams, macros, parsejson, options export @@ -353,6 +353,14 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = assert(obj.kind == JObject) obj.fields[key] = val +proc `%`*(table: StringTableRef): JsonNode = + ## Generic constructor for JSON data. Creates a new ``JObject JsonNode``. + result = newJObject() + result["mode"] = %($table.mode) + var data = newJObject() + for k, v in table: data[k] = %v + result["data"] = data + proc `%`*[T: object](o: T): JsonNode = ## Construct JsonNode from tuples and objects. result = newJObject() @@ -981,11 +989,12 @@ when defined(nimFixedForwardGeneric): proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson(dst: var StringTableRef; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) # initFromJson definitions @@ -1043,7 +1052,7 @@ when defined(nimFixedForwardGeneric): initFromJson(dst[i], jsonNode[i], jsonPath) jsonPath.setLen originalJsonPathLen - proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) = + proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) = dst = initTable[string, T]() verifyJsonKind(jsonNode, {JObject}, jsonPath) let originalJsonPathLen = jsonPath.len @@ -1053,7 +1062,7 @@ when defined(nimFixedForwardGeneric): initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) jsonPath.setLen originalJsonPathLen - proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) = + proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) = dst = initOrderedTable[string,T]() verifyJsonKind(jsonNode, {JObject}, jsonPath) let originalJsonPathLen = jsonPath.len @@ -1063,6 +1072,20 @@ when defined(nimFixedForwardGeneric): initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) jsonPath.setLen originalJsonPathLen + proc mgetOrPut(tab: var StringTableRef, key: string): var string = + if not tab.hasKey(key): tab[key] = "" + result = tab[key] + + proc initFromJson(dst: var StringTableRef; jsonNode: JsonNode; jsonPath: var string) = + dst = newStringTable(parseEnum[StringTableMode](jsonNode["mode"].getStr)) + verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len + for key in keys(jsonNode["data"].fields): + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath) if jsonNode.kind == JNull: diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 26811cc65..cfafdf018 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -71,7 +71,7 @@ type StringTableObj* = object of RootObj counter: int data: KeyValuePairSeq - mode: StringTableMode + mode*: StringTableMode StringTableRef* = ref StringTableObj From 0824fdd06100282a853fa50efb66e2161f4235d8 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 5 Jun 2020 16:15:13 +0200 Subject: [PATCH 0634/4254] fixes #14562 --- compiler/semcall.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c6e12facf..665eb4ea4 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -527,7 +527,10 @@ proc semResolvedCall(c: PContext, x: TCandidate, for s in instantiateGenericParamList(c, gp, x.bindings): case s.kind of skConst: - x.call.add s.ast + if not s.ast.isNil: + x.call.add s.ast + else: + x.call.add c.graph.emptyNode of skType: x.call.add newSymNode(s, n.info) else: From 7cdf4702699b5de0e31e1139122aa0486fad24a9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 5 Jun 2020 19:04:39 -0700 Subject: [PATCH 0635/4254] refs #14545 fix snippet errors: avoid showing confusing errors when they are expected (#14569) --- compiler/docgen.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 0263b36eb..0af830a42 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -17,7 +17,7 @@ import packages/docutils/rst, packages/docutils/rstgen, json, xmltree, cgi, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, trees, tables, nimpaths, renderverbatim + pathutils, trees, tables, nimpaths, renderverbatim, osproc from std/private/globs import nativeToUnixPath @@ -225,8 +225,9 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, ] let cmd = cmd.interpSnippetCmd rawMessage(conf, hintExecuting, cmd) - if execShellCmd(cmd) != status: - rawMessage(conf, errGenerated, "executing of external program failed: " & cmd) + let (output, gotten) = execCmdEx(cmd) + if gotten != status: + rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output]) result.emitted = initIntSet() result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false) result.thisDir = result.destFile.splitFile.dir From b19ad22b90b920036fcc7752eca624e55a929cf3 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Sat, 6 Jun 2020 10:31:19 +0300 Subject: [PATCH 0636/4254] Fix #14570 (#14571) * Fix #14570 --- compiler/jsgen.nim | 2 +- tests/js/t14570.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/js/t14570.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 6aacf818a..0410a7a55 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1822,7 +1822,7 @@ proc genNewSeq(p: PProc, n: PNode) = x.rdLoc, y.rdLoc, createVar(p, t, false)]) proc genOrd(p: PProc, n: PNode, r: var TCompRes) = - case skipTypes(n[1].typ, abstractVar).kind + case skipTypes(n[1].typ, abstractVar + abstractRange).kind of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r) of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)") else: internalError(p.config, n.info, "genOrd") diff --git a/tests/js/t14570.nim b/tests/js/t14570.nim new file mode 100644 index 000000000..100c2651d --- /dev/null +++ b/tests/js/t14570.nim @@ -0,0 +1,11 @@ +discard """ + output: ''' +18 +''' +""" + +type A = range[15 .. 30] + +let a: A = 18 + +echo ord(a) From d573581eb72997e27d91dac82b860964ed706590 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 6 Jun 2020 02:50:46 -0700 Subject: [PATCH 0637/4254] remove isMainModule from json,os,sequtils (#14572) * move json.isMainModule => tjson * move isMainModule => tos,tsequtils --- lib/pure/collections/sequtils.nim | 461 ------------------------------ lib/pure/json.nim | 235 +-------------- lib/pure/os.nim | 63 ---- tests/stdlib/tjson.nim | 234 +++++++++++++++ tests/stdlib/tos.nim | 63 ++++ tests/stdlib/tsequtils.nim | 460 +++++++++++++++++++++++++++++ 6 files changed, 759 insertions(+), 757 deletions(-) create mode 100644 tests/stdlib/tjson.nim create mode 100644 tests/stdlib/tsequtils.nim diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index a89d2c572..f101d508e 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1065,464 +1065,3 @@ iterator items*[T](xs: iterator: T): T = ## templates. for x in xs(): yield x - -when isMainModule: - import strutils - from algorithm import sorted - - # helper for testing double substitution side effects which are handled - # by `evalOnceAs` - var counter = 0 - proc identity[T](a: T): auto = - counter.inc - a - - block: # concat test - let - s1 = @[1, 2, 3] - s2 = @[4, 5] - s3 = @[6, 7] - total = concat(s1, s2, s3) - assert total == @[1, 2, 3, 4, 5, 6, 7] - - block: # count test - let - s1 = @[1, 2, 3, 2] - s2 = @['a', 'b', 'x', 'a'] - a1 = [1, 2, 3, 2] - a2 = ['a', 'b', 'x', 'a'] - r0 = count(s1, 0) - r1 = count(s1, 1) - r2 = count(s1, 2) - r3 = count(s2, 'y') - r4 = count(s2, 'x') - r5 = count(s2, 'a') - ar0 = count(a1, 0) - ar1 = count(a1, 1) - ar2 = count(a1, 2) - ar3 = count(a2, 'y') - ar4 = count(a2, 'x') - ar5 = count(a2, 'a') - assert r0 == 0 - assert r1 == 1 - assert r2 == 2 - assert r3 == 0 - assert r4 == 1 - assert r5 == 2 - assert ar0 == 0 - assert ar1 == 1 - assert ar2 == 2 - assert ar3 == 0 - assert ar4 == 1 - assert ar5 == 2 - - block: # cycle tests - let - a = @[1, 2, 3] - b: seq[int] = @[] - c = [1, 2, 3] - - doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] - doAssert a.cycle(0) == @[] - #doAssert a.cycle(-1) == @[] # will not compile! - doAssert b.cycle(3) == @[] - doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] - doAssert c.cycle(0) == @[] - - block: # repeat tests - assert repeat(10, 5) == @[10, 10, 10, 10, 10] - assert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]] - assert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]] - - block: # deduplicates test - let - dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4] - dup2 = @["a", "a", "c", "d", "d"] - dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4] - dup4 = ["a", "a", "c", "d", "d"] - unique1 = deduplicate(dup1) - unique2 = deduplicate(dup2) - unique3 = deduplicate(dup3) - unique4 = deduplicate(dup4) - unique5 = deduplicate(dup1.sorted, true) - unique6 = deduplicate(dup2, true) - unique7 = deduplicate(dup3.sorted, true) - unique8 = deduplicate(dup4, true) - assert unique1 == @[1, 3, 4, 2, 8] - assert unique2 == @["a", "c", "d"] - assert unique3 == @[1, 3, 4, 2, 8] - assert unique4 == @["a", "c", "d"] - assert unique5 == @[1, 2, 3, 4, 8] - assert unique6 == @["a", "c", "d"] - assert unique7 == @[1, 2, 3, 4, 8] - assert unique8 == @["a", "c", "d"] - - block: # zip test - let - short = @[1, 2, 3] - long = @[6, 5, 4, 3, 2, 1] - words = @["one", "two", "three"] - ashort = [1, 2, 3] - along = [6, 5, 4, 3, 2, 1] - awords = ["one", "two", "three"] - zip1 = zip(short, long) - zip2 = zip(short, words) - zip3 = zip(ashort, along) - assert zip1 == @[(1, 6), (2, 5), (3, 4)] - assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] - assert zip3 == @[(1, 6), (2, 5), (3, 4)] - assert zip1[2][1] == 4 - assert zip2[2][1] == "three" - assert zip3[2][1] == 4 - when (NimMajor, NimMinor) <= (1, 0): - let - # In Nim 1.0.x and older, zip returned a seq of tuple strictly - # with fields named "a" and "b". - zipAb = zip(ashort, awords) - assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] - assert zipAb[2].b == "three" - else: - let - # As zip returns seq of anonymous tuples, they can be assigned - # to any variable that's a sequence of named tuples too. - zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) - zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) - assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] - assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] - assert zipXy[2].y == "three" - assert zipMn[2].n == "three" - - block: # distribute tests - let numbers = @[1, 2, 3, 4, 5, 6, 7] - doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]] - doAssert numbers.distribute(6)[0] == @[1, 2] - doAssert numbers.distribute(6)[5] == @[7] - let a = @[1, 2, 3, 4, 5, 6, 7] - doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]] - doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]] - doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]] - doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]] - doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]] - doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] - doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] - doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] - doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]] - doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]] - doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]] - doAssert a.distribute(6, false) == @[ - @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]] - doAssert a.distribute(8, false) == a.distribute(8, true) - doAssert a.distribute(90, false) == a.distribute(90, true) - var b = @[0] - for f in 1 .. 25: b.add(f) - doAssert b.distribute(5, true)[4].len == 5 - doAssert b.distribute(5, false)[4].len == 2 - - block: # map test - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - m1 = map(numbers, proc(x: int): int = 2*x) - m2 = map(anumbers, proc(x: int): int = 2*x) - assert m1 == @[2, 8, 10, 16, 18, 14, 8] - assert m2 == @[2, 8, 10, 16, 18, 14, 8] - - block: # apply test - var a = @["1", "2", "3", "4"] - apply(a, proc(x: var string) = x &= "42") - assert a == @["142", "242", "342", "442"] - - block: # filter proc test - let - colors = @["red", "yellow", "black"] - acolors = ["red", "yellow", "black"] - f1 = filter(colors, proc(x: string): bool = x.len < 6) - f2 = filter(colors) do (x: string) -> bool: x.len > 5 - f3 = filter(acolors, proc(x: string): bool = x.len < 6) - f4 = filter(acolors) do (x: string) -> bool: x.len > 5 - assert f1 == @["red", "black"] - assert f2 == @["yellow"] - assert f3 == @["red", "black"] - assert f4 == @["yellow"] - - block: # filter iterator test - let numbers = @[1, 4, 5, 8, 9, 7, 4] - let anumbers = [1, 4, 5, 8, 9, 7, 4] - assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == - @[4, 8, 4] - assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) == - @[4, 8, 4] - - block: # keepIf test - var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] - keepIf(floats, proc(x: float): bool = x > 10) - assert floats == @[13.0, 12.5, 10.1] - - block: # delete tests - let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] - var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] - dest.delete(3, 8) - assert outcome == dest, """\ - Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] - is [1,1,1,1,1,1,1,1]""" - var x = @[1, 2, 3] - x.delete(100, 100) - assert x == @[1, 2, 3] - - block: # insert tests - var dest = @[1, 1, 1, 1, 1, 1, 1, 1] - let - src = @[2, 2, 2, 2, 2, 2] - outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] - dest.insert(src, 3) - assert dest == outcome, """\ - Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1] - at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]""" - - block: # filterIt test - let - temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] - acceptable = filterIt(temperatures, it < 50 and it > -10) - notAcceptable = filterIt(temperatures, it > 50 or it < -10) - assert acceptable == @[-2.0, 24.5, 44.31] - assert notAcceptable == @[-272.15, 99.9, -113.44] - - block: # keepItIf test - var candidates = @["foo", "bar", "baz", "foobar"] - keepItIf(candidates, it.len == 3 and it[0] == 'b') - assert candidates == @["bar", "baz"] - - block: # all - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - assert all(numbers, proc (x: int): bool = return x < 10) == true - assert all(numbers, proc (x: int): bool = return x < 9) == false - assert all(len0seq, proc (x: int): bool = return false) == true - assert all(anumbers, proc (x: int): bool = return x < 10) == true - assert all(anumbers, proc (x: int): bool = return x < 9) == false - - block: # allIt - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - assert allIt(numbers, it < 10) == true - assert allIt(numbers, it < 9) == false - assert allIt(len0seq, false) == true - assert allIt(anumbers, it < 10) == true - assert allIt(anumbers, it < 9) == false - - block: # any - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - assert any(numbers, proc (x: int): bool = return x > 8) == true - assert any(numbers, proc (x: int): bool = return x > 9) == false - assert any(len0seq, proc (x: int): bool = return true) == false - assert any(anumbers, proc (x: int): bool = return x > 8) == true - assert any(anumbers, proc (x: int): bool = return x > 9) == false - - block: # anyIt - let - numbers = @[1, 4, 5, 8, 9, 7, 4] - anumbers = [1, 4, 5, 8, 9, 7, 4] - len0seq: seq[int] = @[] - assert anyIt(numbers, it > 8) == true - assert anyIt(numbers, it > 9) == false - assert anyIt(len0seq, true) == false - assert anyIt(anumbers, it > 8) == true - assert anyIt(anumbers, it > 9) == false - - block: # toSeq test - block: - let - numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - oddNumbers = toSeq(filter(numeric) do (x: int) -> bool: - if x mod 2 == 1: - result = true) - assert oddNumbers == @[1, 3, 5, 7, 9] - - block: - doAssert [1, 2].toSeq == @[1, 2] - doAssert @[1, 2].toSeq == @[1, 2] - - doAssert @[1, 2].toSeq == @[1, 2] - doAssert toSeq(@[1, 2]) == @[1, 2] - - block: - iterator myIter(seed: int): auto = - for i in 0...nim") - doAssert not isValidFilename(" foo.log") - # Positive Tests. - doAssert isValidFilename("abcd", maxLen = 42.Positive) - doAssert isValidFilename("c0n") - doAssert isValidFilename("foo.aux") - doAssert isValidFilename("bar.prn") - doAssert isValidFilename("OwO_UwU") - doAssert isValidFilename("cron") - doAssert isValidFilename("ux.bat") - doAssert isValidFilename("nim.nim") - doAssert isValidFilename("foo.log") diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim new file mode 100644 index 000000000..bc7ff02b2 --- /dev/null +++ b/tests/stdlib/tjson.nim @@ -0,0 +1,234 @@ +#[ +Note: Macro tests are in tests/stdlib/tjsonmacro.nim +]# + +import std/[json,parsejson,strutils,streams] + +let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}""" +# nil passthrough +doAssert(testJson{"doesnt_exist"}{"anything"}.isNil) +testJson{["e", "f"]} = %true +doAssert(testJson["e"]["f"].bval) + +# make sure UTF-16 decoding works. +doAssert(testJson["c"].str == "🎃") +doAssert(testJson["d"].str == "æ") + +# make sure no memory leek when parsing invalid string +let startMemory = getOccupiedMem() +for i in 0 .. 10000: + try: + discard parseJson"""{ invalid""" + except: + discard +# memory diff should less than 4M +doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) + + +# test `$` +let stringified = $testJson +let parsedAgain = parseJson(stringified) +doAssert(parsedAgain["b"].str == "asd") + +parsedAgain["abc"] = %5 +doAssert parsedAgain["abc"].num == 5 + +# Bounds checking +when compileOption("boundChecks"): + try: + let a = testJson["a"][9] + doAssert(false, "IndexDefect not thrown") + except IndexDefect: + discard + try: + let a = testJson["a"][-1] + doAssert(false, "IndexDefect not thrown") + except IndexDefect: + discard + try: + doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value") + except: + doAssert(false, "IndexDefect thrown for valid index") + +doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}") +doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") +doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") +doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") +doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found") +doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil") + +# Generator: +var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}] +doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + +var j2 = %* + [ + { + "name": "John", + "age": 30 + }, + { + "name": "Susan", + "age": 31 + } + ] +doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + +var name = "John" +let herAge = 30 +const hisAge = 31 + +var j3 = %* + [ {"name": "John" + , "age": herAge + } + , {"name": "Susan" + , "age": hisAge + } + ] +doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + +var j4 = %*{"test": nil} +doAssert j4 == %{"test": newJNull()} + +let seqOfNodes = @[%1, %2] +let jSeqOfNodes = %seqOfNodes +doAssert(jSeqOfNodes[1].num == 2) + +type MyObj = object + a, b: int + s: string + f32: float32 + f64: float64 + next: ref MyObj +var m: MyObj +m.s = "hi" +m.a = 5 +let jMyObj = %m +doAssert(jMyObj["a"].num == 5) +doAssert(jMyObj["s"].str == "hi") + +# Test loading of file. +when not defined(js): + var parsed = parseFile("tests/testdata/jsontest.json") + + try: + discard parsed["key2"][12123] + doAssert(false) + except IndexDefect: doAssert(true) + + var parsed2 = parseFile("tests/testdata/jsontest2.json") + doAssert(parsed2{"repository", "description"}.str == + "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}") + +doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ" +doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887 +doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\"" +doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887 + +# Test with extra data +when not defined(js): + try: + discard parseJson("123 456") + doAssert(false) + except JsonParsingError: + doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected]) + + try: + discard parseFile("tests/testdata/jsonwithextradata.json") + doAssert(false) + except JsonParsingError: + doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected]) + +# bug #6438 +doAssert($ %*[] == "[]") +doAssert($ %*{} == "{}") + +doAssert(not compiles(%{"error": "No messages"})) + +# bug #9111 +block: + type + Bar = string + Foo = object + a: int + b: Bar + + let + js = """{"a": 123, "b": "abc"}""".parseJson + foo = js.to Foo + + doAssert(foo.b == "abc") + +# Generate constructors for range[T] types +block: + type + Q1 = range[0'u8 .. 50'u8] + Q2 = range[0'u16 .. 50'u16] + Q3 = range[0'u32 .. 50'u32] + Q4 = range[0'i8 .. 50'i8] + Q5 = range[0'i16 .. 50'i16] + Q6 = range[0'i32 .. 50'i32] + Q7 = range[0'f32 .. 50'f32] + Q8 = range[0'f64 .. 50'f64] + Q9 = range[0 .. 50] + + X = object + m1: Q1 + m2: Q2 + m3: Q3 + m4: Q4 + m5: Q5 + m6: Q6 + m7: Q7 + m8: Q8 + m9: Q9 + + let obj = X( + m1: Q1(42), + m2: Q2(42), + m3: Q3(42), + m4: Q4(42), + m5: Q5(42), + m6: Q6(42), + m7: Q7(42), + m8: Q8(42), + m9: Q9(42) + ) + + doAssert(obj == to(%obj, type(obj))) + + when not defined(js): + const fragments = """[1,2,3] {"hi":3} 12 [] """ + var res = "" + for x in parseJsonFragments(newStringStream(fragments)): + res.add($x) + res.add " " + doAssert res == fragments + + +# test isRefSkipDistinct +type + MyRef = ref object + MyObject = object + MyDistinct = distinct MyRef + MyOtherDistinct = distinct MyRef + +var x0: ref int +var x1: MyRef +var x2: MyObject +var x3: MyDistinct +var x4: MyOtherDistinct + +doAssert isRefSkipDistinct(x0) +doAssert isRefSkipDistinct(x1) +doAssert not isRefSkipDistinct(x2) +doAssert isRefSkipDistinct(x3) +doAssert isRefSkipDistinct(x4) + + +doAssert isRefSkipDistinct(ref int) +doAssert isRefSkipDistinct(MyRef) +doAssert not isRefSkipDistinct(MyObject) +doAssert isRefSkipDistinct(MyDistinct) +doAssert isRefSkipDistinct(MyOtherDistinct) diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 20e82173d..a440d86d8 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -447,3 +447,66 @@ block isRelativeTo: doAssert isRelativeTo("foo/bar", ".") doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim") doAssert not isRelativeTo("/foo2", "/foo") + +block: # quoteShellWindows + assert quoteShellWindows("aaa") == "aaa" + assert quoteShellWindows("aaa\"") == "aaa\\\"" + assert quoteShellWindows("") == "\"\"" + +block: # quoteShellWindows + assert quoteShellPosix("aaa") == "aaa" + assert quoteShellPosix("aaa a") == "'aaa a'" + assert quoteShellPosix("") == "''" + assert quoteShellPosix("a'a") == "'a'\"'\"'a'" + +block: # quoteShell + when defined(posix): + assert quoteShell("") == "''" + +block: # normalizePathEnd + # handle edge cases correctly: shouldn't affect whether path is + # absolute/relative + doAssert "".normalizePathEnd(true) == "" + doAssert "".normalizePathEnd(false) == "" + doAssert "/".normalizePathEnd(true) == $DirSep + doAssert "/".normalizePathEnd(false) == $DirSep + + when defined(posix): + doAssert "//".normalizePathEnd(false) == "/" + doAssert "foo.bar//".normalizePathEnd == "foo.bar" + doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/" + when defined(Windows): + doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo" + doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\" + # this one is controversial: we could argue for returning `D:\` instead, + # but this is simplest. + doAssert r"D:\".normalizePathEnd == r"D:" + doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\" + doAssert "/".normalizePathEnd == r"\" + +block: # isValidFilename + # Negative Tests. + doAssert not isValidFilename("abcd", maxLen = 2) + doAssert not isValidFilename("0123456789", maxLen = 8) + doAssert not isValidFilename("con") + doAssert not isValidFilename("aux") + doAssert not isValidFilename("prn") + doAssert not isValidFilename("OwO|UwU") + doAssert not isValidFilename(" foo") + doAssert not isValidFilename("foo ") + doAssert not isValidFilename("foo.") + doAssert not isValidFilename("con.txt") + doAssert not isValidFilename("aux.bat") + doAssert not isValidFilename("prn.exe") + doAssert not isValidFilename("nim>.nim") + doAssert not isValidFilename(" foo.log") + # Positive Tests. + doAssert isValidFilename("abcd", maxLen = 42.Positive) + doAssert isValidFilename("c0n") + doAssert isValidFilename("foo.aux") + doAssert isValidFilename("bar.prn") + doAssert isValidFilename("OwO_UwU") + doAssert isValidFilename("cron") + doAssert isValidFilename("ux.bat") + doAssert isValidFilename("nim.nim") + doAssert isValidFilename("foo.log") diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim new file mode 100644 index 000000000..ea3f06982 --- /dev/null +++ b/tests/stdlib/tsequtils.nim @@ -0,0 +1,460 @@ +import std/sequtils +import strutils +from algorithm import sorted + +# helper for testing double substitution side effects which are handled +# by `evalOnceAs` +var counter = 0 +proc identity[T](a: T): auto = + counter.inc + a + +block: # concat test + let + s1 = @[1, 2, 3] + s2 = @[4, 5] + s3 = @[6, 7] + total = concat(s1, s2, s3) + assert total == @[1, 2, 3, 4, 5, 6, 7] + +block: # count test + let + s1 = @[1, 2, 3, 2] + s2 = @['a', 'b', 'x', 'a'] + a1 = [1, 2, 3, 2] + a2 = ['a', 'b', 'x', 'a'] + r0 = count(s1, 0) + r1 = count(s1, 1) + r2 = count(s1, 2) + r3 = count(s2, 'y') + r4 = count(s2, 'x') + r5 = count(s2, 'a') + ar0 = count(a1, 0) + ar1 = count(a1, 1) + ar2 = count(a1, 2) + ar3 = count(a2, 'y') + ar4 = count(a2, 'x') + ar5 = count(a2, 'a') + assert r0 == 0 + assert r1 == 1 + assert r2 == 2 + assert r3 == 0 + assert r4 == 1 + assert r5 == 2 + assert ar0 == 0 + assert ar1 == 1 + assert ar2 == 2 + assert ar3 == 0 + assert ar4 == 1 + assert ar5 == 2 + +block: # cycle tests + let + a = @[1, 2, 3] + b: seq[int] = @[] + c = [1, 2, 3] + + doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] + doAssert a.cycle(0) == @[] + #doAssert a.cycle(-1) == @[] # will not compile! + doAssert b.cycle(3) == @[] + doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3] + doAssert c.cycle(0) == @[] + +block: # repeat tests + assert repeat(10, 5) == @[10, 10, 10, 10, 10] + assert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]] + assert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]] + +block: # deduplicates test + let + dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4] + dup2 = @["a", "a", "c", "d", "d"] + dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4] + dup4 = ["a", "a", "c", "d", "d"] + unique1 = deduplicate(dup1) + unique2 = deduplicate(dup2) + unique3 = deduplicate(dup3) + unique4 = deduplicate(dup4) + unique5 = deduplicate(dup1.sorted, true) + unique6 = deduplicate(dup2, true) + unique7 = deduplicate(dup3.sorted, true) + unique8 = deduplicate(dup4, true) + assert unique1 == @[1, 3, 4, 2, 8] + assert unique2 == @["a", "c", "d"] + assert unique3 == @[1, 3, 4, 2, 8] + assert unique4 == @["a", "c", "d"] + assert unique5 == @[1, 2, 3, 4, 8] + assert unique6 == @["a", "c", "d"] + assert unique7 == @[1, 2, 3, 4, 8] + assert unique8 == @["a", "c", "d"] + +block: # zip test + let + short = @[1, 2, 3] + long = @[6, 5, 4, 3, 2, 1] + words = @["one", "two", "three"] + ashort = [1, 2, 3] + along = [6, 5, 4, 3, 2, 1] + awords = ["one", "two", "three"] + zip1 = zip(short, long) + zip2 = zip(short, words) + zip3 = zip(ashort, along) + assert zip1 == @[(1, 6), (2, 5), (3, 4)] + assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] + assert zip3 == @[(1, 6), (2, 5), (3, 4)] + assert zip1[2][1] == 4 + assert zip2[2][1] == "three" + assert zip3[2][1] == 4 + when (NimMajor, NimMinor) <= (1, 0): + let + # In Nim 1.0.x and older, zip returned a seq of tuple strictly + # with fields named "a" and "b". + zipAb = zip(ashort, awords) + assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] + assert zipAb[2].b == "three" + else: + let + # As zip returns seq of anonymous tuples, they can be assigned + # to any variable that's a sequence of named tuples too. + zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) + zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) + assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] + assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] + assert zipXy[2].y == "three" + assert zipMn[2].n == "three" + +block: # distribute tests + let numbers = @[1, 2, 3, 4, 5, 6, 7] + doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]] + doAssert numbers.distribute(6)[0] == @[1, 2] + doAssert numbers.distribute(6)[5] == @[7] + let a = @[1, 2, 3, 4, 5, 6, 7] + doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]] + doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]] + doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]] + doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]] + doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]] + doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] + doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] + doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] + doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]] + doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]] + doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]] + doAssert a.distribute(6, false) == @[ + @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]] + doAssert a.distribute(8, false) == a.distribute(8, true) + doAssert a.distribute(90, false) == a.distribute(90, true) + var b = @[0] + for f in 1 .. 25: b.add(f) + doAssert b.distribute(5, true)[4].len == 5 + doAssert b.distribute(5, false)[4].len == 2 + +block: # map test + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + m1 = map(numbers, proc(x: int): int = 2*x) + m2 = map(anumbers, proc(x: int): int = 2*x) + assert m1 == @[2, 8, 10, 16, 18, 14, 8] + assert m2 == @[2, 8, 10, 16, 18, 14, 8] + +block: # apply test + var a = @["1", "2", "3", "4"] + apply(a, proc(x: var string) = x &= "42") + assert a == @["142", "242", "342", "442"] + +block: # filter proc test + let + colors = @["red", "yellow", "black"] + acolors = ["red", "yellow", "black"] + f1 = filter(colors, proc(x: string): bool = x.len < 6) + f2 = filter(colors) do (x: string) -> bool: x.len > 5 + f3 = filter(acolors, proc(x: string): bool = x.len < 6) + f4 = filter(acolors) do (x: string) -> bool: x.len > 5 + assert f1 == @["red", "black"] + assert f2 == @["yellow"] + assert f3 == @["red", "black"] + assert f4 == @["yellow"] + +block: # filter iterator test + let numbers = @[1, 4, 5, 8, 9, 7, 4] + let anumbers = [1, 4, 5, 8, 9, 7, 4] + assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == + @[4, 8, 4] + assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) == + @[4, 8, 4] + +block: # keepIf test + var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] + keepIf(floats, proc(x: float): bool = x > 10) + assert floats == @[13.0, 12.5, 10.1] + +block: # delete tests + let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] + var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] + dest.delete(3, 8) + assert outcome == dest, """\ + Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] + is [1,1,1,1,1,1,1,1]""" + var x = @[1, 2, 3] + x.delete(100, 100) + assert x == @[1, 2, 3] + +block: # insert tests + var dest = @[1, 1, 1, 1, 1, 1, 1, 1] + let + src = @[2, 2, 2, 2, 2, 2] + outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] + dest.insert(src, 3) + assert dest == outcome, """\ + Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1] + at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]""" + +block: # filterIt test + let + temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] + acceptable = filterIt(temperatures, it < 50 and it > -10) + notAcceptable = filterIt(temperatures, it > 50 or it < -10) + assert acceptable == @[-2.0, 24.5, 44.31] + assert notAcceptable == @[-272.15, 99.9, -113.44] + +block: # keepItIf test + var candidates = @["foo", "bar", "baz", "foobar"] + keepItIf(candidates, it.len == 3 and it[0] == 'b') + assert candidates == @["bar", "baz"] + +block: # all + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert all(numbers, proc (x: int): bool = return x < 10) == true + assert all(numbers, proc (x: int): bool = return x < 9) == false + assert all(len0seq, proc (x: int): bool = return false) == true + assert all(anumbers, proc (x: int): bool = return x < 10) == true + assert all(anumbers, proc (x: int): bool = return x < 9) == false + +block: # allIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert allIt(numbers, it < 10) == true + assert allIt(numbers, it < 9) == false + assert allIt(len0seq, false) == true + assert allIt(anumbers, it < 10) == true + assert allIt(anumbers, it < 9) == false + +block: # any + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert any(numbers, proc (x: int): bool = return x > 8) == true + assert any(numbers, proc (x: int): bool = return x > 9) == false + assert any(len0seq, proc (x: int): bool = return true) == false + assert any(anumbers, proc (x: int): bool = return x > 8) == true + assert any(anumbers, proc (x: int): bool = return x > 9) == false + +block: # anyIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + assert anyIt(numbers, it > 8) == true + assert anyIt(numbers, it > 9) == false + assert anyIt(len0seq, true) == false + assert anyIt(anumbers, it > 8) == true + assert anyIt(anumbers, it > 9) == false + +block: # toSeq test + block: + let + numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + oddNumbers = toSeq(filter(numeric) do (x: int) -> bool: + if x mod 2 == 1: + result = true) + assert oddNumbers == @[1, 3, 5, 7, 9] + + block: + doAssert [1, 2].toSeq == @[1, 2] + doAssert @[1, 2].toSeq == @[1, 2] + + doAssert @[1, 2].toSeq == @[1, 2] + doAssert toSeq(@[1, 2]) == @[1, 2] + + block: + iterator myIter(seed: int): auto = + for i in 0.. Date: Sat, 6 Jun 2020 12:20:11 +0200 Subject: [PATCH 0638/4254] Fix asynchttpserver newline breaking content-length (#14565) [backport] --- lib/pure/asynchttpserver.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 7fbbf38ea..afd452b01 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -105,8 +105,9 @@ proc respond*(req: Request, code: HttpCode, content: string, msg.add("Content-Length: ") # this particular way saves allocations: msg.addInt content.len - - msg.add "\c\L\c\L" + msg.add "\c\L" + + msg.add "\c\L" msg.add(content) result = req.client.send(msg) From 336f1e63d0186ab283fdb9868a8f7d8d05293a31 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 6 Jun 2020 20:08:25 +0200 Subject: [PATCH 0639/4254] reorder.nim: fixes the indentation --- compiler/reorder.nim | 79 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 631806587..5e380a199 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -100,10 +100,9 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev for i in 0.. Date: Sat, 6 Jun 2020 11:15:24 -0700 Subject: [PATCH 0640/4254] fix #14576 addr of param (including for lent) now works with nim js (#14577) * fix #14576 addr(param) now works in nim js * workaround https://github.com/nim-lang/Nim/issues/14578 --- compiler/ccgexprs.nim | 1 + compiler/jsgen.nim | 11 ++++++-- tests/js/taddr.nim | 62 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ec54081a2..2850ab750 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -141,6 +141,7 @@ proc genSetNode(p: BProc, n: PNode): Rope = result = genRawSetData(cs, size) proc getStorageLoc(n: PNode): TStorageLoc = + ## deadcode case n.kind of nkSym: case n.sym.kind diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0410a7a55..9f022882b 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1065,8 +1065,11 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc]) elif b.typ == etyBaseIndex: lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) + elif b.typ == etyNone: + internalAssert p.config, b.address == nil + lineF(p, "$# = [$#, 0];$n", [a.address, b.res]) else: - internalError(p.config, x.info, "genAsgn") + internalError(p.config, x.info, $("genAsgn", b.typ, a.typ)) else: lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) else: @@ -1266,6 +1269,10 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = let s = n[0].sym if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") case s.kind + of skParam: + r.res = s.loc.r + r.address = nil + r.typ = etyNone of skVar, skLet, skResult: r.kind = resExpr let jsType = mapType(p, n.typ) @@ -1287,7 +1294,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = # 'var openArray' for instance produces an 'addr' but this is harmless: gen(p, n[0], r) #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n)) - else: internalError(p.config, n.info, "genAddr: 2") + else: internalError(p.config, n.info, $("genAddr: 2", s.kind)) of nkCheckedFieldExpr: genCheckedFieldOp(p, n[0], n.typ, r) of nkDotExpr: diff --git a/tests/js/taddr.nim b/tests/js/taddr.nim index d8ff4c11b..9c45621a8 100644 --- a/tests/js/taddr.nim +++ b/tests/js/taddr.nim @@ -1,5 +1,5 @@ discard """ - action: run + targets: "c js" """ type T = object @@ -77,3 +77,63 @@ let someGlobalPtr = getSomeGlobalPtr() doAssert(someGlobalPtr[] == 5) someGlobalPtr[] = 10 doAssert(someGlobal == 10) + +block: + # issue #14576 + # lots of these used to give: Error: internal error: genAddr: 2 + proc byLent[T](a: T): lent T = a + proc byPtr[T](a: T): ptr T = a.unsafeAddr + + block: + let a = (10,11) + let (x,y) = byLent(a) + doAssert (x,y) == a + + block: + when defined(c) and defined(release): + # bug; pending https://github.com/nim-lang/Nim/issues/14578 + discard + else: + let a = 10 + doAssert byLent(a) == 10 + let a2 = byLent(a) + doAssert a2 == 10 + + block: + let a = [11,12] + doAssert byLent(a) == [11,12] + let a2 = (11,) + doAssert byLent(a2) == (11,) + + block: + when defined(c) and defined(release): + discard # probably not a bug since optimizer is free to pass by value, and `unsafeAddr` is used + else: + var a = @[12] + doAssert byPtr(a)[] == @[12] + let a2 = [13] + doAssert byPtr(a2)[] == [13] + let a3 = 14 + doAssert byPtr(a3)[] == 14 + + block: + proc byLent2[T](a: seq[T]): lent T = a[1] + var a = @[20,21,22] + doAssert byLent2(a) == 21 + + block: # sanity checks + proc bar[T](a: var T): var T = a + var a = (10, 11) + let (k,v) = bar(a) + doAssert (k, v) == a + doAssert k == 10 + bar(a)[0]+=100 + doAssert a == (110, 11) + var a2 = 12 + doAssert bar(a2) == a2 + bar(a2).inc + doAssert a2 == 13 + + block: # xxx: bug this doesn't work + when false: + proc byLent2[T](a: T): lent type(a[0]) = a[0] From 82092b3bb7ead1414f673ed7f43e9fa1dcf8c5f4 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 1 Jun 2020 17:10:02 -0500 Subject: [PATCH 0641/4254] asyncnet, net: call SSL_shutdown only when connection established This commit prevents "SSL_shutdown while in init" errors from happening. See https://github.com/openssl/openssl/issues/710#issuecomment-253897666 --- lib/pure/asyncnet.nim | 9 ++++++++- lib/pure/net.nim | 22 +++++++++++++--------- lib/wrappers/openssl.nim | 28 ++++++++++++++++++++++++++++ tests/stdlib/thttpclient_ssl.nim | 5 +++-- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 7ccb469cf..8df839c14 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -713,7 +713,14 @@ proc close*(socket: AsyncSocket) = socket.fd.AsyncFD.closeSocket() when defineSsl: if socket.isSsl: - let res = SSL_shutdown(socket.sslHandle) + let res = + # Don't call SSL_shutdown if the connection has not been fully + # established, see: + # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 + if SSL_in_init(socket.sslHandle) == 0: + SSL_shutdown(socket.sslHandle) + else: + 0 SSL_free(socket.sslHandle) if res == 0: discard diff --git a/lib/pure/net.nim b/lib/pure/net.nim index b08629a96..f7aacfb0c 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1007,15 +1007,19 @@ proc close*(socket: Socket) = when defineSsl: if socket.isSsl and socket.sslHandle != nil: ErrClearError() - # As we are closing the underlying socket immediately afterwards, - # it is valid, under the TLS standard, to perform a unidirectional - # shutdown i.e not wait for the peers "close notify" alert with a second - # call to SSL_shutdown - let res = SSL_shutdown(socket.sslHandle) - if res == 0: - discard - elif res != 1: - socketError(socket, res) + # Don't call SSL_shutdown if the connection has not been fully + # established, see: + # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 + if SSL_in_init(socket.sslHandle) == 0: + # As we are closing the underlying socket immediately afterwards, + # it is valid, under the TLS standard, to perform a unidirectional + # shutdown i.e not wait for the peers "close notify" alert with a second + # call to SSL_shutdown + let res = SSL_shutdown(socket.sslHandle) + if res == 0: + discard + elif res != 1: + socketError(socket, res) finally: when defineSsl: if socket.isSsl and socket.sslHandle != nil: diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 5aaa0a0e8..5fd4def0b 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -201,6 +201,9 @@ const SSL_OP_ALL* = 0x000FFFFF SSL_VERIFY_NONE* = 0x00000000 SSL_VERIFY_PEER* = 0x00000001 + SSL_ST_CONNECT* = 0x1000 + SSL_ST_ACCEPT* = 0x2000 + SSL_ST_INIT* = SSL_ST_CONNECT or SSL_ST_ACCEPT OPENSSL_DES_DECRYPT* = 0 OPENSSL_DES_ENCRYPT* = 1 X509_V_OK* = 0 @@ -282,6 +285,13 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): # Static linking against OpenSSL < 1.1.0 is not supported discard + when defined(libressl) or defined(openssl10): + proc SSL_state(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.} + proc SSL_in_init*(ssl: SslPtr): cint {.inline.} = + SSl_state(ssl) and SSL_ST_INIT + else: + proc SSL_in_init*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.} + template OpenSSL_add_all_algorithms*() = discard proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} @@ -382,6 +392,24 @@ else: if theProc.isNil: 0.culong else: theProc() + proc SSL_in_init*(ssl: SslPtr): cint = + # A compatibility wrapper for `SSL_in_init()` for OpenSSL 1.0, 1.1 and LibreSSL + const MainProc = "SSL_in_init" + let + theProc {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl.}](sslSymNullable(MainProc)) + # Fallback + sslState {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl.}](sslSymNullable("SSL_state")) + + # FIXME: This shouldn't be needed, but the compiler is complaining about + # `sslState` being GC-ed memory??? + {.gcsafe.}: + if not theProc.isNil: + theProc(ssl) + elif not sslState.isNil: + sslState(ssl) and SSL_ST_INIT + else: + raiseInvalidLibrary MainProc + proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index 2e9d1c5be..f06c1eddd 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -124,7 +124,8 @@ when not defined(windows): let msg = getCurrentExceptionMsg() log "client: exception: " & msg # SSL_shutdown:shutdown while in init - if not (msg.contains("shutdown while in init") or msg.contains("alert number 48") or - msg.contains("routines:CONNECT_CR_CERT:certificate verify failed")): + if not (msg.contains("alert number 48") or + msg.contains("routines:CONNECT_CR_CERT:certificate verify failed") or + msg.contains("routines:tls_process_server_certificate:certificate verify failed")): echo "CVerifyPeer exception: " & msg check(false) From 19ccc5fd8d7e187dde0f9190532d7a168bec9572 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 1 Jun 2020 17:48:12 -0500 Subject: [PATCH 0642/4254] untestable/thttpclient_ssl: catch errors caused by the bad catergory Previously the errors caused by `SSL_shutdown()` masked these, so now we catch them. --- tests/untestable/thttpclient_ssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim index 353567085..a27da6d5c 100644 --- a/tests/untestable/thttpclient_ssl.nim +++ b/tests/untestable/thttpclient_ssl.nim @@ -106,7 +106,7 @@ template evaluate(exception_msg: string, category: Category, desc: string) = exception_msg == "SSL Certificate check failed." or exception_msg.contains("certificate verify failed") or exception_msg.contains("key too small") or - exception_msg.contains "shutdown while in init", exception_msg + exception_msg.contains "alert handshake failure", exception_msg else: # this is unexpected From df91f61e2091164eb5afdd2c88367cf48a042998 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 1 Jun 2020 17:58:55 -0500 Subject: [PATCH 0643/4254] untestable/thttpclient_ssl: fix 10000-sans test --- tests/untestable/thttpclient_ssl.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim index a27da6d5c..2c3c3b4bb 100644 --- a/tests/untestable/thttpclient_ssl.nim +++ b/tests/untestable/thttpclient_ssl.nim @@ -106,7 +106,9 @@ template evaluate(exception_msg: string, category: Category, desc: string) = exception_msg == "SSL Certificate check failed." or exception_msg.contains("certificate verify failed") or exception_msg.contains("key too small") or - exception_msg.contains "alert handshake failure", exception_msg + exception_msg.contains("alert handshake failure") or + # TODO: This one should only triggers for 10000-sans + exception_msg.contains("excessive message size"), exception_msg else: # this is unexpected From 65b350f11246654f2b04a9a606a731ba0b9a72c5 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 1 Jun 2020 18:15:11 -0500 Subject: [PATCH 0644/4254] untestable/thttpclient_ssl: fix macos --- tests/untestable/thttpclient_ssl.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim index 2c3c3b4bb..624573a80 100644 --- a/tests/untestable/thttpclient_ssl.nim +++ b/tests/untestable/thttpclient_ssl.nim @@ -107,6 +107,7 @@ template evaluate(exception_msg: string, category: Category, desc: string) = exception_msg.contains("certificate verify failed") or exception_msg.contains("key too small") or exception_msg.contains("alert handshake failure") or + exception_msg.contains("bad dh p length") or # TODO: This one should only triggers for 10000-sans exception_msg.contains("excessive message size"), exception_msg From d06e6eec79c68f8e9bf87c89fc770ca7722c4728 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 1 Jun 2020 20:32:42 -0500 Subject: [PATCH 0645/4254] net: don't clear all errors on close Closing a socket clears the error queue of the entire thread, which seems to be a bit too invasive. Also I don't find any reason in the PR that added this. --- lib/pure/net.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f7aacfb0c..d807a5112 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1006,7 +1006,6 @@ proc close*(socket: Socket) = try: when defineSsl: if socket.isSsl and socket.sslHandle != nil: - ErrClearError() # Don't call SSL_shutdown if the connection has not been fully # established, see: # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 From 44d0b4bdfd95a420946d287adacd762bd12ce646 Mon Sep 17 00:00:00 2001 From: Leorize Date: Mon, 1 Jun 2020 21:20:14 -0500 Subject: [PATCH 0646/4254] thttpclient_ssl: be less specific The error we're looking for is "certificate verify failed". The routine that reports this will be different between openssl versions, so it makes no sense to track the routine name as well. --- tests/stdlib/thttpclient_ssl.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index f06c1eddd..9872985e4 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -125,7 +125,6 @@ when not defined(windows): log "client: exception: " & msg # SSL_shutdown:shutdown while in init if not (msg.contains("alert number 48") or - msg.contains("routines:CONNECT_CR_CERT:certificate verify failed") or - msg.contains("routines:tls_process_server_certificate:certificate verify failed")): + msg.contains("certificate verify failed")): echo "CVerifyPeer exception: " & msg check(false) From 19ccce2617116270c5a83324f5f442fa7d239ee8 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 13:42:12 -0500 Subject: [PATCH 0647/4254] Revert "net: don't clear all errors on close" You're supposed to clear the error queue before any I/O operations. Per SSL_get_error(3) man page. This reverts commit ee3ed37300743addb1344e39bc46d3cd2b89a718. --- lib/pure/net.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d807a5112..f7aacfb0c 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1006,6 +1006,7 @@ proc close*(socket: Socket) = try: when defineSsl: if socket.isSsl and socket.sslHandle != nil: + ErrClearError() # Don't call SSL_shutdown if the connection has not been fully # established, see: # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 From 78982b52f035904de0ba2b90f6e4cb43fb76e300 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 13:43:17 -0500 Subject: [PATCH 0648/4254] net: don't clear error queue unless shutdown() will be performed --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f7aacfb0c..1442e8544 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1006,7 +1006,6 @@ proc close*(socket: Socket) = try: when defineSsl: if socket.isSsl and socket.sslHandle != nil: - ErrClearError() # Don't call SSL_shutdown if the connection has not been fully # established, see: # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 @@ -1015,6 +1014,7 @@ proc close*(socket: Socket) = # it is valid, under the TLS standard, to perform a unidirectional # shutdown i.e not wait for the peers "close notify" alert with a second # call to SSL_shutdown + ErrClearError() let res = SSL_shutdown(socket.sslHandle) if res == 0: discard From f243f9aeb5c5ef6f59efadbee81feb918a20fae8 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 14:51:05 -0500 Subject: [PATCH 0649/4254] openssl: fix erroneous function signatures Now matches the declaration in openssl/err.h --- lib/pure/net.nim | 2 -- lib/wrappers/openssl.nim | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 1442e8544..c60caab08 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -479,8 +479,6 @@ when defineSsl: let err = ERR_peek_last_error() if err == 0: raise newException(SslError, "No error reported.") - if err == -1: - raiseOSError(osLastError()) var errStr = $ERR_error_string(err, nil) case err of 336032814, 336032784: diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 5fd4def0b..01c53b755 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -478,10 +478,10 @@ proc BIO_free*(b: BIO): cint{.cdecl, dynlib: DLLUtilName, importc.} proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLSSLName, importc.} -proc ERR_error_string*(e: cint, buf: cstring): cstring{.cdecl, +proc ERR_error_string*(e: culong, buf: cstring): cstring{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_get_error*(): cint{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_peek_last_error*(): cint{.cdecl, dynlib: DLLUtilName, importc.} +proc ERR_get_error*(): culong{.cdecl, dynlib: DLLUtilName, importc.} +proc ERR_peek_last_error*(): culong{.cdecl, dynlib: DLLUtilName, importc.} proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.} From 6cb94b5da6ac409915cc0ca3f50c50214edee0ef Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 15:11:10 -0500 Subject: [PATCH 0650/4254] asyncnet, net: clear openssl error queue before performing I/O Per SSL_get_error(3): The current thread's error queue must be empty before the TLS/SSL I/O operation is attempted, or SSL_get_error() will not work reliably. There has been records of not clearing the error queue causing weird SSL errors when there shouldn't be any, see: https://github.com/openssl/openssl/issues/11889 --- lib/pure/asyncnet.nim | 1 + lib/pure/net.nim | 7 +++++++ tests/stdlib/thttpclient_ssl.nim | 1 + 3 files changed, 9 insertions(+) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 8df839c14..bd9cd4312 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -718,6 +718,7 @@ proc close*(socket: AsyncSocket) = # established, see: # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 if SSL_in_init(socket.sslHandle) == 0: + ErrClearError() SSL_shutdown(socket.sslHandle) else: 0 diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c60caab08..af66c3a15 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -752,12 +752,14 @@ when defineSsl: # Discard result in case OpenSSL version doesn't support SNI, or we're # not using TLSv1+ discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) + ErrClearError() let ret = SSL_connect(socket.sslHandle) socketError(socket, ret) when not defined(nimDisableCertificateValidation) and not defined(windows): if hostname.len > 0 and not isIpAddress(hostname): socket.checkCertName(hostname) of handshakeAsServer: + ErrClearError() let ret = SSL_accept(socket.sslHandle) socketError(socket, ret) @@ -926,6 +928,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, # We must wrap the client sock in a ssl context. server.sslContext.wrapSocket(client) + ErrClearError() let ret = SSL_accept(client.sslHandle) socketError(client, ret, false) @@ -955,6 +958,7 @@ when false: #defineSsl: if not client.isSsl or client.sslHandle == nil: server.sslContext.wrapSocket(client) + ErrClearError() let ret = SSL_accept(client.sslHandle) while ret <= 0: let err = SSL_get_error(client.sslHandle, ret) @@ -1135,6 +1139,7 @@ proc uniRecv(socket: Socket, buffer: pointer, size, flags: cint): int = assert(not socket.isClosed, "Cannot `recv` on a closed socket") when defineSsl: if socket.isSsl: + ErrClearError() return SSL_read(socket.sslHandle, buffer, size) return recv(socket.fd, buffer, size, flags) @@ -1484,6 +1489,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {. assert(not socket.isClosed, "Cannot `send` on a closed socket") when defineSsl: if socket.isSsl: + ErrClearError() return SSL_write(socket.sslHandle, cast[cstring](data), size) when useWinVersion or defined(macosx): @@ -1768,6 +1774,7 @@ proc connect*(socket: Socket, address: string, # not using TLSv1+ discard SSL_set_tlsext_host_name(socket.sslHandle, address) + ErrClearError() let ret = SSL_connect(socket.sslHandle) socketError(socket, ret) when not defined(nimDisableCertificateValidation) and not defined(windows): diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index 9872985e4..71745c9df 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -61,6 +61,7 @@ when not defined(windows): var ssl: SslPtr = SSL_new(ctx.context) discard SSL_set_fd(ssl, client.getFd()) log "server: accepting connection" + ErrClearError() if SSL_accept(ssl) <= 0: ERR_print_errors_fp(stderr) else: From 1fb2a58674dd8136b246c7499cd295e85484d8c3 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 17:02:18 -0500 Subject: [PATCH 0651/4254] net: use a secure cipher list by default Previously, the `net` module use the blanket "ALL" as the default cipher list. This list may contain security ciphers that are weak and/or outdated according to the current standard. This commit introduces a new module `ssl_config` that contains the latest OpenSSL configurations as recommended by Mozilla OpSec, and make the `net` module use the cipher list targeting `intermediate` compatibility level as the default. --- changelog.md | 9 ++++++ lib/pure/net.nim | 3 +- lib/pure/ssl_config.nim | 51 +++++++++++++++++++++++++++++ tools/ssl_config_parser.nim | 62 ++++++++++++++++++++++++++++++++++++ tools/ssl_config_parser.nims | 1 + 5 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 lib/pure/ssl_config.nim create mode 100644 tools/ssl_config_parser.nim create mode 100644 tools/ssl_config_parser.nims diff --git a/changelog.md b/changelog.md index 25fc3535c..e20077feb 100644 --- a/changelog.md +++ b/changelog.md @@ -99,6 +99,15 @@ - `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` parameters. +- Add `ssl_config` module containing lists of secure ciphers as recommended by + [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) + +- `net.newContext` now uses the list of ciphers targeting + ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) + per Mozilla's recommendation instead of `ALL`. This change should protect + users from the use of weak and insecure ciphers while still provides + adequate compatiblity with the majority of the Internet. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index af66c3a15..a5643330e 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -68,6 +68,7 @@ import std/private/since import nativesockets, os, strutils, times, sets, options, std/monotimes from ssl_certs import scanSSLCertificates +import ssl_config export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol @@ -533,7 +534,7 @@ when defineSsl: raiseSSLError("Verification of private key file failed.") proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, - certFile = "", keyFile = "", cipherList = "ALL", + certFile = "", keyFile = "", cipherList = CiphersIntermediate, caDir = "", caFile = ""): SSLContext = ## Creates an SSL context. ## diff --git a/lib/pure/ssl_config.nim b/lib/pure/ssl_config.nim new file mode 100644 index 000000000..14f66ede4 --- /dev/null +++ b/lib/pure/ssl_config.nim @@ -0,0 +1,51 @@ +# This file was automatically generated by tools/ssl_config_parser on 2020-06-03T22:02:05Z. DO NOT EDIT. + +## This module contains SSL configuration parameters obtained from +## `Mozilla OpSec `_. +## +## The configuration file used to generate this module: https://ssl-config.mozilla.org/guidelines/5.4.json + +const CiphersModern* = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" + ## An OpenSSL-compatible list of secure ciphers for ``modern`` compatibility + ## per Mozilla's recommendations. + ## + ## Oldest clients supported by this list: + ## * Firefox 63 + ## * Android 10.0 + ## * Chrome 70 + ## * Edge 75 + ## * Java 11 + ## * OpenSSL 1.1.1 + ## * Opera 57 + ## * Safari 12.1 + +const CiphersIntermediate* = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" + ## An OpenSSL-compatible list of secure ciphers for ``intermediate`` compatibility + ## per Mozilla's recommendations. + ## + ## Oldest clients supported by this list: + ## * Firefox 27 + ## * Android 4.4.2 + ## * Chrome 31 + ## * Edge + ## * IE 11 on Windows 7 + ## * Java 8u31 + ## * OpenSSL 1.0.1 + ## * Opera 20 + ## * Safari 9 + +const CiphersOld* = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + ## An OpenSSL-compatible list of secure ciphers for ``old`` compatibility + ## per Mozilla's recommendations. + ## + ## Oldest clients supported by this list: + ## * Firefox 1 + ## * Android 2.3 + ## * Chrome 1 + ## * Edge 12 + ## * IE8 on Windows XP + ## * Java 6 + ## * OpenSSL 0.9.8 + ## * Opera 5 + ## * Safari 1 + diff --git a/tools/ssl_config_parser.nim b/tools/ssl_config_parser.nim new file mode 100644 index 000000000..d13ea1ee2 --- /dev/null +++ b/tools/ssl_config_parser.nim @@ -0,0 +1,62 @@ +# +# +# SSL configuration generator +# (c) Copyright 2020 Leorize +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import httpclient, json, net, strformat, strutils, sequtils, times + +const + ConfigSource = "https://ssl-config.mozilla.org/guidelines/latest.json" + OutputFile = "ssl_config.nim" + +func appendToList(list, str: string): string = + if list.len == 0: + result = str + elif str.len == 0: + result = list + else: + result = list & ':' & str + +proc main() = + let + client = newHttpClient(sslContext = newContext(verifyMode = CVerifyPeer)) + resp = client.get(ConfigSource) + defer: client.close() + if not resp.code.is2xx: + quit "Couldn't fetch configuration, server returned: " & $resp.code + + let configs = resp.bodyStream.parseJson("ssl-config.json") + + let generationTime = now().utc() + let output = open(OutputFile, fmWrite) + echo "Generating ", OutputFile + output.writeLine(&""" +# This file was automatically generated by tools/ssl_config_parser on {generationTime}. DO NOT EDIT. + +## This module contains SSL configuration parameters obtained from +## `Mozilla OpSec `_. +## +## The configuration file used to generate this module: {configs["href"].getStr} +""") + + for name, config in configs["configurations"]: + let + constantName = "Ciphers" & name[0].toUpperAscii & name[1..^1] + ciphers = config["ciphersuites"].foldl(a.appendToList b.getStr, "").appendToList( + config["ciphers"]["openssl"].foldl(a.appendToList b.getStr, "") + ) + oldestClients = config["oldest_clients"].foldl(a & "\n ## * " & b.getStr, "") + + output.writeLine(&""" +const {constantName}* = "{ciphers}" + ## An OpenSSL-compatible list of secure ciphers for ``{name}`` compatibility + ## per Mozilla's recommendations. + ## + ## Oldest clients supported by this list:{oldestClients} +""") + +when isMainModule: main() diff --git a/tools/ssl_config_parser.nims b/tools/ssl_config_parser.nims new file mode 100644 index 000000000..796d18894 --- /dev/null +++ b/tools/ssl_config_parser.nims @@ -0,0 +1 @@ +--d:ssl From 23cc4091d93b2aa9f3a342f14da5d94c19b11392 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 17:25:10 -0500 Subject: [PATCH 0652/4254] untestable/thttpclient_ssl: move incomplete-chain to dubious_broken It's unsure why this test fail for macOS, but it doesn't hurt if it's not passing. --- tests/untestable/thttpclient_ssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim index 624573a80..ef9d71078 100644 --- a/tests/untestable/thttpclient_ssl.nim +++ b/tests/untestable/thttpclient_ssl.nim @@ -41,7 +41,7 @@ const certificate_tests: array[0..55, CertTest] = [ ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"), ("https://no-common-name.badssl.com/", dubious_broken, "no-common-name"), ("https://no-subject.badssl.com/", dubious_broken, "no-subject"), - ("https://incomplete-chain.badssl.com/", dubious, "incomplete-chain"), + ("https://incomplete-chain.badssl.com/", dubious_broken, "incomplete-chain"), ("https://sha1-intermediate.badssl.com/", bad_broken, "sha1-intermediate"), ("https://sha256.badssl.com/", good, "sha256"), ("https://sha384.badssl.com/", good, "sha384"), From 3d4d3f4ac2939bc22f830363c46f7a1c0c209c8c Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 17:39:17 -0500 Subject: [PATCH 0653/4254] untestable/thttpclient_ssl: some tests are no longer broken With the changes to the default cipher suites, certain tests are no longer broken and are acting as they should. --- tests/untestable/thttpclient_ssl.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim index ef9d71078..038eba99d 100644 --- a/tests/untestable/thttpclient_ssl.nim +++ b/tests/untestable/thttpclient_ssl.nim @@ -42,7 +42,7 @@ const certificate_tests: array[0..55, CertTest] = [ ("https://no-common-name.badssl.com/", dubious_broken, "no-common-name"), ("https://no-subject.badssl.com/", dubious_broken, "no-subject"), ("https://incomplete-chain.badssl.com/", dubious_broken, "incomplete-chain"), - ("https://sha1-intermediate.badssl.com/", bad_broken, "sha1-intermediate"), + ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), ("https://sha256.badssl.com/", good, "sha256"), ("https://sha384.badssl.com/", good, "sha384"), ("https://sha512.badssl.com/", good, "sha512"), @@ -54,7 +54,7 @@ const certificate_tests: array[0..55, CertTest] = [ ("https://rsa8192.badssl.com/", dubious_broken, "rsa8192"), ("http://http.badssl.com/", good, "regular http"), ("https://http.badssl.com/", bad_broken, "http on https URL"), # FIXME - ("https://cbc.badssl.com/", dubious_broken, "cbc"), + ("https://cbc.badssl.com/", dubious, "cbc"), ("https://rc4-md5.badssl.com/", bad, "rc4-md5"), ("https://rc4.badssl.com/", bad, "rc4"), ("https://3des.badssl.com/", bad, "3des"), @@ -68,10 +68,10 @@ const certificate_tests: array[0..55, CertTest] = [ ("https://dh2048.badssl.com/", good, "dh2048"), ("https://dh-small-subgroup.badssl.com/", bad_broken, "dh-small-subgroup"), ("https://dh-composite.badssl.com/", bad_broken, "dh-composite"), - ("https://static-rsa.badssl.com/", dubious_broken, "static-rsa"), - ("https://tls-v1-0.badssl.com:1010/", dubious_broken, "tls-v1-0"), - ("https://tls-v1-1.badssl.com:1011/", dubious_broken, "tls-v1-1"), - ("https://invalid-expected-sct.badssl.com/", bad_broken, "invalid-expected-sct"), + ("https://static-rsa.badssl.com/", dubious, "static-rsa"), + ("https://tls-v1-0.badssl.com:1010/", dubious, "tls-v1-0"), + ("https://tls-v1-1.badssl.com:1011/", dubious, "tls-v1-1"), + ("https://invalid-expected-sct.badssl.com/", bad, "invalid-expected-sct"), ("https://hsts.badssl.com/", good, "hsts"), ("https://upgrade.badssl.com/", good, "upgrade"), ("https://preloaded-hsts.badssl.com/", good, "preloaded-hsts"), From 1715935846416cc0e0979f8cc614c0b20cf02841 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 17:46:45 -0500 Subject: [PATCH 0654/4254] ssl_config_parser: refactor for sanity reasons --- tools/ssl_config_parser.nim | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tools/ssl_config_parser.nim b/tools/ssl_config_parser.nim index d13ea1ee2..6c0cccf1c 100644 --- a/tools/ssl_config_parser.nim +++ b/tools/ssl_config_parser.nim @@ -13,14 +13,6 @@ const ConfigSource = "https://ssl-config.mozilla.org/guidelines/latest.json" OutputFile = "ssl_config.nim" -func appendToList(list, str: string): string = - if list.len == 0: - result = str - elif str.len == 0: - result = list - else: - result = list & ':' & str - proc main() = let client = newHttpClient(sslContext = newContext(verifyMode = CVerifyPeer)) @@ -46,17 +38,27 @@ proc main() = for name, config in configs["configurations"]: let constantName = "Ciphers" & name[0].toUpperAscii & name[1..^1] - ciphers = config["ciphersuites"].foldl(a.appendToList b.getStr, "").appendToList( - config["ciphers"]["openssl"].foldl(a.appendToList b.getStr, "") - ) - oldestClients = config["oldest_clients"].foldl(a & "\n ## * " & b.getStr, "") - output.writeLine(&""" + var ciphers: string + for c in config["ciphersuites"].getElems & config["ciphers"]["openssl"].getElems: + if ciphers.len == 0: + ciphers.add c.getStr + else: + ciphers.add ':' + ciphers.add c.getStr + + var constant = &""" const {constantName}* = "{ciphers}" ## An OpenSSL-compatible list of secure ciphers for ``{name}`` compatibility ## per Mozilla's recommendations. ## - ## Oldest clients supported by this list:{oldestClients} -""") + ## Oldest clients supported by this list: +""" + + for c in config["oldest_clients"]: + constant.add " ## * " & c.getStr + constant.add '\n' + + output.writeLine constant when isMainModule: main() From 256841cf2cfbeb0ccd28de53427583ef348a1ab6 Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 17:51:46 -0500 Subject: [PATCH 0655/4254] changelog.md: clarify that only the default has changed [ci-skip] --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index e20077feb..bbcf2ed18 100644 --- a/changelog.md +++ b/changelog.md @@ -102,7 +102,7 @@ - Add `ssl_config` module containing lists of secure ciphers as recommended by [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) -- `net.newContext` now uses the list of ciphers targeting +- `net.newContext` now defaults to the list of ciphers targeting ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) per Mozilla's recommendation instead of `ALL`. This change should protect users from the use of weak and insecure ciphers while still provides From e4e3d99ee2381e5fc2fe922aa6933df8cebb599b Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 23:48:24 -0500 Subject: [PATCH 0656/4254] asyncnet: clear SSL error queue before performing I/O Follow up of 476be6cc278d58232e2c6cd3515eb24eca7e2d38 --- lib/pure/asyncnet.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index bd9cd4312..3fc1a0177 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -253,6 +253,7 @@ when defineSsl: op: untyped) = var opResult {.inject.} = -1.cint while opResult < 0: + ErrClearError() # Call the desired operation. opResult = op # Bit hackish here. From 9278e785bd9490029ea2f9eb353d241fd14b302a Mon Sep 17 00:00:00 2001 From: Leorize Date: Wed, 3 Jun 2020 23:51:59 -0500 Subject: [PATCH 0657/4254] wrappers/openssl: fix SSL_CTX_ctrl signature --- lib/wrappers/openssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 01c53b755..cf248fc86 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -531,7 +531,7 @@ proc CRYPTO_malloc_init*() = when not useWinVersion and not defined(macosx) and not defined(android) and not defined(nimNoAllocForSSL): CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper) -proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cint, larg: int, parg: pointer): int{. +proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cint, larg: clong, parg: pointer): clong{. cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cint, fp: PFunction): int{. From 6c0f86c486f6491a2602e95228e63f3c44ab14fc Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 00:01:13 -0500 Subject: [PATCH 0658/4254] net: enable automatic EC curve selection for OpenSSL 1.0.2 This setting is required for servers running OpenSSL < 1.1.0 to support EC-based secure ciphers that is now part of the default cipher list. --- lib/pure/net.nim | 7 +++++++ lib/wrappers/openssl.nim | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index a5643330e..f628ee056 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -580,6 +580,13 @@ when defineSsl: if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1: raiseSSLError() + # Automatically the best ECDH curve for client exchange. Without this, ECDH + # ciphers will be ignored by the server. + # + # From OpenSSL >= 1.1.0, this setting is set by default and can't be + # overriden. + if newCTX.SSL_CTX_set_ecdh_auto(1) != 1: + raiseSSLError() when defined(nimDisableCertificateValidation) or defined(windows): newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index cf248fc86..29cda3efc 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -181,6 +181,7 @@ const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53 SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54 SSL_CTRL_SET_TLSEXT_HOSTNAME = 55 + SSL_CTRL_SET_ECDH_AUTO* = 94 TLSEXT_NAMETYPE_host_name* = 0 SSL_TLSEXT_ERR_OK* = 0 SSL_TLSEXT_ERR_ALERT_WARNING* = 1 @@ -263,6 +264,12 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.} proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} + + proc getOpenSSLVersion*(): culong = + ## This interface is not supported for OpenSSL < 1.1.0 and will + ## always return 0. The interface is provided to aid code + ## supporting multiple OpenSSL versions. + 0 else: proc OPENSSL_init_ssl*(opts: uint64, settings: uint8): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_library_init*(): cint {.discardable.} = @@ -588,6 +595,15 @@ proc SSL_CTX_use_psk_identity_hint*(ctx: SslCtx; hint: cstring): cint {.cdecl, d proc SSL_get_psk_identity*(ssl: SslPtr): cstring {.cdecl, dynlib: DLLSSLName, importc.} ## Get PSK identity. +proc SSL_CTX_set_ecdh_auto*(ctx: SslCtx, onoff: cint): cint {.inline.} = + ## Set automatic curve selection. + ## + ## On OpenSSL >= 1.1.0 this is on by default and cannot be disabled. + if getOpenSSLVersion() < 0x010100000: + result = cint SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, nil) + else: + result = 1 + proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".} proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".} proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".} From 61d4fbce4f0ae764092c51591112ce39d78fca73 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 00:12:26 -0500 Subject: [PATCH 0659/4254] wrappers/openssl: getOpenSSLVersion is gcsafe Yet another weird {.gcsafe.} triggering when it shouldn't. --- lib/wrappers/openssl.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 29cda3efc..2a03b577f 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -395,9 +395,10 @@ else: proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long or 0 if not available let theProc = cast[proc(): culong {.cdecl.}](sslSymNullable("OpenSSL_version_num")) - result = - if theProc.isNil: 0.culong - else: theProc() + {.gcsafe.}: + result = + if theProc.isNil: 0.culong + else: theProc() proc SSL_in_init*(ssl: SslPtr): cint = # A compatibility wrapper for `SSL_in_init()` for OpenSSL 1.0, 1.1 and LibreSSL From b5b191af4bb3dea9c49b2637d203957daf42478a Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 00:29:39 -0500 Subject: [PATCH 0660/4254] wrappers/openssl: fix SSL_CTX_set_mode Follow up of 794042080b270d9da8d64bb4285ce83787bdec7e --- lib/wrappers/openssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 2a03b577f..5af1edea5 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -546,7 +546,7 @@ proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cint, fp: PFunction): int{. cdecl, dynlib: DLLSSLName, importc.} proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int = - result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil) + result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, clong mode, nil) proc SSL_ctrl*(ssl: SslPtr, cmd: cint, larg: int, parg: pointer): int{. cdecl, dynlib: DLLSSLName, importc.} From 279438f1df355e2eee09734cc0fc5ab86e0d2271 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 08:53:14 -0500 Subject: [PATCH 0661/4254] net: don't call set_ecdh_auto for super old OpenSSL And the fun thing is that currently we use a super old OpenSSL on Windows. --- lib/pure/net.nim | 2 +- lib/wrappers/openssl.nim | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f628ee056..5db3edbed 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -585,7 +585,7 @@ when defineSsl: # # From OpenSSL >= 1.1.0, this setting is set by default and can't be # overriden. - if newCTX.SSL_CTX_set_ecdh_auto(1) != 1: + if getOpenSSLVersion() >= 0x10002000 and newCTX.SSL_CTX_set_ecdh_auto(1) != 1: raiseSSLError() when defined(nimDisableCertificateValidation) or defined(windows): diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 5af1edea5..c2f0250c0 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -264,12 +264,10 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.} proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} + proc SSLeay(): culong {.cdecl, dynlib: DLLSSLName, importc.} proc getOpenSSLVersion*(): culong = - ## This interface is not supported for OpenSSL < 1.1.0 and will - ## always return 0. The interface is provided to aid code - ## supporting multiple OpenSSL versions. - 0 + SSLeay() else: proc OPENSSL_init_ssl*(opts: uint64, settings: uint8): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_library_init*(): cint {.discardable.} = @@ -394,7 +392,7 @@ else: proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long or 0 if not available - let theProc = cast[proc(): culong {.cdecl.}](sslSymNullable("OpenSSL_version_num")) + let theProc = cast[proc(): culong {.cdecl.}](sslSymNullable("OpenSSL_version_num", "SSLeay")) {.gcsafe.}: result = if theProc.isNil: 0.culong From 0ca069b4f8ff4e4f6d85178247818857970ce591 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 09:00:03 -0500 Subject: [PATCH 0662/4254] net: use CiphersOld list for Windows The default DLLs shipped are too old, switch to CiphersOld list to ensure compatibility. This commit should be reverted before any future release. --- lib/pure/net.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 5db3edbed..8da14f6e3 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -534,7 +534,10 @@ when defineSsl: raiseSSLError("Verification of private key file failed.") proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, - certFile = "", keyFile = "", cipherList = CiphersIntermediate, + certFile = "", keyFile = "", + # XXX: update the OpenSSL that we ship with Windows for the + # next release. + cipherList = when not defined(windows): CiphersIntermediate else: CiphersOld, caDir = "", caFile = ""): SSLContext = ## Creates an SSL context. ## From d406f588d89fcf4a19c3e556ca57def9644a8a57 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 09:22:41 -0500 Subject: [PATCH 0663/4254] wrappers/openssl: the version number comes from the utility library Previously we loaded the SSL library for this, but that's not where the symbol resides. --- lib/wrappers/openssl.nim | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index c2f0250c0..8a80a554c 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -264,7 +264,7 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.} proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} - proc SSLeay(): culong {.cdecl, dynlib: DLLSSLName, importc.} + proc SSLeay(): culong {.cdecl, dynlib: DLLUtilName, importc.} proc getOpenSSLVersion*(): culong = SSLeay() @@ -278,7 +278,7 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): proc SSLv23_method*(): PSSL_METHOD = TLS_method() - proc OpenSSL_version_num(): culong {.cdecl, dynlib: DLLSSLName, importc.} + proc OpenSSL_version_num(): culong {.cdecl, dynlib: DLLUtilName, importc.} proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long @@ -318,13 +318,18 @@ else: result = sslMod - proc sslSymNullable(name: string, alternativeName = ""): pointer = + proc utilModule(): LibHandle {.inline.} = + var utilMod {.global.}: LibHandle + if utilMod.isNil: utilMod = loadLibPattern(DLLUtilName) + + result = utilMod + + proc symNullable(dll: LibHandle, name: string, alternativeName = ""): pointer = # Load from DLL. - var sslDynlib = sslModule() - if not sslDynlib.isNil: - result = symAddr(sslDynlib, name) + if not dll.isNil: + result = symAddr(dll, name) if result.isNil and alternativeName.len > 0: - result = symAddr(sslDynlib, alternativeName) + result = symAddr(dll, alternativeName) # Attempt to load from current exe. if result.isNil: @@ -332,12 +337,18 @@ else: if thisDynlib.isNil: return nil result = symAddr(thisDynlib, name) if result.isNil and alternativeName.len > 0: - result = symAddr(sslDynlib, alternativeName) + result = symAddr(thisDynlib, alternativeName) + + proc sslSymNullable(name: string, alternativeName = ""): pointer = + sslModule().symNullable(name, alternativeName) proc sslSymThrows(name: string, alternativeName = ""): pointer = result = sslSymNullable(name, alternativeName) if result.isNil: raiseInvalidLibrary(name) + proc utilSymNullable(name: string, alternativeName = ""): pointer = + utilModule().symNullable(name, alternativeName) + proc loadPSSLMethod(method1, method2: string): PSSL_METHOD = ## Load from OpenSSL if available, otherwise ## @@ -392,7 +403,7 @@ else: proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long or 0 if not available - let theProc = cast[proc(): culong {.cdecl.}](sslSymNullable("OpenSSL_version_num", "SSLeay")) + let theProc = cast[proc(): culong {.cdecl.}](utilSymNullable("OpenSSL_version_num", "SSLeay")) {.gcsafe.}: result = if theProc.isNil: 0.culong From e80a23f4d2bf4f628cb6bf7c235cb63cc58fdcb0 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 09:57:19 -0500 Subject: [PATCH 0664/4254] net: revert compatibility changes for Windows This reverts commit d53a6355f3ad4401731142d8fc66b95ecfdfb321 and 688b1f250ed058ecc49737dc75fd089206fa25b9. --- lib/pure/net.nim | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 8da14f6e3..f628ee056 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -534,10 +534,7 @@ when defineSsl: raiseSSLError("Verification of private key file failed.") proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, - certFile = "", keyFile = "", - # XXX: update the OpenSSL that we ship with Windows for the - # next release. - cipherList = when not defined(windows): CiphersIntermediate else: CiphersOld, + certFile = "", keyFile = "", cipherList = CiphersIntermediate, caDir = "", caFile = ""): SSLContext = ## Creates an SSL context. ## @@ -588,7 +585,7 @@ when defineSsl: # # From OpenSSL >= 1.1.0, this setting is set by default and can't be # overriden. - if getOpenSSLVersion() >= 0x10002000 and newCTX.SSL_CTX_set_ecdh_auto(1) != 1: + if newCTX.SSL_CTX_set_ecdh_auto(1) != 1: raiseSSLError() when defined(nimDisableCertificateValidation) or defined(windows): From b323bccd8125e9fa4ff28330da1a3adf206b8d32 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 10:50:28 -0500 Subject: [PATCH 0665/4254] wrappers/openssl: enable SSL_CTX_set_ecdh_auto for LibreSSL This procedure is not no-op for older LibreSSL, and the ABI is kept for newer versions, so there's no harm in enabling it unconditionally for all LibreSSL versions. --- lib/wrappers/openssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 8a80a554c..82fcb2194 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -609,7 +609,7 @@ proc SSL_CTX_set_ecdh_auto*(ctx: SslCtx, onoff: cint): cint {.inline.} = ## Set automatic curve selection. ## ## On OpenSSL >= 1.1.0 this is on by default and cannot be disabled. - if getOpenSSLVersion() < 0x010100000: + if getOpenSSLVersion() < 0x010100000 or getOpenSSLVersion() == 0x020000000: result = cint SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, nil) else: result = 1 From 3cd74c6408353aec97f04672140d5de226f3f3af Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 17:41:53 -0500 Subject: [PATCH 0666/4254] wrappers/openssl: mark casts as gcsafe Nim will pretend that these proc are not gcsafe if they are not marked. --- lib/wrappers/openssl.nim | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 82fcb2194..a3825b801 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -403,29 +403,25 @@ else: proc getOpenSSLVersion*(): culong = ## Return OpenSSL version as unsigned long or 0 if not available - let theProc = cast[proc(): culong {.cdecl.}](utilSymNullable("OpenSSL_version_num", "SSLeay")) - {.gcsafe.}: - result = - if theProc.isNil: 0.culong - else: theProc() + let theProc = cast[proc(): culong {.cdecl, gcsafe.}](utilSymNullable("OpenSSL_version_num", "SSLeay")) + result = + if theProc.isNil: 0.culong + else: theProc() proc SSL_in_init*(ssl: SslPtr): cint = # A compatibility wrapper for `SSL_in_init()` for OpenSSL 1.0, 1.1 and LibreSSL const MainProc = "SSL_in_init" let - theProc {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl.}](sslSymNullable(MainProc)) + theProc {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl, gcsafe.}](sslSymNullable(MainProc)) # Fallback - sslState {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl.}](sslSymNullable("SSL_state")) + sslState {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl, gcsafe.}](sslSymNullable("SSL_state")) - # FIXME: This shouldn't be needed, but the compiler is complaining about - # `sslState` being GC-ed memory??? - {.gcsafe.}: - if not theProc.isNil: - theProc(ssl) - elif not sslState.isNil: - sslState(ssl) and SSL_ST_INIT - else: - raiseInvalidLibrary MainProc + if not theProc.isNil: + theProc(ssl) + elif not sslState.isNil: + sslState(ssl) and SSL_ST_INIT + else: + raiseInvalidLibrary MainProc proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} From 6b2d8bfc8b9e46ae92e490111cb6a2abc49a32b6 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 18:13:06 -0500 Subject: [PATCH 0667/4254] net: also set TLSv1.3 cipher suites --- lib/pure/net.nim | 7 +++++++ lib/wrappers/openssl.nim | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f628ee056..c1896dc1c 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -580,6 +580,13 @@ when defineSsl: if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1: raiseSSLError() + when not defined(openssl10) and not defined(libressl): + let sslVersion = getOpenSSLVersion() + if sslVersion >= 0x010101000 and not sslVersion == 0x020000000: + # In OpenSSL >= 1.1.1, TLSv1.3 cipher suites can only be configured via + # this API. + if newCTX.SSL_CTX_set_ciphersuites(cipherList) != 1: + raiseSSLError() # Automatically the best ECDH curve for client exchange. Without this, ECDH # ciphers will be ignored by the server. # diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index a3825b801..c81176a9b 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -296,6 +296,7 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks): SSl_state(ssl) and SSL_ST_INIT else: proc SSL_in_init*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.} + proc SSL_CTX_set_ciphersuites*(ctx: SslCtx, str: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.} template OpenSSL_add_all_algorithms*() = discard @@ -423,6 +424,10 @@ else: else: raiseInvalidLibrary MainProc + proc SSL_CTX_set_ciphersuites*(ctx: SslCtx, str: cstring): cint = + let theProc {.global.} = cast[proc(ctx: SslCtx, str: cstring) {.cdecl, gcsafe.}](sslSymThrows("SSL_CTX_set_ciphersuites")) + theProc(ctx, str) + proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} From 4fdf9cb808db9251feb1c23652da6141ce111437 Mon Sep 17 00:00:00 2001 From: Leorize Date: Thu, 4 Jun 2020 18:30:20 -0500 Subject: [PATCH 0668/4254] wrappers/openssl: defer loading SSL_CTX_set_ciphersuites --- lib/wrappers/openssl.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index c81176a9b..b7f18ad79 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -425,7 +425,9 @@ else: raiseInvalidLibrary MainProc proc SSL_CTX_set_ciphersuites*(ctx: SslCtx, str: cstring): cint = - let theProc {.global.} = cast[proc(ctx: SslCtx, str: cstring) {.cdecl, gcsafe.}](sslSymThrows("SSL_CTX_set_ciphersuites")) + var theProc {.global.}: proc(ctx: SslCtx, str: cstring) {.cdecl, gcsafe.} + if theProc.isNil: + theProc = cast[typeof(theProc)](sslSymThrows("SSL_CTX_set_ciphersuites")) theProc(ctx, str) proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} From 32083c7ff88c46b81c30df95ff5c81c57935bc23 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 6 Jun 2020 21:28:46 +0200 Subject: [PATCH 0669/4254] more precise analysis about 'observable stores' [backport:1.2] (#14582) --- compiler/ast.nim | 1 + compiler/ccgcalls.nim | 12 +++++++++--- compiler/sempass2.nim | 6 +++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d13487e9c..76b1d8c91 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -293,6 +293,7 @@ type sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation sfNeverRaises # proc can never raise an exception, not even OverflowDefect # or out-of-memory + sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 10f5ef638..3dd2b54d4 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -22,14 +22,20 @@ proc canRaiseDisp(p: BProc; n: PNode): bool = result = canRaiseConservative(n) proc preventNrvo(p: BProc; le, ri: PNode): bool = - proc locationEscapes(p: BProc; le: PNode): bool = + proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool = var n = le while true: # do NOT follow nkHiddenDeref here! case n.kind of nkSym: # we don't own the location so it escapes: - return n.sym.owner != p.prc + if n.sym.owner != p.prc: + return true + elif inTryStmt and sfUsedInFinallyOrExcept in n.sym.flags: + # it is also an observable store if the location is used + # in 'except' or 'finally' + return true + return false of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: n = n[0] @@ -46,7 +52,7 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool = # we use the weaker 'canRaise' here in order to prevent too many # annoying warnings, see #14514 if canRaise(ri[0]) and - (p.nestedTryStmts.len > 0 or locationEscapes(p, le)): + locationEscapes(p, le, p.nestedTryStmts.len > 0): message(p.config, le.info, warnObservableStores, $le) proc hasNoInit(call: PNode): bool {.inline.} = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 862123eab..6808b1b9b 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -66,7 +66,7 @@ type TEffects = object exc: PNode # stack of exceptions tags: PNode # list of tags - bottom, inTryStmt: int + bottom, inTryStmt, inExceptOrFinallyStmt: int owner: PSym ownerModule: PSym init: seq[int] # list of initialized variables @@ -248,6 +248,8 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) = proc useVar(a: PEffects, n: PNode) = let s = n.sym + if a.inExceptOrFinallyStmt > 0: + incl s.flags, sfUsedInFinallyOrExcept if isLocalVar(a, s): if sfNoInit in s.flags: # If the variable is explicitly marked as .noinit. do not emit any error @@ -382,6 +384,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) = var branches = 1 var hasFinally = false + inc tracked.inExceptOrFinallyStmt # Collect the exceptions caught by the except branches for i in 1.. Date: Sat, 6 Jun 2020 21:53:18 +0200 Subject: [PATCH 0670/4254] Fix link to "rebuilding the compiler" (#14567) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index eb6b68d0d..f529c0df0 100644 --- a/readme.md +++ b/readme.md @@ -79,7 +79,7 @@ Next run the appropriate build shell script for your platform: Finally, once you have finished the build steps (on Windows, Mac or Linux) you should add the ``bin`` directory to your PATH. -See also [rebuilding the compiler](intern.html#rebuilding-the-compiler). +See also [rebuilding the compiler](doc/intern.rst#rebuilding-the-compiler). ## Koch From 66c50c2ffcfdd31f9f1eecfaf23b1b58b22d3a36 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 7 Jun 2020 09:55:56 +0200 Subject: [PATCH 0671/4254] implement the 'bind' statement for generics, it was an oversight that this was never implemented (#14584) --- compiler/semgnrc.nim | 15 +++++++++++---- tests/lookups/tbind_for_generics.nim | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 tests/lookups/tbind_for_generics.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 6fefc2233..23b6e9b9d 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -28,7 +28,7 @@ proc getIdentNode(c: PContext; n: PNode): PNode = type GenericCtx = object - toMixin: IntSet + toMixin, toBind: IntSet cursorInBody: bool # only for nimsuggest bracketExpr: PNode @@ -124,7 +124,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, if ident.id notin ctx.toMixin and withinMixin notin flags: errorUndeclaredIdentifier(c, n.info, ident.s) else: - if withinBind in flags: + if withinBind in flags or s.id in ctx.toBind: result = symChoice(c, n, s, scClosed) elif s.isMixedIn: result = symChoice(c, n, s, scForceOpen) @@ -155,7 +155,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, var s = searchInScopes(c, ident, routineKinds).skipAlias(n, c.config) if s != nil: isMacro = s.kind in {skTemplate, skMacro} - if withinBind in flags: + if withinBind in flags or s.id in ctx.toBind: result = newDot(result, symChoice(c, n, s, scClosed)) elif s.isMixedIn: result = newDot(result, symChoice(c, n, s, scForceOpen)) @@ -211,6 +211,8 @@ proc semGenericStmt(c: PContext, n: PNode, result = semGenericStmt(c, n[0], flags+{withinBind}, ctx) of nkMixinStmt: result = semMixinStmt(c, n, ctx.toMixin) + of nkBindStmt: + result = semBindStmt(c, n, ctx.toBind) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1, c.config) @@ -227,7 +229,10 @@ proc semGenericStmt(c: PContext, n: PNode, if s != nil: incl(s.flags, sfUsed) mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr} - let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen) + let whichChoice = if s.id in ctx.toBind: scClosed + elif s.isMixedIn: scForceOpen + else: scOpen + let sc = symChoice(c, fn, s, whichChoice) case s.kind of skMacro: if macroToExpand(s) and sc.safeLen <= 1: @@ -492,12 +497,14 @@ proc semGenericStmt(c: PContext, n: PNode, proc semGenericStmt(c: PContext, n: PNode): PNode = var ctx: GenericCtx ctx.toMixin = initIntSet() + ctx.toBind = initIntSet() result = semGenericStmt(c, n, {}, ctx) semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody) proc semConceptBody(c: PContext, n: PNode): PNode = var ctx: GenericCtx ctx.toMixin = initIntSet() + ctx.toBind = initIntSet() result = semGenericStmt(c, n, {withinConcept}, ctx) semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody) diff --git a/tests/lookups/tbind_for_generics.nim b/tests/lookups/tbind_for_generics.nim new file mode 100644 index 000000000..db5fbebbc --- /dev/null +++ b/tests/lookups/tbind_for_generics.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: "type mismatch: got " + line: 8 +""" +proc g[T](x: T) = + bind `+` + # because we bind `+` here, we must not find the `+` for 'Foo' below: + echo x + x + +type + Foo = object + a: int + +proc `+`(a, b: Foo): Foo = Foo(a: a.a+b.a) + +g(3) +g(Foo(a: 8)) From 419dbd573d91c493f80c75fa23fae1dd6fece18e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 7 Jun 2020 20:11:42 +0200 Subject: [PATCH 0672/4254] fixes #14118 (#14595) --- compiler/injectdestructors.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 9cb777f2c..c13c93b00 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -277,8 +277,11 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} = else: result = t.attachedOps[attachedSink] != nil +proc isNoInit(dest: PNode): bool {.inline.} = + result = dest.kind == nkSym and sfNoInit in dest.sym.flags + proc genSink(c: var Con; dest, ri: PNode): PNode = - if isUnpackedTuple(dest) or isFirstWrite(dest, c): + if isUnpackedTuple(dest) or isFirstWrite(dest, c) or isNoInit(dest): # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) else: From 754a196d4739b17fc0783d8e4b025d38bbcc4e32 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 7 Jun 2020 23:29:26 +0200 Subject: [PATCH 0673/4254] fixes #14315 (#14594) --- compiler/semtypinst.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 257094289..15a63e75e 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -390,7 +390,6 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = let bbody = lastSon body var newbody = replaceTypeVarsT(cl, bbody) - let bodyIsNew = newbody != bbody cl.skipTypedesc = oldSkipTypedesc newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) result.flags = result.flags + newbody.flags - tfInstClearedFlags @@ -412,7 +411,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # generics *when the type is constructed*: newbody.attachedOps[attachedDeepCopy] = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, attachedDeepCopy, 1) - if bodyIsNew and newbody.typeInst == nil: + if newbody.typeInst == nil: #doassert newbody.typeInst == nil newbody.typeInst = result if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst: From 52841dba0936d3679d2c7115fed620c35627155d Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 7 Jun 2020 23:32:41 +0200 Subject: [PATCH 0674/4254] Fix #14568 (#14583) * Fix #14568 * Add testcase * Fix bogus test * Adapt other failing tests * Declarations are always first writes --- compiler/injectdestructors.nim | 46 ++++++++++++++-------------- tests/arc/tmovebug.nim | 27 ++++++++++++++-- tests/destructor/tmove_objconstr.nim | 1 + 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index c13c93b00..d5eca7475 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -63,7 +63,7 @@ template dbg(body) = body proc p(n: PNode; c: var Con; mode: ProcessMode): PNode -proc moveOrCopy(dest, ri: PNode; c: var Con): PNode +proc moveOrCopy(dest, ri: PNode; c: var Con, isDecl = false): PNode proc isLastRead(location: PNode; c: var Con; pc, until: int): int = var pc = pc @@ -280,8 +280,8 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} = proc isNoInit(dest: PNode): bool {.inline.} = result = dest.kind == nkSym and sfNoInit in dest.sym.flags -proc genSink(c: var Con; dest, ri: PNode): PNode = - if isUnpackedTuple(dest) or isFirstWrite(dest, c) or isNoInit(dest): +proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = + if isUnpackedTuple(dest) or (isDecl and c.inLoop <= 0) or (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)) or isNoInit(dest): # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) else: @@ -578,7 +578,7 @@ proc ensureDestruction(arg: PNode; c: var Con): PNode = let tmp = getTemp(c, arg.typ, arg.info) when not scopeBasedDestruction: c.addTopVar(tmp) - result.add genSink(c, tmp, arg) + result.add genSink(c, tmp, arg, isDecl = true) result.add tmp c.destroys.add genDestroy(c, tmp) else: @@ -652,9 +652,9 @@ proc pVarTopLevel(v: PNode; c: var Con; ri, res: PNode) = else: c.destroys.add genDestroy(c, v) if ri.kind == nkEmpty and c.inLoop > 0: - res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c) + res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, isDecl = true) elif ri.kind != nkEmpty: - res.add moveOrCopy(v, ri, c) + res.add moveOrCopy(v, ri, c, isDecl = true) proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = if not containsOrIncl(c.declaredVars, v.sym.id): @@ -675,9 +675,9 @@ proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = #if c.inDangerousBranch == 0: v.sym.flags.incl sfNoInit c.scopeDestroys.add genDestroy(c, v) if ri.kind == nkEmpty and c.inLoop > 0: - res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c) + res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, isDecl = true) elif ri.kind != nkEmpty: - res.add moveOrCopy(v, ri, c) + res.add moveOrCopy(v, ri, c, isDecl = true) template handleNestedTempl(n: untyped, processCall: untyped) = case n.kind @@ -901,7 +901,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = if ri.kind == nkEmpty and c.inLoop > 0: ri = genDefaultCall(v.typ, c, v.info) if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c) + result.add moveOrCopy(v, ri, c, isDecl = true) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) @@ -975,18 +975,18 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = for i in 0.. 0: echo "assign ",x.who + if y.who.len > 0: echo "assign ",y.who proc `=sink`(x: var ME, y: ME) = - if x.who.len > 0: echo "sink ",x.who + if y.who.len > 0: echo "sink ",y.who var dump: ME template use(x) = dump = x @@ -302,3 +306,22 @@ proc shouldNotSink() = use(x) # Not ok without the '[else]' shouldNotSink() + +# bug #14568 +import os + +type O2 = object + s: seq[int] + +proc `=sink`(dest: var O2, src: O2) = + echo "sinked and not optimized to a bitcopy" + +var testSeq: O2 + +proc Update(): void = + # testSeq.add(0) # uncommenting this line fixes the leak + testSeq = O2(s: @[]) + testSeq.s.add(0) + +for i in 1..3: + Update() diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 5b2198e51..5366f4957 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -2,6 +2,7 @@ discard """ output: '''test created test destroyed 0 +Pony is dying! 1 2 3 From 8edac9cf1d8a052b306e43ba92b3a91f51a221be Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 8 Jun 2020 01:15:10 -0500 Subject: [PATCH 0675/4254] openssl: use explicit result for SSL_in_init (#14597) Sometimes the analysis might get funky and decide that the if-expression below is not an if-expression. Details of how this can happen is largely unknown, but it's easy to prevent so we will just go forward with that. Fix #14591 --- lib/wrappers/openssl.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index b7f18ad79..bea96127d 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -418,9 +418,9 @@ else: sslState {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl, gcsafe.}](sslSymNullable("SSL_state")) if not theProc.isNil: - theProc(ssl) + result = theProc(ssl) elif not sslState.isNil: - sslState(ssl) and SSL_ST_INIT + result = sslState(ssl) and SSL_ST_INIT else: raiseInvalidLibrary MainProc From 0d814f2d4464b6426df8f65d845299b969a86d71 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 7 Jun 2020 23:15:34 -0700 Subject: [PATCH 0676/4254] hotfix disable nitter refs https://github.com/timotheecour/Nim/issues/167 (#14603) --- testament/important_packages.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index cb436bfb2..19e11e322 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -90,7 +90,8 @@ pkg2 "nimsvg" # pkg2 "nimterop", true pkg2 "nimwc", true, "nim c nimwc.nim" # pkg2 "nimx", true, "nim c --threads:on test/main.nim" -pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" +# pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" + # pending https://github.com/timotheecour/Nim/issues/167 or new git tag for nitter pkg2 "norm", true, "nim c -r tests/tsqlite.nim" pkg2 "npeg", false, "nimble testarc" pkg2 "numericalnim", true, "nim c -r tests/test_integrate.nim" From 733bd76f6bc8253f255df4cec26099502090264b Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Mon, 8 Jun 2020 17:28:42 +0900 Subject: [PATCH 0677/4254] Fix sugar.dump: It doesn't work correctly with compile time expression (#14580) --- lib/pure/sugar.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index dbc60b8a9..d2bdb0fdc 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -150,7 +150,7 @@ macro `->`*(p, b: untyped): untyped = result = createProcType(p, b) -macro dump*(x: typed): untyped = +macro dump*(x: untyped): untyped = ## Dumps the content of an expression, useful for debugging. ## It accepts any expression and prints a textual representation ## of the tree representing the expression - as it would appear in From c7a1a7b8bf38ab5c15decdf913dfc272ad922c21 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 8 Jun 2020 01:35:23 -0700 Subject: [PATCH 0678/4254] `toJson`, `jsonTo`, json (de)serialization for custom types; remove dependency on strtabs thanks to a hooking mechanism (#14563) * json custom serialization; application for strtabs * serialize using nesting * make toJson more feature complete * add since * Revert "Improve JSON serialisation of strtabs (#14549)" This reverts commit 7cb4ef26addb3bb5ce2405d8396df6fd41664dae. * better approach via mixin * toJson, jsonTo * fix test * address comments * move to jsonutils * doc * cleanups * also test for js * also test for vm --- changelog.md | 2 + lib/pure/json.nim | 42 ++++-------- lib/pure/strtabs.nim | 20 +++++- lib/std/jsonutils.nim | 126 ++++++++++++++++++++++++++++++++++++ tests/stdlib/tjsonutils.nim | 44 +++++++++++++ 5 files changed, 203 insertions(+), 31 deletions(-) create mode 100644 lib/std/jsonutils.nim create mode 100644 tests/stdlib/tjsonutils.nim diff --git a/changelog.md b/changelog.md index bbcf2ed18..8e06d30f1 100644 --- a/changelog.md +++ b/changelog.md @@ -108,6 +108,8 @@ users from the use of weak and insecure ciphers while still provides adequate compatiblity with the majority of the Internet. +- new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json serialization/deserialization of custom types. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 58a8c1dce..041816c7d 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -140,6 +140,9 @@ ## var j2 = %* {"name": "Isaac", "books": ["Robot Dreams"]} ## j2["details"] = %* {"age":35, "pi":3.1415} ## echo j2 +## +## See also: std/jsonutils for hookable json serialization/deserialization +## of arbitrary types. runnableExamples: ## Note: for JObject, key ordering is preserved, unlike in some languages, @@ -149,8 +152,10 @@ runnableExamples: doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" import - hashes, tables, strtabs, strutils, lexbase, streams, macros, parsejson, - options + hashes, tables, strutils, lexbase, streams, macros, parsejson + +import options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 +import std/private/since export tables.`$` @@ -353,14 +358,6 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = assert(obj.kind == JObject) obj.fields[key] = val -proc `%`*(table: StringTableRef): JsonNode = - ## Generic constructor for JSON data. Creates a new ``JObject JsonNode``. - result = newJObject() - result["mode"] = %($table.mode) - var data = newJObject() - for k, v in table: data[k] = %v - result["data"] = data - proc `%`*[T: object](o: T): JsonNode = ## Construct JsonNode from tuples and objects. result = newJObject() @@ -378,20 +375,20 @@ proc `%`*(o: enum): JsonNode = ## string. Creates a new ``JString JsonNode``. result = %($o) -proc toJson(x: NimNode): NimNode {.compileTime.} = +proc toJsonImpl(x: NimNode): NimNode {.compileTime.} = case x.kind of nnkBracket: # array if x.len == 0: return newCall(bindSym"newJArray") result = newNimNode(nnkBracket) for i in 0 ..< x.len: - result.add(toJson(x[i])) + result.add(toJsonImpl(x[i])) result = newCall(bindSym("%", brOpen), result) of nnkTableConstr: # object if x.len == 0: return newCall(bindSym"newJObject") result = newNimNode(nnkTableConstr) for i in 0 ..< x.len: x[i].expectKind nnkExprColonExpr - result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1])) + result.add newTree(nnkExprColonExpr, x[i][0], toJsonImpl(x[i][1])) result = newCall(bindSym("%", brOpen), result) of nnkCurly: # empty object x.expectLen(0) @@ -399,7 +396,7 @@ proc toJson(x: NimNode): NimNode {.compileTime.} = of nnkNilLit: result = newCall(bindSym"newJNull") of nnkPar: - if x.len == 1: result = toJson(x[0]) + if x.len == 1: result = toJsonImpl(x[0]) else: result = newCall(bindSym("%", brOpen), x) else: result = newCall(bindSym("%", brOpen), x) @@ -407,7 +404,7 @@ proc toJson(x: NimNode): NimNode {.compileTime.} = macro `%*`*(x: untyped): untyped = ## Convert an expression to a JsonNode directly, without having to specify ## `%` for every element. - result = toJson(x) + result = toJsonImpl(x) proc `==`*(a, b: JsonNode): bool = ## Check two nodes for equality @@ -992,7 +989,6 @@ when defined(nimFixedForwardGeneric): proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson(dst: var StringTableRef; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) @@ -1073,20 +1069,6 @@ when defined(nimFixedForwardGeneric): initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) jsonPath.setLen originalJsonPathLen - proc mgetOrPut(tab: var StringTableRef, key: string): var string = - if not tab.hasKey(key): tab[key] = "" - result = tab[key] - - proc initFromJson(dst: var StringTableRef; jsonNode: JsonNode; jsonPath: var string) = - dst = newStringTable(parseEnum[StringTableMode](jsonNode["mode"].getStr)) - verifyJsonKind(jsonNode, {JObject}, jsonPath) - let originalJsonPathLen = jsonPath.len - for key in keys(jsonNode["data"].fields): - jsonPath.add '.' - jsonPath.add key - initFromJson(mgetOrPut(dst, key), jsonNode[key], jsonPath) - jsonPath.setLen originalJsonPathLen - proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath) if jsonNode.kind == JNull: diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index cfafdf018..81ff7fbde 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -71,7 +71,7 @@ type StringTableObj* = object of RootObj counter: int data: KeyValuePairSeq - mode*: StringTableMode + mode: StringTableMode StringTableRef* = ref StringTableObj @@ -419,6 +419,24 @@ proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {. add(result, f[i]) inc(i) +since (1,3,5): + proc fromJsonHook*[T](a: var StringTableRef, b: T) = + ## for json.fromJson + mixin jsonTo + var mode = jsonTo(b["mode"], StringTableMode) + a = newStringTable(mode) + let b2 = b["table"] + for k,v in b2: a[k] = jsonTo(v, string) + + proc toJsonHook*[](a: StringTableRef): auto = + ## for json.toJson + mixin newJObject + mixin toJson + result = newJObject() + result["mode"] = toJson($a.mode) + let t = newJObject() + for k,v in a: t[k] = toJson(v) + result["table"] = t when isMainModule: var x = {"k": "v", "11": "22", "565": "67"}.newStringTable diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim new file mode 100644 index 000000000..bfa600fa9 --- /dev/null +++ b/lib/std/jsonutils.nim @@ -0,0 +1,126 @@ +##[ +This module implements a hookable (de)serialization for arbitrary types. +Design goal: avoid importing modules where a custom serialization is needed; +see strtabs.fromJsonHook,toJsonHook for an example. + +]## + +import std/[json,tables,strutils] + +#[ +xxx +use toJsonHook,fromJsonHook for Table|OrderedTable +add Options support also using toJsonHook,fromJsonHook and remove `json=>options` dependency + +future direction: +add a way to customize serialization, for eg allowing missing +or extra fields in JsonNode, field renaming, and a way to handle cyclic references +using a cache of already visited addresses. +]# + +proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} +proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} +template distinctBase[T](a: T): untyped = distinctBase(type(a))(a) + +proc checkJsonImpl(cond: bool, condStr: string, msg = "") = + if not cond: + # just pick 1 exception type for simplicity; other choices would be: + # JsonError, JsonParser, JsonKindError + raise newException(ValueError, msg) + +template checkJson(cond: untyped, msg = "") = + checkJsonImpl(cond, astToStr(cond), msg) + +proc fromJson*[T](a: var T, b: JsonNode) = + ## inplace version of `jsonTo` + #[ + adding "json path" leading to `b` can be added in future work. + ]# + checkJson b != nil, $($T, b) + when compiles(fromJsonHook(a, b)): fromJsonHook(a, b) + elif T is bool: a = to(b,T) + elif T is Table | OrderedTable: + a.clear + for k,v in b: + a[k] = jsonTo(v, typeof(a[k])) + elif T is enum: + case b.kind + of JInt: a = T(b.getBiggestInt()) + of JString: a = parseEnum[T](b.getStr()) + else: checkJson false, $($T, " ", b) + elif T is Ordinal: a = T(to(b, int)) + elif T is pointer: a = cast[pointer](to(b, int)) + elif T is distinct: + when nimvm: + # bug, potentially related to https://github.com/nim-lang/Nim/issues/12282 + a = T(jsonTo(b, distinctBase(T))) + else: + a.distinctBase.fromJson(b) + elif T is string|SomeNumber: a = to(b,T) + elif T is JsonNode: a = b + elif T is ref | ptr: + if b.kind == JNull: a = nil + else: + a = T() + fromJson(a[], b) + elif T is array: + checkJson a.len == b.len, $(a.len, b.len, $T) + for i, val in b.getElems: + fromJson(a[i], val) + elif T is seq: + a.setLen b.len + for i, val in b.getElems: + fromJson(a[i], val) + elif T is object | tuple: + const isNamed = T is object or isNamedTuple(T) + when isNamed: + checkJson b.kind == JObject, $(b.kind) # we could customize whether to allow JNull + var num = 0 + for key, val in fieldPairs(a): + num.inc + if b.hasKey key: + fromJson(val, b[key]) + else: + # we could customize to allow this + checkJson false, $($T, key, b) + checkJson b.len == num, $(b.len, num, $T, b) # could customize + else: + checkJson b.kind == JArray, $(b.kind) # we could customize whether to allow JNull + var i = 0 + for val in fields(a): + fromJson(val, b[i]) + i.inc + else: + # checkJson not appropriate here + static: doAssert false, "not yet implemented: " & $T + +proc jsonTo*(b: JsonNode, T: typedesc): T = + ## reverse of `toJson` + fromJson(result, b) + +proc toJson*[T](a: T): JsonNode = + ## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to + ## customize serialization, see strtabs.toJsonHook for an example. + when compiles(toJsonHook(a)): result = toJsonHook(a) + elif T is Table | OrderedTable: + result = newJObject() + for k, v in pairs(a): result[k] = toJson(v) + elif T is object | tuple: + const isNamed = T is object or isNamedTuple(T) + when isNamed: + result = newJObject() + for k, v in a.fieldPairs: result[k] = toJson(v) + else: + result = newJArray() + for v in a.fields: result.add toJson(v) + elif T is ref | ptr: + if a == nil: result = newJNull() + else: result = toJson(a[]) + elif T is array | seq: + result = newJArray() + for ai in a: result.add toJson(ai) + elif T is pointer: result = toJson(cast[int](a)) + elif T is distinct: result = toJson(a.distinctBase) + elif T is bool: result = %(a) + elif T is Ordinal: result = %(a.ord) + else: result = %a diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim new file mode 100644 index 000000000..01c6aa05a --- /dev/null +++ b/tests/stdlib/tjsonutils.nim @@ -0,0 +1,44 @@ +discard """ + targets: "c cpp js" +""" + +import std/jsonutils +import std/json + +proc testRoundtrip[T](t: T, expected: string) = + let j = t.toJson + doAssert $j == expected, $j + doAssert j.jsonTo(T).toJson == j + +import tables +import strtabs + +template fn() = + block: # toJson, jsonTo + type Foo = distinct float + testRoundtrip('x', """120""") + when not defined(js): + testRoundtrip(cast[pointer](12345)): """12345""" + + # causes workaround in `fromJson` potentially related to + # https://github.com/nim-lang/Nim/issues/12282 + testRoundtrip(Foo(1.5)): """1.5""" + + block: + testRoundtrip({"z": "Z", "y": "Y"}.toOrderedTable): """{"z":"Z","y":"Y"}""" + when not defined(js): # pending https://github.com/nim-lang/Nim/issues/14574 + testRoundtrip({"z": (f1: 'f'), }.toTable): """{"z":{"f1":102}}""" + + block: + testRoundtrip({"name": "John", "city": "Monaco"}.newStringTable): """{"mode":"modeCaseSensitive","table":{"city":"Monaco","name":"John"}}""" + + block: # complex example + let t = {"z": "Z", "y": "Y"}.newStringTable + type A = ref object + a1: string + let a = (1.1, "fo", 'x', @[10,11], [true, false], [t,newStringTable()], [0'i8,3'i8], -4'i16, (foo: 0.5'f32, bar: A(a1: "abc"), bar2: A.default)) + testRoundtrip(a): + """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null}]""" + +static: fn() +fn() From e3f80e434aa8eb1d81a3d7a83d0beb02c0158846 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 8 Jun 2020 14:32:45 +0200 Subject: [PATCH 0679/4254] fixes #14557 (#14607) --- compiler/parampatterns.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 33881a7b3..e97631b77 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -200,7 +200,7 @@ proc exprRoot*(n: PNode): PSym = if it.len > 0 and it.typ != nil: it = it.lastSon else: break of nkCallKinds: - if it.typ != nil and it.typ.kind == tyVar and it.len > 1: + if it.typ != nil and it.typ.kind in {tyVar, tyLent} and it.len > 1: # See RFC #7373, calls returning 'var T' are assumed to # return a view into the first argument (if there is one): it = it[1] From c308c2e60b472c6ceade2cd319e2fe32fcd1d9a7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 8 Jun 2020 14:34:26 +0200 Subject: [PATCH 0680/4254] optimized wrapWords; fixes #14579 (#14606) [backport:1.2] --- lib/std/wordwrap.nim | 73 +++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim index 4b0dc4417..bb6f2dc6f 100644 --- a/lib/std/wordwrap.nim +++ b/lib/std/wordwrap.nim @@ -11,10 +11,10 @@ import strutils, unicode -proc olen(s: string): int = - var i = 0 +proc olen(s: string; start, lastExclusive: int): int = + var i = start result = 0 - while i < s.len: + while i < lastExclusive: inc result let L = graphemeLen(s, i) inc i, L @@ -32,31 +32,46 @@ proc wrapWords*(s: string, maxLineWidth = 80, result = newStringOfCap(s.len + s.len shr 6) var spaceLeft = maxLineWidth var lastSep = "" - for word, isSep in tokenize(s, seps): - let wlen = olen(word) + + var i = 0 + while true: + var j = i + let isSep = j < s.len and s[j] in seps + while j < s.len and (s[j] in seps) == isSep: inc(j) + if j <= i: break + #yield (substr(s, i, j-1), isSep) if isSep: - lastSep = word - spaceLeft = spaceLeft - wlen - elif wlen > spaceLeft: - if splitLongWords and wlen > maxLineWidth: - var i = 0 - while i < word.len: - if spaceLeft <= 0: - spaceLeft = maxLineWidth - result.add newLine - dec spaceLeft - let L = graphemeLen(word, i) - for j in 0 ..< L: result.add word[i+j] - inc i, L + lastSep.setLen 0 + for k in i.. spaceLeft: + if splitLongWords and wlen > maxLineWidth: + var k = 0 + while k < j - i: + if spaceLeft <= 0: + spaceLeft = maxLineWidth + result.add newLine + dec spaceLeft + let L = graphemeLen(s, k+i) + for m in 0 ..< L: result.add s[i+k+m] + inc k, L + else: + spaceLeft = maxLineWidth - wlen + result.add(newLine) + for k in i.. Date: Mon, 8 Jun 2020 20:06:04 +0200 Subject: [PATCH 0681/4254] [OpenBSD] Add arm support (#14608) * add arm support to openbsd * use clang on openbsd --- compiler/installer.ini | 2 +- tools/niminst/buildsh.nimf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index ed815d2eb..9718dbb94 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -11,7 +11,7 @@ Platforms: """ solaris: i386;amd64;sparc;sparc64 freebsd: i386;amd64;powerpc64;arm;arm64 netbsd: i386;amd64 - openbsd: i386;amd64 + openbsd: i386;amd64;arm;arm64 dragonfly: i386;amd64 haiku: i386;amd64 android: i386;arm;arm64 diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 83c4aca6d..537a8a01d 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -90,6 +90,7 @@ case $uos in ;; *openbsd* ) myos="openbsd" + CC="clang" LINK_FLAGS="$LINK_FLAGS -lm" ;; *netbsd* ) From cc3409e26437e7e1d89c8d4b7baacdee695a7b44 Mon Sep 17 00:00:00 2001 From: Max Grender-Jones Date: Tue, 9 Jun 2020 02:49:07 +0100 Subject: [PATCH 0682/4254] Make the example better describe the desired outcome (#14611) --- lib/std/wordwrap.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim index bb6f2dc6f..27df229bf 100644 --- a/lib/std/wordwrap.nim +++ b/lib/std/wordwrap.nim @@ -110,9 +110,9 @@ tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολ # bug #14579 const input60 = """ -This is a long string. It is manually wrapped to 60 -characters. I would not expect it to be changed by -wordwrap if wordwrap is set to wrap at 80 characters""" - const input60Res = """This is a long string. It is manually wrapped to 60 characters. I would not -expect it to be changed by wordwrap if wordwrap is set to wrap at 80 characters""" +This string is wrapped to 60 characters. If we call +wrapwords on it it will be re-wrapped to 80 characters. +""" + const input60Res = """This string is wrapped to 60 characters. If we call wrapwords on it it will be +re-wrapped to 80 characters.""" doAssert wrapWords(input60) == input60Res From aa70cfdea282e717a41f7dbfec32d739f7b2e08a Mon Sep 17 00:00:00 2001 From: ynfle <23086821+ynfle@users.noreply.github.com> Date: Mon, 8 Jun 2020 23:14:26 -0400 Subject: [PATCH 0683/4254] Fix(astspec.txt): type of repeated word (#14612) --- doc/astspec.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/astspec.txt b/doc/astspec.txt index 5d50d82d9..ab2fbcacc 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1014,7 +1014,7 @@ AST: ) Note that not all ``nnkTypeDef`` utilize ``nnkIdent`` as their -their parameter. One of the most common uses of type declarations +parameter. One of the most common uses of type declarations is to work with objects. Concrete syntax: From 881fa94b57d6d0ebd661ad21340c8e75f173809d Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 9 Jun 2020 10:43:42 -0300 Subject: [PATCH 0684/4254] Documentation Fix Typo, Add Table (#14609) --- doc/gc.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/gc.rst b/doc/gc.rst index 01e6b347f..39d6d0484 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -36,13 +36,25 @@ To choose the memory management strategy use the ``--gc:`` switch. cause memory leaks, beware. - ``--gc:orc``. Same as ``-gc:arc`` but adds a cycle collector based on "trial deletion". - Unforunately that makes its performance profile hard to reason about so it is less + Unfortunately that makes its performance profile hard to reason about so it is less useful for hard realtime systems. - ``--gc:none``. No memory management strategy nor garbage collector. Allocated memory is simply never freed. You should use ``--gc:arc`` instead. +================== ======== ================= ====================== +Memory Management Heap Reference Cycles Command line switch +================== ======== ================= ====================== +RefC Local Cycle Collector ``--gc:refc`` +Mark & Sweep Local Cycle Collector ``--gc:markAndSweep`` +ARC Shared Leak ``--gc:arc`` +ORC Shared Cycle Collector ``--gc:orc`` +Boehm Shared Cycle Collector ``--gc:boehm`` +Go Shared Cycle Collector ``--gc:go`` +None Manual Manual ``--gc:none`` +================== ======== ================= ====================== + JavaScript's garbage collector is used for the `JavaScript and NodeJS `_ compilation targets. The `NimScript `_ target uses the memory management strategy built into From b3029ba2139a018946218e1917918d1a1ef019e2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 9 Jun 2020 17:05:01 +0200 Subject: [PATCH 0685/4254] fixes #14578 (#14615) --- compiler/ccgtypes.nim | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 96b59cd60..f7eb1bc34 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -268,19 +268,18 @@ proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = result = true elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): result = true # requested anyway - elif retType != nil and retType.kind == tyLent: - result = true elif (tfFinal in pt.flags) and (pt[0] == nil): result = false # no need, because no subtyping possible else: result = true # ordinary objects are always passed by reference, # otherwise casting doesn't work of tyTuple: - if retType != nil and retType.kind == tyLent: - result = true - else: - result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) - else: result = false + result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) + else: + result = false + # first parameter and return type is 'lent T'? --> use pass by pointer + if s.position == 0 and retType != nil and retType.kind == tyLent: + result = true proc fillResult(conf: ConfigRef; param: PNode) = fillLoc(param.sym.loc, locParam, param, ~"Result", From 6085ad95ff4f712d14de2786a8bd5e2cea4397df Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 9 Jun 2020 20:39:26 +0200 Subject: [PATCH 0686/4254] fixes #14279 (#14618) --- compiler/closureiters.nim | 8 ++++++-- tests/async/tasynctry.nim | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 3422a8a46..675f1ae41 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -129,7 +129,7 @@ # break :stateLoop import - ast, msgs, idents, + ast, astalgo, msgs, idents, renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos type @@ -388,6 +388,10 @@ proc hasYieldsInExpressions(n: PNode): bool = return true else: result = n.hasYields + of nkCast: + for i in 1.. Date: Tue, 9 Jun 2020 18:17:32 -0300 Subject: [PATCH 0687/4254] Documentation update a description (#14619) * Documentation update a description in a page listing links * Update doc/docs.rst Co-authored-by: Danil Yarantsev Co-authored-by: Danil Yarantsev --- doc/docs.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/docs.rst b/doc/docs.rst index 4a69bd69a..b34383253 100644 --- a/doc/docs.rst +++ b/doc/docs.rst @@ -23,8 +23,8 @@ The documentation consists of several documents: | Description of some tools that come with the standard distribution. - | `GC `_ - | Additional documentation about Nim's GC and how to operate it in a - | realtime setting. + | Additional documentation about Nim's multi-paradigm memory management strategies + | and how to operate them in a realtime setting. - | `Source code filters `_ | The Nim compiler supports source code filters as a simple yet powerful @@ -36,4 +36,3 @@ The documentation consists of several documents: - | `Index `_ | The generated index. **Index + (Ctrl+F) == Joy** - From d81bc69587efb9249ad2e022d1bc3f8e4865506f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 9 Jun 2020 19:15:18 -0700 Subject: [PATCH 0688/4254] enable tioselectors on osx; more diagnostic for #13166 (#14625) --- tests/async/tioselectors.nim | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index 48aa64838..c20df29e5 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -10,9 +10,7 @@ template processTest(t, x: untyped) = #stdout.flushFile() if not x: echo(t & " FAILED\r\n") -when defined(macosx): - echo "All tests passed!" -elif not defined(windows): +when not defined(windows): import os, posix, nativesockets when ioselSupportedPlatform: @@ -149,13 +147,13 @@ elif not defined(windows): var timer = selector.registerTimer(100, false, 0) var rc1 = selector.select(140) var rc2 = selector.select(140) - assert(len(rc1) == 1 and len(rc2) == 1) + assert len(rc1) == 1 and len(rc2) == 1, $(len(rc1), len(rc2)) selector.unregister(timer) discard selector.select(0) selector.registerTimer(100, true, 0) var rc4 = selector.select(120) var rc5 = selector.select(120) - assert(len(rc4) == 1 and len(rc5) == 0) + assert len(rc4) == 1 and len(rc5) == 0, $(len(rc4), len(rc5)) assert(selector.isEmpty()) selector.close() result = true From b7b84fa1652e6ef4ea203f553a6c1f0aed51bcf3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 9 Jun 2020 23:57:27 -0700 Subject: [PATCH 0689/4254] parseutils: integerOutOfRangeDefect => integerOutOfRangeError (#14627) --- lib/pure/parseutils.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index c185eca37..c358005f1 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -393,7 +393,7 @@ proc captureBetween*(s: string, first: char, second = '\0', start = 0): string = result = "" discard s.parseUntil(result, if second == '\0': first else: second, i) -proc integerOutOfRangeDefect() {.noinline.} = +proc integerOutOfRangeError() {.noinline.} = raise newException(ValueError, "Parsed integer outside of valid range") # See #6752 @@ -416,11 +416,11 @@ proc rawParseInt(s: string, b: var BiggestInt, start = 0): int = if b >= (low(BiggestInt) + c) div 10: b = b * 10 - c else: - integerOutOfRangeDefect() + integerOutOfRangeError() inc(i) while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored if sign == -1 and b == low(BiggestInt): - integerOutOfRangeDefect() + integerOutOfRangeError() else: b = b * sign result = i - start @@ -459,7 +459,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {. result = parseBiggestInt(s, res, start) when sizeof(int) <= 4: if res < low(int) or res > high(int): - integerOutOfRangeDefect() + integerOutOfRangeError() if result != 0: number = int(res) @@ -493,7 +493,7 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int = prev = 0.BiggestUInt i = start if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}: - integerOutOfRangeDefect() + integerOutOfRangeError() if i < s.len and s[i] == '+': inc(i) # Allow if i < s.len and s[i] in {'0'..'9'}: b = 0 @@ -501,7 +501,7 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int = prev = res res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt if prev > res: - integerOutOfRangeDefect() + integerOutOfRangeError() inc(i) while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored b = res @@ -540,7 +540,7 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {. result = parseBiggestUInt(s, res, start) when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4: if res > 0xFFFF_FFFF'u64: - integerOutOfRangeDefect() + integerOutOfRangeError() if result != 0: number = uint(res) From 5131af1a446140d275510d67bff281f2e42cc19b Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Wed, 10 Jun 2020 09:34:20 +0200 Subject: [PATCH 0690/4254] exceptions.nim: Fix a bad `Error` -> `Defect` renaming (#14621) This commit fixes a mistake from 7d6cbf290a. --- lib/system/exceptions.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index ab092647c..3006cff19 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -140,7 +140,7 @@ type ## This is only raised if the `segfaults module `_ was imported! ArithmeticError* {.deprecated: "See corresponding Defect".} = ArithmeticDefect - DivByZeroError* {.deprecated: "See corresponding Defect".} = ArithmeticDefect + DivByZeroError* {.deprecated: "See corresponding Defect".} = DivByZeroDefect OverflowError* {.deprecated: "See corresponding Defect".} = OverflowDefect AccessViolationError* {.deprecated: "See corresponding Defect".} = AccessViolationDefect AssertionError* {.deprecated: "See corresponding Defect".} = AssertionDefect From 8bbdb8f43fb0da04d4b75bca011662f690972bfe Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 10 Jun 2020 05:10:57 -0700 Subject: [PATCH 0691/4254] fix #14545 windows CI docs (#14590) * fix #14545 windows paths * add lib/std/private/strutils2.nim * remove dependency strutils2 => strutils * address comment: lib/std/private/strutils2.nim => compiler/strutils2.nim --- .github/workflows/ci_docs.yml | 1 + compiler/msgs.nim | 18 +++++++++-- compiler/strutils2.nim | 57 +++++++++++++++++++++++++++++++++++ tests/stdlib/tstrutils2.nim | 32 ++++++++++++++++++++ 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 compiler/strutils2.nim create mode 100644 tests/stdlib/tstrutils2.nim diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 2fbf7e7dc..816f560c9 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -24,6 +24,7 @@ on: - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' + jobs: build: strategy: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index a0fc9b08d..e27eedd1c 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -11,6 +11,7 @@ import options, strutils, os, tables, ropes, terminal, macros, lineinfos, pathutils import std/private/miscdollars +import strutils2 type InstantiationInfo = typeof(instantiationInfo()) template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) @@ -66,6 +67,12 @@ when defined(nimpretty): proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string = substr(conf.m.fileInfos[fid.int].fullContent, a, b) +proc canonicalCase(path: var string) = + ## the idea is to only use this for checking whether a path is already in + ## the table but otherwise keep the original case + when FileSystemCaseSensitive: discard + else: toLowerAscii(path) + proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool = var canon: AbsoluteFile @@ -73,6 +80,7 @@ proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool = canon = canonicalizePath(conf, filename) except OSError: canon = filename + canon.string.canonicalCase result = conf.m.filenameToIndexTbl.hasKey(canon.string) proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool): FileIndex = @@ -89,15 +97,19 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool # This flag indicates that we are working with such a path here pseudoPath = true - if conf.m.filenameToIndexTbl.hasKey(canon.string): + var canon2: string + forceCopy(canon2, canon.string) # because `canon` may be shallow + canon2.canonicalCase + + if conf.m.filenameToIndexTbl.hasKey(canon2): isKnownFile = true - result = conf.m.filenameToIndexTbl[canon.string] + result = conf.m.filenameToIndexTbl[canon2] else: isKnownFile = false result = conf.m.fileInfos.len.FileIndex conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: RelativeFile filename else: relativeTo(canon, conf.projectPath))) - conf.m.filenameToIndexTbl[canon.string] = result + conf.m.filenameToIndexTbl[canon2] = result proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex = var dummy: bool diff --git a/compiler/strutils2.nim b/compiler/strutils2.nim new file mode 100644 index 000000000..6cb50347f --- /dev/null +++ b/compiler/strutils2.nim @@ -0,0 +1,57 @@ +##[ +internal API for now, subject to modifications and moving around + +string API's focusing on performance, that can be used as building blocks +for other routines. + +Un-necessary allocations are avoided and appropriate algorithms are used at the +expense of code clarity when justified. +]## + +proc dataPointer*[T](a: T): pointer = + ## same as C++ `data` that works with std::string, std::vector etc. + ## Note: safe to use when a.len == 0 but whether the result is nil or not + ## is implementation defined for performance reasons. + # this could be improved with ocmpiler support to avoid the `if`, eg in C++ + # `&a[0]` is well defined even if a.size() == 0 + when T is string | seq: + if a.len == 0: nil else: cast[pointer](a[0].unsafeAddr) + elif T is array: + when a.len > 0: a.unsafeAddr + else: nil + elif T is cstring: + cast[pointer](a) + else: static: doAssert false, $T + +proc setLen*(result: var string, n: int, isInit: bool) = + ## when isInit = false, elements are left uninitialized, analog to `{.noinit.}` + ## else, there are 0-initialized. + # xxx placeholder until system.setLen supports this + # to distinguish between algorithms that need 0-initialization vs not; note + # that `setLen` for string is inconsistent with `setLen` for seq. + # likwise with `newString` vs `newSeq`. This should be fixed in `system`. + let n0 = result.len + result.setLen(n) + if isInit and n > n0: + zeroMem(result[n0].addr, n - n0) + +proc forceCopy*(result: var string, a: string) = + ## also forces a copy if `a` is shallow + # the naitve `result = a` would not work if `a` is shallow + let n = a.len + result.setLen n, isInit = false + copyMem(result.dataPointer, a.dataPointer, n) + +proc isUpperAscii(c: char): bool {.inline.} = + # avoids import strutils.isUpperAscii + c in {'A'..'Z'} + +proc toLowerAscii*(a: var string) = + ## optimized and inplace overload of strutils.toLowerAscii + # refs https://github.com/timotheecour/Nim/pull/54 + # this is 10X faster than a naive implementation using a an optimization trick + # that can be adapted in similar contexts. Predictable writes avoid write + # hazards and lead to better machine code, compared to random writes arising + # from: `if c.isUpperAscii: c = ...` + for c in mitems(a): + c = chr(c.ord + (if c.isUpperAscii: (ord('a') - ord('A')) else: 0)) diff --git a/tests/stdlib/tstrutils2.nim b/tests/stdlib/tstrutils2.nim new file mode 100644 index 000000000..881817f90 --- /dev/null +++ b/tests/stdlib/tstrutils2.nim @@ -0,0 +1,32 @@ +import "$lib/.." / compiler/strutils2 + +block: # setLen + var a = "abc" + a.setLen 0 + a.setLen 3, isInit = false + doAssert a[1] == 'b' + a.setLen 0 + a.setLen 3, isInit = true + doAssert a[1] == '\0' + +block: # forceCopy + var a: string + a = "foo" + shallow(a) + var b: string + b = a + doAssert b[0].addr == a[0].addr + var c: string + c.forceCopy a + doAssert c == a + doAssert c[0].addr != a[0].addr + +block: # toLowerAscii + var a = "fooBAr" + a.toLowerAscii + doAssert a == "foobar" + +block: # dataPointer + var a: string + discard a.dataPointer + # doAssert a.dataPointer == nil # not guaranteed From 6aa971d39f1339a27a953972cd329f9cbe791f98 Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 10 Jun 2020 14:53:18 -0400 Subject: [PATCH 0692/4254] Add `proc find` to `heapqueue` (#14628) * Unwind just the "pseudorandom probing" (whole hash-code-keyed variable stride double hashing) part of recent sets & tables changes (which has still been causing bugs over a month later (e.g., two days ago https://github.com/nim-lang/Nim/issues/13794) as well as still having several "figure this out" implementation question comments in them (see just diffs of this PR). This topic has been discussed in many places: https://github.com/nim-lang/Nim/issues/13393 https://github.com/nim-lang/Nim/pull/13418 https://github.com/nim-lang/Nim/pull/13440 https://github.com/nim-lang/Nim/issues/13794 Alternative/non-mandatory stronger integer hashes (or vice-versa opt-in identity hashes) are a better solution that is more general (no illusion of one hard-coded sequence solving all problems) while retaining the virtues of linear probing such as cache obliviousness and age-less tables under delete-heavy workloads (still untested after a month of this change). The only real solution for truly adversarial keys is a hash keyed off of data unobservable to attackers. That all fits better with a few families of user-pluggable/define-switchable hashes which can be provided in a separate PR more about `hashes.nim`. This PR carefully preserves the better (but still hard coded!) probing of the `intsets` and other recent fixes like `move` annotations, hash order invariant tests, `intsets.missingOrExcl` fixing, and the move of `rightSize` into `hashcommon.nim`. * Fix `data.len` -> `dataLen` problem. * Add neglected API call `find` to heapqueue. * Add a changelog.md entry, `since` annotation and rename parameter to be `heap` like all the other procs for consistency. * Add missing import. --- changelog.md | 2 ++ lib/pure/collections/heapqueue.nim | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 8e06d30f1..e86e42b33 100644 --- a/changelog.md +++ b/changelog.md @@ -110,6 +110,8 @@ - new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json serialization/deserialization of custom types. +- new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index f958a5b0a..b0789593a 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -50,6 +50,7 @@ assert jobs[0].priority == 1 ]## +import std/private/since type HeapQueue*[T] = object ## A heap queue, commonly known as a priority queue. @@ -125,6 +126,12 @@ proc pop*[T](heap: var HeapQueue[T]): T = else: result = lastelt +proc find*[T](heap: HeapQueue[T], x: T): int {.since: (1, 3).} = + ## Linear scan to find index of item ``x`` or -1 if not found. + result = -1 + for i in 0 ..< heap.len: + if heap[i] == x: return i + proc del*[T](heap: var HeapQueue[T], index: Natural) = ## Removes the element at `index` from `heap`, maintaining the heap invariant. swap(heap.data[^1], heap.data[index]) @@ -207,18 +214,20 @@ when isMainModule: heap.del(0) doAssert(heap[0] == 1) - heap.del(heap.data.find(7)) + heap.del(heap.find(7)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) - heap.del(heap.data.find(5)) + heap.del(heap.find(5)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) - heap.del(heap.data.find(6)) + heap.del(heap.find(6)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) - heap.del(heap.data.find(2)) + heap.del(heap.find(2)) doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) + doAssert(heap.find(2) == -1) + block: # Test del last var heap = initHeapQueue[int]() let data = [1, 2, 3] From c83a22b76e22d3cae0e0e6e4b9358ed9bd31ecb5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 11 Jun 2020 12:54:32 -0700 Subject: [PATCH 0693/4254] Disable tfdleak_multiple on platforms other than Windows (#14624) --- tests/stdlib/tfdleak_multiple.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/stdlib/tfdleak_multiple.nim b/tests/stdlib/tfdleak_multiple.nim index 51d291284..75c4c0503 100644 --- a/tests/stdlib/tfdleak_multiple.nim +++ b/tests/stdlib/tfdleak_multiple.nim @@ -20,4 +20,7 @@ proc testFdLeak() = count.inc doAssert count == 0, "Leaked " & $count & " times" -when isMainModule: testFdLeak() +when defined(windows): + # tfdleak was only flaky for windows (and for netbsd, there is still a bug) + # note that this test is quite slow, 87 sec on windows. + testFdLeak() From 67d34366dc442cd655c78ce41a3fa50491736eb6 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 12 Jun 2020 03:06:29 -0500 Subject: [PATCH 0694/4254] tools/kochdocs: add log folding supports for more CI services (#14643) Added log folding for: - Github Actions - Azure Pipelines --- tools/kochdocs.nim | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 4f39463e1..eacfb45ca 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -49,14 +49,22 @@ proc exec*(cmd: string, errorcode: int = QuitFailure, additionalPath = "") = template inFold*(desc, body) = if existsEnv("TRAVIS"): echo "travis_fold:start:" & desc.replace(" ", "_") + elif existsEnv("GITHUB_ACTIONS"): + echo "::group::" & desc + elif existsEnv("TF_BUILD"): + echo "##[group]" & desc body if existsEnv("TRAVIS"): echo "travis_fold:end:" & desc.replace(" ", "_") + elif existsEnv("GITHUB_ACTIONS"): + echo "::endgroup::" + elif existsEnv("TF_BUILD"): + echo "##[endgroup]" proc execFold*(desc, cmd: string, errorcode: int = QuitFailure, additionalPath = "") = - ## Execute shell command. Add log folding on Travis CI. + ## Execute shell command. Add log folding for various CI services. # https://github.com/travis-ci/travis-ci/issues/2285#issuecomment-42724719 inFold(desc): exec(cmd, errorcode, additionalPath) From 1168c75381446f8c81ce3f5f329ce2dab238415c Mon Sep 17 00:00:00 2001 From: djazz Date: Fri, 12 Jun 2020 10:16:38 +0200 Subject: [PATCH 0695/4254] httpcore: Add http code 308 Permanent Redirect (#14639) * httpcore: Add http code 308 * httpclient: Add 308 to redirection proc * fix typo --- lib/pure/httpclient.nim | 2 +- lib/pure/httpcore.nim | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 42735ad4e..1ac3ae185 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -457,7 +457,7 @@ proc sendFile(socket: Socket | AsyncSocket, file.close() proc redirection(status: string): bool = - const redirectionNRs = ["301", "302", "303", "307"] + const redirectionNRs = ["301", "302", "303", "307", "308"] for i in items(redirectionNRs): if status.startsWith(i): return true diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 78cb66ded..9c51887cb 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -66,6 +66,7 @@ const Http304* = HttpCode(304) Http305* = HttpCode(305) Http307* = HttpCode(307) + Http308* = HttpCode(308) Http400* = HttpCode(400) Http401* = HttpCode(401) Http403* = HttpCode(403) @@ -272,6 +273,7 @@ proc `$`*(code: HttpCode): string = of 304: "304 Not Modified" of 305: "305 Use Proxy" of 307: "307 Temporary Redirect" + of 308: "308 Permanent Redirect" of 400: "400 Bad Request" of 401: "401 Unauthorized" of 403: "403 Forbidden" From 82e424189ee4bf0f05fcf5695fe1c3e2d2dfc51f Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 12 Jun 2020 05:51:55 -0300 Subject: [PATCH 0696/4254] Add rstgen.rstToLatex convenience proc for renderRstToOut and initRstGenerator with outLatex output, see https://github.com/nim-lang/fusion/pull/11#issuecomment-641804899 (#14629) --- changelog.md | 2 ++ lib/packages/docutils/rstgen.nim | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/changelog.md b/changelog.md index e86e42b33..623b3f6bc 100644 --- a/changelog.md +++ b/changelog.md @@ -111,6 +111,8 @@ - new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json serialization/deserialization of custom types. - new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. +- Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` with `outLatex` output. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 6a7b33cc0..2ec25cc6e 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -29,6 +29,7 @@ import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, algorithm, parseutils import "$lib/../compiler/nimpaths" import "$lib/../compiler/pathutils" +import ../../std/private/since const HtmlExt = "html" @@ -1344,6 +1345,16 @@ proc rstToHtml*(s: string, options: RstParseOptions, renderRstToOut(d, rst, result) +proc rstToLatex*(rstSource: string; options: RstParseOptions): string {.inline, since: (1, 3).} = + ## Convenience proc for `renderRstToOut` and `initRstGenerator`. + runnableExamples: doAssert rstToLatex("*Hello* **world**", {}) == """\emph{Hello} \textbf{world}""" + if rstSource.len == 0: return + var option: bool + var rstGenera: RstGenerator + rstGenera.initRstGenerator(outLatex, defaultConfig(), "input", options) + rstGenera.renderRstToOut(rstParse(rstSource, "", 1, 1, option, options), result) + + when isMainModule: assert rstToHtml("*Hello* **world**!", {}, newStringTable(modeStyleInsensitive)) == From e30a08103da14d5b1e02d6c04dc2d5afb5b9368d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 12 Jun 2020 02:03:52 -0700 Subject: [PATCH 0697/4254] remove tyOpt, mOpt (#14636) * remove tyOpt, mOpt * fixup --- compiler/ast.nim | 10 +++++----- compiler/ccgtypes.nim | 2 +- compiler/jsgen.nim | 9 +++++---- compiler/liftdestructors.nim | 3 ++- compiler/semtypes.nim | 1 - compiler/types.nim | 10 ++++------ compiler/vmdeps.nim | 2 +- compiler/vmgen.nim | 2 -- lib/core/macros.nim | 2 +- lib/system/hti.nim | 2 +- 10 files changed, 20 insertions(+), 23 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 76b1d8c91..bc26defd4 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -434,8 +434,8 @@ type # instantiation and prior to this it has the potential to # be any type. - tyOpt - # Builtin optional type + tyOptDeprecated + # deadcode: was `tyOpt`, Builtin optional type tyVoid # now different from tyEmpty, hurray! @@ -658,7 +658,7 @@ type mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, mDefault, mUnown, mAccessEnv, mReset, - mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, + mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, @@ -1492,7 +1492,7 @@ proc isGCedMem*(t: PType): bool {.inline.} = t.kind == tyProc and t.callConv == ccClosure proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = - const HaveTheirOwnEmpty = {tySequence, tyOpt, tySet, tyPtr, tyRef, tyProc} + const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc} owner.flags = owner.flags + (elem.flags * {tfHasMeta, tfTriggersCompileTime}) if tfNotNil in elem.flags: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: @@ -1505,7 +1505,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = if mask != {} and propagateHasAsgn: let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) if o2.kind in {tyTuple, tyObject, tyArray, - tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}: + tySequence, tySet, tyDistinct, tyOpenArray, tyVarargs}: o2.flags.incl mask owner.flags.incl mask diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index f7eb1bc34..199d5c918 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -367,7 +367,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = if result != nil: return result = getTypePre(m, typ, sig) if result != nil: return - let concrete = typ.skipTypes(abstractInst + {tyOpt}) + let concrete = typ.skipTypes(abstractInst) case concrete.kind of tySequence, tyTuple, tyObject: result = getTypeName(m, typ, sig) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 9f022882b..99d2bc4f2 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -193,7 +193,7 @@ proc mapType(typ: PType): TJSTypeKind = of tyBool: result = etyBool of tyFloat..tyFloat128: result = etyFloat of tySet: result = etyObject # map a set to a table - of tyString, tySequence, tyOpt: result = etySeq + of tyString, tySequence: result = etySeq of tyObject, tyArray, tyTuple, tyOpenArray, tyVarargs, tyUncheckedArray: result = etyObject of tyNil: result = etyNull @@ -210,6 +210,7 @@ proc mapType(typ: PType): TJSTypeKind = else: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString + of tyOptDeprecated: doAssert false proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) @@ -1041,7 +1042,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = # we don't care if it's an etyBaseIndex (global) of a string, it's # still a string that needs to be copied properly: - if x.typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}: + if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}: xtyp = etySeq case xtyp of etySeq: @@ -1086,7 +1087,7 @@ proc genFastAsgn(p: PProc, n: PNode) = # See bug #5933. So we try to be more compatible with the C backend semantics # here for 'shallowCopy'. This is an educated guess and might require further # changes later: - let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString} + let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString} genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy) proc genSwap(p: PProc, n: PNode) = @@ -1697,7 +1698,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("null", indirect) of tySequence, tyString: result = putToSeq("[]", indirect) - of tyCString, tyOpt, tyProc: + of tyCString, tyProc: result = putToSeq("null", indirect) of tyStatic: if t.n != nil: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 2d8655cae..0346f6c67 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -703,7 +703,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind of tyNone, tyEmpty, tyVoid: discard of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, - tyPtr, tyOpt, tyUncheckedArray, tyVar, tyLent: + tyPtr, tyUncheckedArray, tyVar, tyLent: defaultOp(c, t, body, x, y) of tyRef: if c.g.config.selectedGC in {gcArc, gcOrc}: @@ -785,6 +785,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = of tyOrdinal, tyRange, tyInferred, tyGenericInst, tyAlias, tySink: fillBody(c, lastSon(t), body, x, y) + of tyOptDeprecated: doAssert false proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 77da403fa..313328385 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1814,7 +1814,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semContainer(c, n, tySequence, "seq", prev) if optSeqDestructors in c.config.globalOptions: incl result.flags, tfHasAsgn - of mOpt: result = semContainer(c, n, tyOpt, "opt", prev) of mVarargs: result = semVarargs(c, n, prev) of mTypeDesc, mType, mTypeOf: result = makeTypeDesc(c, semTypeNode(c, n[1], nil)) diff --git a/compiler/types.nim b/compiler/types.nim index e1b283f87..aaaa8e99f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -608,10 +608,6 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "seq" if t.len > 0: result &= "[" & typeToString(t[0]) & ']' - of tyOpt: - result = "opt" - if t.len > 0: - result &= "opt[" & typeToString(t[0]) & ']' of tyOrdinal: result = "ordinal" if t.len > 0: @@ -1150,7 +1146,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst, - tyAnd, tyOr, tyNot, tyAnything, tyOpt, tyOwned: + tyAnd, tyOr, tyNot, tyAnything, tyOwned: cycleCheck() if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) @@ -1173,6 +1169,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = cycleCheck() result = sameTypeAux(a.lastSon, b.lastSon, c) of tyNone: result = false + of tyOptDeprecated: doAssert false proc sameBackendType*(x, y: PType): bool = var c = initSameTypeClosure() @@ -1365,7 +1362,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = t else: result = typeAllowedAux(marker, lastSon(t), kind, flags-{taHeap}) - of tySequence, tyOpt: + of tySequence: if t[0].kind != tyEmpty: result = typeAllowedAux(marker, t[0], kind, flags+{taHeap}) elif kind in {skVar, skLet}: @@ -1408,6 +1405,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap}) else: result = t + of tyOptDeprecated: doAssert false proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType = # returns 'nil' on success and otherwise the part of the type that is diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 7cfba046a..6f90b7918 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -224,7 +224,6 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info) of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info) of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) - of tyOpt: result = mapTypeToBracket("opt", mOpt, t, info) of tyProc: if inst: result = newNodeX(nkProcTy) @@ -298,6 +297,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; if t.n != nil: result.add t.n.copyTree of tyOwned: result = mapTypeToBracket("owned", mBuiltinType, t, info) + of tyOptDeprecated: doAssert false proc opMapTypeToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode = result = mapTypeToAstX(cache, t, info, inst=false, allowRecursionX=true) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index b408db08b..52b7b6eb3 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1820,8 +1820,6 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = result.add getNullValue(t[i], info, conf) of tySet: result = newNodeIT(nkCurly, info, t) - of tyOpt: - result = newNodeIT(nkNilLit, info, t) of tySequence: result = newNodeIT(nkBracket, info, t) else: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 9e17b665a..3590a162b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -106,7 +106,7 @@ type ntyError, ntyBuiltinTypeClass, ntyUserTypeClass, ntyUserTypeClassInst, ntyCompositeTypeClass, ntyInferred, ntyAnd, ntyOr, ntyNot, - ntyAnything, ntyStatic, ntyFromExpr, ntyOpt, ntyVoid + ntyAnything, ntyStatic, ntyFromExpr, ntyOptDeprecated, ntyVoid TNimTypeKinds* {.deprecated.} = set[NimTypeKind] NimSymKind* = enum diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 63c1a5448..b77f7ccde 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -69,7 +69,7 @@ type tyAnythingHidden, tyStaticHidden, tyFromExprHidden, - tyOpt, + tyOptDeprecated, tyVoidHidden TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase From 5a26c3799b77e68c6e9d1c90e0dcb614de25206f Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 12 Jun 2020 11:57:10 +0200 Subject: [PATCH 0698/4254] reorder.nim: fixed typos --- compiler/reorder.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 5e380a199..28e12ca2a 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -290,13 +290,13 @@ proc hasAccQuoted(n: PNode): bool = if hasAccQuoted(a): return true -const extandedProcDefs = procDefs + {nkMacroDef, nkTemplateDef} +const extendedProcDefs = procDefs + {nkMacroDef, nkTemplateDef} proc hasAccQuotedDef(n: PNode): bool = # Checks if the node is a function, macro, template ... # with a quoted name or if it contains one case n.kind - of extandedProcDefs: + of extendedProcDefs: result = n[0].hasAccQuoted of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt: for a in n: @@ -316,7 +316,7 @@ proc hasBody(n: PNode): bool = case n.kind of nkCommand, nkCall: result = true - of extandedProcDefs: + of extendedProcDefs: result = n[^1].kind == nkStmtList of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt: for a in n: From d1498230198888c1b7699ed0b1de12796fd30a7d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 12 Jun 2020 21:19:23 -0700 Subject: [PATCH 0699/4254] fix #13166 tioselectors flaky test on freebsd+OSX (#14634) --- testament/important_packages.nim | 3 +- tests/async/tioselectors.nim | 9 +++--- tests/m14634.nim | 48 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 tests/m14634.nim diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 19e11e322..5a28fa3dd 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -40,7 +40,8 @@ pkg1 "delaunay" pkg1 "docopt" pkg1 "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg1 "elvis" -pkg1 "fidget", true, "nim c -d:release -r tests/runNative.nim" +# pkg1 "fidget", true, "nim c -d:release -r tests/runNative.nim" + # Error: cannot open 'tests/runNative.nim' pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "ggplotnim", true, "nim c -d:noCairo -r -d:nimWorkaround14447 tests/tests.nim" diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index c20df29e5..f7487525a 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -145,14 +145,15 @@ when not defined(windows): proc timer_notification_test(): bool = var selector = newSelector[int]() var timer = selector.registerTimer(100, false, 0) - var rc1 = selector.select(140) - var rc2 = selector.select(140) + var rc1 = selector.select(10000) + var rc2 = selector.select(10000) + # if this flakes, see tests/m14634.nim assert len(rc1) == 1 and len(rc2) == 1, $(len(rc1), len(rc2)) selector.unregister(timer) discard selector.select(0) selector.registerTimer(100, true, 0) - var rc4 = selector.select(120) - var rc5 = selector.select(120) + var rc4 = selector.select(10000) + var rc5 = selector.select(1000) # this will be an actual wait, keep it small assert len(rc4) == 1 and len(rc5) == 0, $(len(rc4), len(rc5)) assert(selector.isEmpty()) selector.close() diff --git a/tests/m14634.nim b/tests/m14634.nim new file mode 100644 index 000000000..56a3d9034 --- /dev/null +++ b/tests/m14634.nim @@ -0,0 +1,48 @@ +#[ +Tool to investigate underlying reasons for https://github.com/nim-lang/Nim/pull/14634 +nim r --threads:on -d:threadsafe tests/m14634.nim +]# + +when not defined(windows): + import std/selectors + + type TestData = object + s1, s2, s3: int + + proc timerNotificationTestImpl(data: var TestData) = + var selector = newSelector[int]() + let t0 = 5 + var timer = selector.registerTimer(t0, false, 0) + let t = 2000 + # values too close to `t0` cause the test to be flaky in CI on OSX+freebsd + # When running locally, t0=100, t=98 will succeed some of the time which indicates + # there is some lag involved. Note that the higher `t-t0` is, the less times + # the test fails. + var rc1 = selector.select(t) + var rc2 = selector.select(t) + assert len(rc1) <= 1 and len(rc2) <= 1 + data.s1 += ord(len(rc1) == 1) + data.s2 += ord(len(rc2) == 1) + selector.unregister(timer) + discard selector.select(0) + selector.registerTimer(t0, true, 0) + # same comment as above + var rc4 = selector.select(t) + let t2 = 100 + # this can't be too large as it'll actually wait that long: + # timer_notification_test.n * t2 + var rc5 = selector.select(t2) + assert len(rc4) + len(rc5) <= 1 + data.s3 += ord(len(rc4) + len(rc5) == 1) + assert(selector.isEmpty()) + selector.close() + + proc timerNotificationTest() = + var data: TestData + let n = 10 + for i in 0.. Date: Sat, 13 Jun 2020 11:44:01 +0100 Subject: [PATCH 0700/4254] Clarify imported exceptions note in manual --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 451359dca..6eec8bef9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4354,7 +4354,7 @@ caught by reference. Example: fn() **Note:** `getCurrentException()` and `getCurrentExceptionMsg()` are not available -for imported exceptions. One needs to use the `except ImportedException as x:` syntax +for imported exceptions from C++. One needs to use the `except ImportedException as x:` syntax and rely on functionality of the `x` object to get exception details. From 0fc5d3f13beb13b4bd5a6174a2f2b00d14d862fb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 14 Jun 2020 02:11:26 -0700 Subject: [PATCH 0701/4254] fix #14655 setLen(seq) now zeros memory (#14656) * simplify sysstr.nim * fix #14655 --- lib/system/sysstr.nim | 29 +++++++++++++++-------------- tests/collections/tseq.nim | 9 ++++++++- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index dbf9bcf06..06e605a7b 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -15,6 +15,13 @@ # we don't use refcounts because that's a behaviour # the programmer may not want + +proc dataPointer(a: PGenericSeq, elemAlign: int): pointer = + cast[pointer](cast[ByteAddress](a) +% align(GenericSeqSize, elemAlign)) + +proc dataPointer(a: PGenericSeq, elemAlign, elemSize, index: int): pointer = + cast[pointer](cast[ByteAddress](a) +% align(GenericSeqSize, elemAlign) +% (index*%elemSize)) + proc resize(old: int): int {.inline.} = if old <= 0: result = 4 elif old < 65536: result = old * 2 @@ -267,9 +274,6 @@ proc incrSeqV2(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compil result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r)) result.reserved = r -template `+!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) +% s) - proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} = if s == nil: result = cast[PGenericSeq](newSeq(typ, 1)) @@ -281,7 +285,7 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} = when defined(nimIncrSeqV3): result = cast[PGenericSeq](newSeq(typ, r)) result.len = s.len - copyMem(result +! align(GenericSeqSize, typ.base.align), s +! align(GenericSeqSize, typ.base.align), s.len * typ.base.size) + copyMem(dataPointer(result, typ.base.align), dataPointer(s, typ.base.align), s.len * typ.base.size) # since we steal the content from 's', it's crucial to set s's len to 0. s.len = 0 else: @@ -303,7 +307,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS when false: # compileOption("gc", "v2"): for i in newLen..result.len-1: let len0 = gch.tempStack.len - forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% (i*%elemSize)), + forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), extGetCellType(result).base, waPush) let len1 = gch.tempStack.len for i in len0 ..< len1: @@ -312,8 +316,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS else: if ntfNoRefs notin extGetCellType(result).base.flags: for i in newLen..result.len-1: - forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% - align(GenericSeqSize, elemAlign) +% (i*%elemSize)), + forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out @@ -322,8 +325,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destroy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% - (newLen*%elemSize)), (result.len-%newLen) *% elemSize) + zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) result.len = newLen proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. @@ -338,7 +340,7 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. if s.space < newLen: let r = max(resize(s.space), newLen) result = cast[PGenericSeq](newSeq(typ, r)) - copyMem(result +! align(GenericSeqSize, elemAlign), s +! align(GenericSeqSize, elemAlign), s.len * elemSize) + copyMem(dataPointer(result, elemAlign), dataPointer(s, elemAlign), s.len * elemSize) # since we steal the content from 's', it's crucial to set s's len to 0. s.len = 0 elif newLen < s.len: @@ -349,8 +351,7 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. not defined(gcRegions): if ntfNoRefs notin typ.base.flags: for i in newLen..result.len-1: - forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% - align(GenericSeqSize, elemAlign) +% (i*%elemSize)), + forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out @@ -359,10 +360,10 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destroy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% - (newLen*%elemSize)), (result.len-%newLen) *% elemSize) + zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) else: result = s + zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize) result.len = newLen else: result = setLengthSeq(s, typ.base.size, newLen) diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim index ac68e5636..263a571bf 100644 --- a/tests/collections/tseq.nim +++ b/tests/collections/tseq.nim @@ -206,4 +206,11 @@ block ttoseq: stdout.write("\n") block tseqmapitchain: - doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100)) \ No newline at end of file + doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100)) + + +for i in 0..100: + # fix #14655 + var test = newSeqOfCap[uint32](1) + test.setLen(1) + doAssert test[0] == 0, $(test[0], i) From 4e3edf58360d1c4da79d50acdf5cf98b97ce585d Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Sun, 14 Jun 2020 05:12:08 -0400 Subject: [PATCH 0702/4254] add arc and orc to gc list (#14653) --- doc/advopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index a668be5c0..e522973cd 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -113,7 +113,7 @@ Advanced options: --skipUserCfg:on|off do not read the user's configuration file --skipParentCfg:on|off do not read the parent dirs' configuration files --skipProjCfg:on|off do not read the project's configuration file - --gc:refc|markAndSweep|boehm|go|none|regions + --gc:refc|arc|orc|markAndSweep|boehm|go|none|regions select the GC to use; default is 'refc' --exceptions:setjmp|cpp|goto|quirky select the exception handling implementation From d749c8cd87508871dc28b528f57d26b1004007b3 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 14 Jun 2020 04:22:55 -0500 Subject: [PATCH 0703/4254] compiler/commands: make gitHash settable at compile-time. (#14654) This is useful for building nightlies, since we will be building from a generated source archive and git metadata is lost there. --- compiler/commands.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 2d8418139..c945a633a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -98,7 +98,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = CPU[conf.target.hostCPU].name, CompileDate]), {msgStdout}) - const gitHash = gorge("git log -n 1 --format=%H").strip + const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip when gitHash.len == 40: msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) From 5a22d6b57bec6eca3d123a7d911f32b58b410cf8 Mon Sep 17 00:00:00 2001 From: jcosborn Date: Mon, 15 Jun 2020 01:40:12 -0500 Subject: [PATCH 0704/4254] fix codegen bug due to changing existing symbol declaration in template (#14666) --- compiler/semtempl.nim | 2 +- tests/template/template_various.nim | 106 ++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index dedea2e99..c9cd82833 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -229,7 +229,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = if s != nil and s.owner == c.owner and sfGenSym in s.flags: onUse(n.info, s) replaceIdentBySym(c.c, n, newSymNode(s, n.info)) - elif not (n.kind == nkSym and sfGenSym in n.sym.flags): + elif n.kind != nkSym: let local = newGenSym(k, ident, c) addPrelimDecl(c.c, local) styleCheckDef(c.c.config, n.info, local) diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim index ac7e91fa2..e8202a2e0 100644 --- a/tests/template/template_various.nim +++ b/tests/template/template_various.nim @@ -10,6 +10,28 @@ bar7 4true 132 20 +1 +-1 +4 +11 +26 +57 +-1-1-1 + 4 +4 + 4 + 11 +11 + 4 + 11 + 26 +26 + 4 + 11 + 26 + 57 +57 +-1-1-1 ''' """ @@ -245,3 +267,87 @@ template parse9(body: untyped): untyped = parse9: echo val9("1") + + +block gensym1: + template x: untyped = -1 + template t1() = + template x: untyped {.gensym.} = 1 + echo x() # 1 + template t2() = + template x: untyped = 1 # defaults to {.inject.} + echo x() # -1 injected x not available during template definition + t1() + t2() + +block gensym2: + let x,y,z = -1 + template `!`(xx,yy: typed): untyped = + template x: untyped {.gensym.} = xx + template y: untyped {.gensym.} = yy + let z = x + x + y + z + var + a = 1 + b = 2 + c = 3 + d = 4 + e = 5 + echo a ! b + echo a ! b ! c + echo a ! b ! c ! d + echo a ! b ! c ! d ! e + echo x,y,z + +block gensym3: + macro liftStmts(body: untyped): auto = + # convert + # template x: untyped {.gensym.} = + # let z = a + a + b + # echo z + # z + # to + # let z = a + a + b + # echo z + # template x: untyped {.gensym.} = + # z + #echo body.repr + body.expectKind nnkStmtList + result = newNimNode nnkStmtList + for s in body: + s.expectKind nnkTemplateDef + var sle = s[6] + while sle.kind == nnkStmtList: + doAssert(sle.len==1) + sle = sle[0] + if sle.kind == nnkStmtListExpr: + let n = sle.len + for i in 0..(n-2): + result.add sle[i] + var td = newNimNode nnkTemplateDef + for i in 0..5: + td.add s[i] + td.add sle[n-1] + result.add td + else: + result.add s + #echo result.repr + let x,y,z = -1 + template `!`(xx,yy: typed): untyped = + liftStmts: + template x: untyped {.gensym.} = xx + template y: untyped {.gensym.} = yy + let z = x + x + y + echo " ", z + z + var + a = 1 + b = 2 + c = 3 + d = 4 + e = 5 + echo a ! b + echo a ! b ! c + echo a ! b ! c ! d + echo a ! b ! c ! d ! e + echo x,y,z From a056b4c3f135120bdd948c32273fd902273c2773 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 15 Jun 2020 03:55:24 -0300 Subject: [PATCH 0705/4254] Change 'Future Directions' to link memory management documentation (#14664) --- doc/manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 6eec8bef9..75cc507a4 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7449,9 +7449,9 @@ be used: deepCopy(perThread, someGlobal) -Future directions: +See also: -- A shared GC'ed heap might be provided. +- `Shared heap memory management. `_. Threadvar pragma From 571bc011eaa9eb9214291d34ca008ab41ce7ebc1 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Mon, 15 Jun 2020 08:58:11 +0200 Subject: [PATCH 0706/4254] Added --benchmarkVM to times.cpuTime() documentation (#14663) --- lib/pure/times.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 1fff3d99b..01eb16c23 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -2619,6 +2619,8 @@ when not defined(js): fib.add(fib[^1] + fib[^2]) echo "CPU time [s] ", cpuTime() - t0 echo "Fib is [s] ", fib + ## When the flag `--benchmarkVM` is passed to the compiler, this proc is + ## also available at compile time when defined(posix) and not defined(osx) and declared(CLOCK_THREAD_CPUTIME_ID): # 'clocksPerSec' is a compile-time constant, possibly a # rather awful one, so use clock_gettime instead From 3cbf59336d6b9838dbf534f8e55fdfc8e7ab6954 Mon Sep 17 00:00:00 2001 From: solo989 Date: Mon, 15 Jun 2020 00:15:17 -0700 Subject: [PATCH 0707/4254] Update newLit set[T] to work when set is empty. (#14662) * Update macros.nim * Update lib/core/macros.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- lib/core/macros.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 3590a162b..27ff063a7 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -793,6 +793,10 @@ proc newLit*[T](s: set[T]): NimNode {.compileTime.} = result = nnkCurly.newTree for x in s: result.add newLit(x) + if result.len == 0: + # add type cast for empty set + var typ = getTypeInst(typeof(s))[1] + result = newCall(typ,result) proc newLit*(arg: tuple): NimNode {.compileTime.} = result = nnkPar.newTree From bf604c6829f87a551dc3b5ad836679be4ab53789 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Jun 2020 01:57:34 -0700 Subject: [PATCH 0708/4254] normalizeExe (#14668) --- changelog.md | 1 + lib/pure/os.nim | 16 ++++++++++++++-- testament/testament.nim | 11 +++-------- tests/stdlib/tos.nim | 10 ++++++++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index 623b3f6bc..b9fb48117 100644 --- a/changelog.md +++ b/changelog.md @@ -112,6 +112,7 @@ - new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. - Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` with `outLatex` output. +- Add `os.normalizeExe`, eg: `koch` => `./koch`. ## Language changes diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 97e414d44..79cd27e10 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1407,6 +1407,18 @@ proc absolutePath*(path: string, root = getCurrentDir()): string = proc absolutePathInternal(path: string): string = absolutePath(path, getCurrentDir()) +proc normalizeExe*(file: var string) {.since: (1, 3, 5).} = + ## on posix, prepends `./` if `file` doesn't contain `/` and is not `"", ".", ".."`. + runnableExamples: + import sugar + when defined(posix): + doAssert "foo".dup(normalizeExe) == "./foo" + doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" + doAssert "".dup(normalizeExe) == "" + when defined(posix): + if file.len > 0 and DirSep notin file and file != "." and file != "..": + file = "./" & file + proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## Normalize a path. ## @@ -1420,8 +1432,8 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## ## See also: ## * `absolutePath proc <#absolutePath,string>`_ - ## * `normalizedPath proc <#normalizedPath,string>`_ for a version which returns - ## a new string + ## * `normalizedPath proc <#normalizedPath,string>`_ for outplace version + ## * `normalizeExe proc <#normalizeExe,string>`_ runnableExamples: when defined(posix): var a = "a///b//..//c///d" diff --git a/testament/testament.nim b/testament/testament.nim index f83b244c2..69b7e322e 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -13,8 +13,8 @@ import strutils, pegs, os, osproc, streams, json, backend, parseopt, specs, htmlgen, browsers, terminal, algorithm, times, md5, sequtils, azure - -include compiler/nodejs +from std/sugar import dup +import compiler/nodejs var useColors = true var backendLogging = true @@ -450,12 +450,7 @@ proc testSpecHelper(r: var TResults, test: TTest, expected: TSpec, exeCmd = nodejs args = concat(@[exeFile], args) else: - if defined(posix) and not exeFile.contains('/'): - # "security" in Posix is actually just a euphemism - # for "unproductive arbitrary shit" - exeCmd = "./" & exeFile - else: - exeCmd = exeFile + exeCmd = exeFile.dup(normalizeExe) if expected.useValgrind: args = @["--error-exitcode=1"] & exeCmd & args exeCmd = "valgrind" diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index a440d86d8..814ff103d 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -510,3 +510,13 @@ block: # isValidFilename doAssert isValidFilename("ux.bat") doAssert isValidFilename("nim.nim") doAssert isValidFilename("foo.log") + +import sugar + +block: # normalizeExe + doAssert "".dup(normalizeExe) == "" + when defined(posix): + doAssert "foo".dup(normalizeExe) == "./foo" + doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" + when defined(windows): + doAssert "foo".dup(normalizeExe) == "foo" From d51beb7b20c7670a17769b30e721fe67761f98e6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Jun 2020 04:22:43 -0700 Subject: [PATCH 0709/4254] make `fromJson/toJson` work with `array[range, typ]`, + 1 bugfix (#14669) * make toJson more robust * properly handle array --- lib/std/jsonutils.nim | 32 ++++++++++++++++++++++++-------- tests/stdlib/tjsonutils.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index bfa600fa9..be3d7e7c8 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -2,9 +2,17 @@ This module implements a hookable (de)serialization for arbitrary types. Design goal: avoid importing modules where a custom serialization is needed; see strtabs.fromJsonHook,toJsonHook for an example. - ]## +runnableExamples: + import std/[strtabs,json] + type Foo = ref object + t: bool + z1: int8 + let a = (1.5'f32, (b: "b2", a: "a2"), 'x', @[Foo(t: true, z1: -3), nil], [{"name": "John"}.newStringTable]) + let j = a.toJson + doAssert j.jsonTo(type(a)).toJson == j + import std/[json,tables,strutils] #[ @@ -12,10 +20,14 @@ xxx use toJsonHook,fromJsonHook for Table|OrderedTable add Options support also using toJsonHook,fromJsonHook and remove `json=>options` dependency -future direction: -add a way to customize serialization, for eg allowing missing -or extra fields in JsonNode, field renaming, and a way to handle cyclic references -using a cache of already visited addresses. +Future directions: +add a way to customize serialization, for eg: +* allowing missing or extra fields in JsonNode +* field renaming +* allow serializing `enum` and `char` as `string` instead of `int` + (enum is more compact/efficient, and robust to enum renamings, but string + is more human readable) +* handle cyclic references, using a cache of already visited addresses ]# proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} @@ -65,8 +77,10 @@ proc fromJson*[T](a: var T, b: JsonNode) = fromJson(a[], b) elif T is array: checkJson a.len == b.len, $(a.len, b.len, $T) - for i, val in b.getElems: - fromJson(a[i], val) + var i = 0 + for ai in mitems(a): + fromJson(ai, b[i]) + i.inc elif T is seq: a.setLen b.len for i, val in b.getElems: @@ -114,12 +128,14 @@ proc toJson*[T](a: T): JsonNode = result = newJArray() for v in a.fields: result.add toJson(v) elif T is ref | ptr: - if a == nil: result = newJNull() + if system.`==`(a, nil): result = newJNull() else: result = toJson(a[]) elif T is array | seq: result = newJArray() for ai in a: result.add toJson(ai) elif T is pointer: result = toJson(cast[int](a)) + # edge case: `a == nil` could've also led to `newJNull()`, but this results + # in simpler code for `toJson` and `fromJson`. elif T is distinct: result = toJson(a.distinctBase) elif T is bool: result = %(a) elif T is Ordinal: result = %(a.ord) diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 01c6aa05a..fca980dc9 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -13,12 +13,26 @@ proc testRoundtrip[T](t: T, expected: string) = import tables import strtabs +type Foo = ref object + id: int + +proc `==`(a, b: Foo): bool = + a.id == b.id + template fn() = block: # toJson, jsonTo type Foo = distinct float testRoundtrip('x', """120""") when not defined(js): testRoundtrip(cast[pointer](12345)): """12345""" + when nimvm: + discard + # bugs: + # Error: unhandled exception: 'intVal' is not accessible using discriminant 'kind' of type 'TNode' [ + # Error: VM does not support 'cast' from tyNil to tyPointer + else: + testRoundtrip(pointer(nil)): """0""" + testRoundtrip(cast[pointer](nil)): """0""" # causes workaround in `fromJson` potentially related to # https://github.com/nim-lang/Nim/issues/12282 @@ -40,5 +54,17 @@ template fn() = testRoundtrip(a): """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null}]""" + block: + # edge case when user defined `==` doesn't handle `nil` well, eg: + # https://github.com/nim-lang/nimble/blob/63695f490728e3935692c29f3d71944d83bb1e83/src/nimblepkg/version.nim#L105 + testRoundtrip(@[Foo(id: 10), nil]): """[{"id":10},null]""" + + block: + type Foo = enum f1, f2, f3, f4, f5 + type Bar = enum b1, b2, b3, b4 + let a = [f2: b2, f3: b3, f4: b4] + doAssert b2.ord == 1 # explains the `1` + testRoundtrip(a): """[1,2,3]""" + static: fn() fn() From 49033eb5314d7f07e5ecc088dd0933010bb581d8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Jun 2020 04:27:33 -0700 Subject: [PATCH 0710/4254] make tests/stdlib tests joinable (#14626) * make tests/stdlib tests joinable * fixup --- testament/categories.nim | 33 +++++++++++++++++++------------ tests/stdlib/tcgi.nim | 6 ++++++ tests/stdlib/tfdleak.nim | 1 + tests/stdlib/tfdleak_multiple.nim | 4 ++++ tests/stdlib/tmarshal.nim | 5 +++++ tests/stdlib/tnetbind.nim | 10 ++++++++++ tests/stdlib/tosproc.nim | 9 ++++++++- tests/stdlib/trst.nim | 6 ++++++ tests/stdlib/tstrutil.nim | 10 ++++------ 9 files changed, 64 insertions(+), 20 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 88f168608..4e83fa1a9 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -35,7 +35,6 @@ const "niminaction", "threads", "untestable", - "stdlib", "testdata", "nimcache", "coroutines", @@ -573,6 +572,9 @@ proc isJoinableSpec(spec: TSpec): bool = spec.outputCheck != ocSubstr and spec.ccodeCheck.len == 0 and (spec.targets == {} or spec.targets == {targetC}) + if result: + if spec.file.readFile.contains "when isMainModule": + result = false proc norm(s: var string) = while true: @@ -585,6 +587,13 @@ proc quoted(a: string): string = # todo: consider moving to system.nim result.addQuoted(a) +proc normalizeExe(file: string): string = + # xxx common pattern, should be exposed in std/os, even if simple (error prone) + when defined(posix): + if file.len == 0: "" + elif DirSep in file: file else: "./" & file + else: file + proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = ## returns a list of tests that have problems var specs: seq[TSpec] = @[] @@ -620,26 +629,24 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = for i, runSpec in specs: let file = runSpec.file - let file2 = outDir / ("megatest_" & $i & ".nim") + let file2 = outDir / ("megatest_$1.nim" % $i) # `include` didn't work with `trecmod2.nim`, so using `import` - let code = "echo \"" & marker & "\", " & quoted(file) & "\n" + let code = "echo \"$1\", $2\n" % [marker, quoted(file)] createDir(file2.parentDir) writeFile(file2, code) - megatest.add "import " & quoted(file2) & "\n" - megatest.add "import " & quoted(file) & "\n" + megatest.add "import $1\nimport $2\n" % [quoted(file2), quoted(file)] - writeFile("megatest.nim", megatest) - - let args = ["c", "--nimCache:" & outDir, "-d:testing", "--listCmd", - "--listFullPaths:off", "--excessiveStackTrace:off", "megatest.nim"] + let megatestFile = testsDir / "megatest.nim" # so it uses testsDir / "config.nims" + writeFile(megatestFile, megatest) + let root = getCurrentDir() + let args = ["c", "--nimCache:" & outDir, "-d:testing", "--listCmd", "--path:" & root, megatestFile] var (cmdLine, buf, exitCode) = execCmdEx2(command = compilerPrefix, args = args, input = "") if exitCode != 0: - echo "$ ", cmdLine - echo buf.string + echo "$ " & cmdLine & "\n" & buf.string quit("megatest compilation failed") - (buf, exitCode) = execCmdEx("./megatest") + (buf, exitCode) = execCmdEx(megatestFile.changeFileExt(ExeExt).normalizeExe) if exitCode != 0: echo buf.string quit("megatest execution failed") @@ -662,7 +669,7 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = else: echo "output OK" removeFile("outputGotten.txt") - removeFile("megatest.nim") + removeFile(megatestFile) #testSpec r, makeTest("megatest", options, cat) # --------------------------------------------------------------------------- diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index bc177125e..7df1b077d 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,3 +1,9 @@ +discard """ + output: ''' +[Suite] Test cgi module +''' +""" + import unittest import cgi, strtabs diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim index 5931be8c1..79d7ee0d0 100644 --- a/tests/stdlib/tfdleak.nim +++ b/tests/stdlib/tfdleak.nim @@ -2,6 +2,7 @@ discard """ exitcode: 0 output: "" matrix: "; -d:nimInheritHandles" + joinable: false """ import os, osproc, strutils, nativesockets, net, selectors, memfiles, diff --git a/tests/stdlib/tfdleak_multiple.nim b/tests/stdlib/tfdleak_multiple.nim index 75c4c0503..22387607f 100644 --- a/tests/stdlib/tfdleak_multiple.nim +++ b/tests/stdlib/tfdleak_multiple.nim @@ -1,3 +1,7 @@ +discard """ +joinable: false +""" + import os, osproc, strutils const Iterations = 200 diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index a6fc6c1a5..118d0ae02 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -5,8 +5,13 @@ true alpha 100 omega 200 ''' +joinable: false """ +#[ +joinable: false pending https://github.com/nim-lang/Nim/issues/9754 +]# + import marshal template testit(x) = discard $$to[type(x)]($$x) diff --git a/tests/stdlib/tnetbind.nim b/tests/stdlib/tnetbind.nim index b2bcf4b05..734b6c5e7 100644 --- a/tests/stdlib/tnetbind.nim +++ b/tests/stdlib/tnetbind.nim @@ -1,3 +1,13 @@ +discard """ +joinable: false +""" + +#[ +joinable: false +otherwise: +Error: unhandled exception: Address already in use [OSError] +]# + import net ## Test for net.bindAddr diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index b5328c9eb..cb6e260c5 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -1,4 +1,11 @@ -# test the osproc module +discard """ +joinable: false +""" + +#[ +joinable: false +because it'd need cleanup up stdout +]# import stdtest/[specialpaths, unittest_light] diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 6b1bd6897..797010a22 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -1,3 +1,9 @@ +discard """ + output: ''' +[Suite] RST include directive +''' +""" + # tests for rst module import ../../lib/packages/docutils/rstgen diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index cb6985a6e..5702b7341 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -1,6 +1,3 @@ -discard """ - output: "ha/home/a1xyz/usr/bin" -""" # test the new strutils module import @@ -15,7 +12,7 @@ template rejectParse(e) = except ValueError: discard proc testStrip() = - write(stdout, strip(" ha ")) + doAssert strip(" ha ") == "ha" proc testRemoveSuffix = var s = "hello\n\r" @@ -143,8 +140,9 @@ proc main() = testStrip() testRemoveSuffix() testRemovePrefix() - for p in split("/home/a1:xyz:/usr/bin", {':'}): - write(stdout, p) + var ret: seq[string] # or use `toSeq` + for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p + doAssert ret == @["/home/a1", "xyz", "/usr/bin"] proc testDelete = var s = "0123456789ABCDEFGH" From faedb14a167497f96b1499305deb5538e579eeb0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Jun 2020 21:17:24 -0700 Subject: [PATCH 0711/4254] misc cleanups in compiler msgs: use toHumanStr, etc (#14677) --- compiler/msgs.nim | 7 ++++--- compiler/sem.nim | 6 ++---- compiler/semstmts.nim | 3 +-- compiler/semtypes.nim | 5 ++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index e27eedd1c..aecaaf405 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -558,12 +558,13 @@ template fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = template globalAssert*(conf: ConfigRef; cond: untyped, info: TLineInfo = unknownLineInfo, arg = "") = ## avoids boilerplate if not cond: - const info2 = instantiationInfo(-1, fullPaths = true) var arg2 = "'$1' failed" % [astToStr(cond)] if arg.len > 0: arg2.add "; " & astToStr(arg) & ": " & arg - liMessage(conf, info, errGenerated, arg2, doRaise, info2) + liMessage(conf, info, errGenerated, arg2, doRaise, instLoc()) template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + ## `local` means compilation keeps going until errorMax is reached (via `doNothing`), + ## `global` means it stops. liMessage(conf, info, msg, arg, doRaise, instLoc()) template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = @@ -593,7 +594,7 @@ template internalError*(conf: ConfigRef; errMsg: string) = internalErrorImpl(conf, unknownLineInfo, errMsg, instLoc()) template internalAssert*(conf: ConfigRef, e: bool) = - # xxx merge with globalAssert from PR #14324 + # xxx merge with `globalAssert` if not e: const info2 = instLoc() let arg = info2.toFileLineCol diff --git a/compiler/sem.nim b/compiler/sem.nim index ca5d9c448..a657939a5 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -197,15 +197,13 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = suggestDecl(c, n, result) proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = - proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii - # like newSymS, but considers gensym'ed symbols if n.kind == nkSym: # and sfGenSym in n.sym.flags: result = n.sym if result.kind notin {kind, skTemp}: - localError(c.config, n.info, "cannot use symbol of kind '" & - $result.kind & "' as a '" & $kind & "'") + localError(c.config, n.info, "cannot use symbol of kind '$1' as a '$2'" % + [result.kind.toHumanStr, kind.toHumanStr]) when false: if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: # declarative context, so produce a fresh gensym: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a4b4c9362..6ffaa9dda 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -514,8 +514,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): - localError(c.config, def.info, errCannotInferTypeOfTheLiteral % - ($typ.kind).substr(2).toLowerAscii) + localError(c.config, def.info, errCannotInferTypeOfTheLiteral % typ.kind.toHumanStr) elif typ.kind == tyProc and tfUnresolved in typ.flags: localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree) when false: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 313328385..eba8dd397 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -905,8 +905,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if t.kind == tyTypeDesc and tfUnresolved notin t.flags: t = t.base if t.kind == tyVoid: - const kindToStr: array[tyPtr..tyRef, string] = ["ptr", "ref"] - localError(c.config, n.info, "type '$1 void' is not allowed" % kindToStr[kind]) + localError(c.config, n.info, "type '$1 void' is not allowed" % kind.toHumanStr) result = newOrPrevType(kind, prev, c) var isNilable = false var wrapperKind = tyNone @@ -1400,7 +1399,7 @@ proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if s.typ == nil: localError(c.config, n.info, "cannot instantiate the '$1' $2" % - [s.name.s, ($s.kind).substr(2).toLowerAscii]) + [s.name.s, s.kind.toHumanStr]) return newOrPrevType(tyError, prev, c) var t = s.typ From de5cde473a2809ac4a2940ec2704d575307521b4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Jun 2020 23:49:57 -0700 Subject: [PATCH 0712/4254] `hintMsgOrigin` now works in VM code (#14678) * `hintMsgOrigin` now works in VM code * remove a simplification for now --- compiler/msgs.nim | 6 +++--- compiler/vm.nim | 18 ++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index aecaaf405..a5953237e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -13,7 +13,7 @@ import import std/private/miscdollars import strutils2 -type InstantiationInfo = typeof(instantiationInfo()) +type InstantiationInfo* = typeof(instantiationInfo()) template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) template flushDot(conf, stdorr) = @@ -385,7 +385,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = result = msgKindToString(msg) % [arg] type - TErrorHandling = enum doNothing, doAbort, doRaise + TErrorHandling* = enum doNothing, doAbort, doRaise proc log*(s: string) = var f: File @@ -485,7 +485,7 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s else: ErrorTitle conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg) -proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, +proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.noinline.} = var title: string diff --git a/compiler/vm.nim b/compiler/vm.nim index c15f9e268..9b76d7986 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -72,20 +72,18 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = msgWriteln(c.config, s) proc stackTraceImpl(c: PCtx, tos: PStackFrame, pc: int, - msg: string, lineInfo: TLineInfo) = + msg: string, lineInfo: TLineInfo, infoOrigin: InstantiationInfo) {.noinline.} = + # noinline to avoid code bloat msgWriteln(c.config, "stack trace: (most recent call last)") stackTraceAux(c, tos, pc) - # XXX test if we want 'globalError' for every mode - if c.mode == emRepl: globalError(c.config, lineInfo, msg) - else: localError(c.config, lineInfo, msg) + let action = if c.mode == emRepl: doRaise else: doNothing + # XXX test if we want 'globalError' for every mode + let lineInfo = if lineInfo == TLineInfo.default: c.debug[pc] else: lineInfo + liMessage(c.config, lineInfo, errGenerated, msg, action, infoOrigin) template stackTrace(c: PCtx, tos: PStackFrame, pc: int, - msg: string, lineInfo: TLineInfo) = - stackTraceImpl(c, tos, pc, msg, lineInfo) - return - -template stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) = - stackTraceImpl(c, tos, pc, msg, c.debug[pc]) + msg: string, lineInfo: TLineInfo = TLineInfo.default) = + stackTraceImpl(c, tos, pc, msg, lineInfo, instantiationInfo(-2, fullPaths = true)) return proc bailOut(c: PCtx; tos: PStackFrame) = From 7b12f13946e833d85ddfe23fafee0c808b27bafb Mon Sep 17 00:00:00 2001 From: Euan Date: Tue, 16 Jun 2020 07:50:57 +0100 Subject: [PATCH 0713/4254] Use cc on OpenBSD and link to libm when building result (#14672) --- tools/detect/detect.nim | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index 720e24975..a10794555 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -14,10 +14,18 @@ # compilation. import os, strutils -const - cc = "gcc -o $# $#.c" - cpp = "gcc -E -o $#.i $#.c" +when defined(openbsd): + const + cc = "cc -o $# $#.c" + cpp = "cc -E -o $#.i $#.c" + ccLinkMath = "cc -lm -o $# $#.c" + cppLinkMath = "cc -lm -E -o $#.i $#.c" +else: + const + cc = "gcc -o $# $#.c" + cpp = "gcc -E -o $#.i $#.c" +const cfile = """ /* Generated by detect.nim */ #define _GNU_SOURCE @@ -89,8 +97,11 @@ proc main = if open(f, "other_consts.nim", fmWrite): f.write(nimfile % [other]) close(f) - if not myExec(cc % [gen.addFileExt(ExeExt), gen]): quit(1) - if not myExec(cpp % [pre.addFileExt(ExeExt), pre]): quit(1) + + let cCompile = when defined(openbsd): ccLinkMath else: cc + let cppCompile = when defined(openbsd): cppLinkMath else: cpp + if not myExec(cCompile % [gen.addFileExt(ExeExt), gen]): quit(1) + if not myExec(cppCompile % [pre.addFileExt(ExeExt), pre]): quit(1) when defined(windows): if not myExec(gen.addFileExt(ExeExt)): quit(1) else: From 45cac4afda2272182ea1eb7572493d6c71e2da4e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 15 Jun 2020 23:56:12 -0700 Subject: [PATCH 0714/4254] fix #14179, fix #14142, make CI 1.4x faster (2x faster locally) (#14658) * fix #14142: no more clash with: import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims * remove a comment * Revert "fixes the regression #12860 caused; hotfix" This reverts commit 3d2459bdc0b6d6236a2cd9209ed81c965ee411a5. * Revert "Undefine `paramCount` & `paramStr` in nimscript.nim for *.nims (#12860)" This reverts commit d38853c504d89d6e361f064a17391afaf42d74b8. * noNimScript => noWeirdTarget + noNimJs --- changelog.md | 1 - compiler/scriptconfig.nim | 10 ++- lib/pure/os.nim | 131 ++++++++++++++++++-------------------- lib/system/nimscript.nim | 11 +++- tests/test_nimscript.nims | 7 ++ 5 files changed, 81 insertions(+), 79 deletions(-) diff --git a/changelog.md b/changelog.md index b9fb48117..588af989b 100644 --- a/changelog.md +++ b/changelog.md @@ -62,7 +62,6 @@ - Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom`. UDP functionality. -- `paramCount` & `paramStr` are now defined in os.nim instead of nimscript.nim for nimscript/nimble. - `dollars.$` now works for unsigned ints with `nim js` - Improvements to the `bitops` module, including bitslices, non-mutating versions diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 994a2d342..13ab03426 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -141,12 +141,10 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; setResult(a, options.existsConfigVar(conf, a.getString 0)) cbconf nimcacheDir: setResult(a, options.getNimcacheDir(conf).string) - result.registerCallback "stdlib.os." & astToStr(paramStr), - proc (a: VmArgs) = - setResult(a, os.paramStr(int a.getInt 0)) - result.registerCallback "stdlib.os." & astToStr(paramCount), - proc (a: VmArgs) = - setResult(a, os.paramCount()) + cbconf paramStr: + setResult(a, os.paramStr(int a.getInt 0)) + cbconf paramCount: + setResult(a, os.paramCount()) cbconf cmpIgnoreStyle: setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1)) cbconf cmpIgnoreCase: diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 79cd27e10..bb09c966f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -76,9 +76,17 @@ else: {.error: "OS module not ported to your operating system!".} when weirdTarget and defined(nimErrorProcCanHaveBody): - {.pragma: noNimScript, error: "this proc is not available on the NimScript target".} + {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} else: - {.pragma: noNimScript.} + {.pragma: noWeirdTarget.} + +when defined(nimscript): + # for procs already defined in scriptconfig.nim + template noNimJs(body): untyped = discard +elif defined(js): + {.pragma: noNimJs, error: "this proc is not available on the js target".} +else: + {.pragma: noNimJs.} proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.} @@ -1088,7 +1096,7 @@ when defined(windows) and not weirdTarget: f.cFileName[1].int == dot and f.cFileName[2].int == 0) proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noNimScript.} = + tags: [ReadDirEffect], noNimJs.} = ## Returns true if `filename` exists and is a regular file or symlink. ## ## Directories, device files, named pipes and sockets return false. @@ -1108,7 +1116,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode) proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], - noNimScript.} = + noNimJs.} = ## Returns true if the directory `dir` exists. If `dir` is a file, false ## is returned. Follows symlinks. ## @@ -1128,7 +1136,7 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect] proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], - noNimScript.} = + noWeirdTarget.} = ## Returns true if the symlink `link` exists. Will return true ## regardless of whether the link points to a directory or file. ## @@ -1146,7 +1154,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", var res: Stat return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) -proc fileExists*(filename: string): bool {.inline, noNimScript.} = +proc fileExists*(filename: string): bool {.inline, noNimJs.} = ## Alias for `existsFile proc <#existsFile,string>`_. ## ## See also: @@ -1154,7 +1162,7 @@ proc fileExists*(filename: string): bool {.inline, noNimScript.} = ## * `symlinkExists proc <#symlinkExists,string>`_ existsFile(filename) -proc dirExists*(dir: string): bool {.inline, noNimScript.} = +proc dirExists*(dir: string): bool {.inline, noNimJs.} = ## Alias for `existsDir proc <#existsDir,string>`_. ## ## See also: @@ -1175,7 +1183,7 @@ const proc findExe*(exe: string, followSymlinks: bool = true; extensions: openArray[string]=ExeExts): string {. - tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect], noNimScript.} = + tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect], noNimJs.} = ## Searches for `exe` in the current working directory and then ## in directories listed in the ``PATH`` environment variable. ## @@ -1231,7 +1239,7 @@ when weirdTarget: const times = "fake const" template Time(x: untyped): untyped = string -proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} = +proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdTarget.} = ## Returns the `file`'s last modification time. ## ## See also: @@ -1249,7 +1257,7 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", result = fromWinTime(rdFileTime(f.ftLastWriteTime)) findClose(h) -proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} = +proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdTarget.} = ## Returns the `file`'s last read or write access time. ## ## See also: @@ -1267,7 +1275,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimS result = fromWinTime(rdFileTime(f.ftLastAccessTime)) findClose(h) -proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} = +proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdTarget.} = ## Returns the `file`'s creation time. ## ## **Note:** Under POSIX OS's, the returned time may actually be the time at @@ -1289,7 +1297,7 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScr result = fromWinTime(rdFileTime(f.ftCreationTime)) findClose(h) -proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noNimScript.} = +proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noWeirdTarget.} = ## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s ## modification time is later than `b`'s. ## @@ -1368,7 +1376,7 @@ when not defined(nimscript): else: raiseOSError(osLastError()) -proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} = +proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} = ## Sets the `current working directory`:idx:; `OSError` ## is raised if `newDir` cannot been set. ## @@ -1502,7 +1510,7 @@ when defined(Windows) and not weirdTarget: ) proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noNimScript.} = + tags: [ReadDirEffect], noWeirdTarget.} = ## Returns true if both pathname arguments refer to the same physical ## file or directory. ## @@ -1547,7 +1555,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", result = a.st_dev == b.st_dev and a.st_ino == b.st_ino proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [ReadIOEffect], noNimScript.} = + tags: [ReadIOEffect], noWeirdTarget.} = ## Returns true if both pathname arguments refer to files with identical ## binary content. ## @@ -1598,7 +1606,7 @@ type fpOthersRead ## read access for others proc getFilePermissions*(filename: string): set[FilePermission] {. - rtl, extern: "nos$1", tags: [ReadDirEffect], noNimScript.} = + rtl, extern: "nos$1", tags: [ReadDirEffect], noWeirdTarget.} = ## Retrieves file permissions for `filename`. ## ## `OSError` is raised in case of an error. @@ -1636,7 +1644,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {. result = {fpUserExec..fpOthersRead} proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. - rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} = + rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = ## Sets the file permissions for `filename`. ## ## `OSError` is raised in case of an error. @@ -1678,7 +1686,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions)) proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = + tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} = ## Copies a file from `source` to `dest`. ## ## If this fails, `OSError` is raised. @@ -1754,7 +1762,7 @@ when defined(Windows) and not weirdTarget: template setFileAttributes(file, attrs: untyped): untyped = setFileAttributesA(file, attrs) -proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} = +proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = ## Removes the `file`. ## ## If this fails, returns `false`. This does not fail @@ -1786,7 +1794,7 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE if unlink(file) != 0'i32 and errno != ENOENT: result = false -proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} = +proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = ## Removes the `file`. ## ## If this fails, `OSError` is raised. This does not fail @@ -1803,7 +1811,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n if not tryRemoveFile(file): raiseOSError(osLastError(), file) -proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} = +proc tryMoveFSObject(source, dest: string): bool {.noWeirdTarget.} = ## Moves a file or directory from `source` to `dest`. ## ## Returns false in case of `EXDEV` error. @@ -1827,7 +1835,7 @@ proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} = return true proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = + tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} = ## Moves a file from `source` to `dest`. ## ## If this fails, `OSError` is raised. @@ -1864,7 +1872,7 @@ proc exitStatusLikeShell*(status: cint): cint = status proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", - tags: [ExecIOEffect], noNimScript.} = + tags: [ExecIOEffect], noWeirdTarget.} = ## Executes a `shell command`:idx:. ## ## Command has the form 'program args' where args are the command @@ -1938,7 +1946,7 @@ template walkCommon(pattern: string, filter) = if filter(path): yield path -iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} = +iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = ## Iterate over all the files and directories that match the `pattern`. ## ## On POSIX this uses the `glob`:idx: call. @@ -1952,7 +1960,7 @@ iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noNimScr ## * `walkDirRec iterator <#walkDirRec.i,string>`_ walkCommon(pattern, defaultWalkFilter) -iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} = +iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = ## Iterate over all the files that match the `pattern`. ## ## On POSIX this uses the `glob`:idx: call. @@ -1966,7 +1974,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noNimScrip ## * `walkDirRec iterator <#walkDirRec.i,string>`_ walkCommon(pattern, isFile) -iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} = +iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = ## Iterate over all the directories that match the `pattern`. ## ## On POSIX this uses the `glob`:idx: call. @@ -1981,7 +1989,7 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noNimScript walkCommon(pattern, isDir) proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noNimScript.} = + tags: [ReadDirEffect], noWeirdTarget.} = ## Returns the full (`absolute`:idx:) path of an existing file `filename`. ## ## Raises `OSError` in case of an error. Follows symlinks. @@ -2215,7 +2223,7 @@ iterator walkDirRec*(dir: string, # continue iteration. # Future work can provide a way to customize this and do error reporting. -proc rawRemoveDir(dir: string) {.noNimScript.} = +proc rawRemoveDir(dir: string) {.noWeirdTarget.} = when defined(windows): when useWinUnicode: wrapUnary(res, removeDirectoryW, dir) @@ -2229,7 +2237,7 @@ proc rawRemoveDir(dir: string) {.noNimScript.} = if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError(), dir) proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ - WriteDirEffect, ReadDirEffect], benign, noNimScript.} = + WriteDirEffect, ReadDirEffect], benign, noWeirdTarget.} = ## Removes the directory `dir` including all subdirectories and files ## in `dir` (recursively). ## @@ -2253,7 +2261,7 @@ proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ # the same files) rawRemoveDir(dir) -proc rawCreateDir(dir: string): bool {.noNimScript.} = +proc rawCreateDir(dir: string): bool {.noWeirdTarget.} = # Try to create one directory (not the whole path). # returns `true` for success, `false` if the path has previously existed # @@ -2298,7 +2306,7 @@ proc rawCreateDir(dir: string): bool {.noNimScript.} = raiseOSError(osLastError(), dir) proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", - tags: [WriteDirEffect, ReadDirEffect], noNimScript.} = + tags: [WriteDirEffect, ReadDirEffect], noWeirdTarget.} = ## Check if a `directory`:idx: `dir` exists, and create it otherwise. ## ## Does not create parent directories (fails if parent does not exist). @@ -2318,7 +2326,7 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", raise newException(IOError, "Failed to create '" & dir & "'") proc createDir*(dir: string) {.rtl, extern: "nos$1", - tags: [WriteDirEffect, ReadDirEffect], noNimScript.} = + tags: [WriteDirEffect, ReadDirEffect], noWeirdTarget.} = ## Creates the `directory`:idx: `dir`. ## ## The directory may contain several subdirectories that do not exist yet. @@ -2349,7 +2357,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", discard existsOrCreateDir(dir) proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", - tags: [WriteIOEffect, ReadIOEffect], benign, noNimScript.} = + tags: [WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = ## Copies a directory from `source` to `dest`. ## ## If this fails, `OSError` is raised. @@ -2380,7 +2388,7 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", copyDir(path, dest / noSource) else: discard -proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = +proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} = ## Moves a directory from `source` to `dest`. ## ## If this fails, `OSError` is raised. @@ -2398,7 +2406,7 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noNim copyDir(source, dest) removeDir(source) -proc createSymlink*(src, dest: string) {.noNimScript.} = +proc createSymlink*(src, dest: string) {.noWeirdTarget.} = ## Create a symbolic link at `dest` which points to the item specified ## by `src`. On most operating systems, will fail if a link already exists. ## @@ -2426,7 +2434,7 @@ proc createSymlink*(src, dest: string) {.noNimScript.} = if symlink(src, dest) != 0: raiseOSError(osLastError(), $(src, dest)) -proc createHardlink*(src, dest: string) {.noNimScript.} = +proc createHardlink*(src, dest: string) {.noWeirdTarget.} = ## Create a hard link at `dest` which points to the item specified ## by `src`. ## @@ -2449,7 +2457,7 @@ proc createHardlink*(src, dest: string) {.noNimScript.} = raiseOSError(osLastError(), $(src, dest)) proc copyFileWithPermissions*(source, dest: string, - ignorePermissionErrors = true) {.noNimScript.} = + ignorePermissionErrors = true) {.noWeirdTarget.} = ## Copies a file from `source` to `dest` preserving file permissions. ## ## This is a wrapper proc around `copyFile <#copyFile,string,string>`_, @@ -2483,7 +2491,7 @@ proc copyFileWithPermissions*(source, dest: string, proc copyDirWithPermissions*(source, dest: string, ignorePermissionErrors = true) {.rtl, extern: "nos$1", - tags: [WriteIOEffect, ReadIOEffect], benign, noNimScript.} = + tags: [WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = ## Copies a directory from `source` to `dest` preserving file permissions. ## ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir @@ -2526,7 +2534,7 @@ proc copyDirWithPermissions*(source, dest: string, proc inclFilePermissions*(filename: string, permissions: set[FilePermission]) {. - rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noNimScript.} = + rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noWeirdTarget.} = ## A convenience proc for: ## ## .. code-block:: nim @@ -2535,14 +2543,14 @@ proc inclFilePermissions*(filename: string, proc exclFilePermissions*(filename: string, permissions: set[FilePermission]) {. - rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noNimScript.} = + rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noWeirdTarget.} = ## A convenience proc for: ## ## .. code-block:: nim ## setFilePermissions(filename, getFilePermissions(filename)-permissions) setFilePermissions(filename, getFilePermissions(filename)-permissions) -proc expandSymlink*(symlinkPath: string): string {.noNimScript.} = +proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} = ## Returns a string representing the path to which the symbolic link points. ## ## On Windows this is a noop, ``symlinkPath`` is simply returned. @@ -2720,23 +2728,8 @@ when defined(nimdoc): ## else: ## # Do something else! -elif defined(nimscript): - proc paramStr*(i: int): string = - ## Retrieves the ``i``'th command line parameter. - discard - - proc paramCount*(): int = - ## Retrieves the number of command line parameters. - discard - -elif defined(js): - proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = - raise newException(OSError, "paramStr is not implemented on JavaScript") - - proc paramCount*(): int {.tags: [ReadIOEffect].} = - raise newException(OSError, "paramCount is not implemented on JavaScript") - -elif defined(nintendoswitch): +elif defined(nimscript): discard +elif defined(nintendoswitch) or weirdTarget: proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = raise newException(OSError, "paramStr is not implemented on Nintendo Switch") @@ -2947,7 +2940,7 @@ when defined(haiku): else: result = "" -proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} = +proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget.} = ## Returns the filename of the application's executable. ## This proc will resolve symlinks. ## @@ -3013,14 +3006,14 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noN if result.len == 0: result = getApplHeuristic() -proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} = +proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget.} = ## Returns the directory of the application's executable. ## ## See also: ## * `getAppFilename proc <#getAppFilename>`_ result = splitFile(getAppFilename()).dir -proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noNimScript.} = +proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTarget.} = ## Sleeps `milsecs` milliseconds. when defined(windows): winlean.sleep(int32(milsecs)) @@ -3031,7 +3024,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noNimScrip discard posix.nanosleep(a, b) proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", - tags: [ReadIOEffect], noNimScript.} = + tags: [ReadIOEffect], noWeirdTarget.} = ## Returns the file size of `file` (in bytes). ``OSError`` is ## raised in case of an error. when defined(windows): @@ -3132,13 +3125,13 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = assert(path != "") # symlinks can't occur for file handles formalInfo.kind = getSymlinkFileKind(path) -when defined(js) or defined(nimscript): +when defined(js): when not declared(FileHandle): type FileHandle = distinct int32 when not declared(File): type File = object -proc getFileInfo*(handle: FileHandle): FileInfo {.noNimScript.} = +proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} = ## Retrieves file information for the file object represented by the given ## handle. ## @@ -3164,7 +3157,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noNimScript.} = raiseOSError(osLastError(), $handle) rawToFormalFileInfo(rawInfo, "", result) -proc getFileInfo*(file: File): FileInfo {.noNimScript.} = +proc getFileInfo*(file: File): FileInfo {.noWeirdTarget.} = ## Retrieves file information for the file object. ## ## See also: @@ -3174,7 +3167,7 @@ proc getFileInfo*(file: File): FileInfo {.noNimScript.} = raise newException(IOError, "File is nil") result = getFileInfo(file.getFileHandle()) -proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noNimScript.} = +proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget.} = ## Retrieves file information for the file object pointed to by `path`. ## ## Due to intrinsic differences between operating systems, the information @@ -3212,7 +3205,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noNimScript.} raiseOSError(osLastError(), path) rawToFormalFileInfo(rawInfo, path, result) -proc isHidden*(path: string): bool {.noNimScript.} = +proc isHidden*(path: string): bool {.noWeirdTarget.} = ## Determines whether ``path`` is hidden or not, using `this ## reference `_. ## @@ -3242,7 +3235,7 @@ proc isHidden*(path: string): bool {.noNimScript.} = let fileName = lastPathPart(path) result = len(fileName) >= 2 and fileName[0] == '.' and fileName != ".." -proc getCurrentProcessId*(): int {.noNimScript.} = +proc getCurrentProcessId*(): int {.noWeirdTarget.} = ## Return current process ID. ## ## See also: @@ -3254,7 +3247,7 @@ proc getCurrentProcessId*(): int {.noNimScript.} = else: result = getpid() -proc setLastModificationTime*(file: string, t: times.Time) {.noNimScript.} = +proc setLastModificationTime*(file: string, t: times.Time) {.noWeirdTarget.} = ## Sets the `file`'s last modification time. `OSError` is raised in case of ## an error. when defined(posix): diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index da5c291fa..ceaaef013 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -56,6 +56,14 @@ proc rawExec(cmd: string): int {.tags: [ExecIOEffect], raises: [OSError].} = proc warningImpl(arg, orig: string) = discard proc hintImpl(arg, orig: string) = discard +proc paramStr*(i: int): string = + ## Retrieves the ``i``'th command line parameter. + builtin + +proc paramCount*(): int = + ## Retrieves the number of command line parameters. + builtin + proc switch*(key: string, val="") = ## Sets a Nim compiler command line switch, for ## example ``switch("checks", "on")``. @@ -272,9 +280,6 @@ proc selfExec*(command: string) {. raise newException(OSError, "FAILED: " & c) checkOsError() -from os import paramCount, paramStr -export paramCount, paramStr - proc put*(key, value: string) = ## Sets a configuration 'key' like 'gcc.options.always' to its value. builtin diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index a2e8ac945..de4b34728 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -81,3 +81,10 @@ when false: # #14142 discard findExe("nim") echo "Nimscript imports are successful." + +block: # #14142 + discard existsDir("/usr") + discard dirExists("/usr") + discard existsFile("/usr/foo") + discard fileExists("/usr/foo") + discard findExe("nim") From dfe51d10a1f204d0c3ab1a8be1e109029cc54f9b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 16 Jun 2020 02:43:48 -0700 Subject: [PATCH 0715/4254] `addQuitProc` now works with closures, and c, js(node/browser) backend; fix some bugs in testament (#14342) * make addQuitProc great again * fix bugs in testament * fix test * change 2016 => 2020 * addQuitProc => addExitProc + locks * move to std/exitprocs --- lib/core/locks.nim | 13 ++++-- lib/pure/quitprocs.nim | 28 ------------ lib/std/exitprocs.nim | 65 ++++++++++++++++++++++++++++ lib/system.nim | 9 ++-- testament/categories.nim | 4 +- testament/specs.nim | 7 +++ testament/testament.nim | 12 ++--- tests/converter/tor_in_converter.nim | 2 +- tests/stdlib/texitprocs.nim | 21 +++++++++ 9 files changed, 117 insertions(+), 44 deletions(-) delete mode 100644 lib/pure/quitprocs.nim create mode 100644 lib/std/exitprocs.nim create mode 100644 tests/stdlib/texitprocs.nim diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 7e2f4ad34..bddd6d864 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -9,6 +9,10 @@ ## This module contains Nim's support for locks and condition vars. +#[ +for js, for now we treat locks as noop's to avoid pushing `when defined(js)` +in client code that uses locks. +]# when not compileOption("threads") and not defined(nimdoc): when false: # fix #12330 @@ -26,7 +30,8 @@ type proc initLock*(lock: var Lock) {.inline.} = ## Initializes the given lock. - initSysLock(lock) + when not defined(js): + initSysLock(lock) proc deinitLock*(lock: var Lock) {.inline.} = ## Frees the resources associated with the lock. @@ -38,11 +43,13 @@ proc tryAcquire*(lock: var Lock): bool = proc acquire*(lock: var Lock) = ## Acquires the given lock. - acquireSys(lock) + when not defined(js): + acquireSys(lock) proc release*(lock: var Lock) = ## Releases the given lock. - releaseSys(lock) + when not defined(js): + releaseSys(lock) proc initCond*(cond: var Cond) {.inline.} = diff --git a/lib/pure/quitprocs.nim b/lib/pure/quitprocs.nim deleted file mode 100644 index 76bbcdb2b..000000000 --- a/lib/pure/quitprocs.nim +++ /dev/null @@ -1,28 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2016 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## ``system.addQuitProc`` is nice and very useful but due to its C-based -## implementation it doesn't support closures which limits its usefulness. -## This module fixes this. Later versions of this module will also -## support the JavaScript backend. - -var - gClosures: seq[proc () {.closure.}] - -proc callClosures() {.noconv.} = - for i in countdown(gClosures.len-1, 0): - gClosures[i]() - -proc addQuitClosure*(cl: proc () {.closure.}) = - ## Like ``system.addQuitProc`` but it supports closures. - if gClosures.len == 0: - addQuitProc(callClosures) - gClosures = @[cl] - else: - gClosures.add(cl) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim new file mode 100644 index 000000000..b2811735c --- /dev/null +++ b/lib/std/exitprocs.nim @@ -0,0 +1,65 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import locks + +type + FunKind = enum kClosure, kNoconv # extend as needed + Fun = object + case kind: FunKind + of kClosure: fun1: proc () {.closure.} + of kNoconv: fun2: proc () {.noconv.} + +var + gFunsLock: Lock + gFuns: seq[Fun] + +initLock(gFunsLock) + +when defined(js): + proc addAtExit(quitProc: proc() {.noconv.}) = + when defined(nodejs): + asm """ + process.on('exit', `quitProc`); + """ + elif defined(js): + asm """ + window.onbeforeunload = `quitProc`; + """ +else: + proc addAtExit(quitProc: proc() {.noconv.}) {. + importc: "atexit", header: "".} + +proc callClosures() {.noconv.} = + withLock gFunsLock: + for i in countdown(gFuns.len-1, 0): + let fun = gFuns[i] + case fun.kind + of kClosure: fun.fun1() + of kNoconv: fun.fun2() + +template fun() = + if gFuns.len == 0: + addAtExit(callClosures) + +proc addExitProc*(cl: proc () {.closure.}) = + ## Adds/registers a quit procedure. Each call to `addExitProc` registers + ## another quit procedure. They are executed on a last-in, first-out basis. + # Support for `addExitProc` is done by Ansi C's facilities here. + # In case of an unhandled exception the exit handlers should + # not be called explicitly! The user may decide to do this manually though. + withLock gFunsLock: + fun() + gFuns.add Fun(kind: kClosure, fun1: cl) + +proc addExitProc*(cl: proc() {.noconv.}) = + ## overload for `noconv` procs. + withLock gFunsLock: + fun() + gFuns.add Fun(kind: kNoconv, fun2: cl) diff --git a/lib/system.nim b/lib/system.nim index 85be43cba..2235b8b70 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1147,8 +1147,8 @@ when defined(nimdoc): proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} ## Stops the program immediately with an exit code. ## - ## Before stopping the program the "quit procedures" are called in the - ## opposite order they were added with `addQuitProc <#addQuitProc,proc>`_. + ## Before stopping the program the "exit procedures" are called in the + ## opposite order they were added with `addExitProc `_. ## ``quit`` never returns and ignores any exception that may have been raised ## by the quit procedures. It does *not* call the garbage collector to free ## all the memory, unless a quit procedure calls `GC_fullCollect @@ -1426,8 +1426,8 @@ proc toBiggestInt*(f: BiggestFloat): BiggestInt {.noSideEffect.} = ## Same as `toInt <#toInt,float>`_ but for ``BiggestFloat`` to ``BiggestInt``. if f >= 0: BiggestInt(f+0.5) else: BiggestInt(f-0.5) -proc addQuitProc*(quitProc: proc() {.noconv.}) {. - importc: "atexit", header: "".} +proc addQuitProc*(quitProc: proc() {.noconv.}) {. + importc: "atexit", header: "", deprecated: "use exitprocs.addExitProc".} ## Adds/registers a quit procedure. ## ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30 @@ -1440,7 +1440,6 @@ proc addQuitProc*(quitProc: proc() {.noconv.}) {. # In case of an unhandled exception the exit handlers should # not be called explicitly! The user may decide to do this manually though. - proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## Swaps the values `a` and `b`. ## diff --git a/testament/categories.nim b/testament/categories.nim index 4e83fa1a9..45a2113a6 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -269,8 +269,8 @@ proc debuggerTests(r: var TResults, cat: Category, options: string) = proc jsTests(r: var TResults, cat: Category, options: string) = template test(filename: untyped) = - testSpec r, makeTest(filename, options & " -d:nodejs", cat), {targetJS} - testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat), {targetJS} + testSpec r, makeTest(filename, options, cat), {targetJS} + testSpec r, makeTest(filename, options & " -d:release", cat), {targetJS} for t in os.walkFiles("tests/js/t*.nim"): test(t) diff --git a/testament/specs.nim b/testament/specs.nim index 964d53d24..7405c5055 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -87,6 +87,13 @@ const targetToExt*: array[TTarget, string] = ["nim.c", "nim.cpp", "nim.m", "js"] targetToCmd*: array[TTarget, string] = ["c", "cpp", "objc", "js"] +proc defaultOptions*(a: TTarget): string = + case a + of targetJS: "-d:nodejs" + # once we start testing for `nim js -d:nimbrowser` (eg selenium or similar), + # we can adapt this logic; or a given js test can override with `-u:nodejs`. + else: "" + when not declared(parseCfgBool): # candidate for the stdlib: proc parseCfgBool(s: string): bool = diff --git a/testament/testament.nim b/testament/testament.nim index 69b7e322e..098c07ac5 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -135,7 +135,10 @@ proc nimcacheDir(filename, options: string, target: TTarget): string = proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, target: TTarget, extraOptions = ""): seq[string] = - let options = options & " " & quoteShell("--nimCache:" & nimcache) & " " & extraOptions + var options = target.defaultOptions & " " & options + # improve pending https://github.com/nim-lang/Nim/issues/14343 + if nimcache.len > 0: options.add " " & ("--nimCache:" & nimcache).quoteShell + options.add " " & extraOptions result = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell, "filedir", filename.getFileDir()]) @@ -192,9 +195,7 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, proc callCCompiler(cmdTemplate, filename, options: string, target: TTarget): TSpec = - let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], - "options", options, "file", filename.quoteShell, - "filedir", filename.getFileDir()]) + let c = prepareTestArgs(cmdTemplate, filename, options, nimcache = "", target) var p = startProcess(command="gcc", args=c[5 .. ^1], options={poStdErrToStdOut, poUsePath}) let outp = p.outputStream @@ -254,7 +255,8 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, # test.name is easier to find than test.name.extractFilename # A bit hacky but simple and works with tests/testament/tshould_not_work.nim var name = test.name.replace(DirSep, '/') - name.add " " & $target & test.options + name.add " " & $target + if test.options.len > 0: name.add " " & test.options let duration = epochTime() - test.startTime let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout diff --git a/tests/converter/tor_in_converter.nim b/tests/converter/tor_in_converter.nim index 5674526a1..df2334647 100644 --- a/tests/converter/tor_in_converter.nim +++ b/tests/converter/tor_in_converter.nim @@ -4,7 +4,7 @@ test''' """ # bug #4537 -# nim js --d:nodejs +# nim js -d:nodejs type Str = distinct string diff --git a/tests/stdlib/texitprocs.nim b/tests/stdlib/texitprocs.nim new file mode 100644 index 000000000..9d5378fe8 --- /dev/null +++ b/tests/stdlib/texitprocs.nim @@ -0,0 +1,21 @@ +discard """ +targets: "c cpp js" +output: ''' +ok4 +ok3 +ok2 +ok1 +''' +""" + +import std/exitprocs + +proc fun1() {.noconv.} = echo "ok1" +proc fun2() = echo "ok2" +proc fun3() {.noconv.} = echo "ok3" +proc fun4() = echo "ok4" + +addExitProc(fun1) +addExitProc(fun2) +addExitProc(fun3) +addExitProc(fun4) From 1bc2e19498a718276496263b574a66bb2ee84f56 Mon Sep 17 00:00:00 2001 From: Euan Date: Tue, 16 Jun 2020 10:44:28 +0100 Subject: [PATCH 0716/4254] Set cincludes and clibdir for FreeBSD, OpenBSD and NetBSD. (#14680) --- config/nim.cfg | 3 +++ tests/niminaction/Chapter8/sfml/sfml_test.nim | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index b43dfd80b..206f80413 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -205,6 +205,9 @@ clang.objc.options.linker = "-lobjc -lgnustep-base" llvm_gcc.cpp.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" clang.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" clang.cpp.options.linker = "-Wl,-rpath=.:/usr/local/lib:/usr/pkg/lib:/usr/X11R6/lib" + + cincludes: "/usr/local/include" + clibdir: "/usr/local/lib" @end # Configuration for the VxWorks diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim index cdd5be776..e71060cb4 100644 --- a/tests/niminaction/Chapter8/sfml/sfml_test.nim +++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim @@ -1,9 +1,6 @@ discard """ action: compile disabled: "windows" -disabled: "freebsd" -disabled: "openbsd" -disabled: "netbsd" """ import sfml, os From e35b21e55310e93ca04980febe1a48c9436bded9 Mon Sep 17 00:00:00 2001 From: Dylan Modesitt Date: Tue, 16 Jun 2020 10:24:26 -0400 Subject: [PATCH 0717/4254] Close#5586 (#14682) * re-enable macos and bsd on some coro tests * re-enable macos and bsd on some coro tests --- tests/coroutines/tgc.nim | 1 - tests/coroutines/twait.nim | 2 -- 2 files changed, 3 deletions(-) diff --git a/tests/coroutines/tgc.nim b/tests/coroutines/tgc.nim index 86b625370..46f4f8e83 100644 --- a/tests/coroutines/tgc.nim +++ b/tests/coroutines/tgc.nim @@ -1,6 +1,5 @@ discard """ target: "c" - disabled: "openbsd" """ import coro diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim index 2563ad7d3..b88801869 100644 --- a/tests/coroutines/twait.nim +++ b/tests/coroutines/twait.nim @@ -1,7 +1,5 @@ discard """ output: "Exit 1\nExit 2" - disabled: "macosx" - disabled: "openbsd" target: "c" """ import coro From 7ded490ec06286bb016bcb525e8d816f952e7bfc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 16 Jun 2020 14:38:30 -0700 Subject: [PATCH 0718/4254] cleanup tests/test_nimscript.nims (#14686) --- tests/test_nimscript.nims | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index de4b34728..7c64ea762 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -69,19 +69,11 @@ import std/[ decls, compilesettings, with, wrapnils ] +echo "Nimscript imports are successful." block: doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath -when false: # #14142 - discard existsDir("/usr") - discard dirExists("/usr") - discard existsFile("/usr/foo") - discard fileExists("/usr/foo") - discard findExe("nim") - -echo "Nimscript imports are successful." - block: # #14142 discard existsDir("/usr") discard dirExists("/usr") From ff93302f69c724bc03d7e0529fb0b9b6bfa0b36e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 16 Jun 2020 15:57:57 -0700 Subject: [PATCH 0719/4254] use check to investigate #14685 flaky tests/async/t7758.nim (#14689) --- tests/async/t7758.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim index 15aec1c04..3cbe16852 100644 --- a/tests/async/t7758.nim +++ b/tests/async/t7758.nim @@ -1,4 +1,5 @@ import asyncdispatch +import std/unittest proc task() {.async.} = await sleepAsync(40) @@ -10,6 +11,6 @@ proc main() = inc(counter) poll(10) - doAssert counter <= 4 + check counter <= 4 -for i in 0 .. 4: main() +for i in 0 .. 10: main() From bdd2c25e9f97e8b92d6445417dd70450123a79fe Mon Sep 17 00:00:00 2001 From: solo989 Date: Tue, 16 Jun 2020 22:57:04 -0700 Subject: [PATCH 0720/4254] Update macros.nim (#14697) --- lib/core/macros.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 27ff063a7..aa4269101 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -466,6 +466,8 @@ proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect, comp ## Creates an identifier node from `i`. It is simply an alias for ## ``ident(string)``. Use that, it's shorter. +proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.} + ## Create a new ident node from a string. type BindSymRule* = enum ## specifies how ``bindSym`` behaves @@ -1283,9 +1285,6 @@ proc `$`*(node: NimNode): string {.compileTime.} = else: badNodeKind node, "$" -proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.} - ## Create a new ident node from a string. - iterator items*(n: NimNode): NimNode {.inline.} = ## Iterates over the children of the NimNode ``n``. for i in 0 ..< n.len: From 15a45e8e73a4e8eb645e4c3c3a5080465347cc60 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 17 Jun 2020 02:58:03 -0300 Subject: [PATCH 0721/4254] Documentation update nims.rst (#14683) * Update nims.rst to add modules that work on NimScript as mentioned in the changelog.md * https://github.com/nim-lang/Nim/pull/14683#issuecomment-644976921 --- doc/nims.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/nims.rst b/doc/nims.rst index c1d434476..03afa258a 100644 --- a/doc/nims.rst +++ b/doc/nims.rst @@ -87,11 +87,24 @@ At least the following standard library modules are available: * `std/editdistance `_ * `std/wordwrap `_ * `std/sums `_ +* `parsecsv `_ +* `parsecfg `_ +* `parsesql `_ +* `xmlparser `_ +* `htmlparser `_ +* `ropes `_ +* `json `_ +* `parsejson `_ +* `strtabs `_ +* `unidecode `_ In addition to the standard Nim syntax (`system `_ module), NimScripts support the procs and templates defined in the `nimscript `_ module too. +See also: +* `Check the tests for more information about modules compatible with NimScript. `_ + NimScript as a configuration file ================================= From 861953429362d72a76fe3768a25db3f8a1cf70ee Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 16 Jun 2020 23:10:34 -0700 Subject: [PATCH 0722/4254] remove compilerproc from `newIdentNode` (#14692) --- lib/core/macros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index aa4269101..f3bca3af8 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -462,7 +462,7 @@ proc newIdentNode*(i: NimIdent): NimNode {.compileTime, deprecated.} = {.pop.} -proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect, compilerproc.} +proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect.} ## Creates an identifier node from `i`. It is simply an alias for ## ``ident(string)``. Use that, it's shorter. From e7f280bd26a54b4f187b087c8d35f43f0e6328c7 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 17 Jun 2020 15:25:02 +0200 Subject: [PATCH 0723/4254] Remove deprecated stuff from stdlib (#14699) * update to the latest Jester * remove deprecated procs from some stdlib modules * 'criterion' is not maintained anymore and relies on obsolete stuff --- doc/backends.rst | 2 +- lib/core/macros.nim | 6 - lib/impure/re.nim | 7 - lib/pure/algorithm.nim | 4 - lib/pure/asyncdispatch.nim | 2 +- lib/pure/collections/heapqueue.nim | 8 - lib/pure/collections/sets.nim | 39 +--- lib/pure/concurrency/cpuload.nim | 2 +- lib/pure/httpclient.nim | 2 +- lib/pure/math.nim | 39 ---- lib/pure/nativesockets.nim | 16 -- lib/pure/random.nim | 34 +--- lib/pure/selectors.nim | 19 -- lib/pure/times.nim | 175 +----------------- lib/pure/unicode.nim | 82 -------- lib/pure/unittest.nim | 5 +- lib/system/arithmetics.nim | 8 - testament/important_packages.nim | 1 - tests/ccgbugs2/tinefficient_const_table.nim | 27 +++ tests/collections/thashsets.nim | 5 +- tests/deps/jester-#head/jester.nim | 121 +++++++----- tests/deps/jester-#head/jester.nimble | 8 +- tests/deps/jester-#head/jester/patterns.nim | 4 +- .../jester-#head/jester/private/utils.nim | 3 +- tests/deps/jester-#head/jester/request.nim | 1 + tests/gc/gcleak5.nim | 2 +- .../argument_parser/argument_parser.nim | 2 +- tests/manyloc/keineschweine/keineschweine.nim | 2 +- tests/manyloc/nake/nakefile.nim | 4 +- .../Chapter7/Tweeter/src/database.nim | 4 +- .../Chapter7/Tweeter/src/tweeter.nim | 2 +- .../Chapter7/Tweeter/src/views/user.nim | 2 +- tests/stdlib/tstdlib_various.nim | 18 +- tests/stdlib/tunittest.nim | 4 +- tests/template/template_various.nim | 2 +- tests/template/tgensymregression.nim | 2 +- tests/vm/textensionmap.nim | 2 +- tests/vm/tgloballetfrommacro.nim | 2 +- tools/niminst/debcreation.nim | 2 +- tools/nimweb.nim | 2 +- tools/website.nimf | 2 +- 41 files changed, 155 insertions(+), 519 deletions(-) create mode 100644 tests/ccgbugs2/tinefficient_const_table.nim diff --git a/doc/backends.rst b/doc/backends.rst index d34a06238..e46941a12 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -367,7 +367,7 @@ A similar thing happens with C code invoking Nim code which returns a .. code-block:: nim proc gimme(): cstring {.exportc.} = - result = "Hey there C code! " & $random(100) + result = "Hey there C code! " & $rand(100) Since Nim's garbage collector is not aware of the C code, once the ``gimme`` proc has finished it can reclaim the memory of the ``cstring``. diff --git a/lib/core/macros.nim b/lib/core/macros.nim index f3bca3af8..856c4f2c1 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -996,12 +996,6 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## ## Also see ``dumpTree`` and ``dumpLisp``. -macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr - ## Deprecated. Use `dumpTree` instead. - -macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr - ## Deprecated. Use `dumpLisp` instead. - proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} = ## Create a new empty node. result = newNimNode(nnkEmpty) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index c520fa833..1a6622677 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -483,13 +483,6 @@ proc multiReplace*(s: string, subs: openArray[ # copy the rest: add(result, substr(s, i)) -proc parallelReplace*(s: string, subs: openArray[ - tuple[pattern: Regex, repl: string]]): string {.deprecated: - "Deprecated since v0.18.0: Use ``multiReplace`` instead.".} = - ## Returns a modified copy of ``s`` with the substitutions in ``subs`` - ## applied in parallel. - result = multiReplace(s, subs) - proc transformFile*(infile, outfile: string, subs: openArray[tuple[pattern: Regex, repl: string]]) = ## reads in the file ``infile``, performs a parallel replacement (calls diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 91f2f41b8..4a6c2510a 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -223,10 +223,6 @@ proc binarySearch*[T](a: openArray[T], key: T): int = assert binarySearch([0, 1, 4, 2, 3], 4) == 2 binarySearch(a, key, cmp[T]) -proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated: - "Deprecated since v0.18.1; Use 'binarySearch'".} = - binarySearch(a, key, cmp[T]) - const onlySafeCode = true diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 0800cb638..a15442109 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -285,7 +285,7 @@ when defined(windows) or defined(nimdoc): new result result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) result.handles = initHashSet[AsyncFD]() - result.timers.newHeapQueue() + result.timers.clear() result.callbacks = initDeque[proc () {.closure, gcsafe.}](64) var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index b0789593a..608fd2920 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -183,14 +183,6 @@ proc `$`*[T](heap: HeapQueue[T]): string = result.addQuoted(x) result.add("]") -proc newHeapQueue*[T](): HeapQueue[T] {.deprecated: - "Deprecated since v0.20.0: use 'initHeapQueue' instead.".} = - initHeapQueue[T]() - -proc newHeapQueue*[T](heap: var HeapQueue[T]) {.deprecated: - "Deprecated since v0.20.0: use 'clear' instead.".} = - heap.clear() - when isMainModule: proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = var tmp = h diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 11639df3b..2b270c2cb 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -111,9 +111,7 @@ proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) = ## * `toHashSet proc <#toHashSet,openArray[A]>`_ runnableExamples: var a: HashSet[int] - assert(not a.isValid) init(a) - assert a.isValid initImpl(s, initialSize) @@ -647,9 +645,7 @@ proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) = ## * `toOrderedSet proc <#toOrderedSet,openArray[A]>`_ runnableExamples: var a: OrderedSet[int] - assert(not a.isValid) init(a) - assert a.isValid initImpl(s, initialSize) @@ -923,21 +919,6 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = -proc isValid*[A](s: OrderedSet[A]): bool {.deprecated: - "Deprecated since v0.20; sets are initialized by default".} = - ## - ## Returns `true` if the set has been initialized (with `initHashSet proc - ## <#initOrderedSet,int>`_ or `init proc <#init,OrderedSet[A],int>`_). - ## - ## **Examples:** - ## - ## .. code-block :: - ## proc savePreferences(options: OrderedSet[string]) = - ## assert options.isValid, "Pass an initialized set!" - ## # Do stuff here, may crash in release builds! - result = s.data.len > 0 - - # ----------------------------------------------------------------------- @@ -945,16 +926,8 @@ proc isValid*[A](s: OrderedSet[A]): bool {.deprecated: when isMainModule and not defined(release): proc testModule() = ## Internal micro test to validate docstrings and such. - block isValidTest: # isValid is deprecated - var options: HashSet[string] - proc savePreferences(options: HashSet[string]) = - assert options.isValid, "Pass an initialized set!" - options = initHashSet[string]() - options.savePreferences - block lenTest: var values: HashSet[int] - assert(not values.isValid) assert values.len == 0 assert values.card == 0 @@ -1046,16 +1019,8 @@ when isMainModule and not defined(release): var b = a.map(proc (x: int): string = $x) assert b == toHashSet(["1", "2", "3"]) - block isValidTest: # isValid is deprecated - var cards: OrderedSet[string] - proc saveTarotCards(cards: OrderedSet[string]) = - assert cards.isValid, "Pass an initialized set!" - cards = initOrderedSet[string]() - cards.saveTarotCards - block lenTest: var values: OrderedSet[int] - assert(not values.isValid) assert values.len == 0 assert values.card == 0 @@ -1119,7 +1084,7 @@ when isMainModule and not defined(release): a.init(4) a.incl(2) a.init - assert a.len == 0 and a.isValid + assert a.len == 0 a = initOrderedSet[int](4) a.incl(2) assert a.len == 1 @@ -1128,7 +1093,7 @@ when isMainModule and not defined(release): b.init(4) b.incl(2) b.init - assert b.len == 0 and b.isValid + assert b.len == 0 b = initHashSet[int](4) b.incl(2) assert b.len == 1 diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim index 3ee7336f0..841d58d86 100644 --- a/lib/pure/concurrency/cpuload.nim +++ b/lib/pure/concurrency/cpuload.nim @@ -88,7 +88,7 @@ when not defined(testing) and isMainModule and not defined(nimdoc): proc busyLoop() = while true: - discard random(80) + discard rand(80) os.sleep(100) spawn busyLoop() diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 1ac3ae185..dfd4abea5 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -435,7 +435,7 @@ proc `[]=`*(p: MultipartData, name: string, proc getBoundary(p: MultipartData): string = if p == nil or p.content.len == 0: return while true: - result = $random(int.high) + result = $rand(int.high) for i, entry in p.content: if result in entry.content: break elif i == p.content.high: return diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 6291cddf1..ea44de6d3 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -196,17 +196,6 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = result = result or (result shr 1) result += 1 + ord(x <= 0) -proc countBits32*(n: int32): int {.noSideEffect, deprecated: - "Deprecated since v0.20.0; use 'bitops.countSetBits' instead".} = - runnableExamples: - doAssert countBits32(7) == 3 - doAssert countBits32(8) == 1 - doAssert countBits32(15) == 4 - doAssert countBits32(16) == 1 - doAssert countBits32(17) == 2 - - bitops.countSetBits(n) - proc sum*[T](x: openArray[T]): T {.noSideEffect.} = ## Computes the sum of the elements in ``x``. ## @@ -611,13 +600,6 @@ when not defined(js): # C ## echo gamma(4.0) # 6.0 ## echo gamma(11.0) # 3628800.0 ## echo gamma(-1.0) # nan - proc tgamma*(x: float32): float32 - {.deprecated: "Deprecated since v0.19.0; use 'gamma' instead", - importc: "tgammaf", header: "".} - proc tgamma*(x: float64): float64 - {.deprecated: "Deprecated since v0.19.0; use 'gamma' instead", - importc: "tgamma", header: "".} - ## The gamma function proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} ## Computes the natural log of the gamma function for ``x``. @@ -750,12 +732,6 @@ when not defined(js): # C ## echo trunc(PI) # 3.0 ## echo trunc(-1.85) # -1.0 - proc fmod*(x, y: float32): float32 {.deprecated: "Deprecated since v0.19.0; use 'mod' instead", - importc: "fmodf", header: "".} - proc fmod*(x, y: float64): float64 {.deprecated: "Deprecated since v0.19.0; use 'mod' instead", - importc: "fmod", header: "".} - ## Computes the remainder of ``x`` divided by ``y``. - proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "".} proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "".} ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). @@ -1111,7 +1087,6 @@ when isMainModule and not defined(js) and not windowsCC89: # check gamma function assert(gamma(5.0) == 24.0) # 4! - assert($tgamma(5.0) == $24.0) # 4! assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 assert(erf(6.0) > erf(5.0)) assert(erfc(6.0) < erfc(5.0)) @@ -1133,20 +1108,6 @@ when isMainModule: doAssert round(-54.652) ==~ -55.0 doAssert round(-54.352) ==~ -54.0 doAssert round(0.0) ==~ 0.0 - # Round to positive decimal places - doAssert round(-547.652, 1) ==~ -547.7 - doAssert round(547.652, 1) ==~ 547.7 - doAssert round(-547.652, 2) ==~ -547.65 - doAssert round(547.652, 2) ==~ 547.65 - # Round to negative decimal places - doAssert round(547.652, -1) ==~ 550.0 - doAssert round(547.652, -2) ==~ 500.0 - doAssert round(547.652, -3) ==~ 1000.0 - doAssert round(547.652, -4) ==~ 0.0 - doAssert round(-547.652, -1) ==~ -550.0 - doAssert round(-547.652, -2) ==~ -500.0 - doAssert round(-547.652, -3) ==~ -1000.0 - doAssert round(-547.652, -4) ==~ 0.0 block: # splitDecimal() tests doAssert splitDecimal(54.674).intpart ==~ 54.0 diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 177476f41..67e24eedc 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -233,22 +233,6 @@ proc createNativeSocket*(domain: Domain = AF_INET, ## by child processes. createNativeSocket(toInt(domain), toInt(sockType), toInt(protocol), inheritable) -proc newNativeSocket*(domain: Domain = AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP): SocketHandle - {.deprecated: "deprecated since v0.18.0; use 'createNativeSocket' instead".} = - ## Creates a new socket; returns `osInvalidSocket` if an error occurs. - createNativeSocket(domain, sockType, protocol) - -proc newNativeSocket*(domain: cint, sockType: cint, - protocol: cint): SocketHandle - {.deprecated: "deprecated since v0.18.0; use 'createNativeSocket' instead".} = - ## Creates a new socket; returns `osInvalidSocket` if an error occurs. - ## - ## Use this overload if one of the enums specified above does - ## not contain what you need. - createNativeSocket(domain, sockType, protocol) - proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint = result = bindSocket(socket, name, namelen) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index e36f2be47..e794a4dde 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -206,30 +206,6 @@ proc skipRandomNumbers*(s: var Rand) = s.a0 = s0 s.a1 = s1 -proc random*(max: int): int {.benign, deprecated: - "Deprecated since v0.18.0; use 'rand' instead".} = - while true: - let x = next(state) - if x < randMax - (randMax mod Ui(max)): - return int(x mod uint64(max)) - -proc random*(max: float): float {.benign, deprecated: - "Deprecated since v0.18.0; use 'rand' instead".} = - let x = next(state) - when defined(js): - result = (float(x) / float(high(uint32))) * max - else: - let u = (0x3FFu64 shl 52u64) or (x shr 12u64) - result = (cast[float](u) - 1.0) * max - -proc random*[T](x: HSlice[T, T]): T {.deprecated: - "Deprecated since v0.18.0; use 'rand' instead".} = - result = T(random(x.b - x.a)) + x.a - -proc random*[T](a: openArray[T]): T {.deprecated: - "Deprecated since v0.18.0; use 'sample' instead".} = - result = a[random(a.low..a.len)] - proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. ## @@ -362,10 +338,6 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = doAssert rand(1..6) == 6 result = rand(state, x) -proc rand*[T](r: var Rand; a: openArray[T]): T {.deprecated: - "Deprecated since v0.20.0; use 'sample' instead".} = - result = a[rand(r, a.low..a.high)] - proc rand*[T: SomeInteger](t: typedesc[T]): T = ## Returns a random integer in the range `low(T)..high(T)`. ## @@ -395,10 +367,6 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T = else: result = cast[T](state.next) -proc rand*[T](a: openArray[T]): T {.deprecated: - "Deprecated since v0.20.0; use 'sample' instead".} = - result = a[rand(a.low..a.high)] - proc sample*[T](r: var Rand; s: set[T]): T = ## Returns a random element from the set ``s`` using the given state. ## @@ -687,6 +655,6 @@ when isMainModule: # don't use causes integer overflow - doAssert compiles(random[int](low(int) .. high(int))) + doAssert compiles(rand[int](low(int) .. high(int))) main() diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index c475c1b4f..12a134ef8 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -334,22 +334,3 @@ else: include ioselects/ioselectors_select else: include ioselects/ioselectors_poll - -proc register*[T](s: Selector[T], fd: int | SocketHandle, - events: set[Event], data: T) {.deprecated: "use registerHandle instead".} = - ## **Deprecated since v0.18.0:** Use ``registerHandle`` instead. - s.registerHandle(fd, events, data) - -proc setEvent*(ev: SelectEvent) {.deprecated: "use trigger instead".} = - ## Trigger event ``ev``. - ## - ## **Deprecated since v0.18.0:** Use ``trigger`` instead. - ev.trigger() - -proc update*[T](s: Selector[T], fd: int | SocketHandle, - events: set[Event]) {.deprecated: "use updateHandle instead".} = - ## Update file/socket descriptor ``fd``, registered in selector - ## ``s`` with new events set ``event``. - ## - ## **Deprecated since v0.18.0:** Use ``updateHandle`` instead. - s.updateHandle() diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 01eb16c23..7d82733e1 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -581,8 +581,8 @@ proc initDuration*(nanoseconds, microseconds, milliseconds, ## Create a new `Duration <#Duration>`_. runnableExamples: let dur = initDuration(seconds = 1, milliseconds = 1) - doAssert dur.milliseconds == 1 - doAssert dur.seconds == 1 + doAssert dur.inMilliseconds == 1001 + doAssert dur.inSeconds == 1 let seconds = convert(Weeks, Seconds, weeks) + convert(Days, Seconds, days) + @@ -1464,7 +1464,7 @@ type s, ss fff, ffffff, fffffffff t, tt - y, yy, yyy, yyyy, yyyyy + yy, yyyy YYYY uuuu UUUU @@ -1612,11 +1612,8 @@ proc stringToPattern(str: string): FormatPattern = of "fffffffff": result = fffffffff of "t": result = t of "tt": result = tt - of "y": result = y of "yy": result = yy - of "yyy": result = yyy of "yyyy": result = yyyy - of "yyyyy": result = yyyyy of "YYYY": result = YYYY of "uuuu": result = uuuu of "UUUU": result = UUUU @@ -1709,20 +1706,14 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add if dt.hour >= 12: "P" else: "A" of tt: result.add if dt.hour >= 12: "PM" else: "AM" - of y: # Deprecated - result.add $(dt.yearOfEra mod 10) of yy: result.add (dt.yearOfEra mod 100).intToStr(2) - of yyy: # Deprecated - result.add (dt.yearOfEra mod 1000).intToStr(3) of yyyy: let year = dt.yearOfEra if year < 10000: result.add year.intToStr(4) else: result.add '+' & $year - of yyyyy: # Deprecated - result.add (dt.yearOfEra mod 100_000).intToStr(5) of YYYY: if dt.year < 1: result.add $(abs(dt.year) + 1) @@ -1933,8 +1924,6 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, i.inc 2 else: result = false - of y, yyy, yyyyy: - raiseAssert "Pattern is invalid for parsing: " & $pattern of Lit: doAssert false, "Can't happen" proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, @@ -2631,167 +2620,11 @@ when not defined(js): else: result = toFloat(int(getClock())) / toFloat(clocksPerSec) + # # Deprecations # -proc countLeapYears*(yearSpan: int): int - {.deprecated.} = - ## Returns the number of leap years spanned by a given number of years. - ## - ## **Note:** For leap years, start date is assumed to be 1 AD. - ## counts the number of leap years up to January 1st of a given year. - ## Keep in mind that if specified year is a leap year, the leap day - ## has not happened before January 1st of that year. - # Deprecated since v0.20.0 - (yearSpan - 1) div 4 - (yearSpan - 1) div 100 + (yearSpan - 1) div 400 - -proc countDays*(yearSpan: int): int - {.deprecated.} = - ## Returns the number of days spanned by a given number of years. - # Deprecated since v0.20.0 - (yearSpan - 1) * 365 + countLeapYears(yearSpan) - -proc countYears*(daySpan: int): int - {.deprecated.} = - ## Returns the number of years spanned by a given number of days. - # Deprecated since v0.20.0 - ((daySpan - countLeapYears(daySpan div 365)) div 365) - -proc countYearsAndDays*(daySpan: int): tuple[years: int, days: int] - {.deprecated.} = - ## Returns the number of years spanned by a given number of days and the - ## remainder as days. - # Deprecated since v0.20.0 - let days = daySpan - countLeapYears(daySpan div 365) - result.years = days div 365 - result.days = days mod 365 - -proc toTimeInterval*(time: Time): TimeInterval - {.deprecated: "Use 'between' instead".} = - ## Converts a Time to a TimeInterval. To be used when diffing times. - # Deprecated since version 0.20.0 - runnableExamples: - let a = fromUnix(10) - let b = fromUnix(1_500_000_000) - let ti = b.toTimeInterval() - a.toTimeInterval() - doAssert a + ti == b - var dt = time.local - initTimeInterval(dt.nanosecond, 0, 0, dt.second, dt.minute, dt.hour, - dt.monthday, 0, dt.month.ord - 1, dt.year) - -proc weeks*(dur: Duration): int64 - {.inline, deprecated: "Use 'inWeeks' instead".} = - ## Number of whole weeks represented by the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4) - doAssert dur.weeks == 1 - dur.inWeeks - -proc days*(dur: Duration): int64 - {.inline, deprecated: "Use 'inDays' instead".} = - ## Number of whole days represented by the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(weeks = 1, days = 2, hours = 3, minutes = 4) - doAssert dur.days == 9 - dur.inDays - -proc hours*(dur: Duration): int64 - {.inline, deprecated: "Use 'inHours' instead".} = - ## Number of whole hours represented by the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(days = 1, hours = 2, minutes = 3) - doAssert dur.hours == 26 - dur.inHours - -proc minutes*(dur: Duration): int64 - {.inline, deprecated: "Use 'inMinutes' instead".} = - ## Number of whole minutes represented by the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(days = 1, hours = 2, minutes = 3) - doAssert dur.minutes == 1563 - dur.inMinutes - -proc seconds*(dur: Duration): int64 - {.inline, deprecated: "Use 'inSeconds' instead".} = - ## Number of whole seconds represented by the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(minutes = 10, seconds = 30) - doAssert dur.seconds == 630 - dur.inSeconds - -proc milliseconds*(dur: Duration): int {.inline, deprecated.} = - ## Number of whole milliseconds represented by the **fractional** - ## part of the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, - microseconds = 8, nanoseconds = 9) - doAssert dur.milliseconds == 7 - result = convert(Nanoseconds, Milliseconds, dur.nanosecond) - -proc microseconds*(dur: Duration): int {.inline, deprecated.} = - ## Number of whole microseconds represented by the **fractional** - ## part of the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, - microseconds = 8, nanoseconds = 9) - doAssert dur.microseconds == 7008 - result = convert(Nanoseconds, Microseconds, dur.nanosecond) - -proc nanoseconds*(dur: Duration): NanosecondRange {.inline, deprecated.} = - ## Number of whole microseconds represented by the **fractional** - ## part of the duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, - microseconds = 8, nanoseconds = 9) - doAssert dur.nanoseconds == 7008009 - dur.nanosecond - -proc fractional*(dur: Duration): Duration {.inline, deprecated.} = - ## The fractional part of `dur`, as a duration. - # Deprecated since version v0.20.0 - runnableExamples: - let dur = initDuration(minutes = 5, seconds = 6, milliseconds = 7, - microseconds = 8, nanoseconds = 9) - doAssert dur.fractional == initDuration(milliseconds = 7, microseconds = 8, - nanoseconds = 9) - initDuration(nanoseconds = dur.nanosecond) - -proc fromSeconds*(since1970: float): Time - {.tags: [], raises: [], benign, deprecated: "Use `fromUnixFloat or 'fromUnix' instead".} = - ## Takes a float which contains the number of seconds since the unix epoch and - ## returns a time object. - # Deprecated since v0.18.0 - fromUnixFloat(since1970) - -proc fromSeconds*(since1970: int64): Time - {.tags: [], raises: [], benign, deprecated: "Use 'fromUnix' instead".} = - ## Takes an int which contains the number of seconds since the unix epoch and - ## returns a time object. - # Deprecated since v0.18.0 - fromUnix(since1970) - -proc toSeconds*(time: Time): float - {.tags: [], raises: [], benign, deprecated: "Use 'toUnixFloat' or 'toUnix' instead".} = - ## Returns the time in seconds since the unix epoch, with subsecond resolution. - # Deprecated since v0.18.0 - toUnixFloat(time) - -proc getGMTime*(time: Time): DateTime - {.tags: [], raises: [], benign, deprecated: "Use 'utc' instead".} = - ## Converts the calendar time `time` to broken-down time representation, - ## expressed in Coordinated Universal Time (UTC). - # Deprecated since v0.18.0 - time.utc - proc `nanosecond=`*(dt: var DateTime, value: NanosecondRange) {.deprecated: "Deprecated since v1.3.1".} = dt.nanosecond = value diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 497d5e465..b550b0eac 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1169,88 +1169,6 @@ proc alignLeft*(s: string, count: Natural, padding = ' '.Rune): string {. else: result = s -# ----------------------------------------------------------------------------- -# deprecated - -template runeCaseCheck(s, runeProc, skipNonAlpha) = - ## Common code for rune.isLower and rune.isUpper. - if len(s) == 0: return false - var - i = 0 - rune: Rune - hasAtleastOneAlphaRune = false - while i < len(s): - fastRuneAt(s, i, rune, doInc = true) - if skipNonAlpha: - var runeIsAlpha = isAlpha(rune) - if not hasAtleastOneAlphaRune: - hasAtleastOneAlphaRune = runeIsAlpha - if runeIsAlpha and (not runeProc(rune)): - return false - else: - if not runeProc(rune): - return false - return if skipNonAlpha: hasAtleastOneAlphaRune else: true - -proc isLower*(s: string, skipNonAlpha: bool): bool {. - deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = - ## **Deprecated since version 0.20 since its semantics are unclear** - ## - ## Checks whether ``s`` is lower case. - ## - ## If ``skipNonAlpha`` is true, returns true if all alphabetical - ## runes in ``s`` are lower case. Returns false if none of the - ## runes in ``s`` are alphabetical. - ## - ## If ``skipNonAlpha`` is false, returns true only if all runes in - ## ``s`` are alphabetical and lower case. - ## - ## For either value of ``skipNonAlpha``, returns false if ``s`` is - ## an empty string. - runeCaseCheck(s, isLower, skipNonAlpha) - -proc isUpper*(s: string, skipNonAlpha: bool): bool {. - deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = - ## **Deprecated since version 0.20 since its semantics are unclear** - ## - ## Checks whether ``s`` is upper case. - ## - ## If ``skipNonAlpha`` is true, returns true if all alphabetical - ## runes in ``s`` are upper case. Returns false if none of the - ## runes in ``s`` are alphabetical. - ## - ## If ``skipNonAlpha`` is false, returns true only if all runes in - ## ``s`` are alphabetical and upper case. - ## - ## For either value of ``skipNonAlpha``, returns false if ``s`` is - ## an empty string. - runeCaseCheck(s, isUpper, skipNonAlpha) - -proc isTitle*(s: string): bool {.noSideEffect, rtl, extern: "nuc$1Str", - deprecated: "Deprecated since version 0.20 since its semantics are unclear".} = - ## **Deprecated since version 0.20 since its semantics are unclear** - ## - ## Checks whether or not ``s`` is a unicode title. - ## - ## Returns true if the first character in each word inside ``s`` - ## are upper case and there is at least one character in ``s``. - if s.len == 0: - return false - result = true - var - i = 0 - rune: Rune - var firstRune = true - - while i < len(s) and result: - fastRuneAt(s, i, rune, doInc = true) - if not rune.isWhiteSpace() and firstRune: - result = rune.isUpper() and result - firstRune = false - elif rune.isWhiteSpace(): - firstRune = true - - when isMainModule: diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index bb4e2867c..bea7d9c44 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -416,8 +416,7 @@ proc ensureInitialized() = if formatters.len == 0: formatters = @[OutputFormatter(defaultConsoleFormatter())] - if not disabledParamFiltering and not testsFilters.isValid: - testsFilters.init() + if not disabledParamFiltering: when declared(paramCount): # Read tests to run from the command line. for i in 1 .. paramCount(): @@ -712,7 +711,7 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = ## import math, random ## proc defectiveRobot() = ## randomize() - ## case random(1..4) + ## case rand(1..4) ## of 1: raise newException(OSError, "CANNOT COMPUTE!") ## of 2: discard parseInt("Hello World!") ## of 3: raise newException(IOError, "I can't do that Dave.") diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index 8d176985d..f6c1b69ff 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -481,18 +481,10 @@ proc `+=`*[T: SomeInteger](x: var T, y: T) {. magic: "Inc", noSideEffect.} ## Increments an integer. -proc `+=`*[T: enum|bool](x: var T, y: T) {. - magic: "Inc", noSideEffect, deprecated: "use `inc` instead".} - ## **Deprecated since v0.20**: use `inc` instead. - proc `-=`*[T: SomeInteger](x: var T, y: T) {. magic: "Dec", noSideEffect.} ## Decrements an integer. -proc `-=`*[T: enum|bool](x: var T, y: T) {. - magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".} - ## **Deprecated since v0.20**: use `dec` instead. - proc `*=`*[T: SomeInteger](x: var T, y: T) {. inline, noSideEffect.} = ## Binary `*=` operator for integers. diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 5a28fa3dd..6da644ce3 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -34,7 +34,6 @@ pkg1 "coco", true pkg1 "combparser" pkg1 "compactdict" pkg1 "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" -pkg1 "criterion" pkg1 "dashing", false, "nim c tests/functional.nim" pkg1 "delaunay" pkg1 "docopt" diff --git a/tests/ccgbugs2/tinefficient_const_table.nim b/tests/ccgbugs2/tinefficient_const_table.nim new file mode 100644 index 000000000..a1b89e220 --- /dev/null +++ b/tests/ccgbugs2/tinefficient_const_table.nim @@ -0,0 +1,27 @@ +discard """ + output: '''a +long +list +of +words''' + cmd: r"nim c --hints:on $options -d:release $file" + ccodecheck: "! @'genericSeqAssign'" + target: "c" +""" + +# bug #4354 +import tables +import sets +import strutils + +#const FRUITS = ["banana", "apple", "grapes"] +#let FRUITS = ["banana", "apple", "grapes"].toHashSet +const FRUITS = {"banana":0, "apple":0, "grapes":0}.toTable + +proc main() = + let L = "a long list of words".split() + for word in L: + if word notin FRUITS: + echo(word) + +main() diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim index bc387d292..4ab3a66b7 100644 --- a/tests/collections/thashsets.nim +++ b/tests/collections/thashsets.nim @@ -79,9 +79,8 @@ block hashForHashedSet: let seq1 = "This is the test." seq2 = "the test is This." - s1 = seq1.toSet() - s2 = seq2.toSet() - var hashSeq: seq[Hash] = @[] + s1 = seq1.toHashSet() + s2 = seq2.toHashSet() doAssert s1 == s2 doAssert hash(s1) == hash(s2) diff --git a/tests/deps/jester-#head/jester.nim b/tests/deps/jester-#head/jester.nim index d9db50856..1118214c2 100644 --- a/tests/deps/jester-#head/jester.nim +++ b/tests/deps/jester-#head/jester.nim @@ -1,6 +1,6 @@ # Copyright (C) 2015 Dominik Picheta # MIT License - Look at license.txt for details. -import net, strtabs, re, tables, parseutils, os, strutils, uri, +import net, strtabs, re, tables, os, strutils, uri, times, mimetypes, asyncnet, asyncdispatch, macros, md5, logging, httpcore, asyncfile, macrocache, json, options, strformat @@ -23,6 +23,7 @@ export SameSite when useHttpBeast: import httpbeast except Settings, Request import options + from nativesockets import close else: import asynchttpserver except Request @@ -72,14 +73,14 @@ type of RouteCode: data: ResponseData -const jesterVer = "0.4.0" +const jesterVer = "0.4.3" proc toStr(headers: Option[RawHeaders]): string = return $newHttpHeaders(headers.get(@({:}))) proc createHeaders(headers: RawHeaders): string = result = "" - if headers != nil: + if headers.len > 0: for header in headers: let (key, value) = header result.add(key & ": " & value & "\c\L") @@ -98,22 +99,24 @@ proc unsafeSend(request: Request, content: string) = proc send( request: Request, code: HttpCode, headers: Option[RawHeaders], body: string -) = +): Future[void] = when useHttpBeast: let h = if headers.isNone: "" else: headers.get().createHeaders request.getNativeReq.send(code, body, h) + var fut = newFuture[void]() + complete(fut) + return fut else: - # TODO: This may cause issues if we send too fast. - asyncCheck request.getNativeReq.respond( + return request.getNativeReq.respond( code, body, newHttpHeaders(headers.get(@({:}))) ) proc statusContent(request: Request, status: HttpCode, content: string, - headers: Option[RawHeaders]) = + headers: Option[RawHeaders]): Future[void] = try: - send(request, status, headers, content) + result = send(request, status, headers, content) when not defined(release): logging.debug(" $1 $2" % [$status, toStr(headers)]) except: @@ -174,7 +177,11 @@ proc sendStaticIfExists( return Http403 let fileSize = getFileSize(p) - let mimetype = req.settings.mimes.getMimetype(p.splitFile.ext[1 .. ^1]) + let ext = p.splitFile.ext + let mimetype = req.settings.mimes.getMimetype( + if ext.len > 0: ext[1 .. ^1] + else: "" + ) if fileSize < 10_000_000: # 10 mb var file = readFile(p) @@ -183,18 +190,18 @@ proc sendStaticIfExists( # If the user has a cached version of this file and it matches our # version, let them use it if req.headers.hasKey("If-None-Match") and req.headers["If-None-Match"] == hashed: - req.statusContent(Http304, "", none[RawHeaders]()) + await req.statusContent(Http304, "", none[RawHeaders]()) else: - req.statusContent(Http200, file, some(@({ - "Content-Type": mimetype, - "ETag": hashed - }))) + await req.statusContent(Http200, file, some(@({ + "Content-Type": mimetype, + "ETag": hashed + }))) else: let headers = @({ "Content-Type": mimetype, "Content-Length": $fileSize }) - req.statusContent(Http200, "", some(headers)) + await req.statusContent(Http200, "", some(headers)) var fileStream = newFutureStream[string]("sendStaticIfExists") var file = openAsync(p, fmRead) @@ -216,13 +223,22 @@ proc sendStaticIfExists( # If we get to here then no match could be found. return Http404 +proc close*(request: Request) = + ## Closes client socket connection. + ## + ## Routes using this procedure must enable raw mode. + let nativeReq = request.getNativeReq() + when useHttpBeast: + nativeReq.forget() + nativeReq.client.close() + proc defaultErrorFilter(error: RouteError): ResponseData = case error.kind of RouteException: let e = error.exc let traceback = getStackTrace(e) var errorMsg = e.msg - if errorMsg.isNil: errorMsg = "(nil)" + if errorMsg.len == 0: errorMsg = "(empty)" let error = traceback & errorMsg logging.error(error) @@ -295,9 +311,11 @@ proc handleFileRequest( jes.settings.staticDir / cgi.decodeUrl(req.pathInfo) ) - # Verify that this isn't outside our static` dir. + # Verify that this isn't outside our static dir. var status = Http400 - if path.splitFile.dir.startsWith(jes.settings.staticDir): + let pathDir = path.splitFile.dir / "" + let staticDir = jes.settings.staticDir / "" + if pathDir.startsWith(staticDir): if existsDir(path): status = await sendStaticIfExists( req, @@ -347,7 +365,7 @@ proc handleRequestSlow( not dispatchedError and respData.content.len == 0: respData = await dispatchError(jes, req, initRouteError(respData)) - statusContent( + await statusContent( req, respData.code, respData.content, @@ -368,7 +386,7 @@ proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] = if likely(jes.matchers.len == 1 and not jes.matchers[0].async): let respData = jes.matchers[0].syncProc(req) if likely(respData.matched): - statusContent( + return statusContent( req, respData.code, respData.content, @@ -383,6 +401,8 @@ proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] = let respDataFut = dispatchError(jes, req, initRouteError(exc)) return handleRequestSlow(jes, req, respDataFut, true) + assert(not result.isNil, "Expected handleRequest to return a valid future.") + proc newSettings*( port = Port(5000), staticDir = getCurrentDir() / "public", appName = "", bindAddr = "", reusePort = false, @@ -461,14 +481,19 @@ proc serve*( ] ) else: - logging.info("Jester is making jokes at http://0.0.0.0:$1$2" % - [$self.settings.port, self.settings.appName]) + when defined(windows): + logging.info("Jester is making jokes at http://127.0.0.1:$1$2 (all interfaces)" % + [$self.settings.port, self.settings.appName]) + else: + logging.info("Jester is making jokes at http://0.0.0.0:$1$2" % + [$self.settings.port, self.settings.appName]) var jes = self when useHttpBeast: run( proc (req: httpbeast.Request): Future[void] = - result = handleRequest(jes, req), + {.gcsafe.}: + result = handleRequest(jes, req), httpbeast.initSettings(self.settings.port, self.settings.bindAddr) ) else: @@ -484,14 +509,6 @@ proc serve*( asyncCheck serveFut runForever() -template resp*(code: HttpCode, - headers: openarray[tuple[key, value: string]], - content: string): typed = - ## Sets ``(code, headers, content)`` as the response. - bind TCActionSend, newHttpHeaders - result = (TCActionSend, code, headers.newHttpHeaders.some(), content, true) - break route - template setHeader(headers: var Option[RawHeaders], key, value: string): typed = bind isNone if isNone(headers): @@ -509,6 +526,17 @@ template setHeader(headers: var Option[RawHeaders], key, value: string): typed = # Add key if it doesn't exist. headers = some(h & @({key: value})) +template resp*(code: HttpCode, + headers: openarray[tuple[key, val: string]], + content: string): typed = + ## Sets ``(code, headers, content)`` as the response. + bind TCActionSend + result = (TCActionSend, code, none[RawHeaders](), content, true) + for header in headers: + setHeader(result[2], header[0], header[1]) + break route + + template resp*(content: string, contentType = "text/html;charset=utf-8"): typed = ## Sets ``content`` as the response; ``Http200`` as the status code ## and ``contentType`` as the Content-Type. @@ -687,7 +715,8 @@ proc daysForward*(days: int): DateTime = return getTime().utc + initTimeInterval(days = days) template setCookie*(name, value: string, expires="", - sameSite: SameSite=Lax): typed = + sameSite: SameSite=Lax, secure = false, + httpOnly = false, domain = "", path = "") = ## Creates a cookie which stores ``value`` under ``name``. ## ## The SameSite argument determines the level of CSRF protection that @@ -695,7 +724,7 @@ template setCookie*(name, value: string, expires="", ## should protect you from most vulnerabilities. Note that this is only ## supported by some browsers: ## https://caniuse.com/#feat=same-site-cookie-attribute - let newCookie = makeCookie(name, value, expires) + let newCookie = makeCookie(name, value, expires, domain, path, secure, httpOnly, sameSite) if isSome(result[2]) and (let headers = result[2].get(); headers.toTable.hasKey("Set-Cookie")): result[2] = some(headers & @({"Set-Cookie": newCookie})) @@ -703,9 +732,12 @@ template setCookie*(name, value: string, expires="", setHeader(result[2], "Set-Cookie", newCookie) template setCookie*(name, value: string, expires: DateTime, - sameSite: SameSite=Lax): typed = + sameSite: SameSite=Lax, secure = false, + httpOnly = false, domain = "", path = "") = ## Creates a cookie which stores ``value`` under ``name``. - setCookie(name, value, format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'")) + setCookie(name, value, + format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"), + sameSite, secure, httpOnly, domain, path) proc normalizeUri*(uri: string): string = ## Remove any trailing ``/``. @@ -721,7 +753,10 @@ proc checkAction*(respData: var ResponseData): bool = of TCActionPass: result = false of TCActionNothing: - assert(false) + raise newException( + ValueError, + "Missing route action, did you forget to use `resp` in your route?" + ) proc skipDo(node: NimNode): NimNode {.compiletime.} = if node.kind == nnkDo: @@ -764,14 +799,14 @@ proc ctParsePattern(pattern, pathPrefix: string): NimNode {.compiletime.} = newStrLitNode(node.text), newIdentNode(if node.optional: "true" else: "false")) -template setDefaultResp*(): typed = +template setDefaultResp*() = # TODO: bindSym this in the 'routes' macro and put it in each route bind TCActionNothing, newHttpHeaders result.action = TCActionNothing result.code = Http200 result.content = "" -template declareSettings(): typed {.dirty.} = +template declareSettings() {.dirty.} = when not declaredInScope(settings): var settings = newSettings() @@ -1299,7 +1334,7 @@ proc routesEx(name: string, body: NimNode): NimNode = for branch in exceptionBranches: stmts.add(newIfStmt(branch)) errorHandlerProc[6][0][1][^1][1][1][0] = stmts - if httpCodeBranches.len > 1: + if httpCodeBranches.len != 0: var stmts = newStmtList() for branch in httpCodeBranches: stmts.add(newIfStmt(branch)) @@ -1313,7 +1348,7 @@ proc routesEx(name: string, body: NimNode): NimNode = # echo toStrLit(result) # echo treeRepr(result) -macro routes*(body: untyped): typed = +macro routes*(body: untyped) = result = routesEx("match", body) let jesIdent = genSym(nskVar, "jes") let matchIdent = newIdentNode("match") @@ -1329,13 +1364,13 @@ macro routes*(body: untyped): typed = serve(`jesIdent`) ) -macro router*(name: untyped, body: untyped): typed = +macro router*(name: untyped, body: untyped) = if name.kind != nnkIdent: error("Need an ident.", name) - routesEx($name.ident, body) + routesEx(strVal(name), body) -macro settings*(body: untyped): typed = +macro settings*(body: untyped) = #echo(treeRepr(body)) expectKind(body, nnkStmtList) diff --git a/tests/deps/jester-#head/jester.nimble b/tests/deps/jester-#head/jester.nimble index 08e990bd7..a1306c525 100644 --- a/tests/deps/jester-#head/jester.nimble +++ b/tests/deps/jester-#head/jester.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.0" # Be sure to update jester.jesterVer too! +version = "0.4.3" # Be sure to update jester.jesterVer too! author = "Dominik Picheta" description = "A sinatra-like web framework for Nim." license = "MIT" @@ -13,10 +13,10 @@ skipDirs = @["tests"] requires "nim >= 0.18.1" when not defined(windows): - requires "httpbeast >= 0.2.0" + requires "httpbeast >= 0.2.2" # For tests -requires "asynctools" +requires "https://github.com/timotheecour/asynctools#pr_fix_compilation" task test, "Runs the test suite.": - exec "nimble c -y -r tests/tester" \ No newline at end of file + exec "nimble c -y -r tests/tester" diff --git a/tests/deps/jester-#head/jester/patterns.nim b/tests/deps/jester-#head/jester/patterns.nim index c827fbc7f..03d41796e 100644 --- a/tests/deps/jester-#head/jester/patterns.nim +++ b/tests/deps/jester-#head/jester/patterns.nim @@ -15,7 +15,7 @@ type proc parsePattern*(pattern: string): Pattern = result = @[] template addNode(result: var Pattern, theT: NodeType, theText: string, - isOptional: bool): typed = + isOptional: bool) = block: var newNode: Node newNode.typ = theT @@ -120,7 +120,7 @@ proc match*(pattern: Pattern, s: string): if s.len != i: result.matched = false -when true: +when isMainModule: let f = parsePattern("/show/@id/test/@show?/?") doAssert match(f, "/show/12/test/hallo/").matched doAssert match(f, "/show/2131726/test/jjjuuwąąss").matched diff --git a/tests/deps/jester-#head/jester/private/utils.nim b/tests/deps/jester-#head/jester/private/utils.nim index 16dce61fe..2d1390955 100644 --- a/tests/deps/jester-#head/jester/private/utils.nim +++ b/tests/deps/jester-#head/jester/private/utils.nim @@ -21,7 +21,7 @@ type JesterError* = object of Exception proc parseUrlQuery*(query: string, result: var Table[string, string]) - {.deprecated: "use stdlib".} = + {.deprecated: "use stdlib cgi/decodeData".} = var i = 0 i = query.skip("?") while i < query.len()-1: @@ -192,4 +192,3 @@ when false: var r = {:}.newStringTable parseUrlQuery("FirstName=Mickey", r) echo r - diff --git a/tests/deps/jester-#head/jester/request.nim b/tests/deps/jester-#head/jester/request.nim index 1b837d728..7c6a1a961 100644 --- a/tests/deps/jester-#head/jester/request.nim +++ b/tests/deps/jester-#head/jester/request.nim @@ -61,6 +61,7 @@ proc reqMethod*(req: Request): HttpMethod = req.req.httpMethod.get() else: req.req.reqMethod + proc reqMeth*(req: Request): HttpMethod {.deprecated.} = req.reqMethod diff --git a/tests/gc/gcleak5.nim b/tests/gc/gcleak5.nim index 6ab50e19e..f1913831b 100644 --- a/tests/gc/gcleak5.nim +++ b/tests/gc/gcleak5.nim @@ -9,7 +9,7 @@ proc main = for ii in 0..50_000: #while true: var t = getTime() - var g = t.getGMTime() + var g = t.utc() #echo isOnStack(addr g) if i mod 100 == 0: diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 459e38674..136d3e06b 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -447,7 +447,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[], # First generate the joined version of input parameters in a list. var - seen = initSet[string]() + seen = initHashSet[string]() prefixes: seq[string] = @[] helps: seq[string] = @[] for key in keys: diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index b6fd3cc19..6d8e48f24 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -486,7 +486,7 @@ when defined(DebugKeys): activeVehicle.body.setPos mouseToSpace()) ingameClient.registerHandler(KeyY, down, proc() = const looloo = ["Asteroid1", "Asteroid2"] - addObject(looloo[random(looloo.len)])) + addObject(looloo[rand(looloo.len)])) ingameClient.registerHandler(KeyO, down, proc() = if objects.len == 0: echo "Objects is empty" diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 0b5055512..91dd61726 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -63,7 +63,7 @@ task "release", "release build": ## zip up all the files and such or something useful here task "testskel", "create skeleton test dir for testing": - let dirname = "test-" & $random(5000) + let dirname = "test-" & $rand(5000) removeDir dirName createDir dirName/"data/fnt" copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf" @@ -133,7 +133,7 @@ task "download", "download game assets": else: ## this crashes, dunno why var z: TZipArchive - destDir = getCurrentDir()/("unzip" & $random(5000)) + destDir = getCurrentDir()/("unzip" & $rand(5000)) if not z.open(path, fmRead): echo "Could not open zip, bad download?" return diff --git a/tests/niminaction/Chapter7/Tweeter/src/database.nim b/tests/niminaction/Chapter7/Tweeter/src/database.nim index 3785ea307..bd6667f70 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/database.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/database.nim @@ -50,7 +50,7 @@ proc post*(database: Database, message: Message) = raise newException(ValueError, "Message has to be less than 140 characters.") database.db.exec(sql"INSERT INTO Message VALUES (?, ?, ?);", #<2> - message.username, $message.time.toSeconds().int, message.msg) #<3> + message.username, $message.time.toUnix().int, message.msg) #<3> proc follow*(database: Database, follower: User, user: User) = database.db.exec(sql"INSERT INTO Following VALUES (?, ?);",#<2> @@ -90,4 +90,4 @@ proc findMessages*(database: Database, usernames: seq[string], "ORDER BY time DESC LIMIT " & $limit), usernames) for row in messages: - result.add(Message(username: row[0], time: fromSeconds(row[1].parseInt), msg: row[2])) + result.add(Message(username: row[0], time: fromUnix(row[1].parseInt), msg: row[2])) diff --git a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim index 12aaf49b8..fe39278fb 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim @@ -51,7 +51,7 @@ routes: redirect(uri("/" & @"target")) post "/login": - setCookie("username", @"username", getTime().getGMTime() + 2.hours) + setCookie("username", @"username", getTime().utc() + 2.hours) redirect("/") post "/createMessage": diff --git a/tests/niminaction/Chapter7/Tweeter/src/views/user.nim b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim index 18f3713b3..4abcf440d 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/views/user.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim @@ -33,7 +33,7 @@ #for message in messages:
    ${message.username} - ${message.time.getGMTime().format("HH:mm MMMM d',' yyyy")} + ${message.time.utc().format("HH:mm MMMM d',' yyyy")}

    ${message.msg}

    #end for diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim index 42ed4fda2..cddd43f6e 100644 --- a/tests/stdlib/tstdlib_various.nim +++ b/tests/stdlib/tstdlib_various.nim @@ -60,15 +60,15 @@ block tcritbits: block testequivalence: - doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset") - doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3]), "equivalent or subset") - doAssert((not(toSet(@[1,2,3]) <= toSet(@[1,2]))), "equivalent or subset") - doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "strict subset") - doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2,3]))), "strict subset") - doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2]))), "strict subset") - doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2,3,4]))), "==") - doAssert(toSet(@[1,2,3]) == toSet(@[1,2,3]), "==") - doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2]))), "==") + doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset") + doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset") + doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset") + doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset") + doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset") + doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset") + doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==") + doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==") + doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==") diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index b0efdb617..9ef689e32 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -47,10 +47,10 @@ test "unittest multiple requires": require(true) -import math, random +import random from strutils import parseInt proc defectiveRobot() = - case random(1..4) + case rand(1..4) of 1: raise newException(OSError, "CANNOT COMPUTE!") of 2: discard parseInt("Hello World!") of 3: raise newException(IOError, "I can't do that Dave.") diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim index e8202a2e0..75226ea2d 100644 --- a/tests/template/template_various.nim +++ b/tests/template/template_various.nim @@ -107,7 +107,7 @@ block tgetast_typeliar: error("Assertion failed: " & $(`message`) & "\n" & `line`) return - macro assertOrReturn(condition: bool): typed = + macro assertOrReturn(condition: bool) = var message : NimNode = newLit(condition.repr) # echo message result = getAst assertOrReturn2(condition, message) diff --git a/tests/template/tgensymregression.nim b/tests/template/tgensymregression.nim index a743d3a08..f84c96403 100644 --- a/tests/template/tgensymregression.nim +++ b/tests/template/tgensymregression.nim @@ -57,7 +57,7 @@ converter int2string(x: int): string = $x template wrap(body: typed): untyped = body -macro makeProc(): typed = +macro makeProc() = # Make a template tree result = quote do: proc someProc* = diff --git a/tests/vm/textensionmap.nim b/tests/vm/textensionmap.nim index 5d4b25d01..7ada1880d 100644 --- a/tests/vm/textensionmap.nim +++ b/tests/vm/textensionmap.nim @@ -10,4 +10,4 @@ const EXTENSIONMAP = { "c": @["*.c", "*.h"], }.toTable() -const EXTENSIONS = toSet(concat(toSeq(EXTENSIONMAP.values()))) +const EXTENSIONS = toHashSet(concat(toSeq(EXTENSIONMAP.values()))) diff --git a/tests/vm/tgloballetfrommacro.nim b/tests/vm/tgloballetfrommacro.nim index 14dbff1e8..4be09b56e 100644 --- a/tests/vm/tgloballetfrommacro.nim +++ b/tests/vm/tgloballetfrommacro.nim @@ -5,7 +5,7 @@ line: 11 import sets -let BUILTIN_NAMES = toSet(["int8", "int16", "int32", "int64"]) +let BUILTIN_NAMES = toHashSet(["int8", "int16", "int32", "int64"]) macro test*(): bool = echo "int64" notin BUILTIN_NAMES diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim index 60aa48639..d0f46fa52 100644 --- a/tools/niminst/debcreation.nim +++ b/tools/niminst/debcreation.nim @@ -101,7 +101,7 @@ proc createChangelog(pkgName, version, maintainer: string): string = addN(" * Initial release.") addN("") addN(" -- " & maintainer & " " & - formatDateTime(getGMTime(getTime()), "+0000")) + formatDateTime(utc(getTime()), "+0000")) proc createRules(): string = ## Creates a nim application-agnostic rules file for building deb packages. diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 460135f49..a654c2b0a 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -421,7 +421,7 @@ proc generateRss(outputFilename: string, news: seq[TRssItem]) = output.write(link(href = rssNewsUrl)) output.write(id(rssNewsUrl)) - let now = getGMTime(getTime()) + let now = utc(getTime()) output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday)) for rss in news: diff --git a/tools/website.nimf b/tools/website.nimf index 9e5eb2460..bde84b32f 100644 --- a/tools/website.nimf +++ b/tools/website.nimf @@ -250,7 +250,7 @@ runForever()

    This section lists the companies and individuals that are, very kindly, contributing a monthly amount to help sustain Nim's development. For more details take a look at the Bountysource campaign.

    -

    Last updated: ${getTime().getGMTime().format("dd/MM/yyyy")}

    +

    Last updated: ${getTime().utc().format("dd/MM/yyyy")}

    ${generateSponsors(activeSponsors)}
    From 7df27b5035ad128812fbd070e3fa80ef6819e4df Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 17 Jun 2020 20:25:25 -0700 Subject: [PATCH 0724/4254] [cleanups] doassert => doAssert; mark deadcode (#14711) --- compiler/semtypinst.nim | 22 ++++++++++++---------- tests/casestmt/tcasestmt.nim | 12 ++++++------ tests/stdlib/thtmlparser.nim | 12 ++++++------ tests/stdlib/tstrformat.nim | 4 ++-- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 15a63e75e..22f0d1db6 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -110,7 +110,7 @@ proc lookup(typeMap: LayeredIdTable, key: PType): PType = template put(typeMap: LayeredIdTable, key, value: PType) = idTablePut(typeMap.topLayer, key, value) -template checkMetaInvariants(cl: TReplTypeVars, t: PType) = +template checkMetaInvariants(cl: TReplTypeVars, t: PType) = # noop code when false: if t != nil and tfHasMeta in t.flags and cl.allowMetaTypes == false: @@ -412,7 +412,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = newbody.attachedOps[attachedDeepCopy] = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, attachedDeepCopy, 1) if newbody.typeInst == nil: - #doassert newbody.typeInst == nil + # doAssert newbody.typeInst == nil newbody.typeInst = result if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst: # can come here for tyGenericInst too, see tests/metatype/ttypeor.nim @@ -670,14 +670,16 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode; result = replaceTypeVarsN(cl, n) popInfoContext(p.config) -proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode; - original, new: PSym): PNode = - var typeMap = initLayeredTypeMap(pt) - var cl = initTypeVars(p, typeMap, n.info, original) - idTablePut(cl.symMap, original, new) - pushInfoContext(p.config, n.info) - result = replaceTypeVarsN(cl, n) - popInfoContext(p.config) +when false: + # deadcode + proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode; + original, new: PSym): PNode = + var typeMap = initLayeredTypeMap(pt) + var cl = initTypeVars(p, typeMap, n.info, original) + idTablePut(cl.symMap, original, new) + pushInfoContext(p.config, n.info) + result = replaceTypeVarsN(cl, n) + popInfoContext(p.config) proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) = if t != nil and t.len > 0 and t[0] != nil: diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 6abea53bc..53cccdb64 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -184,33 +184,33 @@ block tcasestm: doAssert(bstatic == false) var bb: bool - doassert(not compiles( + doAssert(not compiles( bb = case str2: of "": raise newException(ValueError, "Invalid boolean") elif str.startsWith("Y"): true elif str.startsWith("N"): false )) - doassert(not compiles( + doAssert(not compiles( bb = case str2: of "Y": true of "N": false )) - doassert(not compiles( + doAssert(not compiles( bb = case str2: of "Y": true of "N": raise newException(ValueError, "N not allowed") )) - doassert(not compiles( + doAssert(not compiles( bb = case str2: of "Y": raise newException(ValueError, "Invalid Y") else: raise newException(ValueError, "Invalid N") )) - doassert(not compiles( + doAssert(not compiles( bb = case str2: of "Y": raise newException(ValueError, "Invalid Y") @@ -219,7 +219,7 @@ block tcasestm: )) - doassert(not compiles( + doAssert(not compiles( bb = case str2: of "Y": "invalid Y".quit(3) diff --git a/tests/stdlib/thtmlparser.nim b/tests/stdlib/thtmlparser.nim index e7dcd50d5..2ac7b4004 100644 --- a/tests/stdlib/thtmlparser.nim +++ b/tests/stdlib/thtmlparser.nim @@ -110,21 +110,21 @@ block t6154: doAssert ps[0].attrsLen == 2 doAssert ps[0].attr("class") == "foo" doAssert ps[0].attr("id") == "bar" - doassert ps[0].len == 0 + doAssert ps[0].len == 0 doAssert ps[1].attrsLen == 1 doAssert ps[1].attr("something") == "\tfoo\tbar²" - doassert ps[1].len == 0 + doAssert ps[1].len == 0 doAssert ps[2].attrsLen == 2 doAssert ps[2].attr("something") == "\tfoo\tbar²" doAssert ps[2].attr("foo") == "bloo" - doassert ps[2].len == 0 + doAssert ps[2].len == 0 doAssert ps[3].attrsLen == 2 doAssert ps[3].attr("class") == "foo2" doAssert ps[3].attr("id") == "bar2" - doassert ps[3].len == 0 + doAssert ps[3].len == 0 doAssert ps[4].attrsLen == 1 doAssert ps[4].attr("wrong") == "" @@ -133,12 +133,12 @@ block t6154: doAssert ps[5].attr("data-foo") == "" doAssert ps[5].attr("data-bar") == "correct!" doAssert ps[5].attr("enabled") == "" - doassert ps[5].len == 0 + doAssert ps[5].len == 0 doAssert ps[6].attrsLen == 2 doAssert ps[6].attr("quux") == "" doAssert ps[6].attr("whatever") == "" - doassert ps[6].len == 0 + doAssert ps[6].len == 0 # bug #11713, #1034 var content = """ diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 7db001979..22c0cf95d 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -65,8 +65,8 @@ doAssert fmt"{1.5: 08}" == " 00001.5" # works # only add explicitly requested sign if value != -0.0 (neg zero) doAssert fmt"{-0.0:g}" == "-0" -doassert fmt"{-0.0:+g}" == "-0" -doassert fmt"{-0.0: g}" == "-0" +doAssert fmt"{-0.0:+g}" == "-0" +doAssert fmt"{-0.0: g}" == "-0" doAssert fmt"{0.0:g}" == "0" doAssert fmt"{0.0:+g}" == "+0" doAssert fmt"{0.0: g}" == " 0" From bb62feff72a911ca9a314eba6409a6f4f786b568 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 17 Jun 2020 23:47:16 -0700 Subject: [PATCH 0725/4254] fix #14691 docgen works again for methods (#14701) * fix #14691 docgen methods * fixup --- compiler/docgen.nim | 19 ++----- nimdoc/testproject/expected/testproject.html | 58 ++++++++++++++++++++ nimdoc/testproject/expected/testproject.idx | 5 ++ nimdoc/testproject/expected/theindex.html | 20 +++++++ nimdoc/testproject/testproject.nim | 22 ++++++++ 5 files changed, 110 insertions(+), 14 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 0af830a42..a973bdfc1 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -609,21 +609,12 @@ proc getRoutineBody(n: PNode): PNode = so we normalize the results to get to the statement list containing the (0 or more) doc comments and runnableExamples. - (even if using `result = n[bodyPos]`, you'd still to apply similar logic). ]## - result = n[^1] - case result.kind - of nkSym: - result = n[^2] - case result.kind - of nkAsgn: - doAssert result[0].kind == nkSym - doAssert result.len == 2 - result = result[1] - else: # eg: nkStmtList - discard - else: - discard + result = n[bodyPos] + if result.kind == nkAsgn and n.len > bodyPos+1 and n[bodyPos+1].kind == nkSym: + doAssert result[0].kind == nkSym + doAssert result.len == 2 + result = result[1] proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var Rope) = var n = n diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 7bd2e64a3..a4f8876fd 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -211,11 +211,27 @@ function main() { +
  • + Methods + +
  • Iterators
  • @@ -653,6 +669,32 @@ My someFunc. Stuff in quotes +
    +
    +

    Methods

    +
    + +
    method method1(self: Moo) {...}{.raises: [], tags: [].}
    +
    + +foo1 + +
    + +
    method method2(self: Moo): int {...}{.raises: [], tags: [].}
    +
    + +foo2 + +
    + +
    method method3(self: Moo): int {...}{.raises: [], tags: [].}
    +
    + +foo3 + +
    +

    Iterators

    @@ -667,6 +709,22 @@ My someFunc. Stuff in quotesassert 1 == 1 # ok2
    + + +
    iterator iter1(n: int): int {...}{.raises: [], tags: [].}
    +
    + +foo1 + +
    + +
    iterator iter2(n: int): int {...}{.raises: [], tags: [].}
    +
    + +foo2 +

    Example:

    +
    discard # bar
    +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 46798f314..6d0bc6c5e 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -38,6 +38,11 @@ c_nonexistant testproject.html#c_nonexistant,cstring testproject: c_nonexistant( low testproject.html#low,T testproject: low[T: Ordinal | enum | range](x: T): T low2 testproject.html#low2,T testproject: low2[T: Ordinal | enum | range](x: T): T tripleStrLitTest testproject.html#tripleStrLitTest testproject: tripleStrLitTest() +method1 testproject.html#method1.e,Moo testproject: method1(self: Moo) +method2 testproject.html#method2.e,Moo testproject: method2(self: Moo): int +method3 testproject.html#method3.e,Moo testproject: method3(self: Moo): int +iter1 testproject.html#iter1.i,int testproject: iter1(n: int): int +iter2 testproject.html#iter2.i,int testproject: iter2(n: int): int bar testproject.html#bar.m testproject: bar(): untyped z16 testproject.html#z16.m testproject: z16() z18 testproject.html#z18.m testproject: z18(): int diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 14d07bfd9..8d34506a6 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -181,6 +181,14 @@ function main() {
  • testproject: isValid[T](x: T): bool
  • +
    iter1:
    +
    iter2:
    low:
    +
    method1:
    +
    method2:
    +
    method3:
    myfn:
    • testproject: myfn()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index b05754d51..5282c6f77 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -247,6 +247,28 @@ at indent 0 # should be in # should be out +when true: # methods; issue #14691 + type Moo = object + method method1*(self: Moo) = + ## foo1 + method method2*(self: Moo): int = + ## foo2 + result = 1 + method method3*(self: Moo): int = + ## foo3 + 1 + +when true: # iterators + iterator iter1*(n: int): int = + ## foo1 + for i in 0.. Date: Thu, 18 Jun 2020 20:48:55 +0200 Subject: [PATCH 0726/4254] make nim-gdb compatible with BSD systems (#14700) --- bin/nim-gdb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bin/nim-gdb b/bin/nim-gdb index b9956073b..1486b6dce 100755 --- a/bin/nim-gdb +++ b/bin/nim-gdb @@ -5,17 +5,15 @@ set -e which nim > /dev/null || (echo "nim not in PATH"; exit 1) which gdb > /dev/null || (echo "gdb not in PATH"; exit 1) +which readlink > /dev/null || (echo "readlink not in PATH."; exit 1) -if [[ "$(uname -s)" == "Darwin" ]]; then - which greadlink > /dev/null || (echo "readlink not in PATH. Please install coreutils from homebrew."; exit 1) - READLINK=greadlink +if [[ "$(uname -s)" == "Darwin" || "(uname -s)" == *"BSD" ]]; then + NIM_SYSROOT=$(dirname $(dirname $($READLINK -f $(which nim)))) else - which readlink > /dev/null || (echo "readlink not in PATH."; exit 1) - READLINK=readlink + NIM_SYSROOT=$(dirname $(dirname $($READLINK -e $(which nim)))) fi # Find out where the pretty printer Python module is -NIM_SYSROOT=$(dirname $(dirname $($READLINK -e $(which nim)))) GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py" # Run GDB with the additional arguments that load the pretty printers From 408518c9fed9757fd1cc246e3ced05ecbb3bcaab Mon Sep 17 00:00:00 2001 From: solo989 Date: Tue, 16 Jun 2020 13:35:41 -0700 Subject: [PATCH 0727/4254] Update tuple newLit --- lib/core/macros.nim | 17 ++++++++++++----- tests/macros/tmacros_various.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 856c4f2c1..04a85d355 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -760,7 +760,7 @@ proc newLit*(arg: enum): NimNode {.compileTime.} = proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} proc newLit*[T](s: set[T]): NimNode {.compileTime.} -proc newLit*(arg: tuple): NimNode {.compileTime.} +proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} proc newLit*(arg: object): NimNode {.compileTime.} = result = nnkObjConstr.newTree(arg.type.getTypeInst[1]) @@ -800,10 +800,17 @@ proc newLit*[T](s: set[T]): NimNode {.compileTime.} = var typ = getTypeInst(typeof(s))[1] result = newCall(typ,result) -proc newLit*(arg: tuple): NimNode {.compileTime.} = - result = nnkPar.newTree - for a,b in arg.fieldPairs: - result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b)) +proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} + ## See typetraits.isNamedTuple + +proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} = + result = nnkTupleConstr.newTree + when isNamedTuple(T): + for a,b in arg.fieldPairs: + result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b)) + else: + for b in arg.fields: + result.add newLit(b) proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} = ## Nests the list `pack` into a tree of call expressions: diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 3991a5e30..695353b0c 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -194,3 +194,35 @@ static: doAssert(v == a) echo "macrocache ok" + +block tupleNewLitTests: + macro t0(): untyped = + result = newLit(()) + doAssert t0 == () + macro t1(): untyped = + result = newLit((5,)) + doAssert t1 == (5,) + macro t2(): untyped = + result = newLit((a: 5)) + doAssert t2 == (a: 5) + macro t3(): untyped = + result = newLit((5, "5")) + doAssert t3 == (5, "5") + macro t4(): untyped = + result = newLit((a: 5, b: "5")) + doAssert t4 == (a: 5, b: "5") + macro t5(): untyped = + result = newLit(@[(5,)]) + doAssert t5 == @[(5,)] + macro t6(): untyped = + result = newLit(@[(a: 5)]) + doAssert t6 == @[(a: 5)] + macro t7(): untyped = + result = newLit(@[(5, "5")]) + doAssert t7 == @[(5, "5")] + macro t8(): untyped = + result = newLit(@[(a: 5, b: "5")]) + doAssert t8 == @[(a: 5, b: "5")] + macro t9(): untyped = + result = newLit(@[(a: (5, 6), b: ())]) + doAssert t9 == @[(a: (5, 6), b: ())] From 9c42ae91b735bda29de9afbc1333da52a85b3297 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 18 Jun 2020 13:36:45 -0700 Subject: [PATCH 0728/4254] add legacy workaround; improve test so that it actually tests for the bugfix --- changelog.md | 1 + lib/core/macros.nim | 8 ++++--- testament/important_packages.nim | 2 +- tests/macros/tmacros_various.nim | 38 ++++++-------------------------- 4 files changed, 14 insertions(+), 35 deletions(-) diff --git a/changelog.md b/changelog.md index 588af989b..3f3a2f9b2 100644 --- a/changelog.md +++ b/changelog.md @@ -112,6 +112,7 @@ - new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. - Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` with `outLatex` output. - Add `os.normalizeExe`, eg: `koch` => `./koch`. +- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior ## Language changes diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 04a85d355..1b0986d33 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -801,12 +801,14 @@ proc newLit*[T](s: set[T]): NimNode {.compileTime.} = result = newCall(typ,result) proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} - ## See typetraits.isNamedTuple + ## See `typetraits.isNamedTuple` proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} = + ## use -d:nimHasWorkaround14720 to restore behavior prior to PR, forcing + ## a named tuple even when `arg` is unnamed. result = nnkTupleConstr.newTree - when isNamedTuple(T): - for a,b in arg.fieldPairs: + when defined(nimHasWorkaround14720) or isNamedTuple(T): + for a, b in arg.fieldPairs: result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b)) else: for b in arg.fields: diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 6da644ce3..0a64f6c33 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -43,7 +43,7 @@ pkg1 "elvis" # Error: cannot open 'tests/runNative.nim' pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" -pkg1 "ggplotnim", true, "nim c -d:noCairo -r -d:nimWorkaround14447 tests/tests.nim" +pkg1 "ggplotnim", true, "nim c -d:noCairo -r -d:nimWorkaround14447 -d:nimHasWorkaround14720 tests/tests.nim" # pkg1 "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" pkg1 "glob" pkg1 "gnuplot" diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 695353b0c..533db25e1 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -194,35 +194,11 @@ static: doAssert(v == a) echo "macrocache ok" - + block tupleNewLitTests: - macro t0(): untyped = - result = newLit(()) - doAssert t0 == () - macro t1(): untyped = - result = newLit((5,)) - doAssert t1 == (5,) - macro t2(): untyped = - result = newLit((a: 5)) - doAssert t2 == (a: 5) - macro t3(): untyped = - result = newLit((5, "5")) - doAssert t3 == (5, "5") - macro t4(): untyped = - result = newLit((a: 5, b: "5")) - doAssert t4 == (a: 5, b: "5") - macro t5(): untyped = - result = newLit(@[(5,)]) - doAssert t5 == @[(5,)] - macro t6(): untyped = - result = newLit(@[(a: 5)]) - doAssert t6 == @[(a: 5)] - macro t7(): untyped = - result = newLit(@[(5, "5")]) - doAssert t7 == @[(5, "5")] - macro t8(): untyped = - result = newLit(@[(a: 5, b: "5")]) - doAssert t8 == @[(a: 5, b: "5")] - macro t9(): untyped = - result = newLit(@[(a: (5, 6), b: ())]) - doAssert t9 == @[(a: (5, 6), b: ())] + macro t(): untyped = + result = newLit (1, "foo", (), (1,), (a1: 'x', a2: @["ba"])) + doAssert $t() == """(1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))""" + # this `$` test is needed because tuple equality doesn't distinguish + # between named vs unnamed tuples + doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"])) From 5ad8b9e8ebb2e21e20484afbaffa9450715079cd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 19 Jun 2020 00:53:45 -0700 Subject: [PATCH 0729/4254] fix #14685 tests/async/t7758.nim flaky (#14721) * fix #14685 tests/async/t7758.nim flaky * address comment * address comment --- tests/async/t7758.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim index 3cbe16852..fe6d32ad3 100644 --- a/tests/async/t7758.nim +++ b/tests/async/t7758.nim @@ -2,7 +2,8 @@ import asyncdispatch import std/unittest proc task() {.async.} = - await sleepAsync(40) + const tSleep = 40 + await sleepAsync(tSleep) proc main() = var counter = 0 @@ -11,6 +12,10 @@ proc main() = inc(counter) poll(10) - check counter <= 4 + const slack = 1 + # because there is overhead in `async` + `sleepAsync` + # as can be seen by increasing `tSleep` from 40 to 49, which increases the number + # of failures. + check counter <= 4 + slack for i in 0 .. 10: main() From 522bc8dda1f36ffe5f14eb6b1bfdba215b45b139 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 16 Jun 2020 11:39:58 +0200 Subject: [PATCH 0730/4254] added a space --- compiler/ast.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index bc26defd4..9639f52d3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1294,7 +1294,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = of tyUInt16: result = newNode(nkUInt16Lit) of tyUInt32: result = newNode(nkUInt32Lit) of tyUInt64: result = newNode(nkUInt64Lit) - of tyBool,tyEnum: + of tyBool, tyEnum: # XXX: does this really need to be the kind nkIntLit? result = newNode(nkIntLit) of tyStatic: # that's a pre-existing bug, will fix in another PR From 45bc6954c510fa9ca742cb333ce88d9625ad1e29 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 19 Jun 2020 10:50:39 +0200 Subject: [PATCH 0731/4254] improve the parser's error message --- compiler/parser.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 8f7eb1226..868054f36 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -2285,7 +2285,7 @@ proc parseStmt(p: var TParser): PNode = case p.tok.tokType of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc, tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar: - parMessage(p, "complex statement requires indentation") + parMessage(p, "nestable statement requires indentation") result = p.emptyNode else: if p.inSemiStmtList > 0: From 45d1e55e72aea9acfcf1a6fb7061779a243d7921 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 19 Jun 2020 14:56:38 +0200 Subject: [PATCH 0732/4254] Add testcases for #11811 and #14315 (#14726) * Add testcase for #11811 * Add testcase for #14315 --- tests/bind/tbind.nim | 11 +++++++++++ tests/destructor/tdestructor.nim | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/bind/tbind.nim b/tests/bind/tbind.nim index 49c37ae2e..f3fb952e3 100644 --- a/tests/bind/tbind.nim +++ b/tests/bind/tbind.nim @@ -4,6 +4,7 @@ output: ''' 1 1 1 +5 ''' """ @@ -65,3 +66,13 @@ block tmixin: Foo(a) Foo(b) + +# issue #11811 +proc p(a : int) = + echo a + +proc printVar*[T:int|float|string](a : T) = + bind p + p(a) + +printVar(5) diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index b6d60323c..9fd47fe00 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -154,4 +154,14 @@ proc caseobj_test_sink: TCaseObj = echo "---" -discard caseobj_test_sink() \ No newline at end of file +discard caseobj_test_sink() + +# issue #14315 + +type Vector*[T] = object + x1: int + # x2: T # uncomment will remove error + +# proc `=destroy`*(x: var Vector[int]) = discard # this will remove error +proc `=destroy`*[T](x: var Vector[T]) = discard +var a: Vector[int] # Error: unresolved generic parameter From 65c7884a3c84d7e1750cf630940b089ed204bc1a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 19 Jun 2020 09:51:25 +0200 Subject: [PATCH 0733/4254] fixes #14718 [backport] --- lib/pure/pegs.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 4f723b4af..946891420 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -907,16 +907,16 @@ macro mkHandlerTplts(handlers: untyped): untyped = result = newStmtList() for topCall in handlers[0]: - if nnkCall != topCall.kind: + if topCall.kind notin nnkCallKinds: error("Call syntax expected.", topCall) let pegKind = topCall[0] - if nnkIdent != pegKind.kind: + if pegKind.kind notin {nnkIdent, nnkSym}: error("PegKind expected.", pegKind) if 2 == topCall.len: for hdDef in topCall[1]: - if nnkCall != hdDef.kind: + if hdDef.kind notin nnkCallKinds: error("Call syntax expected.", hdDef) - if nnkIdent != hdDef[0].kind: + if hdDef[0].kind notin {nnkIdent, nnkSym}: error("Handler identifier expected.", hdDef[0]) if 2 == hdDef.len: let hdPostf = substr(pegKind.strVal, 2) From 2039e3e883ac42cd9b6012335a92564ca2b56387 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 19 Jun 2020 06:08:00 -0700 Subject: [PATCH 0734/4254] fix #13899 defer now works with async (#14723) --- lib/pure/asyncmacro.nim | 3 +++ tests/async/tasync_misc.nim | 25 ++++++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index cbed6372c..621a4b00c 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -207,6 +207,9 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = futureVarIdents) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: + # fix #13899, defer should not escape its original scope + procBody = newStmtList(newTree(nnkBlockStmt, newEmptyNode(), procBody)) + procBody.add(createFutureVarCompletions(futureVarIdents, nil)) if not subtypeIsVoid: diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index c5ee22a42..29e6faa72 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -1,8 +1,3 @@ -discard """ - exitcode: 0 - output: "ok" -""" - import json, asyncdispatch block: #6100 let done = newFuture[int]() @@ -61,5 +56,21 @@ block: # 12743 waitFor prc() - -echo "ok" +block: # issue #13899 + proc someConnect() {.async.} = + await sleepAsync(1) + proc someClose() {.async.} = + await sleepAsync(2) + proc testFooFails(): Future[bool] {.async.} = + await someConnect() + defer: + await someClose() + result = true + proc testFooSucceed(): Future[bool] {.async.} = + try: + await someConnect() + finally: + await someClose() + result = true + doAssert waitFor testFooSucceed() + doAssert waitFor testFooFails() From 99c198625c602984578f9c53b05a28c54de4f4cb Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 19 Jun 2020 10:08:45 -0300 Subject: [PATCH 0735/4254] Deprecate unroll pragma, remove from documentation (#14705) --- changelog.md | 2 ++ doc/manual.rst | 19 ------------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/changelog.md b/changelog.md index 3f3a2f9b2..9ab6ebfda 100644 --- a/changelog.md +++ b/changelog.md @@ -176,6 +176,8 @@ proc mydiv(a, b): int {.raises: [].} = with `--panics:on` `Defects` become unrecoverable errors. - Added `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose +- Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. + ## Compiler changes diff --git a/doc/manual.rst b/doc/manual.rst index 75cc507a4..a7bca7616 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6210,25 +6210,6 @@ the underlying backend (C compiler) does not support the computed goto extension the pragma is simply ignored. -unroll pragma -------------- -The ``unroll`` pragma can be used to tell the compiler that it should unroll -a `for`:idx: or `while`:idx: loop for execution efficiency: - -.. code-block:: nim - proc searchChar(s: string, c: char): int = - for i in 0 .. s.high: - {.unroll: 4.} - if s[i] == c: return i - result = -1 - -In the above example, the search loop is unrolled by a factor 4. The unroll -factor can be left out too; the compiler then chooses an appropriate unroll -factor. - -**Note**: Currently the compiler recognizes but ignores this pragma. - - immediate pragma ---------------- From ac8ab4c54967a83d800655d9de42ece7d5e21c93 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Fri, 19 Jun 2020 10:22:48 -0400 Subject: [PATCH 0736/4254] Clarify the use of the backwards index operator (^N) in tut1 (#14681) * Clarify the use of the backwards index operator (^N) in tut1 For consistency: - Do `[a .. ^b]` (notice spaces on both sides of `..`) - Do `[c ..< d]` (notice spaces on both sides of `..<`) Fixes https://github.com/nim-lang/Nim/issues/14671. * tut1: Add a note that ^ template calls can be saved to consts --- doc/tut1.rst | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 6d54d88a3..24874096c 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -395,20 +395,29 @@ Since counting up occurs so often in programs, Nim also has a `.. `_ iterator that does the same: .. code-block:: nim - for i in 1..10: + for i in 1 .. 10: ... -Zero-indexed counting have two shortcuts ``..<`` and ``..^`` to simplify counting to one less than the higher index: +Zero-indexed counting has two shortcuts ``..<`` and ``.. ^1`` +(`backwards index operator `_) to simplify +counting to one less than the higher index: .. code-block:: nim - for i in 0..<10: - ... # 0..9 + for i in 0 ..< 10: + ... # 0 .. 9 or .. code-block:: nim var s = "some string" - for i in 0.. 'a prog' - b[11..^2] = "useful" + echo a[7 .. 12] # --> 'a prog' + b[11 .. ^2] = "useful" echo b # --> 'Slices are useful.' In the previous example slices are used to modify a part of a string. The @@ -1425,17 +1434,22 @@ indices are 0 11 17 using indices ^19 ^8 ^2 using ^ syntax -where ``b[0..^1]`` is equivalent to ``b[0..b.len-1]`` and ``b[0..`_. In the above example, because the string ends in a period, to get the portion of the string that is "useless" and replace it with "useful". -``b[11..^2]`` is the portion "useless", and ``b[11..^2] = "useful"`` replaces the +``b[11 .. ^2]`` is the portion "useless", and ``b[11 .. ^2] = "useful"`` replaces the "useless" portion with "useful", giving the result "Slices are useful." -Note: alternate ways of writing this are ``b[^8..^2] = "useful"`` or -as ``b[11..b.len-2] = "useful"`` or as ``b[11..`_ +of type ``BackwardsIndex``, we can have a ``lastIndex`` constant defined as ``const lastIndex = ^1``, +and later used as ``b[0 .. lastIndex]``. Objects ------- From 79c90b30ee5590b02f8bcfac68ed0c9ef7b38e7d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 19 Jun 2020 14:38:43 -0700 Subject: [PATCH 0737/4254] nep1: use subjectVerb, not verbSuject (#14732) --- doc/nep1.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/nep1.rst b/doc/nep1.rst index 1ef8c3c24..35b1a1f62 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -101,11 +101,13 @@ changed in the future. fd: int64 HandleRef = ref Handle # Will be used less often -- Exception and Error types should have the "Error" suffix. +- Exception and Error types should have the "Error" or "Defect" suffix. .. code-block:: nim type - UnluckyError = object of Exception + ValueError = object of CatchableError + AssertionDefect = object of Defect + Foo = object of Exception # bad style, try to inherit CatchableError or Defect - Unless marked with the `{.pure.}` pragma, members of enums should have an identifying prefix, such as an abbreviation of the enum's name. @@ -147,6 +149,8 @@ changed in the future. an in-place version should get an ``-In`` suffix (``replaceIn`` for this example). +- Use `subjectVerb`, not `verbSubject`, eg: `fileExists`, not `existsFile`. + The stdlib API is designed to be **easy to use** and consistent. Ease of use is measured by the number of calls to achieve a concrete high level action. The ultimate goal is that the programmer can *guess* a name. From ca71a60ff6a86244eddee28d175e9c546fe2bfc7 Mon Sep 17 00:00:00 2001 From: treeform Date: Sun, 21 Jun 2020 10:25:29 -0700 Subject: [PATCH 0738/4254] Add css white-space property to dom.nim. (#14743) https://developer.mozilla.org/en-US/docs/Web/CSS/white-space --- lib/js/dom.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 65f9a946b..38ec18a61 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -463,6 +463,7 @@ type verticalAlign*: cstring visibility*: cstring width*: cstring + whiteSpace*: cstring wordSpacing*: cstring zIndex*: int From c7dee55b87fe0f35a411b4ec48f833be5537a231 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 21 Jun 2020 17:28:03 +0000 Subject: [PATCH 0739/4254] encodings: use only one iconv definition [backport:1.2] (#14741) Fix an issue reported on IRC: using encodings with --dynlibOverrideAll result in duplicated iconv definitions, causing compile errors. This commit remove the `var` wrapper of iconv and go all out on pointers, as it should due to how the API accepts nil. Also corrected the API to resemble iconv(3p). --- lib/pure/encodings.nim | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index ff9c3889a..1d8512018 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -290,11 +290,8 @@ else: importc: "iconv_open", importIconv.} proc iconvClose(c: EncodingConverter) {. importc: "iconv_close", importIconv.} - proc iconv(c: EncodingConverter, inbuf: var cstring, inbytesLeft: var int, - outbuf: var cstring, outbytesLeft: var int): int {. - importc: "iconv", importIconv.} - proc iconv(c: EncodingConverter, inbuf: pointer, inbytesLeft: pointer, - outbuf: var cstring, outbytesLeft: var int): int {. + proc iconv(c: EncodingConverter, inbuf: ptr cstring, inbytesLeft: ptr csize_t, + outbuf: ptr cstring, outbytesLeft: ptr csize_t): csize_t {. importc: "iconv", importIconv.} proc getCurrentEncoding*(uiApp = false): string = @@ -428,14 +425,14 @@ when defined(windows): else: proc convert*(c: EncodingConverter, s: string): string = result = newString(s.len) - var inLen = len(s) - var outLen = len(result) + var inLen = csize_t len(s) + var outLen = csize_t len(result) var src = cstring(s) var dst = cstring(result) - var iconvres: int + var iconvres: csize_t while inLen > 0: - iconvres = iconv(c, src, inLen, dst, outLen) - if iconvres == -1: + iconvres = iconv(c, addr src, addr inLen, addr dst, addr outLen) + if iconvres == high(csize_t): var lerr = errno if lerr == EILSEQ or lerr == EINVAL: # unknown char, skip @@ -446,24 +443,24 @@ else: dec(outLen) elif lerr == E2BIG: var offset = cast[int](dst) - cast[int](cstring(result)) - setLen(result, len(result)+inLen*2+5) + setLen(result, len(result) + inLen.int * 2 + 5) # 5 is minimally one utf-8 char dst = cast[cstring](cast[int](cstring(result)) + offset) - outLen = len(result) - offset + outLen = csize_t(len(result) - offset) else: raiseOSError(lerr.OSErrorCode) # iconv has a buffer that needs flushing, specially if the last char is # not '\0' - discard iconv(c, nil, nil, dst, outLen) - if iconvres == cint(-1) and errno == E2BIG: + discard iconv(c, nil, nil, addr dst, addr outLen) + if iconvres == high(csize_t) and errno == E2BIG: var offset = cast[int](dst) - cast[int](cstring(result)) - setLen(result, len(result)+inLen*2+5) + setLen(result, len(result) + inLen.int * 2 + 5) # 5 is minimally one utf-8 char dst = cast[cstring](cast[int](cstring(result)) + offset) - outLen = len(result) - offset - discard iconv(c, nil, nil, dst, outLen) + outLen = csize_t(len(result) - offset) + discard iconv(c, nil, nil, addr dst, addr outLen) # trim output buffer - setLen(result, len(result) - outLen) + setLen(result, len(result) - outLen.int) proc convert*(s: string, destEncoding = "UTF-8", srcEncoding = "CP1252"): string = From 3ba0c30758e1044aba11bb908a7d83de7ea215bc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 21 Jun 2020 19:58:37 +0200 Subject: [PATCH 0740/4254] sizeof for empty objects/tuples should be 1; fixes #14690 (#14751) --- compiler/sizealignoffsetimpl.nim | 4 ++-- tests/misc/tsizeof.nim | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 9d12297ea..4d73923db 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -330,7 +330,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = sym.offset = accum.offset accum.inc(int(child.size)) typ.paddingAtEnd = int16(accum.finish()) - typ.size = accum.offset + typ.size = if accum.offset == 0: 1 else: accum.offset typ.align = int16(accum.maxAlign) except IllegalTypeRecursionError: typ.paddingAtEnd = szIllegalRecursion @@ -388,7 +388,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.align = szUnknownSize typ.paddingAtEnd = szUnknownSize else: - typ.size = accum.offset + typ.size = if accum.offset == 0: 1 else: accum.offset typ.align = int16(accum.maxAlign) typ.paddingAtEnd = paddingAtEnd except IllegalTypeRecursionError: diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 7b92d3639..579532fcc 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -78,7 +78,7 @@ macro c_offsetof(fieldAccess: typed): int32 = ## Bullet proof implementation that works on actual offsetof operator ## in the c backend. Assuming of course this implementation is ## correct. - let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] + let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] else: fieldAccess let a = s[0].getTypeInst let b = s[1] @@ -686,3 +686,11 @@ reject: reject: const off8 = offsetof(MyPackedCaseObject, val5) + + +type + O0 = object + T0 = tuple[] + +doAssert sizeof(O0) == 1 +doAssert sizeof(T0) == 1 From 1ffe1134501210e23e71e0f23099c2005edd98c9 Mon Sep 17 00:00:00 2001 From: treeform Date: Sun, 21 Jun 2020 11:41:24 -0700 Subject: [PATCH 0741/4254] Export fields from the Selection object. (#14752) See: https://developer.mozilla.org/en-US/docs/Web/API/Selection --- lib/js/dom.nim | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 38ec18a61..48d32fc18 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -107,6 +107,13 @@ type timing*: PerformanceTiming Selection* {.importc.} = ref object ## see `docs`_ + anchorNode*: Node + anchorOffset*: int + focusNode*: Node + focusOffset*: int + isCollapsed*: bool + rangeCount*: int + `type`*: cstring LocalStorage* {.importc.} = ref object From 1e484ed62b499432883575e6b29c930874377d7a Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 22 Jun 2020 08:12:50 +0200 Subject: [PATCH 0742/4254] [backport] Docs: Fix broken `code-block` (#14749) This commit indents the contents of a `code-block` in `httpclient.nim` so that it displays correctly. The bug was introduced by 42a64245f8. I did a quick search for other `code-block`s that are broken in the same way, but the only other one I found (in `pegs.nim`) is not included in the generated documentation. --- lib/pure/httpclient.nim | 10 +++++----- lib/pure/pegs.nim | 40 ++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index dfd4abea5..92e4cd2d6 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -25,13 +25,13 @@ ## ``AsyncHttpClient``: ## ## .. code-block:: Nim -## import asyncdispatch, httpclient +## import asyncdispatch, httpclient ## -## proc asyncProc(): Future[string] {.async.} = -## var client = newAsyncHttpClient() -## return await client.getContent("http://example.com") +## proc asyncProc(): Future[string] {.async.} = +## var client = newAsyncHttpClient() +## return await client.getContent("http://example.com") ## -## echo waitFor asyncProc() +## echo waitFor asyncProc() ## ## The functionality implemented by ``HttpClient`` and ``AsyncHttpClient`` ## is the same, so you can use whichever one suits you best in the examples diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 946891420..8abd3deb5 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -870,26 +870,26 @@ macro mkHandlerTplts(handlers: untyped): untyped = # The AST structure of *handlers[0]*: # # .. code-block:: - # StmtList - # Call - # Ident "pkNonTerminal" - # StmtList - # Call - # Ident "enter" - # StmtList - # - # Call - # Ident "leave" - # StmtList - # - # Call - # Ident "pkChar" - # StmtList - # Call - # Ident "leave" - # StmtList - # - # ... + # StmtList + # Call + # Ident "pkNonTerminal" + # StmtList + # Call + # Ident "enter" + # StmtList + # + # Call + # Ident "leave" + # StmtList + # + # Call + # Ident "pkChar" + # StmtList + # Call + # Ident "leave" + # StmtList + # + # ... proc mkEnter(hdName, body: NimNode): NimNode = template helper(hdName, body) {.dirty.} = template hdName(s, p, start) = From c8554ebc0c0c67b4f691a760b5e844f974e92ddc Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 22 Jun 2020 07:23:24 +0000 Subject: [PATCH 0743/4254] posix_other: add define to force time_t to 64 bit [backport] (#14753) This is a temporary remedy for time_t transition to 64 bit on newer Linux libc (musl >= 1.2.0, glibc >= 2.32). In the future we might want to move away from libc, or figure out a way to reliably detect the real size of C types at compile time, both of which are difficult. --- lib/posix/posix_other.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 919d564d3..59ae9c8f7 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -32,7 +32,12 @@ type SocketHandle* = distinct cint # The type used to represent socket descriptors type - Time* {.importc: "time_t", header: "".} = distinct clong + Time* {.importc: "time_t", header: "".} = distinct ( + when defined(nimUse64BitCTime): + int64 + else: + clong + ) Timespec* {.importc: "struct timespec", header: "", final, pure.} = object ## struct timespec From 8df20276c9e7f714aacfad7b20f9308233f6bfdd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 22 Jun 2020 13:06:22 +0200 Subject: [PATCH 0744/4254] fixes #14458 [backport:1.2] (#14756) --- compiler/cgen.nim | 9 ++++++--- compiler/pragmas.nim | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 338b337f2..417acf178 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -975,6 +975,9 @@ proc genProcBody(p: BProc; procBody: PNode) = p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", [])) p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", [])) +proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = + sfNoReturn in s.flags and m.config.exc != excGoto + proc genProcAux(m: BModule, prc: PSym) = var p = newProc(prc, m) var header = genProcHeader(m, prc) @@ -1029,7 +1032,7 @@ proc genProcAux(m: BModule, prc: PSym) = var generatedProc: Rope generatedProc.genCLineDir prc.info, m.config - if sfNoReturn in prc.flags: + if isNoReturn(p.module, prc): if hasDeclspec in extccomp.CC[p.config.cCompiler].props: header = "__declspec(noreturn) " & header if sfPure in prc.flags: @@ -1092,13 +1095,13 @@ proc genProcPrototype(m: BModule, sym: PSym) = let asPtr = isReloadable(m, sym) var header = genProcHeader(m, sym, asPtr) if not asPtr: - if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props: + if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props: header = "__declspec(noreturn) " & header if sym.typ.callConv != ccInline and requiresExternC(m, sym): header = "extern \"C\" " & header if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props: header.add(" __attribute__((naked))") - if sfNoReturn in sym.flags and hasAttribute in CC[m.config.cCompiler].props: + if isNoReturn(m, sym) and hasAttribute in CC[m.config.cCompiler].props: header.add(" __attribute__((noreturn))") m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header])) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 021a8b339..c9fe3a5e1 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -904,7 +904,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wNoreturn: noVal(c, it) # Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode! - if c.config.exc notin {excQuirky, excGoto}: + if c.config.exc != excQuirky: incl(sym.flags, sfNoReturn) if sym.typ[0] != nil: localError(c.config, sym.ast[paramsPos][0].info, From 451129de4213805b74b1635565d998904d705458 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 22 Jun 2020 14:11:13 +0200 Subject: [PATCH 0745/4254] fixes #14240 [backport:1.2] (#14757) --- compiler/ccgstmts.nim | 17 +++++++++-------- compiler/cgen.nim | 1 + compiler/cgendata.nim | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index ca6e51f29..82f1caadc 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -688,14 +688,15 @@ proc genBreakStmt(p: BProc, t: PNode) = proc raiseExit(p: BProc) = assert p.config.exc == excGoto - p.flags.incl nimErrorFlagAccessed - if p.nestedTryStmts.len == 0: - p.flags.incl beforeRetNeeded - # easy case, simply goto 'ret': - lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", []) - else: - lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n", - [p.nestedTryStmts[^1].label]) + if nimErrorFlagDisabled notin p.flags: + p.flags.incl nimErrorFlagAccessed + if p.nestedTryStmts.len == 0: + p.flags.incl beforeRetNeeded + # easy case, simply goto 'ret': + lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", []) + else: + lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n", + [p.nestedTryStmts[^1].label]) proc finallyActions(p: BProc) = if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 417acf178..cd02ba9b1 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -682,6 +682,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = else: var p = newProc(nil, m) p.options = p.options - {optStackTrace} + p.flags.incl nimErrorFlagDisabled var dest: TLoc initLoc(dest, locTemp, lib.path, OnStack) dest.r = getTempName(m) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 96e382873..ce74963e2 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -70,7 +70,8 @@ type hasCurFramePointer, noSafePoints, nimErrorFlagAccessed, - nimErrorFlagDeclared + nimErrorFlagDeclared, + nimErrorFlagDisabled TCProc = object # represents C proc that is currently generated prc*: PSym # the Nim proc that this C proc belongs to From 59ba4d8c031ecd145c027c632e443c92b9c3b29d Mon Sep 17 00:00:00 2001 From: b3liever <43617260+b3liever@users.noreply.github.com> Date: Mon, 22 Jun 2020 21:48:33 +0300 Subject: [PATCH 0746/4254] added normal variate function (#14725) * added normal variate function * change method only slightly faster * changelog + since Co-authored-by: b3liever --- changelog.md | 2 +- lib/pure/random.nim | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 9ab6ebfda..151eafcd5 100644 --- a/changelog.md +++ b/changelog.md @@ -113,7 +113,7 @@ - Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` with `outLatex` output. - Add `os.normalizeExe`, eg: `koch` => `./koch`. - `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior - +- Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/random.nim b/lib/pure/random.nim index e794a4dde..7c5d51ceb 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -78,7 +78,8 @@ ## `_ ## in the standard library -import algorithm #For upperBound +import algorithm, math +import std/private/since include "system/inclrtl" {.push debugger: off.} @@ -516,6 +517,33 @@ proc sample*[T, U](a: openArray[T]; cdf: openArray[U]): T = doAssert sample(marbles, cdf) == "blue" state.sample(a, cdf) +proc gauss*(r: var Rand; mu = 0.0; sigma = 1.0): float {.since: (1, 3).} = + ## Returns a Gaussian random variate, + ## with mean ``mu`` and standard deviation ``sigma`` + ## using the given state. + # Ratio of uniforms method for normal + # http://www2.econ.osaka-u.ac.jp/~tanizaki/class/2013/econome3/13.pdf + const K = sqrt(2 / E) + var + a = 0.0 + b = 0.0 + while true: + a = rand(r, 1.0) + b = (2.0 * rand(r, 1.0) - 1.0) * K + if b * b <= -4.0 * a * a * ln(a): break + result = mu + sigma * (b / a) + +proc gauss*(mu = 0.0, sigma = 1.0): float {.since: (1, 3).} = + ## Returns a Gaussian random variate, + ## with mean ``mu`` and standard deviation ``sigma``. + ## + ## If `randomize<#randomize>`_ has not been called, the order of outcomes + ## from this proc will always be the same. + ## + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. + result = gauss(state, mu, sigma) + proc initRand*(seed: int64): Rand = ## Initializes a new `Rand<#Rand>`_ state using the given seed. ## @@ -619,6 +647,8 @@ when not defined(nimscript) and not defined(standalone): {.pop.} when isMainModule: + import stats + proc main = var occur: array[1000, int] @@ -632,6 +662,17 @@ when isMainModule: elif oc > 150: doAssert false, "too many occurrences of " & $i + when false: + var rs: RunningStat + for j in 1..5: + for i in 1 .. 1_000: + rs.push(gauss()) + echo("mean: ", rs.mean, + " stdDev: ", rs.standardDeviation(), + " min: ", rs.min, + " max: ", rs.max) + rs.clear() + var a = [0, 1] shuffle(a) doAssert a[0] == 1 From 03c8bbcc6ed499c9333e1c1e946c403c1f135831 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 22 Jun 2020 22:05:18 +0200 Subject: [PATCH 0747/4254] Remove outdated comment and copy of length (#14759) --- lib/system/iterators.nim | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 5d8685e40..99ad6eef6 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -1,21 +1,12 @@ when defined(nimHasLentIterators) and not defined(nimWorkaround14447): - template lent2(T): untyped = - # xxx this should actually depend on T.sizeof >= thresLentSizeof - # with for example `thresLentSizeof ~= int.sizeof`: - # it may be faster to return by value for small sizes compared to - # forcing a deref; this could be adjusted using profiling. - # However, `simply using `when T.sizeof >= thresLentSizeof: lent T else: T` - # does not work, for a few reasons (eg importc types would cause CT error - # and we can't filter them out without compiles() or some magic. - lent T + template lent2(T): untyped = lent T else: template lent2(T): untyped = T iterator items*[T: not char](a: openArray[T]): lent2 T {.inline.} = ## Iterates over each item of `a`. var i = 0 - let n = len(a) - while i < n: + while i < len(a): yield a[i] inc(i) @@ -25,8 +16,7 @@ iterator items*[T: char](a: openArray[T]): T {.inline.} = # elements converted from a string (would fail in `tests/misc/thallo.nim`) # in any case there's no performance advantage of returning char by address. var i = 0 - let n = len(a) - while i < n: + while i < len(a): yield a[i] inc(i) From 235d8ba069b122f34dee3ab12a34d2fba73326ce Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 22 Jun 2020 18:38:23 -0700 Subject: [PATCH 0748/4254] unbreak CI, refs https://github.com/timotheecour/Nim/issues/167 (#14765) --- testament/important_packages.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 0a64f6c33..8974b78ec 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -92,7 +92,8 @@ pkg2 "nimwc", true, "nim c nimwc.nim" # pkg2 "nimx", true, "nim c --threads:on test/main.nim" # pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" # pending https://github.com/timotheecour/Nim/issues/167 or new git tag for nitter -pkg2 "norm", true, "nim c -r tests/tsqlite.nim" +# pkg2 "norm", true, "nim c -r tests/tsqlite.nim" + # pending https://github.com/timotheecour/Nim/issues/167 pkg2 "npeg", false, "nimble testarc" pkg2 "numericalnim", true, "nim c -r tests/test_integrate.nim" pkg2 "optionsutils" From 511bd947d3a90a5ffedc994a45a36c4eeca63856 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Jun 2020 01:06:36 -0700 Subject: [PATCH 0749/4254] fix bug in semgnrc: runnableExamples should not semcheck, even with > 1 arg (#14768) --- compiler/semgnrc.nim | 2 +- tests/nimdoc/trunnableexamples.nim | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 23b6e9b9d..3366732ca 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -265,7 +265,7 @@ proc semGenericStmt(c: PContext, n: PNode, # We're not interested in the example code during this pass so let's # skip it if s.magic == mRunnableExamples: - inc first + first = result.safeLen # see trunnableexamples.fun3 of skGenericParam: result[0] = newSymNodeTypeDesc(s, fn.info) onUse(fn.info, s) diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim index 73cfacd43..6232011cb 100644 --- a/tests/nimdoc/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -91,6 +91,16 @@ when true: # runnableExamples with rdoccmd proc fun2*() = runnableExamples "-d:foo": discard # checks that it also works inside procs + template fun3Impl(): untyped = + runnableExamples(rdoccmd="-d:foo"): + nonexistant + # bugfix: this shouldn't be semchecked when `runnableExamples` + # has more than 1 argument + discard + + proc fun3*[T]() = + fun3Impl() + when false: # future work # passing non-string-litterals (for reuse) const a = "-b:cpp" From 8e54bc5b0c06dcf2ed0de6b8a10733155e15dc0a Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 23 Jun 2020 05:51:33 -0300 Subject: [PATCH 0750/4254] Deprecate and/or remove ospaths (#14767) --- lib/pure/reservedmem.nim | 2 +- lib/pure/ssl_certs.nim | 2 +- nimpretty/tests/expected/wrong_ind.nim | 2 +- nimpretty/tests/wrong_ind.nim | 2 +- tests/untestable/thttpclient_ssl_disabled.nim | 2 +- tests/untestable/thttpclient_ssl_env_var.nim | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pure/reservedmem.nim b/lib/pure/reservedmem.nim index 85a6e324f..469ca7efa 100644 --- a/lib/pure/reservedmem.nim +++ b/lib/pure/reservedmem.nim @@ -18,7 +18,7 @@ ## ## Unstable API. -from ospaths import raiseOSError, osLastError +from os import raiseOSError, osLastError template distance*(lhs, rhs: pointer): int = cast[int](rhs) - cast[int](lhs) diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index 9845de9b6..806316b02 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -11,7 +11,7 @@ ## SSL_CERT_DIR environment variables. import os, strutils -from ospaths import existsEnv, getEnv +from os import existsEnv, getEnv import strutils # SECURITY: this unnecessarily scans through dirs/files regardless of the diff --git a/nimpretty/tests/expected/wrong_ind.nim b/nimpretty/tests/expected/wrong_ind.nim index 95a35a8fd..3ff9de91c 100644 --- a/nimpretty/tests/expected/wrong_ind.nim +++ b/nimpretty/tests/expected/wrong_ind.nim @@ -2,7 +2,7 @@ # bug #9505 import std/[ - strutils, ospaths, os + strutils, os ] import pkg/[ regex diff --git a/nimpretty/tests/wrong_ind.nim b/nimpretty/tests/wrong_ind.nim index 3c7544cdb..a042e8822 100644 --- a/nimpretty/tests/wrong_ind.nim +++ b/nimpretty/tests/wrong_ind.nim @@ -2,7 +2,7 @@ # bug #9505 import std/[ - strutils, ospaths, os + strutils, os ] import pkg/[ regex diff --git a/tests/untestable/thttpclient_ssl_disabled.nim b/tests/untestable/thttpclient_ssl_disabled.nim index 4d4ede4de..0f7e95831 100644 --- a/tests/untestable/thttpclient_ssl_disabled.nim +++ b/tests/untestable/thttpclient_ssl_disabled.nim @@ -12,7 +12,7 @@ import httpclient, net, unittest, - ospaths + os from strutils import contains diff --git a/tests/untestable/thttpclient_ssl_env_var.nim b/tests/untestable/thttpclient_ssl_env_var.nim index 32af43579..3f25a6ff4 100644 --- a/tests/untestable/thttpclient_ssl_env_var.nim +++ b/tests/untestable/thttpclient_ssl_env_var.nim @@ -13,7 +13,7 @@ ## SSL_CERT_FILE=BogusInexistentFileName tests/untestable/thttpclient_ssl_env_var ## SSL_CERT_DIR=BogusInexistentDirName tests/untestable/thttpclient_ssl_env_var -import httpclient, unittest, ospaths +import httpclient, unittest, os from net import newSocket, newContext, wrapSocket, connect, close, Port, CVerifyPeerUseEnvVars from strutils import contains From a9eee6db65e72e0e11cbf5faf0794b1b6ac8bd0c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Jun 2020 01:53:03 -0700 Subject: [PATCH 0751/4254] misc testament cleanups (#14764) * misc testament cleanups extracted cleanups from #14530 * make sure all CI failures can be searched with `FAIL: ` including megatest failures --- testament/categories.nim | 36 ++++++++++------------------ testament/testament.nim | 5 ++-- tests/misc/tunsignedconv.nim | 14 ++++------- tests/testament/tshould_not_work.nim | 2 ++ 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 45a2113a6..3bd31ddc4 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -587,13 +587,6 @@ proc quoted(a: string): string = # todo: consider moving to system.nim result.addQuoted(a) -proc normalizeExe(file: string): string = - # xxx common pattern, should be exposed in std/os, even if simple (error prone) - when defined(posix): - if file.len == 0: "" - elif DirSep in file: file else: "./" & file - else: file - proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = ## returns a list of tests that have problems var specs: seq[TSpec] = @[] @@ -618,12 +611,7 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = return var megatest: string - #[ - TODO(minor): - get from Nim cmd - put outputGotten.txt, outputGotten.txt, megatest.nim there too - delete upon completion, maybe - ]# + # xxx (minor) put outputExceptedFile, outputGottenFile, megatestFile under here or `buildDir` var outDir = nimcacheDir(testsDir / "megatest", "", targetC) const marker = "megatest:processing: " @@ -644,15 +632,17 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = var (cmdLine, buf, exitCode) = execCmdEx2(command = compilerPrefix, args = args, input = "") if exitCode != 0: echo "$ " & cmdLine & "\n" & buf.string - quit("megatest compilation failed") + quit(failString & "megatest compilation failed") - (buf, exitCode) = execCmdEx(megatestFile.changeFileExt(ExeExt).normalizeExe) + (buf, exitCode) = execCmdEx(megatestFile.changeFileExt(ExeExt).dup normalizeExe) if exitCode != 0: echo buf.string - quit("megatest execution failed") + quit(failString & "megatest execution failed") norm buf.string - writeFile("outputGotten.txt", buf.string) + const outputExceptedFile = "outputExpected.txt" + const outputGottenFile = "outputGotten.txt" + writeFile(outputGottenFile, buf.string) var outputExpected = "" for i, runSpec in specs: outputExpected.add marker & runSpec.file & "\n" @@ -661,14 +651,14 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = norm outputExpected if buf.string != outputExpected: - writeFile("outputExpected.txt", outputExpected) - discard execShellCmd("diff -uNdr outputExpected.txt outputGotten.txt") - echo "output different!" - # outputGotten.txt, outputExpected.txt not removed on purpose for debugging. + writeFile(outputExceptedFile, outputExpected) + discard execShellCmd("diff -uNdr $1 $2" % [outputExceptedFile, outputGottenFile]) + echo failString & "megatest output different!" + # outputGottenFile, outputExceptedFile not removed on purpose for debugging. quit 1 else: - echo "output OK" - removeFile("outputGotten.txt") + echo "megatest output OK" + removeFile(outputGottenFile) removeFile(megatestFile) #testSpec r, makeTest("megatest", options, cat) diff --git a/testament/testament.nim b/testament/testament.nim index 098c07ac5..158a68822 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -21,6 +21,7 @@ var backendLogging = true var simulate = false const + failString* = "FAIL: " # ensures all failures can be searched with 1 keyword in CI logs testsDir = "tests" & DirSep resultsFile = "testresults.html" #jsonFile = "testresults.json" # not used @@ -279,7 +280,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, elif success == reJoined: maybeStyledEcho styleDim, fgYellow, "JOINED: ", styleBright, fgCyan, name else: - maybeStyledEcho styleBright, fgRed, "FAIL: ", fgCyan, name + maybeStyledEcho styleBright, fgRed, failString, fgCyan, name maybeStyledEcho styleBright, fgCyan, "Test \"", test.name, "\"", " in category \"", test.cat.string, "\"" maybeStyledEcho styleBright, fgRed, "Failure: ", $success if success in {reBuildFailed, reNimcCrash, reInstallFailed}: @@ -701,7 +702,7 @@ proc main() = cmds.add(myself & runtype & quoteShell(cat) & rest) proc progressStatus(idx: int) = - echo "progress[all]: i: " & $idx & " / " & $cats.len & " cat: " & cats[idx] + echo "progress[all]: $1/$2 starting: cat: $3" % [$idx, $cats.len, cats[idx]] if simulate: skips = loadSkipFrom(skipFrom) diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index bc7aff30a..0e5fc43db 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -1,10 +1,4 @@ -discard """ - output: '''uint -1''' -""" - # Tests unsigned literals and implicit conversion between uints and ints -# Passes if it compiles var h8:uint8 = 128 var h16:uint16 = 32768 @@ -53,7 +47,7 @@ block t4176: proc fun(): uint = cast[uint](-1) const x0 = fun() -echo typeof(x0) +doAssert typeof(x0) is uint discard $x0 @@ -62,6 +56,6 @@ discard $x0 const x1 = cast[uint](-1) discard $(x1,) -# bug 13698 -let n: csize = 1 -echo n.int32 +# bug #13698 +let n: csize = 1 # xxx should that be csize_t or is that essential here? +doAssert $n.int32 == "1" diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index aca73c308..e7790a4df 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -31,3 +31,5 @@ FAIL: tests/shouldfail/ttimeout.nim C Failure: reTimeout ''' """ + +# xxx `--nim:../compiler/nim`, doesn't seem correct (and should also honor `testament --nim`) From da29222f86f7689227ffe12605842d18c9bf0fc1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 23 Jun 2020 10:53:57 +0200 Subject: [PATCH 0752/4254] init checks and 'out' parameters (#14521) * I don't care about observable stores * enforce explicit initializations * cleaner code for the stdlib * stdlib: use explicit initializations * make tests green * algorithm.nim: set result explicitly * remove out parameters and bring the PR into a mergable state * updated the changelog --- changelog.md | 10 +- compiler/ast.nim | 12 +- compiler/ccgcalls.nim | 14 +-- compiler/ccgexprs.nim | 12 +- compiler/ccgtypes.nim | 2 +- compiler/dfa.nim | 6 +- compiler/guards.nim | 2 +- compiler/jsgen.nim | 2 +- compiler/lineinfos.nim | 2 +- compiler/lowerings.nim | 2 +- compiler/nim.cfg | 4 + compiler/nimsets.nim | 32 +++--- compiler/parampatterns.nim | 6 +- compiler/parser.nim | 6 +- compiler/renderer.nim | 8 +- compiler/renderverbatim.nim | 1 + compiler/semcall.nim | 2 +- compiler/semexprs.nim | 6 +- compiler/semmagic.nim | 3 - compiler/semobjconstr.nim | 2 +- compiler/sempass2.nim | 219 ++++++++++++++++++++---------------- compiler/semstmts.nim | 18 +-- compiler/semtypes.nim | 8 +- compiler/sigmatch.nim | 12 +- compiler/spawn.nim | 4 +- compiler/transf.nim | 10 +- compiler/types.nim | 2 +- compiler/writetracking.nim | 6 +- doc/manual.rst | 32 ++++-- doc/manual_experimental.rst | 6 +- lib/core/macros.nim | 7 +- lib/pure/algorithm.nim | 1 + lib/pure/bitops.nim | 2 + lib/pure/os.nim | 6 +- lib/pure/parseutils.nim | 16 ++- lib/pure/pathnorm.nim | 2 +- lib/pure/strutils.nim | 22 +++- lib/pure/times.nim | 18 +-- lib/pure/typetraits.nim | 2 +- lib/pure/unicode.nim | 1 + lib/std/stackframes.nim | 6 +- lib/system.nim | 7 +- lib/system/alloc.nim | 3 +- lib/system/assertions.nim | 1 + lib/system/gc_common.nim | 5 +- lib/system/io.nim | 16 +-- lib/system/repr.nim | 1 + lib/system/sets.nim | 1 + lib/system/strmantle.nim | 6 +- lib/system/widestrs.nim | 1 + tests/assert/tassert_c.nim | 7 +- tests/effects/toutparam.nim | 28 +++++ tests/init/tuninit1.nim | 2 +- 53 files changed, 355 insertions(+), 257 deletions(-) create mode 100644 tests/effects/toutparam.nim diff --git a/changelog.md b/changelog.md index 151eafcd5..9d1454dcb 100644 --- a/changelog.md +++ b/changelog.md @@ -60,7 +60,7 @@ accept an existing string to modify, which avoids memory allocations, similar to `streams.readLine` (#13857). -- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom`. UDP functionality. +- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. - `dollars.$` now works for unsigned ints with `nim js` @@ -116,7 +116,11 @@ - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. ## Language changes -- In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: +- In the newruntime it is now allowed to assign to the discriminator field + without restrictions as long as case object doesn't have custom destructor. + The discriminator value doesn't have to be a constant either. If you have a + custom destructor for a case object and you do want to freely assign discriminator + fields, it is recommended to refactor object into 2 objects like this: ```nim type @@ -175,6 +179,8 @@ proc mydiv(a, b): int {.raises: [].} = The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. +- Added the `thiscall` calling convention as specified by Microsoft. + - Added `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. diff --git a/compiler/ast.nim b/compiler/ast.nim index 9639f52d3..66a1a253b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -435,7 +435,8 @@ type # be any type. tyOptDeprecated - # deadcode: was `tyOpt`, Builtin optional type + # 'out' parameter. Comparable to a 'var' parameter but every + # path must assign a value to it before it can be read from. tyVoid # now different from tyEmpty, hurray! @@ -1802,12 +1803,12 @@ proc skipStmtList*(n: PNode): PNode = else: result = n -proc toVar*(typ: PType): PType = +proc toVar*(typ: PType; kind: TTypeKind): PType = ## If ``typ`` is not a tyVar then it is converted into a `var ` and ## returned. Otherwise ``typ`` is simply returned as-is. result = typ - if typ.kind != tyVar: - result = newType(tyVar, typ.owner) + if typ.kind != kind: + result = newType(kind, typ.owner) rawAddSon(result, typ) proc toRef*(typ: PType): PType = @@ -1934,3 +1935,6 @@ proc toHumanStr*(kind: TSymKind): string = proc toHumanStr*(kind: TTypeKind): string = ## strips leading `tk` result = toHumanStrImpl(kind, 2) + +proc skipAddr*(n: PNode): PNode {.inline.} = + (if n.kind == nkHiddenAddr: n[0] else: n) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 3dd2b54d4..80f02b6c3 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -178,10 +178,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: let atyp = skipTypes(a.t, abstractInst) - if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and + if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if atyp.kind == tyVar and not compileToCpp(p.module): + if atyp.kind in {tyVar} and not compileToCpp(p.module): result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] else: result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] @@ -194,10 +194,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: let ntyp = skipTypes(n.typ, abstractInst) - if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and + if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if ntyp.kind == tyVar and not compileToCpp(p.module): + if ntyp.kind in {tyVar} and not compileToCpp(p.module): var t: TLoc t.r = "(*$1)" % [a.rdLoc] result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] @@ -232,7 +232,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): initLocExpr(p, n, a) result = addrLoc(p.config, a) - elif p.module.compileToCpp and param.typ.kind == tyVar and + elif p.module.compileToCpp and param.typ.kind in {tyVar} and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still @@ -372,7 +372,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = assert(paramType.kind == nkSym) if paramType.typ.isCompileTimeOnly: result = nil - elif typ[i].kind == tyVar and ri[i].kind == nkHiddenAddr: + elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr: result = genArgNoParam(p, ri[i][0]) else: result = genArgNoParam(p, ri[i]) #, typ.n[i].sym) @@ -449,7 +449,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = var ri = ri[i] while ri.kind == nkObjDownConv: ri = ri[0] let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink}) - if t.kind == tyVar: + if t.kind in {tyVar}: let x = if ri.kind == nkHiddenAddr: ri[0] else: ri if x.typ.kind == tyPtr: result = genArgNoParam(p, x) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2850ab750..a59529021 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -126,9 +126,8 @@ proc genRawSetData(cs: TBitSet, size: int): Rope = result = intLiteral(cast[BiggestInt](bitSetToWord(cs, size))) proc genSetNode(p: BProc, n: PNode): Rope = - var cs: TBitSet var size = int(getSize(p.config, n.typ)) - toBitSet(p.config, n, cs) + let cs = toBitSet(p.config, n) if size > 8: let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) result = p.module.tmpBase & rope(id) @@ -676,7 +675,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc isCppRef(p: BProc; typ: PType): bool {.inline.} = result = p.module.compileToCpp and - skipTypes(typ, abstractInstOwned).kind == tyVar and + skipTypes(typ, abstractInstOwned).kind in {tyVar} and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags proc genDeref(p: BProc, e: PNode, d: var TLoc) = @@ -693,7 +692,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon typ = typ.skipTypes(abstractInstOwned) - if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: + if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: initLocExprSingleUse(p, e[0][0], d) return else: @@ -716,7 +715,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: internalError(p.config, e.info, "genDeref " & $typ.kind) elif p.module.compileToCpp: - if typ.kind == tyVar and tfVarIsPtr notin typ.flags and + if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: putIntoDest(p, d, e, rdLoc(a), a.storage) return @@ -2960,8 +2959,7 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind case ty of tySet: - var cs: TBitSet - toBitSet(p.config, n, cs) + let cs = toBitSet(p.config, n) result = genRawSetData(cs, int(getSize(p.config, n.typ))) of tySequence: if optSeqDestructors in p.config.globalOptions: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 199d5c918..11743499d 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -701,7 +701,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = return case t.kind of tyRef, tyPtr, tyVar, tyLent: - var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and + var star = if t.kind in {tyVar} and tfVarIsPtr notin origTyp.flags and compileToCpp(m): "&" else: "*" var et = origTyp.skipTypes(abstractInst).lastSon var etB = et.skipTypes(abstractInst) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index a0ec31ac6..c393b2c81 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -715,10 +715,8 @@ proc genCall(c: var Con; n: PNode) = for i in 1.. 0 and canRaiseConservative(n[0]): diff --git a/compiler/guards.nim b/compiler/guards.nim index e4f87bae4..a6ca44978 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -46,7 +46,7 @@ proc isLet(n: PNode): bool = if n.sym.kind in {skLet, skTemp, skForVar}: result = true elif n.sym.kind == skParam and skipTypes(n.sym.typ, - abstractInst).kind != tyVar: + abstractInst).kind notin {tyVar}: result = true proc isVar(n: PNode): bool = diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 99d2bc4f2..57a6b8094 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1053,7 +1053,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "$1 = nimCopy(null, $2, $3);$n", [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: - if x.typ.kind == tyVar or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index bc3c51d53..6287e21aa 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -113,7 +113,7 @@ const warnStaticIndexCheck: "$1", warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", - warnUninit: "'$1' might not have been initialized", + warnUninit: "use explicit initialization of '$1' for clarity", warnGcMem: "'$1' uses GC'ed memory", warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", warnLockLevel: "$1", diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 575bfe8aa..5e75c36de 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -59,7 +59,7 @@ proc newFastAsgnStmt*(le, ri: PNode): PNode = result[0] = le result[1] = ri -proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode = +proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode = result = newNodeI(nkFastAsgn, le.info, 2) result[0] = le result[1] = newNodeIT(nkCall, ri.info, ri.typ) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index a77fa84d3..8e733bdf8 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -21,3 +21,7 @@ define:useStdoutAsStdmsg #define:useNodeIds #gc:markAndSweep + +@if nimHasWarningObservableStores: + warning[ObservableStores]: off +@end diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 3876a114e..8683604af 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -58,18 +58,18 @@ proc someInSet*(s: PNode, a, b: PNode): bool = return true result = false -proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) = +proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet = var first, j: Int128 first = firstOrd(conf, s.typ[0]) - bitSetInit(b, int(getSize(conf, s.typ))) + bitSetInit(result, int(getSize(conf, s.typ))) for i in 0.. 0: result = bracketKind(g, n[0]) - of nkSym: + of nkSym: result = case n.sym.name.s of "[]": bkBracket of "[]=": bkBracketAsgn @@ -974,7 +974,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParRi, ")") put(g, tkColon, ":") gsub(g, n, n.len-1) - elif n.len >= 1: + elif n.len >= 1: case bracketKind(g, n[0]) of bkBracket: gsub(g, n, 1) diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index d20ee1549..2dce6824c 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -107,6 +107,7 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = var indent = info.col let numLines = numLines(conf, info.fileIndex).uint16 var lastNonemptyPos = 0 + result = "" var ldata = LineData(lineFirst: first.line.int, conf: conf) visitMultilineStrings(ldata, n[^1]) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 665eb4ea4..405de52ee 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -676,7 +676,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true var x: PType if param.typ.kind == tyVar: - x = newTypeS(tyVar, c) + x = newTypeS(param.typ.kind, c) x.addSonSkipIntLit t.baseOfDistinct else: x = t.baseOfDistinct diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 200d1d60a..6f267b4eb 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -712,7 +712,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = # note sometimes this is eval'ed twice so we check for nkHiddenAddr here: for i in 1.. 0: @@ -257,20 +270,11 @@ proc useVar(a: PEffects, n: PNode) = elif s.id notin a.init: if s.typ.requiresInit: message(a.config, n.info, warnProveInit, s.name.s) - else: + elif a.leftPartOfAsgn <= 0: message(a.config, n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id - if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and - s.magic != mNimvm: - if s.guard != nil: guardGlobal(a, n, s.guard) - if {sfGlobal, sfThread} * s.flags == {sfGlobal} and - (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): - #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n) - markGcUnsafe(a, s) - markSideEffect(a, s) - else: - markSideEffect(a, s) + useVarNoInitCheck(a, n, s) type @@ -538,7 +542,7 @@ proc isNoEffectList(n: PNode): bool {.inline.} = proc isTrival(caller: PNode): bool {.inline.} = result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved} -proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) = +proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) = let a = skipConvAndClosure(n) let op = a.typ # assume indirect calls are taken here: @@ -572,7 +576,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags: markSideEffect(tracked, a) - if paramType != nil and paramType.kind == tyVar: + if paramType != nil and paramType.kind in {tyVar}: invalidateFacts(tracked.guards, n) if n.kind == nkSym and isLocalVar(tracked, n.sym): makeVolatile(tracked, n.sym) @@ -732,7 +736,7 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = optSeqDestructors in tracked.config.globalOptions: tracked.owner.flags.incl sfInjectDestructors -proc track(tracked: PEffects, n: PNode) = +proc trackCall(tracked: PEffects; n: PNode) = template gcsafeAndSideeffectCheck() = if notGcSafe(op) and not importedFromC(a): # and it's not a recursive call: @@ -744,11 +748,105 @@ proc track(tracked: PEffects, n: PNode) = if not (a.kind == nkSym and a.sym == tracked.owner): markSideEffect(tracked, a) + # p's effects are ours too: + var a = n[0] + #if canRaise(a): + # echo "this can raise ", tracked.config $ n.info + let op = a.typ + if n.typ != nil: + if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray: + createTypeBoundOps(tracked, n.typ, n.info) + if getConstExpr(tracked.ownerModule, n, tracked.graph) != nil: + return + if a.kind == nkCast and a[1].typ.kind == tyProc: + a = a[1] + # XXX: in rare situations, templates and macros will reach here after + # calling getAst(templateOrMacro()). Currently, templates and macros + # are indistinguishable from normal procs (both have tyProc type) and + # we can detect them only by checking for attached nkEffectList. + if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList: + if a.kind == nkSym: + if a.sym == tracked.owner: tracked.isRecursive = true + # even for recursive calls we need to check the lock levels (!): + mergeLockLevels(tracked, n, a.sym.getLockLevel) + if sfSideEffect in a.sym.flags: markSideEffect(tracked, a) + else: + mergeLockLevels(tracked, n, op.lockLevel) + var effectList = op.n[0] + if a.kind == nkSym and a.sym.kind == skMethod: + propagateEffects(tracked, n, a.sym) + elif isNoEffectList(effectList): + if isForwardedProc(a): + propagateEffects(tracked, n, a.sym) + elif isIndirectCall(a, tracked.owner): + assumeTheWorst(tracked, n, op) + gcsafeAndSideeffectCheck() + else: + mergeEffects(tracked, effectList[exceptionEffects], n) + mergeTags(tracked, effectList[tagEffects], n) + gcsafeAndSideeffectCheck() + if a.kind != nkSym or a.sym.magic != mNBindSym: + for i in 1.. 0: + createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) + createTypeBoundOps(tracked, n[1].typ, n.info) + # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? + + elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and + optStaticBoundsCheck in tracked.currOptions: + checkBounds(tracked, n[1], n[2]) + + if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and + tracked.owner.kind != skMacro: + let opKind = find(AttachedOpToStr, a.sym.name.s.normalize) + if opKind != -1: + # rebind type bounds operations after createTypeBoundOps call + let t = n[1].typ.skipTypes({tyAlias, tyVar}) + if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]: + createTypeBoundOps(tracked, t, n.info) + let op = t.attachedOps[TTypeAttachedOp(opKind)] + if op != nil: + n[0].sym = op + + if a.kind != nkSym or a.sym.magic != mRunnableExamples: + for i in 0.. 0: - createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) - createTypeBoundOps(tracked, n[1].typ, n.info) - # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? - - elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and - optStaticBoundsCheck in tracked.currOptions: - checkBounds(tracked, n[1], n[2]) - - if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and - tracked.owner.kind != skMacro: - let opKind = find(AttachedOpToStr, a.sym.name.s.normalize) - if opKind != -1: - # rebind type bounds operations after createTypeBoundOps call - let t = n[1].typ.skipTypes({tyAlias, tyVar}) - if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]: - createTypeBoundOps(tracked, t, n.info) - let op = t.attachedOps[TTypeAttachedOp(opKind)] - if op != nil: - n[0].sym = op - - if a.kind != nkSym or a.sym.magic != mRunnableExamples: - for i in 0.. x @@ -569,14 +569,14 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = result = putArgInto(arg[0], formal) of nkCurly, nkBracket: for i in 0.. 0 and p[0].kind == nnkSym and p[0] == cp: diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 4a6c2510a..a277d1429 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -187,6 +187,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K, else: return -1 + result = 0 if (len and (len - 1)) == 0: # when `len` is a power of 2, a faster shr can be used. var step = len shr 1 diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 7dd171a38..4f22388f3 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -395,6 +395,8 @@ proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} = if k == 0: k = uint32(v shr 32'u32) and 0xFFFFFFFF'u32 result = 32 + else: + result = 0 result += firstSetBitNim(k) proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} = diff --git a/lib/pure/os.nim b/lib/pure/os.nim index bb09c966f..dcb63458b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -417,7 +417,8 @@ proc relativePath*(path, base: string, sep = DirSep): string {. if not sameRoot(path, base): return path - var f, b: PathIter + var f = default PathIter + var b = default PathIter var ff = (0, -1) var bb = (0, -1) # (int, int) result = newStringOfCap(path.len) @@ -1053,6 +1054,7 @@ when defined(windows) or defined(posix) or defined(nintendoswitch): assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\"" # can't use `map` pending https://github.com/nim-lang/Nim/issues/8303 + result = "" for i in 0.. 0: result.add " " result.add quoteShell(args[i]) @@ -2981,7 +2983,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW setLen(result, L) break elif defined(macosx): - var size: cuint32 + var size = cuint32(0) getExecPath1(nil, size) result = newString(int(size)) if getExecPath2(result, size): diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index c358005f1..baf238843 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -249,6 +249,7 @@ proc skipWhitespace*(s: string, start = 0): int {.inline.} = doAssert skipWhitespace(" Hello World", 0) == 1 doAssert skipWhitespace("Hello World", 5) == 1 doAssert skipWhitespace("Hello World", 5) == 2 + result = 0 while start+result < s.len and s[start+result] in Whitespace: inc(result) proc skip*(s, token: string, start = 0): int {.inline.} = @@ -260,6 +261,7 @@ proc skip*(s, token: string, start = 0): int {.inline.} = doAssert skip("2019-01-22", "19", 2) == 2 doAssert skip("CAPlow", "CAP", 0) == 3 doAssert skip("CAPlow", "cap", 0) == 0 + result = 0 while start+result < s.len and result < token.len and s[result+start] == token[result]: inc(result) @@ -270,6 +272,7 @@ proc skipIgnoreCase*(s, token: string, start = 0): int = runnableExamples: doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3 doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3 + result = 0 while start+result < s.len and result < token.len and toLower(s[result+start]) == toLower(token[result]): inc(result) if result != token.len: result = 0 @@ -282,6 +285,7 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} = doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1 doAssert skipUntil("Hello World", {'W'}, 0) == 6 doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6 + result = 0 while start+result < s.len and s[result+start] notin until: inc(result) proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = @@ -293,6 +297,7 @@ proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = doAssert skipUntil("Hello World", 'o', 4) == 0 doAssert skipUntil("Hello World", 'W', 0) == 6 doAssert skipUntil("Hello World", 'w', 0) == 11 + result = 0 while start+result < s.len and s[result+start] != until: inc(result) proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = @@ -302,6 +307,7 @@ proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = doAssert skipWhile("Hello World", {'H', 'e'}) == 2 doAssert skipWhile("Hello World", {'e'}) == 0 doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3 + result = 0 while start+result < s.len and s[result+start] in toSkip: inc(result) proc parseUntil*(s: string, token: var string, until: set[char], @@ -437,7 +443,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {. var res: BiggestInt doAssert parseBiggestInt("9223372036854775807", res, 0) == 19 doAssert res == 9223372036854775807 - var res: BiggestInt + var res = BiggestInt(0) # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): result = rawParseInt(s, res, start) @@ -455,7 +461,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {. doAssert res == 2019 doAssert parseInt("2019", res, 2) == 2 doAssert res == 19 - var res: BiggestInt + var res = BiggestInt(0) result = parseBiggestInt(s, res, start) when sizeof(int) <= 4: if res < low(int) or res > high(int): @@ -518,7 +524,7 @@ proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {. doAssert res == 12 doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19 doAssert res == 1111111111111111111'u64 - var res: BiggestUInt + var res = BiggestUInt(0) # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): result = rawParseUInt(s, res, start) @@ -536,7 +542,7 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {. doAssert res == 3450 doAssert parseUInt("3450", res, 2) == 2 doAssert res == 50 - var res: BiggestUInt + var res = BiggestUInt(0) result = parseBiggestUInt(s, res, start) when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4: if res > 0xFFFF_FFFF'u64: @@ -563,7 +569,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {. doAssert res == 32.57 doAssert parseFloat("32.57", res, 3) == 2 doAssert res == 57.00 - var bf: BiggestFloat + var bf = BiggestFloat(0.0) result = parseBiggestFloat(s, bf, start) if result != 0: number = bf diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 8763ba878..03a65bd60 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -44,7 +44,7 @@ proc next*(it: var PathIter; x: string): (int, int) = it.notFirst = true iterator dirs(x: string): (int, int) = - var it: PathIter + var it = default PathIter while hasNext(it, x): yield next(it, x) proc isDot(x: string; bounds: (int, int)): bool = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 7c00de2d2..1ffc8bf22 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1103,6 +1103,7 @@ proc parseInt*(s: string): int {.noSideEffect, ## If `s` is not a valid integer, `ValueError` is raised. runnableExamples: doAssert parseInt("-0042") == -42 + result = 0 let L = parseutils.parseInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) @@ -1112,6 +1113,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, ## Parses a decimal integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. + result = BiggestInt(0) let L = parseutils.parseBiggestInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) @@ -1121,6 +1123,7 @@ proc parseUInt*(s: string): uint {.noSideEffect, ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. + result = uint(0) let L = parseutils.parseUInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) @@ -1130,6 +1133,7 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. + result = BiggestUInt(0) let L = parseutils.parseBiggestUInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) @@ -1143,6 +1147,7 @@ proc parseFloat*(s: string): float {.noSideEffect, runnableExamples: doAssert parseFloat("3.14") == 3.14 doAssert parseFloat("inf") == 1.0/0 + result = 0.0 let L = parseutils.parseFloat(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid float: " & s) @@ -1161,6 +1166,7 @@ proc parseBinInt*(s: string): int {.noSideEffect, doAssert a.parseBinInt() == 53 doAssert b.parseBinInt() == 7 + result = 0 let L = parseutils.parseBin(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid binary integer: " & s) @@ -1172,6 +1178,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, ## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one ## of the following optional prefixes: ``0o``, ``0O``. Underscores within ## `s` are ignored. + result = 0 let L = parseutils.parseOct(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid oct integer: " & s) @@ -1183,6 +1190,7 @@ proc parseHexInt*(s: string): int {.noSideEffect, ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one ## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores ## within `s` are ignored. + result = 0 let L = parseutils.parseHex(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid hex integer: " & s) @@ -1270,9 +1278,9 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = result = nnkCaseStmt.newTree(nnkDotExpr.newTree(argSym, bindSym"nimIdentNormalize")) # stores all processed field strings to give error msg for ambiguous enums - var foundFields: seq[string] - var fStr: string # string of current field - var fNum: BiggestInt # int value of current field + var foundFields: seq[string] = @[] + var fStr = "" # string of current field + var fNum = BiggestInt(0) # int value of current field for f in impl: case f.kind of nnkEmpty: continue # skip first node of `enumTy` @@ -2028,6 +2036,7 @@ proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect, if sub.len == 0: return -1 let last = if last == -1: s.high else: last + result = 0 for i in countdown(last - sub.len + 1, start): for j in 0..sub.len-1: result = i @@ -2044,6 +2053,7 @@ proc count*(s: string, sub: char): int {.noSideEffect, ## ## See also: ## * `countLines proc<#countLines,string>`_ + result = 0 for c in s: if c == sub: inc result @@ -2054,6 +2064,7 @@ proc count*(s: string, subs: set[char]): int {.noSideEffect, ## See also: ## * `countLines proc<#countLines,string>`_ doAssert card(subs) > 0 + result = 0 for c in s: if c in subs: inc result @@ -2066,6 +2077,7 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {. ## See also: ## * `countLines proc<#countLines,string>`_ doAssert sub.len > 0 + result = 0 var i = 0 while true: i = s.find(sub, i) @@ -2313,7 +2325,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, case s[i+1]: of 'x': inc i, 2 - var c: int + var c = 0 i += parseutils.parseHex(s, c, i, maxLen = 2) result.add(chr(c)) dec i, 2 @@ -2514,7 +2526,7 @@ proc formatSize*(bytes: int64, xb: int64 = bytes fbytes: float lastXb: int64 = bytes - matchedIndex: int + matchedIndex = 0 prefixes: array[9, string] if prefix == bpColloquial: prefixes = collPrefixes diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 7d82733e1..fb2f5e430 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -895,16 +895,16 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} = millis mod convert(Seconds, Milliseconds, 1).int) result = initTime(seconds, nanos) elif defined(macosx): - var a: Timeval + var a {.noinit.}: Timeval gettimeofday(a) result = initTime(a.tv_sec.int64, convert(Microseconds, Nanoseconds, a.tv_usec.int)) elif defined(posix): - var ts: Timespec + var ts {.noinit.}: Timespec discard clock_gettime(CLOCK_REALTIME, ts) result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) elif defined(windows): - var f: FILETIME + var f {.noinit.}: FILETIME getSystemTimeAsFileTime(f) result = fromWinTime(rdFileTime(f)) @@ -1756,7 +1756,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, proc parsePattern(input: string, pattern: FormatPattern, i: var int, parsed: var ParsedTime, loc: DateTimeLocale): bool = template takeInt(allowedWidth: Slice[int], allowSign = false): int = - var sv: int + var sv = 0 var pd = parseInt(input, sv, i, allowedWidth.b, allowSign) if pd < allowedWidth.a: return false @@ -1987,6 +1987,7 @@ proc format*(dt: DateTime, f: TimeFormat, let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert "2000-01-01" == dt.format(f) assertDateTimeInitialized dt + result = "" var idx = 0 while idx <= f.patterns.high: case f.patterns[idx].FormatPattern @@ -2284,7 +2285,7 @@ proc between*(startDt, endDt: DateTime): TimeInterval = endDate.monthday.dec # Years - result.years.inc endDate.year - startDate.year - 1 + result.years = endDate.year - startDate.year - 1 if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday): result.years.inc startDate.year.inc result.years @@ -2441,6 +2442,7 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): var months = interval.years * 12 + interval.months var curYear = dt.year var curMonth = dt.month + result = default(tuple[adjDur, absDur: Duration]) # Subtracting if months < 0: for mth in countdown(-1 * months, 1): @@ -2562,17 +2564,17 @@ proc epochTime*(): float {.tags: [TimeEffect].} = ## ## ``getTime`` should generally be preferred over this proc. when defined(macosx): - var a: Timeval + var a {.noinit.}: Timeval gettimeofday(a) result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat( a.tv_usec)*0.00_0001 elif defined(posix): - var ts: Timespec + var ts {.noinit.}: Timespec discard clock_gettime(CLOCK_REALTIME, ts) result = toBiggestFloat(ts.tv_sec.int64) + toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 elif defined(windows): - var f: winlean.FILETIME + var f {.noinit.}: winlean.FILETIME getSystemTimeAsFileTime(f) var i64 = rdFileTime(f) - epochDiff var secs = i64 div rateDiff diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 9a215a353..317376405 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -112,7 +112,7 @@ macro genericParamsImpl(T: typedesc): untyped = of nnkBracketExpr: for i in 1.. 0, "getBigChunk 2") var size = size # roundup(size, PageSize) - var fl, sl: int + var fl = 0 + var sl = 0 mappingSearch(size, fl, sl) sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk") result = findSuitableBlock(a, fl, sl) diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index ca3bd7bc1..c6283c89c 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -11,6 +11,7 @@ proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.} proc `$`(info: InstantiationInfo): string = # The +1 is needed here # instead of overriding `$` (and changing its meaning), consider explicit name. + result = "" result.toLocation(info.filename, info.line, info.column+1) # --------------------------------------------------------------------------- diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index d75ada791..7f6c41e1b 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -217,7 +217,7 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} = when nimCoroutines: var pos = stack.pos else: - var pos {.volatile.}: pointer + var pos {.volatile, noinit.}: pointer pos = addr(pos) if pos != nil: @@ -229,6 +229,7 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} = result = 0 proc stackSize(): int {.noinline.} = + result = 0 for stack in gch.stack.items(): result = result + stack.stackSize() @@ -303,7 +304,7 @@ when not defined(useNimRtl): {.pop.} proc isOnStack(p: pointer): bool = - var stackTop {.volatile.}: pointer + var stackTop {.volatile, noinit.}: pointer stackTop = addr(stackTop) var a = cast[ByteAddress](gch.getActiveStack().bottom) var b = cast[ByteAddress](stackTop) diff --git a/lib/system/io.nim b/lib/system/io.nim index d1a7f1fc7..482057214 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -424,12 +424,12 @@ proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.} = else: write(f, "false") proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.} = - var buffer: array[65, char] + var buffer {.noinit.}: array[65, char] discard writeFloatToBuffer(buffer, r) if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f) proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.} = - var buffer: array[65, char] + var buffer {.noinit.}: array[65, char] discard writeFloatToBuffer(buffer, r) if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f) @@ -591,7 +591,7 @@ when defined(posix) and not defined(nimscript): proc open*(f: var File, filename: string, mode: FileMode = fmRead, - bufSize: int = -1): bool {.tags: [], raises: [], benign.} = + bufSize: int = -1): bool {.tags: [], raises: [], benign.} = ## Opens a file named `filename` with given `mode`. ## ## Default mode is readonly. Returns true if the file could be opened. @@ -605,7 +605,7 @@ proc open*(f: var File, filename: string, # How `fopen` handles opening a directory is not specified in ISO C and # POSIX. We do not want to handle directories as regular files that can # be opened. - var res: Stat + var res {.noinit.}: Stat if c_fstat(getFileHandle(f2), res) >= 0'i32 and modeIsDir(res.st_mode): close(f2) return false @@ -759,7 +759,7 @@ proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} ## Raises an IO exception in case of an error. If you need to call ## this inside a compile time macro you can use `staticRead ## `_. - var f: File + var f: File = nil if open(f, filename): try: result = readAll(f) @@ -772,7 +772,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} = ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - var f: File + var f: File = nil if open(f, filename, fmWrite): try: f.write(content) @@ -785,7 +785,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} = ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - var f: File + var f: File = nil if open(f, filename, fmWrite): try: f.writeBuffer(unsafeAddr content[0], content.len) @@ -799,7 +799,7 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] = ## in case of an error. Raises EOF if file does not contain at least `n` lines. ## Available at compile time. A line of text may be delimited by ``LF`` or ``CRLF``. ## The newline character(s) are not part of the returned strings. - var f: File + var f: File = nil if open(f, filename): try: result = newSeq[TaintedString](n) diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 526839aa2..318e95ebb 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -102,6 +102,7 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) = of 4: u = cast[ptr uint32](p)[] of 8: u = cast[ptr uint64](p)[] else: + u = uint64(0) var a = cast[PByteArray](p) for i in 0 .. typ.size*8-1: if (uint(a[i shr 3]) and (1'u shl (i and 7))) != 0: diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 0df50957d..42c448848 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -31,6 +31,7 @@ proc countBits64(n: uint64): int {.compilerproc, inline.} = proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = var i = 0 + result = 0 when defined(x86) or defined(amd64): while i < len - 8: inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[])) diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index c3ac5fc1b..cb26833ac 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -94,7 +94,7 @@ proc addFloat*(result: var string; x: float) = when nimvm: result.add $x else: - var buffer: array[65, char] + var buffer {.noinit.}: array[65, char] let n = writeFloatToBuffer(buffer, x) result.addCstringN(cstring(buffer[0].addr), n) @@ -131,8 +131,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, i = start sign = 1.0 kdigits, fdigits = 0 - exponent: int - integer: uint64 + exponent = 0 + integer = uint64(0) fracExponent = 0 expSign = 1 firstDigit = -1 diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 3048de82a..a7a514446 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -63,6 +63,7 @@ proc ord(arg: Utf16Char): int = int(cast[uint16](arg)) proc len*(w: WideCString): int = ## returns the length of a widestring. This traverses the whole string to ## find the binary zero end marker! + result = 0 while int16(w[result]) != 0'i16: inc result const diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index cbb565f84..c6a2eadb1 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -6,8 +6,8 @@ discard """ const expected = """ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo -assertions.nim(29) failedAssertImpl -assertions.nim(22) raiseAssert +assertions.nim(30) failedAssertImpl +assertions.nim(23) raiseAssert fatal.nim(49) sysFatal""" proc tmatch(x, p: string): bool = @@ -36,4 +36,5 @@ try: except AssertionDefect: let e = getCurrentException() let trace = e.getStackTrace - if tmatch(trace, expected): echo true else: echo "wrong trace:\n" & trace + if tmatch(trace, expected): echo true + else: echo "wrong trace:\n" & trace diff --git a/tests/effects/toutparam.nim b/tests/effects/toutparam.nim new file mode 100644 index 000000000..00572aa6b --- /dev/null +++ b/tests/effects/toutparam.nim @@ -0,0 +1,28 @@ +discard """ + cmd: '''nim c --warningAsError[Uninit]:on --skipCfg --skipParentCfg $file''' + errormsg: "use explicit initialization of 'x' for clarity [Uninit]" + line: 24 + disabled: "true" +""" + +proc gah[T](x: out T) = + x = 3 + +proc main = + var a: array[2, int] + var x: int + gah(x) + a[0] = 3 + a[x] = 3 + echo x + +main() + +proc mainB = + var a: array[2, int] + var x: int + a[0] = 3 + a[x] = 3 + echo x + +mainB() diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim index 67c0c4d8b..fe91733ff 100644 --- a/tests/init/tuninit1.nim +++ b/tests/init/tuninit1.nim @@ -1,5 +1,5 @@ discard """ - nimout: "Warning: 'y' might not have been initialized [Uninit]" + nimout: "Warning: use explicit initialization of 'y' for clarity [Uninit]" line:34 action: compile """ From ebd1cc0265bd2b9fa071b0649183f14def0f307b Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 23 Jun 2020 10:58:55 +0200 Subject: [PATCH 0753/4254] minor bugfixes for 'func' and .borrow --- compiler/ast.nim | 2 +- compiler/semcall.nim | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 66a1a253b..40fd40209 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1756,7 +1756,7 @@ proc isRoutine*(s: PSym): bool {.inline.} = proc isCompileTimeProc*(s: PSym): bool {.inline.} = result = s.kind == skMacro or - s.kind == skProc and sfCompileTime in s.flags + s.kind in {skProc, skFunc} and sfCompileTime in s.flags proc isRunnableExamples*(n: PNode): bool = # Templates and generics don't perform symbol lookups. diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 405de52ee..0d8f0ae8b 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -682,7 +682,8 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = x = t.baseOfDistinct call.add(newNodeIT(nkEmpty, fn.info, x)) if hasDistinct: - var resolved = semOverloadedCall(c, call, call, {fn.kind}, {}) + let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind} + var resolved = semOverloadedCall(c, call, call, filter, {}) if resolved != nil: result = resolved[0].sym if not compareTypes(result.typ[0], fn.typ[0], dcEqIgnoreDistinct): From 79ed8e79efa49f49e1c522ea803d0317e05f0462 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 23 Jun 2020 06:21:33 -0300 Subject: [PATCH 0754/4254] Documentation GC (#14739) --- doc/gc.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index 39d6d0484..b118b1f8a 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -43,17 +43,17 @@ To choose the memory management strategy use the ``--gc:`` switch. simply never freed. You should use ``--gc:arc`` instead. -================== ======== ================= ====================== -Memory Management Heap Reference Cycles Command line switch -================== ======== ================= ====================== -RefC Local Cycle Collector ``--gc:refc`` -Mark & Sweep Local Cycle Collector ``--gc:markAndSweep`` -ARC Shared Leak ``--gc:arc`` -ORC Shared Cycle Collector ``--gc:orc`` -Boehm Shared Cycle Collector ``--gc:boehm`` -Go Shared Cycle Collector ``--gc:go`` -None Manual Manual ``--gc:none`` -================== ======== ================= ====================== +================== ======== ================= ============== =================== +Memory Management Heap Reference Cycles Stop-The-World Command line switch +================== ======== ================= ============== =================== +RefC Local Cycle Collector No ``--gc:refc`` +Mark & Sweep Local Cycle Collector No ``--gc:markAndSweep`` +ARC Shared Leak No ``--gc:arc`` +ORC Shared Cycle Collector No ``--gc:orc`` +Boehm Shared Cycle Collector Yes ``--gc:boehm`` +Go Shared Cycle Collector Yes ``--gc:go`` +None Manual Manual Manual ``--gc:none`` +================== ======== ================= ============== =================== JavaScript's garbage collector is used for the `JavaScript and NodeJS `_ compilation targets. From c3459c7b148cd00d85b01ddae74782648a5d4e37 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 23 Jun 2020 06:22:07 -0300 Subject: [PATCH 0755/4254] Deprecate oldNewlines, clean out deprecated code from oldNewlines (#14763) --- changelog.md | 1 + compiler/commands.nim | 10 ---------- compiler/lexer.nim | 7 +------ doc/advopt.txt | 1 - 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index 9d1454dcb..d2cf0b811 100644 --- a/changelog.md +++ b/changelog.md @@ -218,5 +218,6 @@ proc mydiv(a, b): int {.raises: [].} = - `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified (with or without `--project`); passing `--project` now automatically generates an index and enables search. See [docgen](docgen.html#introduction-quick-start) for details. +- Deprecated `--oldNewlines` and its Deprecated code cleaned out. ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index c945a633a..6dccbcd00 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -582,16 +582,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; else: undefSymbol(conf.symbols, "hotcodereloading") undefSymbol(conf.symbols, "useNimRtl") - of "oldnewlines": - case arg.normalize - of "", "on": - conf.oldNewlines = true - defineSymbol(conf.symbols, "nimOldNewlines") - of "off": - conf.oldNewlines = false - undefSymbol(conf.symbols, "nimOldNewlines") - else: - localError(conf, info, errOnOrOffExpectedButXFound % arg) of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info) of "oldast": processOnOffSwitch(conf, {optOldAst}, arg, pass, info) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index bd71a6ad5..f9679adee 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -684,12 +684,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = inc(L.bufpos) # skip '\' case L.buf[L.bufpos] of 'n', 'N': - if L.config.oldNewlines: - if tok.tokType == tkCharLit: - lexMessage(L, errGenerated, "\\n not allowed in character literal") - tok.literal.add(L.config.target.tnl) - else: - tok.literal.add('\L') + tok.literal.add('\L') inc(L.bufpos) of 'p', 'P': if tok.tokType == tkCharLit: diff --git a/doc/advopt.txt b/doc/advopt.txt index e522973cd..b2aa82d2b 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -101,7 +101,6 @@ Advanced options: --excessiveStackTrace:on|off stack traces use full file paths --stackTraceMsgs:on|off enable user defined stack frame msgs via `setFrameMsg` - --oldNewlines:on|off turn on|off the old behaviour of "\n" --laxStrings:on|off when turned on, accessing the zero terminator in strings is allowed; only for backwards compatibility --nilseqs:on|off allow 'nil' for strings/seqs for From 28510a9da9bf2a6b02590ba27b64e951a208b23d Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 23 Jun 2020 08:20:53 -0300 Subject: [PATCH 0756/4254] Deprecated laxStrings for mutating the internal zero terminator on strings and its Deprecated code cleaned out (#14766) Co-authored-by: Andreas Rumpf --- changelog.md | 3 +++ compiler/ccgexprs.nim | 2 +- compiler/commands.nim | 1 - compiler/options.nim | 1 - compiler/semfold.nim | 2 -- compiler/vm.nim | 2 -- doc/advopt.txt | 2 -- 7 files changed, 4 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index d2cf0b811..96841fc50 100644 --- a/changelog.md +++ b/changelog.md @@ -220,4 +220,7 @@ proc mydiv(a, b): int {.raises: [].} = See [docgen](docgen.html#introduction-quick-start) for details. - Deprecated `--oldNewlines` and its Deprecated code cleaned out. +- Deprecated `--laxStrings` for mutating the internal zero terminator on strings and its Deprecated code cleaned out. + + ## Tool changes diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a59529021..08b9e1ff6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -930,7 +930,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: - if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): + if ty.kind == tyString and not defined(nimNoZeroTerminator): linefmt(p, cpsStmts, "if ((NU)($1) > (NU)$2){ #raiseIndexError2($1,$2); $3}$n", [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) diff --git a/compiler/commands.nim b/compiler/commands.nim index 6dccbcd00..fc559d68c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -582,7 +582,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; else: undefSymbol(conf.symbols, "hotcodereloading") undefSymbol(conf.symbols, "useNimRtl") - of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info) of "oldast": processOnOffSwitch(conf, {optOldAst}, arg, pass, info) of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) diff --git a/compiler/options.nim b/compiler/options.nim index 289509c16..92c664587 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -39,7 +39,6 @@ type # please make sure we have under 32 options # evaluation optTrMacros, # en/disable pattern matching optMemTracker, - optLaxStrings, optNilSeqs, optOldAst, optSinkInference # 'sink T' inference diff --git a/compiler/semfold.nim b/compiler/semfold.nim index d24adb979..604aa9fea 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -482,8 +482,6 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = result = newNodeIT(nkCharLit, x.info, n.typ) if idx >= 0 and idx < x.strVal.len: result.intVal = ord(x.strVal[int(idx)]) - elif idx == x.strVal.len and optLaxStrings in g.config.options: - discard else: localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n) else: discard diff --git a/compiler/vm.nim b/compiler/vm.nim index 9b76d7986..5d8d21bb9 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -684,8 +684,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let s = regs[rb].node.strVal if idx <% s.len: regs[ra].intVal = s[idx].ord - elif idx == s.len and optLaxStrings in c.config.options: - regs[ra].intVal = 0 else: stackTrace(c, tos, pc, formatErrorIndexBound(idx, s.len-1)) of opcWrArr: diff --git a/doc/advopt.txt b/doc/advopt.txt index b2aa82d2b..18bfde11b 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -101,8 +101,6 @@ Advanced options: --excessiveStackTrace:on|off stack traces use full file paths --stackTraceMsgs:on|off enable user defined stack frame msgs via `setFrameMsg` - --laxStrings:on|off when turned on, accessing the zero terminator in - strings is allowed; only for backwards compatibility --nilseqs:on|off allow 'nil' for strings/seqs for backwards compatibility --seqsv2:on|off use the new string/seq implementation based on From 4cb41f53f06995709d8f00587fbcaa34eb555b7b Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 23 Jun 2020 14:17:12 +0200 Subject: [PATCH 0757/4254] Add testcase for #14440 (#14771) --- tests/borrow/tborrow.nim | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/borrow/tborrow.nim b/tests/borrow/tborrow.nim index ee0d0194d..9c403021e 100644 --- a/tests/borrow/tborrow.nim +++ b/tests/borrow/tborrow.nim @@ -1,5 +1,6 @@ discard """ - output: "4887 true" + output: '''4887 true +0.5''' """ # test the new borrow feature that works with generics: @@ -19,3 +20,16 @@ proc `$`(x: DI): string {.borrow.} proc `$`(x: DF): string {.borrow.} echo 4544.DI ++ 343.DI, " ", (4.5.DF ++ 0.5.DF).float == 5.0 + +# issue #14440 + +type Radians = distinct float64 + +func `-=`(a: var Radians, b: Radians) {.borrow.} + +var a = Radians(1.5) +let b = Radians(1.0) + +a -= b + +echo a.float64 From 16bdc547b7726c3abfcc763d2410d5cd39481a54 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 23 Jun 2020 15:17:17 +0200 Subject: [PATCH 0758/4254] fixes #14760 (#14769) --- lib/pure/memfiles.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index dab5483e4..09db80936 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -445,7 +445,7 @@ iterator lines*(mfile: MemFile, buf: var TaintedString, delim = '\l', for ms in memSlices(mfile, delim, eat): setLen(buf.string, ms.size) if ms.size > 0: - copyMem(addr buf[0], ms.data, ms.size) + copyMem(addr string(buf)[0], ms.data, ms.size) yield buf iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): TaintedString {.inline.} = From 685d03e2e0af156021b63b33575ad6d26dc6a228 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 23 Jun 2020 15:20:31 +0200 Subject: [PATCH 0759/4254] Correct changelog (#14775) These switches were removed, not deprecated :) --- changelog.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 96841fc50..abb761b4f 100644 --- a/changelog.md +++ b/changelog.md @@ -218,9 +218,8 @@ proc mydiv(a, b): int {.raises: [].} = - `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified (with or without `--project`); passing `--project` now automatically generates an index and enables search. See [docgen](docgen.html#introduction-quick-start) for details. -- Deprecated `--oldNewlines` and its Deprecated code cleaned out. - -- Deprecated `--laxStrings` for mutating the internal zero terminator on strings and its Deprecated code cleaned out. +- Removed the `--oldNewlines` switch. +- Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. ## Tool changes From 881d1ee57b99c42e016fe0f8d2ca64a253f75960 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 23 Jun 2020 16:15:37 +0200 Subject: [PATCH 0760/4254] fix #14750, don't allocate too much in newWideCString (#14773) --- lib/system/widestrs.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index a7a514446..aabcbdc90 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -56,7 +56,7 @@ else: WideCStringObj* = WideCString template createWide(a; L) = - unsafeNew(a, L * 4 + 2) + unsafeNew(a, L) proc ord(arg: Utf16Char): int = int(cast[uint16](arg)) @@ -138,8 +138,7 @@ iterator runes(s: cstring, L: int): int = yield result proc newWideCString*(source: cstring, L: int): WideCStringObj = - createWide(result, L * 4 + 2) - #result = cast[wideCString](alloc(L * 4 + 2)) + createWide(result, L * 2 + 2) var d = 0 for ch in runes(source, L): From 6bf2990f6639726afa96cabfe1a5338f491743e0 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 23 Jun 2020 20:36:59 +0200 Subject: [PATCH 0761/4254] [backport] fix #14748, move gdb files to other section of installer.ini (#14772) --- compiler/installer.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index 9718dbb94..c59b9a2ea 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -112,13 +112,13 @@ Files: "bin/*.dll" [UnixBin] Files: "bin/nim" -Files: "bin/nim-gdb" -Files: "bin/nim-gdb.bash" [Unix] InstallScript: "yes" UninstallScript: "yes" +Files: "bin/nim-gdb" +Files: "bin/nim-gdb.bash" [InnoSetup] From 9ebbe000a81b735f0bb8350b0897c9d1b0d1f43f Mon Sep 17 00:00:00 2001 From: treeform Date: Tue, 23 Jun 2020 11:37:29 -0700 Subject: [PATCH 0762/4254] Enable fidget in important_packages. (#14742) * Enable fidget in important_packages. Fidget now works with `nimble test` and there is a CI: https://github.com/treeform/fidget/commits/master * Add libx11-dev to make fidget compile. * try libxcursor-dev * try xorg-dev --- .github/workflows/ci_packages.yml | 2 +- testament/important_packages.nim | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 6cf41aa8e..8a1a8a81f 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -33,7 +33,7 @@ jobs: DEBIAN_FRONTEND='noninteractive' \ sudo apt-fast install --no-install-recommends -yq \ libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ - valgrind libc6-dbg libblas-dev + valgrind libc6-dbg libblas-dev xorg-dev - name: 'Install dependencies (macOS)' if: runner.os == 'macOS' run: brew install boehmgc make sfml gtk+3 diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 8974b78ec..8cb277d5f 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -39,8 +39,7 @@ pkg1 "delaunay" pkg1 "docopt" pkg1 "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg1 "elvis" -# pkg1 "fidget", true, "nim c -d:release -r tests/runNative.nim" - # Error: cannot open 'tests/runNative.nim' +pkg1 "fidget", true pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "ggplotnim", true, "nim c -d:noCairo -r -d:nimWorkaround14447 -d:nimHasWorkaround14720 tests/tests.nim" From a3b95162499833c17699e0d22c44d3dd09a1ef54 Mon Sep 17 00:00:00 2001 From: ktamp Date: Tue, 23 Jun 2020 23:31:41 +0300 Subject: [PATCH 0763/4254] readLine: Unicode support for Windows console When input is read from the Windows console, input encoding is UTF16. This is translated internally to UTF8. --- lib/system/io.nim | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/system/io.nim b/lib/system/io.nim index 482057214..330b67dff 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -14,6 +14,11 @@ include inclrtl import std/private/since import formatfloat +when defined(windows) and not defined(useWinAnsi): + import os + import system/widestrs + import terminal + # ----------------- IO Part ------------------------------------------------ type CFile {.importc: "FILE", header: "", @@ -352,6 +357,37 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], proc c_memchr(s: pointer, c: cint, n: csize_t): pointer {. importc: "memchr", header: "".} + when defined(windows) and not defined(useWinAnsi): + proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, + nNumberOfCharsToRead: uint32, + lpNumberOfCharsRead: ptr uint32, + pInputControl: pointer): int32 {. + stdcall, dynlib: "kernel32", importc: "ReadConsoleW".} + + if f.isatty: + if c_feof(f) < 0: + return false + const numberOfCharsToRead = 2048 + var numberOfCharsRead = 0'u32 + var buffer = newWideCString("", numberOfCharsToRead) + if readConsole(getOsFileHandle(f), addr(buffer[0]), + numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: + var error = osLastError() + raiseEIO("error: " & $error & " `" & osErrorMsg(error) & "`") + # input always ends with "\r\n" + numberOfCharsRead -= 2 + # handle Ctrl+Z as EOF + for i in 0'u32.. Date: Wed, 24 Jun 2020 02:36:41 +0400 Subject: [PATCH 0764/4254] Fix Norm test path. (#14779) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 8cb277d5f..501d9c22d 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -91,7 +91,7 @@ pkg2 "nimwc", true, "nim c nimwc.nim" # pkg2 "nimx", true, "nim c --threads:on test/main.nim" # pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" # pending https://github.com/timotheecour/Nim/issues/167 or new git tag for nitter -# pkg2 "norm", true, "nim c -r tests/tsqlite.nim" +pkg2 "norm", true, "nim c -r tests/tsqliterows.nim" # pending https://github.com/timotheecour/Nim/issues/167 pkg2 "npeg", false, "nimble testarc" pkg2 "numericalnim", true, "nim c -r tests/test_integrate.nim" From 2220ff70beea0a72c61f9363cb8f0102ea317e6e Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 24 Jun 2020 13:16:40 +0200 Subject: [PATCH 0765/4254] cleanup [ci skip] --- testament/important_packages.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 501d9c22d..3d30b40e2 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -92,7 +92,6 @@ pkg2 "nimwc", true, "nim c nimwc.nim" # pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" # pending https://github.com/timotheecour/Nim/issues/167 or new git tag for nitter pkg2 "norm", true, "nim c -r tests/tsqliterows.nim" - # pending https://github.com/timotheecour/Nim/issues/167 pkg2 "npeg", false, "nimble testarc" pkg2 "numericalnim", true, "nim c -r tests/test_integrate.nim" pkg2 "optionsutils" From 302e3b7f447d2ab776030a720441694a374f59c6 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 24 Jun 2020 17:27:46 +0200 Subject: [PATCH 0766/4254] CI: Install the pkg we cloned (#14770) --- lib/std/private/nimbleutils.nim | 32 ------------------- testament/categories.nim | 53 ++++++++++++++++++++++---------- testament/important_packages.nim | 17 +++++----- 3 files changed, 45 insertions(+), 57 deletions(-) delete mode 100644 lib/std/private/nimbleutils.nim diff --git a/lib/std/private/nimbleutils.nim b/lib/std/private/nimbleutils.nim deleted file mode 100644 index 297fb9695..000000000 --- a/lib/std/private/nimbleutils.nim +++ /dev/null @@ -1,32 +0,0 @@ -##[ -internal API for now, API subject to change -]## - -import std/[os,osproc,sugar,strutils] - -proc actionRetry*(maxRetry: int, backoffDuration: float, action: proc(): bool): bool = - ## retry `action` up to `maxRetry` times with exponential backoff and initial - ## duraton of `backoffDuration` seconds - var t = backoffDuration - for i in 0.. Date: Wed, 24 Jun 2020 09:00:35 -0700 Subject: [PATCH 0767/4254] fix #10343 (#14789) --- tests/exception/t9657.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/exception/t9657.nim b/tests/exception/t9657.nim index ea93aff59..514d29353 100644 --- a/tests/exception/t9657.nim +++ b/tests/exception/t9657.nim @@ -1,11 +1,12 @@ discard """ action: run exitcode: 1 - target: "c" + target: "c cpp" disabled: "openbsd" disabled: "netbsd" """ -# todo: remove `target: "c"` workaround once #10343 is properly fixed + close stdmsg const m = "exception!" +# see #10343 for details on this test discard writeBuffer(stdmsg, cstring(m), m.len) From a3ae52de1a1a1e0556f235eadf3279db44ca3113 Mon Sep 17 00:00:00 2001 From: Euan Date: Wed, 24 Jun 2020 17:02:18 +0100 Subject: [PATCH 0768/4254] Fix #14715 - detect tool fails on FreeBSD (#14716) --- tools/detect/detect.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index a10794555..fda122002 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -14,7 +14,7 @@ # compilation. import os, strutils -when defined(openbsd): +when defined(openbsd) or defined(freebsd) or defined(netbsd): const cc = "cc -o $# $#.c" cpp = "cc -E -o $#.i $#.c" @@ -98,8 +98,8 @@ proc main = f.write(nimfile % [other]) close(f) - let cCompile = when defined(openbsd): ccLinkMath else: cc - let cppCompile = when defined(openbsd): cppLinkMath else: cpp + let cCompile = defined(openbsd) or defined(freebsd) or defined(netbsd): ccLinkMath else: cc + let cppCompile = defined(openbsd) or defined(freebsd) or defined(netbsd): cppLinkMath else: cpp if not myExec(cCompile % [gen.addFileExt(ExeExt), gen]): quit(1) if not myExec(cppCompile % [pre.addFileExt(ExeExt), pre]): quit(1) when defined(windows): From 37081e29458d9fba906e162c690d9c2d56cffeca Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 24 Jun 2020 09:03:01 -0700 Subject: [PATCH 0769/4254] fromJson: support object variants (#14694) --- lib/std/jsonutils.nim | 88 ++++++++++++++++++++++++++++++------- tests/stdlib/tjsonutils.nim | 53 ++++++++++++++++++++++ 2 files changed, 126 insertions(+), 15 deletions(-) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index be3d7e7c8..22f2a7a89 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -30,10 +30,59 @@ add a way to customize serialization, for eg: * handle cyclic references, using a cache of already visited addresses ]# +import std/macros + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} template distinctBase[T](a: T): untyped = distinctBase(type(a))(a) +macro getDiscriminants(a: typedesc): seq[string] = + ## return the discriminant keys + # candidate for std/typetraits + var a = a.getTypeImpl + doAssert a.kind == nnkBracketExpr + let sym = a[1] + let t = sym.getTypeImpl + let t2 = t[2] + doAssert t2.kind == nnkRecList + result = newTree(nnkBracket) + for ti in t2: + if ti.kind == nnkRecCase: + let key = ti[0][0] + let typ = ti[0][1] + result.add newLit key.strVal + if result.len > 0: + result = quote do: + @`result` + else: + result = quote do: + seq[string].default + +macro initCaseObject(a: typedesc, fun: untyped): untyped = + ## does the minimum to construct a valid case object, only initializing + ## the discriminant fields; see also `getDiscriminants` + # maybe candidate for std/typetraits + var a = a.getTypeImpl + doAssert a.kind == nnkBracketExpr + let sym = a[1] + let t = sym.getTypeImpl + var t2: NimNode + case t.kind + of nnkObjectTy: t2 = t[2] + of nnkRefTy: t2 = t[0].getTypeImpl[2] + else: doAssert false, $t.kind # xxx `nnkPtrTy` could be handled too + doAssert t2.kind == nnkRecList + result = newTree(nnkObjConstr) + result.add sym + for ti in t2: + if ti.kind == nnkRecCase: + let key = ti[0][0] + let typ = ti[0][1] + let key2 = key.strVal + let val = quote do: + `fun`(`key2`, typedesc[`typ`]) + result.add newTree(nnkExprColonExpr, key, val) + proc checkJsonImpl(cond: bool, condStr: string, msg = "") = if not cond: # just pick 1 exception type for simplicity; other choices would be: @@ -43,6 +92,19 @@ proc checkJsonImpl(cond: bool, condStr: string, msg = "") = template checkJson(cond: untyped, msg = "") = checkJsonImpl(cond, astToStr(cond), msg) +template fromJsonFields(a, b, T, keys) = + checkJson b.kind == JObject, $(b.kind) # we could customize whether to allow JNull + var num = 0 + for key, val in fieldPairs(a): + num.inc + when key notin keys: + if b.hasKey key: + fromJson(val, b[key]) + else: + # we could customize to allow this + checkJson false, $($T, key, b) + checkJson b.len == num, $(b.len, num, $T, b) # could customize + proc fromJson*[T](a: var T, b: JsonNode) = ## inplace version of `jsonTo` #[ @@ -85,25 +147,22 @@ proc fromJson*[T](a: var T, b: JsonNode) = a.setLen b.len for i, val in b.getElems: fromJson(a[i], val) - elif T is object | tuple: - const isNamed = T is object or isNamedTuple(T) - when isNamed: - checkJson b.kind == JObject, $(b.kind) # we could customize whether to allow JNull - var num = 0 - for key, val in fieldPairs(a): - num.inc - if b.hasKey key: - fromJson(val, b[key]) - else: - # we could customize to allow this - checkJson false, $($T, key, b) - checkJson b.len == num, $(b.len, num, $T, b) # could customize + elif T is object: + template fun(key, typ): untyped = + jsonTo(b[key], typ) + a = initCaseObject(T, fun) + const keys = getDiscriminants(T) + fromJsonFields(a, b, T, keys) + elif T is tuple: + when isNamedTuple(T): + fromJsonFields(a, b, T, seq[string].default) else: checkJson b.kind == JArray, $(b.kind) # we could customize whether to allow JNull var i = 0 for val in fields(a): fromJson(val, b[i]) i.inc + checkJson b.len == i, $(b.len, i, $T, b) # could customize else: # checkJson not appropriate here static: doAssert false, "not yet implemented: " & $T @@ -120,8 +179,7 @@ proc toJson*[T](a: T): JsonNode = result = newJObject() for k, v in pairs(a): result[k] = toJson(v) elif T is object | tuple: - const isNamed = T is object or isNamedTuple(T) - when isNamed: + when T is object or isNamedTuple(T): result = newJObject() for k, v in a.fieldPairs: result[k] = toJson(v) else: diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index fca980dc9..0b2ec7179 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -9,6 +9,9 @@ proc testRoundtrip[T](t: T, expected: string) = let j = t.toJson doAssert $j == expected, $j doAssert j.jsonTo(T).toJson == j + var t2: T + t2.fromJson(j) + doAssert t2.toJson == j import tables import strtabs @@ -66,5 +69,55 @@ template fn() = doAssert b2.ord == 1 # explains the `1` testRoundtrip(a): """[1,2,3]""" + block: # case object + type Foo = object + x0: float + case t1: bool + of true: z1: int8 + of false: z2: uint16 + x1: string + testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}""" + testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" + type PFoo = ref Foo + testRoundtrip(PFoo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" + + block: # ref case object + type Foo = ref object + x0: float + case t1: bool + of true: z1: int8 + of false: z2: uint16 + x1: string + testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}""" + testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" + + block: # generic case object + type Foo[T] = ref object + x0: float + case t1: bool + of true: z1: int8 + of false: z2: uint16 + x1: string + testRoundtrip(Foo[float](t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}""" + testRoundtrip(Foo[int](x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}""" + # sanity check: nesting inside a tuple + testRoundtrip((Foo[int](x0: 1.5, t1: false, z2: 6), "foo")): """[{"x0":1.5,"t1":false,"z2":6,"x1":""},"foo"]""" + + block: # case object: 2 discriminants, `when` branch, range discriminant + type Foo[T] = object + case t1: bool + of true: + z1: int8 + of false: + z2: uint16 + when T is float: + case t2: range[0..3] + of 0: z3: int8 + of 2,3: z4: uint16 + else: discard + testRoundtrip(Foo[float](t1: true, z1: 5, t2: 3, z4: 12)): """{"t1":true,"z1":5,"t2":3,"z4":12}""" + testRoundtrip(Foo[int](t1: false, z2: 7)): """{"t1":false,"z2":7}""" + # pending https://github.com/nim-lang/Nim/issues/14698, test with `type Foo[T] = ref object` + static: fn() fn() From 0434aef4cdc1dd018dff702a9edeb19b5073bc05 Mon Sep 17 00:00:00 2001 From: Euan Date: Wed, 24 Jun 2020 17:44:10 +0100 Subject: [PATCH 0770/4254] Patch #14716 - add missing `when` (#14792) --- tools/detect/detect.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index fda122002..841b3a675 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -98,8 +98,8 @@ proc main = f.write(nimfile % [other]) close(f) - let cCompile = defined(openbsd) or defined(freebsd) or defined(netbsd): ccLinkMath else: cc - let cppCompile = defined(openbsd) or defined(freebsd) or defined(netbsd): cppLinkMath else: cpp + let cCompile = when defined(openbsd) or defined(freebsd) or defined(netbsd): ccLinkMath else: cc + let cppCompile = when defined(openbsd) or defined(freebsd) or defined(netbsd): cppLinkMath else: cpp if not myExec(cCompile % [gen.addFileExt(ExeExt), gen]): quit(1) if not myExec(cppCompile % [pre.addFileExt(ExeExt), pre]): quit(1) when defined(windows): From 3e5743d6f72d9953eb97e54c11149c8b77c1062d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 24 Jun 2020 13:31:07 -0700 Subject: [PATCH 0771/4254] add typetraits.elementType (#14780) * add typetraits.elementType * add a test for 0-sized seq --- changelog.md | 1 + lib/pure/typetraits.nim | 12 ++++++++++++ tests/metatype/ttypetraits.nim | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/changelog.md b/changelog.md index abb761b4f..2c7cdeed0 100644 --- a/changelog.md +++ b/changelog.md @@ -114,6 +114,7 @@ - Add `os.normalizeExe`, eg: `koch` => `./koch`. - `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. +- Add `typetraits.elementType` to get element type of an iterable. ## Language changes - In the newruntime it is now allowed to assign to the discriminator field diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 317376405..346ac06d4 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -93,6 +93,18 @@ since (1, 1): type StaticParam*[value: static type] = object ## used to wrap a static value in `genericParams` +since (1, 3, 5): + template elementType*(a: untyped): typedesc = + ## return element type of `a`, which can be any iterable (over which you + ## can iterate) + runnableExamples: + iterator myiter(n: int): auto = + for i in 0.. Date: Wed, 24 Jun 2020 23:32:01 +0300 Subject: [PATCH 0772/4254] Reject casts to builtin typeclasses (#14788) * Closes #14231, closes #14452 * Merge test to tcast.nim --- compiler/semexprs.nim | 2 ++ tests/misc/tcast.nim | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6f267b4eb..a9d45615e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -191,6 +191,8 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = return false if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc: return false + if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass: + return false if conf.selectedGC in {gcArc, gcOrc}: let d = skipTypes(dst, abstractInst) let s = skipTypes(src, abstractInst) diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index a8d1cf306..745b9e221 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -10,15 +10,22 @@ type MyProc3 = proc() #{.closure.} is implicit proc testProc() = echo "Hello World" +template reject(x) = doAssert(not compiles(x)) + proc callPointer(p: pointer) = # can cast to proc(){.cdecl.} let ffunc0 = cast[MyProc](p) # can cast to proc(){.nimcall.} let ffunc1 = cast[MyProc2](p) # cannot cast to proc(){.closure.} - doAssert(not compiles(cast[MyProc3](p))) + reject: cast[MyProc3](p) ffunc0() ffunc1() callPointer(cast[pointer](testProc)) + +reject: discard cast[enum](0) +proc a = echo "hi" + +reject: discard cast[ptr](a) From c6e09e335a63f2a0e3108d40e56b72a3214a045f Mon Sep 17 00:00:00 2001 From: ktamp Date: Thu, 25 Jun 2020 00:22:24 +0300 Subject: [PATCH 0773/4254] readLine: Remove recursive imports --- lib/system/io.nim | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 330b67dff..b550b6b7b 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -14,11 +14,6 @@ include inclrtl import std/private/since import formatfloat -when defined(windows) and not defined(useWinAnsi): - import os - import system/widestrs - import terminal - # ----------------- IO Part ------------------------------------------------ type CFile {.importc: "FILE", header: "", @@ -362,18 +357,44 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], nNumberOfCharsToRead: uint32, lpNumberOfCharsRead: ptr uint32, pInputControl: pointer): int32 {. - stdcall, dynlib: "kernel32", importc: "ReadConsoleW".} + importc: "ReadConsoleW", stdcall, dynlib: "kernel32".} + proc getLastError(): int32 {. + importc: "GetLastError", stdcall, dynlib: "kernel32", sideEffect.} + + proc formatMessageW(dwFlags: int32, lpSource: pointer, + dwMessageId, dwLanguageId: int32, + lpBuffer: pointer, nSize: int32, + arguments: pointer): int32 {. + importc: "FormatMessageW", stdcall, dynlib: "kernel32".} + + proc localFree(p: pointer) {. + importc: "LocalFree", stdcall, dynlib: "kernel32".} + + proc isatty(f: File): bool = + when defined(posix): + proc isatty(fildes: FileHandle): cint {. + importc: "isatty", header: "".} + else: + proc isatty(fildes: FileHandle): cint {. + importc: "_isatty", header: "".} + result = isatty(getFileHandle(f)) != 0'i32 + + # this implies the file is open if f.isatty: - if c_feof(f) < 0: - return false const numberOfCharsToRead = 2048 var numberOfCharsRead = 0'u32 var buffer = newWideCString("", numberOfCharsToRead) if readConsole(getOsFileHandle(f), addr(buffer[0]), numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: - var error = osLastError() - raiseEIO("error: " & $error & " `" & osErrorMsg(error) & "`") + var error = getLastError() + var errorMsg: string + var msgbuf: WideCString + if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, + nil, error, 0, addr(msgbuf), 0, nil) != 0'i32: + errorMsg = $msgbuf + if msgbuf != nil: localFree(cast[pointer](msgbuf)) + raiseEIO("error: " & $error & " `" & errorMsg & "`") # input always ends with "\r\n" numberOfCharsRead -= 2 # handle Ctrl+Z as EOF From 03271593446f72cb99ebe8b68121999ba7ea8021 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Thu, 25 Jun 2020 06:38:08 +0300 Subject: [PATCH 0774/4254] Add test-cases to some fixed issues to close them (#14795) --- tests/async/tasync_misc.nim | 7 +++++++ tests/generics/tgenerics_issues.nim | 18 ++++++++++++++++++ tests/metatype/ttypedesc1.nim | 6 ++++++ tests/misc/tints.nim | 4 ++++ 4 files changed, 35 insertions(+) diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index 29e6faa72..ec1418e8c 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -74,3 +74,10 @@ block: # issue #13899 result = true doAssert waitFor testFooSucceed() doAssert waitFor testFooFails() + +block: # issue #9313 + doAssert compiles(block: + proc a() {.async.} = + echo "Hi" + quit(0) + ) diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index af71a8938..54360f178 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -762,3 +762,21 @@ block t3717: var f: Foo[Foo[int]] discard foo(f) + + + +block: # issue #9458 + type + Option[T] = object + val: T + has: bool + + Bar = object + + proc none(T: typedesc): Option[T] = + discard + + proc foo[T](self: T; x: Option[Bar] = Bar.none) = + discard + + foo(1) diff --git a/tests/metatype/ttypedesc1.nim b/tests/metatype/ttypedesc1.nim index 837c8eccc..549dbc62a 100644 --- a/tests/metatype/ttypedesc1.nim +++ b/tests/metatype/ttypedesc1.nim @@ -60,3 +60,9 @@ reject: reject: foo seq[int], ss +# issue #12398 +reject: + let xs = [int, float, string] + +reject: + let data = @[int, typedesc] diff --git a/tests/misc/tints.nim b/tests/misc/tints.nim index fa3eb42cb..d24cbd4ac 100644 --- a/tests/misc/tints.nim +++ b/tests/misc/tints.nim @@ -77,5 +77,9 @@ block: # Casts to uint testCast(-5'i32, uint8, 251'u8) +# issue #7174 +let c = 1'u +let val = c > 0 +doAssert val echo("Success") #OUT Success From 32f335f594d7007fabe4232a63f51137d7fb6cc1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 24 Jun 2020 23:00:19 -0700 Subject: [PATCH 0775/4254] fix #14802 (#14803) --- compiler/ast.nim | 3 ++- tests/statictypes/tstatictypes.nim | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 40fd40209..b57ee542d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1841,7 +1841,8 @@ proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as" proc findUnresolvedStatic*(n: PNode): PNode = - if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil: + # n.typ == nil: see issue #14802 + if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil: return n for son in n: diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 1aab6e124..2a8d09dbf 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -216,3 +216,10 @@ block: # #12713 proc test(c: static string) = discard #Remove this and it compiles proc test(c: Cell) = discard test Cell() + +block: # issue #14802 + template fn(s: typed): untyped = + proc bar() = discard + 12 + const myConst = static(fn(1)) + doAssert myConst == 12 From 0c56eeda0e3a9a2fd5bb3d9b53f593d6d41fb5d9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 25 Jun 2020 01:22:08 -0700 Subject: [PATCH 0776/4254] expr => untyped; stmt => typed (#14804) * expr => untyped; stmt => typed * changelog + comment --- changelog.md | 1 + compiler/vmdeps.nim | 4 ++-- tests/metatype/ttypetraits.nim | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 2c7cdeed0..07d9b6112 100644 --- a/changelog.md +++ b/changelog.md @@ -221,6 +221,7 @@ proc mydiv(a, b): int {.raises: [].} = See [docgen](docgen.html#introduction-quick-start) for details. - Removed the `--oldNewlines` switch. - Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. +- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is now "typed" instead of "stmt" ## Tool changes diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 6f90b7918..4ba7b23bf 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -93,8 +93,8 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyBool: result = atomicType("bool", mBool) of tyChar: result = atomicType("char", mChar) of tyNil: result = atomicType("nil", mNil) - of tyUntyped: result = atomicType("expr", mExpr) - of tyTyped: result = atomicType("stmt", mStmt) + of tyUntyped: result = atomicType("untyped", mExpr) + of tyTyped: result = atomicType("typed", mStmt) of tyVoid: result = atomicType("void", mVoid) of tyEmpty: result = atomicType("empty", mNone) of tyUncheckedArray: diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 10aa7783d..d0480415e 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -49,6 +49,12 @@ block: # typeToString doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 == "tuple[a: C[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]" + macro fn(): string = + # not 100% sure whether this should even compile; if some PR breaks this test, + # this could be revisited, maybe. + newLit $($getType(untyped), $getType(typed)) + doAssert fn() == """("untyped", "typed")""" + block distinctBase: block: type From 1a0725f022299ab345a34250d37d25498664184a Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 25 Jun 2020 08:28:57 +0000 Subject: [PATCH 0777/4254] koch: add --localdocs to allow building only local docs (#14783) * koch: add --localdocs to allow building only local docs This flag also make koch doc use the passed arguments when building the offline docs. This is useful when generating nightlies as we would want to use --doccmd:skip and also skipping a pass of docgen speed things up drastically (for non-native targets). This flag superseded the undocumented --docslocal. * kochdocs: filter google analytics code from the arg list instead This commit introduce a small PEG expression to filter out the google analytics code before building local docs when --localdocs is not specified. This lets us keep any arguments unrelated to google analytics when building local docs, useful for use with --doccmd:skip --- koch.nim | 20 +++++++++++--------- tools/kochdocs.nim | 23 ++++++++++++++++++----- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/koch.nim b/koch.nim index c1d8df8da..bbcb0e349 100644 --- a/koch.nim +++ b/koch.nim @@ -53,6 +53,8 @@ Options: --latest bundle the installers with a bleeding edge Nimble --stable bundle the installers with a stable Nimble (default) --nim:path use specified path for nim binary + --localdocs[:path] only build local documentations. If a path is not + specified (or empty), the default is used. Possible Commands: boot [options] bootstraps with given command line options distrohelper [bindir] helper for distro packagers @@ -642,7 +644,10 @@ proc showHelp() = when isMainModule: var op = initOptParser() - var latest = false + var + latest = false + localDocsOnly = false + localDocsOut = "" while true: op.next() case op.kind @@ -651,19 +656,16 @@ when isMainModule: of "latest": latest = true of "stable": latest = false of "nim": nimExe = op.val.absolutePath # absolute so still works with changeDir - of "docslocal": - # undocumented for now, allows to rebuild local docs in < 40s as follows: - # `./koch --nim:$nimb --docslocal:htmldocs2 --doccmd:skip --warnings:off --hints:off` - # whereas `./koch docs` takes 190s; useful for development. - doAssert op.val.len > 0 - buildDocsDir(op.cmdLineRest, op.val) - break + of "localdocs": + localDocsOnly = true + if op.val.len > 0: + localDocsOut = op.val.absolutePath else: showHelp() of cmdArgument: case normalize(op.key) of "boot": boot(op.cmdLineRest) of "clean": clean(op.cmdLineRest) - of "doc", "docs": buildDocs(op.cmdLineRest) + of "doc", "docs": buildDocs(op.cmdLineRest, localDocsOnly, localDocsOut) of "doc0", "docs0": # undocumented command for Araq-the-merciful: buildDocs(op.cmdLineRest & gaCode) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index eacfb45ca..d0f8077ed 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,6 +1,6 @@ ## Part of 'koch' responsible for the documentation generation. -import os, strutils, osproc, sets, pathnorm +import os, strutils, osproc, sets, pathnorm, pegs from std/private/globs import nativeToUnixPath, walkDirRecFilter, PathEntry import "../compiler/nimpaths" @@ -182,7 +182,7 @@ lib/system/iterators.nim lib/system/dollars.nim lib/system/widestrs.nim """.splitWhitespace() - + proc follow(a: PathEntry): bool = a.path.lastPathPart notin ["nimcache", "htmldocs", "includes", "deprecated", "genode"] for entry in walkDirRecFilter("lib", follow = follow): @@ -318,6 +318,19 @@ proc buildDocsDir*(args: string, dir: string) = buildDocPackages(args, dir) copyFile(docHackJsSource, dir / docHackJsSource.lastPathPart) -proc buildDocs*(args: string) = - buildDocsDir(args, webUploadOutput / NimVersion) - buildDocsDir("", docHtmlOutput) # no `args` to avoid offline docs containing the 'gaCode'! +proc buildDocs*(args: string, localOnly = false, localOutDir = "") = + let localOutDir = + if localOutDir.len == 0: + docHtmlOutput + else: + localOutDir + + var args = args + + if not localOnly: + buildDocsDir(args, webUploadOutput / NimVersion) + + let gaFilter = peg"@( y'--doc.googleAnalytics:' @(\s / $) )" + args = args.replace(gaFilter) + + buildDocsDir(args, localOutDir) From 0a9a63923060cab29f0d0d9f8dec7fd9a37222e6 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 25 Jun 2020 15:12:30 +0200 Subject: [PATCH 0778/4254] Add testcase for #4796 (#14784) * Add testcase for #4796 * Fix test --- tests/modules/seq.nim | 5 +++++ tests/modules/tseq.nim | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/modules/seq.nim create mode 100644 tests/modules/tseq.nim diff --git a/tests/modules/seq.nim b/tests/modules/seq.nim new file mode 100644 index 000000000..176e44025 --- /dev/null +++ b/tests/modules/seq.nim @@ -0,0 +1,5 @@ +var seq: seq[int] +var b: seq[float] + +echo seq +echo b diff --git a/tests/modules/tseq.nim b/tests/modules/tseq.nim new file mode 100644 index 000000000..22ee48f42 --- /dev/null +++ b/tests/modules/tseq.nim @@ -0,0 +1,8 @@ +discard """ + joinable: false + output: '''@[] +@[] +''' +""" + +import seq From 13193b2964d76e4656a088782b10365c0ffeceed Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 25 Jun 2020 16:55:11 +0200 Subject: [PATCH 0779/4254] turn 'runnableExample' into 'code-block' to make nightlies green This example doesn't work on our nightlies CI. Other procs in this module already use 'code-block'. --- lib/pure/osproc.nim | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 3e3391d52..8be914992 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1446,6 +1446,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## A convenience proc that runs the `command`, and returns its `output` and ## `exitCode`. `env` and `workingDir` params behave as for `startProcess`. ## If `input.len > 0`, it is passed as stdin. + ## ## Note: this could block if `input.len` is greater than your OS's maximum ## pipe buffer size. ## @@ -1456,15 +1457,17 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## * `execProcess proc ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## - runnableExamples: - var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") - import strutils, strtabs - stripLineEnd(result[0]) ## portable way to remove trailing newline, if any - doAssert result == ("12", 0) - doAssert execCmdEx("ls --nonexistant").exitCode != 0 - when defined(posix): - assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) - assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) + ## Example: + ## + ## .. code-block:: Nim + ## var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") + ## import strutils, strtabs + ## stripLineEnd(result[0]) ## portable way to remove trailing newline, if any + ## doAssert result == ("12", 0) + ## doAssert execCmdEx("ls --nonexistant").exitCode != 0 + ## when defined(posix): + ## assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) + ## assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) when (NimMajor, NimMinor, NimPatch) < (1, 3, 5): doAssert input.len == 0 From 41c97e4b70d8d3b67f9080939790c6b9a64a7e74 Mon Sep 17 00:00:00 2001 From: ktamp Date: Fri, 26 Jun 2020 00:31:06 +0300 Subject: [PATCH 0780/4254] readLine: Fix issues with --gc:arc **--gc:arc** defines **nimv2**. This changes the definition of **WideCStringObj**. Also an empty string should be returned in case of EOF. --- lib/system/io.nim | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index b550b6b7b..9f12a1767 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -354,8 +354,8 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], when defined(windows) and not defined(useWinAnsi): proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, - nNumberOfCharsToRead: uint32, - lpNumberOfCharsRead: ptr uint32, + nNumberOfCharsToRead: int32, + lpNumberOfCharsRead: ptr int32, pInputControl: pointer): int32 {. importc: "ReadConsoleW", stdcall, dynlib: "kernel32".} @@ -383,7 +383,7 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], # this implies the file is open if f.isatty: const numberOfCharsToRead = 2048 - var numberOfCharsRead = 0'u32 + var numberOfCharsRead = 0'i32 var buffer = newWideCString("", numberOfCharsToRead) if readConsole(getOsFileHandle(f), addr(buffer[0]), numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0: @@ -393,20 +393,25 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, nil, error, 0, addr(msgbuf), 0, nil) != 0'i32: errorMsg = $msgbuf - if msgbuf != nil: localFree(cast[pointer](msgbuf)) + if msgbuf != nil: + localFree(cast[pointer](msgbuf)) raiseEIO("error: " & $error & " `" & errorMsg & "`") # input always ends with "\r\n" numberOfCharsRead -= 2 # handle Ctrl+Z as EOF - for i in 0'u32.. Date: Thu, 25 Jun 2020 14:45:37 -0700 Subject: [PATCH 0781/4254] Add hasAttribute method to dom.nim. (#14814) See: https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute --- lib/js/dom.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 48d32fc18..c8e10d0f8 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1190,6 +1190,7 @@ proc deleteData*(n: Node, start, len: int) proc focus*(e: Node) proc getAttribute*(n: Node, attr: cstring): cstring proc getAttributeNode*(n: Node, attr: cstring): Node +proc hasAttribute*(n: Node; attr: cstring): bool proc hasChildNodes*(n: Node): bool proc insertData*(n: Node, position: int, data: cstring) proc removeAttribute*(n: Node, attr: cstring) From 49fcda33306227466161b31e0f8e0a21cbecdfaf Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 25 Jun 2020 19:10:22 -0700 Subject: [PATCH 0782/4254] followup after https://github.com/Vindaar/ggplotnim/pull/74 wrt #14447 lent iterators (#14817) * followup after https://github.com/Vindaar/ggplotnim/pull/74 wrt #14447 lent iterators * ggplotnim: remove -d:nimHasWorkaround14720 --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index bc7f77cc4..352ce2cd7 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -42,7 +42,7 @@ pkg1 "elvis" pkg1 "fidget", true pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" -pkg1 "ggplotnim", true, "nim c -d:noCairo -r -d:nimWorkaround14447 -d:nimHasWorkaround14720 tests/tests.nim" +pkg1 "ggplotnim", true, "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" pkg1 "glob" pkg1 "gnuplot" From 4dfb062f4dda5e8491867dc817c4b499f91ee5f7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 26 Jun 2020 01:40:34 -0700 Subject: [PATCH 0783/4254] update contributing.rst and docstyle.rst: refer to a bug via `bug #1234` + other guidelines (#14796) * add a testing convention in nep1 * misc updates to contributing.rst and docstyle.rst * address comments --- doc/contributing.rst | 64 +++++++++++++++++++++++++++++--------------- doc/docstyle.rst | 9 ++++++- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 39a44fb2b..a4baaef05 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -18,15 +18,23 @@ See `codeowners `_ for more details. Writing tests ============= -There are 3 types of tests: +There are 4 types of tests: 1. ``runnableExamples`` documentation comment tests, ran by ``nim doc mymod.nim`` These end up in documentation and ensure documentation stays in sync with code. -2. tests in ``when isMainModule:`` block, ran by ``nim c mymod.nim`` - ``nimble test`` also typially runs these in external nimble packages. +2. separate test files, e.g.: ``tests/stdlib/tos.nim``. + In nim repo, `testament` (see below) runs all `$nim/tests/*/t*.nim` test files; + for nimble packages, see https://github.com/nim-lang/nimble#tests. -3. testament tests, e.g.: ``tests/stdlib/tos.nim`` (only used for Nim repo). +3. (deprecated) tests in ``when isMainModule:`` block, ran by ``nim r mymod.nim``. + ``nimble test`` can run those in nimble packages when specified in a + `task "test"`. + +4. (not preferred) `.. code-block:: nim` RST snippets; these should only be used in rst sources, + in nim sources `runnableExamples` should now always be preferred to those for + several reasons (cleaner syntax, syntax highlights, batched testing, and + `rdoccmd` allows customization). Not all the tests follow the convention here, feel free to change the ones that don't. Always leave the code cleaner than you found it. @@ -34,31 +42,43 @@ that don't. Always leave the code cleaner than you found it. Stdlib ------ -If you change the stdlib (anything under ``lib/``, e.g. ``lib/pure/os.nim``), -put a test in the file you changed. Add the tests under a ``when isMainModule:`` -condition so they only get executed when the tester is building the -file. Each test should be in a separate ``block:`` statement, such that +Each stdlib module (anything under ``lib/``, e.g. ``lib/pure/os.nim``) should +preferably have a corresponding separate test file, eg `tests/stdlib/tos.nim`. +The old convention was to add a ``when isMainModule:`` block in the source file, +which only gets executed when the tester is building the file. + +Each test should be in a separate ``block:`` statement, such that each has its own scope. Use boolean conditions and ``doAssert`` for the -testing by itself, don't rely on echo statements or similar. +testing by itself, don't rely on echo statements or similar; in particular avoid +things like `echo "done"`. Sample test: .. code-block:: nim - when isMainModule: - block: # newSeqWith tests - var seq2D = newSeqWith(4, newSeq[bool](2)) - seq2D[0][0] = true - seq2D[1][0] = true - seq2D[0][1] = true - doAssert seq2D == @[@[true, true], @[true, false], - @[false, false], @[false, false]] - # doAssert with `not` can now be done as follows: - doAssert not (1 == 2) + block: # bug #1234 + static: doAssert 1+1 == 2 -Newer tests tend to be run via ``testament`` rather than via ``when isMainModule:``, -e.g. ``tests/stdlib/tos.nim``; this allows additional features such as custom -compiler flags; for more details see below. + block: # bug #1235 + var seq2D = newSeqWith(4, newSeq[bool](2)) + seq2D[0][0] = true + seq2D[1][0] = true + seq2D[0][1] = true + doAssert seq2D == @[@[true, true], @[true, false], + @[false, false], @[false, false]] + # doAssert with `not` can now be done as follows: + doAssert not (1 == 2) + +Always refer to a github issue using the following exact syntax: `bug #1234` as shown +above, so that it's consistent and easier to search or for tooling. Some browser +extensions (eg https://github.com/sindresorhus/refined-github) will even turn those +in clickable links when it works. + +Rationale for using a separate test file instead of `when isMainModule:` block: +* allows custom compiler flags or testing options (see details below) +* faster CI since they can be joined in `megatest` (combined into a single test) +* avoids making the parser do un-necessary work when a source file is merely imported +* avoids mixing source and test code when reporting line of code statistics or code coverage Compiler -------- diff --git a/doc/docstyle.rst b/doc/docstyle.rst index f0785bc0a..70ded0689 100644 --- a/doc/docstyle.rst +++ b/doc/docstyle.rst @@ -4,10 +4,17 @@ Documentation Style General Guidelines ------------------ +* See also `nep1`_ which should probably be merged here. * Authors should document anything that is exported; documentation for private procs can be useful too (visible via ``nim doc --docInternal foo.nim``). -* Within documentation, a period (`.`) should follow each sentence (or sentence fragment) in a comment block. The documentation may be limited to one sentence fragment, but if multiple sentences are within the documentation, each sentence after the first should be complete and in present tense. +* Within documentation, a period (`.`) should follow each sentence (or sentence fragment) in a comment block. + The documentation may be limited to one sentence fragment, but if multiple sentences are within the documentation, + each sentence after the first should be complete and in present tense. * Documentation is parsed as a custom ReStructuredText (RST) with partial markdown support. +* In nim sources, prefer single backticks to double backticks since it's simpler + and `nim doc` supports it (even in rst files with `nim rst2html`). +* In nim sources, for links, prefer `[link text](link.html)` to ``` `link text`_ ``` + since the syntax is simpler and markdown is more common (likewise, `nim rst2html` also supports it in rst files). .. code-block:: nim From f926dc53f127cb7fc26daf35e0de38612a512552 Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 26 Jun 2020 11:15:21 -0700 Subject: [PATCH 0784/4254] Add all missing css properties to dom.nim. (#14825) * Add all missing css properties * remove extra space --- lib/js/dom.nim | 274 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 270 insertions(+), 4 deletions(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index c8e10d0f8..262c0daad 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -371,19 +371,73 @@ type Style* = ref StyleObj StyleObj {.importc.} = object of RootObj + alignContent*: cstring + alignItems*: cstring + alignSelf*: cstring + all*: cstring + animation*: cstring + animationDelay*: cstring + animationDirection*: cstring + animationDuration*: cstring + animationFillMode*: cstring + animationIterationCount*: cstring + animationName*: cstring + animationPlayState*: cstring + animationTimingFunction*: cstring + backdropFilter*: cstring + backfaceVisibility*: cstring background*: cstring backgroundAttachment*: cstring + backgroundBlendMode*: cstring + backgroundClip*: cstring backgroundColor*: cstring backgroundImage*: cstring + backgroundOrigin*: cstring backgroundPosition*: cstring backgroundRepeat*: cstring backgroundSize*: cstring + blockSize*: cstring border*: cstring + borderBlock*: cstring + borderBlockColor*: cstring + borderBlockEnd*: cstring + borderBlockEndColor*: cstring + borderBlockEndStyle*: cstring + borderBlockEndWidth*: cstring + borderBlockStart*: cstring + borderBlockStartColor*: cstring + borderBlockStartStyle*: cstring + borderBlockStartWidth*: cstring + borderBlockStyle*: cstring + borderBlockWidth*: cstring borderBottom*: cstring borderBottomColor*: cstring + borderBottomLeftRadius*: cstring + borderBottomRightRadius*: cstring borderBottomStyle*: cstring borderBottomWidth*: cstring + borderCollapse*: cstring borderColor*: cstring + borderEndEndRadius*: cstring + borderEndStartRadius*: cstring + borderImage*: cstring + borderImageOutset*: cstring + borderImageRepeat*: cstring + borderImageSlice*: cstring + borderImageSource*: cstring + borderImageWidth*: cstring + borderInline*: cstring + borderInlineColor*: cstring + borderInlineEnd*: cstring + borderInlineEndColor*: cstring + borderInlineEndStyle*: cstring + borderInlineEndWidth*: cstring + borderInlineStart*: cstring + borderInlineStartColor*: cstring + borderInlineStartStyle*: cstring + borderInlineStartWidth*: cstring + borderInlineStyle*: cstring + borderInlineWidth*: cstring borderLeft*: cstring borderLeftColor*: cstring borderLeftStyle*: cstring @@ -393,86 +447,298 @@ type borderRightColor*: cstring borderRightStyle*: cstring borderRightWidth*: cstring + borderSpacing*: cstring + borderStartEndRadius*: cstring + borderStartStartRadius*: cstring borderStyle*: cstring borderTop*: cstring borderTopColor*: cstring + borderTopLeftRadius*: cstring + borderTopRightRadius*: cstring borderTopStyle*: cstring borderTopWidth*: cstring borderWidth*: cstring bottom*: cstring - boxSizing*: cstring + boxDecorationBreak*: cstring boxShadow*: cstring + boxSizing*: cstring + breakAfter*: cstring + breakBefore*: cstring + breakInside*: cstring captionSide*: cstring + caretColor*: cstring clear*: cstring clip*: cstring clipPath*: cstring color*: cstring + colorAdjust*: cstring + columnCount*: cstring + columnFill*: cstring + columnGap*: cstring + columnRule*: cstring + columnRuleColor*: cstring + columnRuleStyle*: cstring + columnRuleWidth*: cstring + columnSpan*: cstring + columnWidth*: cstring + columns*: cstring + contain*: cstring + content*: cstring + counterIncrement*: cstring + counterReset*: cstring + counterSet*: cstring cursor*: cstring direction*: cstring display*: cstring emptyCells*: cstring + filter*: cstring + flex*: cstring + flexBasis*: cstring + flexDirection*: cstring + flexFlow*: cstring + flexGrow*: cstring + flexShrink*: cstring + flexWrap*: cstring cssFloat*: cstring font*: cstring fontFamily*: cstring + fontFeatureSettings*: cstring + fontKerning*: cstring + fontLanguageOverride*: cstring + fontOpticalSizing*: cstring fontSize*: cstring + fontSizeAdjust*: cstring fontStretch*: cstring fontStyle*: cstring + fontSynthesis*: cstring fontVariant*: cstring + fontVariantAlternates*: cstring + fontVariantCaps*: cstring + fontVariantEastAsian*: cstring + fontVariantLigatures*: cstring + fontVariantNumeric*: cstring + fontVariantPosition*: cstring + fontVariationSettings*: cstring fontWeight*: cstring + gap*: cstring + grid*: cstring + gridArea*: cstring + gridAutoColumns*: cstring + gridAutoFlow*: cstring + gridAutoRows*: cstring + gridColumn*: cstring + gridColumnEnd*: cstring + gridColumnStart*: cstring + gridRow*: cstring + gridRowEnd*: cstring + gridRowStart*: cstring + gridTemplate*: cstring + gridTemplateAreas*: cstring + gridTemplateColumns*: cstring + gridTemplateRows*: cstring + hangingPunctuation*: cstring height*: cstring + hyphens*: cstring + imageOrientation*: cstring + imageRendering*: cstring + inlineSize*: cstring + inset*: cstring + insetBlock*: cstring + insetBlockEnd*: cstring + insetBlockStart*: cstring + insetInline*: cstring + insetInlineEnd*: cstring + insetInlineStart*: cstring + isolation*: cstring + justifyContent*: cstring + justifyItems*: cstring + justifySelf*: cstring left*: cstring letterSpacing*: cstring + lineBreak*: cstring lineHeight*: cstring listStyle*: cstring listStyleImage*: cstring listStylePosition*: cstring listStyleType*: cstring margin*: cstring + marginBlock*: cstring + marginBlockEnd*: cstring + marginBlockStart*: cstring marginBottom*: cstring + marginInline*: cstring + marginInlineEnd*: cstring + marginInlineStart*: cstring marginLeft*: cstring marginRight*: cstring marginTop*: cstring + mask*: cstring + maskBorder*: cstring + maskBorderMode*: cstring + maskBorderOutset*: cstring + maskBorderRepeat*: cstring + maskBorderSlice*: cstring + maskBorderSource*: cstring + maskBorderWidth*: cstring + maskClip*: cstring + maskComposite*: cstring + maskImage*: cstring + maskMode*: cstring + maskOrigin*: cstring + maskPosition*: cstring + maskRepeat*: cstring + maskSize*: cstring + maskType*: cstring + maxBlockSize*: cstring maxHeight*: cstring + maxInlineSize*: cstring maxWidth*: cstring + minBlockSize*: cstring minHeight*: cstring + minInlineSize*: cstring minWidth*: cstring + mixBlendMode*: cstring + objectFit*: cstring + objectPosition*: cstring + offset*: cstring + offsetAnchor*: cstring + offsetDistance*: cstring + offsetPath*: cstring + offsetRotate*: cstring opacity*: cstring + order*: cstring + orphans*: cstring outline*: cstring + outlineColor*: cstring + outlineOffset*: cstring + outlineStyle*: cstring + outlineWidth*: cstring overflow*: cstring + overflowAnchor*: cstring + overflowBlock*: cstring + overflowInline*: cstring + overflowWrap*: cstring overflowX*: cstring overflowY*: cstring + overscrollBehavior*: cstring + overscrollBehaviorBlock*: cstring + overscrollBehaviorInline*: cstring + overscrollBehaviorX*: cstring + overscrollBehaviorY*: cstring padding*: cstring + paddingBlock*: cstring + paddingBlockEnd*: cstring + paddingBlockStart*: cstring paddingBottom*: cstring + paddingInline*: cstring + paddingInlineEnd*: cstring + paddingInlineStart*: cstring paddingLeft*: cstring paddingRight*: cstring paddingTop*: cstring pageBreakAfter*: cstring pageBreakBefore*: cstring + pageBreakInside*: cstring + paintOrder*: cstring + perspective*: cstring + perspectiveOrigin*: cstring + placeContent*: cstring + placeItems*: cstring + placeSelf*: cstring pointerEvents*: cstring position*: cstring + quotes*: cstring resize*: cstring right*: cstring + rotate*: cstring + rowGap*: cstring + scale*: cstring + scrollBehavior*: cstring + scrollMargin*: cstring + scrollMarginBlock*: cstring + scrollMarginBlockEnd*: cstring + scrollMarginBlockStart*: cstring + scrollMarginBottom*: cstring + scrollMarginInline*: cstring + scrollMarginInlineEnd*: cstring + scrollMarginInlineStart*: cstring + scrollMarginLeft*: cstring + scrollMarginRight*: cstring + scrollMarginTop*: cstring + scrollPadding*: cstring + scrollPaddingBlock*: cstring + scrollPaddingBlockEnd*: cstring + scrollPaddingBlockStart*: cstring + scrollPaddingBottom*: cstring + scrollPaddingInline*: cstring + scrollPaddingInlineEnd*: cstring + scrollPaddingInlineStart*: cstring + scrollPaddingLeft*: cstring + scrollPaddingRight*: cstring + scrollPaddingTop*: cstring + scrollSnapAlign*: cstring + scrollSnapStop*: cstring + scrollSnapType*: cstring scrollbar3dLightColor*: cstring scrollbarArrowColor*: cstring scrollbarBaseColor*: cstring + scrollbarColor*: cstring scrollbarDarkshadowColor*: cstring scrollbarFaceColor*: cstring scrollbarHighlightColor*: cstring scrollbarShadowColor*: cstring scrollbarTrackColor*: cstring + scrollbarWidth*: cstring + shapeImageThreshold*: cstring + shapeMargin*: cstring + shapeOutside*: cstring + tabSize*: cstring tableLayout*: cstring textAlign*: cstring + textAlignLast*: cstring + textCombineUpright*: cstring textDecoration*: cstring + textDecorationColor*: cstring + textDecorationLine*: cstring + textDecorationSkipInk*: cstring + textDecorationStyle*: cstring + textDecorationThickness*: cstring + textEmphasis*: cstring + textEmphasisColor*: cstring + textEmphasisPosition*: cstring + textEmphasisStyle*: cstring textIndent*: cstring + textJustify*: cstring + textOrientation*: cstring + textOverflow*: cstring + textRendering*: cstring + textShadow*: cstring textTransform*: cstring - transform*: cstring + textUnderlineOffset*: cstring + textUnderlinePosition*: cstring top*: cstring + touchAction*: cstring + transform*: cstring + transformBox*: cstring + transformOrigin*: cstring + transformStyle*: cstring + transition*: cstring + transitionDelay*: cstring + transitionDuration*: cstring + transitionProperty*: cstring + transitionTimingFunction*: cstring + translate*: cstring + unicodeBidi*: cstring verticalAlign*: cstring visibility*: cstring - width*: cstring whiteSpace*: cstring + widows*: cstring + width*: cstring + willChange*: cstring + wordBreak*: cstring wordSpacing*: cstring - zIndex*: int + writingMode*: cstring + zIndex*: cstring EventPhase* = enum None = 0, From 70b07edf42d5bc5296bfc02769846d9d10069213 Mon Sep 17 00:00:00 2001 From: Sizhe Zhao Date: Sat, 27 Jun 2020 18:11:29 +0800 Subject: [PATCH 0785/4254] Fix missing comma (#14829) --- doc/nep1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nep1.rst b/doc/nep1.rst index 35b1a1f62..75343c85b 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -267,7 +267,7 @@ Conventions for multi-line statements and expressions EventCallback = proc (timeReceived: Time, errorCode: int, event: Event, output: var string) - proc lotsOfArguments(argOne: string, argTwo: int, argThree: float + proc lotsOfArguments(argOne: string, argTwo: int, argThree: float, argFour: proc(), argFive: bool): int {.heyLookALongPragma.} = From fdb37400cba234938a27cf158b6f4cf3ac57d689 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 27 Jun 2020 15:58:19 +0200 Subject: [PATCH 0786/4254] Testament: Reenable arraymancer (#14831) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 352ce2cd7..972bb3faa 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -11,7 +11,7 @@ var packages2*: seq[tuple[name, cmd: string; hasDeps: bool; url: string, useHead # packages A-M pkg1 "alea", true pkg1 "argparse" -# pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" +pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" pkg1 "asyncmysql", true pkg1 "awk", true From 90808877c54a3822a978124f39f470ea95e37d4d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 27 Jun 2020 07:51:17 -0700 Subject: [PATCH 0787/4254] testament: generic N-fold batching: windows CI 37mn=>16m (#14823) * testament: run CI faster thanks to batching * move ta_in, tstdin into existing tosproc * move ta_out,tafalse,texitcode,tstderr into existing tosproc * joinable osproc * move tstdout into existing tosproc * spec: batchable; fix tests * fixup --- azure-pipelines.yml | 12 +++- koch.nim | 7 ++- lib/nimhcr.nim | 4 ++ lib/nimrtl.nim | 4 ++ testament/categories.nim | 5 +- testament/specs.nim | 23 ++++++++ testament/testament.nim | 18 +++++- tests/osproc/ta_in.nim | 9 --- tests/osproc/ta_out.nim | 33 ----------- tests/osproc/tafalse.nim | 7 --- tests/osproc/texecps.nim | 4 ++ tests/osproc/texitcode.nim | 26 --------- tests/osproc/tstderr.nim | 37 ------------ tests/osproc/tstdin.nim | 17 ------ tests/osproc/tstdout.nim | 31 ---------- tests/stdlib/tosproc.nim | 116 ++++++++++++++++++++++++++++++++----- 16 files changed, 172 insertions(+), 181 deletions(-) delete mode 100644 tests/osproc/ta_in.nim delete mode 100644 tests/osproc/ta_out.nim delete mode 100644 tests/osproc/tafalse.nim delete mode 100644 tests/osproc/texitcode.nim delete mode 100644 tests/osproc/tstderr.nim delete mode 100644 tests/osproc/tstdin.nim delete mode 100644 tests/osproc/tstdout.nim diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6ec6d0b95..fd8b2eea8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -27,9 +27,19 @@ jobs: vmImage: 'macOS-10.15' CPU: amd64 NIM_COMPILE_TO_CPP: true - Windows_amd64: + Windows_amd64_batch0_3: vmImage: 'windows-2019' CPU: amd64 + # see also: `NIM_TEST_PACKAGES` + NIM_TESTAMENT_BATCH: "0_3" + Windows_amd64_batch1_3: + vmImage: 'windows-2019' + CPU: amd64 + NIM_TESTAMENT_BATCH: "1_3" + Windows_amd64_batch2_3: + vmImage: 'windows-2019' + CPU: amd64 + NIM_TESTAMENT_BATCH: "2_3" pool: vmImage: $(vmImage) diff --git a/koch.nim b/koch.nim index bbcb0e349..e279d76de 100644 --- a/koch.nim +++ b/koch.nim @@ -548,7 +548,12 @@ proc runCI(cmd: string) = execFold("Compile tester", "nim c -d:nimCoroutines --os:genode -d:posix --compileOnly testament/testament") # main bottleneck here - execFold("Run tester", "nim c -r -d:nimCoroutines testament/testament --pedantic all -d:nimCoroutines") + # xxx: even though this is the main bottlneck, we could use same code to batch the other tests + #[ + BUG: with initOptParser, `--batch:'' all` interprets `all` as the argument of --batch + ]# + execFold("Run tester", "nim c -r -d:nimCoroutines testament/testament --pedantic --batch:$1 all -d:nimCoroutines" % ["NIM_TESTAMENT_BATCH".getEnv("_")]) + block CT_FFI: when defined(posix): # windows can be handled in future PR's execFold("nimble install -y libffi", "nimble install -y libffi") diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 372ee1973..89bece6dc 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -1,3 +1,7 @@ +discard """ +batchable: false +""" + # # # Nim's Runtime Library diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim index 7ec5eb981..a2a10c6bd 100644 --- a/lib/nimrtl.nim +++ b/lib/nimrtl.nim @@ -1,3 +1,7 @@ +discard """ +batchable: false +""" + # # # Nim's Runtime Library diff --git a/testament/categories.nim b/testament/categories.nim index d4e6a0803..4dfd42fd2 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -679,8 +679,9 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = quit 1 else: echo "megatest output OK" - removeFile(outputGottenFile) - removeFile(megatestFile) + when false: # no point removing those, always good for debugging + removeFile(outputGottenFile) + removeFile(megatestFile) # keep it around #testSpec r, makeTest("megatest", options, cat) # --------------------------------------------------------------------------- diff --git a/testament/specs.nim b/testament/specs.nim index 7405c5055..2f2c006d8 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -8,6 +8,15 @@ # import sequtils, parseutils, strutils, os, streams, parsecfg +from hashes import hash + +type TestamentData* = ref object + # better to group globals under 1 object; could group the other ones here too + batchArg*: string + testamentNumBatch*: int + testamentBatch*: int + +let testamentData0* = TestamentData() var compilerPrefix* = findExe("nim") @@ -68,11 +77,13 @@ type ccodeCheck*: string maxCodeSize*: int err*: TResultEnum + inCurrentBatch*: bool targets*: set[TTarget] matrix*: seq[string] nimout*: string parseErrors*: string # when the spec definition is invalid, this is not empty. unjoinable*: bool + unbatchable*: bool useValgrind*: bool timeout*: float # in seconds, fractions possible, # but don't rely on much precision @@ -138,6 +149,12 @@ proc addLine*(self: var string; a,b: string) = proc initSpec*(filename: string): TSpec = result.file = filename +proc isCurrentBatch(testamentData: TestamentData, filename: string): bool = + if testamentData.testamentNumBatch != 0: + hash(filename) mod testamentData.testamentNumBatch == testamentData.testamentBatch + else: + true + proc parseSpec*(filename: string): TSpec = result.file = filename let specStr = extractSpec(filename) @@ -203,6 +220,8 @@ proc parseSpec*(filename: string): TSpec = result.action = actionReject of "nimout": result.nimout = e.value + of "batchable": + result.unbatchable = not parseCfgBool(e.value) of "joinable": result.unjoinable = not parseCfgBool(e.value) of "valgrind": @@ -297,3 +316,7 @@ proc parseSpec*(filename: string): TSpec = if skips.anyIt(it in result.file): result.err = reDisabled + + result.inCurrentBatch = isCurrentBatch(testamentData0, filename) or result.unbatchable + if not result.inCurrentBatch: + result.err = reDisabled diff --git a/testament/testament.nim b/testament/testament.nim index 158a68822..58c4e5196 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -273,12 +273,14 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, expected = expected, given = given) r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success) + template disp(msg) = + maybeStyledEcho styleDim, fgYellow, msg & " ", styleBright, fgCyan, name if success == reSuccess: maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " sec)" elif success == reDisabled: - maybeStyledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name - elif success == reJoined: - maybeStyledEcho styleDim, fgYellow, "JOINED: ", styleBright, fgCyan, name + if test.spec.inCurrentBatch: disp("SKIP:") + else: disp("NOTINBATCH:") + elif success == reJoined: disp("JOINED:") else: maybeStyledEcho styleBright, fgRed, failString, fgCyan, name maybeStyledEcho styleBright, fgCyan, "Test \"", test.name, "\"", " in category \"", test.cat.string, "\"" @@ -645,6 +647,15 @@ proc main() = useColors = false else: quit Usage + of "batch": + testamentData0.batchArg = p.val + if p.val != "_": + let s = p.val.split("_") + doAssert s.len == 2, $(p.val, s) + testamentData0.testamentBatch = s[0].parseInt + testamentData0.testamentNumBatch = s[1].parseInt + doAssert testamentData0.testamentNumBatch > 0 + doAssert testamentData0.testamentBatch >= 0 and testamentData0.testamentBatch < testamentData0.testamentNumBatch of "simulate": simulate = true of "megatest": @@ -682,6 +693,7 @@ proc main() = myself &= " " & quoteShell("--targets:" & targetsStr) myself &= " " & quoteShell("--nim:" & compilerPrefix) + myself &= " --batch:" & testamentData0.batchArg if skipFrom.len > 0: myself &= " " & quoteShell("--skipFrom:" & skipFrom) diff --git a/tests/osproc/ta_in.nim b/tests/osproc/ta_in.nim deleted file mode 100644 index fb294ec14..000000000 --- a/tests/osproc/ta_in.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ -action: compile -""" - -# This file is prefixed with an "a", because other tests -# depend on it and it must be compiled first. -import strutils -let x = stdin.readLine() -echo x.parseInt + 5 diff --git a/tests/osproc/ta_out.nim b/tests/osproc/ta_out.nim deleted file mode 100644 index 01b78eb11..000000000 --- a/tests/osproc/ta_out.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ -output: ''' -start ta_out -to stdout -to stdout -to stderr -to stderr -to stdout -to stdout -end ta_out -''' -""" - -echo "start ta_out" - -# This file is prefixed with an "a", because other tests -# depend on it and it must be compiled first. -stdout.writeLine("to stdout") -stdout.flushFile() -stdout.writeLine("to stdout") -stdout.flushFile() - -stderr.writeLine("to stderr") -stderr.flushFile() -stderr.writeLine("to stderr") -stderr.flushFile() - -stdout.writeLine("to stdout") -stdout.flushFile() -stdout.writeLine("to stdout") -stdout.flushFile() - -echo "end ta_out" diff --git a/tests/osproc/tafalse.nim b/tests/osproc/tafalse.nim deleted file mode 100644 index 05a0bfce9..000000000 --- a/tests/osproc/tafalse.nim +++ /dev/null @@ -1,7 +0,0 @@ -discard """ -exitcode: 1 -""" - -# 'tafalse.nim' to ensure it is compiled before texitcode.nim -import system -quit(QuitFailure) diff --git a/tests/osproc/texecps.nim b/tests/osproc/texecps.nim index 10715fa0f..b818fe8eb 100644 --- a/tests/osproc/texecps.nim +++ b/tests/osproc/texecps.nim @@ -1,3 +1,7 @@ +discard """ +joinable: false +""" + import osproc, streams, strutils, os const NumberOfProcesses = 13 diff --git a/tests/osproc/texitcode.nim b/tests/osproc/texitcode.nim deleted file mode 100644 index 0b05ca3cb..000000000 --- a/tests/osproc/texitcode.nim +++ /dev/null @@ -1,26 +0,0 @@ -discard """ - output: "" -""" - -import osproc, os - -const filename = when defined(Windows): "tafalse.exe" else: "tafalse" -let dir = getCurrentDir() / "tests" / "osproc" -doAssert fileExists(dir / filename) - -var p = startProcess(filename, dir) -doAssert(waitForExit(p) == QuitFailure) - -p = startProcess(filename, dir) -var running = true -while running: - running = running(p) -doAssert(waitForExit(p) == QuitFailure) - -# make sure that first call to running() after process exit returns false -p = startProcess(filename, dir) -for j in 0..<30: # refs #13449 - os.sleep(50) - if not running(p): break -doAssert(not running(p)) -doAssert(waitForExit(p) == QuitFailure) # avoid zombies diff --git a/tests/osproc/tstderr.nim b/tests/osproc/tstderr.nim deleted file mode 100644 index 55b11eba5..000000000 --- a/tests/osproc/tstderr.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ - output: ''' -start tstderr --------------------------------------- -to stderr -to stderr --------------------------------------- -''' -""" - -echo "start tstderr" - -import osproc, os, streams - -const filename = "ta_out".addFileExt(ExeExt) - -doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) - -var p = startProcess(filename, getCurrentDir() / "tests" / "osproc", - options={}) - -try: - let stdoutStream = p.outputStream - let stderrStream = p.errorStream - var x = newStringOfCap(120) - var output = "" - while stderrStream.readLine(x.TaintedString): - output.add(x & "\n") - - echo "--------------------------------------" - stdout.flushFile() - stderr.write output - stderr.flushFile() - echo "--------------------------------------" - stdout.flushFile() -finally: - p.close() diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim deleted file mode 100644 index 8579680ab..000000000 --- a/tests/osproc/tstdin.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - output: "10" -""" -import osproc, os, streams - -const filename = when defined(Windows): "ta_in.exe" else: "ta_in" - -doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) - -var p = startProcess(filename, getCurrentDir() / "tests" / "osproc") -p.inputStream.write("5\n") -p.inputStream.flush() - -var line = "" - -while p.outputStream.readLine(line.TaintedString): - echo line diff --git a/tests/osproc/tstdout.nim b/tests/osproc/tstdout.nim deleted file mode 100644 index e3ed3986a..000000000 --- a/tests/osproc/tstdout.nim +++ /dev/null @@ -1,31 +0,0 @@ -discard """ - output: '''-------------------------------------- -start ta_out -to stdout -to stdout -to stderr -to stderr -to stdout -to stdout -end ta_out --------------------------------------- -''' -""" -import osproc, os, streams - -const filename = when defined(Windows): "ta_out.exe" else: "ta_out" - -doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) - -var p = startProcess(filename, getCurrentDir() / "tests" / "osproc", - options={poStdErrToStdOut}) - -let outputStream = p.outputStream -var x = newStringOfCap(120) -var output = "" -while outputStream.readLine(x.TaintedString): - output.add(x & "\n") - -echo "--------------------------------------" -stdout.write output -echo "--------------------------------------" diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index cb6e260c5..363bd5d74 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -5,9 +5,10 @@ joinable: false #[ joinable: false because it'd need cleanup up stdout -]# -import stdtest/[specialpaths, unittest_light] +see also: tests/osproc/*.nim; consider merging those into a single test here +(easier to factor and test more things as a single self contained test) +]# when defined(case_testfile): # compiled test file for child process from posix import exitnow @@ -51,22 +52,58 @@ when defined(case_testfile): # compiled test file for child process echo args[1] main() -else: +elif defined(case_testfile2): + import strutils + let x = stdin.readLine() + echo x.parseInt + 5 +elif defined(case_testfile3): + echo "start ta_out" + stdout.writeLine("to stdout") + stdout.flushFile() + stdout.writeLine("to stdout") + stdout.flushFile() + + stderr.writeLine("to stderr") + stderr.flushFile() + stderr.writeLine("to stderr") + stderr.flushFile() + + stdout.writeLine("to stdout") + stdout.flushFile() + stdout.writeLine("to stdout") + stdout.flushFile() + echo "end ta_out" + +elif defined(case_testfile4): + import system # we could remove that + quit(QuitFailure) + +else: # main driver + import stdtest/[specialpaths, unittest_light] import os, osproc, strutils const nim = getCurrentCompilerExe() + const sourcePath = currentSourcePath() + let dir = getCurrentDir() / "tests" / "osproc" + + template deferScoped(cleanup, body) = + # pending https://github.com/nim-lang/RFCs/issues/236#issuecomment-646855314 + # xxx move to std/sugar or (preferably) some low level module + try: body + finally: cleanup + + # we're testing `execShellCmd` so don't rely on it to compile test file + # note: this should be exported in posix.nim + proc c_system(cmd: cstring): cint {.importc: "system", header: "".} + + proc compileNimProg(opt: string, name: string): string = + result = buildDir / name.addFileExt(ExeExt) + let cmd = "$# c -o:$# --hints:off $# $#" % [nim.quoteShell, result.quoteShell, opt, sourcePath.quoteShell] + doAssert c_system(cmd) == 0, $cmd + doAssert result.fileExists block execShellCmdTest: - ## first, compile child program - const sourcePath = currentSourcePath() - let output = buildDir / "D20190111T024543".addFileExt(ExeExt) - let cmd = "$# c -o:$# -d:release -d:case_testfile $#" % [nim, output, - sourcePath] - # we're testing `execShellCmd` so don't rely on it to compile test file - # note: this should be exported in posix.nim - proc c_system(cmd: cstring): cint {.importc: "system", - header: "".} - assertEquals c_system(cmd), 0 + let output = compileNimProg("-d:release -d:case_testfile", "D20190111T024543") ## use it template runTest(arg: string, expected: int) = @@ -79,7 +116,7 @@ else: runTest("quit_139", 139) block execProcessTest: - let dir = parentDir(currentSourcePath()) + let dir = sourcePath.parentDir let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim")) doAssert err == 0 let exePath = dir / addFileExt("osproctest", ExeExt) @@ -101,6 +138,7 @@ else: discard import std/streams + block: # test for startProcess (more tests needed) # bugfix: windows stdin.close was a noop and led to blocking reads proc startProcessTest(command: string, options: set[ProcessOption] = { @@ -126,6 +164,56 @@ else: var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4") doAssert result == ("12\n", 0) + block: # startProcess stdin (replaces old test `tstdin` + `ta_in`) + let output = compileNimProg("-d:case_testfile2", "D20200626T215919") + var p = startProcess(output, dir) # dir not needed though + p.inputStream.write("5\n") + p.inputStream.flush() + var line = "" + var s: seq[string] + while p.outputStream.readLine(line.TaintedString): + s.add line + doAssert s == @["10"] + + block: + let output = compileNimProg("-d:case_testfile3", "D20200626T221233") + var x = newStringOfCap(120) + block: # startProcess stdout poStdErrToStdOut (replaces old test `tstdout` + `ta_out`) + var p = startProcess(output, dir, options={poStdErrToStdOut}) + deferScoped: p.close() + do: + var sout: seq[string] + while p.outputStream.readLine(x.TaintedString): sout.add x + doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"] + block: # startProcess stderr (replaces old test `tstderr` + `ta_out`) + var p = startProcess(output, dir, options={}) + deferScoped: p.close() + do: + var serr, sout: seq[string] + while p.errorStream.readLine(x.TaintedString): serr.add x + while p.outputStream.readLine(x.TaintedString): sout.add x + doAssert serr == @["to stderr", "to stderr"] + doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stdout", "to stdout", "end ta_out"] + + block: # startProcess exit code (replaces old test `texitcode` + `tafalse`) + let output = compileNimProg("-d:case_testfile4", "D20200626T224758") + var p = startProcess(output, dir) + doAssert waitForExit(p) == QuitFailure + p = startProcess(output, dir) + var running = true + while running: + # xxx: avoid busyloop? + running = running(p) + doAssert waitForExit(p) == QuitFailure + + # make sure that first call to running() after process exit returns false + p = startProcess(output, dir) + for j in 0..<30: # refs #13449 + os.sleep(50) + if not running(p): break + doAssert not running(p) + doAssert waitForExit(p) == QuitFailure # avoid zombies + import std/strtabs block execProcessTest: var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") From ad00d616e8ed3dc3e7b1e8fb4a8681e5b4eca0e8 Mon Sep 17 00:00:00 2001 From: Sizhe Zhao Date: Sat, 27 Jun 2020 22:51:48 +0800 Subject: [PATCH 0788/4254] Warn about calling wrappers at compile time until #14049 is fixed. (#14828) --- doc/manual.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index da50e2c56..9f5252ae0 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -843,7 +843,10 @@ language features: * closure iterators * the ``cast`` operator * reference (pointer) types -* the FFI +* FFI + +The use of wrappers that use FFI and/or ``cast`` is also disallowed. Note that +these wrappers include the ones in the standard libraries. Some or all of these restrictions are likely to be lifted over time. From 22f1b5120e6ea1b182185e31b2744fc3cd39cd6e Mon Sep 17 00:00:00 2001 From: Manuel Bojato <30560560+KingDarBoja@users.noreply.github.com> Date: Sat, 27 Jun 2020 16:36:31 -0500 Subject: [PATCH 0789/4254] Fix nimdoc invalid css on theme switch class (#14834) --- doc/nimdoc.css | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 72b6734ab..6025d6601 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -63,12 +63,13 @@ Modified by Boyd Greenfield and narimiran .theme-switch-wrapper { display: flex; align-items: center; - - em { - margin-left: 10px; - font-size: 1rem; - } } + +.theme-switch-wrapper em { + margin-left: 10px; + font-size: 1rem; +} + .theme-switch { display: inline-block; height: 22px; From bc66788b3fbe0a312ddd4e1c2d58e902787ca512 Mon Sep 17 00:00:00 2001 From: Manuel Bojato <30560560+KingDarBoja@users.noreply.github.com> Date: Sat, 27 Jun 2020 16:42:58 -0500 Subject: [PATCH 0790/4254] docs: Make `..<`, `.. ^` more discoverable (#14835) --- lib/system_overview.rst | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/system_overview.rst b/lib/system_overview.rst index 23284dabf..f0945873c 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -45,24 +45,27 @@ Proc Usage Seqs ---- -======================================== ========================================== -Proc Usage -======================================== ========================================== -`newSeq<#newSeq>`_ Create a new sequence of a given length -`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length - and a given capacity -`setLen<#setLen,seq[T][T],Natural>`_ Set the length of a sequence -`len<#len,seq[T][T]>`_ Return the length of a sequence -`@<#@,array[IDX,T]>`_ Turn an array into a sequence -`add<#add,seq[T][T],T>`_ Add an item to the sequence -`insert<#insert,seq[T][T],T>`_ Insert an item at a specific position -`delete<#delete,seq[T][T],Natural>`_ Delete an item while preserving the - order of elements (`O(n)` operation) -`del<#del,seq[T][T],Natural>`_ `O(1)` removal, doesn't preserve the order -`pop<#pop,seq[T][T]>`_ Remove and return last item of a sequence -`x & y<#&,seq[T][T],seq[T][T]>`_ Concatenate two sequences -`x[a..b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (both ends included) -======================================== ========================================== +=========================================== ========================================== +Proc Usage +=========================================== ========================================== +`newSeq<#newSeq>`_ Create a new sequence of a given length +`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length + and a given capacity +`setLen<#setLen,seq[T][T],Natural>`_ Set the length of a sequence +`len<#len,seq[T][T]>`_ Return the length of a sequence +`@<#@,array[IDX,T]>`_ Turn an array into a sequence +`add<#add,seq[T][T],T>`_ Add an item to the sequence +`insert<#insert,seq[T][T],T>`_ Insert an item at a specific position +`delete<#delete,seq[T][T],Natural>`_ Delete an item while preserving the + order of elements (`O(n)` operation) +`del<#del,seq[T][T],Natural>`_ `O(1)` removal, doesn't preserve the order +`pop<#pop,seq[T][T]>`_ Remove and return last item of a sequence +`x & y<#&,seq[T][T],seq[T][T]>`_ Concatenate two sequences +`x[a..b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (both ends included) +`x[a..^b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence but `b` is a + reversed index (both ends included) +`x[a..\`_ Slice of a sequence (excluded upper bound) +=========================================== ========================================== **See also:** * `sequtils module `_ for operations on container @@ -160,8 +163,10 @@ Proc Usage `T or F<#or,bool,bool>`_ Boolean `or` `T xor F<#xor,bool,bool>`_ Boolean `xor` (exclusive or) `not T<#not,bool>`_ Boolean `not` +`a[^x]<#^.t,int>`_ Take the element at the reversed index `x` `a .. b<#..,T,U>`_ Binary slice that constructs an interval `[a, b]` +`a ..^ b<#..^.t,untyped,untyped>`_ Interval `[a, b]` but `b` as reversed index [a ..< b](#..<.t,untyped,untyped) Interval `[a, b)` (excluded upper bound) [runnableExamples](#runnableExamples,untyped) Create testable documentation ============================================= ============================================ From 252f668829ee15f91c9c7febd6cec8e9a85d6fc7 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Sat, 27 Jun 2020 18:59:08 -0300 Subject: [PATCH 0791/4254] add a second asyncnet.recvFrom (#14237) * add a second asyncnet.recvFrom * fixes * pre-allocating address * add a new nativesockets.getAddrString() --- lib/pure/asyncnet.nim | 95 +++++++++++++++++++++++++------------- lib/pure/nativesockets.nim | 34 ++++++++++++++ 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 3fc1a0177..410310e29 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -853,6 +853,60 @@ proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string, else: raise newException(IOError, "Couldn't resolve address: " & address) +proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int, + address: FutureVar[string], port: FutureVar[Port], + flags = {SocketFlag.SafeDisconn}): owned(Future[int]) + {.async, since: (1, 3).} = + ## Receives a datagram data from ``socket`` into ``data``, which must be at + ## least of size ``size``. The address and port of datagram's sender will be + ## stored into ``address`` and ``port``, respectively. Returned future will + ## complete once one datagram has been received, and will return size of + ## packet received. + ## + ## If an error occurs an OSError exception will be raised. + ## + ## This proc is normally used with connectionless sockets (UDP sockets). + ## + ## **Notes** + ## * ``data`` must be initialized to the length of ``size``. + ## * ``address`` must be initialized to 46 in length. + template adaptRecvFromToDomain(domain: Domain) = + var lAddr = sizeof(sAddr).SockLen + + result = await recvFromInto(AsyncFD(getFd(socket)), cstring(data.mget()), size, + cast[ptr SockAddr](addr sAddr), addr lAddr, + flags) + + data.mget().setLen(result) + data.complete() + + getAddrString(cast[ptr SockAddr](addr sAddr), address.mget()) + + address.complete() + + when domain == AF_INET6: + port.complete(ntohs(sAddr.sin6_port).Port) + else: + port.complete(ntohs(sAddr.sin_port).Port) + + assert(socket.protocol != IPPROTO_TCP, + "Cannot `recvFrom` on a TCP socket. Use `recv` or `recvInto` instead") + assert(not socket.closed, "Cannot `recvFrom` on a closed socket") + assert(size == len(data.mget()), + "`date` was not initialized correctly. `size` != `len(data.mget())`") + assert(46 == len(address.mget()), + "`address` was not initialized correctly. 46 != `len(address.mget())`") + + case socket.domain + of AF_INET6: + var sAddr: Sockaddr_in6 + adaptRecvFromToDomain(AF_INET6) + of AF_INET: + var sAddr: Sockaddr_in + adaptRecvFromToDomain(AF_INET) + else: + raise newException(ValueError, "Unknown socket address family") + proc recvFrom*(socket: AsyncSocket, size: int, flags = {SocketFlag.SafeDisconn}): owned(Future[tuple[data: string, address: string, port: Port]]) @@ -865,38 +919,17 @@ proc recvFrom*(socket: AsyncSocket, size: int, ## If an error occurs an OSError exception will be raised. ## ## This proc is normally used with connectionless sockets (UDP sockets). - template adaptRecvFromToDomain(domain: Domain) = - var lAddr = sizeof(sAddr).SockLen - - let fut = await recvFromInto(AsyncFD(getFd(socket)), cstring(data), size, - cast[ptr SockAddr](addr sAddr), addr lAddr, - flags) - - data.setLen(fut) - - result.data = data - result.address = getAddrString(cast[ptr SockAddr](addr sAddr)) - - when domain == AF_INET6: - result.port = ntohs(sAddr.sin6_port).Port - else: - result.port = ntohs(sAddr.sin_port).Port - - assert(socket.protocol != IPPROTO_TCP, - "Cannot `recvFrom` on a TCP socket. Use `recv` or `recvInto` instead") - assert(not socket.closed, "Cannot `recvFrom` on a closed socket") - - var data = newString(size) + var + data = newFutureVar[string]() + address = newFutureVar[string]() + port = newFutureVar[Port]() - case socket.domain - of AF_INET6: - var sAddr: Sockaddr_in6 - adaptRecvFromToDomain(AF_INET6) - of AF_INET: - var sAddr: Sockaddr_in - adaptRecvFromToDomain(AF_INET) - else: - raise newException(ValueError, "Unknown socket address family") + data.mget().setLen(size) + address.mget().setLen(46) + + let read = await recvFrom(socket, data, size, address, port, flags) + + result = (data.mget(), address.mget(), port.mget()) when not defined(testing) and isMainModule: type diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 67e24eedc..35a7396b9 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -461,6 +461,40 @@ proc getAddrString*(sockAddr: ptr SockAddr): string = return "unix" raise newException(IOError, "Unknown socket family in getAddrString") +proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) = + ## Stores in ``strAddress`` the string representation of the address inside + ## ``sockAddr`` + ## + ## **Note** + ## * ``strAddress`` must be initialized to 46 in length. + assert(46 == len(strAddress), + "`strAddress` was not initialized correctly. 46 != `len(strAddress)`") + if sockAddr.sa_family.cint == nativeAfInet: + let addr4 = addr cast[ptr Sockaddr_in](sockAddr).sin_addr + when not useWinVersion: + if posix.inet_ntop(posix.AF_INET, addr4, addr strAddress[0], + strAddress.len.int32) == nil: + raiseOSError(osLastError()) + else: + if winlean.inet_ntop(winlean.AF_INET, addr4, addr strAddress[0], + strAddress.len.int32) == nil: + raiseOSError(osLastError()) + elif sockAddr.sa_family.cint == nativeAfInet6: + let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr + when not useWinVersion: + if posix.inet_ntop(posix.AF_INET6, addr6, addr strAddress[0], + strAddress.len.int32) == nil: + raiseOSError(osLastError()) + if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0: + strAddress = strAddress.substr("::ffff:".len) + else: + if winlean.inet_ntop(winlean.AF_INET6, addr6, addr strAddress[0], + strAddress.len.int32) == nil: + raiseOSError(osLastError()) + else: + raise newException(IOError, "Unknown socket family in getAddrString") + setLen(strAddress, len(cstring(strAddress))) + when defined(posix) and not defined(nimdoc): proc makeUnixAddr*(path: string): Sockaddr_un = result.sun_family = AF_UNIX.TSa_Family From 54a52e7d088a388f8c52007fbb7e6db1bf2044c6 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 28 Jun 2020 00:13:54 +0200 Subject: [PATCH 0792/4254] Update link to parseSpec proc --- tests/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/readme.md b/tests/readme.md index 234ee4efe..69be92051 100644 --- a/tests/readme.md +++ b/tests/readme.md @@ -9,7 +9,7 @@ top-level tests like `tests/tbar.nim`. Each test can contain a spec in a ``discard """ ... """`` block. -**Check out the [``parseSpec`` procedure](https://github.com/nim-lang/Nim/blob/devel/testament/specs.nim#L132) in the ``specs`` module for a full and reliable reference** +**Check out the [``parseSpec`` procedure](https://github.com/nim-lang/Nim/blob/devel/testament/specs.nim#L158) in the ``specs`` module for a full and reliable reference** ## action From 5d5271b7896eef3eafbb2beaf3f1fd4159b797f6 Mon Sep 17 00:00:00 2001 From: lqdev Date: Sun, 28 Jun 2020 13:38:57 +0200 Subject: [PATCH 0793/4254] fixed #14839 (#14840) --- lib/pure/colors.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index d57e309e9..dbcb1b4a2 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -452,7 +452,7 @@ proc parseColor*(name: string): Color = assert parseColor(b) == Color(0x01_79_fc) doAssertRaises(ValueError): discard parseColor(c) - if name[0] == '#': + if name.len > 0 and name[0] == '#': result = Color(parseHexInt(name)) else: var idx = binarySearch(colorNames, name, colorNameCmp) @@ -472,6 +472,7 @@ proc isColor*(name: string): bool = assert b.isColor assert not c.isColor + if name.len == 0: return false if name[0] == '#': for i in 1 .. name.len-1: if name[i] notin {'0'..'9', 'a'..'f', 'A'..'F'}: return false From 037990bc78914a793a4195c326282f8353cda319 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 28 Jun 2020 15:38:24 +0200 Subject: [PATCH 0794/4254] Changelog: Tiny style improvement --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 07d9b6112..de2e443fc 100644 --- a/changelog.md +++ b/changelog.md @@ -150,7 +150,7 @@ deallocShared(x.val) x.val = nil ``` -- getImpl() on enum type symbols now returns field syms instead of idents. This helps +- `getImpl` on enum type symbols now returns field syms instead of idents. This helps with writing typed macros. Old behavior for backwards compatiblity can be restored with command line switch `--useVersion:1.0`. - ``let`` statements can now be used without a value if declared with From 394a56650ae6139786d8cefb838b0e3e282c24a1 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 28 Jun 2020 17:47:47 +0200 Subject: [PATCH 0795/4254] Fix #14647 (#14776) * Fix #14647 * Correct fix * Typo and add test * For real now :p --- compiler/cgen.nim | 9 +++------ compiler/cgendata.nim | 4 ++-- tests/destructor/tgotoexceptions5.nim | 8 +++++++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index cd02ba9b1..99bfe9119 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1777,11 +1777,6 @@ proc genModule(m: BModule, cfile: Cfile): Rope = if moduleIsEmpty: result = nil -proc newPreInitProc(m: BModule): BProc = - result = newProc(nil, m) - # little hack so that unique temporaries are generated: - result.labels = 100_000 - proc initProcOptions(m: BModule): TOptions = let opts = m.config.options if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts @@ -1802,7 +1797,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule result.sigConflicts = initCountTable[SigHash]() result.initProc = newProc(nil, result) result.initProc.options = initProcOptions(result) - result.preInitProc = newPreInitProc(result) + result.preInitProc = newProc(nil, result) + result.preInitProc.flags.incl nimErrorFlagDisabled + result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated initNodeTable(result.dataCache) result.typeStack = @[] result.typeNodesName = getTempName(result) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index ce74963e2..a20931be4 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -189,8 +189,8 @@ proc newProc*(prc: PSym, module: BModule): BProc = new(result) result.prc = prc result.module = module - if prc != nil: result.options = prc.options - else: result.options = module.config.options + result.options = if prc != nil: prc.options + else: module.config.options newSeq(result.blocks, 1) result.nestedTryStmts = @[] result.finallySafePoints = @[] diff --git a/tests/destructor/tgotoexceptions5.nim b/tests/destructor/tgotoexceptions5.nim index 0e538d89e..695aab0a4 100644 --- a/tests/destructor/tgotoexceptions5.nim +++ b/tests/destructor/tgotoexceptions5.nim @@ -5,7 +5,7 @@ swallowed before swallowed B ''' - cmd: "nim c --gc:arc --exceptions:goto $file" + cmd: "nim c --gc:arc --exceptions:goto -d:ssl $file" """ # bug #13599 @@ -37,3 +37,9 @@ try: mainB() except: echo "swallowed B" + +# bug #14647 +import httpclient + +newAsyncHttpClient().close() + From d9c15017572afbbdfb8007bbaf33733b9ac69613 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 28 Jun 2020 18:59:57 +0300 Subject: [PATCH 0796/4254] get rid of $READLINK variable (#14841) --- bin/nim-gdb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/nim-gdb b/bin/nim-gdb index 1486b6dce..f7f9a79c6 100755 --- a/bin/nim-gdb +++ b/bin/nim-gdb @@ -8,9 +8,9 @@ which gdb > /dev/null || (echo "gdb not in PATH"; exit 1) which readlink > /dev/null || (echo "readlink not in PATH."; exit 1) if [[ "$(uname -s)" == "Darwin" || "(uname -s)" == *"BSD" ]]; then - NIM_SYSROOT=$(dirname $(dirname $($READLINK -f $(which nim)))) + NIM_SYSROOT=$(dirname $(dirname $(readlink -f $(which nim)))) else - NIM_SYSROOT=$(dirname $(dirname $($READLINK -e $(which nim)))) + NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim)))) fi # Find out where the pretty printer Python module is From c285739d55408bb5f75d3190a286d18ac883bd41 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Sun, 28 Jun 2020 19:00:43 +0300 Subject: [PATCH 0797/4254] Remove double entry for thiscall (#14842) --- changelog.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index de2e443fc..54996ea34 100644 --- a/changelog.md +++ b/changelog.md @@ -180,9 +180,7 @@ proc mydiv(a, b): int {.raises: [].} = The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. -- Added the `thiscall` calling convention as specified by Microsoft. - -- Added `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose +- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. From 4f70180a58ae46fcf313aed001242f8aa1252b1a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 28 Jun 2020 18:03:39 +0200 Subject: [PATCH 0798/4254] Fix typo --- doc/hcr.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/hcr.rst b/doc/hcr.rst index f6db0ddfd..b2441dfbc 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -221,7 +221,7 @@ is a suitable place for implementing a program loop capable of calling Please note that reloading won't be possible when any of the type definitions in the program has been changed. When closure iterators are used (directly or -through async code), the reloaded refinitions will affect only newly created +through async code), the reloaded definitions will affect only newly created instances. Existing iterator instancess will execute their original code to completion. From 79367685601f4c90f6c478ce45651bffd9222c39 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Sun, 28 Jun 2020 20:17:18 +0300 Subject: [PATCH 0799/4254] Fix some typos (#14843) --- doc/advopt.txt | 2 +- doc/codeowners.rst | 50 ++++++++++++++++++------------------- doc/destructors.rst | 2 +- doc/docgen.rst | 6 ++--- doc/hcr.rst | 2 +- doc/idetools.rst | 4 +-- doc/intern.rst | 6 ++--- doc/koch.rst | 2 +- doc/lib.rst | 4 +-- doc/manual.rst | 2 +- doc/manual_experimental.rst | 2 +- doc/nimc.rst | 2 +- 12 files changed, 42 insertions(+), 42 deletions(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 18bfde11b..588d4eece 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -78,7 +78,7 @@ Advanced options: if path == @path, will use first matching dir in `--path` if path == @default (the default and most useful), will use best match among @pkg,@path. - if these are nonexistant, will use project path + if these are nonexistent, will use project path -b, --backend:c|cpp|js|objc sets backend to use with commands like `nim doc` or `nim r` --docCmd:cmd if `cmd == skip`, skips runnableExamples else, runs runnableExamples with given options, eg: diff --git a/doc/codeowners.rst b/doc/codeowners.rst index 129c47cfc..4b4a5810e 100644 --- a/doc/codeowners.rst +++ b/doc/codeowners.rst @@ -13,31 +13,31 @@ library, araq is responsible for the compiler. Compiler ~~~~~~~~ -====================== ====================================================== -subsystem owner(s) -====================== ====================================================== -Parsing, Lexing araq -Renderer cooldome, araq -Order of passes cooldome -Semantic Checking araq -Virtual machine jangko, GULPF, araq -Sempass2: effects tracking cooldome, araq -type system, concepts zahary -transf cooldome, araq -semfold constant folding araq -template instantiation zahary, araq -term rewriting macros cooldome, araq -closure interators yglukhov, araq -lambda lifting yglukhov, araq -c, cpp codegen lemonboy, araq -js codegen yglukhov, lemonboy -alias analysis araq -dfa, writetracking araq -parallel, multithreading araq -incremental araq -sizeof computations krux02 -Exception handling cooldome, araq -====================== ====================================================== +=========================== ====================================================== +subsystem owner(s) +=========================== ====================================================== +Parsing, Lexing araq +Renderer cooldome, araq +Order of passes cooldome +Semantic Checking araq +Virtual machine jangko, GULPF, araq +Sempass2: effects tracking cooldome, araq +type system, concepts zahary +transf cooldome, araq +semfold constant folding araq +template instantiation zahary, araq +term rewriting macros cooldome, araq +closure iterators yglukhov, araq +lambda lifting yglukhov, araq +c, cpp codegen lemonboy, araq +js codegen yglukhov, lemonboy +alias analysis araq +dfa, writetracking araq +parallel, multithreading araq +incremental araq +sizeof computations krux02 +Exception handling cooldome, araq +=========================== ====================================================== diff --git a/doc/destructors.rst b/doc/destructors.rst index e7ebd93ea..b06d78bbe 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -225,7 +225,7 @@ A sink parameter *may* be consumed once in the proc's body but doesn't have to be consumed at all. The reason for this is that signatures like ``proc put(t: var Table; k: sink Key, v: sink Value)`` should be possible -without any further overloads and ``put`` might not take owership of ``k`` if +without any further overloads and ``put`` might not take ownership of ``k`` if ``k`` already exists in the table. Sink parameters enable an affine type system, not a linear type system. diff --git a/doc/docgen.rst b/doc/docgen.rst index 24743ba13..dac8808ad 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -244,7 +244,7 @@ Other Input Formats The *Nim compiler* also has support for RST (reStructuredText) files with the ``rst2html`` and ``rst2tex`` commands. Documents like this one are -initially written in a dialect of RST which adds support for nim sourcecode +initially written in a dialect of RST which adds support for nim source code highlighting with the ``.. code-block:: nim`` prefix. ``code-block`` also supports highlighting of C++ and some other c-like languages. @@ -330,7 +330,7 @@ Index (idx) file format Files with the ``.idx`` extension are generated when you use the `Index switch <#related-options-index-switch>`_ along with commands to generate -documentation from source or text files. You can programatically generate +documentation from source or text files. You can programmatically generate indices with the `setIndexTerm() `_ and `writeIndexFile() `_ procs. @@ -375,7 +375,7 @@ exception to this are table of content (TOC) entries. TOC entries are added to the index file with their third column having as much prefix spaces as their level is in the TOC (at least 1 character). The prefix whitespace helps to filter TOC entries from API or text symbols. This is important because the -amount of spaces is used to replicate the hiearchy for document TOCs in the +amount of spaces is used to replicate the hierarchy for document TOCs in the final index, and TOC entries found in ``.nim`` files are discarded. diff --git a/doc/hcr.rst b/doc/hcr.rst index b2441dfbc..567d77178 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -222,7 +222,7 @@ is a suitable place for implementing a program loop capable of calling Please note that reloading won't be possible when any of the type definitions in the program has been changed. When closure iterators are used (directly or through async code), the reloaded definitions will affect only newly created -instances. Existing iterator instancess will execute their original code to +instances. Existing iterator instances will execute their original code to completion. JavaScript target diff --git a/doc/idetools.rst b/doc/idetools.rst index e83bfe935..ac3b92947 100644 --- a/doc/idetools.rst +++ b/doc/idetools.rst @@ -69,7 +69,7 @@ Or:: pass in the same value as **proj.nim**. ``DIRTY_FILE`` - The **FILE** paramater is enough for static analysis, but IDEs + The **FILE** parameter is enough for static analysis, but IDEs tend to have *unsaved buffers* where the user may still be in the middle of typing a line. In such situations the IDE can save the current contents to a temporary file and then use the @@ -210,7 +210,7 @@ tab characters (``\t``). The values of each column are: def for definition, ``sug`` for suggestion, etc). 2. Type of the symbol. This can be ``skProc``, ``skLet``, and just about any of the enums defined in the module ``compiler/ast.nim``. -3. Full qualitifed path of the symbol. If you are querying a symbol +3. Full qualified path of the symbol. If you are querying a symbol defined in the ``proj.nim`` file, this would have the form ``proj.symbolName``. 4. Type/signature. For variables and enums this will contain the diff --git a/doc/intern.rst b/doc/intern.rst index b68067d1b..be183fd8e 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -468,7 +468,7 @@ The CellSet data structure The GC depends on an extremely efficient datastructure for storing a set of pointers - this is called a ``TCellSet`` in the source code. Inserting, deleting and searching are done in constant time. However, -modifying a ``TCellSet`` during traversation leads to undefined behaviour. +modifying a ``TCellSet`` during traversal leads to undefined behaviour. .. code-block:: Nim type @@ -558,7 +558,7 @@ This means that a call through a closure generates an ``if`` but the interoperability is worth the cost of the ``if``. Thunk generation would be possible too, but it's slightly more effort to implement. -Tests with GCC on Amd64 showed that it's really beneficical if the +Tests with GCC on Amd64 showed that it's really beneficial if the 'environment' pointer is passed as the last argument, not as the first argument. Proper thunk generation is harder because the proc that is to wrap @@ -609,7 +609,7 @@ Beware of nesting: .. code-block:: nim proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = - return lamba (y: int): proc (z: int): int {.closure.} = + return lambda (y: int): proc (z: int): int {.closure.} = return lambda (z: int): int = return x + y + z diff --git a/doc/koch.rst b/doc/koch.rst index 436e0e406..e984a71ea 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -77,7 +77,7 @@ https://nim-lang.org. By default the documentation will be built in parallel using the number of available CPU cores. If any documentation build sub commands fail, they will -be rerun in serial fashion so that meaninful error output can be gathered for +be rerun in serial fashion so that meaningful error output can be gathered for inspection. The ``--parallelBuild:n`` switch or configuration option can be used to force a specific number of parallel jobs or run everything serially from the start (``n == 1``). diff --git a/doc/lib.rst b/doc/lib.rst index 97f6c1db1..e05657b42 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -214,7 +214,7 @@ Generic Operating System Services This module implements the ability to access symbols from shared libraries. * `marshal `_ - Contains procs for serialization and deseralization of arbitrary Nim + Contains procs for serialization and deserialization of arbitrary Nim data structures. * `memfiles `_ @@ -267,7 +267,7 @@ Math libraries Statistical analysis * `std/sums `_ - Fast sumation functions. + Fast summation functions. Internet Protocols and Support diff --git a/doc/manual.rst b/doc/manual.rst index 9f5252ae0..d2fcdc080 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6455,7 +6455,7 @@ Align pragma The `align`:idx: pragma is for variables and object field members. It modifies the alignment requirement of the entity being declared. The argument must be a constant power of 2. Valid non-zero -alignments that are weaker than nother align pragmas on the same +alignments that are weaker than other align pragmas on the same declaration are ignored. Alignments that are weaker that the alignment requirement of the type are ignored. diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index d8efddf94..b0614885a 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -811,7 +811,7 @@ object inheritance syntax involving the ``of`` keyword: .. code-block:: nim type - Graph = concept g, type G of EqualyComparable, Copyable + Graph = concept g, type G of EquallyComparable, Copyable type VertexType = G.VertexType EdgeType = G.EdgeType diff --git a/doc/nimc.rst b/doc/nimc.rst index 59289a7c8..bd5e897c3 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -348,7 +348,7 @@ of your program. proc glfmMain*(display: ptr GLFMDisplay) {.exportc.} = NimMain() # initialize garbage collector memory, types and stack -Note: XCodes "make clean" gets confused about the genreated nim.c files, +Note: XCode's "make clean" gets confused about the generated nim.c files, so you need to clean those files manually to do a clean build. From 62394616e848e7a94bc0208d6535df6f582e74ce Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 28 Jun 2020 19:36:30 +0200 Subject: [PATCH 0800/4254] DFA and injectdestructors cleanup (#14824) * DFA and injectdestructors cleanup * More precise write analysis * Cleanup obsoleted path * Unify defInstrTargets and useInstrTargets * Misc cleanups * Nicer CFG printing * Misc cleanups 2 --- compiler/dfa.nim | 225 +++++++++++++-------------------- compiler/injectdestructors.nim | 48 +++---- 2 files changed, 117 insertions(+), 156 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index c393b2c81..2254cd0ff 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -29,7 +29,7 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, types, intsets, lineinfos, renderer +import ast, types, intsets, lineinfos, renderer, asciitables from patterns import sameTrees @@ -57,14 +57,11 @@ type Con = object code: ControlFlowGraph - inCall, inTryStmt: int + inTryStmt: int blocks: seq[TBlock] owner: PSym -proc debugInfo(info: TLineInfo): string = - result = $info.line #info.toFilename & ":" & $info.line - -proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) = +proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string = # for debugging purposes # first iteration: compute all necessary labels: var jumpTargets = initIntSet() @@ -85,17 +82,14 @@ proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) = result.add "L" result.addInt c[i].dest+i result.add("\t#") - result.add(debugInfo(c[i].n.info)) + result.add($c[i].n.info.line) result.add("\n") inc i if i in jumpTargets: result.add("L" & $i & ": End\n") - # consider calling `asciitables.alignTable` -proc echoCfg*(c: ControlFlowGraph; start=0; last = -1) {.deprecated.} = +proc echoCfg*(c: ControlFlowGraph; start = 0; last = -1) {.deprecated.} = ## echos the ControlFlowGraph for debugging purposes. - var buf = "" - codeListing(c, buf, start, last) - echo buf + echo codeListing(c, start, last).alignTable proc forkI(c: var Con; n: PNode): TPosition = result = TPosition(c.code.len) @@ -273,22 +267,20 @@ duplicate the 'join' instructions on breaks and return exits! ]# -proc genLabel(c: Con): TPosition = - result = TPosition(c.code.len) +proc genLabel(c: Con): TPosition = TPosition(c.code.len) + +template checkedDistance(dist): int = + doAssert low(int) div 2 + 1 < dist and dist < high(int) div 2 + dist proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) = - let dist = p.int - c.code.len - doAssert(low(int) div 2 + 1 < dist and dist < high(int) div 2) - c.code.add Instr(n: n, kind: goto, dest: dist) + c.code.add Instr(n: n, kind: goto, dest: checkedDistance(p.int - c.code.len)) proc patch(c: var Con, p: TPosition) = # patch with current index - let p = p.int - let diff = c.code.len - p - doAssert(low(int) div 2 + 1 < diff and diff < high(int) div 2) - c.code[p].dest = diff + c.code[p.int].dest = checkedDistance(c.code.len - p.int) -proc gen(c: var Con; n: PNode) # {.noSideEffect.} +func gen(c: var Con; n: PNode) proc popBlock(c: var Con; oldLen: int) = var exits: seq[TPosition] @@ -302,8 +294,8 @@ proc popBlock(c: var Con; oldLen: int) = c.patch e c.blocks.setLen(oldLen) -template withBlock(labl: PSym; body: untyped) {.dirty.} = - var oldLen {.gensym.} = c.blocks.len +template withBlock(labl: PSym; body: untyped) = + let oldLen = c.blocks.len c.blocks.add TBlock(isTryBlock: false, label: labl) body popBlock(c, oldLen) @@ -366,11 +358,9 @@ when true: endings[i] = c.forkI(n) c.gen(n[1]) for i in countdown(endings.high, 0): - let endPos = endings[i] - c.patch(endPos) + c.patch(endings[i]) else: - proc genWhile(c: var Con; n: PNode) = # lab1: # cond, tmp @@ -385,10 +375,9 @@ else: c.jmpBack(n, lab1) else: c.gen(n[0]) - let lab2 = c.forkI(n) - c.gen(n[1]) - c.jmpBack(n, lab1) - c.patch(lab2) + forkT(n): + c.gen(n[1]) + c.jmpBack(n, lab1) template forkT(n, body) = let lab1 = c.forkI(n) @@ -434,16 +423,14 @@ proc genIf(c: var Con, n: PNode) = ]# var endings: seq[TPosition] = @[] for i in 0.. x; x -> x.f + elif loc.aliases(insloc): + Partial # x.f -> x + else: None proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = var n = orig while true: case n.kind - of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv, - nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr: + of PathKinds0 - {nkBracketExpr, nkHiddenDeref, nkDerefExpr}: n = n[0] + of PathKinds1: + n = n[1] of nkBracketExpr: # in a[i] the 'i' must be known if n.len > 1 and n[1].kind in {nkCharLit..nkUInt64Lit}: @@ -662,10 +622,9 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = # bug #14159, we cannot reason about sinkParam[].location as it can # still be shared for tyRef. n = n[0] - return n.kind == nkSym and n.sym.owner == owner and ( - n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned}) - else: - break + return n.kind == nkSym and n.sym.owner == owner and + (n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned}) + else: break # XXX Allow closure deref operations here if we know # the owner controlled the closure allocation? result = n.kind == nkSym and n.sym.owner == owner and @@ -682,36 +641,37 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = # free the old data and all is lost! Lesson: Don't be too smart, trust the # lower level C++ optimizer to specialize this code. -proc genDef(c: var Con; n: PNode) = - var m = n - # XXX do something about this duplicated logic here. +proc skipTrivials(c: var Con, n: PNode): PNode = + result = n while true: - case m.kind - of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv, - nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr: - m = m[0] + case result.kind + of PathKinds0 - {nkBracketExpr}: + result = result[0] of nkBracketExpr: - gen(c, m[1]) - m = m[0] - of nkHiddenDeref, nkDerefExpr: - m = m[0] - else: - break + gen(c, result[1]) + result = result[0] + of PathKinds1: + result = result[1] + else: break + +proc genUse(c: var Con; orig: PNode) = + let n = c.skipTrivials(orig) if n.kind == nkSym and n.sym.kind in InterestingSyms: - c.code.add Instr(n: n, kind: def) - elif isAnalysableFieldAccess(n, c.owner): - c.code.add Instr(n: n, kind: def) - else: - # bug #13314: An assignment to t5.w = -5 is a usage of 't5' - # we still need to gather the use information: + c.code.add Instr(n: orig, kind: use) + elif n.kind in nkCallKinds: gen(c, n) +proc genDef(c: var Con; orig: PNode) = + let n = c.skipTrivials(orig) + + if n.kind == nkSym and n.sym.kind in InterestingSyms: + c.code.add Instr(n: orig, kind: def) + proc genCall(c: var Con; n: PNode) = gen(c, n[0]) var t = n[0].typ if t != nil: t = t.skipTypes(abstractInst) - inc c.inCall for i in 1.. abandon it. return high(int) + elif instrTargets(cfg[pc].n, location) == Partial: + # only partially writes to 's' --> can't sink 's', so this def reads 's' + otherRead = cfg[pc].n + return -1 inc pc of use: - if useInstrTargets(c.g[pc], location): - c.otherRead = c.g[pc].n + if instrTargets(cfg[pc].n, location) != None: + otherRead = cfg[pc].n return -1 inc pc of goto: - pc = pc + c.g[pc].dest + pc = pc + cfg[pc].dest of fork: # every branch must lead to the last read of the location: var variantA = pc + 1 - var variantB = pc + c.g[pc].dest + var variantB = pc + cfg[pc].dest while variantA != variantB: if min(variantA, variantB) < 0: return -1 - if max(variantA, variantB) >= c.g.len or min(variantA, variantB) >= until: + if max(variantA, variantB) >= cfg.len or min(variantA, variantB) >= until: break if variantA < variantB: - variantA = isLastRead(location, c, variantA, min(variantB, until)) + variantA = isLastRead(location, cfg, otherRead, variantA, min(variantB, until)) else: - variantB = isLastRead(location, c, variantB, min(variantA, until)) + variantB = isLastRead(location, cfg, otherRead, variantB, min(variantA, until)) pc = min(variantA, variantB) return pc proc isLastRead(n: PNode; c: var Con): bool = # first we need to search for the instruction that belongs to 'n': - c.otherRead = nil var instr = -1 let m = dfa.skipConvDfa(n) @@ -116,36 +119,37 @@ proc isLastRead(n: PNode; c: var Con): bool = # ensure that we don't find another 'use X' instruction. if instr+1 >= c.g.len: return true - result = isLastRead(n, c, instr+1, int.high) >= 0 + c.otherRead = nil + result = isLastRead(n, c.g, c.otherRead, instr+1, int.high) >= 0 dbg: echo "ugh ", c.otherRead.isNil, " ", result -proc isFirstWrite(location: PNode; c: var Con; pc, until: int): int = +proc isFirstWrite(location: PNode; cfg: ControlFlowGraph; pc, until: int): int = var pc = pc while pc < until: - case c.g[pc].kind + case cfg[pc].kind of def: - if defInstrTargets(c.g[pc], location): + if instrTargets(cfg[pc].n, location) != None: # a definition of 's' before ours makes ours not the first write return -1 inc pc of use: - if useInstrTargets(c.g[pc], location): + if instrTargets(cfg[pc].n, location) != None: return -1 inc pc of goto: - pc = pc + c.g[pc].dest + pc = pc + cfg[pc].dest of fork: # every branch must not contain a def/use of our location: var variantA = pc + 1 - var variantB = pc + c.g[pc].dest + var variantB = pc + cfg[pc].dest while variantA != variantB: if min(variantA, variantB) < 0: return -1 if max(variantA, variantB) > until: break if variantA < variantB: - variantA = isFirstWrite(location, c, variantA, min(variantB, until)) + variantA = isFirstWrite(location, cfg, variantA, min(variantB, until)) else: - variantB = isFirstWrite(location, c, variantB, min(variantA, until)) + variantB = isFirstWrite(location, cfg, variantB, min(variantA, until)) pc = min(variantA, variantB) return pc @@ -165,7 +169,7 @@ proc isFirstWrite(n: PNode; c: var Con): bool = # ensure that we don't find another 'def/use X' instruction. if instr == 0: return true - result = isFirstWrite(n, c, 0, instr) >= 0 + result = isFirstWrite(n, c.g, 0, instr) >= 0 proc initialized(code: ControlFlowGraph; pc: int, init, uninit: var IntSet; until: int): int = From 37325564689c638ef409c79b8380d7564f173c72 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 28 Jun 2020 14:34:34 -0700 Subject: [PATCH 0801/4254] fix `./koch tests` following #14823 (#14845) --- testament/testament.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/testament.nim b/testament/testament.nim index 58c4e5196..83446336c 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -693,7 +693,8 @@ proc main() = myself &= " " & quoteShell("--targets:" & targetsStr) myself &= " " & quoteShell("--nim:" & compilerPrefix) - myself &= " --batch:" & testamentData0.batchArg + if testamentData0.batchArg.len > 0: + myself &= " --batch:" & testamentData0.batchArg if skipFrom.len > 0: myself &= " " & quoteShell("--skipFrom:" & skipFrom) From 299ddda5f6eaceab0bde443159bd17bab1cdf2f1 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 29 Jun 2020 08:49:53 +0200 Subject: [PATCH 0802/4254] Make unreachable code a warning instead of an error (#14816) * Make unreachable code a warning * Adapt test * Trigger CI --- compiler/lineinfos.nim | 6 ++++-- compiler/semstmts.nim | 6 ++---- tests/controlflow/tstatret.nim | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 6287e21aa..378e06c72 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -49,7 +49,8 @@ type warnEachIdentIsTuple, warnUnsafeSetLen, warnUnsafeDefault, - warnProveInit, warnProveField, warnProveIndex, warnUnreachableElse, + warnProveInit, warnProveField, warnProveIndex, + warnUnreachableElse, warnUnreachableCode, warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, @@ -110,6 +111,7 @@ const warnProveField: "cannot prove that field '$1' is accessible", warnProveIndex: "cannot prove index '$1' is valid", warnUnreachableElse: "unreachable else, all cases are already covered", + warnUnreachableCode: "unreachable code after 'return' statement or '{.noReturn.}' proc", warnStaticIndexCheck: "$1", warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", @@ -169,7 +171,7 @@ const "UnsafeCode", "UnusedImport", "InheritFromException", "EachIdentIsTuple", "UnsafeSetLen", "UnsafeDefault", - "ProveInit", "ProveField", "ProveIndex", "UnreachableElse", + "ProveInit", "ProveField", "ProveIndex", "UnreachableElse", "UnreachableCode", "IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "ResultShadowed", "Spacing", "CaseTransition", "CycleCreated", diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5875a3b68..47a5130af 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2269,10 +2269,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = sfNoReturn in n[i][0].sym.flags: for j in i + 1.. Date: Mon, 29 Jun 2020 08:50:37 +0200 Subject: [PATCH 0803/4254] SSL_CTX_load_verify_locations parameters are reversed (#14815) [backport] --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c1896dc1c..c47d9e8a6 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -614,7 +614,7 @@ when defineSsl: if verifyMode != CVerifyNone: # Use the caDir and caFile parameters if set if caDir != "" or caFile != "": - if newCTX.SSL_CTX_load_verify_locations(caDir, caFile) != 0: + if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != 0: raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).") else: From 5d5df4a39413b76d6131cb3d85e606e255d54b22 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 29 Jun 2020 04:33:07 -0300 Subject: [PATCH 0804/4254] Clean out Deprecated proc (#14797) * Remove and/or clean out Deprecated 'add' proc for floats * Update a test --- lib/system/strmantle.nim | 8 -------- tests/concepts/t3330.nim | 21 ++++++--------------- tests/system/tostring.nim | 4 ++-- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index cb26833ac..43a769b5f 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -66,10 +66,6 @@ proc addInt*(result: var string; x: int64) = for j in 0..i div 2 - 1: swap(result[base+j], result[base+i-j-1]) -proc add*(result: var string; x: int64) {.deprecated: - "Deprecated since v0.20, use 'addInt'".} = - addInt(result, x) - proc nimIntToStr(x: int): string {.compilerRtl.} = result = newStringOfCap(sizeof(x)*4) result.addInt x @@ -98,10 +94,6 @@ proc addFloat*(result: var string; x: float) = let n = writeFloatToBuffer(buffer, x) result.addCstringN(cstring(buffer[0].addr), n) -proc add*(result: var string; x: float) {.deprecated: - "Deprecated since v0.20, use 'addFloat'".} = - addFloat(result, x) - proc nimFloatToStr(f: float): string {.compilerproc.} = result = newStringOfCap(8) result.addFloat f diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index 6faa79c9d..b92af5485 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -1,21 +1,13 @@ discard """ errormsg: "type mismatch: got " nimout: ''' -t3330.nim(78, 4) Error: type mismatch: got +t3330.nim(70, 4) Error: type mismatch: got but expected one of: proc test(foo: Foo[int]) first type mismatch at position: 1 required type for foo: Foo[int] but expression 'bar' is of type: Bar[system.int] -t3330.nim(63, 8) Hint: Non-matching candidates for add(k, string, T) -proc add(result: var string; x: float) - first type mismatch at position: 1 - required type for result: var string - but expression 'k' is of type: Alias -proc add(result: var string; x: int64) - first type mismatch at position: 1 - required type for result: var string - but expression 'k' is of type: Alias +t3330.nim(55, 8) Hint: Non-matching candidates for add(k, string, T) proc add(x: var string; y: char) first type mismatch at position: 1 required type for x: var string @@ -37,10 +29,10 @@ proc add[T](x: var seq[T]; y: sink T) required type for x: var seq[T] but expression 'k' is of type: Alias -t3330.nim(63, 8) template/generic instantiation of `add` from here -t3330.nim(70, 6) Foo: 'bar.value' cannot be assigned to -t3330.nim(63, 8) template/generic instantiation of `add` from here -t3330.nim(71, 6) Foo: 'bar.x' cannot be assigned to +t3330.nim(55, 8) template/generic instantiation of `add` from here +t3330.nim(62, 6) Foo: 'bar.value' cannot be assigned to +t3330.nim(55, 8) template/generic instantiation of `add` from here +t3330.nim(63, 6) Foo: 'bar.x' cannot be assigned to expression: test(bar)''' """ @@ -76,4 +68,3 @@ proc test(foo: Foo[int]) = var bar = Bar[int]() bar.test() - diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index ea4a44417..4ff363075 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -83,9 +83,9 @@ proc stringCompare() = doAssert b == "bee" b.add g doAssert b == "bee" - c.add 123.456 + c.addFloat 123.456 doAssert c == "123.456" - d.add 123456 + d.addInt 123456 doAssert d == "123456" doAssert e == "" From 1b41c3122be1fa2628d814893a4f3a1196b762fc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 29 Jun 2020 00:34:05 -0700 Subject: [PATCH 0805/4254] fix #13432 typetraits.$: $(int,) is now (int,); $tuple[] is now tuple[] (#14799) * typetraits.$: $(int,) is now (int,); $tuple[] is now tuple[] * changelog --- changelog.md | 1 + compiler/types.nim | 3 ++- lib/pure/typetraits.nim | 21 --------------------- tests/metatype/ttypetraits.nim | 31 +++++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/changelog.md b/changelog.md index 54996ea34..d5f3c8aa9 100644 --- a/changelog.md +++ b/changelog.md @@ -115,6 +115,7 @@ - `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. - Add `typetraits.elementType` to get element type of an iterable. +- `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"` ## Language changes - In the newruntime it is now allowed to assign to the discriminator field diff --git a/compiler/types.nim b/compiler/types.nim index b8f58c950..0be0b3eed 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -634,13 +634,14 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < t.n.len - 1: result.add(", ") result.add(']') elif t.len == 0: - result = "tuple" + result = "tuple[]" else: if prefer == preferTypeName: result = "(" else: result = "tuple of (" for i in 0.. Date: Mon, 29 Jun 2020 10:31:25 +0200 Subject: [PATCH 0806/4254] New freebsd platforms (#14801) * add riscv as riscv64 * add all platforms supported by FreeBSD --- compiler/installer.ini | 2 +- tools/niminst/buildsh.nimf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index c59b9a2ea..543a3befb 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -9,7 +9,7 @@ Platforms: """ linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64 macosx: i386;amd64;powerpc64 solaris: i386;amd64;sparc;sparc64 - freebsd: i386;amd64;powerpc64;arm;arm64 + freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc netbsd: i386;amd64 openbsd: i386;amd64;arm;arm64 dragonfly: i386;amd64 diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 537a8a01d..5d532a0fd 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -185,7 +185,7 @@ case $ucpu in mycpu="arm64" ;; *arm*|*armv6l*|*armv71* ) mycpu="arm" ;; - *riscv64* ) + *riscv64|riscv* ) mycpu="riscv64" ;; *) echo 2>&1 "Error: unknown processor: $ucpu" From 74d1f2501023805dadca75e402e70ef73a1d5bf7 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 30 Jun 2020 05:01:25 -0300 Subject: [PATCH 0807/4254] Clean out oldast (#14837) * Clean out old Deprecated CLI switch * Update to remove --oldast CLI option --- changelog.md | 1 + compiler/commands.nim | 2 -- compiler/options.nim | 1 - compiler/semstmts.nim | 28 ++++++++++++---------------- compiler/suggest.nim | 5 +---- config/nim.cfg | 1 - doc/advopt.txt | 1 - 7 files changed, 14 insertions(+), 25 deletions(-) diff --git a/changelog.md b/changelog.md index d5f3c8aa9..2d9a78d3b 100644 --- a/changelog.md +++ b/changelog.md @@ -220,6 +220,7 @@ proc mydiv(a, b): int {.raises: [].} = See [docgen](docgen.html#introduction-quick-start) for details. - Removed the `--oldNewlines` switch. - Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. +- Removed the `--oldast` switch. - `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is now "typed" instead of "stmt" diff --git a/compiler/commands.nim b/compiler/commands.nim index fc559d68c..95df45ebe 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -320,7 +320,6 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool of "patterns", "trmacros": result = contains(conf.options, optTrMacros) of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) of "nilseqs": result = contains(conf.options, optNilSeqs) - of "oldast": result = contains(conf.options, optOldAst) else: invalidCmdLineOption(conf, passCmd1, switch, info) proc processPath(conf: ConfigRef; path: string, info: TLineInfo, @@ -583,7 +582,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; undefSymbol(conf.symbols, "hotcodereloading") undefSymbol(conf.symbols, "useNimRtl") of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info) - of "oldast": processOnOffSwitch(conf, {optOldAst}, arg, pass, info) of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) of "floatchecks": processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) diff --git a/compiler/options.nim b/compiler/options.nim index 92c664587..abec038ed 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -40,7 +40,6 @@ type # please make sure we have under 32 options optTrMacros, # en/disable pattern matching optMemTracker, optNilSeqs, - optOldAst, optSinkInference # 'sink T' inference diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 47a5130af..a2515357b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -586,23 +586,19 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = b.add a[^2] b.add copyTree(def) addToVarSection(c, result, n, b) - if optOldAst in c.config.options: - if def.kind != nkEmpty: - v.ast = def + # this is needed for the evaluation pass, guard checking + # and custom pragmas: + var ast = newNodeI(nkIdentDefs, a.info) + if a[j].kind == nkPragmaExpr: + var p = newNodeI(nkPragmaExpr, a.info) + p.add newSymNode(v) + p.add a[j][1].copyTree + ast.add p else: - # this is needed for the evaluation pass, guard checking - # and custom pragmas: - var ast = newNodeI(nkIdentDefs, a.info) - if a[j].kind == nkPragmaExpr: - var p = newNodeI(nkPragmaExpr, a.info) - p.add newSymNode(v) - p.add a[j][1].copyTree - ast.add p - else: - ast.add newSymNode(v) - ast.add a[^2].copyTree - ast.add def - v.ast = ast + ast.add newSymNode(v) + ast.add a[^2].copyTree + ast.add def + v.ast = ast else: if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j] # bug #7663, for 'nim check' this can be a non-tuple: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 58b54cc03..a9f248fb9 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -510,10 +510,7 @@ proc extractPragma(s: PSym): PNode = proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = var pragmaNode: PNode - if optOldAst in conf.options and s.kind in {skVar, skLet}: - pragmaNode = nil - else: - pragmaNode = if s.kind == skEnumField: extractPragma(s.owner) else: extractPragma(s) + pragmaNode = if s.kind == skEnumField: extractPragma(s.owner) else: extractPragma(s) let name = if s.kind == skEnumField and sfDeprecated notin s.flags: "enum '" & s.owner.name.s & "' which contains field '" & s.name.s & "'" else: s.name.s diff --git a/config/nim.cfg b/config/nim.cfg index 206f80413..c888fcf89 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -314,7 +314,6 @@ tcc.options.always = "-w" @if nimv019: --multimethods:on - --oldAst:on --define:nimOldCaseObjects --define:nimOldShiftRight @end diff --git a/doc/advopt.txt b/doc/advopt.txt index 588d4eece..f5b8c9ec9 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -105,7 +105,6 @@ Advanced options: backwards compatibility --seqsv2:on|off use the new string/seq implementation based on destructors - --oldast:on|off use old AST for backwards compatibility --skipCfg:on|off do not read the nim installation's configuration file --skipUserCfg:on|off do not read the user's configuration file --skipParentCfg:on|off do not read the parent dirs' configuration files From 04deb6c9421d0a11cedfc7e8c52ae3b30e7bf1db Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 30 Jun 2020 05:08:16 -0300 Subject: [PATCH 0808/4254] Clean out dom (#14855) * Clean out dom * Clean out dom --- changelog.md | 2 +- lib/js/dom.nim | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 2d9a78d3b..b983478d2 100644 --- a/changelog.md +++ b/changelog.md @@ -183,7 +183,7 @@ proc mydiv(a, b): int {.raises: [].} = - Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. - +- Remove `dom.releaseEvents` and `dom.captureEvents`, was deprecated. ## Compiler changes diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 262c0daad..09e45c04d 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1415,7 +1415,6 @@ proc removeEventListener*(et: EventTarget; ev: cstring; cb: proc(ev: Event)) proc alert*(w: Window, msg: cstring) proc back*(w: Window) proc blur*(w: Window) -proc captureEvents*(w: Window, eventMask: int) {.deprecated.} proc clearInterval*(w: Window, interval: ref Interval) proc clearTimeout*(w: Window, timeout: ref TimeOut) proc close*(w: Window) @@ -1435,7 +1434,6 @@ proc open*(w: Window, uri, windowname: cstring, properties: cstring = nil): Window proc print*(w: Window) proc prompt*(w: Window, text, default: cstring): cstring -proc releaseEvents*(w: Window, eventMask: int) {.deprecated.} proc resizeBy*(w: Window, x, y: int) proc resizeTo*(w: Window, x, y: int) proc routeEvent*(w: Window, event: Event) @@ -1469,7 +1467,6 @@ proc querySelector*(n: Node, selectors: cstring): Element proc querySelectorAll*(n: Node, selectors: cstring): seq[Element] # Document "methods" -proc captureEvents*(d: Document, eventMask: int) {.deprecated.} proc createAttribute*(d: Document, identifier: cstring): Node proc getElementsByName*(d: Document, name: cstring): seq[Element] proc getElementsByTagName*(d: Document, name: cstring): seq[Element] @@ -1477,7 +1474,6 @@ proc getElementsByClassName*(d: Document, name: cstring): seq[Element] proc getSelection*(d: Document): Selection proc handleEvent*(d: Document, event: Event) proc open*(d: Document) -proc releaseEvents*(d: Document, eventMask: int) {.deprecated.} proc routeEvent*(d: Document, event: Event) proc write*(d: Document, text: cstring) proc writeln*(d: Document, text: cstring) From 89a15e417df52454aa5c40ba058c9b19425dd184 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 30 Jun 2020 05:21:30 -0700 Subject: [PATCH 0809/4254] CI openbsd: 3x batching via NIM_TESTAMENT_BATCH ; overall CI finishes in 21m instead of 34m (#14851) * CI openbsd: 2x batching via NIM_TESTAMENT_BATCH * auto-generate .builds/openbsd_x.yml to avoid code duplication * 3x batching --- .builds/{openbsd.yml => openbsd_0.yml} | 3 ++ .builds/openbsd_1.yml | 34 ++++++++++++++ .builds/openbsd_2.yml | 34 ++++++++++++++ testament/specs.nim | 3 ++ tests/dll/server.nim | 1 + tools/ci_generate.nim | 63 ++++++++++++++++++++++++++ 6 files changed, 138 insertions(+) rename .builds/{openbsd.yml => openbsd_0.yml} (85%) create mode 100644 .builds/openbsd_1.yml create mode 100644 .builds/openbsd_2.yml create mode 100644 tools/ci_generate.nim diff --git a/.builds/openbsd.yml b/.builds/openbsd_0.yml similarity index 85% rename from .builds/openbsd.yml rename to .builds/openbsd_0.yml index c4db2f621..278cb3de9 100644 --- a/.builds/openbsd.yml +++ b/.builds/openbsd_0.yml @@ -1,3 +1,5 @@ +## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` + image: openbsd/latest packages: - gmake @@ -11,6 +13,7 @@ packages: sources: - https://github.com/nim-lang/Nim environment: + NIM_TESTAMENT_BATCH: "0_3" CC: /usr/bin/clang tasks: - setup: | diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml new file mode 100644 index 000000000..d3f0c8795 --- /dev/null +++ b/.builds/openbsd_1.yml @@ -0,0 +1,34 @@ +## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` + +image: openbsd/latest +packages: +- gmake +- sqlite3 +- node +- boehm-gc +- pcre +- sfml +- sdl2 +- libffi +sources: +- https://github.com/nim-lang/Nim +environment: + NIM_TESTAMENT_BATCH: "1_3" + CC: /usr/bin/clang +tasks: +- setup: | + cd Nim + git clone --depth 1 -q https://github.com/nim-lang/csources.git + gmake -C csources -j $(sysctl -n hw.ncpuonline) + bin/nim c koch + echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv +- test: | + cd Nim + if ! ./koch runCI; then + nim c -r tools/ci_testresults.nim + exit 1 + fi +triggers: +- action: email + condition: failure + to: Andreas Rumpf diff --git a/.builds/openbsd_2.yml b/.builds/openbsd_2.yml new file mode 100644 index 000000000..4b63e914d --- /dev/null +++ b/.builds/openbsd_2.yml @@ -0,0 +1,34 @@ +## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` + +image: openbsd/latest +packages: +- gmake +- sqlite3 +- node +- boehm-gc +- pcre +- sfml +- sdl2 +- libffi +sources: +- https://github.com/nim-lang/Nim +environment: + NIM_TESTAMENT_BATCH: "2_3" + CC: /usr/bin/clang +tasks: +- setup: | + cd Nim + git clone --depth 1 -q https://github.com/nim-lang/csources.git + gmake -C csources -j $(sysctl -n hw.ncpuonline) + bin/nim c koch + echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv +- test: | + cd Nim + if ! ./koch runCI; then + nim c -r tools/ci_testresults.nim + exit 1 + fi +triggers: +- action: email + condition: failure + to: Andreas Rumpf diff --git a/testament/specs.nim b/testament/specs.nim index 2f2c006d8..acffbf8be 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -84,6 +84,9 @@ type parseErrors*: string # when the spec definition is invalid, this is not empty. unjoinable*: bool unbatchable*: bool + # whether this test can be batchable via `NIM_TESTAMENT_BATCH`; only very + # few tests are not batchable; the ones that are not could be turned batchable + # by making the dependencies explicit useValgrind*: bool timeout*: float # in seconds, fractions possible, # but don't rely on much precision diff --git a/tests/dll/server.nim b/tests/dll/server.nim index 2b7791d4b..dd4606298 100644 --- a/tests/dll/server.nim +++ b/tests/dll/server.nim @@ -1,6 +1,7 @@ discard """ action: compile cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file" +batchable: false """ type diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim new file mode 100644 index 000000000..bfed8d88f --- /dev/null +++ b/tools/ci_generate.nim @@ -0,0 +1,63 @@ +##[ +avoid code duplication in CI pipelines. +For now, this is only used for openbsd, but there is a lot of other code +duplication that could be removed. + +## usage +edit this file as needed and then re-generate via: +``` +nim r tools/ci_generate.nim +``` +]## + +import std/strformat + +proc genCIopenbsd(batch: int, num: int): string = + result = fmt""" +## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` + +image: openbsd/latest +packages: +- gmake +- sqlite3 +- node +- boehm-gc +- pcre +- sfml +- sdl2 +- libffi +sources: +- https://github.com/nim-lang/Nim +environment: + NIM_TESTAMENT_BATCH: "{batch}_{num}" + CC: /usr/bin/clang +tasks: +- setup: | + cd Nim + git clone --depth 1 -q https://github.com/nim-lang/csources.git + gmake -C csources -j $(sysctl -n hw.ncpuonline) + bin/nim c koch + echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv +- test: | + cd Nim + if ! ./koch runCI; then + nim c -r tools/ci_testresults.nim + exit 1 + fi +triggers: +- action: email + condition: failure + to: Andreas Rumpf +""" + +proc main()= + let num = 3 + # if you reduce this, make sure to remove files that shouldn't be generated, + # or better, do the cleanup logic here eg: `rm .builds/openbsd_*` + for i in 0.. Date: Tue, 30 Jun 2020 21:21:37 +0800 Subject: [PATCH 0810/4254] add debug fmt string like python's (#14808) * add debug format string * remove try except * add changelog --- changelog.md | 2 + lib/pure/strformat.nim | 14 ++++- tests/stdlib/tstrformat.nim | 105 ++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index b983478d2..5f10c5c19 100644 --- a/changelog.md +++ b/changelog.md @@ -117,6 +117,8 @@ - Add `typetraits.elementType` to get element type of an iterable. - `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"` +- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. + ## Language changes - In the newruntime it is now allowed to assign to the discriminator field without restrictions as long as case object doesn't have custom destructor. diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 5f7ef380d..0ea784a43 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -552,8 +552,18 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = var subexpr = "" while i < f.len and f[i] != closeChar and f[i] != ':': - subexpr.add f[i] - inc i + if f[i] == '=': + let start = i + inc i + i += f.skipWhitespace(i) + if f[i] == closeChar or f[i] == ':': + result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i])) + else: + subexpr.add f[start ..< i] + else: + subexpr.add f[i] + inc i + var x: NimNode try: x = parseExpr(subexpr) diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 22c0cf95d..c65165946 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -6,6 +6,8 @@ output: '''Received (name: "Foo", species: "Bar")''' # issue #7632 import genericstrformat +import strutils + doAssert works(5) == "formatted 5" doAssert fails0(6) == "formatted 6" @@ -86,6 +88,8 @@ proc formatValue(result: var string; value: (array|seq|openArray); specifier: st doAssert fmt"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #" doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] =" +doAssert fmt"data1: {data1=:8} #" == "data1: data1=[ 1, 10000, 10000000] #" +doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000, 100, 1] =" # custom format Value @@ -103,6 +107,7 @@ proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) = let v1 = Vec2[float32](x:1.0, y: 2.0) let v2 = Vec2[int32](x:1, y: 1337) doAssert fmt"v1: {v1:+08} v2: {v2:>4}" == "v1: [+0000001, +0000002] v2: [ 1, 1337]" +doAssert fmt"v1: {v1=:+08} v2: {v2=:>4}" == "v1: v1=[+0000001, +0000002] v2: v2=[ 1, 1337]" # bug #11012 @@ -126,6 +131,14 @@ doAssert fmt"{pos:3o}" == "100" doAssert fmt"{pos:3x}" == " 40" doAssert fmt"{pos:3X}" == " 40" +doAssert fmt"{pos=:3}" == "pos= 64" +doAssert fmt"{pos=:3b}" == "pos=1000000" +doAssert fmt"{pos=:3d}" == "pos= 64" +doAssert fmt"{pos=:3o}" == "pos=100" +doAssert fmt"{pos=:3x}" == "pos= 40" +doAssert fmt"{pos=:3X}" == "pos= 40" + + let nat: Natural = 64 doAssert fmt"{nat:3}" == " 64" doAssert fmt"{nat:3b}" == "1000000" @@ -134,6 +147,13 @@ doAssert fmt"{nat:3o}" == "100" doAssert fmt"{nat:3x}" == " 40" doAssert fmt"{nat:3X}" == " 40" +doAssert fmt"{nat=:3}" == "nat= 64" +doAssert fmt"{nat=:3b}" == "nat=1000000" +doAssert fmt"{nat=:3d}" == "nat= 64" +doAssert fmt"{nat=:3o}" == "nat=100" +doAssert fmt"{nat=:3x}" == "nat= 40" +doAssert fmt"{nat=:3X}" == "nat= 40" + # bug #12612 proc my_proc = const value = "value" @@ -186,6 +206,14 @@ doAssert fmt"{msg}{'\n'}" == "hello\n" doAssert fmt("{msg}\n") == "hello\n" doAssert "{msg}\n".fmt == "hello\n" +doAssert fmt"{msg=}\n" == "msg=hello\\n" + +doAssert &"{msg=}\n" == "msg=hello\n" + +doAssert fmt"{msg=}{'\n'}" == "msg=hello\n" +doAssert fmt("{msg=}\n") == "msg=hello\n" +doAssert "{msg=}\n".fmt == "msg=hello\n" + doAssert &"""{"abc":>4}""" == " abc" doAssert &"""{"abc":<4}""" == "abc " @@ -204,3 +232,80 @@ doAssert fmt"{123.456:<9.4f}" == "123.4560 " doAssert fmt"{123.456:e}" == "1.234560e+02" doAssert fmt"{123.456:>13e}" == " 1.234560e+02" doAssert fmt"{123.456:13e}" == " 1.234560e+02" + + +doAssert &"""{"abc"=:>4}""" == "\"abc\"= abc" +doAssert &"""{"abc"=:<4}""" == "\"abc\"=abc " + +doAssert fmt"{-12345=:08}" == "-12345=-0012345" +doAssert fmt"{-1=:3}" == "-1= -1" +doAssert fmt"{-1=:03}" == "-1=-01" +doAssert fmt"{16=:#X}" == "16=0x10" + +doAssert fmt"{123.456=}" == "123.456=123.456" +doAssert fmt"{123.456=:>9.3f}" == "123.456= 123.456" +doAssert fmt"{123.456=:9.3f}" == "123.456= 123.456" +doAssert fmt"{123.456=:9.4f}" == "123.456= 123.4560" +doAssert fmt"{123.456=:>9.0f}" == "123.456= 123." +doAssert fmt"{123.456=:<9.4f}" == "123.456=123.4560 " + +doAssert fmt"{123.456=:e}" == "123.456=1.234560e+02" +doAssert fmt"{123.456=:>13e}" == "123.456= 1.234560e+02" +doAssert fmt"{123.456=:13e}" == "123.456= 1.234560e+02" + +## tests for debug format string +block: + var name = "hello" + let age = 21 + const hobby = "swim" + doAssert fmt"{age*9 + 16=}" == "age*9 + 16=205" + doAssert &"name: {name =}\nage: { age =: >7}\nhobby: { hobby= : 8}" == + "name: name =hello\nage: age = 21\nhobby: hobby= swim " + doAssert fmt"{age == 12}" == "false" + doAssert fmt"{name.toUpperAscii( ) = }" == "name.toUpperAscii( ) = HELLO" + doAssert fmt"{ toUpperAscii( s = name ) = }" == " toUpperAscii( s = name ) = HELLO" + doAssert fmt"{ strutils.toUpperAscii( s = name ) = }" == " strutils.toUpperAscii( s = name ) = HELLO" + doAssert fmt"{age==12}" == "false" + doAssert fmt"{age!= 12}" == "true" + doAssert fmt"{age <= 12}" == "false" + for i in 1 .. 10: + doAssert fmt"{age.float =: .2f}" == "age.float = 21.00" + doAssert fmt"{age.float() =:.3f}" == "age.float() =21.000" + doAssert fmt"{float age= :.3f}" == "float age= 21.000" + doAssert fmt"{12 == int(`!=`(age, 12))}" == "false" + doAssert fmt"{0==1}" == "false" + + +block: + let x = "hello" + doAssert fmt"{x=}" == "x=" & $x + doAssert fmt"{x =}" == "x =" & $x + + + let y = 3.1415926 + doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}" + doAssert fmt"{y=}" == fmt"y={y}" + doAssert fmt"{y =: <16}" == fmt"y ={y: <16}" + + proc hello(a: string, b: float): int = 12 + template foo(a: string, b: float): int = 18 + + doAssert fmt"{hello(x, y)=}" == "hello(x, y)=12" + doAssert fmt"{hello(x, y) =}" == "hello(x, y) =12" + doAssert fmt"{hello(x, y)= }" == "hello(x, y)= 12" + doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12" + + doAssert fmt"{x.hello(y)=}" == "x.hello(y)=12" + doAssert fmt"{x.hello(y) =}" == "x.hello(y) =12" + doAssert fmt"{x.hello(y)= }" == "x.hello(y)= 12" + doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12" + + doAssert fmt"{foo(x, y)=}" == "foo(x, y)=18" + doAssert fmt"{foo(x, y) =}" == "foo(x, y) =18" + doAssert fmt"{foo(x, y)= }" == "foo(x, y)= 18" + doAssert fmt"{foo(x, y) = }" == "foo(x, y) = 18" + + doAssert fmt"{x.foo(y)=}" == "x.foo(y)=18" + doAssert fmt"{x.foo(y) =}" == "x.foo(y) =18" + doAssert fmt"{x.foo(y)= }" == "x.foo(y)= 18" + doAssert fmt"{x.foo(y) = }" == "x.foo(y) = 18" From 36fa79a5242d2e39a83083cd66cf3af9f8931f3b Mon Sep 17 00:00:00 2001 From: Ray Imber Date: Tue, 30 Jun 2020 06:23:53 -0700 Subject: [PATCH 0811/4254] Fix asyncdispatch drain behavior (#14820) (#14838) * Fix asyncdispatch drain behavior (#14820) * Changed test to use asyncCheck instead of discard after code review (#14820) * Added some debug statements to help understand what is happening in Azure. * Removed debug statements and increased timeouts by 1 order of magnitude to account for slow Azure VMs Co-authored-by: Ray Imber --- lib/pure/asyncdispatch.nim | 13 +++++++++---- tests/async/t14820.nim | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 tests/async/t14820.nim diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index a15442109..a0bc96e72 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1601,11 +1601,16 @@ else: p.selector.registerEvent(SelectEvent(ev), data) proc drain*(timeout = 500) = - ## Waits for completion events and processes them. Raises ``ValueError`` + ## Waits for completion of **all** events and processes them. Raises ``ValueError`` ## if there are no pending operations. In contrast to ``poll`` this - ## processes as many events as are available. - if runOnce(timeout) or hasPendingOperations(): - while hasPendingOperations() and runOnce(timeout): discard + ## processes as many events as are available until the timeout has elapsed. + var curTimeout = timeout + let start = now() + while hasPendingOperations(): + discard runOnce(curTimeout) + curTimeout -= (now() - start).inMilliseconds.int + if curTimeout < 0: + break proc poll*(timeout = 500) = ## Waits for completion events and processes them. Raises ``ValueError`` diff --git a/tests/async/t14820.nim b/tests/async/t14820.nim new file mode 100644 index 000000000..359884468 --- /dev/null +++ b/tests/async/t14820.nim @@ -0,0 +1,25 @@ +discard """ +output: ''' +iteration: 1 +iteration: 2 +iteration: 3 +iteration: 4 +async done +iteration: 5 +''' +""" + +import asyncdispatch, times + +var done = false +proc somethingAsync() {.async.} = + yield sleepAsync 5000 + echo "async done" + done = true + +asyncCheck somethingAsync() +var count = 0 +while not done: + count += 1 + drain 1000 + echo "iteration: ", count From 56b3d422b014b42c6367fa56916cfd9851884506 Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 30 Jun 2020 13:25:53 +0000 Subject: [PATCH 0812/4254] typetraits: features and fixes (#14791) * typetraits: add support for nnkTypeOfExpr * typetraits: don't wrap typedesc symbols in StaticParam * typetraits: add nested generics support to genericParams * typetraits: make genericParams understand array[I, T] whackiness Also moved tests to ttypetraits * typetraits: clarify comment on genericParams --- lib/pure/typetraits.nim | 42 +++++++++++++++++++++++++++++++--- tests/metatype/ttypetraits.nim | 17 ++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index c289f6c84..0e23077ac 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -121,6 +121,9 @@ macro genericParamsImpl(T: typedesc): untyped = of nnkTypeDef: impl = impl[2] continue + of nnkTypeOfExpr: + impl = getTypeInst(impl[0]) + continue of nnkBracketExpr: for i in 1.. Date: Tue, 30 Jun 2020 11:29:53 -0300 Subject: [PATCH 0813/4254] Removed asyncdispatch.newAsyncNativeSocket, was deprecated since 0.18 (#14854) Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/pure/asyncdispatch.nim | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index 5f10c5c19..35c701a8a 100644 --- a/changelog.md +++ b/changelog.md @@ -185,6 +185,7 @@ proc mydiv(a, b): int {.raises: [].} = - Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. +- Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. - Remove `dom.releaseEvents` and `dom.captureEvents`, was deprecated. ## Compiler changes diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index a0bc96e72..2ade9065f 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1640,16 +1640,6 @@ proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET, inheritable = defined(nimInheritHandles)): AsyncFD = createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable) -proc newAsyncNativeSocket*(domain: cint, sockType: cint, - protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} = - createAsyncNativeSocketImpl(domain, sockType, protocol) - -proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP): AsyncFD - {.deprecated: "use createAsyncNativeSocket instead".} = - createAsyncNativeSocketImpl(domain, sockType, protocol) - when defined(windows) or defined(nimdoc): proc bindToDomain(handle: SocketHandle, domain: Domain) = # Extracted into a separate proc, because connect() on Windows requires From 05384efec53256d8917a80d1117d8f822a8a2f55 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 30 Jun 2020 14:09:13 -0300 Subject: [PATCH 0814/4254] Clean out sharedtables (#14858) Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/pure/collections/sharedtables.nim | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index 35c701a8a..f32d6f19f 100644 --- a/changelog.md +++ b/changelog.md @@ -185,6 +185,7 @@ proc mydiv(a, b): int {.raises: [].} = - Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. +- Remove `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. - Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. - Remove `dom.releaseEvents` and `dom.captureEvents`, was deprecated. diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 23b653c82..abef89507 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -225,13 +225,3 @@ proc init*[A, B](t: var SharedTable[A, B], initialSize = 64) = proc deinitSharedTable*[A, B](t: var SharedTable[A, B]) = deallocShared(t.data) deinitLock t.lock - -proc initSharedTable*[A, B](initialSize = 64): SharedTable[A, B] {.deprecated: - "use 'init' instead".} = - ## This is not posix compliant, may introduce undefined behavior. - assert isPowerOfTwo(initialSize) - result.counter = 0 - result.dataLen = initialSize - result.data = cast[KeyValuePairSeq[A, B]](allocShared0( - sizeof(KeyValuePair[A, B]) * initialSize)) - initLock result.lock From 2867a33ebcaddccdb52b101d0ea5f75f1d4bd66f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Jul 2020 00:26:23 -0700 Subject: [PATCH 0815/4254] fix #14846; add macros.extractDocCommentsAndRunnables (#14849) * fix #14846; add macros.extractDocCommentsAndRunnables * fixup * update tests * address comment --- changelog.md | 1 + lib/core/macros.nim | 36 ++++++++++++++++++++ lib/pure/asyncmacro.nim | 6 ++-- nimdoc/testproject/expected/testproject.html | 29 ++++++++++++++++ nimdoc/testproject/expected/testproject.idx | 3 ++ nimdoc/testproject/expected/theindex.html | 12 +++++++ nimdoc/testproject/testproject.nim | 14 ++++++++ 7 files changed, 98 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index f32d6f19f..287bce3da 100644 --- a/changelog.md +++ b/changelog.md @@ -116,6 +116,7 @@ - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. - Add `typetraits.elementType` to get element type of an iterable. - `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"` +- add `macros.extractDocCommentsAndRunnables` helper - `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 5be3a2cce..838707280 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1692,3 +1692,39 @@ when defined(nimMacrosSizealignof): proc isExported*(n: NimNode): bool {.noSideEffect.} = ## Returns whether the symbol is exported or not. + +proc extractDocCommentsAndRunnables*(n: NimNode): NimNode = + ## returns a `nnkStmtList` containing the top-level doc comments and + ## runnableExamples in `a`, stopping at the first child that is neither. + ## Example: + ## + ## .. code-block:: nim + ## import macros + ## macro transf(a): untyped = + ## result = quote do: + ## proc fun2*() = discard + ## let header = extractDocCommentsAndRunnables(a.body) + ## # correct usage: rest is appended + ## result.body = header + ## result.body.add quote do: discard # just an example + ## # incorrect usage: nesting inside a nnkStmtList: + ## # result.body = quote do: (`header`; discard) + ## + ## proc fun*() {.transf.} = + ## ## first comment + ## runnableExamples: discard + ## runnableExamples: discard + ## ## last comment + ## discard # first statement after doc comments + runnableExamples + ## ## not docgen'd + + result = newStmtList() + for ni in n: + case ni.kind + of nnkCommentStmt: + result.add ni + of nnkCall: + if ni[0].kind == nnkIdent and ni[0].strVal == "runnableExamples": + result.add ni + else: break + else: break diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 621a4b00c..219ef6c67 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -180,8 +180,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # Extract the documentation comment from the original procedure declaration. # Note that we're not removing it from the body in order not to make this # transformation even more complex. - if prc.body.len > 1 and prc.body[0].kind == nnkCommentStmt: - outerProcBody.add(prc.body[0]) + let body2 = extractDocCommentsAndRunnables(prc.body) # -> var retFuture = newFuture[T]() var retFutureSym = genSym(nskVar, "retFuture") @@ -276,9 +275,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = (cast[type(f)](internalTmpFuture)).read() if procBody.kind != nnkEmpty: - result.body = quote: + body2.add quote do: `awaitDefinition` `outerProcBody` + result.body = body2 #echo(treeRepr(result)) #if prcName == "recvLineInto": diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index a4f8876fd..648ecb629 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -200,6 +200,12 @@ function main() { title="low2[T: Ordinal | enum | range](x: T): T">low2
    • tripleStrLitTest
    • +
    • asyncFun1
    • +
    • asyncFun2
    • +
    • asyncFun3
    @@ -655,6 +661,29 @@ at indent 0 discard # should be in
    + + +
    proc asyncFun1(): Future[int] {...}{.raises: [Exception, ValueError], tags: [RootEffect].}
    +
    + +ok1 + +
    + +
    proc asyncFun2(): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}
    +
    + + + +
    + +
    proc asyncFun3(): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}
    +
    + + +

    Example:

    +
    discard
    ok1 +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 6d0bc6c5e..0b75b29d2 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -50,4 +50,7 @@ foo testproject.html#foo.t,SomeType,SomeType testproject: foo(a, b: SomeType) myfn testproject.html#myfn.t testproject: myfn() z14 testproject.html#z14.t testproject: z14() z15 testproject.html#z15.t testproject: z15() +asyncFun1 testproject.html#asyncFun1 testproject: asyncFun1(): Future[int] +asyncFun2 testproject.html#asyncFun2 testproject: asyncFun2(): owned(Future[void]) +asyncFun3 testproject.html#asyncFun3 testproject: asyncFun3(): owned(Future[void]) testNimDocTrailingExample testproject.html#testNimDocTrailingExample.t testproject: testNimDocTrailingExample() diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 8d34506a6..0b835c409 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -85,6 +85,18 @@ function main() {
  • utils: aEnum(): untyped
  • +
    asyncFun1:
    +
    asyncFun2:
    +
    asyncFun3:
    aVariable:
    • testproject: aVariable
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 5282c6f77..25cdf39a4 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -343,6 +343,20 @@ when true: # issue #14473 toSeq([1,2]) echo doit() # using doAssert or similar to avoid echo would "hide" the original bug +when true: # issue #14846 + import asyncdispatch + proc asyncFun1*(): Future[int] {.async.} = + ## ok1 + result = 1 + proc asyncFun2*() {.async.} = discard + proc asyncFun3*() {.async.} = + runnableExamples: + discard + ## ok1 + discard + ## should be out + discard + when true: template testNimDocTrailingExample*() = # this must be last entry in this file, it checks against a bug (that got fixed) From 1edb9a6178d868e34e76faf9e2a05afbc1431cb0 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 1 Jul 2020 11:40:13 +0200 Subject: [PATCH 0816/4254] fix #14401, trailing comma confuses nimpretty (#14867) --- compiler/layouter.nim | 3 +++ nimpretty/tests/exhaustive.nim | 21 +++++++++++++++++++++ nimpretty/tests/expected/exhaustive.nim | 23 ++++++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/compiler/layouter.nim b/compiler/layouter.nim index 2477458f1..f5d3084dc 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -452,6 +452,9 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if tok.tokType in openPars and tok.indent > em.indentStack[^1]: while em.indentStack[^1] < tok.indent: em.indentStack.add(em.indentStack[^1] + em.indWidth) + while em.indentStack[^1] > tok.indent: + discard em.indentStack.pop() + # aka: we are in an expression context: let alignment = max(tok.indent - em.indentStack[^1], 0) em.indentLevel = alignment + em.indentStack.high * em.indWidth diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index d61820f7a..2ba885d9a 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -822,3 +822,24 @@ proc f = # doesn't break the code, but leaving indentation as is would be nice. let x = if true: callingProcWhatever() else: callingADifferentProc() + + +type + EventKind = enum + Stop, StopSuccess, StopError, + SymbolChange, TextChange, + + SpinnyEvent = tuple + kind: EventKind + payload: string + + +type + EventKind2 = enum + Stop2, StopSuccess2, StopError2, + SymbolChange2, TextChange2, + +type + SpinnyEvent2 = tuple + kind: EventKind + payload: string diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim index e120cf019..cfe9a43fa 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -812,7 +812,7 @@ let foo = if cond: let a = [[aaadsfas, bbb], - [ccc, ddd]] + [ccc, ddd]] let b = [ [aaa, bbb], @@ -835,3 +835,24 @@ proc f = # doesn't break the code, but leaving indentation as is would be nice. let x = if true: callingProcWhatever() else: callingADifferentProc() + + +type + EventKind = enum + Stop, StopSuccess, StopError, + SymbolChange, TextChange, + + SpinnyEvent = tuple + kind: EventKind + payload: string + + +type + EventKind2 = enum + Stop2, StopSuccess2, StopError2, + SymbolChange2, TextChange2, + +type + SpinnyEvent2 = tuple + kind: EventKind + payload: string From 1440e70c62e7dc2e2a2062c1291f65c12055818a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 1 Jul 2020 11:41:03 +0200 Subject: [PATCH 0817/4254] allow packed union (#14868) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Arne Döring --- compiler/sizealignoffsetimpl.nim | 16 +++++++--------- tests/misc/tsizeof.nim | 10 ++++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 4d73923db..baa2c40f9 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -164,7 +164,7 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a accum.maxAlign = szUnknownSize accum.offset = szUnknownSize -proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var OffsetAccum) = +proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bool; accum: var OffsetAccum) = ## ``accum.offset`` will the offset from the larget member of the union. case n.kind of nkRecCase: @@ -175,7 +175,7 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var let accumRoot = accum # copy, because each branch should start af the same offset for i, child in n.sons: var branchAccum = accumRoot - computeUnionObjectOffsetsFoldFunction(conf, child, branchAccum) + computeUnionObjectOffsetsFoldFunction(conf, child, packed, branchAccum) accum.mergeBranch(branchAccum) of nkSym: var size = szUnknownSize @@ -183,7 +183,7 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var if n.sym.bitsize == 0: # 0 represents bitsize not set computeSizeAlign(conf, n.sym.typ) size = n.sym.typ.size.int - align = n.sym.typ.align.int + align = if packed: 1 else: n.sym.typ.align.int accum.align(align) if n.sym.alignment > 0: accum.align(n.sym.alignment) @@ -365,16 +365,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = else: OffsetAccum(maxAlign: 1) if tfUnion in typ.flags: - if tfPacked in typ.flags: - let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo - localError(conf, info, "union type may not be packed.") - accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize) - elif accum.offset != 0: + if accum.offset != 0: let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo localError(conf, info, "union type may not have an object header") accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize) + elif tfPacked in typ.flags: + computeUnionObjectOffsetsFoldFunction(conf, typ.n, true, accum) else: - computeUnionObjectOffsetsFoldFunction(conf, typ.n, accum) + computeUnionObjectOffsetsFoldFunction(conf, typ.n, false, accum) elif tfPacked in typ.flags: accum.maxAlign = 1 computeObjectOffsetsFoldFunction(conf, typ.n, true, accum) diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 579532fcc..c1d9df611 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -694,3 +694,13 @@ type doAssert sizeof(O0) == 1 doAssert sizeof(T0) == 1 + + +type + # this thing may not have padding bytes at the end + PackedUnion* {.union, packed.} = object + a*: array[11, byte] + b*: int64 + +doAssert sizeof(PackedUnion) == 11 +doAssert alignof(PackedUnion) == 1 From 930a0c999b823ae33cecc765110f10b4eaabfcfb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Jul 2020 14:16:22 -0700 Subject: [PATCH 0818/4254] cleanup comment now that #14434 was fixed (#14874) --- nimdoc/testproject/subdir/subdir_b/utils.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index ad8f3d162..128e8e481 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -21,8 +21,6 @@ More text. ]## -# BUG: module link in theindex.html is wrong, see #14434 - type SomeType* = enum enumValueA, From cbcaf2bbc4c7a818747a27f365c4cd1bf54feedf Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 1 Jul 2020 18:16:50 -0300 Subject: [PATCH 0819/4254] Clean out strutils (#14859) Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/pure/strutils.nim | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 287bce3da..49e6c23b6 100644 --- a/changelog.md +++ b/changelog.md @@ -186,6 +186,7 @@ proc mydiv(a, b): int {.raises: [].} = - Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. +- Remove `strutils.isNilOrWhitespace`, was deprecated. - Remove `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. - Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. - Remove `dom.releaseEvents` and `dom.captureEvents`, was deprecated. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 1ffc8bf22..32d6ede1e 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2935,11 +2935,6 @@ proc isEmptyOrWhitespace*(s: string): bool {.noSideEffect, rtl, ## Checks if `s` is empty or consists entirely of whitespace characters. result = s.allCharsInSet(Whitespace) -proc isNilOrWhitespace*(s: string): bool {.noSideEffect, rtl, - extern: "nsuIsNilOrWhitespace", - deprecated: "use isEmptyOrWhitespace instead".} = - ## Alias for isEmptyOrWhitespace - result = isEmptyOrWhitespace(s) when isMainModule: proc nonStaticTests = From d590611fc5de48a281db946d223def3d94b0260f Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 2 Jul 2020 03:40:58 -0300 Subject: [PATCH 0820/4254] Clean out sharedlists (#14857) --- changelog.md | 3 +++ lib/pure/collections/sharedlist.nim | 6 ------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 49e6c23b6..fded20ca6 100644 --- a/changelog.md +++ b/changelog.md @@ -191,6 +191,9 @@ proc mydiv(a, b): int {.raises: [].} = - Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. - Remove `dom.releaseEvents` and `dom.captureEvents`, was deprecated. +- Remove `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. + + ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index f9182acce..790529b79 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -94,10 +94,4 @@ proc deinitSharedList*[A](t: var SharedList[A]) = clear(t) deinitLock t.lock -proc initSharedList*[A](): SharedList[A] {.deprecated: "use 'init' instead".} = - ## This is not posix compliant, may introduce undefined behavior. - initLock result.lock - result.head = nil - result.tail = nil - {.pop.} From 366b9a7e4a067cece3b1215de7fb4dffc703e88a Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Thu, 2 Jul 2020 20:20:34 +0900 Subject: [PATCH 0821/4254] Fix #12745 (#14879) --- compiler/extccomp.nim | 12 +----------- compiler/main.nim | 5 +++++ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 6feb68f81..7d5df0906 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -281,9 +281,6 @@ const hExt* = ".h" -proc libNameTmpl(conf: ConfigRef): string {.inline.} = - result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" - proc nameToCC*(name: string): TSystemCC = ## Returns the kind of compiler referred to by `name`, or ccNone ## if the name doesn't refer to any known compiler. @@ -663,14 +660,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string, isDllBuild: bool): string = if optGenStaticLib in conf.globalOptions: - var libname: string - if not conf.outFile.isEmpty: - libname = conf.outFile.string.expandTilde - if not libname.isAbsolute(): - libname = getCurrentDir() / libname - else: - libname = (libNameTmpl(conf) % splitFile(conf.projectName).name) - result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname), + result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output), "objfiles", objfiles] else: var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe") diff --git a/compiler/main.nim b/compiler/main.nim index e498dc6b9..25a42300f 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -67,10 +67,15 @@ when not defined(leanCompiler): finishDoc2Pass(graph.config.projectName) proc setOutFile(conf: ConfigRef) = + proc libNameTmpl(conf: ConfigRef): string {.inline.} = + result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" + if conf.outFile.isEmpty: let base = conf.projectName let targetName = if optGenDynLib in conf.globalOptions: platform.OS[conf.target.targetOS].dllFrmt % base + elif optGenStaticLib in conf.globalOptions: + libNameTmpl(conf) % base else: base & platform.OS[conf.target.targetOS].exeExt conf.outFile = RelativeFile targetName From dc5a40f3f39c6ea672e6dc6aca7f8118a69dda99 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 2 Jul 2020 07:19:13 -0700 Subject: [PATCH 0822/4254] {.deprecated: [existsFile: fileExists].} (#14735) * {.deprecated: [existsFile: fileExists].} * s/existsFile/fileExists/ except under deps * workaround pending #14819 * fix test --- compiler/docgen.nim | 2 +- compiler/options.nim | 2 +- doc/manual.rst | 4 +-- koch.nim | 6 ++-- lib/packages/docutils/rst.nim | 4 +-- lib/pure/asyncftpclient.nim | 2 +- lib/pure/net.nim | 4 +-- lib/pure/os.nim | 33 +++++++++---------- lib/pure/ssl_certs.nim | 2 +- lib/system/nimscript.nim | 9 ++--- nimpretty/nimpretty.nim | 2 +- testament/categories.nim | 2 +- testament/testament.nim | 2 +- .../keineschweine/dependencies/nake/nake.nim | 2 +- .../keineschweine/enet_server/enet_server.nim | 4 +-- .../keineschweine/lib/client_helpers.nim | 2 +- tests/manyloc/keineschweine/lib/sg_assets.nim | 4 +-- .../keineschweine/server/old_dirserver.nim | 2 +- .../keineschweine/server/old_sg_server.nim | 4 +-- tests/manyloc/nake/nake.nim | 2 +- tests/manyloc/nake/nakefile.nim | 2 +- tests/misc/trunner.nim | 2 +- tests/newconfig/tfoo.nims | 2 +- tests/stdlib/tgetfileinfo.nim | 2 +- tests/test_nimscript.nims | 1 - tools/cmerge.nim | 2 +- tools/kochdocs.nim | 6 ++-- tools/nimgrep.nim | 2 +- tools/niminst/niminst.nim | 8 ++--- tools/nimweb.nim | 8 ++--- tools/vccexe/vccvswhere.nim | 4 +-- 31 files changed, 66 insertions(+), 67 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a973bdfc1..f501dcc8d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -140,7 +140,7 @@ template declareClosures = result = options.findFile(conf, s).string if result.len == 0: result = getCurrentDir() / s - if not existsFile(result): result = "" + if not fileExists(result): result = "" proc parseRst(text, filename: string, line, column: int, hasToc: var bool, diff --git a/compiler/options.nim b/compiler/options.nim index abec038ed..247f35419 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -739,7 +739,7 @@ proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile): RelativeF proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile = if f.isAbsolute: - result = if f.existsFile: AbsoluteFile(f) else: AbsoluteFile"" + result = if f.fileExists: AbsoluteFile(f) else: AbsoluteFile"" else: result = rawFindFile(conf, RelativeFile f, suppressStdlib) if result.isEmpty: diff --git a/doc/manual.rst b/doc/manual.rst index d2fcdc080..99888ad53 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7347,9 +7347,9 @@ string expressions in general: proc getDllName: string = result = "mylib.dll" - if existsFile(result): return + if fileExists(result): return result = "mylib2.dll" - if existsFile(result): return + if fileExists(result): return quit("could not load dynamic library") proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} diff --git a/koch.nim b/koch.nim index e279d76de..95c54892f 100644 --- a/koch.nim +++ b/koch.nim @@ -113,7 +113,7 @@ proc tryExec(cmd: string): bool = result = execShellCmd(cmd) == 0 proc safeRemove(filename: string) = - if existsFile(filename): removeFile(filename) + if fileExists(filename): removeFile(filename) proc overwriteFile(source, dest: string) = safeRemove(dest) @@ -280,11 +280,11 @@ proc findStartNim: string = if ok: return nim when defined(Posix): const buildScript = "build.sh" - if existsFile(buildScript): + if fileExists(buildScript): if tryExec("./" & buildScript): return "bin" / nim else: const buildScript = "build.bat" - if existsFile(buildScript): + if fileExists(buildScript): if tryExec(buildScript): return "bin" / nim echo("Found no nim compiler and every attempt to build one failed!") diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 07cb3eccc..05b58c56b 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -313,7 +313,7 @@ proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind, else: writeLine(stdout, message) proc defaultFindFile*(filename: string): string = - if existsFile(filename): result = filename + if fileExists(filename): result = filename else: result = "" proc newSharedState(options: RstParseOptions, @@ -328,7 +328,7 @@ proc newSharedState(options: RstParseOptions, proc findRelativeFile(p: RstParser; filename: string): string = result = p.filename.splitFile.dir / filename - if not existsFile(result): + if not fileExists(result): result = p.s.findFile(filename) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 132682b23..2d3556a89 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -231,7 +231,7 @@ proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} = result = splitLines(await ftp.getLines()) -proc existsFile*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} = +proc fileExists*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} = ## Determines whether ``file`` exists. var files = await ftp.listDirs() for f in items(files): diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c47d9e8a6..7aeffbc35 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -513,10 +513,10 @@ when defineSsl: # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html proc loadCertificates(ctx: SslCtx, certFile, keyFile: string) = - if certFile != "" and not existsFile(certFile): + if certFile != "" and not fileExists(certFile): raise newException(system.IOError, "Certificate file could not be found: " & certFile) - if keyFile != "" and not existsFile(keyFile): + if keyFile != "" and not fileExists(keyFile): raise newException(system.IOError, "Key file could not be found: " & keyFile) if certFile != "": diff --git a/lib/pure/os.nim b/lib/pure/os.nim index dcb63458b..5d73544ce 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1097,14 +1097,14 @@ when defined(windows) and not weirdTarget: result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or f.cFileName[1].int == dot and f.cFileName[2].int == 0) -proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", +proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], noNimJs.} = ## Returns true if `filename` exists and is a regular file or symlink. ## ## Directories, device files, named pipes and sockets return false. ## ## See also: - ## * `existsDir proc <#existsDir,string>`_ + ## * `dirExists proc <#dirExists,string>`_ ## * `symlinkExists proc <#symlinkExists,string>`_ when defined(windows): when useWinUnicode: @@ -1117,13 +1117,19 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", var res: Stat return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode) +when not defined(nimscript): + when not defined(js): # `noNimJs` doesn't work with templates, this should improve. + template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = + fileExists(args) + # {.deprecated: [existsFile: fileExists].} # pending bug #14819; this would avoid above mentioned issue + proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], noNimJs.} = ## Returns true if the directory `dir` exists. If `dir` is a file, false ## is returned. Follows symlinks. ## ## See also: - ## * `existsFile proc <#existsFile,string>`_ + ## * `fileExists proc <#fileExists,string>`_ ## * `symlinkExists proc <#symlinkExists,string>`_ when defined(windows): when useWinUnicode: @@ -1143,7 +1149,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", ## regardless of whether the link points to a directory or file. ## ## See also: - ## * `existsFile proc <#existsFile,string>`_ + ## * `fileExists proc <#fileExists,string>`_ ## * `existsDir proc <#existsDir,string>`_ when defined(windows): when useWinUnicode: @@ -1156,19 +1162,12 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", var res: Stat return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) -proc fileExists*(filename: string): bool {.inline, noNimJs.} = - ## Alias for `existsFile proc <#existsFile,string>`_. - ## - ## See also: - ## * `existsDir proc <#existsDir,string>`_ - ## * `symlinkExists proc <#symlinkExists,string>`_ - existsFile(filename) proc dirExists*(dir: string): bool {.inline, noNimJs.} = ## Alias for `existsDir proc <#existsDir,string>`_. ## ## See also: - ## * `existsFile proc <#existsFile,string>`_ + ## * `fileExists proc <#fileExists,string>`_ ## * `symlinkExists proc <#symlinkExists,string>`_ existsDir(dir) @@ -1200,7 +1199,7 @@ proc findExe*(exe: string, followSymlinks: bool = true; template checkCurrentDir() = for ext in extensions: result = addFileExt(exe, ext) - if existsFile(result): return + if fileExists(result): return when defined(posix): if '/' in exe: checkCurrentDir() else: @@ -1216,7 +1215,7 @@ proc findExe*(exe: string, followSymlinks: bool = true; var x = expandTilde(candidate) / exe for ext in extensions: var x = addFileExt(x, ext) - if existsFile(x): + if fileExists(x): when not defined(windows): while followSymlinks: # doubles as if here if x.checkSymlink: @@ -2027,7 +2026,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", # way of retrieving the true filename for x in walkFiles(result): result = x - if not existsFile(result) and not existsDir(result): + if not fileExists(result) and not existsDir(result): # consider using: `raiseOSError(osLastError(), result)` raise newException(OSError, "file '" & result & "' does not exist") else: @@ -2893,7 +2892,7 @@ when not weirdTarget and defined(openbsd): # search in path for p in split(string(getEnv("PATH")), {PathSep}): var x = joinPath(p, exePath) - if existsFile(x): + if fileExists(x): return expandFilename(x) else: result = "" @@ -2908,7 +2907,7 @@ when not (defined(windows) or defined(macosx) or weirdTarget): # iterate over any path in the $PATH environment variable for p in split(string(getEnv("PATH")), {PathSep}): var x = joinPath(p, result) - if existsFile(x): return x + if fileExists(x): return x else: result = "" diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index 806316b02..df845decc 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -79,7 +79,7 @@ iterator scanSSLCertificates*(useEnvVars = false): string = when not defined(haiku): for p in certificate_paths: if p.endsWith(".pem") or p.endsWith(".crt"): - if existsFile(p): + if fileExists(p): yield p elif existsDir(p): for fn in joinPath(p, "*").walkFiles(): diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index ceaaef013..75a4b7a6e 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -131,15 +131,16 @@ proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} = ## Checks if the file exists. builtin +template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = + # xxx: warning won't be shown for nimsscript because of current logic handling + # `foreignPackageNotes` + fileExists(args) + proc dirExists*(dir: string): bool {. tags: [ReadIOEffect].} = ## Checks if the directory `dir` exists. builtin -proc existsFile*(filename: string): bool = - ## An alias for ``fileExists``. - fileExists(filename) - proc existsDir*(dir: string): bool = ## An alias for ``dirExists``. dirExists(dir) diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index cca4e7aa8..9b5cf556b 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -86,7 +86,7 @@ proc main = quit "[Error] no input file." if outfile.len == 0: outfile = infile - if not existsFile(outfile) or not sameFile(infile, outfile): + if not fileExists(outfile) or not sameFile(infile, outfile): backup = false # no backup needed since won't be over-written if backup: let infileBackup = infile & ".backup" # works with .nim or .nims diff --git a/testament/categories.nim b/testament/categories.nim index 4dfd42fd2..6abb3faa9 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -572,7 +572,7 @@ proc `&.?`(a, b: string): string = proc processSingleTest(r: var TResults, cat: Category, options, test: string) = let test = testsDir &.? cat.string / test let target = if cat.string.normalize == "js": targetJS else: targetC - if existsFile(test): + if fileExists(test): testSpec r, makeTest(test, options, cat), {target} else: doAssert false, test & " test does not exist" diff --git a/testament/testament.nim b/testament/testament.nim index 83446336c..109ce4ed9 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -440,7 +440,7 @@ proc testSpecHelper(r: var TResults, test: TTest, expected: TSpec, else: let isJsTarget = target == targetJS var exeFile = changeFileExt(test.name, if isJsTarget: "js" else: ExeExt) - if not existsFile(exeFile): + if not fileExists(exeFile): r.addResult(test, target, expected.output, "executable not found: " & exeFile, reExeNotFound) else: diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim index 83569e30e..bc380986f 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nake.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim @@ -51,7 +51,7 @@ template withDir*(dir: string; body: stmt): stmt = cd(curDir) when true: - if not existsFile("nakefile.nim"): + if not fileExists("nakefile.nim"): echo "No nakefile.nim found. Current working dir is ", getCurrentDir() quit 1 var args = "" diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim index 336e57755..794e1c843 100644 --- a/tests/manyloc/keineschweine/enet_server/enet_server.nim +++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim @@ -118,7 +118,7 @@ when true: of cmdShortOption, cmdLongOption: case key of "f", "file": - if existsFile(val): + if fileExists(val): zoneCfgFile = val else: echo("File does not exist: ", val) @@ -136,7 +136,7 @@ when true: address.port = port var path = getAppDir()/../"data"/zoneFile - if not existsFile(path): + if not fileExists(path): echo("Zone settings file does not exist: ../data/", zoneFile) echo(path) quit(1) diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim index 5f74aef85..8c45feb62 100644 --- a/tests/manyloc/keineschweine/lib/client_helpers.nim +++ b/tests/manyloc/keineschweine/lib/client_helpers.nim @@ -127,7 +127,7 @@ proc handleFileChallenge*(serv: PServer; buffer: PBuffer) = challenge = readScFileChallenge(buffer) path = expandPath(challenge) resp: CsFileChallenge - if not existsFile(path): + if not fileExists(path): resp.needFile = true echo "Got file challenge, need file." else: diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index 7caa9c3fb..5929add43 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -221,7 +221,7 @@ template cacheImpl(procName, cacheName, resultType, body: untyped) {.dirty.} = cacheName[filename] = result template checkFile(path: untyped) {.dirty.} = - if not existsFile(path): + if not fileExists(path): errors.add("File missing: " & path) cacheImpl newSprite, SpriteSheets, PSpriteSheet: @@ -322,7 +322,7 @@ proc validateSettings*(settings: JsonNode, errors: var seq[string]): bool = inc id proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool = - if not existsFile(filename): + if not fileExists(filename): errors.add("File does not exist: "&filename) else: result = loadSettings(readFile(filename), errors) diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim index 390b738aa..cd2b60b26 100644 --- a/tests/manyloc/keineschweine/server/old_dirserver.nim +++ b/tests/manyloc/keineschweine/server/old_dirserver.nim @@ -164,7 +164,7 @@ when true: of cmdShortOption, cmdLongOption: case key of "f", "file": - if existsFile(val): + if fileExists(val): cfgFile = val else: echo("File does not exist: ", val) diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim index 473880e2b..8bd44017e 100644 --- a/tests/manyloc/keineschweine/server/old_sg_server.nim +++ b/tests/manyloc/keineschweine/server/old_sg_server.nim @@ -149,7 +149,7 @@ when true: of cmdShortOption, cmdLongOption: case key of "f", "file": - if existsFile(val): + if fileExists(val): zoneCfgFile = val else: echo("File does not exist: ", val) @@ -165,7 +165,7 @@ when true: dirServerInfo = jsonSettings["dirserver"] var path = getAppDir()/../"data"/zoneFile - if not existsFile(path): + if not fileExists(path): echo("Zone settings file does not exist: ../data/", zoneFile) echo(path) quit(1) diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim index ebcf21d19..87db5b54d 100644 --- a/tests/manyloc/nake/nake.nim +++ b/tests/manyloc/nake/nake.nim @@ -51,7 +51,7 @@ template withDir*(dir: string; body: untyped) = cd(curDir) when true: - if not existsFile("nakefile.nim"): + if not fileExists("nakefile.nim"): echo "No nakefile.nim found. Current working dir is ", getCurrentDir() quit 1 var args = "" diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 91dd61726..1da92b76b 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -86,7 +86,7 @@ task "download", "download game assets": client = newHttpClient() path.add DirSep path.add(extractFilename(GameAssets)) - if existsFile(path): + if fileExists(path): echo "The file already exists\n", "[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets case stdin.readLine.toLowerAscii diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 382fd35ae..d67547d62 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -26,7 +26,7 @@ const proc runCmd(file, options = ""): auto = let fileabs = testsDir / file.unixToNativePath - doAssert fileabs.existsFile, fileabs + doAssert fileabs.fileExists, fileabs let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs}" result = execCmdEx(cmd) when false: echo result[0] & "\n" & result[1] # for debugging diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index 4186ee047..fbff38f01 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -72,7 +72,7 @@ assert cmpic("HeLLO", "hello") == 0 assert fileExists("tests/newconfig/tfoo.nims") == true assert dirExists("tests") == true -assert existsFile("tests/newconfig/tfoo.nims") == true +assert fileExists("tests/newconfig/tfoo.nims") == true assert existsDir("tests") == true discard selfExe() diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim index d5ccdea56..19de193e4 100644 --- a/tests/stdlib/tgetfileinfo.nim +++ b/tests/stdlib/tgetfileinfo.nim @@ -20,7 +20,7 @@ proc genBadFileName(limit = 100): string = var hitLimit = true for i in 0..100: - if existsFile(result): + if fileExists(result): result.add("a") else: hitLimit = false diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 7c64ea762..1a6f26137 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -77,6 +77,5 @@ block: block: # #14142 discard existsDir("/usr") discard dirExists("/usr") - discard existsFile("/usr/foo") discard fileExists("/usr/foo") discard findExe("nim") diff --git a/tools/cmerge.nim b/tools/cmerge.nim index ae81699a6..35f2f5555 100644 --- a/tools/cmerge.nim +++ b/tools/cmerge.nim @@ -9,7 +9,7 @@ proc process(dir, infile: string, outfile: File, processed: var HashSet[string]): ProcessResult = if processed.containsOrIncl(infile): return prSkipIncludeDir let toProcess = dir / infile - if not existsFile(toProcess): + if not fileExists(toProcess): echo "Warning: could not process: ", toProcess return prAddIncludeDir echo "adding: ", toProcess diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index d0f8077ed..12d3c31a3 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -25,10 +25,10 @@ proc findNimImpl*(): tuple[path: string, ok: bool] = let nim = "nim".exe result.path = "bin" / nim result.ok = true - if existsFile(result.path): return + if fileExists(result.path): return for dir in split(getEnv("PATH"), PathSep): result.path = dir / nim - if existsFile(result.path): return + if fileExists(result.path): return # assume there is a symlink to the exe or something: return (nim, false) @@ -295,7 +295,7 @@ proc buildPdfDoc*(nimArgs, destPath: string) = removeFile(dest) moveFile(dest=dest, source=pdf) removeFile(changeFileExt(pdf, "aux")) - if existsFile(changeFileExt(pdf, "toc")): + if fileExists(changeFileExt(pdf, "toc")): removeFile(changeFileExt(pdf, "toc")) removeFile(changeFileExt(pdf, "log")) removeFile(changeFileExt(pdf, "out")) diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 42b192f24..e4f0e91aa 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -511,7 +511,7 @@ proc walker(pattern; dir: string; counter: var int, errors: var int) = if optFollow in options and optRecursive in options and path.hasRightDirectory: walker(pattern, path, counter, errors) - elif existsFile(dir): + elif fileExists(dir): processFile(pattern, dir, counter, errors) else: printError "Error: no such file or directory: " & dir diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 4746f328a..88d16f48a 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -639,13 +639,13 @@ proc xzDist(c: var ConfigData; windowsZip=false) = proc processFile(destFile, src: string) = let dest = tmpDir / destFile when false: echo "Copying ", src, " to ", dest - if not existsFile(src): + if not fileExists(src): echo "[Warning] Source file doesn't exist: ", src let destDir = dest.splitFile.dir if not dirExists(destDir): createDir(destDir) copyFileWithPermissions(src, dest) - if not windowsZip and not existsFile("build" / buildBatFile): + if not windowsZip and not fileExists("build" / buildBatFile): quit("No C sources found in ./build/, please build by running " & "./koch csource -d:release.") @@ -708,8 +708,8 @@ RunProgram="tools\downloader.exe" # -- prepare build files for .deb creation proc debDist(c: var ConfigData) = - if not existsFile(getOutputDir(c) / "build.sh"): quit("No build.sh found.") - if not existsFile(getOutputDir(c) / "install.sh"): quit("No install.sh found.") + if not fileExists(getOutputDir(c) / "build.sh"): quit("No build.sh found.") + if not fileExists(getOutputDir(c) / "install.sh"): quit("No install.sh found.") if c.debOpts.shortDesc == "": quit("shortDesc must be set in the .ini file.") if c.debOpts.licenses.len == 0: diff --git a/tools/nimweb.nim b/tools/nimweb.nim index a654c2b0a..0a853a54d 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -199,7 +199,7 @@ proc walkDirRecursively(s: var seq[string], root, ext: string) = proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) = for p in items(patterns): - if existsFile(dir / addFileExt(p, ext)): + if fileExists(dir / addFileExt(p, ext)): s.add(dir / addFileExt(p, ext)) if existsDir(dir / p): walkDirRecursively(s, dir / p, ext) @@ -273,9 +273,9 @@ proc findNim(c: TConfigData): string = if c.nimCompiler.len > 0: return c.nimCompiler var nim = "nim".exe result = "bin" / nim - if existsFile(result): return + if fileExists(result): return for dir in split(getEnv("PATH"), PathSep): - if existsFile(dir / nim): return dir / nim + if fileExists(dir / nim): return dir / nim # assume there is a symlink to the exe or something: return nim @@ -351,7 +351,7 @@ proc buildPdfDoc(c: var TConfigData, destPath: string) = removeFile(dest) moveFile(dest=dest, source=pdf) removeFile(changeFileExt(pdf, "aux")) - if existsFile(changeFileExt(pdf, "toc")): + if fileExists(changeFileExt(pdf, "toc")): removeFile(changeFileExt(pdf, "toc")) removeFile(changeFileExt(pdf, "log")) removeFile(changeFileExt(pdf, "out")) diff --git a/tools/vccexe/vccvswhere.nim b/tools/vccexe/vccvswhere.nim index 11ad39ce9..8f62f06ca 100644 --- a/tools/vccexe/vccvswhere.nim +++ b/tools/vccexe/vccvswhere.nim @@ -18,7 +18,7 @@ proc vccVswhereExtractVcVarsAllPath(vswherePath: string): string = let vsPath = execProcess(&"\"{vswherePath}\" {vswhereArgs}").strip() if vsPath.len > 0: let vcvarsallPath = joinPath(vsPath, vcvarsRelativePath) - if existsFile(vcvarsallPath): + if fileExists(vcvarsallPath): return vcvarsallPath proc vccVswhereGeneratePath(envName: string): string = @@ -41,7 +41,7 @@ proc vccVswhereVcVarsAllPath*(): string = for tryEnv in ["ProgramFiles(x86)", "ProgramFiles"]: let vswherePath = vccVswhereGeneratePath(tryEnv) - if vswherePath.len > 0 and existsFile(vswherePath): + if vswherePath.len > 0 and fileExists(vswherePath): let vcVarsAllPath = vccVswhereExtractVcVarsAllPath(vswherePath) if vcVarsAllPath.len > 0: return vcVarsAllPath From a6cbe58e8c5a9b89d749d9935ee39192de3246d9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 2 Jul 2020 07:19:43 -0700 Subject: [PATCH 0823/4254] typetraits.$: $((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)" (#14812) Co-authored-by: Andreas Rumpf --- changelog.md | 4 +++- compiler/types.nim | 3 +-- tests/errmsgs/tnested_empty_seq.nim | 2 +- tests/errmsgs/tsigmatch.nim | 6 +++--- tests/metatype/ttypetraits.nim | 6 ++---- tests/template/tgensym_instantiationinfo.nim | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index fded20ca6..030644951 100644 --- a/changelog.md +++ b/changelog.md @@ -115,7 +115,9 @@ - `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. - Add `typetraits.elementType` to get element type of an iterable. -- `typetraits.$`: `$(int,)` is now `"(int,)"`; `$tuple[]` is now `"tuple[]"` +- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; + `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; + `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` - add `macros.extractDocCommentsAndRunnables` helper - `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. diff --git a/compiler/types.nim b/compiler/types.nim index 0be0b3eed..1f787a4e5 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -636,8 +636,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = elif t.len == 0: result = "tuple[]" else: - if prefer == preferTypeName: result = "(" - else: result = "tuple of (" + result = "(" for i in 0.. +tsigmatch.nim(125, 6) Error: type mismatch: got <(string, proc (){.gcsafe, locks: 0.})> but expected one of: proc foo(x: (string, proc ())) first type mismatch at position: 1 - required type for x: tuple of (string, proc (){.closure.}) - but expression '("foobar", proc () = echo(["Hello!"]))' is of type: tuple of (string, proc (){.gcsafe, locks: 0.}) + required type for x: (string, proc (){.closure.}) + but expression '("foobar", proc () = echo(["Hello!"]))' is of type: (string, proc (){.gcsafe, locks: 0.}) expression: foo(("foobar", proc () = echo(["Hello!"]))) tsigmatch.nim(132, 11) Error: type mismatch: got diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index ca918266f..50c474fe9 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -52,10 +52,8 @@ block: # name, `$` doAssert $tuple[] == "tuple[]" doAssert $(int,) == "(int,)" doAssert $(int, float) == "(int, float)" - doAssert $((int), tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float)) == "(int, tuple[], tuple[a: uint], tuple[a: uint, b: float], tuple of (int,), tuple of (int, float))" - # xxx this is inconsistent, it should be: - # "(int, tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float))" - # which matches how you write it, is consistent with `$(int,)`, and is un-ambiguous. + doAssert $((int), tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float)) == + "(int, tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float))" block: # typeToString type MyInt = int diff --git a/tests/template/tgensym_instantiationinfo.nim b/tests/template/tgensym_instantiationinfo.nim index 305e7e1c3..4b997ed6a 100644 --- a/tests/template/tgensym_instantiationinfo.nim +++ b/tests/template/tgensym_instantiationinfo.nim @@ -5,7 +5,7 @@ discard """ # bug #7937 template printError(error: typed) = - # Error: inconsistent typing for reintroduced symbol 'instInfo': previous type was: tuple[filename: string, line: int, column: int]; new type is: tuple of (string, int, int) + # Error: inconsistent typing for reintroduced symbol 'instInfo': previous type was: tuple[filename: string, line: int, column: int]; new type is: (string, int, int) let instInfo {.gensym.} = instantiationInfo() echo "Error at ", instInfo.filename, ':', instInfo.line, ": ", error From 4f6acf24ffde4c43ea9f8c954265d23312453b31 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 3 Jul 2020 15:13:10 -0300 Subject: [PATCH 0824/4254] Add jsre (#14870) --- changelog.md | 3 +++ lib/impure/nre.nim | 2 +- lib/impure/re.nim | 2 +- lib/js/jsre.nim | 43 +++++++++++++++++++++++++++++++++++++++++++ tools/kochdocs.nim | 7 +++++-- 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 lib/js/jsre.nim diff --git a/changelog.md b/changelog.md index 030644951..8446f9467 100644 --- a/changelog.md +++ b/changelog.md @@ -122,6 +122,9 @@ - `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. +- Add `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) + + ## Language changes - In the newruntime it is now allowed to assign to the discriminator field without restrictions as long as case object doesn't have custom destructor. diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index fe71f89fe..653d4d1c5 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -7,7 +7,7 @@ # when defined(js): - {.error: "This library needs to be compiled with a c-like backend, and depends on PCRE.".} + {.error: "This library needs to be compiled with a c-like backend, and depends on PCRE; See jsre for JS backend.".} ## What is NRE? ## ============ diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 1a6622677..fe3ea96ff 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -8,7 +8,7 @@ # when defined(js): - {.error: "This library needs to be compiled with a c-like backend, and depends on PCRE.".} + {.error: "This library needs to be compiled with a c-like backend, and depends on PCRE; See jsre for JS backend.".} ## Regular expression support for Nim. ## diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim new file mode 100644 index 000000000..31cfa3d0b --- /dev/null +++ b/lib/js/jsre.nim @@ -0,0 +1,43 @@ +## Regular Expressions for the JavaScript target. +## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + +type RegExp* {.importjs.} = object ## Regular Expressions for JavaScript target. + flags* {.importjs.}: cstring ## cstring that contains the flags of the RegExp object. + dotAll* {.importjs.}: bool ## Whether `.` matches newlines or not. + global* {.importjs.}: bool ## Whether to test against all possible matches in a string, or only against the first. + ignoreCase* {.importjs.}: bool ## Whether to ignore case while attempting a match in a string. + multiline* {.importjs.}: bool ## Whether to search in strings across multiple lines. + source* {.importjs.}: cstring ## The text of the pattern. + sticky* {.importjs.}: bool ## Whether the search is sticky. + unicode* {.importjs.}: bool ## Whether Unicode features are enabled. + lastIndex* {.importjs.}: cint ## Index at which to start the next match (read/write property). + input* {.importjs.}: cstring ## Read-only and modified on successful match. + lastMatch* {.importjs.}: cstring ## Ditto. + lastParen* {.importjs.}: cstring ## Ditto. + leftContext* {.importjs.}: cstring ## Ditto. + rightContext* {.importjs.}: cstring ## Ditto. + +func newRegExp*(pattern: cstring; flags: cstring): RegExp {.importjs: "new RegExp(@)".} + ## Creates a new RegExp object. + +func compile*(self: RegExp; pattern: cstring; flags: cstring) {.importjs: "#.compile(@)".} + ## Recompiles a regular expression during execution of a script. + +func exec*(self: RegExp; pattern: cstring): seq[cstring] {.importjs: "#.exec(#)".} + ## Executes a search for a match in its string parameter. + +func test*(self: RegExp; pattern: cstring): bool {.importjs: "#.test(#)".} + ## Tests for a match in its string parameter. + +func toString*(self: RegExp): cstring {.importjs: "#.toString()".} + ## Returns a string representing the RegExp object. + + +runnableExamples: + let jsregex: RegExp = newRegExp(r"\s+", r"i") + jsregex.compile(r"\w+", r"i") + doAssert jsregex.test(r"nim javascript") + doAssert jsregex.exec(r"nim javascript") == @["nim".cstring] + doAssert jsregex.toString() == r"/\w+/i" + jsregex.compile(r"[0-9]", r"i") + doAssert jsregex.test(r"0123456789abcd") diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 12d3c31a3..43b802ee2 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -15,6 +15,8 @@ const var nimExe*: string +template isJsOnly(file: string): bool = file.isRelativeTo("lib/js") + proc exe*(f: string): string = result = addFileExt(f, ExeExt) when defined(windows): @@ -256,10 +258,11 @@ proc buildDoc(nimArgs, destPath: string) = destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(doc): + let extra = if isJsOnly(d): " --backend:js " else: "" var nimArgs2 = nimArgs if d.isRelativeTo("compiler"): doAssert false - commands[i] = nim & " doc $# --git.url:$# --outdir:$# --index:on $#" % - [nimArgs2, gitUrl, destPath, d] + commands[i] = nim & " doc $# $# --git.url:$# --outdir:$# --index:on $#" % + [extra, nimArgs2, gitUrl, destPath, d] i.inc for d in items(withoutIndex): commands[i] = nim & " doc2 $# --git.url:$# -o:$# $#" % From 695154970d839add2fbbe9754e9e638511120729 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 3 Jul 2020 14:04:23 -0700 Subject: [PATCH 0825/4254] deprecate existsDir; use dirExists instead (#14884) --- changelog.md | 1 + compiler/docgen.nim | 2 +- lib/pure/os.nim | 28 ++++++++----------- lib/pure/ssl_certs.nim | 2 +- lib/system/nimscript.nim | 13 ++++----- testament/categories.nim | 2 +- tests/manyloc/keineschweine/keineschweine.nim | 2 +- .../keineschweine/lib/client_helpers.nim | 2 +- tests/manyloc/nake/nakefile.nim | 2 +- tests/newconfig/tfoo.nims | 2 +- tests/test_nimscript.nims | 1 - tools/nimgrep.nim | 2 +- tools/niminst/niminst.nim | 8 +++--- tools/nimweb.nim | 4 +-- 14 files changed, 32 insertions(+), 39 deletions(-) diff --git a/changelog.md b/changelog.md index 8446f9467..abe69a086 100644 --- a/changelog.md +++ b/changelog.md @@ -121,6 +121,7 @@ - add `macros.extractDocCommentsAndRunnables` helper - `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. +- deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` - Add `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f501dcc8d..cb8c77e87 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -82,7 +82,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re # we're (currently) requiring `isAbsolute` to avoid confusion when passing # a relative path (would it be relative wrt $PWD or to projectfile) conf.globalAssert conf.docRoot.isAbsolute, arg=conf.docRoot - conf.globalAssert conf.docRoot.existsDir, arg=conf.docRoot + conf.globalAssert conf.docRoot.dirExists, arg=conf.docRoot # needed because `canonicalizePath` called on `file` result = file.relativeTo conf.docRoot.expandFilename.AbsoluteDir else: diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 5d73544ce..8bbceddeb 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1117,13 +1117,7 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", var res: Stat return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode) -when not defined(nimscript): - when not defined(js): # `noNimJs` doesn't work with templates, this should improve. - template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = - fileExists(args) - # {.deprecated: [existsFile: fileExists].} # pending bug #14819; this would avoid above mentioned issue - -proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], +proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], noNimJs.} = ## Returns true if the directory `dir` exists. If `dir` is a file, false ## is returned. Follows symlinks. @@ -1150,7 +1144,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", ## ## See also: ## * `fileExists proc <#fileExists,string>`_ - ## * `existsDir proc <#existsDir,string>`_ + ## * `dirExists proc <#dirExists,string>`_ when defined(windows): when useWinUnicode: wrapUnary(a, getFileAttributesW, link) @@ -1163,13 +1157,13 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) -proc dirExists*(dir: string): bool {.inline, noNimJs.} = - ## Alias for `existsDir proc <#existsDir,string>`_. - ## - ## See also: - ## * `fileExists proc <#fileExists,string>`_ - ## * `symlinkExists proc <#symlinkExists,string>`_ - existsDir(dir) +when not defined(nimscript): + when not defined(js): # `noNimJs` doesn't work with templates, this should improve. + template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = + fileExists(args) + template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = + dirExists(args) + # {.deprecated: [existsFile: fileExists].} # pending bug #14819; this would avoid above mentioned issue when not defined(windows) and not weirdTarget: proc checkSymlink(path: string): bool = @@ -2026,7 +2020,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", # way of retrieving the true filename for x in walkFiles(result): result = x - if not fileExists(result) and not existsDir(result): + if not fileExists(result) and not dirExists(result): # consider using: `raiseOSError(osLastError(), result)` raise newException(OSError, "file '" & result & "' does not exist") else: @@ -2323,7 +2317,7 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", result = not rawCreateDir(dir) if result: # path already exists - need to check that it is indeed a directory - if not existsDir(dir): + if not dirExists(dir): raise newException(IOError, "Failed to create '" & dir & "'") proc createDir*(dir: string) {.rtl, extern: "nos$1", diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index df845decc..d04244307 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -81,7 +81,7 @@ iterator scanSSLCertificates*(useEnvVars = false): string = if p.endsWith(".pem") or p.endsWith(".crt"): if fileExists(p): yield p - elif existsDir(p): + elif dirExists(p): for fn in joinPath(p, "*").walkFiles(): yield fn else: diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 75a4b7a6e..bf298e0d4 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -131,18 +131,17 @@ proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} = ## Checks if the file exists. builtin -template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = - # xxx: warning won't be shown for nimsscript because of current logic handling - # `foreignPackageNotes` - fileExists(args) - proc dirExists*(dir: string): bool {. tags: [ReadIOEffect].} = ## Checks if the directory `dir` exists. builtin -proc existsDir*(dir: string): bool = - ## An alias for ``dirExists``. +template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = + # xxx: warning won't be shown for nimsscript because of current logic handling + # `foreignPackageNotes` + fileExists(args) + +template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = dirExists(dir) proc selfExe*(): string = diff --git a/testament/categories.nim b/testament/categories.nim index 6abb3faa9..760c3c5be 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -507,7 +507,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string, p inc r.total var test = makeSupTest(url, "", cat) let buildPath = packagesDir / name - if not existsDir(buildPath): + if not dirExists(buildPath): if useHead: let (installCmdLine, installOutput, installStatus) = execCmdEx2("git", ["clone", url, buildPath]) if installStatus != QuitSuccess: diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index 6d8e48f24..cde31bd18 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -446,7 +446,7 @@ ingameClient.registerHandler(KeyF12, down, proc() = toggleSpec()) ingameClient.registerHandler(KeyF11, down, toggleShipSelect) ingameClient.registerHandler(MouseLeft, down, handleLClick) when defined(recordMode): - if not existsDir("data/snapshots"): + if not dirExists("data/snapshots"): createDir("data/snapshots") ingameClient.registerHandler(keynum9, down, proc() = if not isRecording: startRecording() diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim index 8c45feb62..b535225dc 100644 --- a/tests/manyloc/keineschweine/lib/client_helpers.nim +++ b/tests/manyloc/keineschweine/lib/client_helpers.nim @@ -103,7 +103,7 @@ proc saveCurrentFile() = let path = expandPath(currentFileTransfer.assetType, currentFileTransfer.fileName) parent = parentDir(path) - if not existsDir(parent): + if not dirExists(parent): createDir(parent) echo("Created dir") writeFile path, currentFIleTransfer.data diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 1da92b76b..95058c277 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -77,7 +77,7 @@ task "testskel", "create skeleton test dir for testing": task "clean", "cleanup generated files": var dirs = @["nimcache", "server"/"nimcache"] dirs.apply(proc(x: var string) = - if existsDir(x): removeDir(x)) + if dirExists(x): removeDir(x)) task "download", "download game assets": var diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index fbff38f01..a53e777d4 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -73,7 +73,7 @@ assert fileExists("tests/newconfig/tfoo.nims") == true assert dirExists("tests") == true assert fileExists("tests/newconfig/tfoo.nims") == true -assert existsDir("tests") == true +assert dirExists("tests") == true discard selfExe() diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 1a6f26137..d9f477366 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -75,7 +75,6 @@ block: doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath block: # #14142 - discard existsDir("/usr") discard dirExists("/usr") discard fileExists("/usr/foo") discard findExe("nim") diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index e4f0e91aa..138f1680c 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -495,7 +495,7 @@ proc styleInsensitive(s: string): string = else: addx() proc walker(pattern; dir: string; counter: var int, errors: var int) = - if existsDir(dir): + if dirExists(dir): for kind, path in walkDir(dir): case kind of pcFile: diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 88d16f48a..a5fc388cd 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -251,12 +251,12 @@ proc walkDirRecursively(s: var seq[string], root, explicit: string, proc addFiles(s: var seq[string], patterns: seq[string]) = for p in items(patterns): - if existsDir(p): + if dirExists(p): walkDirRecursively(s, p, p, false) else: var i = 0 for f in walkPattern(p): - if existsDir(f): + if dirExists(f): walkDirRecursively(s, f, p, false) elif not ignoreFile(f, p, false): add(s, unixToNativePath(f)) @@ -518,7 +518,7 @@ template gatherFiles(fun, libpath, outDir) = proc srcdist(c: var ConfigData) = let cCodeDir = getOutputDir(c) / "c_code" - if not existsDir(cCodeDir): createDir(cCodeDir) + if not dirExists(cCodeDir): createDir(cCodeDir) gatherFiles(copyFile, c.libpath, cCodeDir) var winIndex = -1 var intel32Index = -1 @@ -532,7 +532,7 @@ proc srcdist(c: var ConfigData) = if cpuname.cmpIgnoreStyle("i386") == 0: intel32Index = cpuA elif cpuname.cmpIgnoreStyle("amd64") == 0: intel64Index = cpuA var dir = getOutputDir(c) / buildDir(osA, cpuA) - if existsDir(dir): removeDir(dir) + if dirExists(dir): removeDir(dir) createDir(dir) var cmd = ("nim compile -f --symbolfiles:off --compileonly " & "--gen_mapping --cc:gcc --skipUserCfg" & diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 0a853a54d..10319be87 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -201,7 +201,7 @@ proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) = for p in items(patterns): if fileExists(dir / addFileExt(p, ext)): s.add(dir / addFileExt(p, ext)) - if existsDir(dir / p): + if dirExists(dir / p): walkDirRecursively(s, dir / p, ext) proc parseIniFile(c: var TConfigData) = @@ -483,7 +483,7 @@ proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") = quit("[Error] cannot open: " & temp) var f: File var outfile = c.webUploadOutput / "$#.html" % file - if not existsDir(outfile.splitFile.dir): + if not dirExists(outfile.splitFile.dir): createDir(outfile.splitFile.dir) if open(f, outfile, fmWrite): writeLine(f, generateHTMLPage(c, file, title, content, rss, assetDir)) From 1854d29781aff913ca6892cbf73df91b0399397e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Jul 2020 07:37:24 +0200 Subject: [PATCH 0826/4254] scoped memory management (#14790) * fixes the regressions * closes #13936 * scope based memory management implemented * enabled tcontrolflow.nim test case * final cleanups --- compiler/ccgcalls.nim | 26 + compiler/ccgexprs.nim | 22 +- compiler/ccgstmts.nim | 24 +- compiler/cgen.nim | 6 +- compiler/cgendata.nim | 1 + compiler/injectdestructors.nim | 721 ++++++++++++---------------- compiler/semstmts.nim | 4 +- compiler/spawn.nim | 4 +- doc/destructors.rst | 4 +- tests/arc/tarcmisc.nim | 36 ++ tests/arc/tcontrolflow.nim | 21 +- tests/arc/tmovebug.nim | 6 +- tests/arc/tthread.nim | 10 +- tests/arc/tweave.nim | 154 ++++++ tests/async/testmanyasyncevents.nim | 3 +- tests/casestmt/t12785.nim | 8 +- tests/destructor/tdestructor.nim | 38 +- 17 files changed, 611 insertions(+), 477 deletions(-) create mode 100644 tests/arc/tweave.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 80f02b6c3..2c5d306a3 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -644,7 +644,33 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add(~"];$n") line(p, cpsStmts, pl) +proc notYetAlive(n: PNode): bool {.inline.} = + let r = getRoot(n) + result = r != nil and r.loc.lode == nil + +proc isInactiveDestructorCall(p: BProc, e: PNode): bool = + #[ Consider this example. + + var :tmpD_3281815 + try: + if true: + return + let args_3280013 = + wasMoved_3281816(:tmpD_3281815) + `=_3280036`(:tmpD_3281815, [1]) + :tmpD_3281815 + finally: + `=destroy_3280027`(args_3280013) + + We want to return early but the 'finally' section is traversed before + the 'let args = ...' statement. We exploit this to generate better + code for 'return'. ]# + result = e.len == 2 and e[0].kind == nkSym and + e[0].sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr) + proc genCall(p: BProc, e: PNode, d: var TLoc) = + if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, e): + return if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: genClosureCall(p, nil, e, d) elif e[0].kind == nkSym and sfInfixCall in e[0].sym.flags: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 08b9e1ff6..c194ce326 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2066,10 +2066,14 @@ proc skipAddr(n: PNode): PNode = proc genWasMoved(p: BProc; n: PNode) = var a: TLoc - initLocExpr(p, n[1].skipAddr, a) - resetLoc(p, a) - #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", - # [addrLoc(p.config, a), getTypeDesc(p.module, a.t)]) + let n1 = n[1].skipAddr + if p.withinBlockLeaveActions > 0 and notYetAlive(n1): + discard + else: + initLocExpr(p, n1, a) + resetLoc(p, a) + #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", + # [addrLoc(p.config, a), getTypeDesc(p.module, a.t)]) proc genMove(p: BProc; n: PNode; d: var TLoc) = var a: TLoc @@ -2593,10 +2597,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: putLocIntoDest(p, d, sym.loc) of skTemp: - if sym.loc.r == nil: - # we now support undeclared 'skTemp' variables for easier - # transformations in other parts of the compiler: - assignLocalVar(p, n) + when false: + # this is more harmful than helpful. + if sym.loc.r == nil: + # we now support undeclared 'skTemp' variables for easier + # transformations in other parts of the compiler: + assignLocalVar(p, n) if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 82f1caadc..532272374 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -200,6 +200,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = var stack = newSeq[tuple[fin: PNode, inExcept: bool, label: Natural]](0) + inc p.withinBlockLeaveActions for i in 1..howManyTrys: let tryStmt = p.nestedTryStmts.pop if p.config.exc == excSetjmp: @@ -217,6 +218,8 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = if finallyStmt != nil: genStmts(p, finallyStmt[0]) + dec p.withinBlockLeaveActions + # push old elements again: for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) @@ -861,10 +864,10 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) = genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n") proc branchHasTooBigRange(b: PNode): bool = - for i in 0.. RangeExpandLimit: + if (it.kind == nkRange) and + it[1].intVal - it[0].intVal > RangeExpandLimit: return true proc ifSwitchSplitPoint(p: BProc, n: PNode): int = @@ -988,9 +991,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) - startBlock(p, "try {$n") - expr(p, t[0], d) - endBlock(p) + if t.kind == nkHiddenTryStmt: + lineCg(p, cpsStmts, "try {$n", []) + expr(p, t[0], d) + lineCg(p, cpsStmts, "}$n", []) + else: + startBlock(p, "try {$n") + expr(p, t[0], d) + endBlock(p) # First pass: handle Nim based exceptions: lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) @@ -1335,13 +1343,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) else: linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - startBlock(p, "if ($1.status == 0) {$n", [safePoint]) + lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint]) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, quirkyExceptions, 0.Natural)) expr(p, t[0], d) if not quirkyExceptions: linefmt(p, cpsStmts, "#popSafePoint();$n", []) - endBlock(p) + lineCg(p, cpsStmts, "}$n", []) startBlock(p, "else {$n") linefmt(p, cpsStmts, "#popSafePoint();$n", []) genRestoreFrameAfterException(p) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 99bfe9119..86860fbf4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1561,7 +1561,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = if sfSystemModule in m.module.flags: if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", [])) - if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone: + if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])) if m.s[cfsInitProc].len > 0: @@ -1666,6 +1666,10 @@ proc genInitCode(m: BModule) = writeSection(preInitProc, cpsInit, m.hcrOn) writeSection(preInitProc, cpsStmts) prc.addf("}$N", []) + when false: + m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals) + m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit) + m.initProc.blocks[0].sections[cpsStmts].prepend m.preInitProc.s(cpsStmts) # add new scope for following code, because old vcc compiler need variable # be defined at the top of the block diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index a20931be4..3384558f8 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -97,6 +97,7 @@ type # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) withinTryWithExcept*: int # required for goto based exception handling + withinBlockLeaveActions*: int # complex to explain sigConflicts*: CountTable[string] TTypeSeq* = seq[PType] diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index a2669be99..e10686917 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -27,10 +27,101 @@ import lineinfos, parampatterns, sighashes, liftdestructors from trees import exprStructuralEquivalent, getRoot -from algorithm import reverse -const - scopeBasedDestruction = false +type + Scope = object # well we do scope-based memory management. \ + # a scope is comparable to an nkStmtListExpr like + # (try: statements; dest = y(); finally: destructors(); dest) + vars: seq[PSym] + wasMoved: seq[PNode] + final: seq[PNode] # finally section + needsTry: bool + parent: ptr Scope + +proc nestedScope(parent: var Scope): Scope = + Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) + +proc rememberParent(parent: var Scope; inner: Scope) {.inline.} = + parent.needsTry = parent.needsTry or inner.needsTry + +proc optimize(s: var Scope) = + # optimize away simple 'wasMoved(x); destroy(x)' pairs. + #[ Unfortunately this optimization is only really safe when no exceptions + are possible, see for example: + + proc main(inp: string; cond: bool) = + if cond: + try: + var s = ["hi", inp & "more"] + for i in 0..4: + echo s + consume(s) + wasMoved(s) + finally: + destroy(x) + + Now assume 'echo' raises, then we shouldn't do the 'wasMoved(s)' + ]# + # XXX: Investigate how to really insert 'wasMoved()' calls! + proc findCorrespondingDestroy(final: seq[PNode]; moved: PNode): int = + # remember that it's destroy(addr(x)) + for i in 0 ..< final.len: + if final[i] != nil and exprStructuralEquivalent(final[i][1].skipAddr, moved, strictSymEquality = true): + return i + return -1 + + var removed = 0 + for i in 0 ..< s.wasMoved.len: + let j = findCorrespondingDestroy(s.final, s.wasMoved[i][1]) + if j >= 0: + s.wasMoved[i] = nil + s.final[j] = nil + inc removed + if removed > 0: + template filterNil(field) = + var m = newSeq[PNode](s.field.len - removed) + var mi = 0 + for i in 0 ..< s.field.len: + if s.field[i] != nil: + m[mi] = s.field[i] + inc mi + assert mi == m.len + s.field = m + + filterNil(wasMoved) + filterNil(final) + +proc toTree(s: var Scope; ret: PNode; onlyCareAboutVars = false): PNode = + if not s.needsTry: optimize(s) + assert ret != nil + if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: + # trivial, nothing was done: + result = ret + else: + if isEmptyType(ret.typ): + result = newNodeI(nkStmtList, ret.info) + else: + result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) + + if s.vars.len > 0: + let varSection = newNodeI(nkVarSection, ret.info) + for tmp in s.vars: + varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), + newNodeI(nkEmpty, ret.info)) + result.add varSection + if onlyCareAboutVars: + result.add ret + s.vars.setLen 0 + elif s.needsTry: + var finSection = newNodeI(nkStmtList, ret.info) + for m in s.wasMoved: finSection.add m + for i in countdown(s.final.high, 0): finSection.add s.final[i] + result.add newTryFinally(ret, finSection) + else: + #assert isEmptyType(ret.typ) + result.add ret + for m in s.wasMoved: result.add m + for i in countdown(s.final.high, 0): result.add s.final[i] type Con = object @@ -38,14 +129,10 @@ type g: ControlFlowGraph jumpTargets: IntSet destroys, topLevelVars: PNode - scopeDestroys: seq[PNode] # used as a stack that pop from - # at strategic places which try to - # mimic the natural scope. graph: ModuleGraph emptyNode: PNode otherRead: PNode - inLoop, inSpawn, hasUnstructuredCf, inDangerousBranch: int - declaredVars: IntSet # variables we already moved to the top level + inLoop, inSpawn: int uninit: IntSet # set of uninit'ed vars uninitComputed: bool @@ -62,8 +149,8 @@ template dbg(body) = if c.owner.name.s == toDebug or toDebug == "always": body -proc p(n: PNode; c: var Con; mode: ProcessMode): PNode -proc moveOrCopy(dest, ri: PNode; c: var Con, isDecl = false): PNode +proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode +proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode proc isLastRead(location: PNode; cfg: ControlFlowGraph; otherRead: var PNode; pc, until: int): int = var pc = pc @@ -265,15 +352,6 @@ proc genDestroy(c: Con; dest: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) result = genOp(c, t, attachedDestructor, dest, nil) -when false: - proc preventMoveRef(dest, ri: PNode): bool = - let lhs = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - var ri = ri - if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mUnown: - ri = ri[1] - let rhs = ri.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = lhs.kind == tyRef and rhs.kind == tyOwned - proc canBeMoved(c: Con; t: PType): bool {.inline.} = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) if optOwnedRefs in c.graph.config.globalOptions: @@ -284,8 +362,10 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} = proc isNoInit(dest: PNode): bool {.inline.} = result = dest.kind == nkSym and sfNoInit in dest.sym.flags -proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = - if isUnpackedTuple(dest) or (isDecl and c.inLoop <= 0) or (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)) or isNoInit(dest): +proc genSink(c: var Con; s: var Scope; dest, ri: PNode, isDecl = false): PNode = + if isUnpackedTuple(dest) or (isDecl and c.inLoop <= 0) or + (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)) or + isNoInit(dest): # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) else: @@ -311,34 +391,34 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode = checkForErrorPragma(c, t, ri, "=") result = genCopyNoCheck(c, dest, ri) -proc addTopVar(c: var Con; v: PNode) = - c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode) +proc addTopVar(c: var Con; s: var Scope; v: PNode) = + s.vars.add v.sym -proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = +proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) sym.typ = typ + s.vars.add(sym) result = newSymNode(sym) -proc genDiscriminantAsgn(c: var Con; n: PNode): PNode = +proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = # discriminator is ordinal value that doesn't need sink destroy # but fields within active case branch might need destruction # tmp to support self assignments - let tmp = getTemp(c, n[1].typ, n.info) - c.addTopVar(tmp) + let tmp = getTemp(c, s, n[1].typ, n.info) result = newTree(nkStmtList) - result.add newTree(nkFastAsgn, tmp, p(n[1], c, consumed)) - result.add p(n[0], c, normal) + result.add newTree(nkFastAsgn, tmp, p(n[1], c, s, consumed)) + result.add p(n[0], c, s, normal) - let le = p(n[0], c, normal) + let le = p(n[0], c, s, normal) let leDotExpr = if le.kind == nkCheckedFieldExpr: le[0] else: le let objType = leDotExpr[0].typ if hasDestructor(objType): if objType.attachedOps[attachedDestructor] != nil and sfOverriden in objType.attachedOps[attachedDestructor].flags: - localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for object's with user defined destructor is not supported, object must have default destructor. + localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor. It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""") result.add newTree(nkFastAsgn, le, tmp) return @@ -353,9 +433,7 @@ It is best to factor out piece of object that needs custom destructor into separ notExpr.add newSymNode(createMagic(c.graph, "not", mNot)) notExpr.add cond result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, genOp(c, branchDestructor, le))) - result.add newTree(nkFastAsgn, le, tmp) - else: - result.add newTree(nkFastAsgn, le, tmp) + result.add newTree(nkFastAsgn, le, tmp) proc genWasMoved(n: PNode; c: var Con): PNode = result = newNodeI(nkCall, n.info) @@ -369,7 +447,7 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = result.add(newSymNode(createMagic(c.graph, "default", mDefault))) result.typ = t -proc destructiveMoveVar(n: PNode; c: var Con): PNode = +proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = # generate: (let tmp = v; reset(v); tmp) if not hasDestructor(n.typ): result = copyTree(n) @@ -388,28 +466,21 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = v.add(vpart) result.add v - result.add genWasMoved(skipConv(n), c) + let wasMovedCall = genWasMoved(skipConv(n), c) + result.add wasMovedCall result.add tempAsNode -proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = - assert s.kind == nkSym and s.sym.kind == skParam - if not isLastRead(s, c): - localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & - "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) - proc isCapturedVar(n: PNode): bool = let root = getRoot(n) if root != nil: result = root.name.s[0] == ':' -proc passCopyToSink(n: PNode; c: var Con): PNode = +proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let tmp = getTemp(c, n.typ, n.info) - when not scopeBasedDestruction: - c.addTopVar(tmp) + let tmp = getTemp(c, s, n.typ, n.info) if hasDestructor(n.typ): result.add genWasMoved(tmp, c) var m = genCopy(c, tmp, n) - m.add p(n, c, normal) + m.add p(n, c, s, normal) result.add m if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, @@ -418,7 +489,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = else: if c.graph.config.selectedGC in {gcArc, gcOrc}: assert(not containsGarbageCollectedRef(n.typ)) - result.add newTree(nkAsgn, tmp, p(n, c, normal)) + result.add newTree(nkAsgn, tmp, p(n, c, s, normal)) # Since we know somebody will take over the produced copy, there is # no need to destroy it. result.add tmp @@ -442,161 +513,24 @@ proc containsConstSeq(n: PNode): bool = if containsConstSeq(son): return true else: discard -proc handleTmpDestroys(c: var Con; body: PNode; t: PType; - oldHasUnstructuredCf, oldTmpDestroysLen: int) = - if c.hasUnstructuredCf == oldHasUnstructuredCf: - # no need for a try-finally statement: - if body.kind == nkStmtList: - for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): - body.add c.scopeDestroys[i] - elif isEmptyType(t): - var n = newNodeI(nkStmtList, body.info) - n.add body[^1] - for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): - n.add c.scopeDestroys[i] - body[^1] = n - elif body.kind == nkStmtListExpr and body.len > 0 and body[^1].kind == nkSym: - # special case: Do not translate (x; y; sym) into - # (x; y; tmp = sym; destroy(x); destroy(y); tmp ) - # but into - # (x; y; destroy(x); destroy(y); sym ) - let sym = body[^1] - body[^1] = c.scopeDestroys[^1] - for i in countdown(c.scopeDestroys.high - 1, oldTmpDestroysLen): - body.add c.scopeDestroys[i] - body.add sym - else: - # fun ahead: We have to transform (x; y; E()) into - # (x; y; tmp = E(); destroy(x); destroy(y); tmp ) - let t2 = body[^1].typ - let tmp = getTemp(c, t2, body.info) - when not scopeBasedDestruction: - c.addTopVar(tmp) - # the tmp does not have to be initialized - var n = newNodeIT(nkStmtListExpr, body.info, t2) - n.add newTree(nkFastAsgn, tmp, body[^1]) - for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): - n.add c.scopeDestroys[i] - n.add tmp - body[^1] = n - #c.scopeDestroys.add genDestroy(c, tmp) - else: - # unstructured control flow was used, use a 'try finally' to ensure - # destruction: - if isEmptyType(t): - var n = newNodeI(nkStmtList, body.info) - for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): - n.add c.scopeDestroys[i] - body[^1] = newTryFinally(body[^1], n) - else: - # fun ahead: We have to transform (x; y; E()) into - # ((try: tmp = (x; y; E()); finally: destroy(x); destroy(y)); tmp ) - let t2 = body[^1].typ - let tmp = getTemp(c, t2, body.info) - when not scopeBasedDestruction: - c.addTopVar(tmp) - # the tmp does not have to be initialized - var fin = newNodeI(nkStmtList, body.info) - for i in countdown(c.scopeDestroys.high, oldTmpDestroysLen): - fin.add c.scopeDestroys[i] - var n = newNodeIT(nkStmtListExpr, body.info, t2) - n.add newTryFinally(newTree(nkFastAsgn, tmp, body[^1]), fin) - n.add tmp - body[^1] = n - #c.scopeDestroys.add genDestroy(c, tmp) - - c.scopeDestroys.setLen oldTmpDestroysLen - -proc handleNested(n, dest: PNode; c: var Con; mode: ProcessMode): PNode = - template processCall(node: PNode): PNode = - if node.typ == nil or dest == nil: - p(node, c, mode) - else: - moveOrCopy(dest, node, c) - - proc handleScope(n, dest: PNode; t: PType; - takeOver: Natural; c: var Con; mode: ProcessMode): PNode = - let oldHasUnstructuredCf = c.hasUnstructuredCf - let oldTmpDestroysLen = c.scopeDestroys.len - result = shallowCopy(n) - for i in 0.. oldTmpDestroysLen: - handleTmpDestroys(c, result, t, oldHasUnstructuredCf, oldTmpDestroysLen) - else: - setLen(result.sons, last) - if c.scopeDestroys.len > oldTmpDestroysLen: - handleTmpDestroys(c, result, t, oldHasUnstructuredCf, oldTmpDestroysLen) - if result.kind != nkFinally: - result.add processCall(n[last]) - else: - result = newTree(nkStmtListExpr, result, processCall(n[last])) - result.typ = t - - case n.kind - of nkStmtList, nkStmtListExpr: - if n.len == 0: return n - result = shallowCopy(n) - let last = n.len - 1 - for i in 0.. 0: # unpacked tuple needs reset at every loop iteration res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) elif sfThread notin v.sym.flags: # do not destroy thread vars for now at all for consistency. - if sfGlobal in v.sym.flags: + if sfGlobal in v.sym.flags and s.parent == nil: c.graph.globalDestructors.add genDestroy(c, v) else: - c.destroys.add genDestroy(c, v) + s.final.add genDestroy(c, v) if ri.kind == nkEmpty and c.inLoop > 0: - res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, isDecl = true) + res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: - res.add moveOrCopy(v, ri, c, isDecl = true) - -proc pVarScoped(v: PNode; c: var Con; ri, res: PNode) = - if not containsOrIncl(c.declaredVars, v.sym.id): - c.addTopVar(v) - if isUnpackedTuple(v): - if c.inLoop > 0: - # unpacked tuple needs reset at every loop iteration - res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) - elif {sfGlobal, sfThread} * v.sym.flags == {sfGlobal}: - c.graph.globalDestructors.add genDestroy(c, v) - else: - # We always translate 'var v = f()' into bitcopies. If 'v' is in a loop, - # the destruction at the loop end will free the resources. Other assignments - # will destroy the old value inside 'v'. If we have 'var v' without an initial - # default value we translate it into 'var v = default()'. We translate - # 'var x = someGlobal' into 'var v = default(); `=`(v, someGlobal). The - # lack of copy constructors is really beginning to hurt us. :-( - #if c.inDangerousBranch == 0: v.sym.flags.incl sfNoInit - c.scopeDestroys.add genDestroy(c, v) - if ri.kind == nkEmpty and c.inLoop > 0: - res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, isDecl = true) - elif ri.kind != nkEmpty: - res.add moveOrCopy(v, ri, c, isDecl = true) + res.add moveOrCopy(v, ri, c, s, isDecl = true) template handleNestedTempl(n: untyped, processCall: untyped) = + template maybeVoid(child, s): untyped = + if isEmptyType(child.typ): p(child, c, s, normal) + else: processCall(child, s) + case n.kind of nkStmtList, nkStmtListExpr: + # a statement list does not open a new scope if n.len == 0: return n result = copyNode(n) for i in 0.. 0): - result[i] = p(n[i], c, sinkArg) + result[i] = p(n[i], c, s, sinkArg) else: - result[i] = p(n[i], c, normal) + result[i] = p(n[i], c, s, normal) - if isDangerous: - dec c.inDangerousBranch + when false: + if isDangerous: + dec c.inDangerousBranch if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}: result[0] = copyTree(n[0]) @@ -873,15 +805,14 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = let destroyOld = genDestroy(c, result[1]) result = newTree(nkStmtList, destroyOld, result) else: - result[0] = p(n[0], c, normal) - when scopeBasedDestruction: - if canRaise(n[0]): inc c.hasUnstructuredCf + result[0] = p(n[0], c, s, normal) + if canRaise(n[0]): s.needsTry = true if mode == normal: - result = ensureDestruction(result, c) + result = ensureDestruction(result, c, s) of nkDiscardStmt: # Small optimization result = shallowCopy(n) if n[0].kind != nkEmpty: - result[0] = p(n[0], c, normal) + result[0] = p(n[0], c, s, normal) else: result[0] = copyNode(n[0]) of nkVarSection, nkLetSection: @@ -891,27 +822,24 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode = var ri = it[^1] if it.kind == nkVarTuple and hasDestructor(ri.typ): let x = lowerTupleUnpacking(c.graph, it, c.owner) - result.add p(x, c, consumed) + result.add p(x, c, s, consumed) elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0]): for j in 0.. 0: ri = genDefaultCall(v.typ, c, v.info) if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c, isDecl = true) + result.add moveOrCopy(v, ri, c, s, isDecl = true) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) for j in 0.. 0 and isDangerousSeq(ri.typ): result = genCopy(c, dest, ri) - result.add p(ri, c, consumed) + result.add p(ri, c, s, consumed) else: - result = genSink(c, dest, p(ri, c, consumed), isDecl) + result = genSink(c, s, dest, p(ri, c, s, consumed), isDecl) of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - result = genSink(c, dest, p(ri, c, consumed), isDecl) + result = genSink(c, s, dest, p(ri, c, s, consumed), isDecl) of nkSym: if isSinkParam(ri.sym) and isLastRead(ri, c): # Rule 3: `=sink`(x, z); wasMoved(z) - #sinkParamIsLastReadCheck(c, ri) - let snk = genSink(c, dest, ri, isDecl) + let snk = genSink(c, s, dest, ri, isDecl) result = newTree(nkStmtList, snk, genWasMoved(ri, c)) elif ri.sym.kind != skParam and ri.sym.owner == c.owner and isLastRead(ri, c) and canBeMoved(c, dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = genSink(c, dest, ri, isDecl) + let snk = genSink(c, s, dest, ri, isDecl) result = newTree(nkStmtList, snk, genWasMoved(ri, c)) else: result = genCopy(c, dest, ri) - result.add p(ri, c, consumed) - of nkHiddenSubConv, nkHiddenStdConv, nkConv: - when false: - result = moveOrCopy(dest, ri[1], c, isDecl) - if not sameType(ri.typ, ri[1].typ): - let copyRi = copyTree(ri) - copyRi[1] = result[^1] - result[^1] = copyRi - else: - result = genSink(c, dest, p(ri, c, sinkArg), isDecl) - of nkObjDownConv, nkObjUpConv: - when false: - result = moveOrCopy(dest, ri[0], c, isDecl) - let copyRi = copyTree(ri) - copyRi[0] = result[^1] - result[^1] = copyRi - else: - result = genSink(c, dest, p(ri, c, sinkArg), isDecl) + result.add p(ri, c, s, consumed) + of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: + result = genSink(c, s, dest, p(ri, c, s, sinkArg), isDecl) of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt: - when scopeBasedDestruction: - result = handleNested(ri, dest, c, normal) - else: - handleNestedTempl(ri): moveOrCopy(dest, node, c, isDecl) + template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) + handleNestedTempl(ri, process) + of nkRaiseStmt: + result = pRaiseStmt(ri, c, s) else: if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and canBeMoved(c, dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = genSink(c, dest, ri, isDecl) + let snk = genSink(c, s, dest, ri, isDecl) result = newTree(nkStmtList, snk, genWasMoved(ri, c)) else: result = genCopy(c, dest, ri) - result.add p(ri, c, consumed) + result.add p(ri, c, s, consumed) proc computeUninit(c: var Con) = if not c.uninitComputed: @@ -1102,30 +998,19 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = echo "\n### ", owner.name.s, ":\nCFG:" echoCfg(c.g) echo n + + var scope: Scope + let body = p(n, c, scope, normal) + if owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter}: let params = owner.typ.n for i in 1.. 0: - result.add c.topLevelVars - if c.destroys.len > 0 or c.scopeDestroys.len > 0: - reverse c.destroys.sons - var fin: PNode - if owner.kind == skModule: - fin = newTryFinally(body, extractDestroysForTemporaries(c, c.destroys)) - g.globalDestructors.add c.destroys - else: - fin = newTryFinally(body, c.destroys) - for i in countdown(c.scopeDestroys.high, 0): fin[1][0].add c.scopeDestroys[i] - result.add fin - else: - result.add body + result = toTree(scope, body) dbg: echo ">---------transformed-to--------->" echo renderTree(result, {renderIds}) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a2515357b..c88ff3609 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -229,8 +229,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode = a[0][2] = newSymNode(symbol, a[0][2].info) elif a.len == 1: - # count number of ``except: body`` blocks - inc catchAllExcepts + # count number of ``except: body`` blocks + inc catchAllExcepts else: # support ``except KeyError, ValueError, ... : body`` diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 9d837b993..15bed77b0 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -10,7 +10,7 @@ ## This module implements threadpool's ``spawn``. import ast, types, idents, magicsys, msgs, options, modulegraphs, - lowerings, liftdestructors + lowerings, liftdestructors, renderer from trees import getMagic, getRoot proc callProc(a: PNode): PNode = @@ -321,7 +321,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P result = newNodeI(nkStmtList, n.info) if n.kind notin nkCallKinds: - localError(g.config, n.info, "'spawn' takes a call expression") + localError(g.config, n.info, "'spawn' takes a call expression; got " & $n) return if optThreadAnalysis in g.config.globalOptions: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: diff --git a/doc/destructors.rst b/doc/destructors.rst index b06d78bbe..4285bad8b 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -283,8 +283,8 @@ Rewrite rules around the complete routine body. 2. The produced ``finally`` section is wrapped around the enclosing scope. -The current implementation follows strategy (1). This means that resources are -not destroyed at the scope exit, but at the proc exit. +The current implementation follows strategy (2). This means that resources are +destroyed at the scope exit. :: diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 898efd138..e66d9a75f 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -173,3 +173,39 @@ proc bug14495 = echo o[] bug14495() + +when false: + # bug #14396 + type + Spinny = ref object + t: ref int + text: string + + proc newSpinny*(): Spinny = + Spinny(t: new(int), text: "hello") + + proc spinnyLoop(x: ref int, spinny: sink Spinny) = + echo x[] + + proc start*(spinny: sink Spinny) = + spinnyLoop(spinny.t, spinny) + + var spinner1 = newSpinny() + spinner1.start() + + # bug #14345 + + type + SimpleLoopB = ref object + children: seq[SimpleLoopB] + parent: SimpleLoopB + + proc addChildLoop(self: SimpleLoopB, loop: SimpleLoopB) = + self.children.add loop + + proc setParent(self: SimpleLoopB, parent: SimpleLoopB) = + self.parent = parent + self.parent.addChildLoop(self) + + var l = SimpleLoopB() + l.setParent(l) diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim index efe51cc32..478806567 100644 --- a/tests/arc/tcontrolflow.nim +++ b/tests/arc/tcontrolflow.nim @@ -11,15 +11,13 @@ begin true if end true 7 +##index 2 not in 0 .. 1## ''' cmd: "nim c --gc:arc -d:danger $file" - disabled: "true" """ # we use the -d:danger switch to detect uninitialized stack # slots more reliably (there shouldn't be any, of course). -# XXX Enable once scope based destruction works! - type Foo = object id: int @@ -68,12 +66,25 @@ proc run(data: Control) = evt.control = data if evt.button == 1: discard - else: + else: return - + echo data.x var c = Control(x: 7) run(c) +proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = + var buf = newStringOfCap(200) + add(buf, "##") + add(buf, message) + add(buf, "##") + echo buf + +proc ifexpr(i, a, b: int) {.compilerproc, noinline.} = + sysFatal(IndexDefect, + if b < a: "index out of bounds, the container is empty" + else: "index " & $i & " not in " & $a & " .. " & $b) + +ifexpr(2, 0, 1) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 951979a46..ec0fce9a8 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -247,7 +247,7 @@ iterator combinations[T](s: openarray[T], k: int): seq[T] = break type - UndefEx = object of Exception + UndefEx = object of ValueError proc main2 = var delayedSyms = @[1, 2, 3] @@ -318,10 +318,10 @@ proc `=sink`(dest: var O2, src: O2) = var testSeq: O2 -proc Update(): void = +proc update() = # testSeq.add(0) # uncommenting this line fixes the leak testSeq = O2(s: @[]) testSeq.s.add(0) for i in 1..3: - Update() + update() diff --git a/tests/arc/tthread.nim b/tests/arc/tthread.nim index c653c753f..8a55a666e 100644 --- a/tests/arc/tthread.nim +++ b/tests/arc/tthread.nim @@ -14,7 +14,7 @@ type p: int MyObjRef = ref MyObj -proc `=destroy`(x: var MyObj) = +proc `=destroy`(x: var MyObj) = if x.p != 0: echo "destroyed" @@ -48,16 +48,16 @@ proc thread5(x: sink MyObjRef): MyObjRef = os.sleep(1000) result = x -proc ref_forwarding_test = +proc ref_forwarding_test = var x = new(MyObj) x[].p = 2 var y = spawn thread4(x) - -proc ref_sink_forwarding_test = + +proc ref_sink_forwarding_test = var x = new(MyObj) x[].p = 2 var y = spawn thread5(x) ref_forwarding_test() -ref_sink_forwarding_test() +ref_sink_forwarding_test() sync() diff --git a/tests/arc/tweave.nim b/tests/arc/tweave.nim new file mode 100644 index 000000000..220d65f97 --- /dev/null +++ b/tests/arc/tweave.nim @@ -0,0 +1,154 @@ +discard """ + outputsub: '''Success''' + cmd: '''nim c --gc:arc --threads:on $file''' + disabled: "bsd" +""" + +# bug #13936 + +import std/atomics + +const MemBlockSize = 256 + +type + ChannelSPSCSingle* = object + full{.align: 128.}: Atomic[bool] + itemSize*: uint8 + buffer*{.align: 8.}: UncheckedArray[byte] + +proc `=`( + dest: var ChannelSPSCSingle, + source: ChannelSPSCSingle + ) {.error: "A channel cannot be copied".} + +proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} = + ## If ChannelSPSCSingle is used intrusive another data structure + ## be aware that it should be the last part due to ending by UncheckedArray + ## Also due to 128 bytes padding, it automatically takes half + ## of the default MemBlockSize + assert itemsize.int in 0 .. int high(uint8) + assert itemSize.int + + sizeof(chan.itemsize) + + sizeof(chan.full) < MemBlockSize + + chan.itemSize = uint8 itemsize + chan.full.store(false, moRelaxed) + +func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} = + not chan.full.load(moAcquire) + +func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} = + ## Try receiving the item buffered in the channel + ## Returns true if successful (channel was not empty) + ## + ## ⚠ Use only in the consumer thread that reads from the channel. + assert (sizeof(T) == chan.itemsize.int) or + # Support dummy object + (sizeof(T) == 0 and chan.itemsize == 1) + + let full = chan.full.load(moAcquire) + if not full: + return false + dst = cast[ptr T](chan.buffer.addr)[] + chan.full.store(false, moRelease) + return true + +func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} = + ## Try sending an item into the channel + ## Reurns true if successful (channel was empty) + ## + ## ⚠ Use only in the producer thread that writes from the channel. + assert (sizeof(T) == chan.itemsize.int) or + # Support dummy object + (sizeof(T) == 0 and chan.itemsize == 1) + + let full = chan.full.load(moAcquire) + if full: + return false + cast[ptr T](chan.buffer.addr)[] = src + chan.full.store(true, moRelease) + return true + +# Sanity checks +# ------------------------------------------------------------------------------ +when isMainModule: + + when not compileOption("threads"): + {.error: "This requires --threads:on compilation flag".} + + template sendLoop[T](chan: var ChannelSPSCSingle, + data: sink T, + body: untyped): untyped = + while not chan.trySend(data): + body + + template recvLoop[T](chan: var ChannelSPSCSingle, + data: var T, + body: untyped): untyped = + while not chan.tryRecv(data): + body + + type + ThreadArgs = object + ID: WorkerKind + chan: ptr ChannelSPSCSingle + + WorkerKind = enum + Sender + Receiver + + template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} = + if args.ID == id: + body + + proc thread_func(args: ThreadArgs) = + + # Worker RECEIVER: + # --------- + # <- chan + # <- chan + # <- chan + # + # Worker SENDER: + # --------- + # chan <- 42 + # chan <- 53 + # chan <- 64 + Worker(Receiver): + var val: int + for j in 0 ..< 10: + args.chan[].recvLoop(val): + # Busy loop, in prod we might want to yield the core/thread timeslice + discard + echo " Receiver got: ", val + doAssert val == 42 + j*11 + + Worker(Sender): + doAssert args.chan.full.load(moRelaxed) == false + for j in 0 ..< 10: + let val = 42 + j*11 + args.chan[].sendLoop(val): + # Busy loop, in prod we might want to yield the core/thread timeslice + discard + echo "Sender sent: ", val + + proc main() = + echo "Testing if 2 threads can send data" + echo "-----------------------------------" + var threads: array[2, Thread[ThreadArgs]] + + var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize)) + chan[].initialize(itemSize = sizeof(int)) + + createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan)) + createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan)) + + joinThread(threads[0]) + joinThread(threads[1]) + + freeShared(chan) + + echo "-----------------------------------" + echo "Success" + + main() diff --git a/tests/async/testmanyasyncevents.nim b/tests/async/testmanyasyncevents.nim index 5a103736f..9fdd01b4f 100644 --- a/tests/async/testmanyasyncevents.nim +++ b/tests/async/testmanyasyncevents.nim @@ -1,8 +1,9 @@ discard """ output: ''' hasPendingOperations: false -triggerCount: 100 +triggerCount: 100 ''' +disabled: "windows" """ import asyncDispatch diff --git a/tests/casestmt/t12785.nim b/tests/casestmt/t12785.nim index bf0f30d42..7177fb9c2 100644 --- a/tests/casestmt/t12785.nim +++ b/tests/casestmt/t12785.nim @@ -3,6 +3,8 @@ discard """ output: '''copied copied 2 +destroyed +destroyed copied copied 2 @@ -37,9 +39,9 @@ proc test(a: range[0..1], arg: ObjWithDestructor) = inc iteration case a - of 0: - assert false - of 1: + of 0: + assert false + of 1: echo b if iteration == 2: break diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index 9fd47fe00..e081eb251 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -1,27 +1,27 @@ discard """ - output: '''---- + output: '''----1 myobj constructed myobj destroyed ----- +----2 mygeneric1 constructed mygeneric1 destroyed ----- +----3 mygeneric2 constructed mygeneric2 destroyed myobj destroyed ----- +----4 mygeneric3 constructed mygeneric1 destroyed ----- +----5 mydistinctObj constructed myobj destroyed mygeneric2 destroyed ------------------- ----- ----- -myobj destroyed +------------------8 mygeneric1 destroyed ---- +----6 +myobj destroyed +----7 +---9 myobj destroyed myobj destroyed ''' @@ -114,19 +114,19 @@ proc mydistinctObj = echo "mydistinctObj constructed" -echo "----" +echo "----1" myobj() -echo "----" +echo "----2" mygeneric1() -echo "----" +echo "----3" mygeneric2[int](10) -echo "----" +echo "----4" mygeneric3() -echo "----" +echo "----5" mydistinctObj() proc caseobj = @@ -134,16 +134,16 @@ proc caseobj = var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) block: - echo "----" + echo "----6" var o2 = TCaseObj(kind: B, y: open()) block: - echo "----" + echo "----7" var o3 = TCaseObj(kind: D, innerKind: B, r: "test", p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test")) -echo "------------------" +echo "------------------8" caseobj() proc caseobj_test_sink: TCaseObj = @@ -153,7 +153,7 @@ proc caseobj_test_sink: TCaseObj = result = TCaseObj(kind: B, y: open()) -echo "---" +echo "---9" discard caseobj_test_sink() # issue #14315 From af27e6bdea63bbf66718193ec44bc61e745ded38 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 4 Jul 2020 17:45:07 +0200 Subject: [PATCH 0827/4254] Fix #14396 (#14793) * Correct Left-To-Right evaluation of proc args * Fix CPP backend * Add testcase * closes #14396 * closes #14345 * Improve test and optimize * Improve testcase and optimize literals * Fix bug * Expand testcase and use DFA to optimize * Turn genParams into proc * Turn withTmpIfNeeded into a proc * Cleanup * Fix crash * Better analysis * Cleanup * Trailing newline.. * Fix build * Tiny cleanup Co-authored-by: Andreas Rumpf --- compiler/ccgcalls.nim | 145 ++++++++++++++++++++--------- compiler/closureiters.nim | 2 +- tests/arc/tarcmisc.nim | 52 +++++------ tests/ccgbugs/targ_lefttoright.nim | 70 ++++++++++++++ 4 files changed, 198 insertions(+), 71 deletions(-) create mode 100644 tests/ccgbugs/targ_lefttoright.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2c5d306a3..5f99f357d 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -217,21 +217,30 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) -proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = +proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = + if needsTmp: + var tmp: TLoc + getTemp(p, a.lode.typ, tmp, needsInit=false) + genAssignment(p, tmp, a, {}) + tmp + else: + a + +proc genArgStringToCString(p: BProc, n: PNode, needsTmp: bool): Rope {.inline.} = var a: TLoc initLocExpr(p, n[0], a) - result = ropecg(p.module, "#nimToCStringConv($1)", [a.rdLoc]) + ropecg(p.module, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) -proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = +proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rope = var a: TLoc if n.kind == nkStringToCString: - result = genArgStringToCString(p, n) + result = genArgStringToCString(p, n, needsTmp) elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n[0] result = openArrayLoc(p, param.typ, n) elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): initLocExpr(p, n, a) - result = addrLoc(p.config, a) + result = addrLoc(p.config, withTmpIfNeeded(p, a, needsTmp)) elif p.module.compileToCpp and param.typ.kind in {tyVar} and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n[0], a) @@ -246,26 +255,85 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = result = rdLoc(a) else: initLocExprSingleUse(p, n, a) - result = rdLoc(a) + result = rdLoc(withTmpIfNeeded(p, a, needsTmp)) -proc genArgNoParam(p: BProc, n: PNode): Rope = +proc genArgNoParam(p: BProc, n: PNode, needsTmp = false): Rope = var a: TLoc if n.kind == nkStringToCString: - result = genArgStringToCString(p, n) + result = genArgStringToCString(p, n, needsTmp) else: initLocExprSingleUse(p, n, a) - result = rdLoc(a) + result = rdLoc(withTmpIfNeeded(p, a, needsTmp)) -template genParamLoop(params) {.dirty.} = - if i < typ.len: - assert(typ.n[i].kind == nkSym) - let paramType = typ.n[i] - if not paramType.typ.isCompileTimeOnly: - if params != nil: params.add(~", ") - params.add(genArg(p, ri[i], paramType.sym, ri)) +from dfa import instrTargets, InstrTargetKind + +proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool = + for p in potentialWrites: + if instrTargets(p, n) != None: + return true + +proc skipTrivialIndirections(n: PNode): PNode = + result = n + while true: + case result.kind + of {nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv}: + result = result[0] + of {nkHiddenStdConv, nkHiddenSubConv}: + result = result[1] + else: break + +proc getPotentialWrites(n: PNode, mutate = false): seq[PNode] = + case n.kind: + of nkLiterals, nkIdent: discard + of nkSym: + if mutate: result.add n + of nkAsgn, nkFastAsgn: + result.add getPotentialWrites(n[0], true) + result.add getPotentialWrites(n[1], mutate) + of nkAddr, nkHiddenAddr: + result.add getPotentialWrites(n[0], true) + of nkCallKinds: #TODO: Find out why in f += 1, f is a nkSym and not a nkHiddenAddr + for s in n.sons: + result.add getPotentialWrites(s, true) else: - if params != nil: params.add(~", ") - params.add(genArgNoParam(p, ri[i])) + for s in n.sons: + result.add getPotentialWrites(s, mutate) + +proc getPotentialReads(n: PNode): seq[PNode] = + case n.kind: + of nkLiterals, nkIdent: discard + of nkSym: result.add n + else: + for s in n.sons: + result.add getPotentialReads(s) + +proc genParams(p: BProc, ri: PNode, typ: PType): Rope = + # We must generate temporaries in cases like #14396 + # to keep the strict Left-To-Right evaluation + var needTmp = newSeq[bool](ri.len - 1) + var potentialWrites: seq[PNode] + for i in countdown(ri.len - 1, 1): + if ri[i].skipTrivialIndirections.kind == nkSym: + needTmp[i - 1] = potentialAlias(ri[i], potentialWrites) + else: + for n in getPotentialReads(ri[i]): + if not needTmp[i - 1]: + needTmp[i - 1] = potentialAlias(n, potentialWrites) + potentialWrites.add getPotentialWrites(ri[i]) + if ri[i].kind == nkHiddenAddr: + # Optimization: don't use a temp, if we would only take the adress anyway + needTmp[i - 1] = false + + for i in 1.. 0 and isInactiveDestructorCall(p, e): - return - if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: - genClosureCall(p, nil, e, d) - elif e[0].kind == nkSym and sfInfixCall in e[0].sym.flags: - genInfixCall(p, nil, e, d) - elif e[0].kind == nkSym and sfNamedParamCall in e[0].sym.flags: - genNamedParamCall(p, e, d) - else: - genPrefixCall(p, nil, e, d) - postStmtActions(p) - proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = + if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri): + return if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: genClosureCall(p, le, ri, d) elif ri[0].kind == nkSym and sfInfixCall in ri[0].sym.flags: @@ -691,3 +746,5 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = else: genPrefixCall(p, le, ri, d) postStmtActions(p) + +proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 675f1ae41..2248f956e 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -129,7 +129,7 @@ # break :stateLoop import - ast, astalgo, msgs, idents, + ast, msgs, idents, renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos type diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index e66d9a75f..b6d9d781d 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -15,6 +15,7 @@ destroyed: false (x: "8") (x: "9") (x: "10") +0 closed destroying variable ''' @@ -174,38 +175,37 @@ proc bug14495 = bug14495() -when false: - # bug #14396 - type - Spinny = ref object - t: ref int - text: string +# bug #14396 +type + Spinny = ref object + t: ref int + text: string - proc newSpinny*(): Spinny = - Spinny(t: new(int), text: "hello") +proc newSpinny*(): Spinny = + Spinny(t: new(int), text: "hello") - proc spinnyLoop(x: ref int, spinny: sink Spinny) = - echo x[] +proc spinnyLoop(x: ref int, spinny: sink Spinny) = + echo x[] - proc start*(spinny: sink Spinny) = - spinnyLoop(spinny.t, spinny) +proc start*(spinny: sink Spinny) = + spinnyLoop(spinny.t, spinny) - var spinner1 = newSpinny() - spinner1.start() +var spinner1 = newSpinny() +spinner1.start() - # bug #14345 +# bug #14345 - type - SimpleLoopB = ref object - children: seq[SimpleLoopB] - parent: SimpleLoopB +type + SimpleLoopB = ref object + children: seq[SimpleLoopB] + parent: SimpleLoopB - proc addChildLoop(self: SimpleLoopB, loop: SimpleLoopB) = - self.children.add loop +proc addChildLoop(self: SimpleLoopB, loop: SimpleLoopB) = + self.children.add loop - proc setParent(self: SimpleLoopB, parent: SimpleLoopB) = - self.parent = parent - self.parent.addChildLoop(self) +proc setParent(self: SimpleLoopB, parent: SimpleLoopB) = + self.parent = parent + self.parent.addChildLoop(self) - var l = SimpleLoopB() - l.setParent(l) +var l = SimpleLoopB() +l.setParent(l) diff --git a/tests/ccgbugs/targ_lefttoright.nim b/tests/ccgbugs/targ_lefttoright.nim new file mode 100644 index 000000000..b107b2327 --- /dev/null +++ b/tests/ccgbugs/targ_lefttoright.nim @@ -0,0 +1,70 @@ +discard """ + nimout: '''1,2 +2,3 +2,2 +1,2 +1,2 +2,2 +1,2 +''' + output: '''1,2 +2,3 +1,2 +2,2 +1,2 +1,2 +2,2 +1,2 +''' +""" + +template test = + proc say(a, b: int) = + echo a,",",b + + var a = 1 + say a, (a += 1; a) #1,2 + + var b = 1 + say (b += 1; b), (b += 1; b) #2,3 + + type C = object {.byRef.} + i: int + + proc say(a, b: C) = + echo a.i,",",b.i + + proc `+=`(x: var C, y: C) = x.i += y.i + + var c = C(i: 1) + when nimvm: #XXX: This would output 2,2 in the VM, which is wrong + discard + else: + say c, (c += C(i: 1); c) #1,2 + + proc sayVar(a: var int, b: int) = + echo a,",",b + + var d = 1 + sayVar d, (d += 1; d) #2,2 + + var e = 1 + say (addr e)[], (e += 1; e) #1,2 + + var f = 1 + say f, if false: f + else: f += 1; f #1,2 + + var g = 1 + say g + 1, if false: g + else: g += 1; g #2,2 + + proc `+=+`(x: var int, y: int): int = (inc(x, y); x) + + var h = 1 + say h, h +=+ 1 # 1,2 + +test + +static: + test From 21b3ca636fa7eee53911ab134afe2805fd0bf47e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 6 Jul 2020 05:00:25 -0300 Subject: [PATCH 0828/4254] Fix logging tiny bug (#14910) * Fix logging tiny bug * Update changelog.md Co-authored-by: Danil Yarantsev * Update changelog.md Co-authored-by: Danil Yarantsev * Update changelog.md Co-authored-by: Danil Yarantsev * https://github.com/nim-lang/Nim/pull/14910#discussion_r450012032 Co-authored-by: Danil Yarantsev --- changelog.md | 4 ++++ lib/pure/logging.nim | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index abe69a086..efad01515 100644 --- a/changelog.md +++ b/changelog.md @@ -124,6 +124,10 @@ - deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` - Add `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, + because negative values will result in a new file being created for each logged line which doesn't make sense. +- Changed `log` in `logging` to use proper log level on JavaScript target, + eg. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. ## Language changes diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 2637fdf9d..2e79cd3ca 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -364,7 +364,12 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = let ln = substituteLog(logger.fmtStr, level, args) when defined(js): let cln: cstring = ln - {.emit: "console.log(`cln`);".} + case level + of lvlDebug: {.emit: "console.debug(`cln`);".} + of lvlInfo: {.emit: "console.info(`cln`);".} + of lvlWarn: {.emit: "console.warn(`cln`);".} + of lvlError: {.emit: "console.error(`cln`);".} + else: {.emit: "console.log(`cln`);".} else: try: var handle = stdout @@ -504,7 +509,6 @@ when not defined(js): # ------ proc countLogLines(logger: RollingFileLogger): int = - result = 0 let fp = open(logger.baseName, fmRead) for line in fp.lines(): result.inc() @@ -531,7 +535,7 @@ when not defined(js): mode: FileMode = fmReadWrite, levelThreshold = lvlAll, fmtStr = defaultFmtStr, - maxLines = 1000, + maxLines: Positive = 1000, bufSize: int = -1): RollingFileLogger = ## Creates a new `RollingFileLogger<#RollingFileLogger>`_. ## From 842efab8ae867f001d5043a773ee96a7087c2334 Mon Sep 17 00:00:00 2001 From: Dean Eigenmann <7621705+decanus@users.noreply.github.com> Date: Mon, 6 Jul 2020 10:23:42 +0200 Subject: [PATCH 0829/4254] Update btrees.nim (#14916) --- compiler/btrees.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/btrees.nim b/compiler/btrees.nim index 65edc54f3..18854d474 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -79,6 +79,9 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] = var j = 0 if not h.isInternal: while j < h.entries: + if eq(key, h.keys[j]): + h.vals[j] = val + return if less(key, h.keys[j]): break inc j for i in countdown(h.entries, j+1): From ebaf603c84a569b8de447fdb66bb05124d3a0772 Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 6 Jul 2020 10:55:51 +0200 Subject: [PATCH 0830/4254] revert 0944b0f4 --- lib/impure/re.nim | 2 +- lib/pure/asyncnet.nim | 16 +++--- lib/pure/base64.nim | 2 +- lib/pure/httpclient.nim | 6 +-- lib/pure/net.nim | 110 +++++++++++++++++++-------------------- testament/backend.nim | 4 +- testament/categories.nim | 6 +-- testament/htmlgen.nim | 2 +- testament/testament.nim | 14 ++--- tools/nimfind.nim | 8 +-- 10 files changed, 85 insertions(+), 85 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index fe3ea96ff..24841b40e 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -122,7 +122,7 @@ proc bufSubstr(b: cstring, sPos, ePos: int): string {.inline.} = ## Don't assume cstring is '\0' terminated let sz = ePos - sPos result = newString(sz+1) - copyMem(addr(result[0]), unsafeAddr(b[sPos]), sz) + copyMem(addr(result[0]), unsafeaddr(b[sPos]), sz) result.setLen(sz) proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 410310e29..0bdbeb29b 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -202,7 +202,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint, when defineSsl: proc getSslError(handle: SslPtr, err: cint): cint = assert err < 0 - var ret = SSL_get_error(handle, err.cint) + var ret = SSLGetError(handle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") @@ -224,9 +224,9 @@ when defineSsl: let read = bioRead(socket.bioOut, addr data[0], len) assert read != 0 if read < 0: - raiseSSLError() + raiseSslError() data.setLen(read) - await socket.fd.AsyncFD.send(data, flags) + await socket.fd.AsyncFd.send(data, flags) proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag], sslError: cint): owned(Future[bool]) {.async.} = @@ -727,7 +727,7 @@ proc close*(socket: AsyncSocket) = if res == 0: discard elif res != 1: - raiseSSLError() + raiseSslError() socket.closed = true # TODO: Add extra debugging checks for this. when defineSsl: @@ -739,12 +739,12 @@ when defineSsl: ## prone to security vulnerabilities. socket.isSsl = true socket.sslContext = ctx - socket.sslHandle = SSL_new(socket.sslContext.context) + socket.sslHandle = SSLNew(socket.sslContext.context) if socket.sslHandle == nil: - raiseSSLError() + raiseSslError() - socket.bioIn = bioNew(bioSMem()) - socket.bioOut = bioNew(bioSMem()) + socket.bioIn = bioNew(bio_s_mem()) + socket.bioOut = bioNew(bio_s_mem()) sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut) proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket, diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 9495c4d56..c140b9714 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -229,7 +229,7 @@ proc decode*(s: string): string = return (size * 3 div 4) + 6 template inputChar(x: untyped) = - let x = int decodeTable[ord(s[inputIndex])] + let x = int decode_table[ord(s[inputIndex])] inc inputIndex if x == invalidChar: raise newException(ValueError, diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 92e4cd2d6..e8936f87b 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -313,10 +313,10 @@ proc fileError(msg: string) = raise e when not defined(ssl): - type SslContext = ref object -var defaultSslContext {.threadvar.}: SslContext + type SSLContext = ref object +var defaultSslContext {.threadvar.}: SSLContext -proc getDefaultSSL(): SslContext = +proc getDefaultSSL(): SSLContext = result = defaultSslContext when defined(ssl): if result == nil: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 7aeffbc35..d18f18c92 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -128,8 +128,8 @@ type bufLen: int # current length of buffer when defineSsl: isSsl: bool - sslHandle: SslPtr - sslContext: SslContext + sslHandle: SSLPtr + sslContext: SSLContext sslNoHandshake: bool # True if needs handshake. sslHasPeekChar: bool sslPeekChar: char @@ -469,15 +469,15 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, when defineSsl: CRYPTO_malloc_init() doAssert SslLibraryInit() == 1 - SSL_load_error_strings() - ERR_load_BIO_strings() + SslLoadErrorStrings() + ErrLoadBioStrings() OpenSSL_add_all_algorithms() proc raiseSSLError*(s = "") = ## Raises a new SSL error. if s != "": - raise newException(SslError, s) - let err = ERR_peek_last_error() + raise newException(SSLError, s) + let err = ErrPeekLastError() if err == 0: raise newException(SslError, "No error reported.") var errStr = $ERR_error_string(err, nil) @@ -487,10 +487,10 @@ when defineSsl: "necessary protocols. OpenSSL error is: " & errStr else: discard - raise newException(SslError, errStr) + raise newException(SSLError, errStr) - proc getExtraData*(ctx: SslContext, index: int): RootRef = - ## Retrieves arbitrary data stored inside SslContext. + proc getExtraData*(ctx: SSLContext, index: int): RootRef = + ## Retrieves arbitrary data stored inside SSLContext. if index notin ctx.referencedData: raise newException(IndexDefect, "No data with that index.") let res = ctx.context.SSL_CTX_get_ex_data(index.cint) @@ -498,8 +498,8 @@ when defineSsl: raiseSSLError() return cast[RootRef](res) - proc setExtraData*(ctx: SslContext, index: int, data: RootRef) = - ## Stores arbitrary data inside SslContext. The unique `index` + proc setExtraData*(ctx: SSLContext, index: int, data: RootRef) = + ## Stores arbitrary data inside SSLContext. The unique `index` ## should be retrieved using getSslContextExtraDataIndex. if index in ctx.referencedData: GC_unref(getExtraData(ctx, index)) @@ -520,7 +520,7 @@ when defineSsl: raise newException(system.IOError, "Key file could not be found: " & keyFile) if certFile != "": - var ret = SSL_CTX_use_certificate_chain_file(ctx, certFile) + var ret = SSLCTXUseCertificateChainFile(ctx, certFile) if ret != 1: raiseSSLError() @@ -567,18 +567,18 @@ when defineSsl: ## or using ECDSA: ## - ``openssl ecparam -out mykey.pem -name secp256k1 -genkey`` ## - ``openssl req -new -key mykey.pem -x509 -nodes -days 365 -out mycert.pem`` - var newCTX: SslCtx + var newCTX: SSL_CTX case protVersion of protSSLv23: newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support. of protSSLv2: - raiseSSLError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") + raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") of protSSLv3: - raiseSSLError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") + raiseSslError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") of protTLSv1: newCTX = SSL_CTX_new(TLSv1_method()) - if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1: + if newCTX.SSLCTXSetCipherList(cipherList) != 1: raiseSSLError() when not defined(openssl10) and not defined(libressl): let sslVersion = getOpenSSLVersion() @@ -631,11 +631,11 @@ when defineSsl: result = SSLContext(context: newCTX, referencedData: initHashSet[int](), extraInternal: new(SslContextExtraInternal)) - proc getExtraInternal(ctx: SslContext): SslContextExtraInternal = + proc getExtraInternal(ctx: SSLContext): SslContextExtraInternal = return ctx.extraInternal - proc destroyContext*(ctx: SslContext) = - ## Free memory referenced by SslContext. + proc destroyContext*(ctx: SSLContext) = + ## Free memory referenced by SSLContext. # We assume here that OpenSSL's internal indexes increase by 1 each time. # That means we can assume that the next internal index is the length of @@ -644,20 +644,20 @@ when defineSsl: GC_unref(getExtraData(ctx, i).RootRef) ctx.context.SSL_CTX_free() - proc `pskIdentityHint=`*(ctx: SslContext, hint: string) = + proc `pskIdentityHint=`*(ctx: SSLContext, hint: string) = ## Sets the identity hint passed to server. ## ## Only used in PSK ciphersuites. if ctx.context.SSL_CTX_use_psk_identity_hint(hint) <= 0: raiseSSLError() - proc clientGetPskFunc*(ctx: SslContext): SslClientGetPskFunc = + proc clientGetPskFunc*(ctx: SSLContext): SslClientGetPskFunc = return ctx.getExtraInternal().clientGetPskFunc proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; max_psk_len: cuint): cuint {.cdecl.} = - let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) + let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) let hintString = if hint == nil: "" else: $hint let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) if psk.len.cuint > max_psk_len: @@ -670,7 +670,7 @@ when defineSsl: return pskString.len.cuint - proc `clientGetPskFunc=`*(ctx: SslContext, fun: SslClientGetPskFunc) = + proc `clientGetPskFunc=`*(ctx: SSLContext, fun: SslClientGetPskFunc) = ## Sets function that returns the client identity and the PSK based on identity ## hint from the server. ## @@ -679,12 +679,12 @@ when defineSsl: ctx.context.SSL_CTX_set_psk_client_callback( if fun == nil: nil else: pskClientCallback) - proc serverGetPskFunc*(ctx: SslContext): SslServerGetPskFunc = + proc serverGetPskFunc*(ctx: SSLContext): SslServerGetPskFunc = return ctx.getExtraInternal().serverGetPskFunc proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} = - let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) + let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) let pskString = (ctx.serverGetPskFunc)($identity) if psk.len.cint > max_psk_len: return 0 @@ -692,7 +692,7 @@ when defineSsl: return pskString.len.cuint - proc `serverGetPskFunc=`*(ctx: SslContext, fun: SslServerGetPskFunc) = + proc `serverGetPskFunc=`*(ctx: SSLContext, fun: SslServerGetPskFunc) = ## Sets function that returns PSK based on the client identity. ## ## Only used in PSK ciphersuites. @@ -702,10 +702,10 @@ when defineSsl: proc getPskIdentity*(socket: Socket): string = ## Gets the PSK identity provided by the client. - assert socket.isSsl + assert socket.isSSL return $(socket.sslHandle.SSL_get_psk_identity) - proc wrapSocket*(ctx: SslContext, socket: Socket) = + proc wrapSocket*(ctx: SSLContext, socket: Socket) = ## Wraps a socket in an SSL context. This function effectively turns ## ``socket`` into an SSL socket. ## @@ -716,16 +716,16 @@ when defineSsl: ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. - assert(not socket.isSsl) - socket.isSsl = true + assert(not socket.isSSL) + socket.isSSL = true socket.sslContext = ctx - socket.sslHandle = SSL_new(socket.sslContext.context) + socket.sslHandle = SSLNew(socket.sslContext.context) socket.sslNoHandshake = false socket.sslHasPeekChar = false if socket.sslHandle == nil: raiseSSLError() - if SSL_set_fd(socket.sslHandle, socket.fd) != 1: + if SSLSetFd(socket.sslHandle, socket.fd) != 1: raiseSSLError() proc checkCertName(socket: Socket, hostname: string) = @@ -819,7 +819,7 @@ proc getSocketError*(socket: Socket): OSErrorCode = proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode) = - ## Raises an OSError based on the error code returned by ``SSL_get_error`` + ## Raises an OSError based on the error code returned by ``SSLGetError`` ## (for SSL sockets) and ``osLastError`` otherwise. ## ## If ``async`` is ``true`` no error will be thrown in the case when the @@ -827,9 +827,9 @@ proc socketError*(socket: Socket, err: int = -1, async = false, ## ## If ``err`` is not lower than 0 no exception will be raised. when defineSsl: - if socket.isSsl: + if socket.isSSL: if err <= 0: - var ret = SSL_get_error(socket.sslHandle, err.cint) + var ret = SSLGetError(socket.sslHandle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") @@ -845,13 +845,13 @@ proc socketError*(socket: Socket, err: int = -1, async = false, raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL: var errStr = "IO error has occurred " - let sslErr = ERR_peek_last_error() + let sslErr = ErrPeekLastError() if sslErr == 0 and err == 0: errStr.add "because an EOF was observed that violates the protocol" elif sslErr == 0 and err == -1: errStr.add "in the BIO layer" else: - let errStr = $ERR_error_string(sslErr, nil) + let errStr = $ErrErrorString(sslErr, nil) raiseSSLError(errStr & ": " & errStr) let osErr = osLastError() raiseOSError(osErr, errStr) @@ -859,7 +859,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false, raiseSSLError() else: raiseSSLError("Unknown Error") - if err == -1 and not (when defineSsl: socket.isSsl else: false): + if err == -1 and not (when defineSsl: socket.isSSL else: false): var lastE = if lastError.int == -1: getSocketError(socket) else: lastError if async: when useWinVersion: @@ -939,7 +939,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, # Handle SSL. when defineSsl: - if server.isSsl: + if server.isSSL: # We must wrap the client sock in a ssl context. server.sslContext.wrapSocket(client) @@ -949,7 +949,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, when false: #defineSsl: proc acceptAddrSSL*(server: Socket, client: var Socket, - address: var string): SSL_acceptResult {. + address: var string): SSLAcceptResult {. tags: [ReadIOEffect].} = ## This procedure should only be used for non-blocking **SSL** sockets. ## It will immediately return with one of the following values: @@ -967,16 +967,16 @@ when false: #defineSsl: ## to connect. template doHandshake(): untyped = when defineSsl: - if server.isSsl: + if server.isSSL: client.setBlocking(false) # We must wrap the client sock in a ssl context. - if not client.isSsl or client.sslHandle == nil: + if not client.isSSL or client.sslHandle == nil: server.sslContext.wrapSocket(client) ErrClearError() let ret = SSL_accept(client.sslHandle) while ret <= 0: - let err = SSL_get_error(client.sslHandle, ret) + let err = SSLGetError(client.sslHandle, ret) if err != SSL_ERROR_WANT_ACCEPT: case err of SSL_ERROR_ZERO_RETURN: @@ -993,7 +993,7 @@ when false: #defineSsl: raiseSSLError("Unknown error") client.sslNoHandshake = false - if client.isSsl and client.sslNoHandshake: + if client.isSSL and client.sslNoHandshake: doHandshake() return AcceptSuccess else: @@ -1039,8 +1039,8 @@ proc close*(socket: Socket) = socketError(socket, res) finally: when defineSsl: - if socket.isSsl and socket.sslHandle != nil: - SSL_free(socket.sslHandle) + if socket.isSSL and socket.sslHandle != nil: + SSLFree(socket.sslHandle) socket.sslHandle = nil socket.fd.close() @@ -1119,7 +1119,7 @@ when defined(ssl): ## and the server that ``socket`` is connected to. ## ## Throws SslError if ``socket`` is not an SSL socket. - if socket.isSsl: + if socket.isSSL: return not socket.sslNoHandshake else: raiseSSLError("Socket is not an SSL socket.") @@ -1131,7 +1131,7 @@ proc hasDataBuffered*(s: Socket): bool = result = s.bufLen > 0 and s.currPos != s.bufLen when defineSsl: - if s.isSsl and not result: + if s.isSSL and not result: result = s.sslHasPeekChar proc select(readfd: Socket, timeout = 500): int = @@ -1207,7 +1207,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ result = read else: when defineSsl: - if socket.isSsl: + if socket.isSSL: if socket.sslHasPeekChar: # TODO: Merge this peek char mess into uniRecv copyMem(data, addr(socket.sslPeekChar), 1) socket.sslHasPeekChar = false @@ -1246,11 +1246,11 @@ proc waitFor(socket: Socket, waited: var Duration, timeout, size: int, raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") when defineSsl: - if socket.isSsl: + if socket.isSSL: if socket.hasDataBuffered: # sslPeekChar is present. return 1 - let sslPending = SSL_pending(socket.sslHandle) + let sslPending = SSLPending(socket.sslHandle) if sslPending != 0: return min(sslPending, size) @@ -1352,7 +1352,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = c = socket.buffer[socket.currPos] else: when defineSsl: - if socket.isSsl: + if socket.isSSL: if not socket.sslHasPeekChar: result = uniRecv(socket, addr(socket.sslPeekChar), 1, 0'i32) socket.sslHasPeekChar = true @@ -1584,7 +1584,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, proc isSsl*(socket: Socket): bool = ## Determines whether ``socket`` is a SSL socket. when defineSsl: - result = socket.isSsl + result = socket.isSSL else: result = false @@ -1782,7 +1782,7 @@ proc connect*(socket: Socket, address: string, if not success: raiseOSError(lastError) when defineSsl: - if socket.isSsl: + if socket.isSSL: # RFC3546 for SNI specifies that IP addresses are not allowed. if not isIpAddress(address): # Discard result in case OpenSSL version doesn't support SNI, or we're @@ -1850,7 +1850,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), if res != 0: raiseOSError(OSErrorCode(res)) when defineSsl and not defined(nimdoc): - if socket.isSsl: + if socket.isSSL: socket.fd.setBlocking(true) doAssert socket.gotHandshake() socket.fd.setBlocking(true) diff --git a/testament/backend.nim b/testament/backend.nim index 0a6d7d8b9..c2658d6a0 100644 --- a/testament/backend.nim +++ b/testament/backend.nim @@ -23,8 +23,8 @@ var proc getMachine*(): MachineId = var name = execProcess("hostname").string.strip if name.len == 0: - name = when defined(posix): getEnv("HOSTNAME").string - else: getEnv("COMPUTERNAME").string + name = when defined(posix): getenv("HOSTNAME").string + else: getenv("COMPUTERNAME").string if name.len == 0: quit "cannot determine the machine name" diff --git a/testament/categories.nim b/testament/categories.nim index 760c3c5be..e44c3729f 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -297,7 +297,7 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) = testSpec r, makeTest(filename, options, cat), {targetJS} template testCPP(filename: untyped) = - testSpec r, makeTest(filename, options, cat), {targetCpp} + testSpec r, makeTest(filename, options, cat), {targetCPP} let tests = [ "niminaction/Chapter1/various1", @@ -384,7 +384,7 @@ proc findMainFile(dir: string): string = elif file.endsWith(".nim"): if result.len == 0: result = file inc nimFiles - if nimFiles != 1: result.setLen(0) + if nimFiles != 1: result.setlen(0) proc manyLoc(r: var TResults, cat: Category, options: string) = for kind, dir in os.walkDir("tests/manyloc"): @@ -567,7 +567,7 @@ const MegaTestCat = "megatest" proc `&.?`(a, b: string): string = # candidate for the stdlib? - result = if b.startsWith(a): b else: a & b + result = if b.startswith(a): b else: a & b proc processSingleTest(r: var TResults, cat: Category, options, test: string) = let test = testsDir &.? cat.string / test diff --git a/testament/htmlgen.nim b/testament/htmlgen.nim index 8e58dd95e..002bd83bc 100644 --- a/testament/htmlgen.nim +++ b/testament/htmlgen.nim @@ -63,7 +63,7 @@ proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode) = type AllTests = object - data: JsonNode + data: JSonNode totalCount, successCount, ignoredCount, failedCount: int successPercentage, ignoredPercentage, failedPercentage: BiggestFloat diff --git a/testament/testament.nim b/testament/testament.nim index 109ce4ed9..a798544ec 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -97,7 +97,7 @@ proc getFileDir(filename: string): string = if not result.isAbsolute(): result = getCurrentDir() / result -proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: string = ""): tuple[ +proc execCmdEx2(command: string, args: openarray[string]; workingDir, input: string = ""): tuple[ cmdLine: string, output: TaintedString, exitCode: int] {.tags: @@ -473,7 +473,7 @@ proc testSpecHelper(r: var TResults, test: TTest, expected: TSpec, if exitCode != expected.exitCode: r.addResult(test, target, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode & "\n\nOutput:\n" & - bufB, reExitcodesDiffer) + bufB, reExitCodesDiffer) elif (expected.outputCheck == ocEqual and expected.output != bufB) or (expected.outputCheck == ocSubstr and expected.output notin bufB): given.err = reOutputsDiffer @@ -536,7 +536,7 @@ proc testC(r: var TResults, test: TTest, action: TTestAction) = elif action == actionRun: let exeFile = changeFileExt(test.name, ExeExt) var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath}) - if exitCode != 0: given.err = reExitcodesDiffer + if exitCode != 0: given.err = reExitCodesDiffer if given.err == reSuccess: inc(r.passed) proc testExec(r: var TResults, test: TTest) = @@ -549,7 +549,7 @@ proc testExec(r: var TResults, test: TTest) = if errC == 0: given.err = reSuccess else: - given.err = reExitcodesDiffer + given.err = reExitCodesDiffer given.msg = outp.string if given.err == reSuccess: inc(r.passed) @@ -613,8 +613,8 @@ proc loadSkipFrom(name: string): seq[string] = result.add sline proc main() = - os.putEnv "NIMTEST_COLOR", "never" - os.putEnv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" + os.putenv "NIMTEST_COLOR", "never" + os.putenv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" azure.init() backend.open() @@ -627,7 +627,7 @@ proc main() = var p = initOptParser() p.next() - while p.kind in {cmdLongOption, cmdShortOption}: + while p.kind in {cmdLongoption, cmdShortOption}: case p.key.string.normalize of "print", "verbose": optPrintResults = true of "failing": optFailing = true diff --git a/tools/nimfind.nim b/tools/nimfind.nim index 05980d740..6a4585c7e 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -182,10 +182,10 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = parseopt.next(p) case p.kind of cmdEnd: break - of cmdLongOption, cmdShortOption: + of cmdLongoption, cmdShortOption: case p.key.normalize of "help", "h": - stdout.writeLine(Usage) + stdout.writeline(Usage) quit() of "project": conf.projectName = p.val @@ -215,7 +215,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = self.initDefinesProg(conf, "nimfind") if paramCount() == 0: - stdout.writeLine(Usage) + stdout.writeline(Usage) return self.processCmdLineAndProjectPath(conf) @@ -231,4 +231,4 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = discard self.loadConfigsAndRunMainCommand(cache, conf) -handleCmdLine(newIdentCache(), newConfigRef()) +handleCmdline(newIdentCache(), newConfigRef()) From 46aacf917f39d02c96175d358e7a76fc875ea070 Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 6 Jul 2020 11:24:43 +0200 Subject: [PATCH 0831/4254] Fix style inconsistencies due to the previous commit --- lib/impure/re.nim | 2 +- lib/pure/asyncnet.nim | 16 +++--- lib/pure/base64.nim | 2 +- lib/pure/httpclient.nim | 6 +-- lib/pure/net.nim | 110 +++++++++++++++++++-------------------- testament/backend.nim | 4 +- testament/categories.nim | 6 +-- testament/htmlgen.nim | 2 +- testament/testament.nim | 14 ++--- tools/nimfind.nim | 8 +-- 10 files changed, 85 insertions(+), 85 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 24841b40e..fe3ea96ff 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -122,7 +122,7 @@ proc bufSubstr(b: cstring, sPos, ePos: int): string {.inline.} = ## Don't assume cstring is '\0' terminated let sz = ePos - sPos result = newString(sz+1) - copyMem(addr(result[0]), unsafeaddr(b[sPos]), sz) + copyMem(addr(result[0]), unsafeAddr(b[sPos]), sz) result.setLen(sz) proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 0bdbeb29b..410310e29 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -202,7 +202,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint, when defineSsl: proc getSslError(handle: SslPtr, err: cint): cint = assert err < 0 - var ret = SSLGetError(handle, err.cint) + var ret = SSL_get_error(handle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") @@ -224,9 +224,9 @@ when defineSsl: let read = bioRead(socket.bioOut, addr data[0], len) assert read != 0 if read < 0: - raiseSslError() + raiseSSLError() data.setLen(read) - await socket.fd.AsyncFd.send(data, flags) + await socket.fd.AsyncFD.send(data, flags) proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag], sslError: cint): owned(Future[bool]) {.async.} = @@ -727,7 +727,7 @@ proc close*(socket: AsyncSocket) = if res == 0: discard elif res != 1: - raiseSslError() + raiseSSLError() socket.closed = true # TODO: Add extra debugging checks for this. when defineSsl: @@ -739,12 +739,12 @@ when defineSsl: ## prone to security vulnerabilities. socket.isSsl = true socket.sslContext = ctx - socket.sslHandle = SSLNew(socket.sslContext.context) + socket.sslHandle = SSL_new(socket.sslContext.context) if socket.sslHandle == nil: - raiseSslError() + raiseSSLError() - socket.bioIn = bioNew(bio_s_mem()) - socket.bioOut = bioNew(bio_s_mem()) + socket.bioIn = bioNew(bioSMem()) + socket.bioOut = bioNew(bioSMem()) sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut) proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket, diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index c140b9714..9495c4d56 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -229,7 +229,7 @@ proc decode*(s: string): string = return (size * 3 div 4) + 6 template inputChar(x: untyped) = - let x = int decode_table[ord(s[inputIndex])] + let x = int decodeTable[ord(s[inputIndex])] inc inputIndex if x == invalidChar: raise newException(ValueError, diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index e8936f87b..92e4cd2d6 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -313,10 +313,10 @@ proc fileError(msg: string) = raise e when not defined(ssl): - type SSLContext = ref object -var defaultSslContext {.threadvar.}: SSLContext + type SslContext = ref object +var defaultSslContext {.threadvar.}: SslContext -proc getDefaultSSL(): SSLContext = +proc getDefaultSSL(): SslContext = result = defaultSslContext when defined(ssl): if result == nil: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d18f18c92..7aeffbc35 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -128,8 +128,8 @@ type bufLen: int # current length of buffer when defineSsl: isSsl: bool - sslHandle: SSLPtr - sslContext: SSLContext + sslHandle: SslPtr + sslContext: SslContext sslNoHandshake: bool # True if needs handshake. sslHasPeekChar: bool sslPeekChar: char @@ -469,15 +469,15 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, when defineSsl: CRYPTO_malloc_init() doAssert SslLibraryInit() == 1 - SslLoadErrorStrings() - ErrLoadBioStrings() + SSL_load_error_strings() + ERR_load_BIO_strings() OpenSSL_add_all_algorithms() proc raiseSSLError*(s = "") = ## Raises a new SSL error. if s != "": - raise newException(SSLError, s) - let err = ErrPeekLastError() + raise newException(SslError, s) + let err = ERR_peek_last_error() if err == 0: raise newException(SslError, "No error reported.") var errStr = $ERR_error_string(err, nil) @@ -487,10 +487,10 @@ when defineSsl: "necessary protocols. OpenSSL error is: " & errStr else: discard - raise newException(SSLError, errStr) + raise newException(SslError, errStr) - proc getExtraData*(ctx: SSLContext, index: int): RootRef = - ## Retrieves arbitrary data stored inside SSLContext. + proc getExtraData*(ctx: SslContext, index: int): RootRef = + ## Retrieves arbitrary data stored inside SslContext. if index notin ctx.referencedData: raise newException(IndexDefect, "No data with that index.") let res = ctx.context.SSL_CTX_get_ex_data(index.cint) @@ -498,8 +498,8 @@ when defineSsl: raiseSSLError() return cast[RootRef](res) - proc setExtraData*(ctx: SSLContext, index: int, data: RootRef) = - ## Stores arbitrary data inside SSLContext. The unique `index` + proc setExtraData*(ctx: SslContext, index: int, data: RootRef) = + ## Stores arbitrary data inside SslContext. The unique `index` ## should be retrieved using getSslContextExtraDataIndex. if index in ctx.referencedData: GC_unref(getExtraData(ctx, index)) @@ -520,7 +520,7 @@ when defineSsl: raise newException(system.IOError, "Key file could not be found: " & keyFile) if certFile != "": - var ret = SSLCTXUseCertificateChainFile(ctx, certFile) + var ret = SSL_CTX_use_certificate_chain_file(ctx, certFile) if ret != 1: raiseSSLError() @@ -567,18 +567,18 @@ when defineSsl: ## or using ECDSA: ## - ``openssl ecparam -out mykey.pem -name secp256k1 -genkey`` ## - ``openssl req -new -key mykey.pem -x509 -nodes -days 365 -out mycert.pem`` - var newCTX: SSL_CTX + var newCTX: SslCtx case protVersion of protSSLv23: newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support. of protSSLv2: - raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") + raiseSSLError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") of protSSLv3: - raiseSslError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") + raiseSSLError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") of protTLSv1: newCTX = SSL_CTX_new(TLSv1_method()) - if newCTX.SSLCTXSetCipherList(cipherList) != 1: + if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1: raiseSSLError() when not defined(openssl10) and not defined(libressl): let sslVersion = getOpenSSLVersion() @@ -631,11 +631,11 @@ when defineSsl: result = SSLContext(context: newCTX, referencedData: initHashSet[int](), extraInternal: new(SslContextExtraInternal)) - proc getExtraInternal(ctx: SSLContext): SslContextExtraInternal = + proc getExtraInternal(ctx: SslContext): SslContextExtraInternal = return ctx.extraInternal - proc destroyContext*(ctx: SSLContext) = - ## Free memory referenced by SSLContext. + proc destroyContext*(ctx: SslContext) = + ## Free memory referenced by SslContext. # We assume here that OpenSSL's internal indexes increase by 1 each time. # That means we can assume that the next internal index is the length of @@ -644,20 +644,20 @@ when defineSsl: GC_unref(getExtraData(ctx, i).RootRef) ctx.context.SSL_CTX_free() - proc `pskIdentityHint=`*(ctx: SSLContext, hint: string) = + proc `pskIdentityHint=`*(ctx: SslContext, hint: string) = ## Sets the identity hint passed to server. ## ## Only used in PSK ciphersuites. if ctx.context.SSL_CTX_use_psk_identity_hint(hint) <= 0: raiseSSLError() - proc clientGetPskFunc*(ctx: SSLContext): SslClientGetPskFunc = + proc clientGetPskFunc*(ctx: SslContext): SslClientGetPskFunc = return ctx.getExtraInternal().clientGetPskFunc proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; max_psk_len: cuint): cuint {.cdecl.} = - let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) + let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let hintString = if hint == nil: "" else: $hint let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) if psk.len.cuint > max_psk_len: @@ -670,7 +670,7 @@ when defineSsl: return pskString.len.cuint - proc `clientGetPskFunc=`*(ctx: SSLContext, fun: SslClientGetPskFunc) = + proc `clientGetPskFunc=`*(ctx: SslContext, fun: SslClientGetPskFunc) = ## Sets function that returns the client identity and the PSK based on identity ## hint from the server. ## @@ -679,12 +679,12 @@ when defineSsl: ctx.context.SSL_CTX_set_psk_client_callback( if fun == nil: nil else: pskClientCallback) - proc serverGetPskFunc*(ctx: SSLContext): SslServerGetPskFunc = + proc serverGetPskFunc*(ctx: SslContext): SslServerGetPskFunc = return ctx.getExtraInternal().serverGetPskFunc proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} = - let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) + let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let pskString = (ctx.serverGetPskFunc)($identity) if psk.len.cint > max_psk_len: return 0 @@ -692,7 +692,7 @@ when defineSsl: return pskString.len.cuint - proc `serverGetPskFunc=`*(ctx: SSLContext, fun: SslServerGetPskFunc) = + proc `serverGetPskFunc=`*(ctx: SslContext, fun: SslServerGetPskFunc) = ## Sets function that returns PSK based on the client identity. ## ## Only used in PSK ciphersuites. @@ -702,10 +702,10 @@ when defineSsl: proc getPskIdentity*(socket: Socket): string = ## Gets the PSK identity provided by the client. - assert socket.isSSL + assert socket.isSsl return $(socket.sslHandle.SSL_get_psk_identity) - proc wrapSocket*(ctx: SSLContext, socket: Socket) = + proc wrapSocket*(ctx: SslContext, socket: Socket) = ## Wraps a socket in an SSL context. This function effectively turns ## ``socket`` into an SSL socket. ## @@ -716,16 +716,16 @@ when defineSsl: ## **Disclaimer**: This code is not well tested, may be very unsafe and ## prone to security vulnerabilities. - assert(not socket.isSSL) - socket.isSSL = true + assert(not socket.isSsl) + socket.isSsl = true socket.sslContext = ctx - socket.sslHandle = SSLNew(socket.sslContext.context) + socket.sslHandle = SSL_new(socket.sslContext.context) socket.sslNoHandshake = false socket.sslHasPeekChar = false if socket.sslHandle == nil: raiseSSLError() - if SSLSetFd(socket.sslHandle, socket.fd) != 1: + if SSL_set_fd(socket.sslHandle, socket.fd) != 1: raiseSSLError() proc checkCertName(socket: Socket, hostname: string) = @@ -819,7 +819,7 @@ proc getSocketError*(socket: Socket): OSErrorCode = proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode) = - ## Raises an OSError based on the error code returned by ``SSLGetError`` + ## Raises an OSError based on the error code returned by ``SSL_get_error`` ## (for SSL sockets) and ``osLastError`` otherwise. ## ## If ``async`` is ``true`` no error will be thrown in the case when the @@ -827,9 +827,9 @@ proc socketError*(socket: Socket, err: int = -1, async = false, ## ## If ``err`` is not lower than 0 no exception will be raised. when defineSsl: - if socket.isSSL: + if socket.isSsl: if err <= 0: - var ret = SSLGetError(socket.sslHandle, err.cint) + var ret = SSL_get_error(socket.sslHandle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") @@ -845,13 +845,13 @@ proc socketError*(socket: Socket, err: int = -1, async = false, raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL: var errStr = "IO error has occurred " - let sslErr = ErrPeekLastError() + let sslErr = ERR_peek_last_error() if sslErr == 0 and err == 0: errStr.add "because an EOF was observed that violates the protocol" elif sslErr == 0 and err == -1: errStr.add "in the BIO layer" else: - let errStr = $ErrErrorString(sslErr, nil) + let errStr = $ERR_error_string(sslErr, nil) raiseSSLError(errStr & ": " & errStr) let osErr = osLastError() raiseOSError(osErr, errStr) @@ -859,7 +859,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false, raiseSSLError() else: raiseSSLError("Unknown Error") - if err == -1 and not (when defineSsl: socket.isSSL else: false): + if err == -1 and not (when defineSsl: socket.isSsl else: false): var lastE = if lastError.int == -1: getSocketError(socket) else: lastError if async: when useWinVersion: @@ -939,7 +939,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, # Handle SSL. when defineSsl: - if server.isSSL: + if server.isSsl: # We must wrap the client sock in a ssl context. server.sslContext.wrapSocket(client) @@ -949,7 +949,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, when false: #defineSsl: proc acceptAddrSSL*(server: Socket, client: var Socket, - address: var string): SSLAcceptResult {. + address: var string): SSL_acceptResult {. tags: [ReadIOEffect].} = ## This procedure should only be used for non-blocking **SSL** sockets. ## It will immediately return with one of the following values: @@ -967,16 +967,16 @@ when false: #defineSsl: ## to connect. template doHandshake(): untyped = when defineSsl: - if server.isSSL: + if server.isSsl: client.setBlocking(false) # We must wrap the client sock in a ssl context. - if not client.isSSL or client.sslHandle == nil: + if not client.isSsl or client.sslHandle == nil: server.sslContext.wrapSocket(client) ErrClearError() let ret = SSL_accept(client.sslHandle) while ret <= 0: - let err = SSLGetError(client.sslHandle, ret) + let err = SSL_get_error(client.sslHandle, ret) if err != SSL_ERROR_WANT_ACCEPT: case err of SSL_ERROR_ZERO_RETURN: @@ -993,7 +993,7 @@ when false: #defineSsl: raiseSSLError("Unknown error") client.sslNoHandshake = false - if client.isSSL and client.sslNoHandshake: + if client.isSsl and client.sslNoHandshake: doHandshake() return AcceptSuccess else: @@ -1039,8 +1039,8 @@ proc close*(socket: Socket) = socketError(socket, res) finally: when defineSsl: - if socket.isSSL and socket.sslHandle != nil: - SSLFree(socket.sslHandle) + if socket.isSsl and socket.sslHandle != nil: + SSL_free(socket.sslHandle) socket.sslHandle = nil socket.fd.close() @@ -1119,7 +1119,7 @@ when defined(ssl): ## and the server that ``socket`` is connected to. ## ## Throws SslError if ``socket`` is not an SSL socket. - if socket.isSSL: + if socket.isSsl: return not socket.sslNoHandshake else: raiseSSLError("Socket is not an SSL socket.") @@ -1131,7 +1131,7 @@ proc hasDataBuffered*(s: Socket): bool = result = s.bufLen > 0 and s.currPos != s.bufLen when defineSsl: - if s.isSSL and not result: + if s.isSsl and not result: result = s.sslHasPeekChar proc select(readfd: Socket, timeout = 500): int = @@ -1207,7 +1207,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ result = read else: when defineSsl: - if socket.isSSL: + if socket.isSsl: if socket.sslHasPeekChar: # TODO: Merge this peek char mess into uniRecv copyMem(data, addr(socket.sslPeekChar), 1) socket.sslHasPeekChar = false @@ -1246,11 +1246,11 @@ proc waitFor(socket: Socket, waited: var Duration, timeout, size: int, raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") when defineSsl: - if socket.isSSL: + if socket.isSsl: if socket.hasDataBuffered: # sslPeekChar is present. return 1 - let sslPending = SSLPending(socket.sslHandle) + let sslPending = SSL_pending(socket.sslHandle) if sslPending != 0: return min(sslPending, size) @@ -1352,7 +1352,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = c = socket.buffer[socket.currPos] else: when defineSsl: - if socket.isSSL: + if socket.isSsl: if not socket.sslHasPeekChar: result = uniRecv(socket, addr(socket.sslPeekChar), 1, 0'i32) socket.sslHasPeekChar = true @@ -1584,7 +1584,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, proc isSsl*(socket: Socket): bool = ## Determines whether ``socket`` is a SSL socket. when defineSsl: - result = socket.isSSL + result = socket.isSsl else: result = false @@ -1782,7 +1782,7 @@ proc connect*(socket: Socket, address: string, if not success: raiseOSError(lastError) when defineSsl: - if socket.isSSL: + if socket.isSsl: # RFC3546 for SNI specifies that IP addresses are not allowed. if not isIpAddress(address): # Discard result in case OpenSSL version doesn't support SNI, or we're @@ -1850,7 +1850,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), if res != 0: raiseOSError(OSErrorCode(res)) when defineSsl and not defined(nimdoc): - if socket.isSSL: + if socket.isSsl: socket.fd.setBlocking(true) doAssert socket.gotHandshake() socket.fd.setBlocking(true) diff --git a/testament/backend.nim b/testament/backend.nim index c2658d6a0..0a6d7d8b9 100644 --- a/testament/backend.nim +++ b/testament/backend.nim @@ -23,8 +23,8 @@ var proc getMachine*(): MachineId = var name = execProcess("hostname").string.strip if name.len == 0: - name = when defined(posix): getenv("HOSTNAME").string - else: getenv("COMPUTERNAME").string + name = when defined(posix): getEnv("HOSTNAME").string + else: getEnv("COMPUTERNAME").string if name.len == 0: quit "cannot determine the machine name" diff --git a/testament/categories.nim b/testament/categories.nim index e44c3729f..760c3c5be 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -297,7 +297,7 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) = testSpec r, makeTest(filename, options, cat), {targetJS} template testCPP(filename: untyped) = - testSpec r, makeTest(filename, options, cat), {targetCPP} + testSpec r, makeTest(filename, options, cat), {targetCpp} let tests = [ "niminaction/Chapter1/various1", @@ -384,7 +384,7 @@ proc findMainFile(dir: string): string = elif file.endsWith(".nim"): if result.len == 0: result = file inc nimFiles - if nimFiles != 1: result.setlen(0) + if nimFiles != 1: result.setLen(0) proc manyLoc(r: var TResults, cat: Category, options: string) = for kind, dir in os.walkDir("tests/manyloc"): @@ -567,7 +567,7 @@ const MegaTestCat = "megatest" proc `&.?`(a, b: string): string = # candidate for the stdlib? - result = if b.startswith(a): b else: a & b + result = if b.startsWith(a): b else: a & b proc processSingleTest(r: var TResults, cat: Category, options, test: string) = let test = testsDir &.? cat.string / test diff --git a/testament/htmlgen.nim b/testament/htmlgen.nim index 002bd83bc..8e58dd95e 100644 --- a/testament/htmlgen.nim +++ b/testament/htmlgen.nim @@ -63,7 +63,7 @@ proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode) = type AllTests = object - data: JSonNode + data: JsonNode totalCount, successCount, ignoredCount, failedCount: int successPercentage, ignoredPercentage, failedPercentage: BiggestFloat diff --git a/testament/testament.nim b/testament/testament.nim index a798544ec..109ce4ed9 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -97,7 +97,7 @@ proc getFileDir(filename: string): string = if not result.isAbsolute(): result = getCurrentDir() / result -proc execCmdEx2(command: string, args: openarray[string]; workingDir, input: string = ""): tuple[ +proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: string = ""): tuple[ cmdLine: string, output: TaintedString, exitCode: int] {.tags: @@ -473,7 +473,7 @@ proc testSpecHelper(r: var TResults, test: TTest, expected: TSpec, if exitCode != expected.exitCode: r.addResult(test, target, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode & "\n\nOutput:\n" & - bufB, reExitCodesDiffer) + bufB, reExitcodesDiffer) elif (expected.outputCheck == ocEqual and expected.output != bufB) or (expected.outputCheck == ocSubstr and expected.output notin bufB): given.err = reOutputsDiffer @@ -536,7 +536,7 @@ proc testC(r: var TResults, test: TTest, action: TTestAction) = elif action == actionRun: let exeFile = changeFileExt(test.name, ExeExt) var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath}) - if exitCode != 0: given.err = reExitCodesDiffer + if exitCode != 0: given.err = reExitcodesDiffer if given.err == reSuccess: inc(r.passed) proc testExec(r: var TResults, test: TTest) = @@ -549,7 +549,7 @@ proc testExec(r: var TResults, test: TTest) = if errC == 0: given.err = reSuccess else: - given.err = reExitCodesDiffer + given.err = reExitcodesDiffer given.msg = outp.string if given.err == reSuccess: inc(r.passed) @@ -613,8 +613,8 @@ proc loadSkipFrom(name: string): seq[string] = result.add sline proc main() = - os.putenv "NIMTEST_COLOR", "never" - os.putenv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" + os.putEnv "NIMTEST_COLOR", "never" + os.putEnv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" azure.init() backend.open() @@ -627,7 +627,7 @@ proc main() = var p = initOptParser() p.next() - while p.kind in {cmdLongoption, cmdShortOption}: + while p.kind in {cmdLongOption, cmdShortOption}: case p.key.string.normalize of "print", "verbose": optPrintResults = true of "failing": optFailing = true diff --git a/tools/nimfind.nim b/tools/nimfind.nim index 6a4585c7e..05980d740 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -182,10 +182,10 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = parseopt.next(p) case p.kind of cmdEnd: break - of cmdLongoption, cmdShortOption: + of cmdLongOption, cmdShortOption: case p.key.normalize of "help", "h": - stdout.writeline(Usage) + stdout.writeLine(Usage) quit() of "project": conf.projectName = p.val @@ -215,7 +215,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = self.initDefinesProg(conf, "nimfind") if paramCount() == 0: - stdout.writeline(Usage) + stdout.writeLine(Usage) return self.processCmdLineAndProjectPath(conf) @@ -231,4 +231,4 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = discard self.loadConfigsAndRunMainCommand(cache, conf) -handleCmdline(newIdentCache(), newConfigRef()) +handleCmdLine(newIdentCache(), newConfigRef()) From 6f962a4b3628fe746dba66520d725f4d2d1b5c1a Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 6 Jul 2020 13:41:42 +0200 Subject: [PATCH 0832/4254] fixes #14830 --- lib/packages/docutils/highlite.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index ca6a3e05e..796c17d7d 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -342,7 +342,7 @@ proc nimNextToken(g: var GeneralTokenizer) = inc(pos) g.kind = gtNone g.length = pos - g.pos - if g.kind != gtEof and g.length <= 0: + if g.kind != gtEof and g.state != gtNone and g.length <= 0: assert false, "nimNextToken: produced an empty token" g.pos = pos From 65af99a203387882d9fba7d94ae0cd46f479dd1f Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 6 Jul 2020 14:01:25 +0200 Subject: [PATCH 0833/4254] added security.md; refs #14882 --- security.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 security.md diff --git a/security.md b/security.md new file mode 100644 index 000000000..f1eaf3290 --- /dev/null +++ b/security.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported Versions + +Security fixes are provided in new releases and bugfix releases. + +We do not backport security fixes to older releases. + +(Yet, Linux distributions might backport security fixes for their packages.) + +## Reporting a Vulnerability + +Please do not report vulnerabilities via GitHub issues. + +If you have discovered a vulnerability, it is the best to notify us about it via +security@nim-lang.org in order to setup a meeting where we can discuss the next +steps. From a754160d654f03584088412f51b153ae6a170adb Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 6 Jul 2020 14:02:03 +0200 Subject: [PATCH 0834/4254] tables.nim: Add named fields in `smallest` and `largest` (#14919) The `smallest` and `largest` procs for `CountTable` returned a tuple with named fields, but the same procs for `CountTableRef` returned an anonymous tuple. This commit makes those `CountTableRef` procs more consistent, and adds a test. Fixes: #14918 --- lib/pure/collections/tables.nim | 4 ++-- tests/collections/ttables.nim | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 2ea58ce1f..a969a4c5d 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -2670,14 +2670,14 @@ proc inc*[A](t: CountTableRef[A], key: A, val = 1) = doAssert a == newCountTable("aaabbbbbbbbbbb") t[].inc(key, val) -proc smallest*[A](t: CountTableRef[A]): (A, int) = +proc smallest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n) ## ## See also: ## * `largest proc<#largest,CountTableRef[A]>`_ t[].smallest -proc largest*[A](t: CountTableRef[A]): (A, int) = +proc largest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = ## Returns the ``(key, value)`` pair with the largest ``val``. Efficiency: O(n) ## ## See also: diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 2a590dd26..392b5e93e 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -325,6 +325,20 @@ block tablesref: else: break inc i + block smallestLargestNamedFieldsTest: # bug #14918 + const a = [7, 8, 8] + + proc testNamedFields(t: CountTable | CountTableRef) = + doAssert t.smallest.key == 7 + doAssert t.smallest.val == 1 + doAssert t.largest.key == 8 + doAssert t.largest.val == 2 + + let t1 = toCountTable(a) + testNamedFields(t1) + let t2 = newCountTable(a) + testNamedFields(t2) + block SyntaxTest: var x = newTable[int, string]({:}) discard x From ebd97884a0134ba2f88e19f647585aa6133536aa Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 6 Jul 2020 20:53:38 +0200 Subject: [PATCH 0835/4254] Add testcase for #14472 (#14921) --- tests/arc/t14472.nim | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/arc/t14472.nim diff --git a/tests/arc/t14472.nim b/tests/arc/t14472.nim new file mode 100644 index 000000000..47ed77f4c --- /dev/null +++ b/tests/arc/t14472.nim @@ -0,0 +1,23 @@ +discard """ + valgrind: true + cmd: "nim c --gc:arc -d:useMalloc $file" +""" + +type + ImportMaterial* = object + # Adding a field here makes the problem go away. + + Mesh* = object + vertices: seq[float32] + material: ImportMaterial + + ImportedScene* = object + meshes*: seq[Mesh] + +proc bork() : ImportedScene = + var mats: seq[ImportMaterial] + + setLen(mats, 1) + add(result.meshes, Mesh(material: mats[0])) + +var s = bork() From 5bd2da3f6461ef4dbcfd1f0c35178fa8fa9b5368 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 7 Jul 2020 10:21:18 +0200 Subject: [PATCH 0836/4254] Fix #14911 (#14922) [backport] * Fix #14911 * Add testcase * Fix test --- compiler/semexprs.nim | 2 +- tests/tuples/ttuples_issues.nim | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a9d45615e..de9f2198a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2432,7 +2432,7 @@ proc checkPar(c: PContext; n: PNode): TParKind = for i in 0.. Date: Tue, 7 Jul 2020 17:22:10 +0900 Subject: [PATCH 0837/4254] Limit number of error messages from gcc/clang backend (#14852) * Limit number of error messages from backend * Avoid duplication of -fmax-errors * make tests/misc/trunner.nim success --- config/nim.cfg | 16 +++++++++------- tests/misc/msizeof5.nim.cfg | 5 +++++ 2 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 tests/misc/msizeof5.nim.cfg diff --git a/config/nim.cfg b/config/nim.cfg index c888fcf89..d8d3d4f8b 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -167,17 +167,19 @@ path="$lib/pure" @end @end +gcc.maxerrorsimpl = "-fmax-errors=3" + @if macosx or freebsd or openbsd: cc = clang tlsEmulation:on - gcc.options.always = "-w" - gcc.cpp.options.always = "-w -fpermissive" + gcc.options.always %= "-w ${gcc.maxerrorsimpl}" + gcc.cpp.options.always %= "-w ${gcc.maxerrorsimpl} -fpermissive" @elif windows: - gcc.options.always = "-w -mno-ms-bitfields" - gcc.cpp.options.always = "-w -fpermissive -mno-ms-bitfields" + gcc.options.always %= "-w ${gcc.maxerrorsimpl} -mno-ms-bitfields" + gcc.cpp.options.always %= "-w ${gcc.maxerrorsimpl} -fpermissive -mno-ms-bitfields" @else: - gcc.options.always = "-w" - gcc.cpp.options.always = "-w -fpermissive" + gcc.options.always %= "-w ${gcc.maxerrorsimpl}" + gcc.cpp.options.always %= "-w ${gcc.maxerrorsimpl} -fpermissive" @end # Configuration for Objective-C compiler: @@ -245,7 +247,7 @@ llvm_gcc.options.size = "-Os" # Configuration for the LLVM CLang compiler: clang.options.debug = "-g" clang.cpp.options.debug = "-g" -clang.options.always = "-w" +clang.options.always = "-w -ferror-limit=3" clang.options.speed = "-O3" clang.options.size = "-Os" diff --git a/tests/misc/msizeof5.nim.cfg b/tests/misc/msizeof5.nim.cfg new file mode 100644 index 000000000..dc0712a8c --- /dev/null +++ b/tests/misc/msizeof5.nim.cfg @@ -0,0 +1,5 @@ +# Do not limit number of error messages from backend compiler. +gcc.options.always %= "${gcc.options.always} -fmax-errors=100" +clang.options.always %= "${clang.options.always} -ferror-limit=100" +gcc.cpp.options.always %= "${gcc.cpp.options.always} -fmax-errors=100" +clang.cpp.options.always %= "${clang.cpp.options.always} -ferror-limit=100" From 37253d660f93ac86942579defbde790ec557dcf1 Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Tue, 7 Jul 2020 03:22:55 -0500 Subject: [PATCH 0838/4254] Minor improvements to typecast section of manual (#14896) * Minor improvements to typecast section of manual * Clarification to casting w/ concrete types * Added less ambiguous language --- doc/manual.rst | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 99888ad53..c5608da84 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3230,7 +3230,7 @@ has lots of advantages: Type conversions ---------------- -Syntactically a `type conversion` is like a procedure call, but a +Syntactically a *type conversion* is like a procedure call, but a type name replaces the procedure name. A type conversion is always safe in the sense that a failure to convert a type to another results in an exception (if it cannot be determined statically). @@ -3265,15 +3265,26 @@ conversions too are now *always unchecked*. Type casts ---------- -Example: + +*Type casts* are a crude mechanism to interpret the bit pattern of an expression +as if it would be of another type. Type casts are only needed for low-level +programming and are inherently unsafe. .. code-block:: nim cast[int](x) + +The target type of a cast must be a concrete type, for instance, a target type +that is a type class (which is non-concrete) would be invalid: -Type casts are a crude mechanism to interpret the bit pattern of -an expression as if it would be of another type. Type casts are -only needed for low-level programming and are inherently unsafe. - +.. code-block:: nim + type Foo = int or float + var x = cast[Foo](1) # Error: cannot cast to a non concrete type: 'Foo' + +Type casts should not be confused with *type conversions,* as mentioned in the +prior section. Unlike type conversions, a type cast cannot change the underlying +bit pattern of the data being casted (aside from that the size of the target type +may differ from the source type). Casting resembles *type punning* in other +languages or C++'s ``reinterpret_cast`` and ``bit_cast`` features. The addr operator ----------------- From 49cea86d8bb836188bf1e3b173715d406af48153 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Jul 2020 12:14:43 +0200 Subject: [PATCH 0839/4254] weaken tosproc test for my Windows machine which doesn't have 'ls' --- tests/stdlib/tosproc.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index 363bd5d74..78b3ea807 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -219,7 +219,8 @@ else: # main driver var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") stripLineEnd(result[0]) doAssert result == ("12", 0) - doAssert execCmdEx("ls --nonexistant").exitCode != 0 + when not defined(windows): + doAssert execCmdEx("ls --nonexistant").exitCode != 0 when false: # bug: on windows, this raises; on posix, passes doAssert execCmdEx("nonexistant").exitCode != 0 From 95808c2806ef2dbbbc10296601ba3885efe8bc78 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Jul 2020 12:15:20 +0200 Subject: [PATCH 0840/4254] speed up Nim's lexer by using cstring instead of string. C optimizers are fragile. --- compiler/nimlexbase.nim | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index e3e8f1dbb..af2ae64a3 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -39,7 +39,9 @@ const type TBaseLexer* = object of RootObj bufpos*: int - buf*: string + buf*: cstring + bufStorage: string + bufLen: int stream*: PLLStream # we read from this stream lineNumber*: int # the current line number # private data: @@ -75,8 +77,8 @@ proc fillBuffer(L: var TBaseLexer) = oldBufLen: int # we know here that pos == L.sentinel, but not if this proc # is called the first time by initBaseLexer() - assert(L.sentinel < L.buf.len) - toCopy = L.buf.len - L.sentinel - 1 + assert(L.sentinel < L.bufLen) + toCopy = L.bufLen - L.sentinel - 1 assert(toCopy >= 0) if toCopy > 0: moveMem(addr L.buf[0], addr L.buf[L.sentinel + 1], toCopy) @@ -90,7 +92,7 @@ proc fillBuffer(L: var TBaseLexer) = # compute sentinel: dec(s) # BUGFIX (valgrind) while true: - assert(s < L.buf.len) + assert(s < L.bufLen) while (s >= 0) and not (L.buf[s] in NewLines): dec(s) if s >= 0: # we found an appropriate character for a sentinel: @@ -99,16 +101,18 @@ proc fillBuffer(L: var TBaseLexer) = else: # rather than to give up here because the line is too long, # double the buffer's size and try again: - oldBufLen = L.buf.len - L.buf.setLen(L.buf.len * 2) - assert(L.buf.len - oldBufLen == oldBufLen) + oldBufLen = L.bufLen + L.bufLen = L.bufLen * 2 + L.bufStorage.setLen(L.bufLen) + L.buf = L.bufStorage + assert(L.bufLen - oldBufLen == oldBufLen) charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]), oldBufLen) if charsRead < oldBufLen: L.buf[oldBufLen + charsRead] = EndOfFile L.sentinel = oldBufLen + charsRead break - s = L.buf.len - 1 + s = L.bufLen - 1 proc fillBaseLexer(L: var TBaseLexer, pos: int): int = assert(pos <= L.sentinel) @@ -142,7 +146,9 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) = assert(bufLen > 0) L.bufpos = 0 L.offsetBase = 0 - L.buf = newString(bufLen) + L.bufStorage = newString(bufLen) + L.buf = L.bufStorage + L.bufLen = bufLen L.sentinel = bufLen - 1 L.lineStart = 0 L.lineNumber = 1 # lines start at 1 From a61a7889b8ffe3b5a31b025272b5fd27d69484f5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 7 Jul 2020 17:47:57 +0200 Subject: [PATCH 0841/4254] injectdestructors: refactoring, added more cases explicitly (#14929) --- compiler/injectdestructors.nim | 75 ++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index e10686917..bf0206055 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -706,7 +706,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, - nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt}: + nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkTryStmt}: template process(child, s): untyped = p(child, c, s, mode) handleNestedTempl(n, process) elif mode == sinkArg: @@ -748,7 +748,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = passCopyToSink(n, c, s) else: case n.kind - of nkBracket, nkObjConstr, nkTupleConstr, nkClosure: + of nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkCurly: # Let C(x) be the construction, 'x' the vector of arguments. # C(x) either owns 'x' or it doesn't. # If C(x) owns its data, we must consume C(x). @@ -790,7 +790,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = shallowCopy(n) for i in 1.. 0): + if i < L and isCompileTimeOnly(parameters[i]): + result[i] = n[i] + elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0): result[i] = p(n[i], c, s, sinkArg) else: result[i] = p(n[i], c, s, normal) @@ -867,8 +869,67 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState: + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: result = n + + of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock: + result = shallowCopy(n) + for i in 0 ..< n.len: + result[i] = p(n[i], c, s, normal) + if n.typ != nil and hasDestructor(n.typ): + if mode == normal: + result = ensureDestruction(result, c, s) + + of nkHiddenSubConv, nkHiddenStdConv, nkConv: + # we have an "ownership invariance" for all constructors C(x). + # See the comment for nkBracket construction. If the caller wants + # to own 'C(x)', it really wants to own 'x' too. If it doesn't, + # we need to destroy 'x' but the function call handling ensures that + # already. + result = copyTree(n) + if n.typ.skipTypes(abstractInst-{tyOwned}).kind != tyOwned and + n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned: + # allow conversions from owned to unowned via this little hack: + let nTyp = n[1].typ + n[1].typ = n.typ + result[1] = p(n[1], c, s, mode) + result[1].typ = nTyp + else: + result[1] = p(n[1], c, s, mode) + + of nkObjDownConv, nkObjUpConv: + result = copyTree(n) + result[0] = p(n[0], c, s, mode) + + of nkDotExpr: + result = shallowCopy(n) + result[0] = p(n[0], c, s, normal) + for i in 1 ..< n.len: + result[i] = n[i] + if mode == sinkArg and hasDestructor(n.typ): + if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): + s.wasMoved.add genWasMoved(n, c) + else: + result = passCopyToSink(result, c, s) + + of nkBracketExpr, nkAddr, nkHiddenAddr, nkDerefExpr, nkHiddenDeref: + result = shallowCopy(n) + for i in 0 ..< n.len: + result[i] = p(n[i], c, s, normal) + if mode == sinkArg and hasDestructor(n.typ): + if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): + # consider 'a[(g; destroy(g); 3)]', we want to say 'wasMoved(a[3])' + # without the junk, hence 'genWasMoved(n, c)' + # and not 'genWasMoved(result, c)': + s.wasMoved.add genWasMoved(n, c) + else: + result = passCopyToSink(result, c, s) + + of nkDefer, nkRange: + result = shallowCopy(n) + for i in 0 ..< n.len: + result[i] = p(n[i], c, s, normal) + of nkBreakStmt: s.needsTry = true result = n @@ -886,10 +947,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[0] = p(n[0], c, s, mode) for i in 1.. Date: Tue, 7 Jul 2020 19:18:02 +0100 Subject: [PATCH 0842/4254] Revert commit 3e843ab3358. Closes #14930. --- lib/pure/times.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index fb2f5e430..16d7ff31d 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1408,7 +1408,7 @@ proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} '-' & intToStr(dt.monthday, 2) proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = - ## Gets the current local clock time as a string of the format ``HH:mm:ss``. + ## Gets the current local clock time as a string of the format ``HH:MM:SS``. runnableExamples: echo getClockStr(now() - 1.hours) assertDateTimeInitialized dt From 8480bef1c4f289228808a9b7525f6052c0ca7152 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 7 Jul 2020 22:43:36 +0200 Subject: [PATCH 0843/4254] Add testcase for #14864 (#14928) * Add testcase for #14864 * :D --- tests/arc/bmodule.nim | 4 ++++ tests/arc/cmodule.nim | 4 ++++ tests/arc/t14864.nim | 5 +++++ 3 files changed, 13 insertions(+) create mode 100644 tests/arc/bmodule.nim create mode 100644 tests/arc/cmodule.nim create mode 100644 tests/arc/t14864.nim diff --git a/tests/arc/bmodule.nim b/tests/arc/bmodule.nim new file mode 100644 index 000000000..70c2cc645 --- /dev/null +++ b/tests/arc/bmodule.nim @@ -0,0 +1,4 @@ +import cmodule + +for i in @[1, 2, 3].cycle(): + echo i diff --git a/tests/arc/cmodule.nim b/tests/arc/cmodule.nim new file mode 100644 index 000000000..6c6e6c0fa --- /dev/null +++ b/tests/arc/cmodule.nim @@ -0,0 +1,4 @@ +iterator cycle*[T](s: openArray[T]): T = + let s = @s + for x in s: + yield x diff --git a/tests/arc/t14864.nim b/tests/arc/t14864.nim new file mode 100644 index 000000000..f59b14d2c --- /dev/null +++ b/tests/arc/t14864.nim @@ -0,0 +1,5 @@ +discard """ + cmd: "nim c --gc:arc $file" +""" + +import bmodule From e82a14b2735e58a4230d79820465753e2592cd2b Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 7 Jul 2020 22:57:06 +0200 Subject: [PATCH 0844/4254] fix mistake in times.nim docs --- lib/pure/times.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 16d7ff31d..fb2f5e430 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1408,7 +1408,7 @@ proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} '-' & intToStr(dt.monthday, 2) proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = - ## Gets the current local clock time as a string of the format ``HH:MM:SS``. + ## Gets the current local clock time as a string of the format ``HH:mm:ss``. runnableExamples: echo getClockStr(now() - 1.hours) assertDateTimeInitialized dt From 87f6a9592cbbace5e8f0d647841b4490bb7c0f1f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 8 Jul 2020 08:21:55 +0200 Subject: [PATCH 0845/4254] fixes #14402 (#14908) * fixes #14402 * added a test case --- lib/pure/asyncstreams.nim | 2 +- tests/arc/tasyncorc.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/arc/tasyncorc.nim diff --git a/lib/pure/asyncstreams.nim b/lib/pure/asyncstreams.nim index 44e73003e..393262c4f 100644 --- a/lib/pure/asyncstreams.nim +++ b/lib/pure/asyncstreams.nim @@ -96,7 +96,7 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) = if resFut.finished: return # We don't want this callback called again. - future.cb = nil + #future.cb = nil # The return value depends on whether the FutureStream has finished. var res: (bool, T) diff --git a/tests/arc/tasyncorc.nim b/tests/arc/tasyncorc.nim new file mode 100644 index 000000000..56b8909b1 --- /dev/null +++ b/tests/arc/tasyncorc.nim @@ -0,0 +1,26 @@ +discard """ + output: '''230000''' + cmd: '''nim c --gc:orc -d:useMalloc $file''' + valgrind: "true" +""" + +# bug #14402 + +import asynchttpserver, asyncdispatch, httpclient, strutils + +proc cb(req: Request) {.async, gcsafe.} = + const html = " ".repeat(230000) + await req.respond(Http200, html) + +var server = newAsyncHttpServer() +asyncCheck server.serve(Port(8080), cb) + +proc test {.async.} = + var + client = newAsyncHttpClient() + resp = await client.get("http://localhost:8080") + + let x = (await resp.body).len + echo x # crash + +waitFor test() From b17e1efc67a64ce6acd2ddf4f432879f3bf739e2 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Jul 2020 23:10:00 +0200 Subject: [PATCH 0846/4254] progress --- compiler/injectdestructors.nim | 50 ++++++++++++++++++---------- tests/destructor/tmove_objconstr.nim | 2 +- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index bf0206055..e57898ae8 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -91,17 +91,23 @@ proc optimize(s: var Scope) = filterNil(wasMoved) filterNil(final) -proc toTree(s: var Scope; ret: PNode; onlyCareAboutVars = false): PNode = +type + ToTreeFlag = enum + onlyCareAboutVars, + producesValue + +proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = if not s.needsTry: optimize(s) assert ret != nil if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: # trivial, nothing was done: result = ret else: - if isEmptyType(ret.typ): - result = newNodeI(nkStmtList, ret.info) - else: + let isExpr = producesValue in flags and not isEmptyType(ret.typ) + if isExpr: result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) + else: + result = newNodeI(nkStmtList, ret.info) if s.vars.len > 0: let varSection = newNodeI(nkVarSection, ret.info) @@ -109,7 +115,7 @@ proc toTree(s: var Scope; ret: PNode; onlyCareAboutVars = false): PNode = varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), newNodeI(nkEmpty, ret.info)) result.add varSection - if onlyCareAboutVars: + if onlyCareAboutVars in flags: result.add ret s.vars.setLen 0 elif s.needsTry: @@ -117,8 +123,11 @@ proc toTree(s: var Scope; ret: PNode; onlyCareAboutVars = false): PNode = for m in s.wasMoved: finSection.add m for i in countdown(s.final.high, 0): finSection.add s.final[i] result.add newTryFinally(ret, finSection) + elif isExpr: + for m in s.wasMoved: result.add m + for i in countdown(s.final.high, 0): result.add s.final[i] + result.add ret else: - #assert isEmptyType(ret.typ) result.add ret for m in s.wasMoved: result.add m for i in countdown(s.final.high, 0): result.add s.final[i] @@ -593,22 +602,25 @@ proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = elif ri.kind != nkEmpty: res.add moveOrCopy(v, ri, c, s, isDecl = true) -template handleNestedTempl(n: untyped, processCall: untyped) = +template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = template maybeVoid(child, s): untyped = if isEmptyType(child.typ): p(child, c, s, normal) else: processCall(child, s) + let treeFlags = if not isEmptyType(n.typ) and not alwaysStmt: {producesValue} else: {} case n.kind of nkStmtList, nkStmtListExpr: # a statement list does not open a new scope if n.len == 0: return n result = copyNode(n) + if alwaysStmt: result.typ = nil for i in 0..---------transformed-to--------->" echo renderTree(result, {renderIds}) diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 5366f4957..0740bd46b 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -113,7 +113,7 @@ proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] = var cc = newMySeq(y, 5.0) (a: case x: of 1: - let (z1, z2) = myfunc(x,y) + let (z1, z2) = myfunc(x, y) z2 elif x > 5: raise newException(ValueError, "new error") else: newMySeq(x, 1.0), From cdce245a235f3a8c255d0f782bc088546343b6ed Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Jul 2020 23:59:13 +0200 Subject: [PATCH 0847/4254] fixes #14899 --- compiler/injectdestructors.nim | 41 ++++++++++++++++++++++++++++++---- tests/arc/tcontrolflow.nim | 14 ++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index e57898ae8..291cd36aa 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -37,6 +37,9 @@ type final: seq[PNode] # finally section needsTry: bool parent: ptr Scope + escapingSyms: IntSet # a construct like (block: let x = f(); x) + # means that 'x' escapes. We then destroy it + # in the parent's scope (and also allocate it there). proc nestedScope(parent: var Scope): Scope = Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) @@ -400,8 +403,11 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode = checkForErrorPragma(c, t, ri, "=") result = genCopyNoCheck(c, dest, ri) -proc addTopVar(c: var Con; s: var Scope; v: PNode) = - s.vars.add v.sym +proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope = + result = addr(s) + while v.sym.id in result.escapingSyms and result.parent != nil: + result = result.parent + result[].vars.add v.sym proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) @@ -584,9 +590,31 @@ proc cycleCheck(n: PNode; c: var Con) = message(c.graph.config, n.info, warnCycleCreated, msg) break +proc markEscapingVars(n: PNode; s: var Scope) = + case n.kind + of nkSym: + s.escapingSyms.incl n.sym.id + of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref, + nkAddr, nkHiddenAddr, nkStringToCString, nkCStringToString, nkObjDownConv, + nkObjUpConv: + markEscapingVars(n[0], s) + of nkCast, nkHiddenSubConv, nkHiddenStdConv, nkConv: + markEscapingVars(n[1], s) + of nkTupleConstr, nkBracket, nkPar, nkClosure: + for i in 0 ..< n.len: + markEscapingVars(n[i], s) + of nkObjConstr: + for i in 1 ..< n.len: + markEscapingVars(n[i], s) + of nkStmtList, nkStmtListExpr: + if n.len > 0: + markEscapingVars(n[^1], s) + else: + discard "no arbitrary tree traversal here" + proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = # move the variable declaration to the top of the frame: - c.addTopVar s, v + let owningScope = c.addTopVar(s, v) if isUnpackedTuple(v): if c.inLoop > 0: # unpacked tuple needs reset at every loop iteration @@ -596,7 +624,7 @@ proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = if sfGlobal in v.sym.flags and s.parent == nil: c.graph.globalDestructors.add genDestroy(c, v) else: - s.final.add genDestroy(c, v) + owningScope[].final.add genDestroy(c, v) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: @@ -617,6 +645,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = for i in 0.. Date: Wed, 8 Jul 2020 10:03:09 +0200 Subject: [PATCH 0848/4254] fixes #14900 --- compiler/injectdestructors.nim | 80 ++++++++++++++++++---------------- tests/arc/tcontrolflow.nim | 20 +++++++++ 2 files changed, 62 insertions(+), 38 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 291cd36aa..67d61525e 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -41,6 +41,30 @@ type # means that 'x' escapes. We then destroy it # in the parent's scope (and also allocate it there). +type + Con = object + owner: PSym + g: ControlFlowGraph + jumpTargets: IntSet + destroys, topLevelVars: PNode + graph: ModuleGraph + emptyNode: PNode + otherRead: PNode + inLoop, inSpawn: int + uninit: IntSet # set of uninit'ed vars + uninitComputed: bool + + ProcessMode = enum + normal + consumed + sinkArg + +proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) + sym.typ = typ + s.vars.add(sym) + result = newSymNode(sym) + proc nestedScope(parent: var Scope): Scope = Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) @@ -99,7 +123,7 @@ type onlyCareAboutVars, producesValue -proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = +proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = if not s.needsTry: optimize(s) assert ret != nil if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: @@ -107,8 +131,11 @@ proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = result = ret else: let isExpr = producesValue in flags and not isEmptyType(ret.typ) + var r = PNode(nil) if isExpr: result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) + if ret.kind == nkStmtListExpr: + r = getTemp(c, s, ret.typ, ret.info) else: result = newNodeI(nkStmtList, ret.info) @@ -126,32 +153,15 @@ proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = for m in s.wasMoved: finSection.add m for i in countdown(s.final.high, 0): finSection.add s.final[i] result.add newTryFinally(ret, finSection) - elif isExpr: - for m in s.wasMoved: result.add m - for i in countdown(s.final.high, 0): result.add s.final[i] - result.add ret else: - result.add ret + if r != nil: + result.add newTree(nkFastAsgn, r, ret) + else: + result.add ret for m in s.wasMoved: result.add m for i in countdown(s.final.high, 0): result.add s.final[i] - -type - Con = object - owner: PSym - g: ControlFlowGraph - jumpTargets: IntSet - destroys, topLevelVars: PNode - graph: ModuleGraph - emptyNode: PNode - otherRead: PNode - inLoop, inSpawn: int - uninit: IntSet # set of uninit'ed vars - uninitComputed: bool - - ProcessMode = enum - normal - consumed - sinkArg + if r != nil: + result.add r const toDebug {.strdefine.} = "" @@ -409,12 +419,6 @@ proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope = result = result.parent result[].vars.add v.sym -proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = - let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) - sym.typ = typ - s.vars.add(sym) - result = newSymNode(sym) - proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = # discriminator is ordinal value that doesn't need sink destroy # but fields within active case branch might need destruction @@ -661,7 +665,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = var ofScope = nestedScope(s) markEscapingVars(it[^1], ofScope) let ofResult = maybeVoid(it[^1], ofScope) - branch[^1] = toTree(ofScope, ofResult, treeFlags) + branch[^1] = toTree(c, ofScope, ofResult, treeFlags) result.add branch rememberParent(s, ofScope) @@ -671,7 +675,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = result.add p(n[0], c, s, normal) var bodyScope = nestedScope(s) let bodyResult = p(n[1], c, bodyScope, normal) - result.add toTree(bodyScope, bodyResult, treeFlags) + result.add toTree(c, bodyScope, bodyResult, treeFlags) rememberParent(s, bodyScope) dec c.inLoop @@ -682,7 +686,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = var bodyScope = nestedScope(s) markEscapingVars(n[1], bodyScope) let bodyResult = processCall(n[1], bodyScope) - result.add toTree(bodyScope, bodyResult, treeFlags) + result.add toTree(c, bodyScope, bodyResult, treeFlags) rememberParent(s, bodyScope) of nkIfStmt, nkIfExpr: @@ -695,12 +699,12 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = branchScope.parent = nil if it.kind in {nkElifBranch, nkElifExpr}: let cond = p(it[0], c, branchScope, normal) - branch[0] = toTree(branchScope, cond, {producesValue, onlyCareAboutVars}) + branch[0] = toTree(c, branchScope, cond, {producesValue, onlyCareAboutVars}) branchScope.parent = addr(s) markEscapingVars(it[^1], branchScope) var branchResult = processCall(it[^1], branchScope) - branch[^1] = toTree(branchScope, branchResult, treeFlags) + branch[^1] = toTree(c, branchScope, branchResult, treeFlags) result.add branch rememberParent(s, branchScope) @@ -710,7 +714,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = var tryScope = nestedScope(s) markEscapingVars(n[0], tryScope) var tryResult = maybeVoid(n[0], tryScope) - result.add toTree(tryScope, tryResult, treeFlags) + result.add toTree(c, tryScope, tryResult, treeFlags) rememberParent(s, tryScope) for i in 1..---------transformed-to--------->" echo renderTree(result, {renderIds}) diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim index b53344139..27ae45257 100644 --- a/tests/arc/tcontrolflow.nim +++ b/tests/arc/tcontrolflow.nim @@ -12,6 +12,7 @@ if end true 7 ##index 2 not in 0 .. 1## +true ''' cmd: "nim c --gc:arc -d:danger $file" """ @@ -102,3 +103,22 @@ proc escapeCheck = clItems(toSeq()) escapeCheck() + +# bug #14900 +template sortedByIt(seq1): untyped = + var result = seq1 + result + +proc seqsEqual(seq1, seq2: seq[string]): bool = + # works as a normal proc (if we would assign result inside) + # doesn't work as an expression + result = if false: # needed + false + else: + let a1 = seq1.sortedByIt() + let a2 = seq2.sortedByIt() + # echo a1 - works if you uncomment any of these + # echo a2 + a1 == a2 + +echo seqsEqual(@["a", "b", "c"], @["a", "b", "c"]) From e42ce877a6469ccc6eb99e1e0f6162aeb6839193 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Jul 2020 10:45:51 +0200 Subject: [PATCH 0849/4254] fixes #14805 --- compiler/ccgtypes.nim | 2 +- tests/lent/tlent_from_var.nim | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/lent/tlent_from_var.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 11743499d..fb205110e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -279,7 +279,7 @@ proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = result = false # first parameter and return type is 'lent T'? --> use pass by pointer if s.position == 0 and retType != nil and retType.kind == tyLent: - result = true + result = pt.kind != tyVar proc fillResult(conf: ConfigRef; param: PNode) = fillLoc(param.sym.loc, locParam, param, ~"Result", diff --git a/tests/lent/tlent_from_var.nim b/tests/lent/tlent_from_var.nim new file mode 100644 index 000000000..c8a15b1a1 --- /dev/null +++ b/tests/lent/tlent_from_var.nim @@ -0,0 +1,14 @@ +discard """ + output: "x" +""" + +# bug #14805 + +type Foo = object + a: string + +proc bar(f: var Foo): lent string = + result = f.a + +var foo = Foo(a: "x") +echo bar(foo) From cb1ecbf95620bffd559610b70f99c6f16963ac5c Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Jul 2020 10:51:26 +0200 Subject: [PATCH 0850/4254] closes #14878 --- tests/lent/tlent_from_var.nim | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/lent/tlent_from_var.nim b/tests/lent/tlent_from_var.nim index c8a15b1a1..912390dc1 100644 --- a/tests/lent/tlent_from_var.nim +++ b/tests/lent/tlent_from_var.nim @@ -1,5 +1,6 @@ discard """ - output: "x" + output: '''x +[10, 11, 12, 13]''' """ # bug #14805 @@ -12,3 +13,20 @@ proc bar(f: var Foo): lent string = var foo = Foo(a: "x") echo bar(foo) + + +# bug #14878 + +# proc byLentImpl[T](a: T): lent T = a +proc byLentVar[T](a: var T): lent T = + result = a + # result = a.byLentImpl # this doesn't help + +var x = 3 # error: cannot take the address of an rvalue of type 'NI *' + +var xs = [10,11,12,13] # SIGSEGV + +let x2 = x.byLentVar + +let xs2 = xs.byLentVar +echo xs2 From 06d776a5828d429f62c3189a99161604d50f9b96 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 8 Jul 2020 14:47:14 +0200 Subject: [PATCH 0851/4254] fixes #14900, this time for real, maybe (#14934) --- compiler/injectdestructors.nim | 10 ++++++++-- tests/arc/tcontrolflow.nim | 24 +++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 67d61525e..b5e1db169 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -134,7 +134,7 @@ proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode var r = PNode(nil) if isExpr: result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) - if ret.kind == nkStmtListExpr: + if ret.kind in nkCallKinds + {nkStmtListExpr}: r = getTemp(c, s, ret.typ, ret.info) else: result = newNodeI(nkStmtList, ret.info) @@ -155,7 +155,13 @@ proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode result.add newTryFinally(ret, finSection) else: if r != nil: - result.add newTree(nkFastAsgn, r, ret) + if ret.kind == nkStmtListExpr: + # simplify it a bit further by merging the nkStmtListExprs + let last = ret.len - 1 + for i in 0 ..< last: result.add ret[i] + result.add newTree(nkFastAsgn, r, ret[last]) + else: + result.add newTree(nkFastAsgn, r, ret) else: result.add ret for m in s.wasMoved: result.add m diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim index 27ae45257..41f614cb2 100644 --- a/tests/arc/tcontrolflow.nim +++ b/tests/arc/tcontrolflow.nim @@ -105,20 +105,14 @@ proc escapeCheck = escapeCheck() # bug #14900 -template sortedByIt(seq1): untyped = - var result = seq1 - result -proc seqsEqual(seq1, seq2: seq[string]): bool = - # works as a normal proc (if we would assign result inside) - # doesn't work as an expression - result = if false: # needed - false - else: - let a1 = seq1.sortedByIt() - let a2 = seq2.sortedByIt() - # echo a1 - works if you uncomment any of these - # echo a2 - a1 == a2 +proc seqsEqual(a, b: string): bool = + if false: + false + else: + (var result1 = a; result1) == (var result2 = b; result2) -echo seqsEqual(@["a", "b", "c"], @["a", "b", "c"]) +# can be const or var too +let expected = "hello" + +echo seqsEqual(expected, expected) From 3de5296337a0711b4d907728ac24fa07791d3224 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 8 Jul 2020 15:01:47 +0200 Subject: [PATCH 0852/4254] remove a condition that table size must be passed as power of 2 (#14926) * remove a condition that table size must be passed as power of 2 * remove power-of-2 condition from sets and sharedtables * remove power-of-2 condition from deques * use 'correctSize' for both branches * prettify changelog.md and fix typos * add a changelog entry * fix double-call of 'right-size' * fix the same thing in sets.nim * introduce a new internal proc `slotsNeeded` Deprecate the public proc `rightSize`, which is not needed anymore. Now it is an identity function, allowing the old code to work correctly and without extra allocations. --- changelog.md | 69 ++++++++++++------- lib/pure/collections/deques.nim | 11 +-- lib/pure/collections/hashcommon.nim | 14 ++-- lib/pure/collections/setimpl.nim | 4 +- lib/pure/collections/sets.nim | 30 +------- lib/pure/collections/sharedtables.nim | 8 +-- lib/pure/collections/tableimpl.nim | 6 +- lib/pure/collections/tables.nim | 48 ++----------- tests/collections/ttables.nim | 10 +++ .../argument_parser/argument_parser.nim | 3 +- 10 files changed, 83 insertions(+), 120 deletions(-) diff --git a/changelog.md b/changelog.md index efad01515..1eda82297 100644 --- a/changelog.md +++ b/changelog.md @@ -5,7 +5,7 @@ ## Standard library additions and changes - Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. -- Add `tryInsert`,`insert` procs to db_* libs accept primary key column name. +- Add `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. - Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. - `uri` adds Data URI Base64, implements RFC-2397. - Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) @@ -24,7 +24,7 @@ ease the writing of multi-process servers, where sockets inheritance is desired. - For a transistion period, define `nimInheritHandles` to enable file handle + For a transition period, define `nimInheritHandles` to enable file handle inheritance by default. This flag does **not** affect the `selectors` module due to the differing semantics between operating systems. @@ -83,11 +83,14 @@ proc foo(x: int, y: int): auto {.noSideEffect.} = x + y ``` + - The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters. -- The `times` module now handles the default value for `DateTime` more consistently. Most procs raise an assertion error when given - an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). The proc `times.isInitialized` - has been added which can be used to check if a `DateTime` has been initialized. +- The `times` module now handles the default value for `DateTime` more consistently. + Most procs raise an assertion error when given + an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). + The proc `times.isInitialized` has been added which can be used to check if + a `DateTime` has been initialized. - Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to hangs if a process had both reads from stdin and writes (eg to stdout). @@ -105,14 +108,17 @@ ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) per Mozilla's recommendation instead of `ALL`. This change should protect users from the use of weak and insecure ciphers while still provides - adequate compatiblity with the majority of the Internet. + adequate compatibility with the majority of the Internet. -- new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json serialization/deserialization of custom types. +- new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json + serialization/deserialization of custom types. - new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. -- Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` with `outLatex` output. -- Add `os.normalizeExe`, eg: `koch` => `./koch`. -- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior +- Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` + with `outLatex` output. +- Add `os.normalizeExe`, e.g.: `koch` => `./koch`. +- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` + to keep old behavior. - Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. - Add `typetraits.elementType` to get element type of an iterable. - `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; @@ -120,14 +126,20 @@ `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` - add `macros.extractDocCommentsAndRunnables` helper -- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. +- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now + expands to `fmt"expr={expr}"`. - deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` - Add `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) - Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, - because negative values will result in a new file being created for each logged line which doesn't make sense. + because negative values will result in a new file being created for each logged + line which doesn't make sense. - Changed `log` in `logging` to use proper log level on JavaScript target, - eg. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. + e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. +- Tables, HashSets, SharedTables and deques don't require anymore that the passed + initial size must be a power of two - this is done internally. + Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. + ## Language changes @@ -165,7 +177,7 @@ x.val = nil ``` - `getImpl` on enum type symbols now returns field syms instead of idents. This helps - with writing typed macros. Old behavior for backwards compatiblity can be restored + with writing typed macros. Old behavior for backwards compatibility can be restored with command line switch `--useVersion:1.0`. - ``let`` statements can now be used without a value if declared with ``importc``/``importcpp``/``importjs``/``importobjc``. @@ -223,24 +235,29 @@ proc mydiv(a, b): int {.raises: [].} = (likewise with other hints and warnings), which is consistent with all other bool flags. (since 1.3.3). - `nim doc -r main` and `nim rst2html -r main` now call openDefaultBrowser -- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) was generated; this - helps in particular when it's non obvious where it came from either because multiple locations generate - the same message, or because the message involves runtime formatting. -- new flag `--backend:js|c|cpp|objc (or -b:js etc), to change backend; can be used with any command - (eg nim r, doc, check etc); safe to re-assign. -- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, eg: `--doccmd:-d:foo --threads` +- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) + was generated; this helps in particular when it's non obvious where it came from + either because multiple locations generate the same message, or because the + message involves runtime formatting. +- new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change backend; can be + used with any command (eg nim r, doc, check etc); safe to re-assign. +- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, + e.g.: `--doccmd:-d:foo --threads` use `--doccmd:skip` to skip runnableExamples and rst test snippets. -- new flag `--usenimcache` to output to nimcache (whatever it resolves to after all commands are processed) +- new flag `--usenimcache` to output to nimcache (whatever it resolves to after + all commands are processed) and avoids polluting both $pwd and $projectdir. It can be used with any command. -- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override how an example is compiled and run, - for example to change backend or compile only. -- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified (with or without `--project`); - passing `--project` now automatically generates an index and enables search. +- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override + how an example is compiled and run, for example to change backend or compile only. +- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified + (with or without `--project`); passing `--project` now automatically generates + an index and enables search. See [docgen](docgen.html#introduction-quick-start) for details. - Removed the `--oldNewlines` switch. - Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. - Removed the `--oldast` switch. -- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is now "typed" instead of "stmt" +- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is + now "typed" instead of "stmt". ## Tool changes diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index d096874a3..8150563cc 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -67,9 +67,9 @@ const defaultInitialSize* = 4 template initImpl(result: typed, initialSize: int) = - assert isPowerOfTwo(initialSize) - result.mask = initialSize-1 - newSeq(result.data, initialSize) + let correctSize = nextPowerOfTwo(initialSize) + result.mask = correctSize-1 + newSeq(result.data, correctSize) template checkIfInitialized(deq: typed) = when compiles(defaultInitialSize): @@ -82,11 +82,6 @@ proc initDeque*[T](initialSize: int = 4): Deque[T] = ## Optionally, the initial capacity can be reserved via `initialSize` ## as a performance optimization. ## The length of a newly created deque will still be 0. - ## - ## ``initialSize`` must be a power of two (default: 4). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_. result.initImpl(initialSize) proc len*[T](deq: Deque[T]): int {.inline.} = diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index e998145e7..336dbc07d 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -30,17 +30,23 @@ proc nextTry(h, maxHash: Hash): Hash {.inline.} = result = (h + 1) and maxHash proc mustRehash[T](t: T): bool {.inline.} = + # If this is changed, make sure to synchronize it with `slotsNeeded` below assert(t.dataLen > t.counter) result = (t.dataLen * 2 < t.counter * 3) or (t.dataLen - t.counter < 4) -proc rightSize*(count: Natural): int {.inline.} = +proc slotsNeeded(count: Natural): int {.inline.} = + # Make sure to synchronize with `mustRehash` above + result = nextPowerOfTwo(count * 3 div 2 + 4) + +proc rightSize*(count: Natural): int {.inline, deprecated: "Deprecated since 1.4.0".} = + ## **Deprecated since Nim v1.4.0**, it is not needed anymore + ## because picking the correct size is done internally. + ## ## Return the value of ``initialSize`` to support ``count`` items. ## ## If more items are expected to be added, simply add that ## expected extra amount to the parameter before calling this. - # - # Make sure to synchronize with `mustRehash` - result = nextPowerOfTwo(count * 3 div 2 + 4) + result = count template rawGetKnownHCImpl() {.dirty.} = if t.dataLen == 0: diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index d798cbcb3..20da6b6c2 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -16,12 +16,12 @@ template dataLen(t): untyped = len(t.data) include hashcommon template initImpl(s: typed, size: int) = - assert isPowerOfTwo(size) + let correctSize = slotsNeeded(size) when s is OrderedSet: s.first = -1 s.last = -1 s.counter = 0 - newSeq(s.data, size) + newSeq(s.data, correctSize) template rawInsertImpl() {.dirty.} = if data.len == 0: diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 2b270c2cb..b019da2a7 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -94,11 +94,6 @@ include setimpl proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) = ## Initializes a hash set. ## - ## The `initialSize` parameter needs to be a power of two (default: 64). - ## If you need to accept runtime values for this, you can use - ## `math.nextPowerOfTwo proc `_ or - ## `rightSize proc <#rightSize,Natural>`_ from this module. - ## ## Starting from Nim v0.20, sets are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -222,7 +217,7 @@ proc toHashSet*[A](keys: openArray[A]): HashSet[A] = assert len(b) == 5 ## b == {'a', 'b', 'c', 'd', 'r'} - result = initHashSet[A](rightSize(keys.len)) + result = initHashSet[A](keys.len) for key in items(keys): result.incl(key) iterator items*[A](s: HashSet[A]): A = @@ -628,11 +623,6 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) = ## Initializes an ordered hash set. ## - ## The `initialSize` parameter needs to be a power of two (default: 64). - ## If you need to accept runtime values for this, you can use - ## `math.nextPowerOfTwo proc `_ or - ## `rightSize proc <#rightSize,Natural>`_ from this module. - ## ## Starting from Nim v0.20, sets are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -685,7 +675,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = assert len(b) == 5 ## b == {'a', 'b', 'r', 'c', 'd'} # different than in HashSet - result = initOrderedSet[A](rightSize(keys.len)) + result = initOrderedSet[A](keys.len) for key in items(keys): result.incl(key) proc contains*[A](s: OrderedSet[A], key: A): bool = @@ -980,7 +970,7 @@ when isMainModule and not defined(release): block toSeqAndString: var a = toHashSet([2, 7, 5]) - var b = initHashSet[int](rightSize(a.len)) + var b = initHashSet[int](a.len) for x in [2, 7, 5]: b.incl(x) assert($a == $b) #echo a @@ -1098,20 +1088,6 @@ when isMainModule and not defined(release): b.incl(2) assert b.len == 1 - block: - type FakeTable = object - dataLen: int - counter: int - countDeleted: int - - var t: FakeTable - for i in 0 .. 32: - var s = rightSize(i) - t.dataLen = s - t.counter = i - doAssert s > i and not mustRehash(t), - "performance issue: rightSize() will not elide enlarge() at: " & $i - block missingOrExcl: var s = toOrderedSet([2, 3, 6, 7]) assert s.missingOrExcl(4) == true diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index abef89507..cbd922db7 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -207,15 +207,11 @@ proc len*[A, B](t: var SharedTable[A, B]): int = withLock t: result = t.counter -proc init*[A, B](t: var SharedTable[A, B], initialSize = 64) = +proc init*[A, B](t: var SharedTable[A, B], initialSize = 32) = ## creates a new hash table that is empty. ## ## This proc must be called before any other usage of `t`. - ## - ## `initialSize` needs to be a power of two. If you need to accept runtime - ## values for this you could use the ``nextPowerOfTwo`` proc from the - ## `math `_ module or the ``rightSize`` proc from this module. - assert isPowerOfTwo(initialSize) + let initialSize = slotsNeeded(initialSize) t.counter = 0 t.dataLen = initialSize t.data = cast[KeyValuePairSeq[A, B]](allocShared0( diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 47c14af93..b9d7c70d9 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -121,12 +121,12 @@ template ctAnd(a, b): bool = else: false template initImpl(result: typed, size: int) = + let correctSize = slotsNeeded(size) when ctAnd(declared(SharedTable), type(result) is SharedTable): - init(result, size) + init(result, correctSize) else: - assert isPowerOfTwo(size) result.counter = 0 - newSeq(result.data, size) + newSeq(result.data, correctSize) when compiles(result.first): result.first = -1 result.last = -1 diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index a969a4c5d..cf864c640 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -239,7 +239,7 @@ type ## <#newTable,int>`_. const - defaultInitialSize* = 64 + defaultInitialSize* = 32 # ------------------------------ helpers --------------------------------- @@ -288,12 +288,6 @@ proc enlarge[A, B](t: var Table[A, B]) = proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] = ## Creates a new hash table that is empty. ## - ## ``initialSize`` must be a power of two (default: 64). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ - ## from this module. - ## ## Starting from Nim v0.20, tables are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -335,7 +329,7 @@ proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] = let b = toTable(a) assert b == {'a': 5, 'b': 9}.toTable - result = initTable[A, B](rightSize(pairs.len)) + result = initTable[A, B](pairs.len) for key, val in items(pairs): result[key] = val proc `[]`*[A, B](t: Table[A, B], key: A): B = @@ -780,12 +774,6 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B = proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = ## Creates a new ref hash table that is empty. ## - ## ``initialSize`` must be a power of two (default: 64). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ - ## from this module. - ## ## See also: ## * `newTable proc<#newTable,openArray[]>`_ for creating a `TableRef` ## from a collection of `(key, value)` pairs @@ -1260,12 +1248,6 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A, B] = ## Creates a new ordered hash table that is empty. ## - ## ``initialSize`` must be a power of two (default: 64). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ - ## from this module. - ## ## Starting from Nim v0.20, tables are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -1309,7 +1291,7 @@ proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] = let b = toOrderedTable(a) assert b == {'a': 5, 'b': 9}.toOrderedTable - result = initOrderedTable[A, B](rightSize(pairs.len)) + result = initOrderedTable[A, B](pairs.len) for key, val in items(pairs): result[key] = val proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = @@ -1771,12 +1753,6 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableRef[A, B] = ## Creates a new ordered ref hash table that is empty. ## - ## ``initialSize`` must be a power of two (default: 64). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ - ## from this module. - ## ## See also: ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for creating ## an `OrderedTableRef` from a collection of `(key, value)` pairs @@ -1803,7 +1779,7 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] let b = newOrderedTable(a) assert b == {'a': 5, 'b': 9}.newOrderedTable - result = newOrderedTable[A, B](rightSize(pairs.len)) + result = newOrderedTable[A, B](pairs.len) for key, val in items(pairs): result.add(key, val) @@ -2251,12 +2227,6 @@ proc inc*[A](t: var CountTable[A], key: A, val: Positive = 1) proc initCountTable*[A](initialSize = defaultInitialSize): CountTable[A] = ## Creates a new count table that is empty. ## - ## ``initialSize`` must be a power of two (default: 64). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ - ## from this module. - ## ## Starting from Nim v0.20, tables are initialized by default and it is ## not necessary to call this function explicitly. ## @@ -2269,7 +2239,7 @@ proc initCountTable*[A](initialSize = defaultInitialSize): CountTable[A] = proc toCountTable*[A](keys: openArray[A]): CountTable[A] = ## Creates a new count table with every member of a container ``keys`` ## having a count of how many times it occurs in that container. - result = initCountTable[A](rightSize(keys.len)) + result = initCountTable[A](keys.len) for key in items(keys): result.inc(key) proc `[]`*[A](t: CountTable[A], key: A): int = @@ -2617,12 +2587,6 @@ proc inc*[A](t: CountTableRef[A], key: A, val = 1) proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = ## Creates a new ref count table that is empty. ## - ## ``initialSize`` must be a power of two (default: 64). - ## If you need to accept runtime values for this you could use the - ## `nextPowerOfTwo proc`_ from the - ## `math module`_ or the `rightSize proc<#rightSize,Natural>`_ - ## from this module. - ## ## See also: ## * `newCountTable proc<#newCountTable,openArray[A]>`_ for creating ## a `CountTableRef` from a collection @@ -2634,7 +2598,7 @@ proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = ## Creates a new ref count table with every member of a container ``keys`` ## having a count of how many times it occurs in that container. - result = newCountTable[A](rightSize(keys.len)) + result = newCountTable[A](keys.len) for key in items(keys): result.inc(key) proc `[]`*[A](t: CountTableRef[A], key: A): int = diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 392b5e93e..af8364488 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -446,3 +446,13 @@ block: # https://github.com/nim-lang/Nim/issues/13496 testDel(): (let t = newOrderedTable[int, int]()) testDel(): (var t: CountTable[int]) testDel(): (let t = newCountTable[int]()) + + +block testNonPowerOf2: + var a = initTable[int, int](7) + a[1] = 10 + assert a[1] == 10 + + var b = initTable[int, int](9) + b[1] = 10 + assert b[1] == 10 diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 136d3e06b..b9788a81d 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -301,8 +301,7 @@ template build_specification_lookup(): OrderedTable[string, ptr Tparameter_specification] = ## Returns the table used to keep pointers to all of the specifications. var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification] - result = initOrderedTable[string, ptr Tparameter_specification]( - tables.rightSize(expected.len)) + result = initOrderedTable[string, ptr Tparameter_specification](expected.len) for i in 0..expected.len-1: for param_to_detect in expected[i].names: if result.hasKey(param_to_detect): From 27579cfd3a473c1b449c6c62997107005f8d4c90 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 8 Jul 2020 16:20:16 +0200 Subject: [PATCH 0853/4254] Make arc compile laser again --- compiler/injectdestructors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b5e1db169..0a14a1daf 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1006,7 +1006,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[0] = p(n[0], c, s, mode) for i in 1.. Date: Wed, 8 Jul 2020 18:59:34 +0200 Subject: [PATCH 0854/4254] fixes #14865 (#14937) --- compiler/ccgthreadvars.nim | 1 + compiler/ccgtypes.nim | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 8bf5e573f..eba46f829 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -42,6 +42,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) = proc generateThreadLocalStorage(m: BModule) = if m.g.nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags): for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t) + finishTypeDescriptions(m) m.s[cfsSeqTypes].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv]) proc generateThreadVarsSize(m: BModule) = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fb205110e..f1dc85818 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -944,6 +944,7 @@ proc finishTypeDescriptions(m: BModule) = else: discard getTypeDescAux(m, t, check) inc(i) + m.typeStack.setLen 0 template cgDeclFrmt*(s: PSym): string = s.constraint.strVal From 9016dd96ee1ab6d3a60925cee4ee815dd8627f1e Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 8 Jul 2020 22:04:21 +0200 Subject: [PATCH 0855/4254] Add testcase for #12129 (#14940) * Add testcase for #12129 * Fix test --- tests/macros/tmacros_issues.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index df385c445..23c9c66c0 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -19,6 +19,8 @@ nil 42 false true +@[i0, i1, i2, i3, i4] +@[tmp, tmp, tmp, tmp, tmp] ''' output: ''' @@ -244,3 +246,15 @@ macro toRendererBug(n): untyped = result = newLit repr(n) echo toRendererBug(0o377'i8) + +# bug #12129 +macro foobar() = + var loopVars = newSeq[NimNode](5) + for i, sym in loopVars.mpairs(): + sym = ident("i" & $i) + echo loopVars + for sym in loopVars.mitems(): + sym = ident("tmp") + echo loopVars + +foobar() From 3db6d9ea0c96782955923be4a24f49c1b2cc06fc Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 9 Jul 2020 04:21:30 +0800 Subject: [PATCH 0856/4254] add docs and more tests for debug format strings (#14861) * add debug format string * remove try except * add changelog * add docs and more tests * Update lib/pure/strformat.nim Co-authored-by: Juan Carlos * minor Co-authored-by: Juan Carlos --- lib/pure/strformat.nim | 47 +++++++++++++++++++++++- tests/stdlib/tstrformat.nim | 73 +++++++++++++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 0ea784a43..c37b6b1c0 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -63,7 +63,6 @@ Formatting floats .. code-block:: nim import strformat - doAssert fmt"{-12345:08}" == "-0012345" doAssert fmt"{-1:3}" == " -1" doAssert fmt"{-1:03}" == "-01" @@ -81,6 +80,52 @@ Formatting floats doAssert fmt"{123.456:13e}" == " 1.234560e+02" +Debugging strings +================= + +``fmt"{expr=}"`` expands to ``fmt"expr={expr}"`` namely the text of the expression, +an equal sign and the results of evaluated expression. + +.. code-block:: nim + + import strformat + doAssert fmt"{123.456=}" == "123.456=123.456" + doAssert fmt"{123.456=:>9.3f}" == "123.456= 123.456" + + let x = "hello" + doAssert fmt"{x=}" == "x=hello" + doAssert fmt"{x =}" == "x =hello" + + let y = 3.1415926 + doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}" + doAssert fmt"{y=}" == fmt"y={y}" + doAssert fmt"{y = : <8}" == fmt"y = 3.14159 " + + proc hello(a: string, b: float): int = 12 + let a = "hello" + let b = 3.1415926 + doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12" + doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12" + doAssert fmt"{hello x, y = }" == "hello x, y = 12" + + +Note that it is space sensitive: + +.. code-block:: nim + + import strformat + let x = "12" + doAssert fmt"{x=}" == "x=12" + doAssert fmt"{x =:}" == "x =12" + doAssert fmt"{x =}" == "x =12" + doAssert fmt"{x= :}" == "x= 12" + doAssert fmt"{x= }" == "x= 12" + doAssert fmt"{x = :}" == "x = 12" + doAssert fmt"{x = }" == "x = 12" + doAssert fmt"{x = :}" == "x = 12" + doAssert fmt"{x = }" == "x = 12" + + Implementation details ====================== diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index c65165946..b1f3340a4 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -30,6 +30,10 @@ var o: Obj doAssert fmt"{o}" == "foobar" doAssert fmt"{o:10}" == "foobar " +doAssert fmt"{o=}" == "o=foobar" +doAssert fmt"{o=:10}" == "o=foobar " + + # see issue #7933 var str = "abc" doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 :: a" @@ -47,15 +51,39 @@ doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: ab " doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: abc " doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: abc " doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: " + +doAssert fmt">7.1 :: {str=:>7.1}" == ">7.1 :: str= a" +doAssert fmt">7.2 :: {str=:>7.2}" == ">7.2 :: str= ab" +doAssert fmt">7.3 :: {str=:>7.3}" == ">7.3 :: str= abc" +doAssert fmt">7.9 :: {str=:>7.9}" == ">7.9 :: str= abc" +doAssert fmt">7.0 :: {str=:>7.0}" == ">7.0 :: str= " +doAssert fmt" 7.1 :: {str=:7.1}" == " 7.1 :: str=a " +doAssert fmt" 7.2 :: {str=:7.2}" == " 7.2 :: str=ab " +doAssert fmt" 7.3 :: {str=:7.3}" == " 7.3 :: str=abc " +doAssert fmt" 7.9 :: {str=:7.9}" == " 7.9 :: str=abc " +doAssert fmt" 7.0 :: {str=:7.0}" == " 7.0 :: str= " +doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str= a " +doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str= ab " +doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str= abc " +doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str= abc " +doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str= " str = "äöüe\u0309\u0319o\u0307\u0359" doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 :: ä " doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 :: äö " doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 :: äöü " doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 :: " + +doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str= ä " +doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str= äö " +doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str= äöü " +doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str= " # this is actually wrong, but the unicode module has no support for graphemes doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 :: äöüe " doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359" +doAssert fmt"^7.4 :: {str=:^7.4}" == "^7.4 :: str= äöüe " +doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=äöüe\u0309\u0319o\u0307\u0359" + # see issue #7932 doAssert fmt"{15:08}" == "00000015" # int, works doAssert fmt"{1.5:08}" == "000001.5" # float, works @@ -65,6 +93,14 @@ doAssert fmt"{-1.5:08}" == "-00001.5" # works doAssert fmt"{1.5:+08}" == "+00001.5" # works doAssert fmt"{1.5: 08}" == " 00001.5" # works +doAssert fmt"{15=:08}" == "15=00000015" # int, works +doAssert fmt"{1.5=:08}" == "1.5=000001.5" # float, works +doAssert fmt"{1.5=:0>8}" == "1.5=000001.5" # workaround using fill char works for positive floats +doAssert fmt"{-1.5=:0>8}" == "-1.5=0000-1.5" # even that does not work for negative floats +doAssert fmt"{-1.5=:08}" == "-1.5=-00001.5" # works +doAssert fmt"{1.5=:+08}" == "1.5=+00001.5" # works +doAssert fmt"{1.5=: 08}" == "1.5= 00001.5" # works + # only add explicitly requested sign if value != -0.0 (neg zero) doAssert fmt"{-0.0:g}" == "-0" doAssert fmt"{-0.0:+g}" == "-0" @@ -73,6 +109,13 @@ doAssert fmt"{0.0:g}" == "0" doAssert fmt"{0.0:+g}" == "+0" doAssert fmt"{0.0: g}" == " 0" +doAssert fmt"{-0.0=:g}" == "-0.0=-0" +doAssert fmt"{-0.0=:+g}" == "-0.0=-0" +doAssert fmt"{-0.0=: g}" == "-0.0=-0" +doAssert fmt"{0.0=:g}" == "0.0=0" +doAssert fmt"{0.0=:+g}" == "0.0=+0" +doAssert fmt"{0.0=: g}" == "0.0= 0" + # seq format let data1 = [1'i64, 10000'i64, 10000000'i64] @@ -88,6 +131,7 @@ proc formatValue(result: var string; value: (array|seq|openArray); specifier: st doAssert fmt"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #" doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] =" + doAssert fmt"data1: {data1=:8} #" == "data1: data1=[ 1, 10000, 10000000] #" doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000, 100, 1] =" @@ -160,6 +204,9 @@ proc my_proc = const a = &"{value}" assert a == value + const b = &"{value=}" + assert b == "value=" & value + my_proc() block: @@ -262,6 +309,7 @@ block: doAssert &"name: {name =}\nage: { age =: >7}\nhobby: { hobby= : 8}" == "name: name =hello\nage: age = 21\nhobby: hobby= swim " doAssert fmt"{age == 12}" == "false" + doAssert fmt"{name.toUpperAscii() = }" == "name.toUpperAscii() = HELLO" doAssert fmt"{name.toUpperAscii( ) = }" == "name.toUpperAscii( ) = HELLO" doAssert fmt"{ toUpperAscii( s = name ) = }" == " toUpperAscii( s = name ) = HELLO" doAssert fmt"{ strutils.toUpperAscii( s = name ) = }" == " strutils.toUpperAscii( s = name ) = HELLO" @@ -276,16 +324,30 @@ block: doAssert fmt"{0==1}" == "false" +# It is space sensitive. +block: + let x = "12" + doAssert fmt"{x=:}" == "x=12" + doAssert fmt"{x=}" == "x=12" + doAssert fmt"{x =:}" == "x =12" + doAssert fmt"{x =}" == "x =12" + doAssert fmt"{x= :}" == "x= 12" + doAssert fmt"{x= }" == "x= 12" + doAssert fmt"{x = :}" == "x = 12" + doAssert fmt"{x = }" == "x = 12" + doAssert fmt"{x = :}" == "x = 12" + doAssert fmt"{x = }" == "x = 12" + block: let x = "hello" - doAssert fmt"{x=}" == "x=" & $x - doAssert fmt"{x =}" == "x =" & $x + doAssert fmt"{x=}" == "x=hello" + doAssert fmt"{x =}" == "x =hello" let y = 3.1415926 doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}" doAssert fmt"{y=}" == fmt"y={y}" - doAssert fmt"{y =: <16}" == fmt"y ={y: <16}" + doAssert fmt"{y = : <8}" == fmt"y = 3.14159 " proc hello(a: string, b: float): int = 12 template foo(a: string, b: float): int = 18 @@ -295,6 +357,11 @@ block: doAssert fmt"{hello(x, y)= }" == "hello(x, y)= 12" doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12" + doAssert fmt"{hello x, y=}" == "hello x, y=12" + doAssert fmt"{hello x, y =}" == "hello x, y =12" + doAssert fmt"{hello x, y= }" == "hello x, y= 12" + doAssert fmt"{hello x, y = }" == "hello x, y = 12" + doAssert fmt"{x.hello(y)=}" == "x.hello(y)=12" doAssert fmt"{x.hello(y) =}" == "x.hello(y) =12" doAssert fmt"{x.hello(y)= }" == "x.hello(y)= 12" From 00528cbc3c82ba33e8b9b551d5d86b1b6382c34a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 9 Jul 2020 07:51:18 +0800 Subject: [PATCH 0857/4254] Add testcase for #10465 (#14943) * add debug format string * remove try except * add changelog * add docs and more tests * Update lib/pure/strformat.nim Co-authored-by: Juan Carlos * minor * add testcase Co-authored-by: Juan Carlos --- tests/constr/tconexpr.nim | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/constr/tconexpr.nim diff --git a/tests/constr/tconexpr.nim b/tests/constr/tconexpr.nim new file mode 100644 index 000000000..cca6dd84f --- /dev/null +++ b/tests/constr/tconexpr.nim @@ -0,0 +1,43 @@ +discard """ + nimout: ''' +Fibonacci sequence: 0, 1, 1, 2, 3 +Sequence continues: 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 +''' +""" + + +import strformat + +var fib_n {.compileTime.}: int +var fib_prev {.compileTime.}: int +var fib_prev_prev {.compileTime.}: int + +proc next_fib(): int {.compileTime.} = + let fib = if fib_n < 2: + fib_n + else: + fib_prev_prev + fib_prev + inc(fib_n) + fib_prev_prev = fib_prev + fib_prev = fib + fib + +const f0 = next_fib() +const f1 = next_fib() +const f2 = next_fib() +const f3 = next_fib() +const f4 = next_fib() + +static: + echo fmt"Fibonacci sequence: {f0}, {f1}, {f2}, {f3}, {f4}" + +const fib_continues = block: + var result = fmt"Sequence continues: " + for i in 0..10: + if i > 0: + add(result, ", ") + add(result, $next_fib()) + result + +static: + echo fib_continues \ No newline at end of file From 399b2e3134751432f66a2414fbaf9c2a168fa953 Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 9 Jul 2020 00:18:27 -0700 Subject: [PATCH 0858/4254] Add missing dom.nim things (#14944) --- lib/js/dom.nim | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 09e45c04d..575ec3deb 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -106,7 +106,17 @@ type memory*: PerformanceMemory timing*: PerformanceTiming - Selection* {.importc.} = ref object ## see `docs`_ + Range* {.importc.} = ref object + ## see `docs{https://developer.mozilla.org/en-US/docs/Web/API/Range}`_ + collapsed*: bool + commonAncestorContainer*: Node + endContainer*: Node + endOffset*: int + startContainer*: Node + startOffset*: int + + Selection* {.importc.} = ref object + ## see `docs`_ anchorNode*: Node anchorOffset*: int focusNode*: Node @@ -210,6 +220,7 @@ type applets*: seq[Element] embeds*: seq[EmbedElement] links*: seq[LinkElement] + fonts*: FontFaceSet Element* = ref ElementObj ElementObj {.importc.} = object of NodeObj @@ -1189,6 +1200,10 @@ type ## see `docs`_ dataTransfer*: DataTransfer + ClipboardEvent* {.importc.} = object of Event + ## see `docs`_ + clipboardData*: DataTransfer + TouchList* {.importc.} = ref object of RootObj length*: int @@ -1268,6 +1283,15 @@ type once*: bool passive*: bool + FontFaceSetReady* {.importc.} = ref object + ## see: `docs`_ + then*: proc(cb: proc()) + + FontFaceSet* {.importc.} = ref object + ## see: `docs`_ + ready*: FontFaceSetReady + onloadingdone*: proc(event: Event) + since (1, 3): type DomParser* = ref object @@ -1393,6 +1417,7 @@ else: proc getElementById*(id: cstring): Element {.importc: "document.getElementById", nodecl.} proc appendChild*(n, child: Node) {.importcpp.} proc removeChild*(n, child: Node) {.importcpp.} + proc remove*(child: Node) {.importcpp.} proc replaceChild*(n, newNode, oldNode: Node) {.importcpp.} proc insertBefore*(n, newNode, before: Node) {.importcpp.} proc getElementById*(d: Document, id: cstring): Element {.importcpp.} @@ -1454,7 +1479,7 @@ proc deleteData*(n: Node, start, len: int) proc focus*(e: Node) proc getAttribute*(n: Node, attr: cstring): cstring proc getAttributeNode*(n: Node, attr: cstring): Node -proc hasAttribute*(n: Node; attr: cstring): bool +proc hasAttribute*(n: Node, attr: cstring): bool proc hasChildNodes*(n: Node): bool proc insertData*(n: Node, position: int, data: cstring) proc removeAttribute*(n: Node, attr: cstring) @@ -1471,6 +1496,7 @@ proc createAttribute*(d: Document, identifier: cstring): Node proc getElementsByName*(d: Document, name: cstring): seq[Element] proc getElementsByTagName*(d: Document, name: cstring): seq[Element] proc getElementsByClassName*(d: Document, name: cstring): seq[Element] +proc insertNode*(range: Range, node: Node) proc getSelection*(d: Document): Selection proc handleEvent*(d: Document, event: Event) proc open*(d: Document) @@ -1562,6 +1588,8 @@ proc now*(p: Performance): float # Selection "methods" proc removeAllRanges*(s: Selection) +proc deleteFromDocument*(s: Selection) +proc getRangeAt*(s: Selection, index: int): Range converter toString*(s: Selection): cstring proc `$`*(s: Selection): string = $(s.toString()) From 40b58a0a1864e0cc06ecd0ceb8aadf9e933eeb30 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:57:35 +0800 Subject: [PATCH 0859/4254] fix #11009 (#14935) --- compiler/semdata.nim | 1 + compiler/suggest.nim | 7 ++++++- tests/deprecated/tmessages.nim | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/deprecated/tmessages.nim diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5a2c08de2..8680fcac3 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -143,6 +143,7 @@ type # would otherwise fail. unusedImports*: seq[(PSym, TLineInfo)] exportIndirections*: HashSet[(int, int)] + lastTLineInfo*: TLineInfo template config*(c: PContext): ConfigRef = c.graph.config diff --git a/compiler/suggest.nim b/compiler/suggest.nim index a9f248fb9..6e9844759 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -557,7 +557,12 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) = if sfDeprecated in s.owner.flags: warnAboutDeprecated(conf, info, s) if {sfDeprecated, sfError} * s.flags != {}: - if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s) + if sfDeprecated in s.flags: + if not (c.lastTLineInfo.line == info.line and + c.lastTLineInfo.col == info.col): + warnAboutDeprecated(conf, info, s) + c.lastTLineInfo = info + if sfError in s.flags: userError(conf, info, s) when defined(nimsuggest): suggestSym(conf, info, s, c.graph.usageSym, false) diff --git a/tests/deprecated/tmessages.nim b/tests/deprecated/tmessages.nim new file mode 100644 index 000000000..5884e396d --- /dev/null +++ b/tests/deprecated/tmessages.nim @@ -0,0 +1,10 @@ +discard """ + nimout:'''tmessages.nim(10, 1) Warning: Deprecated since v1.2.0, use 'HelloZ'; hello is deprecated [Deprecated] +''' +""" + +proc hello[T](a: T) {.deprecated: "Deprecated since v1.2.0, use 'HelloZ'".} = + discard + + +hello[int](12) From 64815f59b277ce03e7dd74d9d42a9058379852ec Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 9 Jul 2020 18:53:12 +0800 Subject: [PATCH 0860/4254] add testcase for #4668 (#14946) closes #4668 closes #9463 --- tests/generics/t4668.nim | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/generics/t4668.nim diff --git a/tests/generics/t4668.nim b/tests/generics/t4668.nim new file mode 100644 index 000000000..0d1b18111 --- /dev/null +++ b/tests/generics/t4668.nim @@ -0,0 +1,16 @@ +discard """ +action: compile +""" + +type + FooObj*[T] = object + v*: T + Foo1*[T] = FooObj[T] + Foo2* = FooObj + +proc foo1(x: Foo1) = echo "foo1" +proc foo2(x: Foo2) = echo "foo2" + +var x: FooObj[float] +foo1(x) # works +foo2(x) # works From c38a459582fb4744ce4abcba2d278b48857c0a31 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 9 Jul 2020 17:24:23 +0200 Subject: [PATCH 0861/4254] fixes #14925 (#14947) --- compiler/ccgstmts.nim | 4 ++++ tests/destructor/tgotoexceptions8.nim | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 532272374..c56340e00 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1218,6 +1218,10 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = p.nestedTryStmts.add((fin, false, Natural lab)) p.flags.incl nimErrorFlagAccessed + + if not isEmptyType(t.typ) and d.k == locNone: + getTemp(p, t.typ, d) + expr(p, t[0], d) if 1 < t.len and t[1].kind == nkExceptBranch: diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim index e968cdce2..8ed2ed0ba 100644 --- a/tests/destructor/tgotoexceptions8.nim +++ b/tests/destructor/tgotoexceptions8.nim @@ -8,7 +8,8 @@ outer finally msg1 msg2 finally2 -finally1''' +finally1 +true''' cmd: "nim c --gc:arc $file" """ @@ -67,3 +68,9 @@ when true: echo "finally1" nested_finally() + +# bug #14925 +proc test(b: bool) = + echo b + +test(try: true except: false) From d7ccd82eacd7a03c7cf31ea56315c3a35218e122 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Thu, 9 Jul 2020 19:18:35 +0200 Subject: [PATCH 0862/4254] VM profiler (#14833) * Crude VM profiler * Added --profileVM flag, refactoring * fixed FileLine hash * Use TLineInfo instead of own FileLine, updated formatting * Refactoring, moved PStackFrame to vmdefs for cleaner data structure * Moved vmprofiler to separate file * Simplified TLineInfo hash, use toFileLineCol for output * Hash * Moved profile data into Config, dump only once at end of run * Changed profile output header to show '#instr' instead of 'count' * Do not accumulate instrcount for non-top frames Co-authored-by: Ico Doornekamp --- compiler/commands.nim | 2 ++ compiler/lineinfos.nim | 5 ++++- compiler/main.nim | 4 +++- compiler/options.nim | 15 ++++++++++++++- compiler/vm.nim | 17 +++++------------ compiler/vmdef.nim | 15 +++++++++++++++ compiler/vmprofiler.nim | 42 +++++++++++++++++++++++++++++++++++++++++ doc/advopt.txt | 1 + 8 files changed, 86 insertions(+), 15 deletions(-) create mode 100644 compiler/vmprofiler.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 95df45ebe..cbf93238f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -884,6 +884,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info) + of "profilevm": + processOnOffSwitchG(conf, {optProfileVM}, arg, pass, info) of "sinkinference": processOnOffSwitch(conf, {optSinkInference}, arg, pass, info) of "panics": diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 378e06c72..c9821ac9f 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -10,7 +10,7 @@ ## This module contains the ``TMsgKind`` enum as well as the ## ``TLineInfo`` object. -import ropes, tables, pathutils +import ropes, tables, pathutils, hashes const explanationsBaseUrl* = "https://nim-lang.github.io/Nim" @@ -271,6 +271,9 @@ type proc `==`*(a, b: FileIndex): bool {.borrow.} +proc hash*(i: TLineInfo): Hash = + hash (i.line.int, i.col.int, i.fileIndex.int) + proc raiseRecoverableError*(msg: string) {.noinline.} = raise newException(ERecoverableError, msg) diff --git a/compiler/main.nim b/compiler/main.nim index 25a42300f..256ec14cd 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -19,7 +19,7 @@ import cgen, json, nversion, platform, nimconf, passaux, depends, vm, idgen, modules, - modulegraphs, tables, rod, lineinfos, pathutils + modulegraphs, tables, rod, lineinfos, pathutils, vmprofiler when not defined(leanCompiler): import jsgen, docgen, docgen2 @@ -404,6 +404,8 @@ proc mainCommand*(graph: ModuleGraph) = else: output = $conf.absOutFile if optListFullPaths notin conf.globalOptions: output = output.AbsoluteFile.extractFilename + if optProfileVM in conf.globalOptions: + echo conf.dump(conf.vmProfileData) rawMessage(conf, hintSuccessX, [ "loc", loc, "sec", sec, diff --git a/compiler/options.nim b/compiler/options.nim index 247f35419..80881d903 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -9,7 +9,7 @@ import os, strutils, strtabs, sets, lineinfos, platform, - prefixmatches, pathutils, nimpaths + prefixmatches, pathutils, nimpaths, tables from terminal import isatty from times import utc, fromUnix, local, getTime, format, DateTime @@ -95,6 +95,7 @@ type # please make sure we have under 32 options optPanics # turn panics (sysFatal) into a process termination optNimV1Emulation # emulate Nim v1.0 optSourcemap + optProfileVM # enable VM profiler TGlobalOptions* = set[TGlobalOption] @@ -217,6 +218,13 @@ type version*: int Suggestions* = seq[Suggest] + ProfileInfo* = object + time*: float + count*: int + + ProfileData* = ref object + data*: TableRef[TLineInfo, ProfileInfo] + ConfigRef* = ref object ## every global configuration ## fields marked with '*' are subject to ## the incremental compilation mechanisms @@ -314,6 +322,7 @@ type structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string + vmProfileData*: ProfileData proc assignIfDefault*[T](result: var T, val: T, def = default(T)) = ## if `result` was already assigned to a value (that wasn't `def`), this is a noop. @@ -390,6 +399,9 @@ template newPackageCache*(): untyped = else: modeCaseSensitive) +proc newProfileData(): ProfileData = + ProfileData(data: newTable[TLineInfo, ProfileInfo]()) + proc newConfigRef*(): ConfigRef = result = ConfigRef( selectedGC: gcRefc, @@ -442,6 +454,7 @@ proc newConfigRef*(): ConfigRef = arguments: "", suggestMaxResults: 10_000, maxLoopIterationsVM: 10_000_000, + vmProfileData: newProfileData(), ) setTargetFromSystem(result.target) # enable colors by default on terminals diff --git a/compiler/vm.nim b/compiler/vm.nim index 5d8d21bb9..1edcace82 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -16,7 +16,7 @@ import strutils, msgs, vmdef, vmgen, nimsets, types, passes, parser, vmdeps, idents, trees, renderer, options, transf, parseutils, vmmarshal, gorgeimpl, lineinfos, tables, btrees, macrocacheimpl, - modulegraphs, sighashes, int128 + modulegraphs, sighashes, int128, vmprofiler from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate @@ -27,17 +27,6 @@ const when hasFFI: import evalffi -type - PStackFrame* = ref TStackFrame - TStackFrame* = object - prc: PSym # current prc; proc that is evaluated - slots: seq[TFullReg] # parameters passed to the proc + locals; - # parameters come first - next: PStackFrame # for stacking - comesFrom: int - safePoints: seq[int] # used for exception handling - # XXX 'break' should perform cleanup actions - # What does the C backend do for it? proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = if x != nil: @@ -552,6 +541,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = "ra", regDescr("ra", ra), "rb", regDescr("rb", instr.regB), "rc", regDescr("rc", instr.regC)] + c.profiler.enter(c, tos) + case instr.opcode of opcEof: return regs[ra] of opcRet: @@ -2077,6 +2068,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) + c.profiler.leave(c) + inc pc proc execute(c: PCtx, start: int): PNode = diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 7b51c626d..9228ce5eb 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -261,6 +261,21 @@ type config*: ConfigRef graph*: ModuleGraph oldErrorCount*: int + profiler*: Profiler + + PStackFrame* = ref TStackFrame + TStackFrame* = object + prc*: PSym # current prc; proc that is evaluated + slots*: seq[TFullReg] # parameters passed to the proc + locals; + # parameters come first + next*: PStackFrame # for stacking + comesFrom*: int + safePoints*: seq[int] # used for exception handling + # XXX 'break' should perform cleanup actions + # What does the C backend do for it? + Profiler* = object + tEnter*: float + tos*: PStackFrame TPosition* = distinct int diff --git a/compiler/vmprofiler.nim b/compiler/vmprofiler.nim new file mode 100644 index 000000000..57a0430b4 --- /dev/null +++ b/compiler/vmprofiler.nim @@ -0,0 +1,42 @@ + +import + options, vmdef, times, lineinfos, strutils, tables, + msgs + +proc enter*(prof: var Profiler, c: PCtx, tos: PStackFrame) {.inline.} = + if optProfileVM in c.config.globalOptions: + prof.tEnter = cpuTime() + prof.tos = tos + +proc leave*(prof: var Profiler, c: PCtx) {.inline.} = + if optProfileVM in c.config.globalOptions: + let tLeave = cpuTime() + var tos = prof.tos + var data = c.config.vmProfileData.data + while tos != nil: + if tos.prc != nil: + let li = tos.prc.info + if li notin data: + data[li] = ProfileInfo() + data[li].time += tLeave - prof.tEnter + if tos == prof.tos: + inc data[li].count + tos = tos.next + +proc dump*(conf: ConfigRef, pd: ProfileData): string = + var data = pd.data + echo "\nprof: µs #instr location" + for i in 0..<32: + var tMax: float + var infoMax: ProfileInfo + var flMax: TLineInfo + for fl, info in data: + if info.time > infoMax.time: + infoMax = info + flMax = fl + if infoMax.count == 0: + break + result.add " " & align($int(infoMax.time * 1e6), 10) & + align($int(infoMax.count), 10) & " " & + conf.toFileLineCol(flMax) & "\n" + data.del flMax diff --git a/doc/advopt.txt b/doc/advopt.txt index f5b8c9ec9..547005485 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -150,5 +150,6 @@ Advanced options: works better with `--stackTrace:on` see also https://nim-lang.github.io/Nim/estp.html --benchmarkVM:on|off enable benchmarking of VM code with cpuTime() + --profileVM:on|off enable compile time VM profiler --sinkInference:on|off en-/disable sink parameter inference (default: on) --panics:on|off turn panics into process terminations (default: off) From f92d2eaa3516b4c11e4d499ef2ec0d6047862f80 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 9 Jul 2020 19:21:20 +0200 Subject: [PATCH 0863/4254] cleanup of PR #14833 (VM profiler) --- compiler/vmprofiler.nim | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/vmprofiler.nim b/compiler/vmprofiler.nim index 57a0430b4..f586c8ffe 100644 --- a/compiler/vmprofiler.nim +++ b/compiler/vmprofiler.nim @@ -2,26 +2,29 @@ import options, vmdef, times, lineinfos, strutils, tables, msgs - + proc enter*(prof: var Profiler, c: PCtx, tos: PStackFrame) {.inline.} = if optProfileVM in c.config.globalOptions: prof.tEnter = cpuTime() prof.tos = tos +proc leaveImpl(prof: var Profiler, c: PCtx) {.noinline.} = + let tLeave = cpuTime() + var tos = prof.tos + var data = c.config.vmProfileData.data + while tos != nil: + if tos.prc != nil: + let li = tos.prc.info + if li notin data: + data[li] = ProfileInfo() + data[li].time += tLeave - prof.tEnter + if tos == prof.tos: + inc data[li].count + tos = tos.next + proc leave*(prof: var Profiler, c: PCtx) {.inline.} = if optProfileVM in c.config.globalOptions: - let tLeave = cpuTime() - var tos = prof.tos - var data = c.config.vmProfileData.data - while tos != nil: - if tos.prc != nil: - let li = tos.prc.info - if li notin data: - data[li] = ProfileInfo() - data[li].time += tLeave - prof.tEnter - if tos == prof.tos: - inc data[li].count - tos = tos.next + leaveImpl(prof, c) proc dump*(conf: ConfigRef, pd: ProfileData): string = var data = pd.data From 3e52136f262b9700713eb10594f18e42a2f2af65 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 8 Jul 2020 18:04:14 +0200 Subject: [PATCH 0864/4254] Cosmetics --- compiler/injectdestructors.nim | 103 ++++++++++++++++----------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 0a14a1daf..41f195d43 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -135,7 +135,7 @@ proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode if isExpr: result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) if ret.kind in nkCallKinds + {nkStmtListExpr}: - r = getTemp(c, s, ret.typ, ret.info) + r = c.getTemp(s, ret.typ, ret.info) else: result = newNodeI(nkStmtList, ret.info) @@ -374,11 +374,11 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = if kind == attachedDestructor: echo "destructor is ", op.id, " ", op.ast if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind]) - genOp(c, op, dest) + c.genOp(op, dest) proc genDestroy(c: Con; dest: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = genOp(c, t, attachedDestructor, dest, nil) + result = c.genOp(t, attachedDestructor, dest, nil) proc canBeMoved(c: Con; t: PType): bool {.inline.} = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) @@ -399,25 +399,24 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode, isDecl = false): PNode = else: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) if t.attachedOps[attachedSink] != nil: - result = genOp(c, t, attachedSink, dest, ri) + result = c.genOp(t, attachedSink, dest, ri) result.add ri else: # the default is to use combination of `=destroy(dest)` and # and copyMem(dest, source). This is efficient. - let snk = newTree(nkFastAsgn, dest, ri) - result = newTree(nkStmtList, genDestroy(c, dest), snk) + result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri)) proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = genOp(c, t, attachedAsgn, dest, ri) + result = c.genOp(t, attachedAsgn, dest, ri) proc genCopy(c: var Con; dest, ri: PNode): PNode = let t = dest.typ if tfHasOwned in t.flags and ri.kind != nkNilLit: # try to improve the error message here: if c.otherRead == nil: discard isLastRead(ri, c) - checkForErrorPragma(c, t, ri, "=") - result = genCopyNoCheck(c, dest, ri) + c.checkForErrorPragma(t, ri, "=") + result = c.genCopyNoCheck(dest, ri) proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope = result = addr(s) @@ -430,7 +429,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = # but fields within active case branch might need destruction # tmp to support self assignments - let tmp = getTemp(c, s, n[1].typ, n.info) + let tmp = c.getTemp(s, n[1].typ, n.info) result = newTree(nkStmtList) result.add newTree(nkFastAsgn, tmp, p(n[1], c, s, consumed)) @@ -457,10 +456,10 @@ It is best to factor out piece of object that needs custom destructor into separ let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool)) notExpr.add newSymNode(createMagic(c.graph, "not", mNot)) notExpr.add cond - result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, genOp(c, branchDestructor, le))) + result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le))) result.add newTree(nkFastAsgn, le, tmp) -proc genWasMoved(n: PNode; c: var Con): PNode = +proc genWasMoved(c: var Con, n: PNode): PNode = result = newNodeI(nkCall, n.info) result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved))) result.add copyTree(n) #mWasMoved does not take the address @@ -491,7 +490,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = v.add(vpart) result.add v - let wasMovedCall = genWasMoved(skipConv(n), c) + let wasMovedCall = c.genWasMoved(skipConv(n)) result.add wasMovedCall result.add tempAsNode @@ -501,10 +500,10 @@ proc isCapturedVar(n: PNode): bool = proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let tmp = getTemp(c, s, n.typ, n.info) + let tmp = c.getTemp(s, n.typ, n.info) if hasDestructor(n.typ): - result.add genWasMoved(tmp, c) - var m = genCopy(c, tmp, n) + result.add c.genWasMoved(tmp) + var m = c.genCopy(tmp, n) m.add p(n, c, s, normal) result.add m if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: @@ -547,15 +546,15 @@ proc ensureDestruction(arg: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) if s.parent != nil: - let tmp = getTemp(c, s.parent[], arg.typ, arg.info) - result.add genSink(c, s, tmp, arg, isDecl = true) + let tmp = c.getTemp(s.parent[], arg.typ, arg.info) + result.add c.genSink(s, tmp, arg, isDecl = true) result.add tmp - s.parent[].final.add genDestroy(c, tmp) + s.parent[].final.add c.genDestroy(tmp) else: - let tmp = getTemp(c, s, arg.typ, arg.info) - result.add genSink(c, s, tmp, arg, isDecl = true) + let tmp = c.getTemp(s, arg.typ, arg.info) + result.add c.genSink(s, tmp, arg, isDecl = true) result.add tmp - s.final.add genDestroy(c, tmp) + s.final.add c.genDestroy(tmp) else: result = arg @@ -632,9 +631,9 @@ proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = elif sfThread notin v.sym.flags: # do not destroy thread vars for now at all for consistency. if sfGlobal in v.sym.flags and s.parent == nil: - c.graph.globalDestructors.add genDestroy(c, v) + c.graph.globalDestructors.add c.genDestroy(v) else: - owningScope[].final.add genDestroy(c, v) + owningScope[].final.add c.genDestroy(v) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: @@ -746,14 +745,14 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = result = copyNode(n) result.add call else: - let tmp = getTemp(c, s, n[0].typ, n.info) - var m = genCopyNoCheck(c, tmp, n[0]) + let tmp = c.getTemp(s, n[0].typ, n.info) + var m = c.genCopyNoCheck(tmp, n[0]) m.add p(n[0], c, s, normal) - result = newTree(nkStmtList, genWasMoved(tmp, c), m) + result = newTree(nkStmtList, c.genWasMoved(tmp), m) var toDisarm = n[0] if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner: - result.add genWasMoved(toDisarm, c) + result.add c.genWasMoved(toDisarm) result.add newTree(nkRaiseStmt, tmp) else: result = copyNode(n) @@ -863,7 +862,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}: result[0] = copyTree(n[0]) if c.graph.config.selectedGC in {gcHooks, gcArc, gcOrc}: - let destroyOld = genDestroy(c, result[1]) + let destroyOld = c.genDestroy(result[1]) result = newTree(nkStmtList, destroyOld, result) else: result[0] = p(n[0], c, s, normal) @@ -915,7 +914,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = assert n[1].kind notin {nkAsgn, nkFastAsgn} result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s) elif isDiscriminantField(n[0]): - result = genDiscriminantAsgn(c, s, n) + result = c.genDiscriminantAsgn(s, n) else: result = copyNode(n) result.add p(n[0], c, s, mode) @@ -967,7 +966,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[i] = n[i] if mode == sinkArg and hasDestructor(n.typ): if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): - s.wasMoved.add genWasMoved(n, c) + s.wasMoved.add c.genWasMoved(n) else: result = passCopyToSink(result, c, s) @@ -978,9 +977,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = if mode == sinkArg and hasDestructor(n.typ): if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): # consider 'a[(g; destroy(g); 3)]', we want to say 'wasMoved(a[3])' - # without the junk, hence 'genWasMoved(n, c)' - # and not 'genWasMoved(result, c)': - s.wasMoved.add genWasMoved(n, c) + # without the junk, hence 'c.genWasMoved(n)' + # and not 'c.genWasMoved(result)': + s.wasMoved.add c.genWasMoved(n) else: result = passCopyToSink(result, c, s) @@ -1014,43 +1013,43 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNode = case ri.kind of nkCallKinds: - result = genSink(c, s, dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(s, dest, p(ri, c, s, consumed), isDecl) of nkBracketExpr: if isUnpackedTuple(ri[0]): # unpacking of tuple: take over the elements - result = genSink(c, s, dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(s, dest, p(ri, c, s, consumed), isDecl) elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and not aliases(dest, ri): # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = genSink(c, s, dest, ri, isDecl) - result = newTree(nkStmtList, snk, genWasMoved(ri, c)) + var snk = c.genSink(s, dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - result = genCopy(c, dest, ri) + result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) of nkBracket: # array constructor if ri.len > 0 and isDangerousSeq(ri.typ): - result = genCopy(c, dest, ri) + result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) else: - result = genSink(c, s, dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(s, dest, p(ri, c, s, consumed), isDecl) of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - result = genSink(c, s, dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(s, dest, p(ri, c, s, consumed), isDecl) of nkSym: if isSinkParam(ri.sym) and isLastRead(ri, c): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = genSink(c, s, dest, ri, isDecl) - result = newTree(nkStmtList, snk, genWasMoved(ri, c)) + let snk = c.genSink(s, dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) elif ri.sym.kind != skParam and ri.sym.owner == c.owner and isLastRead(ri, c) and canBeMoved(c, dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = genSink(c, s, dest, ri, isDecl) - result = newTree(nkStmtList, snk, genWasMoved(ri, c)) + let snk = c.genSink(s, dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - result = genCopy(c, dest, ri) + result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: - result = genSink(c, s, dest, p(ri, c, s, sinkArg), isDecl) + result = c.genSink(s, dest, p(ri, c, s, sinkArg), isDecl) of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt: template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) handleNestedTempl(ri, process, true) @@ -1060,10 +1059,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and canBeMoved(c, dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = genSink(c, s, dest, ri, isDecl) - result = newTree(nkStmtList, snk, genWasMoved(ri, c)) + let snk = c.genSink(s, dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - result = genCopy(c, dest, ri) + result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) proc computeUninit(c: var Con) = @@ -1127,7 +1126,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = for i in 1.. Date: Wed, 8 Jul 2020 20:48:17 +0200 Subject: [PATCH 0865/4254] Move `wasMoved` out of `=destroy` --- compiler/ccgexprs.nim | 4 ++-- compiler/injectdestructors.nim | 10 +++++----- compiler/liftdestructors.nim | 10 +--------- lib/system/seqs_v2.nim | 3 +-- lib/system/widestrs.nim | 1 - 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c194ce326..dc9617fe2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2100,14 +2100,14 @@ proc genDestroy(p: BProc; n: PNode) = initLocExpr(p, arg, a) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #deallocShared($1.p);$n" & - " $1.p = NIM_NIL; $1.len = 0; }$n", + "}$n", [rdLoc(a)]) of tySequence: var a: TLoc initLocExpr(p, arg, a) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #deallocShared($1.p);$n" & - " $1.p = NIM_NIL; $1.len = 0; }$n", + "}$n", [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) else: discard "nothing to do" else: diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 41f195d43..f1284f523 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -93,7 +93,7 @@ proc optimize(s: var Scope) = proc findCorrespondingDestroy(final: seq[PNode]; moved: PNode): int = # remember that it's destroy(addr(x)) for i in 0 ..< final.len: - if final[i] != nil and exprStructuralEquivalent(final[i][1].skipAddr, moved, strictSymEquality = true): + if final[i] != nil and exprStructuralEquivalent(final[i][0][1].skipAddr, moved, strictSymEquality = true): return i return -1 @@ -549,12 +549,12 @@ proc ensureDestruction(arg: PNode; c: var Con; s: var Scope): PNode = let tmp = c.getTemp(s.parent[], arg.typ, arg.info) result.add c.genSink(s, tmp, arg, isDecl = true) result.add tmp - s.parent[].final.add c.genDestroy(tmp) + s.parent[].final.add newTree(nkStmtList, c.genDestroy(tmp), c.genWasMoved(tmp)) else: let tmp = c.getTemp(s, arg.typ, arg.info) result.add c.genSink(s, tmp, arg, isDecl = true) result.add tmp - s.final.add c.genDestroy(tmp) + s.final.add newTree(nkStmtList, c.genDestroy(tmp), c.genWasMoved(tmp)) else: result = arg @@ -631,9 +631,9 @@ proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = elif sfThread notin v.sym.flags: # do not destroy thread vars for now at all for consistency. if sfGlobal in v.sym.flags and s.parent == nil: - c.graph.globalDestructors.add c.genDestroy(v) + c.graph.globalDestructors.add c.genDestroy(v) #No need to genWasMoved here else: - owningScope[].final.add c.genDestroy(v) + owningScope[].final.add newTree(nkStmtList, c.genDestroy(v), c.genWasMoved(v)) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 0346f6c67..21fef1d61 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -535,7 +535,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: if isFinal(elemType): @@ -584,7 +583,6 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, cond, actions) - body.add newAsgnStmt(xenv, newNodeIT(nkNilLit, body.info, xenv.typ)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv), y) @@ -613,7 +611,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # prevent wrong "dangling refs exist" problems: var actions = newNodeI(nkStmtList, c.info) actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, x) - actions.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) let des = genIf(c, x, actions) if body.len == 0: body.add des @@ -642,7 +639,6 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, x, actions) - body.add newAsgnStmt(x, newNodeIT(nkNilLit, body.info, t)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace, attachedDispose: discard @@ -672,10 +668,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) body.add newAsgnStmt(x, y) of attachedDestructor: - var actions = newNodeI(nkStmtList, c.info) - actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, xx) - actions.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ)) - let des = genIf(c, xx, actions) + let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) if body.len == 0: body.add des else: @@ -695,7 +688,6 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, xx, actions) - body.add newAsgnStmt(xx, newNodeIT(nkNilLit, body.info, xx.typ)) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace, attachedDispose: discard diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 1b40c00ab..4001e97c3 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -73,11 +73,10 @@ proc shrink*[T](x: var seq[T]; newLen: Natural) = when nimvm: setLen(x, newLen) else: - mixin `=destroy` #sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" when not supportsCopyMem(T): for i in countdown(x.len - 1, newLen): - `=destroy`(x[i]) + reset x[i] # XXX This is wrong for const seqs that were moved into 'x'! cast[ptr NimSeqV2[T]](addr x).len = newLen diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index aabcbdc90..83c11eb79 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -28,7 +28,6 @@ when defined(nimv2): proc `=destroy`(a: var WideCStringObj) = if a.data != nil: deallocShared(a.data) - a.data = nil proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.} From bf51cee4311f5715c2eac675e95fb3d4f2909404 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 9 Jul 2020 17:59:40 +0200 Subject: [PATCH 0866/4254] Update docs and changelog --- changelog.md | 2 ++ doc/destructors.rst | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 1eda82297..36582eee2 100644 --- a/changelog.md +++ b/changelog.md @@ -143,6 +143,8 @@ ## Language changes +- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts + wasMoved calls where needed. - In the newruntime it is now allowed to assign to the discriminator field without restrictions as long as case object doesn't have custom destructor. The discriminator value doesn't have to be a constant either. If you have a diff --git a/doc/destructors.rst b/doc/destructors.rst index 4285bad8b..fefc646f5 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -39,12 +39,12 @@ written as: if x.data != nil: for i in 0.. Date: Fri, 10 Jul 2020 09:45:41 +0200 Subject: [PATCH 0867/4254] renderer.nim: more obvious debug output --- compiler/renderer.nim | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 4b8c78cc7..449ee4504 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1016,11 +1016,21 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"') else: gsub(g, n, 1) - of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: + of nkHiddenStdConv, nkHiddenSubConv: if n.len >= 2: gsub(g, n[1]) else: put(g, tkSymbol, "(wrong conv)") + of nkHiddenCallConv: + if renderIds in g.flags: + accentedName(g, n[0]) + put(g, tkParLe, "(") + gcomma(g, n, 1) + put(g, tkParRi, ")") + elif n.len >= 2: + gsub(g, n[1]) + else: + put(g, tkSymbol, "(wrong conv)") of nkCast: put(g, tkCast, "cast") put(g, tkBracketLe, "[") From 37a98c77f32a5a7f2397ea9faabea6e04e5123ed Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 10 Jul 2020 09:51:43 +0200 Subject: [PATCH 0868/4254] optimize sinks even when in a loop --- compiler/injectdestructors.nim | 35 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index f1284f523..d20b4de15 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -46,7 +46,6 @@ type owner: PSym g: ControlFlowGraph jumpTargets: IntSet - destroys, topLevelVars: PNode graph: ModuleGraph emptyNode: PNode otherRead: PNode @@ -59,6 +58,13 @@ type consumed sinkArg +const toDebug {.strdefine.} = "" + +template dbg(body) = + when toDebug.len > 0: + if c.owner.name.s == toDebug or toDebug == "always": + body + proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) sym.typ = typ @@ -89,7 +95,6 @@ proc optimize(s: var Scope) = Now assume 'echo' raises, then we shouldn't do the 'wasMoved(s)' ]# - # XXX: Investigate how to really insert 'wasMoved()' calls! proc findCorrespondingDestroy(final: seq[PNode]; moved: PNode): int = # remember that it's destroy(addr(x)) for i in 0 ..< final.len: @@ -169,14 +174,6 @@ proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode if r != nil: result.add r - -const toDebug {.strdefine.} = "" - -template dbg(body) = - when toDebug.len > 0: - if c.owner.name.s == toDebug or toDebug == "always": - body - proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode @@ -391,7 +388,7 @@ proc isNoInit(dest: PNode): bool {.inline.} = result = dest.kind == nkSym and sfNoInit in dest.sym.flags proc genSink(c: var Con; s: var Scope; dest, ri: PNode, isDecl = false): PNode = - if isUnpackedTuple(dest) or (isDecl and c.inLoop <= 0) or + if isUnpackedTuple(dest) or isDecl or (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)) or isNoInit(dest): # optimize sink call into a bitwise memcopy @@ -545,16 +542,10 @@ proc ensureDestruction(arg: PNode; c: var Con; s: var Scope): PNode = # This was already done in the sink parameter handling logic. result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) - if s.parent != nil: - let tmp = c.getTemp(s.parent[], arg.typ, arg.info) - result.add c.genSink(s, tmp, arg, isDecl = true) - result.add tmp - s.parent[].final.add newTree(nkStmtList, c.genDestroy(tmp), c.genWasMoved(tmp)) - else: - let tmp = c.getTemp(s, arg.typ, arg.info) - result.add c.genSink(s, tmp, arg, isDecl = true) - result.add tmp - s.final.add newTree(nkStmtList, c.genDestroy(tmp), c.genWasMoved(tmp)) + let tmp = c.getTemp(s, arg.typ, arg.info) + result.add c.genSink(s, tmp, arg, isDecl = true) + result.add tmp + s.final.add newTree(nkStmtList, c.genDestroy(tmp), c.genWasMoved(tmp)) else: result = arg @@ -1103,8 +1094,6 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = return n var c: Con c.owner = owner - c.destroys = newNodeI(nkStmtList, n.info) - c.topLevelVars = newNodeI(nkVarSection, n.info) c.graph = g c.emptyNode = newNodeI(nkEmpty, n.info) let cfg = constructCfg(owner, n) From b59385f22b0c9d7826721079cef879a354c9529a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 10 Jul 2020 10:14:14 +0200 Subject: [PATCH 0869/4254] no wasMoved() calls after destructors necessary --- compiler/injectdestructors.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d20b4de15..d5de70e29 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -87,18 +87,18 @@ proc optimize(s: var Scope) = try: var s = ["hi", inp & "more"] for i in 0..4: - echo s + use s consume(s) wasMoved(s) finally: destroy(x) - Now assume 'echo' raises, then we shouldn't do the 'wasMoved(s)' + Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)' ]# proc findCorrespondingDestroy(final: seq[PNode]; moved: PNode): int = # remember that it's destroy(addr(x)) for i in 0 ..< final.len: - if final[i] != nil and exprStructuralEquivalent(final[i][0][1].skipAddr, moved, strictSymEquality = true): + if final[i] != nil and exprStructuralEquivalent(final[i][1].skipAddr, moved, strictSymEquality = true): return i return -1 @@ -129,7 +129,7 @@ type producesValue proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = - if not s.needsTry: optimize(s) + #if not s.needsTry: optimize(s) assert ret != nil if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: # trivial, nothing was done: @@ -545,7 +545,7 @@ proc ensureDestruction(arg: PNode; c: var Con; s: var Scope): PNode = let tmp = c.getTemp(s, arg.typ, arg.info) result.add c.genSink(s, tmp, arg, isDecl = true) result.add tmp - s.final.add newTree(nkStmtList, c.genDestroy(tmp), c.genWasMoved(tmp)) + s.final.add c.genDestroy(tmp) else: result = arg @@ -624,7 +624,7 @@ proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = if sfGlobal in v.sym.flags and s.parent == nil: c.graph.globalDestructors.add c.genDestroy(v) #No need to genWasMoved here else: - owningScope[].final.add newTree(nkStmtList, c.genDestroy(v), c.genWasMoved(v)) + owningScope[].final.add c.genDestroy(v) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: From 112511084d61edc0bb748ff8c267fb54bc7e9716 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 10 Jul 2020 10:58:16 +0200 Subject: [PATCH 0870/4254] fixes the tcontrolflow regression, clen idea of an escaping expression --- compiler/injectdestructors.nim | 64 +++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d5de70e29..d091e8e29 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -40,6 +40,7 @@ type escapingSyms: IntSet # a construct like (block: let x = f(); x) # means that 'x' escapes. We then destroy it # in the parent's scope (and also allocate it there). + escapingExpr: PNode type Con = object @@ -129,6 +130,9 @@ type producesValue proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = + proc isComplexStmtListExpr(n: PNode): bool = + n.kind == nkStmtListExpr and (n.len == 0 or n[^1].kind != nkSym) + #if not s.needsTry: optimize(s) assert ret != nil if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: @@ -139,7 +143,7 @@ proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode var r = PNode(nil) if isExpr: result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) - if ret.kind in nkCallKinds + {nkStmtListExpr}: + if ret.kind in nkCallKinds or isComplexStmtListExpr(ret): r = c.getTemp(s, ret.typ, ret.info) else: result = newNodeI(nkStmtList, ret.info) @@ -167,12 +171,20 @@ proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode result.add newTree(nkFastAsgn, r, ret[last]) else: result.add newTree(nkFastAsgn, r, ret) + for m in s.wasMoved: result.add m + for i in countdown(s.final.high, 0): result.add s.final[i] + result.add r + elif ret.kind == nkStmtListExpr: + # simplify it a bit further by merging the nkStmtListExprs + let last = ret.len - 1 + for i in 0 ..< last: result.add ret[i] + for m in s.wasMoved: result.add m + for i in countdown(s.final.high, 0): result.add s.final[i] + result.add ret[last] else: result.add ret - for m in s.wasMoved: result.add m - for i in countdown(s.final.high, 0): result.add s.final[i] - if r != nil: - result.add r + for m in s.wasMoved: result.add m + for i in countdown(s.final.high, 0): result.add s.final[i] proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode @@ -534,18 +546,23 @@ proc containsConstSeq(n: PNode): bool = if containsConstSeq(son): return true else: discard -proc ensureDestruction(arg: PNode; c: var Con; s: var Scope): PNode = +proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = # it can happen that we need to destroy expression contructors # like [], (), closures explicitly in order to not leak them. if arg.typ != nil and hasDestructor(arg.typ): # produce temp creation for (fn, env). But we need to move 'env'? # This was already done in the sink parameter handling logic. result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) - - let tmp = c.getTemp(s, arg.typ, arg.info) - result.add c.genSink(s, tmp, arg, isDecl = true) - result.add tmp - s.final.add c.genDestroy(tmp) + if orig == s.escapingExpr and s.parent != nil: + let tmp = c.getTemp(s.parent[], arg.typ, arg.info) + result.add c.genSink(s.parent[], tmp, arg, isDecl = true) + result.add tmp + s.parent[].final.add c.genDestroy(tmp) + else: + let tmp = c.getTemp(s, arg.typ, arg.info) + result.add c.genSink(s, tmp, arg, isDecl = true) + result.add tmp + s.final.add c.genDestroy(tmp) else: result = arg @@ -590,28 +607,35 @@ proc cycleCheck(n: PNode; c: var Con) = message(c.graph.config, n.info, warnCycleCreated, msg) break -proc markEscapingVars(n: PNode; s: var Scope) = +proc markEscapingVarsRec(n: PNode; s: var Scope) = case n.kind of nkSym: s.escapingSyms.incl n.sym.id of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: - markEscapingVars(n[0], s) + markEscapingVarsRec(n[0], s) of nkCast, nkHiddenSubConv, nkHiddenStdConv, nkConv: - markEscapingVars(n[1], s) + markEscapingVarsRec(n[1], s) of nkTupleConstr, nkBracket, nkPar, nkClosure: for i in 0 ..< n.len: - markEscapingVars(n[i], s) + markEscapingVarsRec(n[i], s) of nkObjConstr: for i in 1 ..< n.len: - markEscapingVars(n[i], s) + markEscapingVarsRec(n[i], s) of nkStmtList, nkStmtListExpr: if n.len > 0: - markEscapingVars(n[^1], s) + markEscapingVarsRec(n[^1], s) else: discard "no arbitrary tree traversal here" +proc markEscapingVars(n: PNode; s: var Scope) = + markEscapingVarsRec(n, s) + var it = n + while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: + it = it[^1] + s.escapingExpr = it + proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = # move the variable declaration to the top of the frame: let owningScope = c.addTopVar(s, v) @@ -820,7 +844,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = else: result[i] = p(n[i], c, s, m) if mode == normal and isRefConstr: - result = ensureDestruction(result, c, s) + result = ensureDestruction(result, n, c, s) of nkCallKinds: let inSpawn = c.inSpawn if n[0].kind == nkSym and n[0].sym.magic == mSpawn: @@ -859,7 +883,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[0] = p(n[0], c, s, normal) if canRaise(n[0]): s.needsTry = true if mode == normal: - result = ensureDestruction(result, c, s) + result = ensureDestruction(result, n, c, s) of nkDiscardStmt: # Small optimization result = shallowCopy(n) if n[0].kind != nkEmpty: @@ -927,7 +951,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[i] = p(n[i], c, s, normal) if n.typ != nil and hasDestructor(n.typ): if mode == normal: - result = ensureDestruction(result, c, s) + result = ensureDestruction(result, n, c, s) of nkHiddenSubConv, nkHiddenStdConv, nkConv: # we have an "ownership invariance" for all constructors C(x). From 4603197fe8f2c6fb1fd74fa7ad5b4ef510e8bfb7 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 10 Jul 2020 12:27:32 +0200 Subject: [PATCH 0871/4254] fixes a minor regression --- compiler/injectdestructors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d091e8e29..da41b2d5c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -555,7 +555,7 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) if orig == s.escapingExpr and s.parent != nil: let tmp = c.getTemp(s.parent[], arg.typ, arg.info) - result.add c.genSink(s.parent[], tmp, arg, isDecl = true) + result.add c.genSink(s, tmp, arg, isDecl = true) result.add tmp s.parent[].final.add c.genDestroy(tmp) else: From 04232d92cd401bf301a9e4cac582273356c86cfa Mon Sep 17 00:00:00 2001 From: Manuel Bojato <30560560+KingDarBoja@users.noreply.github.com> Date: Fri, 10 Jul 2020 08:06:07 -0500 Subject: [PATCH 0872/4254] Fix theme switch load from local storage (#14897) * fix theme switch load from local storage * Fix tests Co-authored-by: Clyybber --- config/nimdoc.cfg | 19 +++++-------------- .../expected/index.html | 19 +++++-------------- .../expected/theindex.html | 19 +++++-------------- .../expected/subdir/subdir_b/utils.html | 19 +++++-------------- nimdoc/testproject/expected/testproject.html | 19 +++++-------------- nimdoc/testproject/expected/theindex.html | 19 +++++-------------- 6 files changed, 30 insertions(+), 84 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 945a3dc6c..3560c0d65 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -240,21 +240,12 @@ function main() { toggleSwitch.addEventListener('change', switchTheme, false); + const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + if (currentTheme) { + document.documentElement.setAttribute('data-theme', currentTheme); - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-theme', "dark"); - toggleSwitch.checked = true; - } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { - document.documentElement.setAttribute('data-theme', "light"); - toggleSwitch.checked = false; - } else { - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; - if (currentTheme) { - document.documentElement.setAttribute('data-theme', currentTheme); - - if (currentTheme === 'dark') { - toggleSwitch.checked = true; - } + if (currentTheme === 'dark') { + toggleSwitch.checked = true; } } } diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index a8b65b2c9..f35334503 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -47,21 +47,12 @@ function main() { toggleSwitch.addEventListener('change', switchTheme, false); + const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + if (currentTheme) { + document.documentElement.setAttribute('data-theme', currentTheme); - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-theme', "dark"); - toggleSwitch.checked = true; - } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { - document.documentElement.setAttribute('data-theme', "light"); - toggleSwitch.checked = false; - } else { - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; - if (currentTheme) { - document.documentElement.setAttribute('data-theme', currentTheme); - - if (currentTheme === 'dark') { - toggleSwitch.checked = true; - } + if (currentTheme === 'dark') { + toggleSwitch.checked = true; } } } diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index 095dd7471..b2863f99a 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -47,21 +47,12 @@ function main() { toggleSwitch.addEventListener('change', switchTheme, false); + const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + if (currentTheme) { + document.documentElement.setAttribute('data-theme', currentTheme); - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-theme', "dark"); - toggleSwitch.checked = true; - } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { - document.documentElement.setAttribute('data-theme', "light"); - toggleSwitch.checked = false; - } else { - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; - if (currentTheme) { - document.documentElement.setAttribute('data-theme', currentTheme); - - if (currentTheme === 'dark') { - toggleSwitch.checked = true; - } + if (currentTheme === 'dark') { + toggleSwitch.checked = true; } } } diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 6e83f718f..eefbcfdf9 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -47,21 +47,12 @@ function main() { toggleSwitch.addEventListener('change', switchTheme, false); + const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + if (currentTheme) { + document.documentElement.setAttribute('data-theme', currentTheme); - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-theme', "dark"); - toggleSwitch.checked = true; - } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { - document.documentElement.setAttribute('data-theme', "light"); - toggleSwitch.checked = false; - } else { - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; - if (currentTheme) { - document.documentElement.setAttribute('data-theme', currentTheme); - - if (currentTheme === 'dark') { - toggleSwitch.checked = true; - } + if (currentTheme === 'dark') { + toggleSwitch.checked = true; } } } diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 648ecb629..479a2e89d 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -47,21 +47,12 @@ function main() { toggleSwitch.addEventListener('change', switchTheme, false); + const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + if (currentTheme) { + document.documentElement.setAttribute('data-theme', currentTheme); - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-theme', "dark"); - toggleSwitch.checked = true; - } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { - document.documentElement.setAttribute('data-theme', "light"); - toggleSwitch.checked = false; - } else { - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; - if (currentTheme) { - document.documentElement.setAttribute('data-theme', currentTheme); - - if (currentTheme === 'dark') { - toggleSwitch.checked = true; - } + if (currentTheme === 'dark') { + toggleSwitch.checked = true; } } } diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 0b835c409..66dea92fc 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -47,21 +47,12 @@ function main() { toggleSwitch.addEventListener('change', switchTheme, false); + const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + if (currentTheme) { + document.documentElement.setAttribute('data-theme', currentTheme); - if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-theme', "dark"); - toggleSwitch.checked = true; - } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { - document.documentElement.setAttribute('data-theme', "light"); - toggleSwitch.checked = false; - } else { - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; - if (currentTheme) { - document.documentElement.setAttribute('data-theme', currentTheme); - - if (currentTheme === 'dark') { - toggleSwitch.checked = true; - } + if (currentTheme === 'dark') { + toggleSwitch.checked = true; } } } From 371b416ac818412909243d10a66c20db3eaa23f3 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 10 Jul 2020 16:44:12 +0200 Subject: [PATCH 0873/4254] fix #14912, make `--useVersion:1.0` work again (#14945) * fix #14912, make `--useVersion:1.0` work again * a better fix * add test --- compiler/commands.nim | 1 + tests/system/tuse_version.nim | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/system/tuse_version.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index cbf93238f..1984c894a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -878,6 +878,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "NimPatch", "100") # old behaviors go here: defineSymbol(conf.symbols, "nimOldRelativePathBehavior") + undefSymbol(conf.symbols, "nimDoesntTrackDefects") ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect} conf.globalOptions.incl optNimV1Emulation else: diff --git a/tests/system/tuse_version.nim b/tests/system/tuse_version.nim new file mode 100644 index 000000000..36dac46ec --- /dev/null +++ b/tests/system/tuse_version.nim @@ -0,0 +1,50 @@ +discard """ + cmd: "nim c --useVersion:1.0 -r $file" + output: "1.0.100" +""" + +{.warning[UnusedImport]: off.} + +import std/[ + # Core: + bitops, typetraits, lenientops, macros, volatile, + + # Algorithms: + algorithm, sequtils, + + # Collections: + critbits, deques, heapqueue, intsets, lists, options, sets, + sharedlist, tables, + + # Strings: + editdistance, wordwrap, parseutils, ropes, + pegs, punycode, strformat, strmisc, strscans, strtabs, + strutils, unicode, unidecode, + + # Generic operator system services: + os, streams, + + # Math libraries: + complex, math, mersenne, random, rationals, stats, sums, + + # Internet protocols: + httpcore, mimetypes, uri, + + # Parsers: + htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, + + # XML processing: + xmltree, xmlparser, + + # Generators: + htmlgen, + + # Hashing: + base64, hashes, + + # Miscellaneous: + colors, sugar, varints, +] + + +echo NimVersion From 229a623849da617abd9afc3f30ba6c612b4c04c2 Mon Sep 17 00:00:00 2001 From: kwgchi Date: Fri, 10 Jul 2020 23:45:26 +0900 Subject: [PATCH 0874/4254] Update readme.md (#14953) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index f529c0df0..94241822f 100644 --- a/readme.md +++ b/readme.md @@ -138,7 +138,7 @@ you should familiarize yourself with the following repository structure: If you are not familiar with making a pull request using GitHub and/or git, please read [this guide][pull-request-instructions]. -Ideally you should make sure that all tests pass before submitting a pull request. +Ideally, you should make sure that all tests pass before submitting a pull request. However, if you are short on time, you can just run the tests specific to your changes by only running the corresponding categories of tests. Travis CI verifies that all tests pass before allowing the pull request to be accepted, so only @@ -146,7 +146,7 @@ running specific tests should be harmless. Integration tests should go in ``tests/untestable``. If you're looking for ways to contribute, please look at our [issue tracker][nim-issues]. -There are always plenty of issues labelled [``Easy``][nim-issues-easy]; these should +There are always plenty of issues labeled [``Easy``][nim-issues-easy]; these should be a good starting point for an initial contribution to Nim. You can also help with the development of Nim by making donations. Donations can be From b21782a667f7a819124e95da14053387bd0079a0 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 10 Jul 2020 17:02:49 +0200 Subject: [PATCH 0875/4254] Add testcase for #4722 (#14954) --- tests/template/template_issues.nim | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index e56d44480..420373e61 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -8,6 +8,9 @@ hi Hello, World! (e: 42) hey +foo +foo +foo ''' """ @@ -245,3 +248,21 @@ proc foo(): auto = echo "hey" discard foo() + + +# bug #4722 +type + IteratorF*[In] = iterator() : In {.closure.} + +template foof(In: untyped) : untyped = + proc ggg*(arg: IteratorF[In]) = + for i in arg(): + echo "foo" + + +iterator hello() : int {.closure.} = + for i in 1 .. 3: + yield i + +foof(int) +ggg(hello) From 0db32e98854dd3fc5a6e1d27a1d4980fd61053da Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 10 Jul 2020 17:13:37 +0200 Subject: [PATCH 0876/4254] Add testcase for #12571 (#14955) --- tests/statictypes/tstatictypes.nim | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 2a8d09dbf..50dc60e09 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -9,6 +9,7 @@ output: ''' b is 2 times a 17 ['\x00', '\x00', '\x00', '\x00'] +heyho ''' """ @@ -223,3 +224,18 @@ block: # issue #14802 12 const myConst = static(fn(1)) doAssert myConst == 12 + + +# bug #12571 +type + T[K: static bool] = object of RootObj + when K == true: + foo: string + else: + bar: string + U[K: static bool] = object of T[K] + +let t = T[true](foo: "hey") +let u = U[false](bar: "ho") +echo t.foo, u.bar + From db6ffeba8e8be9d27a8c4610952b0424e9c46d4a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 10 Jul 2020 17:31:15 +0200 Subject: [PATCH 0877/4254] Add testcase for #13815 (#14956) --- tests/iter/tclosureiters.nim | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim index 345a4867a..0ee8e81cc 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -19,7 +19,9 @@ discard """ 0 1 2 -70''' +70 +0 +''' """ when true: @@ -139,3 +141,14 @@ iterator filesIt(path: string): auto {.closure.} = let prefix = path.splitPath[1] for f in files: yield prefix / f + +# bug #13815 +var love = iterator: int {.closure.} = + yield cast[type( + block: + var a = 0 + yield a + a)](0) + +for i in love(): + echo i From 1850efbb6c618946da7c943b153f7caa9a66ba33 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 10 Jul 2020 18:10:32 +0200 Subject: [PATCH 0878/4254] Add testcase for #14383 (#14957) --- tests/arc/dmodule.nim | 23 +++++++++++++++++++++++ tests/arc/t14383.nim | 13 +++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/arc/dmodule.nim create mode 100644 tests/arc/t14383.nim diff --git a/tests/arc/dmodule.nim b/tests/arc/dmodule.nim new file mode 100644 index 000000000..455ec7084 --- /dev/null +++ b/tests/arc/dmodule.nim @@ -0,0 +1,23 @@ +type + MinKind* = enum + minDictionary + minBool + MinValue* = object + case kind*: MinKind + of minDictionary: + symbols: seq[MinOperator] + else: discard + MinOperator = object + +# remove this inline pragma to make it compile +proc `$`*(a: MinValue): string {.inline.} = + case a.kind + of minDictionary: + result = "hello" + for i in a.symbols: + result = "hello" + else: discard + +proc parseMinValue*(): MinValue = + # or this echo + echo result diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim new file mode 100644 index 000000000..115cbf426 --- /dev/null +++ b/tests/arc/t14383.nim @@ -0,0 +1,13 @@ +discard """ + cmd: "nim c --gc:arc $file" + output: ''' +hello +hello +''' +""" + +import dmodule + +var val = parseMinValue() +if val.kind == minDictionary: + echo val From 425972c4e8bde84ff8b84a64f1e68356dc0a1a3a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 10 Jul 2020 19:21:50 +0200 Subject: [PATCH 0879/4254] Add testcase for some old fixed issues (#14960) * Add testcase for #2703 * Add testcase for #2586 * Small fix --- tests/template/template_issues.nim | 8 ++++++++ tests/ccgbugs/trecursive_closure.nim => tissues.nim | 10 ++++++++++ 2 files changed, 18 insertions(+) rename tests/ccgbugs/trecursive_closure.nim => tissues.nim (67%) diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index 420373e61..d12b3c3ef 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -11,6 +11,8 @@ hey foo foo foo +false +true ''' """ @@ -266,3 +268,9 @@ iterator hello() : int {.closure.} = foof(int) ggg(hello) + + +# bug #2586 +var z = 10'u8 +echo z < 9 # Works +echo z > 9 # Error: type mismatch diff --git a/tests/ccgbugs/trecursive_closure.nim b/tissues.nim similarity index 67% rename from tests/ccgbugs/trecursive_closure.nim rename to tissues.nim index 4b6514b90..7a8ede958 100644 --- a/tests/ccgbugs/trecursive_closure.nim +++ b/tissues.nim @@ -16,3 +16,13 @@ f(nil) type A = object #of RootObj <-- Uncomment this to get no errors test: proc(i: A): bool var a: proc(i: A): bool # Or comment this line to get no errors + + +# bug #2703 +type + fooObj[T] = object of RootObj + bazObj[T] = object of fooObj[T] + x: T + +var troz: fooObj[string] +echo bazObj[string](troz).x From 6d10baa3391b5dd25e035c83a41ead9bf456be69 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 11 Jul 2020 07:21:59 -0300 Subject: [PATCH 0880/4254] https://github.com/nim-lang/Nim/pull/14948#issuecomment-656498426 (#14958) --- doc/advopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 547005485..135f297c4 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -111,7 +111,7 @@ Advanced options: --skipProjCfg:on|off do not read the project's configuration file --gc:refc|arc|orc|markAndSweep|boehm|go|none|regions select the GC to use; default is 'refc' - --exceptions:setjmp|cpp|goto|quirky + --exceptions:setjmp|cpp|goto select the exception handling implementation --index:on|off turn index file generation on|off --putenv:key=value set an environment variable From 21772b6419b6cb3b59b436fbdcd8975a9da62349 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 11 Jul 2020 23:09:41 +0800 Subject: [PATCH 0881/4254] add testcase for #5926 (#14965) --- tests/generics/t5926.nim | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/generics/t5926.nim diff --git a/tests/generics/t5926.nim b/tests/generics/t5926.nim new file mode 100644 index 000000000..bb14c3af5 --- /dev/null +++ b/tests/generics/t5926.nim @@ -0,0 +1,22 @@ +discard """ +action: compile +""" + +type + SomeObj[T] = object + +template useSomeObj[T]() = + var retObj: SomeObj[T] + +useSomeObj[void]() +useSomeObj[int]() + + +type + Data*[T] = object + x: T + +template test*[T](xxx: T) = + let data = Data[T](x: xxx) + +test(1) From d409694b02ae403501b23a94c21f60ad8edb7365 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 11 Jul 2020 19:17:40 +0200 Subject: [PATCH 0882/4254] :D --- tissues.nim => tests/ccgbugs/tissues.nim | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tissues.nim => tests/ccgbugs/tissues.nim (100%) diff --git a/tissues.nim b/tests/ccgbugs/tissues.nim similarity index 100% rename from tissues.nim rename to tests/ccgbugs/tissues.nim From 9ec9a31f46697a615630fce3614e68e57d390a74 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 12 Jul 2020 15:31:03 +0800 Subject: [PATCH 0883/4254] Fix #12759 (#14967) * add testcase for #5926 * fix #12759 --- lib/pure/terminal.nim | 2 +- tests/stdlib/tterminal_12759.nim | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tterminal_12759.nim diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index e798bbaf1..99a333cc6 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -37,7 +37,7 @@ type var gTerm {.threadvar.}: owned(PTerminal) -proc newTerminal(): owned(PTerminal) {.gcsafe.} +proc newTerminal(): owned(PTerminal) {.gcsafe, raises: [].} proc getTerminal(): PTerminal {.inline.} = if isNil(gTerm): diff --git a/tests/stdlib/tterminal_12759.nim b/tests/stdlib/tterminal_12759.nim new file mode 100644 index 000000000..d6034ab57 --- /dev/null +++ b/tests/stdlib/tterminal_12759.nim @@ -0,0 +1,10 @@ +discard """ + action: "compile" +""" + +import terminal + +proc test() {.raises:[IOError, ValueError].} = + setBackgroundColor(stdout, bgRed) + +test() From 124feb2af87dcbb44e25e7dd4303098ae5e9225d Mon Sep 17 00:00:00 2001 From: Alexander Wolfe <61166+memoryhole@users.noreply.github.com> Date: Sun, 12 Jul 2020 07:07:31 -0700 Subject: [PATCH 0884/4254] nimpretty support for multiple files (#14890) --- nimpretty/nimpretty.nim | 53 ++++++++++++++++++++++++++++++----------- nimpretty/tester.nim | 28 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index 9b5cf556b..bedf9f248 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -14,7 +14,7 @@ when not defined(nimpretty): import ../compiler / [idents, msgs, syntaxes, options, pathutils, layouter] -import parseopt, strutils, os +import parseopt, strutils, os, sequtils const Version = "0.2" @@ -22,9 +22,10 @@ const (c) 2017 Andreas Rumpf Usage: - nimpretty [options] file.nim + nimpretty [options] nimfiles... Options: --out:file set the output file (default: overwrite the input file) + --outDir:dir set the output dir (default: overwrite the input files) --indent:N[=0] set the number of spaces that is used for indentation --indent:0 means autodetection (default behaviour) --maxLineLen:N set the desired maximum line length (default: 80) @@ -61,37 +62,61 @@ proc prettyPrint(infile, outfile: string, opt: PrettyOptions) = closeParsers(p) proc main = - var infile, outfile: string + var outfile, outdir: string + + var infiles = newSeq[string]() + var outfiles = newSeq[string]() + var backup = false # when `on`, create a backup file of input in case # `prettyPrint` could over-write it (note that the backup may happen even # if input is not actually over-written, when nimpretty is a noop). # --backup was un-documented (rely on git instead). var opt = PrettyOptions(indWidth: 0, maxLineLen: 80) + + for kind, key, val in getopt(): case kind of cmdArgument: - infile = key.addFileExt(".nim") + infiles.add(key.addFileExt(".nim")) of cmdLongOption, cmdShortOption: case normalize(key) of "help", "h": writeHelp() of "version", "v": writeVersion() of "backup": backup = parseBool(val) of "output", "o", "out": outfile = val + of "outDir", "outdir": outdir = val of "indent": opt.indWidth = parseInt(val) of "maxlinelen": opt.maxLineLen = parseInt(val) else: writeHelp() of cmdEnd: assert(false) # cannot happen - if infile.len == 0: + if infiles.len == 0: quit "[Error] no input file." - if outfile.len == 0: - outfile = infile - if not fileExists(outfile) or not sameFile(infile, outfile): - backup = false # no backup needed since won't be over-written - if backup: - let infileBackup = infile & ".backup" # works with .nim or .nims - echo "writing backup " & infile & " > " & infileBackup - os.copyFile(source = infile, dest = infileBackup) - prettyPrint(infile, outfile, opt) + + if outfile.len != 0 and outdir.len != 0: + quit "[Error] out and outDir cannot both be specified" + + if outfile.len == 0 and outdir.len == 0: + outfiles = infiles + elif outfile.len != 0 and infiles.len > 1: + # Take the last file to maintain backwards compatibility + let infile = infiles[^1] + infiles = @[infile] + outfiles = @[outfile] + elif outfile.len != 0: + outfiles = @[outfile] + elif outdir.len != 0: + outfiles = infiles.mapIt($(joinPath(outdir, it))) + + for (infile, outfile) in zip(infiles, outfiles): + let (dir, _, _) = splitFile(outfile) + createDir(dir) + if not fileExists(outfile) or not sameFile(infile, outfile): + backup = false # no backup needed since won't be over-written + if backup: + let infileBackup = infile & ".backup" # works with .nim or .nims + echo "writing backup " & infile & " > " & infileBackup + os.copyFile(source = infile, dest = infileBackup) + prettyPrint(infile, outfile, opt) main() diff --git a/nimpretty/tester.nim b/nimpretty/tester.nim index 041e7edd8..6124eb66a 100644 --- a/nimpretty/tester.nim +++ b/nimpretty/tester.nim @@ -1,9 +1,10 @@ # Small program that runs the test cases -import strutils, os +import strutils, os, sequtils const dir = "nimpretty/tests/" + outputdir = dir / "outputdir" var failures = 0 @@ -30,7 +31,25 @@ proc test(infile, ext: string) = else: echo "SUCCESS: files identical: ", nimFile -for t in walkFiles(dir / "*.nim"): +proc testTogether(infiles: seq[string]) = + if execShellCmd("$# --outDir:$# --backup:off $#" % [nimp, outputdir, infiles.join(" ")]) != 0: + echo "FAILURE: nimpretty cannot prettify files: ", $infiles + failures += 1 + return + + for infile in infiles: + let nimFile = splitFile(infile).name + let expected = dir / "expected" / nimFile & ".nim" + let produced = dir / "outputdir" / infile + if readFile(expected) != readFile(produced): + echo "FAILURE: files differ: ", nimFile + discard execShellCmd("diff -uNdr " & expected & " " & produced) + failures += 1 + else: + echo "SUCCESS: files identical: ", nimFile + +let allFiles = toSeq(walkFiles(dir / "*.nim")) +for t in allFiles: test(t, "pretty") # also test that pretty(pretty(x)) == pretty(x) test(t.changeFileExt("pretty"), "pretty2") @@ -38,5 +57,10 @@ for t in walkFiles(dir / "*.nim"): removeFile(t.changeFileExt("pretty")) removeFile(t.changeFileExt("pretty2")) +testTogether(allFiles) +removeDir(outputdir) + + + if failures > 0: quit($failures & " failures occurred.") From 6cc0061a72826022991262eb8e31b97f6fdf37e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 12 Jul 2020 16:50:56 +0200 Subject: [PATCH 0885/4254] optimize the new nimPrepareStrMutationV2 with inlining (#14969) --- lib/system/strs_v2.nim | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index aa644522f..85c0af190 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -132,10 +132,13 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = a.len = b.len copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1) -proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl.} = +proc nimPrepareStrMutationImpl(s: var NimStringV2) = + let oldP = s.p + # can't mutate a literal, so we need a fresh copy here: + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len))) + s.p.cap = s.len + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) + +proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inline.} = if s.p != nil and (s.p.cap and strlitFlag) == strlitFlag: - let oldP = s.p - # can't mutate a literal, so we need a fresh copy here: - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len))) - s.p.cap = s.len - copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) + nimPrepareStrMutationImpl(s) From f4f21c89e57115a57ed97e30a9b9fe6c901ae453 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 14 Jul 2020 08:18:02 +0200 Subject: [PATCH 0886/4254] asyncftpclient.nim - don't assume a sufficiend line length (#14973) --- lib/pure/asyncftpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 2d3556a89..4e62ecd97 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -134,7 +134,7 @@ proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = var line = await ftp.csock.recvLine() result = TaintedString(line) var count = 0 - while line[3] == '-': + while line.len > 3 and line[3] == '-': ## Multi-line reply. line = await ftp.csock.recvLine() string(result).add("\n" & line) From 086efac49b746214c8d39347fa2d96f0f85413b2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 14 Jul 2020 15:22:48 +0800 Subject: [PATCH 0887/4254] fix #6608 (#14963) * fix #6608 --- compiler/semexprs.nim | 11 ++++++++++- tests/errmsgs/t6608.nim | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/errmsgs/t6608.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index de9f2198a..fd9203f34 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -955,8 +955,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = hasErrorType = true break if not hasErrorType: + let typ = n[0].typ msg.add(">\nbut expected one of: \n" & - typeToString(n[0].typ)) + typeToString(typ)) + # prefer notin preferToResolveSymbols + # t.sym != nil + # sfAnon notin t.sym.flags + # t.kind != tySequence(It is tyProc) + if typ.sym != nil and sfAnon notin typ.sym.flags and + typ.kind == tyProc: + msg.add(" = " & + typeToString(typ, preferDesc)) localError(c.config, n.info, msg) return errorNode(c, n) result = nil diff --git a/tests/errmsgs/t6608.nim b/tests/errmsgs/t6608.nim new file mode 100644 index 000000000..3d82f3cd8 --- /dev/null +++ b/tests/errmsgs/t6608.nim @@ -0,0 +1,16 @@ +discard """ + cmd: "nim c --hints:off $file" + errormsg: "type mismatch: got <>" + nimout: '''t6608.nim(14, 4) Error: type mismatch: got <> +but expected one of: +AcceptCB = proc (s: string){.closure.}''' + line: 14 +""" + +type + AcceptCB = proc (s: string) + +proc x(x: AcceptCB) = + x() + +x() From ffaf4797be4a8e8aec5ada9863ccdec66a066930 Mon Sep 17 00:00:00 2001 From: jcosborn Date: Tue, 14 Jul 2020 04:24:17 -0500 Subject: [PATCH 0888/4254] add full tests from #9463 (#14975) --- tests/generics/t4668.nim | 172 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 161 insertions(+), 11 deletions(-) diff --git a/tests/generics/t4668.nim b/tests/generics/t4668.nim index 0d1b18111..bd44cc975 100644 --- a/tests/generics/t4668.nim +++ b/tests/generics/t4668.nim @@ -1,16 +1,166 @@ discard """ -action: compile + output: ''' +foo1 +foo2 +''' """ -type - FooObj*[T] = object - v*: T - Foo1*[T] = FooObj[T] - Foo2* = FooObj +block: + type + FooObj[T] = object + v: T + Foo1[T] = FooObj[T] + Foo2 = FooObj -proc foo1(x: Foo1) = echo "foo1" -proc foo2(x: Foo2) = echo "foo2" + proc foo1(x: Foo1) = echo "foo1" + proc foo2(x: Foo2) = echo "foo2" -var x: FooObj[float] -foo1(x) # works -foo2(x) # works + var x: FooObj[float] + foo1(x) # works + foo2(x) # works + +block: + type + FooObj[T] = T + Foo1[T] = FooObj[T] + Foo2 = FooObj + Foo3 = Foo1 + Foo4x = FooObj[SomeInteger] + Foo4 = FooObj[SomeFloat] + Foo5x = Foo1[SomeInteger] + Foo5 = Foo1[SomeFloat] + + proc foo0(x: FooObj): int = 0 + proc foo1(x: Foo1): int = 1 + proc foo2(x: Foo2): int = 2 + proc foo3(x: Foo3): int = 3 + proc foo4(x: Foo4x): int = 40 + proc foo4(x: Foo4): int = 4 + proc foo5(x: Foo5x): int = 50 + proc foo5(x: Foo5): int = 5 + + block: + var x: FooObj[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo1[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo2[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + +block: + type + FooObj[T,U] = object + x: T + y: U + Foo1[U,T] = FooObj[T,U] + Foo2 = FooObj + Foo3 = Foo1 + Foo4x = FooObj[SomeInteger,SomeInteger] + Foo4y = FooObj[SomeInteger,SomeFloat] + Foo4z = FooObj[SomeFloat,SomeFloat] + Foo4 = FooObj[SomeFloat,SomeInteger] + Foo5x = Foo1[SomeInteger,SomeInteger] + Foo5y = Foo1[SomeFloat,SomeInteger] + Foo5z = Foo1[SomeFloat,SomeFloat] + Foo5 = Foo1[SomeInteger,SomeFloat] + + proc foo0(x: FooObj): int = 0 + proc foo1(x: Foo1): int = 1 + proc foo2(x: Foo2): int = 2 + proc foo3(x: Foo3): int = 3 + proc foo4(x: Foo4x): int = 40 + proc foo4(x: Foo4y): int = 41 + proc foo4(x: Foo4z): int = 42 + proc foo4(x: Foo4): int = 4 + proc foo5(x: Foo5x): int = 50 + proc foo5(x: Foo5y): int = 51 + proc foo5(x: Foo5z): int = 52 + proc foo5(x: Foo5): int = 5 + + block: + var x: FooObj[float,int] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo1[int,float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + +block: + type + FooObj[T] = object of RootObj + v: T + FooObj2[T] = object of FooObj[T] + Foo1[T] = FooObj[T] + Foo2 = FooObj + Foo3 = Foo1 + Foo4x = FooObj[SomeInteger] + Foo4 = FooObj[SomeFloat] + Foo5x = Foo1[SomeInteger] + Foo5 = Foo1[SomeFloat] + + proc foo0(x: FooObj): int = 0 + proc foo1(x: Foo1): int = 1 + proc foo2(x: Foo2): int = 2 + proc foo3(x: Foo3): int = 3 + proc foo4(x: Foo4x): int = 40 + proc foo4(x: Foo4): int = 4 + proc foo5(x: Foo5x): int = 50 + proc foo5(x: Foo5): int = 5 + + block: + var x: FooObj[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo1[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + #[ XXX These still fail + block: + var x: FooObj2[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + ]# From e07d661d1600989c281a270d90563f1c60392b9d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 14 Jul 2020 04:14:32 -0700 Subject: [PATCH 0889/4254] fix #14475; unittest.require now works with `nim c`; require and check now works with -d:nodejs (#14676) * fix #14475; make unittest work with -d:nodejs * fixup * fixup * disable inim, delaunay which failed after unittest.require got fixed * re-enable tests that have been fixed --- lib/pure/unittest.nim | 13 ++++++------- lib/std/exitprocs.nim | 22 ++++++++++++++++++++++ lib/system.nim | 7 ++----- tests/js/tunittest_error.nim | 2 ++ tests/stdlib/tquit.nim | 2 +- tests/stdlib/tunittest_error.nim | 22 ++++++++++++++++++++++ 6 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 tests/stdlib/tunittest_error.nim diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index bea7d9c44..f3d920d0e 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -94,6 +94,7 @@ ## echo "suite teardown: run once after the tests" import std/private/since +import std/exitprocs import macros, strutils, streams, times, sets, sequtils @@ -498,7 +499,7 @@ template test*(name, body) {.dirty.} = ## .. code-block:: ## ## [OK] roses are red - bind shouldRun, checkpoints, formatters, ensureInitialized, testEnded, exceptionTypeName + bind shouldRun, checkpoints, formatters, ensureInitialized, testEnded, exceptionTypeName, setProgramResult ensureInitialized() @@ -524,7 +525,7 @@ template test*(name, body) {.dirty.} = finally: if testStatusIMPL == TestStatus.FAILED: - programResult = 1 + setProgramResult 1 let testResult = TestResult( suiteName: when declared(testSuiteName): testSuiteName else: "", testName: name, @@ -560,12 +561,11 @@ template fail* = ## fail() ## ## outputs "Checkpoint A" before quitting. - bind ensureInitialized - + bind ensureInitialized, setProgramResult when declared(testStatusIMPL): testStatusIMPL = TestStatus.FAILED else: - programResult = 1 + setProgramResult 1 ensureInitialized() @@ -576,8 +576,7 @@ template fail* = else: formatter.failureOccurred(checkpoints, "") - when declared(programResult): - if abortOnError: quit(programResult) + if abortOnError: quit(1) checkpoints = @[] diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index b2811735c..c6537f7f8 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -63,3 +63,25 @@ proc addExitProc*(cl: proc() {.noconv.}) = withLock gFunsLock: fun() gFuns.add Fun(kind: kNoconv, fun2: cl) + +when not defined(nimscript): + proc getProgramResult*(): int = + when defined(js) and defined(nodejs): + asm """ +`result` = process.exitCode; +""" + elif not defined(js): + result = programResult + else: + doAssert false + + proc setProgramResult*(a: int) = + # pending https://github.com/nim-lang/Nim/issues/14674 + when defined(js) and defined(nodejs): + asm """ +process.exitCode = `a`; +""" + elif not defined(js): + programResult = a + else: + doAssert false diff --git a/lib/system.nim b/lib/system.nim index 822454626..71eed5bee 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1127,12 +1127,9 @@ const ## is the value that should be passed to `quit <#quit,int>`_ to indicate ## failure. -when defined(js) and defined(nodejs) and not defined(nimscript): - var programResult* {.importc: "process.exitCode".}: int - programResult = 0 -elif hostOS != "standalone": +when not defined(js) and hostOS != "standalone": var programResult* {.compilerproc, exportc: "nim_program_result".}: int - ## deprecated, prefer ``quit`` + ## deprecated, prefer `quit` or `exitprocs.getProgramResult`, `exitprocs.setProgramResult`. import std/private/since diff --git a/tests/js/tunittest_error.nim b/tests/js/tunittest_error.nim index ab736bf59..781e34338 100644 --- a/tests/js/tunittest_error.nim +++ b/tests/js/tunittest_error.nim @@ -3,6 +3,8 @@ discard """ outputsub: "[FAILED] with exception" """ +# see also: `tests/stdlib/tunittest_error.nim` + import unittest proc ddd() = diff --git a/tests/stdlib/tquit.nim b/tests/stdlib/tquit.nim index 1f9283ec4..0b4a479dc 100644 --- a/tests/stdlib/tquit.nim +++ b/tests/stdlib/tquit.nim @@ -5,7 +5,7 @@ just exiting... joinable: false """ -# Test the new beforeQuit variable: +# Test `addQuitProc` proc myExit() {.noconv.} = write(stdout, "just exiting...\n") diff --git a/tests/stdlib/tunittest_error.nim b/tests/stdlib/tunittest_error.nim new file mode 100644 index 000000000..7f05ec2a9 --- /dev/null +++ b/tests/stdlib/tunittest_error.nim @@ -0,0 +1,22 @@ +discard """ + exitcode: 1 + outputsub: "failed: 1 == 3" + matrix: "-d:case1; -d:case2" + targets: "c js" + joinable: false +""" + +when defined case1: + import unittest + suite "Test": + test "test require": + check 1==2 + check 1==3 + +when defined case2: + import unittest + suite "Test": + test "test require": + require 1 == 3 + if true: + quit 0 # intentional From 9ed0dbfa6e92f4aa1ebb8ac2ac48af97ae72dbbb Mon Sep 17 00:00:00 2001 From: Hendrik Date: Tue, 14 Jul 2020 13:15:22 +0200 Subject: [PATCH 0890/4254] fix index error (#14974) Co-authored-by: Hendrik Albers --- lib/pure/logging.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 2e79cd3ca..fa6285a04 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -287,6 +287,7 @@ proc substituteLog*(frmt: string, level: Level, runnableExamples: doAssert substituteLog(defaultFmtStr, lvlInfo, "a message") == "INFO a message" doAssert substituteLog("$levelid - ", lvlError, "an error") == "E - an error" + doAssert substituteLog("$levelid", lvlDebug, "error") == "Derror" var msgLen = 0 for arg in args: msgLen += arg.len @@ -300,7 +301,7 @@ proc substituteLog*(frmt: string, level: Level, inc(i) var v = "" let app = when defined(js): "" else: getAppFilename() - while frmt[i] in IdentChars: + while i < frmt.len and frmt[i] in IdentChars: v.add(toLowerAscii(frmt[i])) inc(i) case v From f999f916f31946be3cf8abc485fc07e0d89de9ae Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 14 Jul 2020 19:53:41 +0800 Subject: [PATCH 0891/4254] add missing props,procs (#14978) --- lib/js/dom.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 575ec3deb..be676a813 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -196,6 +196,9 @@ type innerText*: cstring textContent*: cstring style*: Style + baseURI*: cstring + parentElement*: Element + isConnected*: bool Document* = ref DocumentObj DocumentObj {.importc.} = object of NodeObj @@ -224,6 +227,7 @@ type Element* = ref ElementObj ElementObj {.importc.} = object of NodeObj + className*: cstring classList*: ClassList checked*: bool defaultChecked*: bool @@ -1481,6 +1485,7 @@ proc getAttribute*(n: Node, attr: cstring): cstring proc getAttributeNode*(n: Node, attr: cstring): Node proc hasAttribute*(n: Node, attr: cstring): bool proc hasChildNodes*(n: Node): bool +proc normalize*(n: Node) proc insertData*(n: Node, position: int, data: cstring) proc removeAttribute*(n: Node, attr: cstring) proc removeAttributeNode*(n, attr: Node) @@ -1490,6 +1495,13 @@ proc setAttribute*(n: Node, name, value: cstring) proc setAttributeNode*(n: Node, attr: Node) proc querySelector*(n: Node, selectors: cstring): Element proc querySelectorAll*(n: Node, selectors: cstring): seq[Element] +proc compareDocumentPosition*(n: Node, otherNode:Node): int +proc lookupPrefix*(n: Node): cstring +proc lookupNamespaceURI*(n: Node): cstring +proc isDefaultNamespace*(n: Node): bool +proc contains*(n: Node): bool +proc isEqualNode*(n: Node): bool +proc isSameNode*(n: Node): bool # Document "methods" proc createAttribute*(d: Document, identifier: cstring): Node From 2b0e336c971401d06797240686722ce669d902b9 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 14 Jul 2020 14:15:39 +0200 Subject: [PATCH 0892/4254] injectdestructors fixes and refactor (#14964) * injectdestructors fixes and refactor * Tiny cleanup * Refactor and expand testcase * Closes #14902 by adding testcase * Better naming * Fix test failures * Misc cleanup * Add testcase for #14968 * Better approach; expand testcases * Optimizations and fixes * Add testcase * typo * Tiny cleanup --- compiler/dfa.nim | 2 +- compiler/injectdestructors.nim | 301 ++++++++++----------------- tests/arc/tarcmisc.nim | 38 +++- tests/arc/tcontrolflow.nim | 4 +- tests/arc/tmovebug.nim | 169 +++++++++++++++ tests/destructor/tmove_objconstr.nim | 1 - 6 files changed, 317 insertions(+), 198 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 2254cd0ff..f3b358d72 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -628,7 +628,7 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = # XXX Allow closure deref operations here if we know # the owner controlled the closure allocation? result = n.kind == nkSym and n.sym.owner == owner and - owner.kind != skModule and + sfGlobal notin n.sym.flags and (n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar) # Note: There is a different move analyzer possible that checks for # consume(param.key); param.key = newValue for all paths. Then code like diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index da41b2d5c..ff311f079 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -37,18 +37,12 @@ type final: seq[PNode] # finally section needsTry: bool parent: ptr Scope - escapingSyms: IntSet # a construct like (block: let x = f(); x) - # means that 'x' escapes. We then destroy it - # in the parent's scope (and also allocate it there). - escapingExpr: PNode type Con = object owner: PSym g: ControlFlowGraph - jumpTargets: IntSet graph: ModuleGraph - emptyNode: PNode otherRead: PNode inLoop, inSpawn: int uninit: IntSet # set of uninit'ed vars @@ -72,12 +66,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = s.vars.add(sym) result = newSymNode(sym) +const sfSingleUsedTemp = sfExported # For temporaries that we know will only be used once + proc nestedScope(parent: var Scope): Scope = Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) -proc rememberParent(parent: var Scope; inner: Scope) {.inline.} = - parent.needsTry = parent.needsTry or inner.needsTry - proc optimize(s: var Scope) = # optimize away simple 'wasMoved(x); destroy(x)' pairs. #[ Unfortunately this optimization is only really safe when no exceptions @@ -124,68 +117,6 @@ proc optimize(s: var Scope) = filterNil(wasMoved) filterNil(final) -type - ToTreeFlag = enum - onlyCareAboutVars, - producesValue - -proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = - proc isComplexStmtListExpr(n: PNode): bool = - n.kind == nkStmtListExpr and (n.len == 0 or n[^1].kind != nkSym) - - #if not s.needsTry: optimize(s) - assert ret != nil - if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: - # trivial, nothing was done: - result = ret - else: - let isExpr = producesValue in flags and not isEmptyType(ret.typ) - var r = PNode(nil) - if isExpr: - result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) - if ret.kind in nkCallKinds or isComplexStmtListExpr(ret): - r = c.getTemp(s, ret.typ, ret.info) - else: - result = newNodeI(nkStmtList, ret.info) - - if s.vars.len > 0: - let varSection = newNodeI(nkVarSection, ret.info) - for tmp in s.vars: - varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), - newNodeI(nkEmpty, ret.info)) - result.add varSection - if onlyCareAboutVars in flags: - result.add ret - s.vars.setLen 0 - elif s.needsTry: - var finSection = newNodeI(nkStmtList, ret.info) - for m in s.wasMoved: finSection.add m - for i in countdown(s.final.high, 0): finSection.add s.final[i] - result.add newTryFinally(ret, finSection) - else: - if r != nil: - if ret.kind == nkStmtListExpr: - # simplify it a bit further by merging the nkStmtListExprs - let last = ret.len - 1 - for i in 0 ..< last: result.add ret[i] - result.add newTree(nkFastAsgn, r, ret[last]) - else: - result.add newTree(nkFastAsgn, r, ret) - for m in s.wasMoved: result.add m - for i in countdown(s.final.high, 0): result.add s.final[i] - result.add r - elif ret.kind == nkStmtListExpr: - # simplify it a bit further by merging the nkStmtListExprs - let last = ret.len - 1 - for i in 0 ..< last: result.add ret[i] - for m in s.wasMoved: result.add m - for i in countdown(s.final.high, 0): result.add s.final[i] - result.add ret[last] - else: - result.add ret - for m in s.wasMoved: result.add m - for i in countdown(s.final.high, 0): result.add s.final[i] - proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode @@ -228,6 +159,7 @@ proc isLastRead(n: PNode; c: var Con): bool = # first we need to search for the instruction that belongs to 'n': var instr = -1 let m = dfa.skipConvDfa(n) + if m.kind == nkSym and sfSingleUsedTemp in m.sym.flags: return true for i in 0.. 0: - it = it[^1] - s.escapingExpr = it - proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = # move the variable declaration to the top of the frame: - let owningScope = c.addTopVar(s, v) + s.vars.add v.sym if isUnpackedTuple(v): if c.inLoop > 0: # unpacked tuple needs reset at every loop iteration res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) elif sfThread notin v.sym.flags: # do not destroy thread vars for now at all for consistency. - if sfGlobal in v.sym.flags and s.parent == nil: - c.graph.globalDestructors.add c.genDestroy(v) #No need to genWasMoved here + if sfGlobal in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2) + c.graph.globalDestructors.add c.genDestroy(v) else: - owningScope[].final.add c.genDestroy(v) + s.final.add c.genDestroy(v) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: res.add moveOrCopy(v, ri, c, s, isDecl = true) -template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = +proc processScope(c: var Con; s: var Scope; ret: PNode): PNode = + result = newNodeI(nkStmtList, ret.info) + if s.vars.len > 0: + let varSection = newNodeI(nkVarSection, ret.info) + for tmp in s.vars: + varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), + newNodeI(nkEmpty, ret.info)) + result.add varSection + if s.wasMoved.len > 0 or s.final.len > 0: + let finSection = newNodeI(nkStmtList, ret.info) + for m in s.wasMoved: finSection.add m + for i in countdown(s.final.high, 0): finSection.add s.final[i] + if s.needsTry: + result.add newTryFinally(ret, finSection) + else: + result.add ret + result.add finSection + else: + result.add ret + + if s.parent != nil: s.parent[].needsTry = s.parent[].needsTry or s.needsTry + +template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped): PNode = + assert not ret.typ.isEmptyType + var result = newNodeI(nkStmtListExpr, ret.info) + # There is a possibility to do this check: s.wasMoved.len > 0 or s.final.len > 0 + # later and use it to eliminate the temporary when theres no need for it, but its + # tricky because you would have to intercept moveOrCopy at a certain point + let tmp = c.getTemp(s.parent[], ret.typ, ret.info) + tmp.sym.flags.incl sfSingleUsedTemp + let cpy = if ret.typ.hasDestructor: + moveOrCopy(tmp, ret, c, s, isDecl = true) + else: + newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) + + if s.vars.len > 0: + let varSection = newNodeI(nkVarSection, ret.info) + for tmp in s.vars: + varSection.add newTree(nkIdentDefs, newSymNode(tmp), newNodeI(nkEmpty, ret.info), + newNodeI(nkEmpty, ret.info)) + result.add varSection + let finSection = newNodeI(nkStmtList, ret.info) + for m in s.wasMoved: finSection.add m + for i in countdown(s.final.high, 0): finSection.add s.final[i] + if s.needsTry: + result.add newTryFinally(newTree(nkStmtListExpr, cpy, processCall(tmp, s.parent[])), finSection) + else: + result.add cpy + result.add finSection + result.add processCall(tmp, s.parent[]) + + if s.parent != nil: s.parent[].needsTry = s.parent[].needsTry or s.needsTry + + result + +template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = template maybeVoid(child, s): untyped = if isEmptyType(child.typ): p(child, c, s, normal) else: processCall(child, s) - let treeFlags = if not isEmptyType(n.typ) and not alwaysStmt: {producesValue} else: {} case n.kind of nkStmtList, nkStmtListExpr: # a statement list does not open a new scope if n.len == 0: return n result = copyNode(n) - if alwaysStmt: result.typ = nil for i in 0..---------transformed-to--------->" echo renderTree(result, {renderIds}) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index b6d9d781d..2d7e6b455 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -3,6 +3,11 @@ discard """ 123xyzabc destroyed: false destroyed: false +destroyed2: false +destroyed2: false +destroying variable: 2 +destroying variable: 1 +whiley ends :( 1 (x: "0") (x: "1") @@ -17,7 +22,8 @@ destroyed: false (x: "10") 0 closed -destroying variable +destroying variable: 20 +destroying variable: 10 ''' cmd: "nim c --gc:arc $file" """ @@ -40,11 +46,12 @@ type Variable = ref object value: int proc `=destroy`(self: var typeof(Variable()[])) = - echo "destroying variable" + echo "destroying variable: ",self.value proc newVariable(value: int): Variable = result = Variable() result.value = value + #echo "creating variable: ",result.value proc test(count: int) = var v {.global.} = newVariable(10) @@ -57,6 +64,28 @@ proc test(count: int) = test(3) +proc test2(count: int) = + #block: #XXX: Fails with block currently + var v {.global.} = newVariable(20) + + var count = count - 1 + if count == 0: return + + test2(count) + echo "destroyed2: ", v.isNil + +test2(3) + +proc whiley = + var a = newVariable(1) + while true: + var b = newVariable(2) + if true: raise newException(CatchableError, "test") + +try: + whiley() +except CatchableError: + echo "whiley ends :(" #------------------------------------------------------------------------------ # issue #13810 @@ -209,3 +238,8 @@ proc setParent(self: SimpleLoopB, parent: SimpleLoopB) = var l = SimpleLoopB() l.setParent(l) + + +# bug #14968 +import times +let currentTime = now().utc diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim index 41f614cb2..80cc2b187 100644 --- a/tests/arc/tcontrolflow.nim +++ b/tests/arc/tcontrolflow.nim @@ -1,12 +1,12 @@ discard """ output: '''begin A elif -destroyed end A +destroyed begin false if -destroyed end false +destroyed begin true if end true diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index ec0fce9a8..424785ed7 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -40,6 +40,33 @@ sink me (not sink) sinked and not optimized to a bitcopy sinked and not optimized to a bitcopy sinked and not optimized to a bitcopy +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +100 +hey +hey +(a: "a", b: 2) +ho +(a: "b", b: 3) +(b: "b", a: 2) +ho +(b: "a", a: 3) +hey +break +break +hey +ho +hey +ho +ho +king +live long; long live +king ''' """ @@ -325,3 +352,145 @@ proc update() = for i in 1..3: update() + + +# bug #14961 +type + Foo = object + data: seq[int] + +proc initFoo(len: int): Foo = + result = (let s = newSeq[int](len); Foo(data: s) ) + +var f = initFoo(2) +echo initFoo(2) + +proc initFoo2(len: int) = + echo if true: + let s = newSeq[int](len); Foo(data: s) + else: + let s = newSeq[int](len); Foo(data: s) + +initFoo2(2) + +proc initFoo3(len: int) = + echo (block: + let s = newSeq[int](len); Foo(data: s)) + +initFoo3(2) + +proc initFoo4(len: int) = + echo (let s = newSeq[int](len); Foo(data: s)) + +initFoo4(2) + +proc initFoo5(len: int) = + echo (case true + of true: + let s = newSeq[int](len); Foo(data: s) + of false: + let s = newSeq[int](len); Foo(data: s)) + +initFoo5(2) + +proc initFoo6(len: int) = + echo (block: + try: + let s = newSeq[int](len); Foo(data: s) + finally: discard) + +initFoo6(2) + +proc initFoo7(len: int) = + echo (block: + try: + raise newException(CatchableError, "sup") + let s = newSeq[int](len); Foo(data: s) + except CatchableError: + let s = newSeq[int](len); Foo(data: s) ) + +initFoo7(2) + + +# bug #14902 +iterator zip[T](s: openarray[T]): (T, T) = + var i = 0 + while i < 10: + yield (s[i mod 2], s[i mod 2 + 1]) + inc i + +var lastMem = int.high + +proc leak = + const len = 10 + var x = @[newString(len), newString(len), newString(len)] + + var c = 0 + for (a, b) in zip(x): + let newMem = getOccupiedMem() + assert newMem <= lastMem + lastMem = newMem + c += a.len + echo c + +leak() + + +proc consume(a: sink string) = echo a + +proc weirdScopes = + if (let a = "hey"; a.len > 0): + echo a + + while (let a = "hey"; a.len > 0): + echo a + break + + var a = block: (a: "a", b: 2) + echo a + (discard; a) = (echo "ho"; (a: "b", b: 3)) + echo a + + var b = try: (b: "b", a: 2) + except: raise + echo b + (discard; b) = (echo "ho"; (b: "a", a: 3)) + echo b + + var s = "break" + consume((echo "hey"; s)) + echo s + + echo (block: + var a = "hey" + (echo "hey"; "ho")) + + var b2 = "ho" + echo (block: + var a = "hey" + (echo "hey"; b2)) + echo b2 + + type status = enum + alive + + var king = "king" + echo (block: + var a = "a" + when true: + var b = "b" + case alive + of alive: + try: + var c = "c" + if true: + king + else: + "the abyss" + except: + echo "he ded" + "dead king") + echo "live long; long live" + echo king + +weirdScopes() diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 0740bd46b..16d0daa22 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -2,7 +2,6 @@ discard """ output: '''test created test destroyed 0 -Pony is dying! 1 2 3 From 9465b5db443b98d7ac2c1683e986716fb9a9290f Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 14 Jul 2020 11:44:56 -0300 Subject: [PATCH 0893/4254] Clean up macros (#14959) --- changelog.md | 2 +- examples/talk/formatoptimizer.nim | 2 +- lib/core/macros.nim | 34 ----------------------------- lib/pure/unittest.nim | 2 +- testament/important_packages.nim | 2 +- tests/macros/tmemit.nim | 3 --- tests/showoff/tformatopt.nim | 2 +- tests/usingstmt/tusingstatement.nim | 2 +- 8 files changed, 6 insertions(+), 43 deletions(-) diff --git a/changelog.md b/changelog.md index 36582eee2..e30e9038b 100644 --- a/changelog.md +++ b/changelog.md @@ -139,7 +139,7 @@ - Tables, HashSets, SharedTables and deques don't require anymore that the passed initial size must be a power of two - this is done internally. Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. - +- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. ## Language changes diff --git a/examples/talk/formatoptimizer.nim b/examples/talk/formatoptimizer.nim index 104214e19..6e3d0c2c3 100644 --- a/examples/talk/formatoptimizer.nim +++ b/examples/talk/formatoptimizer.nim @@ -33,7 +33,7 @@ macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped = #newCall("&") let f = f.strVal formatImpl(newLit) - result = nestList(!"&", result) + result = nestList(newIdentNode("&"), result) template optAdd1{x = y; add(x, z)}(x, y, z: string) = x = y & z diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 838707280..7b03d4e4d 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -140,10 +140,6 @@ const {.push warnings: off.} -proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated: - "Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".} - ## Constructs an identifier from the string `s`. - proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated: "Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".} ## Constructs an identifier from the string `s`. @@ -393,13 +389,6 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect, de {.pop.} -#proc `typ=`*(n: NimNode, typ: typedesc) {.magic: "NSetType".} -# this is not sound! Unfortunately forbidding 'typ=' is not enough, as you -# can easily do: -# let bracket = semCheck([1, 2]) -# let fake = semCheck(2.0) -# bracket[0] = fake # constructs a mixed array with ints and floats! - proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.} ## Sets the string value of a string literal or comment. ## Setting `strVal` is disallowed for `nnkIdent` and `nnkSym` nodes; a new node @@ -830,14 +819,6 @@ proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime for i in countdown(pack.len - 1, 0): result = newCall(op, pack[i], result) -{.push warnings: off.} - -proc nestList*(theProc: NimIdent, x: NimNode): NimNode {.compileTime, deprecated: - "Deprecated since v0.18.1; use one of 'nestList(NimNode, ...)' instead.".} = - nestList(newIdentNode(theProc), x) - -{.pop.} - proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indented = false) {.benign.} = if level > 0: if indented: @@ -1628,21 +1609,6 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = if result.kind == nnkEmpty: error(n.repr & " doesn't have a pragma named " & cp.repr()) # returning an empty node results in most cases in a cryptic error, - -when not defined(booting): - template emit*(e: static[string]): untyped {.deprecated.} = - ## Accepts a single string argument and treats it as nim code - ## that should be inserted verbatim in the program - ## Example: - ## - ## .. code-block:: nim - ## emit("echo " & '"' & "hello world".toUpper & '"') - ## - ## Deprecated since version 0.15 since it's so rarely useful. - macro payload: untyped {.gensym.} = - result = parseStmt(e) - payload() - macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped = result = newCall(callee) for i in 0 ..< args.len: diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index f3d920d0e..98be959e3 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -678,7 +678,7 @@ macro check*(conditions: untyped): untyped = result = newNimNode(nnkStmtList) for node in checked: if node.kind != nnkCommentStmt: - result.add(newCall(!"check", node)) + result.add(newCall(newIdentNode("check"), node)) else: let lineinfo = newStrLitNode(checked.lineInfo) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 972bb3faa..58f07b017 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -9,7 +9,7 @@ var packages2*: seq[tuple[name, cmd: string; hasDeps: bool; url: string, useHead # packages A-M -pkg1 "alea", true +# pkg1 "alea", true pkg1 "argparse" pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim index 06ab8a1e2..6c9f9f935 100644 --- a/tests/macros/tmemit.nim +++ b/tests/macros/tmemit.nim @@ -1,6 +1,5 @@ discard """ output: ''' -HELLO WORLD c_func 12 ''' @@ -8,8 +7,6 @@ c_func import macros, strutils -emit("echo " & '"' & "hello world".toUpperAscii & '"') - # bug #1025 macro foo(icname): untyped = diff --git a/tests/showoff/tformatopt.nim b/tests/showoff/tformatopt.nim index 6e790c38e..420dd026b 100644 --- a/tests/showoff/tformatopt.nim +++ b/tests/showoff/tformatopt.nim @@ -37,7 +37,7 @@ macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped = result = newNimNode(nnkBracket) let f = f.strVal formatImpl(newLit) - result = nestList(!"&", result) + result = nestList(newIdentNode("&"), result) template optAdd1{x = y; add(x, z)}(x, y, z: string) = x = y & z diff --git a/tests/usingstmt/tusingstatement.nim b/tests/usingstmt/tusingstatement.nim index 6e4998892..dd4cf589d 100644 --- a/tests/usingstmt/tusingstatement.nim +++ b/tests/usingstmt/tusingstatement.nim @@ -38,7 +38,7 @@ macro autoClose(args: varargs[untyped]): untyped = varAssignment.add(varValue) variables.add(varAssignment) - closingCalls.add(newCall(!"close", varName)) + closingCalls.add(newCall(newIdentNode("close"), varName)) else: error "Using statement: Unexpected expression. Got " & $args[i].kind & " instead of assignment." From 03b0374e5cec82146ead8468db0826c287378a13 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 14 Jul 2020 18:36:06 +0200 Subject: [PATCH 0894/4254] Closes #8426 --- tests/generics/tgenerics_issues.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 54360f178..986066a77 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -23,6 +23,7 @@ concrete 88 G:0,1:0.1 G:0,1:0.1 H:1:0.1 +0 ''' joinable: false """ @@ -780,3 +781,16 @@ block: # issue #9458 discard foo(1) + + +# bug #8426 +type + MyBool[T: uint] = range[T(0)..T(1)] # Works + +var x: MyBool[uint] +echo x + +# x = 2 # correctly prevented + +type + MyBool2 = range[uint(0)..uint(1)] # Error ordinal or float type expected From 695a537c054c5b4e2d8d50e349bef3dfdf15800e Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 14 Jul 2020 18:38:45 +0200 Subject: [PATCH 0895/4254] Closes #13253 --- tests/macros/tmacros_issues.nim | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index 23c9c66c0..255a98ba9 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -29,6 +29,12 @@ array[0 .. 100, int] 10 test 0o377'i8 +1 +2 +3 +foo1 +foo2 +foo3 ''' """ @@ -258,3 +264,28 @@ macro foobar() = echo loopVars foobar() + + +# bug #13253 +import macros + +type + FooBar = object + a: seq[int] + +macro genFoobar(a: static FooBar): untyped = + result = newStmtList() + for b in a.a: + result.add(newCall(bindSym"echo", newLit b)) + +proc foobar(a: static FooBar) = + genFoobar(a) # removing this make it work + for b in a.a: + echo "foo" & $b + +proc main() = + const a: seq[int] = @[1, 2,3] + # Error: type mismatch: got but expected 'seq[int]' + const fb = Foobar(a: a) + foobar(fb) +main() From ddfb7d9877920564ceec7863930380d21aa23f47 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 14 Jul 2020 18:44:16 +0200 Subject: [PATCH 0896/4254] Closes #10396 --- tests/generics/tgenerics_issues.nim | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 986066a77..cdbaf885e 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -24,6 +24,9 @@ G:0,1:0.1 G:0,1:0.1 H:1:0.1 0 +(foo: None[seq[Foo]], s: "") +(foo: Some(@[(a: "world", bar: None[Bar])]), s: "hello,") +@[(a: "hey", bar: None[Bar])] ''' joinable: false """ @@ -794,3 +797,55 @@ echo x type MyBool2 = range[uint(0)..uint(1)] # Error ordinal or float type expected + + +# bug #10396 +import options, strutils + +type + Foo {.acyclic.} = object + a: string + bar: Option[Bar] + + Bar {.acyclic.} = object + foo: Option[seq[Foo]] # if this was just Option[Foo], everything works fine + s: string + +proc getBar(x: string): Bar + +proc intoFoos(ss: seq[string]): seq[Foo] = + result = @[] + for s in ss: + let spl = s.split(',') + if spl.len > 1: + result.add Foo(a: spl[0], + bar: some(getBar(spl[1]))) + else: + result.add Foo(a: s, + bar: none[Bar]()) + +proc getBar(x: string): Bar = + let spl = x.split(' ') + result = + if spl.len > 1: + Bar(foo: some(spl[1..high(spl)].intoFoos), + s: spl[0]) + else: + Bar(foo: none[seq[Foo]](), + s: "") + +proc fakeReadLine(): TaintedString = "hey" + +echo getBar(fakeReadLine()) # causes error + +echo getBar("hello, world") # causes error + +discard $getBar(fakeReadLine()) # causes error + +discard $getBar("hello, world") # causes error + +discard getBar(fakeReadLine()) # no error + +discard getBar("hello, world") # no error + +echo intoFoos(fakeReadLine().split(' ')) # no error, works as expected From f2b041f1684430d0118864b3900c54a1bfc15fa3 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 14 Jul 2020 19:33:10 +0200 Subject: [PATCH 0897/4254] Reenable a few tests --- tests/generics/texplicitgeneric2.nim | 7 +++---- tests/misc/tnoforward.nim | 2 +- tests/trmacros/tdisallowif.nim | 5 ++--- tests/typerel/ttypenovalue.nim | 3 +-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/generics/texplicitgeneric2.nim b/tests/generics/texplicitgeneric2.nim index 573b10ae8..37b133130 100644 --- a/tests/generics/texplicitgeneric2.nim +++ b/tests/generics/texplicitgeneric2.nim @@ -1,6 +1,5 @@ discard """ output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13" - disabled: true """ # test explicit type instantiation @@ -14,12 +13,12 @@ proc newDict*[TKey, TValue](): PDict[TKey, TValue] = new(result) result.data = @[] -proc add*(d: PDict, k: TKey, v: TValue) = +proc add*(d: PDict, k: d.TKey, v: d.TValue) = d.data.add((k, v)) -#iterator items*(d: PDict): tuple[k: TKey, v: TValue] = -# for k, v in items(d.data): yield (k, v) +iterator items*(d: PDict): tuple[k: d.TKey, v: d.TValue] = + for k, v in items(d.data): yield (k, v) var d = newDict[int, string]() d.add(12, "12") diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim index 3e96e3489..b6a71897a 100644 --- a/tests/misc/tnoforward.nim +++ b/tests/misc/tnoforward.nim @@ -1,5 +1,5 @@ discard """ - disabled: true + output: "10" """ # {. noforward: on .} diff --git a/tests/trmacros/tdisallowif.nim b/tests/trmacros/tdisallowif.nim index 36f60800e..8d83f6ddf 100644 --- a/tests/trmacros/tdisallowif.nim +++ b/tests/trmacros/tdisallowif.nim @@ -1,7 +1,6 @@ discard """ - errormsg: "usage of 'disallowIf' is a user-defined error" + errormsg: "usage of 'disallowIf' is an {.error.} defined at tdisallowif.nim(10, 1)" line: 24 - disabled: true """ template optZero{x+x}(x: int): int = x*3 @@ -11,7 +10,7 @@ template optSubstr1{x = substr(x, 0, b)}(x: string, b: int) = setlen(x, b+1) template disallowIf{ if cond: action else: action2 -}(cond: bool, action, action2: stmt) {.error.} = action +}(cond: bool, action, action2: typed) {.error.} = action var y = 12 echo y+y diff --git a/tests/typerel/ttypenovalue.nim b/tests/typerel/ttypenovalue.nim index b86baf8b4..9af978466 100644 --- a/tests/typerel/ttypenovalue.nim +++ b/tests/typerel/ttypenovalue.nim @@ -1,7 +1,6 @@ discard """ - errormsg: "value expected, but got a type" + errormsg: "invalid type: 'type seq[tuple[title: string, body: string]]' for var" line: 7 - disabled: true """ proc crashAndBurn() = From c5f64f101b772a1df3ed61c1a2f26a21767b580c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 15 Jul 2020 15:46:17 +0800 Subject: [PATCH 0898/4254] fix #13086 (#14987) * fix #6608 * minor * fix * clean tests * make testamnet happy * again * minor * fix #13086 --- lib/pure/parseopt.nim | 4 ++-- tests/misc/tparseopt.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index a95a5b48d..94df5ea40 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -280,8 +280,8 @@ proc handleShortOption(p: var OptParser; cmd: string) = while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i) p.inShortState = false - if i < cmd.len and cmd[i] in {':', '='} or - card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal: + if i < cmd.len and (cmd[i] in {':', '='} or + card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal): if i < cmd.len and cmd[i] in {':', '='}: inc(i) p.inShortState = false diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim index a3dfcbb26..47be05bac 100644 --- a/tests/misc/tparseopt.nim +++ b/tests/misc/tparseopt.nim @@ -22,6 +22,15 @@ kind: cmdShortOption key:val -- r:0 kind: cmdShortOption key:val -- l: kind: cmdShortOption key:val -- r:4 kind: cmdLongOption key:val -- debug: +cmdShortOption key: v value: '' +cmdArgument key: ABC value: '' +cmdShortOption key: v value: 'ABC' +cmdShortOption key: v value: '' +cmdArgument key: ABC value: '' +cmdShortOption key: v value: '' +cmdArgument key: ABC value: '' +cmdShortOption key: j value: '4' +cmdArgument key: ok value: '' ''' joinable: false """ @@ -121,3 +130,27 @@ arg 3 ai.len:4 :{a4"b} arg 4 ai.len:4 :{a5'b} arg 5 ai.len:4 :{a6\b} arg 6 ai.len:4 :{a7'b}""" + + + + block: + let args = @["-v", "ABC"] + var p = parseopt.initOptParser(args, shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(p): + echo kind," key: ", key, " value: '", val, "'" + + var r = parseopt.initOptParser(@["-v ABC"], shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(r): + echo kind," key: ", key, " value: '", val, "'" + + var s = parseopt.initOptParser("-v ABC", shortnoVal = {'v'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(s): + echo kind," key: ", key, " value: '", val, "'" + + var m = parseopt.initOptParser("-v ABC", shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(m): + echo kind," key: ", key, " value: '", val, "'" + + var n = parseopt.initOptParser("-j4 ok", shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(n): + echo kind," key: ", key, " value: '", val, "'" From 08159733cd1ab508a611cf60380572e879ae7f0f Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 15 Jul 2020 11:34:10 +0200 Subject: [PATCH 0899/4254] Fix #14985 (#14988) --- compiler/injectdestructors.nim | 4 ++-- tests/arc/tmovebug.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index ff311f079..98cfb4743 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -660,7 +660,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = branch[0] = p(it[0], c, s, normal) branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt: - processScope(c, branchScope, processCall(it[^1], branchScope)) + processScope(c, branchScope, maybeVoid(it[^1], branchScope)) else: processScopeExpr(c, branchScope, it[^1], processCall) result.add branch @@ -679,7 +679,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = var branchScope = nestedScope(s) branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt or it.kind == nkFinally: processScope(c, branchScope, if it.kind == nkFinally: p(it[^1], c, branchScope, normal) - else: processCall(it[^1], branchScope)) + else: maybeVoid(it[^1], branchScope)) else: processScopeExpr(c, branchScope, it[^1], processCall) result.add branch diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 424785ed7..3b7a7c5df 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -67,6 +67,9 @@ ho king live long; long live king +hi +try +bye ''' """ @@ -494,3 +497,30 @@ proc weirdScopes = echo king weirdScopes() + + +# bug #14985 +proc getScope(): string = + if true: + return "hi" + else: + "else" + +echo getScope() + +proc getScope3(): string = + try: + "try" + except: + return "except" + +echo getScope3() + +proc getScope2(): string = + case true + of true: + return "bye" + else: + "else" + +echo getScope2() From e057b1d8395f4d639e195bc8f6a7e6922c149201 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 15 Jul 2020 19:00:52 +0200 Subject: [PATCH 0900/4254] Fix #14990 (#14991) * Fix #14990 * Add testcase --- compiler/semtypes.nim | 4 ++-- tests/generics/tgenerics_issues.nim | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5407b9435..4001953bc 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1402,8 +1402,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = [s.name.s, s.kind.toHumanStr]) return newOrPrevType(tyError, prev, c) - var t = s.typ - if t.kind in {tyCompositeTypeClass, tyAlias} and t.base.kind == tyGenericBody: + var t = s.typ.skipTypes({tyAlias}) + if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody: t = t.base result = newOrPrevType(tyGenericInvocation, prev, c) diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index cdbaf885e..812f339b9 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -849,3 +849,14 @@ discard getBar(fakeReadLine()) # no error discard getBar("hello, world") # no error echo intoFoos(fakeReadLine().split(' ')) # no error, works as expected + + +# bug #14990 +type + Tile3 = Tile2 + Tile2 = Tile + Tile[n] = object + a: n + +var a: Tile3[int] + From 813dd1b670b953b0ac8348b04079faadace46c29 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 15 Jul 2020 22:04:15 +0200 Subject: [PATCH 0901/4254] repr_v2 improvements (#14992) * Support proc in arc repr * Typo * Improve repr for strings and chars --- lib/system/repr_v2.nim | 38 ++++++++++++++++++++++++++++---------- tests/arc/trepr.nim | 6 ++++++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index fcc187a42..d456f4454 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -29,21 +29,35 @@ proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.} proc repr*(x: char): string {.noSideEffect.} = ## repr for a character argument. Returns `x` - ## converted to a string. + ## converted to an escaped string. ## ## .. code-block:: Nim ## assert repr('c') == "'c'" - '\'' & $x & '\'' + result.add '\'' + # Elides string creations if not needed + if x in {'\\', '\0'..'\31', '\127'..'\255'}: + result.add '\\' + if x in {'\0'..'\31', '\127'..'\255'}: + result.add $x.uint8 + else: + result.add x + result.add '\'' -proc repr*(x: cstring): string {.noSideEffect.} = - ## repr for a CString argument. Returns `x` - ## converted to a quoted string. - '"' & $x & '"' - -proc repr*(x: string): string {.noSideEffect.} = +proc repr*(x: string | cstring): string {.noSideEffect.} = ## repr for a string argument. Returns `x` - ## but quoted. - '"' & x & '"' + ## converted to a quoted and escaped string. + result.add '\"' + for i in 0.. Date: Wed, 15 Jul 2020 23:00:06 +0200 Subject: [PATCH 0902/4254] An optimizer for ARC (#14962) * WIP: an optimizer for ARC * do not optimize away destructors in 'finally' if unstructured control flow is involved * optimized the optimizer * minor code cleanup * first steps to .cursor inference * cursor inference: big steps to a working solution * baby steps * better .cursor inference * new feature: expandArc for easy inspection of the AST after ARC transformations * added topt_cursor test * adapt tests * cleanups, make tests green * optimize common traversal patterns * moved test case * fixes .cursor inference so that npeg compiles once again * cursor inference: more bugfixes Co-authored-by: Clyybber --- compiler/commands.nim | 3 + compiler/cursor_inference.nim | 295 ++++++++++++++++++ compiler/injectdestructors.nim | 54 ++-- compiler/optimizer.nim | 285 +++++++++++++++++ compiler/options.nim | 2 + compiler/renderer.nim | 21 +- compiler/transf.nim | 2 +- doc/advopt.txt | 2 + doc/destructors.rst | 28 +- lib/impure/nre.nim | 10 +- .../t12785.nim => arc/tcomputedgoto.nim} | 12 +- tests/arc/topt_cursor.nim | 35 +++ tests/arc/topt_no_cursor.nim | 37 +++ tests/arc/topt_refcursors.nim | 39 +++ tests/arc/topt_wasmoved_destroy_pairs.nim | 92 ++++++ tests/{generics => arc}/trtree.nim | 18 +- tests/destructor/tdestructor3.nim | 11 +- tests/destructor/tmisc_destructors.nim | 6 +- .../destructor/tuse_result_prevents_sinks.nim | 5 + 19 files changed, 895 insertions(+), 62 deletions(-) create mode 100644 compiler/cursor_inference.nim create mode 100644 compiler/optimizer.nim rename tests/{casestmt/t12785.nim => arc/tcomputedgoto.nim} (87%) create mode 100644 tests/arc/topt_cursor.nim create mode 100644 tests/arc/topt_no_cursor.nim create mode 100644 tests/arc/topt_refcursors.nim create mode 100644 tests/arc/topt_wasmoved_destroy_pairs.nim rename tests/{generics => arc}/trtree.nim (98%) diff --git a/compiler/commands.nim b/compiler/commands.nim index 1984c894a..d0936a0c6 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -866,6 +866,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "expandmacro": expectArg(conf, switch, arg, pass, info) conf.macrosToExpand[arg] = "T" + of "expandarc": + expectArg(conf, switch, arg, pass, info) + conf.arcToExpand[arg] = "T" of "oldgensym": processOnOffSwitchG(conf, {optNimV019}, arg, pass, info) of "useversion": diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim new file mode 100644 index 000000000..7806a535f --- /dev/null +++ b/compiler/cursor_inference.nim @@ -0,0 +1,295 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Cursor inference: +## The basic idea was like this: Elide 'destroy(x)' calls if only +## special literals are assigned to 'x' and 'x' is not mutated or +## passed by 'var T' to something else. Special literals are string literals or +## arrays / tuples of string literals etc. +## +## However, there is a much more general rule here: Compute which variables +## can be annotated with `.cursor`. To see how and when we can do that, +## think about this question: In `dest = src` when do we really have to +## *materialize* the full copy? - Only if `dest` or `src` are mutated +## afterwards. `dest` is the potential cursor variable, so that is +## simple to analyse. And if `src` is a location derived from a +## formal parameter, we also know it is not mutated! In other words, we +## do a compile-time copy-on-write analysis. + +import + ast, types, renderer, idents, intsets, options, msgs + +type + Cursor = object + s: PSym + deps: IntSet + Con = object + cursors: seq[Cursor] + mayOwnData: IntSet + mutations: IntSet + reassigns: IntSet + config: ConfigRef + +proc locationRoot(e: PNode; followDotExpr = true): PSym = + var n = e + while true: + case n.kind + of nkSym: + if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}: + return n.sym + else: + return nil + of nkDotExpr, nkDerefExpr, nkBracketExpr, nkHiddenDeref, + nkCheckedFieldExpr, nkAddr, nkHiddenAddr: + if followDotExpr: + n = n[0] + else: + return nil + of nkObjUpConv, nkObjDownConv: + n = n[0] + of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: + n = n[1] + of nkStmtList, nkStmtListExpr: + if n.len > 0: + n = n[^1] + else: + return nil + else: + return nil + +proc addDep(c: var Con; dest: var Cursor; dependsOn: PSym) = + if dest.s != dependsOn: + dest.deps.incl dependsOn.id + +proc cursorId(c: Con; x: PSym): int = + for i in 0.. 0: + analyseAsgn(c, dest, n[^1]) + + of nkClosure: + for i in 1.. treat it like a sink parameter + c.mayOwnData.incl r.id + c.mutations.incl r.id + +proc analyse(c: var Con; n: PNode) = + case n.kind + of nkCallKinds: + let parameters = n[0].typ + let L = if parameters != nil: parameters.len else: 0 + + analyse(c, n[0]) + for i in 1..= 0: + analyseAsgn(c, c.cursors[idx], n[1]) + + c.reassigns.incl n[0].sym.id + else: + # assignments like 'x.field = value' mean that 'x' itself cannot + # be a cursor: + let r = locationRoot(n[0]) + if r != nil and r.typ.skipTypes(abstractInst).kind notin {tyPtr, tyRef}: + # however, an assignment like 'it.field = x' does not influence r's + # cursorness property: + c.mayOwnData.incl r.id + c.mutations.incl r.id + + if hasDestructor(n[1].typ): + rhsIsSink(c, n[1]) + + of nkAddr, nkHiddenAddr: + analyse(c, n[0]) + let r = locationRoot(n[0]) + if r != nil: + c.mayOwnData.incl r.id + c.mutations.incl r.id + + of nkTupleConstr, nkBracket, nkObjConstr: + for i in ord(n.kind == nkObjConstr)..---------transformed-to--------->" echo renderTree(result, {renderIds}) + + if g.config.arcToExpand.hasKey(owner.name.s): + echo "--expandArc: ", owner.name.s + echo renderTree(result, {renderIr}) + echo "-- end of expandArc ------------------------" diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim new file mode 100644 index 000000000..5d1139bfd --- /dev/null +++ b/compiler/optimizer.nim @@ -0,0 +1,285 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Optimizer: +## - elide 'wasMoved(x); destroy(x)' pairs +## - recognize "all paths lead to 'wasMoved(x)'" + +import + ast, renderer, idents, intsets + +from trees import exprStructuralEquivalent + +const + nfMarkForDeletion = nfNone # faster than a lookup table + +type + BasicBlock = object + wasMovedLocs: seq[PNode] + kind: TNodeKind + hasReturn, hasBreak: bool + label: PSym # can be nil + parent: ptr BasicBlock + + Con = object + somethingTodo: bool + inFinally: int + +proc nestedBlock(parent: var BasicBlock; kind: TNodeKind): BasicBlock = + BasicBlock(wasMovedLocs: @[], kind: kind, hasReturn: false, hasBreak: false, + label: nil, parent: addr(parent)) + +proc breakStmt(b: var BasicBlock; n: PNode) = + var it = addr(b) + while it != nil: + it.wasMovedLocs.setLen 0 + it.hasBreak = true + + if n.kind == nkSym: + if it.label == n.sym: break + else: + # unnamed break leaves the block is nkWhileStmt or the like: + if it.kind in {nkWhileStmt, nkBlockStmt, nkBlockExpr}: break + + it = it.parent + +proc returnStmt(b: var BasicBlock) = + b.hasReturn = true + var it = addr(b) + while it != nil: + it.wasMovedLocs.setLen 0 + it = it.parent + +proc mergeBasicBlockInfo(parent: var BasicBlock; this: BasicBlock) {.inline.} = + if this.hasReturn: + parent.wasMovedLocs.setLen 0 + parent.hasReturn = true + +proc wasMovedTarget(matches: var IntSet; branch: seq[PNode]; moveTarget: PNode): bool = + result = false + for i in 0.. 0 and (b.hasReturn or b.hasBreak): + discard "cannot optimize away the destructor" + else: + c.wasMovedDestroyPair b, n + special = true + elif s.name.s == "=sink": + reverse = true + + if not special: + if not reverse: + for i in 0 ..< n.len: + analyse(c, b, n[i]) + else: + #[ Test tmatrix.test3: + Prevent this from being elided. We should probably + find a better solution... + + `=sink`(b, - ( + let blitTmp = b; + wasMoved(b); + blitTmp + a) + `=destroy`(b) + + ]# + for i in countdown(n.len-1, 0): + analyse(c, b, n[i]) + if canRaise(n[0]): returnStmt(b) + + of nkSym: + # any usage of the location before destruction implies we + # cannot elide the 'wasMoved(x)': + b.invalidateWasMoved n + + of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, + nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, + nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: + discard "do not follow the construct" + + of nkAsgn, nkFastAsgn: + # reverse order, see remark for `=sink`: + analyse(c, b, n[1]) + analyse(c, b, n[0]) + + of nkIfStmt, nkIfExpr: + let isExhaustive = n[^1].kind in {nkElse, nkElseExpr} + var wasMovedSet: seq[PNode] = @[] + + for i in 0 ..< n.len: + var branch = nestedBlock(b, n[i].kind) + + analyse(c, branch, n[i]) + mergeBasicBlockInfo(b, branch) + if isExhaustive: + if i == 0: + wasMovedSet = move(branch.wasMovedLocs) + else: + wasMovedSet.intersect(branch.wasMovedLocs) + for i in 0..= ord(tokKeywordLow) - ord(tkSymbol)) and (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): @@ -850,7 +860,12 @@ proc gident(g: var TSrcGen, n: PNode) = t = tkSymbol else: t = tkOpr - if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp): + if renderIr in g.flags and n.kind == nkSym: + let localId = disamb(g, n.sym) + if localId != 0 and n.sym.magic == mNone: + s.add '_' + s.addInt localId + elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp): s.add '_' s.addInt n.sym.id when defined(debugMagics): @@ -1022,7 +1037,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = else: put(g, tkSymbol, "(wrong conv)") of nkHiddenCallConv: - if renderIds in g.flags: + if {renderIds, renderIr} * g.flags != {}: accentedName(g, n[0]) put(g, tkParLe, "(") gcomma(g, n, 1) diff --git a/compiler/transf.nim b/compiler/transf.nim index 10a2680ae..be559abb8 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -233,7 +233,7 @@ proc hasContinue(n: PNode): bool = proc newLabel(c: PTransf, n: PNode): PSym = result = newSym(skLabel, nil, getCurrOwner(c), n.info) - result.name = getIdent(c.graph.cache, genPrefix & $result.id) + result.name = getIdent(c.graph.cache, genPrefix) proc transformBlock(c: PTransf, n: PNode): PNode = var labl: PSym diff --git a/doc/advopt.txt b/doc/advopt.txt index 135f297c4..6665ce537 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -122,6 +122,8 @@ Advanced options: use the provided namespace for the generated C++ code, if no namespace is provided "Nim" will be used --expandMacro:MACRO dump every generated AST from MACRO + --expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations + before the final backend phase (mostly ARC/ORC specific) --excludePath:PATH exclude a path from the list of search paths --dynlibOverride:SYMBOL marks SYMBOL so that dynlib:SYMBOL has no effect and can be statically linked instead; diff --git a/doc/destructors.rst b/doc/destructors.rst index fefc646f5..6cab6e1d2 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -354,7 +354,8 @@ Destructor removal ``wasMoved(x);`` followed by a `=destroy(x)` operation cancel each other out. An implementation is encouraged to exploit this in order to improve -efficiency and code sizes. +efficiency and code sizes. The current implementation does perform this +optimization. Self assignments @@ -509,6 +510,31 @@ to be safe, but for ``ptr`` the compiler has to remain silent about possible problems. +Cursor inference / copy elision +=============================== + +The current implementation also performs `.cursor` inference. Cursor inference is +a form of copy elision. + +To see how and when we can do that, think about this question: In `dest = src` when +do we really have to *materialize* the full copy? - Only if `dest` or `src` are mutated +afterwards. If `dest` is a local variable that is simple to analyse. And if `src` is a +location derived from a formal parameter, we also know it is not mutated! In other +words, we do a compile-time copy-on-write analysis. + +This means that "borrowed" views can be written naturally and without explicit pointer +indirections: + +.. code-block:: nim + + proc main(tab: Table[string, string]) = + let v = tab["key"] # inferred as .cursor because 'tab' is not mutated. + # no copy into 'v', no destruction of 'v'. + use(v) + useItAgain(v) + + + Owned refs ========== diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 653d4d1c5..0817ca4ec 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -498,7 +498,7 @@ proc re*(pattern: string): Regex = initRegex(pattern, flags, study) proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Option[RegexMatch] = - var myResult = RegexMatch(pattern : pattern, str : str) + var myResult = RegexMatch(pattern: pattern, str: str) # See PCRE man pages. # 2x capture count to make room for start-end pairs # 1x capture count as slack space for PCRE @@ -528,13 +528,13 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt of pcre.ERROR_NULL: raise newException(AccessViolationDefect, "Expected non-null parameters") of pcre.ERROR_BADOPTION: - raise RegexInternalError(msg : "Unknown pattern flag. Either a bug or " & + raise RegexInternalError(msg: "Unknown pattern flag. Either a bug or " & "outdated PCRE.") of pcre.ERROR_BADUTF8, pcre.ERROR_SHORTUTF8, pcre.ERROR_BADUTF8_OFFSET: - raise InvalidUnicodeError(msg : "Invalid unicode byte sequence", - pos : myResult.pcreMatchBounds[0].a) + raise InvalidUnicodeError(msg: "Invalid unicode byte sequence", + pos: myResult.pcreMatchBounds[0].a) else: - raise RegexInternalError(msg : "Unknown internal error: " & $execRet) + raise RegexInternalError(msg: "Unknown internal error: " & $execRet) proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] = ## Like ` ``find(...)`` <#proc-find>`_, but anchored to the start of the diff --git a/tests/casestmt/t12785.nim b/tests/arc/tcomputedgoto.nim similarity index 87% rename from tests/casestmt/t12785.nim rename to tests/arc/tcomputedgoto.nim index 7177fb9c2..8af17b56e 100644 --- a/tests/casestmt/t12785.nim +++ b/tests/arc/tcomputedgoto.nim @@ -1,15 +1,7 @@ discard """ cmd: '''nim c --newruntime $file''' - output: '''copied -copied -2 -destroyed -destroyed -copied -copied -2 -destroyed -destroyed''' + output: '''2 +2''' """ type diff --git a/tests/arc/topt_cursor.nim b/tests/arc/topt_cursor.nim new file mode 100644 index 000000000..6b923cf76 --- /dev/null +++ b/tests/arc/topt_cursor.nim @@ -0,0 +1,35 @@ +discard """ + output: '''("string here", 80)''' + cmd: '''nim c --gc:arc --expandArc:main --hint:Performance:off $file''' + nimout: '''--expandArc: main + +var + :tmpD + :tmpD_1 + :tmpD_2 +try: + var x = ("hi", 5) + x = if cond: + :tmpD = ("different", 54) + :tmpD else: + :tmpD_1 = ("string here", 80) + :tmpD_1 + echo [ + :tmpD_2 = `$`(x) + :tmpD_2] +finally: + `=destroy`(:tmpD_2) +-- end of expandArc ------------------------''' +""" + +proc main(cond: bool) = + var x = ("hi", 5) # goal: computed as cursor + + x = if cond: + ("different", 54) + else: + ("string here", 80) + + echo x + +main(false) diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim new file mode 100644 index 000000000..3d3262491 --- /dev/null +++ b/tests/arc/topt_no_cursor.nim @@ -0,0 +1,37 @@ +discard """ + output: '''(repo: "", package: "meo", ext: "")''' + cmd: '''nim c --gc:arc --expandArc:newTarget --hint:Performance:off $file''' + nimout: '''--expandArc: newTarget + +var + splat + :tmp + :tmp_1 + :tmp_2 +splat = splitFile(path) +:tmp = splat.dir +wasMoved(splat.dir) +:tmp_1 = splat.name +wasMoved(splat.name) +:tmp_2 = splat.ext +wasMoved(splat.ext) +result = ( + let blitTmp = :tmp + blitTmp, + let blitTmp_1 = :tmp_1 + blitTmp_1, + let blitTmp_2 = :tmp_2 + blitTmp_2) +`=destroy`(splat) +-- end of expandArc ------------------------''' +""" + +import os + +type Target = tuple[repo, package, ext: string] + +proc newTarget*(path: string): Target = + let splat = path.splitFile + result = (repo: splat.dir, package: splat.name, ext: splat.ext) + +echo newTarget("meo") diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim new file mode 100644 index 000000000..7316e2beb --- /dev/null +++ b/tests/arc/topt_refcursors.nim @@ -0,0 +1,39 @@ +discard """ + output: '''''' + cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' + nimout: '''--expandArc: traverse + +var it = root +block :tmp: + while ( + not (it == nil)): + echo [it.s] + it = it.ri +var jt = root +block :tmp_1: + while ( + not (jt == nil)): + let ri_1 = jt.ri + echo [jt.s] + jt = ri_1 +-- end of expandArc ------------------------''' +""" + +type + Node = ref object + le, ri: Node + s: string + +proc traverse(root: Node) = + var it = root + while it != nil: + echo it.s + it = it.ri + + var jt = root + while jt != nil: + let ri = jt.ri + echo jt.s + jt = ri + +traverse(nil) diff --git a/tests/arc/topt_wasmoved_destroy_pairs.nim b/tests/arc/topt_wasmoved_destroy_pairs.nim new file mode 100644 index 000000000..4d248492b --- /dev/null +++ b/tests/arc/topt_wasmoved_destroy_pairs.nim @@ -0,0 +1,92 @@ +discard """ + output: '''''' + cmd: '''nim c --gc:arc --expandArc:main --expandArc:tfor --hint:Performance:off $file''' + nimout: '''--expandArc: main + +var + a + b + x +x = f() +if cond: + add(a): + let blitTmp = x + blitTmp +else: + add(b): + let blitTmp_1 = x + blitTmp_1 +`=destroy`(b) +`=destroy`(a) +-- end of expandArc ------------------------ +--expandArc: tfor + +var + a + b + x +try: + x = f() + block :tmp: + var i + var i_1 = 0 + block :tmp_1: + while i_1 < 4: + var :tmpD + i = i_1 + if i == 2: + return + add(a): + wasMoved(:tmpD) + `=`(:tmpD, x) + :tmpD + inc i_1, 1 + if cond: + add(a): + let blitTmp = x + wasMoved(x) + blitTmp + else: + add(b): + let blitTmp_1 = x + wasMoved(x) + blitTmp_1 +finally: + `=destroy`(x) + `=destroy_1`(b) + `=destroy_1`(a) +-- end of expandArc ------------------------''' +""" + +proc f(): seq[int] = + @[1, 2, 3] + +proc main(cond: bool) = + var a, b: seq[seq[int]] + var x = f() + if cond: + a.add x + else: + b.add x + +# all paths move 'x' so no wasMoved(x); destroy(x) pair should be left in the +# AST. + +main(false) + + +proc tfor(cond: bool) = + var a, b: seq[seq[int]] + + var x = f() + + for i in 0 ..< 4: + if i == 2: return + a.add x + + if cond: + a.add x + else: + b.add x + +tfor(false) diff --git a/tests/generics/trtree.nim b/tests/arc/trtree.nim similarity index 98% rename from tests/generics/trtree.nim rename to tests/arc/trtree.nim index b45ac8c83..986268f51 100644 --- a/tests/generics/trtree.nim +++ b/tests/arc/trtree.nim @@ -138,16 +138,16 @@ proc search*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]): seq[LT] # a R*TREE proc proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; level: int): H[M, D, RT, LT] = assert level >= 0 - var n = t.root - while n.level > level: - let nn = Node[M, D, RT, LT](n) + var it = t.root + while it.level > level: + let nn = Node[M, D, RT, LT](it) var i0 = 0 # selected index var minLoss = type(b[0].a).high - if n.level == 1: # childreen are leaves -- determine the minimum overlap costs - for i in 0 ..< n.numEntries: + if it.level == 1: # childreen are leaves -- determine the minimum overlap costs + for i in 0 ..< it.numEntries: let nx = union(nn.a[i].b, b) var loss = 0 - for j in 0 ..< n.numEntries: + for j in 0 ..< it.numEntries: if i == j: continue loss += (overlap(nx, nn.a[j].b) - overlap(nn.a[i].b, nn.a[j].b)) # overlap (i, j) == (j, i), so maybe cache that? var rep = loss < minLoss @@ -163,7 +163,7 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev i0 = i minLoss = loss else: - for i in 0 ..< n.numEntries: + for i in 0 ..< it.numEntries: let loss = enlargement(nn.a[i].b, b) var rep = loss < minLoss if loss == minLoss: @@ -174,8 +174,8 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev if rep: i0 = i minLoss = loss - n = nn.a[i0].n - return n + it = nn.a[i0].n + return it proc pickSeeds[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; bx: Box[D, RT]): (int, int) = var i0, j0: int diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index b68aedce9..f967bbf95 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -1,5 +1,6 @@ discard """ - output: '''assign + output: ''' +assign destroy destroy 5 @@ -104,12 +105,12 @@ test() #------------------------------------------------------------ # Issue #12883 -type +type TopObject = object internal: UniquePtr[int] proc deleteTop(p: ptr TopObject) = - if p != nil: + if p != nil: `=destroy`(p[]) # !!! this operation used to leak the integer deallocshared(p) @@ -117,12 +118,12 @@ proc createTop(): ptr TopObject = result = cast[ptr TopObject](allocShared0(sizeof(TopObject))) result.internal = newUniquePtr(1) -proc test2() = +proc test2() = let x = createTop() echo $x.internal deleteTop(x) -echo "---------------" +echo "---------------" echo "app begin" test2() echo "app end" \ No newline at end of file diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim index 73c54eab3..082cb0f78 100644 --- a/tests/destructor/tmisc_destructors.nim +++ b/tests/destructor/tmisc_destructors.nim @@ -21,11 +21,13 @@ proc `=sink`(dest: var Foo, src: Foo) = proc `=`(dest: var Foo, src: Foo) = assign_counter.inc +proc createFoo(): Foo = Foo(boo: 0) + proc test(): auto = - var a, b: Foo + var a, b = createFoo() return (a, b, Foo(boo: 5)) -var (a, b, _) = test() +var (ag, bg, _) = test() doAssert assign_counter == 0 doAssert sink_counter == 0 diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim index 37b5af9b2..6eac5c902 100644 --- a/tests/destructor/tuse_result_prevents_sinks.nim +++ b/tests/destructor/tuse_result_prevents_sinks.nim @@ -17,15 +17,20 @@ proc `=sink`(self: var Foo; other: Foo) = proc `=destroy`(self: var Foo) = discard +template preventCursorInference(x) = + let p = unsafeAddr(x) + proc test(): Foo = result = Foo() let temp = result + preventCursorInference temp doAssert temp.i > 0 return result proc testB(): Foo = result = Foo() let temp = result + preventCursorInference temp doAssert temp.i > 0 discard test() From 617c1f16d70657fbe4a69d76a2f00b84560af15a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 15 Jul 2020 23:04:18 +0200 Subject: [PATCH 0903/4254] disable debug output --- compiler/cursor_inference.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim index 7806a535f..e0999b5be 100644 --- a/compiler/cursor_inference.nim +++ b/compiler/cursor_inference.nim @@ -97,7 +97,7 @@ proc getCursors(c: Con): IntSet = break doAdd when true: result.incl cur.s.id - when true: + when false: echo "computed as a cursor ", cur.s, " ", cur.deps, " ", c.config $ cur.s.info proc analyseAsgn(c: var Con; dest: var Cursor; n: PNode) = From 282128ab66b6391c4ab9bc76cd19a63a5bce16f8 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 15 Jul 2020 23:33:58 +0200 Subject: [PATCH 0904/4254] Fix #14994 (#14996) * Fix #14994 * Revert misplaced "optimization" * Typo --- lib/pure/collections/sequtils.nim | 3 ++- lib/system/seqs_v2.nim | 1 + tests/arc/tarcmisc.nim | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index f101d508e..51d8ade85 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -527,7 +527,8 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = assert dest == outcome var j = len(dest) - 1 - var i = len(dest) + len(src) - 1 + var i = j + len(src) + if i == j: return dest.setLen(i + 1) # Move items after `pos` to the end of the sequence. diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 4001e97c3..3c94a03f9 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -82,6 +82,7 @@ proc shrink*[T](x: var seq[T]; newLen: Natural) = proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = let oldLen = x.len + #sysAssert newLen >= x.len, "invalid newLen parameter for 'grow'" if newLen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr x) if xu.p == nil or xu.p.cap < newLen: diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 2d7e6b455..56aa3ec3b 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -21,6 +21,8 @@ whiley ends :( (x: "9") (x: "10") 0 +new line before - @['a'] +new line after - @['a'] closed destroying variable: 20 destroying variable: 10 @@ -243,3 +245,15 @@ l.setParent(l) # bug #14968 import times let currentTime = now().utc + + +# bug #14994 +import sequtils +var newLine = @['a'] +let indent = newSeq[char]() + +echo "new line before - ", newline + +newline.insert(indent, 0) + +echo "new line after - ", newline From ba5604b96d7d2604a02b4f8ac8b67c54ea92ecfa Mon Sep 17 00:00:00 2001 From: Bung Date: Thu, 16 Jul 2020 17:18:59 +0800 Subject: [PATCH 0905/4254] fix #13621, the nim-livereload is mentioned as proposal in #8927 (#14998) --- doc/hcr.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/hcr.rst b/doc/hcr.rst index 567d77178..55ccc06dc 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -228,7 +228,6 @@ completion. JavaScript target ================= -Once your code is compiled for hot reloading, the ``nim-livereload`` NPM -package provides a convenient solution for implementing the actual reloading +Once your code is compiled for hot reloading, a convenient solution for implementing the actual reloading in the browser using a framework such as [LiveReload](http://livereload.com/) or [BrowserSync](https://browsersync.io/). From 6b607413e90111f74dd77c1fa31ba5f183f72bdf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 16 Jul 2020 12:07:06 +0200 Subject: [PATCH 0906/4254] cursor inference: hotfix (#14999) --- compiler/cursor_inference.nim | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim index e0999b5be..224131270 100644 --- a/compiler/cursor_inference.nim +++ b/compiler/cursor_inference.nim @@ -35,6 +35,7 @@ type mutations: IntSet reassigns: IntSet config: ConfigRef + inAsgnSource: int proc locationRoot(e: PNode; followDotExpr = true): PSym = var n = e @@ -221,7 +222,9 @@ proc analyse(c: var Con; n: PNode) = of nkAsgn, nkFastAsgn: analyse(c, n[0]) + inc c.inAsgnSource analyse(c, n[1]) + dec c.inAsgnSource if n[0].kind == nkSym: if hasDestructor(n[0].typ): @@ -252,14 +255,16 @@ proc analyse(c: var Con; n: PNode) = c.mutations.incl r.id of nkTupleConstr, nkBracket, nkObjConstr: - for i in ord(n.kind == nkObjConstr).. 0: + for i in ord(n.kind == nkObjConstr).. Date: Fri, 17 Jul 2020 16:53:26 +0800 Subject: [PATCH 0907/4254] fix #15006 (#15007) --- lib/system/nimscript.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index bf298e0d4..9e19fcfc4 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -142,7 +142,7 @@ template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExi fileExists(args) template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = - dirExists(dir) + dirExists(args) proc selfExe*(): string = ## Returns the currently running nim or nimble executable. From 1355b461aa70cd1e17b2f07085aa6c97cb54283f Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 17 Jul 2020 10:56:17 +0200 Subject: [PATCH 0908/4254] Show that a variable is cursor in --expandArc (#15002) --- compiler/cursor_inference.nim | 9 ++++----- compiler/injectdestructors.nim | 11 +++++------ compiler/renderer.nim | 2 ++ tests/arc/topt_cursor.nim | 6 +++--- tests/arc/topt_refcursors.nim | 18 +++++++++--------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim index 224131270..94b06ac79 100644 --- a/compiler/cursor_inference.nim +++ b/compiler/cursor_inference.nim @@ -73,7 +73,7 @@ proc cursorId(c: Con; x: PSym): int = if c.cursors[i].s == x: return i return -1 -proc getCursors(c: Con): IntSet = +proc getCursors(c: Con) = #[ Question: if x depends on y and y depends on z then also y depends on z. @@ -86,7 +86,6 @@ proc getCursors(c: Con): IntSet = y.s = "mutate" ]# - result = initIntSet() for cur in c.cursors: if not c.mayOwnData.contains(cur.s.id) and cur.s.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned: @@ -97,7 +96,7 @@ proc getCursors(c: Con): IntSet = #echo "bah, not a cursor ", cur.s, " bad dependency ", d break doAdd when true: - result.incl cur.s.id + cur.s.flags.incl sfCursor when false: echo "computed as a cursor ", cur.s, " ", cur.deps, " ", c.config $ cur.s.info @@ -294,7 +293,7 @@ proc analyse(c: var Con; n: PNode) = else: for child in n: analyse(c, child) -proc computeCursors*(n: PNode; config: ConfigRef): IntSet = +proc computeCursors*(n: PNode; config: ConfigRef) = var c = Con(config: config) analyse(c, n) - result = getCursors c + getCursors c diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 556d098f4..99eefca57 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -35,7 +35,6 @@ type Con = object owner: PSym g: ControlFlowGraph - cursors: IntSet graph: ModuleGraph otherRead: PNode inLoop, inSpawn: int @@ -152,13 +151,13 @@ proc isLastRead(location: PNode; cfg: ControlFlowGraph; otherRead: var PNode; pc proc isCursor(n: PNode; c: Con): bool = case n.kind of nkSym: - result = sfCursor in n.sym.flags or c.cursors.contains(n.sym.id) + sfCursor in n.sym.flags of nkDotExpr: - result = sfCursor in n[1].sym.flags + isCursor(n[1], c) of nkCheckedFieldExpr: - result = isCursor(n[0], c) + isCursor(n[0], c) else: - result = false + false proc isLastRead(n: PNode; c: var Con): bool = # first we need to search for the instruction that belongs to 'n': @@ -1043,7 +1042,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = echoCfg(c.g) echo n - c.cursors = computeCursors(n, g.config) + computeCursors(n, g.config) var scope: Scope let body = p(n, c, scope, normal) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 3cd532e15..f600d58bf 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -865,6 +865,8 @@ proc gident(g: var TSrcGen, n: PNode) = if localId != 0 and n.sym.magic == mNone: s.add '_' s.addInt localId + if sfCursor in n.sym.flags: + s.add "_cursor" elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp): s.add '_' s.addInt n.sym.id diff --git a/tests/arc/topt_cursor.nim b/tests/arc/topt_cursor.nim index 6b923cf76..63f261877 100644 --- a/tests/arc/topt_cursor.nim +++ b/tests/arc/topt_cursor.nim @@ -8,14 +8,14 @@ var :tmpD_1 :tmpD_2 try: - var x = ("hi", 5) - x = if cond: + var x_cursor = ("hi", 5) + x_cursor = if cond: :tmpD = ("different", 54) :tmpD else: :tmpD_1 = ("string here", 80) :tmpD_1 echo [ - :tmpD_2 = `$`(x) + :tmpD_2 = `$`(x_cursor) :tmpD_2] finally: `=destroy`(:tmpD_2) diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim index 7316e2beb..c8759f121 100644 --- a/tests/arc/topt_refcursors.nim +++ b/tests/arc/topt_refcursors.nim @@ -3,19 +3,19 @@ discard """ cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' nimout: '''--expandArc: traverse -var it = root +var it_cursor = root block :tmp: while ( - not (it == nil)): - echo [it.s] - it = it.ri -var jt = root + not (it_cursor == nil)): + echo [it_cursor.s] + it_cursor = it_cursor.ri +var jt_cursor = root block :tmp_1: while ( - not (jt == nil)): - let ri_1 = jt.ri - echo [jt.s] - jt = ri_1 + not (jt_cursor == nil)): + let ri_1_cursor = jt_cursor.ri + echo [jt_cursor.s] + jt_cursor = ri_1_cursor -- end of expandArc ------------------------''' """ From c62513049cd7dcbd5b339c2078856a31c498b4aa Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 17 Jul 2020 10:59:53 +0200 Subject: [PATCH 0909/4254] fix #14082, don't crash on incorrectly formatted input (#14977) [backport] * fix #14082, don't crash on incorrectly formatted input * address code review * remove duplication --- lib/pure/cgi.nim | 44 ++++++++-------------------- lib/pure/includes/decode_helpers.nim | 24 +++++++++++++++ lib/pure/uri.nim | 16 ++++------ 3 files changed, 42 insertions(+), 42 deletions(-) create mode 100644 lib/pure/includes/decode_helpers.nim diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index dd7c4d477..734ab9171 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -32,12 +32,7 @@ import strutils, os, strtabs, cookies, uri export uri.encodeUrl, uri.decodeUrl -proc handleHexChar(c: char, x: var int) {.inline.} = - case c - of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) - of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: assert(false) +include includes/decode_helpers proc addXmlChar(dest: var string, c: char) {.inline.} = case c @@ -93,40 +88,27 @@ proc getEncodedData(allowedMethods: set[RequestMethod]): string = iterator decodeData*(data: string): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. + proc parseData(data: string, i: int, field: var string): int = + result = i + while result < data.len: + case data[result] + of '%': add(field, decodePercent(data, result)) + of '+': add(field, ' ') + of '=', '&': break + else: add(field, data[result]) + inc(result) + var i = 0 var name = "" var value = "" # decode everything in one pass: while i < data.len: setLen(name, 0) # reuse memory - while i < data.len: - case data[i] - of '%': - var x = 0 - handleHexChar(data[i+1], x) - handleHexChar(data[i+2], x) - inc(i, 2) - add(name, chr(x)) - of '+': add(name, ' ') - of '=', '&': break - else: add(name, data[i]) - inc(i) + i = parseData(data, i, name) if i >= data.len or data[i] != '=': cgiError("'=' expected") inc(i) # skip '=' setLen(value, 0) # reuse memory - while i < data.len: - case data[i] - of '%': - var x = 0 - if i+2 < data.len: - handleHexChar(data[i+1], x) - handleHexChar(data[i+2], x) - inc(i, 2) - add(value, chr(x)) - of '+': add(value, ' ') - of '&', '\0': break - else: add(value, data[i]) - inc(i) + i = parseData(data, i, value) yield (name.TaintedString, value.TaintedString) if i < data.len: if data[i] == '&': inc(i) diff --git a/lib/pure/includes/decode_helpers.nim b/lib/pure/includes/decode_helpers.nim new file mode 100644 index 000000000..74fe37d07 --- /dev/null +++ b/lib/pure/includes/decode_helpers.nim @@ -0,0 +1,24 @@ +# Include file that implements 'decodePercent' and friends. Do not import it! + +proc handleHexChar(c: char, x: var int, f: var bool) {.inline.} = + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: f = true + +proc decodePercent(s: string, i: var int): char = + ## Converts `%xx` hexadecimal to the charracter with ordinal number `xx`. + ## + ## If `xx` is not a valid hexadecimal value, it is left intact: only the + ## leading `%` is returned as-is, and `xx` characters will be processed in the + ## next step (e.g. in `uri.decodeUrl`) as regular characters. + result = '%' + if i+2 < s.len: + var x = 0 + var failed = false + handleHexChar(s[i+1], x, failed) + handleHexChar(s[i+2], x, failed) + if not failed: + result = chr(x) + inc(i, 2) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index b163a2ab4..04a9d97bd 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -47,6 +47,8 @@ import std/private/since import strutils, parseutils, base64 +include includes/decode_helpers + type Url* = distinct string @@ -90,6 +92,7 @@ proc decodeUrl*(s: string, decodePlus = true): string = ## This means that any ``%xx`` (where ``xx`` denotes a hexadecimal ## value) are converted to the character with ordinal number ``xx``, ## and every other character is carried over. + ## If ``xx`` is not a valid hexadecimal value, it is left intact. ## ## As a special rule, when the value of ``decodePlus`` is true, ``+`` ## characters are converted to a space. @@ -101,12 +104,7 @@ proc decodeUrl*(s: string, decodePlus = true): string = assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test" assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test", false) == "https://nim-lang.org/this is a test" - proc handleHexChar(c: char, x: var int) {.inline.} = - case c - of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) - of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: assert(false) + assert decodeUrl("abc%xyz") == "abc%xyz" result = newString(s.len) var i = 0 @@ -114,11 +112,7 @@ proc decodeUrl*(s: string, decodePlus = true): string = while i < s.len: case s[i] of '%': - var x = 0 - handleHexChar(s[i+1], x) - handleHexChar(s[i+2], x) - inc(i, 2) - result[j] = chr(x) + result[j] = decodePercent(s, i) of '+': if decodePlus: result[j] = ' ' From c2f80de1c74c673ab9d3459d1f86fb9fe4366f61 Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 17 Jul 2020 17:01:47 +0800 Subject: [PATCH 0910/4254] fix #14822 copy test into var in matrix process, so can reset startTime before actully run (#15000) * TTest pass by ref , so can reset startTime before actully run * change TTest to ref type * clone test in matrix process --- testament/testament.nim | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/testament/testament.nim b/testament/testament.nim index 109ce4ed9..baa340139 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -58,7 +58,6 @@ type TResults = object total, passed, skipped: int data: string - TTest = object name: string cat: Category @@ -425,8 +424,9 @@ proc checkDisabled(r: var TResults, test: TTest): bool = var count = 0 -proc testSpecHelper(r: var TResults, test: TTest, expected: TSpec, +proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, target: TTarget, nimcache: string, extraOptions = "") = + test.startTime = epochTime() case expected.action of actionCompile: var given = callCompiler(expected.getCmd, test.name, test.options, nimcache, target, @@ -496,7 +496,8 @@ proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions = echo "testSpec count: ", count, " expected: ", expected else: let nimcache = nimcacheDir(test.name, test.options, target) - testSpecHelper(r, test, expected, target, nimcache, extraOptions) + var testClone = test + testSpecHelper(r, testClone, expected, target, nimcache, extraOptions) proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) = var expected = test.spec @@ -521,7 +522,8 @@ proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) = if not checkDisabled(r, test): return for target in test.spec.targets: inc(r.total) - testSpecHelper(r, test, test.spec, target, nimcache) + var testClone = test + testSpecHelper(r, testClone, test.spec, target, nimcache) proc testC(r: var TResults, test: TTest, action: TTestAction) = # runs C code. Doesn't support any specs, just goes by exit code. From d4984e069adc1984c2f67d073ebb7c42873c4d08 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 17 Jul 2020 15:24:36 +0200 Subject: [PATCH 0911/4254] arc: cursors for simple for loop variables (#15008) * arc: cursors for simple for loop variables * merged devel --- compiler/injectdestructors.nim | 2 +- compiler/transf.nim | 24 ++++++++++++++++++-- tests/arc/topt_cursor.nim | 27 ++++++++++++++++++++++- tests/arc/topt_wasmoved_destroy_pairs.nim | 6 ++--- 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 99eefca57..752438180 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1062,5 +1062,5 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = if g.config.arcToExpand.hasKey(owner.name.s): echo "--expandArc: ", owner.name.s - echo renderTree(result, {renderIr}) + echo renderTree(result, {renderIr, renderNoComments}) echo "-- end of expandArc ------------------------" diff --git a/compiler/transf.nim b/compiler/transf.nim index be559abb8..7aa18bf52 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -350,7 +350,7 @@ proc transformYield(c: PTransf, n: PNode): PNode = # Choose the right assignment instruction according to the given ``lhs`` # node since it may not be a nkSym (a stack-allocated skForVar) but a # nkDotExpr (a heap-allocated slot into the envP block) - case lhs.kind: + case lhs.kind of nkSym: internalAssert c.graph.config, lhs.sym.kind == skForVar result = newAsgnStmt(c, nkFastAsgn, lhs, rhs) @@ -592,6 +592,22 @@ proc findWrongOwners(c: PTransf, n: PNode) = else: for i in 0.. Date: Sat, 18 Jul 2020 09:21:09 +0100 Subject: [PATCH 0912/4254] fix odbc regressions (#15009) [backport] * fix odbc regressions * make only necessary changes --- lib/wrappers/odbcsql.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim index 393f29ad0..7836f087d 100644 --- a/lib/wrappers/odbcsql.nim +++ b/lib/wrappers/odbcsql.nim @@ -47,8 +47,8 @@ type SqlHDesc* = SqlHandle TSqlInteger* = int32 SqlUInteger* = int32 - TSqlLen* = int64 - TSqlULen* = uint64 + TSqlLen* = int + TSqlULen* = uint SqlPointer* = pointer TSqlReal* = cfloat TSqlDouble* = cdouble From c983466c15f1807c66f4c2f07ba348b0f95584b3 Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Sat, 18 Jul 2020 17:41:33 +0900 Subject: [PATCH 0913/4254] Fix #14906 (#14949) * Fix #14906 by wrapping outputStream with PipeOutStream * Fix compile error when ./build_all.sh * Use PipeOutStream on posix * Fix compile error when build_all.sh * Use ptr UncheckedArray * Replace copyRefObj * Remove tmp buffer from posPeekData * Add more tests for outputStream * Add comments about PipeOutStream.buffer * Fix bug in posReadLine * Move implementation of newPipeOutStream to streamwrapper module --- lib/pure/osproc.nim | 71 +++++++++++++++++++--- lib/pure/streamwrapper.nim | 117 +++++++++++++++++++++++++++++++++++++ tests/stdlib/tosproc.nim | 56 +++++++++++++++++- 3 files changed, 235 insertions(+), 9 deletions(-) create mode 100644 lib/pure/streamwrapper.nim diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 8be914992..5113695d8 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -18,7 +18,8 @@ include "system/inclrtl" import - strutils, os, strtabs, streams, cpuinfo + strutils, os, strtabs, streams, cpuinfo, streamwrapper, + std/private/since export quoteShell, quoteShellWindows, quoteShellPosix @@ -237,6 +238,10 @@ proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s output stream for reading from. ## + ## You cannot perform peek/write/setOption operations to this stream. + ## Use `peekableOutputStream proc <#peekableOutputStream,Process>`_ + ## if you need to peek stream. + ## ## **WARNING**: The returned `Stream` should not be closed manually as it ## is closed when closing the Process ``p``. ## @@ -247,6 +252,10 @@ proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s error stream for reading from. ## + ## You cannot perform peek/write/setOption operations to this stream. + ## Use `peekableErrorStream proc <#peekableErrorStream,Process>`_ + ## if you need to peek stream. + ## ## **WARNING**: The returned `Stream` should not be closed manually as it ## is closed when closing the Process ``p``. ## @@ -254,6 +263,30 @@ proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## * `inputStream proc <#inputStream,Process>`_ ## * `outputStream proc <#outputStream,Process>`_ +proc peekableOutputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], since: (1, 3).} + ## Returns ``p``'s output stream for reading from. + ## + ## You can peek returned stream. + ## + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. + ## + ## See also: + ## * `outputStream proc <#outputStream,Process>`_ + ## * `peekableErrorStream proc <#peekableErrorStream,Process>`_ + +proc peekableErrorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], since: (1, 3).} + ## Returns ``p``'s error stream for reading from. + ## + ## You can run peek operation to returned stream. + ## + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. + ## + ## See also: + ## * `errorStream proc <#errorStream,Process>`_ + ## * `peekableOutputStream proc <#peekableOutputStream,Process>`_ + proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## Returns ``p``'s input file handle for writing to. @@ -737,6 +770,18 @@ when defined(Windows) and not defined(useNimRtl): p.errStream = newFileHandleStream(p.errHandle) result = p.errStream + proc peekableOutputStream(p: Process): Stream = + streamAccess(p) + if p.outStream == nil: + p.outStream = newFileHandleStream(p.outHandle).newPipeOutStream + result = p.outStream + + proc peekableErrorStream(p: Process): Stream = + streamAccess(p) + if p.errStream == nil: + p.errStream = newFileHandleStream(p.errHandle).newPipeOutStream + result = p.errStream + proc execCmd(command: string): int = var si: STARTUPINFO @@ -1360,28 +1405,40 @@ elif not defined(useNimRtl): p.exitStatus = status result = exitStatusLikeShell(status) - proc createStream(stream: var owned(Stream), handle: var FileHandle, - fileMode: FileMode) = + proc createStream(handle: var FileHandle, + fileMode: FileMode): owned FileStream = var f: File if not open(f, handle, fileMode): raiseOSError(osLastError()) - stream = newFileStream(f) + return newFileStream(f) proc inputStream(p: Process): Stream = streamAccess(p) if p.inStream == nil: - createStream(p.inStream, p.inHandle, fmWrite) + p.inStream = createStream(p.inHandle, fmWrite) return p.inStream proc outputStream(p: Process): Stream = streamAccess(p) if p.outStream == nil: - createStream(p.outStream, p.outHandle, fmRead) + p.outStream = createStream(p.outHandle, fmRead) return p.outStream proc errorStream(p: Process): Stream = streamAccess(p) if p.errStream == nil: - createStream(p.errStream, p.errHandle, fmRead) + p.errStream = createStream(p.errHandle, fmRead) + return p.errStream + + proc peekableOutputStream(p: Process): Stream = + streamAccess(p) + if p.outStream == nil: + p.outStream = createStream(p.outHandle, fmRead).newPipeOutStream + return p.outStream + + proc peekableErrorStream(p: Process): Stream = + streamAccess(p) + if p.errStream == nil: + p.errStream = createStream(p.errHandle, fmRead).newPipeOutStream return p.errStream proc csystem(cmd: cstring): cint {.nodecl, importc: "system", diff --git a/lib/pure/streamwrapper.nim b/lib/pure/streamwrapper.nim new file mode 100644 index 000000000..b99982f1b --- /dev/null +++ b/lib/pure/streamwrapper.nim @@ -0,0 +1,117 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements stream wrapper. +## +## **Since** version 1.2. + +import deques, streams + +type + PipeOutStream*[T] = ref object of T + # When stream peek operation is called, it reads from base stream + # type using `baseReadDataImpl` and stores the content to this buffer. + # Next stream read operation returns data in the buffer so that previus peek + # operation looks like didn't changed read positon. + # When stream read operation that returns N byte data is called and the size is smaller than buffer size, + # first N elements are removed from buffer. + # Deque type can do such operation more efficiently than seq type. + buffer: Deque[char] + baseReadLineImpl: typeof(StreamObj.readLineImpl) + baseReadDataImpl: typeof(StreamObj.readDataImpl) + +proc posReadLine[T](s: Stream, line: var TaintedString): bool = + var s = PipeOutStream[T](s) + assert s.baseReadLineImpl != nil + + let n = s.buffer.len + line.string.setLen(0) + for i in 0.. 0 + line.string.add(c) + + var line2: string + result = s.baseReadLineImpl(s, line2) + line.add line2 + +proc posReadData[T](s: Stream, buffer: pointer, bufLen: int): int = + var s = PipeOutStream[T](s) + assert s.baseReadDataImpl != nil + + let + dest = cast[ptr UncheckedArray[char]](buffer) + n = min(s.buffer.len, bufLen) + result = n + for i in 0.. n: + result += s.baseReadDataImpl(s, addr dest[n], bufLen - n) + +proc posReadDataStr[T](s: Stream, buffer: var string, slice: Slice[int]): int = + posReadData[T](s, addr buffer[slice.a], slice.len) + +proc posPeekData[T](s: Stream, buffer: pointer, bufLen: int): int = + var s = PipeOutStream[T](s) + assert s.baseReadDataImpl != nil + + let + dest = cast[ptr UncheckedArray[char]](buffer) + n = min(s.buffer.len, bufLen) + + result = n + for i in 0.. n: + let + newDataNeeded = bufLen - n + numRead = s.baseReadDataImpl(s, addr dest[n], newDataNeeded) + result += numRead + for i in 0.. Date: Sat, 18 Jul 2020 01:49:36 -0700 Subject: [PATCH 0914/4254] enable,document,test getImplTransformed, very useful for understanding how nim transforms code (#14924) * enable,document,test getImplTransformed, very useful for understanding how nim transforms code --- lib/core/macros.nim | 7 +++++-- tests/macros/tmacros_various.nim | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 7b03d4e4d..e4a56d6f9 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -277,9 +277,12 @@ else: # bootstrapping substitute {.pop.} -when defined(nimSymImplTransform): +when (NimMajor, NimMinor, NimPatch) >= (1, 3, 5) or defined(nimSymImplTransform): proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.} - ## For a typed proc returns the AST after transformation pass. + ## For a typed proc returns the AST after transformation pass; this is useful + ## for debugging how the compiler transforms code (eg: `defer`, `for`) but + ## note that code transformations are implementation dependent and subject to change. + ## See an example in `tests/macros/tmacros_various.nim`. when defined(nimHasSymOwnerInMacro): proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.} diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 533db25e1..3cb5aaa8f 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -202,3 +202,23 @@ block tupleNewLitTests: # this `$` test is needed because tuple equality doesn't distinguish # between named vs unnamed tuples doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"])) + +from strutils import contains +block getImplTransformed: + macro bar(a: typed): string = + # newLit a.getImpl.repr # this would be before code transformation + let b = a.getImplTransformed + newLit b.repr + template toExpand() = + for ai in 0..2: echo ai + proc baz(a=1): int = + defer: discard + toExpand() + 12 + const code = bar(baz) + # sanity check: + doAssert "finally" in code # `defer` is lowered to try/finally + doAssert "while" in code # `for` is lowered to `while` + doAssert "toExpand" notin code + # template is expanded (but that would already be the case with + # `a.getImpl.repr`, unlike the other transformations mentioned above From ae358a0c7a5f7b14e5dde259cd6ce02b235985a3 Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Sat, 18 Jul 2020 10:39:41 -0400 Subject: [PATCH 0915/4254] fix docs for nativesocket read/write selects (#15010) The sockets which *cannot* be _[read from or written to]_ will also be removed from ``readfds``. --- lib/pure/nativesockets.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 35a7396b9..49a1192df 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -656,7 +656,7 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = proc selectRead*(readfds: var seq[SocketHandle], timeout = 500): int = ## When a socket in ``readfds`` is ready to be read from then a non-zero ## value will be returned specifying the count of the sockets which can be - ## read from. The sockets which can be read from will also be removed + ## read from. The sockets which cannot be read from will also be removed ## from ``readfds``. ## ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for @@ -678,7 +678,7 @@ proc selectWrite*(writefds: var seq[SocketHandle], timeout = 500): int {.tags: [ReadIOEffect].} = ## When a socket in ``writefds`` is ready to be written to then a non-zero ## value will be returned specifying the count of the sockets which can be - ## written to. The sockets which can be written to will also be removed + ## written to. The sockets which cannot be written to will also be removed ## from ``writefds``. ## ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for From ffe7b3a9bf1596e5016c8fcaf775f9261188d349 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 18 Jul 2020 21:40:44 +0200 Subject: [PATCH 0916/4254] threadpool.nim: minor code style changes --- lib/pure/concurrency/threadpool.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 2abcafb80..f0269f526 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -208,7 +208,7 @@ proc finished(fv: var FlowVarBaseObj) = # the worker thread waits for "data" to be set to nil before shutting down owner.data = nil -proc `=destroy`[T](fv: var FlowVarObj[T]) = +proc `=destroy`[T](fv: var FlowVarObj[T]) = finished(fv) `=destroy`(fv.blob) @@ -321,15 +321,15 @@ var currentPoolSize: int maxPoolSize = MaxThreadPoolSize minPoolSize = 4 - gSomeReady : Semaphore + gSomeReady: Semaphore readyWorker: ptr Worker # A workaround for recursion deadlock issue # https://github.com/nim-lang/Nim/issues/4597 var numSlavesLock: Lock - numSlavesRunning {.guard: numSlavesLock}: int - numSlavesWaiting {.guard: numSlavesLock}: int + numSlavesRunning {.guard: numSlavesLock.}: int + numSlavesWaiting {.guard: numSlavesLock.}: int isSlave {.threadvar.}: bool numSlavesLock.initLock @@ -464,7 +464,7 @@ proc pinnedSpawn*(id: ThreadId; call: sink typed): void {.magic: "Spawn".} ## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a ## return type that is either ``void`` or compatible with ``FlowVar[T]``. -template spawnX*(call): void = +template spawnX*(call) = ## Spawns a new task if a CPU core is ready, otherwise executes the ## call in the calling thread. ## From 1e3a0ef1e1983f2e493f8f42afbb0ae3fbc4fd11 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 19 Jul 2020 07:41:36 +0100 Subject: [PATCH 0917/4254] [Backport] Fixes callbacks being dropped on Linux/macOS/BSD. (#15012) Fixes #15003. This is a serious bug which occurs when data cannot be read/sent immediately and there are a bunch of other read/write events pending. What happens is that the new events are dropped which results in the case of the reported bug resulted in some data not being sent (!). --- lib/pure/asyncdispatch.nim | 7 +++- tests/async/tasynceagain.nim | 67 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/async/tasynceagain.nim diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 2ade9065f..6330a6ba9 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1228,14 +1228,19 @@ else: let newLength = max(len(curList), InitCallbackListSize) var newList = newSeqOfCap[Callback](newLength) + var eventsExtinguished = false for cb in curList: + if eventsExtinguished: + newList.add(cb) + continue if not cb(fd): # Callback wants to be called again. newList.add(cb) # This callback has returned with EAGAIN, so we don't need to # call any other callbacks as they are all waiting for the same event # on the same fd. - break + # We do need to ensure they are called again though. + eventsExtinguished = true withData(selector, fd.int, fdData) do: # Descriptor is still present in the queue. diff --git a/tests/async/tasynceagain.nim b/tests/async/tasynceagain.nim new file mode 100644 index 000000000..aebd4ef16 --- /dev/null +++ b/tests/async/tasynceagain.nim @@ -0,0 +1,67 @@ +discard """ + disabled: "windows" + exitcode: 0 +""" +# AsyncSocketBug.nim +# Jens Alfke (@snej) -- 16 July 2020 +# Demonstrates data loss by Nim's AsyncSocket. +# Just run it, and it will raise an assertion failure within a minute. + +import asyncdispatch, asyncnet, strformat, strutils, sugar + +const FrameSize = 9999 # Exact size not important, but larger sizes fail quicker + +proc runServer() {.async.} = + # Server side: + var server = newAsyncSocket() + server.bindAddr(Port(9001)) + server.listen() + let client = await server.accept() + echo "Server got client connection" + var lastN = 0 + while true: + let frame = await client.recv(FrameSize) + assert frame.len == FrameSize + let n = frame[0..<6].parseInt() + echo "RCVD #", n, ": ", frame[0..80], "..." + if n != lastN + 1: + echo &"******** ERROR: Server received #{n}, but last was #{lastN}!" + assert n == lastN + 1 + lastN = n + await sleepAsync 100 + + +proc main() {.async.} = + asyncCheck runServer() + + # Client side: + let socket = newAsyncSocket(buffered = false) + await socket.connect("localhost", Port(9001)) + echo "Client socket connected" + + var sentCount = 0 + var completedCount = 0 + + while sentCount < 2000: + sentCount += 1 + let n = sentCount + + var message = &"{n:06} This is message #{n} of ∞. Please stay tuned for more. " + #echo ">>> ", message + while message.len < FrameSize: + message = message & message + let frame = message[0.. Date: Mon, 20 Jul 2020 05:44:06 +0200 Subject: [PATCH 0918/4254] enable 'nimterop' test --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 58f07b017..3d5436c84 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -86,7 +86,7 @@ pkg2 "nimpy", false, "nim c -r tests/nimfrompy.nim" pkg2 "nimquery" pkg2 "nimsl", true pkg2 "nimsvg" -# pkg2 "nimterop", true +pkg2 "nimterop", true, "nimble minitest" pkg2 "nimwc", true, "nim c nimwc.nim" # pkg2 "nimx", true, "nim c --threads:on test/main.nim" # pkg2 "nitter", true, "nim c src/nitter.nim", "https://github.com/zedeus/nitter" From bb1adf6a706190883fa57a0208ba8e3118235256 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 20 Jul 2020 04:17:33 +0000 Subject: [PATCH 0919/4254] io: fix SetHandleInformation signature to match Windows' (#15017) * io: fix SetHandleInformation signature to match Windows' Fixes #14980 * rename Handle -> IoHandle because system.nim is a mess --- lib/system/io.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 482057214..0b624de8f 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -282,7 +282,11 @@ elif defined(windows): proc getOsfhandle(fd: cint): int {. importc: "_get_osfhandle", header: "".} - proc setHandleInformation(handle: int, mask, flags: culong): cint {. + type + IoHandle = distinct pointer + ## Windows' HANDLE type. Defined as an untyped pointer but is **not** + ## one. Named like this to avoid collision with other `system` modules. + proc setHandleInformation(handle: IoHandle, mask, flags: culong): cint {. importc: "SetHandleInformation", header: "".} const @@ -339,7 +343,8 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w flags = if inheritable: flags and not FD_CLOEXEC else: flags or FD_CLOEXEC result = c_fcntl(f, F_SETFD, flags) != -1 else: - result = setHandleInformation(f.int, HANDLE_FLAG_INHERIT, culong inheritable) != 0 + result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT, + culong inheritable) != 0 proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} = From 71dd5f85b9a13d97ea0c74338722bf08a9ae6286 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Jul 2020 07:50:19 +0200 Subject: [PATCH 0920/4254] 'isolate' builtin; refs https://github.com/nim-lang/RFCs/issues/244 (#15011) --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 2 +- compiler/isolation_check.nim | 117 +++++++++++++++++++++++++++++++++++ compiler/jsgen.nim | 2 +- compiler/sem.nim | 3 +- compiler/semmagic.nim | 5 +- compiler/vmgen.nim | 2 +- lib/std/isolation.nim | 31 ++++++++++ tests/isolate/tisolate.nim | 36 +++++++++++ 9 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 compiler/isolation_check.nim create mode 100644 lib/std/isolation.nim create mode 100644 tests/isolate/tisolate.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b57ee542d..d8fe6b1c0 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -658,7 +658,7 @@ type mSwap, mIsNil, mArrToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, - mDefault, mUnown, mAccessEnv, mReset, + mDefault, mUnown, mIsolate, mAccessEnv, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dc9617fe2..003b3e240 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2209,7 +2209,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") - of mStrToStr, mUnown: expr(p, e[1], d) + of mStrToStr, mUnown, mIsolate: expr(p, e[1], d) of mEnumToStr: if optTinyRtti in p.config.globalOptions: genEnumToStr(p, e, d) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim new file mode 100644 index 000000000..a77e8c97a --- /dev/null +++ b/compiler/isolation_check.nim @@ -0,0 +1,117 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Implementation of the check that `recover` needs, see +## https://github.com/nim-lang/RFCs/issues/244 for more details. + +import + ast, types, renderer, idents, intsets, options, msgs + +proc canAlias(arg, ret: PType; marker: var IntSet): bool + +proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool = + case n.kind + of nkRecList: + for i in 0.. 0 and ret[0] != nil: + result = canAlias(arg, ret[0], marker) + else: + result = true + of tyTuple: + for i in 0.. 0: + result = checkIsolate(n[^1]) + else: + result = false + else: + # unanalysable expression: + result = false + else: + # no ref, no cry: + result = true + diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 57a6b8094..d876531e9 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -653,7 +653,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = useMagic(p, "nimFloatToString") applyFormat "cstrToNimstr(nimFloatToString($1))" of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)") - of mStrToStr, mUnown: applyFormat("$1", "$1") + of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1") else: assert false, $op diff --git a/compiler/sem.nim b/compiler/sem.nim index a657939a5..1f98b4f87 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,7 +16,8 @@ import procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, plugins/active, rod, lineinfos, strtabs, int128 + lowerings, plugins/active, rod, lineinfos, strtabs, int128, + isolation_check from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e7a964d81..6aa440aa9 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -558,6 +558,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, let constructed = result[1].typ.base if constructed.requiresInit: message(c.config, n.info, warnUnsafeDefault, typeToString(constructed)) + of mIsolate: + if not checkIsolate(n[1]): + localError(c.config, n.info, "expression cannot be isolated: " & $n[1]) + result = n else: result = n - diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 52b7b6eb3..4ef510d20 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -997,7 +997,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.genNarrow(n[1], d) c.genAsgnPatch(n[1], d) c.freeTemp(d) - of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest) + of mOrd, mChr, mArrToSeq, mUnown, mIsolate: c.gen(n[1], dest) of mNew, mNewFinalize: unused(c, n, dest) c.genNew(n) diff --git a/lib/std/isolation.nim b/lib/std/isolation.nim new file mode 100644 index 000000000..7ca5f0080 --- /dev/null +++ b/lib/std/isolation.nim @@ -0,0 +1,31 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the `Isolated[T]` type for +## safe construction of isolated subgraphs that can be +## passed efficiently to different channels and threads. + +type + Isolated*[T] = object ## Isolated data can only be moved, not copied. + value: T + +proc `=`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.} + +proc `=sink`*[T](dest: var Isolated[T]; src: Isolated[T]) {.inline.} = + # delegate to value's sink operation + `=sink`(dest.value, src.value) + +proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} = + # delegate to value's destroy operation + `=destroy`(dest.value) + +func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".} + ## Create an isolated subgraph from the expression `value`. + ## Please read https://github.com/nim-lang/RFCs/issues/244 + ## for more details. diff --git a/tests/isolate/tisolate.nim b/tests/isolate/tisolate.nim new file mode 100644 index 000000000..9f3b15441 --- /dev/null +++ b/tests/isolate/tisolate.nim @@ -0,0 +1,36 @@ +discard """ + errormsg: "expression cannot be isolated: select(a, b)" + line: 34 +""" + +import std / isolation + +import json, streams + +proc f(): seq[int] = + @[1, 2, 3] + +type + Node = ref object + x: string + +proc g(): Node = nil + +proc select(a, b: Node): Node = + a + +proc main = + discard isolate f() + + + discard isolate g() + + discard isolate select(Node(x: "a"), nil) + discard isolate select(Node(x: "a"), Node(x: "b")) + + discard isolate parseJson(newFileStream("my.json"), "my.json") + + var a, b: Node + discard isolate select(a, b) + +main() From 9a76398ec6405dab88512fbc891b809ec2dd0325 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 20 Jul 2020 06:02:48 +0000 Subject: [PATCH 0921/4254] koch: use in-tree Nim to run test if possible (#15018) Fixes #15013 --- koch.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index 95c54892f..7dedb039a 100644 --- a/koch.nim +++ b/koch.nim @@ -440,8 +440,10 @@ template `|`(a, b): string = (if a.len > 0: a else: b) proc tests(args: string) = nimexec "cc --opt:speed testament/testament" - let tester = quoteShell(getCurrentDir() / "testament/testament".exe) - let success = tryExec tester & " " & (args|"all") + var testCmd = quoteShell(getCurrentDir() / "testament/testament".exe) + testCmd.add " " & quoteShell("--nim:" & findNim()) + testCmd.add " " & (args|"all") + let success = tryExec testCmd if not success: quit("tests failed", QuitFailure) From 49d4b50fe52f0e961ef367a44be8b1bd79994a03 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Jul 2020 14:28:00 +0200 Subject: [PATCH 0922/4254] fixes #14194 (#15023) --- compiler/extccomp.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 7d5df0906..1c6b1a8d0 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -429,7 +429,6 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} = proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string = result = conf.compileOptions - addOpt(result, conf.cfileSpecificOptions.getOrDefault(fullNimFile)) for option in conf.compileOptionsCmd: if strutils.find(result, option, 0) < 0: @@ -450,6 +449,8 @@ proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string let key = nimname & ".always" if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) + addOpt(result, conf.cfileSpecificOptions.getOrDefault(fullNimFile)) + proc getCompileOptions(conf: ConfigRef): string = result = cFileSpecificOptions(conf, "__dummy__", "__dummy__") From 80d3ef995282ec2e37968feedf7914ade6f2e62f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Jul 2020 17:44:35 +0200 Subject: [PATCH 0923/4254] hotfix: firstOrd/lastOrd for 'tyLent' as it shows up in strange places, as usual --- compiler/types.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 1f787a4e5..506e63478 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -729,7 +729,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = assert(t.n[0].kind == nkSym) result = toInt128(t.n[0].sym.position) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses: + tyStatic, tyInferred, tyUserTypeClasses, tyLent: result = firstOrd(conf, lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(conf, lastSon(t)) @@ -786,7 +786,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = assert(t.n[^1].kind == nkSym) result = toInt128(t.n[^1].sym.position) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses: + tyStatic, tyInferred, tyUserTypeClasses, tyLent: result = lastOrd(conf, lastSon(t)) of tyProxy: result = Zero of tyOrdinal: From 3a4e4cec4d9017705bea1b496e8a2b81776ca34f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Jul 2020 18:37:14 +0200 Subject: [PATCH 0924/4254] cursor inference bugfix --- compiler/cursor_inference.nim | 5 +-- tests/arc/topt_no_cursor.nim | 64 +++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim index 94b06ac79..b26a29d4c 100644 --- a/compiler/cursor_inference.nim +++ b/compiler/cursor_inference.nim @@ -237,10 +237,11 @@ proc analyse(c: var Con; n: PNode) = # assignments like 'x.field = value' mean that 'x' itself cannot # be a cursor: let r = locationRoot(n[0]) - if r != nil and r.typ.skipTypes(abstractInst).kind notin {tyPtr, tyRef}: + if r != nil: # however, an assignment like 'it.field = x' does not influence r's # cursorness property: - c.mayOwnData.incl r.id + if r.typ.skipTypes(abstractInst).kind notin {tyPtr, tyRef}: + c.mayOwnData.incl r.id c.mutations.incl r.id if hasDestructor(n[1].typ): diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 3d3262491..e50418671 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -1,6 +1,9 @@ discard """ - output: '''(repo: "", package: "meo", ext: "")''' - cmd: '''nim c --gc:arc --expandArc:newTarget --hint:Performance:off $file''' + output: '''(repo: "", package: "meo", ext: "") +doing shady stuff... +3 +6''' + cmd: '''nim c --gc:arc --expandArc:newTarget --expandArc:delete --hint:Performance:off $file''' nimout: '''--expandArc: newTarget var @@ -23,6 +26,14 @@ result = ( let blitTmp_2 = :tmp_2 blitTmp_2) `=destroy`(splat) +-- end of expandArc ------------------------ +--expandArc: delete + +var saved +var sibling_cursor = target.parent.left +`=`(saved, sibling_cursor.right) +`=`(sibling_cursor.right, saved.left) +`=sink`(sibling_cursor.parent, saved) -- end of expandArc ------------------------''' """ @@ -35,3 +46,52 @@ proc newTarget*(path: string): Target = result = (repo: splat.dir, package: splat.name, ext: splat.ext) echo newTarget("meo") + +type + Node = ref object + left, right, parent: Node + value: int + +proc delete(target: var Node) = + var sibling = target.parent.left # b3 + var saved = sibling.right # b3.right -> r4 + + sibling.right = saved.left # b3.right -> r4.left = nil + sibling.parent = saved # b3.parent -> r5 = r4 + + #[after this proc: + b 5 + / \ + b 3 b 6 + ]# + + +#[before: + r 5 + / \ + b 3 b 6 - to delete + / \ +empty r 4 +]# +proc main = + var five = Node(value: 5) + + var six = Node(value: 6) + six.parent = five + five.right = six + + var three = Node(value: 3) + three.parent = five + five.left = three + + var four = Node(value: 4) + four.parent = three + three.right = four + + echo "doing shady stuff..." + delete(six) + # need both of these echos + echo five.left.value + echo five.right.value + +main() From 64d629c617b5bbc700349afbc16607e2ed9f8eeb Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 22 Jul 2020 01:11:12 +0800 Subject: [PATCH 0925/4254] Shadow Dom apis (#14979) * shadow dom api * fix typos * host to Element type * fix code style * move elementsFromPoint to dom_extensions.nim --- lib/js/dom.nim | 32 ++++++++++++++++++++++++++++++++ lib/js/dom_extensions.nim | 5 +++++ 2 files changed, 37 insertions(+) create mode 100644 lib/js/dom_extensions.nim diff --git a/lib/js/dom.nim b/lib/js/dom.nim index be676a813..84ceb73f3 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1324,6 +1324,26 @@ since (1, 3): FileReaderObj {.importc.} = object of EventTargetObj FileReaderState* = distinct range[0'u16..2'u16] + RootNodeOptions* = object of RootObj + composed*: bool + DocumentOrShadowRoot* {.importc.} = object of RootObj + activeElement*: Element + # styleSheets*: StyleSheetList + ShadowRoot* = ref ShadowRootObj + ShadowRootObj {.importc.} = object of DocumentOrShadowRoot + delegatesFocus*: bool + host*: Element + innerHTML*: cstring + mode*: cstring # "open" or "closed" + ShadowRootInit* = object of RootObj + mode*: cstring + delegatesFocus*: bool + + HTMLSlotElement* = ref HTMLSlotElementObj + HTMLSlotElementObj {.importc.} = object of RootObj + name*: cstring + SlotOptions* = object of RootObj + flatten*: bool const fileReaderEmpty* = 0.FileReaderState @@ -1503,6 +1523,18 @@ proc contains*(n: Node): bool proc isEqualNode*(n: Node): bool proc isSameNode*(n: Node): bool +since (1, 3): + proc getRootNode*(n: Node,options: RootNodeOptions): Node + + # DocumentOrShadowRoot + proc getSelection*(n: DocumentOrShadowRoot): Selection + proc elementFromPoint*(n: DocumentOrShadowRoot; x, y: float): Element + + # shadow dom + proc attachShadow*(n: Element): ShadowRoot + proc assignedNodes*(n: HTMLSlotElement; options: SlotOptions): seq[Node] + proc assignedElements*(n: HTMLSlotElement; options: SlotOptions): seq[Element] + # Document "methods" proc createAttribute*(d: Document, identifier: cstring): Node proc getElementsByName*(d: Document, name: cstring): seq[Element] diff --git a/lib/js/dom_extensions.nim b/lib/js/dom_extensions.nim new file mode 100644 index 000000000..851ec0c5f --- /dev/null +++ b/lib/js/dom_extensions.nim @@ -0,0 +1,5 @@ +import dom + +{.push importcpp.} +proc elementsFromPoint*(n: DocumentOrShadowRoot; x, y: float): seq[Element] +{.pop.} \ No newline at end of file From 450a3e3179096c09cb473956386940a212f9a1d2 Mon Sep 17 00:00:00 2001 From: genotrance Date: Tue, 21 Jul 2020 12:14:36 -0500 Subject: [PATCH 0926/4254] Fix #2408 - add -d:globalSymbols (#14904) --- doc/nimc.rst | 3 +++ lib/system/dyncalls.nim | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/nimc.rst b/doc/nimc.rst index bd5e897c3..379d8b559 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -454,6 +454,9 @@ Define Effect path for the ``sh`` binary, in cases where it is not located in the default location ``/bin/sh``. ``noSignalHandler`` Disable the crash handler from ``system.nim``. +``globalSymbols`` Load all ``{.dynlib.}`` libraries with the ``RTLD_GLOBAL`` + flag on Posix systems to resolve symbols in subsequently + loaded libraries. ====================== ========================================================= diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index fe4797c5f..a15d9267f 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -91,7 +91,10 @@ when defined(posix): dlclose(lib) proc nimLoadLibrary(path: string): LibHandle = - result = dlopen(path, RTLD_NOW) + let flags = + when defined(globalSymbols): RTLD_NOW or RTLD_GLOBAL + else: RTLD_NOW + result = dlopen(path, flags) when defined(nimDebugDlOpen): let error = dlerror() if error != nil: From 5fafa2fd5c78232e4fe2d3d13bc67ab6c0cda0bb Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 21 Jul 2020 22:49:08 +0200 Subject: [PATCH 0927/4254] fix several newline problems (#15028) [backend] * prevent newlines where they shouldn't be * 'contentLength' shouldn't be negative --- lib/pure/asyncftpclient.nim | 4 ++++ lib/pure/httpclient.nim | 8 +++++++- lib/pure/smtp.nim | 27 ++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 4e62ecd97..208782c05 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -146,7 +146,11 @@ proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} = ## Send a message to the server, and wait for a primary reply. ## ``\c\L`` is added for you. ## + ## You need to make sure that the message ``m`` doesn't contain any newline + ## characters. Failing to do so will raise ``AssertionDefect``. + ## ## **Note:** The server may return multiple lines of coded replies. + doAssert(not m.contains({'\c', '\L'}), "message shouldn't contain any newline characters") await ftp.csock.send(m & "\c\L") return await ftp.expectReply() diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 92e4cd2d6..a590bd83a 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -245,7 +245,8 @@ proc contentLength*(response: Response | AsyncResponse): int = ## ## A ``ValueError`` exception will be raised if the value is not an integer. var contentLengthHeader = response.headers.getOrDefault("Content-Length") - return contentLengthHeader.parseInt() + result = contentLengthHeader.parseInt() + doAssert(result >= 0 and result <= high(int32)) proc lastModified*(response: Response | AsyncResponse): DateTime = ## Retrieves the specified response's last modified time. @@ -1033,6 +1034,11 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string, ## ## This procedure will follow redirects up to a maximum number of redirects ## specified in ``client.maxRedirects``. + ## + ## You need to make sure that the ``url`` doesn't contain any newline + ## characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not url.contains({'\c', '\L'}), "url shouldn't contain any newline characters") + result = await client.requestAux(url, httpMethod, body, headers, multipart) var lastURL = url diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index f24815a1d..7d426041d 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -43,7 +43,7 @@ ## For SSL support this module relies on OpenSSL. If you want to ## enable SSL, compile with ``-d:ssl``. -import net, strutils, strtabs, base64, os +import net, strutils, strtabs, base64, os, strutils import asyncnet, asyncdispatch export Port @@ -65,6 +65,11 @@ type Smtp* = SmtpBase[Socket] AsyncSmtp* = SmtpBase[AsyncSocket] +proc containsNewline(xs: seq[string]): bool = + for x in xs: + if x.contains({'\c', '\L'}): + return true + proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = ## Sends ``cmd`` on the socket connected to the SMTP server. ## @@ -119,6 +124,14 @@ else: proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], otherHeaders: openarray[tuple[name, value: string]]): Message = ## Creates a new MIME compliant message. + ## + ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain + ## any newline characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not mSubject.contains({'\c', '\L'}), + "'mSubject' shouldn't contain any newline characters") + doAssert(not (mTo.containsNewline() or mCc.containsNewline()), + "'mTo' and 'mCc' shouldn't contain any newline characters") + result.msgTo = mTo result.msgCc = mCc result.msgSubject = mSubject @@ -130,6 +143,13 @@ proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string] = @[]): Message = ## Alternate version of the above. + ## + ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain + ## any newline characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not mSubject.contains({'\c', '\L'}), + "'mSubject' shouldn't contain any newline characters") + doAssert(not (mTo.containsNewline() or mCc.containsNewline()), + "'mTo' and 'mCc' shouldn't contain any newline characters") result.msgTo = mTo result.msgCc = mCc result.msgSubject = mSubject @@ -247,6 +267,11 @@ proc sendMail*(smtp: Smtp | AsyncSmtp, fromAddr: string, ## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``. ## Messages may be formed using ``createMessage`` by converting the ## Message into a string. + ## + ## You need to make sure that ``fromAddr`` and ``toAddrs`` don't contain + ## any newline characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not (toAddrs.containsNewline() or fromAddr.contains({'\c', '\L'})), + "'toAddrs' and 'fromAddr' shouldn't contain any newline characters") await smtp.debugSend("MAIL FROM:<" & fromAddr & ">\c\L") await smtp.checkReply("250") From 911e39351e34c1022b586fe9bfc3a67b2ce3bf44 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 21 Jul 2020 23:23:33 +0200 Subject: [PATCH 0928/4254] ARC: optimize the code better when --panics:off (#15031) --- compiler/liftdestructors.nim | 42 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 21fef1d61..034e62494 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -10,9 +10,6 @@ ## This module implements lifting for type-bound operations ## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``). -# Todo: -# - use openArray instead of array to avoid over-specializations - import modulegraphs, lineinfos, idents, ast, renderer, semdata, sighashes, lowerings, options, types, msgs, magicsys, tables @@ -26,8 +23,9 @@ type fn: PSym asgnForType: PType recurse: bool - filterDiscriminator: PSym # we generating destructor for case branch addMemReset: bool # add wasMoved() call after destructor call + canRaise: bool + filterDiscriminator: PSym # we generating destructor for case branch c: PContext # c can be nil, then we are called from lambdalifting! proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) @@ -120,10 +118,12 @@ proc genContainerOf(c: TLiftCtx; objType: PType, field, x: PSym): PNode = result.add newNodeIT(nkType, c.info, objPtr) result.add minusExpr -proc destructorCall(c: TLiftCtx; op: PSym; x: PNode): PNode = +proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = var destroy = newNodeIT(nkCall, x.info, op.typ[0]) destroy.add(newSymNode(op)) destroy.add genAddr(c.g, x) + if sfNeverRaises notin op.flags: + c.canRaise = true if c.addMemReset: result = newTree(nkStmtList, destroy, genBuiltin(c.g, mWasMoved, "wasMoved", x)) else: @@ -243,25 +243,29 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = else: fillBodyObjTImpl(c, t, body, x, y) -proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode = +proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = #if sfError in op.flags: # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) result = newNodeI(nkCall, x.info) result.add newSymNode(op) + if sfNeverRaises notin op.flags: + c.canRaise = true if op.typ.sons[1].kind == tyVar: - result.add genAddr(g, x) + result.add genAddr(c.g, x) else: result.add x if y != nil: result.add y -proc newOpCall(op: PSym; x: PNode): PNode = +proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = result = newNodeIT(nkCall, x.info, op.typ[0]) result.add(newSymNode(op)) result.add x + if sfNeverRaises notin op.flags: + c.canRaise = true -proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = - result = newAsgnStmt(x, newOpCall(op, y)) +proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = + result = newAsgnStmt(x, newOpCall(c, op, y)) proc usesBuiltinArc(t: PType): bool = proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t) @@ -293,7 +297,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; #else: # markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add newHookCall(c.g, op, x, y) + body.add newHookCall(c, op, x, y) result = true elif tfHasAsgn in t.flags: var op: PSym @@ -322,7 +326,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; #debug(t) #return false assert op.ast[genericParamsPos].kind == nkEmpty - body.add newHookCall(c.g, op, x, y) + body.add newHookCall(c, op, x, y) result = true proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) = @@ -373,7 +377,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = if op != nil: #markUsed(c.g.config, c.info, op, c.g.usageSym) onUse(c.info, op) - body.add newDeepCopyCall(op, x, y) + body.add newDeepCopyCall(c, op, x, y) result = true proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = @@ -460,7 +464,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedAsgn, attachedDeepCopy: if t.assignment == nil: return # protect from recursion - body.add newHookCall(c.g, t.assignment, x, y) + body.add newHookCall(c, t.assignment, x, y) of attachedSink: # we always inline the move for better performance: let moveCall = genBuiltin(c.g, mMove, "move", x) @@ -471,18 +475,18 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # alternatively we could do this: when false: doAssert t.asink != nil - body.add newHookCall(c.g, t.asink, x, y) + body.add newHookCall(c, t.asink, x, y) of attachedDestructor: doAssert t.destructor != nil body.add destructorCall(c, t.destructor, x) of attachedTrace: if t.attachedOps[c.kind] == nil: return # protect from recursion - body.add newHookCall(c.g, t.attachedOps[c.kind], x, y) + body.add newHookCall(c, t.attachedOps[c.kind], x, y) of attachedDispose: if t.attachedOps[c.kind] == nil: return # protect from recursion - body.add newHookCall(c.g, t.attachedOps[c.kind], x, nil) + body.add newHookCall(c, t.attachedOps[c.kind], x, nil) proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -837,7 +841,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; sfOverriden in typ.attachedOps[attachedDestructor].flags: ## compiler can use a combination of `=destroy` and memCopy for sink op dest.flags.incl sfCursor - result.ast[bodyPos].add newOpCall(typ.attachedOps[attachedDestructor], d[0]) + result.ast[bodyPos].add newOpCall(a, typ.attachedOps[attachedDestructor], d[0]) result.ast[bodyPos].add newAsgnStmt(d, src) else: var tk: TTypeKind @@ -852,6 +856,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; fillStrOp(a, typ, result.ast[bodyPos], d, src) else: fillBody(a, typ, result.ast[bodyPos], d, src) + if not a.canRaise: incl result.flags, sfNeverRaises proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, info: TLineInfo): PSym = @@ -873,6 +878,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, result.ast[bodyPos].add v let placeHolder = newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) fillBody(a, typ, result.ast[bodyPos], d, placeHolder) + if not a.canRaise: incl result.flags, sfNeverRaises template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = From 503c5e0520779af87dc6c42da7c9d1dbd2e8f8e1 Mon Sep 17 00:00:00 2001 From: Mildred Ki'Lya Date: Wed, 22 Jul 2020 06:30:33 +0200 Subject: [PATCH 0929/4254] smtp: Fix STARTTLS, request HELO once TLS is established (#15032) --- lib/pure/smtp.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 7d426041d..b42664029 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -60,6 +60,7 @@ type SmtpBase[SocketType] = ref object sock: SocketType + address: string debug: bool Smtp* = SmtpBase[Socket] @@ -225,15 +226,19 @@ proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = if not line.startswith(reply): await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line) +proc helo*(smtp: Smtp | AsyncSmtp) {.multisync.} = + # Sends the HELO request + await smtp.debugSend("HELO " & smtp.address & "\c\L") + await smtp.checkReply("250") + proc connect*(smtp: Smtp | AsyncSmtp, address: string, port: Port) {.multisync.} = ## Establishes a connection with a SMTP server. ## May fail with ReplyError or with a socket error. + smtp.address = address await smtp.sock.connect(address, port) - await smtp.checkReply("220") - await smtp.debugSend("HELO " & address & "\c\L") - await smtp.checkReply("250") + await smtp.helo() proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SSLContext = nil) {.multisync.} = ## Put the SMTP connection in TLS (Transport Layer Security) mode. @@ -245,6 +250,7 @@ proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SSLContext = nil) {.multisync getSSLContext().wrapConnectedSocket(smtp.sock, handshakeAsClient) else: sslContext.wrapConnectedSocket(smtp.sock, handshakeAsClient) + await smtp.helo() else: {.error: "SMTP module compiled without SSL support".} From f25454d5c6b455d95aa526b57678ec8494ac0e36 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Wed, 22 Jul 2020 10:52:38 +0300 Subject: [PATCH 0930/4254] Add a testcase for #14480. Fixes #14480 (#15037) --- tests/arc/tarcmisc.nim | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 56aa3ec3b..51c80c348 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -257,3 +257,10 @@ echo "new line before - ", newline newline.insert(indent, 0) echo "new line after - ", newline + +# bug #14480 +proc hello(): int = + result = 42 + +var leaves {.global.} = hello() +doAssert leaves == 42 From 32ac1b7c9df8614510c08c0a4649131cf33f369c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Wed, 22 Jul 2020 10:30:46 +0200 Subject: [PATCH 0931/4254] fix #15033 (#15034) --- lib/pure/math.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index ea44de6d3..c02bef2f7 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -958,7 +958,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = {.pop.} {.pop.} -proc `^`*[T](x: T, y: Natural): T = +proc `^`*[T: SomeNumber](x: T, y: Natural): T = ## Computes ``x`` to the power ``y``. ## ## Exponent ``y`` must be non-negative, use From d84894de2e04b22111a607eb72d301a1535a65e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 22 Jul 2020 13:02:03 +0200 Subject: [PATCH 0932/4254] fixes #15026 [backport] (#15040) no test case since only a special case was affected and the special case got removed --- compiler/ccgstmts.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c56340e00..0f58df3a4 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1292,7 +1292,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = # handler present or only handlers that did not match. linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) endBlock(p) - if p.prc != nil: raiseExit(p) + raiseExit(p) if hasExcept: inc p.withinTryWithExcept proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = From ec65bfae3ac20a6c3d13249bc1fc8413db2b3abb Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 22 Jul 2020 14:57:40 +0200 Subject: [PATCH 0933/4254] Change testing commands for some packages (#15041) --- testament/important_packages.nim | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 3d5436c84..8fa7c99a9 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -13,7 +13,6 @@ var packages2*: seq[tuple[name, cmd: string; hasDeps: bool; url: string, useHead pkg1 "argparse" pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" -pkg1 "asyncmysql", true pkg1 "awk", true pkg1 "bigints" pkg1 "binaryheap", false, "nim c -r binaryheap.nim" @@ -30,7 +29,6 @@ pkg1 "chronicles", true, "nim c -o:chr -r chronicles.nim" when not defined(osx): # testdatagram.nim(560, 54): Check failed pkg1 "chronos", true, "nim c -r -d:release tests/testall" pkg1 "cligen", false, "nim c -o:cligenn -r cligen.nim" -pkg1 "coco", true pkg1 "combparser" pkg1 "compactdict" pkg1 "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension" @@ -45,7 +43,7 @@ pkg1 "gara" pkg1 "ggplotnim", true, "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" pkg1 "glob" -pkg1 "gnuplot" +pkg1 "gnuplot", false, "nim c gnuplot.nim" pkg1 "hts", false, "nim c -o:htss src/hts.nim" # pkg1 "httpauth", true pkg1 "illwill", false, "nimble examples" @@ -69,7 +67,7 @@ pkg1 "stint", false, "nim c -o:stintt -r stint.nim" # packages N-Z pkg2 "nake", false, "nim c nakefile.nim" pkg2 "neo", true, "nim c -d:blas=openblas tests/all.nim" -pkg2 "nesm" +# pkg2 "nesm", false, "nimble tests" # notice plural 'tests' # pkg2 "nico", true pkg2 "nicy", false, "nim c -r src/nicy.nim" pkg2 "nigui", false, "nim c -o:niguii -r src/nigui.nim" @@ -121,7 +119,7 @@ pkg2 "tempdir" pkg2 "templates" pkg2 "tensordsl", false, "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" pkg2 "terminaltables", false, "nim c src/terminaltables.nim" -pkg2 "termstyle" +pkg2 "termstyle", false, "nim c -r termstyle.nim" pkg2 "timeit" pkg2 "timezones" pkg2 "tiny_sqlite" @@ -132,5 +130,5 @@ pkg2 "websocket", false, "nim c websocket.nim" # pkg2 "winim", true pkg2 "with" pkg2 "ws" -pkg2 "yaml" +pkg2 "yaml", false, "nim build" pkg2 "zero_functional", false, "nim c -r -d:nimWorkaround14447 test.nim" From 925dd92e07bd8b031c9f237ceb9e352c34a97d64 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 23 Jul 2020 11:03:39 +0200 Subject: [PATCH 0934/4254] enforce browsers.nim only handles URLs [backport] (#15045) --- lib/pure/browsers.nim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 2dc14b895..9b3b67104 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -18,6 +18,7 @@ import strutils when defined(windows): import winlean + from os import absolutePath else: import os, osproc @@ -26,16 +27,21 @@ const osOpenCmd* = ## Alias for the operating system specific *"open"* command, ## ``"open"`` on OSX, MacOS and Windows, ``"xdg-open"`` on Linux, BSD, etc. +proc prepare(s: string): string = + if s.contains("://"): + result = s + else: + result = "file://" & absolutePath(s) -template openDefaultBrowserImpl(url: string) = +proc openDefaultBrowserImpl(url: string) = when defined(windows): var o = newWideCString(osOpenCmd) - var u = newWideCString(url) + var u = newWideCString(prepare url) discard shellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL) elif defined(macosx): - discard execShellCmd(osOpenCmd & " " & quoteShell(url)) + discard execShellCmd(osOpenCmd & " " & quoteShell(prepare url)) else: - var u = quoteShell(url) + var u = quoteShell(prepare url) if execShellCmd(osOpenCmd & " " & u) == 0: return for b in getEnv("BROWSER").string.split(PathSep): try: From 14d16c2174a4fcefd405f8c4eeaf57a6dcd2731d Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 23 Jul 2020 15:42:12 +0200 Subject: [PATCH 0935/4254] json.nim: smaller init size (#15048) There was a recent `rightSize` change in tables.nim, so the existing value (4) was creating too large tables. --- lib/pure/json.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 041816c7d..3f2e369f6 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -219,7 +219,7 @@ proc newJNull*(): JsonNode = proc newJObject*(): JsonNode = ## Creates a new `JObject JsonNode` - result = JsonNode(kind: JObject, fields: initOrderedTable[string, JsonNode](4)) + result = JsonNode(kind: JObject, fields: initOrderedTable[string, JsonNode](2)) proc newJArray*(): JsonNode = ## Creates a new `JArray JsonNode` @@ -264,7 +264,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool = else: return n.bval proc getFields*(n: JsonNode, - default = initOrderedTable[string, JsonNode](4)): + default = initOrderedTable[string, JsonNode](2)): OrderedTable[string, JsonNode] = ## Retrieves the key, value pairs of a `JObject JsonNode`. ## From c90c53e8bb93c99a323684d73df7e7ec4791107d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 23 Jul 2020 16:53:07 +0200 Subject: [PATCH 0936/4254] fixes #15044 [backport:1.2] --- compiler/semmagic.nim | 8 +++++--- tests/arc/tarcmisc.nim | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 6aa440aa9..f991b4ac6 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -527,12 +527,14 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}: localError(c.config, n.info, "finalizer must be a direct reference to a proc") elif optTinyRtti in c.config.globalOptions: + let fin = if n[^1].kind == nkLambda: n[^1][namePos].sym + else: n[^1].sym # check if we converted this finalizer into a destructor already: - let t = whereToBindTypeHook(c, n[^1].sym.typ[1].skipTypes(abstractInst+{tyRef})) - if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == n[^1].sym: + let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef})) + if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == fin: discard "already turned this one into a finalizer" else: - bindTypeHook(c, turnFinalizerIntoDestructor(c, n[^1].sym, n.info), n, attachedDestructor) + bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor) result = n of mDestroy: result = n diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 51c80c348..cb889db15 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -23,6 +23,7 @@ whiley ends :( 0 new line before - @['a'] new line after - @['a'] +finalizer closed destroying variable: 20 destroying variable: 10 @@ -258,6 +259,23 @@ newline.insert(indent, 0) echo "new line after - ", newline +# bug #15044 + +type + Test = ref object + +proc test: Test = + # broken + new(result, proc(x: Test) = + echo "finalizer" + ) + +proc tdirectFinalizer = + discard test() + +tdirectFinalizer() + + # bug #14480 proc hello(): int = result = 42 From 18a70a75638ded6ff23b2a9a57edfc7dd09bb5b1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 23 Jul 2020 18:21:44 +0200 Subject: [PATCH 0937/4254] fixes #15036 --- compiler/ast.nim | 3 ++- compiler/injectdestructors.nim | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d8fe6b1c0..6ca79aeee 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -230,7 +230,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 42 flags! + TSymFlag* = enum # 43 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -294,6 +294,7 @@ type sfNeverRaises # proc can never raise an exception, not even OverflowDefect # or out-of-memory sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' + sfSingleUsedTemp # For temporaries that we know will only be used once TSymFlags* = set[TSymFlag] diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 752438180..01f72744a 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -59,8 +59,6 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = s.vars.add(sym) result = newSymNode(sym) -const sfSingleUsedTemp = sfExported # For temporaries that we know will only be used once - proc nestedScope(parent: var Scope): Scope = Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) From 12a9fe017e4a49a161f5cabbbbcae0f5668b0ae3 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 24 Jul 2020 17:49:25 +0200 Subject: [PATCH 0938/4254] fixes #15056 [backport] --- compiler/semcall.nim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 0d8f0ae8b..0c30ce45e 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -219,7 +219,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg) # candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging case err.firstMismatch.kind - of kUnknownNamedParam: candidates.add("\n unknown named parameter: " & $nArg[0]) + of kUnknownNamedParam: + if nArg == nil: + candidates.add("\n unknown named parameter") + else: + candidates.add("\n unknown named parameter: " & $nArg[0]) of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0]) of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param") of kExtraArg: candidates.add("\n extra argument given") @@ -318,7 +322,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string = sym = nextOverloadIter(o, c, f) let ident = considerQuotedIdent(c, f, n).s - if nfDotField in n.flags and nfExplicitCall notin n.flags: + if {nfDotField, nfExplicitCall} * n.flags == {nfDotField}: let sym = n[1].typ.sym var typeHint = "" if sym == nil: From 4b93c61f0d783cbc1ce35d4494b533186595cdbd Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 24 Jul 2020 21:15:20 +0200 Subject: [PATCH 0939/4254] jsre: try to fix nightlies (#15057) --- lib/js/jsre.nim | 3 +++ tools/kochdocs.nim | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index 31cfa3d0b..b4f273d0b 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -1,6 +1,9 @@ ## Regular Expressions for the JavaScript target. ## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions +when not defined(js) and not defined(Nimdoc): + {.error: "This module only works on the JavaScript platform".} + type RegExp* {.importjs.} = object ## Regular Expressions for JavaScript target. flags* {.importjs.}: cstring ## cstring that contains the flags of the RegExp object. dotAll* {.importjs.}: bool ## Whether `.` matches newlines or not. diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 43b802ee2..8a8406a69 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -160,6 +160,7 @@ lib/posix/posix_linux_amd64_consts.nim lib/posix/posix_other_consts.nim lib/posix/posix_openbsd_amd64.nim lib/posix/posix_haiku.nim +lib/js/jsre.nim """.splitWhitespace() when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): @@ -258,7 +259,7 @@ proc buildDoc(nimArgs, destPath: string) = destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(doc): - let extra = if isJsOnly(d): " --backend:js " else: "" + let extra = if isJsOnly(d): "--backend:js" else: "" var nimArgs2 = nimArgs if d.isRelativeTo("compiler"): doAssert false commands[i] = nim & " doc $# $# --git.url:$# --outdir:$# --index:on $#" % From add003a07435a862191334a7f105cb27ecb73d1d Mon Sep 17 00:00:00 2001 From: jcosborn Date: Fri, 24 Jul 2020 14:19:11 -0500 Subject: [PATCH 0940/4254] fix assignment to converted concept type (#15051) * fix assignment to converted concept type * check for resolved concepts * add extra test --- compiler/types.nim | 4 +++ tests/concepts/tusertypeclasses2.nim | 54 +++++++++++++++++++--------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 506e63478..b0581e96a 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1070,7 +1070,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if x == y: return true var a = skipTypes(x, {tyGenericInst, tyAlias}) + while a.kind == tyUserTypeClass and tfResolved in a.flags: + a = skipTypes(a[^1], {tyGenericInst, tyAlias}) var b = skipTypes(y, {tyGenericInst, tyAlias}) + while b.kind == tyUserTypeClass and tfResolved in b.flags: + b = skipTypes(b[^1], {tyGenericInst, tyAlias}) assert(a != nil) assert(b != nil) if a.kind != b.kind: diff --git a/tests/concepts/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim index ae05540cd..c9978f6ef 100644 --- a/tests/concepts/tusertypeclasses2.nim +++ b/tests/concepts/tusertypeclasses2.nim @@ -1,24 +1,44 @@ -type - hasFieldX = concept z - z.x is int +block: + type + hasFieldX = concept z + z.x is int - obj_x = object - x: int + obj_x = object + x: int - ref_obj_x = ref object - x: int + ref_obj_x = ref object + x: int - ref_to_obj_x = ref obj_x + ref_to_obj_x = ref obj_x - p_o_x = ptr obj_x - v_o_x = var obj_x + p_o_x = ptr obj_x + v_o_x = var obj_x -template check(x) = - static: assert(x) + template check(x) = + static: assert(x) -check obj_x is hasFieldX -check ref_obj_x is hasFieldX -check ref_to_obj_x is hasFieldX -check p_o_x is hasFieldX -check v_o_x is hasFieldX + check obj_x is hasFieldX + check ref_obj_x is hasFieldX + check ref_to_obj_x is hasFieldX + check p_o_x is hasFieldX + check v_o_x is hasFieldX +block: + type + Foo = concept x + x.isFoo + Bar = distinct float + template isFoo(x: Bar): untyped = true + proc foo(x: var Foo) = + float(x) = 1.0 + proc foo2(x: var Bar) = + float(x) = 1.0 + proc foo3(x: var (Bar|SomeNumber)) = + float(x) = 1.0 + proc foo4(x: var any) = + float(x) = 1.0 + var x: Bar + foo(x) + foo2(x) + foo3(x) + foo4(x) From 8211d385697407c47a17681e37a2de1368e45a9e Mon Sep 17 00:00:00 2001 From: genotrance Date: Sat, 25 Jul 2020 01:16:25 -0500 Subject: [PATCH 0941/4254] Bump nimble commit (#15053) --- koch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index 7dedb039a..1d1fdf997 100644 --- a/koch.nim +++ b/koch.nim @@ -10,11 +10,11 @@ # const - NimbleStableCommit = "63695f490728e3935692c29f3d71944d83bb1e83" # master + NimbleStableCommit = "e5d340df8cf26f89ad2c9f0bc081ecd7e0323b0a" # master when not defined(windows): const - Z3StableCommit = "65de3f748a6812eecd7db7c478d5fc54424d368b" # the version of Z3 that DrNim uses + Z3StableCommit = "65de3f748a6812eecd7db7c478dcd5fc54424d368b" # the version of Z3 that DrNim uses when defined(gcc) and defined(windows): when defined(x86): From 9746868832df3ef4b40597fb84f58900b2336496 Mon Sep 17 00:00:00 2001 From: Bung Date: Sat, 25 Jul 2020 15:51:59 +0800 Subject: [PATCH 0942/4254] fix #14534 (#15060) [backport] --- compiler/jsgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index d876531e9..3351d64ae 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1689,7 +1689,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = of tyObject: var initList: Rope createObjInitList(p, t, initIntSet(), initList) - result = ("{$1}") % [initList] + result = ("({$1})") % [initList] if indirect: result = "[$1]" % [result] of tyVar, tyPtr, tyLent, tyRef, tyPointer: if mapType(p, t) == etyBaseIndex: From 2dddf32726a1472d322644ec1a66caf8c547360e Mon Sep 17 00:00:00 2001 From: Bung Date: Sat, 25 Jul 2020 15:52:29 +0800 Subject: [PATCH 0943/4254] fix #14684 (#15059) --- compiler/commands.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/commands.nim b/compiler/commands.nim index d0936a0c6..504550045 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -486,6 +486,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "project": processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) of "gc": + if conf.backend == backendJs: + return expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: case arg.normalize From 1330597f6df1d2f7d23ec25a7705e21be2e78d29 Mon Sep 17 00:00:00 2001 From: Miran Date: Sat, 25 Jul 2020 09:53:47 +0200 Subject: [PATCH 0944/4254] deprecate tables.add (#15047) --- lib/pure/collections/tables.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index cf864c640..a8742bdbe 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -484,7 +484,8 @@ proc len*[A, B](t: Table[A, B]): int = result = t.counter -proc add*[A, B](t: var Table[A, B], key: A, val: B) = +proc add*[A, B](t: var Table[A, B], key: A, val: B) {.deprecated: + "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** @@ -962,7 +963,8 @@ proc len*[A, B](t: TableRef[A, B]): int = result = t.counter -proc add*[A, B](t: TableRef[A, B], key: A, val: B) = +proc add*[A, B](t: TableRef[A, B], key: A, val: B) {.deprecated: + "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** @@ -1448,7 +1450,8 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} = result = t.counter -proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) = +proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) {.deprecated: + "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** @@ -1935,7 +1938,8 @@ proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} = result = t.counter -proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = +proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) {.deprecated: + "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## ## **This can introduce duplicate keys into the table!** From 7ca32c86bbb84ac7bcadd0a2bc2cd5fc277f1bff Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 25 Jul 2020 15:14:28 +0200 Subject: [PATCH 0945/4254] writing to a location counts as "side effect"; implements https://github.com/nim-lang/RFCs/issues/234 (#15030) --- compiler/isolation_check.nim | 2 +- compiler/options.nim | 1 + compiler/sempass2.nim | 11 +- compiler/varpartitions.nim | 243 +++++++++++++++++++++++++ tests/effects/tfuncs_cannot_mutate.nim | 31 ++++ 5 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 compiler/varpartitions.nim create mode 100644 tests/effects/tfuncs_cannot_mutate.nim diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index a77e8c97a..2b53bce92 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -64,7 +64,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool = else: result = false -proc canAlias(arg, ret: PType): bool = +proc canAlias*(arg, ret: PType): bool = var marker = initIntSet() result = canAlias(arg, ret, marker) diff --git a/compiler/options.nim b/compiler/options.nim index 8b73c07fc..5d9bc245b 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -163,6 +163,7 @@ type ## which itself requires `nimble install libffi`, see #10150 ## Note: this feature can't be localized with {.push.} vmopsDanger, + strictFuncs LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 49fa44ca2..c6d6d9241 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs + modulegraphs, varpartitions when defined(useDfa): import dfa @@ -36,9 +36,6 @@ For every sink parameter of type T T is marked. For every call f() the return type of f() is marked. - - - ]# # ------------------------ exception and tag tracking ------------------------- @@ -73,6 +70,7 @@ type guards: TModel # nested guards locked: seq[PNode] # locked locations gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool + hasDangerousAssign: bool inEnforcedNoSideEffects: bool maxLockLevel, currLockLevel: TLockLevel currOptions: TOptions @@ -885,6 +883,8 @@ proc track(tracked: PEffects, n: PNode) = createTypeBoundOps(tracked, n[0].typ, n.info) if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym): checkForSink(tracked.config, tracked.owner, n[1]) + if not tracked.hasDangerousAssign and n[0].kind != nkSym: + tracked.hasDangerousAssign = true of nkVarSection, nkLetSection: for child in n: let last = lastSon(child) @@ -1237,6 +1237,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = patchResult(t, ensuresSpec) effects[ensuresEffects] = ensuresSpec + if strictFuncs in c.features and not t.hasSideEffect and t.hasDangerousAssign: + t.hasSideEffect = mutatesNonVarParameters(s, body) + if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: #localError(s.info, "'$1' is not GC-safe" % s.name.s) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim new file mode 100644 index 000000000..b89b7d1da --- /dev/null +++ b/compiler/varpartitions.nim @@ -0,0 +1,243 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Partition variables into different graphs. Used for +## Nim's write tracking. The used algorithm is "union find" +## with path compression. + +import ast, types +from trees import getMagic +from isolation_check import canAlias + +type + SubgraphFlag = enum + isMutated, # graph might be mutated + connectsConstParam, # graph is connected to a non-var parameter. + + VarIndexKind = enum + isEmptyRoot, + dependsOn, + isRootOf + + VarIndex = object + case kind: VarIndexKind + of isEmptyRoot: discard + of dependsOn: parent: int + of isRootOf: graphIndex: int + + Partitions = object + symToId: seq[PSym] + s: seq[VarIndex] + graphs: seq[set[SubgraphFlag]] + +proc hasSideEffect(p: Partitions): bool = + for g in p.graphs: + if g == {isMutated, connectsConstParam}: return true + return false + +template isConstParam(a): bool = a.kind == skParam and a.typ.kind != tyVar + +proc registerVariable(p: var Partitions; n: PNode) = + if n.kind == nkSym: + p.symToId.add n.sym + if isConstParam(n.sym): + p.s.add VarIndex(kind: isRootOf, graphIndex: p.graphs.len) + p.graphs.add({connectsConstParam}) + else: + p.s.add VarIndex(kind: isEmptyRoot) + +proc variableId(p: Partitions; x: PSym): int {.inline.} = system.find(p.symToId, x) + +proc root(v: var Partitions; start: int): int = + result = start + while v.s[result].kind == dependsOn: + result = v.s[result].parent + # path compression: + var it = start + while v.s[it].kind == dependsOn: + let next = v.s[it].parent + v.s[it] = VarIndex(kind: dependsOn, parent: result) + it = next + +proc potentialMutation(v: var Partitions; s: PSym) = + let id = variableId(v, s) + if id >= 0: + let r = root(v, id) + case v.s[r].kind + of isEmptyRoot: + v.s[r] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len) + v.graphs.add({isMutated}) + of isRootOf: + v.graphs[v.s[r].graphIndex].incl isMutated + else: + assert false, "cannot happen" + else: + discard "we are not interested in the mutation" + +proc connect(v: var Partitions; a, b: PSym) = + let aid = variableId(v, a) + if aid < 0: + return + let bid = variableId(v, b) + if bid < 0: + return + + let ra = root(v, aid) + let rb = root(v, bid) + if ra != rb: + let paramFlags = + if isConstParam(a) or isConstParam(b): + {connectsConstParam} + else: + {} + + # for now we always make 'rb' the slave and 'ra' the master: + let rbFlags = + if v.s[rb].kind == isRootOf: + v.graphs[v.s[rb].graphIndex] + else: + {} + + v.s[rb] = VarIndex(kind: dependsOn, parent: ra) + case v.s[ra].kind + of isEmptyRoot: + v.s[ra] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len) + v.graphs.add(paramFlags + rbFlags) + of isRootOf: + v.graphs[v.s[ra].graphIndex].incl paramFlags + rbFlags + else: + assert false, "cannot happen" + +proc allRoots(n: PNode; result: var seq[PSym]) = + case n.kind + of nkSym: + if n.sym.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}: + result.add(n.sym) + of nkHiddenDeref, nkDerefExpr, nkAddr, nkDotExpr, nkBracketExpr, + nkCheckedFieldExpr, nkHiddenAddr, nkObjUpConv, nkObjDownConv: + allRoots(n[0], result) + of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv, + nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkCast: + if n.len > 0: + allRoots(n.lastSon, result) + of nkCaseStmt, nkObjConstr: + for i in 1.. 1: + allRoots(n[1], result) + else: + let m = getMagic(n) + case m + of mNone: + # we do significantly better here by using the available escape + # information: + if n[0].typ.isNil: return + var typ = n[0].typ + if typ != nil: + typ = skipTypes(typ, abstractInst) + if typ.kind != tyProc: typ = nil + else: assert(typ.len == typ.n.len) + + for i in 1 ..< n.len: + let it = n[i] + if typ != nil and i < typ.len: + assert(typ.n[i].kind == nkSym) + let paramType = typ.n[i].typ + if not paramType.isCompileTimeOnly and not typ.sons[0].isEmptyType and + canAlias(paramType, typ.sons[0]): + allRoots(it, result) + else: + allRoots(it, result) + + of mSlice: + allRoots(n[1], result) + else: + discard "harmless operation" + else: + discard "nothing to do" + +proc deps(p: var Partitions; dest, src: PNode) = + var targets, sources: seq[PSym] + allRoots(dest, targets) + allRoots(src, sources) + for t in targets: + if dest.kind != nkSym: + potentialMutation(p, t) + + proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} + if types.searchTypeFor(t.typ, wrap): + for s in sources: + connect(p, t, s) + +proc traverse(p: var Partitions; n: PNode) = + case n.kind + of nkLetSection, nkVarSection: + for child in n: + let last = lastSon(child) + traverse(p, last) + if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: + if child.len-2 != last.len: return + for i in 0.. Date: Sat, 25 Jul 2020 19:36:53 +0200 Subject: [PATCH 0946/4254] strict func: much better error messages (#15068) * strict func: much better error messages * documented the 'strict funcs' mode --- changelog.md | 27 ++++--- compiler/sempass2.nim | 5 +- compiler/varpartitions.nim | 104 +++++++++++++++++-------- doc/manual_experimental.rst | 38 +++++++++ tests/effects/tfuncs_cannot_mutate.nim | 5 +- 5 files changed, 133 insertions(+), 46 deletions(-) diff --git a/changelog.md b/changelog.md index e30e9038b..d4161373c 100644 --- a/changelog.md +++ b/changelog.md @@ -101,7 +101,7 @@ - `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` parameters. -- Add `ssl_config` module containing lists of secure ciphers as recommended by +- Added a `ssl_config` module containing lists of secure ciphers as recommended by [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) - `net.newContext` now defaults to the list of ciphers targeting @@ -110,27 +110,28 @@ users from the use of weak and insecure ciphers while still provides adequate compatibility with the majority of the Internet. -- new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` for json - serialization/deserialization of custom types. +- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json + serialization/deserialization of custom types was added. -- new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x``. -- Add `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` +- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x`` + was added. +- Added `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` with `outLatex` output. -- Add `os.normalizeExe`, e.g.: `koch` => `./koch`. +- Added `os.normalizeExe`, e.g.: `koch` => `./koch`. - `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` to keep old behavior. -- Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. -- Add `typetraits.elementType` to get element type of an iterable. +- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. +- Added `typetraits.elementType` to get element type of an iterable. - `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` -- add `macros.extractDocCommentsAndRunnables` helper +- Added `macros.extractDocCommentsAndRunnables` helper - `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. - deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` -- Add `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +- Added `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) - Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, because negative values will result in a new file being created for each logged line which doesn't make sense. @@ -144,7 +145,7 @@ ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts - wasMoved calls where needed. + `wasMoved` calls where needed. - In the newruntime it is now allowed to assign to the discriminator field without restrictions as long as case object doesn't have custom destructor. The discriminator value doesn't have to be a constant either. If you have a @@ -217,6 +218,10 @@ proc mydiv(a, b): int {.raises: [].} = - Remove `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. +- There is a new experimental feature called "strictFuncs" which makes the definition of + `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs) + for more information. + ## Compiler changes diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index c6d6d9241..f6fce712a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1237,8 +1237,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = patchResult(t, ensuresSpec) effects[ensuresEffects] = ensuresSpec + var mutationInfo = MutationInfo() if strictFuncs in c.features and not t.hasSideEffect and t.hasDangerousAssign: - t.hasSideEffect = mutatesNonVarParameters(s, body) + t.hasSideEffect = mutatesNonVarParameters(s, body, mutationInfo) if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: @@ -1251,7 +1252,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = when false: listGcUnsafety(s, onlyWarning=false, g.config) else: - localError(g.config, s.info, "'$1' can have side effects" % s.name.s) + localError(g.config, s.info, ("'$1' can have side effects" % s.name.s) & (g.config $ mutationInfo)) if not t.gcUnsafe: s.typ.flags.incl tfGcSafe if not t.hasSideEffect and sfSideEffect notin s.flags: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index b89b7d1da..1dee5607d 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -11,7 +11,7 @@ ## Nim's write tracking. The used algorithm is "union find" ## with path compression. -import ast, types +import ast, types, lineinfos, options, msgs from trees import getMagic from isolation_check import canAlias @@ -31,14 +31,36 @@ type of dependsOn: parent: int of isRootOf: graphIndex: int + MutationInfo* = object + param: PSym + mutatedHere, connectedVia: TLineInfo + flags: set[SubgraphFlag] + Partitions = object symToId: seq[PSym] s: seq[VarIndex] - graphs: seq[set[SubgraphFlag]] + graphs: seq[MutationInfo] -proc hasSideEffect(p: Partitions): bool = - for g in p.graphs: - if g == {isMutated, connectsConstParam}: return true +proc `$`*(config: ConfigRef; g: MutationInfo): string = + result = "" + if g.flags == {isMutated, connectsConstParam}: + result.add "\nan object reachable from '" + result.add g.param.name.s + result.add "' is potentially mutated" + if g.mutatedHere != unknownLineInfo: + result.add "\n" + result.add config $ g.mutatedHere + result.add " the mutation is here" + if g.connectedVia != unknownLineInfo: + result.add "\n" + result.add config $ g.connectedVia + result.add " is the statement that connected the mutation to the parameter" + +proc hasSideEffect(p: var Partitions; info: var MutationInfo): bool = + for g in mitems p.graphs: + if g.flags == {isMutated, connectsConstParam}: + info = g + return true return false template isConstParam(a): bool = a.kind == skParam and a.typ.kind != tyVar @@ -48,7 +70,8 @@ proc registerVariable(p: var Partitions; n: PNode) = p.symToId.add n.sym if isConstParam(n.sym): p.s.add VarIndex(kind: isRootOf, graphIndex: p.graphs.len) - p.graphs.add({connectsConstParam}) + p.graphs.add MutationInfo(param: n.sym, mutatedHere: unknownLineInfo, + connectedVia: unknownLineInfo, flags: {connectsConstParam}) else: p.s.add VarIndex(kind: isEmptyRoot) @@ -56,31 +79,40 @@ proc variableId(p: Partitions; x: PSym): int {.inline.} = system.find(p.symToId, proc root(v: var Partitions; start: int): int = result = start + var depth = 0 while v.s[result].kind == dependsOn: result = v.s[result].parent - # path compression: - var it = start - while v.s[it].kind == dependsOn: - let next = v.s[it].parent - v.s[it] = VarIndex(kind: dependsOn, parent: result) - it = next + inc depth + if depth > 0: + # path compression: + var it = start + while v.s[it].kind == dependsOn: + let next = v.s[it].parent + v.s[it] = VarIndex(kind: dependsOn, parent: result) + it = next -proc potentialMutation(v: var Partitions; s: PSym) = +proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = let id = variableId(v, s) if id >= 0: let r = root(v, id) case v.s[r].kind of isEmptyRoot: v.s[r] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len) - v.graphs.add({isMutated}) + v.graphs.add MutationInfo(param: if isConstParam(s): s else: nil, mutatedHere: info, + connectedVia: unknownLineInfo, flags: {isMutated}) of isRootOf: - v.graphs[v.s[r].graphIndex].incl isMutated + let g = addr v.graphs[v.s[r].graphIndex] + if g.param == nil and isConstParam(s): + g.param = s + if g.mutatedHere == unknownLineInfo: + g.mutatedHere = info + g.flags.incl isMutated else: assert false, "cannot happen" else: discard "we are not interested in the mutation" -proc connect(v: var Partitions; a, b: PSym) = +proc connect(v: var Partitions; a, b: PSym; info: TLineInfo) = let aid = variableId(v, a) if aid < 0: return @@ -91,26 +123,37 @@ proc connect(v: var Partitions; a, b: PSym) = let ra = root(v, aid) let rb = root(v, bid) if ra != rb: + var param = PSym(nil) + if isConstParam(a): param = a + elif isConstParam(b): param = b + let paramFlags = - if isConstParam(a) or isConstParam(b): + if param != nil: {connectsConstParam} else: {} # for now we always make 'rb' the slave and 'ra' the master: - let rbFlags = - if v.s[rb].kind == isRootOf: - v.graphs[v.s[rb].graphIndex] - else: - {} + var rbFlags: set[SubgraphFlag] = {} + var mutatedHere = unknownLineInfo + if v.s[rb].kind == isRootOf: + var gb = addr v.graphs[v.s[rb].graphIndex] + if param == nil: param = gb.param + mutatedHere = gb.mutatedHere + rbFlags = gb.flags v.s[rb] = VarIndex(kind: dependsOn, parent: ra) case v.s[ra].kind of isEmptyRoot: v.s[ra] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len) - v.graphs.add(paramFlags + rbFlags) + v.graphs.add MutationInfo(param: param, mutatedHere: mutatedHere, + connectedVia: info, flags: paramFlags + rbFlags) of isRootOf: - v.graphs[v.s[ra].graphIndex].incl paramFlags + rbFlags + var g = addr v.graphs[v.s[ra].graphIndex] + if g.param == nil: g.param = param + if g.mutatedHere == unknownLineInfo: g.mutatedHere = mutatedHere + g.connectedVia = info + g.flags.incl paramFlags + rbFlags else: assert false, "cannot happen" @@ -144,8 +187,6 @@ proc allRoots(n: PNode; result: var seq[PSym]) = let m = getMagic(n) case m of mNone: - # we do significantly better here by using the available escape - # information: if n[0].typ.isNil: return var typ = n[0].typ if typ != nil: @@ -177,12 +218,12 @@ proc deps(p: var Partitions; dest, src: PNode) = allRoots(src, sources) for t in targets: if dest.kind != nkSym: - potentialMutation(p, t) + potentialMutation(p, t, dest.info) proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} if types.searchTypeFor(t.typ, wrap): for s in sources: - connect(p, t, s) + connect(p, t, s, dest.info) proc traverse(p: var Partitions; n: PNode) = case n.kind @@ -224,13 +265,12 @@ proc traverse(p: var Partitions; n: PNode) = if paramType.typ.kind == tyVar: var roots: seq[PSym] allRoots(n, roots) - for r in roots: potentialMutation(p, r) + for r in roots: potentialMutation(p, r, n.info) else: for child in n: traverse(p, child) - -proc mutatesNonVarParameters*(s: PSym; n: PNode): bool = +proc mutatesNonVarParameters*(s: PSym; n: PNode; info: var MutationInfo): bool = var par = Partitions() if s.kind != skMacro: let params = s.typ.n @@ -240,4 +280,4 @@ proc mutatesNonVarParameters*(s: PSym; n: PNode): bool = registerVariable(par, s.ast[resultPos]) traverse(par, n) - result = hasSideEffect(par) + result = hasSideEffect(par, info) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index b0614885a..43aa84f20 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1844,3 +1844,41 @@ via ``.noSideEffect``. The rules 3 and 4 can also be approximated by a different 5. A global or thread local variable (or a location derived from such a location) can only passed to a parameter of a ``.noSideEffect`` proc. + + +Strict funcs +============ + +Since version 1.4 a stricter definition of "side effect" is available. In addition +to the existing rule that a side effect is calling a function with side effects +the following rule is also enforced: + +Any mutation to an object does count as a side effect if that object is reachable +via a parameter that is not declared as a ``var`` parameter. + +For example: + +.. code-block:: nim + + {.experimental: "strictFuncs".} + + type + Node = ref object + le, ri: Node + data: string + + func len(n: Node): int = + # valid: len does not have side effects + var it = n + while it != nil: + inc result + it = it.ri + + func mut(n: Node) = + let m = n # is the statement that connected the mutation to the parameter + m.data = "yeah" # the mutation is here + # Error: 'mut' can have side effects + # an object reachable from 'n' is potentially mutated + + +The algorithm behind this analysis is currently not documented. diff --git a/tests/effects/tfuncs_cannot_mutate.nim b/tests/effects/tfuncs_cannot_mutate.nim index ec3ad43f7..2990894ed 100644 --- a/tests/effects/tfuncs_cannot_mutate.nim +++ b/tests/effects/tfuncs_cannot_mutate.nim @@ -1,6 +1,9 @@ discard """ errormsg: "'mutate' can have side effects" - line: 25 + nimout: '''an object reachable from 'n' is potentially mutated +tfuncs_cannot_mutate.nim(34, 15) the mutation is here +tfuncs_cannot_mutate.nim(32, 7) is the statement that connected the mutation to the parameter''' + line: 28 """ {.experimental: "strictFuncs".} From 080bed8b6b478699f740b61915f9e06ab30554d6 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Sat, 25 Jul 2020 21:35:20 +0300 Subject: [PATCH 0947/4254] Add a test-case for #12990 (#15072) * closes #12990 * Add a test-case for #12990 --- tests/arc/amodule.nim | 13 ++++++++++++- tests/arc/tamodule.nim | 5 ++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/arc/amodule.nim b/tests/arc/amodule.nim index e853d0a77..2b4204a66 100644 --- a/tests/arc/amodule.nim +++ b/tests/arc/amodule.nim @@ -1,3 +1,4 @@ +# bug #14219 var vectors = @["a", "b", "c", "d", "e"] iterator testVectors(): string = @@ -7,4 +8,14 @@ iterator testVectors(): string = var r = "" for item in testVectors(): r.add item -echo r \ No newline at end of file +echo r + +# bug #12990 +iterator test(): int {.closure.} = + yield 0 + +let x = test +while true: + let val = x() + if finished(x): break + echo val diff --git a/tests/arc/tamodule.nim b/tests/arc/tamodule.nim index ac9757bd7..1412e0a7c 100644 --- a/tests/arc/tamodule.nim +++ b/tests/arc/tamodule.nim @@ -1,5 +1,8 @@ discard """ - output: "abcde" + output: ''' +abcde +0 +''' cmd: "nim c --gc:arc $file" """ From 33c2d7bfc4fa5ab34fad35c11a384e6945aa6281 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sat, 25 Jul 2020 20:52:18 +0000 Subject: [PATCH 0948/4254] koch: bundle nim-lang/fusion with Nim (#15061) Initial work on bundling nim-lang/fusion as part of the Nim distribution. --- koch.nim | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index 1d1fdf997..3afc20189 100644 --- a/koch.nim +++ b/koch.nim @@ -11,6 +11,7 @@ const NimbleStableCommit = "e5d340df8cf26f89ad2c9f0bc081ecd7e0323b0a" # master + FusionStableCommit = "88100a2f45860e98850f7a62fe0b11c37c7a86a1" when not defined(windows): const @@ -50,8 +51,10 @@ Usage: koch [options] command [options for command] Options: --help, -h shows this help and quits - --latest bundle the installers with a bleeding edge Nimble - --stable bundle the installers with a stable Nimble (default) + --latest bundle the installers with bleeding edge versions of + external components. + --stable bundle the installers with stable versions of + external components (default). --nim:path use specified path for nim binary --localdocs[:path] only build local documentations. If a path is not specified (or empty), the default is used. @@ -59,9 +62,11 @@ Possible Commands: boot [options] bootstraps with given command line options distrohelper [bindir] helper for distro packagers tools builds Nim related tools - toolsNoNimble builds Nim related tools (except nimble) + toolsNoExternal builds Nim related tools (except external tools, + ie. nimble) doesn't require network connectivity nimble builds the Nimble tool + fusion clone fusion into the working tree Boot options: -d:release produce a release version of the compiler -d:nimUseLinenoise use the linenoise library for interactive mode @@ -194,7 +199,13 @@ proc bundleWinTools(args: string) = nimCompile(r"tools\downloader.nim", options = r"--cc:vcc --app:gui -d:ssl --noNimblePath --path:..\ui " & args) +proc bundleFusion(latest: bool) = + let commit = if latest: "HEAD" else: FusionStableCommit + cloneDependency(distDir, "https://github.com/nim-lang/fusion.git", commit) + copyDir(distDir / "fusion" / "src" / "fusion", "lib" / "fusion") + proc zip(latest: bool; args: string) = + bundleFusion(latest) bundleNimbleExe(latest, args) bundleNimsuggest(args) bundleNimpretty(args) @@ -234,6 +245,7 @@ proc buildTools(args: string = "") = options = "-d:release " & args) proc nsis(latest: bool; args: string) = + bundleFusion(latest) bundleNimbleExe(latest, args) bundleNimsuggest(args) bundleWinTools(args) @@ -693,15 +705,18 @@ when isMainModule: of "wintools": bundleWinTools(op.cmdLineRest) of "nimble": buildNimble(latest, op.cmdLineRest) of "nimsuggest": bundleNimsuggest(op.cmdLineRest) - of "toolsnonimble": + # toolsNoNimble is kept for backward compatibility with build scripts + of "toolsnonimble", "toolsnoexternal": buildTools(op.cmdLineRest) of "tools": buildTools(op.cmdLineRest) buildNimble(latest, op.cmdLineRest) + bundleFusion(latest) of "pushcsource", "pushcsources": pushCsources() of "valgrind": valgrind(op.cmdLineRest) of "c2nim": bundleC2nim(op.cmdLineRest) of "drnim": buildDrNim(op.cmdLineRest) + of "fusion": bundleFusion(latest) else: showHelp() break of cmdEnd: break From 5c4e2bf68e067507ce0f26c93737b302bbeb5103 Mon Sep 17 00:00:00 2001 From: Miran Date: Sat, 25 Jul 2020 22:56:37 +0200 Subject: [PATCH 0949/4254] fix nightlies: smaller log files (#15074) Hopefully this will fix "The job exceeded the maximum log length, and has been terminated." --- tools/kochdocs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 8a8406a69..05ddb4f1e 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -8,7 +8,7 @@ const gaCode* = " --doc.googleAnalytics:UA-48159761-1" # errormax: subsequent errors are probably consequences of 1st one; a simple # bug could cause unlimited number of errors otherwise, hard to debug in CI. - nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off -d:boot --putenv:nimversion=$#" % system.NimVersion + nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off --hint:XDeclaredButNotUsed:off --warning:UnusedImport:off -d:boot --putenv:nimversion=$#" % system.NimVersion gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" webUploadOutput = "web/upload" From 624762cfb7ab17606616f75ca280b83c55c3ec3b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 25 Jul 2020 20:26:30 +0200 Subject: [PATCH 0950/4254] fixes #15052 --- compiler/ccgexprs.nim | 11 +++++++++++ tests/arc/tarcmisc.nim | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 003b3e240..73cc2c8a1 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -729,6 +729,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage) +proc cow(p: BProc; n: PNode) = + if n.kind == nkHiddenAddr and optSeqDestructors in p.config.globalOptions: + if n[0].kind == nkBracketExpr: + let strCandidate = n[0][0] + if strCandidate.typ.skipTypes(abstractInst).kind == tyString: + var a: TLoc + initLocExpr(p, strCandidate, a) + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}: @@ -2699,9 +2708,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkReturnStmt: genReturnStmt(p, n) of nkBreakStmt: genBreakStmt(p, n) of nkAsgn: + cow(p, n[1]) if nfPreventCg notin n.flags: genAsgn(p, n, fastAsgn=false) of nkFastAsgn: + cow(p, n[1]) if nfPreventCg notin n.flags: # transf is overly aggressive with 'nkFastAsgn', so we work around here. # See tests/run/tcnstseq3 for an example that would fail otherwise. diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index cb889db15..d60e932a8 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -24,6 +24,7 @@ whiley ends :( new line before - @['a'] new line after - @['a'] finalizer +aaaaa closed destroying variable: 20 destroying variable: 10 @@ -282,3 +283,13 @@ proc hello(): int = var leaves {.global.} = hello() doAssert leaves == 42 + +# bug #15052 + +proc mutstrings = + var data = "hello" + for c in data.mitems(): + c = 'a' + echo data + +mutstrings() From aae998feff6d0234ee02311d59b299adfee0b01c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 25 Jul 2020 22:29:45 +0200 Subject: [PATCH 0951/4254] fixes #15038 [backport:1.2] --- compiler/injectdestructors.nim | 47 +--------------------------------- compiler/sempass2.nim | 2 ++ tests/arc/tarcmisc.nim | 26 +++++++++++++++++++ 3 files changed, 29 insertions(+), 46 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 01f72744a..aaa3db7f9 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -62,52 +62,6 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = proc nestedScope(parent: var Scope): Scope = Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) -proc optimize(s: var Scope) = - # optimize away simple 'wasMoved(x); destroy(x)' pairs. - #[ Unfortunately this optimization is only really safe when no exceptions - are possible, see for example: - - proc main(inp: string; cond: bool) = - if cond: - try: - var s = ["hi", inp & "more"] - for i in 0..4: - use s - consume(s) - wasMoved(s) - finally: - destroy(x) - - Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)' - ]# - proc findCorrespondingDestroy(final: seq[PNode]; moved: PNode): int = - # remember that it's destroy(addr(x)) - for i in 0 ..< final.len: - if final[i] != nil and exprStructuralEquivalent(final[i][1].skipAddr, moved, strictSymEquality = true): - return i - return -1 - - var removed = 0 - for i in 0 ..< s.wasMoved.len: - let j = findCorrespondingDestroy(s.final, s.wasMoved[i][1]) - if j >= 0: - s.wasMoved[i] = nil - s.final[j] = nil - inc removed - if removed > 0: - template filterNil(field) = - var m = newSeq[PNode](s.field.len - removed) - var mi = 0 - for i in 0 ..< s.field.len: - if s.field[i] != nil: - m[mi] = s.field[i] - inc mi - assert mi == m.len - s.field = m - - filterNil(wasMoved) - filterNil(final) - proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode @@ -411,6 +365,7 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = # generate: (let tmp = v; reset(v); tmp) if not hasDestructor(n.typ): + assert n.kind != nkSym or not hasDestructor(n.sym.typ) result = copyTree(n) else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f6fce712a..e9dcc7d8a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -840,6 +840,8 @@ proc track(tracked: PEffects, n: PNode) = useVar(tracked, n) if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags: tracked.owner.flags.incl sfInjectDestructors + # bug #15038: ensure consistency + if not hasDestructor(n.typ): n.typ = n.sym.typ of nkHiddenAddr, nkAddr: if n[0].kind == nkSym and isLocalVar(tracked, n[0].sym): useVarNoInitCheck(tracked, n[0], n[0].sym) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index d60e932a8..a7f2dd98b 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -25,6 +25,7 @@ new line before - @['a'] new line after - @['a'] finalizer aaaaa +hello closed destroying variable: 20 destroying variable: 10 @@ -293,3 +294,28 @@ proc mutstrings = echo data mutstrings() + +# bug #15038 + +type + Machine = ref object + hello: string + +var machineTypes: seq[tuple[factory: proc(): Machine]] + +proc registerMachine(factory: proc(): Machine) = + var mCreator = proc(): Machine = + result = factory() + + machineTypes.add((factory: mCreator)) + +proc facproc(): Machine = + result = Machine(hello: "hello") + +registerMachine(facproc) + +proc createMachine = + for machine in machineTypes: + echo machine.factory().hello + +createMachine() From c229df95a4831d083c0465f745fd2ad0f64b9863 Mon Sep 17 00:00:00 2001 From: genotrance Date: Sun, 26 Jul 2020 01:44:14 -0500 Subject: [PATCH 0952/4254] Bump nimble (#15077) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 3afc20189..a54de1860 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "e5d340df8cf26f89ad2c9f0bc081ecd7e0323b0a" # master + NimbleStableCommit = "c4b9c6e459e72c5b04e0beb993b2a912a4078cb5" # master FusionStableCommit = "88100a2f45860e98850f7a62fe0b11c37c7a86a1" when not defined(windows): From a0049d1fb0c997053ffafe8e53e8be6f611c4695 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 27 Jul 2020 08:05:52 +0200 Subject: [PATCH 0953/4254] compiler: minor code cleanups --- compiler/cursor_inference.nim | 2 +- compiler/importer.nim | 3 +-- compiler/isolation_check.nim | 2 +- compiler/suggest.nim | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim index b26a29d4c..0402febec 100644 --- a/compiler/cursor_inference.nim +++ b/compiler/cursor_inference.nim @@ -23,7 +23,7 @@ ## do a compile-time copy-on-write analysis. import - ast, types, renderer, idents, intsets, options, msgs + ast, types, renderer, idents, intsets, options type Cursor = object diff --git a/compiler/importer.nim b/compiler/importer.nim index 844cb1ad0..34e76d7d9 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -187,10 +187,9 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = let it = transformImportAs(c, it) let m = myImportModule(c, it, importStmtResult) if m != nil: - var emptySet: IntSet # ``addDecl`` needs to be done before ``importAllSymbols``! addDecl(c, m, it.info) # add symbol to symbol table of module - importAllSymbolsExcept(c, m, emptySet) + importAllSymbols(c, m) #importForwarded(c, m.ast, emptySet, m) proc evalImport*(c: PContext, n: PNode): PNode = diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 2b53bce92..f3b0c4919 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -11,7 +11,7 @@ ## https://github.com/nim-lang/RFCs/issues/244 for more details. import - ast, types, renderer, idents, intsets, options, msgs + ast, types, renderer, idents, intsets proc canAlias(arg, ret: PType; marker: var IntSet): bool diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 6e9844759..03c65cd42 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -558,7 +558,7 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) = warnAboutDeprecated(conf, info, s) if {sfDeprecated, sfError} * s.flags != {}: if sfDeprecated in s.flags: - if not (c.lastTLineInfo.line == info.line and + if not (c.lastTLineInfo.line == info.line and c.lastTLineInfo.col == info.col): warnAboutDeprecated(conf, info, s) c.lastTLineInfo = info From a62bc5595598d6cc0f1e4edf1458fdbbda025572 Mon Sep 17 00:00:00 2001 From: Jjp137 Date: Sun, 26 Jul 2020 23:17:23 -0700 Subject: [PATCH 0954/4254] parsecsv: fix '\0' being displayed as '0' in docs (#15086) [backport] --- lib/pure/parsecsv.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 44703e3f8..607702fc0 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -108,10 +108,10 @@ proc open*(my: var CsvParser, input: Stream, filename: string, ## the diverse optional parameters: ## - `separator`: character used to separate fields ## - `quote`: Used to quote fields containing special characters like - ## `separator`, `quote` or new-line characters. '\0' disables the parsing + ## `separator`, `quote` or new-line characters. '\\0' disables the parsing ## of quotes. ## - `escape`: removes any special meaning from the following character; - ## '\0' disables escaping; if escaping is disabled and `quote` is not '\0', + ## '\\0' disables escaping; if escaping is disabled and `quote` is not '\\0', ## two `quote` characters are parsed one literal `quote` character. ## - `skipInitialSpace`: If true, whitespace immediately following the ## `separator` is ignored. From c292c57e48c719875a37fa50d2ca6a3d3639ae2e Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 27 Jul 2020 08:38:20 +0000 Subject: [PATCH 0955/4254] Small optimization for the CI pipeline. (#15088) * azure-pipelines: cache csources to speed up build Building csources takes about 2-4 mins, and since it hasn't changed for a long time, employ some caching to cut the time spent. * azure-pipelines: remove ppa avoidance configs Testing shows that there aren't any difference between having this and not having it, so removing this to simplify the code. --- azure-pipelines.yml | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fd8b2eea8..109efc6e1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -53,9 +53,10 @@ jobs: condition: eq(variables['Agent.OS'], 'Windows_NT') - checkout: self + fetchDepth: 1 - - bash: git clone --depth 1 https://github.com/nim-lang/csources.git - displayName: 'Checkout csources' + - bash: git clone --depth 1 https://github.com/nim-lang/csources + displayName: 'Checkout Nim csources' - task: NodeTool@0 inputs: @@ -73,19 +74,12 @@ jobs: - bash: | sudo dpkg --add-architecture i386 - # Downgrade llvm, libgcc and libstdc++: + # Downgrade llvm: # - llvm has to be downgraded to have 32bit version installed for sfml. - # - libgcc and libstdc++ have to be downgraded as an optimization to - # prevent the use of the toolchain ppa, which has a terrible download - # speed. cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel - Package: libllvm6.0 libgcc1 libstdc++6 + Package: libllvm6.0 Pin: origin "azure.archive.ubuntu.com" Pin-Priority: 1001 - - Package: * - Pin: release o=LP-PPA-ubuntu-toolchain-r-test - Pin-Priority: 100 EOF sudo apt-fast update -qq @@ -141,8 +135,18 @@ jobs: make -v displayName: 'System information' + - bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)" + displayName: 'Get csources version' + + - task: Cache@2 + inputs: + key: 'csources | "$(Agent.OS)" | $(CPU) | $(csources_version)' + path: csources/bin + displayName: 'Restore built csources' + - bash: | ncpu= + ext= case '$(Agent.OS)' in 'Linux') ncpu=$(nproc) @@ -152,19 +156,25 @@ jobs: ;; 'Windows_NT') ncpu=$NUMBER_OF_PROCESSORS + ext=.exe ;; esac [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 - make -C csources -j $ncpu CC=gcc ucpu=$(CPU) - displayName: 'Build csources' + if [[ -x csources/bin/nim$ext ]]; then + echo "Found cached compiler, skipping build" + else + make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no + fi + + cp csources/bin/nim$ext bin + displayName: 'Build 1-stage compiler from csources' - bash: nim c koch displayName: 'Build koch' # set result to omit the "bash exited with error code '1'" message - - bash: | - ./koch runCI || echo '##vso[task.complete result=Failed]' + - bash: ./koch runCI || echo '##vso[task.complete result=Failed]' displayName: 'Run CI' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) From 4c43915b5911b4b1d7cf35e3ba156fabde58ed84 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 27 Jul 2020 14:01:50 +0300 Subject: [PATCH 0956/4254] Add test-cases for #12576 and #12523 (#15085) * Add a test-case for #12576 * Add a test-case for #12523 --- tests/iter/titer_issues.nim | 15 +++++++++++++-- tests/pragmas/tcustom_pragma.nim | 25 +++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index 872ebe2b7..4a76b2fb0 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -27,6 +27,8 @@ end 9014 9016 9018 +@[1, 2] +@[1, 2, 3] ''' """ @@ -191,7 +193,7 @@ block t3499_keepstate: break # bug #3499 last snippet fixed - # bug 705 last snippet fixed + # bug #705 last snippet fixed @@ -225,7 +227,7 @@ block t2023_objiter: block: - # issue #13739 + # bug #13739 iterator myIter(arg: openarray[int]): int = var tmp = 0 let len = arg.len @@ -240,3 +242,12 @@ block: echo x someProc() + +block: + # bug #12576 + iterator ff(sq: varargs[seq[int]]): int = + for x in sq: + echo x + + for x in ff(@[1, 2], @[1, 2, 3]): + echo x diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index b306045e0..756396529 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -336,7 +336,7 @@ ProcDef static: assert bar("x") == "x" #------------------------------------------------------ -# issue #13909 +# bug #13909 template dependency*(id: string, weight = 0.0) {.pragma.} @@ -345,4 +345,25 @@ type provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.} proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} = - result = obj \ No newline at end of file + result = obj + +# bug 12523 +template myCustomPragma {.pragma.} + +type + RefType = ref object + field {.myCustomPragma.}: int + + ObjType = object + field {.myCustomPragma.}: int + RefType2 = ref ObjType + +block: + let x = RefType() + for fieldName, fieldSym in fieldPairs(x[]): + doAssert hasCustomPragma(fieldSym, myCustomPragma) + +block: + let x = RefType2() + for fieldName, fieldSym in fieldPairs(x[]): + doAssert hasCustomPragma(fieldSym, myCustomPragma) From 318f0992eaa6ddce1c306e695f95f49b319c53c7 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 27 Jul 2020 11:44:12 +0200 Subject: [PATCH 0957/4254] fixes a closure iterator memory leaks, progress on #15076 --- compiler/injectdestructors.nim | 2 +- tests/arc/tclosureiter.nim | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tests/arc/tclosureiter.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index aaa3db7f9..231ece0ce 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -787,7 +787,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = if ri.kind == nkEmpty and c.inLoop > 0: ri = genDefaultCall(v.typ, c, v.info) if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c, s, isDecl = true) + result.add moveOrCopy(v, ri, c, s, isDecl = false) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) diff --git a/tests/arc/tclosureiter.nim b/tests/arc/tclosureiter.nim new file mode 100644 index 000000000..e4a2ceac6 --- /dev/null +++ b/tests/arc/tclosureiter.nim @@ -0,0 +1,36 @@ +discard """ + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' + output: '''(allocCount: 102, deallocCount: 102)''' +""" + +type + FutureBase = ref object + someData: string + +const + # Just to occupy some RAM + BigData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +iterator mainIter(): FutureBase {.closure.} = + for x in 0 .. 100: + var internalTmpFuture = FutureBase(someData: BigData) + yield internalTmpFuture + +proc main() = + var nameIterVar = mainIter + var next = nameIterVar() + while not isNil(next): + next = nameIterVar() + if not isNil(next): + doAssert next.someData.len == 97 + # GC_unref(next) + # If you uncomment the GC_ref above, + # the program basically uses no memory after the run. + # but crashes with refc, which might indicate + # that arc/orc simply never frees the result of "next"? + if finished(nameIterVar): + break + +main() +GC_fullCollect() +echo getAllocStats() From 46bd6787b8d81c8c8abd742c92380989938a33a3 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 27 Jul 2020 11:56:53 +0200 Subject: [PATCH 0958/4254] code cleanup --- lib/system/cyclicrefs_v2.nim | 207 ------------------- lib/system/{cyclicrefs_bacon.nim => orc.nim} | 0 lib/system/refs_v2.nim | 3 +- 3 files changed, 1 insertion(+), 209 deletions(-) delete mode 100644 lib/system/cyclicrefs_v2.nim rename lib/system/{cyclicrefs_bacon.nim => orc.nim} (100%) diff --git a/lib/system/cyclicrefs_v2.nim b/lib/system/cyclicrefs_v2.nim deleted file mode 100644 index 564562c99..000000000 --- a/lib/system/cyclicrefs_v2.nim +++ /dev/null @@ -1,207 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2019 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# Cycle collector based on Lins' Jump Stack and other ideas, -# see for example: -# https://pdfs.semanticscholar.org/f2b2/0d168acf38ff86305809a55ef2c5d6ebc787.pdf -# Further refinement in 2008 by the notion of "critical links", see -# "Cyclic reference counting" by Rafael Dueire Lins -# R.D. Lins / Information Processing Letters 109 (2008) 71–78 - -type PT = ptr pointer -include cellseqs_v2 - -const - colGreen = 0b000 - colYellow = 0b001 - colRed = 0b010 - jumpStackFlag = 0b100 # stored in jumpstack - rcShift = 3 # shift by rcShift to get the reference counter - colorMask = 0b011 - -type - TraceProc = proc (p, env: pointer) {.nimcall, benign.} - DisposeProc = proc (p: pointer) {.nimcall, benign.} - -template color(c): untyped = c.rc and colorMask -template setColor(c, col) = - when col == colGreen: - c.rc = c.rc and not colorMask - else: - c.rc = c.rc and not colorMask or col - -proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = - let h = head(p) - inc h.rc, rcIncrement - h.setColor colYellow # mark as potential cycle! - -proc markCyclic*[T](x: ref T) {.inline.} = - ## Mark the underlying object as a candidate for cycle collections. - ## Experimental API. Do not use! - let h = head(cast[pointer](x)) - h.setColor colYellow - -type - GcEnv = object - traceStack: CellSeq - jumpStack: CellSeq - -proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} = - if desc.traceImpl != nil: - var p = s +! sizeof(RefHeader) - cast[TraceProc](desc.traceImpl)(p, addr(j)) - -proc free(s: Cell; desc: PNimType) {.inline.} = - when traceCollector: - cprintf("[From ] %p rc %ld color %ld in jumpstack %ld\n", s, s.rc shr rcShift, - s.color, s.rc and jumpStackFlag) - let p = s +! sizeof(RefHeader) - if desc.disposeImpl != nil: - cast[DisposeProc](desc.disposeImpl)(p) - nimRawDispose(p) - -proc collect(s: Cell; desc: PNimType; j: var GcEnv) = - #[ Algorithm from the paper: - - Collect(S) = - If (Color(S) == red) then - RC(S) = 1; - Color(S) = green; - for T in Sons(S) do - Remove(); - if (Color(T) == red) then Collect(T); - free_list = S; - - (Whatever that really means...) - ]# - if s.color == colRed: - s.setColor colGreen - trace(s, desc, j) - while j.traceStack.len > 0: - let (p, desc) = j.traceStack.pop() - let t = head(p[]) - #Remove(): - p[] = nil - if t.color == colRed: - t.setColor colGreen - trace(t, desc, j) - free(t, desc) - free(s, desc) - #cprintf("[Cycle free] %p %ld\n", s, s.rc shr rcShift) - -proc markRed(s: Cell; desc: PNimType; j: var GcEnv) = - if s.color != colRed: - s.setColor colRed - trace(s, desc, j) - while j.traceStack.len > 0: - let (p, desc) = j.traceStack.pop() - let t = head(p[]) - when traceCollector: - cprintf("[Cycle dec] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) - dec t.rc, rcIncrement - if (t.rc and not rcMask) >= 0 and (t.rc and jumpStackFlag) == 0: - t.rc = t.rc or jumpStackFlag - when traceCollector: - cprintf("[Now in jumpstack] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) - j.jumpStack.add(p, desc) - if t.color != colRed: - t.setColor colRed - trace(t, desc, j) - -proc scanGreen(s: Cell; desc: PNimType; j: var GcEnv) = - s.setColor colGreen - trace(s, desc, j) - while j.traceStack.len > 0: - let (p, desc) = j.traceStack.pop() - let t = head(p[]) - if t.color != colGreen: - t.setColor colGreen - trace(t, desc, j) - inc t.rc, rcIncrement - when traceCollector: - cprintf("[Cycle inc] %p %ld color %ld\n", t, t.rc shr rcShift, t.color) - -proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = - let p = cast[ptr pointer](q) - if p[] != nil: - var j = cast[ptr GcEnv](env) - j.traceStack.add(p, desc) - -proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = - let p = cast[ptr pointer](q) - if p[] != nil: - var j = cast[ptr GcEnv](env) - j.traceStack.add(p, cast[ptr PNimType](p[])[]) - -proc scan(s: Cell; desc: PNimType; j: var GcEnv) = - when traceCollector: - cprintf("[doScanGreen] %p %ld\n", s, s.rc shr rcShift) - # even after trial deletion, `s` is still alive, so undo - # the decrefs by calling `scanGreen`: - if (s.rc and not rcMask) >= 0: - scanGreen(s, desc, j) - s.setColor colYellow - else: - # first we have to repair all the nodes we have seen - # that are still alive; we also need to mark what they - # refer to as alive: - while j.jumpStack.len > 0: - let (p, desc) = j.jumpStack.pop - let t = head(p[]) - # not in jump stack anymore! - t.rc = t.rc and not jumpStackFlag - if t.color == colRed and (t.rc and not rcMask) >= 0: - scanGreen(t, desc, j) - t.setColor colYellow - when traceCollector: - cprintf("[jump stack] %p %ld\n", t, t.rc shr rcShift) - # we have proven that `s` and its subgraph are dead, so we can - # collect these nodes: - collect(s, desc, j) - -proc traceCycle(s: Cell; desc: PNimType) {.noinline.} = - when traceCollector: - cprintf("[traceCycle] %p %ld\n", s, s.rc shr rcShift) - var j: GcEnv - init j.jumpStack - init j.traceStack - markRed(s, desc, j) - scan(s, desc, j) - while j.jumpStack.len > 0: - let (p, desc) = j.jumpStack.pop - let t = head(p[]) - # not in jump stack anymore! - t.rc = t.rc and not jumpStackFlag - deinit j.jumpStack - deinit j.traceStack - -proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p\n", p) - else: - dec cell.rc, rcIncrement - if cell.color == colYellow: - let desc = cast[ptr PNimType](p)[] - traceCycle(cell, desc) - # According to Lins it's correct to do nothing else here. - #cprintf("[DeCREF] %p\n", p) - -proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = - if p != nil: - var cell = head(p) - if (cell.rc and not rcMask) == 0: - result = true - #cprintf("[DESTROY] %p %s\n", p, desc.name) - else: - dec cell.rc, rcIncrement - if cell.color == colYellow: traceCycle(cell, desc) - #cprintf("[DeCREF] %p %s %ld\n", p, desc.name, cell.rc) diff --git a/lib/system/cyclicrefs_bacon.nim b/lib/system/orc.nim similarity index 100% rename from lib/system/cyclicrefs_bacon.nim rename to lib/system/orc.nim diff --git a/lib/system/refs_v2.nim b/lib/system/refs_v2.nim index df1248586..7fe17d3ea 100644 --- a/lib/system/refs_v2.nim +++ b/lib/system/refs_v2.nim @@ -180,9 +180,8 @@ when defined(gcOrc): when defined(nimThinout): include cyclebreaker else: - include cyclicrefs_bacon + include orc #include cyclecollector - #include cyclicrefs_v2 proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = if p != nil: From 947ecd1257f78e8ee723bf3a6806b8f24642a064 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 27 Jul 2020 11:58:31 +0200 Subject: [PATCH 0959/4254] more renamings --- lib/system.nim | 6 +++--- lib/system/{refs_v2.nim => arc.nim} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename lib/system/{refs_v2.nim => arc.nim} (100%) diff --git a/lib/system.nim b/lib/system.nim index 71eed5bee..93386c4ae 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1423,8 +1423,8 @@ proc toBiggestInt*(f: BiggestFloat): BiggestInt {.noSideEffect.} = ## Same as `toInt <#toInt,float>`_ but for ``BiggestFloat`` to ``BiggestInt``. if f >= 0: BiggestInt(f+0.5) else: BiggestInt(f-0.5) -proc addQuitProc*(quitProc: proc() {.noconv.}) {. - importc: "atexit", header: "", deprecated: "use exitprocs.addExitProc".} +proc addQuitProc*(quitProc: proc() {.noconv.}) {. + importc: "atexit", header: "", deprecated: "use exitprocs.addExitProc".} ## Adds/registers a quit procedure. ## ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30 @@ -1752,7 +1752,7 @@ when notJSnotNims: when defined(nimV2): - include system/refs_v2 + include system/arc import system/assertions export assertions diff --git a/lib/system/refs_v2.nim b/lib/system/arc.nim similarity index 100% rename from lib/system/refs_v2.nim rename to lib/system/arc.nim From 191c388792c1b57c3855e9c3b9c83293be8a6207 Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 27 Jul 2020 20:06:54 +0800 Subject: [PATCH 0960/4254] fixes #14189 (#15080) [backport] --- compiler/semtypes.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4001953bc..588a0f4f6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -670,7 +670,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, case typ.kind of shouldChckCovered: chckCovered = true - of tyFloat..tyFloat128, tyString, tyError: + of tyFloat..tyFloat128, tyError: discard of tyRange: if skipTypes(typ[0], abstractInst).kind in shouldChckCovered: @@ -678,7 +678,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, of tyForward: errorUndeclaredIdentifier(c, n[0].info, typ.sym.name.s) elif not isOrdinalType(typ): - localError(c.config, n[0].info, "selector must be of an ordinal type, float or string") + localError(c.config, n[0].info, "selector must be of an ordinal type, float") if firstOrd(c.config, typ) != 0: localError(c.config, n.info, "low(" & $a[0].sym.name.s & ") must be 0 for discriminant") From cac09a43aea0e8bcc6a7f2634cfcd4274a260b49 Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 28 Jul 2020 03:13:49 +0800 Subject: [PATCH 0961/4254] =?UTF-8?q?fix=20#11354=20jsgen=20not=20carefull?= =?UTF-8?q?y=20handle=20genAddr=20with=20nkHiddenAddr,nkStm=E2=80=A6=20(#1?= =?UTF-8?q?5078)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix #11354 jsgen not carefully handle genAddr with nkHiddenAddr,nkStmtListExpr; genAsgn with lvalue tyVar and rvalue tyPtr * correct logic * add test for #11354 * handle nkHiddenAddr when n.len == 1 * Update compiler/jsgen.nim * Update compiler/jsgen.nim * Apply suggestions from code review Co-authored-by: Andreas Rumpf --- compiler/jsgen.nim | 11 ++++++++++- tests/js/t11354.nim | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/js/t11354.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 3351d64ae..ede4d14e0 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1069,6 +1069,10 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = elif b.typ == etyNone: internalAssert p.config, b.address == nil lineF(p, "$# = [$#, 0];$n", [a.address, b.res]) + elif x.typ.kind == tyVar and y.typ.kind == tyPtr: + lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) + lineF(p, "$1 = $2;$n", [a.address, b.res]) + lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: internalError(p.config, x.info, $("genAsgn", b.typ, a.typ)) else: @@ -1318,7 +1322,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = of nkObjDownConv: gen(p, n[0], r) of nkHiddenDeref: - gen(p, n[0][0], r) + gen(p, n[0], r) + of nkHiddenAddr: + gen(p, n[0], r) + of nkStmtListExpr: + if n.len == 1: gen(p, n[0], r) + else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr") else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) proc attachProc(p: PProc; content: Rope; s: PSym) = diff --git a/tests/js/t11354.nim b/tests/js/t11354.nim new file mode 100644 index 000000000..8dee90de0 --- /dev/null +++ b/tests/js/t11354.nim @@ -0,0 +1,20 @@ +discard """ + output: ''' +0 +@[@[0, 1]] +''' +""" + +type + TrackySeq[T] = object + s: seq[T] + pos: int + +proc foobar(ls: var TrackySeq[seq[int]], i: int): var seq[int] = + echo ls.pos # removing this, or making the return explicit works + ls.s[i] + +var foo: TrackySeq[seq[int]] +foo.s.add(@[0]) +foo.foobar(0).add(1) +echo foo.s \ No newline at end of file From 377f71676629d5621d052e662996d30323ea3bee Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 27 Jul 2020 13:32:21 -0700 Subject: [PATCH 0962/4254] fix #14698 nkRecWhen caused internalAssert in semConstructFields when generic type not mentioned in fields (#14709) * fix #14698 nkRecWhen caused internalAssert in semConstructFields when generic type not mentioned in fields * address comment * Update compiler/semtypinst.nim Co-authored-by: Andreas Rumpf --- compiler/semtypinst.nim | 5 ++++- tests/objects/tobject.nim | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 22f0d1db6..e7b289d77 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -630,7 +630,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = t # Slow path, we have some work to do - if result.n != nil and t.kind == tyObject: + if t.kind == tyRef and t.len > 0 and t[0].kind == tyObject and t[0].n != nil: + discard replaceObjBranches(cl, t[0].n) + + elif result.n != nil and t.kind == tyObject: # Invalidate the type size as we may alter its structure result.size = -1 result.n = replaceObjBranches(cl, result.n) diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim index 34856eaef..a79c2bdfd 100644 --- a/tests/objects/tobject.nim +++ b/tests/objects/tobject.nim @@ -42,3 +42,23 @@ var b: TMyObj = a type InheritableFoo {.inheritable.} = ref object InheritableBar = ref object of InheritableFoo # ERROR. + +block: # bug #14698 + const N = 3 + type Foo[T] = ref object + x1: int + when N == 2: + x2: float + when N == 3: + x3: seq[int] + else: + x4: char + x4b: array[9, char] + + let t = Foo[float](x1: 1) + doAssert $(t[]) == "(x1: 1, x3: @[])" + doAssert t.sizeof == int.sizeof + type Foo1 = object + x1: int + x3: seq[int] + doAssert t[].sizeof == Foo1.sizeof From e6f0d4a5a59f8230133481d25ce1c3f6e8daf0a5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 27 Jul 2020 23:27:20 +0200 Subject: [PATCH 0963/4254] fixes #15076 (#15095) --- compiler/injectdestructors.nim | 33 ++++++++++++++++++++------------- compiler/liftdestructors.nim | 2 ++ compiler/sempass2.nim | 29 ++++++++++++++--------------- tests/arc/tasyncleak.nim | 21 +++++++++++++++++++++ 4 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 tests/arc/tasyncleak.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 231ece0ce..fa960b5cf 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -48,6 +48,13 @@ type const toDebug {.strdefine.} = "" +proc hasDestructor(c: Con; t: PType): bool {.inline.} = + result = ast.hasDestructor(t) + when toDebug.len > 0: + # for more effective debugging + if not result and c.graph.config.selectedGC in {gcArc, gcOrc}: + assert(not containsGarbageCollectedRef(t)) + template dbg(body) = when toDebug.len > 0: if c.owner.name.s == toDebug or toDebug == "always": @@ -330,7 +337,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = let leDotExpr = if le.kind == nkCheckedFieldExpr: le[0] else: le let objType = leDotExpr[0].typ - if hasDestructor(objType): + if hasDestructor(c, objType): if objType.attachedOps[attachedDestructor] != nil and sfOverriden in objType.attachedOps[attachedDestructor].flags: localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor. @@ -364,8 +371,8 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = # generate: (let tmp = v; reset(v); tmp) - if not hasDestructor(n.typ): - assert n.kind != nkSym or not hasDestructor(n.sym.typ) + if not hasDestructor(c, n.typ): + assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) result = copyTree(n) else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -393,7 +400,7 @@ proc isCapturedVar(n: PNode): bool = proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = c.getTemp(s, n.typ, n.info) - if hasDestructor(n.typ): + if hasDestructor(c, n.typ): result.add c.genWasMoved(tmp) var m = c.genCopy(tmp, n) m.add p(n, c, s, normal) @@ -432,7 +439,7 @@ proc containsConstSeq(n: PNode): bool = proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = # it can happen that we need to destroy expression contructors # like [], (), closures explicitly in order to not leak them. - if arg.typ != nil and hasDestructor(arg.typ): + if arg.typ != nil and hasDestructor(c, arg.typ): # produce temp creation for (fn, env). But we need to move 'env'? # This was already done in the sink parameter handling logic. result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) @@ -521,7 +528,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt # tricky because you would have to intercept moveOrCopy at a certain point let tmp = c.getTemp(s.parent[], ret.typ, ret.info) tmp.sym.flags.incl sfSingleUsedTemp - let cpy = if ret.typ.hasDestructor: + let cpy = if hasDestructor(c, ret.typ): moveOrCopy(tmp, ret, c, s, isDecl = true) else: newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) @@ -774,10 +781,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = newNodeI(nkStmtList, n.info) for it in n: var ri = it[^1] - if it.kind == nkVarTuple and hasDestructor(ri.typ): + if it.kind == nkVarTuple and hasDestructor(c, ri.typ): let x = lowerTupleUnpacking(c.graph, it, c.owner) result.add p(x, c, s, consumed) - elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0], c): + elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c): for j in 0.. 0: - createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) createTypeBoundOps(tracked, n[1].typ, n.info) # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim new file mode 100644 index 000000000..16e7446a7 --- /dev/null +++ b/tests/arc/tasyncleak.nim @@ -0,0 +1,21 @@ +discard """ + outputsub: "(allocCount: 6013, deallocCount: 6007)" + cmd: "nim c --gc:orc -d:nimAllocStats $file" +""" + +import asyncdispatch +# bug #15076 +const + # Just to occupy some RAM + BigData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +proc doNothing(): Future[void] {.async.} = + discard + +proc main(): Future[void] {.async.} = + for x in 0 .. 1_000: + await doNothing() + +waitFor main() +GC_fullCollect() +echo getAllocStats() From d60fae576f3228c1cee360129b687a1e8c6a8ed8 Mon Sep 17 00:00:00 2001 From: Ray Imber Date: Mon, 27 Jul 2020 23:04:04 -0700 Subject: [PATCH 0964/4254] Improvements to Windows install instructions (#15099) --- readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readme.md b/readme.md index 94241822f..4ef10f231 100644 --- a/readme.md +++ b/readme.md @@ -52,6 +52,12 @@ Next, to build from source you will need: * Either ``git`` or ``wget`` to download the needed source repositories. * The ``build-essential`` package when using ``gcc`` on Ubuntu (and likely other distros as well). + * On Windows MinGW 4.3.0 (GCC 8.10) is the minimum recommended compiler. + * Nim hosts a known working MinGW distribution: + * [MinGW32.7z](https://nim-lang.org/download/mingw32.7z) + * [MinGW64.7z](https://nim-lang.org/download/mingw64.7z) + +**Windows Note: Cygwin and similar posix runtime environments are not supported.** Then, if you are on a \*nix system or Windows, the following steps should compile Nim from source using ``gcc``, ``git`` and the ``koch`` build tool. @@ -75,6 +81,9 @@ Next run the appropriate build shell script for your platform: * `build_all.sh` (Linux, Mac) * `build_all.bat` (Windows) +Windows requires a number of other dependencies that you may need to install including +PCRE and OpenSSL. Nim hosts a zip package containing known working versions of the +required DLLs [here](https://nim-lang.org/download/dlls.zip). Finally, once you have finished the build steps (on Windows, Mac or Linux) you should add the ``bin`` directory to your PATH. From d6a0c35330260acf2ebebfe884290ba88971a8a4 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 28 Jul 2020 08:51:10 +0200 Subject: [PATCH 0965/4254] bump FusionStableCommit to the latest commit --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index a54de1860..421e5bb0d 100644 --- a/koch.nim +++ b/koch.nim @@ -11,7 +11,7 @@ const NimbleStableCommit = "c4b9c6e459e72c5b04e0beb993b2a912a4078cb5" # master - FusionStableCommit = "88100a2f45860e98850f7a62fe0b11c37c7a86a1" + FusionStableCommit = "166900c74d74f005980baf337f17cb956aeed6d2" when not defined(windows): const From 75083979f90c554e695211f129938046f6e9fe52 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 28 Jul 2020 09:27:00 +0200 Subject: [PATCH 0966/4254] another bump --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 421e5bb0d..f087e305f 100644 --- a/koch.nim +++ b/koch.nim @@ -11,7 +11,7 @@ const NimbleStableCommit = "c4b9c6e459e72c5b04e0beb993b2a912a4078cb5" # master - FusionStableCommit = "166900c74d74f005980baf337f17cb956aeed6d2" + FusionStableCommit = "0ab9466e297393829900c4297193fe66f9d61d2b" when not defined(windows): const From a2f330569c3d7f59371854b76d7f87de95d1a72b Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 28 Jul 2020 10:57:24 +0200 Subject: [PATCH 0967/4254] yet another fusion fix --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index f087e305f..be658a53e 100644 --- a/koch.nim +++ b/koch.nim @@ -11,7 +11,7 @@ const NimbleStableCommit = "c4b9c6e459e72c5b04e0beb993b2a912a4078cb5" # master - FusionStableCommit = "0ab9466e297393829900c4297193fe66f9d61d2b" + FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): const From be78b35bb8ec45e995e2e27058fc925da11db550 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 28 Jul 2020 11:34:44 +0200 Subject: [PATCH 0968/4254] cleanup ARC documentation (#15100) --- doc/advopt.txt | 2 -- doc/destructors.rst | 42 ------------------------------------------ 2 files changed, 44 deletions(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 6665ce537..9b7f29a5e 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -146,8 +146,6 @@ Advanced options: --legacy:$2 enable obsolete/legacy language feature --useVersion:1.0 emulate Nim version X of the Nim compiler - --newruntime use an alternative runtime that uses destructors - and that uses a shared heap via -d:useMalloc --profiler:on|off enable profiling; requires `import nimprof`, and works better with `--stackTrace:on` see also https://nim-lang.github.io/Nim/estp.html diff --git a/doc/destructors.rst b/doc/destructors.rst index 6cab6e1d2..c97b17d6f 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -534,48 +534,6 @@ indirections: useItAgain(v) - -Owned refs -========== - -**Note**: The ``owned`` type constructor is only available with -the ``--newruntime`` compiler switch and is experimental. - - -Let ``W`` be an ``owned ref`` type. Conceptually its hooks look like: - -.. code-block:: nim - - proc `=destroy`(x: var W) = - if x != nil: - assert x.refcount == 0, "dangling unowned pointers exist!" - `=destroy`(x[]) - - proc `=`(x: var W; y: W) {.error: "owned refs can only be moved".} - - proc `=sink`(x: var W; y: W) = - `=destroy`(x) - bitwiseCopy x, y # raw pointer copy - - -Let ``U`` be an unowned ``ref`` type. Conceptually its hooks look like: - -.. code-block:: nim - - proc `=destroy`(x: var U) = - if x != nil: - dec x.refcount - - proc `=`(x: var U; y: U) = - # Note: No need to check for self-assignments here. - if y != nil: inc y.refcount - if x != nil: dec x.refcount - bitwiseCopy x, y # raw pointer copy - - proc `=sink`(x: var U, y: U) {.error.} - # Note: Moves are not available. - - Hook lifting ============ From 39487f9728c03e98109b70c2d169e6366b9a8337 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 28 Jul 2020 11:40:56 +0200 Subject: [PATCH 0969/4254] deprecate tables.allValues; continuation of #15047 (#15092) --- lib/pure/collections/tables.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index a8742bdbe..b1354eec3 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -744,7 +744,8 @@ iterator mvalues*[A, B](t: var Table[A, B]): var B = yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") -iterator allValues*[A, B](t: Table[A, B]; key: A): B = +iterator allValues*[A, B](t: Table[A, B]; key: A): B {.deprecated: + "Deprecated since v1.4; tables with duplicated keys are deprecated".} = ## Iterates over any value in the table ``t`` that belongs to the given ``key``. ## ## Used if you have a table with duplicate keys (as a result of using From e2b149190584e53c662d09aeee9390908bbb250f Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 28 Jul 2020 17:47:22 +0800 Subject: [PATCH 0970/4254] Fix #11352 strutil.insertSep() fails on negative numbers (#15087) * fix #11352 strutil.insertSep handle negtive number * test for #11352 * optimize * not parts string var * Update lib/pure/strutils.nim Thanks! Co-authored-by: alaviss * need to be countdown Co-authored-by: alaviss --- lib/pure/strutils.nim | 23 +++++++++++++++++------ tests/modules/tstrutils_insert_sep.nim | 13 +++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 tests/modules/tstrutils_insert_sep.nim diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 32d6ede1e..a0a172430 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2264,17 +2264,28 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect, ## if `s` contains a number. runnableExamples: doAssert insertSep("1000000") == "1_000_000" - - var L = (s.len-1) div digits + s.len - result = newString(L) + result = newStringOfCap(s.len) + let hasPrefix = isDigit(s[s.low]) == false + var idx:int + if hasPrefix: + result.add s[s.low] + for i in (s.low + 1)..s.high: + idx = i + if not isDigit(s[i]): + result.add s[i] + else: + break + let partsLen = s.len - idx + var L = (partsLen-1) div digits + partsLen + result.setLen(L + idx) var j = 0 dec(L) - for i in countdown(len(s)-1, 0): + for i in countdown(partsLen-1,0): if j == digits: - result[L] = sep + result[L + idx] = sep dec(L) j = 0 - result[L] = s[i] + result[L + idx] = s[i + idx] inc(j) dec(L) diff --git a/tests/modules/tstrutils_insert_sep.nim b/tests/modules/tstrutils_insert_sep.nim new file mode 100644 index 000000000..775fe7da1 --- /dev/null +++ b/tests/modules/tstrutils_insert_sep.nim @@ -0,0 +1,13 @@ +discard """ + output: ''' +-100 +-100,000 +100,000 +''' +""" +# test https://github.com/nim-lang/Nim/issues/11352 + +import strutils +echo insertSep($(-100), ',') +echo insertSep($(-100_000), ',') +echo insertSep($(100_000), ',') \ No newline at end of file From e4e4931432fbc81b1ced68b351691228fae31d36 Mon Sep 17 00:00:00 2001 From: Euan Date: Tue, 28 Jul 2020 17:01:25 +0100 Subject: [PATCH 0971/4254] Change clibdir and cincludes for NetBSD (#15102) --- config/nim.cfg | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/config/nim.cfg b/config/nim.cfg index d8d3d4f8b..a33a2f0a9 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -212,6 +212,14 @@ clang.objc.options.linker = "-lobjc -lgnustep-base" clibdir: "/usr/local/lib" @end +@if freebsd or openbsd: + cincludes: "/usr/local/include" + clibdir: "/usr/local/lib" +@elif netbsd: + cincludes: "/usr/pkg/include" + clibdir: "/usr/pkg/lib" +@end + # Configuration for the VxWorks # This has been tested with VxWorks 6.9 only @if vxworks: @@ -350,4 +358,4 @@ tcc.options.always = "-w" gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -s" clang.options.linker %= "${clang.options.linker} -s" clang.cpp.options.linker %= "${clang.cpp.options.linker} -s" -@end \ No newline at end of file +@end From 86c9b7833917cd3deac912488e4dc18a1ca1223a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 28 Jul 2020 19:18:46 +0200 Subject: [PATCH 0972/4254] disable sink inference, only enable it for the stdlib. Reason: better source code compatibility (#15105) --- changelog.md | 4 ++++ compiler/options.nim | 2 +- doc/destructors.rst | 12 ++++++++---- lib/system/inclrtl.nim | 3 +++ tests/arc/nim.cfg | 1 + tests/destructor/nim.cfg | 1 + 6 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 tests/arc/nim.cfg create mode 100644 tests/destructor/nim.cfg diff --git a/changelog.md b/changelog.md index d4161373c..93c0797d3 100644 --- a/changelog.md +++ b/changelog.md @@ -265,6 +265,10 @@ proc mydiv(a, b): int {.raises: [].} = - Removed the `--oldast` switch. - `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is now "typed" instead of "stmt". +- Sink inference is now disabled per default and has to enabled explicitly via + `--sinkInference:on`. *Note*: For the standard library sink inference remains + enabled. This change is most relevant for the `--gc:arc`, `--gc:orc` memory + management modes. ## Tool changes diff --git a/compiler/options.nim b/compiler/options.nim index 5d9bc245b..7beabe5e8 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -373,7 +373,7 @@ const DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` - optTrMacros, optStyleCheck, optSinkInference} + optTrMacros, optStyleCheck} DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, optListFullPaths} diff --git a/doc/destructors.rst b/doc/destructors.rst index c97b17d6f..b433c38d7 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -261,8 +261,14 @@ optimizations (and the current implementation does not). Sink parameter inference ======================== -The current implementation does a limited form of sink parameter -inference. The `.nosinks`:idx: pragma can be used to disable this inference +The current implementation can do a limited form of sink parameter +inference. But it has to be enabled via `--sinkInference:on`, either +on the command line or via a `push` pragma. + +To enable it for a section of code, one can +use `{.push sinkInference: on.}`...`{.pop.}`. + +The `.nosinks`:idx: pragma can be used to disable this inference for a single routine: .. code-block:: nim @@ -270,8 +276,6 @@ for a single routine: proc addX(x: T; child: T) {.nosinks.} = x.s.add child -To disable it for a section of code, one can -use `{.push sinkInference: off.}`...`{.pop.}`. The details of the inference algorithm are currently undocumented. diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 4193f2bdd..d80980c72 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -48,3 +48,6 @@ when defined(nimlocks): {.pragma: benign, gcsafe, locks: 0.} else: {.pragma: benign, gcsafe.} + +when defined(nimHasSinkInference): + {.push sinkInference: on.} diff --git a/tests/arc/nim.cfg b/tests/arc/nim.cfg new file mode 100644 index 000000000..7c148b797 --- /dev/null +++ b/tests/arc/nim.cfg @@ -0,0 +1 @@ +--sinkInference:on diff --git a/tests/destructor/nim.cfg b/tests/destructor/nim.cfg new file mode 100644 index 000000000..7c148b797 --- /dev/null +++ b/tests/destructor/nim.cfg @@ -0,0 +1 @@ +--sinkInference:on From b2a1944587bd23f87d05ed20cf33dd11c4c86e26 Mon Sep 17 00:00:00 2001 From: c-blake Date: Tue, 28 Jul 2020 17:48:50 -0400 Subject: [PATCH 0973/4254] Fulfill https://github.com/nim-lang/Nim/pull/14995#issuecomment-664914391 (#15104) request. This can be conceived as an alternate, more capable resolution of https://github.com/nim-lang/Nim/issues/12200 than https://github.com/nim-lang/Nim/pull/12208 The code re-org idea here is to upgrade tablimpl.nim:`delImpl`/`delImplIdx` to abstract client code conventions for cell emptiness & cell hashing via three new template arguments - `makeEmpty`, `cellEmpty`, `cellHash` which all take a single integer argument and clear a cell, test if clear or produce the hash of the key stored at that index in `.data[]`. Then we update the 3 call sites (`Table`, `CountTable`, `SharedTable`) of `delImpl`/`delImplIdx` by defining define those arguments just before the first invocation as non-exported templates. Because `CountTable` does not save hash() outputs as `.hcode`, it needs a new tableimpl.nim:`delImplNoHCode` which simply in-lines the hash search when no `.hcode` field is available for "prefix compare" acceleration. It is conceivable this new template could be used by future variants, such as one optimized for integer keys where `hash()` and `==` are fast and `.hcode` is both wasted space & time (though a small change to interfaces there for a sentinel key meaning "empty" is needed for maximum efficiency). We also eliminate the old O(n) `proc remove(CountTable...)` in favor of simply invoking the new `delImpl*` templates and take care to correctly handle the case where `val` is either zero for non-existent keys in `inc` or evolves to zero over time in `[]=` or `inc`. The only user-visible changes from the +-42 delta here are speed, iteration order post deletes, and relaxing the `Positive` constraint on `val` in `proc inc` again, as indicated in the `changelog.md` entry. --- changelog.md | 1 + lib/pure/collections/sharedtables.nim | 8 +++-- lib/pure/collections/tableimpl.nim | 23 ++++++++---- lib/pure/collections/tables.nim | 52 ++++++++++----------------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/changelog.md b/changelog.md index 93c0797d3..d9eaa5823 100644 --- a/changelog.md +++ b/changelog.md @@ -140,6 +140,7 @@ - Tables, HashSets, SharedTables and deques don't require anymore that the passed initial size must be a power of two - this is done internally. Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. + `CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again. - Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index cbd922db7..af498d70d 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -138,6 +138,10 @@ proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool = withLock t: hasKeyOrPutImpl(enlarge) +template tabMakeEmpty(i) = t.data[i].hcode = 0 +template tabCellEmpty(i) = isEmpty(t.data[i].hcode) +template tabCellHash(i) = t.data[i].hcode + proc withKey*[A, B](t: var SharedTable[A, B], key: A, mapper: proc(key: A, val: var B, pairExists: var bool)) = ## Computes a new mapping for the ``key`` with the specified ``mapper`` @@ -179,7 +183,7 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A, if pairExists: mapper(t.data[index].key, t.data[index].val, pairExists) if not pairExists: - delImplIdx(t, index) + delImplIdx(t, index, tabMakeEmpty, tabCellEmpty, tabCellHash) else: var val: B mapper(key, val, pairExists) @@ -200,7 +204,7 @@ proc add*[A, B](t: var SharedTable[A, B], key: A, val: B) = proc del*[A, B](t: var SharedTable[A, B], key: A) = ## deletes `key` from hash table `t`. withLock t: - delImpl() + delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash) proc len*[A, B](t: var SharedTable[A, B]): int = ## number of elements in `t` diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index b9d7c70d9..ec2806200 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -78,22 +78,22 @@ template hasKeyOrPutImpl(enlarge) {.dirty.} = maybeRehashPutImpl(enlarge) else: result = true -template delImplIdx(t, i) = +template delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) = let msk = maxHash(t) if i >= 0: dec(t.counter) block outer: while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 - var j = i # The correctness of this depends on (h+1) in nextTry, + var j = i # The correctness of this depends on (h+1) in nextTry var r = j # though may be adaptable to other simple sequences. - t.data[i].hcode = 0 # mark current EMPTY + makeEmpty(i) # mark current EMPTY t.data[i].key = default(type(t.data[i].key)) t.data[i].val = default(type(t.data[i].val)) while true: i = (i + 1) and msk # increment mod table size - if isEmpty(t.data[i].hcode): # end of collision cluster; So all done + if cellEmpty(i): # end of collision cluster; So all done break outer - r = t.data[i].hcode and msk # "home" location of key@i + r = cellHash(i) and msk # initial probe index for key@slot i if not ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): break when defined(js): @@ -101,10 +101,19 @@ template delImplIdx(t, i) = else: t.data[j] = move(t.data[i]) # data[j] will be marked EMPTY next loop -template delImpl() {.dirty.} = +template delImpl(makeEmpty, cellEmpty, cellHash) {.dirty.} = var hc: Hash var i = rawGet(t, key, hc) - delImplIdx(t, i) + delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) + +template delImplNoHCode(makeEmpty, cellEmpty, cellHash) {.dirty.} = + if t.dataLen > 0: + var i: Hash = hash(key) and maxHash(t) + while not cellEmpty(i): + if t.data[i].key == key: + delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) + break + i = nextTry(i, maxHash(t)) template clearImpl() {.dirty.} = for i in 0 ..< t.dataLen: diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index b1354eec3..3aa3af4e9 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -494,6 +494,10 @@ proc add*[A, B](t: var Table[A, B], key: A, val: B) {.deprecated: ## (key, value) pair in the table without introducing duplicates. addImpl(enlarge) +template tabMakeEmpty(i) = t.data[i].hcode = 0 +template tabCellEmpty(i) = isEmpty(t.data[i].hcode) +template tabCellHash(i) = t.data[i].hcode + proc del*[A, B](t: var Table[A, B], key: A) = ## Deletes ``key`` from hash table ``t``. Does nothing if the key does not exist. ## @@ -507,7 +511,7 @@ proc del*[A, B](t: var Table[A, B], key: A) = a.del('z') doAssert a == {'b': 9, 'c': 13}.toTable - delImpl() + delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash) proc pop*[A, B](t: var Table[A, B], key: A, val: var B): bool = ## Deletes the ``key`` from the table. @@ -535,7 +539,7 @@ proc pop*[A, B](t: var Table[A, B], key: A, val: var B): bool = result = index >= 0 if result: val = move(t.data[index].val) - delImplIdx(t, index) + delImplIdx(t, index, tabMakeEmpty, tabCellEmpty, tabCellHash) proc take*[A, B](t: var Table[A, B], key: A, val: var B): bool {.inline.} = ## Alias for: @@ -2199,19 +2203,6 @@ proc enlarge[A](t: var CountTable[A]) = if t.data[i].val != 0: ctRawInsert(t, n, move t.data[i].key, move t.data[i].val) swap(t.data, n) -proc remove[A](t: var CountTable[A], key: A) = - var n: seq[tuple[key: A, val: int]] - newSeq(n, len(t.data)) - var removed: bool - for i in countup(0, high(t.data)): - if t.data[i].val != 0: - if t.data[i].key != key: - ctRawInsert(t, n, move t.data[i].key, move t.data[i].val) - else: - removed = true - swap(t.data, n) - if removed: dec(t.counter) - proc rawGet[A](t: CountTable[A], key: A): int = if t.data.len == 0: return -1 @@ -2225,7 +2216,7 @@ template ctget(t, key, default: untyped): untyped = var index = rawGet(t, key) result = if index >= 0: t.data[index].val else: default -proc inc*[A](t: var CountTable[A], key: A, val: Positive = 1) +proc inc*[A](t: var CountTable[A], key: A, val = 1) # ---------------------------------------------------------------------- @@ -2262,6 +2253,10 @@ proc `[]`*[A](t: CountTable[A], key: A): int = assert(not t.isSorted, "CountTable must not be used after sorting") ctget(t, key, 0) +template cntMakeEmpty(i) = t.data[i].val = 0 +template cntCellEmpty(i) = t.data[i].val == 0 +template cntCellHash(i) = hash(t.data[i].key) + proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = ## Inserts a ``(key, value)`` pair into ``t``. ## @@ -2272,7 +2267,7 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = assert(not t.isSorted, "CountTable must not be used after sorting") assert val >= 0 if val == 0: - t.remove(key) + delImplNoHCode(cntMakeEmpty, cntCellEmpty, cntCellHash) else: let h = rawGet(t, key) if h >= 0: @@ -2280,11 +2275,8 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = else: insertImpl() -proc inc*[A](t: var CountTable[A], key: A, val: Positive = 1) = +proc inc*[A](t: var CountTable[A], key: A, val = 1) = ## Increments ``t[key]`` by ``val`` (default: 1). - ## - ## ``val`` must be a positive number. If you need to decrement a value, - ## use a regular ``Table`` instead. runnableExamples: var a = toCountTable("aab") a.inc('a') @@ -2295,9 +2287,11 @@ proc inc*[A](t: var CountTable[A], key: A, val: Positive = 1) = var index = rawGet(t, key) if index >= 0: inc(t.data[index].val, val) - if t.data[index].val == 0: dec(t.counter) + if t.data[index].val == 0: + delImplIdx(t, index, cntMakeEmpty, cntCellEmpty, cntCellHash) else: - insertImpl() + if val != 0: + insertImpl() proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] = ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n) @@ -2358,8 +2352,6 @@ proc len*[A](t: CountTable[A]): int = proc del*[A](t: var CountTable[A], key: A) {.since: (1, 1).} = ## Deletes ``key`` from table ``t``. Does nothing if the key does not exist. ## - ## O(n) complexity. - ## ## See also: ## * `pop proc<#pop,CountTable[A],A,int>`_ ## * `clear proc<#clear,CountTable[A]>`_ to empty the whole table @@ -2372,7 +2364,7 @@ proc del*[A](t: var CountTable[A], key: A) {.since: (1, 1).} = a.del('c') assert a == toCountTable("aa") - remove(t, key) + delImplNoHCode(cntMakeEmpty, cntCellEmpty, cntCellHash) proc pop*[A](t: var CountTable[A], key: A, val: var int): bool {.since: (1, 1).} = ## Deletes the ``key`` from the table. @@ -2380,8 +2372,6 @@ proc pop*[A](t: var CountTable[A], key: A, val: var int): bool {.since: (1, 1).} ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## - ## O(n) complexity. - ## ## See also: ## * `del proc<#del,CountTable[A],A>`_ ## * `clear proc<#clear,CountTable[A]>`_ to empty the whole table @@ -2398,7 +2388,7 @@ proc pop*[A](t: var CountTable[A], key: A, val: var int): bool {.since: (1, 1).} result = index >= 0 if result: val = move(t.data[index].val) - remove(t, key) + delImplIdx(t, index, cntMakeEmpty, cntCellEmpty, cntCellHash) proc clear*[A](t: var CountTable[A]) = ## Resets the table so that it is empty. @@ -2686,8 +2676,6 @@ proc len*[A](t: CountTableRef[A]): int = proc del*[A](t: CountTableRef[A], key: A) {.since: (1, 1).} = ## Deletes ``key`` from table ``t``. Does nothing if the key does not exist. ## - ## O(n) complexity. - ## ## See also: ## * `pop proc<#pop,CountTableRef[A],A,int>`_ ## * `clear proc<#clear,CountTableRef[A]>`_ to empty the whole table @@ -2699,8 +2687,6 @@ proc pop*[A](t: CountTableRef[A], key: A, val: var int): bool {.since: (1, 1).} ## mapping of the key. Otherwise, returns ``false``, and the ``val`` is ## unchanged. ## - ## O(n) complexity. - ## ## See also: ## * `del proc<#del,CountTableRef[A],A>`_ ## * `clear proc<#clear,CountTableRef[A]>`_ to empty the whole table From a3a87cdb298d7166846133bca5d56f055717474c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 29 Jul 2020 11:11:58 +0200 Subject: [PATCH 0974/4254] fixes #14616 [backport:1.2] (#15109) --- compiler/semmagic.nim | 4 ++++ tests/misc/tunsignedconv.nim | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index f991b4ac6..5cd7b28b0 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -564,5 +564,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if not checkIsolate(n[1]): localError(c.config, n.info, "expression cannot be isolated: " & $n[1]) result = n + of mPred: + if n[1].typ.skipTypes(abstractInst).kind in {tyUInt..tyUInt64}: + n[0].sym.magic = mSubU + result = n else: result = n diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index 0e5fc43db..07fc03e59 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -59,3 +59,13 @@ discard $(x1,) # bug #13698 let n: csize = 1 # xxx should that be csize_t or is that essential here? doAssert $n.int32 == "1" + +# bug #14616 + +let limit = 1'u64 + +let rangeVar = 0'u64 ..< limit + +doAssert repr(rangeVar) == """[a = 0, +b = 0] +""" From 196e747df150ace81e7f4c01253128d4a89f03c7 Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 29 Jul 2020 05:19:02 -0400 Subject: [PATCH 0975/4254] Attempt to explain better why delImplIdx is the way it is. Maybe this can (#15108) avoid future implementation mischief. (Maybe not. Sometimes, general distrust of theory leads people to distrust simple reasoning over times from CPUs trying as hard as possible to mask DRAM latency via pre-fetch.) --- lib/pure/collections/tableimpl.nim | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index ec2806200..df9cb7517 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -78,6 +78,36 @@ template hasKeyOrPutImpl(enlarge) {.dirty.} = maybeRehashPutImpl(enlarge) else: result = true +# delImplIdx is KnuthV3 Algo6.4R adapted to i=i+1 (from i=i-1) which has come to +# be called "back shift delete". It shifts elements in the collision cluster of +# a victim backward to make things as-if the victim were never inserted in the +# first place. This is desirable to keep things "ageless" after many deletes. +# It is trickier than you might guess since initial probe (aka "home") locations +# of keys in a cluster may collide and since table addresses wrap around. +# +# A before-after diagram might look like ('.' means empty): +# slot: 0 1 2 3 4 5 6 7 +# before(1) +# hash1: 6 7 . 3 . 5 5 6 ; Really hash() and msk +# data1: E F . A . B C D ; About to delete C @index 6 +# after(2) +# hash2: 7 . . 3 . 5 6 6 ; Really hash() and msk +# data2: F . . A . B D E ; After deletion of C +# +# This lowers total search depth over the whole table from 1+1+2+2+2+2=10 to 7. +# Had the victim been B@5, C would need back shifting to slot 5. Total depth is +# always lowered by at least 1, e.g. victim A@3. This is all quite fast when +# empty slots are frequent (also needed to keep insert/miss searches fast) and +# hash() is either fast or avoided (via `.hcode`). It need not compare keys. +# +# delImplIdx realizes the above transformation, but only works for dense Linear +# Probing, nextTry(h)=h+1. This is not an important limitation since that's the +# fastest sequence on any CPU made since the 1980s. { Performance analysis often +# overweights "key cmp" neglecting cache behavior, giving bad ideas how big/slow +# tables behave (when perf matters most!). Comparing hcode first means usually +# only 1 key cmp is needed for *any* seq. Timing only predictable activity, +# small tables, and/or integer keys often perpetuates such bad ideas. } + template delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) = let msk = maxHash(t) if i >= 0: From 2629d619a114f9c27b753a32da717a25906c99e6 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 29 Jul 2020 16:17:20 +0200 Subject: [PATCH 0976/4254] Fix forward declaration issues in template/macro context (#15091) * Fix forward declaration issues in template/macro context * Correct forward declaration resolving for overloads * Remove old dead code * WIP consistent gensym ids * Minimize diff * Remove obsoleted hack * Add templInstCounter to give unique IDs to template instantiations * Remove obsoleted code * Eh, init in myOpen, not myProcess... * Remove optNimV019 * Add testcase for #13484 --- changelog.md | 1 + compiler/commands.nim | 2 - compiler/evaltempl.nim | 10 ++- compiler/lookups.nim | 3 +- compiler/options.nim | 1 - compiler/procfind.nim | 45 +--------- compiler/sem.nim | 3 +- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 13 +-- compiler/semstmts.nim | 6 +- compiler/semtempl.nim | 27 ++---- compiler/types.nim | 2 +- compiler/vm.nim | 5 +- compiler/vmdef.nim | 1 + testament/important_packages.nim | 4 +- tests/macros/tmacros_issues.nim | 114 +++++++++++++++++++++++++ tests/template/tparams_gensymed.nim | 126 ++++++++++++++++++++++++++++ 17 files changed, 270 insertions(+), 95 deletions(-) diff --git a/changelog.md b/changelog.md index d9eaa5823..517919de9 100644 --- a/changelog.md +++ b/changelog.md @@ -264,6 +264,7 @@ proc mydiv(a, b): int {.raises: [].} = - Removed the `--oldNewlines` switch. - Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. - Removed the `--oldast` switch. +- Removed the `--oldgensym` switch - `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is now "typed" instead of "stmt". - Sink inference is now disabled per default and has to enabled explicitly via diff --git a/compiler/commands.nim b/compiler/commands.nim index 504550045..b67cd461f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -871,8 +871,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "expandarc": expectArg(conf, switch, arg, pass, info) conf.arcToExpand[arg] = "T" - of "oldgensym": - processOnOffSwitchG(conf, {optNimV019}, arg, pass, info) of "useversion": expectArg(conf, switch, arg, pass, info) case arg diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 2a01a7911..c1024e2fe 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -21,6 +21,7 @@ type # new symbol config: ConfigRef ic: IdentCache + instID: int proc copyNode(ctx: TemplCtx, a, b: PNode): PNode = result = copyNode(a) @@ -53,8 +54,8 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = #if x.kind == skParam and x.owner.kind == skModule: # internalAssert c.config, false idTablePut(c.mapping, s, x) - if sfGenSym in s.flags and optNimV019 notin c.config.globalOptions: - result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id), + if sfGenSym in s.flags: + result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID), if c.instLines: actual.info else: templ.info) else: result.add newSymNode(x, if c.instLines: actual.info else: templ.info) @@ -166,7 +167,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; conf: ConfigRef; - ic: IdentCache; + ic: IdentCache; instID: ref int; fromHlo=false): PNode = inc(conf.evalTemplateCounter) if conf.evalTemplateCounter > evalTemplateLimit: @@ -181,6 +182,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; ctx.config = conf ctx.ic = ic initIdTable(ctx.mapping) + ctx.instID = instID[] let body = tmpl.getBody #echo "instantion of ", renderTree(body, {renderIds}) @@ -203,3 +205,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; #if ctx.debugActive: # echo "instantion of ", renderTree(result, {renderIds}) dec(conf.evalTemplateCounter) + # The instID must be unique for every template instantiation, so we increment it here + inc instID[] diff --git a/compiler/lookups.nim b/compiler/lookups.nim index fe0e6fe7c..a3a2bf49c 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -316,8 +316,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = fixSpelling(n, ident, searchInScopes) errorUndeclaredIdentifier(c, n.info, ident.s) result = errorSym(c, n) - elif checkAmbiguity in flags and result != nil and - contains(c.ambiguousSymbols, result.id): + elif checkAmbiguity in flags and result != nil and result.id in c.ambiguousSymbols: errorUseQualifier(c, n.info, result) of nkSym: result = n.sym diff --git a/compiler/options.nim b/compiler/options.nim index 7beabe5e8..b5fb546ef 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -89,7 +89,6 @@ type # please make sure we have under 32 options # implementation optOwnedRefs # active if the Nim compiler knows about 'owned'. optMultiMethods - optNimV019 optBenchmarkVM # Enables cpuTime() in the VM optProduceAsm # produce assembler code optPanics # turn panics (sysFatal) into a process termination diff --git a/compiler/procfind.nim b/compiler/procfind.nim index f7dc6c379..1d897758a 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -28,40 +28,7 @@ proc equalGenericParams(procA, procB: PNode): bool = if not exprStructuralEquivalent(a.ast, b.ast): return result = true -proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym = - # Searches for a forward declaration or a "twin" symbol of fn - # in the symbol table. If the parameter lists are exactly - # the same the sym in the symbol table is returned, else nil. - var it: TIdentIter - result = initIdentIter(it, scope.symbols, fn.name) - if isGenericRoutine(fn): - # we simply check the AST; this is imprecise but nearly the best what - # can be done; this doesn't work either though as type constraints are - # not kept in the AST .. - while result != nil: - if result.kind == fn.kind and isGenericRoutine(result): - let genR = result.ast[genericParamsPos] - let genF = fn.ast[genericParamsPos] - if exprStructuralEquivalent(genR, genF) and - exprStructuralEquivalent(result.ast[paramsPos], - fn.ast[paramsPos]) and - equalGenericParams(genR, genF): - return - result = nextIdentIter(it, scope.symbols) - else: - while result != nil: - if result.kind == fn.kind and not isGenericRoutine(result): - case equalParams(result.typ.n, fn.typ.n) - of paramsEqual: - return - of paramsIncompatible: - localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s) - return - of paramsNotEqual: - discard - result = nextIdentIter(it, scope.symbols) - -proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym = +proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym = const flags = {ExactGenericParams, ExactTypeDescValues, ExactConstraints, IgnoreCC} var it: TIdentIter @@ -83,16 +50,6 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym = discard result = nextIdentIter(it, scope.symbols) -proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym = - result = searchForProcNew(c, scope, fn) - when false: - let old = searchForProcOld(c, scope, fn) - if old != result: - echo "Mismatch in searchForProc: ", fn.info - debug fn.typ - debug if result != nil: result.typ else: nil - debug if old != nil: old.typ else: nil - when false: proc paramsFitBorrow(child, parent: PNode): bool = result = false diff --git a/compiler/sem.nim b/compiler/sem.nim index 1f98b4f87..a07f62ca0 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -472,7 +472,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, c.graph, n, nOrig, sym) + result = evalMacroCall(c.module, c.graph, c.templInstCounter, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) if c.config.macrosToExpand.hasKey(sym.name.s): @@ -521,6 +521,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = c.semTypeNode = semTypeNode c.instTypeBoundOp = sigmatch.instTypeBoundOp c.hasUnresolvedArgs = hasUnresolvedArgs + c.templInstCounter = new int pushProcCon(c, module) pushOwner(c, c.module) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 8680fcac3..5bd6c4cf2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -35,7 +35,6 @@ type inTryStmt*: int # whether we are in a try statement; works also # in standalone ``except`` and ``finally`` next*: PProcCon # used for stacking procedure contexts - wasForwarded*: bool # whether the current proc has a separate header mappingExists*: bool mapping*: TIdTable caseContext*: seq[tuple[n: PNode, idx: int]] @@ -85,6 +84,7 @@ type # this is used so that generic instantiations # can access private object fields instCounter*: int # to prevent endless instantiations + templInstCounter*: ref int # gives every template instantiation a unique id ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fd9203f34..cdd0f61dd 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -33,7 +33,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, # Note: This is n.info on purpose. It prevents template from creating an info # context when called from an another template pushInfoContext(c.config, n.info, s.detailedInfo) - result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, efFromHlo in flags) + result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, c.templInstCounter, efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) popInfoContext(c.config) @@ -1203,17 +1203,6 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = elif sfGenSym in s.flags: # the owner should have been set by now by addParamOrResult internalAssert c.config, s.owner != nil - if c.p.wasForwarded: - # gensym'ed parameters that nevertheless have been forward declared - # need a special fixup: - let realParam = c.p.owner.typ.n[s.position+1] - internalAssert c.config, realParam.kind == nkSym and realParam.sym.kind == skParam - return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) - elif c.p.owner.kind == skMacro: - # gensym'ed macro parameters need a similar hack (see bug #1944): - var u = searchInScopes(c, s.name) - internalAssert c.config, u != nil and u.kind == skParam and u.owner == s.owner - return newSymNode(u, n.info) result = newSymNode(s, n.info) of skVar, skLet, skResult, skForVar: if s.magic == mNimvm: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c88ff3609..68f0cee64 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1898,6 +1898,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, incl(s.typ.flags, tfNoSideEffect) var proto: PSym = if isAnon: nil else: searchForProc(c, oldScope, s) + if proto == nil and sfForward in s.flags: + #This is a definition that shares its sym with its forward declaration (generated by a macro), + #if the symbol is also gensymmed we won't find it with searchForProc, so we check here + proto = s if proto == nil: if s.kind == skIterator: if s.typ.callConv != ccClosure: @@ -1943,7 +1947,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, addGenericParamListToScope(c, proto.ast[genericParamsPos]) addParams(c, proto.typ.n, proto.kind) proto.info = s.info # more accurate line information - s.typ = proto.typ proto.options = s.options s = proto n[genericParamsPos] = proto.ast[genericParamsPos] @@ -1983,7 +1986,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if n[genericParamsPos].kind == nkEmpty or usePseudoGenerics: if not usePseudoGenerics and s.magic == mNone: paramsTypeCheck(c, s.typ) - c.p.wasForwarded = proto != nil maybeAddResult(c, s, n) # semantic checking also needed with importc in case used in VM s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos])) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index c9cd82833..e771e17c4 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -145,9 +145,6 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode = illFormedAst(n, c.c.config) result = n -template oldCheck(cx: TemplCtx; cond: bool): bool = - (optNimV019 notin cx.c.config.globalOptions or cond) - proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} = result = n.kind == nkSym and n.sym.kind == skParam and n.sym.owner == c.owner and sfTemplateParam in n.sym.flags @@ -215,21 +212,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = closeScope(c) let ident = getIdentNode(c, n) if not isTemplParam(c, ident): - # fix #2670, consider: - # - # when b: - # var a = "hi" - # else: - # var a = 5 - # echo a - # - # We need to ensure that both 'a' produce the same gensym'ed symbol. - # So we need only check the *current* scope. - let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident)) - if s != nil and s.owner == c.owner and sfGenSym in s.flags: - onUse(n.info, s) - replaceIdentBySym(c.c, n, newSymNode(s, n.info)) - elif n.kind != nkSym: + if n.kind != nkSym: let local = newGenSym(k, ident, c) addPrelimDecl(c.c, local) styleCheckDef(c.c.config, n.info, local) @@ -560,16 +543,16 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = if n.kind == nkDotExpr: result = n result[0] = semTemplBody(c, n[0]) - if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym + inc c.noGenSym result[1] = semTemplBody(c, n[1]) - if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym + dec c.noGenSym else: result = semTemplBodySons(c, n) of nkExprColonExpr, nkExprEqExpr: if n.len == 2: - if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym + inc c.noGenSym result[0] = semTemplBody(c, n[0]) - if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym + dec c.noGenSym result[1] = semTemplBody(c, n[1]) else: result = semTemplBodySons(c, n) diff --git a/compiler/types.nim b/compiler/types.nim index b0581e96a..94fe8fd54 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -936,7 +936,7 @@ proc equalParams(a, b: PNode): TParamsEquality = discard of paramsIncompatible: result = paramsIncompatible - if (m.name.id != n.name.id): + if m.name.id != n.name.id: # BUGFIX return paramsNotEqual # paramsIncompatible; # continue traversal! If not equal, we can return immediately; else diff --git a/compiler/vm.nim b/compiler/vm.nim index 1edcace82..bb217c4db 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1233,7 +1233,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let node = regs[rb+i].regToNode node.info = c.debug[pc] macroCall.add(node) - var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache) + var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter) if a.kind == nkStmtList and a.len == 1: a = a[0] a.recSetFlagIsRef ensureKind(rkNode) @@ -2232,7 +2232,7 @@ proc errorNode(owner: PSym, n: PNode): PNode = result.typ = newType(tyError, owner) result.typ.flags.incl tfCheckedForDestructor -proc evalMacroCall*(module: PSym; g: ModuleGraph; +proc evalMacroCall*(module: PSym; g: ModuleGraph; templInstCounter: ref int; n, nOrig: PNode, sym: PSym): PNode = if g.config.errorCounter > 0: return errorNode(module, n) @@ -2253,6 +2253,7 @@ proc evalMacroCall*(module: PSym; g: ModuleGraph; c.mode = emStaticStmt c.comesFromHeuristic.line = 0'u16 c.callsite = nOrig + c.templInstCounter = templInstCounter let start = genProc(c, sym) var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 9228ce5eb..59ffe9581 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -262,6 +262,7 @@ type graph*: ModuleGraph oldErrorCount*: int profiler*: Profiler + templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst PStackFrame* = ref TStackFrame TStackFrame* = object diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 8fa7c99a9..a4187f64c 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -12,7 +12,7 @@ var packages2*: seq[tuple[name, cmd: string; hasDeps: bool; url: string, useHead # pkg1 "alea", true pkg1 "argparse" pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" -pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" +#pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" pkg1 "awk", true pkg1 "bigints" pkg1 "binaryheap", false, "nim c -r binaryheap.nim" @@ -95,7 +95,7 @@ pkg2 "optionsutils" pkg2 "ormin", true, "nim c -o:orminn ormin.nim" pkg2 "parsetoml" pkg2 "patty" -pkg2 "plotly", true, "nim c --oldgensym:on examples/all.nim" +pkg2 "plotly", true, "nim c examples/all.nim" pkg2 "pnm" pkg2 "polypbren" pkg2 "prologue", true, "nim c -d:release -r tests/test_compile/test_compile.nim" diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index 255a98ba9..882c0735d 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -35,6 +35,10 @@ test foo1 foo2 foo3 +true +false +true +false ''' """ @@ -289,3 +293,113 @@ proc main() = const fb = Foobar(a: a) foobar(fb) main() + +# bug #13484 + +proc defForward(id, nid: NimNode): NimNode = + result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode()) + +proc defEven(evenid, oddid, nid: NimNode): NimNode = + result = quote do: + proc `evenid`(`nid`: int): bool = + if `nid` == 0: + return true + else: + return `oddid`(`nid` - 1) + +proc defOdd(evenid, oddid, nid: NimNode): NimNode = + result = quote do: + proc `oddid`(`nid`: int): bool = + if `nid` == 0: + return false + else: + return `evenid`(`nid` - 1) + +proc callNode(funid, param: NimNode): NimNode = + result = quote do: + `funid`(`param`) + +macro testEvenOdd3(): untyped = + let + evenid = newIdentNode("even3") + oddid = newIdentNode("odd3") + nid = newIdentNode("n") + oddForward = defForward(oddid, nid) + even = defEven(evenid, oddid, nid) + odd = defOdd(evenid, oddid, nid) + callEven = callNode(evenid, newLit(42)) + callOdd = callNode(oddid, newLit(42)) + result = quote do: + `oddForward` + `even` + `odd` + echo `callEven` + echo `callOdd` + +macro testEvenOdd4(): untyped = + let + evenid = newIdentNode("even4") + oddid = newIdentNode("odd4") + nid = newIdentNode("n") + oddForward = defForward(oddid, nid) + even = defEven(evenid, oddid, nid) + odd = defOdd(evenid, oddid, nid) + callEven = callNode(evenid, newLit(42)) + callOdd = callNode(oddid, newLit(42)) + # rewrite the body of proc node. + oddForward[6] = newStmtList() + result = quote do: + `oddForward` + `even` + `odd` + echo `callEven` + echo `callOdd` + +macro testEvenOdd5(): untyped = + let + evenid = genSym(nskProc, "even5") + oddid = genSym(nskProc, "odd5") + nid = newIdentNode("n") + oddForward = defForward(oddid, nid) + even = defEven(evenid, oddid, nid) + odd = defOdd(evenid, oddid, nid) + callEven = callNode(evenid, newLit(42)) + callOdd = callNode(oddid, newLit(42)) + result = quote do: + `oddForward` + `even` + `odd` + echo `callEven` + echo `callOdd` + +macro testEvenOdd6(): untyped = + let + evenid = genSym(nskProc, "even6") + oddid = genSym(nskProc, "odd6") + nid = newIdentNode("n") + oddForward = defForward(oddid, nid) + even = defEven(evenid, oddid, nid) + odd = defOdd(evenid, oddid, nid) + callEven = callNode(evenid, newLit(42)) + callOdd = callNode(oddid, newLit(42)) + # rewrite the body of proc node. + oddForward[6] = newStmtList() + result = quote do: + `oddForward` + `even` + `odd` + echo `callEven` + echo `callOdd` + +# it works +testEvenOdd3() + +# it causes an error (redefinition of odd4), which is correct +assert not compiles testEvenOdd4() + +# it caused an error (still forwarded: odd5) +testEvenOdd5() + +# it works, because the forward decl and definition share the symbol and the compiler is forgiving here +#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future + diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index a35d878d5..cfd354a74 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -195,3 +195,129 @@ mystate_machine: state_push(S1) echo state_current() state_pop() + +# bug #15075 +block: #Doesn't work + template genGenTempl: untyped = + proc loop(locals: int) + proc loop(locals: int) = discard + genGenTempl() + let pool = loop + +block: #Doesn't work + macro genGenMacro: untyped = + quote do: + proc loop(locals: int) + proc loop(locals: int) = discard + genGenMacro() + let pool = loop + +block: #This works + proc loop(locals: int) + proc loop(locals: int) = discard + let pool = loop + +#Now somewhat recursive: +type Cont = ref object of RootObj + fn*: proc(c: Cont): Cont {.nimcall.} + +block: #Doesn't work + template genGenTempl(): untyped = + proc loop(locals: Cont): Cont + proc loop(locals: Cont): Cont = + return Cont(fn: loop) + proc doServer(): Cont = + return Cont(fn: loop) + genGenTempl() + discard doServer() + +block: #Doesn't work + macro genGenMacro(): untyped = + quote: + proc loop(locals: Cont): Cont + proc loop(locals: Cont): Cont = + return Cont(fn: loop) + proc doServer(): Cont = + return Cont(fn: loop) + genGenMacro() + discard doServer() + +block: #This works + proc loop(locals: Cont): Cont + proc loop(locals: Cont): Cont = + return Cont(fn: loop) + proc doServer(): Cont = + return Cont(fn: loop) + discard doServer() + +#And fully recursive: +block: #Doesn't work + template genGenTempl: untyped = + proc loop(locals: int) + proc loop(locals: int) = loop(locals) + genGenTempl() + let pool = loop + +block: #Doesn't work + macro genGenMacro: untyped = + quote do: + proc loop(locals: int) + proc loop(locals: int) = loop(locals) + genGenMacro() + let pool = loop + +block: #This works + proc loop(locals: int) + proc loop(locals: int) = loop(locals) + let pool = loop + +block: + template genAndCallLoop: untyped = + proc loop() {.gensym.} + proc loop() {.gensym.} = + discard + loop() + genAndCallLoop + +block: #Fully recursive and gensymmed: + template genGenTempl: untyped = + proc loop(locals: int) {.gensym.} + proc loop(locals: int) {.gensym.} = loop(locals) + let pool = loop + genGenTempl() + +block: #Make sure gensymmed symbol doesn't overwrite the forward decl + proc loop() + proc loop() = discard + template genAndCallLoop: untyped = + proc loop() {.gensym.} = + discard + loop() + genAndCallLoop() + +template genLoopDecl: untyped = + proc loop() +template genLoopDef: untyped = + proc loop() = discard +block: + genLoopDecl + genLoopDef + loop() +block: + proc loop() + genLoopDef + loop() +block: + genLoopDecl + proc loop() = discard + loop() + +block: #Gensymmed sym sharing forward decl + macro genGenMacro: untyped = + let sym = genSym(nskProc, "loop") + nnkStmtList.newTree( + newProc(sym, body = newEmptyNode()), + newCall(sym), + newProc(sym, body = newStmtList()), + ) + genGenMacro From c645dba038f3d801afe1b9c842bd49bd9455b410 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 29 Jul 2020 22:18:27 +0800 Subject: [PATCH 0977/4254] fixes #14139 (#15107) * fix #14139 * Update lib/pure/collections/heapqueue.nim Co-authored-by: Andreas Rumpf Co-authored-by: Clyybber --- lib/pure/collections/heapqueue.nim | 6 +++--- tests/stdlib/t14139.nim | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 tests/stdlib/t14139.nim diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index 608fd2920..c2952cf1b 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -156,10 +156,10 @@ proc replace*[T](heap: var HeapQueue[T], item: T): T = proc pushpop*[T](heap: var HeapQueue[T], item: T): T = ## Fast version of a push followed by a pop. - if heap.len > 0 and heapCmp(heap[0], item): - swap(item, heap[0]) + result = item + if heap.len > 0 and heapCmp(heap.data[0], item): + swap(result, heap.data[0]) siftup(heap, 0) - return item proc clear*[T](heap: var HeapQueue[T]) = ## Remove all elements from `heap`, making it empty. diff --git a/tests/stdlib/t14139.nim b/tests/stdlib/t14139.nim new file mode 100644 index 000000000..78e0f6645 --- /dev/null +++ b/tests/stdlib/t14139.nim @@ -0,0 +1,9 @@ +import heapqueue + +var test_queue : HeapQueue[int] + +test_queue.push(7) +test_queue.push(3) +test_queue.push(9) +let i = test_queue.pushpop(10) +assert i == 3 From 0788a7f97085ceed618285d9b8a869022d17c373 Mon Sep 17 00:00:00 2001 From: genotrance Date: Wed, 29 Jul 2020 15:42:08 -0500 Subject: [PATCH 0978/4254] Bump nimble (#15114) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index be658a53e..1364b6b04 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "c4b9c6e459e72c5b04e0beb993b2a912a4078cb5" # master + NimbleStableCommit = "d01d8f2df0ab321d414156be373704416da67f71" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From 20315637aa5c6f018d868b7c3c26ca1b52d4cc65 Mon Sep 17 00:00:00 2001 From: alaviss Date: Wed, 29 Jul 2020 22:35:02 +0000 Subject: [PATCH 0979/4254] asyncnet, net: don't attempt SSL_shutdown if a fatal error occurred (#15066) * asyncnet, net: don't attempt SSL_shutdown if a fatal error occurred Per TLS standard and SSL_shutdown(3ssl). This should prevent errors coming from a close() after a bad event (ie. the other end of the pipe is closed before shutdown can be negotiated). Ref #9867 * tssl: try sending until an error occur * tssl: cleanup * tssl: actually run the test I forgot to make the test run :P * tssl: run the test on ARC, maybe then it'll be happy * tssl: turns off ARC, switch tlsEmulation on for freebsd * tssl: document why tlsEmulation is employed * net: move SafeDisconn handling logic to socketError --- lib/pure/asyncnet.nim | 13 +++++--- lib/pure/net.nim | 73 +++++++++++++++++++++++++----------------- tests/stdlib/tssl.nim | 63 ++++++++++++++++++++++++++++++++++++ tests/stdlib/tssl.nims | 5 +++ 4 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 tests/stdlib/tssl.nim create mode 100644 tests/stdlib/tssl.nims diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 410310e29..9846f8999 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -123,6 +123,7 @@ type sslContext: SslContext bioIn: BIO bioOut: BIO + sslNoShutdown: bool domain: Domain sockType: SockType protocol: Protocol @@ -200,9 +201,10 @@ proc newAsyncSocket*(domain, sockType, protocol: cint, Protocol(protocol), buffered, inheritable) when defineSsl: - proc getSslError(handle: SslPtr, err: cint): cint = + proc getSslError(socket: AsyncSocket, err: cint): cint = + assert socket.isSsl assert err < 0 - var ret = SSL_get_error(handle, err.cint) + var ret = SSL_get_error(socket.sslHandle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") @@ -213,6 +215,7 @@ when defineSsl: of SSL_ERROR_WANT_X509_LOOKUP: raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: + socket.sslNoShutdown = true raiseSSLError() else: raiseSSLError("Unknown Error") @@ -265,7 +268,7 @@ when defineSsl: # If the operation failed, try to see if SSL has some data to read # or write. if opResult < 0: - let err = getSslError(socket.sslHandle, opResult.cint) + let err = getSslError(socket, opResult.cint) let fut = appeaseSsl(socket, flags, err.cint) yield fut if not fut.read(): @@ -718,7 +721,7 @@ proc close*(socket: AsyncSocket) = # Don't call SSL_shutdown if the connection has not been fully # established, see: # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 - if SSL_in_init(socket.sslHandle) == 0: + if not socket.sslNoShutdown and SSL_in_init(socket.sslHandle) == 0: ErrClearError() SSL_shutdown(socket.sslHandle) else: @@ -747,6 +750,8 @@ when defineSsl: socket.bioOut = bioNew(bioSMem()) sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut) + socket.sslNoShutdown = true + proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket, handshake: SslHandshakeType, hostname: string = "") = diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 7aeffbc35..f53095854 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -133,6 +133,7 @@ type sslNoHandshake: bool # True if needs handshake. sslHasPeekChar: bool sslPeekChar: char + sslNoShutdown: bool # True if shutdown shouldn't be done. lastError: OSErrorCode ## stores the last error on this socket domain: Domain sockType: SockType @@ -173,7 +174,8 @@ when defined(nimHasStyleChecks): {.pop.} proc socketError*(socket: Socket, err: int = -1, async = false, - lastError = (-1).OSErrorCode): void {.gcsafe.} + lastError = (-1).OSErrorCode, + flags: set[SocketFlag] = {}): void {.gcsafe.} proc isDisconnectionError*(flags: set[SocketFlag], lastError: OSErrorCode): bool = @@ -722,6 +724,7 @@ when defineSsl: socket.sslHandle = SSL_new(socket.sslContext.context) socket.sslNoHandshake = false socket.sslHasPeekChar = false + socket.sslNoShutdown = false if socket.sslHandle == nil: raiseSSLError() @@ -818,7 +821,8 @@ proc getSocketError*(socket: Socket): OSErrorCode = raiseOSError(result, "No valid socket error code available") proc socketError*(socket: Socket, err: int = -1, async = false, - lastError = (-1).OSErrorCode) = + lastError = (-1).OSErrorCode, + flags: set[SocketFlag] = {}) = ## Raises an OSError based on the error code returned by ``SSL_get_error`` ## (for SSL sockets) and ``osLastError`` otherwise. ## @@ -826,6 +830,9 @@ proc socketError*(socket: Socket, err: int = -1, async = false, ## error was caused by no data being available to be read. ## ## If ``err`` is not lower than 0 no exception will be raised. + ## + ## If ``flags`` contains ``SafeDisconn``, no exception will be raised + ## when the error was caused by a peer disconnection. when defineSsl: if socket.isSsl: if err <= 0: @@ -844,33 +851,39 @@ proc socketError*(socket: Socket, err: int = -1, async = false, of SSL_ERROR_WANT_X509_LOOKUP: raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL: - var errStr = "IO error has occurred " - let sslErr = ERR_peek_last_error() - if sslErr == 0 and err == 0: - errStr.add "because an EOF was observed that violates the protocol" - elif sslErr == 0 and err == -1: - errStr.add "in the BIO layer" - else: - let errStr = $ERR_error_string(sslErr, nil) - raiseSSLError(errStr & ": " & errStr) + # SSL shutdown must not be done if a fatal error occurred. + socket.sslNoShutdown = true let osErr = osLastError() - raiseOSError(osErr, errStr) + if not flags.isDisconnectionError(osErr): + var errStr = "IO error has occurred " + let sslErr = ERR_peek_last_error() + if sslErr == 0 and err == 0: + errStr.add "because an EOF was observed that violates the protocol" + elif sslErr == 0 and err == -1: + errStr.add "in the BIO layer" + else: + let errStr = $ERR_error_string(sslErr, nil) + raiseSSLError(errStr & ": " & errStr) + raiseOSError(osErr, errStr) of SSL_ERROR_SSL: + # SSL shutdown must not be done if a fatal error occurred. + socket.sslNoShutdown = true raiseSSLError() else: raiseSSLError("Unknown Error") if err == -1 and not (when defineSsl: socket.isSsl else: false): var lastE = if lastError.int == -1: getSocketError(socket) else: lastError - if async: - when useWinVersion: - if lastE.int32 == WSAEWOULDBLOCK: - return - else: raiseOSError(lastE) - else: - if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK: - return - else: raiseOSError(lastE) - else: raiseOSError(lastE) + if not flags.isDisconnectionError(lastE): + if async: + when useWinVersion: + if lastE.int32 == WSAEWOULDBLOCK: + return + else: raiseOSError(lastE) + else: + if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK: + return + else: raiseOSError(lastE) + else: raiseOSError(lastE) proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = ## Marks ``socket`` as accepting connections. @@ -1026,7 +1039,7 @@ proc close*(socket: Socket) = # Don't call SSL_shutdown if the connection has not been fully # established, see: # https://github.com/openssl/openssl/issues/710#issuecomment-253897666 - if SSL_in_init(socket.sslHandle) == 0: + if not socket.sslNoShutdown and SSL_in_init(socket.sslHandle) == 0: # As we are closing the underlying socket immediately afterwards, # it is valid, under the TLS standard, to perform a unidirectional # shutdown i.e not wait for the peers "close notify" alert with a second @@ -1312,9 +1325,9 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, if result < 0: data.setLen(0) let lastError = getSocketError(socket) - if flags.isDisconnectionError(lastError): return - socket.socketError(result, lastError = lastError) - data.setLen(result) + socket.socketError(result, lastError = lastError, flags = flags) + else: + data.setLen(result) proc recv*(socket: Socket, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): string {.inline.} = @@ -1388,8 +1401,9 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, template raiseSockError() {.dirty.} = let lastError = getSocketError(socket) - if flags.isDisconnectionError(lastError): setLen(line.string, 0); return - socket.socketError(n, lastError = lastError) + if flags.isDisconnectionError(lastError): + setLen(line.string, 0) + socket.socketError(n, lastError = lastError, flags = flags) var waited: Duration @@ -1520,8 +1534,7 @@ proc send*(socket: Socket, data: string, let sent = send(socket, cstring(data), data.len) if sent < 0: let lastError = osLastError() - if flags.isDisconnectionError(lastError): return - socketError(socket, lastError = lastError) + socketError(socket, lastError = lastError, flags = flags) if sent != data.len: raiseOSError(osLastError(), "Could not send all data.") diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim new file mode 100644 index 000000000..cda3cb590 --- /dev/null +++ b/tests/stdlib/tssl.nim @@ -0,0 +1,63 @@ +discard """ + joinable: false +""" + +import net, nativesockets + +when defined(posix): import os, posix + +when not defined(ssl): + {.error: "This test must be compiled with -d:ssl".} + +const DummyData = "dummy data\n" + +proc connector(port: Port) {.thread.} = + let clientContext = newContext(verifyMode = CVerifyNone) + var client = newSocket(buffered = false) + clientContext.wrapSocket(client) + client.connect("localhost", port) + + discard client.recvLine() + client.getFd.close() + +proc main() = + let serverContext = newContext(verifyMode = CVerifyNone, + certFile = "tests/testdata/mycert.pem", + keyFile = "tests/testdata/mycert.pem") + + when defined(posix): + var + ignoreAction = SigAction(sa_handler: SIG_IGN) + oldSigPipeHandler: SigAction + if sigemptyset(ignoreAction.sa_mask) == -1: + raiseOSError(osLastError(), "Couldn't create an empty signal set") + if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1: + raiseOSError(osLastError(), "Couldn't ignore SIGPIPE") + + block peer_close_without_shutdown: + var server = newSocket(buffered = false) + defer: server.close() + serverContext.wrapSocket(server) + server.bindAddr(address = "localhost") + let (_, port) = server.getLocalAddr() + server.listen() + + var clientThread: Thread[Port] + createThread(clientThread, connector, port) + + var peer: Socket + try: + server.accept(peer) + peer.send(DummyData) + + joinThread clientThread + + while true: + # Send data until we get EPIPE. + peer.send(DummyData, {}) + except OSError: + discard + finally: + peer.close() + +when isMainModule: main() diff --git a/tests/stdlib/tssl.nims b/tests/stdlib/tssl.nims new file mode 100644 index 000000000..3f24dc325 --- /dev/null +++ b/tests/stdlib/tssl.nims @@ -0,0 +1,5 @@ +--threads:on +--d:ssl +when defined(freebsd): + # See https://github.com/nim-lang/Nim/pull/15066#issuecomment-665541265 + --tlsEmulation:off From 604f7461d786e31e7ae9df5a101770c329e00fe5 Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 29 Jul 2020 20:49:51 -0700 Subject: [PATCH 0980/4254] Fix tables.CountTable largest and smallest (#15115) It needs to have len defined first because of the assert .len > 0. I just moved it up a bit to make them work. --- lib/pure/collections/tables.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 3aa3af4e9..017a2f337 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -2293,6 +2293,10 @@ proc inc*[A](t: var CountTable[A], key: A, val = 1) = if val != 0: insertImpl() +proc len*[A](t: CountTable[A]): int = + ## Returns the number of keys in ``t``. + result = t.counter + proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] = ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n) ## @@ -2345,10 +2349,6 @@ proc getOrDefault*[A](t: CountTable[A], key: A; default: int = 0): int = ## is in the table ctget(t, key, default) -proc len*[A](t: CountTable[A]): int = - ## Returns the number of keys in ``t``. - result = t.counter - proc del*[A](t: var CountTable[A], key: A) {.since: (1, 1).} = ## Deletes ``key`` from table ``t``. Does nothing if the key does not exist. ## From 32c6146200196398986bee092b4ef4a0f82d90b2 Mon Sep 17 00:00:00 2001 From: jcosborn Date: Thu, 30 Jul 2020 08:34:11 -0500 Subject: [PATCH 0981/4254] fix overloading case with generic alias (#15116) * fix overloading case with generic alias * revert reorganization of tests --- compiler/sigmatch.nim | 2 +- tests/overload/toverload_various.nim | 105 +++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e663f96b6..7d97944ce 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1476,7 +1476,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyGenericBody: considerPreviousT: - if a == f or a.kind == tyGenericInst and a[0] == f: + if a == f or a.kind == tyGenericInst and a.skipGenericAlias[0] == f: bindingRet isGeneric let ff = lastSon(f) if ff != nil: diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 78497e607..96cb9a736 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -270,3 +270,108 @@ proc hmac*[A, B](HashType: typedesc, key: openarray[A], ctx.init(nil, 0) sha256.hmac("", "") + + + +# nested generic types +block: + type + Foo[T] = object + f: T + Bar[T] = object + b: T + Baz[T] = object + z: T + FooBar[T] = Foo[Bar[T]] + FooBarBaz[T] = FooBar[Baz[T]] + #Int = int + Int = SomeInteger + FooBarBazInt = FooBarBaz[Int] + FooBarBazX = FooBarBaz[int] + + proc p00(x: Foo): auto = x.f + proc p01[T](x: Foo[T]): auto = x.f + proc p02[T:Foo](x: T): auto = x.f + + proc p10(x: FooBar): auto = x.f + proc p11[T](x: FooBar[T]): auto = x.f + proc p12[T:FooBar](x: T): auto = x.f + proc p13(x: Foo[Bar]): auto = x.f + proc p14[T](x: Foo[Bar[T]]): auto = x.f + proc p15[T:Bar](x: Foo[T]): auto = x.f + proc p16[T:Foo[Bar]](x: T): auto = x.f + + proc p20(x: FooBarBaz): auto = x.f + proc p21[T](x: FooBarBaz[T]): auto = x.f + proc p22[T:FooBarBaz](x: T): auto = x.f + proc p23(x: FooBar[Baz]): auto = x.f + proc p24[T](x: FooBar[Baz[T]]): auto = x.f + proc p25[T:Baz](x: FooBar[T]): auto = x.f + proc p26[T:FooBar[Baz]](x: T): auto = x.f + proc p27(x: Foo[Bar[Baz]]): auto = x.f + proc p28[T](x: Foo[Bar[Baz[T]]]): auto = x.f + proc p29[T:Baz](x: Foo[Bar[T]]): auto = x.f + proc p2A[T:Bar[Baz]](x: Foo[T]): auto = x.f + proc p2B[T:Foo[Bar[Baz]]](x: T): auto = x.f + + proc p30(x: FooBarBazInt): auto = x.f + proc p31[T:FooBarBazInt](x: T): auto = x.f + proc p32(x: FooBarBaz[Int]): auto = x.f + proc p33[T:Int](x: FooBarBaz[T]): auto = x.f + proc p34[T:FooBarBaz[Int]](x: T): auto = x.f + proc p35(x: FooBar[Baz[Int]]): auto = x.f + proc p36[T:Int](x: FooBar[Baz[T]]): auto = x.f + proc p37[T:Baz[Int]](x: FooBar[T]): auto = x.f + proc p38[T:FooBar[Baz[Int]]](x: T): auto = x.f + proc p39(x: Foo[Bar[Baz[Int]]]): auto = x.f + proc p3A[T:Int](x: Foo[Bar[Baz[T]]]): auto = x.f + proc p3B[T:Baz[Int]](x: Foo[Bar[T]]): auto = x.f + proc p3C[T:Bar[Baz[Int]]](x: Foo[T]): auto = x.f + proc p3D[T:Foo[Bar[Baz[Int]]]](x: T): auto = x.f + + template test(x: typed) = + let t00 = p00(x) + let t01 = p01(x) + let t02 = p02(x) + let t10 = p10(x) + let t11 = p11(x) + let t12 = p12(x) + #let t13 = p13(x) + let t14 = p14(x) + #let t15 = p15(x) + #let t16 = p16(x) + let t20 = p20(x) + let t21 = p21(x) + let t22 = p22(x) + #let t23 = p23(x) + let t24 = p24(x) + #let t25 = p25(x) + #let t26 = p26(x) + #let t27 = p27(x) + let t28 = p28(x) + #let t29 = p29(x) + #let t2A = p2A(x) + #let t2B = p2B(x) + let t30 = p30(x) + let t31 = p31(x) + let t32 = p32(x) + let t33 = p33(x) + let t34 = p34(x) + let t35 = p35(x) + let t36 = p36(x) + let t37 = p37(x) + let t38 = p38(x) + let t39 = p39(x) + let t3A = p3A(x) + let t3B = p3B(x) + let t3C = p3C(x) + let t3D = p3D(x) + + var a: Foo[Bar[Baz[int]]] + test(a) + var b: FooBar[Baz[int]] + test(b) + var c: FooBarBaz[int] + test(c) + var d: FooBarBazX + test(d) From d130175342f2b7c1bf87dd05c86509f04cf78154 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Jul 2020 17:32:48 +0200 Subject: [PATCH 0982/4254] cursor and mutation tracking fixes (#15113) * fixes #15110 * fixes #15096 * prepare varpartitions for cursor inference * new cursor inference begins to work * make tests green --- compiler/ast.nim | 9 + compiler/cursor_inference.nim | 300 --------------------------------- compiler/injectdestructors.nim | 4 +- compiler/sempass2.nim | 2 + compiler/varpartitions.nim | 295 ++++++++++++++++++++++++++------ compiler/vmmarshal.nim | 5 - tests/arc/topt_cursor2.nim | 51 ++++++ tests/arc/topt_no_cursor.nim | 13 +- 8 files changed, 311 insertions(+), 368 deletions(-) delete mode 100644 compiler/cursor_inference.nim create mode 100644 tests/arc/topt_cursor2.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 6ca79aeee..1e619e51b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1841,6 +1841,11 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool = proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as" +proc skipColon*(n: PNode): PNode = + result = n + if n.kind == nkExprColonExpr: + result = n[1] + proc findUnresolvedStatic*(n: PNode): PNode = # n.typ == nil: see issue #14802 if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil: @@ -1860,6 +1865,10 @@ when false: if n[i].containsNil: return true template hasDestructor*(t: PType): bool = {tfHasAsgn, tfHasOwned} * t.flags != {} + +proc hasDisabledAsgn*(t: PType): bool = + t.attachedOps[attachedAsgn] != nil and sfError in t.attachedOps[attachedAsgn].flags + template incompleteType*(t: PType): bool = t.sym != nil and {sfForward, sfNoForward} * t.sym.flags == {sfForward} diff --git a/compiler/cursor_inference.nim b/compiler/cursor_inference.nim deleted file mode 100644 index 0402febec..000000000 --- a/compiler/cursor_inference.nim +++ /dev/null @@ -1,300 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Cursor inference: -## The basic idea was like this: Elide 'destroy(x)' calls if only -## special literals are assigned to 'x' and 'x' is not mutated or -## passed by 'var T' to something else. Special literals are string literals or -## arrays / tuples of string literals etc. -## -## However, there is a much more general rule here: Compute which variables -## can be annotated with `.cursor`. To see how and when we can do that, -## think about this question: In `dest = src` when do we really have to -## *materialize* the full copy? - Only if `dest` or `src` are mutated -## afterwards. `dest` is the potential cursor variable, so that is -## simple to analyse. And if `src` is a location derived from a -## formal parameter, we also know it is not mutated! In other words, we -## do a compile-time copy-on-write analysis. - -import - ast, types, renderer, idents, intsets, options - -type - Cursor = object - s: PSym - deps: IntSet - Con = object - cursors: seq[Cursor] - mayOwnData: IntSet - mutations: IntSet - reassigns: IntSet - config: ConfigRef - inAsgnSource: int - -proc locationRoot(e: PNode; followDotExpr = true): PSym = - var n = e - while true: - case n.kind - of nkSym: - if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}: - return n.sym - else: - return nil - of nkDotExpr, nkDerefExpr, nkBracketExpr, nkHiddenDeref, - nkCheckedFieldExpr, nkAddr, nkHiddenAddr: - if followDotExpr: - n = n[0] - else: - return nil - of nkObjUpConv, nkObjDownConv: - n = n[0] - of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: - n = n[1] - of nkStmtList, nkStmtListExpr: - if n.len > 0: - n = n[^1] - else: - return nil - else: - return nil - -proc addDep(c: var Con; dest: var Cursor; dependsOn: PSym) = - if dest.s != dependsOn: - dest.deps.incl dependsOn.id - -proc cursorId(c: Con; x: PSym): int = - for i in 0.. 0: - analyseAsgn(c, dest, n[^1]) - - of nkClosure: - for i in 1.. treat it like a sink parameter - c.mayOwnData.incl r.id - c.mutations.incl r.id - -proc analyse(c: var Con; n: PNode) = - case n.kind - of nkCallKinds: - let parameters = n[0].typ - let L = if parameters != nil: parameters.len else: 0 - - analyse(c, n[0]) - for i in 1..= 0: - analyseAsgn(c, c.cursors[idx], n[1]) - - c.reassigns.incl n[0].sym.id - else: - # assignments like 'x.field = value' mean that 'x' itself cannot - # be a cursor: - let r = locationRoot(n[0]) - if r != nil: - # however, an assignment like 'it.field = x' does not influence r's - # cursorness property: - if r.typ.skipTypes(abstractInst).kind notin {tyPtr, tyRef}: - c.mayOwnData.incl r.id - c.mutations.incl r.id - - if hasDestructor(n[1].typ): - rhsIsSink(c, n[1]) - - of nkAddr, nkHiddenAddr: - analyse(c, n[0]) - let r = locationRoot(n[0]) - if r != nil: - c.mayOwnData.incl r.id - c.mutations.incl r.id - - of nkTupleConstr, nkBracket, nkObjConstr: - for child in n: analyse(c, child) - if c.inAsgnSource > 0: - for i in ord(n.kind == nkObjConstr).. 0: - allRoots(n.lastSon, result) + allRoots(n.lastSon, result, followDotExpr) of nkCaseStmt, nkObjConstr: for i in 1.. 1: - allRoots(n[1], result) + allRoots(n[1], result, followDotExpr) else: let m = getMagic(n) case m @@ -201,77 +216,223 @@ proc allRoots(n: PNode; result: var seq[PSym]) = let paramType = typ.n[i].typ if not paramType.isCompileTimeOnly and not typ.sons[0].isEmptyType and canAlias(paramType, typ.sons[0]): - allRoots(it, result) + allRoots(it, result, followDotExpr) else: - allRoots(it, result) + allRoots(it, result, followDotExpr) of mSlice: - allRoots(n[1], result) + allRoots(n[1], result, followDotExpr) else: discard "harmless operation" else: discard "nothing to do" -proc deps(p: var Partitions; dest, src: PNode) = +proc analyseAsgn(c: var Partitions; dest: var VarIndex; n: PNode) = + case n.kind + of nkEmpty, nkCharLit..nkNilLit: + # primitive literals including the empty are harmless: + discard + + of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv: + analyseAsgn(c, dest, n[1]) + + of nkIfStmt, nkIfExpr: + for i in 0.. 0: + analyseAsgn(c, dest, n[^1]) + + of nkClosure: + for i in 1..= 0: + c.s[vid].flags.incl preventCursor + +proc rhsIsSink(c: var Partitions, n: PNode) = + if n.kind == nkSym and n.typ.skipTypes(abstractInst-{tyOwned}).kind == tyRef: + discard "do no pessimize simple refs further, injectdestructors.nim will prevent moving from it" + else: + var roots: seq[PSym] + allRoots(n, roots, followDotExpr = false) + # let x = cursor? --> treat it like a sink parameter + for r in roots: + noCursor(c, r) + +proc deps(c: var Partitions; dest, src: PNode) = var targets, sources: seq[PSym] allRoots(dest, targets) allRoots(src, sources) for t in targets: if dest.kind != nkSym: - potentialMutation(p, t, dest.info) + potentialMutation(c, t, dest.info) proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} if types.searchTypeFor(t.typ, wrap): for s in sources: - connect(p, t, s, dest.info) + connect(c, t, s, dest.info) -proc traverse(p: var Partitions; n: PNode) = + if c.performCursorInference and src.kind != nkEmpty: + if dest.kind == nkSym: + let vid = variableId(c, dest.sym) + if vid >= 0: + analyseAsgn(c, c.s[vid], src) + # do not borrow from a different local variable, this is easier + # than tracking reassignments, consider 'var cursor = local; local = newNode()' + if src.kind == nkSym and (src.sym.kind in {skVar, skResult, skTemp} or + (src.sym.kind in {skLet, skParam, skForVar} and hasDisabledAsgn(src.sym.typ))): + c.s[vid].flags.incl preventCursor + + if hasDestructor(src.typ): + rhsIsSink(c, src) + +proc traverse(c: var Partitions; n: PNode) = case n.kind of nkLetSection, nkVarSection: for child in n: let last = lastSon(child) - traverse(p, last) + traverse(c, last) if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: if child.len-2 != last.len: return for i in 0.. 0: + for i in 0.. 0: + for i in 1.. Date: Thu, 30 Jul 2020 19:19:59 +0200 Subject: [PATCH 0983/4254] fixes #15112 (#15124) --- compiler/ccgexprs.nim | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 73cc2c8a1..33231b1bc 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -729,14 +729,16 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage) -proc cow(p: BProc; n: PNode) = - if n.kind == nkHiddenAddr and optSeqDestructors in p.config.globalOptions: - if n[0].kind == nkBracketExpr: - let strCandidate = n[0][0] - if strCandidate.typ.skipTypes(abstractInst).kind == tyString: - var a: TLoc - initLocExpr(p, strCandidate, a) - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) +proc cowBracket(p: BProc; n: PNode) = + if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions: + let strCandidate = n[0] + if strCandidate.typ.skipTypes(abstractInst).kind == tyString: + var a: TLoc + initLocExpr(p, strCandidate, a) + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + +proc cow(p: BProc; n: PNode) {.inline.} = + if n.kind == nkHiddenAddr: cowBracket(p, n[0]) proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: @@ -1759,6 +1761,8 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = # temp = a # a = b # b = temp + cowBracket(p, e[1]) + cowBracket(p, e[2]) var a, b, tmp: TLoc getTemp(p, skipTypes(e[1].typ, abstractVar), tmp) initLocExpr(p, e[1], a) # eval a From f1971243d3e162889b10b46caab8ba6e98afa92d Mon Sep 17 00:00:00 2001 From: genotrance Date: Thu, 30 Jul 2020 13:13:34 -0500 Subject: [PATCH 0984/4254] Bump nimble (#15126) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 1364b6b04..68a880d0d 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "d01d8f2df0ab321d414156be373704416da67f71" # master + NimbleStableCommit = "a3e1267265965fc79a50b66999b660e0920db8cd" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From d23ae4953510287c64e5bbbfb8c0e1eea23822f6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 31 Jul 2020 12:13:33 +0200 Subject: [PATCH 0985/4254] fixes #15071 [backport] (#15131) --- compiler/transf.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 7aa18bf52..29344e7a1 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1109,15 +1109,15 @@ proc liftDeferAux(n: PNode) = if n[i].kind == nkDefer: let deferPart = newNodeI(nkFinally, n[i].info) deferPart.add n[i][0] - var tryStmt = newNodeI(nkTryStmt, n[i].info) - var body = newNodeI(n.kind, n[i].info) + var tryStmt = newNodeIT(nkTryStmt, n[i].info, n.typ) + var body = newNodeIT(n.kind, n[i].info, n.typ) if i < last: body.sons = n.sons[(i+1)..last] tryStmt.add body tryStmt.add deferPart n[i] = tryStmt n.sons.setLen(i+1) - n.typ = n[i].typ + n.typ = tryStmt.typ goOn = true break for i in 0..n.safeLen-1: From 4bf8d38248f40cc0bf5323843a9ea38c5bcc20a8 Mon Sep 17 00:00:00 2001 From: Oliver Daniel Date: Fri, 31 Jul 2020 10:35:50 -0400 Subject: [PATCH 0986/4254] Small typo (#15132) The expected output necessarily cannot match the formatted string. --- lib/pure/sugar.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index d2bdb0fdc..3d9a9d42e 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -201,7 +201,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} ## for j in 7..9: ## if i * j == 42: ## capture i, j: - ## myClosure = proc () = echo fmt"{i} * {j} = 42" + ## myClosure = proc () = echo fmt"{i} * {j} == 42" ## myClosure() # output: 6 * 7 == 42 ## let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s] ## var l = m.mapIt(capture(it, proc (s: string): string = it(s))) From 6b88cd0d42cac8059cb4ead691d20c21ed445a12 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 31 Jul 2020 20:27:58 +0200 Subject: [PATCH 0987/4254] Revert "Small typo (#15132)" (#15134) This reverts commit 4bf8d38248f40cc0bf5323843a9ea38c5bcc20a8. --- lib/pure/sugar.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 3d9a9d42e..d2bdb0fdc 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -201,7 +201,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} ## for j in 7..9: ## if i * j == 42: ## capture i, j: - ## myClosure = proc () = echo fmt"{i} * {j} == 42" + ## myClosure = proc () = echo fmt"{i} * {j} = 42" ## myClosure() # output: 6 * 7 == 42 ## let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s] ## var l = m.mapIt(capture(it, proc (s: string): string = it(s))) From 4ab6887a67dcc87f961937447df0907b9dc7f26d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 1 Aug 2020 07:39:00 +0200 Subject: [PATCH 0988/4254] fixes #15111 (#15136) --- compiler/dfa.nim | 4 ++-- compiler/parser.nim | 4 +++- compiler/semobjconstr.nim | 38 +++++++++++++++++++------------------- compiler/semtypes.nim | 8 ++++++-- compiler/varpartitions.nim | 2 ++ 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index f3b358d72..85a9ccf42 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -280,7 +280,7 @@ proc patch(c: var Con, p: TPosition) = # patch with current index c.code[p.int].dest = checkedDistance(c.code.len - p.int) -func gen(c: var Con; n: PNode) +proc gen(c: var Con; n: PNode) proc popBlock(c: var Con; oldLen: int) = var exits: seq[TPosition] @@ -712,7 +712,7 @@ proc genVarSection(c: var Con; n: PNode) = if a.lastSon.kind != nkEmpty: genDef(c, a[0]) -func gen(c: var Con; n: PNode) = +proc gen(c: var Con; n: PNode) = case n.kind of nkSym: genUse(c, n) of nkCallKinds: diff --git a/compiler/parser.nim b/compiler/parser.nim index ccb7ca3b1..8cfeff6b0 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1953,7 +1953,7 @@ proc parseObjectPart(p: var TParser): PNode = else: parMessage(p, errIdentifierExpected, p.tok) break - else: + elif sameOrNoInd(p): case p.tok.tokType of tkWhen: result = parseObjectWhen(p) @@ -1968,6 +1968,8 @@ proc parseObjectPart(p: var TParser): PNode = getTok(p) else: result = p.emptyNode + else: + result = p.emptyNode proc parseObject(p: var TParser): PNode = #| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index f8639b000..cd5a52fe9 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -154,20 +154,20 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode, if assignment == nil: constrCtx.missingFields.add r.sym -proc semConstructFields(c: PContext, recNode: PNode, +proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, flags: TExprFlags): InitStatus = result = initUnknown - case recNode.kind + case n.kind of nkRecList: - for field in recNode: + for field in n: let status = semConstructFields(c, field, constrCtx, flags) mergeInitStatus(result, status) of nkRecCase: template fieldsPresentInBranch(branchIdx: int): string = - let branch = recNode[branchIdx] + let branch = n[branchIdx] let fields = branch[^1] fieldsPresentInInitExpr(c, fields, constrCtx.initExpr) @@ -176,12 +176,12 @@ proc semConstructFields(c: PContext, recNode: PNode, let fields = branchNode[^1] collectMissingFields(c, fields, constrCtx) - let discriminator = recNode[0] + let discriminator = n[0] internalAssert c.config, discriminator.kind == nkSym var selectedBranch = -1 - for i in 1.. MaxSetElements or - lengthOrd(c.config, recNode[0].typ) > MaxSetElements): + lengthOrd(c.config, n[0].typ) > MaxSetElements): localError(c.config, discriminatorVal.info, "branch initialization with a runtime discriminator only " & "supports ordinal types with 2^16 elements or less.") @@ -242,7 +242,7 @@ proc semConstructFields(c: PContext, recNode: PNode, if ctorCase == nil: if discriminatorVal.typ.kind == tyRange: let rangeVals = c.getIntSetOfType(discriminatorVal.typ) - let recBranchVals = branchVals(c, recNode, selectedBranch, false) + let recBranchVals = branchVals(c, n, selectedBranch, false) let diff = rangeVals - recBranchVals if diff.len != 0: valuesInConflictError(diff) @@ -260,7 +260,7 @@ proc semConstructFields(c: PContext, recNode: PNode, else: var ctorBranchVals = branchVals(c, ctorCase, ctorIdx, true) - recBranchVals = branchVals(c, recNode, selectedBranch, false) + recBranchVals = branchVals(c, n, selectedBranch, false) branchValsDiff = ctorBranchVals - recBranchVals if branchValsDiff.len != 0: valuesInConflictError(branchValsDiff) @@ -271,14 +271,14 @@ proc semConstructFields(c: PContext, recNode: PNode, failedBranch = selectedBranch else: # With an else clause, check that all other branches don't match: - for i in 1.. Date: Sat, 1 Aug 2020 17:30:51 +0800 Subject: [PATCH 0989/4254] improve epoll docs (#15137) --- lib/posix/epoll.nim | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 74433631d..9f0cf75ed 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -45,44 +45,46 @@ type proc epoll_create*(size: cint): cint {.importc: "epoll_create", header: "".} ## Creates an epoll instance. Returns an fd for the new instance. - ## The "size" parameter is a hint specifying the number of file - ## descriptors to be associated with the new instance. The fd - ## returned by epoll_create() should be closed with close(). + ## + ## The "size" parameter is a hint specifying the number of file + ## descriptors to be associated with the new instance. The fd + ## returned by epoll_create() should be closed with close(). proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1", header: "".} ## Same as epoll_create but with an FLAGS parameter. The unused SIZE - ## parameter has been dropped. + ## parameter has been dropped. proc epoll_ctl*(epfd: cint; op: cint; fd: cint | SocketHandle; event: ptr EpollEvent): cint {. importc: "epoll_ctl", header: "".} - ## Manipulate an epoll instance "epfd". Returns 0 in case of success, - ## -1 in case of error ( the "errno" variable will contain the - ## specific error code ) The "op" parameter is one of the EPOLL_CTL_* - ## constants defined above. The "fd" parameter is the target of the - ## operation. The "event" parameter describes which events the caller - ## is interested in and any associated user data. + ## Manipulate an epoll instance "epfd". Returns ``0`` in case of success, + ## ``-1`` in case of error (the "errno" variable will contain the specific error code). + ## + ## The "op" parameter is one of the ``EPOLL_CTL_*`` + ## constants defined above. The "fd" parameter is the target of the + ## operation. The "event" parameter describes which events the caller + ## is interested in and any associated user data. proc epoll_wait*(epfd: cint; events: ptr EpollEvent; maxevents: cint; timeout: cint): cint {.importc: "epoll_wait", header: "".} ## Wait for events on an epoll instance "epfd". Returns the number of - ## triggered events returned in "events" buffer. Or -1 in case of - ## error with the "errno" variable set to the specific error code. The - ## "events" parameter is a buffer that will contain triggered - ## events. The "maxevents" is the maximum number of events to be - ## returned ( usually size of "events" ). The "timeout" parameter - ## specifies the maximum wait time in milliseconds (-1 == infinite). + ## triggered events returned in "events" buffer. Or -1 in case of + ## error with the "errno" variable set to the specific error code. The + ## "events" parameter is a buffer that will contain triggered + ## events. The "maxevents" is the maximum number of events to be + ## returned ( usually size of "events" ). The "timeout" parameter + ## specifies the maximum wait time in milliseconds (-1 == infinite). ## - ## This function is a cancellation point and therefore not marked with - ## __THROW. + ## This function is a cancellation point and therefore not marked with + ## __THROW. #proc epoll_pwait*(epfd: cint; events: ptr EpollEvent; maxevents: cint; # timeout: cint; ss: ptr sigset_t): cint {. # importc: "epoll_pwait", header: "".} # Same as epoll_wait, but the thread's signal mask is temporarily -# and atomically replaced with the one provided as parameter. +# and atomically replaced with the one provided as parameter. # -# This function is a cancellation point and therefore not marked with -# __THROW. +# This function is a cancellation point and therefore not marked with +# __THROW. From e192e07bf0ac790bcb0b95ee63e62fce688ab40c Mon Sep 17 00:00:00 2001 From: alaviss Date: Sat, 1 Aug 2020 09:33:19 +0000 Subject: [PATCH 0990/4254] ci_docs: build fusion docs (#15127) --- .github/workflows/ci_docs.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 816f560c9..d3d0ba612 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -11,6 +11,7 @@ on: - 'tools/dochack/dochack.nim' - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' + - 'koch.nim' pull_request: # Run only on changes on these files. paths: @@ -121,6 +122,10 @@ jobs: shell: bash run: ./koch boot -d:release + - name: 'Clone fusion' + shell: bash + run: ./koch fusion + - name: 'Build documentation' shell: bash run: ./koch doc --git.commit:devel From 9ff2c50155ca172e2decb0b66ee78b50af3ff51f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 1 Aug 2020 13:16:50 +0200 Subject: [PATCH 0991/4254] fixes #15122 [backport:1.2] (#15139) --- compiler/sempass2.nim | 1 + tests/arc/tarcmisc.nim | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index a2da2f2e4..6db6448df 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -799,6 +799,7 @@ proc trackCall(tracked: PEffects; n: PNode) = # check required for 'nim check': if n[1].typ.len > 0: + createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) createTypeBoundOps(tracked, n[1].typ, n.info) # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index a7f2dd98b..542e4f316 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -319,3 +319,31 @@ proc createMachine = echo machine.factory().hello createMachine() + +# bug #15122 + +import tables + +type + BENodeKind = enum + tkBytes, + tkList, + tkDict + + BENode = object + case kind: BENodeKind + of tkBytes: strVal: string + of tkList: listVal: seq[BENode] + of tkDict: dictVal: Table[string, BENode] + +var data = { + "examples": { + "values": BENode( + kind: tkList, + listVal: @[BENode(kind: tkBytes, strVal: "test")] + ) + }.toTable() +}.toTable() + +# For ARC listVal is empty for some reason +doAssert data["examples"]["values"].listVal[0].strVal == "test" From 8e3f51f06c7008d9db4499864cced392ec02d423 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 1 Aug 2020 18:04:04 +0200 Subject: [PATCH 0992/4254] fixes #15130 (#15141) * fixes #15130 * you really have to copy from cursors --- compiler/dfa.nim | 2 +- compiler/varpartitions.nim | 6 ++- tests/arc/topt_no_cursor.nim | 77 +++++++++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 85a9ccf42..d07122552 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -628,7 +628,7 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = # XXX Allow closure deref operations here if we know # the owner controlled the closure allocation? result = n.kind == nkSym and n.sym.owner == owner and - sfGlobal notin n.sym.flags and + {sfGlobal, sfThread, sfCursor} * n.sym.flags == {} and (n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar) # Note: There is a different move analyzer possible that checks for # consume(param.key); param.key = newValue for all paths. Then code like diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 7a6cc4f63..4535c9aac 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -48,7 +48,7 @@ type s: seq[VarIndex] graphs: seq[MutationInfo] unanalysableMutation, performCursorInference: bool - inAsgnSource: int + inAsgnSource, inConstructor: int proc `$`*(config: ConfigRef; g: MutationInfo): string = result = "" @@ -264,8 +264,10 @@ proc analyseAsgn(c: var Partitions; dest: var VarIndex; n: PNode) = dest.flags.incl ownsData of nkCurly, nkBracket, nkPar, nkTupleConstr: + inc c.inConstructor for son in n: analyseAsgn(c, dest, son) + dec c.inConstructor if n.typ.skipTypes(abstractInst).kind == tySequence: # you must destroy a sequence: dest.flags.incl ownsData @@ -278,6 +280,8 @@ proc analyseAsgn(c: var Partitions; dest: var VarIndex; n: PNode) = else: # otherwise it's just a dependency, nothing to worry about: connect(c, dest.sym, n.sym, n.info) + # but a construct like ``[symbol]`` is dangerous: + if c.inConstructor > 0: dest.flags.incl ownsData of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr, nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr, nkAddr, nkHiddenAddr: diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 3ea4deaf1..fe63e7585 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -2,8 +2,9 @@ discard """ output: '''(repo: "", package: "meo", ext: "") doing shady stuff... 3 -6''' - cmd: '''nim c --gc:arc --expandArc:newTarget --expandArc:delete --hint:Performance:off $file''' +6 +(@[1], @[2])''' + cmd: '''nim c --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off $file''' nimout: '''--expandArc: newTarget var @@ -37,6 +38,44 @@ var `=`(sibling.right, saved.left) `=sink`(sibling.parent, saved) `=destroy`(sibling) +-- end of expandArc ------------------------ +--expandArc: p1 + +var + lresult + lvalue + _ +`=`(lresult, [123]) +var lnext_cursor: string +_ = ( + let blitTmp = lresult + blitTmp, ";") +lvalue = _[0] +lnext_cursor = _[1] +`=sink`(result.value, lvalue) +-- end of expandArc ------------------------ +--expandArc: tt + +var + a + :tmpD + :tmpD_1 + :tmpD_2 +try: + var it_cursor = x + a = ( + wasMoved(:tmpD) + `=`(:tmpD, it_cursor.key) + :tmpD, + wasMoved(:tmpD_1) + `=`(:tmpD_1, it_cursor.val) + :tmpD_1) + echo [ + :tmpD_2 = `$`(a) + :tmpD_2] +finally: + `=destroy`(:tmpD_2) + `=destroy_1`(a) -- end of expandArc ------------------------''' """ @@ -98,3 +137,37 @@ proc main = echo five.right.value main() + +type + Maybe = object + value: seq[int] + +proc p1(): Maybe = + let lresult = @[123] + var lvalue: seq[int] + var lnext: string + (lvalue, lnext) = (lresult, ";") + + result.value = lvalue + +proc tissue15130 = + doAssert p1().value == @[123] + +tissue15130() + +type + KeyValue = tuple[key, val: seq[int]] + +proc tt(x: KeyValue) = + var it = x + let a = (it.key, it.val) + echo a + +proc encodedQuery = + var query: seq[KeyValue] + query.add (key: @[1], val: @[2]) + + for elem in query: + elem.tt() + +encodedQuery() From 3ce32a7e40c92f305a6f48017fe9323d35720f13 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 2 Aug 2020 03:27:21 +0800 Subject: [PATCH 0993/4254] export asyncdispatch handles (#15140) * improve epoll docs * export handles * add comments and changelog --- changelog.md | 2 ++ lib/pure/asyncdispatch.nim | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 517919de9..281995b0e 100644 --- a/changelog.md +++ b/changelog.md @@ -143,6 +143,8 @@ `CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again. - Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. +- Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. + ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 6330a6ba9..41d67d172 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -253,7 +253,7 @@ when defined(windows) or defined(nimdoc): PDispatcher* = ref object of PDispatcherBase ioPort: Handle - handles: HashSet[AsyncFD] + handles*: HashSet[AsyncFD] # Export handles so that an external library can register them. CustomObj = object of OVERLAPPED data*: CompletionData From c619cedd7cba60d588707fbbb2905c8ac85fd12a Mon Sep 17 00:00:00 2001 From: alaviss Date: Sat, 1 Aug 2020 19:27:55 +0000 Subject: [PATCH 0994/4254] net: allow close() to ignore SSL failures due to disconnections (#15120) * net: allow close() to ignore SSL failures due to disconnections Comes with this PR is also a SIGPIPE handling contraption. * net: don't do selectSigpipe() on macOS macOS sockets have SO_NOSIGPIPE set, so an EPIPE doesn't necessary mean that a SIGPIPE happened. * net: fix alreadyBlocked logic * net: WSAESHUTDOWN is also a disconnection error --- lib/pure/net.nim | 106 +++++++++++++++++++++++++++++++++++++--- lib/windows/winlean.nim | 1 + tests/stdlib/tssl.nim | 85 +++++++++++++++++++++++++++++--- 3 files changed, 177 insertions(+), 15 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f53095854..c0bfc39cc 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -75,6 +75,9 @@ export Domain, SockType, Protocol const useWinVersion = defined(Windows) or defined(nimdoc) const defineSsl = defined(ssl) or defined(nimdoc) +when useWinVersion: + from winlean import WSAESHUTDOWN + when defineSsl: import openssl @@ -187,6 +190,7 @@ proc isDisconnectionError*(flags: set[SocketFlag], lastError.int32 == WSAECONNABORTED or lastError.int32 == WSAENETRESET or lastError.int32 == WSAEDISCON or + lastError.int32 == WSAESHUTDOWN or lastError.int32 == ERROR_NETNAME_DELETED) else: SocketFlag.SafeDisconn in flags and @@ -1031,8 +1035,72 @@ proc accept*(server: Socket, client: var owned(Socket), var addrDummy = "" acceptAddr(server, client, addrDummy, flags) -proc close*(socket: Socket) = +when defined(posix): + from posix import Sigset, sigwait, sigismember, sigemptyset, sigaddset, + sigprocmask, pthread_sigmask, SIGPIPE, SIG_BLOCK, SIG_UNBLOCK + +template blockSigpipe(body: untyped): untyped = + ## Temporary block SIGPIPE within the provided code block. If SIGPIPE is + ## raised for the duration of the code block, it will be queued and will be + ## raised once the block ends. + ## + ## Within the block a `selectSigpipe()` template is provided which can be + ## used to remove SIGPIPE from the queue. Note that if SIGPIPE is **not** + ## raised at the time of call, it will block until SIGPIPE is raised. + ## + ## If SIGPIPE has already been blocked at the time of execution, the + ## signal mask is left as-is and `selectSigpipe()` will become a no-op. + ## + ## For convenience, this template is also available for non-POSIX system, + ## where `body` will be executed as-is. + when not defined(posix): + body + else: + template sigmask(how: cint, set, oset: var Sigset): untyped {.gensym.} = + ## Alias for pthread_sigmask or sigprocmask depending on the status + ## of --threads + when compileOption("threads"): + pthread_sigmask(how, set, oset) + else: + sigprocmask(how, set, oset) + + var oldSet, watchSet: Sigset + if sigemptyset(oldSet) == -1: + raiseOSError(osLastError()) + if sigemptyset(watchSet) == -1: + raiseOSError(osLastError()) + + if sigaddset(watchSet, SIGPIPE) == -1: + raiseOSError(osLastError(), "Couldn't add SIGPIPE to Sigset") + + if sigmask(SIG_BLOCK, watchSet, oldSet) == -1: + raiseOSError(osLastError(), "Couldn't block SIGPIPE") + + let alreadyBlocked = sigismember(oldSet, SIGPIPE) == 1 + + template selectSigpipe(): untyped {.used.} = + if not alreadyBlocked: + var signal: cint + let err = sigwait(watchSet, signal) + if err != 0: + raiseOSError(err.OSErrorCode, "Couldn't select SIGPIPE") + assert signal == SIGPIPE + + try: + body + finally: + if not alreadyBlocked: + if sigmask(SIG_UNBLOCK, watchSet, oldSet) == -1: + raiseOSError(osLastError(), "Couldn't unblock SIGPIPE") + +proc close*(socket: Socket, flags = {SocketFlag.SafeDisconn}) = ## Closes a socket. + ## + ## If `socket` is an SSL/TLS socket, this proc will also send a closure + ## notification to the peer. If `SafeDisconn` is in `flags`, failure to do so + ## due to disconnections will be ignored. This is generally safe in + ## practice. See + ## `here `_ for more details. try: when defineSsl: if socket.isSsl and socket.sslHandle != nil: @@ -1044,12 +1112,34 @@ proc close*(socket: Socket) = # it is valid, under the TLS standard, to perform a unidirectional # shutdown i.e not wait for the peers "close notify" alert with a second # call to SSL_shutdown - ErrClearError() - let res = SSL_shutdown(socket.sslHandle) - if res == 0: - discard - elif res != 1: - socketError(socket, res) + blockSigpipe: + ErrClearError() + let res = SSL_shutdown(socket.sslHandle) + if res == 0: + discard + elif res != 1: + let + err = osLastError() + sslError = SSL_get_error(socket.sslHandle, res) + + # If a close notification is received, failures outside of the + # protocol will be returned as SSL_ERROR_ZERO_RETURN instead + # of SSL_ERROR_SYSCALL. This fact is deduced by digging into + # SSL_get_error() source code. + if sslError == SSL_ERROR_ZERO_RETURN or + sslError == SSL_ERROR_SYSCALL: + when defined(posix) and not defined(macosx) and + not defined(nimdoc): + if err == EPIPE.OSErrorCode: + # Clear the SIGPIPE that's been raised due to + # the disconnection. + selectSigpipe() + else: + discard + if not flags.isDisconnectionError(err): + socketError(socket, res, lastError = err, flags = flags) + else: + socketError(socket, res, lastError = err, flags = flags) finally: when defineSsl: if socket.isSsl and socket.sslHandle != nil: @@ -1470,7 +1560,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int, var addrLen = sizeof(sockAddress).SockLen result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) - + if result != -1: data.setLen(result) address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index bd4cfdca7..c28700374 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -813,6 +813,7 @@ const WSAEINPROGRESS* = 10036 WSAEINTR* = 10004 WSAEWOULDBLOCK* = 10035 + WSAESHUTDOWN* = 10058 ERROR_NETNAME_DELETED* = 64 STATUS_PENDING* = 0x103 diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim index cda3cb590..3c2b6be2b 100644 --- a/tests/stdlib/tssl.nim +++ b/tests/stdlib/tssl.nim @@ -5,13 +5,16 @@ discard """ import net, nativesockets when defined(posix): import os, posix +else: + import winlean + const SD_SEND = 1 when not defined(ssl): {.error: "This test must be compiled with -d:ssl".} const DummyData = "dummy data\n" -proc connector(port: Port) {.thread.} = +proc abruptShutdown(port: Port) {.thread.} = let clientContext = newContext(verifyMode = CVerifyNone) var client = newSocket(buffered = false) clientContext.wrapSocket(client) @@ -20,11 +23,16 @@ proc connector(port: Port) {.thread.} = discard client.recvLine() client.getFd.close() -proc main() = - let serverContext = newContext(verifyMode = CVerifyNone, - certFile = "tests/testdata/mycert.pem", - keyFile = "tests/testdata/mycert.pem") +proc notifiedShutdown(port: Port) {.thread.} = + let clientContext = newContext(verifyMode = CVerifyNone) + var client = newSocket(buffered = false) + clientContext.wrapSocket(client) + client.connect("localhost", port) + discard client.recvLine() + client.close() + +proc main() = when defined(posix): var ignoreAction = SigAction(sa_handler: SIG_IGN) @@ -34,7 +42,11 @@ proc main() = if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1: raiseOSError(osLastError(), "Couldn't ignore SIGPIPE") - block peer_close_without_shutdown: + let serverContext = newContext(verifyMode = CVerifyNone, + certFile = "tests/testdata/mycert.pem", + keyFile = "tests/testdata/mycert.pem") + + block peer_close_during_write_without_shutdown: var server = newSocket(buffered = false) defer: server.close() serverContext.wrapSocket(server) @@ -43,7 +55,7 @@ proc main() = server.listen() var clientThread: Thread[Port] - createThread(clientThread, connector, port) + createThread(clientThread, abruptShutdown, port) var peer: Socket try: @@ -60,4 +72,63 @@ proc main() = finally: peer.close() + when defined(posix): + if sigaction(SIGPIPE, oldSigPipeHandler, nil) == -1: + raiseOSError(osLastError(), "Couldn't restore SIGPIPE handler") + + block peer_close_before_received_shutdown: + var server = newSocket(buffered = false) + defer: server.close() + serverContext.wrapSocket(server) + server.bindAddr(address = "localhost") + let (_, port) = server.getLocalAddr() + server.listen() + + var clientThread: Thread[Port] + createThread(clientThread, abruptShutdown, port) + + var peer: Socket + try: + server.accept(peer) + peer.send(DummyData) + + joinThread clientThread + + # Tell the OS to close off the write side so shutdown attempts will + # be met with SIGPIPE. + when defined(posix): + discard peer.getFd.shutdown(SHUT_WR) + else: + discard peer.getFd.shutdown(SD_SEND) + finally: + peer.close() + + block peer_close_after_received_shutdown: + var server = newSocket(buffered = false) + defer: server.close() + serverContext.wrapSocket(server) + server.bindAddr(address = "localhost") + let (_, port) = server.getLocalAddr() + server.listen() + + var clientThread: Thread[Port] + createThread(clientThread, notifiedShutdown, port) + + var peer: Socket + try: + server.accept(peer) + peer.send(DummyData) + + doAssert peer.recv(1024) == "" # Get the shutdown notification + joinThread clientThread + + # Tell the OS to close off the write side so shutdown attempts will + # be met with SIGPIPE. + when defined(posix): + discard peer.getFd.shutdown(SHUT_WR) + else: + discard peer.getFd.shutdown(SD_SEND) + finally: + peer.close() + when isMainModule: main() From 98eb8410f276edcb2767517ebcb391b8369bc911 Mon Sep 17 00:00:00 2001 From: sschwarzer Date: Sat, 1 Aug 2020 22:00:25 +0200 Subject: [PATCH 0995/4254] Remove `noSideEffect` pragmas (#15143) These don't seem to make sense for the purpose of the procs and lead to errors when the `--experimental:strictFuncs` feature is enabled. See also https://github.com/nim-lang/Nim/issues/15142 --- lib/pure/strtabs.nim | 2 +- lib/pure/xmltree.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 81ff7fbde..76f90938c 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -232,7 +232,7 @@ proc enlarge(t: StringTableRef) = swap(t.data, n) proc `[]=`*(t: StringTableRef, key, val: string) {. - rtlFunc, extern: "nstPut", noSideEffect.} = + rtlFunc, extern: "nstPut".} = ## Inserts a `(key, value)` pair into `t`. ## ## See also: diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 9d2e4317e..00e9a031b 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -334,7 +334,7 @@ proc insert*(father, son: XmlNode, index: int) {.inline.} = else: insert(father.s, son, len(father.s)) -proc delete*(n: XmlNode, i: Natural) {.noSideEffect.} = +proc delete*(n: XmlNode, i: Natural) = ## Delete the `i`'th child of `n`. ## ## See also: From d6161e7e9ea1f40ad734c6e811e8169fe24b5e9f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 1 Aug 2020 22:03:15 +0200 Subject: [PATCH 0996/4254] fixes #15129 [backport:1.2] (#15144) --- compiler/sempass2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 6db6448df..41d83ed55 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -843,7 +843,7 @@ proc track(tracked: PEffects, n: PNode) = if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags: tracked.owner.flags.incl sfInjectDestructors # bug #15038: ensure consistency - if not hasDestructor(n.typ): n.typ = n.sym.typ + if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ of nkHiddenAddr, nkAddr: if n[0].kind == nkSym and isLocalVar(tracked, n[0].sym): useVarNoInitCheck(tracked, n[0], n[0].sym) From 9b08c7b3754cf839492a0183125c70f1dedf6990 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 4 Aug 2020 09:03:20 +0200 Subject: [PATCH 0997/4254] add stale bot --- .github/stale.yml | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..821efc268 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,65 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 550 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 20 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - ARC + - bounty + - Crash + - High Priority + - Next release + - Showstopper + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. + If you think it is still a valid issue, write a comment below; + otherwise it will be closed. Thank you for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed From e4710f893e2314a5479839d042a517b9b27f2535 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 4 Aug 2020 10:47:16 +0200 Subject: [PATCH 0998/4254] stalebot: don't send messages to keep spam down --- .github/stale.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index 821efc268..811a43ff1 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -5,7 +5,7 @@ daysUntilStale: 550 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 20 +daysUntilClose: 30 # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) onlyLabels: [] @@ -32,11 +32,12 @@ exemptAssignees: false staleLabel: stale # Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. - If you think it is still a valid issue, write a comment below; - otherwise it will be closed. Thank you for your contributions. +markComment: false +# markComment: > +# This issue has been automatically marked as stale because it has not had +# recent activity. +# If you think it is still a valid issue, write a comment below; +# otherwise it will be closed. Thank you for your contributions. # Comment to post when removing the stale label. # unmarkComment: > From 836660a2975ae783009501653f69f0c97cdd8b85 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 4 Aug 2020 11:00:04 +0200 Subject: [PATCH 0999/4254] put stale limit at 3 years It needs to be slowly brought down to limit the notifications and prevent excessive spamming. --- .github/stale.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index 811a43ff1..31f1f7798 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 550 +daysUntilStale: 1095 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. @@ -32,12 +32,11 @@ exemptAssignees: false staleLabel: stale # Comment to post when marking as stale. Set to `false` to disable -markComment: false -# markComment: > -# This issue has been automatically marked as stale because it has not had -# recent activity. -# If you think it is still a valid issue, write a comment below; -# otherwise it will be closed. Thank you for your contributions. +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. + If you think it is still a valid issue, write a comment below; + otherwise it will be closed. Thank you for your contributions. # Comment to post when removing the stale label. # unmarkComment: > From 2d494f42f305bbac1f74ebf14c47d20c87acacde Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 4 Aug 2020 17:29:57 +0800 Subject: [PATCH 1000/4254] minor improvement (#15155) --- lib/pure/selectors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 12a134ef8..6007a8250 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -290,7 +290,7 @@ else: skey.ident = pident skey.events = pevents skey.param = pparam - skey.data = data + skey.data = pdata when ioselSupportedPlatform: template blockSignals(newmask: var Sigset, oldmask: var Sigset) = From 64aec6eb85b79f21c9da1d9d0c475942514180c5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 4 Aug 2020 12:45:15 +0200 Subject: [PATCH 1001/4254] fixes a collect() bug reported on the forum (#15156) [backport:1.2] --- compiler/semstmts.nim | 2 +- compiler/varpartitions.nim | 2 +- lib/pure/sugar.nim | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 68f0cee64..1315e8960 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -159,7 +159,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode = if it.len == 2: openScope(c) it[0] = forceBool(c, semExprWithType(c, it[0])) - it[1] = semExprBranch(c, it[1]) + it[1] = semExprBranch(c, it[1], flags) typ = commonType(typ, it[1]) closeScope(c) elif it.len == 1: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 4535c9aac..6857e1b57 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -11,7 +11,7 @@ ## Nim's write tracking and also for the cursor inference. ## The algorithm is a reinvention / variation of Steensgaard's ## algorithm. -## The used algorithm is "union find" with path compression. +## The used data structure is "union find" with path compression. import ast, types, lineinfos, options, msgs, renderer from trees import getMagic diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index d2bdb0fdc..00f4de5d8 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -394,3 +394,13 @@ when isMainModule: of "bird": "word" else: d assert z == @["word", "word"] + + + proc tforum = + let ans = collect(newSeq): + for y in 0..10: + if y mod 5 == 2: + for x in 0..y: + x + + tforum() From eb3ba0ae5f9804645343d9b3ae1c41199c5016e8 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 4 Aug 2020 13:00:09 +0200 Subject: [PATCH 1002/4254] limit stalebot a bit more --- .github/stale.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index 31f1f7798..e314fa55e 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -14,10 +14,14 @@ onlyLabels: [] exemptLabels: - ARC - bounty + - Codegen - Crash + - Generics - High Priority + - Macros - Next release - Showstopper + - Static[T] # Set to true to ignore issues in a project (defaults to false) exemptProjects: false @@ -47,7 +51,7 @@ markComment: > # Your comment here. # Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 30 +limitPerRun: 20 # Limit to only `issues` or `pulls` # only: issues From ef6358f0b0be71266d9fa7ae19a3b6f193b305cf Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 4 Aug 2020 18:22:35 +0100 Subject: [PATCH 1003/4254] implement (#15153) --- compiler/vmops.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 27d1ef479..e49d1e38c 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -86,7 +86,7 @@ template wrap2svoid(op, modop) {.dirty.} = template wrapDangerous(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = - if defined(nimsuggest) or c.config.cmd == cmdCheck: + if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck): discard else: op(getString(a, 0), getString(a, 1)) From d9ed816b10a67e802817daa07b5b823c79bcd13e Mon Sep 17 00:00:00 2001 From: archnim <68890552+archnim@users.noreply.github.com> Date: Wed, 5 Aug 2020 16:41:42 +0000 Subject: [PATCH 1004/4254] Added the ability to initialize a deque with an openArray (#15138) * Add ability to initialize a deque with a sequence Example: var dq = initDeque[char](@['a', 'b', 'c']) * Update deques.nim * Optimized deque initialization * Sequence replaced by open array in deque initialization --- lib/pure/collections/deques.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 8150563cc..43ca536b6 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -84,6 +84,12 @@ proc initDeque*[T](initialSize: int = 4): Deque[T] = ## The length of a newly created deque will still be 0. result.initImpl(initialSize) +proc initDeque*[T](arr: openArray[T]): Deque[T] = + ## Create a new deque initialized with an open array + result.initImpl(nextPowerOfTwo(arr.len)) + for i in 0 ..< arr.len: + result.addLast(arr[i]) + proc len*[T](deq: Deque[T]): int {.inline.} = ## Return the number of elements of `deq`. result = deq.count From a528382e057780845585f0befa6da505462a622e Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 7 Aug 2020 21:37:54 +0100 Subject: [PATCH 1005/4254] fix sqlgetdata regression in odbc (#15161) * fix sqlgetdata import * fix db_odbc * more fixes * fix style --- lib/impure/db_odbc.nim | 20 ++++++++------------ lib/wrappers/odbcsql.nim | 8 ++++---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 863cf6c8c..8aadfae73 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -279,7 +279,7 @@ iterator fastRows*(db: var DbConn, query: SqlQuery, ## Rows are retrieved from the server at each iteration. var rowRes: Row - sz: TSqlInteger = 0 + sz: TSqlLen = 0 cCnt: TSqlSmallInt = 0 res: TSqlSmallInt = 0 res = db.prepareFetch(query, args) @@ -293,8 +293,7 @@ iterator fastRows*(db: var DbConn, query: SqlQuery, for colId in 1..cCnt: buf[0] = '\0' db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, - cast[cstring](buf.addr), 4095.TSqlSmallInt, - sz.addr)) + cast[cstring](buf.addr), 4095, sz.addr)) rowRes[colId-1] = $(addr buf) yield rowRes res = SQLFetch(db.stmt) @@ -308,7 +307,7 @@ iterator instantRows*(db: var DbConn, query: SqlQuery, ## on demand using []. Returned handle is valid only within the iterator body. var rowRes: Row = @[] - sz: TSqlInteger = 0 + sz: TSqlLen = 0 cCnt: TSqlSmallInt = 0 res: TSqlSmallInt = 0 res = db.prepareFetch(query, args) @@ -322,8 +321,7 @@ iterator instantRows*(db: var DbConn, query: SqlQuery, for colId in 1..cCnt: buf[0] = '\0' db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, - cast[cstring](buf.addr), 4095.TSqlSmallInt, - sz.addr)) + cast[cstring](buf.addr), 4095, sz.addr)) rowRes[colId-1] = $(addr buf) yield (row: rowRes, len: cCnt.int) res = SQLFetch(db.stmt) @@ -349,7 +347,7 @@ proc getRow*(db: var DbConn, query: SqlQuery, ## will return a Row with empty strings for each column. var rowRes: Row - sz: TSqlInteger = 0 + sz: TSqlLen = 0 cCnt: TSqlSmallInt = 0 res: TSqlSmallInt = 0 res = db.prepareFetch(query, args) @@ -362,8 +360,7 @@ proc getRow*(db: var DbConn, query: SqlQuery, for colId in 1..cCnt: buf[0] = '\0' db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, - cast[cstring](buf.addr), 4095.TSqlSmallInt, - sz.addr)) + cast[cstring](buf.addr), 4095, sz.addr)) rowRes[colId-1] = $(addr buf) res = SQLFetch(db.stmt) result = rowRes @@ -377,7 +374,7 @@ proc getAllRows*(db: var DbConn, query: SqlQuery, var rows: seq[Row] = @[] rowRes: Row - sz: TSqlInteger = 0 + sz: TSqlLen = 0 cCnt: TSqlSmallInt = 0 res: TSqlSmallInt = 0 res = db.prepareFetch(query, args) @@ -391,8 +388,7 @@ proc getAllRows*(db: var DbConn, query: SqlQuery, for colId in 1..cCnt: buf[0] = '\0' db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, - cast[cstring](buf.addr), 4095.TSqlSmallInt, - sz.addr)) + cast[cstring](buf.addr), 4095, sz.addr)) rowRes[colId-1] = $(addr buf) rows.add(rowRes) res = SQLFetch(db.stmt) diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim index 7836f087d..4e37e1a17 100644 --- a/lib/wrappers/odbcsql.nim +++ b/lib/wrappers/odbcsql.nim @@ -718,19 +718,19 @@ proc SQLNumResultCols*(StatementHandle: SqlHStmt, ColumnCount: var TSqlSmallInt) proc SQLDescribeCol*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, ColumnName: PSQLCHAR, BufferLength: TSqlSmallInt, NameLength: var TSqlSmallInt, DataType: var TSqlSmallInt, - ColumnSize: var TSQLULEN, + ColumnSize: var TSqlULen, DecimalDigits: var TSqlSmallInt, Nullable: var TSqlSmallInt): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLFetchScroll*(StatementHandle: SqlHStmt, FetchOrientation: TSqlSmallInt, - FetchOffset: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, + FetchOffset: TSqlLen): TSqlSmallInt{.dynlib: odbclib, importc.} proc SQLExtendedFetch*(hstmt: SqlHStmt, fFetchType: SqlUSmallInt, - irow: TSqlInteger, pcrow: var TSQLULEN, + irow: TSqlLen, pcrow: var TSqlULen, rgfRowStatus: PSQLUSMALLINT): TSqlSmallInt{.dynlib: odbclib, importc.} proc SQLGetData*(StatementHandle: SqlHStmt, ColumnNumber: SqlUSmallInt, TargetType: TSqlSmallInt, TargetValue: SqlPointer, - BufferLength: TSqlInteger, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{. + BufferLength: TSqlLen, StrLen_or_Ind: ptr TSqlLen): TSqlSmallInt{. dynlib: odbclib, importc.} proc SQLSetStmtAttr*(StatementHandle: SqlHStmt, Attribute: TSqlInteger, Value: SqlPointer, StringLength: TSqlInteger): TSqlSmallInt{. From 6f482ab9346230f8e9c24f71091bcd5ca2cb41f8 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Fri, 7 Aug 2020 22:54:34 +0200 Subject: [PATCH 1006/4254] deques.nim: Refactor the `toDeque` functionality (#15166) This commit polishes the new proc introduced by d9ed816b10a6. Changes: - Rename to `toDeque` for more consistency with well-known procs like `toHashSet` and `toTable`. - Rename the `openArray` parameter. The name `arr` was potentially less clear given that the proc can be used with a seq (or string). - Add a `since` annotation. - Reword the doc comment, and clarify that ordering is preserved. - Add runnableExamples. - Add "see also" cross linking between `initDeque` and `toDeque`. - Remove duplicate `nextPowerOfTwo`. The `initImpl` template already includes it. - Implement the proc using the `items` iterator, rather than indexing. This matches the implementation of `sets.toHashSet` and `tables.toTable`. - Add a test within `when isMainModule`. - Add a changelog entry. --- changelog.md | 3 +++ lib/pure/collections/deques.nim | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 281995b0e..f6f1f94cd 100644 --- a/changelog.md +++ b/changelog.md @@ -145,6 +145,9 @@ - Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. +- Added `deques.toDeque`, which creates a deque from an openArray. The usage is + similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, + it was necessary to create an empty deque and add items manually. ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 43ca536b6..54756707d 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -82,13 +82,25 @@ proc initDeque*[T](initialSize: int = 4): Deque[T] = ## Optionally, the initial capacity can be reserved via `initialSize` ## as a performance optimization. ## The length of a newly created deque will still be 0. + ## + ## See also: + ## * `toDeque proc <#toDeque,openArray[T]>`_ result.initImpl(initialSize) -proc initDeque*[T](arr: openArray[T]): Deque[T] = - ## Create a new deque initialized with an open array - result.initImpl(nextPowerOfTwo(arr.len)) - for i in 0 ..< arr.len: - result.addLast(arr[i]) +proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} = + ## Creates a new deque that contains the elements of `x` (in the same order). + ## + ## See also: + ## * `initDeque proc <#initDeque,int>`_ + runnableExamples: + var a = toDeque([7, 8, 9]) + assert len(a) == 3 + assert a.popFirst == 7 + assert len(a) == 2 + + result.initImpl(x.len) + for item in items(x): + result.addLast(item) proc len*[T](deq: Deque[T]): int {.inline.} = ## Return the number of elements of `deq`. @@ -534,6 +546,7 @@ when isMainModule: assert first == 123 assert second == 9 assert($deq == "[4, 56, 6, 789]") + assert deq == [4, 56, 6, 789].toDeque assert deq[0] == deq.peekFirst and deq.peekFirst == 4 #assert deq[^1] == deq.peekLast and deq.peekLast == 789 From eee3b189ff867c0149434e198e89802eca4920ce Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 8 Aug 2020 13:24:54 +0800 Subject: [PATCH 1007/4254] fix #15148 (#15149) * fix #15148 Co-authored-by: alaviss --- lib/pure/asyncfile.nim | 15 +++++++++++---- tests/async/t15148.nim | 12 ++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/async/t15148.nim diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index ad111ec50..71b42c763 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -379,7 +379,7 @@ proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] = proc cb(fd: AsyncFD): bool = result = true - let remainderSize = size-written + let remainderSize = size - written var cbuf = cast[cstring](buf) let res = write(fd.cint, addr cbuf[written], remainderSize.cint) if res < 0: @@ -409,7 +409,7 @@ proc write*(f: AsyncFile, data: string): Future[void] = var copy = data when defined(windows) or defined(nimdoc): var buffer = alloc0(data.len) - copyMem(buffer, addr copy[0], data.len) + copyMem(buffer, copy.cstring, data.len) var ol = newCustom() ol.data = CompletionData(fd: f.fd, cb: @@ -454,8 +454,15 @@ proc write*(f: AsyncFile, data: string): Future[void] = proc cb(fd: AsyncFD): bool = result = true - let remainderSize = data.len-written - let res = write(fd.cint, addr copy[written], remainderSize.cint) + + let remainderSize = data.len - written + + let res = + if data.len == 0: + write(fd.cint, copy.cstring, 0) + else: + write(fd.cint, addr copy[written], remainderSize.cint) + if res < 0: let lastError = osLastError() if lastError.int32 != EAGAIN: diff --git a/tests/async/t15148.nim b/tests/async/t15148.nim new file mode 100644 index 000000000..ba14c1157 --- /dev/null +++ b/tests/async/t15148.nim @@ -0,0 +1,12 @@ +import asyncdispatch, asyncfile, os + +const Filename = "t15148.txt" + +proc saveEmpty() {.async.} = + let + text = "" + file = openAsync(Filename, fmWrite) + await file.write(text) + file.close() + +waitFor saveEmpty() From 0bc8dd0b0065534b2dfab53b1844a9f6cc36844e Mon Sep 17 00:00:00 2001 From: c-blake Date: Sat, 8 Aug 2020 01:26:20 -0400 Subject: [PATCH 1008/4254] Add `iterator inotify_events` which is *almost always* needed logic for (#15152) client code since Linux `inotify` is much like Linux `getdents64`. Expanding on "almost always"..The only time that this `iterator` logic is ***not*** needed on the output of a `read` from inotify fd's is when one passes a length to `read` *guaranteed* to only pass one event struct in the buffer. That unusual circumstance requires (at least!) knowing the length of the delivered filename before an event occurs, and the filename itself is optional for some event types. It is *far* more common to not know lengths in advance which means one passes a buffer big enough for at least one maximum length directory entry (256 bytes) which is then also big enough for *many* "typical" length entries and therefore many events. In such more common scenarios this iterator logic is definitely needed. Further, not using this logic, yet treating the return from read as "the whole answer" can test ok on "thin" event streams (e.g. 1 event per ms), hiding a latent bug of processing only the first event. --- lib/posix/inotify.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim index 79b408425..db698c59c 100644 --- a/lib/posix/inotify.nim +++ b/lib/posix/inotify.nim @@ -73,6 +73,20 @@ proc inotify_rm_watch*(fd: cint; wd: cint): cint {.cdecl, importc: "inotify_rm_watch", header: "".} ## Remove the watch specified by WD from the inotify instance FD. +iterator inotify_events*(evs: pointer, n: int): ptr InotifyEvent = + ## Abstract the packed buffer interface to yield event object pointers. + ## + ## .. code-block:: Nim + ## var evs = newSeq[byte](8192) # Already did inotify_init+add_watch + ## while (let n = read(fd, evs[0].addr, 8192); n) > 0: # read forever + ## for e in inotify_events(evs[0].addr, n): echo e[].len # echo name lens + var ev: ptr InotifyEvent = cast[ptr InotifyEvent](evs) + var n = n + while n > 0: + yield ev + let sz = InotifyEvent.sizeof + int(ev[].len) + n -= sz + ev = cast[ptr InotifyEvent](cast[uint](ev) + uint(sz)) runnableExamples: when defined(linux): From 38068f977843c5070667f40c199f037f9a838d7c Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 8 Aug 2020 12:36:20 +0200 Subject: [PATCH 1009/4254] Make explicit {.nimcall.} a seperate calling convention --- compiler/ast.nim | 7 +++++-- compiler/ccgexprs.nim | 2 +- compiler/ccgtypes.nim | 4 ++-- compiler/cgmeth.nim | 2 +- compiler/lambdalifting.nim | 4 ++-- compiler/pragmas.nim | 6 +++--- compiler/semdata.nim | 2 +- compiler/sigmatch.nim | 4 ++-- compiler/transf.nim | 2 +- compiler/types.nim | 2 +- tests/closure/tinvalidclosure.nim | 2 +- tests/closure/tinvalidclosure4.nim | 9 +++++++++ 12 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 tests/closure/tinvalidclosure4.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 1e619e51b..9f9ead23d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -17,7 +17,8 @@ export int128 type TCallingConvention* = enum - ccDefault, # proc has no explicit calling convention + ccImplicit, # proc has no explicit calling convention + ccNimCall, # proc was explicitly marked as nimcall ccStdCall, # procedure is stdcall ccCDecl, # cdecl ccSafeCall, # safecall @@ -30,10 +31,12 @@ type ccNoConvention # needed for generating proper C procs sometimes const - CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", + ccDefault* = {ccImplicit, ccNimCall} + CallingConvToStr*: array[TCallingConvention, string] = ["", "nimcall", "stdcall", "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", "closure", "noconv"] + type TNodeKind* = enum # order is extremely important, because ranges are used # to check whether a node belongs to a certain class diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 33231b1bc..feaabc59e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1240,7 +1240,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: - if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccDefault: + if bt.destructor.typ == nil or bt.destructor.typ.callConv notin ccDefault: localError(p.module.config, a.lode.info, "the destructor that is turned into a finalizer needs " & "to have the 'nimcall' calling convention") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index f1dc85818..b64d0664b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -234,7 +234,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = else: result = false const - CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", + CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", "N_NIMCALL", "N_STDCALL", "N_CDECL", "N_SAFECALL", "N_SYSCALL", # this is probably not correct for all platforms, # but one can #define it to what one wants @@ -1297,7 +1297,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: - if theProc.typ == nil or theProc.typ.callConv != ccDefault: + if theProc.typ == nil or theProc.typ.callConv notin ccDefault: localError(m.config, info, theProc.name.s & " needs to have the 'nimcall' calling convention") diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index edf9db383..9b871a898 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -113,7 +113,7 @@ proc createDispatcher(s: PSym): PSym = excl(disp.flags, sfExported) disp.typ = copyType(disp.typ, disp.typ.owner, false) # we can't inline the dispatcher itself (for now): - if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault + if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall disp.ast = copyTree(s.ast) disp.ast[bodyPos] = newNodeI(nkEmpty, s.info) disp.loc.r = nil diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c1cd07583..e113b81e4 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -293,7 +293,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = ("'$1' is of type <$2> which cannot be captured as it would violate memory" & " safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") % [s.name.s, typeToString(s.typ), g.config$s.info]) - elif owner.typ.callConv notin {ccClosure, ccDefault}: + elif owner.typ.callConv notin {ccClosure, ccImplicit}: localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) incl(owner.typ.flags, tfCapturesEnv) @@ -822,7 +822,7 @@ proc semCaptureSym*(s, owner: PSym) = var o = owner.skipGenericOwner while o != nil and o.kind != skModule: if s.owner == o: - if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator: + if owner.typ.callConv in {ccClosure, ccImplicit} or owner.kind == skIterator: owner.typ.callConv = ccClosure propagateClosure(owner.skipGenericOwner, s.owner) else: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c9fe3a5e1..d19584d48 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -247,7 +247,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) = proc wordToCallConv(sw: TSpecialWord): TCallingConvention = # this assumes that the order of special words and calling conventions is # the same - result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall)) + TCallingConvention(ord(ccNimCall) + ord(sw) - ord(wNimcall)) proc isTurnedOn(c: PContext, n: PNode): bool = if n.kind in nkPragmaCallKinds and n.len == 2: @@ -326,7 +326,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = # a calling convention that doesn't introduce custom name mangling # cdecl is the default - the user can override this explicitly if sym.kind in routineKinds and sym.typ != nil and - sym.typ.callConv == ccDefault: + sym.typ.callConv == ccImplicit: sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = @@ -978,7 +978,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, incl(sym.flags, sfProcvar) if sym.typ != nil: incl(sym.typ.flags, tfThread) - if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault + if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall of wGcSafe: noVal(c, it) if sym != nil: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5bd6c4cf2..5b1e425d7 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -212,7 +212,7 @@ proc considerGenSyms*(c: PContext; n: PNode) = proc newOptionEntry*(conf: ConfigRef): POptionEntry = new(result) result.options = conf.options - result.defaultCC = ccDefault + result.defaultCC = ccImplicit result.dynlib = nil result.notes = conf.notes result.warningAsErrors = conf.warningAsErrors diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7d97944ce..34b75861a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -639,11 +639,11 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = return isNone elif f.callConv != a.callConv: # valid to pass a 'nimcall' thingie to 'closure': - if f.callConv == ccClosure and a.callConv == ccDefault: + if f.callConv == ccClosure and a.callConv in ccDefault: result = if result == isInferred: isInferredConvertible elif result == isBothMetaConvertible: isBothMetaConvertible else: isConvertible - else: + elif not(f.callConv in ccDefault and a.callConv in ccDefault): return isNone when useEffectSystem: if compatibleEffects(f, a) != efCompat: return isNone diff --git a/compiler/transf.nim b/compiler/transf.nim index 29344e7a1..6d497c546 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -539,7 +539,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = # happens sometimes for generated assignments, etc. of tyProc: result = transformSons(c, n) - if dest.callConv == ccClosure and source.callConv == ccDefault: + if dest.callConv == ccClosure and source.callConv in ccDefault: result = generateThunk(c, result[1], dest) else: result = transformSons(c, n) diff --git a/compiler/types.nim b/compiler/types.nim index 94fe8fd54..8d94423a8 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -679,7 +679,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < t.len - 1: result.add(", ") result.add(')') if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0])) - var prag = if t.callConv == ccDefault: "" else: CallingConvToStr[t.callConv] + var prag = if t.callConv == ccImplicit: "" else: CallingConvToStr[t.callConv] if tfNoSideEffect in t.flags: addSep(prag) prag.add("noSideEffect") diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim index b2d8bd28d..47f3f105f 100644 --- a/tests/closure/tinvalidclosure.nim +++ b/tests/closure/tinvalidclosure.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got " + errormsg: "type mismatch: got " line: 12 """ diff --git a/tests/closure/tinvalidclosure4.nim b/tests/closure/tinvalidclosure4.nim new file mode 100644 index 000000000..7985a2488 --- /dev/null +++ b/tests/closure/tinvalidclosure4.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "illegal capture 'v'" + line: 7 +""" + +proc outer(v: int) = + proc b {.nimcall.} = echo v + b() +outer(5) From 78b2012a9264448fdde8d1018f6623339c113f04 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 8 Aug 2020 12:44:45 +0200 Subject: [PATCH 1010/4254] Add testcase for #5688 --- tests/closure/tnested.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim index dbbe9ba58..7a1881a60 100644 --- a/tests/closure/tnested.nim +++ b/tests/closure/tnested.nim @@ -33,6 +33,7 @@ py py px 6 +proc (){.closure, gcsafe, locks: 0.} ''' """ @@ -177,3 +178,19 @@ block tclosure2: outer2() + +# bug #5688 + +import typetraits + +proc myDiscard[T](a: T) = discard + +proc foo() = + let a = 5 + let f = (proc() = + myDiscard (proc() = echo a) + ) + echo name(type(f)) + +foo() + From 2a8d010742f2429bc31e319554302ffc2a8503a2 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 8 Aug 2020 12:50:06 +0200 Subject: [PATCH 1011/4254] Fix bootstrapping --- compiler/vmops.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index e49d1e38c..7d623ad86 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -85,10 +85,11 @@ template wrap2svoid(op, modop) {.dirty.} = modop op template wrapDangerous(op, modop) {.dirty.} = - proc `op Wrapper`(a: VmArgs) {.nimcall.} = - if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck): + if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck): + proc `op Wrapper`(a: VmArgs) {.nimcall.} = discard - else: + else: + proc `op Wrapper`(a: VmArgs) {.nimcall.} = op(getString(a, 0), getString(a, 1)) modop op From 26a867c83ca162373b8a6f780443d253f70c8912 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 8 Aug 2020 13:22:53 +0200 Subject: [PATCH 1012/4254] Remove little lies :) --- compiler/vmops.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 7d623ad86..298a02bb6 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -88,10 +88,11 @@ template wrapDangerous(op, modop) {.dirty.} = if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck): proc `op Wrapper`(a: VmArgs) {.nimcall.} = discard + modop op else: proc `op Wrapper`(a: VmArgs) {.nimcall.} = op(getString(a, 0), getString(a, 1)) - modop op + modop op proc getCurrentExceptionMsgWrapper(a: VmArgs) {.nimcall.} = setResult(a, if a.currentException.isNil: "" @@ -187,9 +188,9 @@ proc registerAdditionalOps*(c: PCtx) = registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) when defined(nimHasInvariant): - registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} = + registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) = setResult(a, querySettingImpl(c.config, getInt(a, 0))) - registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} = + registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) = setResult(a, querySettingSeqImpl(c.config, getInt(a, 0))) if defined(nimsuggest) or c.config.cmd == cmdCheck: @@ -201,14 +202,14 @@ proc registerAdditionalOps*(c: PCtx) = registerCallback c, "stdlib.os.getCurrentCompilerExe", proc (a: VmArgs) {.nimcall.} = setResult(a, getAppFilename()) - registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) {.nimcall.} = + registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) = let n = getNode(a, 0) if n.kind != nkSym: stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, "symBodyHash() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info) setResult(a, $symBodyDigest(c.graph, n.sym)) - registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) {.nimcall.} = + registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) = let n = getNode(a, 0) if n.kind != nkSym: stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, From 2a8bf470af995f4e7d5bb8a0f49bb2226f95c311 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 8 Aug 2020 23:08:34 +0200 Subject: [PATCH 1013/4254] fixes #15101 [backport] (#15171) --- compiler/semfields.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index a911ae823..cea084d3a 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -23,7 +23,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = result = newNode(nkEmpty) return case n.kind - of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n + of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = copyNode(n) of nkIdent, nkSym: result = n let ident = considerQuotedIdent(c.c, n) @@ -52,8 +52,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = if n.kind == nkContinueStmt: localError(c.c.config, n.info, "'continue' not supported in a 'fields' loop") - result = copyNode(n) - newSons(result, n.len) + result = shallowCopy(n) for i in 0.. Date: Sun, 9 Aug 2020 15:12:53 +0300 Subject: [PATCH 1014/4254] [FIX] strtabs interpolation in nimscript (#15172) * [FIX] strtabs interpolation in nimscript * [TEST] Use `static` in strtabs test --- lib/pure/strtabs.nim | 2 +- tests/stdlib/tstrtabs.nims | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tstrtabs.nims diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 76f90938c..676e8eb1d 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -302,7 +302,7 @@ proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = when defined(js) or defined(nimscript): result = "" else: - if useEnvironment in flags: result = os.getEnv(key).string + if useEnvironment in flags: result = getEnv(key).string else: result = "" if result.len == 0: if useKey in flags: result = '$' & key diff --git a/tests/stdlib/tstrtabs.nims b/tests/stdlib/tstrtabs.nims new file mode 100644 index 000000000..c8ed4ac40 --- /dev/null +++ b/tests/stdlib/tstrtabs.nims @@ -0,0 +1,5 @@ +import strtabs + +static: + let t = {"name": "John", "city": "Monaco"}.newStringTable + doAssert "${name} lives in ${city}" % t == "John lives in Monaco" From b022576ce96f5c166c7f5684bef9de682704cb1b Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 10 Aug 2020 12:57:32 +0200 Subject: [PATCH 1015/4254] Use typeflag instead --- compiler/ast.nim | 8 +++----- compiler/ccgexprs.nim | 2 +- compiler/ccgtypes.nim | 4 ++-- compiler/evalffi.nim | 2 +- compiler/lambdalifting.nim | 5 +++-- compiler/pragmas.nim | 6 ++++-- compiler/semdata.nim | 2 +- compiler/sigmatch.nim | 4 ++-- compiler/transf.nim | 2 +- compiler/types.nim | 2 +- tests/closure/tinvalidclosure5.nim | 10 ++++++++++ 11 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 tests/closure/tinvalidclosure5.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 9f9ead23d..62c1e3894 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -17,8 +17,7 @@ export int128 type TCallingConvention* = enum - ccImplicit, # proc has no explicit calling convention - ccNimCall, # proc was explicitly marked as nimcall + ccNimCall, # nimcall, also the default ccStdCall, # procedure is stdcall ccCDecl, # cdecl ccSafeCall, # safecall @@ -31,12 +30,10 @@ type ccNoConvention # needed for generating proper C procs sometimes const - ccDefault* = {ccImplicit, ccNimCall} - CallingConvToStr*: array[TCallingConvention, string] = ["", "nimcall", "stdcall", + CallingConvToStr*: array[TCallingConvention, string] = ["nimcall", "stdcall", "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", "closure", "noconv"] - type TNodeKind* = enum # order is extremely important, because ranges are used # to check whether a node belongs to a certain class @@ -563,6 +560,7 @@ type tfCompleteStruct # (for importc types); type is fully specified, allowing to compute # sizeof, alignof, offsetof at CT + tfExplicitCallConv TTypeFlags* = set[TTypeFlag] diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index feaabc59e..a97d15d70 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1240,7 +1240,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: - if bt.destructor.typ == nil or bt.destructor.typ.callConv notin ccDefault: + if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccNimCall: localError(p.module.config, a.lode.info, "the destructor that is turned into a finalizer needs " & "to have the 'nimcall' calling convention") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index b64d0664b..fad6093ed 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -234,7 +234,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = else: result = false const - CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", "N_NIMCALL", + CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", "N_STDCALL", "N_CDECL", "N_SAFECALL", "N_SYSCALL", # this is probably not correct for all platforms, # but one can #define it to what one wants @@ -1297,7 +1297,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: - if theProc.typ == nil or theProc.typ.callConv notin ccDefault: + if theProc.typ == nil or theProc.typ.callConv != ccNimCall: localError(m.config, info, theProc.name.s & " needs to have the 'nimcall' calling convention") diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index f89451f51..0d471cf98 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -104,7 +104,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI = case cc - of ccDefault: result = DEFAULT_ABI + of ccNimCall: result = DEFAULT_ABI of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI of ccCDecl: result = DEFAULT_ABI else: diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index e113b81e4..c23ca52cb 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -293,7 +293,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = ("'$1' is of type <$2> which cannot be captured as it would violate memory" & " safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") % [s.name.s, typeToString(s.typ), g.config$s.info]) - elif owner.typ.callConv notin {ccClosure, ccImplicit}: + elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags): localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) incl(owner.typ.flags, tfCapturesEnv) @@ -822,7 +822,8 @@ proc semCaptureSym*(s, owner: PSym) = var o = owner.skipGenericOwner while o != nil and o.kind != skModule: if s.owner == o: - if owner.typ.callConv in {ccClosure, ccImplicit} or owner.kind == skIterator: + if owner.typ.callConv == ccClosure or owner.kind == skIterator or + owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags: owner.typ.callConv = ccClosure propagateClosure(owner.skipGenericOwner, s.owner) else: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index d19584d48..44ff90010 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -326,7 +326,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = # a calling convention that doesn't introduce custom name mangling # cdecl is the default - the user can override this explicitly if sym.kind in routineKinds and sym.typ != nil and - sym.typ.callConv == ccImplicit: + tfExplicitCallConv notin sym.typ.flags: sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = @@ -1061,7 +1061,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of FirstCallConv..LastCallConv: assert(sym != nil) if sym.typ == nil: invalidPragma(c, it) - else: sym.typ.callConv = wordToCallConv(k) + else: + sym.typ.callConv = wordToCallConv(k) + sym.typ.flags.incl tfExplicitCallConv of wEmit: pragmaEmit(c, it) of wUnroll: pragmaUnroll(c, it) of wLinearScanEnd, wComputedGoto: noVal(c, it) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5b1e425d7..b99ddcba3 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -212,7 +212,7 @@ proc considerGenSyms*(c: PContext; n: PNode) = proc newOptionEntry*(conf: ConfigRef): POptionEntry = new(result) result.options = conf.options - result.defaultCC = ccImplicit + result.defaultCC = ccNimCall result.dynlib = nil result.notes = conf.notes result.warningAsErrors = conf.warningAsErrors diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 34b75861a..786cca01f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -639,11 +639,11 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = return isNone elif f.callConv != a.callConv: # valid to pass a 'nimcall' thingie to 'closure': - if f.callConv == ccClosure and a.callConv in ccDefault: + if f.callConv == ccClosure and a.callConv == ccNimCall: result = if result == isInferred: isInferredConvertible elif result == isBothMetaConvertible: isBothMetaConvertible else: isConvertible - elif not(f.callConv in ccDefault and a.callConv in ccDefault): + else: return isNone when useEffectSystem: if compatibleEffects(f, a) != efCompat: return isNone diff --git a/compiler/transf.nim b/compiler/transf.nim index 6d497c546..3333acbf1 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -539,7 +539,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = # happens sometimes for generated assignments, etc. of tyProc: result = transformSons(c, n) - if dest.callConv == ccClosure and source.callConv in ccDefault: + if dest.callConv == ccClosure and source.callConv == ccNimCall: result = generateThunk(c, result[1], dest) else: result = transformSons(c, n) diff --git a/compiler/types.nim b/compiler/types.nim index 8d94423a8..3545b0703 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -679,7 +679,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < t.len - 1: result.add(", ") result.add(')') if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0])) - var prag = if t.callConv == ccImplicit: "" else: CallingConvToStr[t.callConv] + var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: CallingConvToStr[t.callConv] if tfNoSideEffect in t.flags: addSep(prag) prag.add("noSideEffect") diff --git a/tests/closure/tinvalidclosure5.nim b/tests/closure/tinvalidclosure5.nim new file mode 100644 index 000000000..d03d93867 --- /dev/null +++ b/tests/closure/tinvalidclosure5.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "type mismatch: got but expected 'A = proc (){.nimcall.}'" + line: 9 +""" + +type A = proc() {.nimcall.} +proc main = + let b = 1 + let a: A = proc() = echo b + From 2260ede247c50b88677e9f80530469d4d7d0c43a Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Mon, 10 Aug 2020 14:01:47 +0200 Subject: [PATCH 1016/4254] Added array type definition to manual (#15173) Co-authored-by: Ico Doornekamp --- doc/manual.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index c5608da84..4d26421fe 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1301,6 +1301,9 @@ array constructor ``[]``. The element type of this array expression is inferred from the type of the first element. All other elements need to be implicitly convertible to this type. +An array type can be defined using the `array[size, T]` syntax, or using +`array[lo..hi, T]` for arrays that start at an index other than zero. + Sequences are similar to arrays but of dynamic length which may change during runtime (like strings). Sequences are implemented as growable arrays, allocating pieces of memory as items are added. A sequence ``S`` is always From 963db9e7dac39f4238f013addfae36439318b67f Mon Sep 17 00:00:00 2001 From: Silvio Date: Tue, 11 Aug 2020 14:49:57 +0200 Subject: [PATCH 1017/4254] docs: dlimport -> dynlib (#15175) --- lib/pure/dynlib.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index f31ae94dd..42d13535f 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -97,7 +97,7 @@ proc libCandidates*(s: string, dest: var seq[string]) = add(dest, s) proc loadLibPattern*(pattern: string, globalSymbols = false): LibHandle = - ## loads a library with name matching `pattern`, similar to what `dlimport` + ## loads a library with name matching `pattern`, similar to what `dynlib` ## pragma does. Returns nil if the library could not be loaded. ## Warning: this proc uses the GC and so cannot be used to load the GC. var candidates = newSeq[string]() From 2cea52ee7e7d0f118976df5311a84540cbea85cd Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 11 Aug 2020 22:28:49 +0200 Subject: [PATCH 1018/4254] Allow pragmas on parameters (#15178) --- compiler/semtypes.nim | 4 ++-- tests/template/tparams_gensymed.nim | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index c2aeadc21..6a1c1afc9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1234,7 +1234,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if typ == nil: typ = def.typ if isEmptyContainer(typ): - localError(c.config, a.info, "cannot infer the type of parameter '" & a[0].ident.s & "'") + localError(c.config, a.info, "cannot infer the type of parameter '" & $a[0] & "'") if typ.kind == tyTypeDesc: # consider a proc such as: @@ -1265,7 +1265,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, continue for j in 0.. Date: Tue, 11 Aug 2020 23:46:16 -0300 Subject: [PATCH 1019/4254] Fix typo on CoroutineRef* doc (#15179) Just a small fix for a typo ("for for"). --- lib/pure/coro.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index ead3849c6..6e49b6323 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -158,7 +158,7 @@ type ## CoroutineRef holds a pointer to actual coroutine object. Public API always returns ## CoroutineRef instead of CoroutinePtr in order to allow holding a reference to coroutine ## object while it can be safely deallocated by coroutine scheduler loop. In this case - ## Coroutine.reference.coro is set to nil. Public API checks for for it being nil and + ## Coroutine.reference.coro is set to nil. Public API checks for it being nil and ## gracefully fails if it is nil. coro: CoroutinePtr From 957bf15a08d5443a50452909743747d19b5f29f8 Mon Sep 17 00:00:00 2001 From: alaviss Date: Wed, 12 Aug 2020 06:04:54 +0000 Subject: [PATCH 1020/4254] asyncnet: don't try to close the socket again [backport] (#15174) The closed flag isn't a good design by any means, but let's have this working first before I get rid of the flag and potentially create a non-backportable commit. --- lib/pure/asyncnet.nim | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 9846f8999..455efe1c1 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -713,8 +713,12 @@ elif defined(nimdoc): proc close*(socket: AsyncSocket) = ## Closes the socket. + if socket.closed: return + defer: socket.fd.AsyncFD.closeSocket() + socket.closed = true # TODO: Add extra debugging checks for this. + when defineSsl: if socket.isSsl: let res = @@ -731,7 +735,6 @@ proc close*(socket: AsyncSocket) = discard elif res != 1: raiseSSLError() - socket.closed = true # TODO: Add extra debugging checks for this. when defineSsl: proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) = @@ -819,9 +822,9 @@ proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string, ## address or a hostname. If a hostname is specified this function will try ## each IP of that hostname. The returned future will complete once all data ## has been sent. - ## + ## ## If an error occurs an OSError exception will be raised. - ## + ## ## This proc is normally used with connectionless sockets (UDP sockets). assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket. Use `send` instead") @@ -834,22 +837,22 @@ proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string, it = aiList success = false lastException: ref Exception - + while it != nil: let fut = sendTo(socket.fd.AsyncFD, cstring(data), len(data), it.ai_addr, it.ai_addrlen.SockLen, flags) - + yield fut if not fut.failed: success = true break - + lastException = fut.readError() it = it.ai_next - + freeaddrinfo(aiList) if not success: @@ -869,24 +872,24 @@ proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int, ## packet received. ## ## If an error occurs an OSError exception will be raised. - ## + ## ## This proc is normally used with connectionless sockets (UDP sockets). - ## + ## ## **Notes** ## * ``data`` must be initialized to the length of ``size``. ## * ``address`` must be initialized to 46 in length. template adaptRecvFromToDomain(domain: Domain) = var lAddr = sizeof(sAddr).SockLen - + result = await recvFromInto(AsyncFD(getFd(socket)), cstring(data.mget()), size, cast[ptr SockAddr](addr sAddr), addr lAddr, flags) - + data.mget().setLen(result) data.complete() getAddrString(cast[ptr SockAddr](addr sAddr), address.mget()) - + address.complete() when domain == AF_INET6: @@ -901,7 +904,7 @@ proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int, "`date` was not initialized correctly. `size` != `len(data.mget())`") assert(46 == len(address.mget()), "`address` was not initialized correctly. 46 != `len(address.mget())`") - + case socket.domain of AF_INET6: var sAddr: Sockaddr_in6 @@ -920,18 +923,18 @@ proc recvFrom*(socket: AsyncSocket, size: int, ## ``size``. Returned future will complete once one datagram has been received ## and will return tuple with: data of packet received; and address and port ## of datagram's sender. - ## + ## ## If an error occurs an OSError exception will be raised. - ## + ## ## This proc is normally used with connectionless sockets (UDP sockets). var data = newFutureVar[string]() address = newFutureVar[string]() port = newFutureVar[Port]() - + data.mget().setLen(size) address.mget().setLen(46) - + let read = await recvFrom(socket, data, size, address, port, flags) result = (data.mget(), address.mget(), port.mget()) From ba042af9cc6194cd3c3e67e5daf0165b4b3630c0 Mon Sep 17 00:00:00 2001 From: slangmgh <37659406+slangmgh@users.noreply.github.com> Date: Sat, 15 Aug 2020 07:33:21 +0800 Subject: [PATCH 1021/4254] std/with support field assign (#14484) * std/with support filed assign * add changelog * add support x.dup.with * add example * revert support x.dup.with; add example * update changelog; fix assignment in parameter * Update changelog.md * add example for assignment in parameter * Remove colon style assign Co-authored-by: Clyybber --- changelog.md | 15 +++++++++++++++ lib/pure/sugar.nim | 26 ++++++++++++++++++++++++++ lib/std/private/underscored_calls.nim | 23 +++++++++++------------ lib/std/with.nim | 7 +++++++ 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index f6f1f94cd..eebccb62f 100644 --- a/changelog.md +++ b/changelog.md @@ -148,6 +148,21 @@ - Added `deques.toDeque`, which creates a deque from an openArray. The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create an empty deque and add items manually. + +- `std/with`, `sugar.dup` now support object field assignment expression: + ```nim + import std/with + + type Foo = object + x, y: int + + var foo = Foo() + with foo: + x = 10 + y = 20 + + echo foo + ``` ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 00f4de5d8..0edcc5697 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -337,6 +337,32 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} = when isMainModule: since (1, 1): + block dup_with_field: + type + Foo = object + col, pos: int + name: string + + proc inc_col(foo: var Foo) = inc(foo.col) + proc inc_pos(foo: var Foo) = inc(foo.pos) + proc name_append(foo: var Foo, s: string) = foo.name &= s + + let a = Foo(col: 1, pos: 2, name: "foo") + block: + let b = a.dup(inc_col, inc_pos): + _.pos = 3 + name_append("bar") + inc_pos + + doAssert(b == Foo(col: 2, pos: 4, name: "foobar")) + + block: + let b = a.dup(inc_col, pos = 3, name = "bar"): + name_append("bar") + inc_pos + + doAssert(b == Foo(col: 2, pos: 4, name: "barbar")) + import algorithm var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim index c7aeb6ae2..f0bcbcc74 100644 --- a/lib/std/private/underscored_calls.nim +++ b/lib/std/private/underscored_calls.nim @@ -26,6 +26,12 @@ proc underscoredCall(n, arg0: NimNode): NimNode = for i in 1..u-1: result.add n[i] result.add arg0 for i in u+1..n.len-1: result.add n[i] + elif n.kind in {nnkAsgn, nnkExprEqExpr}: + var field = n[0] + if n[0].kind == nnkDotExpr and n[0][0].eqIdent("_"): + # handle _.field = ... + field = n[0][1] + result = newDotExpr(arg0, field).newAssignment n[1] else: # handle e.g. 'x.dup(sort)' result = newNimNode(nnkCall, n) @@ -33,17 +39,10 @@ proc underscoredCall(n, arg0: NimNode): NimNode = result.add arg0 proc underscoredCalls*(result, calls, arg0: NimNode) = - proc handleStmtList(result, n, arg0: NimNode) = - for a in n: - if a.kind in {nnkStmtList, nnkStmtListExpr}: - handleStmtList(result, a, arg0) - else: - result.add underscoredCall(a, arg0) + expectKind calls, {nnkArgList, nnkStmtList, nnkStmtListExpr} - expectKind calls, nnkArgList - if calls.len == 1 and calls[0].kind in {nnkStmtList, nnkStmtListExpr}: - # the 'macro: body' syntax is used: - handleStmtList(result, calls[0], arg0) - else: - for call in calls: + for call in calls: + if call.kind in {nnkStmtList, nnkStmtListExpr}: + underscoredCalls(result, call, arg0) + else: result.add underscoredCall(call, arg0) diff --git a/lib/std/with.nim b/lib/std/with.nim index c1ac96fcb..ea26065a1 100644 --- a/lib/std/with.nim +++ b/lib/std/with.nim @@ -41,6 +41,7 @@ when isMainModule: type Foo = object col, pos: string + name: string proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) @@ -49,3 +50,9 @@ when isMainModule: with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) echo f + f = Foo() + with f: + col = $(2, 3, 4) + pos = $(0.0, 1.0) + _.name = "bar" + echo f From c9fdad2c21a6394daec70e9d0e215176b69783ac Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 17 Aug 2020 03:39:58 -0300 Subject: [PATCH 1022/4254] db_postgres document how to use it with unix socket (#15187) --- lib/impure/db_postgres.nim | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 9e8075450..f9f584663 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -37,6 +37,26 @@ ## VALUES ($1, $2, $3)""", ## 3) ## +## +## Unix Socket +## =========== +## +## Using Unix sockets instead of TCP connection can +## `improve performance up to 30% ~ 175% for some operations `_. +## +## To use Unix sockets with `db_postgres`, change the server address to the socket file path: +## +## .. code-block:: Nim +## import db_postgres ## Change "localhost" or "127.0.0.1" to the socket file path +## let db = db_postgres.open("/run/postgresql", "user", "password", "database") +## echo db.getAllRows(sql"SELECT version();") +## db.close() +## +## The socket file path is operating system specific and distribution specific, +## additional configuration may or may not be needed on your `postgresql.conf`. +## The Postgres server must be on the same computer and only works for Unix-like operating systems. +## +## ## Examples ## ======== ## @@ -491,7 +511,7 @@ proc tryInsert*(db: DbConn, query: SqlQuery,pkName: string, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect], since: (1, 3).}= ## executes the query (typically "INSERT") and returns the - ## generated ID for the row or -1 in case of an error. + ## generated ID for the row or -1 in case of an error. var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName), args), 0, 0) if not isNil(x): @@ -503,7 +523,7 @@ proc insert*(db: DbConn, query: SqlQuery, pkName: string, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect], since: (1, 3).} = ## executes the query (typically "INSERT") and returns the - ## generated ID + ## generated ID result = tryInsertID(db, query, args) if result < 0: dbError(db) From 39906c52c4fd075b813bc1e0f65a9e25a8e9e95a Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 17 Aug 2020 09:11:33 +0200 Subject: [PATCH 1023/4254] stale bot is now active only for pull requests --- .github/stale.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index e314fa55e..7825ad58d 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 1095 +daysUntilStale: 730 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. @@ -37,9 +37,9 @@ staleLabel: stale # Comment to post when marking as stale. Set to `false` to disable markComment: > - This issue has been automatically marked as stale because it has not had + This pull request has been automatically marked as stale because it has not had recent activity. - If you think it is still a valid issue, write a comment below; + If you think it is still a valid PR, please rebase it on the latest devel; otherwise it will be closed. Thank you for your contributions. # Comment to post when removing the stale label. @@ -54,7 +54,7 @@ markComment: > limitPerRun: 20 # Limit to only `issues` or `pulls` -# only: issues +only: pulls # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': # pulls: From cd28fe2ef7a204721efa72082c9f65f8d13bcfb3 Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 17 Aug 2020 16:54:34 +0800 Subject: [PATCH 1024/4254] add openssl missing procs (#15180) --- lib/wrappers/openssl.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index bea96127d..a37c5b1be 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -691,6 +691,7 @@ proc EVP_sha512*(): EVP_MD {.cdecl, importc.} proc EVP_mdc2*(): EVP_MD {.cdecl, importc.} proc EVP_ripemd160*(): EVP_MD {.cdecl, importc.} proc EVP_whirlpool*(): EVP_MD {.cdecl, importc.} +proc EVP_MD_size*(md: EVP_MD): cint {.cdecl, importc.} # hmac functions proc HMAC*(evp_md: EVP_MD; key: pointer; key_len: cint; d: cstring; n: csize_t; md: cstring; md_len: ptr cuint): cstring {.cdecl, importc.} @@ -699,7 +700,9 @@ proc HMAC*(evp_md: EVP_MD; key: pointer; key_len: cint; d: cstring; n: csize_t; proc PEM_read_bio_PrivateKey*(bp: BIO, x: ptr EVP_PKEY, cb: pointer, u: pointer): EVP_PKEY {.cdecl, importc.} proc EVP_PKEY_free*(p: EVP_PKEY) {.cdecl, importc.} proc EVP_DigestSignInit*(ctx: EVP_MD_CTX, pctx: ptr EVP_PKEY_CTX, typ: EVP_MD, e: ENGINE, pkey: EVP_PKEY): cint {.cdecl, importc.} +proc EVP_DigestInit_ex*(ctx: EVP_MD_CTX, typ: PEVP_MD, engine: SslPtr = nil): cint {.cdecl, importc.} proc EVP_DigestUpdate*(ctx: EVP_MD_CTX, data: pointer, len: cuint): cint {.cdecl, importc.} +proc EVP_DigestFinal_ex*(ctx: EVP_MD_CTX, buffer: pointer, size: ptr cuint): cint {.cdecl, importc.} proc EVP_DigestSignFinal*(ctx: EVP_MD_CTX, data: pointer, len: ptr csize_t): cint {.cdecl, importc.} proc EVP_PKEY_CTX_new*(pkey: EVP_PKEY, e: ENGINE): EVP_PKEY_CTX {.cdecl, importc.} proc EVP_PKEY_CTX_free*(pkeyCtx: EVP_PKEY_CTX) {.cdecl, importc.} @@ -708,10 +711,12 @@ proc EVP_PKEY_sign_init*(c: EVP_PKEY_CTX): cint {.cdecl, importc.} when defined(macosx) or defined(windows): proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc.} proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc.} + proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.cdecl, importc.} else: # some times you will need this instead: proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc: "EVP_MD_CTX_new".} proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc: "EVP_MD_CTX_free".} + proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.cdecl, importc: "EVP_MD_CTX_cleanup".} # type From 6feb3900b121a356a1c091855008d080223ea802 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 17 Aug 2020 14:32:52 +0200 Subject: [PATCH 1025/4254] fixes #15177, the error message is now what it should have been (#15195) --- lib/pure/net.nim | 2 +- lib/pure/smtp.nim | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c0bfc39cc..ea1c86c31 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -116,7 +116,7 @@ when defineSsl: else: type - SslContext* = void # TODO: Workaround #4797. + SslContext* = ref object # TODO: Workaround #4797. const BufferSize*: int = 4000 ## size of a buffered socket's buffer diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index b42664029..5eafc6680 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -87,7 +87,7 @@ proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = await smtp.sock.send(cmd) proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = - ## Receives a line of data from the socket connected to the + ## Receives a line of data from the socket connected to the ## SMTP server. ## ## If the ``smtp`` object was created with ``debug`` enabled, @@ -112,8 +112,7 @@ proc quitExcpt(smtp: Smtp, msg: string) = const compiledWithSsl = defined(ssl) when not defined(ssl): - type PSSLContext = ref object - let defaultSSLContext: PSSLContext = nil + let defaultSSLContext: SSLContext = nil else: var defaultSSLContext {.threadvar.}: SSLContext From e9df8ebcfd475a715756d24e1718a5c1455689d2 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 17 Aug 2020 18:20:48 +0000 Subject: [PATCH 1026/4254] gc_regions: cleanup & fixes for deallocation (#11920) * gc_regions: withRegion nows return the modified MemRegion * gc_regions: make withScratchRegion dealloc correctly * tests/gc: add tregionleak test This test checks if memory within regions are freed properly. --- lib/system/gc_regions.nim | 9 ++++----- tests/gc/tregionleak.nim | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 tests/gc/tregionleak.nim diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index 4f802c812..9425e040a 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -87,13 +87,13 @@ var tlRegion {.threadVar.}: MemRegion # tempStrRegion {.threadVar.}: MemRegion # not yet used -template withRegion*(r: MemRegion; body: untyped) = +template withRegion*(r: var MemRegion; body: untyped) = let oldRegion = tlRegion tlRegion = r try: body finally: - #r = tlRegion + r = tlRegion tlRegion = oldRegion template inc(p: pointer, s: int) = @@ -262,14 +262,13 @@ when false: setObstackPtr(obs) template withScratchRegion*(body: untyped) = - var scratch: MemRegion let oldRegion = tlRegion - tlRegion = scratch + tlRegion = MemRegion() try: body finally: + deallocAll() tlRegion = oldRegion - deallocAll(scratch) when false: proc joinRegion*(dest: var MemRegion; src: MemRegion) = diff --git a/tests/gc/tregionleak.nim b/tests/gc/tregionleak.nim new file mode 100644 index 000000000..277cfc987 --- /dev/null +++ b/tests/gc/tregionleak.nim @@ -0,0 +1,23 @@ +discard """ + cmd: '''nim c --gc:regions $file''' + output: ''' +finalized +finalized +''' +""" + +proc finish(o: RootRef) = + echo "finalized" + +withScratchRegion: + var test: RootRef + new(test, finish) + +var + mr: MemRegion + test: RootRef + +withRegion(mr): + new(test, finish) + +deallocAll(mr) From e194cb41a4502d3d8b5e4426fbd72e8d80513c3b Mon Sep 17 00:00:00 2001 From: jcosborn Date: Tue, 18 Aug 2020 01:23:19 -0500 Subject: [PATCH 1027/4254] fix overloading issue with generic invocation (#15135) * fix overloading issue with generic alias * add test for inheritance depth --- compiler/sigmatch.nim | 15 +------ tests/overload/toverload_various.nim | 60 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 786cca01f..1d648c32a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -579,7 +579,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if f.isMetaType: # We are matching a generic proc (as proc param) # to another generic type appearing in the proc - # signature. There is a change that the target + # signature. There is a chance that the target # type is already fully-determined, so we are # going to try resolve it if c.call != nil: @@ -1496,7 +1496,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, #echo "inferred ", typeToString(inst), " for ", f return typeRel(c, inst, a) - var depth = 0 if x.kind == tyGenericInvocation or f[0].kind != tyGenericBody: #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") # simply no match for now: @@ -1510,18 +1509,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # Workaround for regression #4589 if f[i].kind != tyTypeDesc: return result = isGeneric - elif x.kind == tyGenericInst and isGenericSubtype(c, x, f, depth, f) and - (x.len - 1 == f.len): - # do not recurse here in order to not K bind twice for this code: - # - # type - # BaseFruit[T] = object of RootObj - # Banana[T] = object of BaseFruit[uint32] # Concrete type here, not T! - # proc setColor[K](self: var BaseFruit[K]) - # var x: Banana[float64] - # x.setColor() - c.inheritancePenalty += depth - result = isGeneric else: let genericBody = f[0] var askip = skippedNone diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 96cb9a736..e8a0108e3 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -375,3 +375,63 @@ block: test(c) var d: FooBarBazX test(d) + + +# overloading on tuples with generic alias +block: + type + Foo[F,T] = object + exArgs: T + FooUn[F,T] = Foo[F,tuple[a:T]] + FooBi[F,T1,T2] = Foo[F,tuple[a:T1,b:T2]] + + proc foo1[F,T](x: Foo[F,tuple[a:T]]): int = 1 + proc foo1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2 + proc foo2[F,T](x: FooUn[F,T]): int = 1 + proc foo2[F,T1,T2](x: FooBi[F,T1,T2]):int = 2 + + template bar1[F,T](x: Foo[F,tuple[a:T]]): int = 1 + template bar1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2 + template bar2[F,T](x: FooUn[F,T]): int = 1 + template bar2[F,T1,T2](x: FooBi[F,T1,T2]): int = 2 + + proc test(x: any, n: int) = + doAssert(foo1(x) == n) + doAssert(foo2(x) == n) + doAssert(bar1(x) == n) + doAssert(bar2(x) == n) + + var a: Foo[int, tuple[a:int]] + test(a, 1) + var b: FooUn[int, int] + test(b, 1) + var c: Foo[int, tuple[a:int,b:int]] + test(c, 2) + var d: FooBi[int, int, int] + test(d, 2) + + +# inheritance depth +block: + type + Foo[T] = object of RootObj + x: T + Bar[T] = object of Foo[T] + y: T + Baz[T] = object of Bar[T] + z: T + + template t0[T](x: Foo[T]): int = 0 + template t0[T](x: Bar[T]): int = 1 + proc p0[T](x: Foo[T]): int = 0 + proc p0[T](x: Bar[T]): int = 1 + + var a: Foo[int] + var b: Bar[int] + var c: Baz[int] + doAssert(t0(a) == 0) + doAssert(t0(b) == 1) + doAssert(t0(c) == 1) + doAssert(p0(a) == 0) + doAssert(p0(b) == 1) + doAssert(p0(c) == 1) From ddff13f01b4704dbe22d8b6c86a606675a1700b0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 18 Aug 2020 12:45:22 +0200 Subject: [PATCH 1028/4254] better strict funcs, WIP (#15199) * better strict funcs, WIP * progress --- compiler/types.nim | 2 +- compiler/varpartitions.nim | 26 +++++++++++++++++++++----- lib/impure/nre.nim | 6 ++++-- lib/pure/mimetypes.nim | 3 ++- lib/pure/strtabs.nim | 13 ++++++++----- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 3545b0703..b8452c3ea 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -543,7 +543,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = else: result = "" of tyBuiltInTypeClass: - result = case t.base.kind: + result = case t.base.kind of tyVar: "var" of tyRef: "ref" of tyPtr: "ptr" diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 6857e1b57..fd6751cdf 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -14,7 +14,8 @@ ## The used data structure is "union find" with path compression. import ast, types, lineinfos, options, msgs, renderer -from trees import getMagic +from trees import getMagic, whichPragma +from wordrecg import wNoSideEffect from isolation_check import canAlias type @@ -48,7 +49,7 @@ type s: seq[VarIndex] graphs: seq[MutationInfo] unanalysableMutation, performCursorInference: bool - inAsgnSource, inConstructor: int + inAsgnSource, inConstructor, inNoSideEffectSection: int proc `$`*(config: ConfigRef; g: MutationInfo): string = result = "" @@ -336,12 +337,15 @@ proc deps(c: var Partitions; dest, src: PNode) = var targets, sources: seq[PSym] allRoots(dest, targets) allRoots(src, sources) + + proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} + let destIsComplex = types.searchTypeFor(dest.typ, wrap) + for t in targets: if dest.kind != nkSym: potentialMutation(c, t, dest.info) - proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} - if types.searchTypeFor(t.typ, wrap): + if destIsComplex: for s in sources: connect(c, t, s, dest.info) @@ -399,7 +403,8 @@ proc traverse(c: var Partitions; n: PNode) = var roots: seq[PSym] allRoots(it, roots) if paramType.kind == tyVar: - for r in roots: potentialMutation(c, r, it.info) + if c.inNoSideEffectSection == 0: + for r in roots: potentialMutation(c, r, it.info) else: for r in roots: noCursor(c, r) @@ -434,6 +439,17 @@ proc traverse(c: var Partitions; n: PNode) = # test arc/topt_no_cursor.nim noCursor(c, it.sym) + of nkPragmaBlock: + let pragmaList = n[0] + var enforceNoSideEffects = 0 + for i in 0.. 0, "ext argument can not be empty string" assert mimetype.strip.len > 0, "mimetype argument can not be empty string" - mimedb.mimes[ext.toLowerAscii()] = mimetype.toLowerAscii() + {.noSideEffect.}: + mimedb.mimes[ext.toLowerAscii()] = mimetype.toLowerAscii() runnableExamples: static: diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 676e8eb1d..4c2dd1451 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -252,7 +252,7 @@ proc `[]=`*(t: StringTableRef, key, val: string) {. inc(t.counter) proc newStringTable*(mode: StringTableMode): owned(StringTableRef) {. - rtlFunc, extern: "nst$1".} = + rtlFunc, extern: "nst$1", noSideEffect.} = ## Creates a new empty string table. ## ## See also: @@ -265,7 +265,7 @@ proc newStringTable*(mode: StringTableMode): owned(StringTableRef) {. proc newStringTable*(keyValuePairs: varargs[string], mode: StringTableMode): owned(StringTableRef) {. - rtlFunc, extern: "nst$1WithPairs".} = + rtlFunc, extern: "nst$1WithPairs", noSideEffect.} = ## Creates a new string table with given `key, value` string pairs. ## ## `StringTableMode` must be specified. @@ -276,12 +276,13 @@ proc newStringTable*(keyValuePairs: varargs[string], result = newStringTable(mode) var i = 0 while i < high(keyValuePairs): - result[keyValuePairs[i]] = keyValuePairs[i + 1] + {.noSideEffect.}: + result[keyValuePairs[i]] = keyValuePairs[i + 1] inc(i, 2) proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]], mode: StringTableMode = modeCaseSensitive): owned(StringTableRef) {. - rtlFunc, extern: "nst$1WithTableConstr".} = + rtlFunc, extern: "nst$1WithTableConstr", noSideEffect.} = ## Creates a new string table with given `(key, value)` tuple pairs. ## ## The default mode is case sensitive. @@ -291,7 +292,9 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]], mytab2 = newStringTable([("key3", "val3"), ("key4", "val4")]) result = newStringTable(mode) - for key, val in items(keyValuePairs): result[key] = val + for key, val in items(keyValuePairs): + {.noSideEffect.}: + result[key] = val proc raiseFormatException(s: string) = raise newException(ValueError, "format string: key not found: " & s) From 8a004e2fc07c87b8308c3c03e4448372a2094383 Mon Sep 17 00:00:00 2001 From: Elijah Shaw-Rutschman Date: Tue, 18 Aug 2020 11:02:10 -0500 Subject: [PATCH 1029/4254] Add test coverage for atomics (#15193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add test coverage for atomics Signed-off-by: Elijah Shaw-Rutschman * Fix compareExchange bugs for non-trivial objects Bugs fixed: 1. compareExchange would not set the desired value in the success case. 2. compareExchange would not set var expected to the found value in the failure case. 3. withLock would spin forever running the unit tests. try..body..finally prevents this. Not sure why this makes a difference, since an exception wasn’t being raised, but clearing the guard in a finally block seems correct anyways. Signed-off-by: Elijah Shaw-Rutschman --- lib/pure/concurrency/atomics.nim | 14 +- tests/stdlib/concurrency/tatomics.nim | 609 ++++++++++++++++++++++++++ 2 files changed, 616 insertions(+), 7 deletions(-) create mode 100644 tests/stdlib/concurrency/tatomics.nim diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index 29491f68c..eaa811aa6 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -326,8 +326,10 @@ else: template withLock[T: not Trivial](location: var Atomic[T]; order: MemoryOrder; body: untyped): untyped = while location.guard.testAndSet(moAcquire): discard - body - location.guard.clear(moRelease) + try: + body + finally: + location.guard.clear(moRelease) proc load*[T: not Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} = withLock(location, order): @@ -345,16 +347,14 @@ else: proc compareExchange*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} = withLock(location, success): if location.nonAtomicValue != expected: + expected = location.nonAtomicValue return false + expected = desired swap(location.nonAtomicValue, expected) return true proc compareExchangeWeak*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; success, failure: MemoryOrder): bool {.inline.} = - withLock(location, success): - if location.nonAtomicValue != expected: - return false - swap(location.nonAtomicValue, expected) - return true + compareExchange(location, expected, desired, success, failure) proc compareExchange*[T: not Trivial](location: var Atomic[T]; expected: var T; desired: T; order: MemoryOrder = moSequentiallyConsistent): bool {.inline.} = compareExchange(location, expected, desired, order, order) diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim new file mode 100644 index 000000000..260d00990 --- /dev/null +++ b/tests/stdlib/concurrency/tatomics.nim @@ -0,0 +1,609 @@ +# test atomic operations + +import atomics, bitops + +type + Object = object + val: int + + +# Atomic operations for trivial objects + + +block trivialLoad: + var location: Atomic[int] + location.store(1) + doAssert location.load == 1 + location.store(2) + doAssert location.load(moRelaxed) == 2 + location.store(3) + doAssert location.load(moAcquire) == 3 + + +block trivialStore: + var location: Atomic[int] + location.store(1) + doAssert location.load == 1 + location.store(2, moRelaxed) + doAssert location.load == 2 + location.store(3, moRelease) + doAssert location.load == 3 + + +block trivialExchange: + var location: Atomic[int] + location.store(1) + doAssert location.exchange(2) == 1 + doAssert location.exchange(3, moRelaxed) == 2 + doAssert location.exchange(4, moAcquire) == 3 + doAssert location.exchange(5, moRelease) == 4 + doAssert location.exchange(6, moAcquireRelease) == 5 + doAssert location.load == 6 + + +block trivialCompareExchangeDoesExchange: + var location: Atomic[int] + var expected = 1 + location.store(1) + doAssert location.compareExchange(expected, 2) + doAssert expected == 1 + doAssert location.load == 2 + expected = 2 + doAssert location.compareExchange(expected, 3, moRelaxed) + doAssert expected == 2 + doAssert location.load == 3 + expected = 3 + doAssert location.compareExchange(expected, 4, moAcquire) + doAssert expected == 3 + doAssert location.load == 4 + expected = 4 + doAssert location.compareExchange(expected, 5, moRelease) + doAssert expected == 4 + doAssert location.load == 5 + expected = 5 + doAssert location.compareExchange(expected, 6, moAcquireRelease) + doAssert expected == 5 + doAssert location.load == 6 + + +block trivialCompareExchangeDoesNotExchange: + var location: Atomic[int] + var expected = 10 + location.store(1) + doAssert not location.compareExchange(expected, 2) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 3, moRelaxed) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 4, moAcquire) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 5, moRelease) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 6, moAcquireRelease) + doAssert expected == 1 + doAssert location.load == 1 + + +block trivialCompareExchangeSuccessFailureDoesExchange: + var location: Atomic[int] + var expected = 1 + location.store(1) + doAssert location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == 1 + doAssert location.load == 2 + expected = 2 + doAssert location.compareExchange(expected, 3, moRelaxed, moRelaxed) + doAssert expected == 2 + doAssert location.load == 3 + expected = 3 + doAssert location.compareExchange(expected, 4, moAcquire, moAcquire) + doAssert expected == 3 + doAssert location.load == 4 + expected = 4 + doAssert location.compareExchange(expected, 5, moRelease, moRelease) + doAssert expected == 4 + doAssert location.load == 5 + expected = 5 + doAssert location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease) + doAssert expected == 5 + doAssert location.load == 6 + + +block trivialCompareExchangeSuccessFailureDoesNotExchange: + var location: Atomic[int] + var expected = 10 + location.store(1) + doAssert not location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 3, moRelaxed, moRelaxed) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 4, moAcquire, moAcquire) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 5, moRelease, moRelease) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease) + doAssert expected == 1 + doAssert location.load == 1 + + +block trivialCompareExchangeWeakDoesExchange: + var location: Atomic[int] + var expected = 1 + location.store(1) + doAssert location.compareExchangeWeak(expected, 2) + doAssert expected == 1 + doAssert location.load == 2 + expected = 2 + doAssert location.compareExchangeWeak(expected, 3, moRelaxed) + doAssert expected == 2 + doAssert location.load == 3 + expected = 3 + doAssert location.compareExchangeWeak(expected, 4, moAcquire) + doAssert expected == 3 + doAssert location.load == 4 + expected = 4 + doAssert location.compareExchangeWeak(expected, 5, moRelease) + doAssert expected == 4 + doAssert location.load == 5 + expected = 5 + doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease) + doAssert expected == 5 + doAssert location.load == 6 + + +block trivialCompareExchangeWeakDoesNotExchange: + var location: Atomic[int] + var expected = 10 + location.store(1) + doAssert not location.compareExchangeWeak(expected, 2) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 3, moRelaxed) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 4, moAcquire) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 5, moRelease) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease) + doAssert expected == 1 + doAssert location.load == 1 + + +block trivialCompareExchangeWeakSuccessFailureDoesExchange: + var location: Atomic[int] + var expected = 1 + location.store(1) + doAssert location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == 1 + doAssert location.load == 2 + expected = 2 + doAssert location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed) + doAssert expected == 2 + doAssert location.load == 3 + expected = 3 + doAssert location.compareExchangeWeak(expected, 4, moAcquire, moAcquire) + doAssert expected == 3 + doAssert location.load == 4 + expected = 4 + doAssert location.compareExchangeWeak(expected, 5, moRelease, moRelease) + doAssert expected == 4 + doAssert location.load == 5 + expected = 5 + doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease) + doAssert expected == 5 + doAssert location.load == 6 + + +block trivialCompareExchangeWeakSuccessFailureDoesNotExchange: + var location: Atomic[int] + var expected = 10 + location.store(1) + doAssert not location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 4, moAcquire, moAcquire) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 5, moRelease, moRelease) + doAssert expected == 1 + doAssert location.load == 1 + expected = 10 + doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease) + doAssert expected == 1 + doAssert location.load == 1 + + +# Atomic operations for non-trivial objects + + +block objectLoad: + var location: Atomic[Object] + location.store(Object(val: 1)) + doAssert location.load == Object(val: 1) + location.store(Object(val: 2)) + doAssert location.load(moRelaxed) == Object(val: 2) + location.store(Object(val: 3)) + doAssert location.load(moAcquire) == Object(val: 3) + + +block objectStore: + var location: Atomic[Object] + location.store(Object(val: 1)) + doAssert location.load == Object(val: 1) + location.store(Object(val: 2), moRelaxed) + doAssert location.load == Object(val: 2) + location.store(Object(val: 3), moRelease) + doAssert location.load == Object(val: 3) + + +block objectExchange: + var location: Atomic[Object] + location.store(Object(val: 1)) + doAssert location.exchange(Object(val: 2)) == Object(val: 1) + doAssert location.exchange(Object(val: 3), moRelaxed) == Object(val: 2) + doAssert location.exchange(Object(val: 4), moAcquire) == Object(val: 3) + doAssert location.exchange(Object(val: 5), moRelease) == Object(val: 4) + doAssert location.exchange(Object(val: 6), moAcquireRelease) == Object(val: 5) + doAssert location.load == Object(val: 6) + + +block objectCompareExchangeDoesExchange: + var location: Atomic[Object] + var expected = Object(val: 1) + location.store(Object(val: 1)) + doAssert location.compareExchange(expected, Object(val: 2)) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 2) + expected = Object(val: 2) + doAssert location.compareExchange(expected, Object(val: 3), moRelaxed) + doAssert expected == Object(val: 2) + doAssert location.load == Object(val: 3) + expected = Object(val: 3) + doAssert location.compareExchange(expected, Object(val: 4), moAcquire) + doAssert expected == Object(val: 3) + doAssert location.load == Object(val: 4) + expected = Object(val: 4) + doAssert location.compareExchange(expected, Object(val: 5), moRelease) + doAssert expected == Object(val: 4) + doAssert location.load == Object(val: 5) + expected = Object(val: 5) + doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease) + doAssert expected == Object(val: 5) + doAssert location.load == Object(val: 6) + + +block objectCompareExchangeDoesNotExchange: + var location: Atomic[Object] + var expected = Object(val: 10) + location.store(Object(val: 1)) + doAssert not location.compareExchange(expected, Object(val: 2)) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 4), moAcquire) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 5), moRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + + +block objectCompareExchangeSuccessFailureDoesExchange: + var location: Atomic[Object] + var expected = Object(val: 1) + location.store(Object(val: 1)) + doAssert location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 2) + expected = Object(val: 2) + doAssert location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed) + doAssert expected == Object(val: 2) + doAssert location.load == Object(val: 3) + expected = Object(val: 3) + doAssert location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire) + doAssert expected == Object(val: 3) + doAssert location.load == Object(val: 4) + expected = Object(val: 4) + doAssert location.compareExchange(expected, Object(val: 5), moRelease, moRelease) + doAssert expected == Object(val: 4) + doAssert location.load == Object(val: 5) + expected = Object(val: 5) + doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease) + doAssert expected == Object(val: 5) + doAssert location.load == Object(val: 6) + + +block objectCompareExchangeSuccessFailureDoesNotExchange: + var location: Atomic[Object] + var expected = Object(val: 10) + location.store(Object(val: 1)) + doAssert not location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 5), moRelease, moRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + + +block objectCompareExchangeWeakDoesExchange: + var location: Atomic[Object] + var expected = Object(val: 1) + location.store(Object(val: 1)) + doAssert location.compareExchangeWeak(expected, Object(val: 2)) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 2) + expected = Object(val: 2) + doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed) + doAssert expected == Object(val: 2) + doAssert location.load == Object(val: 3) + expected = Object(val: 3) + doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire) + doAssert expected == Object(val: 3) + doAssert location.load == Object(val: 4) + expected = Object(val: 4) + doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease) + doAssert expected == Object(val: 4) + doAssert location.load == Object(val: 5) + expected = Object(val: 5) + doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease) + doAssert expected == Object(val: 5) + doAssert location.load == Object(val: 6) + + +block objectCompareExchangeWeakDoesNotExchange: + var location: Atomic[Object] + var expected = Object(val: 10) + location.store(Object(val: 1)) + doAssert not location.compareExchangeWeak(expected, Object(val: 2)) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + + +block objectCompareExchangeWeakSuccessFailureDoesExchange: + var location: Atomic[Object] + var expected = Object(val: 1) + location.store(Object(val: 1)) + doAssert location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 2) + expected = Object(val: 2) + doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed) + doAssert expected == Object(val: 2) + doAssert location.load == Object(val: 3) + expected = Object(val: 3) + doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire) + doAssert expected == Object(val: 3) + doAssert location.load == Object(val: 4) + expected = Object(val: 4) + doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease) + doAssert expected == Object(val: 4) + doAssert location.load == Object(val: 5) + expected = Object(val: 5) + doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease) + doAssert expected == Object(val: 5) + doAssert location.load == Object(val: 6) + + +block objectCompareExchangeWeakSuccessFailureDoesNotExchange: + var location: Atomic[Object] + var expected = Object(val: 10) + location.store(Object(val: 1)) + doAssert not location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + expected = Object(val: 10) + doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease) + doAssert expected == Object(val: 1) + doAssert location.load == Object(val: 1) + + +# Numerical operations + + +block fetchAdd: + var location: Atomic[int] + doAssert location.fetchAdd(1) == 0 + doAssert location.fetchAdd(1, moRelaxed) == 1 + doAssert location.fetchAdd(1, moRelease) == 2 + doAssert location.load == 3 + + +block fetchSub: + var location: Atomic[int] + doAssert location.fetchSub(1) == 0 + doAssert location.fetchSub(1, moRelaxed) == -1 + doAssert location.fetchSub(1, moRelease) == -2 + doAssert location.load == -3 + + +block fetchAnd: + var location: Atomic[int] + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchAnd(j) == i) + doAssert(location.load == i.bitand(j)) + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchAnd(j, moRelaxed) == i) + doAssert(location.load == i.bitand(j)) + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchAnd(j, moRelease) == i) + doAssert(location.load == i.bitand(j)) + + +block fetchOr: + var location: Atomic[int] + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchOr(j) == i) + doAssert(location.load == i.bitor(j)) + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchOr(j, moRelaxed) == i) + doAssert(location.load == i.bitor(j)) + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchOr(j, moRelease) == i) + doAssert(location.load == i.bitor(j)) + + +block fetchXor: + var location: Atomic[int] + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchXor(j) == i) + doAssert(location.load == i.bitxor(j)) + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchXor(j, moRelaxed) == i) + doAssert(location.load == i.bitxor(j)) + + for i in 0..16: + for j in 0..16: + location.store(i) + doAssert(location.fetchXor(j, moRelease) == i) + doAssert(location.load == i.bitxor(j)) + + +block atomicInc: + var location: Atomic[int] + location.atomicInc + doAssert location.load == 1 + location.atomicInc(1) + doAssert location.load == 2 + location += 1 + doAssert location.load == 3 + + +block atomicDec: + var location: Atomic[int] + location.atomicDec + doAssert location.load == -1 + location.atomicDec(1) + doAssert location.load == -2 + location -= 1 + doAssert location.load == -3 + + +# Flag operations + + +block testAndSet: + var location: AtomicFlag + doAssert not location.testAndSet + doAssert location.testAndSet + doAssert location.testAndSet + location.clear() + doAssert not location.testAndSet(moRelaxed) + doAssert location.testAndSet(moRelaxed) + doAssert location.testAndSet(moRelaxed) + location.clear() + doAssert not location.testAndSet(moRelease) + doAssert location.testAndSet(moRelease) + doAssert location.testAndSet(moRelease) + + +block clear: + var location: AtomicFlag + discard location.testAndSet + location.clear + doAssert not location.testAndSet + location.clear(moRelaxed) + doAssert not location.testAndSet + location.clear(moRelease) + doAssert not location.testAndSet From 66eba3388aacba20c49b925c9c700f988fb9e5d0 Mon Sep 17 00:00:00 2001 From: John Dupuy Date: Sat, 22 Aug 2020 05:00:38 -0500 Subject: [PATCH 1030/4254] Added more SSL documentation to `net` module. (#15206) * Added more SSL documentation to `net` module. * Changed two of the net.nim doc refs to links. * Update lib/pure/net.nim doc wording. Co-authored-by: Dominik Picheta * Update lib/pure/net.nim - added space to doc URI Co-authored-by: alaviss * Fixed another doc URI in net module. * For net module doc added warning to connect procedure. * Update net.nim Co-authored-by: Dominik Picheta Co-authored-by: alaviss --- lib/pure/net.nim | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ea1c86c31..239e3e9f6 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -20,7 +20,9 @@ ## ==== ## ## In order to use the SSL procedures defined in this module, you will need to -## compile your application with the ``-d:ssl`` flag. +## compile your application with the ``-d:ssl`` flag. See the +## `newContext`_ +## procedure for additional details. ## ## Examples ## ======== @@ -36,9 +38,17 @@ ## var socket = newSocket() ## socket.connect("google.com", Port(80)) ## +## For SSL, use the following example (and make sure to compile with ``-d:ssl``): +## +## .. code-block:: Nim +## var socket = newSocket() +## var ctx = newContext() +## wrapSocket(ctx, socket) +## socket.connect("google.com", Port(443)) +## ## UDP is a connectionless protocol, so UDP sockets don't have to explicitly -## call the ``connect`` procedure. They can simply start sending data -## immediately. +## call the `connect `_ procedure. They can +## simply start sending data immediately. ## ## .. code-block:: Nim ## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) @@ -1942,6 +1952,10 @@ proc connect*(socket: Socket, address: string, port = Port(0), ## ## The ``timeout`` parameter specifies the time in milliseconds to allow for ## the connection to the server to be made. + ## + ## **Warning:** This procedure appears to be broken for SSL connections as of + ## Nim v1.0.2. Consider using the other `connect` procedure. See + ## https://github.com/nim-lang/Nim/issues/15215 for more info. socket.fd.setBlocking(false) socket.connectAsync(address, port, socket.domain) From 9bae1ed205875dee7fd58cf1d740db0d70130228 Mon Sep 17 00:00:00 2001 From: wltsmrz Date: Sat, 22 Aug 2020 17:14:50 -0400 Subject: [PATCH 1031/4254] Unsigned iovlen (#15216) --- lib/posix/posix_macos_amd64.nim | 2 +- lib/posix/posix_nintendoswitch.nim | 2 +- lib/posix/posix_openbsd_amd64.nim | 2 +- lib/posix/posix_other.nim | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 33f2c5c41..94c08acad 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -411,7 +411,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: int ## The size of the memory pointed to by iov_base. + iov_len*: csize_t ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr diff --git a/lib/posix/posix_nintendoswitch.nim b/lib/posix/posix_nintendoswitch.nim index d1cc042ea..44e431437 100644 --- a/lib/posix/posix_nintendoswitch.nim +++ b/lib/posix/posix_nintendoswitch.nim @@ -371,7 +371,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: csize ## The size of the memory pointed to by iov_base. + iov_len*: csize_t ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 4f34791fe..584d06501 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -398,7 +398,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: int ## The size of the memory pointed to by iov_base. + iov_len*: csize_t ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 59ae9c8f7..ed058d5cf 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -421,7 +421,7 @@ type IOVec* {.importc: "struct iovec", pure, final, header: "".} = object ## struct iovec iov_base*: pointer ## Base address of a memory region for input or output. - iov_len*: int ## The size of the memory pointed to by iov_base. + iov_len*: csize_t ## The size of the memory pointed to by iov_base. Tmsghdr* {.importc: "struct msghdr", pure, final, header: "".} = object ## struct msghdr From 575697e1f4d94cfe080edb28f88ce8982b8add54 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 23 Aug 2020 02:48:37 -0500 Subject: [PATCH 1032/4254] doc/nimdoc.css: align field names to the right (#15217) --- doc/nimdoc.css | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 6025d6601..fb9efd858 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -582,6 +582,7 @@ table th { table th.docinfo-name { background-color: transparent; + text-align: right; } table tr:hover { From 07d82b5cc4b7ba177de43a3eb46c7c645930421a Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Mon, 24 Aug 2020 08:05:17 +0200 Subject: [PATCH 1033/4254] Use more `lent` in options (#15208) --- lib/pure/options.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index d56cf4767..4efe04d67 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -363,14 +363,14 @@ proc `$`*[T](self: Option[T]): string = else: result = "None[" & name(T) & "]" -proc unsafeGet*[T](self: Option[T]): T {.inline.}= +proc unsafeGet*[T](self: Option[T]): lent T {.inline.}= ## Returns the value of a `some`. Behavior is undefined for `none`. ## ## **Note:** Use it only when you are **absolutely sure** the value is present ## (e.g. after checking `isSome <#isSome,Option[T]>`_). ## Generally, using `get proc <#get,Option[T]>`_ is preferred. assert self.isSome - self.val + result = self.val when isMainModule: From 8321617a7845f01f1e60e0b00f275345b15845e9 Mon Sep 17 00:00:00 2001 From: Jon Date: Mon, 24 Aug 2020 14:33:51 +0800 Subject: [PATCH 1034/4254] fix in doc: incomplete output (#15222) [ci skip] --- lib/pure/collections/tables.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 017a2f337..6d79638c2 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -131,7 +131,7 @@ ## let myString = "abracadabra" ## let letterFrequencies = toCountTable(myString) ## echo letterFrequencies -## # 'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2} +## # output: {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2} ## ## The same could have been achieved by manually iterating over a container ## and increasing each key's value with `inc proc From 5651a2f711ae0ce3eb86400646ca2b7e9ab2988a Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 24 Aug 2020 13:44:19 +0200 Subject: [PATCH 1035/4254] PRs with no activity in last year are marked as stale --- .github/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index 7825ad58d..c175f64a0 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 730 +daysUntilStale: 365 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. From 15ff89cec14ea6d1bc05a5975dedfcb6e712720b Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 25 Aug 2020 09:57:15 +0200 Subject: [PATCH 1036/4254] [backport] fix #15064, strscans.scanf edge case for '$+' (#15223) --- lib/pure/strscans.nim | 2 +- tests/stdlib/tstrscans.nim | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 0125a1926..f078b0d20 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -396,7 +396,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b var resLen = genSym(nskLet, "resLen") conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", inp, results[i], newLit(token), idx)) - conds.add newCall(bindSym"!=", resLen, newLit min) + conds.add newCall(bindSym">=", resLen, newLit min) conds.add resLen else: matchError diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index 08fc14e45..6f952368c 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -79,8 +79,22 @@ block EmptyTuple: block Arrow: let text = "foo;bar;baz;" var idx = 0 - var res = "" doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false + + +block issue15064: + var nick1, msg1: string + doAssert scanf(" a", "<$+> $+", nick1, msg1) + doAssert nick1 == "abcd" + doAssert msg1 == "a" + + var nick2, msg2: string + doAssert(not scanf(" ", "<$+> $+", nick2, msg2)) + + var nick3, msg3: string + doAssert scanf(" ", "<$+> $*", nick3, msg3) + doAssert nick3 == "abcd" + doAssert msg3 == "" From 7cee63bba3805bd49f0c03b94d65f02dea04f946 Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 25 Aug 2020 15:58:32 +0800 Subject: [PATCH 1037/4254] avoid #8231, bitwise move to mul,div (#15070) * avoid #8231, bitwise move to mul,div * add test for #8231 * fix bitwise move when div result is float * bitwise move depends on typ.size --- compiler/jsgen.nim | 12 ++++++++++-- tests/js/t8231.nim | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/js/t8231.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ede4d14e0..bea5225e6 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -602,8 +602,16 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mMulF64: applyFormat("($1 * $2)", "($1 * $2)") of mDivF64: applyFormat("($1 / $2)", "($1 / $2)") of mShrI: applyFormat("", "") - of mShlI: applyFormat("($1 << $2)", "($1 << $2)") - of mAshrI: applyFormat("($1 >> $2)", "($1 >> $2)") + of mShlI: + if n[1].typ.size <= 4: + applyFormat("($1 << $2)", "($1 << $2)") + else: + applyFormat("($1 * Math.pow(2,$2))", "($1 * Math.pow(2,$2))") + of mAshrI: + if n[1].typ.size <= 4: + applyFormat("($1 >> $2)", "($1 >> $2)") + else: + applyFormat("Math.floor($1 / Math.pow(2,$2))", "Math.floor($1 / Math.pow(2,$2))") of mBitandI: applyFormat("($1 & $2)", "($1 & $2)") of mBitorI: applyFormat("($1 | $2)", "($1 | $2)") of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)") diff --git a/tests/js/t8231.nim b/tests/js/t8231.nim new file mode 100644 index 000000000..b0625a621 --- /dev/null +++ b/tests/js/t8231.nim @@ -0,0 +1,3 @@ +import strutils + +doAssert formatSize(2462056448, '.', bpIEC, false) == "2.293GiB" \ No newline at end of file From 5163fe7d878f48870c6d0235d70d45e1e414dca8 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 25 Aug 2020 15:59:42 +0200 Subject: [PATCH 1038/4254] remove deprecation from `math.round` (#15224) --- changelog.md | 7 +++++++ lib/pure/math.nim | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index eebccb62f..3865f1efb 100644 --- a/changelog.md +++ b/changelog.md @@ -164,7 +164,14 @@ echo foo ``` +- Proc `math.round` is no longer deprecated. The advice to use `strformat` instead + cannot be applied to every use case. The limitations and the (lack of) reliability + of `round` are well documented. + + + ## Language changes + - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts `wasMoved` calls where needed. - In the newruntime it is now allowed to assign to the discriminator field diff --git a/lib/pure/math.nim b/lib/pure/math.nim index c02bef2f7..21d614270 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -768,8 +768,7 @@ else: # JS ## ( 6.5 mod -2.5) == 1.5 ## (-6.5 mod -2.5) == -1.5 -proc round*[T: float32|float64](x: T, places: int): T {. - deprecated: "use strformat module instead".} = +proc round*[T: float32|float64](x: T, places: int): T = ## Decimal rounding on a binary floating point number. ## ## This function is NOT reliable. Floating point numbers cannot hold From 71025b8a8f4ebbb58555de74565ce006a9c17444 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 20 Aug 2020 12:47:07 +0200 Subject: [PATCH 1039/4254] deleted dead code, writetracking.nim was replaced by varpartitions.nim --- compiler/writetracking.nim | 275 ------------------------------------- 1 file changed, 275 deletions(-) delete mode 100644 compiler/writetracking.nim diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim deleted file mode 100644 index 44ef3a937..000000000 --- a/compiler/writetracking.nim +++ /dev/null @@ -1,275 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements the write tracking analysis. Read my block post for -## a basic description of the algorithm and ideas. -## The algorithm operates in 2 phases: -## -## * Collecting information about assignments (and pass-by-var calls). -## * Computing an aliasing relation based on the assignments. This relation -## is then used to compute the 'writes' and 'escapes' effects. - -import intsets, idents, ast, trees, msgs, types, options, lineinfos - -const - debug = false - -type - AssignToResult = enum - asgnNil, # 'nil' is fine - asgnNew, # 'new(result)' - asgnOther # result = fooBar # not a 'new' --> 'result' might not 'new' - NewLocation = enum - newNone, - newLit, - newCall - RootInfo = enum - rootIsResultOrParam, - rootIsHeapAccess, - rootIsSym, - markAsWrittenTo, - markAsEscaping - - Assignment = object # \ - # Note that the transitive closures MUST be computed in - # phase 2 of the algorithm. - dest, src: seq[ptr TSym] # we use 'ptr' here to save RC ops and GC cycles - destNoTc, srcNoTc: int # length of 'dest', 'src' without the - # transitive closure - destInfo: set[RootInfo] - info: TLineInfo - - W = object # WriteTrackContext - owner: PSym - returnsNew: AssignToResult # assignments to 'result' - assignments: seq[Assignment] # list of all assignments in this proc - -proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) = - case n.kind - of nkSym: - if n.sym.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}: - if n.sym.kind in {skResult, skParam}: incl(info, rootIsResultOrParam) - result.add(cast[ptr TSym](n.sym)) - of nkHiddenDeref, nkDerefExpr: - incl(info, rootIsHeapAccess) - allRoots(n[0], result, info) - of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr, - nkHiddenAddr, nkObjUpConv, nkObjDownConv: - allRoots(n[0], result, info) - of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv, - nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch, - nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast: - allRoots(n.lastSon, result, info) - of nkCallKinds: - if getMagic(n) == mSlice: - allRoots(n[1], result, info) - else: - # we do significantly better here by using the available escape - # information: - if n[0].typ.isNil: return - var typ = n[0].typ - if typ != nil: - typ = skipTypes(typ, abstractInst) - if typ.kind != tyProc: typ = nil - else: assert(typ.len == typ.n.len) - - for i in 1.. 0 and a.dest[0] == x and rootIsSym in a.destInfo: - # x = f(..., y, ....) - for i in 0.. Date: Wed, 26 Aug 2020 14:31:00 +0200 Subject: [PATCH 1040/4254] fixes #15207 [backport:1.2] --- lib/pure/terminal.nim | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 99a333cc6..968d6bd9a 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -776,25 +776,20 @@ when defined(windows): ## ``true`` otherwise. password.string.setLen(0) stdout.write(prompt) - while true: - let c = getch() - case c.char - of '\r', chr(0xA): - break - of '\b': - # ensure we delete the whole UTF-8 character: - var i = 0 - var x = 1 - while i < password.len: - x = runeLenAt(password.string, i) - inc i, x - password.string.setLen(max(password.len - x, 0)) - of chr(0x0): - # modifier key - ignore - for details see - # https://github.com/nim-lang/Nim/issues/7764 - continue - else: - password.string.add(toUTF8(c.Rune)) + let hi = createFileA("CONIN$", + GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0) + var mode = DWORD 0 + discard getConsoleMode(hi, addr mode) + let origMode = mode + const + ENABLE_PROCESSED_INPUT = 1 + ENABLE_ECHO_INPUT = 4 + mode = (mode or ENABLE_PROCESSED_INPUT) and not ENABLE_ECHO_INPUT + + discard setConsoleMode(hi, mode) + result = readLine(stdin, password) + discard setConsoleMode(hi, origMode) + discard closeHandle(hi) stdout.write "\n" else: From d85015e9225a0747453a1bd9a8b6f292f5bfe3af Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 26 Aug 2020 11:51:41 -0300 Subject: [PATCH 1041/4254] Remove unroll pragma from stdlib (#14706) --- lib/packages/docutils/highlite.nim | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 796c17d7d..df74dd980 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -651,19 +651,16 @@ proc yamlNextToken(g: var GeneralTokenizer) = of 'x': inc(pos) for i in 1..2: - {.unroll.} if g.buf[pos] in hexChars: inc(pos) break of 'u': inc(pos) for i in 1..4: - {.unroll.} if g.buf[pos] in hexChars: inc(pos) break of 'U': inc(pos) for i in 1..8: - {.unroll.} if g.buf[pos] in hexChars: inc(pos) break else: inc(pos) @@ -802,7 +799,6 @@ proc yamlNextToken(g: var GeneralTokenizer) = if pos == 0 or g.buf[pos - 1] in {'\x0A', '\x0D'}: inc(pos) for i in 1..2: - {.unroll.} if g.buf[pos] != '.': break inc(pos) if pos == g.start + 3: From a9a9860b0b5171487fae100010a18ad71f5d5f6d Mon Sep 17 00:00:00 2001 From: Scott Wadden Date: Wed, 26 Aug 2020 15:00:54 -0300 Subject: [PATCH 1042/4254] Raise KeyError if passed an invalid row entry (#15227) --- lib/pure/parsecsv.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 607702fc0..2c0dbb802 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -322,24 +322,29 @@ proc rowEntry*(my: var CsvParser, entry: string): var string = ## ## Assumes that `readHeaderRow <#readHeaderRow,CsvParser>`_ has already been ## called. + ## + ## If specified `entry` does not exist, raises KeyError. runnableExamples: import streams var strm = newStringStream("One,Two,Three\n1,2,3\n\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") - ## Need calling `readHeaderRow`. + ## Requires calling `readHeaderRow`. parser.readHeaderRow() doAssert parser.readRow() doAssert parser.rowEntry("One") == "1" doAssert parser.rowEntry("Two") == "2" doAssert parser.rowEntry("Three") == "3" - ## `parser.rowEntry("NotExistEntry")` causes SIGSEGV fault. + doAssertRaises(KeyError): + discard parser.rowEntry("NonexistentEntry") parser.close() strm.close() let index = my.headers.find(entry) if index >= 0: result = my.row[index] + else: + raise newException(KeyError, "Entry `" & entry & "` doesn't exist") when not defined(testing) and isMainModule: import os From ccccd30cf6b8704c224e42001d0def2b566d5388 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 27 Aug 2020 11:25:20 +0200 Subject: [PATCH 1043/4254] fixes #15221 (#15230) --- lib/impure/nre.nim | 2 +- lib/pure/typetraits.nim | 90 ++++++++++++++++++++--------------------- 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 88fa0b323..71936bd5f 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -367,7 +367,7 @@ func contains*(pattern: CaptureBounds, name: string): bool = func contains*(pattern: Captures, name: string): bool = name in CaptureBounds(pattern) -func checkNamedCaptured(pattern: RegexMatch, name: string): void = +func checkNamedCaptured(pattern: RegexMatch, name: string) = if not (name in pattern.captureBounds): raise newException(KeyError, "Group '" & name & "' was not captured") diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 0e23077ac..0a05b5ded 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -115,54 +115,52 @@ macro genericParamsImpl(T: typedesc): untyped = impl = impl[1] while true: case impl.kind - of nnkSym: - impl = impl.getImpl - continue - of nnkTypeDef: - impl = impl[2] - continue - of nnkTypeOfExpr: - impl = getTypeInst(impl[0]) - continue - of nnkBracketExpr: - for i in 1.. Date: Thu, 27 Aug 2020 05:56:38 -0500 Subject: [PATCH 1044/4254] fix some issues overloading with generics and inheritance (#15211) * fix some issues overloading with generics and inheritance * fix passing procs with subtype matches --- compiler/sigmatch.nim | 45 +++++++++++++++++++++------- tests/overload/toverload_various.nim | 36 ++++++++++++++++++---- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 1d648c32a..8700d9a47 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -199,6 +199,27 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) = a.baseTypeMatch = b.baseTypeMatch copyIdTable(a.bindings, b.bindings) +proc typeRel*(c: var TCandidate, f, aOrig: PType, + flags: TTypeRelFlags = {}): TTypeRelation + +proc checkGeneric(a, b: TCandidate): int = + let c = a.c + let aa = a.callee + let bb = b.callee + var winner = 0 + for i in 1.. tyGenericInvocation") - # simply no match for now: - discard + if x.kind == tyGenericInvocation: + if f[0] == x[0]: + for i in 1.. Date: Thu, 27 Aug 2020 15:50:59 +0200 Subject: [PATCH 1045/4254] Fix #5691 (#15158) * Fix #5691 * Cleanup and thoughts * Use scope approach * Seperate defined/declared/declaredInScope magics * Fix declaredInScope * Update spec accordingly --- compiler/ast.nim | 2 +- compiler/condsyms.nim | 1 + compiler/lookups.nim | 22 +++++++++++ compiler/sem.nim | 13 +++---- compiler/semcall.nim | 4 -- compiler/semexprs.nim | 42 +++++++++++---------- compiler/semgnrc.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/sigmatch.nim | 26 ++++++------- doc/manual.rst | 25 ++++--------- lib/system.nim | 41 +++++++++++--------- tests/macros/tmacros_various.nim | 15 ++++++++ tests/macros/tmacrotypes.nim | 2 + tests/template/tparams_gensymed.nim | 58 +++++++++++++++++++++++++++++ tests/template/tparamscope.nim | 10 +++++ 15 files changed, 180 insertions(+), 85 deletions(-) create mode 100644 tests/template/tparamscope.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 62c1e3894..06ff92e9f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -617,7 +617,7 @@ var type TMagic* = enum # symbols that require compiler magic: mNone, - mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn, + mDefined, mDeclared, mDeclaredInScope, mCompiles, mArrGet, mArrPut, mAsgn, mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index b7f7100f1..ad13f3e1e 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -119,3 +119,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasStacktraceMsgs") defineSymbol("nimDoesntTrackDefects") defineSymbol("nimHasLentIterators") + defineSymbol("nimHasDeclaredMagic") diff --git a/compiler/lookups.nim b/compiler/lookups.nim index a3a2bf49c..c0db25950 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -93,6 +93,11 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym = proc localSearchInScope*(c: PContext, s: PIdent): PSym = result = strTableGet(c.currentScope.symbols, s) + var shadow = c.currentScope + while result == nil and shadow.parent != nil and shadow.depthLevel == shadow.parent.depthLevel: + # We are in a shadow scope, check in the parent too + result = strTableGet(shadow.parent.symbols, s) + shadow = shadow.parent proc searchInScopes*(c: PContext, s: PIdent): PSym = for scope in walkScopes(c.currentScope): @@ -231,6 +236,23 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) = addOverloadableSymAt(c, scope, sym) addInterfaceDeclAux(c, sym) +proc openShadowScope*(c: PContext) = + c.currentScope = PScope(parent: c.currentScope, + symbols: newStrTable(), + depthLevel: c.scopeDepth) + +proc closeShadowScope*(c: PContext) = + c.closeScope + +proc mergeShadowScope*(c: PContext) = + let shadowScope = c.currentScope + c.rawCloseScope + for sym in shadowScope.symbols: + if sym.kind in OverloadableSyms: + c.addInterfaceOverloadableSymAt(c.currentScope, sym) + else: + c.addInterfaceDecl(sym) + when defined(nimfix): # when we cannot find the identifier, retry with a changed identifier: proc altSpelling(x: PIdent): PIdent = diff --git a/compiler/sem.nim b/compiler/sem.nim index a07f62ca0..07c76eed4 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -383,12 +383,10 @@ when not defined(nimHasSinkInference): include hlo, seminst, semcall -when false: - # hopefully not required: - proc resetSemFlag(n: PNode) = - excl n.flags, nfSem - for i in 0.. 1: m.callee.n[1].sym else: nil while a < n.len: + + c.openShadowScope + if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: formal = m.callee.n[f].sym incl(marker, formal.position) @@ -2383,12 +2385,10 @@ proc matchesAux(c: PContext, n, nOrig: PNode, if n[a][0].kind != nkIdent: localError(c.config, n[a].info, "named parameter has to be an identifier") noMatch() - return formal = getNamedParamFromList(m.callee.n, n[a][0].ident) if formal == nil: # no error message! noMatch() - return if containsOrIncl(marker, formal.position): m.firstMismatch.kind = kAlreadyGiven # already in namedParams, so no match @@ -2397,7 +2397,6 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # different parameter names could match later on): when false: localError(n[a].info, errCannotBindXTwice, formal.name.s) noMatch() - return m.baseTypeMatch = false m.typedescMatched = false n[a][1] = prepareOperand(c, formal.typ, n[a][1]) @@ -2407,7 +2406,6 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m.firstMismatch.kind = kTypeMismatch if arg == nil: noMatch() - return checkConstraint(n[a][1]) if m.baseTypeMatch: #assert(container == nil) @@ -2448,16 +2446,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode, checkConstraint(n[a]) else: noMatch() - return else: m.firstMismatch.kind = kExtraArg noMatch() - return else: if m.callee.n[f].kind != nkSym: internalError(c.config, n[a].info, "matches") noMatch() - return formal = m.callee.n[f].sym m.firstMismatch.kind = kTypeMismatch if containsOrIncl(marker, formal.position) and container.isNil: @@ -2465,7 +2460,6 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # positional param already in namedParams: (see above remark) when false: localError(n[a].info, errCannotBindXTwice, formal.name.s) noMatch() - return if formal.typ.isVarargsUntyped: if container.isNil: @@ -2482,7 +2476,6 @@ proc matchesAux(c: PContext, n, nOrig: PNode, n[a], nOrig[a]) if arg == nil: noMatch() - return if m.baseTypeMatch: assert formal.typ.kind == tyVarargs #assert(container == nil) @@ -2511,8 +2504,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode, localError(c.config, n[a].info, "cannot convert $1 to $2" % [ typeToString(n[a].typ), typeToString(formal.typ) ]) noMatch() - return checkConstraint(n[a]) + + if m.state == csMatch and not(m.calleeSym != nil and m.calleeSym.kind in {skTemplate, skMacro}): + c.mergeShadowScope + else: + c.closeShadowScope + inc(a) # for some edge cases (see tdont_return_unowned_from_owned test case) m.firstMismatch.arg = a @@ -2544,7 +2542,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = if m.state == csNoMatch: return # check that every formal parameter got a value: for f in 1..`_ - ## - ## This can be used to check whether a library provides a certain - ## feature or not: - ## - ## .. code-block:: Nim - ## when not declared(strutils.toUpper): - ## # provide our own toUpper proc here, because strutils is - ## # missing it. +when defined(nimHasDeclaredMagic): + proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} + ## Special compile-time procedure that checks whether `x` is + ## declared. `x` has to be an identifier or a qualified identifier. + ## + ## See also: + ## * `declaredInScope <#declaredInScope,untyped>`_ + ## + ## This can be used to check whether a library provides a certain + ## feature or not: + ## + ## .. code-block:: Nim + ## when not declared(strutils.toUpper): + ## # provide our own toUpper proc here, because strutils is + ## # missing it. +else: + proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} -proc declaredInScope*(x: untyped): bool {. - magic: "DefinedInScope", noSideEffect, compileTime.} - ## Special compile-time procedure that checks whether `x` is - ## declared in the current scope. `x` has to be an identifier. +when defined(nimHasDeclaredMagic): + proc declaredInScope*(x: untyped): bool {.magic: "DeclaredInScope", noSideEffect, compileTime.} + ## Special compile-time procedure that checks whether `x` is + ## declared in the current scope. `x` has to be an identifier. +else: + proc declaredInScope*(x: untyped): bool {.magic: "DefinedInScope", noSideEffect, compileTime.} proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory location. diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 3cb5aaa8f..64bb7345a 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -22,6 +22,7 @@ a[1]: 45 x: some string ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) +0 ''' """ @@ -222,3 +223,17 @@ block getImplTransformed: doAssert "toExpand" notin code # template is expanded (but that would already be the case with # `a.getImpl.repr`, unlike the other transformations mentioned above + + +# test macro resemming +macro makeVar(): untyped = + quote: + var tensorY {.inject.}: int + +macro noop(a: typed): untyped = + a + +noop: + makeVar +echo tensorY + diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim index cfc4ef7fb..43819c81d 100644 --- a/tests/macros/tmacrotypes.nim +++ b/tests/macros/tmacrotypes.nim @@ -43,6 +43,8 @@ macro checkType(ex: typed): untyped = echo ex.getTypeInst.repr, "; ", ex.typeKind, "; ", ex.getType.repr, "; ", ex.getTypeImpl.repr macro checkProcType(fn: typed): untyped = + if fn.kind == nnkProcDef: + result = fn let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index 2a1fda41a..1444667f4 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -336,3 +336,61 @@ test(hello): var data = 5 hello(data) + +# bug #5691 + +template bar(x: typed) = discard +macro barry(x: typed) = discard + +var a = 0 + +bar: + var a = 10 + +barry: + var a = 20 + +bar: + var b = 10 + +barry: + var b = 20 + +var b = 30 + +# template bar(x: static int) = discard +#You may think that this should work: +# bar((var c = 1; echo "hey"; c)) +# echo c +#But it must not! Since this would be incorrect: +# bar((var b = 3; const c = 1; echo "hey"; c)) +# echo b # <- b wouldn't exist + +discard not (let xx = 1; true) +discard xx + +template barrel(a: typed): untyped = a + +barrel: + var aa* = 1 + var bb = 3 + export bb + +# Test declaredInScope within params +template test1: untyped = + when not declaredInScope(thing): + var thing {.inject.}: int + +proc chunkedReadLoop = + test1 + test1 + +template test2: untyped = + when not not not declaredInScope(thing): + var thing {.inject.}: int + +proc chunkedReadLoop2 = + test2 + test2 + +test1(); test2() diff --git a/tests/template/tparamscope.nim b/tests/template/tparamscope.nim new file mode 100644 index 000000000..177c682cf --- /dev/null +++ b/tests/template/tparamscope.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "undeclared identifier: 'a'" + line: 10 +""" + + +template secondArg(a, b: typed): untyped = + b + +echo secondArg((var a = 1; 1), a) From f8c48fc1863a243718acf86b699baed1a5c1512e Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 28 Aug 2020 16:57:52 +0100 Subject: [PATCH 1046/4254] fix #15035 (#15236) --- compiler/injectdestructors.nim | 5 +++-- tests/arc/t14383.nim | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index bac47b3d6..fcaa3c76a 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -699,8 +699,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = elif n.kind in {nkObjDownConv, nkObjUpConv}: result = copyTree(n) result[0] = p(n[0], c, s, sinkArg) - elif n.typ == nil: - # 'raise X' can be part of a 'case' expression. Deal with it here: + elif n.typ == nil or n.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyVar}).kind == tyOpenArray: + # 'raise X' can be part of a 'case' expression. Deal with it here. + # openarrays require perfect forwarding result = p(n, c, s, normal) else: # copy objects that are not temporary but passed to a 'sink' parameter diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim index 115cbf426..742088937 100644 --- a/tests/arc/t14383.nim +++ b/tests/arc/t14383.nim @@ -3,6 +3,7 @@ discard """ output: ''' hello hello +@[4, 3, 2, 1] ''' """ @@ -11,3 +12,18 @@ import dmodule var val = parseMinValue() if val.kind == minDictionary: echo val + + +#------------------------------------------------------------------------------ +# Issue #15035 +#------------------------------------------------------------------------------ + +proc countRun(lst: sink openArray[int]): int = + discard + +proc timSort(lst: var openArray[int]) = + let run = countRun(lst) + +var a = @[4, 3, 2, 1] +timSort(a) +echo a \ No newline at end of file From 13e659cfec83eb3c2c3c2bbbf10d01ba59bc0d5b Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 28 Aug 2020 22:18:09 +0200 Subject: [PATCH 1047/4254] Big compiler Cleanup (#14777) --- compiler/ast.nim | 34 ++- compiler/btrees.nim | 3 +- compiler/ccgexprs.nim | 2 +- compiler/ccgmerge.nim | 6 +- compiler/ccgstmts.nim | 2 +- compiler/cgen.nim | 2 +- compiler/closureiters.nim | 3 - compiler/commands.nim | 21 +- compiler/condsyms.nim | 2 +- compiler/docgen.nim | 45 ++-- compiler/extccomp.nim | 4 +- compiler/filter_tmpl.nim | 8 +- compiler/forloops.nim | 89 -------- compiler/injectdestructors.nim | 6 +- compiler/int128.nim | 6 +- compiler/layouter.nim | 6 +- compiler/lexer.nim | 157 ++++++-------- compiler/liftdestructors.nim | 5 - compiler/linter.nim | 16 +- compiler/main.nim | 4 +- compiler/modulepaths.nim | 6 +- compiler/modules.nim | 2 +- compiler/msgs.nim | 9 +- compiler/nimconf.nim | 34 +-- compiler/nimlexbase.nim | 10 +- compiler/options.nim | 6 +- compiler/packagehandling.nim | 2 - compiler/parampatterns.nim | 4 +- compiler/parser.nim | 369 ++++++++++++++++----------------- compiler/passes.nim | 6 +- compiler/pragmas.nim | 6 +- compiler/renderer.nim | 28 +-- compiler/renderverbatim.nim | 2 +- compiler/reorder.nim | 27 +-- compiler/rodutils.nim | 6 +- compiler/semexprs.nim | 2 +- compiler/semfold.nim | 2 +- compiler/seminst.nim | 2 +- compiler/semobjconstr.nim | 3 +- compiler/semtempl.nim | 1 - compiler/semtypes.nim | 6 +- compiler/semtypinst.nim | 3 +- compiler/sighashes.nim | 2 +- compiler/sigmatch.nim | 51 ++--- compiler/sourcemap.nim | 8 +- compiler/suggest.nim | 2 +- compiler/syntaxes.nim | 128 ++++-------- compiler/types.nim | 2 +- compiler/vmgen.nim | 21 +- compiler/wordrecg.nim | 74 ++----- nimpretty/nimpretty.nim | 12 +- tools/grammar_nanny.nim | 4 +- tools/nimfind.nim | 3 +- 53 files changed, 481 insertions(+), 783 deletions(-) delete mode 100644 compiler/forloops.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 06ff92e9f..23b564af3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -17,22 +17,21 @@ export int128 type TCallingConvention* = enum - ccNimCall, # nimcall, also the default - ccStdCall, # procedure is stdcall - ccCDecl, # cdecl - ccSafeCall, # safecall - ccSysCall, # system call - ccInline, # proc should be inlined - ccNoInline, # proc should not be inlined - ccFastCall, # fastcall (pass parameters in registers) - ccThisCall, # thiscall (parameters are pushed right-to-left) - ccClosure, # proc has a closure + ccNimCall # nimcall, also the default + ccStdCall # procedure is stdcall + ccCDecl # cdecl + ccSafeCall # safecall + ccSysCall # system call + ccInline # proc should be inlined + ccNoInline # proc should not be inlined + ccFastCall # fastcall (pass parameters in registers) + ccThisCall # thiscall (parameters are pushed right-to-left) + ccClosure # proc has a closure ccNoConvention # needed for generating proper C procs sometimes -const - CallingConvToStr*: array[TCallingConvention, string] = ["nimcall", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", - "closure", "noconv"] +const CallingConvToStr*: array[TCallingConvention, string] = ["nimcall", "stdcall", + "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", + "closure", "noconv"] type TNodeKind* = enum # order is extremely important, because ranges are used @@ -1363,7 +1362,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType = proc mergeLoc(a: var TLoc, b: TLoc) = if a.k == low(a.k): a.k = b.k if a.storage == low(a.storage): a.storage = b.storage - a.flags = a.flags + b.flags + a.flags.incl b.flags if a.lode == nil: a.lode = b.lode if a.r == nil: a.r = b.r @@ -1388,7 +1387,7 @@ proc assignType*(dest, src: PType) = # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: - dest.sym.flags = dest.sym.flags + (src.sym.flags-{sfExported}) + dest.sym.flags.incl src.sym.flags-{sfExported} if dest.sym.annex == nil: dest.sym.annex = src.sym.annex mergeLoc(dest.sym.loc, src.sym.loc) else: @@ -1495,8 +1494,7 @@ proc isGCedMem*(t: PType): bool {.inline.} = t.kind == tyProc and t.callConv == ccClosure proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = - const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc} - owner.flags = owner.flags + (elem.flags * {tfHasMeta, tfTriggersCompileTime}) + owner.flags.incl elem.flags * {tfHasMeta, tfTriggersCompileTime} if tfNotNil in elem.flags: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: owner.flags.incl tfNotNil diff --git a/compiler/btrees.nim b/compiler/btrees.nim index 18854d474..473cbd1b0 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -135,8 +135,7 @@ proc `$`[Key, Val](b: BTree[Key, Val]): string = result = "" toString(b.root, "", result) -proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool = - result = index < b.entries +proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool = index < b.entries proc countSubTree[Key, Val](it: Node[Key, Val]): int = if it.isInternal: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a97d15d70..995b75d69 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1653,7 +1653,7 @@ template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = var a: TLoc initLocExpr(p, n[1], a) a.r = ropecg(p.module, frmt, [rdLoc(a)]) - a.flags = a.flags - {lfIndirect} # this flag should not be propagated here (not just for HCR) + a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR) if d.k == locNone: getTemp(p, n.typ, d) genAssignment(p, d, a, {}) gcUsage(p.config, n) diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index c12d6c0b2..a87d5b609 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -282,7 +282,7 @@ proc mergeRequired*(m: BModule): bool = if m.s[i] != nil: #echo "not empty: ", i, " ", m.s[i] return true - for i in low(TCProcSection)..high(TCProcSection): + for i in TCProcSection: if m.initProc.s(i) != nil: #echo "not empty: ", i, " ", m.initProc.s[i] return true @@ -292,7 +292,7 @@ proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) = var old: TMergeSections readMergeSections(cfilename, old) # do the merge; old section before new section: - for i in low(TCFileSection)..high(TCFileSection): + for i in TCFileSection: m.s[i] = old.f[i] & m.s[i] - for i in low(TCProcSection)..high(TCProcSection): + for i in TCProcSection: m.initProc.s(i) = old.p[i] & m.initProc.s(i) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 0f58df3a4..e40e94d01 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1498,7 +1498,7 @@ proc genPragma(p: BProc, n: PNode) = of wEmit: genEmit(p, it) of wInjectStmt: var p = newProc(nil, p.module) - p.options = p.options - {optLineTrace, optStackTrace} + p.options.excl {optLineTrace, optStackTrace} genStmts(p, it[1]) p.module.injectStmt = p.s(cpsStmts) else: discard diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 86860fbf4..d40aa32d7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -681,7 +681,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = [loadlib, genStringLiteral(m, lib.path)]) else: var p = newProc(nil, m) - p.options = p.options - {optStackTrace} + p.options.excl optStackTrace p.flags.incl nimErrorFlagDisabled var dest: TLoc initLoc(dest, locTemp, lib.path, OnStack) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 2248f956e..912172e62 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -485,7 +485,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = if ns: needsSplit = true var tmp: PSym - var s: PNode let isExpr = not isEmptyType(n.typ) if isExpr: tmp = ctx.newTempVar(n.typ) @@ -742,8 +741,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = result.add(n) of nkWhileStmt: - var ns = false - var condNeedsSplit = false n[0] = ctx.lowerStmtListExprs(n[0], condNeedsSplit) var bodyNeedsSplit = false diff --git a/compiler/commands.nim b/compiler/commands.nim index b67cd461f..0af31b2c7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -53,11 +53,10 @@ const "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} = - var x = "" - for f in low(T)..high(T): - if x.len > 0: x.add "|" - x.add $f - x + result = "" + for f in T: + if result.len > 0: result.add "|" + result.add $f const Usage = slurp"../doc/basicopt.txt".replace(" //", " ") @@ -146,24 +145,24 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "","on": conf.options = conf.options + op - of "off": conf.options = conf.options - op + of "","on": conf.options.incl op + of "off": conf.options.excl op else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo): bool = result = false case arg.normalize - of "on": conf.options = conf.options + op - of "off": conf.options = conf.options - op + of "on": conf.options.incl op + of "off": conf.options.excl op of "list": result = true else: localError(conf, info, errOnOffOrListExpectedButXFound % arg) proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "", "on": conf.globalOptions = conf.globalOptions + op - of "off": conf.globalOptions = conf.globalOptions - op + of "", "on": conf.globalOptions.incl op + of "off": conf.globalOptions.excl op else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ad13f3e1e..d99b8b7e6 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -86,7 +86,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimMacrosSizealignof") defineSymbol("nimNoZeroExtendMagic") defineSymbol("nimMacrosGetNodeId") - for f in low(Feature)..high(Feature): + for f in Feature: defineSymbol("nimHas" & $f) for s in WarningsToStr: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index cb8c77e87..1e0756d64 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -302,15 +302,13 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr, proc genComment(d: PDoc, n: PNode): string = result = "" - var dummyHasToc: bool if n.comment.len > 0: - var comment2 = n.comment + let comment = n.comment when false: # RFC: to preseve newlines in comments, this would work: - comment2 = comment2.replace("\n", "\n\n") - renderRstToOut(d[], parseRst(comment2, toFullPath(d.conf, n.info), - toLinenumber(n.info), toColumn(n.info), - dummyHasToc, d.options, d.conf), result) + comment = comment.replace("\n", "\n\n") + renderRstToOut(d[], parseRst(comment, toFullPath(d.conf, n.info), toLinenumber(n.info), + toColumn(n.info), (var dummy: bool; dummy), d.options, d.conf), result) proc genRecCommentAux(d: PDoc, n: PNode): Rope = if n == nil: return nil @@ -342,11 +340,10 @@ proc getPlainDocstring(n: PNode): string = ## You need to call this before genRecComment, whose side effects are removal ## of comments from the tree. The proc will recursively scan and return all ## the concatenated ``##`` comments of the node. - result = "" - if n == nil: return - if startsWith(n.comment, "##"): + if n == nil: result = "" + elif startsWith(n.comment, "##"): result = n.comment - if result.len < 1: + else: for i in 0.. 0: return @@ -458,7 +455,6 @@ proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) = d.exampleGroups[rdoccmd].code.add "import r\"$1\"\n" % outp.string proc runAllExamples(d: PDoc) = - let backend = d.conf.backend # This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however # using `-d:js` (etc) cannot work properly, eg would fail with `importjs` # since semantics are affected by `config.backend`, not by isDefined(d.conf, "js") @@ -522,20 +518,6 @@ proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = for imp in imports: runnableExamples.add imp runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon) -proc renderNimCodeOld(d: PDoc, n: PNode, dest: var Rope) = - ## this is a rather hacky way to get rid of the initial indentation - ## that the renderer currently produces: - # deadcode - var i = 0 - var body = n.lastSon - if body.len == 1 and body.kind == nkStmtList and - body.lastSon.kind == nkStmtList: - body = body.lastSon - for b in body: - if i > 0: dest.add "\n" - inc i - nodeToHighlightedHtml(d, b, dest, {renderRunnableExamples}, nil) - type RunnableState = enum rsStart rsComment @@ -575,12 +557,9 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: Runnab inc d.listingCounter let id = $d.listingCounter dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"]) - when true: - var dest2 = "" - renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) - dest.add dest2 - else: - renderNimCodeOld(d, n, dest) + var dest2 = "" + renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) + dest.add dest2 dest.add(d.config.getOrDefault"doc.listing_end" % id) return rsRunnable else: discard @@ -1213,12 +1192,12 @@ proc genOutFile(d: PDoc): Rope = var tmp = "" renderTocEntries(d[], j, 1, tmp) var toc = tmp.rope - for i in low(TSymKind)..high(TSymKind): + for i in TSymKind: genSection(d, i) toc.add(d.toc[i]) if toc != nil: toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc]) - for i in low(TSymKind)..high(TSymKind): code.add(d.section[i]) + for i in TSymKind: code.add(d.section[i]) # Extract the title. Non API modules generate an entry in the index table. if d.meta[metaTitle].len != 0: diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 1c6b1a8d0..79b4ba637 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -331,7 +331,7 @@ proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) = conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always") conf.linkOptions = "" conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path") - for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name) + for c in CC: undefSymbol(conf.symbols, c.name) defineSymbol(conf.symbols, CC[conf.cCompiler].name) proc addOpt(dest: var string, src: string) = @@ -353,7 +353,7 @@ proc addCompileOptionCmd*(conf: ConfigRef; option: string) = proc initVars*(conf: ConfigRef) = # we need to define the symbol here, because ``CC`` may have never been set! - for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name) + for c in CC: undefSymbol(conf.symbols, c.name) defineSymbol(conf.symbols, CC[conf.cCompiler].name) addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always")) #addLinkOption(getConfigVar(cCompiler, ".options.linker")) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 1d95369a8..6165ff2f3 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -199,8 +199,8 @@ proc parseLine(p: var TTmplParser) = inc(j) llStreamWrite(p.outp, "\\n\"") -proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile, - call: PNode; conf: ConfigRef): PLLStream = +proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile, + call: PNode): PLLStream = var p: TTmplParser p.config = conf p.info = newLineInfo(conf, filename, 0, 0) @@ -214,9 +214,9 @@ proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile, p.x = newStringOfCap(120) # do not process the first line which contains the directive: if llStreamReadLine(p.inp, p.x): - p.info.line = p.info.line + 1'u16 + inc p.info.line while llStreamReadLine(p.inp, p.x): - p.info.line = p.info.line + 1'u16 + inc p.info.line parseLine(p) newLine(p) result = p.outp diff --git a/compiler/forloops.nim b/compiler/forloops.nim deleted file mode 100644 index ee91000d4..000000000 --- a/compiler/forloops.nim +++ /dev/null @@ -1,89 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements for loop detection for better C code generation. - -import ast, astalgo - -const - someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, - mLeI, mLeF64, mLeU, mLeEnum, - mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtEnum, - mLtCh, mLtB, mLtPtr} - -proc isCounter(s: PSym): bool {.inline.} = - s.kind in {skResult, skVar, skLet, skTemp} and - {sfGlobal, sfAddrTaken} * s.flags == {} - -proc isCall(n: PNode): bool {.inline.} = - n.kind in nkCallKinds and n[0].kind == nkSym - -proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags - -proc getCounter(lastStmt: PNode): PSym = - if lastStmt.isCall: - let op = lastStmt.sym - if op.magic in {mDec, mInc} or - ((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem): - if op[1].kind == nkSym and isCounter(op[1].sym): - result = op[1].sym - -proc counterInTree(n, loop: PNode; counter: PSym): bool = - # prune the search tree: within the loop the counter may be used: - if n == loop: return - case n.kind - of nkSym: - if n.sym == counter: return true - of nkVarSection, nkLetSection: - # definitions are fine! - for it in n: - if counterInTree(it.lastSon): return true - else: - for i in 0..= denominator: - dividend = dividend - denominator + dividend -= denominator quotient = bitor(quotient, One) denominator = denominator shr 1 diff --git a/compiler/layouter.nim b/compiler/layouter.nim index f5d3084dc..ee45d357f 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -35,7 +35,7 @@ type Emitter* = object config: ConfigRef fid: FileIndex - lastTok: TTokType + lastTok: TokType inquote, lastTokWasTerse: bool semicolons: SemicolonKind col, lastLineNumber, lineSpan, indentLevel, indWidth*, inSection: int @@ -402,7 +402,7 @@ proc endsInAlpha(em: Emitter): bool = while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i) result = if i >= 0: em.tokens[i].lastChar in SymChars+{'_'} else: false -proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) = +proc emitComment(em: var Emitter; tok: Token; dontIndent: bool) = var col = em.col let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB) em.lineSpan = countNewlines(lit) @@ -417,7 +417,7 @@ proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) = inc col emitMultilineComment(em, lit, col, dontIndent) -proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = +proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = template wasExportMarker(em): bool = em.kinds.len > 0 and em.kinds[^1] == ltExportMarker diff --git a/compiler/lexer.nim b/compiler/lexer.nim index f9679adee..ff433928c 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -30,7 +30,7 @@ const # don't forget to update the 'highlite' module if these charsets should change type - TTokType* = enum + TokType* = enum tkInvalid, tkEof, # order is important here! tkSymbol, # keywords: tkAddr, tkAnd, tkAs, tkAsm, @@ -64,7 +64,7 @@ type tkOpr, tkComment, tkAccent, tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr - TTokTypes* = set[TTokType] + TokTypes* = set[TokType] const weakTokens = {tkComma, tkSemiColon, tkColon, @@ -73,7 +73,7 @@ const # tokens that should not be considered for previousToken tokKeywordLow* = succ(tkSymbol) tokKeywordHigh* = pred(tkIntLit) - TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]", + TokTypeToStr*: array[TokType, string] = ["tkInvalid", "[EOF]", "tkSymbol", "addr", "and", "as", "asm", "bind", "block", "break", "case", "cast", @@ -104,22 +104,19 @@ const "tkPrefixOpr", "tkPostfixOpr"] type - TNumericalBase* = enum + NumericalBase* = enum base10, # base10 is listed as the first element, # so that it is the correct default value base2, base8, base16 - CursorPosition* {.pure.} = enum ## XXX remove this again - None, InToken, BeforeToken, AfterToken - - TToken* = object # a Nim token - tokType*: TTokType # the type of the token + Token* = object # a Nim token + tokType*: TokType # the type of the token indent*: int # the indentation; != -1 if the token has been # preceded with indentation ident*: PIdent # the parsed identifier iNumber*: BiggestInt # the parsed integer literal fNumber*: BiggestFloat # the parsed floating point literal - base*: TNumericalBase # the numerical base; only valid for int + base*: NumericalBase # the numerical base; only valid for int # or float literals strongSpaceA*: int8 # leading spaces of an operator strongSpaceB*: int8 # trailing spaces of an operator @@ -127,26 +124,25 @@ type # documentation comments are here too line*, col*: int when defined(nimpretty): - offsetA*, offsetB*: int # used for pretty printing so that literals - # like 0b01 or r"\L" are unaffected + offsetA*, offsetB*: int # used for pretty printing so that literals + # like 0b01 or r"\L" are unaffected commentOffsetA*, commentOffsetB*: int - TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) - TLexer* = object of TBaseLexer + ErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) + Lexer* = object of TBaseLexer fileIdx*: FileIndex indentAhead*: int # if > 0 an indentation has already been read # this is needed because scanning comments # needs so much look-ahead currLineIndent*: int strongSpaces*, allowTabs*: bool - cursor*: CursorPosition - errorHandler*: TErrorHandler + errorHandler*: ErrorHandler cache*: IdentCache when defined(nimsuggest): previousToken: TLineInfo config*: ConfigRef -proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = +proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} = result = newLineInfo(L.fileIdx, tok.line, tok.col) when defined(nimpretty): result.offsetA = tok.offsetA @@ -154,8 +150,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = result.commentOffsetA = tok.commentOffsetA result.commentOffsetB = tok.commentOffsetB -proc isKeyword*(kind: TTokType): bool = - result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) +proc isKeyword*(kind: TokType): bool = + (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion @@ -169,28 +165,27 @@ proc isNimIdentifier*(s: string): bool = inc(i) result = true -proc `$`*(tok: TToken): string = +proc `$`*(tok: Token): string = case tok.tokType - of tkIntLit..tkInt64Lit: result = $tok.iNumber - of tkFloatLit..tkFloat64Lit: result = $tok.fNumber - of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal - of tkParLe..tkColon, tkEof, tkAccent: - result = TokTypeToStr[tok.tokType] + of tkIntLit..tkInt64Lit: $tok.iNumber + of tkFloatLit..tkFloat64Lit: $tok.fNumber + of tkInvalid, tkStrLit..tkCharLit, tkComment: tok.literal + of tkParLe..tkColon, tkEof, tkAccent: TokTypeToStr[tok.tokType] else: if tok.ident != nil: - result = tok.ident.s + tok.ident.s else: - result = "" + "" -proc prettyTok*(tok: TToken): string = - if isKeyword(tok.tokType): result = "keyword " & tok.ident.s - else: result = $tok +proc prettyTok*(tok: Token): string = + if isKeyword(tok.tokType): "keyword " & tok.ident.s + else: $tok -proc printTok*(conf: ConfigRef; tok: TToken) = +proc printTok*(conf: ConfigRef; tok: Token) = msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & TokTypeToStr[tok.tokType] & " " & $tok) -proc initToken*(L: var TToken) = +proc initToken*(L: var Token) = L.tokType = tkInvalid L.iNumber = 0 L.indent = 0 @@ -203,7 +198,7 @@ proc initToken*(L: var TToken) = L.commentOffsetA = 0 L.commentOffsetB = 0 -proc fillToken(L: var TToken) = +proc fillToken(L: var Token) = L.tokType = tkInvalid L.iNumber = 0 L.indent = 0 @@ -216,7 +211,7 @@ proc fillToken(L: var TToken) = L.commentOffsetA = 0 L.commentOffsetB = 0 -proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; +proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = openBaseLexer(lex, inputstream) lex.fileIdx = fileIdx @@ -228,36 +223,36 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; lex.previousToken.fileIndex = fileIdx lex.config = config -proc openLexer*(lex: var TLexer, filename: AbsoluteFile, inputstream: PLLStream; +proc openLexer*(lex: var Lexer, filename: AbsoluteFile, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config) -proc closeLexer*(lex: var TLexer) = +proc closeLexer*(lex: var Lexer) = if lex.config != nil: inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) -proc getLineInfo(L: TLexer): TLineInfo = +proc getLineInfo(L: Lexer): TLineInfo = result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos)) -proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) = +proc dispMessage(L: Lexer; info: TLineInfo; msg: TMsgKind; arg: string) = if L.errorHandler.isNil: msgs.message(L.config, info, msg, arg) else: L.errorHandler(L.config, info, msg, arg) -proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") = +proc lexMessage*(L: Lexer, msg: TMsgKind, arg = "") = L.dispMessage(getLineInfo(L), msg, arg) -proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") = +proc lexMessageTok*(L: Lexer, msg: TMsgKind, tok: Token, arg = "") = var info = newLineInfo(L.fileIdx, tok.line, tok.col) L.dispMessage(info, msg, arg) -proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = +proc lexMessagePos(L: var Lexer, msg: TMsgKind, pos: int, arg = "") = var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart) L.dispMessage(info, msg, arg) -proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = +proc matchTwoChars(L: Lexer, first: char, second: set[char]): bool = result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second) template tokenBegin(tok, pos) {.dirty.} = @@ -271,7 +266,6 @@ template tokenEnd(tok, pos) {.dirty.} = let colB = getColNumber(L, pos)+1 if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: - L.cursor = CursorPosition.InToken L.config.m.trackPos.col = colA.int16 colA = 0 when defined(nimpretty): @@ -296,23 +290,22 @@ template tokenEndPrevious(tok, pos) = let colB = getColNumber(L, pos) if L.fileIdx == L.config.m.trackPos.fileIndex and L.config.m.trackPos.col in colA..colB and L.lineNumber == L.config.m.trackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: - L.cursor = CursorPosition.BeforeToken L.config.m.trackPos = L.previousToken L.config.m.trackPosAttached = true colA = 0 when defined(nimpretty): tok.offsetB = L.offsetBase + pos -template eatChar(L: var TLexer, t: var TToken, replacementChar: char) = +template eatChar(L: var Lexer, t: var Token, replacementChar: char) = t.literal.add(replacementChar) inc(L.bufpos) -template eatChar(L: var TLexer, t: var TToken) = +template eatChar(L: var Lexer, t: var Token) = t.literal.add(L.buf[L.bufpos]) inc(L.bufpos) -proc getNumber(L: var TLexer, result: var TToken) = - proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]): Natural = +proc getNumber(L: var Lexer, result: var Token) = + proc matchUnderscoreChars(L: var Lexer, tok: var Token, chars: set[char]): Natural = var pos = L.bufpos # use registers for pos, buf result = 0 while true: @@ -332,19 +325,19 @@ proc getNumber(L: var TLexer, result: var TToken) = inc(pos) L.bufpos = pos - proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) = + proc matchChars(L: var Lexer, tok: var Token, chars: set[char]) = var pos = L.bufpos # use registers for pos, buf while L.buf[pos] in chars: tok.literal.add(L.buf[pos]) inc(pos) L.bufpos = pos - proc lexMessageLitNum(L: var TLexer, msg: string, startpos: int, msgKind = errGenerated) = + proc lexMessageLitNum(L: var Lexer, msg: string, startpos: int, msgKind = errGenerated) = # Used to get slightly human friendlier err messages. const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O', 'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'} var msgPos = L.bufpos - var t: TToken + var t: Token t.literal = "" L.bufpos = startpos # Use L.bufpos as pos because of matchChars matchChars(L, t, literalishChars) @@ -612,7 +605,7 @@ proc getNumber(L: var TLexer, result: var TToken) = tokenEnd(result, postPos-1) L.bufpos = postPos -proc handleHexChar(L: var TLexer, xi: var int; position: range[0..4]) = +proc handleHexChar(L: var Lexer, xi: var int; position: range[0..4]) = template invalid() = lexMessage(L, errGenerated, "expected a hex digit, but found: " & L.buf[L.bufpos] & @@ -637,7 +630,7 @@ proc handleHexChar(L: var TLexer, xi: var int; position: range[0..4]) = # Need to progress for `nim check` inc(L.bufpos) -proc handleDecChars(L: var TLexer, xi: var int) = +proc handleDecChars(L: var Lexer, xi: var int) = while L.buf[L.bufpos] in {'0'..'9'}: xi = (xi * 10) + (ord(L.buf[L.bufpos]) - ord('0')) inc(L.bufpos) @@ -680,7 +673,7 @@ proc addUnicodeCodePoint(s: var string, i: int) = s[pos+4] = chr(i shr 6 and ones(6) or 0b10_0000_00) s[pos+5] = chr(i and ones(6) or 0b10_0000_00) -proc getEscapedChar(L: var TLexer, tok: var TToken) = +proc getEscapedChar(L: var Lexer, tok: var Token) = inc(L.bufpos) # skip '\' case L.buf[L.bufpos] of 'n', 'N': @@ -760,13 +753,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = else: lexMessage(L, errGenerated, "invalid character constant") else: lexMessage(L, errGenerated, "invalid character constant") -proc newString(s: cstring, len: int): string = - ## XXX, how come there is no support for this? - result = newString(len) - for i in 0.. ord(tokKeywordHigh) - ord(tkSymbol)): tok.tokType = tkSymbol else: - tok.tokType = TTokType(tok.ident.id + ord(tkSymbol)) + tok.tokType = TokType(tok.ident.id + ord(tkSymbol)) if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}: lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s) L.bufpos = pos -proc endOperator(L: var TLexer, tok: var TToken, pos: int, +proc endOperator(L: var Lexer, tok: var Token, pos: int, hash: Hash) {.inline.} = var h = !$hash tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr - else: tok.tokType = TTokType(tok.ident.id - oprLow + ord(tkColon)) + else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon)) L.bufpos = pos -proc getOperator(L: var TLexer, tok: var TToken) = +proc getOperator(L: var Lexer, tok: var Token) = var pos = L.bufpos tokenBegin(tok, pos) var h: Hash = 0 @@ -935,18 +922,15 @@ proc getOperator(L: var TLexer, tok: var TToken) = if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}: tok.strongSpaceB = -1 -proc getPrecedence*(tok: TToken, strongSpaces: bool): int = +proc getPrecedence*(tok: Token): int = ## Calculates the precedence of the given token. - template considerStrongSpaces(x): untyped = - x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0) - case tok.tokType of tkOpr: let relevantChar = tok.ident.s[0] # arrow like? if tok.ident.s.len > 1 and tok.ident.s[^1] == '>' and - tok.ident.s[^2] in {'-', '~', '='}: return considerStrongSpaces(1) + tok.ident.s[^2] in {'-', '~', '='}: return 1 template considerAsgn(value: untyped) = result = if tok.ident.s[^1] == '=': 1 else: value @@ -962,15 +946,13 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int = of '?': result = 2 else: considerAsgn(2) of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs, tkFrom: result = 5 of tkDotDot: result = 6 + of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs, tkFrom: result = 5 of tkAnd: result = 4 of tkOr, tkXor, tkPtr, tkRef: result = 3 else: return -10 - result = considerStrongSpaces(result) - -proc newlineFollows*(L: TLexer): bool = +proc newlineFollows*(L: Lexer): bool = var pos = L.bufpos while true: case L.buf[pos] @@ -986,7 +968,7 @@ proc newlineFollows*(L: TLexer): bool = else: break -proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; +proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; isDoc: bool) = var pos = start var toStrip = 0 @@ -1051,7 +1033,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; when defined(nimpretty): tok.commentOffsetB = L.offsetBase + pos - 1 -proc scanComment(L: var TLexer, tok: var TToken) = +proc scanComment(L: var Lexer, tok: var Token) = var pos = L.bufpos tok.tokType = tkComment # iNumber contains the number of '\n' in the token @@ -1101,7 +1083,7 @@ proc scanComment(L: var TLexer, tok: var TToken) = when defined(nimpretty): tok.commentOffsetB = L.offsetBase + pos - 1 -proc skip(L: var TLexer, tok: var TToken) = +proc skip(L: var Lexer, tok: var Token) = var pos = L.bufpos tokenBegin(tok, pos) tok.strongSpaceA = 0 @@ -1173,7 +1155,7 @@ proc skip(L: var TLexer, tok: var TToken) = tok.tokType = tkComment tok.indent = commentIndent -proc rawGetTok*(L: var TLexer, tok: var TToken) = +proc rawGetTok*(L: var Lexer, tok: var Token) = template atTokenEnd() {.dirty.} = when defined(nimsuggest): # we attach the cursor to the last *strong* token @@ -1181,8 +1163,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = L.previousToken.line = tok.line.uint16 L.previousToken.col = tok.col.int16 - when defined(nimsuggest): - L.cursor = CursorPosition.None fillToken(tok) if L.indentAhead >= 0: tok.indent = L.indentAhead @@ -1253,7 +1233,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = if L.fileIdx == L.config.m.trackPos.fileIndex and tok.col+1 == L.config.m.trackPos.col and tok.line == L.config.m.trackPos.line.int and L.config.ideCmd == ideSug: tok.tokType = tkDot - L.cursor = CursorPosition.InToken L.config.m.trackPos.col = tok.col.int16 inc(L.bufpos) atTokenEnd() @@ -1326,8 +1305,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef): int = - var lex: TLexer - var tok: TToken + var lex: Lexer + var tok: Token initToken(tok) openLexer(lex, fileIdx, inputstream, cache, config) var prevToken = tkEof @@ -1341,11 +1320,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; proc getPrecedence*(ident: PIdent): int = ## assumes ident is binary operator already - var tok: TToken + var tok: Token initToken(tok) tok.ident = ident tok.tokType = if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol): - TTokType(tok.ident.id + ord(tkSymbol)) + TokType(tok.ident.id + ord(tkSymbol)) else: tkOpr - getPrecedence(tok, false) + getPrecedence(tok) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 1e6b552e2..c1fd7981e 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -919,11 +919,6 @@ template inst(field, t) = proc isTrival(s: PSym): bool {.inline.} = s == nil or (s.ast != nil and s.ast[bodyPos].len == 0) - -proc isEmptyContainer(g: ModuleGraph, t: PType): bool = - (t.kind == tyArray and lengthOrd(g.config, t[0]) == 0) or - (t.kind == tySequence and t[0].kind == tyError) - proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo) = ## In the semantic pass this is called in strategic places ## to ensure we lift assignment, destructors and moves properly. diff --git a/compiler/linter.nim b/compiler/linter.nim index 07563ddbb..a229958e6 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -71,12 +71,9 @@ proc beautifyName(s: string, k: TSymKind): string = proc differ*(line: string, a, b: int, x: string): string = proc substrEq(s: string, pos, last: int, substr: string): bool = - var i = 0 - while i < substr.len and pos+i <= last and s[pos+i] == substr[i]: - inc i - return i == substr.len - - let last = min(b, line.len) + result = true + for i in 0.. last or s[pos+i] != substr[i]: return false result = "" if not substrEq(line, a, b, x): @@ -84,11 +81,6 @@ proc differ*(line: string, a, b: int, x: string): string = if cmpIgnoreStyle(y, x) == 0: result = y -proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) = - let beau = beautifyName(s, k) - if s != beau: - lintReport(conf, info, beau, s) - proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = # operators stay as they are: if k in {skResult, skTemp} or s.name.s[0] notin Letters: return @@ -136,6 +128,6 @@ proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) = lintReport(conf, info, newName, oldName) proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = - let wanted = canonPragmaSpelling(w) + let wanted = specialWords[w] if pragmaName != wanted: lintReport(conf, info, wanted, pragmaName) diff --git a/compiler/main.nim b/compiler/main.nim index 256ec14cd..774dd7625 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -163,8 +163,8 @@ proc commandScan(cache: IdentCache, config: ConfigRef) = var stream = llStreamOpen(f, fmRead) if stream != nil: var - L: TLexer - tok: TToken + L: Lexer + tok: Token initToken(tok) openLexer(L, f, stream, cache, config) while true: diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 0c8a4628e..8511b1592 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -91,8 +91,7 @@ when false: if result.len > 0: return result proc scriptableImport(pkg, sub: string; info: TLineInfo): string = - result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) - if result.isNil: result = "" + resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) proc lookupPackage(pkg, subdir: PNode): string = let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" @@ -112,8 +111,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = case n.kind of nkStrLit, nkRStrLit, nkTripleStrLit: try: - result = - pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir) + result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir) except ValueError: localError(conf, n.info, "invalid path: " & n.strVal) result = n.strVal diff --git a/compiler/modules.nim b/compiler/modules.nim index 383858026..8c5b86ea4 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -86,7 +86,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P result = r if result == nil: result = newModule(graph, fileIdx) - result.flags = result.flags + flags + result.flags.incl flags result.id = id registerModule(graph, result) else: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index a5953237e..7e2b8e8a6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -377,15 +377,12 @@ template styledMsgWriteln*(args: varargs[typed]) = when defined(windows): flushFile(stderr) -proc msgKindToString*(kind: TMsgKind): string = +proc msgKindToString*(kind: TMsgKind): string = MsgKindToStr[kind] # later versions may provide translated error messages - result = MsgKindToStr[kind] -proc getMessageStr(msg: TMsgKind, arg: string): string = - result = msgKindToString(msg) % [arg] +proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) % [arg] -type - TErrorHandling* = enum doNothing, doAbort, doRaise +type TErrorHandling* = enum doNothing, doAbort, doRaise proc log*(s: string) = var f: File diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bd00832be..c3591a945 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -16,13 +16,13 @@ import # ---------------- configuration file parser ----------------------------- # we use Nim's scanner here to save space and work -proc ppGetTok(L: var TLexer, tok: var TToken) = +proc ppGetTok(L: var Lexer, tok: var Token) = # simple filter rawGetTok(L, tok) while tok.tokType in {tkComment}: rawGetTok(L, tok) -proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool -proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool = +proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool +proc parseAtom(L: var Lexer, tok: var Token; config: ConfigRef): bool = if tok.tokType == tkParLe: ppGetTok(L, tok) result = parseExpr(L, tok, config) @@ -35,21 +35,21 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool = result = isDefined(config, tok.ident.s) ppGetTok(L, tok) -proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool = +proc parseAndExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool = result = parseAtom(L, tok, config) while tok.tokType == tkAnd: ppGetTok(L, tok) # skip "and" var b = parseAtom(L, tok, config) result = result and b -proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool = +proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool = result = parseAndExpr(L, tok, config) while tok.tokType == tkOr: ppGetTok(L, tok) # skip "or" var b = parseAndExpr(L, tok, config) result = result or b -proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool = +proc evalppIf(L: var Lexer, tok: var Token; config: ConfigRef): bool = ppGetTok(L, tok) # skip 'if' or 'elif' result = parseExpr(L, tok, config) if tok.tokType == tkColon: ppGetTok(L, tok) @@ -57,7 +57,7 @@ proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool = #var condStack: seq[bool] = @[] -proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) = +proc doEnd(L: var Lexer, tok: var Token; condStack: var seq[bool]) = if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if") ppGetTok(L, tok) # skip 'end' setLen(condStack, high(condStack)) @@ -66,21 +66,21 @@ type TJumpDest = enum jdEndif, jdElseEndif -proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef; +proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef; condStack: var seq[bool]) -proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = +proc doElse(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) = if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if") ppGetTok(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok) if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack) -proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = +proc doElif(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) = if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if") var res = evalppIf(L, tok, config) if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config, condStack) else: condStack[high(condStack)] = true -proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef; +proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef; condStack: var seq[bool]) = var nestedIfs = 0 while true: @@ -110,7 +110,7 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co else: ppGetTok(L, tok) -proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = +proc parseDirective(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) = ppGetTok(L, tok) # skip @ case whichKeyword(tok.ident) of wIf: @@ -149,16 +149,16 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack else: lexMessage(L, errGenerated, "invalid directive: '$1'" % $tok) -proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = +proc confTok(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) = ppGetTok(L, tok) while tok.ident != nil and tok.ident.s == "@": parseDirective(L, tok, config, condStack) # else: give the token to the parser -proc checkSymbol(L: TLexer, tok: TToken) = +proc checkSymbol(L: Lexer, tok: Token) = if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}: lexMessage(L, errGenerated, "expected identifier, but got: " & $tok) -proc parseAssignment(L: var TLexer, tok: var TToken; +proc parseAssignment(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) = if tok.ident != nil: if tok.ident.s == "-" or tok.ident.s == "--": @@ -211,8 +211,8 @@ proc parseAssignment(L: var TLexer, tok: var TToken; proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache; config: ConfigRef): bool = var - L: TLexer - tok: TToken + L: Lexer + tok: Token stream: PLLStream stream = llStreamOpen(filename, fmRead) if stream != nil: diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index af2ae64a3..6132e6f66 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -162,9 +162,9 @@ proc getColNumber(L: TBaseLexer, pos: int): int = proc getCurrentLine(L: TBaseLexer, marker: bool = true): string = result = "" var i = L.lineStart - while not (L.buf[i] in {CR, LF, EndOfFile}): - result.add(L.buf[i]) - inc(i) - result.add("\n") + while L.buf[i] notin {CR, LF, EndOfFile}: + result.add L.buf[i] + inc i + result.add "\n" if marker: - result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n") + result.add spaces(getColNumber(L, L.bufpos)) & '^' & "\n" diff --git a/compiler/options.nim b/compiler/options.nim index b5fb546ef..8ff8cb753 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -691,12 +691,10 @@ iterator nimbleSubs*(conf: ConfigRef; p: string): string = proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile, ext: string): AbsoluteFile = ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" - let (head, tail) = splitPath(path.string) - result = getNimcacheDir(conf) / RelativeFile changeFileExt(tail, ext) + result = getNimcacheDir(conf) / RelativeFile path.string.splitPath.tail.changeFileExt(ext) proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, createSubDir: bool = true): AbsoluteFile = - let (head, tail) = splitPath(f.string) let subdir = getNimcacheDir(conf) if createSubDir: try: @@ -704,7 +702,7 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, except OSError: writeLine(stdout, "cannot create directory: " & subdir.string) quit(1) - result = subdir / RelativeFile tail + result = subdir / RelativeFile f.string.splitPath.tail #echo "completeGeneratedFilePath(", f, ") = ", result proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile = diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 2243e7063..9a3224de2 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -28,8 +28,6 @@ proc getNimbleFile*(conf: ConfigRef; path: string): string = result = file break packageSearch # we also store if we didn't find anything: - when not defined(nimNoNilSeqs): - if result.isNil: result = "" for d in myParentDirs(path): #echo "set cache ", d, " |", result, "|", parents conf.packageCache[d] = result diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index ce9a855d8..ed8f2c16a 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -99,14 +99,14 @@ proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) = else: # check all symkinds: internalAssert conf, int(high(TSymKind)) < 255 - for i in low(TSymKind)..high(TSymKind): + for i in TSymKind: if cmpIgnoreStyle(($i).substr(2), spec) == 0: result.add(ppSymKind) result.add(chr(i.ord)) return # check all nodekinds: internalAssert conf, int(high(TNodeKind)) < 255 - for i in low(TNodeKind)..high(TNodeKind): + for i in TNodeKind: if cmpIgnoreStyle($i, spec) == 0: result.add(ppNodeKind) result.add(chr(i.ord)) diff --git a/compiler/parser.nim b/compiler/parser.nim index 8cfeff6b0..e7db8d8b1 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -37,14 +37,14 @@ when defined(nimpretty): import layouter type - TParser* = object # A TParser object represents a file that - # is being parsed - currInd: int # current indentation level - firstTok: bool # Has the first token been read? - hasProgress: bool # some while loop requires progress ensurance - lex*: TLexer # The lexer that is used for parsing - tok*: TToken # The current token - inPragma*: int # Pragma level + Parser* = object # A Parser object represents a file that + # is being parsed + currInd: int # current indentation level + firstTok: bool # Has the first token been read? + hasProgress: bool # some while loop requires progress ensurance + lex*: Lexer # The lexer that is used for parsing + tok*: Token # The current token + inPragma*: int # Pragma level inSemiStmtList*: int emptyNode: PNode when defined(nimpretty): @@ -53,42 +53,42 @@ type SymbolMode = enum smNormal, smAllowNil, smAfterDot - TPrimaryMode = enum + PrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix -proc parseAll*(p: var TParser): PNode -proc closeParser*(p: var TParser) -proc parseTopLevelStmt*(p: var TParser): PNode +proc parseAll*(p: var Parser): PNode +proc closeParser*(p: var Parser) +proc parseTopLevelStmt*(p: var Parser): PNode # helpers for the other parsers -proc isOperator*(tok: TToken): bool -proc getTok*(p: var TParser) -proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "") -proc skipComment*(p: var TParser, node: PNode) -proc newNodeP*(kind: TNodeKind, p: TParser): PNode -proc newIntNodeP*(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode -proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode -proc newStrNodeP*(kind: TNodeKind, strVal: string, p: TParser): PNode -proc newIdentNodeP*(ident: PIdent, p: TParser): PNode -proc expectIdentOrKeyw*(p: TParser) -proc expectIdent*(p: TParser) -proc parLineInfo*(p: TParser): TLineInfo -proc eat*(p: var TParser, tokType: TTokType) -proc skipInd*(p: var TParser) -proc optPar*(p: var TParser) -proc optInd*(p: var TParser, n: PNode) -proc indAndComment*(p: var TParser, n: PNode) -proc setBaseFlags*(n: PNode, base: TNumericalBase) -proc parseSymbol*(p: var TParser, mode = smNormal): PNode -proc parseTry(p: var TParser; isExpr: bool): PNode -proc parseCase(p: var TParser): PNode -proc parseStmtPragma(p: var TParser): PNode -proc parsePragma(p: var TParser): PNode -proc postExprBlocks(p: var TParser, x: PNode): PNode -proc parseExprStmt(p: var TParser): PNode -proc parseBlock(p: var TParser): PNode -proc primary(p: var TParser, mode: TPrimaryMode): PNode -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode +proc isOperator*(tok: Token): bool +proc getTok*(p: var Parser) +proc parMessage*(p: Parser, msg: TMsgKind, arg: string = "") +proc skipComment*(p: var Parser, node: PNode) +proc newNodeP*(kind: TNodeKind, p: Parser): PNode +proc newIntNodeP*(kind: TNodeKind, intVal: BiggestInt, p: Parser): PNode +proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: Parser): PNode +proc newStrNodeP*(kind: TNodeKind, strVal: string, p: Parser): PNode +proc newIdentNodeP*(ident: PIdent, p: Parser): PNode +proc expectIdentOrKeyw*(p: Parser) +proc expectIdent*(p: Parser) +proc parLineInfo*(p: Parser): TLineInfo +proc eat*(p: var Parser, tokType: TokType) +proc skipInd*(p: var Parser) +proc optPar*(p: var Parser) +proc optInd*(p: var Parser, n: PNode) +proc indAndComment*(p: var Parser, n: PNode) +proc setBaseFlags*(n: PNode, base: NumericalBase) +proc parseSymbol*(p: var Parser, mode = smNormal): PNode +proc parseTry(p: var Parser; isExpr: bool): PNode +proc parseCase(p: var Parser): PNode +proc parseStmtPragma(p: var Parser): PNode +proc parsePragma(p: var Parser): PNode +proc postExprBlocks(p: var Parser, x: PNode): PNode +proc parseExprStmt(p: var Parser): PNode +proc parseBlock(p: var Parser): PNode +proc primary(p: var Parser, mode: PrimaryMode): PNode +proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode # implementation @@ -97,7 +97,7 @@ template prettySection(body) = body when defined(nimpretty): endSection(p.em) -proc getTok(p: var TParser) = +proc getTok(p: var Parser) = ## Get the next token from the parser's lexer, and store it in the parser's ## `tok` member. rawGetTok(p.lex, p.tok) @@ -110,7 +110,7 @@ proc getTok(p: var TParser) = rawGetTok(p.lex, p.tok) emitTok(p.em, p.lex, p.tok) -proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, +proc openParser*(p: var Parser, fileIdx: FileIndex, inputStream: PLLStream, cache: IdentCache; config: ConfigRef) = ## Open a parser, using the given arguments to set up its internal state. ## @@ -122,25 +122,25 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, p.firstTok = true p.emptyNode = newNode(nkEmpty) -proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream, +proc openParser*(p: var Parser, filename: AbsoluteFile, inputStream: PLLStream, cache: IdentCache; config: ConfigRef) = openParser(p, fileInfoIdx(config, filename), inputStream, cache, config) -proc closeParser(p: var TParser) = +proc closeParser(p: var Parser) = ## Close a parser, freeing up its resources. closeLexer(p.lex) when defined(nimpretty): closeEmitter(p.em) -proc parMessage(p: TParser, msg: TMsgKind, arg = "") = +proc parMessage(p: Parser, msg: TMsgKind, arg = "") = ## Produce and emit the parser message `arg` to output. lexMessageTok(p.lex, msg, p.tok, arg) -proc parMessage(p: TParser, msg: string, tok: TToken) = +proc parMessage(p: Parser, msg: string, tok: Token) = ## Produce and emit a parser message to output about the token `tok` parMessage(p, errGenerated, msg % prettyTok(tok)) -proc parMessage(p: TParser, arg: string) = +proc parMessage(p: Parser, arg: string) = ## Produce and emit the parser message `arg` to output. lexMessageTok(p.lex, errGenerated, p.tok, arg) @@ -150,7 +150,7 @@ template withInd(p, body: untyped) = body p.currInd = oldInd -template newlineWasSplitting(p: var TParser) = +template newlineWasSplitting(p: var Parser) = when defined(nimpretty): layouter.newlineWasSplitting(p.em) @@ -158,10 +158,10 @@ template realInd(p): bool = p.tok.indent > p.currInd template sameInd(p): bool = p.tok.indent == p.currInd template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0 -proc validInd(p: var TParser): bool {.inline.} = +proc validInd(p: var Parser): bool {.inline.} = result = p.tok.indent < 0 or p.tok.indent > p.currInd -proc rawSkipComment(p: var TParser, node: PNode) = +proc rawSkipComment(p: var Parser, node: PNode) = if p.tok.tokType == tkComment: if node != nil: when not defined(nimNoNilSeqs): @@ -177,43 +177,42 @@ proc rawSkipComment(p: var TParser, node: PNode) = parMessage(p, errInternal, "skipComment") getTok(p) -proc skipComment(p: var TParser, node: PNode) = +proc skipComment(p: var Parser, node: PNode) = if p.tok.indent < 0: rawSkipComment(p, node) -proc flexComment(p: var TParser, node: PNode) = +proc flexComment(p: var Parser, node: PNode) = if p.tok.indent < 0 or realInd(p): rawSkipComment(p, node) const errInvalidIndentation = "invalid indentation" errIdentifierExpected = "identifier expected, but got '$1'" errExprExpected = "expression expected, but found '$1'" - errTokenExpected = "'$1' expected" -proc skipInd(p: var TParser) = +proc skipInd(p: var Parser) = if p.tok.indent >= 0: if not realInd(p): parMessage(p, errInvalidIndentation) -proc optPar(p: var TParser) = +proc optPar(p: var Parser) = if p.tok.indent >= 0: if p.tok.indent < p.currInd: parMessage(p, errInvalidIndentation) -proc optInd(p: var TParser, n: PNode) = +proc optInd(p: var Parser, n: PNode) = skipComment(p, n) skipInd(p) -proc getTokNoInd(p: var TParser) = +proc getTokNoInd(p: var Parser) = getTok(p) if p.tok.indent >= 0: parMessage(p, errInvalidIndentation) -proc expectIdentOrKeyw(p: TParser) = +proc expectIdentOrKeyw(p: Parser) = if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType): lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok)) -proc expectIdent(p: TParser) = +proc expectIdent(p: Parser) = if p.tok.tokType != tkSymbol: lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok)) -proc eat(p: var TParser, tokType: TTokType) = +proc eat(p: var Parser, tokType: TokType) = ## Move the parser to the next token if the current token is of type ## `tokType`, otherwise error. if p.tok.tokType == tokType: @@ -222,64 +221,63 @@ proc eat(p: var TParser, tokType: TTokType) = lexMessage(p.lex, errGenerated, "expected: '" & TokTypeToStr[tokType] & "', but got: '" & prettyTok(p.tok) & "'") -proc parLineInfo(p: TParser): TLineInfo = +proc parLineInfo(p: Parser): TLineInfo = ## Retrieve the line information associated with the parser's current state. result = getLineInfo(p.lex, p.tok) -proc indAndComment(p: var TParser, n: PNode) = +proc indAndComment(p: var Parser, n: PNode) = if p.tok.indent > p.currInd: if p.tok.tokType == tkComment: rawSkipComment(p, n) else: parMessage(p, errInvalidIndentation) else: skipComment(p, n) -proc newNodeP(kind: TNodeKind, p: TParser): PNode = +proc newNodeP(kind: TNodeKind, p: Parser): PNode = result = newNodeI(kind, parLineInfo(p)) -proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = +proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: Parser): PNode = result = newNodeP(kind, p) result.intVal = intVal proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, - p: TParser): PNode = + p: Parser): PNode = result = newNodeP(kind, p) result.floatVal = floatVal -proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = +proc newStrNodeP(kind: TNodeKind, strVal: string, p: Parser): PNode = result = newNodeP(kind, p) result.strVal = strVal -proc newIdentNodeP(ident: PIdent, p: TParser): PNode = +proc newIdentNodeP(ident: PIdent, p: Parser): PNode = result = newNodeP(nkIdent, p) result.ident = ident -proc parseExpr(p: var TParser): PNode -proc parseStmt(p: var TParser): PNode -proc parseTypeDesc(p: var TParser): PNode -proc parseParamList(p: var TParser, retColon = true): PNode +proc parseExpr(p: var Parser): PNode +proc parseStmt(p: var Parser): PNode +proc parseTypeDesc(p: var Parser): PNode +proc parseParamList(p: var Parser, retColon = true): PNode -proc isSigilLike(tok: TToken): bool {.inline.} = +proc isSigilLike(tok: Token): bool {.inline.} = result = tok.tokType == tkOpr and tok.ident.s[0] == '@' -proc isRightAssociative(tok: TToken): bool {.inline.} = +proc isRightAssociative(tok: Token): bool {.inline.} = ## Determines whether the token is right assocative. result = tok.tokType == tkOpr and tok.ident.s[0] == '^' # or (tok.ident.s.len > 1 and tok.ident.s[^1] == '>') -proc isOperator(tok: TToken): bool = +proc isOperator(tok: Token): bool = ## Determines if the given token is an operator type token. tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, tkOr, tkXor} -proc isUnary(p: TParser): bool = - ## Check if the current parser token is a unary operator - if p.tok.tokType in {tkOpr, tkDotDot} and - p.tok.strongSpaceB == 0 and - p.tok.strongSpaceA > 0: - result = true +proc isUnary(tok: Token): bool = + ## Check if the given token is a unary operator + tok.tokType in {tkOpr, tkDotDot} and + tok.strongSpaceB == 0 and + tok.strongSpaceA > 0 -proc checkBinary(p: TParser) {.inline.} = +proc checkBinary(p: Parser) {.inline.} = ## Check if the current parser token is a binary operator. # we don't check '..' here as that's too annoying if p.tok.tokType == tkOpr: @@ -315,13 +313,13 @@ proc checkBinary(p: TParser) {.inline.} = #| mulExpr = dollarExpr (OP9 optInd dollarExpr)* #| dollarExpr = primary (OP10 optInd primary)* -proc colcom(p: var TParser, n: PNode) = +proc colcom(p: var Parser, n: PNode) = eat(p, tkColon) skipComment(p, n) const tkBuiltInMagics = {tkType, tkStatic, tkAddr} -proc parseSymbol(p: var TParser, mode = smNormal): PNode = +proc parseSymbol(p: var Parser, mode = smNormal): PNode = #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' #| | IDENT | KEYW case p.tok.tokType @@ -374,7 +372,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode = #if not isKeyword(p.tok.tokType): getTok(p) result = p.emptyNode -proc colonOrEquals(p: var TParser, a: PNode): PNode = +proc colonOrEquals(p: var Parser, a: PNode): PNode = if p.tok.tokType == tkColon: result = newNodeP(nkExprColonExpr, p) getTok(p) @@ -391,7 +389,7 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode = else: result = a -proc exprColonEqExpr(p: var TParser): PNode = +proc exprColonEqExpr(p: var Parser): PNode = #| exprColonEqExpr = expr (':'|'=' expr)? var a = parseExpr(p) if p.tok.tokType == tkDo: @@ -399,7 +397,7 @@ proc exprColonEqExpr(p: var TParser): PNode = else: result = colonOrEquals(p, a) -proc exprList(p: var TParser, endTok: TTokType, result: PNode) = +proc exprList(p: var Parser, endTok: TokType, result: PNode) = #| exprList = expr ^+ comma when defined(nimpretty): inc p.em.doIndentMore @@ -415,7 +413,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) = when defined(nimpretty): dec p.em.doIndentMore -proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = +proc exprColonEqExprListAux(p: var Parser, endTok: TokType, result: PNode) = assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) getTok(p) flexComment(p, result) @@ -433,13 +431,13 @@ proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = optPar(p) eat(p, endTok) -proc exprColonEqExprList(p: var TParser, kind: TNodeKind, - endTok: TTokType): PNode = +proc exprColonEqExprList(p: var Parser, kind: TNodeKind, + endTok: TokType): PNode = #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? result = newNodeP(kind, p) exprColonEqExprListAux(p, endTok, result) -proc dotExpr(p: var TParser, a: PNode): PNode = +proc dotExpr(p: var Parser, a: PNode): PNode = #| dotExpr = expr '.' optInd (symbol | '[:' exprList ']') #| explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? var info = p.parLineInfo @@ -461,12 +459,12 @@ proc dotExpr(p: var TParser, a: PNode): PNode = exprColonEqExprListAux(p, tkParRi, y) result = y -proc qualifiedIdent(p: var TParser): PNode = +proc qualifiedIdent(p: var Parser): PNode = #| qualifiedIdent = symbol ('.' optInd symbol)? result = parseSymbol(p) if p.tok.tokType == tkDot: result = dotExpr(p, result) -proc setOrTableConstr(p: var TParser): PNode = +proc setOrTableConstr(p: var Parser): PNode = #| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' result = newNodeP(nkCurly, p) getTok(p) # skip '{' @@ -486,7 +484,7 @@ proc setOrTableConstr(p: var TParser): PNode = optPar(p) eat(p, tkCurlyRi) # skip '}' -proc parseCast(p: var TParser): PNode = +proc parseCast(p: var Parser): PNode = #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' result = newNodeP(nkCast, p) getTok(p) @@ -501,14 +499,14 @@ proc parseCast(p: var TParser): PNode = optPar(p) eat(p, tkParRi) -proc setBaseFlags(n: PNode, base: TNumericalBase) = +proc setBaseFlags(n: PNode, base: NumericalBase) = case base of base10: discard of base2: incl(n.flags, nfBase2) of base8: incl(n.flags, nfBase8) of base16: incl(n.flags, nfBase16) -proc parseGStrLit(p: var TParser, a: PNode): PNode = +proc parseGStrLit(p: var Parser, a: PNode): PNode = case p.tok.tokType of tkGStrLit: result = newNodeP(nkCallStrLit, p) @@ -523,10 +521,10 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode = else: result = a -proc complexOrSimpleStmt(p: var TParser): PNode -proc simpleExpr(p: var TParser, mode = pmNormal): PNode +proc complexOrSimpleStmt(p: var Parser): PNode +proc simpleExpr(p: var Parser, mode = pmNormal): PNode -proc semiStmtList(p: var TParser, result: PNode) = +proc semiStmtList(p: var Parser, result: PNode) = inc p.inSemiStmtList result.add(complexOrSimpleStmt(p)) # progress guaranteed @@ -537,7 +535,7 @@ proc semiStmtList(p: var TParser, result: PNode) = dec p.inSemiStmtList result.transitionSonsKind(nkStmtListExpr) -proc parsePar(p: var TParser): PNode = +proc parsePar(p: var Parser): PNode = #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' #| | 'when' | 'var' | 'mixin' @@ -607,7 +605,7 @@ proc parsePar(p: var TParser): PNode = optPar(p) eat(p, tkParRi) -proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = +proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode = #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT #| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT #| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT @@ -717,15 +715,15 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = getTok(p) # we must consume a token here to prevent endless loops! result = p.emptyNode -proc namedParams(p: var TParser, callee: PNode, - kind: TNodeKind, endTok: TTokType): PNode = +proc namedParams(p: var Parser, callee: PNode, + kind: TNodeKind, endTok: TokType): PNode = let a = callee result = newNodeP(kind, p) result.add(a) # progress guaranteed exprColonEqExprListAux(p, endTok, result) -proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): PNode = +proc commandParam(p: var Parser, isFirstParam: var bool; mode: PrimaryMode): PNode = if mode == pmTypeDesc: result = simpleExpr(p, mode) else: @@ -740,7 +738,7 @@ proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): P result.add(parseExpr(p)) isFirstParam = false -proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode = +proc commandExpr(p: var Parser; r: PNode; mode: PrimaryMode): PNode = result = newNodeP(nkCommand, p) result.add(r) var isFirstParam = true @@ -748,8 +746,8 @@ proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode = p.hasProgress = false result.add commandParam(p, isFirstParam, mode) -proc primarySuffix(p: var TParser, r: PNode, - baseIndent: int, mode: TPrimaryMode): PNode = +proc primarySuffix(p: var Parser, r: PNode, + baseIndent: int, mode: PrimaryMode): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' #| | '.' optInd symbol generalizedLit? #| | '[' optInd exprColonEqExprList optPar ']' @@ -800,7 +798,7 @@ proc primarySuffix(p: var TParser, r: PNode, # `foo ref` or `foo ptr`. Unfortunately, these two are also # used as infix operators for the memory regions feature and # the current parsing rules don't play well here. - if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}): + if p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet # solution, but pragmas.nim can't handle that result = commandExpr(p, result, mode) @@ -808,17 +806,17 @@ proc primarySuffix(p: var TParser, r: PNode, else: break -proc parseOperators(p: var TParser, headNode: PNode, - limit: int, mode: TPrimaryMode): PNode = +proc parseOperators(p: var Parser, headNode: PNode, + limit: int, mode: PrimaryMode): PNode = result = headNode # expand while operators have priorities higher than 'limit' - var opPrec = getPrecedence(p.tok, false) + var opPrec = getPrecedence(p.tok) let modeB = if mode == pmTypeDef: pmTypeDesc else: mode # the operator itself must not start on a new line: # progress guaranteed - while opPrec >= limit and p.tok.indent < 0 and not isUnary(p): + while opPrec >= limit and p.tok.indent < 0 and not isUnary(p.tok): checkBinary(p) - var leftAssoc = 1-ord(isRightAssociative(p.tok)) + let leftAssoc = ord(not isRightAssociative(p.tok)) var a = newNodeP(nkInfix, p) var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: getTok(p) @@ -830,9 +828,9 @@ proc parseOperators(p: var TParser, headNode: PNode, a.add(result) a.add(b) result = a - opPrec = getPrecedence(p.tok, false) + opPrec = getPrecedence(p.tok) -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = +proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode = result = primary(p, mode) if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and mode == pmNormal: @@ -842,14 +840,14 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = result = pragmaExp result = parseOperators(p, result, limit, mode) -proc simpleExpr(p: var TParser, mode = pmNormal): PNode = +proc simpleExpr(p: var Parser, mode = pmNormal): PNode = when defined(nimpretty): inc p.em.doIndentMore result = simpleExprAux(p, -1, mode) when defined(nimpretty): dec p.em.doIndentMore -proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = +proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode = #| condExpr = expr colcom expr optInd #| ('elif' expr colcom expr optInd)* #| 'else' colcom expr @@ -907,7 +905,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = if wasIndented: p.currInd = oldInd -proc parsePragma(p: var TParser): PNode = +proc parsePragma(p: var Parser): PNode = #| pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}') result = newNodeP(nkPragma, p) inc p.inPragma @@ -936,7 +934,7 @@ proc parsePragma(p: var TParser): PNode = dec p.em.doIndentMore dec p.em.keepIndents -proc identVis(p: var TParser; allowDot=false): PNode = +proc identVis(p: var Parser; allowDot=false): PNode = #| identVis = symbol OPR? # postfix position #| identVisDot = symbol '.' optInd symbol OPR? var a = parseSymbol(p) @@ -952,7 +950,7 @@ proc identVis(p: var TParser; allowDot=false): PNode = else: result = a -proc identWithPragma(p: var TParser; allowDot=false): PNode = +proc identWithPragma(p: var Parser; allowDot=false): PNode = #| identWithPragma = identVis pragma? #| identWithPragmaDot = identVisDot pragma? var a = identVis(p, allowDot) @@ -964,13 +962,13 @@ proc identWithPragma(p: var TParser; allowDot=false): PNode = result = a type - TDeclaredIdentFlag = enum + DeclaredIdentFlag = enum withPragma, # identifier may have pragma withBothOptional # both ':' and '=' parts are optional withDot # allow 'var ident.ident = value' - TDeclaredIdentFlags = set[TDeclaredIdentFlag] + DeclaredIdentFlags = set[DeclaredIdentFlag] -proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = +proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = #| declColonEquals = identWithPragma (comma identWithPragma)* comma? #| (':' optInd typeDesc)? ('=' optInd expr)? #| identColonEquals = IDENT (comma IDENT)* comma? @@ -1004,7 +1002,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = else: result.add(newNodeP(nkEmpty, p)) -proc parseTuple(p: var TParser, indentAllowed = false): PNode = +proc parseTuple(p: var Parser, indentAllowed = false): PNode = #| inlTupleDecl = 'tuple' #| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' #| extTupleDecl = 'tuple' @@ -1049,7 +1047,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode = else: result = newNodeP(nkTupleClassTy, p) -proc parseParamList(p: var TParser, retColon = true): PNode = +proc parseParamList(p: var Parser, retColon = true): PNode = #| paramList = '(' declColonEquals ^* (comma/semicolon) ')' #| paramListArrow = paramList? ('->' optInd typeDesc)? #| paramListColon = paramList? (':' optInd typeDesc)? @@ -1097,13 +1095,13 @@ proc parseParamList(p: var TParser, retColon = true): PNode = dec p.em.doIndentMore dec p.em.keepIndents -proc optPragmas(p: var TParser): PNode = +proc optPragmas(p: var Parser): PNode = if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)): result = parsePragma(p) else: result = p.emptyNode -proc parseDoBlock(p: var TParser; info: TLineInfo): PNode = +proc parseDoBlock(p: var Parser; info: TLineInfo): PNode = #| doBlock = 'do' paramListArrow pragma? colcom stmt let params = parseParamList(p, retColon=false) let pragmas = optPragmas(p) @@ -1114,7 +1112,7 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode = body = result, params = params, name = p.emptyNode, pattern = p.emptyNode, genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode) -proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode = +proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode = #| procExpr = 'proc' paramListColon pragma? ('=' COMMENT? stmt)? # either a proc type or a anonymous proc let info = parLineInfo(p) @@ -1136,7 +1134,7 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode = parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead") result.add(pragmas) -proc isExprStart(p: TParser): bool = +proc isExprStart(p: Parser): bool = case p.tok.tokType of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor, tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics, @@ -1145,7 +1143,7 @@ proc isExprStart(p: TParser): bool = result = true else: result = false -proc parseSymbolList(p: var TParser, result: PNode) = +proc parseSymbolList(p: var Parser, result: PNode) = # progress guaranteed while true: var s = parseSymbol(p, smAllowNil) @@ -1155,8 +1153,8 @@ proc parseSymbolList(p: var TParser, result: PNode) = getTok(p) optInd(p, s) -proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, - mode: TPrimaryMode): PNode = +proc parseTypeDescKAux(p: var Parser, kind: TNodeKind, + mode: PrimaryMode): PNode = #| distinct = 'distinct' optInd typeDesc result = newNodeP(kind, p) getTok(p) @@ -1178,9 +1176,9 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, result.add list parseSymbolList(p, list) -proc parseVarTuple(p: var TParser): PNode +proc parseVarTuple(p: var Parser): PNode -proc parseFor(p: var TParser): PNode = +proc parseFor(p: var Parser): PNode = #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt #| forExpr = forStmt getTokNoInd(p) @@ -1210,7 +1208,7 @@ template nimprettyDontTouch(body) = when defined(nimpretty): dec p.em.keepIndents -proc parseExpr(p: var TParser): PNode = +proc parseExpr(p: var Parser): PNode = #| expr = (blockExpr #| | ifExpr #| | whenExpr @@ -1241,11 +1239,11 @@ proc parseExpr(p: var TParser): PNode = result = parseTry(p, isExpr=true) else: result = simpleExpr(p) -proc parseEnum(p: var TParser): PNode -proc parseObject(p: var TParser): PNode -proc parseTypeClass(p: var TParser): PNode +proc parseEnum(p: var Parser): PNode +proc parseObject(p: var Parser): PNode +proc parseTypeClass(p: var Parser): PNode -proc primary(p: var TParser, mode: TPrimaryMode): PNode = +proc primary(p: var Parser, mode: PrimaryMode): PNode = #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple' #| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' #| primary = typeKeyw optInd typeDesc @@ -1313,7 +1311,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = if mode != pmSkipSuffix: result = primarySuffix(p, result, baseInd, mode) -proc binaryNot(p: var TParser; a: PNode): PNode = +proc binaryNot(p: var Parser; a: PNode): PNode = if p.tok.tokType == tkNot: let notOpr = newIdentNodeP(p.tok.ident, p) getTok(p) @@ -1326,13 +1324,13 @@ proc binaryNot(p: var TParser; a: PNode): PNode = else: result = a -proc parseTypeDesc(p: var TParser): PNode = +proc parseTypeDesc(p: var Parser): PNode = #| typeDesc = simpleExpr ('not' expr)? newlineWasSplitting(p) result = simpleExpr(p, pmTypeDesc) result = binaryNot(p, result) -proc parseTypeDefAux(p: var TParser): PNode = +proc parseTypeDefAux(p: var Parser): PNode = #| typeDefAux = simpleExpr ('not' expr)? #| | 'concept' typeClass result = simpleExpr(p, pmTypeDef) @@ -1346,7 +1344,7 @@ proc makeCall(n: PNode): PNode = result = newNodeI(nkCall, n.info) result.add n -proc postExprBlocks(p: var TParser, x: PNode): PNode = +proc postExprBlocks(p: var Parser, x: PNode): PNode = #| postExprBlocks = ':' stmt? ( IND{=} doBlock #| | IND{=} 'of' exprList ':' stmt #| | IND{=} 'elif' expr ':' stmt @@ -1420,7 +1418,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode = if openingParams.kind != nkEmpty: parMessage(p, "expected ':'") -proc parseExprStmt(p: var TParser): PNode = +proc parseExprStmt(p: var Parser): PNode = #| exprStmt = simpleExpr #| (( '=' optInd expr colonBody? ) #| / ( expr ^+ comma @@ -1456,7 +1454,7 @@ proc parseExprStmt(p: var TParser): PNode = result = a result = postExprBlocks(p, result) -proc parseModuleName(p: var TParser, kind: TNodeKind): PNode = +proc parseModuleName(p: var Parser, kind: TNodeKind): PNode = result = parseExpr(p) when false: # parseExpr already handles 'as' syntax ... @@ -1467,7 +1465,7 @@ proc parseModuleName(p: var TParser, kind: TNodeKind): PNode = result.add(a) result.add(parseExpr(p)) -proc parseImport(p: var TParser, kind: TNodeKind): PNode = +proc parseImport(p: var Parser, kind: TNodeKind): PNode = #| importStmt = 'import' optInd expr #| ((comma expr)* #| / 'except' optInd (expr ^+ comma)) @@ -1495,7 +1493,7 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode = optInd(p, a) #expectNl(p) -proc parseIncludeStmt(p: var TParser): PNode = +proc parseIncludeStmt(p: var Parser): PNode = #| includeStmt = 'include' optInd expr ^+ comma result = newNodeP(nkIncludeStmt, p) getTok(p) # skip `import` or `include` @@ -1511,7 +1509,7 @@ proc parseIncludeStmt(p: var TParser): PNode = optInd(p, a) #expectNl(p) -proc parseFromStmt(p: var TParser): PNode = +proc parseFromStmt(p: var Parser): PNode = #| fromStmt = 'from' expr 'import' optInd expr (comma expr)* result = newNodeP(nkFromStmt, p) getTok(p) # skip `from` @@ -1531,7 +1529,7 @@ proc parseFromStmt(p: var TParser): PNode = optInd(p, a) #expectNl(p) -proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = +proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode = #| returnStmt = 'return' optInd expr? #| raiseStmt = 'raise' optInd expr? #| yieldStmt = 'yield' optInd expr? @@ -1552,7 +1550,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = e = postExprBlocks(p, e) result.add(e) -proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = +proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode = #| condStmt = expr colcom stmt COMMENT? #| (IND{=} 'elif' expr colcom stmt)* #| (IND{=} 'else' colcom stmt)? @@ -1576,7 +1574,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = branch.add(parseStmt(p)) result.add(branch) -proc parseWhile(p: var TParser): PNode = +proc parseWhile(p: var Parser): PNode = #| whileStmt = 'while' expr colcom stmt result = newNodeP(nkWhileStmt, p) getTok(p) @@ -1585,7 +1583,7 @@ proc parseWhile(p: var TParser): PNode = colcom(p, result) result.add(parseStmt(p)) -proc parseCase(p: var TParser): PNode = +proc parseCase(p: var Parser): PNode = #| ofBranch = 'of' exprList colcom stmt #| ofBranches = ofBranch (IND{=} ofBranch)* #| (IND{=} 'elif' expr colcom stmt)* @@ -1632,7 +1630,7 @@ proc parseCase(p: var TParser): PNode = if wasIndented: p.currInd = oldInd -proc parseTry(p: var TParser; isExpr: bool): PNode = +proc parseTry(p: var Parser; isExpr: bool): PNode = #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') #| (IND{=}? 'except' exprList colcom stmt)* #| (IND{=}? 'finally' colcom stmt)? @@ -1658,14 +1656,14 @@ proc parseTry(p: var TParser; isExpr: bool): PNode = result.add(b) if b == nil: parMessage(p, "expected 'except'") -proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode = +proc parseExceptBlock(p: var Parser, kind: TNodeKind): PNode = #| exceptBlock = 'except' colcom stmt result = newNodeP(kind, p) getTok(p) colcom(p, result) result.add(parseStmt(p)) -proc parseBlock(p: var TParser): PNode = +proc parseBlock(p: var Parser): PNode = #| blockStmt = 'block' symbol? colcom stmt #| blockExpr = 'block' symbol? colcom stmt result = newNodeP(nkBlockStmt, p) @@ -1675,7 +1673,7 @@ proc parseBlock(p: var TParser): PNode = colcom(p, result) result.add(parseStmt(p)) -proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode = +proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode = #| staticStmt = 'static' colcom stmt #| deferStmt = 'defer' colcom stmt result = newNodeP(k, p) @@ -1683,7 +1681,7 @@ proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode = colcom(p, result) result.add(parseStmt(p)) -proc parseAsm(p: var TParser): PNode = +proc parseAsm(p: var Parser): PNode = #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT) result = newNodeP(nkAsmStmt, p) getTokNoInd(p) @@ -1699,7 +1697,7 @@ proc parseAsm(p: var TParser): PNode = return getTok(p) -proc parseGenericParam(p: var TParser): PNode = +proc parseGenericParam(p: var Parser): PNode = #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)? var a: PNode result = newNodeP(nkIdentDefs, p) @@ -1734,7 +1732,7 @@ proc parseGenericParam(p: var TParser): PNode = else: result.add(p.emptyNode) -proc parseGenericParamList(p: var TParser): PNode = +proc parseGenericParamList(p: var Parser): PNode = #| genericParamList = '[' optInd #| genericParam ^* (comma/semicolon) optPar ']' result = newNodeP(nkGenericParams, p) @@ -1752,13 +1750,13 @@ proc parseGenericParamList(p: var TParser): PNode = optPar(p) eat(p, tkBracketRi) -proc parsePattern(p: var TParser): PNode = +proc parsePattern(p: var Parser): PNode = #| pattern = '{' stmt '}' eat(p, tkCurlyLe) result = parseStmt(p) eat(p, tkCurlyRi) -proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = +proc parseRoutine(p: var Parser, kind: TNodeKind): PNode = #| indAndComment = (IND{>} COMMENT)? | COMMENT? #| routine = optInd identVis pattern? genericParamList? #| paramListColon pragma? ('=' COMMENT? stmt)? indAndComment @@ -1785,17 +1783,14 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = result.add(p.emptyNode) indAndComment(p, result) -proc newCommentStmt(p: var TParser): PNode = +proc newCommentStmt(p: var Parser): PNode = #| commentStmt = COMMENT result = newNodeP(nkCommentStmt, p) result.comment = p.tok.literal getTok(p) -type - TDefParser = proc (p: var TParser): PNode {.nimcall.} - -proc parseSection(p: var TParser, kind: TNodeKind, - defparser: TDefParser): PNode = +proc parseSection(p: var Parser, kind: TNodeKind, + defparser: proc (p: var Parser): PNode {.nimcall.}): PNode = #| section(RULE) = COMMENT? RULE / (IND{>} (RULE / COMMENT)^+IND{=} DED) result = newNodeP(kind, p) if kind != nkTypeSection: getTok(p) @@ -1823,7 +1818,7 @@ proc parseSection(p: var TParser, kind: TNodeKind, else: parMessage(p, errIdentifierExpected, p.tok) -proc parseEnum(p: var TParser): PNode = +proc parseEnum(p: var Parser): PNode = #| enum = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+ result = newNodeP(nkEnumTy, p) getTok(p) @@ -1869,8 +1864,8 @@ proc parseEnum(p: var TParser): PNode = if result.len <= 1: parMessage(p, errIdentifierExpected, p.tok) -proc parseObjectPart(p: var TParser): PNode -proc parseObjectWhen(p: var TParser): PNode = +proc parseObjectPart(p: var Parser): PNode +proc parseObjectWhen(p: var Parser): PNode = #| objectWhen = 'when' expr colcom objectPart COMMENT? #| ('elif' expr colcom objectPart COMMENT?)* #| ('else' colcom objectPart COMMENT?)? @@ -1894,7 +1889,7 @@ proc parseObjectWhen(p: var TParser): PNode = flexComment(p, branch) result.add(branch) -proc parseObjectCase(p: var TParser): PNode = +proc parseObjectCase(p: var Parser): PNode = #| objectBranch = 'of' exprList colcom objectPart #| objectBranches = objectBranch (IND{=} objectBranch)* #| (IND{=} 'elif' expr colcom objectPart)* @@ -1939,7 +1934,7 @@ proc parseObjectCase(p: var TParser): PNode = if wasIndented: p.currInd = oldInd -proc parseObjectPart(p: var TParser): PNode = +proc parseObjectPart(p: var Parser): PNode = #| objectPart = IND{>} objectPart^+IND{=} DED #| / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals if realInd(p): @@ -1971,7 +1966,7 @@ proc parseObjectPart(p: var TParser): PNode = else: result = p.emptyNode -proc parseObject(p: var TParser): PNode = +proc parseObject(p: var Parser): PNode = #| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart result = newNodeP(nkObjectTy, p) getTok(p) @@ -1996,7 +1991,7 @@ proc parseObject(p: var TParser): PNode = else: result.add(parseObjectPart(p)) -proc parseTypeClassParam(p: var TParser): PNode = +proc parseTypeClassParam(p: var Parser): PNode = let modifier = case p.tok.tokType of tkOut, tkVar: nkVarTy of tkPtr: nkPtrTy @@ -2012,7 +2007,7 @@ proc parseTypeClassParam(p: var TParser): PNode = else: result = p.parseSymbol -proc parseTypeClass(p: var TParser): PNode = +proc parseTypeClass(p: var Parser): PNode = #| typeClassParam = ('var' | 'out')? symbol #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? #| &IND{>} stmt @@ -2047,7 +2042,7 @@ proc parseTypeClass(p: var TParser): PNode = else: result.add(parseStmt(p)) -proc parseTypeDef(p: var TParser): PNode = +proc parseTypeDef(p: var Parser): PNode = #| #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux #| indAndComment? / identVisDot genericParamList? pragma '=' optInd typeDefAux @@ -2095,7 +2090,7 @@ proc parseTypeDef(p: var TParser): PNode = result.add(p.emptyNode) indAndComment(p, result) # special extension! -proc parseVarTuple(p: var TParser): PNode = +proc parseVarTuple(p: var Parser): PNode = #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr result = newNodeP(nkVarTuple, p) getTok(p) # skip '(' @@ -2111,7 +2106,7 @@ proc parseVarTuple(p: var TParser): PNode = optPar(p) eat(p, tkParRi) -proc parseVariable(p: var TParser): PNode = +proc parseVariable(p: var Parser): PNode = #| colonBody = colcom stmt postExprBlocks? #| variable = (varTuple / identColonEquals) colonBody? indAndComment if p.tok.tokType == tkParLe: @@ -2123,7 +2118,7 @@ proc parseVariable(p: var TParser): PNode = result[^1] = postExprBlocks(p, result[^1]) indAndComment(p, result) -proc parseConstant(p: var TParser): PNode = +proc parseConstant(p: var Parser): PNode = #| constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment if p.tok.tokType == tkParLe: result = parseVarTuple(p) else: @@ -2142,7 +2137,7 @@ proc parseConstant(p: var TParser): PNode = result[^1] = postExprBlocks(p, result[^1]) indAndComment(p, result) -proc parseBind(p: var TParser, k: TNodeKind): PNode = +proc parseBind(p: var Parser, k: TNodeKind): PNode = #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma result = newNodeP(k, p) @@ -2157,7 +2152,7 @@ proc parseBind(p: var TParser, k: TNodeKind): PNode = optInd(p, a) #expectNl(p) -proc parseStmtPragma(p: var TParser): PNode = +proc parseStmtPragma(p: var Parser): PNode = #| pragmaStmt = pragma (':' COMMENT? stmt)? result = parsePragma(p) if p.tok.tokType == tkColon and p.tok.indent < 0: @@ -2168,7 +2163,7 @@ proc parseStmtPragma(p: var TParser): PNode = result.add a result.add parseStmt(p) -proc simpleStmt(p: var TParser): PNode = +proc simpleStmt(p: var Parser): PNode = #| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt #| | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt #| | includeStmt | commentStmt) / exprStmt) COMMENT? @@ -2191,7 +2186,7 @@ proc simpleStmt(p: var TParser): PNode = else: result = p.emptyNode if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result) -proc complexOrSimpleStmt(p: var TParser): PNode = +proc complexOrSimpleStmt(p: var Parser): PNode = #| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt #| | tryStmt | forStmt #| | blockStmt | staticStmt | deferStmt | asmStmt @@ -2251,7 +2246,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode = of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable) else: result = simpleStmt(p) -proc parseStmt(p: var TParser): PNode = +proc parseStmt(p: var Parser): PNode = #| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED) #| / simpleStmt ^+ ';' if p.tok.indent > p.currInd: @@ -2311,7 +2306,7 @@ proc parseStmt(p: var TParser): PNode = getTok(p) if err and p.tok.tokType == tkEof: break -proc parseAll(p: var TParser): PNode = +proc parseAll(p: var Parser): PNode = ## Parses the rest of the input stream held by the parser into a PNode. result = newNodeP(nkStmtList, p) while p.tok.tokType != tkEof: @@ -2326,7 +2321,7 @@ proc parseAll(p: var TParser): PNode = if p.tok.indent != 0: parMessage(p, errInvalidIndentation) -proc parseTopLevelStmt(p: var TParser): PNode = +proc parseTopLevelStmt(p: var Parser): PNode = ## Implements an iterator which, when called repeatedly, returns the next ## top-level statement or emptyNode if end of stream. result = p.emptyNode @@ -2357,7 +2352,7 @@ proc parseTopLevelStmt(p: var TParser): PNode = proc parseString*(s: string; cache: IdentCache; config: ConfigRef; filename: string = ""; line: int = 0; - errorHandler: TErrorHandler = nil): PNode = + errorHandler: ErrorHandler = nil): PNode = ## Parses a string into an AST, returning the top node. ## `filename` and `line`, although optional, provide info so that the ## compiler can generate correct error messages referring to the original @@ -2365,7 +2360,7 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef; var stream = llStreamOpen(s) stream.lineOffset = line - var parser: TParser + var parser: Parser parser.lex.errorHandler = errorHandler openParser(parser, AbsoluteFile filename, stream, cache, config) diff --git a/compiler/passes.nim b/compiler/passes.nim index 615b9ac88..2d30ebbb5 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -126,7 +126,7 @@ proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} = proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} = if graph.stopCompile(): return true var - p: TParsers + p: Parser a: TPassContextArray s: PLLStream fileIdx = module.fileIdx @@ -164,7 +164,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool { else: s = stream while true: - openParsers(p, fileIdx, s, graph.cache, graph.config) + openParser(p, fileIdx, s, graph.cache, graph.config) if module.owner == nil or module.owner.name.s != "stdlib" or module.name.s == "distros": # XXX what about caching? no processing then? what if I change the @@ -212,7 +212,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool { else: #echo "----- single\n", n if not processTopLevelStmt(graph, n, a): break - closeParsers(p) + closeParser(p) if s.kind != llsStdIn: break closePasses(graph, a) # id synchronization point for more consistent code generation: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 44ff90010..b2529a5b8 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -238,7 +238,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) = var v: string if n[1].kind == nkIdent: v = n[1].ident.s else: v = expectStrLit(c, n) - for m in low(TMagic)..high(TMagic): + for m in TMagic: if substr($m, 1) == v: s.magic = m break @@ -257,8 +257,8 @@ proc isTurnedOn(c: PContext, n: PNode): bool = localError(c.config, n.info, "'on' or 'off' expected") proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) = - if isTurnedOn(c, n): resOptions = resOptions + op - else: resOptions = resOptions - op + if isTurnedOn(c, n): resOptions.incl op + else: resOptions.excl op proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) = if isTurnedOn(c, n): diff --git a/compiler/renderer.nim b/compiler/renderer.nim index f600d58bf..9601bf082 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -24,7 +24,7 @@ type renderIr TRenderFlags* = set[TRenderFlag] TRenderTok* = object - kind*: TTokType + kind*: TokType length*: int16 sym*: PSym @@ -118,7 +118,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) = g.inGenericParams = false g.config = config -proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) = +proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) = setLen(g.tokens, g.tokens.len + 1) g.tokens[^1].kind = kind g.tokens[^1].length = int16(s.len) @@ -178,7 +178,7 @@ proc dedent(g: var TSrcGen) = dec(g.pendingNL, IndentWidth) dec(g.lineLen, IndentWidth) -proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) = +proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) = if kind != tkSpaces: addPendingNL(g) if s.len > 0: @@ -250,7 +250,7 @@ proc maxLineLength(s: string): int = inc(lineLen) inc(i) -proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = +proc putRawStr(g: var TSrcGen, kind: TokType, s: string) = var i = 0 let hi = s.len - 1 var str = "" @@ -459,8 +459,8 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkDo: result = lsons(g, n) + len("do__:_") of nkConstDef, nkIdentDefs: result = lcomma(g, n, 0, - 3) - if n[^2].kind != nkEmpty: result = result + lsub(g, n[^2]) + 2 - if n[^1].kind != nkEmpty: result = result + lsub(g, n[^1]) + 3 + if n[^2].kind != nkEmpty: result += lsub(g, n[^2]) + 2 + if n[^1].kind != nkEmpty: result += lsub(g, n[^1]) + 3 of nkVarTuple: if n[^1].kind == nkEmpty: result = lcomma(g, n, 0, - 2) + len("()") @@ -471,8 +471,8 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkChckRange: result = len("chckRange") + 2 + lcomma(g, n) of nkObjDownConv, nkObjUpConv: result = 2 - if n.len >= 1: result = result + lsub(g, n[0]) - result = result + lcomma(g, n, 1) + if n.len >= 1: result += lsub(g, n[0]) + result += lcomma(g, n, 1) of nkExprColonExpr: result = lsons(g, n) + 2 of nkInfix: result = lsons(g, n) + 2 of nkPrefix: @@ -536,7 +536,7 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkGenericParams: result = lcomma(g, n) + 2 of nkFormalParams: result = lcomma(g, n, 1) + 2 - if n[0].kind != nkEmpty: result = result + lsub(g, n[0]) + 2 + if n[0].kind != nkEmpty: result += lsub(g, n[0]) + 2 of nkExceptBranch: result = lcomma(g, n, 0, -2) + lsub(g, lastSon(n)) + len("except_:_") of nkObjectTy: @@ -575,7 +575,7 @@ proc hasCom(n: PNode): bool = for i in 0.. 0 and s[0] in lexer.SymChars: if n.kind == nkIdent: @@ -855,7 +855,7 @@ proc gident(g: var TSrcGen, n: PNode) = (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): t = tkSymbol else: - t = TTokType(n.ident.id + ord(tkSymbol)) + t = TokType(n.ident.id + ord(tkSymbol)) else: t = tkSymbol else: @@ -1644,7 +1644,7 @@ proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = initSrcGen(r, renderFlags, newPartialConfigRef()) gsub(r, n) -proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) = +proc getNextTok*(r: var TSrcGen, kind: var TokType, literal: var string) = if r.idx < r.tokens.len: kind = r.tokens[r.idx].kind let length = r.tokens[r.idx].length.int diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index 2dce6824c..02d405844 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -107,7 +107,6 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = var indent = info.col let numLines = numLines(conf, info.fileIndex).uint16 var lastNonemptyPos = 0 - result = "" var ldata = LineData(lineFirst: first.line.int, conf: conf) visitMultilineStrings(ldata, n[^1]) @@ -116,6 +115,7 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = for i in 0.. 0 - if nb == 1: - return parts[0] - result = parts[0] / parts[1] - for i in 2..= 0 and idx < x.len: result = x[int(idx)] else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n) of nkStrLit..nkTripleStrLit: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 1a7bd9b6b..ffeed00d6 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -66,7 +66,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym continue let symKind = if q.typ.kind == tyStatic: skConst else: skType var s = newSym(symKind, q.name, getCurrOwner(c), q.info) - s.flags = s.flags + {sfUsed, sfFromGeneric} + s.flags.incl {sfUsed, sfFromGeneric} var t = PType(idTableGet(pt, q.typ)) if t == nil: if tfRetType in q.typ.flags: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index cd5a52fe9..64a27d1db 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -139,8 +139,7 @@ template quoteStr(s: string): string = "'" & s & "'" proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): string = result = "" for field in directFieldsInRecList(fieldsRecList): - let assignment = locateFieldInInitExpr(c, field.sym, initExpr) - if assignment != nil: + if locateFieldInInitExpr(c, field.sym, initExpr) != nil: if result.len != 0: result.add ", " result.add field.sym.name.s.quoteStr diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index e771e17c4..a1afd2c6d 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -336,7 +336,6 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = let s = qualifiedLookUp(c.c, n, {}) if s != nil: if s.owner == c.owner and s.kind == skParam and sfTemplateParam in s.flags: - # oldCheck(c, sfGenSym notin s.flags or c.noGenSym == 0): incl(s.flags, sfUsed) result = newSymNode(s, n.info) onUse(n.info, s) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 6a1c1afc9..953801431 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -786,7 +786,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, {sfImportc, sfExportc} * fieldOwner.flags != {} and not hasCaseFields and f.loc.r == nil: f.loc.r = rope(f.name.s) - f.flags = f.flags + ({sfImportc, sfExportc} * fieldOwner.flags) + f.flags.incl {sfImportc, sfExportc} * fieldOwner.flags inc(pos) if containsOrIncl(check, f.name.id): localError(c.config, info, "attempt to redefine: '" & f.name.s & "'") @@ -1211,11 +1211,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if hasType: typ = semParamType(c, a[^2], constraint) - let sym = getCurrOwner(c) - var owner = sym.owner # TODO: Disallow typed/untyped in procs in the compiler/stdlib if kind == skProc and (typ.kind == tyTyped or typ.kind == tyUntyped): - if not isMagic(sym): + if not isMagic(getCurrOwner(c)): localError(c.config, a[^2].info, "'" & typ.sym.name.s & "' is only allowed in templates and macros or magic procs") if hasDefault: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index e7b289d77..5fa3880af 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -12,8 +12,7 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer, options, lineinfos -const - tfInstClearedFlags = {tfHasMeta, tfUnresolved} +const tfInstClearedFlags = {tfHasMeta, tfUnresolved} proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = if t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}: diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 0902a839b..9a16cc3e0 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -157,7 +157,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = if t.n.len > 0: let oldFlags = t.sym.flags # Mild hack to prevent endless recursion. - t.sym.flags = t.sym.flags - {sfAnon, sfGenSym} + t.sym.flags.excl {sfAnon, sfGenSym} hashTree(c, t.n, flags + {CoHashTypeInsideNode}) t.sym.flags = oldFlags else: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4be84d659..95231744c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -265,17 +265,12 @@ proc sumGeneric(t: PType): int = else: return 0 -#var ggDebug: bool - proc complexDisambiguation(a, b: PType): int = # 'a' matches better if *every* argument matches better or equal than 'b'. var winner = 0 for i in 1.. y: winner = 1 @@ -337,14 +332,13 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string = else: result = arg.typ.typeToString(prefer) -proc describeArgs*(c: PContext, n: PNode, startIdx = 1; - prefer: TPreferedDesc = preferName): string = +proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string = result = "" for i in startIdx.. 1: m.callee.n[1].sym else: nil + + var + a = 1 # iterates over the actual given arguments + f = if m.callee.kind != tyGenericBody: 1 + else: 0 # iterates over formal parameters + arg: PNode # current prepared argument + formalLen = m.callee.n.len + formal = if formalLen > 1: m.callee.n[1].sym else: nil # current routine parameter + container: PNode = nil # constructed container while a < n.len: - c.openShadowScope if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: @@ -2493,7 +2478,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, f = max(f, formalLen - n.len + a + 1) elif formal.typ.kind != tyVarargs or container == nil: setSon(m.call, formal.position + 1, arg) - inc(f) + inc f container = nil else: # we end up here if the argument can be converted into the varargs @@ -2511,7 +2496,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, else: c.closeShadowScope - inc(a) + inc a # for some edge cases (see tdont_return_unowned_from_owned test case) m.firstMismatch.arg = a m.firstMismatch.formal = formal diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim index 90e34eb73..2ec40227b 100644 --- a/compiler/sourcemap.nim +++ b/compiler/sourcemap.nim @@ -78,8 +78,7 @@ proc text*(sourceNode: SourceNode, depth: int): string = result.add(child.node.text(depth + 1)) -proc `$`*(sourceNode: SourceNode): string = - text(sourceNode, 0) +proc `$`*(sourceNode: SourceNode): string = text(sourceNode, 0) # base64_VLQ @@ -107,8 +106,7 @@ proc encode*(i: int): string = z += 1 -type - TokenState = enum Normal, String, Ident, Mangled +type TokenState = enum Normal, String, Ident, Mangled iterator tokenize*(line: string): (bool, string) = # result = @[] @@ -244,10 +242,10 @@ proc serializeMappings(map: SourceMapGenerator, mappings: seq[Mapping]): string var previous = Mapping(generated: (line: 1, column: 0), original: (line: 0, column: 0), name: "", source: "") var previousSourceId = 0 var previousNameId = 0 - result = "" var next = "" var nameId = 0 var sourceId = 0 + result = "" for z, mapping in mappings: next = "" diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 03c65cd42..4943603ce 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -33,7 +33,7 @@ # included from sigmatch.nim import algorithm, sets, prefixmatches, lineinfos, parseutils, linter -from wordrecg import wDeprecated, wError, wAddr, wYield, specialWords +from wordrecg import wDeprecated, wError, wAddr, wYield when defined(nimsuggest): import passes, tables, pathutils # importer diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index c3f3bc0dc..e745e28ba 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -13,44 +13,20 @@ import strutils, llstream, ast, idents, lexer, options, msgs, parser, filters, filter_tmpl, renderer, lineinfos, pathutils -type - TFilterKind* = enum - filtNone, filtTemplate, filtReplace, filtStrip - TParserKind* = enum - skinStandard, skinEndX - -const - parserNames*: array[TParserKind, string] = ["standard", - "endx"] - filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", - "strip"] +export Parser, parseAll, parseTopLevelStmt, closeParser type - TParsers* = object - skin*: TParserKind - parser*: TParser - -template config(p: TParsers): ConfigRef = p.parser.lex.config - -proc parseAll*(p: var TParsers): PNode = - case p.skin - of skinStandard: - result = parser.parseAll(p.parser) - of skinEndX: - internalError(p.config, "parser to implement") - -proc parseTopLevelStmt*(p: var TParsers): PNode = - case p.skin - of skinStandard: - result = parser.parseTopLevelStmt(p.parser) - of skinEndX: - internalError(p.config, "parser to implement") + FilterKind = enum + filtNone = "none" + filtTemplate = "stdtmpl" + filtReplace = "replace" + filtStrip = "strip" proc utf8Bom(s: string): int = if s.len >= 3 and s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF': - result = 3 + 3 else: - result = 0 + 0 proc containsShebang(s: string, i: int): bool = if i+1 < s.len and s[i] == '#' and s[i+1] == '!': @@ -78,23 +54,16 @@ proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache else: inc(i, 2) while i < line.len and line[i] in Whitespace: inc(i) - var q: TParser - parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache, config) - result = parser.parseAll(q) - parser.closeParser(q) + var p: Parser + openParser(p, filename, llStreamOpen(substr(line, i)), cache, config) + result = parseAll(p) + closeParser(p) llStreamClose(s) -proc getFilter(ident: PIdent): TFilterKind = - for i in low(TFilterKind)..high(TFilterKind): - if cmpIgnoreStyle(ident.s, filterNames[i]) == 0: +proc getFilter(ident: PIdent): FilterKind = + for i in FilterKind: + if cmpIgnoreStyle(ident.s, $i) == 0: return i - result = filtNone - -proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind = - for i in low(TParserKind)..high(TParserKind): - if cmpIgnoreStyle(ident.s, parserNames[i]) == 0: - return i - localError(conf, n.info, "unknown parser: " & ident.s) proc getCallee(conf: ConfigRef; n: PNode): PIdent = if n.kind in nkCallKinds and n[0].kind == nkIdent: @@ -104,30 +73,28 @@ proc getCallee(conf: ConfigRef; n: PNode): PIdent = else: localError(conf, n.info, "invalid filter: " & renderTree(n)) -proc applyFilter(p: var TParsers, n: PNode, filename: AbsoluteFile, +proc applyFilter(p: var Parser, n: PNode, filename: AbsoluteFile, stdin: PLLStream): PLLStream = - var ident = getCallee(p.config, n) - var f = getFilter(ident) - case f - of filtNone: - p.skin = getParser(p.config, n, ident) - result = stdin - of filtTemplate: - result = filterTmpl(stdin, filename, n, p.config) - of filtStrip: - result = filterStrip(p.config, stdin, filename, n) - of filtReplace: - result = filterReplace(p.config, stdin, filename, n) + var f = getFilter(getCallee(p.lex.config, n)) + result = case f + of filtNone: + stdin + of filtTemplate: + filterTmpl(p.lex.config, stdin, filename, n) + of filtStrip: + filterStrip(p.lex.config, stdin, filename, n) + of filtReplace: + filterReplace(p.lex.config, stdin, filename, n) if f != filtNone: - assert p.config != nil - if p.config.hasHint(hintCodeBegin): - rawMessage(p.config, hintCodeBegin, "") - msgWriteln(p.config, result.s) - rawMessage(p.config, hintCodeEnd, "") + assert p.lex.config != nil + if p.lex.config.hasHint(hintCodeBegin): + rawMessage(p.lex.config, hintCodeBegin, "") + msgWriteln(p.lex.config, result.s) + rawMessage(p.lex.config, hintCodeEnd, "") -proc evalPipe(p: var TParsers, n: PNode, filename: AbsoluteFile, +proc evalPipe(p: var Parser, n: PNode, filename: AbsoluteFile, start: PLLStream): PLLStream = - assert p.config != nil + assert p.lex.config != nil result = start if n.kind == nkEmpty: return if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|": @@ -141,35 +108,28 @@ proc evalPipe(p: var TParsers, n: PNode, filename: AbsoluteFile, else: result = applyFilter(p, n, filename, result) -proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; +proc openParser*(p: var Parser, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = assert config != nil - var s: PLLStream - p.skin = skinStandard let filename = toFullPathConsiderDirty(config, fileIdx) var pipe = parsePipe(filename, inputstream, cache, config) - p.config() = config - if pipe != nil: s = evalPipe(p, pipe, filename, inputstream) - else: s = inputstream - case p.skin - of skinStandard, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, config) + p.lex.config = config + let s = if pipe != nil: evalPipe(p, pipe, filename, inputstream) + else: inputstream + parser.openParser(p, fileIdx, s, cache, config) -proc closeParsers*(p: var TParsers) = - parser.closeParser(p.parser) - -proc setupParsers*(p: var TParsers; fileIdx: FileIndex; cache: IdentCache; +proc setupParser*(p: var Parser; fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): bool = - var f: File let filename = toFullPathConsiderDirty(config, fileIdx) + var f: File if not open(f, filename.string): rawMessage(config, errGenerated, "cannot open file: " & filename.string) return false - openParsers(p, fileIdx, llStreamOpen(f), cache, config) + openParser(p, fileIdx, llStreamOpen(f), cache, config) result = true proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode = - var p: TParsers - if setupParsers(p, fileIdx, cache, config): + var p: Parser + if setupParser(p, fileIdx, cache, config): result = parseAll(p) - closeParsers(p) + closeParser(p) diff --git a/compiler/types.nim b/compiler/types.nim index b8452c3ea..44827aa33 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -469,9 +469,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = prefer proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = + result = "" let prefer = getPrefer(prefer) let t = typ - result = "" if t == nil: return if prefer in preferToResolveSymbols and t.sym != nil and sfAnon notin t.sym.flags and t.kind != tySequence: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 4ef510d20..c2a2f6d42 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1360,19 +1360,6 @@ proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) = c.gABx(n, opcMarshalStore, 0, c.genType(n[1].typ)) c.freeTemp(tmp) -const - atomicTypes = {tyBool, tyChar, - tyUntyped, tyTyped, tyTypeDesc, tyStatic, - tyEnum, - tyOrdinal, - tyRange, - tyProc, - tyPointer, tyOpenArray, - tyString, tyCString, - tyInt, tyInt8, tyInt16, tyInt32, tyInt64, - tyFloat, tyFloat32, tyFloat64, tyFloat128, - tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64} - proc unneededIndirection(n: PNode): bool = n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef @@ -2200,7 +2187,7 @@ proc optimizeJumps(c: PCtx; start: int) = for iters in countdown(maxIterations, 0): case c.code[d].opcode of opcJmp: - d = d + c.code[d].jmpDiff + d += c.code[d].jmpDiff of opcTJmp, opcFJmp: if c.code[d].regA != reg: break # tjmp x, 23 @@ -2208,12 +2195,12 @@ proc optimizeJumps(c: PCtx; start: int) = # tjmp x, 12 # -- we know 'x' is true, and so can jump to 12+13: if c.code[d].opcode == opc: - d = d + c.code[d].jmpDiff + d += c.code[d].jmpDiff else: # tjmp x, 23 # fjmp x, 22 # We know 'x' is true so skip to the next instruction: - d = d + 1 + d += 1 else: break if d != i + c.code[i].jmpDiff: c.finalJumpTarget(i, d - i) @@ -2221,7 +2208,7 @@ proc optimizeJumps(c: PCtx; start: int) = var d = i + c.code[i].jmpDiff var iters = maxIterations while c.code[d].opcode == opcJmp and iters > 0: - d = d + c.code[d].jmpDiff + d += c.code[d].jmpDiff dec iters if c.code[d].opcode == opcRet: # optimize 'jmp to ret' to 'ret' here diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 454224ae4..e8d03fe4b 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -104,8 +104,7 @@ const wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing} - specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", - + specialWords*: array[TSpecialWord, string] = ["", "addr", "and", "as", "asm", "bind", "block", "break", "case", "cast", "concept", "const", "continue", "converter", @@ -129,35 +128,35 @@ const "immediate", "constructor", "destructor", "delegator", "override", "importcpp", "importobjc", - "importcompilerproc", "importc", "importjs", "exportc", "exportcpp", "exportnims", - "incompletestruct", - "completestruct", - "requiresinit", "align", "nodecl", "pure", "sideeffect", - "header", "nosideeffect", "gcsafe", "noreturn", "nosinks", "merge", "lib", "dynlib", + "importCompilerProc", "importc", "importjs", "exportc", "exportcpp", "exportnims", + "incompleteStruct", + "completeStruct", + "requiresInit", "align", "nodecl", "pure", "sideEffect", + "header", "noSideEffect", "gcsafe", "noreturn", "nosinks", "merge", "lib", "dynlib", "compilerproc", "core", "procvar", "base", "used", - "fatal", "error", "warning", "hint", "warningaserror", "line", - "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", + "fatal", "error", "warning", "hint", "warningAsError", "line", + "push", "pop", "define", "undef", "lineDir", "stackTrace", "lineTrace", "link", "compile", "linksys", "deprecated", "varargs", "callconv", "debugger", "nimcall", "stdcall", "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", "closure", - "noconv", "on", "off", "checks", "rangechecks", "boundchecks", - "overflowchecks", "nilchecks", - "floatchecks", "nanchecks", "infchecks", "stylechecks", "staticboundchecks", - "nonreloadable", "executeonreload", + "noconv", "on", "off", "checks", "rangeChecks", "boundChecks", + "overflowChecks", "nilChecks", + "floatChecks", "nanChecks", "infChecks", "styleChecks", "staticBoundChecks", + "nonReloadable", "executeOnReload", "assertions", "patterns", "trmacros", "sinkinference", "warnings", "hints", "optimization", "raises", "writes", "reads", "size", "effects", "tags", "requires", "ensures", "invariant", "assume", "assert", - "deadcodeelim", # deprecated, dead code elim always happens + "deadCodeElim", # deprecated, dead code elim always happens "safecode", "package", "noforward", "reorder", "norewrite", "nodestroy", "pragma", - "compiletime", "noinit", - "passc", "passl", "localpassc", "borrow", "discardable", "fieldchecks", - "subschar", "acyclic", "shallow", "unroll", "linearscanend", - "computedgoto", "injectstmt", "experimental", + "compileTime", "noinit", + "passc", "passl", "localPassC", "borrow", "discardable", "fieldChecks", + "subschar", "acyclic", "shallow", "unroll", "linearScanEnd", + "computedGoto", "injectStmt", "experimental", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", - "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked", - "guard", "locks", "partial", "explain", "liftlocals", + "asmNoStackFrame", "implicitStatic", "global", "codegenDecl", "unchecked", + "guard", "locks", "partial", "explain", "liftLocals", "auto", "bool", "catch", "char", "class", "compl", "const_cast", "default", "delete", "double", @@ -184,38 +183,3 @@ proc findStr*(a: openArray[string], s: string): int = if cmpIgnoreStyle(a[i], s) == 0: return i result = - 1 - -proc canonPragmaSpelling*(w: TSpecialWord): string = - case w - of wNoSideEffect: "noSideEffect" - of wImportCompilerProc: "importCompilerProc" - of wIncompleteStruct: "incompleteStruct" - of wCompleteStruct: "completeStruct" - of wRequiresInit: "requiresInit" - of wSideEffect: "sideEffect" - of wLineDir: "lineDir" - of wStackTrace: "stackTrace" - of wLineTrace: "lineTrace" - of wRangeChecks: "rangeChecks" - of wBoundChecks: "boundChecks" - of wOverflowChecks: "overflowChecks" - of wNilChecks: "nilChecks" - of wFloatChecks: "floatChecks" - of wNanChecks: "nanChecks" - of wInfChecks: "infChecks" - of wStyleChecks: "styleChecks" - of wNonReloadable: "nonReloadable" - of wExecuteOnReload: "executeOnReload" - of wDeadCodeElimUnused: "deadCodeElim" - of wCompileTime: "compileTime" - of wFieldChecks: "fieldChecks" - of wLinearScanEnd: "linearScanEnd" - of wComputedGoto: "computedGoto" - of wInjectStmt: "injectStmt" - of wAsmNoStackFrame: "asmNoStackFrame" - of wImplicitStatic: "implicitStatic" - of wCodegenDecl: "codegenDecl" - of wLiftLocals: "liftLocals" - of wLocalPassc: "localPassc" - of wWarningAsError: "warningAsError" - else: specialWords[w] diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index bedf9f248..0fb2c6a9e 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -54,12 +54,12 @@ proc prettyPrint(infile, outfile: string, opt: PrettyOptions) = let f = splitFile(outfile.expandTilde) conf.outFile = RelativeFile f.name & f.ext conf.outDir = toAbsoluteDir f.dir - var p: TParsers - p.parser.em.indWidth = opt.indWidth - if setupParsers(p, fileIdx, newIdentCache(), conf): - p.parser.em.maxLineLen = opt.maxLineLen - discard parseAll(p) - closeParsers(p) + var parser: Parser + parser.em.indWidth = opt.indWidth + if setupParser(parser, fileIdx, newIdentCache(), conf): + parser.em.maxLineLen = opt.maxLineLen + discard parseAll(parser) + closeParser(parser) proc main = var outfile, outdir: string diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim index d07c2bf8c..397041559 100644 --- a/tools/grammar_nanny.nim +++ b/tools/grammar_nanny.nim @@ -16,8 +16,8 @@ proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = if stream != nil: declaredSyms.incl "section" # special case for 'section(RULE)' in the grammar var - L: TLexer - tok: TToken + L: Lexer + tok: Token initToken(tok) openLexer(L, f, stream, cache, config) # load the first token: diff --git a/tools/nimfind.nim b/tools/nimfind.nim index 05980d740..4ad5fbb4f 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -195,8 +195,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = of cmdArgument: let info = p.key.split(':') if info.len == 3: - let (dir, file, ext) = info[0].splitFile() - conf.projectName = findProjectNimFile(conf, dir) + conf.projectName = findProjectNimFile(conf, info[0].splitFile.dir) if conf.projectName.len == 0: conf.projectName = info[0] try: conf.m.trackPos = newLineInfo(conf, AbsoluteFile info[0], From b5424b826e57c791a751bf31b69549c7d8daab0b Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Sat, 29 Aug 2020 08:06:11 -0400 Subject: [PATCH 1048/4254] template hygiene (#15240) --- lib/pure/os.nim | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 8bbceddeb..e7087acf7 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -3080,14 +3080,15 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, fpOthersExec, fpOthersRead} else: - result.permissions = {fpUserExec..fpOthersRead} + formalInfo.permissions = {fpUserExec..fpOthersRead} # Retrieve basic file kind - result.kind = pcFile if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32: formalInfo.kind = pcDir + else: + formalInfo.kind = pcFile if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32: - formalInfo.kind = succ(result.kind) + formalInfo.kind = succ(formalInfo.kind) else: template checkAndIncludeMode(rawMode, formalMode: untyped) = @@ -3100,7 +3101,7 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.lastWriteTime = rawInfo.st_mtim.toTime formalInfo.creationTime = rawInfo.st_ctim.toTime - result.permissions = {} + formalInfo.permissions = {} checkAndIncludeMode(S_IRUSR, fpUserRead) checkAndIncludeMode(S_IWUSR, fpUserWrite) checkAndIncludeMode(S_IXUSR, fpUserExec) @@ -3113,12 +3114,14 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = checkAndIncludeMode(S_IWOTH, fpOthersWrite) checkAndIncludeMode(S_IXOTH, fpOthersExec) - formalInfo.kind = pcFile - if S_ISDIR(rawInfo.st_mode): - formalInfo.kind = pcDir - elif S_ISLNK(rawInfo.st_mode): - assert(path != "") # symlinks can't occur for file handles - formalInfo.kind = getSymlinkFileKind(path) + formalInfo.kind = + if S_ISDIR(rawInfo.st_mode): + pcDir + elif S_ISLNK(rawInfo.st_mode): + assert(path != "") # symlinks can't occur for file handles + getSymlinkFileKind(path) + else: + pcFile when defined(js): when not declared(FileHandle): From a76ae8f79584c5a491861daf2efda9908b21e488 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Mon, 31 Aug 2020 03:48:54 -0600 Subject: [PATCH 1049/4254] Changes for FreeRTOS/LwIP Port for the ESP32 (ESP-IDF) (#15250) * Changes for FreeRTOS/LwIP Port for the ESP32 (ESP-IDF) Adding FreeRTOS/LwIP to compiler: * adding freertos option * dyncalls for freertos * add freertos to posix os list * adding lwip option Setting up networking FreeRTOS/LwIP Port: * setting up lwip network for freertos * fixing posix / networking for freertos * disable setInheritable for freerots * using lwip for net control items * Fix builds by ignoring lib/posix/posix_freertos_consts.nim similar to lib/posix/posix_other_consts.nim --- compiler/options.nim | 6 +- compiler/platform.nim | 9 +- lib/posix/posix.nim | 17 +- lib/posix/posix_freertos_consts.nim | 488 ++++++++++++++++++++++ lib/posix/posix_other.nim | 80 +++- lib/pure/ioselects/ioselectors_select.nim | 2 +- lib/pure/nativesockets.nim | 2 +- lib/pure/selectors.nim | 2 + lib/system/dyncalls.nim | 2 +- lib/system/io.nim | 12 +- tools/kochdocs.nim | 1 + 11 files changed, 589 insertions(+), 32 deletions(-) create mode 100644 lib/posix/posix_freertos_consts.nim diff --git a/compiler/options.nim b/compiler/options.nim index 8ff8cb753..56b061358 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -494,7 +494,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osQnx, osAtari, osAix, osHaiku, osVxWorks, osSolaris, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos, - osAndroid, osNintendoSwitch} + osAndroid, osNintendoSwitch, osFreeRTOS} of "linux": result = conf.target.targetOS in {osLinux, osAndroid} of "bsd": @@ -510,6 +510,10 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = of "sunos": result = conf.target.targetOS == osSolaris of "nintendoswitch": result = conf.target.targetOS == osNintendoSwitch + of "freertos": + result = conf.target.targetOS == osFreeRTOS + of "lwip": + result = conf.target.targetOS in {osFreeRTOS} of "littleendian": result = CPU[conf.target.targetCPU].endian == platform.littleEndian of "bigendian": result = CPU[conf.target.targetCPU].endian == platform.bigEndian of "cpu8": result = CPU[conf.target.targetCPU].bit == 8 diff --git a/compiler/platform.nim b/compiler/platform.nim index 4bac7c5a1..df79b2f8d 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -22,7 +22,7 @@ type osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx, osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks - osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osAny + osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny type TInfoOSProp* = enum @@ -177,6 +177,10 @@ const objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", props: {ospNeedsPIC, ospPosix}), + (name: "FreeRTOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", + props: {ospPosix}), (name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", @@ -189,7 +193,7 @@ type cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430, - cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuWasm32 + cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuEsp, cpuWasm32 type TEndian* = enum @@ -223,6 +227,7 @@ const (name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64), (name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), + (name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)] type diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index d3d9728ab..c7a324cde 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -962,9 +962,15 @@ proc IN6_IS_ADDR_LINKLOCAL* (a1: ptr In6Addr): cint {. proc IN6_IS_ADDR_SITELOCAL* (a1: ptr In6Addr): cint {. importc, header: "".} ## Unicast site-local address. -proc IN6_IS_ADDR_V4MAPPED* (a1: ptr In6Addr): cint {. - importc, header: "".} - ## IPv4 mapped address. +when defined(lwip): + proc IN6_IS_ADDR_V4MAPPED*(ipv6_address: ptr In6Addr): cint = + var bits32: ptr array[4, uint32] = cast[ptr array[4, uint32]](ipv6_address) + return (bits32[1] == 0'u32 and bits32[2] == htonl(0x0000FFFF)).cint +else: + proc IN6_IS_ADDR_V4MAPPED* (a1: ptr In6Addr): cint {. + importc, header: "".} + ## IPv4 mapped address. + proc IN6_IS_ADDR_V4COMPAT* (a1: ptr In6Addr): cint {. importc, header: "".} ## IPv4-compatible address. @@ -1026,8 +1032,9 @@ proc setnetent*(a1: cint) {.importc, header: "".} proc setprotoent*(a1: cint) {.importc, header: "".} proc setservent*(a1: cint) {.importc, header: "".} -proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {. - importc, header: "", sideEffect.} +when not defined(lwip): + proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {. + importc, header: "", sideEffect.} proc realpath*(name, resolved: cstring): cstring {. importc: "realpath", header: "".} diff --git a/lib/posix/posix_freertos_consts.nim b/lib/posix/posix_freertos_consts.nim new file mode 100644 index 000000000..5e83fa0f5 --- /dev/null +++ b/lib/posix/posix_freertos_consts.nim @@ -0,0 +1,488 @@ +# Generated by detect.nim + + + +# +var E2BIG* {.importc: "E2BIG", header: "".}: cint +var EACCES* {.importc: "EACCES", header: "".}: cint +var EADDRINUSE* {.importc: "EADDRINUSE", header: "".}: cint +var EADDRNOTAVAIL* {.importc: "EADDRNOTAVAIL", header: "".}: cint +var EAFNOSUPPORT* {.importc: "EAFNOSUPPORT", header: "".}: cint +var EAGAIN* {.importc: "EAGAIN", header: "".}: cint +var EALREADY* {.importc: "EALREADY", header: "".}: cint +var EBADF* {.importc: "EBADF", header: "".}: cint +var EBADMSG* {.importc: "EBADMSG", header: "".}: cint +var EBUSY* {.importc: "EBUSY", header: "".}: cint +var ECANCELED* {.importc: "ECANCELED", header: "".}: cint +var ECHILD* {.importc: "ECHILD", header: "".}: cint +var ECONNABORTED* {.importc: "ECONNABORTED", header: "".}: cint +var ECONNREFUSED* {.importc: "ECONNREFUSED", header: "".}: cint +var ECONNRESET* {.importc: "ECONNRESET", header: "".}: cint +var EDEADLK* {.importc: "EDEADLK", header: "".}: cint +var EDESTADDRREQ* {.importc: "EDESTADDRREQ", header: "".}: cint +var EDOM* {.importc: "EDOM", header: "".}: cint +var EDQUOT* {.importc: "EDQUOT", header: "".}: cint +var EEXIST* {.importc: "EEXIST", header: "".}: cint +var EFAULT* {.importc: "EFAULT", header: "".}: cint +var EFBIG* {.importc: "EFBIG", header: "".}: cint +var EHOSTUNREACH* {.importc: "EHOSTUNREACH", header: "".}: cint +var EIDRM* {.importc: "EIDRM", header: "".}: cint +var EILSEQ* {.importc: "EILSEQ", header: "".}: cint +var EINPROGRESS* {.importc: "EINPROGRESS", header: "".}: cint +var EINTR* {.importc: "EINTR", header: "".}: cint +var EINVAL* {.importc: "EINVAL", header: "".}: cint +var EIO* {.importc: "EIO", header: "".}: cint +var EISCONN* {.importc: "EISCONN", header: "".}: cint +var EISDIR* {.importc: "EISDIR", header: "".}: cint +var ELOOP* {.importc: "ELOOP", header: "".}: cint +var EMFILE* {.importc: "EMFILE", header: "".}: cint +var EMLINK* {.importc: "EMLINK", header: "".}: cint +var EMSGSIZE* {.importc: "EMSGSIZE", header: "".}: cint +var EMULTIHOP* {.importc: "EMULTIHOP", header: "".}: cint +var ENAMETOOLONG* {.importc: "ENAMETOOLONG", header: "".}: cint +var ENETDOWN* {.importc: "ENETDOWN", header: "".}: cint +var ENETRESET* {.importc: "ENETRESET", header: "".}: cint +var ENETUNREACH* {.importc: "ENETUNREACH", header: "".}: cint +var ENFILE* {.importc: "ENFILE", header: "".}: cint +var ENOBUFS* {.importc: "ENOBUFS", header: "".}: cint +var ENODATA* {.importc: "ENODATA", header: "".}: cint +var ENODEV* {.importc: "ENODEV", header: "".}: cint +var ENOENT* {.importc: "ENOENT", header: "".}: cint +var ENOEXEC* {.importc: "ENOEXEC", header: "".}: cint +var ENOLCK* {.importc: "ENOLCK", header: "".}: cint +var ENOLINK* {.importc: "ENOLINK", header: "".}: cint +var ENOMEM* {.importc: "ENOMEM", header: "".}: cint +var ENOMSG* {.importc: "ENOMSG", header: "".}: cint +var ENOPROTOOPT* {.importc: "ENOPROTOOPT", header: "".}: cint +var ENOSPC* {.importc: "ENOSPC", header: "".}: cint +var ENOSR* {.importc: "ENOSR", header: "".}: cint +var ENOSTR* {.importc: "ENOSTR", header: "".}: cint +var ENOSYS* {.importc: "ENOSYS", header: "".}: cint +var ENOTCONN* {.importc: "ENOTCONN", header: "".}: cint +var ENOTDIR* {.importc: "ENOTDIR", header: "".}: cint +var ENOTEMPTY* {.importc: "ENOTEMPTY", header: "".}: cint +var ENOTSOCK* {.importc: "ENOTSOCK", header: "".}: cint +var ENOTSUP* {.importc: "ENOTSUP", header: "".}: cint +var ENOTTY* {.importc: "ENOTTY", header: "".}: cint +var ENXIO* {.importc: "ENXIO", header: "".}: cint +var EOPNOTSUPP* {.importc: "EOPNOTSUPP", header: "".}: cint +var EOVERFLOW* {.importc: "EOVERFLOW", header: "".}: cint +var EPERM* {.importc: "EPERM", header: "".}: cint +var EPIPE* {.importc: "EPIPE", header: "".}: cint +var EPROTO* {.importc: "EPROTO", header: "".}: cint +var EPROTONOSUPPORT* {.importc: "EPROTONOSUPPORT", header: "".}: cint +var EPROTOTYPE* {.importc: "EPROTOTYPE", header: "".}: cint +var ERANGE* {.importc: "ERANGE", header: "".}: cint +var EROFS* {.importc: "EROFS", header: "".}: cint +var ESPIPE* {.importc: "ESPIPE", header: "".}: cint +var ESRCH* {.importc: "ESRCH", header: "".}: cint +var ESTALE* {.importc: "ESTALE", header: "".}: cint +var ETIME* {.importc: "ETIME", header: "".}: cint +var ETIMEDOUT* {.importc: "ETIMEDOUT", header: "".}: cint +var ETXTBSY* {.importc: "ETXTBSY", header: "".}: cint +var EWOULDBLOCK* {.importc: "EWOULDBLOCK", header: "".}: cint +var EXDEV* {.importc: "EXDEV", header: "".}: cint + +# +var F_GETFD* {.importc: "F_GETFD", header: "".}: cint +# var F_SETFD* {.importc: "F_SETFD", header: "".}: cint +var F_GETFL* {.importc: "F_GETFL", header: "".}: cint +var F_SETFL* {.importc: "F_SETFL", header: "".}: cint +# var F_GETLK* {.importc: "F_GETLK", header: "".}: cint +# var F_SETLK* {.importc: "F_SETLK", header: "".}: cint +# var F_SETLKW* {.importc: "F_SETLKW", header: "".}: cint +# var F_GETOWN* {.importc: "F_GETOWN", header: "".}: cint +# var F_SETOWN* {.importc: "F_SETOWN", header: "".}: cint +# var FD_CLOEXEC* {.importc: "FD_CLOEXEC", header: "".}: cint +# var F_RDLCK* {.importc: "F_RDLCK", header: "".}: cint +# var F_UNLCK* {.importc: "F_UNLCK", header: "".}: cint +# var F_WRLCK* {.importc: "F_WRLCK", header: "".}: cint +var O_CREAT* {.importc: "O_CREAT", header: "".}: cint +var O_EXCL* {.importc: "O_EXCL", header: "".}: cint +# var O_NOCTTY* {.importc: "O_NOCTTY", header: "".}: cint +var O_TRUNC* {.importc: "O_TRUNC", header: "".}: cint +var O_APPEND* {.importc: "O_APPEND", header: "".}: cint +# var O_DSYNC* {.importc: "O_DSYNC", header: "".}: cint +var O_NONBLOCK* {.importc: "O_NONBLOCK", header: "".}: cint +# var O_RSYNC* {.importc: "O_RSYNC", header: "".}: cint +# var O_SYNC* {.importc: "O_SYNC", header: "".}: cint +# var O_ACCMODE* {.importc: "O_ACCMODE", header: "".}: cint +var O_RDONLY* {.importc: "O_RDONLY", header: "".}: cint +var O_RDWR* {.importc: "O_RDWR", header: "".}: cint +var O_WRONLY* {.importc: "O_WRONLY", header: "".}: cint +# var O_CLOEXEC* {.importc: "O_CLOEXEC", header: "".}: cint + +# # +# var LC_ALL* {.importc: "LC_ALL", header: "".}: cint +# var LC_COLLATE* {.importc: "LC_COLLATE", header: "".}: cint +# var LC_CTYPE* {.importc: "LC_CTYPE", header: "".}: cint +# var LC_MESSAGES* {.importc: "LC_MESSAGES", header: "".}: cint +# var LC_MONETARY* {.importc: "LC_MONETARY", header: "".}: cint +# var LC_NUMERIC* {.importc: "LC_NUMERIC", header: "".}: cint +# var LC_TIME* {.importc: "LC_TIME", header: "".}: cint + +# +var HOST_NOT_FOUND* {.importc: "HOST_NOT_FOUND", header: "".}: cint +var NO_DATA* {.importc: "NO_DATA", header: "".}: cint +var NO_RECOVERY* {.importc: "NO_RECOVERY", header: "".}: cint +var TRY_AGAIN* {.importc: "TRY_AGAIN", header: "".}: cint +var AI_PASSIVE* {.importc: "AI_PASSIVE", header: "".}: cint +var AI_CANONNAME* {.importc: "AI_CANONNAME", header: "".}: cint +var AI_NUMERICHOST* {.importc: "AI_NUMERICHOST", header: "".}: cint +var AI_NUMERICSERV* {.importc: "AI_NUMERICSERV", header: "".}: cint +var AI_V4MAPPED* {.importc: "AI_V4MAPPED", header: "".}: cint +var AI_ALL* {.importc: "AI_ALL", header: "".}: cint +var AI_ADDRCONFIG* {.importc: "AI_ADDRCONFIG", header: "".}: cint +var NI_NOFQDN* {.importc: "NI_NOFQDN", header: "".}: cint +var NI_NUMERICHOST* {.importc: "NI_NUMERICHOST", header: "".}: cint +var NI_NAMEREQD* {.importc: "NI_NAMEREQD", header: "".}: cint +var NI_NUMERICSERV* {.importc: "NI_NUMERICSERV", header: "".}: cint +var NI_DGRAM* {.importc: "NI_DGRAM", header: "".}: cint +var EAI_AGAIN* {.importc: "EAI_AGAIN", header: "".}: cint +var EAI_BADFLAGS* {.importc: "EAI_BADFLAGS", header: "".}: cint +var EAI_FAIL* {.importc: "EAI_FAIL", header: "".}: cint +var EAI_FAMILY* {.importc: "EAI_FAMILY", header: "".}: cint +var EAI_MEMORY* {.importc: "EAI_MEMORY", header: "".}: cint +var EAI_NONAME* {.importc: "EAI_NONAME", header: "".}: cint +var EAI_SERVICE* {.importc: "EAI_SERVICE", header: "".}: cint +var EAI_SOCKTYPE* {.importc: "EAI_SOCKTYPE", header: "".}: cint + +var LWIP_DNS_API_DECLARE_H_ERRNO* {.importc: "LWIP_DNS_API_DECLARE_H_ERRNO", header: "".}: cint +var LWIP_DNS_API_DEFINE_ERRORS* {.importc: "LWIP_DNS_API_DEFINE_ERRORS", header: "".}: cint +var LWIP_DNS_API_DEFINE_FLAGS* {.importc: "LWIP_DNS_API_DEFINE_FLAGS", header: "".}: cint +var LWIP_DNS_API_DECLARE_STRUCTS* {.importc: "LWIP_DNS_API_DECLARE_STRUCTS", header: "".}: cint +var NETDB_ELEM_SIZE* {.importc: "NETDB_ELEM_SIZE", header: "".}: cint + + +# +var ENABLE_LOOPBACK* {.importc: "ENABLE_LOOPBACK", header: "".}: cint +var NETIF_MAX_HWADDR_LEN* {.importc: "NETIF_MAX_HWADDR_LEN", header: "".}: cint +var NETIF_NAMESIZE* {.importc: "NETIF_NAMESIZE", header: "".}: cint +var NETIF_FLAG_UP* {.importc: "NETIF_FLAG_UP", header: "".}: cint +var NETIF_FLAG_BROADCAST* {.importc: "NETIF_FLAG_BROADCAST", header: "".}: cint +var NETIF_FLAG_LINK_UP* {.importc: "NETIF_FLAG_LINK_UP", header: "".}: cint +var NETIF_FLAG_ETHARP* {.importc: "NETIF_FLAG_ETHARP", header: "".}: cint +var NETIF_FLAG_ETHERNET* {.importc: "NETIF_FLAG_ETHERNET", header: "".}: cint +var NETIF_FLAG_IGMP* {.importc: "NETIF_FLAG_IGMP", header: "".}: cint +var NETIF_FLAG_MLD6* {.importc: "NETIF_FLAG_MLD6", header: "".}: cint +var NETIF_FLAG_GARP* {.importc: "NETIF_FLAG_GARP", header: "".}: cint +var NETIF_CHECKSUM_GEN_IP* {.importc: "NETIF_CHECKSUM_GEN_IP", header: "".}: cint +var NETIF_CHECKSUM_GEN_UDP* {.importc: "NETIF_CHECKSUM_GEN_UDP", header: "".}: cint +var NETIF_CHECKSUM_GEN_TCP* {.importc: "NETIF_CHECKSUM_GEN_TCP", header: "".}: cint +var NETIF_CHECKSUM_GEN_ICMP* {.importc: "NETIF_CHECKSUM_GEN_ICMP", header: "".}: cint +var NETIF_CHECKSUM_GEN_ICMP6* {.importc: "NETIF_CHECKSUM_GEN_ICMP6", header: "".}: cint +var NETIF_CHECKSUM_CHECK_IP* {.importc: "NETIF_CHECKSUM_CHECK_IP", header: "".}: cint +var NETIF_CHECKSUM_CHECK_UDP* {.importc: "NETIF_CHECKSUM_CHECK_UDP", header: "".}: cint +var NETIF_CHECKSUM_CHECK_TCP* {.importc: "NETIF_CHECKSUM_CHECK_TCP", header: "".}: cint +var NETIF_CHECKSUM_CHECK_ICMP* {.importc: "NETIF_CHECKSUM_CHECK_ICMP", header: "".}: cint +var NETIF_CHECKSUM_CHECK_ICMP6* {.importc: "NETIF_CHECKSUM_CHECK_ICMP6", header: "".}: cint +var NETIF_CHECKSUM_ENABLE_ALL* {.importc: "NETIF_CHECKSUM_ENABLE_ALL", header: "".}: cint +var NETIF_CHECKSUM_DISABLE_ALL* {.importc: "NETIF_CHECKSUM_DISABLE_ALL", header: "".}: cint +var NETIF_ADDR_IDX_MAX* {.importc: "NETIF_ADDR_IDX_MAX", header: "".}: cint +var LWIP_NETIF_USE_HINTS* {.importc: "LWIP_NETIF_USE_HINTS", header: "".}: cint +var NETIF_NO_INDEX* {.importc: "NETIF_NO_INDEX", header: "".}: cint +var LWIP_NSC_NONE* {.importc: "LWIP_NSC_NONE", header: "".}: cint +var LWIP_NSC_NETIF_ADDED* {.importc: "LWIP_NSC_NETIF_ADDED", header: "".}: cint +var LWIP_NSC_NETIF_REMOVED* {.importc: "LWIP_NSC_NETIF_REMOVED", header: "".}: cint +var LWIP_NSC_LINK_CHANGED* {.importc: "LWIP_NSC_LINK_CHANGED", header: "".}: cint +var LWIP_NSC_STATUS_CHANGED* {.importc: "LWIP_NSC_STATUS_CHANGED", header: "".}: cint +var LWIP_NSC_IPV4_ADDRESS_CHANGED* {.importc: "LWIP_NSC_IPV4_ADDRESS_CHANGED", header: "".}: cint +var LWIP_NSC_IPV4_GATEWAY_CHANGED* {.importc: "LWIP_NSC_IPV4_GATEWAY_CHANGED", header: "".}: cint +var LWIP_NSC_IPV4_NETMASK_CHANGED* {.importc: "LWIP_NSC_IPV4_NETMASK_CHANGED", header: "".}: cint +var LWIP_NSC_IPV4_SETTINGS_CHANGED* {.importc: "LWIP_NSC_IPV4_SETTINGS_CHANGED", header: "".}: cint +var LWIP_NSC_IPV6_SET* {.importc: "LWIP_NSC_IPV6_SET", header: "".}: cint +var LWIP_NSC_IPV6_ADDR_STATE_CHANGED* {.importc: "LWIP_NSC_IPV6_ADDR_STATE_CHANGED", header: "".}: cint +#define NETIF_DECLARE_EXT_CALLBACK(name) + + +# +var IF_NAMESIZE* {.importc: "IF_NAMESIZE", header: "".}: cint + +# +var IPPROTO_IP* {.importc: "IPPROTO_IP", header: "".}: cint +var IPPROTO_IPV6* {.importc: "IPPROTO_IPV6", header: "".}: cint +var IPPROTO_ICMP* {.importc: "IPPROTO_ICMP", header: "".}: cint +var IPPROTO_ICMPV6* {.importc: "IPPROTO_ICMPV6", header: "".}: cint +var IPPROTO_RAW* {.importc: "IPPROTO_RAW", header: "".}: cint +var IPPROTO_TCP* {.importc: "IPPROTO_TCP", header: "".}: cint +var IPPROTO_UDP* {.importc: "IPPROTO_UDP", header: "".}: cint +var INADDR_ANY* {.importc: "INADDR_ANY", header: "".}: InAddrScalar +var INADDR_LOOPBACK* {.importc: "INADDR_LOOPBACK", header: "".}: InAddrScalar +var INADDR_BROADCAST* {.importc: "INADDR_BROADCAST", header: "".}: InAddrScalar +var INET_ADDRSTRLEN* {.importc: "INET_ADDRSTRLEN", header: "".}: cint +var INET6_ADDRSTRLEN* {.importc: "INET6_ADDRSTRLEN", header: "".}: cint +var IPV6_JOIN_GROUP* {.importc: "IPV6_JOIN_GROUP", header: "".}: cint +var IPV6_LEAVE_GROUP* {.importc: "IPV6_LEAVE_GROUP", header: "".}: cint +var IPV6_MULTICAST_HOPS* {.importc: "IPV6_MULTICAST_HOPS", header: "".}: cint +var IPV6_MULTICAST_IF* {.importc: "IPV6_MULTICAST_IF", header: "".}: cint +var IPV6_MULTICAST_LOOP* {.importc: "IPV6_MULTICAST_LOOP", header: "".}: cint +var IPV6_UNICAST_HOPS* {.importc: "IPV6_UNICAST_HOPS", header: "".}: cint +var IPV6_V6ONLY* {.importc: "IPV6_V6ONLY", header: "".}: cint + +# +var TCP_NODELAY* {.importc: "TCP_NODELAY", header: "".}: cint +var TCP_KEEPALIVE* {.importc: "TCP_KEEPALIVE", header: "".}: cint +var TCP_KEEPIDLE* {.importc: "TCP_KEEPIDLE", header: "".}: cint +var TCP_KEEPINTVL* {.importc: "TCP_KEEPINTVL", header: "".}: cint +var TCP_KEEPCNT* {.importc: "TCP_KEEPCNT", header: "".}: cint + +# +# var NL_SETD* {.importc: "NL_SETD", header: "".}: cint +# var NL_CAT_LOCALE* {.importc: "NL_CAT_LOCALE", header: "".}: cint + +# +# var POLLIN* {.importc: "POLLIN", header: "".}: cshort +# var POLLRDNORM* {.importc: "POLLRDNORM", header: "".}: cshort +# var POLLRDBAND* {.importc: "POLLRDBAND", header: "".}: cshort +# var POLLPRI* {.importc: "POLLPRI", header: "".}: cshort +# var POLLOUT* {.importc: "POLLOUT", header: "".}: cshort +# var POLLWRNORM* {.importc: "POLLWRNORM", header: "".}: cshort +# var POLLWRBAND* {.importc: "POLLWRBAND", header: "".}: cshort +# var POLLERR* {.importc: "POLLERR", header: "".}: cshort +# var POLLHUP* {.importc: "POLLHUP", header: "".}: cshort +# var POLLNVAL* {.importc: "POLLNVAL", header: "".}: cshort + +# +var PTHREAD_STACK_MIN* {.importc: "PTHREAD_STACK_MIN", header: "".}: cint +# var PTHREAD_BARRIER_SERIAL_THREAD* {.importc: "PTHREAD_BARRIER_SERIAL_THREAD", header: "".}: cint +# var PTHREAD_CANCEL_ASYNCHRONOUS* {.importc: "PTHREAD_CANCEL_ASYNCHRONOUS", header: "".}: cint +# var PTHREAD_CANCEL_ENABLE* {.importc: "PTHREAD_CANCEL_ENABLE", header: "".}: cint +# var PTHREAD_CANCEL_DEFERRED* {.importc: "PTHREAD_CANCEL_DEFERRED", header: "".}: cint +# var PTHREAD_CANCEL_DISABLE* {.importc: "PTHREAD_CANCEL_DISABLE", header: "".}: cint +# var PTHREAD_CREATE_DETACHED* {.importc: "PTHREAD_CREATE_DETACHED", header: "".}: cint +# var PTHREAD_CREATE_JOINABLE* {.importc: "PTHREAD_CREATE_JOINABLE", header: "".}: cint +# var PTHREAD_EXPLICIT_SCHED* {.importc: "PTHREAD_EXPLICIT_SCHED", header: "".}: cint +# var PTHREAD_INHERIT_SCHED* {.importc: "PTHREAD_INHERIT_SCHED", header: "".}: cint +# var PTHREAD_MUTEX_DEFAULT* {.importc: "PTHREAD_MUTEX_DEFAULT", header: "".}: cint +# var PTHREAD_MUTEX_ERRORCHECK* {.importc: "PTHREAD_MUTEX_ERRORCHECK", header: "".}: cint +# var PTHREAD_MUTEX_NORMAL* {.importc: "PTHREAD_MUTEX_NORMAL", header: "".}: cint +# var PTHREAD_MUTEX_RECURSIVE* {.importc: "PTHREAD_MUTEX_RECURSIVE", header: "".}: cint +# var PTHREAD_PRIO_INHERIT* {.importc: "PTHREAD_PRIO_INHERIT", header: "".}: cint +# var PTHREAD_PRIO_NONE* {.importc: "PTHREAD_PRIO_NONE", header: "".}: cint +# var PTHREAD_PRIO_PROTECT* {.importc: "PTHREAD_PRIO_PROTECT", header: "".}: cint +# var PTHREAD_PROCESS_SHARED* {.importc: "PTHREAD_PROCESS_SHARED", header: "".}: cint +# var PTHREAD_PROCESS_PRIVATE* {.importc: "PTHREAD_PROCESS_PRIVATE", header: "".}: cint +# var PTHREAD_SCOPE_PROCESS* {.importc: "PTHREAD_SCOPE_PROCESS", header: "".}: cint +# var PTHREAD_SCOPE_SYSTEM* {.importc: "PTHREAD_SCOPE_SYSTEM", header: "".}: cint + +# # +# var SCHED_FIFO* {.importc: "SCHED_FIFO", header: "".}: cint +# var SCHED_RR* {.importc: "SCHED_RR", header: "".}: cint +# var SCHED_SPORADIC* {.importc: "SCHED_SPORADIC", header: "".}: cint +# var SCHED_OTHER* {.importc: "SCHED_OTHER", header: "".}: cint + +# +var SEM_FAILED* {.importc: "SEM_FAILED", header: "".}: pointer + +# # +# var SIGEV_NONE* {.importc: "SIGEV_NONE", header: "".}: cint +# var SIGEV_SIGNAL* {.importc: "SIGEV_SIGNAL", header: "".}: cint +# var SIGEV_THREAD* {.importc: "SIGEV_THREAD", header: "".}: cint +# var SIGABRT* {.importc: "SIGABRT", header: "".}: cint +# var SIGALRM* {.importc: "SIGALRM", header: "".}: cint +# var SIGBUS* {.importc: "SIGBUS", header: "".}: cint +# var SIGCHLD* {.importc: "SIGCHLD", header: "".}: cint +# var SIGCONT* {.importc: "SIGCONT", header: "".}: cint +# var SIGFPE* {.importc: "SIGFPE", header: "".}: cint +# var SIGHUP* {.importc: "SIGHUP", header: "".}: cint +# var SIGILL* {.importc: "SIGILL", header: "".}: cint +# var SIGINT* {.importc: "SIGINT", header: "".}: cint +# var SIGKILL* {.importc: "SIGKILL", header: "".}: cint +# var SIGPIPE* {.importc: "SIGPIPE", header: "".}: cint +# var SIGQUIT* {.importc: "SIGQUIT", header: "".}: cint +# var SIGSEGV* {.importc: "SIGSEGV", header: "".}: cint +# var SIGSTOP* {.importc: "SIGSTOP", header: "".}: cint +# var SIGTERM* {.importc: "SIGTERM", header: "".}: cint +# var SIGTSTP* {.importc: "SIGTSTP", header: "".}: cint +# var SIGTTIN* {.importc: "SIGTTIN", header: "".}: cint +# var SIGTTOU* {.importc: "SIGTTOU", header: "".}: cint +# var SIGUSR1* {.importc: "SIGUSR1", header: "".}: cint +# var SIGUSR2* {.importc: "SIGUSR2", header: "".}: cint +# var SIGPOLL* {.importc: "SIGPOLL", header: "".}: cint +# var SIGPROF* {.importc: "SIGPROF", header: "".}: cint +# var SIGSYS* {.importc: "SIGSYS", header: "".}: cint +# var SIGTRAP* {.importc: "SIGTRAP", header: "".}: cint +# var SIGURG* {.importc: "SIGURG", header: "".}: cint +# var SIGVTALRM* {.importc: "SIGVTALRM", header: "".}: cint +# var SIGXCPU* {.importc: "SIGXCPU", header: "".}: cint +# var SIGXFSZ* {.importc: "SIGXFSZ", header: "".}: cint +# var SA_NOCLDSTOP* {.importc: "SA_NOCLDSTOP", header: "".}: cint +# var SIG_BLOCK* {.importc: "SIG_BLOCK", header: "".}: cint +# var SIG_UNBLOCK* {.importc: "SIG_UNBLOCK", header: "".}: cint +# var SIG_SETMASK* {.importc: "SIG_SETMASK", header: "".}: cint +# var SA_ONSTACK* {.importc: "SA_ONSTACK", header: "".}: cint +# var SA_RESETHAND* {.importc: "SA_RESETHAND", header: "".}: cint +# var SA_RESTART* {.importc: "SA_RESTART", header: "".}: cint +# var SA_SIGINFO* {.importc: "SA_SIGINFO", header: "".}: cint +# var SA_NOCLDWAIT* {.importc: "SA_NOCLDWAIT", header: "".}: cint +# var SA_NODEFER* {.importc: "SA_NODEFER", header: "".}: cint +# var SS_ONSTACK* {.importc: "SS_ONSTACK", header: "".}: cint +# var SS_DISABLE* {.importc: "SS_DISABLE", header: "".}: cint +# var MINSIGSTKSZ* {.importc: "MINSIGSTKSZ", header: "".}: cint +# var SIGSTKSZ* {.importc: "SIGSTKSZ", header: "".}: cint +# var SIG_HOLD* {.importc: "SIG_HOLD", header: "".}: Sighandler +# var SIG_DFL* {.importc: "SIG_DFL", header: "".}: Sighandler +# var SIG_ERR* {.importc: "SIG_ERR", header: "".}: Sighandler +# var SIG_IGN* {.importc: "SIG_IGN", header: "".}: Sighandler + +# # +# var IPC_CREAT* {.importc: "IPC_CREAT", header: "".}: cint +# var IPC_EXCL* {.importc: "IPC_EXCL", header: "".}: cint +# var IPC_NOWAIT* {.importc: "IPC_NOWAIT", header: "".}: cint +# var IPC_PRIVATE* {.importc: "IPC_PRIVATE", header: "".}: cint +# var IPC_RMID* {.importc: "IPC_RMID", header: "".}: cint +# var IPC_SET* {.importc: "IPC_SET", header: "".}: cint +# var IPC_STAT* {.importc: "IPC_STAT", header: "".}: cint + +# # +# var PROT_READ* {.importc: "PROT_READ", header: "".}: cint +# var PROT_WRITE* {.importc: "PROT_WRITE", header: "".}: cint +# var PROT_EXEC* {.importc: "PROT_EXEC", header: "".}: cint +# var PROT_NONE* {.importc: "PROT_NONE", header: "".}: cint +# var MAP_ANONYMOUS* {.importc: "MAP_ANONYMOUS", header: "".}: cint +# var MAP_FIXED_NOREPLACE* {.importc: "MAP_FIXED_NOREPLACE", header: "".}: cint +# var MAP_NORESERVE* {.importc: "MAP_NORESERVE", header: "".}: cint +# var MAP_SHARED* {.importc: "MAP_SHARED", header: "".}: cint +# var MAP_PRIVATE* {.importc: "MAP_PRIVATE", header: "".}: cint +# var MAP_FIXED* {.importc: "MAP_FIXED", header: "".}: cint +# var MS_ASYNC* {.importc: "MS_ASYNC", header: "".}: cint +# var MS_SYNC* {.importc: "MS_SYNC", header: "".}: cint +# var MS_INVALIDATE* {.importc: "MS_INVALIDATE", header: "".}: cint +# var MCL_CURRENT* {.importc: "MCL_CURRENT", header: "".}: cint +# var MCL_FUTURE* {.importc: "MCL_FUTURE", header: "".}: cint +# var MAP_FAILED* {.importc: "MAP_FAILED", header: "".}: pointer +# var POSIX_MADV_NORMAL* {.importc: "POSIX_MADV_NORMAL", header: "".}: cint +# var POSIX_MADV_SEQUENTIAL* {.importc: "POSIX_MADV_SEQUENTIAL", header: "".}: cint +# var POSIX_MADV_RANDOM* {.importc: "POSIX_MADV_RANDOM", header: "".}: cint +# var POSIX_MADV_WILLNEED* {.importc: "POSIX_MADV_WILLNEED", header: "".}: cint +# var POSIX_MADV_DONTNEED* {.importc: "POSIX_MADV_DONTNEED", header: "".}: cint +# var POSIX_TYPED_MEM_ALLOCATE* {.importc: "POSIX_TYPED_MEM_ALLOCATE", header: "".}: cint +# var POSIX_TYPED_MEM_ALLOCATE_CONTIG* {.importc: "POSIX_TYPED_MEM_ALLOCATE_CONTIG", header: "".}: cint +# var POSIX_TYPED_MEM_MAP_ALLOCATABLE* {.importc: "POSIX_TYPED_MEM_MAP_ALLOCATABLE", header: "".}: cint + +# +# var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "".}: cint + +# +var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint + +# +var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint +var MSG_DONTROUTE* {.importc: "MSG_DONTROUTE", header: "".}: cint +var MSG_EOR* {.importc: "MSG_EOR", header: "".}: cint +var MSG_OOB* {.importc: "MSG_OOB", header: "".}: cint + +# var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "".}: cint +var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "".}: cint +var SO_BROADCAST* {.importc: "SO_BROADCAST", header: "".}: cint +var SO_DEBUG* {.importc: "SO_DEBUG", header: "".}: cint +var SO_DONTROUTE* {.importc: "SO_DONTROUTE", header: "".}: cint +var SO_ERROR* {.importc: "SO_ERROR", header: "".}: cint +var SO_KEEPALIVE* {.importc: "SO_KEEPALIVE", header: "".}: cint +var SO_LINGER* {.importc: "SO_LINGER", header: "".}: cint +var SO_OOBINLINE* {.importc: "SO_OOBINLINE", header: "".}: cint +var SO_RCVBUF* {.importc: "SO_RCVBUF", header: "".}: cint +var SO_RCVLOWAT* {.importc: "SO_RCVLOWAT", header: "".}: cint +var SO_RCVTIMEO* {.importc: "SO_RCVTIMEO", header: "".}: cint +var SO_REUSEADDR* {.importc: "SO_REUSEADDR", header: "".}: cint +var SO_SNDBUF* {.importc: "SO_SNDBUF", header: "".}: cint +var SO_SNDLOWAT* {.importc: "SO_SNDLOWAT", header: "".}: cint +var SO_SNDTIMEO* {.importc: "SO_SNDTIMEO", header: "".}: cint +var SO_TYPE* {.importc: "SO_TYPE", header: "".}: cint +var SOCK_DGRAM* {.importc: "SOCK_DGRAM", header: "".}: cint +var SOCK_RAW* {.importc: "SOCK_RAW", header: "".}: cint + +# var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "".}: cint +const SOCK_SEQPACKET* = cint(5) + +var SOCK_STREAM* {.importc: "SOCK_STREAM", header: "".}: cint +var SOL_SOCKET* {.importc: "SOL_SOCKET", header: "".}: cint + +const SocketMaxConnections {.intdefine.}: int = 32 +var SOMAXCONN*: cint = SocketMaxConnections.cint + +var MSG_PEEK* {.importc: "MSG_PEEK", header: "".}: cint +var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "".}: cint +var MSG_WAITALL* {.importc: "MSG_WAITALL", header: "".}: cint +var AF_INET* {.importc: "AF_INET", header: "".}: cint +var AF_INET6* {.importc: "AF_INET6", header: "".}: cint +# var AF_UNIX* {.importc: "AF_UNIX", header: "".}: cint +const AF_UNIX*: cint = 1 # for compat with Nim libraries, doesn't exist on freertos +var AF_UNSPEC* {.importc: "AF_UNSPEC", header: "".}: cint +var SHUT_RD* {.importc: "SHUT_RD", header: "".}: cint +var SHUT_RDWR* {.importc: "SHUT_RDWR", header: "".}: cint +var SHUT_WR* {.importc: "SHUT_WR", header: "".}: cint + +# # +# + +# var S_IFBLK* {.importc: "S_IFBLK", header: "".}: cint +# var S_IFCHR* {.importc: "S_IFCHR", header: "".}: cint +# var S_IFDIR* {.importc: "S_IFDIR", header: "".}: cint +# var S_IFIFO* {.importc: "S_IFIFO", header: "".}: cint +# var S_IFLNK* {.importc: "S_IFLNK", header: "".}: cint +# var S_IFMT* {.importc: "S_IFMT", header: "".}: cint +# var S_IFREG* {.importc: "S_IFREG", header: "".}: cint +# var S_IFSOCK* {.importc: "S_IFSOCK", header: "".}: cint +var S_IRGRP* {.importc: "S_IRGRP", header: "".}: cint +var S_IROTH* {.importc: "S_IROTH", header: "".}: cint +var S_IRUSR* {.importc: "S_IRUSR", header: "".}: cint +# var S_IRWXG* {.importc: "S_IRWXG", header: "".}: cint +# var S_IRWXO* {.importc: "S_IRWXO", header: "".}: cint +# var S_IRWXU* {.importc: "S_IRWXU", header: "".}: cint +# var S_ISGID* {.importc: "S_ISGID", header: "".}: cint +# var S_ISUID* {.importc: "S_ISUID", header: "".}: cint +# var S_ISVTX* {.importc: "S_ISVTX", header: "".}: cint +var S_IWGRP* {.importc: "S_IWGRP", header: "".}: cint +var S_IWOTH* {.importc: "S_IWOTH", header: "".}: cint +var S_IWUSR* {.importc: "S_IWUSR", header: "".}: cint +var S_IXGRP* {.importc: "S_IXGRP", header: "".}: cint +var S_IXOTH* {.importc: "S_IXOTH", header: "".}: cint +var S_IXUSR* {.importc: "S_IXUSR", header: "".}: cint + +# # +# var ST_RDONLY* {.importc: "ST_RDONLY", header: "".}: cint +# var ST_NOSUID* {.importc: "ST_NOSUID", header: "".}: cint + +# # +# var WNOHANG* {.importc: "WNOHANG", header: "".}: cint +# var WUNTRACED* {.importc: "WUNTRACED", header: "".}: cint +# var WEXITED* {.importc: "WEXITED", header: "".}: cint +# var WSTOPPED* {.importc: "WSTOPPED", header: "".}: cint +# var WCONTINUED* {.importc: "WCONTINUED", header: "".}: cint +# var WNOWAIT* {.importc: "WNOWAIT", header: "".}: cint +# var P_ALL* {.importc: "P_ALL", header: "".}: cint +# var P_PID* {.importc: "P_PID", header: "".}: cint +# var P_PGID* {.importc: "P_PGID", header: "".}: cint + +# # +# var POSIX_SPAWN_RESETIDS* {.importc: "POSIX_SPAWN_RESETIDS", header: "".}: cint +# var POSIX_SPAWN_SETPGROUP* {.importc: "POSIX_SPAWN_SETPGROUP", header: "".}: cint +# var POSIX_SPAWN_SETSCHEDPARAM* {.importc: "POSIX_SPAWN_SETSCHEDPARAM", header: "".}: cint +# var POSIX_SPAWN_SETSCHEDULER* {.importc: "POSIX_SPAWN_SETSCHEDULER", header: "".}: cint +# var POSIX_SPAWN_SETSIGDEF* {.importc: "POSIX_SPAWN_SETSIGDEF", header: "".}: cint +# var POSIX_SPAWN_SETSIGMASK* {.importc: "POSIX_SPAWN_SETSIGMASK", header: "".}: cint + +## +# var IOFBF* {.importc: "_IOFBF", header: "".}: cint +# var IONBF* {.importc: "_IONBF", header: "".}: cint + +# +var CLOCKS_PER_SEC* {.importc: "CLOCKS_PER_SEC", header: "".}: clong +var CLOCK_PROCESS_CPUTIME_ID* {.importc: "CLOCK_PROCESS_CPUTIME_ID", header: "".}: cint +var CLOCK_THREAD_CPUTIME_ID* {.importc: "CLOCK_THREAD_CPUTIME_ID", header: "".}: cint +var CLOCK_REALTIME* {.importc: "CLOCK_REALTIME", header: "".}: cint +var TIMER_ABSTIME* {.importc: "TIMER_ABSTIME", header: "".}: cint +var CLOCK_MONOTONIC* {.importc: "CLOCK_MONOTONIC", header: "".}: cint + +# + +const F_OK* = cint(0) +const R_OK* = cint(4) +const W_OK* = cint(2) +const X_OK* = cint(1) +const F_LOCK* = cint(1) +const F_TEST* = cint(3) +const F_TLOCK* = cint(2) +const F_ULOCK* = cint(0) + diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index ed058d5cf..1ad05060d 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -10,9 +10,14 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -const - hasSpawnH = true # should exist for every Posix system nowadays - hasAioH = defined(linux) +when defined(freertos): + const + hasSpawnH = false # should exist for every Posix system nowadays + hasAioH = false +else: + const + hasSpawnH = true # should exist for every Posix system nowadays + hasAioH = defined(linux) when defined(linux) and not defined(android): # On Linux: @@ -397,21 +402,55 @@ type SockLen* {.importc: "socklen_t", header: "".} = cuint TSa_Family* {.importc: "sa_family_t", header: "".} = cushort - SockAddr* {.importc: "struct sockaddr", header: "", - pure, final.} = object ## struct sockaddr - sa_family*: TSa_Family ## Address family. - sa_data*: array[0..255, char] ## Socket address (variable-length data). +when defined(lwip): + type + SockAddr* {.importc: "struct sockaddr", header: "", + pure, final.} = object ## struct sockaddr + sa_len*: uint8 ## Address family. + sa_family*: TSa_Family ## Address family. + sa_data*: array[0..255, char] ## Socket address (variable-length data). +else: + type + SockAddr* {.importc: "struct sockaddr", header: "", + pure, final.} = object ## struct sockaddr + sa_family*: TSa_Family ## Address family. + sa_data*: array[0..255, char] ## Socket address (variable-length data). +type Sockaddr_un* {.importc: "struct sockaddr_un", header: "", pure, final.} = object ## struct sockaddr_un sun_family*: TSa_Family ## Address family. sun_path*: array[0..Sockaddr_un_path_length-1, char] ## Socket path - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - ss_family*: TSa_Family ## Address family. +when defined(lwip): + when not defined(lwip6): + type + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + s2_len*: uint8 ## Address family. + ss_family*: TSa_Family ## Address family. + s2_data1*: array[2, char] ## Address family. + s2_data2*: array[3, uint32] ## Address family. + else: + type + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + s2_len*: uint8 ## Address family. + ss_family*: TSa_Family ## Address family. + s2_data1*: array[2, char] ## Address family. + s2_data2*: array[3, uint32] ## Address family. + s2_data3*: array[3, uint32] ## Address family. +else: + type + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + ss_family*: TSa_Family ## Address family. + +type Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "".} = object ## struct if_nameindex if_index*: cint ## Numeric index of the interface. @@ -530,13 +569,15 @@ type ai_canonname*: cstring ## Canonical name of service location. ai_next*: ptr AddrInfo ## Pointer to next in list. - TPollfd* {.importc: "struct pollfd", pure, final, - header: "".} = object ## struct pollfd - fd*: cint ## The following descriptor being polled. - events*: cshort ## The input event flags (see below). - revents*: cshort ## The output event flags (see below). +when not defined(lwip): + type + TPollfd* {.importc: "struct pollfd", pure, final, + header: "".} = object ## struct pollfd + fd*: cint ## The following descriptor being polled. + events*: cshort ## The input event flags (see below). + revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = cint + Tnfds* {.importc: "nfds_t", header: "".} = cint var errno* {.importc, header: "".}: cint ## error variable @@ -545,7 +586,10 @@ var timezone* {.importc, header: "".}: int # Regenerate using detect.nim! -include posix_other_consts +when defined(lwip): + include posix_freertos_consts +else: + include posix_other_consts when defined(linux): var diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 02a853b42..2f22f1b30 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -312,7 +312,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, verifySelectParams(timeout) if timeout != -1: - when defined(genode): + when defined(genode) or defined(freertos): tv.tv_sec = Time(timeout div 1_000) else: tv.tv_sec = timeout.int32 div 1_000 diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 49a1192df..0b0c4b398 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -269,7 +269,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, let socketPort = if sockType == SOCK_RAW: "" else: $port var gaiResult = getaddrinfo(address, socketPort, addr(hints), result) if gaiResult != 0'i32: - when useWinVersion: + when useWinVersion or defined(freertos): raiseOSError(osLastError()) else: raiseOSError(osLastError(), $gai_strerror(gaiResult)) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 6007a8250..f3726efaa 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -332,5 +332,7 @@ else: include ioselects/ioselectors_select # TODO: use the native VFS layer elif defined(nintendoswitch): include ioselects/ioselectors_select + elif defined(freertos) or defined(lwip): + include ioselects/ioselectors_select else: include ioselects/ioselectors_poll diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index a15d9267f..1b0a3e64c 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -179,7 +179,7 @@ elif defined(genode): proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {. error: "nimGetProcAddr not implemented".} -elif defined(nintendoswitch): +elif defined(nintendoswitch) or defined(freertos): proc nimUnloadLibrary(lib: LibHandle) = cstderr.rawWrite("nimUnLoadLibrary not implemented") cstderr.rawWrite("\n") diff --git a/lib/system/io.nim b/lib/system/io.nim index 3d5cf981a..c3b2976fb 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -269,7 +269,7 @@ when SupportIoctlInheritCtl: proc c_ioctl(fd: cint, request: cint): cint {. importc: "ioctl", header: "", varargs.} -elif defined(posix) and not defined(nimscript): +elif defined(posix) and not defined(lwip) and not defined(nimscript): var F_GETFD {.importc, header: "".}: cint F_SETFD {.importc, header: "".}: cint @@ -336,6 +336,8 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w ## availability with `declared() `. when SupportIoctlInheritCtl: result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1 + elif defined(freertos): + result = true elif defined(posix): var flags = c_fcntl(f, F_GETFD) if flags == -1: @@ -767,6 +769,10 @@ when declared(stdout): var echoLock: SysLock initSysLock echoLock + const stdOutLock = not defined(windows) and not defined(android) and + not defined(nintendoswitch) and not defined(freertos) and + hostOS != "any" + proc echoBinSafe(args: openArray[string]) {.compilerproc.} = when defined(androidNDK): var s = "" @@ -775,7 +781,7 @@ when declared(stdout): android_log_print(ANDROID_LOG_VERBOSE, "nim", s) else: # flockfile deadlocks some versions of Android 5.x.x - when not defined(windows) and not defined(android) and not defined(nintendoswitch) and hostOS != "any": + when stdOutLock: proc flockfile(f: File) {.importc, nodecl.} proc funlockfile(f: File) {.importc, nodecl.} flockfile(stdout) @@ -789,7 +795,7 @@ when declared(stdout): const linefeed = "\n" discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) discard c_fflush(stdout) - when not defined(windows) and not defined(android) and not defined(nintendoswitch) and hostOS != "any": + when stdOutLock: funlockfile(stdout) when defined(windows) and compileOption("threads"): releaseSys echoLock diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 05ddb4f1e..453b1037b 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -158,6 +158,7 @@ lib/posix/posix_nintendoswitch_consts.nim lib/posix/posix_linux_amd64.nim lib/posix/posix_linux_amd64_consts.nim lib/posix/posix_other_consts.nim +lib/posix/posix_freertos_consts.nim lib/posix/posix_openbsd_amd64.nim lib/posix/posix_haiku.nim lib/js/jsre.nim From ff13f8cc3c74d4048b6c2604fe4b8e5365f5c13f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 31 Aug 2020 14:46:23 +0200 Subject: [PATCH 1050/4254] fixes #15210 [backport:1.2] (#15237) * fixes #15210 [backport:1.2] * use patched version of bigints library --- compiler/ccgexprs.nim | 43 +++++++++++++++++--------------- lib/system/chcks.nim | 3 +++ testament/important_packages.nim | 2 +- tests/misc/tunsignedconv.nim | 11 ++++++++ 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 995b75d69..6da44a33a 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1996,25 +1996,30 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = checkUnsignedConversions notin p.config.legacyFeatures): discard "no need to generate a check because it was disabled" else: - let raiser = - case skipTypes(n.typ, abstractVarRange).kind - of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU" - of tyFloat..tyFloat128: "raiseRangeErrorF" - else: "raiseRangeErrorI" - discard cgsym(p.module, raiser) - # This seems to be bug-compatible with Nim version 1 but what we - # should really do here is to check if uint64Value < high(int) let n0t = n[0].typ - let boundaryCast = - if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or - (n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"): - "(NI64)" - else: - "" + # emit range check: - linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n", - [rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest), - raiser, raiseInstr(p), boundaryCast]) + if n0t.kind in {tyUInt, tyUInt64}: + linefmt(p, cpsStmts, "if ($1 > ($6)($3)){ #raiseRangeErrorNoArgs(); $5}$n", + [rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest), + raiser, raiseInstr(p), getTypeDesc(p.module, n0t)]) + else: + let raiser = + case skipTypes(n.typ, abstractVarRange).kind + of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU" + of tyFloat..tyFloat128: "raiseRangeErrorF" + else: "raiseRangeErrorI" + discard cgsym(p.module, raiser) + + let boundaryCast = + if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or + (n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"): + "(NI64)" + else: + "" + linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n", + [rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest), + raiser, raiseInstr(p), boundaryCast]) putIntoDest(p, d, n, "(($1) ($2))" % [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) @@ -2690,9 +2695,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = expr(p, n[1][0], d) of nkObjDownConv: downConv(p, n, d) of nkObjUpConv: upConv(p, n, d) - of nkChckRangeF: genRangeChck(p, n, d) - of nkChckRange64: genRangeChck(p, n, d) - of nkChckRange: genRangeChck(p, n, d) + of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d) of nkStringToCString: convStrToCStr(p, n, d) of nkCStringToString: convCStrToStr(p, n, d) of nkLambdaKinds: diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 0b6a75b1f..e0a8bd78e 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -38,6 +38,9 @@ proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} = # todo: better error reporting sysFatal(RangeDefect, "value out of range") +proc raiseRangeErrorNoArgs() {.compilerproc, noinline.} = + sysFatal(RangeDefect, "value out of range") + proc raiseObjectConversionError() {.compilerproc, noinline.} = sysFatal(ObjectConversionDefect, "invalid object conversion") diff --git a/testament/important_packages.nim b/testament/important_packages.nim index a4187f64c..dc2f8f0d1 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -14,7 +14,7 @@ pkg1 "argparse" pkg1 "arraymancer", true, "nim c tests/tests_cpu.nim" #pkg1 "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim" pkg1 "awk", true -pkg1 "bigints" +pkg1 "bigints", url = "https://github.com/Araq/nim-bigints" pkg1 "binaryheap", false, "nim c -r binaryheap.nim" pkg1 "BipBuffer" # pkg1 "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39 diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index 07fc03e59..e9a2a2189 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -69,3 +69,14 @@ let rangeVar = 0'u64 ..< limit doAssert repr(rangeVar) == """[a = 0, b = 0] """ + +# bug #15210 + +let a3 = not 0'u64 +var success = false +try: + discard a3.int64 +except RangeDefect: + success = true + +doAssert success, "conversion should fail at runtime" From 244760197cf1d24829ae45de5f25c10577152cdd Mon Sep 17 00:00:00 2001 From: PMunch Date: Wed, 2 Sep 2020 08:07:08 +0000 Subject: [PATCH 1051/4254] Fix sets for architectures with default integers smaller than 32 bits (#15258) [backport] --- compiler/ccgexprs.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6da44a33a..dd4774b2a 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1796,9 +1796,9 @@ template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = case int(getSize(p.config, skipTypes(e[1].typ, abstractVar))) - of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)") - of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)") - of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)") + of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)") + of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)") + of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)") of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)") else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)") From 3172ca54758e0a7e68d140a79ed98d0981b05e3f Mon Sep 17 00:00:00 2001 From: Silvio Date: Wed, 2 Sep 2020 20:53:02 +0200 Subject: [PATCH 1052/4254] replace / with _ in trId (#15256) Fixes jquery error when clicking to collapse/expand a panel --- testament/htmlgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/htmlgen.nim b/testament/htmlgen.nim index 8e58dd95e..174f36d0b 100644 --- a/testament/htmlgen.nim +++ b/testament/htmlgen.nim @@ -16,7 +16,7 @@ import "testamenthtml.nimf" proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode) = let trId = htmlQuote(testResultRow["category"].str & "_" & testResultRow["name"].str). - multiReplace({".": "_", " ": "_", ":": "_"}) + multiReplace({".": "_", " ": "_", ":": "_", "/": "_"}) name = testResultRow["name"].str.htmlQuote() category = testResultRow["category"].str.htmlQuote() target = testResultRow["target"].str.htmlQuote() From 48f29972210612b41cb6d98122672b1713edc907 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 3 Sep 2020 12:59:34 +0200 Subject: [PATCH 1053/4254] fixes system.add for strict funcs (#15259) * fixes system.add for strict funcs * fixes #15248 --- compiler/varpartitions.nim | 2 +- lib/system.nim | 38 ++++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index fd6751cdf..23ad8fe09 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -342,7 +342,7 @@ proc deps(c: var Partitions; dest, src: PNode) = let destIsComplex = types.searchTypeFor(dest.typ, wrap) for t in targets: - if dest.kind != nkSym: + if dest.kind != nkSym and c.inNoSideEffectSection == 0: potentialMutation(c, t, dest.info) if destIsComplex: diff --git a/lib/system.nim b/lib/system.nim index 204a1194e..dc603b56d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1227,9 +1227,10 @@ proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = ## .. code-block:: Nim ## var s: seq[string] = @["test2","test2"] ## s.add("test") # s <- @[test2, test2, test] - let xl = x.len - setLen(x, xl + y.len) - for i in 0..high(y): x[xl+i] = y[i] + {.noSideEffect.}: + let xl = x.len + setLen(x, xl + y.len) + for i in 0..high(y): x[xl+i] = y[i] when defined(nimSeqsV2): template movingCopy(a, b) = @@ -1283,22 +1284,23 @@ proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} = ## .. code-block:: Nim ## var i = @[1, 3, 5] ## i.insert(99, 0) # i <- @[99, 1, 3, 5] - template defaultImpl = - let xl = x.len - setLen(x, xl+1) - var j = xl-1 - while j >= i: - movingCopy(x[j+1], x[j]) - dec(j) - when nimvm: - defaultImpl() - else: - when defined(js): - var it : T - {.emit: "`x` = `x` || []; `x`.splice(`i`, 0, `it`);".} - else: + {.noSideEffect.}: + template defaultImpl = + let xl = x.len + setLen(x, xl+1) + var j = xl-1 + while j >= i: + movingCopy(x[j+1], x[j]) + dec(j) + when nimvm: defaultImpl() - x[i] = item + else: + when defined(js): + var it : T + {.emit: "`x` = `x` || []; `x`.splice(`i`, 0, `it`);".} + else: + defaultImpl() + x[i] = item when not defined(nimV2): proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} From 4fb17bc03be3046d8ff619a74eec7cb7ce02b4d2 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 4 Sep 2020 09:23:27 +0200 Subject: [PATCH 1054/4254] fix #15257, `toHex` couldn't handle large uint64 (#15261) [backport:1.2] --- lib/pure/strutils.nim | 43 ++++++++++++++++++++++++++++----------- tests/stdlib/tstrutil.nim | 6 ++++-- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a0a172430..20010ff81 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -938,6 +938,31 @@ proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect, inc shift, 3 mask = mask shl BiggestUInt(3) +proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.noSideEffect.} = + const + HexChars = "0123456789ABCDEF" + var n = x + result = newString(len) + for j in countdown(len-1, 0): + result[j] = HexChars[int(n and 0xF)] + n = n shr 4 + # handle negative overflow + if n == 0 and handleNegative: n = not(BiggestUInt 0) + +proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} = + ## Converts `x` to its hexadecimal representation. + ## + ## The resulting string will be exactly `len` characters long. No prefix like + ## ``0x`` is generated. + runnableExamples: + let + a = 62'u64 + b = 4097'u64 + doAssert a.toHex(3) == "03E" + doAssert b.toHex(3) == "001" + doAssert b.toHex(4) == "1001" + toHexImpl(x, len, false) + proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, rtl, extern: "nsuToHex".} = ## Converts `x` to its hexadecimal representation. @@ -948,25 +973,19 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, let a = 62 b = 4097 + c = -8 doAssert a.toHex(3) == "03E" doAssert b.toHex(3) == "001" doAssert b.toHex(4) == "1001" - const - HexChars = "0123456789ABCDEF" - var - n = x - result = newString(len) - for j in countdown(len-1, 0): - result[j] = HexChars[int(n and 0xF)] - n = n shr 4 - # handle negative overflow - if n == 0 and x < 0: n = -1 + doAssert c.toHex(6) == "FFFFF8" + toHexImpl(cast[BiggestUInt](x), len, x < 0) -proc toHex*[T: SomeInteger](x: T): string = +proc toHex*[T: SomeInteger](x: T): string {.noSideEffect.} = ## Shortcut for ``toHex(x, T.sizeof * 2)`` runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" - toHex(BiggestInt(x), T.sizeof * 2) + doAssert toHex(1984'i16) == "07C0" + toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) proc toHex*(s: string): string {.noSideEffect, rtl.} = ## Converts a bytes string to its hexadecimal representation. diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 5702b7341..ef5b041be 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -3,8 +3,6 @@ import strutils -import macros - template rejectParse(e) = try: discard e @@ -296,6 +294,10 @@ assert "/1/2/3".rfind('0') == -1 assert(toHex(100i16, 32) == "00000000000000000000000000000064") assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") +assert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") +assert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") +assert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") + assert "".parseHexStr == "" assert "00Ff80".parseHexStr == "\0\xFF\x80" try: From 77df02313d92859cd0d8faa87a139b4b6ea0f7d9 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 4 Sep 2020 09:26:14 +0100 Subject: [PATCH 1055/4254] fix #15238 (#15262) * fix_15238 * fix test --- compiler/sempass2.nim | 1 + tests/arc/t14383.nim | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 41d83ed55..dc833ce34 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -826,6 +826,7 @@ proc trackCall(tracked: PEffects; n: PNode) = for i in 1.. Date: Fri, 4 Sep 2020 17:04:27 +0800 Subject: [PATCH 1056/4254] Fix #15219 SQL escape in db_mysql is not enough (#15234) --- lib/impure/db_mysql.nim | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index c96829830..c3bcee677 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -118,10 +118,24 @@ when false: proc dbQuote*(s: string): string = ## DB quotes the string. - result = "'" + result = newStringOfCap(s.len + 2) + result.add "'" for c in items(s): - if c == '\'': add(result, "''") - else: add(result, c) + # see https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html#mysql-escaping + case c + of '\0': result.add "\\0" + of '\b': result.add "\\b" + of '\t': result.add "\\t" + of '\l': result.add "\\n" + of '\r': result.add "\\r" + of '\x1a': result.add "\\Z" + of '"': result.add "\\\"" + of '%': result.add "\\%" + of '\'': result.add "\\'" + of '\\': result.add "\\\\" + of '_': result.add "\\_" + of Letters+Digits: result.add c + else: result.add "\\" & $ord(c) add(result, '\'') proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = From 70d62387568d55cd276472f28ce22ab8bafadf1c Mon Sep 17 00:00:00 2001 From: IDF Date: Sat, 5 Sep 2020 00:27:51 +0300 Subject: [PATCH 1057/4254] Add SSL_CTX_set_session_id_context (#15233) * Added SSL_CTX_set_session_id_context() * Added basic nimdoc * Raise an error if sessionIdContext is longer than the maximum length * Update nimdocs --- lib/pure/net.nim | 16 ++++++++++++++++ lib/wrappers/openssl.nim | 1 + 2 files changed, 17 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 239e3e9f6..5d2ec8e30 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -825,6 +825,22 @@ when defineSsl: else: result = getPeerCertificates(socket.sslHandle) + proc `sessionIdContext=`*(ctx: SslContext, sidCtx: string) = + ## Sets the session id context in which a session can be reused. + ## Used for permitting clients to reuse a session id instead of + ## doing a new handshake. + ## + ## TLS clients might attempt to resume a session using the session id context, + ## thus it must be set if verifyMode is set to CVerifyPeer or CVerifyPeerUseEnvVars, + ## otherwise the connection will fail and SslError will be raised if resumption occurs. + ## + ## - Only useful if set server-side. + ## - Should be unique per-application to prevent clients from malfunctioning. + ## - sidCtx must be at most 32 characters in length. + if sidCtx.len > 32: + raiseSSLError("sessionIdContext must be shorter than 32 characters") + SSL_CTX_set_session_id_context(ctx.context, sidCtx, sidCtx.len) + proc getSocketError*(socket: Socket): OSErrorCode = ## Checks ``osLastError`` for a valid error. If it has been reset it uses ## the last error stored in the socket object. diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index a37c5b1be..becabad99 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -436,6 +436,7 @@ proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} proc SSL_get_SSL_CTX*(ssl: SslPtr): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} proc SSL_set_SSL_CTX*(ssl: SslPtr, ctx: SslCtx): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_set_session_id_context*(context: SslCtx, sid_ctx: string, sid_ctx_len: int){.cdecl, dynlib: DLLSSLName, importc.} proc SSL_get0_verified_chain*(ssl: SslPtr): PSTACK {.cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_new*(meth: PSSL_METHOD): SslCtx{.cdecl, From 35ff17410f303ce0434ef149f3e372d7243f41ab Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 5 Sep 2020 22:01:47 +0200 Subject: [PATCH 1058/4254] Expand hoisted default params in sem (#15270) * Expand hoisted default params in sem Introduce ast.newTree{I,IT} Add test for default params in procs * Cleanup * Simplify hoist transformation and expand test --- compiler/ast.nim | 78 ++++++++++---------- compiler/docgen.nim | 8 +- compiler/lowerings.nim | 11 --- compiler/parser.nim | 2 +- compiler/pragmas.nim | 6 +- compiler/semdata.nim | 8 +- compiler/semexprs.nim | 59 +++++++++++++-- compiler/sempass2.nim | 2 +- compiler/semtypinst.nim | 2 +- compiler/transf.nim | 47 ------------ compiler/vmdeps.nim | 3 +- tests/defaultprocparam/tdefaultprocparam.nim | 75 +++++++++++++++++++ 12 files changed, 178 insertions(+), 123 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 23b564af3..b1a3a4a7b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -312,10 +312,6 @@ const # the compiler will avoid printing such names # in user messages. - sfHoisted* = sfForward - # an expression was hoised to an anonymous variable. - # the flag is applied to the var/let symbol - sfNoForward* = sfRegister # forward declarations are not required (per module) sfReorder* = sfForward @@ -1121,12 +1117,49 @@ proc newNode*(kind: TNodeKind): PNode = writeStackTrace() inc gNodeId +proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = + result = PNode(kind: kind, info: info) + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = + result = PNode(kind: kind, info: info) + if children > 0: + newSeq(result.sons, children) + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = + result = newNode(kind) + result.info = info + result.typ = typ + proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode = result = newNode(kind) if children.len > 0: result.info = children[0].info result.sons = @children +proc newTreeI*(kind: TNodeKind; info: TLineInfo; children: varargs[PNode]): PNode = + result = newNodeI(kind, info) + if children.len > 0: + result.info = children[0].info + result.sons = @children + +proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[PNode]): PNode = + result = newNodeIT(kind, info, typ) + if children.len > 0: + result.info = children[0].info + result.sons = @children + template previouslyInferred*(t: PType): PType = if t.sons.len > 1: t.lastSon else: nil @@ -1227,43 +1260,6 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode = result.typ = sym.typ result.info = info -proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = - result = PNode(kind: kind, info: info) - when defined(useNodeIds): - result.id = gNodeId - if result.id == nodeIdToDebug: - echo "KIND ", result.kind - writeStackTrace() - inc gNodeId - -proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = - result = PNode(kind: kind, info: info) - if children > 0: - newSeq(result.sons, children) - when defined(useNodeIds): - result.id = gNodeId - if result.id == nodeIdToDebug: - echo "KIND ", result.kind - writeStackTrace() - inc gNodeId - -proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[], - typ: PType = nil): PNode = - # XXX use shallowCopy here for ownership transfer: - result = PNode(kind: kind, info: info, typ: typ) - result.sons = sons - when defined(useNodeIds): - result.id = gNodeId - if result.id == nodeIdToDebug: - echo "KIND ", result.kind - writeStackTrace() - inc gNodeId - -proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = - result = newNode(kind) - result.info = info - result.typ = typ - proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = result = newNode(kind) result.intVal = intVal diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 1e0756d64..ff3a540be 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -992,8 +992,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id # set the type so that the following analysis doesn't screw up: effects[i].typ = real[i].typ - result = newNode(nkExprColonExpr, n.info, @[ - newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects]) + result = newTreeI(nkExprColonExpr, n.info, + newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects) proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode = let s = n[namePos].sym @@ -1005,8 +1005,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName effects.add params[i] if effects.len > 0: - result = newNode(nkExprColonExpr, n.info, @[ - newIdentNode(getIdent(cache, pragmaName), n.info), effects]) + result = newTreeI(nkExprColonExpr, n.info, + newIdentNode(getIdent(cache, pragmaName), n.info), effects) proc documentRaises*(cache: IdentCache; n: PNode) = if n[namePos].kind != nkSym: return diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 5e75c36de..f6ca98196 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -369,14 +369,3 @@ proc genLen*(g: ModuleGraph; n: PNode): PNode = result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq)) result[1] = n -proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym = - result = newSym(skLet, name, owner, varSection.info, owner.options) - result.flags.incl sfHoisted - result.typ = expr.typ - - var varDef = newNodeI(nkIdentDefs, varSection.info, 3) - varDef[0] = newSymNode(result) - varDef[1] = newNodeI(nkEmpty, varSection.info) - varDef[2] = expr - - varSection.add varDef diff --git a/compiler/parser.nim b/compiler/parser.nim index e7db8d8b1..0fa860c99 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1444,7 +1444,7 @@ proc parseExprStmt(p: var Parser): PNode = result.add(commandParam(p, isFirstParam, pmNormal)) if p.tok.tokType != tkComma: break elif p.tok.indent < 0 and isExprStart(p): - result = newNode(nkCommand, a.info, @[a]) + result = newTreeI(nkCommand, a.info, a) while true: result.add(commandParam(p, isFirstParam, pmNormal)) if p.tok.tokType != tkComma: break diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index b2529a5b8..71bd6f81f 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -532,7 +532,7 @@ proc processLink(c: PContext, n: PNode) = proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = case n[1].kind of nkStrLit, nkRStrLit, nkTripleStrLit: - result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info) + result = newNodeI(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info) var str = n[1].strVal if str == "": localError(con.config, n.info, "empty 'asm' statement") @@ -563,7 +563,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = a = c + 1 else: illFormedAstLocal(n, con.config) - result = newNode(nkAsmStmt, n.info) + result = newNodeI(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = if n.kind notin nkPragmaCallKinds or n.len != 2: @@ -626,7 +626,7 @@ proc processPragma(c: PContext, n: PNode, i: int) = invalidPragma(c, n) var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options) - userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1]) + userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1]) strTableAdd(c.userPragmas, userPragma) proc pragmaRaisesOrTags(c: PContext, n: PNode) = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b99ddcba3..b15f65967 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -381,8 +381,7 @@ proc makeNotType*(c: PContext, t1: PType): PType = result.flags.incl tfHasMeta proc nMinusOne(c: PContext; n: PNode): PNode = - result = newNode(nkCall, n.info, @[ - newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n]) + result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n) # Remember to fix the procs below this one when you make changes! proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType = @@ -391,9 +390,8 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType = result.sons = @[intType] if n.typ != nil and n.typ.n == nil: result.flags.incl tfUnresolved - result.n = newNode(nkRange, n.info, @[ - newIntTypeNode(0, intType), - makeStaticExpr(c, nMinusOne(c, n))]) + result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType), + makeStaticExpr(c, nMinusOne(c, n))) template rangeHasUnresolvedStatic*(t: PType): bool = tfUnresolved in t.flags diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 575d0b774..0e1c5e9d3 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1556,10 +1556,9 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for # nodes? let aOrig = nOrig[0] - result = newNode(nkCall, n.info, sons = @[setterId, a[0], - semExprWithType(c, n[1])]) + result = newTreeI(nkCall, n.info, setterId, a[0], semExprWithType(c, n[1])) result.flags.incl nfDotSetter - let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]]) + let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1]) result = semOverloadedCallAnalyseEffects(c, result, orig, {}) if result != nil: @@ -2041,7 +2040,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type ids.add c.graph.emptyNode # no default value - dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids) + dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids) var tmpl = semTemplateDef(c, dummyTemplate) quotes[0] = tmpl[namePos] @@ -2053,10 +2052,10 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = newIdentNode(getIdent(c.cache, "newIdentNode"), n.info) else: identNodeSym.newSymNode - quotes[1] = newNode(nkCall, n.info, @[identNode, newStrNode(nkStrLit, "result")]) - result = newNode(nkCall, n.info, @[ + quotes[1] = newTreeI(nkCall, n.info, identNode, newStrNode(nkStrLit, "result")) + result = newTreeI(nkCall, n.info, createMagic(c.graph, "getAst", mExpandToAst).newSymNode, - newNode(nkCall, n.info, quotes)]) + newTreeI(nkCall, n.info, quotes)) result = semExpandToAst(c, result) proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = @@ -2579,6 +2578,43 @@ proc shouldBeBracketExpr(n: PNode): bool = n[0] = be return true +proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) = + # This takes care of complicated signatures such as: + # proc foo(a: int, b = a) + # proc bar(a: int, b: int, c = a + b) + # + # The recursion may confuse you. It performs two duties: + # + # 1) extracting all referenced params from default expressions + # into a let section preceding the call + # + # 2) replacing the "references" within the default expression + # with these extracted skLet symbols. + # + # The first duty is carried out directly in the code here, while the second + # duty is activated by returning a non-nil value. The caller is responsible + # for replacing the input to the function with the returned non-nil value. + # (which is the hoisted symbol) + if defExpr.kind == nkSym and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym: + let paramPos = defExpr.sym.position + 1 + + if call[paramPos].kind != nkSym: + let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.p.owner, letSection.info, c.p.owner.options) + hoistedVarSym.typ = call[paramPos].typ + + letSection.add newTreeI(nkIdentDefs, letSection.info, + newSymNode(hoistedVarSym), + newNodeI(nkEmpty, letSection.info), + call[paramPos]) + + call[paramPos] = newSymNode(hoistedVarSym) # Refer the original arg to its hoisted sym + + # arg we refer to is a sym, wether introduced by hoisting or not doesn't matter, we simply reuse it + defExpr = call[paramPos] + else: + for i in 0.. Date: Sat, 5 Sep 2020 22:00:59 +0100 Subject: [PATCH 1059/4254] Fix c_malloc inside syslocks.nim to take size_t (#15268) [backport] * update c_malloc's to csize_t --- lib/system/syslocks.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index fa4164b95..b7f7aa6bf 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -145,13 +145,13 @@ else: SysCond = ptr SysCondObj when not declared(c_malloc): - proc c_malloc(size: csize): pointer {. + proc c_malloc(size: csize_t): pointer {. importc: "malloc", header: "".} proc c_free(p: pointer) {. importc: "free", header: "".} proc initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) = - L = cast[SysLock](c_malloc(sizeof(SysLockObj))) + L = cast[SysLock](c_malloc(csize_t(sizeof(SysLockObj)))) initSysLockAux(L[], attr) proc deinitSys(L: var SysLock) = @@ -201,7 +201,7 @@ else: when defined(ios): proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = - cond = cast[SysCond](c_malloc(sizeof(SysCondObj))) + cond = cast[SysCond](c_malloc(csize_t(sizeof(SysCondObj)))) initSysCondAux(cond[], cond_attr) proc deinitSysCond(cond: var SysCond) = From 072c6556539706f8301731ebb695ffed848cfe71 Mon Sep 17 00:00:00 2001 From: genotrance Date: Sun, 6 Sep 2020 00:05:35 -0500 Subject: [PATCH 1060/4254] Bump nimble (#15272) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 68a880d0d..d9bbb4176 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "a3e1267265965fc79a50b66999b660e0920db8cd" # master + NimbleStableCommit = "311e5a8cd2c53056bdec24c81393a46b41f96241" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From 2f6d04fd5d302646d40abc60b611653ec58463d0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 Sep 2020 22:01:39 +0200 Subject: [PATCH 1061/4254] strict funcs: use control flow information for a more precise analysis (#15271) * strict funcs: use control flow information for a more precise analysis * cursor inference uses control flow information --- compiler/varpartitions.nim | 99 ++++++++++++++++++++------ tests/effects/tfuncs_cannot_mutate.nim | 11 ++- 2 files changed, 87 insertions(+), 23 deletions(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 23ad8fe09..6cf8e1932 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -39,18 +39,26 @@ type of dependsOn: parent: int of isRootOf: graphIndex: int sym: PSym + aliveStart, aliveEnd: int # the range for which the variable is alive. MutationInfo* = object param: PSym mutatedHere, connectedVia: TLineInfo flags: set[SubgraphFlag] + maxMutation, minConnection: int + mutations: seq[int] Partitions = object + abstractTime: int s: seq[VarIndex] graphs: seq[MutationInfo] unanalysableMutation, performCursorInference: bool inAsgnSource, inConstructor, inNoSideEffectSection: int +proc mutationAfterConnection(g: MutationInfo): bool {.inline.} = + #echo g.maxMutation, " ", g.minConnection, " ", g.param + g.maxMutation > g.minConnection + proc `$`*(config: ConfigRef; g: MutationInfo): string = result = "" if g.flags == {isMutated, connectsConstParam}: @@ -68,27 +76,31 @@ proc `$`*(config: ConfigRef; g: MutationInfo): string = proc hasSideEffect(c: var Partitions; info: var MutationInfo): bool = for g in mitems c.graphs: - if g.flags == {isMutated, connectsConstParam}: + if g.flags == {isMutated, connectsConstParam} and mutationAfterConnection(g): info = g return true return false template isConstParam(a): bool = a.kind == skParam and a.typ.kind != tyVar -proc registerVariable(c: var Partitions; n: PNode) = - if n.kind == nkSym: - if isConstParam(n.sym): - c.s.add VarIndex(kind: isRootOf, graphIndex: c.graphs.len, sym: n.sym) - c.graphs.add MutationInfo(param: n.sym, mutatedHere: unknownLineInfo, - connectedVia: unknownLineInfo, flags: {connectsConstParam}) - else: - c.s.add VarIndex(kind: isEmptyRoot, sym: n.sym) - proc variableId(c: Partitions; x: PSym): int {.inline.} = for i in 0 ..< c.s.len: if c.s[i].sym == x: return i return -1 +proc registerVariable(c: var Partitions; n: PNode) = + if n.kind == nkSym and variableId(c, n.sym) < 0: + if isConstParam(n.sym): + c.s.add VarIndex(kind: isRootOf, graphIndex: c.graphs.len, sym: n.sym, + aliveStart: c.abstractTime, aliveEnd: c.abstractTime) + c.graphs.add MutationInfo(param: n.sym, mutatedHere: unknownLineInfo, + connectedVia: unknownLineInfo, flags: {connectsConstParam}, + maxMutation: -1, minConnection: high(int), + mutations: @[]) + else: + c.s.add VarIndex(kind: isEmptyRoot, sym: n.sym, + aliveStart: c.abstractTime, aliveEnd: c.abstractTime) + proc root(v: var Partitions; start: int): int = result = start var depth = 0 @@ -101,7 +113,9 @@ proc root(v: var Partitions; start: int): int = while v.s[it].kind == dependsOn: let next = v.s[it].parent v.s[it] = VarIndex(kind: dependsOn, parent: result, - sym: v.s[it].sym, flags: v.s[it].flags) + sym: v.s[it].sym, flags: v.s[it].flags, + aliveStart: v.s[it].aliveStart, + aliveEnd: v.s[it].aliveEnd) it = next proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = @@ -111,16 +125,22 @@ proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = case v.s[r].kind of isEmptyRoot: v.s[r] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len, - sym: v.s[r].sym, flags: v.s[r].flags) + sym: v.s[r].sym, flags: v.s[r].flags, + aliveStart: v.s[r].aliveStart, + aliveEnd: v.s[r].aliveEnd) v.graphs.add MutationInfo(param: if isConstParam(s): s else: nil, mutatedHere: info, - connectedVia: unknownLineInfo, flags: {isMutated}) + connectedVia: unknownLineInfo, flags: {isMutated}, + maxMutation: v.abstractTime, minConnection: high(int), + mutations: @[v.abstractTime]) of isRootOf: let g = addr v.graphs[v.s[r].graphIndex] if g.param == nil and isConstParam(s): g.param = s - if g.mutatedHere == unknownLineInfo: + if v.abstractTime > g.maxMutation: g.mutatedHere = info + g.maxMutation = v.abstractTime g.flags.incl isMutated + g.mutations.add v.abstractTime else: assert false, "cannot happen" else: @@ -150,24 +170,39 @@ proc connect(v: var Partitions; a, b: PSym; info: TLineInfo) = # for now we always make 'rb' the slave and 'ra' the master: var rbFlags: set[SubgraphFlag] = {} var mutatedHere = unknownLineInfo + var mut = 0 + var con = v.abstractTime + var gb: ptr MutationInfo = nil if v.s[rb].kind == isRootOf: - var gb = addr v.graphs[v.s[rb].graphIndex] + gb = addr v.graphs[v.s[rb].graphIndex] if param == nil: param = gb.param mutatedHere = gb.mutatedHere rbFlags = gb.flags + mut = gb.maxMutation + con = min(con, gb.minConnection) - v.s[rb] = VarIndex(kind: dependsOn, parent: ra, sym: v.s[rb].sym, flags: v.s[rb].flags) + v.s[rb] = VarIndex(kind: dependsOn, parent: ra, sym: v.s[rb].sym, flags: v.s[rb].flags, + aliveStart: v.s[rb].aliveStart, + aliveEnd: v.s[rb].aliveEnd) case v.s[ra].kind of isEmptyRoot: - v.s[ra] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len, sym: v.s[ra].sym, flags: v.s[ra].flags) + v.s[ra] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len, sym: v.s[ra].sym, + flags: v.s[ra].flags, + aliveStart: v.s[ra].aliveStart, + aliveEnd: v.s[ra].aliveEnd) v.graphs.add MutationInfo(param: param, mutatedHere: mutatedHere, - connectedVia: info, flags: paramFlags + rbFlags) + connectedVia: info, flags: paramFlags + rbFlags, + maxMutation: mut, minConnection: con, + mutations: if gb != nil: gb.mutations else: @[]) of isRootOf: var g = addr v.graphs[v.s[ra].graphIndex] if g.param == nil: g.param = param if g.mutatedHere == unknownLineInfo: g.mutatedHere = mutatedHere + g.minConnection = min(g.minConnection, con) g.connectedVia = info g.flags.incl paramFlags + rbFlags + if gb != nil: + g.mutations.add gb.mutations else: assert false, "cannot happen" @@ -364,6 +399,7 @@ proc deps(c: var Partitions; dest, src: PNode) = rhsIsSink(c, src) proc traverse(c: var Partitions; n: PNode) = + inc c.abstractTime case n.kind of nkLetSection, nkVarSection: for child in n: @@ -384,10 +420,18 @@ proc traverse(c: var Partitions; n: PNode) = traverse(c, n[1]) dec c.inAsgnSource deps(c, n[0], n[1]) - of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, + of nkSym: + dec c.abstractTime + if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}: + let id = variableId(c, n.sym) + if id >= 0: + c.s[id].aliveEnd = max(c.s[id].aliveEnd, c.abstractTime) + + of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: + dec c.abstractTime discard "do not follow the construct" of nkCallKinds: for child in n: traverse(c, child) @@ -450,6 +494,14 @@ proc traverse(c: var Partitions; n: PNode) = inc c.inNoSideEffectSection, enforceNoSideEffects traverse(c, n.lastSon) dec c.inNoSideEffectSection, enforceNoSideEffects + of nkWhileStmt, nkForStmt, nkParForStmt: + for child in n: traverse(c, child) + # analyse loops twice so that 'abstractTime' suffices to detect cases + # like: + # while cond: + # mutate(graph) + # connect(graph, cursorVar) + for child in n: traverse(c, child) else: for child in n: traverse(c, child) @@ -465,6 +517,13 @@ proc mutatesNonVarParameters*(s: PSym; n: PNode; info: var MutationInfo): bool = traverse(par, n) result = hasSideEffect(par, info) +proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = + if isMutated in g.flags: + for m in g.mutations: + if m in v.aliveStart..v.aliveEnd: + return true + return false + proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = var par = Partitions(performCursorInference: true) if s.kind notin {skMacro, skModule}: @@ -481,7 +540,7 @@ proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = v.sym.flags * {sfThread, sfGlobal} == {} and hasDestructor(v.sym.typ) and v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned: let rid = root(par, i) - if par.s[rid].kind == isRootOf and isMutated in par.graphs[par.s[rid].graphIndex].flags: + if par.s[rid].kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].graphIndex], par.s[i]): discard "cannot cursor into a graph that is mutated" else: v.sym.flags.incl sfCursor diff --git a/tests/effects/tfuncs_cannot_mutate.nim b/tests/effects/tfuncs_cannot_mutate.nim index 2990894ed..4768af2b3 100644 --- a/tests/effects/tfuncs_cannot_mutate.nim +++ b/tests/effects/tfuncs_cannot_mutate.nim @@ -1,9 +1,9 @@ discard """ errormsg: "'mutate' can have side effects" nimout: '''an object reachable from 'n' is potentially mutated -tfuncs_cannot_mutate.nim(34, 15) the mutation is here -tfuncs_cannot_mutate.nim(32, 7) is the statement that connected the mutation to the parameter''' - line: 28 +tfuncs_cannot_mutate.nim(39, 15) the mutation is here +tfuncs_cannot_mutate.nim(37, 7) is the statement that connected the mutation to the parameter''' + line: 33 """ {.experimental: "strictFuncs".} @@ -13,6 +13,11 @@ type le, ri: Node data: string +func insert(x: var seq[Node]; yyy: Node) = + let L = x.len + x.setLen L + 1 + x[L] = yyy + func len(n: Node): int = var it = n while it != nil: From e08b802d79e173d230b893ed96fd82c3c5228161 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 7 Sep 2020 18:10:20 +0800 Subject: [PATCH 1062/4254] more Protocol supports in windows (#15274) [backport:1.2] --- lib/pure/nativesockets.nim | 24 +++++++++++++++++++----- tests/stdlib/tnativesockets.nim | 29 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 tests/stdlib/tnativesockets.nim diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 0b0c4b398..9303dff1d 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -68,11 +68,11 @@ type Protocol* = enum ## third argument to `socket` proc IPPROTO_TCP = 6, ## Transmission control protocol. IPPROTO_UDP = 17, ## User datagram protocol. - IPPROTO_IP, ## Internet protocol. Unsupported on Windows. - IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows. + IPPROTO_IP, ## Internet protocol. + IPPROTO_IPV6, ## Internet Protocol Version 6. IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. - IPPROTO_ICMP ## Control message protocol. Unsupported on Windows. - IPPROTO_ICMPV6 ## Control message protocol for IPv6. Unsupported on Windows. + IPPROTO_ICMP ## Control message protocol. + IPPROTO_ICMPV6 ## Control message protocol for IPv6. Servent* = object ## information about a service name*: string @@ -174,7 +174,21 @@ else: result = cint(ord(typ)) proc toInt(p: Protocol): cint = - result = cint(ord(p)) + case p + of IPPROTO_IP: + result = 0.cint + of IPPROTO_ICMP: + result = 1.cint + of IPPROTO_TCP: + result = 6.cint + of IPPROTO_UDP: + result = 17.cint + of IPPROTO_IPV6: + result = 41.cint + of IPPROTO_ICMPV6: + result = 58.cint + else: + result = cint(ord(p)) proc toSockType*(protocol: Protocol): SockType = result = case protocol diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim new file mode 100644 index 000000000..b0cfd09cf --- /dev/null +++ b/tests/stdlib/tnativesockets.nim @@ -0,0 +1,29 @@ +discard """ + cmd: "nim c -r --styleCheck:hint --panics:on $options $file" + targets: "c" + nimout: "" + action: "run" + exitcode: 0 + timeout: 60.0 +""" + +import nativesockets + + +when defined(windows): + doAssert toInt(IPPROTO_IP) == 0.cint + doAssert toInt(IPPROTO_ICMP) == 1.cint + doAssert toInt(IPPROTO_TCP) == 6.cint + doAssert toInt(IPPROTO_UDP) == 17.cint + doAssert toInt(IPPROTO_IPV6) == 41.cint + doAssert toInt(IPPROTO_ICMPV6) == 58.cint + doAssert toInt(IPPROTO_RAW) == 20.cint + + # no changes to enum value + doAssert ord(IPPROTO_TCP) == 6 + doAssert ord(IPPROTO_UDP) == 17 + doAssert ord(IPPROTO_IP) == 18 + doAssert ord(IPPROTO_IPV6) == 19 + doAssert ord(IPPROTO_RAW) == 20 + doAssert ord(IPPROTO_ICMP) == 21 + doAssert ord(IPPROTO_ICMPV6) == 22 From 0b74d26d0c45e0fe16126bd264072783afacd12a Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Mon, 7 Sep 2020 14:04:07 -0400 Subject: [PATCH 1063/4254] don't raise index defects on malformed ast (#15278) * don't raise index defects on malformed ast * style --- compiler/semcall.nim | 11 ++++++++--- compiler/semstmts.nim | 9 ++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 1a6f754ee..3e4ed096b 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -495,9 +495,14 @@ proc updateDefaultParams(call: PNode) = proc getCallLineInfo(n: PNode): TLineInfo = case n.kind of nkAccQuoted, nkBracketExpr, nkCall, nkCallStrLit, nkCommand: - getCallLineInfo(n[0]) - of nkDotExpr: getCallLineInfo(n[1]) - else: n.info + if len(n) > 0: + return getCallLineInfo(n[0]) + of nkDotExpr: + if len(n) > 1: + return getCallLineInfo(n[1]) + else: + discard + result = n.info proc semResolvedCall(c: PContext, x: TCandidate, n: PNode, flags: TExprFlags): PNode = diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index fd4635ea5..5599eb3ef 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -324,11 +324,14 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = proc getLineInfo(n: PNode): TLineInfo = case n.kind of nkPostfix: - getLineInfo(n[1]) + if len(n) > 1: + return getLineInfo(n[1]) of nkAccQuoted, nkPragmaExpr: - getLineInfo(n[0]) + if len(n) > 0: + return getLineInfo(n[0]) else: - n.info + discard + result = n.info let info = getLineInfo(n) suggestSym(c.config, info, result, c.graph.usageSym) From 098a8a7c522986ce250d4e52dc42182e5d9d7352 Mon Sep 17 00:00:00 2001 From: Scott Wadden Date: Mon, 7 Sep 2020 15:05:07 -0300 Subject: [PATCH 1064/4254] nimeval errorHook support (#15255) --- compiler/nimeval.nim | 11 +++++--- tests/compilerapi/invalid.nim | 1 + tests/compilerapi/tcompilerapi.nim | 41 ++++++++++++++++++++---------- 3 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 tests/compilerapi/invalid.nim diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index df3cb2079..5d4fea9f3 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -10,9 +10,9 @@ ## exposes the Nim VM to clients. import ast, astalgo, modules, passes, condsyms, - options, sem, semdata, llstream, vm, vmdef, - modulegraphs, idents, os, pathutils, passaux, - scriptconfig + options, sem, semdata, llstream, lineinfos, vm, + vmdef, modulegraphs, idents, os, pathutils, + passaux, scriptconfig type Interpreter* = ref object ## Use Nim as an interpreter with this object @@ -134,6 +134,11 @@ proc destroyInterpreter*(i: Interpreter) = ## destructor. discard "currently nothing to do." +proc registerErrorHook*(i: Interpreter, hook: + proc (config: ConfigRef; info: TLineInfo; msg: string; + severity: Severity) {.gcsafe.}) = + i.graph.config.structuredErrorHook = hook + proc runRepl*(r: TLLRepl; searchPaths: openArray[string]; supportNimscript: bool) = diff --git a/tests/compilerapi/invalid.nim b/tests/compilerapi/invalid.nim new file mode 100644 index 000000000..3c9364402 --- /dev/null +++ b/tests/compilerapi/invalid.nim @@ -0,0 +1 @@ +noSuchProc() diff --git a/tests/compilerapi/tcompilerapi.nim b/tests/compilerapi/tcompilerapi.nim index 9d5e0e3f2..d8489c763 100644 --- a/tests/compilerapi/tcompilerapi.nim +++ b/tests/compilerapi/tcompilerapi.nim @@ -5,6 +5,7 @@ discard """ my secret 11 12 +raising VMQuit ''' joinable: "false" """ @@ -12,34 +13,35 @@ my secret ## Example program that demonstrates how to use the ## compiler as an API to embed into your own projects. -import "../../compiler" / [ast, vmdef, vm, nimeval, llstream] +import "../../compiler" / [ast, vmdef, vm, nimeval, llstream, lineinfos, options] import std / [os] -proc main() = +proc initInterpreter(script: string): Interpreter = let std = findNimStdLibCompileTime() - var intr = createInterpreter("myscript.nim", [std, parentDir(currentSourcePath), + result = createInterpreter(script , [std, parentDir(currentSourcePath), std / "pure", std / "core"]) - intr.implementRoutine("*", "exposed", "addFloats", proc (a: VmArgs) = + +proc main() = + let i = initInterpreter("myscript.nim") + i.implementRoutine("*", "exposed", "addFloats", proc (a: VmArgs) = setResult(a, getFloat(a, 0) + getFloat(a, 1) + getFloat(a, 2)) ) - - intr.evalScript() - - let foreignProc = selectRoutine(intr, "hostProgramRunsThis") + i.evalScript() + let foreignProc = i.selectRoutine("hostProgramRunsThis") if foreignProc == nil: quit "script does not export a proc of the name: 'hostProgramRunsThis'" - let res = intr.callRoutine(foreignProc, [newFloatNode(nkFloatLit, 0.9), - newFloatNode(nkFloatLit, 0.1)]) + let res = i.callRoutine(foreignProc, [newFloatNode(nkFloatLit, 0.9), + newFloatNode(nkFloatLit, 0.1)]) doAssert res.kind == nkFloatLit echo res.floatVal - let foreignValue = selectUniqueSymbol(intr, "hostProgramWantsThis") + let foreignValue = i.selectUniqueSymbol("hostProgramWantsThis") if foreignValue == nil: quit "script does not export a global of the name: hostProgramWantsThis" - let val = intr.getGlobalValue(foreignValue) + let val = i.getGlobalValue(foreignValue) doAssert val.kind in {nkStrLit..nkTripleStrLit} echo val.strVal - destroyInterpreter(intr) + i.destroyInterpreter() main() @@ -54,3 +56,16 @@ block issue9180: evalString("echo 10+1") evalString("echo 10+2") + +block error_hook: + type VMQuit = object of CatchableError + + let i = initInterpreter("invalid.nim") + i.registerErrorHook proc(config: ConfigRef; info: TLineInfo; msg: string; + severity: Severity) {.gcsafe.} = + if severity == Error and config.errorCounter >= config.errorMax: + echo "raising VMQuit" + raise newException(VMQuit, "Script error") + + doAssertRaises(VMQuit): + i.evalScript() From a81610230ddacf33f11e8cc57a379f12a985f8b6 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 8 Sep 2020 17:27:43 +0800 Subject: [PATCH 1065/4254] nativesockets docs minor [backport: 1.2] (#15285) --- lib/pure/nativesockets.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 9303dff1d..e38dc2ecd 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -71,8 +71,8 @@ type IPPROTO_IP, ## Internet protocol. IPPROTO_IPV6, ## Internet Protocol Version 6. IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. - IPPROTO_ICMP ## Control message protocol. - IPPROTO_ICMPV6 ## Control message protocol for IPv6. + IPPROTO_ICMP ## Internet Control message protocol. + IPPROTO_ICMPV6 ## Internet Control message protocol for IPv6. Servent* = object ## information about a service name*: string @@ -113,7 +113,7 @@ proc `==`*(a, b: Port): bool {.borrow.} ## ``==`` for ports. proc `$`*(p: Port): string {.borrow.} - ## returns the port number as a string + ## Returns the port number as a string proc toInt*(domain: Domain): cint ## Converts the Domain enum to a platform-dependent ``cint``. @@ -200,7 +200,7 @@ proc toSockType*(protocol: Protocol): SockType = SOCK_RAW proc close*(socket: SocketHandle) = - ## closes a socket. + ## Closes a socket. when useWinVersion: discard winlean.closesocket(socket) else: @@ -437,7 +437,7 @@ proc getHostname*(): string {.tags: [ReadIOEffect].} = result.setLen(x) proc getSockDomain*(socket: SocketHandle): Domain = - ## returns the socket's domain (AF_INET or AF_INET6). + ## Returns the socket's domain (AF_INET or AF_INET6). var name: Sockaddr_in6 var namelen = sizeof(name).SockLen if getsockname(socket, cast[ptr SockAddr](addr(name)), @@ -450,7 +450,7 @@ proc getSockDomain*(socket: SocketHandle): Domain = raise newException(IOError, "Unknown socket family in getSockDomain") proc getAddrString*(sockAddr: ptr SockAddr): string = - ## return the string representation of address within sockAddr + ## Returns the string representation of address within sockAddr if sockAddr.sa_family.cint == nativeAfInet: result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) elif sockAddr.sa_family.cint == nativeAfInet6: @@ -517,7 +517,7 @@ when defined(posix) and not defined(nimdoc): copyMem(addr result.sun_path, path.cstring, path.len + 1) proc getSockName*(socket: SocketHandle): Port = - ## returns the socket's associated port number. + ## Returns the socket's associated port number. var name: Sockaddr_in when useWinVersion: name.sin_family = uint16(ord(AF_INET)) @@ -532,7 +532,7 @@ proc getSockName*(socket: SocketHandle): Port = result = Port(nativesockets.ntohs(name.sin_port)) proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## returns the socket's local address and port number. + ## Returns the socket's local address and port number. ## ## Similar to POSIX's `getsockname`:idx:. case domain @@ -569,7 +569,7 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## returns the socket's peer address and port number. + ## Returns the socket's peer address and port number. ## ## Similar to POSIX's `getpeername`:idx: case domain From c49b88163c12d18506ef43e4d26abd5d76f68359 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 8 Sep 2020 14:25:25 +0200 Subject: [PATCH 1066/4254] "for-loop macros" are no longer an experimental feature (#15288) --- changelog.md | 4 +++ compiler/options.nim | 2 +- compiler/semstmts.nim | 5 ++-- doc/manual.rst | 42 +++++++++++++++++++++++++++++ doc/manual_experimental.rst | 46 -------------------------------- tests/macros/tforloop_macro1.nim | 2 +- 6 files changed, 50 insertions(+), 51 deletions(-) diff --git a/changelog.md b/changelog.md index 3865f1efb..58efc42e6 100644 --- a/changelog.md +++ b/changelog.md @@ -250,6 +250,10 @@ proc mydiv(a, b): int {.raises: [].} = `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs) for more information. +- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer + an experimental feature. In other words, you don't have to write pragma + `{.experimental: "forLoopMacros".}` if you want to use them. + ## Compiler changes diff --git a/compiler/options.nim b/compiler/options.nim index 56b061358..14016495f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -154,7 +154,7 @@ type destructor, notnil, dynamicBindSym, - forLoopMacros, + forLoopMacros, # not experimental anymore; remains here for backwards compatibility caseStmtMacros, codeReordering, compiletimeFFI, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5599eb3ef..2c3ff2bea 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -890,9 +890,8 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode = checkMinSonsLen(n, 3, c.config) - if forLoopMacros in c.features: - result = handleForLoopMacro(c, n, flags) - if result != nil: return result + result = handleForLoopMacro(c, n, flags) + if result != nil: return result openScope(c) result = n n[^2] = semExprNoDeref(c, n[^2], {efWantIterator}) diff --git a/doc/manual.rst b/doc/manual.rst index b78e11b32..fc4c11f50 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5469,6 +5469,48 @@ powerful programming construct that still suffices. So the "check list" is: (4) Else: Use a macro. +For loop macros +--------------- + +A macro that takes as its only input parameter an expression of the special +type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: + +.. code-block:: nim + :test: "nim c $1" + + import macros + + macro enumerate(x: ForLoopStmt): untyped = + expectKind x, nnkForStmt + # we strip off the first for loop variable and use + # it as an integer counter: + result = newStmtList() + result.add newVarStmt(x[0], newLit(0)) + var body = x[^1] + if body.kind != nnkStmtList: + body = newTree(nnkStmtList, body) + body.add newCall(bindSym"inc", x[0]) + var newFor = newTree(nnkForStmt) + for i in 1..x.len-3: + newFor.add x[i] + # transform enumerate(X) to 'X' + newFor.add x[^2][1] + newFor.add body + result.add newFor + # now wrap the whole macro in a block to create a new scope + result = quote do: + block: `result` + + for a, b in enumerate(items([1, 2, 3])): + echo a, " ", b + + # without wrapping the macro in a block, we'd need to choose different + # names for `a` and `b` here to avoid redefinition errors + for a, b in enumerate([1, 2, 3, 5]): + echo a, " ", b + + + Special Types ============= diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 43aa84f20..913b771c2 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1030,52 +1030,6 @@ but only the statement's selector expression is used to determine which macro to call. -For loop macros ---------------- - -A macro that takes as its only input parameter an expression of the special -type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: - -.. code-block:: nim - :test: "nim c $1" - - import macros - {.experimental: "forLoopMacros".} - - macro enumerate(x: ForLoopStmt): untyped = - expectKind x, nnkForStmt - # we strip off the first for loop variable and use - # it as an integer counter: - result = newStmtList() - result.add newVarStmt(x[0], newLit(0)) - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - body.add newCall(bindSym"inc", x[0]) - var newFor = newTree(nnkForStmt) - for i in 1..x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][1] - newFor.add body - result.add newFor - # now wrap the whole macro in a block to create a new scope - result = quote do: - block: `result` - - for a, b in enumerate(items([1, 2, 3])): - echo a, " ", b - - # without wrapping the macro in a block, we'd need to choose different - # names for `a` and `b` here to avoid redefinition errors - for a, b in enumerate([1, 2, 3, 5]): - echo a, " ", b - - -Currently for loop macros must be enabled explicitly -via ``{.experimental: "forLoopMacros".}``. - - Term rewriting macros ===================== diff --git a/tests/macros/tforloop_macro1.nim b/tests/macros/tforloop_macro1.nim index 49918563d..a8f45c7ac 100644 --- a/tests/macros/tforloop_macro1.nim +++ b/tests/macros/tforloop_macro1.nim @@ -12,7 +12,7 @@ discard """ """ import macros -{.experimental: "forLoopMacros".} + macro mymacro(): untyped = result = newLit([1, 2, 3]) From 10988d48407e96b707b28c5900fcb0e59354e00a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 9 Sep 2020 07:32:03 +0200 Subject: [PATCH 1067/4254] borrow checking (#15282) * refactoring: move procs to typeallowed.nim * frontend preparations for first class openArray support * prepare the code generator for first class openArray * code generation for first class openArray; WIP * code generation for open arrays, progress * added isViewType proc * preparations for borrow checking * added borrow checking to the front end --- compiler/ccgcalls.nim | 21 +++- compiler/ccgexprs.nim | 102 ++++++++++++---- compiler/ccgstmts.nim | 2 +- compiler/ccgtypes.nim | 111 ++++++++++-------- compiler/cgen.nim | 56 +++++---- compiler/options.nim | 3 +- compiler/renderer.nim | 9 +- compiler/sem.nim | 10 +- compiler/semexprs.nim | 21 ++-- compiler/sempass2.nim | 7 +- compiler/semstmts.nim | 4 +- compiler/transf.nim | 4 + compiler/trees.nim | 2 +- compiler/typeallowed.nim | 228 ++++++++++++++++++++++++++++++++++++ compiler/types.nim | 170 +-------------------------- compiler/varpartitions.nim | 36 +++--- doc/manual_experimental.rst | 52 ++++++++ tests/ccgbugs/tviews1.nim | 27 +++++ 18 files changed, 554 insertions(+), 311 deletions(-) create mode 100644 compiler/typeallowed.nim create mode 100644 tests/ccgbugs/tviews1.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 5f99f357d..6d254ca6f 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -141,6 +141,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, proc genBoundsCheck(p: BProc; arr, a, b: TLoc) +proc reifiedOpenArray(n: PNode): bool {.inline.} = + let x = trees.getRoot(n) + if x != nil and x.kind == skParam: + result = false + else: + result = true + proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = var a: TLoc @@ -174,7 +181,12 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest] - of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString: + of tyOpenArray, tyVarargs: + if reifiedOpenArray(q[1]): + result = "($4*)($1.d)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] + else: + result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] + of tyUncheckedArray, tyCString: result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: let atyp = skipTypes(a.t, abstractInst) @@ -188,10 +200,13 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: - initLocExpr(p, n, a) + initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a) case skipTypes(a.t, abstractVar).kind of tyOpenArray, tyVarargs: - result = "$1, $1Len_0" % [rdLoc(a)] + if reifiedOpenArray(n): + result = "$1.d, $1.l" % [rdLoc(a)] + else: + result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: let ntyp = skipTypes(n.typ, abstractInst) if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dd4774b2a..8f45452bf 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -271,6 +271,34 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) +proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = + assert d.k != locNone + # getTemp(p, d.t, d) + + case a.t.skipTypes(abstractVar).kind + of tyOpenArray, tyVarargs: + if reifiedOpenArray(a.lode): + linefmt(p, cpsStmts, "$1.d = $2.d; $1.l = $2.l;$n", + [rdLoc(d), a.rdLoc]) + else: + linefmt(p, cpsStmts, "$1.d = $2; $1.l = $2Len_0;$n", + [rdLoc(d), a.rdLoc]) + of tySequence: + linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n", + [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)]) + of tyArray: + linefmt(p, cpsStmts, "$1.d = $2; $1.l = $3;$n", + [rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))]) + of tyString: + let etyp = skipTypes(a.t, abstractInst) + if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + + linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n", + [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)]) + else: + internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind) + proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating # the assignment operation in C. @@ -349,7 +377,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyOpenArray, tyVarargs: # open arrays are always on the stack - really? What if a sequence is # passed to an open array? - if containsGarbageCollectedRef(dest.t): + if reifiedOpenArray(dest.lode): + genOpenArrayConv(p, dest, src) + elif containsGarbageCollectedRef(dest.t): linefmt(p, cpsStmts, # XXX: is this correct for arrays? "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), @@ -361,7 +391,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tySet: - if mapType(p.config, ty) == ctArray: + if mapSetType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: @@ -406,7 +436,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfo(p.module, dest.t, dest.lode.info)]) of tySet: - if mapType(p.config, ty) == ctArray: + if mapSetType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: @@ -679,7 +709,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} = tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags proc genDeref(p: BProc, e: PNode, d: var TLoc) = - let mt = mapType(p.config, e[0].typ) + let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? @@ -747,7 +777,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e[0], a) putIntoDest(p, d, e, "&" & a.r, a.storage) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(p.config, e[0].typ) == ctArray or isCppRef(p, e.typ): + elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ): expr(p, e[0], d) else: var a: TLoc @@ -905,10 +935,16 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = let ty = skipTypes(arr.t, abstractVarRange) case ty.kind of tyOpenArray, tyVarargs: - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n", - [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) + if reifiedOpenArray(arr.lode): + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "((NU)($1) >= (NU)($3.l) || (NU)($2) >= (NU)($3.l))){ #raiseIndexError(); $4}$n", + [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) + else: + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n", + [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) of tyArray: let first = intLiteral(firstOrd(p.config, ty)) linefmt(p, cpsStmts, @@ -925,13 +961,22 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) - initLocExpr(p, y, b) # emit range check: - if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", - [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + initLocExpr(p, y, b) + if not reifiedOpenArray(x): + # emit range check: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", + [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! + inheritLocation(d, a) + putIntoDest(p, d, n, + ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + else: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.l)){ #raiseIndexError2($1,$2.l-1); $3}$n", + [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! + inheritLocation(d, a) + putIntoDest(p, d, n, + ropecg(p.module, "$1.d[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -1675,8 +1720,12 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)])) else: - if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") - else: unaryExpr(p, e, d, "$1Len_0") + if not reifiedOpenArray(a): + if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") + else: unaryExpr(p, e, d, "$1Len_0") + else: + if op == mHigh: unaryExpr(p, e, d, "($1.l-1)") + else: unaryExpr(p, e, d, "$1.l") of tyCString: if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") @@ -2253,13 +2302,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)]) of mOffsetOf: var dotExpr: PNode - block findDotExpr: - if e[1].kind == nkDotExpr: - dotExpr = e[1] - elif e[1].kind == nkCheckedFieldExpr: - dotExpr = e[1][0] - else: - internalError(p.config, e.info, "unknown ast") + if e[1].kind == nkDotExpr: + dotExpr = e[1] + elif e[1].kind == nkCheckedFieldExpr: + dotExpr = e[1][0] + else: + internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) let tname = getTypeDesc(p.module, t) let member = @@ -2813,8 +2861,10 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = result.add getDefaultValue(p, t.sons[1], info) result.add "}" #result = rope"{}" + of tyOpenArray, tyVarargs: + result = rope"{NIM_NIL, 0}" of tySet: - if mapType(p.config, t) == ctArray: result = rope"{}" + if mapSetType(p.config, t) == ctArray: result = rope"{}" else: result = rope"0" else: globalError(p.config, info, "cannot create null element for: " & $t.kind) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e40e94d01..48c024b1f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1556,7 +1556,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = let le = e[0] let ri = e[1] var a: TLoc - discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs)) + discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar) initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fad6093ed..5b5720934 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -149,7 +149,7 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctArray -proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = +proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = ## Maps a Nim type to a C type case typ.kind of tyNone, tyTyped: result = ctVoid @@ -157,14 +157,17 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of tyChar: result = ctChar of tyNil: result = ctPtr of tySet: result = mapSetType(conf, typ) - of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray + of tyOpenArray, tyVarargs: + if kind == skParam: result = ctArray + else: result = ctStruct + of tyArray, tyUncheckedArray: result = ctArray of tyObject, tyTuple: result = ctStruct of tyUserTypeClasses: doAssert typ.isResolvedUserTypeClass - return mapType(conf, typ.lastSon) + return mapType(conf, typ.lastSon, kind) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned: - result = mapType(conf, lastSon(typ)) + result = mapType(conf, lastSon(typ), kind) of tyEnum: if firstOrd(conf, typ) < 0: result = ctInt32 @@ -175,7 +178,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of 4: result = ctInt32 of 8: result = ctInt64 else: result = ctInt32 - of tyRange: result = mapType(conf, typ[0]) + of tyRange: result = mapType(conf, typ[0], kind) of tyPtr, tyVar, tyLent, tyRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind @@ -192,14 +195,14 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: - if typ.n != nil: result = mapType(conf, lastSon typ) + if typ.n != nil: result = mapType(conf, lastSon typ, kind) else: doAssert(false, "mapType") else: doAssert(false, "mapType") proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr #else: - result = mapType(conf, typ) + result = mapType(conf, typ, skResult) proc isImportedType(t: PType): bool = result = t.sym != nil and sfImportc in t.sym.flags @@ -209,7 +212,7 @@ proc isImportedCppType(t: PType): bool = result = (t.sym != nil and sfInfixCall in t.sym.flags) or (x.sym != nil and sfInfixCall in x.sym.flags) -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope +proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and @@ -222,7 +225,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = # is necessary for proper code generation of assignments. if rettype == nil: result = true else: - case mapType(conf, rettype) + case mapType(conf, rettype, skResult) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyLent, tyRef, tyPtr}) @@ -346,8 +349,8 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope = if result == nil: result = cacheGetType(m.typeCache, sig) proc structOrUnion(t: PType): Rope = - let cachedUnion {.global.} = rope("union") - let cachedStruct {.global.} = rope("struct") + let cachedUnion = rope("union") + let cachedStruct = rope("struct") let t = t.skipTypes({tyAlias, tySink}) if tfUnion in t.flags: cachedUnion else: cachedStruct @@ -379,7 +382,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = doAssert m.forwTypeCache[sig] == result else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') -proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope = ## like getTypeDescAux but creates only a *weak* dependency. In other words ## we know we only need a pointer to it so we only generate a struct forward ## declaration: @@ -387,7 +390,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and t.kind == tyGenericInst: - result = getTypeDescAux(m, t, check) + result = getTypeDescAux(m, t, check, kind) else: result = getTypeForward(m, t, hashType(t)) pushType(m, t) @@ -417,18 +420,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = result = getTypeForward(m, t, sig) & seqStar(m) pushType(m, t) else: - result = getTypeDescAux(m, t, check) + result = getTypeDescAux(m, t, check, kind) proc getSeqPayloadType(m: BModule; t: PType): Rope = var check = initIntSet() - result = getTypeDescWeak(m, t, check) & "_Content" + result = getTypeDescWeak(m, t, check, skParam) & "_Content" #result = getTypeForward(m, t, hashType(t)) & "_Content" proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = let sig = hashType(t) let result = cacheGetType(m.typeCache, sig) if result == nil: - discard getTypeDescAux(m, t, check) + discard getTypeDescAux(m, t, check, skVar) else: # little hack for now to prevent multiple definitions of the same # Seq_Content: @@ -437,7 +440,7 @@ $3ifndef $2_Content_PP $3define $2_Content_PP struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; $3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"]) + """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -453,7 +456,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, if t[0] == nil or isInvalidReturnType(m.config, t[0]): rettype = ~"void" else: - rettype = getTypeDescAux(m, t[0], check) + rettype = getTypeDescAux(m, t[0], check, skResult) for i in 1.. 0: result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) - result.add getTypeDesc(p.module, s.typ) + result.add getTypeDesc(p.module, s.typ, skVar) if s.constraint.isNil: if sfRegister in s.flags: result.add(" register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: @@ -541,7 +547,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = internalError(p.config, n.info, ".threadvar variables cannot have a value") else: var decl: Rope = nil - var td = getTypeDesc(p.module, s.loc.t) + var td = getTypeDesc(p.module, s.loc.t, skVar) if s.constraint.isNil: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] @@ -687,7 +693,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = initLoc(dest, locTemp, lib.path, OnStack) dest.r = getTempName(m) appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", - [getTypeDesc(m, lib.path.typ), rdLoc(dest)]) + [getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)]) expr(p, lib.path, dest) m.s[cfsVars].add(p.s(cpsLocals)) @@ -727,7 +733,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) = params.add(rdLoc(a)) params.add(", ") let load = "\t$1 = ($2) ($3$4));$n" % - [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)] + [tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)] var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last[1] internalAssert(m.config, last.kind == nkStrLit) @@ -741,8 +747,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) = else: appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)]) - m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) + [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) + m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -754,9 +760,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) = inc(m.labels, 2) appcg(m, m.s[cfsDynLibInit], "$1 = ($2*) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)]) + [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) m.s[cfsVars].addf("$2* $1;$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t)]) + [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.loc.r = mangleDynLibProc(sym) @@ -1187,7 +1193,7 @@ proc requestConstImpl(p: BProc, sym: PSym) = [getTypeDesc(q, sym.typ), actualConstName, genBracedInit(q.initProc, sym.ast, isConst = true)]) if m.hcrOn: # generate the global pointer with the real name - q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t), sym.loc.r]) + q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]) # register it (but ignore the boolean result of hcrRegisterGlobal) q.initProc.procSec(cpsLocals).addf( "\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n", @@ -1201,13 +1207,13 @@ proc requestConstImpl(p: BProc, sym: PSym) = if q != m and not containsOrIncl(m.declaredThings, sym.id): assert(sym.loc.r != nil) if m.hcrOn: - m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t), sym.loc.r]); + m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]); m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t), getModuleDllPath(q, sym)]) + getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)]) else: let headerDecl = "extern NIM_CONST $1 $2;$n" % - [getTypeDesc(m, sym.loc.t), sym.loc.r] + [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r] m.s[cfsData].add(headerDecl) if sfExportc in sym.flags and p.module.g.generatedHeader != nil: p.module.g.generatedHeader.s[cfsData].add(headerDecl) @@ -1247,7 +1253,7 @@ proc genVarPrototype(m: BModule, n: PNode) = if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0: m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)] m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ") - m.s[cfsVars].add(getTypeDesc(m, sym.loc.t)) + m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar)) if m.hcrOn: m.s[cfsVars].add("*") if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") if sfRegister in sym.flags: m.s[cfsVars].add(" register") @@ -1255,7 +1261,7 @@ proc genVarPrototype(m: BModule, n: PNode) = m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) if m.hcrOn: m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) + getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)]) proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = result.addf("#define NIM_INTBITS $1\L", [ @@ -1613,10 +1619,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R prc.typ.sym = nil if not containsOrIncl(m.declaredThings, prc.id): - m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)]) + m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)]) result = "\t$1 = ($2) $3($4, $5);$n" % - [tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] + [tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] proc genInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, diff --git a/compiler/options.nim b/compiler/options.nim index 14016495f..5b23ac9af 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -162,7 +162,8 @@ type ## which itself requires `nimble install libffi`, see #10150 ## Note: this feature can't be localized with {.push.} vmopsDanger, - strictFuncs + strictFuncs, + views LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 9601bf082..9c7609f9a 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1035,7 +1035,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsub(g, n, 1) of nkHiddenStdConv, nkHiddenSubConv: if n.len >= 2: - gsub(g, n[1]) + when false: + # if {renderIds, renderIr} * g.flags != {}: + put(g, tkSymbol, "(conv)") + put(g, tkParLe, "(") + gsub(g, n[1]) + put(g, tkParRi, ")") + else: + gsub(g, n[1]) else: put(g, tkSymbol, "(wrong conv)") of nkHiddenCallConv: diff --git a/compiler/sem.nim b/compiler/sem.nim index 07c76eed4..705e1b72c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -17,7 +17,7 @@ import intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, lowerings, plugins/active, rod, lineinfos, strtabs, int128, - isolation_check + isolation_check, typeallowed from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward @@ -228,9 +228,9 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym -proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind; +proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind; flags: TTypeAllowedFlags = {}) = - let t = typeAllowed(typ, kind, flags) + let t = typeAllowed(typ, kind, c, flags) if t != nil: var err: string if t == typ: @@ -240,10 +240,10 @@ proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKi else: err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t), typeToString(typ), toHumanStr(kind)] - localError(conf, info, err) + localError(c.config, info, err) proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = - typeAllowedCheck(c.config, typ.n.info, typ, skProc) + typeAllowedCheck(c, typ.n.info, typ, skProc) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0e1c5e9d3..80e04ead4 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -178,7 +178,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = else: discard -proc isCastable(conf: ConfigRef; dst, src: PType): bool = +proc isCastable(c: PContext; dst, src: PType): bool = ## Checks whether the source type can be cast to the destination type. ## Casting is very unrestrictive; casts are allowed as long as ## castDest.size >= src.size, and typeAllowed(dst, skParam) @@ -193,6 +193,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = return false if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass: return false + let conf = c.config if conf.selectedGC in {gcArc, gcOrc}: let d = skipTypes(dst, abstractInst) let s = skipTypes(src, abstractInst) @@ -210,7 +211,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = result = false elif srcSize < 0: result = false - elif typeAllowed(dst, skParam) != nil: + elif typeAllowed(dst, skParam, c) != nil: result = false elif dst.kind == tyProc and dst.callConv == ccClosure: result = src.kind == tyProc and src.callConv == ccClosure @@ -338,7 +339,7 @@ proc semCast(c: PContext, n: PNode): PNode = let castedExpr = semExprWithType(c, n[1]) if tfHasMeta in targetType.flags: localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType) - if not isCastable(c.config, targetType, castedExpr.typ): + if not isCastable(c, targetType, castedExpr.typ): let tar = $targetType let alt = typeToString(targetType, preferDesc) let msg = if tar != alt: tar & "=" & alt else: tar @@ -794,7 +795,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine: return - if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return + if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return var call = newNodeIT(nkCall, n.info, n.typ) call.add(n[0]) @@ -962,9 +963,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # t.sym != nil # sfAnon notin t.sym.flags # t.kind != tySequence(It is tyProc) - if typ.sym != nil and sfAnon notin typ.sym.flags and + if typ.sym != nil and sfAnon notin typ.sym.flags and typ.kind == tyProc: - msg.add(" = " & + msg.add(" = " & typeToString(typ, preferDesc)) localError(c.config, n.info, msg) return errorNode(c, n) @@ -1600,7 +1601,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le[0] - if x.typ.kind in {tyVar, tyLent} and x.kind == nkSym and x.sym.kind == skResult: + if (x.typ.kind in {tyVar, tyLent} or isViewType(x.typ)) and x.kind == nkSym and x.sym.kind == skResult: n[0] = x # 'result[]' --> 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr @@ -1732,7 +1733,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}: internalAssert c.config, c.p.resultSym != nil # Make sure the type is valid for the result variable - typeAllowedCheck(c.config, n.info, rhsTyp, skResult) + typeAllowedCheck(c, n.info, rhsTyp, skResult) lhs.typ = rhsTyp c.p.resultSym.typ = rhsTyp c.p.owner.typ[0] = rhsTyp @@ -1825,7 +1826,9 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent) else: localError(c.config, n[0].info, errXExpected, "tuple constructor") - else: discard + else: + if isViewType(t): + n[0] = takeImplicitAddr(c, n[0], false) proc semYield(c: PContext, n: PNode): PNode = result = n diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f745f9075..b48d7e29e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1243,8 +1243,11 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = effects[ensuresEffects] = ensuresSpec var mutationInfo = MutationInfo() - if strictFuncs in c.features and not t.hasSideEffect and t.hasDangerousAssign: - t.hasSideEffect = mutatesNonVarParameters(s, body, mutationInfo) + if {strictFuncs, views} * c.features != {}: + var partitions = computeGraphPartitions(s, body) + if not t.hasSideEffect and t.hasDangerousAssign: + t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) + checkBorrowedLocations(partitions, g.config) if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2c3ff2bea..14f08b4b3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -534,7 +534,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if c.matchedConcept != nil: typFlags.incl taConcept - typeAllowedCheck(c.config, a.info, typ, symkind, typFlags) + typeAllowedCheck(c, a.info, typ, symkind, typFlags) when false: liftTypeBoundOps(c, typ, a.info) instAllTypeBoundOp(c, a.info) @@ -667,7 +667,7 @@ proc semConst(c: PContext, n: PNode): PNode = if def.kind != nkNilLit: if c.matchedConcept != nil: typFlags.incl taConcept - typeAllowedCheck(c.config, a.info, typ, skConst, typFlags) + typeAllowedCheck(c, a.info, typ, skConst, typFlags) var b: PNode if a.kind == nkVarTuple: diff --git a/compiler/transf.nim b/compiler/transf.nim index 8ff0664da..5dd275414 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -494,6 +494,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = result = transformSons(c, n) of tyOpenArray, tyVarargs: result = transform(c, n[1]) + #result = transformSons(c, n) result.typ = takeType(n.typ, n[1].typ) #echo n.info, " came here and produced ", typeToString(result.typ), # " from ", typeToString(n.typ), " and ", typeToString(n[1].typ) @@ -1107,6 +1108,9 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode = else: prc.transformedBody = nil + #if prc.name.s == "main": + # echo "transformed into ", renderTree(result, {renderIds}) + proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n diff --git a/compiler/trees.nim b/compiler/trees.nim index bfb429f13..c5c1a0d75 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -183,7 +183,7 @@ proc getRoot*(n: PNode): PSym = if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}: result = n.sym of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr, - nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: + nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr, nkHiddenAddr, nkAddr: result = getRoot(n[0]) of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = getRoot(n[1]) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim new file mode 100644 index 000000000..5a192783e --- /dev/null +++ b/compiler/typeallowed.nim @@ -0,0 +1,228 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains 'typeAllowed' and friends which check +## for invalid types like 'openArray[var int]'. + +import + intsets, ast, renderer, options, semdata, types + +type + TTypeAllowedFlag* = enum + taField, + taHeap, + taConcept, + taIsOpenArray, + taNoUntyped + taIsTemplateOrMacro + taProcContextIsNotMacro + + TTypeAllowedFlags* = set[TTypeAllowedFlag] + +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind; + c: PContext; flags: TTypeAllowedFlags = {}): PType + +proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind, + c: PContext; flags: TTypeAllowedFlags = {}): PType = + if n != nil: + result = typeAllowedAux(marker, n.typ, kind, c, flags) + if result == nil: + case n.kind + of nkNone..nkNilLit: + discard + else: + #if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}: + # return n[0].typ + for i in 0.. Date: Wed, 9 Sep 2020 07:36:31 +0200 Subject: [PATCH 1068/4254] Better semiStmtList parsing (#15123) * Better semiStmtList parsing * Add examples from forums and wiki * Move parseIfExpr near parseIfOrWhen * Update grammar --- compiler/parser.nim | 122 ++++++++++---------------- tests/parser/tstmtlists.nim | 165 ++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 78 deletions(-) create mode 100644 tests/parser/tstmtlists.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index 0fa860c99..f256cee66 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -523,15 +523,21 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode = proc complexOrSimpleStmt(p: var Parser): PNode proc simpleExpr(p: var Parser, mode = pmNormal): PNode +proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode proc semiStmtList(p: var Parser, result: PNode) = inc p.inSemiStmtList - result.add(complexOrSimpleStmt(p)) - # progress guaranteed - while p.tok.tokType == tkSemiColon: - getTok(p) - optInd(p, result) - result.add(complexOrSimpleStmt(p)) + withInd(p): + # Be lenient with the first stmt/expr + result.add if p.tok.tokType == tkIf: parseIfExpr(p, nkIfStmt) else: complexOrSimpleStmt(p) + while true: + if p.tok.tokType == tkSemiColon: + getTok(p) + if p.tok.tokType == tkParRi: + break + elif not (sameInd(p) or realInd(p)): + parMessage(p, errInvalidIndentation) + result.add complexOrSimpleStmt(p) dec p.inSemiStmtList result.transitionSonsKind(nkStmtListExpr) @@ -540,10 +546,10 @@ proc parsePar(p: var Parser): PNode = #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' #| | 'when' | 'var' | 'mixin' #| par = '(' optInd - #| ( &parKeyw complexOrSimpleStmt ^+ ';' - #| | ';' complexOrSimpleStmt ^+ ';' + #| ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';' + #| | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';' #| | pragmaStmt - #| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? ) + #| | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? ) #| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) #| optPar ')' # @@ -847,64 +853,6 @@ proc simpleExpr(p: var Parser, mode = pmNormal): PNode = when defined(nimpretty): dec p.em.doIndentMore -proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode = - #| condExpr = expr colcom expr optInd - #| ('elif' expr colcom expr optInd)* - #| 'else' colcom expr - #| ifExpr = 'if' condExpr - #| whenExpr = 'when' condExpr - when true: - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `when`, `elif` - var branch = newNodeP(nkElifExpr, p) - optInd(p, branch) - branch.add(parseExpr(p)) - colcom(p, branch) - branch.add(parseStmt(p)) - skipComment(p, branch) - result.add(branch) - if p.tok.tokType != tkElif: break # or not sameOrNoInd(p): break - if p.tok.tokType == tkElse: # and sameOrNoInd(p): - var branch = newNodeP(nkElseExpr, p) - eat(p, tkElse) - colcom(p, branch) - branch.add(parseStmt(p)) - result.add(branch) - else: - var - b: PNode - wasIndented = false - result = newNodeP(kind, p) - - getTok(p) - let branch = newNodeP(nkElifExpr, p) - branch.add(parseExpr(p)) - colcom(p, branch) - let oldInd = p.currInd - if realInd(p): - p.currInd = p.tok.indent - wasIndented = true - branch.add(parseExpr(p)) - result.add branch - while sameInd(p) or not wasIndented: - case p.tok.tokType - of tkElif: - b = newNodeP(nkElifExpr, p) - getTok(p) - optInd(p, b) - b.add(parseExpr(p)) - of tkElse: - b = newNodeP(nkElseExpr, p) - getTok(p) - else: break - colcom(p, b) - b.add(parseStmt(p)) - result.add(b) - if b.kind == nkElseExpr: break - if wasIndented: - p.currInd = oldInd - proc parsePragma(p: var Parser): PNode = #| pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}') result = newNodeP(nkPragma, p) @@ -1574,6 +1522,30 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode = branch.add(parseStmt(p)) result.add(branch) +proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode = + #| condExpr = expr colcom expr optInd + #| ('elif' expr colcom expr optInd)* + #| 'else' colcom expr + #| ifExpr = 'if' condExpr + #| whenExpr = 'when' condExpr + result = newNodeP(kind, p) + while true: + getTok(p) # skip `if`, `when`, `elif` + var branch = newNodeP(nkElifExpr, p) + optInd(p, branch) + branch.add(parseExpr(p)) + colcom(p, branch) + branch.add(parseStmt(p)) + skipComment(p, branch) + result.add(branch) + if p.tok.tokType != tkElif: break + if p.tok.tokType == tkElse: + var branch = newNodeP(nkElseExpr, p) + eat(p, tkElse) + colcom(p, branch) + branch.add(parseStmt(p)) + result.add(branch) + proc parseWhile(p: var Parser): PNode = #| whileStmt = 'while' expr colcom stmt result = newNodeP(nkWhileStmt, p) @@ -2269,17 +2241,11 @@ proc parseStmt(p: var Parser): PNode = # deprecate this syntax later break p.hasProgress = false - var a = complexOrSimpleStmt(p) - if a.kind != nkEmpty: - result.add(a) - else: - # This is done to make the new 'if' expressions work better. - # XXX Eventually we need to be more strict here. - if p.tok.tokType notin {tkElse, tkElif}: - parMessage(p, errExprExpected, p.tok) - getTok(p) - else: - break + if p.tok.tokType in {tkElse, tkElif}: + parMessage(p, errInvalidIndentation) + getTok(p) + + result.add complexOrSimpleStmt(p) if not p.hasProgress and p.tok.tokType == tkEof: break else: # the case statement is only needed for better error messages: diff --git a/tests/parser/tstmtlists.nim b/tests/parser/tstmtlists.nim new file mode 100644 index 000000000..b6c7e4a94 --- /dev/null +++ b/tests/parser/tstmtlists.nim @@ -0,0 +1,165 @@ +discard """ + output: ''' +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +hello +1 +hello +2 +hello +3 +hello +4 +hello +5 +hello +6 +hello +7 +hello +8 +hello +9 +hello +10 +hello +1 +hello +2 +hello +3 +hello +4 +hello +5 +hello +6 +hello +7 +hello +8 +hello +9 +hello +10 +''' +""" + +block: ( + discard; + echo 1 + 1; + ) + +block: ( + discard; #Haha + #haha + echo 1 + 1; +) + +block: ( + discard; + #Hmm + echo 1 + + 1; +) + +block: ( + discard + echo "2" +) + +block: ( + discard; + echo 1 + + 1 +) + +block: ( + discard + echo 1 + + 1 +) + +block: ( + discard; + discard +) + +block: ( + discard + echo 1 + 1; + ) + +block: ( + discard + echo 1 + 1; +) + +block: ( + discard + echo 1 + + 1; +) + +block: ( + discard; + ) + +block: ( discard; echo 1 + #heh + 1; +) + +for i in 1..10: + echo "hello" + echo i + +for i in 1..10: ( + echo "hello"; + echo i; +) + +proc square(inSeq: seq[float]): seq[float] = ( + result = newSeq[float](len(inSeq)); + for i, v in inSeq: ( + result[i] = v * v; + ) +) + +proc square2(inSeq: seq[float]): seq[float] = + result = newSeq[float](len(inSeq)); + for i, v in inSeq: ( + result[i] = v * v; + ) + +proc cstringCheck(tracked: int; n: int) = + if true == false and (let a = high(int); let b = high(int); + a.int8 == 8 and a.int8 notin {3..9}): + echo(tracked, n) + +template dim: int = + (if int.high == 0: + int.high + else: + int.high) + +template dim2: int = + (if int.high == 0: + int.high + else: + int.high) + +template dim: int = + ( + if int.high == 0: + int.high + else: + int.high) + From 7d4f0df107fdce5d1da93e26e54dd87526a0a74f Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 9 Sep 2020 12:43:04 +0200 Subject: [PATCH 1069/4254] deprecate `high(value)` and `low(value)` (#15283) --- lib/system.nim | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index dc603b56d..0a8c52908 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -288,13 +288,14 @@ else: type sink*[T]{.magic: "BuiltinType".} type lent*[T]{.magic: "BuiltinType".} -proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect.} +proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect, + deprecated: "Deprecated since v1.4; there should not be `high(value)`. Use `high(type)`.".} ## Returns the highest possible value of an ordinal value `x`. ## ## As a special semantic rule, `x` may also be a type identifier. ## - ## See also: - ## * `low(T) <#low,T>`_ + ## **This proc is deprecated**, use this one instead: + ## * `high(typedesc) <#high,typedesc[T]>`_ ## ## .. code-block:: Nim ## high(2) # => 9223372036854775807 @@ -360,12 +361,13 @@ proc high*(x: string): int {.magic: "High", noSideEffect.} ## var str = "Hello world!" ## high(str) # => 11 -proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect.} +proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect, + deprecated: "Deprecated since v1.4; there should not be `low(value)`. Use `low(type)`.".} ## Returns the lowest possible value of an ordinal value `x`. As a special ## semantic rule, `x` may also be a type identifier. ## - ## See also: - ## * `high(T) <#high,T>`_ + ## **This proc is deprecated**, use this one instead: + ## * `low(typedesc) <#low,typedesc[T]>`_ ## ## .. code-block:: Nim ## low(2) # => -9223372036854775808 From 8c82144ba507244084836b38689e4925de982626 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 9 Sep 2020 18:47:22 +0800 Subject: [PATCH 1070/4254] add getprotobyname (#15273) * add getprotobyname * tests, docs, changelog * add since --- changelog.md | 3 +++ lib/pure/nativesockets.nim | 14 ++++++++++++++ lib/windows/winlean.nim | 14 ++++++++++++++ tests/stdlib/tgetprotobyname.nim | 25 +++++++++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 tests/stdlib/tgetprotobyname.nim diff --git a/changelog.md b/changelog.md index 58efc42e6..2f7b584a3 100644 --- a/changelog.md +++ b/changelog.md @@ -168,6 +168,9 @@ cannot be applied to every use case. The limitations and the (lack of) reliability of `round` are well documented. +- Add `getprotobyname` to `winlean`. Add `getProtoByname` to `nativesockets` which returns a protocol code + from the database that matches the protocol `name`. + ## Language changes diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index e38dc2ecd..1f597f8eb 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -13,6 +13,8 @@ # TODO: Clean up the exports a bit and everything else in general. import os, options +import std/private/since + when hostOS == "solaris": {.passl: "-lsocket -lnsl".} @@ -199,6 +201,18 @@ proc toSockType*(protocol: Protocol): SockType = of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6: SOCK_RAW +proc getProtoByName*(name: string): int {.since: (1, 3, 5).} = + ## Returns a protocol code from the database that matches the protocol ``name``. + when useWinVersion: + let protoent = winlean.getprotobyname(name.cstring) + else: + let protoent = posix.getprotobyname(name.cstring) + + if protoent == nil: + raise newException(OsError, "protocol not found") + + result = protoent.p_proto.int + proc close*(socket: SocketHandle) = ## Closes a socket. when useWinVersion: diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index c28700374..1334a85d5 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -96,6 +96,12 @@ type dwPlatformId*: DWORD szCSDVersion*: array[0..127, WinChar] + Protoent* = object + p_name*: cstring + p_aliases*: cstringArray + p_proto*: cshort + + const STARTF_USESHOWWINDOW* = 1'i32 STARTF_USESTDHANDLES* = 256'i32 @@ -573,6 +579,14 @@ proc gethostbyname*(name: cstring): ptr Hostent {. proc gethostname*(hostname: cstring, len: cint): cint {. stdcall, importc: "gethostname", dynlib: ws2dll, sideEffect.} +proc getprotobyname*( + name: cstring +): ptr Protoent {.stdcall, importc: "getprotobyname", dynlib: ws2dll, sideEffect.} + +proc getprotobynumber*( + proto: cint +): ptr Protoent {.stdcall, importc: "getprotobynumber", dynlib: ws2dll, sideEffect.} + proc socket*(af, typ, protocol: cint): SocketHandle {. stdcall, importc: "socket", dynlib: ws2dll.} diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim new file mode 100644 index 000000000..c3d8da0d8 --- /dev/null +++ b/tests/stdlib/tgetprotobyname.nim @@ -0,0 +1,25 @@ +discard """ + cmd: "nim c -r --styleCheck:hint --panics:on $options $file" + targets: "c" + nimout: "" + action: "run" + exitcode: 0 + timeout: 60.0 +""" + +import nativesockets + + +doAssert getProtoByName("ip") == 0 +doAssert getProtoByName("ipv6") == 41 +doAssert getProtoByName("tcp") == 6 +doAssert getProtoByName("udp") == 17 +doAssert getProtoByName("icmp") == 1 +doAssert getProtoByName("ipv6-icmp") == 58 + +when defined(windows): + doAssertRaises(OSError): + discard getProtoByName("raw") + +doAssertRaises(OSError): + discard getProtoByName("Error") From 8a2cd7b24bbf493ffb90204ec2892ddf7e2e8316 Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 9 Sep 2020 12:59:14 +0200 Subject: [PATCH 1071/4254] [ci skip] fix typo in the manual --- doc/manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index fc4c11f50..e72554603 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5469,8 +5469,8 @@ powerful programming construct that still suffices. So the "check list" is: (4) Else: Use a macro. -For loop macros ---------------- +For loop macro +-------------- A macro that takes as its only input parameter an expression of the special type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: From ccd77b42af11e53631bee7bd74e16d39538541c9 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Wed, 9 Sep 2020 15:18:59 +0300 Subject: [PATCH 1072/4254] Add some enhancements to `jsonutils.nim` (#15133) * Add some enhancements to `jsonutils.nim` * Use `jsonutils.nim` hookable API to add a possibility to deserialize JSON arrays directly to `HashSet` and `OrderedSet` types and respectively to serialize those types to JSON arrays. * Also add a possibility to deserialize JSON `null` objects to Nim option objects and respectively to serialize Nim option object to JSON object if some or to JSON `null` object if none. * Move serialization/deserialization functionality for `Table` and `OrderedTable` types from `jsonutils.nim` to `tables.nim` via the hookable API. * Add object `jsonutils.Joptions` and parameter from its type to `jsonutils.fromJson` procedure to control whether to allow deserializing JSON objects to Nim objects when the JSON has some extra or missing keys. * Add unit tests for the added functionalities to `tjsonutils.nim`. * improve fromJsonFields * Add changelog entry for the jsonutils enhancements * Add TODO in `jsonutils.nim` * Added an entry to "Future directions" section in `jsonutils.nim` as suggestion for future support of serialization and de-serialization of nested variant objects. * Added currently disabled test case in `tjsonutils.nim` for testing serialization and de-serialization of nested variant objects. * Move JSON hooks to `jsonutils.nim` Move `fromJsonHook` and `toJsonHook` procedures for different types to `jsonutils.nim` module to avoid a dependency of collections modules to the `json.nim` module. The hooks are removed from the following modules: * `tables.nim` * `sets.nim` * `options.nim` * `strtabs.nim` * Add some tests about `StringTableRef` Add tests for `StringTableRef`'s `fromJsonHook` and `toJsonHook` to `tjsonutils.nim`. * Disable a warning in `jsonutils.nim` Mark `fun` template in `jsonutils` module with `{.used.}` pragma in order to disable `[XDeclaredButNotUsed]` hint. The template is actually used by the `initCaseObject` macro in the same module. Co-authored-by: Timothee Cour --- changelog.md | 14 ++ lib/pure/collections/sets.nim | 4 +- lib/pure/collections/tables.nim | 4 - lib/pure/options.nim | 1 - lib/pure/strtabs.nim | 20 +-- lib/std/jsonutils.nim | 282 ++++++++++++++++++++++++++++---- tests/stdlib/tjsonutils.nim | 185 ++++++++++++++++++++- 7 files changed, 449 insertions(+), 61 deletions(-) diff --git a/changelog.md b/changelog.md index 2f7b584a3..3333a837b 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,20 @@ ## Standard library additions and changes +- Added some enhancements to `std/jsonutils` module. + * Added a possibility to deserialize JSON arrays directly to `HashSet` and + `OrderedSet` types and respectively to serialize those types to JSON arrays + via `jsonutils.fromJson` and `jsonutils.toJson` procedures. + * Added a possibility to deserialize JSON `null` objects to Nim option objects + and respectively to serialize Nim option object to JSON object if `isSome` + or to JSON null object if `isNone` via `jsonutils.fromJson` and + `jsonutils.toJson` procedures. + * Added `Joptions` parameter to `jsonutils.fromJson` procedure currently + containing two boolean options `allowExtraKeys` and `allowMissingKeys`. + - If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is + not required to have a field for every JSON key. + - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is + allowed to have fields without corresponding JSON keys. - Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. - Add `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. - Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index b019da2a7..67e407576 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -80,6 +80,8 @@ type ## <#initOrderedSet,int>`_ before calling other procs on it. data: OrderedKeyValuePairSeq[A] counter, first, last: int + SomeSet*[A] = HashSet[A] | OrderedSet[A] + ## Type union representing `HashSet` or `OrderedSet`. const defaultInitialSize* = 64 @@ -907,8 +909,6 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = forAllOrderedPairs: yield (idx, s.data[h].key) - - # ----------------------------------------------------------------------- diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 6d79638c2..dc21c0539 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1750,10 +1750,6 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") - - - - # --------------------------------------------------------------------------- # --------------------------- OrderedTableRef ------------------------------- # --------------------------------------------------------------------------- diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 4efe04d67..076cf3707 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -372,7 +372,6 @@ proc unsafeGet*[T](self: Option[T]): lent T {.inline.}= assert self.isSome result = self.val - when isMainModule: import unittest, sequtils diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 4c2dd1451..864db148f 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -89,6 +89,7 @@ const growthFactor = 2 startSize = 64 +proc mode*(t: StringTableRef): StringTableMode {.inline.} = t.mode iterator pairs*(t: StringTableRef): tuple[key, value: string] = ## Iterates over every `(key, value)` pair in the table `t`. @@ -422,25 +423,6 @@ proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {. add(result, f[i]) inc(i) -since (1,3,5): - proc fromJsonHook*[T](a: var StringTableRef, b: T) = - ## for json.fromJson - mixin jsonTo - var mode = jsonTo(b["mode"], StringTableMode) - a = newStringTable(mode) - let b2 = b["table"] - for k,v in b2: a[k] = jsonTo(v, string) - - proc toJsonHook*[](a: StringTableRef): auto = - ## for json.toJson - mixin newJObject - mixin toJson - result = newJObject() - result["mode"] = toJson($a.mode) - let t = newJObject() - for k,v in a: t[k] = toJson(v) - result["table"] = t - when isMainModule: var x = {"k": "v", "11": "22", "565": "67"}.newStringTable assert x["k"] == "v" diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 22f2a7a89..dd174303a 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -13,25 +13,33 @@ runnableExamples: let j = a.toJson doAssert j.jsonTo(type(a)).toJson == j -import std/[json,tables,strutils] +import std/[json,strutils,tables,sets,strtabs,options] #[ -xxx -use toJsonHook,fromJsonHook for Table|OrderedTable -add Options support also using toJsonHook,fromJsonHook and remove `json=>options` dependency - Future directions: add a way to customize serialization, for eg: -* allowing missing or extra fields in JsonNode * field renaming * allow serializing `enum` and `char` as `string` instead of `int` (enum is more compact/efficient, and robust to enum renamings, but string is more human readable) * handle cyclic references, using a cache of already visited addresses +* implement support for serialization and de-serialization of nested variant + objects. ]# import std/macros +type + Joptions* = object + ## Options controlling the behavior of `fromJson`. + allowExtraKeys*: bool + ## If `true` Nim's object to which the JSON is parsed is not required to + ## have a field for every JSON key. + allowMissingKeys*: bool + ## If `true` Nim's object to which JSON is parsed is allowed to have + ## fields without corresponding JSON keys. + # in future work: a key rename could be added + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} template distinctBase[T](a: T): untyped = distinctBase(type(a))(a) @@ -58,11 +66,11 @@ macro getDiscriminants(a: typedesc): seq[string] = result = quote do: seq[string].default -macro initCaseObject(a: typedesc, fun: untyped): untyped = +macro initCaseObject(T: typedesc, fun: untyped): untyped = ## does the minimum to construct a valid case object, only initializing ## the discriminant fields; see also `getDiscriminants` # maybe candidate for std/typetraits - var a = a.getTypeImpl + var a = T.getTypeImpl doAssert a.kind == nnkBracketExpr let sym = a[1] let t = sym.getTypeImpl @@ -92,20 +100,81 @@ proc checkJsonImpl(cond: bool, condStr: string, msg = "") = template checkJson(cond: untyped, msg = "") = checkJsonImpl(cond, astToStr(cond), msg) -template fromJsonFields(a, b, T, keys) = - checkJson b.kind == JObject, $(b.kind) # we could customize whether to allow JNull - var num = 0 - for key, val in fieldPairs(a): - num.inc - when key notin keys: - if b.hasKey key: - fromJson(val, b[key]) - else: - # we could customize to allow this - checkJson false, $($T, key, b) - checkJson b.len == num, $(b.len, num, $T, b) # could customize +proc hasField[T](obj: T, field: string): bool = + for k, _ in fieldPairs(obj): + if k == field: + return true + return false -proc fromJson*[T](a: var T, b: JsonNode) = +macro accessField(obj: typed, name: static string): untyped = + newDotExpr(obj, ident(name)) + +template fromJsonFields(newObj, oldObj, json, discKeys, opt) = + type T = typeof(newObj) + # we could customize whether to allow JNull + checkJson json.kind == JObject, $json.kind + var num, numMatched = 0 + for key, val in fieldPairs(newObj): + num.inc + when key notin discKeys: + if json.hasKey key: + numMatched.inc + fromJson(val, json[key]) + elif opt.allowMissingKeys: + # if there are no discriminant keys the `oldObj` must always have the + # same keys as the new one. Otherwise we must check, because they could + # be set to different branches. + when typeof(oldObj) isnot typeof(nil): + if discKeys.len == 0 or hasField(oldObj, key): + val = accessField(oldObj, key) + else: + checkJson false, $($T, key, json) + else: + if json.hasKey key: + numMatched.inc + + let ok = + if opt.allowExtraKeys and opt.allowMissingKeys: + true + elif opt.allowExtraKeys: + # This check is redundant because if here missing keys are not allowed, + # and if `num != numMatched` it will fail in the loop above but it is left + # for clarity. + assert num == numMatched + num == numMatched + elif opt.allowMissingKeys: + json.len == numMatched + else: + json.len == num and num == numMatched + + checkJson ok, $(json.len, num, numMatched, $T, json) + +proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) + +proc discKeyMatch[T](obj: T, json: JsonNode, key: static string): bool = + if not json.hasKey key: + return true + let field = accessField(obj, key) + var jsonVal: typeof(field) + fromJson(jsonVal, json[key]) + if jsonVal != field: + return false + return true + +macro discKeysMatchBodyGen(obj: typed, json: JsonNode, + keys: static seq[string]): untyped = + result = newStmtList() + let r = ident("result") + for key in keys: + let keyLit = newLit key + result.add quote do: + `r` = `r` and discKeyMatch(`obj`, `json`, `keyLit`) + +proc discKeysMatch[T](obj: T, json: JsonNode, keys: static seq[string]): bool = + result = true + discKeysMatchBodyGen(obj, json, keys) + +proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = ## inplace version of `jsonTo` #[ adding "json path" leading to `b` can be added in future work. @@ -113,10 +182,6 @@ proc fromJson*[T](a: var T, b: JsonNode) = checkJson b != nil, $($T, b) when compiles(fromJsonHook(a, b)): fromJsonHook(a, b) elif T is bool: a = to(b,T) - elif T is Table | OrderedTable: - a.clear - for k,v in b: - a[k] = jsonTo(v, typeof(a[k])) elif T is enum: case b.kind of JInt: a = T(b.getBiggestInt()) @@ -148,14 +213,26 @@ proc fromJson*[T](a: var T, b: JsonNode) = for i, val in b.getElems: fromJson(a[i], val) elif T is object: - template fun(key, typ): untyped = - jsonTo(b[key], typ) - a = initCaseObject(T, fun) + template fun(key, typ): untyped {.used.} = + if b.hasKey key: + jsonTo(b[key], typ) + elif hasField(a, key): + accessField(a, key) + else: + default(typ) const keys = getDiscriminants(T) - fromJsonFields(a, b, T, keys) + when keys.len == 0: + fromJsonFields(a, nil, b, keys, opt) + else: + if discKeysMatch(a, b, keys): + fromJsonFields(a, nil, b, keys, opt) + else: + var newObj = initCaseObject(T, fun) + fromJsonFields(newObj, a, b, keys, opt) + a = newObj elif T is tuple: when isNamedTuple(T): - fromJsonFields(a, b, T, seq[string].default) + fromJsonFields(a, nil, b, seq[string].default, opt) else: checkJson b.kind == JArray, $(b.kind) # we could customize whether to allow JNull var i = 0 @@ -175,9 +252,6 @@ proc toJson*[T](a: T): JsonNode = ## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to ## customize serialization, see strtabs.toJsonHook for an example. when compiles(toJsonHook(a)): result = toJsonHook(a) - elif T is Table | OrderedTable: - result = newJObject() - for k, v in pairs(a): result[k] = toJson(v) elif T is object | tuple: when T is object or isNamedTuple(T): result = newJObject() @@ -198,3 +272,145 @@ proc toJson*[T](a: T): JsonNode = elif T is bool: result = %(a) elif T is Ordinal: result = %(a.ord) else: result = %a + +proc fromJsonHook*[K, V](t: var (Table[K, V] | OrderedTable[K, V]), + jsonNode: JsonNode) = + ## Enables `fromJson` for `Table` and `OrderedTable` types. + ## + ## See also: + ## * `toJsonHook proc<#toJsonHook,(Table[K,V]|OrderedTable[K,V])>`_ + runnableExamples: + import tables, json + var foo: tuple[t: Table[string, int], ot: OrderedTable[string, int]] + fromJson(foo, parseJson(""" + {"t":{"two":2,"one":1},"ot":{"one":1,"three":3}}""")) + assert foo.t == [("one", 1), ("two", 2)].toTable + assert foo.ot == [("one", 1), ("three", 3)].toOrderedTable + + assert jsonNode.kind == JObject, + "The kind of the `jsonNode` must be `JObject`, but its actual " & + "type is `" & $jsonNode.kind & "`." + clear(t) + for k, v in jsonNode: + t[k] = jsonTo(v, V) + +proc toJsonHook*[K, V](t: (Table[K, V] | OrderedTable[K, V])): JsonNode = + ## Enables `toJson` for `Table` and `OrderedTable` types. + ## + ## See also: + ## * `fromJsonHook proc<#fromJsonHook,(Table[K,V]|OrderedTable[K,V]),JsonNode>`_ + runnableExamples: + import tables, json + let foo = ( + t: [("two", 2)].toTable, + ot: [("one", 1), ("three", 3)].toOrderedTable) + assert $toJson(foo) == """{"t":{"two":2},"ot":{"one":1,"three":3}}""" + + result = newJObject() + for k, v in pairs(t): + result[k] = toJson(v) + +proc fromJsonHook*[A](s: var SomeSet[A], jsonNode: JsonNode) = + ## Enables `fromJson` for `HashSet` and `OrderedSet` types. + ## + ## See also: + ## * `toJsonHook proc<#toJsonHook,SomeSet[A]>`_ + runnableExamples: + import sets, json + var foo: tuple[hs: HashSet[string], os: OrderedSet[string]] + fromJson(foo, parseJson(""" + {"hs": ["hash", "set"], "os": ["ordered", "set"]}""")) + assert foo.hs == ["hash", "set"].toHashSet + assert foo.os == ["ordered", "set"].toOrderedSet + + assert jsonNode.kind == JArray, + "The kind of the `jsonNode` must be `JArray`, but its actual " & + "type is `" & $jsonNode.kind & "`." + clear(s) + for v in jsonNode: + incl(s, jsonTo(v, A)) + +proc toJsonHook*[A](s: SomeSet[A]): JsonNode = + ## Enables `toJson` for `HashSet` and `OrderedSet` types. + ## + ## See also: + ## * `fromJsonHook proc<#fromJsonHook,SomeSet[A],JsonNode>`_ + runnableExamples: + import sets, json + let foo = (hs: ["hash"].toHashSet, os: ["ordered", "set"].toOrderedSet) + assert $toJson(foo) == """{"hs":["hash"],"os":["ordered","set"]}""" + + result = newJArray() + for k in s: + add(result, toJson(k)) + +proc fromJsonHook*[T](self: var Option[T], jsonNode: JsonNode) = + ## Enables `fromJson` for `Option` types. + ## + ## See also: + ## * `toJsonHook proc<#toJsonHook,Option[T]>`_ + runnableExamples: + import options, json + var opt: Option[string] + fromJsonHook(opt, parseJson("\"test\"")) + assert get(opt) == "test" + fromJson(opt, parseJson("null")) + assert isNone(opt) + + if jsonNode.kind != JNull: + self = some(jsonTo(jsonNode, T)) + else: + self = none[T]() + +proc toJsonHook*[T](self: Option[T]): JsonNode = + ## Enables `toJson` for `Option` types. + ## + ## See also: + ## * `fromJsonHook proc<#fromJsonHook,Option[T],JsonNode>`_ + runnableExamples: + import options, json + let optSome = some("test") + assert $toJson(optSome) == "\"test\"" + let optNone = none[string]() + assert $toJson(optNone) == "null" + + if isSome(self): + toJson(get(self)) + else: + newJNull() + +proc fromJsonHook*(a: var StringTableRef, b: JsonNode) = + ## Enables `fromJson` for `StringTableRef` type. + ## + ## See also: + ## * `toJsonHook` proc<#toJsonHook,StringTableRef>`_ + runnableExamples: + import strtabs, json + var t = newStringTable(modeCaseSensitive) + let jsonStr = """{"mode": 0, "table": {"name": "John", "surname": "Doe"}}""" + fromJsonHook(t, parseJson(jsonStr)) + assert t[] == newStringTable("name", "John", "surname", "Doe", + modeCaseSensitive)[] + + var mode = jsonTo(b["mode"], StringTableMode) + a = newStringTable(mode) + let b2 = b["table"] + for k,v in b2: a[k] = jsonTo(v, string) + +proc toJsonHook*(a: StringTableRef): JsonNode = + ## Enables `toJson` for `StringTableRef` type. + ## + ## See also: + ## * `fromJsonHook` proc<#fromJsonHook,StringTableRef,JsonNode>`_ + runnableExamples: + import strtabs, json + let t = newStringTable("name", "John", "surname", "Doe", modeCaseSensitive) + let jsonStr = """{"mode": "modeCaseSensitive", + "table": {"name": "John", "surname": "Doe"}}""" + assert toJson(t) == parseJson(jsonStr) + + result = newJObject() + result["mode"] = toJson($a.mode) + let t = newJObject() + for k,v in a: t[k] = toJson(v) + result["table"] = t diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 0b2ec7179..fefd412e7 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -13,8 +13,7 @@ proc testRoundtrip[T](t: T, expected: string) = t2.fromJson(j) doAssert t2.toJson == j -import tables -import strtabs +import tables, sets, algorithm, sequtils, options, strtabs type Foo = ref object id: int @@ -119,5 +118,187 @@ template fn() = testRoundtrip(Foo[int](t1: false, z2: 7)): """{"t1":false,"z2":7}""" # pending https://github.com/nim-lang/Nim/issues/14698, test with `type Foo[T] = ref object` + block testHashSet: + testRoundtrip(HashSet[string]()): "[]" + testRoundtrip([""].toHashSet): """[""]""" + testRoundtrip(["one"].toHashSet): """["one"]""" + + var s: HashSet[string] + fromJson(s, parseJson("""["one","two"]""")) + doAssert s == ["one", "two"].toHashSet + + let jsonNode = toJson(s) + doAssert jsonNode.elems.mapIt(it.str).sorted == @["one", "two"] + + block testOrderedSet: + testRoundtrip(["one", "two", "three"].toOrderedSet): + """["one","two","three"]""" + + block testOption: + testRoundtrip(some("test")): "\"test\"" + testRoundtrip(none[string]()): "null" + testRoundtrip(some(42)): "42" + testRoundtrip(none[int]()): "null" + + block testStrtabs: + testRoundtrip(newStringTable(modeStyleInsensitive)): + """{"mode":"modeStyleInsensitive","table":{}}""" + + testRoundtrip( + newStringTable("name", "John", "surname", "Doe", modeCaseSensitive)): + """{"mode":"modeCaseSensitive","table":{"name":"John","surname":"Doe"}}""" + + block testJoptions: + type + AboutLifeUniverseAndEverythingElse = object + question: string + answer: int + + block testExceptionOnExtraKeys: + var guide: AboutLifeUniverseAndEverythingElse + let json = parseJson( + """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""") + doAssertRaises ValueError, fromJson(guide, json) + doAssertRaises ValueError, + fromJson(guide, json, Joptions(allowMissingKeys: true)) + + type + A = object + a1,a2,a3: int + var a: A + let j = parseJson("""{"a3": 1, "a4": 2}""") + doAssertRaises ValueError, + fromJson(a, j, Joptions(allowMissingKeys: true)) + + block testExceptionOnMissingKeys: + var guide: AboutLifeUniverseAndEverythingElse + let json = parseJson("""{"answer":42}""") + doAssertRaises ValueError, fromJson(guide, json) + doAssertRaises ValueError, + fromJson(guide, json, Joptions(allowExtraKeys: true)) + + block testAllowExtraKeys: + var guide: AboutLifeUniverseAndEverythingElse + let json = parseJson( + """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""") + fromJson(guide, json, Joptions(allowExtraKeys: true)) + doAssert guide == AboutLifeUniverseAndEverythingElse( + question: "6*9=?", answer: 42) + + block testAllowMissingKeys: + var guide = AboutLifeUniverseAndEverythingElse( + question: "6*9=?", answer: 54) + let json = parseJson("""{"answer":42}""") + fromJson(guide, json, Joptions(allowMissingKeys: true)) + doAssert guide == AboutLifeUniverseAndEverythingElse( + question: "6*9=?", answer: 42) + + block testAllowExtraAndMissingKeys: + var guide = AboutLifeUniverseAndEverythingElse( + question: "6*9=?", answer: 54) + let json = parseJson( + """{"answer":42,"author":"Douglas Adams"}""") + fromJson(guide, json, Joptions( + allowExtraKeys: true, allowMissingKeys: true)) + doAssert guide == AboutLifeUniverseAndEverythingElse( + question: "6*9=?", answer: 42) + + type + Foo = object + a: array[2, string] + case b: bool + of false: f: float + of true: t: tuple[i: int, s: string] + case c: range[0 .. 2] + of 0: c0: int + of 1: c1: float + of 2: c2: string + + block testExceptionOnMissingDiscriminantKey: + var foo: Foo + let json = parseJson("""{"a":["one","two"]}""") + doAssertRaises ValueError, fromJson(foo, json) + + block testDoNotResetMissingFieldsWhenHaveDiscriminantKey: + var foo = Foo(a: ["one", "two"], b: true, t: (i: 42, s: "s"), + c: 0, c0: 1) + let json = parseJson("""{"b":true,"c":2}""") + fromJson(foo, json, Joptions(allowMissingKeys: true)) + doAssert foo.a == ["one", "two"] + doAssert foo.b + doAssert foo.t == (i: 42, s: "s") + doAssert foo.c == 2 + doAssert foo.c2 == "" + + block testAllowMissingDiscriminantKeys: + var foo: Foo + let json = parseJson("""{"a":["one","two"],"c":1,"c1":3.14159}""") + fromJson(foo, json, Joptions(allowMissingKeys: true)) + doAssert foo.a == ["one", "two"] + doAssert not foo.b + doAssert foo.f == 0.0 + doAssert foo.c == 1 + doAssert foo.c1 == 3.14159 + + block testExceptionOnWrongDiscirminatBranchInJson: + var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42) + let json = parseJson("""{"c2": "hello"}""") + doAssertRaises ValueError, + fromJson(foo, json, Joptions(allowMissingKeys: true)) + # Test that the original fields are not reset. + doAssert not foo.b + doAssert foo.f == 3.14159 + doAssert foo.c == 0 + doAssert foo.c0 == 42 + + block testNoExceptionOnRightDiscriminantBranchInJson: + var foo = Foo(b: false, f: 0, c:1, c1: 0) + let json = parseJson("""{"f":2.71828,"c1": 3.14159}""") + fromJson(foo, json, Joptions(allowMissingKeys: true)) + doAssert not foo.b + doAssert foo.f == 2.71828 + doAssert foo.c == 1 + doAssert foo.c1 == 3.14159 + + block testAllowExtraKeysInJsonOnWrongDisciriminatBranch: + var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42) + let json = parseJson("""{"c2": "hello"}""") + fromJson(foo, json, Joptions(allowMissingKeys: true, + allowExtraKeys: true)) + # Test that the original fields are not reset. + doAssert not foo.b + doAssert foo.f == 3.14159 + doAssert foo.c == 0 + doAssert foo.c0 == 42 + + when false: + ## TODO: Implement support for nested variant objects allowing the tests + ## bellow to pass. + block testNestedVariantObjects: + type + Variant = object + case b: bool + of false: + case bf: bool + of false: bff: int + of true: bft: float + of true: + case bt: bool + of false: btf: string + of true: btt: char + + testRoundtrip(Variant(b: false, bf: false, bff: 42)): + """{"b": false, "bf": false, "bff": 42}""" + testRoundtrip(Variant(b: false, bf: true, bft: 3.14159)): + """{"b": false, "bf": true, "bft": 3.14159}""" + testRoundtrip(Variant(b: true, bt: false, btf: "test")): + """{"b": true, "bt": false, "btf": "test"}""" + testRoundtrip(Variant(b: true, bt: true, btt: 'c')): + """{"b": true, "bt": true, "btt": "c"}""" + + # TODO: Add additional tests with missing and extra JSON keys, both when + # allowed and forbidden analogous to the tests for the not nested + # variant objects. + static: fn() fn() From 217675cf84dc47bb68f03b341aff14315804efec Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 9 Sep 2020 14:19:22 +0200 Subject: [PATCH 1073/4254] borrow checking refinements (#15290) * added basic borrowing test --- compiler/typeallowed.nim | 6 +++--- compiler/varpartitions.nim | 20 ++++++++++++++++++-- tests/effects/tcannot_borrow.nim | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 tests/effects/tcannot_borrow.nim diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 5a192783e..651a21ade 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -57,7 +57,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, of tyVar, tyLent: if kind in {skProc, skFunc, skConst} and (views notin c.features): result = t - elif t.kind == tyLent and kind != skResult: + elif t.kind == tyLent and kind != skResult and (views notin c.features): result = t else: var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc}) @@ -68,10 +68,10 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if (kind != skParam and views notin c.features) or taIsOpenArray in flags: result = t else: result = typeAllowedAux(marker, t2[0], kind, c, flags+{taIsOpenArray}) of tyUncheckedArray: - if kind != skParam: result = t + if kind != skParam and views notin c.features: result = t else: result = typeAllowedAux(marker, t2[0], kind, c, flags) else: - if kind notin {skParam, skResult}: result = t + if kind notin {skParam, skResult} and views notin c.features: result = t else: result = typeAllowedAux(marker, t2, kind, c, flags) of tyProc: if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 756249c8b..bbde68cbe 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -375,7 +375,7 @@ proc deps(c: var Partitions; dest, src: PNode) = allRoots(src, sources) proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} - let destIsComplex = types.searchTypeFor(dest.typ, wrap) + let destIsComplex = types.searchTypeFor(dest.typ, wrap) or isViewType(dest.typ) for t in targets: if dest.kind != nkSym and c.inNoSideEffectSection == 0: @@ -518,19 +518,35 @@ proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partit traverse(result, n) proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = + #echo "range ", v.aliveStart, " .. ", v.aliveEnd if isMutated in g.flags: for m in g.mutations: + #echo "mutation ", m if m in v.aliveStart..v.aliveEnd: return true return false +proc cannotBorrow(config: ConfigRef; s: PSym; g: MutationInfo) = + var m = "cannot borrow " & s.name.s & + "; what it borrows from is potentially mutated" + + if g.mutatedHere != unknownLineInfo: + m.add "\n" + m.add config $ g.mutatedHere + m.add " the mutation is here" + if g.connectedVia != unknownLineInfo: + m.add "\n" + m.add config $ g.connectedVia + m.add " is the statement that connected the mutation to the parameter" + localError(config, s.info, m) + proc checkBorrowedLocations*(par: var Partitions; config: ConfigRef) = for i in 0 ..< par.s.len: let s = par.s[i].sym if s.kind != skParam and isViewType(s.typ): let rid = root(par, i) if par.s[rid].kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].graphIndex], par.s[i]): - localError(config, s.info, config $ par.graphs[par.s[rid].graphIndex]) + cannotBorrow(config, s, par.graphs[par.s[rid].graphIndex]) proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = var par = computeGraphPartitions(s, n, true) diff --git a/tests/effects/tcannot_borrow.nim b/tests/effects/tcannot_borrow.nim new file mode 100644 index 000000000..699176b04 --- /dev/null +++ b/tests/effects/tcannot_borrow.nim @@ -0,0 +1,18 @@ +discard """ + errormsg: "cannot borrow" + nimout: '''tcannot_borrow.nim(16, 7) Error: cannot borrow meh; what it borrows from is potentially mutated +tcannot_borrow.nim(17, 3) the mutation is here +tcannot_borrow.nim(16, 7) is the statement that connected the mutation to the parameter''' + line: 16 +""" + +{.experimental: "views".} + +type + Foo = object + field: string + +proc dangerous(s: var seq[Foo]) = + let meh: lent Foo = s[0] + s.setLen 0 + echo meh.field From 3f00a738dbc8319b4dd2b86bf5529c096f2dd243 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 9 Sep 2020 14:20:10 +0200 Subject: [PATCH 1074/4254] fixes #15280 [backport:1.2] (#15281) * fixes #15280 [backport:1.2] * make tests green again * adapt tests --- compiler/sem.nim | 2 +- tests/arc/tmovebug.nim | 6 +-- tests/casestmt/tcasestmt.nim | 2 +- tests/semreject/tmixing_return_and_exprs.nim | 44 ++++++++++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 tests/semreject/tmixing_return_and_exprs.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index 705e1b72c..bc6119460 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -184,7 +184,7 @@ proc endsInNoReturn(n: PNode): bool = var it = n while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: it = it.lastSon - result = it.kind in nkLastBlockStmts or + result = it.kind in (nkLastBlockStmts-{nkReturnStmt}) or it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags proc commonType*(x: PType, y: PNode): PType = diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 3b7a7c5df..c735ea1eb 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -502,7 +502,7 @@ weirdScopes() # bug #14985 proc getScope(): string = if true: - return "hi" + "hi" else: "else" @@ -512,14 +512,14 @@ proc getScope3(): string = try: "try" except: - return "except" + "except" echo getScope3() proc getScope2(): string = case true of true: - return "bye" + "bye" else: "else" diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 53cccdb64..2151892aa 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -258,7 +258,7 @@ func foo(input: string): int = try: parseInt(input) except: - return + 0 func foo2(b, input: string): int = case b: diff --git a/tests/semreject/tmixing_return_and_exprs.nim b/tests/semreject/tmixing_return_and_exprs.nim new file mode 100644 index 000000000..2848c47e4 --- /dev/null +++ b/tests/semreject/tmixing_return_and_exprs.nim @@ -0,0 +1,44 @@ +discard """ + errormsg: "expression 'len(src) shl 1' is of type 'int' and has to be used (or discarded)" + line: 19 +""" + +# bug #15280 + +type + HexFlags* {.pure.} = enum + LowerCase, ## Produce lowercase hexadecimal characters + PadOdd, ## Pads odd strings + SkipSpaces, ## Skips all the whitespace characters inside of string + SkipPrefix ## Skips `0x` and `x` prefixes at the begining of string + + +proc bytesToHex*(src: openarray[byte], dst: var openarray[char], + flags: set[HexFlags]): int = + if len(dst) == 0: + (len(src) shl 1) + else: + var halflast = false + let dstlen = len(dst) + var srclen = len(src) + + if dstlen < (srclen shl 1): + if (dstlen and 1) == 1: + srclen = (dstlen - 1) shr 1 + halflast = true + else: + srclen = (dstlen shr 1) + + let lowercase = (HexFlags.LowerCase in flags) + + var k = 0 + for i in 0 ..< srclen: + let x = int(src[i]) + inc(k, 2) + + if halflast: + let x = int(src[srclen]) + inc(k) + + return k + From 61c85e034de571cb25020b6dddf662c82896907a Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 10 Sep 2020 11:40:39 +0100 Subject: [PATCH 1075/4254] Fix #15286 (#15292) * fix #15286 * fix spacing --- compiler/injectdestructors.nim | 3 +++ tests/arc/t14383.nim | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 4fe4cb1da..b8b8e776e 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -728,6 +728,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = for i in ord(n.kind in {nkObjConstr, nkClosure}).. Date: Thu, 10 Sep 2020 16:30:20 +0200 Subject: [PATCH 1076/4254] testament improvement: allow inline error messages inside test cases (#15294) * testament support for inline error messages * adapt teffects1.nim test to show the potential --- testament/specs.nim | 95 +++++++++++++++++++++++++++++++++---- testament/testament.nim | 49 ++++++++++++++++++- tests/effects/teffects1.nim | 19 ++++---- 3 files changed, 142 insertions(+), 21 deletions(-) diff --git a/testament/specs.nim b/testament/specs.nim index acffbf8be..e0b9cbeec 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -import sequtils, parseutils, strutils, os, streams, parsecfg -from hashes import hash +import sequtils, parseutils, strutils, os, streams, parsecfg, + tables, hashes type TestamentData* = ref object # better to group globals under 1 object; could group the other ones here too @@ -62,6 +62,11 @@ type targetObjC = "ObjC" targetJS = "JS" + InlineError* = object + kind*: string + msg*: string + line*, col*: int + TSpec* = object action*: TTestAction file*, cmd*: string @@ -90,6 +95,7 @@ type useValgrind*: bool timeout*: float # in seconds, fractions possible, # but don't rely on much precision + inlineErrors*: seq[InlineError] # line information to error message proc getCmd*(s: TSpec): string = if s.cmd.len == 0: @@ -116,14 +122,85 @@ when not declared(parseCfgBool): of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) -proc extractSpec(filename: string): string = - const tripleQuote = "\"\"\"" - var x = readFile(filename).string - var a = x.find(tripleQuote) - var b = x.find(tripleQuote, a+3) +const + inlineErrorMarker = "#[tt." + +proc extractErrorMsg(s: string; i: int; line: var int; col: var int; spec: var TSpec): int = + result = i + len(inlineErrorMarker) + inc col, len(inlineErrorMarker) + var kind = "" + while result < s.len and s[result] in IdentChars: + kind.add s[result] + inc result + inc col + + var caret = (line, -1) + + template skipWhitespace = + while result < s.len and s[result] in Whitespace: + if s[result] == '\n': + col = 1 + inc line + else: + inc col + inc result + + skipWhitespace() + if result < s.len and s[result] == '^': + caret = (line-1, col) + inc result + inc col + skipWhitespace() + + var msg = "" + while result < s.len-1: + if s[result] == '\n': + inc result + inc line + col = 1 + elif s[result] == ']' and s[result+1] == '#': + while msg.len > 0 and msg[^1] in Whitespace: + setLen msg, msg.len - 1 + + inc result + inc col, 2 + if kind == "Error": spec.action = actionReject + spec.unjoinable = true + spec.inlineErrors.add InlineError(kind: kind, msg: msg, line: caret[0], col: caret[1]) + break + else: + msg.add s[result] + inc result + inc col + +proc extractSpec(filename: string; spec: var TSpec): string = + const + tripleQuote = "\"\"\"" + var s = readFile(filename).string + + var i = 0 + var a = -1 + var b = -1 + var line = 1 + var col = 1 + while i < s.len: + if s.continuesWith(tripleQuote, i): + if a < 0: a = i + elif b < 0: b = i + inc i, 2 + inc col + elif s[i] == '\n': + inc line + col = 1 + elif s.continuesWith(inlineErrorMarker, i): + i = extractErrorMsg(s, i, line, col, spec) + else: + inc col + inc i + # look for """ only in the first section if a >= 0 and b > a and a < 40: - result = x.substr(a+3, b-1).replace("'''", tripleQuote) + result = s.substr(a+3, b-1).replace("'''", tripleQuote) else: #echo "warning: file does not contain spec: " & filename result = "" @@ -160,7 +237,7 @@ proc isCurrentBatch(testamentData: TestamentData, filename: string): bool = proc parseSpec*(filename: string): TSpec = result.file = filename - let specStr = extractSpec(filename) + let specStr = extractSpec(filename, result) var ss = newStringStream(specStr) var p: CfgParser open(p, ss, filename, 1) diff --git a/testament/testament.nim b/testament/testament.nim index baa340139..4afafb645 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -12,7 +12,7 @@ import strutils, pegs, os, osproc, streams, json, backend, parseopt, specs, htmlgen, browsers, terminal, - algorithm, times, md5, sequtils, azure + algorithm, times, md5, sequtils, azure, intsets from std/sugar import dup import compiler/nodejs @@ -71,6 +71,7 @@ type let pegLineError = peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}" + pegLineTemplate = peg""" {[^(]*} '(' {\d+} ', ' {\d+} ') ' @@ -317,8 +318,50 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, discard waitForExit(p) close(p) +proc checkForInlineErrors(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = + let pegLine = peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' {[^:]*} ':' \s* {.*}" + var covered = initIntSet() + for line in splitLines(given.nimout): + + if line =~ pegLine: + let file = extractFilename(matches[0]) + let line = try: parseInt(matches[1]) except: -1 + let col = try: parseInt(matches[2]) except: -1 + let kind = matches[3] + let msg = matches[4] + + if file == extractFilename test.name: + var i = 0 + for x in expected.inlineErrors: + if x.line == line and (x.col == col or x.col < 0) and + x.kind == kind and x.msg in msg: + covered.incl i + inc i + + block coverCheck: + for j in 0..high(expected.inlineErrors): + if j notin covered: + var e = test.name + e.add "(" + e.addInt expected.inlineErrors[j].line + if expected.inlineErrors[j].col > 0: + e.add ", " + e.addInt expected.inlineErrors[j].col + e.add ") " + e.add expected.inlineErrors[j].kind + e.add ": " + e.add expected.inlineErrors[j].msg + + r.addResult(test, target, e, given.nimout, reMsgsDiffer) + break coverCheck + + r.addResult(test, target, "", given.msg, reSuccess) + inc(r.passed) + proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = - if strip(expected.msg) notin strip(given.msg): + if expected.inlineErrors.len > 0: + checkForInlineErrors(r, expected, given, test, target) + elif strip(expected.msg) notin strip(given.msg): r.addResult(test, target, expected.msg, given.msg, reMsgsDiffer) elif expected.nimout.len > 0 and expected.nimout.normalizeMsg notin given.nimout.normalizeMsg: r.addResult(test, target, expected.nimout, given.nimout, reMsgsDiffer) @@ -389,6 +432,8 @@ proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) = given.err = reMsgsDiffer break + + proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, expected: TSpec; r: var TResults) = var expectedmsg: string = "" diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 3bd19f4ab..3551ff1a1 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -1,13 +1,5 @@ discard """ - errormsg: "type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}'" - file: "teffects1.nim" - line: 38 cmd: "nim check $file" - nimout: '''teffects1.nim(22, 28) template/generic instantiation from here -teffects1.nim(23, 13) Error: can raise an unlisted exception: ref IOError -teffects1.nim(22, 29) Hint: 'IO2Error' is declared but not used [XDeclaredButNotUsed] -teffects1.nim(38, 21) Error: type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' -.raise effects differ''' """ type @@ -20,7 +12,10 @@ type proc forw: int {. .} proc lier(): int {.raises: [IO2Error].} = - writeLine stdout, "arg" + #[tt.Hint ^ 'IO2Error' is declared but not used [XDeclaredButNotUsed] ]# + writeLine stdout, "arg" #[tt.Error + ^ can raise an unlisted exception: ref IOError + ]# proc forw: int = raise newException(IOError, "arg") @@ -35,5 +30,9 @@ proc foo(x: int): string {.raises: [ValueError].} = raise newException(ValueError, "Use single digit") $x -var p: MyProcType = foo +var p: MyProcType = foo #[tt.Error + ^ +type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' + +]# {.pop.} From b03d221d0b98cc338cb0809e9906e840551fa765 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 10 Sep 2020 19:25:09 -0300 Subject: [PATCH 1077/4254] Improve prelude so it does not hijacks documentation when used (#15299) --- lib/prelude.nim | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/prelude.nim b/lib/prelude.nim index 940864207..5ad561158 100644 --- a/lib/prelude.nim +++ b/lib/prelude.nim @@ -7,17 +7,15 @@ # distribution, for details about the copyright. # -## This is an include file that simply imports common modules for your -## convenience: -## -## .. code-block:: nim -## include prelude -## -## Same as: -## -## .. code-block:: nim -## import os, strutils, times, parseutils, parseopt, hashes, tables, sets +# This is an include file that simply imports common modules for your +# convenience: +# +# .. code-block:: nim +# include prelude +# +# Same as: +# +# .. code-block:: nim +# import os, strutils, times, parseutils, parseopt, hashes, tables, sets import os, strutils, times, parseutils, parseopt, hashes, tables, sets - - From 625edf6a98142a4a31c52d694623aa9b7188708d Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Fri, 11 Sep 2020 01:43:10 +0300 Subject: [PATCH 1078/4254] Add /lib/fusion to gitignore (#15295) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cf0bcfbd6..a4577c0d0 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ testament.db /tests/**/*.js /csources /dist/ +/lib/fusion # Private directories and files (IDEs) .*/ From 6a621b35e7c935655d3cafe840eb69d662e333b7 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 11 Sep 2020 01:04:07 +0200 Subject: [PATCH 1079/4254] fix warnings for deprecated `low` and `high` (#15291) --- compiler/ast.nim | 4 ++-- compiler/saturate.nim | 20 ++++++++++---------- compiler/vmgen.nim | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index b1a3a4a7b..8baf49265 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1356,8 +1356,8 @@ proc newType*(kind: TTypeKind, owner: PSym): PType = writeStackTrace() proc mergeLoc(a: var TLoc, b: TLoc) = - if a.k == low(a.k): a.k = b.k - if a.storage == low(a.storage): a.storage = b.storage + if a.k == low(typeof(a.k)): a.k = b.k + if a.storage == low(typeof(a.storage)): a.storage = b.storage a.flags.incl b.flags if a.lode == nil: a.lode = b.lode if a.r == nil: a.r = b.r diff --git a/compiler/saturate.nim b/compiler/saturate.nim index 9e8919514..fe6e03c8b 100644 --- a/compiler/saturate.nim +++ b/compiler/saturate.nim @@ -15,33 +15,33 @@ proc `|+|`*(a, b: BiggestInt): BiggestInt = if (result xor a) >= 0'i64 or (result xor b) >= 0'i64: return result if a < 0 or b < 0: - result = low(result) + result = low(typeof(result)) else: - result = high(result) + result = high(typeof(result)) proc `|-|`*(a, b: BiggestInt): BiggestInt = result = a -% b if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64: return result if b > 0: - result = low(result) + result = low(typeof(result)) else: - result = high(result) + result = high(typeof(result)) proc `|abs|`*(a: BiggestInt): BiggestInt = - if a != low(a): + if a != low(typeof(a)): if a >= 0: result = a else: result = -a else: - result = low(a) + result = low(typeof(a)) proc `|div|`*(a, b: BiggestInt): BiggestInt = # (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4)..(5 div 1) if b == 0'i64: # make the same as ``div 1``: result = a - elif a == low(a) and b == -1'i64: - result = high(result) + elif a == low(typeof(a)) and b == -1'i64: + result = high(typeof(result)) else: result = a div b @@ -74,6 +74,6 @@ proc `|*|`*(a, b: BiggestInt): BiggestInt = return result if floatProd >= 0.0: - result = high(result) + result = high(typeof(result)) else: - result = low(result) + result = low(typeof(result)) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c2a2f6d42..ad5023aeb 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -611,7 +611,7 @@ proc genField(c: PCtx; n: PNode): TRegister = if n.kind != nkSym or n.sym.kind != skField: globalError(c.config, n.info, "no field symbol") let s = n.sym - if s.position > high(result): + if s.position > high(typeof(result)): globalError(c.config, n.info, "too large offset! cannot generate code for: " & s.name.s) result = s.position From 0c41ac792b64b710b4702cd4ae88d4392744a1ea Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 Sep 2020 01:50:42 +0200 Subject: [PATCH 1080/4254] fixes #15122 (#15301) --- compiler/liftdestructors.nim | 17 ++++++++++++-- tests/arc/theavy_recursion.nim | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/arc/theavy_recursion.nim diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index c1fd7981e..b3300850e 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -462,6 +462,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind of attachedAsgn, attachedDeepCopy: + # XXX: replace these with assertions. if t.assignment == nil: return # protect from recursion body.add newHookCall(c, t.assignment, x, y) @@ -827,7 +828,10 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; if typ.kind == tyDistinct: return produceSymDistinctType(g, c, typ, kind, info) - result = symPrototype(g, typ, typ.owner, kind, info) + result = typ.attachedOps[kind] + if result == nil: + result = symPrototype(g, typ, typ.owner, kind, info) + var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType:typ) a.fn = result @@ -947,9 +951,18 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf let lastAttached = if g.config.selectedGC == gcOrc: attachedDispose else: attachedSink + # bug #15122: We need to produce all prototypes before entering the + # mind boggling recursion. Hacks like these imply we shoule rewrite + # this module. + var generics: array[attachedDestructor..attachedDispose, bool] + for k in attachedDestructor..lastAttached: + generics[k] = canon.attachedOps[k] != nil + if not generics[k]: + canon.attachedOps[k] = symPrototype(g, canon, canon.owner, k, info) + # we generate the destructor first so that other operators can depend on it: for k in attachedDestructor..lastAttached: - if canon.attachedOps[k] == nil: + if not generics[k]: discard produceSym(g, c, canon, k, info) else: inst(canon.attachedOps[k], canon) diff --git a/tests/arc/theavy_recursion.nim b/tests/arc/theavy_recursion.nim new file mode 100644 index 000000000..9813331f4 --- /dev/null +++ b/tests/arc/theavy_recursion.nim @@ -0,0 +1,43 @@ +discard """ + output: "yay" + cmd: "nim c --gc:arc $file" +""" + +# bug #15122 + +import tables + +type + BENodeKind* = enum + tkEof, + tkBytes, + tkList, + tkDict + + BENode* = object + case kind: BENodeKind + of tkBytes: strVal: string + of tkList: listVal: seq[BENode] + of tkDict: dictVal*: Table[string, BENode] + else: + discard + +proc unused(s: string): BENode = + # bad: + result = BENode(kind: tkBytes, strVal: "abc") + +proc main = + var data = { + "examples": { + "values": BENode( + kind: tkList, + listVal: @[BENode(kind: tkBytes, strVal: "test")] + ) + }.toTable() + }.toTable() + + # For ARC listVal is empty for some reason + doAssert data["examples"]["values"].listVal[0].strVal == "test" + +main() +echo "yay" From c4e03b540e34a37c24794ade073bf708ab17b35d Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 11 Sep 2020 03:57:57 -0300 Subject: [PATCH 1081/4254] Fix #15183 (#15300) --- lib/js/jsre.nim | 23 +++++++++++++---------- tools/kochdocs.nim | 1 - 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index b4f273d0b..ff80056ea 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -1,5 +1,18 @@ ## Regular Expressions for the JavaScript target. ## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions +## +## Examples +## ======== +## +## .. code-block::nim +## let jsregex: RegExp = newRegExp(r"\s+", r"i") +## jsregex.compile(r"\w+", r"i") +## doAssert jsregex.test(r"nim javascript") +## doAssert jsregex.exec(r"nim javascript") == @["nim".cstring] +## doAssert jsregex.toString() == r"/\w+/i" +## jsregex.compile(r"[0-9]", r"i") +## doAssert jsregex.test(r"0123456789abcd") + when not defined(js) and not defined(Nimdoc): {.error: "This module only works on the JavaScript platform".} @@ -34,13 +47,3 @@ func test*(self: RegExp; pattern: cstring): bool {.importjs: "#.test(#)".} func toString*(self: RegExp): cstring {.importjs: "#.toString()".} ## Returns a string representing the RegExp object. - - -runnableExamples: - let jsregex: RegExp = newRegExp(r"\s+", r"i") - jsregex.compile(r"\w+", r"i") - doAssert jsregex.test(r"nim javascript") - doAssert jsregex.exec(r"nim javascript") == @["nim".cstring] - doAssert jsregex.toString() == r"/\w+/i" - jsregex.compile(r"[0-9]", r"i") - doAssert jsregex.test(r"0123456789abcd") diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 453b1037b..ba2963cfd 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -161,7 +161,6 @@ lib/posix/posix_other_consts.nim lib/posix/posix_freertos_consts.nim lib/posix/posix_openbsd_amd64.nim lib/posix/posix_haiku.nim -lib/js/jsre.nim """.splitWhitespace() when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): From 9e4920c06851307187e9897be91424dc6640f8d3 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 11 Sep 2020 14:21:09 +0200 Subject: [PATCH 1082/4254] fixes #15021 --- lib/pure/collections/tables.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index dc21c0539..8d2680815 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -2298,7 +2298,7 @@ proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] = ## ## See also: ## * `largest proc<#largest,CountTable[A]>`_ - assert t.len > 0 + assert t.len > 0, "counttable is empty" var minIdx = -1 for h in 0 .. high(t.data): if t.data[h].val > 0 and (minIdx == -1 or t.data[minIdx].val > t.data[h].val): @@ -2311,7 +2311,7 @@ proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] = ## ## See also: ## * `smallest proc<#smallest,CountTable[A]>`_ - assert t.len > 0 + assert t.len > 0, "counttable is empty" var maxIdx = 0 for h in 1 .. high(t.data): if t.data[maxIdx].val < t.data[h].val: maxIdx = h From f1f694dccb7ea0c7a6f10793dc05849da01970b7 Mon Sep 17 00:00:00 2001 From: genotrance Date: Fri, 11 Sep 2020 11:57:54 -0500 Subject: [PATCH 1083/4254] Bump nimble (#15304) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index d9bbb4176..90c1296fa 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "311e5a8cd2c53056bdec24c81393a46b41f96241" # master + NimbleStableCommit = "27d1063febe3055252103cacb11787ac83893416" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From 5f08d39398d134607605cb910590aac8babc02ef Mon Sep 17 00:00:00 2001 From: narimiran Date: Sat, 12 Sep 2020 09:22:14 +0200 Subject: [PATCH 1084/4254] fix broken links in the documentation --- lib/system_overview.rst | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/system_overview.rst b/lib/system_overview.rst index f0945873c..9125c29ba 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -45,27 +45,27 @@ Proc Usage Seqs ---- -=========================================== ========================================== -Proc Usage -=========================================== ========================================== -`newSeq<#newSeq>`_ Create a new sequence of a given length -`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length - and a given capacity -`setLen<#setLen,seq[T][T],Natural>`_ Set the length of a sequence -`len<#len,seq[T][T]>`_ Return the length of a sequence -`@<#@,array[IDX,T]>`_ Turn an array into a sequence -`add<#add,seq[T][T],T>`_ Add an item to the sequence -`insert<#insert,seq[T][T],T>`_ Insert an item at a specific position -`delete<#delete,seq[T][T],Natural>`_ Delete an item while preserving the - order of elements (`O(n)` operation) -`del<#del,seq[T][T],Natural>`_ `O(1)` removal, doesn't preserve the order -`pop<#pop,seq[T][T]>`_ Remove and return last item of a sequence -`x & y<#&,seq[T][T],seq[T][T]>`_ Concatenate two sequences -`x[a..b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (both ends included) -`x[a..^b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence but `b` is a - reversed index (both ends included) -`x[a..\`_ Slice of a sequence (excluded upper bound) -=========================================== ========================================== +============================================== ========================================== +Proc Usage +============================================== ========================================== +`newSeq<#newSeq>`_ Create a new sequence of a given length +`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length + and a given capacity +`setLen<#setLen,seq[T],Natural>`_ Set the length of a sequence +`len<#len,seq[T]>`_ Return the length of a sequence +`@<#@>`_ Turn an array into a sequence +`add<#add,seq[T],>`_ Add an item to the sequence +`insert<#insert,seq[T],>`_ Insert an item at a specific position +`delete<#delete,seq[T],Natural>`_ Delete an item while preserving the + order of elements (`O(n)` operation) +`del<#del,seq[T],Natural>`_ `O(1)` removal, doesn't preserve the order +`pop<#pop,seq[T]>`_ Remove and return last item of a sequence +`x & y<#&,seq[T],seq[T]>`_ Concatenate two sequences +`x[a .. b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (both ends included) +`x[a .. ^b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence but `b` is a + reversed index (both ends included) +`x[a ..\< b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (excluded upper bound) +============================================== ========================================== **See also:** * `sequtils module `_ for operations on container From a41b243fea007b9aec8da0e950aa3368777aab37 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 12 Sep 2020 16:34:11 +0800 Subject: [PATCH 1085/4254] remove annoying messages when creating orderedTables (#15309) * nativesockets docs minor [backport: 1.2] * remove annoying messages --- lib/pure/collections/tables.nim | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 8d2680815..c5a7fca56 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1784,7 +1784,7 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] assert b == {'a': 5, 'b': 9}.newOrderedTable result = newOrderedTable[A, B](pairs.len) - for key, val in items(pairs): result.add(key, val) + for key, val in items(pairs): result[key] = val proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = @@ -2967,37 +2967,37 @@ when isMainModule: block: #5482 var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() var b = newOrderedTable[string, string](initialSize = 2) - b.add("wrong?", "foo") - b.add("wrong?", "foo2") + b["wrong?"] = "foo" + b["wrong?"] = "foo2" assert a == b block: #5482 var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() var b = newOrderedTable[string, string](initialSize = 2) - b.add("wrong?", "foo") - b.add("wrong?", "foo2") + b["wrong?"] = "foo" + b["wrong?"] = "foo2" assert a == b block: #5487 var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() var b = newOrderedTable[string, string]() # notice, default size! - b.add("wrong?", "foo") - b.add("wrong?", "foo2") + b["wrong?"] = "foo" + b["wrong?"] = "foo2" assert a == b block: #5487 var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() var b = newOrderedTable[string, string]() # notice, default size! - b.add("wrong?", "foo") - b.add("wrong?", "foo2") + b["wrong?"] = "foo" + b["wrong?"] = "foo2" assert a == b block: var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() var c = newOrderedTable[string, string]() # notice, default size! - c.add("wrong?", "foo") - c.add("wrong?", "foo2") + c["wrong?"] = "foo" + c["wrong?"] = "foo2" assert a == b assert a == c From 1881fc5812aeada551e32c0d81a3aa4f6fceb0bb Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 12 Sep 2020 13:39:46 +0200 Subject: [PATCH 1086/4254] Fix #15305 (#15311) * Fix #15305 * Fix test --- compiler/parser.nim | 3 +-- tests/parser/tifexprs.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/parser/tifexprs.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index f256cee66..17dd092a4 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -2242,8 +2242,7 @@ proc parseStmt(p: var Parser): PNode = break p.hasProgress = false if p.tok.tokType in {tkElse, tkElif}: - parMessage(p, errInvalidIndentation) - getTok(p) + break # Allow this too, see tests/parser/tifexprs result.add complexOrSimpleStmt(p) if not p.hasProgress and p.tok.tokType == tkEof: break diff --git a/tests/parser/tifexprs.nim b/tests/parser/tifexprs.nim new file mode 100644 index 000000000..3a7e2bddc --- /dev/null +++ b/tests/parser/tifexprs.nim @@ -0,0 +1,12 @@ +discard """ + output: ''' +1 +''' +""" + +var a, b: int +let x = if a > b: + 0 + else: 1 + +echo x From 60ad95f79954fa870a124b5afc4ad5239fbebab1 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 12 Sep 2020 14:28:19 +0200 Subject: [PATCH 1087/4254] Add testcase for invalid if statement (#15313) --- tests/parser/tinvifstmt.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/parser/tinvifstmt.nim diff --git a/tests/parser/tinvifstmt.nim b/tests/parser/tinvifstmt.nim new file mode 100644 index 000000000..0455bce60 --- /dev/null +++ b/tests/parser/tinvifstmt.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "invalid indentation" + line: 9 + column: 3 +""" + +if true: + echo "a" + elif: + echo "b" + else: + echo "c" From 1df5cfba52ccc71e3c69b6cd7d08cebd70bbb187 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 Sep 2020 23:11:38 +0200 Subject: [PATCH 1088/4254] fixes #15147 (#15315) --- compiler/varpartitions.nim | 2 +- tests/arc/topt_no_cursor.nim | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index bbde68cbe..87424c4be 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -396,7 +396,7 @@ proc deps(c: var Partitions; dest, src: PNode) = (src.sym.kind in {skLet, skParam, skForVar} and hasDisabledAsgn(src.sym.typ))): c.s[vid].flags.incl preventCursor - if hasDestructor(src.typ): + if src.kind == nkSym and hasDestructor(src.typ): rhsIsSink(c, src) proc traverse(c: var Partitions; n: PNode) = diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index fe63e7585..8a33cb2ee 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -171,3 +171,24 @@ proc encodedQuery = elem.tt() encodedQuery() + +# bug #15147 + +proc s(input: string): (string, string) = + result = (";", "") + +proc charmatch(input: string): (string, string) = + result = ("123", input[0 .. input.high]) + +proc plus(input: string) = + var + lvalue, rvalue: string # cursors + lnext: string # must be cursor!!! + rnext: string # cursor + let lresult = charmatch(input) + (lvalue, lnext) = lresult + + let rresult = s(lnext) + (rvalue, rnext) = rresult + +plus("123;") From 6c49767a6c656fb097df71c41e4f123380bc1ca9 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Mon, 14 Sep 2020 00:57:49 -0600 Subject: [PATCH 1089/4254] Fixing issue #15302 -- lwip doesn't support signals (#15303) * Fixing issue #15302 -- lwip doesn't support signals * Adding test to catch issue #15302 -- lwip/freertos net library don't try to build / run on windows, it'll compile only but not run Fixing issue #15302 -- reworking test to compile on other platforms --- compiler/platform.nim | 2 +- lib/posix/posix_freertos_consts.nim | 36 +++++++++++++++++++---------- lib/posix/posix_other.nim | 4 ++++ lib/pure/net.nim | 4 ++-- tests/stdlib/tlwip.nim | 30 ++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 tests/stdlib/tlwip.nim diff --git a/compiler/platform.nim b/compiler/platform.nim index df79b2f8d..78c523c1a 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -179,7 +179,7 @@ const props: {ospNeedsPIC, ospPosix}), (name: "FreeRTOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", - scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {ospPosix}), (name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", diff --git a/lib/posix/posix_freertos_consts.nim b/lib/posix/posix_freertos_consts.nim index 5e83fa0f5..efe87aacf 100644 --- a/lib/posix/posix_freertos_consts.nim +++ b/lib/posix/posix_freertos_consts.nim @@ -220,11 +220,11 @@ var IPV6_UNICAST_HOPS* {.importc: "IPV6_UNICAST_HOPS", header: "". var IPV6_V6ONLY* {.importc: "IPV6_V6ONLY", header: "".}: cint # -var TCP_NODELAY* {.importc: "TCP_NODELAY", header: "".}: cint -var TCP_KEEPALIVE* {.importc: "TCP_KEEPALIVE", header: "".}: cint -var TCP_KEEPIDLE* {.importc: "TCP_KEEPIDLE", header: "".}: cint -var TCP_KEEPINTVL* {.importc: "TCP_KEEPINTVL", header: "".}: cint -var TCP_KEEPCNT* {.importc: "TCP_KEEPCNT", header: "".}: cint +const TCP_NODELAY* = 0x01 # don't delay send to coalesce packets +const TCP_KEEPALIVE* = 0x02 # send KEEPALIVE probes when idle for pcb->keep_idle milliseconds +const TCP_KEEPIDLE* = 0x03 # set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt +const TCP_KEEPINTVL* = 0x04 # set pcb->keep_intvl - Use seconds for get/setsockopt +const TCP_KEEPCNT* = 0x05 # set pcb->keep_cnt - Use number of probes sent for get/setsockopt # # var NL_SETD* {.importc: "NL_SETD", header: "".}: cint @@ -367,10 +367,25 @@ var SEM_FAILED* {.importc: "SEM_FAILED", header: "".}: pointer var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint # -var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint -var MSG_DONTROUTE* {.importc: "MSG_DONTROUTE", header: "".}: cint -var MSG_EOR* {.importc: "MSG_EOR", header: "".}: cint -var MSG_OOB* {.importc: "MSG_OOB", header: "".}: cint +# struct msghdr->msg_flags bit field values +const MSG_TRUNC* = 0x04 +const MSG_CTRUNC* = 0x08 + +# Flags we can use with send and recv. +const MSG_PEEK* = 0x01 # Peeks at an incoming message +const MSG_WAITALL* = 0x02 # Unimplemented: Requests that the function block until the full amount of data requested can be returned +const MSG_OOB* = 0x04 # Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific +const MSG_DONTWAIT* = 0x08 # Nonblocking i/o for this operation only +const MSG_MORE* = 0x10 # Sender will send more +# const MSG_NOSIGNAL* = 0x20 # Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. + +# Alternately, they can defined like this, but the above seems better when they're known/stable values: +# var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "".}: cint +# var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint +# var MSG_DONTROUTE* {.importc: "MSG_DONTROUTE", header: "".}: cint # not defined in lwip +# var MSG_EOR* {.importc: "MSG_EOR", header: "".}: cint # not defined in lwip +# var MSG_OOB* {.importc: "MSG_OOB", header: "".}: cint + # var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "".}: cint var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "".}: cint @@ -401,9 +416,6 @@ var SOL_SOCKET* {.importc: "SOL_SOCKET", header: "".}: cint const SocketMaxConnections {.intdefine.}: int = 32 var SOMAXCONN*: cint = SocketMaxConnections.cint -var MSG_PEEK* {.importc: "MSG_PEEK", header: "".}: cint -var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "".}: cint -var MSG_WAITALL* {.importc: "MSG_WAITALL", header: "".}: cint var AF_INET* {.importc: "AF_INET", header: "".}: cint var AF_INET6* {.importc: "AF_INET6", header: "".}: cint # var AF_UNIX* {.importc: "AF_UNIX", header: "".}: cint diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 1ad05060d..a5eb32d22 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -625,6 +625,10 @@ elif defined(solaris): # Solaris doesn't have MSG_NOSIGNAL const MSG_NOSIGNAL* = 0'i32 +elif defined(freertos) or defined(lwip): + # LwIP/FreeRTOS doesn't have MSG_NOSIGNAL + const + MSG_NOSIGNAL* = 0x20'i32 else: var MSG_NOSIGNAL* {.importc, header: "".}: cint diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 5d2ec8e30..f30b893a7 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1061,7 +1061,7 @@ proc accept*(server: Socket, client: var owned(Socket), var addrDummy = "" acceptAddr(server, client, addrDummy, flags) -when defined(posix): +when defined(posix) and not defined(lwip): from posix import Sigset, sigwait, sigismember, sigemptyset, sigaddset, sigprocmask, pthread_sigmask, SIGPIPE, SIG_BLOCK, SIG_UNBLOCK @@ -1079,7 +1079,7 @@ template blockSigpipe(body: untyped): untyped = ## ## For convenience, this template is also available for non-POSIX system, ## where `body` will be executed as-is. - when not defined(posix): + when not defined(posix) or defined(lwip): body else: template sigmask(how: cint, set, oset: var Sigset): untyped {.gensym.} = diff --git a/tests/stdlib/tlwip.nim b/tests/stdlib/tlwip.nim new file mode 100644 index 000000000..7f7822236 --- /dev/null +++ b/tests/stdlib/tlwip.nim @@ -0,0 +1,30 @@ +discard """ + targets: "c" + cmd: "nim $target --os:freertos --gc:arc $options $file" + disabled: "bsd" + disabled: "windows" + action: compile +""" + +# Note: +# This file tests FreeRTOS/LwIP cross-compilation on UNIX platforms +# Windows should run when compiled with esp-idf, however I'm not +# sure how to test for only compilation on Windows without running +# a test exe +# +# Note: +# disabling *BSDs since they're not playing well with `gcc` + +import net +import asynchttpserver, asyncdispatch + +proc cb*(req: Request) {.async.} = + await req.respond(Http200, "Hello World") + +proc run_http_server*() {.exportc.} = + echo "starting http server" + var server = newAsyncHttpServer() + + waitFor server.serve(Port(8181), cb) + +echo("ok") From a667475aaf83f3228fe76ffd25c296ca1847146b Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 14 Sep 2020 03:58:21 -0300 Subject: [PATCH 1090/4254] dom.Navigator add missing attributes (#15310) * Add missing attributes and methods to dom.Navigator * Add missing attributes and methods to dom.Navigator * Add missing attributes and methods to dom.Navigator --- changelog.md | 3 ++- lib/js/dom.nim | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 3333a837b..e7afaa229 100644 --- a/changelog.md +++ b/changelog.md @@ -162,7 +162,7 @@ - Added `deques.toDeque`, which creates a deque from an openArray. The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create an empty deque and add items manually. - + - `std/with`, `sugar.dup` now support object field assignment expression: ```nim import std/with @@ -185,6 +185,7 @@ - Add `getprotobyname` to `winlean`. Add `getProtoByname` to `nativesockets` which returns a protocol code from the database that matches the protocol `name`. +- Add missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. ## Language changes diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 84ceb73f3..a74c63231 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1245,10 +1245,19 @@ type appCodeName*: cstring appName*: cstring appVersion*: cstring + buildID*: cstring ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/buildID cookieEnabled*: bool + deviceMemory*: float ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/deviceMemory + doNotTrack*: cstring ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/doNotTrack language*: cstring + languages*: seq[cstring] ## https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages + maxTouchPoints*: cint ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/maxTouchPoints + onLine*: bool ## https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine + oscpu*: cstring ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/oscpu platform*: cstring userAgent*: cstring + vendor*: cstring ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vendor + webdriver*: bool ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver mimeTypes*: seq[ref MimeType] Plugin* {.importc.} = object of RootObj @@ -1328,7 +1337,7 @@ since (1, 3): composed*: bool DocumentOrShadowRoot* {.importc.} = object of RootObj activeElement*: Element - # styleSheets*: StyleSheetList + # styleSheets*: StyleSheetList ShadowRoot* = ref ShadowRootObj ShadowRootObj {.importc.} = object of DocumentOrShadowRoot delegatesFocus*: bool @@ -1581,6 +1590,12 @@ proc pushState*[T](h: History, stateObject: T, title, url: cstring) # Navigator "methods" proc javaEnabled*(h: Navigator): bool +since (1, 3): + proc canShare*(self: Navigator; data: cstring): bool ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/canShare + proc sendBeacon*(self: Navigator; url, data: cstring): bool ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon + proc vibrate*(self: Navigator; pattern: cint): bool ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vibrate + proc vibrate*(self: Navigator; pattern: openArray[cint]): bool ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vibrate + proc registerProtocolHandler*(self: Navigator; scheme, url, title: cstring) ## https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler # ClassList "methods" proc add*(c: ClassList, class: cstring) From 366216da6455fc882da44bac84b1887e6e1a267e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 14 Sep 2020 15:00:29 +0800 Subject: [PATCH 1091/4254] fix cookie with comma (#15319) --- lib/pure/httpcore.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 9c51887cb..81e02a1f8 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -229,7 +229,11 @@ proc parseHeader*(line: string): tuple[key: string, value: seq[string]] = i = line.parseUntil(result.key, ':') inc(i) # skip : if i < len(line): - i += parseList(line, result.value, i) + if cmpIgnoreCase(result.key, "cookie") == 0: + i += line.skipWhitespace(i) + result.value.add line.substr(i) + else: + i += parseList(line, result.value, i) elif result.key.len > 0: result.value = @[""] else: From e111b610caa26b6577f99423d360ff805e0b0ecf Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 14 Sep 2020 18:20:42 +0800 Subject: [PATCH 1092/4254] test cookies with comma for #15319 (#15322) * test cookies with comma for #15319 * space --- tests/stdlib/thttpcore.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index f96fcc3b8..33c24453e 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -34,3 +34,20 @@ suite "httpcore": let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"}) assert seq[string](h1["a"]).join(",") == "1,2,3" + + test "test cookies with comma": + doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) + doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"]) + doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"]) + + doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) + doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"]) + doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"]) + + doAssert parseHeader("Cookie: foo, bar") == (key: "Cookie", value: @["foo, bar"]) + doAssert parseHeader("Cookie: foo, bar, prologue") == (key: "Cookie", value: @["foo, bar, prologue"]) + doAssert parseHeader("Cookie: foo, bar, prologue, starlight") == (key: "Cookie", value: @["foo, bar, prologue, starlight"]) + + doAssert parseHeader("Accept: foo, bar") == (key: "Accept", value: @["foo", "bar"]) + doAssert parseHeader("Accept: foo, bar, prologue") == (key: "Accept", value: @["foo", "bar", "prologue"]) + doAssert parseHeader("Accept: foo, bar, prologue, starlight") == (key: "Accept", value: @["foo", "bar", "prologue", "starlight"]) From c38487aa225674f67659c28ce171fd93e2231ad1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 14 Sep 2020 12:50:23 +0200 Subject: [PATCH 1093/4254] fixes a critical ORC bug, refs #15076 (#15323) --- lib/system/orc.nim | 64 ++++++++++++++++++---------------------- tests/arc/tasyncleak.nim | 2 +- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index b9c820e4a..7c4cf9d98 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -50,6 +50,7 @@ type traceStack: CellSeq when useJumpStack: jumpStack: CellSeq # Lins' jump stack in order to speed up traversals + toFree: CellSeq freed, touched: int proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} = @@ -207,6 +208,11 @@ proc scan(s: Cell; desc: PNimType; j: var GcEnv) = t.setColor(colWhite) trace(t, desc, j) +when false: + proc writeCell(msg: cstring; s: Cell) = + cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n", + msg, s, s.rootIdx, s.rc shr rcShift, s.color) + proc collectWhite(s: Cell; desc: PNimType; j: var GcEnv) = #[ proc collectWhite(s: Cell) = @@ -218,37 +224,14 @@ proc collectWhite(s: Cell; desc: PNimType; j: var GcEnv) = ]# if s.color == colWhite and (s.rc and isCycleCandidate) == 0: s.setColor(colBlack) - when false: - # optimized version (does not work) - j.traceStack.add(s, desc) - # this way of writing the loop means we can free all the nodes - # afterwards avoiding the "use after free" bug in the paper. - var i = 0 - while i < j.traceStack.len: - let (t, desc) = j.traceStack.d[j.traceStack.len-1] - inc i - if t.color == colWhite and (t.rc and isCycleCandidate) == 0: - t.setColor(colBlack) - trace(t, desc, j) - - for i in 0 ..< j.traceStack.len: - free(j.traceStack.d[i][0], j.traceStack.d[i][1]) - j.traceStack.len = 0 - else: - var subgraph: CellSeq - init subgraph - subgraph.add(s, desc) - trace(s, desc, j) - while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() - if t.color == colWhite and (t.rc and isCycleCandidate) == 0: - subgraph.add(t, desc) - t.setColor(colBlack) - trace(t, desc, j) - for i in 0 ..< subgraph.len: - free(subgraph.d[i][0], subgraph.d[i][1]) - inc j.freed, subgraph.len - deinit subgraph + j.toFree.add(s, desc) + trace(s, desc, j) + while j.traceStack.len > 0: + let (t, desc) = j.traceStack.pop() + if t.color == colWhite and (t.rc and isCycleCandidate) == 0: + j.toFree.add(t, desc) + t.setColor(colBlack) + trace(t, desc, j) proc collectCyclesBacon(j: var GcEnv) = # pretty direct translation from @@ -269,10 +252,17 @@ proc collectCyclesBacon(j: var GcEnv) = for i in 0 ..< roots.len: scan(roots.d[i][0], roots.d[i][1], j) + init j.toFree for i in 0 ..< roots.len: let s = roots.d[i][0] s.rc = s.rc and not isCycleCandidate collectWhite(s, roots.d[i][1], j) + + for i in 0 ..< j.toFree.len: + free(j.toFree.d[i][0], j.toFree.d[i][1]) + + inc j.freed, j.toFree.len + deinit j.toFree #roots.len = 0 const @@ -283,6 +273,9 @@ var proc collectCycles() = ## Collect cycles. + when false: + cfprintf(cstderr, "[collectCycles] begin\n") + var j: GcEnv init j.traceStack when useJumpStack: @@ -304,17 +297,18 @@ proc collectCycles() = # we touched. If we're effective, we can reset the threshold: if j.freed * 2 >= j.touched: rootsThreshold = defaultThreshold - else: + elif rootsThreshold < high(int) div 4: rootsThreshold = rootsThreshold * 3 div 2 when false: - cprintf("[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold) + cfprintf(cstderr, "[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold) proc registerCycle(s: Cell; desc: PNimType) = + if roots.len >= rootsThreshold: + collectCycles() if roots.d == nil: init(roots) s.rootIdx = roots.len add(roots, s, desc) - if roots.len >= rootsThreshold: - collectCycles() + #writeCell("[added root]", s) proc GC_fullCollect* = ## Forces a full garbage collection pass. With ``--gc:orc`` triggers the cycle diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index 16e7446a7..71d62222d 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 6013, deallocCount: 6007)" + outputsub: "(allocCount: 4016, deallocCount: 4010)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ From 073bea66064afd72cd5e0ffc65569a1833dce385 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 15 Sep 2020 06:59:33 -0300 Subject: [PATCH 1094/4254] Remove Deprecated {.this:self.} from Documentation so people dont use it anymore (#15328) --- doc/manual_experimental.rst | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index ac8dedf11..a96c121a2 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -321,42 +321,6 @@ scope. Therefore, the following will *fail to compile:* a() -Automatic self insertions -========================= - -**Note**: The ``.this`` pragma is deprecated and should not be used anymore. - -Starting with version 0.14 of the language, Nim supports ``field`` as a -shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java -or C++. This feature has to be explicitly enabled via a ``{.this: self.}`` -statement pragma (instead of ``self`` any other identifier can be used too). -This pragma is active for the rest of the module: - -.. code-block:: nim - type - Parent = object of RootObj - parentField: int - Child = object of Parent - childField: int - - {.this: self.} - proc sumFields(self: Child): int = - result = parentField + childField - # is rewritten to: - # result = self.parentField + self.childField - -In addition to fields, routine applications are also rewritten, but only -if no other interpretation of the call is possible: - -.. code-block:: nim - proc test(self: Child) = - echo childField, " ", sumFields() - # is rewritten to: - echo self.childField, " ", sumFields(self) - # but NOT rewritten to: - echo self, self.childField, " ", sumFields(self) - - Named argument overloading ========================== From bc179ccc3f3c0df8b0c725b477c7cfeefaef4594 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 15 Sep 2020 12:40:23 +0200 Subject: [PATCH 1095/4254] fixes #15076 (#15329) --- compiler/ccgtypes.nim | 6 +-- compiler/liftdestructors.nim | 1 + compiler/lowerings.nim | 2 +- lib/system/orc.nim | 23 ++++++++-- tests/arc/tasyncleak2.nim | 88 ++++++++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 tests/arc/tasyncleak2.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 5b5720934..aa92b8534 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1319,9 +1319,9 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = genProc(m, theProc) result = theProc.loc.r else: - if op == attachedTrace and m.config.selectedGC == gcOrc and - containsGarbageCollectedRef(t): - when false: + when false: + if op == attachedTrace and m.config.selectedGC == gcOrc and + containsGarbageCollectedRef(t): # unfortunately this check is wrong for an object type that only contains # .cursor fields like 'Node' inside 'cycleleak'. internalError(m.config, info, "no attached trace proc found") diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index b3300850e..3d0635761 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -448,6 +448,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # follow all elements: forallElements(c, t, body, x, y) of attachedDispose: + forallElements(c, t, body, x, y) body.add genBuiltin(c.g, mDestroy, "destroy", x) proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index f6ca98196..2d96f8a60 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -158,7 +158,7 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType else: rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) - let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info)), + let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s), owner, info, owner.options) incl s.flags, sfAnon s.typ = result diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 7c4cf9d98..7500ba374 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -40,7 +40,7 @@ template setColor(c, col) = proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = let h = head(p) inc h.rc, rcIncrement - h.setColor colPurple # mark as potential cycle! + #h.setColor colPurple # mark as potential cycle! const useJumpStack = false # for thavlak the jump stack doesn't improve the performance at all @@ -74,6 +74,19 @@ proc free(s: Cell; desc: PNimType) {.inline.} = if desc.disposeImpl != nil: cast[DisposeProc](desc.disposeImpl)(p) + + when false: + cstderr.rawWrite desc.name + cstderr.rawWrite " " + if desc.disposeImpl == nil: + cstderr.rawWrite "lacks dispose" + if desc.traceImpl != nil: + cstderr.rawWrite ", but has trace\n" + else: + cstderr.rawWrite ", and lacks trace\n" + else: + cstderr.rawWrite "has dispose!\n" + nimRawDispose(p) proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = @@ -342,8 +355,8 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = #cprintf("[DESTROY] %p\n", p) else: dec cell.rc, rcIncrement - if cell.color == colPurple: - rememberCycle(result, cell, cast[ptr PNimType](p)[]) + #if cell.color == colPurple: + rememberCycle(result, cell, cast[ptr PNimType](p)[]) proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = if p != nil: @@ -353,5 +366,5 @@ proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl #cprintf("[DESTROY] %p %s\n", p, desc.name) else: dec cell.rc, rcIncrement - if cell.color == colPurple: - rememberCycle(result, cell, desc) + #if cell.color == colPurple: + rememberCycle(result, cell, desc) diff --git a/tests/arc/tasyncleak2.nim b/tests/arc/tasyncleak2.nim new file mode 100644 index 000000000..4d8486b3b --- /dev/null +++ b/tests/arc/tasyncleak2.nim @@ -0,0 +1,88 @@ +discard """ + output: "success" + cmd: "nim c --gc:orc $file" +""" + +# issue #15076 +import deques, strutils, asyncdispatch + +proc doNothing(): Future[void] = + #[ + var + :env + :env_1 + try: + `=destroy`(:env) + internalNew(:env) + `=sink`(:env.retFuture1, newFuture("doNothing")) + + `=destroy_1`(:env_1) + internalNew(:env_1) + `=`(:env_1.:up, :env) + `=sink_1`(:env.nameIterVar2, (doNothingIter, :env_1)) + + (doNothingNimAsyncContinue, :env)() + return `=_1`(result, :env.retFuture1) + finally: + `=destroy`(:env) + ]# + + var retFuture = newFuture[void]("doNothing") + iterator doNothingIter(): FutureBase {.closure.} = + # inspected ARC code: looks correct! + block: + var qqq = initDeque[string]() + for i in 0 .. 1000: + qqq.addLast($i) + complete(retFuture) # env.up.retFuture1 + + var nameIterVar = doNothingIter # iter_Env -> retFuture -> + + proc doNothingNimAsyncContinue() {.closure.} = + # inspected ARC code: looks correct + if not nameIterVar.finished: + var next_gensym0 = nameIterVar() + while (not next_gensym0.isNil) and next_gensym0.finished: + next_gensym0 = nameIterVar() + if nameIterVar.finished: + break + if next_gensym0 != nil: + {.gcsafe.}: + next_gensym0.addCallback cast[proc () {.closure, gcsafe.}](doNothingNimAsyncContinue) + + doNothingNimAsyncContinue() + return retFuture + +proc main(): Future[void] = + template await[T](f_gensym12: Future[T]): auto {.used.} = + var internalTmpFuture_gensym12: FutureBase = f_gensym12 + yield internalTmpFuture_gensym12 + (cast[type(f_gensym12)](internalTmpFuture_gensym12)).read() + + var retFuture = newFuture[void]("main") + iterator mainIter(): FutureBase {.closure.} = + block: + for x in 0 .. 1000: + await doNothing() + complete(retFuture) + + var nameIterVar_gensym11 = mainIter + proc mainNimAsyncContinue() {.closure.} = + if not nameIterVar_gensym11.finished: + var next_gensym11 = unown nameIterVar_gensym11() + while (not next_gensym11.isNil) and next_gensym11.finished: + next_gensym11 = unown nameIterVar_gensym11() + if nameIterVar_gensym11.finished: + break + if next_gensym11 != nil: + {.gcsafe.}: + next_gensym11.addCallback cast[proc () {.closure, gcsafe.}](mainNimAsyncContinue) + + mainNimAsyncContinue() + return retFuture + +for i in 0..9: + waitFor main() + GC_fullCollect() + assert getOccupiedMem() < 1024 +echo "success" From 0aaf4e2dfa2d06a71202bd283e99bb017c781f2c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 16 Sep 2020 20:51:01 +0800 Subject: [PATCH 1096/4254] Methods docs improvement (#15338) * docs improvement * minor --- doc/manual.rst | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index e72554603..ada6261b9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3816,13 +3816,10 @@ Overloading of the subscript operator The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded. -Multi-methods +Methods ============= -**Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -``--multimethods:on`` when compiling. - -Procedures always use static dispatch. Multi-methods use dynamic +Procedures always use static dispatch. Methods use dynamic dispatch. For dynamic dispatch to work on an object it should be a reference type. @@ -3869,6 +3866,35 @@ the effects that a call to ``m`` might cause. **Note**: Starting from Nim 0.20, generic methods are deprecated. +Multi-methods +-------------- + +**Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass +``--multimethods:on`` when compiling. + +In a multi-method all parameters that have an object type are used for the dispatching: + +.. code-block:: nim + :test: "nim c --multiMethods:on $1" + + type + Thing = ref object of RootObj + Unit = ref object of Thing + x: int + + method collide(a, b: Thing) {.inline.} = + quit "to override!" + + method collide(a: Thing, b: Unit) {.inline.} = + echo "1" + + method collide(a: Unit, b: Thing) {.inline.} = + echo "2" + + var a, b: Unit + new a + new b + collide(a, b) # output: 2 Inhibit dynamic method resolution via procCall ----------------------------------------------- From fd31e8ff6f96527cc52125d01311d022ff82fead Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 16 Sep 2020 14:57:01 +0200 Subject: [PATCH 1097/4254] allow old styled RTTI for arc/orc (#15331) --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 83 ++++++++++------- compiler/ccgstmts.nim | 8 +- compiler/ccgtrav.nim | 2 +- compiler/ccgtypes.nim | 164 ++++++++++++++++++++------------- compiler/cgen.nim | 9 +- compiler/cgendata.nim | 2 + compiler/liftdestructors.nim | 4 +- compiler/options.nim | 5 +- lib/core/typeinfo.nim | 167 +++++++++++++++++++++++----------- lib/pure/marshal.nim | 11 +-- lib/system.nim | 57 ++++++------ lib/system/arc.nim | 22 +++-- lib/system/assign.nim | 136 ++++++++++++++++++--------- lib/system/cellseqs_v2.nim | 6 +- lib/system/cyclebreaker.nim | 14 +-- lib/system/deepcopy.nim | 52 ++++++----- lib/system/hti.nim | 2 + lib/system/mm/malloc.nim | 6 +- lib/system/orc.nim | 24 ++--- lib/system/seqs_v2.nim | 16 ++-- lib/system/seqs_v2_reimpl.nim | 17 ++++ tests/stdlib/tmarshal.nim | 6 +- 23 files changed, 512 insertions(+), 303 deletions(-) create mode 100644 lib/system/seqs_v2_reimpl.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 8baf49265..4d37b284c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -680,7 +680,7 @@ type mNBindSym, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mNHint, mNWarning, mNError, - mInstantiationInfo, mGetTypeInfo, + mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, mSymIsInstantiationOf, mNodeId diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 8f45452bf..0d235f62e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -266,10 +266,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)]) else: linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", - [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) + [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", - [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) + [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = assert d.k != locNone @@ -318,7 +318,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", [addrLoc(p.config, dest), rdLoc(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyString: if optSeqDestructors in p.config.globalOptions: genGenericAsgn(p, dest, src, flags) @@ -383,7 +383,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, # XXX: is this correct for arrays? "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: linefmt(p, cpsStmts, # bug #4799, keep the nimCopyMem for a while @@ -425,16 +425,21 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = # XXX optimize this linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySequence, tyString: - linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", - [addrLoc(p.config, dest), rdLoc(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + if optTinyRtti in p.config.globalOptions: + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", + [addrLoc(p.config, dest), addrLocOrTemp(src), + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) + else: + linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", + [addrLoc(p.config, dest), rdLoc(src), + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyOpenArray, tyVarargs: linefmt(p, cpsStmts, "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySet: if mapSetType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", @@ -1229,12 +1234,12 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), getTypeDesc(p.module, e[1].typ), - genTypeInfo(p.module, seqType, e.info)]) + genTypeInfoV1(p.module, seqType, e.info)]) else: const seqAppendPattern = "($2) #incrSeqV3($1, $3)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), getTypeDesc(p.module, e[1].typ), - genTypeInfo(p.module, seqType, e.info)]) + genTypeInfoV1(p.module, seqType, e.info)]) # emit the write barrier if required, but we can always move here, so # use 'genRefAssign' for the seq. genRefAssign(p, a, call) @@ -1254,7 +1259,7 @@ proc genReset(p: BProc, n: PNode) = when false: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(p.config, a), - genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) + genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)]) proc genDefault(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) @@ -1280,7 +1285,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = [getTypeDesc(p.module, typ), sizeExpr]) genAssignment(p, a, b, {}) else: - let ti = genTypeInfo(p.module, typ, a.lode.info) + let ti = genTypeInfoV1(p.module, typ, a.lode.info) if bt.destructor != nil and not isTrivialProc(bt.destructor): # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling @@ -1339,18 +1344,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = if p.config.selectedGC == gcGo: # we need the write barrier call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfo(p.module, seqtype, dest.lode.info), length]) + genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc]) else: call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfo(p.module, seqtype, dest.lode.info), length]) + genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc]) else: if lenIsZero: call.r = rope"NIM_NIL" else: call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfo(p.module, seqtype, dest.lode.info), length]) + genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = @@ -1383,7 +1388,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = putIntoDest(p, d, e, ropecg(p.module, "($1)#nimNewSeqOfCap($2, $3)", [ getTypeDesc(p.module, seqtype), - genTypeInfo(p.module, seqtype, e.info), a.rdLoc])) + genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc])) gcUsage(p.config, e) proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) = @@ -1553,7 +1558,10 @@ proc genNewFinalize(p: BProc, e: PNode) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], f) initLoc(b, locExpr, a.lode, OnHeap) - ti = genTypeInfo(p.module, refType, e.info) + if optTinyRtti in p.config.globalOptions: + ti = genTypeInfoV2(p.module, refType, e.info) + else: + ti = genTypeInfoV1(p.module, refType, e.info) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), @@ -1568,9 +1576,9 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = result = ropecg(p.module, "#isObj($1.m_type, $2)", [a, genTypeInfo2Name(p.module, dest)]) else: - # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we + # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we # have to call it here first: - let ti = genTypeInfo(p.module, dest, info) + let ti = genTypeInfoV1(p.module, dest, info) if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and tfObjHasKids notin dest.flags): result = "$1.m_type == $2" % [a, ti] @@ -1583,7 +1591,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = when false: # former version: result = ropecg(p.module, "#isObj($1.m_type, $2)", - [a, genTypeInfo(p.module, dest, info)]) + [a, genTypeInfoV1(p.module, dest, info)]) proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var a: TLoc @@ -1633,12 +1641,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = of tyEnum, tyOrdinal: putIntoDest(p, d, e, ropecg(p.module, "#reprEnum((NI)$1, $2)", [ - rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) + rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) of tyString: putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) of tySet: putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [ - addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage) + addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage) of tyOpenArray, tyVarargs: var b: TLoc case skipTypes(a.t, abstractVarRange).kind @@ -1653,20 +1661,20 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = else: internalError(p.config, e[0].info, "genRepr()") putIntoDest(p, d, e, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), - genTypeInfo(p.module, elemType(t), e.info)]), a.storage) + genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage) of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", [ - rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) + rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) of tyEmpty, tyVoid: localError(p.config, e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", - [addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), + [addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage) gcUsage(p.config, e) -proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = +proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; enforceV1 = false): Rope = result = rdLoc(a) var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyLent, tyPtr, tyRef}: @@ -1680,13 +1688,20 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = result.add(".Sup") t = skipTypes(t[0], skipPtrs) result.add ".m_type" + if optTinyRtti in p.config.globalOptions and enforceV1: + result.add "->typeInfoV1" proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = discard cgsym(p.module, "TNimType") + let t = e[1].typ + # ordinary static type information + putIntoDest(p, d, e, genTypeInfoV1(p.module, t, e.info)) + +proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) = let t = e[1].typ if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo": # ordinary static type information - putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info)) + putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info)) else: var a: TLoc initLocExpr(p, e[1], a) @@ -1779,13 +1794,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)" call.r = ropecg(p.module, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) + genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) else: const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)" call.r = ropecg(p.module, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) + genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) genAssignment(p, a, call, {}) gcUsage(p.config, e) @@ -2226,6 +2241,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAddI..mPred: binaryArithOverflow(p, e, d, op) of mRepr: genRepr(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d) + of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d) of mSwap: genSwap(p, e, d) of mInc, mDec: const opr: array[mInc..mDec, string] = ["+=", "-="] @@ -2534,7 +2550,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, dest) else: - genTypeInfo(p.module, dest, n.info) + genTypeInfoV1(p.module, dest, n.info) if nilCheck != nil: linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n", [nilCheck, r, checkFor, raiseInstr(p)]) @@ -2951,7 +2967,10 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, getNullValueAuxT(p, orig, base, base.n, constOrNil, result, count, isConst, info) result.add "}" elif not isObjLackingTypeField(t): - result.add genTypeInfo(p.module, orig, obj.info) + if optTinyRtti in p.config.globalOptions: + result.add genTypeInfoV2(p.module, orig, obj.info) + else: + result.add genTypeInfoV1(p.module, orig, obj.info) inc count getNullValueAux(p, t, obj, constOrNil, result, count, isConst, info) # do not emit '{}' as that is not valid C: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 48c024b1f..5bed7cf32 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1040,7 +1040,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, typeNode.typ) else: - genTypeInfo(p.module, typeNode.typ, typeNode.info) + genTypeInfoV1(p.module, typeNode.typ, typeNode.info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1255,7 +1255,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, t[i][j].typ) else: - genTypeInfo(p.module, t[i][j].typ, t[i][j].info) + genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1383,7 +1383,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, t[i][j].typ) else: - genTypeInfo(p.module, t[i][j].typ, t[i][j].info) + genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1508,7 +1508,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType, field: PSym) = var t = skipTypes(objtype, abstractVar) assert t.kind == tyObject - discard genTypeInfo(p.module, t, a.lode.info) + discard genTypeInfoV1(p.module, t, a.lode.info) if not containsOrIncl(p.module.declaredThings, field.id): appcg(p.module, cfsVars, "extern $1", [discriminatorTableDecl(p.module, t, field)]) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 63b1cb88a..29b93e530 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -173,7 +173,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = [result, markerName, getModuleDllPath(m)]) proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope = - discard genTypeInfo(m, s.loc.t, info) + discard genTypeInfoV1(m, s.loc.t, info) var c: TTraversalClosure var p = newProc(nil, m) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index aa92b8534..771e1ede9 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -609,7 +609,10 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags: appcg(m, result, " {$n", []) else: - appcg(m, result, " {$n#TNimType* m_type;$n", []) + if optTinyRtti in m.config.globalOptions: + appcg(m, result, " {$n#TNimTypeV2* m_type;$n", []) + else: + appcg(m, result, " {$n#TNimType* m_type;$n", []) hasField = true elif m.compileToCpp: appcg(m, result, " : public $1 {$n", @@ -1004,7 +1007,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope = # ------------------ type info generation ------------------------------------- -proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope +proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope proc getNimNode(m: BModule): Rope = result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)] inc(m.typeNodes) @@ -1067,7 +1070,7 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope; if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x): base = rope("0") else: - base = genTypeInfo(m, x, info) + base = genTypeInfoV1(m, x, info) else: base = rope("0") genTypeInfoAuxBase(m, typ, origType, name, base, info) @@ -1126,7 +1129,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" & "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r, - genTypeInfo(m, field.typ, info), + genTypeInfoV1(m, field.typ, info), makeCString(field.name.s), tmp, rope(L)]) m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)]) @@ -1163,7 +1166,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; m.s[cfsTypeInit3].addf("$1.kind = 1;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.name = $5;$n", [expr, getTypeDesc(m, origType), - field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)]) + field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)]) else: internalError(m.config, n.info, "genObjectFields") proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = @@ -1198,7 +1201,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) "$1.offset = offsetof($2, Field$3);$n" & "$1.typ = $4;$n" & "$1.name = \"Field$3\";$n", - [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)]) + [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfoV1(m, a, info)]) m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", [expr, rope(typ.len), tmp]) else: @@ -1255,7 +1258,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = - genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ[1], info), info) + genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info) proc fakeClosureType(m: BModule; owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] @@ -1273,13 +1276,14 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) = m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", [result, s.loc.r]) -proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) = +proc declareNimType(m: BModule, name: string; str: Rope, ownerModule: PSym) = + let nr = rope(name) if m.hcrOn: - m.s[cfsData].addf("static TNimType* $1;$n", [str]) - m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n", - [str, getModuleDllPath(m, ownerModule)]) + m.s[cfsData].addf("static $2* $1;$n", [str, nr]) + m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n", + [str, getModuleDllPath(m, ownerModule), nr]) else: - m.s[cfsData].addf("extern TNimType $1;$n", [str]) + m.s[cfsData].addf("extern $2 $1;$n", [str, nr]) proc genTypeInfo2Name(m: BModule; t: PType): Rope = var res = "|" @@ -1327,7 +1331,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = internalError(m.config, info, "no attached trace proc found") result = rope("NIM_NIL") -proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = +proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = var typeName: Rope if t.kind == tyObject: if incompleteType(t): @@ -1337,8 +1341,8 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) else: typeName = rope("NIM_NIL") - discard cgsym(m, "TNimType") - m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) + discard cgsym(m, "TNimTypeV2") + m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) let destroyImpl = genHook(m, t, info, attachedDestructor) let traceImpl = genHook(m, t, info, attachedTrace) let disposeImpl = genHook(m, t, info, attachedDispose) @@ -1347,7 +1351,43 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) name, destroyImpl, getTypeDesc(m, t), typeName, traceImpl, disposeImpl]) -proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = +proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = + let origType = t + var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) + + let prefixTI = if m.hcrOn: "(" else: "(&" + + let sig = hashType(origType) + result = m.typeInfoMarkerV2.getOrDefault(sig) + if result != nil: + return prefixTI.rope & result & ")".rope + + let marker = m.g.typeInfoMarkerV2.getOrDefault(sig) + if marker.str != nil: + discard cgsym(m, "TNimTypeV2") + declareNimType(m, "TNimTypeV2", marker.str, marker.owner) + # also store in local type section: + m.typeInfoMarkerV2[sig] = marker.str + return prefixTI.rope & marker.str & ")".rope + + result = "NTIv2$1_" % [rope($sig)] + m.typeInfoMarkerV2[sig] = result + + let owner = t.skipTypes(typedescPtrs).owner.getModule + if owner != m.module: + # make sure the type info is created in the owner module + assert m.g.modules[owner.position] != nil + discard genTypeInfoV2(m.g.modules[owner.position], origType, info) + # reference the type info as extern here + discard cgsym(m, "TNimTypeV2") + declareNimType(m, "TNimTypeV2", result, owner) + return prefixTI.rope & result & ")".rope + + m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner) + genTypeInfoV2Impl(m, t, origType, result, info) + result = prefixTI.rope & result & ")".rope + +proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = let origType = t var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) @@ -1362,7 +1402,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = if marker.str != nil: discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") - declareNimType(m, marker.str, marker.owner) + declareNimType(m, "TNimType", marker.str, marker.owner) # also store in local type section: m.typeInfoMarker[sig] = marker.str return prefixTI.rope & marker.str & ")".rope @@ -1374,63 +1414,65 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = if owner != m.module: # make sure the type info is created in the owner module assert m.g.modules[owner.position] != nil - discard genTypeInfo(m.g.modules[owner.position], origType, info) + discard genTypeInfoV1(m.g.modules[owner.position], origType, info) # reference the type info as extern here discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") - declareNimType(m, result, owner) + declareNimType(m, "TNimType", result, owner) return prefixTI.rope & result & ")".rope m.g.typeInfoMarker[sig] = (str: result, owner: owner) - if optTinyRtti in m.config.globalOptions: - genTypeInfoV2(m, t, origType, result, info) - else: - case t.kind - of tyEmpty, tyVoid: result = rope"0" - of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: + case t.kind + of tyEmpty, tyVoid: result = rope"0" + of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: + genTypeInfoAuxBase(m, t, t, result, rope"0", info) + of tyStatic: + if t.n != nil: result = genTypeInfoV1(m, lastSon t, info) + else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')') + of tyUserTypeClasses: + internalAssert m.config, t.isResolvedUserTypeClass + return genTypeInfoV1(m, t.lastSon, info) + of tyProc: + if t.callConv != ccClosure: genTypeInfoAuxBase(m, t, t, result, rope"0", info) - of tyStatic: - if t.n != nil: result = genTypeInfo(m, lastSon t, info) - else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') - of tyUserTypeClasses: - internalAssert m.config, t.isResolvedUserTypeClass - return genTypeInfo(m, t.lastSon, info) - of tyProc: - if t.callConv != ccClosure: - genTypeInfoAuxBase(m, t, t, result, rope"0", info) - else: - let x = fakeClosureType(m, t.owner) - genTupleInfo(m, x, x, result, info) - of tySequence: - genTypeInfoAux(m, t, t, result, info) - if optSeqDestructors notin m.config.globalOptions: - if m.config.selectedGC >= gcMarkAndSweep: - let markerProc = genTraverseProc(m, origType, sig) - m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) - of tyRef: - genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC >= gcMarkAndSweep: - let markerProc = genTraverseProc(m, origType, sig) - m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) - of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) - of tyArray: genArrayInfo(m, t, result, info) - of tySet: genSetInfo(m, t, result, info) - of tyEnum: genEnumInfo(m, t, result, info) - of tyObject: - genObjectInfo(m, t, origType, result, info) - of tyTuple: - # if t.n != nil: genObjectInfo(m, t, result) - # else: - # BUGFIX: use consistently RTTI without proper field names; otherwise - # results are not deterministic! - genTupleInfo(m, t, origType, result, info) - else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') + else: + let x = fakeClosureType(m, t.owner) + genTupleInfo(m, x, x, result, info) + of tySequence: + genTypeInfoAux(m, t, t, result, info) + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) + of tyRef: + genTypeInfoAux(m, t, t, result, info) + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) + of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) + of tyArray: genArrayInfo(m, t, result, info) + of tySet: genSetInfo(m, t, result, info) + of tyEnum: genEnumInfo(m, t, result, info) + of tyObject: + genObjectInfo(m, t, origType, result, info) + of tyTuple: + # if t.n != nil: genObjectInfo(m, t, result) + # else: + # BUGFIX: use consistently RTTI without proper field names; otherwise + # results are not deterministic! + genTupleInfo(m, t, origType, result, info) + else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')') if t.attachedOps[attachedDeepCopy] != nil: genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result) elif origType.attachedOps[attachedDeepCopy] != nil: genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result) + + if optTinyRtti in m.config.globalOptions and t.kind == tyObject: + let v2info = genTypeInfoV2(m, origType, info) + addf(m.s[cfsTypeInit3], "$1->typeInfoV1 = (void*)&$2; $2.typeInfoV2 = (void*)$1;$n", [ + v2info, result]) + result = prefixTI.rope & result & ")".rope proc genTypeSection(m: BModule, n: PNode) = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d5e1e020c..242d1f89b 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -360,7 +360,10 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, while s.kind == tyObject and s[0] != nil: r.add(".Sup") s = skipTypes(s[0], skipPtrs) - linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)]) + if optTinyRtti in p.config.globalOptions: + linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV2(p.module, t, a.lode.info)]) + else: + linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) of frEmbedded: if optTinyRtti in p.config.globalOptions: var tmp: TLoc @@ -376,7 +379,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, else: # worst case for performance: var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a) - linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)]) + linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) if isException(t): var r = rdLoc(a) @@ -417,7 +420,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = specializeReset(p, loc) when false: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)]) + [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)]) # XXX: generated reset procs should not touch the m_type # field, so disabling this should be safe: genObjectInit(p, cpsStmts, loc.t, loc, constructObj) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 3384558f8..8e5094336 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -122,6 +122,7 @@ type forwardedProcs*: seq[PSym] # proc:s that did not yet have a body generatedHeader*: BModule typeInfoMarker*: TypeCacheWithOwner + typeInfoMarkerV2*: TypeCacheWithOwner config*: ConfigRef graph*: ModuleGraph strVersion*, seqVersion*: int # version of the string/seq implementation to use @@ -155,6 +156,7 @@ type declaredProtos*: IntSet # prototypes we have declared in this .c file headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information + typeInfoMarkerV2*: TypeCache initProc*: BProc # code for init procedure preInitProc*: BProc # code executed before the init proc hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 3d0635761..dd5332b38 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -523,7 +523,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var cond: PNode if isCyclic: if isFinal(elemType): - let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) + let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo) else: @@ -546,7 +546,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: if isFinal(elemType): - let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) + let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y) else: diff --git a/compiler/options.nim b/compiler/options.nim index 5b23ac9af..03418d953 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -136,9 +136,8 @@ type cmdCompileToBackend, # compile to backend in TBackend TStringSeq* = seq[string] TGCMode* = enum # the selected GC - gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcArc, gcOrc, - gcHooks, - gcRefc, gcV2, gcGo + gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc, + gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo # gcRefc and the GCs that follow it use a write barrier, # as far as usesWriteBarrier() is concerned diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 01588e9eb..b1b9bcb27 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -19,8 +19,6 @@ ## work with the types' AST representation at compile time. See, for example, ## the `getTypeImpl proc`_. As an alternative ## approach to storing arbitrary types at runtime, consider using generics. -## -## {.push hints: off.} @@ -77,11 +75,21 @@ type ppointer = ptr pointer pbyteArray = ptr array[0xffff, int8] - TGenericSeq {.importc.} = object - len, space: int - when defined(gogc): - elemSize: int - PGenSeq = ptr TGenericSeq +when not defined(gcDestructors): + type + TGenericSeq {.importc.} = object + len, space: int + when defined(gogc): + elemSize: int + PGenSeq = ptr TGenericSeq + + when defined(gogc): + const GenericSeqSize = (3 * sizeof(int)) + else: + const GenericSeqSize = (2 * sizeof(int)) + +else: + include system/seqs_v2_reimpl when not defined(js): template rawType(x: Any): PNimType = @@ -90,18 +98,20 @@ when not defined(js): template `rawType=`(x: var Any, p: PNimType) = x.rawTypePtr = cast[pointer](p) -when defined(gogc): - const GenericSeqSize = (3 * sizeof(int)) -else: - const GenericSeqSize = (2 * sizeof(int)) - proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.} -proc genericShallowAssign(dest, src: pointer, mt: PNimType) {. - importCompilerProc.} -proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.} -proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.} -proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.} -proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.} + +when not defined(gcDestructors): + proc genericShallowAssign(dest, src: pointer, mt: PNimType) {. + importCompilerProc.} + proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.} + proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.} + proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.} + proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.} +else: + proc nimNewObj(size: int): pointer {.importCompilerProc.} + proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.importCompilerProc.} + proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. + importCompilerProc.} template `+!!`(a, b): untyped = cast[pointer](cast[ByteAddress](a) + b) @@ -167,29 +177,47 @@ proc baseTypeSize*(x: Any): int {.inline.} = proc invokeNew*(x: Any) = ## performs ``new(x)``. `x` needs to represent a ``ref``. assert x.rawType.kind == tyRef - var z = newObj(x.rawType, x.rawType.base.size) - genericAssign(x.value, addr(z), x.rawType) + when defined(gcDestructors): + cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size) + else: + var z = newObj(x.rawType, x.rawType.base.size) + genericAssign(x.value, addr(z), x.rawType) proc invokeNewSeq*(x: Any, len: int) = ## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``. assert x.rawType.kind == tySequence - var z = newSeq(x.rawType, len) - genericShallowAssign(x.value, addr(z), x.rawType) + when defined(gcDestructors): + var s = cast[ptr NimSeqV2Reimpl](x.value) + s.len = len + let elem = x.rawType.base + s.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(len, elem.size, elem.align)) + else: + var z = newSeq(x.rawType, len) + genericShallowAssign(x.value, addr(z), x.rawType) proc extendSeq*(x: Any) = ## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``. assert x.rawType.kind == tySequence - var y = cast[ptr PGenSeq](x.value)[] - var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align) - # 'incrSeq' already freed the memory for us and copied over the RC! - # So we simply copy the raw pointer into 'x.value': - cast[ppointer](x.value)[] = z - #genericShallowAssign(x.value, addr(z), x.rawType) + when defined(gcDestructors): + var s = cast[ptr NimSeqV2Reimpl](x.value) + let elem = x.rawType.base + s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAdd(s.len, s.p, 1, elem.size, elem.align)) + inc s.len + else: + var y = cast[ptr PGenSeq](x.value)[] + var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align) + # 'incrSeq' already freed the memory for us and copied over the RC! + # So we simply copy the raw pointer into 'x.value': + cast[ppointer](x.value)[] = z + #genericShallowAssign(x.value, addr(z), x.rawType) proc setObjectRuntimeType*(x: Any) = ## this needs to be called to set `x`'s runtime object type field. assert x.rawType.kind == tyObject - objectInit(x.value, x.rawType) + when defined(gcDestructors): + cast[ppointer](x.value)[] = x.rawType.typeInfoV2 + else: + objectInit(x.value, x.rawType) proc skipRange(x: PNimType): PNimType {.inline.} = result = x @@ -202,17 +230,26 @@ proc `[]`*(x: Any, i: int): Any = ## accessor for an any `x` that represents an array or a sequence. case x.rawType.kind of tyArray: - var bs = x.rawType.base.size + let bs = x.rawType.base.size if i >=% x.rawType.size div bs: raise newException(IndexDefect, formatErrorIndexBound(i, x.rawType.size div bs)) return newAny(x.value +!! i*bs, x.rawType.base) of tySequence: - var s = cast[ppointer](x.value)[] - if s == nil: raise newException(ValueError, "sequence is nil") - var bs = x.rawType.base.size - if i >=% cast[PGenSeq](s).len: - raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1)) - return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base) + when defined(gcDestructors): + var s = cast[ptr NimSeqV2Reimpl](x.value) + if i >=% s.len: + raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1)) + let bs = x.rawType.base.size + let ba = x.rawType.base.align + let headerSize = align(sizeof(int), ba) + return newAny(s.p +!! (headerSize+i*bs), x.rawType.base) + else: + var s = cast[ppointer](x.value)[] + if s == nil: raise newException(ValueError, "sequence is nil") + let bs = x.rawType.base.size + if i >=% cast[PGenSeq](s).len: + raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1)) + return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base) else: assert false proc `[]=`*(x: Any, i: int, y: Any) = @@ -225,13 +262,23 @@ proc `[]=`*(x: Any, i: int, y: Any) = assert y.rawType == x.rawType.base genericAssign(x.value +!! i*bs, y.value, y.rawType) of tySequence: - var s = cast[ppointer](x.value)[] - if s == nil: raise newException(ValueError, "sequence is nil") - var bs = x.rawType.base.size - if i >=% cast[PGenSeq](s).len: - raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1)) - assert y.rawType == x.rawType.base - genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType) + when defined(gcDestructors): + var s = cast[ptr NimSeqV2Reimpl](x.value) + if i >=% s.len: + raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1)) + let bs = x.rawType.base.size + let ba = x.rawType.base.align + let headerSize = align(sizeof(int), ba) + assert y.rawType == x.rawType.base + genericAssign(s.p +!! (headerSize+i*bs), y.value, y.rawType) + else: + var s = cast[ppointer](x.value)[] + if s == nil: raise newException(ValueError, "sequence is nil") + var bs = x.rawType.base.size + if i >=% cast[PGenSeq](s).len: + raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1)) + assert y.rawType == x.rawType.base + genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType) else: assert false proc len*(x: Any): int = @@ -240,11 +287,14 @@ proc len*(x: Any): int = of tyArray: result = x.rawType.size div x.rawType.base.size of tySequence: - let pgenSeq = cast[PGenSeq](cast[ppointer](x.value)[]) - if isNil(pgenSeq): - result = 0 + when defined(gcDestructors): + result = cast[ptr NimSeqV2Reimpl](x.value).len else: - result = pgenSeq.len + let pgenSeq = cast[PGenSeq](cast[ppointer](x.value)[]) + if isNil(pgenSeq): + result = 0 + else: + result = pgenSeq.len else: assert false @@ -260,21 +310,27 @@ proc isNil*(x: Any): bool = assert x.rawType.kind in {tyCString, tyRef, tyPtr, tyPointer, tyProc} result = isNil(cast[ppointer](x.value)[]) +const + pointerLike = when defined(gcDestructors): {tyCString, tyRef, tyPtr, tyPointer, tyProc} + else: {tyString, tyCString, tyRef, tyPtr, tyPointer, + tySequence, tyProc} + proc getPointer*(x: Any): pointer = ## retrieve the pointer value out of `x`. ``x`` needs to be of kind ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. - assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, - tySequence, tyProc} + assert x.rawType.kind in pointerLike result = cast[ppointer](x.value)[] proc setPointer*(x: Any, y: pointer) = ## sets the pointer value of `x`. ``x`` needs to be of kind ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. - assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, - tySequence, tyProc} - cast[ppointer](x.value)[] = y + assert x.rawType.kind in pointerLike + when defined(gcDestructors): + genericAssign(x.value, y, x.rawType) + else: + cast[ppointer](x.value)[] = y proc fieldsAux(p: pointer, n: ptr TNimNode, ret: var seq[tuple[name: cstring, any: Any]]) = @@ -607,13 +663,16 @@ proc setBiggestFloat*(x: Any, y: BiggestFloat) = proc getString*(x: Any): string = ## retrieve the string value out of `x`. `x` needs to represent a string. assert x.rawType.kind == tyString - if not isNil(cast[ptr pointer](x.value)[]): + when defined(gcDestructors): result = cast[ptr string](x.value)[] + else: + if not isNil(cast[ptr pointer](x.value)[]): + result = cast[ptr string](x.value)[] proc setString*(x: Any, y: string) = ## sets the string value of `x`. `x` needs to represent a string. assert x.rawType.kind == tyString - cast[ptr string](x.value)[] = y + cast[ptr string](x.value)[] = y # also correct for gcDestructors proc getCString*(x: Any): cstring = ## retrieve the cstring value out of `x`. `x` needs to represent a cstring. diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index b6ad2e20f..e74e68b05 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -51,16 +51,15 @@ ## * `json module `_ const unsupportedPlatform = - when defined(nimV2): "new runtime" - elif defined(js): "javascript" + when defined(js): "javascript" elif defined(nimscript): "nimscript" else: "" when unsupportedPlatform != "": {.error: "marshal module is not supported in " & unsupportedPlatform & """. -Please use alternative packages for serialization. -It is possible to reimplement this module using generics and type traits. -Please contribute new implementation.""".} +Please use alternative packages for serialization. +It is possible to reimplement this module using generics and type traits. +Please contribute a new implementation.""".} import streams, typeinfo, json, intsets, tables, unicode @@ -345,7 +344,7 @@ proc to*[T](data: string): T = when not defined(testing) and isMainModule: - template testit(x: untyped) = echo($$to[type(x)]($$x)) + template testit(x: untyped) = echo($$to[typeof(x)]($$x)) var x: array[0..4, array[0..4, string]] = [ ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], diff --git a/lib/system.nim b/lib/system.nim index 0a8c52908..c05ca24dc 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -537,7 +537,7 @@ when notJSnotNims and not defined(nimSeqsV2): template space(s: PGenericSeq): int {.dirty.} = s.reserved and not (seqShallowFlag or strlitFlag) -when notJSnotNims and not defined(nimV2): +when notJSnotNims: include "system/hti" type @@ -1718,16 +1718,16 @@ when not defined(js) and hasThreadSupport and hostOS != "standalone": when not defined(js) and defined(nimV2): type - TNimNode {.compilerproc.} = object # to keep the code generator simple DestructorProc = proc (p: pointer) {.nimcall, benign, raises: [].} - TNimType {.compilerproc.} = object + TNimTypeV2 {.compilerproc.} = object destructor: pointer size: int align: int name: cstring traceImpl: pointer disposeImpl: pointer - PNimType = ptr TNimType + typeInfoV1: pointer # for backwards compat, usually nil + PNimTypeV2 = ptr TNimTypeV2 when notJSnotNims and defined(nimSeqsV2): include "system/strs_v2" @@ -2271,29 +2271,28 @@ when notJSnotNims: else: const GenericSeqSize = (2 * sizeof(int)) - when not defined(nimV2): - proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint = - sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") - var d: uint - var a = cast[uint](aa) - case n.typ.size - of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[]) - of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[]) - of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[]) - of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[]) - else: - d = 0'u - sysAssert(false, "getDiscriminant: invalid n.typ.size") - return d + proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint = + sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") + var d: uint + var a = cast[uint](aa) + case n.typ.size + of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[]) + of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[]) + of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[]) + of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[]) + else: + d = 0'u + sysAssert(false, "getDiscriminant: invalid n.typ.size") + return d - proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = - var discr = getDiscriminant(aa, n) - if discr < cast[uint](n.len): - result = n.sons[discr] - if result == nil: result = n.sons[n.len] - # n.sons[n.len] contains the ``else`` part (but may be nil) - else: - result = n.sons[n.len] + proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = + var discr = getDiscriminant(aa, n) + if discr < cast[uint](n.len): + result = n.sons[discr] + if result == nil: result = n.sons[n.len] + # n.sons[n.len] contains the ``else`` part (but may be nil) + else: + result = n.sons[n.len] when notJSnotNims and hasAlloc: {.push profiler: off.} @@ -2305,8 +2304,8 @@ when notJSnotNims and hasAlloc: {.pop.} include "system/strmantle" - when not usesDestructors: - include "system/assign" + include "system/assign" + when not defined(nimV2): include "system/repr" @@ -2862,7 +2861,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## # -> B is 1 discard -when hasAlloc and notJSnotNims and not usesDestructors: +when hasAlloc and notJSnotNims: # XXX how to implement 'deepCopy' is an open problem. proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = ## Performs a deep copy of `y` and copies it into `x`. diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 7fe17d3ea..68376cdab 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -59,12 +59,6 @@ type Cell = ptr RefHeader -template `+!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) +% s) - -template `-!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) -% s) - template head(p: pointer): Cell = cast[Cell](cast[int](p) -% sizeof(RefHeader)) @@ -132,6 +126,14 @@ proc nimIncRef(p: pointer) {.compilerRtl, inl.} = when traceCollector: cprintf("[INCREF] %p\n", head(p)) +proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} = + # This is only used by the old RTTI mechanism and we know + # that 'dest[]' is nil and needs no destruction. Which is really handy + # as we cannot destroy the object reliably if it's an object of unknown + # compile-time type. + dest[] = src + if src != nil: nimIncRef src + when not defined(nimscript) and defined(nimArcDebug): proc deallocatedRefId*(p: pointer): int = ## Returns the ref's ID if the ref was already deallocated. This @@ -165,10 +167,10 @@ template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x)) #proc dispose*(x: pointer) = nimRawDispose(x) proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = - let d = cast[ptr PNimType](p)[].destructor + let d = cast[ptr PNimTypeV2](p)[].destructor if d != nil: cast[DestructorProc](d)(p) when false: - cstderr.rawWrite cast[ptr PNimType](p)[].name + cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name cstderr.rawWrite "\n" if d == nil: cstderr.rawWrite "bah, nil\n" @@ -226,11 +228,11 @@ template tearDownForeignThreadGc* = ## With ``--gc:arc`` a nop. discard -proc isObj(obj: PNimType, subclass: cstring): bool {.compilerRtl, inl.} = +proc isObj(obj: PNimTypeV2, subclass: cstring): bool {.compilerRtl, inl.} = proc strstr(s, sub: cstring): cstring {.header: "", importc.} result = strstr(obj.name, subclass) != nil -proc chckObj(obj: PNimType, subclass: cstring) {.compilerRtl.} = +proc chckObj(obj: PNimTypeV2, subclass: cstring) {.compilerRtl.} = # checks if obj is of type subclass: if not isObj(obj, subclass): sysFatal(ObjectConversionDefect, "invalid object conversion") diff --git a/lib/system/assign.nim b/lib/system/assign.nim index ff4ac021e..d332124cd 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +include seqs_v2_reimpl + proc genericResetAux(dest: pointer, n: ptr TNimNode) {.benign.} proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign.} @@ -38,6 +40,20 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, # echo "ugh memory corruption! ", n.kind # quit 1 +template deepSeqAssignImpl(operation, additionalArg) {.dirty.} = + var d = cast[ptr NimSeqV2Reimpl](dest) + var s = cast[ptr NimSeqV2Reimpl](src) + d.len = s.len + let elem = mt.base + d.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(s.len, elem.size, elem.align)) + + let bs = elem.size + let ba = elem.align + let headerSize = align(sizeof(NimSeqPayloadBase), ba) + + for i in 0..d.len-1: + operation(d.p +! (headerSize+i*bs), s.p +! (headerSize+i*bs), mt.base, additionalArg) + proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var d = cast[ByteAddress](dest) @@ -45,38 +61,46 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = sysAssert(mt != nil, "genericAssignAux 2") case mt.kind of tyString: - var x = cast[PPointer](dest) - var s2 = cast[PPointer](s)[] - if s2 == nil or shallow or ( - cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0: - unsureAsgnRef(x, s2) + when defined(nimSeqsV2): + var x = cast[ptr NimStringV2](dest) + var s2 = cast[ptr NimStringV2](s)[] + nimAsgnStrV2(x[], s2) else: - unsureAsgnRef(x, copyString(cast[NimString](s2))) + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] + if s2 == nil or shallow or ( + cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0: + unsureAsgnRef(x, s2) + else: + unsureAsgnRef(x, copyString(cast[NimString](s2))) of tySequence: - var s2 = cast[PPointer](src)[] - var seq = cast[PGenericSeq](s2) - var x = cast[PPointer](dest) - if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0: - # this can happen! nil sequences are allowed - unsureAsgnRef(x, s2) - return - sysAssert(dest != nil, "genericAssignAux 3") - if ntfNoRefs in mt.base.flags: - var ss = nimNewSeqOfCap(mt, seq.len) - cast[PGenericSeq](ss).len = seq.len - unsureAsgnRef(x, ss) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) - copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)), - seq.len *% mt.base.size) + when defined(nimSeqsV2): + deepSeqAssignImpl(genericAssignAux, shallow) else: - unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) - for i in 0..seq.len-1: - genericAssignAux( - cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), - mt.base, shallow) + var s2 = cast[PPointer](src)[] + var seq = cast[PGenericSeq](s2) + var x = cast[PPointer](dest) + if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0: + # this can happen! nil sequences are allowed + unsureAsgnRef(x, s2) + return + sysAssert(dest != nil, "genericAssignAux 3") + if ntfNoRefs in mt.base.flags: + var ss = nimNewSeqOfCap(mt, seq.len) + cast[PGenericSeq](ss).len = seq.len + unsureAsgnRef(x, ss) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) + copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)), + seq.len *% mt.base.size) + else: + unsureAsgnRef(x, newSeq(mt, seq.len)) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) + for i in 0..seq.len-1: + genericAssignAux( + cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), + mt.base, shallow) of tyObject: var it = mt.base # don't use recursion here on the PNimType because the subtype @@ -87,14 +111,19 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = genericAssignAux(dest, src, mt.node, shallow) # we need to copy m_type field for tyObject, as it could be empty for # sequence reallocations: - var pint = cast[ptr PNimType](dest) - # We need to copy the *static* type not the dynamic type: - # if p of TB: - # var tbObj = TB(p) - # tbObj of TC # needs to be false! - #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name) - chckObjAsgn(cast[ptr PNimType](src)[], mt) - pint[] = mt # cast[ptr PNimType](src)[] + when defined(nimSeqsV2): + var pint = cast[ptr PNimTypeV2](dest) + #chckObjAsgn(cast[ptr PNimTypeV2](src)[].typeInfoV2, mt) + pint[] = cast[PNimTypeV2](mt.typeInfoV2) + else: + var pint = cast[ptr PNimType](dest) + # We need to copy the *static* type not the dynamic type: + # if p of TB: + # var tbObj = TB(p) + # tbObj of TC # needs to be false! + #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name) + chckObjAsgn(cast[ptr PNimType](src)[], mt) + pint[] = mt # cast[ptr PNimType](src)[] of tyTuple: genericAssignAux(dest, src, mt.node, shallow) of tyArray, tyArrayConstr: @@ -175,8 +204,12 @@ proc objectInit(dest: pointer, typ: PNimType) = of tyObject: # iterate over any structural type # here we have to init the type field: - var pint = cast[ptr PNimType](dest) - pint[] = typ + when defined(nimSeqsV2): + var pint = cast[ptr PNimTypeV2](dest) + pint[] = cast[PNimTypeV2](typ.typeInfoV2) + else: + var pint = cast[ptr PNimType](dest) + pint[] = typ objectInitAux(dest, typ.node) of tyTuple: objectInitAux(dest, typ.node) @@ -204,15 +237,34 @@ proc genericReset(dest: pointer, mt: PNimType) = var d = cast[ByteAddress](dest) sysAssert(mt != nil, "genericReset 2") case mt.kind - of tyString, tyRef, tySequence: + of tyRef: unsureAsgnRef(cast[PPointer](dest), nil) + of tyString: + when defined(nimSeqsV2): + var s = cast[ptr NimStringV2](dest) + frees(s[]) + zeroMem(dest, mt.size) + else: + unsureAsgnRef(cast[PPointer](dest), nil) + of tySequence: + when defined(nimSeqsV2): + var s = cast[ptr NimSeqV2Reimpl](dest) + if s.p != nil: + deallocShared(s.p) + zeroMem(dest, mt.size) + else: + unsureAsgnRef(cast[PPointer](dest), nil) of tyTuple: genericResetAux(dest, mt.node) of tyObject: genericResetAux(dest, mt.node) # also reset the type field for tyObject, for correct branch switching! - var pint = cast[ptr PNimType](dest) - pint[] = nil + when defined(nimSeqsV2): + var pint = cast[ptr PNimTypeV2](dest) + pint[] = nil + else: + var pint = cast[ptr PNimType](dest) + pint[] = nil of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: genericReset(cast[pointer](d +% i *% mt.base.size), mt.base) diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim index b2ae41d73..fdd9e3099 100644 --- a/lib/system/cellseqs_v2.nim +++ b/lib/system/cellseqs_v2.nim @@ -10,13 +10,13 @@ # Cell seqs for cyclebreaker and cyclicrefs_v2. type - CellTuple = (PT, PNimType) + CellTuple = (PT, PNimTypeV2) CellArray = ptr UncheckedArray[CellTuple] CellSeq = object len, cap: int d: CellArray -proc add(s: var CellSeq, c: PT; t: PNimType) {.inline.} = +proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} = if s.len >= s.cap: s.cap = s.cap * 3 div 2 when defined(useMalloc): @@ -51,6 +51,6 @@ proc deinit(s: var CellSeq) = s.len = 0 s.cap = 0 -proc pop(s: var CellSeq): (PT, PNimType) = +proc pop(s: var CellSeq): (PT, PNimTypeV2) = result = s.d[s.len-1] dec s.len diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim index 3d01eeb9d..c4d802a92 100644 --- a/lib/system/cyclebreaker.nim +++ b/lib/system/cyclebreaker.nim @@ -78,14 +78,14 @@ type GcEnv = object traceStack: CellSeq -proc trace(p: pointer; desc: PNimType; j: var GcEnv) {.inline.} = +proc trace(p: pointer; desc: PNimTypeV2; j: var GcEnv) {.inline.} = when false: cprintf("[Trace] desc: %p %p\n", desc, p) cprintf("[Trace] trace: %p\n", desc.traceImpl) if desc.traceImpl != nil: cast[TraceProc](desc.traceImpl)(p, addr(j)) -proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = +proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} = let p = cast[ptr pointer](q) when traceCollector: cprintf("[Trace] raw: %p\n", p) @@ -101,11 +101,11 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = cprintf("[TraceDyn] deref: %p\n", p[]) if p[] != nil: var j = cast[ptr GcEnv](env) - j.traceStack.add(p, cast[ptr PNimType](p[])[]) + j.traceStack.add(p, cast[ptr PNimTypeV2](p[])[]) var markerGeneration: int -proc breakCycles(s: Cell; desc: PNimType) = +proc breakCycles(s: Cell; desc: PNimTypeV2) = let markerColor = if (markerGeneration and 1) == 0: colRed else: colYellow atomicInc markerGeneration @@ -147,7 +147,7 @@ proc thinout*[T](x: ref T) {.inline.} = ## and thus would keep the graph from being freed are `nil`'ed. ## This is a form of cycle collection that works well with Nim's ARC ## and its associated cost model. - proc getDynamicTypeInfo[T](x: T): PNimType {.magic: "GetTypeInfo", noSideEffect, locks: 0.} + proc getDynamicTypeInfo[T](x: T): PNimTypeV2 {.magic: "GetTypeInfoV2", noSideEffect, locks: 0.} breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[])) @@ -158,7 +158,7 @@ proc thinout*[T: proc](x: T) {.inline.} = """.} let p = rawEnv(x) - breakCycles(head(p), cast[ptr PNimType](p)[]) + breakCycles(head(p), cast[ptr PNimTypeV2](p)[]) proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = if p != nil: @@ -171,7 +171,7 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = # According to Lins it's correct to do nothing else here. #cprintf("[DeCREF] %p\n", p) -proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = +proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} = if p != nil: var cell = head(p) if (cell.rc and not rcMask) == 0: diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 801821d26..5905b5785 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -90,27 +90,35 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = sysAssert(mt != nil, "genericDeepCopyAux 2") case mt.kind of tyString: - var x = cast[PPointer](dest) - var s2 = cast[PPointer](s)[] - if s2 == nil: - unsureAsgnRef(x, s2) + when defined(nimSeqsV2): + var x = cast[ptr NimStringV2](dest) + var s2 = cast[ptr NimStringV2](s)[] + nimAsgnStrV2(x[], s2) else: - unsureAsgnRef(x, copyDeepString(cast[NimString](s2))) + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] + if s2 == nil: + unsureAsgnRef(x, s2) + else: + unsureAsgnRef(x, copyDeepString(cast[NimString](s2))) of tySequence: - var s2 = cast[PPointer](src)[] - var seq = cast[PGenericSeq](s2) - var x = cast[PPointer](dest) - if s2 == nil: - unsureAsgnRef(x, s2) - return - sysAssert(dest != nil, "genericDeepCopyAux 3") - unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) - for i in 0..seq.len-1: - genericDeepCopyAux( - cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - mt.base, tab) + when defined(nimSeqsV2): + deepSeqAssignImpl(genericDeepCopyAux, tab) + else: + var s2 = cast[PPointer](src)[] + var seq = cast[PGenericSeq](s2) + var x = cast[PPointer](dest) + if s2 == nil: + unsureAsgnRef(x, s2) + return + sysAssert(dest != nil, "genericDeepCopyAux 3") + unsureAsgnRef(x, newSeq(mt, seq.len)) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) + for i in 0..seq.len-1: + genericDeepCopyAux( + cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), + cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), + mt.base, tab) of tyObject: # we need to copy m_type field for tyObject, as it could be empty for # sequence reallocations: @@ -151,7 +159,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = sysAssert realType == mt, " types do differ" # this version should work for any possible GC: let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base - let z = newObj(mt, typ.size) + let z = when defined(nimSeqsV2): nimNewObj(typ.size) else: newObj(mt, typ.size) unsureAsgnRef(cast[PPointer](dest), z) tab.put(s2, z) genericDeepCopyAux(z, s2, typ, tab) @@ -168,11 +176,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = copyMem(dest, src, mt.size) proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = - GC_disable() + when not defined(nimSeqsV2): GC_disable() var tab = initPtrTable() genericDeepCopyAux(dest, src, mt, tab) deinit tab - GC_enable() + when not defined(nimSeqsV2): GC_enable() proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = # also invoked for 'string' diff --git a/lib/system/hti.nim b/lib/system/hti.nim index b77f7ccde..3dbcd7615 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -98,6 +98,8 @@ type finalizer*: pointer # the finalizer for the type marker*: proc (p: pointer, op: int) {.nimcall, benign, tags: [], raises: [].} # marker proc for GC deepcopy: proc (p: pointer): pointer {.nimcall, benign, tags: [], raises: [].} + when defined(nimSeqsV2): + typeInfoV2*: pointer when defined(nimTypeNames): name: cstring nextType: ptr TNimType diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 3dad98e93..2ba5c0fec 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -65,8 +65,10 @@ proc growObj(old: pointer, newsize: int): pointer = proc nimGCref(p: pointer) {.compilerproc, inline.} = discard proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard -proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = - dest[] = src +when not defined(gcDestructors): + proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = dest[] = src proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline, diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 7500ba374..4ba462c1f 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -53,7 +53,7 @@ type toFree: CellSeq freed, touched: int -proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} = +proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = if desc.traceImpl != nil: var p = s +! sizeof(RefHeader) cast[TraceProc](desc.traceImpl)(p, addr(j)) @@ -65,7 +65,7 @@ else: let p = s +! sizeof(RefHeader) cprintf("[%s] name %s RC %ld\n", str, p, s.rc shr rcShift) -proc free(s: Cell; desc: PNimType) {.inline.} = +proc free(s: Cell; desc: PNimTypeV2) {.inline.} = when traceCollector: cprintf("[From ] %p rc %ld color %ld\n", s, s.rc shr rcShift, s.color) let p = s +! sizeof(RefHeader) @@ -89,7 +89,7 @@ proc free(s: Cell; desc: PNimType) {.inline.} = nimRawDispose(p) -proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = +proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) @@ -99,7 +99,7 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) - j.traceStack.add(head p[], cast[ptr PNimType](p[])[]) + j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[]) var roots {.threadvar.}: CellSeq @@ -115,7 +115,7 @@ proc unregisterCycle(s: Cell) = roots.d[idx][0].rootIdx = idx dec roots.len -proc scanBlack(s: Cell; desc: PNimType; j: var GcEnv) = +proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ proc scanBlack(s: Cell) = setColor(s, colBlack) @@ -135,7 +135,7 @@ proc scanBlack(s: Cell; desc: PNimType; j: var GcEnv) = t.setColor colBlack trace(t, desc, j) -proc markGray(s: Cell; desc: PNimType; j: var GcEnv) = +proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ proc markGray(s: Cell) = if s.color != colGray: @@ -163,7 +163,7 @@ proc markGray(s: Cell; desc: PNimType; j: var GcEnv) = inc j.touched trace(t, desc, j) -proc scan(s: Cell; desc: PNimType; j: var GcEnv) = +proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ proc scan(s: Cell) = if s.color == colGray: @@ -226,7 +226,7 @@ when false: cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n", msg, s, s.rootIdx, s.rc shr rcShift, s.color) -proc collectWhite(s: Cell; desc: PNimType; j: var GcEnv) = +proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ proc collectWhite(s: Cell) = if s.color == colWhite and not buffered(s): @@ -315,7 +315,7 @@ proc collectCycles() = when false: cfprintf(cstderr, "[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold) -proc registerCycle(s: Cell; desc: PNimType) = +proc registerCycle(s: Cell; desc: PNimTypeV2) = if roots.len >= rootsThreshold: collectCycles() if roots.d == nil: init(roots) @@ -334,7 +334,7 @@ proc GC_enableMarkAndSweep() = proc GC_disableMarkAndSweep() = rootsThreshold = high(int) -proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimType) {.noinline.} = +proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = if isDestroyAction: if (s.rc and isCycleCandidate) != 0: s.rc = s.rc and not isCycleCandidate @@ -356,9 +356,9 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = else: dec cell.rc, rcIncrement #if cell.color == colPurple: - rememberCycle(result, cell, cast[ptr PNimType](p)[]) + rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[]) -proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = +proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} = if p != nil: var cell = head(p) if (cell.rc and not rcMask) == 0: diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 3c94a03f9..111299fff 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -22,7 +22,8 @@ type cap: int data: UncheckedArray[T] - NimSeqV2*[T] = object + NimSeqV2*[T] = object # \ + # if you change this implementation, also change seqs_v2_reimpl.nim! len: int p: ptr NimSeqPayload[T] @@ -40,12 +41,15 @@ proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises else: result = nil -proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. - noSideEffect, raises: [].} = - {.noSideEffect.}: - template `+!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) +% s) +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) +template `-!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) -% s) + +proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. + noSideEffect, raises: [], compilerRtl.} = + {.noSideEffect.}: let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign) if addlen <= 0: result = p diff --git a/lib/system/seqs_v2_reimpl.nim b/lib/system/seqs_v2_reimpl.nim new file mode 100644 index 000000000..750f78c0d --- /dev/null +++ b/lib/system/seqs_v2_reimpl.nim @@ -0,0 +1,17 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +type + NimSeqPayloadReimpl = object + cap: int + data: pointer + + NimSeqV2Reimpl = object + len: int + p: ptr NimSeqPayloadReimpl diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index 118d0ae02..fc5703a03 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -14,7 +14,7 @@ joinable: false pending https://github.com/nim-lang/Nim/issues/9754 import marshal -template testit(x) = discard $$to[type(x)]($$x) +template testit(x) = discard $$to[typeof(x)]($$x) var x: array[0..4, array[0..4, string]] = [ ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], @@ -89,8 +89,8 @@ var instance1 = Person(name: "Cletus", age: 12, bio: "Я Cletus", blob: "ABC\x80") echo($$instance1) -echo(to[Person]($$instance1).bio == instance1.bio) -echo(to[Person]($$instance1).blob == instance1.blob) +echo(to[Person]($$instance1).bio == instance1.bio) # true +echo(to[Person]($$instance1).blob == instance1.blob) # true # bug 5757 From de7f2372be770ca97f3f63dcc9447bdd2827f9d0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 16 Sep 2020 20:58:50 +0800 Subject: [PATCH 1098/4254] docs minor and #15335 (#15337) --- lib/pure/collections/sequtils.nim | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 51d8ade85..d8ea3ad1f 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -809,10 +809,17 @@ template foldl*(sequence, operation: untyped): untyped = multiplication = foldl(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldl(words, a & b) + procs = @["proc", "Is", "Also", "Fine"] + + + proc foo(acc, cur: string): string = + result = acc & cur + assert addition == 25, "Addition is (((5)+9)+11)" assert subtraction == -15, "Subtraction is (((5)-9)-11)" assert multiplication == 495, "Multiplication is (((5)*9)*11)" assert concatenation == "nimiscool" + assert foldl(procs, foo(a, b)) == "procIsAlsoFine" let s = sequence assert s.len > 0, "Can't fold empty sequences" From ae4ede6b009632bd0d809c61066b240e8ee7719a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 16 Sep 2020 17:26:13 +0200 Subject: [PATCH 1099/4254] fixes #15325 (#15340) --- compiler/commands.nim | 3 + compiler/injectdestructors.nim | 3 +- compiler/options.nim | 3 +- compiler/varpartitions.nim | 13 ++- tests/arc/tcursor_on_localvar.nim | 126 ++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 tests/arc/tcursor_on_localvar.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 0af31b2c7..a76a5be73 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -891,6 +891,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optProfileVM}, arg, pass, info) of "sinkinference": processOnOffSwitch(conf, {optSinkInference}, arg, pass, info) + of "cursorinference": + # undocumented, for debugging purposes only: + processOnOffSwitch(conf, {optCursorInference}, arg, pass, info) of "panics": processOnOffSwitchG(conf, {optPanics}, arg, pass, info) if optPanics in conf.globalOptions: diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b8b8e776e..9d1f43595 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1006,7 +1006,8 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = echoCfg(c.g) echo n - computeCursors(owner, n, g.config) + if optCursorInference in g.config.options: + computeCursors(owner, n, g.config) var scope: Scope let body = p(n, c, scope, normal) diff --git a/compiler/options.nim b/compiler/options.nim index 03418d953..226f13c73 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -41,6 +41,7 @@ type # please make sure we have under 32 options optMemTracker, optNilSeqs, optSinkInference # 'sink T' inference + optCursorInference TOptions* = set[TOption] @@ -372,7 +373,7 @@ const DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` - optTrMacros, optStyleCheck} + optTrMacros, optStyleCheck, optCursorInference} DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, optListFullPaths} diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 87424c4be..743c4d55d 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -392,9 +392,18 @@ proc deps(c: var Partitions; dest, src: PNode) = analyseAsgn(c, c.s[vid], src) # do not borrow from a different local variable, this is easier # than tracking reassignments, consider 'var cursor = local; local = newNode()' - if src.kind == nkSym and (src.sym.kind in {skVar, skResult, skTemp} or + if src.kind == nkSym: + if (src.sym.kind in {skVar, skResult, skTemp} or (src.sym.kind in {skLet, skParam, skForVar} and hasDisabledAsgn(src.sym.typ))): - c.s[vid].flags.incl preventCursor + c.s[vid].flags.incl preventCursor + elif src.sym.kind in {skVar, skResult, skTemp, skLet, skForVar}: + # XXX: we need to compute variable alive ranges before doing anything else: + let srcid = variableId(c, src.sym) + if srcid >= 0 and preventCursor in c.s[srcid].flags: + # you cannot borrow from a local that lives shorter than 'vid': + if c.s[srcid].aliveStart > c.s[vid].aliveStart or + c.s[srcid].aliveEnd < c.s[vid].aliveEnd: + c.s[vid].flags.incl preventCursor if src.kind == nkSym and hasDestructor(src.typ): rhsIsSink(c, src) diff --git a/tests/arc/tcursor_on_localvar.nim b/tests/arc/tcursor_on_localvar.nim new file mode 100644 index 000000000..81b48271f --- /dev/null +++ b/tests/arc/tcursor_on_localvar.nim @@ -0,0 +1,126 @@ +discard """ + output: '''Section: common + Param: Floats1 +Section: local + Param: Str + Param: Bool + Param: Floats2''' + cmd: '''nim c --gc:arc $file''' +""" + +# bug #15325 + +import tables +import strutils + +const defaultSection = "***" + +type + Config* = ref object + table: OrderedTableRef[string, OrderedTable[string, string]] + +# ---------------------------------------------------------------------------------------------------------------------- +proc newConfig*(): Config = + result = new(Config) + result.table = newOrderedTable[string, OrderedTable[string, string]]() + +# ---------------------------------------------------------------------------------------------------------------------- +proc add*(self: Config, param, value, section: string) {.nosinks.} = + let s = if section == "": defaultSection else: section + + if not self.table.contains(s): + self.table[s] = initOrderedTable[string, string]() + + self.table[s][param] = value + +# ---------------------------------------------------------------------------------------------------------------------- +proc sections*(self: Config): seq[string] = + for i in self.table.keys: + let s = if i == defaultSection: "" else: i + result.add(s) + +# ---------------------------------------------------------------------------------------------------------------------- +proc params*(self: Config, section: string): seq[string] = + let s = if section == "": defaultSection else: section + + if self.table.contains(s): + for i in self.table[s].keys: + result.add(i) + +# ---------------------------------------------------------------------------------------------------------------------- +proc extract*(str, start, finish: string): string = + let startPos = str.find(start) + + if startPos < 0: + return "" + + let endPos = str.find(finish, startPos) + + if endPos < 0: + return "" + + return str[startPos + start.len() ..< endPos] + +# ---------------------------------------------------------------------------------------------------------------------- +proc loadString*(self: Config, text: string): tuple[valid: bool, errorInLine: int] {.discardable.} = + self.table.clear() + + var data = "" + + data = text + + var + actualSection = "" + lineCount = 0 + + for i in splitLines(data): + lineCount += 1 + + var line = strip(i) + + if line.len() == 0: + continue + + if line[0] == '#' or line[0] == ';': + continue + + if line[0] == '[': + let section = strip(extract(line, "[", "]")) + + if section.len() != 0: + actualSection = section + else: + self.table.clear() + return (false, lineCount) + else: + let equal = find(line, '=') + + if equal <= 0: + self.table.clear() + return (false, lineCount) + else: + let + param = strip(line[0 .. equal - 1]) + value = strip(line[equal + 1 .. ^1]) + + if param.len() == 0: + self.table.clear() + return (false, lineCount) + else: + self.add(param, value, actualSection) + + return (true, 0) + +# ---------------------------------------------------------------------------------------------------------------------- +when isMainModule: + var cfg = newConfig() + + cfg.loadString("[common]\nFloats1 = 1,2,3\n[local]\nStr = \"String...\"\nBool = true\nFloats2 = 4, 5, 6\n") + + for s in cfg.sections(): + echo "Section: " & s + + for p in cfg.params(s): + echo " Param: " & p + + From a3e9cc52343a54cadc7b77b783e1c8b6ba2b327f Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 16 Sep 2020 16:26:45 +0100 Subject: [PATCH 1100/4254] Introduce explicit copy (#15330) --- compiler/injectdestructors.nim | 2 +- lib/system.nim | 5 +++++ tests/arc/tcopytosink_warning.nim | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/arc/tcopytosink_warning.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 9d1f43595..de28c9f70 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -408,7 +408,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & - "if possible, rearrange your program's control flow to prevent it") % $n) + "if possible, rearrange your program's control flow to prevent it or use 'copy($1)' to hint the compiler it is intentional") % $n) else: if c.graph.config.selectedGC in {gcArc, gcOrc}: assert(not containsGarbageCollectedRef(n.typ)) diff --git a/lib/system.nim b/lib/system.nim index c05ca24dc..dbe0f11f7 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -264,6 +264,11 @@ proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = result = x wasMoved(x) +func copy*[T](x: T): T {.inline.} = + ## make explicit copy of the argument `x`, used to signal to the compiler + ## the copy is intentional + result = x + type range*[T]{.magic: "Range".} ## Generic type to construct range types. array*[I, T]{.magic: "Array".} ## Generic type to construct diff --git a/tests/arc/tcopytosink_warning.nim b/tests/arc/tcopytosink_warning.nim new file mode 100644 index 000000000..8ae36386a --- /dev/null +++ b/tests/arc/tcopytosink_warning.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim c --gc:arc $file" + nimout: '''tcopytosink_warning.nim(17, 7) Hint: myhint [User] +tcopytosink_warning.nim(19, 9) Hint: passing 'x' to a sink parameter introduces an implicit copy; if possible, rearrange your program's control flow to prevent it or use 'copy(x)' to hint the compiler it is intentional [Performance] +''' + output: "x" +""" +import macros + +proc test(v: var seq[string], x: sink string) = + v.add x + +var v = @["a", "b", "c"] +var x = "x" + +static: + hint("myhint") +test(v, copy(x)) # no warning +test(v, x) # produces warning + +echo x # use after sink + From 341be0b61cc0603dc921c99b891208dcda274c98 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 16 Sep 2020 17:25:24 +0100 Subject: [PATCH 1101/4254] proc params as syms (#15332) * proc params are now syms * Fix typesrenderer * Add testcase for disrupteks issue * fix test * Trigger build * Trigger build * Trigger build Co-authored-by: Clyybber --- compiler/semtypes.nim | 1 + compiler/typesrenderer.nim | 2 +- lib/js/jsffi.nim | 10 +++++++++- tests/macros/tmacros_various.nim | 8 ++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 953801431..d85008342 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1286,6 +1286,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, addParamOrResult(c, arg, kind) styleCheckDef(c.config, a[j].info, arg) onDef(a[j].info, arg) + a[j] = newSymNode(arg) var r: PType if n[0].kind != nkEmpty: diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 60f9f6603..050a057f4 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -67,7 +67,7 @@ proc renderType(n: PNode): string = let typeStr = renderType(n[typePos]) result = typeStr for i in 1.. Date: Wed, 16 Sep 2020 19:41:14 +0200 Subject: [PATCH 1102/4254] fixes #9754 [backport] (#15342) --- lib/core/typeinfo.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index b1b9bcb27..9fd8ebf8c 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -327,10 +327,7 @@ proc setPointer*(x: Any, y: pointer) = ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. assert x.rawType.kind in pointerLike - when defined(gcDestructors): - genericAssign(x.value, y, x.rawType) - else: - cast[ppointer](x.value)[] = y + genericAssign(x.value, y, x.rawType) proc fieldsAux(p: pointer, n: ptr TNimNode, ret: var seq[tuple[name: cstring, any: Any]]) = From 28a64869f0a5b96ee491a2a4210461709d4800fa Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 16 Sep 2020 20:41:57 +0300 Subject: [PATCH 1103/4254] Fixed undeclared nimIdentNormalize compilation error in parseEnum (#15343) --- lib/pure/strutils.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 20010ff81..156929dee 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1294,8 +1294,7 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = let typ = typ.getTypeInst[1] let impl = typ.getImpl[2] expectKind impl, nnkEnumTy - result = nnkCaseStmt.newTree(nnkDotExpr.newTree(argSym, - bindSym"nimIdentNormalize")) + result = nnkCaseStmt.newTree(newCall(bindSym"nimIdentNormalize", argSym)) # stores all processed field strings to give error msg for ambiguous enums var foundFields: seq[string] = @[] var fStr = "" # string of current field From 913ffbb92d0f0b9c5e7cf3fcbb446c38e890680e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 16 Sep 2020 16:31:35 -0300 Subject: [PATCH 1104/4254] Add documentation for Testament (#15344) --- doc/testament.rst | 187 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 doc/testament.rst diff --git a/doc/testament.rst b/doc/testament.rst new file mode 100644 index 000000000..82dfb75bd --- /dev/null +++ b/doc/testament.rst @@ -0,0 +1,187 @@ +Testament is an advanced automatic unittests runner for Nim tests, is used for the development of Nim itself, +offers process isolation for your tests, it can generate statistics about test cases, +supports multiple targets (C, C++, ObjectiveC, JavaScript, etc), +simulated `Dry-Runs `_, +has logging, can generate HTML reports, skip tests from a file and more, +so can be useful to run your tests, even the most complex ones. + + +Test files location +=================== + +By default Testament looks for test files on ``"./tests/*.nim"``, +you can overwrite this pattern glob using ``pattern ``, +the default working directory path can be changed using ``--directory:"folder/subfolder/"``. + +Testament uses the nim compiler on ``PATH`` you can change that using ``--nim:"folder/subfolder/nim"``, +running JavaScript tests with ``--targets:"js"`` requires a working NodeJS on ``PATH``. + + +Options +======= + +* ``--print`` Also print results to the console +* ``--simulate`` See what tests would be run but don't run them (for debugging) +* ``--failing`` Only show failing/ignored tests +* ``--targets:"c c++ js objc"`` Run tests for specified targets (default: all) +* ``--nim:path`` Use a particular nim executable (default: ``$PATH/nim``) +* ``--directory:dir`` Change to directory dir before reading the tests or doing anything else. +* ``--colors:on|off`` Turn messages coloring on|off. +* ``--backendLogging:on|off`` Disable or enable backend logging. By default turned on. +* ``--skipFrom:file`` Read tests to skip from ``file`` - one test per line, # comments ignored + + +Running a single test +===================== + +This is a minimal example to understand the basics, +not very useful for production, but easy to understand: + +.. code:: + + $ mkdir tests + $ echo "assert 42 == 42" > tests/test0.nim + $ testament run test0.nim + PASS: tests/test0.nim C ( 0.2 sec) + + $ testament r test0 + PASS: tests/test0.nim C ( 0.2 sec) + + $ + + +Running all tests from a directory +================================== + +.. code:: + + $ testament pattern "tests/*.nim" + + +HTML Reports +============ + +Generate HTML Reports ``testresults.html`` from unittests, +you have to run at least 1 test *before* generating a report: + +.. code:: + + $ testament html + + +Writing Unitests +================ + +Example "template" **to edit** and write a Testament unittest: + +.. code-block:: nim + + discard """ + + action: "run" # What to do, one of "compile" OR "run". + + exitcode: 0 # This is the Exit Code the test should return, zero typically. + + output: "" # This is the Standard Output the test should print, if any. + + input: "" # This is the Standard Input the test should take, if any. + + errormsg: "" # Error message the test should print, if any. + + batchable: true # Can be run in batch mode, or not. + + joinable: true # Can be run Joined with other tests to run all togheter, or not. + + valgrind: false # Can use Valgrind to check for memory leaks, or not (Linux 64Bit only). + + cmd: "c -r $file" # Command the test should use to run. + + maxcodesize: 666 # Maximum generated temporary intermediate code file size for the test. + + timeout: 666 # Timeout microseconds to run the test. + + target: "c js" # Targets to run the test into (C, C++, JavaScript, etc). + + disabled: "bsd" # Disable the test by condition, here BSD is disabled just as an example. + + """ + assert true + assert 42 == 42, "Assert error message" + + +* As you can see the "Spec" is just a ``discard """ """``. +* Spec has sane defaults, so you dont need to provide them all, any simple assert will work Ok. +* `This is not the full spec of Testament, check the Testament Spec on GitHub, see parseSpec(). `_ +* `Nim itself uses Testament, so theres plenty of test examples. `_ +* Has some built-in CI compatibility, like Azure Pipelines, etc. +* `Testament supports inlined error messages on Unittests, basically comments with the expected error directly on the code. `_ + + +Unitests Examples +================= + +Expected to fail: + +.. code-block:: nim + + discard """ + errormsg: "undeclared identifier: 'not_defined'" + """ + assert not_defined == "not_defined", "not_defined is not defined" + +Non-Zero exit code: + +.. code-block:: nim + + discard """ + exitcode: 1 + """ + quit "Non-Zero exit code", 1 + +Standard output checking: + +.. code-block:: nim + + discard """ + + output: ''' + 0 + 1 + 2 + 3 + 4 + 5 + ''' + + """ + for i in 0..5: echo i + +JavaScript tests: + +.. code-block:: nim + + discard """ + target: "js" + """ + when defined(js): + import jsconsole + console.log("My Frontend Project") + +Compile time tests: + +.. code-block:: nim + + discard """ + action: "compile" + """ + static: assert 9 == 9, "Compile time assert" + +Tests without Spec: + +.. code-block:: nim + + assert 1 == 1 + + +See also: +* `Unittest `_ From d938c6411e399ee1c936fa7b9ee3a1b53ab65791 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 16 Sep 2020 20:37:23 +0100 Subject: [PATCH 1105/4254] fix #15326 (#15341) --- compiler/semtypes.nim | 118 +++++++++++++++++++++------------------ tests/macros/tmacro2.nim | 8 +++ 2 files changed, 71 insertions(+), 55 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d85008342..4d912a46f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2055,72 +2055,80 @@ proc semGenericConstraints(c: PContext, x: PType): PType = result = newTypeWithSons(c, tyGenericParam, @[x]) proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = + + template addSym(result: PNode, s: PSym): untyped = + if father != nil: addSonSkipIntLit(father, s.typ) + if sfGenSym notin s.flags: addDecl(c, s) + result.add newSymNode(s) + result = copyNode(n) if n.kind != nkGenericParams: illFormedAst(n, c.config) return for i in 0.. Date: Wed, 16 Sep 2020 23:24:17 +0200 Subject: [PATCH 1106/4254] Revert "Introduce explicit copy (#15330)" (#15346) This reverts commit a3e9cc52343a54cadc7b77b783e1c8b6ba2b327f. --- compiler/injectdestructors.nim | 2 +- lib/system.nim | 5 ----- tests/arc/tcopytosink_warning.nim | 22 ---------------------- 3 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 tests/arc/tcopytosink_warning.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index de28c9f70..9d1f43595 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -408,7 +408,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & - "if possible, rearrange your program's control flow to prevent it or use 'copy($1)' to hint the compiler it is intentional") % $n) + "if possible, rearrange your program's control flow to prevent it") % $n) else: if c.graph.config.selectedGC in {gcArc, gcOrc}: assert(not containsGarbageCollectedRef(n.typ)) diff --git a/lib/system.nim b/lib/system.nim index dbe0f11f7..c05ca24dc 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -264,11 +264,6 @@ proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = result = x wasMoved(x) -func copy*[T](x: T): T {.inline.} = - ## make explicit copy of the argument `x`, used to signal to the compiler - ## the copy is intentional - result = x - type range*[T]{.magic: "Range".} ## Generic type to construct range types. array*[I, T]{.magic: "Array".} ## Generic type to construct diff --git a/tests/arc/tcopytosink_warning.nim b/tests/arc/tcopytosink_warning.nim deleted file mode 100644 index 8ae36386a..000000000 --- a/tests/arc/tcopytosink_warning.nim +++ /dev/null @@ -1,22 +0,0 @@ -discard """ - cmd: "nim c --gc:arc $file" - nimout: '''tcopytosink_warning.nim(17, 7) Hint: myhint [User] -tcopytosink_warning.nim(19, 9) Hint: passing 'x' to a sink parameter introduces an implicit copy; if possible, rearrange your program's control flow to prevent it or use 'copy(x)' to hint the compiler it is intentional [Performance] -''' - output: "x" -""" -import macros - -proc test(v: var seq[string], x: sink string) = - v.add x - -var v = @["a", "b", "c"] -var x = "x" - -static: - hint("myhint") -test(v, copy(x)) # no warning -test(v, x) # produces warning - -echo x # use after sink - From cbd78ec1f68e78a88e4a83a5009bc4c8c28c79b3 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 17 Sep 2020 19:55:18 +0200 Subject: [PATCH 1107/4254] close #6071, remove the mentions of deprecated `docSeeSrcUrl` (#15350) --- config/nimdoc.cfg | 4 ++-- doc/docgen.rst | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 3560c0d65..9a56fdaae 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -55,13 +55,13 @@ doc.item.toc = """ """ # HTML rendered for doc.item's seeSrc variable. Note that this will render to -# the empty string if you don't pass anything through --docSeeSrcURL. Available +# the empty string if you don't pass anything through --git.url. Available # substitutaion variables here are: # * $commit: branch/commit to use in source link. # * $devel: branch to use in edit link. # * $path: relative path to the file being processed. # * $line: line of the item in the original source file. -# * $url: whatever you did pass through the --docSeeSrcUrl switch (which also +# * $url: whatever you did pass through the --git.url switch (which also # gets variables path/line replaced!) doc.item.seesrc = """   filename.nim @@ -345,9 +343,8 @@ but can have up to four (additional columns are ignored). The content of these columns is: 1. Mandatory term being indexed. Terms can include quoting according to - Nim's rules (eg. \`^\`). -2. Base filename plus anchor hyperlink (eg. - ``algorithm.html#*,int,SortOrder``). + Nim's rules (e.g. \`^\`). +2. Base filename plus anchor hyperlink (e.g. ``algorithm.html#*,int,SortOrder``). 3. Optional human readable string to display as hyperlink. If the value is not present or is the empty string, the hyperlink will be rendered using the term. Prefix whitespace indicates that this entry is From c57023f3241e99910d44e91330a381e41193047f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 18 Sep 2020 16:02:31 +0800 Subject: [PATCH 1108/4254] string is not nil anymore (#15352) --- lib/pure/collections/critbits.nim | 5 +---- lib/pure/strtabs.nim | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 91c113988..d25e31d66 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -281,10 +281,7 @@ proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = template get[T](c: CritBitTree[T], key: string): T = let n = rawGet(c, key) if n == nil: - when compiles($key): - raise newException(KeyError, "key not found: " & $key) - else: - raise newException(KeyError, "key not found") + raise newException(KeyError, "key not found: " & key) n.val diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 864db148f..d9f6bbc54 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -141,10 +141,8 @@ template get(t: StringTableRef, key: string) = var index = rawGet(t, key) if index >= 0: result = t.data[index].val else: - when compiles($key): - raise newException(KeyError, "key not found: " & $key) - else: - raise newException(KeyError, "key not found") + raise newException(KeyError, "key not found: " & key) + proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} = ## Returns the number of keys in `t`. From e56d50d747451ea222617902ff70f31b4bb3123c Mon Sep 17 00:00:00 2001 From: jcosborn Date: Fri, 18 Sep 2020 04:21:37 -0500 Subject: [PATCH 1109/4254] fix infinite recursion in typeRel (#15241) * fix generic constraints Co-authored-by: James Osborn --- compiler/sigmatch.nim | 115 ++++++++++++++------------- tests/overload/toverload_various.nim | 45 +++++++++++ 2 files changed, 104 insertions(+), 56 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 95231744c..1441203e8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -82,6 +82,7 @@ type TTypeRelFlag* = enum trDontBind trNoCovariance + trBindGenericParam # bind tyGenericParam even with trDontBind TTypeRelFlags* = set[TTypeRelFlag] @@ -1034,7 +1035,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if aOrig.kind == tyInferred: let prev = aOrig.previouslyInferred if prev != nil: - return typeRel(c, f, prev) + return typeRel(c, f, prev, flags) else: var candidate = f @@ -1055,7 +1056,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: discard - result = typeRel(c, aOrig.base, candidate) + result = typeRel(c, aOrig.base, candidate, flags) if result != isNone: c.inferredTypes.add aOrig aOrig.add candidate @@ -1072,16 +1073,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # situation when nkDotExpr are rotated to nkDotCalls if aOrig.kind in {tyAlias, tySink}: - return typeRel(c, f, lastSon(aOrig)) + return typeRel(c, f, lastSon(aOrig), flags) if a.kind == tyGenericInst and skipTypes(f, {tyVar, tyLent, tySink}).kind notin { tyGenericBody, tyGenericInvocation, tyGenericInst, tyGenericParam} + tyTypeClasses: - return typeRel(c, f, lastSon(a)) + return typeRel(c, f, lastSon(a), flags) if a.isResolvedUserTypeClass: - return typeRel(c, f, a.lastSon) + return typeRel(c, f, a.lastSon, flags) template bindingRet(res) = if doBind: @@ -1092,7 +1093,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, template considerPreviousT(body: untyped) = var prev = PType(idTableGet(c.bindings, f)) if prev == nil: body - else: return typeRel(c, prev, a) + else: return typeRel(c, prev, a, flags) case a.kind of tyOr: @@ -1126,7 +1127,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # seq[float] matches the first, but not the second # we must turn the problem around: # is number a subset of int? - return typeRel(c, a.lastSon, f.lastSon) + return typeRel(c, a.lastSon, f.lastSon, flags) else: # negative type classes are essentially infinite, @@ -1158,7 +1159,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyRange: if a.kind == f.kind: if f.base.kind == tyNone: return isGeneric - result = typeRel(c, base(f), base(a)) + result = typeRel(c, base(f), base(a), flags) # bugfix: accept integer conversions here #if result < isGeneric: result = isNone if result notin {isNone, isGeneric}: @@ -1189,7 +1190,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyFloat64: result = handleFloatRange(f, a) of tyFloat128: result = handleFloatRange(f, a) of tyVar, tyLent: - if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base) + if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base, flags) else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance}) subtypeCheck() of tyArray: @@ -1211,7 +1212,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if f[0].kind != tyGenericParam and aa.kind == tyEmpty: result = isGeneric else: - result = typeRel(c, ff, aa) + result = typeRel(c, ff, aa, flags) if result < isGeneric: if nimEnableCovariance and @@ -1232,7 +1233,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: discard of tyUncheckedArray: if a.kind == tyUncheckedArray: - result = typeRel(c, base(f), base(a)) + result = typeRel(c, base(f), base(a), flags) if result < isGeneric: result = isNone else: discard of tyOpenArray, tyVarargs: @@ -1240,13 +1241,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # handle varargs[stmt] which is the same as varargs[typed]: if f.kind == tyVarargs: if tfVarargs in a.flags: - return typeRel(c, f.base, a.lastSon) + return typeRel(c, f.base, a.lastSon, flags) if f[0].kind == tyTyped: return template matchArrayOrSeq(aBase: PType) = let ff = f.base let aa = aBase - let baseRel = typeRel(c, ff, aa) + let baseRel = typeRel(c, ff, aa, flags) if baseRel >= isGeneric: result = isConvertible elif nimEnableCovariance and @@ -1257,7 +1258,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, case a.kind of tyOpenArray, tyVarargs: - result = typeRel(c, base(f), base(a)) + result = typeRel(c, base(f), base(a), flags) if result < isGeneric: result = isNone of tyArray: if (f[0].kind != tyGenericParam) and (a[1].kind == tyEmpty): @@ -1272,7 +1273,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if f[0].kind == tyChar: result = isConvertible elif f[0].kind == tyGenericParam and a.len > 0 and - typeRel(c, base(f), base(a)) >= isGeneric: + typeRel(c, base(f), base(a), flags) >= isGeneric: result = isConvertible else: discard of tySequence: @@ -1283,7 +1284,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: let ff = f[0] let aa = a[0] - result = typeRel(c, ff, aa) + result = typeRel(c, ff, aa, flags) if result < isGeneric: if nimEnableCovariance and trNoCovariance notin flags and @@ -1302,7 +1303,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if f[0].kind == tyNone: result = isGeneric else: - result = typeRel(c, f[0], x) + result = typeRel(c, f[0], x, flags) if result < isGeneric: result = isNone elif a.kind == tyGenericParam: result = isGeneric @@ -1329,16 +1330,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if a.kind == tyDistinct: if sameDistinctTypes(f, a): result = isEqual #elif f.base.kind == tyAnything: result = isGeneric # issue 4435 - elif c.coerceDistincts: result = typeRel(c, f.base, a) + elif c.coerceDistincts: result = typeRel(c, f.base, a, flags) elif a.kind == tyNil and f.base.kind in NilableTypes: result = f.allowsNil # XXX remove this typing rule, it is not in the spec - elif c.coerceDistincts: result = typeRel(c, f.base, a) + elif c.coerceDistincts: result = typeRel(c, f.base, a, flags) of tySet: if a.kind == tySet: if f[0].kind != tyGenericParam and a[0].kind == tyEmpty: result = isSubtype else: - result = typeRel(c, f[0], a[0]) + result = typeRel(c, f[0], a[0], flags) if result <= isConvertible: result = isNone # BUGFIX! of tyPtr, tyRef: @@ -1347,7 +1348,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # ptr[R, T] can be passed to ptr[T], but not the other way round: if a.len < f.len: return isNone for i in 0.. isGeneric: result = isGeneric elif c.isNoCall: - if doBind: + if doBindGP: let concrete = concreteType(c, a, f) if concrete == nil: return isNone put(c, f, concrete) @@ -1700,8 +1702,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)' if f.len > 0 and f[0].kind != tyNone: let oldInheritancePenalty = c.inheritancePenalty - result = typeRel(c, f[0], a, flags + {trDontBind}) - if doBind and result notin {isNone, isGeneric}: + result = typeRel(c, f[0], a, flags + {trDontBind,trBindGenericParam}) + if doBindGP and result notin {isNone, isGeneric}: let concrete = concreteType(c, a, f) if concrete == nil: return isNone put(c, f, concrete) @@ -1729,7 +1731,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, concrete = concreteType(c, a, f) if concrete == nil: return isNone - if doBind: + if doBindGP: put(c, f, concrete) elif result > isGeneric: result = isGeneric @@ -1738,14 +1740,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, elif x.kind == tyGenericParam: result = isGeneric else: - result = typeRel(c, x, a) # check if it fits + result = typeRel(c, x, a, flags) # check if it fits if result > isGeneric: result = isGeneric of tyStatic: let prev = PType(idTableGet(c.bindings, f)) if prev == nil: if aOrig.kind == tyStatic: if f.base.kind != tyNone: - result = typeRel(c, f.base, a) + result = typeRel(c, f.base, a, flags) if result != isNone and f.n != nil: if not exprStructuralEquivalent(f.n, aOrig.n): result = isNone @@ -1753,7 +1755,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isGeneric if result != isNone: put(c, f, aOrig) elif aOrig.n != nil and aOrig.n.typ != nil: - result = if f.base.kind != tyNone: typeRel(c, f.lastSon, aOrig.n.typ) + result = if f.base.kind != tyNone: + typeRel(c, f.lastSon, aOrig.n.typ, flags) else: isGeneric if result != isNone: var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ]) @@ -1763,22 +1766,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNone elif prev.kind == tyStatic: if aOrig.kind == tyStatic: - result = typeRel(c, prev.lastSon, a) + result = typeRel(c, prev.lastSon, a, flags) if result != isNone and prev.n != nil: if not exprStructuralEquivalent(prev.n, aOrig.n): result = isNone else: result = isNone else: # XXX endless recursion? - #result = typeRel(c, prev, aOrig) + #result = typeRel(c, prev, aOrig, flags) result = isNone of tyInferred: let prev = f.previouslyInferred if prev != nil: - result = typeRel(c, prev, a) + result = typeRel(c, prev, a, flags) else: - result = typeRel(c, f.base, a) + result = typeRel(c, f.base, a, flags) if result != isNone: c.inferredTypes.add f f.add a @@ -1798,15 +1801,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, elif f.base.kind == tyNone: result = isGeneric else: - result = typeRel(c, f.base, a.base) + result = typeRel(c, f.base, a.base, flags) if result != isNone: put(c, f, a) else: if tfUnresolved in f.flags: - result = typeRel(c, prev.base, a) + result = typeRel(c, prev.base, a, flags) elif a.kind == tyTypeDesc: - result = typeRel(c, prev.base, a.base) + result = typeRel(c, prev.base, a.base, flags) else: result = isNone @@ -1824,15 +1827,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let reevaluated = tryResolvingStaticExpr(c, f.n) case reevaluated.typ.kind of tyTypeDesc: - result = typeRel(c, a, reevaluated.typ.base) + result = typeRel(c, a, reevaluated.typ.base, flags) of tyStatic: - result = typeRel(c, a, reevaluated.typ.base) + result = typeRel(c, a, reevaluated.typ.base, flags) if result != isNone and reevaluated.typ.n != nil: if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): result = isNone else: # bug #14136: other types are just like 'tyStatic' here: - result = typeRel(c, a, reevaluated.typ) + result = typeRel(c, a, reevaluated.typ, flags) if result != isNone and reevaluated.typ.n != nil: if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): result = isNone diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 132c3be4b..f913ce3ee 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -425,6 +425,7 @@ block: template t0(x: Bar[int]): int = 1 template t0(x: Foo[bool or int]): int = 10 template t0(x: Bar[bool or int]): int = 11 + #template t0[T:bool or int](x: Bar[T]): int = 11 template t0[T](x: Foo[T]): int = 20 template t0[T](x: Bar[T]): int = 21 proc p0(x: Foo[int]): int = 0 @@ -461,3 +462,47 @@ block: doAssert(p0(g) == 20) doAssert(p0(h) == 21) doAssert(p0(i) == 21) + + #type + # f0 = proc(x:Foo) + + +block: + type + TilesetCT[n: static[int]] = distinct int + TilesetRT = int + Tileset = TilesetCT | TilesetRT + + func prepareTileset(tileset: var Tileset) = discard + + func prepareTileset(tileset: Tileset): Tileset = + result = tileset + result.prepareTileset + + var parsedTileset: TilesetRT + prepareTileset(parsedTileset) + + +block: + proc p1[T,U: SomeInteger|SomeFloat](x: T, y: U): int|float = + when T is SomeInteger and U is SomeInteger: + result = int(x) + int(y) + else: + result = float(x) + float(y) + doAssert(p1(1,2) == 3) + doAssert(p1(1.0,2) == 3.0) + doAssert(p1(1,2.0) == 3.0) + doAssert(p1(1.0,2.0) == 3.0) + + type Foo[T,U] = U + template F[T,U](t: typedesc[T], x: U): untyped = Foo[T,U](x) + proc p2[T; U,V:Foo[T,SomeNumber]](x: U, y: V): T = + T(x) + T(y) + #proc p2[T; U:Foo[T,SomeNumber], V:Foo[not T,SomeNumber]](x: U, y: V): T = + # T(x) + T(y) + doAssert(p2(F(int,1),F(int,2)) == 3) + doAssert(p2(F(float,1),F(float,2)) == 3.0) + doAssert(p2(F(float,1),F(float,2.0)) == 3.0) + doAssert(p2(F(float,1.0),F(float,2)) == 3.0) + doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0) + #doAssert(p2(F(float,1),F(int,2.0)) == 3.0) From 2671efab78e0c1a56d5f527b6a25f658575ca9a0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 18 Sep 2020 11:22:34 +0200 Subject: [PATCH 1110/4254] async: minor refactorings (#15354) --- lib/pure/asyncdispatch.nim | 29 +++++++++---------- lib/pure/asyncfutures.nim | 34 ++++++---------------- lib/pure/asyncstreams.nim | 36 ++++++++++++------------ lib/pure/ioselects/ioselectors_epoll.nim | 4 +-- lib/pure/selectors.nim | 2 +- 5 files changed, 43 insertions(+), 62 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 41d67d172..6f38583d8 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -290,7 +290,7 @@ when defined(windows) or defined(nimdoc): var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher - proc setGlobalDispatcher*(disp: owned PDispatcher) = + proc setGlobalDispatcher*(disp: sink PDispatcher) = if not gDisp.isNil: assert gDisp.callbacks.len == 0 gDisp = disp @@ -1217,10 +1217,12 @@ else: withData(selector, fd.int, fdData): case event of Event.Read: - shallowCopy(curList, fdData.readList) + #shallowCopy(curList, fdData.readList) + curList = move fdData.readList fdData.readList = newSeqOfCap[Callback](InitCallbackListSize) of Event.Write: - shallowCopy(curList, fdData.writeList) + #shallowCopy(curList, fdData.writeList) + curList = move fdData.writeList fdData.writeList = newSeqOfCap[Callback](InitCallbackListSize) else: assert false, "Cannot process callbacks for " & $event @@ -1232,8 +1234,7 @@ else: for cb in curList: if eventsExtinguished: newList.add(cb) - continue - if not cb(fd): + elif not cb(fd): # Callback wants to be called again. newList.add(cb) # This callback has returned with EAGAIN, so we don't need to @@ -1259,15 +1260,15 @@ else: result.readCbListCount = -1 result.writeCbListCount = -1 - template processCustomCallbacks(ident: untyped) = + proc processCustomCallbacks(p: PDispatcher; fd: AsyncFD) = # Process pending custom event callbacks. Custom events are # {Event.Timer, Event.Signal, Event.Process, Event.Vnode}. # There can be only one callback registered with one descriptor, # so there is no need to iterate over list. var curList: seq[Callback] - withData(p.selector, ident.int, adata) do: - shallowCopy(curList, adata.readList) + withData(p.selector, fd.int, adata) do: + curList = move adata.readList adata.readList = newSeqOfCap[Callback](InitCallbackListSize) let newLength = len(curList) @@ -1277,7 +1278,7 @@ else: if not cb(fd.AsyncFD): newList.add(cb) - withData(p.selector, ident.int, adata) do: + withData(p.selector, fd.int, adata) do: # descriptor still present in queue. adata.readList = newList & adata.readList if len(adata.readList) == 0: @@ -1308,10 +1309,6 @@ else: proc runOnce(timeout = 500): bool = let p = getGlobalDispatcher() - when ioselSupportedPlatform: - let customSet = {Event.Timer, Event.Signal, Event.Process, - Event.Vnode} - if p.selector.isEmpty() and p.timers.len == 0 and p.callbacks.len == 0: raise newException(ValueError, "No handles or timers registered in dispatcher.") @@ -1346,9 +1343,11 @@ else: result = true when ioselSupportedPlatform: + const customSet = {Event.Timer, Event.Signal, Event.Process, + Event.Vnode} if (customSet * events) != {}: isCustomEvent = true - processCustomCallbacks(fd) + processCustomCallbacks(p, fd) result = true # because state `data` can be modified in callback we need to update @@ -1612,7 +1611,7 @@ proc drain*(timeout = 500) = var curTimeout = timeout let start = now() while hasPendingOperations(): - discard runOnce(curTimeout) + discard runOnce(curTimeout) curTimeout -= (now() - start).inMilliseconds.int if curTimeout < 0: break diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index c1e2770bb..97abf72c9 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -157,33 +157,15 @@ proc checkFinished[T](future: Future[T]) = raise err proc call(callbacks: var CallbackList) = - when not defined(nimV2): - # strictly speaking a little code duplication here, but we strive - # to minimize regressions and I'm not sure I got the 'nimV2' logic - # right: - var current = callbacks - while true: - if not current.function.isNil: - callSoon(current.function) - - if current.next.isNil: - break - else: - current = current.next[] - else: - var currentFunc = unown callbacks.function - var currentNext = unown callbacks.next - - while true: - if not currentFunc.isNil: - callSoon(currentFunc) - - if currentNext.isNil: - break - else: - currentFunc = currentNext.function - currentNext = unown currentNext.next + var current = callbacks + while true: + if not current.function.isNil: + callSoon(current.function) + if current.next.isNil: + break + else: + current = current.next[] # callback will be called only once, let GC collect them now callbacks.next = nil callbacks.function = nil diff --git a/lib/pure/asyncstreams.nim b/lib/pure/asyncstreams.nim index 393262c4f..7ffde9c10 100644 --- a/lib/pure/asyncstreams.nim +++ b/lib/pure/asyncstreams.nim @@ -54,7 +54,8 @@ proc `callback=`*[T](future: FutureStream[T], ## ## If the future stream already has data or is finished then ``cb`` will be ## called immediately. - future.cb = proc () = cb(future) + proc named() = cb(future) + future.cb = named if future.queue.len > 0 or future.finished: callSoon(future.cb) @@ -90,27 +91,26 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) = ## ``FutureStream``. var resFut = newFuture[(bool, T)]("FutureStream.take") let savedCb = future.cb - var newCb = - proc (fs: FutureStream[T]) = - # Exit early if `resFut` is already complete. (See #8994). - if resFut.finished: return + proc newCb(fs: FutureStream[T]) = + # Exit early if `resFut` is already complete. (See #8994). + if resFut.finished: return - # We don't want this callback called again. - #future.cb = nil + # We don't want this callback called again. + #future.cb = nil - # The return value depends on whether the FutureStream has finished. - var res: (bool, T) - if finished(fs): - # Remember, this callback is called when the FutureStream is completed. - res[0] = false - else: - res[0] = true - res[1] = fs.queue.popFirst() + # The return value depends on whether the FutureStream has finished. + var res: (bool, T) + if finished(fs): + # Remember, this callback is called when the FutureStream is completed. + res[0] = false + else: + res[0] = true + res[1] = fs.queue.popFirst() - resFut.complete(res) + resFut.complete(res) - # If the saved callback isn't nil then let's call it. - if not savedCb.isNil: savedCb() + # If the saved callback isn't nil then let's call it. + if not savedCb.isNil: savedCb() if future.queue.len > 0 or future.finished: newCb(future) diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 1b317f8dc..3dcf547bd 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -514,7 +514,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.getData(fdi)) + var value = addr(s.fds[fdi].data) body template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, @@ -523,7 +523,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.getData(fdi)) + var value = addr(s.fds[fdi].data) body1 else: body2 diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index f3726efaa..e89cc7447 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -255,7 +255,7 @@ else: IOSelectorsException* = object of CatchableError ReadyKey* = object - fd* : int + fd*: int events*: set[Event] errorCode*: OSErrorCode From 59b7857167ad458290dc57c4e39ca564b3080e52 Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 18 Sep 2020 11:50:15 +0200 Subject: [PATCH 1111/4254] bump NimVersion to 1.3.7 --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index c05ca24dc..362b5b2b9 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2079,7 +2079,7 @@ const ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 5 + NimPatch* {.intdefine.}: int = 7 ## is the patch number of Nim's version. ## Odd for devel, even for releases. From d19316bbb986a7dd1d6d091173963f6e74c65991 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 18 Sep 2020 11:55:58 +0200 Subject: [PATCH 1112/4254] more ORC bugfixes (#15355) * introduced --define:nimArcIds * ORC: bugfixes --- lib/system/arc.nim | 6 +++-- lib/system/orc.nim | 37 ++++++++++++++++++++++++++----- tests/arc/tasyncleak.nim | 2 +- tests/arc/tasyncleak3.nim | 46 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 tests/arc/tasyncleak3.nim diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 68376cdab..3cbd02806 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -54,7 +54,7 @@ type when defined(gcOrc): rootIdx: int # thanks to this we can delete potential cycle roots # in O(1) without doubly linked lists - when defined(nimArcDebug): + when defined(nimArcDebug) or defined(nimArcIds): refId: int Cell = ptr RefHeader @@ -72,6 +72,8 @@ when defined(nimArcDebug): var gRefId: int var freedCells: CellSet +elif defined(nimArcIds): + var gRefId: int proc nimNewObj(size: int): pointer {.compilerRtl.} = let s = size + sizeof(RefHeader) @@ -85,7 +87,7 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = result = allocShared0(s) +! sizeof(RefHeader) else: result = alloc0(s) +! sizeof(RefHeader) - when defined(nimArcDebug): + when defined(nimArcDebug) or defined(nimArcIds): head(result).refId = gRefId atomicInc gRefId when traceCollector: diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 4ba462c1f..5deed1d14 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -41,6 +41,7 @@ proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = let h = head(p) inc h.rc, rcIncrement #h.setColor colPurple # mark as potential cycle! + h.setColor colBlack const useJumpStack = false # for thavlak the jump stack doesn't improve the performance at all @@ -101,6 +102,11 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = var j = cast[ptr GcEnv](env) j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[]) +template orcAssert(cond, msg) = + if not cond: + cfprintf(cstderr, "[Bug!] %s\n", msg) + quit 1 + var roots {.threadvar.}: CellSeq @@ -115,6 +121,11 @@ proc unregisterCycle(s: Cell) = roots.d[idx][0].rootIdx = idx dec roots.len +when false: + proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) = + cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld\n", + msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color) + proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ proc scanBlack(s: Cell) = @@ -126,14 +137,17 @@ proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = ]# debug "scanBlack", s s.setColor colBlack + let until = j.traceStack.len trace(s, desc, j) - while j.traceStack.len > 0: + #writeCell("root still alive", s, desc) + while j.traceStack.len > until: let (t, desc) = j.traceStack.pop() inc t.rc, rcIncrement debug "incRef", t if t.color != colBlack: t.setColor colBlack trace(t, desc, j) + #writeCell("child still alive", t, desc) proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ @@ -148,6 +162,7 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = if s.color != colGray: s.setColor colGray inc j.touched + orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty") trace(s, desc, j) while j.traceStack.len > 0: let (t, desc) = j.traceStack.pop() @@ -195,6 +210,7 @@ proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = when traceCollector: cprintf("[jump stack] %p %ld\n", t, t.rc shr rcShift) + orcAssert(j.traceStack.len == 0, "scan: trace stack not empty") s.setColor(colWhite) trace(s, desc, j) while j.traceStack.len > 0: @@ -236,6 +252,8 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = free(s) # watch out, a bug here! ]# if s.color == colWhite and (s.rc and isCycleCandidate) == 0: + orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty") + s.setColor(colBlack) j.toFree.add(s, desc) trace(s, desc, j) @@ -261,6 +279,7 @@ proc collectCyclesBacon(j: var GcEnv) = collectWhite(s) ]# for i in 0 ..< roots.len: + #writeCell("root", roots.d[i][0], roots.d[i][1]) markGray(roots.d[i][0], roots.d[i][1], j) for i in 0 ..< roots.len: scan(roots.d[i][0], roots.d[i][1], j) @@ -279,7 +298,7 @@ proc collectCyclesBacon(j: var GcEnv) = #roots.len = 0 const - defaultThreshold = 10_000 + defaultThreshold = when defined(nimAdaptiveOrc): 128 else: 10_000 var rootsThreshold = defaultThreshold @@ -309,11 +328,16 @@ proc collectCycles() = # we're effective when we collected 50% or more of the nodes # we touched. If we're effective, we can reset the threshold: if j.freed * 2 >= j.touched: - rootsThreshold = defaultThreshold + when defined(nimAdaptiveOrc): + rootsThreshold = max(rootsThreshold div 2, 16) + else: + rootsThreshold = defaultThreshold + #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) elif rootsThreshold < high(int) div 4: rootsThreshold = rootsThreshold * 3 div 2 when false: - cfprintf(cstderr, "[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold) + cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld\n", j.freed, rootsThreshold, j.touched, + getOccupiedMem()) proc registerCycle(s: Cell; desc: PNimTypeV2) = if roots.len >= rootsThreshold: @@ -328,10 +352,10 @@ proc GC_fullCollect* = ## collector. collectCycles() -proc GC_enableMarkAndSweep() = +proc GC_enableMarkAndSweep*() = rootsThreshold = defaultThreshold -proc GC_disableMarkAndSweep() = +proc GC_disableMarkAndSweep*() = rootsThreshold = high(int) proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = @@ -345,6 +369,7 @@ proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline. #s.setColor colGreen # XXX This is wrong! if (s.rc and isCycleCandidate) == 0: s.rc = s.rc or isCycleCandidate + s.setColor colBlack registerCycle(s, desc) proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index 71d62222d..72aa3d4c2 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 4016, deallocCount: 4010)" + outputsub: "(allocCount: 4016, deallocCount: 4014)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ diff --git a/tests/arc/tasyncleak3.nim b/tests/arc/tasyncleak3.nim new file mode 100644 index 000000000..c1510895a --- /dev/null +++ b/tests/arc/tasyncleak3.nim @@ -0,0 +1,46 @@ +discard """ + cmd: "nim c --gc:orc $file" + output: "true" +""" + +import strutils + +type + FutureBase* = ref object of RootObj ## Untyped future. + finished: bool + stackTrace: seq[StackTraceEntry] ## For debugging purposes only. + +proc newFuture*(): FutureBase = + new(result) + result.finished = false + result.stackTrace = getStackTraceEntries() + +type + PDispatcher {.acyclic.} = ref object + +var gDisp: PDispatcher +new gDisp + +proc testCompletion(): FutureBase = + var retFuture = newFuture() + + iterator testCompletionIter(): FutureBase {.closure.} = + retFuture.finished = true + when not defined(nobug): + let disp = gDisp # even worse memory consumption this way... + + var nameIterVar = testCompletionIter + proc testCompletionNimAsyncContinue() {.closure.} = + if not nameIterVar.finished: + discard nameIterVar() + testCompletionNimAsyncContinue() + return retFuture + +proc main = + for i in 0..10_000: + discard testCompletion() + +main() + +GC_fullCollect() +echo getOccupiedMem() < 1024 From 341cd844b282cc6ed3b1fc4c1ef10c38fc06d5e7 Mon Sep 17 00:00:00 2001 From: yatsen1 Date: Fri, 18 Sep 2020 23:17:09 +0800 Subject: [PATCH 1113/4254] fix coro proc crash for stack problem when run long enough than a GC cycle (#7612) (#11410) Co-authored-by: drswinghead Co-authored-by: Clyybber --- lib/pure/coro.nim | 8 ++++++++ lib/system/gc_common.nim | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 6e49b6323..2a702b65b 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -36,6 +36,7 @@ const defaultStackSize = 512 * 1024 proc GC_addStack(bottom: pointer) {.cdecl, importc.} proc GC_removeStack(bottom: pointer) {.cdecl, importc.} proc GC_setActiveStack(bottom: pointer) {.cdecl, importc.} +proc GC_getActiveStack() : pointer {.cdecl, importc.} const CORO_BACKEND_UCONTEXT = 0 @@ -166,6 +167,7 @@ type coroutines: DoublyLinkedList[CoroutinePtr] current: DoublyLinkedNode[CoroutinePtr] loop: Coroutine + ncbottom: pointer # non coroutine stack botttom var ctx {.threadvar.}: CoroutineLoopContext @@ -183,6 +185,7 @@ proc initialize() = ctx.coroutines = initDoublyLinkedList[CoroutinePtr]() ctx.loop = Coroutine() ctx.loop.state = CORO_EXECUTING + ctx.ncbottom = GC_getActiveStack() when coroBackend == CORO_BACKEND_FIBERS: ctx.loop.execContext = ConvertThreadToFiberEx(nil, FIBER_FLAG_FLOAT_SWITCH) @@ -193,6 +196,7 @@ proc switchTo(current, to: CoroutinePtr) = to.lastRun = getTicks() # Update position of current stack so gc invoked from another stack knows how much to scan. GC_setActiveStack(current.stack.bottom) + nimGC_setStackBottom(current.stack.bottom) var frame = getFrameState() block: # Execution will switch to another fiber now. We do not need to update current stack @@ -215,12 +219,14 @@ proc switchTo(current, to: CoroutinePtr) = # Execution was just resumed. Restore frame information and set active stack. setFrameState(frame) GC_setActiveStack(current.stack.bottom) + nimGC_setStackBottom(ctx.ncbottom) proc suspend*(sleepTime: float = 0) = ## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds. ## Until then other coroutines are executed. var current = getCurrent() current.sleepTime = sleepTime + nimGC_setStackBottom(ctx.ncbottom) switchTo(current, addr(ctx.loop)) proc runCurrentTask() = @@ -230,6 +236,7 @@ proc runCurrentTask() = block: var current = getCurrent() current.stack.bottom = sp + nimGC_setStackBottom(current.stack.bottom) # Execution of new fiber just started. Since it was entered not through `switchTo` we # have to set active stack here as well. GC_removeStack() has to be called in main loop # because we still need stack available in final suspend(0) call from which we will not @@ -244,6 +251,7 @@ proc runCurrentTask() = echo "Unhandled exception in coroutine." writeStackTrace() current.state = CORO_FINISHED + nimGC_setStackBottom(ctx.ncbottom) suspend(0) # Exit coroutine without returning from coroExecWithStack() doAssert false diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 7f6c41e1b..658c5d025 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -273,6 +273,9 @@ when nimCoroutines: gch.activeStack = gch.stack.find(bottom) gch.activeStack.setPosition(addr(sp)) + proc GC_getActiveStack() : pointer {.cdecl, exportc.} = + return gch.activeStack.bottom + when not defined(useNimRtl): proc nimGC_setStackBottom(theStackBottom: pointer) = # Initializes main stack of the thread. @@ -300,6 +303,9 @@ when not defined(useNimRtl): else: gch.stack.bottom = cast[pointer](max(a, b)) + when nimCoroutines: + if theStackBottom != nil: gch.stack.bottom = theStackBottom + gch.stack.setPosition(theStackBottom) {.pop.} From ae1f5c15593be8137812137d315bb8d367dfac9f Mon Sep 17 00:00:00 2001 From: Euan Date: Fri, 18 Sep 2020 21:26:53 +0100 Subject: [PATCH 1114/4254] Use sysctl on NetBSD to get exe name (#15359) --- lib/pure/os.nim | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e7087acf7..45f022379 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2826,12 +2826,19 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly)): when defined(freebsd): const KERN_PROC_PATHNAME = 12 + elif defined(netbsd): + const KERN_PROC_ARGS = 48 + const KERN_PROC_PATHNAME = 5 else: const KERN_PROC_PATHNAME = 9 proc getApplFreebsd(): string = var pathLength = csize_t(0) - var req = [CTL_KERN.cint, KERN_PROC.cint, KERN_PROC_PATHNAME.cint, -1.cint] + + when defined(netbsd): + var req = [CTL_KERN.cint, KERN_PROC_ARGS.cint, -1.cint, KERN_PROC_PATHNAME.cint] + else: + var req = [CTL_KERN.cint, KERN_PROC.cint, KERN_PROC_PATHNAME.cint, -1.cint] # first call to get the required length var res = sysctl(addr req[0], 4, nil, addr pathLength, nil, 0) @@ -2984,13 +2991,13 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW if result.len > 0: result = result.expandFilename else: - when defined(linux) or defined(aix) or defined(netbsd): + when defined(linux) or defined(aix): result = getApplAux("/proc/self/exe") elif defined(solaris): result = getApplAux("/proc/" & $getpid() & "/path/a.out") elif defined(genode) or defined(nintendoswitch): raiseOSError(OSErrorCode(-1), "POSIX command line not supported") - elif defined(freebsd) or defined(dragonfly): + elif defined(freebsd) or defined(dragonfly) or defined(netbsd): result = getApplFreebsd() elif defined(haiku): result = getApplHaiku() From 8ae4a774b77d492f997f72d36cc3b8705bc080af Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 18 Sep 2020 15:20:41 -0700 Subject: [PATCH 1115/4254] doc fix typo in lib/pure/httpclient.nim (#15364) --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index a590bd83a..533bf3c15 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -17,7 +17,7 @@ ## ``http://google.com``: ## ## .. code-block:: Nim -## import httpClient +## import httpclient ## var client = newHttpClient() ## echo client.getContent("http://google.com") ## From 9a34009f00749bb29f3c58256648994940533e06 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 19 Sep 2020 00:27:43 +0200 Subject: [PATCH 1116/4254] ORC and stdlib optimizations (#15362) --- build.out | Bin 430264 -> 0 bytes lib/pure/asyncdispatch.nim | 8 ++++++-- lib/pure/parseutils.nim | 16 ++++++++++++---- lib/system/arc.nim | 9 ++++++++- lib/system/orc.nim | 38 +++++++++++++++++-------------------- lib/system/strs_v2.nim | 3 ++- 6 files changed, 45 insertions(+), 29 deletions(-) delete mode 100755 build.out diff --git a/build.out b/build.out deleted file mode 100755 index 9edb996b0c494271d8d4f910ce04ee6ae72f2b6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 430264 zcmeFad3;n=(l_2g8qoneE@;$I<2HgTDyXPPTv{6yjSB7xiXe=rh>4~ z;+}CM;~Ez<`Ur$&(otu$-Nv{_1idk+(LsqTzwfu|oV#>)BJcCp@BMsUXGq_BYB^PP z>eQ*T+UxT*+eo0qv;JLqlHhA{eO2}W*b@$)t{S{(=L&bVex-c)zeeUmq)0C_I zwQ#q-sixMP-_|xV4TbElpN_T}caGE=8h3Hv%4ujt()?$Zp!yWc`5$o{QLg0aBn@8uO2Tv}NnjHg}|x^P0pgiEeqA#pFRyo5DSyh|<(O}uj27J%NI;X8eHHrPCl90_k{Tnv2hyd`W1c z1)$E!(;zGmE@ogofLGHhc)2exFPNg?mJAer%<&_SICAWMd+$3WWG}s|eGhaC_uG3Y zU8k4)Pk%SSb#GIm)&v zz&8lpW$r7tnYvd$Do>N};4=s=9lsB33 zbWZt-rxbr)PWdWRUYAq8+LSlsl&>-6jXCANoARcd^8O84Z{M7LX75`s)&9+~Q8C4A zp*COnCR!wa9bft8zVc3AIb*KC%=D(7u zD*uMKH%%^(QeU~v1qc}EE8jpc_0M2mxpLI?nZ5{sG^#k5Bq_$_}{w>}!l(sj?{j0oZ2yJhW`=z|+5Yk>J z_b>6Dp|m|M_s{U2A+$X%_mA?Pp|gFe+&{p3hRpVHa(@@^87kY$<^C4lGeowR$^8wy zXJ~96Ece&)o*}WlRPL|lJwsu8vD{DNJ%_UPklg>3_Y8^coxh`C*YkPLP}trk_h<5+ zA+S9w_b2n7p|8D3?vLd?hrsp*xj%yU41w)+a(^)I8T#7Oa=#z%8S>iWa=$z88S2`n z%Kc8fXNYSbC->X%o}sP19QSO`eZL-=c=Oy?VnwWaWoP;5<5S`1$Mg=xQvFBB&+w;L z_X@2WumUR#YtpgQ@X25hONFUdY*<&t0Jy>;z~~Aat!sfSz z9!qq_mV7fJwxnx=SW$EA&EG4w0E4-PLEm+46C*nu<wDZ|{QW9u{kcLNZ4p=_t>rlQ1B0Vc|KiX{hBlK{A}M6v#a zFEb^?o;Wr_yqxG@mn7Y`YENW$-JDg&svcz!P%M>>i-oQt|$t;RG&l1gBAtJ<#*2RV`joi{y8(r)?3Hr$M(Z#uf z{{D+k&~n(cG2fn_DOcL_OItxfAwT#{?3rDz(!6AmX`nmd+6VV3edKM(34X_AXW((`j z@BQ@0l5XQk+H{8T!-A4Ni)Nmq_xnF zw|Es62nqvKIsSD5720|4gRGD%w_>dRZlaSXN>b5MQWz z2n>>A8e)kfN@CSjjiCz0PIL`*6PjdSHA&~`wjW0u4sX=L{vWb1HQ=A}GjtQFFyky~ zL2t^!k@BpvbC<8py6M`jS`n@Ck*%{}o2`S1DIkYUAU|c1jr<%)&G^twP0PHRrdi^G zHO)0Oaqfzmq88cIw5K-`4MwtvFJb9aO4U zm&zEHsO$u#0}A{b)d>oWO+s-uD)F$3UF_p-LnQt~ zu^+-JFtMg7);Jdn6(bW7)kd`iD*lxzCrD3Zc;v83DRYPUt=9Nr!8rJHeSRBv2qS4@ zM=!f+<6~7tiI5c5wDGf+2;=-{wDEpxjGRCjr~0HVN`4zxT2O&DKI_wf#*czKHRgzi zK12~r8xOWj*if9|5N*34^=d=CgN~QBjen5hoHkzZNuc7(4CzWUfSERa$&%)@@dLIz z*v3s;1={!;7t7bilYR*7#++x_y6A4#)H>0Hr@v!bj1HVV&mawbrTy0 z0#GP67LyLW5! zjf6nf<5-W#=EDDr zDaQq0|8dLg<4O8%xv@e)Npq$g^&YY-A%}|fpK>&>&XulkZ@XV>qAimr_9Wq^I;N;N z(BV-G_aHjeNA#o?9chbfk1NV@mf;*m4)pt+wTNx~qIT2Yeo>wj^G3_QpdtT?nFa@3 z$_eDL7Fp``X4Rid9x?`Vn_kW%g(fH0b*!KLCVPVY_k^D8_okUPe5-;rTjc7hx=_Vm zAhM<_Toge=|H3iU&gF3biI*;RDuWu!Ksztj>IQ*}=Ppd1GtM*02u9b5+%sqdlapX2 zizYfWzzA_XQS96bVbdT9tbSbnRjx_$L(%!ljO}!RISWdrW&S~-3%djaC!(M-l+oi zGsv0fZK6UlTFZu>>#SRsh~8FRbz3Mh`*`+5kldvt?;r1a<~*UvMCbi8b`V_314}_Dp zVu(QdRAoaI2LUt7`FBmzReNd?+m}VQDPO`&n*Ysod(v}XLDNjs5sih7p(*JI|Bsph z9AMI2Ko(0Z0Yg;zfmw-IzNc!KV;Q~W1*w5fU)R1G&CV%uQ>#k4mn&&nB?*6c6m7ml z_-W@!4S$?&@cl}PBE;`2apy5sO%of#_X%;vxk7MnV?`e-?s9`0ONOs9Nc(<{>FXVs zal*Hvj(_F{b|yC6&=`m*yi7$l=FBe(?C!e3kQM^VXyqc&=3dfx$5@c-ZQ>}2?}yCA&wPd-hk%McRA~RN!Dhf-v}!KJABPyOoWtA2+!E4tU? zS)hfEds|w_jsvdh90MWHI7^%gSB_#7Q|;RodW3~q*P|5>Vka2oq~VI9_0Dgaw?hA* z!+rLNUky53zA8I;s+h}e!cqJ!QN>k(2Oglp*WL^Y?yQMav4Y<6K(H{54n!L(Mz94p zRroUjcp0;f27-As0-SFRfTe47JePKgZIYg&?3$1NSlMc2$((wq<&FwbU(VXmt#1aE z<>?C$g*>7LbaF`x&5qJ4JDrgrtajj;3{bu5fm}P3QPC2GKN^6Sl~_CQ$Og!hK`=(j zXk*8-X=g*7FE`}2ddEjTLzJV{3#?CFuRLjpLwlTD+yLWH)N3^4MJ%$!jClP(K;e;h zNm_y_v`Z`Axnp_Xc(*S|8A>VgDS81rlmR7KW&AI#yOlG(T z%z-;FXA1vv(S z_^o1AhWh!4%*xPDnt->$qY=xZbuqItv>ilMdj-RE(RzydrB+2zzwp%xqvUk^d;aa& z%$!nL;3F_g#t+ycE2eu&r2$xd$b#*DYj(A4DdES?5)q4(A1rCtGtRE!_G;JZXQ?gtnVuV`PrBM{3U6Y>Cj! zk>|6J3oYIovp6>^=0NH;3$i@~L?a$~Dr$8Z_;k5=3>1GqYn zJRu0jD8ev{U{=|j$8}`@)(JXX`aPd@rXpHkj#8PQei1v_jnZ1z7F6j%CKY zV-$Y4rKAy;boJ4yuwJvYS1h>&8>O+jZ3L!hZ-1rJGcF>`#nQr49VKGF)0EFoN9&3S zHF2h5a*RIkRIcqt|Ho&$ZX)e>+7Ptc!-gl-$?vHDeMS0!8)@%TL8e+Fy3>-be$?0b z^uIQG1Owf&cXI_Q?CKLep^7d4f+n6kblXv)8<h6?M&)M zs^jydD(rUKdy;*2WKY)mvN_m*|5524_Yr-dMR(dF5qMOcuE?zY4xL*XcL7^j8n=>3 z(hz%k?#{Pz4Ov*^OVnp*%o)};1&uibBHIRjR)?=qK7s{Wbg(V*jkCAQY0!QUw9q)) z`KC|M9^&&W%9(=hWo=SW&?HvQ(0ARjb|;mr>j={zzSZNM74)$OvdMmAHscfn*)EFn zqQPm7KB?V4iOElLOxncwTM-;;qfbJ?Cv}zf&)O*ECHS>SeK4W}Nmp|Xo;Us-C*gTl zt?pR2It(<@yn*UoMk;`i9(jHYVm1bX@o(9YxcxxPanjCx*mDIWZ#29%>sou(YIb8R zupY!&QDVVh{Nx9KGu75KdvjS&F1^Ka+N&l8E?_IBi|d@?CPUX;a|D60hdKQ`8DP^1S?r6(cp5lLcB~ma;n1ijb@k9tg|-0A(yuQ%;sZyjBsnaqB!%>r@2b z_rnydwuYtgg#wGz^fHxHEA1yERL|y`qjG335L%W(O8yuryVzGz`D|ryuVDZcMXW^4 z>A)pIjUrs*AyAE7*C7TiDwEd8ICHQG4TZ)TlIxXZq$^Yu02onuCd&uoQgAidcmP9r zZ4GfCB7cmCBaMhRD7&8z^V%}0MPK@g4AwhtQOzXQN(oKH)lFrRdYHOp4E!5M?S!CG zS;KdZ$7E^_lVo|{p!9cYV-gR(G~Gp?D<7Bea%4tU5y5cnR=UR zjwT=UhB!{gVk+Le7`DKU1Ej4L7%W8;?YP`=&8C#aJHy?W5l3D0?e>pAn{NM){ACA{ zUYl0@hg^Kq@Yu%#x0@AuoeM>AbyF$gw-Dc=;0q17xu(p>o5rRB{Ud@1Duob~Fcow= zXp|0U^auueMU)WZ!xg1&)q2()>MDi6q)KrWGTr`^{QU?2QtaCm{|y)4^f|2k1A2!- zpEl6un!{CU?bTR1N{+D!@D-Rl*9sg85KR@p0~!XIZs6|v#awLF!X=2*YzWa<_gz}| zP*1Xhz%`cC#SO3GM>uKM{m<;(N>gNMxWVZ~`Fj-l`5~@t>R{Sp5Oa$(d#{3*Td*Bo zI4C2g?8=#$-QYI)`u$3Bvmt4&IY#XR3cnYA-$~mL2HWsQZNt+8**ax$f~{3*lLqV9 zFx}BR4f{9?u;U0j(lv8a&f8ygV}14N^1_QsX>~e=_xG%2P&52GXPP|}6KTpM!(uA@ zs702s$vcEG9S5z@@|dvpa<+kJaM0l5O_5)yaa_D9oR|Er6;Lp9+0A72o`oWqJFWN= zL-*UfTRRWfC1-wNCoNkC_RXxtgdZnzB`&WH{W&=OTj31MGNpZ3 zr9Iw5u15)D`8=#nqvy%OWX?H;YDYIJISF2YJb6(Fc3?NXj!T}ln^rqTbOF}#h}QDO zfv!!!y;%H0JO**Bn0WIQZ&3lfwb|H?+|RJ66cbwB8bA#(c^?rQE`K8@(7YD^ABsOd zh!2^k>oP4OwLB~IsNx+Gz@w;X*aM1F=bt$@NR_vtwAM)en3DDO$cPW5pM@01gD%Eq zD$0VLb#$}WwyO(wgGTi`Ht8b=^wbU3;A9Pq=yn5h^yM-`1Q%S}x-Gqy{eR`B{bdG#%D=78mP}eCiBGA(Hu~|!dW4}2$ zI^7$$;)qKc5r5ak-fr75n}|L~U*X{hkl$j-eVUt9$}0`1y6U-5#RSqIl9A?I14u@n zgEeO8(mNbQ9Kft+9&Gt?aYDp`92`ZlhO#0YD|!_|Zo<(rc~llDPqeZ912C6>(WJF> z4RIB#Pc{@IqJSE_LfGkliQ3rivtuWu=u$VVGg2&39?y9^NQvqFj7lo9RKart;DGIp zO7{lW2b8PTZJCmtn@9Esx^WzQ0vokZpfQ#VhNqjC`Fy1mzQU6?ov4V;*d@Q_jLvDm zgr&N`r3=5E`0aF`r&LNj_hX5wtJ*>pn*yhek>wt?exkV}%;te1`E(BbDkHyvSok(`6%o0$?$o5 zVy_b0v44ss!((v0E(@!X$>EB+wTC)mXP~Brj+By&^D`X~h({=5r|~>ZqW6RJ<{_+c z?1=fYZ|ccD)H-cJ+26(z0_t%CM4Q$ZvPAIh!_h}Wp~I!Ky~ug}OURHy%;;I}ELb8f zC^3Bn0jcm(<4dx}#}#QgQ1wE*>V;5cf1H(RT&D$+YDQns_XaB$!|7h}T;VAXW*wq`U+EB5&!99%v-(cy8*2S?hHqYf2Sqz$vm!ed1 z4vwXbv4oU3Z+={0Y-(KW6Kya%cA|1+?o)ZmQ7gg7(dXhG0R=m_*VT$ahQ5wx@{(iN z-@CN?qC-D~4&4KuS@l^Ez~V?W58MiDE(}rA(?0Qida}>!&xn0A%YmJKQac@Ih?=AG zX&}VI_;lLJ91xrzubLmK#F;V=f@nM}nvUF$wYT}|-1Eh`BQqSB znf%GD6Xy#HklB$}TVoF{2NtuYzFO05g-BvL*|k-H2BUQXQ((|-q;zMybbxY9*Cmfj zU^{2|2hvqBiwsU#>R)#I!>rW}Y`Mh3N$^js?2VJ3xu@eNKR*9myC7Y2)t)`M=Kf$x z8FyD18!fU~l?jIiu})or*~92>aGGmoqHdl|jEA@xCAXOGvQ$IvmQXX!6r#FoJ36g^ z#BY5_9BzRWcgP(zb#S>W;fdlXWzZ{Uy?yC$Abs11ldG%HM-=UP4V}Hdd@o-=>+Dn{yh(dqf z-POs6(BO&Ch$=zDT(Yek%X<+h~2Pp<3I=>{RLzVfxE^}>DeP}t3zTxy~EfC7T ze$jPZ^X7_tH@!jIk8XOHWe$gfiNjt2Je}j7JMBhA4>11_~qSHa2RsknjI$actJRg5$U??=ZDN?f|5rFuNB8~_m zqCdgC4vzi`tbp=X@!(w;Dl6*a|%X?f%X{bj(_)xSiV^-?e%2S)pz zYikSe$eTO+sZD@?Ss85SG2rqkL}KV;4GR_F*WH4uCsoQ}f;ZzBVlr!oEN@v%|7x`9 zsu`yj&m82eK}*}VGkX*ZHYuMQTt3mbF`pRS)QpT{sqkWl!9Q<5V~NrqYw4>OmP40N z<=GT+sRH-1Krgn5!r(fN$KDeNX%g0SRT_lLlyJ>o0(NK?mn-TRB$EGAak4=ixSKSW zXVZ-0)w_5y(73HD+dD5&In>*txYxM2+K9Q_B#O9idZCoh_;VVjbq)TWj!O9*u zTXcE-!B1UU*V{@`?2;Jm%ZjA|!1Nu(_-0qv3c@W@#>_%I@?FLFR}Mx}Yd3@Tdx|u_ z8zeEnIF8z8Sb1OZuXOP_kYEUaL}t_XYzxXn>qHbLc4*D_e-|39R1kVT3xq z@&<xWriK>I_U{>*w*8bBjR%s4CA#Tq9$@sOVLh`N%5`3ZrEiQp+vv^%8 zjD#uWR#uLr7U|wqM?ZLx><-ED8yJ16jAnX_wDIQZ2qbp81>4qksQOItPjvB_2x(@z zLP0|esJZ3@v4;)&oI=1{kLvP2hBFn}wG+lGvC|hgyjLr`5zf1%Wy(T6yOw5 zz?zVFhzHOtVf-*% zho*2I&BAu3nw;b?`HVNhE=PFjX_5AE?Jyk6-r33M1QF>gUi%|WvSi1eOcKF@ zHH1_BAtYbu4Wb(@5x1te%BJQR*=o!I%;OaEe2dA0VUe18+7VEB_z&%Gp`N4HFDfSv zy!{FsUV(9GIVi6EWR!C4XX#*6J-JtB4vV3m6tjX86!G&?>%>09Q9$aKCDw_Gwa~*t zH_=R$b{_OP9gtloI5p|tu>Ph#M!PgkeX6YnHPfMj-uKXhYML`ura=~&eq)c|je?pC z8Zs_y%5^Mbm$Q^;%?_Trfx~uZEBqY~o`2YGNS2nyVLPTRA+uWgrdZ#c%iHKXu?COk z!GO-j|1RK$-#zKsX89lV%)#3IX`6$sWCd+g`+(S{j#gv4ZLWPK>=DtiOb;D{-Xi_% zWt?(?fiSa_KwC%3EtK-L?Oj8mPa`nyVfz?-S*NZgiurdB6AZkuc54M+8w9%p?Y0UY z?*}I-nRw?83XKM!oRf@#G#nbGfw#ly49Z-p*jstnz#=adbVmhuZRd7m8?K;>bQ@iQ zG=s=X+8W z@cD*1RE|e(+%v*Mcvb`|n*&+9SZcH&BEq4cOM^BL0}G0bM7=zW25c8WlX`c{sM;xo z0c7>moaTDx&u+8hgsIbq_HmBH4zBpMSRuIDzBBeR*Jr&juDz8SPqlSGNXVGe%NN}b zu>rY9#Xr&_qj7YHuDWdpSzxCYU*NTs8!_-VV5WHwws7ekfky|bAM?q_pby_Ev|jh6 z_7uvO-PZM!0`hHdpAU>33atsgPBijdEZputyawQp_XdO%Orl2Q)C zm6w>Q*ea#JrDyuo4Z2CiRg%#yvIJ(9y3gtbQVG@f>*6s zSNu}z-NqwFuT8t#TN>%kVvqe>rhtQ-|BoC80sro@g15CV(McZLx+f?33EoSa?xK-r zhDDZaATUO)u^B6{cUA0i51T`~)%PH((1`unJRiTm-lsx2d>o!uXw7~HPyE#-J&Av? z5g)G35VF`JciRWoW@Rs&y>QDy68<*dC*e3NAyO|WH>$wPRcC0gr=gFqmBT=EhG0&R zzFQ6bo=Q5vA~TdH(IeRFlA}<|>#-$Ypzpx;Mc>6{EfFWQ4%n*1ty{UC4X=PzY{b?yRqjLLR}}NpEq#i+UB~*}L-0G(#XnN~r#yU&G~V3#V+E&! z;9``9oOReX%yZl?9`@W~c^qz03&)M;50}?z-=;h4Z<#}UG7h@KtUJXWG}i&f@!F$) zAK)s8S`aKV(Rn1sZ=Lzgo}j32ThtUHZfX=l31h2_`Wt_&CNEdaf8=7yf{S3D@~I5N z66{Y>?7vxTKCK_AS*x{YPgdwT7RpFIeBHVYLo-LSflg8IVIH^^8&-Wo9A!?#%Wdq4 zGFtJrbn&>00Jrx<+7_u&$4qLTJynt0x3ET$EeDuh9IFd2h_P%>SIosOCW4Wj-wj(j zLwx8A#kt$X$*Z~!YZ&b}K;d-zZ2qMTXDQVLmx@7=Q>98HbjEqzBzI>k>cK85Oq5FV z0IdW^=BC4zR_#fy=O}8#Ma`3C3&>)ed8{I@*xZ@{%IV5FS)H%Y*L+9WZ9w2vDc*e^9+R8~ zXHyj#F*taR=ZC-hgzjOaG7(1NzvW#}@H7s?QD8ZboeB@I$P)7y{u^v!^pj5T{=2E$ z+-NLW&DwjDnmUlsQ|9+dQ zi!a_V#Q()2i@MzZZKxbWZHg4$$AhCO%y6g^tPK=nWpSQ4xaTIOF_FFF{B*}y>9l>6 zrop2D*Rm2cGJa1kwwB&d(Go$lVkVm0^dn8Np(z24HEv%eJK0a>n@(<|;QfPOnNB(n zEG%IB#Qi>Bo7#Qmf2u|c8vj3$o;t}cII9Wc*4a)nQ6>7jN94`15ue|~B9;VF4HXL0=s^E@I z+=d5p*-#|$RE7TALTyZtC9M3gcQDQnLPv(ZZl=mzn6Em$UX~b!5FeZ>e{rv`iN>Lc z3Y;cdu3ehVbD$?xff!bEvouemZJvJGS$kO`Hbb~|Adt+Ix4$BM*59>+i3pW4ACeRi z=ZOMfo_Z*zp(0BBP#(0rFBis&|3@?i!=T1%?(sBUj$EXtW!ZPM_fqrWwi?t-{esau znHJ66tYJ(w%MTWTZo{Fw@y>6g)f##^6|9Lh5Z5yuAmW z$JFT2-;7%V<dpwhVY#>@9moF{W}U>yz;+7j;HukqREdzo1FW*><7c|yjrCgRnX=25`3Vk>Ss>!gm z)_#f<&qcy$M`Ni=?XO5@M9;|8a!ZuM&a3;LA=lY^D)Ktt9XT?FQ)4#{HB%VorT1OtCjWYcb^vAhSaxJkKXz9!iSDSBDn}^Iazi7}z1k`zU9nZ}FI6t)gRNTS5LS7l zlGo%^nVJfpLsqZ5KvE~)3uI;>M=Mdep9oSdF%zF-6ufT^_|;!AqBcBNpxy7d-EH?- zt1%`Z=yvxmJ$=jBP1>i}@E`W+so@7<`UW*?!BaX*r=|&ySR#GRox4aK`Ip4sI$Gwx ziuyN;I;*Nq9>AV6dIRP4gCd-15oq;Pc?3gMED~Faot@rxtoTte2fLW&S->&%`Z5H0 zGljI~TE*;RF{`W6m~_V&%^^~kLY=Vn5A!e~zSF`Mvh++>g=ppq3o^D~I8h0|iZ%gA%5aCv|A5!5v47 zI1xoI4j@Auo`wOh%@q9I20oQ2t%NP|DJ9nCiuGC$YhZ!K*-A10o{KpwS~ue`vf5e^ z;vT{u+y4#h>6-Acy^J`SusBE zWvqdIiDn%!1COy|<;y-_D^a#ld&N9+j$s$2{D-B?!{0+5)J4(>8|IB#=fE;)BPHA!5{*IF4%?V((@vRpFenF3i`fi^l=ypFLF z+9M~&)}T=^)gW)jN{&LQ8wJd3jk9|y+omGxFgXo?aSSKw_xQQ4B8^&%%28W2EXlwV%=>S}avE&hKnQL9oXT5li8PWHLl%rY(voeu+t5Jl z1&X~QWVPe;uBcVPO3okliOkBNg zgAnRzMLh^8Xhn>>Bk{^jYJqJDcmsc<=m?@&Jq`A6C4D+b>aJ^$4{Xg0=j0MZ6T7Z~ z7i+P`tAk`E2$HfKLb4J=Rtz$Gbo~t_JJKVYCq2{Ml)%HS!A%LC{;y#UMPX?I)Y{u4 zM@1%g;x350Ap$me8zOHiaprf|NPko}9!scsl2oYL>}VuB>h;>sJ9HJy5AwIP@?$MI zip-A2fwo8{wCLA?9gU$RenpA<`!Q3wn}Kg()xv$AnpAHq)qB6W`eHos_BGy7aAOc$ zjM9*^8}^rB+2E%0CMlo0kFyDQ{=UZk8nEcSXIbVDhm3%1@U^Pw&e*4vECWnk>VO6&hYN22kI23cf!WUaO7>?JX$88b&NA63h z3Z9e6#@1%}B4HoFj)BuMoX)(D&DcC^HYHtay3aYBE@Qxga{T0*^)rnGG;41wXF;=` zJX7s3Q1htwezEOuPVVV}XOQl$2+w;6B7l2}RUW%=2LlyOPq>134<)|JBUW@g`p|~& zZt~!tKDJRzU))QvkITn4=d6LVx8m$(ajF+`bjQmL_`xbN*+&ujScJe?X02Ucu%W}k zCNO&}=TvhvPDcAGqlG`KWtwZwXGI7^aY(It%D{3K<|DNN#JNi1=-de35CtE^)>@1d z3P&^hQ6e>Rm=IO%uT`DwRyCegHP=kk8kNsG!iPm*!XJ6p87hlBj}x1uh(FA~xR*N> zV`~wE?K2#(!}#(ifvPOT7raQ#YNTh#cvD*aa`0$&E7_wBUGG_ z5hq{ed-xU;$bFOZq4mo1RL`rzHVhwe%y7S40{v#eBE1btDQOG4?UgwWmtKh%^e~T%_ z>pxgS6!78(5IKV%EHF@QRpSm+=JhLu&*7Y)A&%qI1-2&W$W9*|_Me%qekDmA_CG8# z$Izs#zN39$P#HLO(~)_z01|fQbeZ0nf&JpVp>@J+pTtvbqEh%s^n8sgl=?nfM?tB7 zy;7w8>|*i1M7j}kJ-Wg1inP5!3aruv76wxo z(E^{(m6xrIQu0sN*ydGPxa zpInGV({?_FBaM2RlDzl5>K0gEMkB~dyVg`zic_#f+*P>;rdkxQS`?~0luDegEN(L_ zwBWxUQMlQ)!usK8Oke`%gf_a{gtfvv*I%qdE4%hMFt3tQ!#Qv=PadY|1P&B zjf#-? z8>^Vd`Z2-ibHiwyg7@%)z3LVMt3%(5b??0e0^IDGz5rK_0M}SJB)_gbk-_avd^iHR zLn}>zx^qJE4wq{r`dY<$$RcY}WE491Q;N!mO$>2|3rlMW0L-YO?*- zm<>Q_gl=pcSUBU%S_bEH4=&`s+V_Y~bEf?#&p~wZj%z&fn_^w5Sa$}oP_0<& zRD^t|2z$b5kOq#XJJ)!vxI7M1)xuN-PCuThU7e;HYU?Q2iq%uqREOx&U0;iA=3tlM z5H569afgf?ks3L*f*KD~q6R~x1kpO0e}sbO zdLRTB^mUVimnrxP4_s@XV%~#(MVE*6y0Q&+QN=&n!-svO6|*B1w1)>madLp4S0gdtpA^+;MW4+vVj;b>t|d^`co9)Q4gU$cfTsI z$pXb>3Rq_n-``u+ZAL4f^F2P4bRaB&B{>=d1my$US3xrg%cm;-em&z;!qXJ9ZvYc2 z=$nsgZec$F+Ubh+*;lS1{?8QIh0{OqIYar}>G6R}phb$cnllxAwF~C<0$W?U$FARC zV8*wKaX55SJ3ODK6fu{Aj){~Pb)B!Ey*v;c$!>@sDTd1p%5|m*O7l~@t0yYQOUFKh z`0|vHn{P~1%r`vDM%}DXmUtG337-frdEzoYYYnL`RJuF-bQDD<)-wj67KrAm{3*|% z?j~(INeRz&2?K~5@$6JHHg)qt#}m`N(4l8c5IPE+qu*V_Aw$Q{j!_@-vadavaf*Zo+xNP9e09bp4sK~>MWNLAgRdZogfS!DJ*Sy13FhwjLn zHADdub0p(SFQ_Og-nxhP9Ps-W*r)z#1h3wN@bng_uJh!fTFqmY)*G0>13t2(Z3B8^ z+ZXvpJwQpPT2he^GTSf3QP3Du@&*(U%fEgpsv2`YA@MPj#Mi8XBwa#d;HgX3&>CprjBjYN0uSd!uSm zDvW+oMss-we&lYHDZYy=2?tC57?!i7RTPsGS7RLs5x+<>RWlG=jOoa55mpDJ=FPNb zf__~BPq2hf+~!QTzQOY`6h0&qBX4*$6U_~1Nv zWdMFq9(;@kUsPsneB~XUjq72ibaTxwYS_7A*nn%Cb3a{!a2S<8+G!89rq304B}R_i zM(yKO*l{acG|kTH|Ip)2m-%AKIF1>)ofPk!`BKJ1ju&ry-qX;y*93MqZ;FJp2TV#pY7-~!gU8mrL2ZmTk53vqCJ4xj*;yt1`6I`6|2cO`a0NxZDON8Ix zC6MMTQkg~a=2#g0GR`$CedVs`hkk+eH>xBo9^Nome=EQcj_- zQjB|o7_sUWoKmBD4Q7^cwc=H{c$i^`@)GU#T8kkC+O^+UK)dWEx!UD>Z_`RwvrTOk z1vR_$eAR5Z%CoY~IFQJ~V;3)dge>c6G?jC9Az_a63)78*4)=taZTS}zX2p3b%quF) zX%<;iibXbR&x9c8C~zW4EM8UYK?d6_`Z5V|DegmN5m@fsk!|&w5_W#->MVZw0F&$Uju*k^pvw{T`%uHB#EBfG-zFR1f3<3wkT5x_9ZU3Xg|(KCy5su$BocCekJ zb?i3IziyD2f&LRbN7OK7{X|@#RZzs=KI%!t<8nk?sL6bbB?>P89Kv~%nT{<|%=?0v z=#Ap#4UfaC`gEhkR~PxTC`BK3&}3a`F^tIeNYEu8z&AI?V2%2^P#ioGgvP9dr3$^i zWr_9)s=i;3-J=}ML07@_haod;k>!L5L#F2PNnGxjwOU`S$gQ6HHu{os98AnI{lfX4 z!DM}@Vn6C(!*yi^+uG?SW(BZl#{!uYV!?~DT;&nuu%}G(&^eq(YYTYr&42X_yF3oV z7I-cDGs>Ix+00f`(0d1C9hXW}s7$N8u2gH*cj^ePRB&@HnC^@jlD>_{qWFabco z78Pwgz>i>jdb)ys{=|(MkgB`{65yl@CTni%${9~H9{j5(>|*p_Mt>MUmJRqMKLQZt zDA&q{S~;qt^NQL>F;gYf3?i2Xn3t7saDBxrQT|OC93McD)vOXHd0hebm^LZbJo7n*W%%*Bre+=)I|a=Ds-Qt`Q7dB6~>p$E)rSRqiV8z_6n8 zV^oP?ljY;T)m)kP^|Ai%m?;742$^EOH>Pgw*#d zXsicnh%IsO0Yx39)LVDt9L>bCIwjcKMN+K%n#+Nd*GX~tO^qjuVPATBD-MU+6^Ci#d_GYsc{e_C0j5qYl}_&gE6P%< ztbA@St1r(d>x({=^6dbNn2=&X&d#44_Xv#-nuXdK9paSlN0 z18?kt1y*7}tr&V_Xl}hx2B??ZopYsLCFBCK7Vn*xGsyO2lZM^)i zG~JhqFeQK>yUG4piy87AMIK?1nLJmPq9MUlXq36X-!^m%O?T`kF{wkTi!61IWKN%} z3mf;VvvQ2v2;(*+vbE92#iJ6~y+Jrtw_;8_``e;Wh!=DCK1X`zIrtNqvpMd#bh)vV z7UAQbxPVEzXn(RW<9~|@ni&q35*o&^CV*uR4SiWAXFO-p&QINdMXRvLMB6-8=0F&? zq%zSaQ{IHhWm{y9ywO!QuH?ZYRy+_jw0g4_XmcneloLQISq=ibYUFwTYht#Am$Prm z_Z)g(_LkQ-IG#MYHRLG!!Aw!s!FOY+tb-n*L&x*jgicFOWt(=cH^YQ7>@*B%J)a6K z>~U((PGirVVakr()7|3tg;;2MvHdsn`08j=QTu#^SbX{pDLZN)T*kZ0G_}PtSyeVv zv9V}0WfMEX%b>>%9H_dg1tZ*W)R0D5 z6Fg*7@sJ`oe$60Otfk^NPVefjlF0P~P>g74-=UZa-}A->p(H-@hc~qhNaGqodtDoB z$ZA?$$G8_WH~Dm!fi$5#OH~kQqhrwq?Ql$*qs^GZ`Xg{5$r$|L3Ap6Ou{&dHf0FZ) z33#4~h+vgPcX4JicgR9Jb|mY6pezGrF+gpm%@2ep0IL&NrbmzI1i00Jf4WA%80bY0 zFo=NxM`n@sVNzG)g-A>v>?brm*C>X$fm%t9aOo^5)zxmt3cZI{8pxB(VkBgR^Nz8C z;>0m0ie0LLTYQUGTmKGC2){NPfeFrpFk-X6WoO@ZD^G9Mmna%Y3hn zDohP0|Fb6_%HU-nY@t;&5!Np}WbGsD3^2sGSBV;EaEwB+M-DNy1%KLf6YVJAca~|6j0Ci*o z485qxSh2$Zd0F^Ha03dyN6XnQIzbCw>_5AyBJ7MMEj-*1peGb%1Ne18{CxyJic-3M zG%LAWD*P3WwxI}3i&IXNQRDnTPI1jCRWqnJxtOrIEGZU~kNGak19{N$zRr%=kOotr z2j7kzKFMnYT_nuk%DquT7+vH^+o@3<%@d574;=+V_;Qfh$W%del_e4vVeFXmEF8X< zI((y3gB@JR2Bm{X4=>-X!qjM-_TACMnn2%F!YYF9j zs)%#|nJ-g?EXcln=!*0oFqD+^M&uv0(VMW&aFZ_7mjD5N z!0sss7bybb1#xPlbDTBUzs2>O-0<0Yg4-ZHzVl#;hGsU$0MB#<9Om*P;2^M=tfQsE zj;qC!?4{^t8Rs|T%eB!b<5f@M{Wy=X3j+Ta{-(l>)+T&=P6fYD-XM+2aSEhwYxB^m z4ZN?xLb;h~uTutBx)na96|xb{xxLXyfC8WR;0Nn%sMF@oI8(I>+FPPs<)=2gryUo>DJ(5wRt2e~%I4~WXRpsy$+DvX1Io!X* zxY4l#_;I)>eB_g9U$o23%*GWS4VpAovgOWN+*3z-u}oS*?G070Q-l7+BeJHdr|DzN zbQtcWn=|g>$WaRWz$ifb1pEDE$Gc{jwYrmx6AR@)U1C8glhTA9+seonbO6R`k-$Th z*zlCk&P!p^p6*g2@%5WzC&zr6UVjq8rX5e@bL_4W<%B+*;pc>eAfqPawbi`@)L`U(o*{+HQ%?+?1P^^ z?HXiH%YN((V=io^pBV}~UXSS<0A}EOW_#LK-y4&O#?^94WM5<>mfH{P&}wn`b*(`P z@cFCo!Kh^;tJQZ*t%)<89D?*QacNETwa8QEJqB2#8^!JrH;MG8c*P*0DO;;v>8u^jU`FE8- z3iLS@O*ZT^yT+#HZbzF&8NN+GGIb#CYRp~9A&&vy4JmUm*s(Vt=!v~Q`&KZRAT+6* z64epN1pJ^fXacxJ!CD2pX&cOc!Mg>_@J}Y2O)tSn5J{55{W}4#7Ojffw?nOR<`jL{ z@Ch{Qt$!9(vZ$xkUr%yO)=09oO5$bGNu!FfqKLb>YSRWbjbwu9)IXE#h*-bsyJHwCOcaFtHXR22*Av zrFqXSNFsx1X4{6lK^2?H!VoG(lw>fZZdww_JD86v73JOIvMH+YoJVEsey|| zvdY=Sn0eukRE4Y8bw-P8yP(BIWZEO6Rw#~ts2L|g)Tz}Ocx**ha5t0BfFqS18h(_M z*EgJ-u-X=^Yyc_)6L>5XqJov%eZ-;k7x7Nyi5GhN`718GO1h==Ln@RQ}y(s&= zfZ4XKrZO0l7HQ%P!%k&oNQH^T{3ay5hQuCB%RCxW4tQry02RKgH2A^NsAm`~9vOu{?t)pyY39)Y9d1x1^=MPG52 z%u0n%d%+EEr|4xj!EG2G4ur|F<{81iSY)$00EKaYAcBNuI-3Kx{!F8el;)Aa)m|{F zgSVFYNYtUe#{^t517)R!UCige1g9-v+VFhK#7+(XGS3FyXhHf0UNjJ!I%^&Pyu?CL zgm6t>XW1go2wu8yqW*{Fw%A&3GU8osy<$s#8WBsp8XE-1Kr9CBFs0qWrA6^Y*&ktl ze9E4uXJ+igYiU<}T`tjr)9ghpMNPQO4r-}x8k|_t0oCz|x}}LMVOhY~t@x{fI088hT{@w*xW$Y#` zpUwr(kuHM1MeQp28uVcb+|vSmO)a0QfpD)f6v>xKM=0{T=X}zc(XC8DD=kR3_(2Wz zUGLFW|5BDB-EuAb`fG882C$(=YJh<7M=0MLUA|n=^go5FnJF@WXcl{yR5bgHJD$%o z?Ce451s22^(jn2t$ee#^eYT!myn5!rzzt-3q_W+}fSRM%qaV0B$qo*7Z;M`yJP$k7 zMz42)=*qIa11q%Py}Avt)KqjLkFpA_KMIsTMV=qMUvcf|z98_RuK8nofPLy%tfh^) zUXUPDxyrQaX}2YCp87B7q-m$>i~>2p1&8=@fN>a63#{Q^{H!ozO0=C`b`v!=*eBRV z<^@QOG4A402|meZQz7`g z+;v-Xs(x{HL)3b**2>=8gi7g3nub?b%?nj*gc{}rVptX>-t5MmXrrwTiMB-M$a@AQ zm5Vl^tw4)SUw3KDOfssQN*EfeyMCH?cI0nbLaC^+o#3q7g_^Ts{7VhJ?|#*|1_#Q~5^X>Sez#HxUl?eNj1?GnC7Yop zZ9Yx7?5qjv&HmcFS;$tX4W{*pHOY^d8hW7->lO%ea$N3(FL#t?B+GTQHN805LXVPeq)XV=$nZm z!S6AF12#crm3L`J_$5L2l2WuQLyAaY5>lC=513KM$qc6y6bnD$DJZdeCBx?m9L5Td z_LW;h6sL6Lboh=Ke!3yNT)h3_{D8__t^< zn<+K?sXL+Fx2#<^l`skoI16QJX5QT{JjkRztMrh7=+Ndmsu*4B1XlX2Q zaoq~RKjYMY1`tNGeWkwehE_swIlNH|`+xs9G)N8jNPdRyDkwO_8b+|c6LIRgC&L%t2Wjz0Yd>gn_&pnh968|;ONK`i0139|dcC`yQ4Ax(yTYf=1=L&dc?(&# zwe+mj#pvbOO5iI5a)u)3VF_IFVuI$H2)q>wW#KpP6&WJ4ncKutx;22R4<)j>MV>Fx zKz1BkN|@DY{ek%S2B$28YJZTo7ZCkES)$bi(&T{2tj8`o|YeclXBhv3Kt(o(4|x>oDzk2ECun0RkjM}JnsqYf~W_9(Z_%Ft#lISrw?z|p!| z+zQeb^t4jcQ^Dz?-uQ<`S;PocZW2o|#AlokM%j*YS*PNn=xPp$IxTD?qx?|`l(LNS zi!R%vTA9b8SbFiS6TtxMo8*5jmq{^iU4&(Eal?#D0|8P)x4ctB`6$w;5b_>%D}6~| zIJ6aC>oI}Y^2~;F+KXcjp}-vEs;fFRjp{5Y z!a7~&r^%^*r_sHJY^krU{yjflYUmZF`f~&?{GRq&EQKcryvA#C zwEqsx(ceKf;6vU^qz83v^!Iqx@1cq-giZJb50~%X7%)GGyDna}4vRI4`#%PkS%Zv% z$8)JH8GexE@OwAKx*GaWNkQ5bT~n9As#y$Hp2X$o7%&wUT@qXwAJufc24yr18WmAx z6L4WG0YTr!FSlMlA!4bonVHJS*v&;6oYib9rJ3Gvkb2HQOoUM3ujh$%BD1G3NLqfW zp{s62Igm3zmQ?^tFJ0q=uhc!XJ|v>YVyV6_#O_oUTuvATUuxkVHKtPLyf&kOT`w#M zE&&)x6U_R*N)zF7MMxL~n*}3Hc8V?w>%0Sp zgUYl7%aIPJNXsCJ#fI0sOhnA+&-R2JZQh9lRV zvXMFeRQ_-~cH;St{ZB_5rj z&^J9OmeyU7}lSiZ#ag|K8A4BQ87qiUQ02u##*x7$pOL|z;!g&4!J?*xl9!ZP(3wO}2j z*I;*|5NH}{HcbcgzwYaPq$^izjJWEDvCZo9)(rGVatVI7MyZqI<13O{R+&D4Asb_9TTQ1ERz;F%Z> zoXraf`SUJ5A*EZW(c&%KSVP)*2H5JFEZB=JlHqq3A%E~rwV=j-~ zB?;8^CK4aD4Cb%K6Ji}peJOo6QD&4nIHSz3xAxTL$8N=Q%ZsJm@6d*Q%@Sy&>5ECM zPAK-ru#Q(vIeQ;2r+62`?dgo}8{IbB+1Jif;f(VNXHXB!6^SU^9GT|9%%QPUktu$d*0C8(*CVV**|Jm1cL-u_O- zdB=zIzj)rhqeLR<-OB8G!%UuEe|>~~em%HG`^=6$`xe8#U9hh@4kGI_4N#E7oQ_kS zX6@mQhY&VQh?upyj@2a=PQr)m9Yu-;L%TQzCl?&7b4`VvBtMAM{L0S3sI#OEZykxYG}l}PAd8SmWt<0& zBN>b03k49V;lobNHPif9#m5tiMPSY!!(6_{E}XFS#OGjMf)RF13OaUnrQB_~r(VE*K+gPI@H9j}Cc26)*-@EAU{9 z=+v+sGcu%8_dw1xz%3~2#4nbZxUN8&D)^INg30G{PJV8}jXg1p~~xeqn)(^XwX^8U3{56SYZLOpo#nyQIH^ zunY_^VAurS8+`~H>>GO8U|G6An>+Nhxi&5|^q_v3O}z3ls;Z8*ap(~_QT<-FdR*TR zOImf@+QUaa&J}=Y7fHP50|rA`9a+1V8}J_F=8kIja-+(ObIg-g;8$2XhL^Iz)ZGeM zy;{XEhlZVJ4iyiC!!p&4PvwY>qeMIj1Q+LVjaIy(Uy6BI-86}{3>zUW08qyH^bvEN zOiw4ZFoF{9XE4aXgTzlKlJ1oe!rSKPmr4hAi@s;0e~Agjm!|jP&<`-aVC3thDpG?H zWWg{Izthyp7x8pP?!{MIzKBFmU* zzMYvBHDQUMEW}s5<8NeCR+-6hJyxy{GxN<)#UhsUG&Fz)sLadQQShnKhC?%7QtYcr^}d!n*-8Lw;$w6 z4{nI8!|-+#nrE#VWi1%$)sMB&AL3O%h{=91Ci|f_x&{@jQOoh|EMzi{LlM6rv_>fn zc(8z>*jzO%QA@B!`O+E=AH(IZS`2XKZY)e)dXdbM5;lzv)W<@Al*glC}W z1)iFm3a84uK-MW)qx8DwXdBIkQrtE#?hB(h9~@1u!h`S8Hr0mNr(jg)Otl?ZQFWP` z9?+}(YSf(uk%f2WR{B|9r4yvm&rs=S>shH`>Q)-gsT4*HYPuq?(oT+n(G{q4#d=n1 zn7Wmwdj&OZ%dPbDyh{Hjm41#&KVQ#E4O6$$ZF4F`cM58{GOyA;Qt3)mx^g`$HB8+~ z`NCs=n`Uz>U6ohq%^0z3qpMKqs`aeYFm)^4H>c8;+)5GYa=iD?Qt20{)I_mA^j^c% zt@LGd0>7qBxs^%)4s@CMn9%wIaU~zz?y<`lrnb_KV_9Ps9kc|$2zrux>~0Wt>Z`xNTqp018Mv3B>l0D1FnF{Y}iM;nCthkm5hMcFCw>MxO;@q;Ih}g(X&ObN3 zVhi8g$qxSBK+60H(RF>Eseilzn;rd-HM(}QX(}_`9!{-$@!hsp@O<-F<>|D)X56$j zCJO*r>lGZjum&#w;fcT&9#!Z5FIp|?v~z;YDW#_r@v%x}@!>-mr|X|0I2+z$U-;Pb z8#?H-g$*jyqa)$Y%U$$&8jiKarY)|)GBB_}r)S%FU2p=LSTGKR-cN3k?6XwkPBCD$W96&1ER?a>2i^~L*Tz!)xU>$D2c)mz`VcBg^xjnR zcKk{6BOP&F8I5<`m{vHpN?5Brdlkg^l18o*hO?^Daa_!}3^ZvR=fo`5*#V7F2aG1c zz#JRy%R1|kbJxiUFm#Y;6S(8_AzN>rRy_~0Lz;R$0Y<6ag{Kex2B|Z>F*bk`XB$9m zu9;~}GcUw1AIdFE!&0AVW{PQ8sHXA2%%c6KsbnRx@nlWo6YXZ|oU=kF+G1DM%viY= zBcIr=eUte~;q|#ZR7mvN6ja+5wNX6tqBeky}|0^^UL-{dC0y0H5vm8!x&F;|D(9r4Lv zg?sobgl+D8n~XKUYI7hoblV(naPZ0%W5wct7!qiuISzvu=&^aqBnol4C&(o=^fIGN z*Z;@do4`j|B=6(lcm)qkJW#{~6b}SZJXk?M5gg5`xVVbP5R2wo5`j3N+}ok3BF;(>R(-xyrcRf!k;o~Nq&z2=>OyX^P>=c9Sw>8`G>uCA`G zuCDI4r;HD@N0p~%TwA>PJEtd?qWK~~F^z^IK%2+oTCYScm;wE3aeHx~U6#eP++B!7 z2@IW2%@pj|7q0N6puI(>^Ym(B@+%MxgpL^fQ%nUDS%C+O9=>L@_VB0Jti?G<1dZ+v z;SSgy(DM=!w+-uu_Z}yS#3EXV03sO-TiAL$!(lh6MD3<@pO-Gv8m>bPO((Kh%@Bx% zyP4vz(6c}Z@QQ!BfHd0To10!6Oad#Mo5qk0-htdHs60q)bU(!Qahiq?bOlr+P|N#i z@37*myXQ&~s_;%rA58f=i@7scCOxoC5-|fmziq>9w(a0W4_FR;TcR9dbYt`R*+FPw z(++5_vl1DFPY>D+=VrB`=ck74hH#)d7Laxq>BE_0QV4zi!1{J2?cA}b9@^YrI1WRH zK&awA19HwdvYKM!Ou0s0^H^Pjfz%zocTB?vY;GG~?8iJ^z%h=#=L80;z&RPeoBFb8 zLzx5L$>_Z`i=yuIWuo;T_(!aqt}G_;RY1ZchJ{FQ_W&(^>xx?JL83Rk$5Qwa+8-Og zS%CNv`K{B<%RD~)I=&@7bzY0UhgE70$t<_PoZwC55poZsD5ssrg1LGHcY78dq}jLF zY-{b(CCbG-WbnhgD2vb)M6BD3Meb93#WeBGO#@BrjV8hzEUC}OG_~cP0Ra>=n3myq z5V7$5c#sd@2NmMT#cb-^exAWwLS`RiW5~A-QZg(`LE5?YdXLE`U)>UuYaA?vMkz-TyePLT#%pp?F>J6 zOD+4jpZi`Qw@`DZ___ZK zY<`y#DCR~`bRo>621RFusjw)F7^_7A{dkR2;GRd4RE}%a6Ycz)5%OQ{9wW-HZQ_Y? zg|lQ-+k%DCUlgo)j?$6!=_PJ>%z{9RstD3qy z;??J1SLg|h^^ykAjwh#9{*MKteVVO-L z^_&+jv%-}5sw>LWnKJE78HB`0J-x$aJ~CzIv5eeOhULhWfX zWv)k=rqe4)SqD=B`~6blrErN;FIEl=V~M>vc2+MeG@$o{K`$|&djOPhWZd=3S%20& z?p2JB%b}2TxSZR@GuV1_OaUQ#`v7(q*V^v$t%dG-WUe%s9htc~GiPchHB5uaY$obW zm|3ow4an3LQo7H3%!F&Jz`aN_{SCWxpM}ii{No;{nX6G!9sKD&GnfgDgiA3sv)Pxo z5j1Hc0tfYTx6X+)`@a4Md6!QU9`gg5=x_Pgr%(+F)%u0Zq8U~QIQT9M5Fo1sXYoJ2 zgxU;a1s87Z)CK7hUl#Vd6}0k{k+mIL);VWCD2SS6MEk0!*iR1Xoc;aepw8)xa{ACX4Raf3+;KYRdg9)RfEG>Goj5(;cTEP1O{C^_2Np)Rg5Q07Xrad&13E z9%f^Q*Tfuyn(>HKYL7t`SPD^-GcCA)y5B@2rBzaUWl zfT2~3^lq9CA_C`AitGtOnG|?n2QBej5pui2HY~i$d_jsvp<(Gh?_8+*r+!By^9&1< zb*a5Tk_2jnfqF=xlt&6R-9o7^r-5~xiDCUaZZl3iz`98+&utY zfaLX#j0v*7mXT4euX#qsmfwOTqde@$IPP4Gj8|E^KQey)OK@cDET&P*BjbtL!sxh> zF_EJV+S(it{6f4H5QX5#c#Vnaj`QWw=MgcIvhJFfss201jEqxpCvejYSGiii_*31nSI_d!-AI(iW9~hOYN8uOL3WsXhlAYCLe9r1zo@Vxs!gqQOR6n-^ z`9YlgG9>$huj>X_ z;K%!jIt51YA%1eO+HQVwu-Yv`)sBca7%Igjr+y-R%`@gZe+^DV#{BIgFy`N7?f#fQ z5^4TyI7DQ-yok|r?RGI^ z{;xQ#YlcpGVC{L~<3AhHIZsxT-W-K|m!BN$oE!Y)VCP(lWM3vmq?+*!kX+rft+YmZ zXByTw()L*0b4`;l%F{jk0tFP-Ii`@>y@`1Mq7erayDPvTixoNsCp{i1A6DcRca-+! z=$w7lc#I3jlj?R}F7@a7vNf_r*;+{BA`ov1`Ua~#+S``1j_N_^A#6YaVu(U)8HVt# z=WNTJrq2lj*drA76JLJHF{05Q1;rH%U()DCx%`LrMtwrzA2;w`Kp{5!aOP>Tdsw-I z7-HLv@q@bUwx{Pz2aOdxrwC|OX8(p2pe1xO&M$O0YdcbFJ0e7#9C)b|uOI`$K`1m3 z6xdS>*@+Te*!VivgpGsvmw5iDcz*T!R9mU{idG|+%$RMS_2#OUSHj?3P1xXUVl=nt z+<1{Ed!@FtIU{kY&Ei&Sf1J^pT%*-k^q2VPOVM@JM0*TD(#{EfR<*ZprDxT&!3fxr zo+%MF9jm2wUSBC;)1(DHn;u3%VbCzeFds&y45hL}X{*M;=t0RfEn0Ai*H|`%EHj3@ zN(uU)u9nC#kR*Pbu5b(%`dctR))ui0fL72KA$k#^(OfC0EF`x=vMe0>Ts?v{W!=kd zl6I?`mEY#}pYXgt``>{vSSK|tI7Mdmr-sR6Dx#R9cM*Wq-L+9PVg}mQqa%PIas=kU zFF~F?p$3Rbta(wWy(y%eC|khF5CZr|bJ=b}y7gv-eP7IBXz4N`tza~k3Fd-h@tria zE2ck$Y!GUT`_&g0{^@x=e%Lcn9X!`)Sl+%kRd0_r4#}{jWM~n%*g{1{5jD>Ydqs-0 z2s5-u5?8ep^Qsn+@>`Vd-95U;%`UhSam>hlmUQCZc+X{24%dxjq2s=Mg8-8&dMJPwsep5J?78R34iR9L=k5qtWi3;* zy&oAe%tiy&xZK-_Y&MkAK=3ykE?WW=R#+XD;ARD?2M7ZY+4S1A(V zF_j2$C0A>dk{gF=a77mm9u$?!$JU3DlWFIEu^8%sU~mdWI`a22Zwv;4rG`vHy8aJ@1(Q){RClp_|s)kjj)-!b7{pJ1|jDLoHsfR|=Pc z-*rI1p^G70oThTgx??{@-N?zx=7BTZ0{i?lkp`B%{sNd&s%Z!@EL9BK7!0;AE73Jn zFOlvvV>H;K_drSjJd(ihDePk3bB9yEfBTRX(oe+|{$0ZT{s9*{?h+m>HYP(9gm&%U z%snXTtEy^pgw(%i+W%MK+fqxk9>k)esx#Bt6Ute#v(y$glR%Zt(rFD}(SBG*lf}L! z2mloj;1R}CSl;#e^pMD3yI7iSdjcJU3obml4~xDQhx8+czym=EL?nAZQ6fAFOr0_i zlJu1FdpV~2`aOSnXZxUCz~BvxBfSItX=I42{G6 zF`J-0V<~MsfpL@!#p|#G42ey+*s0Wmk@&F6$W?3C6<@c6!|(LN&+sme8HUACZLR_P zlN~~7=TB!E^(sRyI&1#+ku;)yIfW$c>}G*0oOU;0ITYAes#k~tAL8>QApCu$FZh!N z1tZl^nfdn7@-s~R70#1{(0!!`@mlFl-&9)~*Z{ZtN-MOwoBh%^9LwtZ94t-4H3{97 z@;4N4qyf|g!y(|7+o#E@uHv#K(5?ACs745EQtUcte;H)eQvhuY ziq91CA`cSNzW-63&oy^wPA)#G^Kv_>6X4=TkSWRFsV7aMtTMel(bKBegXeviJA=J!m&)F=F zq5g@Q@grEyU?1;c7rO?%Z|UqV!eH*(;SPXNxI%a@s9a((TKrU7g#@imt88QdKJytV zgRa@Zt3_v)5U%klVG*tB`lSlrc#dha*sM?qGMTBum--)tPo42ZDDt8fnP-b+6V*t8 zIM<;XkBkk2LHlh}{F*=IB_*?fiu&+8ZXy=PFTLhHdB5 zS5NxFzT`(3k%q>|m9%N6(GE+?C^P`Mud-cfXPKX?qO9LiHQ&VS4k=F6VX{uL8i20? zxcw$(1B) zKst;d{u#m*`iN)H4|4r!h7dno-7dc_uvt2&;0JkB>$Y|7>D4I%tC~!FSIODjX4z$= z6;)1tL1FB2qev^qxp7Iz`pOFP$L%E>8rX_D%F~jNAtE=aqEa(N=bdVY6i=}x(9xAm zy-C#jO4OLMJf>^UMn-(L8%nr4VV}1Wl>|%=$8GbeH!R9liD?xdqnOnyI2vYKYCr($ zkBo-9-%@#Kt&`N%7MNS8egnV6BEhXFh#~0mPXYvW#q8;#q0OuZ#wd0-_+4`sb_TL= z*V`=NVsq1`9AgTF1{#-fg|jmaD45^it+N&1;r8)jsa@0remDip0J6%*u!Rp{EO7sY z9NBm<@i*Q#;cW~KZlK_S%{8r>dI?9Nnj1#%1Ol7oRN|Tfz45MD9f8=NeHT~HtdYZ= zYdk|XpCkEvRmf!ZP|LkoRv*X^dMjRl=*p3lb~>3tID_?wx;wYVZf%d_Fq_~1u}WRj zR+UIPm`OLAq)PYKwXnC@MUhiE4Gn=F89{r77ed{iYl1(kRuT!HaI!c0Vr1kh#OP3b zGn)y)CmUc8d_O-M?6xawzM^pAZwT`VDMQ+5RvDhnx~wwHDxN}Hsaitb@)EmfTJPqITxtSb-aE6budKdlVn>~C-m zCeEk1$_36B73T$ca9){%b8-l0JA?CI*a>aK7OvoYNpWtI2j?C+IQxfit~gfPemij% z8l1}%=OP$@m~dAbPI+yA?WJhjznmOw`#lEdk;FM4y~wt|tT->qgL7OC&Rat`FETj4 z!)9tD{8obV6~(!I9-MpU;5;mZ^I(JXZsOd=;CxkazHnlE+uy`qRalmqCI#Ex#^5}f zI2obDwl7zlm*&BFT@KFaA)L#P(LVa|XW+cZ;H+1iJLbXJD+lM05Y9Uc&U=Y-dxP^e z#hE=JzU}WUjkf)pbg=Cg7@Wru=L^P;cwKS+!{97jIQ)JiPdXG|rB5Nng9LVP-VUUV z6HM_pwD>`JNIEiyq%%S!eSfsFZvIcuZRm-&6y4{4))pF#10kF-sLBO$Wq-oZ{7A!}`hIWtz3d&KvRx4u(&l!Ct_Tkqu+r zFSD@R7NYAueYKI)@0Ii$hnac=8C~{72BK{^1`8UOJw98?WxD``U4nqo_LaQL_6=tb zz!6?g0|v|A^299CzecOv-c(sSZdSqAy_nIg8EgNfv|!N90)i?1w zT>w7gn)&p=Y3N?}c9pOzTk>0mpF z44)X+$S1KS>uwv@$Y0(JG&1H`OedXZ*|^y<#pi3>-JE#s;xJ&G!zia3Qac7$YPT1` zAK2}DoWB?{p5&ts!4#}b2{*)6B5S5ZO{IG#Xh%oaM9uTVgOqob1yjr6yVc`_HO=a< z^}b?|@{{2g@RBe0le-6!Pe*bfCWfnm+y%i$+6Xf3Q`??cvA>YhxM7+NQrvqW0+#l^ zRyc!3qu~gn9l)hpk@;0F0@rfD(w3!cEY_ZS${_d^gHMp>tUS3QAVx*t3S;uHDCCC>s)j&&Eu+fv8Mh(*wfbr{At#3E z9X~nPU(fr=!Tx#}$$qsX;`?hqG2kSG=|Fv5Ne1Prsb@G3NBXND`o_KT8f5qZW}o*D z_LnR3RLlK!7CSt?zYgFi@%!s$8Z^-Wvul``?s&dD`dlFu;@&rU8+KkD(_d|0_xcO# z;lb!2ST>=xKjJiTHSQXyN^v`MLX{Xf_@7Juy|j1v36zzf+J$TqwrO`!qTcF%Ie)Ii zu3vk>l4>1w2BZf*0-fkS&p!`=x9%Aj5N=x>iLld4)|q-h+X7JnsIK$8@8UD zN<8^5<6Mt7ToCA-e#k!tRtSP z{G1~dx{&zOPJ>K#&ZhdSGao5ubFK6gK$^x6H?JAzB)shmj3?m9e;Fr%w>BB)gM?P~ zE}lim0P-D?19Wd71;4J*s$SJ!AMufLX8#e7thC)!)dPi;F+K6N6EeHwsa18xTkDK- zFUqo2_u$z{t6IIkRCSvo-%hK#Re#;jN6JZPRjq+T3T2&jD5O;tAaQG8{0%8u)i-#< zywCX&hzvlCia#j^f8(%cFp?t=?W}GbE zx*%l!P*ujc96wl=d8R8W zdrR316}r8aJ(s_-PW=&10VY5cd=PJx+5<>&%6S1l@oNenDd%gV$U1{Th3Trp%xlIO zgttxreNd}81V1y*KKM&)LlDk~@&hGtJ0K%%+u+$1l_LLpE!074E0HO|X{Wzd@{w|G zK8o#n2|rjii)VK&J9a;5*J6b}Ov}#audLI4h*Q9R$~Yen)^_y(8esbcKT+??e59O? zM3HqK0u^R#&cdt8#caHBY`(UyRC6yW%{r5TpZ_w>NW8I$=di| zs77mk3J;bC=ndvI<4nXGbx3c*q@3&cz-_@L(qk3;1wDs{p&^Y|rC}1@NW&G{0p$wn zcr<(n=94pT;|av0G(Ty|1MBtXHRF`wjWp~-n3OY)4}|qh6&gq&pxH)4gKbAf*i9P# zt-UirK_5en+B-KI8p@Q0ziU3*X!vlgdCfRvH)-fjn3QuRA8E&Bpjk=?1PyE>)}17W z?ci%hSV@^=Bed2MytP5fZFm}zr{PuE#%?FcgOp_UDM0u2NN#6HE>Mz%j;upw84 zii#{D$$f|;C4}JDgW`jdJ_F*Z$TKuhXtdz1cq0wZ^^$_@Q-HpU(Vz`@!i<(jbbPQq z$fs-@8rUa_iYy@w`x7Q5eTrX)iSO6SCEI9du{HZngGa;JhK5s= zhRaO8kBa*I%*4f^pVfEoU8XEBgs=sLd6{b8uIYt!~*-aXD zAxz4-ln>0)N`sLHw$adF+mUguK_Y3`Lr3Ho7R)*?phoT1I}Hs}m4>r4pKUaJ;22dJ z$ZpcmnJ_8mB0lg@512;yW#oZvGzD!tG7eeEf*<#gf|uiG#yJmvWmZ`oEpOToF3&dX zs$#+NXv2P98`_&Tw9+=5rupQNA%$aH+i)@7NXmAENjVqrfe*Vf8WZ*ye`Ou=$P~1E z$VgZ0j!eQR=g!3&M>OT$kW8V|dZ-FW@+I12qqiR!WZ9m?8(V)Zo|cZRbe5@^eX6L) zQj**aPk@Tv#)QELK$UB2m|Ay;n8|B#(285eJ%Z__pFT;~I2HzY;T%lbaKA~;%`KGIxSLxxVFB9i zvV_FL`JMubl)%j`3!jlF0=rnMaOwqyT*%+Chunt z*v4)=p3I~xvLcQr`;EaeJ}#r*7475;rA>~Et8$^TbS7!#C39i2=R#3Xa6VF2ym7d) z0)09H@PXTJ8Wi9O1K{1_w|?2d3Z1;-bfPx1#CEz-HqfGy#~u9;USFXsJc> z_-{O}H>_())EL%{7+$u(D=(aBbcjf%p_HyB-H zVk)mQRa=p&C{Q9Us@p77byaw{_7&vAZSXamo#DXiM0L2~?G?V-R+B1f>Mp*16O#G! zp<&5hs4M^vQoT6jR+sYp390~@Ry8{kV@?94Gc;m z-LyR=(mf;#5w!dGXlH{s_g3skLENxwF^;<~1MFQ@=P&fUbN)9V5AU95*6)stxLLo5 z1wym_+P!jS{iO*00V)2h|E|Ck6sMeeyxCd5Y}F{ZPOEZf`1=M38#u#P>ua7FeqV4A z?5n|`5=GsEPwWf$g+$Af!#y=?n9Yj)7CQGJCp~Ml{yth_mr#k=V?(ue4>EYcX=EO+ zHG7cXE@1aCj8jIf*@K)=H`Ws*Y(%xZ?RSU`I)NH%Tm-!%K1+@{T^}$ z$C6v;Is-N-2~pfSB%|0l3W|QY4HY599W2HBD#Z&9*{Bp(J{QN}I=AhBEyEPIX^G;u zCYe!0icd#KhwykmrFip=OYw*E<0)=4V3#n(ZCj#v_aMa&LeUDvvaCrvr}o>ZJl-b{ z#jOV%8m8E3iQ>y`bP0L92CNl|%?{G6z8jU|t8fAA^hcrg0F{WJ4pwUIWU$^bJSKpO>ghnm^H>DWdP4yA_3_j+?#1cEEr$sLDr=%g zDgIg;m;gp_(<**{{T!u%+IKfY4k-kIk^S|WpHNX?SJvDC`Sl;Xp7YK-MV3F+R$&4l z&shtaFtV2}XO3kT9!cJ+2MV(T>xP^cG(Kj>=OFx|{@=J1914>VvV$2lNP+4=Ap+GG zH11=GI9!SN0v0hBPFSID3^qLTbUYDMYeED){f)EixF4)UoU?I>I4BPh)Ko$QJu8j7 zSt5og5$_+gQ8_VpUOXqLe1r&kXd3Ur9~q%XC=n-bTq1hJ5+V9zGs-0|MQhqg2uLUa zZyjj3V5HV<_>t{^6%e`NX2Fx*IJJi>^ypb}YU)@RJh}GLGm4rcc9dUB%!pn41FFm> zszH(1OM}o;DAeCCr5ATt0kL;*fNz;Cov zs*&sEW^7*yg(ZtIhTh1@^V*n`=UZa@*<+^AYPqYO%J6EZvxciw!ku-c<8EPpnKj4} zO4(7CGF+#x*ZhWrMZi&t?NNhGba*OJUFpvIUcj+@3m=ZV_3?nDuv3fmLwC6na68rk%;Yc!&Mof+p_F38s&@x+~w*D4)j_ z+q?Tkc(n0+U^B4Rifxe0PlZW)Zb|MQO*_N>ca&_OkCFk4uizwKBho$@E^!$JCla{~#B17`?>w#~5@>WH= zWrN(dz%JHH>lz^w%RP}fi59MNHyO}c910{>9SR=VCH;dWhgVe*kvo7S8>ek$6t(Fkm4Qe&ISXwRLJdPV>vJ5Lso(x-wgY9XhWd1%@ z2Ck+I7}tA#K4AI?ib9X;gb(GOC`29d>VOX73tw*$5v_L_%eFqI(4Dtoq5$l|lr@hE znFwEs69v+&qQJNEBsl?b<|B_dhh-xo&f9HB8-BkyAE<4}BhDmN+u)I1avb}aUKr^0 z6+N_{gFO*mg-0ZO*!ZA?Gh9ei2aN%sn_$p+y5&F%zzP6xt_4_MXa0T(@9_vJi7!3Gs@Ya+AO}6OV^`oxcy{Cxoy@06`bn5a+?+I z{m8)Ic|)4@`v?9Z4@z(48Th1Mo8`5nR)n2dk%50Q6o@yqH4Tta zzesUSGPvxhZyF@Ii#2ytGNwNoYW|_VSyjEuMeE%+1I|y ze9Nu!xXgbjig%fRfOHVs>~EAWGbw?M@~O8A2Yr|MEP*K~PC0ksE#fkdKOi(g8%85P z<+m|r8Q24@&LrlD&KZK0Dhiz97w}x>M`+eSKdU~WNj+>*z7r9rCUC!ec5GwDu1(yT--s#-ZadQg_lS|lT8^@D9_5qG}d|!KX>^UOO zDc-_4qFST6dJ$FBhhKzsJVrfNr%PeH@?=rp=lP+s#9SE~iMhIQg~*IK1x?2ZTaHq; zytjLJc;tEyVORw%p1$w{pem%ob9&xdgg0k?qmEC^iHh*3`+X5!QksGgmXww!ZpvLD z-lQ~8c#bvXZ~%k<5wG9ZzoPEI3h@}YTTp0wTS)d-v+iqu0hnG3V^@rxU>&PPKI;~4 zc4_pAIP95*nteC}PPvn6){{eZK)-MBfU0Vwh*%%TXWCh8vuGw$wk9t%0EUJUK>&IP z@_XyVNZ{pgEjTUFBQm*djzbN`WhkK<_#P#C=cdrLYkNeRU!Ak$iKzC$W2E^=O;k5> z3|G3#f03jd&2{Cyez&)D%*fqMx`4g@g}&z5X4I?$}lUiY`h!xOdL24$kNW{R{TBijHm?`Nfn`9lk*qy%x zgLRR6HOiy27DWl&BS`2l_|I!|M^Rs&$U|)fu|&>N-+8?#xU{pC1*ZPc??M&g1jr`) zV`w)4l!_&EhOVkQ%C%f#e%{sV+{g4aPv>?v#Js43W`YHl9xTw)RfuiiT{9xoDY-rH zC51l8Knu$wCH91B0!ztFRerltr!3QgI|r))dWbBI2=|xfnD)-TXZ`KnN)b|+7k5?F z!s<|4M1}Q04al*2ss4H;=qA6Asw%W*VG;8{T@BS9^^Wuqz5sC|kx&OmZg^OG_xdTl zOlu;g+xwNqP+Gc1D6RioDg3I7*DQ}h689Nc=M#tD=qdLJl+BTw5joVwZvuU+HIc$s zcJV5Wq3}a`u>*?XA=Ls^fkJaMDQT1Jh{I+M80v1$Hj=9mKloF31sIuUybbipeAS|l z?ec?_OuG`DVS%MyU&L{N3q>4bu(kUS6v^RV*C0_N@^7L&tQC-deQaH^gx#$!`TB3P zhud4=vT@Y~qxbZrRNOpS_ZO8y2puPXd^AnR48?r4BFOG+dP|2QeBk&lo$Vi!hJufW z#2LS#oiX@`=vzf}Z3q$cc&f-9A*OUh6?M2X*iX4?Xtp9EE56&YB~iMSZf-Ly?ZL&G zHc*43a7zzFMO&Tjcm~qcnC3CYGX;H~gK+7A%RA#7+VG>KTfwryoiKq14=$cSMv$9j zfzKoDL@@v>lJrYsf5egvxWj8TvBREBOm}=~CqDYT%?J28;UbK@erQOJ`SQ=A{@i3P5e{J!=b*SlD-hfp5EML9rzV5k8LCX_QH|;1R z!d%~VP@qC&x_<`QpzG@KTDa>rRFR94^ zY4_(RO%OzAQ3S<;V5T6LSpedBOA@{SFtc#p>#$VORoKd;jbE6gS&*N`@xAjhW<0lm zrMH>}Q-H+H&~z|yVRae369dZ}j?pNQ4K*Gom--$kDnlEQd zO0AqhFO=uX+F2@Kl(mbuYf09&WMzTn-8fZ&ef>gK{OYgOtetHZV_|tAV?V^jr{%&! z4A$`q)ZEcjYBzv!?aTI%m2zI+D-x*-r`M-R_13z9f;ZoQ=CTiBCD+2ClVp{3o1Mg{ z(o6UOry6#j*_JB!sezm_XL|;wtyt+p$8#0;Ghw-g_CycEIO!uk{0b` zie{4Au_PR;ih&!Q1_Si6cWsN_-wc=WfgWU005TjqsleLhk53`Drz%R#@RiN(vZ+P_ z;8W#8_0qYf>lHk*ubAu#xUc}cdp=TZ129?G1~loJ0aPz#`qj(6BkK|M=GR!5{Be8b z&Sd4z&s%E`wn#|#972u{5|WRTQfxyxsddQU87Z;ZNl8(L>QzSb>SSgtoV+dCFt8LN zQkcGYYhDO@b>W2h*uCY;O_U8x6}>i5emC)0*Nbo1~0Q>KnQ85Ytf$0RG^p znA)D5=-n41dkio~Dw2|}6}B5pki7Uf4ipQF1L>*WKcWB{d8;<^(V|#k3h6Yxu0G^E zYkQtlTP#whLjgFaD9%$OI7bjFI#Pz^2x!f@f>Sf3MU88=)y|uyhzks2zflW!he**> z-gPJnN15~0AS8mW=~{eo;Rdudm#$7Bx=sPzjb|IWZd1e~4PtzKXC$(%BD`I5kB+Z4 zv}>H~ox_e9^m$g843EWkD9#_ZG-7NuOTGb3a=DxKdsX9f39`_XJw?wv}~ zxrQWYOXjGy9MYna%H{PV=SZWC43Ky;ChyWp)*{{;Qz;JAZI3*EW{6R&{e@?uRS65S z_zb*s{Aug^ynv%hsbUmxG$ktSK$3ZvPeJ$U#GKnV~d3wV54A zok%14h4tu1xtLPAK+;QgK#rLx3Bc{NBy-eA;hPThc5X3DS2I}e)jEzhbwC6Jxxth> zfl97UPhI5JKqaQ72~>*20_2}SpD3YBMJCY9A;Ro@_;M%EZ_v)hv$oX1cfYpuf=y#( zDLjkz1+&6~Z{ZnIw`S-?@aUnLigO!-6P;FSXOssttGT^ax88v}mQ`-3_7`C7h1*gj z%xW;n@C{?t{<{!0sGX%G{nd~JHOric_7@E6A6s)y7k&&AMhQQRK+V=l3T(RrH-|r{ zS)aGF^1K5|`?@`LVjwv(F%T9M^YMEo25HWJz}CU#`Pqtdo`H!W!t!yWBL|I1ap_F{ zH4{Ui30IhSxQCQ8%QpER3(ManCOVI>>{och<(#PU2~)qqiGMZ|*~3cjj)q>N@DO?w zoyBx+2yS7QoC?OS&lLJkd+nwhq}QZYZx+)IvU~ISW-*<4g0tANQ$)m>5kHHm@CO@L zrA0IY?7*OVL|L`Et?gQbox^2;VF6wiGIH+)@h%08}jFcCKbUYO?I~BJEoL zNNpRWNk(ep_3)p_ELfwMPq39DCLZ7UkT39n^v5)}kI5}vKy^`2GSKht^-qvDoGeT< z9I0$NEHXPLO4l%R*edak43~Ws?BN$0_ES z{%>Xbe@D>I{-5oAtduF3E%?wb_WDg7m9q=)gmuJhl?4y5Fxd{{(n>fy!r=oQ$=or2 z|B0Z?d=X6gN*a)BIcZ6emd_<{S#iaR1UB#JdXOTq0QoJaEB{VLMJ%VA5KqtozFe_+ z>T_^r2a%blmD~FjD7W3sKLaj|!dgw=-lSVu+CZ&z$q7D1DOvtCK7}Y=B7Rm8FI?AJ z){hpk5z_Elyf1n%Y^Zfq#G1hmq$KL+E5eHn!c1}}lxo@TNK}c@K|qKRAI9i7lr!LZ zrZ3bAiv!yP#urNV7LZWcfD3(8(t5O4jAyo)m{Hz0;YN&s3o9<;s=^zlVOYgy4jO~i zKwPQQ#$b;iE@QuZCHjpyAhrY!&g7}%?2?EHME;e|X~c?>NXWQSVS1`M@+#|MNa zQPp_BS~HJ5r#)Qp+XjeCu3q~D<19c%{f_U z>-U8K)KW+nXcLzHs!hlwcLuwt)M`DY#uP{+AF)cUR+JjERjGM^VWpN6Wf-H>mj5Zh zX)2TTE489=evw$6^xKmEJ`V@Kz(-~|5wow;`QQ$0Qpb4R7yYX!$ zE4{t3vQ@pYbLpl^K8uDzR1EzLJr@y&XSHS9QxhANzXELn+E9AD+fnB$Jb{&J0hNoC!0`{14G1*Dt1`)_PEtw|?V zd*ORape2PGlyNaVqYMH-$h(r+#rTvi<2NzWX5HdX5yMi#CUZkIvgzDqtk-qdtr`ZI z`L1xQ7EWkrM zAXy}@#p&c~0)nv1>+#GcUHl|SHu;8mLn6yvxT%chn|y?sWDlh8Ve}t;=)VtJp;}?a)E+-2tNLh5^maa^TN*(#X7*p8YJ|tA1t9{jv;i67TMG%K_F5!a0xQTbgWR=s)hW?0dao`n?s1=s=|2_9Cq%2 zeMfJbleSOEH74!cddR$tAfAJemiy`nU!=d{ATPhj&u5f|_Yri9-K=@LfCz{gaoU{1 zd1;RP@?%>U$rmsy|7VroJK7VyQf1zxe+M|+67w!VQJ>(Ogn5y6umM)EwW~)3u~Qm~ z%_VGDAks2PCmWa;+6KAtNHRz>D3aqTlVJ6=xawX~IbYzoUi~$WdzKHI5>aY==r>NI zUn~cV+L?*~x~ESsHLPUTYPzV{P~F}k;x5ROSKavj;*mj$V|b2My# znESw{%XkoCYrbuX*yEL0Z=N<^K)Tu%3eMAZN|s2o#hUw#jB?@upEdCa}xkfQrW zc|2qIs0kaD4=R-5bB^5NO{^&$x2B*3A64fU78tyssj?DCtkLyC2dK64M3C_{#SWDM zixW%euV%bAo4aBC%STeH&DA4_RvHD_El*6yoz%Bggfyl$w+)OnrXE>})>&T=Aj)wr z9fjWd#&D%<0qZCz*%je(xSE4k2b8lZ@YqlV)ye2#nAaAdT(_O{oKgKG#dMRwWY==D zaf=@8opqsZtqgbT7ZQ|V_v|9x9vc5a8F)s4k*ZeLWUY5wuLa|33JNEEK#hU+Rch{! z|FZ34tDt+eRl%Sr5=oaquSm;-$`?%*FtzCKyOfeLyrytrVnT66T5{5tL2(Z)FK+cM zKU%chee@FZ=^xN?v(oZ6pBBVIA3`c`(VSs6hvY#XCqw(lii_hwoK~|qpy8rx>RJh* zV$o?@w4*JGzGWX(y8CBIU4jD6!z%~bs|eq_*pp*l$e^)GjhN*M*K;aS6s|d6x1<67 zlwm0GbYcAUH0jdLIKP0W7|Jy3FE*=e0a>R3Z^A^+Vy6;gBjp=nI2dKZH+-&PsgPQ&G7QVc_(55HgZj5UJwF~R#MwdRi-F6O5_5Uq;~DZ zCKVH_1ZtvwC9Ks#gZi^WrCy{W>~m-9QMy5~^)uMK?q=oFE8RaWp(`daJu2Zp{VgEj zbyNhY1*bs5utd_e^HjQ%a^?I36)(zp=Bt+E{DK#NEU>4FooCAW&9+e40@hP7n*Aa* z%3LshOME)%x5m~5?hF_WX86w4CZ1%A`dF($xQwJ*734r4q|#_7uJ?fi@?!Pk|dEwsRwHmOV)qeD+v> zY$z(e(wRhOJe)pe5zgC`(y!dGa3bbAyuW}w!;o+uH9&+Dsfo%)dQC;~-mcj0G}tg~ zt7O{D&ruXNy^eqv_RI)d7M*p6q8pk^T*MVR3Iv4do7G>$vEE?a%wn}+BtzjC33Bm3 zn(f@@LA5nn?OR_O8KDMD_c?eK5BX%>+jbR5C`Fww)5SQsG8}W$W++dq%7%&q0$(O8 zd%ksXMcaDh!QupdU^rzPU|^Aop~zp{x;WMLC9o=Z22Ee^eadH8Sos`a%jGJc?M;@|AM3$P`IG{BT+UFy)aT^{(v`fRKnRhERNj=9pt|b++3!?WRdh7VMF5bx zuk2iE)YaFYn!f%$>I&SYx_Zo(_0`qgCdrOQ=+ek&%vD#-e-J6GH&{=%So5i?3FxYb zy4uStBkHRBOI252K{*5Rzfe~XZb{y?sIKnO$=|B0J3k39v~a>b7&t+7HO^#P25pGC zdbbgl#84WbnYM|}rvw~a=RCi8519635wW}2^6<)23 z#)UYO3L0;;V{@eP=;IHyx9!-3ff6wU(S-KJsd{^k_0R)Mm0YE)q-&5IzfiH=YOtaE zv<(zm(+0bues>#zl~C$$N3iq#aDWq~ooj;$C}4AnbZEJY4E*&;c7UA>Er&fUe__DqjU|Ft{r zL?t7?JMM(yvQ?*8H)&7}y8G9m%^kITEneUJNMvd$8d+zW4>lBIhmY3qUYL!UbD=hW zwgr~m%9GJg)#^69miKqnU7}FehoH=!W~U~Hx7)Fcp+d4QKB$b<)YkfeR-DeSFrV3MkE<^!MFXqQ$CdGiSpQ(jNIR>osK@s4V0x|W(f|;! z;%Ggz(ehk|dioy0M$B?8KK1967pCPRSd^WpEEw+rV3om%3z1!M2Uxc{1631=7yF<_ z7nKdyB)D5bf(b+~b<@tM$M7W)=bAb;SR3@-S1JR)p$!ff83o0RCr3~U zCO@<8T=2%Naau^810TM&qcH32^hVo)Q%G&r*#WOO4u}uIb;cV%l{REP zW5b+n@iXIWg1@bhxb`htM$QF%Xn7XODUYxUXL}Ukzl^gf-te*1#VEv&FfPPXN~N8T zRtUOUqDwntq*2b}`s)QgQchbwvd*`FG*$h}yk?wl@W!fE;i*-9h&NPq0}9Fa9`P(f z4v;^I9H1LVbQob;)fM`yoR5?<<4vh514vWV3+6TBEWsPAT8yVw^#tBf)iEf`s*3UK zq*bMm19XEG`IGOn=bQohYbYNn=TNQc4nUf!s?2M~xeafuY8sweRXN^JRT0Xvst$N| z)vC@y4$!qz>92G6NI8$AaKMFC&|ky(!1n-A7KNSw zq#?7$yk?xo@J2G{;K_d(ry6e{vlGg)s*c2=RgFOo&=o53+INNdo9eI5e59Nmh0HDR zgJqdFOv_$XFZpd0`bI7Lo6kRleW31tqlVV#*qgMb4kSG7e5k*+CyK1I4}O_u>}_5% zP7l2Cdx$HROEtT*MA|8XXAMN{i(gjX*h^BlnZ@8A@2iDfF;O51_otXFJh68*s67;H zgR#z>wVYifxlV?xRhovw&D&))4!nNeLKY+rYmQGQ{=}7?BgaSq7Bpb#g%q zq**MGOIFHsLj&v|`YP^TNJ_*2!<@D5{K9YQxKmw=skr`1N7U^=Q%drR3wtDH3xtbp zhIQW+7A0!2vwUqGx{Q<7w$_H2e8O6ZXQ{JB#HvxbwC(KE)}=+-Zo!0XX~U$MsPXRq z8fK>I?I8PT;>x$BwJWoUDQuxySD8h8ci;arVpS4T*tG2x`XK{tQCFik#2R~$^+~gg zGqjTyxH3`zCMnI)tc&O?uK@T{L?#t=cnRR&6`r*i??bD2?{RKWF6VYrLfEUHzokuPyV%aKS$zskuJpj?U|6_E9V73{_}(AyuEa1<0)y7y zo5y?R2ELOHbSa^v zMZeUuTIxPktt$;E5WMM?dJAuzk+Q;+$~gbT8&vB!l%;yS3Qt4C9moL@qlq=`IKmg_ z68$xvkCe<=DD)^Gjrx1Yyk?w-@kVoL+sDORnu(toXFC3}nhH}5KCg>6s@F3W;|%~n zKI=9ZtIR9rf4otl4kk>>xs{K!^UTkpQ18O8jPu27ivLqQrF_~sQK3IT3ZN5j$_()~ zf8o2uc);a`f96Os z?8W$%apvF$%RY>!bYc3GOsHt26WwH!qeLn zdX|>GmA_y|pb%FA8D|H)u}z;Sl?UP{ezoNz<($dtv(DwnGmO5}yk?wHcq5~CP!j*f z@@eM+33hQt01ZDHCcI^+ZtNxMIQEgWy_DocV zf;ylg+XtK_TVe00BJl{OjOx^D#VZ;R4*@lrdLC)1*H*Zju1+PMbP=BepeLj8Ne2)0 zw3GLBVsW+W4sNcdoTlWlb;lS=<25A^b8%XY20+dd_HM`RY#|#(jb$`)zaUiFX?{%` zkE9w7GG=|LSs&P}GK8I!IBsWb(G;hRM-p3JvL2Vc%fCQJ%g0HZy8y(CovF-$N8{uBaQScp_i+YOis zebAp3boUVGg>|>~nYg15^s54`TdwqLrTa@yk*41?yTQw57cT6e)mOv5rGIj zWkIJhBUQh+p>?bJUUyD;c!!i=ZR`cXtjvb)Lusw9gsV(ZY@3RRJuL@tAfWuRI1HKk z;*@cYhqesbXz2ldX>6xX60rqYZ8dinlWT=3XL};L7v6to=^aRz?xQ-2=dD+BJDLZm zLc61pj$XZ!?P#7U$s=wkBjR@O(To=z3EnMkXrDp>3JBa?x&zm0DfZM51F&g*N?;nX zjib)lO_aVr82S{2l^&vFAMvyy`e>^Vkd>Z$F_9})f=Z-1?rVO<3I=gl>9P2D6b1Me zhk$(P*+R4LHQ8v(Y(KMuW+uI|l$XVBkq@z@LYy0dxUlY`mzt6)OQf?ZsLCt1iFhxw?Ynr7GYnelc{gj@BEhJH=XOPG0S{*$M;|Q0C9}!6Et4Um+ z2^5c~V&fO_j?aVnj1EHqbHc=n4ufiR+&j+9mrYN0+4DubPdfFsyT6Ud9YAuqoQRz4 zNF3?$1lCI?fiI6F)*|eZk)^!paV<8K*6M~59iJ}uS&O^ji3k{mL#>5*K#=mpIzHF6 zuvpI~RvTu?vuR(h>VR`Kw?B#(H?-A*k66vaF!2`j2mK2x=d#3VT#h)dS-F8i9yj_Y zR*!$$+eq;DEzX>q#~wNY8FBW|J}eNjhdP^-fIakC--tc*;~bWvJ+umM)(#ZuYA#NF zTbz1{A{oDVaeyys`&p@p6*U+%-c6~0(Jk?{%XDCX;%an-2uXE-E%Z7w+C}>CY49n`^?sh^$))dj!{m zmyTOhP{PQxb6-ScTDxPt$TVC)$D)6?^>A!t2hk{(aW+P?e|yO=fLj=HVyZgk&7daM0V$xPyxg8Zc`Av7pmHttsqGXDi+{o)}SWp{0IS#qj2i_&tIZDFjm z6vJYXuYw@Ald`0jEf9N4tOkG8@1U@)eAt*9R?QB3XN7$eQih=j4#5z_<*Oy9P-&Zf zsI{45>0qODZmXt#Vg&A_rKei}+M#-9G8{$4RNOTbCInpLK5U3Jzxv@ez^4gb&5d^9 zJA(pUI0F2G1ja3yF45Y^zlBQ;*|Gdc1$7>g*Hf0J~<0|JO0}|anuw?pBg5{9f zErFqe^BcPmvCJ0X8FYKU1=p>rW^Jj}e@rzWo5~!UT8_buNY_!ExNP`_ekv=K=1yv^ zoJ>+W+0M7JEw!^NeHz(B6)F@Ra2TIyXNE1L))kdY7n$bt9>|n@u;7mhTVi3s$U&O) z7n@|RWrP~XMmNs;CF&1Xh(QsEY{870XSPNc6UKbVd?z19nhs?gvjNYTRnF!mU0Kw8 zQT*eK*XSxRXkFuPQ0{`ex7J^00nDlmxFK?Ob3b}Eq6S%HH0Psk>|%5#D%)Rijn2iz zPz#}%6IdX8TjIfS?q4$_l}4f>ATMGk7aqo;JQ-TZtU*zEU|MGlxNjc)SRRN`DNHV+ z)dV8{phPbJr*cF>cKrG`CZXpaN)E*nN##ekZzf?NPZIm5Fgck-{%@$NADEY_ zvO2Yh%vcg`j}=BvQrk<(Q^`75`8aWjkt~`ASTQx;hjfvwz6x-@2N2uIF!F+@Zfc>) z@IP@$_5Ebi2H&IMwz8n@r)UceTGc$})K1Tczos&*e9kFk)49Hf^Li!^mCDDV!na=E z-QQE4_V9>jUug^SeI~iLl0+qQ*$duyi!tcu%r)X-4x&I=VQe?7H5ss-Zi*aD|9&zSrydYU9sqdSdPWe*D@E?wfM2P z)g1^=4+@sj5OW@4nN&J%Qb7q+v?mU+L_r87=*jq1U}Q$Z-5?=FfpE8^R0X*yYi=W7 z__87kE#N-$y-bsnqj5-&_Y3rOH97a+OfvnI=hFY^6-Zeg`)vNd!Ir=zWAys~TWCG3 ziP7(^Y*AoE=d5eQiN=tAZ>Y1w)MNXG==WUZK0O!F#?+Yy^xFXC{wBIJtlZ_>P`+~i zZc(iCZ%jf{eJR@U%DtetpD6eLOSS%!gha>E6Q|Z^2n+2P(N(t?3`VWjEVS~HN3Box z05(LRqH6sw(15fW8lQ@&^}Yt}?@{YFZpyAOYW>yK@}ny1eaQClhI)(Z&k0HZ2k|ww zi4ZL4hKN_@$8S(kz#=wZEITStNTf3D9AuNk_u_xCtecVw-h^kMoi>ovZa%5I+A3m6 zJqD!O^`QA;+3E$pf?^;7n)`uGvfoegzF2k@%IiWgOz1xj3h;CoRvERqmiMcQmHd3e zRuD_%1OF0!)-O?NW?5j_nC6=L%zN>rofC1(i2D^lIj4kH&|hFT+FLS?;F2eom`b0R zqb&YdVs3 z>*v@FptPM&>7(;~(PX9JIDql1R7^fs3QK)pk3!o2v0p5E9A$IlX3qYWk0%sgw~7lt z$WA$y%cbE%>Bp*vJSbEe8he(Kz|h#;o)OaXgvKsu64L98E8vG(1I&XgvLcjI+w$&v z9l5lkdm(XR*j@4jTv@H~Aux4ifiq&5&-hsJ`ov>))rN%Ec(Pl;i26P@ zUzd3vYY)I*0OSzZkSD2e#|F8^~P`Eklxxt<4*ZxUQi@*TgF`^ zSw`dYai2G;FozrfzjlKW}r zKwHQ^C5FDGm30biP|9>rj?3*bqddCIFnx{=s4r`1B|FITS`mR};GQa6YpU=t;5@Ma8`$nJ_HqjH0c!VBYLib1bJ;`=B@pM4$$eP+YdFTeNcbYkyqXn6 zL(RbPS8bm4-T6E1>}%1MjVsmLBp{U7)(Ed_DTolML^TQOt0f1hJcA%vQCYlZfxC;% zH4DD}iR!}1M zOz#CNB8eOFczPLJ;+ifn<~ZuJ?jewrask5eWx^VV#z9z*knkQ#+D}gy!Z!|SzwQHR z**K^kBPu%+#x)ZzlHA6N!r^#T!S5}hqNz353~=xM76{=@j##vza0WA|g9G3xi7qu6 zSp9-`J(YJ09^a_Et3x!*M&exwQN?hlqD7uPr98vo8)YB7yp*KBHH-1XhWFQoZ(-!w z=n)MCfCL5uLt;32kp$$L3@Ow&8@mCO?tP!dm;?9hZOwt=vL#RjY6|4)&WuVhO{@27 zJjD{TPIwi!-LVm7k-yFY%i%=&fn~ZWk7`S^sb**WdNb?Snc}<~L}&enKjExDt#sTp zo%MH_i&=j+7&XQrWM=(|!Fsd)CYNy#k2KkK)*t&Yl<4MfQHh#J1ks5Pzhm)Qb!eTw zds+Nxxpau?0c{Engx;2kxk+TNnz?pTJ5ldV})_o81#q2(seSw#qkN!7l-eMpd zz8XLBex_VY!y8&Z}2sNa3yV#HE^ zvq73s%N#c6N_Hjg*Rh3kLacRn0$Csv!#})Z+|j2j>zp^+i^M$#uiT@}IDf$#<9E-- zlm9Z#@pxn4Ycw^zeYvCX8$T(-=FJnMY z$CLk%KcE~t@hN9G!Eld?2!Qh^{WXG*l(QI*jPqywWm)F2Qb3nZl(Iq}u2a#nLs%&5 zG_ZbvWt?XWC6_ZJ<*dL@l)ayil(S%#K);TMAk8|<&1=S~$6F_WUP+jg^Aa8z=Q;dk zyI%Q_0_?mZiF*PWY3qh3{~>>Z7TQ^B`&Gow* z%Osvfmn7;3Z!TT_j4i;y2n(|W$B3V8)mVnIve`03!EP~NnZ$fpw)}W0H>~EDj+aNWD|5lfjzvOj;c#0mnpk3hTyrfanC8b zXWcL100F{hqaL!KclDGOrR2Z5sP5ZGM2Y1;8HG$e2l?67RuD_%8L;6f$xA3mY3FS%w-WMHt1&pe zCc$60dky@B)in1w7K0Ht^KfK1IPt~#3+sGhuCVxHiCM1U5%tDjc(etU9`wC`@&3Y{ z473SdLZAC3TJ#rw`jBTCU<~>G!WvMM)85Q3>u>Mdijd5oXmQ83_ahCHsG*p%6O6y` z&we4D_R;?Q{=!W)^rI#^@$a+&lpgF;`oV)OSs{ItQX2(d;{$sXl6A5E!jUMO!^dlP zj`A^HEzi=L$je)2w?yHs44e!ohKJNnIxA3UjwT&rlkAAYW$aW8bsB}5qZn4;JM*51 z=NWHpd@`q4^s!yO%Gk?f8`^Y%1s2QA7uZjsveBU!gRR}}peu)ehX#piL9t$@6_9_w z%xZ~$Cm6!MQNmuez?_yw?+MPTlvX6F+0nmHZ7{e?;;FJOoIG}=v|16QEdm|9T%qml z^^ZvdqQ?~xm`;U*-;idrH278#9T7qVJ)SCZJA&98mh{}w_7iVm7#mz{s*Cwz#Y7kL zrTUu3#eCEnk)^uRm4d+rxNx2`@t(E?6Y2_+%XC3icZNcAwdg9GivhvL;xvSF4&TwJ zD@4gU$Kfacfem$MYr!uckUk+Dl{RaHX1#2(GKq3kq(!3yTk zCwMbb+;W*eog{PNHclUn5a{+;#v$YCmq+}w=+LYo$-uZY*rYkJ#j{GNAZw4gQ zc7+&3zR&mwoeJvyqRm(|Q~6|^7H~91S8nCumD_Wxh+YqeG(H3AqybfTu422)V9Pl3 z?t%@@Rox3%EmERFe&BaH5sBvqHb;lWoJJTY5H@RjbK*D$?Ld|Vzk|?K4B%ABYH-R$ zyYc_f)u^x8M1I}@tI{59wn5Q^E*rPHVD!-d1TZ>f7_QaBt41<5OVX$!LDLGD<@itq zFiDDhgk6fYqVoYY6``fJ64>LZ)#Zur6_iF~Gj53fUhdK+uvc4i=7^#q}1e=T-U0}k*nz`at$KL6mbpBqU%*{=A@|GMAgE9L=I3mXvjq5L*H4swmJ~R zjZ`AKTOul)k~=USFz(SC&V_tu^QhqW^H>r3d!CLkQyeCVQPGjIa966H-7$--us zQoXC8I{zpy4Uh7-Tp8s^#SM0Em{DGTv0|&3;fY&0YKE)wLpqVg{}VR-zunf(9GEyp zVWd{&%JIvJjT7ksKH_>*6O*hM&c)EZmrF&aGWY%tbdx`f>^)LOfxX+4PYLz{zby7org>bj+nb!LVaBT zbxF&ptBKkwkP7E0f%b>YGwePQdrt-Ja<4Ea5LOtS@}QmC2R8d&{G5XUS5a3u?ldw4 z*SYc{)rz)D&1gKmyP&LYq{fticZ2eE#NFYJaT%3^4jQ?Y2&U|tOjOW52GsbDYdu-L z4Z$8Ew=r+GhcMw2@>^@QO}k5-)bQx(Rd;!HLMdk5tKXHns@=Yf8ljyTx%TuJ5aZk7 zxg)f{Qby?s=B7}E)9)d$&wepNj(8Qzyw!$eim+h8YYEZb!@ z$V7Eane4q`ly+iy1LfJJ?94eUr86rVF^7qy$sE0~H;G9PJiG)xg~MT$fhiDI{Gaal z^=P_uY0L1}(|1xhh82mXw}XIm$K&PE=L9}L&J`cPx%C2LGiXOeyn=6S;f>6)RWUcO z{8f<1M^BbP1|SZ39GCxgQ9*j(Yk0V?IQVnCi9F#jc3WcL~Rf^D2I3oI3pFj=(0YB;~w@pVmCz!26E2M8zQfKe+FxH|zy>1J*?Qub?MWMja#LJsQv>X1c1>XGl@7xs-sJ{S_T9%?g%bA zet<^+BDQU<(Vbm3UAImG2=FWlUUp$jpL*uw>^EFi?jb$(2s zka3;&wMh}zc`qdwb9I>1Dks39WuF~r1lexD=A4}$`hM62}Xw$D#O;@P(;e9|e z=sKT@BAC*{TUKp?M77ZE?`Q?&-ymC8EMc;75a6FV!?1avklB-Lp5oCAqX=FSvnTm= zo~?&d+6MS1q~`Lkk56W!MITG%4!T29Ljgc{+uf!o{X(k7AdB8^6GE407SITTB1zP^ zLzGeqX2^vwr%ja7__1`e)<&jQ_!Y+pVbAPP?_G0iV&00=s*9p#>Ih(PRG2D6Dk8xCI90W}qiW6vwuXaxJ%ipHigc z*rpbLZ2$H%#Js4idH`Mwg$3Xw?-P4j_HL#}dg~Y(daXW*W zoc5NtincdiN|q{8wz;FlAKT^xkDnsP>{_`un>NSqT0NnDF$ga-D`-6zYKsd8AXu$z zm}L=AA;VFcXV>a)K?fTU9iojUBC~6CRtOROp+#;x5Szo2k^;*T9-NR{gHj7HNn+SN zRUnV4&A^^oTAutK&!BwhuGalpQ!RM)jK1dC)!Kn;taPGuVRyC_RByxO6m~_f*4gQ5 zQ#z9}Qz@63wCrBRqb~ec5;&s9gRDE za+A+0X(yW;O^#^ra%pktOt#y6;EJz?1@d_$^hc@oM{=?ZnWY}#`I;y_w4qHDU~S?9 zSoFZ!Q?4n~y|15_!wd&0*C{DKPf}7^?4Z7AN!a3htv(?kcDAN6Bt z%2Chl(qAy}{vd&c+_Q-3bbcJmE1ZuDQ{km zOtUqmGx^uZG+#~gK4$aK9}`rN9=qv(EYq+5lE1}9G|UGM_cWxmDAQc-hGqJtlzaUDls4zgoRx2@qZx~kNljUO9OhfAQwGbkc+NSUB}jx&g5Ss z7lGzkxiH^axb4ROv0Oa+Q~nm0C$6W6rc^|?G^G4ax%hlp9=WJcv`?q3T;>x(I{4DycqZj6ByQXug`qDn3%`)<;9E-yFjOq3ynI#HL_}o&5LvugllL*nEs9C5=5Mo9h}I05(v2*d z4=lc!G&-zes!YK!=n)Ro9t|o0p(X}s=)Qc_Z@gl3n6JOyZi*T=pq4iuV+=b3jfq+m z*zdfE-cDnC`bPa!ZR;R|Ig{K2L~N+qAuJ?_kN*o9-x=$tylQ7(k#UluG9DnR$ru;r ztCS~B&<<#^UvnkBXT}#spMU0axdjF%$P09;w}jBZuCY8*nbI8qbgKEB?mx?voJgk* zLrWsp>c+U+r~NZW*mmM_xXye8a->0yq)H%^b)5P7>QIxFN%B)&8`|ZBMVIqoy4?L= zTBbd|YoW^rjmd9)o;D`G)jDEKx4dF>RaA$trKL0Z*XWQy(?2$XWj|k4H*83Vv_}XJ(hqR?x$1 zHNC^uOiy=gx|WYVhX_>GUA;gyN8OLL=JrDG&{D+TV($n(pi?l%4TbycOzeu`BG1$* zAc}sqVO`g- zu%n`4iGmPBbTt+f3yKBBf{OSmDkv5-8Wysw3sDJTkD`DbMIj<3Sh9#MHbk*tzai+0 zohJN0pP6&+J$H8#ec$i*`Tu^;kLMwG_RgGhX6DSy>F3&XrSn;0-pKtBA!@f*in(bdP0r#+>??R$di}20 z`YnpkNf03k=l{a{*LT!{r`;raSY{&`B`MxV+$^%LT+H{8g~S^cNH9}`ZiIsPvIRHg zon*2FFQcfNTSPaVw9Er7GL&Ga`cOA(aQlSJId@j_%?x=>{1|3cGN1L@OZp>xQ8Hg% zkK9HPa;Q%zwWC6$X-dDOR>9-Wn(ve1e3 zgrLMy)bW`ystKEevg^Rv6jY`=h03Cvf{^^&X;cGxtjP+kIDi^&+JAwJ<$KD(tETdb zKPC3mRhzl7+Few>H*e6YRlS^B5PyyDA^)yMeuFPgRrIH{x}$0Va>--p>xMaexg_O| zc~a3rV?HIZo8~ao=3tlcOGlUM-hlEPx@-BP=&q8w4s?fG8%1%Qj}paIT00c|?-MJJ z7~w#&88O1&Ul!g3VJ>hHcrGaUFTB8IBE8RUBGWw=mI-0tp(BL>-g=1L0_NkOVVyPX zQaC)oy|`J|+G7$ITD<*H6f3*<5Q}BUf=rthe@2DdN=C$%w+G5wIZkh1b&^-y>7bRo z9Lf{t*h8z}`%zlS5KR{@|A7&Yp|hFwSgQlqh$rV&JQjk~HY*s5 zvO|3Cd+Gc6U(P zKjwR?LZv~*Yn1RnLx?792EMg{j@TH6y3#e*6pU$4lCYa&J6l)wLuYIMiIUr;UXz-VX7yl5`D>(THvBx9ih|@1cVA%F+IoBPBheO5e9^&-baegXB?o zxKO42-(Rrzfz)o)^#2}dB;tmU(lwh3#(YbIKmnVS;2lfg+@%s_BYGd3tj&HZ%(?kpK6_?l@Qg0)t z1bLxB2aL>oIcBI$guDH> zyP4m9*z+pvb8fNnFS~4Bpw`&OA>6WHqMRx~Hs;GQyBMt4%S+v8gKR1C7rTugL!`UX zyBu_t4QQk(F<+j!?`k!r zn%MNblF^e!@kGt^^Xt8GJdS`tO)r>TYi3c%UG$SgGZ=#si%ZSLYJ-%!8R`P1e)Gme z>Gsb>dBdC+P*FzH?;wi*_D856+2<79!Pb36V0yQ%>d(4J%*Xs861`Y0kBTZhvJK;B zR3kE`VZ;?|V07@^hcpbCT7)(w0QJ@??`P8`<65GQw@~YcD?!(gpc&)uBLDERIJS36 znCzo8%?u5O?8N8*UalMJs{}s`*E&-@n=#$6>P@b?%|-*)cosZQi?BNoSiFfUM`^a@ zCR>Qs3P>wjOtDv6Y%)&u70m9lndxD3`v8Nm+^2;5ak2EmnxL5 zxw2qPxdA3VFTlVN%}du@Fk(R6RFmH^TJYK{O|VN9?e{M@8jn>YFp|akn^Kk&Vs9THPc+JdGr_ej1WYZ2g}~Cd4Y)M%g%R z_vwhp;XWPFs`Vge9}K+17@sDv8@P?HS;`bEMUIxE#>~#{`-f_k+R)yCHIlgl3@gPM zYWwCXQJW&fX6mZ3qfsJ@oEA-a&tDc8i;3S&P5d5WtZJYdO~Me?#BnBI6Z)3Y3YE#P zlKJvZ=Ale3O?vIiZ$1fHCtpZX7XOk=La;M6*Mp+P%guVW(%{fW!`qlMRNCW+ew87v z*5Y;qmYLSEo7qE}84(4uE69FME>y>E!izPbQGPMYhTLbV z+&xW&fSYOOTdDEQth$R_3H6zwDWf7wK~0{5-5s2op66*_HHb zcyq0pqA!&JvpVKL(Tp?0(U8ybHVyO}U%3m#nB_G)R4~VFB$keRlbW{v(Vw}iN!`5)?Z@G)|riUs#>}Mk$H;71cD<`s2}eXp$3aC zbj+11dn__$7wE3b8nU0#Ju5w(Iaq}mgJ|6Qb9 z-YfOalSQ@@lHaRWL0r1p&NPA@=p*3}O?bXd=!7xN+?jdD*dHlOqrdP%qYya)E;|v4 zHI4qm0ah512-!o3ZrZ%Ot_3=ZBsPVAdy&mbvoX^eAh=k$do?7`O2_OgXLM-3s+B?I zqE4}Aq%#fB4u%Wc0ClFe|GojbfOFWv*n)}b4#pobhf9^C1EL)L@3a6bACq#mX}}CT z1R1Kuy%JR?#w+=~Fde>xSWsQ2RQFq|RE4w%IN}@htz}UsW@p49QRZ~GHZyJq=zGpK8{M1fa3RWW zG)g`a24;vWCQVP?n7!~JJdDRu3%ZpJPKwiFa&_~H8=n-vE``FgC&dqX-SJvZc}u&p zqr8nwiZ_>6GAT|D>e!A-UHnVy;=S{YOO#@st6;(>3^%B$D-=7+VuLAjP|1{>o^wZz z&bq-FABv)M>L;V7%Cx2~;)T?hhG=NMykRX#!#ebK(MINc`R=c|+L&pyQ6O(+zMR>j zo8{NaD-&-r=0Dzb=09X`{?De&KOZa#l=%+@8=C)k6-+|4kE?12T4K{}8NoXeiovIz z6)A{6XsY4~rSD?t&5|0Z`;!{xzk_r)xRUly<|CEnuHjM+Sf zI)vh$){;8elC-^VZq#Is73LeP%*N}2!D6Jt!a>>Npp?0kN&yBI+G{+xE;gzjo6K^6{+lare2#bCi!(NL44@FOWQ^BqO3E z7%}A4^&|=;&nwBvQIcjP=^!M*`h#8An0zo6Hcr2mwWqDJ*=Cw*+Y1<7*pT)+)%F0% zRTnm9YeD{?fZb8hG0MqXI0%3Iwh76RFQIUGqzcEMMe4NwX0^MpL8L~S-@g!QElw6T zB%w|vT%uh&LAnbYC-FT*e?d7q-EyRI98sn3TlVJrRNFD~D7;vx(tgMLgN2Pbn!cS) zZ+jUjv7FXk-HE|%p2z}gyVF(kG+mA>764qFktT#Kvv!6D&FiV z?6&8KYcPawuV4cq91Bx4;9zZIl^WuAXIs~b)wb2OrshsQhH9aqTDTXz?x8rX41o>j zx3$-pDl8O=w11RrTf&t~0Zyk1&oc*R7ob@2&aqq#U?yDCNENm<>388If~+QEE7W2k zsq%3p3twWHIeOZ*&*H#LgB75Q6S{7lre7sIG_(Y?1&ZRz2z`BbvYPS^Gs5H5 zOyM4=Jrvc+qHtRR7JOvK39x%AHs8VK-Mj@{c;=R7;bu!v1gcp6=EhA0a|TSJ+?+V~ z^GjD0Bo=+JQodk=vzIrM8?zF4uw|bYG&GXwSY*l!%VN`+x{229A7=*DEtbIb9>&VM zc^Z~|8(qw|ow6b9(`I)59PsLBXA zBWj$w9L!q?5HTmVN{9M8kjGH{P?q$G7ku&8CjVQU&dmzYN5Af9tAFkr1wPgCsG&_~1l68H zL))SR>R`Esg!e5mJuX#vpZrYw2Y?w;eWp}TS*oGYJBn(>~Mw6c{%2ZLW@opm_Jnt9++7 z#`Bx@bNr#m4|XyqGwv(~WpD*spKOM&(?Y5F`00&l{vJlfRM8V_&=4=2hvV^o;zd?v zpBWaH_PP`|%|rhcGJ3lMWI(F%_5j4sPwa{(|J8VHNrv)qyy8IKz8OZ?@h7Cyt1 z|9~&*!tR&1lw>I{E!=vw`s*t`65a)P)Oa7@FVhmoLP4FcX_t^Jojc@f2mv)vBukYj9%#UF`me+gHqS&ufBYwy)*D& z*Aw7r2CVT00BVPfHy$ksPr}a{?+EcUjn-X`lo2 zKmDjg8x-*$d{n}7*;_U=WH0HhJJ#WRzJm(yaoS>^2Kp{P?VY>tvJ~%&BYl_G%p0fg zG679ELR{E)sT3O4)MP+bx23BjK;epmnc1%Ln6@W$l_zY=hA@Kq%n0LqqyOSh!k;Yn zI1CFPfj2f%)Gc9Ahc{Z(Li7Rry>b=x?n0-i!3?{UisQX($vTF`)i&Bd^=EMy*k(&M z*e$MsDF1rc4i0U!m^!q&{;9c&S-ZfIs)1rI4U1{gXfe03m{qx2_&eQVx%aZ-Rh28nuX)HksG>iYmZEUO?1o~Xp7#*ao2``H1ZW|UH`5*)M#s(~p zU01ddRoZc={+_I*ycU)icVb{}v6)#*%V&d!^h>q9=@(FWx9zl9*vC6VZuax8z&q(l zEZBv)qLk(gMo9mImhzZwI+9*r(4zf)`DC^rY5%#U(*9P@(t^GX3AZC5D1J0q8CG5i zDgNA%?#yEX(yzGKWc96Pbx%n64hfOfBPOdlr3f0dr1umlQiUhh1Nr3W%fiZ@~m73`Un<EiG#S-i`FMs>cjs&WI)vVT^ChRUoN={qAC7NrGc^g#p z(I=szyJ;yyBQ!Pt&auD2d9hUxSQKj>#Ih}$Q9l8rHn1SOQ zajcSZ(z%dwW567y7JK4jm#OQFpZ=x6(fdq5 zsoph@law|yY@7@){}(s;T^X2ns!^ZoChgc0m$jm_|BGG>OE)Q}n|!Umqi!mb9>3MXocrKoGkTYsuO)`=y*hH zRQ$jCq2hl=i(Gdro0_^C`Pcsp;UufwzO5?olhW5p5U|U#8_^$55iQMtY)J*Hz~D^q z$6#Gep<@z6T4=zU$%X{P=UQSc@4!=OcQe;1>PUmCiB%vb#>!y0TlQ+g9SyMxboMLM zh+|B#UQ@IVQcMm~;OiIsNR|0gBGPs4m9KBmBf`(g$W0;5ups^iLn$)dpqb8-0Ll?} ztQGH9!dYwpa@W$$^q>zhYV?1S`MlT^^`I$8DOs=s4k51(v!E2VMe^0sXG+Ti|1wnM zQMTnZ8PTzHO_N(XqR=f$*W{0AR^J-8Sa+^(fxn&VJ^bC7hB|Yp#{L_FQoNb%ofa*Q zZBO`A!rjG5ZwlUv$!W8F=xSQAcN^ZK(Xn$0KVy-C*?P+SJTwJxTFCF6Ny1cN6G%)$ zUu+0X`RgrVn6|`uWvD(fuZ)z)?#Lo`{c&&b0){iJ8F)XpW8)?*;6+hp_O}@(y|+k| zDy+bS08{rggr?QKA|#wDx#8YiN*k){gn(i|2b4KFEOYfcssPjK?ivt!15H+4O;)DW z%?~LKQLf%SR=Ii%S=CL0HAqD@Q;lARm@67h;ggs$T?77K<6dxykBIXxN?@;rbxp=> zh+nS1+4jx+ORaJblSin=4LwzjPuNyFRdhWQpQ?#{WZr>_I#Pe*qZ}yRV{Ul40DQs= z{Lk=Fi){aYA@qM8B4qpj&nJpZ=uCJ?1siCoTj*yqYFnx<&b7qSQa8`@&&tI?p38ys zNYP(dk=Z51c}oUi-&`s%42hs-r&HP)v1<)du0~4ex>iFHYDMbM&Xoj`%8@$ed;xafEG%Bo1DGAevn^SlaMQ(-k)SbAjN$@a)%J zvti$jq<}$wdxf~bl$zK?M$+0PYWDA1M$)lLyb;u!e5Sk?EUK}L(EuVdxm_yd-DXp; zf7=s-h149(W{{w@8s{R3EwaZ{rDNa2NEhjQ;KYjdJ(P@n4@;KO_oy^+t&i;Z)>G6h zKHRz(n@A4K8GyqL2XOO=GUL2U>6(rOzT%`BW|mb{E0{a16alg zvw(9-bo!^T+J%=>BgHG3I`e7#hXr`A79gx1Ara#n8zq#Rm)qN5Ek2mRym|phyA-$a6N_l@uJT~&% z^iM_8?_=dh->zdorCDo&!2=%-;qG!s~^wY(J58W|?N&B*D!f!YC`xj?>>&C28p zE;Y!(N8}Lhz-G%XCx~9=6u<8CU=g;#-wH{~>-T08Rcp>ar;F8I3Kk5QNJ?#tUsv{~ z2&L?h!@Q&s-S%WFGkdb^6uaHn_tD=(mUtVhWQp%m_LTR#DY3D*03VgU>w8C`T`Qc8 zru7Kab$MM+{`EWmXj;&WbBeFx`-{P})8K~Z8(uv|WM+_DtY8C8Sg~FkP6sxU(#3a*jG~N znD8+-E1%6Aa_Dd46Pc`L_rY3(Y%a9f=VWtSo#@Yos@mJs1;>YpR08l8OblUzoMXJW zS@}6;!Z?+&)_YnOr@5#1F45Ac)bqoFa~S0(e%8&(-JAsGX5}62D{GL!&C1QdC<5`q z%*(!?eB4oK117n3$mHb`jI|Q8J?CIB$r^u6Re882W>t!-S77Yq-`)dDN25TRWr{nw z%t(;RuHU3)N{xMq2nc^`AV5v$o?$TahBEWKB^F!zyPK8A80wnXLJp!4lEM^wzzE7> z3#m;VeecX-Ob6_Ew-|&wd$V#GxXF@tzZs75Mc&+2@}Oo)nd=cO8(7(S~`QS)KoZ4;Wj|8(>D%oMWqY|-4s3gZq%-|z} zcB-?24VXbCcFD4S4$+YFYagRO2`_zGX^WjI+;txvICedYy#tKD*-5ExWjd;7((jSU zp_<7v(M&oAD{+?(aZ`6Tsdq4`yKCy5fDx7@LV zDl-RL*Y`H{j#JTjBhEqnqQ}o2QaAS}RUa+rBTHqQf3f>Ms7Q8H*;h>a7hwfV%1ZR@ zjJ_r=qi8MG0@OfMv>qezr$B-%UG;wSpX=&1wG#ULLThedG&|@n zlPK(x?h~8R*lv)+ucKUCOrrI3Fn2ZXtpo4%L1D7iaCdgg6jCo@3Jki$6W_e_=T zR8&=T$M4Zo1G#Tq)tRbJ%;%Q)Yzuj;NUEs}QXi|}6v$R?q^?9tUY!V4zacju#mbM= zitA{IFE03Z^)Cgj<+P}O%t_Y2%<<8roYDHFpjB}P{1KvG3eH)?1l=$;XG!L)@msxw z57>xc=I#d$q)W9B<>kR?uc-FF+aF1SGmYgj<>XGAG8L-|I$^75&zx#%h16t!xf*!6 zIg>odCNk4g`^u;MaCA7ljOY%zZ$TP6ThyL56>^@7p(=7_e|l68^rtrpbF2zImzI<+ zb(Pzt{wAg(n{&*c^i+}2uGyK_9We7+FtI5Nir0ax#|jK*V0+d50*J~wUPXS$q;$&C za#DpIH!@R9JEE+*mrXKrDEU&8tR{|oOmX@%;IuQ_8GMS_a^Bf^YQ{~UOjYt2|K{U} z7N6Q2pF-Bm+2*EMtjY8>f`!c-U=T^nG1$`ieP9iFa-}P?m6`FdfP(lq>KcWdWaK~0 z7)x5Vl>_Mr(^z@Q3ON{(Jf#%_m#G^JQs4ELaUg5%0u48-Ly_BZd}j_ctwuo{g_fJc z+3hVKj&RUqgTnTw&6m#S0|yc&7@^Er?j^7yggttIGTBEY;okY+w*=6U-Q8CxuZ{bg zqx;AQb!!$f4mVm|GkQW3G4z#OA~_#5E_iyI2m>a(bNE zQW@s(adV4x3TaFk163J(rgLEB=AiQY?wQIE8--z739OB_bZ#f8-wL%OoA4Pl z$lDoeFjwTvu3*glB+JaQU_#uaHV0t4Wu)r|`#MsP%*(XpjIqaiBW8>@JueC&f!Q4Rz#is_{2CMtm;p#vt`>P@m`&hzFyl-&biNI( zCl)Xji@l)MI>kUT{W3Z!tI2eVYX;{eox_DrKFJDJK)6bb?;(R{s9dIc8<}-ZR*1+t z2Y2W=M+s*BS9PHb+@fQ*^8Q+X8;z}5`;pqoTr1AD;(u}aJbLJF9k==*o>RkvRl{E$ z9MrneFnzmV%vD4Ok{kanm~a+fBlY>3da6yGid6^A{a?$W5_hG16<^rPp40y8It96c z`Iy6~XWM+75@8U#Q4tBO=7c34U@1|6)9UYXAOdBxE<#=%^4$y*Y1MA4|6>tIklTgI z|2GF2>8(j$hqO{tV$!$ZXs6jTRBjHWK4(*;Vv7TbTd07xic>`&8~}Dc>Llzejb*Gz><6(0CIQE5MpWd5BW=NJWapAz(j z&1S>we(-cHU@@ZG5ehaiQd*>!K-FHZ)!D`p>+m+<>e1hntAF9aG^Bw`zqu?>M-k(4#D^?41aE=QO{>eA60RgGGGHr+8p;o$;aa{XzQSg8fg_Jqf`!b(f<&sf#Sfkf`0$UKYW!U^x!dN#kl2OY7tqY``>8Wp-^ z!_mZptrV{FHKRrJSJ7bboA+Eje-O7%L08YBMrdGdcIV>$2+u#FA}}ypeHo{;aBL{C z4!5EWc&aRxV~gqop-=3)zxZDRihcS632`$~E<<%~jf$~mzaWuVp$^7UMP(hE=J}WQ zmbg&`nXsj;?ZJ2_=lo(-1+&3Vf7S)T8D;&O2@MX2__J6Lm5{O6a{8n|RGjq5Hjy6@ zdJsOuk3yzu$uIT^tpL|(P3REcyf2c>Acm5dWupB|BAs_i745MvLfJ33fR;y;K*y|L zf1BIPlipMl0Q$Vkin@zL?0?PgMi8;lC#)EE=JuZf;Ai7W@- zc15b;%7GZ(2TC`_(5YGrKL;7*nvLls9jtA~Og~iOGXhTT%BwFH3;akiMbT_#n{2L( zX0ud@TZP&1-thVpB&UxR`Ku(QwAdY$D!QF~SB<8$lVP-z9j2CPf>(kBU`jd;wVxSWq*4F+^{<$W9+)0j$42k(dF%u1@{uI%?EY7C99>y3=CoYz~ zMv8#yu8}@-k#LQ-vC6vj2r%}R$uG5-E&&4r?t%=HUOT1el;Z=|{9jheX zAEPR$WQ`Xm+g?u`zR+tba{_vl#*U|I@hkSS0bnfF>b;?$$8tSvHMogCHnwEQSWL3S z#;SjGuZfL=RBiWT)=6)FJ`x|J0RO_{=t|>2Ixaf{6dUAG5I>NmLw}Dd7iSqR7W9D( z@XYtyL%hYv4m39Y1rdF^rrE=!@$ZKRqt+$%nL*(aV;x9d4r(dN3`s==Iy&o=G{wR{@)BUTAH zjr+2JmJTU{jRU1b(kZS&7<>-Je~xx2sBM zb-&qa$XT_&y%C;>{8O2FHB2B?ioH1ZBcwC9p-9;pf_^2PUtRCdTDh|{HmBTg3*J!+ zI1d?Z0jkDl@ZLa2{tMLy*`B{!U|2aUvPjr|Oe}G@hKbv40$x5Z-+_m}GO~~CNR7+f zLdv_?P}Rg9%ddMDGx$;+*Ju{U21uOmmTcGuWj6JmS~qXy;k@zQv<6PByzAqb9^&ux zlF`%6mmfxGW*c_35sf!Da3M>Kc|YtkEsH%?hY^65eXWwe9gxS$WnjBN%fJrfT}9av zX|Ge_N=uw`;}t6gt7Q4|^{v|LHOapsNzhKhtW`Z-K#c8M+!`jYa!wvM8!zqv0$jWi zN>ljtMv-O+3K31-sHJV%#R#8Ei|RWWlaZNzv+Fr1Fz1+zi;g{NM@y~Vq{Wq+;!vx3 zb?hq&FE=alngBVCwF*)HW9ggo8WB-XMEXN8Z3UAw$cMLRkEsb=GW=IKK|1X@!hY}=3E@-FT7+d z5HF*5L*%3;J1~-rBBP5dk%e`OPd?Cf}7YD{3slV;24!u7IkE#ihC@tGGvo38sL3_PVRKl3w>qd}yz`#~`sTGqezcy<3wv zHOY}{e%+JC^eZK!9Np@*ECA=SY`jc*C$JD*HuL&Oxrkbk^*qz=MmyjAtdXMgZ3?S3 zo$tVYse9>suP3XhU{iX+`m|IIOc|(k%GebF%A3_f8N+6DZ#rT4fU^jKWLN)WJ|ed?lF! zllQ2~@91dV$lKbKO(vU|vU4)|UGq@QpAbe_4KTSCm;{5fgeuA)Zh#UdW0hp*US+3= zVMm8-*m;#S-zd`+8|^}IQ?41dsmF;8-KRNJ?_k4cJiq=jI|%QuRdS&*Fxv(F+Y!yO z)5QPEiaDbB6J0k6p$}+L1Hz*6%Kg)-#R21)+e!W`u?~1@ap|f{*}S-&PXB;v81d~I zCwM+})Al03VrZorTys2uUL5AwX0k$WSqSF=2HhY?$lg9&8}(e#{W)#wA%ONu(qqLN;Fieu(GT8L;t7nRpEN>3fSMp{}4vfVmJ3mq^9 zq~v~h5Im=L(9bfP^yY4%nbU`!A)MjpQ>>%kVF>ByaYLBlL$=$y_!jEiJ5Q)^Fd(cQ z@f>qu+~N+_kz=U9Rn0by?2Ip*Z5oMoGwok|DI_Up0Ab@S?ZZH+WHT~$}v5?w=%%?>b3TbSn+6IV1n-c&%Wn65(X&6lja34A2HJ*mmG*9#A$ zv>pbm@eTt-r5%bV|J8VV0ix2@@TXPU8Ys=np|s1PVWYHMBvjhTAc070idAVKEB54f zDB|fKHK;V&mQh-c0`R?6aBGwXe4wea4 z@R!CD+D?sx0~+C<8Xf4!__dZbl<;;T>##FCOsqKAfHhtrAjXO>RG<5kH0AxgLSjV^ z{z`kj@#sKq(q2!1S`obf@uoD=@E;Toh&)UcyYX%ZD>YsPeo&%2@#H_?w_PT+aJ%xj zppE<*tH18%BjF8{v zI6|q<)U;RdSK3=n&l4$L07NO?)_QqIjNE%jH93%4N_+ppqYH&edzS%Jg$x5k%RFtp z6f=aR2%gM8;XQ=hYP@3nAX70sjX<0KEYydSEaknqt%%n{e;vn1!W$-Od*KJu5@!Tz zzE;w*0YTcynwISce)Z-f;T^$<!SRsmMn)w-_~u^LczEypvED_FA)~_b`k< zSP?#|V|XW9c=6f<@|)|@*pWcwx-@nW6G-f1R7VK(jyG?di`Uv-l5z3co6eka>JCnJN%vBaW0G2^Dr0qMZ)rJVRm70O96tQ5JGB`(eE5}pC6hrI zfSJRGXD|oZJ{4Uyxb^CwlhG)vwVE$kea9A&lT{2tFx`OjWx$%=;R8+r))n#?Z(n5{ z>BFap%;H;=(PdXTjP}RqxGGzpH-=2!Y75B8D!5&Nt%H>NzVIka`A= zypr`LN_~%^{*RCJ4R(t`kKP{X+YiNL$$R#2NBIrNdzxlQ3u$We&Z+!C*xv#PW>OQB z7;hdKO)3jOb~Um;76+lJinx{_qub;~kCjgL1rcqF|g=$-`OZAg1J zyh%0Wjw|04iYh7Kdj|(v%^~3X>!d1zxMB{4-|r+c1HgoRWgXTW3g5&Wa>SLru5jw1 z0e3wjWb=KSeNKznN7=OVH;-9jDK|XA>K+Qe1WB^gKj~i%Q;q2FSuKG2>tV~v$=IEk zU#AJ1lc`%-;?mLhuyxkS)Ol*eGsSLUH~bPArskQ!YW0CP4>Gl-zR!t-TqjeniFiZW zzXrBuGBWqk-4@9R%>YiOo(5*KRC4R(j!L>AlKFpkA>@@v0atYH-f4woXeDv?PI3VL z$JPWE`zTr+do?L`1!o7ze#$2`eT-!}r>47byAb9!gNRUqto>X0R-*u>1fmVb^kIQy zN$*~C8Un6%Y~%V-1I9Tk+?Q$gMK{nkPvEU*w8T_l8|hW0{We&Q@xR0SEOl?=GPR@2 zRN1yJQ!q|w^ylKl5~v!rm+NxV<3bKwDA)jptNsX^`&Yn@FwNr3KI<&-w44w-JHu` zqofopAci}#KnQiQ5lj^wwgRALWrZy%XT-V|yHFzRzoV^KCD_DX*@@EkDN~-OhB-|k zn&KoBRc29*oI>Jy1X7IG6sOx1I-`ucuVf1c2+WfB=i$ENDH2|QN^08eZCYCzrkaEM zuG~dFnQHD9+~@-r2*?_kXxaxGSh)7~ksk6{iTH1RO0 zgOT!mV6#5IbI3cwV%o>PS9PMqfU3F*2qDes?JCU)hWH;(OSi@)9x#=1Xk`jDn$mol z+Cr^X;Ad9cdQW>#_5!2T9z1gdIvRC1apX{k@9kj4Vi_-A3v4jD>ulpifen_f>c%D* zZ7D)!^ipQH+6v?VoNNypIwZ3d?i{qj|Cii=hjsSfomO}HR{v=O_kOr}a&Nm$6P1EG z$rwSkz_u1U<}BALTWfY7vo*uDCjJ>9$<=nB) z3z$T|9PP^?A&cYee&?JlUW&8tHL>~P+2$@ z7JI2=^h)*UL!k>Y3q3~iT!5SwL^eRrD;YA6JE-Sr{s-zPG{O#Q9qcRw(ZcMc zTKqf|uh2_nvHAW}a;a%-erDsc^n9nP2LFQ&(*5BM&6VLU&>Z&jCXb)nh8ER#iH4#V zO(OZ6MYI+ULD<39DInDx5xpQjmUf41l({v+v^C(j%9=U z<-Lt>$RKA8Y<7+Ll9ddGWv1;bAZ?PQcaU4k#ZDu1(!Fw?-G&xZgf#sL{P(B)Tt5F zAQ#o$LCMVKn!g)QT^MfJeA(<$rXOaT&;7V{ETg#@ZxSFNNOR+Zgds1}Y_=H`=-N!T zX7@1rhkP8=C?9Q5h^=^XdZmV*jdmL{UYU*3_2!jEGPEU;G0QRu(Q`^h&&eCPH3ka&vgD)3{ez0`|WD_B3t+V!^$h&2+C>X9iW6^iHpL zLfKwT+)#F;i`qJZ>gJ+;#R@52$FKaMwSr+@RMlbUv>3=eM`3YCJLB_1nONRl0vH!E~$QQcBnKjha>~_xG z9cihT#s!{eMlXK`yN>ZOzUb)X2TTYzI(m88q(x_-Z1@RoGRe^ynRRNQ zWW@jPo!GF~2G^B`xu~rpsKGAk*Y$3y0WNA;1l89?&5xk=cTtZ-P#s;=xCm-X7j=0A z^~ZOPTqj3R-?*qlfI=Ml*nPK4g#1GnwM7KA$VIKf1w*D8D1g2Y&%wKPyKV*35b<2P8wo~xg92f;2GHbos5|lcGG+H zt?-8af;Z_+@1v>pw?*-M6B#x2IWY*i=umR}mp!8WQyHaz=i9P#4p;hqssdK&NcLb$ z%ut{3T7HdHvk4%{V&Y}&p)t1@CB2`%a*XYOKf-D&eXRuiMFN%X!#X46Z&91ZD&Ub% zls_JXgfNpF;#qpoMt6onx46G%6Pm29xJ!Vl$Br1LSZ5@{zGrYLBiEjaSz$2#q4Oj~ zCF)8h6xpsLWl31p6pPX|J8y_ZCA|wi!id=%KRBJRyK5dnP6qQc$q?5>knLVUTG)ad zKaguTLC{;givK4Kj^DW zyc%%Xa+FZUDs@dq7elr>SXE{An+@1j>+l~h`)uEdOoYom=EzD*lMnc7ZY09OkGJuI z483A<5cX+LBfPs3)qV{+B6Tw`uToyeja4!w8&g^SG`ZqZl1Gt~y64u&clHZS^3XK> z`*>I^Yv>rIPlsIG#FC-cj-Vb+804)bCU}GJlmFX8B2$iYT;zi<92eR8*U&|h zUbTz*^%ocQw2N96LEY=3=0{KyUDP8$f%#JR-Gm5viHo|%L5cTfF3+HS=Z$3p;Mo0g zIQ9)VK2)q%Qu(bKbL=;8YZ>O?!|f$If3ALOKD79RliGah>u&QZM^~i7cZ|MHSLA%w z=aw2Y&I_~R&I`CGx+EqFmmubrsU>o<3Q-v6o*|reWH!AIS&S2>{mHV?8gngJ`K;er zET)B)@K=F~>W}#hLU2Y0B>n)37%V|XC-H794veG0X~_dy2fDo96hNscLUcdl=nqA8 z!FXi8a&?JGWW91m@v!R1jjiOf8BQydnuBCxaKpSX%<0FwnW^;nql>4DjtMwVdLuq_ z%=*yPq3t#()F7=4woK`*8#9m@diz=+6qjO<=uVU99}D&D_Kr}m=uK;gA5o!J9qkA; zeYqpl1^*6(N_vxA)G-m%tuCr-1a*arY8^qH?V|qp$t|ncMJ)#kZrsa#myVG4a8XY= zsQ<=|*Q%CTOFOr0td^SaW;xf5&oT|R`AESxTZO63HQ%-7RZZ*}xME~PaWV$hWwB>4 zntw*4^w~0%YWx)+i|m)>uXf{9ecOoN+Sj;Dkkgith0te8hCIU?-NIsap=CuYFG(WF}t1o}%u3|51TGHRuVas$!|*`7J^%WxMx-wc+Z= zB4zS+n*g^L+$amn3;pjw29XwmANCi6&0?)WUXtFCpE$NXc2#I^4YK)^>Vs^yv!&*Y zLVw~SGrLIhin94#b0e3-=HU&nIrPXtWmpHr#o56u~X@ZZV7r-neFZ*n58{|pk7i%&DWxnQM(9Lj{HpD@|7Rl8io3uD<2lTN-`qMkE}F&gfgN3NwG48KMS&(6^k^SNfJG3RQ!B%S!?#T6Pr5Xy0h%%AZl68cx4dQrs=fWO4fZYXGa5(VvKTpqeao|+kiO+z zN5FPj@uqJ%ET|!`v*Ch$%Ql43w|o)KfrB~u_{o3lTNdDwHn{b~%qFWxAID#A!ayPL zmuLOZUy|NX7d0t@;&>%Ub$tYNq>DN?g6ig?j*OsocTrt{f@s^h@7hGj+qtNkc~0NH0yn$aKvYh@OL^y*1W;sWZcdsDl3cO!+ungv5fHQEiy!i^ zWurW-%$ukF22z%_{R8le#80(_LY%w3+fYJ@(ek{%rqu z=9la@1p-w9fmL&yS3bF!$d@<*x{1!4G=qG2Hzj)ca&{f>qvcVa-EGl1?QHW*dCrCR z`se*;TwUEO!qu&-*uO8iDUPe?41I*Ip}-xULM?wtKG zl;rHq8mpOJi!*9w5}HTWj2VpW=%hA-vF7HL?5j;y43a8t5wPLLlm4Y zv&iC^S;FZwn89#iS<1*Z;N!JwXuucc zH&*R2T)S4Bij@aPJRU$>!y4LNW5^y(>Oy_Bt$mfEWabJWy|yX|?%Tc`h_f>18tcIjdq~V?hytfF1F@6YA{S|h;rVP*O;7xaN`@~ z4CfkNG;@S$6{@#QEgLjWrv?@)W;cUrxbuOi)65w{AA!v-kO^;bw@WRGjRxl>n(f<| zs03!2e;OIF!FhMG83gC(0QLCpfj*Mn*6%p&_M#PGyP5QMby3qIsO~N*8A0vqqJ}%D zoDK0)%02bo)CfYA!Mig8{&%?fETbX*0IQ0W+&07qyq3EmKKsx>-Ude|XKUq1{hMra z^Dzi~5M$cjlN@5x_VzNbgxg5l`+Ly#I&=H`pqg5-ijO=L)t%sOC)Bv?c6tll7~JpP zfv<4Kdwpk#DW*~W=r5IC>C=8anqz-Ia0efVHdbe2zpKUqb2nAE{#S|hKa>{zFrKde zEz5VYj7>&z73)@R&#}d4Q!ma zmZLMySfvW*y{bZOI1zi#-p2bZ1+P2UD!90zV2j2koa#J5KTVSzZOg1SQr;i9f{wKhKRX;WvLS32ntnHf10u_V&{8^uCQOM0`-%8haFNi(D~ojaUh`%VnE zseUu{Ov4eIYU}YeA5N<9HP1EaBxrDI1eCH8guVGS{uK!6^}D)lq-P5@hcjRd-QX|& z*$_2L<7Ef^FKK*OXb@x8HKy?)3svK$IXlB4HqF^l_7$45pj&#kG>dXKu(W8!$1uElv+Ok|@i814nH=+-X_6TCju z3_92hbcNF24{GwSLh)HbK6pSNB<|-*JB?Kv+yfA<=`M9qYd>*OZ@Q>29Mu2JS(mE} zRO_*88dK}u^CQmM(IGa@x}|xQ!&%p2tk5RmM-$qiQTMowZ<$d=8Rc ziK84C4BbfQ{ZuLMx0Kd-#l6ETdaLv6y(*9*P~aN^D+7;a3v4}lgbYljdHlSNT&Df= zt?V|D{sLfo| z_aC{b)}T!fGJG?F`q4$rjG#VsQ56wX+C|+ELA~Ij&WoTPc2P$~P?KHMUO*M&-dOit z+X(qM7q#v~SJn|O>PrXJU}yN5U&Zj~XICoNKsTg+RoE$)5jpN3auQ6_KHfg|73~qL zCzGlIR}oyp-`&ufVtY0J0K?g)7tZu z!SOb|9WZInv)^ZbZSp@u>MY~jGUPGob$rFKrCUA-Ro|d~=V*D20g21 zhx#?Mk6-*8%6gBo|E7Iq^jjhN-4%@I(r>@L1N|nwOBXr3zxsa2d(s==qGm);eO*+_ zK{Y7xtWe?|Ew?!(-uR+KwP2+d+c7vy@K>wUcI+&dAiJOH%v^r<{-Ve5Eta19Dj(D+MKLE#k}%AA*r2udV(3*NSd*hUAw!Z{$cYS^&kC? ztNu|gYM%&dh>L0!L7n2Fet+A|@NgIPX#~~PMJ%J?GkZ2i?dp;lXi0|;I?^A1-$-N zs4wwdOuaUKg^j~uaibjW1r9SpV|$YTJ}O5pM}j1mzdp2U!0$g}YDlQIS!g_9l?|wE z(z9aTK}%x}UfgUFtsoy2QPj< zPCF!*Db-r(Q-gCv-vxLj9qh?lo7@PwU`ad1G-sG9;dP{L5zds%C zvs~}P&W@I^bD26W!qnh@a5;j*;oCnnX64U3mF0T(n*`SN)`29K>+Kfu`_Ei&rDn{g zrhB7IZHE%!6Pd2JnMw5DxL*2uqXm3F6B~y7Ke#D4>Uxh_lBnyQR~&J@n*%Dx^>%0x zalPYE0$uM43|ynG*T<$#6~(>*8&?`O{E8=YyWYZ`9HY2wj$^5XY1fF)a8cVwP)E6_ zO*L++16Wv7hg^PLyD7fCH*$!*>M#wj~s9PLVgV%}WVSaFhnHxNj34-1K zRc>AfMe^#88FWlPr-1qtQ9q~Tv zd*44HxRk{HrrPCyY)}E}^xY`o4b%*S;k5;RGO3_DH zwA?dyn)U%Ou5MfT2)v+2?Z_ka2D)7WOyO8!kW)8Y9w&P)@VV?(43)gHPD+v0x!#v= z+EjNRO2J2Vc!%A|K@M%lJgj;5&dU2TVvzTT@I9ON3%I2yBk!xvMtJROGVT#(y#9G4 zPZfUqkmiDo=H|oA+_vj7w{Rdbz_zyzP!?+~a`Y*-o#T&<1ec}oe-m8Rebtyx9{E_L zN(N~<>BCXjUCo@+Gg>9j*t{~Uq@__?c9r~EsRBQMHBzg#(X8mG)Tdt6V3qt#m7%(` ztK?&&%p;tjtW1)N@iLCqJkhmf0%fMq6f6-Xgv_=VR zQcV!sN7Dr!^Yal}H7{z_++_2TsyR25ZutYMy5qA{w}=?{-mrs0)g8|YXXU$FGf1== zmBaO$x@W@*Iy)@oMJf*!RGd}HeMYUGQ_6R;dpSobC!V9F@DuPN$dO?Yr#yoqQiUz< zQ?C1B*-gEuQ%;6=A7HXVh%09u7iPL0HHNx5 zG%M3h_o^<3I+-5pWV-NN7<*5XBfiat8bfQJYWwk1QWYilX!1FK+N!`=KW$>SK26=^ z<%e=;-rvS*-k(^F0b$e4vCh@d@pH^|M!Y3Q(Idk?l+aOASu??X0I_%01>vm?s) zTjGU(VHN(&W}a8A!k_J#@vhAH4rJ^vxBzO$w`?}mX0>+%LYD5L5*y^fA50E#`M6=k z@-PMWPBf7B+SXQFcva`b=nd#-f$st6PmzDG$CI1oC1V>BUKap(hmM%HFF^l#mXY+X zzp+VPuv@Wum%O}ewUjKULB-ds7T%UElV8n##;G{ zijsKvf9yt$7M+W*oF z*_V?4me1k+WTknO@OXtU#AK*{v%*&szFOf&2w$x5>x9oz_(Q@cD*O%Mz6yVjB@F)% zg?}f!x57>50NzRAZ3%Cq@GgWmSNH(J>o^ycD(XY{CxuTU{I$YY6JDzDt%R2-+!3pE z{sM*fA^g0;hY_Bp@UevNRd^ub2?}3A_%?;FC48;Ial)4=JcIDL3eO>Yio!L7k5+gk z)+zkM6kbbsKZToNvw^>h!tDvSQ+N-;%@r;rypa=NsUm(F&i_T>Qwe{s@CAfFRro5x z?kh5HizTH%ukFI9Lj;Ux-RNqB+6cM^VH;RPQ8o~H2Igzr`OGr|)Tt|xq(!abJ* zzE#X@Job0Rd_MscNFgU72sDCev9yIg_je4LgAH!A2jecfbUfJUfdey zk5%|_!Z#>fMfeJZ(}XWjcq!r275OR)h~xn75kxdn>#j z;hhvNBD{^lg9&f0a3$e&JBsW(;(A{HCxyEb{#xOlgqJFO9N{GjpGkOu!j}?$p0GB# zW>3$z@4Ibr=dZObMyvj+^u6MI1Fa8u9P?-|zlbTEg!ecxrSpZBhX$1ft#$srpw-;b zFGWYp8yn{Ce>y6_VyHmur6Cq=erGiPZ1c}#F6Jk0Dd(#>TcY48Xs^4FCaDkXMTvJj z6WnWwoR3DHAJ)3^tbjwXZ((R&Qkt0#4er0V1L9zp70*^aNZ2_881F*yQ6L|QcsD+@ zIPPUYaYNj!;w-MXr;rt-X;#;}ycquvX7OL_;Ia(V1>4=vX{cBz@+o708BZ*FK? z0bW-wJmUL;o9eeHPQS7V|G=V@t<#u?ZHZb=dhZEgg&=|t($=6dS5HCb?W(Y{Fc>F$ zpSZGkZ-NNJnRBL-=d`~OW@tn=SAAUeZXk`>*r7aRe4{o#>T{%w9F5pxIi~^*LKCT; z%;g`g!ki&SbBbZ=XXC_-`suFqBM())e7m-08qD>w0vy)7cq4l3b%XiWus=?vJ@uV{ zeg9+XBH^vL8@VUie#M6}RHn3hhO|)M8^HUA-52Nsd;X}tdqb}MpGF4Q@rwQS?Vvc5 zH#QtI*@a=Un)r#(6%5cjnk=LWpM@Ay{#UnR?NX2hv*jTJ%Yyj(?U03Xie19Yt!a$R5T1m)5d$cz7^Pm z^&TxM`i19sNtXBcAB*=WLgkEj&--r%IYZvJZdX0AeyRz(_0wPLM;@wp@t(4&@Sd() z<@6q$`l7T?hwLL(=luflU|SDP!qfaTp?kw-CUiF=O)@SIhVFw~2F6#Wd7kOysS=f| zYG*77BwBEx#NDD7p;*6~KA4F2LCc1daK(J2<1>FWAwOjhY5%l)gpL?+pbuD!*Lf23 zp(Q<{EG%_&r-+9XG2cNXy&vvE!cu%9b<8|?k;!7JQr_iIrizNl=Tx|_A-Y5p zV}>_Az_%5Wl|ib_Umyr2M<&0N1Pq%C4(5kdP~&}kr`&NMBX@I!)&n8l|9N>V4u!-2ycS^mV{liU97^%BN4CVFRd)oDD%u7G$!*4NhuCtg=7V( zNwg>>HkWLD6DjwBgqF*&atGmzutMJXeRwv?R~cG{l_7>UBdiFys`#;d2`jyXutE@# zuyP-oc>l9I16lg2r5xq5*Yb}tvgBO}T8$cdsC69rwMHrvUfxazDzM>2i_8cwWm(}R zfjzLW97U+|R9~iXz9!5WocxOnnR+^3n9GAPO2dNL6|EGCL?!H1qJ`W`)!GNCS+FKG(mm*NAhrbrWNx`a7{ z%jYY>W%tp6C74jNnM0J0uRxVha%ALNFxhrbDc|cN<;$7v*7s9dp+V3QQVBYQ=o6*Y zEl|%bm=n~RnkzwvnZtDCkt%!y{1CZ0qi?c8Qz}wD;>Rf=Ip{{;grA5GmaTMrjRli! zW74(oj^;zJS-et%KWV_BkP3(LLO9$C9BySetba*3Wai*d9;w0-!{J53NQI_Uq;hz? zawz2BaQThGAtx+NSez!?xFpilc-81J;B=%L7RQEo|I=YXY7-W_ycU=mlC8-Z7MnUW zxc_bp$2DK%TlVs z8xC4GEDpz%hN%w|7H7W_sKACrEixl4mS=^dg3Jr_9EebSeRQkMz>Zy+4s*&duF+N1p#IMu1*LJ?N<=z55 z)Q`tbV5B3yWWG=p#9M@&Ds%l(?=UY!I{$uX>cnt5!8qe~AyJKY5K72!#Uv)&l6+xV&2bqb3>l_-i|F?#fJcO|8j2*O+<&lVY<}cNbamKE0R`EO(2WKQ% zE@wPE z?qVzw<%}~{y0Wx9MN)h9=nc5e_zgpZs=zqoUJC<_TW8cFGn{csmNR}QJ4)k9X)CwXWEh%?3~!^HO5w4sqc$`c{`aK_V+u`c)WKGBN@ zi!(m-XO=UL2vdP>55pRraeKmW#+S!ZQQj8#89JlC1BUH&hj@8;erpckle%;T@h8C!u^{dmy?${#9i`ec&c45`W@oEgc_a8{c%i#DYn0M|Px= zePmXyc7e31#G(ZjB58r;g|xs;&;lcG5o_r4Ld|T!y*yHd6YgO}rTwqV`L;q+DpD=- z4MAA)TMYRu=dDOIVJswiXj~u>?iHg%TSO!(vtp#<dcP1Pfk$g?D9mR-0Co-}i(EK89}KHDKjnMYrP{M7n!)f}a6J>RwdVaxz@Q(I&FA<7zxH~!UPW#Yvqe11AF zNLJ(hhW0oke9jH={?-=;g_`hr&dWh+aMLVj`0Vb`VE*%_P@{Vg4mFyHPf;z&BN4CU zFO|`R&mZT8#bHuG!zalKQt({s1!jns7jh0in|q^{%kcRO;f(MpnVIl8!O${%-ezbs z!l#gH&Afu!d_j1o5LO5x5>+5`1Ep6YF?n2A0Bops-{?b9-BcBEd zO#t;@3Y1_2s1}+LKr6EX=%cu|09K_4RbM24P6%^`KxH?m#yE#`6JfWeW@t^xqo>rA z1kj`IKmhgEB7ovEP?&)|J$sNhG^|4e&~1@%7(jPFTLS30zhni_gTho`=ez5bHO_E; zLKv2QgG{%0HTcPY{s-Zp8u#GRL;f9#hmyBMx2ISBNPII~+yU3plIG2j2GRJAvzp|= zu6PfhA;XotBzx2$OBKE|3M{0G+9OAQd~-NlI^GQp4A}sKdD7jIH~4h{y9{7=$o&i& z-Z%VNI$y|TRfQ1oPnJl%cMtQamXvY6L1E)DOXhdhOr~ijLMxdF4KleHnLyN?fG_jP zNTtH!_H|0}MO9!)va_m?{h3XLXUN}U@z<}r5{2>3CQa8~(@k^ICB1=^9$iaT#tDQ` z@Q=5Ud#?w6sut`FAasWP^1y{~{H4X2 z==ko74!3a@ht4I*a?PuM9Vz$zYgIHx$8y3M(NQup(Q&w;WpupA&}KwOA=l{m=uZ+I zdkSHNAR^JR3F^jQE?N{n+@$q*WQ4uXZw5=L!aopQsPy%6HMEeMnE2rff#^0SYEc<6 zaYj~5EU%WBs0dY>D%Er)JZ5_aq7Qmr3(sNy9icEggO|KV?liP@`C zW?p@OQ*){K3Nx>M^k~$e`Dy0WA6>OUmqdM?SCxCgi(a&PvcFt_C()!17LLdik* z@X&x^)7!c{)P0S&5siIDZ|j5*?^m7~q&D&7r{{v2gC08Mj3-MRnxyyI)ezpyNK_Ga z?RB;CFAwa}<1ei&6Hjh&vy$QvPe_()uzKh7A#Z30Ou39FeYD)j%n^CFGe?~bE#pZW zLz@v#gj`j8+DeHh^;c1t3PD8T$t&nk_{ng}&J0$6b!BP!n56b5gI2?Z_O%XqFHnJr zD>uyyq_S~Ei_C~CGqd7K_jwXm6rsvf<(jy%OPDj{?ns7AJ+%_%oSCCM?Q6+HD?sAP zvT^WlZ((uayo{fwk+AimY`4{4c^V?5$-M#ybl? z`7bhaWWvvFP9`e&JsN)AdnQmRg4>!ffsmw7|_$XpM^LY|Hk3m?*UUnNA&FuYUPO?DE)*E}MDi)kRbJW_>E8@8@uA351}nxs^udeuNdm^W$PzbN3y1g=?O zt<`ujq|XRkcZGQWhtq=8CU6x#?JBWz&cM~$p-Flzu28FEL%Zo;fZf2=S%s4ab_elS zByiO{6&8nmO4<=3S+2nKNu=DnSQf0Efoq(W8wp&Jndt~!VrW?zXB*m#z$N6W;`_dn zz;&PyRtO>zxVA$N$$$UaKo%3Y4s+RSx$1JN!ut_j4>xd)ek(|30@tfg1}dy|kZxD=tviv+HrVb0*>LNa6m*BQc`6S%r*J;|e|)RP3RPNgvVSL+)KTt|g9 zh`{yJFgI}J^^?HWV{lc7T;v-NsY~zF) zb7zuBmg)AsnFAQ&OXdqzuF3QKFfR-j>#?WFZ+(7XCdREl3x%!muDB-4t>=Y!ztzb> zYU9@DhVnsGU2?khVGd2wJNUBDT)Gf;-MYJ)i#)KuBg?J-JtI&jLK}-ie}rVY+`37~ zIqHAjP%W2kJ(F<8_(n1_Ze4C@>DFTmZH8M5xw`dhUx{0vErb<pR1oA@}W< zhV@iJ*sZ5xttWYC1&CW0-vSd`^+RKB{jabF;nwYuaX9z0*RkT(7p%x~>qEm-V6E;F zWo<{mpA&{#-^^)>w6_F5#jS(sn)}qJ2g!~)-5R1&8=wBnkvihjuVx`kR@*pPrQ#)S z_vJj+vcA*q%j7Z8$f+DPMe@ER%)2H&(s(&@f>oD=UOuaYUQT?;e4)za1@9*6&NNv1))MJ6oL5^-Yz5FzX2J62Uht|`Vuxma2 z)q3QSh!5m1)ea51IOT2WW+lbJ%So2Y%R7dg!yJ|l(Q@hKO9*FpIeE9Ej{lFZD-X14 z`u>VT$s=?tV^N5tzPMy~NrpnmP%=biN=O+K@l;pux$aNC+$7%yAt4H-!mA9umpK^< zMTm~E$Pkr&pU+zBoW0MzSN+l6=d88YUVE**KYQ)rp7*5ja+HrZ-hxps>^jOnUoNBk z24Tz#Au-CYLbwv9q!-GzgpKl{ep|}gO6i~@c>Pg6|Ml1eHp;htG`4s&%C*XZQNFNf zl)uVFZZ@L?HJ%#RRvl9xi6x`mlP__88q2)zr{3x(Nz?%{%KP4eF19u1-haQwGt#M# zQT`tYcBA|_T=l_#y>(g9C_lrMf@)iuY8>T%UJTVxXpCH?2v*|JMtQg%6RMt%{lcl$ zosTuq6(ILV$ZK89&d0uWRtTGsQ4UC^BYX+ZxH@)*osZ3N%#gx+`6h5ml*PRsiG1{Y zZ2BW`K~;uSEHQ*h_8H^_I^^*A{`uHR4+uBKLVHPa=>fOVOSR#vyic6XYe^+)cYHz! z5&K2PexLVNTJ$Z#obdLm;uhKY*s4jc6X51#)C}B6v~2jS#wmP88|1Z|kI4)Fd~Afp zSPat#Gw*tkJ0H7rw6u{Gp^cK{(w`31HhzA+v{5B1QQNpc2od{d#y(BnrnZy1eD={E zJ50B4&$!igKK2W)b8)eVXbZ}|#^3{d!~dXeydM7w-h^km+d77wFS=qiL09k;EPTc~ zdiZnaxKhK;qbIsbYcuUjVrNs2CmZb42Z~uhy*2aBqE(ssYC=h>G7I^Xz|MCjxazV} z9k7#ZrOwAzB>Oac#Lm9PTY#Oyu8y3v6ei9FM+jqH2np=$ zhTtds#BG(?`Pi|(dZ`u?A(j1j5j6|;;FIpz44W4l!O(Nz_}B;$dTONw=((r}Jx4rA zO*2YR^Ci%8fRhX*`cW72)CHoKxAa-0o{~geAn4ihMxf`y&w-x*dOmiN^C8f4?S(#i z2Cxk}ZHFaA=()2i1=SXy6jkGq%pB%X=)B8ls9-W4`7eClZFSiB*n6&dsJRb%$LYcu^Yy9kcr_X85d$s4FE@dDI6;SLVW z;5ZV8R|~uB)G){9WOdVIpp(;F=zQ!>uUs~0&(@nW4rCq`zatwg!7g}I zD`adZALnE3ewAJry{H#1nNZ?u4=VMIleC)to;)!&S~_Y8e*ba4R>AouWZp-|fqMQT3I19GpR_uQET{RRGOP~h zNVZbvW3PI;;r!d`B{~k&dK241BFxs0-Hey$c)alzprf!WI*yQw*THVWm={6<9s9yJ z;Y)5mZj)NRMMAxDb>JW9^ECQrv*V^4CeFa-t64F^M6Id-6PFfY;=sqGH!4Amrbe}h z@;oOQ?LGTE=btXj`~Im=|45>S7fft82qSgIC&0viJs(SZp37zCuSN6F%zgVJwMRQ2 z8}YuKk1Zq*0%0aRAN#)@;=T)L;t)9r$6-;&%4H`0rZN|Ei^LvHX1hq{6!K&Lp78Wz;?gz%$2ol=woAzYc(cco4X*3y9DF(R zzJuHAq$deBa9oRQ03PIvlIpmD1GZ92yJJ27WP|nRXuTYOtC=qdPpEqop1fzg9DuJG zZ@~Z*b{&9Q;`_&794m}@AtVOicW`rfq}w^OrQIaIEoEm*>7W|CI=(bG`R0Y#;x-Ul zkB)mtG!V7Qf`PcAXdte7SO%gJ)Od-3_&%=eTHix+-s<7}G>>`TPhHeclBfe@Adb8m zU99!Tn_JpVb?Rf@>;b`UY1a>35~K3rcZ-6P8(k@=*2+|4aI!n|C{*2xh6?KAk^jOL zS7Tkr$uZmoISjg`UmyYFF?bAh5x^=&Hwq7*kd-r<~XLB;4MT?1q*-&9X=fN zcs$u)$L`K^0rS4+nyTj{!TsW*5%#uRaj`{?REH5pwo)VPi$uK-o~`wAgyono7-7^s z8evx(FGpA(<1H9r!mcCiVSJ?+jO~RnFNDMhy9bUAmr4)tH%~hH>XrR^7F7x^2CqND zhCd%$+(y_N_(hM6gJ^_ll?5X#EE-{%@iM}cpvFs#uxp%TXmSM=vhcr`DCdR$t<+DF zr~_n#?b9D!?2W~n8(}9q4`PJRarjtEGXbC&N$Q2Px)Ur{rsIWIZ zjoY0%F;3Bm(K`g`;)K*>u7j80_q=dJT`44oAjjiUSf$V_s)ei6_UHz$3AysEuZ8)y z>k{`E8{tbFQ%&$4qLzXYKFiU=2JPe0Hp0(!O@ozsmK@<}j|bn0Kg0E$7R>u2yqoqM zNw7UyG{V2XC$=Qq$LcV`$yREFZ%ouXtDDx#5&jhO1tVO9SrD5wUXJkFjkjQg3%ic+ zc?)HP_YlUs5E3JN=D8T*f4KWBHius5t5?=gN(WWo^+))_(_)L;2w(Mou?eCPu2mL{ z@HIsv{E@LT!j+)LON{WGlZZ5Kj%S= z@SPyo&7m#Z$q4UNTQtHCcBP=&%F|ReZjUZy9wYqb9yC<20FV6VZdBThj5S{4wAI+U z;y6Dh7uyq|?{o~Y_(sOv^qIb66-Nn(2uPdIhdiO#Jj)`fI#_RIUlmMMzYDNBcQ?c*`LWrUo=TdL!$+ zS)1uy5|1A9c(TESuG*QnsJ@SRzn>3gt8n_vq$*RvM62V_L+3fq7bVpJkH}UEkFJ(` zDA6A5epWB>Xg94lv8bl*QN*$S6xESN1qX3VDT}|9pzdBqajCmm>@FWeK6rgR+VQElnBmbmcf}Tu@JOpHz@v3Vc(gNj#_^*}A*k`xxVE_7 zSQSe~yZ=1d`RNDdeLq#IpCnNS2p&D(2czPgH#dhzOP%@{3&SAT;nDrA1&`i&wFr+U zxl&N=Y*Vcn@?Dt60QgSs3j}FA@}J(d2v5RFN>6N#;hM@t_Lu4siz{}rTQ9Q{n?qe~ z;nif6E&Cf0c7+qpiv3|HHrqI6NLleiEHI3++2AON*!0BapDG#jq+-wulim#F3mNqO ziOmB;g_~lby(IX1qnGHQZ+HRU=0%hdwMYJWzR&)&v482kl@?7!cox2MCU~_U*ojTr z>j(I)bkq#|df2kzCZY{4aZ)S%E}F09#718DCpITrY{$82kRlzL9fAHnms+9iM%r5bRBDczp-(X{+tT<`~>rL7VKv zriud4t=?Zo-FRX%5^utZ?pBJyXFXS}CfF4`1@IY;jKzjW9~4(=@OjsrF%{bMD+!;M zc|6#^?hM6jA#gVH&Z1SBEp%8)f~FL~=Wf0zsSfZ-wo)fH2RY5*z3@b>m+-lad306( zTR7A`g3p(Ym+(2=cnjcD*wvA1_!B?GKf;(7LIOS;BT@_Z>lT~NPHgV++miZDBBrt< zMM&^9pLA1X(PMEz1JK5q*ya&{YNZ7Ly2a-xnfRvE;!)HzqXacy0zh9L5lcpcUN}K5 z#=id~^S-AVs;4AT7YKk}djSBn@d5zozn<7U;M50z9t*(^K+oD&0QBzaA^`2nsI2|Pu=HsvnvuS#e+up~Nm z@py2aXH{^_9mc#r<|_3>KoV?~^GU0-;BsSyr)`GS0UgO!>cpmDqG@j)t4$+1&Sky; z9YvTecE=kp(eb~=TY!$juIRXUj-cZe!k8CA0v(&fH(`D4>~yf5*bGXTWj%wWTzW=d zb>RLJ;-(uW)^$yfFj1>2z{Gk*m^e2pn5YCbni|!D$|<*dMhzx)R6Ef>qnY>pGe-R* zi5gxo@xpU3QtQqKCjRS*&2Xna){hmxqj~6C*K_a19_@5x@hm&BsU#0Bz%k+J%JGfj zzH4jEw!X~t8z<3%3r=MqP#$y{S2YzSp# zQ@2P`et{(EUQF~;J-=ZUS1H^T)l#O^r+S7u$xwAwZ|If7P_<5OE7YDI6N0<%<8XCd zl+C7=b)h!Fawhr#jg}GxXUM~VkE{~3$_oivx5r9#dkkS3{;O+=%_5uu9Sh~sOP~*l z=QD)L=Cz~}wWoIyg1xB?7ayvs{}5|fFUn?9C##01I1PvO20LON@IXUh6%FM@k%k>r z!!5{-37ttUoi+{UFxJTCwWJbN!-+z$H~7ORrXfb11%vB{#+|(;7>ekuAQ;qpMS4Eg zwk2vwz}?VW9^o-Ar)_Mtd?=fEhcho%!2B#S>;qDRREr2^=R}+6dL*Q0y3b$_|y%K^nY@W*Q1EcqlGru-D+0*y0iFX_W=A*RTloYBA@c=O{sqmw>%z zhs2W6?x&7&ewx6%@2BSKCrQ)+0(+OAiSgUurOmCS?{?}VN;wRIT`1UPcL@dWc)lnU z?BPm5wR)ynGvqfM3Dqz}$91Big75Iie~I5M7&`9ggv{FpJmIR7P^Kz)AK@cDUA7pB z{s`ecegB5Of0KzC%5ZX_XDB5YPEK=#n#@4M$zd#?O%0c%{1QphmoibD-1#)(B)Jiq zFtO02_`7D^oOpockPBe!-tFT4VPM(XW5Q1k;3(Py4QLl-v#Bo_vf=kp61mA)!4W(+ z#~C~QiXYpPRiH>-2o(8W4V!tjfF*^aLrIcL_lG|8#6ey8Hm@a>sN*Ch1bb5(KGqg| zxbhdNRh#J;WwWVMRm0Pqh7Z6@(2zXPP*_Dnc~PX{&Z;4WLqkb&>F|8j@a|LiHm@a> zs2W};1bc&@^QwjnQ4B2K#T^48Hr~_(-4Lu5faNoej&F3M7VRDu8+N-XE)7CONw7T7 zmb)_V55g|mI7#s1WIkzi78`zvt8}I;Y{2ROmSighmcJ$HedchjmtZ-G z`2w&MVHO(>GhTw_jmBF5mcp(kenIYE2d4^SUI+=WyaYjG_*2KYEe4j|ef7$=kfrU)$eccq}(XK7Wf8S?Kj zk0Cm+oQ4Ws#v}ig0?Udqt8f^OONfrzE>OW$ve;4 zyp~j=4uwDn_NF$>9{@g_x!Ll6bhg$CC{jAAadJb zJS1BwJY1Qmcl^OxFY)ld%opIH2s1pq)_94BmlfpIT6LQUpc!?4%vp#x=t!Y^88lR7;ssYvVpnGT`lpvtXV<`^FwMcstr-s?CgnY1smFmWfd| zn`$og2YX5V0&gdu06Dl}LQf2@7FGcdc_HB8hkG>_3%pS{x_~6P^!X>VE8)Hw18-bE z@rc^9_Z5P&gYSiXz=z9cky`j&O_a^1Zqo_ z4h<#ArRSWa8jd@bZ}VDGiK^iUA=sPRu#sx$g?nGfNwtN0ePF%9YT{bC935OJjCmm>;B6c{9{zJ! z+!lkk%Y3txHI>rAAn^L|_Qc(BF@v|&SH>oY;7zM6fVWmf@b=VA0&hxC<0arN?%bPi+p~209M{-gbpx7w#QcCh&IYqebv`q$>s0 zer&C(HA8*{^B8(}$Q6j-9X#@%!dv(y#;2Y$FVT@2-5}k_N6g3AXC%AzGCOB}+ZiGZ zcril`8b3!Q86NI7?(Cd-f@6l1+1!Ftf%Bs*_E#8_+Ltp&UnxLCDh9nU$)J}P0!#im zbK8rAn_@BOCBc2y6Lru}Dd*d~mQh^%6d>*LoA@%+x*FT0Gl$ z37=hzw*WqcT^(6Dk+2jr6UMv{67YE&!p3mkf8w^-IrDzLdZ{xcwk%t`A1xA`!YAEa z>^CwlXaM@mWwAXY0M$wh0JL2ZfcEF^bT*>|HD3Zi&vufb#A(#U;=@j&mlq#~>M2Ro z1p=Vkb^w4rGZ_H-ujkBdoeu$^pX}=c=nvZnfVP}a1fYKMY7dmRrJ-{(Ld9Bg{G5O>szfBikST>AcfphB*E z93+O__~98q4JH_>0R``r09M}MsTD&8sN4D^f<|x!iNmXfU5<#EBYjXCQGcnEbE3-O z8&uY@Gc5gW7ZGxx3K3orB0LasAcUZ)UEA`Ud3$oHzwMm)(M#i=q`wUO0gRi{%jN&~ z@P9aMcT`q%&U}?u4(I4>y*Xni=27wU2U7cBQ%iLQI-Q+};hecK|KNgqQ7^2$y6@3mS+m81y}()H5%3nroB(R>J#omaNfW=1hz9XJD4bIm|m)yimE*n=r5^ z5t|oGZ1dtqd^XPvv|gnRchcaxG+Glibbsa{>&@2E(8f_iRT)FatrA*JEQyXQ-xI6UX+6`$L3@T2%oiwlBiO9^8b+?z66$rH~rc_7FQd$!NxrdprLe z#JumH>FOUz)bN6df3(L)9s4ja@n6rGck?`lFUS2s2V;&u0I5CNIdlI9?VPzEd2s!f z3D23A){FbDout%yiffCesc9R_aisRRTxR~y-bLw)=?8tMG2@#EOTu#`^vIDDRW4+b zODzJWOVxW|3wP%Zlmuk2A$kozq}p1et;>%tQpNTjTX=+QkYOmCOZO1TwP72Cd!@fV z_oLr}@*An+hQ@KFw&9#2Gqu(pjK^$h=>aUMMD6LH3c=pghW(vJ7Ha7^u&q=_qI^N9m2w(~S8N@($G~LP zg>e^$b*GdBllwd#{Qjw#Hk4p;2lIYs9mrN;myrp6X3Qi3CS80{QXRmAY^7GJ=U?P> z!{5KMdI=`=wcZ4nQ1>X*`fg9vk^J-h;Wdo#i&(ZY^6;VP^e2ql+)A~^sgD?7AOyRW>ac(6@K=s6 z<%X)KqTGSNGaTl2)C^I+_Y9~N7^1xI5wgK?3|n*Qtwb_@QI0Ld(ugwF zE0!zYsuPU+2g#<;=_zwv#HTiQi-;*5Q4p_4VyZR3{k#z=Bx?QC|`gmuQ__yq;A|ELzGL;i~Bdm z{`8WFa;(RL`{ui$akeCA%e>!HM``0E!F5PJB@pG0b6s`#fDS?6C}AswDD|D@FzRc& zYQ031Sh!bysQ(QTqF4 zDcfC22g?xz`iS!M&9Mm#QP$%4s{m27$^t~`QiLeeE)hggf*LP@C=WWxX!m{i!EofK zk<9ykny7w~L>(ZAa(X*-`n6*=hbY%O4+2s4gkXm#?GS*YFJEzQ5u$W(rJ&lHrm7kd zWhL_{lxa>w1@GgL|7`E;8=UOx-q&Y5<9ENYsH68O82gajdYSEgEpmnk>yuGnk5pLzh_=Cz~}wMX73goynlV;}0hl@?VX`V6nwD{hhPeZ4Qog$l5^tbwYn zMO`c#K15^U58C1xZIIWp_a!gc+jV z^YJD;T6&o*G7LT+b;W9eKbjZ8=Lkm+mu`^1h~b@#?%O>c%+O|bN%*Ym@!%d*O8Y(o zvNg>6!?K&2P!jxPmQM-zoOQOV4m+s|pJXew_w{C?-Vs(W;d8Lon}AOdX7Jh5cnP0f zjkf?kg2V=B)jVR zxS#>(b2wlt08p*806@DH0q6j3L}xQfQ1c}Kw5O8{CC;QSHqo6ZdU<{Y}LSlIKqp&g7 zCa?(AfP#NZ%qVa0bRa_psN4214$NRViTJo6*=5^`Inr;~Rs25P$$3%b@C_>4>Tp>4 z`?Ls|s6vESga{9Ww1W^dwK?dO!7y^Ezisbp%9(Lb(!H;Xz_KZQhWvjV{tut8kIIVn zz6N^bvccYLy*Z;X^Qd^1+@T1z#G_gvTBT#}Yghh3hIrY2eZBA%EH#VvzP599guU0r zxbvLG&^@|2&9zCGdf|iMqcdVcP3A1@YtaLDwlx_-k#iKM-m9gNmUP89NA7;`4@D1<`Ra^FBJx z*1Z);sxtHWq}4ItLfaqoMP*nWf=jZM+WVU7>4y6sRxi=Fpp8#=H;`=(quKWB8c6a$|d6WeN3`Fu2U6J07MET!2rk!!$ z_xWu8fb>P!%8EY{a5?>;?=)z5_h9ILK0^-`VQbrKJlWYiML?IOO!QL38FA3L4~AY? z!-l8;Te}|Q2~dKqT~i(bf2WFz`w0sKlj^I-VglY&s)Zo+S+xF$An)K ze-|Tkg~j9S(bqFCVQdquU7K)Z!4+2>OQ4l9XeoZH>NhNCEe_IIl zrZ&95X=K6IeoiBNucS#)@U@Mjhv%=2LD1mkiBp^-amHH`UNRmJzW=eE>%P}9?|0vj zt;%L3!4FLMq^>b|Inoy;)d60}R%-2fYFDQleg|pw5?xBa7hzWu?=V8(WwJ2lg^+-kryHaHo#?K-*xL0Ozb$3GrF3uyc>T5OFa2W^7|a|l zcZnp%j$lTsEP$EbMKH6ryTFVR)Oc!KgPG-W2Plf(mu&0&^cM5JpVq0LBvA(l%-pvZ zI{o2yZEo#4+o_MJpf3cwwd?giNa*$Su%ggwm@5UB9BQgHL%tRB7yxhVNJ9lFJn~+F~nlW0Fb;_2Aqr>}mj!kcfvB5J?0x`b!2>4zq1Jzvm+txZX zf5KI%(z{(#y<)lY#{YrwUfvXsFhh)y9uq2cvDk$c8?%#2oGggp|JkV{%LOr527^kH zT)Hi)p~0SKteQY+MUM=!QSA{Q#p+cF@BfxJLxAi!7RkO1-o4zIeNJN>bO0I z7&pn`k@hm2&z3}tvpk+`aB4l+(-r~8GVk}qdfGTisxl4vlt7Gnz9^{}ulWw+muiFN}F1BoHHuP8l|m9_@d_ z>{h=mWd}*=;3Dw)h%xW7*aU_c!HF>rMu?$R79d8yBE)#*3_%PfsPPhr@sym!M2PX& z*3M54GVlATsrpG0b$}p7pFPm&14I=6{)MAEo%%qGb`b0kqthxuj9YFiLX2*%6kJl* zR3l>i5kNHzfCpszBKR7Q4l%+%ani24T|e>6-R*YmyocD8(GJ~_hEqTQ|&ju38& zh4zx*_eRZi(9dNQgzKFiQG4WLLWtPUH}-qHx6-1zY|$;-Lx}bR+wJ=L__&9GFgt2S zZDzh@!>4IXEErfZZmaRN>~_fuf46I*7v0{UjBed-SD*IMMplG2N|H-|+)Uf}DG&T` zo6RF?8($GZ#Jf5%8>yInsW=USZ&zSv&7)$L=b8+W^w z<4t&)+axpie8Cl~2?m3w06s@Mdiec!ais>I?d7l{g3qNT;j@v)gTITor5l!YnfHg~ zLbZ}4xQNH61bn_BM>aOXGpr8qNw!kEUCR>nj;^cq5bIW72EC7a~^9;>KHI}$(Dt6m;^`gNq4($>k}Kn z0QB{av7;jZ)k+HhbYKyHR&eVXr@KN>^CbYZzmp6lE}M2Ro1p=VW zn*u;zuh`sf*9p#t0MON2_yAhxD*@0WZ!QAR9b74>_6kZ-HSTuJWF8};M?D%Un1o0E z3#YjiwC#4i<(h|@a|m&Zce@^UJP>yEm;bWcRpGJa(ob%xix8{)K1d8NyB9XD%{0dZ zBRGohYcrO{2Tf(l2|6%jfV#)F;J^$nB5`=Nu**i3uz@~u8}WN9C+BFD!#Akx#C>7u z4SS1_y;X?tiV)#}kWLVSrcOc_S{ZCbF7>zVcD;B^+>>;->q{_hN`D~#FTnrdf~@ie-7Y4!+cgef z6fgs=*J>Vg(jexPe_TV4VIHzp1k&pc#G^D+l`(YOHKFB-lIZxy(Xqm)V$DXag1cQS znfK9gk?y8Qf?KhC(&`8UU2?%wzNieV13Hqe)Na>YPdDuUTfIcbtF+$4ZkGr%bnI%p zM8}TCTY!$juIN~C1HBzI5yrd_66kmv#zQ#E-D}yTmT#6&?_3U=T)GqXjcD{G?)w*p ziPMjYtr%gVR#kwBgNrcns?O3Im7qpbquMgGhm(wEblc$kb3F6De^#h}BvHc)CT_Pg zM(XriHn-dLAJ22SO!IZ{9GbZ|c4e{mB#*Y+RdJo|cC{i;HX{jlyEbhV_ubiQ!4r;* zO)~Embdd1*Z7DXhLN=xHA(LEY4U%}XYY5$t3x@Jw8~YvPz-QQyNY}=}uxd;dLwG(grNA$i96P zc7-K@Wt_*84IcQ*b=)lTe#fm~tFjqM@bgPPC4l8jUsQ(G0a(aZYSnt_5plo6fN5s+ z5?FTDdK17R!VFl}u2UTeEUTD@GYWu3*ww`Q4H96PD~x#|B!DHo6@cZ!x^Y`#OXI}Zq>TTsgHPI2n4%T>)lHw=vr`1QP4Hkm4ZvU znrh9E@5np`z?c89YX)ub$bX4_t``-Ds?)LMfHzyL_V8v~dM6h=-5d!%CkPVyT|Fc+ zc(F&sH~2J;B;}15TV&IWDeSkHOZUVF^FPFrMwiHMa&hC9$ZK@1Lx>c4YIR#8&vRA} z*O5`yNc9oJhX-sSdJx5IiTq#33k>`6(sm*kW znt`wQTQCLAER!{atNp-+#vXxpQ&+&A_-#@W>iPe{Dy$P(Q?$HioXX7PS zA7#7+SS{@8$Xod9K-{Yq#=H;`Sp5XT=kPgqm&TUJyZY*-Ze_@wEnDy_li)@Pz~7|< z&p$IZf}!=pva6gxYpt{Ztt*Srx)(R8aTikvYQ6+ocXpDY#Ie-HJe3x`yd`o!^^_#) z0zvDI^?=q758B)kd2i=Kp!M6o_-Ot4VnORB{fp50$AoI*Q7T%M{g-(d>X5$#t#8L8 z|AlumBGl&D5_yV~fto)>gj>8s9^rTZ{U<{o0DbX=kX{~JE1?l%_@g)P}$DA zz|x=WEJ7|)A;K#{ga<;JK?s_+4u{!^Us>uOs$#=$(6$n`VQ3oW|G5_$T;C6>tR+s3+u zr+*yd&dV169~4uqNq;Nhbyut=)7_THk8?uLrQ5+|RIbxkTq2W*B{CCRA`ja+US_OU zX*W7)aAYgACTi&J%tKZ+_Ym;+Z=!~(eGMJ|Y~yRWt|U5s;PGUGcYf9?IN!X&ypN8d zF2N+h3WiTwoh^|oeNh=!2XrJ`sU`A5o&~c(cdM7^c#_teKt~Z~k?j7)OLW}Bcni=` z*cBanT}E#Qzx~9<4u5917k}^ zOJuF8024L-^OEP>us5~gJY9B&ky;4eqHH$RSvBn9G<=ppHZVsu z6jsqtUWkVNccw=r9UesH__;O*)3n2l<7ybq?-sacXbhfQ5@lG<@J!X~j)7{MbeyT^$04SNL0|b=M{s$=X3~s<276f&nn^VB7%w9%@dW&wDVEDA9osaLBPXTd}C8ly}d(q zd4u0;2&$J~D^q>?IwlI6qj+lvpS~o$D&IxRb2OPw?VV0FnE{H$dEv$?SqjNrphMB$ zDurHAEnKDk9@vk5Gs<7UYB}8SS=>(zAZi^G{{9XY0tIW?#~nRf|5jYu0OF*Uad*W~ zu2&Ku_VIYI|M!i0m(kkJ%=;a$p>{k;@XcU8B>>`6*=CIZg4LmalC2a#{FJEo@s(OH z0pcO%3jjidS+sVG@e&}eG2Q}z5OxKKX%`4UoG6TWAtV6e1jP5@w?DO!ysh(@mqK%9Dh5kTziNww+|Td5xo`RAbHKc^%N9lIV*%~$S4~@ zRT#nH-ap1Zw0*$495bX$jG_VDnu)UbK8j#~?gQQ-$Fo93&>~C{5-`UOIefnV!?0Z& z!(sTco6ee&H6Qjs8+90oGACS4kK432|?mr_L_q%<-!&1^lRs;`8l1o3eLEAWu z_j$8{E@sLf)pn`H{WVXTRKIM_>8VEsbp-@YUw7)!E>G6ac=nc~U9H z8jCk!3%7k}*qL?3YJxq$Q-GaUI(j&-CN{NUXIV2>X>F!qN$mV?PsfuDzWzcxKCyEN z^ZuBeuO^hFDzlJJ3G5v2i<0Vqon$Mu5BRL7TQ<1T>Lqqwr1d6(E9xEvSH~DHvGWk) zEx=A;S4UoV4lya%Rv7a_NMPswKfv%$hOy~vA8;pMz0`*9X^OJy&zS^&@JUZ?&gu{w z!O-);Jz{%C=&6+!py!k#^z6ug2|YQ6+|9^)iKi6f|sg~4q^FK^AeNIfNqx&t!g{20LtI_(ZUiqLaqLbcH-7468}#XJhNmirXJO?c$L zaD?p8$lk&Z3X2n+4AguuBKzWfz*`*;Vzo}t2a#FvK45o`EtkH18C1xXcY(z4r~$As z7Ri`hs0Qr#A1)!PTG;iL3#TQ}FIXuZrk#`X3*&FZYh=Lh zJhw(D^!_Gn3seP5NWo{)$tyyH2SS=a2%6d%^vYlkxzyi{)gbrm9`_`@Dl-}^o6?o? z{}B8ij{N{y6zv0^b*v4?e@*R!@A0Tsh;}Tn4_HUeIO7-f!YNob z7G0HDyIZVV*!k6X@XXghxqR1{YE80zz?WUInoJMd2bjRQKbNkz4GYzVN50FzlSJ$T zGO>L?{tU#V**@R^Ck?J^&c<0o8(BkVVownbtrIm=?Q7_`S~eb|aK33tbbQO>!M*lR zwF;u+9Oiv=+~R9^9tVg_u)JcDK*tJSREE_79m!T|AMifUg1G-}^%5PA)p`@?D8ekV z+{<{0jw$0UKu2L$bnJenpyQ99urYZdB+&5?EQi9orMvk1fWP@|3AX1F3g?G`I&kXY zanlVGGfm_E5MiQLRe*`pi!kxnmV${&P@^RHN0Tr zm#cwBnVy^52i)3gZ7#FI_5uIoPKZ6)K4AB5whtKUKAm?x38@dqKH%XHMfj@SmNSP4 z2O6*r42=!Yhs2KGK@|Sl1>YJ`$KifLPFlAmI6_)k{RP+o|J{yyM7sv(6#2}yG47fr+QjD&Fb?-5nQj1ZI^8m3f3?kiZR zx~+VBAIZ zmjq*nPudfRKNu@(aX}6i<0cqv!0G_TWGl7I-`Z(TyML(l5{zdsU$D#SUH!Y7%*GUJ}<-S?Uc9GJ-li*dX)j;)0_q|mE z?f4`YQhZk1*zikN}Ryum%Wg zK8a0dz;TeTUfGKGXo}!w@cO_psBPRq3^-=t?w?_21RPpr0dUMO0*>o;72r^U8ZQAH zy_{rdat;+TfImf)^P;(d>L*E#5)6Q(yuzHCOy|ms0I#Bm$2dvz9i4OlU-U4(Gc14Fl#|t{t6UMv{66kQx zQlP_>k7CmqIyCgvD|_`Vnj*LuygoXdC0`wurD3%HwQX$82pzP_0(4kdgbv-g8I8}n zYFHtK66kP@lMGFcphAWYZA3W_9V*pNlBff8|LaS1u?J7y96IdkJP34n{Y@VoK7LB~ zzm6+Hhm{G{Mx#`O4tFsRbZEVp_6=^rBmV&%!vDimucrqiIO)67gD3e|o8jt_yoMI_ zG{(5uRTVx*M%h0803$eD$?YIDS$$>h>X<=Tvnm$2F3RGZRxm(M502BN0jXF>2$L)% z|xqG4^y`*$&P}aN>KA9(6f${j0UY=;5@aOdEZmb z)l-tF3j{r9EdzRM@cLeI&r z6jbYJs_}=mU71Hu|4DWmf+O(Af8mK(d|1tPdeGO&K+V^`U+VOrgW~}dZv}l2nR$WQ zj@pPO9$PMb?CVe=S3VXJ!;RfxWBhR@*oSIB!Qps~F~T=^l6V2?E?p%X|Cfwj8TUW&qF&g4>k_92Gq;R&3+q1_yK;dB%A4xMRBMu*9^B@N)nv}G-NQbd z`*Z0}f6;kl!%POAB;xddiJczo+Xi$skewd1bJEbbuU>Tx{g`<)^rknZp|9al8mh$& z9iL5T*|8)#<~$z!{VS`2k>xGS`(v)D?oLaByPSN|>I@w_`Jytc4(Ld>Ql|&qWiu~A z#~rL*qT`lYZvq`fn5{d%enrhdbX>wbCjElQQrHz8n;a?V_>3^-g^)nU4Aw&7Y0_Q% z(}NfMwgkPoe#)hHS)&ddz|VDQ(+v|lW0=}J6k(!PRe*_0i!gD^?W8vA^zsAP{E4(}T(uao@Ea`RhHI+M>60?7W687HiQwf?N2X_fQW$JEH5k zg-q~iIVAClaUFYkE?B{vsQ3T|IdDf7i4AUflg;xD_LD?VcBTl@72`u2STJ~k%ZsYi zlT1`4({-UU@;nZta6At9P@qx^RJj6^6uBO71x%8i9^B>#HJM9n{2$Bm*;FS<%3Da1 zZplQ|`wD?~rEphNOPNxq2Q8gs!0$6ZLCZq{Bv$>ks@EoGTM$Nl8;71_qHH$xh^$0{ zN15m?;<69LuH?a7AgmHn%L@sq_rdAGJ}?ZsMb)noZc;dUfF!x}TGR5fEYXYZk{2kPmI*U20)a}rgl^fcXAqD$sikl#zi$0R?$#ih=%@;lUMyB8d5l_ zlq8qFz%=YFisZGV5>>;_s-dt$!zFH^ZlUTVxkV(9RTCVKRZ>ByI?U0-j~|itd8Y?0 zH^ki@uIW+|jJNQ3@IBa<;UQZ-{>;2T*r#jbB&o{G=96}51LK+4s({7p^nld?jLBAN znZGbm?=Y*EV0@$2n*d`GW?5u0sWk_Y%gu5E5YA>J5PLD+^-N zb<$qFzpq}|XD`td!G?v&W&Tz2Szmvd|J>iP2_jI|Dhoh)MG+_uKtzC^qXhAl8P`C$ zr;`j#&ZI)-rxQgvZ<#+|{UnJxKtOr>#TdWO9l5z>{vpnTh@qCh=m)B+ACf?|)geWJ z>c)g>(@=`4HG`UuFprLXyxfHdM&XhF5~l}-hqFB)+N<7C?B3?D*rfAVIK1Hv8JH`G zyjA&-3BI0yB*yNe>CRlxlD|sBLYy4ys$1ivbrz+Tk zYoe;uo=g(hy`9rFT=%;0%KE7)RoC$vY_D+Yn-GKTT1TkKTxziWqAZ3|FG*7VKS|Q# zn5bs0ad=xP+!fVQrW9;n?IZ)X{|sTXq0^wHw!vV#i^qfybfU|Maq#86D4R{~F7*d{ zNd2;b*+V8N;Q?$5tAHYN42p)&_hEbSj{=Gm4y#L&OKF>!ht0;vuCW;UYW%7w z!cqJVyd-R&G0sqGzBFtcWg7Ffz?=#*4*cNs*@dt8eI_NKqc_AcV`(Z4z!fofrrZd>S z);CL8ODP@P0Nxj+ckBMbO!vvvmk9{DU_EXCn#GmT>@d6lw!HKsL^S+O2V8-WP)1{zCiF0^5Vy z6v6h1t`t;TH$zoxhWwArqhse@rhS7?@W_9qV7rbdL>vCD!gjZ{u}L-LmNN|e_-GCK zUsb*ylU$}Dk{Gr#^H5zbxSBud!7u#CQJZOsgq6d{@&?zjNXS-;pzKT$q~O@<7b)1B z^s0O-CioEvlDLKzT0;Y^fh5$>9*NZ;Z}1}$60+4IC_7UGX$>`NSVM3qS9VpYG!t#K zO=4@kM)Tum;TxRzs)C)hKqFVcW`|c@0h462!xN5Blex@hhqq<W;dCb%v%@D}L(7YvfR@@2n;j1Dm_UfO#c_8(%4SmsN&P`vsb8?S zJy&lC0Ck^SSOt6Kh0G2e5Y%^|H_^Lhd@Hj9g~Pd$DqtTRU1=LPkr%Z`9X*|nLT zC1;1$9uMySJ&X3+?63>-KI$}A{UyQuEIw&ZAP{0SuE3@neX3W2SRI0TvXz=0)+XwG zdb-xj+2LX43uXrqX0yW`#>?5^2II|j+w{XWU20$5gnzKVu&aq@wvwQ}t1#w;keD5w zug2`~$QlnzFM*Pk68*daE7%?`_dj!h8F4q9cw?69V2c6jh_baBL+ zIy*=qHLlGL!<}Tbd+0Rhr$Nm7erl(Fl0+RKv%?WJ7{AL8+T84Lq4OYShk6j~W`|uz z$?R~}enqoGD_07tefo^5)(rV~nMcRI<^|d}cnOdES88_n+H0RS{9~OR4wjX%^eUYl zCRRfj?&=YF@$)<;xlA`CF?L^0cjkiq)(Rs@=%_uBuyPn#-emK91MC(-*_jm7H5WY3 zC6Z#~SDYkN7X$4Mo|5=`DP+x+*I5C({zE)dUc>91JYFRjUjOA9RFk>f@Vcw4%u=UH zQhtym>9$N%m&S;uD}}qFTFR8d>j_RW^s4#-dQEdHeZ%V^9usCX^cArRE=We%Z0Z>< z#)5A0V8+RFt<|p9N zUId`EncgMw`WBA|`1ceXWq5rB^F9vrRQ)BvSBLnd9ntW*oi9qN174G@6kZ?aG)K?a z_@vfLy#9sx0=%Z~(Rtzf#!I|jV7vu*E$nLIfS*{!@4JLCFN6eM9|EI>N9+C^4R3h; zsNa^d9#T5k2E0CAui`arHG$!E8(CorxI}oZRTkj&x+1*(?l-|}C8+UKvf=dyvNE*E zFnH$)=ciYg_x;pQ{UnJxK=8V1KE`jG{Wpi#&p7pg*F7QF;dTGJ1g{_2s|c?LyHc?9 z0j63rM8Bi{DWM{IDld2XPbnf;e zrDsO@LQc>cpOYY6NT_iPIHX2w1dF^p-$1O^HM0^=m?2)_YD`i2YWJrJY=+p~b9*j5 znXI|;W}m^6%Vc9qb^vXLSmP{Zz0zigC5}*&>1Q*LoKO9 z)o`K^><#{MnQG|G5bNc3kKjU0Fz&gc8R9cX58K`yyT)dSp|a*tRKYJ)O3o1HdOX?S ztjFLen;|+g?<3DBZJZ?dk{6$}ClCxVBDeQNNp+YZ$X05G*vn~-p7GhES}$ja_n0r3 zA*g#aLrgPX&Jd3nZ@~;9>}uk#cb6Grh%n}bkeDHkg;B#@-A0?u5X1bolpQLigA{n# zR&+c0D&2xDV-wg6(LmO4i5WtxESMp-_yQ%X>UF7FG<-#!5j@GS{aI!RC8+TdGsLrB zvD#>ccK`*)@aj2xa(JYKGX+6QT|OLT8BHU&ale$HL*e&q7#LW+KtH zDnEruE;AiTJVWH421hRFzDgKLLPwpAgyq3J-)HV8%sIZp$Q5S%KwX}yrH<@O*5PJ| zzrLaL%pzY%3$1a~_fjKCsBtM0sWB_ez$m`K454++T!<&k5btqCrl@?%cPOu|w;AGZ z*Lpzk46uebur6h?so^7!NeMPJyzB@ynJa8+xJFihsezJ|pCL*5OeU(tC$DhvK<t$0zxyOV z-w}zj+0-$rVMnLo<+AxEJkU^BMMLIP!yPd-?8wdr;rpnD6b=m~$)(4dhU1?T4Yi~a zRl|%B>1|MG{>Km09&c4VQZ&3ddB?mS}&)D8O#?< z4I<1od+s-0P7RgDTQD^UyP9~RT!0QP62`m`5>rDD7&YAVcx*bG8ZP(EQnrhf4h{gX zKQ%nb>m6zWn;OhTS08O$}{sld0jdRMFIMlq&_*e)^xP)(rVCnaAiD z_9zV%yo*Qv)2Si+3gc7nYA@B1x>T%E8~(#b94q3k4%yAb^-vgq|Bf?6xHT7ja#{BQ zEbqehlVg9>SLTV18B%)URKx`Kj!3DA&=K`%@)=;ejLlK-Wbc8i3Y zVln6?$)&r`Vi&;qAH$7oUP~%bd*mn~MC>OT`w;J~w214&@Uq9^7Hz97dKU`^0H^Gz zBHW9bf#Gf0a15=7HIueMUdvr=dEwvHzLHBjivurW-gP2(SG((b(neNSBHWIMK_y0#m7;l0;n~ z0NP+00CZXt0O$q({L5YKcFu7~A_BkXl+JO;jmJ21nY^`X;Tn`C#j7fU=T*k6|fVWtv zHtbf(z@9|h)n+0yIHLPKL04&ZS9^q$21g#2cMUy&dB}Q8wkm=qc$9`}aYM%-p=Cu$ zbo}xI*AlG%@7F4L7x+EqeROQ6cY!6T%CzT`R!10sQAYcsGOP~hNVZaUwV&{G!|&^? zUZUeUT5kd!MVJMbhZ`@^v9<9Qprf!WI$kMvp@X`@m={6<9Z$mAEu7?b(>AGtw@s+m z5=?O5({HE)Uv)=JFKg2u!qq#B4NmzHCTdj$nAo%k6VLfvFi{C=G&QOPmB%{CXzx+? zIsdd}-uF*O^^YWKc)`R!pTJ0cXeVIezuwi}-Sb>7GjTmUhrU(z5W2lR+Fk7{w}rN2 z(9$X7$!fy8+HW?30aWp?)q?Hbk4<6(?AoxKO!Hc#C2(Xd{ildvqP|(=MB!V|u;JW# zv^#V>n4ZJ^u!(d~o}@17_ZODOW7fnU?!?z*dh5^>VU+XjGLA{Ut*91SsUPnC?lmb_ zKCc#b4KS9id53E&7CEMx;47eQ!PT(ojvj6`I4*5N_Drv-_`E^MA$yR=gYUrK>$=45 z%==wp`ZwYxNpPc=Pl+M>^?S~;_)`ozWXV=)J@`kW-sz*XUJltunJ-umiZC0pBaD|r zcChgl3|V1U*UhdcTZN|!V_pb}Av+mMy>Rt|vFU6*c#f}LS$!!T3<0l>NDXJky1joJ zx+~s|O%M%Tt+HU~wkjIB|KnbBHlqYJUSjCp=_I4w756wlUC+Glr}^q9NpPbVPcn3m zo{TQGV*Aal2m3e=Vy0~X!EQac$3O{ZdTdh^&a`%=pxW~PQ`Pvh{`Z;3fVfsRI)b@) zT`LL3^gh~iF=iyMja=LR!*{QXOB-tJ z?ll!Z(I|-;>m>S!Hm-lYTV2kH{#)k#-ndYEqa@fx;!^@Op7upab=*Y)TPf6-@9CBe zhFHBsjR9J3Vxp(+(K6^X<0WczGTs8z5Ozh4VOt4m>>`YLAtX>^@K~V6oP2CLLyf(B z^~yfT(iA~g@cO86$q#WcLyafjjQeSX8d_xmYP2sxjmth3)KG#NFM%4}oMdQnG8M8# zPzO=YTLdjtKS`nv5Y*Uu61v!vn5qB$Piwb!9t3K9beE4BtF9E(Xuf3;YW$v1?QxW% zYDA5Pm|rN<1b}W0el?-6VpFI^joL)#cLPGC|=jKaQ=8c#9Fi2(Lml66RA9 zuJj1mRJt#IDTnx&$q}#aFyid3z@+?Gd654ok3Ux)yaEHA;x-d(o4m2dgcTHw%Qiqz z7-jMIP5baid9~rh1q3jmaOFb=*@a?`Ga=$7Y&|z*d2l~jE!-4|2}6=xdeeL*wqOXK z&1*>|YLDJl2==Bn9DBQ%XHBFGe(?}xv%!(3S3T8>6zC-kqL;i7y&6F;1Z$$#PO2A0 zLN7^j>Bmj4EW4>YWG;BYnB$&1KcyRx*QhOr7Y!~KzFxx_R3M7F}MSD6caKSFB4qtlG5QuE0z-(=z z-ls=uy#%v|nJ)-|L|AnH(Rc}FHyCdLm!smZ zFGu_|<_ktVb&tZAdyJPOez@@#jCf(!5&znH8S&={V_pb}5&sF6cH!UdYKe{bzP?$? z8cFHkY4G|Z{;{uOi`$6*0W)C1h}S9$MtrxT5&!r*GUAn>##7_ke#N~`GTNOT=KOR! z^S+;2sh=cK2gr!;{2;p64|O&-;;(WZ#E5SU!EVI2x>!bhpTCPn{9&#XR15D=)fm1k zV;%!yXcY|=yn#m<@pYo_eEg{6_=5Sd*}!%rmYDo!z3V6CY47vM_OFfgS)OGQV|08G z!9@Ku&sB&0I4&BYWT=;VdlrrL9!^e8=3*P`!iG{8FXC9|+lp$Tl^W}foCNMC&w(Ra z-W2y88|$lG18aghP^w^df6vjw7MI7RZLAOS+Jw6ZCCB=y9uM}fE7VaO>qjx~_n~&$ zha|zCWYJi!>x+`=xF`89V?E_GM_upTuJv-Pzs7vQSf}pMSbxNLIo2OA-h#0%>^jz$ z{3&C7fH3BTkQnQ~=P=f{m%b<+$j17Oep|{~N$KDX@cLtY&gZekZLDv?$SfG^T4ljl z?_D(3UwT8vx)RiQiLw5elZ^RA{py9{82R4Pj;oC+J>R38prw?<}o1d&B$0^jz|9Em&ty+KRWIH9yvtB zOT{Eu=j*bOo1Wyg0bdU#F`azjtPnOOqa1f0fputj^2pd3cG~@%V}_K$Q2<|?sfe=K z;2&A%>1p>98ljVlcwU$!o|hNskjcMm(&a_clM7{U1F6<2uJ4b50iESPcW-Fu1jhEPYzVQ}dr?9JM9^#imvcbW^ zm={6Q*X*?WNMF6wR9PgJeRDG{5=`ckZV%t$_Wuk$UxDq-2oQn1S)%Z| zP`@Jd9QwMTrxMhB3G}?&Nrn=AsEcj%bQirmPfbxzNun+g^xR_<(DRjbK+g;Q?Xo&*!{$baEfcOPU29U%){ z^HB4rSd|r@c0cNP5Kr}oK6N0>?KSVHqK0~G*q^uwD&)$y!0I-- z@3^kSN=W7#jTfM9hldD^!P_JbuNHPWs1`QRN9Z0#Hz(%_mBTlv?D?nB#=pjjkb6{! z@QM)OfskV$1WjFy^s$4AV{OH(S#eL&)9%wCXj8hQ{C_b14__UC5npuLeY;l< z-#umP%^CYJkBVzZLQC=Gr7X?OrLjhIFGRbFN05K`rP0TzV9)VoV$xR&4^+zna<(eX>> zeRS-ir>Tu>WKA5*@G5dK2gjSIiSkRDv2!B_k}N56^Ov(cV+9cm6q+dEY-h)jyJ`;RO@xXE9Qr zUJFe8*VFEUJkQ~0N*mxgG_%>QXr?{dY4^|{*6V3^C3z4aFyU$UpE!OtldRDp(&@R_ zBu21R-z#2=w5hhkGo^@NqW*j~78N$*Pt9?6hxgU-DI6vVAs0I#HJJ-_0Oo}opRABV za+UicAXBB#E2@R7)Z(v+lLf@9GZl8+4`bIVJX}HSSJ%#(;C`%=3l@Ki9X;Il+_>bTJZwo)5CO`YcGdW#2X zy&R%7%oi;FsC%^dn{2!sqGOG>V2BF44$)7)lOZ}t81q6%4AE{_;)XlA9X4D1-R!re zthJO5T7p+cpoT9mW07zEvY}dcdfb_!p{i9D4AsF!Lv`*;GE|kI#!C#bd^UBHB;`FNNuSF^e+be9(QKt~S5!-xQa=Pa*Gb0c zeQgR%d&Q-3Z@|c5vkvu`@L71cg{_C~?W1fqwUq1QZ19OJlLb9GjbLkq2f>rD${Lh8 zj*H>*{oiQMorHdaKO3Yzmn4@yWCFWkZFu+{5QXorctjl)dkR5If$y11MD>o5S_tu? zY&LbGYS`InIFa!_fs2biX z1bb5(Zl@Z0r(R2BzO+-Xn{O?G##xRYHaJ__=lu}mT;MI5V3)=hmW0N%$CC}(UJXat zilGJb{*ddYjgzD*)00oy5s3m_a>4gcx$1BiQll5Lm4e2NiF#*UrS%dTpJKiM8bz2z zFInRyG~RB!1<)w$YT|h-1sZz@V_paeXzYd6Z1~3wvFQvNFZ9(bYbd3I|A5zr#)tXQ zF*Sifj)O$ zk^k(6AfI4->JLHQ(~%l&js4C??E4@zBDSQ!fpqb%-;%F0-`#{Ta~0UA;<=!HoJy}Xb?@Ba{FzwyFNu^9A{;gE= zXY7X~c#o((a-DeQ+jW08#z;V7u)HXgMgou5P zvFGG%>TfPFO_s7>@3F&lTU`|U(YD6k6C{lSgJ*4x+GitmtHInf4R6ABZb!``%Q3E4 zO>iW53L?wFjvl^!T3o3`mb*Ugn|e`6`1}L6=^}{5KJew*_i53U%sY$XBW5}*B>^ZG z!RJ%Hs0^z^WJ$JCTVr!Q-EjZW>Lq+$rS&Eje+l){na#7FanSK7vAfZ+dC*OJndwl z=F_pVE#4Zday$@rI`k>IHP+W-%cbwW1S;gpFNMUg%O9{Yetrh~Pz~7eG%lg>$Gya2 zL34%-P`3r38?o$vNE}`*?6RvRY@lCpmH2(2le4|b;Tu#oWgOc0`A8A++jSyDctwct zKuAjnK~paQy)yWiTS3ig8o#rHJ0;5 zNp(O+vX$Bzo9J0E8=PnL5*<&|dK2hK-J^B)LB>mT+}n5y&{5bG9s9~{?clFIY)oDV z33Tj+C3X0qyPINLV|5bh$+|n2ZuviT;GB7Je=tn^@5I>B5hiL?1(-Oh2oq16D!ow& zYBcqs1(ofcWVH8SHp4J+Uulwui38O?lBnSY6Mw!5BlW*4Hn%mlv*$VdwcU*{Hu~09 z+y=5o+ZyY;)V9X@kq5sNWx}noK3m0o_s=@W;)8Co_S1MESN<24+~LOOV!PRbd#vBO z)Q4a~BR^uIUo!h$elg4NVIc+l;x?uxVPvD0b3FlSH(PRd^a$DDE{e>h9~nzG)rKb{ zk{bc7$88yF{fNq|?-k3H-v|D17YtV$mbRW==`{^sQ?RHGnzvvza1Xm?6Xqoz^}i?o zz-STPWruWSiaOZQ z!#huiOB+snD8LjgLRXZ;iRm5>e&>6kHk3Fqo_QZ9W^1e|3H}xXpVT!R8t~brzNieV z15S{w)FO27c)BbKD-X7Mi4*&3y$PHUVHQPgZM<~G-@Vis1vnw>YT_g1es=J_Fy@7j z#0kus;UIUfrIYrTPyDu&WuJ+qzsBxIm2J z3)Ld@z!kC^3zpfFj3gJKGN8#K^xhj~Y>_P5OW=F6(?$E(+;FUT`p5YU7pYogiX^P) z>vi-!Vw$NFktN#9ioIcnvn{0;p;>o0{f2eARSeE&=*x!I(kSwtGRRsq`|DhefI~9MKA&;8BUT^i zL!3DG`R#3Xvi$iQJ5%jGmo2whv}s7_KBu|jEDTJ&$g$`|aqU=?FMBB~NmwvqNmJydp!s9-BmSXr`lWo)KMdf=CjN!W3qm-d$q^wz&MaiHan6zUwWRTJkk4ine3^d~MA77myf zC}T~{Ri@7o;HRQ8(tKD%#A-e zfqkSOO}bYf#*dmRo{9MdX%da@-N5TMHI8o68Y~n z{M*p!JdE085&GUTcRRUh9O*KeiOQHOuF3cmsePcDTV(}ny38VU!M|lI)bnS~XY^Q} zU=ezSlSjkf&a^v^UTePedq)FRBu(TvV)b(;yn|KIs z)N$jyql~V+<2!#9wH=7ah|475@s4M*d~ay48oPKnq!*#H++_(IDVF?;``mqls=(fl z+3i95#Dj0PE6VbTDyul3xVni?d|B)uFPy6gWi*dZeBvfMWs33eSY;$UUi!qcGJ5L4uP0lC-r%Uus*_O`*T5KmF~!ukdJ+20%X$$yLd4;N&;sHXp+Bib z=)JPFTZ_=$te6|V{iAI+y$C(RmGQzO{vwyvfsF#xBJ{J>NXY5K6C#0fu_vX>qZgsu zUFK1QUW7jDA~^pel3d*9_{FLMUt*S%co90sCAN4_TjDn?rMv1(^&)hlD-zF19T(YF zWTO|MDdJkrN8QhA51T98u9OkxlfJZ1XRX#kF*{m##Fj}yQjw|=S4%>N@cy5pQ9m`b zyy_U6zrTxo+$`#0hi_=n&n}Pl6Qgf*+8B>Y68eeLTyc2+Z;UFaXop9OYj-;wBTB{B z;|1^}RDh})(KT>OyJR=g>q?m&enLb`v+L0OLu;KZ~8n zq|y$<=ma}hmyCyUhe0hu=PZ`pSg=fdWF)x=l>xHTyPt#}ceRWyl0|z7i~9^NRlevJ z@i>n^dg3Bgi@Z`2R`fG;^eL`TS)#{Tu{Y#78)bSC`s^ZipAK5Z*gQ8wUpCB@Mv?cF zK?ci3sJQYx2_2)i3q)tn5!X&5au%TjIMqjQ7a37T35)wYGDVf~aWOYuxJ;$2NL9w$ zBwAq{W4c{n#+&bc0KAv=u4bML<{w&RRTAP1c-N`{38ZpD|0a+ z4W~5O!@I!|s}BT;6X!lF9lqg(o_40%eYU&a$&|kMf!%n-e1db`!sqQ-;Kbqk59gqm z-W&RtxOObcIUZ#~37i2EcOLh7k2@)u9qv;^OSA}G=hBVuKj?gg`<$%u_3YsZ-7WVy zSjQFav#*XD=RRe0Rgu$Q5N;`Ou#C7&5+3*2@nQ`BaGq^Cy$C(Rt=HgrPLC$?x?>Ak9UggAL5jqron9{k9>>a9-8t;m> zxX(4iQDO0*GfA=GthcZ+PeQSePy+?i#l`|puB62RM~W!}>K;8+IE_FnLGmP2L|0Ej zMKt({qow*)PCC2gYJ08-A+xsEQpW9<$wXce%(c(Sxavu$PUIL8p{VD;&kw8-u~dEQ zMd;1f*)2&u30*)Gv(FXs-wOV1xbrNuXtD^s*d@0x&_+y~%{f!KfFIAL zZRuOR2p#{dUW8_dI1A@W5R1@%IL{PQR2Ml;wstii*gSU^x(R>O@SHgIxIo?`FM=_w z+*hDA|FFXDXsIfdH>Js~RK%$MxFRla*+m)bF+~h=i2Avg=pHyi>_L!0=uXk~MCk12 zB$w#jfT&CJ#e-hD3at;K%j&M#Pi6Cl6RAG1gZ+TGdCOA{-_W{?EvMYKfAzL+Q9r?OSP zqGvuRuH%+{GBMpVuh(%!&-|T^8`m>sbk#He{3qEn$H|DxB;o0qE6%59e&-xQ(aXL| z-0B^Ch?EXg5m$9QHEUV9(zdwnp&wI?aXnOJ8P`L%H0h!DE|fh~5z2U;9=ga$nR3r# zdS%tq<>K01Py19oNl+Cad+6W`X<{G$CE2oXic^COsE3lUv+O(RL^*3ISl?vU($kSb zwGYo$s-3{~o8p=dQ788^0-LxMKfUbR!J0-b`(6{P8)wE|T71VcyVfq+K6+*>{T*nN(I|7@go+>vCb>Ub&`M%f7`|NxvajrW!JmT=vO; zCduqy7;YC z@i+a>ZebAXtzz)%kG^cUK^jHgQwA9Ov+R4!wRdozckjSi_6@FWI|`ZX-^d`<&tM4Szk!&Q!b4qh~pp@;6cwy3g;faN;oj zXFA>TLviiymRpnwCGfOH+?IhSq=12c5K!hKFv`FbWcLU(J~ zcdm{r+~?UkZk+p+(N#rWwGI<=4p2s1CJB%GyfPQVKjoZy(aXN$-Rd1NhDbbneECcP zfpf&2a-b9Mux+j#=zW*l_EesBp|V8$;f-xg9BAP@q3K*jC?SsnJ=aMYC58%J^b}`+ z)XO!+*`aDmf~o@PKwFH(f!_B_vSr^XP95Svw+(bV&<~E44)oY3nmEv}JgVJ`lu%79 z`)(1}^oV|gg`oo1aw~ofOPq!FA<8eTanc~?M_8seUG~j);*i)V^l3q2&YN0#*;nX_ zwz$v20jRKe&?-`F7%rZ*U{z3aJXA6#rSTxm@=Slr%Ob~3{(m7+UI0+xnh&i z;7irMPMVX>c`6+dLS{#CSfSya0-4AeDiIl1CL-gI$VntZQD0=yK0k1Th^6XVFZ=G8 zX}2V`?E8j@W}n^i-#7TT;r<>NwaK!t$R)QhaD*tmu8af4H5orBPbmbx@2@I@MyDsJ zEc*_AO}0WSAgy8D6>{0v@EMEL&)PTa77Jcyq-!l4pHf?Y1a^0wt#-qiy=3GJ=A%M~ zK*OWzOHoe11*G0^UFJ`GiEZJ~eZ?bAYk6`8RZ7%#k4DXxUmQ1L!AGLq3`#ND5zggo zF4MTI4_wXFVTAk+6uIU_EI*aVz*SX6UE);Knx*~Nqyj-;)>XhfTZ@N zfW?80>h3M!j5Y_p0D6c-HwQlBQWa_sSBDbyJEh{sD(V@eFMjobHe88>10u%-f!7o- ze6`eXb6}UgtPi};)saNKUc^}tcv}F6BXX#d1%Z#m-R8i*feuQCPqFwVQ6_`$y?Jkf%{4prO_XArm`@VdSeupp2wWrcl&tl(tD zE)Jv~E)Ba?#ePW1){DE%fg(T|Hd9=Y(?4Z@3tXULcNVZ9kcFDW9tUV^jMbO*fjq86 zp~isXS05P6RSN9`S=l~7@gwoNBUJlPiFZ`0OjUQe0u}_0K$z4{1$4vg%%!ql23I1h zlR@#T4;;mn&^oMyGh}BEoUSEwI!gF7Ei4jI!p8{V`oLslg`N{Z@guoyZKa+UiBuN{ zX5nBU_+C#oiZ@vQyOEY5@xZqF(9)w{s(8 zZw0meI<%Ad-lSr0RI&@j-R8hP_NYWA^?|>OEA(nDO1mKNnb^x(9M~XWL13K7eskbK zKqk65@JD@FA6U(mu-|>4_|*q)zKq zFKr_=@250xtu*hc?hX^MAaDi3q_zamnl09s^?@6>5-zEqh_fItAD{#BuPEmm3#DgT zC8tpLhgcZau88R z2^49HnBxAo-)|Q9%>ut!;5Q5WW`W-<@S6piYk?MWc4!!yYa*eF?uFH5k z8!?Pbot)9k^oqh2Ris%Hu2kt&N6NE{i!UCMZJ^8I#)e9a+M4S8@Q_e> zxq;5ZhtyV9he}3;hs-Q04;d6}SYf2FTxZzK{7OU;GRy3mnoxD5EL@orDhU-ujOxO& znve<@za=
        $plainName + $content +
      +""" + # Chunk of HTML emitted for each entry in the HTML table of contents. # Available variables are: # * $desc: the actual docstring of the item. @@ -54,6 +60,14 @@ doc.item.toc = """ title="$header_plain">$name$attype """ +# This is used for TOC items which are grouped by the same name (e.g. procs). +doc.item.tocTable = """ +
    • $itemSymOrID$attype
    • +""" + + + # HTML rendered for doc.item's seeSrc variable. Note that this will render to # the empty string if you don't pass anything through --git.url. Available # substitutaion variables here are: diff --git a/doc/nimdoc.css b/doc/nimdoc.css index fb9efd858..e0c5a1de4 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -154,10 +154,12 @@ body { margin-left: 0; } .three.columns { - width: 19%; } + width: 22%; + line-break: anywhere; +} .nine.columns { - width: 80.0%; } + width: 77.0%; } .twelve.columns { width: 100%; @@ -420,7 +422,7 @@ ul.simple-boot li { } ol.simple > li, ul.simple > li { - margin-bottom: 0.25em; + margin-bottom: 0.2em; margin-left: 0.4em } ul.simple.simple-toc > li { @@ -439,9 +441,19 @@ ul.simple-toc > li { ul.simple-toc-section { list-style-type: circle; - margin-left: 1em; + margin-left: 0.8em; color: #6c9aae; } +ul.nested-toc-section { + list-style-type: circle; + margin-left: -0.75em; + color: var(--text); +} + +ul.nested-toc-section > li { + margin-left: 1.25em; +} + ol.arabic { list-style: decimal; } diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index f35334503..d6e318f7d 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -94,8 +94,11 @@ function main() {
    • Procs
        +
          foo
        • foo
        • + title="foo()">foo + +
    • diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index eefbcfdf9..ebbedc648 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -108,8 +108,11 @@ function main() {
    • Procs
        +
          someType
        • someTypeSomeType
        • + title="someType(): SomeType">someType_2SomeType + +
    • diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 479a2e89d..9c06211c9 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -137,74 +137,164 @@ function main() {
    • Procs
    • Funcs
        +
          someFunc
        • someFunc
        • + title="someFunc()">someFunc + +
    • From af9cc2882f2863712ddc29b2f0f36df1f26db551 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 5 Oct 2020 23:04:08 +0800 Subject: [PATCH 1203/4254] use func in uri module (#15486) --- lib/pure/uri.nim | 52 ++++++++++++++++----------------- tests/effects/tstrict_funcs.nim | 2 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 4b84a8902..3e107a6b8 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -59,7 +59,7 @@ type opaque*: bool isIpv6: bool # not expose it for compatibility. -proc encodeUrl*(s: string, usePlus = true): string = +func encodeUrl*(s: string, usePlus = true): string = ## Encodes a URL according to RFC3986. ## ## This means that characters in the set @@ -72,7 +72,7 @@ proc encodeUrl*(s: string, usePlus = true): string = ## spaces are encoded as ``+`` instead of ``%20``. ## ## **See also:** - ## * `decodeUrl proc<#decodeUrl,string>`_ + ## * `decodeUrl func<#decodeUrl,string>`_ runnableExamples: assert encodeUrl("https://nim-lang.org") == "https%3A%2F%2Fnim-lang.org" assert encodeUrl("https://nim-lang.org/this is a test") == "https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test" @@ -88,7 +88,7 @@ proc encodeUrl*(s: string, usePlus = true): string = add(result, '%') add(result, toHex(ord(c), 2)) -proc decodeUrl*(s: string, decodePlus = true): string = +func decodeUrl*(s: string, decodePlus = true): string = ## Decodes a URL according to RFC3986. ## ## This means that any ``%xx`` (where ``xx`` denotes a hexadecimal @@ -100,7 +100,7 @@ proc decodeUrl*(s: string, decodePlus = true): string = ## characters are converted to a space. ## ## **See also:** - ## * `encodeUrl proc<#encodeUrl,string>`_ + ## * `encodeUrl func<#encodeUrl,string>`_ runnableExamples: assert decodeUrl("https%3A%2F%2Fnim-lang.org") == "https://nim-lang.org" assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test" @@ -125,7 +125,7 @@ proc decodeUrl*(s: string, decodePlus = true): string = inc(j) setLen(result, j) -proc encodeQuery*(query: openArray[(string, string)], usePlus = true, +func encodeQuery*(query: openArray[(string, string)], usePlus = true, omitEq = true): string = ## Encodes a set of (key, value) parameters into a URL query string. ## @@ -138,7 +138,7 @@ proc encodeQuery*(query: openArray[(string, string)], usePlus = true, ## is used for the URL encoding of the string values. ## ## **See also:** - ## * `encodeUrl proc<#encodeUrl,string>`_ + ## * `encodeUrl func<#encodeUrl,string>`_ runnableExamples: assert encodeQuery({: }) == "" assert encodeQuery({"a": "1", "b": "2"}) == "a=1&b=2" @@ -153,7 +153,7 @@ proc encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add('=') result.add(encodeUrl(val, usePlus)) -proc parseAuthority(authority: string, result: var Uri) = +func parseAuthority(authority: string, result: var Uri) = var i = 0 var inPort = false var inIPv6 = false @@ -182,7 +182,7 @@ proc parseAuthority(authority: string, result: var Uri) = result.hostname.add(authority[i]) i.inc -proc parsePath(uri: string, i: var int, result: var Uri) = +func parsePath(uri: string, i: var int, result: var Uri) = i.inc parseUntil(uri, result.path, {'?', '#'}, i) @@ -199,7 +199,7 @@ proc parsePath(uri: string, i: var int, result: var Uri) = i.inc # Skip '#' i.inc parseUntil(uri, result.anchor, {}, i) -proc initUri*(): Uri = +func initUri*(): Uri = ## Initializes a URI with ``scheme``, ``username``, ``password``, ## ``hostname``, ``port``, ``path``, ``query`` and ``anchor``. ## @@ -211,7 +211,7 @@ proc initUri*(): Uri = result = Uri(scheme: "", username: "", password: "", hostname: "", port: "", path: "", query: "", anchor: "") -proc initUri*(isIpv6: bool): Uri {.since: (1, 3, 5).} = +func initUri*(isIpv6: bool): Uri {.since: (1, 3, 5).} = ## Initializes a URI with ``scheme``, ``username``, ``password``, ## ``hostname``, ``port``, ``path``, ``query``, ``anchor`` and ``isIpv6``. ## @@ -226,19 +226,19 @@ proc initUri*(isIpv6: bool): Uri {.since: (1, 3, 5).} = result = Uri(scheme: "", username: "", password: "", hostname: "", port: "", path: "", query: "", anchor: "", isIpv6: isIpv6) -proc resetUri(uri: var Uri) = +func resetUri(uri: var Uri) = for f in uri.fields: when f is string: f.setLen(0) else: f = false -proc parseUri*(uri: string, result: var Uri) = +func parseUri*(uri: string, result: var Uri) = ## Parses a URI. The `result` variable will be cleared before. ## ## **See also:** ## * `Uri type <#Uri>`_ for available fields in the URI type - ## * `initUri proc <#initUri>`_ for initializing a URI + ## * `initUri func <#initUri>`_ for initializing a URI runnableExamples: var res = initUri() parseUri("https://nim-lang.org/docs/manual.html", res) @@ -281,7 +281,7 @@ proc parseUri*(uri: string, result: var Uri) = # Path parsePath(uri, i, result) -proc parseUri*(uri: string): Uri = +func parseUri*(uri: string): Uri = ## Parses a URI and returns it. ## ## **See also:** @@ -294,7 +294,7 @@ proc parseUri*(uri: string): Uri = result = initUri() parseUri(uri, result) -proc removeDotSegments(path: string): string = +func removeDotSegments(path: string): string = if path.len == 0: return "" var collection: seq[string] = @[] let endsWithSlash = path[path.len-1] == '/' @@ -324,7 +324,7 @@ proc removeDotSegments(path: string): string = result = collection.join("/") if endsWithSlash: result.add '/' -proc merge(base, reference: Uri): string = +func merge(base, reference: Uri): string = # http://tools.ietf.org/html/rfc3986#section-5.2.3 if base.hostname != "" and base.path == "": '/' & reference.path @@ -335,7 +335,7 @@ proc merge(base, reference: Uri): string = else: base.path[0 .. lastSegment] & reference.path -proc combine*(base: Uri, reference: Uri): Uri = +func combine*(base: Uri, reference: Uri): Uri = ## Combines a base URI with a reference URI. ## ## This uses the algorithm specified in @@ -345,7 +345,7 @@ proc combine*(base: Uri, reference: Uri): Uri = ## URIs path affect the resulting URI. ## ## **See also:** - ## * `/ proc <#/,Uri,string>`_ for building URIs + ## * `/ func <#/,Uri,string>`_ for building URIs runnableExamples: let foo = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("/baz")) assert foo.path == "/baz" @@ -386,11 +386,11 @@ proc combine*(base: Uri, reference: Uri): Uri = result.scheme = base.scheme result.anchor = reference.anchor -proc combine*(uris: varargs[Uri]): Uri = +func combine*(uris: varargs[Uri]): Uri = ## Combines multiple URIs together. ## ## **See also:** - ## * `/ proc <#/,Uri,string>`_ for building URIs + ## * `/ func <#/,Uri,string>`_ for building URIs runnableExamples: let foo = combine(parseUri("https://nim-lang.org/"), parseUri("docs/"), parseUri("manual.html")) @@ -400,7 +400,7 @@ proc combine*(uris: varargs[Uri]): Uri = for i in 1 ..< uris.len: result = combine(result, uris[i]) -proc isAbsolute*(uri: Uri): bool = +func isAbsolute*(uri: Uri): bool = ## Returns true if URI is absolute, false otherwise. runnableExamples: let foo = parseUri("https://nim-lang.org") @@ -409,15 +409,15 @@ proc isAbsolute*(uri: Uri): bool = assert isAbsolute(bar) == false return uri.scheme != "" and (uri.hostname != "" or uri.path != "") -proc `/`*(x: Uri, path: string): Uri = +func `/`*(x: Uri, path: string): Uri = ## Concatenates the path specified to the specified URIs path. ## - ## Contrary to the `combine proc <#combine,Uri,Uri>`_ you do not have to worry about + ## Contrary to the `combine func <#combine,Uri,Uri>`_ you do not have to worry about ## the slashes at the beginning and end of the path and URIs path ## respectively. ## ## **See also:** - ## * `combine proc <#combine,Uri,Uri>`_ + ## * `combine func <#combine,Uri,Uri>`_ runnableExamples: let foo = parseUri("https://nim-lang.org/foo/bar") / "/baz" assert foo.path == "/foo/bar/baz" @@ -443,7 +443,7 @@ proc `/`*(x: Uri, path: string): Uri = result.path.add '/' result.path.add(path) -proc `?`*(u: Uri, query: openArray[(string, string)]): Uri = +func `?`*(u: Uri, query: openArray[(string, string)]): Uri = ## Concatenates the query parameters to the specified URI object. runnableExamples: let foo = parseUri("https://example.com") / "foo" ? {"bar": "qux"} @@ -451,7 +451,7 @@ proc `?`*(u: Uri, query: openArray[(string, string)]): Uri = result = u result.query = encodeQuery(query) -proc `$`*(u: Uri): string = +func `$`*(u: Uri): string = ## Returns the string representation of the specified URI object. runnableExamples: let foo = parseUri("https://nim-lang.org") diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 38f5b7601..166ab77c1 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim c --experimental:strictFuncs --experimental:views $file" """ -import tables, streams, nre, parsecsv +import tables, streams, nre, parsecsv, uri type Contig2Reads = TableRef[string, seq[string]] From f25ca0d3043c67a73b9eb78c36f910daee631a18 Mon Sep 17 00:00:00 2001 From: David Krause Date: Mon, 5 Oct 2020 17:04:47 +0200 Subject: [PATCH 1204/4254] added testament documentation link to tools.rst (#15481) --- doc/tools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tools.rst b/doc/tools.rst index 66cbdca26..df4d2e99f 100644 --- a/doc/tools.rst +++ b/doc/tools.rst @@ -30,7 +30,7 @@ The standard distribution ships with the following tools: | ``nimpretty`` is a Nim source code beautifier, to format code according to the official style guide. -- | testament +- | `testament `_ | ``testament`` is an advanced automatic *unittests runner* for Nim tests, is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, JS, etc), From 1e28cea0d102afd43a62f6f7fcabd65cd8996762 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 5 Oct 2020 12:08:50 -0300 Subject: [PATCH 1205/4254] inline tiny func on httpcore (#15480) --- lib/pure/httpcore.nim | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index e7da77ae8..af1bfc088 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -113,7 +113,7 @@ func toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = return if headers.isTitleCase: toTitleCase(s) else: toLowerAscii(s) func newHttpHeaders*(titleCase=false): HttpHeaders = - ## Returns a new ``HttpHeaders`` object. if ``titleCase`` is set to true, + ## Returns a new ``HttpHeaders`` object. if ``titleCase`` is set to true, ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() @@ -121,7 +121,7 @@ func newHttpHeaders*(titleCase=false): HttpHeaders = func newHttpHeaders*(keyValuePairs: openArray[tuple[key: string, val: string]], titleCase=false): HttpHeaders = - ## Returns a new ``HttpHeaders`` object from an array. if ``titleCase`` is set to true, + ## Returns a new ``HttpHeaders`` object from an array. if ``titleCase`` is set to true, ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() @@ -134,10 +134,10 @@ func newHttpHeaders*(keyValuePairs: result.table[key] = @[pair.val] -func `$`*(headers: HttpHeaders): string = - return $headers.table +func `$`*(headers: HttpHeaders): string {.inline.} = + $headers.table -proc clear*(headers: HttpHeaders) = +proc clear*(headers: HttpHeaders) {.inline.} = headers.table.clear() func `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = @@ -206,7 +206,7 @@ func getOrDefault*(headers: HttpHeaders, key: string, else: return default -func len*(headers: HttpHeaders): int = return headers.table.len +func len*(headers: HttpHeaders): int {.inline.} = headers.table.len func parseList(line: string, list: var seq[string], start: int): int = var i = 0 @@ -323,21 +323,21 @@ proc `==`*(rawCode: string, code: HttpCode): bool ## string form of itself. return cmpIgnoreCase(rawCode, $code) == 0 -func is2xx*(code: HttpCode): bool = +func is2xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 2xx HTTP status code. - return code.int in {200 .. 299} + code.int in {200 .. 299} -func is3xx*(code: HttpCode): bool = +func is3xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 3xx HTTP status code. - return code.int in {300 .. 399} + code.int in {300 .. 399} -func is4xx*(code: HttpCode): bool = +func is4xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 4xx HTTP status code. - return code.int in {400 .. 499} + code.int in {400 .. 499} -func is5xx*(code: HttpCode): bool = +func is5xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 5xx HTTP status code. - return code.int in {500 .. 599} + code.int in {500 .. 599} func `$`*(httpMethod: HttpMethod): string = return (system.`$`(httpMethod))[4 .. ^1].toUpperAscii() @@ -366,5 +366,3 @@ when isMainModule: doAssert testTitleCase.hasKey("Content-Length") for key, val in testTitleCase: doAssert key == "Content-Length" - - From 4e438f9096fc413824bdbe8377a4ca376d63be35 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 5 Oct 2020 18:31:46 +0200 Subject: [PATCH 1206/4254] const view types; fixes some cases from https://github.com/nim-lang/Nim/issues/15428 (#15488) --- compiler/astalgo.nim | 9 +++- compiler/ccgexprs.nim | 95 ++++++++++++++++++++---------------- compiler/ccgstmts.nim | 4 +- compiler/cgen.nim | 3 +- compiler/typeallowed.nim | 2 +- compiler/vmgen.nim | 2 +- tests/views/tconst_views.nim | 26 ++++++++++ 7 files changed, 94 insertions(+), 47 deletions(-) create mode 100644 tests/views/tconst_views.nim diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 5e23d2284..6aecb1dcb 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -591,10 +591,17 @@ proc value(this: var DebugPrinter; value: PNode) = if this.conf != nil: this.key "info" this.value $lineInfoToStr(this.conf, value.info) - if card(value.flags) > 0: + if value.flags != {}: this.key "flags" this.value value.flags + if value.typ != nil: + this.key "typ" + this.value value.typ.kind + else: + this.key "typ" + this.value "nil" + case value.kind of nkCharLit..nkUInt64Lit: this.key "intVal" diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b58519614..364bcc143 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1400,7 +1400,7 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) = # expression not found in the cache: inc(p.module.labels) p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", - [getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true)]) + [getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true, t)]) proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr: @@ -2485,7 +2485,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = inc(p.module.labels) var tmp = "CNSTCLOSURE" & rope(p.module.labels) p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", - [getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true)]) + [getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true, n.typ)]) putIntoDest(p, d, n, tmp, OnStatic) else: var tmp, a, b: TLoc @@ -2624,7 +2624,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = # expression not found in the cache: inc(p.module.labels) p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", - [getTypeDesc(p.module, t), tmp, genBracedInit(p, n, isConst = true)]) + [getTypeDesc(p.module, t, skConst), tmp, genBracedInit(p, n, isConst = true, t)]) if d.k == locNone: fillLoc(d, locData, n, tmp, OnStatic) @@ -2847,8 +2847,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope = - if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst) - else: result = genBracedInit(p, n, isConst) + if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst, n[0].typ) + else: result = genBracedInit(p, n, isConst, n.typ) proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc}) @@ -2955,10 +2955,10 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, for i in 1.. 0: - result.add(genNamedConstExpr(p, n[^1], isConst)) - result.addf("}$n", []) + for i in 0.. 0: result.add ",\n" + if it.kind == nkExprColonExpr: result.add genBracedInit(p, it[1], isConst, it[0].typ) + else: result.add genBracedInit(p, it, isConst, it.typ) + result.add("}\n") + +proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType): Rope = + result = rope("{") + for i in 0.. 0: result.add ",\n" + if it.kind == nkExprColonExpr: result.add genBracedInit(p, it[1], isConst, tup[i]) + else: result.add genBracedInit(p, it, isConst, tup[i]) + result.add("}\n") proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope = var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope] + let base = t.skipTypes(abstractInst)[0] if n.len > 0: # array part needs extra curlies: data.add(", {") for i in 0.. 0: data.addf(",$n", []) - data.add genBracedInit(p, n[i], isConst) + data.add genBracedInit(p, n[i], isConst, base) data.add("}") data.add("}") result = getTempName(p.module) - let base = t.skipTypes(abstractInst)[0] appcg(p.module, cfsData, "static $5 struct {$n" & @@ -3030,14 +3040,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope = result = "(($1)&$2)" % [getTypeDesc(p.module, t), result] proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope = + let base = t.skipTypes(abstractInst)[0] var data = rope"{" for i in 0.. 0: data.addf(",$n", []) - data.add genBracedInit(p, n[i], isConst) + data.add genBracedInit(p, n[i], isConst, base) data.add("}") let payload = getTempName(p.module) - let base = t.skipTypes(abstractInst)[0] appcg(p.module, cfsData, "static $5 struct {$n" & @@ -3047,46 +3057,32 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope = if isConst: "const" else: ""]) result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload] -proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = +proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope = case n.kind of nkHiddenStdConv, nkHiddenSubConv: - when false: - # XXX The frontend doesn't keep conversions to openArray for us. :-( - # We need to change 'transformConv' first, but that is hard. - if n.typ.kind == tyOpenArray: - assert n[1].kind == nkBracket - let data = genBracedInit(p, n[1], isConst) - - let payload = getTempName(p.module) - let ctype = getTypeDesc(p.module, n.typ.skipTypes(abstractInst)[0]) - let arrLen = n[1].len - appcg(p.module, cfsData, - "static $5 $1 $3[$2] = $4;$n", [ - ctype, arrLen, payload, data, - if isConst: "const" else: ""]) - result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen] - else: - result = genBracedInit(p, n[1], isConst) + result = genBracedInit(p, n[1], isConst, n.typ) else: var ty = tyNone - if n.typ == nil: + var typ: PType = nil + if optionalType == nil: if n.kind in nkStrKinds: ty = tyString else: internalError(p.config, n.info, "node has no type") else: - ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind + typ = skipTypes(optionalType, abstractInstOwned + {tyStatic}) + ty = typ.kind case ty of tySet: let cs = toBitSet(p.config, n) result = genRawSetData(cs, int(getSize(p.config, n.typ))) of tySequence: if optSeqDestructors in p.config.globalOptions: - result = genConstSeqV2(p, n, n.typ, isConst) + result = genConstSeqV2(p, n, typ, isConst) else: - result = genConstSeq(p, n, n.typ, isConst) + result = genConstSeq(p, n, typ, isConst) of tyProc: - if n.typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit: + if typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit: # Conversion: nimcall -> closure. # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} # this behaviour is needed since closure_var = nil must be @@ -3099,13 +3095,30 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = else: var d: TLoc initLocExpr(p, n[0], d) - result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, n.typ, clHalfWithEnv), rdLoc(d)] + result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)] else: var d: TLoc initLocExpr(p, n, d) result = rdLoc(d) - of tyArray, tyTuple, tyOpenArray, tyVarargs: + of tyArray, tyVarargs: result = genConstSimpleList(p, n, isConst) + of tyTuple: + result = genConstTuple(p, n, isConst, typ) + of tyOpenArray: + if n.kind != nkBracket: + internalError(p.config, n.info, "const openArray expression is not an array construction") + + let data = genConstSimpleList(p, n, isConst) + + let payload = getTempName(p.module) + let ctype = getTypeDesc(p.module, typ[0]) + let arrLen = n.len + appcg(p.module, cfsData, + "static $5 $1 $3[$2] = $4;$n", [ + ctype, arrLen, payload, data, + if isConst: "const" else: ""]) + result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen] + of tyObject: result = genConstObjConstr(p, n, isConst) of tyString, tyCString: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 5bed7cf32..1282cf11f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -272,7 +272,7 @@ proc genGotoVar(p: BProc; value: PNode) = else: lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope]) -proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope +proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope = if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn: @@ -280,7 +280,7 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope = elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ): #echo "New code produced for ", v.name.s, " ", p.config $ value.info - result = genBracedInit(p, value, isConst = false) + result = genBracedInit(p, value, isConst = false, v.typ) else: result = nil diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f50676647..9a50b718c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1195,7 +1195,8 @@ proc requestConstImpl(p: BProc, sym: PSym) = # add a suffix for hcr - will later init the global pointer with this data let actualConstName = if m.hcrOn: sym.loc.r & "_const" else: sym.loc.r q.s[cfsData].addf("N_LIB_PRIVATE NIM_CONST $1 $2 = $3;$n", - [getTypeDesc(q, sym.typ), actualConstName, genBracedInit(q.initProc, sym.ast, isConst = true)]) + [getTypeDesc(q, sym.typ), actualConstName, + genBracedInit(q.initProc, sym.ast, isConst = true, sym.typ)]) if m.hcrOn: # generate the global pointer with the real name q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 13eff35be..a8210508c 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -217,7 +217,7 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind = case t.kind of tyVar: result = mutableView - of tyLent, tyVarargs, tyOpenArray: + of tyLent, tyOpenArray: result = immutableView of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned, tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index ad5023aeb..6f81c6a9c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1807,7 +1807,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = result.add getNullValue(t[i], info, conf) of tySet: result = newNodeIT(nkCurly, info, t) - of tySequence: + of tySequence, tyOpenArray: result = newNodeIT(nkBracket, info, t) else: globalError(conf, info, "cannot create null element for: " & $t.kind) diff --git a/tests/views/tconst_views.nim b/tests/views/tconst_views.nim new file mode 100644 index 000000000..d7f1fc481 --- /dev/null +++ b/tests/views/tconst_views.nim @@ -0,0 +1,26 @@ +discard """ + cmd: "nim c --experimental:views $file" + output: '''(data: [1, 2, 3], other: 4) +[1, 20, 3]''' +""" + +type + Foo = object + data: openArray[int] + other: int + +const + c = Foo(data: [1, 2, 3], other: 4) + + c2 = Foo(data: [1, 20, 3], other: 4) + +proc `$`(x: openArray[int]): string = + result = "[" + for i in x: + if result.len > 1: result.add ", " + result.add $i + result.add "]" + +echo c +echo c2.data + From e9d7e21dbef65bb8bab88b7cd326e15a2d407fca Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 6 Oct 2020 06:10:47 +0200 Subject: [PATCH 1207/4254] minor reformating --- compiler/main.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/main.nim b/compiler/main.nim index 774dd7625..ab074aa1f 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -249,7 +249,7 @@ proc mainCommand*(graph: ModuleGraph) = # so by default should not end up in $PWD nor in $projectPath. conf.outDir = block: var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) - else: conf.projectPath + else: conf.projectPath doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee if docLikeCmd2: ret = ret / htmldocsDir ret From 37758826ff64fb93324675d81ef724e04c474b39 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 6 Oct 2020 06:33:43 +0200 Subject: [PATCH 1208/4254] typo --- lib/pure/osproc.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 2d48597dc..a7c6c3754 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -80,7 +80,7 @@ proc execProcess*(command: string, workingDir: string = "", ## A convenience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. ## - ## **WARNING:** This function uses `poEvalCommand` by default for backward + ## **WARNING:** This function uses `poEvalCommand` by default for backwards ## compatibility. ## Make sure to pass options explicitly. ## From aca1fae55a8009627888944afeb69f0a0141c160 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 6 Oct 2020 01:52:49 -0300 Subject: [PATCH 1209/4254] GitHub Actions Skip CI (#15289) --- .github/workflows/ci_docs.yml | 2 ++ .github/workflows/ci_packages.yml | 2 ++ .github/workflows/ci_ssl.yml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index d3d0ba612..6b21475f6 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -28,6 +28,8 @@ on: jobs: build: + if: | + !contains(format('{0} {1} {2}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 8a1a8a81f..a59bcee9d 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -3,6 +3,8 @@ on: [push, pull_request] jobs: build: + if: | + !contains(format('{0} {1} {2}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: diff --git a/.github/workflows/ci_ssl.yml b/.github/workflows/ci_ssl.yml index fe5faded6..070e4aa1e 100644 --- a/.github/workflows/ci_ssl.yml +++ b/.github/workflows/ci_ssl.yml @@ -12,6 +12,8 @@ on: jobs: build: + if: | + !contains(format('{0} {1} {2}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: From acd71dd6bb745eb08f81ab489d635951f8edfcfa Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Tue, 6 Oct 2020 04:29:45 -0400 Subject: [PATCH 1210/4254] Iterate over smaller set when computing intersection (#15497) Closes #15496 --- lib/pure/collections/sets.nim | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 67e407576..98dedc5ff 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -422,8 +422,15 @@ proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] = assert c == toHashSet(["b"]) result = initHashSet[A](max(min(s1.data.len, s2.data.len), 2)) - for item in s1: - if item in s2: incl(result, item) + + # iterate over the elements of the smaller set + if s1.data.len < s2.data.len: + for item in s1: + if item in s2: incl(result, item) + else: + for item in s2: + if item in s1: incl(result, item) + proc difference*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the difference of the sets `s1` and `s2`. From 92163fa3304e5b6768a50d36a5243639ce4a2f69 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 6 Oct 2020 16:47:15 +0200 Subject: [PATCH 1211/4254] implements https://github.com/nim-lang/RFCs/issues/258 (#15503) * implements https://github.com/nim-lang/RFCs/issues/258 * don't be too strict with custom pragma blocks * cast pragmas: documentation * added most missing inference query procs to effecttraits.nim --- changelog.md | 5 +- compiler/condsyms.nim | 2 + compiler/parser.nim | 25 ++++--- compiler/pragmas.nim | 9 +++ compiler/renderer.nim | 7 +- compiler/sempass2.nim | 108 +++++++++++++++++++++++------- compiler/semstmts.nim | 2 +- compiler/transf.nim | 1 + compiler/trees.nim | 14 +++- compiler/varpartitions.nim | 5 +- compiler/vmops.nim | 20 +++++- doc/grammar.txt | 22 +++--- doc/manual.rst | 8 +-- lib/std/effecttraits.nim | 43 ++++++++++-- tests/effects/tcast_as_pragma.nim | 18 +++++ tests/macros/tgetraiseslist.nim | 11 ++- 16 files changed, 232 insertions(+), 68 deletions(-) create mode 100644 tests/effects/tcast_as_pragma.nim diff --git a/changelog.md b/changelog.md index e905dd941..3144c7cf5 100644 --- a/changelog.md +++ b/changelog.md @@ -304,10 +304,13 @@ proc mydiv(a, b): int {.raises: [].} = - `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via `--deepcopy:on`. -- Added a `std/effecttraits` module for introspection of the inferred `.raise` effects. +- Added a `std/effecttraits` module for introspection of the inferred effects. We hope this enables `async` macros that are precise about the possible exceptions that can be raised. - Added `critbits.toCritBitTree`, similar to `tables.toTable`, creates a new `CritBitTree` with given arguments. +- The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be + written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new + preferred way of writing these, emphasizing their unsafe nature. ## Compiler changes diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 7dc1d183e..9771a48d3 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -121,3 +121,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasLentIterators") defineSymbol("nimHasDeclaredMagic") defineSymbol("nimHasStacktracesModule") + defineSymbol("nimHasEffectTraitsModule") + defineSymbol("nimHasCastPragmaBlocks") diff --git a/compiler/parser.nim b/compiler/parser.nim index 1ec708057..e3cf54b38 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -485,17 +485,24 @@ proc setOrTableConstr(p: var Parser): PNode = eat(p, tkCurlyRi) # skip '}' proc parseCast(p: var Parser): PNode = - #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' + #| castExpr = 'cast' ('[' optInd typeDesc optPar ']' '(' optInd expr optPar ')') / + # ('(' optInd exprColonEqExpr optPar ')') result = newNodeP(nkCast, p) getTok(p) - eat(p, tkBracketLe) - optInd(p, result) - result.add(parseTypeDesc(p)) - optPar(p) - eat(p, tkBracketRi) - eat(p, tkParLe) - optInd(p, result) - result.add(parseExpr(p)) + if p.tok.tokType == tkBracketLe: + getTok(p) + optInd(p, result) + result.add(parseTypeDesc(p)) + optPar(p) + eat(p, tkBracketRi) + eat(p, tkParLe) + optInd(p, result) + result.add(parseExpr(p)) + else: + result.add p.emptyNode + eat(p, tkParLe) + optInd(p, result) + result.add(exprColonEqExpr(p)) optPar(p) eat(p, tkParRi) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 67e574d52..fe8cd3cfe 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -771,6 +771,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if key.kind == nkBracketExpr: processNote(c, it) return + elif key.kind == nkCast: + if comesFromPush: + localError(c.config, n.info, "a 'cast' pragma cannot be pushed") + elif not isStatement: + localError(c.config, n.info, "'cast' pragma only allowed in a statement context") + case whichPragma(key[1]) + of wRaises, wTags: pragmaRaisesOrTags(c, key[1]) + else: discard + return elif key.kind notin nkIdentKinds: n[i] = semCustomPragma(c, it) return diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 88b9adf27..08012bb55 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1057,9 +1057,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkSymbol, "(wrong conv)") of nkCast: put(g, tkCast, "cast") - put(g, tkBracketLe, "[") - gsub(g, n, 0) - put(g, tkBracketRi, "]") + if n.len > 0 and n[0].kind != nkEmpty: + put(g, tkBracketLe, "[") + gsub(g, n, 0) + put(g, tkBracketRi, "]") put(g, tkParLe, "(") gsub(g, n, 1) put(g, tkParRi, ")") diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index cda156224..19223b88f 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -325,7 +325,7 @@ proc createTag(g: ModuleGraph; n: PNode): PNode = result.typ = g.sysTypeFromName(n.info, "RootEffect") if not n.isNil: result.info = n.info -proc addEffect(a: PEffects, e, comesFrom: PNode) = +proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) = assert e.kind != nkRaiseStmt var aa = a.exc for i in a.bottom.. 0: n[0] else: n - if key.kind == nkIdent: result = whichKeyword(key.ident) + case key.kind + of nkIdent: result = whichKeyword(key.ident) + of nkSym: result = whichKeyword(key.sym.name) + of nkCast: result = wCast + of nkClosedSymChoice, nkOpenSymChoice: + result = whichPragma(key[0]) + else: result = wInvalid + +proc isNoSideEffectPragma*(n: PNode): bool = + var k = whichPragma(n) + if k == wCast: + k = whichPragma(n[1]) + result = k == wNoSideEffect proc findPragma*(n: PNode, which: TSpecialWord): PNode = if n.kind == nkPragma: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index e59c5cb75..a172a906e 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -29,8 +29,7 @@ ## for a high-level description of how borrow checking works. import ast, types, lineinfos, options, msgs, renderer, typeallowed -from trees import getMagic, whichPragma, stupidStmtListExpr -from wordrecg import wNoSideEffect +from trees import getMagic, isNoSideEffectPragma, stupidStmtListExpr from isolation_check import canAlias type @@ -713,7 +712,7 @@ proc traverse(c: var Partitions; n: PNode) = let pragmaList = n[0] var enforceNoSideEffects = 0 for i in 0..= effectListLen and - fn.typ.n[0][exceptionEffects] != nil: + fn.typ.n[0][effectIndex] != nil: var list = newNodeI(nkBracket, fn.info) - for e in fn.typ.n[0][exceptionEffects]: + for e in fn.typ.n[0][effectIndex]: list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info) setResult(a, list) + + registerCallback c, "stdlib.effecttraits.getRaisesListImpl", proc (a: VmArgs) = + getEffectList(c, a, exceptionEffects) + registerCallback c, "stdlib.effecttraits.getTagsListImpl", proc (a: VmArgs) = + getEffectList(c, a, tagEffects) + + registerCallback c, "stdlib.effecttraits.isGcSafeImpl", proc (a: VmArgs) = + let fn = getNode(a, 0) + setResult(a, fn.typ != nil and tfGcSafe in fn.typ.flags) + + registerCallback c, "stdlib.effecttraits.hasNoSideEffectsImpl", proc (a: VmArgs) = + let fn = getNode(a, 0) + setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or + (fn.kind == nkSym and fn.sym.kind == skFunc)) diff --git a/doc/grammar.txt b/doc/grammar.txt index 9d952d372..f5e619ebc 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -6,7 +6,7 @@ colon = ':' COMMENT? colcom = ':' COMMENT? operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | 'or' | 'xor' | 'and' - | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' | 'from' | + | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' | 'from' | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' prefixOperator = operator optInd = COMMENT? IND? @@ -31,15 +31,15 @@ dotExpr = expr '.' optInd (symbol | '[:' exprList ']') explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? qualifiedIdent = symbol ('.' optInd symbol)? setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' -castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' +castExpr = 'cast' ('[' optInd typeDesc optPar ']' '(' optInd expr optPar ')') / parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' | 'when' | 'var' | 'mixin' par = '(' optInd - ( &parKeyw complexOrSimpleStmt ^+ ';' - | ';' complexOrSimpleStmt ^+ ';' + ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';' + | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';' | pragmaStmt - | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? ) + | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? ) | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) optPar ')' literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT @@ -59,11 +59,6 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' | '[' optInd exprColonEqExprList optPar ']' | '{' optInd exprColonEqExprList optPar '}' | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax -condExpr = expr colcom expr optInd - ('elif' expr colcom expr optInd)* - 'else' colcom expr -ifExpr = 'if' condExpr -whenExpr = 'when' condExpr pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}') identVis = symbol OPR? # postfix position identVisDot = symbol '.' optInd symbol OPR? @@ -130,6 +125,11 @@ condStmt = expr colcom stmt COMMENT? (IND{=} 'else' colcom stmt)? ifStmt = 'if' condStmt whenStmt = 'when' condStmt +condExpr = expr colcom expr optInd + ('elif' expr colcom expr optInd)* + 'else' colcom expr +ifExpr = 'if' condExpr +whenExpr = 'when' condExpr whileStmt = 'while' expr colcom stmt ofBranch = 'of' exprList colcom stmt ofBranches = ofBranch (IND{=} ofBranch)* @@ -193,8 +193,8 @@ complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt | tryStmt | forStmt | blockStmt | staticStmt | deferStmt | asmStmt | 'proc' routine - | 'func' routine | 'method' routine + | 'func' routine | 'iterator' routine | 'macro' routine | 'template' routine diff --git a/doc/manual.rst b/doc/manual.rst index 11ea6b99c..494a009cb 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6031,12 +6031,12 @@ so that it can be used for debugging routines marked as ``noSideEffect``. To override the compiler's side effect analysis a ``{.noSideEffect.}`` -pragma block can be used: +``cast`` pragma block can be used: .. code-block:: nim func f() = - {.noSideEffect.}: + {.cast(noSideEffect).}: echo "test" @@ -7501,7 +7501,7 @@ To disable the GC-safety checking the ``--threadAnalysis:off`` command line switch can be used. This is a temporary workaround to ease the porting effort from old code to the new threading model. -To override the compiler's gcsafety analysis a ``{.gcsafe.}`` pragma block can +To override the compiler's gcsafety analysis a ``{.cast(gcsafe).}`` pragma block can be used: .. code-block:: nim @@ -7511,7 +7511,7 @@ be used: perThread {.threadvar.}: string proc setPerThread() = - {.gcsafe.}: + {.cast(gcsafe).}: deepCopy(perThread, someGlobal) diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim index a5d799786..0f0a24492 100644 --- a/lib/std/effecttraits.nim +++ b/lib/std/effecttraits.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2018 Nim contributors +# (c) Copyright 2020 Nim contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -9,11 +9,46 @@ ## This module provides access to the inferred .raises effects ## for Nim's macro system. +## **Since**: Version 1.4. +## +## One can test for the existance of this standard module +## via ``defined(nimHasEffectTraitsModule)``. import macros proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" +proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" +proc isGcSafeImpl(n: NimNode): bool = discard "see compiler/vmops.nim" +proc hasNoSideEffectsImpl(n: NimNode): bool = discard "see compiler/vmops.nim" -proc getRaisesList*(call: NimNode): NimNode = - expectKind call, nnkCallKinds - result = getRaisesListImpl(call[0]) +proc getRaisesList*(fn: NimNode): NimNode = + ## Extracts the ``.raises`` list of the func/proc/etc ``fn``. + ## ``fn`` has to be a resolved symbol of kind ``nnkSym``. This + ## implies that the macro that calls this proc should accept ``typed`` + ## arguments and not ``untyped`` arguments. + expectKind fn, nnkSym + result = getRaisesListImpl(fn) + +proc getTagsList*(fn: NimNode): NimNode = + ## Extracts the ``.tags`` list of the func/proc/etc ``fn``. + ## ``fn`` has to be a resolved symbol of kind ``nnkSym``. This + ## implies that the macro that calls this proc should accept ``typed`` + ## arguments and not ``untyped`` arguments. + expectKind fn, nnkSym + result = getTagsListImpl(fn) + +proc isGcSafe*(fn: NimNode): bool = + ## Return true if the func/proc/etc ``fn`` is `gcsafe`. + ## ``fn`` has to be a resolved symbol of kind ``nnkSym``. This + ## implies that the macro that calls this proc should accept ``typed`` + ## arguments and not ``untyped`` arguments. + expectKind fn, nnkSym + result = isGcSafeImpl(fn) + +proc hasNoSideEffects*(fn: NimNode): bool = + ## Return true if the func/proc/etc ``fn`` has `noSideEffect`. + ## ``fn`` has to be a resolved symbol of kind ``nnkSym``. This + ## implies that the macro that calls this proc should accept ``typed`` + ## arguments and not ``untyped`` arguments. + expectKind fn, nnkSym + result = hasNoSideEffectsImpl(fn) diff --git a/tests/effects/tcast_as_pragma.nim b/tests/effects/tcast_as_pragma.nim new file mode 100644 index 000000000..1de61333e --- /dev/null +++ b/tests/effects/tcast_as_pragma.nim @@ -0,0 +1,18 @@ +discard """ + cmd: "nim c $file" + action: "compile" +""" + +proc taggy() {.tags: RootEffect.} = discard + +proc m {.raises: [], tags: [].} = + {.cast(noSideEffect).}: + echo "hi" + + {.cast(raises: []).}: + raise newException(ValueError, "bah") + + {.cast(tags: []).}: + taggy() + +m() diff --git a/tests/macros/tgetraiseslist.nim b/tests/macros/tgetraiseslist.nim index de7ba06c8..79694a66f 100644 --- a/tests/macros/tgetraiseslist.nim +++ b/tests/macros/tgetraiseslist.nim @@ -1,5 +1,7 @@ discard """ - nimout: '''##[ValueError, Gen[string]]##''' + nimout: '''##[ValueError, Gen[string]]## +%%[RootEffect]%% +true true''' """ import macros @@ -10,13 +12,18 @@ type x: T macro m(call: typed): untyped = - echo "##", repr getRaisesList(call), "##" + echo "##", repr getRaisesList(call[0]), "##" + echo "%%", repr getTagsList(call[0]), "%%" + echo isGcSafe(call[0]), " ", hasNoSideEffects(call[0]) result = call +proc gutenTag() {.tags: RootEffect.} = discard + proc r(inp: int) = if inp == 0: raise newException(ValueError, "bah") elif inp == 1: raise newException(Gen[string], "bahB") + gutenTag() m r(2) From 9560e49e8fa412839743aa86400bd73e2c57ab3d Mon Sep 17 00:00:00 2001 From: IDF Date: Tue, 6 Oct 2020 17:49:30 +0300 Subject: [PATCH 1212/4254] New hint for unused exceptions in .raises (#15492) * New hint for unused exceptions in .raises * Fix effects test * Further adapt teffects1.nim --- compiler/lineinfos.nim | 4 +++- compiler/sempass2.nim | 8 +++++--- tests/effects/teffects1.nim | 7 ++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index c9821ac9f..db0569fda 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -58,6 +58,7 @@ type warnUser, hintSuccess, hintSuccessX, hintCC, hintLineTooLong, hintXDeclaredButNotUsed, + hintXCannotRaiseY, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, @@ -131,6 +132,7 @@ const hintCC: "CC: $1", hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", + hintXCannotRaiseY: "$1", hintConvToBaseNotNeeded: "conversion to base object is not needed", hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", hintExprAlwaysX: "expression evaluates always to '$1'", @@ -179,7 +181,7 @@ const HintsToStr* = [ "Success", "SuccessX", "CC", "LineTooLong", - "XDeclaredButNotUsed", + "XDeclaredButNotUsed", "XCannotRaiseY", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency", diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 19223b88f..4eac6ef13 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1140,7 +1140,8 @@ proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool = return safeInheritanceDiff(g.excType(real), spec.typ) <= 0 proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool; - effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) = + effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}; + hintsArg: PNode = nil) = # check that any real exception is listed in 'spec'; mark those as used; # report any unused exception var used = initIntSet() @@ -1158,7 +1159,8 @@ proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool if hints: for s in 0.. but expected 'MyProcType = proc (x: int): string{.closure.}' +.raise effects differ''' """ type @@ -12,7 +17,7 @@ type proc forw: int {. .} proc lier(): int {.raises: [IO2Error].} = - #[tt.Hint ^ 'IO2Error' is declared but not used [XDeclaredButNotUsed] ]# + #[tt.Hint ^ 'lier' cannot raise 'IO2Error' [XCannotRaiseY] ]# writeLine stdout, "arg" #[tt.Error ^ can raise an unlisted exception: ref IOError ]# From 695f955f70bfcbad12e64592583daf28e781c047 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 6 Oct 2020 11:52:12 -0300 Subject: [PATCH 1213/4254] inline tiny proc (#15498) --- lib/pure/httpclient.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 533bf3c15..0cf19f031 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -232,7 +232,7 @@ proc code*(response: Response | AsyncResponse): HttpCode ## corresponding ``HttpCode``. return response.status[0 .. 2].parseInt.HttpCode -proc contentType*(response: Response | AsyncResponse): string = +proc contentType*(response: Response | AsyncResponse): string {.inline.} = ## Retrieves the specified response's content type. ## ## This is effectively the value of the "Content-Type" header. @@ -329,7 +329,7 @@ proc newProxy*(url: string, auth = ""): Proxy = ## Constructs a new ``TProxy`` object. result = Proxy(url: parseUri(url), auth: auth) -proc newMultipartData*: MultipartData = +proc newMultipartData*: MultipartData {.inline.} = ## Constructs a new ``MultipartData`` object. MultipartData() @@ -415,7 +415,7 @@ proc addFiles*(p: MultipartData, xs: openArray[tuple[name, file: string]], p.add(name, content, fName & ext, contentType, useStream = useStream) result = p -proc `[]=`*(p: MultipartData, name, content: string) = +proc `[]=`*(p: MultipartData, name, content: string) {.inline.} = ## Add a multipart entry to the multipart data ``p``. The value is added ## without a filename and without a content type. ## @@ -424,7 +424,7 @@ proc `[]=`*(p: MultipartData, name, content: string) = p.add(name, content) proc `[]=`*(p: MultipartData, name: string, - file: tuple[name, contentType, content: string]) = + file: tuple[name, contentType, content: string]) {.inline.} = ## Add a file to the multipart data ``p``, specifying filename, contentType ## and content manually. ## @@ -635,7 +635,7 @@ proc close*(client: HttpClient | AsyncHttpClient) = client.socket.close() client.connected = false -proc getSocket*(client: HttpClient): Socket = +proc getSocket*(client: HttpClient): Socket {.inline.} = ## Get network socket, useful if you want to find out more details about the connection ## ## this example shows info about local and remote endpoints @@ -647,7 +647,7 @@ proc getSocket*(client: HttpClient): Socket = ## return client.socket -proc getSocket*(client: AsyncHttpClient): AsyncSocket = +proc getSocket*(client: AsyncHttpClient): AsyncSocket {.inline.} = return client.socket proc reportProgress(client: HttpClient | AsyncHttpClient, From fa841214212cba21ebbf9a0a18a9ce367fab15d2 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Wed, 7 Oct 2020 00:05:31 +0800 Subject: [PATCH 1214/4254] effects: exclude swap() from "indirect calls" assumption (#15504) swap() will never call any procs passed to it, and so it can be safely excluded from the "assume indirect calls are taken" effects tracking rule. --- compiler/sempass2.nim | 2 +- tests/effects/teffects10.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/effects/teffects10.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 4eac6ef13..f0d6c6c7a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -552,7 +552,7 @@ proc isNoEffectList(n: PNode): bool {.inline.} = n.len == 0 or (n[tagEffects] == nil and n[exceptionEffects] == nil) proc isTrival(caller: PNode): bool {.inline.} = - result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved} + result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved, mSwap} proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) = let a = skipConvAndClosure(n) diff --git a/tests/effects/teffects10.nim b/tests/effects/teffects10.nim new file mode 100644 index 000000000..8193b394a --- /dev/null +++ b/tests/effects/teffects10.nim @@ -0,0 +1,12 @@ +discard """ +action: compile +""" + +# https://github.com/nim-lang/Nim/issues/15495 + +proc f() {.raises: [].} = + var a: proc () + var b: proc () + swap(a, b) + +f() From dd862285483b402424607d5a1365d99cbd8566c7 Mon Sep 17 00:00:00 2001 From: Serban Constantin Date: Tue, 6 Oct 2020 19:05:57 +0300 Subject: [PATCH 1215/4254] update unittest docs with correct exit code info (#15502) --- lib/pure/unittest.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 98be959e3..31eaa657b 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -22,8 +22,8 @@ ## parent test as failed. Setup and teardown are inherited. Setup can be ## overridden locally. ## -## Compiled test files return the number of failed test as exit code, while -## ``nim c -r `` exits with 0 or 1 +## Compiled test files as well as ``nim c -r `` +## exit with 0 for success (no failed tests) or 1 for failure. ## ## Running a single test ## ===================== From 51e3e0c7c43e82932d9bbae2e6ccc876d29b9fab Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Oct 2020 00:09:28 +0200 Subject: [PATCH 1216/4254] implements https://github.com/nim-lang/RFCs/issues/260 (#15505) * implements https://github.com/nim-lang/RFCs/issues/260 * added a test case --- compiler/extccomp.nim | 4 ++++ compiler/options.nim | 1 + compiler/pragmas.nim | 30 ++++++++++++++++++++---------- compiler/rodimpl.nim | 5 +++-- doc/manual.rst | 8 ++++++++ tests/pragmas/cfunction.c | 4 ++++ tests/pragmas/tcompile_pragma.nim | 9 +++++++++ 7 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 tests/pragmas/cfunction.c create mode 100644 tests/pragmas/tcompile_pragma.nim diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 79b4ba637..11b001f9d 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -554,6 +554,10 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, ospNeedsPIC in platform.OS[conf.target.targetOS].props: options.add(' ' & CC[c].pic) + if cfile.customArgs != "": + options.add ' ' + options.add cfile.customArgs + var compilePattern: string # compute include paths: var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath) diff --git a/compiler/options.nim b/compiler/options.nim index 40d86a01d..6054eb3a5 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -198,6 +198,7 @@ type nimname*: string cname*, obj*: AbsoluteFile flags*: set[CfileFlag] + customArgs*: string CfileList* = seq[Cfile] Suggest* = ref object diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index fe8cd3cfe..4d5240e3c 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -93,11 +93,10 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode = proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords; isStatement: bool = false) -proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") = +proc recordPragma(c: PContext; n: PNode; args: varargs[string]) = var recorded = newNodeI(nkCommentStmt, n.info) - recorded.add newStrNode(key, n.info) - recorded.add newStrNode(val, n.info) - if val2.len > 0: recorded.add newStrNode(val2, n.info) + for i in 0..args.high: + recorded.add newStrNode(args[i], n.info) c.graph.recordStmt(c.graph, c.module, recorded) const @@ -491,11 +490,12 @@ proc relativeFile(c: PContext; n: PNode; ext=""): AbsoluteFile = if result.isEmpty: result = AbsoluteFile s proc processCompile(c: PContext, n: PNode) = - proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile) = + proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile; customArgs: string) = var cf = Cfile(nimname: splitFile(src).name, - cname: src, obj: dest, flags: {CfileFlag.External}) + cname: src, obj: dest, flags: {CfileFlag.External}, + customArgs: customArgs) extccomp.addExternalFileToCompile(c.config, cf) - recordPragma(c, it, "compile", src.string, dest.string) + recordPragma(c, it, "compile", src.string, dest.string, customArgs) proc getStrLit(c: PContext, n: PNode; i: int): string = n[i] = c.semConstExpr(c, n[i]) @@ -513,9 +513,19 @@ proc processCompile(c: PContext, n: PNode) = var found = parentDir(toFullPath(c.config, n.info)) / s for f in os.walkFiles(found): let obj = completeCfilePath(c.config, AbsoluteFile(dest % extractFilename(f))) - docompile(c, it, AbsoluteFile f, obj) + docompile(c, it, AbsoluteFile f, obj, "") else: - let s = expectStrLit(c, n) + var s = "" + var customArgs = "" + if n.kind in nkCallKinds: + s = getStrLit(c, n, 1) + if n.len <= 3: + customArgs = getStrLit(c, n, 2) + else: + localError(c.config, n.info, "'.compile' pragma takes up 2 arguments") + else: + s = expectStrLit(c, n) + var found = AbsoluteFile(parentDir(toFullPath(c.config, n.info)) / s) if not fileExists(found): if isAbsolute(s): found = AbsoluteFile s @@ -523,7 +533,7 @@ proc processCompile(c: PContext, n: PNode) = found = findFile(c.config, s) if found.isEmpty: found = AbsoluteFile s let obj = toObjFile(c.config, completeCfilePath(c.config, found, false)) - docompile(c, it, found, obj) + docompile(c, it, found, obj, customArgs) proc processLink(c: PContext, n: PNode) = let found = relativeFile(c, n, CC[c.config.cCompiler].objExt) diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim index 52b4d1f85..e50ab66de 100644 --- a/compiler/rodimpl.nim +++ b/compiler/rodimpl.nim @@ -838,11 +838,12 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) = of "warning": message(g.config, n.info, warnUser, n[1].strVal) of "error": localError(g.config, n.info, errUser, n[1].strVal) of "compile": - internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit + internalAssert g.config, n.len == 4 and n[2].kind == nkStrLit let cname = AbsoluteFile n[1].strVal var cf = Cfile(nimname: splitFile(cname).name, cname: cname, obj: AbsoluteFile n[2].strVal, - flags: {CfileFlag.External}) + flags: {CfileFlag.External}, + customArgs: n[3].strVal) extccomp.addExternalFileToCompile(g.config, cf) of "link": extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal) diff --git a/doc/manual.rst b/doc/manual.rst index 494a009cb..7258e7775 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6622,6 +6622,14 @@ with the project: has changed. One can use the ``-f`` command line option to force recompilation of the file. +Since 1.4 the `compile` pragma is also available with this syntax: + +.. code-block:: Nim + {.compile("myfile.cpp", "--custom flags here").} + +As can be seen in the example, this new variant allows for custom flags +that are passed to the C compiler when the file is recompiled. + Link pragma ----------- diff --git a/tests/pragmas/cfunction.c b/tests/pragmas/cfunction.c new file mode 100644 index 000000000..bf49d6a29 --- /dev/null +++ b/tests/pragmas/cfunction.c @@ -0,0 +1,4 @@ + +int cfunction(void) { + return NUMBER_HERE; +} diff --git a/tests/pragmas/tcompile_pragma.nim b/tests/pragmas/tcompile_pragma.nim new file mode 100644 index 000000000..4e09a7501 --- /dev/null +++ b/tests/pragmas/tcompile_pragma.nim @@ -0,0 +1,9 @@ +discard """ + output: '''34''' +""" + +{.compile("cfunction.c", "-DNUMBER_HERE=34").} + +proc cfunction(): cint {.importc.} + +echo cfunction() From acbe27b082c202895df1b78a82951389b4a232a0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Oct 2020 13:05:19 +0200 Subject: [PATCH 1217/4254] disable 'observable stores' warning message for 1.4 (#15507) --- compiler/lineinfos.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index db0569fda..a0b1d1965 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -214,7 +214,7 @@ type TNoteKinds* = set[TNoteKind] proc computeNotesVerbosity(): array[0..3, TNoteKinds] = - result[3] = {low(TNoteKind)..high(TNoteKind)} - {} + result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores} result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, From 0426a4d85ab8f9558dee35c657aad0d299748c15 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Oct 2020 14:38:25 +0200 Subject: [PATCH 1218/4254] fixes #15508 (#15509) --- compiler/varpartitions.nim | 19 +++++++++++------ tests/effects/tfuncs_cannot_mutate_simple.nim | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 tests/effects/tfuncs_cannot_mutate_simple.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index a172a906e..f831d33cc 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -48,7 +48,8 @@ proc dec(x: var AbstractTime; diff = 1) {.borrow.} type SubgraphFlag = enum isMutated, # graph might be mutated - connectsConstParam, # graph is connected to a non-var parameter. + isMutatedDirectly, # graph is mutated directly by a non-var parameter. + connectsConstParam # graph is connected to a non-var parameter. VarFlag = enum ownsData, @@ -99,12 +100,12 @@ type config: ConfigRef proc mutationAfterConnection(g: MutationInfo): bool {.inline.} = - #echo g.maxMutation, " ", g.minConnection, " ", g.param + #echo g.maxMutation.int, " ", g.minConnection.int, " ", g.param g.maxMutation > g.minConnection proc `$`*(config: ConfigRef; g: MutationInfo): string = result = "" - if g.flags == {isMutated, connectsConstParam}: + if g.flags * {isMutated, connectsConstParam} == {isMutated, connectsConstParam}: result.add "\nan object reachable from '" result.add g.param.name.s result.add "' is potentially mutated" @@ -119,7 +120,8 @@ proc `$`*(config: ConfigRef; g: MutationInfo): string = proc hasSideEffect*(c: var Partitions; info: var MutationInfo): bool = for g in mitems c.graphs: - if g.flags == {isMutated, connectsConstParam} and mutationAfterConnection(g): + if g.flags * {isMutated, connectsConstParam} == {isMutated, connectsConstParam} and + (mutationAfterConnection(g) or isMutatedDirectly in g.flags): info = g return true return false @@ -173,11 +175,16 @@ proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = let id = variableId(v, s) if id >= 0: let r = root(v, id) + let flags = if s.kind == skParam and isConstParam(s): + {isMutated, isMutatedDirectly} + else: + {isMutated} + case v.s[r].con.kind of isEmptyRoot: v.s[r].con = Connection(kind: isRootOf, graphIndex: v.graphs.len) v.graphs.add MutationInfo(param: if isConstParam(s): s else: nil, mutatedHere: info, - connectedVia: unknownLineInfo, flags: {isMutated}, + connectedVia: unknownLineInfo, flags: flags, maxMutation: v.abstractTime, minConnection: MaxTime, mutations: @[v.abstractTime]) of isRootOf: @@ -187,7 +194,7 @@ proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = if v.abstractTime > g.maxMutation: g.mutatedHere = info g.maxMutation = v.abstractTime - g.flags.incl isMutated + g.flags.incl flags g.mutations.add v.abstractTime else: assert false, "cannot happen" diff --git a/tests/effects/tfuncs_cannot_mutate_simple.nim b/tests/effects/tfuncs_cannot_mutate_simple.nim new file mode 100644 index 000000000..9de20d1ec --- /dev/null +++ b/tests/effects/tfuncs_cannot_mutate_simple.nim @@ -0,0 +1,21 @@ +discard """ + errormsg: "'edit' can have side effects" + nimout: '''an object reachable from 'x' is potentially mutated +tfuncs_cannot_mutate_simple.nim(17, 4) the mutation is here''' + line: 16 +""" + +{.experimental: "strictFuncs".} + +# bug #15508 + +type + MyType = ref object + data: string + +func edit(x: MyType) = + x.data = "hello" + +let x = MyType() +x.edit() +echo x.data From 3b901d1e361f49d48fb64d115e42c04a4a37100c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Oct 2020 14:39:13 +0200 Subject: [PATCH 1219/4254] docgen: improve alignment of comments (still not perfect) (#15506) * docgen: improve alignment of comments (still not perfect) * fix error message text in `tunknown_named_parameter` Co-authored-by: narimiran --- compiler/renderer.nim | 2 +- nimdoc/testproject/expected/testproject.html | 11 ++++++----- tests/errmsgs/tunknown_named_parameter.nim | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 08012bb55..1de56a296 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -183,9 +183,9 @@ proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) = addPendingNL(g) if s.len > 0: addTok(g, kind, s, sym) - inc(g.lineLen, s.len) else: g.pendingWhitespace = s.len + inc(g.lineLen, s.len) proc putComment(g: var TSrcGen, s: string) = if s.len == 0: return diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 9c06211c9..a5522a2e2 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -661,16 +661,16 @@ Some proc

      FMe)pXdJNe8EXx`FQ)r(Z;bly2h-c!ph2UBshcq5(?Hts>>>;1S8>K3H2sp{?-rU z`r&CO8)cQUw-(k+sT93d_MD+3M@xG(vwf6>Wv3iDdT4cZxY{Tx4HZr0(lA0ey}@Ob zd4(maKAM|;Bvf4(3F{Wv+L#iG45Nxi6jm1Niq`GoI4@?63ezeIi>3x6)rCc&$>OST zI=#AZa(Sq=j_U@~Xwf2tU#kAKjQa)l^E=?b{I&XD{#my8o`<92XWhr+3Pm^J57iMh zW=)t-P0it&i-RTA;fjIrHc!>@HD+CMi8n^PKlr8oHeO!r=(>OLe7rx6=e^pwQ&QI* zb&$p^*&hZ5Yb#4-Q!NgL>WV^DV%$8Ew3?4#;gg3E6O5~P;r-Fw{G3yB)r<3pl>y1<&7LZa#a4n;K)imNOf%$ zi3BIl3=WA@m!Cc)K~jUXyhb6PH+1*~Bv4)+no?MfHwjl4P6-7Ii;6-uHQj<4*(g>~ z6;Z}5RLwkCSyp~_e9>ge3G~YzJQfABCs&56E64ynE6OShMH5M&-!WQ0jY7X+V}>Gb zPZ)!gGhCfOR7%E=pTa)5xlZxIRl?CG&RZmqsq@z;@*g}d&yoKx&0`#?)7L1{A2U)E za7ugOwDV|${sT^SX(11RGMvI zaQKjkp-M42$d)HsOKpU}U|CJDu)I1{SUfYR_+p)s7f#c+8nepiHg&-;X@pCHlf(3) zny$e}DXE7mBP;+y)goolfOu5JFMj@}ky5J?C+6@FJGj()-xXu=-3*wN(#$s+!5l(2h0Ci znZ*0=fa2k4n!`1;Exi~nZlsRyam5*@QEPTXZ&26$WSmx7c zt)Gg^YN`q&MWts3tt;i27{|P+9j$LQ(!W&i3{Sp{Rk-kK=pZ`0j>klObWu@lRavO` zyii5+*X8BqVYStu7j(_Ed!ao{s-Nxq8O$D>*wry8fG4e!Z_m$?`&x;h~73hszqH zim`g67*u6x#2l=Q!CD5hqa~J}4Ef_KYndkyBaazX`4ACgoJ?^CiN)_&(Ro0OhWWBZ z%PM4AI3`j}pj;VOi*dTPN)(})`iE=CSGU-Tn#uIZio&WYswXd0SY1?Vl*_OZM)$nh zvWS>&3?}+iwH6;;8yQ_9drPzPuc#3HST-L$_oxU}gsW$^Ho`Ts#A7gH4LAAKGhO$T ze@Jb0waB}?T!tHk#l<5+g;lv_n6NrDtu|B>8C@eST4U5!F(`+|REMU^E~IK}Ol?Hi zvD~PsDld!3n7yphkE|4%cA|+6#v~*y>HP3{h3wqaxg-p>3=6A8q-yk@9+L5fv4B)D zdx@4kxNM3H7T2zNE-$Nz&=L%RW2LZ&FoN!A#~vJxM8Xw@tfK7c<)gyI>`zV&%}@#m zy{L#8y8NOZ6Ki3xmMb?(=%=`?XV+&{K`qKeJE7=p2 zUar~gRE=Hi>rCt^8>>!Pv>|=z?);;1dRUz5%qgoWsxA}jq)Ij1HLst_JZnPb3|)hn z9MdsRJ=riG?GZCed;a|YMf@A}|8BWjosNZq6LH0TWoX9e$(I=l#t!M3V8U1PFX`Vg0Gr_39q~&VlVJsu9{BRzw z@z>tJAFH;7^zOYenrVaBUC{T;_@`9T56UWW0rDTw9B9#FL;QnHM7g!~MukU;Sn8+u zTjc&iF&izV!E&03*mo#oQ?fY7+NLmA9GYA^g@s*Nd2x`*SC1aSlG;kfNtP)>u%=75 z;6>qDuDO>}EhbgL89b2*o?bid2~VL|#ENnaA0ldgY-kGJDpZ|cDpr`e3`phY6;@9TRT~qA54l7r zB9?j8Iu=tw5iN*gV!vQIa~d&#oJp49Ahk!{iTD~L{*j5j)I}3A7n{LFjC>J8j<32V z-TDsv&r2O;KT0h|#x@Eqder zKg7%*`G3@^n0YV%f6xEt+!r(N;{U7v_{;zQCV|{w(h>iE!3TS-YYT5r5N2`zr{b{x z50y#uz-G2zdwiBnm`-AhDl5;HTc5huGm0^K4zbsLI#?`H@Feo#V@1srW**@pc~j1w zmmwa{$vgQ}hIu6O_v)HZUSXt`rEI8pl)Mm2PnX_fs>4&N3o97(r*t31Lv-=Kcw}D1 zpx9l?*G9_9^)t%q+R9LFsPbpa*H)GlF%6W()Uw%3K1pSCNr@P8iJyiJL%)7eV?Ml!4tjDzO`uhL(d5NaaX?0U#=}${yj1`Oh z3&i%WobwowaBg@;s5-l*h!1uZRaA|f!UF{s{xew}i-qPW`FMe?j$*OE5!-zI_r%Qa z`15oBNNG&^|6;zu>5e1r_xHa$e*AU6pJL|!#Q!H7s@JhPW3d|>EMKo2pP~s(oYI zK~g2Yr3qDqi%Rp$)HxZKeUjQaLVRUqd1VYM3zZl5P|(x3 zJX{$n7D<$JKt=)_> z&gdE(fCXDey2-T?+vJ(SNVj4-2h$D5d}TGb=Ca~n-0o%jh^s%@ekY6@~1KJ`m(FFV<=a}o&z6Q zT3(|qA7KwU$mXbLoht71lC>+x$f}rAu!Y*WrgK-h+c||jNu8Vx*5iGRKO=oM2`7iD zUFkD73yKHco$JV_^LX*kWbse2_$S=i%32jG{(M0XYl5ORYQj&pRh1V___z})@$>&4 zUhyV(!*z(pELS^7+MXEblf*+s9u&a}ch_ibU;={mm&m#7O@e!rmI zDZeICXr6qN^?bK(29BZm>BW!3xCe1mx!L;Z@sf#w^MqQC?aeH&|G2Inp;?b(WDn%= zO=WRmb@4E@bf+Jcm6WNG(Ut$tZy)YuzkE`n=307fEB6G9im5qeQkq`U3eUo4D&&iSj*H2p;I=N`U_Z|~mHG<}~Zt~)e2KW7`# zZ4}paeEl7mNo$GJh&l+0ZHz&k(tCC~%MpmT_bKI(Gac4wQXi*G@$vy3S!32Ig%wrq z1P;)=#;jAO@kGiMp$T7D6|Qmd@%B6AB)4`=ub1i|jlWL&_#Zr<7u5P|%sNn2U{PU> zU4JKa3bLgmYVss^O)9~Iw7kZw%$liXRXpkoc2|`izy8YSRH0}gLG`Mee9A3P4An-e zY9sPgAy2{Oj8vw4qE25U`W=`l*&zFE;vBV7EB&O*?lRcb)THF`T3(}+S99OfiGP-m zbKUC5E|8N7?lnqzp*qiinrfg4w+;vEv@{C)b{FLr1{U#}@QRilNbrYgd5u|?e;hq7 zf6Tc2iMbb84{&t6c!*Emk{>cUSGv{s{#41Ep>9_l-(L#LXB5tKEfU)43^m&NjT$}C z%EF^keE%9aP|>o$%vx^{WsUGt$aW+V{T?S{;!!Y zvrQfM!lGK)G|w(p>u9!J6R+WoO=vnk?Rh;$$ADEO=c>yeZ1fq)N7eCTRf;|F6vNdiL)5Gw1*61@m9< z{za-l!$-7FtN;x!kVCxiC;f(w6VfTt?8BCrZO}(vwXd&t^rNT z#~PXEgyQ8HoWv;FPSfm-`1!Gxu?rMG|H|X@9qxCITj(@3X2rjd7Qg-#YD_>KtK4n0 zyhip%rKUkkfr~V+v6=SigMIq@*r!`rjmtLi<(Uv?vv}SrM_e@fHvat6IKLO4wM2aS zK|3XN5#PRQsE@cPp4&_HoyKO`uYXr|U7OfX%5&riK^cyOl2?dAA&*XIF-C@_q21Ffk5S=IT z-CQbIgM-FjH-AoRS`Vr0&n!sK>ge(7)KA}p^&@Q0X_`nEuZwk+-Y~4uUt=@NFOGNi zYSKQ$I|5P%X0#j*6l#c`@5#S|zSEeMAig~oc?9)MnisQpBa9~y`sH=F$(q;Lyz=#; z|MhBGKHC?FA>O{x8ERlSXUSL|FCpL8D&4QtzIri!B(=XNfox;Ke4Yw8MBi!5a-yjU_;u{dA*=-U zwdPXECV=tnpEmqy3%H zbpGnJB~>(AtDjpq^gLecs?pUx$S7bSUW5#hz>>C_w!8gA$~fpw^v)rs_+L&8&YhzBZkIql@iyRMFht zTa_w){_T}Xs=CxX{`ncNZCn09zRjoBi%xmtuYQ&Jr`V22;NPlvhlbbjL~G}(74bQ% z`}py}lCesDz82Hiy!z=)|Lom#e2f1!ipWaudsvu-J+%gjVZIL5*i8NCAAOqcf5_f} z<+^l3iwt3zV8--;VzYpunty|XS_gyEgQo_2iPpt+P|Y%W^>#*T>->*K8eR4Kv(rpk%?ayQ}vGCxk_KXkS>%+psIn`s~NPtbm>_P-zN z$OjQ@s`5H|)0JNQe6ggwFmj&D=UJc6)7U)y`%=HXo7zvce`;6dnZavbqj`acPw+;> zYua+ilyQ0`Sa@i=p6o^4{*$B`*V^O9ADy3W-G(t!r?0V@2wpeAKN=NJulTWPTyape~Ht#y~X~P_xVYD|EegQIXNWXsTaE~Vp=9+bn4m3-;5_| zeKj_*UtF3^j1=F#>>PFbieIl->p9CzDf&WVR?oNyH)vjC^V(-W_RstJ^iNm&^p@3b zDKdB{pVlcXt8iQOL}AteT0f2Zv7b+xO{{8Jr|I`2wSCE38TeP}zx~Ag#m7D_U-NVA zBYlio8u>RouiY#=D*OG?Jd@b(P@RuP&;Fu42sq|$a&?dn(U_IT`dNSBOfrR<*Vw%F z*nhPbZGw-^JjhXbMhC3*X6a~GJT=3ndKMHw-T(6I6x9E$%s@` zscxrkt0H_;&>k?`>HIZj)wpDmGz&}pCf_I3@>VAMZ6cTIlr%Q4`~$@Lx~YHH^P0x#nzCIz}|0(RRqo3G+X{w*ho2GC{hEM0fLdCj%G&Zw- zc)pQf|5^Gu(GrzH%DIvanx}xp3ZHWZppI@g3`6!flIf?_{;sa3K;@$;!=Pj<| z{nsc_U*fb;v8uCQ!#;g_@cb>o{!n^lcygHU6JwoDu6#Y)eev@vOUCNEzU5cN7p2cg zHps-MFZCG1CqcuN(g4=pxW;C+k3RDGXw&CIl!dQXlapfsowH+t`1z9~qbzWou279x zymch2Ulm_`V3n^(aB4L;Y0#iaI<6be(>EHMRlc4*@z3&g1o1?VBT-@*URFLSNZR>2 zeT~gZzfVtbKBQ^?u5vvvv_8nTf2Axu*Ig$uB>*X}v$nwvO|6GW7Fb-g!mlYO?seLS|A`NW@(6`wKVh~|tYB@x@o0}H8RR`yJH1>n)D%J;HnmQ^%O2Z2J9jTCEt;y1zy9L0 z^!h}g_;8i@w21x`m;Q4=MvG%p&s=eoVSK|vu&z(k+{SfAzo@w$Jh6Y&+y^cJJMh4C zHP|1_8xS?egE6oUTredKLV@3 z!_VeVm4kKQTJRHa8)$-Gfgff^&2}6J+B_s`_5fStAP;s2tH7n;5-@cr^5C)HHn1N2 z3JecJ{#f({dw_d}BM;s(0(r3aNaVryz_noH9OS|4&P5)4JQw+nhH={{(AVD~)A50-)Zz+1r%3?wnIKiEDW`+=*$Ixue>_5;UWfIN8gg~)>k zj7J_k%dVHkOzMN*Ms*KAP?qVf;@QHrO5LKC+?q!JlJm% z^5EBC9XO{Dd9cG|$gOIr88u70844hmi*d zRUr?SRU^;-!XLo?VA~qx!Fn(Pz8=AT;2&$F<~nfj^r*QVoC)p)?*ZF0bZ-WGgJWk# z&3y3SS;&KTflI;gwaA0l%t0Rfd@l0ff!86=M$4!3kq6&gfIK+kdgQ_7i;xE=EJhw| z1h<3jmmm+0`91PH@C__Q9^4D&gVSz79&EoHdGLVSkOx1#9eME37082A??j#r#iF~B z2UG4t9&7|7V7L2`2lw!2ZP$SVA4DGfa4quSvd54=#W1Eng*=%1H1gmlU<5quPsoGk zJ%>DagXNo$2akLSc`&ygdGOTD$b(OV+rd9>K^{EkW#lvX zTMn-v4`ze;VA)@h2j{u8W;g{ zzC|9KxEFcwb#Ob_>O17Yyzh}e9e?v9^5Ezw^5CkUkOv=rR|9r!4?9o!D?1&!30*}gmJg1x~dftZ;Oz5+(T zSqC5w&Q3!fyyZaT!TZ6lzylA8neBQQ#+PkkW)JYwgJb3xu;`GOSp`mL7c-ZD#-TBD zEjaqHn7IvX0KWo9v`3x|+TVdaz{5Kr4}JhvfyU9ugV%v;!H&lw4<6GId2m<|`Cf+c z4%h>nb0YHKk6;yOc0wL}Ap?0Z+y!~?CGab7H`s>f{!CbKCX)&`LyaHSV zUfMNgt^pgstzeh#F>?=?1Gec+`{aAgUBP)^F4zc`gYWV^=SASMGh*gya8&P@xdr?Y zYyhYAiJ57AC|}>0nE|%$7c)nI?fb{fVsIfi2fSxM%v=RtJTPW%0&hAqX6^#hGGnH} z8RM(KAh>K$%*+Ds0}H^8XT{7};A`LtaO~iixdCiFEN1QmSBylyANDv0dGMTE?}l1UL)aH5z&FKVy*x=jS00ZUJLp>-?D6p+Da}1N(!=jEkA$!P6(i%sTM+OJnA8 zun)Li@DpR^4$uVmfq$BW`~bt~QHVS^Y%=m-8CVDI0+)l|7au*9Hy!!XZgI$**pJ^EX1p9-Nmmv?1y#;wN1}+D0zZH3K=yK%2e}VhJ&u>G1 z5cPfs^57_NJU9!i1K$UigFmf69xUP8y*t2`_aF}jHz0qOVO$9I2d@IhgKs~FJXrA} z^599EkOwb(33>1ta36TW7Ua)n{`6Pm!S#Pb9vrwGd2r*K$b;Q?AP)`)cYq&*`@oTJ zA)jR!r~NBtW`a+>P5T311!sYScE!w@eOH}ZpNmmeb!mVSaf_$D|B{1TiEzSw{~cn{yD+z3ATCGud4 zuaF2^|FZ~vIa5=aOd>=G&(EB^&!4JVKu;54J!4Wa! z!843Tb0zpLxDmXrMWeY3Y|nQ!jiJjBj99a50z*egl?+XCB{Z zE&>lcvC&*3uv4SC6?`=50DE79JUAKba6a;2 zf3V%P$bvx)XVD{9VX{--C5vkGqivXM*d&KkptYcqgNvj-Urr!^BzPV9Q+XSBK#5L!D}8v9!z}_`EiU>Pc@pE;E?r=W&v3GOrtpq zZ2xSdxdQC^0)7J=4(C0mdOXTFR)xE5Rq?f^G}d9NT3R)WTO=0ji*O#LhJ;B(+4u=iHv z!OgEC57xbgJQ&-CJlOZ|$X~>I5e$MagIVBia1uE4b>zYH?Z|@*{)s%e3fu+$1vD%WN_&&G` zjDf~P_9xy$9_$5XfgkKb9vuDw^5A4}C3q#c5nK-L0-pelN$3v-!B4>~u;quygC~Hq z!GYjPungP?&H;CUcY{VD^RC^EW;(bQ%mM!j7K0yybHElKG46pK!A)R4a5p#>Y&jV} z38sT9z#Q;tuo!$DoCAIit^(6OMjku~+zp-uwk$G?i@_Hy9>T~450bd{=Vm<_>gKfV= z9_#`ZgE`ey!312!GD9|!`*>zkOyx9SAlE5P2lt2 zArI~ZTTWp-1k=I8zDFKB9V`Y%fOEhZ;41KDa1(gse~gG z;N3Cg!ABdB2VVgEPX9jzAN6aGvp#IUh7y{A8{Mt5be5w}3NJ ze=-}uf|fs-X_s*iW`H+?Bfy8jQt*TWkO$LSArI!KArFSZ2Jm_?Z7Tj4%m6onBfz)8 zQt*3lK6vPX$b((ME#Ppl0h|t|m1AEp16%`+0MBcUJoq&@A8d0F^5DbZ7H|vL0DcIj zRbU1%16f;`v@ECma}`QR*Y zHF#<}@MQuv}z|Ho&S6D|H|Xo%O;-Dw%xF{9nLxApc!eijkAwA^VBoaI}vIK zS%xU%#9-8-=8`~%?CaFeKwy7KjfsSd6$R3&E^Z> zpNBsZw9B7*XbTZRlzA56Pp3ysT#3VTDY)fufs>nZ9pTo&<-rZ)+D^AtW-INs9lip- zo0~6l_`UE~z%v9m@+p&Sz1yeI2jTtdtvCE3r})=fK71?q-Q;8Im-?P8x6nTV|JTm` z{8IQEyZD!H9sC3Ee&yQ^|1`W``S!xc;Qh+iK9x1{ss82b4L=0luU+QDzXtEuE+g<4 zp61^!m%?v?_iLBy;FoswZ`O`E{;6tADoqo6iegnLpf7}4S4t}Xe{zhBBo$%sW zt6x3G;GcjuJ@P-=@*NLgPQ)|W%^v;*o6m$FFd%Av?%^A3z5xD!fl>27Pd&G^>v(h`;@2 z!T%e+(o_C2r~L5!hepjkv{T1Ep9Dk(qJM6HZ+Wi2pV|pO6aIdWe)rh=#o$eNKR?y+ zK<3WpMa`Wa{ob_o%Y?7zS^ce^^l!G)FMuC3I%;-x`hi z)c%D}*Z}_s{Cao(TnpRmfIDYw)NJF?y_K!|KKQ!hUoB~w|9JQ-;WONPk;B))&xJq5%@;cSa`=Vt3q7`*XWMQ){P!0`&1XIQ zQ#QW?{-%rk`_4Z2l#8S0-|+!X+uC}7&_LL)!$J7QN&aJ8fB5?gsT+@dOKkg&hyQwV z)a>ZtkFxnX_|J=?<}MHaw#_exe>fC1zi`_pt8edxxXulb-a~+UYNce;NKu5C3nQUk|^$Dr#Qov0t5Sza8-3O^cd;@bGup z{66@)nyC4WC;iXu^gA3(|A|D+4?Xhl+VcJ351vl@_V6d!{CM~yW-y2G@Z)U04t{hU z=T|)Zw>G~VzVqc#^KOstyWRGE>*4ReDr!bO`hRchzXSg2*-^8nn=hBNwEsT%o8kZL zslPwj_1B>-`_|V+%~2lxM%w!Ihrg6_Fb{b8&nmnBjEDc^`l$K1JO7l2ZT;%tXD*DI z?=uf`+Q-h8B7$fi%i#wuiJEVCvH(HocDRi z(|_)_`_Fp#c6a*EJ$As~4&T>Pe?9H`+Xuh)uBiF0C;zwX@^xUfUwOCx+^RqP+wgvC zl=1Knt)%~X(!a}2zYf0JJyEmX!#{8H%i*`f`?cTo@E^hZ^}ikPpWhobPw=$wW9;_5 z4}Q<8s5!!8-yybrI~>X$$ZCK4^@l(80spznc=);pIalM!{}4O>I{5N6j9;GeKjoAk zzSYA~^Bxbs!sge*&xik;r+#0t>vsoyzel6yB_4jf&F_PctcCaJH{RB-!(r?vJsvgJ zc=G?FoqvD$K~J!T_N0HAo&I?EMeCA`|L{xUXL!XuL0V(Y&T{tNhvJo@L``gb@S|NFH6_|qT$dw9RSpYiaK^{hQS>Cd*) zuY-S!b9E~``rT^lw;X=lGt6H+@{4Tw_3-u2M$JhceuB;KfIr~5sL5j*$G@grWT(Fm zJ_p{<|8!tu@KyL(9{)JQ_K*GHyS%{M)06)bcK+kxpMNoGp6t$FEp27})xp=p-|3NG zZp$x+AM%p_{A)dY-+Ja3?(}Ck?PCZ0Sa`Y3Y41HwbIK3D8va;M{zuyRcQ}IQIGj_g zai^bBY0LMA{~o@No3C>69}j=fmZ+KQNq@MVejR+jm!swokA2Uw?YkWQ;#Z^QpWNxE zth4i95C1LvIFJ7tWBaci@EL!PnoRSY`XA=#w-5es`0;K&MQy%{{@3A1_Q2o^Jp6@r z{{7*vgHLz!6P@(O!!LyQ+q(_yb+q5IG zeMFu1=bvZZ;@rABeXfP>`EZZG6?w{jshxHN{_B55&5u3&`!>H6{%OwY{^(9SvnH@y=zFZamT+Vb1sKYN$CwMYJ2TYfM6i|_gG>$N|cXD_>==4em)=h*3scMN8{ zA2o0Dq`%ZoKOg=pct779f$#Ala|^e;a!t~HOW}vXFZ1;6C3fFl2mkEHjQwu;lvnKh zx5Hn?8RX;LymI|A{k`y|@YlKdlxuAH_Q!BG3x1iW{7anj!{>Y&HGlHR|6t4K!*}{O zZQtYDI@`W20^f}@(6@Tzoqdy~@b|(0(ZkzDq%eLMU$@BxqhhOPfz_$gnp z_Vui-{%o(U+8@il&-YRDVNd?6?fiSg-wJ<$hgZ&tre);AzY6b}yAUqgZWY`%xUfgo zc_y|5{)GP|-t!UiYvC`0_ZyeC!9NFojwk)0w(eiSe**uZhkw`R#d|0Z?u(k&d-%CF zFWygS|3lQw_V|rV+b@atR{C)MoNOGweSs8L<%jP9-^Eim>2}>Lfgccynlw>IKHrgF z3*QTVhMP}u=8fCn7r?*o;djaeMBRJ^e@qvRto)xmvd);>75;ao z|C~4%zO@na)vX-95Z-UhSpC;#8sy03wM2EKIy-M7H4PVvvX0p5i7%R3Ec z@m*>xVcCV96&6 ze>EsXW`~%0lw1GQ!<_QNpK)x=_ZdVM{3`e?gP%1|xnd_`^MWP;Ko!sGaZ+cZ!)`d&<7YE_)3AcPCSJgP*1Q zSf#tjzvGFV35Ng3&8O^=5d@zJKkyWPz5w2Yf5s#4JfE2be_Ln&wz~rUEBHkHLgc>z z{$t)rImw;=rH=kP;Xj4<>l-onEZ$v7l)k9Dj-6Oz@h(fEcGVy5RJd|?-YHXT+l+^w z4i7lC)%#;Xg6bgZ;BR9e-nM<}($-3Q)jn1b=kwk%a~e_XI4NoqQe-iJ=_@!R}e=Pjvo_R*CJ`Vw-2BOQ``rNFY6R~Hh((^&ep4qLWa+;Xet4e0{xSGl z;QjRP$l~q>_)Jg!{p|cR;U63qGyl`Vo&PuXSY7~s^@TCt=c}{e+l-I-?m?`8Uk1OJ z z&98ueeqqdfx}{tH$L)302KezyV&*j-{z{wQDe~uCvU#a)`KxXJ5`zye_xBGSF?<-_ z&p%|sPl3PNW53&N`xU@{3}58o)c_SFY!-YM-dX#=&5Lt7J7f~F4Xh;2C&XFkse^fT z9c+Xjdq?6iT;#C}ek6RA$3|17jYPJho?3Rn&+sms-#j24ei8g6Az-!RlnHh@bKtka z`>lD3;WsDY=fJ-J@7E7j!M_DhQJnmX92;$de;?j&O}QJs$4dWtY^^i!N? z$?5Q`;Rkx^ppRV#Iq)ys6Em;y$WOQJQw)FHy)pB3Pdk6rZs&90|F+71oL>bWywAUU zo8ZIne(iKO{1o`@9{v7i>(}x$#_9WG=DQw0@s{l;(&68Fh<8Ih z{%||}V)!56{pMkF;Kw}dU%plFcf?2*6DmQRPj1%9BLua&gyKRNJg;YYgplpI^W82&BzEKmMt+WF6c|6y&+_Z-+N z_&XkpnKM0oIAZ&`P4Ii4bKrNvKj^WaGf!CsU-IX~^OPVmo8WiD|J~icMqHbkx=D61 zSw{`Tx#{_sd6uV*53t*K8k2}e>(SAjM(SsFAI*Tj>gAYuyGO@mvW|rgBjA64|JqXr zdt@C55#eXciBr$J!4)FF_M@eCJ6QyO_*Q>Ex(2>2yq}-j3V#W_Uq9IcKTf3Y(b0M4 z)22K9@YTfQmC(N{{O{o(^62l(2Xo<%f6c$0l*9iKez8a1na?hQZ~r&{cCrS3H@sgv z*$Q8|Epa;$`tO0?1MjDQn;znsiT`}IEBqe#MDy7o>F2_~_j=5{z}THDchZkMzG#{4ieRAW_fTi8Glve)EaF@H654<`eCEv2KI+^Y^{s?|}EKqkQ-W z;Qi_-0{;bk*i!~)4}2;7p!faz@jCcE@HHMAR@ye)4nLoF`k(fs|F~TTd*M&`$iE-7 zKZA8G{4$Tc>-;mwzkV8l@BN9tpI8e29K4^OSOQL>giZ;9){-9QkzUi-rFMx0D>4yQkAMSu3b|CME9_lJ%YP6jwV344F@TVNp zXrAwxQ{;Nq1s(hFp3U)%zUzWa_;cX>=KTfmL*f1U(Jc6h@P7Sh1$+g(Uq9La|2Vu~ zKiUc3;so9er@VGOyZ67~e?b03x35d>XwREE@__P3n!l!7qgO z%fDlP_OIZlc+#J2r=JObVrPH80KOESY@GJz+TWQ4e-*snIJ5%(I`~viAOFd&-wp7W zb!jx`xzkU%+SYF;{5JRukB>RY9w%b(JG$Z{JU$?5^Bo6JzkKWC8c+IH+UaM)AJfyn ze;2^_hWG2=v)~8A`}OY?@Ylin&1E*guZ8dI@v)t3AG;I&>AsETzdZW?)7C!*KdoP* z?|iT$jw=Sg%p>oNgPHKt`uocl2zhwFac~y=yaA2=`@isq3~clr2RFdag8#~+pKJdY zKKIPVgyWzXV`A`UXZrIU&*WM2phn;Q;Y|3o@P21}3g9=K#Wy-U`Z?!NX2CB#yU}cW z5D~0#IQ2k#|9%DhHRm+?zJId;ejof@p7d|C>vt#o^mF~&XAFJ`ykGn3n92LE@P6y| zO!&8Q{rzVF{5JUQ9{rqsms#+0&g0u8p8k2O-Tzj=8|OEgZ+ZIvc6*H90RJbxm9xl` zzO!$!6aM7$%!S^D&S78aw@T__gqJ zJbmmcyN~6-x3BZ}v&Hb;;Qi(SbKo=K{pJCy;ID@Fv+pMOS@3@CV>kTQ@DH`1fOa3h z-zooKzDGXZJ%QJ z$KhY`@Gsf?9QcCY`S+hy@YCV_<|&)t?}qoAr|gFR%T@mM+j1!5M-o0A{>dbK4*c3A zd@=k(N%%SN_b1_3!QYdF-vqw`-miV^-cSB5hb7NH9bV+`*MD;051#FB-(vW*B>Wus z)Fk{W_@9!MAO43V{BHQYN%)p*rhb`(Plx|Eyq|q@;FINF44*9jIs3_fmCj#&Z^!oE z583{C6a3|T6VcCq?}q=&HU9O}as=%^37-!CWD-6Her*!I82+Io{2ciElkltH?@7XM zf?tt@-wl6j622vla|37-K!CJ8?R{@f&dDf}>aKO4{APyVa-lmC|e0fVty~I!!FB%f^Wo1=!mozUO~P-1AD)D7 zfFBI+XTP-blINcRFY=$_nIliOeeekQ-_Q47qm;s*z932Y;WOa<);O!-Uq~Xq1^&4t zd;|RYBz)Q^_NtTc8SsxJ;YYwf0PkntQut)~&)4~1<+1POwtZK_AGXkc4zdOQckq7g zvjKi)68W^zy!(+vJ_CLi{1Kk^-Og^`BjEpegMa>|@Y|B`^Wp!RgkKF`pM>86|9ld@ z0e%B~cX$7Hts&CJB+owsUgST=EuV6g?LS7qpL%1X>E~Zc;SX5CcRM}u@7eP6;a`Ej z#lzoZ^Q+;rZfZ1Jr4YgPFDdpKd<%T%-}4=CPy1S0&-M!cR@Y?}0B#!neui{j?-}SNMV?d@lTj@P0m~96nk8i}sWM8lC?=?lzv{ zd=q0U{5#~o%ERAn`;a{%{k#0@ugy5h2k)1DSNM05$mhcENWz!H|04;%2>vyAzd67f z_|m)m_1g;nDZHN#-2*>yWs>q=z#0MGxBT#LCy~#EeR-M0}{rAA%l0?5Y z7js4!-p~GB;SX5lZ~t8QbMN!Fe>wcHB>W=y>?Hge_{=2yR``BN_&xBw;Qj31W!k1Z9B(W9(AEC@9{BYS zH2QuMu+1fW8~&k2^WhdKV6QP&JM%yIEo<;^9^U!xNG^P*NBrxj9R4`?I#2m(?D8#w zuZ3^p=7&pKwy!nth43t89Q{(xwdJ?M-vpoK=C4rlLBjUHKL#I|OaZL&wKTYM;@dQ$4R7*0$Y^DI?o?}eX9wv7xc=?;n+1Ne zz;71#%>ut!;5Q5WW`W-<@S6pGv%qf__}{X?#=}(3RT^inZYcv+KA>=;MoYgB9#!EV zY22gH;`i$NpEMr4R>c=fN%5PYFRXicmWOcbzABEtLf^}^qDVk2sQ4YMz*s#+rGK=( zpH!h%S;y-8G>yk-EY*C+IR3kz)Uj^)Tp!L_tF0I7Lw*{JEb&~FUuy-%V_Lt1^nC}7 zM`*M_i}7GXr7RxriC>kzXs>RKRvM4e*q}4A!qW~^gjKFxI)5E3|E89R!C$)x>m+2< zpY;8DEoka{EpB|J?=RE*5BlD=yH4zX8n)>AiqE&NZU@6OUZAl=<8+PlG~S}|evMCQ ztk?L4#*a0AuknCGRnA9hJVj$)jl(ovps_^bbdB>g-lFk-jZbN;*BD>E`1`bJR*Up9 zRy(jlJ6a9P3fK=?@)iysGGt&dWB90XU4lJ(bnDrz$A07m&3hbtld);UR3pXMlrTKi zXh;~|(y;oUJGE4Lqt)-c;RhI2|MZ5pGOTv&4No(y_U{cp(6IWIH@vlB^*?Voyz)rAvgx**Sz8FjMe{26n>~N;+sU_hZ&YX^rmyTVfjIC zczdHNL4Qj%jxZAS!&Ku)V@J4YyG%9kUfR!j)5kj|Xve9>(Z=kA;g;8SQW5^DrSY}t zgs3ageiMZsPI!tKE%f+i$qD}~!h6JpXXtQiJhbBTY7MRYXk&}k)AE}fw1KC$Pyh4Ycc%%w=P>0{5!~d$o@6zF`b$FQ`(BwB5;r>B* zqVhHn-oiM<*fmYHXRBOk_zMwkRC~iSba*f>e1s0qiVH8*;gjOR=j-sM^LBbbLMDsKc%DeoQ)v?DIY0(hfCVJBagI zB0Lxu-dl%f#f9hT@JTw{^7B@C!^bPdswcyqPDcbmGhVkPf%XYqi@K zb$EQctqiJk;@j;}C#vxHcDqW4$G6+1omBkzc6-)ID%@(f)!0YWqxiO@_*wegt;4TN zSK;y*BA1(Vc*m1fxO_*A%dI;6jxH*^NP+PV;fd<^Yr;i6&aPGUYt>6TZbkUU>E3$p zuETf5g^$wV{LyEbqws6uSE<8$=y1#aH|X#&ap8~X@T$1**L3)jxbQD@_}aMewhR+O z|7~&M-E_E7haf+zyrXn@4;^mlS*gRv#D(9W!)NPotGtis@Qrcdujz0@er${H{L9?= zUW*RT(&1J*ZCL=wdePyQp51i#Mjbvzr!z{22QT-Qt5SzgiVMF%hp&tae?*7x(&1M6 zuj%lt|A(^k0F$h!`hKg3D2j`(A}GS3AczW`gCb7n?&%z7x>b5Q=bT4{HKQOdBFO-& z0-`9chzN+fhyhV_6+}c{T?4NefE5)nf9Kx%*X(vN-Pdm(9%lA;PoFw<>eQ)l@2!3# z)6eaE7<@bU66`sQ77&vCJHff0Q@~a77oezA%iMnOW$;b^gRg^g{pW#i2j})&3%*Ox z^F8oA0)H4>_2$`n(XBMu{$+um0=`|~LGWGRoA!h65%_uF`viV1__i~dJzUTCz|{hO z7(6WS!)Spf`M)FZQ^0o!JP5u^;4Sby0zVIYpTMsL-*%Q@Ke$@p4}*sVei*GoW%~tw z3iwX&lX(1q?*+dayv60WGkbWyJCDnQ^Zv!hqaVMLDGHc9_`y%6?hWrKKYd0}42EQ5n`{0<)svZD; zSdi!IrVS}U(GQ=0KI3p!uaj?M9L>Br&ph$FjPrIs74omTlW}xol>_|H`xrl-{Zd82 zPX*`sFaz!ee-Y#>;05p_z`NiZ;KzZ#1N=ka+&`ZJf6h;tAYTvidGgi&%Q(VU^#jPC z^s8CReyNV7b+XjozxEgd@^|ylpF!}SJe36$(uC>^@PnVm_+U_(PP-j+`xb75rj&+=lbuO zqo3gSG>M2q7EzZW$<;_$;)k5w=VZ*;Jn;#qFyhP zzs!99y7*D>yTN&W=6U$dZKhw$!_UACpM9{0&wu_7&hz<2^l{0bS9F;ko+tVI$|k=I zv)>**4|xduLg?q~^tbkz9-cq>JoA%YY0c^-~}j|I;C|9)^2^l<-w8=U)}`|Xe5qTkkUVdZkabx`gEd?)l@MqJ82 z>*pi?u#c&}0N({G=I{)0IiFm_;_z(fc@y|v@Ezcnf^WZgR{jR!l0BcigV{fZJa3n!?`&PK z_kq*L<)6LKvvDVrKNtL98lWZp2Y-)o-mkZTFN1p_ZvlTd_%i#L$`1bR?=!&HcNOq+ z_AriZAk_}=gMP&LAD~Ct7nbbVcMk*dS?yFd&#OPZkMV0@56`Rb{3+vNUOn}G#>KpP z3%Hn9KmETpE1t!>H}n_6wiAvVDY)cE~^fD0pq*Dx53U6z*QH{#dUeLwhi@FmE9j=1E{GvVMS`2FC&2j_W%$JN0Pu?mU(WeCp8 z{X6u$7yO0r1J9pVKgeA?qoUK}3{;Cy^M zmKs8`^Ml~L-US6nS2NQGVl&KZ{IJ2?-2O? z;JXC=5AZz#f5FkrPSs9UF1N=5z7EdI<>S;_scb+N z{qF_m{^#+3Ew~u}FFKg%;dZW({Ze}wz~!^Z$){(6U;T6@|3&zj$6H1|u=i~A9)s&7yHr4hcV9k5uXRX;Mt7xIOp+s z&Py2Q@yW;EyTSSRdnNqvi2Mb{bbA|q_#F89DNGOCp}L>=R&o9)aVgH1KF;EY`+plP zz~ymP;HQAE3takcPRVaya32-s4ZUz_Q z>Sb=Ghu7!C#ctU1S@0!rF8>4KTlwubvOL`vyMp1;M@;)fiL5^K{NdGD3=H4{y&`lc#>-Wb0&vC zUM+LFKLz<^@DTW3L4ON;3C}00A^%?Rb#QLar@{Gijr33X=R5R=WX}Z8y>NSeCv%D` z=%IhgKTki7$!{0rPm(!3w*YzGj&AU!PtC?*349rx$KgA`*99)!&z9PKJ2=;W8~83k z{+Gn1Jn+#V>vz1rt6t3bE#N#qycGN{a6XR;gD;0>^|ZiWCvZN#jKIY_@BlckFCPcD zMVWpR{LI&DZg5^-p07UkdL}RCtNX#leD#bsFnOM@c%E;A^E}VTubc8ro{vX-zEmhM zE{@FJ|pt zXfXab`1Rnb>8w0oH(dtK{mj=*_kwf3@paR28%)pglUM;?gZ}Ir8RzlF*K4=Fm2tja z`yJ#1Z)03O)0$Kr_7Z0QDeqwX7T9kjF0E6xU&_XjFzaTjq|BeI+JSz`<82K2Js)B6 zoPQAVy9D_!L4Kbg|1tUl>w>(S_*UcE>t%VG59~Tf*39*6 zfG>kzjdCvm-zUg_k?Z*!(_@DGJ>cu$T+d&?w_V5NdAZL$f#siN@Co$jz;}c5JRAkz zC+O*dFMXcr??BHE@SWgG;GgCC!MQ!(1K%s~hrm_WGyPo8GhfQ=UlRDs!I#0gJuBe5 zz` zoR^yg-wnPU^4qzdFEahS9WMvp4$kfQ3b^VWaRxgQ<_-viFu<%pA+ z{rd!N1Yi0JEB9>pEeXCG+zdVfSABI>{vz<5;M|@Y!1sW2d+yXFGTjd^r5d;`}5z6AaEfbRsafIkMl?KY-| z*Y}85F#DImcS7C>z8BmBp5*dhpY_iOd>woT2hPjA0etBjOb;*j9`N1ZyxhmQ z{5NOIJ>r$HAN&$-Klom7?uR7!`nQ-KErL*{}LO<0r{iRVpL+GWZgB5_}ze0zLxYEAWfB{2r!%JLGTR z^5DGOd%%}|Fl*0aTn~5$dXCUA`}Ydm2p;|+)3fP+@a^DS&j?&~7nA4px`@kzb31PU z-!1TaxSqS2o+a4%82A!6*MEeT*}qeeH-hg5=jA5BRX>{5KLTF@=lU<=`UUwLxPEYQ zul#cl*MASwzYhKw_&Rt6{0N<7|52)KpE_73+rVEAz9jHvaJ9e_;L8H9frkZt7IA5P zefNjidW5g9`TF+}@HXuEGX0k1&-e(F=kf4O@Dcbmkbe~XxXYOQC&7=Vb(N&&4)FJa z^XHmYFK6=m!1+4Vy_4}zf%A3ZAHn%Lkv}i=zK=5b<01bM)c5n?yuN(B{5^1PKVL6T zKgRU%^)lagJ?!I*^K~oV2RQBu#>IVrHEUxGc`!QTiwe*yjvaBk;+z>m0+>ED3- z@p|UZ9pGHv4t@>z&5*Bw7q4P^#^5`^?+3pC>)-3a+tS7b{d^Acd>`YAYZ&M2YkoiF zXW*3f<)5FBnAGmi{4|pUuiEC2B4$36^Bj{(R(Z-@Tt1pOZezZ3ji$bS($^|@I)?*Six z?}GfZjI6%LUpFiN3h>tooIlT&20spZe2{-5I1Oj=PYwK2f}VGSe?#C`gYOmix4{1a zej)Tf1inKG4Ep&Y_zS3mNbR1xp7A@t`M%97zQ8z-E52`20{23m@7sJ9d>QfZTIhe| zhFQOz0sf3H&hj^dpCEAQyB#Gvmj(VM@Yf0aKJbyi{|0`(z>hRD{htQs?P3D|sUV*O ze@x&*@WXFp_2TjNKJbr#^L}wH_>BU;6Z|fL{{j4AfgfsN_CNimS%01ke!RfF;I9>U z1w0MT{qQdEcMI}YfnOo;Z-9SQ;17V`2fhn&awr9u)V`10GHd_K!JqNvS?&WrLEv@p zWr3dq{yKqQ13nV?cfijV`0v3#E$~BM&Fue{z+VpjOK|Q_ANb*4nXOkH{1pN}2iy(* z82a5V@Yj5GR?i;rHG%H~?+bj}Y0Uof1g-}Eq`<@AUl(`>{O1DS0sePz?uT9AFWW8H z5AG27KJbjdx4nkhzaeln_=N%wgYOb}2mCt%-vR!A0^bGxq+131!H)*#_1y>V6Xds@ z&g?IN{}b)22mj62X7$IxpYhFEJ^(*K;2!{A7WnnxuM_y);3IHu|DVCH6y%@#T4w)l zaQS;5s17FZU)(-x=PLLO-=5`T@E-{LV(>o*{EOgEyJJ?*kHKFo@V|n;2AtRH`OD1y zh9GYOe;2s?eG62tGr-^f-Pv-_1h?Ed%P#}3?wRFZ0e`!|e+GWJ!2b{8iv@SFxWf!M_6jPw+dzZ~h_E^K0-wfnRnP;}?M+X=8Tk z?`B;7egeAo8t_-&!#ICmrUbrvFXJzSo_B)x1b!9xdjf8e))^ZGu^&g^vm zwT@OKOR0q`pX{!|aM^Q!_s0sKC2-i}W2r~hu&o+9}1 z;MbyE&H?|SAb$<`LjwN}_#wZa)&G0&mk9h&S`bO|*wY36a`2SEec%IdUava%#|8Ow zz`r8!Yrua3&hyVb;ITi<+W#1M3!JYLk6vN+S00{~KMnkC0)IXDWdeT__)P-;F!@Zw9p-5q|aEPvqtwvxYu>Zq6jSha_$>hbnsZrszc`5fu7ZE|`|RI-lsf|N#aV&xWS3PR z0^fEa8NtHt6{!_~ox;{Cx1IhFN|8{W1n_ z1wS5K^K}N^gmQJ@$Nz%ygHWym{3Qo7{l9{q9Qb>_!~~1%vg)nif4P_mejD;12fr)K z#?Sa4cHzkpW`8@%_*2*~)rsJ@)R^39XfGdl^efDeH$r~~{G3}Dcm%u& zzVBfMjNli8zX9*pP+E|Gz6}2R_cKFIfIYtif68xIx%7RC!VeSh&)m-BZ-o9U zz_qVr{7UvqbqDxOBL>ot|2_Dba6FI0L*vZOb*C}~$ z|C^Y@J`DRW0RO}bn1Wx!o-cscka!~S&wb!O`WMqPLAk#K|Fxch_kuq?!R){K_Y8!f zUjzP$e=&X={QL&+3;xdZe+Kf~!B77+livpY=Yd<@O#V1-Klp2oWPr>=p+ z4fsFyFknZ04^A@sf1YFd?}Pj+z`yk|rXR~NRT$j+T*hyL{2Acixr}i=`=#oFfA?CZ zpSSz@;CJFZ;`Y;+qTS%;z3ktwg8qHrqdOTGf&UBKvYUbPQSPy;tX?<1ft7nA{BHyQ z^c$Jr(O6)tfai8HUSuCrCBYwf9pfj1Z-C$DXMpF)^TA69%s%YA3jEQJGw@CD+rh7_ zFz|fnf1LB}jPv+Eni7#T{=R07*>g4G{B-bd;K9<LqPwbY0RO<-m|T#3Om#Q-*DMS?z%Hx)3jUSL8Q}ATV^geN zpS+UEeZo=x>2P$HKsAu;+a6mttVK5PCij{*;GUy?A`y z4SwN(DL^`=FA!sPo{fg8bp2HxAtz;)nHrw>Z;<~V*< z|8d}V+{y&kQSPbW51z#g=i5~&aPPO7Akv3w3|_pM=|MQE&IDijB-8VD_~FCgU%7%cpw;+B3;6F03 zdSMx+YJ*?6&J4k@s(LT@wOYo}Y^u+LKi*{g3+$KbKJY*Nmg)Z>_+#LQU&X+&sKzmG zVD|s7naT5hw+wz;l<^JZ2Osz+@ZRzD(BA+LVm!*TkEzZDKk_R~@Ezb6fM1J*_bc$5 zz?(R4>R9OiEx4AVOZxdB{CVgZ%>F6H**fG;1wU+qDaJ6PN`k-c^Gxs!C|CM!A}Ma~ z!1{|nx9~CWV~b4wIQZ>5;NAcONUy2~z@HEMX}FPp4$Cn8XWz#D{Ymf_f$w;T0p2f8 z2S0R!@yp@=47mCx#!rHt8u(v-#6SZ6IS2e&EKpjg?=J9vz)tSBd%!>Y6Q+m4M*jH~ z_!oAt`WoSfr>?VlxoG^6etvK;`+e#<L&2J zu4nul_Dgj?_&G;21-}OWC-|RtGX68@e_@{4{}jxJuLQS&|Lz^Ez&!l94*s<7GeJII zdNcUNzhNBBrur!OA3x6w`6cv!75shgXMnG#egppA-!b_=!v24OzX|dA3hH+e z7a{$_E~JH{-Z{rD}s;^FGF(0sZd>e>FBv+|Yj&`0JZY{;)&Yh1g?_&Qnx{vOop80dK&xVg^C<#G5<@aJKmy8-eSf}c$JTl%S^ zUS9-nM;JecsZ-qx{_r|$aQS-yN#u9nCt&@;^VOlW4w3Bt3?{tWm^#%9!B4!H75I9T zdn$2hekGpAZi9U7DNOJ)(9;C3-^TdQp2{w~AN(H}DEZnEL^V`@CNAyfis$4%jRq{Ky`KC$rpE+3 zj|9J^#|nHD<-QvH1z6v`7~D(zNn4z6pMm^)?qGr+;eG)Bp9$j_##HYFe;pilEaX29 z{<#O3{QrU90e&MUo>;D{{sjK_7?a2LrRqp(IH|tss~Pto51$79cQxbRV!u>pfPVrT z&o_f_fIs^TX2|-X?7~j)%T8yU$N!hW-*yS(??>GJ0Q@6gWuN~r^#2L`&aW`}A0i%} z(O~u$?_h!_K;8iUn!}hppC^>SZ~Y<@Y_rR%*g2A(L-%j+L(ln;zh^rGcsxsWE4cM# zjHe<0Ao#VYFa1;gIgHjJlApB=R^VSz?$O}C73NDW@a2E9it=%x27V|e2(N@6J_7y@ zOmIGdaz6#W?{Ox`=aY94Km5sbZqGRf%aY5Gf0Xm980YQvf|it(o~7DZW_b_Ir8=3o zr042SFnLr-$6S_1^;RpZH@YF8OmO7L;6meUAK@kl**Q+4^1qz76MNa6Pwz?}Z;Ye~k0@F+IyL?YUi* zYUzn)s?@{}m)@tw_grv24vCZf%O9Wh^GDw%>7gJOzQ3a=%RgIn(he3^NI$Ccq305z z9lr>^e(tQD_Yjxj;WI)!s3>1c_Uu9Ya61j)dxiK+aK2+!e;@o_!JZ4iw+sHfiR&59 z#>0=n*9WuwG4R{bkGP$$pb5NW|2CoAb>h$2qFn}%-`k(n|9(lH{1d=D_L=zX<#Y6W z9(o=}zrgfXbqo0N&RPH52VTLsUfljC4Ve8M^dsKCwBV}CXZ3`^w+s54;ExObc@J@^ zUdR57<$(uKug^h#8TM}jzgv>u!fy{l{t(D>`(H9-_U{nlc?G;9@Fw^^2jg5Fy@v1io8n zmq)?(3HkYXV`k6UA7$;!%QX|w`YLw5cIzVeECSGf1SoH>E{FB z6Cr=z1imEn>wCbr3vqQQ&BNq=C$!^hIfp!tt1|fGLVeExe^AH|yTL0$JN^b-E%^V1 zQ)bV0!Jgygaqx-X4`n0yt>QchJsx3PJ5%OIs+Q0$%d$6Bs-2KugFU?eeiwYNApd*t zlTcqS|NISR|4t$A>A`ovZ`_}8@I6Aibck4PmsSA{6T^L1$?j2UN3(mvvXaD zpVNtNRc@HePiEt`34Rj#FZaWx;2j|zzQDO)=l$Tjgns%s_}N07Join^{)&({)Zj-# z54Y#_;7iEcyxljzw+s3CQt+L^yzvI`icqiLfv*ew?vOVlo-dxw|0jT}gnFgH)q?)B zh)a3(Dm*87GvfAY$S(kkDzDwxWmxDhjlzSI= zM=1AcXEA$Jm(2R-rQkbx%^YNqkZ9rBhfCe0N)AyoX5cT3jL@Dz61KX{H0uvFn_xldow#ot##&o<;q zuID@8D#356cQAW)3+?z)@LhtupK~D(_qZNG{*%O)wy^U?$nO>M-aha(!EYzLli9gP z@Z0H^s#M3(I&>%IAw1q*2l?%S{`blJNR{|KsUIf3l|Qe8o*jaod%-7yAO1Z@&*ASP z`|11;{(YSX!6!=+r+D5j^j{ZosohV!owYk3*E*0lBTk+KJs$xN3-jb}fG@*No}V8A z-z((vL(gXRm=OMrozIG=49{{J5M?LxUveh;%}9rG)0 z=ZWAdLEZuO3i2HxpPVPlL+F5CAA|huLj3<2{3Ibx{ssQHz+XZefKq>n-^u!m z^gWl-Pk^{&|88L(RRcdn@XzJoR||ROCN7WoKZL1Q{Ty6{bIzB+{|UZVm{%P2US`jd zFz+&g?-b_Aaqw-hljrjZ_&y>3e1_{0_VM<;P8!!}9|_N~!%Wqc^7ys?dxuZOh3}9a zseMz}FA9U-1^qjOarQ5gJo!I|_gE>7%Rk4Q$Ld=V`rWH#PUk5NkqOZ;vXI{`tVhlS ze_V*qE5XA;e!Crfr_f&i2A>G=`NH=xJNLlPyr0^@*M)e z&)dPxLL5HA^}ugj|8sV*b`4yykO@yiEouB?~^%w zF9YIa8SVaa=m`t@pLag9b6Mz*TF!;~rond#`F{+q7V3Kq_~SzR{t$e-&`%#BzE!;r zdOx#sx6tk{2frQphsVh(_?jSp9{AOWPcDBm_+B9o+zYM}?Eeq=y@Edt7ce`|7V(ps3;Fq8@V$aPe+GY0$j{q8!0bFy z;I9C`8hW^$Yv7Ly^%@YD?Ej}QFWL$DC1D=&Rq#Eqe;ew%7yL${UQfM{**Ou~@zvn> z3h~wk-y_uP1K{g|{oe-PCHU=O@O?sl`=5)LJxjv4uL0jH?3V_?w+r)=2KchDpYv|c zg?@1r_}N09{{i^AFs?lezEkk?|6I)MU&s7```-fI5%O~r{A!`x^TAbuKfeLKL+CGm zllhUVim)zt(Iw2Dj-cNKz8CGz$Jr+MHi3TtdZ_vli#-1q z#=B#{mxT5`P2yXucVfh!gV;XsR|R_Zz)tS}cX9o~{?!%W4+`;l#~l6lLw*&-n)UHlg4B16(EC&pPTdmFmS?#Djsj)K7N`{Uru|yAbDRgD(s5 za4q;Q*w4qid%3(|=f61@{CxD~%${ZBRj$Vleu%J+&VZ|gy!2-9C1D@+L&T+V_Pf7e z^8_^txRuKb?f4t;eFA^hPWVm8V=tFD<+0sDe|#S0zBRh!lZJ=deQ75gTT3jWh7_(!YYAFV?Dv<7j9Rj zzwDJ_zD_d(Qb7Y>G3W6)TybqEoO32qdXvkN<8#1Hwp{eK3dKn#lMjSUJ?m;j?b}GL zg_C8QIvv&VlB#`cK40wjtGPxolX0f|o$`iRuj{N>vW1pIo$joJjC^({>7|-9uyfxwX)Z@?6)R?Y z`AQ};QMWBwe_!33=BkF+v>EDK^3}MXw^(D5#!UlhT~de*tAi}Hm#xvxlgqOGWKb6f z1>D-6&DxEbVojfVb1fjvKWS#=FSb;@?0B_T9TZjVzO_Lg4O4UWGZ{}HR9Wq%G?74- z=Gj_Xeq|hUq`6h?e!MsRFT^(uq?w<6*z3t*z7kF}%pJW>Yfk$uxwV#akjtj?+=XOX ztT>PbHzp;YE!7$fEqPnEQ?K;wp}MA2ZWfzuT6&RSy4Y)zq-ulx&SYHuQKb~<=K5o2 zyg3c54zf*0k%!a)!S67qSJlmFx?pl;jjg<6v`P`15Af;@JB93^815BEvFZkO087qb zqnNIbP0?(_Vb@ptHhmL-llsCG)uB~jz z=CeLtAxSPuZW~c$=80}9EflHawe!|dBiJs`2Rh|)CD?QXR>NAIzdH$bE!jcc#4AsW zMWvSA)ZFenm~I4FAsTQF2jQ5to{L&?mRuv)jBkwE-0G}UGisS=snRleMy*IZY|WXo zwYFx++q9eyWP23t6GJTL59)?Vo4xPM8cjj1x)tU^d0L~!+lfAuy3;t z_10Fq7`E;gl{NOvZkuy;Iu5E$HeED3&}BDb`iQDm?8~8>57`~7J&iHt(ARVYS}Nx} zx+!;XXV|YujYseRp+gq(!J`gYSdDR6BRP{HCjl&i(t@;=C< z-ZiIlD?LljoA7ypmb_0th#P`jT-w5k4YK*VtvwjDo2o4RubTI^@|n!Y*bPPdwAS8e zcs!MmU$c_3+N1n~(t>>M!b)pax$T)kwJ#;>OeWe-X^Yl6)y_F;I4U_)dKz_^dGDI_ zWz6hI8Y`uI*>1_Jz12kD+Ky^1`G};j*jlJ>vk%T{jIOjip&Y45>RQDhsddz&<-l}& zK>OH|+0}AAk~HP|X;ZgcPfcjsMa`=^tFEx(FGr@SrZt(0ta_@Un9UZSS`Sd>o0u)x zMxgBqcUF5&O8*mWe!7z6J!@8*C*VyMQnf-lwc4-8oAF4pZLmdz_;2S1U014K9vEDu z6>n_ZX*Fx(1BNS1|aShBWOEk3C_Om)g+gLJZB$p)&m11sXTWGjQ=25s4m?Q6!-&>600ht;hk zCF`?J+J1F|B1s)i2TL@Bhi#n$yPb7l?M*1+yNO}eSx+P^`SH-(tMisv7{cmP6eh>| zjNuf8`L!XVqit5~?$NZiUmOmq4ZguggS(?TqG>Ld7`Cc;8jY~+gOBwGy#qfa*}USW zS(znQ(K>Xkcp(ur#og1cIcv?Z<;2{}v|QY;w3uyjLnNJvqG`~w<@RL6DE1G;X!dM*}S%Wp59m~5Yb2O;Q0}Be!XEbVZBkUSfn?-KbY>0XK zE7e3IPveTmR!C6l^Nj1UxHwQ)vWAg96bU!n-M&?8sJ4UViYsN64KN0Cj`6r=aHZ4+ zOHNbX&|3S}bR@&pIP&siKRnYbjh<(9P4J%V_rpR3+Q5YkEOptVW9REo&GW1c20wREvd_lmOJYR8gqM!dsfDeNm0 zw1)A}>EubB-9?bbFdpudK}+o(1^og0>0QU#M!#B$M+z4aw;D3<;vY$EnJ$~ zHCkOFrr|?yp*^7gNNPeG0Jfwpu(}bW1@2lfP^~woelE5-w$T<_v+k&trS)JST#Xow zbxS_4t2Pb6ysNGWlxa-fY#`oZwB1AZ2eXX>8q6Nl^|Cfvl?`ikXEofJq^yNTnP=~L zS6Nb;clCg*Bv0c@jo^yEXAPzYRpTm6(Eag-+sy`#c`Dcj&AC3Nl z0Sz+;R65br*&|^}N?yO!+is*o{YlVEH+@*O=3Qk$IPWUklAL#yMd-Y%xF0n4G7G`E zmswhxdwH?ln#G1|6f9?bYhKw}%u(j}8~1VMetL1mv@A&GetL0h;vUc3PcN>wcCpux zQ|2kh{h7I!7h8_IGjl(^*mB&vnfGbjdYN|_cW&lg#*LY|mlroEZp+O5G)uK}FE93* zVR6~o{llr8vqFWQ+tbS#2ccRvNITLiy(CS}511DpFz8lBt-ODAC9NNIriI8_-d;7? zS$dmi>*C1O?;kU|)-{^(Omqfc!j&>vvTNq>if%$PB=!Uc4F`BSB5KzNHEwHpXf1Ib9u&hJ%Po+VQ2QCp6=LAyK6*tXiuVF+?2tc6buv3(N`cEs6RLT&RG+fAmuU2-DC8y`CGy41syCgY5Ee$#vDn`R zbw-c5-Mp$8O!APjsJ2E)%jT-IEpLb&I1AJ}f_;51kf`^^mDRkytuF*DIqAt6d3HAM zD)ZpHs~9-uUS_VDdzpEE?q!9tS)Q5uX*M#~q{$pZn>>KF4kCd7suVu9$wYa>L>lGc0Z~1MB7UOv4TJxtAB4 zhTGZmK8?G%b1yHB7SrOg&1~42r`)`_-sZ(+TNZy>qh=Gwd4+4#i;dH$7q_WKz1TdB zdT}&s)QcldqfxLA&pFMlA6A`nuPfvU4W@B(Kd;c&HF%C^{^u3^i@DnT&nx&(ui$^o ziRS88=+hd7POZUnEc5j*?mHSh$1(Twc#dNJb%p*xU(G9x=yN}BR`8!?aZ=ML^-s&< z{-agszgmUiU#k%RTCDx%)nALn-`wj;gSbNf($ej$MgG?+#J^TyK-1zmt-1E=75r~t z%h$P|H!RMtT7~|l#dBcu^(*)X&wJ+A>Iy~n%w|;m|aQ^kh^8=m2_@^@~eBQjc z|LdrK1gp(Vs3bomn6X>!9;eQ-1=LfdKS5GY!`Bv2yA@n)=;CRhLDixcbLh#r72Vnj z-N5M4?Z=B=<6&x0@uk*U_D&>Q{%=%hG<1tC zC|hFcjDosmz0fSvO;c^zVW-<%(fF8a*}QQh?=-De41+gxhDN1ykYmL>3$tO zFq6sD1~sE;)mky=%gJynYfafSbxUs3o_?F&Aj&i~p_#am zF|?>add_`|j|BSkuxrgf&`~(&%c%kF!X))cdd$JlEc3fvi?m{kbY8E;9_ZZ5i$h&u z%AznMp$P|X&zP-~wj2D~R=J(1PSurGsqIZ|Hq)@xr^mG9`>=s_qwJhUsyf$IT4;1F`Eo-2Uxk^%JO_`f&+{0bHlKTW@gRz4 z$>)B0@erf10#TR%DdcyP{4$rV-Rrf-|6g&fFfUR_`wFWXg-MaZoJe6xWLccb6&6$q z>m?eQ7WG>V4N^#A)5b93HwH&0pSRnJw952krG7+D#Ia3V1ucswO&Ya=6*NvPv{GSG zrcqe5Y4GyYynxr>p4|NF3ic^1`ZNlAvl`rZn_s?#4So5rHB1jZ(n2RH%q%qu+prqk=bCGzLXy|u4W#*>UpxwE6jrtxg_WyDVJ}ysuyWNX%zQNp z8C|20(lrWOvKob)ufZEebN#C@^VTS=j5W0KrFShdnYDVG9*!`!t=>{8YEEc1O{*^7 z{O=M4y`{4-Mio}C8im!XMj_2>%nFH0VRKnSs{`2wdS||zP3NXDXMdz0nXNj1GvwNw zf-bD0W%1~$RoH;msux#5tFVC9Dr`_|6*j1~3b|ZMxx7@R_krlS-eP}B&pwsa*~rSI zS4i3{dAG?N+nn<+a+6jeWoz-I!@OwM;(gS)*A@1uwF)zDE#5bsuV0~=6tb2oT$5@TD(F}s#V&xl+U%&w%PrT&2dKV z1NO0h5Hk&G{!zV8kGwbO4UnKw-QE9=6 zc^K)8P5RBKW^QhG3a*gb)b4Z#p`6t;Y^g2T6}#Z&{=m?#^6j4iowaYF5@ z+bmM{v$Yl7nB*ws#%wEv9zC28@daud_RRt}{oKs1_G9j0(3dQ@eWjwF9(k`6r~jRs z6_x~Ag&Trela3`ub9~@cH)@fAwK3^W=|R@2$(q$Y(bifo;IOuvBifuWYKqQeVxy*} zr(yq_*``+E7KK(}5YQ^zVALvX0cjN`>{^8xyH?>Ah*n`ruT>gB6z2RogTupgts$KH9n$A$XS=DTIN?vPi!>|&W zwxg+(ezHMNum_?;dS&3ht2K>o+{JTB`!B1lu=3C;tUPoIx1)3lD-)fTi|MM2zPg`B;RIS@Cgle?q+Dhj_HLKaSvYBTWt699) zr=uOU#h+KW;h}ItQm3%-rc+q5>1atdyZKKOB~m&yg{u1Qz*}|1niG4}l4Vbi&TVnp z!DBP8N-gTFyWB>*J?EUX>E)QU@oGD^8MfTz4x1(%(L~*$gm2BJ9fxCUp@iwb%Qgzz zeL98tfzGmcqeG`Kf6yt+A9OT75MH%itqv*_Z1kqC^p`!GuM`&sg&I$X&hxgJUi?v5 z-x#HLe-`g->I@o^S-iETGg?SSIzP@8wFaCSXOLbSQT6F;hN6=W-k@i8YkHF}SF8?o zqY}Lg)yoYdx(&ClOfJaNd1%=U51n6?GIaZvoYqO{G1f2YOU<-ZRqV9$l{mcwD7{M6 zF4%jkYyEu4T?{5G+I(l2uG8yb^qK^{3Y^I{lMUJqt##9CjnGA@eXW@(%qTCs|m~=;(!FcKjWG zlfz4Av^BcJ zSinrBVkR@<_E`+1 z$&7sgohjY+8&?P6P=a24GbYL!vsJ~;p`&+vijlS8Bv&wX%+vem}0SCkHZp%?GTVN*-CJWWNbuAx8LubK0c zoGGBC_eSM+V#%$oLbg|+GhgT>tyrg+ua>IPRz)&t_j&atpV6HPPa^c*cBkfzNv~Q< zk+#_w(WW~dYib&1ZMrllmUI;<;mfxr>Ag*yt)dYM#A&9}BHGEx9PY7nwI#v$7H*k0BX)Tp_Kqm=D9eQsf5u!s26Ln`{u+kr`Ib~IH zFNp_&vFS+PHBY0yhR0CUBhAbp8ZavI*=<%?|_zL!Hv2; z8*eA=vA9#y?v$J(3i@KVKtbGV)6ox^LQG?G>5`KgouRQ3Xf`X!6<@3qp(vzRFY^QW z1VehJe$7*D)0rWimcQ*Wxu^D;hF(T0(tSxCV#*uJWYVd+Mqk&_SuE*f!43C1*I;7KhEIHR&+`3}UXG4Cyw>{Oibv7LZ0WUK?zdTl&e5#L=?n3qC zPL6XnG8vy~7%^t!zR{{N)Cwid&OkdDj8KrX1BB!=T&?s@@;w$UAfn&y==UiaqtT8H{=wp-|ZzHhG6u6`h_bA0i{4mJsh{rQ<8| zPFp1$)94Cx{*ZUA9Wqoq32R3VK6;6@=%K)t&OfMx#{OKuR9wrZ%g&XaXVqV<2I-7L zsnMk80ovxyBwbi@TD@7*xbA7t3lSmdXur*lSj$#}$&K3TaA>6rsUKx04qcW^-fZDoN#~68l5{s*I&Z1ci2J+s>RQV08zTJboddSe-o@yMv!$RvyCCS!)mAZ>@;0tXi^$g4Z14Lj*C8HL`8?u1n6B3 z>9&eBKd6qRJ}w>e(;S9Ot8TYRrw+$gRy*xPt1X%fcgyFSE{atBmJMg0I8C8w zI9Ok^(7OrKCg}$DUFR;D27JGUa8ThV-s5a zYHToV6z%dkGM0SOTS_>c#&pSO(-mR~_t>2G(@`Z-2Bx?DZBywy9~FJlogJ3R7bDv5 z)2Q9uQLwmXrDG#v-GW5@y^9lf6!jEga!fnvt=Sq`rY#Pfy<{NP3`gjuxM?gEP5GqSq=Jn4cw0&& zlwDYRhv+a)t8@zN{?-lDM$t8Iz*lUg1G=?Z#9gk};$pb+VxR2L)Tjz3K}4 zQqjI6pK{r2X@7u@>q(RUXprv>60M5dISO)rrjt&yX1lqQpvizgvYH&%b%usvRFXOY z4d-;A2_lo`OD#l2rx9wn`Vp&jlus3OEtkPxTHP3{Cd~#r$Aa>pHkD7&2HtesDi+=8 zWHr$=X{p~)9j%1|oxVwRrB{sPcZGYyRxwm6QLdt`lU9#5bpz^LyBp~it==fD-wI9g zIfe_ooytcHav)7e=##Qx{2UeOcp){tb2J&`)4E7#&DXb?nt^;}k|@yw2~xe}vx?-L z?dr9gfh-OF6UyFeuF}A2UFlh)+2+I@q8F+na@@%sd2v5hNwuIkiFKFxS-qNV|;*rFq5rNE2n%}I5!>Ksn(*+#`QZnre4RZ17qc|=}!GSHt+D(+IK zP;>MPd8a$np$u4HzG5$R9WakMa8&b7VlHpdn$-7w$)VpkEanDPZ&_8GNHaegzgD}Q zvR4z#RVry+J{k5@yarh_pYfDkW!EqtX{^x6DS2Zm78~~pJwrr=gW)!lerZ%`k>3ns zXK7<Gaz{un8}z&p}=?)w3%}aekdtDJ zT6gPt%FO&@!xr!Rw1Mz2n9loB#)PqHDy&GUYJYzVwxuAKeJag;*`$Nw-CxX(iqv-~ zCgnrQqBwp!Ug;IH1%EqFCo;%qLa_x7OMm3^P)R#Syzj`Cn2ss#1tZv(c?5UMhBkgE4GR(Ybc^ zV1;sIE9!4`SAF#{#g%-h65dH16*TlznXzuO76x5?+*(K{YKh6_%$W7kMsr;D^b3`E zzZaof39j1EJeCJbO0ASC=^Uy|rY{{-QSrC(u417)-WVCC;lOdp z8n3ov$(5L=jN_*HSM2A$4YgIj@Go#YsM4_mOX;=Ll zu|kX{X$LGd^oCM+;HsqbuIwn9O^qFuXo;phY{@o=wMy}|k;y$-YdfYcN7IrUZFI}3 zO0`^37|AHr(SUy7Nr&p{#Aa*wY=%gX)@GAlb7K%~+Q+Jfbi=Hl476h-b8WJgUYXF4 z=E~O!dg_OCzFCaMFP^?=VjZT*yes8x72BRhZDJ0sjk+_LB=57@z0tvN%@m9UyndSU z>XKF(?}mA#NeWJykyI%n+zx-RJ56ki=>)D^Z{%v^UC*5Yk8 zsAV##*h+e(Tuc}e32ioOb_Yj&-Rctt)B{Eod3`I7r39q2 z6u1K$Dc#Z0bFrREiRR&S2X{5P5*+)6K3W9z2XxYWu-c^G2ln=M&A;l&c6@$Kt>c=k zBx_AyIZ>v`1D&APAB6g{qiO!T^$M5z-ps~DsS+|4X}cik&K6QbdhR%Ept+)fwl1iP zdT2r_tDCEhR(+JY4ouMU0(t*B+Z!JBd(&>cPoY1VWXn2lq^Fg(eFoHbWjBR%u4r%7 z=Svi-=3zAMo>apHnjXND(fwODSxrCbiAS?=-qxlaN7ErX|njg3{J5&|-J)z|7~Cv;{|d9hJH@>yL(d1+_;?sL{~s zKts(Z*Vih4p#jY(JMI;?!QPH+IF0&#-9_Vg*ln`1QCC{5SX%`?CQ+j#jB(S->cHXe ztyTuj%37>VGdZK=4{6<(qWc2*NX4-ljg?b%Psz8M@46cO2raHD2yN{)9q35i9}{%; zx73@d?n&u{Hhn#>&rde`c2hQ`@rHbZkUP6U8IXndoQdabJoG~LH99*f-*H=W!+Ld9 zH*vOX)>#?p34+$N8uA6p3A1LyS#p)5x)B9`C0`F#8;)wfBSjChs!uy}2D4gkG;O3> zI<3`7XWP-njo$CKvOOz*ReA(o>uWpGYb!RrzeyVlVUOS4q?vzte~+_j$K6^rT6K2D z*;QN7<}`bQRe89Q4>e2~>A-`Ot5zPbsA;FezoF0N)ohTU?j~kD-3cHx22qs{`^P z4e4Wf#T1~Ei|G_wc`q_bPeJzzzDb{E%${B(U+~1}xqO=U#M^#pPs-ZQSF7?W=Ls8g zZR?sXZAyimXtuy|AdPzzd-8e9ol>=5AJpmK#9nJ9ykW@ez5YS8ERX6^ z%p*f5;?qgMtf!+_y}q$6Y|^J)^feb~cB(>_TwbB6iFz2D>Y|-+qDuDxY`PVivr9RO zue#~<|o?pKW^-7rzsm&?^?jAl2oSEWuMtr%(hS6g?Kx`kL?Q%sfAY5Qu(U8Ua2 z_8G8nrW1_m%QNZ`bGK%m7!AF`P?|qej+J&90`0<(zNLdN7i9NP7*jasdo(_`veM$) zy`5m!+i~h0(_+6w$69XKYaL^Qx&uv8 z^7W2%1~*NU@>5T=77nI$&0ZnvX;!^G=i25lPAA{)-`YN)NjLn1{7Sc3t5A>frs>S$ zbihrM7kPSPr&Fg%u|HLhw#I=vO>*LP+Wj)n@us76p9W8C%2nNEb=2$27o($olQwW& z2~Wr=Y%A$DYBXi;~2N-sjw<{%wxscA(ubU)kEP341m zhxLj3)<(Kd5o!BN`9?kGNcVer51j^Qqz4M5xM8s-p9+W(Et2NrTZ8R|NXphFaU|@Bvm{vz<`_Y~1YMffyM!`+>1AIuwrw#@*fKm5ejnX-y zqfj+l^cFV;MyqpUt&6Rw{kx))QEW*YqmJ7sIvaF6-po>>FRkLFInWb!GX1G=N;@jJ z%;99Oq>09SPC5pa2DV|3{`1I(+u5u3YMS;A>9F-|qvz60lDddPlci~>lm*x+(#cRl zN6$d#2A)95R<$Q>hCyIWLs3pUIK{3M({en?UAUAmrW-5P0o@Jn71etBejb0p-KP}? z9n5~f?qA**^m|h)5rf0)8$`O%6^}V)5~rdqAMH!ip`z7%sWtGro5{3s)wzF$$?wP< z;9Tk_a(APf6XwRMmWF6;%aHbDCmu`ATGG>JtF36ZC8b!Kx2tRD+O|>8R!qfKU2#Ko zjrKJ8Tr)&R)k~Wj-OAML&aP#{bX&{c?HQA1J9*0`P1dL|>wwZ}Zb zDQeEs;c5Pjc+5;s{~5?lbY?l7T*t=xrsOm^2U8=ugNcmOgBxxhN0iM=WCP{#z$=A0 z+k2uTbDG^&(&l#zQk8Udqe~C5jXZP?qI5ey|vg>)8goFCmShb8e#QgeH`mM_2K6=m=etw$V*= zbB#f(KXujUPTQ6nne*0sG_#RMavObfnRJhj7PEuoY9gPU`aHBIvW4{yb=Z=pd8~YE zoPuKPR<+*zSX|9GQQwr1C;&(^$gjaNEf{E0i&i*}@> ziMzZ@gl)4Y%(i+lqa|NoacH~AVBcrfYr5XPKSEQIxR>rF(Mh2tdeXG6Pq`z;R?$h{ zfaVYT#u;fn({AN8blWa%HJQ_E(px4pL&~StNSsFWqQg!nSDGkG(3h{}Gx`2d{t`Dn zjUNpA-ay!&$%JB^GHru|I=xl1wDySozt*lD)_o?chvzOJV4(pCicexCX!b8V@#{(y zn|GY|!*SwBkj=x1llT=sk~kFwLQ8|Tph6T|p|6AnZAn3~1qBV#ifS9gRumvnA(r3x zac^!uC)a<8NcWBt`^=1I&YU^#q0G7r{o8g9N4&5Pk1{mRb6c_ick4Pa>LEusW=>nP zj8Pp+^_A?;+GS1IdPr~|vW2R7`u4Z$ZLw4){szd5mF*4U=N9nd2@J~zp`5eqMb*5e z&U$@u?KR|0rxO&wlw=waY&MymD}2sKu`!Pco(Uaf*)hLmuG+pKzbwllryA0>vU`=F zvJ8D88u~|B^XECsd^46L8SLltC6d#h2fEanY3;LGsT8<9@~3Tc8{dR_;{bPm^==Me zi+}Y2Al6v9uU4A6B7xoxiuTOjG=%eh3oKF{$F%0CB~((ruO+0QF~?8q&Z?|1CB6Y6 zZ_%p_uA3FpKVuneOLcOlpP?R1yD@RR^Rd&cqY*52a9N2xamrCp&%1$<=XuDC>IR*zbzLsOXth;+D9G0ti_EYgdM;ghy;Y@4L)`c468w)YheHFY$#QcM?o@B5AWEGw zIRjB5+2RTDw0!UVTSRz~M|&gd%#Veui34gb7t_5?0;VdXk0jS~#7p6TwlE?3L>5PV z-!06JWqITyKK%NB6I{E74u~Er)JNd z!}emWz-j>LJb^w}_g3YISPP#T_?599?oS_&fDpA|7K+SvKXhudlHWBYx@RhL+1)b<68)eB7hs%w*1CIOPRST1RFho5dn>)ucjqpfJ zL)S2YOHS!*L8`aT3RVfwdJw<(ScP?;=!YZeEtJ!t*AoN9F&ebuKnT|_O7*PFAX$XH ze-OSO4}7tHG-!2vz%iMZtEuQbUvg%oOW-_@3sa-ctzE6=4@*1Ec1m4lK(-8H5iHe^ zR}I^zS`M~lea{?lDwAAgDXb5#0+z~xy~8Cc>N?nmu~RmX(_5-@vy;EHwcH)}Dh?b;CbG}Rk3FUWSZq(; zKV*=5rYhpZPmfsju^U+MrYV+=<2Br5pa@y{aLui?u_=B;aFAO)Q>P2hdX#aWz1hKT zC@}jHlaTyup<2`Y9+}G>=e#>C*&;Q7WhG@Mc$R0mkZiv!^5vI>ou~T~ryta>GrvDck%MOf89fSjduB^46_BO)AG^J{9QJ^6;yz)O!=1F+#9E{gIym3|#x;1X=Un{=j znk^Pv@?2d*2^F>U=tz)+*LuqeNcoE&%j3(?%wd$uc z&i#s7J~?c~lIXqImg?)FuAJzeV&fgtM)w7g;31wHhdtc$#^Yj;<9 zt)X~4_Kg(`J!zfhUnq(v<2UW^3L_nRP?y`nt!X&icHtrp4}^~^o+GwAt!|Es2c#qy z*KK#C9j3fHI7w~4U>;zN%v3c|tvWC@zLA-bLw!|qfvZ~{S*<-(dcjUwDFLK9aOD-^ z#ZN>rCmNIrHNF;^t6T9|Z)-OPcxa_h``gdpC1a)_@Pb{rd2BIoodV{H&=L$~y9l-> zw%uglBIDgP{h%Zw)O+19AaX0!t3s%OA~;WRb`sqf0AJ;$~g zoY`mS%3uI~Fl2D%EA22R63yGVrBBiehg})+@tmGfd8pKVZMqx`h4Rs#nau(Y<4Bv? z7nWs0px}C(wvLoD=B`Um<8~ut{B5UW8iP2(koYJU$S^h|FKZeEhiPTZffp|pLf57_ zc$Y2q$vKoTaB0gK2;X~q12Xd==?Sc^UaDWHO5PjpuHsr7_|-0!W%e0(wpV0YO*jbU z32|qh+~c0ydo=)NKq4j@iwB1@#GC@UKFzrQua{MyQWCyg~EFwWaUGFQA|tk@n$#vRof%b#qd99BZ;44ZYJvNQ@kz z(*D6_H@{(=9ycFLp3aahT^+i@9-ND1(cM)yPzhU`GGziK#4NYnbDfPw+l~CO4>lHV z6VhPD!AUF?Do@59Z`8V!Il3J*nVLPYx5FZwx5m@-)y?s2#HM%6WogtLjnA6v!H%_C zI(-V~RfWjGk2jJd_FXvR*DL*V1DeBg6Q}&d$oS|iv3br=4d`Uw69OXe>WCbGJ9_Bb z+xDP%hhDj?a$;X=7RI%1yNlH7Vap?soHA70=0cg7^~q{4t>NJYwEU3MLo&Ru2C1QJ z{UU_#(RR09U1x>hTopSIbv~|v3h5HeoSrW&$@W;> zpGSvyMMUt!#*kQz@Nm#I>n{u1*TMS_o0DA!7hO~AoRSs$;M6XlTe{jJtTp|BJq(qx zCI;n98-G3<>w_EynOLMeO*HPvjJ6^stV~J(Oh^_Egi~V9Ug$&Oml5%w z&1H}FcFeeaan8`uG1qQ?iIo|v2Z7%>!P9^V^ga5Ms*St7F^g&g`21Cl7*43!h9pLt zU3=#AO~lz*PzS8(j?trrt7{DlnK;(&@B5WPWC-6GsgMfh?5Z-y7PmFpQiGWthm;5< zD?CtN_1@00tt;#jtHrCF^S!BZY*tO!U&wa<5vIpfGyUK`^mk6g48k+P(w3z@mhhBc z8Tqs~WD|M7E>=`Z4H#WfF7C|fTq^YobY!nEk4ZiTk3Yo z^GIz@k*yx`l&~xx+oe2&jQ(MGY>O{2N0E4g*IB)3odL4v`H)304#;jN2HLi^P|wbJ zRpvCrhot}s)JrTGcEloFtIN*bZ*Brfhm+zsFAkoE72+ZN&`d?;wh{s;z$qMTsP5dBr{*16XV~E6 z9z-}wgzcxFc=}myd_x0n(3#D%6i-&%_}sXPCX%5PkF|2MqguOSH4k1CqOzlIU@U7p zJ$`x|`C?s#J<|1Nb%ioOeqdNJt@j8XcDYKmsdHVyQEB~(K+A2{>-O>q*8`1$QWI;w zSHZcImX8BcXa1!4K(EarO)W#@BD!Sl*V^QAG)~N=v{=@?w&=hG(ma(d1Mv&QeYo8Y zYM?#t+NWpJPUTcog$g`evh2QTRDx%?m?V{}k|5v^TyNjy_W{)(?!bUR_$S{7q|;e z+z(<*x=8s=VPiu+;i1=mSx!!tR39`5XYpn(CEg5aO$g98MNRCW$)Mr5zGT+p4c}`r z_S>fK;&_JJEb#SR<^$$3qt@ zwr`1Bx)~LQx)5{g)ze5GUDo}{WZS8C7y*)q@&Gp(Cf-E!qhKAqGNNHi{z*9)r@kUN z@E3z3$!XLC&I*(XHR>&?Sx;Q$14IR9>3ggRE?0z#eM0oMQ5>ndyy%WB?wYJ6c>&L= z7PYh$<0uX&qqS;m2Iy}1F4JnTa>}lONE^7{Oo~c%wJs$$9~>f^Ny14(4_?60A~;V8 z#4Ip-6Xr4=6p)lw6E~G<%`5;t!amgm#2o85ow<(i=v@nbXPa_GCPHdtID$_owyH2X zwK3etokn4=sHNtW8*oS##`V2eYkNDR57@CMnjol`Hf|dVYTphGqcF#qY+jt5jtb-I zK?xBL=X!S-n_AP)LQI5Hg2+#N5rlYud!j}UJxrpo(i`e5u<>#`E?30W#F>GbA~5#aMXb}zup+xMS38atz~0xiU;UUqFSE3e`0<5 zU?h`wdQ#I12-(tgV~N9dps?=*B}Mhs!+BC__ID0zwn`FQ=hNsCRx_37FrB;3uBsmp zz05FL(}yXu%2q*^QehG`yk>G9b?C3BB)ZccvGClq3;V>z@TAWy91G#wdM9lXnKZRQ z2HpXY{z%itcBg!Dryd;Ugtl&R2w;FaX1LDm$y%n(3Q}YFM%%eizS?Tmu=X=eDY8F> zm82h!p3c4tFH~gyLNwL5v7!yB*w;Eean~7F_k2cEM@)p%PeYy~RM^~pMgGmgDbJ0mn2=(r{IeN8SZotAC6agt$vQRBOYI#H)cDnb&IK3PfnX(LOB1+A(z+qk0Kl!ZZXN=IWJo&ceF4MF?RW%mo0r9u*m z%Lv*U3cV%_$=L^xO`_K$FMvoUj`a)tGs;uGwqS~8xw}86OU3*P19qF>&Pq8q8Yh{Tn*6oRiov-imEhd| zif@m*b7Ovf>kiK|v2DCNY45a)j{ujG>e-DEJIG(;-i@^VxaJ!f=J7-EW&~+ft2yn3 zHgwy0gsW|a71`4h)@R*pZwG;56lG-q_x|3fRFYmDe@-pBb=@c%x>9fN#-iPZK7B-C zvckD6J4L5BR;f*=RqUzjAtNlS*QDNoI?=fjx7mysd(2JX>$P$!U~NJtnm9-$bT)Uu zF-*-9)eM}8T4+dXia*;UhmYCxzNcLJhQdy%wdHJ1mtt+%w9yE3V{k5sjF0N=}WBeDbE+3d}mPz3i4YUoh+=*lVkQGm|%yBrvdO5H-$h zN_Az5Z)~~+WOeCE^>W9zki=vKH@lcOvpfcQaQ4RoygX``x)$vBdl?SDuNZPuFLG5x zv_(D^PwQ6E^9O^oTXnjl)3kC)g%PMky?3e=`E|YEi<)ieLkN|}t$}<*AMzBSj-d_X zMipEYPaUn;EuD}K#Lic*Cl6r{ML6Y z|IxITVfY|7VEW^;R4xq;;#D~86}dOf#~g>%4lHfJ_wrCt*3FIHb6uf|b(3X(2F1PX z?o3ecWL}~}Ps1$^=h=lg+aMV=_S%5t1nx6NZNawWU3~%)8oF4&e;q^-cgk_9E(8JC zAzs7Rfj3Kv=;X(4WmvV9K%cdkjh{^%#j#Bxfp~a=Z${P&nf^lu&csRmo%?1c<_#G) z{nvydiH~e#3>h}zZ9^ z_6lr6s~%K6Mi}^a$Om~(AA9Gmp6BhB6i}`MyiJ>EC?YwU@a8=*N+lRZ^mQJpqnXM! zs&*0kiIZ&|$9wWvC{DVwX`>`}CZ%l=8WBcZsaO?RXaUjM5Y6trXJi)Gc!Pq+fHX$f z+slF<>muA46=Ti%3pd$H4m-}K2f?OyXtoD9-RR7AMe31`j7yZ+#dATR534e>Dzy&5 zaRdWoZG>3R*8zRJab~1%>DxO4C&WDA8>TaMxH=BI60bOwR*!+$;Xz^#SH{t4k1Cd$ zw@Oy=*!7yQ5v)BE1md-KH+zPVkN1pO$5jy*q3qjzy4#axJmjjQjR2Ie&XU&Yz%^EJ z+q+Jups3Q)la*~q+*X$b@%#@%{ok+t5Yk838_)K}{b9B1mWncD2Hfom>Lb_gG;mH7hhG%`I`r<9*!J+5#++vB;LcJ*3260=SS{U!n zD`r5$T5sjMOc`+xV?+ej;GVwa&x}-9m`m;is+Xe_Hy84B~B_`~Ud-4l4N>{QYcP*_ZJ} zQvU8;BjnlJ&+p;O*YKCX|6_cSl;6C47}r04_npJ{Tlk;E@Jac_-ShYG72N;tpZ?TJ z+W-2`MF2@D#PGimmtT*|r0C+}SMZm>e>;Xx%1iwH7x4^v_XPg8aZNrl{>UQ<{13>3 z_$1}u-3{2?*W4fD*`MC@e;+rHl+CcVTrTN<(oRwyaQ}aA;C~RqCuKi|zwdwibMA@@ zGNws=U;m}(PE!6j?r_rn{rmrE3}1@CazFXy=prfYxMBkTTll+&{|o#^nuv!jm-`03 zkWX9^{Jj0#&;Os}<}LgeF|K&D% zJ}G}Sc`z>D*OtqDKZZ}nKWE2J#O2@Y-&gR(`>(k#@8G}u*SP(-{A)7kH=q0V{~q_q z5GCz5{xf*AzVk;>dH;O!Jt_YQu)lr-uf_0M zM))5Amh?Yq-;Uw!7=DU-x1am@`#0PqxR=2HFoyqO4F8RIU=sXH`kmDCAAr4W|3_Bz z-and0hAXh{x|P_Ping@6WqIf^t*BU(?5%TCHv6t12vOz uOXx2lS4rP*;eY(^(fe1vfBS3H*V|vna!-T*=69nR|3=c$80hY6?*9NLkB?RW diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 6f38583d8..5cb56f4e4 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1247,9 +1247,13 @@ else: # Descriptor is still present in the queue. case event of Event.Read: - fdData.readList = newList & fdData.readList + let oldReadList = move fdData.readList + fdData.readList = move newList + fdData.readList.add oldReadList of Event.Write: - fdData.writeList = newList & fdData.writeList + let oldWriteList = move fdData.writeList + fdData.writeList = move newList + fdData.writeList.add oldWriteList else: assert false, "Cannot process callbacks for " & $event diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index baf238843..4b123117a 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -310,6 +310,10 @@ proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = result = 0 while start+result < s.len and s[result+start] in toSkip: inc(result) +proc fastSubstr(s: string; token: var string; start, length: int) = + token.setLen length + for i in 0 ..< length: token[i] = s[i+start] + proc parseUntil*(s: string, token: var string, until: set[char], start = 0): int {.inline.} = ## Parses a token and stores it in ``token``. Returns @@ -326,7 +330,8 @@ proc parseUntil*(s: string, token: var string, until: set[char], var i = start while i < s.len and s[i] notin until: inc(i) result = i-start - token = substr(s, start, i-1) + fastSubstr(s, token, start, result) + #token = substr(s, start, i-1) proc parseUntil*(s: string, token: var string, until: char, start = 0): int {.inline.} = @@ -344,7 +349,8 @@ proc parseUntil*(s: string, token: var string, until: char, var i = start while i < s.len and s[i] != until: inc(i) result = i-start - token = substr(s, start, i-1) + fastSubstr(s, token, start, result) + #token = substr(s, start, i-1) proc parseUntil*(s: string, token: var string, until: string, start = 0): int {.inline.} = @@ -370,7 +376,8 @@ proc parseUntil*(s: string, token: var string, until: string, if u >= until.len: break inc(i) result = i-start - token = substr(s, start, i-1) + fastSubstr(s, token, start, result) + #token = substr(s, start, i-1) proc parseWhile*(s: string, token: var string, validChars: set[char], start = 0): int {.inline.} = @@ -386,7 +393,8 @@ proc parseWhile*(s: string, token: var string, validChars: set[char], var i = start while i < s.len and s[i] in validChars: inc(i) result = i-start - token = substr(s, start, i-1) + fastSubstr(s, token, start, result) + #token = substr(s, start, i-1) proc captureBetween*(s: string, first: char, second = '\0', start = 0): string = ## Finds the first occurrence of ``first``, then returns everything from there diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 3cbd02806..973b951d4 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -68,7 +68,7 @@ const when defined(nimArcDebug): include cellsets - const traceId = 7739 # 1037 + const traceId = 20 # 1037 var gRefId: int var freedCells: CellSet @@ -90,6 +90,9 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = when defined(nimArcDebug) or defined(nimArcIds): head(result).refId = gRefId atomicInc gRefId + if head(result).refId == traceId: + writeStackTrace() + cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).rc shr rcShift) when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) @@ -112,6 +115,10 @@ proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = when defined(nimArcDebug): head(result).refId = gRefId atomicInc gRefId + if head(result).refId == traceId: + writeStackTrace() + cfprintf(cstderr, "[nimNewObjUninit] %p %ld\n", result, head(result).rc shr rcShift) + when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 5deed1d14..ac6211ebb 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -26,6 +26,8 @@ const jumpStackFlag = 0b1000 colorMask = 0b011 + logOrc = defined(nimArcIds) + type TraceProc = proc (p, env: pointer) {.nimcall, benign.} DisposeProc = proc (p: pointer) {.nimcall, benign.} @@ -59,19 +61,17 @@ proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = var p = s +! sizeof(RefHeader) cast[TraceProc](desc.traceImpl)(p, addr(j)) -when true: - template debug(str: cstring; s: Cell) = discard -else: - proc debug(str: cstring; s: Cell) = - let p = s +! sizeof(RefHeader) - cprintf("[%s] name %s RC %ld\n", str, p, s.rc shr rcShift) +when logOrc: + proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) = + cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld\n", + msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color) proc free(s: Cell; desc: PNimTypeV2) {.inline.} = when traceCollector: cprintf("[From ] %p rc %ld color %ld\n", s, s.rc shr rcShift, s.color) let p = s +! sizeof(RefHeader) - debug("free", s) + when logOrc: writeCell("free", s, desc) if desc.disposeImpl != nil: cast[DisposeProc](desc.disposeImpl)(p) @@ -90,13 +90,13 @@ proc free(s: Cell; desc: PNimTypeV2) {.inline.} = nimRawDispose(p) -proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} = +proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inline.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) j.traceStack.add(head p[], desc) -proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} = +proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inline.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) @@ -121,11 +121,6 @@ proc unregisterCycle(s: Cell) = roots.d[idx][0].rootIdx = idx dec roots.len -when false: - proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) = - cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld\n", - msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color) - proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ proc scanBlack(s: Cell) = @@ -135,19 +130,17 @@ proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = if t.color != colBlack: scanBlack(t) ]# - debug "scanBlack", s s.setColor colBlack let until = j.traceStack.len trace(s, desc, j) - #writeCell("root still alive", s, desc) + when logOrc: writeCell("root still alive", s, desc) while j.traceStack.len > until: let (t, desc) = j.traceStack.pop() inc t.rc, rcIncrement - debug "incRef", t if t.color != colBlack: t.setColor colBlack trace(t, desc, j) - #writeCell("child still alive", t, desc) + when logOrc: writeCell("child still alive", t, desc) proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ @@ -278,8 +271,11 @@ proc collectCyclesBacon(j: var GcEnv) = s.buffered = false collectWhite(s) ]# + when logOrc: + for i in 0 ..< roots.len: + writeCell("root", roots.d[i][0], roots.d[i][1]) + for i in 0 ..< roots.len: - #writeCell("root", roots.d[i][0], roots.d[i][1]) markGray(roots.d[i][0], roots.d[i][1], j) for i in 0 ..< roots.len: scan(roots.d[i][0], roots.d[i][1], j) @@ -305,7 +301,7 @@ var proc collectCycles() = ## Collect cycles. - when false: + when logOrc: cfprintf(cstderr, "[collectCycles] begin\n") var j: GcEnv @@ -335,7 +331,7 @@ proc collectCycles() = #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) elif rootsThreshold < high(int) div 4: rootsThreshold = rootsThreshold * 3 div 2 - when false: + when logOrc: cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld\n", j.freed, rootsThreshold, j.touched, getOccupiedMem()) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 85c0af190..57fdd5ee1 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -52,7 +52,8 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap))) s.p.cap = newCap -proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} = +proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inline.} = + #if (s.p == nil) or (s.len+1 > s.p.cap and not strlitFlag): prepareAdd(s, 1) s.p.data[s.len] = c s.p.data[s.len+1] = '\0' From cbdda631dbd68765203d1843f217f47c6e0c5c48 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Sep 2020 00:05:41 +0200 Subject: [PATCH 1117/4254] base64: fixes the error message for an invalid base64 input character [backport:1.2] --- lib/pure/base64.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 9495c4d56..40c9af905 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -230,11 +230,11 @@ proc decode*(s: string): string = template inputChar(x: untyped) = let x = int decodeTable[ord(s[inputIndex])] - inc inputIndex if x == invalidChar: raise newException(ValueError, "Invalid base64 format character `" & s[inputIndex] & "` (ord " & $s[inputIndex].ord & ") at location " & $inputIndex & ".") + inc inputIndex template outputChar(x: untyped) = result[outputIndex] = char(x and 255) From a15d77df7e324f6cda831bf44ced7a5a8bd93ef4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Sep 2020 00:27:32 +0200 Subject: [PATCH 1118/4254] ORC/ARC async progress (#15370) * ARC/ORC: fixes memory leak for empty seqs that have a non-zero capacity * async: minor refactorings * it helps to finish a refactoring --- compiler/ccgexprs.nim | 2 +- lib/pure/asyncdispatch.nim | 15 +++++++-------- lib/pure/ioselects/ioselectors_kqueue.nim | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 0d235f62e..83f7f7278 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2164,7 +2164,7 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = # generated by liftdestructors: var src: TLoc initLocExpr(p, n[2], src) - linefmt(p, cpsStmts, "if ($1.len && $1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) + linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) genStmts(p, n[3]) linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)]) else: diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5cb56f4e4..d8b274c34 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1198,6 +1198,11 @@ else: let p = getGlobalDispatcher() not p.selector.isEmpty() or p.timers.len != 0 or p.callbacks.len != 0 + proc prependSeq(dest: var seq[Callback]; src: sink seq[Callback]) = + let old = move dest + dest = src + dest.add old + proc processBasicCallbacks( fd: AsyncFD, event: Event ): tuple[readCbListCount, writeCbListCount: int] = @@ -1246,14 +1251,8 @@ else: withData(selector, fd.int, fdData) do: # Descriptor is still present in the queue. case event - of Event.Read: - let oldReadList = move fdData.readList - fdData.readList = move newList - fdData.readList.add oldReadList - of Event.Write: - let oldWriteList = move fdData.writeList - fdData.writeList = move newList - fdData.writeList.add oldWriteList + of Event.Read: prependSeq(fdData.readList, newList) + of Event.Write: prependSeq(fdData.writeList, newList) else: assert false, "Cannot process callbacks for " & $event diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 7635a04d5..a65be9842 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -616,7 +616,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.getData(fdi)) + var value = addr(s.fds[fdi].data) body template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, @@ -625,7 +625,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, let fdi = int(fd) s.checkFd(fdi) if fdi in s: - var value = addr(s.getData(fdi)) + var value = addr(s.fds[fdi].data) body1 else: body2 From ebb632ccba0d786b90684e4da2b393cfae04a24c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Sep 2020 01:07:13 +0200 Subject: [PATCH 1119/4254] fixes #15369 (#15371) --- lib/pure/cgi.nim | 6 +++--- tests/stdlib/tcgi.nim | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index 734ab9171..1f0e0736a 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -105,10 +105,10 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] = while i < data.len: setLen(name, 0) # reuse memory i = parseData(data, i, name) - if i >= data.len or data[i] != '=': cgiError("'=' expected") - inc(i) # skip '=' setLen(value, 0) # reuse memory - i = parseData(data, i, value) + if i < data.len and data[i] == '=': + inc(i) # skip '=' + i = parseData(data, i, value) yield (name.TaintedString, value.TaintedString) if i < data.len: if data[i] == '&': inc(i) diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index 7df1b077d..222a3bf6d 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,6 +1,14 @@ discard """ output: ''' [Suite] Test cgi module +(key: "a", value: "1") +(key: "b", value: "0") +(key: "c", value: "3") +(key: "d", value: "") +(key: "e", value: "") +(key: "a", value: "5") +(key: "a", value: "t e x t") +(key: "e", value: "http://w3schools.com/my test.asp?name=ståle&car=saab") ''' """ @@ -21,3 +29,9 @@ suite "Test cgi module": expect KeyError: discard parsedQuery["not_existing_key"] + +# bug #15369 +let queryString = "a=1&b=0&c=3&d&e&a=5&a=t%20e%20x%20t&e=http%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab" + +for pair in decodeData(queryString): + echo pair From 33be7c6f5ef1a9e54d037682984f563c8ee11fcb Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 20 Sep 2020 09:01:42 +0200 Subject: [PATCH 1120/4254] arc: =deepcopy fixes --- compiler/varpartitions.nim | 1 - lib/system/deepcopy.nim | 19 ++++++++--- tests/arc/tdeepcopy.nim | 67 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 tests/arc/tdeepcopy.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 743c4d55d..f983f9416 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -459,7 +459,6 @@ proc traverse(c: var Partitions; n: PNode) = if paramType.kind == tyVar: if c.inNoSideEffectSection == 0: for r in roots: potentialMutation(c, r, it.info) - else: for r in roots: noCursor(c, r) of nkAddr, nkHiddenAddr: diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 5905b5785..b9dc594fa 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -140,7 +140,10 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = unsureAsgnRef(cast[PPointer](dest), s2) elif mt.base.deepcopy != nil: let z = mt.base.deepcopy(s2) - unsureAsgnRef(cast[PPointer](dest), z) + when defined(nimSeqsV2): + cast[PPointer](dest)[] = z + else: + unsureAsgnRef(cast[PPointer](dest), z) else: let z = tab.get(s2) if z == nil: @@ -157,10 +160,16 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = let x = usrToCell(s2) let realType = x.typ sysAssert realType == mt, " types do differ" - # this version should work for any possible GC: - let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base - let z = when defined(nimSeqsV2): nimNewObj(typ.size) else: newObj(mt, typ.size) - unsureAsgnRef(cast[PPointer](dest), z) + when defined(nimSeqsV2): + let typ = if mt.base.kind == tyObject: cast[PNimType](cast[ptr PNimTypeV2](s2)[].typeInfoV1) + else: mt.base + let z = nimNewObj(typ.size) + cast[PPointer](dest)[] = z + else: + # this version should work for any other GC: + let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base + let z = newObj(mt, typ.size) + unsureAsgnRef(cast[PPointer](dest), z) tab.put(s2, z) genericDeepCopyAux(z, s2, typ, tab) else: diff --git a/tests/arc/tdeepcopy.nim b/tests/arc/tdeepcopy.nim new file mode 100644 index 000000000..0eaf7ea40 --- /dev/null +++ b/tests/arc/tdeepcopy.nim @@ -0,0 +1,67 @@ +discard """ + cmd: "nim c --gc:arc $file" + output: '''13 abc +13 abc +13 abc +13 abc +13 abc +13 abc +13 abc +13 abc +13 abc +13 abc +13 abc +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +called deepCopy for int +0''' +""" + +type + PBinaryTree = ref object of RootObj + le, ri: PBinaryTree + value: int + +proc mainB = + var x: PBinaryTree + deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13)))) + + var y: string + deepCopy y, "abc" + echo x.ri.le.value, " ", y + +for i in 0..10: + mainB() + + +type + Bar[T] = object + x: T + +proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] = + result.new + result.x = b.x + when T is int: + echo "called deepCopy for int" + else: + echo "called deepCopy for something else" + +proc main = + var dummy, c: ref Bar[int] + new(dummy) + dummy.x = 44 + + deepCopy c, dummy + +for i in 0..10: + main() + +echo getOccupiedMem() From cdac67376c599c39e748401e8c0a82ab51a87326 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 20 Sep 2020 09:10:40 +0200 Subject: [PATCH 1121/4254] arc: added tmarshal.nim test case --- tests/arc/tmarshal.nim | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 tests/arc/tmarshal.nim diff --git a/tests/arc/tmarshal.nim b/tests/arc/tmarshal.nim new file mode 100644 index 000000000..f7ec6e2c5 --- /dev/null +++ b/tests/arc/tmarshal.nim @@ -0,0 +1,140 @@ +discard """ + cmd: "nim c --gc:orc $file" + output: ''' +{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"} +true +true +alpha 100 +omega 200 +0''' +""" + +import marshal + +template testit(x) = discard $$to[typeof(x)]($$x) + +var x: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] + +proc blockA = + testit(x) + var test2: tuple[name: string, s: int] = ("tuple test", 56) + testit(test2) + +blockA() + +type + TE = enum + blah, blah2 + + TestObj = object + test, asd: int + case test2: TE + of blah: + help: string + else: + discard + + PNode = ref TNode + TNode = object + next, prev: PNode + data: string + +proc buildList(): PNode = + new(result) + new(result.next) + new(result.prev) + result.data = "middle" + result.next.data = "next" + result.prev.data = "prev" + result.next.next = result.prev + result.next.prev = result + result.prev.next = result + result.prev.prev = result.next + +proc blockB = + var test3: TestObj + test3.test = 42 + test3.test2 = blah + testit(test3) + + var test4: ref tuple[a, b: string] + new(test4) + test4.a = "ref string test: A" + test4.b = "ref string test: B" + testit(test4) + + var test5 = @[(0,1),(2,3),(4,5)] + testit(test5) + + var test7 = buildList() + testit(test7) + + var test6: set[char] = {'A'..'Z', '_'} + testit(test6) + +blockB() + +# bug #1352 + +type + Entity = object of RootObj + name: string + + Person = object of Entity + age: int + bio: string + blob: string + +proc blockC = + var instance1 = Person(name: "Cletus", age: 12, + bio: "Я Cletus", + blob: "ABC\x80") + echo($$instance1) + echo(to[Person]($$instance1).bio == instance1.bio) # true + echo(to[Person]($$instance1).blob == instance1.blob) # true + +blockC() + +# bug 5757 + +type + Something = object + x: string + y: int + +proc blockD = + var data1 = """{"x": "alpha", "y": 100}""" + var data2 = """{"x": "omega", "y": 200}""" + + var r = to[Something](data1) + + echo r.x, " ", r.y + + r = to[Something](data2) + + echo r.x, " ", r.y + +blockD() + +type + Foo = object + a1: string + a2: string + a3: seq[string] + a4: seq[int] + a5: seq[int] + a6: seq[int] + +proc blockE = + var foo = Foo(a2: "", a4: @[], a6: @[1]) + foo.a6.setLen 0 + doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" + testit(foo) + +blockE() + +GC_fullCollect() +echo getOccupiedMem() From 04cecdf9c28c1f1d526d209c582afe7daa7fe654 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Sep 2020 18:01:07 +0200 Subject: [PATCH 1122/4254] async: removed the 'unown' references, async never worked with --newruntime anyway and --newruntime is dead (#15374) --- lib/pure/asyncmacro.nim | 11 +++++------ lib/system/orc.nim | 7 ++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 219ef6c67..65cf2f3b9 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -14,21 +14,20 @@ import macros, strutils, asyncfutures template createCb(retFutureSym, iteratorNameSym, strName, identName, futureVarCompletions: untyped) = bind finished - let retFutUnown = unown retFutureSym var nameIterVar = iteratorNameSym proc identName {.closure.} = try: if not nameIterVar.finished: - var next = unown nameIterVar() + var next = nameIterVar() # Continue while the yielded future is already finished. while (not next.isNil) and next.finished: - next = unown nameIterVar() + next = nameIterVar() if nameIterVar.finished: break if next == nil: - if not retFutUnown.finished: + if not retFutureSym.finished: let msg = "Async procedure ($1) yielded `nil`, are you await'ing a " & "`nil` Future?" raise newException(AssertionDefect, msg % strName) @@ -39,12 +38,12 @@ template createCb(retFutureSym, iteratorNameSym, {.pop.} except: futureVarCompletions - if retFutUnown.finished: + if retFutureSym.finished: # Take a look at tasyncexceptions for the bug which this fixes. # That test explains it better than I can here. raise else: - retFutUnown.fail(getCurrentException()) + retFutureSym.fail(getCurrentException()) identName() proc createFutureVarCompletions(futureVarIdents: seq[NimNode], diff --git a/lib/system/orc.nim b/lib/system/orc.nim index ac6211ebb..cf8d6379a 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -103,9 +103,10 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inline.} = j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[]) template orcAssert(cond, msg) = - if not cond: - cfprintf(cstderr, "[Bug!] %s\n", msg) - quit 1 + when logOrc: + if not cond: + cfprintf(cstderr, "[Bug!] %s\n", msg) + quit 1 var roots {.threadvar.}: CellSeq From 4d75059e8b16c64a9765da6489af7c3d697c81b5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Sep 2020 22:47:48 +0200 Subject: [PATCH 1123/4254] added a basic ORC test I still had lying around (#15376) --- tests/arc/torc_basic_test.nim | 138 ++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 tests/arc/torc_basic_test.nim diff --git a/tests/arc/torc_basic_test.nim b/tests/arc/torc_basic_test.nim new file mode 100644 index 000000000..73039fad7 --- /dev/null +++ b/tests/arc/torc_basic_test.nim @@ -0,0 +1,138 @@ +discard """ + output: "MEM 0" + cmd: "nim c --gc:orc $file" +""" + +type + Node = ref object + name: char + sccId: int + #a: array[3, Node] + a0, a1, a2: Node + rc: int + +proc edge(a, b: Node) = + inc b.rc + if a.a0 == nil: a.a0 = b + elif a.a1 == nil: a.a1 = b + else: a.a2 = b + when false: + var i = 0 + while a.a[i] != nil: inc i + a.a[i] = b + +proc createNode(name: char): Node = + new result + result.name = name + +#[ + + +--------------------------------+ + v | ++---------+ +------+ | +| | | | | +| A +----->+ | +------+------+ ++--+------+ | | | | + | | | | C ------------> G <--| + | | R | | | ++--v------+ | | +-------------+ +| | | | ^ +| B <------+ | | +| | | +--------+ ++---------+ | | + +------+ + +]# +proc use(x: Node) = discard + +proc main = + let a = createNode('A') + let b = createNode('B') + let r = createNode('R') + let c = createNode('C') + + a.edge b + a.edge r + + r.edge b + r.edge c + + let g = createNode('G') + g.edge g + g.edge g + + c.edge g + c.edge a + + use g + use b + +proc buildComplexGraph: Node = + # see https://en.wikipedia.org/wiki/Strongly_connected_component for the + # graph: + let a = createNode('a') + let b = createNode('b') + let c = createNode('c') + let d = createNode('d') + let e = createNode('e') + + a.edge c + c.edge b + c.edge e + b.edge a + d.edge c + e.edge d + + + let f = createNode('f') + b.edge f + e.edge f + + let g = createNode('g') + let h = createNode('h') + let i = createNode('i') + + f.edge g + f.edge i + g.edge h + h.edge i + i.edge g + + let j = createNode('j') + + h.edge j + i.edge j + + let k = createNode('k') + let l = createNode('l') + + f.edge k + k.edge l + l.edge k + k.edge j + + let m = createNode('m') + let n = createNode('n') + let p = createNode('p') + let q = createNode('q') + + m.edge n + n.edge p + n.edge q + q.edge p + p.edge m + + q.edge k + + d.edge m + e.edge n + + result = a + +proc main2 = + let g = buildComplexGraph() + +main() +main2() +GC_fullCollect() +echo "MEM ", getOccupiedMem() From 0a1e4cad7fc6149d168ecaa06bd613b64fc704fb Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 21 Sep 2020 18:21:05 +0800 Subject: [PATCH 1124/4254] add testcase for #9710 (#15365) * string is not nil anymore * tatus --- tests/stdlib/t9710.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/stdlib/t9710.nim diff --git a/tests/stdlib/t9710.nim b/tests/stdlib/t9710.nim new file mode 100644 index 000000000..f3ed860df --- /dev/null +++ b/tests/stdlib/t9710.nim @@ -0,0 +1,11 @@ +discard """ + cmd: "nim c -r --debugger:native --panics:on $options $file" + targets: "c" + nimout: "" + action: "run" + exitcode: 0 + timeout: 60.0 +""" + +for i in 1 || 200: + discard i From c2434d939e193c066fad1eaefcba486dc0af6087 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 21 Sep 2020 12:35:23 +0200 Subject: [PATCH 1125/4254] fixes #15360 [backport:1.2] (#15378) --- compiler/semstmts.nim | 2 +- tests/iter/titer.nim | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 14f08b4b3..e99ce8937 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -718,7 +718,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n let iterBase = n[^2].typ var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink, tyOwned}) - var iterAfterVarLent = iter.skipTypes({tyLent, tyVar}) + var iterAfterVarLent = iter.skipTypes({tyGenericInst, tyAlias, tyLent, tyVar}) # n.len == 3 means that there is one for loop variable # and thus no tuple unpacking: if iterAfterVarLent.kind != tyTuple or n.len == 3: diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim index 22be1bad5..8e1c13e82 100644 --- a/tests/iter/titer.nim +++ b/tests/iter/titer.nim @@ -55,3 +55,10 @@ const for i in 0..len(stringArray)-1: echo(stringArray[i]) +# bug #15360 + +type Rule[T] = (int, T) + +var t: seq[Rule[int]] +for (c, t) in t: + discard From db9ab2a4c00bc650a8526115d659b57dcd38c39b Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 21 Sep 2020 07:37:14 -0300 Subject: [PATCH 1126/4254] Documentation prelude (#15377) --- doc/prelude.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 doc/prelude.rst diff --git a/doc/prelude.rst b/doc/prelude.rst new file mode 100644 index 000000000..47fa70b70 --- /dev/null +++ b/doc/prelude.rst @@ -0,0 +1,29 @@ +Prelude +======= + +This is an include file that simply imports common modules for your convenience: + +.. code-block:: nim + include prelude + +Same as: + +.. code-block:: nim + import os, strutils, times, parseutils, parseopt, hashes, tables, sets + + +Examples +======== + +Get the basic most common imports ready to start coding using ``prelude``: + +.. code-block:: nim + include prelude + + echo now() + echo getCurrentDir() + echo "Hello $1".format("World") + + +See also: +- `Sugar `_ From 6c83eb48c2686818a0527a64576e27f0dbb87560 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 21 Sep 2020 19:32:05 +0800 Subject: [PATCH 1127/4254] add testcase for #7165 (#15368) * add testcase for #7165 * Remove overspecific testament spec Co-authored-by: Clyybber --- tests/distinct/t7165.nim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/distinct/t7165.nim diff --git a/tests/distinct/t7165.nim b/tests/distinct/t7165.nim new file mode 100644 index 000000000..b16c29c0e --- /dev/null +++ b/tests/distinct/t7165.nim @@ -0,0 +1,15 @@ + +type + Table[K, V] = object + key: K + val: V + + MyTable = distinct Table[string, int] + MyTableRef = ref MyTable + +proc newTable[K, V](): ref Table[K, V] = discard + +proc newMyTable: MyTableRef = + MyTableRef(newTable[string, int]()) # <--- error here + +discard newMyTable() From 40a868bccc6934aba99a9e490dad04296533b00f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 21 Sep 2020 19:37:14 +0800 Subject: [PATCH 1128/4254] add testcase for #6060 (#15366) * add testcase for #6060 * Remove overspecific testament spec Co-authored-by: Clyybber --- tests/generics/t6060.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/generics/t6060.nim diff --git a/tests/generics/t6060.nim b/tests/generics/t6060.nim new file mode 100644 index 000000000..6b1856f1c --- /dev/null +++ b/tests/generics/t6060.nim @@ -0,0 +1,11 @@ +import tables + +type MyTab[A,B] = distinct TableRef[A,B] + +proc `$`[A,B](t: MyTab[A,B]): string = + "My special table " & $TableRef[A,B](t) + +proc create[A,B](): MyTab[A,B] = MyTab(newTable[A,B]()) + +var a = create[int,int]() +doAssert $a == "My special table {:}" From 464518327211ea3a693e9ae5e9b03c739d410ac4 Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 21 Sep 2020 17:01:12 +0200 Subject: [PATCH 1129/4254] fix #6430, support `:target:` for images (#15379) --- lib/packages/docutils/rstgen.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 2ec25cc6e..9f707f4e8 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -848,6 +848,18 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = """ else: htmlOut = "" + + # support for `:target:` links for images: + var target = esc(d.target, getFieldValue(n, "target").strip()) + if target.len > 0: + # `htmlOut` needs to be of the following format for link to work for images: + # + var htmlOutWithLink = "" + dispA(d.target, htmlOutWithLink, + "$1", + "\\href{$2}{$1}", [htmlOut, target]) + htmlOut = htmlOutWithLink + dispA(d.target, result, htmlOut, "\\includegraphics$2{$1}", [esc(d.target, arg), options]) if len(n) >= 3: renderRstToOut(d, n.sons[2], result) From 8f511fd0e68d1f75f418a5ed69663b8a41e29ae2 Mon Sep 17 00:00:00 2001 From: genotrance Date: Mon, 21 Sep 2020 11:48:00 -0500 Subject: [PATCH 1130/4254] Bump nimble (#15380) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 90c1296fa..966ff932e 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "27d1063febe3055252103cacb11787ac83893416" # master + NimbleStableCommit = "f4c818a046c2c3ceb1523c4c974e4b6e625d8ca3" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From aca9c5fb30fe2de12671e9103e93b81201bb8e71 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 21 Sep 2020 17:52:44 +0000 Subject: [PATCH 1131/4254] os: make getApplFreebsd available for NetBSD (#15381) NetBSD was switched to getApplFreebsd() in #15359, however the proc was not made available for the said target. This commit exposes `getApplFreebsd()` to NetBSD. --- lib/pure/os.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 45f022379..5efbde268 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2814,7 +2814,7 @@ else: "commandLineParams() unsupported by dynamic libraries".} = discard -when not weirdTarget and (defined(freebsd) or defined(dragonfly)): +when not weirdTarget and (defined(freebsd) or defined(dragonfly) or defined(netbsd)): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include From d67c5cb75171fcbf1ca9078452e8fcbe36fc79bc Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 22 Sep 2020 10:43:12 +0200 Subject: [PATCH 1132/4254] Add strutils.indentation and make unindent use it (#15264) * Add strutils.indentation and make unindent use it * Code style * Fix bootstrapping * Improve wording * Fix test * Introduce without breaking change * Fix * Reduce diff * Fix docs link * Add since annotation * Update changelog --- changelog.md | 9 ++++++++ lib/pure/strutils.nim | 47 ++++++++++++++++++++++++++++++--------- tests/stdlib/tstrutil.nim | 22 ++++++++++++++++++ 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index e7afaa229..1bc1d7303 100644 --- a/changelog.md +++ b/changelog.md @@ -187,6 +187,15 @@ - Add missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. +- Added `strutils.indentation` and `strutils.dedent` which enable indented string literals: + ```nim + import strutils + echo dedent """ + This + is + cool! + """ + ``` ## Language changes diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 156929dee..d97ed9a07 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -82,6 +82,7 @@ when defined(nimVmExportFixed): export toLower, toUpper include "system/inclrtl" +import std/private/since const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} @@ -1511,6 +1512,7 @@ proc indent*(s: string, count: Natural, padding: string = " "): string ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ ## * `spaces proc<#spaces,Natural>`_ ## * `unindent proc<#unindent,string,Natural,string>`_ + ## * `dedent proc<#dedent,string,Natural,string>`_ runnableExamples: doAssert indent("First line\c\l and second line.", 2) == " First line\l and second line." @@ -1524,21 +1526,25 @@ proc indent*(s: string, count: Natural, padding: string = " "): string result.add(line) i.inc -proc unindent*(s: string, count: Natural, padding: string = " "): string +proc unindent*(s: string, count: Natural = int.high, padding: string = " "): string {.noSideEffect, rtl, extern: "nsuUnindent".} = ## Unindents each line in ``s`` by ``count`` amount of ``padding``. - ## Sometimes called `dedent`:idx: ## ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: + ## * `dedent proc<#dedent,string,Natural,string>` ## * `align proc<#align,string,Natural,char>`_ ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ ## * `spaces proc<#spaces,Natural>`_ ## * `indent proc<#indent,string,Natural,string>`_ runnableExamples: - doAssert unindent(" First line\l and second line", 3) == - "First line\land second line" + let x = """ + Hello + There + """.unindent() + + doAssert x == "Hello\nThere\n" result = "" var i = 0 for line in s.splitLines(): @@ -1553,11 +1559,30 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string result.add(line[indentCount*padding.len .. ^1]) i.inc -proc unindent*(s: string): string - {.noSideEffect, rtl, extern: "nsuUnindentAll".} = - ## Removes all indentation composed of whitespace from each line in ``s``. +proc indentation*(s: string): Natural {.since: (1, 3).} = + ## Returns the amount of indentation all lines of ``s`` have in common, + ## ignoring lines that consist only of whitespace. + result = int.high + for line in s.splitLines: + for i, c in line: + if i >= result: break + elif c != ' ': + result = i + break + if result == int.high: + result = 0 + +proc dedent*(s: string, count: Natural = indentation(s)): string + {.noSideEffect, rtl, extern: "nsuDedent", since: (1, 3).} = + ## Unindents each line in ``s`` by ``count`` amount of ``padding``. + ## The only difference between this and `unindent proc<#unindent,string,Natural,string>` + ## is that this by default only cuts off the amount of indentation that all + ## lines of ``s`` share as opposed to all indentation. It only supports spcaes as padding. + ## + ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: + ## * `unindent proc<#unindent,string,Natural,string>` ## * `align proc<#align,string,Natural,char>`_ ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ ## * `spaces proc<#spaces,Natural>`_ @@ -1565,11 +1590,11 @@ proc unindent*(s: string): string runnableExamples: let x = """ Hello - There - """.unindent() + There + """.dedent() - doAssert x == "Hello\nThere\n" - unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish. + doAssert x == "Hello\n There\n" + unindent(s, count, " ") proc delete*(s: var string, first, last: int) {.noSideEffect, rtl, extern: "nsuDelete".} = diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index ef5b041be..162b8ea1b 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -435,3 +435,25 @@ block: doAssert a == f1 doAssert b == f2 doAssert c == f3 + +block: + assert 0 == indentation """ +hey + low + there +""" + assert 2 == indentation """ + hey + low + there +""" + assert 2 == indentation """ hey + low + there +""" + assert 2 == indentation """ hey + low + there""" + assert 0 == indentation "" + assert 0 == indentation " \n \n" + assert 0 == indentation " " From 1fae66e4df8cc43b4ec8ab97fff96282ef234f2e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 22 Sep 2020 13:03:24 +0200 Subject: [PATCH 1133/4254] better nativestacktrace support; refs #15284; backport [1.2] (#15384) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nimStackTraceOverride: enable stack traces in exceptions This is a two-step stack trace collection scheme, because re-raised exceptions will collect multiple stack traces but use them rarely, when printing info about an uncaught exception, so it makes sense to only do the cheap stack unwinding all the time and the relatively expensive debugging information collection on-demand. `asyncfutures` implements its own `$` proc for printing `seq[StackTraceEntry]`, so we have to add the debugging info there, just like we do for the private `$` proc in `system/excpt`. * cleaned up PR #15284 Co-authored-by: Ștefan Talpalaru --- lib/pure/asyncfutures.nim | 13 +++- lib/system.nim | 6 ++ lib/system/exceptions.nim | 5 ++ lib/system/excpt.nim | 45 ++++++------ lib/system/stacktraces.nim | 83 +++++++++++++++++++++++ tests/system/tnim_stacktrace_override.nim | 18 +++++ 6 files changed, 142 insertions(+), 28 deletions(-) create mode 100644 lib/system/stacktraces.nim create mode 100644 tests/system/tnim_stacktrace_override.nim diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 97abf72c9..2333c5ef1 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -9,6 +9,8 @@ import os, tables, strutils, times, heapqueue, options, deques, cstrutils +import "system/stacktraces" + # TODO: This shouldn't need to be included, but should ideally be exported. type CallbackFunc = proc () {.closure, gcsafe.} @@ -293,7 +295,12 @@ proc getHint(entry: StackTraceEntry): string = if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0: return "Resumes an async procedure" -proc `$`*(entries: seq[StackTraceEntry]): string = +proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string = + when defined(nimStackTraceOverride): + let entries = addDebuggingInfo(stackTraceEntries) + else: + let entries = stackTraceEntries + result = "" # Find longest filename & line number combo for alignment purposes. var longestLeft = 0 @@ -308,10 +315,10 @@ proc `$`*(entries: seq[StackTraceEntry]): string = # Format the entries. for entry in entries: if entry.procname.isNil: - if entry.line == -10: + if entry.line == reraisedFromBegin: result.add(spaces(indent) & "#[\n") indent.inc(2) - else: + elif entry.line == reraisedFromEnd: indent.dec(2) result.add(spaces(indent) & "]#\n") continue diff --git a/lib/system.nim b/lib/system.nim index 362b5b2b9..eefa84565 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1383,6 +1383,12 @@ type # these work for most platforms: culonglong* {.importc: "unsigned long long", nodecl.} = uint64 ## This is the same as the type ``unsigned long long`` in *C*. + # There is a disparity on macOS where Nim's `uint` is `unsigned long long` and + # `uintptr_t` is `unsigned long`. Even though both data types are the same + # size (64 bits), clang++ refuses to do automatic conversion between them. + cuintptr_t* {.importc: "uintptr_t", nodecl.} = uint + ## This is the same as the type ``uintptr_t`` in *C*. + cstringArray* {.importc: "char**", nodecl.} = ptr UncheckedArray[cstring] ## This is binary compatible to the type ``char**`` in *C*. The array's ## high value is large enough to disable bounds checking in practice. diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index 3006cff19..fc8bd89f7 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -25,6 +25,11 @@ type ## rendered at a later time, we should ensure the stacktrace ## data isn't invalidated; any pointer into PFrame is ## subject to being invalidated so shouldn't be stored. + when defined(nimStackTraceOverride): + programCounter*: uint ## Program counter - will be used to get the rest of the info, + ## when `$` is called on this type. We can't use + ## "cuintptr_t" in here. + procnameStr*, filenameStr*: string ## GC-ed objects holding the cstrings in "procname" and "filename" Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ ## Base exception class. diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 089048163..1a7473a76 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -11,6 +11,7 @@ # use the heap (and nor exceptions) do not include the GC or memory allocator. import std/private/miscdollars +import stacktraces var errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign, @@ -137,20 +138,6 @@ const hasSomeStackTrace = NimStackTrace or defined(nimStackTraceOverride) or (defined(nativeStackTrace) and nativeStackTraceSupported) -when defined(nimStackTraceOverride): - type StackTraceOverrideProc* = proc (): string {.nimcall, noinline, benign, raises: [], tags: [].} - ## Procedure type for overriding the default stack trace. - - var stackTraceOverrideGetTraceback: StackTraceOverrideProc = proc(): string {.noinline.} = - result = "Stack trace override procedure not registered.\n" - - proc registerStackTraceOverride*(overrideProc: StackTraceOverrideProc) = - ## Override the default stack trace inside rawWriteStackTrace() with your - ## own procedure. - stackTraceOverrideGetTraceback = overrideProc - - proc auxWriteStackTraceWithOverride(s: var string) = - add(s, stackTraceOverrideGetTraceback()) when defined(nativeStacktrace) and nativeStackTraceSupported: type @@ -168,13 +155,13 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: when not hasThreadSupport: var - tempAddresses: array[0..127, pointer] # should not be alloc'd on stack + tempAddresses: array[maxStackTraceLines, pointer] # should not be alloc'd on stack tempDlInfo: TDl_info proc auxWriteStackTraceWithBacktrace(s: var string) = when hasThreadSupport: var - tempAddresses: array[0..127, pointer] # but better than a threadvar + tempAddresses: array[maxStackTraceLines, pointer] # but better than a threadvar tempDlInfo: TDl_info # This is allowed to be expensive since it only happens during crashes # (but this way you don't need manual stack tracing) @@ -202,11 +189,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: when hasSomeStackTrace and not hasThreadSupport: var - tempFrames: array[0..127, PFrame] # should not be alloc'd on stack - -const - reraisedFromBegin = -10 - reraisedFromEnd = -100 + tempFrames: array[maxStackTraceLines, PFrame] # should not be alloc'd on stack template reraisedFrom(z): untyped = StackTraceEntry(procname: nil, line: z, filename: nil) @@ -253,7 +236,12 @@ template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) = for i in first.. 0: + result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines)) diff --git a/tests/system/tnim_stacktrace_override.nim b/tests/system/tnim_stacktrace_override.nim new file mode 100644 index 000000000..c75da9d9b --- /dev/null +++ b/tests/system/tnim_stacktrace_override.nim @@ -0,0 +1,18 @@ +discard """ + cmd: "nim c -d:nimStacktraceOverride $file" + output: '''begin +Traceback (most recent call last, using override) +Error: unhandled exception: stack trace produced [ValueError] +''' + exitcode: 1 +""" + +import asyncfutures + +proc main = + echo "begin" + if true: + raise newException(ValueError, "stack trace produced") + echo "unreachable" + +main() From ab05e141c0ee298d42344e8a15101097e73ff2f9 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 22 Sep 2020 19:07:31 +0800 Subject: [PATCH 1134/4254] deinitLock (#15383) * deinitLock * minor --- lib/pure/ioselects/ioselectors_select.nim | 1 + lib/system/threads.nim | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 2f22f1b30..eed64a34d 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -110,6 +110,7 @@ proc close*[T](s: Selector[T]) = when hasThreadSupport: deallocSharedArray(s.fds) deallocShared(cast[pointer](s)) + deinitLock(s.lock) when defined(windows): proc newSelectEvent*(): SelectEvent = diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 6b858c4bb..bf93b5e01 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -41,6 +41,8 @@ ## for i in 0..high(thr): ## createThread(thr[i], threadFunc, (i*10, i*10+5)) ## joinThreads(thr) +## +## deinitLock(L) when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} From 11c377c1149a23657a7f0dd897866cb550ade8d1 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 22 Sep 2020 13:08:36 +0200 Subject: [PATCH 1135/4254] add `enumerate` macro (#15297) * add `enumerate` macro * address the comments * put `enumerate` in its own module --- doc/manual.rst | 11 +++++---- lib/pure/sugar.nim | 1 + lib/std/enumerate.nim | 56 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 lib/std/enumerate.nim diff --git a/doc/manual.rst b/doc/manual.rst index ada6261b9..8c167bf62 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5508,10 +5508,11 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: macro enumerate(x: ForLoopStmt): untyped = expectKind x, nnkForStmt - # we strip off the first for loop variable and use - # it as an integer counter: + # check if the starting count is specified: + var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1] result = newStmtList() - result.add newVarStmt(x[0], newLit(0)) + # we strip off the first for loop variable and use it as an integer counter: + result.add newVarStmt(x[0], countStart) var body = x[^1] if body.kind != nnkStmtList: body = newTree(nnkStmtList, body) @@ -5520,7 +5521,7 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: for i in 1..x.len-3: newFor.add x[i] # transform enumerate(X) to 'X' - newFor.add x[^2][1] + newFor.add x[^2][^1] newFor.add body result.add newFor # now wrap the whole macro in a block to create a new scope @@ -5532,7 +5533,7 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: # without wrapping the macro in a block, we'd need to choose different # names for `a` and `b` here to avoid redefinition errors - for a, b in enumerate([1, 2, 3, 5]): + for a, b in enumerate(10, [1, 2, 3, 5]): echo a, " ", b diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 0edcc5697..8bfc7b7ff 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -335,6 +335,7 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} = call.add init[i] result = newTree(nnkStmtListExpr, newVarStmt(res, call), resBody, res) + when isMainModule: since (1, 1): block dup_with_field: diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim new file mode 100644 index 000000000..4620af94d --- /dev/null +++ b/lib/std/enumerate.nim @@ -0,0 +1,56 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements `enumerate` syntactic sugar based on Nim's +## macro system. + +import std/private/since +import macros + + +macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = + ## Enumerating iterator for collections. + ## + ## It yields `(count, value)` tuples (which must be immediately unpacked). + ## The default starting count `0` can be manually overridden if needed. + runnableExamples: + let a = [10, 20, 30] + var b: seq[(int, int)] + for i, x in enumerate(a): + b.add((i, x)) + assert b == @[(0, 10), (1, 20), (2, 30)] + + let c = "abcd" + var d: seq[(int, char)] + for i, x in enumerate(97, c): + d.add((i, x)) + assert d == @[(97, 'a'), (98, 'b'), (99, 'c'), (100, 'd')] + + expectKind x, nnkForStmt + # check if the starting count is specified: + var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1] + result = newStmtList() + # We strip off the first for loop variable and use it as an integer counter. + # We must immediately decrement it by one, because it gets incremented before + # the loop body - to be able to use the final expression in other macros. + result.add newVarStmt(x[0], infix(countStart, "-", newLit(1))) + var body = x[^1] + if body.kind != nnkStmtList: + body = newTree(nnkStmtList, body) + body.insert(0, newCall(bindSym"inc", x[0])) + var newFor = newTree(nnkForStmt) + for i in 1..x.len-3: + newFor.add x[i] + # transform enumerate(X) to 'X' + newFor.add x[^2][^1] + newFor.add body + result.add newFor + # now wrap the whole macro in a block to create a new scope + result = quote do: + block: `result` From 4b9eea2fcc5d030393ca9020fbbee33fcb48d41a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 22 Sep 2020 18:24:13 +0200 Subject: [PATCH 1136/4254] Fix forward declarations in shadow scope contexts (#15386) * Fix forward declarations in shadow scope contexts * Add testcase for #15385 * Less empty lines * Fix tests * Inline isShadowScope * Add original testcase (with reduced amount of iterations) * Add testcase without forward decl --- compiler/lookups.nim | 12 ++--- compiler/procfind.nim | 12 ++++- compiler/semstmts.nim | 9 ++-- compiler/semtempl.nim | 4 +- tests/macros/tmacros_issues.nim | 77 +++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 13 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index c0db25950..744f77cf8 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -91,13 +91,15 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym = message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " & s.name.s & " is deprecated") +proc isShadowScope*(s: PScope): bool {.inline.} = s.parent != nil and s.parent.depthLevel == s.depthLevel + proc localSearchInScope*(c: PContext, s: PIdent): PSym = - result = strTableGet(c.currentScope.symbols, s) - var shadow = c.currentScope - while result == nil and shadow.parent != nil and shadow.depthLevel == shadow.parent.depthLevel: + var scope = c.currentScope + result = strTableGet(scope.symbols, s) + while result == nil and scope.isShadowScope: # We are in a shadow scope, check in the parent too - result = strTableGet(shadow.parent.symbols, s) - shadow = shadow.parent + scope = scope.parent + result = strTableGet(scope.symbols, s) proc searchInScopes*(c: PContext, s: PIdent): PSym = for scope in walkScopes(c.currentScope): diff --git a/compiler/procfind.nim b/compiler/procfind.nim index 1d897758a..0bdb3dae6 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -11,7 +11,7 @@ # This is needed for proper handling of forward declarations. import - ast, astalgo, msgs, semdata, types, trees, strutils + ast, astalgo, msgs, semdata, types, trees, strutils, lookups proc equalGenericParams(procA, procB: PNode): bool = if procA.len != procB.len: return false @@ -28,7 +28,7 @@ proc equalGenericParams(procA, procB: PNode): bool = if not exprStructuralEquivalent(a.ast, b.ast): return result = true -proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym = +proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym = const flags = {ExactGenericParams, ExactTypeDescValues, ExactConstraints, IgnoreCC} var it: TIdentIter @@ -50,6 +50,14 @@ proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym = discard result = nextIdentIter(it, scope.symbols) +proc searchForProc*(c: PContext, scope: PScope, fn: PSym): tuple[proto: PSym, comesFromShadowScope: bool] = + var scope = scope + result.proto = searchForProcAux(c, scope, fn) + while result.proto == nil and scope.isShadowScope: + scope = scope.parent + result.proto = searchForProcAux(c, scope, fn) + result.comesFromShadowScope = true + when false: proc paramsFitBorrow(child, parent: PNode): bool = result = false diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index e99ce8937..53d381f5d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1898,8 +1898,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, elif s.kind == skFunc: incl(s.flags, sfNoSideEffect) incl(s.typ.flags, tfNoSideEffect) - var proto: PSym = if isAnon: nil - else: searchForProc(c, oldScope, s) + var (proto, comesFromShadowScope) = if isAnon: (nil, false) + else: searchForProc(c, oldScope, s) if proto == nil and sfForward in s.flags: #This is a definition that shares its sym with its forward declaration (generated by a macro), #if the symbol is also gensymmed we won't find it with searchForProc, so we check here @@ -1941,8 +1941,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, onDefResolveForward(n[namePos].info, proto) if sfForward notin proto.flags and proto.magic == mNone: wrongRedefinition(c, n.info, proto.name.s, proto.info) - excl(proto.flags, sfForward) - incl(proto.flags, sfWasForwarded) + if not comesFromShadowScope: + excl(proto.flags, sfForward) + incl(proto.flags, sfWasForwarded) closeScope(c) # close scope with wrong parameter symbols openScope(c) # open scope for old (correct) parameter symbols if proto.ast[genericParamsPos].kind != nkEmpty: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index a1afd2c6d..1ec8c07b0 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -662,10 +662,10 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s) elif n[bodyPos].kind == nkEmpty: localError(c.config, n.info, "implementation of '$1' expected" % s.name.s) - var proto = searchForProc(c, c.currentScope, s) + var (proto, comesFromShadowscope) = searchForProc(c, c.currentScope, s) if proto == nil: addInterfaceOverloadableSymAt(c, c.currentScope, s) - else: + elif not comesFromShadowscope: symTabReplace(c.currentScope.symbols, proto, s) if n[patternPos].kind != nkEmpty: c.patterns.add(s) diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index 882c0735d..f53429888 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -39,6 +39,7 @@ true false true false +1.0 ''' """ @@ -403,3 +404,79 @@ testEvenOdd5() # it works, because the forward decl and definition share the symbol and the compiler is forgiving here #testEvenOdd6() #Don't test it though, the compiler may become more strict in the future +# bug #15385 +var captured_funcs {.compileTime.}: seq[NimNode] = @[] + +macro aad*(fns: varargs[typed]): typed = + result = newStmtList() + for fn in fns: + captured_funcs.add fn[0] + result.add fn + +func exp*(x: float): float ## get different error if you remove forward declaration + +func exp*(x: float): float {.aad.} = + var x1 = min(max(x, -708.4), 709.8) + var result: float ## looks weird because it is taken from template expansion + result = x1 + 1.0 + result + +template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto = + + proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} = + let k = (rng.b - rng.a) / (float) n + var + res, x: float + i, max_ulp = 0 + avg_ulp = 0.0 + + x = rng.a + while (i < n): + res = f(x) + i.inc + x = x + 0.001 + (avg_ulp, max_ulp) + check_accuracy() + +discard check_accuracy(exp, -730.0..709.4, 4) + +# And without forward decl +macro aad2*(fns: varargs[typed]): typed = + result = newStmtList() + for fn in fns: + captured_funcs.add fn[0] + result.add fn + +func exp2*(x: float): float {.aad2.} = + var x1 = min(max(x, -708.4), 709.8) + var result: float ## looks weird because it is taken from template expansion + result = x1 + 1.0 + result + +template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto = + + proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} = + let k = (rng.b - rng.a) / (float) n + var + res, x: float + i, max_ulp = 0 + avg_ulp = 0.0 + + x = rng.a + while (i < n): + res = f(x) + i.inc + x = x + 0.001 + (avg_ulp, max_ulp) + check_accuracy2() + +discard check_accuracy2(exp2, -730.0..709.4, 4) + +# And minimized: +macro aadMin(fn: typed): typed = fn + +func expMin: float + +func expMin: float {.aadMin.} = 1 + +echo expMin() From e2d80b15a6963f4a1ea64c32d7aeec9fcb862260 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 23 Sep 2020 10:01:52 +0200 Subject: [PATCH 1137/4254] finish the stacktraces.nim implementation [backport:1.2] (#15393) --- compiler/condsyms.nim | 1 + lib/system/stacktraces.nim | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index d99b8b7e6..7dc1d183e 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -120,3 +120,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimDoesntTrackDefects") defineSymbol("nimHasLentIterators") defineSymbol("nimHasDeclaredMagic") + defineSymbol("nimHasStacktracesModule") diff --git a/lib/system/stacktraces.nim b/lib/system/stacktraces.nim index dce25fdc0..62de27260 100644 --- a/lib/system/stacktraces.nim +++ b/lib/system/stacktraces.nim @@ -22,26 +22,26 @@ when defined(nimStackTraceOverride): ## This is the same as the type ``uintptr_t`` in C. StackTraceOverrideGetTracebackProc* = proc (): string {. - nimcall, gcsafe, locks: 0, raises: [], tags: [].} + nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} StackTraceOverrideGetProgramCountersProc* = proc (maxLength: cint): seq[cuintptr_t] {. - nimcall, gcsafe, locks: 0, raises: [], tags: [].} + nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} StackTraceOverrideGetDebuggingInfoProc* = proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {. - nimcall, gcsafe, locks: 0, raises: [], tags: [].} + nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} # Default procedures (not normally used, because people opting in on this # override are supposed to register their own versions). var stackTraceOverrideGetTraceback: StackTraceOverrideGetTracebackProc = - proc (): string {.nimcall, gcsafe, locks: 0, raises: [], tags: [].} = + proc (): string {.nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} = discard #result = "Stack trace override procedure not registered.\n" stackTraceOverrideGetProgramCounters: StackTraceOverrideGetProgramCountersProc = - proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, locks: 0, raises: [], tags: [].} = + proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} = discard stackTraceOverrideGetDebuggingInfo: StackTraceOverrideGetDebuggingInfoProc = proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {. - nimcall, gcsafe, locks: 0, raises: [], tags: [].} = + nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} = discard # Custom procedure registration. From 94c8d53a03c437d1601fa75aecb5b84bb694711f Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 23 Sep 2020 10:41:23 +0200 Subject: [PATCH 1138/4254] 'koch temp' bugfix --- compiler/docgen.nim | 4 ++-- koch.nim | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index ff3a540be..c2ce12e50 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -992,7 +992,7 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id # set the type so that the following analysis doesn't screw up: effects[i].typ = real[i].typ - result = newTreeI(nkExprColonExpr, n.info, + result = newTreeI(nkExprColonExpr, n.info, newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects) proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode = @@ -1005,7 +1005,7 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName effects.add params[i] if effects.len > 0: - result = newTreeI(nkExprColonExpr, n.info, + result = newTreeI(nkExprColonExpr, n.info, newIdentNode(getIdent(cache, pragmaName), n.info), effects) proc documentRaises*(cache: IdentCache; n: PNode) = diff --git a/koch.nim b/koch.nim index 966ff932e..188004571 100644 --- a/koch.nim +++ b/koch.nim @@ -481,7 +481,7 @@ proc temp(args: string) = var (bootArgs, programArgs) = splitArgs(args) if "doc" notin programArgs and "threads" notin programArgs and - "js" notin programArgs: + "js" notin programArgs and "rst2html" notin programArgs: bootArgs.add " -d:leanCompiler" let nimexec = findNim().quoteShell() exec(nimexec & " c -d:debug --debugger:native -d:nimBetterRun " & bootArgs & " " & (d / "compiler" / "nim"), 125) From fe3211fbcfa6b14a2e2fcd4dfb8664dcf8a1bd21 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 23 Sep 2020 12:44:41 +0200 Subject: [PATCH 1139/4254] fix the indentation in `--help` and `--fullhelp` (#15387) * fix the indentation in `--help` and `--fullhelp` * a better way to fix it --- compiler/commands.nim | 4 ++-- doc/advopt.txt | 4 ++-- doc/basicopt.txt | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index a76a5be73..17124a759 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -59,8 +59,8 @@ proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} = result.add $f const - Usage = slurp"../doc/basicopt.txt".replace(" //", " ") - AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)] + Usage = slurp"../doc/basicopt.txt".replace(" //", " ") + AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)] proc getCommandLineDesc(conf: ConfigRef): string = result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name, diff --git a/doc/advopt.txt b/doc/advopt.txt index 9b7f29a5e..8b906298d 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -11,9 +11,9 @@ Advanced commands: //ctags create a tags file //buildIndex build an index for the whole documentation //genDepend generate a DOT file containing the - module dependency graph + module dependency graph //dump dump all defined conditionals and search paths - see also: --dump.format:json (useful with: ` | jq`) + see also: --dump.format:json (useful with: ` | jq`) //check checks the project for syntax and semantic Runtime checks (see -x): diff --git a/doc/basicopt.txt b/doc/basicopt.txt index cdd8ab9be..7ea55cf6c 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -3,11 +3,11 @@ nim command [options] [projectfile] [arguments] Command: - //compile, c compile project with default code generator (C) - //r compile to $nimcache/projname, run with [arguments] - using backend specified by `--backend` (default: c) - //doc generate the documentation for inputfile for - backend specified by `--backend` (default: c) + //compile, c compile project with default code generator (C) + //r compile to $nimcache/projname, run with [arguments] + using backend specified by `--backend` (default: c) + //doc generate the documentation for inputfile for + backend specified by `--backend` (default: c) Arguments: arguments are passed to the program being run (if --run option is selected) From f21a49b2c4b20402198546aae9d9884bb9fa2a9f Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 24 Sep 2020 00:07:30 +0100 Subject: [PATCH 1140/4254] Fix #15389 (#15390) * allow result symbol reuse * try different approach * Revert "try different approach" This reverts commit abcfb6b75983c2f798cc887342ff1a9ff10c0324. --- compiler/semexprs.nim | 18 +++++++++++------- compiler/semstmts.nim | 33 ++++++++++++++++----------------- tests/macros/tmacros_issues.nim | 17 +++++++++++++++++ 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 80e04ead4..d6b146800 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1754,17 +1754,21 @@ proc semReturn(c: PContext, n: PNode): PNode = if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or (not c.p.owner.typ.isNil and isClosureIterator(c.p.owner.typ)): if n[0].kind != nkEmpty: - # transform ``return expr`` to ``result = expr; return`` - if c.p.resultSym != nil: + if n[0].kind == nkAsgn and n[0][0].kind == nkSym and c.p.resultSym == n[0][0].sym: + discard "return is already transformed" + elif c.p.resultSym != nil: + # transform ``return expr`` to ``result = expr; return`` var a = newNodeI(nkAsgn, n[0].info) a.add newSymNode(c.p.resultSym) a.add n[0] - n[0] = semAsgn(c, a) - # optimize away ``result = result``: - if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: - n[0] = c.graph.emptyNode - else: + n[0] = a + else: localError(c.config, n.info, errNoReturnTypeDeclared) + return + result[0] = semAsgn(c, n[0]) + # optimize away ``result = result``: + if result[0][1].kind == nkSym and result[0][1].sym == c.p.resultSym: + result[0] = c.graph.emptyNode else: localError(c.config, n.info, "'return' not allowed here") diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 53d381f5d..abf2cc0b6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1430,16 +1430,19 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = else: localError(c.config, n.info, errNoSymbolToBorrowFromFound) -proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = +proc addResult(c: PContext, n: PNode, t: PType, owner: TSymKind) = if owner == skMacro or t != nil: - var s = newSym(skResult, getIdent(c.cache, "result"), getCurrOwner(c), info) - s.typ = t - incl(s.flags, sfUsed) - addParamOrResult(c, s, owner) - c.p.resultSym = s - -proc addResultNode(c: PContext, n: PNode) = - if c.p.resultSym != nil: n.add newSymNode(c.p.resultSym) + if n.len > resultPos and n[resultPos] != nil: + if n[resultPos].sym.kind != skResult or n[resultPos].sym.owner != getCurrOwner(c): + localError(c.config, n.info, "incorrect result proc symbol") + c.p.resultSym = n[resultPos].sym + else: + var s = newSym(skResult, getIdent(c.cache, "result"), getCurrOwner(c), n.info) + s.typ = t + incl(s.flags, sfUsed) + c.p.resultSym = s + n.add newSymNode(c.p.resultSym) + addParamOrResult(c, c.p.resultSym, owner) proc copyExcept(n: PNode, i: int): PNode = result = copyNode(n) @@ -1563,8 +1566,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # XXX not good enough; see tnamedparamanonproc.nim if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags): pushProcCon(c, s) - addResult(c, s.typ[0], n.info, skProc) - addResultNode(c, n) + addResult(c, n, s.typ[0], skProc) s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos])) trackProc(c, s, s.ast[bodyPos]) popProcCon(c) @@ -1606,8 +1608,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} = pushOwner(c, s) addParams(c, params, skProc) pushProcCon(c, s) - addResult(c, n.typ[0], n.info, skProc) - addResultNode(c, n) + addResult(c, n, n.typ[0], skProc) s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos])) trackProc(c, s, s.ast[bodyPos]) popProcCon(c) @@ -1637,11 +1638,9 @@ proc activate(c: PContext, n: PNode) = proc maybeAddResult(c: PContext, s: PSym, n: PNode) = if s.kind == skMacro: let resultType = sysTypeFromName(c.graph, n.info, "NimNode") - addResult(c, resultType, n.info, s.kind) - addResultNode(c, n) + addResult(c, n, resultType, s.kind) elif s.typ[0] != nil and not isInlineIterator(s.typ): - addResult(c, s.typ[0], n.info, s.kind) - addResultNode(c, n) + addResult(c, n, s.typ[0], s.kind) proc canonType(c: PContext, t: PType): PType = if t.kind == tySequence: diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index f53429888..3d992a27f 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -480,3 +480,20 @@ func expMin: float func expMin: float {.aadMin.} = 1 echo expMin() + + +# issue #15389 +block double_sem_for_procs: + + macro aad(fns: varargs[typed]): typed = + result = newStmtList() + for fn in fns: + result.add fn + + func exp(x: float): float {.aad.} = + var x1 = min(max(x, -708.4), 709.8) + if x1 > 0.0: + return x1 + 1.0 + result = 10.0 + + discard exp(5.0) \ No newline at end of file From 7a6f4eca1987f41fccf2eea0896f4a433208a355 Mon Sep 17 00:00:00 2001 From: genotrance Date: Thu, 24 Sep 2020 01:07:32 -0500 Subject: [PATCH 1141/4254] Bump nimble (#15398) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 188004571..cce689135 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "f4c818a046c2c3ceb1523c4c974e4b6e625d8ca3" # master + NimbleStableCommit = "26167cd3b7671006c8bd38cbef8708431ddf8687" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From e85c5ad3797b378cf6b93f35cc1d63e2d066b57a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 24 Sep 2020 14:54:13 +0800 Subject: [PATCH 1142/4254] fix #15333 (#15336) --- changelog.md | 2 ++ lib/pure/uri.nim | 28 ++++++++++++++++++++++++++-- tests/stdlib/turi.nim | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/stdlib/turi.nim diff --git a/changelog.md b/changelog.md index 1bc1d7303..bd5674610 100644 --- a/changelog.md +++ b/changelog.md @@ -197,6 +197,8 @@ """ ``` +- Add `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. + ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 04a9d97bd..4b84a8902 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -49,6 +49,7 @@ import std/private/since import strutils, parseutils, base64 include includes/decode_helpers + type Url* = distinct string @@ -56,6 +57,7 @@ type scheme*, username*, password*: string hostname*, port*, path*, query*, anchor*: string opaque*: bool + isIpv6: bool # not expose it for compatibility. proc encodeUrl*(s: string, usePlus = true): string = ## Encodes a URL according to RFC3986. @@ -170,6 +172,7 @@ proc parseAuthority(authority: string, result: var Uri) = inPort = true of '[': inIPv6 = true + result.isIpv6 = true of ']': inIPv6 = false else: @@ -208,6 +211,21 @@ proc initUri*(): Uri = result = Uri(scheme: "", username: "", password: "", hostname: "", port: "", path: "", query: "", anchor: "") +proc initUri*(isIpv6: bool): Uri {.since: (1, 3, 5).} = + ## Initializes a URI with ``scheme``, ``username``, ``password``, + ## ``hostname``, ``port``, ``path``, ``query``, ``anchor`` and ``isIpv6``. + ## + ## **See also:** + ## * `Uri type <#Uri>`_ for available fields in the URI type + runnableExamples: + var uri2 = initUri(isIpv6 = true) + uri2.scheme = "tcp" + uri2.hostname = "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + uri2.port = "8080" + assert $uri2 == "tcp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" + result = Uri(scheme: "", username: "", password: "", hostname: "", port: "", + path: "", query: "", anchor: "", isIpv6: isIpv6) + proc resetUri(uri: var Uri) = for f in uri.fields: when f is string: @@ -452,9 +470,15 @@ proc `$`*(u: Uri): string = result.add(u.password) result.add("@") if u.hostname.endsWith('/'): - result.add(u.hostname[0..^2]) + if u.isIpv6: + result.add("[" & u.hostname[0 .. ^2] & "]") + else: + result.add(u.hostname[0 .. ^2]) else: - result.add(u.hostname) + if u.isIpv6: + result.add("[" & u.hostname & "]") + else: + result.add(u.hostname) if u.port.len > 0: result.add(":") result.add(u.port) diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim new file mode 100644 index 000000000..9fb349e88 --- /dev/null +++ b/tests/stdlib/turi.nim @@ -0,0 +1,17 @@ +discard """ + cmd: "nim c -r --styleCheck:hint --panics:on $options $file" + targets: "c" + nimout: "" + action: "run" + exitcode: 0 + timeout: 60.0 +""" +import uri + + +block: + let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" + let url = parseUri(org) + doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true + let newUrl = parseUri($url) + doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true From 8a6c5edc43bb4ef90feb4eabbc2520004244a011 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:14:23 +0800 Subject: [PATCH 1143/4254] use release version (#15400) --- compiler/nimpaths.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim index 9caaf4f05..7b2216080 100644 --- a/compiler/nimpaths.nim +++ b/compiler/nimpaths.nim @@ -36,11 +36,11 @@ proc interp*(path: string, nimr: string): string = doAssert '$' notin result, $(path, nimr, result) # avoids un-interpolated variables in output proc getDocHacksJs*(nimr: string, nim = getCurrentCompilerExe(), forceRebuild = false): string = - ## return absolute path to dochhack.js, rebuilding if it doesn't exist or if + ## return absolute path to dochack.js, rebuilding if it doesn't exist or if ## `forceRebuild`. let docHackJs2 = docHackJs.interp(nimr = nimr) if forceRebuild or not docHackJs2.fileExists: - let cmd = "$nim js $file" % ["nim", nim.quoteShell, "file", docHackNim.interp(nimr = nimr).quoteShell] + let cmd = "$nim js -d:release $file" % ["nim", nim.quoteShell, "file", docHackNim.interp(nimr = nimr).quoteShell] echo "getDocHacksJs: cmd: " & cmd doAssert execShellCmd(cmd) == 0, $(cmd) doAssert docHackJs2.fileExists From 4ec5cbac0df2914b71e9813e6df81c248510ae57 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 24 Sep 2020 15:41:45 +0200 Subject: [PATCH 1144/4254] fixes #15361 (#15401) * fixes #15361; better cursor inference --- compiler/varpartitions.nim | 167 +++++++++++++++++++++++------- tests/arc/top_no_cursor2.nim | 53 ++++++++++ tests/arc/topt_no_cursor.nim | 4 +- tests/destructor/tdestructor3.nim | 11 +- tests/destructor/tmatrix.nim | 6 +- 5 files changed, 196 insertions(+), 45 deletions(-) create mode 100644 tests/arc/top_no_cursor2.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index f983f9416..9297c19e1 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -13,6 +13,17 @@ ## algorithm. ## The used data structure is "union find" with path compression. +## We perform two passes over the AST: +## - Pass one (``computeLiveRanges``): collect livetimes of local +## variables and whether they are potentially re-assigned. +## - Pass two (``traverse``): combine local variables to abstract "graphs". +## Strict func checking: Ensure that graphs that are connected to +## const parameters are not mutated. +## Cursor inference: Ensure that potential cursors are not +## borrowed from locations that are connected to a graph +## that is mutated during the liveness of the cursor. +## (We track all possible mutations of a graph.) + import ast, types, lineinfos, options, msgs, renderer from trees import getMagic, whichPragma from wordrecg import wNoSideEffect @@ -26,7 +37,8 @@ type VarFlag = enum ownsData, - preventCursor + preventCursor, + isReassigned VarIndexKind = enum isEmptyRoot, @@ -266,36 +278,38 @@ proc allRoots(n: PNode; result: var seq[PSym]; followDotExpr = true) = else: discard "nothing to do" -proc analyseAsgn(c: var Partitions; dest: var VarIndex; n: PNode) = +proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = + ## Analyse if 'n' is an expression that owns the data, if so mark 'dest' + ## with 'ownsData'. case n.kind of nkEmpty, nkCharLit..nkNilLit: # primitive literals including the empty are harmless: discard of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv: - analyseAsgn(c, dest, n[1]) + destMightOwn(c, dest, n[1]) of nkIfStmt, nkIfExpr: for i in 0.. 0: - analyseAsgn(c, dest, n[^1]) + destMightOwn(c, dest, n[^1]) of nkClosure: for i in 1..= 0: - analyseAsgn(c, c.s[vid], src) - # do not borrow from a different local variable, this is easier - # than tracking reassignments, consider 'var cursor = local; local = newNode()' + destMightOwn(c, c.s[vid], src) if src.kind == nkSym: - if (src.sym.kind in {skVar, skResult, skTemp} or - (src.sym.kind in {skLet, skParam, skForVar} and hasDisabledAsgn(src.sym.typ))): + let s = src.sym + if {sfGlobal, sfThread} * s.flags != {} or hasDisabledAsgn(s.typ): + # do not borrow from a global variable or from something with a + # disabled assignment operator. c.s[vid].flags.incl preventCursor - elif src.sym.kind in {skVar, skResult, skTemp, skLet, skForVar}: - # XXX: we need to compute variable alive ranges before doing anything else: - let srcid = variableId(c, src.sym) - if srcid >= 0 and preventCursor in c.s[srcid].flags: - # you cannot borrow from a local that lives shorter than 'vid': - if c.s[srcid].aliveStart > c.s[vid].aliveStart or - c.s[srcid].aliveEnd < c.s[vid].aliveEnd: + when false: echo "A not a cursor: ", dest.sym, " ", s + else: + let srcid = variableId(c, s) + if srcid >= 0: + if s.kind notin {skResult, skParam} and ( + c.s[srcid].aliveEnd < c.s[vid].aliveEnd): + # you cannot borrow from a local that lives shorter than 'vid': + when false: echo "B not a cursor ", dest.sym, " ", c.s[srcid].aliveEnd, " ", c.s[vid].aliveEnd + c.s[vid].flags.incl preventCursor + elif {isReassigned, preventCursor} * c.s[srcid].flags != {}: + # you cannot borrow from something that is re-assigned: + when false: echo "C not a cursor ", dest.sym, " ", c.s[srcid].flags c.s[vid].flags.incl preventCursor - if src.kind == nkSym and hasDestructor(src.typ): - rhsIsSink(c, src) + #if src.kind == nkSym and hasDestructor(src.typ): + # rhsIsSink(c, src) + +const + nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit, + nkTypeSection, nkProcDef, nkConverterDef, + nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, + nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr} proc traverse(c: var Partitions; n: PNode) = inc c.abstractTime @@ -418,11 +444,11 @@ proc traverse(c: var Partitions; n: PNode) = if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: if child.len-2 != last.len: return for i in 0..= 0: - c.s[id].aliveEnd = max(c.s[id].aliveEnd, c.abstractTime) - of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, - nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, - nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: + of nodesToIgnoreSet: dec c.abstractTime discard "do not follow the construct" of nkCallKinds: @@ -514,6 +533,79 @@ proc traverse(c: var Partitions; n: PNode) = else: for child in n: traverse(c, child) +proc computeLiveRanges(c: var Partitions; n: PNode) = + # first pass: Compute live ranges for locals. + # **Watch out!** We must traverse the tree like 'traverse' does + # so that the 'c.abstractTime' is consistent. + inc c.abstractTime + case n.kind + of nkLetSection, nkVarSection: + for child in n: + let last = lastSon(child) + computeLiveRanges(c, last) + if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: + if child.len-2 != last.len: return + for i in 0..= 0: + c.s[vid].flags.incl isReassigned + + of nkSym: + dec c.abstractTime + if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}: + let id = variableId(c, n.sym) + if id >= 0: + c.s[id].aliveEnd = max(c.s[id].aliveEnd, c.abstractTime) + + of nodesToIgnoreSet: + dec c.abstractTime + discard "do not follow the construct" + of nkCallKinds: + for child in n: computeLiveRanges(c, child) + + let parameters = n[0].typ + let L = if parameters != nil: parameters.len else: 0 + + for i in 1..= 0: + c.s[vid].flags.incl isReassigned + + of nkAddr, nkHiddenAddr: + computeLiveRanges(c, n[0]) + if n[0].kind == nkSym: + let vid = variableId(c, n[0].sym) + if vid >= 0: + c.s[vid].flags.incl preventCursor + + of nkPragmaBlock: + computeLiveRanges(c, n.lastSon) + of nkWhileStmt, nkForStmt, nkParForStmt: + for child in n: computeLiveRanges(c, child) + # analyse loops twice so that 'abstractTime' suffices to detect cases + # like: + # while cond: + # mutate(graph) + # connect(graph, cursorVar) + for child in n: computeLiveRanges(c, child) + else: + for child in n: computeLiveRanges(c, child) + proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partitions = result = Partitions(performCursorInference: cursorInference) if s.kind notin {skModule, skMacro}: @@ -523,6 +615,9 @@ proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partit if resultPos < s.ast.safeLen: registerVariable(result, s.ast[resultPos]) + computeLiveRanges(result, n) + # resart the timer for the second pass: + result.abstractTime = 0 traverse(result, n) proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = @@ -560,7 +655,7 @@ proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = var par = computeGraphPartitions(s, n, true) for i in 0 ..< par.s.len: let v = addr(par.s[i]) - if v.flags == {} and v.sym.kind notin {skParam, skResult} and + if v.flags * {ownsData, preventCursor} == {} and v.sym.kind notin {skParam, skResult} and v.sym.flags * {sfThread, sfGlobal} == {} and hasDestructor(v.sym.typ) and v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned: let rid = root(par, i) diff --git a/tests/arc/top_no_cursor2.nim b/tests/arc/top_no_cursor2.nim new file mode 100644 index 000000000..5dfde57aa --- /dev/null +++ b/tests/arc/top_no_cursor2.nim @@ -0,0 +1,53 @@ +discard """ + output: '''true +true +true +true +true''' + cmd: "nim c --gc:arc $file" +""" +# bug #15361 + +type + ErrorNodeKind = enum Branch, Leaf + Error = ref object + case kind: ErrorNodeKind + of Branch: + left: Error + right: Error + of Leaf: + leafError: string + input: string + +proc ret(input: string, lefterr, righterr: Error): Error = + result = Error(kind: Branch, left: lefterr, right: righterr, input: input) + +proc parser() = + var rerrors: Error + let lerrors = Error( + kind: Leaf, + leafError: "first error", + input: "123 ;" + ) + # If you remove "block" - everything works + block: + let rresult = Error( + kind: Leaf, + leafError: "second error", + input: ";" + ) + # this assignment is needed too + rerrors = rresult + + # Returns Error(kind: Branch, left: lerrors, right: rerrors, input: "some val") + # needs to be a proc call for some reason, can't inline the result + var data = ret(input = "some val", lefterr = lerrors, righterr = rerrors) + + echo data.left.leafError == "first error" + echo data.left.input == "123 ;" + # stacktrace shows this line + echo data.right.leafError == "second error" + echo data.right.input == ";" + echo data.input == "some val" + +parser() diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 8a33cb2ee..1e5cf7142 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -52,7 +52,7 @@ _ = ( blitTmp, ";") lvalue = _[0] lnext_cursor = _[1] -`=sink`(result.value, lvalue) +`=sink`(result.value, move lvalue) -- end of expandArc ------------------------ --expandArc: tt @@ -148,7 +148,7 @@ proc p1(): Maybe = var lnext: string (lvalue, lnext) = (lresult, ";") - result.value = lvalue + result.value = move lvalue proc tissue15130 = doAssert p1().value == @[123] diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index f967bbf95..ca9a891e1 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -23,17 +23,18 @@ joinable: false type T = object proc `=`(lhs: var T, rhs: T) = - echo "assign" + echo "assign" proc `=destroy`(v: var T) = - echo "destroy" + echo "destroy" proc use(x: T) = discard proc usedToBeBlock = - var v1 : T - var v2 : T = v1 - use v1 + var v1 = T() + var v2: T = v1 + discard addr(v2) # prevent cursorfication + use v1 usedToBeBlock() diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim index a3bd59df3..98ca95c94 100644 --- a/tests/destructor/tmatrix.nim +++ b/tests/destructor/tmatrix.nim @@ -96,14 +96,16 @@ proc info = allocCount = 0 deallocCount = 0 +proc copy(a: Matrix): Matrix = a + proc test1 = var a = matrix(5, 5, 1.0) - var b = a + var b = copy a var c = a + b proc test2 = var a = matrix(5, 5, 1.0) - var b = a + var b = copy a var c = -a proc test3 = From 496e9f74e12b1ad73b621872771e9634404f95ff Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 24 Sep 2020 16:41:08 +0200 Subject: [PATCH 1145/4254] fix #14474, crash inside of a sole code-block (#15402) --- lib/packages/docutils/rst.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 05b58c56b..123922c99 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1102,6 +1102,8 @@ proc whichSection(p: RstParser): RstNodeKind = of tkPunct: if isMarkdownHeadline(p): result = rnHeadline + elif p.tok[p.idx].symbol == "```": + result = rnCodeBlock elif match(p, tokenAfterNewline(p), "ai"): result = rnHeadline elif p.tok[p.idx].symbol == "::": From ce72d7ffc512c99e8eb8825b08c9985763f878b6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 24 Sep 2020 19:34:59 +0200 Subject: [PATCH 1146/4254] fixes #15403 (#15404) --- compiler/sempass2.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b48d7e29e..d6db0885e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1247,7 +1247,8 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = var partitions = computeGraphPartitions(s, body) if not t.hasSideEffect and t.hasDangerousAssign: t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) - checkBorrowedLocations(partitions, g.config) + if views in c.features: + checkBorrowedLocations(partitions, g.config) if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: From e3b5f80a890428a0c9b5c2bdd7a3205d79946957 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 24 Sep 2020 22:07:23 +0200 Subject: [PATCH 1147/4254] more precise borrow checking of 'result' (#15406) --- compiler/sempass2.nim | 2 +- compiler/varpartitions.nim | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d6db0885e..797aff7f7 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1248,7 +1248,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = if not t.hasSideEffect and t.hasDangerousAssign: t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) if views in c.features: - checkBorrowedLocations(partitions, g.config) + checkBorrowedLocations(partitions, body, g.config) if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 9297c19e1..474a362cd 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -110,6 +110,9 @@ proc registerVariable(c: var Partitions; n: PNode) = connectedVia: unknownLineInfo, flags: {connectsConstParam}, maxMutation: -1, minConnection: high(int), mutations: @[]) + elif n.sym.kind == skResult: + c.s.add VarIndex(kind: isEmptyRoot, sym: n.sym, + aliveStart: high(int), aliveEnd: c.abstractTime) else: c.s.add VarIndex(kind: isEmptyRoot, sym: n.sym, aliveStart: c.abstractTime, aliveEnd: c.abstractTime) @@ -567,6 +570,8 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = let id = variableId(c, n.sym) if id >= 0: c.s[id].aliveEnd = max(c.s[id].aliveEnd, c.abstractTime) + if n.sym.kind == skResult: + c.s[id].aliveStart = min(c.s[id].aliveStart, c.abstractTime) of nodesToIgnoreSet: dec c.abstractTime @@ -621,7 +626,7 @@ proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partit traverse(result, n) proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = - #echo "range ", v.aliveStart, " .. ", v.aliveEnd + #echo "range ", v.aliveStart, " .. ", v.aliveEnd, " ", v.sym if isMutated in g.flags: for m in g.mutations: #echo "mutation ", m @@ -643,7 +648,7 @@ proc cannotBorrow(config: ConfigRef; s: PSym; g: MutationInfo) = m.add " is the statement that connected the mutation to the parameter" localError(config, s.info, m) -proc checkBorrowedLocations*(par: var Partitions; config: ConfigRef) = +proc checkBorrowedLocations*(par: var Partitions; body: PNode; config: ConfigRef) = for i in 0 ..< par.s.len: let s = par.s[i].sym if s.kind != skParam and isViewType(s.typ): From 68ec7a018b85e978c437e776dfcc183cf7b79057 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 24 Sep 2020 21:21:14 +0100 Subject: [PATCH 1148/4254] Revert "fix #15035 (#15236)" (#15408) This reverts commit f8c48fc1863a243718acf86b699baed1a5c1512e. --- compiler/injectdestructors.nim | 5 ++--- tests/arc/t14383.nim | 19 +------------------ 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 9d1f43595..28f2c93f1 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -699,9 +699,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = elif n.kind in {nkObjDownConv, nkObjUpConv}: result = copyTree(n) result[0] = p(n[0], c, s, sinkArg) - elif n.typ == nil or n.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyVar}).kind == tyOpenArray: - # 'raise X' can be part of a 'case' expression. Deal with it here. - # openarrays require perfect forwarding + elif n.typ == nil: + # 'raise X' can be part of a 'case' expression. Deal with it here: result = p(n, c, s, normal) else: # copy objects that are not temporary but passed to a 'sink' parameter diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim index 78afc58e2..f112a1a6c 100644 --- a/tests/arc/t14383.nim +++ b/tests/arc/t14383.nim @@ -3,7 +3,6 @@ discard """ output: ''' hello hello -@[4, 3, 2, 1] @["a", "b"] ''' """ @@ -14,22 +13,6 @@ var val = parseMinValue() if val.kind == minDictionary: echo val - -#------------------------------------------------------------------------------ -# Issue #15035 -#------------------------------------------------------------------------------ - -proc countRun(lst: sink openArray[int]): int = - discard - -proc timSort(lst: var openArray[int]) = - let run = countRun(lst) - -var a = @[4, 3, 2, 1] -timSort(a) -echo a - - #------------------------------------------------------------------------------ # Issue #15238 #------------------------------------------------------------------------------ @@ -50,4 +33,4 @@ echo x #------------------------------------------------------------------------------ import std/os -discard getFileInfo(".") \ No newline at end of file +discard getFileInfo(".") From e9fa486493b5fa796cfd7d312b0004d5ee6ea6f5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 25 Sep 2020 08:49:21 +0200 Subject: [PATCH 1149/4254] fixes #14983 (#15320) * fixes #14983 * allow bootstrapping with 0.20 * added a test case for the new system.add with a sink parameter * make npeg green again --- lib/system.nim | 63 ++++++++++++++++++++++++++++----------- tests/destructor/tarc.nim | 15 +++++++++- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index eefa84565..a9c45f8fa 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1215,24 +1215,51 @@ when defined(nimscript) or not defined(nimSeqsV2): ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. -proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = - ## Generic proc for adding a container `y` to a container `x`. - ## - ## For containers that have an order, `add` means *append*. New generic - ## containers should also call their adding proc `add` for consistency. - ## Generic code becomes much easier to write if the Nim naming scheme is - ## respected. - ## - ## See also: - ## * `& proc <#&,seq[T][T],seq[T][T]>`_ - ## - ## .. code-block:: Nim - ## var s: seq[string] = @["test2","test2"] - ## s.add("test") # s <- @[test2, test2, test] - {.noSideEffect.}: - let xl = x.len - setLen(x, xl + y.len) - for i in 0..high(y): x[xl+i] = y[i] +when defined(gcDestructors): + proc add*[T](x: var seq[T], y: sink openArray[T]) {.noSideEffect.} = + ## Generic proc for adding a container `y` to a container `x`. + ## + ## For containers that have an order, `add` means *append*. New generic + ## containers should also call their adding proc `add` for consistency. + ## Generic code becomes much easier to write if the Nim naming scheme is + ## respected. + ## + ## See also: + ## * `& proc <#&,seq[T][T],seq[T][T]>`_ + ## + ## .. code-block:: Nim + ## var s: seq[string] = @["test2","test2"] + ## s.add("test") # s <- @[test2, test2, test] + {.noSideEffect.}: + let xl = x.len + setLen(x, xl + y.len) + for i in 0..high(y): + when nimvm: + # workaround the fact that the VM does not yet + # handle sink parameters properly: + x[xl+i] = y[i] + else: + x[xl+i] = move y[i] +else: + proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = + ## Generic proc for adding a container `y` to a container `x`. + ## + ## For containers that have an order, `add` means *append*. New generic + ## containers should also call their adding proc `add` for consistency. + ## Generic code becomes much easier to write if the Nim naming scheme is + ## respected. + ## + ## See also: + ## * `& proc <#&,seq[T][T],seq[T][T]>`_ + ## + ## .. code-block:: Nim + ## var s: seq[string] = @["test2","test2"] + ## s.add("test") # s <- @[test2, test2, test] + {.noSideEffect.}: + let xl = x.len + setLen(x, xl + y.len) + for i in 0..high(y): x[xl+i] = y[i] + when defined(nimSeqsV2): template movingCopy(a, b) = diff --git a/tests/destructor/tarc.nim b/tests/destructor/tarc.nim index 12ea46b2c..54d75a410 100644 --- a/tests/destructor/tarc.nim +++ b/tests/destructor/tarc.nim @@ -8,6 +8,8 @@ Hello 2 0 List +@["4", "5", "6", "", "", "a", ""] +@["", "", "a", ""] ''' cmd: '''nim c --gc:arc $file''' """ @@ -162,10 +164,21 @@ type case kind: TagKind of List: values: seq[Tag] - of Compound: + of Compound: compound: Table[string, Tag] var a = Tag(kind: List) var b = a echo a.kind var c = a + +proc testAdd(i: int; yyy: openArray[string]) = + var x: seq[string] + x.add [$i, $(i+1), $(i+2)] + x.add yyy + echo x + +var y = newSeq[string](4) +y[2] = "a" +testAdd(4, y) +echo y From 2de6e18774ec9f0f15c88ab916d7f501ba13b467 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 25 Sep 2020 09:25:47 +0200 Subject: [PATCH 1150/4254] fix #11537, correct parse inline code without surrounding spaces (#15399) --- doc/advopt.txt | 2 +- lib/packages/docutils/rst.nim | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 8b906298d..830b8bfc6 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -13,7 +13,7 @@ Advanced commands: //genDepend generate a DOT file containing the module dependency graph //dump dump all defined conditionals and search paths - see also: --dump.format:json (useful with: ` | jq`) + see also: --dump.format:json (useful with: `| jq`) //check checks the project for syntax and semantic Runtime checks (see -x): diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 123922c99..56bfe580b 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -507,6 +507,7 @@ proc isInlineMarkupEnd(p: RstParser, markup: string): bool = if not result: return # Rule 4: result = (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) or + (markup in ["``", "`"] and p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkWord, tkEof}) or (p.tok[p.idx + 1].symbol[0] in {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', '?', '_'}) @@ -522,6 +523,7 @@ proc isInlineMarkupStart(p: RstParser, markup: string): bool = if not result: return # Rule 1: result = (p.idx == 0) or (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) or + (markup in ["``", "`"] and p.tok[p.idx - 1].kind in {tkIndent, tkWhite, tkWord}) or (p.tok[p.idx - 1].symbol[0] in {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'}) if not result: From d4892e9388084e71f9389efce7bba42d8c069d09 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sat, 26 Sep 2020 07:31:55 +0000 Subject: [PATCH 1151/4254] koch, compiler: bundle fusion as part of the source archive (#15409) This allows distributions to build Nim from the downloaded source archive without an Internet connection. --- compiler/installer.ini | 1 + koch.nim | 3 ++- tools/deps.nim | 25 +++++++++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index 543a3befb..01b7b8c6b 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -76,6 +76,7 @@ Files: "lib" [Other] Files: "examples" Files: "dist/nimble" +Files: "dist/fusion" Files: "tests" diff --git a/koch.nim b/koch.nim index cce689135..68c5764be 100644 --- a/koch.nim +++ b/koch.nim @@ -201,7 +201,8 @@ proc bundleWinTools(args: string) = proc bundleFusion(latest: bool) = let commit = if latest: "HEAD" else: FusionStableCommit - cloneDependency(distDir, "https://github.com/nim-lang/fusion.git", commit) + cloneDependency(distDir, "https://github.com/nim-lang/fusion.git", commit, + allowBundled = true) copyDir(distDir / "fusion" / "src" / "fusion", "lib" / "fusion") proc zip(latest: bool; args: string) = diff --git a/tools/deps.nim b/tools/deps.nim index 888237761..394dc0d25 100644 --- a/tools/deps.nim +++ b/tools/deps.nim @@ -1,13 +1,25 @@ -import os, uri, strformat +import os, uri, strformat, osproc proc exec(cmd: string) = echo "deps.cmd: " & cmd let status = execShellCmd(cmd) doAssert status == 0, cmd +proc execEx(cmd: string): tuple[output: TaintedString, exitCode: int] = + echo "deps.cmd: " & cmd + execCmdEx(cmd, {poStdErrToStdOut, poUsePath, poEvalCommand}) + +proc isGitRepo(dir: string): bool = + # This command is used to get the relative path to the root of the repository. + # Using this, we can verify whether a folder is a git repository by checking + # whether the command success and if the output is empty. + let (output, status) = execEx fmt"git -C {quoteShell(dir)} rev-parse --show-cdup" + result = status == 0 and output == "" + const commitHead* = "HEAD" -proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, appendRepoName = true) = +proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, + appendRepoName = true, allowBundled = false) = let destDirBase = destDirBase.absolutePath let p = url.parseUri.path let name = p.splitFile.name @@ -18,5 +30,10 @@ proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, app # note: old code used `destDir / .git` but that wouldn't prevent git clone # from failing exec fmt"git clone -q {url} {destDir2}" - exec fmt"git -C {destDir2} fetch -q" - exec fmt"git -C {destDir2} checkout -q {commit}" + if isGitRepo(destDir): + exec fmt"git -C {destDir2} fetch -q" + exec fmt"git -C {destDir2} checkout -q {commit}" + elif allowBundled: + discard "this dependency was bundled with Nim, don't do anything" + else: + quit "FAILURE: " & destdir & " already exists but is not a git repo" From e6616115e65381aaab427c557431d7992bb25063 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 26 Sep 2020 13:11:35 +0200 Subject: [PATCH 1152/4254] cursor inference: makes combparser work; refactorings (#15411) * cursor inference: makes combparser work; refactorings --- compiler/varpartitions.nim | 139 ++++++++++++++++--------------- testament/important_packages.nim | 2 +- tests/arc/topt_no_cursor.nim | 6 +- tests/arc/topt_refcursors.nim | 2 + 4 files changed, 78 insertions(+), 71 deletions(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 474a362cd..5af6e56b5 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -45,13 +45,17 @@ type dependsOn, isRootOf - VarIndex = object - flags: set[VarFlag] + Connection = object case kind: VarIndexKind of isEmptyRoot: discard of dependsOn: parent: int of isRootOf: graphIndex: int + + VarIndex = object + con: Connection + flags: set[VarFlag] sym: PSym + reassignedTo: int aliveStart, aliveEnd: int # the range for which the variable is alive. MutationInfo* = object @@ -96,60 +100,62 @@ proc hasSideEffect*(c: var Partitions; info: var MutationInfo): bool = template isConstParam(a): bool = a.kind == skParam and a.typ.kind != tyVar -proc variableId(c: Partitions; x: PSym): int {.inline.} = +proc variableId(c: Partitions; x: PSym): int = for i in 0 ..< c.s.len: if c.s[i].sym == x: return i return -1 +proc registerResult(c: var Partitions; n: PNode) = + if n.kind == nkSym: + c.s.add VarIndex(con: Connection(kind: isEmptyRoot), sym: n.sym, reassignedTo: 0, + aliveStart: high(int), aliveEnd: c.abstractTime) + +proc registerParam(c: var Partitions; n: PNode) = + assert n.kind == nkSym + if isConstParam(n.sym): + c.s.add VarIndex(con: Connection(kind: isRootOf, graphIndex: c.graphs.len), + sym: n.sym, reassignedTo: 0, + aliveStart: c.abstractTime, aliveEnd: c.abstractTime) + c.graphs.add MutationInfo(param: n.sym, mutatedHere: unknownLineInfo, + connectedVia: unknownLineInfo, flags: {connectsConstParam}, + maxMutation: -1, minConnection: high(int), + mutations: @[]) + else: + c.s.add VarIndex(con: Connection(kind: isEmptyRoot), sym: n.sym, reassignedTo: 0, + aliveStart: c.abstractTime, aliveEnd: c.abstractTime) + proc registerVariable(c: var Partitions; n: PNode) = if n.kind == nkSym and variableId(c, n.sym) < 0: - if isConstParam(n.sym): - c.s.add VarIndex(kind: isRootOf, graphIndex: c.graphs.len, sym: n.sym, - aliveStart: c.abstractTime, aliveEnd: c.abstractTime) - c.graphs.add MutationInfo(param: n.sym, mutatedHere: unknownLineInfo, - connectedVia: unknownLineInfo, flags: {connectsConstParam}, - maxMutation: -1, minConnection: high(int), - mutations: @[]) - elif n.sym.kind == skResult: - c.s.add VarIndex(kind: isEmptyRoot, sym: n.sym, - aliveStart: high(int), aliveEnd: c.abstractTime) - else: - c.s.add VarIndex(kind: isEmptyRoot, sym: n.sym, - aliveStart: c.abstractTime, aliveEnd: c.abstractTime) + c.s.add VarIndex(con: Connection(kind: isEmptyRoot), sym: n.sym, reassignedTo: 0, + aliveStart: c.abstractTime, aliveEnd: c.abstractTime) proc root(v: var Partitions; start: int): int = result = start var depth = 0 - while v.s[result].kind == dependsOn: - result = v.s[result].parent + while v.s[result].con.kind == dependsOn: + result = v.s[result].con.parent inc depth if depth > 0: # path compression: var it = start - while v.s[it].kind == dependsOn: - let next = v.s[it].parent - v.s[it] = VarIndex(kind: dependsOn, parent: result, - sym: v.s[it].sym, flags: v.s[it].flags, - aliveStart: v.s[it].aliveStart, - aliveEnd: v.s[it].aliveEnd) + while v.s[it].con.kind == dependsOn: + let next = v.s[it].con.parent + v.s[it].con = Connection(kind: dependsOn, parent: result) it = next proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = let id = variableId(v, s) if id >= 0: let r = root(v, id) - case v.s[r].kind + case v.s[r].con.kind of isEmptyRoot: - v.s[r] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len, - sym: v.s[r].sym, flags: v.s[r].flags, - aliveStart: v.s[r].aliveStart, - aliveEnd: v.s[r].aliveEnd) + v.s[r].con = Connection(kind: isRootOf, graphIndex: v.graphs.len) v.graphs.add MutationInfo(param: if isConstParam(s): s else: nil, mutatedHere: info, connectedVia: unknownLineInfo, flags: {isMutated}, maxMutation: v.abstractTime, minConnection: high(int), mutations: @[v.abstractTime]) of isRootOf: - let g = addr v.graphs[v.s[r].graphIndex] + let g = addr v.graphs[v.s[r].con.graphIndex] if g.param == nil and isConstParam(s): g.param = s if v.abstractTime > g.maxMutation: @@ -189,29 +195,24 @@ proc connect(v: var Partitions; a, b: PSym; info: TLineInfo) = var mut = 0 var con = v.abstractTime var gb: ptr MutationInfo = nil - if v.s[rb].kind == isRootOf: - gb = addr v.graphs[v.s[rb].graphIndex] + if v.s[rb].con.kind == isRootOf: + gb = addr v.graphs[v.s[rb].con.graphIndex] if param == nil: param = gb.param mutatedHere = gb.mutatedHere rbFlags = gb.flags mut = gb.maxMutation con = min(con, gb.minConnection) - v.s[rb] = VarIndex(kind: dependsOn, parent: ra, sym: v.s[rb].sym, flags: v.s[rb].flags, - aliveStart: v.s[rb].aliveStart, - aliveEnd: v.s[rb].aliveEnd) - case v.s[ra].kind + v.s[rb].con = Connection(kind: dependsOn, parent: ra) + case v.s[ra].con.kind of isEmptyRoot: - v.s[ra] = VarIndex(kind: isRootOf, graphIndex: v.graphs.len, sym: v.s[ra].sym, - flags: v.s[ra].flags, - aliveStart: v.s[ra].aliveStart, - aliveEnd: v.s[ra].aliveEnd) + v.s[ra].con = Connection(kind: isRootOf, graphIndex: v.graphs.len) v.graphs.add MutationInfo(param: param, mutatedHere: mutatedHere, connectedVia: info, flags: paramFlags + rbFlags, maxMutation: mut, minConnection: con, mutations: if gb != nil: gb.mutations else: @[]) of isRootOf: - var g = addr v.graphs[v.s[ra].graphIndex] + var g = addr v.graphs[v.s[ra].con.graphIndex] if g.param == nil: g.param = param if g.mutatedHere == unknownLineInfo: g.mutatedHere = mutatedHere g.minConnection = min(g.minConnection, con) @@ -376,15 +377,13 @@ proc noCursor(c: var Partitions, s: PSym) = if vid >= 0: c.s[vid].flags.incl preventCursor -proc rhsIsSink(c: var Partitions, n: PNode) = - if n.kind == nkSym and n.typ.skipTypes(abstractInst-{tyOwned}).kind == tyRef: - discard "do no pessimize simple refs further, injectdestructors.nim will prevent moving from it" - else: - var roots: seq[PSym] - allRoots(n, roots, followDotExpr = false) - # let x = cursor? --> treat it like a sink parameter - for r in roots: - noCursor(c, r) +proc pretendOwnsData(c: var Partitions, s: PSym) = + let vid = variableId(c, s) + if vid >= 0: + c.s[vid].flags.incl ownsData + +const + explainCursors = false proc deps(c: var Partitions; dest, src: PNode) = var targets, sources: seq[PSym] @@ -407,28 +406,29 @@ proc deps(c: var Partitions; dest, src: PNode) = let vid = variableId(c, dest.sym) if vid >= 0: destMightOwn(c, c.s[vid], src) - if src.kind == nkSym: - let s = src.sym - if {sfGlobal, sfThread} * s.flags != {} or hasDisabledAsgn(s.typ): + for s in sources: + if s == dest.sym: + discard "assignments like: it = it.next are fine" + elif {sfGlobal, sfThread} * s.flags != {} or hasDisabledAsgn(s.typ): # do not borrow from a global variable or from something with a # disabled assignment operator. c.s[vid].flags.incl preventCursor - when false: echo "A not a cursor: ", dest.sym, " ", s + when explainCursors: echo "A not a cursor: ", dest.sym, " ", s else: let srcid = variableId(c, s) if srcid >= 0: if s.kind notin {skResult, skParam} and ( c.s[srcid].aliveEnd < c.s[vid].aliveEnd): # you cannot borrow from a local that lives shorter than 'vid': - when false: echo "B not a cursor ", dest.sym, " ", c.s[srcid].aliveEnd, " ", c.s[vid].aliveEnd + when explainCursors: echo "B not a cursor ", dest.sym, " ", c.s[srcid].aliveEnd, " ", c.s[vid].aliveEnd c.s[vid].flags.incl preventCursor elif {isReassigned, preventCursor} * c.s[srcid].flags != {}: # you cannot borrow from something that is re-assigned: - when false: echo "C not a cursor ", dest.sym, " ", c.s[srcid].flags + when explainCursors: echo "C not a cursor ", dest.sym, " ", c.s[srcid].flags, " reassignedTo ", c.s[srcid].reassignedTo + c.s[vid].flags.incl preventCursor + elif c.s[srcid].reassignedTo != 0 and c.s[srcid].reassignedTo != dest.sym.id: + when explainCursors: echo "D not a cursor ", dest.sym, " reassignedTo ", c.s[srcid].reassignedTo c.s[vid].flags.incl preventCursor - - #if src.kind == nkSym and hasDestructor(src.typ): - # rhsIsSink(c, src) const nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit, @@ -501,7 +501,7 @@ proc traverse(c: var Partitions; n: PNode) = # we assume constructions with cursors are better without # the cursors because it's likely we can move then, see # test arc/topt_no_cursor.nim - noCursor(c, n[i].sym) + pretendOwnsData(c, n[i].sym) of nkObjConstr: for child in n: traverse(c, child) @@ -512,7 +512,7 @@ proc traverse(c: var Partitions; n: PNode) = # we assume constructions with cursors are better without # the cursors because it's likely we can move then, see # test arc/topt_no_cursor.nim - noCursor(c, it.sym) + pretendOwnsData(c, it.sym) of nkPragmaBlock: let pragmaList = n[0] @@ -562,7 +562,10 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = if n[0].kind == nkSym: let vid = variableId(c, n[0].sym) if vid >= 0: - c.s[vid].flags.incl isReassigned + if n[1].kind == nkSym and (c.s[vid].reassignedTo == 0 or c.s[vid].reassignedTo == n[1].sym.id): + c.s[vid].reassignedTo = n[1].sym.id + else: + c.s[vid].flags.incl isReassigned of nkSym: dec c.abstractTime @@ -616,9 +619,9 @@ proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partit if s.kind notin {skModule, skMacro}: let params = s.typ.n for i in 1.. Date: Sun, 27 Sep 2020 09:20:10 +0200 Subject: [PATCH 1153/4254] better support for slices as views (#15414) * moved view tests to tests/views * refactoring * more refactorings * better support for system.toOpenArray for first class view types --- compiler/ccgcalls.nim | 85 ++++++++++++--------- compiler/ccgexprs.nim | 12 ++- compiler/semexprs.nim | 10 ++- tests/{effects => views}/tcannot_borrow.nim | 0 tests/views/tsplit_into_openarray.nim | 37 +++++++++ tests/{ccgbugs => views}/tviews1.nim | 0 6 files changed, 100 insertions(+), 44 deletions(-) rename tests/{effects => views}/tcannot_borrow.nim (100%) create mode 100644 tests/views/tsplit_into_openarray.nim rename tests/{ccgbugs => views}/tviews1.nim (100%) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 6d254ca6f..31e5e5924 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -148,9 +148,52 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} = else: result = true -proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = - var a: TLoc +proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) = + var a, b, c: TLoc + initLocExpr(p, q[1], a) + initLocExpr(p, q[2], b) + initLocExpr(p, q[3], c) + # but first produce the required index checks: + if optBoundsCheck in p.options: + genBoundsCheck(p, a, b, c) + let ty = skipTypes(a.t, abstractVar+{tyPtr}) + let dest = getTypeDesc(p.module, destType) + let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)] + case ty.kind + of tyArray: + let first = toInt64(firstOrd(p.config, ty)) + if first == 0: + result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest], + lengthExpr) + else: + result = ("($4*)($1)+(($2)-($3))" % + [rdLoc(a), rdLoc(b), intLiteral(first), dest], + lengthExpr) + of tyOpenArray, tyVarargs: + if reifiedOpenArray(q[1]): + result = ("($3*)($1.d)+($2)" % [rdLoc(a), rdLoc(b), dest], + lengthExpr) + else: + result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest], + lengthExpr) + of tyUncheckedArray, tyCString: + result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest], + lengthExpr) + of tyString, tySequence: + let atyp = skipTypes(a.t, abstractInst) + if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and + optSeqDestructors in p.config.globalOptions: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + if atyp.kind in {tyVar} and not compileToCpp(p.module): + result = ("($4*)(*$1)$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest], + lengthExpr) + else: + result = ("($4*)$1$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest], + lengthExpr) + else: + internalError(p.config, "openArrayLoc: " & typeToString(a.t)) +proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = var q = skipConv(n) var skipped = false while q.kind == nkStmtListExpr and q.len > 0: @@ -164,42 +207,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = for i in 0.. Date: Sun, 27 Sep 2020 20:47:58 +0300 Subject: [PATCH 1154/4254] Fix proc generic params ident defs, missing empty (#15412) --- doc/astspec.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/astspec.txt b/doc/astspec.txt index ab2fbcacc..c41aee96f 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1255,7 +1255,9 @@ AST: nnkEmpty(), # patterns for term rewriting in templates and macros (not procs) nnkGenericParams( # generic type parameters, like with type declaration nnkIdentDefs( - nnkIdent("T"), nnkIdent("SomeInteger") + nnkIdent("T"), + nnkIdent("SomeInteger"), + nnkEmpty() ) ), nnkFormalParams( From f1ac01459cfecdaa26fd26128bb586236d4ba24e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 27 Sep 2020 20:44:22 +0200 Subject: [PATCH 1155/4254] produce runtime type information for reified openArrays (#15415) * produce runtime type information for reified openArrays * added a test case --- compiler/ccgcalls.nim | 7 ++++-- compiler/ccgexprs.nim | 22 ++++++++--------- compiler/ccgtypes.nim | 24 ++++++++++++++----- tests/views/tsplit_into_seq.nim | 42 +++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 tests/views/tsplit_into_seq.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 31e5e5924..6f0d327d9 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -171,7 +171,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, lengthExpr) of tyOpenArray, tyVarargs: if reifiedOpenArray(q[1]): - result = ("($3*)($1.d)+($2)" % [rdLoc(a), rdLoc(b), dest], + result = ("($3*)($1.Field0)+($2)" % [rdLoc(a), rdLoc(b), dest], lengthExpr) else: result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest], @@ -215,7 +215,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = case skipTypes(a.t, abstractVar).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(n): - result = "$1.d, $1.l" % [rdLoc(a)] + if a.t.kind in {tyVar, tyLent}: + result = "$1->Field0, $1->Field1" % [rdLoc(a)] + else: + result = "$1.Field0, $1.Field1" % [rdLoc(a)] else: result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f348a7e26..b6808a55e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -278,23 +278,23 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = case a.t.skipTypes(abstractVar).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(a.lode): - linefmt(p, cpsStmts, "$1.d = $2.d; $1.l = $2.l;$n", + linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n", [rdLoc(d), a.rdLoc]) else: - linefmt(p, cpsStmts, "$1.d = $2; $1.l = $2Len_0;$n", + linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n", [rdLoc(d), a.rdLoc]) of tySequence: - linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n", + linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n", [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)]) of tyArray: - linefmt(p, cpsStmts, "$1.d = $2; $1.l = $3;$n", + linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))]) of tyString: let etyp = skipTypes(a.t, abstractInst) if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n", + linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n", [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)]) else: internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind) @@ -943,7 +943,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = if reifiedOpenArray(arr.lode): linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)($3.l) || (NU)($2) >= (NU)($3.l))){ #raiseIndexError(); $4}$n", + "((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n", [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) else: linefmt(p, cpsStmts, @@ -977,11 +977,11 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) else: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.l)){ #raiseIndexError2($1,$2.l-1); $3}$n", + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.Field1)){ #raiseIndexError2($1,$2.Field1-1); $3}$n", [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, - ropecg(p.module, "$1.d[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + ropecg(p.module, "$1.Field0[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -1739,8 +1739,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") else: unaryExpr(p, e, d, "$1Len_0") else: - if op == mHigh: unaryExpr(p, e, d, "($1.l-1)") - else: unaryExpr(p, e, d, "$1.l") + if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)") + else: unaryExpr(p, e, d, "$1.Field1") of tyCString: if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") @@ -2218,7 +2218,7 @@ proc genDispose(p: BProc; n: PNode) = proc genSlice(p: BProc; e: PNode; d: var TLoc) = let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon) if d.k == locNone: getTemp(p, e.typ, d) - linefmt(p, cpsStmts, "$1.d = $2; $1.l = $3;$n", [rdLoc(d), x, y]) + linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y]) when false: localError(p.config, e.info, "invalid context for 'toOpenArray'; " & "'toOpenArray' is only valid within a call expression") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 771e1ede9..8dee6ee70 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -693,7 +693,7 @@ proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): result = getTypeName(m, t, sig) m.typeCache[sig] = result let elemType = getTypeDescWeak(m, t[0], check, kind) - m.s[cfsTypes].addf("typedef struct {$n$2* d;$nNI l;$n} $1;$n", + m.s[cfsTypes].addf("typedef struct {$n$2* Field0;$nNI Field1;$n} $1;$n", [result, elemType]) proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope = @@ -724,7 +724,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin compileToCpp(m): "&" else: "*" var et = origTyp.skipTypes(abstractInst).lastSon var etB = et.skipTypes(abstractInst) - if mapType(m.config, t, kind) == ctPtrToArray: + if mapType(m.config, t, kind) == ctPtrToArray and (etB.kind != tyOpenArray or kind == skParam): if etB.kind == tySet: et = getSysType(m.g.graph, unknownLineInfo, tyUInt8) else: @@ -1030,7 +1030,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; if tfIncompleteStruct in typ.flags: size = rope"void*" else: - size = getTypeDesc(m, origType) + size = getTypeDesc(m, origType, skVar) m.s[cfsTypeInit3].addf( "$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($2);$n$1.kind = $3;$n$1.base = $4;$n", [nameHcr, size, rope(nimtypeKind), base] @@ -1128,7 +1128,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; m.s[cfsTypeInit3].addf("$1.kind = 3;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" & - "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r, + "$1.len = $7;$n", [expr, getTypeDesc(m, origType, skVar), field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s), tmp, rope(L)]) @@ -1165,7 +1165,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; internalError(m.config, n.info, "genObjectFields") m.s[cfsTypeInit3].addf("$1.kind = 1;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & - "$1.name = $5;$n", [expr, getTypeDesc(m, origType), + "$1.name = $5;$n", [expr, getTypeDesc(m, origType, skVar), field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)]) else: internalError(m.config, n.info, "genObjectFields") @@ -1201,7 +1201,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) "$1.offset = offsetof($2, Field$3);$n" & "$1.typ = $4;$n" & "$1.name = \"Field$3\";$n", - [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfoV1(m, a, info)]) + [tmp2, getTypeDesc(m, origType, skVar), rope(i), genTypeInfoV1(m, a, info)]) m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", [expr, rope(typ.len), tmp]) else: @@ -1387,6 +1387,15 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = genTypeInfoV2Impl(m, t, origType, result, info) result = prefixTI.rope & result & ")".rope +proc openArrayToTuple(m: BModule; t: PType): PType = + result = newType(tyTuple, t.owner) + let p = newType(tyPtr, t.owner) + let a = newType(tyUncheckedArray, t.owner) + a.add t.lastSon + p.add a + result.add p + result.add getSysType(m.g.graph, t.owner.info, tyInt) + proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = let origType = t var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) @@ -1461,6 +1470,9 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = # BUGFIX: use consistently RTTI without proper field names; otherwise # results are not deterministic! genTupleInfo(m, t, origType, result, info) + of tyOpenArray: + let x = openArrayToTuple(m, t) + genTupleInfo(m, x, origType, result, info) else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')') if t.attachedOps[attachedDeepCopy] != nil: diff --git a/tests/views/tsplit_into_seq.nim b/tests/views/tsplit_into_seq.nim new file mode 100644 index 000000000..409451601 --- /dev/null +++ b/tests/views/tsplit_into_seq.nim @@ -0,0 +1,42 @@ +discard """ + output: '''asdf +asdf +231 +231 +''' + cmd: "nim c $file" +""" + +{.experimental: "views".} + +const + Whitespace = {' ', '\t', '\n', '\r'} + +proc split*(s: string, seps: set[char] = Whitespace, + maxsplit: int = -1): seq[openArray[char]] = + var last = 0 + var splits = maxsplit + result = @[] + + while last <= len(s): + var first = last + while last < len(s) and s[last] notin seps: + inc(last) + if splits == 0: last = len(s) + {.noSideEffect.}: + result.add toOpenArray(s, first, last-1) + result.add toOpenArray(s, first, last-1) + if splits == 0: break + dec(splits) + inc(last) + +proc `$`(x: openArray[char]): string = + result = newString(x.len) + for i in 0.. Date: Mon, 28 Sep 2020 10:51:13 +0200 Subject: [PATCH 1156/4254] cleanup lib/system/stacktraces.nim; refs #15416 (#15418) --- lib/system.nim | 6 ------ lib/system/stacktraces.nim | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index a9c45f8fa..0784cacce 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1410,12 +1410,6 @@ type # these work for most platforms: culonglong* {.importc: "unsigned long long", nodecl.} = uint64 ## This is the same as the type ``unsigned long long`` in *C*. - # There is a disparity on macOS where Nim's `uint` is `unsigned long long` and - # `uintptr_t` is `unsigned long`. Even though both data types are the same - # size (64 bits), clang++ refuses to do automatic conversion between them. - cuintptr_t* {.importc: "uintptr_t", nodecl.} = uint - ## This is the same as the type ``uintptr_t`` in *C*. - cstringArray* {.importc: "char**", nodecl.} = ptr UncheckedArray[cstring] ## This is binary compatible to the type ``char**`` in *C*. The array's ## high value is large enough to disable bounds checking in practice. diff --git a/lib/system/stacktraces.nim b/lib/system/stacktraces.nim index 62de27260..6c7b1433c 100644 --- a/lib/system/stacktraces.nim +++ b/lib/system/stacktraces.nim @@ -18,7 +18,7 @@ const when defined(nimStackTraceOverride): ## Procedure types for overriding the default stack trace. type - cuintptr_t {.importc: "uintptr_t", nodecl.} = uint + cuintptr_t* {.importc: "uintptr_t", nodecl.} = uint ## This is the same as the type ``uintptr_t`` in C. StackTraceOverrideGetTracebackProc* = proc (): string {. From 50b6f6996ab604931d8ee7ca2a26bfdce5559933 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 28 Sep 2020 13:51:39 +0200 Subject: [PATCH 1157/4254] .noalias annotation; frontend support (#15419) * .noalias annotation; frontend support * added .noalias support to Nim; implements https://github.com/nim-lang/RFCs/issues/204 --- changelog.md | 5 ++++- compiler/ast.nim | 5 +++-- compiler/ccgtypes.nim | 2 ++ compiler/cgen.nim | 3 +++ compiler/pragmas.nim | 8 ++++++-- compiler/semtypes.nim | 10 ++++++---- compiler/wordrecg.nim | 4 ++-- doc/manual_experimental.rst | 15 +++++++++++++++ lib/impure/nre.nim | 2 +- lib/nimbase.h | 3 +++ tests/ccgbugs/tnoalias.nim | 8 ++++++++ 11 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 tests/ccgbugs/tnoalias.nim diff --git a/changelog.md b/changelog.md index bd5674610..fffcdcb35 100644 --- a/changelog.md +++ b/changelog.md @@ -195,7 +195,7 @@ is cool! """ - ``` + ``` - Add `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. @@ -283,6 +283,9 @@ proc mydiv(a, b): int {.raises: [].} = an experimental feature. In other words, you don't have to write pragma `{.experimental: "forLoopMacros".}` if you want to use them. +- Added a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased + performance this keyword can enable. + ## Compiler changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 4d37b284c..6bcc6845d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -229,7 +229,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 43 flags! + TSymFlag* = enum # 46 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -293,7 +293,8 @@ type sfNeverRaises # proc can never raise an exception, not even OverflowDefect # or out-of-memory sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' - sfSingleUsedTemp # For temporaries that we know will only be used once + sfSingleUsedTemp # For temporaries that we know will only be used once + sfNoalias # 'noalias' annotation, means C's 'restrict' TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8dee6ee70..ff7b17590 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -474,6 +474,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, else: params.add(getTypeDescAux(m, param.typ, check, skParam)) params.add(~" ") + if sfNoalias in param.flags: + params.add(~"NIM_NOALIAS ") params.add(param.loc.r) # declare the len field for open arrays: var arr = param.typ diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 242d1f89b..f50676647 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -503,6 +503,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope = #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # decl.add(" GC_GUARD") if sfVolatile in s.flags: result.add(" volatile") + if sfNoalias in s.flags: result.add(" NIM_NOALIAS") result.add(" ") result.add(s.loc.r) else: @@ -563,6 +564,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = if p.hcrOn: decl.add("*") if sfRegister in s.flags: decl.add(" register") if sfVolatile in s.flags: decl.add(" volatile") + if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") if value != nil: decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: @@ -1261,6 +1263,7 @@ proc genVarPrototype(m: BModule, n: PNode) = if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") if sfRegister in sym.flags: m.s[cfsVars].add(" register") if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile") + if sfNoalias in sym.flags: m.s[cfsVars].add(" NIM_NOALIAS") m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) if m.hcrOn: m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 71bd6f81f..3b7ae175d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -65,14 +65,15 @@ const wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wBorrow, wGcSafe, wPartial, wExplain, wPackage} fieldPragmas* = declPragmas + { - wGuard, wBitsize, wCursor, wRequiresInit} - {wExportNims, wNodecl} # why exclude these? + wGuard, wBitsize, wCursor, wRequiresInit, wNoalias} - {wExportNims, wNodecl} # why exclude these? varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar, wMagic, wHeader, wCompilerProc, wCore, wDynlib, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor} + wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wNoalias} constPragmas* = declPragmas + {wHeader, wMagic, wGensym, wInject, wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore} + paramPragmas* = {wNoalias, wInject, wGensym} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, wThread, wRaises, wLocks, wTags, wGcSafe, @@ -864,6 +865,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wRegister: noVal(c, it) incl(sym.flags, sfRegister) + of wNoalias: + noVal(c, it) + incl(sym.flags, sfNoalias) of wThreadVar: noVal(c, it) incl(sym.flags, {sfThread, sfGlobal}) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4d912a46f..9bb7673fa 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1264,6 +1264,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, for j in 0.. Date: Mon, 28 Sep 2020 22:54:17 -0700 Subject: [PATCH 1158/4254] document that items no longer works with enum with holes (#15426) --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index fffcdcb35..474f1eae1 100644 --- a/changelog.md +++ b/changelog.md @@ -286,6 +286,7 @@ proc mydiv(a, b): int {.raises: [].} = - Added a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased performance this keyword can enable. +- `items` no longer compiles with enum with holes as its behavior was error prone, see #14004 ## Compiler changes From 22d0a3993268c334e62461f39ef02b1d02c64ca1 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Tue, 29 Sep 2020 17:55:53 +0300 Subject: [PATCH 1159/4254] Dont assert on setstacksize result in iOS (#15427) [backport:1.2] --- lib/system/threads.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index bf93b5e01..cd1cf5e29 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -319,7 +319,10 @@ else: when hasSharedHeap: t.core.stackSize = ThreadStackSize var a {.noinit.}: Pthread_attr doAssert pthread_attr_init(a) == 0 - doAssert pthread_attr_setstacksize(a, ThreadStackSize) == 0 + let setstacksizeResult = pthread_attr_setstacksize(a, ThreadStackSize) + when not defined(ios): + # This fails on iOS + doAssert(setstacksizeResult == 0) if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0: raise newException(ResourceExhaustedError, "cannot create thread") doAssert pthread_attr_destroy(a) == 0 From f8866598e7e0226aac7a6720adf4440278f9508d Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Tue, 29 Sep 2020 16:08:24 +0100 Subject: [PATCH 1160/4254] odbc regression from #14357 (#15417) #14357 changed from sending 'val', an int, to a pointer to int, which is understandable, but not how SQLSetEnvAttr works. "Depending on the value of Attribute, ValuePtr will be a 32-bit integer value or point to a null-terminated character string" --- lib/impure/db_odbc.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 8aadfae73..3568cf1cc 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -508,7 +508,7 @@ proc open*(connection, user, password, database: string): DbConn {. if res != SQL_SUCCESS: dbError("Error: unable to initialise ODBC environment.") res = SQLSetEnvAttr(result.env, SQL_ATTR_ODBC_VERSION.TSqlInteger, - cast[SqlPointer](val.addr), resLen.TSqlInteger) + cast[SqlPointer](val), resLen.TSqlInteger) if res != SQL_SUCCESS: dbError("Error: unable to set ODBC driver version.") # allocate hDb handle res = SQLAllocHandle(SQL_HANDLE_DBC, result.env, result.hDb) From 4058801607b37fa707eb1b41d129ce74557eccac Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 29 Sep 2020 23:42:38 +0200 Subject: [PATCH 1161/4254] spec for view types (#15424) * spec for view types * spec additions * refactoring; there are two different kinds of views * refactorings and spec additions * enforce that view types are initialized * enforce borrowing from the first formal parameter * enforce lifetimes for borrowing of locals * typo in the manual * clarify in the implementation what a borrow operation really is --- compiler/ast.nim | 3 - compiler/semexprs.nim | 6 +- compiler/sempass2.nim | 4 +- compiler/typeallowed.nim | 75 +++++-- compiler/varpartitions.nim | 196 ++++++++++++++++-- doc/manual.rst | 8 +- doc/manual_experimental.rst | 190 ++++++++++++++++- tests/views/tcannot_borrow.nim | 13 +- .../tmust_borrow_from_first_parameter.nim | 9 + tests/views/tsplit_into_seq.nim | 5 +- tests/views/tviews1.nim | 3 +- 11 files changed, 446 insertions(+), 66 deletions(-) create mode 100644 tests/views/tmust_borrow_from_first_parameter.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 6bcc6845d..8adbfa15c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1403,9 +1403,6 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType = proc exactReplica*(t: PType): PType = copyType(t, t.owner, true) -template requiresInit*(t: PType): bool = - t.flags * {tfRequiresInit, tfNotNil} != {} - proc copySym*(s: PSym): PSym = result = newSym(s.kind, s.name, s.owner, s.info, s.options) #result.ast = nil # BUGFIX; was: s.ast which made problems diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e26ea42dd..cb852c68a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1601,7 +1601,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le[0] - if (x.typ.kind in {tyVar, tyLent} or isViewType(x.typ)) and x.kind == nkSym and x.sym.kind == skResult: + if (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView) and x.kind == nkSym and x.sym.kind == skResult: n[0] = x # 'result[]' --> 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr @@ -1712,8 +1712,8 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if le == nil: localError(c.config, a.info, "expression has no type") elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and - isAssignable(c, a) in {arNone, arLentValue}) or - skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: + isAssignable(c, a) in {arNone, arLentValue}) or ( + skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features): # Direct assignment to a discriminant is allowed! localError(c.config, a.info, errXCannotBeAssignedTo % renderTree(a, {renderNoComments})) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 797aff7f7..d591da855 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, varpartitions + modulegraphs, varpartitions, typeallowed when defined(useDfa): import dfa @@ -1244,7 +1244,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = var mutationInfo = MutationInfo() if {strictFuncs, views} * c.features != {}: - var partitions = computeGraphPartitions(s, body) + var partitions = computeGraphPartitions(s, body, g.config) if not t.hasSideEffect and t.hasDangerousAssign: t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) if views in c.features: diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 651a21ade..aabaa46dd 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -187,42 +187,77 @@ proc typeAllowed*(t: PType, kind: TSymKind; c: PContext; flags: TTypeAllowedFlag var marker = initIntSet() result = typeAllowedAux(marker, t, kind, c, flags) -proc isViewTypeAux(marker: var IntSet, t: PType): bool +type + ViewTypeKind* = enum + noView, immutableView, mutableView -proc isViewTypeNode(marker: var IntSet, n: PNode): bool = +proc combine(dest: var ViewTypeKind, b: ViewTypeKind) {.inline.} = + case dest + of noView, mutableView: + dest = b + of immutableView: + if b == mutableView: dest = b + +proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind + +proc classifyViewTypeNode(marker: var IntSet, n: PNode): ViewTypeKind = case n.kind of nkSym: - result = isViewTypeAux(marker, n.typ) + result = classifyViewTypeAux(marker, n.typ) of nkOfBranch: - result = isViewTypeNode(marker, n.lastSon) + result = classifyViewTypeNode(marker, n.lastSon) else: + result = noView for child in n: - result = isViewTypeNode(marker, child) - if result: break + result.combine classifyViewTypeNode(marker, child) + if result == mutableView: break -proc isViewTypeAux(marker: var IntSet, t: PType): bool = - if containsOrIncl(marker, t.id): return false +proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind = + if containsOrIncl(marker, t.id): return noView case t.kind - of tyVar, tyLent, tyVarargs, tyOpenArray: - result = true + of tyVar: + result = mutableView + of tyLent, tyVarargs, tyOpenArray: + result = immutableView of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned, - tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic, tyFromExpr: - result = isViewTypeAux(marker, lastSon(t)) + tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic: + result = classifyViewTypeAux(marker, lastSon(t)) + of tyFromExpr: + if t.len > 0: + result = classifyViewTypeAux(marker, lastSon(t)) + else: + result = noView of tyTuple: + result = noView for i in 0.. 1: + if (n.typ != nil and classifyViewType(n.typ) != noView) or getMagic(n) == mSlice: + n = n[1] + else: + break + else: + break + else: + break + # borrowFromConstExpr(n) is correct here because we need 'node' + # stripped off the path suffixes: + if result == nil and borrowFromConstExpr(n): + result = n + proc allRoots(n: PNode; result: var seq[PSym]; followDotExpr = true) = case n.kind of nkSym: @@ -385,13 +478,57 @@ proc pretendOwnsData(c: var Partitions, s: PSym) = const explainCursors = false +proc borrowFrom(c: var Partitions; dest: PSym; src: PNode) = + const + url = "; see https://nim-lang.github.io/Nim/manual_experimental.html#view-types-algorithm-path-expressions for details" + + let s = pathExpr(src, c.owner) + if s == nil: + localError(c.config, src.info, "cannot borrow from " & $src & ", it is not a path expression; " & url) + elif s.kind == nkSym: + if dest.kind == skResult: + if s.sym.kind != skParam or s.sym.position != 0: + localError(c.config, src.info, "'result' must borrow from the first parameter") + + let vid = variableId(c, dest) + if vid >= 0: + var sourceIdx = variableId(c, s.sym) + if sourceIdx < 0: + sourceIdx = c.s.len + c.s.add VarIndex(con: Connection(kind: isEmptyRoot), sym: s.sym, reassignedTo: 0, + aliveStart: MinTime, aliveEnd: MaxTime) + + c.s[vid].borrowsFrom.add sourceIdx + else: + discard "a valid borrow location that is a deeply constant expression so we have nothing to track" + + +proc borrowingCall(c: var Partitions; destType: PType; n: PNode; i: int) = + let v = pathExpr(n[i], c.owner) + if v.kind == nkSym: + for j in i+1..= 0: + for b in par.s[rid].borrowsFrom: + let sid = root(par, b) + if sid >= 0: + if par.s[sid].con.kind == isRootOf and dangerousMutation(par.graphs[par.s[sid].con.graphIndex], par.s[i]): + cannotBorrow(config, v, par.graphs[par.s[sid].con.graphIndex]) + if par.s[sid].sym.kind != skParam and par.s[sid].aliveEnd < par.s[rid].aliveEnd: + localError(config, v.info, "'" & v.name.s & "' borrows from location '" & par.s[sid].sym.name.s & + "' which does not live long enough") + + #if par.s[rid].con.kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].con.graphIndex], par.s[i]): + # cannotBorrow(config, s, par.graphs[par.s[rid].con.graphIndex]) proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = - var par = computeGraphPartitions(s, n, true) + var par = computeGraphPartitions(s, n, config, true) for i in 0 ..< par.s.len: let v = addr(par.s[i]) if v.flags * {ownsData, preventCursor} == {} and v.sym.kind notin {skParam, skResult} and diff --git a/doc/manual.rst b/doc/manual.rst index 8c167bf62..11ea6b99c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -655,7 +655,7 @@ Precedence level Operators First ================ ======================================================= ================== =============== -Whether an operator is used a prefix operator is also affected by preceding +Whether an operator is used as a prefix operator is also affected by preceding whitespace (this parsing change was introduced with version 0.13.0): .. code-block:: nim @@ -3275,16 +3275,16 @@ programming and are inherently unsafe. .. code-block:: nim cast[int](x) - + The target type of a cast must be a concrete type, for instance, a target type that is a type class (which is non-concrete) would be invalid: .. code-block:: nim type Foo = int or float var x = cast[Foo](1) # Error: cannot cast to a non concrete type: 'Foo' - + Type casts should not be confused with *type conversions,* as mentioned in the -prior section. Unlike type conversions, a type cast cannot change the underlying +prior section. Unlike type conversions, a type cast cannot change the underlying bit pattern of the data being casted (aside from that the size of the target type may differ from the source type). Casting resembles *type punning* in other languages or C++'s ``reinterpret_cast`` and ``bit_cast`` features. diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 459139f94..abb699d1f 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1814,18 +1814,49 @@ For example: # an object reachable from 'n' is potentially mutated -The algorithm behind this analysis is currently not documented. +The algorithm behind this analysis is described in +the `view types section <#view-types-algorithm>`_. View types ========== -A view type is a type that contains one of the following types: +**Note**: ``--experimental:views`` is more effective +with ``--experimental:strictFuncs``. + +A view type is a type that is or contains one of the following types: - ``var T`` (mutable view into ``T``) - ``lent T`` (immutable view into ``T``) - ``openArray[T]`` (pair of (pointer to array of ``T``, size)) +For example: + +.. code-block:: nim + + type + View1 = var int + View2 = openArray[byte] + View3 = lent string + View4 = Table[openArray[char], int] + + +Exceptions to this rule are types constructed via ``ptr`` or ``proc``. +For example, the following types are **not** view types: + +.. code-block:: nim + + type + NotView1 = proc (x: openArray[int]) + NotView2 = ptr openArray[char] + NotView3 = ptr array[4, var int] + + +A *mutable* view type is a type that is or contains a ``var T`` type. +An *immutable* view type is a view type that is not a mutable view type. + +A *view* is a symbol (a let, var, const, etc.) that has a view type. + Since version 1.4 Nim allows view types to be used as local variables. This feature needs to be enabled via ``{.experimental: "views".}``. @@ -1860,10 +1891,159 @@ For example: main(@[11, 22, 33]) +A local variable of a view type can borrow from a location +derived from a parameter, another local variable, a global ``const`` or ``let`` +symbol or a thread-local ``var`` or ``let``. -If a view type is used as a return type, the location must borrow from the -first parameter that is passed to the proc. +Let ``p`` the proc that is analysed for the correctness of the borrow operation. + +Let ``source`` be one of: + +- A formal parameter of ``p``. Note that this does not cover parameters of + inner procs. +- The ``result`` symbol of ``p``. +- A local ``var`` or ``let`` or ``const`` of ``p``. Note that this does + not cover locals of inner procs. +- A thread-local ``var`` or ``let``. +- A global ``let`` or ``const``. +- A constant arraq/seq/object/tuple constructor. + + +Path expressions +---------------- + +A location derived from ``source`` is then defined as a path expression that +has ``source`` as the owner. A path expression ``e`` is defined recursively: + +- ``source`` itself is a path expression. +- Container access like ``e[i]`` is a path expression. +- Tuple access ``e[0]`` is a path expression. +- Object field access ``e.field`` is a path expression. +- ``system.toOpenArray(e, ...)`` is a path expression. +- Pointer dereference ``e[]`` is a path expression. +- An address ``addr e``, ``unsafeAddr e`` is a path expression. +- A type conversion ``T(e)`` is a path expression. +- A cast expression ``cast[T](e)`` is a path expression. +- ``f(e, ...)`` is a path expression if ``f``'s return type is a view type. + Because the view can only have been borrowed from ``e``, we then know + that owner of ``f(e, ...)`` is ``e``. + + +If a view type is used as a return type, the location must borrow from a location +that is derived from the first parameter that is passed to the proc. See https://nim-lang.org/docs/manual.html#procedures-var-return-type for details about how this is done for ``var T``. -The algorithm behind this analysis is currently not documented. +A mutable view can borrow from a mutable location, an immutable view can borrow +from both a mutable or an immutable location. + +The *duration* of a borrow is the span of commands beginning from the assignment +to the view and ending with the last usage of the view. + +For the duration of the borrow operation, no mutations to the borrowed locations +may be performed except via the potentially mutable view that borrowed from the +location. The borrowed location is said to be *sealed* during the borrow. + +.. code-block:: nim + + {.experimental: "views".} + + type + Obj = object + field: string + + proc dangerous(s: var seq[Obj]) = + let v: lent Obj = s[0] # seal 's' + s.setLen 0 # prevented at compile-time because 's' is sealed. + echo v.field + + +The scope of the view does not matter: + +.. code-block:: nim + + proc valid(s: var seq[Obj]) = + let v: lent Obj = s[0] # begin of borrow + echo v.field # end of borrow + s.setLen 0 # valid because 'v' isn't used afterwards + + +The analysis requires as much precision about mutations as is reasonably obtainable, +so it is more effective with the experimental `strict funcs <#strict-funcs>`_ +feature. In other words ``--experimental:views`` works better +with ``--experimental:strictFuncs``. + +The analysis is currently control flow insensitive: + +.. code-block:: nim + + proc invalid(s: var seq[Obj]) = + let v: lent Obj = s[0] + if false: + s.setLen 0 + echo v.field + +In this example, the compiler assumes that ``s.setLen 0`` invalidates the +borrow operation of ``v`` even though a human being can easily see that it +will never do that at runtime. + + +Reborrows +--------- + +A view ``v`` can borrow from multiple different locations. However, the borrow +is always the full span of ``v``'s lifetime and every location that is borrowed +from is sealed during ``v``'s lifetime. + + +Algorithm +--------- + +The following section is an outline of the algorithm that the current implementation +uses. The algorithm performs two traversals over the AST of the procedure or global +section of code that uses a view variable. No fixpoint iterations are performed, the +complexity of the analysis is O(N) where N is the number of nodes of the AST. + +The first pass over the AST computes the lifetime of each local variable based on +a notion of an "abstract time", in the implementation it's a simple integer that is +incremented for every visited node. + +In the second pass information about the underlying object "graphs" is computed. +Let ``v`` be a parameter or a local variable. Let ``G(v)`` be the graph +that ``v`` belongs to. A graph is defined by the set of variables that belong +to the graph. Initially for all ``v``: ``G(v) = {v}``. Every variable can only +be part of a single graph. + +Assignments like ``a = b`` "connect" two variables, both variables end up in the +same graph ``{a, b} = G(a) = G(b)``. Unfortunately, the pattern to look for is +much more complex than that and can involve multiple assignment targets +and sources:: + + f(x, y) = g(a, b) + +connects ``x`` and ``y`` to ``a`` and ``b``: ``G(x) = G(y) = G(a) = G(b) = {x, y, a, b}``. +A type based alias analysis rules out some of these combinations, for example +a ``string`` value cannot possibly be connected to a ``seq[int]``. + +A pattern like ``v[] = value`` or ``v.field = value`` marks ``G(v)`` as mutated. +After the second pass a set of disjoint graphs was computed. + +For strict functions it is then enforced that there is no graph that is both mutated +and has an element that is an immutable parameter (that is a parameter that is not +of type ``var T``). + +For borrow checking a different set of checks is performed. Let ``v`` be the view +and ``b`` the location that is borrowed from. + +- The lifetime of ``v`` must not exceed ``b``'s lifetime. Note: The lifetime of + a parameter is the complete proc body. +- If ``v`` is a mutable view and ``v`` is used to actually mutate the + borrowed location, then ``b`` has to be a mutable location. + Note: If it is not actually used for mutation, borrowing a mutable view from an + immutable location is allowed! This allows for many important idioms and will be + justified in an upcoming RFC. +- During ``v``'s lifetime, ``G(b)`` can only be modified by ``v`` (and only if + ``v`` is a mutable view). +- If ``v`` is ``result`` then ``b`` has to be a location derived from the first + formal parameter or from a constant location. +- A view cannot be used for a read or a write access before it was assigned to. diff --git a/tests/views/tcannot_borrow.nim b/tests/views/tcannot_borrow.nim index 699176b04..d1c194b25 100644 --- a/tests/views/tcannot_borrow.nim +++ b/tests/views/tcannot_borrow.nim @@ -1,17 +1,22 @@ discard """ errormsg: "cannot borrow" - nimout: '''tcannot_borrow.nim(16, 7) Error: cannot borrow meh; what it borrows from is potentially mutated -tcannot_borrow.nim(17, 3) the mutation is here -tcannot_borrow.nim(16, 7) is the statement that connected the mutation to the parameter''' - line: 16 + nimout: '''tcannot_borrow.nim(21, 7) Error: cannot borrow meh; what it borrows from is potentially mutated +tcannot_borrow.nim(22, 3) the mutation is here''' + line: 21 """ + {.experimental: "views".} type Foo = object field: string +proc valid(s: var seq[Foo]) = + let v: lent Foo = s[0] # begin of borrow + echo v.field # end of borrow + s.setLen 0 # valid because 'v' isn't used afterwards + proc dangerous(s: var seq[Foo]) = let meh: lent Foo = s[0] s.setLen 0 diff --git a/tests/views/tmust_borrow_from_first_parameter.nim b/tests/views/tmust_borrow_from_first_parameter.nim new file mode 100644 index 000000000..b2decfb38 --- /dev/null +++ b/tests/views/tmust_borrow_from_first_parameter.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "'result' must borrow from the first parameter" + line: 9 +""" + +{.experimental: "views".} + +proc p(a, b: openArray[char]): openArray[char] = + result = b diff --git a/tests/views/tsplit_into_seq.nim b/tests/views/tsplit_into_seq.nim index 409451601..49968f4c2 100644 --- a/tests/views/tsplit_into_seq.nim +++ b/tests/views/tsplit_into_seq.nim @@ -23,9 +23,8 @@ proc split*(s: string, seps: set[char] = Whitespace, while last < len(s) and s[last] notin seps: inc(last) if splits == 0: last = len(s) - {.noSideEffect.}: - result.add toOpenArray(s, first, last-1) - result.add toOpenArray(s, first, last-1) + result.add toOpenArray(s, first, last-1) + result.add toOpenArray(s, first, last-1) if splits == 0: break dec(splits) inc(last) diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index 3ce0bb6d8..51f17b9d6 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -4,6 +4,7 @@ discard """ 33 3 2 +3 3''' targets: "c cpp" """ @@ -22,6 +23,6 @@ proc main(s: seq[int]) = take(x.toOpenArray(0, 1)) let y = x take y - + take x main(@[11, 22, 33]) From eb2a4961c71029c874ebdacd1b23a349eb8e61d5 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 29 Sep 2020 23:43:12 +0200 Subject: [PATCH 1162/4254] various documentation fixes [backport] (#15422) --- lib/impure/nre.nim | 8 ++++---- lib/pure/strutils.nim | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 12ea7ab56..4696f7322 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -539,7 +539,7 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt raise RegexInternalError(msg: "Unknown internal error: " & $execRet) proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] = - ## Like ` ``find(...)`` <#proc-find>`_, but anchored to the start of the + ## Like `find(...)<#find,string,Regex,int>`_, but anchored to the start of the ## string. ## runnableExamples: @@ -549,11 +549,11 @@ proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[R return str.matchImpl(pattern, start, endpos, pcre.ANCHORED) iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): RegexMatch = - ## Works the same as ` ``find(...)`` <#proc-find>`_, but finds every + ## Works the same as `find(...)<#find,string,Regex,int>`_, but finds every ## non-overlapping match. ``"2222".find(re"22")`` is ``"22", "22"``, not ## ``"22", "22", "22"``. ## - ## Arguments are the same as ` ``find(...)`` <#proc-find>`_ + ## Arguments are the same as `find(...)<#find,string,Regex,int>`_ ## ## Variants: ## @@ -632,7 +632,7 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] ## Splits the string with the given regex. This works according to the ## rules that Perl and Javascript use. ## - ## ``start`` behaves the same as in ` ``find(...)`` <#proc-find>`_. + ## ``start`` behaves the same as in `find(...)<#find,string,Regex,int>`_. ## runnableExamples: # - If the match is zero-width, then the string is still split: diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index d97ed9a07..20ad2f517 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1930,7 +1930,7 @@ proc initSkipTable*(a: var SkipTable, sub: string) proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {.noSideEffect, rtl, extern: "nsuFindStrA".} = - ## Searches for `sub` in `s` inside range `start`..`last` using preprocessed + ## Searches for `sub` in `s` inside range `start..last` using preprocessed ## table `a`. If `last` is unspecified, it defaults to `s.high` (the last ## element). ## From 9c86f4867e8475e38e1e8fb026b9cfd1555271a8 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 30 Sep 2020 16:52:49 +0800 Subject: [PATCH 1163/4254] fix doc search(escape HTML code) (#15433) * use release version * fix doc search --- tools/dochack/dochack.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 4c4db4638..471212a50 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -267,6 +267,19 @@ var template normalize(x: cstring): cstring = x.toLower.replace("_", "") +proc escapeCString(x: var cstring) = + var s = "" + for c in x: + case c + of '&': s.add("&") + of '<': s.add("<") + of '>': s.add(">") + of '"': s.add(""") + of '\'': s.add("'") + of '/': s.add("/") + else: s.add(c) + x = s.cstring + proc dosearch(value: cstring): Element = if db.len == 0: var stuff: Element @@ -305,6 +318,7 @@ proc dosearch(value: cstring): Element = matches.sort(proc(a, b: auto): int = b[1] - a[1]) for i in 0 ..< min(matches.len, 29): matches[i][0].innerHTML = matches[i][0].getAttribute("data-doc-search-tag") + escapeCString(matches[i][0].innerHTML) ul.add(tree("LI", cast[Element](matches[i][0]))) if ul.len == 0: result.add tree("B", text"no search results") From 86d7b63e2ae7177061ff13d7b4cf32ba512f22f6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 30 Sep 2020 20:44:18 +0200 Subject: [PATCH 1164/4254] better support for view types (#15436) * you can put borrows into tables * enforces mutating views only mutate mutable data --- compiler/ccgcalls.nim | 6 ++-- compiler/typeallowed.nim | 2 +- compiler/varpartitions.nim | 54 ++++++++++++++++++++++++++----- tests/views/tdont_mutate.nim | 48 +++++++++++++++++++++++++++ tests/views/tsplit_into_table.nim | 40 +++++++++++++++++++++++ 5 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 tests/views/tdont_mutate.nim create mode 100644 tests/views/tsplit_into_table.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 6f0d327d9..6c5b721c7 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -142,8 +142,10 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, proc genBoundsCheck(p: BProc; arr, a, b: TLoc) proc reifiedOpenArray(n: PNode): bool {.inline.} = - let x = trees.getRoot(n) - if x != nil and x.kind == skParam: + var x = n + while x.kind in {nkAddr, nkHiddenAddr, nkHiddenStdConv, nkHiddenDeref}: + x = x[0] + if x.kind == nkSym and x.sym.kind == skParam: result = false else: result = true diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index aabaa46dd..13eff35be 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -121,7 +121,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t of tyOpenArray: # you cannot nest openArrays/sinks/etc. - if (kind != skParam and views notin c.features) or taIsOpenArray in flags: + if (kind != skParam or taIsOpenArray in flags) and views notin c.features: result = t else: result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray}) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 2047a90e1..1fb4bd93e 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -54,7 +54,9 @@ type VarFlag = enum ownsData, preventCursor, - isReassigned + isReassigned, + viewDoesMutate, + viewBorrowsFromConst VarIndexKind = enum isEmptyRoot, @@ -478,9 +480,12 @@ proc pretendOwnsData(c: var Partitions, s: PSym) = const explainCursors = false +proc isConstSym(s: PSym): bool = + result = s.kind in {skConst, skLet} or isConstParam(s) + proc borrowFrom(c: var Partitions; dest: PSym; src: PNode) = const - url = "; see https://nim-lang.github.io/Nim/manual_experimental.html#view-types-algorithm-path-expressions for details" + url = "see https://nim-lang.github.io/Nim/manual_experimental.html#view-types-algorithm-path-expressions for details" let s = pathExpr(src, c.owner) if s == nil: @@ -499,28 +504,50 @@ proc borrowFrom(c: var Partitions; dest: PSym; src: PNode) = aliveStart: MinTime, aliveEnd: MaxTime) c.s[vid].borrowsFrom.add sourceIdx + if isConstSym(s.sym): + c.s[vid].flags.incl viewBorrowsFromConst else: - discard "a valid borrow location that is a deeply constant expression so we have nothing to track" + let vid = variableId(c, dest) + if vid >= 0: + c.s[vid].flags.incl viewBorrowsFromConst + #discard "a valid borrow location that is a deeply constant expression so we have nothing to track" proc borrowingCall(c: var Partitions; destType: PType; n: PNode; i: int) = let v = pathExpr(n[i], c.owner) - if v.kind == nkSym: + if v != nil and v.kind == nkSym: + when false: + let isView = directViewType(destType) == immutableView + if n[0].kind == nkSym and n[0].sym.name.s == "[]=": + localError(c.config, n[i].info, "attempt to mutate an immutable view") + for j in i+1..= 0: + c.s[vid].flags.incl viewDoesMutate + of immutableView: + localError(c.config, dest.info, "attempt to mutate a borrowed location from an immutable view") + of noView: discard "nothing to do" proc deps(c: var Partitions; dest, src: PNode) = if not c.performCursorInference: - trackBorrow(c, dest, src) + borrowingAsgn(c, dest, src) var targets, sources: seq[PSym] allRoots(dest, targets) @@ -801,6 +828,7 @@ proc checkBorrowedLocations*(par: var Partitions; body: PNode; config: ConfigRef if v.kind != skParam and classifyViewType(v.typ) != noView: let rid = root(par, i) if rid >= 0: + var constViolation = false for b in par.s[rid].borrowsFrom: let sid = root(par, b) if sid >= 0: @@ -809,6 +837,16 @@ proc checkBorrowedLocations*(par: var Partitions; body: PNode; config: ConfigRef if par.s[sid].sym.kind != skParam and par.s[sid].aliveEnd < par.s[rid].aliveEnd: localError(config, v.info, "'" & v.name.s & "' borrows from location '" & par.s[sid].sym.name.s & "' which does not live long enough") + if viewDoesMutate in par.s[rid].flags and isConstSym(par.s[sid].sym): + localError(config, v.info, "'" & v.name.s & "' borrows from the immutable location '" & + par.s[sid].sym.name.s & "' and attempts to mutate it") + constViolation = true + if {viewDoesMutate, viewBorrowsFromConst} * par.s[rid].flags == {viewDoesMutate, viewBorrowsFromConst} and + not constViolation: + # we do not track the constant expressions we allow to borrow from so + # we can only produce a more generic error message: + localError(config, v.info, "'" & v.name.s & + "' borrows from an immutable location and attempts to mutate it") #if par.s[rid].con.kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].con.graphIndex], par.s[i]): # cannotBorrow(config, s, par.graphs[par.s[rid].con.graphIndex]) diff --git a/tests/views/tdont_mutate.nim b/tests/views/tdont_mutate.nim new file mode 100644 index 000000000..907aff018 --- /dev/null +++ b/tests/views/tdont_mutate.nim @@ -0,0 +1,48 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +import tables + +{.experimental: "views".} + +const + Whitespace = {' ', '\t', '\n', '\r'} + +proc split*(s: string, seps: set[char] = Whitespace, + maxsplit: int = -1): Table[int, openArray[char]] = + var last = 0 + var splits = maxsplit + result = initTable[int, openArray[char]]() + + while last <= len(s): + var first = last + while last < len(s) and s[last] notin seps: + inc(last) + if splits == 0: last = len(s) + result[first] = toOpenArray(s, first, last-1) + + result[first][0] = 'c' #[tt.Error + attempt to mutate a borrowed location from an immutable view + ]# + + if splits == 0: break + dec(splits) + inc(last) + +proc `$`(x: openArray[char]): string = + result = newString(x.len) + for i in 0.. Date: Thu, 1 Oct 2020 04:22:22 -0300 Subject: [PATCH 1165/4254] Add 1 overload to apply (#15439) --- lib/pure/collections/sequtils.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index d8ea3ad1f..803f89cc5 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -415,6 +415,11 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) for i in 0 ..< s.len: s[i] = op(s[i]) +proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = + ## Same as `apply` but for proc that do not return and do not mutate `s` directly. + runnableExamples: apply([0, 1, 2, 3, 4], proc(item: int) = echo item) + for i in 0 ..< s.len: op(s[i]) + iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## Iterates through a container `s` and yields every item that fulfills the ## predicate `pred` (function that returns a `bool`). From b703f02ad2a95975513f07d1a48c368b80825ddb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 1 Oct 2020 09:46:50 +0200 Subject: [PATCH 1166/4254] added missing .noalias support for object fields (#15445) --- compiler/ccgtypes.nim | 8 +++++--- tests/ccgbugs/tnoalias.nim | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index ff7b17590..c1a214532 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -564,19 +564,21 @@ proc genRecordFieldsAux(m: BModule, n: PNode, # have to recurse via 'getTypeDescAux'. And not doing so prevents problems # with heavily templatized C++ code: if not isImportedCppType(rectype): + let noAlias = if sfNoalias in field.flags: ~" NIM_NOALIAS" else: nil + let fieldType = field.loc.lode.typ.skipTypes(abstractInst) if fieldType.kind == tyUncheckedArray: result.addf("$1 $2[SEQ_DECL_SIZE];$n", [getTypeDescAux(m, fieldType.elemType, check, skField), sname]) elif fieldType.kind == tySequence: # we need to use a weak dependency here for trecursive_table. - result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname]) + result.addf("$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias]) elif field.bitsize != 0: - result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize)]) + result.addf("$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias]) else: # don't use fieldType here because we need the # tyGenericInst for C++ template support - result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname]) + result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = diff --git a/tests/ccgbugs/tnoalias.nim b/tests/ccgbugs/tnoalias.nim index 5ddfac5bb..0c6e84e44 100644 --- a/tests/ccgbugs/tnoalias.nim +++ b/tests/ccgbugs/tnoalias.nim @@ -1,8 +1,13 @@ discard """ - ccodecheck: "\\i@'NIM_CHAR* NIM_NOALIAS x,' @'void* NIM_NOALIAS q'" + ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x,' @'void* NIM_NOALIAS q'" """ +type + BigNum = object + field {.noalias.}: ptr UncheckedArray[int] + proc p(x {.noalias.}: openArray[char]) = var q {.noalias.}: pointer = unsafeAddr(x[0]) +var bn: BigNum p "abc" From 2b91845f1db165541be5d2ebad7fe1f956e90fb1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 1 Oct 2020 11:16:04 +0200 Subject: [PATCH 1167/4254] refactoring, fixes yet another strictFuncs regression (#15446) --- compiler/sempass2.nim | 5 ++++- compiler/varpartitions.nim | 20 +++++++++++++------- tests/effects/tstrict_funcs.nim | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 tests/effects/tstrict_funcs.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d591da855..cda156224 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1244,7 +1244,10 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = var mutationInfo = MutationInfo() if {strictFuncs, views} * c.features != {}: - var partitions = computeGraphPartitions(s, body, g.config) + var goals: set[Goal] = {} + if strictFuncs in c.features: goals.incl constParameters + if views in c.features: goals.incl borrowChecking + var partitions = computeGraphPartitions(s, body, g.config, goals) if not t.hasSideEffect and t.hasDangerousAssign: t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) if views in c.features: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 1fb4bd93e..b416aa41d 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -84,11 +84,17 @@ type maxMutation, minConnection: AbstractTime mutations: seq[AbstractTime] + Goal* = enum + constParameters, + borrowChecking, + cursorInference + Partitions* = object abstractTime: AbstractTime s: seq[VarIndex] graphs: seq[MutationInfo] - unanalysableMutation, performCursorInference: bool + goals: set[Goal] + unanalysableMutation: bool inAsgnSource, inConstructor, inNoSideEffectSection: int owner: PSym config: ConfigRef @@ -546,7 +552,7 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) = of noView: discard "nothing to do" proc deps(c: var Partitions; dest, src: PNode) = - if not c.performCursorInference: + if borrowChecking in c.goals: borrowingAsgn(c, dest, src) var targets, sources: seq[PSym] @@ -565,7 +571,7 @@ proc deps(c: var Partitions; dest, src: PNode) = for s in sources: connect(c, t, s, dest.info) - if c.performCursorInference and src.kind != nkEmpty: + if cursorInference in c.goals and src.kind != nkEmpty: if dest.kind == nkSym: let vid = variableId(c, dest.sym) if vid >= 0: @@ -647,7 +653,7 @@ proc traverse(c: var Partitions; n: PNode) = for r in roots: potentialMutation(c, r, it.info) for r in roots: noCursor(c, r) - if not c.performCursorInference: + if borrowChecking in c.goals: # a call like 'result.add toOpenArray()' can also be a borrow # operation. We know 'paramType' is a tyVar and we really care if # 'paramType[0]' is still a view type, this is not a typo! @@ -785,8 +791,8 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = else: for child in n: computeLiveRanges(c, child) -proc computeGraphPartitions*(s: PSym; n: PNode; config: ConfigRef; cursorInference = false): Partitions = - result = Partitions(performCursorInference: cursorInference, owner: s, config: config) +proc computeGraphPartitions*(s: PSym; n: PNode; config: ConfigRef; goals: set[Goal]): Partitions = + result = Partitions(owner: s, config: config, goals: goals) if s.kind notin {skModule, skMacro}: let params = s.typ.n for i in 1.. Date: Thu, 1 Oct 2020 06:21:27 -0300 Subject: [PATCH 1168/4254] Clean out jssys (#15442) --- lib/system/jssys.nim | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 705a6a208..df05a9a62 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -772,12 +772,6 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int { number = number * sign result = i - start -when defined(nodejs): - # Deprecated. Use `alert` defined in dom.nim - proc alert*(s: cstring) {.importc: "console.log", nodecl, deprecated.} -else: - # Deprecated. Use `alert` defined in dom.nim - proc alert*(s: cstring) {.importc, nodecl, deprecated.} # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce # 'Math.trunc' for Nim's ``div`` and ``mod`` operators: From 79a92da8efdb895ba5762ca9ed0471a3a5846068 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 1 Oct 2020 07:39:50 -0300 Subject: [PATCH 1169/4254] Clean out (#15440) --- changelog.md | 2 +- lib/pure/sugar.nim | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 474f1eae1..d610025d7 100644 --- a/changelog.md +++ b/changelog.md @@ -156,7 +156,7 @@ Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. `CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again. - Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. - +- Removed `sugar.distinctBase`, deprecated since `0.19`. - Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. - Added `deques.toDeque`, which creates a deque from an openArray. The usage is diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 8bfc7b7ff..49934b9bb 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -186,10 +186,6 @@ proc freshIdentNodes(ast: NimNode): NimNode = result.add inspect(child) result = inspect(ast) -template distinctBase*(T: typedesc): typedesc {.deprecated: "use distinctBase from typetraits instead".} = - ## reverses ``type T = distinct A``; works recursively. - typetraits.distinctBase(T) - macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} = ## Useful when creating a closure in a loop to capture some local loop variables ## by their current iteration values. Example: From ab405c936e77a875199aa1ee0f99eddd3d5a0c10 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 1 Oct 2020 15:04:36 +0200 Subject: [PATCH 1170/4254] views: yet another bugfix (#15447) * views: yet another bugfix * views: extended the spec * views: take into account potential hidden mutations via proc calls --- compiler/semtempl.nim | 5 ----- compiler/trees.nim | 5 +++++ compiler/varpartitions.nim | 26 ++++++++++++++++++++++---- doc/manual_experimental.rst | 16 ++++++++++++++++ tests/effects/tstrict_funcs.nim | 2 +- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 1ec8c07b0..df832c814 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -707,11 +707,6 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = localError(c.c.config, n.info, "invalid expression") result = n - proc stupidStmtListExpr(n: PNode): bool = - for i in 0.. 0 and stupidStmtListExpr(n): + n = n.lastSon + else: + break of nkCallKinds: if n.len > 1: if (n.typ != nil and classifyViewType(n.typ) != noView) or getMagic(n) == mSlice: @@ -551,6 +556,10 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) = localError(c.config, dest.info, "attempt to mutate a borrowed location from an immutable view") of noView: discard "nothing to do" +proc containsPointer(t: PType): bool = + proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} + result = types.searchTypeFor(t, wrap) + proc deps(c: var Partitions; dest, src: PNode) = if borrowChecking in c.goals: borrowingAsgn(c, dest, src) @@ -559,9 +568,7 @@ proc deps(c: var Partitions; dest, src: PNode) = allRoots(dest, targets) allRoots(src, sources) - proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} - - let destIsComplex = types.searchTypeFor(dest.typ, wrap) + let destIsComplex = containsPointer(dest.typ) for t in targets: if dest.kind != nkSym and c.inNoSideEffectSection == 0: @@ -607,6 +614,14 @@ const nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr} +proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) = + if constParameters in c.goals and tfNoSideEffect in callee.flags: + discard "we know there are no hidden mutations through an immutable parameter" + elif c.inNoSideEffectSection == 0 and containsPointer(n.typ): + var roots: seq[PSym] + allRoots(n, roots) + for r in roots: potentialMutation(c, r, n.info) + proc traverse(c: var Partitions; n: PNode) = inc c.abstractTime case n.kind @@ -640,6 +655,7 @@ proc traverse(c: var Partitions; n: PNode) = let parameters = n[0].typ let L = if parameters != nil: parameters.len else: 0 + let m = getMagic(n) for i in 1.. Date: Thu, 1 Oct 2020 10:07:57 -0300 Subject: [PATCH 1171/4254] Clean out (#15448) --- compiler/options.nim | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 226f13c73..efb0aa2da 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -628,17 +628,6 @@ proc setDefaultLibpath*(conf: ConfigRef) = proc canonicalizePath*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile = result = AbsoluteFile path.string.expandFilename -proc shortenDir*(conf: ConfigRef; dir: string): string {. - deprecated: "use 'relativeTo' instead".} = - ## returns the interesting part of a dir - var prefix = conf.projectPath.string & DirSep - if startsWith(dir, prefix): - return substr(dir, prefix.len) - prefix = getPrefixDir(conf).string & DirSep - if startsWith(dir, prefix): - return substr(dir, prefix.len) - result = dir - proc removeTrailingDirSep*(path: string): string = if (path.len > 0) and (path[^1] == DirSep): result = substr(path, 0, path.len - 2) From 5e160bff1b07e813fd3ed75f2bc48c4331cbfa39 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 1 Oct 2020 10:11:10 -0300 Subject: [PATCH 1172/4254] Add critbits.toCritBitTree (#15444) * Add critbits.toCritBitTree * https://github.com/nim-lang/Nim/pull/15444#discussion_r498035342 --- changelog.md | 3 +++ lib/pure/collections/critbits.nim | 28 ++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index d610025d7..5061a90b6 100644 --- a/changelog.md +++ b/changelog.md @@ -288,6 +288,9 @@ proc mydiv(a, b): int {.raises: [].} = - `items` no longer compiles with enum with holes as its behavior was error prone, see #14004 +- Added `critbits.toCritBitTree`, similar to `tables.toTable`, creates a new `CritBitTree` with given arguments. + + ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index d25e31d66..4611c2540 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -33,7 +33,7 @@ type root: Node[T] count: int -proc len*[T](c: CritBitTree[T]): int = +func len*[T](c: CritBitTree[T]): int {.inline.} = ## Returns the number of elements in `c` in O(1). runnableExamples: var c: CritBitTree[void] @@ -53,7 +53,7 @@ proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = else: return if it.key == key: it else: nil -proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = +func contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = ## Returns true if `c` contains the given `key`. runnableExamples: var c: CritBitTree[void] @@ -62,7 +62,7 @@ proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = result = rawGet(c, key) != nil -proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} = +func hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} = ## Alias for `contains <#contains,CritBitTree[T],string>`_. result = rawGet(c, key) != nil @@ -116,7 +116,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = wherep[] = inner inc c.count -proc exclImpl[T](c: var CritBitTree[T], key: string): int = +func exclImpl[T](c: var CritBitTree[T], key: string): int = var p = c.root var wherep = addr(c.root) var whereq: ptr Node[T] = nil @@ -285,7 +285,7 @@ template get[T](c: CritBitTree[T], key: string): T = n.val -proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = +func `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = ## Retrieves the value at ``c[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. @@ -295,7 +295,7 @@ proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) -proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = +func `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = ## Retrieves the value at ``c[key]``. The value can be modified. ## If `key` is not in `t`, the ``KeyError`` exception is raised. ## @@ -485,7 +485,7 @@ iterator mpairsWithPrefix*[T](c: var CritBitTree[T], let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) -proc `$`*[T](c: CritBitTree[T]): string = +func `$`*[T](c: CritBitTree[T]): string = ## Turns `c` into a string representation. Example outputs: ## ``{keyA: value, keyB: value}``, ``{:}`` ## If `T` is void the outputs look like: @@ -515,7 +515,7 @@ proc `$`*[T](c: CritBitTree[T]): string = result.addQuoted(val) result.add("}") -proc commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = +func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = ## Returns longest common prefix length of all keys of `c`. ## If `c` is empty, returns 0. runnableExamples: @@ -531,6 +531,18 @@ proc commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = else: c.root.byte else: 0 +func toCritBitTree*[A, B](pairs: openArray[(A, B)]): CritBitTree[A] {.since: (1, 3).} = + ## Creates a new `CritBitTree` that contains the given `pairs`. + runnableExamples: + doAssert {"a": "0", "b": "1", "c": "2"}.toCritBitTree is CritBitTree[string] + for item in pairs: result.incl item[0], item[1] + +func toCritBitTree*[T](items: openArray[T]): CritBitTree[void] {.since: (1, 3).} = + ## Creates a new `CritBitTree` that contains the given `items`. + runnableExamples: + doAssert ["a", "b", "c"].toCritBitTree is CritBitTree[void] + for item in items: result.incl item + runnableExamples: static: From 0bfa0fcaea69d247304ed06cb129bfcc80fcd864 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 1 Oct 2020 21:17:16 +0800 Subject: [PATCH 1173/4254] [docs minor] unify generates and Generates (#15434) * [docs] unify generates and Generates * fix typo --- lib/pure/htmlgen.nim | 220 +++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index 99af26c99..ba50a4a6e 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -119,82 +119,82 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", result = nestList(!"&", result) macro a*(e: varargs[untyped]): untyped = - ## generates the HTML ``a`` element. + ## Generates the HTML ``a`` element. result = xmlCheckedTag(e, "a", "href target download rel hreflang type " & commonAttr) macro abbr*(e: varargs[untyped]): untyped = - ## generates the HTML ``abbr`` element. + ## Generates the HTML ``abbr`` element. result = xmlCheckedTag(e, "abbr", commonAttr) macro address*(e: varargs[untyped]): untyped = - ## generates the HTML ``address`` element. + ## Generates the HTML ``address`` element. result = xmlCheckedTag(e, "address", commonAttr) macro area*(e: varargs[untyped]): untyped = - ## generates the HTML ``area`` element. + ## Generates the HTML ``area`` element. result = xmlCheckedTag(e, "area", "coords download href hreflang rel " & "shape target type" & commonAttr, "alt", true) macro article*(e: varargs[untyped]): untyped = - ## generates the HTML ``article`` element. + ## Generates the HTML ``article`` element. result = xmlCheckedTag(e, "article", commonAttr) macro aside*(e: varargs[untyped]): untyped = - ## generates the HTML ``aside`` element. + ## Generates the HTML ``aside`` element. result = xmlCheckedTag(e, "aside", commonAttr) macro audio*(e: varargs[untyped]): untyped = - ## generates the HTML ``audio`` element. + ## Generates the HTML ``audio`` element. result = xmlCheckedTag(e, "audio", "src crossorigin preload " & "autoplay mediagroup loop muted controls" & commonAttr) macro b*(e: varargs[untyped]): untyped = - ## generates the HTML ``b`` element. + ## Generates the HTML ``b`` element. result = xmlCheckedTag(e, "b", commonAttr) macro base*(e: varargs[untyped]): untyped = - ## generates the HTML ``base`` element. + ## Generates the HTML ``base`` element. result = xmlCheckedTag(e, "base", "href target" & commonAttr, "", true) macro bdi*(e: varargs[untyped]): untyped = - ## generates the HTML ``bdi`` element. + ## Generates the HTML ``bdi`` element. result = xmlCheckedTag(e, "bdi", commonAttr) macro bdo*(e: varargs[untyped]): untyped = - ## generates the HTML ``bdo`` element. + ## Generates the HTML ``bdo`` element. result = xmlCheckedTag(e, "bdo", commonAttr) macro big*(e: varargs[untyped]): untyped = - ## generates the HTML ``big`` element. + ## Generates the HTML ``big`` element. result = xmlCheckedTag(e, "big", commonAttr) macro blockquote*(e: varargs[untyped]): untyped = - ## generates the HTML ``blockquote`` element. + ## Generates the HTML ``blockquote`` element. result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr) macro body*(e: varargs[untyped]): untyped = - ## generates the HTML ``body`` element. + ## Generates the HTML ``body`` element. result = xmlCheckedTag(e, "body", "onafterprint onbeforeprint " & "onbeforeunload onhashchange onmessage onoffline ononline onpagehide " & "onpageshow onpopstate onstorage onunload" & commonAttr) macro br*(e: varargs[untyped]): untyped = - ## generates the HTML ``br`` element. + ## Generates the HTML ``br`` element. result = xmlCheckedTag(e, "br", commonAttr, "", true) macro button*(e: varargs[untyped]): untyped = - ## generates the HTML ``button`` element. + ## Generates the HTML ``button`` element. result = xmlCheckedTag(e, "button", "autofocus disabled form formaction " & "formenctype formmethod formnovalidate formtarget menu name type value" & commonAttr) macro canvas*(e: varargs[untyped]): untyped = - ## generates the HTML ``canvas`` element. + ## Generates the HTML ``canvas`` element. result = xmlCheckedTag(e, "canvas", "width height" & commonAttr) macro caption*(e: varargs[untyped]): untyped = - ## generates the HTML ``caption`` element. + ## Generates the HTML ``caption`` element. result = xmlCheckedTag(e, "caption", commonAttr) macro center*(e: varargs[untyped]): untyped = @@ -202,35 +202,35 @@ macro center*(e: varargs[untyped]): untyped = result = xmlCheckedTag(e, "center", commonAttr) macro cite*(e: varargs[untyped]): untyped = - ## generates the HTML ``cite`` element. + ## Generates the HTML ``cite`` element. result = xmlCheckedTag(e, "cite", commonAttr) macro code*(e: varargs[untyped]): untyped = - ## generates the HTML ``code`` element. + ## Generates the HTML ``code`` element. result = xmlCheckedTag(e, "code", commonAttr) macro col*(e: varargs[untyped]): untyped = - ## generates the HTML ``col`` element. + ## Generates the HTML ``col`` element. result = xmlCheckedTag(e, "col", "span" & commonAttr, "", true) macro colgroup*(e: varargs[untyped]): untyped = - ## generates the HTML ``colgroup`` element. + ## Generates the HTML ``colgroup`` element. result = xmlCheckedTag(e, "colgroup", "span" & commonAttr) macro data*(e: varargs[untyped]): untyped = - ## generates the HTML ``data`` element. + ## Generates the HTML ``data`` element. result = xmlCheckedTag(e, "data", "value" & commonAttr) macro datalist*(e: varargs[untyped]): untyped = - ## generates the HTML ``datalist`` element. + ## Generates the HTML ``datalist`` element. result = xmlCheckedTag(e, "datalist", commonAttr) macro dd*(e: varargs[untyped]): untyped = - ## generates the HTML ``dd`` element. + ## Generates the HTML ``dd`` element. result = xmlCheckedTag(e, "dd", commonAttr) macro del*(e: varargs[untyped]): untyped = - ## generates the HTML ``del`` element. + ## Generates the HTML ``del`` element. result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr) macro details*(e: varargs[untyped]): untyped = @@ -238,7 +238,7 @@ macro details*(e: varargs[untyped]): untyped = result = xmlCheckedTag(e, "details", commonAttr & "open") macro dfn*(e: varargs[untyped]): untyped = - ## generates the HTML ``dfn`` element. + ## Generates the HTML ``dfn`` element. result = xmlCheckedTag(e, "dfn", commonAttr) macro dialog*(e: varargs[untyped]): untyped = @@ -246,103 +246,103 @@ macro dialog*(e: varargs[untyped]): untyped = result = xmlCheckedTag(e, "dialog", commonAttr & "open") macro `div`*(e: varargs[untyped]): untyped = - ## generates the HTML ``div`` element. + ## Generates the HTML ``div`` element. result = xmlCheckedTag(e, "div", commonAttr) macro dl*(e: varargs[untyped]): untyped = - ## generates the HTML ``dl`` element. + ## Generates the HTML ``dl`` element. result = xmlCheckedTag(e, "dl", commonAttr) macro dt*(e: varargs[untyped]): untyped = - ## generates the HTML ``dt`` element. + ## Generates the HTML ``dt`` element. result = xmlCheckedTag(e, "dt", commonAttr) macro em*(e: varargs[untyped]): untyped = - ## generates the HTML ``em`` element. + ## Generates the HTML ``em`` element. result = xmlCheckedTag(e, "em", commonAttr) macro embed*(e: varargs[untyped]): untyped = - ## generates the HTML ``embed`` element. + ## Generates the HTML ``embed`` element. result = xmlCheckedTag(e, "embed", "src type height width" & commonAttr, "", true) macro fieldset*(e: varargs[untyped]): untyped = - ## generates the HTML ``fieldset`` element. + ## Generates the HTML ``fieldset`` element. result = xmlCheckedTag(e, "fieldset", "disabled form name" & commonAttr) macro figure*(e: varargs[untyped]): untyped = - ## generates the HTML ``figure`` element. + ## Generates the HTML ``figure`` element. result = xmlCheckedTag(e, "figure", commonAttr) macro figcaption*(e: varargs[untyped]): untyped = - ## generates the HTML ``figcaption`` element. + ## Generates the HTML ``figcaption`` element. result = xmlCheckedTag(e, "figcaption", commonAttr) macro footer*(e: varargs[untyped]): untyped = - ## generates the HTML ``footer`` element. + ## Generates the HTML ``footer`` element. result = xmlCheckedTag(e, "footer", commonAttr) macro form*(e: varargs[untyped]): untyped = - ## generates the HTML ``form`` element. + ## Generates the HTML ``form`` element. result = xmlCheckedTag(e, "form", "accept-charset action autocomplete " & "enctype method name novalidate target" & commonAttr) macro h1*(e: varargs[untyped]): untyped = - ## generates the HTML ``h1`` element. + ## Generates the HTML ``h1`` element. result = xmlCheckedTag(e, "h1", commonAttr) macro h2*(e: varargs[untyped]): untyped = - ## generates the HTML ``h2`` element. + ## Generates the HTML ``h2`` element. result = xmlCheckedTag(e, "h2", commonAttr) macro h3*(e: varargs[untyped]): untyped = - ## generates the HTML ``h3`` element. + ## Generates the HTML ``h3`` element. result = xmlCheckedTag(e, "h3", commonAttr) macro h4*(e: varargs[untyped]): untyped = - ## generates the HTML ``h4`` element. + ## Generates the HTML ``h4`` element. result = xmlCheckedTag(e, "h4", commonAttr) macro h5*(e: varargs[untyped]): untyped = - ## generates the HTML ``h5`` element. + ## Generates the HTML ``h5`` element. result = xmlCheckedTag(e, "h5", commonAttr) macro h6*(e: varargs[untyped]): untyped = - ## generates the HTML ``h6`` element. + ## Generates the HTML ``h6`` element. result = xmlCheckedTag(e, "h6", commonAttr) macro head*(e: varargs[untyped]): untyped = - ## generates the HTML ``head`` element. + ## Generates the HTML ``head`` element. result = xmlCheckedTag(e, "head", commonAttr) macro header*(e: varargs[untyped]): untyped = - ## generates the HTML ``header`` element. + ## Generates the HTML ``header`` element. result = xmlCheckedTag(e, "header", commonAttr) macro html*(e: varargs[untyped]): untyped = - ## generates the HTML ``html`` element. + ## Generates the HTML ``html`` element. result = xmlCheckedTag(e, "html", "xmlns" & commonAttr, "") macro hr*(): untyped = - ## generates the HTML ``hr`` element. + ## Generates the HTML ``hr`` element. result = xmlCheckedTag(newNimNode(nnkArglist), "hr", commonAttr, "", true) macro i*(e: varargs[untyped]): untyped = - ## generates the HTML ``i`` element. + ## Generates the HTML ``i`` element. result = xmlCheckedTag(e, "i", commonAttr) macro iframe*(e: varargs[untyped]): untyped = - ## generates the HTML ``iframe`` element. + ## Generates the HTML ``iframe`` element. result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height" & commonAttr) macro img*(e: varargs[untyped]): untyped = - ## generates the HTML ``img`` element. + ## Generates the HTML ``img`` element. result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width" & commonAttr, "src alt", true) macro input*(e: varargs[untyped]): untyped = - ## generates the HTML ``input`` element. + ## Generates the HTML ``input`` element. result = xmlCheckedTag(e, "input", "accept alt autocomplete autofocus " & "checked dirname disabled form formaction formenctype formmethod " & "formnovalidate formtarget height inputmode list max maxlength min " & @@ -350,45 +350,45 @@ macro input*(e: varargs[untyped]): untyped = "src step type value width" & commonAttr, "", true) macro ins*(e: varargs[untyped]): untyped = - ## generates the HTML ``ins`` element. + ## Generates the HTML ``ins`` element. result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr) macro kbd*(e: varargs[untyped]): untyped = - ## generates the HTML ``kbd`` element. + ## Generates the HTML ``kbd`` element. result = xmlCheckedTag(e, "kbd", commonAttr) macro keygen*(e: varargs[untyped]): untyped = - ## generates the HTML ``keygen`` element. + ## Generates the HTML ``keygen`` element. result = xmlCheckedTag(e, "keygen", "autofocus challenge disabled " & "form keytype name" & commonAttr) macro label*(e: varargs[untyped]): untyped = - ## generates the HTML ``label`` element. + ## Generates the HTML ``label`` element. result = xmlCheckedTag(e, "label", "form for" & commonAttr) macro legend*(e: varargs[untyped]): untyped = - ## generates the HTML ``legend`` element. + ## Generates the HTML ``legend`` element. result = xmlCheckedTag(e, "legend", commonAttr) macro li*(e: varargs[untyped]): untyped = - ## generates the HTML ``li`` element. + ## Generates the HTML ``li`` element. result = xmlCheckedTag(e, "li", "value" & commonAttr) macro link*(e: varargs[untyped]): untyped = - ## generates the HTML ``link`` element. + ## Generates the HTML ``link`` element. result = xmlCheckedTag(e, "link", "href crossorigin rel media hreflang " & "type sizes" & commonAttr, "", true) macro main*(e: varargs[untyped]): untyped = - ## generates the HTML ``main`` element. + ## Generates the HTML ``main`` element. result = xmlCheckedTag(e, "main", commonAttr) macro map*(e: varargs[untyped]): untyped = - ## generates the HTML ``map`` element. + ## Generates the HTML ``map`` element. result = xmlCheckedTag(e, "map", "name" & commonAttr) macro mark*(e: varargs[untyped]): untyped = - ## generates the HTML ``mark`` element. + ## Generates the HTML ``mark`` element. result = xmlCheckedTag(e, "mark", commonAttr) macro marquee*(e: varargs[untyped]): untyped = @@ -398,51 +398,51 @@ macro marquee*(e: varargs[untyped]): untyped = "scrolldelay truespeed vspace width onbounce onfinish onstart") macro meta*(e: varargs[untyped]): untyped = - ## generates the HTML ``meta`` element. + ## Generates the HTML ``meta`` element. result = xmlCheckedTag(e, "meta", "name http-equiv content charset" & commonAttr, "", true) macro meter*(e: varargs[untyped]): untyped = - ## generates the HTML ``meter`` element. + ## Generates the HTML ``meter`` element. result = xmlCheckedTag(e, "meter", "value min max low high optimum" & commonAttr) macro nav*(e: varargs[untyped]): untyped = - ## generates the HTML ``nav`` element. + ## Generates the HTML ``nav`` element. result = xmlCheckedTag(e, "nav", commonAttr) macro noscript*(e: varargs[untyped]): untyped = - ## generates the HTML ``noscript`` element. + ## Generates the HTML ``noscript`` element. result = xmlCheckedTag(e, "noscript", commonAttr) macro `object`*(e: varargs[untyped]): untyped = - ## generates the HTML ``object`` element. + ## Generates the HTML ``object`` element. result = xmlCheckedTag(e, "object", "data type typemustmatch name usemap " & "form width height" & commonAttr) macro ol*(e: varargs[untyped]): untyped = - ## generates the HTML ``ol`` element. + ## Generates the HTML ``ol`` element. result = xmlCheckedTag(e, "ol", "reversed start type" & commonAttr) macro optgroup*(e: varargs[untyped]): untyped = - ## generates the HTML ``optgroup`` element. + ## Generates the HTML ``optgroup`` element. result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false) macro option*(e: varargs[untyped]): untyped = - ## generates the HTML ``option`` element. + ## Generates the HTML ``option`` element. result = xmlCheckedTag(e, "option", "disabled label selected value" & commonAttr) macro output*(e: varargs[untyped]): untyped = - ## generates the HTML ``output`` element. + ## Generates the HTML ``output`` element. result = xmlCheckedTag(e, "output", "for form name" & commonAttr) macro p*(e: varargs[untyped]): untyped = - ## generates the HTML ``p`` element. + ## Generates the HTML ``p`` element. result = xmlCheckedTag(e, "p", commonAttr) macro param*(e: varargs[untyped]): untyped = - ## generates the HTML ``param`` element. + ## Generates the HTML ``param`` element. result = xmlCheckedTag(e, "param", commonAttr, "name value", true) macro picture*(e: varargs[untyped]): untyped = @@ -450,56 +450,56 @@ macro picture*(e: varargs[untyped]): untyped = result = xmlCheckedTag(e, "picture", commonAttr) macro pre*(e: varargs[untyped]): untyped = - ## generates the HTML ``pre`` element. + ## Generates the HTML ``pre`` element. result = xmlCheckedTag(e, "pre", commonAttr) macro progress*(e: varargs[untyped]): untyped = - ## generates the HTML ``progress`` element. + ## Generates the HTML ``progress`` element. result = xmlCheckedTag(e, "progress", "value max" & commonAttr) macro q*(e: varargs[untyped]): untyped = - ## generates the HTML ``q`` element. + ## Generates the HTML ``q`` element. result = xmlCheckedTag(e, "q", "cite" & commonAttr) macro rb*(e: varargs[untyped]): untyped = - ## generates the HTML ``rb`` element. + ## Generates the HTML ``rb`` element. result = xmlCheckedTag(e, "rb", commonAttr) macro rp*(e: varargs[untyped]): untyped = - ## generates the HTML ``rp`` element. + ## Generates the HTML ``rp`` element. result = xmlCheckedTag(e, "rp", commonAttr) macro rt*(e: varargs[untyped]): untyped = - ## generates the HTML ``rt`` element. + ## Generates the HTML ``rt`` element. result = xmlCheckedTag(e, "rt", commonAttr) macro rtc*(e: varargs[untyped]): untyped = - ## generates the HTML ``rtc`` element. + ## Generates the HTML ``rtc`` element. result = xmlCheckedTag(e, "rtc", commonAttr) macro ruby*(e: varargs[untyped]): untyped = - ## generates the HTML ``ruby`` element. + ## Generates the HTML ``ruby`` element. result = xmlCheckedTag(e, "ruby", commonAttr) macro s*(e: varargs[untyped]): untyped = - ## generates the HTML ``s`` element. + ## Generates the HTML ``s`` element. result = xmlCheckedTag(e, "s", commonAttr) macro samp*(e: varargs[untyped]): untyped = - ## generates the HTML ``samp`` element. + ## Generates the HTML ``samp`` element. result = xmlCheckedTag(e, "samp", commonAttr) macro script*(e: varargs[untyped]): untyped = - ## generates the HTML ``script`` element. + ## Generates the HTML ``script`` element. result = xmlCheckedTag(e, "script", "src type charset async defer " & "crossorigin" & commonAttr) macro section*(e: varargs[untyped]): untyped = - ## generates the HTML ``section`` element. + ## Generates the HTML ``section`` element. result = xmlCheckedTag(e, "section", commonAttr) macro select*(e: varargs[untyped]): untyped = - ## generates the HTML ``select`` element. + ## Generates the HTML ``select`` element. result = xmlCheckedTag(e, "select", "autofocus disabled form multiple " & "name required size" & commonAttr) @@ -508,27 +508,27 @@ macro slot*(e: varargs[untyped]): untyped = result = xmlCheckedTag(e, "slot", commonAttr) macro small*(e: varargs[untyped]): untyped = - ## generates the HTML ``small`` element. + ## Generates the HTML ``small`` element. result = xmlCheckedTag(e, "small", commonAttr) macro source*(e: varargs[untyped]): untyped = - ## generates the HTML ``source`` element. + ## Generates the HTML ``source`` element. result = xmlCheckedTag(e, "source", "type" & commonAttr, "src", true) macro span*(e: varargs[untyped]): untyped = - ## generates the HTML ``span`` element. + ## Generates the HTML ``span`` element. result = xmlCheckedTag(e, "span", commonAttr) macro strong*(e: varargs[untyped]): untyped = - ## generates the HTML ``strong`` element. + ## Generates the HTML ``strong`` element. result = xmlCheckedTag(e, "strong", commonAttr) macro style*(e: varargs[untyped]): untyped = - ## generates the HTML ``style`` element. + ## Generates the HTML ``style`` element. result = xmlCheckedTag(e, "style", "media type" & commonAttr) macro sub*(e: varargs[untyped]): untyped = - ## generates the HTML ``sub`` element. + ## Generates the HTML ``sub`` element. result = xmlCheckedTag(e, "sub", commonAttr) macro summary*(e: varargs[untyped]): untyped = @@ -536,84 +536,84 @@ macro summary*(e: varargs[untyped]): untyped = result = xmlCheckedTag(e, "summary", commonAttr) macro sup*(e: varargs[untyped]): untyped = - ## generates the HTML ``sup`` element. + ## Generates the HTML ``sup`` element. result = xmlCheckedTag(e, "sup", commonAttr) macro table*(e: varargs[untyped]): untyped = - ## generates the HTML ``table`` element. + ## Generates the HTML ``table`` element. result = xmlCheckedTag(e, "table", "border sortable" & commonAttr) macro tbody*(e: varargs[untyped]): untyped = - ## generates the HTML ``tbody`` element. + ## Generates the HTML ``tbody`` element. result = xmlCheckedTag(e, "tbody", commonAttr) macro td*(e: varargs[untyped]): untyped = - ## generates the HTML ``td`` element. + ## Generates the HTML ``td`` element. result = xmlCheckedTag(e, "td", "colspan rowspan headers" & commonAttr) macro `template`*(e: varargs[untyped]): untyped = - ## generates the HTML ``template`` element. + ## Generates the HTML ``template`` element. result = xmlCheckedTag(e, "template", commonAttr) macro textarea*(e: varargs[untyped]): untyped = - ## generates the HTML ``textarea`` element. + ## Generates the HTML ``textarea`` element. result = xmlCheckedTag(e, "textarea", "autocomplete autofocus cols " & "dirname disabled form inputmode maxlength minlength name placeholder " & "readonly required rows wrap" & commonAttr) macro tfoot*(e: varargs[untyped]): untyped = - ## generates the HTML ``tfoot`` element. + ## Generates the HTML ``tfoot`` element. result = xmlCheckedTag(e, "tfoot", commonAttr) macro th*(e: varargs[untyped]): untyped = - ## generates the HTML ``th`` element. + ## Generates the HTML ``th`` element. result = xmlCheckedTag(e, "th", "colspan rowspan headers abbr scope axis" & " sorted" & commonAttr) macro thead*(e: varargs[untyped]): untyped = - ## generates the HTML ``thead`` element. + ## Generates the HTML ``thead`` element. result = xmlCheckedTag(e, "thead", commonAttr) macro time*(e: varargs[untyped]): untyped = - ## generates the HTML ``time`` element. + ## Generates the HTML ``time`` element. result = xmlCheckedTag(e, "time", "datetime" & commonAttr) macro title*(e: varargs[untyped]): untyped = - ## generates the HTML ``title`` element. + ## Generates the HTML ``title`` element. result = xmlCheckedTag(e, "title", commonAttr) macro tr*(e: varargs[untyped]): untyped = - ## generates the HTML ``tr`` element. + ## Generates the HTML ``tr`` element. result = xmlCheckedTag(e, "tr", commonAttr) macro track*(e: varargs[untyped]): untyped = - ## generates the HTML ``track`` element. + ## Generates the HTML ``track`` element. result = xmlCheckedTag(e, "track", "kind srclang label default" & commonAttr, "src", true) macro tt*(e: varargs[untyped]): untyped = - ## generates the HTML ``tt`` element. + ## Generates the HTML ``tt`` element. result = xmlCheckedTag(e, "tt", commonAttr) macro u*(e: varargs[untyped]): untyped = - ## generates the HTML ``u`` element. + ## Generates the HTML ``u`` element. result = xmlCheckedTag(e, "u", commonAttr) macro ul*(e: varargs[untyped]): untyped = - ## generates the HTML ``ul`` element. + ## Generates the HTML ``ul`` element. result = xmlCheckedTag(e, "ul", commonAttr) macro `var`*(e: varargs[untyped]): untyped = - ## generates the HTML ``var`` element. + ## Generates the HTML ``var`` element. result = xmlCheckedTag(e, "var", commonAttr) macro video*(e: varargs[untyped]): untyped = - ## generates the HTML ``video`` element. + ## Generates the HTML ``video`` element. result = xmlCheckedTag(e, "video", "src crossorigin poster preload " & "autoplay mediagroup loop muted controls width height" & commonAttr) macro wbr*(e: varargs[untyped]): untyped = - ## generates the HTML ``wbr`` element. + ## Generates the HTML ``wbr`` element. result = xmlCheckedTag(e, "wbr", commonAttr, "", true) From 3919f0aa544d84c7a236e5095b87d7d0c8fb63b4 Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 1 Oct 2020 10:20:38 -0500 Subject: [PATCH 1174/4254] koch: unify nimble building scripts [backport:1.4] (#15443) This commit gets rid of buildNimble in favor of the simpler bundleNimbleExe, which does pretty much the same thing. --- koch.nim | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/koch.nim b/koch.nim index 68c5764be..714d70bfe 100644 --- a/koch.nim +++ b/koch.nim @@ -145,35 +145,11 @@ proc bundleC2nim(args: string) = proc bundleNimbleExe(latest: bool, args: string) = let commit = if latest: "HEAD" else: NimbleStableCommit - cloneDependency(distDir, "https://github.com/nim-lang/nimble.git", commit = commit) + cloneDependency(distDir, "https://github.com/nim-lang/nimble.git", + commit = commit, allowBundled = true) # installer.ini expects it under $nim/bin nimCompile("dist/nimble/src/nimble.nim", - options = "-d:release --nilseqs:on " & args) - -proc buildNimble(latest: bool, args: string) = - # if koch is used for a tar.xz, build the dist/nimble we shipped - # with the tarball: - var installDir = "dist/nimble" - if not latest and dirExists(installDir) and not dirExists("dist/nimble/.git"): - discard "don't do the git dance" - else: - if not dirExists("dist/nimble/.git"): - if dirExists(installDir): - var id = 0 - while dirExists("dist/nimble" & $id): - inc id - installDir = "dist/nimble" & $id - # consider using/adapting cloneDependency - exec("git clone -q https://github.com/nim-lang/nimble.git " & installDir) - withDir(installDir): - if latest: - exec("git checkout -f master") - exec("git pull") - else: - exec("git fetch") - exec("git checkout " & NimbleStableCommit) - nimCompile(installDir / "src/nimble.nim", - options = "--noNimblePath --nilseqs:on -d:release " & args) + options = "-d:release --noNimblePath " & args) proc bundleNimsuggest(args: string) = nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim", @@ -704,14 +680,14 @@ when isMainModule: of "temp": temp(op.cmdLineRest) of "xtemp": xtemp(op.cmdLineRest) of "wintools": bundleWinTools(op.cmdLineRest) - of "nimble": buildNimble(latest, op.cmdLineRest) + of "nimble": bundleNimbleExe(latest, op.cmdLineRest) of "nimsuggest": bundleNimsuggest(op.cmdLineRest) # toolsNoNimble is kept for backward compatibility with build scripts of "toolsnonimble", "toolsnoexternal": buildTools(op.cmdLineRest) of "tools": buildTools(op.cmdLineRest) - buildNimble(latest, op.cmdLineRest) + bundleNimbleExe(latest, op.cmdLineRest) bundleFusion(latest) of "pushcsource", "pushcsources": pushCsources() of "valgrind": valgrind(op.cmdLineRest) From 531ed2dc365d6d33c7bccdfbe22df561cf14af86 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 1 Oct 2020 16:39:48 +0100 Subject: [PATCH 1175/4254] fix #15405. deepcopy arc (#15410) * fix #15405 * fix tests * deepcopy for ARC has to be enabled via --deepcopy:on Co-authored-by: Araq --- changelog.md | 3 +++ compiler/ccgexprs.nim | 4 ++++ compiler/ccgtypes.nim | 7 +++++-- compiler/commands.nim | 3 ++- compiler/options.nim | 1 + doc/advopt.txt | 1 + lib/system.nim | 3 +++ tests/arc/tarcmisc.nim | 33 ++++++++++++++++++++++++++++++++- tests/arc/tdeepcopy.nim | 2 +- 9 files changed, 52 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 5061a90b6..3bae911e9 100644 --- a/changelog.md +++ b/changelog.md @@ -287,6 +287,9 @@ proc mydiv(a, b): int {.raises: [].} = performance this keyword can enable. - `items` no longer compiles with enum with holes as its behavior was error prone, see #14004 +- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via + `--deepcopy:on`. + - Added `critbits.toCritBitTree`, similar to `tables.toTable`, creates a new `CritBitTree` with given arguments. diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b6808a55e..49b1f3d16 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2394,6 +2394,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) expr(p, n, d) of mDeepCopy: + if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions: + localError(p.config, e.info, + "for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on") + var a, b: TLoc let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] initLocExpr(p, x, a) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index c1a214532..0df7c8d2a 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1355,6 +1355,9 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn name, destroyImpl, getTypeDesc(m, t), typeName, traceImpl, disposeImpl]) + if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: + discard genTypeInfoV1(m, t, info) + proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = let origType = t var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) @@ -1454,12 +1457,12 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = genTupleInfo(m, x, x, result, info) of tySequence: genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC >= gcMarkAndSweep: + if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}: let markerProc = genTraverseProc(m, origType, sig) m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) of tyRef: genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC >= gcMarkAndSweep: + if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}: let markerProc = genTraverseProc(m, origType, sig) m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) diff --git a/compiler/commands.nim b/compiler/commands.nim index 17124a759..19048065f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -901,7 +901,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "sourcemap": conf.globalOptions.incl optSourcemap conf.options.incl optLineDir - # processOnOffSwitchG(conf, {optSourcemap, opt}, arg, pass, info) + of "deepcopy": + processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info) of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) handleStdinInput(conf) else: diff --git a/compiler/options.nim b/compiler/options.nim index efb0aa2da..40d86a01d 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -96,6 +96,7 @@ type # please make sure we have under 32 options optNimV1Emulation # emulate Nim v1.0 optSourcemap optProfileVM # enable VM profiler + optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types. TGlobalOptions* = set[TGlobalOption] diff --git a/doc/advopt.txt b/doc/advopt.txt index 830b8bfc6..60f5a1e10 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -153,3 +153,4 @@ Advanced options: --profileVM:on|off enable compile time VM profiler --sinkInference:on|off en-/disable sink parameter inference (default: on) --panics:on|off turn panics into process terminations (default: off) + --deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc`` diff --git a/lib/system.nim b/lib/system.nim index 0784cacce..fe73a70f5 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2895,6 +2895,9 @@ when hasAlloc and notJSnotNims: ## ## This is also used by the code generator ## for the implementation of ``spawn``. + ## + ## For ``--gc:arc`` or ``--gc:orc`` deepcopy support has to be enabled + ## via ``--deepcopy:on``. discard proc deepCopy*[T](y: T): T = diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 542e4f316..b53d49df8 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -30,7 +30,7 @@ closed destroying variable: 20 destroying variable: 10 ''' - cmd: "nim c --gc:arc $file" + cmd: "nim c --gc:arc --deepcopy:on $file" """ proc takeSink(x: sink string): bool = true @@ -347,3 +347,34 @@ var data = { # For ARC listVal is empty for some reason doAssert data["examples"]["values"].listVal[0].strVal == "test" + + + + +############################################################################### +# bug #15405 +import parsexml +const test_xml_str = "value" +var stream = newStringStream(test_xml_str) +var xml: XmlParser +open(xml, stream, "test") +var xml2 = deepCopy(xml) + +proc text_parser(xml: var XmlParser) = + var test_passed = false + while true: + xml.next() + case xml.kind + of xmlElementStart: + if xml.elementName == "B": + xml.next() + if xml.kind == xmlCharData and xml.charData == "value": + test_passed = true + + of xmlEof: break + else: discard + xml.close() + doAssert(test_passed) + +text_parser(xml) +text_parser(xml2) \ No newline at end of file diff --git a/tests/arc/tdeepcopy.nim b/tests/arc/tdeepcopy.nim index 0eaf7ea40..91d93aa28 100644 --- a/tests/arc/tdeepcopy.nim +++ b/tests/arc/tdeepcopy.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim c --gc:arc $file" + cmd: "nim c --gc:arc --deepcopy:on $file" output: '''13 abc 13 abc 13 abc From 26d656e73e2354bc6f177073b948a7791e8f7427 Mon Sep 17 00:00:00 2001 From: c-blake Date: Thu, 1 Oct 2020 12:06:38 -0400 Subject: [PATCH 1176/4254] Add first draft of new osproc.readLines (#15429) * Add first draft of new osproc.readLines * Add test for new osproc.readLines * Rename test to start w/t to run; Also add newline to output * Suppress hint messages. * Output should match this time. * Shoulda picked a program with simpler syntax than ..lol * Address https://github.com/nim-lang/Nim/pull/15429#issuecomment-701890898 and https://github.com/nim-lang/Nim/pull/15429#issuecomment-701985976 by factoring `readLines` into `iterator lines` and a wrapper `proc`. * Address https://github.com/nim-lang/Nim/pull/15429#issuecomment-702127289 and also add a `ReadIOEffect` tag to the iterator (called by the wrapper.. so it should need no separate tag, if I understand correctly). --- changelog.md | 2 ++ lib/pure/osproc.nim | 51 +++++++++++++++++++++++++++++++++++++ tests/osproc/treadlines.nim | 20 +++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 tests/osproc/treadlines.nim diff --git a/changelog.md b/changelog.md index 3bae911e9..3cdf138ad 100644 --- a/changelog.md +++ b/changelog.md @@ -199,6 +199,8 @@ - Add `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. +- Add `readLines(p: Process)` to `osproc` module for `startProcess` convenience. + ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 5113695d8..2d48597dc 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -444,6 +444,57 @@ proc execProcesses*(cmds: openArray[string], if afterRunEvent != nil: afterRunEvent(i, p) close(p) +iterator lines*(p: Process): string {.since: (1, 3), tags: [ReadIOEffect].} = + ## Convenience iterator for working with `startProcess` to read data from a + ## background process. + ## + ## See also: + ## * `readLines proc <#readLines,Process>`_ + ## + ## Example: + ## + ## .. code-block:: Nim + ## const opts = {poUsePath, poDaemon, poStdErrToStdOut} + ## var ps: seq[Process] + ## for prog in ["a", "b"]: # run 2 progs in parallel + ## ps.add startProcess("nim", "", ["r", prog], nil, opts) + ## for p in ps: + ## var i = 0 + ## for line in p.lines: + ## echo line + ## i.inc + ## if i > 100: break + ## p.close + var outp = p.outputStream + var line = newStringOfCap(120) + while true: + if outp.readLine(line): + yield line + else: + if p.peekExitCode != -1: break + +proc readLines*(p: Process): (seq[string], int) {.since: (1, 3).} = + ## Convenience function for working with `startProcess` to read data from a + ## background process. + ## + ## See also: + ## * `lines iterator <#lines.i,Process>`_ + ## + ## Example: + ## + ## .. code-block:: Nim + ## const opts = {poUsePath, poDaemon, poStdErrToStdOut} + ## var ps: seq[Process] + ## for prog in ["a", "b"]: # run 2 progs in parallel + ## ps.add startProcess("nim", "", ["r", prog], nil, opts) + ## for p in ps: + ## let (lines, exCode) = p.readLines + ## if exCode != 0: + ## for line in lines: echo line + ## p.close + for line in p.lines: result[0].add(line) + result[1] = p.peekExitCode + when not defined(useNimRtl): proc execProcess(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, diff --git a/tests/osproc/treadlines.nim b/tests/osproc/treadlines.nim new file mode 100644 index 000000000..3a8303321 --- /dev/null +++ b/tests/osproc/treadlines.nim @@ -0,0 +1,20 @@ +discard """ + output: '''Error: cannot open 'a.nim' +Error: cannot open 'b.nim' +''' + targets: "c" +""" + +import osproc + +var ps: seq[Process] # compile & run 2 progs in parallel +for prog in ["a", "b"]: + ps.add startProcess("nim", "", + ["r", "--hint[Conf]=off", "--hint[Processing]=off", prog], + options = {poUsePath, poDaemon, poStdErrToStdOut}) + +for p in ps: + let (lines, exCode) = p.readLines + if exCode != 0: + for line in lines: echo line + p.close From 84d9b1227d036e2286cbceace0d8dd27c515c62b Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Thu, 1 Oct 2020 17:07:55 +0100 Subject: [PATCH 1177/4254] fixes #15430, pop pragma takes invalid input (#15449) * fix #15430, pop pragma {.pop, experimental.} should be allowed, but not {.pop experimental.} --- compiler/pragmas.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 3b7ae175d..67e574d52 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1037,7 +1037,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wPush: processPush(c, n, i + 1) result = true - of wPop: processPop(c, it) + of wPop: + processPop(c, it) + result = true of wPragma: if not sym.isNil and sym.kind == skTemplate: sym.flags.incl sfCustomPragma From 800d6204cd1e55919fb608ed8f151774894ee2b7 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 1 Oct 2020 19:58:08 +0200 Subject: [PATCH 1178/4254] Fix "arraq" typo :) --- doc/manual_experimental.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index a71fd00b9..109399d61 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1906,7 +1906,7 @@ Let ``source`` be one of: not cover locals of inner procs. - A thread-local ``var`` or ``let``. - A global ``let`` or ``const``. -- A constant arraq/seq/object/tuple constructor. +- A constant array/seq/object/tuple constructor. Path expressions From 37e0d6f32d39752e0017685c471e19071570150c Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 1 Oct 2020 19:58:53 +0200 Subject: [PATCH 1179/4254] Fix typo --- doc/manual_experimental.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 109399d61..655adae02 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1994,7 +1994,7 @@ Start of a borrow A borrow starts with one of the following: - The assignment of a non-view-type to a view-type. -- The assingment of a location that is derived from a local parameter +- The assignment of a location that is derived from a local parameter to a view-type. From b4fe0c88624e3af03715a93733644b0c71dfdcce Mon Sep 17 00:00:00 2001 From: Euan Date: Thu, 1 Oct 2020 21:15:34 +0100 Subject: [PATCH 1180/4254] Fix #15452 - ip protocol not defined on NetBSD (#15453) --- tests/stdlib/tgetprotobyname.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim index c3d8da0d8..b4df05102 100644 --- a/tests/stdlib/tgetprotobyname.nim +++ b/tests/stdlib/tgetprotobyname.nim @@ -10,7 +10,10 @@ discard """ import nativesockets -doAssert getProtoByName("ip") == 0 +when not defined(netbsd): + # Ref: https://github.com/nim-lang/Nim/issues/15452 - NetBSD doesn't define an `ip` protocol + doAssert getProtoByName("ip") == 0 + doAssert getProtoByName("ipv6") == 41 doAssert getProtoByName("tcp") == 6 doAssert getProtoByName("udp") == 17 From d1eb76184b114736a40aef2299f98be6b0b384c7 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 1 Oct 2020 17:19:06 -0300 Subject: [PATCH 1181/4254] Clean out niminst (#15451) --- tools/niminst/niminst.nim | 105 +++++++++++--------------------------- 1 file changed, 31 insertions(+), 74 deletions(-) diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index a5fc388cd..2b6172390 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -7,12 +7,6 @@ # distribution, for details about the copyright. # -const - haveZipLib = false # zip not in stdlib anymore - -when haveZipLib: - import zipfiles - import os, strutils, parseopt, parsecfg, strtabs, streams, debcreation, std / sha1 @@ -36,7 +30,6 @@ type actionInno, # action: create Inno Setup installer actionNsis, # action: create NSIS installer actionScripts # action: create install and deinstall scripts - actionZip, # action: create zip file actionXz, # action: create xz file actionDeb # action: prepare deb package @@ -75,7 +68,7 @@ const "$configdir", "$datadir", "$docdir", "$libdir" ] -proc iniConfigData(c: var ConfigData) = +func iniConfigData(c: var ConfigData) = c.actions = {} for i in low(FileCategory)..high(FileCategory): c.cat[i] = @[] c.binPaths = @[] @@ -107,17 +100,17 @@ proc iniConfigData(c: var ConfigData) = c.debOpts.shortDesc = "" c.debOpts.licenses = @[] -proc firstBinPath(c: ConfigData): string = +func firstBinPath(c: ConfigData): string = if c.binPaths.len > 0: result = c.binPaths[0] else: result = "" -proc `\`(a, b: string): string = +func `\`(a, b: string): string = result = if a.len == 0: b else: a & '\\' & b template toUnix(s: string): string = s.replace('\\', '/') template toWin(s: string): string = s.replace('/', '\\') -proc skipRoot(f: string): string = +func skipRoot(f: string): string = # "abc/def/xyz" --> "def/xyz" var i = 0 result = "" @@ -146,7 +139,6 @@ Usage: Command: csource build C source code for source based installations scripts build install and deinstall scripts - zip build the ZIP file inno build the Inno Setup installer nsis build the NSIS Setup installer deb create files for debhelper @@ -175,7 +167,6 @@ proc parseCmdLine(c: var ConfigData) = case a of "csource": incl(c.actions, actionCSource) of "scripts": incl(c.actions, actionScripts) - of "zip": incl(c.actions, actionZip) of "xz": incl(c.actions, actionXz) of "inno": incl(c.actions, actionInno) of "nsis": incl(c.actions, actionNsis) @@ -221,11 +212,11 @@ proc eqT(a, b: string; t: proc (a: char): char{.nimcall.}): bool = inc j result = i >= a.len and j >= b.len -proc tPath(c: char): char = +func tPath(c: char): char = if c == '\\': '/' else: c -proc ignoreFile(f, explicit: string, allowHtml: bool): bool = +func ignoreFile(f, explicit: string, allowHtml: bool): bool = let (_, name, ext) = splitFile(f) let html = if not allowHtml: ".html" else: "" result = (ext in ["", ".exe", ".idx", ".o", ".obj", ".dylib"] or @@ -283,13 +274,13 @@ proc yesno(p: var CfgParser, v: string): bool = result = false else: quit(errorStr(p, "unknown value; use: yes|no")) -proc incl(s: var seq[string], x: string): int = +func incl(s: var seq[string], x: string): int = for i in 0 ..< s.len: if cmpIgnoreStyle(s[i], x) == 0: return i s.add(x) result = s.len-1 -proc platforms(c: var ConfigData, v: string) = +func platforms(c: var ConfigData, v: string) = for line in splitLines(v): let p = line.find(": ") if p <= 1: continue @@ -462,10 +453,10 @@ proc readCFiles(c: var ConfigData, osA, cpuA: int) = else: quit("Cannot open: " & f) -proc buildDir(os, cpu: int): string = - return "c_code" / ($os & "_" & $cpu) +func buildDir(os, cpu: int): string = + "c_code" / ($os & "_" & $cpu) -proc getOutputDir(c: var ConfigData): string = +func getOutputDir(c: var ConfigData): string = if c.outdir.len > 0: c.outdir else: "build" proc writeFile(filename, content, newline: string) = @@ -596,42 +587,6 @@ proc setupDist2(c: var ConfigData) = else: quit("External program failed") -# ------------------ generate ZIP file --------------------------------------- -when haveZipLib: - proc zipDist(c: var ConfigData) = - var proj = toLowerAscii(c.name) & "-" & c.version - var n = "$#.zip" % proj - if c.outdir.len == 0: n = "build" / n - else: n = c.outdir / n - var z: ZipArchive - if open(z, n, fmWrite): - addFile(z, proj / buildBatFile, "build" / buildBatFile) - addFile(z, proj / buildBatFile32, "build" / buildBatFile32) - addFile(z, proj / buildBatFile64, "build" / buildBatFile64) - addFile(z, proj / buildShFile, "build" / buildShFile) - addFile(z, proj / makeFile, "build" / makeFile) - addFile(z, proj / installShFile, installShFile) - addFile(z, proj / deinstallShFile, deinstallShFile) - - template addFileAux(src, dst) = addFile(z, dst, src) - gatherFiles(addFileAux, c.libpath, proj / "c_code") - for osA in 1..c.oses.len: - for cpuA in 1..c.cpus.len: - var dir = buildDir(osA, cpuA) - for k, f in walkDir("build" / dir): - if k == pcFile: addFile(z, proj / dir / extractFilename(f), f) - - for cat in items({fcConfig..fcOther, fcUnix, fcNimble}): - for f in items(c.cat[cat]): addFile(z, proj / f, f) - - # Copy the .nimble file over - let nimbleFile = c.nimblePkgName & ".nimble" - processFile(z, proj / nimbleFile, nimbleFile) - - close(z) - else: - quit("Cannot open for writing: " & n) - proc xzDist(c: var ConfigData; windowsZip=false) = let proj = toLowerAscii(c.name) & "-" & c.version let tmpDir = if c.outdir.len == 0: "build" else: c.outdir @@ -753,21 +708,23 @@ proc debDist(c: var ConfigData) = # ------------------- main ---------------------------------------------------- -var c: ConfigData -iniConfigData(c) -parseCmdLine(c) -parseIniFile(c) -if actionInno in c.actions: - setupDist(c) -if actionNsis in c.actions: - setupDist2(c) -if actionCSource in c.actions: - srcdist(c) -if actionScripts in c.actions: - writeInstallScripts(c) -if actionZip in c.actions: - xzDist(c, true) -if actionXz in c.actions: - xzDist(c) -if actionDeb in c.actions: - debDist(c) +proc main() = + var c: ConfigData + iniConfigData(c) + parseCmdLine(c) + parseIniFile(c) + if actionInno in c.actions: + setupDist(c) + if actionNsis in c.actions: + setupDist2(c) + if actionCSource in c.actions: + srcdist(c) + if actionScripts in c.actions: + writeInstallScripts(c) + if actionXz in c.actions: + xzDist(c) + if actionDeb in c.actions: + debDist(c) + +when isMainModule: + main() From 6e32a9e88c4f2a63a4645748e06a9ff51d384232 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 2 Oct 2020 14:47:24 +0800 Subject: [PATCH 1182/4254] use func in httpcore (#15457) --- lib/pure/httpcore.nim | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 81e02a1f8..e7da77ae8 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -102,24 +102,24 @@ const const httpNewLine* = "\c\L" const headerLimit* = 10_000 -proc toTitleCase(s: string): string = +func toTitleCase(s: string): string = result = newString(len(s)) var upper = true for i in 0..len(s) - 1: result[i] = if upper: toUpperAscii(s[i]) else: toLowerAscii(s[i]) upper = s[i] == '-' -proc toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = +func toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = return if headers.isTitleCase: toTitleCase(s) else: toLowerAscii(s) -proc newHttpHeaders*(titleCase=false): HttpHeaders = +func newHttpHeaders*(titleCase=false): HttpHeaders = ## Returns a new ``HttpHeaders`` object. if ``titleCase`` is set to true, ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() result.isTitleCase = titleCase -proc newHttpHeaders*(keyValuePairs: +func newHttpHeaders*(keyValuePairs: openArray[tuple[key: string, val: string]], titleCase=false): HttpHeaders = ## Returns a new ``HttpHeaders`` object from an array. if ``titleCase`` is set to true, ## headers are passed to the server in title case (e.g. "Content-Length") @@ -134,13 +134,13 @@ proc newHttpHeaders*(keyValuePairs: result.table[key] = @[pair.val] -proc `$`*(headers: HttpHeaders): string = +func `$`*(headers: HttpHeaders): string = return $headers.table proc clear*(headers: HttpHeaders) = headers.table.clear() -proc `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = +func `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = ## Returns the values associated with the given ``key``. If the returned ## values are passed to a procedure expecting a ``string``, the first ## value is automatically picked. If there are @@ -153,7 +153,7 @@ proc `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = converter toString*(values: HttpHeaderValues): string = return seq[string](values)[0] -proc `[]`*(headers: HttpHeaders, key: string, i: int): string = +func `[]`*(headers: HttpHeaders, key: string, i: int): string = ## Returns the ``i``'th value associated with the given key. If there are ## no values associated with the key or the ``i``'th value doesn't exist, ## an exception is raised. @@ -188,16 +188,16 @@ iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = for value in v: yield (k, value) -proc contains*(values: HttpHeaderValues, value: string): bool = +func contains*(values: HttpHeaderValues, value: string): bool = ## Determines if ``value`` is one of the values inside ``values``. Comparison ## is performed without case sensitivity. for val in seq[string](values): if val.toLowerAscii == value.toLowerAscii: return true -proc hasKey*(headers: HttpHeaders, key: string): bool = +func hasKey*(headers: HttpHeaders, key: string): bool = return headers.table.hasKey(headers.toCaseInsensitive(key)) -proc getOrDefault*(headers: HttpHeaders, key: string, +func getOrDefault*(headers: HttpHeaders, key: string, default = @[""].HttpHeaderValues): HttpHeaderValues = ## Returns the values associated with the given ``key``. If there are no ## values associated with the key, then ``default`` is returned. @@ -206,9 +206,9 @@ proc getOrDefault*(headers: HttpHeaders, key: string, else: return default -proc len*(headers: HttpHeaders): int = return headers.table.len +func len*(headers: HttpHeaders): int = return headers.table.len -proc parseList(line: string, list: var seq[string], start: int): int = +func parseList(line: string, list: var seq[string], start: int): int = var i = 0 var current = "" while start+i < line.len and line[start + i] notin {'\c', '\l'}: @@ -219,7 +219,7 @@ proc parseList(line: string, list: var seq[string], start: int): int = i.inc # Skip , current.setLen(0) -proc parseHeader*(line: string): tuple[key: string, value: seq[string]] = +func parseHeader*(line: string): tuple[key: string, value: seq[string]] = ## Parses a single raw header HTTP line into key value pairs. ## ## Used by ``asynchttpserver`` and ``httpclient`` internally and should not @@ -239,7 +239,7 @@ proc parseHeader*(line: string): tuple[key: string, value: seq[string]] = else: result.value = @[] -proc `==`*(protocol: tuple[orig: string, major, minor: int], +func `==`*(protocol: tuple[orig: string, major, minor: int], ver: HttpVersion): bool = let major = case ver @@ -250,10 +250,10 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int], of HttpVer10: 0 result = protocol.major == major and protocol.minor == minor -proc contains*(methods: set[HttpMethod], x: string): bool = +func contains*(methods: set[HttpMethod], x: string): bool = return parseEnum[HttpMethod](x) in methods -proc `$`*(code: HttpCode): string = +func `$`*(code: HttpCode): string = ## Converts the specified ``HttpCode`` into a HTTP status. ## ## For example: @@ -311,7 +311,7 @@ proc `$`*(code: HttpCode): string = of 505: "505 HTTP Version Not Supported" else: $(int(code)) -proc `==`*(a, b: HttpCode): bool {.borrow.} +func `==`*(a, b: HttpCode): bool {.borrow.} proc `==`*(rawCode: string, code: HttpCode): bool {.deprecated: "Deprecated since v1.2; use rawCode == $code instead".} = @@ -323,23 +323,23 @@ proc `==`*(rawCode: string, code: HttpCode): bool ## string form of itself. return cmpIgnoreCase(rawCode, $code) == 0 -proc is2xx*(code: HttpCode): bool = +func is2xx*(code: HttpCode): bool = ## Determines whether ``code`` is a 2xx HTTP status code. return code.int in {200 .. 299} -proc is3xx*(code: HttpCode): bool = +func is3xx*(code: HttpCode): bool = ## Determines whether ``code`` is a 3xx HTTP status code. return code.int in {300 .. 399} -proc is4xx*(code: HttpCode): bool = +func is4xx*(code: HttpCode): bool = ## Determines whether ``code`` is a 4xx HTTP status code. return code.int in {400 .. 499} -proc is5xx*(code: HttpCode): bool = +func is5xx*(code: HttpCode): bool = ## Determines whether ``code`` is a 5xx HTTP status code. return code.int in {500 .. 599} -proc `$`*(httpMethod: HttpMethod): string = +func `$`*(httpMethod: HttpMethod): string = return (system.`$`(httpMethod))[4 .. ^1].toUpperAscii() when isMainModule: From f785174c6009969ab853e0e2ce28f68c8b961776 Mon Sep 17 00:00:00 2001 From: Euan Date: Fri, 2 Oct 2020 10:17:31 +0100 Subject: [PATCH 1183/4254] Ref #14094 - disable hot code reloading tests on NetBSD (#15458) --- tests/dll/nimhcr_integration.nim | 1 + tests/dll/nimhcr_unit.nim | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/dll/nimhcr_integration.nim b/tests/dll/nimhcr_integration.nim index f6c6d21bc..626502364 100644 --- a/tests/dll/nimhcr_integration.nim +++ b/tests/dll/nimhcr_integration.nim @@ -1,5 +1,6 @@ discard """ disabled: "openbsd" + disabled: "netbsd" disabled: "macosx" output: ''' main: HELLO! diff --git a/tests/dll/nimhcr_unit.nim b/tests/dll/nimhcr_unit.nim index 31f398258..0b924bdf7 100644 --- a/tests/dll/nimhcr_unit.nim +++ b/tests/dll/nimhcr_unit.nim @@ -1,5 +1,6 @@ discard """ disabled: "openbsd" +disabled: "netbsd" output: ''' fastcall_proc implementation #1 10 11 From aa1d7fe1e9d9c63691b46d7d1c4c37e2c814bfc5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Oct 2020 12:38:16 +0200 Subject: [PATCH 1184/4254] closureiters: fixes #15243 (#15454) [backport:1.2] * fixes #15243 [backport:1.2] --- compiler/ccgexprs.nim | 18 +++- compiler/closureiters.nim | 105 ++++++++++++++++++++++- compiler/nim.cfg | 7 ++ lib/pure/xmltree.nim | 4 +- tests/async/tasyncawait_cyclebreaker.nim | 66 -------------- tests/async/tbreak_must_exec_finally.nim | 25 ++++++ 6 files changed, 153 insertions(+), 72 deletions(-) delete mode 100644 tests/async/tasyncawait_cyclebreaker.nim create mode 100644 tests/async/tbreak_must_exec_finally.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 49b1f3d16..b58519614 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3050,7 +3050,23 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope = proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = case n.kind of nkHiddenStdConv, nkHiddenSubConv: - result = genBracedInit(p, n[1], isConst) + when false: + # XXX The frontend doesn't keep conversions to openArray for us. :-( + # We need to change 'transformConv' first, but that is hard. + if n.typ.kind == tyOpenArray: + assert n[1].kind == nkBracket + let data = genBracedInit(p, n[1], isConst) + + let payload = getTempName(p.module) + let ctype = getTypeDesc(p.module, n.typ.skipTypes(abstractInst)[0]) + let arrLen = n[1].len + appcg(p.module, cfsData, + "static $5 $1 $3[$2] = $4;$n", [ + ctype, arrLen, payload, data, + if isConst: "const" else: ""]) + result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen] + else: + result = genBracedInit(p, n[1], isConst) else: var ty = tyNone if n.typ == nil: diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 912172e62..567bb3b91 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -130,7 +130,8 @@ import ast, msgs, idents, - renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos + renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos, + tables, options type Ctx = object @@ -1103,7 +1104,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int = result = ctx.states[stateIdx][0].intVal.int -proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode = +proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode= result = n case n.kind of nkSkip: @@ -1283,6 +1284,101 @@ proc deleteEmptyStates(ctx: var Ctx) = else: inc i +type + PreprocessContext = object + finallys: seq[PNode] + config: ConfigRef + blocks: seq[(PNode, int)] + FreshVarsContext = object + tab: Table[int, PSym] + config: ConfigRef + info: TLineInfo + +proc freshVars(n: PNode; c: var FreshVarsContext): PNode = + case n.kind + of nkSym: + let x = c.tab.getOrDefault(n.sym.id) + if x == nil: + result = n + else: + result = newSymNode(x, n.info) + of nkSkip - {nkSym}: + result = n + of nkLetSection, nkVarSection: + result = copyNode(n) + for it in n: + if it.kind in {nkIdentDefs, nkVarTuple}: + let idefs = copyNode(it) + for v in 0..it.len-3: + if it[v].kind == nkSym: + let x = copySym(it[v].sym) + c.tab[it[v].sym.id] = x + idefs.add newSymNode(x) + else: + idefs.add it[v] + + for rest in it.len-2 ..< it.len: idefs.add it[rest] + result.add idefs + else: + result.add it + of nkRaiseStmt: + localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'") + else: + result = n + for i in 0..= 0: + result = newNodeI(nkStmtList, n.info) + for i in countdown(c.finallys.high, fin): + var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info) + result.add freshVars(preprocess(c, c.finallys[i]), vars) + result.add n + of nkSkip: discard + else: + for i in 0 ..< n.len: + result[i] = preprocess(c, n[i]) + proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode = var ctx: Ctx ctx.g = g @@ -1295,7 +1391,10 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode = ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info) ctx.stateVarSym.typ = g.createClosureIterStateType(fn) ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info) - var n = n.toStmtList + var pc = PreprocessContext(finallys: @[], config: g.config) + var n = preprocess(pc, n.toStmtList) + #echo "transformed into ", n + #var n = n.toStmtList discard ctx.newState(n, nil) let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1)) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 8e733bdf8..33ddc6f0b 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -19,6 +19,13 @@ define:useStdoutAsStdmsg styleCheck:error @end +# die when the Nim compiler uses more than 4GB: +@if cpu32: + define:"nimMaxHeap=2000" +@else: + define:"nimMaxHeap=4000" +@end + #define:useNodeIds #gc:markAndSweep diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 00e9a031b..df8db1bb7 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -45,7 +45,7 @@ type XmlNodeKind* = enum ## Different kinds of XML nodes. xnText, ## a text element - xnVerbatimText, ## + xnVerbatimText, ## xnElement, ## an element with 0 or more children xnCData, ## a CDATA node xnEntity, ## an entity (like ``&thing;``) @@ -103,7 +103,7 @@ proc newText*(text: string): XmlNode = result = newXmlNode(xnText) result.fText = text -proc newVerbatimText*(text: string): XmlNode {.since: (1, 3).} = +proc newVerbatimText*(text: string): XmlNode {.since: (1, 3).} = ## Creates a new ``XmlNode`` of kind ``xnVerbatimText`` with the text `text`. ## **Since**: Version 1.3. result = newXmlNode(xnVerbatimText) diff --git a/tests/async/tasyncawait_cyclebreaker.nim b/tests/async/tasyncawait_cyclebreaker.nim deleted file mode 100644 index 2229d99c0..000000000 --- a/tests/async/tasyncawait_cyclebreaker.nim +++ /dev/null @@ -1,66 +0,0 @@ -discard """ - output: "20000" - cmd: "nim c -d:nimTypeNames -d:nimCycleBreaker $file" -""" -import asyncdispatch, asyncnet, nativesockets, net, strutils -from stdtest/netutils import bindAvailablePort - -var msgCount = 0 - -const - swarmSize = 400 - messagesToSend = 50 - -var clientCount = 0 - -proc sendMessages(client: AsyncFD) {.async.} = - for i in 0 ..< messagesToSend: - await send(client, "Message " & $i & "\c\L") - -proc launchSwarm(port: Port) {.async.} = - for i in 0 ..< swarmSize: - var sock = createAsyncNativeSocket() - - await connect(sock, "localhost", port) - await sendMessages(sock) - closeSocket(sock) - -proc readMessages(client: AsyncFD) {.async.} = - # wrapping the AsyncFd into a AsyncSocket object - var sockObj = newAsyncSocket(client) - var (ipaddr, port) = sockObj.getPeerAddr() - doAssert ipaddr == "127.0.0.1" - (ipaddr, port) = sockObj.getLocalAddr() - doAssert ipaddr == "127.0.0.1" - while true: - var line = await recvLine(sockObj) - if line == "": - closeSocket(client) - clientCount.inc - break - else: - if line.startswith("Message "): - msgCount.inc - else: - doAssert false - -proc createServer(server: AsyncFD) {.async.} = - discard server.SocketHandle.listen() - while true: - asyncCheck readMessages(await accept(server)) - -let server = createAsyncNativeSocket() -let port = bindAvailablePort(server.SocketHandle) -asyncCheck createServer(server) -asyncCheck launchSwarm(port) -while true: - poll() - GC_collectZct() - - let (allocs, deallocs) = getMemCounters() - doAssert allocs < deallocs + 1000 - - if clientCount == swarmSize: break - -assert msgCount == swarmSize * messagesToSend -echo msgCount diff --git a/tests/async/tbreak_must_exec_finally.nim b/tests/async/tbreak_must_exec_finally.nim new file mode 100644 index 000000000..8780e6149 --- /dev/null +++ b/tests/async/tbreak_must_exec_finally.nim @@ -0,0 +1,25 @@ +discard """ + output: ''' +finally handler 8 +do not duplicate this one +''' +""" + +# bug #15243 + +import asyncdispatch + +proc f() {.async.} = + try: + while true: + try: + await sleepAsync(400) + break + finally: + var localHere = 8 + echo "finally handler ", localHere + finally: + echo "do not duplicate this one" + +when isMainModule: + waitFor f() From 1f4b9cebd4a073024f68e70156be1d8ceab7344f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Oct 2020 17:22:31 +0200 Subject: [PATCH 1185/4254] Added std/effecttraits.nim (#15462) --- changelog.md | 4 +++- compiler/vmops.nim | 9 +++++++++ lib/std/effecttraits.nim | 19 +++++++++++++++++++ tests/macros/tgetraiseslist.nim | 22 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 lib/std/effecttraits.nim create mode 100644 tests/macros/tgetraiseslist.nim diff --git a/changelog.md b/changelog.md index 3cdf138ad..219d085b1 100644 --- a/changelog.md +++ b/changelog.md @@ -292,7 +292,9 @@ proc mydiv(a, b): int {.raises: [].} = - `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via `--deepcopy:on`. - +- Added a `std/effecttraits` module for introspection of the inferred `.raise` effects. + We hope this enables `async` macros that are precise about the possible exceptions that + can be raised. - Added `critbits.toCritBitTree`, similar to `tables.toTable`, creates a new `CritBitTree` with given arguments. diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 298a02bb6..de6229ec7 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -261,3 +261,12 @@ proc registerAdditionalOps*(c: PCtx) = a.setResult osproc.execCmdEx(getString(a, 0), options).toLit registerCallback c, "stdlib.times.getTime", proc (a: VmArgs) {.nimcall.} = setResult(a, times.getTime().toLit) + + registerCallback c, "stdlib.effecttraits.getRaisesListImpl", proc (a: VmArgs) = + let fn = getNode(a, 0) + if fn.typ != nil and fn.typ.n != nil and fn.typ.n[0].len >= effectListLen and + fn.typ.n[0][exceptionEffects] != nil: + var list = newNodeI(nkBracket, fn.info) + for e in fn.typ.n[0][exceptionEffects]: + list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info) + setResult(a, list) diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim new file mode 100644 index 000000000..a5d799786 --- /dev/null +++ b/lib/std/effecttraits.nim @@ -0,0 +1,19 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2018 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module provides access to the inferred .raises effects +## for Nim's macro system. + +import macros + +proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" + +proc getRaisesList*(call: NimNode): NimNode = + expectKind call, nnkCallKinds + result = getRaisesListImpl(call[0]) diff --git a/tests/macros/tgetraiseslist.nim b/tests/macros/tgetraiseslist.nim new file mode 100644 index 000000000..de7ba06c8 --- /dev/null +++ b/tests/macros/tgetraiseslist.nim @@ -0,0 +1,22 @@ +discard """ + nimout: '''##[ValueError, Gen[string]]##''' +""" + +import macros +import std / effecttraits + +type + Gen[T] = object of CatchableError + x: T + +macro m(call: typed): untyped = + echo "##", repr getRaisesList(call), "##" + result = call + +proc r(inp: int) = + if inp == 0: + raise newException(ValueError, "bah") + elif inp == 1: + raise newException(Gen[string], "bahB") + +m r(2) From 7d8c1be8fb1ba96dd16c40df990d4c2639515173 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Oct 2020 18:26:52 +0200 Subject: [PATCH 1186/4254] parser hotfix: don't run into endless loops; regression (#15468) --- compiler/parser.nim | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 17dd092a4..1ec708057 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -529,15 +529,21 @@ proc semiStmtList(p: var Parser, result: PNode) = inc p.inSemiStmtList withInd(p): # Be lenient with the first stmt/expr - result.add if p.tok.tokType == tkIf: parseIfExpr(p, nkIfStmt) else: complexOrSimpleStmt(p) - while true: + let a = if p.tok.tokType == tkIf: parseIfExpr(p, nkIfStmt) else: complexOrSimpleStmt(p) + result.add a + + while p.tok.tokType != tkEof: if p.tok.tokType == tkSemiColon: getTok(p) if p.tok.tokType == tkParRi: break elif not (sameInd(p) or realInd(p)): parMessage(p, errInvalidIndentation) - result.add complexOrSimpleStmt(p) + let a = complexOrSimpleStmt(p) + if a.kind == nkEmpty: + parMessage(p, errExprExpected, p.tok) + else: + result.add a dec p.inSemiStmtList result.transitionSonsKind(nkStmtListExpr) @@ -2244,7 +2250,13 @@ proc parseStmt(p: var Parser): PNode = if p.tok.tokType in {tkElse, tkElif}: break # Allow this too, see tests/parser/tifexprs - result.add complexOrSimpleStmt(p) + let a = complexOrSimpleStmt(p) + if a.kind == nkEmpty and not p.hasProgress: + parMessage(p, errExprExpected, p.tok) + break + else: + result.add a + if not p.hasProgress and p.tok.tokType == tkEof: break else: # the case statement is only needed for better error messages: From ff70ff529d23d5ca6abe0e16d815172dd24a9dd1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Oct 2020 18:51:49 +0200 Subject: [PATCH 1187/4254] remove nim.cfg file change lefover [backport:1.2] (#15469) --- compiler/nim.cfg | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 33ddc6f0b..cb586a9cb 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -19,12 +19,6 @@ define:useStdoutAsStdmsg styleCheck:error @end -# die when the Nim compiler uses more than 4GB: -@if cpu32: - define:"nimMaxHeap=2000" -@else: - define:"nimMaxHeap=4000" -@end #define:useNodeIds #gc:markAndSweep From e3eae3f7c7e9db6962f30dcb84657f3269ff3476 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 2 Oct 2020 11:52:20 -0500 Subject: [PATCH 1188/4254] tools/deps: fix git dir check (#15470) On Windows, a successful call will have a trailing newline appended, so strip that away before doing any checks. --- tools/deps.nim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/deps.nim b/tools/deps.nim index 394dc0d25..b238f12ed 100644 --- a/tools/deps.nim +++ b/tools/deps.nim @@ -1,4 +1,4 @@ -import os, uri, strformat, osproc +import os, uri, strformat, osproc, strutils proc exec(cmd: string) = echo "deps.cmd: " & cmd @@ -14,7 +14,11 @@ proc isGitRepo(dir: string): bool = # Using this, we can verify whether a folder is a git repository by checking # whether the command success and if the output is empty. let (output, status) = execEx fmt"git -C {quoteShell(dir)} rev-parse --show-cdup" - result = status == 0 and output == "" + # On Windows there will be a trailing newline on success, remove it. + # The value of a successful call typically won't have a whitespace (it's + # usually a series of ../), so we know that it's safe to unconditionally + # remove trailing whitespaces from the result. + result = status == 0 and output.strip() == "" const commitHead* = "HEAD" From 9828392df3ac05ead78e14bde7b5865309df8a95 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Oct 2020 18:53:22 +0200 Subject: [PATCH 1189/4254] implements https://github.com/nim-lang/RFCs/issues/257 (#15466) --- compiler/parampatterns.nim | 2 ++ compiler/transf.nim | 7 ------- compiler/trees.nim | 7 +++++++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index ed8f2c16a..c2be4b134 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -223,6 +223,8 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arLValue elif isUnsafeAddr and n.sym.kind == skParam: result = arLValue + elif isUnsafeAddr and n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast): + result = arLValue elif n.sym.kind in kinds: if owner != nil and owner == n.sym.owner and sfGlobal notin n.sym.flags: diff --git a/compiler/transf.nim b/compiler/transf.nim index 5dd275414..c8dbf5e04 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -850,13 +850,6 @@ proc transformExceptBranch(c: PTransf, n: PNode): PNode = else: result = transformSons(c, n) -proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} = - # symbols that expand to a complex constant (array, etc.) should not be - # inlined, unless it's the empty array: - result = orig.kind == nkSym and - cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and - cnst.len != 0 - proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode = result = n for i in 0.. Date: Fri, 2 Oct 2020 12:18:44 -0500 Subject: [PATCH 1190/4254] koch: remove c2nim from windows release builds (#15471) We don't ship this tool with any other OS, and the c2nim bundle is non-deterministic due to the lack of a pinned commit. --- koch.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/koch.nim b/koch.nim index 714d70bfe..bbb37b702 100644 --- a/koch.nim +++ b/koch.nim @@ -168,7 +168,6 @@ proc bundleWinTools(args: string) = buildVccTool(args) nimCompile("tools/nimgrab.nim", options = "-d:ssl " & args) nimCompile("tools/nimgrep.nim", options = args) - bundleC2nim(args) nimCompile("testament/testament.nim", options = args) when false: # not yet a tool worth including From d48b356e493a7a7f6e2cf9855de893f811b2e9ad Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Fri, 2 Oct 2020 21:10:24 +0200 Subject: [PATCH 1191/4254] intsets.nim: Add `toIntSet` proc (#15460) Similar to: - `critbits.toCritBitTree` - `deques.toDeque` - `sets.toHashSet` - `tables.toTable` --- changelog.md | 5 +++++ lib/pure/collections/intsets.nim | 28 +++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 219d085b1..7d1217f97 100644 --- a/changelog.md +++ b/changelog.md @@ -201,6 +201,11 @@ - Add `readLines(p: Process)` to `osproc` module for `startProcess` convenience. +- Added `intsets.toIntSet`, which creates an IntSet from an openArray. The usage + is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, + it was necessary to create an empty IntSet and add items manually. + + ## Language changes - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index eae3fa447..3be453e29 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -18,9 +18,8 @@ ## **See also:** ## * `sets module `_ for more general hash sets - -import - hashes +import std/private/since +import hashes type BitScalar = uint @@ -161,6 +160,9 @@ iterator items*(s: IntSet): int {.inline.} = proc initIntSet*: IntSet = ## Returns an empty IntSet. + ## + ## See also: + ## * `toIntSet proc <#toIntSet,openArray[int]>`_ runnableExamples: var a = initIntSet() assert len(a) == 0 @@ -251,6 +253,24 @@ proc incl*(s: var IntSet, other: IntSet) = for item in other: incl(s, item) +proc toIntSet*(x: openArray[int]): IntSet {.since: (1, 3).} = + ## Creates a new IntSet that contains the elements of `x`. + ## + ## Duplicates are removed. + ## + ## See also: + ## * `initIntSet proc <#initIntSet>`_ + runnableExamples: + var + a = toIntSet([5, 6, 7]) + b = toIntSet(@[1, 8, 8, 8]) + assert len(a) == 3 + assert len(b) == 2 + + result = initIntSet() + for item in items(x): + result.incl(item) + proc containsOrIncl*(s: var IntSet, key: int): bool = ## Includes `key` in the set `s` and tells if `key` was already in `s`. ## @@ -585,6 +605,8 @@ when isMainModule: x.incl(1044) x.excl(1044) + assert x == [1, 2, 7, 1056].toIntSet + assert x.containsOrIncl(888) == false assert 888 in x assert x.containsOrIncl(888) == true From 0a05176057dd0f98793b41e18f5599d662ab1672 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Fri, 2 Oct 2020 22:01:03 +0200 Subject: [PATCH 1192/4254] heapqueue.nim: Add `toHeapQueue` proc (#15459) Similar to: - `critbits.toCritBitTree` - `deques.toDeque` - `sets.toHashSet` - `tables.toTable` Co-authored-by: Andreas Rumpf --- changelog.md | 4 ++++ lib/pure/collections/heapqueue.nim | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/changelog.md b/changelog.md index 7d1217f97..5a439285c 100644 --- a/changelog.md +++ b/changelog.md @@ -201,6 +201,10 @@ - Add `readLines(p: Process)` to `osproc` module for `startProcess` convenience. +- Added `heapqueue.toHeapQueue`, which creates a HeapQueue from an openArray. + The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. + Previously, it was necessary to create an empty HeapQueue and add items + manually. - Added `intsets.toIntSet`, which creates an IntSet from an openArray. The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create an empty IntSet and add items manually. diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index c2952cf1b..ca0666651 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -58,6 +58,9 @@ type HeapQueue*[T] = object proc initHeapQueue*[T](): HeapQueue[T] = ## Create a new empty heap. + ## + ## See also: + ## * `toHeapQueue proc <#toHeapQueue,openArray[T]>`_ discard proc len*[T](heap: HeapQueue[T]): int {.inline.} = @@ -115,6 +118,20 @@ proc push*[T](heap: var HeapQueue[T], item: T) = heap.data.add(item) siftdown(heap, 0, len(heap)-1) +proc toHeapQueue*[T](x: openArray[T]): HeapQueue[T] {.since: (1, 3).} = + ## Creates a new HeapQueue that contains the elements of `x`. + ## + ## See also: + ## * `initHeapQueue proc <#initHeapQueue>`_ + runnableExamples: + var heap = toHeapQueue([9, 5, 8]) + assert heap.pop() == 5 + assert heap[0] == 8 + + result = initHeapQueue[T]() + for item in items(x): + result.push(item) + proc pop*[T](heap: var HeapQueue[T]): T = ## Pop and return the smallest item from `heap`, ## maintaining the heap invariant. @@ -195,6 +212,7 @@ when isMainModule: let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] for item in data: push(heap, item) + doAssert(heap == data.toHeapQueue) doAssert(heap[0] == 0) doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) From dcd0ce17759609084951e4d3ac7f24b3eec62a26 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 2 Oct 2020 15:48:35 -0500 Subject: [PATCH 1193/4254] niminst: restore ZIP building functionality (#15472) This is necessary for building Windows releases, was erroneously removed by #15451. --- tools/niminst/niminst.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 2b6172390..a0a0d9ad4 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -30,6 +30,7 @@ type actionInno, # action: create Inno Setup installer actionNsis, # action: create NSIS installer actionScripts # action: create install and deinstall scripts + actionZip # action: create zip file actionXz, # action: create xz file actionDeb # action: prepare deb package @@ -139,6 +140,7 @@ Usage: Command: csource build C source code for source based installations scripts build install and deinstall scripts + zip build the ZIP file inno build the Inno Setup installer nsis build the NSIS Setup installer deb create files for debhelper @@ -167,6 +169,7 @@ proc parseCmdLine(c: var ConfigData) = case a of "csource": incl(c.actions, actionCSource) of "scripts": incl(c.actions, actionScripts) + of "zip": incl(c.actions, actionZip) of "xz": incl(c.actions, actionXz) of "inno": incl(c.actions, actionInno) of "nsis": incl(c.actions, actionNsis) @@ -721,6 +724,8 @@ proc main() = srcdist(c) if actionScripts in c.actions: writeInstallScripts(c) + if actionZip in c.actions: + xzDist(c, true) if actionXz in c.actions: xzDist(c) if actionDeb in c.actions: From 662c5080755eb5a42df2c3acb84c044876571a46 Mon Sep 17 00:00:00 2001 From: supakeen <39536295+supakeen@users.noreply.github.com> Date: Sat, 3 Oct 2020 13:43:43 +0200 Subject: [PATCH 1194/4254] Return type of asyncftpclient to fix example. (#15476) Related to: #13641 --- lib/pure/asyncftpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 208782c05..ba565059d 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -63,7 +63,7 @@ ## import asyncdispatch, asyncftpclient ## ## proc onProgressChanged(total, progress: BiggestInt, -## speed: float): Future[void] = +## speed: float) {.async.} = ## echo("Uploaded ", progress, " of ", total, " bytes") ## echo("Current speed: ", speed, " kb/s") ## From 2288188fe9a9d854a167dd270eb8d72d19676865 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 3 Oct 2020 17:34:42 +0200 Subject: [PATCH 1195/4254] fixes https://github.com/nim-lang/RFCs/issues/257 [backport:1.2] (#15479) --- compiler/trees.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index 2cf6b4f67..c5e2cb7b4 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -200,5 +200,5 @@ proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} = # symbols that expand to a complex constant (array, etc.) should not be # inlined, unless it's the empty array: result = orig.kind == nkSym and - cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and - cnst.len != 0 + cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and + cnst.len > ord(cnst.kind == nkObjConstr) From fc973b2c0cf4fb550556ef05968e952ca174956f Mon Sep 17 00:00:00 2001 From: alaviss Date: Sat, 3 Oct 2020 17:39:56 -0500 Subject: [PATCH 1196/4254] renderer: use the biggest integer type for masking literals (#15482) On 32-bit system the mask would have a size of 32-bit, which is smaller than the BiggestInt (usually 64-bit) it was masked against. For some reason this only affect 32-bit Windows but not 32-bit Linux. Might just be a difference in how gcc handle out of bound shifts for Windows and Linux. --- compiler/renderer.nim | 2 +- tests/macros/tmacros_issues.nim | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 9c7609f9a..88b9adf27 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -336,7 +336,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8) elif nfBase8 in n.flags: - var y = if size < sizeof(BiggestInt): x and ((1 shl (size*8)) - 1) + var y = if size < sizeof(BiggestInt): x and ((1.BiggestInt shl (size*8)) - 1) else: x result = "0o" & toOct(y, size * 3) elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2) diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index 3d992a27f..19c706a82 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -29,6 +29,7 @@ array[0 .. 100, int] 10 test 0o377'i8 +0o000000000755'i32 1 2 3 @@ -257,6 +258,7 @@ macro toRendererBug(n): untyped = result = newLit repr(n) echo toRendererBug(0o377'i8) +echo toRendererBug(0o755'i32) # bug #12129 macro foobar() = From ccd1f5818334c9e6d2bfca2fc60fed7656ac2b66 Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Sun, 4 Oct 2020 14:28:19 +0530 Subject: [PATCH 1197/4254] Installation Instruction (#15485) The instruction command was missing `install` for Ubuntu. --- lib/pure/distros.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index ae2248b40..8debbf9c8 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -13,8 +13,8 @@ ## ## To complete the installation, run: ## -## sudo apt-get libblas-dev -## sudo apt-get libvoodoo +## sudo apt-get install libblas-dev +## sudo apt-get install libvoodoo ## ## The above output could be the result of a code snippet like: ## From bbe2eb20dff980c55f9c480158ceb90046935c34 Mon Sep 17 00:00:00 2001 From: supakeen <39536295+supakeen@users.noreply.github.com> Date: Sun, 4 Oct 2020 12:32:07 +0200 Subject: [PATCH 1198/4254] Provide a configurable progressInterval. (#15477) --- changelog.md | 3 +++ lib/pure/asyncftpclient.nim | 17 +++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 5a439285c..e905dd941 100644 --- a/changelog.md +++ b/changelog.md @@ -209,6 +209,9 @@ is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create an empty IntSet and add items manually. +- Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval + at which progress callbacks are called. + ## Language changes diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index ba565059d..b538e10c9 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -59,6 +59,9 @@ ## by specifying a ``onProgressChanged`` procedure to the ``store`` or ## ``retrFile`` procedures. ## +## Procs that take an ``onProgressChanged`` callback will call this every +## ``progressInterval`` milliseconds. +## ## .. code-block::nim ## import asyncdispatch, asyncftpclient ## @@ -68,7 +71,7 @@ ## echo("Current speed: ", speed, " kb/s") ## ## proc main() {.async.} = -## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") +## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test", progressInterval = 500) ## await ftp.connect() ## await ftp.store("file.txt", "/home/user/file.txt", onProgressChanged) ## echo("File finished uploading") @@ -85,6 +88,7 @@ type user*, pass*: string address*: string port*: Port + progressInterval: int jobInProgress*: bool job*: FtpJob dsockConnected*: bool @@ -303,7 +307,7 @@ proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt, assert ftp.dsockConnected var progress = 0 var progressInSecond = 0 - var countdownFut = sleepAsync(1000) + var countdownFut = sleepAsync(ftp.progressInterval) var dataFut = ftp.dsock.recv(BufferSize) while ftp.dsockConnected: await dataFut or countdownFut @@ -311,7 +315,7 @@ proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt, asyncCheck onProgressChanged(total, progress, progressInSecond.float) progressInSecond = 0 - countdownFut = sleepAsync(1000) + countdownFut = sleepAsync(ftp.progressInterval) if dataFut.finished: let data = dataFut.read @@ -359,7 +363,7 @@ proc doUpload(ftp: AsyncFtpClient, file: File, var data = newString(4000) var progress = 0 var progressInSecond = 0 - var countdownFut = sleepAsync(1000) + var countdownFut = sleepAsync(ftp.progressInterval) var sendFut: Future[void] = nil while ftp.dsockConnected: if sendFut == nil or sendFut.finished: @@ -380,7 +384,7 @@ proc doUpload(ftp: AsyncFtpClient, file: File, if countdownFut.finished: asyncCheck onProgressChanged(total, progress, progressInSecond.float) progressInSecond = 0 - countdownFut = sleepAsync(1000) + countdownFut = sleepAsync(ftp.progressInterval) await countdownFut or sendFut @@ -415,13 +419,14 @@ proc removeDir*(ftp: AsyncFtpClient, dir: string) {.async.} = assertReply(await ftp.send("RMD " & dir), "250") proc newAsyncFtpClient*(address: string, port = Port(21), - user, pass = ""): AsyncFtpClient = + user, pass = "", progressInterval: int = 1000): AsyncFtpClient = ## Creates a new ``AsyncFtpClient`` object. new result result.user = user result.pass = pass result.address = address result.port = port + result.progressInterval = progressInterval result.dsockConnected = false result.csock = newAsyncSocket() From b760fdc9ca858dd146a34da86eabbc3d43fb0833 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 5 Oct 2020 15:57:23 +0800 Subject: [PATCH 1199/4254] make testing for prologue more stable (#15491) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index b4cc25f2a..e8d136151 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -98,7 +98,7 @@ pkg2 "patty" pkg2 "plotly", true, "nim c examples/all.nim" pkg2 "pnm" pkg2 "polypbren" -pkg2 "prologue", true, "nim c -d:release -r tests/test_compile/test_compile.nim" +pkg2 "prologue", true, "nimble tcompile" pkg2 "protobuf", true, "nim c -o:protobuff -r src/protobuf.nim" pkg2 "pylib" pkg2 "rbtree" From cc4c546f8f0846c44b295c9417c2fd98cb694ae8 Mon Sep 17 00:00:00 2001 From: Euan Date: Mon, 5 Oct 2020 11:00:06 +0100 Subject: [PATCH 1200/4254] Fix #15493 - disable TLS emulation for NetBSD (#15494) TLS emulation was already disabled for FreeBSD due to the same issue. --- tests/stdlib/tssl.nims | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/stdlib/tssl.nims b/tests/stdlib/tssl.nims index 3f24dc325..4739e7f07 100644 --- a/tests/stdlib/tssl.nims +++ b/tests/stdlib/tssl.nims @@ -1,5 +1,5 @@ --threads:on --d:ssl -when defined(freebsd): - # See https://github.com/nim-lang/Nim/pull/15066#issuecomment-665541265 +when defined(freebsd) or defined(netbsd): + # See https://github.com/nim-lang/Nim/pull/15066#issuecomment-665541265 and https://github.com/nim-lang/Nim/issues/15493 --tlsEmulation:off From 5967b6f60f669f343ed089a4cd09f324cbfc5c69 Mon Sep 17 00:00:00 2001 From: Luis Felipe Manfroni <33612042+luismanfroni@users.noreply.github.com> Date: Mon, 5 Oct 2020 07:02:08 -0300 Subject: [PATCH 1201/4254] doc(sugar): added description and examples to dup (#15455) --- lib/pure/sugar.nim | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 49934b9bb..be5e1f326 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -217,7 +217,10 @@ since (1, 1): macro dup*[T](arg: T, calls: varargs[untyped]): T = ## Turns an `in-place`:idx: algorithm into one that works on - ## a copy and returns this copy. + ## a copy and returns this copy, without modifying its input. + ## + ## This macro also allows for (otherwise in-place) function chaining. + ## ## **Since**: Version 1.2. runnableExamples: import algorithm @@ -234,6 +237,21 @@ since (1, 1): var s2 = "xyz" doAssert s1 & s2 == s1.dup(&= s2) + proc makePalindrome(s: var string) = + for i in countdown(s.len-2, 0): + s.add(s[i]) + + var c = "xyz" + + # An underscore (_) can be used to denote the place of the argument you're passing: + # b = "xyz" + var d = dup c: + makePalindrome # xyzyx + sort(_, SortOrder.Descending) # zyyxx + makePalindrome # zyyxxxyyz + + doAssert d == "zyyxxxyyz" + result = newNimNode(nnkStmtListExpr, arg) let tmp = genSym(nskVar, "dupResult") result.add newVarStmt(tmp, arg) From 112b11c154af1f56b8c842b5723e6097d40d9e60 Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 5 Oct 2020 17:03:14 +0200 Subject: [PATCH 1202/4254] group procs of the same name in TOC (#15487) * group procs of the same name in TOC * correctly show `sink` parameters in TOC * no need to reinvent the wheel - `mgetorPut` exists * better setting of text color [ci skip] * fix CSS for better alignment --- compiler/docgen.nim | 33 ++- compiler/docgen2.nim | 3 +- compiler/typesrenderer.nim | 5 + config/nimdoc.cfg | 14 ++ doc/nimdoc.css | 20 +- .../expected/index.html | 5 +- .../expected/subdir/subdir_b/utils.html | 5 +- nimdoc/testproject/expected/testproject.html | 208 +++++++++++++----- 8 files changed, 220 insertions(+), 73 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index c2ce12e50..fb15f3826 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -37,7 +37,8 @@ type modDesc: Rope # module description module: PSym modDeprecationMsg: Rope - toc, section: TSections + toc, toc2, section: TSections + tocTable: array[TSymKind, Table[string, Rope]] indexValFilename: string analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. @@ -871,6 +872,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, attype])) + d.tocTable[k].mgetOrPut(cleanPlainSymbol, nil).add(ropeFormatNamedVars( + d.conf, getConfigVar(d.conf, "doc.item.tocTable"), + ["name", "header", "desc", "itemID", "header_plain", "itemSym", + "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"], + [rope(getName(d, nameNode, d.splitAfter)), result, comm, + itemIDRope, plainNameRope, plainSymbolRope, + symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, attype])) + # Ironically for types the complexSymbol is *cleaner* than the plainName # because it doesn't include object fields or documentation comments. So we # use the plain one for callable elements, and the complex for the rest. @@ -1167,7 +1176,7 @@ proc generateTags*(d: PDoc, n: PNode, r: var Rope) = generateTags(d, lastSon(n[0]), r) else: discard -proc genSection(d: PDoc, kind: TSymKind) = +proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = const sectionNames: array[skModule..skField, string] = [ "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs", "Methods", "Iterators", "Converters", "Macros", "Templates", "Exports" @@ -1177,14 +1186,23 @@ proc genSection(d: PDoc, kind: TSymKind) = d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [ "sectionid", "sectionTitle", "sectionTitleID", "content"], [ ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]]) + + var tocSource = d.toc + if groupedToc: + for p in d.tocTable[kind].keys: + d.toc2[kind].add ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc2"), [ + "sectionid", "sectionTitle", "sectionTitleID", "content", "plainName"], [ + ord(kind).rope, title, rope(ord(kind) + 50), d.tocTable[kind][p], p.rope]) + tocSource = d.toc2 + d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [ "sectionid", "sectionTitle", "sectionTitleID", "content"], [ - ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]]) + ord(kind).rope, title, rope(ord(kind) + 50), tocSource[kind]]) proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): Rope = rope($relativeTo(outDir / linkto, destFile.splitFile().dir, '/')) -proc genOutFile(d: PDoc): Rope = +proc genOutFile(d: PDoc, groupedToc = false): Rope = var code, content: Rope title = "" @@ -1193,7 +1211,8 @@ proc genOutFile(d: PDoc): Rope = renderTocEntries(d[], j, 1, tmp) var toc = tmp.rope for i in TSymKind: - genSection(d, i) + var shouldSort = i in {skProc, skFunc} and groupedToc + genSection(d, i, shouldSort) toc.add(d.toc[i]) if toc != nil: toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc]) @@ -1246,9 +1265,9 @@ proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = if isAbsolute(d.conf.outFile.string): d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile -proc writeOutput*(d: PDoc, useWarning = false) = +proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) = runAllExamples(d) - var content = genOutFile(d) + var content = genOutFile(d, groupedToc) if optStdout in d.conf.globalOptions: writeRope(stdout, content) else: diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 438417ca0..9cb40a7fc 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -29,6 +29,7 @@ proc shouldProcess(g: PGen): bool = template closeImpl(body: untyped) {.dirty.} = var g = PGen(p) let useWarning = sfMainModule notin g.module.flags + let groupedToc = true if shouldProcess(g): body try: @@ -38,7 +39,7 @@ template closeImpl(body: untyped) {.dirty.} = proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: - writeOutput(g.doc, useWarning) + writeOutput(g.doc, useWarning, groupedToc) proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 050a057f4..613173252 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -78,6 +78,11 @@ proc renderType(n: PNode): string = result = renderType(n[0]) & '[' for i in 1.. 1: result.add ", " + result.add(renderType(n[i])) else: result = "" diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 9a56fdaae..a6a402bab 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -24,6 +24,12 @@ doc.section.toc = """ """ +doc.section.toc2 = """ +

    -
    proc c_printf(frmt: cstring): cint {...}{.importc: "printf", header: "<stdio.h>", varargs,
    -                                 discardable.}
    +
    proc c_printf(frmt: cstring): cint {...}{.importc: "printf", header: "<stdio.h>",
    +                                     varargs, discardable.}
    the c printf. etc.
    -
    proc c_nonexistant(frmt: cstring): cint {...}{.importc: "nonexistant", header: "<stdio.h>",
    -                                      varargs, discardable.}
    +
    proc c_nonexistant(frmt: cstring): cint {...}{.importc: "nonexistant",
    +    header: "<stdio.h>", varargs, discardable.}
    @@ -744,7 +744,8 @@ at indent 0
    -
    proc asyncFun1(): Future[int] {...}{.raises: [Exception, ValueError], tags: [RootEffect].}
    +
    proc asyncFun1(): Future[int] {...}{.raises: [Exception, ValueError],
    +                                tags: [RootEffect].}
    ok1 diff --git a/tests/errmsgs/tunknown_named_parameter.nim b/tests/errmsgs/tunknown_named_parameter.nim index b139310db..829ab9497 100644 --- a/tests/errmsgs/tunknown_named_parameter.nim +++ b/tests/errmsgs/tunknown_named_parameter.nim @@ -10,7 +10,8 @@ proc rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: string but expression '{':'}' is of type: set[char] -proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[string] +proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[ + string] first type mismatch at position: 3 unknown named parameter: maxsplits @@ -22,6 +23,5 @@ expression: rsplit("abc:def", {':'}, maxsplits = 1) # bug #8043 - import strutils "abc:def".rsplit({':'}, maxsplits = 1) From fe187719abf5fa87e12e4092f87c270234fad25c Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 8 Oct 2020 08:12:03 +0100 Subject: [PATCH 1220/4254] fix #15516 (#15518) --- compiler/sizealignoffsetimpl.nim | 10 ++++++---- tests/misc/tsizeof.nim | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index baa2c40f9..be35247f7 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -138,12 +138,13 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a accum.offset = szUnknownSize accum.maxAlign = szUnknownSize else: - # the union neds to be aligned first, before the offsets can be assigned + # the union needs to be aligned first, before the offsets can be assigned accum.align(maxChildAlign) let accumRoot = accum # copy, because each branch should start af the same offset for i in 1.. 10 - testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo) + testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516) type WithBitsize {.objectconfig.} = object From 0ac74ddd749ddde26dcc76deebedbd5459a168eb Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 8 Oct 2020 10:28:27 +0200 Subject: [PATCH 1221/4254] fixes a regression --- compiler/lexer.nim | 1 + compiler/renderer.nim | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index ff433928c..0cf00e612 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -62,6 +62,7 @@ type tkComma, tkSemiColon, tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon, tkOpr, tkComment, tkAccent, + # these are fake tokens used by renderer.nim tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr TokTypes* = set[TokType] diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 1de56a296..b897aff5d 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -32,6 +32,7 @@ type TSrcGen* = object indent*: int lineLen*: int + col: int pos*: int # current position for iteration over the buffer idx*: int # current token index for iteration over the buffer tokens*: TRenderTokSeq @@ -119,11 +120,10 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) = g.config = config proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) = - setLen(g.tokens, g.tokens.len + 1) - g.tokens[^1].kind = kind - g.tokens[^1].length = int16(s.len) - g.tokens[^1].sym = sym + g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym) g.buf.add(s) + if kind != tkSpaces: + inc g.col, s.len proc addPendingNL(g: var TSrcGen) = if g.pendingNL >= 0: @@ -133,6 +133,7 @@ proc addPendingNL(g: var TSrcGen) = const newlines = "\n" addTok(g, tkSpaces, newlines & spaces(g.pendingNL)) g.lineLen = g.pendingNL + g.col = g.pendingNL g.pendingNL = - 1 g.pendingWhitespace = -1 elif g.pendingWhitespace >= 0: @@ -141,7 +142,10 @@ proc addPendingNL(g: var TSrcGen) = proc putNL(g: var TSrcGen, indent: int) = if g.pendingNL >= 0: addPendingNL(g) - else: addTok(g, tkSpaces, "\n") + else: + addTok(g, tkSpaces, "\n") + g.col = 0 + g.pendingNL = indent g.lineLen = indent g.pendingWhitespace = -1 @@ -185,14 +189,15 @@ proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) = addTok(g, kind, s, sym) else: g.pendingWhitespace = s.len + inc g.col, s.len inc(g.lineLen, s.len) proc putComment(g: var TSrcGen, s: string) = if s.len == 0: return var i = 0 let hi = s.len - 1 - var isCode = (s.len >= 2) and (s[1] != ' ') - var ind = g.lineLen + let isCode = (s.len >= 2) and (s[1] != ' ') + let ind = g.col var com = "## " while i <= hi: case s[i] @@ -218,7 +223,7 @@ proc putComment(g: var TSrcGen, s: string) = # compute length of the following word: var j = i while j <= hi and s[j] > ' ': inc(j) - if not isCode and (g.lineLen + (j - i) > MaxLineLen): + if not isCode and (g.col + (j - i) > MaxLineLen): put(g, tkComment, com) optNL(g, ind) com = "## " @@ -300,15 +305,18 @@ proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = proc gcom(g: var TSrcGen, n: PNode) = assert(n != nil) if shouldRenderComment(g, n): + var oneSpaceAdded = 0 if (g.pendingNL < 0) and (g.buf.len > 0) and (g.buf[^1] != ' '): put(g, tkSpaces, Space) + oneSpaceAdded = 1 # Before long comments we cannot make sure that a newline is generated, # because this might be wrong. But it is no problem in practice. if (g.pendingNL < 0) and (g.buf.len > 0) and - (g.lineLen < LineCommentColumn): + (g.col < LineCommentColumn): var ml = maxLineLength(n.comment) if ml + LineCommentColumn <= MaxLineLen: - put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen)) + put(g, tkSpaces, spaces(LineCommentColumn - g.col)) + dec g.col, oneSpaceAdded putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n); proc gcoms(g: var TSrcGen) = From 4d91cc79508e27c35ea9b733cb0e778b1d7fdad1 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 8 Oct 2020 10:52:18 +0200 Subject: [PATCH 1222/4254] changelog improvements --- changelog.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 3144c7cf5..7ab7784f0 100644 --- a/changelog.md +++ b/changelog.md @@ -19,10 +19,10 @@ - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is allowed to have fields without corresponding JSON keys. - Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. -- Add `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. +- Added `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. - Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. - `uri` adds Data URI Base64, implements RFC-2397. -- Add [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) +- Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) to the `dom` module for the JavaScript target. - The default hash for `Ordinal` has changed to something more bit-scrambling. `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old @@ -182,10 +182,10 @@ cannot be applied to every use case. The limitations and the (lack of) reliability of `round` are well documented. -- Add `getprotobyname` to `winlean`. Add `getProtoByname` to `nativesockets` which returns a protocol code +- Added `getprotobyname` to `winlean`. Added `getProtoByname` to `nativesockets` which returns a protocol code from the database that matches the protocol `name`. -- Add missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. +- Added missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. - Added `strutils.indentation` and `strutils.dedent` which enable indented string literals: ```nim @@ -197,9 +197,9 @@ """ ``` -- Add `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. +- Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. -- Add `readLines(p: Process)` to `osproc` module for `startProcess` convenience. +- Added `readLines(p: Process)` to `osproc` module for `startProcess` convenience. - Added `heapqueue.toHeapQueue`, which creates a HeapQueue from an openArray. The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. @@ -233,7 +233,6 @@ proc `=destroy`(x: MyObj) = if x.kind and x.y != nil: deallocShared(x.y) - x.y = nil ``` Refactor into: ```nim @@ -248,7 +247,6 @@ proc `=destroy`(x: MySubObj) = if x.val != nil: deallocShared(x.val) - x.val = nil ``` - `getImpl` on enum type symbols now returns field syms instead of idents. This helps with writing typed macros. Old behavior for backwards compatibility can be restored @@ -280,14 +278,14 @@ proc mydiv(a, b): int {.raises: [].} = The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. -- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose +- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes. - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. -- Remove `strutils.isNilOrWhitespace`, was deprecated. -- Remove `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. +- Removed `strutils.isNilOrWhitespace`, was deprecated. +- Removed `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. - Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. -- Remove `dom.releaseEvents` and `dom.captureEvents`, was deprecated. +- Removed `dom.releaseEvents` and `dom.captureEvents`, was deprecated. -- Remove `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. +- Removed `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. - There is a new experimental feature called "strictFuncs" which makes the definition of `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs) @@ -331,7 +329,7 @@ proc mydiv(a, b): int {.raises: [].} = - `--hint:processing` is now supported and means `--hint:processing:on` (likewise with other hints and warnings), which is consistent with all other bool flags. (since 1.3.3). -- `nim doc -r main` and `nim rst2html -r main` now call openDefaultBrowser +- `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`. - new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) was generated; this helps in particular when it's non obvious where it came from either because multiple locations generate the same message, or because the From 1e9d83efb0e59d3a71bf3b077808b96f29c5e529 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 8 Oct 2020 14:17:27 +0200 Subject: [PATCH 1223/4254] fixes #15512 (#15521) --- compiler/injectdestructors.nim | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 28f2c93f1..bec8b49f4 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -593,6 +593,18 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = result.add processScope(c, bodyScope, bodyResult) dec c.inLoop + of nkParForStmt: + inc c.inLoop + result = shallowCopy(n) + let last = n.len-1 + for i in 0.. Date: Thu, 8 Oct 2020 14:21:20 +0200 Subject: [PATCH 1224/4254] changelog.md: Group the new `to` procs (#15522) * changelog.md: Group the new `to` procs [ci skip] This also moves the `critbits.toCritBitTree` entry from the "Language Changes" section to the "Standard library additions and changes" section. * changelog.md: Remove extra space --- changelog.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 7ab7784f0..6b4d4cf2b 100644 --- a/changelog.md +++ b/changelog.md @@ -159,10 +159,6 @@ - Removed `sugar.distinctBase`, deprecated since `0.19`. - Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. -- Added `deques.toDeque`, which creates a deque from an openArray. The usage is - similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, - it was necessary to create an empty deque and add items manually. - - `std/with`, `sugar.dup` now support object field assignment expression: ```nim import std/with @@ -201,13 +197,14 @@ - Added `readLines(p: Process)` to `osproc` module for `startProcess` convenience. -- Added `heapqueue.toHeapQueue`, which creates a HeapQueue from an openArray. - The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. - Previously, it was necessary to create an empty HeapQueue and add items - manually. -- Added `intsets.toIntSet`, which creates an IntSet from an openArray. The usage - is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, - it was necessary to create an empty IntSet and add items manually. +- Added the below `to` procs for collections. The usage is similar to procs such as + `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the + respective empty collection and add items manually. + * `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of + items or an `openArray` of pairs. + * `deques.toDeque`, which creates a `Deque` from an `openArray`. + * `heapqueue.toHeapQueue`, which creates a `HeapQueue` from an `openArray`. + * `intsets.toIntSet`, which creates an `IntSet` from an `openArray`. - Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval at which progress callbacks are called. @@ -305,7 +302,6 @@ proc mydiv(a, b): int {.raises: [].} = - Added a `std/effecttraits` module for introspection of the inferred effects. We hope this enables `async` macros that are precise about the possible exceptions that can be raised. -- Added `critbits.toCritBitTree`, similar to `tables.toTable`, creates a new `CritBitTree` with given arguments. - The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new preferred way of writing these, emphasizing their unsafe nature. From cfba237d142a5ae53d593d69d6e6a560cd21863f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 8 Oct 2020 15:28:23 +0200 Subject: [PATCH 1225/4254] fixes #15510 (#15523) --- compiler/sempass2.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f0d6c6c7a..5eb464bb8 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1065,7 +1065,10 @@ proc track(tracked: PEffects, n: PNode) = for i in 0.. Date: Thu, 8 Oct 2020 17:09:28 +0200 Subject: [PATCH 1226/4254] fixes #15511 (#15524) --- compiler/injectdestructors.nim | 4 +++- compiler/types.nim | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index bec8b49f4..b18bcf34e 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -411,7 +411,9 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = "if possible, rearrange your program's control flow to prevent it") % $n) else: if c.graph.config.selectedGC in {gcArc, gcOrc}: - assert(not containsGarbageCollectedRef(n.typ)) + assert(not containsManagedMemory(n.typ)) + if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}: + localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter") result.add newTree(nkAsgn, tmp, p(n, c, s, normal)) # Since we know somebody will take over the produced copy, there is # no need to destroy it. diff --git a/compiler/types.nim b/compiler/types.nim index b9fc4d4a2..b20bf9c06 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -321,6 +321,13 @@ proc containsGarbageCollectedRef*(typ: PType): bool = # things that are garbage-collected) result = searchTypeFor(typ, isGCRef) +proc isManagedMemory(t: PType): bool = + result = t.kind in GcTypeKinds or + (t.kind == tyProc and t.callConv == ccClosure) + +proc containsManagedMemory*(typ: PType): bool = + result = searchTypeFor(typ, isManagedMemory) + proc isTyRef(t: PType): bool = result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure) From 3eaacac2303ab9fc1aef62208a112fae0ddd9152 Mon Sep 17 00:00:00 2001 From: lihaifeng Date: Thu, 8 Oct 2020 23:17:00 +0800 Subject: [PATCH 1227/4254] Update parsecfg.nim (#15513) * Update parsecfg.nim Returns the specified default value if the specified key value does not exist. * Update lib/pure/parsecfg.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Update lib/pure/parsecfg.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Update lib/pure/parsecfg.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- lib/pure/parsecfg.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index c8e936ef1..15868c219 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -560,15 +560,16 @@ proc writeConfig*(dict: Config, filename: string) = let fileStream = newFileStream(file) dict.writeConfig(fileStream) -proc getSectionValue*(dict: Config, section, key: string): string = - ## Gets the Key value of the specified Section, returns an empty string if the key does not exist. +proc getSectionValue*(dict: Config, section, key: string, defaultVal = ""): string = + ## Gets the key value of the specified Section. + ## Returns the specified default value if the specified key does not exist. if dict.hasKey(section): if dict[section].hasKey(key): result = dict[section][key] else: - result = "" + result = defaultVal else: - result = "" + result = defaultVal proc setSectionKey*(dict: var Config, section, key, value: string) = ## Sets the Key value of the specified Section. From 91ce4515c87c084ade6b2b74ebfc2e19e25b5261 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 9 Oct 2020 07:52:26 +0100 Subject: [PATCH 1228/4254] fix gc:arc in nimscript (#15525) --- compiler/scriptconfig.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 13ab03426..b359c9a48 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -228,11 +228,14 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; # watch out, "newruntime" can be set within NimScript itself and then we need # to remember this: + if conf.selectedGC == gcUnselected: + conf.selectedGC = oldSelectedGC if optOwnedRefs in oldGlobalOptions: conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors} defineSymbol(conf.symbols, "nimv2") - if conf.selectedGC == gcUnselected: - conf.selectedGC = oldSelectedGC + if conf.selectedGC in {gcArc, gcOrc}: + conf.globalOptions.incl {optTinyRtti, optSeqDestructors} + defineSymbol(conf.symbols, "nimv2") # ensure we load 'system.nim' again for the real non-config stuff! resetSystemArtifacts(graph) From 8fb57d74515348d04dcd8c132e5e3787be80b577 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 8 Oct 2020 23:56:09 -0700 Subject: [PATCH 1229/4254] close #13081 (#15529) * close #13081 * fixup --- tests/vm/tvmmisc.nim | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 20adb5b8f..7da1c6743 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -178,3 +178,34 @@ const static: doAssert ctor doAssert ctand + +block: # bug #13081 + type Kind = enum + k0, k1, k2, k3 + + type Foo = object + x0: float + case kind: Kind + of k0: discard + of k1: x1: int + of k2: x2: string + of k3: x3: string + + const j1 = Foo(x0: 1.2, kind: k1, x1: 12) + const j2 = Foo(x0: 1.3, kind: k2, x2: "abc") + const j3 = Foo(x0: 1.3, kind: k3, x3: "abc2") + static: + doAssert $j1 == "(x0: 1.2, kind: k1, x1: 12)" + doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")""" + doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")""" + doAssert $j1 == "(x0: 1.2, kind: k1, x1: 12)" + doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")""" + doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")""" + + when false: + # BUG: this doesn't work yet + # Error: unhandled exception: 'sons' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect] + discard j1.x1 + static: + # ditto + discard j1.x1 From 16e8005031cdc017405ea0c85ddd03c7adf0cef0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 9 Oct 2020 02:28:21 -0700 Subject: [PATCH 1230/4254] fix gitignore for testament cruft (#15530) * fix gitignore for testament cruft * fix rendertree => renderTree --- .gitignore | 2 ++ compiler/ccgexprs.nim | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a4577c0d0..e55f2c5f0 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,8 @@ megatest.nim /outputExpected.txt /outputGotten.txt +/t15148.txt +/tests/vm/tfile_rw.txt /lib/pure/*.js diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 364bcc143..c1469fa60 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1410,7 +1410,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = result = false proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = - #echo rendertree e, " ", e.isDeepConstExpr + #echo renderTree e, " ", e.isDeepConstExpr # inheritance in C++ does not allow struct initialization so # we skip this step here: if not p.module.compileToCpp and optSeqDestructors notin p.config.globalOptions: From d4302162885919d4b10a6d846a6f9d53ec9873eb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 9 Oct 2020 16:18:36 +0200 Subject: [PATCH 1231/4254] fixes #15532 (#15534) --- compiler/semfold.nim | 2 ++ tests/arc/tcaseobj.nim | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index d59dacd9a..e94a15fbe 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -719,6 +719,8 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = result.typ = n.typ of nkBracketExpr: result = foldArrayAccess(m, n, g) of nkDotExpr: result = foldFieldAccess(m, n, g) + of nkCheckedFieldExpr: + result = foldFieldAccess(m, n[0], g) of nkStmtListExpr: var i = 0 while i <= n.len - 2: diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim index 107cf9fc1..a967a509b 100644 --- a/tests/arc/tcaseobj.nim +++ b/tests/arc/tcaseobj.nim @@ -223,3 +223,24 @@ type MyObj = object var a = MyObj(kind: false, x0: 1234) a.kind = true doAssert(a.x1 == "") + +block: + # bug #15532 + type Kind = enum + k0, k1 + + type Foo = object + y: int + case kind: Kind + of k0: x0: int + of k1: x1: int + + const j0 = Foo(y: 1, kind: k0, x0: 2) + const j1 = Foo(y: 1, kind: k1, x1: 2) + + doAssert j0.y == 1 + doAssert j0.kind == k0 + doAssert j1.kind == k1 + + doAssert j1.x1 == 2 + doAssert j0.x0 == 2 From 0a560144cef00bb2d41ce52f218c9927c1b1f6e2 Mon Sep 17 00:00:00 2001 From: genotrance Date: Sat, 10 Oct 2020 00:04:03 -0500 Subject: [PATCH 1232/4254] Bump nimble (#15539) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index bbb37b702..51ebac659 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "26167cd3b7671006c8bd38cbef8708431ddf8687" # master + NimbleStableCommit = "5d9aed105b561d1e5117f958721307d23b94f858" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From 442841037a57d3b0f36ed1c6fd1fffd7110253d2 Mon Sep 17 00:00:00 2001 From: genotrance Date: Sat, 10 Oct 2020 00:04:57 -0500 Subject: [PATCH 1233/4254] Fix #12027 (#15519) --- koch.nim | 8 ++++---- tools/niminst/niminst.nim | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/koch.nim b/koch.nim index 51ebac659..398a14e23 100644 --- a/koch.nim +++ b/koch.nim @@ -78,7 +78,7 @@ Boot options: Commands for core developers: runCI runs continuous integration (CI), eg from travis docs [options] generates the full documentation - csource -d:release builds the C sources for installation + csource -d:danger builds the C sources for installation pdf builds the PDF documentation zip builds the installation zip package xz builds the installation tar.xz package @@ -416,7 +416,7 @@ proc winRelease*() = "web/upload/download/docs-$1.zip" % VersionAsString when true: inFold "winrelease csource": - csource("-d:release") + csource("-d:danger") when sizeof(pointer) == 4: winReleaseArch "32" when sizeof(pointer) == 8: @@ -561,7 +561,7 @@ proc runCI(cmd: string) = proc pushCsources() = if not dirExists("../csources/.git"): quit "[Error] no csources git repository found" - csource("-d:release") + csource("-d:danger") let cwd = getCurrentDir() try: copyDir("build/c_code", "../csources/c_code") @@ -582,7 +582,7 @@ proc pushCsources() = setCurrentDir(cwd) proc testUnixInstall(cmdLineRest: string) = - csource("-d:release " & cmdLineRest) + csource("-d:danger" & cmdLineRest) xz(false, cmdLineRest) let oldCurrentDir = getCurrentDir() try: diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index a0a0d9ad4..47137f8f3 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -605,7 +605,7 @@ proc xzDist(c: var ConfigData; windowsZip=false) = if not windowsZip and not fileExists("build" / buildBatFile): quit("No C sources found in ./build/, please build by running " & - "./koch csource -d:release.") + "./koch csource -d:danger.") if not windowsZip: processFile(proj / buildBatFile, "build" / buildBatFile) From 8a5f5504919acb4ccbebe3025b22d11ca67ee82e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 9 Oct 2020 22:05:27 -0700 Subject: [PATCH 1234/4254] followup after #15529 and #15534 (#15536) --- tests/vm/tvmmisc.nim | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 7da1c6743..7ac75c7c5 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -1,7 +1,6 @@ # bug #4462 import macros import os -import strutils block: proc foo(t: typedesc) {.compileTime.} = @@ -202,10 +201,6 @@ block: # bug #13081 doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")""" doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")""" - when false: - # BUG: this doesn't work yet - # Error: unhandled exception: 'sons' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect] - discard j1.x1 - static: - # ditto - discard j1.x1 + doAssert j1.x1 == 12 + static: + doAssert j1.x1 == 12 From c7ccbfac39008903826d8c56d9eaa6572c9acea7 Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Sat, 10 Oct 2020 07:06:13 +0200 Subject: [PATCH 1235/4254] close socket in getPrimaryIPAddr (#15538) [backport] --- lib/pure/net.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f30b893a7..3f768470d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -2006,4 +2006,5 @@ proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress = else: newSocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP) socket.connect($dest, 80.Port) - socket.getLocalAddr()[0].parseIpAddress() + result = socket.getLocalAddr()[0].parseIpAddress() + socket.close() From 992952d86844805231bcc8a92063c122f721658d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 10 Oct 2020 17:46:22 +0200 Subject: [PATCH 1236/4254] nimpretty: do not produce 'line too long' messages (#15541) --- compiler/lexer.nim | 5 +++-- nimpretty/tester.nim | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0cf00e612..9b1dc642d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -758,8 +758,9 @@ proc handleCRLF(L: var Lexer, pos: int): int = template registerLine = let col = L.getColNumber(pos) - if col > MaxLineLength: - lexMessagePos(L, hintLineTooLong, pos) + when not defined(nimpretty): + if col > MaxLineLength: + lexMessagePos(L, hintLineTooLong, pos) case L.buf[pos] of CR: diff --git a/nimpretty/tester.nim b/nimpretty/tester.nim index 6124eb66a..d646b25ce 100644 --- a/nimpretty/tester.nim +++ b/nimpretty/tester.nim @@ -60,7 +60,4 @@ for t in allFiles: testTogether(allFiles) removeDir(outputdir) - - - if failures > 0: quit($failures & " failures occurred.") From 3eac9b2344bda64b1f74e0475ce8a3b5afa63271 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 11 Oct 2020 11:43:01 -0700 Subject: [PATCH 1237/4254] os: add overload copyFile*(source, dest: string, isDir = false) (#15537) * os: add overload copyFile*(source, dest: string, isDir = false) * renamed to copyFileToDir --- changelog.md | 1 + lib/pure/os.nim | 8 +++++++- tests/stdlib/tos.nim | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 6b4d4cf2b..07533c2d2 100644 --- a/changelog.md +++ b/changelog.md @@ -209,6 +209,7 @@ - Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval at which progress callbacks are called. +- Added `os.copyFileToDir` ## Language changes diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 5efbde268..2601f9d47 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1682,7 +1682,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} = - ## Copies a file from `source` to `dest`. + ## Copies a file from `source` to `dest`, where `dest.parentDir` must exist. ## ## If this fails, `OSError` is raised. ## @@ -1738,6 +1738,12 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", flushFile(d) close(d) +proc copyFileToDir*(source, dir: string) {.noWeirdTarget, since: (1,3,7).} = + ## Copies a file `source` into directory `dir`, which must exist. + if dir.len == 0: # treating "" as "." is error prone + raise newException(ValueError, "dest is empty") + copyFile(source, dir / source.lastPathPart) + when not declared(ENOENT) and not defined(Windows): when NoFakeVars: when not defined(haiku): diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 814ff103d..019303ebf 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -36,6 +36,25 @@ block fileOperations: createDir(dname) doAssert dirExists(dname) + block: # copyFile, copyFileToDir + doAssertRaises(OSError): copyFile(dname/"nonexistant.txt", dname/"nonexistant.txt") + let fname = "D20201009T112235" + let fname2 = "D20201009T112235.2" + writeFile(dname/fname, "foo") + let sub = "sub" + doAssertRaises(OSError): copyFile(dname/fname, dname/sub/fname2) + doAssertRaises(OSError): copyFileToDir(dname/fname, dname/sub) + doAssertRaises(ValueError): copyFileToDir(dname/fname, "") + copyFile(dname/fname, dname/fname2) + doAssert fileExists(dname/fname2) + createDir(dname/sub) + copyFileToDir(dname/fname, dname/sub) + doAssert fileExists(dname/sub/fname) + removeDir(dname/sub) + doAssert not dirExists(dname/sub) + removeFile(dname/fname) + removeFile(dname/fname2) + # Test creating files and dirs for dir in dirs: createDir(dname/dir) From c2c7f6025922034073418e608a62f8f4d5a5b381 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 12 Oct 2020 02:43:44 +0800 Subject: [PATCH 1238/4254] docs minor (#15550) --- lib/pure/collections/deques.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 54756707d..c3eeb3156 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -13,7 +13,7 @@ ## None of the procs that get an individual value from the deque can be used ## on an empty deque. ## If compiled with `boundChecks` option, those procs will raise an `IndexDefect` -## on such access. This should not be relied upon, as `-d:release` will +## on such access. This should not be relied upon, as `-d:danger` or `--checks:off` will ## disable those checks and may return garbage or crash the program. ## ## As such, a check to see if the deque is empty is needed before any @@ -114,7 +114,7 @@ template emptyCheck(deq) = template xBoundsCheck(deq, i) = # Bounds check for the array like accesses. - when compileOption("boundChecks"): # d:release should disable this. + when compileOption("boundChecks"): # `-d:danger` or `--checks:off` should disable this. if unlikely(i >= deq.count): # x < deq.low is taken care by the Natural parameter raise newException(IndexDefect, "Out of bounds: " & $i & " > " & $(deq.count - 1)) From 3492178494484e0c0c1d8eec83aadc5b2ad06ede Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 11 Oct 2020 12:11:47 +0200 Subject: [PATCH 1239/4254] refactoring: removed cmdlinehelper.mainCommand callback --- compiler/cmdlinehelper.nim | 23 ++++++++++------------- compiler/nim.nim | 9 +++++---- drnim/drnim.nim | 11 +++++------ nimsuggest/nimsuggest.nim | 14 ++++++++------ tools/nimfind.nim | 7 ++++--- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index 4777af8df..a6b56b97e 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -34,7 +34,6 @@ type suggestMode*: bool supportsStdinFile*: bool processCmdLine*: proc(pass: TCmdLinePass, cmd: string; config: ConfigRef) - mainCommand*: proc(graph: ModuleGraph) proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) = condsyms.initDefines(conf.symbols) @@ -56,21 +55,21 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = else: conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir()) -proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool = +proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef; + graph: ModuleGraph): bool = if self.suggestMode: conf.command = "nimsuggest" loadConfigs(DefaultConfig, cache, conf) # load all config files - block: + if not self.suggestMode: let scriptFile = conf.projectFull.changeFileExt("nims") - if not self.suggestMode: - # 'nim foo.nims' means to just run the NimScript file and do nothing more: - if fileExists(scriptFile) and scriptFile == conf.projectFull: - if conf.command == "": - conf.command = "e" - return false - elif conf.command.normalize == "e": - return false + # 'nim foo.nims' means to just run the NimScript file and do nothing more: + if fileExists(scriptFile) and scriptFile == conf.projectFull: + if conf.command == "": + conf.command = "e" + return false + elif conf.command.normalize == "e": + return false # now process command line arguments again, because some options in the # command line can overwrite the config file's settings @@ -79,7 +78,5 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi if conf.command == "": rawMessage(conf, errGenerated, "command missing") - let graph = newModuleGraph(cache, conf) graph.suggestMode = self.suggestMode - self.mainCommand(graph) return true diff --git a/compiler/nim.nim b/compiler/nim.nim index 2b0d78dd4..15aeccb33 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -22,7 +22,7 @@ import commands, options, msgs, extccomp, strutils, os, main, parseopt, idents, lineinfos, cmdlinehelper, - pathutils + pathutils, modulegraphs from std/browsers import openDefaultBrowser from nodejs import findNodeJs @@ -70,8 +70,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let self = NimProg( supportsStdinFile: true, - processCmdLine: processCmdLine, - mainCommand: mainCommand + processCmdLine: processCmdLine ) self.initDefinesProg(conf, "nim_compiler") if paramCount() == 0: @@ -79,7 +78,9 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = return self.processCmdLineAndProjectPath(conf) - if not self.loadConfigsAndRunMainCommand(cache, conf): return + var graph = newModuleGraph(cache, conf) + if not self.loadConfigsAndRunMainCommand(cache, conf, graph): return + mainCommand(graph) if conf.hasHint(hintGCStats): echo(GC_getStatistics()) #echo(GC_getStatistics()) if conf.errorCounter != 0: return diff --git a/drnim/drnim.nim b/drnim/drnim.nim index e17667ec7..b4761a398 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1209,15 +1209,13 @@ proc mainCommand(graph: ModuleGraph) = else: "Debug" let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName - var output = $conf.absOutFile - if optListFullPaths notin conf.globalOptions: output = output.AbsoluteFile.extractFilename rawMessage(conf, hintSuccessX, [ "loc", loc, "sec", sec, "mem", mem, "build", build, "project", project, - "output", output, + "output", "" ]) proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = @@ -1262,8 +1260,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = incl conf.options, optStaticBoundsCheck let self = NimProg( supportsStdinFile: true, - processCmdLine: processCmdLine, - mainCommand: mainCommand + processCmdLine: processCmdLine ) self.initDefinesProg(conf, "drnim") if paramCount() == 0: @@ -1271,7 +1268,9 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = return self.processCmdLineAndProjectPath(conf) - if not self.loadConfigsAndRunMainCommand(cache, conf): return + var graph = newModuleGraph(cache, conf) + if not self.loadConfigsAndRunMainCommand(cache, conf, graph): return + mainCommand(graph) if conf.hasHint(hintGCStats): echo(GC_getStatistics()) when compileOption("gc", "v2") or compileOption("gc", "refc"): diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 9a0962df3..afc692241 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -619,8 +619,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let self = NimProg( suggestMode: true, - processCmdLine: processCmdLine, - mainCommand: mainCommand + processCmdLine: processCmdLine ) self.initDefinesProg(conf, "nimsuggest") @@ -644,7 +643,9 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = #msgs.writelnHook = proc (line: string) = log(line) myLog("START " & conf.projectFull.string) - discard self.loadConfigsAndRunMainCommand(cache, conf) + var graph = newModuleGraph(cache, conf) + if self.loadConfigsAndRunMainCommand(cache, conf, graph): + mainCommand(graph) when isMainModule: handleCmdLine(newIdentCache(), newConfigRef()) @@ -698,8 +699,7 @@ else: conf = newConfigRef() self = NimProg( suggestMode: true, - processCmdLine: mockCmdLine, - mainCommand: mockCommand + processCmdLine: mockCmdLine ) self.initDefinesProg(conf, "nimsuggest") @@ -722,7 +722,9 @@ else: #msgs.writelnHook = proc (line: string) = log(line) myLog("START " & conf.projectFull.string) - discard self.loadConfigsAndRunMainCommand(cache, conf) + var graph = newModuleGraph(cache, conf) + if self.loadConfigsAndRunMainCommand(cache, conf, graph): + mockCommand(graph) if gLogging: for it in conf.searchPaths: log(it.string) diff --git a/tools/nimfind.nim b/tools/nimfind.nim index 4ad5fbb4f..f13e86aaa 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -208,8 +208,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let self = NimProg( suggestMode: true, - processCmdLine: processCmdLine, - mainCommand: mainCommand + processCmdLine: processCmdLine ) self.initDefinesProg(conf, "nimfind") @@ -228,6 +227,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = if not dirExists(conf.prefixDir / RelativeDir"lib"): conf.prefixDir = AbsoluteDir"" - discard self.loadConfigsAndRunMainCommand(cache, conf) + var graph = newModuleGraph(cache, conf) + if self.loadConfigsAndRunMainCommand(cache, conf, graph): + mainCommand(graph) handleCmdLine(newIdentCache(), newConfigRef()) From d66e274e1ac8e86266151ad0c48f7705b3bd1582 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 11 Oct 2020 18:03:40 +0200 Subject: [PATCH 1240/4254] refactoring: moved setOutFile to where it belongs --- compiler/main.nim | 14 -------------- compiler/options.nim | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index ab074aa1f..d85aa43dc 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -66,20 +66,6 @@ when not defined(leanCompiler): compileProject(graph) finishDoc2Pass(graph.config.projectName) -proc setOutFile(conf: ConfigRef) = - proc libNameTmpl(conf: ConfigRef): string {.inline.} = - result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" - - if conf.outFile.isEmpty: - let base = conf.projectName - let targetName = if optGenDynLib in conf.globalOptions: - platform.OS[conf.target.targetOS].dllFrmt % base - elif optGenStaticLib in conf.globalOptions: - libNameTmpl(conf) % base - else: - base & platform.OS[conf.target.targetOS].exeExt - conf.outFile = RelativeFile targetName - proc commandCompileToC(graph: ModuleGraph) = let conf = graph.config setOutFile(conf) diff --git a/compiler/options.nim b/compiler/options.nim index 6054eb3a5..2f796afe6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -884,3 +884,18 @@ proc floatInt64Align*(conf: ConfigRef): int16 = # to 4bytes (except with -malign-double) return 4 return 8 + +proc setOutFile*(conf: ConfigRef) = + proc libNameTmpl(conf: ConfigRef): string {.inline.} = + result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" + + if conf.outFile.isEmpty: + let base = conf.projectName + let targetName = + if optGenDynLib in conf.globalOptions: + platform.OS[conf.target.targetOS].dllFrmt % base + elif optGenStaticLib in conf.globalOptions: + libNameTmpl(conf) % base + else: + base & platform.OS[conf.target.targetOS].exeExt + conf.outFile = RelativeFile targetName From 9668a1106de6ccd86b377d2a2c566d8efb11479b Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 12 Oct 2020 10:12:32 +0100 Subject: [PATCH 1241/4254] Fix 15543 (#15544) * fix #15543 * fix spacing * fix test * simplify test for freebsd platform --- compiler/ccgtypes.nim | 2 +- tests/arc/t14472.nim | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 0df7c8d2a..6c82a140b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1487,7 +1487,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = elif origType.attachedOps[attachedDeepCopy] != nil: genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result) - if optTinyRtti in m.config.globalOptions and t.kind == tyObject: + if optTinyRtti in m.config.globalOptions and t.kind == tyObject and sfImportc notin t.sym.flags: let v2info = genTypeInfoV2(m, origType, info) addf(m.s[cfsTypeInit3], "$1->typeInfoV1 = (void*)&$2; $2.typeInfoV2 = (void*)$1;$n", [ v2info, result]) diff --git a/tests/arc/t14472.nim b/tests/arc/t14472.nim index 47ed77f4c..4ef661161 100644 --- a/tests/arc/t14472.nim +++ b/tests/arc/t14472.nim @@ -1,6 +1,6 @@ discard """ valgrind: true - cmd: "nim c --gc:arc -d:useMalloc $file" + cmd: "nim cpp --gc:arc -d:useMalloc --deepcopy:on $file" """ type @@ -21,3 +21,23 @@ proc bork() : ImportedScene = add(result.meshes, Mesh(material: mats[0])) var s = bork() + + +#------------------------------------------------------------------------ +# issue #15543 + +import tables + +type + cdbl {.importc: "double".} = object + + MyObject = ref object of RootObj + y: Table[string, cdbl] + + +proc test = + var x = new(MyObject) + +test() + + From 30b966bdf7ea898f5cda9bcd3d9470d17eba5634 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 12 Oct 2020 12:04:40 -0700 Subject: [PATCH 1242/4254] unbreak CI: fix logic for skipping ci (#15556) --- .github/workflows/ci_docs.yml | 2 +- .github/workflows/ci_packages.yml | 2 +- .github/workflows/ci_ssl.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 6b21475f6..64314cce4 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -29,7 +29,7 @@ on: jobs: build: if: | - !contains(format('{0} {1} {2}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') + !contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index a59bcee9d..0d2f89aa6 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: build: if: | - !contains(format('{0} {1} {2}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') + !contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: diff --git a/.github/workflows/ci_ssl.yml b/.github/workflows/ci_ssl.yml index 070e4aa1e..6a024eca0 100644 --- a/.github/workflows/ci_ssl.yml +++ b/.github/workflows/ci_ssl.yml @@ -13,7 +13,7 @@ on: jobs: build: if: | - !contains(format('{0} {1} {2}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') + !contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: From 1f51a3399808218f99e820fd43f5bd9d2204ce61 Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Mon, 12 Oct 2020 22:02:17 +0200 Subject: [PATCH 1243/4254] close socket in getPrimaryIPAddr even if exception occurs (#15558) --- lib/pure/net.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 3f768470d..3ef41aa3c 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -2005,6 +2005,8 @@ proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) else: newSocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP) - socket.connect($dest, 80.Port) - result = socket.getLocalAddr()[0].parseIpAddress() - socket.close() + try: + socket.connect($dest, 80.Port) + result = socket.getLocalAddr()[0].parseIpAddress() + finally: + socket.close() From f1d81dc6e6673a74710f15b93c0938c22b90c4e1 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Mon, 12 Oct 2020 23:33:53 -0500 Subject: [PATCH 1244/4254] Fix doc for CountTable (#15561) [backport] --- lib/pure/collections/tables.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index c5a7fca56..85440bd2b 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -2599,7 +2599,7 @@ proc `[]`*[A](t: CountTableRef[A], key: A): int = ## See also: ## * `getOrDefault<#getOrDefault,CountTableRef[A],A,int>`_ to return ## a custom value if the key doesn't exist - ## * `mget proc<#mget,CountTableRef[A],A>`_ + ## * `inc proc<#inc,CountTableRef[A],A>`_ to inc even if missing ## * `[]= proc<#[]%3D,CountTableRef[A],A,int>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,CountTableRef[A],A>`_ for checking if a key From 0134e34e035a139677413acb20e42b4f7f490021 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 12 Oct 2020 23:24:30 -0700 Subject: [PATCH 1245/4254] dup docs: add an example with `addQuoted` (#15548) * dup docs: add addQuoted example * fixup --- lib/pure/sugar.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index be5e1f326..92e9f662a 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -244,6 +244,11 @@ since (1, 1): var c = "xyz" # An underscore (_) can be used to denote the place of the argument you're passing: + doAssert "".dup(addQuoted(_, "foo")) == "\"foo\"" + # but `_` is optional here since the substitution is in 1st position: + doAssert "".dup(addQuoted("foo")) == "\"foo\"" + + # chaining: # b = "xyz" var d = dup c: makePalindrome # xyzyx From d1af9587b889bc1c9b080a48b9858436d2482599 Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 13 Oct 2020 11:39:32 -0500 Subject: [PATCH 1246/4254] terminal: fix fgColor/bgColor commands [backport] (#15554) Since #8296, fgSetColor is no longer a global. These commands were probably left out from the change as an oversight, so some tests have been added to make sure this won't happen again. --- lib/pure/terminal.nim | 7 +++---- tests/stdlib/tterminal.nim | 8 ++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 tests/stdlib/tterminal.nim diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 968d6bd9a..ac6720771 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -689,10 +689,9 @@ template styledEchoProcessArg(f: File, color: Color) = template styledEchoProcessArg(f: File, cmd: TerminalCmd) = when cmd == resetStyle: resetAttributes(f) - when cmd == fgColor: - fgSetColor = true - when cmd == bgColor: - fgSetColor = false + elif cmd in {fgColor, bgColor}: + let term = getTerminal() + term.fgSetColor = cmd == fgColor macro styledWrite*(f: File, m: varargs[typed]): untyped = ## Similar to ``write``, but treating terminal style arguments specially. diff --git a/tests/stdlib/tterminal.nim b/tests/stdlib/tterminal.nim new file mode 100644 index 000000000..364c8d82e --- /dev/null +++ b/tests/stdlib/tterminal.nim @@ -0,0 +1,8 @@ +discard """ + action: compile +""" + +import terminal, colors + +styledEcho fgColor, colRed, "Test" +styledEcho bgColor, colBlue, "Test" From 0c0f86b2c54d2ef367e5a401c8744b8f5295aaa5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Oct 2020 00:25:28 -0700 Subject: [PATCH 1247/4254] reference fusion docs (#15562) --- config/nimdoc.cfg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index a6a402bab..67d619ea1 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -132,7 +132,10 @@ doc.body_toc_group = """ Index
  • - Compiler docs + compiler docs +
  • +
  • + fusion docs
  • From fc90eb9f27082e36d2ccf3c36757f08bbd5b4ea5 Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 14 Oct 2020 09:26:44 +0200 Subject: [PATCH 1248/4254] change case in nimdoc [ci skip] --- config/nimdoc.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 67d619ea1..13beb5af1 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -132,10 +132,10 @@ doc.body_toc_group = """ Index
  • - compiler docs + Compiler docs
  • - fusion docs + Fusion docs
  • From c664fb284349e2d03148890dfec169b844694eae Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 14 Oct 2020 09:55:47 +0200 Subject: [PATCH 1249/4254] sigmatch: hotfix [backport] (#15565) --- compiler/sigmatch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 1441203e8..687634e93 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1107,7 +1107,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let x = typeRel(c, f, branch, flags + {trDontBind}) if x == isNone: return isNone if x < result: result = x - return + return result of tyAnd: # XXX: deal with the current dual meaning of tyGenericParam @@ -1441,7 +1441,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let ff = rootf[i] let aa = roota[i] let res = typeRel(c, ff, aa, nextFlags) - if res != isEqual: result = isGeneric + if res != isNone and res != isEqual: result = isGeneric if res notin {isEqual, isGeneric}: if trNoCovariance notin flags and ff.kind == aa.kind: let paramFlags = rootf.base[i-1].flags From 12c8ef5949aca6be288a304292c89c350db44f29 Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Wed, 14 Oct 2020 05:20:59 -0400 Subject: [PATCH 1250/4254] Update the list of GC options when raising an error (closes #15547) (#15553) --- compiler/commands.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 19048065f..3c6cc5919 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -229,7 +229,7 @@ proc processCompile(conf: ConfigRef; filename: string) = extccomp.addExternalFileToCompile(conf, found) const - errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found" + errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found" errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found" errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found" errInvalidExceptionSystem = "'goto', 'setjump', 'cpp' or 'quirky' expected, but '$1' found" From 09cad44be9153211317f3f4a998f054192ffe9fc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Oct 2020 03:04:14 -0700 Subject: [PATCH 1251/4254] ci docs: add config/nimdoc.cfg to paths (#15566) --- .github/workflows/ci_docs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 64314cce4..718dcd7e3 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -4,6 +4,7 @@ on: paths: - 'compiler/docgen.nim' - 'compiler/renderverbatim.nim' + - 'config/nimdoc.cfg' - 'doc/**.rst' - 'doc/nimdoc.css' - 'lib/**.nim' @@ -17,6 +18,7 @@ on: paths: - 'compiler/docgen.nim' - 'compiler/renderverbatim.nim' + - 'config/nimdoc.cfg' - 'doc/**.rst' - 'doc/nimdoc.css' - 'lib/**.nim' From 89781124579fdf7fe884aca093ed9348195a57af Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 14 Oct 2020 13:58:36 +0200 Subject: [PATCH 1252/4254] fixes a C code generator regression, no need to backport, only the 1.4 line is affected (#15569) --- compiler/ccgcalls.nim | 2 +- tests/ccgbugs/t2procs.nim | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/ccgbugs/t2procs.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 6c5b721c7..242e9f5cf 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -249,7 +249,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = - if needsTmp: + if needsTmp and a.lode.typ != nil: var tmp: TLoc getTemp(p, a.lode.typ, tmp, needsInit=false) genAssignment(p, tmp, a, {}) diff --git a/tests/ccgbugs/t2procs.nim b/tests/ccgbugs/t2procs.nim new file mode 100644 index 000000000..d8b7a2815 --- /dev/null +++ b/tests/ccgbugs/t2procs.nim @@ -0,0 +1,18 @@ +discard """ + output: '''before +1 +before +2''' +""" + +proc fn[T1, T2](a: T1, b: T2) = + a(1) + b(2) + +fn( (proc(x: int) = + echo "before" # example block, can span multiple lines + echo x), + (proc (y: int) = + echo "before" + echo y) +) From 977bccdbff9db889bebfa963d1292c4d433f6779 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 14 Oct 2020 16:07:25 +0200 Subject: [PATCH 1253/4254] Make useVersion:1.0 disable the proc arg sym change (#15570) * Make useVersion:1.0 disable the proc arg sym change * Also do this for useVersion:1.2 --- changelog.md | 5 ++++- compiler/commands.nim | 6 ++++++ compiler/options.nim | 1 + compiler/semtypes.nim | 3 ++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 07533c2d2..694d9635f 100644 --- a/changelog.md +++ b/changelog.md @@ -248,7 +248,10 @@ ``` - `getImpl` on enum type symbols now returns field syms instead of idents. This helps with writing typed macros. Old behavior for backwards compatibility can be restored - with command line switch `--useVersion:1.0`. + with `--useVersion:1.0`. +- The typed AST for proc headers will now have the arguments be syms instead of idents. + This helps with writing typed macros. Old behaviour for backwards compatibility can + be restored with `--useVersion:1.0`. - ``let`` statements can now be used without a value if declared with ``importc``/``importcpp``/``importjs``/``importobjc``. - The keyword `from` is now usable as an operator. diff --git a/compiler/commands.nim b/compiler/commands.nim index 3c6cc5919..b9199c1b0 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -883,6 +883,12 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; undefSymbol(conf.symbols, "nimDoesntTrackDefects") ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect} conf.globalOptions.incl optNimV1Emulation + of "1.2": + defineSymbol(conf.symbols, "NimMajor", "1") + defineSymbol(conf.symbols, "NimMinor", "2") + # always be compatible with 1.2.100: + defineSymbol(conf.symbols, "NimPatch", "100") + conf.globalOptions.incl optNimV12Emulation else: localError(conf, info, "unknown Nim version; currently supported values are: {1.0}") of "benchmarkvm": diff --git a/compiler/options.nim b/compiler/options.nim index 2f796afe6..3be7c5099 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -94,6 +94,7 @@ type # please make sure we have under 32 options optProduceAsm # produce assembler code optPanics # turn panics (sysFatal) into a process termination optNimV1Emulation # emulate Nim v1.0 + optNimV12Emulation # emulate Nim v1.2 optSourcemap optProfileVM # enable VM profiler optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types. diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9bb7673fa..8ef393839 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1288,7 +1288,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, addParamOrResult(c, arg, kind) styleCheckDef(c.config, a[j].info, arg) onDef(a[j].info, arg) - a[j] = newSymNode(arg) + if {optNimV1Emulation, optNimV12Emulation} * c.config.globalOptions == {}: + a[j] = newSymNode(arg) var r: PType if n[0].kind != nkEmpty: From c2ba4ef9799a097fec8b2bb1b033448860d60f1b Mon Sep 17 00:00:00 2001 From: alaviss Date: Wed, 14 Oct 2020 10:08:56 -0500 Subject: [PATCH 1254/4254] suggest: try to find the implementation of a symbol when def is used (#15555) * suggest: try to find the implementation of a symbol when def is used * suggest: return all declarations of the symbol on `def` --- changelog.md | 4 ++++ compiler/semstmts.nim | 1 + compiler/suggest.nim | 22 +++++++++++++++------- nimsuggest/tests/tdef_forward.nim | 13 +++++++++++++ 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 nimsuggest/tests/tdef_forward.nim diff --git a/changelog.md b/changelog.md index 694d9635f..2c8f9b5e2 100644 --- a/changelog.md +++ b/changelog.md @@ -361,3 +361,7 @@ proc mydiv(a, b): int {.raises: [].} = ## Tool changes + +- `nimsuggest` will now return both the forward declaration and the + implementation location upon a `def` query. Previously the behavior was + just to return the forward declaration. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 44a31c2ea..27cd9019f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1943,6 +1943,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not comesFromShadowScope: excl(proto.flags, sfForward) incl(proto.flags, sfWasForwarded) + suggestSym(c.config, s.info, proto, c.graph.usageSym) closeScope(c) # close scope with wrong parameter symbols openScope(c) # open scope for old (correct) parameter symbols if proto.ast[genericParamsPos].kind != nkEmpty: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 4943603ce..be337af12 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -119,7 +119,8 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; - inTypeContext: bool; scope: int): Suggest = + inTypeContext: bool; scope: int; + useSuppliedInfo = false): Suggest = new(result) result.section = section result.quality = quality @@ -156,7 +157,11 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info result.forth = "" when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): result.doc = s.extractDocComment - let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info + let infox = + if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}: + info + else: + s.info result.filePath = toFullPath(conf, infox) result.line = toLinenumber(infox) result.column = toColumn(infox) @@ -463,11 +468,14 @@ when defined(nimsuggest): let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse suggestResult(conf, symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) -proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym) = +proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = if s.isNil: return - if isTracked(info, conf.m.trackPos, s.name.s.len): - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) - suggestQuit() + if isTracked(info, conf.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags): + suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym)) + if sfForward notin s.flags: + suggestQuit() + else: + usageSym = s proc ensureIdx[T](x: var T, y: int) = if x.len <= y: x.setLen(y+1) @@ -487,7 +495,7 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; if conf.ideCmd == ideUse: findUsages(conf, info, s, usageSym) elif conf.ideCmd == ideDef: - findDefinition(conf, info, s) + findDefinition(conf, info, s, usageSym) elif conf.ideCmd == ideDus and s != nil: if isTracked(info, conf.m.trackPos, s.name.s.len): suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) diff --git a/nimsuggest/tests/tdef_forward.nim b/nimsuggest/tests/tdef_forward.nim new file mode 100644 index 000000000..9bdd8b21d --- /dev/null +++ b/nimsuggest/tests/tdef_forward.nim @@ -0,0 +1,13 @@ +discard """ +$nimsuggest --tester $file +>def $1 +def;;skProc;;tdef_forward.hello;;proc (): string;;$file;;8;;5;;"";;100 +def;;skProc;;tdef_forward.hello;;proc (): string;;$file;;12;;5;;"";;100 +""" + +proc hello(): string + +hel#[!]#lo() + +proc hello(): string = + "Hello" From 644eb4dd5439b574f03b0d65db6d2b31b246a4be Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 14 Oct 2020 22:26:21 +0200 Subject: [PATCH 1255/4254] ORC: critical bugfix for the cycle analyser, introduce -d:nimStressOrc for easier stress testing (#15572) --- compiler/liftdestructors.nim | 2 +- lib/system/arc.nim | 6 +++++ lib/system/orc.nim | 45 +++++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index dd5332b38..2735fb417 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -518,7 +518,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) - let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(t) + let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType) var cond: PNode if isCyclic: diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 973b951d4..3e24c2506 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -161,6 +161,12 @@ proc nimRawDispose(p: pointer) {.compilerRtl.} = if head(p).rc >= rcIncrement: cstderr.rawWrite "[FATAL] dangling references exist\n" quit 1 + + when defined(gcOrc) and defined(nimArcDebug): + if (head(p).rc and 0b100) != 0: + cstderr.rawWrite "[FATAL] cycle root freed\n" + quit 1 + when defined(nimArcDebug): # we do NOT really free the memory here in order to reliably detect use-after-frees if freedCells.data == nil: init(freedCells) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index cf8d6379a..1d856696c 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -297,8 +297,10 @@ proc collectCyclesBacon(j: var GcEnv) = const defaultThreshold = when defined(nimAdaptiveOrc): 128 else: 10_000 -var - rootsThreshold = defaultThreshold +when defined(nimStressOrc): + const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8 +else: + var rootsThreshold = defaultThreshold proc collectCycles() = ## Collect cycles. @@ -320,28 +322,31 @@ proc collectCycles() = deinit j.traceStack deinit roots - # compute the threshold based on the previous history - # of the cycle collector's effectiveness: - # we're effective when we collected 50% or more of the nodes - # we touched. If we're effective, we can reset the threshold: - if j.freed * 2 >= j.touched: - when defined(nimAdaptiveOrc): - rootsThreshold = max(rootsThreshold div 2, 16) - else: - rootsThreshold = defaultThreshold - #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) - elif rootsThreshold < high(int) div 4: - rootsThreshold = rootsThreshold * 3 div 2 + + when not defined(nimStressOrc): + # compute the threshold based on the previous history + # of the cycle collector's effectiveness: + # we're effective when we collected 50% or more of the nodes + # we touched. If we're effective, we can reset the threshold: + if j.freed * 2 >= j.touched: + when defined(nimAdaptiveOrc): + rootsThreshold = max(rootsThreshold div 2, 16) + else: + rootsThreshold = defaultThreshold + #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) + elif rootsThreshold < high(int) div 4: + rootsThreshold = rootsThreshold * 3 div 2 when logOrc: cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld\n", j.freed, rootsThreshold, j.touched, getOccupiedMem()) proc registerCycle(s: Cell; desc: PNimTypeV2) = + s.rootIdx = roots.len + if roots.d == nil: init(roots) + add(roots, s, desc) + if roots.len >= rootsThreshold: collectCycles() - if roots.d == nil: init(roots) - s.rootIdx = roots.len - add(roots, s, desc) #writeCell("[added root]", s) proc GC_fullCollect* = @@ -350,10 +355,12 @@ proc GC_fullCollect* = collectCycles() proc GC_enableMarkAndSweep*() = - rootsThreshold = defaultThreshold + when not defined(nimStressOrc): + rootsThreshold = defaultThreshold proc GC_disableMarkAndSweep*() = - rootsThreshold = high(int) + when not defined(nimStressOrc): + rootsThreshold = high(int) proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = if isDestroyAction: From a4c28394beab558a160671ab216e736b36276a94 Mon Sep 17 00:00:00 2001 From: genotrance Date: Wed, 14 Oct 2020 15:26:44 -0500 Subject: [PATCH 1256/4254] Bump nimble (#15573) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 398a14e23..7be35fed7 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "5d9aed105b561d1e5117f958721307d23b94f858" # master + NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" when not defined(windows): From 1bbc20010e3c8efc0de2c73a8d0d3d844de97049 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 15 Oct 2020 09:42:43 +0200 Subject: [PATCH 1257/4254] harden the ORC asyncleak3 test case (#15580) * harden the ORC asyncleak3 test case * add another ORC stress test --- tests/arc/tasyncleak3.nim | 3 +- tests/arc/thavlak_orc_stress.nim | 414 +++++++++++++++++++++++++++++++ 2 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 tests/arc/thavlak_orc_stress.nim diff --git a/tests/arc/tasyncleak3.nim b/tests/arc/tasyncleak3.nim index c1510895a..21e963b7f 100644 --- a/tests/arc/tasyncleak3.nim +++ b/tests/arc/tasyncleak3.nim @@ -1,6 +1,7 @@ discard """ - cmd: "nim c --gc:orc $file" + cmd: "nim c --gc:orc -d:useMalloc $file" output: "true" + valgrind: "true" """ import strutils diff --git a/tests/arc/thavlak_orc_stress.nim b/tests/arc/thavlak_orc_stress.nim new file mode 100644 index 000000000..3c61f10ef --- /dev/null +++ b/tests/arc/thavlak_orc_stress.nim @@ -0,0 +1,414 @@ +discard """ + cmd: "nim c --gc:orc -d:useMalloc -d:nimStressOrc $file" + valgrind: "true" + output: "done" +""" + +import tables +import sets +import net + +type + BasicBlock = object + inEdges: seq[ref BasicBlock] + outEdges: seq[ref BasicBlock] + name: int + +proc newBasicBlock(name: int): ref BasicBlock = + new(result) + result.inEdges = newSeq[ref BasicBlock]() + result.outEdges = newSeq[ref BasicBlock]() + result.name = name + +proc hash(x: ref BasicBlock): int {.inline.} = + result = x.name + +type + BasicBlockEdge = object + fr: ref BasicBlock + to: ref BasicBlock + + Cfg = object + basicBlockMap: Table[int, ref BasicBlock] + edgeList: seq[BasicBlockEdge] + startNode: ref BasicBlock + +proc newCfg(): Cfg = + result.basicBlockMap = initTable[int, ref BasicBlock]() + result.edgeList = newSeq[BasicBlockEdge]() + +proc createNode(self: var Cfg, name: int): ref BasicBlock = + #var node: ref BasicBlock + result = self.basicBlockMap.getOrDefault(name) + if result == nil: + result = newBasicBlock(name) + self.basicBlockMap.add name, result + + if self.startNode == nil: + self.startNode = result + +proc addEdge(self: var Cfg, edge: BasicBlockEdge) = + self.edgeList.add(edge) + +proc getNumNodes(self: Cfg): int = + self.basicBlockMap.len + +proc newBasicBlockEdge(cfg: var Cfg, fromName: int, toName: int) = + var newEdge = BasicBlockEdge() + newEdge.fr = cfg.createNode(fromName) + newEdge.to = cfg.createNode(toName) + newEdge.fr.outEdges.add(newEdge.to) + newEdge.to.inEdges.add(newEdge.fr) + cfg.addEdge(newEdge) + +type + SimpleLoop = object + basicBlocks: seq[ref BasicBlock] # TODO: set here + children: seq[ref SimpleLoop] # TODO: set here + parent: ref SimpleLoop + header: ref BasicBlock + isRoot: bool + isReducible: bool + counter: int + nestingLevel: int + depthLevel: int + +proc newSimpleLoop(): ref SimpleLoop = + new(result) + result.basicBlocks = newSeq[ref BasicBlock]() + result.children = newSeq[ref SimpleLoop]() + result.parent = nil + result.header = nil + result.isRoot = false + result.isReducible = true + result.counter = 0 + result.nestingLevel = 0 + result.depthLevel = 0 + +proc addNode(self: ref SimpleLoop, bb: ref BasicBlock) = + self.basicBlocks.add bb + +proc addChildLoop(self: ref SimpleLoop, loop: ref SimpleLoop) = + self.children.add loop + +proc setParent(self: ref SimpleLoop, parent: ref SimpleLoop) = + self.parent = parent + self.parent.addChildLoop(self) + +proc setHeader(self: ref SimpleLoop, bb: ref BasicBlock) = + self.basicBlocks.add(bb) + self.header = bb + +proc setNestingLevel(self: ref SimpleLoop, level: int) = + self.nestingLevel = level + if level == 0: self.isRoot = true + +var loop_counter: int = 0 + +type + Lsg = object + loops: seq[ref SimpleLoop] + root: ref SimpleLoop + +proc createNewLoop(self: var Lsg): ref SimpleLoop = + var s = newSimpleLoop() + loop_counter += 1 + s.counter = loop_counter + s + +proc addLoop(self: var Lsg, l: ref SimpleLoop) = + self.loops.add l + +proc newLsg(): Lsg = + result.loops = newSeq[ref SimpleLoop]() + result.root = result.createNewLoop() + result.root.setNestingLevel(0) + result.addLoop(result.root) + +proc getNumLoops(self: Lsg): int = + self.loops.len + +type + UnionFindNode = object + parent: ref UnionFindNode + bb: ref BasicBlock + l: ref SimpleLoop + dfsNumber: int + +proc newUnionFindNode(): ref UnionFindNode = + new(result) + result.parent = nil + result.bb = nil + result.l = nil + result.dfsNumber = 0 + +proc initNode(self: ref UnionFindNode, bb: ref BasicBlock, dfsNumber: int) = + self.parent = self + self.bb = bb + self.dfsNumber = dfsNumber + +proc findSet(self: ref UnionFindNode): ref UnionFindNode = + var nodeList = newSeq[ref UnionFindNode]() + var node = self + + while node != node.parent: + var parent = node.parent + if parent != parent.parent: nodeList.add node + node = parent + + for iter in nodeList: iter.parent = node.parent + node + +proc union(self: ref UnionFindNode, unionFindNode: ref UnionFindNode) = + self.parent = unionFindNode + + +const + BB_NONHEADER = 1 # a regular BB + BB_REDUCIBLE = 2 # reducible loop + BB_SELF = 3 # single BB loop + BB_IRREDUCIBLE = 4 # irreducible loop + BB_DEAD = 5 # a dead BB + + # # Marker for uninitialized nodes. + UNVISITED = -1 + + # # Safeguard against pathologic algorithm behavior. + MAXNONBACKPREDS = (32 * 1024) + +type + HavlakLoopFinder = object + cfg: Cfg + lsg: Lsg + +proc newHavlakLoopFinder(cfg: sink Cfg, lsg: sink Lsg): HavlakLoopFinder = + result.cfg = cfg + result.lsg = lsg + +proc isAncestor(w: int, v: int, last: seq[int]): bool = + w <= v and v <= last[w] + +proc dfs(currentNode: ref BasicBlock, nodes: var seq[ref UnionFindNode], number: var Table[ref BasicBlock, int], last: var seq[int], current: int): int = + nodes[current].initNode(currentNode, current) + number[currentNode] = current + + var lastid = current + for target in currentNode.outEdges: + if number[target] == UNVISITED: + lastid = dfs(target, nodes, number, last, lastid + 1) + + last[number[currentNode]] = lastid + return lastid + +proc findLoops(self: var HavlakLoopFinder): int = + var startNode = self.cfg.startNode + if startNode == nil: return 0 + var size = self.cfg.getNumNodes + + var nonBackPreds = newSeq[HashSet[int]]() + var backPreds = newSeq[seq[int]]() + var number = initTable[ref BasicBlock, int]() + var header = newSeq[int](size) + var types = newSeq[int](size) + var last = newSeq[int](size) + var nodes = newSeq[ref UnionFindNode]() + + for i in 1..size: + nonBackPreds.add initHashSet[int](1) + backPreds.add newSeq[int]() + nodes.add newUnionFindNode() + + # Step a: + # - initialize all nodes as unvisited. + # - depth-first traversal and numbering. + # - unreached BB's are marked as dead. + # + for v in self.cfg.basicBlockMap.values: number[v] = UNVISITED + discard dfs(startNode, nodes, number, last, 0) + + # Step b: + # - iterate over all nodes. + # + # A backedge comes from a descendant in the DFS tree, and non-backedges + # from non-descendants (following Tarjan). + # + # - check incoming edges 'v' and add them to either + # - the list of backedges (backPreds) or + # - the list of non-backedges (nonBackPreds) + # + for w in 0 ..< size: + header[w] = 0 + types[w] = BB_NONHEADER + + var nodeW = nodes[w].bb + if nodeW != nil: + for nodeV in nodeW.inEdges: + var v = number[nodeV] + if v != UNVISITED: + if isAncestor(w, v, last): + backPreds[w].add v + else: + nonBackPreds[w].incl v + else: + types[w] = BB_DEAD + + # Start node is root of all other loops. + header[0] = 0 + + # Step c: + # + # The outer loop, unchanged from Tarjan. It does nothing except + # for those nodes which are the destinations of backedges. + # For a header node w, we chase backward from the sources of the + # backedges adding nodes to the set P, representing the body of + # the loop headed by w. + # + # By running through the nodes in reverse of the DFST preorder, + # we ensure that inner loop headers will be processed before the + # headers for surrounding loops. + + for w in countdown(size - 1, 0): + # this is 'P' in Havlak's paper + var nodePool = newSeq[ref UnionFindNode]() + + var nodeW = nodes[w].bb + if nodeW != nil: # dead BB + # Step d: + for v in backPreds[w]: + if v != w: + nodePool.add nodes[v].findSet + else: + types[w] = BB_SELF + + # Copy nodePool to workList. + # + var workList = newSeq[ref UnionFindNode]() + for x in nodePool: workList.add x + + if nodePool.len != 0: types[w] = BB_REDUCIBLE + + # work the list... + # + while workList.len > 0: + var x = workList[0] + workList.del(0) + + # Step e: + # + # Step e represents the main difference from Tarjan's method. + # Chasing upwards from the sources of a node w's backedges. If + # there is a node y' that is not a descendant of w, w is marked + # the header of an irreducible loop, there is another entry + # into this loop that avoids w. + # + + # The algorithm has degenerated. Break and + # return in this case. + # + var nonBackSize = nonBackPreds[x.dfsNumber].len + if nonBackSize > MAXNONBACKPREDS: return 0 + + for iter in nonBackPreds[x.dfsNumber]: + var y = nodes[iter] + var ydash = y.findSet + + if not isAncestor(w, ydash.dfsNumber, last): + types[w] = BB_IRREDUCIBLE + nonBackPreds[w].incl ydash.dfsNumber + else: + if ydash.dfsNumber != w and not nodePool.contains(ydash): + workList.add ydash + nodePool.add ydash + + # Collapse/Unionize nodes in a SCC to a single node + # For every SCC found, create a loop descriptor and link it in. + # + if (nodePool.len > 0) or (types[w] == BB_SELF): + var l = self.lsg.createNewLoop + + l.setHeader(nodeW) + l.isReducible = types[w] != BB_IRREDUCIBLE + + # At this point, one can set attributes to the loop, such as: + # + # the bottom node: + # iter = backPreds(w).begin(); + # loop bottom is: nodes(iter).node; + # + # the number of backedges: + # backPreds(w).size() + # + # whether this loop is reducible: + # types(w) != BB_IRREDUCIBLE + # + nodes[w].l = l + + for node in nodePool: + # Add nodes to loop descriptor. + header[node.dfsNumber] = w + node.union(nodes[w]) + + # Nested loops are not added, but linked together. + var node_l = node.l + if node_l != nil: + node_l.setParent(l) + else: + l.addNode(node.bb) + + self.lsg.addLoop(l) + + result = self.lsg.getNumLoops + + +type + LoopTesterApp = object + cfg: Cfg + lsg: Lsg + +proc newLoopTesterApp(): LoopTesterApp = + result.cfg = newCfg() + result.lsg = newLsg() + +proc buildDiamond(self: var LoopTesterApp, start: int): int = + var bb0 = start + newBasicBlockEdge(self.cfg, bb0, bb0 + 1) + newBasicBlockEdge(self.cfg, bb0, bb0 + 2) + newBasicBlockEdge(self.cfg, bb0 + 1, bb0 + 3) + newBasicBlockEdge(self.cfg, bb0 + 2, bb0 + 3) + result = bb0 + 3 + +proc buildConnect(self: var LoopTesterApp, start1: int, end1: int) = + newBasicBlockEdge(self.cfg, start1, end1) + +proc buildStraight(self: var LoopTesterApp, start: int, n: int): int = + for i in 0..n-1: + self.buildConnect(start + i, start + i + 1) + result = start + n + +proc buildBaseLoop(self: var LoopTesterApp, from1: int): int = + var header = self.buildStraight(from1, 1) + var diamond1 = self.buildDiamond(header) + var d11 = self.buildStraight(diamond1, 1) + var diamond2 = self.buildDiamond(d11) + var footer = self.buildStraight(diamond2, 1) + + self.buildConnect(diamond2, d11) + self.buildConnect(diamond1, header) + self.buildConnect(footer, from1) + result = self.buildStraight(footer, 1) + +proc run(self: var LoopTesterApp) = + discard self.cfg.createNode(0) + discard self.buildBaseLoop(0) + discard self.cfg.createNode(1) + self.buildConnect(0, 2) + + for i in 1..8: + # yes, it's 8 and it's correct. + var h = newHavlakLoopFinder(self.cfg, newLsg()) + discard h.findLoops() + + echo "done" + +var l = newLoopTesterApp() +l.run() From fd9ab2ce6d3721545bec0d43c3e862eb3b458feb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 15 Oct 2020 11:51:40 +0200 Subject: [PATCH 1258/4254] ORC: API extensions for 1.4 (#15581) --- lib/system/orc.nim | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 1d856696c..3c2327fd5 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -349,19 +349,36 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) = collectCycles() #writeCell("[added root]", s) -proc GC_fullCollect* = - ## Forces a full garbage collection pass. With ``--gc:orc`` triggers the cycle - ## collector. +proc GC_runOrc* = + ## Forces a cycle collection pass. collectCycles() -proc GC_enableMarkAndSweep*() = +proc GC_enableOrc*() = + ## Enables the cycle collector subsystem of ``--gc:orc``. This is a ``--gc:orc`` + ## specific API. Check with ``when defined(gcOrc)`` for its existence. when not defined(nimStressOrc): rootsThreshold = defaultThreshold -proc GC_disableMarkAndSweep*() = +proc GC_disableOrc*() = + ## Disables the cycle collector subsystem of ``--gc:orc``. This is a ``--gc:orc`` + ## specific API. Check with ``when defined(gcOrc)`` for its existence. when not defined(nimStressOrc): rootsThreshold = high(int) + +proc GC_fullCollect* = + ## Forces a full garbage collection pass. With ``--gc:orc`` triggers the cycle + ## collector. This is an alias for ``GC_runOrc``. + collectCycles() + +proc GC_enableMarkAndSweep*() = + ## For ``--gc:orc`` an alias for ``GC_enableOrc``. + GC_enableOrc() + +proc GC_disableMarkAndSweep*() = + ## For ``--gc:orc`` an alias for ``GC_disableOrc``. + GC_disableOrc() + proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = if isDestroyAction: if (s.rc and isCycleCandidate) != 0: From 42c180c665cb283bcb07e078a5ff91c69c84fa62 Mon Sep 17 00:00:00 2001 From: Igor Ribeiro de Assis Date: Thu, 15 Oct 2020 12:45:55 +0200 Subject: [PATCH 1259/4254] Fix crash in parsexml (#15582) (#15583) Co-authored-by: Igor Ribeiro de Assis --- lib/pure/parsexml.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 6ec77ebdb..79a9cc730 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -666,6 +666,9 @@ proc parseAttribute(my: var XmlParser) = parseEntity(my, my.b) my.kind = xmlAttribute # parseEntity overwrites my.kind! pos = my.bufpos + elif c == '/': + pos = lexbase.handleRefillChar(my, pos) + add(my.b, '/') else: add(my.b, c) inc(pos) From da4aa2e1fb8b0084fcf03b85edf4a5c1d0170856 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 15 Oct 2020 12:52:30 +0200 Subject: [PATCH 1260/4254] renamed '=' to '=copy' [backport:1.2] (#15585) * Assign hook name changed to `=copy` * Adapt destructors.rst * [nobackport] Duplicate tests for =copy hook * Fix tests * added a changelog entry Co-authored-by: Clyybber --- changelog.md | 4 + compiler/ast.nim | 2 +- compiler/injectdestructors.nim | 4 +- compiler/sempass2.nim | 3 +- compiler/semstmts.nim | 4 +- doc/destructors.rst | 22 +- tests/arc/tcaseobjcopy.nim | 246 ++++++++ tests/arc/tcomputedgotocopy.nim | 41 ++ tests/arc/tmovebugcopy.nim | 526 ++++++++++++++++++ tests/arc/topt_no_cursor.nim | 12 +- tests/arc/topt_wasmoved_destroy_pairs.nim | 2 +- tests/arc/tweavecopy.nim | 154 +++++ tests/destructor/tconsume_twice.nim | 2 +- tests/destructor/tprevent_assign.nim | 2 +- tests/destructor/tprevent_assign2.nim | 2 +- tests/destructor/tprevent_assign3.nim | 2 +- tests/destructor/tuse_ownedref_after_move.nim | 2 +- 17 files changed, 1001 insertions(+), 29 deletions(-) create mode 100644 tests/arc/tcaseobjcopy.nim create mode 100644 tests/arc/tcomputedgotocopy.nim create mode 100644 tests/arc/tmovebugcopy.nim create mode 100644 tests/arc/tweavecopy.nim diff --git a/changelog.md b/changelog.md index 2c8f9b5e2..14bcbe608 100644 --- a/changelog.md +++ b/changelog.md @@ -215,6 +215,10 @@ - The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts `wasMoved` calls where needed. +- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there + is no need to update your code. This change was backported to 1.2 too so you can use the + more readability `=copy` without loss of compatibility. + - In the newruntime it is now allowed to assign to the discriminator field without restrictions as long as case object doesn't have custom destructor. The discriminator value doesn't have to be a constant either. If you have a diff --git a/compiler/ast.nim b/compiler/ast.nim index 8adbfa15c..f796e64c2 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1331,7 +1331,7 @@ const MaxLockLevel* = 1000'i16 UnknownLockLevel* = TLockLevel(1001'i16) AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=destroy", "=", "=sink", "=trace", "=dispose", "=deepcopy"] + "=destroy", "=copy", "=sink", "=trace", "=dispose", "=deepcopy"] proc `$`*(x: TLockLevel): string = if x.ord == UnspecifiedLockLevel.ord: result = "" diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b18bcf34e..ea90299e2 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -235,7 +235,7 @@ template isUnpackedTuple(n: PNode): bool = proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">" - if opname == "=" and ri != nil: + if (opname == "=" or opname == "=copy") and ri != nil: m.add "; requires a copy because it's not the last read of '" m.add renderTree(ri) m.add '\'' @@ -319,7 +319,7 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode = if tfHasOwned in t.flags and ri.kind != nkNilLit: # try to improve the error message here: if c.otherRead == nil: discard isLastRead(ri, c) - c.checkForErrorPragma(t, ri, "=") + c.checkForErrorPragma(t, ri, "=copy") result = c.genCopyNoCheck(dest, ri) proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 5eb464bb8..aa04f7451 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -809,7 +809,8 @@ proc trackCall(tracked: PEffects; n: PNode) = if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and tracked.owner.kind != skMacro: - let opKind = find(AttachedOpToStr, a.sym.name.s.normalize) + var opKind = find(AttachedOpToStr, a.sym.name.s.normalize) + if a.sym.name.s.normalize == "=": opKind = attachedAsgn.int if opKind != -1: # rebind type bounds operations after createTypeBoundOps call let t = n[1].typ.skipTypes({tyAlias, tyVar}) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 27cd9019f..b5e69c135 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1732,7 +1732,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T") incl(s.flags, sfUsed) incl(s.flags, sfOverriden) - of "=", "=sink": + of "=", "=copy", "=sink": if s.magic == mAsgn: return incl(s.flags, sfUsed) incl(s.flags, sfOverriden) @@ -1754,7 +1754,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = # attach these ops to the canonical tySequence obj = canonType(c, obj) #echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj) - let k = if name == "=": attachedAsgn else: attachedSink + let k = if name == "=" or name == "=copy": attachedAsgn else: attachedSink if obj.attachedOps[k] == s: discard "forward declared op" elif obj.attachedOps[k].isNil and tfCheckedForDestructor notin obj.flags: diff --git a/doc/destructors.rst b/doc/destructors.rst index b433c38d7..b581fce3e 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -40,7 +40,7 @@ written as: for i in 0..= 0 and k <= n + var pos = newSeq[int](k) + var current = newSeq[T](k) + for i in 0..k-1: + pos[k-i-1] = i + var done = false + while not done: + for i in 0..k-1: + current[i] = s[pos[k-i-1]] + yield current + var i = 0 + while i < k: + pos[i] += 1 + if pos[i] < n-i: + for j in 0..i-1: + pos[j] = pos[i] + i - j + break + i += 1 + if i >= k: + break + +type + UndefEx = object of ValueError + +proc main2 = + var delayedSyms = @[1, 2, 3] + var unp: seq[int] + block myb: + for a in 1 .. 2: + if delayedSyms.len > a: + unp = delayedSyms + for t in unp.combinations(a + 1): + try: + var h = false + for k in t: + echo "fff" + if h: continue + if true: + raise newException(UndefEx, "forward declaration") + break myb + except UndefEx: + echo t.len + echo "mmm" + +main2() + + + +type ME = object + who: string + +proc `=copy`(x: var ME, y: ME) = + if y.who.len > 0: echo "assign ",y.who + +proc `=sink`(x: var ME, y: ME) = + if y.who.len > 0: echo "sink ",y.who + +var dump: ME +template use(x) = dump = x +template def(x) = x = dump + +var c = true + +proc shouldSink() = + var x = ME(who: "me (sink)") + use(x) # we analyse this + if c: def(x) + else: def(x) + use(x) # ok, with the [else] part. + +shouldSink() + +dump = ME() + +proc shouldNotSink() = + var x = ME(who: "me (not sink)") + use(x) # we analyse this + if c: def(x) + use(x) # Not ok without the '[else]' + +shouldNotSink() + +# bug #14568 +import os + +type O2 = object + s: seq[int] + +proc `=sink`(dest: var O2, src: O2) = + echo "sinked and not optimized to a bitcopy" + +var testSeq: O2 + +proc update() = + # testSeq.add(0) # uncommenting this line fixes the leak + testSeq = O2(s: @[]) + testSeq.s.add(0) + +for i in 1..3: + update() + + +# bug #14961 +type + Foo = object + data: seq[int] + +proc initFoo(len: int): Foo = + result = (let s = newSeq[int](len); Foo(data: s) ) + +var f = initFoo(2) +echo initFoo(2) + +proc initFoo2(len: int) = + echo if true: + let s = newSeq[int](len); Foo(data: s) + else: + let s = newSeq[int](len); Foo(data: s) + +initFoo2(2) + +proc initFoo3(len: int) = + echo (block: + let s = newSeq[int](len); Foo(data: s)) + +initFoo3(2) + +proc initFoo4(len: int) = + echo (let s = newSeq[int](len); Foo(data: s)) + +initFoo4(2) + +proc initFoo5(len: int) = + echo (case true + of true: + let s = newSeq[int](len); Foo(data: s) + of false: + let s = newSeq[int](len); Foo(data: s)) + +initFoo5(2) + +proc initFoo6(len: int) = + echo (block: + try: + let s = newSeq[int](len); Foo(data: s) + finally: discard) + +initFoo6(2) + +proc initFoo7(len: int) = + echo (block: + try: + raise newException(CatchableError, "sup") + let s = newSeq[int](len); Foo(data: s) + except CatchableError: + let s = newSeq[int](len); Foo(data: s) ) + +initFoo7(2) + + +# bug #14902 +iterator zip[T](s: openarray[T]): (T, T) = + var i = 0 + while i < 10: + yield (s[i mod 2], s[i mod 2 + 1]) + inc i + +var lastMem = int.high + +proc leak = + const len = 10 + var x = @[newString(len), newString(len), newString(len)] + + var c = 0 + for (a, b) in zip(x): + let newMem = getOccupiedMem() + assert newMem <= lastMem + lastMem = newMem + c += a.len + echo c + +leak() + + +proc consume(a: sink string) = echo a + +proc weirdScopes = + if (let a = "hey"; a.len > 0): + echo a + + while (let a = "hey"; a.len > 0): + echo a + break + + var a = block: (a: "a", b: 2) + echo a + (discard; a) = (echo "ho"; (a: "b", b: 3)) + echo a + + var b = try: (b: "b", a: 2) + except: raise + echo b + (discard; b) = (echo "ho"; (b: "a", a: 3)) + echo b + + var s = "break" + consume((echo "hey"; s)) + echo s + + echo (block: + var a = "hey" + (echo "hey"; "ho")) + + var b2 = "ho" + echo (block: + var a = "hey" + (echo "hey"; b2)) + echo b2 + + type status = enum + alive + + var king = "king" + echo (block: + var a = "a" + when true: + var b = "b" + case alive + of alive: + try: + var c = "c" + if true: + king + else: + "the abyss" + except: + echo "he ded" + "dead king") + echo "live long; long live" + echo king + +weirdScopes() + + +# bug #14985 +proc getScope(): string = + if true: + "hi" + else: + "else" + +echo getScope() + +proc getScope3(): string = + try: + "try" + except: + "except" + +echo getScope3() + +proc getScope2(): string = + case true + of true: + "bye" + else: + "else" + +echo getScope2() diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 5fd21439a..d5811e91e 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -33,9 +33,9 @@ result = ( var sibling saved -`=`(sibling, target.parent.left) -`=`(saved, sibling.right) -`=`(sibling.right, saved.left) +`=copy`(sibling, target.parent.left) +`=copy`(saved, sibling.right) +`=copy`(sibling.right, saved.left) `=sink`(sibling.parent, saved) `=destroy`(sibling) -- end of expandArc ------------------------ @@ -46,7 +46,7 @@ var lvalue lnext _ -`=`(lresult, [123]) +`=copy`(lresult, [123]) _ = ( let blitTmp = lresult blitTmp, ";") @@ -67,10 +67,10 @@ try: var it_cursor = x a = ( wasMoved(:tmpD) - `=`(:tmpD, it_cursor.key) + `=copy`(:tmpD, it_cursor.key) :tmpD, wasMoved(:tmpD_1) - `=`(:tmpD_1, it_cursor.val) + `=copy`(:tmpD_1, it_cursor.val) :tmpD_1) echo [ :tmpD_2 = `$`(a) diff --git a/tests/arc/topt_wasmoved_destroy_pairs.nim b/tests/arc/topt_wasmoved_destroy_pairs.nim index 2a6391dd2..2f971f112 100644 --- a/tests/arc/topt_wasmoved_destroy_pairs.nim +++ b/tests/arc/topt_wasmoved_destroy_pairs.nim @@ -38,7 +38,7 @@ try: return add(a): wasMoved(:tmpD) - `=`(:tmpD, x) + `=copy`(:tmpD, x) :tmpD inc i_1, 1 if cond: diff --git a/tests/arc/tweavecopy.nim b/tests/arc/tweavecopy.nim new file mode 100644 index 000000000..fc796b352 --- /dev/null +++ b/tests/arc/tweavecopy.nim @@ -0,0 +1,154 @@ +discard """ + outputsub: '''Success''' + cmd: '''nim c --gc:arc --threads:on $file''' + disabled: "bsd" +""" + +# bug #13936 + +import std/atomics + +const MemBlockSize = 256 + +type + ChannelSPSCSingle* = object + full{.align: 128.}: Atomic[bool] + itemSize*: uint8 + buffer*{.align: 8.}: UncheckedArray[byte] + +proc `=copy`( + dest: var ChannelSPSCSingle, + source: ChannelSPSCSingle + ) {.error: "A channel cannot be copied".} + +proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} = + ## If ChannelSPSCSingle is used intrusive another data structure + ## be aware that it should be the last part due to ending by UncheckedArray + ## Also due to 128 bytes padding, it automatically takes half + ## of the default MemBlockSize + assert itemsize.int in 0 .. int high(uint8) + assert itemSize.int + + sizeof(chan.itemsize) + + sizeof(chan.full) < MemBlockSize + + chan.itemSize = uint8 itemsize + chan.full.store(false, moRelaxed) + +func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} = + not chan.full.load(moAcquire) + +func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} = + ## Try receiving the item buffered in the channel + ## Returns true if successful (channel was not empty) + ## + ## ⚠ Use only in the consumer thread that reads from the channel. + assert (sizeof(T) == chan.itemsize.int) or + # Support dummy object + (sizeof(T) == 0 and chan.itemsize == 1) + + let full = chan.full.load(moAcquire) + if not full: + return false + dst = cast[ptr T](chan.buffer.addr)[] + chan.full.store(false, moRelease) + return true + +func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} = + ## Try sending an item into the channel + ## Reurns true if successful (channel was empty) + ## + ## ⚠ Use only in the producer thread that writes from the channel. + assert (sizeof(T) == chan.itemsize.int) or + # Support dummy object + (sizeof(T) == 0 and chan.itemsize == 1) + + let full = chan.full.load(moAcquire) + if full: + return false + cast[ptr T](chan.buffer.addr)[] = src + chan.full.store(true, moRelease) + return true + +# Sanity checks +# ------------------------------------------------------------------------------ +when isMainModule: + + when not compileOption("threads"): + {.error: "This requires --threads:on compilation flag".} + + template sendLoop[T](chan: var ChannelSPSCSingle, + data: sink T, + body: untyped): untyped = + while not chan.trySend(data): + body + + template recvLoop[T](chan: var ChannelSPSCSingle, + data: var T, + body: untyped): untyped = + while not chan.tryRecv(data): + body + + type + ThreadArgs = object + ID: WorkerKind + chan: ptr ChannelSPSCSingle + + WorkerKind = enum + Sender + Receiver + + template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} = + if args.ID == id: + body + + proc thread_func(args: ThreadArgs) = + + # Worker RECEIVER: + # --------- + # <- chan + # <- chan + # <- chan + # + # Worker SENDER: + # --------- + # chan <- 42 + # chan <- 53 + # chan <- 64 + Worker(Receiver): + var val: int + for j in 0 ..< 10: + args.chan[].recvLoop(val): + # Busy loop, in prod we might want to yield the core/thread timeslice + discard + echo " Receiver got: ", val + doAssert val == 42 + j*11 + + Worker(Sender): + doAssert args.chan.full.load(moRelaxed) == false + for j in 0 ..< 10: + let val = 42 + j*11 + args.chan[].sendLoop(val): + # Busy loop, in prod we might want to yield the core/thread timeslice + discard + echo "Sender sent: ", val + + proc main() = + echo "Testing if 2 threads can send data" + echo "-----------------------------------" + var threads: array[2, Thread[ThreadArgs]] + + var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize)) + chan[].initialize(itemSize = sizeof(int)) + + createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan)) + createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan)) + + joinThread(threads[0]) + joinThread(threads[1]) + + freeShared(chan) + + echo "-----------------------------------" + echo "Success" + + main() diff --git a/tests/destructor/tconsume_twice.nim b/tests/destructor/tconsume_twice.nim index 0030267f8..b0a039e9b 100644 --- a/tests/destructor/tconsume_twice.nim +++ b/tests/destructor/tconsume_twice.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --newruntime $file" - errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice" + errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice" line: 11 """ type diff --git a/tests/destructor/tprevent_assign.nim b/tests/destructor/tprevent_assign.nim index 108ccc371..4c484ebc1 100644 --- a/tests/destructor/tprevent_assign.nim +++ b/tests/destructor/tprevent_assign.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'otherTree'" line: 29 """ diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim index 0e4481710..ef20672d5 100644 --- a/tests/destructor/tprevent_assign2.nim +++ b/tests/destructor/tprevent_assign2.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'otherTree'" file: "tprevent_assign2.nim" line: 48 """ diff --git a/tests/destructor/tprevent_assign3.nim b/tests/destructor/tprevent_assign3.nim index a8a35ea5e..0577aa5ff 100644 --- a/tests/destructor/tprevent_assign3.nim +++ b/tests/destructor/tprevent_assign3.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=' is not available for type ; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'otherTree'" file: "tprevent_assign3.nim" line: 46 """ diff --git a/tests/destructor/tuse_ownedref_after_move.nim b/tests/destructor/tuse_ownedref_after_move.nim index 46540837c..ce96b741e 100644 --- a/tests/destructor/tuse_ownedref_after_move.nim +++ b/tests/destructor/tuse_ownedref_after_move.nim @@ -1,6 +1,6 @@ discard """ cmd: '''nim c --newruntime $file''' - errormsg: "'=' is not available for type ; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)" + errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)" line: 48 """ From 4ef255b69d00d66e4554bad72fab1780578792f5 Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Thu, 15 Oct 2020 11:54:01 +0100 Subject: [PATCH 1261/4254] fix rlock compilation failure (#15584) * change SysLockType_Reentrant fix edge case where using SysLockType_Reentrant doesn't trigger an #include pthread.h * syslocktype_reentrant now a var * remove nodecl to remove empty system_syslocks.c * let is better than var. in reality SysLockType = enum, maybe that would be a better fix --- lib/core/rlocks.nim | 2 +- lib/system/syslocks.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index 34d7687f9..27a9c5e60 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -24,7 +24,7 @@ proc initRLock*(lock: var RLock) {.inline.} = when defined(posix): var a: SysLockAttr initSysLockAttr(a) - setSysLockType(a, SysLockType_Reentrant()) + setSysLockType(a, SysLockType_Reentrant) initSysLock(lock, a.addr) else: initSysLock(lock) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index b7f7aa6bf..07fb9cb8a 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -181,8 +181,8 @@ else: releaseSysAux(L) when insideRLocksModule: - proc SysLockType_Reentrant: SysLockType = - {.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".} + let SysLockType_Reentrant{.importc: "PTHREAD_MUTEX_RECURSIVE", + header: "".}: SysLockType proc initSysLockAttr(a: var SysLockAttr) {. importc: "pthread_mutexattr_init", header: "", noSideEffect.} proc setSysLockType(a: var SysLockAttr, t: SysLockType) {. From a43202ea57f49a3b49927f114669335a7d40dbb2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 15 Oct 2020 15:49:00 +0200 Subject: [PATCH 1262/4254] fixes #15560 (#15587) --- lib/impure/db_mysql.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index c3bcee677..82f27537c 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -134,8 +134,7 @@ proc dbQuote*(s: string): string = of '\'': result.add "\\'" of '\\': result.add "\\\\" of '_': result.add "\\_" - of Letters+Digits: result.add c - else: result.add "\\" & $ord(c) + else: result.add c add(result, '\'') proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = From b50a0ee95c78cd5137b6a4291471bcbda1e69341 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Thu, 15 Oct 2020 23:43:20 +0000 Subject: [PATCH 1263/4254] fix option formatting (#15591) --- doc/gc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/gc.rst b/doc/gc.rst index b118b1f8a..ee7f9000e 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -35,7 +35,7 @@ To choose the memory management strategy use the ``--gc:`` switch. It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles cause memory leaks, beware. -- ``--gc:orc``. Same as ``-gc:arc`` but adds a cycle collector based on "trial deletion". +- ``--gc:orc``. Same as ``--gc:arc`` but adds a cycle collector based on "trial deletion". Unfortunately that makes its performance profile hard to reason about so it is less useful for hard realtime systems. From 6349001879b18c8934a3427d1dfec49ef2ac46e4 Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 16 Oct 2020 07:16:46 +0200 Subject: [PATCH 1264/4254] create a changelog for 1.4.0 --- changelog.md | 355 +------------------------------- changelogs/changelog_1_4_0.md | 371 ++++++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+), 354 deletions(-) create mode 100644 changelogs/changelog_1_4_0.md diff --git a/changelog.md b/changelog.md index 14bcbe608..f585f4e15 100644 --- a/changelog.md +++ b/changelog.md @@ -1,371 +1,18 @@ -# v1.4.0 - yyyy-mm-dd +# v1.6.x - yyyy-mm-dd ## Standard library additions and changes -- Added some enhancements to `std/jsonutils` module. - * Added a possibility to deserialize JSON arrays directly to `HashSet` and - `OrderedSet` types and respectively to serialize those types to JSON arrays - via `jsonutils.fromJson` and `jsonutils.toJson` procedures. - * Added a possibility to deserialize JSON `null` objects to Nim option objects - and respectively to serialize Nim option object to JSON object if `isSome` - or to JSON null object if `isNone` via `jsonutils.fromJson` and - `jsonutils.toJson` procedures. - * Added `Joptions` parameter to `jsonutils.fromJson` procedure currently - containing two boolean options `allowExtraKeys` and `allowMissingKeys`. - - If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is - not required to have a field for every JSON key. - - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is - allowed to have fields without corresponding JSON keys. -- Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. -- Added `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. -- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. -- `uri` adds Data URI Base64, implements RFC-2397. -- Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) - to the `dom` module for the JavaScript target. -- The default hash for `Ordinal` has changed to something more bit-scrambling. - `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old - one in an instantiation context while `-d:nimIntHash1` recovers it globally. -- `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads. -- File handles created from high-level abstractions in the stdlib will no longer - be inherited by child processes. In particular, these modules are affected: - `asyncdispatch`, `asyncnet`, `system`, `nativesockets`, `net` and `selectors`. - For `asyncdispatch`, `asyncnet`, `net` and `nativesockets`, an `inheritable` - flag has been added to all `proc`s that create sockets, allowing the user to - control whether the resulting socket is inheritable. This flag is provided to - ease the writing of multi-process servers, where sockets inheritance is - desired. - - For a transition period, define `nimInheritHandles` to enable file handle - inheritance by default. This flag does **not** affect the `selectors` module - due to the differing semantics between operating systems. - - `asyncdispatch.setInheritable`, `system.setInheritable` and - `nativesockets.setInheritable` is also introduced for setting file handle or - socket inheritance. Not all platform have these `proc`s defined. - -- The file descriptors created for internal bookkeeping by `ioselector_kqueue` - and `ioselector_epoll` will no longer be leaked to child processes. - -- `strutils.formatFloat` with `precision = 0` has been restored to the version - 1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)` - is now `3.`, not `3`. -- `critbits` adds `commonPrefixLen`. - -- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results - (see #13222); instead they now use `getCurrentDir` to resolve those cases, - and this can now throw in edge cases where `getCurrentDir` throws. - `relativePath` also now works for js with `-d:nodejs`. - -- JavaScript and NimScript standard library changes: `streams.StringStream` is - now supported in JavaScript, with the limitation that any buffer `pointer`s - used must be castable to `ptr string`, any incompatible pointer type will not - work. The `lexbase` and `streams` modules used to fail to compile on - NimScript due to a bug, but this has been fixed. - - The following modules now compile on both JS and NimScript: `parsecsv`, - `parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally - supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for - NimScript: `json`, `parsejson`, `strtabs` and `unidecode`. - -- Added `streams.readStr` and `streams.peekStr` overloads to - accept an existing string to modify, which avoids memory - allocations, similar to `streams.readLine` (#13857). - -- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. - -- `dollars.$` now works for unsigned ints with `nim js` - -- Improvements to the `bitops` module, including bitslices, non-mutating versions - of the original masking functions, `mask`/`masked`, and varargs support for - `bitand`, `bitor`, and `bitxor`. - -- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed - into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency - with regular proc definitions (although you cannot use semicolons). - - Pragmas and using a name are now allowed on the lefthand side of `=>`. Here - is an aggregate example of these changes: - ```nim - import sugar - - foo(x, y: int) {.noSideEffect.} => x + y - - # is transformed into - - proc foo(x: int, y: int): auto {.noSideEffect.} = x + y - ``` - -- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters. - -- The `times` module now handles the default value for `DateTime` more consistently. - Most procs raise an assertion error when given - an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). - The proc `times.isInitialized` has been added which can be used to check if - a `DateTime` has been initialized. - -- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to - hangs if a process had both reads from stdin and writes (eg to stdout). - -- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. -- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. - -- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` - parameters. - -- Added a `ssl_config` module containing lists of secure ciphers as recommended by - [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) - -- `net.newContext` now defaults to the list of ciphers targeting - ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) - per Mozilla's recommendation instead of `ALL`. This change should protect - users from the use of weak and insecure ciphers while still provides - adequate compatibility with the majority of the Internet. - -- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json - serialization/deserialization of custom types was added. - -- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x`` - was added. -- Added `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` - with `outLatex` output. -- Added `os.normalizeExe`, e.g.: `koch` => `./koch`. -- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` - to keep old behavior. -- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. -- Added `typetraits.elementType` to get element type of an iterable. -- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; - `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; - `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` -- Added `macros.extractDocCommentsAndRunnables` helper - -- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now - expands to `fmt"expr={expr}"`. -- deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` - -- Added `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) -- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, - because negative values will result in a new file being created for each logged - line which doesn't make sense. -- Changed `log` in `logging` to use proper log level on JavaScript target, - e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. -- Tables, HashSets, SharedTables and deques don't require anymore that the passed - initial size must be a power of two - this is done internally. - Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. - `CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again. -- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. -- Removed `sugar.distinctBase`, deprecated since `0.19`. -- Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. - -- `std/with`, `sugar.dup` now support object field assignment expression: - ```nim - import std/with - - type Foo = object - x, y: int - - var foo = Foo() - with foo: - x = 10 - y = 20 - - echo foo - ``` - -- Proc `math.round` is no longer deprecated. The advice to use `strformat` instead - cannot be applied to every use case. The limitations and the (lack of) reliability - of `round` are well documented. - -- Added `getprotobyname` to `winlean`. Added `getProtoByname` to `nativesockets` which returns a protocol code - from the database that matches the protocol `name`. - -- Added missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. - -- Added `strutils.indentation` and `strutils.dedent` which enable indented string literals: - ```nim - import strutils - echo dedent """ - This - is - cool! - """ - ``` - -- Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. - -- Added `readLines(p: Process)` to `osproc` module for `startProcess` convenience. - -- Added the below `to` procs for collections. The usage is similar to procs such as - `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the - respective empty collection and add items manually. - * `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of - items or an `openArray` of pairs. - * `deques.toDeque`, which creates a `Deque` from an `openArray`. - * `heapqueue.toHeapQueue`, which creates a `HeapQueue` from an `openArray`. - * `intsets.toIntSet`, which creates an `IntSet` from an `openArray`. - -- Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval - at which progress callbacks are called. - -- Added `os.copyFileToDir` ## Language changes -- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts - `wasMoved` calls where needed. -- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there - is no need to update your code. This change was backported to 1.2 too so you can use the - more readability `=copy` without loss of compatibility. - -- In the newruntime it is now allowed to assign to the discriminator field - without restrictions as long as case object doesn't have custom destructor. - The discriminator value doesn't have to be a constant either. If you have a - custom destructor for a case object and you do want to freely assign discriminator - fields, it is recommended to refactor object into 2 objects like this: - - ```nim - type - MyObj = object - case kind: bool - of true: y: ptr UncheckedArray[float] - of false: z: seq[int] - - proc `=destroy`(x: MyObj) = - if x.kind and x.y != nil: - deallocShared(x.y) - ``` - Refactor into: - ```nim - type - MySubObj = object - val: ptr UncheckedArray[float] - MyObj = object - case kind: bool - of true: y: MySubObj - of false: z: seq[int] - - proc `=destroy`(x: MySubObj) = - if x.val != nil: - deallocShared(x.val) - ``` -- `getImpl` on enum type symbols now returns field syms instead of idents. This helps - with writing typed macros. Old behavior for backwards compatibility can be restored - with `--useVersion:1.0`. -- The typed AST for proc headers will now have the arguments be syms instead of idents. - This helps with writing typed macros. Old behaviour for backwards compatibility can - be restored with `--useVersion:1.0`. -- ``let`` statements can now be used without a value if declared with - ``importc``/``importcpp``/``importjs``/``importobjc``. -- The keyword `from` is now usable as an operator. -- Exceptions inheriting from `system.Defect` are no longer tracked with - the `.raises: []` exception tracking mechanism. This is more consistent with the - built-in operations. The following always used to compile (and still does): - -```nim - -proc mydiv(a, b): int {.raises: [].} = - a div b # can raise an DivByZeroDefect - -``` - - Now also this compiles: - -```nim - -proc mydiv(a, b): int {.raises: [].} = - if b == 0: raise newException(DivByZeroDefect, "division by zero") - else: result = a div b - -``` - - The reason for this is that `DivByZeroDefect` inherits from `Defect` and - with `--panics:on` `Defects` become unrecoverable errors. - -- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes. -- Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. -- Removed `strutils.isNilOrWhitespace`, was deprecated. -- Removed `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. -- Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. -- Removed `dom.releaseEvents` and `dom.captureEvents`, was deprecated. - -- Removed `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. - -- There is a new experimental feature called "strictFuncs" which makes the definition of - `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs) - for more information. - -- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer - an experimental feature. In other words, you don't have to write pragma - `{.experimental: "forLoopMacros".}` if you want to use them. - -- Added a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased - performance this keyword can enable. - -- `items` no longer compiles with enum with holes as its behavior was error prone, see #14004 -- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via - `--deepcopy:on`. - -- Added a `std/effecttraits` module for introspection of the inferred effects. - We hope this enables `async` macros that are precise about the possible exceptions that - can be raised. -- The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be - written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new - preferred way of writing these, emphasizing their unsafe nature. ## Compiler changes -- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. -- The `define` and `undef` pragmas have been de-deprecated. -- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache` - so that output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to - avoid recompiling when sources don't change. This is now the preferred way to - run tests, avoiding the usual pain of clobbering your repo with binaries or - using tricky gitignore rules on posix. Example: - ```nim - nim r compiler/nim.nim --help # only compiled the first time - echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too - nim r compiler/nim.nim --fullhelp # no recompilation - nim r --nimcache:/tmp main # binary saved to /tmp/main - ``` -- `--hint:processing` is now supported and means `--hint:processing:on` - (likewise with other hints and warnings), which is consistent with all other bool flags. - (since 1.3.3). -- `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`. -- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) - was generated; this helps in particular when it's non obvious where it came from - either because multiple locations generate the same message, or because the - message involves runtime formatting. -- new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change backend; can be - used with any command (eg nim r, doc, check etc); safe to re-assign. -- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, - e.g.: `--doccmd:-d:foo --threads` - use `--doccmd:skip` to skip runnableExamples and rst test snippets. -- new flag `--usenimcache` to output to nimcache (whatever it resolves to after - all commands are processed) - and avoids polluting both $pwd and $projectdir. It can be used with any command. -- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override - how an example is compiled and run, for example to change backend or compile only. -- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified - (with or without `--project`); passing `--project` now automatically generates - an index and enables search. - See [docgen](docgen.html#introduction-quick-start) for details. -- Removed the `--oldNewlines` switch. -- Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. -- Removed the `--oldast` switch. -- Removed the `--oldgensym` switch -- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is - now "typed" instead of "stmt". -- Sink inference is now disabled per default and has to enabled explicitly via - `--sinkInference:on`. *Note*: For the standard library sink inference remains - enabled. This change is most relevant for the `--gc:arc`, `--gc:orc` memory - management modes. ## Tool changes -- `nimsuggest` will now return both the forward declaration and the - implementation location upon a `def` query. Previously the behavior was - just to return the forward declaration. diff --git a/changelogs/changelog_1_4_0.md b/changelogs/changelog_1_4_0.md new file mode 100644 index 000000000..1e12a02b2 --- /dev/null +++ b/changelogs/changelog_1_4_0.md @@ -0,0 +1,371 @@ +# v1.4.0 - 2020-10-16 + + + +## Standard library additions and changes + +- Added some enhancements to `std/jsonutils` module. + * Added a possibility to deserialize JSON arrays directly to `HashSet` and + `OrderedSet` types and respectively to serialize those types to JSON arrays + via `jsonutils.fromJson` and `jsonutils.toJson` procedures. + * Added a possibility to deserialize JSON `null` objects to Nim option objects + and respectively to serialize Nim option object to JSON object if `isSome` + or to JSON null object if `isNone` via `jsonutils.fromJson` and + `jsonutils.toJson` procedures. + * Added `Joptions` parameter to `jsonutils.fromJson` procedure currently + containing two boolean options `allowExtraKeys` and `allowMissingKeys`. + - If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is + not required to have a field for every JSON key. + - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is + allowed to have fields without corresponding JSON keys. +- Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. +- Added `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. +- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. +- `uri` adds Data URI Base64, implements RFC-2397. +- Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) + to the `dom` module for the JavaScript target. +- The default hash for `Ordinal` has changed to something more bit-scrambling. + `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old + one in an instantiation context while `-d:nimIntHash1` recovers it globally. +- `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads. +- File handles created from high-level abstractions in the stdlib will no longer + be inherited by child processes. In particular, these modules are affected: + `asyncdispatch`, `asyncnet`, `system`, `nativesockets`, `net` and `selectors`. + + For `asyncdispatch`, `asyncnet`, `net` and `nativesockets`, an `inheritable` + flag has been added to all `proc`s that create sockets, allowing the user to + control whether the resulting socket is inheritable. This flag is provided to + ease the writing of multi-process servers, where sockets inheritance is + desired. + + For a transition period, define `nimInheritHandles` to enable file handle + inheritance by default. This flag does **not** affect the `selectors` module + due to the differing semantics between operating systems. + + `asyncdispatch.setInheritable`, `system.setInheritable` and + `nativesockets.setInheritable` is also introduced for setting file handle or + socket inheritance. Not all platform have these `proc`s defined. + +- The file descriptors created for internal bookkeeping by `ioselector_kqueue` + and `ioselector_epoll` will no longer be leaked to child processes. + +- `strutils.formatFloat` with `precision = 0` has been restored to the version + 1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)` + is now `3.`, not `3`. +- `critbits` adds `commonPrefixLen`. + +- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results + (see #13222); instead they now use `getCurrentDir` to resolve those cases, + and this can now throw in edge cases where `getCurrentDir` throws. + `relativePath` also now works for js with `-d:nodejs`. + +- JavaScript and NimScript standard library changes: `streams.StringStream` is + now supported in JavaScript, with the limitation that any buffer `pointer`s + used must be castable to `ptr string`, any incompatible pointer type will not + work. The `lexbase` and `streams` modules used to fail to compile on + NimScript due to a bug, but this has been fixed. + + The following modules now compile on both JS and NimScript: `parsecsv`, + `parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally + supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for + NimScript: `json`, `parsejson`, `strtabs` and `unidecode`. + +- Added `streams.readStr` and `streams.peekStr` overloads to + accept an existing string to modify, which avoids memory + allocations, similar to `streams.readLine` (#13857). + +- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. + +- `dollars.$` now works for unsigned ints with `nim js` + +- Improvements to the `bitops` module, including bitslices, non-mutating versions + of the original masking functions, `mask`/`masked`, and varargs support for + `bitand`, `bitor`, and `bitxor`. + +- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed + into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency + with regular proc definitions (although you cannot use semicolons). + + Pragmas and using a name are now allowed on the lefthand side of `=>`. Here + is an aggregate example of these changes: + ```nim + import sugar + + foo(x, y: int) {.noSideEffect.} => x + y + + # is transformed into + + proc foo(x: int, y: int): auto {.noSideEffect.} = x + y + ``` + +- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters. + +- The `times` module now handles the default value for `DateTime` more consistently. + Most procs raise an assertion error when given + an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). + The proc `times.isInitialized` has been added which can be used to check if + a `DateTime` has been initialized. + +- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to + hangs if a process had both reads from stdin and writes (eg to stdout). + +- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. +- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. + +- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` + parameters. + +- Added a `ssl_config` module containing lists of secure ciphers as recommended by + [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) + +- `net.newContext` now defaults to the list of ciphers targeting + ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) + per Mozilla's recommendation instead of `ALL`. This change should protect + users from the use of weak and insecure ciphers while still provides + adequate compatibility with the majority of the Internet. + +- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json + serialization/deserialization of custom types was added. + +- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x`` + was added. +- Added `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` + with `outLatex` output. +- Added `os.normalizeExe`, e.g.: `koch` => `./koch`. +- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` + to keep old behavior. +- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. +- Added `typetraits.elementType` to get element type of an iterable. +- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; + `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; + `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` +- Added `macros.extractDocCommentsAndRunnables` helper + +- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now + expands to `fmt"expr={expr}"`. +- deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` + +- Added `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, + because negative values will result in a new file being created for each logged + line which doesn't make sense. +- Changed `log` in `logging` to use proper log level on JavaScript target, + e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. +- Tables, HashSets, SharedTables and deques don't require anymore that the passed + initial size must be a power of two - this is done internally. + Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. + `CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again. +- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. +- Removed `sugar.distinctBase`, deprecated since `0.19`. +- Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. + +- `std/with`, `sugar.dup` now support object field assignment expression: + ```nim + import std/with + + type Foo = object + x, y: int + + var foo = Foo() + with foo: + x = 10 + y = 20 + + echo foo + ``` + +- Proc `math.round` is no longer deprecated. The advice to use `strformat` instead + cannot be applied to every use case. The limitations and the (lack of) reliability + of `round` are well documented. + +- Added `getprotobyname` to `winlean`. Added `getProtoByname` to `nativesockets` which returns a protocol code + from the database that matches the protocol `name`. + +- Added missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. + +- Added `strutils.indentation` and `strutils.dedent` which enable indented string literals: + ```nim + import strutils + echo dedent """ + This + is + cool! + """ + ``` + +- Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. + +- Added `readLines(p: Process)` to `osproc` module for `startProcess` convenience. + +- Added the below `to` procs for collections. The usage is similar to procs such as + `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the + respective empty collection and add items manually. + * `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of + items or an `openArray` of pairs. + * `deques.toDeque`, which creates a `Deque` from an `openArray`. + * `heapqueue.toHeapQueue`, which creates a `HeapQueue` from an `openArray`. + * `intsets.toIntSet`, which creates an `IntSet` from an `openArray`. + +- Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval + at which progress callbacks are called. + +- Added `os.copyFileToDir` + +## Language changes + +- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts + `wasMoved` calls where needed. +- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there + is no need to update your code. This change was backported to 1.2 too so you can use the + more readability `=copy` without loss of compatibility. + +- In the newruntime it is now allowed to assign to the discriminator field + without restrictions as long as case object doesn't have custom destructor. + The discriminator value doesn't have to be a constant either. If you have a + custom destructor for a case object and you do want to freely assign discriminator + fields, it is recommended to refactor object into 2 objects like this: + + ```nim + type + MyObj = object + case kind: bool + of true: y: ptr UncheckedArray[float] + of false: z: seq[int] + + proc `=destroy`(x: MyObj) = + if x.kind and x.y != nil: + deallocShared(x.y) + ``` + Refactor into: + ```nim + type + MySubObj = object + val: ptr UncheckedArray[float] + MyObj = object + case kind: bool + of true: y: MySubObj + of false: z: seq[int] + + proc `=destroy`(x: MySubObj) = + if x.val != nil: + deallocShared(x.val) + ``` +- `getImpl` on enum type symbols now returns field syms instead of idents. This helps + with writing typed macros. Old behavior for backwards compatibility can be restored + with `--useVersion:1.0`. +- The typed AST for proc headers will now have the arguments be syms instead of idents. + This helps with writing typed macros. Old behaviour for backwards compatibility can + be restored with `--useVersion:1.0`. +- ``let`` statements can now be used without a value if declared with + ``importc``/``importcpp``/``importjs``/``importobjc``. +- The keyword `from` is now usable as an operator. +- Exceptions inheriting from `system.Defect` are no longer tracked with + the `.raises: []` exception tracking mechanism. This is more consistent with the + built-in operations. The following always used to compile (and still does): + +```nim + +proc mydiv(a, b): int {.raises: [].} = + a div b # can raise an DivByZeroDefect + +``` + + Now also this compiles: + +```nim + +proc mydiv(a, b): int {.raises: [].} = + if b == 0: raise newException(DivByZeroDefect, "division by zero") + else: result = a div b + +``` + + The reason for this is that `DivByZeroDefect` inherits from `Defect` and + with `--panics:on` `Defects` become unrecoverable errors. + +- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes. +- Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. +- Removed `strutils.isNilOrWhitespace`, was deprecated. +- Removed `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. +- Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. +- Removed `dom.releaseEvents` and `dom.captureEvents`, was deprecated. + +- Removed `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. + +- There is a new experimental feature called "strictFuncs" which makes the definition of + `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs) + for more information. + +- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer + an experimental feature. In other words, you don't have to write pragma + `{.experimental: "forLoopMacros".}` if you want to use them. + +- Added a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased + performance this keyword can enable. + +- `items` no longer compiles with enum with holes as its behavior was error prone, see #14004 +- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via + `--deepcopy:on`. + +- Added a `std/effecttraits` module for introspection of the inferred effects. + We hope this enables `async` macros that are precise about the possible exceptions that + can be raised. +- The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be + written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new + preferred way of writing these, emphasizing their unsafe nature. + + +## Compiler changes + +- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. +- The `define` and `undef` pragmas have been de-deprecated. +- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache` + so that output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to + avoid recompiling when sources don't change. This is now the preferred way to + run tests, avoiding the usual pain of clobbering your repo with binaries or + using tricky gitignore rules on posix. Example: + ```nim + nim r compiler/nim.nim --help # only compiled the first time + echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too + nim r compiler/nim.nim --fullhelp # no recompilation + nim r --nimcache:/tmp main # binary saved to /tmp/main + ``` +- `--hint:processing` is now supported and means `--hint:processing:on` + (likewise with other hints and warnings), which is consistent with all other bool flags. + (since 1.3.3). +- `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`. +- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) + was generated; this helps in particular when it's non obvious where it came from + either because multiple locations generate the same message, or because the + message involves runtime formatting. +- new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change backend; can be + used with any command (eg nim r, doc, check etc); safe to re-assign. +- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, + e.g.: `--doccmd:-d:foo --threads` + use `--doccmd:skip` to skip runnableExamples and rst test snippets. +- new flag `--usenimcache` to output to nimcache (whatever it resolves to after + all commands are processed) + and avoids polluting both $pwd and $projectdir. It can be used with any command. +- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override + how an example is compiled and run, for example to change backend or compile only. +- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified + (with or without `--project`); passing `--project` now automatically generates + an index and enables search. + See [docgen](docgen.html#introduction-quick-start) for details. +- Removed the `--oldNewlines` switch. +- Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. +- Removed the `--oldast` switch. +- Removed the `--oldgensym` switch +- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is + now "typed" instead of "stmt". +- Sink inference is now disabled per default and has to enabled explicitly via + `--sinkInference:on`. *Note*: For the standard library sink inference remains + enabled. This change is most relevant for the `--gc:arc`, `--gc:orc` memory + management modes. + + +## Tool changes + +- `nimsuggest` will now return both the forward declaration and the + implementation location upon a `def` query. Previously the behavior was + just to return the forward declaration. From f8890a0804b6d05a14c9d64d71e1cb27a36bc5ca Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 16 Oct 2020 07:36:09 +0200 Subject: [PATCH 1265/4254] change NimVersion to 1.5.1 --- lib/system.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index fe73a70f5..e41dfe1ca 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2102,11 +2102,11 @@ const ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard # see also std/private/since - NimMinor* {.intdefine.}: int = 3 + NimMinor* {.intdefine.}: int = 5 ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 7 + NimPatch* {.intdefine.}: int = 1 ## is the patch number of Nim's version. ## Odd for devel, even for releases. From 091ec916fd2737d495c5ef54afb5964ee62c049d Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 16 Oct 2020 08:13:23 +0200 Subject: [PATCH 1266/4254] add bufixes for 1.4 in its changelog --- changelogs/changelog_1_4_0.md | 515 ++++++++++++++++++++++++++++++++++ 1 file changed, 515 insertions(+) diff --git a/changelogs/changelog_1_4_0.md b/changelogs/changelog_1_4_0.md index 1e12a02b2..b44e46ffb 100644 --- a/changelogs/changelog_1_4_0.md +++ b/changelogs/changelog_1_4_0.md @@ -369,3 +369,518 @@ proc mydiv(a, b): int {.raises: [].} = - `nimsuggest` will now return both the forward declaration and the implementation location upon a `def` query. Previously the behavior was just to return the forward declaration. + + +## Bugfixes + +- Fixed "repr() not available for uint{,8,16,32,64} under --gc:arc" + ([#13872](https://github.com/nim-lang/Nim/issues/13872)) +- Fixed "Critical: 1 completed Future, multiple await: Only 1 await will be awakened (the last one)" + ([#13889](https://github.com/nim-lang/Nim/issues/13889)) +- Fixed "crash on openarray interator with argument in stmtListExpr" + ([#13739](https://github.com/nim-lang/Nim/issues/13739)) +- Fixed "Some compilers on Windows don't work" + ([#13910](https://github.com/nim-lang/Nim/issues/13910)) +- Fixed "httpclient hangs if it recieves an HTTP 204 (No Content)" + ([#13894](https://github.com/nim-lang/Nim/issues/13894)) +- Fixed ""distinct uint64" type corruption on 32-bit, when using {.borrow.} operators" + ([#13902](https://github.com/nim-lang/Nim/issues/13902)) +- Fixed "Regression: impossible to use typed pragmas with proc types" + ([#13909](https://github.com/nim-lang/Nim/issues/13909)) +- Fixed "openssl wrapper corrupts stack on OpenSSL 1.1.1f + Android" + ([#13903](https://github.com/nim-lang/Nim/issues/13903)) +- Fixed "C compile error with --gc:arc on version 1.2.0 "unknown type name 'TGenericSeq'" + ([#13863](https://github.com/nim-lang/Nim/issues/13863)) +- Fixed "var return type for proc doesn't work at c++ backend" + ([#13848](https://github.com/nim-lang/Nim/issues/13848)) +- Fixed "TimeFormat() should raise an error but craches at compilation time" + ([#12864](https://github.com/nim-lang/Nim/issues/12864)) +- Fixed "gc:arc cannot fully support threadpool with FlowVar" + ([#13781](https://github.com/nim-lang/Nim/issues/13781)) +- Fixed "simple 'var openarray[char]' assignment crash when the openarray source is a local string and using gc:arc" + ([#14003](https://github.com/nim-lang/Nim/issues/14003)) +- Fixed "Cant use expressions with `when` in `type` sections." + ([#14007](https://github.com/nim-lang/Nim/issues/14007)) +- Fixed "`for a in MyEnum` gives incorrect results with enum with holes" + ([#14001](https://github.com/nim-lang/Nim/issues/14001)) +- Fixed "Trivial crash" + ([#12741](https://github.com/nim-lang/Nim/issues/12741)) +- Fixed "Enum with holes cannot be used as Table index" + ([#12834](https://github.com/nim-lang/Nim/issues/12834)) +- Fixed "spawn proc that uses typedesc crashes the compiler" + ([#14014](https://github.com/nim-lang/Nim/issues/14014)) +- Fixed "Docs Search `Results` box styling is not Dark Mode Friendly" + ([#13972](https://github.com/nim-lang/Nim/issues/13972)) +- Fixed "--gc:arc -d:useSysAssert undeclared identifier `cstderr` with newSeq" + ([#14038](https://github.com/nim-lang/Nim/issues/14038)) +- Fixed "issues in the manual" + ([#12486](https://github.com/nim-lang/Nim/issues/12486)) +- Fixed "Annoying warning: inherit from a more precise exception type like ValueError, IOError or OSError [InheritFromException]" + ([#14052](https://github.com/nim-lang/Nim/issues/14052)) +- Fixed "relativePath("foo", "/") and relativePath("/", "foo") is wrong" + ([#13222](https://github.com/nim-lang/Nim/issues/13222)) +- Fixed "[regression] `parseEnum` does not work anymore for enums with holes" + ([#14030](https://github.com/nim-lang/Nim/issues/14030)) +- Fixed "Exception types in the stdlib should inherit from `CatchableError` or `Defect`, not `Exception`" + ([#10288](https://github.com/nim-lang/Nim/issues/10288)) +- Fixed "Make debugSend and debugRecv procs public in smtp.nim" + ([#12189](https://github.com/nim-lang/Nim/issues/12189)) +- Fixed "xmltree need add raw text, when add style element" + ([#14064](https://github.com/nim-lang/Nim/issues/14064)) +- Fixed "raises requirement does not propagate to derived methods" + ([#8481](https://github.com/nim-lang/Nim/issues/8481)) +- Fixed "tests/stdlib/tgetaddrinfo.nim fails on NetBSD" + ([#14091](https://github.com/nim-lang/Nim/issues/14091)) +- Fixed "tests/niminaction/Chapter8/sdl/sdl_test.nim fails on NetBSD" + ([#14088](https://github.com/nim-lang/Nim/issues/14088)) +- Fixed "Incorrect escape sequence for example in jsffi library documentation" + ([#14110](https://github.com/nim-lang/Nim/issues/14110)) +- Fixed "HCR: Can not link exported const, in external library" + ([#13915](https://github.com/nim-lang/Nim/issues/13915)) +- Fixed "Cannot import std/unidecode" + ([#14112](https://github.com/nim-lang/Nim/issues/14112)) +- Fixed "macOS: dsymutil should not be called on static libraries" + ([#14132](https://github.com/nim-lang/Nim/issues/14132)) +- Fixed "nim jsondoc -o:doc.json filename.nim fails when sequences without a type are used" + ([#14066](https://github.com/nim-lang/Nim/issues/14066)) +- Fixed "algorithm.sortedByIt template corrupts tuple input under --gc:arc" + ([#14079](https://github.com/nim-lang/Nim/issues/14079)) +- Fixed "Invalid C code with lvalue conversion" + ([#14160](https://github.com/nim-lang/Nim/issues/14160)) +- Fixed "strformat: doc example fails" + ([#14054](https://github.com/nim-lang/Nim/issues/14054)) +- Fixed "Nim doc fail to run for nim 1.2.0 (nim 1.0.4 is ok)" + ([#13986](https://github.com/nim-lang/Nim/issues/13986)) +- Fixed "Exception when converting csize to clong" + ([#13698](https://github.com/nim-lang/Nim/issues/13698)) +- Fixed "[Documentation] overloading using named arguments works but is not documented" + ([#11932](https://github.com/nim-lang/Nim/issues/11932)) +- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error" + ([#14142](https://github.com/nim-lang/Nim/issues/14142)) +- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error" + ([#14142](https://github.com/nim-lang/Nim/issues/14142)) +- Fixed "runnableExamples doc gen crashes compiler with `except Exception as e` syntax" + ([#14177](https://github.com/nim-lang/Nim/issues/14177)) +- Fixed "[ARC] Segfault with cyclic references (?)" + ([#14159](https://github.com/nim-lang/Nim/issues/14159)) +- Fixed "Semcheck regression when accessing a static parameter in proc" + ([#14136](https://github.com/nim-lang/Nim/issues/14136)) +- Fixed "iterator walkDir doesn't work with -d:useWinAnsi" + ([#14201](https://github.com/nim-lang/Nim/issues/14201)) +- Fixed "cas is wrong for tcc" + ([#14151](https://github.com/nim-lang/Nim/issues/14151)) +- Fixed "proc execCmdEx doesn't work with -d:useWinAnsi" + ([#14203](https://github.com/nim-lang/Nim/issues/14203)) +- Fixed "Use -d:nimEmulateOverflowChecks by default?" + ([#14209](https://github.com/nim-lang/Nim/issues/14209)) +- Fixed "Old sequences with destructor objects bug" + ([#14217](https://github.com/nim-lang/Nim/issues/14217)) +- Fixed "[ARC] ICE when changing the discriminant of a return value" + ([#14244](https://github.com/nim-lang/Nim/issues/14244)) +- Fixed "[ARC] ICE with static objects" + ([#14236](https://github.com/nim-lang/Nim/issues/14236)) +- Fixed "[ARC] "internal error: environment misses: a" in a finalizer" + ([#14243](https://github.com/nim-lang/Nim/issues/14243)) +- Fixed "[ARC] compile failure using repr with object containing `ref seq[string]`" + ([#14270](https://github.com/nim-lang/Nim/issues/14270)) +- Fixed "[ARC] implicit move on last use happening on non-last use" + ([#14269](https://github.com/nim-lang/Nim/issues/14269)) +- Fixed "[ARC] Compiler crash with a recursive non-ref object variant" + ([#14294](https://github.com/nim-lang/Nim/issues/14294)) +- Fixed "htmlparser.parseHtml behaves differently using --gc:arc or --gc:orc" + ([#13946](https://github.com/nim-lang/Nim/issues/13946)) +- Fixed "Invalid return value of openProcess is NULL rather than INVALID_HANDLE_VALUE(-1) in windows" + ([#14289](https://github.com/nim-lang/Nim/issues/14289)) +- Fixed "ARC codegen bug with inline iterators" + ([#14219](https://github.com/nim-lang/Nim/issues/14219)) +- Fixed "Building koch on OpenBSD fails unless the Nim directory is in `$PATH`" + ([#13758](https://github.com/nim-lang/Nim/issues/13758)) +- Fixed "[gc:arc] case object assignment SIGSEGV: destroy not called for primitive type " + ([#14312](https://github.com/nim-lang/Nim/issues/14312)) +- Fixed "Crash when using thread and --gc:arc " + ([#13881](https://github.com/nim-lang/Nim/issues/13881)) +- Fixed "Getting "Warning: Cannot prove that 'result' is initialized" for an importcpp'd proc with `var T` return type" + ([#14314](https://github.com/nim-lang/Nim/issues/14314)) +- Fixed "`nim cpp -r --gc:arc` segfaults on caught AssertionError" + ([#13071](https://github.com/nim-lang/Nim/issues/13071)) +- Fixed "tests/async/tasyncawait.nim is recently very flaky" + ([#14320](https://github.com/nim-lang/Nim/issues/14320)) +- Fixed "Documentation nonexistent quitprocs module" + ([#14331](https://github.com/nim-lang/Nim/issues/14331)) +- Fixed "SIGSEV encountered when creating threads in a loop w/ --gc:arc" + ([#13935](https://github.com/nim-lang/Nim/issues/13935)) +- Fixed "nim-gdb is missing from all released packages" + ([#13104](https://github.com/nim-lang/Nim/issues/13104)) +- Fixed "sysAssert error with gc:arc on 3 line program" + ([#13862](https://github.com/nim-lang/Nim/issues/13862)) +- Fixed "compiler error with inline async proc and pragma" + ([#13998](https://github.com/nim-lang/Nim/issues/13998)) +- Fixed "[ARC] Compiler crash when adding to a seq[ref Object]" + ([#14333](https://github.com/nim-lang/Nim/issues/14333)) +- Fixed "nimvm: sysFatal: unhandled exception: 'sons' is not accessible using discriminant 'kind' of type 'TNode' [FieldError]" + ([#14340](https://github.com/nim-lang/Nim/issues/14340)) +- Fixed "[Regression] karax events are not firing " + ([#14350](https://github.com/nim-lang/Nim/issues/14350)) +- Fixed "odbcsql module has some wrong integer types" + ([#9771](https://github.com/nim-lang/Nim/issues/9771)) +- Fixed "db_sqlite needs sqlPrepared" + ([#13559](https://github.com/nim-lang/Nim/issues/13559)) +- Fixed "[Regression] `createThread` is not GC-safe" + ([#14370](https://github.com/nim-lang/Nim/issues/14370)) +- Fixed "Broken example on hot code reloading" + ([#14380](https://github.com/nim-lang/Nim/issues/14380)) +- Fixed "runnableExamples block with `except` on specified error fails with `nim doc`" + ([#12746](https://github.com/nim-lang/Nim/issues/12746)) +- Fixed "compiler as a library: findNimStdLibCompileTime fails to find system.nim" + ([#12293](https://github.com/nim-lang/Nim/issues/12293)) +- Fixed "5 bugs with importcpp exceptions" + ([#14369](https://github.com/nim-lang/Nim/issues/14369)) +- Fixed "Docs shouldn't collapse pragmas inside runnableExamples/code blocks" + ([#14174](https://github.com/nim-lang/Nim/issues/14174)) +- Fixed "Bad codegen/emit for hashes.hiXorLo in some contexts." + ([#14394](https://github.com/nim-lang/Nim/issues/14394)) +- Fixed "Boehm GC does not scan thread-local storage" + ([#14364](https://github.com/nim-lang/Nim/issues/14364)) +- Fixed "RVO not exception safe" + ([#14126](https://github.com/nim-lang/Nim/issues/14126)) +- Fixed "runnableExamples that are only compiled" + ([#10731](https://github.com/nim-lang/Nim/issues/10731)) +- Fixed "`foldr` raises IndexError when called on sequence" + ([#14404](https://github.com/nim-lang/Nim/issues/14404)) +- Fixed "moveFile does not overwrite destination file" + ([#14057](https://github.com/nim-lang/Nim/issues/14057)) +- Fixed "doc2 outputs in current work dir" + ([#6583](https://github.com/nim-lang/Nim/issues/6583)) +- Fixed "[docgen] proc doc comments silently omitted after 1st runnableExamples" + ([#9227](https://github.com/nim-lang/Nim/issues/9227)) +- Fixed "`nim doc --project` shows '@@/' instead of '../' for relative paths to submodules" + ([#14448](https://github.com/nim-lang/Nim/issues/14448)) +- Fixed "re, nre have wrong `start` semantics" + ([#14284](https://github.com/nim-lang/Nim/issues/14284)) +- Fixed "runnableExamples should preserve source code doc comments, strings, and (maybe) formatting" + ([#8871](https://github.com/nim-lang/Nim/issues/8871)) +- Fixed "`nim doc ..` fails when runnableExamples uses `$` [devel] [regression]" + ([#14485](https://github.com/nim-lang/Nim/issues/14485)) +- Fixed "`items` is 20%~30% slower than iteration via an index" + ([#14421](https://github.com/nim-lang/Nim/issues/14421)) +- Fixed "ARC: unreliable setLen " + ([#14495](https://github.com/nim-lang/Nim/issues/14495)) +- Fixed "lent is unsafe: after #14447 you can modify variables with "items" loop for sequences" + ([#14498](https://github.com/nim-lang/Nim/issues/14498)) +- Fixed "`var op = fn()` wrongly gives warning `ObservableStores` with `object of RootObj` type" + ([#14514](https://github.com/nim-lang/Nim/issues/14514)) +- Fixed "Compiler assertion" + ([#14562](https://github.com/nim-lang/Nim/issues/14562)) +- Fixed "Can't get `ord` of a value of a Range type in the JS backend " + ([#14570](https://github.com/nim-lang/Nim/issues/14570)) +- Fixed "js: can't take addr of param (including implicitly via `lent`)" + ([#14576](https://github.com/nim-lang/Nim/issues/14576)) +- Fixed "{.noinit.} ignored in for loop -> bad codegen for non-movable types" + ([#14118](https://github.com/nim-lang/Nim/issues/14118)) +- Fixed "generic destructor gives: `Error: unresolved generic parameter`" + ([#14315](https://github.com/nim-lang/Nim/issues/14315)) +- Fixed "Memory leak with arc gc" + ([#14568](https://github.com/nim-lang/Nim/issues/14568)) +- Fixed "escape analysis broken with `lent`" + ([#14557](https://github.com/nim-lang/Nim/issues/14557)) +- Fixed "`wrapWords` seems to ignore linebreaks when wrapping, leaving breaks in the wrong place" + ([#14579](https://github.com/nim-lang/Nim/issues/14579)) +- Fixed "`lent` gives wrong results with -d:release" + ([#14578](https://github.com/nim-lang/Nim/issues/14578)) +- Fixed "Nested await expressions regression: `await a(await expandValue())` doesnt compile" + ([#14279](https://github.com/nim-lang/Nim/issues/14279)) +- Fixed "windows CI docs fails with strange errors" + ([#14545](https://github.com/nim-lang/Nim/issues/14545)) +- Fixed "[CI] tests/async/tioselectors.nim flaky test for freebsd + OSX CI" + ([#13166](https://github.com/nim-lang/Nim/issues/13166)) +- Fixed "seq.setLen sometimes doesn't zero memory" + ([#14655](https://github.com/nim-lang/Nim/issues/14655)) +- Fixed "`nim dump` is roughly 100x slower in 1.3 versus 1.2" + ([#14179](https://github.com/nim-lang/Nim/issues/14179)) +- Fixed "Regression: devel docgen cannot generate document for method" + ([#14691](https://github.com/nim-lang/Nim/issues/14691)) +- Fixed "recently flaky tests/async/t7758.nim" + ([#14685](https://github.com/nim-lang/Nim/issues/14685)) +- Fixed "Bind no longer working in generic procs." + ([#11811](https://github.com/nim-lang/Nim/issues/11811)) +- Fixed "The pegs module doesn't work with generics!" + ([#14718](https://github.com/nim-lang/Nim/issues/14718)) +- Fixed "Defer is not properly working for asynchronous procedures." + ([#13899](https://github.com/nim-lang/Nim/issues/13899)) +- Fixed "Add an ARC test with threads in a loop" + ([#14690](https://github.com/nim-lang/Nim/issues/14690)) +- Fixed "[goto exceptions] {.noReturn.} pragma is not detected in a case expression" + ([#14458](https://github.com/nim-lang/Nim/issues/14458)) +- Fixed "[exceptions:goto] C compiler error with dynlib pragma calling a proc" + ([#14240](https://github.com/nim-lang/Nim/issues/14240)) +- Fixed "Cannot borrow var float64 in infix assignment" + ([#14440](https://github.com/nim-lang/Nim/issues/14440)) +- Fixed "lib/pure/memfiles.nim: compilation error with --taintMode:on" + ([#14760](https://github.com/nim-lang/Nim/issues/14760)) +- Fixed "newWideCString allocates a multiple of the memory needed" + ([#14750](https://github.com/nim-lang/Nim/issues/14750)) +- Fixed "Nim source archive install: 'install.sh' fails with error: cp: cannot stat 'bin/nim-gdb': No such file or directory" + ([#14748](https://github.com/nim-lang/Nim/issues/14748)) +- Fixed "`nim cpp -r tests/exception/t9657` hangs" + ([#10343](https://github.com/nim-lang/Nim/issues/10343)) +- Fixed "Detect tool fails on FreeBSD" + ([#14715](https://github.com/nim-lang/Nim/issues/14715)) +- Fixed "compiler crash: `findUnresolvedStatic` " + ([#14802](https://github.com/nim-lang/Nim/issues/14802)) +- Fixed "seq namespace (?) regression" + ([#4796](https://github.com/nim-lang/Nim/issues/4796)) +- Fixed "Possible out of bounds string access in std/colors parseColor and isColor" + ([#14839](https://github.com/nim-lang/Nim/issues/14839)) +- Fixed "compile error on latest devel with orc and ssl" + ([#14647](https://github.com/nim-lang/Nim/issues/14647)) +- Fixed "[minor] `$` wrong for type tuple" + ([#13432](https://github.com/nim-lang/Nim/issues/13432)) +- Fixed "Documentation missing on devel asyncftpclient" + ([#14846](https://github.com/nim-lang/Nim/issues/14846)) +- Fixed "nimpretty is confused with a trailing comma in enum definition" + ([#14401](https://github.com/nim-lang/Nim/issues/14401)) +- Fixed "Output arguments get ignored when compiling with --app:staticlib" + ([#12745](https://github.com/nim-lang/Nim/issues/12745)) +- Fixed "[ARC] destructive move destroys the object too early" + ([#14396](https://github.com/nim-lang/Nim/issues/14396)) +- Fixed "highlite.getNextToken() crashes if the buffer string is "echo "\""" + ([#14830](https://github.com/nim-lang/Nim/issues/14830)) +- Fixed "Memory corruption with --gc:arc with a seq of objects with an empty body." + ([#14472](https://github.com/nim-lang/Nim/issues/14472)) +- Fixed "Stropped identifiers don't work as field names in tuple literals" + ([#14911](https://github.com/nim-lang/Nim/issues/14911)) +- Fixed "Please revert my commit" + ([#14930](https://github.com/nim-lang/Nim/issues/14930)) +- Fixed "[ARC] C compiler error with inline iterators and imports" + ([#14864](https://github.com/nim-lang/Nim/issues/14864)) +- Fixed "AsyncHttpClient segfaults with gc:orc, possibly memory corruption" + ([#14402](https://github.com/nim-lang/Nim/issues/14402)) +- Fixed "[ARC] Template with a block evaluating to a GC'd value results in a compiler crash" + ([#14899](https://github.com/nim-lang/Nim/issues/14899)) +- Fixed "[ARC] Weird issue with if expressions and templates" + ([#14900](https://github.com/nim-lang/Nim/issues/14900)) +- Fixed "xmlparser does not compile on devel" + ([#14805](https://github.com/nim-lang/Nim/issues/14805)) +- Fixed "returning lent T from a var T param gives codegen errors or SIGSEGV" + ([#14878](https://github.com/nim-lang/Nim/issues/14878)) +- Fixed "[ARC] Weird issue with if expressions and templates" + ([#14900](https://github.com/nim-lang/Nim/issues/14900)) +- Fixed "threads:on + gc:orc + unittest = C compiler errors" + ([#14865](https://github.com/nim-lang/Nim/issues/14865)) +- Fixed "mitems, mpairs doesn't work at compile time anymore" + ([#12129](https://github.com/nim-lang/Nim/issues/12129)) +- Fixed "strange result from executing code in const expression" + ([#10465](https://github.com/nim-lang/Nim/issues/10465)) +- Fixed "Same warning printed 3 times" + ([#11009](https://github.com/nim-lang/Nim/issues/11009)) +Was unsure about: " add testcase for #4668 (#14946)" +- Fixed "type alias for generic typeclass doesn't work" + ([#4668](https://github.com/nim-lang/Nim/issues/4668)) +- Fixed "exceptions:goto Bug devel codegen lvalue NIM_FALSE=NIM_FALSE" + ([#14925](https://github.com/nim-lang/Nim/issues/14925)) +- Fixed "the --useVersion:1.0 no longer works in devel" + ([#14912](https://github.com/nim-lang/Nim/issues/14912)) +- Fixed "template declaration of iterator doesn't compile" + ([#4722](https://github.com/nim-lang/Nim/issues/4722)) +- Fixed "Compiler crash on type inheritance with static generic parameter and equality check" + ([#12571](https://github.com/nim-lang/Nim/issues/12571)) +- Fixed "Nim crashes while handling a cast in async circumstances." + ([#13815](https://github.com/nim-lang/Nim/issues/13815)) +- Fixed "[ARC] Internal compiler error when calling an iterator from an inline proc " + ([#14383](https://github.com/nim-lang/Nim/issues/14383)) +- Fixed ""Cannot instantiate" error when template uses generic type" + ([#5926](https://github.com/nim-lang/Nim/issues/5926)) +- Fixed "Different raises behaviour for newTerminal between Linux and Windows" + ([#12759](https://github.com/nim-lang/Nim/issues/12759)) +- Fixed "Expand on a type (that defines a proc type) in error message " + ([#6608](https://github.com/nim-lang/Nim/issues/6608)) +- Fixed "unittest require quits program with an exit code of 0" + ([#14475](https://github.com/nim-lang/Nim/issues/14475)) +- Fixed "Range type: Generics vs concrete type, semcheck difference." + ([#8426](https://github.com/nim-lang/Nim/issues/8426)) +- Fixed "[Macro] Type mismatch when parameter name is the same as a field" + ([#13253](https://github.com/nim-lang/Nim/issues/13253)) +- Fixed "Generic instantiation failure when converting a sequence of circular generic types to strings" + ([#10396](https://github.com/nim-lang/Nim/issues/10396)) +- Fixed "initOptParser ignores argument after value option with empty value." + ([#13086](https://github.com/nim-lang/Nim/issues/13086)) +- Fixed "[ARC] proc with both explicit and implicit return results in a C compiler error" + ([#14985](https://github.com/nim-lang/Nim/issues/14985)) +- Fixed "Alias type forgets implicit generic params depending on order" + ([#14990](https://github.com/nim-lang/Nim/issues/14990)) +- Fixed "[ARC] sequtils.insert has different behaviour between ARC/refc" + ([#14994](https://github.com/nim-lang/Nim/issues/14994)) +- Fixed "The documentation for "hot code reloading" references a non-existent npm package" + ([#13621](https://github.com/nim-lang/Nim/issues/13621)) +- Fixed "existsDir deprecated but breaking `dir` undeclared" + ([#15006](https://github.com/nim-lang/Nim/issues/15006)) +- Fixed "uri.decodeUrl crashes on incorrectly formatted input" + ([#14082](https://github.com/nim-lang/Nim/issues/14082)) +- Fixed "testament incorrectly reports time for tests, leading to wrong conclusions" + ([#14822](https://github.com/nim-lang/Nim/issues/14822)) +- Fixed "Calling peekChar with Stream returned from osproc.outputStream generate runtime error" + ([#14906](https://github.com/nim-lang/Nim/issues/14906)) +- Fixed "localPassC pragma should come *after* other flags" + ([#14194](https://github.com/nim-lang/Nim/issues/14194)) +- Fixed ""Could not load" dynamic library at runtime because of hidden dependency" + ([#2408](https://github.com/nim-lang/Nim/issues/2408)) +- Fixed "--gc:arc generate invalid code for {.global.} (`«nimErr_» in NIM_UNLIKELY`)" + ([#14480](https://github.com/nim-lang/Nim/issues/14480)) +- Fixed "Using `^` from stdlib/math along with converters gives a match for types that aren't SomeNumber" + ([#15033](https://github.com/nim-lang/Nim/issues/15033)) +- Fixed "[ARC] Weird exception behaviour from doAssertRaises" + ([#15026](https://github.com/nim-lang/Nim/issues/15026)) +- Fixed "[ARC] Compiler crash declaring a finalizer proc directly in 'new'" + ([#15044](https://github.com/nim-lang/Nim/issues/15044)) +- Fixed "[ARC] C compiler error when creating a var of a const seq" + ([#15036](https://github.com/nim-lang/Nim/issues/15036)) +- Fixed "code with named arguments in proc of winim/com can not been compiled" + ([#15056](https://github.com/nim-lang/Nim/issues/15056)) +- Fixed "javascript backend produces javascript code with syntax error in object syntax" + ([#14534](https://github.com/nim-lang/Nim/issues/14534)) +- Fixed "--gc:arc should be ignored in JS mode." + ([#14684](https://github.com/nim-lang/Nim/issues/14684)) +- Fixed "arc: C compilation error with imported global code using a closure iterator" + ([#12990](https://github.com/nim-lang/Nim/issues/12990)) +- Fixed "[ARC] Crash when modifying a string with mitems iterator" + ([#15052](https://github.com/nim-lang/Nim/issues/15052)) +- Fixed "[ARC] SIGSEGV when calling a closure as a tuple field in a seq" + ([#15038](https://github.com/nim-lang/Nim/issues/15038)) +- Fixed "pass varargs[seq[T]] to iterator give empty seq " + ([#12576](https://github.com/nim-lang/Nim/issues/12576)) +- Fixed "Compiler crashes when using string as object variant selector with else branch" + ([#14189](https://github.com/nim-lang/Nim/issues/14189)) +- Fixed "JS compiler error related to implicit return and return var type" + ([#11354](https://github.com/nim-lang/Nim/issues/11354)) +- Fixed "`nkRecWhen` causes internalAssert in semConstructFields" + ([#14698](https://github.com/nim-lang/Nim/issues/14698)) +- Fixed "Memory leaks with async (closure iterators?) under ORC" + ([#15076](https://github.com/nim-lang/Nim/issues/15076)) +- Fixed "strutil.insertSep() fails on negative numbers" + ([#11352](https://github.com/nim-lang/Nim/issues/11352)) +- Fixed "Constructing a uint64 range on a 32-bit machine leads to incorrect codegen" + ([#14616](https://github.com/nim-lang/Nim/issues/14616)) +- Fixed "heapqueue pushpop() proc doesn't compile" + ([#14139](https://github.com/nim-lang/Nim/issues/14139)) +- Fixed "[ARC] SIGSEGV when trying to swap in a literal/const string" + ([#15112](https://github.com/nim-lang/Nim/issues/15112)) +- Fixed "Defer and --gc:arc" + ([#15071](https://github.com/nim-lang/Nim/issues/15071)) +- Fixed "internal error: compiler/semobjconstr.nim(324, 20) example" + ([#15111](https://github.com/nim-lang/Nim/issues/15111)) +- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant" + ([#15122](https://github.com/nim-lang/Nim/issues/15122)) +- Fixed "[ARC] SIGSEGV with tuple assignment caused by cursor inference" + ([#15130](https://github.com/nim-lang/Nim/issues/15130)) +- Fixed "Issue with --gc:arc at compile time" + ([#15129](https://github.com/nim-lang/Nim/issues/15129)) +- Fixed "Writing an empty string to an AsyncFile raises an IndexDefect" + ([#15148](https://github.com/nim-lang/Nim/issues/15148)) +- Fixed "Compiler is confused about call convention of function with nested closure" + ([#5688](https://github.com/nim-lang/Nim/issues/5688)) +- Fixed "Nil check on each field fails in generic function" + ([#15101](https://github.com/nim-lang/Nim/issues/15101)) +- Fixed "{.nimcall.} convention won't avoid the creation of closures" + ([#8473](https://github.com/nim-lang/Nim/issues/8473)) +- Fixed "smtp.nim(161, 40) Error: type mismatch: got but expected 'SslContext = void'" + ([#15177](https://github.com/nim-lang/Nim/issues/15177)) +- Fixed "[strscans] scanf doesn't match a single character with $+ if it's the end of the string" + ([#15064](https://github.com/nim-lang/Nim/issues/15064)) +- Fixed "Crash and incorrect return values when using readPasswordFromStdin on Windows." + ([#15207](https://github.com/nim-lang/Nim/issues/15207)) +- Fixed "Possible capture error with fieldPairs and genericParams" + ([#15221](https://github.com/nim-lang/Nim/issues/15221)) +- Fixed "The StmtList processing of template parameters can lead to unexpected errors" + ([#5691](https://github.com/nim-lang/Nim/issues/5691)) +- Fixed "[ARC] C compiler error when passing a var openArray to a sink openArray" + ([#15035](https://github.com/nim-lang/Nim/issues/15035)) +- Fixed "Inconsistent unsigned -> signed RangeDefect usage across integer sizes" + ([#15210](https://github.com/nim-lang/Nim/issues/15210)) +- Fixed "toHex results in RangeDefect exception when used with large uint64" + ([#15257](https://github.com/nim-lang/Nim/issues/15257)) +- Fixed "Arc sink arg crash" + ([#15238](https://github.com/nim-lang/Nim/issues/15238)) +- Fixed "SQL escape in db_mysql is not enough" + ([#15219](https://github.com/nim-lang/Nim/issues/15219)) +- Fixed "Mixing 'return' with expressions is allowed in 1.2" + ([#15280](https://github.com/nim-lang/Nim/issues/15280)) +- Fixed "os.getFileInfo() causes ICE with --gc:arc on Windows" + ([#15286](https://github.com/nim-lang/Nim/issues/15286)) +- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant" + ([#15122](https://github.com/nim-lang/Nim/issues/15122)) +- Fixed "Documentation regression jsre module missing" + ([#15183](https://github.com/nim-lang/Nim/issues/15183)) +- Fixed "CountTable.smallest/largest() on empty table either asserts or gives bogus answer" + ([#15021](https://github.com/nim-lang/Nim/issues/15021)) +- Fixed "[Regression] Parser regression" + ([#15305](https://github.com/nim-lang/Nim/issues/15305)) +- Fixed "[ARC] SIGSEGV with tuple unpacking caused by cursor inference" + ([#15147](https://github.com/nim-lang/Nim/issues/15147)) +- Fixed "LwIP/FreeRTOS compile error - missing SIGPIPE and more " + ([#15302](https://github.com/nim-lang/Nim/issues/15302)) +- Fixed "Memory leaks with async (closure iterators?) under ORC" + ([#15076](https://github.com/nim-lang/Nim/issues/15076)) +- Fixed "Bug compiling with --gc:arg or --gc:orc" + ([#15325](https://github.com/nim-lang/Nim/issues/15325)) +- Fixed "memory corruption in tmarshall.nim" + ([#9754](https://github.com/nim-lang/Nim/issues/9754)) +- Fixed "typed macros break generic proc definitions" + ([#15326](https://github.com/nim-lang/Nim/issues/15326)) +- Fixed "nim doc2 ignores --docSeeSrcUrl parameter" + ([#6071](https://github.com/nim-lang/Nim/issues/6071)) +- Fixed "The decodeData Iterator from cgi module crash" + ([#15369](https://github.com/nim-lang/Nim/issues/15369)) +- Fixed "|| iterator generates invalid code when compiling with --debugger:native" + ([#9710](https://github.com/nim-lang/Nim/issues/9710)) +- Fixed "Wrong number of variables" + ([#15360](https://github.com/nim-lang/Nim/issues/15360)) +- Fixed "Coercions with distinct types should traverse pointer modifiers transparently." + ([#7165](https://github.com/nim-lang/Nim/issues/7165)) +- Fixed "Error with distinct generic TableRef" + ([#6060](https://github.com/nim-lang/Nim/issues/6060)) +- Fixed "Support images in nim docgen" + ([#6430](https://github.com/nim-lang/Nim/issues/6430)) +- Fixed "Regression. Double sem check for procs." + ([#15389](https://github.com/nim-lang/Nim/issues/15389)) +- Fixed "uri.nim url with literal ipv6 address is printed wrong, and cannot parsed again" + ([#15333](https://github.com/nim-lang/Nim/issues/15333)) +- Fixed "[ARC] Object variant gets corrupted with cursor inference" + ([#15361](https://github.com/nim-lang/Nim/issues/15361)) +- Fixed "`nim doc ..` compiler crash (regression 0.19.6 => 1.0)" + ([#14474](https://github.com/nim-lang/Nim/issues/14474)) +- Fixed "cannot borrow result; what it borrows from is potentially mutated" + ([#15403](https://github.com/nim-lang/Nim/issues/15403)) +- Fixed "memory corruption for seq.add(seq) with gc:arc and d:useMalloc " + ([#14983](https://github.com/nim-lang/Nim/issues/14983)) +- Fixed "DocGen HTML output appears improperly when encountering text immediately after/before inline monospace; in some cases won't compile" + ([#11537](https://github.com/nim-lang/Nim/issues/11537)) +- Fixed "Deepcopy in arc crashes" + ([#15405](https://github.com/nim-lang/Nim/issues/15405)) +- Fixed "pop pragma takes invalid input" + ([#15430](https://github.com/nim-lang/Nim/issues/15430)) +- Fixed "tests/stdlib/tgetprotobyname fails on NetBSD" + ([#15452](https://github.com/nim-lang/Nim/issues/15452)) +- Fixed "defer doesnt work with block, break and await" + ([#15243](https://github.com/nim-lang/Nim/issues/15243)) +- Fixed "tests/stdlib/tssl failing on NetBSD" + ([#15493](https://github.com/nim-lang/Nim/issues/15493)) +- Fixed "strictFuncs doesn't seem to catch simple ref mutation" + ([#15508](https://github.com/nim-lang/Nim/issues/15508)) +- Fixed "Sizeof of case object is incorrect. Showstopper" + ([#15516](https://github.com/nim-lang/Nim/issues/15516)) +- Fixed "[ARC] Internal error when trying to use a parallel for loop" + ([#15512](https://github.com/nim-lang/Nim/issues/15512)) +- Fixed "[ARC] Type-bound assign op is not being generated" + ([#15510](https://github.com/nim-lang/Nim/issues/15510)) +- Fixed "[ARC] Crash when adding openArray proc argument to a local seq" + ([#15511](https://github.com/nim-lang/Nim/issues/15511)) +- Fixed "VM: const case object gets some fields zeroed out at runtime" + ([#13081](https://github.com/nim-lang/Nim/issues/13081)) +- Fixed "regression(1.2.6 => devel): VM: const case object field access gives: 'sons' is not accessible" + ([#15532](https://github.com/nim-lang/Nim/issues/15532)) +- Fixed "Csources: huge size increase (x2.3) in 0.20" + ([#12027](https://github.com/nim-lang/Nim/issues/12027)) +- Fixed "Out of date error message for GC options" + ([#15547](https://github.com/nim-lang/Nim/issues/15547)) +- Fixed "dbQuote additional escape regression" + ([#15560](https://github.com/nim-lang/Nim/issues/15560)) From 6b8baab536d25c744150e0190d2e172165faf92e Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 16 Oct 2020 13:18:31 +0200 Subject: [PATCH 1267/4254] cosmetic fixes for the 1.4 changelog [ci skip] --- changelogs/changelog_1_4_0.md | 144 ++++++++++++++++------------------ 1 file changed, 66 insertions(+), 78 deletions(-) diff --git a/changelogs/changelog_1_4_0.md b/changelogs/changelog_1_4_0.md index b44e46ffb..091048ad1 100644 --- a/changelogs/changelog_1_4_0.md +++ b/changelogs/changelog_1_4_0.md @@ -12,16 +12,16 @@ and respectively to serialize Nim option object to JSON object if `isSome` or to JSON null object if `isNone` via `jsonutils.fromJson` and `jsonutils.toJson` procedures. - * Added `Joptions` parameter to `jsonutils.fromJson` procedure currently + * Added a `Joptions` parameter to `jsonutils.fromJson` currently containing two boolean options `allowExtraKeys` and `allowMissingKeys`. - If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is not required to have a field for every JSON key. - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is allowed to have fields without corresponding JSON keys. - Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. -- Added `tryInsert`,`insert` procs to `db_*` libs accept primary key column name. +- Added `tryInsert`,`insert` procs to `db_*` libs which accept primary key column name. - Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. -- `uri` adds Data URI Base64, implements RFC-2397. +- `uri` module now implements RFC-2397. - Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) to the `dom` module for the JavaScript target. - The default hash for `Ordinal` has changed to something more bit-scrambling. @@ -43,8 +43,8 @@ due to the differing semantics between operating systems. `asyncdispatch.setInheritable`, `system.setInheritable` and - `nativesockets.setInheritable` is also introduced for setting file handle or - socket inheritance. Not all platform have these `proc`s defined. + `nativesockets.setInheritable` are also introduced for setting file handle or + socket inheritance. Not all platforms have these `proc`s defined. - The file descriptors created for internal bookkeeping by `ioselector_kqueue` and `ioselector_epoll` will no longer be leaked to child processes. @@ -52,7 +52,7 @@ - `strutils.formatFloat` with `precision = 0` has been restored to the version 1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)` is now `3.`, not `3`. -- `critbits` adds `commonPrefixLen`. +- Added `commonPrefixLen` to `critbits`. - `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results (see #13222); instead they now use `getCurrentDir` to resolve those cases, @@ -76,18 +76,18 @@ - Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. -- `dollars.$` now works for unsigned ints with `nim js` +- `dollars.$` now works for unsigned ints with `nim js`. - Improvements to the `bitops` module, including bitslices, non-mutating versions of the original masking functions, `mask`/`masked`, and varargs support for `bitand`, `bitor`, and `bitxor`. - `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed - into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency + into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` for consistency with regular proc definitions (although you cannot use semicolons). Pragmas and using a name are now allowed on the lefthand side of `=>`. Here - is an aggregate example of these changes: + is an example of these changes: ```nim import sugar @@ -106,8 +106,8 @@ The proc `times.isInitialized` has been added which can be used to check if a `DateTime` has been initialized. -- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to - hangs if a process had both reads from stdin and writes (eg to stdout). +- Fix a bug where calling `close` on io streams in `osproc.startProcess` was a noop and led to + hangs if a process had both reads from stdin and writes (e.g. to stdout). - The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. - The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. @@ -129,37 +129,35 @@ - A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x`` was added. -- Added `rstgen.rstToLatex` convenience proc for `renderRstToOut` and `initRstGenerator` - with `outLatex` output. -- Added `os.normalizeExe`, e.g.: `koch` => `./koch`. -- `macros.newLit` now preserves named vs unnamed tuples; use `-d:nimHasWorkaround14720` - to keep old behavior. +- Added `rstgen.rstToLatex` a convenience proc for `renderRstToOut` and `initRstGenerator`. +- Added `os.normalizeExe`. +- `macros.newLit` now preserves named vs unnamed tuples. - Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. -- Added `typetraits.elementType` to get element type of an iterable. +- Added `typetraits.elementType` to get the element type of an iterable. - `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` -- Added `macros.extractDocCommentsAndRunnables` helper +- Added `macros.extractDocCommentsAndRunnables` helper. -- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now +- `strformat.fmt` and `strformat.&` support `specifier =`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`. -- deprecations: `os.existsDir` => `dirExists`, `os.existsFile` => `fileExists` +- Deprecations: instead of `os.existsDir` use `dirExists`, instead of `os.existsFile` use `fileExists`. -- Added `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +- Added the `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). - Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, because negative values will result in a new file being created for each logged line which doesn't make sense. -- Changed `log` in `logging` to use proper log level on JavaScript target, +- Changed `log` in `logging` to use proper log level for JavaScript, e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. - Tables, HashSets, SharedTables and deques don't require anymore that the passed initial size must be a power of two - this is done internally. Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. - `CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again. -- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`. -- Removed `sugar.distinctBase`, deprecated since `0.19`. -- Export `asyncdispatch.PDispatcher.handles` so that an external library can register them. + `CountTable.inc` takes `val: int` again not `val: Positive`; i.e. it can "count down" again. +- Removed deprecated symbols from `macros` module, some of which were deprecated already in `0.15`. +- Removed `sugar.distinctBase`, deprecated since `0.19`. Use `typetraits.distinctBase`. +- `asyncdispatch.PDispatcher.handles` is exported so that an external low-level libraries can access it. -- `std/with`, `sugar.dup` now support object field assignment expression: +- `std/with`, `sugar.dup` now support object field assignment expressions: ```nim import std/with @@ -195,9 +193,9 @@ - Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. -- Added `readLines(p: Process)` to `osproc` module for `startProcess` convenience. +- Added `readLines(p: Process)` to `osproc`. -- Added the below `to` procs for collections. The usage is similar to procs such as +- Added the below `toX` procs for collections. The usage is similar to procs such as `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the respective empty collection and add items manually. * `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of @@ -209,7 +207,7 @@ - Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval at which progress callbacks are called. -- Added `os.copyFileToDir` +- Added `os.copyFileToDir`. ## Language changes @@ -217,20 +215,20 @@ `wasMoved` calls where needed. - The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there is no need to update your code. This change was backported to 1.2 too so you can use the - more readability `=copy` without loss of compatibility. + more readable `=copy` without loss of compatibility. - In the newruntime it is now allowed to assign to the discriminator field - without restrictions as long as case object doesn't have custom destructor. + without restrictions as long as the case object doesn't have a custom destructor. The discriminator value doesn't have to be a constant either. If you have a custom destructor for a case object and you do want to freely assign discriminator - fields, it is recommended to refactor object into 2 objects like this: + fields, it is recommended to refactor the object into 2 objects like this: ```nim type MyObj = object case kind: bool - of true: y: ptr UncheckedArray[float] - of false: z: seq[int] + of true: y: ptr UncheckedArray[float] + of false: z: seq[int] proc `=destroy`(x: MyObj) = if x.kind and x.y != nil: @@ -251,10 +249,10 @@ deallocShared(x.val) ``` - `getImpl` on enum type symbols now returns field syms instead of idents. This helps - with writing typed macros. Old behavior for backwards compatibility can be restored + with writing typed macros. The old behavior for backwards compatibility can be restored with `--useVersion:1.0`. - The typed AST for proc headers will now have the arguments be syms instead of idents. - This helps with writing typed macros. Old behaviour for backwards compatibility can + This helps with writing typed macros. The old behaviour for backwards compatibility can be restored with `--useVersion:1.0`. - ``let`` statements can now be used without a value if declared with ``importc``/``importcpp``/``importjs``/``importobjc``. @@ -262,52 +260,46 @@ - Exceptions inheriting from `system.Defect` are no longer tracked with the `.raises: []` exception tracking mechanism. This is more consistent with the built-in operations. The following always used to compile (and still does): - -```nim - -proc mydiv(a, b): int {.raises: [].} = - a div b # can raise an DivByZeroDefect - -``` + ```nim + proc mydiv(a, b): int {.raises: [].} = + a div b # can raise an DivByZeroDefect + ``` Now also this compiles: - -```nim - -proc mydiv(a, b): int {.raises: [].} = - if b == 0: raise newException(DivByZeroDefect, "division by zero") - else: result = a div b - -``` + ```nim + proc mydiv(a, b): int {.raises: [].} = + if b == 0: raise newException(DivByZeroDefect, "division by zero") + else: result = a div b + ``` The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. - Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes. -- Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. -- Removed `strutils.isNilOrWhitespace`, was deprecated. -- Removed `sharedtables.initSharedTable`, was deprecated and produces undefined behavior. -- Removed `asyncdispatch.newAsyncNativeSocket`, was deprecated since `0.18`. -- Removed `dom.releaseEvents` and `dom.captureEvents`, was deprecated. +- Deprecated the `{.unroll.}` pragma, because it was always ignored by the compiler anyway. +- Removed the deprecated `strutils.isNilOrWhitespace`. +- Removed the deprecated `sharedtables.initSharedTable`. +- Removed the deprecated `asyncdispatch.newAsyncNativeSocket`. +- Removed the deprecated `dom.releaseEvents` and `dom.captureEvents`. - Removed `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. - There is a new experimental feature called "strictFuncs" which makes the definition of - `.noSideEffect` stricter. [See](manual_experimental.html#stricts-funcs) + `.noSideEffect` stricter. [See here](manual_experimental.html#stricts-funcs) for more information. - "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer an experimental feature. In other words, you don't have to write pragma `{.experimental: "forLoopMacros".}` if you want to use them. -- Added a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased +- Added the ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased performance this keyword can enable. -- `items` no longer compiles with enum with holes as its behavior was error prone, see #14004 +- `items` no longer compiles with enums with holes as its behavior was error prone, see #14004. - `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via `--deepcopy:on`. -- Added a `std/effecttraits` module for introspection of the inferred effects. +- Added the `std/effecttraits` module for introspection of the inferred effects. We hope this enables `async` macros that are precise about the possible exceptions that can be raised. - The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be @@ -320,11 +312,10 @@ proc mydiv(a, b): int {.raises: [].} = - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. - The `define` and `undef` pragmas have been de-deprecated. - New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache` - so that output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to - avoid recompiling when sources don't change. This is now the preferred way to - run tests, avoiding the usual pain of clobbering your repo with binaries or - using tricky gitignore rules on posix. Example: - ```nim + so that the output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to + avoid recompilations when sources don't change. + Example: + ```bash nim r compiler/nim.nim --help # only compiled the first time echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too nim r compiler/nim.nim --fullhelp # no recompilation @@ -334,20 +325,18 @@ proc mydiv(a, b): int {.raises: [].} = (likewise with other hints and warnings), which is consistent with all other bool flags. (since 1.3.3). - `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`. -- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) +- Added the new hint `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) was generated; this helps in particular when it's non obvious where it came from either because multiple locations generate the same message, or because the message involves runtime formatting. -- new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change backend; can be - used with any command (eg nim r, doc, check etc); safe to re-assign. -- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, +- Added the new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change the backend; can be + used with any command (e.g. nim r, doc, check etc); safe to re-assign. +- Added the new flag `--doccmd:cmd` to pass additional flags for runnableExamples, e.g.: `--doccmd:-d:foo --threads` use `--doccmd:skip` to skip runnableExamples and rst test snippets. -- new flag `--usenimcache` to output to nimcache (whatever it resolves to after - all commands are processed) - and avoids polluting both $pwd and $projectdir. It can be used with any command. +- Added the new flag `--usenimcache` to output binary files to nimcache. - `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override - how an example is compiled and run, for example to change backend or compile only. + how an example is compiled and run, for example to change the backend. - `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified (with or without `--project`); passing `--project` now automatically generates an index and enables search. @@ -355,7 +344,7 @@ proc mydiv(a, b): int {.raises: [].} = - Removed the `--oldNewlines` switch. - Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. - Removed the `--oldast` switch. -- Removed the `--oldgensym` switch +- Removed the `--oldgensym` switch. - `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is now "typed" instead of "stmt". - Sink inference is now disabled per default and has to enabled explicitly via @@ -366,9 +355,9 @@ proc mydiv(a, b): int {.raises: [].} = ## Tool changes -- `nimsuggest` will now return both the forward declaration and the +- `nimsuggest` now returns both the forward declaration and the implementation location upon a `def` query. Previously the behavior was - just to return the forward declaration. + to return the forward declaration only. ## Bugfixes @@ -673,7 +662,6 @@ proc mydiv(a, b): int {.raises: [].} = ([#10465](https://github.com/nim-lang/Nim/issues/10465)) - Fixed "Same warning printed 3 times" ([#11009](https://github.com/nim-lang/Nim/issues/11009)) -Was unsure about: " add testcase for #4668 (#14946)" - Fixed "type alias for generic typeclass doesn't work" ([#4668](https://github.com/nim-lang/Nim/issues/4668)) - Fixed "exceptions:goto Bug devel codegen lvalue NIM_FALSE=NIM_FALSE" From 66cd9c2e57de027781a11f4434112ab0e5cfea7b Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 16 Oct 2020 18:03:01 +0200 Subject: [PATCH 1268/4254] Fix #15599 (#15601) * Fix #15599 * Add test --- compiler/semmagic.nim | 2 +- tests/arc/tarcmisc.nim | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 5cd7b28b0..cffd58b92 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -527,7 +527,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}: localError(c.config, n.info, "finalizer must be a direct reference to a proc") elif optTinyRtti in c.config.globalOptions: - let fin = if n[^1].kind == nkLambda: n[^1][namePos].sym + let fin = if n[^1].kind in {nkLambda, nkDo}: n[^1][namePos].sym else: n[^1].sym # check if we converted this finalizer into a destructor already: let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef})) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index b53d49df8..8d857921e 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -26,6 +26,7 @@ new line after - @['a'] finalizer aaaaa hello +ok closed destroying variable: 20 destroying variable: 10 @@ -377,4 +378,15 @@ proc text_parser(xml: var XmlParser) = doAssert(test_passed) text_parser(xml) -text_parser(xml2) \ No newline at end of file +text_parser(xml2) + +# bug #15599 +type + PixelBuffer = ref object + +proc newPixelBuffer(): PixelBuffer = + new(result) do (buffer: PixelBuffer): + echo "ok" + +discard newPixelBuffer() + From b16b2eb06fa09b22ab50b3bd2703fe79c0ca4fc6 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Sat, 17 Oct 2020 18:30:12 +0000 Subject: [PATCH 1269/4254] document that Nim executable must be included (#15611) --- doc/testament.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/testament.rst b/doc/testament.rst index 82dfb75bd..d515ac2cb 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -94,7 +94,7 @@ Example "template" **to edit** and write a Testament unittest: valgrind: false # Can use Valgrind to check for memory leaks, or not (Linux 64Bit only). - cmd: "c -r $file" # Command the test should use to run. + cmd: "nim c -r $file" # Command the test should use to run. maxcodesize: 666 # Maximum generated temporary intermediate code file size for the test. From ba2a477e648513fac0183ae77990dfe16f890960 Mon Sep 17 00:00:00 2001 From: Euan Date: Sun, 18 Oct 2020 10:26:36 +0100 Subject: [PATCH 1270/4254] Fix FreeBSD build failures (#15613) The FreeBSD is/was failing, due to a conflict with installing Git. Git is guaranteed to be in the base image, so this removes that package from the package list. It also reverts back to the built-in `packages` tag since it's officially supported. Should the build fail in the future, the best place to go is the #sr.ht channel on freenode. --- .builds/freebsd.yml | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index ef2e8f44d..6898a80fd 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,25 +1,19 @@ # see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd image: freebsd/latest - -# packages: -# - databases/sqlite3 -# - devel/boehm-gc-threaded -# - devel/pcre -# - devel/sdl20 -# - devel/sfml -# - www/node -# - devel/gmake -# - devel/git +packages: +- databases/sqlite3 +- devel/boehm-gc-threaded +- devel/pcre +- devel/sdl20 +- devel/sfml +- www/node +- devel/gmake sources: - https://github.com/nim-lang/Nim environment: CC: /usr/bin/clang tasks: - setup: | - # workaround https://github.com/timotheecour/Nim/issues/76 - sudo pkg update -q -f - sudo pkg install -y -q databases/sqlite3 devel/boehm-gc-threaded devel/pcre \ - devel/sdl20 devel/sfml www/node devel/gmake devel/git cd Nim git clone --depth 1 -q https://github.com/nim-lang/csources.git gmake -C csources -j $(sysctl -n hw.ncpu) From 78cbb52fa01d6c73307fe276bdf7d4c34d7a556c Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Sun, 18 Oct 2020 16:57:13 +0000 Subject: [PATCH 1271/4254] add tests for #15584 (#15619) * add test for #15584 * Rename userlocks.nim to trlocks.nim * add bug comment * improve cmd * reference bugfix, not bug * add test that runs rlocks * disallow joining joining with other test cases (e.g., a test case that invokes `RLock.initRLock()`) may cause this test to compile, when the goal is to test if these lines can be compiled in isolation --- tests/stdlib/trlocks.nim | 14 ++++++++++++++ tests/stdlib/tuserlocks.nim | 13 +++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/stdlib/trlocks.nim create mode 100644 tests/stdlib/tuserlocks.nim diff --git a/tests/stdlib/trlocks.nim b/tests/stdlib/trlocks.nim new file mode 100644 index 000000000..135d9b028 --- /dev/null +++ b/tests/stdlib/trlocks.nim @@ -0,0 +1,14 @@ +discard """ + action: "compile" + # Disallow joining to ensure it can compile in isolation. + # See #15584 + joinable: false + cmd: "nim $target --threads:on $options $file" +""" + +# bugfix #15584 + +import rlocks + +var r: RLock +r.initRLock() diff --git a/tests/stdlib/tuserlocks.nim b/tests/stdlib/tuserlocks.nim new file mode 100644 index 000000000..f6eafa05d --- /dev/null +++ b/tests/stdlib/tuserlocks.nim @@ -0,0 +1,13 @@ +discard """ + cmd: "nim $target --threads:on $options $file" +""" + +import rlocks + +var r: RLock +r.initRLock() +doAssert r.tryAcquire() +doAssert r.tryAcquire() +r.release() +r.release() +r.deinitRLock() From 9c34d6ee09e73b200d2bd7fc40ba727c3f9773f6 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 19 Oct 2020 13:58:33 +0300 Subject: [PATCH 1272/4254] Add discord to the README (#15634) --- readme.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 4ef10f231..0ccfc8fa9 100644 --- a/readme.md +++ b/readme.md @@ -9,6 +9,7 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( ## Community [![Join the IRC chat][badge-nim-irc]][nim-irc] +[![Join the Discord server][badge-nim-discord]][nim-discord] [![Join the Gitter chat][badge-nim-gitter]][nim-gitter] [![Get help][badge-nim-forum-gethelp]][nim-forum] [![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest] @@ -17,10 +18,12 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( * The [forum][nim-forum] - the best place to ask questions and to discuss Nim. * [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time. Also where most development decisions get made. +* [Discord][nim-discord] - an additional place to discuss Nim in real-time. Most + channels there are bridged to IRC. * [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There is a bridge between Gitter and the IRC channel. * [Telegram][nim-telegram] - an additional place to discuss Nim in real-time. There - is the official Telegram channel. + is the official Telegram channel. Not bridged to IRC. * [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related topics that includes posts about Nim. * [Github Wiki][nim-wiki] - Misc user-contributed content. @@ -211,6 +214,7 @@ Copyright © 2006-2020 Andreas Rumpf, all rights reserved. [nim-twitter]: https://twitter.com/nim_lang [nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim-lang [nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim-lang?sort=newest&pageSize=15 +[nim-discord]: https://discord.gg/nim [nim-gitter]: https://gitter.im/nim-lang/Nim [nim-telegram]: https://t.me/nim_lang [nim-bountysource]: https://www.bountysource.com/teams/nim @@ -220,6 +224,7 @@ Copyright © 2006-2020 Andreas Rumpf, all rights reserved. [csources-repo]: https://github.com/nim-lang/csources [badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square [badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square +[badge-nim-discord]: https://img.shields.io/discord/371759389889003530?label=discord&logo=discord&logoColor=gold&style=flat-square [badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square [badge-nim-forum-gethelp]: https://img.shields.io/badge/Forum-get%20help-4eb899.svg?style=flat-square [badge-nim-twitter]: https://img.shields.io/twitter/follow/nim_lang.svg?style=social From 528069a9678fb7f9691ea78e5fd4eec905767b78 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 19 Oct 2020 14:02:51 +0300 Subject: [PATCH 1273/4254] Change discord's badge color to be consistent with other badges --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0ccfc8fa9..8fcf4d2bb 100644 --- a/readme.md +++ b/readme.md @@ -224,7 +224,7 @@ Copyright © 2006-2020 Andreas Rumpf, all rights reserved. [csources-repo]: https://github.com/nim-lang/csources [badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square [badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square -[badge-nim-discord]: https://img.shields.io/discord/371759389889003530?label=discord&logo=discord&logoColor=gold&style=flat-square +[badge-nim-discord]: https://img.shields.io/discord/371759389889003530?color=blue&label=discord&logo=discord&logoColor=gold&style=flat-square [badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square [badge-nim-forum-gethelp]: https://img.shields.io/badge/Forum-get%20help-4eb899.svg?style=flat-square [badge-nim-twitter]: https://img.shields.io/twitter/follow/nim_lang.svg?style=social From d22ab0fb9688f4322ba438af88927b414f3a898c Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 19 Oct 2020 14:16:56 +0300 Subject: [PATCH 1274/4254] Add tests to #15363 (#15633) --- tests/vm/tvmmisc.nim | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 7ac75c7c5..73faac495 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -204,3 +204,29 @@ block: # bug #13081 doAssert j1.x1 == 12 static: doAssert j1.x1 == 12 + +# bug #15363 +import sequtils + +block: + func identity(a: bool): bool = a + + var a: seq[bool] = static: + newSeq[bool](0).mapIt(it) # segfaults + var b: seq[bool] = static: + newSeq[bool](0).filterIt(it) # does not segfault + var c: seq[bool] = static: + newSeq[bool](0).map(identity) # does not segfault + var d: seq[bool] = static: + newSeq[bool](0).map(proc (a: bool): bool = false) # segfaults + var e: seq[bool] = static: + newSeq[bool](0).filter(identity) # does not segfault + var f: seq[bool] = static: + newSeq[bool](0).filter(proc (a: bool): bool = false) # segfaults + + doAssert a == @[] + doAssert b == @[] + doAssert c == @[] + doAssert d == @[] + doAssert e == @[] + doAssert f == @[] From 04f8fcfbd06e72eb45f36e487a110316370e47c1 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 19 Oct 2020 13:13:26 +0100 Subject: [PATCH 1275/4254] Tables, use sink val arguments more actively (#15625) --- compiler/sempass2.nim | 39 +++++++++++++++--------------- lib/pure/collections/tableimpl.nim | 2 +- lib/pure/collections/tables.nim | 18 +++++++------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index aa04f7451..352871412 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -514,25 +514,26 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = #elif n.kind in nkSymChoices: # echo "came here" let paramType = paramType.skipTypesOrNil(abstractInst) - if paramType != nil and tfNotNil in paramType.flags and - n.typ != nil and tfNotNil notin n.typ.flags: - if isAddrNode(n): - # addr(x[]) can't be proven, but addr(x) can: - if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return - elif (n.kind == nkSym and n.sym.kind in routineKinds) or - (n.kind in procDefs+{nkObjConstr, nkBracket, nkClosure, nkStrLit..nkTripleStrLit}) or - (n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mArrToSeq) or - n.typ.kind == tyTypeDesc: - # 'p' is not nil obviously: - return - case impliesNotNil(tracked.guards, n) - of impUnknown: - message(tracked.config, n.info, errGenerated, - "cannot prove '$1' is not nil" % n.renderTree) - of impNo: - message(tracked.config, n.info, errGenerated, - "'$1' is provably nil" % n.renderTree) - of impYes: discard + if paramType != nil and tfNotNil in paramType.flags and n.typ != nil: + let ntyp = n.typ.skipTypesOrNil({tyVar, tyLent, tySink}) + if ntyp != nil and tfNotNil notin ntyp.flags: + if isAddrNode(n): + # addr(x[]) can't be proven, but addr(x) can: + if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return + elif (n.kind == nkSym and n.sym.kind in routineKinds) or + (n.kind in procDefs+{nkObjConstr, nkBracket, nkClosure, nkStrLit..nkTripleStrLit}) or + (n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mArrToSeq) or + n.typ.kind == tyTypeDesc: + # 'p' is not nil obviously: + return + case impliesNotNil(tracked.guards, n) + of impUnknown: + message(tracked.config, n.info, errGenerated, + "cannot prove '$1' is not nil" % n.renderTree) + of impNo: + message(tracked.config, n.info, errGenerated, + "'$1' is provably nil" % n.renderTree) + of impYes: discard proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) = addRaiseEffect(tracked, createRaise(tracked.graph, n), nil) diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index df9cb7517..c66da513c 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -27,7 +27,7 @@ proc rawGetDeep[X, A](t: X, key: A, hc: var Hash): int {.inline.} = rawGetDeepImpl() proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B], - key: A, val: B, hc: Hash, h: Hash) = + key: A, val: sink B, hc: Hash, h: Hash) = rawInsertImpl() template checkIfInitialized() = diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 85440bd2b..bd46bdd27 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -300,7 +300,7 @@ proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] = b = initTable[char, seq[int]]() initImpl(result, initialSize) -proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: var Table[A, B], key: A, val: sink B) = ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: @@ -484,7 +484,7 @@ proc len*[A, B](t: Table[A, B]): int = result = t.counter -proc add*[A, B](t: var Table[A, B], key: A, val: B) {.deprecated: +proc add*[A, B](t: var Table[A, B], key: A, val: sink B) {.deprecated: "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## @@ -839,7 +839,7 @@ proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = result = t[][key] -proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: sink B) = ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: @@ -968,7 +968,7 @@ proc len*[A, B](t: TableRef[A, B]): int = result = t.counter -proc add*[A, B](t: TableRef[A, B], key: A, val: B) {.deprecated: +proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated: "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## @@ -1217,7 +1217,7 @@ proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int = proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], - key: A, val: B, hc: Hash, h: Hash) = + key: A, val: sink B, hc: Hash, h: Hash) = rawInsertImpl() data[h].next = -1 if t.first < 0: t.first = h @@ -1268,7 +1268,7 @@ proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A, b = initOrderedTable[char, seq[int]]() initImpl(result, initialSize) -proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) = ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: @@ -1455,7 +1455,7 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} = result = t.counter -proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) {.deprecated: +proc add*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) {.deprecated: "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## @@ -1810,7 +1810,7 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = echo a['z'] result = t[][key] -proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) = ## Inserts a ``(key, value)`` pair into ``t``. ## ## See also: @@ -1939,7 +1939,7 @@ proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} = result = t.counter -proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) {.deprecated: +proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) {.deprecated: "Deprecated since v1.4; it was more confusing than useful, use `[]=`".} = ## Puts a new ``(key, value)`` pair into ``t`` even if ``t[key]`` already exists. ## From 7526472a6ed56db11ec141ca4898de467b62696b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Oct 2020 05:14:43 -0700 Subject: [PATCH 1276/4254] add a section on naming new stdlib module names (#15590) --- doc/contributing.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/contributing.rst b/doc/contributing.rst index a4baaef05..9c567cb0b 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -555,3 +555,17 @@ to existing modules is acceptable. For two reasons: Newly introduced issues have to be balanced against motivating new people. We know where to find perfectly designed pieces of software that have no bugs -- these are the systems that nobody uses. + +Conventions +----------- +1. New stdlib modules should go under `Nim/lib/std/`. The rationale is to require +users to import via `import std/foo` instead of `import foo`, which would cause +potential conflicts with nimble packages. Note that this still applies for new modules +in existing logical directories, eg: +use `lib/std/collections/foo.nim`, not `lib/pure/collections/foo.nim`. + +2. New module names should prefer plural form whenever possible, eg: +`std/sums.nim` instead of `std/sum.nim`. In particular, this reduces chances of conflicts +between module name and the symbols it defines. Furthermore, is should use `snake_case` +and not use capital letters, which cause issues when going from an OS without case +sensitivity to an OS without it. From 67afe72e9caa8df435738c9011135d7053e01eb2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Oct 2020 05:49:06 -0700 Subject: [PATCH 1277/4254] contributing docs: add instructions for economically restarting failed CI jobs, debugging failed CI (#15576) * contributing docs: add instructions for economically restarting failed CI jobs, debugging failed CI * fixup --- doc/contributing.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 9c567cb0b..cc71a62f3 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -444,12 +444,31 @@ Continuous Integration (CI) `_ and `Travis `_. -2. Consider enabling CI (travis and appveyor) in your own Nim fork, and +2. Consider enabling CI (azure, github actions and builds.sr.ht) in your own Nim fork, and waiting for CI to be green in that fork (fixing bugs as needed) before opening your PR in original Nim repo, so as to reduce CI congestion. Same applies for updates on a PR: you can test commits on a separate private branch before updating the main PR. +Debugging CI failures, flaky tests, etc +--------------------------------------- + +1. First check the CI logs and search for `FAIL` to find why CI failed; if the + failure seems related to your PR, try to fix the code instead of restarting CI. + +2. If CI failure seems unrelated to your PR, it could be caused by a flaky test. + File a bug for it if it isn't already reported. A PR push (or opening/closing PR) + will re-trigger all CI jobs (even successful ones, which can be wasteful). Instead, + follow these instructions to only restart the jobs that failed: + + * Azure: if on your own fork, it's possible from inside azure console + (eg `dev.azure.com/username/username/_build/results?buildId=1430&view=results`) via `rerun failed jobs` on top. + If either on you own fork or in Nim repo, it's possible from inside github UI + under checks tab, see https://github.com/timotheecour/Nim/issues/211#issuecomment-629751569 + * github actions: under "Checks" tab, click "Re-run jobs" in the right. + * builds.sr.ht: create a sourcehut account so you can restart a PR job as illustrated + + Code reviews ------------ From 833035bacd91c2cf16ea006b64bf996e87eac75d Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 19 Oct 2020 13:50:06 +0100 Subject: [PATCH 1278/4254] arc allocation method aligned (#15588) * progress * fix typo --- compiler/ccgexprs.nim | 24 ++++++++++++++------- lib/system/arc.nim | 8 ------- lib/system/assign.nim | 4 +--- lib/system/cellseqs_v2.nim | 16 +++++++------- lib/system/memalloc.nim | 2 +- lib/system/seqs_v2.nim | 15 ++++++++++--- lib/system/seqs_v2_reimpl.nim | 7 ++++++ lib/system/strs_v2.nim | 40 ++++++++++++++++++++++++++++------- lib/system/widestrs.nim | 10 +++++++-- 9 files changed, 85 insertions(+), 41 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c1469fa60..004b8f41e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2180,17 +2180,25 @@ proc genDestroy(p: BProc; n: PNode) = of tyString: var a: TLoc initLocExpr(p, arg, a) - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #deallocShared($1.p);$n" & - "}$n", - [rdLoc(a)]) + if optThreads in p.config.globalOptions: + linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & + " #deallocShared($1.p);$n" & + "}$n", [rdLoc(a)]) + else: + linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & + " #dealloc($1.p);$n" & + "}$n", [rdLoc(a)]) of tySequence: var a: TLoc initLocExpr(p, arg, a) - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #deallocShared($1.p);$n" & - "}$n", - [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) + if optThreads in p.config.globalOptions: + linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & + " #deallocShared($1.p);$n" & + "}$n", [rdLoc(a)]) + else: + linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & + " #dealloc($1.p);$n" & + "}$n", [rdLoc(a)]) else: discard "nothing to do" else: let t = n[1].typ.skipTypes(abstractVar) diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 3e24c2506..46579eaef 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -79,10 +79,6 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = let s = size + sizeof(RefHeader) when defined(nimscript): discard - elif defined(useMalloc): - var orig = c_malloc(cuint s) - nimZeroMem(orig, s) - result = orig +! sizeof(RefHeader) elif compileOption("threads"): result = allocShared0(s) +! sizeof(RefHeader) else: @@ -102,8 +98,6 @@ proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = let s = size + sizeof(RefHeader) when defined(nimscript): discard - elif defined(useMalloc): - var orig = cast[ptr RefHeader](c_malloc(cuint s)) elif compileOption("threads"): var orig = cast[ptr RefHeader](allocShared(s)) else: @@ -171,8 +165,6 @@ proc nimRawDispose(p: pointer) {.compilerRtl.} = # we do NOT really free the memory here in order to reliably detect use-after-frees if freedCells.data == nil: init(freedCells) freedCells.incl head(p) - elif defined(useMalloc): - c_free(p -! sizeof(RefHeader)) elif compileOption("threads"): deallocShared(p -! sizeof(RefHeader)) else: diff --git a/lib/system/assign.nim b/lib/system/assign.nim index d332124cd..a809fa423 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -248,9 +248,7 @@ proc genericReset(dest: pointer, mt: PNimType) = unsureAsgnRef(cast[PPointer](dest), nil) of tySequence: when defined(nimSeqsV2): - var s = cast[ptr NimSeqV2Reimpl](dest) - if s.p != nil: - deallocShared(s.p) + frees(cast[ptr NimSeqV2Reimpl](dest)[]) zeroMem(dest, mt.size) else: unsureAsgnRef(cast[PPointer](dest), nil) diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim index fdd9e3099..59cf67dcd 100644 --- a/lib/system/cellseqs_v2.nim +++ b/lib/system/cellseqs_v2.nim @@ -19,13 +19,13 @@ type proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} = if s.len >= s.cap: s.cap = s.cap * 3 div 2 - when defined(useMalloc): - var d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + when compileOption("threads"): + var d = cast[CellArray](allocShared(uint(s.cap * sizeof(CellTuple)))) else: var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) copyMem(d, s.d, s.len * sizeof(CellTuple)) - when defined(useMalloc): - c_free(s.d) + when compileOption("threads"): + deallocShared(s.d) else: dealloc(s.d) s.d = d @@ -36,15 +36,15 @@ proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} = proc init(s: var CellSeq, cap: int = 1024) = s.len = 0 s.cap = cap - when defined(useMalloc): - s.d = cast[CellArray](c_malloc(uint(s.cap * sizeof(CellTuple)))) + when compileOption("threads"): + s.d = cast[CellArray](allocShared(uint(s.cap * sizeof(CellTuple)))) else: s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) proc deinit(s: var CellSeq) = if s.d != nil: - when defined(useMalloc): - c_free(s.d) + when compileOption("threads"): + deallocShared(s.d) else: dealloc(s.d) s.d = nil diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index 178d199b8..142762fe7 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -174,7 +174,7 @@ when hasAlloc and not defined(js): ## from a shared heap. cast[ptr T](realloc(p, T.sizeof * newSize)) - template dealloc*(p: pointer) = + proc dealloc*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = ## Frees the memory allocated with ``alloc``, ``alloc0`` or ## ``realloc``. ## diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 111299fff..d83a0009a 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -35,7 +35,10 @@ proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises # we have to use type erasure here as Nim does not support generic # compilerProcs. Oh well, this will all be inlined anyway. if cap > 0: - var p = cast[ptr NimSeqPayloadBase](allocShared0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize)) + when compileOption("threads"): + var p = cast[ptr NimSeqPayloadBase](allocShared0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize)) + else: + var p = cast[ptr NimSeqPayloadBase](alloc0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize)) p.cap = cap result = p else: @@ -62,14 +65,20 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin let oldCap = p.cap and not strlitFlag let newCap = max(resize(oldCap), len+addlen) if (p.cap and strlitFlag) == strlitFlag: - var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * newCap)) + when compileOption("threads"): + var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * newCap)) + else: + var q = cast[ptr NimSeqPayloadBase](alloc0(headerSize + elemSize * newCap)) copyMem(q +! headerSize, p +! headerSize, len * elemSize) q.cap = newCap result = q else: let oldSize = headerSize + elemSize * oldCap let newSize = headerSize + elemSize * newCap - var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize)) + when compileOption("threads"): + var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize)) + else: + var q = cast[ptr NimSeqPayloadBase](realloc0(p, oldSize, newSize)) q.cap = newCap result = q diff --git a/lib/system/seqs_v2_reimpl.nim b/lib/system/seqs_v2_reimpl.nim index 750f78c0d..09b7e7ac4 100644 --- a/lib/system/seqs_v2_reimpl.nim +++ b/lib/system/seqs_v2_reimpl.nim @@ -15,3 +15,10 @@ type NimSeqV2Reimpl = object len: int p: ptr NimSeqPayloadReimpl + +template frees(s: NimSeqV2Reimpl) = + if s.p != nil and (s.p.cap and strlitFlag) != strlitFlag: + when compileOption("threads"): + deallocShared(s.p) + else: + dealloc(s.p) \ No newline at end of file diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 57fdd5ee1..f51791da2 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -29,7 +29,10 @@ template contentSize(cap): int = cap + 1 + sizeof(NimStrPayloadBase) template frees(s) = if not isLiteral(s): - deallocShared(s.p) + when compileOption("threads"): + deallocShared(s.p) + else: + dealloc(s.p) proc resize(old: int): int {.inline.} = if old <= 0: result = 4 @@ -40,7 +43,10 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = if isLiteral(s): let oldP = s.p # can't mutate a literal, so we need a fresh copy here: - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen))) + when compileOption("threads"): + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen))) + else: + s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len + addlen))) s.p.cap = s.len + addlen if s.len > 0: # we are about to append, so there is no need to copy the \0 terminator: @@ -49,7 +55,10 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = let oldCap = s.p.cap and not strlitFlag if s.len + addlen > oldCap: let newCap = max(s.len + addlen, resize(oldCap)) - s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap))) + when compileOption("threads"): + s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap))) + else: + s.p = cast[ptr NimStrPayload](realloc0(s.p, contentSize(oldCap), contentSize(newCap))) s.p.cap = newCap proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inline.} = @@ -63,7 +72,10 @@ proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} = if len <= 0: result = NimStringV2(len: 0, p: nil) else: - var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) + when compileOption("threads"): + var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) + else: + var p = cast[ptr NimStrPayload](alloc0(contentSize(len))) p.cap = len if len > 0: # we are about to append, so there is no need to copy the \0 terminator: @@ -94,7 +106,10 @@ proc rawNewString(space: int): NimStringV2 {.compilerproc.} = if space <= 0: result = NimStringV2(len: 0, p: nil) else: - var p = cast[ptr NimStrPayload](allocShared0(contentSize(space))) + when compileOption("threads"): + var p = cast[ptr NimStrPayload](allocShared0(contentSize(space))) + else: + var p = cast[ptr NimStrPayload](alloc0(contentSize(space))) p.cap = space result = NimStringV2(len: 0, p: p) @@ -102,7 +117,10 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} = if len <= 0: result = NimStringV2(len: 0, p: nil) else: - var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) + when compileOption("threads"): + var p = cast[ptr NimStrPayload](allocShared0(contentSize(len))) + else: + var p = cast[ptr NimStrPayload](alloc0(contentSize(len))) p.cap = len result = NimStringV2(len: len, p: p) @@ -128,7 +146,10 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = # 'let y = newStringOfCap(); var x = y' # on the other hand... These get turned into moves now. frees(a) - a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len))) + when compileOption("threads"): + a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len))) + else: + a.p = cast[ptr NimStrPayload](alloc0(contentSize(b.len))) a.p.cap = b.len a.len = b.len copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1) @@ -136,7 +157,10 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = proc nimPrepareStrMutationImpl(s: var NimStringV2) = let oldP = s.p # can't mutate a literal, so we need a fresh copy here: - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len))) + when compileOption("threads"): + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len))) + else: + s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len))) s.p.cap = s.len copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 83c11eb79..6d54bce9b 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -27,7 +27,10 @@ when defined(nimv2): proc `=destroy`(a: var WideCStringObj) = if a.data != nil: - deallocShared(a.data) + when compileOption("threads"): + deallocShared(a.data) + else: + dealloc(a.data) proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.} @@ -37,7 +40,10 @@ when defined(nimv2): proc createWide(a: var WideCStringObj; bytes: int) = a.bytes = bytes - a.data = cast[typeof(a.data)](allocShared0(bytes)) + when compileOption("threads"): + a.data = cast[typeof(a.data)](allocShared0(bytes)) + else: + a.data = cast[typeof(a.data)](alloc0(bytes)) template `[]`*(a: WideCStringObj; idx: int): Utf16Char = a.data[idx] template `[]=`*(a: WideCStringObj; idx: int; val: Utf16Char) = a.data[idx] = val From 436e1fa5b13d0a5b667a800b1716e5139f1c20fe Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Mon, 19 Oct 2020 20:25:43 +0000 Subject: [PATCH 1279/4254] fix #15631 (#15632) * trigger valgrind failure on memory leak * remove non-malloc tests * remove ORC test is redundant because we already have an ARC test * only run valgrind tests on 64-bit Linux * disable freebsd and openbsd * Remove tleak_refc As to not test implementation details (or bug) * Fix test failures by removing redundant test Since this tests/shoulfail/tvalgrind.nim was specified here to fail this test itself fails since it will be skipped on non-linux CI * Remove test, reason detailed in the previous commit * Remove redundant disables * Revert removing disables * Add and use valgrind: leaks * Fix Co-authored-by: Clyybber Co-authored-by: n5m --- doc/testament.rst | 5 +++++ testament/specs.nim | 14 +++++++++----- testament/testament.nim | 7 +++++-- tests/arc/tasyncorc.nim | 2 +- tests/arc/thavlak_orc_stress.nim | 2 +- tests/valgrind/tleak_arc.nim | 14 ++++++++++++++ 6 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 tests/valgrind/tleak_arc.nim diff --git a/doc/testament.rst b/doc/testament.rst index d515ac2cb..1b2b71c18 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -103,6 +103,11 @@ Example "template" **to edit** and write a Testament unittest: target: "c js" # Targets to run the test into (C, C++, JavaScript, etc). disabled: "bsd" # Disable the test by condition, here BSD is disabled just as an example. + disabled: "win" # Can disable multiple OSes at once + disabled: "32bit" # ...or architectures + disabled: "i386" + disabled: "azure" # ...or pipeline runners + disabled: true # ...or can disable the test entirely """ assert true diff --git a/testament/specs.nim b/testament/specs.nim index e0b9cbeec..eaae598bb 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -43,7 +43,7 @@ type reFilesDiffer, # expected and given filenames differ reLinesDiffer, # expected and given line numbers differ reOutputsDiffer, - reExitcodesDiffer, + reExitcodesDiffer, # exit codes of program or of valgrind differ reTimeout, reInvalidPeg, reCodegenFailure, @@ -67,6 +67,9 @@ type msg*: string line*, col*: int + ValgrindSpec* = enum + disabled, enabled, leaking + TSpec* = object action*: TTestAction file*, cmd*: string @@ -92,7 +95,7 @@ type # whether this test can be batchable via `NIM_TESTAMENT_BATCH`; only very # few tests are not batchable; the ones that are not could be turned batchable # by making the dependencies explicit - useValgrind*: bool + useValgrind*: ValgrindSpec timeout*: float # in seconds, fractions possible, # but don't rely on much precision inlineErrors*: seq[InlineError] # line information to error message @@ -306,14 +309,15 @@ proc parseSpec*(filename: string): TSpec = result.unjoinable = not parseCfgBool(e.value) of "valgrind": when defined(linux) and sizeof(int) == 8: - result.useValgrind = parseCfgBool(e.value) + result.useValgrind = if e.value.normalize == "leaks": leaking + else: ValgrindSpec(parseCfgBool(e.value)) result.unjoinable = true - if result.useValgrind: + if result.useValgrind != disabled: result.outputCheck = ocSubstr else: # Windows lacks valgrind. Silly OS. # Valgrind only supports OSX <= 17.x - result.useValgrind = false + result.useValgrind = disabled of "disabled": case e.value.normalize of "y", "yes", "true", "1", "on": result.err = reDisabled diff --git a/testament/testament.nim b/testament/testament.nim index 4afafb645..8fead76ef 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -501,8 +501,11 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, args = concat(@[exeFile], args) else: exeCmd = exeFile.dup(normalizeExe) - if expected.useValgrind: - args = @["--error-exitcode=1"] & exeCmd & args + if expected.useValgrind != disabled: + var valgrindOptions = @["--error-exitcode=1"] + if expected.useValgrind != leaking: + valgrindOptions.add "--leak-check=yes" + args = valgrindOptions & exeCmd & args exeCmd = "valgrind" var (_, buf, exitCode) = execCmdEx2(exeCmd, args, input = expected.input) # Treat all failure codes from nodejs as 1. Older versions of nodejs used diff --git a/tests/arc/tasyncorc.nim b/tests/arc/tasyncorc.nim index 56b8909b1..63703b559 100644 --- a/tests/arc/tasyncorc.nim +++ b/tests/arc/tasyncorc.nim @@ -1,7 +1,7 @@ discard """ output: '''230000''' cmd: '''nim c --gc:orc -d:useMalloc $file''' - valgrind: "true" + valgrind: "leaks" """ # bug #14402 diff --git a/tests/arc/thavlak_orc_stress.nim b/tests/arc/thavlak_orc_stress.nim index 3c61f10ef..862e1a097 100644 --- a/tests/arc/thavlak_orc_stress.nim +++ b/tests/arc/thavlak_orc_stress.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --gc:orc -d:useMalloc -d:nimStressOrc $file" - valgrind: "true" + valgrind: "leaks" output: "done" """ diff --git a/tests/valgrind/tleak_arc.nim b/tests/valgrind/tleak_arc.nim new file mode 100644 index 000000000..8dea7c62a --- /dev/null +++ b/tests/valgrind/tleak_arc.nim @@ -0,0 +1,14 @@ +discard """ +valgrind: true +cmd: "nim $target --gc:arc -d:useMalloc $options $file" +exitcode: 1 +outputsub: " definitely lost: 7 bytes in 2 blocks" +disabled: "freebsd" +disabled: "macosx" +disabled: "openbsd" +disabled: "windows" +disabled: "32bit" +""" + +discard alloc(3) +discard alloc(4) From 0f4b1ed270a0f0c380122723474ec0d36c1a7e00 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 19 Oct 2020 22:39:50 +0200 Subject: [PATCH 1280/4254] Fix #15639 (#15640) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 7be35fed7..e34fdb4f4 100644 --- a/koch.nim +++ b/koch.nim @@ -15,7 +15,7 @@ const when not defined(windows): const - Z3StableCommit = "65de3f748a6812eecd7db7c478dcd5fc54424d368b" # the version of Z3 that DrNim uses + Z3StableCommit = "65de3f748a6812eecd7db7c478d5fc54424d368b" # the version of Z3 that DrNim uses when defined(gcc) and defined(windows): when defined(x86): From f20e485827df6df97b8396558b10d7c59ca1b7dc Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 20 Oct 2020 01:19:49 +0200 Subject: [PATCH 1281/4254] Fix commentOffsetA for doc comments (#15643) --- compiler/lexer.nim | 2 +- nimpretty/tests/expected/simple.nim | 5 +++++ nimpretty/tests/simple.nim | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 9b1dc642d..c15ecddfc 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -1042,7 +1042,7 @@ proc scanComment(L: var Lexer, tok: var Token) = tok.iNumber = 0 assert L.buf[pos+1] == '#' when defined(nimpretty): - tok.commentOffsetA = L.offsetBase + pos - 1 + tok.commentOffsetA = L.offsetBase + pos if L.buf[pos+2] == '[': skipMultiLineComment(L, tok, pos+3, true) diff --git a/nimpretty/tests/expected/simple.nim b/nimpretty/tests/expected/simple.nim index 5126658ea..d13558621 100644 --- a/nimpretty/tests/expected/simple.nim +++ b/nimpretty/tests/expected/simple.nim @@ -11,3 +11,8 @@ proc a() = # comment 2 discard + +# bug #15596 +discard ## comment 3 + +discard # comment 4 diff --git a/nimpretty/tests/simple.nim b/nimpretty/tests/simple.nim index 5126658ea..435bd6bd2 100644 --- a/nimpretty/tests/simple.nim +++ b/nimpretty/tests/simple.nim @@ -11,3 +11,8 @@ proc a() = # comment 2 discard + +# bug #15596 +discard## comment 3 + +discard # comment 4 From 4ab1bd7e3301e22f0a5a9c62f9c90636932fde80 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Oct 2020 20:06:06 -0700 Subject: [PATCH 1282/4254] workaround https://github.com/citycide/glob/issues/49 glob broken (#15647) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index e8d136151..92d720e60 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -42,7 +42,7 @@ pkg1 "fragments", false, "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "ggplotnim", true, "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", true, "nimble test", "https://github.com/disruptek/gittyup" -pkg1 "glob" +# pkg1 "glob" # pending https://github.com/citycide/glob/issues/49 pkg1 "gnuplot", false, "nim c gnuplot.nim" pkg1 "hts", false, "nim c -o:htss src/hts.nim" # pkg1 "httpauth", true From 0a686659d23b67aaa2d63646865a120c203bfe21 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 20 Oct 2020 10:47:43 +0200 Subject: [PATCH 1283/4254] it is not "eg", it is "e.g." --- doc/contributing.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index cc71a62f3..15017cd84 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -43,7 +43,7 @@ Stdlib ------ Each stdlib module (anything under ``lib/``, e.g. ``lib/pure/os.nim``) should -preferably have a corresponding separate test file, eg `tests/stdlib/tos.nim`. +preferably have a corresponding separate test file, e.g. `tests/stdlib/tos.nim`. The old convention was to add a ``when isMainModule:`` block in the source file, which only gets executed when the tester is building the file. @@ -71,7 +71,7 @@ Sample test: Always refer to a github issue using the following exact syntax: `bug #1234` as shown above, so that it's consistent and easier to search or for tooling. Some browser -extensions (eg https://github.com/sindresorhus/refined-github) will even turn those +extensions (e.g. https://github.com/sindresorhus/refined-github) will even turn those in clickable links when it works. Rationale for using a separate test file instead of `when isMainModule:` block: @@ -462,7 +462,7 @@ Debugging CI failures, flaky tests, etc follow these instructions to only restart the jobs that failed: * Azure: if on your own fork, it's possible from inside azure console - (eg `dev.azure.com/username/username/_build/results?buildId=1430&view=results`) via `rerun failed jobs` on top. + (e.g. `dev.azure.com/username/username/_build/results?buildId=1430&view=results`) via `rerun failed jobs` on top. If either on you own fork or in Nim repo, it's possible from inside github UI under checks tab, see https://github.com/timotheecour/Nim/issues/211#issuecomment-629751569 * github actions: under "Checks" tab, click "Re-run jobs" in the right. @@ -580,10 +580,10 @@ Conventions 1. New stdlib modules should go under `Nim/lib/std/`. The rationale is to require users to import via `import std/foo` instead of `import foo`, which would cause potential conflicts with nimble packages. Note that this still applies for new modules -in existing logical directories, eg: +in existing logical directories, e.g.: use `lib/std/collections/foo.nim`, not `lib/pure/collections/foo.nim`. -2. New module names should prefer plural form whenever possible, eg: +2. New module names should prefer plural form whenever possible, e.g.: `std/sums.nim` instead of `std/sum.nim`. In particular, this reduces chances of conflicts between module name and the symbols it defines. Furthermore, is should use `snake_case` and not use capital letters, which cause issues when going from an OS without case From 5e9dd81baa5781c15f95de45528cc072804ce969 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 20 Oct 2020 10:51:50 +0200 Subject: [PATCH 1284/4254] more "eg" fixes --- doc/advopt.txt | 2 +- doc/docstyle.rst | 2 +- doc/intern.rst | 2 +- doc/manual.rst | 2 +- doc/manual_experimental.rst | 2 +- doc/nep1.rst | 2 +- doc/nimc.rst | 2 +- doc/subexes.txt | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 60f5a1e10..85899031f 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -81,7 +81,7 @@ Advanced options: if these are nonexistent, will use project path -b, --backend:c|cpp|js|objc sets backend to use with commands like `nim doc` or `nim r` --docCmd:cmd if `cmd == skip`, skips runnableExamples - else, runs runnableExamples with given options, eg: + else, runs runnableExamples with given options, e.g.: `--docCmd:"-d:foo --threads:on"` --docSeeSrcUrl:url activate 'see source' for doc and doc2 commands (see doc.item.seesrc in config/nimdoc.cfg) diff --git a/doc/docstyle.rst b/doc/docstyle.rst index 70ded0689..9a983097b 100644 --- a/doc/docstyle.rst +++ b/doc/docstyle.rst @@ -19,7 +19,7 @@ General Guidelines .. code-block:: nim proc someproc*(s: string, foo: int) = - ## Use single backticks for inline code, eg: `s` or `someExpr(true)`. + ## Use single backticks for inline code, e.g.: `s` or `someExpr(true)`. ## Use a backlash to follow with alphanumeric char: `int8`\s are great. diff --git a/doc/intern.rst b/doc/intern.rst index be183fd8e..89d477d09 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -125,7 +125,7 @@ you can rebuild the compiler as follows: A faster approach if you don't need to run the full bootstrapping implied by `koch boot`, is the following: * `pathto/nim c --lib:lib -d:release -o:bin/nim_temp compiler/nim.nim` -Where `pathto/nim` is any nim binary sufficiently recent (eg `bin/nim_cources` +Where `pathto/nim` is any nim binary sufficiently recent (e.g. `bin/nim_cources` built during bootstrap or `$HOME/.nimble/bin/nim` installed by `choosenim 1.2.0`) You can pass any additional options such as `-d:leanCompiler` if you don't need diff --git a/doc/manual.rst b/doc/manual.rst index 7258e7775..ddee5cabe 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6707,7 +6707,7 @@ Example: embedsC() ``nimbase.h`` defines ``NIM_EXTERNC`` C macro that can be used for -``extern "C"`` code to work with both ``nim c`` and ``nim cpp``, eg: +``extern "C"`` code to work with both ``nim c`` and ``nim cpp``, e.g.: .. code-block:: Nim proc foobar() {.importc:"$1".} diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 655adae02..caf3dfb48 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1703,7 +1703,7 @@ noRewrite pragma Term rewriting macros and templates are currently greedy and they will rewrite as long as there is a match. There was no way to ensure some rewrite happens only once, -eg. when rewriting term to same term plus extra content. +e.g. when rewriting term to same term plus extra content. ``noRewrite`` pragma can actually prevent further rewriting on marked code, e.g. with given example ``echo("ab")`` will be rewritten just once: diff --git a/doc/nep1.rst b/doc/nep1.rst index 75343c85b..1ab45d680 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -149,7 +149,7 @@ changed in the future. an in-place version should get an ``-In`` suffix (``replaceIn`` for this example). -- Use `subjectVerb`, not `verbSubject`, eg: `fileExists`, not `existsFile`. +- Use `subjectVerb`, not `verbSubject`, e.g.: `fileExists`, not `existsFile`. The stdlib API is designed to be **easy to use** and consistent. Ease of use is measured by the number of calls to achieve a concrete high level action. The diff --git a/doc/nimc.rst b/doc/nimc.rst index 379d8b559..9a698312b 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -423,7 +423,7 @@ complete list. Define Effect ====================== ========================================================= ``release`` Turns on the optimizer. - More aggressive optimizations are possible, eg: + More aggressive optimizations are possible, e.g.: ``--passC:-ffast-math`` (but see issue #10305) ``danger`` Turns off all runtime checks and turns on the optimizer. ``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``. diff --git a/doc/subexes.txt b/doc/subexes.txt index 54304f033..62ddd1ec8 100644 --- a/doc/subexes.txt +++ b/doc/subexes.txt @@ -14,7 +14,7 @@ Notation meaning ===================== ===================================================== ``$#`` use first or next argument ``$name`` use named argument, you can wrap the named argument - in curly braces (eg. ``${name}``) to separate it from + in curly braces (e.g. ``${name}``) to separate it from the next characters. ``$$`` produces a single ``$`` ``$1`` use first argument From 725c7caa027ff9e04ad514bade72163522c8d28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20H=C3=BCbelbauer?= Date: Tue, 20 Oct 2020 13:36:19 +0200 Subject: [PATCH 1285/4254] Remove bit about opening files not raising (#15654) Resolved #473 I am removing this bit because this advice to not throw on recoverable-from cases like a file failing to open is actually not respected by Nim standard library. `readFile` and `readLines` both throw and exceptions must be used as a method of control flow for the recovery from that. There are alternatives, like opening a file handle instead of using these helpers, but that's less convenient than these helper methods for cases where you really want to just slurp up a file to memory and use a fallback value if it doesn't exist or is for whatever reason not readable. --- doc/tut2.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/tut2.rst b/doc/tut2.rst index ac8e82b0a..577b65622 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -345,10 +345,8 @@ The compiler will prevent you from raising an exception created on the stack. All raised exceptions should at least specify the reason for being raised in the ``msg`` field. -A convention is that exceptions should be raised in *exceptional* cases: -For example, if a file cannot be opened, this should not raise an -exception since this is quite common (the file may not exist). - +A convention is that exceptions should be raised in *exceptional* cases, +they should not be used as an alternative method of control flow. Raise statement --------------- From b418c54ec46ac79718d0bc68abb4e6531930f398 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 20 Oct 2020 13:57:50 +0200 Subject: [PATCH 1286/4254] even more "eg" fixes [ci skip] --- compiler/ast.nim | 2 +- compiler/cmdlinehelper.nim | 2 +- compiler/docgen.nim | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index f796e64c2..d81ccf33b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -875,7 +875,7 @@ type annex*: PLib # additional fields (seldom used, so we use a # reference to another object to save space) when hasFFI: - cname*: string # resolved C declaration name in importc decl, eg: + cname*: string # resolved C declaration name in importc decl, e.g.: # proc fun() {.importc: "$1aux".} => cname = funaux constraint*: PNode # additional constraints like 'lit|result'; also # misused for the codegenDecl pragma in the hope diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index a6b56b97e..5fb8ab471 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix +## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix import options, idents, nimconf, extccomp, commands, msgs, diff --git a/compiler/docgen.nim b/compiler/docgen.nim index fb15f3826..e9cd08402 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -30,7 +30,7 @@ type ExampleGroup = ref object ## a group of runnableExamples with same rdoccmd rdoccmd: string ## from 1st arg in `runnableExamples(rdoccmd): body` - docCmd: string ## from user config, eg --doccmd:-d:foo + docCmd: string ## from user config, e.g. --doccmd:-d:foo code: string ## contains imports; each import contains `body` index: int ## group index TDocumentor = object of rstgen.RstGenerator @@ -457,7 +457,7 @@ proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) = proc runAllExamples(d: PDoc) = # This used to be: `let backend = if isDefined(d.conf, "js"): "js"` (etc), however - # using `-d:js` (etc) cannot work properly, eg would fail with `importjs` + # using `-d:js` (etc) cannot work properly, e.g. would fail with `importjs` # since semantics are affected by `config.backend`, not by isDefined(d.conf, "js") let outputDir = d.exampleOutputDir for _, group in d.exampleGroups: @@ -1259,7 +1259,7 @@ proc generateIndex*(d: PDoc) = writeIndexFile(d[], dest.string) proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = - if d.module == nil or sfMainModule in d.module.flags: # nil for eg for commandRst2Html + if d.module == nil or sfMainModule in d.module.flags: # nil for e.g. for commandRst2Html if d.conf.outFile.isEmpty: d.conf.outFile = outfile.relativeTo(d.conf.outDir) if isAbsolute(d.conf.outFile.string): From ed0f8a497333c75b9035c4e7837ee1158d53aa20 Mon Sep 17 00:00:00 2001 From: RecruitMain707 <37117366+RecruitMain707@users.noreply.github.com> Date: Tue, 20 Oct 2020 14:22:02 +0200 Subject: [PATCH 1287/4254] Fix compilation error for regions and memory profiling (#15641) (#15656) Co-authored-by: Recruit_main707 --- lib/system/gc_regions.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index 9425e040a..394337192 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -8,6 +8,9 @@ # "Stack GC" for embedded devices or ultra performance requirements. +when defined(memProfiler): + proc nimProfile(requestedSize: int) {.benign.} + when defined(useMalloc): proc roundup(x, v: int): int {.inline.} = result = (x + (v-1)) and not (v-1) From 3cbe8d2c53cec1f41de116f3d3a9a7678a62da11 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Oct 2020 05:26:37 -0700 Subject: [PATCH 1288/4254] $(uint|uint64) now works with nimscript (#15644) * $(uint|uint64) now works with nimscript * fixup --- lib/system/dollars.nim | 20 ++++++++++++++++++++ lib/system/mm/go.nim | 2 -- lib/system/strmantle.nim | 20 -------------------- tests/test_nimscript.nims | 3 +++ 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index b2f0186b3..e87c237ad 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -19,6 +19,26 @@ when defined(js): ## 64bit ints. # pending https://github.com/nim-lang/RFCs/issues/187 $(cast[int](x)) +else: + proc `$`*(x: uint64): string {.noSideEffect, raises: [].} = + ## The stringify operator for an unsigned integer argument. Returns `x` + ## converted to a decimal string. + if x == 0: + result = "0" + else: + result = newString(60) + var i = 0 + var n = x + while n != 0: + let nn = n div 10'u64 + result[i] = char(n - 10'u64 * nn + ord('0')) + inc i + n = nn + result.setLen i + + let half = i div 2 + # Reverse + for t in 0 .. half-1: swap(result[t], result[i-t-1]) proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` diff --git a/lib/system/mm/go.nim b/lib/system/mm/go.nim index b6d5a1a44..9a8c47ea5 100644 --- a/lib/system/mm/go.nim +++ b/lib/system/mm/go.nim @@ -35,8 +35,6 @@ proc goMalloc(size: uint): pointer {.importc: "go_malloc", dynlib: goLib.} proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.} proc writebarrierptr(dest: PPointer, src: pointer) {.importc: "writebarrierptr", codegenDecl:"$1 $2$3 __asm__ (\"main.Atomic_store_pointer\");\n$1 $2$3", dynlib: goLib.} -proc `$`*(x: uint64): string {.noSideEffect, raises: [].} - proc GC_getStatistics(): string = var mstats = goMemStats() result = "[GC] total allocated memory: " & $(mstats.total_alloc) & "\n" & diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 43a769b5f..21b790603 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -283,26 +283,6 @@ proc nimCharToStr(x: char): string {.compilerRtl.} = result = newString(1) result[0] = x -proc `$`*(x: uint64): string {.noSideEffect, raises: [].} = - ## The stringify operator for an unsigned integer argument. Returns `x` - ## converted to a decimal string. - if x == 0: - result = "0" - else: - result = newString(60) - var i = 0 - var n = x - while n != 0: - let nn = n div 10'u64 - result[i] = char(n - 10'u64 * nn + ord('0')) - inc i - n = nn - result.setLen i - - let half = i div 2 - # Reverse - for t in 0 .. half-1: swap(result[t], result[i-t-1]) - when defined(gcDestructors): proc GC_getStatistics*(): string = result = "[GC] total memory: " diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index d9f477366..b94146b1e 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -73,6 +73,9 @@ echo "Nimscript imports are successful." block: doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath +block: + doAssert $3'u == "3" + doAssert $3'u64 == "3" block: # #14142 discard dirExists("/usr") From 877d5206162fcb491777c9d6cedf65810a3f421f Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 20 Oct 2020 15:00:16 +0200 Subject: [PATCH 1289/4254] gc.rst: updated the docs to reflect reality --- doc/gc.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index ee7f9000e..84a1338c3 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -176,8 +176,7 @@ useful for us, so it might be useful for you. To get a heap dump, compile with ``-d:nimTypeNames`` and call ``dumpNumberOfInstances`` at a strategic place in your program. This produces a list of used types in your program and for every type the total amount of object instances for this type as well as the total -amount of bytes these instances take up. This list is currently unsorted! -You need to use external shell script hacking to sort it. +amount of bytes these instances take up. The numbers count the number of objects in all garbage collector heaps, they refer to all running threads, not only to the current thread. (The current thread From 675cf5760f35c4c178bdef1fbcfd8b95e918cdb2 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Oct 2020 15:47:23 +0100 Subject: [PATCH 1290/4254] Fixes compilation for --os:any + --exception:setjmp (#15626) --- lib/system/excpt.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 1a7473a76..c189f116d 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -554,7 +554,7 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = when defined(cpp) and appType != "lib" and not gotoBasedExceptions and not defined(js) and not defined(nimscript) and - hostOS != "standalone" and not defined(noCppExceptions): + hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions): type StdException {.importcpp: "std::exception", header: "".} = object From 94a4b57280591d1b5e3fa63be17b5721776e2b30 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Oct 2020 11:21:10 -0700 Subject: [PATCH 1291/4254] make patchFile more discoverable (#15659) --- doc/advopt.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/advopt.txt b/doc/advopt.txt index 85899031f..f1e6f376d 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -51,6 +51,7 @@ Advanced options: resolution --lib:PATH set the system library path --import:PATH add an automatically imported module + see also `patchFile` in nimscript which offers more flexibility. --include:PATH add an automatically included module --nimcache:PATH set the path used for generated files see also https://nim-lang.org/docs/nimc.html#compiler-usage-generated-c-code-directory From 9a059657caa5bc744dba2c026b4e03b6231c6736 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 20 Oct 2020 21:07:24 +0200 Subject: [PATCH 1292/4254] fixes bootstrapping for any machine that has a Nim already installed [backport:1.4] (#15660) --- compiler/docgen.nim | 22 +++++++++++----------- compiler/semcall.nim | 7 +++++++ lib/packages/docutils/rstgen.nim | 13 ++++++------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e9cd08402..6c77a44ae 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -168,7 +168,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.module = module result.conf = conf result.cache = cache - result.outDir = conf.outDir + result.outDir = conf.outDir.string initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), conf.configVars, filename.string, {roSupportRawDirective, roSupportMarkdown}, docgenFindFile, compilerMsgHandler) @@ -230,8 +230,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, if gotten != status: rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output]) result.emitted = initIntSet() - result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false) - result.thisDir = result.destFile.splitFile.dir + result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string + result.thisDir = result.destFile.AbsoluteFile.splitFile.dir template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) = if conf.cmd != cmdRst2tex: dest.addf(xml, args) @@ -849,7 +849,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope, deprecationMsgRope])) - let external = d.destFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string + let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string var attype: Rope if k in routineKinds and nameNode.kind == nkSym: @@ -1237,14 +1237,14 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope = content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection"], [title.rope, toc, d.modDesc, rope(getDateStr()), - rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile), groupsection.rope]) + rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile.AbsoluteFile, theindexFname.RelativeFile), groupsection.rope]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ "nimdoccss", "dochackjs", "title", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics", "deprecationMsg"], - [relLink(d.conf.outDir, d.destFile, nimdocOutCss.RelativeFile), - relLink(d.conf.outDir, d.destFile, docHackJsFname.RelativeFile), + [relLink(d.conf.outDir, d.destFile.AbsoluteFile, nimdocOutCss.RelativeFile), + relLink(d.conf.outDir, d.destFile.AbsoluteFile, docHackJsFname.RelativeFile), title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), content, d.meta[metaAuthor].rope, d.meta[metaVersion].rope, d.analytics.rope, d.modDeprecationMsg]) else: @@ -1271,7 +1271,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) = if optStdout in d.conf.globalOptions: writeRope(stdout, content) else: - template outfile: untyped = d.destFile + template outfile: untyped = d.destFile.AbsoluteFile #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt) let dir = outfile.splitFile.dir createDir(dir) @@ -1300,13 +1300,13 @@ proc writeOutputJson*(d: PDoc, useWarning = false) = write(stdout, $content) else: var f: File - if open(f, d.destFile.string, fmWrite): + if open(f, d.destFile, fmWrite): write(f, $content) close(f) - updateOutfile(d, d.destFile) + updateOutfile(d, d.destFile.AbsoluteFile) else: localError(d.conf, newLineInfo(d.conf, AbsoluteFile d.filename, -1, -1), - warnUser, "unable to open file \"" & d.destFile.string & + warnUser, "unable to open file \"" & d.destFile & "\" for writing") proc handleDocOutputOptions*(conf: ConfigRef) = diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 3e4ed096b..dedae225b 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -230,6 +230,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): doAssert err.firstMismatch.formal != nil candidates.add("\n required type for " & nameParam & ": ") candidates.add typeToString(wanted) + when false: + if wanted.sym != nil: + candidates.add "(" & (c.config $ wanted.sym.info) & ")" candidates.add "\n but expression '" if err.firstMismatch.kind == kVarNeeded: candidates.add renderNotLValue(nArg) @@ -239,6 +242,10 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add "' is of type: " var got = nArg.typ candidates.add typeToString(got) + when false: + if got.sym != nil: + candidates.add "(" & (c.config $ got.sym.info) & ")" + doAssert wanted != nil if got != nil: effectProblem(wanted, got, candidates, c) of kUnknown: discard "do not break 'nim check'" diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 9f707f4e8..c70998edb 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -27,8 +27,7 @@ import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, algorithm, parseutils -import "$lib/../compiler/nimpaths" -import "$lib/../compiler/pathutils" + import ../../std/private/since const @@ -58,8 +57,8 @@ type options*: RstParseOptions findFile*: FindFileHandler msgHandler*: MsgHandler - outDir*: AbsoluteDir ## output directory, initialized by docgen.nim - destFile*: AbsoluteFile ## output (HTML) file, initialized by docgen.nim + outDir*: string ## output directory, initialized by docgen.nim + destFile*: string ## output (HTML) file, initialized by docgen.nim filename*: string ## source Nim or Rst file meta*: array[MetaEnum, string] currentSection: string ## \ @@ -84,7 +83,7 @@ type status: int proc prettyLink*(file: string): string = - changeFileExt(file, "").replace(dotdotMangle, "..") + changeFileExt(file, "").replace("_._", "..") proc init(p: var CodeBlockParams) = ## Default initialisation of CodeBlockParams to sane values. @@ -759,13 +758,13 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = # Generate index entry using spaces to indicate TOC level for the output HTML. assert n.level >= 0 let - htmlFileRelPath = if d.outDir.isEmpty(): + htmlFileRelPath = if d.outDir.len == 0: # /foo/bar/zoo.nim -> zoo.html changeFileExt(extractFilename(d.filename), HtmlExt) else: # d is initialized in docgen.nim # outDir = /foo -\ # destFile = /foo/bar/zoo.html -|-> bar/zoo.html - d.destFile.relativeTo(d.outDir, '/').string + d.destFile.relativePath(d.outDir, '/') setIndexTerm(d, htmlFileRelPath, refname, tmp.stripTocHtml, spaces(max(0, n.level)) & tmp) From 4b0b3818c3deaa56aa8763bb015d835479b69f67 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Oct 2020 02:49:59 -0700 Subject: [PATCH 1293/4254] fix cgen header copyright (#15649) * remove copyright Andreas Rumpf from cgen files --- compiler/cgen.nim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 9a50b718c..afb36e787 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1283,12 +1283,10 @@ proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = if optCompileOnly in conf.globalOptions: result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* (c) " & copyrightYear & " Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N") % [rope(VersionAsString)] else: result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* (c) " & copyrightYear & " Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N" & "/* Compiled for: $2, $3, $4 */$N" & "/* Command for C compiler:$n $5 */$N") % @@ -1860,8 +1858,8 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = incl g.generatedHeader.flags, isHeaderFile proc writeHeader(m: BModule) = + # could factor with 2 other instances var result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* (c) 2017 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N") % [rope(VersionAsString)] From 05752cd5d027a746053897d124f9dae513a0e664 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Oct 2020 06:37:29 -0700 Subject: [PATCH 1294/4254] add --declaredlocs (#15666) --- changelog.md | 2 +- compiler/commands.nim | 2 ++ compiler/lineinfos.nim | 6 ++++-- compiler/options.nim | 1 + compiler/semcall.nim | 11 +++++------ compiler/types.nim | 9 +++++++-- doc/advopt.txt | 1 + 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index f585f4e15..dcaffe23c 100644 --- a/changelog.md +++ b/changelog.md @@ -11,7 +11,7 @@ ## Compiler changes - +add `--declaredlocs` to show symbol declaration location in messages ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index b9199c1b0..325b362a9 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -794,6 +794,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optStdout}, arg, pass, info) of "listfullpaths": processOnOffSwitchG(conf, {optListFullPaths}, arg, pass, info) + of "declaredlocs": + processOnOffSwitchG(conf, {optDeclaredLocs}, arg, pass, info) of "dynliboverride": dynlibOverride(conf, switch, arg, pass, info) of "dynliboverrideall": diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index a0b1d1965..4a7c09276 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -69,6 +69,7 @@ type hintUser, hintUserRaw, hintExtendedContext, hintMsgOrigin, # since 1.3.5 + hintDeclaredLoc, # since 1.5.1 const MsgKindToStr*: array[TMsgKind, string] = [ @@ -159,6 +160,7 @@ const hintUserRaw: "$1", hintExtendedContext: "$1", hintMsgOrigin: "$1", + hintDeclaredLoc: "$1", ] const @@ -186,7 +188,7 @@ const "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency", "Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro", - "User", "UserRaw", "ExtendedContext", "MsgOrigin", + "User", "UserRaw", "ExtendedContext", "MsgOrigin", "DeclaredLoc" ] const @@ -215,7 +217,7 @@ type proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores} - result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} + result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext, hintDeclaredLoc} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin} diff --git a/compiler/options.nim b/compiler/options.nim index 3be7c5099..872ab9582 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -81,6 +81,7 @@ type # please make sure we have under 32 options optDocInternal # generate documentation for non-exported symbols optMixedMode # true if some module triggered C++ codegen optListFullPaths # use full paths in toMsgFilename + optDeclaredLocs # show declaration locations in messages optNoNimblePath optHotCodeReloading optDynlibOverrideAll diff --git a/compiler/semcall.nim b/compiler/semcall.nim index dedae225b..50df1085f 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -208,6 +208,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): {renderNoBody, renderNoComments, renderNoPragmas})) else: candidates.add(getProcHeader(c.config, err.sym, prefer)) + candidates.addDeclaredLocMaybe(c.config, err.sym) candidates.add("\n") let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: "" @@ -230,9 +231,8 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): doAssert err.firstMismatch.formal != nil candidates.add("\n required type for " & nameParam & ": ") candidates.add typeToString(wanted) - when false: - if wanted.sym != nil: - candidates.add "(" & (c.config $ wanted.sym.info) & ")" + if wanted.sym != nil: + candidates.addDeclaredLocMaybe(c.config, wanted.sym) candidates.add "\n but expression '" if err.firstMismatch.kind == kVarNeeded: candidates.add renderNotLValue(nArg) @@ -242,9 +242,8 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add "' is of type: " var got = nArg.typ candidates.add typeToString(got) - when false: - if got.sym != nil: - candidates.add "(" & (c.config $ got.sym.info) & ")" + if got.sym != nil: + candidates.addDeclaredLocMaybe(c.config, got.sym) doAssert wanted != nil if got != nil: effectProblem(wanted, got, candidates, c) diff --git a/compiler/types.nim b/compiler/types.nim index b20bf9c06..75e12cac4 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -123,8 +123,13 @@ proc isIntLit*(t: PType): bool {.inline.} = proc isFloatLit*(t: PType): bool {.inline.} = result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit -proc addDeclaredLoc(result: var string, conf: ConfigRef; sym: PSym) = - result.add " [declared in " & conf$sym.info & "]" +proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) = + # result.add " [declared in " & conf$sym.info & "]" + result.add " [declared in " & toFileLineCol(conf, sym.info) & "]" + +proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) = + if optDeclaredLocs in conf.globalOptions: + addDeclaredLoc(result, conf, sym) proc addTypeHeader*(result: var string, conf: ConfigRef; typ: PType; prefer: TPreferedDesc = preferMixed; getDeclarationPath = true) = result.add typeToString(typ, prefer) diff --git a/doc/advopt.txt b/doc/advopt.txt index f1e6f376d..e5cf7d894 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -35,6 +35,7 @@ Advanced options: --stdout:on|off output to stdout --colors:on|off turn compiler messages coloring on|off --listFullPaths:on|off list full paths in messages + --declaredlocs:on|off show declaration locations in messages -w:on|off|list, --warnings:on|off|list turn all warnings on|off or list all available --warning[X]:on|off turn specific warning X on|off From ec6a1125a0d20909db63bd8305c66445bf7bf78e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Oct 2020 10:33:19 -0700 Subject: [PATCH 1295/4254] --declaredlocs => --declaredLocs (#15672) --- doc/advopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index e5cf7d894..1fc0c946e 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -35,7 +35,7 @@ Advanced options: --stdout:on|off output to stdout --colors:on|off turn compiler messages coloring on|off --listFullPaths:on|off list full paths in messages - --declaredlocs:on|off show declaration locations in messages + --declaredLocs:on|off show declaration locations in messages -w:on|off|list, --warnings:on|off|list turn all warnings on|off or list all available --warning[X]:on|off turn specific warning X on|off From e09c259bf3dc8beb2c4d5abf9334c787d18f99f5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Oct 2020 15:53:43 -0700 Subject: [PATCH 1296/4254] reuse existing toHumanStr (#15674) --- compiler/parampatterns.nim | 2 +- compiler/semtypes.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index c2be4b134..eb99004ab 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -100,7 +100,7 @@ proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) = # check all symkinds: internalAssert conf, int(high(TSymKind)) < 255 for i in TSymKind: - if cmpIgnoreStyle(($i).substr(2), spec) == 0: + if cmpIgnoreStyle(i.toHumanStr, spec) == 0: result.add(ppSymKind) result.add(chr(i.ord)) return diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 8ef393839..f2bb82a5c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1913,7 +1913,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, "type expected, but symbol '$1' has no type." % [s.name.s]) else: localError(c.config, n.info, "type expected, but got symbol '$1' of kind '$2'" % - [s.name.s, substr($s.kind, 2)]) + [s.name.s, s.kind.toHumanStr]) result = newOrPrevType(tyError, prev, c) of nkObjectTy: result = semObjectNode(c, n, prev, isInheritable=false) of nkTupleTy: result = semTuple(c, n, prev) From b2f51e29504160da7bb6ee98af464c21a9a96efd Mon Sep 17 00:00:00 2001 From: Gampol T Date: Thu, 22 Oct 2020 10:40:45 +0700 Subject: [PATCH 1297/4254] Fix #13609 (#15567) * add documentation that discardable pragma cannot use on template * Update doc/manual.rst Co-authored-by: Euan * Update doc/manual.rst Co-authored-by: Euan Co-authored-by: Euan --- doc/manual.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index ddee5cabe..ca53999ac 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2592,6 +2592,17 @@ been declared with the `discardable`:idx: pragma: p(3, 4) # now valid +however the discardable pragma does not work on templates as templates substitute the AST in place. For example: + +.. code-block:: nim + {.push discardable .} + template example(): string = "https://nim-lang.org" + {.pop.} + + example() + +This template will resolve into "https://nim-lang.org" which is a string literal and since {.discardable.} doesn't apply to literals, the compiler will error. + An empty ``discard`` statement is often used as a null statement: .. code-block:: nim From 09795241375839c2b9fbd1ba8b61dc9a920837d7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 22 Oct 2020 01:44:28 -0700 Subject: [PATCH 1298/4254] add Source+Edit links on top of every docgend file (#15642) --- changelog.md | 1 + compiler/commands.nim | 2 + compiler/docgen.nim | 46 ++++++++++--------- config/nimdoc.cfg | 3 +- .../expected/index.html | 1 + .../expected/subdir/subdir_b/utils.html | 1 + nimdoc/testproject/expected/testproject.html | 1 + 7 files changed, 32 insertions(+), 23 deletions(-) diff --git a/changelog.md b/changelog.md index dcaffe23c..66c9131cd 100644 --- a/changelog.md +++ b/changelog.md @@ -12,6 +12,7 @@ ## Compiler changes add `--declaredlocs` to show symbol declaration location in messages +* Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index 325b362a9..93a202639 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -396,6 +396,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; var key, val: string case switch.normalize + of "input", "i": # PRTEMP + expectArg(conf, switch, arg, pass, info) of "path", "p": expectArg(conf, switch, arg, pass, info) for path in nimbleSubs(conf, arg): diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6c77a44ae..3945a30f8 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -777,6 +777,26 @@ type DocFlags = enum kDefault kForceExport +proc genSeeSrcRope(d: PDoc, path: string, line: int): Rope = + let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") + if docItemSeeSrc.len > 0: + let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/') + when false: + let cwd = canonicalizePath(d.conf, getCurrentDir()) + var path = path + if path.startsWith(cwd): + path = path[cwd.len+1..^1].replace('\\', '/') + let gitUrl = getConfigVar(d.conf, "git.url") + if gitUrl.len > 0: + let defaultBranch = + if NimPatch mod 2 == 1: "devel" + else: "version-$1-$2" % [$NimMajor, $NimMinor] + let commit = getConfigVar(d.conf, "git.commit", defaultBranch) + let develBranch = getConfigVar(d.conf, "git.devel", "devel") + dispA(d.conf, result, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, + ["path", "line", "url", "commit", "devel"], [rope path.string, + rope($line), rope gitUrl, rope commit, rope develBranch])]) + proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = if (docFlags != kForceExport) and not isVisible(d, nameNode): return let @@ -822,26 +842,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, renderDocComments, renderSyms}, symbolOrIdEncRope) - var seeSrcRope: Rope = nil - let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") - if docItemSeeSrc.len > 0: - let path = relativeTo(AbsoluteFile toFullPath(d.conf, n.info), AbsoluteDir getCurrentDir(), '/') - when false: - let cwd = canonicalizePath(d.conf, getCurrentDir()) - var path = toFullPath(d.conf, n.info) - if path.startsWith(cwd): - path = path[cwd.len+1..^1].replace('\\', '/') - let gitUrl = getConfigVar(d.conf, "git.url") - if gitUrl.len > 0: - let defaultBranch = - if NimPatch mod 2 == 1: "devel" - else: "version-$1-$2" % [$NimMajor, $NimMinor] - let commit = getConfigVar(d.conf, "git.commit", defaultBranch) - let develBranch = getConfigVar(d.conf, "git.devel", "devel") - dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, - ["path", "line", "url", "commit", "devel"], [rope path.string, - rope($n.info.line), rope gitUrl, rope commit, rope develBranch])]) - + let seeSrcRope = genSeeSrcRope(d, toFullPath(d.conf, n.info), n.info.line.int) d.section[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"), ["name", "header", "desc", "itemID", "header_plain", "itemSym", "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc", "deprecationMsg"], @@ -1234,10 +1235,11 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope = "doc.body_toc_group" elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" + let seeSrcRope = genSeeSrcRope(d, d.filename, 1) content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", - "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection"], + "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection", "seeSrc"], [title.rope, toc, d.modDesc, rope(getDateStr()), - rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile.AbsoluteFile, theindexFname.RelativeFile), groupsection.rope]) + rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile.AbsoluteFile, theindexFname.RelativeFile), groupsection.rope, seeSrcRope]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 13beb5af1..db86af021 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -80,7 +80,7 @@ doc.item.tocTable = """ doc.item.seesrc = """  Source -Edit +  Edit """ doc.deprecationmsg = """ @@ -187,6 +187,7 @@ doc.body_toc_group = """ $tableofcontents + $seeSrc
    $deprecationMsg diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index d6e318f7d..58ab4fc6d 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -106,6 +106,7 @@ function main() {
    +
    diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index ebbedc648..5acf196b0 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -132,6 +132,7 @@ function main() {
    +
    diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index a5522a2e2..922319914 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -358,6 +358,7 @@ function main() {
    +
    From 773643b47b04242cb8c81d44a84ae24693ad2ded Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 22 Oct 2020 11:03:05 +0200 Subject: [PATCH 1299/4254] Cleanup --- compiler/commands.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 93a202639..325b362a9 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -396,8 +396,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; var key, val: string case switch.normalize - of "input", "i": # PRTEMP - expectArg(conf, switch, arg, pass, info) of "path", "p": expectArg(conf, switch, arg, pass, info) for path in nimbleSubs(conf, arg): From e47c3987c1a9004eb346b3ae64997b33c85ea046 Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 22 Oct 2020 11:16:15 +0200 Subject: [PATCH 1300/4254] small changelog cleanup [ci skip] --- changelog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 66c9131cd..1885eaacd 100644 --- a/changelog.md +++ b/changelog.md @@ -11,8 +11,9 @@ ## Compiler changes -add `--declaredlocs` to show symbol declaration location in messages -* Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given + +- Added `--declaredlocs` to show symbol declaration location in messages. +- Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. ## Tool changes From 8da0e01769231d795300c7ce6894178cf6025e19 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Thu, 22 Oct 2020 09:25:11 +0000 Subject: [PATCH 1301/4254] expect valgrind test failure on memory leak (#15669) * expect valgrind test failure on memory leak * alloc 1 instead of 0 --- testament/tests/shouldfail/tvalgrind.nim | 17 +++++++++++++++++ tests/testament/tshould_not_work.nim | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 testament/tests/shouldfail/tvalgrind.nim diff --git a/testament/tests/shouldfail/tvalgrind.nim b/testament/tests/shouldfail/tvalgrind.nim new file mode 100644 index 000000000..4f699fd3b --- /dev/null +++ b/testament/tests/shouldfail/tvalgrind.nim @@ -0,0 +1,17 @@ +discard """ +valgrind: true +cmd: "nim $target --gc:arc -d:useMalloc $options $file" +""" + +# this is the same check used by testament/specs.nim whether or not valgrind +# tests are supported +when defined(linux) and sizeof(int) == 8: + # discarding this allocation will cause valgrind to fail (which is what we + # want), but valgrind only runs on 64-bit Linux machines... + discard alloc(1) +else: + # ...so on all other OS/architectures, simulate any non-zero exit code to + # mimic how valgrind would have failed on this test. We cannot use things like + # `disabled: "freebsd"` in the Testament configs above or else the tests will + # be SKIP-ed rather than FAIL-ed + quit(1) # choose 1 to match valgrind's `--error-exit=1`, but could be anything diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index e7790a4df..501e2c32f 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -29,6 +29,8 @@ FAIL: tests/shouldfail/tsortoutput.nim C Failure: reOutputsDiffer FAIL: tests/shouldfail/ttimeout.nim C Failure: reTimeout +FAIL: tests/shouldfail/tvalgrind.nim C +Failure: reExitcodesDiffer ''' """ From d8a6b0b04eb690e9d8611bec4ee9d99499cddff1 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 22 Oct 2020 12:16:19 +0200 Subject: [PATCH 1302/4254] [backport: 1.4] Better linebreaks (#15658) --- compiler/docgen.nim | 14 +-- config/nimdoc.cfg | 4 +- doc/nimdoc.css | 1 - .../expected/index.html | 2 +- .../expected/subdir/subdir_b/utils.html | 10 +- nimdoc/testproject/expected/testproject.html | 110 +++++++++--------- 6 files changed, 67 insertions(+), 74 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 3945a30f8..1d950f835 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -867,19 +867,13 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = xmltree.escape(getPlainDocstring(e).docstringSummary)) d.toc[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"), - ["name", "header", "desc", "itemID", "header_plain", "itemSym", - "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"], - [rope(getName(d, nameNode, d.splitAfter)), result, comm, - itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope, - plainSymbolEncRope, symbolOrIdEncRope, attype])) + ["name", "header_plain", "itemSymOrIDEnc"], + [nameRope, plainNameRope, symbolOrIdEncRope])) d.tocTable[k].mgetOrPut(cleanPlainSymbol, nil).add(ropeFormatNamedVars( d.conf, getConfigVar(d.conf, "doc.item.tocTable"), - ["name", "header", "desc", "itemID", "header_plain", "itemSym", - "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"], - [rope(getName(d, nameNode, d.splitAfter)), result, comm, - itemIDRope, plainNameRope, plainSymbolRope, - symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, attype])) + ["name", "header_plain", "itemSymOrID", "itemSymOrIDEnc"], + [nameRope, plainNameRope, rope(symbolOrId.replace(",", ",")), symbolOrIdEncRope])) # Ironically for types the complexSymbol is *cleaner* than the plainName # because it doesn't include object fields or documentation comments. So we diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index db86af021..a99af70ed 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -57,13 +57,13 @@ $seeSrc # See doc.item for available substitution variables. doc.item.toc = """
  • $name$attype
  • + title="$header_plain">$name """ # This is used for TOC items which are grouped by the same name (e.g. procs). doc.item.tocTable = """
  • $itemSymOrID$attype
  • + title="$header_plain">$itemSymOrID """ diff --git a/doc/nimdoc.css b/doc/nimdoc.css index e0c5a1de4..457f024b5 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -155,7 +155,6 @@ body { .three.columns { width: 22%; - line-break: anywhere; } .nine.columns { diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 58ab4fc6d..65241d356 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -96,7 +96,7 @@ function main() {
        foo
      • foo
      • + title="foo()">foo
      diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 5acf196b0..40de645e3 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -101,7 +101,7 @@ function main() {
      • SomeType
      • + enumValueA, enumValueB, enumValueC">SomeType
      @@ -110,7 +110,7 @@ function main() {
        @@ -120,11 +120,11 @@ function main() { Templates
        • aEnum
        • + title="aEnum(): untyped">aEnum
        • bEnum
        • + title="bEnum(): untyped">bEnum
        • fromUtilsGen
        • + title="fromUtilsGen(): untyped">fromUtilsGen
        diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 922319914..103dea25f 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -102,13 +102,13 @@ function main() {
        • A
        • + aA">A
        • B
        • + bB">B
        • Foo
        • + enumValueA2">Foo
        @@ -116,7 +116,7 @@ function main() { Vars
        • aVariable
        • + title="aVariable: array[1, int]">aVariable
        @@ -124,13 +124,13 @@ function main() { Consts
        • C_A
        • + title="C_A = 0x7FF0000000000000'f64">C_A
        • C_B
        • + title="C_B = 0o377'i8">C_B
        • C_C
        • + title="C_C = 0o277'i8">C_C
        • C_D
        • + title="C_D = 0o177777'i16">C_D
        @@ -139,149 +139,149 @@ function main() {
            z10
          • z10
          • + title="z10()">z10
            tripleStrLitTest
          • tripleStrLitTest
          • + title="tripleStrLitTest()">tripleStrLitTest
            z17
          • z17
          • + title="z17()">z17
            asyncFun3
          • asyncFun3
          • + title="asyncFun3(): owned(Future[void])">asyncFun3
            z2
          • z2
          • + title="z2()">z2
            bar
          • bar,T,T
          • + title="bar[T](a, b: T): T">bar,T,T
            fromUtils3
          • fromUtils3
          • + title="fromUtils3()">fromUtils3
            isValid
          • isValid,T
          • + title="isValid[T](x: T): bool">isValid,T
            z6
          • z6
          • + title="z6(): int">z6
            low
          • low,T
          • + title="low[T: Ordinal | enum | range](x: T): T">low,T
            p1
          • p1
          • + title="p1()">p1
            z11
          • z11
          • + title="z11()">z11
            buzz
          • buzz,T,T
          • + title="buzz[T](a, b: T): T">buzz,T,T
            low2
          • low2,T
          • + title="low2[T: Ordinal | enum | range](x: T): T">low2,T
            z7
          • z7
          • + title="z7(): int">z7
            z13
          • z13
          • + title="z13()">z13
            baz
          • baz,T,T
          • + title="baz[T](a, b: T): T">baz,T,T
          • baz
          • + title="baz()">baz
            addfBug14485
          • addfBug14485
          • + title="addfBug14485()">addfBug14485
            c_printf
          • c_printf,cstring
          • + title="c_printf(frmt: cstring): cint">c_printf,cstring
            z12
          • z12
          • + title="z12(): int">z12
            z3
          • z3
          • + title="z3()">z3
            z9
          • z9
          • + title="z9()">z9
            z4
          • z4
          • + title="z4()">z4
            z8
          • z8
          • + title="z8(): int">z8
            z1
          • z1Foo
          • + title="z1(): Foo">z1
            z5
          • z5
          • + title="z5(): int">z5
            asyncFun2
          • asyncFun2
          • + title="asyncFun2(): owned(Future[void])">asyncFun2
            asyncFun1
          • asyncFun1
          • + title="asyncFun1(): Future[int]">asyncFun1
          @@ -292,7 +292,7 @@ function main() {
              someFunc
            • someFunc
            • + title="someFunc()">someFunc
            @@ -302,11 +302,11 @@ function main() { Methods
            • method1
            • + title="method1(self: Moo)">method1
            • method2
            • + title="method2(self: Moo): int">method2
            • method3
            • + title="method3(self: Moo): int">method3
            @@ -314,11 +314,11 @@ function main() { Iterators
            • fromUtils1
            • + title="fromUtils1(): int">fromUtils1
            • iter1
            • + title="iter1(n: int): int">iter1
            • iter2
            • + title="iter2(n: int): int">iter2
            @@ -326,11 +326,11 @@ function main() { Macros
            • bar
            • + title="bar(): untyped">bar
            • z16
            • + title="z16()">z16
            • z18
            • + title="z18(): int">z18
            @@ -338,19 +338,19 @@ function main() { Templates
            • fromUtils2
            • + title="fromUtils2()">fromUtils2
            • z6t
            • + title="z6t(): int">z6t
            • foo
            • + title="foo(a, b: SomeType)">foo
            • myfn
            • + title="myfn()">myfn
            • z14
            • + title="z14()">z14
            • z15
            • + title="z15()">z15
            • testNimDocTrailingExample
            • + title="testNimDocTrailingExample()">testNimDocTrailingExample
            From 7c359a062c17696aab5dd5b75d595af0596c001c Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 22 Oct 2020 12:51:03 +0200 Subject: [PATCH 1303/4254] Add testcase for #12252 (#15676) --- tests/defaultprocparam/tdefaultprocparam.nim | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/defaultprocparam/tdefaultprocparam.nim b/tests/defaultprocparam/tdefaultprocparam.nim index 0d62cc955..90edfa8c9 100644 --- a/tests/defaultprocparam/tdefaultprocparam.nim +++ b/tests/defaultprocparam/tdefaultprocparam.nim @@ -81,3 +81,10 @@ block: echo p3(a) echo p3(b) echo p3(a, 0) + +# bug #12252 +proc foo(a = 0, b = a.high, c = high(typeof(a))) = + discard + +foo() + From 7435d912adcf411feed4ba124808527c7e04a44f Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 22 Oct 2020 13:23:39 +0200 Subject: [PATCH 1304/4254] Add testcase for #14601 (#15677) --- tests/destructor/tdestructor3.nim | 46 ++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index ca9a891e1..eb49f3f15 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -127,4 +127,48 @@ proc test2() = echo "---------------" echo "app begin" test2() -echo "app end" \ No newline at end of file +echo "app end" + +# bug #14601 + +when true: # D20200607T202043 + type Foo2 = object + x: int + x2: array[10, int] + + type Vec = object + vals: seq[Foo2] + + proc `=destroy`*(a: var Foo2) {.inline.} = + discard + + proc initFoo2(x: int): Foo2 = Foo2(x: x) + + proc add2(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2` + v.vals.add a + + proc add3(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2` + v.vals = @[a] + + proc add4(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2` + v.vals.add a + + proc add5(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2` + v.vals = @[a] + + proc main2()= + var a: Vec + var b = Foo2(x: 10) + a.add2 b # ok + a.vals.add Foo2(x: 10) # ok + a.add2 initFoo2(x = 10) # ok + a.add2 Foo2(x: 10) # bug + a.add3 initFoo2(x = 10) # ok + a.add3 Foo2(x: 10) # bug + a.add4 initFoo2(x = 10) # ok + a.add4 Foo2(x: 10) # bug + a.add5 initFoo2(x = 10) # ok + a.add5 Foo2(x: 10) # bug + main2() + + From 8358974b73afe8db06822779f2a28adbafc58280 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 22 Oct 2020 17:28:43 +0200 Subject: [PATCH 1305/4254] fixes #15652 [backport:1.4] (#15679) --- compiler/ccgexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 004b8f41e..b2a325632 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -760,7 +760,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = # See tmissingderef. So we get rid of the deref instead. The codegen # ends up using 'memcpy' for the array assignment, # so the '&' and '*' cancel out: - putIntoDest(p, d, lodeTyp(a.t[0]), rdLoc(a), a.storage) + putIntoDest(p, d, e, rdLoc(a), a.storage) else: putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage) From 64016ddedcfc266c87d8fe7eece8b9476aa6db30 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 22 Oct 2020 18:52:05 +0200 Subject: [PATCH 1306/4254] fixes view types for sizeof() and --gc:orc (#15680) --- compiler/ccgexprs.nim | 6 +++--- compiler/sizealignoffsetimpl.nim | 2 +- tests/views/tsplit_into_seq.nim | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b2a325632..5c897e1a4 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2328,10 +2328,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)]) + putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, skVar)]) of mAlignOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)]) + putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)]) of mOffsetOf: var dotExpr: PNode if e[1].kind == nkDotExpr: @@ -2341,7 +2341,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) - let tname = getTypeDesc(p.module, t) + let tname = getTypeDesc(p.module, t, skVar) let member = if t.kind == tyTuple: "Field" & rope(dotExpr[1].sym.position) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index be35247f7..3e536f5d7 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -242,7 +242,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = else: typ.size = conf.target.ptrSize typ.align = int16(conf.target.ptrSize) - of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray: + of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent: let base = typ.lastSon if base == typ: # this is not the correct location to detect ``type A = ptr A`` diff --git a/tests/views/tsplit_into_seq.nim b/tests/views/tsplit_into_seq.nim index 49968f4c2..a0861458b 100644 --- a/tests/views/tsplit_into_seq.nim +++ b/tests/views/tsplit_into_seq.nim @@ -4,7 +4,7 @@ asdf 231 231 ''' - cmd: "nim c $file" + cmd: "nim c --gc:orc $file" """ {.experimental: "views".} From 2cb484cefb13e4663afd8e0eb2ad81d43f097803 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 22 Oct 2020 12:02:18 -0700 Subject: [PATCH 1307/4254] followup #15642: make source + edit also work with stdlib (which uses -d:boot) (#15684) --- config/nimdoc.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index a99af70ed..e4b485ca0 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -146,6 +146,7 @@ doc.body_toc_group = """ $body_toc_groupsection $tableofcontents
    + $seeSrc
    $deprecationMsg @@ -156,7 +157,7 @@ doc.body_toc_group = """ """ @else - +# keep in sink with other `doc.body_toc_group` or better, refactor doc.body_toc_group = """
    From 01a62320f03ebd3282a7def231351c4f84c319d2 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 23 Oct 2020 03:26:50 +0200 Subject: [PATCH 1308/4254] Fix #12410 (#15685) * Fix #12410, big thanks to @pmetras for this fix * Add testcase --- lib/pure/streams.nim | 2 +- tests/stdlib/tstreams.nim | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 77f384a79..dc00271a5 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -242,7 +242,7 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int = result = s.readDataStrImpl(s, buffer, slice) else: # fallback - result = s.readData(addr buffer[0], buffer.len) + result = s.readData(addr buffer[slice.a], slice.b + 1 - slice.a) template jsOrVmBlock(caseJsOrVm, caseElse: untyped): untyped = when nimvm: diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 354bdf60f..6979bae38 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -6,6 +6,7 @@ Nice name: Arne fs is: nil threw exception +_heh_ ''' nimout: ''' I @@ -49,3 +50,15 @@ block tstreams3: for line in s.lines: echo line s.close + +# bug #12410 + +var a = newStringStream "hehohihahuhyh" +a.readDataStrImpl = nil + +var buffer = "_ooo_" + +doAssert a.readDataStr(buffer, 1..3) == 3 + +echo buffer + From 275354709d2a5e38b9e06b2cee823ddef756d62d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 22 Oct 2020 23:03:09 -0700 Subject: [PATCH 1309/4254] make cgen header consistent with jsgen header (#15682) --- compiler/cgen.nim | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index afb36e787..5c60a3cf3 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1280,18 +1280,15 @@ proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = if conf.isDefined("nimEmulateOverflowChecks"): result.add("#define NIM_EmulateOverflowChecks\L") +proc headerTop(): Rope = + result = "/* Generated by Nim Compiler v$1 */$N" % [rope(VersionAsString)] + proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = - if optCompileOnly in conf.globalOptions: - result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* The generated code is subject to the original license. */$N") % - [rope(VersionAsString)] - else: - result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* The generated code is subject to the original license. */$N" & - "/* Compiled for: $2, $3, $4 */$N" & - "/* Command for C compiler:$n $5 */$N") % - [rope(VersionAsString), - rope(platform.OS[conf.target.targetOS].name), + result = headerTop() + if optCompileOnly notin conf.globalOptions: + result.add ("/* Compiled for: $1, $2, $3 */$N" & + "/* Command for C compiler:$n $4 */$N") % + [rope(platform.OS[conf.target.targetOS].name), rope(platform.CPU[conf.target.targetCPU].name), rope(extccomp.CC[conf.cCompiler].name), rope(getCompileCFileCmd(conf, cfile))] @@ -1858,11 +1855,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = incl g.generatedHeader.flags, isHeaderFile proc writeHeader(m: BModule) = - # could factor with 2 other instances - var result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* The generated code is subject to the original license. */$N") % - [rope(VersionAsString)] - + var result = headerTop() var guard = "__$1__" % [m.filename.splitFile.name.rope] result.addf("#ifndef $1$n#define $1$n", [guard]) addNimDefines(result, m.config) From ae320b4e7dfd07ed6ae85a2693da3bb8568520c6 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 23 Oct 2020 10:14:54 +0100 Subject: [PATCH 1310/4254] fix #15662 (#15678) * fix #15662 * alternative fix * fix spacing --- compiler/vmgen.nim | 32 +++++++++++++++----------------- tests/vm/tconstobj.nim | 5 +++++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 6f81c6a9c..4dcd01458 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -586,9 +586,6 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = # varargs need 'opcSetType' for the FFI support: let fntyp = skipTypes(n[0].typ, abstractInst) for i in 0.. 0 and i < fntyp.len: - # let paramType = fntyp.n[i] - # if paramType.typ.isCompileTimeOnly: continue var r: TRegister = x+i c.gen(n[i], r, {gfIsParam}) if i >= fntyp.len: @@ -1926,20 +1923,21 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) = proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) - c.gABx(n, opcLdNull, dest, c.genType(n.typ)) - # XXX x = (x.old, 22) produces wrong code ... stupid self assignments - for i in 0.. Date: Fri, 23 Oct 2020 23:16:47 +0200 Subject: [PATCH 1311/4254] close #8007 (#15695) --- tests/vm/tvmmisc.nim | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 73faac495..61a187faf 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -230,3 +230,54 @@ block: doAssert d == @[] doAssert e == @[] doAssert f == @[] + +import tables + +block: # bug #8007 + type + CostKind = enum + Fixed, + Dynamic + + Cost = object + case kind*: CostKind + of Fixed: + cost*: int + of Dynamic: + handler*: proc(value: int): int {.nimcall.} + + proc foo(value: int): int {.nimcall.} = + sizeof(value) + + const a: array[2, Cost] =[ + Cost(kind: Fixed, cost: 999), + Cost(kind: Dynamic, handler: foo) + ] + + # OK with arrays & object variants + doAssert $a == "[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" + + const b: Table[int, Cost] = { + 0: Cost(kind: Fixed, cost: 999), + 1: Cost(kind: Dynamic, handler: foo) + }.toTable + + # KO with Tables & object variants + # echo b # {0: (kind: Fixed, cost: 0), 1: (kind: Dynamic, handler: ...)} # <----- wrong behaviour + doAssert $b == "{0: (kind: Fixed, cost: 999), 1: (kind: Dynamic, handler: ...)}" + + const c: Table[int, int] = { + 0: 100, + 1: 999 + }.toTable + + # OK with Tables and primitive int + doAssert $c == "{0: 100, 1: 999}" + + # For some reason the following gives + # Error: invalid type for const: Cost + const d0 = Cost(kind: Fixed, cost: 999) + + # OK with seq & object variants + const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)] + doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" From d4022ebe53062a7e1be5fd55637a3cce39b93a12 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 24 Oct 2020 11:45:18 +0200 Subject: [PATCH 1312/4254] Revert "fixes #15280 [backport:1.2] (#15281)" (#15700) This reverts commit 3f00a738dbc8319b4dd2b86bf5529c096f2dd243. --- compiler/sem.nim | 2 +- tests/arc/tmovebug.nim | 6 +-- tests/casestmt/tcasestmt.nim | 2 +- tests/semreject/tmixing_return_and_exprs.nim | 44 -------------------- 4 files changed, 5 insertions(+), 49 deletions(-) delete mode 100644 tests/semreject/tmixing_return_and_exprs.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index bc6119460..705e1b72c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -184,7 +184,7 @@ proc endsInNoReturn(n: PNode): bool = var it = n while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: it = it.lastSon - result = it.kind in (nkLastBlockStmts-{nkReturnStmt}) or + result = it.kind in nkLastBlockStmts or it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags proc commonType*(x: PType, y: PNode): PType = diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index c735ea1eb..3b7a7c5df 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -502,7 +502,7 @@ weirdScopes() # bug #14985 proc getScope(): string = if true: - "hi" + return "hi" else: "else" @@ -512,14 +512,14 @@ proc getScope3(): string = try: "try" except: - "except" + return "except" echo getScope3() proc getScope2(): string = case true of true: - "bye" + return "bye" else: "else" diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 2151892aa..53cccdb64 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -258,7 +258,7 @@ func foo(input: string): int = try: parseInt(input) except: - 0 + return func foo2(b, input: string): int = case b: diff --git a/tests/semreject/tmixing_return_and_exprs.nim b/tests/semreject/tmixing_return_and_exprs.nim deleted file mode 100644 index 2848c47e4..000000000 --- a/tests/semreject/tmixing_return_and_exprs.nim +++ /dev/null @@ -1,44 +0,0 @@ -discard """ - errormsg: "expression 'len(src) shl 1' is of type 'int' and has to be used (or discarded)" - line: 19 -""" - -# bug #15280 - -type - HexFlags* {.pure.} = enum - LowerCase, ## Produce lowercase hexadecimal characters - PadOdd, ## Pads odd strings - SkipSpaces, ## Skips all the whitespace characters inside of string - SkipPrefix ## Skips `0x` and `x` prefixes at the begining of string - - -proc bytesToHex*(src: openarray[byte], dst: var openarray[char], - flags: set[HexFlags]): int = - if len(dst) == 0: - (len(src) shl 1) - else: - var halflast = false - let dstlen = len(dst) - var srclen = len(src) - - if dstlen < (srclen shl 1): - if (dstlen and 1) == 1: - srclen = (dstlen - 1) shr 1 - halflast = true - else: - srclen = (dstlen shr 1) - - let lowercase = (HexFlags.LowerCase in flags) - - var k = 0 - for i in 0 ..< srclen: - let x = int(src[i]) - inc(k, 2) - - if halflast: - let x = int(src[srclen]) - inc(k) - - return k - From e18fc698ed4fba3fc0e33e8116d3739d2161e618 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 24 Oct 2020 17:02:42 +0200 Subject: [PATCH 1313/4254] Try to fix CI failures (#15701) * Use cligens release version * Rework important_packages main loop * Fix * Fix * Create pkgs dir * Don't use nimble develop since it doesn't work for binary only packages, and always install head * Use git to get the latest release/tag instead * Tackle the root cause * Reduce diff * Cleanup --- testament/categories.nim | 75 ++++++------- testament/important_packages.nim | 175 +++++++++++++++---------------- 2 files changed, 120 insertions(+), 130 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 760c3c5be..07d35f6fb 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -452,15 +452,15 @@ type ppOne ppTwo -iterator listPackages(part: PkgPart): tuple[name, url, cmd: string, hasDeps: bool, useHead: bool] = +iterator listPackages(part: PkgPart): tuple[name, cmd, url: string, useHead: bool] = let packageList = parseFile(packageIndex) let importantList = case part of ppOne: important_packages.packages1 of ppTwo: important_packages.packages2 - for n, cmd, hasDeps, url, useHead in importantList.items: + for n, cmd, url, useHead in importantList.items: if url.len != 0: - yield (n, url, cmd, hasDeps, useHead) + yield (n, cmd, url, useHead) else: var found = false for package in packageList.items: @@ -468,7 +468,7 @@ iterator listPackages(part: PkgPart): tuple[name, url, cmd: string, hasDeps: boo if name == n: found = true let pUrl = package["url"].str - yield (name, pUrl, cmd, hasDeps, useHead) + yield (name, cmd, pUrl, useHead) break if not found: raise newException(ValueError, "Cannot find package '$#'." % n) @@ -479,16 +479,6 @@ proc makeSupTest(test, options: string, cat: Category): TTest = result.options = options result.startTime = epochTime() -proc actionRetry(maxRetry: int, backoffDuration: float, action: proc: bool): bool = - ## retry `action` up to `maxRetry` times with exponential backoff and initial - ## duraton of `backoffDuration` seconds - var t = backoffDuration - for i in 0.. Date: Sun, 25 Oct 2020 01:56:07 +0300 Subject: [PATCH 1314/4254] [minor] nimVMDebug: fix codeListing formatting for jump-to-file to work (#15711) --- compiler/vmgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 4dcd01458..44b10ea67 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -99,7 +99,7 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) = inc i else: result.addf("\t$#\tr$#, $#", opc.toStr, x.regA, x.regBx-wordExcess) - result.add("\t#") + result.add("\t# ") result.add(debugInfo(c, c.debug[i])) result.add("\n") inc i From 7252a50fefb844d97ad4630c1db00063380ff3c4 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Sun, 25 Oct 2020 04:29:57 -0300 Subject: [PATCH 1315/4254] fix #15698 (#15699) * fix in the net.`$` to print zeros that are not in the compressed group * Update lib/pure/net.nim Co-authored-by: Andreas Rumpf * Update net.nim Co-authored-by: Andreas Rumpf --- lib/pure/net.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 3ef41aa3c..cd509463a 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1827,6 +1827,10 @@ proc `$`*(address: IpAddress): string = result.add(chr(uint16(ord('a'))+val-0xA)) afterLeadingZeros = true mask = mask shr 4 + + if not afterLeadingZeros: + result.add '0' + printedLastGroup = true proc dial*(address: string, port: Port, From 226595515c25785eaf078834dfb6f0ac337a5278 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 25 Oct 2020 08:50:47 +0100 Subject: [PATCH 1316/4254] explicit ID generation for easier IC (#15559) * refactoring: idents don't need inheritance * refactoring: adding an IdGenerator (part 1) * refactoring: adding an IdGenerator (part 2) * refactoring: adding an IdGenerator (part 3) * refactoring: adding an IdGenerator (part 4) * refactoring: adding an IdGenerator (part 5) * refactoring: adding an IdGenerator (part 5) * IdGenerator must be a ref type; hello world works again * make bootstrapping work again * progress: add back the 'exactReplica' ideas * added back the missing exactReplica hacks * make tcompilerapi work again * make important packages green * attempt to fix the build for 32 bit machines (probably need a better solution here) --- compiler/ast.nim | 93 +++++++++++------- compiler/ccgexprs.nim | 20 ++-- compiler/ccgmerge.nim | 9 +- compiler/ccgstmts.nim | 4 +- compiler/ccgtypes.nim | 14 +-- compiler/cgen.nim | 11 ++- compiler/cgmeth.nim | 12 +-- compiler/closureiters.nim | 35 ++++--- compiler/cmdlinehelper.nim | 2 +- compiler/depends.nim | 2 +- compiler/docgen2.nim | 4 +- compiler/enumtostr.nim | 20 ++-- compiler/evaltempl.nim | 5 +- compiler/guards.nim | 5 +- compiler/hlo.nim | 4 +- compiler/idents.nim | 7 +- compiler/idgen.nim | 59 ------------ compiler/importer.nim | 2 +- compiler/injectdestructors.nim | 27 +++--- compiler/isolation_check.nim | 2 +- compiler/jsgen.nim | 18 ++-- compiler/lambdalifting.nim | 138 ++++++++++++++------------- compiler/liftdestructors.nim | 99 ++++++++++--------- compiler/liftlocals.nim | 8 +- compiler/lookups.nim | 2 +- compiler/lowerings.nim | 61 ++++++------ compiler/magicsys.nim | 30 +++--- compiler/main.nim | 17 ++-- compiler/modulegraphs.nim | 7 +- compiler/modules.nim | 21 ++-- compiler/nimconf.nim | 21 ++-- compiler/nimeval.nim | 14 ++- compiler/passaux.nim | 8 +- compiler/passes.nim | 32 ++----- compiler/plugins/itersgen.nim | 6 +- compiler/plugins/locals.nim | 4 +- compiler/pragmas.nim | 8 +- compiler/rod.nim | 4 +- compiler/rodimpl.nim | 4 +- compiler/scriptconfig.nim | 10 +- compiler/sem.nim | 44 ++++----- compiler/semcall.nim | 4 +- compiler/semdata.nim | 35 +++---- compiler/semexprs.nim | 54 +++++------ compiler/semfields.nim | 2 +- compiler/semfold.nim | 131 +++++++++---------------- compiler/semgnrc.nim | 10 +- compiler/seminst.nim | 18 ++-- compiler/semmagic.nim | 38 ++++---- compiler/semparallel.nim | 30 +++--- compiler/sempass2.nim | 18 ++-- compiler/semstmts.nim | 44 ++++----- compiler/semtempl.nim | 6 +- compiler/semtypes.nim | 84 ++++++++-------- compiler/semtypinst.nim | 19 ++-- compiler/sigmatch.nim | 18 ++-- compiler/sinkparameter_inference.nim | 12 +-- compiler/spawn.nim | 107 +++++++++++---------- compiler/transf.nim | 62 ++++++------ compiler/types.nim | 12 +-- compiler/vm.nim | 68 ++++++------- compiler/vmdef.nim | 7 +- compiler/vmdeps.nim | 51 +++++----- compiler/vmgen.nim | 6 +- compiler/vmmarshal.nim | 23 ++--- compiler/vmops.nim | 2 +- lib/system/iterators.nim | 2 +- 67 files changed, 853 insertions(+), 903 deletions(-) delete mode 100644 compiler/idgen.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index d81ccf33b..a9793fb21 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,7 @@ # abstract syntax tree + symbol table import - lineinfos, hashes, options, ropes, idents, idgen, int128 + lineinfos, hashes, options, ropes, idents, int128 from strutils import toLowerAscii export int128 @@ -717,6 +717,14 @@ const mInSet, mRepr} type + ItemId* = object + module*: int32 + item*: int32 + + TIdObj* = object of RootObj + itemId*: ItemId + PIdObj* = ref TIdObj + PNode* = ref TNode TNodeSeq* = seq[PNode] PType* = ref TType @@ -926,7 +934,7 @@ type loc*: TLoc typeInst*: PType # for generic instantiations the tyGenericInst that led to this # type. - uniqueId*: int # due to a design mistake, we need to keep the real ID here as it + uniqueId*: ItemId # due to a design mistake, we need to keep the real ID here as it # required by the --incremental:on mode. TPair* = object @@ -1060,6 +1068,35 @@ proc getnimblePkg*(a: PSym): PSym = else: assert false, $result.kind +const + moduleShift = when defined(cpu32): 20 else: 24 + +template id*(a: PIdObj): int = + let x = a + (x.itemId.module.int shl moduleShift) + x.itemId.item.int + +type + IdGenerator* = ref ItemId # unfortunately, we really need the 'shared mutable' aspect here. + +const + PackageModuleId* = -3'i32 + +proc idGeneratorFromModule*(m: PSym): IdGenerator = + assert m.kind == skModule + result = IdGenerator(module: m.itemId.module, item: m.itemId.item) + +proc nextId*(x: IdGenerator): ItemId {.inline.} = + inc x.item + result = x[] + +when false: + proc storeBack*(dest: var IdGenerator; src: IdGenerator) {.inline.} = + assert dest.ItemId.module == src.ItemId.module + if dest.ItemId.item > src.ItemId.item: + echo dest.ItemId.item, " ", src.ItemId.item, " ", src.ItemId.module + assert dest.ItemId.item <= src.ItemId.item + dest = src + proc getnimblePkgId*(a: PSym): int = let b = a.getnimblePkg result = if b == nil: -1 else: b.id @@ -1164,13 +1201,11 @@ proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[ template previouslyInferred*(t: PType): PType = if t.sons.len > 1: t.lastSon else: nil -proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, +proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym, info: TLineInfo; options: TOptions = {}): PSym = # generates a symbol and initializes the hash field too - result = PSym(name: name, kind: symKind, flags: {}, info: info, id: getID(), + result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id, options: options, owner: owner, offset: defaultOffset) - when debugIds: - registerId(result) proc astdef*(s: PSym): PNode = # get only the definition (initializer) portion of the ast @@ -1344,13 +1379,11 @@ proc `$`*(s: PSym): string = else: result = "" -proc newType*(kind: TTypeKind, owner: PSym): PType = - let id = getID() +proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = result = PType(kind: kind, owner: owner, size: defaultSize, - align: defaultAlignment, id: id, uniqueId: id, - lockLevel: UnspecifiedLockLevel) - when debugIds: - registerId(result) + align: defaultAlignment, itemId: id, + lockLevel: UnspecifiedLockLevel, + uniqueId: id) when false: if result.id == 76426: echo "KNID ", kind @@ -1392,22 +1425,18 @@ proc assignType*(dest, src: PType) = newSons(dest, src.len) for i in 0..` and ## returned. Otherwise ``typ`` is simply returned as-is. result = typ if typ.kind != kind: - result = newType(kind, typ.owner) + result = newType(kind, nextId(idgen), typ.owner) rawAddSon(result, typ) -proc toRef*(typ: PType): PType = +proc toRef*(typ: PType; idgen: IdGenerator): PType = ## If ``typ`` is a tyObject then it is converted into a `ref ` and ## returned. Otherwise ``typ`` is simply returned as-is. if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject: - result = newType(tyRef, typ.owner) + result = newType(tyRef, nextId(idgen), typ.owner) rawAddSon(result, typ) proc toObject*(typ: PType): PType = @@ -1888,8 +1917,8 @@ proc isSinkParam*(s: PSym): bool {.inline.} = proc isSinkType*(t: PType): bool {.inline.} = t.kind == tySink or tfHasOwned in t.flags -proc newProcType*(info: TLineInfo; owner: PSym): PType = - result = newType(tyProc, owner) +proc newProcType*(info: TLineInfo; id: ItemId; owner: PSym): PType = + result = newType(tyProc, id, owner) result.n = newNodeI(nkFormalParams, info) rawAddSon(result, nil) # return type # result.n[0] used to be `nkType`, but now it's `nkEffectList` because diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 5c897e1a4..b6caec760 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1765,20 +1765,20 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ))) else: internalError(p.config, e.info, "genArrayLen()") -proc makePtrType(baseType: PType): PType = - result = newType(tyPtr, baseType.owner) - addSonSkipIntLit(result, baseType) +proc makePtrType(baseType: PType; idgen: IdGenerator): PType = + result = newType(tyPtr, nextId idgen, baseType.owner) + addSonSkipIntLit(result, baseType, idgen) -proc makeAddr(n: PNode): PNode = +proc makeAddr(n: PNode; idgen: IdGenerator): PNode = if n.kind == nkHiddenAddr: result = n else: result = newTree(nkHiddenAddr, n) - result.typ = makePtrType(n.typ) + result.typ = makePtrType(n.typ, idgen) proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1]) + e[1] = makeAddr(e[1], p.module.idgen) genCall(p, e, d) return var a, b, call: TLoc @@ -2240,7 +2240,7 @@ proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) = toStrProc = p break if toStrProc == nil: - toStrProc = genEnumToStrProc(t, e.info, p.module.g.graph) + toStrProc = genEnumToStrProc(t, e.info, p.module.g.graph, p.module.idgen) t.methods.add((ToStringProcSlot, toStrProc)) var n = copyTree(e) n[0] = newSymNode(toStrProc) @@ -2294,7 +2294,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1]) + e[1] = makeAddr(e[1], p.module.idgen) genCall(p, e, d) else: genSeqElemAppend(p, e, d) @@ -2393,13 +2393,13 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = when defined(leanCompiler): quit "compiler built without support for the 'spawn' statement" else: - let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil) + let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.idgen, p.module.module, e, e.typ, nil, nil) expr(p, n, d) of mParallel: when defined(leanCompiler): quit "compiler built without support for the 'parallel' statement" else: - let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) + let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e) expr(p, n, d) of mDeepCopy: if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions: diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index a87d5b609..40833a64e 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -180,10 +180,6 @@ proc readKey(L: var TBaseLexer, result: var string) = if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected") L.bufpos = pos + 1 # skip ':' -proc newFakeType(id: int): PType = - new(result) - result.id = id - proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") inc L.bufpos @@ -192,10 +188,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = var key = decodeStr(L.buf, L.bufpos) if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected") inc L.bufpos - var value = decodeStr(L.buf, L.bufpos) - # XXX implement me - when false: - idTablePut(result, newFakeType(key), value.rope) + discard decodeStr(L.buf, L.bufpos) inc L.bufpos proc readIntSet(L: var TBaseLexer, result: var IntSet) = diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 1282cf11f..aaed37508 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -66,7 +66,7 @@ proc genVarTuple(p: BProc, n: PNode) = # if we have a something that's been captured, use the lowering instead: for i in 0..= prc.ast.len: @@ -1844,9 +1844,10 @@ template injectG() {.dirty.} = when not defined(nimHasSinkInference): {.pragma: nosinks.} -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = +proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = injectG() result = newModule(g, module, graph.config) + result.idgen = idgen if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile else: graph.config.projectFull @@ -1920,9 +1921,9 @@ proc myProcess(b: PPassContext, n: PNode): PNode = m.initProc.options = initProcOptions(m) #softRnl = if optLineDir in m.config.options: noRnl else: rnl # XXX replicate this logic! - var transformedN = transformStmt(m.g.graph, m.module, n) + var transformedN = transformStmt(m.g.graph, m.idgen, m.module, n) if sfInjectDestructors in m.module.flags: - transformedN = injectDestructorCalls(m.g.graph, m.module, transformedN) + transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN) if m.hcrOn: addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 9b871a898..a0c16f2ed 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -107,11 +107,11 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = s.ast[resultPos] = newNodeI(nkEmpty, s.info) s.ast[dispatcherPos] = dispatcher -proc createDispatcher(s: PSym): PSym = - var disp = copySym(s) +proc createDispatcher(s: PSym; idgen: IdGenerator): PSym = + var disp = copySym(s, nextId(idgen)) incl(disp.flags, sfDispatcher) excl(disp.flags, sfExported) - disp.typ = copyType(disp.typ, disp.typ.owner, false) + disp.typ = copyType(disp.typ, nextId(idgen), disp.typ.owner) # we can't inline the dispatcher itself (for now): if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall disp.ast = copyTree(s.ast) @@ -119,7 +119,7 @@ proc createDispatcher(s: PSym): PSym = disp.loc.r = nil if s.typ[0] != nil: if disp.ast.len > resultPos: - disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym) + disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextId(idgen)) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will @@ -157,7 +157,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = if disp.typ.lockLevel < meth.typ.lockLevel: disp.typ.lockLevel = meth.typ.lockLevel -proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) = +proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym, fromCache: bool) = var witness: PSym for i in 0..= 0: result = newNodeI(nkStmtList, n.info) for i in countdown(c.finallys.high, fin): - var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info) + var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info, idgen: c.idgen) result.add freshVars(preprocess(c, c.finallys[i]), vars) + c.idgen = vars.idgen result.add n of nkSkip: discard else: for i in 0 ..< n.len: result[i] = preprocess(c, n[i]) -proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode = +proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: PNode): PNode = var ctx: Ctx ctx.g = g ctx.fn = fn + ctx.idgen = idgen if getEnvParam(fn).isNil: # Lambda lifting was not done yet. Use temporary :state sym, which will # be handled specially by lambda lifting. Local temp vars (if needed) # should follow the same logic. - ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info) - ctx.stateVarSym.typ = g.createClosureIterStateType(fn) - ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info) - var pc = PreprocessContext(finallys: @[], config: g.config) + ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextId(idgen), fn, fn.info) + ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen) + ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextId(idgen), fn, fn.info) + var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen) var n = preprocess(pc, n.toStmtList) #echo "transformed into ", n #var n = n.toStmtList diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index 5fb8ab471..a415afce9 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -59,7 +59,7 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi graph: ModuleGraph): bool = if self.suggestMode: conf.command = "nimsuggest" - loadConfigs(DefaultConfig, cache, conf) # load all config files + loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files if not self.suggestMode: let scriptFile = conf.projectFull.changeFileExt("nims") diff --git a/compiler/depends.nim b/compiler/depends.nim index cc385da4b..7225b6b47 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -54,7 +54,7 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) = when not defined(nimHasSinkInference): {.pragma: nosinks.} -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = +proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = var g: PGen new(g) g.module = module diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 9cb40a7fc..cfbb33156 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -68,10 +68,10 @@ template myOpenImpl(ext: untyped) {.dirty.} = g.doc = d result = g -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = myOpenImpl(HtmlExt) -proc myOpenJson(graph: ModuleGraph; module: PSym): PPassContext = +proc myOpenJson(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = myOpenImpl(JsonExt) const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close) diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 3eb703ade..3274462d7 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -1,16 +1,16 @@ import ast, idents, lineinfos, modulegraphs, magicsys -proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym = - result = newSym(skProc, getIdent(g.cache, "$"), t.owner, info) +proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = + result = newSym(skProc, getIdent(g.cache, "$"), nextId idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), nextId idgen, result, info) dest.typ = t - let res = newSym(skResult, getIdent(g.cache, "result"), result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), nextId idgen, result, info) res.typ = getSysType(g, info, tyString) - result.typ = newType(tyProc, t.owner) + result.typ = newType(tyProc, nextId idgen, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) @@ -62,16 +62,16 @@ proc searchObjCase(t: PType; field: PSym): PNode = result = searchObjCase(t[0].skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field) doAssert result != nil -proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph): PSym = - result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), t.owner, info) +proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = + result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextId idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), nextId idgen, result, info) dest.typ = field.typ - let res = newSym(skResult, getIdent(g.cache, "result"), result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), nextId idgen, result, info) res.typ = getSysType(g, info, tyUInt8) - result.typ = newType(tyProc, t.owner) + result.typ = newType(tyProc, nextId idgen, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index c1024e2fe..218a597d8 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -22,6 +22,7 @@ type config: ConfigRef ic: IdentCache instID: int + idgen: IdGenerator proc copyNode(ctx: TemplCtx, a, b: PNode): PNode = result = copyNode(a) @@ -48,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: - x = copySym(s) + x = copySym(s, nextId(c.idgen)) # sem'check needs to set the owner properly later, see bug #9476 x.owner = nil # c.genSymOwner #if x.kind == skParam and x.owner.kind == skModule: @@ -168,6 +169,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; conf: ConfigRef; ic: IdentCache; instID: ref int; + idgen: IdGenerator; fromHlo=false): PNode = inc(conf.evalTemplateCounter) if conf.evalTemplateCounter > evalTemplateLimit: @@ -183,6 +185,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; ctx.ic = ic initIdTable(ctx.mapping) ctx.instID = instID[] + ctx.idgen = idgen let body = tmpl.getBody #echo "instantion of ", renderTree(body, {renderIds}) diff --git a/compiler/guards.nim b/compiler/guards.nim index a6ca44978..4f07df201 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -993,8 +993,9 @@ proc addFactLt*(m: var TModel; a, b: PNode) = addFactLe(m, a, bb) proc settype(n: PNode): PType = - result = newType(tySet, n.typ.owner) - addSonSkipIntLit(result, n.typ) + result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner) + var idgen: IdGenerator + addSonSkipIntLit(result, n.typ, idgen) proc buildOf(it, loc: PNode; o: Operators): PNode = var s = newNodeI(nkCurly, it.info, it.len-1) diff --git a/compiler/hlo.nim b/compiler/hlo.nim index bb69a1477..af54cabbb 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -86,9 +86,9 @@ proc hlo(c: PContext, n: PNode): PNode = else: result = fitNode(c, n.typ, result, n.info) # optimization has been applied so check again: - result = commonOptimizations(c.graph, c.module, result) + result = commonOptimizations(c.graph, c.idgen, c.module, result) result = hlo(c, result) - result = commonOptimizations(c.graph, c.module, result) + result = commonOptimizations(c.graph, c.idgen, c.module, result) proc hloBody(c: PContext, n: PNode): PNode = # fast exit: diff --git a/compiler/idents.nim b/compiler/idents.nim index a035974f3..b621503ec 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -15,12 +15,9 @@ import hashes, wordrecg type - TIdObj* = object of RootObj - id*: int # unique id; use this for comparisons and not the pointers - - PIdObj* = ref TIdObj PIdent* = ref TIdent - TIdent*{.acyclic.} = object of TIdObj + TIdent*{.acyclic.} = object + id*: int # unique id; use this for comparisons and not the pointers s*: string next*: PIdent # for hash-table chaining h*: Hash # hash value of s diff --git a/compiler/idgen.nim b/compiler/idgen.nim deleted file mode 100644 index 7d49e33e3..000000000 --- a/compiler/idgen.nim +++ /dev/null @@ -1,59 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module contains a simple persistent id generator. - -import idents, strutils, options, pathutils - -var gFrontEndId*: int - -const - debugIds* = false - -when debugIds: - import intsets - - var usedIds = initIntSet() - -proc registerID*(id: PIdObj) = - when debugIds: - if id.id == -1 or containsOrIncl(usedIds, id.id): - internalError("ID already used: " & $id.id) - -proc getID*(): int {.inline.} = - result = gFrontEndId - inc(gFrontEndId) - -proc setId*(id: int) {.inline.} = - gFrontEndId = max(gFrontEndId, id + 1) - -proc idSynchronizationPoint*(idRange: int) = - gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1 - -proc toGid(conf: ConfigRef; f: AbsoluteFile): string = - # we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this - # will cause strange bugs if multiple projects are in the same folder, so - # we simply use a project independent name: - result = options.completeGeneratedFilePath(conf, AbsoluteFile"nim.gid").string - -proc saveMaxIds*(conf: ConfigRef; project: AbsoluteFile) = - var f = open(toGid(conf, project), fmWrite) - f.writeLine($gFrontEndId) - f.close() - -proc loadMaxIds*(conf: ConfigRef; project: AbsoluteFile) = - var f: File - if open(f, toGid(conf, project), fmRead): - var line = newStringOfCap(20) - if f.readLine(line): - var frontEndId = parseInt(line) - if f.readLine(line): - # var backEndId = parseInt(line) - gFrontEndId = max(gFrontEndId, frontEndId) - f.close() diff --git a/compiler/importer.nim b/compiler/importer.nim index 34e76d7d9..6722eab15 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -136,7 +136,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym = localError(c.config, n.info, "module alias must be an identifier") elif n[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... - result = createModuleAlias(realModule, n[1].ident, realModule.info, + result = createModuleAlias(realModule, nextId c.idgen, n[1].ident, realModule.info, c.config.options) proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index ea90299e2..0b893ede8 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -40,6 +40,7 @@ type inLoop, inSpawn: int uninit: IntSet # set of uninit'ed vars uninitComputed: bool + idgen: IdGenerator ProcessMode = enum normal @@ -61,7 +62,7 @@ template dbg(body) = body proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = - let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextId c.idgen, c.owner, info) sym.typ = typ s.vars.add(sym) result = newSymNode(sym) @@ -250,16 +251,16 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = m.add c.owner.name.s localError(c.graph.config, ri.info, errGenerated, m) -proc makePtrType(c: Con, baseType: PType): PType = - result = newType(tyPtr, c.owner) - addSonSkipIntLit(result, baseType) +proc makePtrType(c: var Con, baseType: PType): PType = + result = newType(tyPtr, nextId c.idgen, c.owner) + addSonSkipIntLit(result, baseType, c.idgen) -proc genOp(c: Con; op: PSym; dest: PNode): PNode = +proc genOp(c: var Con; op: PSym; dest: PNode): PNode = let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) addrExp.add(dest) result = newTree(nkCall, newSymNode(op), addrExp) -proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = +proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = var op = t.attachedOps[kind] if op == nil or op.ast[genericParamsPos].kind != nkEmpty: # give up and find the canonical type instead: @@ -280,7 +281,7 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind]) c.genOp(op, dest) -proc genDestroy(c: Con; dest: PNode): PNode = +proc genDestroy(c: var Con; dest: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) result = c.genOp(t, attachedDestructor, dest, nil) @@ -310,7 +311,7 @@ proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = # and copyMem(dest, source). This is efficient. result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri)) -proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode = +proc genCopyNoCheck(c: var Con; dest, ri: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) result = c.genOp(t, attachedAsgn, dest, ri) @@ -346,7 +347,7 @@ It is best to factor out piece of object that needs custom destructor into separ return # generate: if le != tmp: `=destroy`(le) - let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info) + let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen) let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool)) cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info)) cond.add le @@ -377,7 +378,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) - var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info) + var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextId c.idgen, c.owner, n.info) temp.typ = n.typ var v = newNodeI(nkLetSection, n.info) let tempAsNode = newSymNode(temp) @@ -799,7 +800,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = for it in n: var ri = it[^1] if it.kind == nkVarTuple and hasDestructor(c, ri.typ): - let x = lowerTupleUnpacking(c.graph, it, c.owner) + let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner) result.add p(x, c, s, consumed) elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c): for j in 0..> $2)", "($1 >> $2)") else: @@ -1804,7 +1804,7 @@ proc genVarStmt(p: PProc, n: PNode) = var a = n[i] if a.kind != nkCommentStmt: if a.kind == nkVarTuple: - let unpacked = lowerTupleUnpacking(p.module.graph, a, p.prc) + let unpacked = lowerTupleUnpacking(p.module.graph, a, p.module.idgen, p.prc) genStmt(p, unpacked) else: assert(a.kind == nkIdentDefs) @@ -2316,9 +2316,9 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = else: returnStmt = "return $#;$n" % [a.res] - var transformedBody = transformBody(oldProc.module.graph, prc, cache = false) + var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, cache = false) if sfInjectDestructors in prc.flags: - transformedBody = injectDestructorCalls(oldProc.module.graph, prc, transformedBody) + transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody) p.nested: genStmt(p, transformedBody) @@ -2607,9 +2607,9 @@ proc genModule(p: PProc, n: PNode) = p.body.add(frameCreate(p, makeJSString("module " & p.module.module.name.s), makeJSString(toFilenameOption(p.config, p.module.module.info.fileIndex, foStacktrace)))) - var transformedN = transformStmt(p.module.graph, p.module.module, n) + var transformedN = transformStmt(p.module.graph, p.module.idgen, p.module.module, n) if sfInjectDestructors in p.module.module.flags: - transformedN = injectDestructorCalls(p.module.graph, p.module.module, transformedN) + transformedN = injectDestructorCalls(p.module.graph, p.module.idgen, p.module.module, transformedN) if p.config.hcrOn and n.kind == nkStmtList: let moduleSym = p.module.module var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" & @@ -2686,7 +2686,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = writeFile(outFile.string & ".map", $(%map)) discard writeRopeIfNotEqual(code, outFile) -proc myOpen(graph: ModuleGraph; s: PSym): PPassContext = + +proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = result = newModule(graph, s) + result.idgen = idgen const JSgenPass* = makePass(myOpen, myProcess, myClose) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c23ca52cb..b552d9455 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -126,32 +126,32 @@ proc newCall(a: PSym, b: PNode): PNode = result.add newSymNode(a) result.add b -proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType = +proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PType = var n = newNodeI(nkRange, iter.info) n.add newIntNode(nkIntLit, -1) n.add newIntNode(nkIntLit, 0) - result = newType(tyRange, iter) + result = newType(tyRange, nextId(idgen), iter) result.n = n var intType = nilOrSysInt(g) - if intType.isNil: intType = newType(tyInt, iter) + if intType.isNil: intType = newType(tyInt, nextId(idgen), iter) rawAddSon(result, intType) -proc createStateField(g: ModuleGraph; iter: PSym): PSym = - result = newSym(skField, getIdent(g.cache, ":state"), iter, iter.info) - result.typ = createClosureIterStateType(g, iter) +proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = + result = newSym(skField, getIdent(g.cache, ":state"), nextId(idgen), iter, iter.info) + result.typ = createClosureIterStateType(g, iter, idgen) -proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType = +proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = # YYY meh, just add the state field for every closure for now, it's too # hard to figure out if it comes from a closure iterator: - result = createObj(g, owner, info, final=false) - rawAddField(result, createStateField(g, owner)) + result = createObj(g, idgen, owner, info, final=false) + rawAddField(result, createStateField(g, owner, idgen)) -proc getClosureIterResult*(g: ModuleGraph; iter: PSym): PSym = +proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = if resultPos < iter.ast.len: result = iter.ast[resultPos].sym else: # XXX a bit hacky: - result = newSym(skResult, getIdent(g.cache, ":result"), iter, iter.info, {}) + result = newSym(skResult, getIdent(g.cache, ":result"), nextId(idgen), iter, iter.info, {}) result.typ = iter.typ[0] incl(result.flags, sfUsed) iter.ast.add newSymNode(result) @@ -209,7 +209,7 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = result[0] = le result[1] = ri -proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode = +proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; info: TLineInfo): PNode = result = newNodeIT(nkClosure, info, prc.typ) result.add(newSymNode(prc)) if env == nil: @@ -219,7 +219,7 @@ proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode localError(g.config, info, "internal error: taking closure of closure") result.add(env) #if isClosureIterator(result.typ): - createTypeBoundOps(g, nil, result.typ, info) + createTypeBoundOps(g, nil, result.typ, info, idgen) if tfHasAsgn in result.typ.flags or optSeqDestructors in g.config.globalOptions: prc.flags.incl sfInjectDestructors @@ -237,13 +237,13 @@ proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro result = conf.backend == backendJs and not isCompileTime -proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; owner: PSym) = - createTypeBoundOps(g, nil, refType.lastSon, info) - createTypeBoundOps(g, nil, refType, info) +proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) = + createTypeBoundOps(g, nil, refType.lastSon, info, idgen) + createTypeBoundOps(g, nil, refType, info, idgen) if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions: owner.flags.incl sfInjectDestructors -proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = +proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) if liftingHarmful(g.config, owner): return n let iter = n.sym @@ -255,10 +255,10 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = var env: PNode if owner.isIterator: let it = getHiddenParam(g, owner) - addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache) + addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen) env = indirectAccess(newSymNode(it), hp, hp.info) else: - let e = newSym(skLet, iter.name, owner, n.info) + let e = newSym(skLet, iter.name, nextId(idgen), owner, n.info) e.typ = hp.typ e.flags = hp.flags env = newSymNode(e) @@ -267,13 +267,13 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = result.add(v) # add 'new' statement: result.add newCall(getSysSym(g, n.info, "internalNew"), env) - createTypeBoundOpsLL(g, env.typ, n.info, owner) - result.add makeClosure(g, iter, env, n.info) + createTypeBoundOpsLL(g, env.typ, n.info, idgen, owner) + result.add makeClosure(g, idgen, iter, env, n.info) -proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode = +proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: PSym): PNode = let envParam = getHiddenParam(g, owner) let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr}) - addField(obj, s, g.cache) + addField(obj, s, g.cache, idgen) var access = newSymNode(envParam) assert obj.kind == tyObject @@ -305,13 +305,15 @@ type ownerToType: Table[int, PType] somethingToDo: bool graph: ModuleGraph + idgen: IdGenerator -proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass = +proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass = result.processed = initIntSet() result.capturedVars = initIntSet() result.ownerToType = initTable[int, PType]() result.processed.incl(fn.id) result.graph = g + result.idgen = idgen discard """ proc outer = @@ -327,15 +329,15 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = result = c.ownerToType.getOrDefault(owner.id) if result.isNil: - result = newType(tyRef, owner) - let obj = createEnvObj(c.graph, owner, info) + result = newType(tyRef, nextId(c.idgen), owner) + let obj = createEnvObj(c.graph, c.idgen, owner, info) rawAddSon(result, obj) c.ownerToType[owner.id] = result -proc asOwnedRef(c: DetectionPass; t: PType): PType = +proc asOwnedRef(c: var DetectionPass; t: PType): PType = if optOwnedRefs in c.graph.config.globalOptions: assert t.kind == tyRef - result = newType(tyOwned, t.owner) + result = newType(tyOwned, nextId(c.idgen), t.owner) result.flags.incl tfHasOwned result.rawAddSon t else: @@ -344,7 +346,7 @@ proc asOwnedRef(c: DetectionPass; t: PType): PType = proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = var r = c.getEnvTypeForOwner(owner, info) - result = newType(tyPtr, owner) + result = newType(tyPtr, nextId(c.idgen), owner) rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr})) proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = @@ -372,7 +374,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags: localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor") else: - let result = newSym(skField, upIdent, obj.owner, obj.owner.info) + let result = newSym(skField, upIdent, nextId(c.idgen), obj.owner, obj.owner.info) result.typ = fieldType when false: if c.graph.config.selectedGC == gcDestructors: @@ -410,7 +412,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner let t = c.getEnvTypeForOwner(owner, info) if cp == nil: - cp = newSym(skParam, getIdent(c.graph.cache, paramName), fn, fn.info) + cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextId(c.idgen), fn, fn.info) incl(cp.flags, sfFromGeneric) cp.typ = t addHiddenParam(fn, cp) @@ -433,7 +435,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if innerProc: if s.isIterator: c.somethingToDo = true if not c.processed.containsOrIncl(s.id): - let body = transformBody(c.graph, s, cache = true) + let body = transformBody(c.graph, c.idgen, s, cache = true) detectCapturedVars(body, s, c) let ow = s.skipGenericOwner if ow == owner: @@ -446,9 +448,9 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = #let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr}) if s.name.id == getIdent(c.graph.cache, ":state").id: - obj.n[0].sym.id = -s.id + obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) else: - addField(obj, s, c.graph.cache) + addField(obj, s, c.graph.cache, c.idgen) # direct or indirect dependency: elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s): discard """ @@ -470,7 +472,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr}) #getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) - addField(obj, s, c.graph.cache) + addField(obj, s, c.graph.cache, c.idgen) # create required upFields: var w = owner.skipGenericOwner if isInnerProc(w) or owner.isIterator: @@ -535,8 +537,8 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = localError(g.config, n.info, "internal error: environment misses: " & s.name.s) result = n -proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNode = - var v = newSym(skVar, getIdent(cache, envName), owner, info) +proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode = + var v = newSym(skVar, getIdent(cache, envName), nextId(idgen), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = typ result = newSymNode(v) @@ -548,7 +550,7 @@ proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNo else: result = newSymNode(v) -proc setupEnvVar(owner: PSym; d: DetectionPass; +proc setupEnvVar(owner: PSym; d: var DetectionPass; c: var LiftingPass; info: TLineInfo): PNode = if owner.isIterator: return getHiddenParam(d.graph, owner).newSymNode @@ -557,10 +559,10 @@ proc setupEnvVar(owner: PSym; d: DetectionPass; let envVarType = d.ownerToType.getOrDefault(owner.id) if envVarType.isNil: localError d.graph.config, owner.info, "internal error: could not determine closure type" - result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info) + result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen) c.envVars[owner.id] = result if optOwnedRefs in d.graph.config.globalOptions: - var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), owner, info) + var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextId d.idgen, owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType c.unownedEnvVars[owner.id] = newSymNode(v) @@ -576,7 +578,7 @@ proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode = result = rawIndirectAccess(result, upField, p.info) proc rawClosureCreation(owner: PSym; - d: DetectionPass; c: var LiftingPass; + d: var DetectionPass; c: var LiftingPass; info: TLineInfo): PNode = result = newNodeI(nkStmtList, owner.info) @@ -602,7 +604,7 @@ proc rawClosureCreation(owner: PSym; let env2 = copyTree(env) env2.typ = unowned.typ result.add newAsgnStmt(unowned, env2, env.info) - createTypeBoundOpsLL(d.graph, unowned.typ, env.info, owner) + createTypeBoundOpsLL(d.graph, unowned.typ, env.info, d.idgen, owner) # add assignment statements for captured parameters: for i in 1..= 0 or isDefined(graph.config, "nimBackendAssumesChange") -proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} = +proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; + stream: PLLStream): bool {.discardable.} = if graph.stopCompile(): return true var p: Parser @@ -135,7 +123,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool { # new module caching mechanism: for i in 0.. evalTemplateLimit: globalError(c.config, s.info, "template instantiation too nested") c.friendModules.add(s.owner.getModule) - idSynchronizationPoint(5000) result = macroResult resetSemFlag result if s.typ[0] == nil: @@ -469,7 +468,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, c.graph, c.templInstCounter, n, nOrig, sym) + result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) if c.config.macrosToExpand.hasKey(sym.name.s): @@ -502,8 +501,9 @@ proc addCodeForGenerics(c: PContext, n: PNode) = n.add prc.ast c.lastGenericIdx = c.generics.len -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = +proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = var c = newContext(graph, module) + c.idgen = idgen if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 50df1085f..dd2398f87 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -688,9 +688,9 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = var x: PType if param.typ.kind == tyVar: x = newTypeS(param.typ.kind, c) - x.addSonSkipIntLit t.baseOfDistinct + x.addSonSkipIntLit(t.baseOfDistinct(c.idgen), c.idgen) else: - x = t.baseOfDistinct + x = t.baseOfDistinct(c.idgen) call.add(newNodeIT(nkEmpty, fn.info, x)) if hasDistinct: let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind} diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b15f65967..8d1c25e4d 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -277,14 +277,14 @@ proc addToLib*(lib: PLib, sym: PSym) = sym.annex = lib proc newTypeS*(kind: TTypeKind, c: PContext): PType = - result = newType(kind, getCurrOwner(c)) + result = newType(kind, nextId(c.idgen), getCurrOwner(c)) -proc makePtrType*(owner: PSym, baseType: PType): PType = - result = newType(tyPtr, owner) - addSonSkipIntLit(result, baseType) +proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType = + result = newType(tyPtr, nextId(idgen), owner) + addSonSkipIntLit(result, baseType, idgen) proc makePtrType*(c: PContext, baseType: PType): PType = - makePtrType(getCurrOwner(c), baseType) + makePtrType(getCurrOwner(c), baseType, c.idgen) proc makeTypeWithModifier*(c: PContext, modifier: TTypeKind, @@ -295,21 +295,21 @@ proc makeTypeWithModifier*(c: PContext, result = baseType else: result = newTypeS(modifier, c) - addSonSkipIntLit(result, baseType) + addSonSkipIntLit(result, baseType, c.idgen) proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType = if baseType.kind == kind: result = baseType else: result = newTypeS(kind, c) - addSonSkipIntLit(result, baseType) + addSonSkipIntLit(result, baseType, c.idgen) -proc makeVarType*(owner: PSym, baseType: PType; kind = tyVar): PType = +proc makeVarType*(owner: PSym, baseType: PType; idgen: IdGenerator; kind = tyVar): PType = if baseType.kind == kind: result = baseType else: - result = newType(kind, owner) - addSonSkipIntLit(result, baseType) + result = newType(kind, nextId(idgen), owner) + addSonSkipIntLit(result, baseType, idgen) proc makeTypeDesc*(c: PContext, typ: PType): PType = if typ.kind == tyTypeDesc: @@ -317,14 +317,14 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = else: result = newTypeS(tyTypeDesc, c) incl result.flags, tfCheckedForDestructor - result.addSonSkipIntLit(typ) + result.addSonSkipIntLit(typ, c.idgen) proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = newTypeS(tyTypeDesc, c) incl typedesc.flags, tfCheckedForDestructor internalAssert(c.config, typ != nil) - typedesc.addSonSkipIntLit(typ) - let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info, + typedesc.addSonSkipIntLit(typ, c.idgen) + let sym = newSym(skType, c.cache.idAnon, nextId(c.idgen), getCurrOwner(c), info, c.config.options).linkTo(typedesc) return newSymNode(sym, info) @@ -333,13 +333,14 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType = assert n != nil result.n = n -proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]): PType = - result = newType(kind, owner) +proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]; + idgen: IdGenerator): PType = + result = newType(kind, nextId(idgen), owner) result.sons = sons proc newTypeWithSons*(c: PContext, kind: TTypeKind, sons: seq[PType]): PType = - result = newType(kind, getCurrOwner(c)) + result = newType(kind, nextId(c.idgen), getCurrOwner(c)) result.sons = sons proc makeStaticExpr*(c: PContext, n: PNode): PNode = @@ -418,7 +419,7 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt; n.add newIntTypeNode(last, intType) result = newTypeS(tyRange, c) result.n = n - addSonSkipIntLit(result, intType) # basetype of range + addSonSkipIntLit(result, intType, c.idgen) # basetype of range proc markIndirect*(c: PContext, s: PSym) {.inline.} = if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cb852c68a..2de25dadb 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -33,7 +33,8 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, # Note: This is n.info on purpose. It prevents template from creating an info # context when called from an another template pushInfoContext(c.config, n.info, s.detailedInfo) - result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, c.templInstCounter, efFromHlo in flags) + result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, + c.templInstCounter, c.idgen, efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) popInfoContext(c.config) @@ -384,7 +385,7 @@ proc fixupStaticType(c: PContext, n: PNode) = # apply this measure only in code that is enlightened to work # with static types. if n.typ.kind != tyStatic: - n.typ = newTypeWithSons(getCurrOwner(c), tyStatic, @[n.typ]) + n.typ = newTypeWithSons(getCurrOwner(c), tyStatic, @[n.typ], c.idgen) n.typ.n = n # XXX: cycles like the one here look dangerous. # Consider using `n.copyTree` @@ -555,7 +556,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType = rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype! else: var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) - addSonSkipIntLit(typ, t) + addSonSkipIntLit(typ, t, c.idgen) typ[0] = makeRangeType(c, 0, n.len - 1, n.info) result = typ @@ -605,11 +606,11 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = let xx = semExprWithType(c, x, flags*{efAllowDestructor}) result.add xx - typ = commonType(typ, xx.typ) + typ = commonType(c, typ, xx.typ) #n[i] = semExprWithType(c, x, flags*{efAllowDestructor}) #result.add fitNode(c, typ, n[i]) inc(lastIndex) - addSonSkipIntLit(result.typ, typ) + addSonSkipIntLit(result.typ, typ, c.idgen) for i in 0.. MaxSetElements: typ = makeRangeType(c, 0, MaxSetElements-1, n.info) - addSonSkipIntLit(result.typ, typ) + addSonSkipIntLit(result.typ, typ, c.idgen) for i in 0.. 2: - b = getConstExpr(m, n[2], g) + b = getConstExpr(m, n[2], idgen, g) if b == nil: return if n.len > 3: - c = getConstExpr(m, n[3], g) + c = getConstExpr(m, n[3], idgen, g) if c == nil: return result = evalOp(s.magic, n, a, b, c, g) @@ -451,19 +412,19 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = result = a result.typ = n.typ -proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode = +proc getArrayConstr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = if n.kind == nkBracket: result = n else: - result = getConstExpr(m, n, g) + result = getConstExpr(m, n, idgen, g) if result == nil: result = n -proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = - var x = getConstExpr(m, n[0], g) +proc foldArrayAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = + var x = getConstExpr(m, n[0], idgen, g) if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc: return - var y = getConstExpr(m, n[1], g) + var y = getConstExpr(m, n[1], idgen, g) if y == nil: return var idx = toInt64(getOrdValue(y)) @@ -486,9 +447,9 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n) else: discard -proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = +proc foldFieldAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = # a real field access; proc calls have already been transformed - var x = getConstExpr(m, n[0], g) + var x = getConstExpr(m, n[0], idgen, g) if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return var field = n[1].sym @@ -504,23 +465,23 @@ proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = return localError(g.config, n.info, "field not found: " & field.name.s) -proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode = +proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = result = newNodeIT(nkStrLit, n.info, n.typ) result.strVal = "" for i in 1.. 2 and operand2.kind == tyGenericParam): return traitCall ## too early to evaluate @@ -160,19 +160,19 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) result.info = traitCall.info of "arity": result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc)) - result.typ = newType(tyInt, context) + result.typ = newType(tyInt, nextId c.idgen, context) result.info = traitCall.info of "genericHead": var arg = operand case arg.kind of tyGenericInst: - result = getTypeDescNode(arg.base, operand.owner, traitCall.info) + result = getTypeDescNode(c, arg.base, operand.owner, traitCall.info) # of tySequence: # this doesn't work # var resType = newType(tySequence, operand.owner) # result = toNode(resType, traitCall.info) # doesn't work yet else: localError(c.config, traitCall.info, "expected generic type, got: type $2 of kind $1" % [arg.kind.toHumanStr, typeToString(operand)]) - result = newType(tyError, context).toNode(traitCall.info) + result = newType(tyError, nextId c.idgen, context).toNode(traitCall.info) of "stripGenericParams": result = uninstantiate(operand).toNode(traitCall.info) of "supportsCopyMem": @@ -194,11 +194,11 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) while arg.kind == tyDistinct: arg = arg.base arg = arg.skipTypes(skippedTypes + {tyGenericInst}) - result = getTypeDescNode(arg, operand.owner, traitCall.info) + result = getTypeDescNode(c, arg, operand.owner, traitCall.info) else: localError(c.config, traitCall.info, "distinctBase expects a distinct type as argument. The given type was " & typeToString(operand)) - result = newType(tyError, context).toNode(traitCall.info) + result = newType(tyError, nextId c.idgen, context).toNode(traitCall.info) else: localError(c.config, traitCall.info, "unknown trait: " & s) result = newNodeI(nkEmpty, traitCall.info) @@ -286,7 +286,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode = return semBindSym(c, n) if c.graph.vm.isNil: - setupGlobalCtx(c.module, c.graph) + setupGlobalCtx(c.module, c.graph, c.idgen) let vm = PCtx c.graph.vm @@ -370,7 +370,7 @@ proc semUnown(c: PContext; n: PNode): PNode = elems[i] = unownedType(c, t[i]) if elems[i] != t[i]: someChange = true if someChange: - result = newType(tyTuple, t.owner) + result = newType(tyTuple, nextId c.idgen, t.owner) # we have to use 'rawAddSon' here so that type flags are # properly computed: for e in elems: result.rawAddSon(e) @@ -381,7 +381,7 @@ proc semUnown(c: PContext; n: PNode): PNode = tyGenericInst, tyAlias: let b = unownedType(c, t[^1]) if b != t[^1]: - result = copyType(t, t.owner, keepId = false) + result = copyType(t, nextId c.idgen, t.owner) result[^1] = b result.flags.excl tfHasOwned else: @@ -399,7 +399,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym # Replace nkDerefExpr by nkHiddenDeref # nkDeref is for 'ref T': x[].field # nkHiddenDeref is for 'var T': x.field - proc transform(procSym: PSym; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode = + proc transform(c: PContext; procSym: PSym; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode = result = shallowCopy(n) if sameTypeOrNil(n.typ, old): result.typ = fresh @@ -407,26 +407,26 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym if n.sym == oldParam: result.sym = newParam elif n.sym.owner == orig: - result.sym = copySym(n.sym) + result.sym = copySym(n.sym, nextId c.idgen) result.sym.owner = procSym for i in 0 ..< safeLen(n): - result[i] = transform(procSym, n[i], old, fresh, oldParam, newParam) + result[i] = transform(c, procSym, n[i], old, fresh, oldParam, newParam) #if n.kind == nkDerefExpr and sameType(n[0].typ, old): # result = - result = copySym(orig) + result = copySym(orig, nextId c.idgen) result.info = info result.flags.incl sfFromGeneric result.owner = orig let origParamType = orig.typ[1] - let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs)) + let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen) let oldParam = orig.typ.n[1].sym - let newParam = newSym(skParam, oldParam.name, result, result.info) + let newParam = newSym(skParam, oldParam.name, nextId c.idgen, result, result.info) newParam.typ = newParamType # proc body: - result.ast = transform(result, orig.ast, origParamType, newParamType, oldParam, newParam) + result.ast = transform(c, result, orig.ast, origParamType, newParamType, oldParam, newParam) # proc signature: - result.typ = newProcType(result.info, result) + result.typ = newProcType(result.info, nextId c.idgen, result) result.typ.addParam newParam proc semQuantifier(c: PContext; n: PNode): PNode = diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 578687e6c..82fb069db 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -416,13 +416,13 @@ proc transformSlices(g: ModuleGraph; n: PNode): PNode = else: result = n -proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode -proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode = +proc transformSpawn(g: ModuleGraph; idgen: IdGenerator;owner: PSym; n, barrier: PNode): PNode +proc transformSpawnSons(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier: PNode): PNode = result = shallowCopy(n) for i in 0.. 0: - result = transformSpawnSons(g, owner, n, barrier) + result = transformSpawnSons(g, idgen, owner, n, barrier) else: result = n @@ -464,7 +464,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) = proc generateAliasChecks(a: AnalysisCtx; result: PNode) = discard "too implement" -proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode = +proc liftParallel*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): PNode = # this needs to be called after the 'for' loop elimination # first pass: @@ -482,16 +482,16 @@ proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode = checkArgs(a, body) var varSection = newNodeI(nkVarSection, n.info) - var temp = newSym(skTemp, getIdent(g.cache, "barrier"), owner, n.info) + var temp = newSym(skTemp, getIdent(g.cache, "barrier"), nextId idgen, owner, n.info) temp.typ = magicsys.getCompilerProc(g, "Barrier").typ incl(temp.flags, sfFromGeneric) let tempNode = newSymNode(temp) varSection.addVar tempNode - let barrier = genAddrOf(tempNode) + let barrier = genAddrOf(tempNode, idgen) result = newNodeI(nkStmtList, n.info) generateAliasChecks(a, result) result.add varSection result.add callCodegenProc(g, "openBarrier", barrier.info, barrier) - result.add transformSpawn(g, owner, body, barrier) + result.add transformSpawn(g, idgen, owner, body, barrier) result.add callCodegenProc(g, "closeBarrier", barrier.info, barrier) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 352871412..92a896a38 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -92,7 +92,7 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = optSeqDestructors in tracked.config.globalOptions: createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info) - createTypeBoundOps(tracked.graph, tracked.c, typ, info) + createTypeBoundOps(tracked.graph, tracked.c, typ, info, tracked.c.idgen) if (tfHasAsgn in typ.flags) or optSeqDestructors in tracked.config.globalOptions: tracked.owner.flags.incl sfInjectDestructors @@ -219,7 +219,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = if reason.kind == nkSym: a.owner.gcUnsafetyReason = reason.sym else: - a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, + a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, nextId a.c.idgen, a.owner, reason.info, {}) when true: @@ -755,7 +755,7 @@ proc trackCall(tracked: PEffects; n: PNode) = if n.typ != nil: if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray: createTypeBoundOps(tracked, n.typ, n.info) - if getConstExpr(tracked.ownerModule, n, tracked.graph) != nil: + if getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) != nil: return if a.kind == nkCast and a[1].typ.kind == tyProc: a = a[1] @@ -829,7 +829,7 @@ proc trackCall(tracked: PEffects; n: PNode) = case op[i].kind of tySink: createTypeBoundOps(tracked, op[i][0], n.info) - checkForSink(tracked.config, tracked.owner, n[i]) + checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n[i]) of tyVar: tracked.hasDangerousAssign = true #of tyOut: @@ -947,7 +947,7 @@ proc track(tracked: PEffects, n: PNode) = if tracked.owner.kind != skMacro: createTypeBoundOps(tracked, n[0].typ, n.info) if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym): - checkForSink(tracked.config, tracked.owner, n[1]) + checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n[1]) if not tracked.hasDangerousAssign and n[0].kind != nkSym: tracked.hasDangerousAssign = true of nkVarSection, nkLetSection: @@ -1054,9 +1054,9 @@ proc track(tracked: PEffects, n: PNode) = if x.kind == nkExprColonExpr: if x[0].kind == nkSym: notNilCheck(tracked, x[1], x[0].sym.typ) - checkForSink(tracked.config, tracked.owner, x[1]) + checkForSink(tracked.config, tracked.c.idgen, tracked.owner, x[1]) else: - checkForSink(tracked.config, tracked.owner, x) + checkForSink(tracked.config, tracked.c.idgen, tracked.owner, x) setLen(tracked.guards.s, oldFacts) if tracked.owner.kind != skMacro: # XXX n.typ can be nil in runnableExamples, we need to do something about it. @@ -1071,7 +1071,7 @@ proc track(tracked: PEffects, n: PNode) = createTypeBoundOps(tracked, n[i][0].typ, n.info) else: createTypeBoundOps(tracked, n[i].typ, n.info) - checkForSink(tracked.config, tracked.owner, n[i]) + checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n[i]) of nkPragmaBlock: let pragmaList = n[0] var bc = createBlockContext(tracked) @@ -1122,7 +1122,7 @@ proc track(tracked: PEffects, n: PNode) = of nkBracket: for i in 0.. 1: result.n = n[1] proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = @@ -217,7 +217,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = result.n = newNodeI(nkRange, n.info) # always create a 'valid' range type, but overwrite it later # because 'semExprWithType' can raise an exception. See bug #6895. - addSonSkipIntLit(result, errorType(c)) + addSonSkipIntLit(result, errorType(c), c.idgen) if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): localError(c.config, n.info, "range is empty") @@ -228,7 +228,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = var rangeT: array[2, PType] for i in 0..1: - rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit + rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit(c.idgen) let hasUnknownTypes = c.inGenericContext > 0 and rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr @@ -345,7 +345,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = # bug #6682: Do not propagate initialization requirements etc for the # index type: rawAddSonNoPropagationOfTypeFlags(result, indx) - addSonSkipIntLit(result, base) + addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errArrayExpectsTwoTypeParams) result = newOrPrevType(tyError, prev, c) @@ -357,7 +357,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = if base.kind != tyGenericParam: if not isOrdinalType(base): localError(c.config, n[1].info, errOrdinalTypeExpected) - addSonSkipIntLit(result, base) + addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal") result = newOrPrevType(tyError, prev, c) @@ -384,7 +384,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if result.typ.sym == nil: localError(c.config, n.info, errTypeExpected) return errorSym(c, n) - result = result.typ.sym.copySym + result = result.typ.sym.copySym(nextId c.idgen) result.typ = exactReplica(result.typ) result.typ.flags.incl tfUnresolved @@ -429,7 +429,7 @@ proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyTuple, prev, c) for it in n: - addSonSkipIntLit(result, semTypeNode(c, it, nil)) + addSonSkipIntLit(result, semTypeNode(c, it, nil), c.idgen) proc semTuple(c: PContext, n: PNode, prev: PType): PType = var typ: PType @@ -457,15 +457,13 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'") else: result.n.add newSymNode(field) - addSonSkipIntLit(result, typ) + addSonSkipIntLit(result, typ, c.idgen) styleCheckDef(c.config, a[j].info, field) onDef(field.info, field) if result.n.len == 0: result.n = nil if isTupleRecursive(result): localError(c.config, n.info, errIllegalRecursionInTypeX % typeToString(result)) - - proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = # identifier with visibility @@ -925,11 +923,11 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = elif region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin { tyError, tyObject}: message c.config, n[i].info, errGenerated, "region needs to be an object type" - addSonSkipIntLit(result, region) + addSonSkipIntLit(result, region, c.idgen) else: message(c.config, n.info, warnDeprecated, "region for pointer types is deprecated") - addSonSkipIntLit(result, region) - addSonSkipIntLit(result, t) + addSonSkipIntLit(result, region, c.idgen) + addSonSkipIntLit(result, t, c.idgen) if tfPartial in result.flags: if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial) #if not isNilable: result.flags.incl tfNotNil @@ -963,7 +961,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = if kind == skMacro: let staticType = findEnforcedStaticType(param.typ) if staticType != nil: - var a = copySym(param) + var a = copySym(param, nextId c.idgen) a.typ = staticType.base addDecl(c, a) #elif param.typ != nil and param.typ.kind == tyTypeDesc: @@ -971,7 +969,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = else: # within a macro, every param has the type NimNode! let nn = getSysSym(c.graph, param.info, "NimNode") - var a = copySym(param) + var a = copySym(param, nextId c.idgen) a.typ = nn.typ addDecl(c, a) else: @@ -1001,7 +999,7 @@ proc addImplicitGeneric(c: PContext; typeClass: PType, typId: PIdent; let owner = if typeClass.sym != nil: typeClass.sym else: getCurrOwner(c) - var s = newSym(skType, finalTypId, owner, info) + var s = newSym(skType, finalTypId, nextId c.idgen, owner, info) if sfExplain in owner.flags: s.flags.incl sfExplain if typId == nil: s.flags.incl(sfAnon) s.linkTo(typeClass) @@ -1107,7 +1105,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericInst: if paramType.lastSon.kind == tyUserTypeClass: - var cp = copyType(paramType, getCurrOwner(c), false) + var cp = copyType(paramType, nextId c.idgen, getCurrOwner(c)) cp.kind = tyUserTypeClassInst return addImplicitGeneric(c, cp, paramTypId, info, genericParams, paramName) @@ -1144,7 +1142,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyUserTypeClasses, tyBuiltInTypeClass, tyCompositeTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(c, - copyType(paramType, getCurrOwner(c), false), paramTypId, + copyType(paramType, nextId c.idgen, getCurrOwner(c)), paramTypId, info, genericParams, paramName) of tyGenericParam: @@ -1274,7 +1272,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, typ = errorType(c) let lifted = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info) - let finalType = if lifted != nil: lifted else: typ.skipIntLit + let finalType = if lifted != nil: lifted else: typ.skipIntLit(c.idgen) arg.typ = finalType arg.position = counter arg.constraint = constraint @@ -1331,7 +1329,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, #if r.kind != tyGenericParam: #echo "came here for ", typeToString(r) r.flags.incl tfRetType - r = skipIntLit(r) + r = skipIntLit(r, c.idgen) if kind == skIterator: # see tchainediterators # in cases like iterator foo(it: iterator): type(it) @@ -1413,13 +1411,13 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = t = t.base result = newOrPrevType(tyGenericInvocation, prev, c) - addSonSkipIntLit(result, t) + addSonSkipIntLit(result, t, c.idgen) template addToResult(typ) = if typ.isNil: internalAssert c.config, false rawAddSon(result, typ) - else: addSonSkipIntLit(result, typ) + else: addSonSkipIntLit(result, typ, c.idgen) if t.kind == tyForward: for i in 1.. 0: t.n[i].sym.typ = skipped @@ -553,7 +558,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = n.typ of tyInt, tyFloat: - result = skipIntLit(t) + result = skipIntLit(t, cl.c.idgen) of tyTypeDesc: let lookup = cl.typeMap.lookup(t) @@ -617,7 +622,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = of tyProc: eraseVoidParams(result) - skipIntLiteralParams(result) + skipIntLiteralParams(result, cl.c.idgen) of tyRange: result[0] = result[0].skipTypes({tyStatic, tyDistinct}) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 687634e93..2cf2846c0 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -143,7 +143,7 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} = writeStackTrace() if c.c.module.name.s == "temp3": echo "binding ", key, " -> ", val - idTablePut(c.bindings, key, val.skipIntLit) + idTablePut(c.bindings, key, val.skipIntLit(c.c.idgen)) proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1, @@ -726,7 +726,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = if alreadyBound != nil: typ = alreadyBound template paramSym(kind): untyped = - newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info, {}) + newSym(kind, typeParamName, nextId(c.idgen), typeClass.sym, typeClass.sym.info, {}) block addTypeParam: for prev in typeParams: @@ -739,6 +739,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = of tyStatic: param = paramSym skConst param.typ = typ.exactReplica + #copyType(typ, nextId(c.idgen), typ.owner) if typ.n == nil: param.typ.flags.incl tfInferrableStatic else: @@ -746,6 +747,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = of tyUnknown: param = paramSym skVar param.typ = typ.exactReplica + #copyType(typ, nextId(c.idgen), typ.owner) else: param = paramSym skType param.typ = if typ.isMetaType: @@ -796,7 +798,8 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = if ff.kind == tyUserTypeClassInst: result = generateTypeInstance(c, m.bindings, typeClass.sym.info, ff) else: - result = copyType(ff, ff.owner, true) + result = ff.exactReplica + #copyType(ff, nextId(c.idgen), ff.owner) result.n = checkedBody @@ -1086,7 +1089,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, template bindingRet(res) = if doBind: - let bound = aOrig.skipTypes({tyRange}).skipIntLit + let bound = aOrig.skipTypes({tyRange}).skipIntLit(c.c.idgen) put(c, f, bound) return res @@ -1500,14 +1503,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyGenericInvocation: var x = a.skipGenericAlias + var preventHack = false if x.kind == tyOwned and f[0].kind != tyOwned: preventHack = true x = x.lastSon # XXX: This is very hacky. It should be moved back into liftTypeParam if x.kind in {tyGenericInst, tyArray} and - c.calleeSym != nil and - c.calleeSym.kind in {skProc, skFunc} and c.call != nil and not preventHack: + c.calleeSym != nil and + c.calleeSym.kind in {skProc, skFunc} and c.call != nil and not preventHack: let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f) #echo "inferred ", typeToString(inst), " for ", f return typeRel(c, inst, a, flags) @@ -2291,7 +2295,7 @@ proc arrayConstr(c: PContext, n: PNode): PType = result = newTypeS(tyArray, c) rawAddSon(result, makeRangeType(c, 0, 0, n.info)) addSonSkipIntLit(result, skipTypes(n.typ, - {tyGenericInst, tyVar, tyLent, tyOrdinal})) + {tyGenericInst, tyVar, tyLent, tyOrdinal}), c.idgen) proc arrayConstr(c: PContext, info: TLineInfo): PType = result = newTypeS(tyArray, c) diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim index 182e44324..841f2de8e 100644 --- a/compiler/sinkparameter_inference.nim +++ b/compiler/sinkparameter_inference.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) = +proc checkForSink*(config: ConfigRef; idgen: IdGenerator; owner: PSym; arg: PNode) = #[ Patterns we seek to detect: someLocation = p # ---> p: sink T @@ -32,7 +32,7 @@ proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) = if sfWasForwarded notin owner.flags: let argType = arg.sym.typ - let sinkType = newType(tySink, owner) + let sinkType = newType(tySink, nextId(idgen), owner) sinkType.size = argType.size sinkType.align = argType.align sinkType.paddingAtEnd = argType.paddingAtEnd @@ -52,18 +52,18 @@ proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) = #echo config $ arg.info, " candidate for a sink parameter here" of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr: if not isEmptyType(arg.typ): - checkForSink(config, owner, arg.lastSon) + checkForSink(config, idgen, owner, arg.lastSon) of nkIfStmt, nkIfExpr, nkWhen: for branch in arg: let value = branch.lastSon if not isEmptyType(value.typ): - checkForSink(config, owner, value) + checkForSink(config, idgen, owner, value) of nkCaseStmt: for i in 1.. 16) and n.getRoot != nil: # it is more efficient to pass a pointer instead: - let a = genAddrOf(n) + let a = genAddrOf(n, idgen) field.typ = a.typ - objType.addField(field, g.cache) + objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - let threadLocal = addLocalVar(g, varSection,nil, owner, field.typ, + let threadLocal = addLocalVar(g, varSection, nil, idgen, owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(genDeref(threadLocal.newSymNode)) else: # boring case field.typ = argType - objType.addField(field, g.cache) + objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) let threadLocal = addLocalVar(g, varSection, varInit, - owner, field.typ, + idgen, owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(threadLocal.newSymNode) -proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType; +proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExpr: PNode; retType: PType; barrier, dest: PNode = nil): PNode = # if 'barrier' != nil, then it is in a 'parallel' section and we # generate quite different code @@ -330,9 +332,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P var fn = n[0] let name = (if fn.kind == nkSym: fn.sym.name.s else: genPrefix) & "Wrapper" - wrapperProc = newSym(skProc, getIdent(g.cache, name), owner, fn.info, g.config.options) - threadParam = newSym(skParam, getIdent(g.cache, "thread"), wrapperProc, n.info, g.config.options) - argsParam = newSym(skParam, getIdent(g.cache, "args"), wrapperProc, n.info, g.config.options) + wrapperProc = newSym(skProc, getIdent(g.cache, name), nextId idgen, owner, fn.info, g.config.options) + threadParam = newSym(skParam, getIdent(g.cache, "thread"), nextId idgen, wrapperProc, n.info, g.config.options) + argsParam = newSym(skParam, getIdent(g.cache, "args"), nextId idgen, wrapperProc, n.info, g.config.options) wrapperProc.flags.incl sfInjectDestructors block: @@ -341,11 +343,11 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P argsParam.typ = ptrType argsParam.position = 1 - var objType = createObj(g, owner, n.info) + var objType = createObj(g, idgen, owner, n.info) incl(objType.flags, tfFinal) - let castExpr = createCastExpr(argsParam, objType) + let castExpr = createCastExpr(argsParam, objType, idgen) - var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), owner, n.info, g.config.options) + var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), nextId idgen, owner, n.info, g.config.options) block: scratchObj.typ = objType incl(scratchObj.flags, sfFromGeneric) @@ -362,9 +364,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P skFunc, skMethod, skConverter}): # for indirect calls we pass the function pointer in the scratchObj var argType = n[0].typ.skipTypes(abstractInst) - var field = newSym(skField, getIdent(g.cache, "fn"), owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fn"), nextId idgen, owner, n.info, g.config.options) field.typ = argType - objType.addField(field, g.cache) + objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) fn = indirectAccess(castExpr, field, n.info) elif fn.kind == nkSym and fn.sym.kind == skIterator: @@ -376,49 +378,48 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P var varSection = newNodeI(nkVarSection, n.info) var varInit = newNodeI(nkStmtList, n.info) if barrier.isNil: - setupArgsForConcurrency(g, n, objType, wrapperProc, scratchObj, castExpr, call, + setupArgsForConcurrency(g, n, objType, idgen, wrapperProc, scratchObj, castExpr, call, varSection, varInit, result) else: - setupArgsForParallelism(g, n, objType, wrapperProc, scratchObj, castExpr, call, + setupArgsForParallelism(g, n, objType, idgen, wrapperProc, scratchObj, castExpr, call, varSection, varInit, result) var barrierAsExpr: PNode = nil if barrier != nil: - let typ = newType(tyPtr, owner) + let typ = newType(tyPtr, nextId idgen, owner) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) - var field = newSym(skField, getIdent(g.cache, "barrier"), owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "barrier"), nextId idgen, owner, n.info, g.config.options) field.typ = typ - objType.addField(field, g.cache) + objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) barrierAsExpr = indirectAccess(castExpr, field, n.info) var fvField, fvAsExpr: PNode = nil if spawnKind == srFlowVar: - var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fv"), nextId idgen, owner, n.info, g.config.options) field.typ = retType - objType.addField(field, g.cache) + objType.addField(field, g.cache, idgen) fvField = newDotExpr(scratchObj, field) fvAsExpr = indirectAccess(castExpr, field, n.info) # create flowVar: result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1])) if barrier == nil: - result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, - fvField) + result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, fvField) elif spawnKind == srByVar: - var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options) - field.typ = newType(tyPtr, objType.owner) + var field = newSym(skField, getIdent(g.cache, "fv"), nextId idgen, owner, n.info, g.config.options) + field.typ = newType(tyPtr, nextId idgen, objType.owner) field.typ.rawAddSon(retType) - objType.addField(field, g.cache) + objType.addField(field, g.cache, idgen) fvAsExpr = indirectAccess(castExpr, field, n.info) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest, idgen)) - createTypeBoundOps(g, nil, objType, n.info) + createTypeBoundOps(g, nil, objType, n.info, idgen) createWrapperProc(g, fn, threadParam, argsParam, varSection, varInit, call, - barrierAsExpr, fvAsExpr, spawnKind, wrapperProc) + barrierAsExpr, fvAsExpr, idgen, spawnKind, wrapperProc) result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapperProc.info, - wrapperProc.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr) + wrapperProc.newSymNode, genAddrOf(scratchObj.newSymNode, idgen), nil, spawnExpr) if spawnKind == srFlowVar: result.add fvField diff --git a/compiler/transf.nim b/compiler/transf.nim index 5922ca595..42a78c8e3 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -24,7 +24,7 @@ import lowerings, liftlocals, modulegraphs, lineinfos -proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode +proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, cache: bool): PNode import closureiters, lambdalifting @@ -40,7 +40,7 @@ type # if we encounter the 2nd yield statement next: PTransCon # for stacking - TTransfContext = object of TPassContext + TTransfContext = object module: PSym transCon: PTransCon # top of a TransCon stack inlining: int # > 0 if we are in inlining context (copy vars) @@ -48,6 +48,7 @@ type contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' deferDetected, tooEarly: bool graph: ModuleGraph + idgen: IdGenerator PTransf = ref TTransfContext proc newTransNode(a: PNode): PNode {.inline.} = @@ -86,12 +87,12 @@ proc getCurrOwner(c: PTransf): PSym = else: result = c.module proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode = - let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), getCurrOwner(c), info) + let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), nextId(c.idgen), getCurrOwner(c), info) r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink}) incl(r.flags, sfFromGeneric) let owner = getCurrOwner(c) if owner.isIterator and not c.tooEarly: - result = freshVarForClosureIter(c.graph, r, owner) + result = freshVarForClosureIter(c.graph, r, c.idgen, owner) else: result = newSymNode(r) @@ -111,13 +112,13 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = let s = n.sym if s.typ != nil and s.typ.callConv == ccClosure: if s.kind in routineKinds: - discard transformBody(c.graph, s, true) + discard transformBody(c.graph, c.idgen, s, true) if s.kind == skIterator: if c.tooEarly: return n - else: return liftIterSym(c.graph, n, getCurrOwner(c)) + else: return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c)) elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly: # top level .closure procs are still somewhat supported for 'Nake': - return makeClosure(c.graph, s, nil, n.info) + return makeClosure(c.graph, c.idgen, s, nil, n.info) #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure: # echo n.info, " come heer for ", c.tooEarly # if not c.tooEarly: @@ -160,9 +161,9 @@ proc transformSym(c: PTransf, n: PNode): PNode = proc freshVar(c: PTransf; v: PSym): PNode = let owner = getCurrOwner(c) if owner.isIterator and not c.tooEarly: - result = freshVarForClosureIter(c.graph, v, owner) + result = freshVarForClosureIter(c.graph, v, c.idgen, owner) else: - var newVar = copySym(v) + var newVar = copySym(v, nextId(c.idgen)) incl(newVar.flags, sfFromGeneric) newVar.owner = owner result = newSymNode(newVar) @@ -232,7 +233,7 @@ proc hasContinue(n: PNode): bool = if hasContinue(n[i]): return true proc newLabel(c: PTransf, n: PNode): PSym = - result = newSym(skLabel, nil, getCurrOwner(c), n.info) + result = newSym(skLabel, nil, nextId(c.idgen), getCurrOwner(c), n.info) result.name = getIdent(c.graph.cache, genPrefix) proc transformBlock(c: PTransf, n: PNode): PNode = @@ -423,7 +424,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = if n.typ.skipTypes(abstractVar).kind != tyOpenArray: result.typ = n.typ elif n.typ.skipTypes(abstractInst).kind in {tyVar}: - result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind) + result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen) of nkHiddenStdConv, nkHiddenSubConv, nkConv: var m = n[0][1] if m.kind == a or m.kind == b: @@ -433,7 +434,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = if n.typ.skipTypes(abstractVar).kind != tyOpenArray: result.typ = n.typ elif n.typ.skipTypes(abstractInst).kind in {tyVar}: - result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind) + result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen) else: if n[0].kind == a or n[0].kind == b: # addr ( deref ( x )) --> x @@ -495,7 +496,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = of tyOpenArray, tyVarargs: result = transform(c, n[1]) #result = transformSons(c, n) - result.typ = takeType(n.typ, n[1].typ) + result.typ = takeType(n.typ, n[1].typ, c.idgen) #echo n.info, " came here and produced ", typeToString(result.typ), # " from ", typeToString(n.typ), " and ", typeToString(n[1].typ) of tyCString: @@ -629,7 +630,7 @@ proc transformFor(c: PTransf, n: PNode): PNode = result[1] = n result[1][^1] = transformLoopBody(c, n[^1]) result[1][^2] = transform(c, n[^2]) - result[1] = lambdalifting.liftForLoop(c.graph, result[1], getCurrOwner(c)) + result[1] = lambdalifting.liftForLoop(c.graph, result[1], c.idgen, getCurrOwner(c)) discard c.breakSyms.pop return result @@ -698,7 +699,7 @@ proc transformFor(c: PTransf, n: PNode): PNode = stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg)) idNodeTablePut(newC.mapping, formal, temp) - let body = transformBody(c.graph, iter, true) + let body = transformBody(c.graph, c.idgen, iter, true) pushInfoContext(c.graph.config, n.info) inc(c.inlining) stmtList.add(transform(c, body)) @@ -830,7 +831,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PNode = let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2) convNode[0] = newNodeI(nkEmpty, n.info) convNode[1] = excCall - convNode.typ = excTypeNode.typ.toRef() + convNode.typ = excTypeNode.typ.toRef(c.idgen) # -> let exc = ... let identDefs = newTransNode(nkIdentDefs, n[1].info, 3) identDefs[0] = n[0][2] @@ -850,10 +851,10 @@ proc transformExceptBranch(c: PTransf, n: PNode): PNode = else: result = transformSons(c, n) -proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode = +proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode): PNode = result = n for i in 0..= 3): result = newNodeIT(nkCall, n.info, n.typ) @@ -873,7 +874,7 @@ proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode = result.add(a) if result.len == 2: result = result[1] else: - var cnst = getConstExpr(c, n, g) + var cnst = getConstExpr(c, n, idgen, g) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = cnst @@ -1012,7 +1013,7 @@ proc transform(c: PTransf, n: PNode): PNode = n.typ != nil and n.typ.kind == tyPointer if not exprIsPointerCast: - var cnst = getConstExpr(c.module, result, c.graph) + var cnst = getConstExpr(c.module, result, c.idgen, c.graph) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = cnst # do not miss an optimization @@ -1027,12 +1028,13 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = popTransCon(c) incl(result.flags, nfTransf) -proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf = +proc openTransf(g: ModuleGraph; module: PSym, filename: string; idgen: IdGenerator): PTransf = new(result) result.contSyms = @[] result.breakSyms = @[] result.module = module result.graph = g + result.idgen = idgen proc flattenStmts(n: PNode) = var goOn = true @@ -1075,7 +1077,7 @@ template liftDefer(c, root) = if c.deferDetected: liftDeferAux(root) -proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode = +proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; cache: bool): PNode = assert prc.kind in routineKinds if prc.transformedBody != nil: @@ -1084,14 +1086,14 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode = result = prc.ast[bodyPos] else: prc.transformedBody = newNode(nkEmpty) # protects from recursion - var c = openTransf(g, prc.getModule, "") - result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly) + var c = openTransf(g, prc.getModule, "", idgen) + result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly, c.idgen) result = processTransf(c, result, prc) liftDefer(c, result) - result = liftLocalsIfRequested(prc, result, g.cache, g.config) + result = liftLocalsIfRequested(prc, result, g.cache, g.config, c.idgen) if prc.isIterator: - result = g.transformClosureIterator(prc, result) + result = g.transformClosureIterator(c.idgen, prc, result) incl(result.flags, nfTransf) @@ -1105,21 +1107,21 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode = #if prc.name.s == "main": # echo "transformed into ", renderTree(result, {renderIds}) -proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = +proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n else: - var c = openTransf(g, module, "") + var c = openTransf(g, module, "", idgen) result = processTransf(c, n, module) liftDefer(c, result) #result = liftLambdasForTopLevel(module, result) incl(result.flags, nfTransf) -proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = +proc transformExpr*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n else: - var c = openTransf(g, module, "") + var c = openTransf(g, module, "", idgen) result = processTransf(c, n, module) liftDefer(c, result) # expressions are not to be injected with destructor calls as that diff --git a/compiler/types.nim b/compiler/types.nim index 75e12cac4..a3a4695b0 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1296,11 +1296,11 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool = proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) -proc baseOfDistinct*(t: PType): PType = +proc baseOfDistinct*(t: PType; idgen: IdGenerator): PType = if t.kind == tyDistinct: result = t[0] else: - result = copyType(t, t.owner, false) + result = copyType(t, nextId idgen, t.owner) var parent: PType = nil var it = result while it.kind in {tyPtr, tyRef, tyOwned}: @@ -1438,7 +1438,7 @@ proc isEmptyContainer*(t: PType): bool = of tyGenericInst, tyAlias, tySink: result = isEmptyContainer(t.lastSon) else: result = false -proc takeType*(formal, arg: PType): PType = +proc takeType*(formal, arg: PType; idgen: IdGenerator): PType = # param: openArray[string] = [] # [] is an array constructor of length 0 of type string! if arg.kind == tyNil: @@ -1446,7 +1446,7 @@ proc takeType*(formal, arg: PType): PType = result = formal elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and arg.isEmptyContainer: - let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), arg.owner, keepId=false) + let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), nextId(idgen), arg.owner) a[ord(arg.kind == tyArray)] = formal[0] result = a elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind: @@ -1454,14 +1454,14 @@ proc takeType*(formal, arg: PType): PType = else: result = arg -proc skipHiddenSubConv*(n: PNode): PNode = +proc skipHiddenSubConv*(n: PNode; idgen: IdGenerator): PNode = if n.kind == nkHiddenSubConv: # param: openArray[string] = [] # [] is an array constructor of length 0 of type string! let formal = n.typ result = n[1] let arg = result.typ - let dest = takeType(formal, arg) + let dest = takeType(formal, arg, idgen) if dest == arg and formal.kind != tyUntyped: #echo n.info, " came here for ", formal.typeToString result = n diff --git a/compiler/vm.nim b/compiler/vm.nim index bb217c4db..185975ec3 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1105,7 +1105,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let ast = a.sym.ast.shallowCopy for i in 0.. ord(high(TSymKind)): internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") - var sym = newSym(k.TSymKind, getIdent(c.cache, name), c.module.owner, c.debug[pc]) + var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextId c.idgen, c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) regs[ra].node.flags.incl nfIsRef @@ -2058,7 +2058,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let rb = instr.regB inc pc let typ = c.types[c.code[pc].regBx - wordExcess] - putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.cache, c.config)) + putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.cache, c.config, c.idgen)) of opcMarshalStore: decodeB(rkNode) inc pc @@ -2103,7 +2103,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = "NimScript: attempt to call non-routine: " & sym.name.s) proc evalStmt*(c: PCtx, n: PNode) = - let n = transformExpr(c.graph, c.module, n) + let n = transformExpr(c.graph, c.idgen, c.module, n) let start = genStmt(c, n) # execute new instructions; this redundant opcEof check saves us lots # of allocations in 'execute': @@ -2111,7 +2111,7 @@ proc evalStmt*(c: PCtx, n: PNode) = discard execute(c, start) proc evalExpr*(c: PCtx, n: PNode): PNode = - let n = transformExpr(c.graph, c.module, n) + let n = transformExpr(c.graph, c.idgen, c.module, n) let start = genExpr(c, n) assert c.code[start].opcode != opcEof result = execute(c, start) @@ -2122,20 +2122,20 @@ proc getGlobalValue*(c: PCtx; s: PSym): PNode = include vmops -proc setupGlobalCtx*(module: PSym; graph: ModuleGraph) = +proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) = if graph.vm.isNil: - graph.vm = newCtx(module, graph.cache, graph) + graph.vm = newCtx(module, graph.cache, graph, idgen) registerAdditionalOps(PCtx graph.vm) else: - refresh(PCtx graph.vm, module) + refresh(PCtx graph.vm, module, idgen) -proc myOpen(graph: ModuleGraph; module: PSym): PPassContext {.nosinks.} = +proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = #var c = newEvalContext(module, emRepl) #c.features = {allowCast, allowInfiniteLoops} #pushStackFrame(c, newStackFrame()) # XXX produce a new 'globals' environment here: - setupGlobalCtx(module, graph) + setupGlobalCtx(module, graph, idgen) result = PCtx graph.vm proc myProcess(c: PPassContext, n: PNode): PNode = @@ -2149,16 +2149,16 @@ proc myProcess(c: PPassContext, n: PNode): PNode = c.oldErrorCount = c.config.errorCounter proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = - myProcess(c, n) + result = myProcess(c, n) const evalPass* = makePass(myOpen, myProcess, myClose) -proc evalConstExprAux(module: PSym; +proc evalConstExprAux(module: PSym; idgen: IdGenerator; g: ModuleGraph; prc: PSym, n: PNode, mode: TEvalMode): PNode = if g.config.errorCounter > 0: return n - let n = transformExpr(g, module, n) - setupGlobalCtx(module, g) + let n = transformExpr(g, idgen, module, n) + setupGlobalCtx(module, g, idgen) var c = PCtx g.vm let oldMode = c.mode c.mode = mode @@ -2173,17 +2173,17 @@ proc evalConstExprAux(module: PSym; if result.info.col < 0: result.info = n.info c.mode = oldMode -proc evalConstExpr*(module: PSym; g: ModuleGraph; e: PNode): PNode = - result = evalConstExprAux(module, g, nil, e, emConst) +proc evalConstExpr*(module: PSym; idgen: IdGenerator; g: ModuleGraph; e: PNode): PNode = + result = evalConstExprAux(module, idgen, g, nil, e, emConst) -proc evalStaticExpr*(module: PSym; g: ModuleGraph; e: PNode, prc: PSym): PNode = - result = evalConstExprAux(module, g, prc, e, emStaticExpr) +proc evalStaticExpr*(module: PSym; idgen: IdGenerator; g: ModuleGraph; e: PNode, prc: PSym): PNode = + result = evalConstExprAux(module, idgen, g, prc, e, emStaticExpr) -proc evalStaticStmt*(module: PSym; g: ModuleGraph; e: PNode, prc: PSym) = - discard evalConstExprAux(module, g, prc, e, emStaticStmt) +proc evalStaticStmt*(module: PSym; idgen: IdGenerator; g: ModuleGraph; e: PNode, prc: PSym) = + discard evalConstExprAux(module, idgen, g, prc, e, emStaticStmt) -proc setupCompileTimeVar*(module: PSym; g: ModuleGraph; n: PNode) = - discard evalConstExprAux(module, g, nil, n, emStaticStmt) +proc setupCompileTimeVar*(module: PSym; idgen: IdGenerator; g: ModuleGraph; n: PNode) = + discard evalConstExprAux(module, idgen, g, nil, n, emStaticStmt) proc prepareVMValue(arg: PNode): PNode = ## strip nkExprColonExpr from tuple values recurively. That is how @@ -2227,14 +2227,14 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) = # to prevent endless recursion in macro instantiation const evalMacroLimit = 1000 -proc errorNode(owner: PSym, n: PNode): PNode = +proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) - result.typ = newType(tyError, owner) + result.typ = newType(tyError, nextId idgen, owner) result.typ.flags.incl tfCheckedForDestructor -proc evalMacroCall*(module: PSym; g: ModuleGraph; templInstCounter: ref int; +proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int; n, nOrig: PNode, sym: PSym): PNode = - if g.config.errorCounter > 0: return errorNode(module, n) + if g.config.errorCounter > 0: return errorNode(idgen, module, n) # XXX globalError() is ugly here, but I don't know a better solution for now inc(g.config.evalMacroCounter) @@ -2247,7 +2247,7 @@ proc evalMacroCall*(module: PSym; g: ModuleGraph; templInstCounter: ref int; globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [ n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) - setupGlobalCtx(module, g) + setupGlobalCtx(module, g, idgen) var c = PCtx g.vm let oldMode = c.mode c.mode = emStaticStmt diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 59ffe9581..202087af7 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -282,17 +282,18 @@ type PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx = +proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: g.config.maxLoopIterationsVM, comesFromHeuristic: unknownLineInfo, callbacks: @[], errorFlag: "", - cache: cache, config: g.config, graph: g) + cache: cache, config: g.config, graph: g, idgen: idgen) -proc refresh*(c: PCtx, module: PSym) = +proc refresh*(c: PCtx, module: PSym; idgen: IdGenerator) = c.module = module c.prc = PProc(blocks: @[]) c.loopIterations = c.config.maxLoopIterationsVM + c.idgen = idgen proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} = result = c.callbacks.len diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 37e7e4b38..8083ae179 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -24,8 +24,9 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): str localError(conf, info, "cannot open file: " & file) result = "" -proc atomicTypeX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo): PNode = - let sym = newSym(skType, getIdent(cache, name), t.owner, info) +proc atomicTypeX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo; + idgen: IdGenerator): PNode = + let sym = newSym(skType, getIdent(cache, name), nextId(idgen), t.owner, info) sym.magic = m sym.typ = t result = newSymNode(sym) @@ -35,44 +36,46 @@ proc atomicTypeX(s: PSym; info: TLineInfo): PNode = result = newSymNode(s) result.info = info -proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; +proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator; inst=false; allowRecursionX=false): PNode proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo; + idgen: IdGenerator; inst=false): PNode = result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicTypeX(cache, name, m, t, info) + result.add atomicTypeX(cache, name, m, t, info, idgen) for i in 0.. 0: - result.add objectNode(cache, t.n) + result.add objectNode(cache, t.n, idgen) else: result.add newNodeI(nkEmpty, info) else: @@ -298,15 +301,15 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyOwned: result = mapTypeToBracket("owned", mBuiltinType, t, info) of tyOptDeprecated: doAssert false -proc opMapTypeToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode = - result = mapTypeToAstX(cache, t, info, inst=false, allowRecursionX=true) +proc opMapTypeToAst*(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator): PNode = + result = mapTypeToAstX(cache, t, info, idgen, inst=false, allowRecursionX=true) # the "Inst" version includes generic parameters in the resulting type tree # and also tries to look like the corresponding Nim type declaration -proc opMapTypeInstToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode = - result = mapTypeToAstX(cache, t, info, inst=true, allowRecursionX=false) +proc opMapTypeInstToAst*(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator): PNode = + result = mapTypeToAstX(cache, t, info, idgen, inst=true, allowRecursionX=false) # the "Impl" version includes generic parameters in the resulting type tree # and also tries to look like the corresponding Nim type implementation -proc opMapTypeImplToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode = - result = mapTypeToAstX(cache, t, info, inst=true, allowRecursionX=true) +proc opMapTypeImplToAst*(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator): PNode = + result = mapTypeToAstX(cache, t, info, idgen, inst=true, allowRecursionX=true) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 44b10ea67..5ba15bb2b 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1118,7 +1118,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(d) of mSwap: unused(c, n, dest) - c.gen(lowerSwap(c.graph, n, if c.prc == nil: c.module else: c.prc.sym)) + c.gen(lowerSwap(c.graph, n, c.idgen, if c.prc == nil: c.module else: c.prc.sym)) of mIsNil: genUnaryABC(c, n, dest, opcIsNil) of mParseBiggestFloat: if dest < 0: dest = c.getTemp(n.typ) @@ -1819,7 +1819,7 @@ proc genVarSection(c: PCtx; n: PNode) = if a[i].kind == nkSym: if not a[i].sym.isGlobal: setSlot(c, a[i].sym) checkCanEval(c, a[i]) - c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner)) + c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner)) elif a[0].kind == nkSym: let s = a[0].sym checkCanEval(c, a[0]) @@ -2235,7 +2235,7 @@ proc genProc(c: PCtx; s: PSym): int = s.ast[miscPos] = x # thanks to the jmp we can add top level statements easily and also nest # procs easily: - let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s)) + let body = transformBody(c.graph, c.idgen, s, cache = not isCompileTimeProc(s)) let procStart = c.xjmp(body, opcJmp, 0) var p = PProc(blocks: @[], sym: s) let oldPrc = c.prc diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index 696183943..979e5de8a 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -136,7 +136,8 @@ proc storeAny*(s: var string; t: PType; a: PNode; conf: ConfigRef) = proc loadAny(p: var JsonParser, t: PType, tab: var Table[BiggestInt, PNode]; cache: IdentCache; - conf: ConfigRef): PNode = + conf: ConfigRef; + idgen: IdGenerator): PNode = case t.kind of tyNone: assert false of tyBool: @@ -170,7 +171,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkBracket) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.elemType, tab, cache, conf) + result.add loadAny(p, t.elemType, tab, cache, conf, idgen) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") of tySequence: @@ -182,7 +183,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkBracket) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.elemType, tab, cache, conf) + result.add loadAny(p, t.elemType, tab, cache, conf, idgen) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "") else: @@ -198,7 +199,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) if i >= t.len: raiseParseErr(p, "too many fields to tuple type " & typeToString(t)) - result.add loadAny(p, t[i], tab, cache, conf) + result.add loadAny(p, t[i], tab, cache, conf, idgen) inc i if p.kind == jsonObjectEnd: next(p) else: raiseParseErr(p, "'}' end of object expected") @@ -219,8 +220,8 @@ proc loadAny(p: var JsonParser, t: PType, if pos >= result.len: setLen(result.sons, pos + 1) let fieldNode = newNode(nkExprColonExpr) - fieldNode.add newSymNode(newSym(skField, ident, nil, unknownLineInfo)) - fieldNode.add loadAny(p, field.typ, tab, cache, conf) + fieldNode.add newSymNode(newSym(skField, ident, nextId(idgen), nil, unknownLineInfo)) + fieldNode.add loadAny(p, field.typ, tab, cache, conf, idgen) result[pos] = fieldNode if p.kind == jsonObjectEnd: next(p) else: raiseParseErr(p, "'}' end of object expected") @@ -229,7 +230,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkCurly) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.lastSon, tab, cache, conf) + result.add loadAny(p, t.lastSon, tab, cache, conf, idgen) next(p) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") @@ -248,7 +249,7 @@ proc loadAny(p: var JsonParser, t: PType, if p.kind == jsonInt: let idx = p.getInt next(p) - result = loadAny(p, t.lastSon, tab, cache, conf) + result = loadAny(p, t.lastSon, tab, cache, conf, idgen) tab[idx] = result else: raiseParseErr(p, "index for ref type expected") if p.kind == jsonArrayEnd: next(p) @@ -276,14 +277,14 @@ proc loadAny(p: var JsonParser, t: PType, return raiseParseErr(p, "float expected") of tyRange, tyGenericInst, tyAlias, tySink: - result = loadAny(p, t.lastSon, tab, cache, conf) + result = loadAny(p, t.lastSon, tab, cache, conf, idgen) else: internalError conf, "cannot marshal at compile-time " & t.typeToString -proc loadAny*(s: string; t: PType; cache: IdentCache; conf: ConfigRef): PNode = +proc loadAny*(s: string; t: PType; cache: IdentCache; conf: ConfigRef; idgen: IdGenerator): PNode = var tab = initTable[BiggestInt, PNode]() var p: JsonParser open(p, newStringStream(s), "unknown file") next(p) - result = loadAny(p, t, tab, cache, conf) + result = loadAny(p, t, tab, cache, conf, idgen) close(p) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index a3d4d74db..47df3d24f 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -268,7 +268,7 @@ proc registerAdditionalOps*(c: PCtx) = fn.typ.n[0][effectIndex] != nil: var list = newNodeI(nkBracket, fn.info) for e in fn.typ.n[0][effectIndex]: - list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info) + list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info, c.idgen) setResult(a, list) registerCallback c, "stdlib.effecttraits.getRaisesListImpl", proc (a: VmArgs) = diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 99ad6eef6..c8c0edbd4 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -82,7 +82,7 @@ iterator mitems*(a: var cstring): var char {.inline.} = yield a[i] inc(i) -iterator items*(E: typedesc[enum]): E = +iterator items*[T: enum](E: typedesc[T]): T = ## Iterates over the values of the enum ``E``. for v in low(E) .. high(E): yield v From b56a037183fa572c85d4f33d0f92cca77586019f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Oct 2020 03:10:38 +0200 Subject: [PATCH 1317/4254] workaround #15713 disable freebsd tssl.nim (#15718) --- tests/stdlib/tssl.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim index 3c2b6be2b..7625f3694 100644 --- a/tests/stdlib/tssl.nim +++ b/tests/stdlib/tssl.nim @@ -1,7 +1,9 @@ discard """ joinable: false + disabled: "freebsd" + disabled: "openbsd" """ - +# disabled: pending bug #15713 import net, nativesockets when defined(posix): import os, posix From d4c2e2c53ffe86a78c302d7002f6baf346540d17 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Oct 2020 10:13:37 +0200 Subject: [PATCH 1318/4254] fix #15704 #15597 wrong VM register was freed (#15705) * fix #15704 #15597 wrong VM register was freed * same treatment for nkCheckedFieldExpr * note concerning HighRegisterPressure * bump NimPatch * Update lib/system.nim Co-authored-by: Andreas Rumpf --- compiler/vmgen.nim | 6 +- tests/vm/tvmmisc.nim | 130 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 5ba15bb2b..f084ab7ba 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -247,6 +247,8 @@ proc freeTemp(c: PCtx; r: TRegister) = proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister = # if register pressure is high, we re-use more aggressively: let c = cc.prc + # we could also customize via the following (with proper caching in ConfigRef): + # let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister): for i in 0..c.maxSlots-n: if not c.slots[i].inUse: @@ -1508,14 +1510,14 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = let tmp = c.genx(ri) c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp) c.freeTemp(tmp) - c.freeTemp(idx) + # c.freeTemp(idx) # BUGFIX, see nkDotExpr c.freeTemp(objR) of nkDotExpr: let dest = c.genx(le[0], {gfNode}) let idx = genField(c, le[1]) let tmp = c.genx(ri) c.preventFalseAlias(le, opcWrObj, dest, idx, tmp) - c.freeTemp(idx) + # c.freeTemp(idx) # BUGFIX: idx is an immediate (field position), not a register c.freeTemp(tmp) c.freeTemp(dest) of nkDerefExpr, nkHiddenDeref: diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 61a187faf..f05bb6dec 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -281,3 +281,133 @@ block: # bug #8007 # OK with seq & object variants const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)] doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" + +block: # VM wrong register free causes errors in unrelated code + block: # bug #15597 + #[ + Error: unhandled exception: 'sym' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect] + in /Users/timothee/git_clone/nim/Nim_prs/compiler/vm.nim(1176) rawExecute + in opcIndCall + in let prc = if not isClosure: bb.sym else: bb[0].sym + ]# + proc bar2(head: string): string = "asdf" + proc gook(u1: int) = discard + + type PathEntry = object + kind: int + path: string + + iterator globOpt(): int = + var u1: int + + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + + var entry = PathEntry() + entry.path = bar2("") + if false: + echo "here2" + + proc processAux(a: float) = discard + + template bar(iter: untyped): untyped = + var ret: float + for x in iter: break + ret + + proc main() = + processAux(bar(globOpt())) + static: main() + + block: # ditto + # D20201024T133245 + type Deque = object + proc initDeque2(initialSize: int = 4): Deque = Deque() + proc len2(a: Deque): int = 2 + proc baz(dir: string): bool = true + proc bar2(head: string): string = "asdf" + proc bar3(path: var string) = path = path + + type PathEntry = object + kind: int + path: string + + proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = dir + + iterator globOpt(dir: string): int = + var stack = initDeque2() + doAssert baz("") + let z = stack.len2 + if stack.len2 >= 0: + var entry = PathEntry() + let current = if true: stack.len2 else: stack.len2 + entry.path = bar2("") + bar3(entry.path) + if false: + echo "here2" # comment here => you get same error as https://github.com/nim-lang/Nim/issues/15704 + + proc processAux(a: float) = discard + + template bar(iter: untyped): untyped = + var ret: float + for x in iter: break + ret + proc main() = + processAux(bar(globOpt(initGlobOpt(".")))) + static: main() + + block: # bug #15704 + #[ + Error: attempt to access a nil address kind: rkFloat + ]# + type Deque = object + proc initDeque2(initialSize: int = 4): Deque = Deque() + proc len2(a: Deque): int = 2 + + proc baz(dir: string): bool = true + proc bar2(head: string): string = "asdf" + proc bar3(path: var string) = path = path + + type PathEntry = object + kind: int + path: string + depth: int + + proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = + dir + + iterator globOpt(dir: string): int = + var stack = initDeque2() + doAssert baz("") + let z = stack.len2 + var a5: int + if stack.len2 >= 0: + var entry = PathEntry() + if false: + echo "here" + let current = if true: stack.len2 else: stack.len2 + entry.depth = 1 + entry.path = bar2("") + bar3(entry.path) + proc processAux(a: float) = discard + template bar(iter: untyped): untyped = + var ret: float + for x in iter: + break + ret + const dir = "." + proc main() = + processAux(bar(globOpt(initGlobOpt(dir)))) + static: main() From 86d7726fb8044d4e2fc55b0eac3d1d42f5ffc94f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Oct 2020 10:53:39 +0200 Subject: [PATCH 1319/4254] workaround #15725 disable freebsd tblocking_channel.nim (#15726) --- tests/parallel/tblocking_channel.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim index 6ec0e1588..eb5fcb715 100644 --- a/tests/parallel/tblocking_channel.nim +++ b/tests/parallel/tblocking_channel.nim @@ -1,6 +1,8 @@ discard """ output: "" +disabled: "freebsd" """ +# disabled pending bug #15725 import threadpool, os var chan: Channel[int] From e284445e514283e09b705b890b4ad4c94288aba0 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 26 Oct 2020 06:36:12 -0300 Subject: [PATCH 1320/4254] Fix Prelude (#15714) * ReSync with Devel * Fix prelude for JS target * ReSync devel * Fix prelude for JS target --- changelog.md | 1 + lib/prelude.nim | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 1885eaacd..8bd556e33 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ ## Standard library additions and changes +- `prelude` now works with the JavaScript target. ## Language changes diff --git a/lib/prelude.nim b/lib/prelude.nim index 5ad561158..d24f35513 100644 --- a/lib/prelude.nim +++ b/lib/prelude.nim @@ -18,4 +18,5 @@ # .. code-block:: nim # import os, strutils, times, parseutils, parseopt, hashes, tables, sets -import os, strutils, times, parseutils, parseopt, hashes, tables, sets +import os, strutils, times, parseutils, hashes, tables, sets +when not defined(js): import parseopt From 2ebca5e87e1181498261d5262611a4c7c7738341 Mon Sep 17 00:00:00 2001 From: Bo Lingen Date: Mon, 26 Oct 2020 04:54:15 -0500 Subject: [PATCH 1321/4254] Revert "workaround https://github.com/citycide/glob/issues/49 glob broken (#15647)" (#15728) This reverts commit 4ab1bd7e3301e22f0a5a9c62f9c90636932fde80. --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index c94f3e98d..6a265f39a 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -39,9 +39,9 @@ pkg1 "elvis" pkg1 "fidget" pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" +pkg1 "glob" pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" -# pkg1 "glob" # pending https://github.com/citycide/glob/issues/49 pkg1 "gnuplot", "nim c gnuplot.nim" pkg1 "hts", "nim c -o:htss src/hts.nim" # pkg1 "httpauth" From b2740f5c63088c0f0f723086c1742dd057355bf6 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 26 Oct 2020 13:03:44 +0300 Subject: [PATCH 1322/4254] Add support to the latest LibreSSL version (#15715) [backport:1.2] [backport:1.4] --- lib/wrappers/openssl.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index becabad99..694152db1 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -64,9 +64,9 @@ elif useWinVersion: from winlean import SocketHandle else: when defined(osx): - const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.47|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" + const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.47|.48|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" else: - const versions = "(.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.47|.46|.45|.44|.43|.41|.39|.38|.10|)" + const versions = "(.1.1|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.48|.47|.46|.45|.44|.43|.41|.39|.38|.10|)" when defined(macosx): const From a87617956f9a521eac3663df6a6a9862bc7ae87e Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 26 Oct 2020 04:06:18 -0600 Subject: [PATCH 1323/4254] Fixed iteration limit hit from execproc (#15723) [backport:1.2] [backport:1.4] When calling procs from Nim in Nimscript you could hit the VM iteration limit even though the code is functioning properly. This resolves that by making the iteration limit reset eachtime you call a proc. --- compiler/vm.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/vm.nim b/compiler/vm.nim index 185975ec3..ac2feac26 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2078,6 +2078,7 @@ proc execute(c: PCtx, start: int): PNode = result = rawExecute(c, start, tos).regToNode proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = + c.loopIterations = c.config.maxLoopIterationsVM if sym.kind in routineKinds: if sym.typ.len-1 != args.len: localError(c.config, sym.info, From ea6c28249ae7107fba954f90dac31132564dcaad Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Mon, 26 Oct 2020 09:15:56 -0400 Subject: [PATCH 1324/4254] add criterion to important packages (#15604) * add criterion to important packages * use a special nimscript for criterion tests * fix criterion speed differently Co-authored-by: Andreas Rumpf --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 6a265f39a..ef7dded4b 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -31,6 +31,7 @@ pkg1 "cligen", "nim c --path:. -r cligen.nim" pkg1 "combparser", "nimble test --gc:orc" pkg1 "compactdict" pkg1 "comprehension", "nimble test", "https://github.com/alehander42/comprehension" +pkg1 "criterion" pkg1 "dashing", "nim c tests/functional.nim" pkg1 "delaunay" pkg1 "docopt" From ae8eb1ec3dab5a9384473c7b37c240da5861a784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yanis=20Zafir=C3=B3pulos?= <1265028+drkameleon@users.noreply.github.com> Date: Mon, 26 Oct 2020 18:47:33 +0100 Subject: [PATCH 1325/4254] Copy editing (#15733) * Minor fixes * Minor fixes * Minor fixes * Minor fixes --- doc/contributing.rst | 36 ++++++++++++++++++------------------ doc/gc.rst | 32 ++++++++++++++++---------------- readme.md | 20 ++++++++++---------- security.md | 4 ++-- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 15017cd84..f570336e2 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -49,7 +49,7 @@ which only gets executed when the tester is building the file. Each test should be in a separate ``block:`` statement, such that each has its own scope. Use boolean conditions and ``doAssert`` for the -testing by itself, don't rely on echo statements or similar; in particular avoid +testing by itself, don't rely on echo statements or similar; in particular, avoid things like `echo "done"`. Sample test: @@ -69,7 +69,7 @@ Sample test: # doAssert with `not` can now be done as follows: doAssert not (1 == 2) -Always refer to a github issue using the following exact syntax: `bug #1234` as shown +Always refer to a GitHub issue using the following exact syntax: `bug #1234` as shown above, so that it's consistent and easier to search or for tooling. Some browser extensions (e.g. https://github.com/sindresorhus/refined-github) will even turn those in clickable links when it works. @@ -100,7 +100,7 @@ Possible keys are: For a full spec, see here: ``testament/specs.nim`` -An example for a test: +An example of a test: .. code-block:: nim @@ -162,7 +162,7 @@ Comparing tests Test failures can be grepped using ``Failure:``. -The tester can compare two test runs. First, you need to create the +The tester can compare two test runs. First, you need to create a reference test. You'll also need to the commit id, because that's what the tester needs to know in order to compare the two. @@ -344,7 +344,7 @@ which for which ``nim doc`` ignores ``-d:release``). .. _delegate_printing: Delegate printing to caller: return ``string`` instead of calling ``echo`` -rationale: it's more flexible (e.g. allows caller to call custom printing, +rationale: it's more flexible (e.g. allows the caller to call custom printing, including prepending location info, writing to log files, etc). .. code-block:: nim @@ -364,7 +364,7 @@ unless stack allocation is needed (e.g. for efficiency). .. _use_doAssert_not_echo: Tests (including in testament) should always prefer assertions over ``echo``, except when that's not possible. It's more precise, easier for readers and -maintaners to where expected values refer to. See for example +maintainers to where expected values refer to. See for example https://github.com/nim-lang/Nim/pull/9335 and https://forum.nim-lang.org/t/4089 .. code-block:: nim @@ -386,7 +386,7 @@ General commit rules stable releases" and the tag ``[backport:$VERSION]`` for backporting to the given $VERSION. -2. If you introduce changes which affect backwards compatibility, +2. If you introduce changes which affect backward compatibility, make breaking changes, or have PR which is tagged as ``[feature]``, the changes should be mentioned in `the changelog `_. @@ -404,7 +404,7 @@ General commit rules 4. Changes should not introduce any trailing whitespace. Always check your changes for whitespace errors using ``git diff --check`` - or add following ``pre-commit`` hook: + or add the following ``pre-commit`` hook: .. code-block:: sh @@ -416,7 +416,7 @@ General commit rules ``Fixes #123; refs #124`` - indicates that issue ``#123`` is completely fixed (github may automatically + indicates that issue ``#123`` is completely fixed (GitHub may automatically close it when the PR is committed), wheres issue ``#124`` is referenced (e.g.: partially fixed) and won't close the issue when committed. @@ -431,7 +431,7 @@ General commit rules 7. Do not mix pure formatting changes (e.g. whitespace changes, nimpretty) or automated changes (e.g. nimfix) with other code changes: these should be in - separate commits (and the merge on github should not squash these into 1). + separate commits (and the merge on GitHub should not squash these into 1). Continuous Integration (CI) @@ -444,9 +444,9 @@ Continuous Integration (CI) `_ and `Travis `_. -2. Consider enabling CI (azure, github actions and builds.sr.ht) in your own Nim fork, and +2. Consider enabling CI (azure, GitHub actions and builds.sr.ht) in your own Nim fork, and waiting for CI to be green in that fork (fixing bugs as needed) before - opening your PR in original Nim repo, so as to reduce CI congestion. Same + opening your PR in the original Nim repo, so as to reduce CI congestion. Same applies for updates on a PR: you can test commits on a separate private branch before updating the main PR. @@ -463,21 +463,21 @@ Debugging CI failures, flaky tests, etc * Azure: if on your own fork, it's possible from inside azure console (e.g. `dev.azure.com/username/username/_build/results?buildId=1430&view=results`) via `rerun failed jobs` on top. - If either on you own fork or in Nim repo, it's possible from inside github UI + If either on you own fork or in Nim repo, it's possible from inside GitHub UI under checks tab, see https://github.com/timotheecour/Nim/issues/211#issuecomment-629751569 - * github actions: under "Checks" tab, click "Re-run jobs" in the right. + * GitHub actions: under "Checks" tab, click "Re-run jobs" in the right. * builds.sr.ht: create a sourcehut account so you can restart a PR job as illustrated Code reviews ------------ -1. Whenever possible, use github's new 'Suggested change' in code reviews, which +1. Whenever possible, use GitHub's new 'Suggested change' in code reviews, which saves time explaining the change or applying it; see also https://forum.nim-lang.org/t/4317 -2. When reviewing large diffs that may involve code moving around, github's interface - doesn't help much as it doesn't highlight moves. Instead you can use something +2. When reviewing large diffs that may involve code moving around, GitHub's interface + doesn't help much as it doesn't highlight moves. Instead, you can use something like this, see visual results `here `_: .. code-block:: sh @@ -485,7 +485,7 @@ Code reviews git fetch origin pull/10431/head && git checkout FETCH_HEAD git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^ -3. In addition, you can view github-like diffs locally to identify what was changed +3. In addition, you can view GitHub-like diffs locally to identify what was changed within a code block using `diff-highlight` or `diff-so-fancy`, e.g.: .. code-block:: sh diff --git a/doc/gc.rst b/doc/gc.rst index 84a1338c3..23c4f64cf 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -26,8 +26,8 @@ To choose the memory management strategy use the ``--gc:`` switch. - ``--gc:refc``. This is the default GC. It's a deferred reference counting based garbage collector - with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread local. -- ``--gc:markAndSweep``. Simple Mark-And-Sweep based garbage collector. Heaps are thread local. + with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. +- ``--gc:markAndSweep``. Simple Mark-And-Sweep based garbage collector. Heaps are thread-local. - ``--gc:boehm``. Boehm based garbage collector, it offers a shared heap. - ``--gc:go``. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. - ``--gc:arc``. Plain reference counting with @@ -36,10 +36,10 @@ To choose the memory management strategy use the ``--gc:`` switch. cause memory leaks, beware. - ``--gc:orc``. Same as ``--gc:arc`` but adds a cycle collector based on "trial deletion". - Unfortunately that makes its performance profile hard to reason about so it is less - useful for hard realtime systems. + Unfortunately, that makes its performance profile hard to reason about so it is less + useful for hard real-time systems. -- ``--gc:none``. No memory management strategy nor garbage collector. Allocated memory is +- ``--gc:none``. No memory management strategy nor a garbage collector. Allocated memory is simply never freed. You should use ``--gc:arc`` instead. @@ -71,10 +71,10 @@ The cycle collector can be en-/disabled independently from the other parts of the garbage collector with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. -Soft realtime support +Soft real-time support --------------------- -To enable realtime support, the symbol `useRealtimeGC`:idx: needs to be +To enable real-time support, the symbol `useRealtimeGC`:idx: needs to be defined via ``--define:useRealtimeGC`` (you can put this into your config file as well). With this switch the garbage collector supports the following operations: @@ -85,7 +85,7 @@ With this switch the garbage collector supports the following operations: The unit of the parameters ``maxPauseInUs`` and ``us`` is microseconds. -These two procs are the two modus operandi of the realtime garbage collector: +These two procs are the two modus operandi of the real-time garbage collector: (1) GC_SetMaxPause Mode @@ -98,7 +98,7 @@ These two procs are the two modus operandi of the realtime garbage collector: (2) GC_step Mode This allows the garbage collector to perform some work for up to ``us`` time. - This is useful to call in a main loop to ensure the garbage collector can do its work. + This is useful to call in the main loop to ensure the garbage collector can do its work. To bind all garbage collector activity to a ``GC_step`` call, deactivate the garbage collector with ``GC_disable`` at program startup. If ``strongAdvice`` is set to ``true``, @@ -106,13 +106,13 @@ These two procs are the two modus operandi of the realtime garbage collector: Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. You may also specify the current stack size via ``stackSize`` parameter. - It can improve performance, when you know that there are no unique Nim - references below certain point on the stack. Make sure the size you specify - is greater than the potential worst case size. + It can improve performance when you know that there are no unique Nim + references below a certain point on the stack. Make sure the size you specify + is greater than the potential worst-case size. -These procs provide a "best effort" realtime guarantee; in particular the +These procs provide a "best effort" real-time guarantee; in particular the cycle collector is not aware of deadlines. Deactivate it to get more -predictable realtime behaviour. Tests show that a 1ms max pause +predictable real-time behaviour. Tests show that a 1ms max pause time will be met in almost all cases on modern CPUs (with the cycle collector disabled). @@ -120,14 +120,14 @@ disabled). Time measurement with garbage collectors ---------------------------------------- -The garbage collectors's way of measuring time uses +The garbage collectors' way of measuring time uses (see ``lib/system/timers.nim`` for the implementation): 1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. 2) ``mach_absolute_time`` on Mac OS X. 3) ``gettimeofday`` on Posix systems. -As such it supports a resolution of nanoseconds internally; however the API +As such it supports a resolution of nanoseconds internally; however, the API uses microseconds for convenience. Define the symbol ``reportMissedDeadlines`` to make the diff --git a/readme.md b/readme.md index 8fcf4d2bb..bfd153143 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ [![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=devel)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=devel) -This repository contains the Nim compiler, Nim's stdlib, tools and documentation. +This repository contains the Nim compiler, Nim's stdlib, tools, and documentation. For more information about Nim, including downloads and documentation for the latest release, check out [Nim's website][nim-site] or [bleeding edge docs](https://nim-lang.github.io/Nim/). @@ -37,7 +37,7 @@ architecture combinations: * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l * Mac OS X (10.04 or greater) - x86, x86_64 and ppc64 -More platforms are supported, however they are not tested regularly and they +More platforms are supported, however, they are not tested regularly and they may not be as stable as the above-listed platforms. Compiling the Nim compiler is quite straightforward if you follow these steps: @@ -60,10 +60,10 @@ Next, to build from source you will need: * [MinGW32.7z](https://nim-lang.org/download/mingw32.7z) * [MinGW64.7z](https://nim-lang.org/download/mingw64.7z) -**Windows Note: Cygwin and similar posix runtime environments are not supported.** +**Windows Note: Cygwin and similar POSIX runtime environments are not supported.** Then, if you are on a \*nix system or Windows, the following steps should compile -Nim from source using ``gcc``, ``git`` and the ``koch`` build tool. +Nim from source using ``gcc``, ``git``, and the ``koch`` build tool. **Note: The following commands are for the development version of the compiler.** For most users, installing the latest stable version is enough. Check out @@ -72,14 +72,14 @@ the installation instructions on the website to do so: https://nim-lang.org/inst For package maintainers: see [packaging guidelines](https://nim-lang.github.io/Nim/packaging.html). -First get Nim from github: +First, get Nim from github: ``` git clone https://github.com/nim-lang/Nim.git cd Nim ``` -Next run the appropriate build shell script for your platform: +Next, run the appropriate build shell script for your platform: * `build_all.sh` (Linux, Mac) * `build_all.bat` (Windows) @@ -88,7 +88,7 @@ Windows requires a number of other dependencies that you may need to install inc PCRE and OpenSSL. Nim hosts a zip package containing known working versions of the required DLLs [here](https://nim-lang.org/download/dlls.zip). -Finally, once you have finished the build steps (on Windows, Mac or Linux) you +Finally, once you have finished the build steps (on Windows, Mac, or Linux) you should add the ``bin`` directory to your PATH. See also [rebuilding the compiler](doc/intern.rst#rebuilding-the-compiler). @@ -140,11 +140,11 @@ you should familiarize yourself with the following repository structure: * ``pure/`` - modules in the standard library written in pure Nim. * ``impure/`` - modules in the standard library written in pure Nim with dependencies written in other languages. - * ``wrappers/`` - modules which wrap dependencies written in other languages. + * ``wrappers/`` - modules that wrap dependencies written in other languages. * ``tests/`` - contains categorized tests for the compiler and standard library. * ``tools/`` - the tools including ``niminst`` and ``nimweb`` (mostly invoked via ``koch``). -* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, +* ``koch.nim`` - the tool used to bootstrap Nim, generate C sources, build the website, and generate the documentation. If you are not familiar with making a pull request using GitHub and/or git, please @@ -198,7 +198,7 @@ You can also see a list of all our sponsors/backers from various payment service ## License The compiler and the standard library are licensed under the MIT license, except -for some modules which explicitly state otherwise. As a result you may use any +for some modules which explicitly state otherwise. As a result, you may use any compatible license (essentially any license) for your own programs developed with Nim. You are explicitly permitted to develop commercial applications using Nim. diff --git a/security.md b/security.md index f1eaf3290..e8d31b1b9 100644 --- a/security.md +++ b/security.md @@ -12,6 +12,6 @@ We do not backport security fixes to older releases. Please do not report vulnerabilities via GitHub issues. -If you have discovered a vulnerability, it is the best to notify us about it via -security@nim-lang.org in order to setup a meeting where we can discuss the next +If you have discovered a vulnerability, it is best to notify us about it via +security@nim-lang.org in order to set up a meeting where we can discuss the next steps. From 3a69f14621156358e2fc154881f60459d04814a1 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 26 Oct 2020 14:49:01 -0300 Subject: [PATCH 1326/4254] Documentation only iup (#15732) * ReSync with Devel * ReSync * Add Examples for IUP, based from official doc --- lib/wrappers/iup.nim | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim index 3c1ff1483..0242d7981 100644 --- a/lib/wrappers/iup.nim +++ b/lib/wrappers/iup.nim @@ -34,6 +34,46 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # **************************************************************************** + +## Wrapper for the `IUP native GUI library `_. +## +## Requires `iup.dll` on Windows, `libiup.so` on Linux, `libiup.dylib` on OS X. +## Compile with `-d:nimDebugDlOpen` to debug the shared library opening. +## +## Examples +## ======== +## +## .. image:: http://webserver2.tecgraf.puc-rio.br/iup/en/tutorial/example2_1.png +## +## .. code-block:: nim +## import os, iup +## var argc = create(cint) +## argc[] = paramCount().cint +## var argv = allocCstringArray(commandLineParams()) +## assert open(argc, argv.addr) == 0 # UIP requires calling open() +## message(r"Hello world 1", r"Hello world") # Message popup +## close() # UIP requires calling close() +## +## +## .. image:: http://webserver2.tecgraf.puc-rio.br/iup/en/tutorial/example3_1.png +## +## .. code-block:: nim +## import os, iup +## var argc = create(cint) +## argc[] = paramCount().cint +## var argv = allocCstringArray(commandLineParams()) +## assert open(argc, argv.addr) == 0 # UIP requires open() +## let textarea = text(nil) # Text widget. +## setAttribute(textarea, r"MULTILINE", r"YES") # Set text widget to multiline. +## setAttribute(textarea, r"EXPAND", r"YES") # Set text widget to auto expand. +## let layout = vbox(textarea) # Vertical layout. +## let window = dialog(layout) # Dialog window. +## setAttribute(window, "TITLE", "Nim Notepad") # Set window title. +## showXY(window, IUP_CENTER, IUP_CENTER) # Show window. +## mainLoop() # Main loop. +## close() # UIP requires calling close() + + when defined(windows): const dllname = "iup(|30|27|26|25|24).dll" elif defined(macosx): From cf01945f54f099c268850c720986ad6c9bbdb51e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 26 Oct 2020 21:08:57 +0100 Subject: [PATCH 1327/4254] ensure the Nim compiler works with --experimental:strictFuncs --experimental:views [backport:1.4] (#15737) --- compiler/varpartitions.nim | 9 ++++++++- tests/views/tcan_compile_nim.nim | 4 ++++ tests/views/tdont_mutate.nim | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/views/tcan_compile_nim.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index f831d33cc..49221654d 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -545,6 +545,9 @@ proc borrowingCall(c: var Partitions; destType: PType; n: PNode; i: int) = localError(c.config, n[i].info, "cannot determine the target of the borrow") proc borrowingAsgn(c: var Partitions; dest, src: PNode) = + proc mutableParameter(n: PNode): bool {.inline.} = + result = n.kind == nkSym and n.sym.kind == skParam and n.sym.typ.kind == tyVar + if dest.kind == nkSym: if directViewType(dest.typ) != noView: borrowFrom(c, dest.sym, src) @@ -559,7 +562,11 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) = if vid >= 0: c.s[vid].flags.incl viewDoesMutate of immutableView: - localError(c.config, dest.info, "attempt to mutate a borrowed location from an immutable view") + if dest.kind == nkBracketExpr and dest[0].kind == nkHiddenDeref and + mutableParameter(dest[0][0]): + discard "remains a mutable location anyhow" + else: + localError(c.config, dest.info, "attempt to mutate a borrowed location from an immutable view") of noView: discard "nothing to do" proc containsPointer(t: PType): bool = diff --git a/tests/views/tcan_compile_nim.nim b/tests/views/tcan_compile_nim.nim new file mode 100644 index 000000000..e990606cd --- /dev/null +++ b/tests/views/tcan_compile_nim.nim @@ -0,0 +1,4 @@ +discard """ + cmd: "nim check --hints:on --experimental:strictFuncs --experimental:views compiler/nim.nim" + action: "compile" +""" diff --git a/tests/views/tdont_mutate.nim b/tests/views/tdont_mutate.nim index 907aff018..d243c7c7a 100644 --- a/tests/views/tdont_mutate.nim +++ b/tests/views/tdont_mutate.nim @@ -46,3 +46,14 @@ proc main() = echo i, ": ", x main() + +# This has to continue to work: + +type + PNode = ref object + TSrcGen = object + comStack: seq[PNode] + +proc pushCom(g: var TSrcGen, n: PNode) = + setLen(g.comStack, g.comStack.len + 1) + g.comStack[^1] = n From 3bdc0005211b0d543e0ff48ccf6bc5a9f2a2a30b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Oct 2020 22:19:05 +0200 Subject: [PATCH 1328/4254] [backport] fix #15595 procvar `==` works in VM (#15724) --- compiler/vm.nim | 6 ++++-- tests/vm/tvmmisc.nim | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index ac2feac26..761186dc3 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -994,8 +994,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let nb = regs[rb].node let nc = regs[rc].node if nb.kind != nc.kind: discard - elif (nb == nc) or (nb.kind == nkNilLit): ret = true - elif nb.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit + elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional + elif sameConstant(nb, nc): ret = true + # this also takes care of procvar's, represented as nkTupleConstr, eg (nil, nil) + elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit let tb = nb.getTyp let tc = nc.getTyp ret = tb.kind in PtrLikeKinds and tc.kind == tb.kind diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index f05bb6dec..e4d6c308f 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -205,6 +205,30 @@ block: # bug #13081 static: doAssert j1.x1 == 12 +block: # bug #15595 + proc fn0()=echo 0 + proc fn1()=discard + proc main= + var local = 0 + proc fn2()=echo local + var a0 = fn0 + var a1 = fn1 + var a2 = fn2 + var a3: proc() + var a4: proc() + doAssert a0 == fn0 # bugfix + doAssert a1 == fn1 # ditto + doAssert a2 == fn2 # ditto + + doAssert fn0 != fn1 + + doAssert a2 != nil + doAssert a3 == nil # bugfix + + doAssert a3 == a4 # bugfix + static: main() + main() + # bug #15363 import sequtils From 25955440df3bf32b058ed27bdc2e619874f0d4ee Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 27 Oct 2020 07:27:02 +0100 Subject: [PATCH 1329/4254] Document implicit return values from procedures (#15738) --- doc/tut1.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/tut1.rst b/doc/tut1.rst index 24874096c..68e74df52 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -641,6 +641,16 @@ initialised with the type's default value. Note that referential data types will be ``nil`` at the start of the procedure, and thus may require manual initialisation. +A procedure that does not have any ``return`` statement and does not use the +special ``result`` variable returns the value of its last expression. For example, +this procedure + +.. code-block:: nim + :test: "nim c $1" + proc helloWorld(): string = + "Hello, World!" + +returns the string "Hello, World!". Parameters ---------- From da476a872312a4353ed1623c5328be47d1d3b145 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Oct 2020 08:35:10 +0200 Subject: [PATCH 1330/4254] fix #15740 --hint:conf now works more reliably (#15741) --- compiler/nimconf.nim | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 3e8c4d194..05f234ce6 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -287,16 +287,21 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: if cfg == DefaultConfig: runNimScriptIfExists(pd / DefaultConfigNims) - for filename in configFiles: - # delayed to here so that `hintConf` is honored - rawMessage(conf, hintConf, filename.string) - let scriptFile = conf.projectFull.changeFileExt("nims") + let isMain = scriptFile == conf.projectFull + template showHintConf = + for filename in configFiles: + # delayed to here so that `hintConf` is honored + rawMessage(conf, hintConf, filename.string) + if isMain: + showHintConf() + configFiles.setLen 0 if conf.command != "nimsuggest": runNimScriptIfExists(scriptFile) else: - if scriptFile != conf.projectFull: + if not isMain: runNimScriptIfExists(scriptFile) else: # 'nimsuggest foo.nims' means to just auto-complete the NimScript file discard + showHintConf() From 58a1eec96a98adbc3fa36abc8cc770e1a1596443 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Oct 2020 08:53:45 +0200 Subject: [PATCH 1331/4254] condsyms: add nimHasDeclaredLocs (#15735) --- compiler/condsyms.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 9771a48d3..1fbc30bbe 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -123,3 +123,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasStacktracesModule") defineSymbol("nimHasEffectTraitsModule") defineSymbol("nimHasCastPragmaBlocks") + defineSymbol("nimHasDeclaredLocs") From 066f3ebc2ae00af10f477dd9c07b94f1f161030d Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Tue, 27 Oct 2020 07:48:14 +0000 Subject: [PATCH 1332/4254] add tests for Testament "reject" action (#15709) * add test for reject action * highlight that a compilation failure is expected * add the converse test for action=reject * add trailing newline * fix wording --- testament/tests/shouldfail/treject.nim | 7 +++++++ tests/testament/treject.nim | 6 ++++++ tests/testament/tshould_not_work.nim | 2 ++ 3 files changed, 15 insertions(+) create mode 100644 testament/tests/shouldfail/treject.nim create mode 100644 tests/testament/treject.nim diff --git a/testament/tests/shouldfail/treject.nim b/testament/tests/shouldfail/treject.nim new file mode 100644 index 000000000..aaf2b4a63 --- /dev/null +++ b/testament/tests/shouldfail/treject.nim @@ -0,0 +1,7 @@ +discard """ +action: "reject" +""" + +# Because we set action="reject", we expect this line not to compile. But the +# line does compile, therefore the test fails. +assert true diff --git a/tests/testament/treject.nim b/tests/testament/treject.nim new file mode 100644 index 000000000..be2db86a9 --- /dev/null +++ b/tests/testament/treject.nim @@ -0,0 +1,6 @@ +discard """ +action: "reject" +""" + +# this line does not compile, so the test should pass, since action="reject" +let x: int = "type mismatch" diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index 501e2c32f..e4d3c7be7 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -25,6 +25,8 @@ FAIL: tests/shouldfail/toutput.nim C Failure: reOutputsDiffer FAIL: tests/shouldfail/toutputsub.nim C Failure: reOutputsDiffer +FAIL: tests/shouldfail/treject.nim C +Failure: reFilesDiffer FAIL: tests/shouldfail/tsortoutput.nim C Failure: reOutputsDiffer FAIL: tests/shouldfail/ttimeout.nim C From 12143d90c828bb4142751a6511ce790aac8aca51 Mon Sep 17 00:00:00 2001 From: Regis Caillaud <35006197+Clonkk@users.noreply.github.com> Date: Tue, 27 Oct 2020 08:52:40 +0100 Subject: [PATCH 1333/4254] Add C function dup and dup2 posix to system/io (#15675) * * Add handle to dup and dup2 posix as duplicate and duplicateTo in std/ioutils. * Added small test & changelog entry * Fixed import in tioutils removed when isMainModule * * Nest test inside block. Rename proc var -> let in captureStdout * Renamed tmpfile to iotuils.txt * Added block: # duplicate, duplicateTo * Improved docstring * Clean non-idiomatic code * Added runnable examples * rm 2 trailing space in expected output * Made syntax prettier * Runnable example: file in getTempDir() * Tmp -> Temp * Fixed runnableExamples on windows --- changelog.md | 3 +- lib/std/ioutils.nim | 85 +++++++++++++++++++++++++++++++++++++++ tests/stdlib/tioutils.nim | 49 ++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 lib/std/ioutils.nim create mode 100644 tests/stdlib/tioutils.nim diff --git a/changelog.md b/changelog.md index 8bd556e33..7f1034376 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,8 @@ - `prelude` now works with the JavaScript target. +- Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. + ## Language changes @@ -18,4 +20,3 @@ ## Tool changes - diff --git a/lib/std/ioutils.nim b/lib/std/ioutils.nim new file mode 100644 index 000000000..bef61c54a --- /dev/null +++ b/lib/std/ioutils.nim @@ -0,0 +1,85 @@ +when defined(windows): + proc c_dup(oldfd: FileHandle): FileHandle {. + importc: "_dup", header: "".} + proc c_dup2(oldfd: FileHandle, newfd: FileHandle): cint {. + importc: "_dup2", header: "".} +else: + proc c_dup(oldfd: FileHandle): FileHandle{. + importc: "dup", header: "".} + proc c_dup2(oldfd: FileHandle, newfd: FileHandle): cint {. + importc: "dup2", header: "".} + +# when false: +# const SupportIoctlInheritCtl = (defined(linux) or defined(bsd)) and +# not defined(nimscript) +# when SupportIoctlInheritCtl: +# var +# FIOCLEX {.importc, header: "".}: cint +# FIONCLEX {.importc, header: "".}: cint + +## Also defined in std/posix and system/io +proc strerror(errnum: cint): cstring {.importc, header: "".} +when not defined(nimscript): + var errno {.importc, header: "".}: cint ## error variable + +template checkError(ret: cint) = + if ret == -1: + when not defined(nimscript): + raise newException(IOError, $strerror(errno)) + else: + doAssert(false) + +proc duplicate*(oldfd: FileHandle): FileHandle = + ##[ + Return a copy of the file handle `oldfd`. + After a successful return, both `FileHandle` may be used interchangeably. + They refer to the same open file description and share file offset and status flags. + Calls POSIX function `dup` on Posix platform and `_dup` on Windows + ]## + runnableExamples: + # stdoutDuplicate is a copy of stdout FileHandle that points to STDOUT + let stdoutDuplicate = duplicate(stdout.getFileHandle()) + # Writing to stdoutDuplicate will write to stdout + doAssert(stdoutDuplicate != stdout.getFileHandle()) + # On windows, opening a file from a FileHandle does not work + when not defined(windows): + var f : File + let res = open(f, stdoutDuplicate, mode=fmWrite) + let msg = "This is a test message that will be displayed ! \n" + f.write(msg) + # Output "Test" + f.close() + + result = c_dup(oldfd) + checkError(result) + +proc duplicateTo*(oldfd: FileHandle, newfd: FileHandle) = + ##[ + Perform the same task a `duplicate` but instead of using the lowest unused file descriptor + it uses the FileHandle` specified by `newfd`. + Calls POSIX function `dup2` on Posix platform and `_dup2` on Windows. + ]## + runnableExamples: + import os + # Redirect stdout to a file temporarily + let tmpFileName = getTempDir() / "hidden_output.txt" + let stdoutFileno = stdout.getFileHandle() + let stdoutDupFd = duplicate(stdoutFileno) + + # Create a new file + let tmpFile: File = open(tmpFileName, fmAppend) + let tmpFileFd: FileHandle = tmpFile.getFileHandle() + + # stdoutFileno now writes to tmpFile + duplicateTo(tmpFileFd, stdoutFileno) + echo "This is not displayed, but written to tmpFile instead !" + + # Close file & restore stdout + tmpFile.close() + duplicateTo(stdoutDupFd, stdoutFileno) + + # stdout is now restored ! + echo "This is displayed" + + let retValue = c_dup2(oldfd, newfd) + checkError(retValue) diff --git a/tests/stdlib/tioutils.nim b/tests/stdlib/tioutils.nim new file mode 100644 index 000000000..6854a7c1c --- /dev/null +++ b/tests/stdlib/tioutils.nim @@ -0,0 +1,49 @@ +discard """ + output: ''' +hello1 +hello1 +''' +""" + +import std/ioutils +import os +from stdtest/specialpaths import buildDir + +block: # duplicate, duplicateTo + let tmpFileName = buildDir / "tioutils.txt" + template captureStdout(body) : untyped = + let stdoutFileno = stdout.getFileHandle() + # Duplicate stoudFileno + let stdout_dupfd = duplicate(stdoutFileno) + # Create a new file + # You can use append strategy if you'd like + let tmpFile: File = open(tmpFileName, fmWrite) + # Get the FileHandle (the file descriptor) of your file + let tmpFileFd: FileHandle = tmpFile.getFileHandle() + # dup2 tmpFileFd to stdoutFileno -> writing to stdoutFileno now writes to tmpFile + duplicateTo(tmpFileFd, stdoutFileno) + body + # Force flush + tmpFile.flushFile() + # Close tmp + tmpFile.close() + # Read tmp + let ret = readFile(tmpFileName) + # Restore stdout + duplicateTo(stdout_dupfd, stdoutFileno) + ret + + proc duplicateStdout() = + var msg = "hello" + echo msg & "1" + + let s = captureStdout: + echo msg & "2" + + doAssert s == "hello2\n" + + discard tryRemoveFile(tmpFileName) + duplicateStdout() + # Check it works twice + duplicateStdout() + doAssert tryRemoveFile(tmpFileName) From 218acfe3671a5a4b7a4c203b6010fdacbe32051c Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Tue, 27 Oct 2020 12:38:46 +0000 Subject: [PATCH 1334/4254] fixes #10456,#12928 issues when chaining templates to sortedByIt (#15734) * update c_malloc's to csize_t fix for broken --os:ios * I'm an idiot sorry * Create talgorithm.nim * workaround for #10456 I don't understand the intricacies of how lambdalifting and template expansions interact with lent, so i don't know how to fix the real problem, but this sidesteps whatever issue that is. * working test, use typeof rather than auto --- lib/pure/algorithm.nim | 2 +- tests/stdlib/talgorithm.nim | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/talgorithm.nim diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index a277d1429..ff835b57a 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -501,7 +501,7 @@ template sortedByIt*(seq1, op: untyped): untyped = # Nested sort assert people.sortedByIt((it.age, it.name)) == @[(name: "p2", age: 20), (name: "p3", age: 30), (name: "p4", age: 30), (name: "p1", age: 60)] - var result = sorted(seq1, proc(x, y: typeof(seq1[0])): int = + var result = sorted(seq1, proc(x, y: typeof(items(seq1), typeOfIter)): int = var it {.inject.} = x let a = op it = y diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim new file mode 100644 index 000000000..85ae79219 --- /dev/null +++ b/tests/stdlib/talgorithm.nim @@ -0,0 +1,18 @@ +discard """ + output:'''@["3", "2", "1"] + ''' +""" +#12928,10456 +import sequtils, strutils, algorithm, json + +proc test() = + try: + let info = parseJson(""" + {"a": ["1", "2", "3"]} + """) + let prefixes = info["a"].getElems().mapIt(it.getStr()).sortedByIt(it).reversed() + echo prefixes + except: + discard + +test() From 0fb878324eeb39a4707be5ab0fd6ad8412950b78 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Oct 2020 15:19:28 +0200 Subject: [PATCH 1335/4254] honor --declaredLocs in more places, including type mismatch errors; also show `kind` with --declaredLocs (#15673) * honor --declaredLocs in more places, including type mismatch errors * fix tests * show declaration location also when type mismatch names clash --- compiler/lookups.nim | 10 +++++---- compiler/semcall.nim | 9 +++----- compiler/semexprs.nim | 5 +++-- compiler/types.nim | 32 +++++++++++++++++++++------- tests/errmsgs/t8794.nim | 2 +- tests/errmsgs/undeclared_routime.nim | 4 ++-- tests/misc/tnoop.nim | 2 +- 7 files changed, 40 insertions(+), 24 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 0a6a0b950..9225706b5 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -154,12 +154,14 @@ type scope*: PScope inSymChoice: IntSet -proc getSymRepr*(conf: ConfigRef; s: PSym): string = +proc getSymRepr*(conf: ConfigRef; s: PSym, getDeclarationPath = true): string = case s.kind of routineKinds, skType: - result = getProcHeader(conf, s) + result = getProcHeader(conf, s, getDeclarationPath = getDeclarationPath) else: - result = s.name.s + result = "'$1'" % s.name.s + if getDeclarationPath: + result.addDeclaredLoc(conf, s) proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = # check if all symbols have been used and defined: @@ -172,7 +174,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = # and slow 'suggest' down: if missingImpls == 0: localError(c.config, s.info, "implementation of '$1' expected" % - getSymRepr(c.config, s)) + getSymRepr(c.config, s, getDeclarationPath=false)) inc missingImpls elif {sfUsed, sfExported} * s.flags == {}: if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam, skEnumField}: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index dd2398f87..0446d28c2 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -231,8 +231,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): doAssert err.firstMismatch.formal != nil candidates.add("\n required type for " & nameParam & ": ") candidates.add typeToString(wanted) - if wanted.sym != nil: - candidates.addDeclaredLocMaybe(c.config, wanted.sym) + candidates.addDeclaredLocMaybe(c.config, wanted) candidates.add "\n but expression '" if err.firstMismatch.kind == kVarNeeded: candidates.add renderNotLValue(nArg) @@ -242,9 +241,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add "' is of type: " var got = nArg.typ candidates.add typeToString(got) - if got.sym != nil: - candidates.addDeclaredLocMaybe(c.config, got.sym) - + candidates.addDeclaredLocMaybe(c.config, got) doAssert wanted != nil if got != nil: effectProblem(wanted, got, candidates, c) of kUnknown: discard "do not break 'nim check'" @@ -320,7 +317,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string = var o: TOverloadIter var sym = initOverloadIter(o, c, f) while sym != nil: - result &= "\n found '$1' of kind '$2'" % [getSymRepr(c.config, sym), sym.kind.toHumanStr] + result &= "\n found $1" % [getSymRepr(c.config, sym)] sym = nextOverloadIter(o, c, f) let ident = considerQuotedIdent(c, f, n).s diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2de25dadb..b2f0207e7 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -966,8 +966,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # t.kind != tySequence(It is tyProc) if typ.sym != nil and sfAnon notin typ.sym.flags and typ.kind == tyProc: - msg.add(" = " & - typeToString(typ, preferDesc)) + # when can `typ.sym != nil` ever happen? + msg.add(" = " & typeToString(typ, preferDesc)) + msg.addDeclaredLocMaybe(c.config, typ) localError(c.config, n.info, msg) return errorNode(c, n) result = nil diff --git a/compiler/types.nim b/compiler/types.nim index a3a4695b0..7e56f5002 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -124,13 +124,22 @@ proc isFloatLit*(t: PType): bool {.inline.} = result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) = - # result.add " [declared in " & conf$sym.info & "]" - result.add " [declared in " & toFileLineCol(conf, sym.info) & "]" + result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)] proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) = - if optDeclaredLocs in conf.globalOptions: + if optDeclaredLocs in conf.globalOptions and sym != nil: addDeclaredLoc(result, conf, sym) +proc addDeclaredLoc(result: var string, conf: ConfigRef; typ: PType) = + let typ = typ.skipTypes(abstractInst - {tyRange}) + result.add " [$1" % typ.kind.toHumanStr + if typ.sym != nil: + result.add " declared in " & toFileLineCol(conf, typ.sym.info) + result.add "]" + +proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) = + if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ) + proc addTypeHeader*(result: var string, conf: ConfigRef; typ: PType; prefer: TPreferedDesc = preferMixed; getDeclarationPath = true) = result.add typeToString(typ, prefer) if getDeclarationPath: result.addDeclaredLoc(conf, typ.sym) @@ -1473,12 +1482,19 @@ proc skipHiddenSubConv*(n: PNode; idgen: IdGenerator): PNode = proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) = if formal.kind != tyError and actual.kind != tyError: - let named = typeToString(formal) + let actualStr = typeToString(actual) + let formalStr = typeToString(formal) let desc = typeToString(formal, preferDesc) - let x = if named == desc: named else: named & " = " & desc - var msg = "type mismatch: got <" & - typeToString(actual) & "> " & - "but expected '" & x & "'" + let x = if formalStr == desc: formalStr else: formalStr & " = " & desc + let verbose = actualStr == formalStr or optDeclaredLocs in conf.globalOptions + var msg = "type mismatch:" + if verbose: msg.add "\n" + msg.add " got <$1>" % actualStr + if verbose: + msg.addDeclaredLoc(conf, actual) + msg.add "\n" + msg.add " but expected '$1'" % x + if verbose: msg.addDeclaredLoc(conf, formal) if formal.kind == tyProc and actual.kind == tyProc: case compatibleEffects(formal, actual) diff --git a/tests/errmsgs/t8794.nim b/tests/errmsgs/t8794.nim index 22e4014f1..9db54a9c7 100644 --- a/tests/errmsgs/t8794.nim +++ b/tests/errmsgs/t8794.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim check $options $file" errormsg: "" nimout: ''' -t8794.nim(39, 27) Error: undeclared field: 'a3' for type m8794.Foo3 [declared in m8794.nim(1, 6)] +t8794.nim(39, 27) Error: undeclared field: 'a3' for type m8794.Foo3 [type declared in m8794.nim(1, 6)] ''' """ diff --git a/tests/errmsgs/undeclared_routime.nim b/tests/errmsgs/undeclared_routime.nim index 426507652..7ef12cc0e 100644 --- a/tests/errmsgs/undeclared_routime.nim +++ b/tests/errmsgs/undeclared_routime.nim @@ -2,8 +2,8 @@ discard """ cmd: '''nim c --hints:off $file''' errormsg: "attempting to call routine: 'myiter'" nimout: '''undeclared_routime.nim(13, 15) Error: attempting to call routine: 'myiter' - found 'undeclared_routime.myiter(a: string)[declared in undeclared_routime.nim(10, 9)]' of kind 'iterator' - found 'undeclared_routime.myiter()[declared in undeclared_routime.nim(11, 9)]' of kind 'iterator' + found 'undeclared_routime.myiter(a: string)[iterator declared in undeclared_routime.nim(10, 9)]' + found 'undeclared_routime.myiter()[iterator declared in undeclared_routime.nim(11, 9)]' ''' """ diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim index a1365cfbe..7f5bb1045 100644 --- a/tests/misc/tnoop.nim +++ b/tests/misc/tnoop.nim @@ -1,6 +1,6 @@ discard """ nimout: ''' - found 'a' of kind 'var' + found 'a' [var declared in tnoop.nim(11, 3)] ''' file: "tnoop.nim" line: 13 From f8cac6bbbcfa8ddc649160945a17a6f5b7a4d9d6 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 27 Oct 2020 23:09:26 +0000 Subject: [PATCH 1336/4254] fix #15752 (#15754) --- compiler/sizealignoffsetimpl.nim | 8 ++++---- tests/enum/tenum.nim | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 3e536f5d7..2c764fe12 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -277,14 +277,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.size = 4 # use signed int32 typ.align = 4 else: - let length = toInt64(lastOrd(conf, typ)) # BUGFIX: use lastOrd! - if length + 1 < `shl`(1, 8): + let lastOrd = toInt64(lastOrd(conf, typ)) # BUGFIX: use lastOrd! + if lastOrd < `shl`(1, 8): typ.size = 1 typ.align = 1 - elif length + 1 < `shl`(1, 16): + elif lastOrd < `shl`(1, 16): typ.size = 2 typ.align = 2 - elif length + 1 < `shl`(BiggestInt(1), 32): + elif lastOrd < `shl`(BiggestInt(1), 32): typ.size = 4 typ.align = 4 else: diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index 8cc578d3c..aa338ee2c 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -154,3 +154,12 @@ block nonzero: # bug #6959 B C let slice = SomeEnum.low..SomeEnum.high + +block size_one_byte: #issue 15752 + type + Flag = enum + Disabled = 0x00 + Enabled = 0xFF + + static: + assert 1 == sizeof(Flag) \ No newline at end of file From b13fb9ddb869d46a6bcc5d9f8cb6576be17c3f22 Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 28 Oct 2020 08:57:42 +0100 Subject: [PATCH 1337/4254] fix #15750 --- lib/pure/collections/tables.nim | 2 ++ tests/collections/ttables.nim | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index bd46bdd27..1d76d42ea 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1619,6 +1619,8 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool = if s.counter != t.counter: return false + if s.counter == 0 and t.counter == 0: + return true var ht = t.first var hs = s.first while ht >= 0 and hs >= 0: diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index af8364488..4d94b3d95 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -456,3 +456,9 @@ block testNonPowerOf2: var b = initTable[int, int](9) b[1] = 10 assert b[1] == 10 + +block emptyOrdered: + var t1: OrderedTable[int, string] + var t2: OrderedTable[int, string] + assert t1 == t2 + From 732ddc02da9b6203e402d246078827d525434e6b Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 28 Oct 2020 08:57:52 +0100 Subject: [PATCH 1338/4254] change/remove deprecated stuff --- tests/collections/ttables.nim | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 4d94b3d95..338a83fed 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -23,7 +23,7 @@ block tableadds: proc main = var tab = newTable[string, string]() for i in 0..1000: - tab.add "key", "value " & $i + tab["key"] = "value " & $i main() echo "done tableadds" @@ -133,8 +133,8 @@ block tindexby: doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table" var tbl1 = initTable[int, int]() - tbl1.add(1,1) - tbl1.add(2,2) + tbl1[1] = 1 + tbl1[2] = 2 doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table" type @@ -147,8 +147,8 @@ block tindexby: elem2 = TElem(foo: 2, bar: "baz") var tbl2 = initTable[string, TElem]() - tbl2.add("bar", elem1) - tbl2.add("baz", elem2) + tbl2["bar"] = elem1 + tbl2["baz"] = elem2 doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table" @@ -197,24 +197,6 @@ block ttables2: run1() echo "2" -block allValues: - var t: Table[int, string] - var key = 0 - let n = 1000 - for i in 0.. Date: Wed, 28 Oct 2020 13:00:49 +0000 Subject: [PATCH 1339/4254] ARC now capable of custom extra alignment. Ref, closure and seq support. (#15697) --- compiler/ccgexprs.nim | 22 ++- compiler/liftdestructors.nim | 8 +- lib/core/typeinfo.nim | 4 +- lib/system/arc.nim | 47 +++--- lib/system/bitmasks.nim | 6 +- lib/system/deepcopy.nim | 2 +- lib/system/memalloc.nim | 81 ++++++++++ lib/system/orc.nim | 2 +- lib/system/seqs_v2.nim | 15 +- tests/arc/thard_alignment.nim | 146 ++++++++++++++++++ .../collections/thardalignmentconstraint.nim | 17 -- 11 files changed, 273 insertions(+), 77 deletions(-) create mode 100644 tests/arc/thard_alignment.nim delete mode 100644 tests/collections/thardalignmentconstraint.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b6caec760..1eb6caeb3 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1278,11 +1278,11 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = if optTinyRtti in p.config.globalOptions: if needsInit: - b.r = ropecg(p.module, "($1) #nimNewObj($2)", - [getTypeDesc(p.module, typ), sizeExpr]) + b.r = ropecg(p.module, "($1) #nimNewObj($2, NIM_ALIGNOF($3))", + [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)]) else: - b.r = ropecg(p.module, "($1) #nimNewObjUninit($2)", - [getTypeDesc(p.module, typ), sizeExpr]) + b.r = ropecg(p.module, "($1) #nimNewObjUninit($2, NIM_ALIGNOF($3))", + [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)]) genAssignment(p, a, b, {}) else: let ti = genTypeInfoV1(p.module, typ, a.lode.info) @@ -2191,14 +2191,10 @@ proc genDestroy(p: BProc; n: PNode) = of tySequence: var a: TLoc initLocExpr(p, arg, a) - if optThreads in p.config.globalOptions: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #deallocShared($1.p);$n" & - "}$n", [rdLoc(a)]) - else: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #dealloc($1.p);$n" & - "}$n", [rdLoc(a)]) + linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & + " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & + "}$n", + [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) else: discard "nothing to do" else: let t = n[1].typ.skipTypes(abstractVar) @@ -2217,7 +2213,7 @@ proc genDispose(p: BProc; n: PNode) = if elemType.destructor != nil: var destroyCall = newNodeI(nkCall, n.info) genStmts(p, destroyCall) - lineCg(p, cpsStmts, ["#nimRawDispose($#)", rdLoc(a)]) + lineFmt(p, cpsStmts, "#nimRawDispose($1, NIM_ALIGNOF($2))", [rdLoc(a), getTypeDesc(p.module, elemType)]) else: # ``nimRawDisposeVirtual`` calls the ``finalizer`` which is the same as the # destructor, but it uses the runtime type. Afterwards the memory is freed: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 30094875c..9b6c179db 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -515,7 +515,9 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if isFinal(elemType): addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) + var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) + alignOf.typ = getSysType(c.g, c.info, tyInt) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf) else: addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) @@ -638,7 +640,9 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if isFinal(elemType): addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) + var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) + alignOf.typ = getSysType(c.g, c.info, tyInt) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf) else: addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 9fd8ebf8c..5c4e1b601 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -108,7 +108,7 @@ when not defined(gcDestructors): proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.} proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.} else: - proc nimNewObj(size: int): pointer {.importCompilerProc.} + proc nimNewObj(size, align: int): pointer {.importCompilerProc.} proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.importCompilerProc.} proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. importCompilerProc.} @@ -178,7 +178,7 @@ proc invokeNew*(x: Any) = ## performs ``new(x)``. `x` needs to represent a ``ref``. assert x.rawType.kind == tyRef when defined(gcDestructors): - cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size) + cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size, x.rawType.base.align) else: var z = newObj(x.rawType, x.rawType.base.size) genericAssign(x.value, addr(z), x.rawType) diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 46579eaef..0eecadd66 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -75,14 +75,13 @@ when defined(nimArcDebug): elif defined(nimArcIds): var gRefId: int -proc nimNewObj(size: int): pointer {.compilerRtl.} = - let s = size + sizeof(RefHeader) +proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} = + let hdrSize = align(sizeof(RefHeader), alignment) + let s = size + hdrSize when defined(nimscript): discard - elif compileOption("threads"): - result = allocShared0(s) +! sizeof(RefHeader) else: - result = alloc0(s) +! sizeof(RefHeader) + result = alignedAlloc0(s, alignment) +! hdrSize when defined(nimArcDebug) or defined(nimArcIds): head(result).refId = gRefId atomicInc gRefId @@ -92,20 +91,18 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) -proc nimNewObjUninit(size: int): pointer {.compilerRtl.} = +proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} = # Same as 'newNewObj' but do not initialize the memory to zero. # The codegen proved for us that this is not necessary. - let s = size + sizeof(RefHeader) + let hdrSize = align(sizeof(RefHeader), alignment) + let s = size + hdrSize when defined(nimscript): discard - elif compileOption("threads"): - var orig = cast[ptr RefHeader](allocShared(s)) else: - var orig = cast[ptr RefHeader](alloc(s)) - orig.rc = 0 + result = cast[ptr RefHeader](alignedAlloc0(s, alignment) +! hdrSize) + head(result).rc = 0 when defined(gcOrc): - orig.rootIdx = 0 - result = orig +! sizeof(RefHeader) + head(result).rootIdx = 0 when defined(nimArcDebug): head(result).refId = gRefId atomicInc gRefId @@ -147,7 +144,7 @@ when not defined(nimscript) and defined(nimArcDebug): else: result = 0 -proc nimRawDispose(p: pointer) {.compilerRtl.} = +proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} = when not defined(nimscript): when traceCollector: cprintf("[Freed] %p\n", p -! sizeof(RefHeader)) @@ -155,27 +152,21 @@ proc nimRawDispose(p: pointer) {.compilerRtl.} = if head(p).rc >= rcIncrement: cstderr.rawWrite "[FATAL] dangling references exist\n" quit 1 - - when defined(gcOrc) and defined(nimArcDebug): - if (head(p).rc and 0b100) != 0: - cstderr.rawWrite "[FATAL] cycle root freed\n" - quit 1 - when defined(nimArcDebug): # we do NOT really free the memory here in order to reliably detect use-after-frees if freedCells.data == nil: init(freedCells) freedCells.incl head(p) - elif compileOption("threads"): - deallocShared(p -! sizeof(RefHeader)) else: - dealloc(p -! sizeof(RefHeader)) + let hdrSize = align(sizeof(RefHeader), alignment) + alignedDealloc(p -! hdrSize, alignment) -template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x)) +template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf) #proc dispose*(x: pointer) = nimRawDispose(x) proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = - let d = cast[ptr PNimTypeV2](p)[].destructor - if d != nil: cast[DestructorProc](d)(p) + let rti = cast[ptr PNimTypeV2](p) + if rti.destructor != nil: + cast[DestructorProc](rti.destructor)(p) when false: cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name cstderr.rawWrite "\n" @@ -183,7 +174,7 @@ proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = cstderr.rawWrite "bah, nil\n" else: cstderr.rawWrite "has destructor!\n" - nimRawDispose(p) + nimRawDispose(p, rti.align) when defined(gcOrc): when defined(nimThinout): @@ -216,7 +207,7 @@ proc GC_unref*[T](x: ref T) = if nimDecRefIsLast(cast[pointer](x)): # XXX this does NOT work for virtual destructors! `=destroy`(x[]) - nimRawDispose(cast[pointer](x)) + nimRawDispose(cast[pointer](x), T.alignOf) proc GC_ref*[T](x: ref T) = ## New runtime only supports this operation for 'ref T'. diff --git a/lib/system/bitmasks.nim b/lib/system/bitmasks.nim index 922ad5fb7..d7c55a4d9 100644 --- a/lib/system/bitmasks.nim +++ b/lib/system/bitmasks.nim @@ -15,7 +15,11 @@ const PageSize = 1 shl PageShift PageMask = PageSize-1 - MemAlign = 16 # also minimal allocatable memory block + MemAlign = # also minimal allocatable memory block + when defined(useMalloc): + when defined(amd64): 16 + else: 8 + else: 16 BitsPerPage = PageSize div MemAlign UnitsPerPage = BitsPerPage div (sizeof(int)*8) diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index b9dc594fa..1f30b8427 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -163,7 +163,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = when defined(nimSeqsV2): let typ = if mt.base.kind == tyObject: cast[PNimType](cast[ptr PNimTypeV2](s2)[].typeInfoV1) else: mt.base - let z = nimNewObj(typ.size) + let z = nimNewObj(typ.size, typ.align) cast[PPointer](dest)[] = z else: # this version should work for any other GC: diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index 142762fe7..5f4304502 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -304,6 +304,87 @@ when hasAlloc and not defined(js): ## or other memory may be corrupted. deallocShared(p) + include bitmasks + + template `+!`(p: pointer, s: SomeInteger): pointer = + cast[pointer](cast[int](p) +% int(s)) + + template `-!`(p: pointer, s: SomeInteger): pointer = + cast[pointer](cast[int](p) -% int(s)) + + proc alignedAlloc(size, align: Natural): pointer = + if align <= MemAlign: + when compileOption("threads"): + result = allocShared(size) + else: + result = alloc(size) + else: + # allocate (size + align - 1) necessary for alignment, + # plus 2 bytes to store offset + when compileOption("threads"): + let base = allocShared(size + align - 1 + sizeof(uint16)) + else: + let base = alloc(size + align - 1 + sizeof(uint16)) + # memory layout: padding + offset (2 bytes) + user_data + # in order to deallocate: read offset at user_data - 2 bytes, + # then deallocate user_data - offset + let offset = align - (cast[int](base) and (align - 1)) + cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) + result = base +! offset + + proc alignedAlloc0(size, align: Natural): pointer = + if align <= MemAlign: + when compileOption("threads"): + result = allocShared0(size) + else: + result = alloc0(size) + else: + # see comments for alignedAlloc + when compileOption("threads"): + let base = allocShared0(size + align - 1 + sizeof(uint16)) + else: + let base = alloc0(size + align - 1 + sizeof(uint16)) + let offset = align - (cast[int](base) and (align - 1)) + cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) + result = base +! offset + + proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = + if align <= MemAlign: + when compileOption("threads"): + deallocShared(p) + else: + dealloc(p) + else: + # read offset at p - 2 bytes, then deallocate (p - offset) pointer + let offset = cast[ptr uint16](p -! sizeof(uint16))[] + when compileOption("threads"): + deallocShared(p -! offset) + else: + dealloc(p -! offset) + + proc alignedRealloc(p: pointer, oldSize, newSize, align: Natural): pointer = + if align <= MemAlign: + when compileOption("threads"): + result = reallocShared(p, newSize) + else: + result = realloc(p, newSize) + else: + result = alignedAlloc(newSize, align) + copyMem(result, p, oldSize) + alignedDealloc(p, align) + + proc alignedRealloc0(p: pointer, oldSize, newSize, align: Natural): pointer = + if align <= MemAlign: + when compileOption("threads"): + result = reallocShared0(p, oldSize, newSize) + else: + result = realloc0(p, oldSize, newSize) + else: + result = alignedAlloc(newSize, align) + copyMem(result, p, oldSize) + zeroMem(result +! oldSize, newSize - oldSize) + alignedDealloc(p, align) + {.pop.} # GC interface: diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 3c2327fd5..28f8e5808 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -88,7 +88,7 @@ proc free(s: Cell; desc: PNimTypeV2) {.inline.} = else: cstderr.rawWrite "has dispose!\n" - nimRawDispose(p) + nimRawDispose(p, desc.align) proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inline.} = let p = cast[ptr pointer](q) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index d83a0009a..b7f24ecd5 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -35,10 +35,7 @@ proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises # we have to use type erasure here as Nim does not support generic # compilerProcs. Oh well, this will all be inlined anyway. if cap > 0: - when compileOption("threads"): - var p = cast[ptr NimSeqPayloadBase](allocShared0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize)) - else: - var p = cast[ptr NimSeqPayloadBase](alloc0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize)) + var p = cast[ptr NimSeqPayloadBase](alignedAlloc0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize, elemAlign)) p.cap = cap result = p else: @@ -65,20 +62,14 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin let oldCap = p.cap and not strlitFlag let newCap = max(resize(oldCap), len+addlen) if (p.cap and strlitFlag) == strlitFlag: - when compileOption("threads"): - var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * newCap)) - else: - var q = cast[ptr NimSeqPayloadBase](alloc0(headerSize + elemSize * newCap)) + var q = cast[ptr NimSeqPayloadBase](alignedAlloc0(headerSize + elemSize * newCap, elemAlign)) copyMem(q +! headerSize, p +! headerSize, len * elemSize) q.cap = newCap result = q else: let oldSize = headerSize + elemSize * oldCap let newSize = headerSize + elemSize * newCap - when compileOption("threads"): - var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize)) - else: - var q = cast[ptr NimSeqPayloadBase](realloc0(p, oldSize, newSize)) + var q = cast[ptr NimSeqPayloadBase](alignedRealloc0(p, oldSize, newSize, elemAlign)) q.cap = newCap result = q diff --git a/tests/arc/thard_alignment.nim b/tests/arc/thard_alignment.nim new file mode 100644 index 000000000..e644572f0 --- /dev/null +++ b/tests/arc/thard_alignment.nim @@ -0,0 +1,146 @@ +discard """ +disabled: "arm64" +cmd: "nim c --gc:arc $file" +output: "y" +""" + +{.passC: "-march=native".} + +proc isAlignedCheck(p: pointer, alignment: int) = + doAssert (cast[uint](p) and uint(alignment - 1)) == 0 + +proc isAlignedCheck[T](p: ref T, alignment: int) = + isAlignedCheck(cast[pointer](p), alignment) + +type + m256d {.importc: "__m256d", header: "immintrin.h".} = object + +proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".} +func `+`(a,b: m256d): m256d {.importc: "_mm256_add_pd", header: "immintrin.h".} +proc `$`(a: m256d): string = + result = $(cast[ptr float](a.unsafeAddr)[]) + + +var res: seq[seq[m256d]] + +for _ in 1..1000: + var x = newSeq[m256d](1) + x[0] = set1(1.0) # test if operation causes segfault + isAlignedCheck(x[0].addr, alignof(m256d)) + res.add x + +var res2: seq[m256d] +for i in 1..10000: + res2.setLen(res2.len + 1) # check if realloc works + isAlignedCheck(res2[0].addr, alignof(m256d)) + +proc lambdaGen(a, b: float, z: ref m256d) : auto = + var x1 = new(m256d) + var x2 = new(m256d) + isAlignedCheck(x1, alignof(m256d)) + isAlignedCheck(x2, alignof(m256d)) + x1[] = set1(2.0 + a) + x2[] = set1(-23.0 - b) + let capturingLambda = proc(x: ref m256d): ref m256d = + var cc = new(m256d) + var bb = new(m256d) + isAlignedCheck(x1, alignof(m256d)) + isAlignedCheck(x2, alignof(m256d)) + isAlignedCheck(cc, alignof(m256d)) + isAlignedCheck(bb, alignof(m256d)) + isAlignedCheck(z, alignof(m256d)) + + cc[] = x1[] + x1[] + z[] + bb[] = x2[] + set1(12.5) + z[] + + result = new(m256d) + isAlignedCheck(result, alignof(m256d)) + result[] = cc[] + bb[] + x[] + + return capturingLambda + +var xx = new(m256d) +xx[] = set1(10) +isAlignedCheck(xx, alignOf(m256d)) + +let f1 = lambdaGen(2.0 , 2.221, xx) +let f2 = lambdaGen(-1.226 , 3.5, xx) +isAlignedCheck(f1(xx), alignOf(m256d)) +isAlignedCheck(f2(xx), alignOf(m256d)) + + +#----------------------------------------------------------------------------- + +type + MyAligned = object of RootObj + a{.align: 128.}: float + + +var f: MyAligned +isAlignedCheck(f.addr, MyAligned.alignOf) + +var fref = new(MyAligned) +isAlignedCheck(fref, MyAligned.alignOf) + +var fs: seq[MyAligned] +var fr: seq[RootRef] + +for i in 0..1000: + fs.add MyAligned() + isAlignedCheck(fs[^1].addr, MyAligned.alignOf) + fs[^1].a = i.float + + fr.add new(MyAligned) + isAlignedCheck(fr[^1], MyAligned.alignOf) + ((ref MyAligned)fr[^1])[].a = i.float + +for i in 0..1000: + doAssert(fs[i].a == i.float) + doAssert(((ref MyAligned)fr[i]).a == i.float) + + +proc lambdaTest2(a: MyAligned, z: ref MyAligned): auto = + var x1: MyAligned + x1.a = a.a + z.a + var x2: MyAligned + x2.a = a.a - z.a + let capturingLambda = proc(x: MyAligned): MyAligned = + var cc: MyAligned + var bb: MyAligned + isAlignedCheck(x1.addr, MyAligned.alignOf) + isAlignedCheck(x2.addr, MyAligned.alignOf) + isAlignedCheck(cc.addr, MyAligned.alignOf) + isAlignedCheck(bb.addr, MyAligned.alignOf) + isAlignedCheck(z, MyAligned.alignOf) + + cc.a = x1.a + x1.a + z.a + bb.a = x2.a - z.a + + isAlignedCheck(result.addr, MyAligned.alignOf) + result.a = cc.a + bb.a + x2.a + + return capturingLambda + + +let q1 = lambdaTest2(MyAligned(a: 1.0), (ref MyAligned)(a: 2.0)) +let q2 = lambdaTest2(MyAligned( a: -1.0), (ref MyAligned)(a: -2.0)) + +isAlignedCheck(rawEnv(q1), MyAligned.alignOf) +isAlignedCheck(rawEnv(q2), MyAligned.alignOf) +discard q1(MyAligned(a: 1.0)) +discard q2(MyAligned(a: -1.0)) + + +#----------------------------------------------------------------------------- + +block: + var s: seq[seq[MyAligned]] + for len in 0..128: + s.add newSeq[MyAligned](len) + for i in 0.. 0: + isAlignedCheck(s[^1][0].addr, MyAligned.alignOf) + +echo "y" diff --git a/tests/collections/thardalignmentconstraint.nim b/tests/collections/thardalignmentconstraint.nim deleted file mode 100644 index e3a3081b9..000000000 --- a/tests/collections/thardalignmentconstraint.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ -disabled: true -""" - -# does not yet work - -{.passC: "-march=native".} - -type - m256d {.importc: "__m256d", header: "immintrin.h".} = object - -proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".} - -for _ in 1..1000: - var x = newSeq[m256d](1) - x[0] = set1(1.0) # test if operation causes segfault - doAssert (cast[uint](x[0].addr) and 31) == 0 From 610e9b2fe9d5908b9941939e975f394aba009b43 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 28 Oct 2020 13:24:38 +0000 Subject: [PATCH 1340/4254] fix #15756 (#15761) * fix #15756 * simplify test --- compiler/varpartitions.nim | 2 +- tests/effects/tstrict_funcs.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 49221654d..34a64c759 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -126,7 +126,7 @@ proc hasSideEffect*(c: var Partitions; info: var MutationInfo): bool = return true return false -template isConstParam(a): bool = a.kind == skParam and a.typ.kind != tyVar +template isConstParam(a): bool = a.kind == skParam and a.typ.kind notin {tyVar, tySink} proc variableId(c: Partitions; x: PSym): int = for i in 0 ..< c.s.len: diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 166ab77c1..75ed9c8d9 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -15,3 +15,15 @@ proc get_Contig2Reads(sin: Stream, fn: string, contig2len: TableRef[string, int] if contig2len.haskey(parser.row[1]): mgetOrPut(result, parser.row[1], @[]).add(parser.row[0]) + + +block: + # issue #15756 + func `&&&`[T](x: var seq[T], y: sink T): seq[T] = + newSeq(result, x.len + 1) + for i in 0..x.len-1: + result[i] = move(x[i]) + result[x.len] = move(y) + + var x = @[0, 1] + let z = x &&& 2 \ No newline at end of file From 94e2b9e83725d8bcaa43f4bb3e64b8c79d3bec95 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Wed, 28 Oct 2020 18:54:42 +0200 Subject: [PATCH 1341/4254] Make newObjUninit proc to adhere to its name (#15764) Co-authored-by: b3liever --- lib/system/arc.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 0eecadd66..4c97f1aa0 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -99,7 +99,7 @@ proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} = when defined(nimscript): discard else: - result = cast[ptr RefHeader](alignedAlloc0(s, alignment) +! hdrSize) + result = cast[ptr RefHeader](alignedAlloc(s, alignment) +! hdrSize) head(result).rc = 0 when defined(gcOrc): head(result).rootIdx = 0 @@ -165,7 +165,7 @@ template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignO proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = let rti = cast[ptr PNimTypeV2](p) - if rti.destructor != nil: + if rti.destructor != nil: cast[DestructorProc](rti.destructor)(p) when false: cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name From 485d4ff802c361f363d2f455b98abc5db1a7082d Mon Sep 17 00:00:00 2001 From: Tim Smith <69870077+timscodebase@users.noreply.github.com> Date: Wed, 28 Oct 2020 09:56:56 -0700 Subject: [PATCH 1342/4254] Spelling and Grammer fixes (#15719) Co-authored-by: Tim Smith Co-authored-by: Miran --- doc/gc.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index 23c4f64cf..804481cd9 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -102,10 +102,14 @@ These two procs are the two modus operandi of the real-time garbage collector: To bind all garbage collector activity to a ``GC_step`` call, deactivate the garbage collector with ``GC_disable`` at program startup. If ``strongAdvice`` is set to ``true``, - then the garbage collector will be forced to perform collection cycle. + then the garbage collector will be forced to perform the collection cycle. Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. You may also specify the current stack size via ``stackSize`` parameter. + It can improve performance when you know that there are no unique Nim references + below a certain point on the stack. Make sure the size you specify is greater + than the potential worst-case size. + It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size. @@ -174,7 +178,7 @@ Heap dump The heap dump feature is still in its infancy, but it already proved useful for us, so it might be useful for you. To get a heap dump, compile with ``-d:nimTypeNames`` and call ``dumpNumberOfInstances`` at a strategic place in your program. -This produces a list of used types in your program and for every type +This produces a list of the used types in your program and for every type the total amount of object instances for this type as well as the total amount of bytes these instances take up. From 0cae8ef2caccaf1104b21ab957dd877d5c2f461c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yanis=20Zafir=C3=B3pulos?= <1265028+drkameleon@users.noreply.github.com> Date: Thu, 29 Oct 2020 10:33:47 +0100 Subject: [PATCH 1343/4254] Massive documentation fixes + copy editing (#15747) --- doc/apis.rst | 2 +- doc/backends.rst | 41 ++--- doc/destructors.rst | 24 +-- doc/docgen.rst | 46 ++--- doc/drnim.rst | 8 +- doc/hcr.rst | 6 +- doc/koch.rst | 4 +- doc/lib.rst | 79 ++++---- doc/manual.rst | 357 ++++++++++++++++++------------------ doc/manual/var_t_return.rst | 2 +- doc/nimc.rst | 83 +++++---- doc/niminst.rst | 8 +- doc/testament.rst | 8 +- doc/tools.rst | 4 +- doc/tut1.rst | 106 +++++------ doc/tut3.rst | 34 ++-- 16 files changed, 401 insertions(+), 411 deletions(-) diff --git a/doc/apis.rst b/doc/apis.rst index d0327c76e..03374c2db 100644 --- a/doc/apis.rst +++ b/doc/apis.rst @@ -3,7 +3,7 @@ API naming design ================= The API is designed to be **easy to use** and consistent. Ease of use is -measured by the number of calls to achieve a concrete high level action. +measured by the number of calls to achieve a concrete high-level action. Naming scheme diff --git a/doc/backends.rst b/doc/backends.rst index e46941a12..b50c7e38f 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -15,16 +15,16 @@ Introduction The `Nim Compiler User Guide `_ documents the typical compiler invocation, using the ``compile`` or ``c`` command to transform a ``.nim`` file into one or more ``.c`` files which are then compiled with the -platform's C compiler into a static binary. However there are other commands -to compile to C++, Objective-C or JavaScript. This document tries to +platform's C compiler into a static binary. However, there are other commands +to compile to C++, Objective-C, or JavaScript. This document tries to concentrate in a single place all the backend and interfacing options. The Nim compiler supports mainly two backend families: the C, C++ and Objective-C targets and the JavaScript target. `The C like targets -<#backends-the-c-like-targets>`_ creates source files which can be compiled +<#backends-the-c-like-targets>`_ creates source files that can be compiled into a library or a final executable. `The JavaScript target <#backends-the-javascript-target>`_ can generate a ``.js`` file which you -reference from an HTML file or create a `standalone nodejs program +reference from an HTML file or create a `standalone Node.js program `_. On top of generating libraries or standalone applications, Nim offers @@ -48,7 +48,7 @@ The most significant difference between these commands is that if you look into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m`` files, other than that all of them will produce a native binary for your project. This allows you to take the generated code and place it directly -into a project using any of these languages. Here are some typical command +into a project using any of these languages. Here are some typical command- line invocations:: $ nim c hallo.nim @@ -56,8 +56,8 @@ line invocations:: $ nim objc hallo.nim The compiler commands select the target backend, but if needed you can -`specify additional switches for cross compilation -`_ to select the target CPU, operative system +`specify additional switches for cross-compilation +`_ to select the target CPU, operative system or compiler/linker commands. @@ -79,7 +79,7 @@ available. This includes: * OS-specific operations * threading, coroutines * some modules of the standard library -* proper 64 bit integer arithmetic +* proper 64-bit integer arithmetic To compensate, the standard library has modules `catered to the JS backend `_ @@ -119,7 +119,7 @@ pragmas to call methods from classes. Whenever you use any of these pragmas you need to integrate native code into your final binary. In the case of JavaScript this is no problem at all, the -same html file which hosts the generated JavaScript will likely provide other +same HTML file which hosts the generated JavaScript will likely provide other JavaScript functions which you are importing with ``importc``. However, for the C like targets you need to link external code either @@ -167,7 +167,7 @@ With these two files in place, you can run ``nim c -r calculator.nim`` and the Nim compiler will compile the ``logic.c`` file in addition to ``calculator.nim`` and link both into an executable, which outputs ``10`` when run. Another way to link the C file statically and get the same effect would -be remove the line with the ``compile`` pragma and run the following typical +be to remove the line with the ``compile`` pragma and run the following typical Unix commands:: $ gcc -c logic.c @@ -211,7 +211,7 @@ calculator.nim`` and open ``host.html`` in a browser. If the browser supports javascript, you should see the value ``10`` in the browser's console. Use the `dom module `_ for specific DOM querying and modification procs or take a look at `karax `_ for how to -develop browser based applications. +develop browser-based applications. Backend code calling Nim @@ -220,7 +220,7 @@ Backend code calling Nim Backend code can interface with Nim code exposed through the `exportc pragma `_. The ``exportc`` pragma is the *generic* way of making Nim symbols available to -the backends. By default the Nim compiler will mangle all the Nim symbols to +the backends. By default, the Nim compiler will mangle all the Nim symbols to avoid any name collision, so the most significant thing the ``exportc`` pragma does is maintain the Nim symbol name, or if specified, use an alternative symbol for the backend in case the symbol rules don't match. @@ -233,7 +233,7 @@ the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. The Nim compiler can generate a C interface header through the ``--header`` -command line switch. The generated header will contain all the exported +command-line switch. The generated header will contain all the exported symbols and the ``NimMain`` proc which you need to call before any other Nim code. @@ -322,8 +322,8 @@ from the previous section): Compile the Nim code to JavaScript with ``nim js -o:fib.js fib.nim`` and open ``mhost.html`` in a browser. If the browser supports javascript, you should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned -earlier, JavaScript doesn't require an initialisation call to ``NimMain`` or -similar function and you can call the exported Nim proc directly. +earlier, JavaScript doesn't require an initialization call to ``NimMain`` or +a similar function and you can call the exported Nim proc directly. Nimcache naming logic @@ -333,15 +333,15 @@ The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default name for the directory depends on the used backend and on your OS but you can use the ``--nimcache`` `compiler switch -`_ to change it. +`_ to change it. Memory management ================= -In the previous sections the ``NimMain()`` function reared its head. Since +In the previous sections, the ``NimMain()`` function reared its head. Since JavaScript already provides automatic memory management, you can freely pass -objects between the two language without problems. In C and derivate languages +objects between the two languages without problems. In C and derivate languages you need to be careful about what you do and how you share memory. The previous examples only dealt with simple scalar values, but passing a Nim string to C, or reading back a C string in Nim already requires you to be @@ -355,7 +355,7 @@ The manual mentions that `Nim strings are implicitly convertible to cstrings `_ which makes interaction usually painless. Most C functions accepting a Nim string converted to a ``cstring`` will likely not need to keep this string around and by the time -they return the string won't be needed any more. However, for the rare cases +they return the string won't be needed anymore. However, for the rare cases where a Nim string has to be preserved and made available to the C backend as a ``cstring``, you will need to manually prevent the string data from being freed with `GC_ref `_ and `GC_unref @@ -388,7 +388,7 @@ to hand a Nim reference to C code, you will need to use `GC_ref `_ to mark the reference as used, so it does not get freed. And for the C backend you will need to expose the `GC_unref `_ proc to clean up this memory when it is not -required any more. +required anymore. Again, if you are wrapping a library which *mallocs* and *frees* data structures, you need to expose the appropriate *free* function to Nim so @@ -424,4 +424,3 @@ leaks by calling .. code-block:: nim system.tearDownForeignThreadGc() - diff --git a/doc/destructors.rst b/doc/destructors.rst index b581fce3e..ff09d6644 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -25,7 +25,7 @@ move semantics and destructors work in Nim. Motivating example ================== -With the language mechanisms described here a custom seq could be +With the language mechanisms described here, a custom seq could be written as: .. code-block:: nim @@ -88,7 +88,7 @@ Lifetime-tracking hooks ======================= The memory management for Nim's standard ``string`` and ``seq`` types as -well as other standard collections is performed via so called +well as other standard collections is performed via so-called "Lifetime-tracking hooks" or "type-bound operators". There are 3 different hooks for each (generic or concrete) object type ``T`` (``T`` can also be a ``distinct`` type) that are called implicitly by the compiler. @@ -128,13 +128,13 @@ The general pattern in ``=destroy`` looks like: ------------ A `=sink` hook moves an object around, the resources are stolen from the source -and passed to the destination. It is ensured that source's destructor does -not free the resources afterwards by setting the object to its default value +and passed to the destination. It is ensured that the source's destructor does +not free the resources afterward by setting the object to its default value (the value the object's state started in). Setting an object ``x`` back to its default value is written as ``wasMoved(x)``. When not provided the compiler is using a combination of `=destroy` and `copyMem` instead. This is efficient hence users rarely need to implement their own `=sink` operator, it is enough to -provide `=destroy` and `=copy`, compiler will take care about the rest. +provide `=destroy` and `=copy`, compiler will take care of the rest. The prototype of this hook for a type ``T`` needs to be: @@ -191,7 +191,7 @@ Move semantics ============== A "move" can be regarded as an optimized copy operation. If the source of the -copy operation is not used afterwards, the copy can be replaced by a move. This +copy operation is not used afterward, the copy can be replaced by a move. This document uses the notation ``lastReadOf(x)`` to describe that ``x`` is not used afterwards. This property is computed by a static control flow analysis but can also be enforced by using ``system.move`` explicitly. @@ -218,7 +218,7 @@ Sink parameters =============== To move a variable into a collection usually ``sink`` parameters are involved. -A location that is passed to a ``sink`` parameter should not be used afterwards. +A location that is passed to a ``sink`` parameter should not be used afterward. This is ensured by a static analysis over a control flow graph. If it cannot be proven to be the last usage of the location, a copy is done instead and this copy is then passed to the sink parameter. @@ -232,7 +232,7 @@ without any further overloads and ``put`` might not take ownership of ``k`` if not a linear type system. The employed static analysis is limited and only concerned with local variables; -however object and tuple fields are treated as separate entities: +however, object and tuple fields are treated as separate entities: .. code-block:: nim @@ -509,7 +509,7 @@ to avoid this overhead: In fact, ``.cursor`` more generally prevents object construction/destruction pairs and so can also be useful in other contexts. The alternative solution would be to use raw pointers (``ptr``) instead which is more cumbersome and also more dangerous -for Nim's evolution: Later on the compiler can try to prove ``.cursor`` annotations +for Nim's evolution: Later on, the compiler can try to prove ``.cursor`` annotations to be safe, but for ``ptr`` the compiler has to remain silent about possible problems. @@ -522,7 +522,7 @@ a form of copy elision. To see how and when we can do that, think about this question: In `dest = src` when do we really have to *materialize* the full copy? - Only if `dest` or `src` are mutated -afterwards. If `dest` is a local variable that is simple to analyse. And if `src` is a +afterward. If `dest` is a local variable that is simple to analyze. And if `src` is a location derived from a formal parameter, we also know it is not mutated! In other words, we do a compile-time copy-on-write analysis. @@ -547,9 +547,9 @@ other words, a copy ``x = y`` is implemented as ``x[0] = y[0]; x[1] = y[1]; ...``, likewise for ``=sink`` and ``=destroy``. Other value-based compound types like ``object`` and ``array`` are handled -correspondingly. For ``object`` however, the compiler generated hooks +correspondingly. For ``object`` however, the compiler-generated hooks can be overridden. This can also be important to use an alternative traversal -of the involved datastructure that is more efficient or in order to avoid +of the involved data structure that is more efficient or in order to avoid deep recursions. diff --git a/doc/docgen.rst b/doc/docgen.rst index 636af6574..07218982c 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -14,7 +14,7 @@ Introduction This document describes the `documentation generation tools`:idx: built into the `Nim compiler `_, which can generate HTML and JSON output from input .nim files and projects, as well as HTML and LaTeX from input RST -(reStructuredText) files. The output documentation will include module +(reStructuredText) files. The output documentation will include the module dependencies (``import``), any top-level documentation comments (##), and exported symbols (*), including procedures, types, and variables. @@ -107,7 +107,7 @@ Document Types HTML ---- -Generation of HTML documents is done via the ``doc`` command. This command +The generation of HTML documents is done via the ``doc`` command. This command takes either a single .nim file, outputting a single .html file with the same base filename, or multiple .nim files, outputting multiple .html files and, optionally, an index file. @@ -121,15 +121,15 @@ Partial Output:: ... The full output can be seen here: `docgen_sample.html `_. -It runs after semantic checking, and includes pragmas attached implicitly by the +It runs after semantic checking and includes pragmas attached implicitly by the compiler. JSON ---- -Generation of JSON documents is done via the ``jsondoc`` command. This command -takes in a .nim file, and outputs a .json file with the same base filename. Note +The generation of JSON documents is done via the ``jsondoc`` command. This command +takes in a .nim file and outputs a .json file with the same base filename. Note that this tool is built off of the ``doc`` command (previously ``doc2``), and contains the same information. @@ -153,8 +153,8 @@ Output:: ] } -Similarly to the old ``doc`` command the old ``jsondoc`` command has been -renamed ``jsondoc0``. +Similarly to the old ``doc`` command, the old ``jsondoc`` command has been +renamed to ``jsondoc0``. The ``jsondoc0`` command:: nim jsondoc0 sample @@ -197,8 +197,8 @@ Index switch This will generate an index of all the exported symbols in the input Nim module, and put it into a neighboring file with the extension of ``.idx``. The -index file is line oriented (newlines have to be escaped). Each line -represents a tab separated record of several columns, the first two mandatory, +index file is line-oriented (newlines have to be escaped). Each line +represents a tab-separated record of several columns, the first two mandatory, the rest optional. See the `Index (idx) file format`_ section for details. Once index files have been generated for one or more modules, the Nim @@ -231,7 +231,7 @@ You can edit ``config/nimdoc.cfg`` and modify the ``doc.item.seesrc`` value with In the case of Nim's own documentation, the ``commit`` value is just a commit hash to append to a formatted URL to https://github.com/nim-lang/Nim. The -``tools/nimweb.nim`` helper queries the current git commit hash during doc +``tools/nimweb.nim`` helper queries the current git commit hash during the doc generation, but since you might be working on an unpublished repository, it also allows specifying a ``githash`` value in ``web/website.ini`` to force a specific commit in the output. @@ -260,8 +260,8 @@ HTML anchor generation ====================== When you run the ``rst2html`` command, all sections in the RST document will -get an anchor you can hyperlink to. Usually you can guess the anchor lower -casing the section title and replacing spaces with dashes, and in any case you +get an anchor you can hyperlink to. Usually, you can guess the anchor lower +casing the section title and replacing spaces with dashes, and in any case, you can get it from the table of contents. But when you run the ``doc`` or ``doc2`` commands to generate API documentation, some symbol get one or two anchors at the same time: a numerical identifier, or a plain name plus a complex name. @@ -274,20 +274,20 @@ numbers may shuffle around. The plain name of a symbol is a simplified version of its fully exported signature. Variables or constants have the same plain name symbol as their complex name. The plain name for procs, templates, and other callable types -will be their unquoted value after removing parameters, return types and -pragmas. The plain name allows short and nice linking of symbols which works +will be their unquoted value after removing parameters, return types, and +pragmas. The plain name allows short and nice linking of symbols that works unless you have a module with collisions due to overloading. If you hyperlink a plain name symbol and there are other matches on the same HTML file, most browsers will go to the first one. To differentiate the rest, you will need to use the complex name. A complex name for a callable type is -made up from several parts: +made up of several parts: (**plain symbol**)(**.type**),(**first param**)?(**,param type**)\* The first thing to note is that all callable types have at least a comma, even if they don't have any parameters. If there are parameters, they are -represented by their types and will be comma separated. To the plain symbol a +represented by their types and will be comma-separated. To the plain symbol a suffix may be added depending on the type of the callable: ------------- -------------- @@ -337,15 +337,15 @@ references so they can be later concatenated into a big index file with `mergeIndexes() `_. This section documents the file format in detail. -Index files are line oriented and tab separated (newline and tab characters -have to be escaped). Each line represents a record with at least two fields, +Index files are line-oriented and tab-separated (newline and tab characters +have to be escaped). Each line represents a record with at least two fields but can have up to four (additional columns are ignored). The content of these columns is: 1. Mandatory term being indexed. Terms can include quoting according to Nim's rules (e.g. \`^\`). 2. Base filename plus anchor hyperlink (e.g. ``algorithm.html#*,int,SortOrder``). -3. Optional human readable string to display as hyperlink. If the value is not +3. Optional human-readable string to display as a hyperlink. If the value is not present or is the empty string, the hyperlink will be rendered using the term. Prefix whitespace indicates that this entry is not for an API symbol but for a TOC entry. @@ -361,14 +361,14 @@ human reading. To differentiate both types (documents and APIs), the index generator will add to the index of documents an entry with the title of the document. Since the title is the topmost element, it will be added with a second field containing -just the filename without any HTML anchor. By convention this entry without +just the filename without any HTML anchor. By convention, this entry without anchor is the *title entry*, and since entries in the index file are added as they are scanned, the title entry will be the first line. The title for APIs is not present because it can be generated concatenating the name of the file to the word **Module**. Normal symbols are added to the index with surrounding whitespaces removed. An -exception to this are table of content (TOC) entries. TOC entries are added to +exception to this are the table of content (TOC) entries. TOC entries are added to the index file with their third column having as much prefix spaces as their level is in the TOC (at least 1 character). The prefix whitespace helps to filter TOC entries from API or text symbols. This is important because the @@ -379,14 +379,14 @@ final index, and TOC entries found in ``.nim`` files are discarded. Additional resources ==================== -`Nim Compiler User Guide `_ +`Nim Compiler User Guide `_ `RST Quick Reference `_ The output for HTML and LaTeX comes from the ``config/nimdoc.cfg`` and ``config/nimdoc.tex.cfg`` configuration files. You can add and modify these -files to your project to change the look of docgen output. +files to your project to change the look of the docgen output. You can import the `packages/docutils/rstgen module `_ in your programs if you want to reuse the compiler's documentation generation procs. diff --git a/doc/drnim.rst b/doc/drnim.rst index 5351daac9..ee6e0ea17 100644 --- a/doc/drnim.rst +++ b/doc/drnim.rst @@ -13,8 +13,8 @@ Introduction This document describes the usage of the *DrNim* tool. DrNim combines the Nim frontend with the `Z3 `_ proof -engine in order to allow verify / validate software written in Nim. -DrNim's command line options are the same as the Nim compiler's. +engine, in order to allow verify/validate software written in Nim. +DrNim's command-line options are the same as the Nim compiler's. DrNim currently only checks the sections of your code that are marked @@ -140,8 +140,8 @@ Example: insertionSort swap a[t], a[t-1] dec t -Unfortunately the invariants required to prove this code correct take more -code than the imperative instructions. However this effort can be compensated +Unfortunately, the invariants required to prove that this code is correct take more +code than the imperative instructions. However, this effort can be compensated by the fact that the result needs very little testing. Be aware though that DrNim only proves that after ``insertionSort`` this condition holds:: diff --git a/doc/hcr.rst b/doc/hcr.rst index 55ccc06dc..d2e13e1c7 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -14,11 +14,11 @@ preserved. Basic workflow ============== -Currently hot code reloading does not work for the main module itself, +Currently, hot code reloading does not work for the main module itself, so we have to use a helper module where the major logic we want to change during development resides. -In this example we use SDL2 to create a window and we reload the logic +In this example, we use SDL2 to create a window and we reload the logic code when ``F9`` is pressed. The important lines are marked with ``#***``. To install SDL2 you can use ``nimble install sdl2``. @@ -125,7 +125,7 @@ Then recompile the project, but do not restart or quit the mymain.exe program! nim c --hotcodereloading:on mymain.nim -Now give the ``mymain`` SDL window the focus, press F9 and watch the +Now give the ``mymain`` SDL window the focus, press F9, and watch the updated version of the program. diff --git a/doc/koch.rst b/doc/koch.rst index e984a71ea..01c690816 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -75,8 +75,8 @@ from rst to HTML. It also repeats the same operation but places the result in the ``web/upload`` which can be used to update the website at https://nim-lang.org. -By default the documentation will be built in parallel using the number of -available CPU cores. If any documentation build sub commands fail, they will +By default, the documentation will be built in parallel using the number of +available CPU cores. If any documentation build sub-commands fail, they will be rerun in serial fashion so that meaningful error output can be gathered for inspection. The ``--parallelBuild:n`` switch or configuration option can be used to force a specific number of parallel jobs or run everything serially diff --git a/doc/lib.rst b/doc/lib.rst index e05657b42..2dd43109e 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -7,7 +7,7 @@ Nim Standard Library .. contents:: -Nim's library is divided into *pure libraries*, *impure libraries* and *wrappers*. +Nim's library is divided into *pure libraries*, *impure libraries*, and *wrappers*. Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary while impure libraries do. A wrapper is an impure library that is a very @@ -32,7 +32,7 @@ Automatic imports * `system `_ Basic procs and operators that every program needs. It also provides IO facilities for reading and writing text and binary files. It is imported - implicitly by the compiler. Do not import it directly. It relies on compiler + implicitly by the compiler. Do not import it directly. It relies on compiler magic to work. * `threads `_ @@ -48,7 +48,7 @@ Core ---- * `bitops `_ - Provides a series of low level methods for bit manipulation. + Provides a series of low-level methods for bit manipulation. * `cpuinfo `_ This module implements procs to determine the number of CPUs / cores. @@ -69,7 +69,7 @@ Core Reentrant locks for Nim. * `typeinfo `_ - Provides (unsafe) access to Nim's run time type information. + Provides (unsafe) access to Nim's run-time type information. * `typetraits `_ This module defines compile-time reflection procs for working with types. @@ -83,7 +83,7 @@ Algorithms ---------- * `algorithm `_ - Implements some common generic algorithms like sort or binary search. + This module implements some common generic algorithms like sort or binary search. * `sequtils `_ This module implements operations for the built-in seq type @@ -96,7 +96,7 @@ Collections * `critbits `_ This module implements a *crit bit tree* which is an efficient - container for a sorted set of strings, or for a sorted mapping of strings. + container for a sorted set of strings, or a sorted mapping of strings. * `deques `_ Implementation of a double-ended queue. @@ -119,13 +119,13 @@ Collections Nim hash and bit set support. * `sharedlist `_ - Nim shared linked list support. Contains shared singly linked list. + Nim shared linked list support. Contains a shared singly-linked list. * `sharedtables `_ Nim shared hash table support. Contains shared tables. * `tables `_ - Nim hash table support. Contains tables, ordered tables and count tables. + Nim hash table support. Contains tables, ordered tables, and count tables. @@ -154,11 +154,11 @@ String handling * `ropes `_ This module contains support for a *rope* data type. - Ropes can represent very long strings efficiently; especially concatenation - is done in O(1) instead of O(n). + Ropes can represent very long strings efficiently; + especially concatenation is done in O(1) instead of O(n). * `strformat `_ - Macro based standard string interpolation / formatting. Inspired by + Macro based standard string interpolation/formatting. Inspired by Python's ``f``-strings. * `strmisc `_ @@ -207,7 +207,7 @@ Generic Operating System Services and the OS's native package manager. Its primary purpose is to produce output for Nimble packages, but it also contains the widely used **Distribution** enum - that is useful for writing platform specific code. + that is useful for writing platform-specific code. See `packaging `_ for hints on distributing Nim using OS packages. * `dynlib `_ @@ -218,7 +218,7 @@ Generic Operating System Services data structures. * `memfiles `_ - This module provides support for memory mapped files (Posix's ``mmap``) + This module provides support for memory-mapped files (Posix's ``mmap``) on the different operating systems. * `os `_ @@ -231,8 +231,8 @@ Generic Operating System Services * `streams `_ This module provides a stream interface and two implementations thereof: - the `FileStream` and the `StringStream` which implement the stream - interface for Nim file objects (`File`) and strings. Other modules + the `FileStream` and the `StringStream` which implement the stream + interface for Nim file objects (`File`) and strings. Other modules may provide other implementations for this standard stream interface. * `terminal `_ @@ -245,7 +245,7 @@ Math libraries -------------- * `complex `_ - This module implements complex numbers and their mathematical operations. + This module implements complex numbers and relevant mathematical operations. * `fenv `_ Floating-point environment. Handling of floating-point rounding and @@ -261,7 +261,7 @@ Math libraries Fast and tiny random number generator. * `rationals `_ - This module implements rational numbers and their mathematical operations. + This module implements rational numbers and relevant mathematical operations. * `stats `_ Statistical analysis @@ -317,10 +317,10 @@ Internet Protocols and Support * `selectors `_ This module implements a selector API with backends specific to each OS. - Currently epoll on Linux and select on other operating systems. + Currently, epoll on Linux and select on other operating systems. * `smtp `_ - This module implement a simple SMTP client. + This module implements a simple SMTP client. * `uri `_ This module provides functions for working with URIs. @@ -340,47 +340,46 @@ Parsers This module parses an HTML document and creates its XML tree representation. * `json `_ - High performance JSON parser. + High-performance JSON parser. * `lexbase `_ - This is a low level module that implements an extremely efficient buffering + This is a low-level module that implements an extremely efficient buffering scheme for lexers and parsers. This is used by the diverse parsing modules. * `parsecfg `_ - The ``parsecfg`` module implements a high performance configuration file + The ``parsecfg`` module implements a high-performance configuration file parser. The configuration file's syntax is similar to the Windows ``.ini`` format, but much more powerful, as it is not a line based parser. String - literals, raw string literals and triple quote string literals are supported + literals, raw string literals, and triple quote string literals are supported as in the Nim programming language. * `parsecsv `_ - The ``parsecsv`` module implements a simple high performance CSV parser. + The ``parsecsv`` module implements a simple high-performance CSV parser. * `parseopt `_ The ``parseopt`` module implements a command line option parser. * `parsesql `_ - The ``parsesql`` module implements a simple high performance SQL parser. + The ``parsesql`` module implements a simple high-performance SQL parser. * `parsexml `_ The ``parsexml`` module implements a simple high performance XML/HTML parser. The only encoding that is supported is UTF-8. The parser has been designed - to be somewhat error correcting, so that even some "wild HTML" found on the - Web can be parsed with it. + to be somewhat error-correcting, so that even some "wild HTML" found on the + web can be parsed with it. Docutils -------- * `packages/docutils/highlite `_ - Source highlighter for programming or markup languages. Currently - only few languages are supported, other languages may be added. + Source highlighter for programming or markup languages. Currently, + only a few languages are supported, other languages may be added. The interface supports one language nested in another. * `packages/docutils/rst `_ - This module implements a reStructuredText parser. A large subset - is implemented. Some features of the markdown wiki syntax are - also supported. + This module implements a reStructuredText parser. A large subset + is implemented. Some features of the markdown wiki syntax are also supported. * `packages/docutils/rstast `_ This module implements an AST for the reStructuredText parser. @@ -404,8 +403,8 @@ Generators ---------- * `htmlgen `_ - This module implements a simple XML and HTML code - generator. Each commonly used HTML tag has a corresponding macro + This module implements a simple XML and HTML code + generator. Each commonly used HTML tag has a corresponding macro that generates a string with its HTML representation. @@ -425,7 +424,7 @@ Hashing * `oids `_ An OID is a global ID that consists of a timestamp, - a unique counter and a random value. This combination should suffice to + a unique counter, and a random value. This combination should suffice to produce a globally distributed unique ID. This implementation was extracted from the Mongodb interface and it thus binary compatible with a Mongo OID. @@ -460,7 +459,7 @@ Miscellaneous Implements a Unit testing DSL. * `std/varints `_ - Decode variable length integers that are compatible with SQLite. + Decode variable-length integers that are compatible with SQLite. Modules for JS backend @@ -476,7 +475,7 @@ Modules for JS backend Wrapper for the ``console`` object. * `jscore `_ - Wrapper of core JavaScript functions. For most purposes you should be using + The wrapper of core JavaScript functions. For most purposes, you should be using the ``math``, ``json``, and ``times`` stdlib modules instead of this module. * `jsffi `_ @@ -490,7 +489,7 @@ Regular expressions ------------------- * `re `_ - This module contains procedures and operators for handling regular + This module contains procedures and operators for handling regular expressions. The current implementation uses PCRE. @@ -517,7 +516,7 @@ The generated HTML for some of these wrappers is so huge that it is not contained in the distribution. You can then find them on the website. -Windows specific +Windows-specific ---------------- * `winlean `_ @@ -545,7 +544,7 @@ GUI libraries ------------- * `iup `_ - Wrapper of the IUP GUI library. + The wrapper of the IUP GUI library. Database support diff --git a/doc/manual.rst b/doc/manual.rst index ca53999ac..d09bb4c76 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -8,8 +8,8 @@ Nim Manual .. contents:: - "Complexity" seems to be a lot like "energy": you can transfer it from the end - user to one/some of the other players, but the total amount seems to remain + "Complexity" seems to be a lot like "energy": you can transfer it from the + end-user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran @@ -22,7 +22,7 @@ precise wording. This manual is constantly evolving into a proper specification. **Note**: The experimental features of Nim are covered `here `_. -**Note**: Assignments, moves and destruction are specified in +**Note**: Assignments, moves, and destruction are specified in the `destructors `_ document. @@ -90,9 +90,9 @@ for example, be a native binary or JavaScript source code. In a typical Nim program, most of the code is compiled into the executable. However, some of the code may be executed at -`compile time`:idx:. This can include constant expressions, macro definitions, +`compile-time`:idx:. This can include constant expressions, macro definitions, and Nim procedures used by macro definitions. Most of the Nim language is -supported at compile time, but there are some restrictions -- see `Restrictions +supported at compile-time, but there are some restrictions -- see `Restrictions on Compile-Time Execution <#restrictions-on-compileminustime-execution>`_ for details. We use the term `runtime`:idx: to cover both compile-time execution and code execution in the executable. @@ -125,18 +125,18 @@ compiler may instead choose to allow the program to die with a fatal error. echo "invalid index" The current implementation allows to switch between these different behaviors -via ``--panics:on|off``. When panics are turned on, the program dies on a +via ``--panics:on|off``. When panics are turned on, the program dies with a panic, if they are turned off the runtime errors are turned into exceptions. The benefit of ``--panics:on`` is that it produces smaller binary code and the compiler has more freedom to optimize the code. An `unchecked runtime error`:idx: is an error that is not guaranteed to be -detected, and can cause the subsequent behavior of the computation to +detected and can cause the subsequent behavior of the computation to be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx: language features are used and if no runtime checks are disabled. A `constant expression`:idx: is an expression whose value can be computed during -semantic analysis of the code in which it appears. It is never an l-value and +a semantic analysis of the code in which it appears. It is never an l-value and never has side effects. Constant expressions are not limited to the capabilities of semantic analysis, such as constant folding; they can use all Nim language features that are supported for compile-time execution. Since constant @@ -163,7 +163,7 @@ encodings are not supported. Any of the standard platform line termination sequences can be used - the Unix form using ASCII LF (linefeed), the Windows form using the ASCII sequence CR LF (return followed by linefeed), or the old Macintosh form using the ASCII CR (return) character. All of these forms can be -used equally, regardless of platform. +used equally, regardless of the platform. Indentation @@ -180,7 +180,7 @@ lookahead. The parser uses a stack of indentation levels: the stack consists of integers counting the spaces. The indentation information is queried at strategic -places in the parser but ignored otherwise: The pseudo terminal ``IND{>}`` +places in the parser but ignored otherwise: The pseudo-terminal ``IND{>}`` denotes an indentation that consists of more spaces than the entry at the top of the stack; ``IND{=}`` an indentation that has the same number of spaces. ``DED`` is another pseudo terminal that describes the *action* of popping a value @@ -265,7 +265,7 @@ and underscores, with the following restrictions: digit ::= '0'..'9' IDENTIFIER ::= letter ( ['_'] (letter | digit) )* -Currently any Unicode character with an ordinal value > 127 (non ASCII) is +Currently, any Unicode character with an ordinal value > 127 (non-ASCII) is classified as a ``letter`` and may thus be part of an identifier but later versions of the language may assign some Unicode characters to belong to the operator characters instead. @@ -289,11 +289,11 @@ Two identifiers are considered equal if the following algorithm returns true: a[0] == b[0] and a.replace("_", "").toLowerAscii == b.replace("_", "").toLowerAscii -That means only the first letters are compared in a case sensitive manner. Other -letters are compared case insensitively within the ASCII range and underscores are ignored. +That means only the first letters are compared in a case-sensitive manner. Other +letters are compared case-insensitively within the ASCII range and underscores are ignored. This rather unorthodox way to do identifier comparisons is called -`partial case insensitivity`:idx: and has some advantages over the conventional +`partial case-insensitivity`:idx: and has some advantages over the conventional case sensitivity: It allows programmers to mostly use their own preferred @@ -455,7 +455,7 @@ literals: exactly two hex digits are allowed ================== =================================================== -A character is not an Unicode character but a single byte. The reason for this +A character is not a Unicode character but a single byte. The reason for this is efficiency: for the overwhelming majority of use-cases, the resulting programs will still handle UTF-8 properly as UTF-8 was specially designed for this. Another reason is that Nim can thus support ``array[char, int]`` or @@ -504,18 +504,18 @@ Numerical constants are of a single type and have the form:: As can be seen in the productions, numerical constants can contain underscores -for readability. Integer and floating point literals may be given in decimal (no -prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal +for readability. Integer and floating-point literals may be given in decimal (no +prefix), binary (prefix ``0b``), octal (prefix ``0o``), and hexadecimal (prefix ``0x``) notation. There exists a literal for each numerical type that is defined. The suffix starting with an apostrophe ('\'') is called a -`type suffix`:idx:. Literals without a type suffix are of an integer type, +`type suffix`:idx:. Literals without a type suffix are of an integer type unless the literal contains a dot or ``E|e`` in which case it is of type ``float``. This integer type is ``int`` if the literal is in the range ``low(i32)..high(i32)``, otherwise it is ``int64``. -For notational convenience the apostrophe of a type suffix -is optional if it is not ambiguous (only hexadecimal floating point literals +For notational convenience, the apostrophe of a type suffix +is optional if it is not ambiguous (only hexadecimal floating-point literals with a type suffix can be ambiguous). @@ -539,12 +539,12 @@ The type suffixes are: ``'f64`` float64 ================= ========================= -Floating point literals may also be in binary, octal or hexadecimal +Floating-point literals may also be in binary, octal or hexadecimal notation: ``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`` -is approximately 1.72826e35 according to the IEEE floating point standard. +is approximately 1.72826e35 according to the IEEE floating-point standard. -Literals are bounds checked so that they fit the datatype. Non base-10 +Literals are bounds checked so that they fit the datatype. Non-base-10 literals are used mainly for flags and bit pattern representations, therefore bounds checking is done on bit width, not value range. If the literal fits in the bit width of the datatype, it is accepted. @@ -626,7 +626,7 @@ operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. -For binary operators that are not keywords the precedence is determined by the +For binary operators that are not keywords, the precedence is determined by the following rules: Operators ending in either ``->``, ``~>`` or ``=>`` are called @@ -634,9 +634,9 @@ Operators ending in either ``->``, ``~>`` or ``=>`` are called If the operator ends with ``=`` and its first character is none of ``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which -has the second lowest precedence. +has the second-lowest precedence. -Otherwise precedence is determined by the first character. +Otherwise, precedence is determined by the first character. ================ ======================================================= ================== =============== Precedence level Operators First character Terminal symbol @@ -664,7 +664,7 @@ whitespace (this parsing change was introduced with version 0.13.0): echo($foo) -Spacing also determines whether ``(a, b)`` is parsed as an the argument list +Spacing also determines whether ``(a, b)`` is parsed as an argument list of a call or whether it is parsed as a tuple constructor: .. code-block:: nim @@ -798,7 +798,7 @@ block. The ability to access and modify compile-time variables adds flexibility to constant expressions that may be surprising to those coming from other statically typed languages. For example, the following code echoes the beginning -of the Fibonacci series **at compile time**. (This is a demonstration of +of the Fibonacci series **at compile-time**. (This is a demonstration of flexibility in defining constants, not a recommended style for solving this problem!) @@ -854,7 +854,7 @@ Some or all of these restrictions are likely to be lifted over time. Types ===== -All expressions have a type which is known during semantic analysis. Nim +All expressions have a type that is known during semantic analysis. Nim is statically typed. One can declare new types, which is in essence defining an identifier that can be used to denote this custom type. @@ -862,7 +862,7 @@ These are the major type classes: * ordinal types (consist of integer, bool, character, enumeration (and subranges thereof) types) -* floating point types +* floating-point types * string type * structured types * reference (pointer) type @@ -877,12 +877,12 @@ Ordinal types have the following characteristics: - Ordinal types are countable and ordered. This property allows the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to be defined. -- Ordinal values have a smallest possible value. Trying to count further +- Ordinal values have the smallest possible value. Trying to count further down than the smallest value produces a panic or a static error. -- Ordinal values have a largest possible value. Trying to count further +- Ordinal values have the largest possible value. Trying to count further than the largest value produces a panic or a static error. -Integers, bool, characters and enumeration types (and subranges of these +Integers, bool, characters, and enumeration types (and subranges of these types) belong to ordinal types. For reasons of simplicity of implementation the types ``uint`` and ``uint64`` are not ordinal types. (This will be changed in later versions of the language.) @@ -895,25 +895,23 @@ Pre-defined integer types These integer types are pre-defined: ``int`` - the generic signed integer type; its size is platform dependent and has the + the generic signed integer type; its size is platform-dependent and has the same size as a pointer. This type should be used in general. An integer literal that has no type suffix is of this type if it is in the range ``low(int32)..high(int32)`` otherwise the literal's type is ``int64``. intXX additional signed integer types of XX bits use this naming scheme - (example: int16 is a 16 bit wide integer). + (example: int16 is a 16-bit wide integer). The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``. Literals of these types have the suffix 'iXX. ``uint`` - the generic `unsigned integer`:idx: type; its size is platform dependent and - has the same size as a pointer. An integer literal with the type - suffix ``'u`` is of this type. + the generic `unsigned integer`:idx: type; its size is platform-dependent and has the same size as a pointer. An integer literal with the type suffix ``'u`` is of this type. uintXX additional unsigned integer types of XX bits use this naming scheme - (example: uint16 is a 16 bit wide unsigned integer). + (example: uint16 is a 16-bit wide unsigned integer). The current implementation supports ``uint8``, ``uint16``, ``uint32``, ``uint64``. Literals of these types have the suffix 'uXX. Unsigned operations all wrap around; they cannot lead to over- or @@ -977,7 +975,7 @@ For further details, see `Convertible relation Subrange types -------------- -A subrange type is a range of values from an ordinal or floating point type (the base +A subrange type is a range of values from an ordinal or floating-point type (the base type). To define a subrange type, one must specify its limiting values -- the lowest and highest value of the type. For example: @@ -988,8 +986,8 @@ lowest and highest value of the type. For example: ``Subrange`` is a subrange of an integer which can only hold the values 0 -to 5. ``PositiveFloat`` defines a subrange of all positive floating point values. -NaN does not belong to any subrange of floating point types. +to 5. ``PositiveFloat`` defines a subrange of all positive floating-point values. +NaN does not belong to any subrange of floating-point types. Assigning any other value to a variable of type ``Subrange`` is a panic (or a static error if it can be determined during semantic analysis). Assignments from the base type to one of its subrange types @@ -999,27 +997,27 @@ A subrange type has the same size as its base type (``int`` in the Subrange example). -Pre-defined floating point types +Pre-defined floating-point types -------------------------------- -The following floating point types are pre-defined: +The following floating-point types are pre-defined: ``float`` - the generic floating point type; its size used to be platform dependent, + the generic floating-point type; its size used to be platform-dependent, but now it is always mapped to ``float64``. This type should be used in general. floatXX - an implementation may define additional floating point types of XX bits using - this naming scheme (example: float64 is a 64 bit wide float). The current + an implementation may define additional floating-point types of XX bits using + this naming scheme (example: float64 is a 64-bit wide float). The current implementation supports ``float32`` and ``float64``. Literals of these types have the suffix 'fXX. Automatic type conversion in expressions with different kinds -of floating point types is performed: See `Convertible relation`_ for further -details. Arithmetic performed on floating point types follows the IEEE -standard. Integer types are not converted to floating point types automatically +of floating-point types is performed: See `Convertible relation`_ for further +details. Arithmetic performed on floating-point types follows the IEEE +standard. Integer types are not converted to floating-point types automatically and vice versa. The IEEE standard defines five types of floating-point exceptions: @@ -1059,7 +1057,7 @@ combination of ``nanChecks`` and ``infChecks`` pragmas. ``floatChecks`` are turned off as default. The only operations that are affected by the ``floatChecks`` pragma are -the ``+``, ``-``, ``*``, ``/`` operators for floating point types. +the ``+``, ``-``, ``*``, ``/`` operators for floating-point types. An implementation should always use the maximum precision available to evaluate floating pointer values during semantic analysis; this means expressions like @@ -1094,9 +1092,9 @@ The size of the bool type is one byte. Character type -------------- The character type is named ``char`` in Nim. Its size is one byte. -Thus it cannot represent an UTF-8 character, but a part of it. +Thus it cannot represent a UTF-8 character, but a part of it. The reason for this is efficiency: for the overwhelming majority of use-cases, -the resulting programs will still handle UTF-8 properly as UTF-8 was specially +the resulting programs will still handle UTF-8 properly as UTF-8 was especially designed for this. Another reason is that Nim can support ``array[char, int]`` or ``set[char]`` efficiently as many algorithms rely on this feature. The @@ -1144,7 +1142,7 @@ An explicit ordered enum can have *holes*: TokenType = enum a = 2, b = 4, c = 89 # holes are valid -However, it is then not an ordinal anymore, so it is not possible to use these +However, it is then not ordinal anymore, so it is not possible to use these enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ`` and ``pred`` are not available for them either. @@ -1166,8 +1164,8 @@ As can be seen from the example, it is possible to both specify a field's ordinal value and its string value by using a tuple. It is also possible to only specify one of them. -An enum can be marked with the ``pure`` pragma so that it's fields are -added to a special module specific hidden scope that is only queried +An enum can be marked with the ``pure`` pragma so that its fields are +added to a special module-specific hidden scope that is only queried as the last attempt. Only non-ambiguous symbols are added to this scope. But one can always access these via type qualification written as ``MyEnum.value``: @@ -1254,7 +1252,7 @@ cstring type The ``cstring`` type meaning `compatible string` is the native representation of a string for the compilation backend. For the C backend the ``cstring`` type represents a pointer to a zero-terminated char array -compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy +compatible with the type ``char*`` in Ansi C. Its primary purpose lies in easy interfacing with C. The index operation ``s[i]`` means the i-th *char* of ``s``; however no bounds checking for ``cstring`` is performed making the index operation unsafe. @@ -1271,7 +1269,7 @@ variadic proc, it is implicitly converted to ``cstring`` too: Even though the conversion is implicit, it is not *safe*: The garbage collector does not consider a ``cstring`` to be a root and may collect the underlying -memory. However in practice this almost never happens as the GC considers +memory. However, in practice, this almost never happens as the GC considers stack roots conservatively. One can use the builtin procs ``GC_ref`` and ``GC_unref`` to keep the string data alive for the rare cases where it does not work. @@ -1288,7 +1286,7 @@ Structured types ---------------- A variable of a structured type can hold multiple values at the same time. Structured types can be nested to unlimited levels. Arrays, sequences, -tuples, objects and sets belong to the structured types. +tuples, objects, and sets belong to the structured types. Array and sequence types ------------------------ @@ -1341,7 +1339,7 @@ The notation ``x[i]`` can be used to access the i-th element of ``x``. Arrays are always bounds checked (statically or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -``--boundChecks:off`` command line switch. +``--boundChecks:off`` command-line switch. An array constructor can have explicit indexes for readability: @@ -1456,7 +1454,7 @@ Unchecked arrays ---------------- The ``UncheckedArray[T]`` type is a special kind of ``array`` where its bounds are not checked. This is often useful to implement customized flexibly sized -arrays. Additionally an unchecked array is translated into a C array of +arrays. Additionally, an unchecked array is translated into a C array of undetermined size: .. code-block:: nim @@ -1526,7 +1524,7 @@ trailing comma: In fact, a trailing comma is allowed for every tuple construction. -The implementation aligns the fields for best access performance. The alignment +The implementation aligns the fields for the best access performance. The alignment is compatible with the way the C compiler does it. For consistency with ``object`` declarations, tuples in a ``type`` section @@ -1540,7 +1538,7 @@ can also be defined with indentation instead of ``[]``: Objects provide many features that tuples do not. Object provide inheritance and the ability to hide fields from other modules. Objects with inheritance enabled -have information about their type at runtime, so that the ``of`` operator can be +have information about their type at runtime so that the ``of`` operator can be used to determine the object's type. The ``of`` operator is similar to the ``instanceof`` operator in Java. @@ -1592,8 +1590,8 @@ For a ``ref object`` type ``system.new`` is invoked implicitly. Object variants --------------- -Often an object hierarchy is overkill in certain situations where simple variant -types are needed. Object variants are tagged unions discriminated via a +Often an object hierarchy is an overkill in certain situations where simple variant +types are needed. Object variants are tagged unions discriminated via an enumerated type used for runtime type flexibility, mirroring the concepts of *sum types* and *algebraic data types (ADTs)* as found in other languages. @@ -1638,14 +1636,14 @@ An example: # valid: does not change the active object branch: x.kind = nkSub -As can been seen from the example, an advantage to an object hierarchy is that +As can be seen from the example, an advantage to an object hierarchy is that no casting between different object types is needed. Yet, access to invalid object fields raises an exception. The syntax of ``case`` in an object declaration follows closely the syntax of the ``case`` statement: The branches in a ``case`` section may be indented too. -In the example the ``kind`` field is called the `discriminator`:idx:\: For +In the example, the ``kind`` field is called the `discriminator`:idx:\: For safety its address cannot be taken and assignments to it are restricted: The new value must not lead to a change of the active object branch. Also, when the fields of a particular branch are specified during object construction, the @@ -1708,16 +1706,16 @@ point to and modify the same location in memory (also called `aliasing`:idx:). Nim distinguishes between `traced`:idx: and `untraced`:idx: references. Untraced references are also called *pointers*. Traced references point to -objects of a garbage collected heap, untraced references point to -manually allocated objects or to objects somewhere else in memory. Thus -untraced references are *unsafe*. However for certain low-level operations +objects of a garbage-collected heap, untraced references point to +manually allocated objects or objects somewhere else in memory. Thus +untraced references are *unsafe*. However, for certain low-level operations (accessing the hardware) untraced references are unavoidable. Traced references are declared with the **ref** keyword, untraced references are declared with the **ptr** keyword. In general, a `ptr T` is implicitly convertible to the `pointer` type. -An empty subscript ``[]`` notation can be used to derefer a reference, +An empty subscript ``[]`` notation can be used to de-refer a reference, the ``addr`` procedure returns the address of an item. An address is always an untraced reference. Thus the usage of ``addr`` is an *unsafe* feature. @@ -1807,7 +1805,7 @@ Mixing GC'ed memory with ``ptr`` -------------------------------- Special care has to be taken if an untraced object contains traced objects like -traced references, strings or sequences: in order to free everything properly, +traced references, strings, or sequences: in order to free everything properly, the built-in procedure ``reset`` has to be called before freeing the untraced memory manually: @@ -1828,8 +1826,7 @@ memory manually: dealloc(d) Without the ``reset`` call the memory allocated for the ``d.s`` string would -never be freed. The example also demonstrates two important features for low -level programming: the ``sizeof`` proc returns the size of a type or value +never be freed. The example also demonstrates two important features for low-level programming: the ``sizeof`` proc returns the size of a type or value in bytes. The ``cast`` operator can circumvent the type system: the compiler is forced to treat the result of the ``alloc0`` call (which returns an untyped pointer) as if it would have the type ``ptr Data``. Casting should only be @@ -1838,8 +1835,8 @@ mysterious crashes. **Note**: The example only works because the memory is initialized to zero (``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to -binary zero which the string assignment can handle. One needs to know low level -details like this when mixing garbage collected data with unmanaged memory. +binary zero which the string assignment can handle. One needs to know low-level +details like this when mixing garbage-collected data with unmanaged memory. .. XXX finalizers for traced objects @@ -1948,7 +1945,7 @@ accesses its environment. If it does so, it has the calling convention Distinct type ------------- -A ``distinct`` type is new type derived from a `base type`:idx: that is +A ``distinct`` type is a new type derived from a `base type`:idx: that is incompatible with its base type. In particular, it is an essential property of a distinct type that it **does not** imply a subtype relation between it and its base type. Explicit type conversions from a distinct type to its @@ -1958,7 +1955,7 @@ reverse operation. A distinct type is an ordinal type if its base type is an ordinal type. -Modelling currencies +Modeling currencies ~~~~~~~~~~~~~~~~~~~~ A distinct type can be used to model different physical `units`:idx: with a @@ -2002,7 +1999,7 @@ number without unit; and the same holds for division: This quickly gets tedious. The implementations are trivial and the compiler should not generate all this code only to optimize it away later - after all ``+`` for dollars should produce the same binary code as ``+`` for ints. -The pragma `borrow`:idx: has been designed to solve this problem; in principle +The pragma `borrow`:idx: has been designed to solve this problem; in principle, it generates the above trivial implementations: .. code-block:: nim @@ -2067,14 +2064,14 @@ certain builtin operations to be lifted: bb.a = 90 bb.s = "abc" -Currently only the dot accessor can be borrowed in this way. +Currently, only the dot accessor can be borrowed in this way. Avoiding SQL injection attacks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An SQL statement that is passed from Nim to an SQL database might be -modelled as a string. However, using string templates and filling in the +modeled as a string. However, using string templates and filling in the values is vulnerable to the famous `SQL injection attack`:idx:\: .. code-block:: nim @@ -2152,7 +2149,7 @@ Is the same as: .. code-block:: nim proc foo[T1, T2](a: T1, b: T2) = discard -However later versions of the language might change this to mean "infer the +However, later versions of the language might change this to mean "infer the parameters' types from the body". Then the above ``foo`` would be rejected as the parameters' types can not be inferred from an empty ``discard`` statement. @@ -2375,8 +2372,8 @@ of the argument. 1. Exact match: ``a`` and ``f`` are of the same type. 2. Literal match: ``a`` is an integer literal of value ``v`` and ``f`` is a signed or unsigned integer type and ``v`` is in ``f``'s - range. Or: ``a`` is a floating point literal of value ``v`` - and ``f`` is a floating point type and ``v`` is in ``f``'s + range. Or: ``a`` is a floating-point literal of value ``v`` + and ``f`` is a floating-point type and ``v`` is in ``f``'s range. 3. Generic match: ``f`` is a generic type and ``a`` matches, for instance ``a`` is ``int`` and ``f`` is a generic (constrained) parameter @@ -2384,7 +2381,7 @@ of the argument. 4. Subrange or subtype match: ``a`` is a ``range[T]`` and ``T`` matches ``f`` exactly. Or: ``a`` is a subtype of ``f``. 5. Integral conversion match: ``a`` is convertible to ``f`` and ``f`` and ``a`` - is some integer or floating point type. + is some integer or floating-point type. 6. Conversion match: ``a`` is convertible to ``f``, possibly via a user defined ``converter``. @@ -2507,7 +2504,7 @@ Lazy type resolution for untyped lookups and no type checking have been performed. Since templates and macros that are not declared as ``immediate`` participate -in overloading resolution it's essential to have a way to pass unresolved +in overloading resolution, it's essential to have a way to pass unresolved expressions to a template or macro. This is what the meta-type ``untyped`` accomplishes: @@ -2549,7 +2546,7 @@ statements. Statements are separated into `simple statements`:idx: and `complex statements`:idx:. Simple statements are statements that cannot contain other statements like -assignments, calls or the ``return`` statement; complex statements can +assignments, calls, or the ``return`` statement; complex statements can contain other statements. To avoid the `dangling else problem`:idx:, complex statements always have to be indented. The details can be found in the grammar. @@ -2559,7 +2556,7 @@ Statement list expression Statements can also occur in an expression context that looks like ``(stmt1; stmt2; ...; ex)``. This is called -an statement list expression or ``(;)``. The type +a statement list expression or ``(;)``. The type of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.) ``(;)`` does not introduce a new scope. @@ -2635,7 +2632,7 @@ Var statement ------------- Var statements declare new local and global variables and -initialize them. A comma separated list of variables can be used to specify +initialize them. A comma-separated list of variables can be used to specify variables of the same type: .. code-block:: nim @@ -2684,7 +2681,7 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit The implicit initialization can be also prevented by the `requiresInit`:idx: type pragma. The compiler requires an explicit initialization for the object -and all of its fields. However it does a `control flow analysis`:idx: to prove +and all of its fields. However, it does a `control flow analysis`:idx: to prove the variable has been initialized and does not rely on syntactic properties: .. code-block:: nim @@ -2710,7 +2707,7 @@ statement, except that the keyword ``var`` is replaced by the keyword ``let``. Let variables are not l-values and can thus not be passed to ``var`` parameters nor can their address be taken. They cannot be assigned new values. -For let variables the same pragmas are available as for ordinary variables. +For let variables, the same pragmas are available as for ordinary variables. As ``let`` statements are immutable after creation they need to define a value when they are declared. The only exception to this is if the ``{.importc.}`` @@ -2837,7 +2834,7 @@ ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s type. To suppress the static error an ``else`` part with an empty ``discard`` statement should be used. -For non ordinal types it is not possible to list every possible value and so +For non-ordinal types, it is not possible to list every possible value and so these always require an ``else`` part. Because case statements are checked for exhaustiveness during semantic analysis, @@ -2928,8 +2925,8 @@ within ``object`` definitions. When nimvm statement -------------------- -``nimvm`` is a special symbol, that may be used as expression of ``when nimvm`` -statement to differentiate execution path between compile time and the +``nimvm`` is a special symbol, that may be used as an expression of ``when nimvm`` +statement to differentiate execution path between compile-time and the executable. Example: @@ -2995,7 +2992,7 @@ Example: The ``yield`` statement is used instead of the ``return`` statement in iterators. It is only valid in iterators. Execution is returned to the body of the for loop that called the iterator. Yield does not end the iteration -process, but execution is passed back to the iterator if the next iteration +process, but the execution is passed back to the iterator if the next iteration starts. See the section about iterators (`Iterators and the for statement`_) for further information. @@ -3155,7 +3152,7 @@ name ``c`` should default to type ``Context``, ``n`` should default to The ``using`` section uses the same indentation based grouping syntax as a ``var`` or ``let`` section. -Note that ``using`` is not applied for ``template`` since untyped template +Note that ``using`` is not applied for ``template`` since the untyped template parameters default to the type ``system.untyped``. Mixing parameters that should use the ``using`` declaration with parameters @@ -3202,9 +3199,9 @@ Block expression ---------------- A `block expression` is almost like a block statement, but it is an expression -that uses last expression under the block as the value. +that uses the last expression under the block as the value. It is similar to the statement list expression, but the statement list expression -does not open new block scope. +does not open a new block scope. .. code-block:: nim let a = block: @@ -3236,7 +3233,7 @@ has lots of advantages: can easily put it into the executable's data section just like it can for arrays and the generated data section requires a minimal amount of memory. -* Every table implementation is treated equal syntactically. +* Every table implementation is treated equally syntactically. * Apart from the minimal syntactic sugar the language core does not need to know about tables. @@ -3251,9 +3248,9 @@ results in an exception (if it cannot be determined statically). Ordinary procs are often preferred over type conversions in Nim: For instance, ``$`` is the ``toString`` operator by convention and ``toFloat`` and ``toInt`` -can be used to convert from floating point to integer or vice versa. +can be used to convert from floating-point to integer or vice versa. -A type conversion can also be used to disambiguate overloaded routines: +Type conversion can also be used to disambiguate overloaded routines: .. code-block:: nim @@ -3347,7 +3344,7 @@ declaration consists of an identifier, zero or more formal parameters, a return value type and a block of code. Formal parameters are declared as a list of identifiers separated by either comma or semicolon. A parameter is given a type by ``: typename``. The type applies to all parameters immediately before it, -until either the beginning of the parameter list, a semicolon separator or an +until either the beginning of the parameter list, a semicolon separator, or an already typed parameter, is reached. The semicolon can be used to make separation of types and subsequent identifiers more distinct. @@ -3460,7 +3457,7 @@ current module: Method call syntax ------------------ -For object oriented programming, the syntax ``obj.method(args)`` can be used +For object-oriented programming, the syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``. The parentheses can be omitted if there are no remaining arguments: ``obj.len`` (instead of ``len(obj)``). @@ -3494,7 +3491,7 @@ Properties ---------- Nim has no need for *get-properties*: Ordinary get-procedures that are called with the *method call syntax* achieve the same. But setting a value is -different; for this a special setter syntax is needed: +different; for this, a special setter syntax is needed: .. code-block:: nim # Module asocket @@ -3566,8 +3563,8 @@ more argument in this case: The command invocation syntax also can't have complex expressions as arguments. For example: (`anonymous procs <#procedures-anonymous-procs>`_), ``if``, -``case`` or ``try``. Function calls with no arguments still needs () to -distinguish between a call and the function itself as a first class value. +``case`` or ``try``. Function calls with no arguments still need () to +distinguish between a call and the function itself as a first-class value. Closures @@ -3603,7 +3600,7 @@ procedures: cmp(x.len, y.len)) -Procs as expressions can appear both as nested procs and inside top level +Procs as expressions can appear both as nested procs and inside top-level executable code. The `sugar `_ module contains the `=>` macro which enables a more succinct syntax for anonymous procedures resembling lambdas as they are in languages like JavaScript, C#, etc. @@ -3627,7 +3624,7 @@ Is short for: Nonoverloadable builtins ------------------------ -The following builtin procs cannot be overloaded for reasons of implementation +The following built-in procs cannot be overloaded for reasons of implementation simplicity (they require specialized semantic checking):: declared, defined, definedInScope, compiles, sizeof, @@ -3636,7 +3633,7 @@ simplicity (they require specialized semantic checking):: Thus they act more like keywords than like ordinary identifiers; unlike a keyword however, a redefinition may `shadow`:idx: the definition in the ``system`` module. From this list the following should not be written in dot -notation ``x.f`` since ``x`` cannot be type checked before it gets passed +notation ``x.f`` since ``x`` cannot be type-checked before it gets passed to ``f``:: declared, defined, definedInScope, compiles, getAst, astToStr @@ -3703,7 +3700,7 @@ free to pass arguments by reference if it considers it can speed up execution. Var return type --------------- -A proc, converter or iterator may return a ``var`` type which means that the +A proc, converter, or iterator may return a ``var`` type which means that the returned value is an l-value and can be modified by the caller: .. code-block:: nim @@ -3994,7 +3991,7 @@ the rewriting step, so that all overloads of ``items``/``pairs`` are taken into account. -First class iterators +First-class iterators --------------------- There are 2 kinds of iterators in Nim: *inline* and *closure* iterators. @@ -4009,7 +4006,7 @@ to avoid code bloat. 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. +templates, macros, and other inline iterators. In contrast to that, a `closure iterator`:idx: can be passed around more freely: @@ -4284,7 +4281,7 @@ above, ``IOError``), one must convert it explicitly: # "e" is now of the proper type However, this is seldom needed. The most common case is to extract an -error message from ``e``, and for such situations it is enough to use +error message from ``e``, and for such situations, it is enough to use ``getCurrentExceptionMsg``: .. code-block:: nim @@ -4339,7 +4336,7 @@ Is rewritten to: finally: close(f) -Top level ``defer`` statements are not supported +Top-level ``defer`` statements are not supported since it's unclear what such a statement should refer to. @@ -4474,9 +4471,7 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph: 1. Every indirect call via some proc type ``T`` is assumed to raise ``system.Exception`` (the base type of the exception hierarchy) and thus any exception unless ``T`` has an explicit ``raises`` list. - However if the call is of the form ``f(...)`` where ``f`` is a parameter - of the currently analysed routine it is ignored. The call is optimistically - assumed to have no effect. Rule 2 compensates for this case. + However, if the call is of the form ``f(...)`` where ``f`` is a parameter of the currently analyzed routine it is ignored. The call is optimistically assumed to have no effect. Rule 2 compensates for this case. 2. Every expression of some proc type within a call that is not a call itself (and not nil) is assumed to be called indirectly somehow and thus its raises list is added to ``p``'s raises list. @@ -4579,10 +4574,10 @@ Generics ======== Generics are Nim's means to parametrize procs, iterators or types with -`type parameters`:idx:. Depending on context, the brackets are used either to -introduce type parameters or to instantiate a generic proc, iterator or type. +`type parameters`:idx:. Depending on the context, the brackets are used either to +introduce type parameters or to instantiate a generic proc, iterator, or type. -The following example shows a generic binary tree can be modelled: +The following example shows a generic binary tree can be modeled: .. code-block:: nim :test: "nim c $1" @@ -4705,7 +4700,7 @@ more complex type classes: Whilst the syntax of type classes appears to resemble that of ADTs/algebraic data types in ML-like languages, it should be understood that type classes are static constraints to be enforced at type instantiations. Type classes are not really -types in themselves, but are instead a system of providing generic "checks" that +types in themselves but are instead a system of providing generic "checks" that ultimately *resolve* to some singular type. Type classes do not allow for runtime type dynamism, unlike object variants or methods. @@ -4742,11 +4737,11 @@ A type class can be used directly as the parameter's type. echo key, " = ", value -Procedures utilizing type classes in such manner are considered to be +Procedures utilizing type classes in such a manner are considered to be `implicitly generic`:idx:. They will be instantiated once for each unique combination of param types used within the program. -By default, during overload resolution each named type class will bind to +By default, during overload resolution, each named type class will bind to exactly one concrete type. We call such type classes `bind once`:idx: types. Here is an example taken directly from the system module to illustrate this: @@ -4899,7 +4894,7 @@ at definition and the context at instantiation are considered: echo a == b # works! -In the example the generic ``==`` for tuples (as defined in the system module) +In the example, the generic ``==`` for tuples (as defined in the system module) uses the ``==`` operators of the tuple's components. However, the ``==`` for the ``Index`` type is defined *after* the ``==`` for tuples; yet the example compiles as the instantiation takes the currently defined symbols into account @@ -5008,7 +5003,7 @@ example *undeclared* identifiers can be passed to the template: template declareInt(x: typed) = var x: int - declareInt(x) # invalid, because x has not been declared and so has no type + declareInt(x) # invalid, because x has not been declared and so it has no type A template where every parameter is ``untyped`` is called an `immediate`:idx: template. For historical reasons templates can be explicitly annotated with @@ -5344,7 +5339,7 @@ A macro is a special function that is executed at compile time. Normally the input for a macro is an abstract syntax tree (AST) of the code that is passed to it. The macro can then do transformations on it and return the transformed AST. This can be used to -add custom language features and implement `domain specific languages`:idx:. +add custom language features and implement `domain-specific languages`:idx:. Macro invocation is a case where semantic analysis does **not** entirely proceed top to bottom and left to right. Instead, semantic analysis happens at least @@ -5608,11 +5603,11 @@ possible type mismatch error. typedesc[T] ----------- -In many contexts, Nim allows to treat the names of types as regular -values. These values exists only during the compilation phase, but since +In many contexts, Nim treats the names of types as regular +values. These values exist only during the compilation phase, but since all values must have a type, ``typedesc`` is considered their special type. -``typedesc`` acts like a generic type. For instance, the type of the symbol +``typedesc`` acts as a generic type. For instance, the type of the symbol ``int`` is ``typedesc[int]``. Just like with regular generic types, when the generic param is omitted, ``typedesc`` denotes the type class of all types. As a syntactic convenience, one can also use ``typedesc`` as a modifier. @@ -5649,7 +5644,7 @@ Once bound, type params can appear in the rest of the proc signature: Overload resolution can be further influenced by constraining the set -of types that will match the type param. This works in practice to +of types that will match the type param. This works in practice by attaching attributes to types via templates. The constraint can be a concrete type or a type class. @@ -5705,7 +5700,7 @@ operator): If ``typeof`` is used to determine the result type of a proc/iterator/converter call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the -interpretation where ``c`` is an iterator is preferred over the +interpretation, where ``c`` is an iterator, is preferred over the other interpretations, but this behavior can be changed by passing ``typeOfProc`` as the second argument to ``typeof``: @@ -5783,7 +5778,7 @@ imported: It is not checked that the ``except`` list is really exported from the module. -This feature allows to compile against an older version of the module that +This feature allows us to compile against an older version of the module that does not export these identifiers. The ``import`` statement is only allowed at the top level. @@ -5836,7 +5831,7 @@ and so one **cannot** do: import lib/pure/strutils echo lib/pure/strutils.toUpperAscii("abc") -Likewise the following does not make sense as the name is ``strutils`` already: +Likewise, the following does not make sense as the name is ``strutils`` already: .. code-block:: nim import lib/pure/strutils as strutils @@ -5858,7 +5853,7 @@ name is not a valid Nim identifier it needs to be a string literal: Pseudo import/include paths ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A directory can also be a so called "pseudo directory". They can be used to +A directory can also be a so-called "pseudo directory". They can be used to avoid ambiguity when there are multiple modules with the same path. There are two pseudo directories: @@ -5875,7 +5870,7 @@ library locations*. In other words, it is the opposite of ``std``. From import statement ~~~~~~~~~~~~~~~~~~~~~ -After the ``from`` statement a module name follows followed by +After the ``from`` statement, a module name follows followed by an ``import`` to list the symbols one likes to use without explicit full qualification: @@ -5964,7 +5959,7 @@ the end of the module. Identifiers from indirectly dependent modules are *not* available. The `system`:idx: module is automatically imported in every module. If a module imports an identifier by two different modules, each occurrence of -the identifier has to be qualified, unless it is an overloaded procedure or +the identifier has to be qualified unless it is an overloaded procedure or iterator in which case the overloading resolution takes place: .. code-block:: nim @@ -6121,7 +6116,7 @@ Or if we directly use a ref object: left, right: Node data: string -In the example a tree structure is declared with the ``Node`` type. Note that +In the example, a tree structure is declared with the ``Node`` type. Note that the type definition is recursive and the GC has to assume that objects of this type may form a cyclic graph. The ``acyclic`` pragma passes the information that this cannot happen to the GC. If the programmer uses the @@ -6182,7 +6177,7 @@ assembler statements. error pragma ------------ The ``error`` pragma is used to make the compiler output an error message -with the given content. Compilation does not necessarily abort after an error +with the given content. The compilation does not necessarily abort after an error though. The ``error`` pragma can also be used to @@ -6198,7 +6193,7 @@ operation is valid due to overloading and type conversions: fatal pragma ------------ The ``fatal`` pragma is used to make the compiler output an error message -with the given content. In contrast to the ``error`` pragma, compilation +with the given content. In contrast to the ``error`` pragma, the compilation is guaranteed to be aborted by this pragma. Example: .. code-block:: nim @@ -6218,7 +6213,7 @@ the given content. Compilation continues after the hint. line pragma ----------- The ``line`` pragma can be used to affect line information of the annotated -statement as seen in stack backtraces: +statement, as seen in stack backtraces: .. code-block:: nim @@ -6251,9 +6246,9 @@ statement: In the example, the case branches ``0`` and ``1`` are much more common than the other cases. Therefore the generated assembler code should test for these -values first, so that the CPU's branch predictor has a good chance to succeed +values first so that the CPU's branch predictor has a good chance to succeed (avoiding an expensive CPU pipeline stall). The other cases might be put into a -jump table for O(1) overhead, but at the cost of a (very likely) pipeline +jump table for O(1) overhead but at the cost of a (very likely) pipeline stall. The ``linearScanEnd`` pragma should be put into the last branch that should be @@ -6383,7 +6378,7 @@ but are used to override the settings temporarily. Example: proc sample(): bool = true {.pop.} -For third party pragmas it depends on its implementation, but uses the same syntax. +For third party pragmas, it depends on its implementation but uses the same syntax. register pragma @@ -6445,7 +6440,7 @@ is particularly useful when the symbol was generated by a macro: implementArithOps(int) echoAdd 3, 5 -``used`` can also be used as a top level statement to mark a module as "used". +``used`` can also be used as a top-level statement to mark a module as "used". This prevents the "Unused import" warning: .. code-block:: nim @@ -6462,9 +6457,9 @@ experimental pragma ------------------- The ``experimental`` pragma enables experimental language features. Depending -on the concrete feature this means that the feature is either considered +on the concrete feature, this means that the feature is either considered too unstable for an otherwise stable release or that the future of the feature -is uncertain (it may be removed any time). +is uncertain (it may be removed at any time). Example: @@ -6483,9 +6478,9 @@ Example: useParallel() -As a top level statement, the experimental pragma enables a feature for the +As a top-level statement, the experimental pragma enables a feature for the rest of the module it's enabled in. This is problematic for macro and generic -instantiations that cross a module scope. Currently these usages have to be +instantiations that cross a module scope. Currently, these usages have to be put into a ``.push/pop`` environment: .. code-block:: nim @@ -6539,7 +6534,7 @@ The `align`:idx: pragma is for variables and object field members. It modifies the alignment requirement of the entity being declared. The argument must be a constant power of 2. Valid non-zero alignments that are weaker than other align pragmas on the same -declaration are ignored. Alignments that are weaker that the +declaration are ignored. Alignments that are weaker than the alignment requirement of the type are ignored. .. code-block:: Nim @@ -6562,7 +6557,7 @@ alignment requirement of the type are ignored. main() -This pragma has no effect for the JS backend. +This pragma has no effect on the JS backend. Volatile pragma @@ -6595,7 +6590,7 @@ Header pragma ------------- The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be applied to almost any symbol and specifies that it should not be declared -and instead the generated code should contain an ``#include``: +and instead, the generated code should contain an ``#include``: .. code-block:: Nim type @@ -6630,7 +6625,7 @@ with the project: {.compile: "myfile.cpp".} **Note**: Nim computes a SHA1 checksum and only recompiles the file if it -has changed. One can use the ``-f`` command line option to force recompilation +has changed. One can use the ``-f`` command-line option to force the recompilation of the file. Since 1.4 the `compile` pragma is also available with this syntax: @@ -6653,7 +6648,7 @@ The ``link`` pragma can be used to link an additional file with the project: PassC pragma ------------ The ``passc`` pragma can be used to pass additional parameters to the C -compiler like one would using the commandline switch ``--passc``: +compiler like one would using the command-line switch ``--passc``: .. code-block:: Nim {.passc: "-Wall -Werror".} @@ -6681,7 +6676,7 @@ the pragma resides in: PassL pragma ------------ The ``passL`` pragma can be used to pass additional parameters to the linker -like one would using the commandline switch ``--passL``: +like one would be using the command-line switch ``--passL``: .. code-block:: Nim {.passL: "-lSDLmain -lSDL".} @@ -6728,7 +6723,7 @@ Example: void fun(){} """.} -For backwards compatibility, if the argument to the ``emit`` statement +For backward compatibility, if the argument to the ``emit`` statement is a single string literal, Nim symbols can be referred to via backticks. This usage is however deprecated. @@ -6828,8 +6823,7 @@ language for maximum flexibility: - A hash ``#`` symbol is replaced by the first or next argument. - A dot following the hash ``#.`` indicates that the call should use C++'s dot or arrow notation. -- An at symbol ``@`` is replaced by the remaining arguments, separated by - commas. +- An at symbol ``@`` is replaced by the remaining arguments, separated by commas. For example: @@ -6843,7 +6837,7 @@ Produces: .. code-block:: C x->CppMethod(1, 2, 3) -As a special rule to keep backwards compatibility with older versions of the +As a special rule to keep backward compatibility with older versions of the ``importcpp`` pragma, if there is no special pattern character (any of ``# ' @``) at all, C++'s dot or arrow notation is assumed, so the above example can also be written as: @@ -6862,7 +6856,7 @@ capabilities: - An apostrophe ``'`` followed by an integer ``i`` in the range 0..9 is replaced by the i'th parameter *type*. The 0th position is the result type. This can be used to pass types to C++ function templates. Between - the ``'`` and the digit an asterisk can be used to get to the base type + the ``'`` and the digit, an asterisk can be used to get to the base type of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.) Two stars can be used to get to the element type of the element type etc. @@ -6929,7 +6923,7 @@ Wrapping destructors Since Nim generates C++ directly, any destructor is called implicitly by the C++ compiler at the scope exits. This means that often one can get away with -not wrapping the destructor at all! However when it needs to be invoked +not wrapping the destructor at all! However, when it needs to be invoked explicitly, it needs to be wrapped. The pattern language provides everything that is required: @@ -7046,7 +7040,7 @@ The ``codegenDecl`` pragma can be used to directly influence Nim's code generator. It receives a format string that determines how the variable or proc is declared in the generated code. -For variables $1 in the format string represents the type of the variable +For variables, $1 in the format string represents the type of the variable and $2 is the name of the variable. The following Nim code: @@ -7087,7 +7081,7 @@ debugging: # ... complex code here that produces crashes ... -compile time define pragmas +compile-time define pragmas --------------------------- The pragmas listed here can be used to optionally accept values from @@ -7112,7 +7106,7 @@ pragma description nim c -d:FooBar=42 foobar.nim In the above example, providing the -d flag causes the symbol -``FooBar`` to be overwritten at compile time, printing out 42. If the +``FooBar`` to be overwritten at compile-time, printing out 42. If the ``-d:FooBar=42`` were to be omitted, the default value of 5 would be used. To see if a value was provided, `defined(FooBar)` can be used. @@ -7125,9 +7119,8 @@ User-defined pragmas pragma pragma ------------- -The ``pragma`` pragma can be used to declare user defined pragmas. This is -useful because Nim's templates and macros do not affect pragmas. User -defined pragmas are in a different module-wide scope than all other symbols. +The ``pragma`` pragma can be used to declare user-defined pragmas. This is +useful because Nim's templates and macros do not affect pragmas. User-defined pragmas are in a different module-wide scope than all other symbols. They cannot be imported from a module. Example: @@ -7141,14 +7134,14 @@ Example: proc p*(a, b: int): int {.rtl.} = result = a+b -In the example a new pragma named ``rtl`` is introduced that either imports +In the example, a new pragma named ``rtl`` is introduced that either imports a symbol from a dynamic library or exports the symbol for dynamic library generation. Custom annotations ------------------ -It is possible to define custom typed pragmas. Custom pragmas do not effect +It is possible to define custom typed pragmas. Custom pragmas do not affect code generation directly, but their presence can be detected by macros. Custom pragmas are defined using templates annotated with pragma ``pragma``: @@ -7178,7 +7171,7 @@ Consider stylized example of possible Object Relation Mapping (ORM) implementati write_access: bool admin_acess: bool -In this example custom pragmas are used to describe how Nim objects are +In this example, custom pragmas are used to describe how Nim objects are mapped to the schema of the relational database. Custom pragmas can have zero or more arguments. In order to pass multiple arguments use one of template call syntaxes. All arguments are typed and follow standard @@ -7216,7 +7209,7 @@ Macro pragmas ------------- All macros and templates can also be used as pragmas. They can be attached -to routines (procs, iterators, etc), type names or type expressions. The +to routines (procs, iterators, etc), type names, or type expressions. The compiler will perform the following simple syntactic transformations: .. code-block:: nim @@ -7299,7 +7292,7 @@ is not set to C, other pragmas are available: .. code-block:: Nim proc p(s: cstring) {.importc: "prefix$1".} -In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` +In the example, the external name of ``p`` is set to ``prefixp``. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. @@ -7339,7 +7332,7 @@ mangling. The string literal passed to ``extern`` can be a format string: proc p(s: string) {.extern: "prefix$1".} = echo s -In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` +In the example, the external name of ``p`` is set to ``prefixp``. Only ``$1`` is available and a literal dollar sign must be written as ``$$``. @@ -7430,7 +7423,7 @@ At runtime the dynamic library is searched for (in this order):: libtcl8.3.so.1 libtcl8.3.so.0 -The ``dynlib`` pragma supports not only constant strings as argument but also +The ``dynlib`` pragma supports not only constant strings as an argument but also string expressions in general: .. code-block:: nim @@ -7452,7 +7445,7 @@ strings, because they are precompiled. because of order of initialization problems. **Note**: A ``dynlib`` import can be overridden with -the ``--dynlibOverride:name`` command line option. The Compiler User Guide +the ``--dynlibOverride:name`` command-line option. The Compiler User Guide contains further information. @@ -7467,23 +7460,23 @@ conjunction with the ``exportc`` pragma: proc exportme(): int {.cdecl, exportc, dynlib.} This is only useful if the program is compiled as a dynamic library via the -``--app:lib`` command line option. +``--app:lib`` command-line option. Threads ======= -To enable thread support the ``--threads:on`` command line switch needs to +To enable thread support the ``--threads:on`` command-line switch needs to be used. The ``system`` module then contains several threading primitives. See the `threads `_ and `channels `_ modules -for the low level thread API. There are also high level parallelism constructs +for the low-level thread API. There are also high-level parallelism constructs available. See `spawn `_ for further details. Nim's memory model for threads is quite different than that of other common programming languages (C, Pascal, Java): Each thread has its own (garbage -collected) heap and sharing of memory is restricted to global variables. This +collected) heap, and sharing of memory is restricted to global variables. This helps to prevent race conditions. GC efficiency is improved quite a lot, because the GC never has to stop other threads and see what they reference. @@ -7495,7 +7488,7 @@ A proc that is executed as a new thread of execution should be marked by the ``thread`` pragma for reasons of readability. The compiler checks for violations of the `no heap sharing restriction`:idx:\: This restriction implies that it is invalid to construct a data structure that consists of memory -allocated from different (thread local) heaps. +allocated from different (thread-local) heaps. A thread proc is passed to ``createThread`` or ``spawn`` and invoked indirectly; so the ``thread`` pragma implies ``procvar``. @@ -7516,7 +7509,7 @@ any of its parameters contain a ``ref`` or ``closure`` type. This enforces the *no heap sharing restriction*. Routines that are imported from C are always assumed to be ``gcsafe``. -To disable the GC-safety checking the ``--threadAnalysis:off`` command line +To disable the GC-safety checking the ``--threadAnalysis:off`` command-line switch can be used. This is a temporary workaround to ease the porting effort from old code to the new threading model. @@ -7549,8 +7542,8 @@ of the ``global`` pragma. .. code-block:: nim var checkpoints* {.threadvar.}: seq[string] -Due to implementation restrictions thread local variables cannot be -initialized within the ``var`` section. (Every thread local variable needs to +Due to implementation restrictions thread-local variables cannot be +initialized within the ``var`` section. (Every thread-local variable needs to be replicated at thread creation.) diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.rst index 2235d5aa4..c6de8cf7c 100644 --- a/doc/manual/var_t_return.rst +++ b/doc/manual/var_t_return.rst @@ -17,4 +17,4 @@ then it has to be derived from the routine's first parameter: In other words, the lifetime of what ``result`` points to is attached to the lifetime of the first parameter and that is enough knowledge to verify -memory safety at the callsite. +memory safety at the call site. diff --git a/doc/nimc.rst b/doc/nimc.rst index 9a698312b..57255a31f 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -26,9 +26,9 @@ Nim is free software; it is licensed under the Compiler Usage ============== -Command line switches +Command-line switches --------------------- -Basic command line switches are: +Basic command-line switches are: Usage: @@ -36,7 +36,7 @@ Usage: ---- -Advanced command line switches are: +Advanced command-line switches are: .. include:: advopt.txt @@ -62,7 +62,7 @@ SmallLshouldNotBeUsed The letter 'l' should not be used as an identifier. EachIdentIsTuple The code contains a confusing ``var`` declaration. -User Some user defined warning. +User Some user-defined warning. ========================== ============================================ @@ -118,7 +118,7 @@ Level Description `_. This is the default level. 2 Displays compilation statistics, enumerates the dynamic - libraries that will be loaded by the final binary and dumps to + libraries that will be loaded by the final binary, and dumps to standard output the result of applying `a filter to the source code `_ if any filter was used during compilation. 3 In addition to the previous levels dumps a debug stack trace @@ -126,10 +126,10 @@ Level Description ===== ============================================ -Compile time symbols +Compile-time symbols -------------------- -Through the ``-d:x`` or ``--define:x`` switch you can define compile time +Through the ``-d:x`` or ``--define:x`` switch you can define compile-time symbols for conditional compilation. The defined switches can be checked in source code with the `when statement `_ and @@ -139,14 +139,14 @@ enabled for better performance. Another common use is the ``-d:ssl`` switch to activate SSL sockets. Additionally, you may pass a value along with the symbol: ``-d:x=y`` -which may be used in conjunction with the `compile time define -pragmas`_ +which may be used in conjunction with the `compile-time define +pragmas`_ to override symbols during build time. -Compile time symbols are completely **case insensitive** and underscores are +Compile-time symbols are completely **case insensitive** and underscores are ignored too. ``--define:FOO`` and ``--define:foo`` are identical. -Compile time symbols starting with the ``nim`` prefix are reserved for the +Compile-time symbols starting with the ``nim`` prefix are reserved for the implementation and should not be used elsewhere. @@ -154,7 +154,7 @@ Configuration files ------------------- **Note:** The *project file name* is the name of the ``.nim`` file that is -passed as a command line argument to the compiler. +passed as a command-line argument to the compiler. The ``nim`` executable processes configuration files in the following @@ -162,12 +162,12 @@ directories (in this order; later files overwrite previous settings): 1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. 2) If environment variable ``XDG_CONFIG_HOME`` is defined, ``$XDG_CONFIG_HOME/nim/nim.cfg`` or ``~/.config/nim/nim.cfg`` (POSIX) or ``%APPDATA%/nim/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. -3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option. -4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option. -5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option. +3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command-line option. +4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command-line option. +5) A project can also have a project-specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command-line option. -Command line settings have priority over configuration file settings. +Command-line settings have priority over configuration file settings. The default build of a project is a `debug build`:idx:. To compile a `release build`:idx: define the ``release`` symbol:: @@ -217,12 +217,12 @@ The ``_r`` suffix is used for release builds, ``_d`` is for debug builds. This makes it easy to delete all generated files. The ``--nimcache`` -`compiler switch <#compiler-usage-command-line-switches>`_ can be used to +`compiler switch <#compiler-usage-commandminusline-switches>`_ can be used to to change the ``nimcache`` directory. -However, the generated C code is not platform independent. C code generated for +However, the generated C code is not platform-independent. C code generated for Linux does not compile on Windows, for instance. The comment on top of the -C file lists the OS, CPU and CC the file has been compiled for. +C file lists the OS, CPU, and CC the file has been compiled for. Compiler Selection @@ -245,7 +245,7 @@ To use the ``CC`` environment variable, use ``nim c --cc:env myfile.nim``. To us since Nim version 1.4. -Cross compilation +Cross-compilation ================= To cross compile, use for example:: @@ -268,10 +268,10 @@ configuration file should contain something like:: arm.linux.gcc.exe = "arm-linux-gcc" arm.linux.gcc.linkerexe = "arm-linux-gcc" -Cross compilation for Windows +Cross-compilation for Windows ============================= -To cross compile for Windows from Linux or macOS using the MinGW-w64 toolchain:: +To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain:: nim c -d:mingw myproject.nim @@ -284,15 +284,15 @@ The MinGW-w64 toolchain can be installed as follows:: OSX: brew install mingw-w64 -Cross compilation for Android +Cross-compilation for Android ============================= There are two ways to compile for Android: terminal programs (Termux) and with the NDK (Android Native Development Kit). -First one is to treat Android as a simple Linux and use +The first one is to treat Android as a simple Linux and use `Termux `_ to connect and run the Nim compiler -directly on android as if it was Linux. These programs are console only +directly on android as if it was Linux. These programs are console-only programs that can't be distributed in the Play Store. Use regular ``nim c`` inside termux to make Android terminal programs. @@ -300,8 +300,8 @@ Use regular ``nim c`` inside termux to make Android terminal programs. Normal Android apps are written in Java, to use Nim inside an Android app you need a small Java stub that calls out to a native library written in Nim using the `NDK `_. You can also use -`native-acitivty `_ -to have the Java stub be auto generated for you. +`native-activity `_ +to have the Java stub be auto-generated for you. Use ``nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on`` to generate the C source files you need to include in your Android Studio @@ -323,10 +323,10 @@ of your program. NimMain() # initialize garbage collector memory, types and stack -Cross compilation for iOS +Cross-compilation for iOS ========================= -To cross compile for iOS you need to be on a MacOS computer and use XCode. +To cross-compile for iOS you need to be on a macOS computer and use XCode. Normal languages for iOS development are Swift and Objective C. Both of these use LLVM and can be compiled into object files linked together with C, C++ or Objective C code produced by Nim. @@ -338,8 +338,8 @@ sign everything. Because Nim is part of a library it can't have its own c style ``main()`` so you would need to define `main` that calls ``autoreleasepool`` and ``UIApplicationMain`` to do it, or use a library like SDL2 or GLFM. After -the iOS setup is done, it's very important to call ``NimMain()`` in order to -initialize Nim's garbage collector and to run the top level statements +the iOS setup is done, it's very important to call ``NimMain()`` to +initialize Nim's garbage collector and to run the top-level statements of your program. .. code-block:: Nim @@ -352,7 +352,7 @@ Note: XCode's "make clean" gets confused about the generated nim.c files, so you need to clean those files manually to do a clean build. -Cross compilation for Nintendo Switch +Cross-compilation for Nintendo Switch ===================================== Simply add --os:nintendoswitch @@ -374,7 +374,7 @@ The DevkitPro setup must be the same as the default with their new installer `here for Mac/Linux `_ or `here for Windows `_. -For example, with the above mentioned config:: +For example, with the above-mentioned config:: nim c --os:nintendoswitch switchhomebrew.nim @@ -479,8 +479,7 @@ debugging with GDB. StackTrace option ----------------- If the ``stackTrace`` option is turned on, the generated C contains code to -ensure that proper stack traces are given if the program crashes or an -uncaught exception is raised. +ensure that proper stack traces are given if the program crashes or some uncaught exception is raised. LineTrace option @@ -509,8 +508,8 @@ Backend language options The typical compiler usage involves using the ``compile`` or ``c`` command to transform a ``.nim`` file into one or more ``.c`` files which are then -compiled with the platform's C compiler into a static binary. However there -are other commands to compile to C++, Objective-C or JavaScript. More details +compiled with the platform's C compiler into a static binary. However, there +are other commands to compile to C++, Objective-C, or JavaScript. More details can be read in the `Nim Backend Integration document `_. @@ -584,7 +583,7 @@ The ``--opt:size`` flag instructs Nim to optimize code generation for small size (with the help of the C compiler), the ``flto`` flags enable link-time optimization in the compiler and linker. -Check the `Cross compilation` section for instructions how to compile the +Check the `Cross-compilation` section for instructions on how to compile the program for your target. Nim for realtime systems @@ -630,7 +629,7 @@ Optimizing string handling String assignments are sometimes expensive in Nim: They are required to copy the whole string. However, the compiler is often smart enough to not copy strings. Due to the argument passing semantics, strings are never copied when -passed to subroutines. The compiler does not copy strings that are a result from +passed to subroutines. The compiler does not copy strings that are a result of a procedure call, because the callee returns a new string anyway. Thus it is efficient to do: @@ -638,7 +637,7 @@ Thus it is efficient to do: var s = procA() # assignment will not copy the string; procA allocates a new # string already -However it is not efficient to do: +However, it is not efficient to do: .. code-block:: Nim var s = varA # assignment has to copy the whole string into a new buffer! @@ -649,12 +648,12 @@ For ``let`` symbols a copy is not always necessary: let s = varA # may only copy a pointer if it safe to do so -If you know what you're doing, you can also mark single string (or sequence) +If you know what you're doing, you can also mark single-string (or sequence) objects as `shallow`:idx:\: .. code-block:: Nim var s = "abc" - shallow(s) # mark 's' as shallow string + shallow(s) # mark 's' as a shallow string var x = s # now might not copy the string! Usage of ``shallow`` is always safe once you know the string won't be modified diff --git a/doc/niminst.rst b/doc/niminst.rst index bf5cb0f50..adb5e6f1f 100644 --- a/doc/niminst.rst +++ b/doc/niminst.rst @@ -59,7 +59,7 @@ Key description ``Description`` the project's description ``App`` the application's type: "Console" or "GUI". If "Console", niminst generates a special batch file - for Windows to open up the command line shell. + for Windows to open up the command-line shell. ``License`` the filename of the application's license ==================== ======================================================= @@ -114,7 +114,7 @@ Listed files will be installed into the OS's native library directory Windows section --------------- -The ``windows`` section supports the ``files`` key for Windows specific files. +The ``windows`` section supports the ``files`` key for Windows-specific files. Listed files will be installed into the application installation directory (``$appdir``). @@ -149,7 +149,7 @@ Key description ==================== ======================================================= ``InstallScript`` boolean flag whether an installation shell script should be generated. Example: ``InstallScript: "Yes"`` -``UninstallScript`` boolean flag whether a deinstallation shell script +``UninstallScript`` boolean flag whether a de-installation shell script should be generated. Example: ``UninstallScript: "Yes"`` ==================== ======================================================= @@ -184,7 +184,7 @@ Key description ==================== ======================================================= -Real world example +Real-world example ================== The installers for the Nim compiler itself are generated by niminst. Have a diff --git a/doc/testament.rst b/doc/testament.rst index 1b2b71c18..e2612711b 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -2,7 +2,7 @@ Testament is an advanced automatic unittests runner for Nim tests, is used for t offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, C++, ObjectiveC, JavaScript, etc), simulated `Dry-Runs `_, -has logging, can generate HTML reports, skip tests from a file and more, +has logging, can generate HTML reports, skip tests from a file, and more, so can be useful to run your tests, even the most complex ones. @@ -115,9 +115,9 @@ Example "template" **to edit** and write a Testament unittest: * As you can see the "Spec" is just a ``discard """ """``. -* Spec has sane defaults, so you dont need to provide them all, any simple assert will work Ok. +* Spec has sane defaults, so you don't need to provide them all, any simple assert will work just fine. * `This is not the full spec of Testament, check the Testament Spec on GitHub, see parseSpec(). `_ -* `Nim itself uses Testament, so theres plenty of test examples. `_ +* `Nim itself uses Testament, so there are plenty of test examples. `_ * Has some built-in CI compatibility, like Azure Pipelines, etc. * `Testament supports inlined error messages on Unittests, basically comments with the expected error directly on the code. `_ @@ -172,7 +172,7 @@ JavaScript tests: import jsconsole console.log("My Frontend Project") -Compile time tests: +Compile-time tests: .. code-block:: nim diff --git a/doc/tools.rst b/doc/tools.rst index df4d2e99f..f231cdc7d 100644 --- a/doc/tools.rst +++ b/doc/tools.rst @@ -14,7 +14,7 @@ The standard distribution ships with the following tools: - | `Nimsuggest for IDE support `_ | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file - and obtain useful information like definition of symbols or suggestions for + and obtain useful information like the definition of symbols or suggestions for completion. - | `C2nim `_ @@ -35,5 +35,5 @@ The standard distribution ships with the following tools: is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, JS, etc), `simulated Dry-Runs `_, - has logging, can generate HTML reports, skip tests from a file and more, + has logging, can generate HTML reports, skip tests from a file, and more, so can be useful to run your tests, even the most complex ones. diff --git a/doc/tut1.rst b/doc/tut1.rst index 68e74df52..415a44f5f 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -18,7 +18,7 @@ Introduction This document is a tutorial for the programming language *Nim*. This tutorial assumes that you are familiar with basic programming concepts -like variables, types or statements but is kept very basic. The `manual +like variables, types, or statements but is kept very basic. The `manual `_ contains many more examples of the advanced language features. All code examples in this tutorial, as well as the ones found in the rest of Nim's documentation, follow the `Nim style guide `_. @@ -41,9 +41,9 @@ Save this code to the file "greetings.nim". Now compile and run it:: nim compile --run greetings.nim -With the ``--run`` `switch `_ Nim +With the ``--run`` `switch `_ Nim executes the file automatically after compilation. You can give your program -command line arguments by appending them after the filename:: +command-line arguments by appending them after the filename:: nim compile --run greetings.nim arg1 arg2 @@ -55,17 +55,17 @@ To compile a release version use:: nim c -d:release greetings.nim -By default the Nim compiler generates a large amount of runtime checks +By default, the Nim compiler generates a large number of runtime checks aiming for your debugging pleasure. With ``-d:release`` some checks are `turned off and optimizations are turned on -`_. +`_. Though it should be pretty obvious what the program does, I will explain the syntax: statements which are not indented are executed when the program starts. Indentation is Nim's way of grouping statements. Indentation is done with spaces only, tabulators are not allowed. -String literals are enclosed in double quotes. The ``var`` statement declares +String literals are enclosed in double-quotes. The ``var`` statement declares a new variable named ``name`` of type ``string`` with the value that is returned by the `readLine `_ procedure. Since the compiler knows that `readLine `_ returns a string, @@ -96,16 +96,16 @@ keywords, comments, operators, and other punctuation marks. String and character literals ----------------------------- -String literals are enclosed in double quotes; character literals in single +String literals are enclosed in double-quotes; character literals in single quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t`` means tabulator, etc. There are also *raw* string literals: .. code-block:: Nim r"C:\program files\nim" -In raw literals the backslash is not an escape character. +In raw literals, the backslash is not an escape character. -The third and last way to write string literals are *long string literals*. +The third and last way to write string literals is *long-string literals*. They are written with three quotes: ``""" ... """``; they can span over multiple lines and the ``\`` is not an escape character either. They are very useful for embedding HTML code templates for example. @@ -148,7 +148,7 @@ Numbers Numerical literals are written as in most other languages. As a special twist, underscores are allowed for better readability: ``1_000_000`` (one million). -A number that contains a dot (or 'e' or 'E') is a floating point literal: +A number that contains a dot (or 'e' or 'E') is a floating-point literal: ``1.0e9`` (one billion). Hexadecimal literals are prefixed with ``0x``, binary literals with ``0b`` and octal literals with ``0o``. A leading zero alone does not produce an octal. @@ -195,11 +195,11 @@ statement and all the variables will have the same value: echo "x ", x # outputs "x 42" echo "y ", y # outputs "y 3" -Note that declaring multiple variables with a single assignment which calls a +Note that declaring multiple variables with a single assignment that calls a procedure can have unexpected results: the compiler will *unroll* the assignments and end up calling the procedure several times. If the result of the procedure depends on side effects, your variables may end up having -different values! For safety use side-effect free procedures if making multiple +different values! For safety use side-effect-free procedures if making multiple assignments. @@ -296,10 +296,10 @@ a multi-branch: else: echo "Hi, ", name, "!" -As it can be seen, for an ``of`` branch a comma separated list of values is also +As it can be seen, for an ``of`` branch a comma-separated list of values is also allowed. -The case statement can deal with integers, other ordinal types and strings. +The case statement can deal with integers, other ordinal types, and strings. (What an ordinal type is will be explained soon.) For integers or other ordinal types value ranges are also possible: @@ -332,7 +332,7 @@ cannot fail and thus the error disappears. Note that it is impossible to cover all possible string values: that is why string cases always need an ``else`` branch. -In general the case statement is used for subrange types or enumerations where +In general, the case statement is used for subrange types or enumerations where it is of great help that the compiler checks that you covered any possible value. @@ -399,7 +399,7 @@ Since counting up occurs so often in programs, Nim also has a `.. ... Zero-indexed counting has two shortcuts ``..<`` and ``.. ^1`` -(`backwards index operator `_) to simplify +(`backward index operator `_) to simplify counting to one less than the higher index: .. code-block:: nim @@ -520,7 +520,7 @@ differences: * The compiler checks the semantics and produces code *only* for the statements that belong to the first condition that evaluates to ``true``. -The ``when`` statement is useful for writing platform specific code, similar to +The ``when`` statement is useful for writing platform-specific code, similar to the ``#ifdef`` construct in the C programming language. @@ -530,15 +530,15 @@ Statements and indentation Now that we covered the basic control flow statements, let's return to Nim indentation rules. -In Nim there is a distinction between *simple statements* and *complex +In Nim, there is a distinction between *simple statements* and *complex statements*. *Simple statements* cannot contain other statements: -Assignment, procedure calls or the ``return`` statement belong to the simple +Assignment, procedure calls, or the ``return`` statement are all simple statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can contain other statements. To avoid ambiguities, complex statements must always be indented, but single simple statements do not: .. code-block:: nim - # no indentation needed for single assignment statement: + # no indentation needed for single-assignment statement: if x: x = false # indentation needed for nested if statement: @@ -554,8 +554,8 @@ be indented, but single simple statements do not: y = false -*Expressions* are parts of a statement which usually result in a value. The -condition in an if statement is an example for an expression. Expressions can +*Expressions* are parts of a statement that usually result in a value. The +condition in an if statement is an example of an expression. Expressions can contain indentation at certain places for better readability: .. code-block:: nim @@ -617,7 +617,7 @@ Some terminology: in the example ``question`` is called a (formal) *parameter*, Result variable --------------- A procedure that returns a value has an implicit ``result`` variable declared -that represents the return value. A ``return`` statement with no expression is a +that represents the return value. A ``return`` statement with no expression is shorthand for ``return result``. The ``result`` value is always returned automatically at the end of a procedure if there is no ``return`` statement at the exit. @@ -637,9 +637,9 @@ the exit. The ``result`` variable is already implicitly declared at the start of the function, so declaring it again with 'var result', for example, would shadow it with a normal variable of the same name. The result variable is also already -initialised with the type's default value. Note that referential data types will +initialized with the type's default value. Note that referential data types will be ``nil`` at the start of the procedure, and thus may require manual -initialisation. +initialization. A procedure that does not have any ``return`` statement and does not use the special ``result`` variable returns the value of its last expression. For example, @@ -798,7 +798,7 @@ Apart from a few built-in keyword operators such as ``and``, ``or``, ``not``, operators always consist of these characters: ``+ - * \ / < > = @ $ ~ & % ! ? ^ . |`` -User defined operators are allowed. Nothing stops you from defining your own +User-defined operators are allowed. Nothing stops you from defining your own ``@!?+~`` operator, but doing so may reduce readability. The operator's precedence is determined by its first character. The details @@ -824,7 +824,7 @@ Forward declarations Every variable, procedure, etc. needs to be declared before it can be used. (The reason for this is that it is non-trivial to avoid this need in a -language that supports meta programming as extensively as Nim does.) +language that supports metaprogramming as extensively as Nim does.) However, this cannot be done for mutually recursive procedures: .. code-block:: nim @@ -900,13 +900,12 @@ important differences: ``yield`` statement). * Iterators have no implicit ``result`` variable. * Iterators do not support recursion. -* Iterators cannot be forward declared, because the compiler must be able - to inline an iterator. (This restriction will be gone in a +* Iterators cannot be forward declared, because the compiler must be able to inline an iterator. (This restriction will be gone in a future version of the compiler.) However, you can also use a ``closure`` iterator to get a different set of -restrictions. See `first class iterators `_ -for details. Iterators can have the same name and parameters as a proc, since +restrictions. See `first-class iterators `_ +for details. Iterators can have the same name and parameters as a proc since essentially they have their own namespaces. Therefore it is common practice to wrap iterators in procs of the same name which accumulate the result of the iterator and return it as a sequence, like ``split`` from the `strutils module @@ -940,10 +939,10 @@ evaluation. For example: Characters ---------- The `character type` is called ``char``. Its size is always one byte, so -it cannot represent most UTF-8 characters; but it *can* represent one of the bytes +it cannot represent most UTF-8 characters, but it *can* represent one of the bytes that makes up a multi-byte UTF-8 character. The reason for this is efficiency: for the overwhelming majority of use-cases, -the resulting programs will still handle UTF-8 properly as UTF-8 was specially +the resulting programs will still handle UTF-8 properly as UTF-8 was especially designed for this. Character literals are enclosed in single quotes. @@ -995,7 +994,7 @@ Most often integers are used for counting objects that reside in memory, so ``int`` has the same size as a pointer. The common operators ``+ - * div mod < <= == != > >=`` are defined for -integers. The ``and or xor not`` operators are also defined for integers, and +integers. The ``and or xor not`` operators are also defined for integers and provide *bitwise* operations. Left bit shifting is done with the ``shl``, right shifting with the ``shr`` operator. Bit shifting operators always treat their arguments as *unsigned*. For `arithmetic bit shifts`:idx: ordinary @@ -1012,7 +1011,7 @@ cannot be detected at compile time). Floats ------ -Nim has these floating point types built-in: ``float float32 float64``. +Nim has these floating-point types built-in: ``float float32 float64``. The default float type is ``float``. In the current implementation, ``float`` is always 64-bits. @@ -1030,9 +1029,8 @@ type: The common operators ``+ - * / < <= == != > >=`` are defined for floats and follow the IEEE-754 standard. -Automatic type conversion in expressions with different kinds of floating -point types is performed: the smaller type is converted to the larger. Integer -types are **not** converted to floating point types automatically, nor vice +Automatic type conversion in expressions with different kinds of floating-point types is performed: the smaller type is converted to the larger. Integer +types are **not** converted to floating-point types automatically, nor vice versa. Use the `toInt `_ and `toFloat `_ procs for these conversions. @@ -1104,7 +1102,7 @@ Enumerations A variable of an enumeration type can only be assigned one of the enumeration's specified values. These values are a set of ordered symbols. Each symbol is mapped to an integer value internally. The first symbol is represented -at runtime by 0, the second by 1 and so on. For example: +at runtime by 0, the second by 1, and so on. For example: .. code-block:: nim :test: "nim c $1" @@ -1135,6 +1133,7 @@ Enumerations, integer types, ``char`` and ``bool`` (and subranges) are called ordinal types. Ordinal types have quite a few special operations: + ----------------- -------------------------------------------------------- Operation Comment ----------------- -------------------------------------------------------- @@ -1150,6 +1149,7 @@ Operation Comment ``pred(x, n)`` returns the `n`'th predecessor of `x` ----------------- -------------------------------------------------------- + The `inc `_, `dec `_, `succ `_ and `pred `_ operations can fail by raising an `EOutOfRange` or `EOverflow` exception. (If the code has been @@ -1187,7 +1187,7 @@ Sets Arrays ------ -An array is a simple fixed length container. Each element in +An array is a simple fixed-length container. Each element in an array has the same type. The array's index type can be any ordinal type. Arrays can be constructed using ``[]``: @@ -1240,7 +1240,7 @@ same index type as the others. In Nim you can have different dimensions with different index types, so the nesting syntax is slightly different. Building on the previous example where a level is defined as an array of enums indexed by yet another enum, we can add the following lines to add a light tower type -subdivided in height levels accessed through their integer index: +subdivided into height levels accessed through their integer index: .. code-block:: nim type @@ -1314,7 +1314,7 @@ The ``for`` statement can be used with one or two variables when used with a sequence. When you use the one variable form, the variable will hold the value provided by the sequence. The ``for`` statement is looping over the results from the `items() `_ iterator from the `system -`_ module. But if you use the two variable form, the first +`_ module. But if you use the two-variable form, the first variable will hold the index position and the second variable will hold the value. Here the ``for`` statement is looping over the results from the `pairs() `_ iterator from the `system @@ -1339,7 +1339,7 @@ Open arrays ----------- **Note**: Openarrays can only be used for parameters. -Often fixed size arrays turn out to be too inflexible; procedures should be +Often fixed-size arrays turn out to be too inflexible; procedures should be able to deal with arrays of different sizes. The `openarray`:idx: type allows this. Openarrays are always indexed with an ``int`` starting at position 0. The `len `_, `low `_ @@ -1591,10 +1591,10 @@ having the same field types. Tuples can be *unpacked* during variable assignment (and only then!). This can be handy to assign directly the fields of the tuples to individually named variables. An example of this is the `splitFile `_ -proc from the `os module `_ which returns the directory, name and +proc from the `os module `_ which returns the directory, name, and extension of a path at the same time. For tuple unpacking to work you must use parentheses around the values you want to assign the unpacking to, -otherwise you will be assigning the same value to all the individual +otherwise, you will be assigning the same value to all the individual variables! For example: .. code-block:: nim @@ -1626,15 +1626,15 @@ point to and modify the same location in memory. Nim distinguishes between `traced`:idx: and `untraced`:idx: references. Untraced references are also called *pointers*. Traced references point to -objects in a garbage collected heap, untraced references point to -manually allocated objects or to objects elsewhere in memory. Thus -untraced references are *unsafe*. However for certain low-level operations +objects in a garbage-collected heap, untraced references point to +manually allocated objects or objects elsewhere in memory. Thus +untraced references are *unsafe*. However, for certain low-level operations (e.g., accessing the hardware), untraced references are necessary. Traced references are declared with the **ref** keyword; untraced references are declared with the **ptr** keyword. -The empty ``[]`` subscript notation can be used to *derefer* a reference, +The empty ``[]`` subscript notation can be used to *de-refer* a reference, meaning to retrieve the item the reference points to. The ``.`` (access a tuple/object field operator) and ``[]`` (array/string/sequence index operator) operators perform implicit dereferencing operations for reference types: @@ -1688,9 +1688,9 @@ listed in the `manual `_. Distinct type ------------- -A Distinct type allows for the creation of new type that "does not imply a +A Distinct type allows for the creation of a new type that "does not imply a subtype relationship between it and its base type". -You must **explicitly** define all behaviour for the distinct type. +You must **explicitly** define all behavior for the distinct type. To help with this, both the distinct type and its base type can cast from one type to the other. Examples are provided in the `manual `_. @@ -1775,7 +1775,7 @@ Excluding symbols ----------------- The normal ``import`` statement will bring in all exported symbols. -These can be limited by naming symbols which should be excluded with +These can be limited by naming symbols that should be excluded using the ``except`` qualifier. .. code-block:: nim @@ -1794,7 +1794,7 @@ exported symbols. An alternative that only imports listed symbols is the The ``from`` statement can also force namespace qualification on symbols, thereby making symbols available, but needing to be qualified -to be used. +in order to be used. .. code-block:: nim from mymodule import x, y, z diff --git a/doc/tut3.rst b/doc/tut3.rst index a39074db9..a159f0d82 100644 --- a/doc/tut3.rst +++ b/doc/tut3.rst @@ -14,7 +14,7 @@ Introduction "With Great Power Comes Great Responsibility." -- Spider Man's Uncle This document is a tutorial about Nim's macro system. -A macro is a function that is executed at compile time and transforms +A macro is a function that is executed at compile-time and transforms a Nim syntax tree into a different tree. Examples of things that can be implemented in macros: @@ -35,7 +35,7 @@ Macro Arguments --------------- The types of macro arguments have two faces. One face is used for -the overload resolution, and the other face is used within the macro +the overload resolution and the other face is used within the macro body. For example, if ``macro foo(arg: int)`` is called in an expression ``foo(x)``, ``x`` has to be of a type compatible to int, but *within* the macro's body ``arg`` has the type ``NimNode``, not ``int``! @@ -52,10 +52,10 @@ Untyped Arguments Untyped macro arguments are passed to the macro before they are semantically checked. This means the syntax tree that is passed down to the macro does not need to make sense for Nim yet, the only -limitation is that it needs to be parsable. Usually the macro does +limitation is that it needs to be parsable. Usually, the macro does not check the argument either but uses it in the transformation's result somehow. The result of a macro expansion is always checked -by the compiler, so apart from weird error messages nothing bad +by the compiler, so apart from weird error messages, nothing bad can happen. The downside for an ``untyped`` argument is that these do not play @@ -73,7 +73,7 @@ For typed arguments, the semantic checker runs on the argument and does transformations on it, before it is passed to the macro. Here identifier nodes are resolved as symbols, implicit type conversions are visible in the tree as calls, templates are -expanded and probably most importantly, nodes have type information. +expanded, and probably most importantly, nodes have type information. Typed arguments can have the type ``typed`` in the arguments list. But all other types, such as ``int``, ``float`` or ``MyObjectType`` are typed arguments as well, and they are passed to the macro as a @@ -103,7 +103,7 @@ Code Blocks as Arguments ------------------------ It is possible to pass the last argument of a call expression in a -separate code block with indentation. For example the following code +separate code block with indentation. For example, the following code example is a valid (but not a recommended) way to call ``echo``: .. code-block:: nim @@ -126,10 +126,10 @@ look like so that the Nim compiler will understand it. The nodes of the Nim syntax tree are documented in the `macros `_ module. But a more interactive way to explore the Nim syntax tree is with ``macros.treeRepr``, it converts a syntax tree -into a multi line string for printing on the console. It can be used +into a multi-line string for printing on the console. It can be used to explore how the argument expressions are represented in tree form and for debug printing of generated syntax tree. ``dumpTree`` is a -predefined macro that just prints its argument in tree representation, +predefined macro that just prints its argument in a tree representation, but does nothing else. Here is an example of such a tree representation: .. code-block:: nim @@ -176,7 +176,7 @@ Generating Code There are two ways to generate the code. Either by creating the syntax tree with expressions that contain a lot of calls to ``newTree`` and ``newLit``, or with ``quote do:`` expressions. The first option offers -the best low level control for the syntax tree generation, but the +the best low-level control for the syntax tree generation, but the second option is much less verbose. If you choose to create the syntax tree with calls to ``newTree`` and ``newLit`` the macro ``macros.dumpAstGen`` can help you with the verbosity. ``quote do:`` @@ -226,8 +226,8 @@ Building Your First Macro To give a starting point to writing macros we will show now how to implement the ``myDebug`` macro mentioned earlier. The first thing to do is to build a simple example of the macro usage, and then just -print the argument. This way it is possible to get an idea of a -correct argument should be look like. +print the argument. This way it is possible to get an idea of what a +correct argument should look like. .. code-block:: nim :test: "nim c $1" @@ -250,9 +250,9 @@ correct argument should be look like. Ident "b" -From the output it is possible to see that the argument is an infix +From the output, it is possible to see that the argument is an infix operator (node kind is "Infix"), as well as that the two operands are -at index 1 and 2. With this information the actual macro can be +at index 1 and 2. With this information, the actual macro can be written. .. code-block:: nim @@ -292,13 +292,13 @@ used to get this output. With Power Comes Responsibility ------------------------------- -Macros are very powerful. A good advice is to use them as little as +Macros are very powerful. A piece of good advice is to use them as little as possible, but as much as necessary. Macros can change the semantics of expressions, making the code incomprehensible for anybody who does not know exactly what the macro does with it. So whenever a macro is not necessary and the same logic can be implemented using templates or generics, it is probably better not to use a macro. And when a macro -is used for something, the macro should better have a well written +is used for something, the macro should better have a well-written documentation. For all the people who claim to write only perfectly self-explanatory code: when it comes to macros, the implementation is not enough for documentation. @@ -309,7 +309,7 @@ Limitations Since macros are evaluated in the compiler in the NimVM, macros share all the limitations of the NimVM. They have to be implemented in pure Nim code. Macros can start external processes on the shell, but they -cannot call C functions except from those that are built in the +cannot call C functions except those that are built in the compiler. @@ -348,7 +348,7 @@ OpenGL Sandbox -------------- This project has a working Nim to GLSL compiler written entirely in -macros. It scans recursively though all used function symbols to +macros. It scans recursively through all used function symbols to compile them so that cross library functions can be executed on the GPU. `OpenGL Sandbox `_ From 53d9902347dad9e22171f643916e830c1b20872c Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Thu, 29 Oct 2020 12:14:22 +0200 Subject: [PATCH 1344/4254] Make default state public (#15763) * Make default state public * Address review comments Co-authored-by: b3liever --- changelog.md | 2 +- lib/pure/random.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 7f1034376..7c7640207 100644 --- a/changelog.md +++ b/changelog.md @@ -7,7 +7,7 @@ - `prelude` now works with the JavaScript target. - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. - +- Added `randState` template that exposes the default random number generator. Useful for library authors. ## Language changes diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 7c5d51ceb..3d9948d08 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -119,6 +119,12 @@ else: a0: 0x69B4C98CB8530805u64, a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility +since (1, 5): + template randState*(): untyped = + ## Makes the default Rand state accessible from other modules. + ## Useful for module authors. + state + proc rotl(x, k: Ui): Ui = result = (x shl k) or (x shr (Ui(64) - k)) From 87a60c1b28a777e35701c2f934fc1361818a216e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 29 Oct 2020 17:32:56 +0100 Subject: [PATCH 1345/4254] fixes #15413 (#15768) * fixes #15413 * better hide it properly * see if this makes our list of important packages happy --- changelog.md | 7 ++++ lib/pure/json.nim | 82 +++++++++++++++++++++++++++++++----------- tests/stdlib/tjson.nim | 3 ++ 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/changelog.md b/changelog.md index 7c7640207..552e1e8df 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,13 @@ - `prelude` now works with the JavaScript target. - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. + +- The JSON module can now handle integer literals and floating point literals of arbitrary length and precision. + Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are kept as string literals and + one can use external BigNum libraries to handle these. The `parseFloat` family of functions also has now optional + `rawIntegers` and `rawFloats` parameters that can be used to enforce that all integer or float literals remain + in the "raw" string form so that client code can easily treat small and large numbers uniformly. + - Added `randState` template that exposes the default random number generator. Useful for library authors. ## Language changes diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 3f2e369f6..9766e32cb 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -177,6 +177,8 @@ type JsonNode* = ref JsonNodeObj ## JSON node JsonNodeObj* {.acyclic.} = object + isUnquoted: bool # the JString was a number-like token and + # so shouldn't be quoted case kind*: JsonNodeKind of JString: str*: string @@ -197,6 +199,13 @@ proc newJString*(s: string): JsonNode = ## Creates a new `JString JsonNode`. result = JsonNode(kind: JString, str: s) +proc newJRawNumber(s: string): JsonNode = + ## Creates a "raw JS number", that is a number that does not + ## fit into Nim's ``BiggestInt`` field. This is really a `JString` + ## with the additional information that it should be converted back + ## to the string representation without the quotes. + result = JsonNode(kind: JString, str: s, isUnquoted: true) + proc newJStringMove(s: string): JsonNode = result = JsonNode(kind: JString) shallowCopy(result.str, s) @@ -562,6 +571,7 @@ proc copy*(p: JsonNode): JsonNode = case p.kind of JString: result = newJString(p.str) + result.isUnquoted = p.isUnquoted of JInt: result = newJInt(p.num) of JFloat: @@ -652,7 +662,10 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, result.add("{}") of JString: if lstArr: result.indent(currIndent) - escapeJson(node.str, result) + if node.isUnquoted: + result.add node.str + else: + escapeJson(node.str, result) of JInt: if lstArr: result.indent(currIndent) when defined(js): result.add($node.num) @@ -734,7 +747,10 @@ proc toUgly*(result: var string, node: JsonNode) = result.toUgly value result.add "}" of JString: - node.str.escapeJson(result) + if node.isUnquoted: + result.add node.str + else: + node.str.escapeJson(result) of JInt: when defined(js): result.add($node.num) else: result.addInt(node.num) @@ -783,7 +799,7 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] = for key, val in mpairs(node.fields): yield (key, val) -proc parseJson(p: var JsonParser): JsonNode = +proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode = ## Parses JSON from a JSON Parser `p`. case p.tok of tkString: @@ -792,10 +808,22 @@ proc parseJson(p: var JsonParser): JsonNode = p.a = "" discard getTok(p) of tkInt: - result = newJInt(parseBiggestInt(p.a)) + if rawIntegers: + result = newJRawNumber(p.a) + else: + try: + result = newJInt(parseBiggestInt(p.a)) + except ValueError: + result = newJRawNumber(p.a) discard getTok(p) of tkFloat: - result = newJFloat(parseFloat(p.a)) + if rawFloats: + result = newJRawNumber(p.a) + else: + try: + result = newJFloat(parseFloat(p.a)) + except ValueError: + result = newJRawNumber(p.a) discard getTok(p) of tkTrue: result = newJBool(true) @@ -815,7 +843,7 @@ proc parseJson(p: var JsonParser): JsonNode = var key = p.a discard getTok(p) eat(p, tkColon) - var val = parseJson(p) + var val = parseJson(p, rawIntegers, rawFloats) result[key] = val if p.tok != tkComma: break discard getTok(p) @@ -824,39 +852,47 @@ proc parseJson(p: var JsonParser): JsonNode = result = newJArray() discard getTok(p) while p.tok != tkBracketRi: - result.add(parseJson(p)) + result.add(parseJson(p, rawIntegers, rawFloats)) if p.tok != tkComma: break discard getTok(p) eat(p, tkBracketRi) of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof: raiseParseErr(p, "{") -iterator parseJsonFragments*(s: Stream, filename: string = ""): JsonNode = +iterator parseJsonFragments*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats = false): JsonNode = ## Parses from a stream `s` into `JsonNodes`. `filename` is only needed ## for nice error messages. ## The JSON fragments are separated by whitespace. This can be substantially ## faster than the comparable loop ## ``for x in splitWhitespace(s): yield parseJson(x)``. ## This closes the stream `s` after it's done. + ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` + ## field but kept as raw numbers via `JString`. + ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` + ## field but kept as raw numbers via `JString`. var p: JsonParser p.open(s, filename) try: discard getTok(p) # read first token while p.tok != tkEof: - yield p.parseJson() + yield p.parseJson(rawIntegers, rawFloats) finally: p.close() -proc parseJson*(s: Stream, filename: string = ""): JsonNode = +proc parseJson*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats = false): JsonNode = ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed ## for nice error messages. ## If `s` contains extra data, it will raise `JsonParsingError`. ## This closes the stream `s` after it's done. + ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` + ## field but kept as raw numbers via `JString`. + ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` + ## field but kept as raw numbers via `JString`. var p: JsonParser p.open(s, filename) try: discard getTok(p) # read first token - result = p.parseJson() + result = p.parseJson(rawIntegers, rawFloats) eat(p, tkEof) # check if there is no extra data finally: p.close() @@ -924,6 +960,7 @@ when defined(js): of JFloat: result = newJFloat(cast[float](x)) of JString: + # Dunno what to do with isUnquoted here result = newJString($cast[cstring](x)) of JBool: result = newJBool(cast[bool](x)) @@ -937,10 +974,14 @@ when defined(js): return parseNativeJson(buffer).convertObject() else: - proc parseJson*(buffer: string): JsonNode = + proc parseJson*(buffer: string; rawIntegers = false, rawFloats = false): JsonNode = ## Parses JSON from `buffer`. ## If `buffer` contains extra data, it will raise `JsonParsingError`. - result = parseJson(newStringStream(buffer), "input") + ## If `rawIntegers` is true, integer literals will not be converted to a `JInt` + ## field but kept as raw numbers via `JString`. + ## If `rawFloats` is true, floating point literals will not be converted to a `JFloat` + ## field but kept as raw numbers via `JString`. + result = parseJson(newStringStream(buffer), "input", rawIntegers, rawFloats) proc parseFile*(filename: string): JsonNode = ## Parses `file` into a `JsonNode`. @@ -948,7 +989,7 @@ else: var stream = newFileStream(filename, fmRead) if stream == nil: raise newException(IOError, "cannot read from file: " & filename) - result = parseJson(stream, filename) + result = parseJson(stream, filename, rawIntegers=false, rawFloats=false) # -- Json deserialiser. -- @@ -986,9 +1027,9 @@ when defined(nimFixedForwardGeneric): proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[S, T](dst: var array[S, T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var Table[string, T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var OrderedTable[string, T]; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) @@ -1082,7 +1123,7 @@ when defined(nimFixedForwardGeneric): dst = some(default(T)) initFromJson(dst.get, jsonNode, jsonPath) - macro assignDistinctImpl[T : distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = + macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = let typInst = getTypeInst(dst) let typImpl = getTypeImpl(dst) let baseTyp = typImpl[0] @@ -1096,7 +1137,7 @@ when defined(nimFixedForwardGeneric): else: initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) - proc initFromJson[T : distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = assignDistinctImpl(dst, jsonNode, jsonPath) proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode): void = @@ -1186,7 +1227,6 @@ when defined(nimFixedForwardGeneric): else: error("unhandled kind: " & $typeNode.kind, typeNode) - macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) = let typeSym = getTypeInst(dst) let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen") @@ -1201,7 +1241,7 @@ when defined(nimFixedForwardGeneric): else: foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen) - proc initFromJson[T : object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = assignObjectImpl(dst, jsonNode, jsonPath) proc to*[T](node: JsonNode, t: typedesc[T]): T = diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index bc7ff02b2..78f284abb 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -232,3 +232,6 @@ doAssert isRefSkipDistinct(MyRef) doAssert not isRefSkipDistinct(MyObject) doAssert isRefSkipDistinct(MyDistinct) doAssert isRefSkipDistinct(MyOtherDistinct) + +let x = parseJson("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999") +doAssert x.kind == JString From 912d8f80ad5782ee371376f9f5664af3ac21995e Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Thu, 29 Oct 2020 18:54:28 +0200 Subject: [PATCH 1346/4254] Fix doc comment for sumKbn (#15769) Co-authored-by: b3liever --- lib/std/sums.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/sums.nim b/lib/std/sums.nim index a48360180..0f8c5ebfb 100644 --- a/lib/std/sums.nim +++ b/lib/std/sums.nim @@ -10,7 +10,7 @@ func sumKbn*[T](x: openArray[T]): T = - ## Kahan (compensated) summation: O(1) error growth, at the expense + ## Kahan-Babuška-Neumaier summation: O(1) error growth, at the expense ## of a considerable increase in computational expense. if len(x) == 0: return var sum = x[0] From 33e258c72fe9c06410b30c5bc4364626c4f6ecb1 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 01:12:14 +0800 Subject: [PATCH 1347/4254] add tests for #7686 (#15771) --- tests/stdlib/t7686.nim | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/stdlib/t7686.nim diff --git a/tests/stdlib/t7686.nim b/tests/stdlib/t7686.nim new file mode 100644 index 000000000..c174dfb51 --- /dev/null +++ b/tests/stdlib/t7686.nim @@ -0,0 +1,9 @@ +import strutils + +type + MyEnum = enum + A, + a + +doAssert parseEnum[MyEnum]("A") == A +doAssert parseEnum[MyEnum]("a") == a From d8fb2379c9a6e83b7e8151ba13116afb1bedc00f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 10:54:39 +0800 Subject: [PATCH 1348/4254] add testcase for #7127 (#15780) --- tests/js/t7127.nim | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/js/t7127.nim diff --git a/tests/js/t7127.nim b/tests/js/t7127.nim new file mode 100644 index 000000000..364aedd4a --- /dev/null +++ b/tests/js/t7127.nim @@ -0,0 +1,2 @@ +doAssertRaises(DivByZeroDefect): discard 1 mod 0 +doAssertRaises(DivByZeroDefect): discard 1 div 0 \ No newline at end of file From f79ded3cb6a1a8eb754081fca6b074bef455224e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:16:47 +0800 Subject: [PATCH 1349/4254] fix #15638 (#15789) --- compiler/jsgen.nim | 1 + tests/js/tdiscard.nim | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 tests/js/tdiscard.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 4d913aa87..8b91ada8a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2534,6 +2534,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = if n[0].kind != nkEmpty: genLineDir(p, n) gen(p, n[0], r) + r.res = "var _ = " & r.res of nkAsmStmt: genAsmOrEmitStmt(p, n) of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r) of nkRaiseStmt: genRaiseStmt(p, n) diff --git a/tests/js/tdiscard.nim b/tests/js/tdiscard.nim new file mode 100644 index 000000000..9aa6ea1b1 --- /dev/null +++ b/tests/js/tdiscard.nim @@ -0,0 +1,3 @@ +import dom + +discard Node() \ No newline at end of file From b5df82319186595b2cc35678203a0992588dca8c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:55:21 +0800 Subject: [PATCH 1350/4254] add testcase for #9091 (#15791) * add testcase for #9091 * more tests --- tests/stdlib/t9091.nim | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/stdlib/t9091.nim diff --git a/tests/stdlib/t9091.nim b/tests/stdlib/t9091.nim new file mode 100644 index 000000000..8419479a7 --- /dev/null +++ b/tests/stdlib/t9091.nim @@ -0,0 +1,36 @@ +discard """ + targets: "c" + output: "test AObj" + action: "compile" + exitcode: 0 + timeout: 60.0 +""" +import streams + +block: + type Mine = ref object + a: int + + proc write(io: Stream, t: Mine) = + io.write("sure") + + let str = newStringStream() + let mi = new Mine + + str.write(mi) + +block: + type + AObj = object + x: int + + proc foo(a: int): string = "" + + proc test(args: varargs[string, foo]) = + echo "varargs" + + proc test(a: AObj) = + echo "test AObj" + + let x = AObj() + test(x) From c274d9aed637af05f7acf553edb57721bd91d021 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Fri, 30 Oct 2020 10:56:28 +0200 Subject: [PATCH 1351/4254] add approxequal (#15766) * add approxequal * Address review comments, tests that pass * more wikipedia links [ci skip] * forgot since Co-authored-by: b3liever Co-authored-by: Andreas Rumpf --- changelog.md | 2 ++ lib/pure/math.nim | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 552e1e8df..6bff75a44 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ - `prelude` now works with the JavaScript target. - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. +- Added `almostEqual` in `math` for comparing two float values using a machine epsilon. - The JSON module can now handle integer literals and floating point literals of arbitrary length and precision. Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are kept as string literals and @@ -16,6 +17,7 @@ - Added `randState` template that exposes the default random number generator. Useful for library authors. + ## Language changes diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 21d614270..2a2660524 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -56,7 +56,7 @@ import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import bitops +import bitops, fenv proc binom*(n, k: int): int {.noSideEffect.} = ## Computes the `binomial coefficient `_. @@ -158,6 +158,29 @@ proc classify*(x: float): FloatClass = return fcSubnormal return fcNormal +proc almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. + since: (1, 5), inline, noSideEffect.} = + ## Checks if two float values are almost equal, using + ## `machine epsilon `_. + ## + ## `unitsInLastPlace` is the max number of + ## `units in last place `_ + ## difference tolerated when comparing two numbers. The larger the value, the + ## more error is allowed. A ``0`` value means that two numbers must be exactly the + ## same to be considered equal. + ## + ## The machine epsilon has to be scaled to the magnitude of the values used + ## and multiplied by the desired precision in ULPs unless the difference is + ## subnormal. + ## + # taken from: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon + runnableExamples: + doAssert almostEqual(3.141592653589793, 3.1415926535897936) + doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32) + let diff = abs(x - y) + result = diff <= epsilon(T) * abs(x + y) * T(unitsInLastPlace) or + diff < minimumPositiveValue(T) + proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = ## Returns ``true``, if ``x`` is a power of two, ``false`` otherwise. ## From 1655c04aa3b980bf0a9d65bf658c19efa6af7d94 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:57:02 +0800 Subject: [PATCH 1352/4254] add testcase for #9165 (#15787) --- tests/converter/t9165.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/converter/t9165.nim diff --git a/tests/converter/t9165.nim b/tests/converter/t9165.nim new file mode 100644 index 000000000..d0225ffbc --- /dev/null +++ b/tests/converter/t9165.nim @@ -0,0 +1,11 @@ +type ustring = distinct string + +converter toUString(s: string): ustring = ustring(s) +converter toString(s: ustring): string = string(s) + +proc `[]=`*(s: var ustring, slice: Slice[int], replacement: ustring) {.inline.} = + s = replacement + +var s = ustring("123") +s[1..2] = "3" +doAssert s == "3" \ No newline at end of file From 2de90a14cbc5182efad2cff63cd33f820e3a8832 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:57:26 +0800 Subject: [PATCH 1353/4254] add testcase for #8012 (#15785) --- tests/concepts/t8012.nim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/concepts/t8012.nim diff --git a/tests/concepts/t8012.nim b/tests/concepts/t8012.nim new file mode 100644 index 000000000..ec2aa6e5c --- /dev/null +++ b/tests/concepts/t8012.nim @@ -0,0 +1,15 @@ +type + MyTypeCon = concept c + c.counter is int + MyType = object + counter: int + +proc foo(conc: var MyTypeCon) = + conc.counter.inc + if conc.counter < 5: + foo(conc) + +var x: MyType + +x.foo +discard x.repr From 17f08b2939db224d533db846fc3fa8ab91cc9755 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:58:55 +0800 Subject: [PATCH 1354/4254] closes #7658 (#15784) * fix #7658 * more --- compiler/pragmas.nim | 9 ++++++--- tests/js/tunion.nim | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 tests/js/tunion.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c0c9cc06a..273b2b004 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1110,9 +1110,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: sym.typ.kind = tyUncheckedArray of wUnion: - noVal(c, it) - if sym.typ == nil: invalidPragma(c, it) - else: incl(sym.typ.flags, tfUnion) + if c.config.backend == backendJs: + localError(c.config, it.info, "`{.union.}` is not implemented for js backend.") + else: + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) + else: incl(sym.typ.flags, tfUnion) of wRequiresInit: noVal(c, it) if sym.kind == skField: diff --git a/tests/js/tunion.nim b/tests/js/tunion.nim new file mode 100644 index 000000000..e185495ad --- /dev/null +++ b/tests/js/tunion.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "`{.union.}` is not implemented for js backend." +""" + +type Foo {.union.} = object + as_bytes: array[8, int8] + data: int64 From 3028c1be82a04c0271fcb98396f28ebc62775b3a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:59:38 +0800 Subject: [PATCH 1355/4254] add testcase for #7416 (#15782) --- tests/overload/t7416.nim | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/overload/t7416.nim diff --git a/tests/overload/t7416.nim b/tests/overload/t7416.nim new file mode 100644 index 000000000..4a9b2e7cb --- /dev/null +++ b/tests/overload/t7416.nim @@ -0,0 +1,9 @@ +type + Foo[T] = object + IntFoo = Foo[int] + +proc bar(b: object|tuple) = discard +proc bar(b: IntFoo) = discard + +var f: IntFoo +bar(f) \ No newline at end of file From 1725db9295b037ac410f0e6d48952c01218aee89 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:59:56 +0800 Subject: [PATCH 1356/4254] closes #7374 (#15781) * add testcase for #7374 * minor * fix test --- tests/template/tshadow.nim | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/template/tshadow.nim diff --git a/tests/template/tshadow.nim b/tests/template/tshadow.nim new file mode 100644 index 000000000..a4de71592 --- /dev/null +++ b/tests/template/tshadow.nim @@ -0,0 +1,29 @@ +discard """ + output: '''fish +fish''' +""" + +import macros + +block: + template init(initHook: proc(s: string)) = + proc dostuff = + var s = "fish" + initHook(s) + dostuff() + + init do(s: string): + echo s + +block: + macro init(initHook: proc(s: string)) = + result = newStmtList( + newProc(name = ident("dostuff"), body = newStmtList( + newVarStmt(ident("s"), newStrLitNode("fish")), + newCall(initHook, ident("s")) + )), + newCall("dostuff") + ) + + init proc(s: string) = + echo s From 4374c638cd328b8cf9b72ff756cfe0564d6d9c78 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 17:00:25 +0800 Subject: [PATCH 1357/4254] closes #6036 (#15779) * add testcase for #6036 * try * try again * make it work --- tests/ccgbugs/tcompile_time_var_at_runtime.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/ccgbugs/tcompile_time_var_at_runtime.nim diff --git a/tests/ccgbugs/tcompile_time_var_at_runtime.nim b/tests/ccgbugs/tcompile_time_var_at_runtime.nim new file mode 100644 index 000000000..c0de0390b --- /dev/null +++ b/tests/ccgbugs/tcompile_time_var_at_runtime.nim @@ -0,0 +1,11 @@ +discard """ + output: "1\n2\n2\n3" +""" +var a {.compileTime.} = 1 + +echo a +a = 2 +echo a +echo a +a = 3 +echo a \ No newline at end of file From c0fdc8b215b02736cdb1c275a92b1d5a513f8bad Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 30 Oct 2020 10:04:53 +0100 Subject: [PATCH 1358/4254] fix `toHex` - make it work with int literals (#15770) --- lib/pure/strutils.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 20ad2f517..94bdafc10 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -981,6 +981,18 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, doAssert c.toHex(6) == "FFFFF8" toHexImpl(cast[BiggestUInt](x), len, x < 0) +proc toHex*(x: int, len: Positive): string {.noSideEffect.} = + ## Converts `x` to its hexadecimal representation. + ## + ## The resulting string will be exactly `len` characters long. No prefix like + ## ``0x`` is generated. `x` is treated as an unsigned value. + runnableExamples: + doAssert toHex(62, 3) == "03E" + doAssert toHex(4097, 3) == "001" + doAssert toHex(4097, 4) == "1001" + doAssert toHex(-8, 6) == "FFFFF8" + toHexImpl(cast[BiggestUInt](x), len, x < 0) + proc toHex*[T: SomeInteger](x: T): string {.noSideEffect.} = ## Shortcut for ``toHex(x, T.sizeof * 2)`` runnableExamples: From ec059240b030161111d7ffdbd07a8c677bc17994 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 30 Oct 2020 10:12:01 +0100 Subject: [PATCH 1359/4254] promote `collect` macro as a map+filter replacement (#15788) * promote `collect` macro as a map+filter replacement * Update lib/pure/collections/sequtils.nim --- lib/pure/collections/sequtils.nim | 27 +++++++++++++++++++++++++++ lib/pure/strutils.nim | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 803f89cc5..20a0f77cb 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -27,6 +27,7 @@ ## languages. ## ## For functional style programming you have different options at your disposal: +## * `sugar.collect macro`_ ## * pass `anonymous proc`_ ## * import `sugar module`_ and use ## `=> macro.m,untyped,untyped>`_ @@ -45,8 +46,14 @@ ## let ## foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0) ## bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0) +## baz = collect(newSeq): +## for i in 1..10: +## let j = 2*i +## if j mod 6 != 0: +## j ## ## doAssert foo == bar +## doAssert foo == baz ## echo foo # @[2, 4, 8, 10, 14, 16, 20] ## ## echo foo.any(x => x > 17) # true @@ -361,7 +368,11 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): ## Since the input is not modified you can use it to ## transform the type of the elements in the input container. ## + ## Instead of using `map` and `filter`, consider using the `collect` macro + ## from the `sugar` module. + ## ## See also: + ## * `sugar.collect macro`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version ## @@ -424,7 +435,11 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## Iterates through a container `s` and yields every item that fulfills the ## predicate `pred` (function that returns a `bool`). ## + ## Instead of using `map` and `filter`, consider using the `collect` macro + ## from `sugar` module. + ## ## See also: + ## * `sugar.collect macro`_ ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## @@ -444,7 +459,11 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] ## Returns a new sequence with all the items of `s` that fulfilled the ## predicate `pred` (function that returns a `bool`). ## + ## Instead of using `map` and `filter`, consider using the `collect` macro + ## from `sugar` module. + ## ## See also: + ## * `sugar.collect macro`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ for the in-place version @@ -560,7 +579,11 @@ template filterIt*(s, pred: untyped): untyped = ## the predicate needs to be an expression using the ``it`` variable ## for testing, like: ``filterIt("abcxyz", it == 'x')``. ## + ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro + ## from `sugar` module. + ## ## See also: + ## * `sugar.collect macro`_ ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## @@ -916,7 +939,11 @@ template mapIt*(s: typed, op: untyped): untyped = ## The template injects the ``it`` variable which you can use directly in an ## expression. ## + ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro + ## from `sugar` module. + ## ## See also: + ## * `sugar.collect macro`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version ## diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 94bdafc10..740a6e391 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -59,12 +59,13 @@ ## * `unicode module`_ for Unicode UTF-8 handling ## * `sequtils module`_ for operations on container ## types (including strings) +## * `parsecsv module`_ for a high-performance CSV parser ## * `parseutils module`_ for lower-level parsing of tokens, ## numbers, identifiers, etc. ## * `parseopt module`_ for command-line parsing +## * `pegs module`_ for PEG (Parsing Expression Grammar) support ## * `strtabs module`_ for efficient hash tables ## (dictionaries, in some programming languages) mapping from strings to strings -## * `pegs module`_ for PEG (Parsing Expression Grammar) support ## * `ropes module`_ for rope data type, which can represent very ## long strings efficiently ## * `re module`_ for regular expression (regex) support From 6fe2e8977d0227a454cfb606c821cc455a9d0e07 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 30 Oct 2020 11:42:06 +0000 Subject: [PATCH 1360/4254] canAlias improvement (#15773) * canAlias improvement * fix comment --- compiler/isolation_check.nim | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 8c40dd4ad..01f0a002a 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -64,9 +64,18 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool = else: result = false +proc isValueOnlyType(t: PType): bool = + # t doesn't contain pointers and references + proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent} + result = not types.searchTypeFor(t, wrap) + proc canAlias*(arg, ret: PType): bool = - var marker = initIntSet() - result = canAlias(arg, ret, marker) + if isValueOnlyType(arg): + # can alias only with unsafeAddr(arg.x) and we don't care if it is not safe + result = false + else: + var marker = initIntSet() + result = canAlias(arg, ret, marker) proc checkIsolate*(n: PNode): bool = if types.containsTyRef(n.typ): From 2cfe5e0745cf33ed5698378dd16e01ce542f05e5 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 22:34:07 +0800 Subject: [PATCH 1361/4254] [closes #11625 and closes #2488]add global and threadvar(with `--threads:off` mode ) pragmas supports for JS backend (#15772) * add global pragma support for js backend * globalThis * add support for threadvar * more tests * Update compiler/jsgen.nim Co-authored-by: Andreas Rumpf --- compiler/jsgen.nim | 7 ++++++- tests/js/tglobal.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/js/tglobal.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 8b91ada8a..766e6a80d 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1736,6 +1736,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = varCode: string varName = mangleName(p.module, v) useReloadingGuard = sfGlobal in v.flags and p.config.hcrOn + useGlobalPragmas = sfGlobal in v.flags and ({sfPure, sfThread} * v.flags != {}) if v.constraint.isNil: if useReloadingGuard: @@ -1743,6 +1744,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = lineF(p, "if ($1 === undefined) {$n", varName) varCode = $varName inc p.extraIndent + elif useGlobalPragmas: + lineF(p, "if (globalThis.$1 === undefined) {$n", varName) + varCode = $varName + inc p.extraIndent else: varCode = "var $2" else: @@ -1795,7 +1800,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = else: line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, s])) - if useReloadingGuard: + if useReloadingGuard or useGlobalPragmas: dec p.extraIndent lineF(p, "}$n") diff --git a/tests/js/tglobal.nim b/tests/js/tglobal.nim new file mode 100644 index 000000000..38f5eec34 --- /dev/null +++ b/tests/js/tglobal.nim @@ -0,0 +1,30 @@ +block global: + proc getState(): int = + var state0 {.global.}: int + inc state0 + result = state0 + + for i in 0 ..< 3: + doAssert getState() == i + 1 + + for i in 0 ..< 3: + once: + doAssert i == 0 + + +block threadvar: + proc getThreadState0(): int = + var state0 {.threadvar.}: int + inc state0 + result = state0 + + for i in 0 ..< 3: + doAssert getThreadState0() == i + 1 + + proc getThreadState1(): int = + var state1 {.threadvar.}: int + inc state1 + result = state1 + + for i in 0 ..< 3: + doAssert getThreadState1() == i + 1 From ae86df12af6c00ea74659375b758178cc2d73311 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 30 Oct 2020 22:53:45 +0800 Subject: [PATCH 1362/4254] add testcase for #14227 (#15794) --- tests/macros/t14227.nim | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/macros/t14227.nim diff --git a/tests/macros/t14227.nim b/tests/macros/t14227.nim new file mode 100644 index 000000000..4206e2c06 --- /dev/null +++ b/tests/macros/t14227.nim @@ -0,0 +1,23 @@ +discard """ + action: "compile" +""" +import sugar + + +block: + let y = @[@[1, 2], @[2, 4, 6]] + let x = collect(newSeq): + for i in y: + if i.len > 2: + for j in i: + j + echo(x) + +block: + let y = @[@[1, 2], @[2, 4, 6]] + let x = collect(newSeq): + for i in y: + for j in i: + if i.len > 2: + j + echo(x) From 7364794fedcf8ee20ca5a55f58c14c76dfa31723 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 30 Oct 2020 16:00:37 +0100 Subject: [PATCH 1363/4254] Grammar fixes --- lib/pure/collections/sequtils.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 20a0f77cb..ea2c02b8c 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -436,7 +436,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## predicate `pred` (function that returns a `bool`). ## ## Instead of using `map` and `filter`, consider using the `collect` macro - ## from `sugar` module. + ## from the `sugar` module. ## ## See also: ## * `sugar.collect macro`_ @@ -460,7 +460,7 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] ## predicate `pred` (function that returns a `bool`). ## ## Instead of using `map` and `filter`, consider using the `collect` macro - ## from `sugar` module. + ## from the `sugar` module. ## ## See also: ## * `sugar.collect macro`_ @@ -580,7 +580,7 @@ template filterIt*(s, pred: untyped): untyped = ## for testing, like: ``filterIt("abcxyz", it == 'x')``. ## ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro - ## from `sugar` module. + ## from the `sugar` module. ## ## See also: ## * `sugar.collect macro`_ @@ -940,7 +940,7 @@ template mapIt*(s: typed, op: untyped): untyped = ## expression. ## ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro - ## from `sugar` module. + ## from the `sugar` module. ## ## See also: ## * `sugar.collect macro`_ From 28bbcd9d45f15247af347785a46d0c2e2750b8ca Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 30 Oct 2020 16:30:00 +0100 Subject: [PATCH 1364/4254] fix #15702, show enum fields documentation (#15792) --- compiler/semtypes.nim | 3 ++- nimdoc/testproject/expected/testproject.html | 15 +++++++++++++++ nimdoc/testproject/expected/testproject.idx | 4 ++++ nimdoc/testproject/expected/theindex.html | 16 ++++++++++++++++ nimdoc/testproject/testproject.nim | 10 +++++++++- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 97cf7c5ec..21667895a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -133,7 +133,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e.typ = result e.position = int(counter) let symNode = newSymNode(e) - if optNimV1Emulation notin c.config.globalOptions and identToReplace != nil: + if optNimV1Emulation notin c.config.globalOptions and identToReplace != nil and + c.config.cmd != cmdDoc: # A hack to produce documentation for enum fields. identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 103dea25f..d9132d087 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -109,6 +109,11 @@ function main() {
  • Foo
  • +
  • Shapes
  • @@ -406,6 +411,16 @@ The enum B. +
    + +
    Shapes = enum
    +  Circle,                   ## A circle
    +  Triangle,                 ## A three-sided shape
    +  Rectangle                  ## A four-sided shape
    +
    + +Some shapes. +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 0b75b29d2..8d132acc4 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -54,3 +54,7 @@ asyncFun1 testproject.html#asyncFun1 testproject: asyncFun1(): Future[int] asyncFun2 testproject.html#asyncFun2 testproject: asyncFun2(): owned(Future[void]) asyncFun3 testproject.html#asyncFun3 testproject: asyncFun3(): owned(Future[void]) testNimDocTrailingExample testproject.html#testNimDocTrailingExample.t testproject: testNimDocTrailingExample() +Circle testproject.html#Circle Shapes.Circle +Triangle testproject.html#Triangle Shapes.Triangle +Rectangle testproject.html#Rectangle Shapes.Rectangle +Shapes testproject.html#Shapes testproject: Shapes diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 66dea92fc..34d24e900 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -132,6 +132,10 @@ function main() {
  • testproject: C_D
  • +
    Circle:
    c_nonexistant:
    +
    Rectangle:
    +
    Shapes:
    someFunc:
    +
    Triangle:
    tripleStrLitTest:
    • testproject: tripleStrLitTest()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 25cdf39a4..ffddc356f 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -363,4 +363,12 @@ when true: # where runnableExamples would not show if there was not at least 2 "\n" after # the last character of runnableExamples runnableExamples: - discard 2 \ No newline at end of file + discard 2 + +when true: # issue #15702 + type + Shapes* = enum + ## Some shapes. + Circle, ## A circle + Triangle, ## A three-sided shape + Rectangle ## A four-sided shape From bc9a52127092680c662e0456797cbd1278203360 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 31 Oct 2020 10:03:51 +0800 Subject: [PATCH 1365/4254] [closes #12682]add testcase for #12682 (#15796) * add testcase for #12682 * fix --- tests/misc/tlocals.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/misc/tlocals.nim b/tests/misc/tlocals.nim index ad9e7d032..a6df68224 100644 --- a/tests/misc/tlocals.nim +++ b/tests/misc/tlocals.nim @@ -62,3 +62,14 @@ proc foo3[T](y: T) = bar2(y) foo3(12) + +block: # bug #12682 + template foo(): untyped = + var c1 = locals() + 1 + + proc testAll()= + doAssert foo() == 1 + let c2=locals() + + testAll() From 8115b655e77297e3d1ede5889de211a6a4dbad7b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 31 Oct 2020 17:05:01 +0800 Subject: [PATCH 1366/4254] support par expression as checkpoint (#15802) --- lib/pure/unittest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 31eaa657b..0536956e9 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -641,7 +641,7 @@ macro check*(conditions: untyped): untyped = let paramAst = exp[i] if exp[i].kind == nnkIdent: result.printOuts.add getAst(print(argStr, paramAst)) - if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr}: + if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr, nnkPar}: let callVar = newIdentNode(":c" & $counter) result.assigns.add getAst(asgn(callVar, paramAst)) result.check[i] = callVar From 80b0748d75fe70febd89f02cf419e1644f67350d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 31 Oct 2020 19:06:13 +0800 Subject: [PATCH 1367/4254] fix #15651 (#15800) * fix * minor --- compiler/jsgen.nim | 1 + tests/js/treprinifexpr.nim | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/js/treprinifexpr.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 766e6a80d..cd14f1cf9 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1927,6 +1927,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) = genReprAux(p, n, r, "reprJSONStringify") else: genReprAux(p, n, r, "reprAny", genTypeInfo(p, t)) + r.kind = resExpr proc genOf(p: PProc, n: PNode, r: var TCompRes) = var x: TCompRes diff --git a/tests/js/treprinifexpr.nim b/tests/js/treprinifexpr.nim new file mode 100644 index 000000000..09ded18b9 --- /dev/null +++ b/tests/js/treprinifexpr.nim @@ -0,0 +1,18 @@ +type + Enum = enum A + +let + enumVal = A + tmp = if true: $enumVal else: $enumVal + +let + intVal = 12 + tmp2 = if true: repr(intVal) else: $enumVal + +let + strVal = "123" + tmp3 = if true: repr(strVal) else: $strVal + +let + floatVal = 12.4 + tmp4 = if true: repr(floatVal) else: $floatVal \ No newline at end of file From bcb30566fc5bdddcf8eb283efc12d57663717901 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Sat, 31 Oct 2020 16:45:14 +0000 Subject: [PATCH 1368/4254] improve public Testament docs (#15710) * improve glob docs * punctuation * move spec descriptions above example notably, change the description of timeout to reference seconds, not microseconds * document nimout * document sortoutput * explain the action options --- doc/testament.rst | 93 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 20 deletions(-) diff --git a/doc/testament.rst b/doc/testament.rst index e2612711b..b74030183 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -9,12 +9,15 @@ so can be useful to run your tests, even the most complex ones. Test files location =================== -By default Testament looks for test files on ``"./tests/*.nim"``, -you can overwrite this pattern glob using ``pattern ``, -the default working directory path can be changed using ``--directory:"folder/subfolder/"``. +By default Testament looks for test files on ``"./tests/*.nim"``. +You can overwrite this pattern glob using ``pattern ``. +The default working directory path can be changed using +``--directory:"folder/subfolder/"``. -Testament uses the nim compiler on ``PATH`` you can change that using ``--nim:"folder/subfolder/nim"``, -running JavaScript tests with ``--targets:"js"`` requires a working NodeJS on ``PATH``. +Testament uses the ``nim`` compiler on ``PATH``. +You can change that using ``--nim:"folder/subfolder/nim"``. +Running JavaScript tests with ``--targets:"js"`` requires a working NodeJS on +``PATH``. Options @@ -47,8 +50,6 @@ not very useful for production, but easy to understand: $ testament r test0 PASS: tests/test0.nim C ( 0.2 sec) - $ - Running all tests from a directory ================================== @@ -57,6 +58,12 @@ Running all tests from a directory $ testament pattern "tests/*.nim" +To recursively search for all tests in a directory, use + +.. code:: + + $ testament pattern "tests/**/*.nim" + HTML Reports ============ @@ -78,32 +85,78 @@ Example "template" **to edit** and write a Testament unittest: discard """ - action: "run" # What to do, one of "compile" OR "run". + # What actions to expect completion on. + # Options: + # "compile": expect successful compilation + # "run": expect successful compilation and execution + # "reject": expect failed compilation + action: "run" - exitcode: 0 # This is the Exit Code the test should return, zero typically. + # The exit code that the test is expected to return. Typically, the default + # value of 0 is fine. Note that if the test will be run by valgrind, then + # the test will exit with either a code of 0 on success or 1 on failure. + exitcode: 0 - output: "" # This is the Standard Output the test should print, if any. + # Provide an `output` string to assert that the test prints to standard out + # exatly the expected string. Provide an `outputsub` string to assert that + # the string given here is a substring of the standard out output of the + # test. + output: "" + outputsub: "" - input: "" # This is the Standard Input the test should take, if any. + # Whether to sort the output lines before comparing them to the desired + # output. + sortoutput: true - errormsg: "" # Error message the test should print, if any. + # Each line in the stringgiven here appear in the same order in the + # compiler output, but there may be more lines that appear before, after, or + # in between them. + nimout: ''' + a very long, + multi-line + string''' - batchable: true # Can be run in batch mode, or not. + # This is the Standard Input the test should take, if any. + input: "" - joinable: true # Can be run Joined with other tests to run all togheter, or not. + # Error message the test should print, if any. + errormsg: "" + # Can be run in batch mode, or not. + batchable: true + + # Can be run Joined with other tests to run all togheter, or not. + joinable: true + + # On Linux 64-bit machines, whether to use Valgrind to check for bad memory + # accesses or memory leaks. On other architectures, the test will be run + # as-is, without Valgrind. + # Options: + # true: run the test with Valgrind + # false: run the without Valgrind + # "leaks": run the test with Valgrind, but do not check for memory leaks valgrind: false # Can use Valgrind to check for memory leaks, or not (Linux 64Bit only). - cmd: "nim c -r $file" # Command the test should use to run. + # Command the test should use to run. If left out or an empty string is + # provided, the command is taken to be: + # "nim $target --hints:on -d:testing --nimblePath:tests/deps $options $file" + # You can use the $target, $options, and $file placeholders in your own + # command, too. + cmd: "nim c -r $file" - maxcodesize: 666 # Maximum generated temporary intermediate code file size for the test. + # Maximum generated temporary intermediate code file size for the test. + maxcodesize: 666 - timeout: 666 # Timeout microseconds to run the test. + # Timeout seconds to run the test. Fractional values are supported. + timeout: 1.5 - target: "c js" # Targets to run the test into (C, C++, JavaScript, etc). + # Targets to run the test into (C, C++, JavaScript, etc). + target: "c js" - disabled: "bsd" # Disable the test by condition, here BSD is disabled just as an example. - disabled: "win" # Can disable multiple OSes at once + # Conditions that will skip this test. Use of multiple "disabled" clauses + # is permitted. + disabled: "bsd" # Can disable OSes... + disabled: "win" disabled: "32bit" # ...or architectures disabled: "i386" disabled: "azure" # ...or pipeline runners From 1eb4a38a50f6b0d02e7896203dcc14b049348e05 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 31 Oct 2020 17:47:09 +0100 Subject: [PATCH 1369/4254] Typos --- doc/testament.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/testament.rst b/doc/testament.rst index b74030183..18501f4cd 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -108,7 +108,7 @@ Example "template" **to edit** and write a Testament unittest: # output. sortoutput: true - # Each line in the stringgiven here appear in the same order in the + # Each line in the string given here appears in the same order in the # compiler output, but there may be more lines that appear before, after, or # in between them. nimout: ''' From 98cec6b6922da62d9fc304de5c1d7cfb28fca879 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 02:53:00 +0800 Subject: [PATCH 1370/4254] closes #3670 [add testcase for #3670] (#15808) * add testcase * Update tests/template/twhenintemplates.nim Co-authored-by: Clyybber --- tests/template/twhenintemplates.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/template/twhenintemplates.nim diff --git a/tests/template/twhenintemplates.nim b/tests/template/twhenintemplates.nim new file mode 100644 index 000000000..6fded856d --- /dev/null +++ b/tests/template/twhenintemplates.nim @@ -0,0 +1,11 @@ +# bug #3670 + +template someTempl(someConst: bool) = + when someConst: + var a : int + if true: + when not someConst: + var a : int + a = 5 + +someTempl(true) From 27eb19cc48ad76868de921795a0895ddf89aefb3 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 15:56:51 +0800 Subject: [PATCH 1371/4254] fix #15145 (#15816) --- compiler/types.nim | 10 ++++++---- tests/enum/tenum_self.nim | 11 +++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 tests/enum/tenum_self.nim diff --git a/compiler/types.nim b/compiler/types.nim index 7e56f5002..9875f5e1b 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -747,8 +747,9 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = if t.len > 0 and t[0] != nil: result = firstOrd(conf, t[0]) else: - assert(t.n[0].kind == nkSym) - result = toInt128(t.n[0].sym.position) + if t.n.len > 0: + assert(t.n[0].kind == nkSym) + result = toInt128(t.n[0].sym.position) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses, tyLent: result = firstOrd(conf, lastSon(t)) @@ -804,8 +805,9 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = of tyUInt64: result = toInt128(0xFFFFFFFFFFFFFFFF'u64) of tyEnum: - assert(t.n[^1].kind == nkSym) - result = toInt128(t.n[^1].sym.position) + if t.n.len > 0: + assert(t.n[^1].kind == nkSym) + result = toInt128(t.n[^1].sym.position) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses, tyLent: result = lastOrd(conf, lastSon(t)) diff --git a/tests/enum/tenum_self.nim b/tests/enum/tenum_self.nim new file mode 100644 index 000000000..27b1c3204 --- /dev/null +++ b/tests/enum/tenum_self.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "1 can't be converted to ErrorFoo" +""" + + +type + Foo = enum + Bar = 0.Foo + + ErrorFoo = enum + eBar = 1.ErrorFoo From 919593395c7325ffd1cb93fb787c2772da2195f0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 17:22:26 +0800 Subject: [PATCH 1372/4254] fix #15815 (#15817) --- lib/pure/json.nim | 5 ++++- tests/stdlib/toptions.nim | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/toptions.nim diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 9766e32cb..f3145301f 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1120,7 +1120,10 @@ when defined(nimFixedForwardGeneric): proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) = if jsonNode != nil and jsonNode.kind != JNull: - dst = some(default(T)) + when T is ref: + dst = some(new(T)) + else: + dst = some(default(T)) initFromJson(dst.get, jsonNode, jsonPath) macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim new file mode 100644 index 000000000..b982d747d --- /dev/null +++ b/tests/stdlib/toptions.nim @@ -0,0 +1,16 @@ +discard """ + output: '''{"foo":{"test":"123"}}''' +""" + +import json, options + +type + Foo = ref object + test: string + Test = object + foo: Option[Foo] + +let js = """{"foo": {"test": "123"}}""" +let parsed = parseJson(js) +let a = parsed.to(Test) +echo $(%*a) \ No newline at end of file From 558115fa2906abeda11e6fd128ac139e9aac1838 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 17:27:48 +0800 Subject: [PATCH 1373/4254] fixes #15717 --- compiler/vmgen.nim | 2 ++ tests/vm/tnewseqofcap.nim | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/vm/tnewseqofcap.nim diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index f084ab7ba..0c0c491e0 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -683,6 +683,8 @@ proc genNewSeq(c: PCtx; n: PNode) = proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) = let t = n.typ + if dest < 0: + dest = c.getTemp(n.typ) let tmp = c.getTemp(n[1].typ) c.gABx(n, opcLdNull, dest, c.genType(t)) c.gABx(n, opcLdImmInt, tmp, 0) diff --git a/tests/vm/tnewseqofcap.nim b/tests/vm/tnewseqofcap.nim new file mode 100644 index 000000000..c61c3c485 --- /dev/null +++ b/tests/vm/tnewseqofcap.nim @@ -0,0 +1,19 @@ +discard """ + output: '''@["aaa", "bbb", "ccc"]''' +""" + + +const + foo = @["aaa", "bbb", "ccc"] + +proc myTuple: tuple[n: int, bar: seq[string]] = + result.n = 42 + result.bar = newSeqOfCap[string](foo.len) + for f in foo: + result.bar.add(f) + +# It works if you change the below `const` to `let` +const + (n, bar) = myTuple() + +echo bar \ No newline at end of file From 5298366f862861a900c1a3b66d417cd54122a5ec Mon Sep 17 00:00:00 2001 From: Thomas Tay Date: Mon, 2 Nov 2020 01:33:16 -0800 Subject: [PATCH 1374/4254] Update tables documentation (#15807) Added a case where a user might use mgetOrPut and create an accidental copy of a seq. --- lib/pure/collections/tables.nim | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 1d76d42ea..e94e2a00b 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -460,6 +460,13 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. ## + ## + ## Note that while the value returned is of type `var B`, + ## it is easy to accidentally create an copy of the value at `t[key]`. + ## Remember that seqs and strings are value types, and therefore + ## cannot be copied into a separate variable for modification. + ## See the example below. + ## ## See also: ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key ## * `hasKey proc<#hasKey,Table[A,B],A>`_ @@ -474,6 +481,17 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = doAssert a.mgetOrPut('z', 99) == 99 doAssert a == {'a': 5, 'b': 9, 'z': 99}.toTable + # An example of accidentally creating a copy + var t = initTable[int, seq[int]]() + # In this example, we expect t[10] to be modified, + # but it is not. + var copiedSeq = t.mgetOrPut(10, @[10]) + copiedSeq.add(20) + doAssert t[10] == @[10] + # Correct + t.mgetOrPut(25, @[25]).add(35) + doAssert t[25] == @[25, 35] + mgetOrPutImpl(enlarge) proc len*[A, B](t: Table[A, B]): int = @@ -944,6 +962,12 @@ proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = ## Retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. ## + ## Note that while the value returned is of type `var B`, + ## it is easy to accidentally create an copy of the value at `t[key]`. + ## Remember that seqs and strings are value types, and therefore + ## cannot be copied into a separate variable for modification. + ## See the example below. + ## ## See also: ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ @@ -958,6 +982,16 @@ proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = doAssert a.mgetOrPut('z', 99) == 99 doAssert a == {'a': 5, 'b': 9, 'z': 99}.newTable + # An example of accidentally creating a copy + var t = newTable[int, seq[int]]() + # In this example, we expect t[10] to be modified, + # but it is not. + var copiedSeq = t.mgetOrPut(10, @[10]) + copiedSeq.add(20) + doAssert t[10] == @[10] + # Correct + t.mgetOrPut(25, @[25]).add(35) + doAssert t[25] == @[25, 35] t[].mgetOrPut(key, val) proc len*[A, B](t: TableRef[A, B]): int = From 00b495de9520a91fe24d81e55da109960189a966 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 2 Nov 2020 09:35:24 +0000 Subject: [PATCH 1375/4254] Use modern enums in compiler (#15775) --- compiler/ast.nim | 26 ++--- compiler/astalgo.nim | 2 +- compiler/commands.nim | 8 +- compiler/condsyms.nim | 10 +- compiler/docgen.nim | 2 +- compiler/idents.nim | 4 +- compiler/lambdalifting.nim | 2 +- compiler/layouter.nim | 18 +-- compiler/lexer.nim | 103 +++++++---------- compiler/lineinfos.nim | 106 ++++++----------- compiler/linter.nim | 2 +- compiler/main.nim | 4 +- compiler/msgs.nim | 6 +- compiler/parser.nim | 2 +- compiler/pragmas.nim | 14 +-- compiler/renderer.nim | 2 +- compiler/types.nim | 2 +- compiler/wordrecg.nim | 229 ++++++++++++++----------------------- 18 files changed, 212 insertions(+), 330 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index a9793fb21..ca931ab09 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -17,21 +17,17 @@ export int128 type TCallingConvention* = enum - ccNimCall # nimcall, also the default - ccStdCall # procedure is stdcall - ccCDecl # cdecl - ccSafeCall # safecall - ccSysCall # system call - ccInline # proc should be inlined - ccNoInline # proc should not be inlined - ccFastCall # fastcall (pass parameters in registers) - ccThisCall # thiscall (parameters are pushed right-to-left) - ccClosure # proc has a closure - ccNoConvention # needed for generating proper C procs sometimes - -const CallingConvToStr*: array[TCallingConvention, string] = ["nimcall", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", - "closure", "noconv"] + ccNimCall = "nimcall" # nimcall, also the default + ccStdCall = "stdcall" # procedure is stdcall + ccCDecl = "cdecl" # cdecl + ccSafeCall = "safecall" # safecall + ccSysCall = "syscall" # system call + ccInline = "inline" # proc should be inlined + ccNoInline = "noinline" # proc should not be inlined + ccFastCall = "fastcall" # fastcall (pass parameters in registers) + ccThisCall = "thiscall" # thiscall (parameters are pushed right-to-left) + ccClosure = "closure" # proc has a closure + ccNoConvention = "noconv" # needed for generating proper C procs sometimes type TNodeKind* = enum # order is extremely important, because ranges are used diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 6aecb1dcb..d9cd5ade1 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -345,7 +345,7 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int, result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)]) if card(n.flags) > 0: result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) - result.addf("$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])]) + result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)]) result.addf("$N$1\"size\": $2", [istr, rope(n.size)]) result.addf("$N$1\"align\": $2", [istr, rope(n.align)]) result.addf("$N$1\"sons\": $2", [istr, sonsRope]) diff --git a/compiler/commands.nim b/compiler/commands.nim index 325b362a9..a35d1dae7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -193,12 +193,12 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, elif i < arg.len and (arg[i] in {':', '='}): inc(i) else: invalidCmdLineOption(conf, pass, orig, info) if state == wHint: - let x = findStr(lineinfos.HintsToStr, id) - if x >= 0: n = TNoteKind(x + ord(hintMin)) + let x = findStr(hintMin..hintMax, id, errUnknown) + if x != errUnknown: n = TNoteKind(x) else: localError(conf, info, "unknown hint: " & id) else: - let x = findStr(lineinfos.WarningsToStr, id) - if x >= 0: n = TNoteKind(x + ord(warnMin)) + let x = findStr(warnMin..warnMax, id, errUnknown) + if x != errUnknown: n = TNoteKind(x) else: localError(conf, info, "unknown warning: " & id) var val = substr(arg, i).normalize diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 1fbc30bbe..ee849435f 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -13,7 +13,7 @@ import strtabs from options import Feature -from lineinfos import HintsToStr, WarningsToStr +from lineinfos import hintMin, hintMax, warnMin, warnMax proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") = symbols[symbol] = value @@ -89,10 +89,10 @@ proc initDefines*(symbols: StringTableRef) = for f in Feature: defineSymbol("nimHas" & $f) - for s in WarningsToStr: - defineSymbol("nimHasWarning" & s) - for s in HintsToStr: - defineSymbol("nimHasHint" & s) + for s in warnMin..warnMax: + defineSymbol("nimHasWarning" & $s) + for s in hintMin..hintMax: + defineSymbol("nimHasHint" & $s) defineSymbol("nimFixedOwned") defineSymbol("nimHasStyleChecks") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 1d950f835..7609c96ee 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -997,7 +997,7 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id effects[i].typ = real[i].typ result = newTreeI(nkExprColonExpr, n.info, - newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects) + newIdentNode(getIdent(cache, $effectType), n.info), effects) proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode = let s = n[namePos].sym diff --git a/compiler/idents.nim b/compiler/idents.nim index b621503ec..1e8c912d9 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -107,8 +107,8 @@ proc newIdentCache*(): IdentCache = result.idDelegator = result.getIdent":delegator" result.emptyIdent = result.getIdent("") # initialize the keywords: - for s in succ(low(specialWords))..high(specialWords): - result.getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s) + for s in succ(low(TSpecialWord))..high(TSpecialWord): + result.getIdent($s, hashIgnoreStyle($s)).id = ord(s) proc whichKeyword*(id: PIdent): TSpecialWord = if id.id < 0: result = wInvalid diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index b552d9455..95e50d00f 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -295,7 +295,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = [s.name.s, typeToString(s.typ), g.config$s.info]) elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags): localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % - [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) + [s.name.s, owner.name.s, $owner.typ.callConv]) incl(owner.typ.flags, tfCapturesEnv) owner.typ.callConv = ccClosure diff --git a/compiler/layouter.nim b/compiler/layouter.nim index ee45d357f..c603c16ff 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -494,7 +494,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = wrSpace em if not em.inquote: - wr(em, TokTypeToStr[tok.tokType], ltKeyword) + wr(em, $tok.tokType, ltKeyword) if tok.tokType in {tkAnd, tkOr, tkIn, tkNotin}: rememberSplit(splitIn) wrSpace em @@ -503,28 +503,28 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = wr(em, tok.ident.s, ltIdent) of tkColon: - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) wrSpace em of tkSemiColon, tkComma: - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) rememberSplit(splitComma) wrSpace em of openPars: if tok.strongSpaceA > 0 and not em.endsInWhite and (not em.wasExportMarker or tok.tokType == tkCurlyDotLe): wrSpace em - wr(em, TokTypeToStr[tok.tokType], ltSomeParLe) + wr(em, $tok.tokType, ltSomeParLe) rememberSplit(splitParLe) of closedPars: - wr(em, TokTypeToStr[tok.tokType], ltSomeParRi) + wr(em, $tok.tokType, ltSomeParRi) of tkColonColon: - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) of tkDot: lastTokWasTerse = true - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) of tkEquals: if not em.inquote and not em.endsInWhite: wrSpace(em) - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) if not em.inquote: wrSpace(em) of tkOpr, tkDotDot: if em.inquote or ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) and @@ -544,7 +544,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = wrSpace(em) of tkAccent: if not em.inquote and endsInAlpha(em): wrSpace(em) - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) em.inquote = not em.inquote of tkComment: if not preventComment: diff --git a/compiler/lexer.nim b/compiler/lexer.nim index c15ecddfc..e020236b1 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -31,37 +31,44 @@ const type TokType* = enum - tkInvalid, tkEof, # order is important here! - tkSymbol, # keywords: - tkAddr, tkAnd, tkAs, tkAsm, - tkBind, tkBlock, tkBreak, tkCase, tkCast, - tkConcept, tkConst, tkContinue, tkConverter, - tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo, - tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport, - tkFinally, tkFor, tkFrom, tkFunc, - tkIf, tkImport, tkIn, tkInclude, tkInterface, - tkIs, tkIsnot, tkIterator, - tkLet, - tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, - tkObject, tkOf, tkOr, tkOut, - tkProc, tkPtr, tkRaise, tkRef, tkReturn, - tkShl, tkShr, tkStatic, - tkTemplate, - tkTry, tkTuple, tkType, tkUsing, - tkVar, tkWhen, tkWhile, tkXor, - tkYield, # end of keywords - tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, - tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit, - tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit, - tkStrLit, tkRStrLit, tkTripleStrLit, - tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe, - tkBracketRi, tkCurlyLe, tkCurlyRi, - tkBracketDotLe, tkBracketDotRi, # [. and .] - tkCurlyDotLe, tkCurlyDotRi, # {. and .} - tkParDotLe, tkParDotRi, # (. and .) - tkComma, tkSemiColon, - tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon, - tkOpr, tkComment, tkAccent, + tkInvalid = "tkInvalid", tkEof = "[EOF]", # order is important here! + tkSymbol = "tkSymbol", # keywords: + tkAddr = "addr", tkAnd = "and", tkAs = "as", tkAsm = "asm", + tkBind = "bind", tkBlock = "block", tkBreak = "break", tkCase = "case", tkCast = "cast", + tkConcept = "concept", tkConst = "const", tkContinue = "continue", tkConverter = "converter", + tkDefer = "defer", tkDiscard = "discard", tkDistinct = "distinct", tkDiv = "div", tkDo = "do", + tkElif = "elif", tkElse = "else", tkEnd = "end", tkEnum = "enum", tkExcept = "except", tkExport = "export", + tkFinally = "finally", tkFor = "for", tkFrom = "from", tkFunc = "func", + tkIf = "if", tkImport = "import", tkIn = "in", tkInclude = "include", tkInterface = "interface", + tkIs = "is", tkIsnot = "isnot", tkIterator = "iterator", + tkLet = "let", + tkMacro = "macro", tkMethod = "method", tkMixin = "mixin", tkMod = "mod", tkNil = "nil", tkNot = "not", tkNotin = "notin", + tkObject = "object", tkOf = "of", tkOr = "or", tkOut = "out", + tkProc = "proc", tkPtr = "ptr", tkRaise = "raise", tkRef = "ref", tkReturn = "return", + tkShl = "shl", tkShr = "shr", tkStatic = "static", + tkTemplate = "template", + tkTry = "try", tkTuple = "tuple", tkType = "type", tkUsing = "using", + tkVar = "var", tkWhen = "when", tkWhile = "while", tkXor = "xor", + tkYield = "yield", # end of keywords + + tkIntLit = "tkIntLit", tkInt8Lit = "tkInt8Lit", tkInt16Lit = "tkInt16Lit", + tkInt32Lit = "tkInt32Lit", tkInt64Lit = "tkInt64Lit", + tkUIntLit = "tkUIntLit", tkUInt8Lit = "tkUInt8Lit", tkUInt16Lit = "tkUInt16Lit", + tkUInt32Lit = "tkUInt32Lit", tkUInt64Lit = "tkUInt64Lit", + tkFloatLit = "tkFloatLit", tkFloat32Lit = "tkFloat32Lit", + tkFloat64Lit = "tkFloat64Lit", tkFloat128Lit = "tkFloat128Lit", + tkStrLit = "tkStrLit", tkRStrLit = "tkRStrLit", tkTripleStrLit = "tkTripleStrLit", + tkGStrLit = "tkGStrLit", tkGTripleStrLit = "tkGTripleStrLit", tkCharLit = "tkCharLit", + + tkParLe = "(", tkParRi = ")", tkBracketLe = "[", + tkBracketRi = "]", tkCurlyLe = "{", tkCurlyRi = "}", + tkBracketDotLe = "[.", tkBracketDotRi = ".]", + tkCurlyDotLe = "{.", tkCurlyDotRi = ".}", + tkParDotLe = "(.", tkParDotRi = ".)", + tkComma = ",", tkSemiColon = ";", + tkColon = ":", tkColonColon = "::", tkEquals = "=", + tkDot = ".", tkDotDot = "..", tkBracketLeColon = "[:", + tkOpr, tkComment, tkAccent = "`", # these are fake tokens used by renderer.nim tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr @@ -74,35 +81,6 @@ const # tokens that should not be considered for previousToken tokKeywordLow* = succ(tkSymbol) tokKeywordHigh* = pred(tkIntLit) - TokTypeToStr*: array[TokType, string] = ["tkInvalid", "[EOF]", - "tkSymbol", - "addr", "and", "as", "asm", - "bind", "block", "break", "case", "cast", - "concept", "const", "continue", "converter", - "defer", "discard", "distinct", "div", "do", - "elif", "else", "end", "enum", "except", "export", - "finally", "for", "from", "func", "if", - "import", "in", "include", "interface", "is", "isnot", "iterator", - "let", - "macro", "method", "mixin", "mod", - "nil", "not", "notin", "object", "of", "or", - "out", "proc", "ptr", "raise", "ref", "return", - "shl", "shr", "static", - "template", - "try", "tuple", "type", "using", - "var", "when", "while", "xor", - "yield", - "tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit", - "tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit", - "tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkFloat128Lit", - "tkStrLit", "tkRStrLit", - "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(", - ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)", - ",", ";", - ":", "::", "=", ".", "..", "[:", - "tkOpr", "tkComment", "`", - "tkSpaces", "tkInfixOpr", - "tkPrefixOpr", "tkPostfixOpr"] type NumericalBase* = enum @@ -171,7 +149,7 @@ proc `$`*(tok: Token): string = of tkIntLit..tkInt64Lit: $tok.iNumber of tkFloatLit..tkFloat64Lit: $tok.fNumber of tkInvalid, tkStrLit..tkCharLit, tkComment: tok.literal - of tkParLe..tkColon, tkEof, tkAccent: TokTypeToStr[tok.tokType] + of tkParLe..tkColon, tkEof, tkAccent: $tok.tokType else: if tok.ident != nil: tok.ident.s @@ -183,8 +161,7 @@ proc prettyTok*(tok: Token): string = else: $tok proc printTok*(conf: ConfigRef; tok: Token) = - msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & - TokTypeToStr[tok.tokType] & " " & $tok) + msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok) proc initToken*(L: var Token) = L.tokType = tkInvalid diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 4a7c09276..759002312 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -36,40 +36,40 @@ type errProveInit, # deadcode errGenerated, errUser, - warnCannotOpenFile, - warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, - warnDeprecated, warnConfigDeprecated, - warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, - warnUnknownSubstitutionX, warnLanguageXNotSupported, - warnFieldXNotSupported, warnCommentXIgnored, - warnTypelessParam, - warnUseBase, warnWriteToForeignHeap, warnUnsafeCode, - warnUnusedImportX, - warnInheritFromException, - warnEachIdentIsTuple, - warnUnsafeSetLen, - warnUnsafeDefault, - warnProveInit, warnProveField, warnProveIndex, - warnUnreachableElse, warnUnreachableCode, - warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2, - warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, - warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, - warnObservableStores, - warnUser, - hintSuccess, hintSuccessX, hintCC, - hintLineTooLong, hintXDeclaredButNotUsed, - hintXCannotRaiseY, - hintConvToBaseNotNeeded, - hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, - hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, - hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern, - hintExecuting, hintLinking, hintDependency, - hintSource, hintPerformance, hintStackTrace, hintGCStats, - hintGlobalVar, hintExpandMacro, - hintUser, hintUserRaw, - hintExtendedContext, - hintMsgOrigin, # since 1.3.5 - hintDeclaredLoc, # since 1.5.1 + + warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", + warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit", + warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated", + warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", + warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX", + warnLanguageXNotSupported = "LanguageXNotSupported", warnFieldXNotSupported = "FieldXNotSupported", + warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam", + warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap", + warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport", + warnInheritFromException = "InheritFromException", warnEachIdentIsTuple = "EachIdentIsTuple", + warnUnsafeSetLen = "UnsafeSetLen", warnUnsafeDefault = "UnsafeDefault", + warnProveInit = "ProveInit", warnProveField = "ProveField", warnProveIndex = "ProveIndex", + warnUnreachableElse = "UnreachableElse", warnUnreachableCode = "UnreachableCode", + warnStaticIndexCheck = "IndexCheck", warnGcUnsafe = "GcUnsafe", warnGcUnsafe2 = "GcUnsafe2", + warnUninit = "Uninit", warnGcMem = "GcMem", warnDestructor = "Destructor", + warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed", + warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition", + warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores", + warnUser = "User", + + hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", + hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", + hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", + hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", + hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintCodeBegin = "CodeBegin", + hintCodeEnd = "CodeEnd", hintConf = "Conf", hintPath = "Path", + hintConditionAlwaysTrue = "CondTrue", hintConditionAlwaysFalse = "CondFalse", hintName = "Name", + hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency", + hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace", + hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro", + hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext", + hintMsgOrigin = "MsgOrigin", # since 1.3.5 + hintDeclaredLoc = "DeclaredLoc", # since 1.5.1 const MsgKindToStr*: array[TMsgKind, string] = [ @@ -163,34 +163,6 @@ const hintDeclaredLoc: "$1", ] -const - WarningsToStr* = ["CannotOpenFile", "OctalEscape", - "XIsNeverRead", "XmightNotBeenInit", - "Deprecated", "ConfigDeprecated", - "SmallLshouldNotBeUsed", "UnknownMagic", - "RedefinitionOfLabel", "UnknownSubstitutionX", - "LanguageXNotSupported", "FieldXNotSupported", - "CommentXIgnored", - "TypelessParam", "UseBase", "WriteToForeignHeap", - "UnsafeCode", "UnusedImport", "InheritFromException", - "EachIdentIsTuple", - "UnsafeSetLen", "UnsafeDefault", - "ProveInit", "ProveField", "ProveIndex", "UnreachableElse", "UnreachableCode", - "IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit", - "GcMem", "Destructor", "LockLevel", "ResultShadowed", - "Spacing", "CaseTransition", "CycleCreated", - "ObservableStores", "User"] - - HintsToStr* = [ - "Success", "SuccessX", "CC", "LineTooLong", - "XDeclaredButNotUsed", "XCannotRaiseY", - "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", - "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", - "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency", - "Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro", - "User", "UserRaw", "ExtendedContext", "MsgOrigin", "DeclaredLoc" - ] - const fatalMin* = errUnknown fatalMax* = errInternal @@ -201,16 +173,6 @@ const hintMin* = hintSuccess hintMax* = high(TMsgKind) -proc msgToStr*(msg: TMsgKind): string = - case msg - of warnMin..warnMax: WarningsToStr[ord(msg) - ord(warnMin)] - of hintMin..hintMax: HintsToStr[ord(msg) - ord(hintMin)] - else: "" # we could at least do $msg - prefix `err` - -static: - doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1 - doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1 - type TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints TNoteKinds* = set[TNoteKind] diff --git a/compiler/linter.nim b/compiler/linter.nim index a229958e6..77e0a84e4 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -128,6 +128,6 @@ proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) = lintReport(conf, info, newName, oldName) proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = - let wanted = specialWords[w] + let wanted = $w if pragmaName != wanted: lintReport(conf, info, wanted, pragmaName) diff --git a/compiler/main.nim b/compiler/main.nim index 210933231..af9102414 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -303,10 +303,10 @@ proc mainCommand*(graph: ModuleGraph) = var hints = newJObject() # consider factoring with `listHints` for a in hintMin..hintMax: - hints[a.msgToStr] = %(a in conf.notes) + hints[$a] = %(a in conf.notes) var warnings = newJObject() for a in warnMin..warnMax: - warnings[a.msgToStr] = %(a in conf.notes) + warnings[$a] = %(a in conf.notes) var dumpdata = %[ (key: "version", val: %VersionAsString), diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 7e2b8e8a6..0f5879ff6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -489,7 +489,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, color: ForegroundColor ignoreMsg = false sev: Severity - let kind = if msg != hintUserRaw: msg.msgToStr else: "" # xxx not sure why hintUserRaw is special + let kind = if msg in warnMin..hintMax and msg != hintUserRaw: $msg else: "" # xxx not sure why hintUserRaw is special case msg of errMin..errMax: sev = Severity.Error @@ -536,7 +536,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, if hintMsgOrigin in conf.mainPackageNotes: styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, - KindFormat % hintMsgOrigin.msgToStr, + KindFormat % $hintMsgOrigin, resetStyle) handleError(conf, msg, eh, s) @@ -612,7 +612,7 @@ proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = template listMsg(title, r) = msgWriteln(conf, title) - for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", a.msgToStr]) + for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", $a]) proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax) proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax) diff --git a/compiler/parser.nim b/compiler/parser.nim index e3cf54b38..01ec6fe95 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -219,7 +219,7 @@ proc eat(p: var Parser, tokType: TokType) = getTok(p) else: lexMessage(p.lex, errGenerated, - "expected: '" & TokTypeToStr[tokType] & "', but got: '" & prettyTok(p.tok) & "'") + "expected: '" & $tokType & "', but got: '" & prettyTok(p.tok) & "'") proc parLineInfo(p: Parser): TLineInfo = ## Retrieve the line information associated with the parser's current state. diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 273b2b004..c1d54c4a2 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -330,10 +330,10 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = - template handleNote(toStrArray, msgMin, notes) = - let x = findStr(toStrArray, n[0][1].ident.s) - if x >= 0: - nk = TNoteKind(x + ord(msgMin)) + template handleNote(enumVals, notes) = + let x = findStr(enumVals, n[0][1].ident.s, errUnknown) + if x != errUnknown: + nk = TNoteKind(x) let x = c.semConstBoolExpr(c, n[1]) n[1] = x if x.kind == nkIntLit and x.intVal != 0: incl(notes, nk) @@ -347,9 +347,9 @@ proc processNote(c: PContext, n: PNode) = n[0][1].kind == nkIdent and n[0][0].kind == nkIdent: var nk: TNoteKind case whichKeyword(n[0][0].ident) - of wHint: handleNote(HintsToStr, hintMin, c.config.notes) - of wWarning: handleNote(WarningsToStr, warnMin, c.config.notes) - of wWarningAsError: handleNote(WarningsToStr, warnMin, c.config.warningAsErrors) + of wHint: handleNote(hintMin .. hintMax, c.config.notes) + of wWarning: handleNote(warnMin .. warnMax, c.config.notes) + of wWarningAsError: handleNote(warnMin .. warnMax, c.config.warningAsErrors) else: invalidPragma(c, n) else: invalidPragma(c, n) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index b897aff5d..a4152cf29 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -597,7 +597,7 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, gsub(g, n[i]) if c: if g.tokens.len > oldLen: - putWithSpace(g, separator, TokTypeToStr[separator]) + putWithSpace(g, separator, $separator) if hasCom(n[i]): gcoms(g) optNL(g, ind) diff --git a/compiler/types.nim b/compiler/types.nim index 9875f5e1b..42b7de416 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -700,7 +700,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < t.len - 1: result.add(", ") result.add(')') if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0])) - var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: CallingConvToStr[t.callConv] + var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv if tfNoSideEffect in t.flags: addSep(prag) prag.add("noSideEffect") diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index f6fc92dc8..e2e3a1d2f 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -15,78 +15,99 @@ from strutils import cmpIgnoreStyle -# Keywords must be kept sorted and within a range - type TSpecialWord* = enum - wInvalid, + wInvalid = "", + wAddr = "addr", wAnd = "and", wAs = "as", wAsm = "asm", + wBind = "bind", wBlock = "block", wBreak = "break", wCase = "case", wCast = "cast", + wConcept = "concept", wConst = "const", wContinue = "continue", wConverter = "converter", + wDefer = "defer", wDiscard = "discard", wDistinct = "distinct", wDiv = "div", wDo = "do", + wElif = "elif", wElse = "else", wEnd = "end", wEnum = "enum", wExcept = "except", + wExport = "export", wFinally = "finally", wFor = "for", wFrom = "from", wFunc = "func", + wIf = "if", wImport = "import", wIn = "in", wInclude = "include", wInterface = "interface", + wIs = "is", wIsnot = "isnot", wIterator = "iterator", wLet = "let", wMacro = "macro", + wMethod = "method", wMixin = "mixin", wMod = "mod", wNil = "nil", wNot = "not", wNotin = "notin", + wObject = "object", wOf = "of", wOr = "or", wOut = "out", wProc = "proc", wPtr = "ptr", + wRaise = "raise", wRef = "ref", wReturn = "return", wShl = "shl", wShr = "shr", wStatic = "static", + wTemplate = "template", wTry = "try", wTuple = "tuple", wType = "type", wUsing = "using", + wVar = "var", wWhen = "when", wWhile = "while", wXor = "xor", wYield = "yield", - wAddr, wAnd, wAs, wAsm, - wBind, wBlock, wBreak, wCase, wCast, wConcept, wConst, - wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo, - wElif, wElse, wEnd, wEnum, wExcept, wExport, - wFinally, wFor, wFrom, wFunc, wIf, wImport, wIn, - wInclude, wInterface, wIs, wIsnot, wIterator, wLet, - wMacro, wMethod, wMixin, wMod, wNil, - wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, - wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar, - wWhen, wWhile, wXor, wYield, + wColon = ":", wColonColon = "::", wEquals = "=", wDot = ".", wDotDot = "..", + wStar = "*", wMinus = "-", + wMagic = "magic", wThread = "thread", wFinal = "final", wProfiler = "profiler", + wMemTracker = "memtracker", wObjChecks = "objchecks", + wIntDefine = "intdefine", wStrDefine = "strdefine", wBoolDefine = "booldefine", + wCursor = "cursor", wNoalias = "noalias", - wColon, wColonColon, wEquals, wDot, wDotDot, - wStar, wMinus, - wMagic, wThread, wFinal, wProfiler, wMemTracker, wObjChecks, - wIntDefine, wStrDefine, wBoolDefine, wCursor, wNoalias, + wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor", + wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp", + wImportObjC = "importobjc", wImportCompilerProc = "importcompilerproc", + wImportc = "importc", wImportJs = "importjs", wExportc = "exportc", wExportCpp = "exportcpp", + wExportNims = "exportnims", + wIncompleteStruct = "incompleteStruct", # deprecated + wCompleteStruct = "completeStruct", wRequiresInit = "requiresInit", wAlign = "align", + wNodecl = "nodecl", wPure = "pure", wSideEffect = "sideEffect", wHeader = "header", + wNoSideEffect = "noSideEffect", wGcSafe = "gcsafe", wNoreturn = "noreturn", + wNosinks = "nosinks", wMerge = "merge", wLib = "lib", wDynlib = "dynlib", + wCompilerProc = "compilerproc", wCore = "core", wProcVar = "procvar", + wBase = "base", wUsed = "used", wFatal = "fatal", wError = "error", wWarning = "warning", + wHint = "hint", wWarningAsError = "warningAsError", wLine = "line", wPush = "push", + wPop = "pop", wDefine = "define", wUndef = "undef", wLineDir = "lineDir", + wStackTrace = "stackTrace", wLineTrace = "lineTrace", wLink = "link", wCompile = "compile", + wLinksys = "linksys", wDeprecated = "deprecated", wVarargs = "varargs", wCallconv = "callconv", + wDebugger = "debugger", wNimcall = "nimcall", wStdcall = "stdcall", wCdecl = "cdecl", + wSafecall = "safecall", wSyscall = "syscall", wInline = "inline", wNoInline = "noinline", + wFastcall = "fastcall", wThiscall = "thiscall", wClosure = "closure", wNoconv = "noconv", + wOn = "on", wOff = "off", wChecks = "checks", wRangeChecks = "rangeChecks", + wBoundChecks = "boundChecks", wOverflowChecks = "overflowChecks", wNilChecks = "nilChecks", + wFloatChecks = "floatChecks", wNanChecks = "nanChecks", wInfChecks = "infChecks", + wStyleChecks = "styleChecks", wStaticBoundchecks = "staticBoundChecks", + wNonReloadable = "nonReloadable", wExecuteOnReload = "executeOnReload", - wImmediate, wConstructor, wDestructor, wDelegator, wOverride, - wImportCpp, wImportObjC, - wImportCompilerProc, - wImportc, wImportJs, wExportc, wExportCpp, wExportNims, - wIncompleteStruct, # deprecated - wCompleteStruct, - wRequiresInit, - wAlign, wNodecl, wPure, wSideEffect, wHeader, - wNoSideEffect, wGcSafe, wNoreturn, wNosinks, wMerge, wLib, wDynlib, - wCompilerProc, wCore, wProcVar, wBase, wUsed, - wFatal, wError, wWarning, wHint, wWarningAsError, wLine, wPush, wPop, wDefine, wUndef, - wLineDir, wStackTrace, wLineTrace, wLink, wCompile, - wLinksys, wDeprecated, wVarargs, wCallconv, wDebugger, - wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, - wFastcall, wThiscall, wClosure, wNoconv, wOn, wOff, wChecks, wRangeChecks, - wBoundChecks, wOverflowChecks, wNilChecks, - wFloatChecks, wNanChecks, wInfChecks, wStyleChecks, wStaticBoundchecks, - wNonReloadable, wExecuteOnReload, - wAssertions, wPatterns, wTrMacros, wSinkInference, wWarnings, - wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, - wRequires, wEnsures, wInvariant, wAssume, wAssert, - wDeadCodeElimUnused, # deprecated, dead code elim always happens - wSafecode, wPackage, wNoForward, wReorder, wNoRewrite, wNoDestroy, - wPragma, - wCompileTime, wNoInit, - wPassc, wPassl, wLocalPassc, wBorrow, wDiscardable, - wFieldChecks, - wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, - wInjectStmt, wExperimental, - wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, - wAsmNoStackFrame, - wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks, - wPartial, wExplain, wLiftLocals, + wAssertions = "assertions", wPatterns = "patterns", wTrMacros = "trmacros", + wSinkInference = "sinkInference", wWarnings = "warnings", + wHints = "hints", wOptimization = "optimization", wRaises = "raises", + wWrites = "writes", wReads = "reads", wSize = "size", wEffects = "effects", wTags = "tags", + wRequires = "requires", wEnsures = "ensures", wInvariant = "invariant", + wAssume = "assume", wAssert = "assert", + wDeadCodeElimUnused = "deadCodeElim", # deprecated, dead code elim always happens + wSafecode = "safecode", wPackage = "package", wNoForward = "noforward", wReorder = "reorder", + wNoRewrite = "norewrite", wNoDestroy = "nodestroy", wPragma = "pragma", + wCompileTime = "compileTime", wNoInit = "noinit", wPassc = "passc", wPassl = "passl", + wLocalPassc = "localPassC", wBorrow = "borrow", wDiscardable = "discardable", + wFieldChecks = "fieldChecks", wSubsChar = "subschar", wAcyclic = "acyclic", + wShallow = "shallow", wUnroll = "unroll", wLinearScanEnd = "linearScanEnd", + wComputedGoto = "computedGoto", wInjectStmt = "injectStmt", wExperimental = "experimental", + wWrite = "write", wGensym = "gensym", wInject = "inject", wDirty = "dirty", + wInheritable = "inheritable", wThreadVar = "threadvar", wEmit = "emit", + wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic", + wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked", + wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain", + wLiftLocals = "liftlocals", - wAuto, wBool, wCatch, wChar, wClass, wCompl - wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, - wExplicit, wExtern, wFalse, wFloat, wFriend, - wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator, - wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, wRestrict, - wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch, - wThis, wThrow, wTrue, wTypedef, wTypeid, wTypeof, wTypename, - wUnion, wPacked, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t, + wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", + wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default", + wDelete = "delete", wDouble = "double", wDynamic_cast = "dynamic_cast", + wExplicit = "explicit", wExtern = "extern", wFalse = "false", wFloat = "float", + wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable", + wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private", + wProtected = "protected", wPublic = "public", wRegister = "register", + wReinterpret_cast = "reinterpret_cast", wRestrict = "restrict", wShort = "short", + wSigned = "signed", wSizeof = "sizeof", wStatic_cast = "static_cast", wStruct = "struct", + wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef", + wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename", + wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual", + wVoid = "void", wVolatile = "volatile", wWchar_t = "wchar_t", - wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept, - wThread_local, wStatic_assert, wChar16_t, wChar32_t, + wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype", + wNullptr = "nullptr", wNoexcept = "noexcept", + wThread_local = "thread_local", wStatic_assert = "static_assert", + wChar16_t = "char16_t", wChar32_t = "char32_t", - wStdIn, wStdOut, wStdErr, + wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr", - wInOut, wByCopy, wByRef, wOneWay, - wBitsize + wInOut = "inout", wByCopy = "bycopy", wByRef = "byref", wOneWay = "oneway", + wBitsize = "bitsize" TSpecialWords* = set[TSpecialWord] @@ -104,82 +125,8 @@ const wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing} - specialWords*: array[TSpecialWord, string] = ["", - "addr", "and", "as", "asm", - "bind", "block", "break", "case", "cast", - "concept", "const", "continue", "converter", - "defer", "discard", "distinct", "div", "do", - "elif", "else", "end", "enum", "except", "export", - "finally", "for", "from", "func", "if", - "import", "in", "include", "interface", "is", "isnot", "iterator", - "let", - "macro", "method", "mixin", "mod", "nil", "not", "notin", - "object", "of", "or", - "out", "proc", "ptr", "raise", "ref", "return", - "shl", "shr", "static", - "template", "try", "tuple", "type", "using", "var", - "when", "while", "xor", - "yield", - - ":", "::", "=", ".", "..", - "*", "-", - "magic", "thread", "final", "profiler", "memtracker", "objchecks", - "intdefine", "strdefine", "booldefine", "cursor", "noalias", - - "immediate", "constructor", "destructor", "delegator", "override", - "importcpp", "importobjc", - "importCompilerProc", "importc", "importjs", "exportc", "exportcpp", "exportnims", - "incompleteStruct", - "completeStruct", - "requiresInit", "align", "nodecl", "pure", "sideEffect", - "header", "noSideEffect", "gcsafe", "noreturn", "nosinks", "merge", "lib", "dynlib", - "compilerproc", "core", "procvar", "base", "used", - "fatal", "error", "warning", "hint", "warningAsError", "line", - "push", "pop", "define", "undef", "lineDir", "stackTrace", "lineTrace", - "link", "compile", "linksys", "deprecated", "varargs", - "callconv", "debugger", "nimcall", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall", "closure", - "noconv", "on", "off", "checks", "rangeChecks", "boundChecks", - "overflowChecks", "nilChecks", - "floatChecks", "nanChecks", "infChecks", "styleChecks", "staticBoundChecks", - "nonReloadable", "executeOnReload", - - "assertions", "patterns", "trmacros", "sinkinference", "warnings", "hints", - "optimization", "raises", "writes", "reads", "size", "effects", "tags", - "requires", "ensures", "invariant", "assume", "assert", - "deadCodeElim", # deprecated, dead code elim always happens - "safecode", "package", "noforward", "reorder", "norewrite", "nodestroy", - "pragma", - "compileTime", "noinit", - "passc", "passl", "localPassC", "borrow", "discardable", "fieldChecks", - "subschar", "acyclic", "shallow", "unroll", "linearScanEnd", - "computedGoto", "injectStmt", "experimental", - "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", - "asmNoStackFrame", "implicitStatic", "global", "codegenDecl", "unchecked", - "guard", "locks", "partial", "explain", "liftLocals", - - "auto", "bool", "catch", "char", "class", "compl", - "const_cast", "default", "delete", "double", - "dynamic_cast", "explicit", "extern", "false", - "float", "friend", "goto", "int", "long", "mutable", - "namespace", "new", "operator", - "private", "protected", "public", "register", "reinterpret_cast", "restrict", - "short", "signed", "sizeof", "static_cast", "struct", "switch", - "this", "throw", "true", "typedef", "typeid", "typeof", - "typename", "union", "packed", "unsigned", "virtual", "void", "volatile", - "wchar_t", - - "alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept", - "thread_local", "static_assert", "char16_t", "char32_t", - - "stdin", "stdout", "stderr", - - "inout", "bycopy", "byref", "oneway", - "bitsize" - ] - -proc findStr*(a: openArray[string], s: string): int = - for i in low(a)..high(a): - if cmpIgnoreStyle(a[i], s) == 0: +proc findStr*[T:enum](a: Slice[T], s: string, default: T): T = + for i in a: + if cmpIgnoreStyle($i, s) == 0: return i - result = - 1 + result = default \ No newline at end of file From 544cb107c75523196ceee9408f9b1d5d89c82e48 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 17:41:44 +0800 Subject: [PATCH 1376/4254] fix #8821 (#15809) --- compiler/jsgen.nim | 5 +++++ tests/js/t8821.nim | 12 ++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/js/t8821.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index cd14f1cf9..10c072253 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -865,6 +865,7 @@ proc genRaiseStmt(p: PProc, n: PNode) = proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = var cond, stmt: TCompRes + totalRange = 0 genLineDir(p, n) gen(p, n[0], cond) let stringSwitch = skipTypes(n[0].typ, abstractVar).kind == tyString @@ -884,6 +885,10 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = let e = it[j] if e.kind == nkRange: var v = copyNode(e[0]) + inc(totalRange, int(e[1].intVal - v.intVal)) + if totalRange > 65535: + localError(p.config, n.info, + "Your case statement contains too many branches, consider using if/else instead!") while v.intVal <= e[1].intVal: gen(p, v, cond) lineF(p, "case $1:$n", [cond.rdLoc]) diff --git a/tests/js/t8821.nim b/tests/js/t8821.nim new file mode 100644 index 000000000..43cf3f6f2 --- /dev/null +++ b/tests/js/t8821.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "Your case statement contains too many branches, consider using if/else instead!" +""" + +proc isInt32(i: int): bool = + case i + of 1 .. 70000: + return true + else: + return false + +discard isInt32(1) \ No newline at end of file From 5b4c17b5e7166220c7b5c149946579f245f54645 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 17:58:14 +0800 Subject: [PATCH 1377/4254] Closure iterators are not supported by VM (#15818) --- compiler/vmgen.nim | 2 ++ tests/vm/tclosureiterator.nim | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/vm/tclosureiterator.nim diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 0c0c491e0..61c7fefd9 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1982,6 +1982,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = genRdVar(c, n, dest, flags) of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator: # 'skTemplate' is only allowed for 'getAst' support: + if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure: + globalError(c.config, n.info, "Closure iterators are not supported by VM!") if procIsCallback(c, s): discard elif importcCond(s): c.importcSym(n.info, s) genLit(c, n, dest) diff --git a/tests/vm/tclosureiterator.nim b/tests/vm/tclosureiterator.nim new file mode 100644 index 000000000..c909392d5 --- /dev/null +++ b/tests/vm/tclosureiterator.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "Closure iterators are not supported by VM!" +""" + +iterator iter*(): int {.closure.} = + yield 3 + +static: + var x = iter From 4fe56b56ce2b856ff8fae9051cceb766ab7729e0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 20:01:19 +0800 Subject: [PATCH 1378/4254] more clear (#15812) --- lib/pure/asynchttpserver.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index afd452b01..ec7f2a0de 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -11,8 +11,8 @@ ## ## This HTTP server has not been designed to be used in production, but ## for testing applications locally. Because of this, when deploying your -## application you should use a reverse proxy (for example nginx) instead of -## allowing users to connect directly to this server. +## application in production you should use a reverse proxy (for example nginx) +## instead of allowing users to connect directly to this server. ## ## Basic usage ## =========== From 6fa82a5b3afbe644eef3fb41647a341d8e9b21c4 Mon Sep 17 00:00:00 2001 From: Regis Caillaud <35006197+Clonkk@users.noreply.github.com> Date: Mon, 2 Nov 2020 13:02:55 +0100 Subject: [PATCH 1379/4254] Handle BLOB column type in SQLite as binary data (#15681) * Fixed not handling blob correctly in sqlite * Fixed setLen commented by mistake * Added binary example as db_sqlite doc * Added tests for sqlite binary data --- lib/impure/db_sqlite.nim | 93 ++++++++++++++++++++++++++------ tests/stdlib/tsqlitebindatas.nim | 50 +++++++++++++++++ 2 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 tests/stdlib/tsqlitebindatas.nim diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 80eee59fb..ce57996be 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -94,6 +94,57 @@ ## ## db.close() ## +## Storing binary data example +##---------------------------- +## +## .. code-block:: nim +## +## import random +## +## ## Generate random float datas +## var orig = newSeq[float64](150) +## randomize() +## for x in orig.mitems: +## x = rand(1.0)/10.0 +## +## let db = open("mysqlite.db", "", "", "") +## block: ## Create database +## ## Binary datas needs to be of type BLOB in SQLite +## let createTableStr = sql"""CREATE TABLE test( +## id INTEGER NOT NULL PRIMARY KEY, +## data BLOB +## ) +## """ +## db.exec(createTableStr) +## +## block: ## Insert data +## var id = 1 +## ## Data needs to be converted to seq[byte] to be interpreted as binary by bindParams +## var dbuf = newSeq[byte](orig.len*sizeof(float64)) +## copyMem(unsafeAddr(dbuf[0]), unsafeAddr(orig[0]), dbuf.len) +## +## ## Use prepared statement to insert binary data into database +## var insertStmt = db.prepare("INSERT INTO test (id, data) VALUES (?, ?)") +## insertStmt.bindParams(id, dbuf) +## let bres = db.tryExec(insertStmt) +## ## Check insert +## doAssert(bres) +## # Destroy statement +## finalize(insertStmt) +## +## block: ## Use getValue to select data +## var dataTest = db.getValue(sql"SELECT data FROM test WHERE id = ?", 1) +## ## Calculate sequence size from buffer size +## let seqSize = int(dataTest.len*sizeof(byte)/sizeof(float64)) +## ## Copy binary string data in dataTest into a seq +## var res: seq[float64] = newSeq[float64](seqSize) +## copyMem(unsafeAddr(res[0]), addr(dataTest[0]), dataTest.len) +## +## ## Check datas obtained is identical +## doAssert res == orig +## +## db.close() +## ## ## Note ## ==== @@ -242,10 +293,14 @@ proc setupQuery(db: DbConn, stmtName: SqlPrepared): SqlPrepared {.since: (1, 3). proc setRow(stmt: PStmt, r: var Row, cols: cint) = for col in 0'i32..cols-1: - setLen(r[col], column_bytes(stmt, col)) # set capacity - setLen(r[col], 0) - let x = column_text(stmt, col) - if not isNil(x): add(r[col], x) + let cb = column_bytes(stmt, col) + setLen(r[col], cb) # set capacity + if column_type(stmt, col) == SQLITE_BLOB: + copyMem(addr(r[col][0]), column_blob(stmt, col), cb) + else: + setLen(r[col], 0) + let x = column_text(stmt, col) + if not isNil(x): add(r[col], x) iterator fastRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = @@ -288,7 +343,7 @@ iterator fastRows*(db: DbConn, query: SqlQuery, finally: if finalize(stmt) != SQLITE_OK: dbError(db) -iterator fastRows*(db: DbConn, stmtName: SqlPrepared): Row +iterator fastRows*(db: DbConn, stmtName: SqlPrepared): Row {.tags: [ReadDbEffect,WriteDbEffect], since: (1, 3).} = discard setupQuery(db, stmtName) var L = (column_count(stmtName.PStmt)) @@ -491,7 +546,7 @@ proc getAllRows*(db: DbConn, query: SqlQuery, for r in fastRows(db, query, args): result.add(r) -proc getAllRows*(db: DbConn, stmtName: SqlPrepared): seq[Row] +proc getAllRows*(db: DbConn, stmtName: SqlPrepared): seq[Row] {.tags: [ReadDbEffect,WriteDbEffect], since: (1, 3).} = result = @[] for r in fastRows(db, stmtName): @@ -524,7 +579,7 @@ iterator rows*(db: DbConn, query: SqlQuery, ## db.close() for r in fastRows(db, query, args): yield r -iterator rows*(db: DbConn, stmtName: SqlPrepared): Row +iterator rows*(db: DbConn, stmtName: SqlPrepared): Row {.tags: [ReadDbEffect,WriteDbEffect], since: (1, 3).} = for r in fastRows(db, stmtName): yield r @@ -558,13 +613,17 @@ proc getValue*(db: DbConn, query: SqlQuery, if cb == 0: result = "" else: - result = newStringOfCap(cb) - add(result, column_text(stmt, 0)) + if column_type(stmt, 0) == SQLITE_BLOB: + result.setLen(cb) + copyMem(addr(result[0]), column_blob(stmt, 0), cb) + else: + result = newStringOfCap(cb) + add(result, column_text(stmt, 0)) else: result = "" if finalize(stmt) != SQLITE_OK: dbError(db) -proc getValue*(db: DbConn, stmtName: SqlPrepared): string +proc getValue*(db: DbConn, stmtName: SqlPrepared): string {.tags: [ReadDbEffect,WriteDbEffect], since: (1, 3).} = var stmt = setupQuery(db, stmtName).PStmt if step(stmt) == SQLITE_ROW: @@ -572,8 +631,12 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared): string if cb == 0: result = "" else: - result = newStringOfCap(cb) - add(result, column_text(stmt, 0)) + if column_type(stmt, 0) == SQLITE_BLOB: + result.setLen(cb) + copyMem(addr(result[0]), column_blob(stmt, 0), cb) + else: + result = newStringOfCap(cb) + add(result, column_text(stmt, 0)) else: result = "" @@ -671,7 +734,7 @@ proc execAffectedRows*(db: DbConn, query: SqlQuery, exec(db, query, args) result = changes(db) -proc execAffectedRows*(db: DbConn, stmtName: SqlPrepared): int64 +proc execAffectedRows*(db: DbConn, stmtName: SqlPrepared): int64 {.tags: [ReadDbEffect, WriteDbEffect],since: (1, 3).} = exec(db, stmtName) result = changes(db) @@ -723,7 +786,7 @@ proc setEncoding*(connection: DbConn, encoding: string): bool {. exec(connection, sql"PRAGMA encoding = ?", [encoding]) result = connection.getValue(sql"PRAGMA encoding") == encoding -proc finalize*(sqlPrepared:SqlPrepared) {.discardable, since: (1, 3).} = +proc finalize*(sqlPrepared:SqlPrepared) {.discardable, since: (1, 3).} = discard finalize(sqlPrepared.PStmt) template dbBindParamError*(paramIdx: int, val: varargs[untyped]) = @@ -756,7 +819,7 @@ proc bindParam*(ps: SqlPrepared, paramIdx: int, val: float64) {.since: (1, 3).} dbBindParamError(paramIdx, val) proc bindNull*(ps: SqlPrepared, paramIdx: int) {.since: (1, 3).} = - ## Sets the bindparam at the specified paramIndex to null + ## Sets the bindparam at the specified paramIndex to null ## (default behaviour by sqlite). if bind_null(ps.PStmt, paramIdx.int32) != SQLITE_OK: dbBindParamError(paramIdx) diff --git a/tests/stdlib/tsqlitebindatas.nim b/tests/stdlib/tsqlitebindatas.nim new file mode 100644 index 000000000..643f1e2e6 --- /dev/null +++ b/tests/stdlib/tsqlitebindatas.nim @@ -0,0 +1,50 @@ +discard """ + action: "run" + exitcode: 0 +""" +import db_sqlite +import random +import os +from stdtest/specialpaths import buildDir + +block tsqlitebindatas: ## db_sqlite binary data + const dbName = buildDir / "tsqlitebindatas.db" + + let origName = "Bobby" + var orig = newSeq[float64](150) + randomize() + for x in orig.mitems: + x = rand(1.0)/10.0 + + discard tryRemoveFile(dbName) + let db = open(dbName, "", "", "") + let createTableStr = sql"""CREATE TABLE test( + id INTEGER NOT NULL PRIMARY KEY, + name TEXT, + data BLOB + ) + """ + db.exec(createTableStr) + + var dbuf = newSeq[byte](orig.len*sizeof(float64)) + copyMem(unsafeAddr(dbuf[0]), unsafeAddr(orig[0]), dbuf.len) + + var insertStmt = db.prepare("INSERT INTO test (id, name, data) VALUES (?, ?, ?)") + insertStmt.bindParams(1, origName, dbuf) + let bres = db.tryExec(insertStmt) + doAssert(bres) + + finalize(insertStmt) + + var nameTest = db.getValue(sql"SELECT name FROM test WHERE id = ?", 1) + doAssert nameTest == origName + + var dataTest = db.getValue(sql"SELECT data FROM test WHERE id = ?", 1) + let seqSize = int(dataTest.len*sizeof(byte)/sizeof(float64)) + var res: seq[float64] = newSeq[float64](seqSize) + copyMem(unsafeAddr(res[0]), addr(dataTest[0]), dataTest.len) + doAssert res.len == orig.len + doAssert res == orig + + db.close() + doAssert tryRemoveFile(dbName) From eb429988cd15555f2af35389d52256b06e00e900 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 2 Nov 2020 21:16:33 +0800 Subject: [PATCH 1380/4254] fixes #15594 (#15819) --- lib/pure/sugar.nim | 2 ++ tests/closure/t15594.nim | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/closure/t15594.nim diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 92e9f662a..dd44c731d 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -207,6 +207,8 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0] else: locals for arg in locals: + if arg.strVal == "result": + error("The variable name cannot be `result`!", arg) params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg)) result = newNimNode(nnkCall) result.add(newProc(newEmptyNode(), params, body, nnkProcDef)) diff --git a/tests/closure/t15594.nim b/tests/closure/t15594.nim new file mode 100644 index 000000000..aacd9ed84 --- /dev/null +++ b/tests/closure/t15594.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "The variable name cannot be `result`!" +""" + +import sugar + +proc begin(): int = + capture result: + echo 1+1 + result From dfd8a83f3557164fd41714c11c6f92b65eef9018 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 2 Nov 2020 14:17:09 +0100 Subject: [PATCH 1381/4254] fixes #15804 (#15820) * fixes #15804 * fix the existing test * add the testcase for #15804 Co-authored-by: narimiran --- lib/pure/asyncmacro.nim | 21 +++++++++------------ tests/async/t15804.nim | 15 +++++++++++++++ tests/async/tasync_noasync.nim | 6 +++--- 3 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 tests/async/t15804.nim diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 65cf2f3b9..579e9fede 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -129,6 +129,15 @@ proc verifyReturnType(typeName: string, node: NimNode = nil) {.compileTime.} = error("Expected return type of 'Future' got '$1'" % typeName, node) +template await*(f: typed): untyped {.used.} = + static: + error "await expects Future[T], got " & $typeof(f) + +template await*[T](f: Future[T]): auto {.used.} = + var internalTmpFuture: FutureBase = f + yield internalTmpFuture + (cast[typeof(f)](internalTmpFuture)).read() + proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. ## The ``async`` macro supports a stmtList holding multiple async procedures. @@ -262,20 +271,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = result.params[0] = parseExpr("owned(Future[void])") # based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 - # however here the overloads are placed inside each expanded async - var awaitDefinition = quote: - template await(f: typed): untyped {.used.} = - static: - error "await expects Future[T], got " & $typeof(f) - - template await[T](f: Future[T]): auto {.used.} = - var internalTmpFuture: FutureBase = f - yield internalTmpFuture - (cast[type(f)](internalTmpFuture)).read() - if procBody.kind != nnkEmpty: body2.add quote do: - `awaitDefinition` `outerProcBody` result.body = body2 diff --git a/tests/async/t15804.nim b/tests/async/t15804.nim new file mode 100644 index 000000000..8de012196 --- /dev/null +++ b/tests/async/t15804.nim @@ -0,0 +1,15 @@ +import asyncdispatch + +type + Foo*[E] = ref object + op: proc(): Future[bool] {.gcsafe.} + +proc newFoo*[E](): Foo[E] = + result = Foo[E]() + result.op = proc(): Future[bool] {.gcsafe,async.} = + await sleepAsync(100) + result = false + +when isMainModule: + let f = newFoo[int]() + echo waitFor f.op() diff --git a/tests/async/tasync_noasync.nim b/tests/async/tasync_noasync.nim index 812b40da6..54f4f597f 100644 --- a/tests/async/tasync_noasync.nim +++ b/tests/async/tasync_noasync.nim @@ -1,7 +1,7 @@ discard """ - errormsg: "undeclared identifier: 'await'" + errormsg: "'yield' only allowed in an iterator" cmd: "nim c $file" - file: "tasync_noasync.nim" + file: "asyncmacro.nim" """ import async @@ -12,4 +12,4 @@ await a() # if we overload a fallback handler to get # await only available within {.async.} -# we would need `{.dirty.}` templates for await \ No newline at end of file +# we would need `{.dirty.}` templates for await From 235e4930ab2f5a9a4c94d6cc66d62701ee58550d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 2 Nov 2020 14:48:36 +0100 Subject: [PATCH 1382/4254] simplify toHex (#15821) --- lib/pure/strutils.nim | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 740a6e391..491760137 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -951,11 +951,11 @@ proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.no # handle negative overflow if n == 0 and handleNegative: n = not(BiggestUInt 0) -proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} = +proc toHex*[T: SomeInteger](x: T, len: Positive): string {.noSideEffect.} = ## Converts `x` to its hexadecimal representation. ## ## The resulting string will be exactly `len` characters long. No prefix like - ## ``0x`` is generated. + ## ``0x`` is generated. `x` is treated as an unsigned value. runnableExamples: let a = 62'u64 @@ -963,34 +963,7 @@ proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} = doAssert a.toHex(3) == "03E" doAssert b.toHex(3) == "001" doAssert b.toHex(4) == "1001" - toHexImpl(x, len, false) - -proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, - rtl, extern: "nsuToHex".} = - ## Converts `x` to its hexadecimal representation. - ## - ## The resulting string will be exactly `len` characters long. No prefix like - ## ``0x`` is generated. `x` is treated as an unsigned value. - runnableExamples: - let - a = 62 - b = 4097 - c = -8 - doAssert a.toHex(3) == "03E" - doAssert b.toHex(3) == "001" - doAssert b.toHex(4) == "1001" - doAssert c.toHex(6) == "FFFFF8" - toHexImpl(cast[BiggestUInt](x), len, x < 0) - -proc toHex*(x: int, len: Positive): string {.noSideEffect.} = - ## Converts `x` to its hexadecimal representation. - ## - ## The resulting string will be exactly `len` characters long. No prefix like - ## ``0x`` is generated. `x` is treated as an unsigned value. - runnableExamples: doAssert toHex(62, 3) == "03E" - doAssert toHex(4097, 3) == "001" - doAssert toHex(4097, 4) == "1001" doAssert toHex(-8, 6) == "FFFFF8" toHexImpl(cast[BiggestUInt](x), len, x < 0) From c243639979b795d28a69f19ad988726225e22fcd Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 2 Nov 2020 16:52:54 +0100 Subject: [PATCH 1383/4254] `ioutils` are moved to `fusion` (#15822) --- lib/std/ioutils.nim | 85 --------------------------------------- tests/stdlib/tioutils.nim | 49 ---------------------- 2 files changed, 134 deletions(-) delete mode 100644 lib/std/ioutils.nim delete mode 100644 tests/stdlib/tioutils.nim diff --git a/lib/std/ioutils.nim b/lib/std/ioutils.nim deleted file mode 100644 index bef61c54a..000000000 --- a/lib/std/ioutils.nim +++ /dev/null @@ -1,85 +0,0 @@ -when defined(windows): - proc c_dup(oldfd: FileHandle): FileHandle {. - importc: "_dup", header: "".} - proc c_dup2(oldfd: FileHandle, newfd: FileHandle): cint {. - importc: "_dup2", header: "".} -else: - proc c_dup(oldfd: FileHandle): FileHandle{. - importc: "dup", header: "".} - proc c_dup2(oldfd: FileHandle, newfd: FileHandle): cint {. - importc: "dup2", header: "".} - -# when false: -# const SupportIoctlInheritCtl = (defined(linux) or defined(bsd)) and -# not defined(nimscript) -# when SupportIoctlInheritCtl: -# var -# FIOCLEX {.importc, header: "".}: cint -# FIONCLEX {.importc, header: "".}: cint - -## Also defined in std/posix and system/io -proc strerror(errnum: cint): cstring {.importc, header: "".} -when not defined(nimscript): - var errno {.importc, header: "".}: cint ## error variable - -template checkError(ret: cint) = - if ret == -1: - when not defined(nimscript): - raise newException(IOError, $strerror(errno)) - else: - doAssert(false) - -proc duplicate*(oldfd: FileHandle): FileHandle = - ##[ - Return a copy of the file handle `oldfd`. - After a successful return, both `FileHandle` may be used interchangeably. - They refer to the same open file description and share file offset and status flags. - Calls POSIX function `dup` on Posix platform and `_dup` on Windows - ]## - runnableExamples: - # stdoutDuplicate is a copy of stdout FileHandle that points to STDOUT - let stdoutDuplicate = duplicate(stdout.getFileHandle()) - # Writing to stdoutDuplicate will write to stdout - doAssert(stdoutDuplicate != stdout.getFileHandle()) - # On windows, opening a file from a FileHandle does not work - when not defined(windows): - var f : File - let res = open(f, stdoutDuplicate, mode=fmWrite) - let msg = "This is a test message that will be displayed ! \n" - f.write(msg) - # Output "Test" - f.close() - - result = c_dup(oldfd) - checkError(result) - -proc duplicateTo*(oldfd: FileHandle, newfd: FileHandle) = - ##[ - Perform the same task a `duplicate` but instead of using the lowest unused file descriptor - it uses the FileHandle` specified by `newfd`. - Calls POSIX function `dup2` on Posix platform and `_dup2` on Windows. - ]## - runnableExamples: - import os - # Redirect stdout to a file temporarily - let tmpFileName = getTempDir() / "hidden_output.txt" - let stdoutFileno = stdout.getFileHandle() - let stdoutDupFd = duplicate(stdoutFileno) - - # Create a new file - let tmpFile: File = open(tmpFileName, fmAppend) - let tmpFileFd: FileHandle = tmpFile.getFileHandle() - - # stdoutFileno now writes to tmpFile - duplicateTo(tmpFileFd, stdoutFileno) - echo "This is not displayed, but written to tmpFile instead !" - - # Close file & restore stdout - tmpFile.close() - duplicateTo(stdoutDupFd, stdoutFileno) - - # stdout is now restored ! - echo "This is displayed" - - let retValue = c_dup2(oldfd, newfd) - checkError(retValue) diff --git a/tests/stdlib/tioutils.nim b/tests/stdlib/tioutils.nim deleted file mode 100644 index 6854a7c1c..000000000 --- a/tests/stdlib/tioutils.nim +++ /dev/null @@ -1,49 +0,0 @@ -discard """ - output: ''' -hello1 -hello1 -''' -""" - -import std/ioutils -import os -from stdtest/specialpaths import buildDir - -block: # duplicate, duplicateTo - let tmpFileName = buildDir / "tioutils.txt" - template captureStdout(body) : untyped = - let stdoutFileno = stdout.getFileHandle() - # Duplicate stoudFileno - let stdout_dupfd = duplicate(stdoutFileno) - # Create a new file - # You can use append strategy if you'd like - let tmpFile: File = open(tmpFileName, fmWrite) - # Get the FileHandle (the file descriptor) of your file - let tmpFileFd: FileHandle = tmpFile.getFileHandle() - # dup2 tmpFileFd to stdoutFileno -> writing to stdoutFileno now writes to tmpFile - duplicateTo(tmpFileFd, stdoutFileno) - body - # Force flush - tmpFile.flushFile() - # Close tmp - tmpFile.close() - # Read tmp - let ret = readFile(tmpFileName) - # Restore stdout - duplicateTo(stdout_dupfd, stdoutFileno) - ret - - proc duplicateStdout() = - var msg = "hello" - echo msg & "1" - - let s = captureStdout: - echo msg & "2" - - doAssert s == "hello2\n" - - discard tryRemoveFile(tmpFileName) - duplicateStdout() - # Check it works twice - duplicateStdout() - doAssert tryRemoveFile(tmpFileName) From fde17b159fdc96eda5609fd98e1fe3c7a34ef40b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 3 Nov 2020 01:27:39 +0800 Subject: [PATCH 1384/4254] follow #15818 and close #7109 (#15823) * follow #15818 and close #7109 * Update compiler/jsgen.nim Co-authored-by: Juan Carlos Co-authored-by: Juan Carlos --- compiler/jsgen.nim | 7 +++++-- tests/js/t7109.nim | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/js/t7109.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 10c072253..d124ae5fe 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2549,9 +2549,12 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkAsmStmt: genAsmOrEmitStmt(p, n) of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r) of nkRaiseStmt: genRaiseStmt(p, n) - of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, + of nkTypeSection, nkCommentStmt, nkIncludeStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard + of nkIteratorDef: + if n[0].sym.typ.callConv == TCallingConvention.ccClosure: + globalError(p.config, n.info, "Closure iterators are not supported by JS backend!") of nkPragma: genPragma(p, n) of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: var s = n[namePos].sym @@ -2559,7 +2562,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = genSym(p, n[namePos], r) r.res = nil of nkGotoState, nkState: - internalError(p.config, n.info, "first class iterators not implemented") + globalError(p.config, n.info, "First class iterators not implemented") of nkPragmaBlock: gen(p, n.lastSon, r) of nkComesFrom: discard "XXX to implement for better stack traces" diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim new file mode 100644 index 000000000..0d071dbbf --- /dev/null +++ b/tests/js/t7109.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "Closure iterators are not supported by JS backend!" +""" + +iterator iter*(): int {.closure.} = + yield 3 + +var x = iter From b8bcf236dd29ee2a6ec7587dc3f028f14023ebec Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 3 Nov 2020 18:41:41 +0800 Subject: [PATCH 1385/4254] fix #12640 (#15829) --- compiler/ccgstmts.nim | 8 +++++++- tests/pragmas/t12640.nim | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/t12640.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index aaed37508..367e693e9 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -382,7 +382,13 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = proc genSingleVar(p: BProc, a: PNode) = let v = a[0].sym - if sfCompileTime in v.flags: return + if sfCompileTime in v.flags: + # fix issue #12640 + # {.global, compileTime.} pragma in proc + if sfGlobal in v.flags and p.prc != nil and p.prc.kind == skProc: + discard + else: + return genSingleVar(p, v, a[0], a[2]) proc genClosureVar(p: BProc, a: PNode) = diff --git a/tests/pragmas/t12640.nim b/tests/pragmas/t12640.nim new file mode 100644 index 000000000..60177d034 --- /dev/null +++ b/tests/pragmas/t12640.nim @@ -0,0 +1,25 @@ +discard """ + nimout: '''1 +2 +3 +[1, 2, 3]''' + + output: '''1 +2 +3 +[1, 2, 3]''' +""" + + +proc doIt(a: openArray[int]) = + echo a + +proc foo() = + var bug {.global, compiletime.}: seq[int] + bug = @[1, 2 ,3] + for i in 0 .. high(bug): echo bug[i] + doIt(bug) + +static: + foo() +foo() From d62f3627aa1946cd5fa9d3e52abedf9576db0e8e Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 3 Nov 2020 15:26:16 +0000 Subject: [PATCH 1386/4254] EnumUtils, speed up findStr in compiler (#15777) * add parseEnumRange * fix runnable example * update changelog * use parseEnumRange in compiler * reorganise code * add changelog, make single normalizer argument --- changelog.md | 1 + compiler/commands.nim | 4 +-- compiler/pragmas.nim | 2 +- compiler/wordrecg.nim | 25 ++++++++++++----- lib/pure/strutils.nim | 61 ++--------------------------------------- lib/std/enumutils.nim | 64 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 68 deletions(-) create mode 100644 lib/std/enumutils.nim diff --git a/changelog.md b/changelog.md index 6bff75a44..d28edd34c 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,7 @@ - Added `randState` template that exposes the default random number generator. Useful for library authors. +- Added std/enumutils module containing `genEnumCaseStmt` macro that generates case statement to parse string to enum. ## Language changes diff --git a/compiler/commands.nim b/compiler/commands.nim index a35d1dae7..cb7517f06 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -193,11 +193,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, elif i < arg.len and (arg[i] in {':', '='}): inc(i) else: invalidCmdLineOption(conf, pass, orig, info) if state == wHint: - let x = findStr(hintMin..hintMax, id, errUnknown) + let x = findStr(hintMin, hintMax, id, errUnknown) if x != errUnknown: n = TNoteKind(x) else: localError(conf, info, "unknown hint: " & id) else: - let x = findStr(warnMin..warnMax, id, errUnknown) + let x = findStr(warnMin, warnMax, id, errUnknown) if x != errUnknown: n = TNoteKind(x) else: localError(conf, info, "unknown warning: " & id) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c1d54c4a2..8affccbf3 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -331,7 +331,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = proc processNote(c: PContext, n: PNode) = template handleNote(enumVals, notes) = - let x = findStr(enumVals, n[0][1].ident.s, errUnknown) + let x = findStr(enumVals.a, enumVals.b, n[0][1].ident.s, errUnknown) if x != errUnknown: nk = TNoteKind(x) let x = c.semConstBoolExpr(c, n[1]) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index e2e3a1d2f..170d04df1 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -13,8 +13,6 @@ # does not support strings. Without this the code would # be slow and unreadable. -from strutils import cmpIgnoreStyle - type TSpecialWord* = enum wInvalid = "", @@ -125,8 +123,21 @@ const wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing} -proc findStr*[T:enum](a: Slice[T], s: string, default: T): T = - for i in a: - if cmpIgnoreStyle($i, s) == 0: - return i - result = default \ No newline at end of file + +const enumUtilsExist = compiles: + import std/enumutils + +when enumUtilsExist: + from std/enumutils import genEnumCaseStmt + from strutils import normalize + proc findStr*[T: enum](a, b: static[T], s: string, default: T): T = + genEnumCaseStmt(T, s, default, ord(a), ord(b), normalize) + +else: + from strutils import cmpIgnoreStyle + proc findStr*[T: enum](a, b: static[T], s: string, default: T): T {.deprecated.} = + # used for compiler bootstrapping only + for i in a..b: + if cmpIgnoreStyle($i, s) == 0: + return i + result = default \ No newline at end of file diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 491760137..19a37425e 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -76,7 +76,7 @@ import parseutils from math import pow, floor, log10 from algorithm import reverse -import macros # for `parseEnum` +import std/enumutils when defined(nimVmExportFixed): from unicode import toLower, toUpper @@ -1264,61 +1264,6 @@ proc parseBool*(s: string): bool = of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) -proc addOfBranch(s: string, field, enumType: NimNode): NimNode = - result = nnkOfBranch.newTree( - newLit s, - nnkCall.newTree(enumType, field) # `T()` - ) - -macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = - # generates a case stmt, which assigns the correct enum field given - # a normalized string comparison to the `argSym` input. - # NOTE: for an enum with fields Foo, Bar, ... we cannot generate - # `of "Foo".nimIdentNormalize: Foo`. - # This will fail, if the enum is not defined at top level (e.g. in a block). - # Thus we check for the field value of the (possible holed enum) and convert - # the integer value to the generic argument `typ`. - let typ = typ.getTypeInst[1] - let impl = typ.getImpl[2] - expectKind impl, nnkEnumTy - result = nnkCaseStmt.newTree(newCall(bindSym"nimIdentNormalize", argSym)) - # stores all processed field strings to give error msg for ambiguous enums - var foundFields: seq[string] = @[] - var fStr = "" # string of current field - var fNum = BiggestInt(0) # int value of current field - for f in impl: - case f.kind - of nnkEmpty: continue # skip first node of `enumTy` - of nnkSym, nnkIdent: fStr = f.strVal - of nnkEnumFieldDef: - case f[1].kind - of nnkStrLit: fStr = f[1].strVal - of nnkTupleConstr: - fStr = f[1][1].strVal - fNum = f[1][0].intVal - of nnkIntLit: - fStr = f[0].strVal - fNum = f[1].intVal - else: error("Invalid tuple syntax!", f[1]) - else: error("Invalid node for enum type!", f) - # add field if string not already added - fStr = nimIdentNormalize(fStr) - if fStr notin foundFields: - result.add addOfBranch(fStr, newLit fNum, typ) - foundFields.add fStr - else: - error("Ambiguous enums cannot be parsed, field " & $fStr & - " appears multiple times!", f) - inc fNum - # finally add else branch to raise or use default - if default == nil: - let raiseStmt = quote do: - raise newException(ValueError, "Invalid enum value: " & $`argSym`) - result.add nnkElse.newTree(raiseStmt) - else: - expectKind(default, nnkSym) - result.add nnkElse.newTree(default) - proc parseEnum*[T: enum](s: string): T = ## Parses an enum ``T``. This errors at compile time, if the given enum ## type contains multiple fields with the same string value. @@ -1337,7 +1282,7 @@ proc parseEnum*[T: enum](s: string): T = doAssertRaises(ValueError): echo parseEnum[MyEnum]("third") - genEnumStmt(T, s, default = nil) + genEnumCaseStmt(T, s, default = nil, ord(low(T)), ord(high(T)), nimIdentNormalize) proc parseEnum*[T: enum](s: string, default: T): T = ## Parses an enum ``T``. This errors at compile time, if the given enum @@ -1356,7 +1301,7 @@ proc parseEnum*[T: enum](s: string, default: T): T = doAssert parseEnum[MyEnum]("second") == second doAssert parseEnum[MyEnum]("last", third) == third - genEnumStmt(T, s, default) + genEnumCaseStmt(T, s, default, ord(low(T)), ord(high(T)), nimIdentNormalize) proc repeat*(c: char, count: Natural): string {.noSideEffect, rtl, extern: "nsuRepeatChar".} = diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim new file mode 100644 index 000000000..704e42de5 --- /dev/null +++ b/lib/std/enumutils.nim @@ -0,0 +1,64 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import macros + +macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, + userMin, userMax: static[int], normalizer: static[proc(s :string): string]): untyped = + # generates a case stmt, which assigns the correct enum field given + # a normalized string comparison to the `argSym` input. + # string normalization is done using passed normalizer. + # NOTE: for an enum with fields Foo, Bar, ... we cannot generate + # `of "Foo".nimIdentNormalize: Foo`. + # This will fail, if the enum is not defined at top level (e.g. in a block). + # Thus we check for the field value of the (possible holed enum) and convert + # the integer value to the generic argument `typ`. + let typ = typ.getTypeInst[1] + let impl = typ.getImpl[2] + expectKind impl, nnkEnumTy + let normalizerNode = quote: `normalizer` + expectKind normalizerNode, nnkSym + result = nnkCaseStmt.newTree(newCall(normalizerNode, argSym)) + # stores all processed field strings to give error msg for ambiguous enums + var foundFields: seq[string] = @[] + var fStr = "" # string of current field + var fNum = BiggestInt(0) # int value of current field + for f in impl: + case f.kind + of nnkEmpty: continue # skip first node of `enumTy` + of nnkSym, nnkIdent: fStr = f.strVal + of nnkEnumFieldDef: + case f[1].kind + of nnkStrLit: fStr = f[1].strVal + of nnkTupleConstr: + fStr = f[1][1].strVal + fNum = f[1][0].intVal + of nnkIntLit: + fStr = f[0].strVal + fNum = f[1].intVal + else: error("Invalid tuple syntax!", f[1]) + else: error("Invalid node for enum type!", f) + # add field if string not already added + if fNum >= userMin and fNum <= userMax: + fStr = normalizer(fStr) + if fStr notin foundFields: + result.add nnkOfBranch.newTree(newLit fStr, nnkCall.newTree(typ, newLit fNum)) + foundFields.add fStr + else: + error("Ambiguous enums cannot be parsed, field " & $fStr & + " appears multiple times!", f) + inc fNum + # finally add else branch to raise or use default + if default == nil: + let raiseStmt = quote do: + raise newException(ValueError, "Invalid enum value: " & $`argSym`) + result.add nnkElse.newTree(raiseStmt) + else: + expectKind(default, nnkSym) + result.add nnkElse.newTree(default) \ No newline at end of file From 75dc69417a235c3be1edb3d89ddb49104bdd438d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 3 Nov 2020 23:31:16 +0800 Subject: [PATCH 1387/4254] fix deprecated messages regarding high (#15832) --- lib/system/gc.nim | 2 +- lib/system/gc_ms.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 304eda19a..1f7164266 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -856,7 +856,7 @@ when not defined(useNimRtl): gch.cycleThreshold = InitialCycleThreshold proc GC_disableMarkAndSweep() = - gch.cycleThreshold = high(gch.cycleThreshold)-1 + gch.cycleThreshold = high(typeof(gch.cycleThreshold))-1 # set to the max value to suppress the cycle detector proc GC_fullCollect() = diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 6683b9e34..852f5d7aa 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -507,7 +507,7 @@ when not defined(useNimRtl): gch.cycleThreshold = InitialThreshold proc GC_disableMarkAndSweep() = - gch.cycleThreshold = high(gch.cycleThreshold)-1 + gch.cycleThreshold = high(typeof(gch.cycleThreshold))-1 # set to the max value to suppress the cycle detector when defined(nimTracing): From b0e26d8fbffd044aa3f23fc680e6a2e666593399 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 4 Nov 2020 03:43:51 +0800 Subject: [PATCH 1388/4254] remove iup from stdlib in contrast to #15828 (#15830) * remove iup from stdlib * Update changelog.md --- changelog.md | 2 + doc/lib.rst | 7 - lib/wrappers/iup.nim | 995 ------------------------------------------- tools/kochdocs.nim | 1 - 4 files changed, 2 insertions(+), 1003 deletions(-) delete mode 100644 lib/wrappers/iup.nim diff --git a/changelog.md b/changelog.md index d28edd34c..871fb229d 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,8 @@ - Added std/enumutils module containing `genEnumCaseStmt` macro that generates case statement to parse string to enum. +- Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). + ## Language changes diff --git a/doc/lib.rst b/doc/lib.rst index 2dd43109e..3c80fd343 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -540,13 +540,6 @@ Regular expressions Wrapper for the PCRE library. -GUI libraries -------------- - -* `iup `_ - The wrapper of the IUP GUI library. - - Database support ---------------- diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim deleted file mode 100644 index 0242d7981..000000000 --- a/lib/wrappers/iup.nim +++ /dev/null @@ -1,995 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# C header files translated by hand -# Licence of IUP follows: - - -# **************************************************************************** -# Copyright (C) 1994-2009 Tecgraf, PUC-Rio. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# **************************************************************************** - - -## Wrapper for the `IUP native GUI library `_. -## -## Requires `iup.dll` on Windows, `libiup.so` on Linux, `libiup.dylib` on OS X. -## Compile with `-d:nimDebugDlOpen` to debug the shared library opening. -## -## Examples -## ======== -## -## .. image:: http://webserver2.tecgraf.puc-rio.br/iup/en/tutorial/example2_1.png -## -## .. code-block:: nim -## import os, iup -## var argc = create(cint) -## argc[] = paramCount().cint -## var argv = allocCstringArray(commandLineParams()) -## assert open(argc, argv.addr) == 0 # UIP requires calling open() -## message(r"Hello world 1", r"Hello world") # Message popup -## close() # UIP requires calling close() -## -## -## .. image:: http://webserver2.tecgraf.puc-rio.br/iup/en/tutorial/example3_1.png -## -## .. code-block:: nim -## import os, iup -## var argc = create(cint) -## argc[] = paramCount().cint -## var argv = allocCstringArray(commandLineParams()) -## assert open(argc, argv.addr) == 0 # UIP requires open() -## let textarea = text(nil) # Text widget. -## setAttribute(textarea, r"MULTILINE", r"YES") # Set text widget to multiline. -## setAttribute(textarea, r"EXPAND", r"YES") # Set text widget to auto expand. -## let layout = vbox(textarea) # Vertical layout. -## let window = dialog(layout) # Dialog window. -## setAttribute(window, "TITLE", "Nim Notepad") # Set window title. -## showXY(window, IUP_CENTER, IUP_CENTER) # Show window. -## mainLoop() # Main loop. -## close() # UIP requires calling close() - - -when defined(windows): - const dllname = "iup(|30|27|26|25|24).dll" -elif defined(macosx): - const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib" -else: - const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)" - -const - IUP_NAME* = "IUP - Portable User Interface" - IUP_COPYRIGHT* = "Copyright (C) 1994-2009 Tecgraf, PUC-Rio." - IUP_DESCRIPTION* = "Portable toolkit for building graphical user interfaces." - constIUP_VERSION* = "3.0" - constIUP_VERSION_NUMBER* = 300000 - constIUP_VERSION_DATE* = "2009/07/18" - -type - Ihandle = object - PIhandle* = ptr Ihandle - - Icallback* = proc (arg: PIhandle): cint {.cdecl.} - -# pre-defined dialogs -proc fileDlg*: PIhandle {.importc: "IupFileDlg", dynlib: dllname, cdecl.} -proc messageDlg*: PIhandle {.importc: "IupMessageDlg", dynlib: dllname, cdecl.} -proc colorDlg*: PIhandle {.importc: "IupColorDlg", dynlib: dllname, cdecl.} -proc fontDlg*: PIhandle {.importc: "IupFontDlg", dynlib: dllname, cdecl.} - -proc getFile*(arq: cstring): cint {. - importc: "IupGetFile", dynlib: dllname, cdecl.} -proc message*(title, msg: cstring) {. - importc: "IupMessage", dynlib: dllname, cdecl.} -proc messagef*(title, format: cstring) {. - importc: "IupMessagef", dynlib: dllname, cdecl, varargs.} -proc alarm*(title, msg, b1, b2, b3: cstring): cint {. - importc: "IupAlarm", dynlib: dllname, cdecl.} -proc scanf*(format: cstring): cint {. - importc: "IupScanf", dynlib: dllname, cdecl, varargs.} -proc listDialog*(theType: cint, title: cstring, size: cint, - list: cstringArray, op, maxCol, maxLin: cint, - marks: ptr cint): cint {. - importc: "IupListDialog", dynlib: dllname, cdecl.} -proc getText*(title, text: cstring): cint {. - importc: "IupGetText", dynlib: dllname, cdecl.} -proc getColor*(x, y: cint, r, g, b: var byte): cint {. - importc: "IupGetColor", dynlib: dllname, cdecl.} - -type - Iparamcb* = proc (dialog: PIhandle, paramIndex: cint, - userData: pointer): cint {.cdecl.} - -proc getParam*(title: cstring, action: Iparamcb, userData: pointer, - format: cstring): cint {. - importc: "IupGetParam", cdecl, varargs, dynlib: dllname.} -proc getParamv*(title: cstring, action: Iparamcb, userData: pointer, - format: cstring, paramCount, paramExtra: cint, - paramData: pointer): cint {. - importc: "IupGetParamv", cdecl, dynlib: dllname.} - - -# Functions - -proc open*(argc: ptr cint, argv: ptr cstringArray): cint {. - importc: "IupOpen", cdecl, dynlib: dllname.} -proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.} -proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.} - -proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, - discardable.} -proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname, - discardable.} -proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, - dynlib: dllname, discardable.} -proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.} -proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.} - -proc update*(ih: PIhandle) {.importc: "IupUpdate", cdecl, dynlib: dllname.} -proc updateChildren*(ih: PIhandle) {.importc: "IupUpdateChildren", cdecl, dynlib: dllname.} -proc redraw*(ih: PIhandle, children: cint) {.importc: "IupRedraw", cdecl, dynlib: dllname.} -proc refresh*(ih: PIhandle) {.importc: "IupRefresh", cdecl, dynlib: dllname.} - -proc mapFont*(iupfont: cstring): cstring {.importc: "IupMapFont", cdecl, dynlib: dllname.} -proc unMapFont*(driverfont: cstring): cstring {.importc: "IupUnMapFont", cdecl, dynlib: dllname.} -proc help*(url: cstring): cint {.importc: "IupHelp", cdecl, dynlib: dllname.} -proc load*(filename: cstring): cstring {.importc: "IupLoad", cdecl, dynlib: dllname.} - -proc iupVersion*(): cstring {.importc: "IupVersion", cdecl, dynlib: dllname.} -proc iupVersionDate*(): cstring {.importc: "IupVersionDate", cdecl, dynlib: dllname.} -proc iupVersionNumber*(): cint {.importc: "IupVersionNumber", cdecl, dynlib: dllname.} -proc setLanguage*(lng: cstring) {.importc: "IupSetLanguage", cdecl, dynlib: dllname.} -proc getLanguage*(): cstring {.importc: "IupGetLanguage", cdecl, dynlib: dllname.} - -proc destroy*(ih: PIhandle) {.importc: "IupDestroy", cdecl, dynlib: dllname.} -proc detach*(child: PIhandle) {.importc: "IupDetach", cdecl, dynlib: dllname.} -proc append*(ih, child: PIhandle): PIhandle {. - importc: "IupAppend", cdecl, dynlib: dllname, discardable.} -proc insert*(ih, refChild, child: PIhandle): PIhandle {. - importc: "IupInsert", cdecl, dynlib: dllname, discardable.} -proc getChild*(ih: PIhandle, pos: cint): PIhandle {. - importc: "IupGetChild", cdecl, dynlib: dllname.} -proc getChildPos*(ih, child: PIhandle): cint {. - importc: "IupGetChildPos", cdecl, dynlib: dllname.} -proc getChildCount*(ih: PIhandle): cint {. - importc: "IupGetChildCount", cdecl, dynlib: dllname.} -proc getNextChild*(ih, child: PIhandle): PIhandle {. - importc: "IupGetNextChild", cdecl, dynlib: dllname.} -proc getBrother*(ih: PIhandle): PIhandle {. - importc: "IupGetBrother", cdecl, dynlib: dllname.} -proc getParent*(ih: PIhandle): PIhandle {. - importc: "IupGetParent", cdecl, dynlib: dllname.} -proc getDialog*(ih: PIhandle): PIhandle {. - importc: "IupGetDialog", cdecl, dynlib: dllname.} -proc getDialogChild*(ih: PIhandle, name: cstring): PIhandle {. - importc: "IupGetDialogChild", cdecl, dynlib: dllname.} -proc reparent*(ih, newParent: PIhandle): cint {. - importc: "IupReparent", cdecl, dynlib: dllname.} - -proc popup*(ih: PIhandle, x, y: cint): cint {. - importc: "IupPopup", cdecl, dynlib: dllname, discardable.} -proc show*(ih: PIhandle): cint {. - importc: "IupShow", cdecl, dynlib: dllname, discardable.} -proc showXY*(ih: PIhandle, x, y: cint): cint {. - importc: "IupShowXY", cdecl, dynlib: dllname, discardable.} -proc hide*(ih: PIhandle): cint {. - importc: "IupHide", cdecl, dynlib: dllname, discardable.} -proc map*(ih: PIhandle): cint {. - importc: "IupMap", cdecl, dynlib: dllname, discardable.} -proc unmap*(ih: PIhandle) {. - importc: "IupUnmap", cdecl, dynlib: dllname, discardable.} - -proc setAttribute*(ih: PIhandle, name, value: cstring) {. - importc: "IupSetAttribute", cdecl, dynlib: dllname.} -proc storeAttribute*(ih: PIhandle, name, value: cstring) {. - importc: "IupStoreAttribute", cdecl, dynlib: dllname.} -proc setAttributes*(ih: PIhandle, str: cstring): PIhandle {. - importc: "IupSetAttributes", cdecl, dynlib: dllname.} -proc getAttribute*(ih: PIhandle, name: cstring): cstring {. - importc: "IupGetAttribute", cdecl, dynlib: dllname.} -proc getAttributes*(ih: PIhandle): cstring {. - importc: "IupGetAttributes", cdecl, dynlib: dllname.} -proc getInt*(ih: PIhandle, name: cstring): cint {. - importc: "IupGetInt", cdecl, dynlib: dllname.} -proc getInt2*(ih: PIhandle, name: cstring): cint {. - importc: "IupGetInt2", cdecl, dynlib: dllname.} -proc getIntInt*(ih: PIhandle, name: cstring, i1, i2: var cint): cint {. - importc: "IupGetIntInt", cdecl, dynlib: dllname.} -proc getFloat*(ih: PIhandle, name: cstring): cfloat {. - importc: "IupGetFloat", cdecl, dynlib: dllname.} -proc setfAttribute*(ih: PIhandle, name, format: cstring) {. - importc: "IupSetfAttribute", cdecl, dynlib: dllname, varargs.} -proc getAllAttributes*(ih: PIhandle, names: cstringArray, n: cint): cint {. - importc: "IupGetAllAttributes", cdecl, dynlib: dllname.} -proc setAtt*(handleName: cstring, ih: PIhandle, name: cstring): PIhandle {. - importc: "IupSetAtt", cdecl, dynlib: dllname, varargs, discardable.} - -proc setGlobal*(name, value: cstring) {. - importc: "IupSetGlobal", cdecl, dynlib: dllname.} -proc storeGlobal*(name, value: cstring) {. - importc: "IupStoreGlobal", cdecl, dynlib: dllname.} -proc getGlobal*(name: cstring): cstring {. - importc: "IupGetGlobal", cdecl, dynlib: dllname.} - -proc setFocus*(ih: PIhandle): PIhandle {. - importc: "IupSetFocus", cdecl, dynlib: dllname.} -proc getFocus*(): PIhandle {. - importc: "IupGetFocus", cdecl, dynlib: dllname.} -proc previousField*(ih: PIhandle): PIhandle {. - importc: "IupPreviousField", cdecl, dynlib: dllname.} -proc nextField*(ih: PIhandle): PIhandle {. - importc: "IupNextField", cdecl, dynlib: dllname.} - -proc getCallback*(ih: PIhandle, name: cstring): Icallback {. - importc: "IupGetCallback", cdecl, dynlib: dllname.} -proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {. - importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.} - -proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {. - importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.} - -proc getFunction*(name: cstring): Icallback {. - importc: "IupGetFunction", cdecl, dynlib: dllname.} -proc setFunction*(name: cstring, fn: Icallback): Icallback {. - importc: "IupSetFunction", cdecl, dynlib: dllname, discardable.} -proc getActionName*(): cstring {. - importc: "IupGetActionName", cdecl, dynlib: dllname.} - -proc getHandle*(name: cstring): PIhandle {. - importc: "IupGetHandle", cdecl, dynlib: dllname.} -proc setHandle*(name: cstring, ih: PIhandle): PIhandle {. - importc: "IupSetHandle", cdecl, dynlib: dllname.} -proc getAllNames*(names: cstringArray, n: cint): cint {. - importc: "IupGetAllNames", cdecl, dynlib: dllname.} -proc getAllDialogs*(names: cstringArray, n: cint): cint {. - importc: "IupGetAllDialogs", cdecl, dynlib: dllname.} -proc getName*(ih: PIhandle): cstring {. - importc: "IupGetName", cdecl, dynlib: dllname.} - -proc setAttributeHandle*(ih: PIhandle, name: cstring, ihNamed: PIhandle) {. - importc: "IupSetAttributeHandle", cdecl, dynlib: dllname.} -proc getAttributeHandle*(ih: PIhandle, name: cstring): PIhandle {. - importc: "IupGetAttributeHandle", cdecl, dynlib: dllname.} - -proc getClassName*(ih: PIhandle): cstring {. - importc: "IupGetClassName", cdecl, dynlib: dllname.} -proc getClassType*(ih: PIhandle): cstring {. - importc: "IupGetClassType", cdecl, dynlib: dllname.} -proc getClassAttributes*(classname: cstring, names: cstringArray, - n: cint): cint {. - importc: "IupGetClassAttributes", cdecl, dynlib: dllname.} -proc saveClassAttributes*(ih: PIhandle) {. - importc: "IupSaveClassAttributes", cdecl, dynlib: dllname.} -proc setClassDefaultAttribute*(classname, name, value: cstring) {. - importc: "IupSetClassDefaultAttribute", cdecl, dynlib: dllname.} - -proc create*(classname: cstring): PIhandle {. - importc: "IupCreate", cdecl, dynlib: dllname.} -proc createv*(classname: cstring, params: pointer): PIhandle {. - importc: "IupCreatev", cdecl, dynlib: dllname.} -proc createp*(classname: cstring, first: pointer): PIhandle {. - importc: "IupCreatep", cdecl, dynlib: dllname, varargs.} - -proc fill*(): PIhandle {.importc: "IupFill", cdecl, dynlib: dllname.} -proc radio*(child: PIhandle): PIhandle {. - importc: "IupRadio", cdecl, dynlib: dllname.} -proc vbox*(child: PIhandle): PIhandle {. - importc: "IupVbox", cdecl, dynlib: dllname, varargs.} -proc vboxv*(children: ptr PIhandle): PIhandle {. - importc: "IupVboxv", cdecl, dynlib: dllname.} -proc zbox*(child: PIhandle): PIhandle {. - importc: "IupZbox", cdecl, dynlib: dllname, varargs.} -proc zboxv*(children: ptr PIhandle): PIhandle {. - importc: "IupZboxv", cdecl, dynlib: dllname.} -proc hbox*(child: PIhandle): PIhandle {. - importc: "IupHbox", cdecl, dynlib: dllname, varargs.} -proc hboxv*(children: ptr PIhandle): PIhandle {. - importc: "IupHboxv", cdecl, dynlib: dllname.} - -proc normalizer*(ihFirst: PIhandle): PIhandle {. - importc: "IupNormalizer", cdecl, dynlib: dllname, varargs.} -proc normalizerv*(ihList: ptr PIhandle): PIhandle {. - importc: "IupNormalizerv", cdecl, dynlib: dllname.} - -proc cbox*(child: PIhandle): PIhandle {. - importc: "IupCbox", cdecl, dynlib: dllname, varargs.} -proc cboxv*(children: ptr PIhandle): PIhandle {. - importc: "IupCboxv", cdecl, dynlib: dllname.} -proc sbox*(child: PIhandle): PIhandle {. - importc: "IupSbox", cdecl, dynlib: dllname.} - -proc frame*(child: PIhandle): PIhandle {. - importc: "IupFrame", cdecl, dynlib: dllname.} - -proc image*(width, height: cint, pixmap: pointer): PIhandle {. - importc: "IupImage", cdecl, dynlib: dllname.} -proc imageRGB*(width, height: cint, pixmap: pointer): PIhandle {. - importc: "IupImageRGB", cdecl, dynlib: dllname.} -proc imageRGBA*(width, height: cint, pixmap: pointer): PIhandle {. - importc: "IupImageRGBA", cdecl, dynlib: dllname.} - -proc item*(title, action: cstring): PIhandle {. - importc: "IupItem", cdecl, dynlib: dllname.} -proc submenu*(title: cstring, child: PIhandle): PIhandle {. - importc: "IupSubmenu", cdecl, dynlib: dllname.} -proc separator*(): PIhandle {. - importc: "IupSeparator", cdecl, dynlib: dllname.} -proc menu*(child: PIhandle): PIhandle {. - importc: "IupMenu", cdecl, dynlib: dllname, varargs.} -proc menuv*(children: ptr PIhandle): PIhandle {. - importc: "IupMenuv", cdecl, dynlib: dllname.} - -proc button*(title, action: cstring): PIhandle {. - importc: "IupButton", cdecl, dynlib: dllname.} -proc link*(url, title: cstring): PIhandle {. - importc: "IupLink", cdecl, dynlib: dllname.} -proc canvas*(action: cstring): PIhandle {. - importc: "IupCanvas", cdecl, dynlib: dllname.} -proc dialog*(child: PIhandle): PIhandle {. - importc: "IupDialog", cdecl, dynlib: dllname.} -proc user*(): PIhandle {. - importc: "IupUser", cdecl, dynlib: dllname.} -proc label*(title: cstring): PIhandle {. - importc: "IupLabel", cdecl, dynlib: dllname.} -proc list*(action: cstring): PIhandle {. - importc: "IupList", cdecl, dynlib: dllname.} -proc text*(action: cstring): PIhandle {. - importc: "IupText", cdecl, dynlib: dllname.} -proc multiLine*(action: cstring): PIhandle {. - importc: "IupMultiLine", cdecl, dynlib: dllname.} -proc toggle*(title, action: cstring): PIhandle {. - importc: "IupToggle", cdecl, dynlib: dllname.} -proc timer*(): PIhandle {. - importc: "IupTimer", cdecl, dynlib: dllname.} -proc progressBar*(): PIhandle {. - importc: "IupProgressBar", cdecl, dynlib: dllname.} -proc val*(theType: cstring): PIhandle {. - importc: "IupVal", cdecl, dynlib: dllname.} -proc tabs*(child: PIhandle): PIhandle {. - importc: "IupTabs", cdecl, dynlib: dllname, varargs.} -proc tabsv*(children: ptr PIhandle): PIhandle {. - importc: "IupTabsv", cdecl, dynlib: dllname.} -proc tree*(): PIhandle {.importc: "IupTree", cdecl, dynlib: dllname.} - -proc spin*(): PIhandle {.importc: "IupSpin", cdecl, dynlib: dllname.} -proc spinbox*(child: PIhandle): PIhandle {. - importc: "IupSpinbox", cdecl, dynlib: dllname.} - -# IupText utilities -proc textConvertLinColToPos*(ih: PIhandle, lin, col: cint, pos: var cint) {. - importc: "IupTextConvertLinColToPos", cdecl, dynlib: dllname.} -proc textConvertPosToLinCol*(ih: PIhandle, pos: cint, lin, col: var cint) {. - importc: "IupTextConvertPosToLinCol", cdecl, dynlib: dllname.} - -proc convertXYToPos*(ih: PIhandle, x, y: cint): cint {. - importc: "IupConvertXYToPos", cdecl, dynlib: dllname.} - -# IupTree utilities -proc treeSetUserId*(ih: PIhandle, id: cint, userid: pointer): cint {. - importc: "IupTreeSetUserId", cdecl, dynlib: dllname, discardable.} -proc treeGetUserId*(ih: PIhandle, id: cint): pointer {. - importc: "IupTreeGetUserId", cdecl, dynlib: dllname.} -proc treeGetId*(ih: PIhandle, userid: pointer): cint {. - importc: "IupTreeGetId", cdecl, dynlib: dllname.} - -proc treeSetAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. - importc: "IupTreeSetAttribute", cdecl, dynlib: dllname.} -proc treeStoreAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. - importc: "IupTreeStoreAttribute", cdecl, dynlib: dllname.} -proc treeGetAttribute*(ih: PIhandle, name: cstring, id: cint): cstring {. - importc: "IupTreeGetAttribute", cdecl, dynlib: dllname.} -proc treeGetInt*(ih: PIhandle, name: cstring, id: cint): cint {. - importc: "IupTreeGetInt", cdecl, dynlib: dllname.} -proc treeGetFloat*(ih: PIhandle, name: cstring, id: cint): cfloat {. - importc: "IupTreeGetFloat", cdecl, dynlib: dllname.} -proc treeSetfAttribute*(ih: PIhandle, name: cstring, id: cint, format: cstring) {. - importc: "IupTreeSetfAttribute", cdecl, dynlib: dllname, varargs.} - - -# Common Return Values -const - IUP_ERROR* = cint(1) - IUP_NOERROR* = cint(0) - IUP_OPENED* = cint(-1) - IUP_INVALID* = cint(-1) - - # Callback Return Values - IUP_IGNORE* = cint(-1) - IUP_DEFAULT* = cint(-2) - IUP_CLOSE* = cint(-3) - IUP_CONTINUE* = cint(-4) - - # IupPopup and IupShowXY Parameter Values - IUP_CENTER* = cint(0xFFFF) - IUP_LEFT* = cint(0xFFFE) - IUP_RIGHT* = cint(0xFFFD) - IUP_MOUSEPOS* = cint(0xFFFC) - IUP_CURRENT* = cint(0xFFFB) - IUP_CENTERPARENT* = cint(0xFFFA) - IUP_TOP* = IUP_LEFT - IUP_BOTTOM* = IUP_RIGHT - - # SHOW_CB Callback Values - IUP_SHOW* = cint(0) - IUP_RESTORE* = cint(1) - IUP_MINIMIZE* = cint(2) - IUP_MAXIMIZE* = cint(3) - IUP_HIDE* = cint(4) - - # SCROLL_CB Callback Values - IUP_SBUP* = cint(0) - IUP_SBDN* = cint(1) - IUP_SBPGUP* = cint(2) - IUP_SBPGDN* = cint(3) - IUP_SBPOSV* = cint(4) - IUP_SBDRAGV* = cint(5) - IUP_SBLEFT* = cint(6) - IUP_SBRIGHT* = cint(7) - IUP_SBPGLEFT* = cint(8) - IUP_SBPGRIGHT* = cint(9) - IUP_SBPOSH* = cint(10) - IUP_SBDRAGH* = cint(11) - - # Mouse Button Values and Macros - IUP_BUTTON1* = cint(ord('1')) - IUP_BUTTON2* = cint(ord('2')) - IUP_BUTTON3* = cint(ord('3')) - IUP_BUTTON4* = cint(ord('4')) - IUP_BUTTON5* = cint(ord('5')) - -proc isShift*(s: cstring): bool = return s[0] == 'S' -proc isControl*(s: cstring): bool = return s[1] == 'C' -proc isButton1*(s: cstring): bool = return s[2] == '1' -proc isButton2*(s: cstring): bool = return s[3] == '2' -proc isbutton3*(s: cstring): bool = return s[4] == '3' -proc isDouble*(s: cstring): bool = return s[5] == 'D' -proc isAlt*(s: cstring): bool = return s[6] == 'A' -proc isSys*(s: cstring): bool = return s[7] == 'Y' -proc isButton4*(s: cstring): bool = return s[8] == '4' -proc isButton5*(s: cstring): bool = return s[9] == '5' - -# Pre-Defined Masks -const - IUP_MASK_FLOAT* = "[+/-]?(/d+/.?/d*|/./d+)" - IUP_MASK_UFLOAT* = "(/d+/.?/d*|/./d+)" - IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?" - IUP_MASK_INT* = "[+/-]?/d+" - IUP_MASK_UINT* = "/d+" - -# from 32 to 126, all character sets are equal, -# the key code i the same as the character code. -const - K_SP* = cint(ord(' ')) - K_exclam* = cint(ord('!')) - K_quotedbl* = cint(ord('\"')) - K_numbersign* = cint(ord('#')) - K_dollar* = cint(ord('$')) - K_percent* = cint(ord('%')) - K_ampersand* = cint(ord('&')) - K_apostrophe* = cint(ord('\'')) - K_parentleft* = cint(ord('(')) - K_parentright* = cint(ord(')')) - K_asterisk* = cint(ord('*')) - K_plus* = cint(ord('+')) - K_comma* = cint(ord(',')) - K_minus* = cint(ord('-')) - K_period* = cint(ord('.')) - K_slash* = cint(ord('/')) - K_0* = cint(ord('0')) - K_1* = cint(ord('1')) - K_2* = cint(ord('2')) - K_3* = cint(ord('3')) - K_4* = cint(ord('4')) - K_5* = cint(ord('5')) - K_6* = cint(ord('6')) - K_7* = cint(ord('7')) - K_8* = cint(ord('8')) - K_9* = cint(ord('9')) - K_colon* = cint(ord(':')) - K_semicolon* = cint(ord(';')) - K_less* = cint(ord('<')) - K_equal* = cint(ord('=')) - K_greater* = cint(ord('>')) - K_question* = cint(ord('?')) - K_at* = cint(ord('@')) - K_upperA* = cint(ord('A')) - K_upperB* = cint(ord('B')) - K_upperC* = cint(ord('C')) - K_upperD* = cint(ord('D')) - K_upperE* = cint(ord('E')) - K_upperF* = cint(ord('F')) - K_upperG* = cint(ord('G')) - K_upperH* = cint(ord('H')) - K_upperI* = cint(ord('I')) - K_upperJ* = cint(ord('J')) - K_upperK* = cint(ord('K')) - K_upperL* = cint(ord('L')) - K_upperM* = cint(ord('M')) - K_upperN* = cint(ord('N')) - K_upperO* = cint(ord('O')) - K_upperP* = cint(ord('P')) - K_upperQ* = cint(ord('Q')) - K_upperR* = cint(ord('R')) - K_upperS* = cint(ord('S')) - K_upperT* = cint(ord('T')) - K_upperU* = cint(ord('U')) - K_upperV* = cint(ord('V')) - K_upperW* = cint(ord('W')) - K_upperX* = cint(ord('X')) - K_upperY* = cint(ord('Y')) - K_upperZ* = cint(ord('Z')) - K_bracketleft* = cint(ord('[')) - K_backslash* = cint(ord('\\')) - K_bracketright* = cint(ord(']')) - K_circum* = cint(ord('^')) - K_underscore* = cint(ord('_')) - K_grave* = cint(ord('`')) - K_lowera* = cint(ord('a')) - K_lowerb* = cint(ord('b')) - K_lowerc* = cint(ord('c')) - K_lowerd* = cint(ord('d')) - K_lowere* = cint(ord('e')) - K_lowerf* = cint(ord('f')) - K_lowerg* = cint(ord('g')) - K_lowerh* = cint(ord('h')) - K_loweri* = cint(ord('i')) - K_lowerj* = cint(ord('j')) - K_lowerk* = cint(ord('k')) - K_lowerl* = cint(ord('l')) - K_lowerm* = cint(ord('m')) - K_lowern* = cint(ord('n')) - K_lowero* = cint(ord('o')) - K_lowerp* = cint(ord('p')) - K_lowerq* = cint(ord('q')) - K_lowerr* = cint(ord('r')) - K_lowers* = cint(ord('s')) - K_lowert* = cint(ord('t')) - K_loweru* = cint(ord('u')) - K_lowerv* = cint(ord('v')) - K_lowerw* = cint(ord('w')) - K_lowerx* = cint(ord('x')) - K_lowery* = cint(ord('y')) - K_lowerz* = cint(ord('z')) - K_braceleft* = cint(ord('{')) - K_bar* = cint(ord('|')) - K_braceright* = cint(ord('}')) - K_tilde* = cint(ord('~')) - -proc isPrint*(c: cint): bool = return c > 31 and c < 127 - -# also define the escape sequences that have keys associated -const - K_BS* = cint(ord('\b')) - K_TAB* = cint(ord('\t')) - K_LF* = cint(10) - K_CR* = cint(13) - -# IUP Extended Key Codes, range start at 128 -# Modifiers use 256 interval -# These key code definitions are specific to IUP - -proc isXkey*(c: cint): bool = return c > 128 -proc isShiftXkey*(c: cint): bool = return c > 256 and c < 512 -proc isCtrlXkey*(c: cint): bool = return c > 512 and c < 768 -proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024 -proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280 - -proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128) -proc iUPsxCODE*(c: cint): cint = - return c + cint(256) - # Shift (must have range to include the standard keys and the normal - # extended keys, so must be above 256 - -proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl -proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt -proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) - -const - IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys - - K_HOME* = iUPxCODE(1) - K_UP* = iUPxCODE(2) - K_PGUP* = iUPxCODE(3) - K_LEFT* = iUPxCODE(4) - K_MIDDLE* = iUPxCODE(5) - K_RIGHT* = iUPxCODE(6) - K_END* = iUPxCODE(7) - K_DOWN* = iUPxCODE(8) - K_PGDN* = iUPxCODE(9) - K_INS* = iUPxCODE(10) - K_DEL* = iUPxCODE(11) - K_PAUSE* = iUPxCODE(12) - K_ESC* = iUPxCODE(13) - K_ccedilla* = iUPxCODE(14) - K_F1* = iUPxCODE(15) - K_F2* = iUPxCODE(16) - K_F3* = iUPxCODE(17) - K_F4* = iUPxCODE(18) - K_F5* = iUPxCODE(19) - K_F6* = iUPxCODE(20) - K_F7* = iUPxCODE(21) - K_F8* = iUPxCODE(22) - K_F9* = iUPxCODE(23) - K_F10* = iUPxCODE(24) - K_F11* = iUPxCODE(25) - K_F12* = iUPxCODE(26) - K_Print* = iUPxCODE(27) - K_Menu* = iUPxCODE(28) - - K_acute* = iUPxCODE(29) # no Shift/Ctrl/Alt - - K_sHOME* = iUPsxCODE(K_HOME) - K_sUP* = iUPsxCODE(K_UP) - K_sPGUP* = iUPsxCODE(K_PGUP) - K_sLEFT* = iUPsxCODE(K_LEFT) - K_sMIDDLE* = iUPsxCODE(K_MIDDLE) - K_sRIGHT* = iUPsxCODE(K_RIGHT) - K_sEND* = iUPsxCODE(K_END) - K_sDOWN* = iUPsxCODE(K_DOWN) - K_sPGDN* = iUPsxCODE(K_PGDN) - K_sINS* = iUPsxCODE(K_INS) - K_sDEL* = iUPsxCODE(K_DEL) - K_sSP* = iUPsxCODE(K_SP) - K_sTAB* = iUPsxCODE(K_TAB) - K_sCR* = iUPsxCODE(K_CR) - K_sBS* = iUPsxCODE(K_BS) - K_sPAUSE* = iUPsxCODE(K_PAUSE) - K_sESC* = iUPsxCODE(K_ESC) - K_sCcedilla* = iUPsxCODE(K_ccedilla) - K_sF1* = iUPsxCODE(K_F1) - K_sF2* = iUPsxCODE(K_F2) - K_sF3* = iUPsxCODE(K_F3) - K_sF4* = iUPsxCODE(K_F4) - K_sF5* = iUPsxCODE(K_F5) - K_sF6* = iUPsxCODE(K_F6) - K_sF7* = iUPsxCODE(K_F7) - K_sF8* = iUPsxCODE(K_F8) - K_sF9* = iUPsxCODE(K_F9) - K_sF10* = iUPsxCODE(K_F10) - K_sF11* = iUPsxCODE(K_F11) - K_sF12* = iUPsxCODE(K_F12) - K_sPrint* = iUPsxCODE(K_Print) - K_sMenu* = iUPsxCODE(K_Menu) - - K_cHOME* = iUPcxCODE(K_HOME) - K_cUP* = iUPcxCODE(K_UP) - K_cPGUP* = iUPcxCODE(K_PGUP) - K_cLEFT* = iUPcxCODE(K_LEFT) - K_cMIDDLE* = iUPcxCODE(K_MIDDLE) - K_cRIGHT* = iUPcxCODE(K_RIGHT) - K_cEND* = iUPcxCODE(K_END) - K_cDOWN* = iUPcxCODE(K_DOWN) - K_cPGDN* = iUPcxCODE(K_PGDN) - K_cINS* = iUPcxCODE(K_INS) - K_cDEL* = iUPcxCODE(K_DEL) - K_cSP* = iUPcxCODE(K_SP) - K_cTAB* = iUPcxCODE(K_TAB) - K_cCR* = iUPcxCODE(K_CR) - K_cBS* = iUPcxCODE(K_BS) - K_cPAUSE* = iUPcxCODE(K_PAUSE) - K_cESC* = iUPcxCODE(K_ESC) - K_cCcedilla* = iUPcxCODE(K_ccedilla) - K_cF1* = iUPcxCODE(K_F1) - K_cF2* = iUPcxCODE(K_F2) - K_cF3* = iUPcxCODE(K_F3) - K_cF4* = iUPcxCODE(K_F4) - K_cF5* = iUPcxCODE(K_F5) - K_cF6* = iUPcxCODE(K_F6) - K_cF7* = iUPcxCODE(K_F7) - K_cF8* = iUPcxCODE(K_F8) - K_cF9* = iUPcxCODE(K_F9) - K_cF10* = iUPcxCODE(K_F10) - K_cF11* = iUPcxCODE(K_F11) - K_cF12* = iUPcxCODE(K_F12) - K_cPrint* = iUPcxCODE(K_Print) - K_cMenu* = iUPcxCODE(K_Menu) - - K_mHOME* = iUPmxCODE(K_HOME) - K_mUP* = iUPmxCODE(K_UP) - K_mPGUP* = iUPmxCODE(K_PGUP) - K_mLEFT* = iUPmxCODE(K_LEFT) - K_mMIDDLE* = iUPmxCODE(K_MIDDLE) - K_mRIGHT* = iUPmxCODE(K_RIGHT) - K_mEND* = iUPmxCODE(K_END) - K_mDOWN* = iUPmxCODE(K_DOWN) - K_mPGDN* = iUPmxCODE(K_PGDN) - K_mINS* = iUPmxCODE(K_INS) - K_mDEL* = iUPmxCODE(K_DEL) - K_mSP* = iUPmxCODE(K_SP) - K_mTAB* = iUPmxCODE(K_TAB) - K_mCR* = iUPmxCODE(K_CR) - K_mBS* = iUPmxCODE(K_BS) - K_mPAUSE* = iUPmxCODE(K_PAUSE) - K_mESC* = iUPmxCODE(K_ESC) - K_mCcedilla* = iUPmxCODE(K_ccedilla) - K_mF1* = iUPmxCODE(K_F1) - K_mF2* = iUPmxCODE(K_F2) - K_mF3* = iUPmxCODE(K_F3) - K_mF4* = iUPmxCODE(K_F4) - K_mF5* = iUPmxCODE(K_F5) - K_mF6* = iUPmxCODE(K_F6) - K_mF7* = iUPmxCODE(K_F7) - K_mF8* = iUPmxCODE(K_F8) - K_mF9* = iUPmxCODE(K_F9) - K_mF10* = iUPmxCODE(K_F10) - K_mF11* = iUPmxCODE(K_F11) - K_mF12* = iUPmxCODE(K_F12) - K_mPrint* = iUPmxCODE(K_Print) - K_mMenu* = iUPmxCODE(K_Menu) - - K_yHOME* = iUPyxCODE(K_HOME) - K_yUP* = iUPyxCODE(K_UP) - K_yPGUP* = iUPyxCODE(K_PGUP) - K_yLEFT* = iUPyxCODE(K_LEFT) - K_yMIDDLE* = iUPyxCODE(K_MIDDLE) - K_yRIGHT* = iUPyxCODE(K_RIGHT) - K_yEND* = iUPyxCODE(K_END) - K_yDOWN* = iUPyxCODE(K_DOWN) - K_yPGDN* = iUPyxCODE(K_PGDN) - K_yINS* = iUPyxCODE(K_INS) - K_yDEL* = iUPyxCODE(K_DEL) - K_ySP* = iUPyxCODE(K_SP) - K_yTAB* = iUPyxCODE(K_TAB) - K_yCR* = iUPyxCODE(K_CR) - K_yBS* = iUPyxCODE(K_BS) - K_yPAUSE* = iUPyxCODE(K_PAUSE) - K_yESC* = iUPyxCODE(K_ESC) - K_yCcedilla* = iUPyxCODE(K_ccedilla) - K_yF1* = iUPyxCODE(K_F1) - K_yF2* = iUPyxCODE(K_F2) - K_yF3* = iUPyxCODE(K_F3) - K_yF4* = iUPyxCODE(K_F4) - K_yF5* = iUPyxCODE(K_F5) - K_yF6* = iUPyxCODE(K_F6) - K_yF7* = iUPyxCODE(K_F7) - K_yF8* = iUPyxCODE(K_F8) - K_yF9* = iUPyxCODE(K_F9) - K_yF10* = iUPyxCODE(K_F10) - K_yF11* = iUPyxCODE(K_F11) - K_yF12* = iUPyxCODE(K_F12) - K_yPrint* = iUPyxCODE(K_Print) - K_yMenu* = iUPyxCODE(K_Menu) - - K_sPlus* = iUPsxCODE(K_plus) - K_sComma* = iUPsxCODE(K_comma) - K_sMinus* = iUPsxCODE(K_minus) - K_sPeriod* = iUPsxCODE(K_period) - K_sSlash* = iUPsxCODE(K_slash) - K_sAsterisk* = iUPsxCODE(K_asterisk) - - K_cupperA* = iUPcxCODE(K_upperA) - K_cupperB* = iUPcxCODE(K_upperB) - K_cupperC* = iUPcxCODE(K_upperC) - K_cupperD* = iUPcxCODE(K_upperD) - K_cupperE* = iUPcxCODE(K_upperE) - K_cupperF* = iUPcxCODE(K_upperF) - K_cupperG* = iUPcxCODE(K_upperG) - K_cupperH* = iUPcxCODE(K_upperH) - K_cupperI* = iUPcxCODE(K_upperI) - K_cupperJ* = iUPcxCODE(K_upperJ) - K_cupperK* = iUPcxCODE(K_upperK) - K_cupperL* = iUPcxCODE(K_upperL) - K_cupperM* = iUPcxCODE(K_upperM) - K_cupperN* = iUPcxCODE(K_upperN) - K_cupperO* = iUPcxCODE(K_upperO) - K_cupperP* = iUPcxCODE(K_upperP) - K_cupperQ* = iUPcxCODE(K_upperQ) - K_cupperR* = iUPcxCODE(K_upperR) - K_cupperS* = iUPcxCODE(K_upperS) - K_cupperT* = iUPcxCODE(K_upperT) - K_cupperU* = iUPcxCODE(K_upperU) - K_cupperV* = iUPcxCODE(K_upperV) - K_cupperW* = iUPcxCODE(K_upperW) - K_cupperX* = iUPcxCODE(K_upperX) - K_cupperY* = iUPcxCODE(K_upperY) - K_cupperZ* = iUPcxCODE(K_upperZ) - K_c1* = iUPcxCODE(K_1) - K_c2* = iUPcxCODE(K_2) - K_c3* = iUPcxCODE(K_3) - K_c4* = iUPcxCODE(K_4) - K_c5* = iUPcxCODE(K_5) - K_c6* = iUPcxCODE(K_6) - K_c7* = iUPcxCODE(K_7) - K_c8* = iUPcxCODE(K_8) - K_c9* = iUPcxCODE(K_9) - K_c0* = iUPcxCODE(K_0) - K_cPlus* = iUPcxCODE(K_plus) - K_cComma* = iUPcxCODE(K_comma) - K_cMinus* = iUPcxCODE(K_minus) - K_cPeriod* = iUPcxCODE(K_period) - K_cSlash* = iUPcxCODE(K_slash) - K_cSemicolon* = iUPcxCODE(K_semicolon) - K_cEqual* = iUPcxCODE(K_equal) - K_cBracketleft* = iUPcxCODE(K_bracketleft) - K_cBracketright* = iUPcxCODE(K_bracketright) - K_cBackslash* = iUPcxCODE(K_backslash) - K_cAsterisk* = iUPcxCODE(K_asterisk) - - K_mupperA* = iUPmxCODE(K_upperA) - K_mupperB* = iUPmxCODE(K_upperB) - K_mupperC* = iUPmxCODE(K_upperC) - K_mupperD* = iUPmxCODE(K_upperD) - K_mupperE* = iUPmxCODE(K_upperE) - K_mupperF* = iUPmxCODE(K_upperF) - K_mupperG* = iUPmxCODE(K_upperG) - K_mupperH* = iUPmxCODE(K_upperH) - K_mupperI* = iUPmxCODE(K_upperI) - K_mupperJ* = iUPmxCODE(K_upperJ) - K_mupperK* = iUPmxCODE(K_upperK) - K_mupperL* = iUPmxCODE(K_upperL) - K_mupperM* = iUPmxCODE(K_upperM) - K_mupperN* = iUPmxCODE(K_upperN) - K_mupperO* = iUPmxCODE(K_upperO) - K_mupperP* = iUPmxCODE(K_upperP) - K_mupperQ* = iUPmxCODE(K_upperQ) - K_mupperR* = iUPmxCODE(K_upperR) - K_mupperS* = iUPmxCODE(K_upperS) - K_mupperT* = iUPmxCODE(K_upperT) - K_mupperU* = iUPmxCODE(K_upperU) - K_mupperV* = iUPmxCODE(K_upperV) - K_mupperW* = iUPmxCODE(K_upperW) - K_mupperX* = iUPmxCODE(K_upperX) - K_mupperY* = iUPmxCODE(K_upperY) - K_mupperZ* = iUPmxCODE(K_upperZ) - K_m1* = iUPmxCODE(K_1) - K_m2* = iUPmxCODE(K_2) - K_m3* = iUPmxCODE(K_3) - K_m4* = iUPmxCODE(K_4) - K_m5* = iUPmxCODE(K_5) - K_m6* = iUPmxCODE(K_6) - K_m7* = iUPmxCODE(K_7) - K_m8* = iUPmxCODE(K_8) - K_m9* = iUPmxCODE(K_9) - K_m0* = iUPmxCODE(K_0) - K_mPlus* = iUPmxCODE(K_plus) - K_mComma* = iUPmxCODE(K_comma) - K_mMinus* = iUPmxCODE(K_minus) - K_mPeriod* = iUPmxCODE(K_period) - K_mSlash* = iUPmxCODE(K_slash) - K_mSemicolon* = iUPmxCODE(K_semicolon) - K_mEqual* = iUPmxCODE(K_equal) - K_mBracketleft* = iUPmxCODE(K_bracketleft) - K_mBracketright* = iUPmxCODE(K_bracketright) - K_mBackslash* = iUPmxCODE(K_backslash) - K_mAsterisk* = iUPmxCODE(K_asterisk) - - K_yA* = iUPyxCODE(K_upperA) - K_yB* = iUPyxCODE(K_upperB) - K_yC* = iUPyxCODE(K_upperC) - K_yD* = iUPyxCODE(K_upperD) - K_yE* = iUPyxCODE(K_upperE) - K_yF* = iUPyxCODE(K_upperF) - K_yG* = iUPyxCODE(K_upperG) - K_yH* = iUPyxCODE(K_upperH) - K_yI* = iUPyxCODE(K_upperI) - K_yJ* = iUPyxCODE(K_upperJ) - K_yK* = iUPyxCODE(K_upperK) - K_yL* = iUPyxCODE(K_upperL) - K_yM* = iUPyxCODE(K_upperM) - K_yN* = iUPyxCODE(K_upperN) - K_yO* = iUPyxCODE(K_upperO) - K_yP* = iUPyxCODE(K_upperP) - K_yQ* = iUPyxCODE(K_upperQ) - K_yR* = iUPyxCODE(K_upperR) - K_yS* = iUPyxCODE(K_upperS) - K_yT* = iUPyxCODE(K_upperT) - K_yU* = iUPyxCODE(K_upperU) - K_yV* = iUPyxCODE(K_upperV) - K_yW* = iUPyxCODE(K_upperW) - K_yX* = iUPyxCODE(K_upperX) - K_yY* = iUPyxCODE(K_upperY) - K_yZ* = iUPyxCODE(K_upperZ) - K_y1* = iUPyxCODE(K_1) - K_y2* = iUPyxCODE(K_2) - K_y3* = iUPyxCODE(K_3) - K_y4* = iUPyxCODE(K_4) - K_y5* = iUPyxCODE(K_5) - K_y6* = iUPyxCODE(K_6) - K_y7* = iUPyxCODE(K_7) - K_y8* = iUPyxCODE(K_8) - K_y9* = iUPyxCODE(K_9) - K_y0* = iUPyxCODE(K_0) - K_yPlus* = iUPyxCODE(K_plus) - K_yComma* = iUPyxCODE(K_comma) - K_yMinus* = iUPyxCODE(K_minus) - K_yPeriod* = iUPyxCODE(K_period) - K_ySlash* = iUPyxCODE(K_slash) - K_ySemicolon* = iUPyxCODE(K_semicolon) - K_yEqual* = iUPyxCODE(K_equal) - K_yBracketleft* = iUPyxCODE(K_bracketleft) - K_yBracketright* = iUPyxCODE(K_bracketright) - K_yBackslash* = iUPyxCODE(K_backslash) - K_yAsterisk* = iUPyxCODE(K_asterisk) - -proc controlsOpen*(): cint {.cdecl, importc: "IupControlsOpen", dynlib: dllname.} -proc controlsClose*() {.cdecl, importc: "IupControlsClose", dynlib: dllname.} - -proc oldValOpen*() {.cdecl, importc: "IupOldValOpen", dynlib: dllname.} -proc oldTabsOpen*() {.cdecl, importc: "IupOldTabsOpen", dynlib: dllname.} - -proc colorbar*(): PIhandle {.cdecl, importc: "IupColorbar", dynlib: dllname.} -proc cells*(): PIhandle {.cdecl, importc: "IupCells", dynlib: dllname.} -proc colorBrowser*(): PIhandle {.cdecl, importc: "IupColorBrowser", dynlib: dllname.} -proc gauge*(): PIhandle {.cdecl, importc: "IupGauge", dynlib: dllname.} -proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dllname.} -proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.} - -# IupMatrix utilities -proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, - value: cstring) {. - cdecl, importc: "IupMatSetAttribute", dynlib: dllname.} -proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, - value: cstring) {.cdecl, - importc: "IupMatStoreAttribute", dynlib: dllname.} -proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {. - cdecl, importc: "IupMatGetAttribute", dynlib: dllname.} -proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {. - cdecl, importc: "IupMatGetInt", dynlib: dllname.} -proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {. - cdecl, importc: "IupMatGetFloat", dynlib: dllname.} -proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, - format: cstring) {.cdecl, - importc: "IupMatSetfAttribute", - dynlib: dllname, varargs.} - -# Used by IupColorbar -const - IUP_PRIMARY* = -1 - IUP_SECONDARY* = -2 - -# Initialize PPlot widget class -proc pPlotOpen*() {.cdecl, importc: "IupPPlotOpen", dynlib: dllname.} - -# Create an PPlot widget instance -proc pPlot*: PIhandle {.cdecl, importc: "IupPPlot", dynlib: dllname.} - -# Add dataset to plot -proc pPlotBegin*(ih: PIhandle, strXdata: cint) {. - cdecl, importc: "IupPPlotBegin", dynlib: dllname.} -proc pPlotAdd*(ih: PIhandle, x, y: cfloat) {. - cdecl, importc: "IupPPlotAdd", dynlib: dllname.} -proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {. - cdecl, importc: "IupPPlotAddStr", dynlib: dllname.} -proc pPlotEnd*(ih: PIhandle): cint {. - cdecl, importc: "IupPPlotEnd", dynlib: dllname.} - -proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring, - y: cfloat) {.cdecl, importc: "IupPPlotInsertStr", - dynlib: dllname.} -proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint, - x, y: cfloat) {. - cdecl, importc: "IupPPlotInsert", dynlib: dllname.} - -# convert from plot coordinates to pixels -proc pPlotTransform*(ih: PIhandle, x, y: cfloat, ix, iy: var cint) {. - cdecl, importc: "IupPPlotTransform", dynlib: dllname.} - -# Plot on the given device. Uses a "cdCanvas*". -proc pPlotPaintTo*(ih: PIhandle, cnv: pointer) {. - cdecl, importc: "IupPPlotPaintTo", dynlib: dllname.} - - diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index ba2963cfd..81ab265f2 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -127,7 +127,6 @@ lib/system/channels.nim withoutIndex = """ lib/wrappers/mysql.nim -lib/wrappers/iup.nim lib/wrappers/sqlite3.nim lib/wrappers/postgres.nim lib/wrappers/tinyc.nim From 7d640e0943679a772f9595ef3be56fe2158b0912 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 4 Nov 2020 14:24:40 +0800 Subject: [PATCH 1389/4254] fix #15835 (#15838) * fix #15835 * add tests --- lib/pure/json.nim | 2 ++ tests/stdlib/t15835.nim | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/stdlib/t15835.nim diff --git a/lib/pure/json.nim b/lib/pure/json.nim index f3145301f..a3f7a782e 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1052,6 +1052,8 @@ when defined(nimFixedForwardGeneric): dst = jsonNode.bval proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = + if jsonNode == nil: + raise newException(KeyError, "key not found: " & jsonPath) dst = jsonNode.copy proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = diff --git a/tests/stdlib/t15835.nim b/tests/stdlib/t15835.nim new file mode 100644 index 000000000..bddfa87aa --- /dev/null +++ b/tests/stdlib/t15835.nim @@ -0,0 +1,17 @@ +import json + +type + Foo = object + ii*: int + data*: JsonNode + +block: + const jt = """{"ii": 123, "data": ["some", "data"]}""" + let js = parseJson(jt) + discard js.to(Foo) + +block: + const jt = """{"ii": 123}""" + let js = parseJson(jt) + doAssertRaises(KeyError): + echo js.to(Foo) From f17555770e816580b475674be23458da51b10dfd Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 4 Nov 2020 10:56:22 -0500 Subject: [PATCH 1390/4254] Clarify the sense in which Nim supports recursive iterators in the (#15834) manual, the tutorial, and the `tbintree` test. --- doc/manual.rst | 43 ++++++++++++++++++++++++++++++++++--- doc/tut2.rst | 4 ++-- tests/generics/tbintree.nim | 4 ++-- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index d09bb4c76..d9f9cc9b9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4031,10 +4031,13 @@ Closure iterators and inline iterators have some restrictions: 1. For now, a closure iterator cannot be executed at compile time. 2. ``return`` is allowed in a closure iterator but not in an inline iterator (but rarely useful) and ends the iteration. -3. Neither inline nor closure iterators can be recursive. +3. Neither inline nor closure iterators can be (directly)* recursive. 4. Neither inline nor closure iterators have the special ``result`` variable. 5. Closure iterators are not supported by the js backend. +(*) Closure iterators can be co-recursive with a factory proc which results +in similar syntax to a recursive iterator. More details follow. + Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly default to being inline, but this may change in future versions of the implementation. @@ -4129,7 +4132,41 @@ parameters of an outer factory proc: for f in foo(): echo f +The call can be made more like an inline iterator with a for loop macro: +.. code-block:: nim + import macros + macro toItr(x: ForLoopStmt): untyped = + let expr = x[0] + let call = x[1][1] # Get foo out of toItr(foo) + let body = x[2] + result = quote do: + block: + let itr = `call` + for `expr` in itr(): + `body` + + for f in toItr(mycount(1, 4)): # using early `proc mycount` + echo f + +Because of full backend function call aparatus involvment, closure iterator +invocation is typically higher cost than inline iterators. Adornment by +a macro wrapper at the call site like this is a possibly useful reminder. + +The factory ``proc``, as an ordinary procedure, can be recursive. The +above macro allows such recursion to look much like a recursive iterator +would. For example: + +.. code-block:: nim + proc recCountDown(n: int): iterator(): int = + result = iterator(): int = + if n > 0: + yield n + for e in toItr(recCountDown(n - 1)): + yield e + + for i in toItr(recCountDown(6)): # Emits: 6 5 4 3 2 1 + echo i Converters ========== @@ -4619,8 +4656,8 @@ The following example shows a generic binary tree can be modeled: iterator preorder*[T](root: BinaryTree[T]): T = # Preorder traversal of a binary tree. - # Since recursive iterators are not yet implemented, - # this uses an explicit stack (which is more efficient anyway): + # This uses an explicit stack (which is more efficient than + # a recursive iterator factory). var stack: seq[BinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() diff --git a/doc/tut2.rst b/doc/tut2.rst index 577b65622..94725a5d8 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -511,8 +511,8 @@ containers: iterator preorder*[T](root: BinaryTree[T]): T = # Preorder traversal of a binary tree. - # Since recursive iterators are not yet implemented, - # this uses an explicit stack (which is more efficient anyway): + # This uses an explicit stack (which is more efficient than + # a recursive iterator factory). var stack: seq[BinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() diff --git a/tests/generics/tbintree.nim b/tests/generics/tbintree.nim index a1a13c7b5..83f14406b 100644 --- a/tests/generics/tbintree.nim +++ b/tests/generics/tbintree.nim @@ -55,8 +55,8 @@ proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool = iterator preorder*[T](root: PBinaryTree[T]): T = # Preorder traversal of a binary tree. - # Since recursive iterators are not yet implemented, - # this uses an explicit stack: + # This uses an explicit stack (which is more efficient than + # a recursive iterator factory). var stack: seq[PBinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() From 4c19c5dfae01638ae66fc2c1561762d94fb36a1a Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 4 Nov 2020 18:52:53 +0000 Subject: [PATCH 1391/4254] fix static[Slice[T]] as argument issue (#15842) --- compiler/sigmatch.nim | 2 +- tests/types/tisopr.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2cf2846c0..d5039fcad 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1079,7 +1079,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return typeRel(c, f, lastSon(aOrig), flags) if a.kind == tyGenericInst and - skipTypes(f, {tyVar, tyLent, tySink}).kind notin { + skipTypes(f, {tyStatic, tyVar, tyLent, tySink}).kind notin { tyGenericBody, tyGenericInvocation, tyGenericInst, tyGenericParam} + tyTypeClasses: return typeRel(c, f, lastSon(a), flags) diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim index 1bbd0da94..533cf05be 100644 --- a/tests/types/tisopr.nim +++ b/tests/types/tisopr.nim @@ -109,3 +109,15 @@ block: doAssert Foo2[int,float|int] is Foo doAssert Foo2[int,float|int] isnot Bar doAssert int is (int|float) + + +block: + # Slice[T] as static type issue + type + MyEnum = enum + x1, x2, x3, x4, x5, x6 + + proc enumGen[T: enum](s: static[Slice[T]]) = + doAssert($s.a & " " & $s.b == "x1 x3") + + enumGen(x1..x3) From fdd25ed19c7adccaf94984e02d4222596ec08224 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 18:31:44 +0800 Subject: [PATCH 1392/4254] close #8457 (#15844) --- tests/pragmas/tcustom_pragma.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 756396529..a4a200c34 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -367,3 +367,14 @@ block: let x = RefType2() for fieldName, fieldSym in fieldPairs(x[]): doAssert hasCustomPragma(fieldSym, myCustomPragma) + +# bug 8457 +block: + template world {.pragma.} + + type + Hello = ref object + a: float32 + b {.world.}: int + + discard Hello(a: 1.0, b: 12) From dfa2f011d7e7856074729d3d809d2848b9b897c1 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 18:55:42 +0800 Subject: [PATCH 1393/4254] close #10307(add testcase for #10307) (#15840) --- tests/magics/t10307.nim | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/magics/t10307.nim diff --git a/tests/magics/t10307.nim b/tests/magics/t10307.nim new file mode 100644 index 000000000..111b0d221 --- /dev/null +++ b/tests/magics/t10307.nim @@ -0,0 +1,23 @@ +discard """ + cmd: "nim c -d:useGcAssert $file" + output: '''running someProc(true) +res: yes +yes +running someProc(false) +res: +''' +""" + +proc someProc(x:bool):cstring = + var res:string = "" + if x: + res = "yes" + echo "res: ", res + GC_ref(res) + result = res + +echo "running someProc(true)" +echo someProc(true) + +echo "running someProc(false)" +echo someProc(false) \ No newline at end of file From cae92f670a00ca1a343667dfeb5dfef208086f21 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 20:11:22 +0800 Subject: [PATCH 1394/4254] change non-working example to runnableExamples (#15841) --- lib/pure/sugar.nim | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index dd44c731d..d0f85ad17 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -57,13 +57,11 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} = macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. - ## - ## .. code-block:: nim - ## - ## proc passTwoAndTwo(f: (int, int) -> int): int = - ## f(2, 2) - ## - ## passTwoAndTwo((x, y) => x + y) # 4 + runnableExamples: + proc passTwoAndTwo(f: (int, int) -> int): int = + f(2, 2) + + doAssert passTwoAndTwo((x, y) => x + y) == 4 var params = @[ident"auto"] From a8af664e8ba8672e736c72971a18c0e00ba9b086 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 21:00:08 +0800 Subject: [PATCH 1395/4254] fix #15463 (#15831) --- compiler/lowerings.nim | 1 + compiler/vmgen.nim | 2 +- tests/vm/tswap.nim | 12 +++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 40d61b779..e9e704075 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -138,6 +138,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextId(idgen), owner, n.info, owner.options) temp.typ = n[1].typ incl(temp.flags, sfFromGeneric) + incl(temp.flags, sfGenSym) var v = newNodeI(nkVarSection, n.info) let tempAsNode = newSymNode(temp) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 61c7fefd9..bcb7faa47 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1122,7 +1122,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(d) of mSwap: unused(c, n, dest) - c.gen(lowerSwap(c.graph, n, c.idgen, if c.prc == nil: c.module else: c.prc.sym)) + c.gen(lowerSwap(c.graph, n, c.idgen, if c.prc == nil or c.prc.sym == nil: c.module else: c.prc.sym)) of mIsNil: genUnaryABC(c, n, dest, opcIsNil) of mParseBiggestFloat: if dest < 0: dest = c.getTemp(n.typ) diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim index 4243b5a71..bdbe5528c 100644 --- a/tests/vm/tswap.nim +++ b/tests/vm/tswap.nim @@ -3,7 +3,9 @@ nimout: ''' x.data = @[10] y = @[11] x.data = @[11] -y = @[10]''' +y = @[10] +@[3, 2, 1] +''' """ # bug #2946 @@ -22,3 +24,11 @@ proc testSwap(): int {.compiletime.} = result = 99 const something = testSwap() + +# bug #15463 +block: + static: + var s = @[1, 2, 3] + swap(s[0], s[2]) + + echo s From 8e1fa84b0d44bc6fb995992becf659d62b36713a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 21:00:49 +0800 Subject: [PATCH 1396/4254] fix #15663 (#15839) [backport:1.4] --- lib/system/widestrs.nim | 7 +++++++ tests/stdlib/t15663.nim | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/stdlib/t15663.nim diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 6d54bce9b..955fab46a 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -214,3 +214,10 @@ proc `$`*(w: WideCString, estimate: int, replacement: int = 0xFFFD): string = proc `$`*(s: WideCString): string = result = s $ 80 + +when defined(nimv2): + proc `$`*(s: WideCStringObj, estimate: int, replacement: int = 0xFFFD): string = + `$`(s.data, estimate, replacement) + + proc `$`*(s: WideCStringObj): string = + $(s.data) diff --git a/tests/stdlib/t15663.nim b/tests/stdlib/t15663.nim new file mode 100644 index 000000000..1ad5677fd --- /dev/null +++ b/tests/stdlib/t15663.nim @@ -0,0 +1,7 @@ +discard """ + cmd: "nim c --gc:arc $file" + output: "Test" +""" + +let ws = newWideCString("Test") +echo ws \ No newline at end of file From c4cc907433a3ac2e5373cb0190ece145bfc047bb Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 21:01:28 +0800 Subject: [PATCH 1397/4254] fix adding empty sequence to HTTP headers (#15783) * fix adding empty sequence to HTTP headers * add tests --- lib/pure/httpcore.nim | 11 +++++++---- tests/stdlib/thttpcore.nim | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index af1bfc088..d796c788d 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -166,9 +166,12 @@ proc `[]=`*(headers: HttpHeaders, key, value: string) = proc `[]=`*(headers: HttpHeaders, key: string, value: seq[string]) = ## Sets the header entries associated with ``key`` to the specified list of - ## values. - ## Replaces any existing values. - headers.table[headers.toCaseInsensitive(key)] = value + ## values. Replaces any existing values. If ``value`` is empty, + ## deletes the header entries associated with ``key``. + if value.len > 0: + headers.table[headers.toCaseInsensitive(key)] = value + else: + headers.table.del(headers.toCaseInsensitive(key)) proc add*(headers: HttpHeaders, key, value: string) = ## Adds the specified value to the specified key. Appends to any existing @@ -179,7 +182,7 @@ proc add*(headers: HttpHeaders, key, value: string) = headers.table[headers.toCaseInsensitive(key)].add(value) proc del*(headers: HttpHeaders, key: string) = - ## Delete the header entries associated with ``key`` + ## Deletes the header entries associated with ``key`` headers.table.del(headers.toCaseInsensitive(key)) iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index 33c24453e..cb1a0875f 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -51,3 +51,30 @@ suite "httpcore": doAssert parseHeader("Accept: foo, bar") == (key: "Accept", value: @["foo", "bar"]) doAssert parseHeader("Accept: foo, bar, prologue") == (key: "Accept", value: @["foo", "bar", "prologue"]) doAssert parseHeader("Accept: foo, bar, prologue, starlight") == (key: "Accept", value: @["foo", "bar", "prologue", "starlight"]) + + test "add empty sequence to HTTP headers": + block: + var headers = newHttpHeaders() + headers["empty"] = @[] + + doAssert not headers.hasKey("empty") + + block: + var headers = newHttpHeaders() + headers["existing"] = "true" + headers["existing"] = @[] + + doAssert not headers.hasKey("existing") + + block: + var headers = newHttpHeaders() + headers["existing"] = @["true"] + headers["existing"] = @[] + + doAssert not headers.hasKey("existing") + + block: + var headers = newHttpHeaders() + headers["existing"] = @[] + headers["existing"] = @["true"] + doAssert headers.hasKey("existing") From adde5ba6b06e12f74c7746f93883ad009cfb00b8 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 5 Nov 2020 21:04:24 +0800 Subject: [PATCH 1398/4254] document #15618 (#15810) * document #15618 * Update lib/pure/unittest.nim * Update lib/pure/unittest.nim Co-authored-by: Juan Carlos * Update lib/pure/unittest.nim Co-authored-by: Andreas Rumpf Co-authored-by: Juan Carlos --- lib/pure/unittest.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 0536956e9..617b8ab78 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -92,6 +92,15 @@ ## discard v[4] ## ## echo "suite teardown: run once after the tests" +## +## Limitations/Bugs +## ================ +## Since `check` will rewrite some programs for +## supporting checkpoints (namely assigns expressions to variables). +## Some type conversions are not supported. +## For example `check 4.0 == 2 + 2` won't work. But `doAssert 4.0 == 2 + 2` works. +## Make sure both sides of the operator (such as `==`, `>=` and so on) have the same type. +## import std/private/since import std/exitprocs From 9455a0c3e324e13a4a49da7ccecc098bfe895a7f Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 5 Nov 2020 13:51:45 +0000 Subject: [PATCH 1399/4254] close #11142 (#15847) --- tests/types/tisopr.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim index 533cf05be..67f1ce0c1 100644 --- a/tests/types/tisopr.nim +++ b/tests/types/tisopr.nim @@ -121,3 +121,17 @@ block: doAssert($s.a & " " & $s.b == "x1 x3") enumGen(x1..x3) + +block: + # issue #11142 + type + MyObjParam[N: static int] = object + x: int + + MyObj[P: static MyObjParam] = object + y: int + + const P = MyObjParam[256](x: 2) + let Q = MyObj[P](y: 2) + doAssert($Q == "(y: 2)") + From 3aab6a409d0a02874717b1e10ca54a32da35cd1a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 5 Nov 2020 14:56:44 +0100 Subject: [PATCH 1400/4254] micro improvements (#15849) --- doc/destructors.rst | 2 +- lib/system/excpt.nim | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index ff09d6644..66f1043b3 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -522,7 +522,7 @@ a form of copy elision. To see how and when we can do that, think about this question: In `dest = src` when do we really have to *materialize* the full copy? - Only if `dest` or `src` are mutated -afterward. If `dest` is a local variable that is simple to analyze. And if `src` is a +afterwards. If `dest` is a local variable that is simple to analyze. And if `src` is a location derived from a formal parameter, we also know it is not mutated! In other words, we do a compile-time copy-on-write analysis. diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index c189f116d..04c5d3ce8 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -554,7 +554,8 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = when defined(cpp) and appType != "lib" and not gotoBasedExceptions and not defined(js) and not defined(nimscript) and - hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions): + hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions) and + not defined(nimQuirky): type StdException {.importcpp: "std::exception", header: "".} = object From 3af7818af4bb541e24146fa8f8334cf7c0b53128 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 5 Nov 2020 17:55:52 +0000 Subject: [PATCH 1401/4254] Fix #12636 (#15850) * close #11142 * fix #12636 * undo unwanted changes * fix illegal recursion case --- compiler/sizealignoffsetimpl.nim | 8 ++++++-- tests/misc/tsizeof.nim | 14 +++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 2c764fe12..b50777c9e 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -258,12 +258,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = of tyArray: computeSizeAlign(conf, typ[1]) - let elemSize = typ[1].size + let elemSize = typ[1].size + let len = lengthOrd(conf, typ[0]) if elemSize < 0: typ.size = elemSize typ.align = int16(elemSize) + elif len < 0: + typ.size = szUnknownSize + typ.align = szUnknownSize else: - typ.size = toInt64Checked(lengthOrd(conf, typ[0]) * int32(elemSize), szTooBigSize) + typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize) typ.align = typ[1].align of tyUncheckedArray: diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index a09265667..0d96a5e04 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -361,6 +361,16 @@ testinstance: y: int32 z: AnotherEnum + Stack[N: static int, T: object] = object + pad: array[128 - sizeof(array[N, ptr T]) - sizeof(int) - sizeof(pointer), byte] + stack: array[N, ptr T] + len*: int + rawMem: ptr array[N, T] + + Stack2[T: object] = object + pad: array[128 - sizeof(array[sizeof(T), ptr T]), byte] + + const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time proc main(): void = @@ -377,6 +387,8 @@ testinstance: var po : PaddingOfSetEnum33 var capo: MyCustomAlignPackedObject var issue15516: MyObject + var issue12636_1: Stack[5, MyObject] + var issue12636_2: Stack2[MyObject] var e1: Enum1 @@ -395,7 +407,7 @@ testinstance: else: doAssert sizeof(SimpleAlignment) > 10 - testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516) + testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516, issue12636_1, issue12636_2) type WithBitsize {.objectconfig.} = object From d1bea1f71f0318f08ddd80b75706a602753b55d4 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 5 Nov 2020 21:02:14 +0100 Subject: [PATCH 1402/4254] Tiny unittest doc fix --- lib/pure/unittest.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 617b8ab78..c0b2e7c1e 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -95,9 +95,8 @@ ## ## Limitations/Bugs ## ================ -## Since `check` will rewrite some programs for -## supporting checkpoints (namely assigns expressions to variables). -## Some type conversions are not supported. +## Since `check` will rewrite some expressions for supporting checkpoints +## (namely assigns expressions to variables), some type conversions are not supported. ## For example `check 4.0 == 2 + 2` won't work. But `doAssert 4.0 == 2 + 2` works. ## Make sure both sides of the operator (such as `==`, `>=` and so on) have the same type. ## From fa5f225efc7161110b0d4cf57e86646f2b0d97f8 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 5 Nov 2020 22:29:05 +0000 Subject: [PATCH 1403/4254] fix #15609 (#15856) * fix #15609 * fix test --- compiler/injectdestructors.nim | 19 +++++++++---------- tests/arc/tmovebug.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 0b893ede8..7e64ebfdc 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -824,14 +824,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = of nkAsgn, nkFastAsgn: if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and not isCursor(n[0], c): - # rule (self-assignment-removal): - if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym: - result = newNodeI(nkEmpty, n.info) - else: - if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: - cycleCheck(n, c) - assert n[1].kind notin {nkAsgn, nkFastAsgn} - result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s) + if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: + cycleCheck(n, c) + assert n[1].kind notin {nkAsgn, nkFastAsgn} + result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s) elif isDiscriminantField(n[0]): result = c.genDiscriminantAsgn(s, n) else: @@ -954,8 +950,11 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod result = c.genSink(dest, p(ri, c, s, consumed), isDecl) of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkSym: - if isSinkParam(ri.sym) and isLastRead(ri, c): + of nkSym: + if dest.kind == nkSym and dest.sym == ri.sym: + # rule (self-assignment-removal): + result = newNodeI(nkEmpty, dest.info) + elif isSinkParam(ri.sym) and isLastRead(ri, c): # Rule 3: `=sink`(x, z); wasMoved(z) let snk = c.genSink(dest, ri, isDecl) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 3b7a7c5df..61105b44e 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -70,6 +70,9 @@ king hi try bye +() +() +() ''' """ @@ -524,3 +527,33 @@ proc getScope2(): string = "else" echo getScope2() + + +#-------------------------------------------------------------------- +#bug #15609 + +type + Wrapper = object + discard + +proc newWrapper(): ref Wrapper = + new(result) + result + + +proc newWrapper2(a: int): ref Wrapper = + new(result) + if a > 0: + result + else: + new(Wrapper) + + +let w1 = newWrapper() +echo $w1[] + +let w2 = newWrapper2(1) +echo $w2[] + +let w3 = newWrapper2(-1) +echo $w3[] \ No newline at end of file From cdd459dd60e7cf69868ac23e754e8047df6afddc Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 6 Nov 2020 09:25:43 +0000 Subject: [PATCH 1404/4254] static[T] related fixes (#15853) * close #9679 * close #7546 * close #9520 * close #6177 --- compiler/semtypes.nim | 2 +- tests/statictypes/tstatictypes.nim | 101 +++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 21667895a..467645aee 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -159,7 +159,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType = var base = semTypeNode(c, n[1], nil) addSonSkipIntLit(result, base, c.idgen) if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base) - if base.kind != tyGenericParam: + if base.kind notin {tyGenericParam, tyGenericInvocation}: if not isOrdinalType(base, allowEnumWithHoles = true): localError(c.config, n.info, errOrdinalTypeExpected) elif lengthOrd(c.config, base) > MaxSetElements: diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 50dc60e09..b5c45850a 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -10,6 +10,8 @@ b is 2 times a 17 ['\x00', '\x00', '\x00', '\x00'] heyho +Val1 +Val1 ''' """ @@ -239,3 +241,102 @@ let t = T[true](foo: "hey") let u = U[false](bar: "ho") echo t.foo, u.bar + +#------------------------------------------------------------------------------ +# issue #9679 + +discard """ + output: '''''' +""" +type + Foo*[T] = object + bar*: int + dummy: T + +proc initFoo(T: type, bar: int): Foo[T] = + result.bar = 1 + +proc fails[T](x: static Foo[T]) = # Change to non-static and it compiles + doAssert($x == "(bar: 1, dummy: 0)") + +block: + const foo = initFoo(int, 2) + fails(foo) + + +import macros, tables + +var foo{.compileTime.} = [ + "Foo", + "Bar" +] + +var bar{.compileTime.} = { + 0: "Foo", + 1: "Bar" +}.toTable() + +macro fooM(): untyped = + for i, val in foo: + echo i, ": ", val + +macro barM(): untyped = + for i, val in bar: + echo i, ": ", val + +macro fooParam(x: static array[2, string]): untyped = + for i, val in x: + echo i, ": ", val + +macro barParam(x: static Table[int, string]): untyped = + for i, val in x: + echo i, ": ", val + +fooM() +barM() +fooParam(foo) +barParam(bar) + + +#----------------------------------------------------------------------------------------- +# issue #7546 +type + rangeB[N: static[int16]] = range[0'i16 .. N] + setB[N: static[int16]] = set[rangeB[N]] + +block: + var s : setB[14'i16] + + +#----------------------------------------------------------------------------------------- +# issue #9520 + +type + MyEnum = enum + Val1, Val2 + +proc myproc(a: static[MyEnum], b: int) = + if b < 0: + myproc(a, -b) + + echo $a + +myproc(Val1, -10) + + +#------------------------------------------------------------------------------------------ +# issue #6177 + +type + G[N,M:static[int], T] = object + o: T + +proc newG[N,M:static[int],T](x:var G[N,M,T], y:T) = + x.o = y+10*N+100*M + +proc newG[N,M:static[int],T](x:T):G[N,M,T] = result.newG(x) + +var x:G[2,3,int] +x.newG(4) +var y = newG[2,3,int](4) + From 218ff27b70c05340069d262204f785290467aa00 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 6 Nov 2020 18:40:14 +0800 Subject: [PATCH 1405/4254] fix #15851 (#15852) * fix #15851 * {.cast(noSideEffect).} --- lib/pure/httpcore.nim | 16 ++++++++++------ tests/effects/tstrict_funcs.nim | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index d796c788d..b3d1da8d6 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -126,12 +126,14 @@ func newHttpHeaders*(keyValuePairs: new result result.table = newTable[string, seq[string]]() result.isTitleCase = titleCase + for pair in keyValuePairs: let key = result.toCaseInsensitive(pair.key) - if key in result.table: - result.table[key].add(pair.val) - else: - result.table[key] = @[pair.val] + {.cast(noSideEffect).}: + if key in result.table: + result.table[key].add(pair.val) + else: + result.table[key] = @[pair.val] func `$`*(headers: HttpHeaders): string {.inline.} = @@ -148,7 +150,8 @@ func `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = ## ## To access multiple values of a key, use the overloaded ``[]`` below or ## to get all of them access the ``table`` field directly. - return headers.table[headers.toCaseInsensitive(key)].HttpHeaderValues + {.cast(noSideEffect).}: + return headers.table[headers.toCaseInsensitive(key)].HttpHeaderValues converter toString*(values: HttpHeaderValues): string = return seq[string](values)[0] @@ -157,7 +160,8 @@ func `[]`*(headers: HttpHeaders, key: string, i: int): string = ## Returns the ``i``'th value associated with the given key. If there are ## no values associated with the key or the ``i``'th value doesn't exist, ## an exception is raised. - return headers.table[headers.toCaseInsensitive(key)][i] + {.cast(noSideEffect).}: + return headers.table[headers.toCaseInsensitive(key)][i] proc `[]=`*(headers: HttpHeaders, key, value: string) = ## Sets the header entries associated with ``key`` to the specified value. diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 75ed9c8d9..0028e7d7e 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim c --experimental:strictFuncs --experimental:views $file" """ -import tables, streams, nre, parsecsv, uri +import tables, streams, nre, parsecsv, uri, httpcore type Contig2Reads = TableRef[string, seq[string]] From 9fd67958b97c0254c3b4d8762a7003e317ec21bb Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 6 Nov 2020 18:42:43 +0800 Subject: [PATCH 1406/4254] follow #11707(add pragmas examples for =>) (#15863) --- lib/pure/sugar.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index d0f85ad17..46dbb1ece 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -57,12 +57,22 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} = macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. + ## It also supports pragmas. runnableExamples: proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) doAssert passTwoAndTwo((x, y) => x + y) == 4 + type + Bot = object + call: proc (): string {.nosideEffect.} + + var myBot = Bot() + + myBot.call = () {.nosideEffect.} => "I'm a bot." + doAssert myBot.call() == "I'm a bot." + var params = @[ident"auto"] name = newEmptyNode() From fb60e35a5495c530f8cf5c7a8cc3005495d089f8 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 6 Nov 2020 23:39:20 +0800 Subject: [PATCH 1407/4254] close #8829(add testcase for #8829) (#15866) --- tests/overload/t8829.nim | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/overload/t8829.nim diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim new file mode 100644 index 000000000..a688e18cb --- /dev/null +++ b/tests/overload/t8829.nim @@ -0,0 +1,18 @@ +block: + let txt = "Hello World" + + template `[]`[T](p: ptr T, span: Slice[int]): untyped = + toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) + + doAssert $cast[ptr uint8](txt[0].unsafeAddr)[0 ..< txt.len] == + "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" + + +block: + let txt = "Hello World" + + template `[]`[T](p: ptr T, span: Slice[int]): untyped = + toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) + + doAssert $cast[ptr uint8](txt[0].unsafeAddr)[0 ..< txt.len] == + "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" From 60c364fb224a8b55dc7cacc5a589c569cf202ec5 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 6 Nov 2020 16:49:51 +0100 Subject: [PATCH 1408/4254] Closes #12897 (#15867) --- tests/statictypes/tstatictypes.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index b5c45850a..359ae4c9f 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -340,3 +340,12 @@ var x:G[2,3,int] x.newG(4) var y = newG[2,3,int](4) + +#------------------------------------------------------------------------------------------ +# issue #12897 + +type + TileCT[n: static int] = object + a: array[n, int] + Tile = TileCT #Commenting this out to make it work + From 3c85aa9e53cbaae5fae83f9fd29de3bdb107c7aa Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Fri, 6 Nov 2020 20:56:09 +0200 Subject: [PATCH 1409/4254] Make `{.requiresInit.}` to work for distinct types (#15869) Make `requiresInit` pragma to work for distinct types in addition to objects. Tagging of distinct types with `requiresInit` pragma was already supported, but its impact wasn't applied. Now its behavior when applied on distinct types is as follows. Given the following distinct type definitions: ```nim type DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject DistinctString {.requiresInit.} = distinct string ``` The following code blocks will fail to compile: ```nim var foo: DistinctFoo foo.x = "test" doAssert foo.x == "test" ``` ```nim var s: DistinctString s = "test" doAssert s == "test" ``` But these ones will compile successfully: ```nim let foo = DistinctFoo(Foo(x: "test")) doAssert foo.x == "test" ``` ```nim let s = "test" doAssert s == "test" ``` --- changelog.md | 2 ++ compiler/semobjconstr.nim | 21 ++++++++++++++------- compiler/semstmts.nim | 3 ++- compiler/typeallowed.nim | 3 ++- doc/manual.rst | 30 ++++++++++++++++++++++++++++++ tests/distinct/tdistinct.nim | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 871fb229d..53730ecc5 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,8 @@ ## Standard library additions and changes +- Make `{.requiresInit.}` pragma to work for `distinct` types. + - `prelude` now works with the JavaScript target. - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 64a27d1db..42529e1e5 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -355,15 +355,22 @@ proc computeRequiresInit(c: PContext, t: PType): bool = proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = var objType = t - while objType.kind != tyObject: + while objType.kind notin {tyObject, tyDistinct}: objType = objType.lastSon assert objType != nil - var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info)) - let initResult = semConstructTypeAux(c, constrCtx, {}) - assert constrCtx.missingFields.len > 0 - localError(c.config, info, - "The $1 type doesn't have a default value. The following fields must be initialized: $2.", - [typeToString(t), listSymbolNames(constrCtx.missingFields)]) + if objType.kind == tyObject: + var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info)) + let initResult = semConstructTypeAux(c, constrCtx, {}) + assert constrCtx.missingFields.len > 0 + localError(c.config, info, + "The $1 type doesn't have a default value. The following fields must " & + "be initialized: $2.", + [typeToString(t), listSymbolNames(constrCtx.missingFields)]) + elif objType.kind == tyDistinct: + localError(c.config, info, + "The $1 distinct type doesn't have a default value.", [typeToString(t)]) + else: + assert false, "Must not enter here." proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var t = semTypeNode(c, n[0], nil) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2a058eee2..4b79cd546 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -611,7 +611,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if def.kind == nkEmpty: let actualType = v.typ.skipTypes({tyGenericInst, tyAlias, tyUserTypeClassInst}) - if actualType.kind == tyObject and actualType.requiresInit: + if actualType.kind in {tyObject, tyDistinct} and + actualType.requiresInit: defaultConstructionError(c, v.typ, v.info) else: checkNilable(c, v) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index a8210508c..e163b914a 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -260,4 +260,5 @@ proc directViewType*(t: PType): ViewTypeKind = result = noView proc requiresInit*(t: PType): bool = - (t.flags * {tfRequiresInit, tfNotNil} != {}) or classifyViewType(t) != noView + (t.flags * {tfRequiresInit, tfNeedsFullInit, tfNotNil} != {}) or + classifyViewType(t) != noView diff --git a/doc/manual.rst b/doc/manual.rst index d9f9cc9b9..4e5b861b1 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2697,6 +2697,36 @@ the variable has been initialized and does not rely on syntactic properties: x = a() # use x +`requiresInit` pragma can also be applyied to `distinct` types. + +Given the following distinct type definitions: + +.. code-block:: nim + type + DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject + DistinctString {.requiresInit.} = distinct string + +The following code blocks will fail to compile: + +.. code-block:: nim + var foo: DistinctFoo + foo.x = "test" + doAssert foo.x == "test" + +.. code-block:: nim + var s: DistinctString + s = "test" + doAssert s == "test" + +But these ones will compile successfully: + +.. code-block:: nim + let foo = DistinctFoo(Foo(x: "test")) + doAssert foo.x == "test" + +.. code-block:: nim + let s = "test" + doAssert s == "test" Let statement ------------- diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index 2c0196745..d64f33443 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -106,3 +106,35 @@ type FooD = distinct int proc `<=`(a, b: FooD): bool {.borrow.} for f in [FooD(0): "Foo"]: echo f + +block tRequiresInit: + template accept(x) = + static: doAssert compiles(x) + + template reject(x) = + static: doAssert not compiles(x) + + type + Foo = object + x: string + + DistinctFoo {.requiresInit, borrow: `.`.} = distinct Foo + DistinctString {.requiresInit.} = distinct string + + reject: + var foo: DistinctFoo + foo.x = "test" + doAssert foo.x == "test" + + accept: + let foo = DistinctFoo(Foo(x: "test")) + doAssert foo.x == "test" + + reject: + var s: DistinctString + s = "test" + doAssert s == "test" + + accept: + let s = "test" + doAssert s == "test" From 5828620d47b3100e30da280442946e02c5eca18d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 7 Nov 2020 15:58:52 +0800 Subject: [PATCH 1410/4254] uint and uint64 is Ordinal type since nim 1.0.0 (#15873) --- doc/manual.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 4e5b861b1..fa28582a7 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -883,9 +883,7 @@ Ordinal types have the following characteristics: than the largest value produces a panic or a static error. Integers, bool, characters, and enumeration types (and subranges of these -types) belong to ordinal types. For reasons of simplicity of implementation -the types ``uint`` and ``uint64`` are not ordinal types. (This will be changed -in later versions of the language.) +types) belong to ordinal types. A distinct type is an ordinal type if its base type is an ordinal type. From 8f7a013cc7bf0a1f47aec8d5b2037951a36eb4f1 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 7 Nov 2020 15:59:47 +0800 Subject: [PATCH 1411/4254] close #8558(add testcase for #8558) (#15872) --- tests/concepts/t8558.nim | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/concepts/t8558.nim diff --git a/tests/concepts/t8558.nim b/tests/concepts/t8558.nim new file mode 100644 index 000000000..acb2de30e --- /dev/null +++ b/tests/concepts/t8558.nim @@ -0,0 +1,26 @@ +discard """ + output: '''10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +go! +''' +""" + +type Integral = concept x + x == 0 is bool + x - 1 is type(x) + +proc countToZero(n: Integral) = + if n == 0: echo "go!" + else: + echo n + countToZero(n-1) + +countToZero(10) \ No newline at end of file From c07807bedf1749fa9d3e826d3d736907fefbe568 Mon Sep 17 00:00:00 2001 From: Bung Date: Sat, 7 Nov 2020 16:00:41 +0800 Subject: [PATCH 1412/4254] Fix #15706 (#15846) * fix #15706 Underflow not detected when using dec on distinct ranges * fix #15846 first, jsgen even doesn't care of range in this op --- compiler/ccgexprs.nim | 2 +- tests/overflw/tdistinct_range.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/overflw/tdistinct_range.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1eb6caeb3..a3fbeca5f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2269,7 +2269,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent}) + let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyDistinct}) let res = binaryArithOverflowRaw(p, ranged, a, b, if underlying.kind == tyInt64: fun64[op] else: fun[op]) diff --git a/tests/overflw/tdistinct_range.nim b/tests/overflw/tdistinct_range.nim new file mode 100644 index 000000000..f53515d45 --- /dev/null +++ b/tests/overflw/tdistinct_range.nim @@ -0,0 +1,6 @@ +discard """ + outputsub: "Error: unhandled exception: over- or underflow [OverflowDefect]" + exitcode: "1" +""" +var x: distinct range[0..5] +dec(x) \ No newline at end of file From 552075d10ea579a40216843815d419261d327c03 Mon Sep 17 00:00:00 2001 From: sherbst Date: Sat, 7 Nov 2020 08:58:49 -0600 Subject: [PATCH 1413/4254] Fix typo in lexer.nim (#15876) --- compiler/lexer.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index e020236b1..b55dd3585 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -10,7 +10,7 @@ # This scanner is handwritten for efficiency. I used an elegant buffering # scheme which I have not seen anywhere else: # We guarantee that a whole line is in the buffer. Thus only when scanning -# the \n or \r character we have to check wether we need to read in the next +# the \n or \r character we have to check whether we need to read in the next # chunk. (\n or \r already need special handling for incrementing the line # counter; choosing both \n and \r allows the scanner to properly read Unix, # DOS or Macintosh text files, even when it is not the native format. From 203bddf307493b1065325759fef549499f2a3fc2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:02:12 +0800 Subject: [PATCH 1414/4254] close #11637(add testcase for #11637) (#15879) * close #11637(add testcase for #11637) * Update tests/vm/t11637.nim --- tests/vm/t11637.nim | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/vm/t11637.nim diff --git a/tests/vm/t11637.nim b/tests/vm/t11637.nim new file mode 100644 index 000000000..c061c6641 --- /dev/null +++ b/tests/vm/t11637.nim @@ -0,0 +1,52 @@ +type Foo = ref object + val: int + +proc `+`(a, b: Foo): Foo = + Foo(val: a.val + b.val) + +proc `*`(a: Foo, b: int): Foo = + Foo(val: a.val * b) + +proc `+=`(a: var Foo, b: Foo) = + a = Foo( + val: a.val + b.val + ) + +proc foobar(a, b, c: Foo): tuple[bar, baz, buzz: Foo] = + + let foo = a + b + c + result.bar = foo * 2 + + result.baz = foo * 3 + result.buzz = result.baz + + result.buzz += a * 10000 + result.baz += b + result.buzz += b + + +block: # Compile-Time + let + a {.compileTime.} = Foo(val: 1) + b {.compileTime.} = Foo(val: 2) + c {.compileTime.} = Foo(val: 3) + r {.compileTime.} = foobar(a, b, c) + + static: + doAssert r.bar.val == 12 + doAssert r.baz.val == 20 + doAssert r.buzz.val == 10020 + +#################################### + +block: # Run-time + let + a = Foo(val: 1) + b = Foo(val: 2) + c = Foo(val: 3) + r = foobar(a, b, c) + + # Expected values + doAssert r.bar.val == 12 + doAssert r.baz.val == 20 + doAssert r.buzz.val == 10020 From 49f68122e658ba7bcc13340fe157e276b4033a90 Mon Sep 17 00:00:00 2001 From: Luca Guzzon Date: Sun, 8 Nov 2020 04:51:40 +0100 Subject: [PATCH 1415/4254] Console apps in Windows can raise OSError (#15874) Console apps in Windows implementation can raise OSError so I've fixed it, see below some examples for reference: - https://github.com/nim-lang/Nim/blob/c07807bedf1749fa9d3e826d3d736907fefbe568/lib/pure/terminal.nim#L170 - https://github.com/nim-lang/Nim/blob/c07807bedf1749fa9d3e826d3d736907fefbe568/lib/pure/terminal.nim#L178 - https://github.com/nim-lang/Nim/blob/c07807bedf1749fa9d3e826d3d736907fefbe568/lib/pure/terminal.nim#L191-L192 - https://github.com/nim-lang/Nim/blob/c07807bedf1749fa9d3e826d3d736907fefbe568/lib/pure/terminal.nim#L196-L197 - ... --- lib/pure/terminal.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index ac6720771..3bda5b7aa 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -37,7 +37,10 @@ type var gTerm {.threadvar.}: owned(PTerminal) -proc newTerminal(): owned(PTerminal) {.gcsafe, raises: [].} +when defined(windows) and defined(consoleapp): + proc newTerminal(): owned(PTerminal) {.gcsafe, raises: [OSError].} +else: + proc newTerminal(): owned(PTerminal) {.gcsafe, raises: [].} proc getTerminal(): PTerminal {.inline.} = if isNil(gTerm): From 5db181f377e30f3a06e70b48e14337722d4dc114 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 9 Nov 2020 11:19:06 +0300 Subject: [PATCH 1416/4254] Nimgrep improvements 2 (#15612) * nimgrep: speed up by threads and Channels * nimgrep: add --bin, --text, --count options * nimgrep: add --sortTime option * allow Peg in all matches including --includeFile, --excludeFile, --excludeDir * add --match and --noMatch options * add --includeDir option * add --limit (-m) and --onlyAscii (-o) options * fix performance regression introduced in nimgrep improvements #12779 * better error handling * add option --fit * fix groups in --replace * fix flushing, --replace, improve --count * use "." as the default directory, not full path * fix --fit for Windows * force target to C for macosx * validate non-negative int input for options #15318 * switch nimgrep to using --gc:orc * address review: implement cropping in matches,... * implement stdin/pipe & revise --help * address stylistic review & add limitations --- testament/categories.nim | 3 + tools/nimgrep.nim | 1346 +++++++++++++++++++++++++++++--------- tools/nimgrep.nim.cfg | 9 +- 3 files changed, 1055 insertions(+), 303 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 07d35f6fb..fa9391055 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -262,6 +262,9 @@ proc debuggerTests(r: var TResults, cat: Category, options: string) = if fileExists("tools/nimgrep.nim"): var t = makeTest("tools/nimgrep", options & " --debugger:on", cat) t.spec.action = actionCompile + # force target to C because of MacOS 10.15 SDK headers bug + # https://github.com/nim-lang/Nim/pull/15612#issuecomment-712471879 + t.spec.targets = { targetC } testSpec r, t # ------------------------- JS tests ------------------------------------------ diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 138f1680c..1e563435c 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -8,86 +8,247 @@ # import - os, strutils, parseopt, pegs, re, terminal + os, strutils, parseopt, pegs, re, terminal, osproc, tables, algorithm, times const - Version = "1.5" - Usage = "nimgrep - Nim Grep Utility Version " & Version & """ + Version = "1.6.0" + Usage = "nimgrep - Nim Grep Searching and Replacement Utility Version " & + Version & """ + + (c) 2012-2020 Andreas Rumpf - (c) 2012 Andreas Rumpf Usage: - nimgrep [options] [pattern] [replacement] (file/directory)* +* To search: + nimgrep [options] PATTERN [(FILE/DIRECTORY)*/-] +* To replace: + nimgrep [options] PATTERN --replace REPLACEMENT (FILE/DIRECTORY)*/- +* To list file names: + nimgrep [options] --filenames [PATTERN] [(FILE/DIRECTORY)*] + +Positional arguments, from left to right: +* PATERN is either Regex (default) or Peg if --peg is specified. + PATTERN and REPLACEMENT should be skipped when --stdin is specified. +* REPLACEMENT supports $1, $# notations for captured groups in PATTERN. + Note: --replace mode DOES NOT ask confirmation unless --confirm is specified! +* Final arguments are a list of paths (FILE/DIRECTORY) or a standalone + minus '-' (pipe) or not specified (empty). Note for the empty case: when + no FILE/DIRECTORY/- is specified nimgrep DOES NOT read the pipe, but + searches files in the current dir instead! + - read buffer once from stdin: pipe or terminal input; + in --replace mode the result is directed to stdout; + it's not compatible with --stdin, --filenames, --confirm + (empty) current directory '.' is assumed (not with --replace) + For any given DIRECTORY nimgrep searches only its immediate files without + traversing sub-directories unless --recursive is specified. + In replacement mode all 3 positional arguments are required to avoid damaging. + Options: - --find, -f find the pattern (default) - --replace, -! replace the pattern - --peg pattern is a peg - --re pattern is a regular expression (default) - --rex, -x use the "extended" syntax for the regular expression - so that whitespace is not significant - --recursive, -r process directories recursively - --follow follow all symlinks when processing recursively +* Mode of operation: + --find, -f find the PATTERN (default) + --replace, -! replace the PATTERN to REPLACEMENT, rewriting the files --confirm confirm each occurrence/replacement; there is a chance to abort any time without touching the file - --stdin read pattern from stdin (to avoid the shell's confusing - quoting rules) - --word, -w the match should have word boundaries (buggy for pegs!) - --ignoreCase, -i be case insensitive - --ignoreStyle, -y be style insensitive + --filenames just list filenames. Provide a PATTERN to find it in + the filenames (not in the contents of a file) or run + with empty pattern to just list all files: + nimgrep --filenames # In current directory + nimgrep --filenames "" DIRECTORY # Note empty pattern "" + +* Interprete patterns: + --peg PATTERN and PAT are Peg + --re PATTERN and PAT are regular expressions (default) + --rex, -x use the "extended" syntax for the regular expression + so that whitespace is not significant + --word, -w matches should have word boundaries (buggy for pegs!) + --ignoreCase, -i be case insensitive in PATTERN and PAT + --ignoreStyle, -y be style insensitive in PATTERN and PAT + NOTE: PATERN and patterns PAT (see below in other options) are all either + Regex or Peg simultaneously and options --rex, --word, --ignoreCase, + --ignoreStyle are applied to all of them. + +* File system walk: + --recursive, -r process directories recursively + --follow follow all symlinks when processing recursively --ext:EX1|EX2|... only search the files with the given extension(s), empty one ("--ext") means files with missing extension --noExt:EX1|... exclude files having given extension(s), use empty one to skip files with no extension (like some binary files are) - --includeFile:PAT include only files whose names match the given regex PAT - --excludeFile:PAT skip files whose names match the given regex pattern PAT - --excludeDir:PAT skip directories whose names match the given regex PAT - --nocolor output will be given without any colours - --color[:always] force color even if output is redirected + --includeFile:PAT search only files whose names contain pattern PAT + --excludeFile:PAT skip files whose names contain pattern PAT + --includeDir:PAT search only files with whole directory path containing PAT + --excludeDir:PAT skip directories whose name (not path) contain pattern PAT + --if,--ef,--id,--ed abbreviations of 4 options above + --sortTime order files by the last modification time (default: off): + -s[:asc|desc] ascending (recent files go last) or descending + +* Filter file content: + --match:PAT select files containing a (not displayed) match of PAT + --noMatch:PAT select files not containing any match of PAT + --bin:on|off|only process binary files? (detected by \0 in first 1K bytes) + (default: on - binary and text files treated the same way) + --text, -t process only text files, the same as --bin:off + +* Represent results: + --nocolor output will be given without any colors + --color[:on] force color even if output is redirected (default: auto) --colorTheme:THEME select color THEME from 'simple' (default), 'bnw' (black and white) ,'ack', or 'gnu' (GNU grep) + --count only print counts of matches for files that matched + --context:N, -c:N print N lines of leading context before every match and + N lines of trailing context after it (default N: 0) --afterContext:N, -a:N print N lines of trailing context after every match --beforeContext:N, -b:N print N lines of leading context before every match - --context:N, -c:N print N lines of leading context before every match and - N lines of trailing context after it --group, -g group matches by file --newLine, -l display every matching line starting from a new line + --cols[:N] limit max displayed columns/width of output lines from + files by N characters, cropping overflows (default: off) + --cols:auto, -% calculate columns from terminal width for every line + --onlyAscii, -@ display only printable ASCII Latin characters 0x20-0x7E + substitutions: 0 -> ^@, 1 -> ^A, ... 0x1F -> ^_, + 0x7F -> '7F, ..., 0xFF -> 'FF +* Miscellaneous: + --threads:N, -j:N speed up search by N additional workers (default: 0, off) + --stdin read PATTERN from stdin (to avoid the shell's confusing + quoting rules) and, if --replace given, REPLACEMENT --verbose be verbose: list every processed file - --filenames find the pattern in the filenames, not in the contents - of the file --help, -h shows this help --version, -v shows the version """ +# Limitations / ideas / TODO: +# * No unicode support with --cols +# * Consider making --onlyAscii default, since dumping binary data has +# stability and security repercussions +# * Mode - reads entire buffer by whole from stdin, which is bad for streaming. +# To implement line-by-line reading after adding option to turn off +# multiline matches +# * Add some form of file pre-processing, e.g. feed binary files to utility +# `strings` and then do the search inside these strings +# * Add --showCol option to also show column (of match), not just line; it +# makes it easier when jump to line+col in an editor or on terminal + + +# Search results for a file are modelled by these levels: +# FileResult -> Block -> Output/Chunk -> SubLine +# +# 1. SubLine is an entire line or its part. +# +# 2. Chunk, which is a sequence of SubLine, represents a match and its +# surrounding context. +# Output is a Chunk or one of auxiliary results like an openError. +# +# 3. Block, which is a sequence of Chunks, is not present as a separate type. +# It will just be separated from another Block by newline when there is +# more than 3 lines in it. +# Here is an example of a Block where only 1 match is found and +# 1 line before and 1 line after of context are required: +# +# ...a_line_before...................................... <<\n") - elif newLine: + elif newLine and optFilenames notin options and optPipe notin options: if oneline: printBlockFile(filename) printBlockLineN(":" & $line & ":") @@ -231,234 +405,434 @@ proc blockHeader(filename: string, line: int|string, replMode=false) = printBlockLineN($line.`$`.align(alignment) & ":") stdout.write("\n") -proc lineHeader(filename: string, line: int|string, isMatch: bool) = +proc newLn(curCol: var Column) = + stdout.write("\n") + curCol.file = 0 + curCol.terminal = 0 + +# We reserve 10+3 chars on the right in --cols mode (optLimitChars). +# If the current match touches this right margin, subLine before it will +# be cropped (even if space is enough for subLine after the match — we +# currently don't have a way to know it since we get it afterwards). +const matchPaddingFromRight = 10 +const ellipsis = "..." + +proc lineHeader(filename: string, line: int|string, isMatch: bool, + curCol: var Column) = let lineSym = if isMatch: $line & ":" else: $line & " " - if not newLine: + if not newLine and optFilenames notin options and optPipe notin options: if oneline: printFile(filename) printLineN(":" & lineSym, isMatch) + curcol.terminal += filename.len + 1 + lineSym.len else: printLineN(lineSym.align(alignment+1), isMatch) - stdout.write(" ") + curcol.terminal += lineSym.align(alignment+1).len + stdout.write(" "); curCol.terminal += 1 + curCol.terminal = curCol.terminal mod termWidth + if optLimitChars in options and + curCol.terminal > limitCharUsr - matchPaddingFromRight - ellipsis.len: + newLn(curCol) -proc printMatch(fileName: string, mi: MatchInfo) = - let lines = mi.match.splitLines() - for i, l in lines: - if i > 0: - lineHeader(filename, mi.lineBeg + i, isMatch = true) - writeColored(l) - if i < lines.len - 1: - stdout.write("\n") - -proc printLinesBefore(si: SearchInfo, curMi: MatchInfo, nLines: int, - replMode=false) = - # start block: print 'linesBefore' lines before current match `curMi` - let first = beforePattern(si.buf, curMi.first-1, nLines) - let lines = splitLines(substr(si.buf, first, curMi.first-1)) - let startLine = curMi.lineBeg - lines.len + 1 - blockHeader(si.filename, curMi.lineBeg, replMode=replMode) - for i, l in lines: - lineHeader(si.filename, startLine + i, isMatch = (i == lines.len - 1)) - stdout.write(l) - if i < lines.len - 1: - stdout.write("\n") - -proc printLinesAfter(si: SearchInfo, mi: MatchInfo, nLines: int) = - # finish block: print 'linesAfter' lines after match `mi` - let s = si.buf - let last = afterPattern(s, mi.last+1, nLines) - let lines = splitLines(substr(s, mi.last+1, last)) - if lines.len == 0: # EOF - stdout.write("\n") +proc reserveChars(mi: MatchInfo): int = + if optLimitChars in options: + let patternChars = afterPattern(mi.match, 0) + 1 + result = patternChars + ellipsis.len + matchPaddingFromRight else: - stdout.write(lines[0]) # complete the line after match itself - stdout.write("\n") - let skipLine = # workaround posix line ending at the end of file - if last == s.len-1 and s.len >= 2 and s[^1] == '\l' and s[^2] != '\c': 1 - else: 0 - for i in 1 ..< lines.len - skipLine: - lineHeader(si.filename, mi.lineEnd + i, isMatch = false) - stdout.write(lines[i]) - stdout.write("\n") - if linesAfter + linesBefore >= 2 and not newLine: stdout.write("\n") + result = 0 -proc printBetweenMatches(si: SearchInfo, prevMi: MatchInfo, curMi: MatchInfo) = +# Our substitutions of non-printable symbol to ASCII character are similar to +# those of programm 'less'. +const lowestAscii = 0x20 # lowest ASCII Latin printable symbol (@) +const largestAscii = 0x7e +const by2ascii = 2 # number of ASCII chars to represent chars < lowestAscii +const by3ascii = 3 # number of ASCII chars to represent chars > largestAscii + +proc printExpanded(s: string, curCol: var Column, isMatch: bool, + limitChar: int) = + # Print taking into account tabs and optOnlyAscii (and also optLimitChar: + # the proc called from printCropped but we need to check column < limitChar + # also here, since exact cut points are known only after tab expansion). + # With optOnlyAscii non-ascii chars are highlighted even in matches. + # + # use buffer because: + # 1) we need to print non-ascii character inside matches while keeping the + # amount of color escape sequences minimal. + # 2) there is a report that fwrite buffering is slow on MacOS + # https://github.com/nim-lang/Nim/pull/15612#discussion_r510538326 + const bufSize = 8192 # typical for fwrite too + var buffer: string + const normal = 0 + const special = 1 + var lastAdded = normal + template dumpBuf() = + if lastAdded == normal: + printContents(buffer, isMatch) + else: + printSpecial(buffer) + template addBuf(i: int, s: char|string, size: int) = + if lastAdded != i or buffer.len + size > bufSize: + dumpBuf() + buffer.setlen(0) + buffer.add s + lastAdded = i + for c in s: + let charsAllowed = limitChar - curCol.terminal + if charsAllowed <= 0: + break + if lowestAscii <= int(c) and int(c) <= largestAscii: # ASCII latin + addBuf(normal, c, 1) + curCol.file += 1; curCol.terminal += 1 + elif (not optOnlyAscii) and c != '\t': # the same, print raw + addBuf(normal, c, 1) + curCol.file += 1; curCol.terminal += 1 + elif c == '\t': + let spaces = 8 - (curCol.file mod 8) + let spacesAllowed = min(spaces, charsAllowed) + curCol.file += spaces + curCol.terminal += spacesAllowed + if expandTabs: + if optOnlyAscii: # print a nice box for tab + addBuf(special, " ", 1) + addBuf(normal, " ".repeat(spacesAllowed-1), spacesAllowed-1) + else: + addBuf(normal, " ".repeat(spacesAllowed), spacesAllowed) + else: + addBuf(normal, '\t', 1) + else: # substitute characters that are not ACSII Latin + if int(c) < lowestAscii: + let substitute = char(int(c) + 0x40) # use common "control codes" + addBuf(special, "^" & substitute, by2ascii) + curCol.terminal += by2ascii + else: # int(c) > largestAscii + curCol.terminal += by3ascii + let substitute = '\'' & c.BiggestUInt.toHex(2) + addBuf(special, substitute, by3ascii) + curCol.file += 1 + if buffer.len > 0: + dumpBuf() + +template nextCharacter(c: char, file: var int, term: var int) = + if lowestAscii <= int(c) and int(c) <= largestAscii: # ASCII latin + file += 1 + term += 1 + elif (not optOnlyAscii) and c != '\t': # the same, print raw + file += 1 + term += 1 + elif c == '\t': + term += 8 - (file mod 8) + file += 8 - (file mod 8) + elif int(c) < lowestAscii: + file += 1 + term += by2ascii + else: # int(c) > largestAscii: + file += 1 + term += by3ascii + +proc calcTermLen(s: string, firstCol: int, chars: int, fromLeft: bool): int = + # calculate additional length added by Tabs expansion and substitutions + var col = firstCol + var first, last: int + if fromLeft: + first = max(0, s.len - chars) + last = s.len - 1 + else: + first = 0 + last = min(s.len - 1, chars - 1) + for c in s[first .. last]: + nextCharacter(c, col, result) + +proc printCropped(s: string, curCol: var Column, fromLeft: bool, + limitChar: int, isMatch = false) = + # print line `s`, may be cropped if option --cols was set + const eL = ellipsis.len + if optLimitChars notin options: + if not expandTabs and not optOnlyAscii: # for speed mostly + printContents(s, isMatch) + else: + printExpanded(s, curCol, isMatch, limitChar) + else: # limit columns, expand Tabs is also forced + var charsAllowed = limitChar - curCol.terminal + if fromLeft and charsAllowed < eL: + charsAllowed = eL + if (not fromLeft) and charsAllowed <= 0: + # already overflown and ellipsis shold be in place + return + let fullLenWithin = calcTermLen(s, curCol.file, charsAllowed, fromLeft) + # additional length from Tabs and special symbols + let addLen = fullLenWithin - min(s.len, charsAllowed) + # determine that the string is guaranteed to fit within `charsAllowed` + let fits = + if s.len > charsAllowed: + false + else: + if isMatch: fullLenWithin <= charsAllowed - eL + else: fullLenWithin <= charsAllowed + if fits: + printExpanded(s, curCol, isMatch, limitChar = high(int)) + else: + if fromLeft: + printBold ellipsis + curCol.terminal += eL + # find position `pos` where the right side of line will fit charsAllowed + var col = 0 + var term = 0 + var pos = min(s.len, max(0, s.len - (charsAllowed - eL))) + while pos <= s.len - 1: + let c = s[pos] + nextCharacter(c, col, term) + if term >= addLen: + break + inc pos + curCol.file = pos + # TODO don't expand tabs when cropped from the left - difficult, meaningless + printExpanded(s[pos .. s.len - 1], curCol, isMatch, + limitChar = high(int)) + else: + let last = max(-1, min(s.len - 1, charsAllowed - eL - 1)) + printExpanded(s[0 .. last], curCol, isMatch, limitChar-eL) + let numDots = limitChar - curCol.terminal + printBold ".".repeat(numDots) + curCol.terminal = limitChar + +proc printMatch(fileName: string, mi: MatchInfo, curCol: var Column) = + let sLines = mi.match.splitLines() + for i, l in sLines: + if i > 0: + lineHeader(filename, mi.lineBeg + i, isMatch = true, curCol) + let charsAllowed = limitCharUsr - curCol.terminal + if charsAllowed > 0: + printCropped(l, curCol, fromLeft = false, limitCharUsr, isMatch = true) + else: + curCol.overflowMatches += 1 + if i < sLines.len - 1: + newLn(curCol) + +proc getSubLinesBefore(buf: string, curMi: MatchInfo): string = + let first = beforePattern(buf, curMi.first-1, linesBefore+1) + result = substr(buf, first, curMi.first-1) + +proc printSubLinesBefore(filename: string, beforeMatch: string, lineBeg: int, + curCol: var Column, reserveChars: int, + replMode=false) = + # start block: print 'linesBefore' lines before current match `curMi` + let sLines = splitLines(beforeMatch) + let startLine = lineBeg - sLines.len + 1 + blockHeader(filename, lineBeg, replMode=replMode) + for i, l in sLines: + let isLastLine = i == sLines.len - 1 + lineHeader(filename, startLine + i, isMatch = isLastLine, curCol) + let limit = if isLastLine: limitCharUsr - reserveChars else: limitCharUsr + l.printCropped(curCol, fromLeft = isLastLine, limitChar = limit) + if not isLastLine: + newLn(curCol) + +proc getSubLinesAfter(buf: string, mi: MatchInfo): string = + let last = afterPattern(buf, mi.last+1, 1+linesAfter) + let skipByte = # workaround posix: suppress extra line at the end of file + if (last == buf.len-1 and buf.len >= 2 and + buf[^1] == '\l' and buf[^2] != '\c'): 1 + else: 0 + result = substr(buf, mi.last+1, last - skipByte) + +proc printOverflow(filename: string, line: int, curCol: var Column) = + if curCol.overflowMatches > 0: + lineHeader(filename, line, isMatch = true, curCol) + printBold("(" & $curCol.overflowMatches & " matches skipped)") + newLn(curCol) + curCol.overflowMatches = 0 + +proc printSubLinesAfter(filename: string, afterMatch: string, matchLineEnd: int, + curCol: var Column) = + # finish block: print 'linesAfter' lines after match `mi` + let sLines = splitLines(afterMatch) + if sLines.len == 0: # EOF + newLn(curCol) + else: + sLines[0].printCropped(curCol, fromLeft = false, limitCharUsr) + # complete the line after the match itself + newLn(curCol) + printOverflow(filename, matchLineEnd, curCol) + for i in 1 ..< sLines.len: + lineHeader(filename, matchLineEnd + i, isMatch = false, curCol) + sLines[i].printCropped(curCol, fromLeft = false, limitCharUsr) + newLn(curCol) + +proc getSubLinesBetween(buf: string, prevMi: MatchInfo, + curMi: MatchInfo): string = + buf.substr(prevMi.last+1, curMi.first-1) + +proc printBetweenMatches(filename: string, betweenMatches: string, + lastLineBeg: int, + curCol: var Column, reserveChars: int) = # continue block: print between `prevMi` and `curMi` - let lines = si.buf.substr(prevMi.last+1, curMi.first-1).splitLines() - stdout.write(lines[0]) # finish the line of previous Match - if lines.len > 1: - stdout.write("\n") - for i in 1 ..< lines.len: - lineHeader(si.filename, prevMi.lineEnd + i, - isMatch = (i == lines.len - 1)) - stdout.write(lines[i]) - if i < lines.len - 1: - stdout.write("\n") + let sLines = betweenMatches.splitLines() + sLines[0].printCropped(curCol, fromLeft = false, limitCharUsr) + # finish the line of previous Match + if sLines.len > 1: + newLn(curCol) + printOverflow(filename, lastLineBeg - sLines.len + 1, curCol) + for i in 1 ..< sLines.len: + let isLastLine = i == sLines.len - 1 + lineHeader(filename, lastLineBeg - sLines.len + i + 1, + isMatch = isLastLine, curCol) + let limit = if isLastLine: limitCharUsr - reserveChars else: limitCharUsr + sLines[i].printCropped(curCol, fromLeft = isLastLine, limitChar = limit) + if not isLastLine: + newLn(curCol) -proc printContextBetween(si: SearchInfo, prevMi, curMi: MatchInfo) = - # print context after previous match prevMi and before current match curMi - let nLinesBetween = curMi.lineBeg - prevMi.lineEnd - if nLinesBetween <= linesAfter + linesBefore + 1: # print as 1 block - printBetweenMatches(si, prevMi, curMi) - else: # finalize previous block and then print next block - printLinesAfter(si, prevMi, 1+linesAfter) - printLinesBefore(si, curMi, linesBefore+1) - -proc printReplacement(si: SearchInfo, mi: MatchInfo, repl: string, - showRepl: bool, curPos: int, +proc printReplacement(fileName: string, buf: string, mi: MatchInfo, + repl: string, showRepl: bool, curPos: int, newBuf: string, curLine: int) = - printLinesBefore(si, mi, linesBefore+1) - printMatch(si.fileName, mi) - printLinesAfter(si, mi, 1+linesAfter) + var curCol: Column + printSubLinesBefore(fileName, getSubLinesBefore(buf, mi), mi.lineBeg, + curCol, reserveChars(mi)) + printMatch(fileName, mi, curCol) + printSubLinesAfter(fileName, getSubLinesAfter(buf, mi), mi.lineEnd, curCol) stdout.flushFile() if showRepl: - let newSi: SearchInfo = (buf: newBuf, filename: si.filename) let miForNewBuf: MatchInfo = (first: newBuf.len, last: newBuf.len, lineBeg: curLine, lineEnd: curLine, match: "") - printLinesBefore(newSi, miForNewBuf, linesBefore+1, replMode=true) + printSubLinesBefore(fileName, getSubLinesBefore(newBuf, miForNewBuf), + miForNewBuf.lineBeg, curCol, reserveChars(miForNewBuf), + replMode=true) let replLines = countLineBreaks(repl, 0, repl.len-1) let miFixLines: MatchInfo = (first: mi.first, last: mi.last, lineBeg: curLine, lineEnd: curLine + replLines, match: repl) - printMatch(si.fileName, miFixLines) - printLinesAfter(si, miFixLines, 1+linesAfter) + printMatch(fileName, miFixLines, curCol) + printSubLinesAfter(fileName, getSubLinesAfter(buf, miFixLines), + miFixLines.lineEnd, curCol) + if linesAfter + linesBefore >= 2 and not newLine: stdout.write("\n") stdout.flushFile() -proc doReplace(si: SearchInfo, mi: MatchInfo, i: int, r: string; - newBuf: var string, curLine: var int, reallyReplace: var bool) = - newBuf.add(si.buf.substr(i, mi.first-1)) - inc(curLine, countLineBreaks(si.buf, i, mi.first-1)) +proc replace1match(filename: string, buf: string, mi: MatchInfo, i: int, + r: string; newBuf: var string, curLine: var int): bool = + newBuf.add(buf.substr(i, mi.first-1)) + inc(curLine, countLineBreaks(buf, i, mi.first-1)) if optConfirm in options: - printReplacement(si, mi, r, showRepl=true, i, newBuf, curLine) + printReplacement(filename, buf, mi, r, showRepl=true, i, newBuf, curLine) case confirm() of ceAbort: quit(0) - of ceYes: reallyReplace = true + of ceYes: gVar.reallyReplace = true of ceAll: - reallyReplace = true + gVar.reallyReplace = true options.excl(optConfirm) of ceNo: - reallyReplace = false + gVar.reallyReplace = false of ceNone: - reallyReplace = false + gVar.reallyReplace = false options.excl(optConfirm) - else: - printReplacement(si, mi, r, showRepl=reallyReplace, i, newBuf, curLine) - if reallyReplace: + elif optPipe notin options: + printReplacement(filename, buf, mi, r, showRepl=gVar.reallyReplace, i, + newBuf, curLine) + if gVar.reallyReplace: + result = true newBuf.add(r) inc(curLine, countLineBreaks(r, 0, r.len-1)) else: newBuf.add(mi.match) inc(curLine, countLineBreaks(mi.match, 0, mi.match.len-1)) -proc processFile(pattern; filename: string; counter: var int, errors: var int) = - var filenameShown = false - template beforeHighlight = - if not filenameShown and optVerbose notin options and not oneline: - printBlockFile(filename) - stdout.write("\n") - stdout.flushFile() - filenameShown = true +template updateCounters(output: Output) = + case output.kind + of blockFirstMatch, blockNextMatch: inc(gVar.matches) + of justCount: inc(gVar.matches, output.matches) + of openError: inc(gVar.errors) + of rejected, blockEnd, fileContents, outputFileName: discard - var buffer: string - if optFilenames in options: - buffer = filename - else: - try: - buffer = system.readFile(filename) - except IOError: - printError "Error: cannot open file: " & filename - inc(errors) - return - if optVerbose in options: - printFile(filename) - stdout.write("\n") - stdout.flushFile() - var result: string +proc printInfo(filename:string, output: Output) = + case output.kind + of openError: + printError("can not open path " & filename & " " & output.msg) + of rejected: + if optVerbose in options: + echo "(rejected: ", output.reason, ")" + of justCount: + echo " (" & $output.matches & " matches)" + of blockFirstMatch, blockNextMatch, blockEnd, fileContents, outputFileName: + discard - if optReplace in options: - result = newStringOfCap(buffer.len) +proc printOutput(filename: string, output: Output, curCol: var Column) = + case output.kind + of openError, rejected, justCount: printInfo(filename, output) + of fileContents: discard # impossible + of outputFileName: + printCropped(output.name, curCol, fromLeft=false, limitCharUsr) + newLn(curCol) + of blockFirstMatch: + printSubLinesBefore(filename, output.pre, output.match.lineBeg, + curCol, reserveChars(output.match)) + printMatch(filename, output.match, curCol) + of blockNextMatch: + printBetweenMatches(filename, output.pre, output.match.lineBeg, + curCol, reserveChars(output.match)) + printMatch(filename, output.match, curCol) + of blockEnd: + printSubLinesAfter(filename, output.blockEnding, output.firstLine, curCol) + if linesAfter + linesBefore >= 2 and not newLine and + optFilenames notin options: stdout.write("\n") - var lineRepl = 1 - let si: SearchInfo = (buf: buffer, filename: filename) +iterator searchFile(pattern: Pattern; buffer: string): Output = var prevMi, curMi: MatchInfo - curMi.lineEnd = 1 + prevMi.lineEnd = 1 var i = 0 var matches: array[0..re.MaxSubpatterns-1, string] for j in 0..high(matches): matches[j] = "" - var reallyReplace = true - while i < buffer.len: + while true: let t = findBounds(buffer, pattern, matches, i) if t.first < 0 or t.last < t.first: - if optReplace notin options and prevMi.lineBeg != 0: # finalize last match - printLinesAfter(si, prevMi, 1+linesAfter) - stdout.flushFile() + if prevMi.lineBeg != 0: # finalize last match + yield Output(kind: blockEnd, + blockEnding: getSubLinesAfter(buffer, prevMi), + firstLine: prevMi.lineEnd) break - let lineBeg = curMi.lineEnd + countLineBreaks(buffer, i, t.first-1) + let lineBeg = prevMi.lineEnd + countLineBreaks(buffer, i, t.first-1) curMi = (first: t.first, last: t.last, lineBeg: lineBeg, lineEnd: lineBeg + countLineBreaks(buffer, t.first, t.last), match: buffer.substr(t.first, t.last)) - beforeHighlight() - inc counter - if optReplace notin options: - if prevMi.lineBeg == 0: # no previous match, so no previous block to finalize - printLinesBefore(si, curMi, linesBefore+1) - else: - printContextBetween(si, prevMi, curMi) - printMatch(si.fileName, curMi) - if t.last == buffer.len - 1: - stdout.write("\n") - stdout.flushFile() + if prevMi.lineBeg == 0: # no prev. match, so no prev. block to finalize + let pre = getSubLinesBefore(buffer, curMi) + prevMi = curMi + yield Output(kind: blockFirstMatch, pre: pre, match: move(curMi)) else: - let r = replace(curMi.match, pattern, replacement % matches) - doReplace(si, curMi, i, r, result, lineRepl, reallyReplace) - + let nLinesBetween = curMi.lineBeg - prevMi.lineEnd + if nLinesBetween <= linesAfter + linesBefore + 1: # print as 1 block + let pre = getSubLinesBetween(buffer, prevMi, curMi) + prevMi = curMi + yield Output(kind: blockNextMatch, pre: pre, match: move(curMi)) + else: # finalize previous block and then print next block + let after = getSubLinesAfter(buffer, prevMi) + yield Output(kind: blockEnd, blockEnding: after, + firstLine: prevMi.lineEnd) + let pre = getSubLinesBefore(buffer, curMi) + prevMi = curMi + yield Output(kind: blockFirstMatch, + pre: pre, + match: move(curMi)) i = t.last+1 - prevMi = curMi - if optReplace in options: - result.add(substr(buffer, i)) # finalize new buffer after last match - var f: File - if open(f, filename, fmWrite): - f.write(result) - f.close() - else: - quit "cannot open file for overwriting: " & filename +func detectBin(buffer: string): bool = + for i in 0 ..< min(1024, buffer.len): + if buffer[i] == '\0': + return true -proc hasRightFileName(path: string): bool = - let filename = path.lastPathPart - let ex = filename.splitFile.ext.substr(1) # skip leading '.' - if extensions.len != 0: - var matched = false - for x in items(extensions): - if os.cmpPaths(x, ex) == 0: - matched = true - break - if not matched: return false - for x in items(skipExtensions): - if os.cmpPaths(x, ex) == 0: return false - if includeFile.len != 0: - var matched = false - for x in items(includeFile): - if filename.match(x): - matched = true - break - if not matched: return false - for x in items(excludeFile): - if filename.match(x): return false - result = true - -proc hasRightDirectory(path: string): bool = - let dirname = path.lastPathPart - for x in items(excludeDir): - if dirname.match(x): return false - result = true +proc compilePeg(initPattern: string): Peg = + var pattern = initPattern + if optWord in options: + pattern = r"(^ / !\letter)(" & pattern & r") !\letter" + if optIgnoreStyle in options: + pattern = "\\y " & pattern + elif optIgnoreCase in options: + pattern = "\\i " & pattern + result = peg(pattern) proc styleInsensitive(s: string): string = template addx = @@ -494,28 +868,358 @@ proc styleInsensitive(s: string): string = addx() else: addx() -proc walker(pattern; dir: string; counter: var int, errors: var int) = - if dirExists(dir): - for kind, path in walkDir(dir): +proc compileRegex(initPattern: string): Regex = + var pattern = initPattern + var reflags = {reStudy} + if optIgnoreStyle in options: + pattern = styleInsensitive(pattern) + if optWord in options: + # see https://github.com/nim-lang/Nim/issues/13528#issuecomment-592786443 + pattern = r"(^|\W)(:?" & pattern & r")($|\W)" + if {optIgnoreCase, optIgnoreStyle} * options != {}: + reflags.incl reIgnoreCase + result = if optRex in options: rex(pattern, reflags) + else: re(pattern, reflags) + +template declareCompiledPatterns(compiledStruct: untyped, + StructType: untyped, + body: untyped) = + {.hint[XDeclaredButNotUsed]: off.} + if optRegex notin options: + var compiledStruct: StructType[Peg] + template compile1Pattern(p: string, pat: Peg) = + if p!="": pat = p.compilePeg() + proc compileArray(initPattern: seq[string]): seq[Peg] = + for pat in initPattern: + result.add pat.compilePeg() + body + else: + var compiledStruct: StructType[Regex] + template compile1Pattern(p: string, pat: Regex) = + if p!="": pat = p.compileRegex() + proc compileArray(initPattern: seq[string]): seq[Regex] = + for pat in initPattern: + result.add pat.compileRegex() + body + {.hint[XDeclaredButNotUsed]: on.} + +iterator processFile(searchOptC: SearchOptComp[Pattern], filename: string, + yieldContents=false): Output = + var buffer: string + + var error = false + if optFilenames in options: + buffer = filename + elif optPipe in options: + buffer = stdin.readAll() + else: + try: + buffer = system.readFile(filename) + except IOError as e: + yield Output(kind: openError, msg: "readFile failed") + error = true + + if not error: + var reject = false + var reason: string + if searchOpt.checkBin in {biOff, biOnly}: + let isBin = detectBin(buffer) + if isBin and searchOpt.checkBin == biOff: + reject = true + reason = "binary file" + if (not isBin) and searchOpt.checkBin == biOnly: + reject = true + reason = "text file" + + if not reject: + if searchOpt.checkMatch != "": + reject = not contains(buffer, searchOptC.checkMatch, 0) + reason = "doesn't contain a requested match" + + if not reject: + if searchOpt.checkNoMatch != "": + reject = contains(buffer, searchOptC.checkNoMatch, 0) + reason = "contains a forbidden match" + + if reject: + yield Output(kind: rejected, reason: move(reason)) + elif optFilenames in options and searchOpt.pattern == "": + yield Output(kind: outputFileName, name: move(buffer)) + else: + var found = false + var cnt = 0 + for output in searchFile(searchOptC.pattern, buffer): + found = true + if optCount notin options: + yield output + else: + if output.kind in {blockFirstMatch, blockNextMatch}: + inc(cnt) + if optCount in options and cnt > 0: + yield Output(kind: justCount, matches: cnt) + if yieldContents and found and optCount notin options: + yield Output(kind: fileContents, buffer: move(buffer)) + + +proc hasRightFileName(path: string, walkOptC: WalkOptComp[Pattern]): bool = + let filename = path.lastPathPart + let ex = filename.splitFile.ext.substr(1) # skip leading '.' + if walkOpt.extensions.len != 0: + var matched = false + for x in walkOpt.extensions: + if os.cmpPaths(x, ex) == 0: + matched = true + break + if not matched: return false + for x in walkOpt.skipExtensions: + if os.cmpPaths(x, ex) == 0: return false + if walkOptC.includeFile.len != 0: + var matched = false + for pat in walkOptC.includeFile: + if filename.contains(pat): + matched = true + break + if not matched: return false + for pat in walkOptC.excludeFile: + if filename.contains(pat): return false + let dirname = path.parentDir + if walkOptC.includeDir.len != 0: + var matched = false + for pat in walkOptC.includeDir: + if dirname.contains(pat): + matched = true + break + if not matched: return false + result = true + +proc hasRightDirectory(path: string, walkOptC: WalkOptComp[Pattern]): bool = + let dirname = path.lastPathPart + for pat in walkOptC.excludeDir: + if dirname.contains(pat): return false + result = true + +iterator walkDirBasic(dir: string, walkOptC: WalkOptComp[Pattern]): string = + var dirStack = @[dir] # stack of directories + var timeFiles = newSeq[(times.Time, string)]() + while dirStack.len > 0: + let d = dirStack.pop() + var files = newSeq[string]() + var dirs = newSeq[string]() + for kind, path in walkDir(d): case kind of pcFile: - if path.hasRightFileName: - processFile(pattern, path, counter, errors) + if path.hasRightFileName(walkOptC): + files.add(path) of pcLinkToFile: - if optFollow in options and path.hasRightFileName: - processFile(pattern, path, counter, errors) + if optFollow in options and path.hasRightFileName(walkOptC): + files.add(path) of pcDir: - if optRecursive in options and path.hasRightDirectory: - walker(pattern, path, counter, errors) + if optRecursive in options and path.hasRightDirectory(walkOptC): + dirs.add path of pcLinkToDir: if optFollow in options and optRecursive in options and - path.hasRightDirectory: - walker(pattern, path, counter, errors) - elif fileExists(dir): - processFile(pattern, dir, counter, errors) + path.hasRightDirectory(walkOptC): + dirs.add path + if sortTime: # sort by time - collect files before yielding + for file in files: + var time: Time + try: + time = getLastModificationTime(file) # can fail for broken symlink + except: + discard + timeFiles.add((time, file)) + else: # alphanumeric sort, yield immediately after sorting + files.sort() + for file in files: + yield file + dirs.sort(order = SortOrder.Descending) + for dir in dirs: + dirStack.add(dir) + if sortTime: + timeFiles.sort(sortTimeOrder) + for (_, file) in timeFiles: + yield file + +iterator walkRec(paths: seq[string]): (string, string) = + declareCompiledPatterns(walkOptC, WalkOptComp): + walkOptC.excludeFile.add walkOpt.excludeFile.compileArray() + walkOptC.includeFile.add walkOpt.includeFile.compileArray() + walkOptC.includeDir.add walkOpt.includeDir.compileArray() + walkOptC.excludeDir.add walkOpt.excludeDir.compileArray() + for path in paths: + if dirExists(path): + for p in walkDirBasic(path, walkOptC): + yield ("", p) + else: + yield ( + if fileExists(path): ("", path) + else: ("Error: no such file or directory: ", path)) + +proc replaceMatches(pattern: Pattern; filename: string, buffer: string, + fileResult: FileResult) = + var newBuf = newStringOfCap(buffer.len) + + var changed = false + var lineRepl = 1 + var i = 0 + for output in fileResult: + if output.kind in {blockFirstMatch, blockNextMatch}: + let curMi = output.match + let r = replacef(curMi.match, pattern, replacement) + if replace1match(filename, buffer, curMi, i, r, newBuf, lineRepl): + changed = true + i = curMi.last + 1 + if changed and optPipe notin options: + newBuf.add(substr(buffer, i)) # finalize new buffer after last match + var f: File + if open(f, filename, fmWrite): + f.write(newBuf) + f.close() + else: + printError "cannot open file for overwriting: " & filename + inc(gVar.errors) + elif optPipe in options: # always print new buffer to stdout in pipe mode + newBuf.add(substr(buffer, i)) # finalize new buffer after last match + stdout.write(newBuf) + +template processFileResult(pattern: Pattern; filename: string, + fileResult: untyped) = + var filenameShown = false + template showFilename = + if not filenameShown: + printBlockFile(filename) + stdout.write("\n") + stdout.flushFile() + filenameShown = true + if optVerbose in options: + showFilename + if optReplace notin options: + var curCol: Column + var toFlush: bool + for output in fileResult: + updateCounters(output) + toFlush = true + if output.kind notin {rejected, openError, justCount} and not oneline: + showFilename + if output.kind == justCount and oneline: + printFile(filename & ":") + printOutput(filename, output, curCol) + if nWorkers == 0 and output.kind in {blockFirstMatch, blockNextMatch}: + stdout.flushFile() # flush immediately in single thread mode + if toFlush: stdout.flushFile() else: - printError "Error: no such file or directory: " & dir - inc(errors) + var buffer = "" + var matches: FileResult + for output in fileResult: + updateCounters(output) + case output.kind + of rejected, openError, justCount, outputFileName: + printInfo(filename, output) + of blockFirstMatch, blockNextMatch, blockEnd: + matches.add(output) + of fileContents: buffer = output.buffer + if matches.len > 0: + replaceMatches(pattern, filename, buffer, matches) + +proc run1Thread() = + declareCompiledPatterns(searchOptC, SearchOptComp): + compile1Pattern(searchOpt.pattern, searchOptC.pattern) + compile1Pattern(searchOpt.checkMatch, searchOptC.checkMatch) + compile1Pattern(searchOpt.checkNoMatch, searchOptC.checkNoMatch) + if optPipe in options: + processFileResult(searchOptC.pattern, "-", + processFile(searchOptC, "-", + yieldContents=optReplace in options)) + for (err, filename) in walkRec(paths): + if err != "": + inc(gVar.errors) + printError (err & filename) + continue + processFileResult(searchOptC.pattern, filename, + processFile(searchOptC, filename, + yieldContents=optReplace in options)) + +# Multi-threaded version: all printing is being done in the Main thread. +# Totally nWorkers+1 additional threads are created (workers + pathProducer). +# An example of case nWorkers=2: +# +# ------------------ initial paths ------------------- +# | Main thread |----------------->| pathProducer | +# ------------------ ------------------- +# ^ | | +# resultsChan | walking errors, | | searchRequestsChan +# | number of files | -----+----- +# ----+--------------------------- | | +# | | (when walking finished) |a path |a path to file +# | | | | +# | | V V +# | | ------------ ------------ +# | | | worker 1 | | worker 2 | +# | | ------------ ------------ +# | | matches in the file | | +# | -------------------------------- | +# | matches in the file | +# ---------------------------------------------- +# +# The matches from each file are passed at once as FileResult type. + +proc worker(initSearchOpt: SearchOpt) {.thread.} = + searchOpt = initSearchOpt # init thread-local var + declareCompiledPatterns(searchOptC, SearchOptComp): + compile1Pattern(searchOpt.pattern, searchOptC.pattern) + compile1Pattern(searchOpt.checkMatch, searchOptC.checkMatch) + compile1Pattern(searchOpt.checkNoMatch, searchOptC.checkNoMatch) + while true: + let (fileNo, filename) = searchRequestsChan.recv() + var fileResult: FileResult + for output in processFile(searchOptC, filename, + yieldContents=(optReplace in options)): + fileResult.add(output) + resultsChan.send((false, fileNo, filename, move(fileResult))) + +proc pathProducer(arg: (seq[string], WalkOpt)) {.thread.} = + let paths = arg[0] + walkOpt = arg[1] # init thread-local copy of opt + var + nextFileN = 0 + for (err, filename) in walkRec(paths): + if err == "": + searchRequestsChan.send((nextFileN,filename)) + else: + resultsChan.send((false, nextFileN, + filename, @[Output(kind: openError, msg: err)])) + nextFileN += 1 + resultsChan.send((true, nextFileN, "", @[])) # pass total number of files + +proc runMultiThread() = + var + workers = newSeq[Thread[SearchOpt]](nWorkers) + storage = newTable[int, (string, FileResult) ]() + # file number -> tuple[filename, fileResult - accumulated data structure] + firstUnprocessedFile = 0 # for always processing files in the same order + open(searchRequestsChan) + open(resultsChan) + for n in 0 ..< nWorkers: + createThread(workers[n], worker, searchOpt) + var producerThread: Thread[(seq[string], WalkOpt)] + createThread(producerThread, pathProducer, (paths, walkOpt)) + declareCompiledPatterns(pat, SinglePattern): + compile1Pattern(searchOpt.pattern, pat.pattern) + template add1fileResult(fileNo: int, fname: string, fResult: FileResult) = + storage[fileNo] = (fname, fResult) + while storage.haskey(firstUnprocessedFile): + let fileResult = storage[firstUnprocessedFile][1] + let filename = storage[firstUnprocessedFile][0] + processFileResult(pat.pattern, filename, fileResult) + storage.del(firstUnprocessedFile) + firstUnprocessedFile += 1 + var totalFiles = -1 # will be known when pathProducer finishes + while totalFiles == -1 or firstUnprocessedFile < totalFiles: + let msg = resultsChan.recv() + if msg.finished: + totalFiles = msg.fileNo + else: + add1fileResult(msg.fileNo, msg.filename, msg.fileResult) proc reportError(msg: string) = printError "Error: " & msg @@ -535,6 +1239,15 @@ proc checkOptions(subset: TOptions, a, b: string) = if subset <= options: quit("cannot specify both '$#' and '$#'" % [a, b]) +proc parseNonNegative(str: string, key: string): int = + try: + result = parseInt(str) + except ValueError: + reportError("Option " & key & " requires an integer but '" & + str & "' was given") + if result < 0: + reportError("A positive integer is expected for option " & key) + when defined(posix): useWriteStyled = terminal.isatty(stdout) # that should be before option processing to allow override of useWriteStyled @@ -543,13 +1256,15 @@ for kind, key, val in getopt(): case kind of cmdArgument: if options.contains(optStdin): - filenames.add(key) - elif pattern.len == 0: - pattern = key - elif options.contains(optReplace) and replacement.len == 0: + paths.add(key) + elif not searchOpt.patternSet: + searchOpt.pattern = key + searchOpt.patternSet = true + elif options.contains(optReplace) and not replacementSet: replacement = key + replacementSet = true else: - filenames.add(key) + paths.add(key) of cmdLongOption, cmdShortOption: case normalize(key) of "find", "f": incl(options, optFind) @@ -569,98 +1284,133 @@ for kind, key, val in getopt(): of "confirm": incl(options, optConfirm) of "stdin": incl(options, optStdin) of "word", "w": incl(options, optWord) - of "ignorecase", "i": incl(options, optIgnoreCase) - of "ignorestyle", "y": incl(options, optIgnoreStyle) - of "ext": extensions.add val.split('|') - of "noext": skipExtensions.add val.split('|') - of "excludedir", "exclude-dir": excludeDir.add rex(val) - of "includefile", "include-file": includeFile.add rex(val) - of "excludefile", "exclude-file": excludeFile.add rex(val) - of "nocolor": useWriteStyled = false + of "ignorecase", "ignore-case", "i": incl(options, optIgnoreCase) + of "ignorestyle", "ignore-style", "y": incl(options, optIgnoreStyle) + of "threads", "j": + if val == "": + nWorkers = countProcessors() + else: + nWorkers = parseNonNegative(val, key) + of "ext": walkOpt.extensions.add val.split('|') + of "noext", "no-ext": walkOpt.skipExtensions.add val.split('|') + of "excludedir", "exclude-dir", "ed": walkOpt.excludeDir.add val + of "includedir", "include-dir", "id": walkOpt.includeDir.add val + of "includefile", "include-file", "if": walkOpt.includeFile.add val + of "excludefile", "exclude-file", "ef": walkOpt.excludeFile.add val + of "match": searchOpt.checkMatch = val + of "nomatch": + searchOpt.checkNoMatch = val + of "bin": + case val + of "on": searchOpt.checkBin = biOn + of "off": searchOpt.checkBin = biOff + of "only": searchOpt.checkBin = biOnly + else: reportError("unknown value for --bin") + of "text", "t": searchOpt.checkBin = biOff + of "count": incl(options, optCount) + of "sorttime", "sort-time", "s": + case normalize(val) + of "off": sortTime = false + of "", "on", "asc", "ascending": + sortTime = true + sortTimeOrder = SortOrder.Ascending + of "desc", "descending": + sortTime = true + sortTimeOrder = SortOrder.Descending + else: reportError("invalid value '" & val & "' for --sortTime") + of "nocolor", "no-color": useWriteStyled = false of "color": case val of "auto": discard - of "never", "false": useWriteStyled = false - of "", "always", "true": useWriteStyled = true + of "off", "never", "false": useWriteStyled = false + of "", "on", "always", "true": useWriteStyled = true else: reportError("invalid value '" & val & "' for --color") - of "colortheme": + of "colortheme", "color-theme": colortheme = normalize(val) if colortheme notin ["simple", "bnw", "ack", "gnu"]: reportError("unknown colortheme '" & val & "'") of "beforecontext", "before-context", "b": - try: - linesBefore = parseInt(val) - except ValueError: - reportError("option " & key & " requires an integer but '" & - val & "' was given") + linesBefore = parseNonNegative(val, key) of "aftercontext", "after-context", "a": - try: - linesAfter = parseInt(val) - except ValueError: - reportError("option " & key & " requires an integer but '" & - val & "' was given") + linesAfter = parseNonNegative(val, key) of "context", "c": - try: - linesContext = parseInt(val) - except ValueError: - reportError("option --context requires an integer but '" & - val & "' was given") - of "newline", "l": newLine = true - of "oneline": oneline = true - of "group", "g": oneline = false + linesContext = parseNonNegative(val, key) + of "newline", "l": + newLine = true + # Tabs are aligned automatically for --group, --newLine, --filenames + expandTabs = false + of "group", "g": + oneline = false + expandTabs = false + of "cols", "%": + incl(options, optLimitChars) + termWidth = terminalWidth() + if val == "auto" or key == "%": + limitCharUsr = termWidth + when defined(windows): # Windows cmd & powershell add an empty line + limitCharUsr -= 1 # when printing '\n' right after the last column + elif val == "": + limitCharUsr = 80 + else: + limitCharUsr = parseNonNegative(val, key) + of "onlyascii", "only-ascii", "@": + if val == "" or val == "on" or key == "@": + optOnlyAscii = true + elif val == "off": + optOnlyAscii = false + else: + printError("unknown value for --onlyAscii option") of "verbose": incl(options, optVerbose) - of "filenames": incl(options, optFilenames) + of "filenames": + incl(options, optFilenames) + expandTabs = false of "help", "h": writeHelp() of "version", "v": writeVersion() + of "": incl(options, optPipe) else: reportError("unrecognized option '" & key & "'") of cmdEnd: assert(false) # cannot happen checkOptions({optFind, optReplace}, "find", "replace") +checkOptions({optCount, optReplace}, "count", "replace") checkOptions({optPeg, optRegex}, "peg", "re") checkOptions({optIgnoreCase, optIgnoreStyle}, "ignore_case", "ignore_style") checkOptions({optFilenames, optReplace}, "filenames", "replace") +checkOptions({optPipe, optStdin}, "-", "stdin") +checkOptions({optPipe, optFilenames}, "-", "filenames") +checkOptions({optPipe, optConfirm}, "-", "confirm") +checkOptions({optPipe, optRecursive}, "-", "recursive") linesBefore = max(linesBefore, linesContext) linesAfter = max(linesAfter, linesContext) +if optPipe in options and paths.len != 0: + reportError("both - and paths are specified") + if optStdin in options: - pattern = ask("pattern [ENTER to exit]: ") - if pattern.len == 0: quit(0) + searchOpt.pattern = ask("pattern [ENTER to exit]: ") + if searchOpt.pattern.len == 0: quit(0) if optReplace in options: replacement = ask("replacement [supports $1, $# notations]: ") -if pattern.len == 0: +if optReplace in options and not replacementSet: + reportError("provide REPLACEMENT as second argument (use \"\" for empty one)") +if optReplace in options and paths.len == 0 and optPipe notin options: + reportError("provide paths for replacement explicitly (use . for current directory)") + +if searchOpt.pattern == "" and optFilenames notin options: reportError("empty pattern was given") else: - var counter = 0 - var errors = 0 - if filenames.len == 0: - filenames.add(os.getCurrentDir()) - if optRegex notin options: - if optWord in options: - pattern = r"(^ / !\letter)(" & pattern & r") !\letter" - if optIgnoreStyle in options: - pattern = "\\y " & pattern - elif optIgnoreCase in options: - pattern = "\\i " & pattern - let pegp = peg(pattern) - for f in items(filenames): - walker(pegp, f, counter, errors) + if paths.len == 0 and optPipe notin options: + paths.add(".") + if optPipe in options or nWorkers == 0: + run1Thread() else: - var reflags = {reStudy} - if optIgnoreStyle in options: - pattern = styleInsensitive(pattern) - if optWord in options: - # see https://github.com/nim-lang/Nim/issues/13528#issuecomment-592786443 - pattern = r"(^|\W)(:?" & pattern & r")($|\W)" - if {optIgnoreCase, optIgnoreStyle} * options != {}: - reflags.incl reIgnoreCase - let rep = if optRex in options: rex(pattern, reflags) - else: re(pattern, reflags) - for f in items(filenames): - walker(rep, f, counter, errors) - if errors != 0: - printError $errors & " errors" - stdout.write($counter & " matches\n") - if errors != 0: + runMultiThread() + if gVar.errors != 0: + printError $gVar.errors & " errors" + if searchOpt.pattern != "": + # PATTERN allowed to be empty if --filenames is given + printBold($gVar.matches & " matches") + stdout.write("\n") + if gVar.errors != 0: quit(1) diff --git a/tools/nimgrep.nim.cfg b/tools/nimgrep.nim.cfg index 6d0ea5aad..64d3edc7a 100644 --- a/tools/nimgrep.nim.cfg +++ b/tools/nimgrep.nim.cfg @@ -1,5 +1,4 @@ -# The GC is stable enough now: - -#--gc:none - - +# don't use --gc:refc because of bug +# https://github.com/nim-lang/Nim/issues/14138 . +# --gc:orc and --gc:markandsweep work well. +--threads:on --gc:orc From d03f24147a185091344c67a720a13ca0b3c98dc2 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Mon, 9 Nov 2020 11:02:01 +0200 Subject: [PATCH 1417/4254] Add a macro returning enum items count (#15824) Add a macro `enumLen` which is used to determine the number of items in an enumeration type to the `typetraits.nim` module. Also, add unit tests for it in the `ttypetraits.nim` module. Related to nimlang/Nim#15824 --- changelog.md | 2 ++ lib/pure/typetraits.nim | 13 +++++++++++ tests/metatype/ttypetraits.nim | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/changelog.md b/changelog.md index 53730ecc5..d00d07fa1 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,8 @@ - Make `{.requiresInit.}` pragma to work for `distinct` types. +- Added a macros `enumLen` for returning the number of items in an enum to the `typetraits.nim` module. + - `prelude` now works with the JavaScript target. - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 0a05b5ded..7b6c94cbd 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -107,6 +107,19 @@ since (1, 3, 5): import std/macros +macro enumLen*(T: typedesc[enum]): int = + ## Returns the number of items in the enum `T`. + + runnableExamples: + type Foo = enum fooItem1 fooItem2 + doAssert Foo.enumLen == 2 + + let bracketExpr = getType(T) + expectKind(bracketExpr, nnkBracketExpr) + let enumTy = bracketExpr[1] + expectKind(enumTy, nnkEnumTy) + result = newLit(enumTy.len - 1) + macro genericParamsImpl(T: typedesc): untyped = # auxiliary macro needed, can't do it directly in `genericParams` result = newNimNode(nnkTupleConstr) diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 50c474fe9..326faac82 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -303,3 +303,43 @@ block: # elementType var a: seq[int] doAssert elementType(a) is int doAssert elementType(seq[char].default) is char + +block: # enum.len + type + Direction = enum + north, east, south, west + + Direction2 = Direction + Direction3 = Direction2 + + TokenType = enum + a = 2, b = 4, c = 89 + + MyEnum = enum + ##[This is test of enum with a doc comment. + + Which is also a multi line one.]## + valueA = (0, "my value A"), + ## The items are also commented. This has both integer and string + ## values. + valueB = "value B", + ## This item has only a string value, + valueC = 2, + ## and this one only an integer. + valueD = (3, "abc") + ## Both, integer and string values again. + + OtherEnum {.pure.} = enum + valueX, valueY, valueZ + + MyFlag {.size: sizeof(cint).} = enum + A, B, C, D + + static: + doAssert Direction.enumLen == 4 + doAssert Direction2.enumLen == 4 + doAssert Direction3.enumLen == 4 + doAssert TokenType.enumLen == 3 + doAssert MyEnum.enumLen == 4 + doAssert OtherEnum.enumLen == 3 + doAssert MyFlag.enumLen == 4 From 3be404af0488805493a46329d35ad276d739151d Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Mon, 9 Nov 2020 10:45:43 +0000 Subject: [PATCH 1418/4254] include example of error-marked copy proc (#15886) * include example of error-marked copy proc * Update destructors.rst --- doc/destructors.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index 66f1043b3..e48e360dd 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -184,8 +184,14 @@ The general pattern in ``=copy`` looks like: The ``=copy`` proc can be marked with the ``{.error.}`` pragma. Then any assignment -that otherwise would lead to a copy is prevented at compile-time. +that otherwise would lead to a copy is prevented at compile-time. This looks like: +.. code-block:: nim + + proc `=copy`(dest: var T; source: T) {.error.} + +but a custom error message (e.g., ``{.error: "custom error".}``) will not be emitted +by the compiler. Notice that there is no ``=`` before the ``{.error.}`` pragma. Move semantics ============== From 673c5990c6b2130dd3b1a4854eb5d85c73a90cd0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 9 Nov 2020 18:46:25 +0800 Subject: [PATCH 1419/4254] fix #12558 (#15864) * fix #12558 * Update compiler/pragmas.nim --- compiler/pragmas.nim | 6 +++++- tests/pragmas/t12558.nim | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/t12558.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 8affccbf3..1ec0aa112 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -896,7 +896,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wMagic: processMagic(c, it, sym) of wCompileTime: noVal(c, it) - incl(sym.flags, sfCompileTime) + if comesFromPush: + if sym.kind in {skProc, skFunc}: + incl(sym.flags, sfCompileTime) + else: + incl(sym.flags, sfCompileTime) #incl(sym.loc.flags, lfNoDecl) of wGlobal: noVal(c, it) diff --git a/tests/pragmas/t12558.nim b/tests/pragmas/t12558.nim new file mode 100644 index 000000000..14fc74cee --- /dev/null +++ b/tests/pragmas/t12558.nim @@ -0,0 +1,15 @@ +discard """ + nimout: '''@["1", "2", "3"]''' +""" + +import sequtils + +{.push compile_time.} + +proc foo = + echo map_it([1, 2, 3], $it) + +{.pop.} + +static: + foo() From 7b192177984d77355ce67f8cfa4aee227be73e7b Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 9 Nov 2020 10:47:29 +0000 Subject: [PATCH 1420/4254] fix #15707 (#15870) --- compiler/astalgo.nim | 4 ++-- compiler/semmagic.nim | 26 ++++++++++++++++++-------- compiler/sempass2.nim | 4 ++-- tests/arc/t14383.nim | 14 ++++++++++++++ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index d9cd5ade1..832f8819a 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -110,14 +110,14 @@ proc iiTablePut*(t: var TIITable, key, val: int) # implementation -proc skipConvAndClosure*(n: PNode): PNode = +proc skipConvCastAndClosure*(n: PNode): PNode = result = n while true: case result.kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64, nkClosure: result = result[0] - of nkHiddenStdConv, nkHiddenSubConv, nkConv: + of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: result = result[1] else: break diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 5e6b4dbe2..3368bcfbf 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -527,14 +527,24 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}: localError(c.config, n.info, "finalizer must be a direct reference to a proc") elif optTinyRtti in c.config.globalOptions: - let fin = if n[^1].kind in {nkLambda, nkDo}: n[^1][namePos].sym - else: n[^1].sym - # check if we converted this finalizer into a destructor already: - let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef})) - if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == fin: - discard "already turned this one into a finalizer" - else: - bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor) + let nfin = skipConvCastAndClosure(n[^1]) + let fin = case nfin.kind + of nkSym: nfin.sym + of nkLambda, nkDo: nfin[namePos].sym + else: + localError(c.config, n.info, "finalizer must be a direct reference to a proc") + nil + if fin != nil: + if fin.kind notin {skProc, skFunc}: + # calling convention is checked in codegen + localError(c.config, n.info, "finalizer must be a direct reference to a proc") + + # check if we converted this finalizer into a destructor already: + let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef})) + if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == fin: + discard "already turned this one into a finalizer" + else: + bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor) result = n of mDestroy: result = n diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 92a896a38..39ba1b307 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -510,7 +510,7 @@ proc procVarCheck(n: PNode; conf: ConfigRef) = proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = let n = n.skipConv if paramType.isNil or paramType.kind != tyTypeDesc: - procVarCheck skipConvAndClosure(n), tracked.config + procVarCheck skipConvCastAndClosure(n), tracked.config #elif n.kind in nkSymChoices: # echo "came here" let paramType = paramType.skipTypesOrNil(abstractInst) @@ -556,7 +556,7 @@ proc isTrival(caller: PNode): bool {.inline.} = result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved, mSwap} proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) = - let a = skipConvAndClosure(n) + let a = skipConvCastAndClosure(n) let op = a.typ # assume indirect calls are taken here: if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and not isTrival(caller): diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim index f112a1a6c..834c50def 100644 --- a/tests/arc/t14383.nim +++ b/tests/arc/t14383.nim @@ -34,3 +34,17 @@ echo x import std/os discard getFileInfo(".") + + +#------------------------------------------------------------------------------ +# Issue #15707 +#------------------------------------------------------------------------------ + +type + JVMObject = ref object +proc freeJVMObject(o: JVMObject) = + discard +proc fromJObject(T: typedesc[JVMObject]): T = + result.new(cast[proc(r: T) {.nimcall.}](freeJVMObject)) + +discard JVMObject.fromJObject() \ No newline at end of file From 204435ad97d7de20316d75cd7299cfa807361427 Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 9 Nov 2020 19:05:17 +0800 Subject: [PATCH 1421/4254] export PrettyOptions,prettyPrint from nimpretty (#15865) --- nimpretty/nimpretty.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index 0fb2c6a9e..a7940349d 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -44,11 +44,11 @@ proc writeVersion() = quit(0) type - PrettyOptions = object - indWidth: Natural - maxLineLen: Positive + PrettyOptions* = object + indWidth*: Natural + maxLineLen*: Positive -proc prettyPrint(infile, outfile: string, opt: PrettyOptions) = +proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) = var conf = newConfigRef() let fileIdx = fileInfoIdx(conf, AbsoluteFile infile) let f = splitFile(outfile.expandTilde) @@ -119,4 +119,5 @@ proc main = os.copyFile(source = infile, dest = infileBackup) prettyPrint(infile, outfile, opt) -main() +when isMainModule: + main() From 3bff12b96612be4e47e20d880d3ba9e57e8bf713 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Mon, 9 Nov 2020 11:20:55 +0000 Subject: [PATCH 1422/4254] improve Testament docs (#15881) * fix mentions of recursive test discovery * document that {.fatal.} pragmas cannot be caught --- doc/testament.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/testament.rst b/doc/testament.rst index 18501f4cd..09c248d1f 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -58,12 +58,12 @@ Running all tests from a directory $ testament pattern "tests/*.nim" -To recursively search for all tests in a directory, use +To search for tests deeper in a directory, use .. code:: - $ testament pattern "tests/**/*.nim" - + $ testament pattern "tests/**/*.nim" # one level deeper + $ testament pattern "tests/**/**/*.nim" # two levels deeper HTML Reports ============ @@ -89,7 +89,9 @@ Example "template" **to edit** and write a Testament unittest: # Options: # "compile": expect successful compilation # "run": expect successful compilation and execution - # "reject": expect failed compilation + # "reject": expect failed compilation. The "reject" action can catch + # {.error.} pragmas but not {.fatal.} pragmas because + # {.fatal.} pragmas guarantee that compilation will be aborted. action: "run" # The exit code that the test is expected to return. Typically, the default From d5a0a5dfffcf77e3221e8522e023e5485a2c37cc Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 9 Nov 2020 11:21:56 +0000 Subject: [PATCH 1423/4254] Fix #15858 (#15887) * fix #15858 * fix space * fix #15629 * Revert "fix #15629" --- compiler/semtypes.nim | 2 +- tests/statictypes/tstatictypes.nim | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 467645aee..f111f6308 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -306,7 +306,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType = result = makeRangeWithStaticExpr(c, e) if c.inGenericContext > 0: result.flags.incl tfUnresolved elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e): - if not isOrdinalType(e.typ): + if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})): localError(c.config, n[1].info, errOrdinalTypeExpected) # This is an int returning call, depending on an # yet unknown generic param (see tgenericshardcases). diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 359ae4c9f..fe1d1c8ca 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -349,3 +349,11 @@ type a: array[n, int] Tile = TileCT #Commenting this out to make it work + +#------------------------------------------------------------------------------------------ +# issue #15858 + +proc fn(N1: static int, N2: static int, T: typedesc): array[N1 * N2, T] = + doAssert(len(result) == N1 * N2) + +let yy = fn(5, 10, float) From 69fe7070250e0dbbcc0fafff4e341d1d805b7d59 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 9 Nov 2020 11:26:12 +0000 Subject: [PATCH 1424/4254] Fix 15629 (#15888) * fix #15858 * fix space * fix #15629 * Revert "fix space" * Revert "fix #15858" --- compiler/varpartitions.nim | 23 +++++++++++++---------- tests/arc/topt_cursor2.nim | 29 +++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 34a64c759..2e781c041 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -45,6 +45,8 @@ proc `<`(a, b: AbstractTime): bool {.borrow.} proc inc(x: var AbstractTime; diff = 1) {.borrow.} proc dec(x: var AbstractTime; diff = 1) {.borrow.} +proc `$`(x: AbstractTime): string {.borrow.} + type SubgraphFlag = enum isMutated, # graph might be mutated @@ -591,33 +593,34 @@ proc deps(c: var Partitions; dest, src: PNode) = for s in sources: connect(c, t, s, dest.info) - if cursorInference in c.goals and src.kind != nkEmpty: - if dest.kind == nkSym: - let vid = variableId(c, dest.sym) + if cursorInference in c.goals and src.kind != nkEmpty: + let d = pathExpr(dest, c.owner) + if d != nil and d.kind == nkSym: + let vid = variableId(c, d.sym) if vid >= 0: destMightOwn(c, c.s[vid], src) for s in sources: - if s == dest.sym: + if s == d.sym: discard "assignments like: it = it.next are fine" elif {sfGlobal, sfThread} * s.flags != {} or hasDisabledAsgn(s.typ): # do not borrow from a global variable or from something with a # disabled assignment operator. c.s[vid].flags.incl preventCursor - when explainCursors: echo "A not a cursor: ", dest.sym, " ", s + when explainCursors: echo "A not a cursor: ", d.sym, " ", s else: let srcid = variableId(c, s) if srcid >= 0: if s.kind notin {skResult, skParam} and ( c.s[srcid].aliveEnd < c.s[vid].aliveEnd): # you cannot borrow from a local that lives shorter than 'vid': - when explainCursors: echo "B not a cursor ", dest.sym, " ", c.s[srcid].aliveEnd, " ", c.s[vid].aliveEnd + when explainCursors: echo "B not a cursor ", d.sym, " ", c.s[srcid].aliveEnd, " ", c.s[vid].aliveEnd c.s[vid].flags.incl preventCursor elif {isReassigned, preventCursor} * c.s[srcid].flags != {}: # you cannot borrow from something that is re-assigned: - when explainCursors: echo "C not a cursor ", dest.sym, " ", c.s[srcid].flags, " reassignedTo ", c.s[srcid].reassignedTo + when explainCursors: echo "C not a cursor ", d.sym, " ", c.s[srcid].flags, " reassignedTo ", c.s[srcid].reassignedTo c.s[vid].flags.incl preventCursor - elif c.s[srcid].reassignedTo != 0 and c.s[srcid].reassignedTo != dest.sym.id: - when explainCursors: echo "D not a cursor ", dest.sym, " reassignedTo ", c.s[srcid].reassignedTo + elif c.s[srcid].reassignedTo != 0 and c.s[srcid].reassignedTo != d.sym.id: + when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo c.s[vid].flags.incl preventCursor const @@ -900,4 +903,4 @@ proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = discard "cannot cursor into a graph that is mutated" else: v.sym.flags.incl sfCursor - #echo "this is now a cursor ", v.sym, " ", par.s[rid].flags, " ", config $ v.sym.info + #echo "this is now a cursor ", v.sym, " ", par.s[rid].flags, " ", config $ v.sym.info \ No newline at end of file diff --git a/tests/arc/topt_cursor2.nim b/tests/arc/topt_cursor2.nim index 2e6fb256f..4b566ed24 100644 --- a/tests/arc/topt_cursor2.nim +++ b/tests/arc/topt_cursor2.nim @@ -1,6 +1,8 @@ -discard """ - output: '''emptyemptyempty''' +discard """ cmd: '''nim c --gc:arc $file''' + output: '''emptyemptyempty +inner destroy +''' """ # bug #15039 @@ -49,3 +51,26 @@ proc parse() = echo children parse() + + +#------------------------------------------------------------------------------ +# issue #15629 + +type inner = object +type outer = ref inner + +proc `=destroy`(b: var inner) = + echo "inner destroy" + +proc newOuter(): outer = + new(result) + +type holder = object + contents: outer + +proc main() = + var t: holder + t.contents = newOuter() + +main() + From 3948b40bcd79a3883529608bf4bd156c2e9de5f8 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 9 Nov 2020 13:08:17 +0100 Subject: [PATCH 1425/4254] CI(actions): Replace deprecated `add-path` commands (#15892) This commit resolves the following warning in the CI logs: > Error: The `add-path` command is deprecated and will be disabled soon. > Please upgrade to using Environment Files. For more information see: > https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/ The deprecation is due to an injection vulnerability (CVE-2020-15228). See: - https://bugs.chromium.org/p/project-zero/issues/detail?id=2070 - https://github.com/nim-lang/Nim/runs/1373146963#step:8:1 --- .github/workflows/ci.yml.disabled | 4 ++-- .github/workflows/ci_docs.yml | 4 ++-- .github/workflows/ci_packages.yml | 4 ++-- .github/workflows/ci_ssl.yml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml.disabled b/.github/workflows/ci.yml.disabled index 446560663..183576456 100644 --- a/.github/workflows/ci.yml.disabled +++ b/.github/workflows/ci.yml.disabled @@ -85,11 +85,11 @@ jobs: curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip 7z x dist/mingw64.7z -odist 7z x dist/dlls.zip -obin - echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" + echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - name: 'Add build binaries to PATH' shell: bash - run: echo "::add-path::${{ github.workspace }}/bin" + run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - name: 'Build csources' shell: bash diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 718dcd7e3..74ca804f3 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -64,11 +64,11 @@ jobs: curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip 7z x dist/mingw64.7z -odist 7z x dist/dlls.zip -obin - echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" + echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - name: 'Add build binaries to PATH' shell: bash - run: echo "::add-path::${{ github.workspace }}/bin" + run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - name: 'Get current csources version' id: csources-version diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 0d2f89aa6..59e918f58 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -48,11 +48,11 @@ jobs: curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip 7z x dist/mingw64.7z -odist 7z x dist/dlls.zip -obin - echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" + echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - name: 'Add build binaries to PATH' shell: bash - run: echo "::add-path::${{ github.workspace }}/bin" + run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - name: 'Build csources' shell: bash diff --git a/.github/workflows/ci_ssl.yml b/.github/workflows/ci_ssl.yml index 6a024eca0..0ec7aeb3b 100644 --- a/.github/workflows/ci_ssl.yml +++ b/.github/workflows/ci_ssl.yml @@ -49,11 +49,11 @@ jobs: curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip 7z x dist/mingw64.7z -odist 7z x dist/dlls.zip -obin - echo "::add-path::${{ github.workspace }}/dist/mingw64/bin" + echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - name: 'Add build binaries to PATH' shell: bash - run: echo "::add-path::${{ github.workspace }}/bin" + run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - name: 'Build 1-stage compiler from csources' shell: bash From 53eca459f1d96c710238be95bd3fb048b336f2f3 Mon Sep 17 00:00:00 2001 From: Aethylia Date: Mon, 9 Nov 2020 13:14:06 +0000 Subject: [PATCH 1426/4254] Added [:T] syntax explanation to generics tutorial. (#15890) * Added [:T] syntax explanation to generics tutorial. * Update doc/tut2.rst Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Update doc/tut2.rst Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Made second generics example runnable and added test line. * Update doc/tut2.rst * Update doc/tut2.rst * Update doc/tut2.rst Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: Andreas Rumpf --- doc/tut2.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/tut2.rst b/doc/tut2.rst index 94725a5d8..32faf452c 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -534,6 +534,19 @@ iterator or type. As the example shows, generics work with overloading: the best match of ``add`` is used. The built-in ``add`` procedure for sequences is not hidden and is used in the ``preorder`` iterator. +There is a special ``[:T]`` syntax when using generics with the method call syntax: + +.. code-block:: nim + :test: "nim c $1" + proc foo[T](i: T) = + discard + + var i: int + + # i.foo[int]() # Error: expression 'foo(i)' has no type (or is ambiguous) + + i.foo[:int]() # Success + Templates ========= From c1664f93b0024b558ff359f13ab6cd2e6c1b5cc7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 9 Nov 2020 09:07:22 -0600 Subject: [PATCH 1427/4254] new: `nim -e:cmd` to run a command directly; also fixes #15731 (#15687) * new: `nim -i cmd` * rename -i to -e (for eval); consistent with majority of other programing languages * `nim e -e:cmd` now works; bugfix: `echo cmd | nim e -` now works * honor --betterRun * address comments * --eval alias for -e (replaces undocumented --eval which was a noop) * --eval now defaults to e (nimscript) instead of r * address comment: remove -e, only keep --eval * address comment * fixup * Update compiler/nimconf.nim Co-authored-by: Andreas Rumpf --- changelog.md | 1 + compiler/cmdlinehelper.nim | 6 +++++- compiler/commands.nim | 25 +++++++++++++++++++------ compiler/extccomp.nim | 11 +++++++++++ compiler/main.nim | 5 +++-- compiler/modules.nim | 13 +++++++++---- compiler/msgs.nim | 1 + compiler/nim.nim | 3 ++- compiler/nimconf.nim | 21 +++++++++++++-------- compiler/options.nim | 5 +++-- compiler/scriptconfig.nim | 4 ++-- compiler/vm.nim | 3 +++ doc/basicopt.txt | 3 +++ 13 files changed, 75 insertions(+), 26 deletions(-) diff --git a/changelog.md b/changelog.md index d00d07fa1..54a32b2a1 100644 --- a/changelog.md +++ b/changelog.md @@ -33,6 +33,7 @@ - Added `--declaredlocs` to show symbol declaration location in messages. - Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. +- Added `nim --eval:cmd` to evaluate a command directly, see `nim --help` ## Tool changes diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index a415afce9..d5a26717d 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -41,7 +41,9 @@ proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) = proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = self.processCmdLine(passCmd1, "", conf) - if self.supportsStdinFile and conf.projectName == "-": + if conf.projectIsCmd and conf.projectName in ["-", ""]: + handleCmdInput(conf) + elif self.supportsStdinFile and conf.projectName == "-": handleStdinInput(conf) elif conf.projectName != "": try: @@ -59,6 +61,8 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi graph: ModuleGraph): bool = if self.suggestMode: conf.command = "nimsuggest" + if conf.command == "e": + incl(conf.globalOptions, optWasNimscript) loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files if not self.suggestMode: diff --git a/compiler/commands.nim b/compiler/commands.nim index cb7517f06..7a94fb612 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -383,19 +383,33 @@ proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, in expectArg(conf, switch, arg, pass, info) options.inclDynlibOverride(conf, arg) -proc handleStdinInput*(conf: ConfigRef) = - conf.projectName = "stdinfile" +template handleStdinOrCmdInput = conf.projectFull = conf.projectName.AbsoluteFile conf.projectPath = AbsoluteDir getCurrentDir() - conf.projectIsStdin = true if conf.outDir.isEmpty: conf.outDir = getNimcacheDir(conf) +proc handleStdinInput*(conf: ConfigRef) = + conf.projectName = "stdinfile" + conf.projectIsStdin = true + handleStdinOrCmdInput() + +proc handleCmdInput*(conf: ConfigRef) = + conf.projectName = "cmdfile" + handleStdinOrCmdInput() + proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = var key, val: string case switch.normalize + of "eval": + expectArg(conf, switch, arg, pass, info) + conf.projectIsCmd = true + conf.cmdInput = arg # can be empty (a nim file with empty content is valid too) + if conf.command == "": + conf.command = "e" # better than "r" as a default + conf.implicitCmd = true of "path", "p": expectArg(conf, switch, arg, pass, info) for path in nimbleSubs(conf, arg): @@ -781,9 +795,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "def": expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideDef - of "eval": - expectArg(conf, switch, arg, pass, info) - conf.evalExpr = arg of "context": expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideCon @@ -936,6 +947,8 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = proc processArgument*(pass: TCmdLinePass; p: OptParser; argsCount: var int; config: ConfigRef): bool = + if argsCount == 0 and config.implicitCmd: + argsCount.inc if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endsWith(".nims"): diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 11b001f9d..d97f9a887 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1022,6 +1022,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = lit ",\L\"stdinInput\": " lit $(%* conf.projectIsStdin) + lit ",\L\"projectIsCmd\": " + lit $(%* conf.projectIsCmd) + lit ",\L\"cmdInput\": " + lit $(%* conf.cmdInput) if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): lit ",\L\"cmdline\": " @@ -1051,11 +1055,18 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol return true if not data.hasKey("stdinInput"): return true let stdinInput = data["stdinInput"].getBool + let projectIsCmd = data["projectIsCmd"].getBool if conf.projectIsStdin or stdinInput: # could optimize by returning false if stdin input was the same, # but I'm not sure how to get full stding input return true + if conf.projectIsCmd or projectIsCmd: + if not (conf.projectIsCmd and projectIsCmd): return true + if not data.hasKey("cmdInput"): return true + let cmdInput = data["cmdInput"].getStr + if cmdInput != conf.cmdInput: return true + let depfilesPairs = data["depfiles"] doAssert depfilesPairs.kind == JArray for p in depfilesPairs: diff --git a/compiler/main.nim b/compiler/main.nim index af9102414..242bc0719 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -348,11 +348,12 @@ proc mainCommand*(graph: ModuleGraph) = conf.cmd = cmdInteractive commandInteractive(graph) of "e": - if not fileExists(conf.projectFull): + if conf.projectIsCmd or conf.projectIsStdin: discard + elif not fileExists(conf.projectFull): rawMessage(conf, errGenerated, "NimScript file does not exist: " & conf.projectFull.string) elif not conf.projectFull.string.endsWith(".nims"): rawMessage(conf, errGenerated, "not a NimScript file: " & conf.projectFull.string) - # main NimScript logic handled in cmdlinehelper.nim. + # main NimScript logic handled in `loadConfigs`. of "nop", "help": # prevent the "success" message: conf.cmd = cmdDump diff --git a/compiler/modules.nim b/compiler/modules.nim index 87a6bc507..748b74953 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -82,6 +82,13 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P var flags = flags if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule result = graph.getModule(fileIdx) + + template processModuleAux = + var s: PLLStream + if sfMainModule in flags: + if graph.config.projectIsStdin: s = stdin.llStreamOpen + elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput) + discard processModule(graph, result, idGeneratorFromModule(result), s) if result == nil: let filename = AbsoluteFile toFullPath(graph.config, fileIdx) result = loadModuleSym(graph, fileIdx, filename) @@ -91,15 +98,13 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P registerModule(graph, result) else: partialInitModule(result, graph, fileIdx, filename) - discard processModule(graph, result, idGeneratorFromModule(result), - if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil) + processModuleAux() elif graph.isDirty(result): result.flags.excl sfDirty # reset module fields: initStrTable(result.tab) result.ast = nil - discard processModule(graph, result, idGeneratorFromModule(result), - if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil) + processModuleAux() graph.markClientsDirty(fileIdx) proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 0f5879ff6..7b691323f 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -523,6 +523,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, let s = if isRaw: arg else: getMessageStr(msg, arg) if not ignoreMsg: let loc = if info != unknownLineInfo: conf.toFileLineCol(info) & " " else: "" + # we could also show `conf.cmdInput` here for `projectIsCmd` var kindmsg = if kind.len > 0: KindFormat % kind else: "" if conf.structuredErrorHook != nil: conf.structuredErrorHook(conf, info, s & kindmsg, sev) diff --git a/compiler/nim.nim b/compiler/nim.nim index 15aeccb33..9ff0eedbc 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -79,7 +79,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = self.processCmdLineAndProjectPath(conf) var graph = newModuleGraph(cache, conf) - if not self.loadConfigsAndRunMainCommand(cache, conf, graph): return + if not self.loadConfigsAndRunMainCommand(cache, conf, graph): + return mainCommand(graph) if conf.hasHint(hintGCStats): echo(GC_getStatistics()) #echo(GC_getStatistics()) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 05f234ce6..b6ec1bbc8 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -248,11 +248,16 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: if readConfigFile(configPath, cache, conf): configFiles.add(configPath) - template runNimScriptIfExists(path: AbsoluteFile) = + template runNimScriptIfExists(path: AbsoluteFile, isMain = false) = let p = path # eval once - if fileExists(p): + var s: PLLStream + if isMain and optWasNimscript in conf.globalOptions: + if conf.projectIsStdin: s = stdin.llStreamOpen + elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput) + if s == nil and fileExists(p): s = llStreamOpen(p, fmRead) + if s != nil: configFiles.add(p) - runNimScript(cache, p, idgen, freshDefines = false, conf) + runNimScript(cache, p, idgen, freshDefines = false, conf, s) if optSkipSystemConfigFile notin conf.globalOptions: readConfigFile(getSystemConfigPath(conf, cfg)) @@ -288,19 +293,19 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: runNimScriptIfExists(pd / DefaultConfigNims) let scriptFile = conf.projectFull.changeFileExt("nims") - let isMain = scriptFile == conf.projectFull + let scriptIsProj = scriptFile == conf.projectFull template showHintConf = for filename in configFiles: # delayed to here so that `hintConf` is honored rawMessage(conf, hintConf, filename.string) - if isMain: + if scriptIsProj: showHintConf() configFiles.setLen 0 if conf.command != "nimsuggest": - runNimScriptIfExists(scriptFile) + runNimScriptIfExists(scriptFile, isMain = true) else: - if not isMain: - runNimScriptIfExists(scriptFile) + if not scriptIsProj: + runNimScriptIfExists(scriptFile, isMain = true) else: # 'nimsuggest foo.nims' means to just auto-complete the NimScript file discard diff --git a/compiler/options.nim b/compiler/options.nim index 872ab9582..58d09938c 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -246,11 +246,13 @@ type evalMacroCounter*: int exitcode*: int8 cmd*: TCommands # the command + cmdInput*: string # input command + projectIsCmd*: bool # whether we're compiling from a command input + implicitCmd*: bool # whether some flag triggered an implicit `command` selectedGC*: TGCMode # the selected GC (+) exc*: ExceptionSystem verbosity*: int # how verbose the compiler is numberOfProcessors*: int # number of processors - evalExpr*: string # expression for idetools --eval lastCmdTime*: float # when caas is enabled, we measure each command symbolFiles*: SymbolFilesOption @@ -418,7 +420,6 @@ proc newConfigRef*(): ConfigRef = macrosToExpand: newStringTable(modeStyleInsensitive), arcToExpand: newStringTable(modeStyleInsensitive), m: initMsgConfig(), - evalExpr: "", cppDefines: initHashSet[string](), headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting}, diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index ab7e5e0b5..a353278d6 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -199,7 +199,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; idgen: IdGenerator; - freshDefines=true; conf: ConfigRef) = + freshDefines=true; conf: ConfigRef, stream: PLLStream) = let oldSymbolFiles = conf.symbolFiles conf.symbolFiles = disabledSf @@ -226,7 +226,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; graph.vm = vm graph.compileSystemModule() - discard graph.processModule(m, vm.idgen, llStreamOpen(scriptName, fmRead)) + discard graph.processModule(m, vm.idgen, stream) # watch out, "newruntime" can be set within NimScript itself and then we need # to remember this: diff --git a/compiler/vm.nim b/compiler/vm.nim index 761186dc3..8aac11ff7 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2114,6 +2114,9 @@ proc evalStmt*(c: PCtx, n: PNode) = discard execute(c, start) proc evalExpr*(c: PCtx, n: PNode): PNode = + # deadcode + # `nim --eval:"expr"` might've used it at some point for idetools; could + # be revived for nimsuggest let n = transformExpr(c.graph, c.idgen, c.module, n) let start = genExpr(c, n) assert c.code[start].opcode != opcEof diff --git a/doc/basicopt.txt b/doc/basicopt.txt index 7ea55cf6c..a2db1c92e 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -31,6 +31,9 @@ Options: --app:console|gui|lib|staticlib generate a console app|GUI app|DLL|static library -r, --run run the compiled program with given arguments + --eval:cmd evaluates nim code directly; e.g.: `nim --eval:"echo 1"` + defaults to `e` (nimscript) but customizable: + `nim r --eval:'for a in stdin.lines: echo a'` --fullhelp show all command line switches -h, --help show this help -v, --version show detailed version information From 338602a4021771c8a1cbcedfe30738c67b957646 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 9 Nov 2020 18:24:32 +0000 Subject: [PATCH 1428/4254] fix #15825 (#15894) * fix #15825 * better fix --- compiler/semtypes.nim | 2 +- tests/destructor/tdestructor3.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f111f6308..5feb25a59 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1056,7 +1056,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, # disable the bindOnce behavior for the type class result = recurse(paramType.base, true) - of tyAlias, tyOwned: + of tyAlias, tyOwned, tySink: result = recurse(paramType.base) of tySequence, tySet, tyArray, tyOpenArray, diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index eb49f3f15..3f5eb2cc1 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -172,3 +172,14 @@ when true: # D20200607T202043 main2() + +#------------------------------------------------------------ +# Issue #15825 + +type + Union = string | int | char + +proc run(a: sink Union) = + discard + +run("123") From d8e7caf5dd4ab70b7429896c1587cde992e7855a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 10 Nov 2020 09:23:58 +0800 Subject: [PATCH 1429/4254] follow #15874(add testcase for #15874) (#15893) --- tests/stdlib/tterminal_15874.nim | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/stdlib/tterminal_15874.nim diff --git a/tests/stdlib/tterminal_15874.nim b/tests/stdlib/tterminal_15874.nim new file mode 100644 index 000000000..c3455c350 --- /dev/null +++ b/tests/stdlib/tterminal_15874.nim @@ -0,0 +1,8 @@ +discard """ + cmd: "nim c --app:console $file" + action: "compile" +""" + +import terminal + +writeStyled("hello", {styleBright}) From ee78d7610853f4866c9b3d1e81d523b7ef339da0 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 10 Nov 2020 09:41:26 +0100 Subject: [PATCH 1430/4254] rst: add support for markdown tables (#15854) * rst: add support for markdown tables * change template into proc * don't create unnecessary `seq[string]` --- compiler/docgen.nim | 1 + compiler/lineinfos.nim | 30 +++++++------ lib/packages/docutils/rst.nim | 73 ++++++++++++++++++++++++++++++++ lib/packages/docutils/rstast.nim | 2 +- lib/packages/docutils/rstgen.nim | 2 +- tests/stdlib/trstgen.nim | 24 +++++++++++ 6 files changed, 116 insertions(+), 16 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 7609c96ee..8f6b7a560 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -127,6 +127,7 @@ template declareClosures = of meCannotOpenFile: k = errCannotOpenFile of meExpected: k = errXExpected of meGridTableNotImplemented: k = errGridTableNotImplemented + of meMarkdownIllformedTable: k = errMarkdownIllformedTable of meNewSectionExpected: k = errNewSectionExpected of meGeneralParseError: k = errGeneralParseError of meInvalidDirective: k = errInvalidDirectiveX diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 759002312..f9ea90caf 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -30,42 +30,43 @@ type errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errXExpected, errGridTableNotImplemented, + errMarkdownIllformedTable, errGeneralParseError, errNewSectionExpected, errInvalidDirectiveX, errProveInit, # deadcode errGenerated, errUser, - - warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", + + warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit", warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated", - warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", - warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX", - warnLanguageXNotSupported = "LanguageXNotSupported", warnFieldXNotSupported = "FieldXNotSupported", + warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", + warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX", + warnLanguageXNotSupported = "LanguageXNotSupported", warnFieldXNotSupported = "FieldXNotSupported", warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam", - warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap", + warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap", warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport", warnInheritFromException = "InheritFromException", warnEachIdentIsTuple = "EachIdentIsTuple", warnUnsafeSetLen = "UnsafeSetLen", warnUnsafeDefault = "UnsafeDefault", warnProveInit = "ProveInit", warnProveField = "ProveField", warnProveIndex = "ProveIndex", warnUnreachableElse = "UnreachableElse", warnUnreachableCode = "UnreachableCode", warnStaticIndexCheck = "IndexCheck", warnGcUnsafe = "GcUnsafe", warnGcUnsafe2 = "GcUnsafe2", - warnUninit = "Uninit", warnGcMem = "GcMem", warnDestructor = "Destructor", - warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed", - warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition", - warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores", + warnUninit = "Uninit", warnGcMem = "GcMem", warnDestructor = "Destructor", + warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed", + warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition", + warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores", warnUser = "User", hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", - hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", - hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintCodeBegin = "CodeBegin", + hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", + hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintCodeBegin = "CodeBegin", hintCodeEnd = "CodeEnd", hintConf = "Conf", hintPath = "Path", - hintConditionAlwaysTrue = "CondTrue", hintConditionAlwaysFalse = "CondFalse", hintName = "Name", + hintConditionAlwaysTrue = "CondTrue", hintConditionAlwaysFalse = "CondFalse", hintName = "Name", hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency", - hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace", + hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace", hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro", hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext", hintMsgOrigin = "MsgOrigin", # since 1.3.5 @@ -79,6 +80,7 @@ const errCannotOpenFile: "cannot open '$1'", errXExpected: "'$1' expected", errGridTableNotImplemented: "grid table is not implemented", + errMarkdownIllformedTable: "illformed delimiter row of a markdown table", errGeneralParseError: "general parse error", errNewSectionExpected: "new section expected", errInvalidDirectiveX: "invalid directive: '$1'", diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 56bfe580b..c04a6e07c 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -36,6 +36,7 @@ type meCannotOpenFile, meExpected, meGridTableNotImplemented, + meMarkdownIllformedTable, meNewSectionExpected, meGeneralParseError, meInvalidDirective, @@ -53,6 +54,7 @@ const meCannotOpenFile: "cannot open '$1'", meExpected: "'$1' expected", meGridTableNotImplemented: "grid table is not implemented", + meMarkdownIllformedTable: "illformed delimiter row of a markdown table", meNewSectionExpected: "new section expected", meGeneralParseError: "general parse error", meInvalidDirective: "invalid directive: '$1'", @@ -1091,6 +1093,13 @@ proc isMarkdownHeadline(p: RstParser): bool = if p.tok[p.idx+2].kind in {tkWord, tkOther, tkPunct}: result = true +proc findPipe(p: RstParser, start: int): bool = + var i = start + while true: + if p.tok[i].symbol == "|": return true + if p.tok[i].kind in {tkIndent, tkEof}: return false + inc i + proc whichSection(p: RstParser): RstNodeKind = case p.tok[p.idx].kind of tkAdornment: @@ -1104,6 +1113,9 @@ proc whichSection(p: RstParser): RstNodeKind = of tkPunct: if isMarkdownHeadline(p): result = rnHeadline + elif roSupportMarkdown in p.s.options and predNL(p) and + match(p, p.idx, "| w") and findPipe(p, p.idx+3): + result = rnMarkdownTable elif p.tok[p.idx].symbol == "```": result = rnCodeBlock elif match(p, tokenAfterNewline(p), "ai"): @@ -1206,6 +1218,9 @@ proc parseHeadline(p: var RstParser): PRstNode = type IntSeq = seq[int] + ColumnLimits = tuple + first, last: int + ColSeq = seq[ColumnLimits] proc tokEnd(p: RstParser): int = result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1 @@ -1280,6 +1295,63 @@ proc parseSimpleTable(p: var RstParser): PRstNode = add(a, b) add(result, a) +proc readTableRow(p: var RstParser): ColSeq = + if p.tok[p.idx].symbol == "|": inc p.idx + while p.tok[p.idx].kind notin {tkIndent, tkEof}: + var limits: ColumnLimits + limits.first = p.idx + while p.tok[p.idx].kind notin {tkIndent, tkEof}: + if p.tok[p.idx].symbol == "|" and p.tok[p.idx-1].symbol != "\\": break + inc p.idx + limits.last = p.idx + result.add(limits) + if p.tok[p.idx].kind in {tkIndent, tkEof}: break + inc p.idx + p.idx = tokenAfterNewline(p) + +proc getColContents(p: var RstParser, colLim: ColumnLimits): string = + for i in colLim.first ..< colLim.last: + result.add(p.tok[i].symbol) + result.strip + +proc isValidDelimiterRow(p: var RstParser, colNum: int): bool = + let row = readTableRow(p) + if row.len != colNum: return false + for limits in row: + let content = getColContents(p, limits) + if content.len < 3 or not (content.startsWith("--") or content.startsWith(":-")): + return false + return true + +proc parseMarkdownTable(p: var RstParser): PRstNode = + var + row: ColSeq + colNum: int + a, b: PRstNode + q: RstParser + result = newRstNode(rnMarkdownTable) + + proc parseRow(p: var RstParser, cellKind: RstNodeKind, result: PRstNode) = + row = readTableRow(p) + if colNum == 0: colNum = row.len # table header + elif row.len < colNum: row.setLen(colNum) + a = newRstNode(rnTableRow) + for j in 0 ..< colNum: + b = newRstNode(cellKind) + initParser(q, p.s) + q.col = p.col + q.line = p.tok[p.idx].line - 1 + q.filename = p.filename + q.col += getTokens(getColContents(p, row[j]), false, q.tok) + b.add(parseDoc(q)) + a.add(b) + result.add(a) + + parseRow(p, rnTableHeaderCell, result) + if not isValidDelimiterRow(p, colNum): rstMessage(p, meMarkdownIllformedTable) + while predNL(p) and p.tok[p.idx].symbol == "|": + parseRow(p, rnTableDataCell, result) + proc parseTransition(p: var RstParser): PRstNode = result = newRstNode(rnTransition) inc(p.idx) @@ -1461,6 +1533,7 @@ proc parseSection(p: var RstParser, result: PRstNode) = of rnHeadline: a = parseHeadline(p) of rnOverline: a = parseOverline(p) of rnTable: a = parseSimpleTable(p) + of rnMarkdownTable: a = parseMarkdownTable(p) of rnOptionList: a = parseOptionList(p) else: #InternalError("rst.parseSection()") diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 044ea2c14..8b2159aeb 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -37,7 +37,7 @@ type rnLineBlock, # the | thingie rnLineBlockItem, # sons of the | thing rnBlockQuote, # text just indented - rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, + rnTable, rnGridTable, rnMarkdownTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, rnLabel, # used for footnotes and other things rnFootnote, # a footnote rnCitation, # similar to footnote diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index c70998edb..604cc3ca9 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1094,7 +1094,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnBlockQuote: renderAux(d, n, "

      $1

      \n", "\\begin{quote}$1\\end{quote}\n", result) - of rnTable, rnGridTable: + of rnTable, rnGridTable, rnMarkdownTable: renderAux(d, n, "$1
      ", "\\begin{table}\\begin{rsttab}{" & diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 8fdbf3911..d35bc5821 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -153,3 +153,27 @@ suite "YAML syntax highlighting": assert a == """(( Nim ))""" assert b == """((Nim))""" assert c == """[Nim]""" + + test "Markdown tables": + let input1 = """ +| A1 header | A2 \| not fooled +| :--- | ----: | +| C1 | C2 **bold** | ignored | +| D1 `code \|` | D2 | also ignored +| E1 \| text | +| | F2 without pipe +not in table""" + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + assert output1 == """ + + + + +
      A1 headerA2 | not fooled
      C1C2 bold
      D1 code |D2
      E1 | text
      F2 without pipe

      not in table

      +""" + let input2 = """ +| A1 header | A2 | +| --- | --- |""" + let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + assert output2 == """ +
      A1 headerA2
      """ From 17acf146a07e89ecb7499ee0910417f83fd1ee25 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 10 Nov 2020 12:46:13 +0100 Subject: [PATCH 1431/4254] followup #15854: add a changelog entry about markdown tables support --- changelog.md | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 54a32b2a1..801d50b94 100644 --- a/changelog.md +++ b/changelog.md @@ -6,24 +6,35 @@ - Make `{.requiresInit.}` pragma to work for `distinct` types. -- Added a macros `enumLen` for returning the number of items in an enum to the `typetraits.nim` module. +- Added a macros `enumLen` for returning the number of items in an enum to the + `typetraits.nim` module. - `prelude` now works with the JavaScript target. -- Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`. +- Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate + `FileHandle` using C function `dup` and `dup2`. + - Added `almostEqual` in `math` for comparing two float values using a machine epsilon. -- The JSON module can now handle integer literals and floating point literals of arbitrary length and precision. - Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are kept as string literals and - one can use external BigNum libraries to handle these. The `parseFloat` family of functions also has now optional - `rawIntegers` and `rawFloats` parameters that can be used to enforce that all integer or float literals remain - in the "raw" string form so that client code can easily treat small and large numbers uniformly. +- The JSON module can now handle integer literals and floating point literals of + arbitrary length and precision. + Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are + kept as string literals and one can use external BigNum libraries to handle these. + The `parseFloat` family of functions also has now optional `rawIntegers` and + `rawFloats` parameters that can be used to enforce that all integer or float + literals remain in the "raw" string form so that client code can easily treat + small and large numbers uniformly. -- Added `randState` template that exposes the default random number generator. Useful for library authors. +- Added `randState` template that exposes the default random number generator. + Useful for library authors. + +- Added std/enumutils module containing `genEnumCaseStmt` macro that generates + case statement to parse string to enum. + +- Removed deprecated `iup` module from stdlib, it has already moved to + [nimble](https://github.com/nim-lang/iup). -- Added std/enumutils module containing `genEnumCaseStmt` macro that generates case statement to parse string to enum. -- Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). ## Language changes @@ -32,8 +43,18 @@ ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. -- Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. -- Added `nim --eval:cmd` to evaluate a command directly, see `nim --help` + +- Source+Edit links now appear on top of every docgen'd page when + `nim doc --git.url:url ...` is given. + +- Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`. + ## Tool changes + +- The rst parser now supports markdown table syntax. + Known limitations: + - cell alignment is not supported, i.e. alignment annotations in a delimiter + row (`:---`, `:--:`, `---:`) are ignored, + - every table row must start with `|`, e.g. `| cell 1 | cell 2 |`. From b38f0403fd3c66fdeab3806a12e1a19bcb696e03 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 10 Nov 2020 20:15:16 +0800 Subject: [PATCH 1432/4254] fix #12471 (#15901) * fix #12471 * add testcase * fix * test nimdoc is tricky * Delete t12471.nim --- lib/pure/selectors.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index e89cc7447..933b5491a 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -47,6 +47,9 @@ when defined(nimdoc): Selector*[T] = ref object ## An object which holds descriptors to be checked for read/write status + IOSelectorsException* = object of CatchableError + ## Exception that is raised if an IOSelectors error occurs. + Event* {.pure.} = enum ## An enum which hold event types Read, ## Descriptor is available for read From c44ae647a9f3c987eed2b2c1c31f127f986c24f9 Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 10 Nov 2020 13:25:05 +0100 Subject: [PATCH 1433/4254] fix `norm` package testing command --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index ef7dded4b..22d58ba3e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -88,7 +88,7 @@ pkg2 "nimterop", "nimble minitest" pkg2 "nimwc", "nim c nimwc.nim" # pkg2 "nimx", "nim c --threads:on test/main.nim" # pkg2 "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" -pkg2 "norm", "nim c -r tests/tsqliterows.nim" +pkg2 "norm", "nim c -r tests/sqlite/trows.nim" pkg2 "npeg", "nimble testarc" pkg2 "numericalnim", "nim c -r tests/test_integrate.nim" pkg2 "optionsutils" From bc3c0487d3059900864d6e8074cf83555a5c446d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 10 Nov 2020 10:54:10 -0600 Subject: [PATCH 1434/4254] remove ioutils mention in changelog (#15907) --- changelog.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/changelog.md b/changelog.md index 801d50b94..bc8ad2295 100644 --- a/changelog.md +++ b/changelog.md @@ -11,9 +11,6 @@ - `prelude` now works with the JavaScript target. -- Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate - `FileHandle` using C function `dup` and `dup2`. - - Added `almostEqual` in `math` for comparing two float values using a machine epsilon. - The JSON module can now handle integer literals and floating point literals of From bbe49a14ae827b6474d692042406716a3b3dd71f Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 10 Nov 2020 21:53:25 +0100 Subject: [PATCH 1435/4254] Correct all eggs (#15906) * "eg" is a misspelled "egg", "e.g." is "exempli gratia" * Also, "ie" is "i.e.". --- build_all.sh | 4 ++-- compiler/main.nim | 2 +- compiler/msgs.nim | 8 ++++---- compiler/packagehandling.nim | 4 ++-- compiler/renderer.nim | 2 +- compiler/semcall.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/sigmatch.nim | 4 ++-- compiler/strutils2.nim | 2 +- compiler/types.nim | 2 +- compiler/vm.nim | 4 ++-- koch.nim | 8 ++++---- lib/core/macros.nim | 4 ++-- lib/pure/times.nim | 2 +- lib/std/jsonutils.nim | 2 +- lib/system/jssys.nim | 2 +- lib/system/strmantle.nim | 2 +- nimdoc/testproject/testproject.nim | 2 +- testament/categories.nim | 4 ++-- tests/config.nims | 2 +- tests/deps/jester-#head/jester/request.nim | 2 +- tests/deps/x11-1.0/xvlib.nim | 2 +- tests/misc/trunner.nim | 2 +- tests/stdlib/tjsonutils.nim | 2 +- tools/ci_generate.nim | 2 +- 26 files changed, 38 insertions(+), 38 deletions(-) diff --git a/build_all.sh b/build_all.sh index d3bba2211..e66980e56 100755 --- a/build_all.sh +++ b/build_all.sh @@ -1,7 +1,7 @@ #! /bin/sh # build development version of the compiler; can be rerun safely. -# arguments can be passed, eg `--os freebsd` +# arguments can be passed, e.g. `--os freebsd` set -u # error on undefined variables set -e # exit on first error @@ -24,7 +24,7 @@ build_nim_csources(){ # avoid changing dir in case of failure ( if [ $# -ne 0 ]; then - # some args were passed (eg: `--cpu i386`), need to call build.sh + # some args were passed (e.g.: `--cpu i386`), need to call build.sh build_nim_csources_via_script "$@" else # no args, use multiple Make jobs (5X faster on 16 cores: 10s instead of 50s) diff --git a/compiler/main.nim b/compiler/main.nim index 242bc0719..f9b0dd413 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -260,7 +260,7 @@ proc mainCommand*(graph: ModuleGraph) = conf.setNoteDefaults(warnLockLevel, false) # issue #13218 conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 # because currently generates lots of false positives due to conflation - # of labels links in doc comments, eg for random.rand: + # of labels links in doc comments, e.g. for random.rand: # ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer # ## * `rand proc<#rand,Rand,range[]>`_ that returns a float commandDoc2(graph, false) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 7b691323f..be3dc5ec4 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -233,11 +233,11 @@ template toFullPathConsiderDirty*(conf: ConfigRef; info: TLineInfo): string = string toFullPathConsiderDirty(conf, info.fileIndex) type FilenameOption* = enum - foAbs # absolute path, eg: /pathto/bar/foo.nim - foRelProject # relative to project path, eg: ../foo.nim + foAbs # absolute path, e.g.: /pathto/bar/foo.nim + foRelProject # relative to project path, e.g.: ../foo.nim foMagicSauce # magic sauce, shortest of (foAbs, foRelProject) - foName # lastPathPart, eg: foo.nim - foShort # foName without extension, eg: foo + foName # lastPathPart, e.g.: foo.nim + foShort # foName without extension, e.g.: foo foStacktrace # if optExcessiveStackTrace: foAbs else: foName proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption): string = diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 9a3224de2..a781f1d51 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -16,7 +16,7 @@ iterator myParentDirs(p: string): string = yield current proc getNimbleFile*(conf: ConfigRef; path: string): string = - ## returns absolute path to nimble file, eg: /pathto/cligen.nimble + ## returns absolute path to nimble file, e.g.: /pathto/cligen.nimble var parents = 0 block packageSearch: for d in myParentDirs(path): @@ -35,7 +35,7 @@ proc getNimbleFile*(conf: ConfigRef; path: string): string = if parents <= 0: break proc getPackageName*(conf: ConfigRef; path: string): string = - ## returns nimble package name, eg: `cligen` + ## returns nimble package name, e.g.: `cligen` let path = getNimbleFile(conf, path) result = path.splitFile.name diff --git a/compiler/renderer.nim b/compiler/renderer.nim index a4152cf29..765bcded5 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1226,7 +1226,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = infixArgument(g, n, 1) put(g, tkSpaces, Space) gsub(g, n, 0) # binary operator - # eg: `n1 == n2` decompses as following sum: + # e.g.: `n1 == n2` decompses as following sum: if n.len == 3 and not fits(g, oldLineLen + lsub(g, n[1]) + lsub(g, n[2]) + lsub(g, n[0]) + len(" ")): optNL(g, g.indent + longIndentWid) else: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 0446d28c2..70a7e099c 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -326,7 +326,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string = var typeHint = "" if sym == nil: # Perhaps we're in a `compiles(foo.bar)` expression, or - # in a concept, eg: + # in a concept, e.g.: # ExplainedConcept {.explain.} = concept x # x.foo is int # We could use: `(c.config $ n[1].info)` to get more context. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b2f0207e7..cb119b3e8 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -432,7 +432,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = m.diagnostics = @[] m.diagnosticsEnabled = true res = typeRel(m, t2, t1) >= isSubtype # isNone - # `res = sameType(t1, t2)` would be wrong, eg for `int is (int|float)` + # `res = sameType(t1, t2)` would be wrong, e.g. for `int is (int|float)` result = newIntNode(nkIntLit, ord(res)) result.typ = n.typ diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4b79cd546..f83864775 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -435,7 +435,7 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = var b = a[0] if b.kind == nkPragmaExpr: if b[1].len != 1: - # we could in future support pragmas w args eg: `var foo {.bar:"goo".} = expr` + # we could in future support pragmas w args e.g.: `var foo {.bar:"goo".} = expr` return nil let nodePragma = b[1][0] # see: `singlePragma` diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d5039fcad..2e332f105 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1555,7 +1555,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, for i in 1.. varargs[T]) but we have already instantiated + # formal (e.g. seq[T] -> varargs[T]) but we have already instantiated # a container #assert arg.kind == nkHiddenStdConv # for 'nim check' # this assertion can be off diff --git a/compiler/strutils2.nim b/compiler/strutils2.nim index 6cb50347f..f44b811c7 100644 --- a/compiler/strutils2.nim +++ b/compiler/strutils2.nim @@ -12,7 +12,7 @@ proc dataPointer*[T](a: T): pointer = ## same as C++ `data` that works with std::string, std::vector etc. ## Note: safe to use when a.len == 0 but whether the result is nil or not ## is implementation defined for performance reasons. - # this could be improved with ocmpiler support to avoid the `if`, eg in C++ + # this could be improved with ocmpiler support to avoid the `if`, e.g. in C++ # `&a[0]` is well defined even if a.size() == 0 when T is string | seq: if a.len == 0: nil else: cast[pointer](a[0].unsafeAddr) diff --git a/compiler/types.nim b/compiler/types.nim index 42b7de416..1f2ee9d20 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -23,7 +23,7 @@ type preferTypeName, preferResolved, # fully resolved symbols preferMixed, - # most useful, shows: symbol + resolved symbols if it differs, eg: + # most useful, shows: symbol + resolved symbols if it differs, e.g.: # tuple[a: MyInt{int}, b: float] proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string diff --git a/compiler/vm.nim b/compiler/vm.nim index 8aac11ff7..a6478f3f0 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -765,7 +765,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if regs[rb].node.kind == nkRefTy: regs[ra].node = regs[rb].node[0] elif not maybeHandlePtr(regs[rb].node, regs[ra], false): - ## eg: typ.kind = tyObject + ## e.g.: typ.kind = tyObject ensureKind(rkNode) regs[ra].node = regs[rb].node else: @@ -996,7 +996,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if nb.kind != nc.kind: discard elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional elif sameConstant(nb, nc): ret = true - # this also takes care of procvar's, represented as nkTupleConstr, eg (nil, nil) + # this also takes care of procvar's, represented as nkTupleConstr, e.g. (nil, nil) elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit let tb = nb.getTyp let tc = nc.getTyp diff --git a/koch.nim b/koch.nim index e34fdb4f4..47bde9d18 100644 --- a/koch.nim +++ b/koch.nim @@ -63,7 +63,7 @@ Possible Commands: distrohelper [bindir] helper for distro packagers tools builds Nim related tools toolsNoExternal builds Nim related tools (except external tools, - ie. nimble) + e.g. nimble) doesn't require network connectivity nimble builds the Nimble tool fusion clone fusion into the working tree @@ -76,14 +76,14 @@ Boot options: for bootstrapping Commands for core developers: - runCI runs continuous integration (CI), eg from travis + runCI runs continuous integration (CI), e.g. from travis docs [options] generates the full documentation csource -d:danger builds the C sources for installation pdf builds the PDF documentation zip builds the installation zip package xz builds the installation tar.xz package testinstall test tar.xz package; Unix only! - installdeps [options] installs external dependency (eg tinyc) to dist/ + installdeps [options] installs external dependency (e.g. tinyc) to dist/ tests [options] run the testsuite (run a subset of tests by specifying a category, e.g. `tests cat async`) temp options creates a temporary compiler for testing @@ -93,7 +93,7 @@ Web options: build the official docs, use UA-48159761-1 """ -let kochExe* = when isMainModule: os.getAppFilename() # always correct when koch is main program, even if `koch` exe renamed eg: `nim c -o:koch_debug koch.nim` +let kochExe* = when isMainModule: os.getAppFilename() # always correct when koch is main program, even if `koch` exe renamed e.g.: `nim c -o:koch_debug koch.nim` else: getAppDir() / "koch".exe # works for winrelease proc kochExec*(cmd: string) = diff --git a/lib/core/macros.nim b/lib/core/macros.nim index e4a56d6f9..d2985bc72 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -160,7 +160,7 @@ proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} = ## Compares two Nim nodes' types. Return true if the types are the same, - ## eg. true when comparing alias with original type. + ## e.g. true when comparing alias with original type. discard proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.} @@ -280,7 +280,7 @@ else: # bootstrapping substitute when (NimMajor, NimMinor, NimPatch) >= (1, 3, 5) or defined(nimSymImplTransform): proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.} ## For a typed proc returns the AST after transformation pass; this is useful - ## for debugging how the compiler transforms code (eg: `defer`, `for`) but + ## for debugging how the compiler transforms code (e.g.: `defer`, `for`) but ## note that code transformations are implementation dependent and subject to change. ## See an example in `tests/macros/tmacros_various.nim`. diff --git a/lib/pure/times.nim b/lib/pure/times.nim index fb2f5e430..35dda131b 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1049,7 +1049,7 @@ since((1, 3)): export isInitialized proc isLeapDay*(dt: DateTime): bool {.since: (1, 1).} = - ## returns whether `t` is a leap day, ie, Feb 29 in a leap year. This matters + ## Returns whether `t` is a leap day, i.e. Feb 29 in a leap year. This matters ## as it affects time offset calculations. runnableExamples: let dt = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index dd174303a..50dcd9675 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -17,7 +17,7 @@ import std/[json,strutils,tables,sets,strtabs,options] #[ Future directions: -add a way to customize serialization, for eg: +add a way to customize serialization, for e.g.: * field renaming * allow serializing `enum` and `char` as `string` instead of `int` (enum is more compact/efficient, and robust to enum renamings, but string diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index df05a9a62..c4c671ea3 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -485,7 +485,7 @@ proc negInt64(a: int64): int64 {.compilerproc.} = result = a*(-1) proc nimFloatToString(a: float): cstring {.compilerproc.} = - ## ensures the result doesn't print like an integer, ie return 2.0, not 2 + ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 asm """ function nimOnlyDigitsOrMinus(n) { return n.toString().match(/^-?\d+$/); diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 21b790603..fa6ff411b 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -113,7 +113,7 @@ when defined(nimHasInvariant): proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {.compilerproc.} = # This routine attempt to parse float that can parsed quickly. - # ie whose integer part can fit inside a 53bits integer. + # i.e. whose integer part can fit inside a 53bits integer. # their real exponent must also be <= 22. If the float doesn't follow # these restrictions, transform the float into this form: # INTEGER * 10 ^ exponent and leave the work to standard `strtod()`. diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index ffddc356f..3cb7fddc5 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -49,7 +49,7 @@ proc isValid*[T](x: T): bool = x.len > 0 when true: # these cases appear redundant but they're actually (almost) all different at - # AST level and needed to ensure docgen keeps working, eg because of issues + # AST level and needed to ensure docgen keeps working, e.g. because of issues # like D20200526T163511 type Foo* = enum diff --git a/testament/categories.nim b/testament/categories.nim index fa9391055..0d19842ec 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -413,7 +413,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = proc isValid(file: string): bool = for dir in parentDirs(file, inclusive = false): if dir.lastPathPart in ["includes", "nimcache"]: - # eg: lib/pure/includes/osenv.nim gives: Error: This is an include file for os.nim! + # e.g.: lib/pure/includes/osenv.nim gives: Error: This is an include file for os.nim! return false let name = extractFilename(file) if name.splitFile.ext != ".nim": return false @@ -433,7 +433,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = #[ todo: this logic is fragile: - false positives (if appears in a comment), or false negatives, eg + false positives (if appears in a comment), or false negatives, e.g. `when defined(osx) and isMainModule`. Instead of fixing this, see https://github.com/nim-lang/Nim/issues/10045 for a much better way. diff --git a/tests/config.nims b/tests/config.nims index e91c3aa4f..640df9cad 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -1,7 +1,7 @@ switch("path", "$lib/../testament/lib") # so we can `import stdtest/foo` inside tests # Using $lib/../ instead of $nim/ so you can use a different nim to run tests - # during local testing, eg nim --lib:lib. + # during local testing, e.g. nim --lib:lib. ## prevent common user config settings to interfere with testament expectations ## Indifidual tests can override this if needed to test for these options. diff --git a/tests/deps/jester-#head/jester/request.nim b/tests/deps/jester-#head/jester/request.nim index 7c6a1a961..20e5c840f 100644 --- a/tests/deps/jester-#head/jester/request.nim +++ b/tests/deps/jester-#head/jester/request.nim @@ -56,7 +56,7 @@ proc path*(req: Request): string = return u.path proc reqMethod*(req: Request): HttpMethod = - ## Request method, eg. HttpGet, HttpPost + ## Request method, e.g. HttpGet, HttpPost when useHttpBeast: req.req.httpMethod.get() else: diff --git a/tests/deps/x11-1.0/xvlib.nim b/tests/deps/x11-1.0/xvlib.nim index e642cb350..354a4b93b 100644 --- a/tests/deps/x11-1.0/xvlib.nim +++ b/tests/deps/x11-1.0/xvlib.nim @@ -155,7 +155,7 @@ type vert_y_period*: cuint vert_u_period*: cuint vert_v_period*: cuint - component_order*: array[0..31, char] # eg. UYVY + component_order*: array[0..31, char] # e.g. UYVY scanline_order*: cint # XvTopToBottom, XvBottomToTop PXvImage* = ptr TXvImage diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index d67547d62..018916e67 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -149,7 +149,7 @@ mmain.html doAssert exitCode == 0, output block: let (output, exitCode) = runCmd(file, "-d:checkAbi -d:caseBad") - # on platforms that support _StaticAssert natively, errors will show full context, eg: + # on platforms that support _StaticAssert natively, errors will show full context, e.g.: # error: static_assert failed due to requirement 'sizeof(unsigned char) == 8' # "backend & Nim disagree on size for: BadImportcType{int64} [declared in mabi_check.nim(1, 6)]" check2 "sizeof(unsigned char) == 8" diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index fefd412e7..28f05ecbe 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -57,7 +57,7 @@ template fn() = """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null}]""" block: - # edge case when user defined `==` doesn't handle `nil` well, eg: + # edge case when user defined `==` doesn't handle `nil` well, e.g.: # https://github.com/nim-lang/nimble/blob/63695f490728e3935692c29f3d71944d83bb1e83/src/nimblepkg/version.nim#L105 testRoundtrip(@[Foo(id: 10), nil]): """[{"id":10},null]""" diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index bfed8d88f..dba10d74a 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -53,7 +53,7 @@ triggers: proc main()= let num = 3 # if you reduce this, make sure to remove files that shouldn't be generated, - # or better, do the cleanup logic here eg: `rm .builds/openbsd_*` + # or better, do the cleanup logic here e.g.: `rm .builds/openbsd_*` for i in 0.. Date: Wed, 11 Nov 2020 10:29:17 +0800 Subject: [PATCH 1436/4254] close #4318(add testcase for #4318) (#15904) * close #4318(add testcase for #4318) * Update tests/objects/t4318.nim Co-authored-by: Juan Carlos Co-authored-by: Juan Carlos --- tests/objects/t4318.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/objects/t4318.nim diff --git a/tests/objects/t4318.nim b/tests/objects/t4318.nim new file mode 100644 index 000000000..34ff722f5 --- /dev/null +++ b/tests/objects/t4318.nim @@ -0,0 +1,12 @@ +type + A = object of RootObj + B = object of A + +method identify(a:A) {.base.} = echo "A" +method identify(b:B) = echo "B" + +var b: B + +doAssertRaises(ObjectAssignmentDefect): + var a: A = b + discard a From 42c434fa3d48356bda8ba0b85cd940385f42edfb Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Wed, 11 Nov 2020 03:37:14 +0100 Subject: [PATCH 1437/4254] Docs(strutils): Fix broken links (#15912) The `dedent` and `unindent` links were introduced by commit d67c5cb75171 (#15264). --- lib/pure/strutils.nim | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 19a37425e..0eff80863 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1443,7 +1443,7 @@ proc indent*(s: string, count: Natural, padding: string = " "): string ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ ## * `spaces proc<#spaces,Natural>`_ ## * `unindent proc<#unindent,string,Natural,string>`_ - ## * `dedent proc<#dedent,string,Natural,string>`_ + ## * `dedent proc<#dedent,string,Natural>`_ runnableExamples: doAssert indent("First line\c\l and second line.", 2) == " First line\l and second line." @@ -1464,7 +1464,7 @@ proc unindent*(s: string, count: Natural = int.high, padding: string = " "): str ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `dedent proc<#dedent,string,Natural,string>` + ## * `dedent proc<#dedent,string,Natural>`_ ## * `align proc<#align,string,Natural,char>`_ ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ ## * `spaces proc<#spaces,Natural>`_ @@ -1506,14 +1506,15 @@ proc indentation*(s: string): Natural {.since: (1, 3).} = proc dedent*(s: string, count: Natural = indentation(s)): string {.noSideEffect, rtl, extern: "nsuDedent", since: (1, 3).} = ## Unindents each line in ``s`` by ``count`` amount of ``padding``. - ## The only difference between this and `unindent proc<#unindent,string,Natural,string>` - ## is that this by default only cuts off the amount of indentation that all - ## lines of ``s`` share as opposed to all indentation. It only supports spcaes as padding. + ## The only difference between this and the + ## `unindent proc<#unindent,string,Natural,string>`_ is that this by default + ## only cuts off the amount of indentation that all lines of ``s`` share as + ## opposed to all indentation. It only supports spaces as padding. ## ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `unindent proc<#unindent,string,Natural,string>` + ## * `unindent proc<#unindent,string,Natural,string>`_ ## * `align proc<#align,string,Natural,char>`_ ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ ## * `spaces proc<#spaces,Natural>`_ @@ -1905,7 +1906,7 @@ proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffe ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `rfind proc<#rfind,string,char,Natural,int>`_ + ## * `rfind proc<#rfind,string,char,Natural>`_ ## * `replace proc<#replace,string,char,char>`_ let last = if last == 0: s.high else: last when nimvm: @@ -1933,7 +1934,7 @@ proc find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.noS ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `rfind proc<#rfind,string,set[char],Natural,int>`_ + ## * `rfind proc<#rfind,string,set[char],Natural>`_ ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ let last = if last == 0: s.high else: last for i in int(start)..last: @@ -1950,7 +1951,7 @@ proc find*(s, sub: string, start: Natural = 0, last = 0): int {.noSideEffect, ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `rfind proc<#rfind,string,string,Natural,int>`_ + ## * `rfind proc<#rfind,string,string,Natural>`_ ## * `replace proc<#replace,string,string,string>`_ if sub.len > s.len: return -1 if sub.len == 1: return find(s, sub[0], start, last) From b831033db6c0bb7b11128383e8f186912f620fd1 Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 11 Nov 2020 14:02:35 +0100 Subject: [PATCH 1438/4254] remove `codeowners` [ci skip] --- doc/codeowners.rst | 65 -------------------------------------------- doc/contributing.rst | 5 +--- 2 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 doc/codeowners.rst diff --git a/doc/codeowners.rst b/doc/codeowners.rst deleted file mode 100644 index 4b4a5810e..000000000 --- a/doc/codeowners.rst +++ /dev/null @@ -1,65 +0,0 @@ -=========== -Code owners -=========== - - -Subsystems and code owners --------------------------- - -*Note*: This list is incomplete, in doubt dom96 is responsible for the standard -library, araq is responsible for the compiler. - - -Compiler -~~~~~~~~ - -=========================== ====================================================== -subsystem owner(s) -=========================== ====================================================== -Parsing, Lexing araq -Renderer cooldome, araq -Order of passes cooldome -Semantic Checking araq -Virtual machine jangko, GULPF, araq -Sempass2: effects tracking cooldome, araq -type system, concepts zahary -transf cooldome, araq -semfold constant folding araq -template instantiation zahary, araq -term rewriting macros cooldome, araq -closure iterators yglukhov, araq -lambda lifting yglukhov, araq -c, cpp codegen lemonboy, araq -js codegen yglukhov, lemonboy -alias analysis araq -dfa, writetracking araq -parallel, multithreading araq -incremental araq -sizeof computations krux02 -Exception handling cooldome, araq -=========================== ====================================================== - - - -Standard library -~~~~~~~~~~~~~~~~ - -====================== ====================================================== -subsystem owner(s) -====================== ====================================================== -async dom96 -strutils araq -sequtils dom96, araq -times GULPF -os dom96, araq -re araq -nre flaviu -math, fenv krux02, cooldome -io dom96 -garbage collector araq -Go garbage collector stefantalpalaru -coroutines Rokas Kupstys -collections GULPF -parseopt araq -json dom96 -====================== ====================================================== diff --git a/doc/contributing.rst b/doc/contributing.rst index f570336e2..6ddbd65bc 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -8,11 +8,8 @@ Contributing Contributing happens via "Pull requests" (PR) on github. Every PR needs to be reviewed before it can be merged and the Continuous Integration should be green. -The PR has to be approved (and is often merged too) by one "code owner", either -by the code owner who is responsible for the subsystem the PR belongs to or by -two core developers or by Araq. +The PR has to be approved by two core developers or by Araq. -See `codeowners `_ for more details. Writing tests From f02c7542fcd21d4b3d7b82908325512be4e5404a Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 11 Nov 2020 15:59:41 +0100 Subject: [PATCH 1439/4254] nimdoc: items of ordered lists now have numbers instead of circles --- doc/nimdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 457f024b5..2d9533ceb 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -410,7 +410,7 @@ ol ul { margin-bottom: 0; margin-left: 1.25em; } -li { +ul.simple > li { list-style-type: circle; } From a81434a890d70e7146c440c59caadc701c6099b3 Mon Sep 17 00:00:00 2001 From: Bung Date: Thu, 12 Nov 2020 01:41:49 +0800 Subject: [PATCH 1440/4254] Fix 14127 js from int to int casting (#15918) * fix #14127 from int to int casting * add test for #14127 * use template for test, also test uint2int * move to tests/types/t14127_cast_number.nim targets:c cpp js --- compiler/jsgen.nim | 3 +-- tests/types/t14127_cast_number.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/types/t14127_cast_number.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index d124ae5fe..87021de11 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2406,8 +2406,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = r.res = "($1 $2)" % [r.res, trimmer] elif toInt: if fromInt: - let trimmer = unsignedTrimmer(dest.size) - r.res = "($1 $2)" % [r.res, trimmer] + return elif fromUint: if src.size == 4 and dest.size == 4: # XXX prevent multi evaluations diff --git a/tests/types/t14127_cast_number.nim b/tests/types/t14127_cast_number.nim new file mode 100644 index 000000000..4bb23f22f --- /dev/null +++ b/tests/types/t14127_cast_number.nim @@ -0,0 +1,30 @@ +discard """ + targets: "c cpp js" +""" +block: # bug #14127 + template int2uint(T) = + var a = -1 + let b = cast[T](a) + doAssert b < 0 + let c = b + 1 + doAssert c is T + doAssert c == 0 + + int2uint(int8) + int2uint(int16) + int2uint(int32) + int2uint(int64) + +block: # maybe related + template uint2int(T) = + var a = 3 + let b = cast[T](a) + doAssert b > 0 + let c = b - 1 + doAssert c is T + doAssert c == 2 + + uint2int(uint8) + uint2int(uint16) + uint2int(uint32) + uint2int(uint64) From 826e62953faa1f6cd9bac582246186935af4b8e6 Mon Sep 17 00:00:00 2001 From: Bung Date: Thu, 12 Nov 2020 16:16:40 +0800 Subject: [PATCH 1441/4254] fix #12726 Cannot take the compile-time sizeof Atomic types (#15928) * fix #12726 Cannot take the compile-time sizeof Atomic types * fix for arch 32 --- lib/pure/concurrency/atomics.nim | 15 ++++++++------- tests/stdlib/concurrency/tatomics_size.nim | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 tests/stdlib/concurrency/tatomics_size.nim diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index eaa811aa6..dc575c6c0 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -51,10 +51,11 @@ when defined(cpp) or defined(nimdoc): ## with other moSequentiallyConsistent operations. type - Atomic* {.importcpp: "std::atomic".} [T] = object + Atomic*[T] {.importcpp: "std::atomic", completeStruct.} = object ## An atomic object with underlying type `T`. + raw: T - AtomicFlag* {.importcpp: "std::atomic_flag".} = object + AtomicFlag* {.importcpp: "std::atomic_flag", size: 1.} = object ## An atomic boolean state. # Access operations @@ -249,10 +250,10 @@ else: type # Atomic* {.importcpp: "_Atomic('0)".} [T] = object - AtomicInt8 {.importc: "_Atomic NI8".} = object - AtomicInt16 {.importc: "_Atomic NI16".} = object - AtomicInt32 {.importc: "_Atomic NI32".} = object - AtomicInt64 {.importc: "_Atomic NI64".} = object + AtomicInt8 {.importc: "_Atomic NI8", size: 1.} = object + AtomicInt16 {.importc: "_Atomic NI16", size: 2.} = object + AtomicInt32 {.importc: "_Atomic NI32", size: 4.} = object + AtomicInt64 {.importc: "_Atomic NI64", size: 8.} = object template atomicType*(T: typedesc[Trivial]): untyped = # Maps the size of a trivial type to it's internal atomic type @@ -262,7 +263,7 @@ else: elif sizeof(T) == 8: AtomicInt64 type - AtomicFlag* {.importc: "atomic_flag".} = object + AtomicFlag* {.importc: "atomic_flag", size: 1.} = object Atomic*[T] = object when T is Trivial: diff --git a/tests/stdlib/concurrency/tatomics_size.nim b/tests/stdlib/concurrency/tatomics_size.nim new file mode 100644 index 000000000..49387c0c1 --- /dev/null +++ b/tests/stdlib/concurrency/tatomics_size.nim @@ -0,0 +1,18 @@ +discard """ + targets: "c cpp" +""" +import std/atomics + +block testSize: # issue 12726 + type + Node = ptr object + # works + next: Atomic[pointer] + f:AtomicFlag + MyChannel = object + # type not defined completely + back: Atomic[ptr int] + f: AtomicFlag + static: + doAssert sizeof(Node) == sizeof(pointer) + doAssert sizeof(MyChannel) == sizeof(pointer) * 2 \ No newline at end of file From 1f9bf43100f7236d8ccbcaa14c43bc18f7e6e5d8 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 12 Nov 2020 16:20:10 +0800 Subject: [PATCH 1442/4254] fix #14157 (#15877) * fix #14157 * Update compiler/jsgen.nim * add changelog * Update compiler/jsgen.nim * Update tests/js/tmodify_cstring.nim Co-authored-by: Andreas Rumpf --- changelog.md | 2 ++ compiler/jsgen.nim | 4 ++++ tests/js/tmodify_cstring.nim | 6 ++++++ 3 files changed, 12 insertions(+) create mode 100644 tests/js/tmodify_cstring.nim diff --git a/changelog.md b/changelog.md index bc8ad2295..3bdf8a511 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,8 @@ ## Language changes +- The `cstring` doesn't support `[]=` operator in JS backend. + ## Compiler changes diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 87021de11..357e18000 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1049,6 +1049,10 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = var a, b: TCompRes var xtyp = mapType(p, x.typ) + # disable `[]=` for cstring + if x.kind == nkBracketExpr and x.len >= 2 and x[0].typ.skipTypes(abstractInst).kind == tyCString: + localError(p.config, x.info, "cstring doesn't support `[]=` operator") + gen(p, x, a) genLineDir(p, y) gen(p, y, b) diff --git a/tests/js/tmodify_cstring.nim b/tests/js/tmodify_cstring.nim new file mode 100644 index 000000000..82f8ccb23 --- /dev/null +++ b/tests/js/tmodify_cstring.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "cstring doesn't support `[]=` operator" +""" + +var x = cstring"abcd" +x[0] = 'x' From e5db5316c2101a27efd744ba10126fdb57a7eb7c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 12 Nov 2020 02:25:41 -0600 Subject: [PATCH 1443/4254] doAssertRaises improvements; nimscript supports `except Exception as e` (#15765) * doAssertRaises now correctly handles foreign exceptions; now shows which exception is raised on mismatch * nimscript now handles `Exception as e` * remove catch-all doAssertRaises overload from this PR Co-authored-by: Andreas Rumpf --- changelog.md | 3 ++- lib/system.nim | 3 ++- lib/system/assertions.nim | 19 ++++++++++--------- tests/test_nimscript.nims | 6 ++++++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 3bdf8a511..8b427bfc5 100644 --- a/changelog.md +++ b/changelog.md @@ -31,10 +31,11 @@ - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). - +- `doAssertRaises` now correctly handles foreign exceptions. ## Language changes +- `nimscript` now handles `except Exception as e` - The `cstring` doesn't support `[]=` operator in JS backend. diff --git a/lib/system.nim b/lib/system.nim index e41dfe1ca..fd5eb2dac 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2360,7 +2360,8 @@ when notJSnotNims and hostOS != "standalone": ## ## **Warning**: Only use this if you know what you are doing. currException = exc - +elif defined(nimscript): + proc getCurrentException*(): ref Exception {.compilerRtl.} = discard when notJSnotNims: {.push stackTrace: off, profiler: off.} diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index c6283c89c..1a4fda123 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -81,20 +81,23 @@ template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = code template doAssertRaises*(exception: typedesc, code: untyped) = - ## Raises ``AssertionDefect`` if specified ``code`` does not raise the - ## specified exception. Example: + ## Raises ``AssertionDefect`` if specified ``code`` does not raise `exception`. + ## Example: ## ## .. code-block:: nim ## doAssertRaises(ValueError): ## raise newException(ValueError, "Hello World") var wrong = false + const begin = "expected raising '" & astToStr(exception) & "', instead" + const msgEnd = " by: " & astToStr(code) + template raisedForeign = raiseAssert(begin & " raised foreign exception" & msgEnd) when Exception is exception: try: if true: code wrong = true - except Exception: - discard + except Exception as e: discard + except: raisedForeign() else: try: if true: @@ -102,9 +105,7 @@ template doAssertRaises*(exception: typedesc, code: untyped) = wrong = true except exception: discard - except Exception: - raiseAssert(astToStr(exception) & - " wasn't raised, another error was raised instead by:\n"& - astToStr(code)) + except Exception as e: raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd) + except: raisedForeign() if wrong: - raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code)) + raiseAssert(begin & " nothing was raised" & msgEnd) diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index b94146b1e..ea640cac6 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -81,3 +81,9 @@ block: # #14142 discard dirExists("/usr") discard fileExists("/usr/foo") discard findExe("nim") + +block: + doAssertRaises(AssertionDefect): doAssert false + try: doAssert false + except Exception as e: + discard From 7d4f70280ef33192dc5862f8b4c4d23e9d956b40 Mon Sep 17 00:00:00 2001 From: Fanael Linithien Date: Thu, 12 Nov 2020 09:28:32 +0100 Subject: [PATCH 1444/4254] Fix #15909 (#15914) --- compiler/varpartitions.nim | 1 + tests/arc/t15909.nim | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/arc/t15909.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 2e781c041..63c18d94a 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -399,6 +399,7 @@ proc allRoots(n: PNode; result: var seq[PSym]; followDotExpr = true) = proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = ## Analyse if 'n' is an expression that owns the data, if so mark 'dest' ## with 'ownsData'. + if n.typ == nil: return case n.kind of nkEmpty, nkCharLit..nkNilLit: # primitive literals including the empty are harmless: diff --git a/tests/arc/t15909.nim b/tests/arc/t15909.nim new file mode 100644 index 000000000..f25c89daf --- /dev/null +++ b/tests/arc/t15909.nim @@ -0,0 +1,16 @@ +discard """ + action: run + cmd: "nim c --gc:arc $file" +""" + +proc f1() {.noreturn.} = raise newException(CatchableError, "") + +proc f2(y: int): int = + if y != 0: + y + else: + f1() + +doAssert f2(5) == 5 +doAssertRaises(CatchableError): + discard f2(0) From 402df0b06139183fc8b982058774807a13534daf Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 12 Nov 2020 16:31:35 +0800 Subject: [PATCH 1445/4254] fix #15916 (#15917) [backport] * fix #15916 * add testcase for #15916 * add comments --- compiler/docgen.nim | 6 ++++-- tests/nimdoc/t15916.nim | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/nimdoc/t15916.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 8f6b7a560..57fdad12a 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -592,8 +592,10 @@ proc getRoutineBody(n: PNode): PNode = (0 or more) doc comments and runnableExamples. ]## result = n[bodyPos] - if result.kind == nkAsgn and n.len > bodyPos+1 and n[bodyPos+1].kind == nkSym: - doAssert result[0].kind == nkSym + + # This won't be transformed: result.id = 10. Namely result[0].kind != nkSym. + if result.kind == nkAsgn and result[0].kind == nkSym and + n.len > bodyPos+1 and n[bodyPos+1].kind == nkSym: doAssert result.len == 2 result = result[1] diff --git a/tests/nimdoc/t15916.nim b/tests/nimdoc/t15916.nim new file mode 100644 index 000000000..c6c09d94b --- /dev/null +++ b/tests/nimdoc/t15916.nim @@ -0,0 +1,16 @@ +discard """ +cmd: "nim doc --hints:off $file" +action: "compile" +joinable: false +""" + +type + Test* = object + id: int + +proc initTest*(id: int): Test = + result.id = id + +proc hello*() = + runnableExamples: + discard From c6ceefea6de2a0159f33722839bfe9a0ce9134e1 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Thu, 12 Nov 2020 02:32:38 -0600 Subject: [PATCH 1446/4254] Fix a problem for long symlinks in conda (#15908) [backport] * https://github.com/conda-forge/nim-feedstock/commit/d8c80ea69dca30d99073d33845ddd79f9892755b#diff-e1d8e552330911f9f779f85b6f2c00a15e790dcc3fbb3b28f5da1d660a30c5b8 --- lib/pure/os.nim | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 2601f9d47..234d82bc2 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1172,6 +1172,7 @@ when not defined(windows) and not weirdTarget: else: result = S_ISLNK(rawInfo.st_mode) const + maxSymlinkLen = 1024 ExeExts* = ## Platform specific file extension for executables. ## On Windows ``["exe", "cmd", "bat"]``, on Posix ``[""]``. when defined(windows): ["exe", "cmd", "bat"] else: [""] @@ -1213,11 +1214,11 @@ proc findExe*(exe: string, followSymlinks: bool = true; when not defined(windows): while followSymlinks: # doubles as if here if x.checkSymlink: - var r = newString(256) - var len = readlink(x, r, 256) + var r = newString(maxSymlinkLen) + var len = readlink(x, r, maxSymlinkLen) if len < 0: raiseOSError(osLastError(), exe) - if len > 256: + if len > maxSymlinkLen: r = newString(len+1) len = readlink(x, r, len) setLen(r, len) @@ -2561,11 +2562,11 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} = when defined(windows): result = symlinkPath else: - result = newString(256) - var len = readlink(symlinkPath, result, 256) + result = newString(maxSymlinkLen) + var len = readlink(symlinkPath, result, maxSymlinkLen) if len < 0: raiseOSError(osLastError(), symlinkPath) - if len > 256: + if len > maxSymlinkLen: result = newString(len+1) len = readlink(symlinkPath, result, len) setLen(result, len) @@ -2863,9 +2864,9 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly) or defined(netb when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)): proc getApplAux(procPath: string): string = - result = newString(256) - var len = readlink(procPath, result, 256) - if len > 256: + result = newString(maxSymlinkLen) + var len = readlink(procPath, result, maxSymlinkLen) + if len > maxSymlinkLen: result = newString(len+1) len = readlink(procPath, result, len) setLen(result, len) From 63c559e781cafaab6bcc9e62d5631e93749450bb Mon Sep 17 00:00:00 2001 From: lenoil98 Date: Thu, 12 Nov 2020 04:43:13 -0500 Subject: [PATCH 1447/4254] Add support for FreeBSD/PowerPC64 Little Endian (#15927) * Update installer.ini Add support for powerpc64 little endian * Update buildsh.nimf Add support for powerpc64 little endian * Update makefile.nimf Add support for freebsd/powerpc64 little endian --- compiler/installer.ini | 2 +- tools/niminst/buildsh.nimf | 5 ++++- tools/niminst/makefile.nimf | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index 01b7b8c6b..f0756ab3e 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -9,7 +9,7 @@ Platforms: """ linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64 macosx: i386;amd64;powerpc64 solaris: i386;amd64;sparc;sparc64 - freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc + freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el netbsd: i386;amd64 openbsd: i386;amd64;arm;arm64 dragonfly: i386;amd64 diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 5d532a0fd..5ec5d5c2c 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -159,7 +159,10 @@ case $ucpu in COMP_FLAGS="$COMP_FLAGS -m64" LINK_FLAGS="$LINK_FLAGS -m64" mycpu=`uname -p` - else + if [ "$(mycpu)" = "powerpc64le"] ; then + mycpu="powerpc64el" + fi + else mycpu="powerpc" fi ;; diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index ad9d55c03..aff0c5da0 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -124,6 +124,9 @@ ifeq ($(ucpu),powerpc) mycpu = $(shell sh -c 'uname -p | tr "[:upper:]" "[:lower:]"') CFLAGS += -m64 LDFLAGS += -m64 + ifeq ($(mycpu),powerpc64le) + mycpu = powerpc64el + endif endif endif ifeq ($(ucpu),ppc) From ef2677f5f3f58ad5bd514f82a0efd68d4d17e7f9 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 12 Nov 2020 17:47:56 +0800 Subject: [PATCH 1448/4254] change some code-blocks to runnableExamples and correct some errors in docs (#15900) * original docs are wrong * fix pathnorm * Update lib/pure/pathnorm.nim Co-authored-by: Juan Carlos --- lib/pure/httpcore.nim | 7 ++---- lib/pure/json.nim | 57 +++++++++++++++++++++---------------------- lib/pure/math.nim | 30 +++++++++++------------ lib/pure/pathnorm.nim | 14 +++++------ 4 files changed, 51 insertions(+), 57 deletions(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index b3d1da8d6..401e78b9b 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -262,11 +262,8 @@ func contains*(methods: set[HttpMethod], x: string): bool = func `$`*(code: HttpCode): string = ## Converts the specified ``HttpCode`` into a HTTP status. - ## - ## For example: - ## - ## .. code-block:: nim - ## doAssert($Http404 == "404 Not Found") + runnableExamples: + doAssert($Http404 == "404 Not Found") case code.int of 100: "100 Continue" of 101: "101 Switching Protocols" diff --git a/lib/pure/json.nim b/lib/pure/json.nim index a3f7a782e..063fad8b4 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -519,9 +519,10 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = ## This proc can be used to create tree structures on the ## fly (sometimes called `autovivification`:idx:): ## - ## .. code-block:: nim - ## myjson{"parent", "child", "grandchild"} = newJInt(1) - ## + runnableExamples: + var myjson = %* {"parent": {"child": {"grandchild": 1}}} + doAssert myjson{"parent", "child", "grandchild"} == newJInt(1) + result = node for key in keys: if isNil(result) or result.kind != JObject: @@ -1258,32 +1259,30 @@ when defined(nimFixedForwardGeneric): ## * Sets in object variants are not supported. ## * Not nil annotations are not supported. ## - ## Example: - ## - ## .. code-block:: Nim - ## let jsonNode = parseJson(""" - ## { - ## "person": { - ## "name": "Nimmer", - ## "age": 21 - ## }, - ## "list": [1, 2, 3, 4] - ## } - ## """) - ## - ## type - ## Person = object - ## name: string - ## age: int - ## - ## Data = object - ## person: Person - ## list: seq[int] - ## - ## var data = to(jsonNode, Data) - ## doAssert data.person.name == "Nimmer" - ## doAssert data.person.age == 21 - ## doAssert data.list == @[1, 2, 3, 4] + runnableExamples: + let jsonNode = parseJson(""" + { + "person": { + "name": "Nimmer", + "age": 21 + }, + "list": [1, 2, 3, 4] + } + """) + + type + Person = object + name: string + age: int + + Data = object + person: Person + list: seq[int] + + var data = to(jsonNode, Data) + doAssert data.person.name == "Nimmer" + doAssert data.person.age == 21 + doAssert data.list == @[1, 2, 3, 4] var jsonPath = "" initFromJson(result, node, jsonPath) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 2a2660524..59368fbd2 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -862,10 +862,10 @@ when not defined(js): ## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns ## m. ## - ## .. code-block:: nim - ## var x: int - ## echo frexp(5.0, x) # 0.625 - ## echo x # 3 + runnableExamples: + var x: int + doAssert frexp(5.0, x) == 0.625 + doAssert x == 3 var exp: int32 result = c_frexp(x, exp) exponent = exp @@ -929,9 +929,9 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = ## Both parts have the same sign as ``x``. Analogous to the ``modf`` ## function in C. ## - ## .. code-block:: nim - ## echo splitDecimal(5.25) # (intpart: 5.0, floatpart: 0.25) - ## echo splitDecimal(-2.73) # (intpart: -2.0, floatpart: -0.73) + runnableExamples: + doAssert splitDecimal(5.25) == (intpart: 5.0, floatpart: 0.25) + doAssert splitDecimal(-2.73) == (intpart: -2.0, floatpart: -0.73) var absolute: T absolute = abs(x) @@ -949,8 +949,8 @@ proc degToRad*[T: float32|float64](d: T): T {.inline.} = ## See also: ## * `radToDeg proc <#radToDeg,T>`_ ## - ## .. code-block:: nim - ## echo degToRad(180.0) # 3.141592653589793 + runnableExamples: + doAssert degToRad(180.0) == 3.141592653589793 result = T(d) * RadPerDeg proc radToDeg*[T: float32|float64](d: T): T {.inline.} = @@ -959,8 +959,8 @@ proc radToDeg*[T: float32|float64](d: T): T {.inline.} = ## See also: ## * `degToRad proc <#degToRad,T>`_ ## - ## .. code-block:: nim - ## echo degToRad(2 * PI) # 360.0 + runnableExamples: + doAssert radToDeg(2 * PI) == 360.0 result = T(d) / RadPerDeg proc sgn*[T: SomeNumber](x: T): int {.inline.} = @@ -971,10 +971,10 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = ## * `1` for positive numbers and ``Inf``, ## * `0` for positive zero, negative zero and ``NaN`` ## - ## .. code-block:: nim - ## echo sgn(5) # 1 - ## echo sgn(0) # 0 - ## echo sgn(-4.1) # -1 + runnableExamples: + doAssert sgn(5) == 1 + doAssert sgn(0) == 0 + doAssert sgn(-4.1) == -1 ord(T(0) < x) - ord(x < T(0)) {.pop.} diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 03a65bd60..5bc66f0b7 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -100,15 +100,13 @@ proc addNormalizePath*(x: string; result: var string; state: var int; if result == "" and x != "": result = "." proc normalizePath*(path: string; dirSep = DirSep): string = - ## Example: - ## - ## .. code-block:: nim - ## assert normalizePath("./foo//bar/../baz") == "foo/baz" - ## - ## + runnableExamples: + when defined(posix): + doAssert normalizePath("./foo//bar/../baz") == "foo/baz" + ## - Turns multiple slashes into single slashes. - ## - Resolves '/foo/../bar' to '/bar'. - ## - Removes './' from the path (but "foo/.." becomes ".") + ## - Resolves `'/foo/../bar'` to `'/bar'`. + ## - Removes `'./'` from the path, but `"foo/.."` becomes `"."`. result = newStringOfCap(path.len) var state = 0 addNormalizePath(path, result, state, dirSep) From 527e792827497002ded742ad815c567a4a056471 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Thu, 12 Nov 2020 13:44:21 +0300 Subject: [PATCH 1449/4254] make var string return var char w/ BackwardsIndex (#15461) * make var string return var char w/ BackwardsIndex fixes #14497 * work around VM bug * properly workaround again --- lib/pure/pathnorm.nim | 6 +++--- lib/system.nim | 1 + tests/stdlib/tstring.nim | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 5bc66f0b7..7834f8d95 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -69,7 +69,7 @@ proc addNormalizePath*(x: string; result: var string; state: var int; while hasNext(it, x): let b = next(it, x) if (state shr 1 == 0) and isSlash(x, b): - if result.len == 0 or result[^1] notin {DirSep, AltSep}: + if result.len == 0 or result[result.len - 1] notin {DirSep, AltSep}: result.add dirSep state = state or 1 elif isDotDot(x, b): @@ -87,13 +87,13 @@ proc addNormalizePath*(x: string; result: var string; state: var int; setLen(result, d-1) dec state, 2 else: - if result.len > 0 and result[^1] notin {DirSep, AltSep}: + if result.len > 0 and result[result.len - 1] notin {DirSep, AltSep}: result.add dirSep result.add substr(x, b[0], b[1]) elif isDot(x, b): discard "discard the dot" elif b[1] >= b[0]: - if result.len > 0 and result[^1] notin {DirSep, AltSep}: + if result.len > 0 and result[result.len - 1] notin {DirSep, AltSep}: result.add dirSep result.add substr(x, b[0], b[1]) inc state, 2 diff --git a/lib/system.nim b/lib/system.nim index fd5eb2dac..1104cb17f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2579,6 +2579,7 @@ proc `[]`*[T](s: var openArray[T]; i: BackwardsIndex): var T {.inline.} = system.`[]`(s, s.len - int(i)) proc `[]`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T {.inline.} = a[Idx(a.len - int(i) + int low(a))] +proc `[]`*(s: var string; i: BackwardsIndex): var char {.inline.} = s[s.len - int(i)] proc `[]=`*[T](s: var openArray[T]; i: BackwardsIndex; x: T) {.inline.} = system.`[]=`(s, s.len - int(i), x) diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 0a7bf0511..ff3d41b49 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -91,3 +91,10 @@ proc tester[T](x: T) = tester(1) +# #14497 +func reverse*(a: string): string = + result = a + for i in 0 ..< a.len div 2: + swap(result[i], result[^(i + 1)]) + +doAssert reverse("hello") == "olleh" From bc007a3cd32890d30501c7c0921681281be4ebb9 Mon Sep 17 00:00:00 2001 From: Bung Date: Thu, 12 Nov 2020 19:36:42 +0800 Subject: [PATCH 1450/4254] add parent property to window in dom.nim (#15922) --- lib/js/dom.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index a74c63231..d2e5776f0 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -154,6 +154,7 @@ type performance*: Performance onpopstate*: proc (event: Event) localStorage*: LocalStorage + parent*: Window Frame* = ref FrameObj FrameObj {.importc.} = object of WindowObj From cc882917feda383a283eb128f80bf49681921995 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 12 Nov 2020 07:36:57 -0600 Subject: [PATCH 1451/4254] js -d:nodejs now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv` (v2) (#15826) * js -d:nodejs now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv` * refactor to osenv * fix for js (without -d:nodejs) + VM Co-authored-by: Andreas Rumpf --- changelog.md | 2 + lib/pure/includes/osenv.nim | 452 +++++++++++++++++++----------------- tests/js/tos.nim | 26 +++ 3 files changed, 272 insertions(+), 208 deletions(-) diff --git a/changelog.md b/changelog.md index 8b427bfc5..ac1ec1163 100644 --- a/changelog.md +++ b/changelog.md @@ -31,6 +31,8 @@ - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). +- Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). +- nodejs now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv` - `doAssertRaises` now correctly handles foreign exceptions. ## Language changes diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index 01abf12df..55ace92f2 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -3,228 +3,264 @@ when not declared(os) and not declared(ospaths): {.error: "This is an include file for os.nim!".} -when defined(windows): - from parseutils import skipIgnoreCase +when defined(nodejs): + proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = + var ret: cstring + let key2 = key.cstring + {.emit: "`ret` = process.env[`key2`];".} + result = $ret -proc c_getenv(env: cstring): cstring {. - importc: "getenv", header: "".} -proc c_putenv(env: cstring): cint {. - importc: "putenv", header: "".} -proc c_unsetenv(env: cstring): cint {. - importc: "unsetenv", header: "".} + proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + var key2 = key.cstring + var ret: bool + {.emit: "`ret` = `key2` in process.env;".} + result = ret -# Environment handling cannot be put into RTL, because the ``envPairs`` -# iterator depends on ``environment``. + proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + var key2 = key.cstring + var val2 = val.cstring + {.emit: "process.env[`key2`] = `val2`;".} -var - envComputed {.threadvar.}: bool - environment {.threadvar.}: seq[string] + proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + var key2 = key.cstring + {.emit: "delete process.env[`key2`];".} -when defined(nimV2): - proc unpairedEnvAllocs*(): int = - result = environment.len - if result > 0: inc result + iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = + var num: int + var keys: RootObj + {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".} + for i in 0..".} - else: - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. - importc: "wcschr", header: "".} - else: - proc strEnd(cstr: cstring, c = 0'i32): cstring {. - importc: "strchr", header: "".} - - proc getEnvVarsC() = - if not envComputed: - environment = @[] - when useWinUnicode: - var - env = getEnvironmentStringsW() - e = env - if e == nil: return # an error occurred - while true: - var eend = strEnd(e) - add(environment, $e) - e = cast[WideCString](cast[ByteAddress](eend)+2) - if eend[1].int == 0: break - discard freeEnvironmentStringsW(env) - else: - var - env = getEnvironmentStringsA() - e = env - if e == nil: return # an error occurred - while true: - var eend = strEnd(e) - add(environment, $e) - e = cast[cstring](cast[ByteAddress](eend)+1) - if eend[1] == '\0': break - discard freeEnvironmentStringsA(env) - envComputed = true +# commented because it must keep working with js+VM +# elif defined(js): +# {.error: "requires -d:nodejs".} else: - const - useNSGetEnviron = (defined(macosx) and not defined(ios) and not defined(emscripten)) or defined(nimscript) + when defined(windows): + from parseutils import skipIgnoreCase - when useNSGetEnviron: - # From the manual: - # Shared libraries and bundles don't have direct access to environ, - # which is only available to the loader ld(1) when a complete program - # is being linked. - # The environment routines can still be used, but if direct access to - # environ is needed, the _NSGetEnviron() routine, defined in - # , can be used to retrieve the address of environ - # at runtime. - proc NSGetEnviron(): ptr cstringArray {. - importc: "_NSGetEnviron", header: "".} - elif defined(haiku): - var gEnv {.importc: "environ", header: "".}: cstringArray - else: - var gEnv {.importc: "environ".}: cstringArray + proc c_getenv(env: cstring): cstring {. + importc: "getenv", header: "".} + proc c_putenv(env: cstring): cint {. + importc: "putenv", header: "".} + proc c_unsetenv(env: cstring): cint {. + importc: "unsetenv", header: "".} - proc getEnvVarsC() = - # retrieves the variables of char** env of C's main proc - if not envComputed: - environment = @[] - when useNSGetEnviron: - var gEnv = NSGetEnviron()[] - var i = 0 - while gEnv[i] != nil: - add environment, $gEnv[i] - inc(i) - envComputed = true + # Environment handling cannot be put into RTL, because the ``envPairs`` + # iterator depends on ``environment``. -proc findEnvVar(key: string): int = - getEnvVarsC() - var temp = key & '=' - for i in 0..high(environment): - when defined(windows): - if skipIgnoreCase(environment[i], temp) == len(temp): return i - else: - if startsWith(environment[i], temp): return i - return -1 + var + envComputed {.threadvar.}: bool + environment {.threadvar.}: seq[string] -proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = - ## Returns the value of the `environment variable`:idx: named `key`. - ## - ## If the variable does not exist, `""` is returned. To distinguish - ## whether a variable exists or it's value is just `""`, call - ## `existsEnv(key) proc <#existsEnv,string>`_. - ## - ## See also: - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - runnableExamples: - assert getEnv("unknownEnv") == "" - assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" + when defined(nimV2): + proc unpairedEnvAllocs*(): int = + result = environment.len + if result > 0: inc result - when nimvm: - discard "built into the compiler" - else: - var i = findEnvVar(key) - if i >= 0: - return TaintedString(substr(environment[i], find(environment[i], '=')+1)) - else: - var env = c_getenv(key) - if env == nil: return TaintedString(default) - result = TaintedString($env) - -proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = - ## Checks whether the environment variable named `key` exists. - ## Returns true if it exists, false otherwise. - ## - ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - runnableExamples: - assert not existsEnv("unknownEnv") - - when nimvm: - discard "built into the compiler" - else: - if c_getenv(key) != nil: return true - else: return findEnvVar(key) >= 0 - -proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = - ## Sets the value of the `environment variable`:idx: named `key` to `val`. - ## If an error occurs, `OSError` is raised. - ## - ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - - # Note: by storing the string in the environment sequence, - # we guarantee that we don't free the memory before the program - # ends (this is needed for POSIX compliance). It is also needed so that - # the process itself may access its modified environment variables! - when nimvm: - discard "built into the compiler" - else: - var indx = findEnvVar(key) - if indx >= 0: - environment[indx] = key & '=' & val - else: - add environment, (key & '=' & val) - indx = high(environment) - when defined(windows) and not defined(nimscript): - when useWinUnicode: - var k = newWideCString(key) - var v = newWideCString(val) - if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) + when defined(windows) and not defined(nimscript): + # because we support Windows GUI applications, things get really + # messy here... + when useWinUnicode: + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "".} else: - if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importc: "wcschr", header: "".} else: - if c_putenv(environment[indx]) != 0'i32: - raiseOSError(osLastError()) + proc strEnd(cstr: cstring, c = 0'i32): cstring {. + importc: "strchr", header: "".} + + proc getEnvVarsC() = + if not envComputed: + environment = @[] + when useWinUnicode: + var + env = getEnvironmentStringsW() + e = env + if e == nil: return # an error occurred + while true: + var eend = strEnd(e) + add(environment, $e) + e = cast[WideCString](cast[ByteAddress](eend)+2) + if eend[1].int == 0: break + discard freeEnvironmentStringsW(env) + else: + var + env = getEnvironmentStringsA() + e = env + if e == nil: return # an error occurred + while true: + var eend = strEnd(e) + add(environment, $e) + e = cast[cstring](cast[ByteAddress](eend)+1) + if eend[1] == '\0': break + discard freeEnvironmentStringsA(env) + envComputed = true -proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = - ## Deletes the `environment variable`:idx: named `key`. - ## If an error occurs, `OSError` is raised. - ## - ## See also:ven - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - when nimvm: - discard "built into the compiler" else: - var indx = findEnvVar(key) - if indx < 0: return # Do nothing if the env var is not already set - when defined(windows) and not defined(nimscript): - when useWinUnicode: - var k = newWideCString(key) - if setEnvironmentVariableW(k, nil) == 0'i32: raiseOSError(osLastError()) - else: - if setEnvironmentVariableA(key, nil) == 0'i32: raiseOSError(osLastError()) - else: - if c_unsetenv(key) != 0'i32: - raiseOSError(osLastError()) - environment.delete(indx) + const + useNSGetEnviron = (defined(macosx) and not defined(ios) and not defined(emscripten)) or defined(nimscript) -iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = - ## Iterate over all `environments variables`:idx:. - ## - ## In the first component of the tuple is the name of the current variable stored, - ## in the second its value. - ## - ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - getEnvVarsC() - for i in 0..high(environment): - var p = find(environment[i], '=') - yield (TaintedString(substr(environment[i], 0, p-1)), - TaintedString(substr(environment[i], p+1))) + when useNSGetEnviron: + # From the manual: + # Shared libraries and bundles don't have direct access to environ, + # which is only available to the loader ld(1) when a complete program + # is being linked. + # The environment routines can still be used, but if direct access to + # environ is needed, the _NSGetEnviron() routine, defined in + # , can be used to retrieve the address of environ + # at runtime. + proc NSGetEnviron(): ptr cstringArray {. + importc: "_NSGetEnviron", header: "".} + elif defined(haiku): + var gEnv {.importc: "environ", header: "".}: cstringArray + else: + var gEnv {.importc: "environ".}: cstringArray + + proc getEnvVarsC() = + # retrieves the variables of char** env of C's main proc + if not envComputed: + environment = @[] + when useNSGetEnviron: + var gEnv = NSGetEnviron()[] + var i = 0 + while gEnv[i] != nil: + add environment, $gEnv[i] + inc(i) + envComputed = true + + proc findEnvVar(key: string): int = + getEnvVarsC() + var temp = key & '=' + for i in 0..high(environment): + when defined(windows): + if skipIgnoreCase(environment[i], temp) == len(temp): return i + else: + if startsWith(environment[i], temp): return i + return -1 + + proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = + ## Returns the value of the `environment variable`:idx: named `key`. + ## + ## If the variable does not exist, `""` is returned. To distinguish + ## whether a variable exists or it's value is just `""`, call + ## `existsEnv(key) proc <#existsEnv,string>`_. + ## + ## See also: + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + runnableExamples: + assert getEnv("unknownEnv") == "" + assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" + + when nimvm: + discard "built into the compiler" + else: + var i = findEnvVar(key) + if i >= 0: + return TaintedString(substr(environment[i], find(environment[i], '=')+1)) + else: + var env = c_getenv(key) + if env == nil: return TaintedString(default) + result = TaintedString($env) + + proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + ## Checks whether the environment variable named `key` exists. + ## Returns true if it exists, false otherwise. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + runnableExamples: + assert not existsEnv("unknownEnv") + + when nimvm: + discard "built into the compiler" + else: + if c_getenv(key) != nil: return true + else: return findEnvVar(key) >= 0 + + proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + ## Sets the value of the `environment variable`:idx: named `key` to `val`. + ## If an error occurs, `OSError` is raised. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + + # Note: by storing the string in the environment sequence, + # we guarantee that we don't free the memory before the program + # ends (this is needed for POSIX compliance). It is also needed so that + # the process itself may access its modified environment variables! + when nimvm: + discard "built into the compiler" + else: + var indx = findEnvVar(key) + if indx >= 0: + environment[indx] = key & '=' & val + else: + add environment, (key & '=' & val) + indx = high(environment) + when defined(windows) and not defined(nimscript): + when useWinUnicode: + var k = newWideCString(key) + var v = newWideCString(val) + if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) + else: + if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) + else: + if c_putenv(environment[indx]) != 0'i32: + raiseOSError(osLastError()) + + proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + ## Deletes the `environment variable`:idx: named `key`. + ## If an error occurs, `OSError` is raised. + ## + ## See also:ven + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + when nimvm: + discard "built into the compiler" + else: + var indx = findEnvVar(key) + if indx < 0: return # Do nothing if the env var is not already set + when defined(windows) and not defined(nimscript): + when useWinUnicode: + var k = newWideCString(key) + if setEnvironmentVariableW(k, nil) == 0'i32: raiseOSError(osLastError()) + else: + if setEnvironmentVariableA(key, nil) == 0'i32: raiseOSError(osLastError()) + else: + if c_unsetenv(key) != 0'i32: + raiseOSError(osLastError()) + environment.delete(indx) + + iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = + ## Iterate over all `environments variables`:idx:. + ## + ## In the first component of the tuple is the name of the current variable stored, + ## in the second its value. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + getEnvVarsC() + for i in 0..high(environment): + var p = find(environment[i], '=') + yield (TaintedString(substr(environment[i], 0, p-1)), + TaintedString(substr(environment[i], p+1))) diff --git a/tests/js/tos.nim b/tests/js/tos.nim index 30c19c1ae..07eb3aaa3 100644 --- a/tests/js/tos.nim +++ b/tests/js/tos.nim @@ -19,3 +19,29 @@ block: if not isWindows: doAssert cwd.isAbsolute doAssert relativePath(getCurrentDir() / "foo", "bar") == "../foo" + +import std/sequtils + +template main = + putEnv("foo", "bar") + doAssert getEnv("foo") == "bar" + doAssert existsEnv("foo") + + putEnv("foo", "") + doAssert existsEnv("foo") + putEnv("foo", "bar2") + doAssert getEnv("foo") == "bar2" + + when nimvm: + discard + else: + # need support in vmops: envPairs, delEnv + let s = toSeq(envPairs()) + doAssert ("foo", "bar2") in s + doAssert ("foo", "bar") notin s + + delEnv("foo") + doAssert not existsEnv("foo") + +static: main() +main() From 4663319bf566fc39df4252100d0e5d5f55da336e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 12 Nov 2020 22:28:45 +0800 Subject: [PATCH 1452/4254] follow #8463 #14157 and document cstring literals modification is not allowed (#15878) * follow #8463 #14157 and document cstring literals * Update doc/manual.rst Co-authored-by: Juan Carlos Co-authored-by: Andreas Rumpf --- doc/manual.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index fa28582a7..bfcce24cf 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1280,6 +1280,20 @@ string from a cstring: var cstr: cstring = str var newstr: string = $cstr +``cstring`` literals shouldn't be modified. + +.. code-block:: nim + var x = cstring"literals" + x[1] = 'A' # This is wrong!!! + +If the ``cstring`` originates from a regular memory (not read-only memory), +it can be modified: + +.. code-block:: nim + var x = "123456" + var s: cstring = x + s[0] = 'u' # This is ok + Structured types ---------------- A variable of a structured type can hold multiple values at the same From 077eba7b388259ecca7e9e7990f48efe9e3641c5 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 12 Nov 2020 23:24:45 +0800 Subject: [PATCH 1453/4254] make workaround for #15934 and #15620 --- lib/core/typeinfo.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 5c4e1b601..2f213956b 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -327,7 +327,8 @@ proc setPointer*(x: Any, y: pointer) = ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. assert x.rawType.kind in pointerLike - genericAssign(x.value, y, x.rawType) + if y != nil: + genericAssign(x.value, y, x.rawType) proc fieldsAux(p: pointer, n: ptr TNimNode, ret: var seq[tuple[name: cstring, any: Any]]) = From 8ec3c141ae28616382a82235b2f4049eaa0ab0d7 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 12 Nov 2020 23:58:42 +0800 Subject: [PATCH 1454/4254] add testcase --- tests/stdlib/tmarshal.nim | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index fc5703a03..315036631 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -4,6 +4,9 @@ true true alpha 100 omega 200 +Some(null) +None[JsonNode] +(numeric: "") ''' joinable: false """ @@ -123,3 +126,25 @@ var foo = Foo(a2: "", a4: @[], a6: @[1]) foo.a6.setLen 0 doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}""" testit(foo) + +import options, json + +# bug #15934 +block: + let + a1 = some(newJNull()) + a2 = none(JsonNode) + echo ($$a1).to[:Option[JsonNode]] + echo ($$a2).to[:Option[JsonNode]] + + +# bug #15620 +block: + let str = """{"numeric": null}""" + + type + LegacyEntry = object + numeric: string + + let test = to[LegacyEntry](str) + echo test From 1413818aa14fd694d362326f428b470fa22e1a0a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 12 Nov 2020 09:36:07 -0800 Subject: [PATCH 1455/4254] Update changelog.md --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index ac1ec1163..11930cf92 100644 --- a/changelog.md +++ b/changelog.md @@ -31,8 +31,8 @@ - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). -- Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). - nodejs now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv` + - `doAssertRaises` now correctly handles foreign exceptions. ## Language changes From d0c4c738b955f2641baa55ece6b5b90d4e632d8c Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 12 Nov 2020 22:25:23 +0100 Subject: [PATCH 1456/4254] add a tester for rst2html (#15936) --- koch.nim | 1 + nimdoc/rst2html/expected/rst_examples.html | 319 +++++++++++++ nimdoc/rst2html/source/rst_examples.rst | 510 +++++++++++++++++++++ nimdoc/rsttester.nim | 34 ++ 4 files changed, 864 insertions(+) create mode 100644 nimdoc/rst2html/expected/rst_examples.html create mode 100644 nimdoc/rst2html/source/rst_examples.rst create mode 100644 nimdoc/rsttester.nim diff --git a/koch.nim b/koch.nim index 47bde9d18..628c81098 100644 --- a/koch.nim +++ b/koch.nim @@ -554,6 +554,7 @@ proc runCI(cmd: string) = execFold("test with -d:nimHasLibFFI", "$1 $2 -r testament/testament --nim:$1 r tests/misc/trunner.nim -d:nimTrunnerFfi" % [nimFFI, backend]) execFold("Run nimdoc tests", "nim c -r nimdoc/tester") + execFold("Run rst2html tests", "nim c -r nimdoc/rsttester") execFold("Run nimpretty tests", "nim c -r nimpretty/tester.nim") when defined(posix): execFold("Run nimsuggest tests", "nim c -r nimsuggest/tester") diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html new file mode 100644 index 000000000..8a08e8df5 --- /dev/null +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + +Not a Nim Manual + + + + + + + + +
      +
      +

      Not a Nim Manual

      +
      + + +
      +
      + +

      + +
      Authors: Andreas Rumpf, Zahary Karadjov
      Version: |nimversion|

      "Complexity" seems to be a lot like "energy": you can transfer it from the end-user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran

      + +

      About this document

      Note: This document is a draft! Several of Nim's features may need more precise wording. This manual is constantly evolving into a proper specification.

      +

      Note: The experimental features of Nim are covered here.

      +

      Note: Assignments, moves, and destruction are specified in the destructors document.

      +

      The language constructs are explained using an extended BNF, in which (a)* means 0 or more a's, a+ means 1 or more a's, and (a)? means an optional a. Parentheses may be used to group elements.

      +

      & is the lookahead operator; &a means that an a is expected but not consumed. It will be consumed in the following rule.

      +

      Non-terminals start with a lowercase letter, abstract terminal symbols are in UPPERCASE. Verbatim terminal symbols (including keywords) are quoted with '. An example:

      +ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
      +

      +

      In a typical Nim program, most of the code is compiled into the executable. However, some of the code may be executed at compile-time. This can include constant expressions, macro definitions, and Nim procedures used by macro definitions. Most of the Nim language is supported at compile-time, but there are some restrictions -- see Restrictions on Compile-Time Execution for details. We use the term runtime to cover both compile-time execution and code execution in the executable.

      +
      var a: array[0..1, char]
      +let i = 5
      +try:
      +  a[i] = 'N'
      +except IndexDefect:
      +  echo "invalid index"
      +

      Encoding

      All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other encodings are not supported. Any of the standard platform line termination sequences can be used - the Unix form using ASCII LF (linefeed), the Windows form using the ASCII sequence CR LF (return followed by linefeed), or the old Macintosh form using the ASCII CR (return) character. All of these forms can be used equally, regardless of the platform.

      + +

      Indentation

      Nim's standard grammar describes an indentation sensitive language. This means that all the control structures are recognized by indentation. Indentation consists only of spaces; tabulators are not allowed.

      +

      With this notation we can now easily define the core of the grammar: A block of statements (simplified example):

      +ifStmt = 'if' expr ':' stmt
      +         (IND{=} 'elif' expr ':' stmt)*
      +         (IND{=} 'else' ':' stmt)?
      +
      +simpleStmt = ifStmt / ...
      +
      +stmt = IND{>} stmt ^+ IND{=} DED  # list of statements
      +     / simpleStmt                 # or a simple statement
      +

      +

      String literals can be delimited by matching double quotes, and can contain the following escape sequences:

      + + + + + + + + + + + + + + + + + +
      Escape sequenceMeaning
      \pplatform specific newline: CRLF on Windows, LF on Unix
      \r, \ccarriage return
      \n, \lline feed (often called newline)
      \fform feed
      \ttabulator
      \vvertical tabulator
      \\backslash
      \"quotation mark
      \'apostrophe
      \ '0'..'9'+character with decimal value d; all decimal digits directly following are used for the character
      \aalert
      \bbackspace
      \eescape [ESC]
      \x HHcharacter with hex value HH; exactly two hex digits are allowed
      \u HHHHunicode codepoint with hex value HHHH; exactly four hex digits are allowed
      \u {H+}unicode codepoint; all hex digits enclosed in {} are used for the codepoint
      """"long string within quotes""""

      Produces:

      +"long string within quotes"
      +

      + +

      Operators

      Nim allows user defined operators. An operator is any combination of the following characters:

      +=     +     -     *     /     <     >
      +@     $     ~     &     %     |
      +!     ?     ^     .     :     \
      +

      +

      (The grammar uses the terminal OPR to refer to operator symbols as defined here.)

      +

      The following strings denote other tokens:

      +`   (    )     {    }     [    ]    ,  ;   [.    .]  {.   .}  (.  .)  [:
      +

      +

      Otherwise, precedence is determined by the first character.

      + + + + + + + + + + + + +
      Precedence levelOperatorsFirst characterTerminal symbol
      10 (highest)$ ^OP10
      9* / div mod shl shr %* % \ /OP9
      8+ -+ - ~ |OP8
      7&&OP7
      6...OP6
      5== <= < >= > != in notin is isnot not of as from= < > !OP5
      4andOP4
      3or xorOP3
      2@ : ?OP2
      1assignment operator (like +=, *=)OP1
      0 (lowest)arrow like operator (like ->, =>)OP0
      +

      Constants and Constant Expressions

      A constant is a symbol that is bound to the value of a constant expression. Constant expressions are restricted to depend only on the following categories of values and operations, because these are either built into the language or declared and evaluated before semantic analysis of the constant expression:

      +
      • literals
      • +
      • built-in operators
      • +
      • previously declared constants and compile-time variables
      • +
      • previously declared macros and templates
      • +
      • previously declared procedures that have no side effects beyond possibly modifying compile-time variables
      • +
      +

      These integer types are pre-defined:

      +
      int
      +
      the generic signed integer type; its size is platform-dependent and has the same size as a pointer. This type should be used in general. An integer literal that has no type suffix is of this type if it is in the range low(int32)..high(int32) otherwise the literal's type is int64.
      +
      intXX
      +
      additional signed integer types of XX bits use this naming scheme (example: int16 is a 16-bit wide integer). The current implementation supports int8, int16, int32, int64. Literals of these types have the suffix 'iXX.
      +
      uint
      +
      the generic unsigned integer type; its size is platform-dependent and has the same size as a pointer. An integer literal with the type suffix 'u is of this type.
      +
      +

      Let T's be p's return type. NRVO applies for T if sizeof(T) >= N (where N is implementation dependent), in other words, it applies for "big" structures.

      +

      Apart from built-in operations like array indexing, memory allocation, etc. the raise statement is the only way to raise an exception.

      +

      typedesc used as a parameter type also introduces an implicit generic. typedesc has its own set of rules:

      +

      The !=, >, >=, in, notin, isnot operators are in fact templates:

      +

      a > b is transformed into b < a.
      a in b is transformed into contains(b, a).
      notin and isnot have the obvious meanings.

      A template where every parameter is untyped is called an immediate template. For historical reasons templates can be explicitly annotated with an immediate pragma and then these templates do not take part in overloading resolution and the parameters' types are ignored by the compiler. Explicit immediate templates are now deprecated.

      + +

      Symbol lookup in generics

      +

      Open and Closed symbols

      The symbol binding rules in generics are slightly subtle: There are "open" and "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation context, an "open" symbol can. Per default overloaded symbols are open and every other symbol is closed.

      +

      In templates identifiers can be constructed with the backticks notation:

      +
      template typedef(name: untyped, typ: typedesc) =
      +  type
      +    `T name`* {.inject.} = typ
      +    `P name`* {.inject.} = ref `T name`
      +
      +typedef(myint, int)
      +var x: PMyInt

      In the example name is instantiated with myint, so `T name` becomes Tmyint.

      +

      Only top-level symbols that are marked with an asterisk (*) are exported.

      +

      The algorithm for compiling modules is:

      +
      • compile the whole module as usual, following import statements recursively
      • +
      • if there is a cycle only import the already parsed symbols (that are exported); if an unknown identifier occurs then abort
      • +
      + +

      Collective imports from a directory

      The syntax import dir / [moduleA, moduleB] can be used to import multiple modules from the same directory.

      + +

      Pragmas

      Pragmas are Nim's method to give the compiler additional information / commands without introducing a massive number of new keywords. Pragmas are processed on the fly during semantic checking. Pragmas are enclosed in the special {. and .} curly brackets. Pragmas are also often used as a first implementation to play with a language feature before a nicer syntax to access the feature becomes available.

      + +

      deprecated pragma

      The deprecated pragma is used to mark a symbol as deprecated:

      +

      Note: c2nim can parse a large subset of C++ and knows about the importcpp pragma pattern language. It is not necessary to know all the details described here.

      +

      Pure libraries do not depend on any external *.dll or lib*.so binary while impure libraries do. A wrapper is an impure library that is a very low-level interface to a C library.

      + +

      Pure libraries

      +

      Automatic imports

      • system Basic procs and operators that every program needs. It also provides IO facilities for reading and writing text and binary files. It is imported implicitly by the compiler. Do not import it directly. It relies on compiler magic to work.
      • +
      • threads Basic Nim thread support. Note: This is part of the system module. Do not import it explicitly. Enabled with --threads:on.
      • +
      + +

      Code reordering

      The code reordering feature can implicitly rearrange procedure, template, and macro definitions along with variable declarations and initializations at the top level scope so that, to a large extent, a programmer should not have to worry about ordering definitions correctly or be forced to use forward declarations to preface definitions inside a module.

      +

      Example:

      +
      {.experimental: "codeReordering".}
      +
      +proc foo(x: int) =
      +  bar(x)
      +
      +proc bar(x: int) =
      +  echo(x)
      +
      +foo(10)

      It is important to note that reordering only works for symbols at top level scope. Therefore, the following will fail to compile:

      + +

      Parameter constraints

      The parameter constraint expression can use the operators | (or), & (and) and ~ (not) and the following predicates:

      + +

      The ~ operator

      The ~ operator is the not operator in patterns:

      + +

      The ** operator

      The ** is much like the * operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation:

      +

      Nim significantly improves on the safety of these features via additional pragmas:

      +
      1. A guard annotation is introduced to prevent data races.
      2. +
      3. Every access of a guarded memory location needs to happen in an appropriate locks statement.
      4. +
      5. Locks and routines can be annotated with lock levels to allow potential deadlocks to be detected during semantic analysis.
      6. +
      +
      1. Two output parameters should never be aliased.
      2. +
      3. An input and an output parameter should not be aliased.
      4. +
      5. An output parameter should never be aliased with a global or thread local variable referenced by the called proc.
      6. +
      7. An input parameter should not be aliased with a global or thread local variable updated by the called proc.
      8. +
      +

      One problem with rules 3 and 4 is that they affect specific global or thread local variables, but Nim's effect tracking only tracks "uses no global variable" via .noSideEffect. The rules 3 and 4 can also be approximated by a different rule:

      +
      1. A global or thread local variable (or a location derived from such a location) can only passed to a parameter of a .noSideEffect proc.
      2. +
      +

      These two procs are the two modus operandi of the real-time garbage collector:

      +

      (1) GC_SetMaxPause Mode

      +

      You can call GC_SetMaxPause at program startup and then each triggered garbage collector run tries to not take longer than maxPause time. However, it is possible (and common) that the work is nevertheless not evenly distributed as each call to new can trigger the garbage collector and thus take maxPause time.

      +

      (2) GC_step Mode

      +

      This allows the garbage collector to perform some work for up to us time. This is useful to call in the main loop to ensure the garbage collector can do its work. To bind all garbage collector activity to a GC_step call, deactivate the garbage collector with GC_disable at program startup. If strongAdvice is set to true, then the garbage collector will be forced to perform the collection cycle. Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. You may also specify the current stack size via stackSize parameter. It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

      +

      It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

      +

      +

      These procs provide a "best effort" real-time guarantee; in particular the cycle collector is not aware of deadlines. Deactivate it to get more predictable real-time behaviour. Tests show that a 1ms max pause time will be met in almost all cases on modern CPUs (with the cycle collector disabled).

      + +

      Time measurement with garbage collectors

      The garbage collectors' way of measuring time uses (see lib/system/timers.nim for the implementation):

      +
      1. QueryPerformanceCounter and QueryPerformanceFrequency on Windows.
      2. +
      3. mach_absolute_time on Mac OS X.
      4. +
      5. gettimeofday on Posix systems.
      6. +
      +

      As such it supports a resolution of nanoseconds internally; however, the API uses microseconds for convenience.

      + +

      Introduction

      +"Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir." +

      This document is a tutorial for the programming language Nim. This tutorial assumes that you are familiar with basic programming concepts like variables, types, or statements but is kept very basic. The manual contains many more examples of the advanced language features. All code examples in this tutorial, as well as the ones found in the rest of Nim's documentation, follow the Nim style guide.

      +

      However, this does not work. The problem is that the procedure should not only return, but return and continue after an iteration has finished. This return and continue is called a yield statement. Now the only thing left to do is to replace the proc keyword by iterator and here it is - our first iterator:

      + + + + + +
      A1 headerA2 | not fooled
      C1C2 bold
      D1 code |D2
      E1 | text
      F2 without pipe

      not in table

      +

      + +
      +
      + +
      + +
      +
      +
      + + + diff --git a/nimdoc/rst2html/source/rst_examples.rst b/nimdoc/rst2html/source/rst_examples.rst new file mode 100644 index 000000000..c8d15aef8 --- /dev/null +++ b/nimdoc/rst2html/source/rst_examples.rst @@ -0,0 +1,510 @@ +========== +Not a Nim Manual +========== + +:Authors: Andreas Rumpf, Zahary Karadjov +:Version: |nimversion| + +.. contents:: + + + "Complexity" seems to be a lot like "energy": you can transfer it from the + end-user to one/some of the other players, but the total amount seems to remain + pretty much constant for a given task. -- Ran + + +About this document +=================== + +**Note**: This document is a draft! Several of Nim's features may need more +precise wording. This manual is constantly evolving into a proper specification. + +**Note**: The experimental features of Nim are +covered `here `_. + +**Note**: Assignments, moves, and destruction are specified in +the `destructors `_ document. + +The language constructs are explained using an extended BNF, in which ``(a)*`` +means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and ``(a)?`` means an +optional *a*. Parentheses may be used to group elements. + +``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but +not consumed. It will be consumed in the following rule. + +Non-terminals start with a lowercase letter, abstract terminal symbols are in +UPPERCASE. Verbatim terminal symbols (including keywords) are quoted +with ``'``. An example:: + + ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)? + +In a typical Nim program, most of the code is compiled into the executable. +However, some of the code may be executed at +`compile-time`:idx:. This can include constant expressions, macro definitions, +and Nim procedures used by macro definitions. Most of the Nim language is +supported at compile-time, but there are some restrictions -- see `Restrictions +on Compile-Time Execution <#restrictions-on-compileminustime-execution>`_ for +details. We use the term `runtime`:idx: to cover both compile-time execution +and code execution in the executable. + +.. code-block:: nim + var a: array[0..1, char] + let i = 5 + try: + a[i] = 'N' + except IndexDefect: + echo "invalid index" + +Encoding +-------- + +All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other +encodings are not supported. Any of the standard platform line termination +sequences can be used - the Unix form using ASCII LF (linefeed), the Windows +form using the ASCII sequence CR LF (return followed by linefeed), or the old +Macintosh form using the ASCII CR (return) character. All of these forms can be +used equally, regardless of the platform. + + +Indentation +----------- + +Nim's standard grammar describes an `indentation sensitive`:idx: language. +This means that all the control structures are recognized by indentation. +Indentation consists only of spaces; tabulators are not allowed. + +With this notation we can now easily define the core of the grammar: A block of +statements (simplified example):: + + ifStmt = 'if' expr ':' stmt + (IND{=} 'elif' expr ':' stmt)* + (IND{=} 'else' ':' stmt)? + + simpleStmt = ifStmt / ... + + stmt = IND{>} stmt ^+ IND{=} DED # list of statements + / simpleStmt # or a simple statement + + +String literals can be delimited by matching double quotes, and can +contain the following `escape sequences`:idx:\ : + +================== =================================================== + Escape sequence Meaning +================== =================================================== + ``\p`` platform specific newline: CRLF on Windows, + LF on Unix + ``\r``, ``\c`` `carriage return`:idx: + ``\n``, ``\l`` `line feed`:idx: (often called `newline`:idx:) + ``\f`` `form feed`:idx: + ``\t`` `tabulator`:idx: + ``\v`` `vertical tabulator`:idx: + ``\\`` `backslash`:idx: + ``\"`` `quotation mark`:idx: + ``\'`` `apostrophe`:idx: + ``\`` '0'..'9'+ `character with decimal value d`:idx:; + all decimal digits directly + following are used for the character + ``\a`` `alert`:idx: + ``\b`` `backspace`:idx: + ``\e`` `escape`:idx: `[ESC]`:idx: + ``\x`` HH `character with hex value HH`:idx:; + exactly two hex digits are allowed + ``\u`` HHHH `unicode codepoint with hex value HHHH`:idx:; + exactly four hex digits are allowed + ``\u`` {H+} `unicode codepoint`:idx:; + all hex digits enclosed in ``{}`` are used for + the codepoint +================== =================================================== + +.. code-block:: nim + """"long string within quotes"""" + +Produces:: + + "long string within quotes" + +Operators +--------- + +Nim allows user defined operators. An operator is any combination of the +following characters:: + + = + - * / < > + @ $ ~ & % | + ! ? ^ . : \ + +(The grammar uses the terminal OPR to refer to operator symbols as +defined here.) + +The following strings denote other tokens:: + + ` ( ) { } [ ] , ; [. .] {. .} (. .) [: + + +Otherwise, precedence is determined by the first character. + +================ ======================================================= ================== =============== +Precedence level Operators First character Terminal symbol +================ ======================================================= ================== =============== + 10 (highest) ``$ ^`` OP10 + 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 + 8 ``+ -`` ``+ - ~ |`` OP8 + 7 ``&`` ``&`` OP7 + 6 ``..`` ``.`` OP6 + 5 ``== <= < >= > != in notin is isnot not of as from`` ``= < > !`` OP5 + 4 ``and`` OP4 + 3 ``or xor`` OP3 + 2 ``@ : ?`` OP2 + 1 *assignment operator* (like ``+=``, ``*=``) OP1 + 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 +================ ======================================================= ================== =============== + + +Constants and Constant Expressions +================================== + +A `constant`:idx: is a symbol that is bound to the value of a constant +expression. Constant expressions are restricted to depend only on the following +categories of values and operations, because these are either built into the +language or declared and evaluated before semantic analysis of the constant +expression: + +* literals +* built-in operators +* previously declared constants and compile-time variables +* previously declared macros and templates +* previously declared procedures that have no side effects beyond + possibly modifying compile-time variables + +These integer types are pre-defined: + +``int`` + the generic signed integer type; its size is platform-dependent and has the + same size as a pointer. This type should be used in general. An integer + literal that has no type suffix is of this type if it is in the range + ``low(int32)..high(int32)`` otherwise the literal's type is ``int64``. + +intXX + additional signed integer types of XX bits use this naming scheme + (example: int16 is a 16-bit wide integer). + The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``. + Literals of these types have the suffix 'iXX. + +``uint`` + the generic `unsigned integer`:idx: type; its size is platform-dependent and has the same size as a pointer. An integer literal with the type suffix ``'u`` is of this type. + +Let ``T``'s be ``p``'s return type. NRVO applies for ``T`` +if ``sizeof(T) >= N`` (where ``N`` is implementation dependent), +in other words, it applies for "big" structures. + +Apart from built-in operations like array indexing, memory allocation, etc. +the ``raise`` statement is the only way to raise an exception. + +.. XXX document this better! + +`typedesc` used as a parameter type also introduces an implicit +generic. `typedesc` has its own set of rules: + +The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact +templates: + +| ``a > b`` is transformed into ``b < a``. +| ``a in b`` is transformed into ``contains(b, a)``. +| ``notin`` and ``isnot`` have the obvious meanings. + +A template where every parameter is ``untyped`` is called an `immediate`:idx: +template. For historical reasons templates can be explicitly annotated with +an ``immediate`` pragma and then these templates do not take part in +overloading resolution and the parameters' types are *ignored* by the +compiler. Explicit immediate templates are now deprecated. + + + +Symbol lookup in generics +------------------------- + +Open and Closed symbols +~~~~~~~~~~~~~~~~~~~~~~~ + +The symbol binding rules in generics are slightly subtle: There are "open" and +"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation +context, an "open" symbol can. Per default overloaded symbols are open +and every other symbol is closed. + +In templates identifiers can be constructed with the backticks notation: + +.. code-block:: nim + :test: "nim c $1" + + template typedef(name: untyped, typ: typedesc) = + type + `T name`* {.inject.} = typ + `P name`* {.inject.} = ref `T name` + + typedef(myint, int) + var x: PMyInt + +In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes +``Tmyint``. + +Only top-level symbols that are marked with an asterisk (``*``) are +exported. + +The algorithm for compiling modules is: + +- compile the whole module as usual, following import statements recursively + +- if there is a cycle only import the already parsed symbols (that are + exported); if an unknown identifier occurs then abort + + +Collective imports from a directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The syntax ``import dir / [moduleA, moduleB]`` can be used to import multiple modules +from the same directory. + + +Pragmas +======= + +Pragmas are Nim's method to give the compiler additional information / +commands without introducing a massive number of new keywords. Pragmas are +processed on the fly during semantic checking. Pragmas are enclosed in the +special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a +first implementation to play with a language feature before a nicer syntax +to access the feature becomes available. + + +deprecated pragma +----------------- + +The deprecated pragma is used to mark a symbol as deprecated: + +**Note**: `c2nim `_ can parse a large subset of C++ and knows +about the ``importcpp`` pragma pattern language. It is not necessary +to know all the details described here. + + + +Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary +while impure libraries do. A wrapper is an impure library that is a very +low-level interface to a C library. + + +Pure libraries +============== + +Automatic imports +----------------- + +* `system `_ + Basic procs and operators that every program needs. It also provides IO + facilities for reading and writing text and binary files. It is imported + implicitly by the compiler. Do not import it directly. It relies on compiler + magic to work. + +* `threads `_ + Basic Nim thread support. **Note**: This is part of the system module. Do not + import it explicitly. Enabled with ``--threads:on``. + +Code reordering +=============== + +The code reordering feature can implicitly rearrange procedure, template, and +macro definitions along with variable declarations and initializations at the top +level scope so that, to a large extent, a programmer should not have to worry +about ordering definitions correctly or be forced to use forward declarations to +preface definitions inside a module. + +.. + NOTE: The following was documentation for the code reordering precursor, + which was {.noForward.}. + + In this mode, procedure definitions may appear out of order and the compiler + will postpone their semantic analysis and compilation until it actually needs + to generate code using the definitions. In this regard, this mode is similar + to the modus operandi of dynamic scripting languages, where the function + calls are not resolved until the code is executed. Here is the detailed + algorithm taken by the compiler: + + 1. When a callable symbol is first encountered, the compiler will only note + the symbol callable name and it will add it to the appropriate overload set + in the current scope. At this step, it won't try to resolve any of the type + expressions used in the signature of the symbol (so they can refer to other + not yet defined symbols). + + 2. When a top level call is encountered (usually at the very end of the + module), the compiler will try to determine the actual types of all of the + symbols in the matching overload set. This is a potentially recursive process + as the signatures of the symbols may include other call expressions, whose + types will be resolved at this point too. + + 3. Finally, after the best overload is picked, the compiler will start + compiling the body of the respective symbol. This in turn will lead the + compiler to discover more call expressions that need to be resolved and steps + 2 and 3 will be repeated as necessary. + + Please note that if a callable symbol is never used in this scenario, its + body will never be compiled. This is the default behavior leading to best + compilation times, but if exhaustive compilation of all definitions is + required, using ``nim check`` provides this option as well. + +Example: + +.. code-block:: nim + + {.experimental: "codeReordering".} + + proc foo(x: int) = + bar(x) + + proc bar(x: int) = + echo(x) + + foo(10) + + +.. + TODO: Let's table this for now. This is an *experimental feature* and so the + specific manner in which ``declared`` operates with it can be decided in + eventuality, because right now it works a bit weirdly. + + The values of expressions involving ``declared`` are decided *before* the + code reordering process, and not after. As an example, the output of this + code is the same as it would be with code reordering disabled. + + .. code-block:: nim + {.experimental: "codeReordering".} + + proc x() = + echo(declared(foo)) + + var foo = 4 + + x() # "false" + +It is important to note that reordering *only* works for symbols at top level +scope. Therefore, the following will *fail to compile:* + + +Parameter constraints +--------------------- + +The `parameter constraint`:idx: expression can use the operators ``|`` (or), +``&`` (and) and ``~`` (not) and the following predicates: + + +The ``~`` operator +~~~~~~~~~~~~~~~~~~ + +The ``~`` operator is the **not** operator in patterns: + + +The ``**`` operator +~~~~~~~~~~~~~~~~~~~ + +The ``**`` is much like the ``*`` operator, except that it gathers not only +all the arguments, but also the matched operators in reverse polish notation: + +Nim significantly improves on the safety of these features via additional +pragmas: + +1) A `guard`:idx: annotation is introduced to prevent data races. +2) Every access of a guarded memory location needs to happen in an + appropriate `locks`:idx: statement. +3) Locks and routines can be annotated with `lock levels`:idx: to allow + potential deadlocks to be detected during semantic analysis. + +1. Two output parameters should never be aliased. +2. An input and an output parameter should not be aliased. +3. An output parameter should never be aliased with a global or thread local + variable referenced by the called proc. +4. An input parameter should not be aliased with a global or thread local + variable updated by the called proc. + +One problem with rules 3 and 4 is that they affect specific global or thread +local variables, but Nim's effect tracking only tracks "uses no global variable" +via ``.noSideEffect``. The rules 3 and 4 can also be approximated by a different rule: + +5. A global or thread local variable (or a location derived from such a location) + can only passed to a parameter of a ``.noSideEffect`` proc. + +These two procs are the two modus operandi of the real-time garbage collector: + +(1) GC_SetMaxPause Mode + + You can call ``GC_SetMaxPause`` at program startup and then each triggered + garbage collector run tries to not take longer than ``maxPause`` time. However, it is + possible (and common) that the work is nevertheless not evenly distributed + as each call to ``new`` can trigger the garbage collector and thus take ``maxPause`` + time. + +(2) GC_step Mode + + This allows the garbage collector to perform some work for up to ``us`` time. + This is useful to call in the main loop to ensure the garbage collector can do its work. + To bind all garbage collector activity to a ``GC_step`` call, + deactivate the garbage collector with ``GC_disable`` at program startup. + If ``strongAdvice`` is set to ``true``, + then the garbage collector will be forced to perform the collection cycle. + Otherwise, the garbage collector may decide not to do anything, + if there is not much garbage to collect. + You may also specify the current stack size via ``stackSize`` parameter. + It can improve performance when you know that there are no unique Nim references + below a certain point on the stack. Make sure the size you specify is greater + than the potential worst-case size. + + It can improve performance when you know that there are no unique Nim + references below a certain point on the stack. Make sure the size you specify + is greater than the potential worst-case size. + +These procs provide a "best effort" real-time guarantee; in particular the +cycle collector is not aware of deadlines. Deactivate it to get more +predictable real-time behaviour. Tests show that a 1ms max pause +time will be met in almost all cases on modern CPUs (with the cycle collector +disabled). + +Time measurement with garbage collectors +---------------------------------------- + +The garbage collectors' way of measuring time uses +(see ``lib/system/timers.nim`` for the implementation): + +1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. +2) ``mach_absolute_time`` on Mac OS X. +3) ``gettimeofday`` on Posix systems. + +As such it supports a resolution of nanoseconds internally; however, the API +uses microseconds for convenience. + +Introduction +============ + +.. raw:: html +

      + "Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir." +

      + + +This document is a tutorial for the programming language *Nim*. +This tutorial assumes that you are familiar with basic programming concepts +like variables, types, or statements but is kept very basic. The `manual +`_ contains many more examples of the advanced language features. +All code examples in this tutorial, as well as the ones found in the rest of +Nim's documentation, follow the `Nim style guide `_. + +However, this does not work. The problem is that the procedure should not +only ``return``, but return and **continue** after an iteration has +finished. This *return and continue* is called a `yield` statement. Now +the only thing left to do is to replace the ``proc`` keyword by ``iterator`` +and here it is - our first iterator: + +| A1 header | A2 \| not fooled +| :--- | ----: | +| C1 | C2 **bold** | ignored | +| D1 `code \|` | D2 | also ignored +| E1 \| text | +| | F2 without pipe +not in table diff --git a/nimdoc/rsttester.nim b/nimdoc/rsttester.nim new file mode 100644 index 000000000..6d41ffb86 --- /dev/null +++ b/nimdoc/rsttester.nim @@ -0,0 +1,34 @@ +import os, strutils + +const + baseDir = "nimdoc/rst2html" + +var failures = 0 + +proc exec(cmd: string) = + if execShellCmd(cmd) != 0: + quit("FAILURE: " & cmd) + +proc testRst2Html(fixup = false) = + putEnv("SOURCE_DATE_EPOCH", "100000") + const nimExe = getCurrentCompilerExe() # so that `bin/nim_temp r nimdoc/tester.nim` works + + for expectedHtml in walkDir(baseDir / "expected"): + let expectedHtml = expectedHtml.path + let sourceFile = expectedHtml.replace('\\', '/').replace("/expected/", "/source/").replace(".html", ".rst") + exec("$1 rst2html $2" % [nimExe, sourceFile]) + let producedHtml = expectedHtml.replace('\\', '/').replace("/expected/", "/source/htmldocs/") + if readFile(expectedHtml) != readFile(producedHtml): + discard execShellCmd("diff -uNdr " & expectedHtml & " " & producedHtml) + inc failures + if fixup: + copyFile(producedHtml, expectedHtml) + else: + echo "SUCCESS: files identical: ", producedHtml + if failures == 0: + removeDir(baseDir / "source/htmldocs") + +testRst2Html(defined(fixup)) + +# Check for failures +if failures > 0: quit($failures & " failures occurred.") From 492e9afa4c32be278b61498be20ae0afc3ef3188 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 13 Nov 2020 15:11:00 +0800 Subject: [PATCH 1457/4254] fix #15941 (#15948) * fix #15941 * add testcase * update --- lib/pure/collections/sharedlist.nim | 11 +++++++---- tests/stdlib/tsharedlist.nim | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/stdlib/tsharedlist.nim diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index 790529b79..c72477675 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -65,11 +65,14 @@ iterator items*[A](x: var SharedList[A]): A = proc add*[A](x: var SharedList[A]; y: A) = withLock(x): var node: SharedListNode[A] - if x.tail == nil or x.tail.dataLen == ElemsPerNode: - node = cast[type node](allocShared0(sizeof(node[]))) - node.next = x.tail + if x.tail == nil: + node = cast[typeof node](allocShared0(sizeof(node[]))) + x.tail = node + x.head = node + elif x.tail.dataLen == ElemsPerNode: + node = cast[typeof node](allocShared0(sizeof(node[]))) + x.tail.next = node x.tail = node - if x.head == nil: x.head = node else: node = x.tail node.d[node.dataLen] = y diff --git a/tests/stdlib/tsharedlist.nim b/tests/stdlib/tsharedlist.nim new file mode 100644 index 000000000..a795be0f3 --- /dev/null +++ b/tests/stdlib/tsharedlist.nim @@ -0,0 +1,17 @@ +import sharedlist + +var + list: SharedList[int] + count: int + +init(list) + +for i in 1 .. 250: + list.add i + +for i in list: + inc count + +doAssert count == 250 + +deinitSharedList(list) From 83432aecfc1c4820837911b53b450e23936a4da7 Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 12 Nov 2020 23:12:03 -0800 Subject: [PATCH 1458/4254] Add documentElement to Document. (#15943) --- lib/js/dom.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index d2e5776f0..b73a85291 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -204,6 +204,7 @@ type Document* = ref DocumentObj DocumentObj {.importc.} = object of NodeObj activeElement*: Element + documentElement*: Element alinkColor*: cstring bgColor*: cstring body*: Element From 1fdfa234d76d59fd8d5cafd9d53cfdf8bfbf5c0a Mon Sep 17 00:00:00 2001 From: wilypomegranate Date: Fri, 13 Nov 2020 02:15:46 -0500 Subject: [PATCH 1459/4254] Don't use os for Standalone (#15944) --- lib/pure/strtabs.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index d9f6bbc54..7b726e134 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -53,7 +53,7 @@ import std/private/since import hashes, strutils -when defined(js) or defined(nimscript): +when defined(js) or defined(nimscript) or defined(Standalone): {.pragma: rtlFunc.} else: {.pragma: rtlFunc, rtl.} @@ -301,7 +301,7 @@ proc raiseFormatException(s: string) = proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = if hasKey(t, key): return t.getOrDefault(key) # hm difficult: assume safety in taint mode here. XXX This is dangerous! - when defined(js) or defined(nimscript): + when defined(js) or defined(nimscript) or defined(Standalone): result = "" else: if useEnvironment in flags: result = getEnv(key).string From 778914c3ca9d6c57b0158d8bf69f92b01b0bd2e1 Mon Sep 17 00:00:00 2001 From: lenoil98 Date: Fri, 13 Nov 2020 02:16:20 -0500 Subject: [PATCH 1460/4254] Update buildsh.nimf (#15945) fix powerpc64le detection --- tools/niminst/buildsh.nimf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 5ec5d5c2c..e13221781 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -159,9 +159,10 @@ case $ucpu in COMP_FLAGS="$COMP_FLAGS -m64" LINK_FLAGS="$LINK_FLAGS -m64" mycpu=`uname -p` - if [ "$(mycpu)" = "powerpc64le"] ; then - mycpu="powerpc64el" - fi + case $mycpu in + powerpc64le) + mycpu="powerpc64el" + esac else mycpu="powerpc" fi From 0f53b129b78ae480f62a68877778600ba100e96c Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 13 Nov 2020 15:28:22 +0800 Subject: [PATCH 1461/4254] nil --- lib/core/typeinfo.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 2f213956b..00f7c176c 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -329,6 +329,8 @@ proc setPointer*(x: Any, y: pointer) = assert x.rawType.kind in pointerLike if y != nil: genericAssign(x.value, y, x.rawType) + else: + cast[ppointer](x.value)[] = nil proc fieldsAux(p: pointer, n: ptr TNimNode, ret: var seq[tuple[name: cstring, any: Any]]) = From a968e7dd9b2a22adeae8a71f7ca1e8dfb2e56a2c Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 13 Nov 2020 15:42:59 +0800 Subject: [PATCH 1462/4254] add testcase for #9754 --- tests/stdlib/t9754.nim | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/stdlib/t9754.nim diff --git a/tests/stdlib/t9754.nim b/tests/stdlib/t9754.nim new file mode 100644 index 000000000..6e81fd8bc --- /dev/null +++ b/tests/stdlib/t9754.nim @@ -0,0 +1,2 @@ +import tmarshal +import tparsesql \ No newline at end of file From a86aa310813d326d88959534c36b5499870dcb95 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 13 Nov 2020 16:15:13 +0800 Subject: [PATCH 1463/4254] minor --- tests/stdlib/t9754.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/stdlib/t9754.nim b/tests/stdlib/t9754.nim index 6e81fd8bc..971b5a8fb 100644 --- a/tests/stdlib/t9754.nim +++ b/tests/stdlib/t9754.nim @@ -1,2 +1,6 @@ +discard """ + joinable: false +""" + import tmarshal import tparsesql \ No newline at end of file From 8a21f94c7263f10c12c62ec2beb736ab8ce183c9 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 13 Nov 2020 10:25:00 +0100 Subject: [PATCH 1464/4254] refactoring: modernize rst.nim (#15953) --- lib/packages/docutils/rst.nim | 958 ++++++++++++++++------------------ 1 file changed, 449 insertions(+), 509 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index c04a6e07c..a72ee17b6 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -33,37 +33,22 @@ type mcError = "Error" MsgKind* = enum ## the possible messages - meCannotOpenFile, - meExpected, - meGridTableNotImplemented, - meMarkdownIllformedTable, - meNewSectionExpected, - meGeneralParseError, - meInvalidDirective, - mwRedefinitionOfLabel, - mwUnknownSubstitution, - mwUnsupportedLanguage, - mwUnsupportedField + meCannotOpenFile = "cannot open '$1'", + meExpected = "'$1' expected", + meGridTableNotImplemented = "grid table is not implemented", + meMarkdownIllformedTable = "illformed delimiter row of a markdown table", + meNewSectionExpected = "new section expected", + meGeneralParseError = "general parse error", + meInvalidDirective = "invalid directive: '$1'", + mwRedefinitionOfLabel = "redefinition of label '$1'", + mwUnknownSubstitution = "unknown substitution '$1'", + mwUnsupportedLanguage = "language '$1' not supported", + mwUnsupportedField = "field '$1' not supported" MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind, arg: string) {.closure, gcsafe.} ## what to do in case of an error FindFileHandler* = proc (filename: string): string {.closure, gcsafe.} -const - messages: array[MsgKind, string] = [ - meCannotOpenFile: "cannot open '$1'", - meExpected: "'$1' expected", - meGridTableNotImplemented: "grid table is not implemented", - meMarkdownIllformedTable: "illformed delimiter row of a markdown table", - meNewSectionExpected: "new section expected", - meGeneralParseError: "general parse error", - meInvalidDirective: "invalid directive: '$1'", - mwRedefinitionOfLabel: "redefinition of label '$1'", - mwUnknownSubstitution: "unknown substitution '$1'", - mwUnsupportedLanguage: "language '$1' not supported", - mwUnsupportedField: "field '$1' not supported" - ] - proc rstnodeToRefname*(n: PRstNode): string proc addNodes*(n: PRstNode): string proc getFieldValue*(n: PRstNode, fieldname: string): string @@ -136,10 +121,10 @@ proc getThing(L: var Lexer, tok: var Token, s: set[char]) = tok.col = L.col var pos = L.bufpos while true: - add(tok.symbol, L.buf[pos]) - inc(pos) + tok.symbol.add(L.buf[pos]) + inc pos if L.buf[pos] notin s: break - inc(L.col, pos - L.bufpos) + inc L.col, pos - L.bufpos L.bufpos = pos proc getAdornment(L: var Lexer, tok: var Token) = @@ -147,19 +132,19 @@ proc getAdornment(L: var Lexer, tok: var Token) = tok.line = L.line tok.col = L.col var pos = L.bufpos - var c = L.buf[pos] + let c = L.buf[pos] while true: - add(tok.symbol, L.buf[pos]) - inc(pos) + tok.symbol.add(L.buf[pos]) + inc pos if L.buf[pos] != c: break - inc(L.col, pos - L.bufpos) + inc L.col, pos - L.bufpos L.bufpos = pos proc getBracket(L: var Lexer, tok: var Token) = tok.kind = tkPunct tok.line = L.line tok.col = L.col - add(tok.symbol, L.buf[L.bufpos]) + tok.symbol.add(L.buf[L.bufpos]) inc L.col inc L.bufpos @@ -167,26 +152,26 @@ proc getIndentAux(L: var Lexer, start: int): int = var pos = start # skip the newline (but include it in the token!) if L.buf[pos] == '\x0D': - if L.buf[pos + 1] == '\x0A': inc(pos, 2) - else: inc(pos) + if L.buf[pos + 1] == '\x0A': inc pos, 2 + else: inc pos elif L.buf[pos] == '\x0A': - inc(pos) + inc pos if L.skipPounds: - if L.buf[pos] == '#': inc(pos) - if L.buf[pos] == '#': inc(pos) + if L.buf[pos] == '#': inc pos + if L.buf[pos] == '#': inc pos while true: case L.buf[pos] of ' ', '\x0B', '\x0C': - inc(pos) - inc(result) + inc pos + inc result of '\x09': - inc(pos) + inc pos result = result - (result mod 8) + 8 else: break # EndOfFile also leaves the loop if L.buf[pos] == '\0': result = 0 - elif (L.buf[pos] == '\x0A') or (L.buf[pos] == '\x0D'): + elif L.buf[pos] == '\x0A' or L.buf[pos] == '\x0D': # look at the next line for proper indentation: result = getIndentAux(L, pos) L.bufpos = pos # no need to set back buf @@ -219,7 +204,7 @@ proc rawGetTok(L: var Lexer, tok: var Token) = '/', ':', ';', '<', '=', '>', '?', '@', '\\', '^', '_', '`', '|', '~': getAdornment(L, tok) - if len(tok.symbol) <= 3: tok.kind = tkPunct + if tok.symbol.len <= 3: tok.kind = tkPunct of '(', ')', '[', ']', '{', '}': getBracket(L, tok) else: @@ -229,39 +214,39 @@ proc rawGetTok(L: var Lexer, tok: var Token) = tok.kind = tkEof else: tok.kind = tkOther - add(tok.symbol, c) - inc(L.bufpos) - inc(L.col) + tok.symbol.add(c) + inc L.bufpos + inc L.col tok.col = max(tok.col - L.baseIndent, 0) proc getTokens(buffer: string, skipPounds: bool, tokens: var TokenSeq): int = var L: Lexer - var length = len(tokens) + var length = tokens.len L.buf = cstring(buffer) L.line = 0 # skip UTF-8 BOM - if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'): - inc(L.bufpos, 3) + if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF': + inc L.bufpos, 3 L.skipPounds = skipPounds if skipPounds: if L.buf[L.bufpos] == '#': - inc(L.bufpos) - inc(result) + inc L.bufpos + inc result if L.buf[L.bufpos] == '#': - inc(L.bufpos) - inc(result) + inc L.bufpos + inc result L.baseIndent = 0 while L.buf[L.bufpos] == ' ': - inc(L.bufpos) - inc(L.baseIndent) - inc(result) + inc L.bufpos + inc L.baseIndent + inc result while true: - inc(length) + inc length setLen(tokens, length) rawGetTok(L, tokens[length - 1]) if tokens[length - 1].kind == tkEof: break if tokens[0].kind == tkWhite: # BUGFIX - tokens[0].ival = len(tokens[0].symbol) + tokens[0].ival = tokens[0].symbol.len tokens[0].kind = tkIndent type @@ -298,6 +283,10 @@ type EParseError* = object of ValueError +template currentTok(p: RstParser): Token = p.tok[p.idx] +template prevTok(p: RstParser): Token = p.tok[p.idx - 1] +template nextTok(p: RstParser): Token = p.tok[p.idx + 1] + proc whichMsgClass*(k: MsgKind): MsgClass = ## returns which message class `k` belongs to. case ($k)[1] @@ -309,7 +298,7 @@ proc whichMsgClass*(k: MsgKind): MsgClass = proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind, arg: string) = let mc = msgkind.whichMsgClass - let a = messages[msgkind] % arg + let a = $msgkind % arg let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a] if mc == mcError: raise newException(EParseError, message) else: writeLine(stdout, message) @@ -334,26 +323,26 @@ proc findRelativeFile(p: RstParser; filename: string): string = result = p.s.findFile(filename) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = - p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, - p.col + p.tok[p.idx].col, msgKind, arg) + p.s.msgHandler(p.filename, p.line + currentTok(p).line, + p.col + currentTok(p).col, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) = p.s.msgHandler(p.filename, p.line + line, p.col + col, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind) = - p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, - p.col + p.tok[p.idx].col, msgKind, - p.tok[p.idx].symbol) + p.s.msgHandler(p.filename, p.line + currentTok(p).line, + p.col + currentTok(p).col, msgKind, + currentTok(p).symbol) proc currInd(p: RstParser): int = result = p.indentStack[high(p.indentStack)] proc pushInd(p: var RstParser, ind: int) = - add(p.indentStack, ind) + p.indentStack.add(ind) proc popInd(p: var RstParser) = - if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1) + if p.indentStack.len > 1: setLen(p.indentStack, p.indentStack.len - 1) proc initParser(p: var RstParser, sharedState: PSharedState) = p.indentStack = @[0] @@ -367,41 +356,40 @@ proc initParser(p: var RstParser, sharedState: PSharedState) = proc addNodesAux(n: PRstNode, result: var string) = if n.kind == rnLeaf: - add(result, n.text) + result.add(n.text) else: - for i in countup(0, len(n) - 1): addNodesAux(n.sons[i], result) + for i in 0 ..< n.len: addNodesAux(n.sons[i], result) proc addNodes(n: PRstNode): string = - result = "" - addNodesAux(n, result) + n.addNodesAux(result) proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) = template special(s) = if b: - add(r, '-') + r.add('-') b = false - add(r, s) + r.add(s) if n == nil: return if n.kind == rnLeaf: - for i in countup(0, len(n.text) - 1): + for i in 0 ..< n.text.len: case n.text[i] of '0'..'9': if b: - add(r, '-') + r.add('-') b = false - if len(r) == 0: add(r, 'Z') - add(r, n.text[i]) + if r.len == 0: r.add('Z') + r.add(n.text[i]) of 'a'..'z', '\128'..'\255': if b: - add(r, '-') + r.add('-') b = false - add(r, n.text[i]) + r.add(n.text[i]) of 'A'..'Z': if b: - add(r, '-') + r.add('-') b = false - add(r, chr(ord(n.text[i]) - ord('A') + ord('a'))) + r.add(chr(ord(n.text[i]) - ord('A') + ord('a'))) of '$': special "dollar" of '%': special "percent" of '&': special "amp" @@ -422,12 +410,11 @@ proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) = of '@': special "at" of '|': special "bar" else: - if len(r) > 0: b = true + if r.len > 0: b = true else: - for i in countup(0, len(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b) + for i in 0 ..< n.len: rstnodeToRefnameAux(n.sons[i], r, b) proc rstnodeToRefname(n: PRstNode): string = - result = "" var b = false rstnodeToRefnameAux(n, result, b) @@ -443,27 +430,22 @@ proc findSub(p: var RstParser, n: PRstNode): int = result = -1 proc setSub(p: var RstParser, key: string, value: PRstNode) = - var length = len(p.s.subs) - for i in countup(0, length - 1): + var length = p.s.subs.len + for i in 0 ..< length: if key == p.s.subs[i].key: p.s.subs[i].value = value return - setLen(p.s.subs, length + 1) - p.s.subs[length].key = key - p.s.subs[length].value = value + p.s.subs.add(Substitution(key: key, value: value)) proc setRef(p: var RstParser, key: string, value: PRstNode) = - var length = len(p.s.refs) - for i in countup(0, length - 1): + var length = p.s.refs.len + for i in 0 ..< length: if key == p.s.refs[i].key: if p.s.refs[i].value.addNodes != value.addNodes: rstMessage(p, mwRedefinitionOfLabel, key) - p.s.refs[i].value = value return - setLen(p.s.refs, length + 1) - p.s.refs[length].key = key - p.s.refs[length].value = value + p.s.refs.add(Substitution(key: key, value: value)) proc findRef(p: var RstParser, key: string): PRstNode = for i in countup(0, high(p.s.refs)): @@ -471,73 +453,73 @@ proc findRef(p: var RstParser, key: string): PRstNode = return p.s.refs[i].value proc newLeaf(p: var RstParser): PRstNode = - result = newRstNode(rnLeaf, p.tok[p.idx].symbol) + result = newRstNode(rnLeaf, currentTok(p).symbol) proc getReferenceName(p: var RstParser, endStr: string): PRstNode = var res = newRstNode(rnInner) while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkWord, tkOther, tkWhite: - add(res, newLeaf(p)) + res.add(newLeaf(p)) of tkPunct: - if p.tok[p.idx].symbol == endStr: - inc(p.idx) + if currentTok(p).symbol == endStr: + inc p.idx break else: - add(res, newLeaf(p)) + res.add(newLeaf(p)) else: rstMessage(p, meExpected, endStr) break - inc(p.idx) + inc p.idx result = res proc untilEol(p: var RstParser): PRstNode = result = newRstNode(rnInner) - while not (p.tok[p.idx].kind in {tkIndent, tkEof}): - add(result, newLeaf(p)) - inc(p.idx) + while currentTok(p).kind notin {tkIndent, tkEof}: + result.add(newLeaf(p)) + inc p.idx proc expect(p: var RstParser, tok: string) = - if p.tok[p.idx].symbol == tok: inc(p.idx) + if currentTok(p).symbol == tok: inc p.idx else: rstMessage(p, meExpected, tok) proc isInlineMarkupEnd(p: RstParser, markup: string): bool = - result = p.tok[p.idx].symbol == markup - if not result: - return # Rule 3: - result = not (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) - if not result: - return # Rule 4: - result = (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) or - (markup in ["``", "`"] and p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkWord, tkEof}) or - (p.tok[p.idx + 1].symbol[0] in - {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', - '?', '_'}) - if not result: - return # Rule 7: + # rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules + result = currentTok(p).symbol == markup + if not result: return + # Rule 2: + result = prevTok(p).kind notin {tkIndent, tkWhite} + if not result: return + # Rule 7: + result = nextTok(p).kind in {tkIndent, tkWhite, tkEof} or + markup in ["``", "`"] and nextTok(p).kind in {tkIndent, tkWhite, tkWord, tkEof} or + nextTok(p).symbol[0] in + {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', '?', '_'} + if not result: return + # Rule 4: if p.idx > 0: - if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"): + if markup != "``" and prevTok(p).symbol == "\\": result = false proc isInlineMarkupStart(p: RstParser, markup: string): bool = + # rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules var d: char - result = p.tok[p.idx].symbol == markup - if not result: - return # Rule 1: - result = (p.idx == 0) or (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) or - (markup in ["``", "`"] and p.tok[p.idx - 1].kind in {tkIndent, tkWhite, tkWord}) or - (p.tok[p.idx - 1].symbol[0] in - {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'}) - if not result: - return # Rule 2: - result = not (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) - if not result: - return # Rule 5 & 7: + result = currentTok(p).symbol == markup + if not result: return + # Rule 6: + result = p.idx == 0 or prevTok(p).kind in {tkIndent, tkWhite} or + (markup in ["``", "`"] and prevTok(p).kind in {tkIndent, tkWhite, tkWord}) or + prevTok(p).symbol[0] in {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'} + if not result: return + # Rule 1: + result = nextTok(p).kind notin {tkIndent, tkWhite, tkEof} + if not result: return + # Rules 4 & 5: if p.idx > 0: - if p.tok[p.idx - 1].symbol == "\\": + if prevTok(p).symbol == "\\": result = false else: - var c = p.tok[p.idx - 1].symbol[0] + var c = prevTok(p).symbol[0] case c of '\'', '\"': d = c of '(': d = ')' @@ -545,7 +527,7 @@ proc isInlineMarkupStart(p: RstParser, markup: string): bool = of '{': d = '}' of '<': d = '>' else: d = '\0' - if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d + if d != '\0': result = nextTok(p).symbol[0] != d proc match(p: RstParser, start: int, expr: string): bool = # regular expressions are: @@ -560,7 +542,7 @@ proc match(p: RstParser, start: int, expr: string): bool = # 'e' tkWord or '#' (for enumeration lists) var i = 0 var j = start - var last = len(expr) - 1 + var last = expr.len - 1 while i <= last: case expr[i] of 'w': result = p.tok[j].kind == tkWord @@ -572,79 +554,79 @@ proc match(p: RstParser, start: int, expr: string): bool = of 'T': result = true of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent} of 'e': - result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#") + result = p.tok[j].kind == tkWord or p.tok[j].symbol == "#" if result: case p.tok[j].symbol[0] - of 'a'..'z', 'A'..'Z', '#': result = len(p.tok[j].symbol) == 1 + of 'a'..'z', 'A'..'Z', '#': result = p.tok[j].symbol.len == 1 of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'}) else: result = false else: var c = expr[i] var length = 0 - while (i <= last) and (expr[i] == c): - inc(i) - inc(length) - dec(i) - result = (p.tok[j].kind in {tkPunct, tkAdornment}) and - (len(p.tok[j].symbol) == length) and (p.tok[j].symbol[0] == c) + while i <= last and expr[i] == c: + inc i + inc length + dec i + result = p.tok[j].kind in {tkPunct, tkAdornment} and + p.tok[j].symbol.len == length and p.tok[j].symbol[0] == c if not result: return - inc(j) - inc(i) + inc j + inc i result = true proc fixupEmbeddedRef(n, a, b: PRstNode) = var sep = - 1 - for i in countdown(len(n) - 2, 0): + for i in countdown(n.len - 2, 0): if n.sons[i].text == "<": sep = i break - var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1 - for i in countup(0, sep - incr): add(a, n.sons[i]) - for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i]) + var incr = if sep > 0 and n.sons[sep - 1].text[0] == ' ': 2 else: 1 + for i in countup(0, sep - incr): a.add(n.sons[i]) + for i in countup(sep + 1, n.len - 2): b.add(n.sons[i]) proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = result = n if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"): - inc(p.idx) + inc p.idx if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">": var a = newRstNode(rnInner) var b = newRstNode(rnInner) fixupEmbeddedRef(n, a, b) - if len(a) == 0: + if a.len == 0: result = newRstNode(rnStandaloneHyperlink) - add(result, b) + result.add(b) else: result = newRstNode(rnHyperlink) - add(result, a) - add(result, b) + result.add(a) + result.add(b) setRef(p, rstnodeToRefname(a), b) elif n.kind == rnInterpretedText: n.kind = rnRef else: result = newRstNode(rnRef) - add(result, n) + result.add(n) elif match(p, p.idx, ":w:"): # a role: - if p.tok[p.idx + 1].symbol == "idx": + if nextTok(p).symbol == "idx": n.kind = rnIdx - elif p.tok[p.idx + 1].symbol == "literal": + elif nextTok(p).symbol == "literal": n.kind = rnInlineLiteral - elif p.tok[p.idx + 1].symbol == "strong": + elif nextTok(p).symbol == "strong": n.kind = rnStrongEmphasis - elif p.tok[p.idx + 1].symbol == "emphasis": + elif nextTok(p).symbol == "emphasis": n.kind = rnEmphasis - elif (p.tok[p.idx + 1].symbol == "sub") or - (p.tok[p.idx + 1].symbol == "subscript"): + elif nextTok(p).symbol == "sub" or + nextTok(p).symbol == "subscript": n.kind = rnSub - elif (p.tok[p.idx + 1].symbol == "sup") or - (p.tok[p.idx + 1].symbol == "supscript"): + elif nextTok(p).symbol == "sup" or + nextTok(p).symbol == "supscript": n.kind = rnSup else: result = newRstNode(rnGeneralRole) n.kind = rnInner - add(result, n) - add(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol)) - inc(p.idx, 3) + result.add(n) + result.add(newRstNode(rnLeaf, nextTok(p).symbol)) + inc p.idx, 3 proc matchVerbatim(p: RstParser, start: int, expr: string): int = result = start @@ -656,7 +638,7 @@ proc matchVerbatim(p: RstParser, start: int, expr: string): int = if j < expr.len: result = 0 proc parseSmiley(p: var RstParser): PRstNode = - if p.tok[p.idx].symbol[0] notin SmileyStartChars: return + if currentTok(p).symbol[0] notin SmileyStartChars: return for key, val in items(Smilies): let m = matchVerbatim(p, p.idx, key) if m > 0: @@ -665,135 +647,105 @@ proc parseSmiley(p: var RstParser): PRstNode = result.text = val return -when false: - const - urlChars = {'A'..'Z', 'a'..'z', '0'..'9', ':', '#', '@', '%', '/', ';', - '$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&', - '\128'..'\255'} - proc isUrl(p: RstParser, i: int): bool = - result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and - (p.tok[i+3].kind == tkWord) and - (p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"]) + result = p.tok[i+1].symbol == ":" and p.tok[i+2].symbol == "//" and + p.tok[i+3].kind == tkWord and + p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"] proc parseUrl(p: var RstParser, father: PRstNode) = - #if p.tok[p.idx].symbol[strStart] == '<': + #if currentTok(p).symbol[strStart] == '<': if isUrl(p, p.idx): var n = newRstNode(rnStandaloneHyperlink) while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkWord, tkAdornment, tkOther: discard of tkPunct: - if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}: + if nextTok(p).kind notin {tkWord, tkAdornment, tkOther, tkPunct}: break else: break - add(n, newLeaf(p)) - inc(p.idx) - add(father, n) + n.add(newLeaf(p)) + inc p.idx + father.add(n) else: var n = newLeaf(p) - inc(p.idx) - if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n) - add(father, n) + inc p.idx + if currentTok(p).symbol == "_": n = parsePostfix(p, n) + father.add(n) proc parseBackslash(p: var RstParser, father: PRstNode) = - assert(p.tok[p.idx].kind == tkPunct) - if p.tok[p.idx].symbol == "\\\\": - add(father, newRstNode(rnLeaf, "\\")) - inc(p.idx) - elif p.tok[p.idx].symbol == "\\": + assert(currentTok(p).kind == tkPunct) + if currentTok(p).symbol == "\\\\": + father.add(newRstNode(rnLeaf, "\\")) + inc p.idx + elif currentTok(p).symbol == "\\": # XXX: Unicode? - inc(p.idx) - if p.tok[p.idx].kind != tkWhite: add(father, newLeaf(p)) - if p.tok[p.idx].kind != tkEof: inc(p.idx) + inc p.idx + if currentTok(p).kind != tkWhite: father.add(newLeaf(p)) + if currentTok(p).kind != tkEof: inc p.idx else: - add(father, newLeaf(p)) - inc(p.idx) - -when false: - proc parseAdhoc(p: var RstParser, father: PRstNode, verbatim: bool) = - if not verbatim and isURL(p, p.idx): - var n = newRstNode(rnStandaloneHyperlink) - while true: - case p.tok[p.idx].kind - of tkWord, tkAdornment, tkOther: nil - of tkPunct: - if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}: - break - else: break - add(n, newLeaf(p)) - inc(p.idx) - add(father, n) - elif not verbatim and roSupportSmilies in p.sharedState.options: - let n = parseSmiley(p) - if s != nil: - add(father, n) - else: - var n = newLeaf(p) - inc(p.idx) - if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n) - add(father, n) + father.add(newLeaf(p)) + inc p.idx proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, interpretBackslash: bool) = let - line = p.tok[p.idx].line - col = p.tok[p.idx].col + line = currentTok(p).line + col = currentTok(p).col inc p.idx while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkPunct: if isInlineMarkupEnd(p, postfix): - inc(p.idx) + inc p.idx break elif interpretBackslash: parseBackslash(p, father) else: - add(father, newLeaf(p)) - inc(p.idx) + father.add(newLeaf(p)) + inc p.idx of tkAdornment, tkWord, tkOther: - add(father, newLeaf(p)) - inc(p.idx) + father.add(newLeaf(p)) + inc p.idx of tkIndent: - add(father, newRstNode(rnLeaf, " ")) - inc(p.idx) - if p.tok[p.idx].kind == tkIndent: + father.add(newRstNode(rnLeaf, " ")) + inc p.idx + if currentTok(p).kind == tkIndent: rstMessage(p, meExpected, postfix, line, col) break of tkWhite: - add(father, newRstNode(rnLeaf, " ")) - inc(p.idx) + father.add(newRstNode(rnLeaf, " ")) + inc p.idx else: rstMessage(p, meExpected, postfix, line, col) proc parseMarkdownCodeblock(p: var RstParser): PRstNode = var args = newRstNode(rnDirArg) - if p.tok[p.idx].kind == tkWord: - add(args, newLeaf(p)) - inc(p.idx) + if currentTok(p).kind == tkWord: + args.add(newLeaf(p)) + inc p.idx else: args = nil var n = newRstNode(rnLeaf, "") while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkEof: rstMessage(p, meExpected, "```") break of tkPunct: - if p.tok[p.idx].symbol == "```": - inc(p.idx) + if currentTok(p).symbol == "```": + inc p.idx break else: - add(n.text, p.tok[p.idx].symbol) - inc(p.idx) + n.text.add(currentTok(p).symbol) + inc p.idx else: - add(n.text, p.tok[p.idx].symbol) - inc(p.idx) + n.text.add(currentTok(p).symbol) + inc p.idx var lb = newRstNode(rnLiteralBlock) - add(lb, n) + lb.add(n) result = newRstNode(rnCodeBlock) - add(result, args) - add(result, PRstNode(nil)) - add(result, lb) + result.add(args) + result.add(PRstNode(nil)) + result.add(lb) proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = result = true @@ -821,78 +773,78 @@ proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = result = true proc parseInline(p: var RstParser, father: PRstNode) = - case p.tok[p.idx].kind + case currentTok(p).kind of tkPunct: if isInlineMarkupStart(p, "***"): var n = newRstNode(rnTripleEmphasis) parseUntil(p, n, "***", true) - add(father, n) + father.add(n) elif isInlineMarkupStart(p, "**"): var n = newRstNode(rnStrongEmphasis) parseUntil(p, n, "**", true) - add(father, n) + father.add(n) elif isInlineMarkupStart(p, "*"): var n = newRstNode(rnEmphasis) parseUntil(p, n, "*", true) - add(father, n) - elif roSupportMarkdown in p.s.options and p.tok[p.idx].symbol == "```": - inc(p.idx) - add(father, parseMarkdownCodeblock(p)) + father.add(n) + elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": + inc p.idx + father.add(parseMarkdownCodeblock(p)) elif isInlineMarkupStart(p, "``"): var n = newRstNode(rnInlineLiteral) parseUntil(p, n, "``", false) - add(father, n) + father.add(n) elif isInlineMarkupStart(p, "`"): var n = newRstNode(rnInterpretedText) parseUntil(p, n, "`", true) n = parsePostfix(p, n) - add(father, n) + father.add(n) elif isInlineMarkupStart(p, "|"): var n = newRstNode(rnSubstitutionReferences) parseUntil(p, n, "|", false) - add(father, n) + father.add(n) elif roSupportMarkdown in p.s.options and - p.tok[p.idx].symbol == "[" and p.tok[p.idx+1].symbol != "[" and + currentTok(p).symbol == "[" and nextTok(p).symbol != "[" and parseMarkdownLink(p, father): discard "parseMarkdownLink already processed it" else: if roSupportSmilies in p.s.options: let n = parseSmiley(p) if n != nil: - add(father, n) + father.add(n) return parseBackslash(p, father) of tkWord: if roSupportSmilies in p.s.options: let n = parseSmiley(p) if n != nil: - add(father, n) + father.add(n) return parseUrl(p, father) of tkAdornment, tkOther, tkWhite: if roSupportSmilies in p.s.options: let n = parseSmiley(p) if n != nil: - add(father, n) + father.add(n) return - add(father, newLeaf(p)) - inc(p.idx) + father.add(newLeaf(p)) + inc p.idx else: discard proc getDirective(p: var RstParser): string = - if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord: + if currentTok(p).kind == tkWhite and nextTok(p).kind == tkWord: var j = p.idx - inc(p.idx) - result = p.tok[p.idx].symbol - inc(p.idx) - while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}: - if p.tok[p.idx].symbol == "::": break - add(result, p.tok[p.idx].symbol) - inc(p.idx) - if p.tok[p.idx].kind == tkWhite: inc(p.idx) - if p.tok[p.idx].symbol == "::": - inc(p.idx) - if (p.tok[p.idx].kind == tkWhite): inc(p.idx) + inc p.idx + result = currentTok(p).symbol + inc p.idx + while currentTok(p).kind in {tkWord, tkPunct, tkAdornment, tkOther}: + if currentTok(p).symbol == "::": break + result.add(currentTok(p).symbol) + inc p.idx + if currentTok(p).kind == tkWhite: inc p.idx + if currentTok(p).symbol == "::": + inc p.idx + if currentTok(p).kind == tkWhite: inc p.idx else: p.idx = j # set back result = "" # error @@ -900,23 +852,23 @@ proc getDirective(p: var RstParser): string = result = "" proc parseComment(p: var RstParser): PRstNode = - case p.tok[p.idx].kind + case currentTok(p).kind of tkIndent, tkEof: - if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent: - inc(p.idx) # empty comment + if currentTok(p).kind != tkEof and nextTok(p).kind == tkIndent: + inc p.idx # empty comment else: - var indent = p.tok[p.idx].ival + var indent = currentTok(p).ival while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkEof: break of tkIndent: - if (p.tok[p.idx].ival < indent): break + if currentTok(p).ival < indent: break else: discard - inc(p.idx) + inc p.idx else: - while p.tok[p.idx].kind notin {tkIndent, tkEof}: inc(p.idx) + while currentTok(p).kind notin {tkIndent, tkEof}: inc p.idx result = nil type @@ -936,13 +888,13 @@ proc getDirKind(s: string): DirKind = proc parseLine(p: var RstParser, father: PRstNode) = while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father) else: break proc parseUntilNewline(p: var RstParser, father: PRstNode) = while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father) of tkEof, tkIndent: break @@ -952,19 +904,19 @@ proc parseField(p: var RstParser): PRstNode = ## ## rnField nodes have two children nodes, a rnFieldName and a rnFieldBody. result = newRstNode(rnField) - var col = p.tok[p.idx].col + var col = currentTok(p).col var fieldname = newRstNode(rnFieldName) parseUntil(p, fieldname, ":", false) var fieldbody = newRstNode(rnFieldBody) - if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody) - if p.tok[p.idx].kind == tkIndent: - var indent = p.tok[p.idx].ival + if currentTok(p).kind != tkIndent: parseLine(p, fieldbody) + if currentTok(p).kind == tkIndent: + var indent = currentTok(p).ival if indent > col: pushInd(p, indent) parseSection(p, fieldbody) popInd(p) - add(result, fieldname) - add(result, fieldbody) + result.add(fieldname) + result.add(fieldbody) proc parseFields(p: var RstParser): PRstNode = ## Parses fields for a section or directive block. @@ -973,16 +925,16 @@ proc parseFields(p: var RstParser): PRstNode = ## otherwise it will return a node of rnFieldList type with children. result = nil var atStart = p.idx == 0 and p.tok[0].symbol == ":" - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx + 1].symbol == ":") or + if currentTok(p).kind == tkIndent and nextTok(p).symbol == ":" or atStart: - var col = if atStart: p.tok[p.idx].col else: p.tok[p.idx].ival + var col = if atStart: currentTok(p).col else: currentTok(p).ival result = newRstNode(rnFieldList) - if not atStart: inc(p.idx) + if not atStart: inc p.idx while true: - add(result, parseField(p)) - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and - (p.tok[p.idx + 1].symbol == ":"): - inc(p.idx) + result.add(parseField(p)) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col and + nextTok(p).symbol == ":": + inc p.idx else: break @@ -999,13 +951,12 @@ proc getFieldValue*(n: PRstNode): string = result = addNodes(n.sons[1]).strip proc getFieldValue(n: PRstNode, fieldname: string): string = - result = "" if n.sons[1] == nil: return - if (n.sons[1].kind != rnFieldList): + if n.sons[1].kind != rnFieldList: #InternalError("getFieldValue (2): " & $n.sons[1].kind) # We don't like internal errors here anymore as that would break the forum! return - for i in countup(0, len(n.sons[1]) - 1): + for i in 0 ..< n.sons[1].len: var f = n.sons[1].sons[i] if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0: result = addNodes(f.sons[1]) @@ -1020,32 +971,32 @@ proc parseDotDot(p: var RstParser): PRstNode {.gcsafe.} proc parseLiteralBlock(p: var RstParser): PRstNode = result = newRstNode(rnLiteralBlock) var n = newRstNode(rnLeaf, "") - if p.tok[p.idx].kind == tkIndent: - var indent = p.tok[p.idx].ival - inc(p.idx) + if currentTok(p).kind == tkIndent: + var indent = currentTok(p).ival + inc p.idx while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkEof: break of tkIndent: - if (p.tok[p.idx].ival < indent): + if currentTok(p).ival < indent: break else: - add(n.text, "\n") - add(n.text, spaces(p.tok[p.idx].ival - indent)) - inc(p.idx) + n.text.add("\n") + n.text.add(spaces(currentTok(p).ival - indent)) + inc p.idx else: - add(n.text, p.tok[p.idx].symbol) - inc(p.idx) + n.text.add(currentTok(p).symbol) + inc p.idx else: - while not (p.tok[p.idx].kind in {tkIndent, tkEof}): - add(n.text, p.tok[p.idx].symbol) - inc(p.idx) - add(result, n) + while currentTok(p).kind notin {tkIndent, tkEof}: + n.text.add(currentTok(p).symbol) + inc p.idx + result.add(n) proc getLevel(map: var LevelMap, lvl: var int, c: char): int = if map[c] == 0: - inc(lvl) + inc lvl map[c] = lvl result = map[c] @@ -1056,26 +1007,26 @@ proc tokenAfterNewline(p: RstParser): int = of tkEof: break of tkIndent: - inc(result) + inc result break - else: inc(result) + else: inc result proc isLineBlock(p: RstParser): bool = var j = tokenAfterNewline(p) - result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or - (p.tok[j].col > p.tok[p.idx].col) + result = currentTok(p).col == p.tok[j].col and p.tok[j].symbol == "|" or + p.tok[j].col > currentTok(p).col proc predNL(p: RstParser): bool = result = true if p.idx > 0: - result = p.tok[p.idx-1].kind == tkIndent and - p.tok[p.idx-1].ival == currInd(p) + result = prevTok(p).kind == tkIndent and + prevTok(p).ival == currInd(p) proc isDefList(p: RstParser): bool = var j = tokenAfterNewline(p) - result = (p.tok[p.idx].col < p.tok[j].col) and - (p.tok[j].kind in {tkWord, tkOther, tkPunct}) and - (p.tok[j - 2].symbol != "::") + result = currentTok(p).col < p.tok[j].col and + p.tok[j].kind in {tkWord, tkOther, tkPunct} and + p.tok[j - 2].symbol != "::" proc isOptionList(p: RstParser): bool = result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or @@ -1089,7 +1040,7 @@ proc isMarkdownHeadlinePattern(s: string): bool = proc isMarkdownHeadline(p: RstParser): bool = if roSupportMarkdown in p.s.options: - if isMarkdownHeadlinePattern(p.tok[p.idx].symbol) and p.tok[p.idx+1].kind == tkWhite: + if isMarkdownHeadlinePattern(currentTok(p).symbol) and nextTok(p).kind == tkWhite: if p.tok[p.idx+2].kind in {tkWord, tkOther, tkPunct}: result = true @@ -1101,7 +1052,7 @@ proc findPipe(p: RstParser, start: int): bool = inc i proc whichSection(p: RstParser): RstNodeKind = - case p.tok[p.idx].kind + case currentTok(p).kind of tkAdornment: if match(p, p.idx + 1, "ii"): result = rnTransition elif match(p, p.idx + 1, " a"): result = rnTable @@ -1116,22 +1067,21 @@ proc whichSection(p: RstParser): RstNodeKind = elif roSupportMarkdown in p.s.options and predNL(p) and match(p, p.idx, "| w") and findPipe(p, p.idx+3): result = rnMarkdownTable - elif p.tok[p.idx].symbol == "```": + elif currentTok(p).symbol == "```": result = rnCodeBlock elif match(p, tokenAfterNewline(p), "ai"): result = rnHeadline - elif p.tok[p.idx].symbol == "::": + elif currentTok(p).symbol == "::": result = rnLiteralBlock elif predNL(p) and - ((p.tok[p.idx].symbol == "+") or (p.tok[p.idx].symbol == "*") or - (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite): + currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: result = rnBulletList - elif (p.tok[p.idx].symbol == "|") and isLineBlock(p): + elif currentTok(p).symbol == "|" and isLineBlock(p): result = rnLineBlock - elif (p.tok[p.idx].symbol == "..") and predNL(p): + elif currentTok(p).symbol == ".." and predNL(p): result = rnDirective elif match(p, p.idx, ":w:") and predNL(p): - # (p.tok[p.idx].symbol == ":") + # (currentTok(p).symbol == ":") result = rnFieldList elif match(p, p.idx, "(e) ") or match(p, p.idx, "e. "): result = rnEnumList @@ -1153,47 +1103,46 @@ proc whichSection(p: RstParser): RstNodeKind = proc parseLineBlock(p: var RstParser): PRstNode = result = nil - if p.tok[p.idx + 1].kind == tkWhite: - var col = p.tok[p.idx].col + if nextTok(p).kind == tkWhite: + var col = currentTok(p).col result = newRstNode(rnLineBlock) pushInd(p, p.tok[p.idx + 2].col) - inc(p.idx, 2) + inc p.idx, 2 while true: var item = newRstNode(rnLineBlockItem) parseSection(p, item) - add(result, item) - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and - (p.tok[p.idx + 1].symbol == "|") and - (p.tok[p.idx + 2].kind == tkWhite): - inc(p.idx, 3) + result.add(item) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col and + nextTok(p).symbol == "|" and p.tok[p.idx + 2].kind == tkWhite: + inc p.idx, 3 else: break popInd(p) proc parseParagraph(p: var RstParser, result: PRstNode) = while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkIndent: - if p.tok[p.idx + 1].kind == tkIndent: - inc(p.idx) + if nextTok(p).kind == tkIndent: + inc p.idx break - elif (p.tok[p.idx].ival == currInd(p)): - inc(p.idx) + elif currentTok(p).ival == currInd(p): + inc p.idx case whichSection(p) of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective: - add(result, newRstNode(rnLeaf, " ")) + result.add(newRstNode(rnLeaf, " ")) of rnLineBlock: - addIfNotNil(result, parseLineBlock(p)) + result.addIfNotNil(parseLineBlock(p)) else: break else: break of tkPunct: - if (p.tok[p.idx].symbol == "::") and - (p.tok[p.idx + 1].kind == tkIndent) and - (currInd(p) < p.tok[p.idx + 1].ival): - add(result, newRstNode(rnLeaf, ":")) - inc(p.idx) # skip '::' - add(result, parseLiteralBlock(p)) + if currentTok(p).symbol == "::" and + nextTok(p).kind == tkIndent and + currInd(p) < nextTok(p).ival: + result.add(newRstNode(rnLeaf, ":")) + inc p.idx # skip '::' + result.add(parseLiteralBlock(p)) break else: parseInline(p, result) @@ -1204,16 +1153,16 @@ proc parseParagraph(p: var RstParser, result: PRstNode) = proc parseHeadline(p: var RstParser): PRstNode = result = newRstNode(rnHeadline) if isMarkdownHeadline(p): - result.level = p.tok[p.idx].symbol.len - assert(p.tok[p.idx+1].kind == tkWhite) + result.level = currentTok(p).symbol.len + assert(nextTok(p).kind == tkWhite) inc p.idx, 2 parseUntilNewline(p, result) else: parseUntilNewline(p, result) - assert(p.tok[p.idx].kind == tkIndent) - assert(p.tok[p.idx + 1].kind == tkAdornment) - var c = p.tok[p.idx + 1].symbol[0] - inc(p.idx, 2) + assert(currentTok(p).kind == tkIndent) + assert(nextTok(p).kind == tkAdornment) + var c = nextTok(p).symbol[0] + inc p.idx, 2 result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c) type @@ -1223,20 +1172,20 @@ type ColSeq = seq[ColumnLimits] proc tokEnd(p: RstParser): int = - result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1 + result = currentTok(p).col + currentTok(p).symbol.len - 1 proc getColumns(p: var RstParser, cols: var IntSeq) = var L = 0 while true: - inc(L) + inc L setLen(cols, L) cols[L - 1] = tokEnd(p) - assert(p.tok[p.idx].kind == tkAdornment) - inc(p.idx) - if p.tok[p.idx].kind != tkWhite: break - inc(p.idx) - if p.tok[p.idx].kind != tkAdornment: break - if p.tok[p.idx].kind == tkIndent: inc(p.idx) + assert(currentTok(p).kind == tkAdornment) + inc p.idx + if currentTok(p).kind != tkWhite: break + inc p.idx + if currentTok(p).kind != tkAdornment: break + if currentTok(p).kind == tkIndent: inc p.idx # last column has no limit: cols[L - 1] = 32000 @@ -1254,35 +1203,35 @@ proc parseSimpleTable(p: var RstParser): PRstNode = cols = @[] row = @[] a = nil - c = p.tok[p.idx].symbol[0] + c = currentTok(p).symbol[0] while true: - if p.tok[p.idx].kind == tkAdornment: + if currentTok(p).kind == tkAdornment: last = tokenAfterNewline(p) if p.tok[last].kind in {tkEof, tkIndent}: # skip last adornment line: p.idx = last break getColumns(p, cols) - setLen(row, len(cols)) + setLen(row, cols.len) if a != nil: - for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell - if p.tok[p.idx].kind == tkEof: break + for j in 0 ..< a.len: a.sons[j].kind = rnTableHeaderCell + if currentTok(p).kind == tkEof: break for j in countup(0, high(row)): row[j] = "" # the following while loop iterates over the lines a single cell may span: - line = p.tok[p.idx].line + line = currentTok(p).line while true: i = 0 - while not (p.tok[p.idx].kind in {tkIndent, tkEof}): - if (tokEnd(p) <= cols[i]): - add(row[i], p.tok[p.idx].symbol) - inc(p.idx) + while currentTok(p).kind notin {tkIndent, tkEof}: + if tokEnd(p) <= cols[i]: + row[i].add(currentTok(p).symbol) + inc p.idx else: - if p.tok[p.idx].kind == tkWhite: inc(p.idx) - inc(i) - if p.tok[p.idx].kind == tkIndent: inc(p.idx) + if currentTok(p).kind == tkWhite: inc p.idx + inc i + if currentTok(p).kind == tkIndent: inc p.idx if tokEnd(p) <= cols[0]: break - if p.tok[p.idx].kind in {tkEof, tkAdornment}: break - for j in countup(1, high(row)): add(row[j], '\x0A') + if currentTok(p).kind in {tkEof, tkAdornment}: break + for j in countup(1, high(row)): row[j].add('\x0A') a = newRstNode(rnTableRow) for j in countup(0, high(row)): initParser(q, p.s) @@ -1291,21 +1240,21 @@ proc parseSimpleTable(p: var RstParser): PRstNode = q.filename = p.filename q.col += getTokens(row[j], false, q.tok) b = newRstNode(rnTableDataCell) - add(b, parseDoc(q)) - add(a, b) - add(result, a) + b.add(parseDoc(q)) + a.add(b) + result.add(a) proc readTableRow(p: var RstParser): ColSeq = - if p.tok[p.idx].symbol == "|": inc p.idx - while p.tok[p.idx].kind notin {tkIndent, tkEof}: + if currentTok(p).symbol == "|": inc p.idx + while currentTok(p).kind notin {tkIndent, tkEof}: var limits: ColumnLimits limits.first = p.idx - while p.tok[p.idx].kind notin {tkIndent, tkEof}: - if p.tok[p.idx].symbol == "|" and p.tok[p.idx-1].symbol != "\\": break + while currentTok(p).kind notin {tkIndent, tkEof}: + if currentTok(p).symbol == "|" and prevTok(p).symbol != "\\": break inc p.idx limits.last = p.idx result.add(limits) - if p.tok[p.idx].kind in {tkIndent, tkEof}: break + if currentTok(p).kind in {tkIndent, tkEof}: break inc p.idx p.idx = tokenAfterNewline(p) @@ -1340,7 +1289,7 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = b = newRstNode(cellKind) initParser(q, p.s) q.col = p.col - q.line = p.tok[p.idx].line - 1 + q.line = currentTok(p).line - 1 q.filename = p.filename q.col += getTokens(getColContents(p, row[j]), false, q.tok) b.add(parseDoc(q)) @@ -1349,50 +1298,50 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = parseRow(p, rnTableHeaderCell, result) if not isValidDelimiterRow(p, colNum): rstMessage(p, meMarkdownIllformedTable) - while predNL(p) and p.tok[p.idx].symbol == "|": + while predNL(p) and currentTok(p).symbol == "|": parseRow(p, rnTableDataCell, result) proc parseTransition(p: var RstParser): PRstNode = result = newRstNode(rnTransition) - inc(p.idx) - if p.tok[p.idx].kind == tkIndent: inc(p.idx) - if p.tok[p.idx].kind == tkIndent: inc(p.idx) + inc p.idx + if currentTok(p).kind == tkIndent: inc p.idx + if currentTok(p).kind == tkIndent: inc p.idx proc parseOverline(p: var RstParser): PRstNode = - var c = p.tok[p.idx].symbol[0] - inc(p.idx, 2) + var c = currentTok(p).symbol[0] + inc p.idx, 2 result = newRstNode(rnOverline) while true: parseUntilNewline(p, result) - if p.tok[p.idx].kind == tkIndent: - inc(p.idx) - if p.tok[p.idx - 1].ival > currInd(p): - add(result, newRstNode(rnLeaf, " ")) + if currentTok(p).kind == tkIndent: + inc p.idx + if prevTok(p).ival > currInd(p): + result.add(newRstNode(rnLeaf, " ")) else: break else: break result.level = getLevel(p.s.overlineToLevel, p.s.oLevel, c) - if p.tok[p.idx].kind == tkAdornment: - inc(p.idx) # XXX: check? - if p.tok[p.idx].kind == tkIndent: inc(p.idx) + if currentTok(p).kind == tkAdornment: + inc p.idx # XXX: check? + if currentTok(p).kind == tkIndent: inc p.idx proc parseBulletList(p: var RstParser): PRstNode = result = nil - if p.tok[p.idx + 1].kind == tkWhite: - var bullet = p.tok[p.idx].symbol - var col = p.tok[p.idx].col + if nextTok(p).kind == tkWhite: + var bullet = currentTok(p).symbol + var col = currentTok(p).col result = newRstNode(rnBulletList) pushInd(p, p.tok[p.idx + 2].col) - inc(p.idx, 2) + inc p.idx, 2 while true: var item = newRstNode(rnBulletItem) parseSection(p, item) - add(result, item) - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and - (p.tok[p.idx + 1].symbol == bullet) and - (p.tok[p.idx + 2].kind == tkWhite): - inc(p.idx, 3) + result.add(item) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col and + nextTok(p).symbol == bullet and + p.tok[p.idx + 2].kind == tkWhite: + inc p.idx, 3 else: break popInd(p) @@ -1404,63 +1353,62 @@ proc parseOptionList(p: var RstParser): PRstNode = var a = newRstNode(rnOptionGroup) var b = newRstNode(rnDescription) var c = newRstNode(rnOptionListItem) - if match(p, p.idx, "//w"): inc(p.idx) - while not (p.tok[p.idx].kind in {tkIndent, tkEof}): - if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1): - inc(p.idx) + if match(p, p.idx, "//w"): inc p.idx + while currentTok(p).kind notin {tkIndent, tkEof}: + if currentTok(p).kind == tkWhite and currentTok(p).symbol.len > 1: + inc p.idx break - add(a, newLeaf(p)) - inc(p.idx) + a.add(newLeaf(p)) + inc p.idx var j = tokenAfterNewline(p) - if (j > 0) and (p.tok[j - 1].kind == tkIndent) and - (p.tok[j - 1].ival > currInd(p)): + if j > 0 and p.tok[j - 1].kind == tkIndent and p.tok[j - 1].ival > currInd(p): pushInd(p, p.tok[j - 1].ival) parseSection(p, b) popInd(p) else: parseLine(p, b) - if (p.tok[p.idx].kind == tkIndent): inc(p.idx) - add(c, a) - add(c, b) - add(result, c) + if currentTok(p).kind == tkIndent: inc p.idx + c.add(a) + c.add(b) + result.add(c) else: break proc parseDefinitionList(p: var RstParser): PRstNode = result = nil var j = tokenAfterNewline(p) - 1 - if (j >= 1) and (p.tok[j].kind == tkIndent) and - (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"): - var col = p.tok[p.idx].col + if j >= 1 and p.tok[j].kind == tkIndent and + p.tok[j].ival > currInd(p) and p.tok[j - 1].symbol != "::": + var col = currentTok(p).col result = newRstNode(rnDefList) while true: j = p.idx var a = newRstNode(rnDefName) parseLine(p, a) - if (p.tok[p.idx].kind == tkIndent) and - (p.tok[p.idx].ival > currInd(p)) and - (p.tok[p.idx + 1].symbol != "::") and - not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}): - pushInd(p, p.tok[p.idx].ival) + if currentTok(p).kind == tkIndent and + currentTok(p).ival > currInd(p) and + nextTok(p).symbol != "::" and + nextTok(p).kind notin {tkIndent, tkEof}: + pushInd(p, currentTok(p).ival) var b = newRstNode(rnDefBody) parseSection(p, b) var c = newRstNode(rnDefItem) - add(c, a) - add(c, b) - add(result, c) + c.add(a) + c.add(b) + result.add(c) popInd(p) else: p.idx = j break - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col): - inc(p.idx) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col: + inc p.idx j = tokenAfterNewline(p) - 1 if j >= 1 and p.tok[j].kind == tkIndent and p.tok[j].ival > col and p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent: discard else: break - if len(result) == 0: result = nil + if result.len == 0: result = nil proc parseEnumList(p: var RstParser): PRstNode = const @@ -1470,54 +1418,54 @@ proc parseEnumList(p: var RstParser): PRstNode = var w = 0 while w <= 2: if match(p, p.idx, wildcards[w]): break - inc(w) + inc w if w <= 2: - var col = p.tok[p.idx].col + var col = currentTok(p).col result = newRstNode(rnEnumList) - inc(p.idx, wildpos[w] + 3) + inc p.idx, wildpos[w] + 3 var j = tokenAfterNewline(p) - if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]): - pushInd(p, p.tok[p.idx].col) + if p.tok[j].col == currentTok(p).col or match(p, j, wildcards[w]): + pushInd(p, currentTok(p).col) while true: var item = newRstNode(rnEnumItem) parseSection(p, item) - add(result, item) - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and + result.add(item) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col and match(p, p.idx + 1, wildcards[w]): - inc(p.idx, wildpos[w] + 4) + inc p.idx, wildpos[w] + 4 else: break popInd(p) else: - dec(p.idx, wildpos[w] + 3) + dec p.idx, wildpos[w] + 3 result = nil proc sonKind(father: PRstNode, i: int): RstNodeKind = result = rnLeaf - if i < len(father): result = father.sons[i].kind + if i < father.len: result = father.sons[i].kind proc parseSection(p: var RstParser, result: PRstNode) = while true: var leave = false assert(p.idx >= 0) - while p.tok[p.idx].kind == tkIndent: - if currInd(p) == p.tok[p.idx].ival: - inc(p.idx) - elif p.tok[p.idx].ival > currInd(p): - pushInd(p, p.tok[p.idx].ival) + while currentTok(p).kind == tkIndent: + if currInd(p) == currentTok(p).ival: + inc p.idx + elif currentTok(p).ival > currInd(p): + pushInd(p, currentTok(p).ival) var a = newRstNode(rnBlockQuote) parseSection(p, a) - add(result, a) + result.add(a) popInd(p) else: leave = true break - if leave or p.tok[p.idx].kind == tkEof: break + if leave or currentTok(p).kind == tkEof: break var a: PRstNode = nil var k = whichSection(p) case k of rnLiteralBlock: - inc(p.idx) # skip '::' + inc p.idx # skip '::' a = parseLiteralBlock(p) of rnBulletList: a = parseBulletList(p) of rnLineBlock: a = parseLineBlock(p) @@ -1527,7 +1475,7 @@ proc parseSection(p: var RstParser, result: PRstNode) = of rnParagraph: discard of rnDefList: a = parseDefinitionList(p) of rnFieldList: - if p.idx > 0: dec(p.idx) + if p.idx > 0: dec p.idx a = parseFields(p) of rnTransition: a = parseTransition(p) of rnHeadline: a = parseHeadline(p) @@ -1541,14 +1489,14 @@ proc parseSection(p: var RstParser, result: PRstNode) = if a == nil and k != rnDirective: a = newRstNode(rnParagraph) parseParagraph(p, a) - addIfNotNil(result, a) + result.addIfNotNil(a) if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph: result.sons[0].kind = rnInner proc parseSectionWrapper(p: var RstParser): PRstNode = result = newRstNode(rnInner) parseSection(p, result) - while (result.kind == rnInner) and (len(result) == 1): + while result.kind == rnInner and result.len == 1: result = result.sons[0] proc `$`(t: Token): string = @@ -1556,15 +1504,7 @@ proc `$`(t: Token): string = proc parseDoc(p: var RstParser): PRstNode = result = parseSectionWrapper(p) - if p.tok[p.idx].kind != tkEof: - when false: - assert isAllocatedPtr(cast[pointer](p.tok)) - for i in 0 .. high(p.tok): - assert isNil(p.tok[i].symbol) or - isAllocatedPtr(cast[pointer](p.tok[i].symbol)) - echo "index: ", p.idx, " length: ", high(p.tok), "##", - p.tok[p.idx-1], p.tok[p.idx], p.tok[p.idx+1] - #assert isAllocatedPtr(cast[pointer](p.indentStack)) + if currentTok(p).kind != tkEof: rstMessage(p, meGeneralParseError) type @@ -1590,29 +1530,29 @@ proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode = args = newRstNode(rnDirArg) if argIsFile in flags: while true: - case p.tok[p.idx].kind + case currentTok(p).kind of tkWord, tkOther, tkPunct, tkAdornment: - add(args, newLeaf(p)) - inc(p.idx) + args.add(newLeaf(p)) + inc p.idx else: break elif argIsWord in flags: - while p.tok[p.idx].kind == tkWhite: inc(p.idx) - if p.tok[p.idx].kind == tkWord: - add(args, newLeaf(p)) - inc(p.idx) + while currentTok(p).kind == tkWhite: inc p.idx + if currentTok(p).kind == tkWord: + args.add(newLeaf(p)) + inc p.idx else: args = nil else: parseLine(p, args) - add(result, args) + result.add(args) if hasOptions in flags: - if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and - (p.tok[p.idx + 1].symbol == ":"): + if currentTok(p).kind == tkIndent and currentTok(p).ival >= 3 and + nextTok(p).symbol == ":": options = parseFields(p) - add(result, options) + result.add(options) proc indFollows(p: RstParser): bool = - result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p) + result = currentTok(p).kind == tkIndent and currentTok(p).ival > currInd(p) proc parseDirective(p: var RstParser, flags: DirFlags, contentParser: SectionParser): PRstNode = @@ -1621,16 +1561,16 @@ proc parseDirective(p: var RstParser, flags: DirFlags, ## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil. result = parseDirective(p, flags) if not isNil(contentParser) and indFollows(p): - pushInd(p, p.tok[p.idx].ival) + pushInd(p, currentTok(p).ival) var content = contentParser(p) popInd(p) - add(result, content) + result.add(content) else: - add(result, PRstNode(nil)) + result.add(PRstNode(nil)) proc parseDirBody(p: var RstParser, contentParser: SectionParser): PRstNode = if indFollows(p): - pushInd(p, p.tok[p.idx].ival) + pushInd(p, currentTok(p).ival) result = contentParser(p) popInd(p) @@ -1666,7 +1606,7 @@ proc dirInclude(p: var RstParser): PRstNode = # XXX: error handling; recursive file inclusion! if getFieldValue(n, "literal") != "": result = newRstNode(rnLiteralBlock) - add(result, newRstNode(rnLeaf, readFile(path))) + result.add(newRstNode(rnLeaf, readFile(path))) else: let inputString = readFile(path).string() let startPosition = @@ -1674,7 +1614,7 @@ proc dirInclude(p: var RstParser): PRstNode = let searchFor = n.getFieldValue("start-after").strip() if searchFor != "": let pos = inputString.find(searchFor) - if pos != -1: pos + searchFor.len() + if pos != -1: pos + searchFor.len else: 0 else: 0 @@ -1724,7 +1664,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = var path = p.findRelativeFile(filename) if path == "": rstMessage(p, meCannotOpenFile, filename) var n = newRstNode(rnLiteralBlock) - add(n, newRstNode(rnLeaf, readFile(path))) + n.add(newRstNode(rnLeaf, readFile(path))) result.sons[2] = n # Extend the field block if we are using our custom extension. @@ -1745,7 +1685,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = proc dirContainer(p: var RstParser): PRstNode = result = parseDirective(p, {hasArg}, parseSectionWrapper) assert(result.kind == rnDirective) - assert(len(result) == 3) + assert(result.len == 3) result.kind = rnContainer proc dirImage(p: var RstParser): PRstNode = @@ -1779,10 +1719,10 @@ proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind, else: var f = readFile(path) result = newRstNode(kind) - add(result, newRstNode(rnLeaf, f)) + result.add(newRstNode(rnLeaf, f)) else: result.kind = kind - add(result, parseDirBody(p, contentParser)) + result.add(parseDirBody(p, contentParser)) proc dirRaw(p: var RstParser): PRstNode = # @@ -1806,8 +1746,8 @@ proc dirRaw(p: var RstParser): PRstNode = proc parseDotDot(p: var RstParser): PRstNode = result = nil - var col = p.tok[p.idx].col - inc(p.idx) + var col = currentTok(p).col + inc p.idx var d = getDirective(p) if d != "": pushInd(p, col) @@ -1830,32 +1770,32 @@ proc parseDotDot(p: var RstParser): PRstNode = popInd(p) elif match(p, p.idx, " _"): # hyperlink target: - inc(p.idx, 2) + inc p.idx, 2 var a = getReferenceName(p, ":") - if p.tok[p.idx].kind == tkWhite: inc(p.idx) + if currentTok(p).kind == tkWhite: inc p.idx var b = untilEol(p) setRef(p, rstnodeToRefname(a), b) elif match(p, p.idx, " |"): # substitution definitions: - inc(p.idx, 2) + inc p.idx, 2 var a = getReferenceName(p, "|") var b: PRstNode - if p.tok[p.idx].kind == tkWhite: inc(p.idx) - if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0: - inc(p.idx) + if currentTok(p).kind == tkWhite: inc p.idx + if cmpIgnoreStyle(currentTok(p).symbol, "replace") == 0: + inc p.idx expect(p, "::") b = untilEol(p) - elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0: - inc(p.idx) + elif cmpIgnoreStyle(currentTok(p).symbol, "image") == 0: + inc p.idx b = dirImage(p) else: - rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol) + rstMessage(p, meInvalidDirective, currentTok(p).symbol) setSub(p, addNodes(a), b) elif match(p, p.idx, " ["): # footnotes, citations - inc(p.idx, 2) + inc p.idx, 2 var a = getReferenceName(p, "]") - if p.tok[p.idx].kind == tkWhite: inc(p.idx) + if currentTok(p).kind == tkWhite: inc p.idx var b = untilEol(p) setRef(p, rstnodeToRefname(a), b) else: @@ -1879,14 +1819,14 @@ proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = if y != nil: result = newRstNode(rnHyperlink) n.kind = rnInner - add(result, n) - add(result, y) + result.add(n) + result.add(y) of rnLeaf: discard of rnContents: p.hasToc = true else: - for i in countup(0, len(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i]) + for i in 0 ..< n.len: n.sons[i] = resolveSubs(p, n.sons[i]) proc rstParse*(text, filename: string, line, column: int, hasToc: var bool, From 7d51ad96e9add19c45b3c679f30fcb70d7fbe138 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 13 Nov 2020 18:57:56 +0800 Subject: [PATCH 1465/4254] close #2771(add testcase for #2771) (#15932) --- tests/iter/t2771.nim | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/iter/t2771.nim diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim new file mode 100644 index 000000000..49befb0a9 --- /dev/null +++ b/tests/iter/t2771.nim @@ -0,0 +1,21 @@ +template t1(i: int): int= + i+1 +template t2(i: int): int= + i+1 + +doAssert t1(10).t2() == 12 + + +template it1(i: int): iterator(): int = + iterator result(): int {.closure, gensym.} = + yield i+1 + result + +template it2(iter: iterator(): int): iterator(): int = + iterator result(): int {.closure, gensym.} = + yield iter()+1 + result + +let x2 = it1(10).it2() + +doAssert x2() == 12 From d802a4a669aa8661b4ba80abbd9310b93b9fe605 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 13 Nov 2020 19:49:30 +0800 Subject: [PATCH 1466/4254] close #13062(add testcase for #13062) (#15956) --- tests/ccgbugs/t13062.nim | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/ccgbugs/t13062.nim diff --git a/tests/ccgbugs/t13062.nim b/tests/ccgbugs/t13062.nim new file mode 100644 index 000000000..fed32a1f7 --- /dev/null +++ b/tests/ccgbugs/t13062.nim @@ -0,0 +1,27 @@ +discard """ + output: "[p = nil]" + targets: "c cpp" +""" + +import atomics + +type + Pledge* {.exportc.} = object + p: PledgePtr + + PledgeKind {.exportc.} = enum + Single + Iteration + + PledgePtr {.exportc.} = ptr object + case kind: PledgeKind + of Single: + impl: PledgeImpl + of Iteration: + discard + + PledgeImpl {.exportc.} = object + fulfilled: Atomic[bool] + +var x: Pledge +echo x.repr From 8778d4a6f36fee5a4c31f6f8f355b8607f2a592c Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 13 Nov 2020 13:03:14 +0100 Subject: [PATCH 1467/4254] attempt to make asynchttpserver better; fixes #15925; [backport:1.0] --- changelog.md | 6 ++ lib/pure/asyncdispatch.nim | 22 ++++ lib/pure/asynchttpserver.nim | 125 +++++++++++++++------- lib/pure/ioselects/ioselectors_epoll.nim | 4 +- lib/pure/ioselects/ioselectors_kqueue.nim | 8 +- lib/pure/ioselects/ioselectors_poll.nim | 4 +- lib/pure/ioselects/ioselectors_select.nim | 4 +- 7 files changed, 123 insertions(+), 50 deletions(-) diff --git a/changelog.md b/changelog.md index 11930cf92..e50be6de3 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,12 @@ - `doAssertRaises` now correctly handles foreign exceptions. +- Added `asyncdispatch.activeDescriptors` that returns the number of currently + active async event handles/file descriptors +- Added `asyncdispatch.maxDescriptors` that returns the maximum number of + active async event handles/file descriptors. + + ## Language changes - `nimscript` now handles `except Exception as e` diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index d8b274c34..0afc60864 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1934,3 +1934,25 @@ proc waitFor*[T](fut: Future[T]): T = poll() fut.read + +proc activeDescriptors*(): int {.inline.} = + ## Returns the current number of active file descriptors for the current + ## event loop. This is a cheap operation that does not involve a system call. + when defined(windows): + result = getGlobalDispatcher().handles.len + else: + result = getGlobalDispatcher().selector.count + +when defined(posix): + import posix + +proc maxDescriptors*(): int {.raises: OSError.} = + ## Returns the maximum number of active file descriptors for the current + ## process. This involves a system call. + when defined(windows): + result = 16_700_000 + else: + var fdLim: RLimit + if getrlimit(RLIMIT_NOFILE, fdLim) < 0: + raiseOSError(osLastError()) + result = int(fdLim.rlim_cur) - 1 diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index ec7f2a0de..74b7d17b3 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -7,28 +7,44 @@ # distribution, for details about the copyright. # -## This module implements a high performance asynchronous HTTP server. -## -## This HTTP server has not been designed to be used in production, but -## for testing applications locally. Because of this, when deploying your -## application in production you should use a reverse proxy (for example nginx) -## instead of allowing users to connect directly to this server. -## -## Basic usage -## =========== -## -## This example will create an HTTP server on port 8080. The server will -## respond to all requests with a ``200 OK`` response code and "Hello World" -## as the response body. -## -## .. code-block::nim -## import asynchttpserver, asyncdispatch -## -## var server = newAsyncHttpServer() -## proc cb(req: Request) {.async.} = -## await req.respond(Http200, "Hello World") -## -## waitFor server.serve(Port(8080), cb) +##[ This module implements a high performance asynchronous HTTP server. + +This HTTP server has not been designed to be used in production, but +for testing applications locally. Because of this, when deploying your +application in production you should use a reverse proxy (for example nginx) +instead of allowing users to connect directly to this server. + +Basic usage +=========== + +This example will create an HTTP server on port 8080. The server will +respond to all requests with a ``200 OK`` response code and "Hello World" +as the response body. + +.. code-block::nim + import asynchttpserver, asyncdispatch + + proc main {.async.} = + var server = newAsyncHttpServer() + proc cb(req: Request) {.async.} = + #echo(req.reqMethod, " ", req.url) + #echo(req.headers) + let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", + "Content-type": "text/plain; charset=utf-8"} + await req.respond(Http200, "Hello World", headers.newHttpHeaders()) + + server.listen Port(5555) + while true: + if server.shouldAcceptRequest(5): + var (address, client) = await server.socket.acceptAddr() + asyncCheck processClient(server, client, address, cb) + else: + poll() + + asyncCheck main() + runForever() + +]## import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore @@ -58,14 +74,12 @@ type reuseAddr: bool reusePort: bool maxBody: int ## The maximum content-length that will be read for the body. + maxFDs: int proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = ## Creates a new ``AsyncHttpServer`` instance. - new result - result.reuseAddr = reuseAddr - result.reusePort = reusePort - result.maxBody = maxBody + result = AsyncHttpServer(reuseAddr: reuseAddr, reusePort: reusePort, maxBody: maxBody) proc addHeaders(msg: var string, headers: HttpHeaders) = for k, v in headers: @@ -279,7 +293,7 @@ proc processRequest( request.client.close() return false -proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string, +proc processClient*(server: AsyncHttpServer, client: AsyncSocket, address: string, callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = var request = newFutureVar[Request]("asynchttpserver.processClient") @@ -294,13 +308,8 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string ) if not retry: break -proc serve*(server: AsyncHttpServer, port: Port, - callback: proc (request: Request): Future[void] {.closure, gcsafe.}, - address = "") {.async.} = - ## Starts the process of listening for incoming HTTP connections on the - ## specified address and port. - ## - ## When a request is made by a client the specified callback will be called. +proc listen*(server: AsyncHttpServer; port: Port; address = "") = + server.maxFDs = maxDescriptors() server.socket = newAsyncSocket() if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) @@ -309,9 +318,38 @@ proc serve*(server: AsyncHttpServer, port: Port, server.socket.bindAddr(port, address) server.socket.listen() +proc shouldAcceptRequest*(server: AsyncHttpServer; + assumedDescriptorsPerRequest = 5): bool {.inline.} = + ## Returns true if the process's current number of opened file + ## descriptors is still within the maximum limit and so it's reasonable to + ## accept yet another request. + result = assumedDescriptorsPerRequest < 0 or + (activeDescriptors() + assumedDescriptorsPerRequest < server.maxFDs) + +proc acceptRequest*(server: AsyncHttpServer, port: Port, + callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = + ## Accepts a single request. + var (address, client) = await server.socket.acceptAddr() + asyncCheck processClient(server, client, address, callback) + +proc serve*(server: AsyncHttpServer, port: Port, + callback: proc (request: Request): Future[void] {.closure, gcsafe.}, + address = ""; + assumedDescriptorsPerRequest = 5) {.async.} = + ## Starts the process of listening for incoming HTTP connections on the + ## specified address and port. + ## + ## When a request is made by a client the specified callback will be called. + ## + ## If `flowControl` is true the server cares about the process's maximum + ## file descriptor limit. + listen server, port, address while true: - var (address, client) = await server.socket.acceptAddr() - asyncCheck processClient(server, client, address, callback) + if shouldAcceptRequest(server, assumedDescriptorsPerRequest): + var (address, client) = await server.socket.acceptAddr() + asyncCheck processClient(server, client, address, callback) + else: + poll() #echo(f.isNil) #echo(f.repr) @@ -320,7 +358,7 @@ proc close*(server: AsyncHttpServer) = server.socket.close() when not defined(testing) and isMainModule: - proc main = + proc main {.async.} = var server = newAsyncHttpServer() proc cb(req: Request) {.async.} = #echo(req.reqMethod, " ", req.url) @@ -329,6 +367,13 @@ when not defined(testing) and isMainModule: "Content-type": "text/plain; charset=utf-8"} await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - asyncCheck server.serve(Port(5555), cb) - runForever() - main() + server.listen Port(5555) + while true: + if server.shouldAcceptRequest(5): + var (address, client) = await server.socket.acceptAddr() + asyncCheck processClient(server, client, address, cb) + else: + poll() + + asyncCheck main() + runForever() diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 3dcf547bd..b62b4c2db 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -55,7 +55,7 @@ when hasThreadSupport: maxFD: int numFD: int fds: ptr SharedArray[SelectorKey[T]] - count: int + count*: int Selector*[T] = ptr SelectorImpl[T] else: type @@ -64,7 +64,7 @@ else: maxFD: int numFD: int fds: seq[SelectorKey[T]] - count: int + count*: int Selector*[T] = ref SelectorImpl[T] type SelectEventImpl = object diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index a65be9842..68be969c7 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -30,7 +30,7 @@ when defined(macosx) or defined(freebsd) or defined(dragonfly): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include - #include """} + #include """.} elif defined(netbsd) or defined(openbsd): # OpenBSD and NetBSD don't have KERN_MAXFILESPERPROC, so we are using # KERN_MAXFILES, because KERN_MAXFILES is always bigger, @@ -39,7 +39,7 @@ elif defined(netbsd) or defined(openbsd): proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include - #include """} + #include """.} when hasThreadSupport: type @@ -48,7 +48,7 @@ when hasThreadSupport: maxFD: int changes: ptr SharedArray[KEvent] fds: ptr SharedArray[SelectorKey[T]] - count: int + count*: int changesLock: Lock changesSize: int changesLength: int @@ -61,7 +61,7 @@ else: maxFD: int changes: seq[KEvent] fds: seq[SelectorKey[T]] - count: int + count*: int sock: cint Selector*[T] = ref SelectorImpl[T] diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 1af2a46db..00e2f3fe9 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -21,7 +21,7 @@ when hasThreadSupport: pollcnt: int fds: ptr SharedArray[SelectorKey[T]] pollfds: ptr SharedArray[TPollFd] - count: int + count*: int lock: Lock Selector*[T] = ptr SelectorImpl[T] else: @@ -31,7 +31,7 @@ else: pollcnt: int fds: seq[SelectorKey[T]] pollfds: seq[TPollFd] - count: int + count*: int Selector*[T] = ref SelectorImpl[T] type diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index eed64a34d..2fd9ac0ba 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -58,7 +58,7 @@ when hasThreadSupport: eSet: FdSet maxFD: int fds: ptr SharedArray[SelectorKey[T]] - count: int + count*: int lock: Lock Selector*[T] = ptr SelectorImpl[T] else: @@ -69,7 +69,7 @@ else: eSet: FdSet maxFD: int fds: seq[SelectorKey[T]] - count: int + count*: int Selector*[T] = ref SelectorImpl[T] type From cb19dc53ca49a237770271a3559772cc545e747f Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 13 Nov 2020 13:07:48 +0100 Subject: [PATCH 1468/4254] better documentation --- lib/pure/asynchttpserver.nim | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 74b7d17b3..b69f3f9a4 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -293,7 +293,7 @@ proc processRequest( request.client.close() return false -proc processClient*(server: AsyncHttpServer, client: AsyncSocket, address: string, +proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string, callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = var request = newFutureVar[Request]("asynchttpserver.processClient") @@ -309,6 +309,7 @@ proc processClient*(server: AsyncHttpServer, client: AsyncSocket, address: strin if not retry: break proc listen*(server: AsyncHttpServer; port: Port; address = "") = + ## Listen to the given port and address. server.maxFDs = maxDescriptors() server.socket = newAsyncSocket() if server.reuseAddr: @@ -328,7 +329,8 @@ proc shouldAcceptRequest*(server: AsyncHttpServer; proc acceptRequest*(server: AsyncHttpServer, port: Port, callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = - ## Accepts a single request. + ## Accepts a single request. Write an explicit loop around this proc so that + ## errors can be handled properly. var (address, client) = await server.socket.acceptAddr() asyncCheck processClient(server, client, address, callback) @@ -341,8 +343,13 @@ proc serve*(server: AsyncHttpServer, port: Port, ## ## When a request is made by a client the specified callback will be called. ## - ## If `flowControl` is true the server cares about the process's maximum - ## file descriptor limit. + ## If `assumedDescriptorsPerRequest` is 0 or greater the server cares about + ## the process's maximum file descriptor limit. It then ensures that the + ## process still has the resources for `assumedDescriptorsPerRequest` + ## file descriptors before accepting a connection. + ## + ## You should prefer to call `acceptRequest` instead with a custom server + ## loop so that you're in control over the error handling and logging. listen server, port, address while true: if shouldAcceptRequest(server, assumedDescriptorsPerRequest): From 797cb2e67b084f28474cc5d4251e57275c1e8f5f Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 13 Nov 2020 20:44:48 +0800 Subject: [PATCH 1469/4254] Fix #8404 JS backend doesn't handle float->int type conversion (#15950) [backport] * Fix #8404 JS backend doesn't handle float->int type conversion * handle conv to uint as cast, discard other cases * limit to int32, times use int64 * toInt including tyInt64 break times timezones lib, ignore for now * also affect to vm * move to tests/misc/t8404.nim --- compiler/jsgen.nim | 12 +++++++++--- tests/misc/t8404.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 tests/misc/t8404.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 357e18000..34ebd306a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2208,11 +2208,17 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) = if dest.kind == src.kind: # no-op conversion return - case dest.kind: - of tyBool: + let toInt = (dest.kind in tyInt..tyInt32) + let fromInt = (src.kind in tyInt..tyInt32) + let toUint = (dest.kind in tyUInt..tyUInt32) + let fromUint = (src.kind in tyUInt..tyUInt32) + if toUint and (fromInt or fromUint): + let trimmer = unsignedTrimmer(dest.size) + r.res = "($1 $2)" % [r.res, trimmer] + elif dest.kind == tyBool: r.res = "(!!($1))" % [r.res] r.kind = resExpr - of tyInt: + elif toInt: r.res = "(($1)|0)" % [r.res] else: # TODO: What types must we handle here? diff --git a/tests/misc/t8404.nim b/tests/misc/t8404.nim new file mode 100644 index 000000000..87991071c --- /dev/null +++ b/tests/misc/t8404.nim @@ -0,0 +1,33 @@ +discard """ + targets: "c cpp js" +""" +template main() = + block: # bug #8404 + # can conv + template float2int(T) = + var a = -1.0 + let b = T(a) + doAssert b < 0 + let c = b + 1 + doAssert c is T + doAssert c == 0 + + float2int(int8) + float2int(int16) + float2int(int32) + float2int(int64) + + block: + # can handle middle conv + # `/` can trigger int to float + template float2int(T) = + let n = T(1 / 256) + doAssert n == 0 + + float2int(int8) + float2int(int16) + float2int(int32) + # float2int(int64) +main() +static: + main() From 19d52033f885a686f39b3f1b52564246b0fade83 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 13 Nov 2020 13:50:57 +0100 Subject: [PATCH 1470/4254] fixes 'nim doc' --- lib/pure/asyncdispatch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 0afc60864..0bacf3bb5 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1940,7 +1940,7 @@ proc activeDescriptors*(): int {.inline.} = ## event loop. This is a cheap operation that does not involve a system call. when defined(windows): result = getGlobalDispatcher().handles.len - else: + elif not defined(nimdoc): result = getGlobalDispatcher().selector.count when defined(posix): From a9bd4c4e80a73fde73ae4a976d1ee4d65a4a3a66 Mon Sep 17 00:00:00 2001 From: c-blake Date: Fri, 13 Nov 2020 08:04:40 -0500 Subject: [PATCH 1471/4254] Alternate to https://github.com/nim-lang/Nim/pull/15915 (#15937) * Alternate PR to https://github.com/nim-lang/Nim/pull/15915 to resolve the problem mentioned there (`hash() == 0`) as well as to close https://github.com/nim-lang/Nim/issues/15624 * Address https://github.com/nim-lang/Nim/pull/15937#discussion_r522759669 { though this was only a move from 2 copies to 3 copies. ;-) } --- lib/pure/hashes.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 1024ce26f..3191d4030 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -113,8 +113,12 @@ proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} = const P0 = 0xa0761d6478bd642f'u64 const P1 = 0xe7037ed1a0b428db'u64 const P58 = 0xeb44accab455d165'u64 xor 8'u64 + template h(x): untyped = hiXorLo(hiXorLo(P0, uint64(x) xor P1), P58) when nimvm: - cast[Hash](hiXorLo(hiXorLo(P0, uint64(x) xor P1), P58)) + when defined(js): # Nim int64<->JS Number & VM match => JS gets 32-bit hash + result = cast[Hash](h(x)) and cast[Hash](0xFFFFFFFF) + else: + result = cast[Hash](h(x)) else: when defined(js): asm """ @@ -132,8 +136,9 @@ proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} = var res = hi_xor_lo_js(hi_xor_lo_js(P0, BigInt(`x`) ^ P1), P58); `result` = Number(res & ((BigInt(1) << BigInt(53)) - BigInt(1))); }""" + result = result and cast[Hash](0xFFFFFFFF) else: - cast[Hash](hiXorLo(hiXorLo(P0, uint64(x) xor P1), P58)) + result = cast[Hash](h(x)) proc hashData*(data: pointer, size: int): Hash = ## Hashes an array of bytes of size `size`. From c39fa0d49535da7f803d9972abdb15d09eed92a6 Mon Sep 17 00:00:00 2001 From: landerlo Date: Fri, 13 Nov 2020 13:12:51 +0000 Subject: [PATCH 1472/4254] Make IntSet a generic ordinal set OrdSet[A] (#15564) * Make IntSet an ordinal set OrdSet[A: Ordinal] Backward compatibility with IntSet is maintained. IntSet is an alias for OrdSet[int] * move ordsets to new file, intsets exports it * ordset, move to lib/std folder * Fix `$` for ordsets and test cleanup * Fix ordsets compilation in doc example * Rename ordsets to packedsets --- lib/pure/collections/intsets.nim | 694 +------------------------------ lib/std/packedsets.nim | 607 +++++++++++++++++++++++++++ tests/stdlib/tintsets.nim | 65 --- tests/stdlib/tpackedsets.nim | 259 ++++++++++++ 4 files changed, 873 insertions(+), 752 deletions(-) create mode 100644 lib/std/packedsets.nim delete mode 100644 tests/stdlib/tintsets.nim create mode 100644 tests/stdlib/tpackedsets.nim diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 3be453e29..e4c216d08 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -7,698 +7,18 @@ # distribution, for details about the copyright. # -## The ``intsets`` module implements an efficient `int` set implemented as a -## `sparse bit set`:idx:. -## -## **Note**: Currently the assignment operator ``=`` for ``IntSet`` -## performs some rather meaningless shallow copy. Since Nim currently does -## not allow the assignment operator to be overloaded, use `assign proc -## <#assign,IntSet,IntSet>`_ to get a deep copy. -## +## Deprecated by the generic `PackedSet` for ordinal sparse sets. ## **See also:** -## * `sets module `_ for more general hash sets +## * `Ordinal packed sets module `_ for more general packed sets import std/private/since -import hashes +import std/packedsets +export packedsets type - BitScalar = uint + IntSet* = PackedSet[int] -const - InitIntSetSize = 8 # must be a power of two! - TrunkShift = 9 - BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and - # divisible by 64 - TrunkMask = BitsPerTrunk - 1 - IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8) - IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width - IntMask = 1 shl IntShift - 1 +proc toIntSet*(x: openArray[int]): IntSet {.since: (1, 3), inline.} = toPackedSet[int](x) -type - PTrunk = ref Trunk - Trunk = object - next: PTrunk # all nodes are connected with this pointer - key: int # start address at bit 0 - bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector +proc initIntSet*(): IntSet {.inline.} = initPackedSet[int]() - TrunkSeq = seq[PTrunk] - IntSet* = object ## An efficient set of `int` implemented as a sparse bit set. - elems: int # only valid for small numbers - counter, max: int - head: PTrunk - data: TrunkSeq - a: array[0..33, int] # profiling shows that 34 elements are enough - -proc mustRehash[T](t: T): bool {.inline.} = - let length = t.max + 1 - assert length > t.counter - result = (length * 2 < t.counter * 3) or (length - t.counter < 4) - -proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} = - const PERTURB_SHIFT = 5 - var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT - perturb = cast[Hash](perturb2) - result = ((5*h) + 1 + perturb) and maxHash - -proc intSetGet(t: IntSet, key: int): PTrunk = - var h = key and t.max - var perturb = key - while t.data[h] != nil: - if t.data[h].key == key: - return t.data[h] - h = nextTry(h, t.max, perturb) - result = nil - -proc intSetRawInsert(t: IntSet, data: var TrunkSeq, desc: PTrunk) = - var h = desc.key and t.max - var perturb = desc.key - while data[h] != nil: - assert(data[h] != desc) - h = nextTry(h, t.max, perturb) - assert(data[h] == nil) - data[h] = desc - -proc intSetEnlarge(t: var IntSet) = - var n: TrunkSeq - var oldMax = t.max - t.max = ((t.max + 1) * 2) - 1 - newSeq(n, t.max + 1) - for i in countup(0, oldMax): - if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) - swap(t.data, n) - -proc intSetPut(t: var IntSet, key: int): PTrunk = - var h = key and t.max - var perturb = key - while t.data[h] != nil: - if t.data[h].key == key: - return t.data[h] - h = nextTry(h, t.max, perturb) - if mustRehash(t): intSetEnlarge(t) - inc(t.counter) - h = key and t.max - perturb = key - while t.data[h] != nil: h = nextTry(h, t.max, perturb) - assert(t.data[h] == nil) - new(result) - result.next = t.head - result.key = key - t.head = result - t.data[h] = result - -proc bitincl(s: var IntSet, key: int) {.inline.} = - var ret: PTrunk - var t = intSetPut(s, `shr`(key, TrunkShift)) - var u = key and TrunkMask - t.bits[u shr IntShift] = t.bits[u shr IntShift] or - (BitScalar(1) shl (u and IntMask)) - -proc exclImpl(s: var IntSet, key: int) = - if s.elems <= s.a.len: - for i in 0.. 1: result.add(", ") - result.add($key) - result.add("}") - - -iterator items*(s: IntSet): int {.inline.} = - ## Iterates over any included element of `s`. - if s.elems <= s.a.len: - for i in 0..`_ - runnableExamples: - var a = initIntSet() - assert len(a) == 0 - - # newSeq(result.data, InitIntSetSize) - # result.max = InitIntSetSize-1 - result = IntSet( - elems: 0, - counter: 0, - max: 0, - head: nil, - data: when defined(nimNoNilSeqs): @[] else: nil) - # a: array[0..33, int] # profiling shows that 34 elements are enough - -proc contains*(s: IntSet, key: int): bool = - ## Returns true if `key` is in `s`. - ## - ## This allows the usage of `in` operator. - runnableExamples: - var a = initIntSet() - for x in [1, 3, 5]: - a.incl(x) - assert a.contains(3) - assert 3 in a - assert(not a.contains(8)) - assert 8 notin a - - if s.elems <= s.a.len: - for i in 0..`_ for excluding an element - ## * `incl proc <#incl,IntSet,IntSet>`_ for including other set - ## * `containsOrIncl proc <#containsOrIncl,IntSet,int>`_ - runnableExamples: - var a = initIntSet() - a.incl(3) - a.incl(3) - assert len(a) == 1 - - if s.elems <= s.a.len: - for i in 0..`_. - ## - ## See also: - ## * `excl proc <#excl,IntSet,IntSet>`_ for excluding other set - ## * `incl proc <#incl,IntSet,int>`_ for including an element - ## * `containsOrIncl proc <#containsOrIncl,IntSet,int>`_ - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1) - b.incl(5) - a.incl(b) - assert len(a) == 2 - assert 5 in a - - for item in other: incl(s, item) - -proc toIntSet*(x: openArray[int]): IntSet {.since: (1, 3).} = - ## Creates a new IntSet that contains the elements of `x`. - ## - ## Duplicates are removed. - ## - ## See also: - ## * `initIntSet proc <#initIntSet>`_ - runnableExamples: - var - a = toIntSet([5, 6, 7]) - b = toIntSet(@[1, 8, 8, 8]) - assert len(a) == 3 - assert len(b) == 2 - - result = initIntSet() - for item in items(x): - result.incl(item) - -proc containsOrIncl*(s: var IntSet, key: int): bool = - ## Includes `key` in the set `s` and tells if `key` was already in `s`. - ## - ## The difference with regards to the `incl proc <#incl,IntSet,int>`_ is - ## that this proc returns `true` if `s` already contained `key`. The - ## proc will return `false` if `key` was added as a new value to `s` during - ## this call. - ## - ## See also: - ## * `incl proc <#incl,IntSet,int>`_ for including an element - ## * `missingOrExcl proc <#missingOrExcl,IntSet,int>`_ - runnableExamples: - var a = initIntSet() - assert a.containsOrIncl(3) == false - assert a.containsOrIncl(3) == true - assert a.containsOrIncl(4) == false - - if s.elems <= s.a.len: - for i in 0..`_ for including an element - ## * `excl proc <#excl,IntSet,IntSet>`_ for excluding other set - ## * `missingOrExcl proc <#missingOrExcl,IntSet,int>`_ - runnableExamples: - var a = initIntSet() - a.incl(3) - a.excl(3) - a.excl(3) - a.excl(99) - assert len(a) == 0 - exclImpl(s, key) - -proc excl*(s: var IntSet, other: IntSet) = - ## Excludes all elements from `other` from `s`. - ## - ## This is the in-place version of `s - other <#-,IntSet,IntSet>`_. - ## - ## See also: - ## * `incl proc <#incl,IntSet,IntSet>`_ for including other set - ## * `excl proc <#excl,IntSet,int>`_ for excluding an element - ## * `missingOrExcl proc <#missingOrExcl,IntSet,int>`_ - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1) - a.incl(5) - b.incl(5) - a.excl(b) - assert len(a) == 1 - assert 5 notin a - - for item in other: excl(s, item) - -proc len*(s: IntSet): int {.inline.} = - ## Returns the number of elements in `s`. - if s.elems < s.a.len: - result = s.elems - else: - result = 0 - for _ in s: - inc(result) - -proc missingOrExcl*(s: var IntSet, key: int): bool = - ## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. - ## - ## The difference with regards to the `excl proc <#excl,IntSet,int>`_ is - ## that this proc returns `true` if `key` was missing from `s`. - ## The proc will return `false` if `key` was in `s` and it was removed - ## during this call. - ## - ## See also: - ## * `excl proc <#excl,IntSet,int>`_ for excluding an element - ## * `excl proc <#excl,IntSet,IntSet>`_ for excluding other set - ## * `containsOrIncl proc <#containsOrIncl,IntSet,int>`_ - runnableExamples: - var a = initIntSet() - a.incl(5) - assert a.missingOrExcl(5) == false - assert a.missingOrExcl(5) == true - - var count = s.len - exclImpl(s, key) - result = count == s.len - -proc clear*(result: var IntSet) = - ## Clears the IntSet back to an empty state. - runnableExamples: - var a = initIntSet() - a.incl(5) - a.incl(7) - clear(a) - assert len(a) == 0 - - # setLen(result.data, InitIntSetSize) - # for i in 0..InitIntSetSize-1: result.data[i] = nil - # result.max = InitIntSetSize-1 - when defined(nimNoNilSeqs): - result.data = @[] - else: - result.data = nil - result.max = 0 - result.counter = 0 - result.head = nil - result.elems = 0 - -proc isNil*(x: IntSet): bool {.inline.} = x.head.isNil and x.elems == 0 - -proc assign*(dest: var IntSet, src: IntSet) = - ## Copies `src` to `dest`. - ## `dest` does not need to be initialized by `initIntSet proc <#initIntSet>`_. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - b.incl(5) - b.incl(7) - a.assign(b) - assert len(a) == 2 - - if src.elems <= src.a.len: - when defined(nimNoNilSeqs): - dest.data = @[] - else: - dest.data = nil - dest.max = 0 - dest.counter = src.counter - dest.head = nil - dest.elems = src.elems - dest.a = src.a - else: - dest.counter = src.counter - dest.max = src.max - dest.elems = src.elems - newSeq(dest.data, src.data.len) - - var it = src.head - while it != nil: - var h = it.key and dest.max - var perturb = it.key - while dest.data[h] != nil: h = nextTry(h, dest.max, perturb) - assert(dest.data[h] == nil) - var n: PTrunk - new(n) - n.next = dest.head - n.key = it.key - n.bits = it.bits - dest.head = n - dest.data[h] = n - it = it.next - -proc union*(s1, s2: IntSet): IntSet = - ## Returns the union of the sets `s1` and `s2`. - ## - ## The same as `s1 + s2 <#+,IntSet,IntSet>`_. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1); a.incl(2); a.incl(3) - b.incl(3); b.incl(4); b.incl(5) - assert union(a, b).len == 5 - ## {1, 2, 3, 4, 5} - - result.assign(s1) - incl(result, s2) - -proc intersection*(s1, s2: IntSet): IntSet = - ## Returns the intersection of the sets `s1` and `s2`. - ## - ## The same as `s1 * s2 <#*,IntSet,IntSet>`_. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1); a.incl(2); a.incl(3) - b.incl(3); b.incl(4); b.incl(5) - assert intersection(a, b).len == 1 - ## {3} - - result = initIntSet() - for item in s1: - if contains(s2, item): - incl(result, item) - -proc difference*(s1, s2: IntSet): IntSet = - ## Returns the difference of the sets `s1` and `s2`. - ## - ## The same as `s1 - s2 <#-,IntSet,IntSet>`_. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1); a.incl(2); a.incl(3) - b.incl(3); b.incl(4); b.incl(5) - assert difference(a, b).len == 2 - ## {1, 2} - - result = initIntSet() - for item in s1: - if not contains(s2, item): - incl(result, item) - -proc symmetricDifference*(s1, s2: IntSet): IntSet = - ## Returns the symmetric difference of the sets `s1` and `s2`. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1); a.incl(2); a.incl(3) - b.incl(3); b.incl(4); b.incl(5) - assert symmetricDifference(a, b).len == 4 - ## {1, 2, 4, 5} - - result.assign(s1) - for item in s2: - if containsOrIncl(result, item): excl(result, item) - -proc `+`*(s1, s2: IntSet): IntSet {.inline.} = - ## Alias for `union(s1, s2) <#union,IntSet,IntSet>`_. - result = union(s1, s2) - -proc `*`*(s1, s2: IntSet): IntSet {.inline.} = - ## Alias for `intersection(s1, s2) <#intersection,IntSet,IntSet>`_. - result = intersection(s1, s2) - -proc `-`*(s1, s2: IntSet): IntSet {.inline.} = - ## Alias for `difference(s1, s2) <#difference,IntSet,IntSet>`_. - result = difference(s1, s2) - -proc disjoint*(s1, s2: IntSet): bool = - ## Returns true if the sets `s1` and `s2` have no items in common. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1); a.incl(2) - b.incl(2); b.incl(3) - assert disjoint(a, b) == false - b.excl(2) - assert disjoint(a, b) == true - - for item in s1: - if contains(s2, item): - return false - return true - -proc card*(s: IntSet): int {.inline.} = - ## Alias for `len() <#len,IntSet>`_. - result = s.len() - -proc `<=`*(s1, s2: IntSet): bool = - ## Returns true if `s1` is subset of `s2`. - ## - ## A subset `s1` has all of its elements in `s2`, and `s2` doesn't necessarily - ## have more elements than `s1`. That is, `s1` can be equal to `s2`. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1) - b.incl(1); b.incl(2) - assert a <= b - a.incl(2) - assert a <= b - a.incl(3) - assert(not (a <= b)) - - for item in s1: - if not s2.contains(item): - return false - return true - -proc `<`*(s1, s2: IntSet): bool = - ## Returns true if `s1` is proper subset of `s2`. - ## - ## A strict or proper subset `s1` has all of its elements in `s2`, but `s2` has - ## more elements than `s1`. - runnableExamples: - var - a = initIntSet() - b = initIntSet() - a.incl(1) - b.incl(1); b.incl(2) - assert a < b - a.incl(2) - assert(not (a < b)) - return s1 <= s2 and not (s2 <= s1) - -proc `==`*(s1, s2: IntSet): bool = - ## Returns true if both `s1` and `s2` have the same elements and set size. - return s1 <= s2 and s2 <= s1 - -proc `$`*(s: IntSet): string = - ## The `$` operator for int sets. - ## - ## Converts the set `s` to a string, mostly for logging and printing purposes. - dollarImpl() - - - -when isMainModule: - import sequtils, algorithm - - var x = initIntSet() - x.incl(1) - x.incl(2) - x.incl(7) - x.incl(1056) - - x.incl(1044) - x.excl(1044) - - assert x == [1, 2, 7, 1056].toIntSet - - assert x.containsOrIncl(888) == false - assert 888 in x - assert x.containsOrIncl(888) == true - - assert x.missingOrExcl(888) == false - assert 888 notin x - assert x.missingOrExcl(888) == true - - var xs = toSeq(items(x)) - xs.sort(cmp[int]) - assert xs == @[1, 2, 7, 1056] - - var y: IntSet - assign(y, x) - var ys = toSeq(items(y)) - ys.sort(cmp[int]) - assert ys == @[1, 2, 7, 1056] - - assert x == y - - var z: IntSet - for i in 0..1000: - incl z, i - assert z.len() == i+1 - for i in 0..1000: - assert z.contains(i) - - var w = initIntSet() - w.incl(1) - w.incl(4) - w.incl(50) - w.incl(1001) - w.incl(1056) - - var xuw = x.union(w) - var xuws = toSeq(items(xuw)) - xuws.sort(cmp[int]) - assert xuws == @[1, 2, 4, 7, 50, 1001, 1056] - - var xiw = x.intersection(w) - var xiws = toSeq(items(xiw)) - xiws.sort(cmp[int]) - assert xiws == @[1, 1056] - - var xdw = x.difference(w) - var xdws = toSeq(items(xdw)) - xdws.sort(cmp[int]) - assert xdws == @[2, 7] - - var xsw = x.symmetricDifference(w) - var xsws = toSeq(items(xsw)) - xsws.sort(cmp[int]) - assert xsws == @[2, 4, 7, 50, 1001] - - x.incl(w) - xs = toSeq(items(x)) - xs.sort(cmp[int]) - assert xs == @[1, 2, 4, 7, 50, 1001, 1056] - - assert w <= x - - assert w < x - - assert(not disjoint(w, x)) - - var u = initIntSet() - u.incl(3) - u.incl(5) - u.incl(500) - assert disjoint(u, x) - - var v = initIntSet() - v.incl(2) - v.incl(50) - - x.excl(v) - xs = toSeq(items(x)) - xs.sort(cmp[int]) - assert xs == @[1, 4, 7, 1001, 1056] - - proc bug12366 = - var - x = initIntSet() - y = initIntSet() - n = 3584 - - for i in 0..n: - x.incl(i) - y.incl(i) - - let z = symmetricDifference(x, y) - doAssert z.len == 0 - doAssert $z == "{}" - - bug12366() diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim new file mode 100644 index 000000000..20002d07f --- /dev/null +++ b/lib/std/packedsets.nim @@ -0,0 +1,607 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## The ``packedsets`` module implements an efficient `Ordinal`set implemented as a +## `sparse bit set`:idx:. +## +## Supports any Ordinal type. +## +## **Note**: Currently the assignment operator ``=`` for ``PackedSet[A]`` +## performs some rather meaningless shallow copy. Since Nim currently does +## not allow the assignment operator to be overloaded, use `assign proc +## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy. +## +## **See also:** +## * `sets module `_ for more general hash sets + +import std/private/since +import hashes + +type + BitScalar = uint + +const + InitIntSetSize = 8 # must be a power of two! + TrunkShift = 9 + BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and + # divisible by 64 + TrunkMask = BitsPerTrunk - 1 + IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8) + IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width + IntMask = 1 shl IntShift - 1 + +type + PTrunk = ref Trunk + Trunk = object + next: PTrunk # all nodes are connected with this pointer + key: int # start address at bit 0 + bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector + + TrunkSeq = seq[PTrunk] + + ## An efficient set of `Ordinal` types implemented as a sparse bit set. + PackedSet*[A: Ordinal] = object + elems: int # only valid for small numbers + counter, max: int + head: PTrunk + data: TrunkSeq + a: array[0..33, int] # profiling shows that 34 elements are enough + +proc mustRehash[T](t: T): bool {.inline.} = + let length = t.max + 1 + assert length > t.counter + result = (length * 2 < t.counter * 3) or (length - t.counter < 4) + +proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} = + const PERTURB_SHIFT = 5 + var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT + perturb = cast[Hash](perturb2) + result = ((5*h) + 1 + perturb) and maxHash + +proc packedSetGet[A](t: PackedSet[A], key: int): PTrunk = + var h = key and t.max + var perturb = key + while t.data[h] != nil: + if t.data[h].key == key: + return t.data[h] + h = nextTry(h, t.max, perturb) + result = nil + +proc intSetRawInsert[A](t: PackedSet[A], data: var TrunkSeq, desc: PTrunk) = + var h = desc.key and t.max + var perturb = desc.key + while data[h] != nil: + assert(data[h] != desc) + h = nextTry(h, t.max, perturb) + assert(data[h] == nil) + data[h] = desc + +proc intSetEnlarge[A](t: var PackedSet[A]) = + var n: TrunkSeq + var oldMax = t.max + t.max = ((t.max + 1) * 2) - 1 + newSeq(n, t.max + 1) + for i in countup(0, oldMax): + if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) + swap(t.data, n) + +proc intSetPut[A](t: var PackedSet[A], key: int): PTrunk = + var h = key and t.max + var perturb = key + while t.data[h] != nil: + if t.data[h].key == key: + return t.data[h] + h = nextTry(h, t.max, perturb) + if mustRehash(t): intSetEnlarge(t) + inc(t.counter) + h = key and t.max + perturb = key + while t.data[h] != nil: h = nextTry(h, t.max, perturb) + assert(t.data[h] == nil) + new(result) + result.next = t.head + result.key = key + t.head = result + t.data[h] = result + +proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} = + var ret: PTrunk + var t = intSetPut(s, `shr`(key, TrunkShift)) + var u = key and TrunkMask + t.bits[u shr IntShift] = t.bits[u shr IntShift] or + (BitScalar(1) shl (u and IntMask)) + +proc exclImpl[A](s: var PackedSet[A], key: int) = + if s.elems <= s.a.len: + for i in 0.. 1: result.add(", ") + result.add $key + result.add("}") + +iterator items*[A](s: PackedSet[A]): A {.inline.} = + ## Iterates over any included element of `s`. + if s.elems <= s.a.len: + for i in 0..`_ + runnableExamples: + var a = initPackedSet[int]() + assert len(a) == 0 + + type Id = distinct int + var ids = initPackedSet[Id]() + ids.incl(3.Id) + + result = PackedSet[A]( + elems: 0, + counter: 0, + max: 0, + head: nil, + data: when defined(nimNoNilSeqs): @[] else: nil) + # a: array[0..33, int] # profiling shows that 34 elements are enough + +proc contains*[A](s: PackedSet[A], key: A): bool = + ## Returns true if `key` is in `s`. + ## + ## This allows the usage of `in` operator. + runnableExamples: + type ABCD = enum A, B, C, D + + var a = initPackedSet[int]() + for x in [1, 3, 5]: + a.incl(x) + assert a.contains(3) + assert 3 in a + assert(not a.contains(8)) + assert 8 notin a + + var letters = initPackedSet[ABCD]() + for x in [A, C]: + letters.incl(x) + assert A in letters + assert C in letters + assert B notin letters + + if s.elems <= s.a.len: + for i in 0..`_ for excluding an element + ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including other set + ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ + runnableExamples: + var a = initPackedSet[int]() + a.incl(3) + a.incl(3) + assert len(a) == 1 + + if s.elems <= s.a.len: + for i in 0..`_. + ## + ## See also: + ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set + ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element + ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1) + b.incl(5) + a.incl(b) + assert len(a) == 2 + assert 5 in a + + for item in other: incl(s, item) + +proc toPackedSet*[A](x: openArray[A]): PackedSet[A] {.since: (1, 3).} = + ## Creates a new PackedSet[A] that contains the elements of `x`. + ## + ## Duplicates are removed. + ## + ## See also: + ## * `initPackedSet[A] proc <#initPackedSet[A]>`_ + runnableExamples: + var + a = toPackedSet([5, 6, 7]) + b = toPackedSet(@[1, 8, 8, 8]) + assert len(a) == 3 + assert len(b) == 2 + + result = initPackedSet[A]() + for item in x: + result.incl(item) + +proc containsOrIncl*[A](s: var PackedSet[A], key: A): bool = + ## Includes `key` in the set `s` and tells if `key` was already in `s`. + ## + ## The difference with regards to the `incl proc <#incl,PackedSet[A],A>`_ is + ## that this proc returns `true` if `s` already contained `key`. The + ## proc will return `false` if `key` was added as a new value to `s` during + ## this call. + ## + ## See also: + ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element + ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ + runnableExamples: + var a = initPackedSet[int]() + assert a.containsOrIncl(3) == false + assert a.containsOrIncl(3) == true + assert a.containsOrIncl(4) == false + + if s.elems <= s.a.len: + for i in 0..`_ for including an element + ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set + ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ + runnableExamples: + var a = initPackedSet[int]() + a.incl(3) + a.excl(3) + a.excl(3) + a.excl(99) + assert len(a) == 0 + exclImpl[A](s, cast[int](key)) + +proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) = + ## Excludes all elements from `other` from `s`. + ## + ## This is the in-place version of `s - other <#-,PackedSet[A],PackedSet[A]>`_. + ## + ## See also: + ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including other set + ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element + ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1) + a.incl(5) + b.incl(5) + a.excl(b) + assert len(a) == 1 + assert 5 notin a + + for item in other: + excl(s, item) + +proc len*[A](s: PackedSet[A]): int {.inline.} = + ## Returns the number of elements in `s`. + if s.elems < s.a.len: + result = s.elems + else: + result = 0 + for _ in s: + inc(result) + +proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool = + ## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. + ## + ## The difference with regards to the `excl proc <#excl,PackedSet[A],A>`_ is + ## that this proc returns `true` if `key` was missing from `s`. + ## The proc will return `false` if `key` was in `s` and it was removed + ## during this call. + ## + ## See also: + ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element + ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set + ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ + runnableExamples: + var a = initPackedSet[int]() + a.incl(5) + assert a.missingOrExcl(5) == false + assert a.missingOrExcl(5) == true + + var count = s.len + exclImpl(s, cast[int](key)) + result = count == s.len + +proc clear*[A](result: var PackedSet[A]) = + ## Clears the PackedSet[A] back to an empty state. + runnableExamples: + var a = initPackedSet[int]() + a.incl(5) + a.incl(7) + clear(a) + assert len(a) == 0 + + # setLen(result.data, InitIntSetSize) + # for i in 0..InitIntSetSize-1: result.data[i] = nil + # result.max = InitIntSetSize-1 + when defined(nimNoNilSeqs): + result.data = @[] + else: + result.data = nil + result.max = 0 + result.counter = 0 + result.head = nil + result.elems = 0 + +proc isNil*[A](x: PackedSet[A]): bool {.inline.} = x.head.isNil and x.elems == 0 + +proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = + ## Copies `src` to `dest`. + ## `dest` does not need to be initialized by `initPackedSet[A] proc <#initPackedSet[A]>`_. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + b.incl(5) + b.incl(7) + a.assign(b) + assert len(a) == 2 + + if src.elems <= src.a.len: + when defined(nimNoNilSeqs): + dest.data = @[] + else: + dest.data = nil + dest.max = 0 + dest.counter = src.counter + dest.head = nil + dest.elems = src.elems + dest.a = src.a + else: + dest.counter = src.counter + dest.max = src.max + dest.elems = src.elems + newSeq(dest.data, src.data.len) + + var it = src.head + while it != nil: + var h = it.key and dest.max + var perturb = it.key + while dest.data[h] != nil: h = nextTry(h, dest.max, perturb) + assert(dest.data[h] == nil) + var n: PTrunk + new(n) + n.next = dest.head + n.key = it.key + n.bits = it.bits + dest.head = n + dest.data[h] = n + it = it.next + +proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] = + ## Returns the union of the sets `s1` and `s2`. + ## + ## The same as `s1 + s2 <#+,PackedSet[A],PackedSet[A]>`_. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert union(a, b).len == 5 + ## {1, 2, 3, 4, 5} + + result.assign(s1) + incl(result, s2) + +proc intersection*[A](s1, s2: PackedSet[A]): PackedSet[A] = + ## Returns the intersection of the sets `s1` and `s2`. + ## + ## The same as `s1 * s2 <#*,PackedSet[A],PackedSet[A]>`_. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert intersection(a, b).len == 1 + ## {3} + + result = initPackedSet[A]() + for item in s1: + if contains(s2, item): + incl(result, item) + +proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] = + ## Returns the difference of the sets `s1` and `s2`. + ## + ## The same as `s1 - s2 <#-,PackedSet[A],PackedSet[A]>`_. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert difference(a, b).len == 2 + ## {1, 2} + + result = initPackedSet[A]() + for item in s1: + if not contains(s2, item): + incl(result, item) + +proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] = + ## Returns the symmetric difference of the sets `s1` and `s2`. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1); a.incl(2); a.incl(3) + b.incl(3); b.incl(4); b.incl(5) + assert symmetricDifference(a, b).len == 4 + ## {1, 2, 4, 5} + + result.assign(s1) + for item in s2: + if containsOrIncl(result, item): excl(result, item) + +proc `+`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = + ## Alias for `union(s1, s2) <#union,PackedSet[A],PackedSet[A]>`_. + result = union(s1, s2) + +proc `*`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = + ## Alias for `intersection(s1, s2) <#intersection,PackedSet[A],PackedSet[A]>`_. + result = intersection(s1, s2) + +proc `-`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = + ## Alias for `difference(s1, s2) <#difference,PackedSet[A],PackedSet[A]>`_. + result = difference(s1, s2) + +proc disjoint*[A](s1, s2: PackedSet[A]): bool = + ## Returns true if the sets `s1` and `s2` have no items in common. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1); a.incl(2) + b.incl(2); b.incl(3) + assert disjoint(a, b) == false + b.excl(2) + assert disjoint(a, b) == true + + for item in s1: + if contains(s2, item): + return false + return true + +proc card*[A](s: PackedSet[A]): int {.inline.} = + ## Alias for `len() <#len,PackedSet[A]>`_. + result = s.len() + +proc `<=`*[A](s1, s2: PackedSet[A]): bool = + ## Returns true if `s1` is subset of `s2`. + ## + ## A subset `s1` has all of its elements in `s2`, and `s2` doesn't necessarily + ## have more elements than `s1`. That is, `s1` can be equal to `s2`. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1) + b.incl(1); b.incl(2) + assert a <= b + a.incl(2) + assert a <= b + a.incl(3) + assert(not (a <= b)) + + for item in s1: + if not s2.contains(item): + return false + return true + +proc `<`*[A](s1, s2: PackedSet[A]): bool = + ## Returns true if `s1` is proper subset of `s2`. + ## + ## A strict or proper subset `s1` has all of its elements in `s2`, but `s2` has + ## more elements than `s1`. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + a.incl(1) + b.incl(1); b.incl(2) + assert a < b + a.incl(2) + assert(not (a < b)) + return s1 <= s2 and not (s2 <= s1) + +proc `==`*[A](s1, s2: PackedSet[A]): bool = + ## Returns true if both `s1` and `s2` have the same elements and set size. + return s1 <= s2 and s2 <= s1 + +proc `$`*[A](s: PackedSet[A]): string = + ## The `$` operator for int sets. + ## + ## Converts the set `s` to a string, mostly for logging and printing purposes. + dollarImpl() diff --git a/tests/stdlib/tintsets.nim b/tests/stdlib/tintsets.nim deleted file mode 100644 index f859b87ae..000000000 --- a/tests/stdlib/tintsets.nim +++ /dev/null @@ -1,65 +0,0 @@ -import intsets -import std/sets - -from sequtils import toSeq -from algorithm import sorted - -proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted -template sortedItems(t: untyped): untyped = sorted(toSeq(t)) - -block: # we use HashSet as groundtruth, it's well tested elsewhere - template testDel(t, t0) = - - template checkEquals() = - doAssert t.len == t0.len - for k in t0: - doAssert k in t - for k in t: - doAssert k in t0 - - doAssert sortedItems(t) == sortedItems(t0) - - template incl2(i) = - t.incl i - t0.incl i - - template excl2(i) = - t.excl i - t0.excl i - - block: - var expected: seq[int] - let n = 100 - let n2 = n*2 - for i in 0.. Date: Fri, 13 Nov 2020 14:18:01 +0100 Subject: [PATCH 1473/4254] makes test green again --- tests/errmsgs/tgcsafety.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index e6a62204e..721677e95 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -5,8 +5,8 @@ nimout: ''' type mismatch: got .}> but expected one of: proc serve(server: AsyncHttpServer; port: Port; - callback: proc (request: Request): Future[void] {.closure, gcsafe.}; - address = ""): owned(Future[void]) + callback: proc (request: Request): Future[void] {.closure, gcsafe.}; + address = ""; assumedDescriptorsPerRequest = 5): owned(Future[void]) first type mismatch at position: 3 required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.} but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: .} From 9f566881f15bed58276d3df4b5b2cb2289016396 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 13 Nov 2020 17:03:07 +0100 Subject: [PATCH 1474/4254] ported to FreeRTOS --- lib/pure/asyncdispatch.nim | 22 ++++++++++++---------- lib/pure/asynchttpserver.nim | 11 ++++++++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 0bacf3bb5..90345676f 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1946,13 +1946,15 @@ proc activeDescriptors*(): int {.inline.} = when defined(posix): import posix -proc maxDescriptors*(): int {.raises: OSError.} = - ## Returns the maximum number of active file descriptors for the current - ## process. This involves a system call. - when defined(windows): - result = 16_700_000 - else: - var fdLim: RLimit - if getrlimit(RLIMIT_NOFILE, fdLim) < 0: - raiseOSError(osLastError()) - result = int(fdLim.rlim_cur) - 1 +when defined(linux) or defined(windows) or defined(macosx) or defined(bsd): + proc maxDescriptors*(): int {.raises: OSError.} = + ## Returns the maximum number of active file descriptors for the current + ## process. This involves a system call. For now `maxDescriptors` is + ## supported on the following OSes: Windows, Linux, OSX, BSD. + when defined(windows): + result = 16_700_000 + else: + var fdLim: RLimit + if getrlimit(RLIMIT_NOFILE, fdLim) < 0: + raiseOSError(osLastError()) + result = int(fdLim.rlim_cur) - 1 diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index b69f3f9a4..a5f6a0bc8 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -308,9 +308,18 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string ) if not retry: break +const + nimMaxDescriptorsFallback* {.intdefine.} = 16_000 ## fallback value for \ + ## when `maxDescriptors` is not available. + ## This can be set on the command line during compilation + ## via `-d:nimMaxDescriptorsFallback=N` + proc listen*(server: AsyncHttpServer; port: Port; address = "") = ## Listen to the given port and address. - server.maxFDs = maxDescriptors() + when declared(maxDescriptors): + server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback + else: + server.maxFDs = nimMaxDescriptorsFallback server.socket = newAsyncSocket() if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) From 02f8b11a716843be8270f8bf7b2dac94f1c7dc1a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 13 Nov 2020 17:16:00 +0100 Subject: [PATCH 1475/4254] fixes the doc rendering --- lib/pure/asynchttpserver.nim | 73 +++++++++++++++++------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index a5f6a0bc8..f3d4b3dd2 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -7,44 +7,41 @@ # distribution, for details about the copyright. # -##[ This module implements a high performance asynchronous HTTP server. - -This HTTP server has not been designed to be used in production, but -for testing applications locally. Because of this, when deploying your -application in production you should use a reverse proxy (for example nginx) -instead of allowing users to connect directly to this server. - -Basic usage -=========== - -This example will create an HTTP server on port 8080. The server will -respond to all requests with a ``200 OK`` response code and "Hello World" -as the response body. - -.. code-block::nim - import asynchttpserver, asyncdispatch - - proc main {.async.} = - var server = newAsyncHttpServer() - proc cb(req: Request) {.async.} = - #echo(req.reqMethod, " ", req.url) - #echo(req.headers) - let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", - "Content-type": "text/plain; charset=utf-8"} - await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - - server.listen Port(5555) - while true: - if server.shouldAcceptRequest(5): - var (address, client) = await server.socket.acceptAddr() - asyncCheck processClient(server, client, address, cb) - else: - poll() - - asyncCheck main() - runForever() - -]## +## This module implements a high performance asynchronous HTTP server. +## +## This HTTP server has not been designed to be used in production, but +## for testing applications locally. Because of this, when deploying your +## application in production you should use a reverse proxy (for example nginx) +## instead of allowing users to connect directly to this server. +## +## Basic usage +## =========== +## +## This example will create an HTTP server on port 8080. The server will +## respond to all requests with a ``200 OK`` response code and "Hello World" +## as the response body. +## +## .. code-block:: Nim +## +## import asynchttpserver, asyncdispatch +## +## proc main {.async.} = +## var server = newAsyncHttpServer() +## proc cb(req: Request) {.async.} = +## let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", +## "Content-type": "text/plain; charset=utf-8"} +## await req.respond(Http200, "Hello World", headers.newHttpHeaders()) +## +## server.listen Port(5555) +## while true: +## if server.shouldAcceptRequest(5): +## var (address, client) = await server.socket.acceptAddr() +## asyncCheck processClient(server, client, address, cb) +## else: +## poll() +## +## asyncCheck main() +## runForever() import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore From edd84bd9bc8a35d3b96f427d8d81829cb45f29dc Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 14 Nov 2020 01:21:27 +0300 Subject: [PATCH 1476/4254] nimgrep: change 2 iterators to closure --- tools/nimgrep.nim | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 1e563435c..cb46f30b8 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -998,7 +998,8 @@ proc hasRightDirectory(path: string, walkOptC: WalkOptComp[Pattern]): bool = if dirname.contains(pat): return false result = true -iterator walkDirBasic(dir: string, walkOptC: WalkOptComp[Pattern]): string = +iterator walkDirBasic(dir: string, walkOptC: WalkOptComp[Pattern]): string + {.closure.} = var dirStack = @[dir] # stack of directories var timeFiles = newSeq[(times.Time, string)]() while dirStack.len > 0: @@ -1040,7 +1041,8 @@ iterator walkDirBasic(dir: string, walkOptC: WalkOptComp[Pattern]): string = for (_, file) in timeFiles: yield file -iterator walkRec(paths: seq[string]): (string, string) = +iterator walkRec(paths: seq[string]): tuple[error: string, filename: string] + {.closure.} = declareCompiledPatterns(walkOptC, WalkOptComp): walkOptC.excludeFile.add walkOpt.excludeFile.compileArray() walkOptC.includeFile.add walkOpt.includeFile.compileArray() @@ -1130,13 +1132,13 @@ proc run1Thread() = processFileResult(searchOptC.pattern, "-", processFile(searchOptC, "-", yieldContents=optReplace in options)) - for (err, filename) in walkRec(paths): - if err != "": + for entry in walkRec(paths): + if entry.error != "": inc(gVar.errors) - printError (err & filename) + printError (entry.error & entry.filename) continue - processFileResult(searchOptC.pattern, filename, - processFile(searchOptC, filename, + processFileResult(searchOptC.pattern, entry.filename, + processFile(searchOptC, entry.filename, yieldContents=optReplace in options)) # Multi-threaded version: all printing is being done in the Main thread. @@ -1182,12 +1184,12 @@ proc pathProducer(arg: (seq[string], WalkOpt)) {.thread.} = walkOpt = arg[1] # init thread-local copy of opt var nextFileN = 0 - for (err, filename) in walkRec(paths): - if err == "": - searchRequestsChan.send((nextFileN,filename)) + for entry in walkRec(paths): + if entry.error == "": + searchRequestsChan.send((nextFileN, entry.filename)) else: - resultsChan.send((false, nextFileN, - filename, @[Output(kind: openError, msg: err)])) + resultsChan.send((false, nextFileN, entry.filename, + @[Output(kind: openError, msg: entry.error)])) nextFileN += 1 resultsChan.send((true, nextFileN, "", @[])) # pass total number of files From 1a47fc2291b285ceb6b2f330f45997944b754b3a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 13 Nov 2020 14:44:44 -0800 Subject: [PATCH 1477/4254] strengthen taddr.nim: add test case for #14578; reference other issues; test cpp (#15960) --- tests/{js => misc}/taddr.nim | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) rename tests/{js => misc}/taddr.nim (84%) diff --git a/tests/js/taddr.nim b/tests/misc/taddr.nim similarity index 84% rename from tests/js/taddr.nim rename to tests/misc/taddr.nim index 9c45621a8..4d0aebc01 100644 --- a/tests/js/taddr.nim +++ b/tests/misc/taddr.nim @@ -1,5 +1,6 @@ discard """ - targets: "c js" + targets: "c cpp js" + matrix: "; -d:release" """ type T = object @@ -79,7 +80,7 @@ someGlobalPtr[] = 10 doAssert(someGlobal == 10) block: - # issue #14576 + # bug #14576 # lots of these used to give: Error: internal error: genAddr: 2 proc byLent[T](a: T): lent T = a proc byPtr[T](a: T): ptr T = a.unsafeAddr @@ -89,24 +90,21 @@ block: let (x,y) = byLent(a) doAssert (x,y) == a - block: - when defined(c) and defined(release): - # bug; pending https://github.com/nim-lang/Nim/issues/14578 - discard - else: - let a = 10 - doAssert byLent(a) == 10 - let a2 = byLent(a) - doAssert a2 == 10 + block: # (with -d:release) bug #14578 + let a = 10 + doAssert byLent(a) == 10 + let a2 = byLent(a) + doAssert a2 == 10 block: - let a = [11,12] - doAssert byLent(a) == [11,12] + when not defined(cpp): # pending bug #15958 + let a = [11,12] + doAssert byLent(a) == [11,12] let a2 = (11,) doAssert byLent(a2) == (11,) block: - when defined(c) and defined(release): + when (defined(c) or defined(cpp)) and defined(release): discard # probably not a bug since optimizer is free to pass by value, and `unsafeAddr` is used else: var a = @[12] @@ -134,6 +132,6 @@ block: bar(a2).inc doAssert a2 == 13 - block: # xxx: bug this doesn't work + block: # pending bug #15959 when false: proc byLent2[T](a: T): lent type(a[0]) = a[0] From 96930b9caec2ed51777af5d8570f64b00bfaf2a8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 14 Nov 2020 01:08:15 -0800 Subject: [PATCH 1478/4254] targets: use cpp instead of c++ everywhere (was by far the most common) (#15961) --- doc/testament.rst | 2 +- testament/testament.nim | 2 +- tests/float/tfloatmod.nim | 2 +- tests/osproc/passenv.nim | 2 +- tests/stdlib/tfrexp1.nim | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/testament.rst b/doc/testament.rst index 09c248d1f..1a1909022 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -26,7 +26,7 @@ Options * ``--print`` Also print results to the console * ``--simulate`` See what tests would be run but don't run them (for debugging) * ``--failing`` Only show failing/ignored tests -* ``--targets:"c c++ js objc"`` Run tests for specified targets (default: all) +* ``--targets:"c cpp js objc"`` Run tests for specified targets (default: all) * ``--nim:path`` Use a particular nim executable (default: ``$PATH/nim``) * ``--directory:dir`` Change to directory dir before reading the tests or doing anything else. * ``--colors:on|off`` Turn messages coloring on|off. diff --git a/testament/testament.nim b/testament/testament.nim index 8fead76ef..2912b03ab 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -41,7 +41,7 @@ Options: --print also print results to the console --simulate see what tests would be run but don't run them (for debugging) --failing only show failing/ignored tests - --targets:"c c++ js objc" run tests for specified targets (default: all) + --targets:"c cpp js objc" run tests for specified targets (default: all) --nim:path use a particular nim executable (default: $$PATH/nim) --directory:dir Change to directory dir before reading the tests or doing anything else. --colors:on|off Turn messages coloring on|off. diff --git a/tests/float/tfloatmod.nim b/tests/float/tfloatmod.nim index 0b84ec7e0..37546a64c 100644 --- a/tests/float/tfloatmod.nim +++ b/tests/float/tfloatmod.nim @@ -1,5 +1,5 @@ discard """ - targets: "c c++ js" + targets: "c cpp js" output: "ok" exitcode: "0" """ diff --git a/tests/osproc/passenv.nim b/tests/osproc/passenv.nim index 815f7536f..40b1c3f7c 100644 --- a/tests/osproc/passenv.nim +++ b/tests/osproc/passenv.nim @@ -1,7 +1,7 @@ discard """ file: "passenv.nim" output: "123" - targets: "c c++ objc" + targets: "c cpp objc" """ import osproc, os, strtabs diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim index 6da185420..21ecc7491 100644 --- a/tests/stdlib/tfrexp1.nim +++ b/tests/stdlib/tfrexp1.nim @@ -1,5 +1,5 @@ discard """ - targets: "js c c++" + targets: "js c cpp" output: '''ok''' """ From 5af798c21b5d32bb6c2b9cff21e8288dc829a41a Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 14 Nov 2020 18:47:17 +0800 Subject: [PATCH 1479/4254] [docs minor]add some tips yo intern.rst --- doc/intern.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/intern.rst b/doc/intern.rst index 89d477d09..ea9e1a07c 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -153,13 +153,21 @@ are also lots of procs that aid in debugging: debug(symbol) # pretty prints the Nim ast, but annotates symbol IDs: echo renderTree(someNode, {renderIds}) - if n.info ?? "temp.nim": + if `??`(conf, n.info, "temp.nim"): # only output when it comes from "temp.nim" echo renderTree(n) - if n.info ?? "temp.nim": + if `??`(conf, n.info, "temp.nim"): # why does it process temp.nim here? writeStackTrace() +These procs may not be imported by module, you can import them for debuging: + +.. code-block:: nim + from astalgo import debug + from types import typeToString + from renderer import renderTree + from msgs import `??` + To create a new compiler for each run, use ``koch temp``:: ./koch temp c /tmp/test.nim From bfa387d384762cf0b46431407669ec1889b8c4a3 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 14 Nov 2020 18:51:05 +0800 Subject: [PATCH 1480/4254] minor --- doc/intern.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/intern.rst b/doc/intern.rst index ea9e1a07c..3f8a2ce56 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -160,7 +160,7 @@ are also lots of procs that aid in debugging: # why does it process temp.nim here? writeStackTrace() -These procs may not be imported by module, you can import them for debuging: +These procs may not be imported by a module. You can import them directly for debugging: .. code-block:: nim from astalgo import debug From 47ce24f680dbf5aed8cd393f011739ea5d7a9928 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 14 Nov 2020 19:51:23 +0800 Subject: [PATCH 1481/4254] fix #12303 (#15964) --- compiler/jsgen.nim | 9 +++++++-- tests/js/t12303.nim | 16 ++++++++++++++++ tests/varres/tvarres0.nim | 3 +++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/js/t12303.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 34ebd306a..3a1ef7fbb 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1074,8 +1074,13 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") - lineF(p, "nimCopy($1, $2, $3);$n", - [a.res, b.res, genTypeInfo(p, y.typ)]) + # supports proc getF(): var T + if x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].kind in nkCallKinds: + lineF(p, "nimCopy($1, $2, $3);$n", + [a.res, b.res, genTypeInfo(p, y.typ)]) + else: + lineF(p, "$1 = nimCopy($1, $2, $3);$n", + [a.res, b.res, genTypeInfo(p, y.typ)]) of etyBaseIndex: if a.typ != etyBaseIndex or b.typ != etyBaseIndex: if y.kind == nkCall: diff --git a/tests/js/t12303.nim b/tests/js/t12303.nim new file mode 100644 index 000000000..270d82ced --- /dev/null +++ b/tests/js/t12303.nim @@ -0,0 +1,16 @@ +discard """ + output: "{ b: 2 }" +""" + +import jsconsole, jsffi + +type + A = ref object + b: B + + B = object + b: int + +var a = cast[A](js{}) +a.b = B(b: 2) +console.log a.b diff --git a/tests/varres/tvarres0.nim b/tests/varres/tvarres0.nim index 0f89c7e71..94bdb4a06 100644 --- a/tests/varres/tvarres0.nim +++ b/tests/varres/tvarres0.nim @@ -4,6 +4,7 @@ discard """ 123 1234 12345 +123456 ''' """ @@ -28,6 +29,8 @@ getF().a = 1234 echo getF().a getF() = Foo(a: 12345) echo getF().a +(addr getF())[] = Foo(a: 123456) +echo getF().a block: # #13848 From d0dda9efab6bd67d033e30e2ba16820450c38cbe Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 14 Nov 2020 15:31:59 -0300 Subject: [PATCH 1482/4254] Fix #15806 --- doc/manual.rst | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index bfcce24cf..bbc8bb225 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -8,7 +8,7 @@ Nim Manual .. contents:: - "Complexity" seems to be a lot like "energy": you can transfer it from the + "Complexity" seems to be a lot like "energy": you can transfer it from the end-user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran @@ -313,6 +313,35 @@ it was not case-sensitive and underscores were ignored and there was not even a distinction between ``foo`` and ``Foo``. +Stropping +--------- + +`Stropping `_ +allows the same letter sequence to be used both as a keyword and as an identifier, and simplifies parsing. +For example, allowing a variable named `if` without clashing with the keyword `if`. +In Nim, this is achieved via backticks, allowing any reserved word to be used as an identifier. + +Examples + +.. code-block:: nim + var `var` = "Hello Stropping" + +.. code-block:: nim + type Type = object + `int`: int + + let `object` = Type(`int`: 9) + assert `object` is Type + assert `object`.`int` == 9 + + var `var` = 42 + let `let` = 8 + assert `var` + `let` == 50 + + const `assert` = true + assert `assert` + + String literals --------------- From 3cebae492e61ccbb29cfc38fbaa1f54270dfeb8a Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 14 Nov 2020 15:39:03 -0300 Subject: [PATCH 1483/4254] Fix #15806 --- doc/manual.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index bbc8bb225..0656dfa76 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -317,7 +317,8 @@ Stropping --------- `Stropping `_ -allows the same letter sequence to be used both as a keyword and as an identifier, and simplifies parsing. +allows the same letter sequence to be used both as a keyword and as an identifier, +this simplifies parsing and FFI with languages where that identifier is not a reserved keyword. For example, allowing a variable named `if` without clashing with the keyword `if`. In Nim, this is achieved via backticks, allowing any reserved word to be used as an identifier. From 9ab1a86b5bfb8f5647b9f9cb4ab48a5b5eb55707 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 14 Nov 2020 15:43:31 -0300 Subject: [PATCH 1484/4254] Fix #15806 --- doc/manual.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 0656dfa76..6dfff55a6 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -317,8 +317,9 @@ Stropping --------- `Stropping `_ -allows the same letter sequence to be used both as a keyword and as an identifier, -this simplifies parsing and FFI with languages where that identifier is not a reserved keyword. +allows the same letter sequence to be used both as a keyword and as an identifier, this simplifies parsing and +`FFI `_ +with languages where that identifier is not a reserved keyword. For example, allowing a variable named `if` without clashing with the keyword `if`. In Nim, this is achieved via backticks, allowing any reserved word to be used as an identifier. From c56a6133bb3c1d2e862726e10e445d477dd6d15e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 14 Nov 2020 15:45:13 -0300 Subject: [PATCH 1485/4254] Fix #15806 --- doc/manual.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 6dfff55a6..c80b60ea0 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -320,6 +320,7 @@ Stropping allows the same letter sequence to be used both as a keyword and as an identifier, this simplifies parsing and `FFI `_ with languages where that identifier is not a reserved keyword. + For example, allowing a variable named `if` without clashing with the keyword `if`. In Nim, this is achieved via backticks, allowing any reserved word to be used as an identifier. @@ -330,7 +331,7 @@ Examples .. code-block:: nim type Type = object - `int`: int + `int`: int let `object` = Type(`int`: 9) assert `object` is Type From 1b9f37c6dc99b95a2ccee0a51535faf224b31f31 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 14 Nov 2020 19:57:06 -0300 Subject: [PATCH 1486/4254] https://github.com/nim-lang/Nim/pull/15968/files#r523468677 --- doc/manual.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index c80b60ea0..9a4ae378d 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -316,13 +316,7 @@ distinction between ``foo`` and ``Foo``. Stropping --------- -`Stropping `_ -allows the same letter sequence to be used both as a keyword and as an identifier, this simplifies parsing and -`FFI `_ -with languages where that identifier is not a reserved keyword. - -For example, allowing a variable named `if` without clashing with the keyword `if`. -In Nim, this is achieved via backticks, allowing any reserved word to be used as an identifier. +If a keyword is enclosed in backticks it loses its keyword property and becomes an ordinary identifier. Examples From 122f22d1632255cf7d0539c620a30155dc84fd69 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 15 Nov 2020 07:27:13 +0100 Subject: [PATCH 1487/4254] asynchttpserver cleanups [backport:1.0] (#15966) * asynchttpserver cleanups [backport:1.0] --- lib/pure/asynchttpserver.nim | 20 +++++++++----------- tests/errmsgs/tgcsafety.nim | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index f3d4b3dd2..f3f59baf8 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -14,8 +14,8 @@ ## application in production you should use a reverse proxy (for example nginx) ## instead of allowing users to connect directly to this server. ## -## Basic usage -## =========== +## Example +## ======= ## ## This example will create an HTTP server on port 8080. The server will ## respond to all requests with a ``200 OK`` response code and "Hello World" @@ -32,11 +32,10 @@ ## "Content-type": "text/plain; charset=utf-8"} ## await req.respond(Http200, "Hello World", headers.newHttpHeaders()) ## -## server.listen Port(5555) +## server.listen Port(8080) ## while true: -## if server.shouldAcceptRequest(5): -## var (address, client) = await server.socket.acceptAddr() -## asyncCheck processClient(server, client, address, cb) +## if server.shouldAcceptRequest(): +## asyncCheck server.acceptRequest(cb) ## else: ## poll() ## @@ -333,7 +332,7 @@ proc shouldAcceptRequest*(server: AsyncHttpServer; result = assumedDescriptorsPerRequest < 0 or (activeDescriptors() + assumedDescriptorsPerRequest < server.maxFDs) -proc acceptRequest*(server: AsyncHttpServer, port: Port, +proc acceptRequest*(server: AsyncHttpServer, callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = ## Accepts a single request. Write an explicit loop around this proc so that ## errors can be handled properly. @@ -343,7 +342,7 @@ proc acceptRequest*(server: AsyncHttpServer, port: Port, proc serve*(server: AsyncHttpServer, port: Port, callback: proc (request: Request): Future[void] {.closure, gcsafe.}, address = ""; - assumedDescriptorsPerRequest = 5) {.async.} = + assumedDescriptorsPerRequest = -1) {.async.} = ## Starts the process of listening for incoming HTTP connections on the ## specified address and port. ## @@ -382,9 +381,8 @@ when not defined(testing) and isMainModule: server.listen Port(5555) while true: - if server.shouldAcceptRequest(5): - var (address, client) = await server.socket.acceptAddr() - asyncCheck processClient(server, client, address, cb) + if server.shouldAcceptRequest(): + asyncCheck server.acceptRequest(cb) else: poll() diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 721677e95..77515b74f 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -6,7 +6,7 @@ type mismatch: got .} From 92da06e64ece2f87e259c17439c085074d77ef97 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 15 Nov 2020 15:08:27 +0100 Subject: [PATCH 1488/4254] Fix nimsuggest/#117 (#15602) --- compiler/extccomp.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index d97f9a887..e37e867da 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -627,10 +627,7 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = getCompileCFileCmd(conf, cfile)) proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = - case conf.backend - of backendInvalid: doAssert false - of backendJs: return false # pre-existing behavior, but not sure it's good - else: discard + if conf.backend == backendJs: return false # pre-existing behavior, but not sure it's good var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") var currentHash = footprint(conf, cfile) From 7eb34d170a489c2a0ed90d921f3f7cc6813f19c1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 15 Nov 2020 15:47:42 +0100 Subject: [PATCH 1489/4254] fixes #15753 [backport:1.4] (#15971) --- compiler/liftdestructors.nim | 95 ++++++++++++++++++++++++++++------- tests/arc/torc_selfcycles.nim | 33 ++++++++++++ 2 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 tests/arc/torc_selfcycles.nim diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 9b6c179db..943dd074e 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -392,6 +392,16 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = v.addVar(result, lowerings.newIntLit(c.g, body.info, first)) body.add v +proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode = + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextId(c.idgen), c.fn, c.info) + temp.typ = value.typ + incl(temp.flags, sfFromGeneric) + + var v = newNodeI(nkVarSection, c.info) + result = newSymNode(temp) + v.addVar(result, value) + body.add v + proc addIncStmt(c: var TLiftCtx; body, i: PNode) = let incCall = genBuiltin(c.g, mInc, "inc", i) incCall.add lowerings.newIntLit(c.g, c.info, 1) @@ -508,43 +518,75 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = discard "strings are atomic and have no inner elements that are to trace" proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + #[ bug #15753 is really subtle. Usually the classical write barrier for reference + counting looks like this:: + + incRef source # increment first; this takes care of self-assignments1 + decRef dest + dest[] = source + + However, 'decRef dest' might trigger a cycle collection and then the collector + traverses the graph. It is crucial that when it follows the pointers the assignment + 'dest[] = source' already happened so that we don't do trial deletion on a wrong + graph -- this causes premature freeing of objects! The correct barrier looks like + this:: + + let tmp = dest + incRef source + dest[] = source + decRef tmp + + ]# var actions = newNodeI(nkStmtList, c.info) let elemType = t.lastSon createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen) + let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType) + + let tmp = + if isCyclic and c.kind in {attachedAsgn, attachedSink}: + declareTempOf(c, body, x) + else: + x if isFinal(elemType): - addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) + addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr)) var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) alignOf.typ = getSysType(c.g, c.info, tyInt) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf) else: - addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) - actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) - - let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType) + addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr)) + actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp) var cond: PNode if isCyclic: if isFinal(elemType): let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) - cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo) + cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo) else: - cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, x) + cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp) else: cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x) cond.typ = getSysType(c.g, x.info, tyBool) case c.kind of attachedSink: - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + if isCyclic: + body.add newAsgnStmt(x, y) + body.add genIf(c, cond, actions) + else: + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedAsgn: body.add genIf(c, y, callCodegenProc(c.g, if isCyclic: "nimIncRefCyclic" else: "nimIncRef", c.info, y)) - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + if isCyclic: + body.add newAsgnStmt(x, y) + body.add genIf(c, cond, actions) + else: + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, cond, actions) of attachedDeepCopy: assert(false, "cannot happen") @@ -571,19 +613,30 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xenv = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xenv.typ = getSysType(c.g, c.info, tyPointer) + let isCyclic = c.g.config.selectedGC == gcOrc + let tmp = + if isCyclic and c.kind in {attachedAsgn, attachedSink}: + declareTempOf(c, body, xenv) + else: + xenv + var actions = newNodeI(nkStmtList, c.info) - actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xenv) + actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp) let decRefProc = - if c.g.config.selectedGC == gcOrc: "nimDecRefIsLastCyclicDyn" + if isCyclic: "nimDecRefIsLastCyclicDyn" else: "nimDecRefIsLast" - let cond = callCodegenProc(c.g, decRefProc, c.info, xenv) + let cond = callCodegenProc(c.g, decRefProc, c.info, tmp) cond.typ = getSysType(c.g, x.info, tyBool) case c.kind of attachedSink: - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + if isCyclic: + body.add newAsgnStmt(x, y) + body.add genIf(c, cond, actions) + else: + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedAsgn: let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y) yenv.typ = getSysType(c.g, c.info, tyPointer) @@ -591,8 +644,12 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.g.config.selectedGC == gcOrc: "nimIncRefCyclic" else: "nimIncRef" body.add genIf(c, yenv, callCodegenProc(c.g, incRefProc, c.info, yenv)) - body.add genIf(c, cond, actions) - body.add newAsgnStmt(x, y) + if isCyclic: + body.add newAsgnStmt(x, y) + body.add genIf(c, cond, actions) + else: + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, cond, actions) of attachedDeepCopy: assert(false, "cannot happen") diff --git a/tests/arc/torc_selfcycles.nim b/tests/arc/torc_selfcycles.nim new file mode 100644 index 000000000..ac4fa52ce --- /dev/null +++ b/tests/arc/torc_selfcycles.nim @@ -0,0 +1,33 @@ +discard """ + output: '''ok''' + cmd: '''nim c --gc:orc -d:useMalloc -d:nimStressOrc $file''' + valgrind: "leaks" +""" + +# bug #15753 + +type + NodeKind = enum + nkDancing, + nkColumn + + DancingNode = ref object + right: DancingNode + column: DancingNode + kind: NodeKind + +proc newColumnNode(): DancingNode = + result = DancingNode(kind: nkColumn) + result.right = result + result.column = result + +proc createDLXList(): DancingNode = + result = newColumnNode() + + for i in 0 .. 15: + let n = newColumnNode() + n.right = result.right + result = n + echo "ok" + +var dlxlist = createDLXList() From a4d02f591c685b261a41a7b9b51aaba05c542499 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 16 Nov 2020 11:39:28 +0000 Subject: [PATCH 1490/4254] fix #15910 (#15984) * fix #15910 * produce op of op is nil * Trigger build --- compiler/liftdestructors.nim | 16 ++++++--- tests/arc/t14383.nim | 66 +++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 943dd074e..45a66e795 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -42,6 +42,9 @@ proc at(a, i: PNode, elemType: PType): PNode = result[1] = i result.typ = elemType +proc destructorOverriden(t: PType): bool = + t.attachedOps[attachedDestructor] != nil and sfOverriden in t.attachedOps[attachedDestructor].flags + proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = for i in 0.. Date: Mon, 16 Nov 2020 22:19:26 +0800 Subject: [PATCH 1491/4254] rename: stmt -> typed and expr -> untyped (#15989) * stmt -> typed * expr -> untyped * minor --- compiler/ast.nim | 2 +- compiler/semtypes.nim | 2 +- compiler/sigmatch.nim | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index ca931ab09..3d14aba66 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1804,7 +1804,7 @@ proc isAtom*(n: PNode): bool {.inline.} = result = n.kind >= nkNone and n.kind <= nkNilLit proc isEmptyType*(t: PType): bool {.inline.} = - ## 'void' and 'stmt' types are often equivalent to 'nil' these days: + ## 'void' and 'typed' types are often equivalent to 'nil' these days: result = t == nil or t.kind in {tyVoid, tyTyped} proc makeStmtList*(n: PNode): PNode = diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5feb25a59..0ec7140e0 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1315,7 +1315,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, "' is only valid for macros and templates") # 'auto' as a return type does not imply a generic: elif r.kind == tyAnything: - # 'p(): auto' and 'p(): expr' are equivalent, but the rest of the + # 'p(): auto' and 'p(): untyped' are equivalent, but the rest of the # compiler is hardly aware of 'auto': r = newTypeS(tyUntyped, c) elif r.kind == tyStatic: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2e332f105..b674c3d9e 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1240,8 +1240,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if result < isGeneric: result = isNone else: discard of tyOpenArray, tyVarargs: - # varargs[expr] is special too but handled earlier. So we only need to - # handle varargs[stmt] which is the same as varargs[typed]: + # varargs[untyped] is special too but handled earlier. So we only need to + # handle varargs[typed]: if f.kind == tyVarargs: if tfVarargs in a.flags: return typeRel(c, f.base, a.lastSon, flags) From 3e5e029ef8c480d73e847fde546551c9416c948e Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 16 Nov 2020 17:46:48 +0100 Subject: [PATCH 1492/4254] telling us once about a change is enough [ci skip] --- changelog.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index e50be6de3..200214ff3 100644 --- a/changelog.md +++ b/changelog.md @@ -37,13 +37,12 @@ - Added `asyncdispatch.activeDescriptors` that returns the number of currently active async event handles/file descriptors -- Added `asyncdispatch.maxDescriptors` that returns the maximum number of - active async event handles/file descriptors. ## Language changes - `nimscript` now handles `except Exception as e` + - The `cstring` doesn't support `[]=` operator in JS backend. From a8858eb93ee666d669c272ec2ba1ade89e81177c Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 16 Nov 2020 15:15:05 -0300 Subject: [PATCH 1493/4254] htmlgen: Add lazy loading (#15986) --- lib/pure/htmlgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index ba50a4a6e..acec05832 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -333,12 +333,12 @@ macro i*(e: varargs[untyped]): untyped = macro iframe*(e: varargs[untyped]): untyped = ## Generates the HTML ``iframe`` element. - result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height" & + result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height loading" & commonAttr) macro img*(e: varargs[untyped]): untyped = ## Generates the HTML ``img`` element. - result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width" & + result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width loading" & commonAttr, "src alt", true) macro input*(e: varargs[untyped]): untyped = From 61352d5a203e76e3334b21766bdbd4ebc71c300a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 16 Nov 2020 13:52:02 -0800 Subject: [PATCH 1494/4254] remove unused and misleading FilenameOption.foShort (#15982) --- compiler/msgs.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index be3dc5ec4..d0209db5d 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -237,7 +237,6 @@ type FilenameOption* = enum foRelProject # relative to project path, e.g.: ../foo.nim foMagicSauce # magic sauce, shortest of (foAbs, foRelProject) foName # lastPathPart, e.g.: foo.nim - foShort # foName without extension, e.g.: foo foStacktrace # if optExcessiveStackTrace: foAbs else: foName proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption): string = @@ -255,7 +254,6 @@ proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption) else: relPath of foName: result = toProjPath(conf, fileIdx).lastPathPart - of foShort: result = toFilename(conf, fileIdx) of foStacktrace: if optExcessiveStackTrace in conf.globalOptions: result = toFilenameOption(conf, fileIdx, foAbs) From 50d035b7896b85184fc6e97e22f32a189d76b81b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 16 Nov 2020 23:40:17 -0800 Subject: [PATCH 1495/4254] defer: improve manual, clarify difference wrt try/finally (#16010) --- doc/manual.rst | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 9a4ae378d..1a23c5997 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4414,7 +4414,9 @@ Custom exceptions can be raised like any others, e.g.: Defer statement --------------- -Instead of a ``try finally`` statement a ``defer`` statement can be used. +Instead of a ``try finally`` statement a ``defer`` statement can be used, which +avoids lexical nesting and offers more flexibility in terms of scoping as shown +below. Any statements following the ``defer`` in the current block will be considered to be in an implicit try block: @@ -4423,7 +4425,7 @@ to be in an implicit try block: :test: "nim c $1" proc main = - var f = open("numbers.txt") + var f = open("numbers.txt", fmWrite) defer: close(f) f.write "abc" f.write "def" @@ -4441,6 +4443,33 @@ Is rewritten to: finally: close(f) +When `defer` is at the outermost scope of a template/macro, its scope extends +to the block where the template is called from: + +.. code-block:: nim + :test: "nim c $1" + + template safeOpenDefer(f, path) = + var f = open(path, fmWrite) + defer: close(f) + + template safeOpenFinally(f, path, body) = + var f = open(path, fmWrite) + try: body # without `defer`, `body` must be specified as parameter + finally: close(f) + + block: + safeOpenDefer(f, "/tmp/z01.txt") + f.write "abc" + block: + safeOpenFinally(f, "/tmp/z01.txt"): + f.write "abc" # adds a lexical scope + block: + var f = open("/tmp/z01.txt", fmWrite) + try: + f.write "abc" # adds a lexical scope + finally: close(f) + Top-level ``defer`` statements are not supported since it's unclear what such a statement should refer to. From fec19c980e36e62747eb119f0740cb785e858ac3 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 17 Nov 2020 18:47:01 +0800 Subject: [PATCH 1496/4254] follow #16009 VM supports cast nil to ptr (#16012) * follow #16009 VM supports cast nil to ptr * more testcase --- compiler/vmgen.nim | 3 +++ tests/vm/tcastnil.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/vm/tcastnil.nim diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bcb7faa47..069b8cbf5 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -901,6 +901,9 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = c.gABx(n, opcSetType, dest, c.genType(dst)) c.gABC(n, opcCastIntToPtr, dest, tmp) c.freeTemp(tmp) + elif src.kind == tyNil and dst.kind in PtrLikeKinds: + if dest < 0: dest = c.getTemp(n[0].typ) + genLit(c, n[1], dest) else: # todo: support cast from tyInt to tyRef globalError(c.config, n.info, "VM does not support 'cast' from " & $src.kind & " to " & $dst.kind) diff --git a/tests/vm/tcastnil.nim b/tests/vm/tcastnil.nim new file mode 100644 index 000000000..5a4684f95 --- /dev/null +++ b/tests/vm/tcastnil.nim @@ -0,0 +1,30 @@ +discard """ + nimout: '''nil +nil +nil +nil +nil +''' +""" + +block: + static: + let a = cast[pointer](nil) + echo a.repr + +block: + static: + echo cast[ptr int](nil).repr + +block: + const str = cast[ptr int](nil) + static: + echo str.repr + +block: + static: + echo cast[ptr int](nil).repr + +block: + static: + echo cast[RootRef](nil).repr From 0f7f159a35bc10a43ff15bcb6c20eefdc574138e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 18 Nov 2020 01:05:20 +0800 Subject: [PATCH 1497/4254] fix #15623 (#16009) * fix #15623 * add testcase for #15623 * fix * add testcase --- compiler/semfold.nim | 2 +- lib/posix/posix_linux_amd64_consts.nim | 2 +- tests/ccgbugs/t15623.nim | 11 +++++++++++ tests/ccgbugs/t15623_2.nim | 13 +++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/ccgbugs/t15623.nim create mode 100644 tests/ccgbugs/t15623_2.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 9b21c5fa3..f38359a64 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -674,7 +674,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkCast: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return - if n.typ != nil and n.typ.kind in NilableTypes: + if n.typ != nil and n.typ.kind in NilableTypes and a.kind != nkNilLit: # we allow compile-time 'cast' for pointer types: result = a result.typ = n.typ diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index f3230f71d..917c1f966 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -365,7 +365,7 @@ const SCHED_RR* = cint(2) const SCHED_OTHER* = cint(0) # -const SEM_FAILED* = cast[pointer]((nil)) +const SEM_FAILED* = nil # const SIGEV_NONE* = cint(1) diff --git a/tests/ccgbugs/t15623.nim b/tests/ccgbugs/t15623.nim new file mode 100644 index 000000000..c8246c85b --- /dev/null +++ b/tests/ccgbugs/t15623.nim @@ -0,0 +1,11 @@ +discard """ + action: "compile" +""" + +# bug #15623 +block: + echo cast[ptr int](nil)[] + +block: + var x: ref int = nil + echo cast[ptr int](x)[] diff --git a/tests/ccgbugs/t15623_2.nim b/tests/ccgbugs/t15623_2.nim new file mode 100644 index 000000000..4f33bc745 --- /dev/null +++ b/tests/ccgbugs/t15623_2.nim @@ -0,0 +1,13 @@ +discard """ + output: '''0 +0 +''' +""" + +# bug #15623 +block: + echo cast[int](cast[ptr int](nil)) + +block: + var x: ref int = nil + echo cast[int](cast[ptr int](x)) From 1663ad77e3398fec0b5d6b00516f91565ce12cce Mon Sep 17 00:00:00 2001 From: "Andrey R (cooldome)" Date: Tue, 17 Nov 2020 18:54:14 +0000 Subject: [PATCH 1498/4254] Revert "fix #15623 (#16009)" This reverts commit 0f7f159a35bc10a43ff15bcb6c20eefdc574138e. --- compiler/semfold.nim | 2 +- lib/posix/posix_linux_amd64_consts.nim | 2 +- tests/ccgbugs/t15623.nim | 11 ----------- tests/ccgbugs/t15623_2.nim | 13 ------------- 4 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 tests/ccgbugs/t15623.nim delete mode 100644 tests/ccgbugs/t15623_2.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index f38359a64..9b21c5fa3 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -674,7 +674,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkCast: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return - if n.typ != nil and n.typ.kind in NilableTypes and a.kind != nkNilLit: + if n.typ != nil and n.typ.kind in NilableTypes: # we allow compile-time 'cast' for pointer types: result = a result.typ = n.typ diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 917c1f966..f3230f71d 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -365,7 +365,7 @@ const SCHED_RR* = cint(2) const SCHED_OTHER* = cint(0) # -const SEM_FAILED* = nil +const SEM_FAILED* = cast[pointer]((nil)) # const SIGEV_NONE* = cint(1) diff --git a/tests/ccgbugs/t15623.nim b/tests/ccgbugs/t15623.nim deleted file mode 100644 index c8246c85b..000000000 --- a/tests/ccgbugs/t15623.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - action: "compile" -""" - -# bug #15623 -block: - echo cast[ptr int](nil)[] - -block: - var x: ref int = nil - echo cast[ptr int](x)[] diff --git a/tests/ccgbugs/t15623_2.nim b/tests/ccgbugs/t15623_2.nim deleted file mode 100644 index 4f33bc745..000000000 --- a/tests/ccgbugs/t15623_2.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: '''0 -0 -''' -""" - -# bug #15623 -block: - echo cast[int](cast[ptr int](nil)) - -block: - var x: ref int = nil - echo cast[int](cast[ptr int](x)) From 632af8afad92594da050a5f7fd784ea111c3cc54 Mon Sep 17 00:00:00 2001 From: "Andrey R (cooldome)" Date: Tue, 17 Nov 2020 18:54:33 +0000 Subject: [PATCH 1499/4254] Revert "follow #16009 VM supports cast nil to ptr (#16012)" This reverts commit fec19c980e36e62747eb119f0740cb785e858ac3. --- compiler/vmgen.nim | 3 --- tests/vm/tcastnil.nim | 30 ------------------------------ 2 files changed, 33 deletions(-) delete mode 100644 tests/vm/tcastnil.nim diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 069b8cbf5..bcb7faa47 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -901,9 +901,6 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = c.gABx(n, opcSetType, dest, c.genType(dst)) c.gABC(n, opcCastIntToPtr, dest, tmp) c.freeTemp(tmp) - elif src.kind == tyNil and dst.kind in PtrLikeKinds: - if dest < 0: dest = c.getTemp(n[0].typ) - genLit(c, n[1], dest) else: # todo: support cast from tyInt to tyRef globalError(c.config, n.info, "VM does not support 'cast' from " & $src.kind & " to " & $dst.kind) diff --git a/tests/vm/tcastnil.nim b/tests/vm/tcastnil.nim deleted file mode 100644 index 5a4684f95..000000000 --- a/tests/vm/tcastnil.nim +++ /dev/null @@ -1,30 +0,0 @@ -discard """ - nimout: '''nil -nil -nil -nil -nil -''' -""" - -block: - static: - let a = cast[pointer](nil) - echo a.repr - -block: - static: - echo cast[ptr int](nil).repr - -block: - const str = cast[ptr int](nil) - static: - echo str.repr - -block: - static: - echo cast[ptr int](nil).repr - -block: - static: - echo cast[RootRef](nil).repr From 0869d2a47777685d221ddde927f0175096c911b0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 18 Nov 2020 08:14:14 +0800 Subject: [PATCH 1500/4254] fix #15972 (#15994) * fix #15972 * add testcase * more --- compiler/semstmts.nim | 4 ++-- .../stmt/tforloop_tuple_multiple_underscore.nim | 10 ++++++++++ tests/stmt/tforloop_tuple_underscore.nim | 16 ++++++++++++++++ tests/stmt/tforloop_underscore.nim | 6 ++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 tests/stmt/tforloop_tuple_multiple_underscore.nim create mode 100644 tests/stmt/tforloop_tuple_underscore.nim create mode 100644 tests/stmt/tforloop_underscore.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f83864775..cd7428b62 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -739,7 +739,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = else: v.typ = iter[i] n[0][i] = newSymNode(v) - if sfGenSym notin v.flags: addDecl(c, v) + if sfGenSym notin v.flags and not isDiscardUnderscore(v): addDecl(c, v) elif v.owner == nil: v.owner = getCurrOwner(c) else: var v = symForVar(c, n[0]) @@ -749,7 +749,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = # for an example: v.typ = iterBase n[0] = newSymNode(v) - if sfGenSym notin v.flags: addDecl(c, v) + if sfGenSym notin v.flags and not isDiscardUnderscore(v): addDecl(c, v) elif v.owner == nil: v.owner = getCurrOwner(c) else: localError(c.config, n.info, errWrongNumberOfVariables) diff --git a/tests/stmt/tforloop_tuple_multiple_underscore.nim b/tests/stmt/tforloop_tuple_multiple_underscore.nim new file mode 100644 index 000000000..2afdb0b77 --- /dev/null +++ b/tests/stmt/tforloop_tuple_multiple_underscore.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "undeclared identifier: '_'" +""" + +iterator iter(): (int, int, int) = + yield (1, 1, 2) + + +for (_, i, _) in iter(): + echo _ \ No newline at end of file diff --git a/tests/stmt/tforloop_tuple_underscore.nim b/tests/stmt/tforloop_tuple_underscore.nim new file mode 100644 index 000000000..8cbb0fc10 --- /dev/null +++ b/tests/stmt/tforloop_tuple_underscore.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "undeclared identifier: '_'" +""" + +iterator iter(): (int, int) = + yield (1, 2) + yield (3, 4) + yield (1, 2) + yield (3, 4) + yield (1, 2) + yield (3, 4) + + +for (_, i) in iter(): + echo _ + diff --git a/tests/stmt/tforloop_underscore.nim b/tests/stmt/tforloop_underscore.nim new file mode 100644 index 000000000..c5b49da77 --- /dev/null +++ b/tests/stmt/tforloop_underscore.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "undeclared identifier: '_'" +""" + +for _ in ["a"]: + echo _ From e6e1e9574de8c090cb9de7a809064037e2af39f7 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 18 Nov 2020 15:28:05 +0800 Subject: [PATCH 1501/4254] combine PR#16009 and PR#16012 (#16024) * fix #15623 * add testcase for #15623 * add testcase * combine #16009 * support casting nil to NilableTypes in VM --- compiler/semfold.nim | 2 +- compiler/vmgen.nim | 5 +++++ tests/misc/tcast.nim | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 9b21c5fa3..f38359a64 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -674,7 +674,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkCast: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return - if n.typ != nil and n.typ.kind in NilableTypes: + if n.typ != nil and n.typ.kind in NilableTypes and a.kind != nkNilLit: # we allow compile-time 'cast' for pointer types: result = a result.typ = n.typ diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bcb7faa47..84ff1a91d 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -901,6 +901,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = c.gABx(n, opcSetType, dest, c.genType(dst)) c.gABC(n, opcCastIntToPtr, dest, tmp) c.freeTemp(tmp) + elif src.kind == tyNil and dst.kind in NilableTypes: + # supports casting nil literals to NilableTypes in VM + # see #16024 + if dest < 0: dest = c.getTemp(n[0].typ) + genLit(c, n[1], dest) else: # todo: support cast from tyInt to tyRef globalError(c.config, n.info, "VM does not support 'cast' from " & $src.kind & " to " & $dst.kind) diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index 745b9e221..12179cb1c 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -29,3 +29,47 @@ reject: discard cast[enum](0) proc a = echo "hi" reject: discard cast[ptr](a) + +# bug #15623 +block: + if false: + echo cast[ptr int](nil)[] + +block: + if false: + var x: ref int = nil + echo cast[ptr int](x)[] + +block: + doAssert cast[int](cast[ptr int](nil)) == 0 + +block: + var x: ref int = nil + doAssert cast[int](cast[ptr int](x)) == 0 + +block: + block: + static: + let a = cast[pointer](nil) + doAssert a.repr == "nil" + + block: + static: + doAssert cast[ptr int](nil).repr == "nil" + + block: + const str = cast[ptr int](nil) + static: + doAssert str.repr == "nil" + + block: + static: + doAssert cast[ptr int](nil).repr == "nil" + + block: + static: + doAssert cast[RootRef](nil).repr == "nil" + + block: + static: + doAssert cast[cstring](nil).repr == "nil" From 581bcfe29094f525d2ab4e27455bed18a3eac811 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 18 Nov 2020 15:56:31 +0800 Subject: [PATCH 1502/4254] fix #6497 (#16027) * fix #6497 * add testcase for #16027 --- compiler/ast.nim | 1 + tests/ccgbugs/t16027.nim | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/ccgbugs/t16027.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 3d14aba66..c75a149c0 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1441,6 +1441,7 @@ proc copySym*(s: PSym; id: ItemId): PSym = result.position = s.position result.loc = s.loc result.annex = s.annex # BUGFIX + result.constraint = s.constraint if result.kind in {skVar, skLet, skField}: result.guard = s.guard result.bitsize = s.bitsize diff --git a/tests/ccgbugs/t16027.nim b/tests/ccgbugs/t16027.nim new file mode 100644 index 000000000..58f15eb6e --- /dev/null +++ b/tests/ccgbugs/t16027.nim @@ -0,0 +1,13 @@ +discard """ + ccodecheck: "__restrict__" + action: compile + joinable: false +""" + +# see bug #16027 +iterator myitems(s: seq[int]): int = + var data {.codegenDecl: "$# __restrict__ $#".} : ptr int = nil + yield 1 + +for i in @[1].myitems: + discard From 33d79b9e64f8f67adcf8415de61d1568630e36cb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Nov 2020 03:01:43 -0800 Subject: [PATCH 1503/4254] fix https://github.com/nim-lang/RFCs/issues/286: add FileInfo.blockSize (#16023) --- changelog.md | 2 ++ lib/pure/os.nim | 71 ++++++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/changelog.md b/changelog.md index 200214ff3..ce06a23bc 100644 --- a/changelog.md +++ b/changelog.md @@ -38,6 +38,8 @@ - Added `asyncdispatch.activeDescriptors` that returns the number of currently active async event handles/file descriptors +- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, + determining preferred I/O block size for this file object. ## Language changes diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 234d82bc2..aa2a1aaa8 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1550,40 +1550,6 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", else: result = a.st_dev == b.st_dev and a.st_ino == b.st_ino -proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [ReadIOEffect], noWeirdTarget.} = - ## Returns true if both pathname arguments refer to files with identical - ## binary content. - ## - ## See also: - ## * `sameFile proc <#sameFile,string,string>`_ - const - bufSize = 8192 # 8K buffer - var - a, b: File - if not open(a, path1): return false - if not open(b, path2): - close(a) - return false - var bufA = alloc(bufSize) - var bufB = alloc(bufSize) - while true: - var readA = readBuffer(a, bufA, bufSize) - var readB = readBuffer(b, bufB, bufSize) - if readA != readB: - result = false - break - if readA == 0: - result = true - break - result = equalMem(bufA, bufB, readA) - if not result: break - if readA != bufSize: break # end of file - dealloc(bufA) - dealloc(bufB) - close(a) - close(b) - type FilePermission* = enum ## File access permission, modelled after UNIX. ## @@ -3074,6 +3040,8 @@ type lastAccessTime*: times.Time ## Time file was last accessed. lastWriteTime*: times.Time ## Time file was last modified/written to. creationTime*: times.Time ## Time file was created. Not supported on all systems! + blockSize*: int ## Preferred I/O block size for this object. + ## In some filesystems, this may vary from file to file. template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = ## Transforms the native file info structure into the one nim uses. @@ -3088,6 +3056,7 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime)) formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime)) formalInfo.creationTime = fromWinTime(rdFileTime(rawInfo.ftCreationTime)) + formalInfo.blockSize = 8192 # xxx use windows API instead of hardcoding # Retrieve basic permissions if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32: @@ -3114,6 +3083,7 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.lastAccessTime = rawInfo.st_atim.toTime formalInfo.lastWriteTime = rawInfo.st_mtim.toTime formalInfo.creationTime = rawInfo.st_ctim.toTime + formalInfo.blockSize = rawInfo.st_blksize formalInfo.permissions = {} checkAndIncludeMode(S_IRUSR, fpUserRead) @@ -3217,6 +3187,39 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget. raiseOSError(osLastError(), path) rawToFormalFileInfo(rawInfo, path, result) +proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", + tags: [ReadIOEffect], noWeirdTarget.} = + ## Returns true if both pathname arguments refer to files with identical + ## binary content. + ## + ## See also: + ## * `sameFile proc <#sameFile,string,string>`_ + var + a, b: File + if not open(a, path1): return false + if not open(b, path2): + close(a) + return false + let bufSize = getFileInfo(a).blockSize + var bufA = alloc(bufSize) + var bufB = alloc(bufSize) + while true: + var readA = readBuffer(a, bufA, bufSize) + var readB = readBuffer(b, bufB, bufSize) + if readA != readB: + result = false + break + if readA == 0: + result = true + break + result = equalMem(bufA, bufB, readA) + if not result: break + if readA != bufSize: break # end of file + dealloc(bufA) + dealloc(bufB) + close(a) + close(b) + proc isHidden*(path: string): bool {.noWeirdTarget.} = ## Determines whether ``path`` is hidden or not, using `this ## reference `_. From 87d3e5331a7838aa255deca8a840c2080b5424ce Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 18 Nov 2020 17:19:57 +0000 Subject: [PATCH 1504/4254] Semfold for nil cast (#16030) * bring back the semfold of nil * remove space * fix test * proc type can't be dereferenced --- compiler/ccgexprs.nim | 4 +++- compiler/semfold.nim | 2 +- tests/misc/tcast.nim | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a3fbeca5f..ec28eb1ec 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -71,8 +71,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = p.module.s[cfsData].addf( "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", [getTypeDesc(p.module, ty), result]) - else: + elif k in {tyPointer, tyNil, tyProc}: result = rope("NIM_NIL") + else: + result = "(($1) NIM_NIL)" % [getTypeDesc(p.module, ty)] of nkStrLit..nkTripleStrLit: let k = if ty == nil: tyString else: skipTypes(ty, abstractVarRange + {tyStatic, tyUserTypeClass, tyUserTypeClassInst}).kind diff --git a/compiler/semfold.nim b/compiler/semfold.nim index f38359a64..9b21c5fa3 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -674,7 +674,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkCast: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return - if n.typ != nil and n.typ.kind in NilableTypes and a.kind != nkNilLit: + if n.typ != nil and n.typ.kind in NilableTypes: # we allow compile-time 'cast' for pointer types: result = a result.typ = n.typ diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index 12179cb1c..6c6de6f8d 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -70,6 +70,7 @@ block: static: doAssert cast[RootRef](nil).repr == "nil" - block: - static: - doAssert cast[cstring](nil).repr == "nil" + # Issue #15730, not fixed yet + # block: + # static: + # doAssert cast[cstring](nil).repr == "nil" From baaa19b92751598b6519a64eed2b1beb06b2e662 Mon Sep 17 00:00:00 2001 From: Igor Ribeiro de Assis Date: Wed, 18 Nov 2020 20:55:49 +0100 Subject: [PATCH 1505/4254] Do not read the whole file to compute SHA1 hash (fixes 15997) (#16006) * Do not read the whole file to compute SHA1 hash (fixes 15997) * Update lib/std/sha1.nim Co-authored-by: Andreas Rumpf * Update lib/std/sha1.nim Co-authored-by: Andreas Rumpf * Directly break from loop Co-authored-by: Andreas Rumpf [backport:1.2] [backport:1.4] --- lib/std/sha1.nim | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 8f35a44ff..9763b286e 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -213,7 +213,22 @@ proc secureHashFile*(filename: string): SecureHash = ## **See also:** ## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string ## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash`` - secureHash(readFile(filename)) + const BufferLength = 8192 + + let f = open(filename) + var state = newSha1State() + var buffer = newString(BufferLength) + while true: + let length = readChars(f, buffer, 0, BufferLength) + if length == 0: + break + buffer.setLen(length) + state.update(buffer) + if length != BufferLength: + break + close(f) + + SecureHash(state.finalize()) proc `$`*(self: SecureHash): string = ## Returns the string representation of a ``SecureHash``. From b9eb91cbb5c8104955e595808d4b4d388894d406 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Nov 2020 22:31:06 +0100 Subject: [PATCH 1506/4254] ORC: prepare for another patent-pending optimization (#15996) * ORC: prepare for another patent-pending optimization * bugfix * '=copy' for refs can take a cyclic parameter for more ORC optimizations * ORC: exploit the common 'it = it.next' pattern * can't hurt to check for nil * use an algorithm that is not obviously broken * restore the test case * final cleanups for --gc:orc --- changelog.md | 4 +++ compiler/injectdestructors.nim | 49 ++++++++++++++++++++++++++++-- compiler/liftdestructors.nim | 55 +++++++++++++++++++++++++++------- lib/system/arc.nim | 17 ++++++----- lib/system/cyclebreaker.nim | 4 ++- lib/system/orc.nim | 55 +++++++++++++++++++++++----------- tests/arc/tasyncleak.nim | 2 +- 7 files changed, 147 insertions(+), 39 deletions(-) diff --git a/changelog.md b/changelog.md index ce06a23bc..7cbd4bb66 100644 --- a/changelog.md +++ b/changelog.md @@ -38,6 +38,10 @@ - Added `asyncdispatch.activeDescriptors` that returns the number of currently active async event handles/file descriptors +- ``--gc:orc`` is now 10% faster than previously for common workloads. If + you have trouble with its changed behavior, compile with ``-d:nimOldOrc``. + + - `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, determining preferred I/O block size for this file object. diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 7e64ebfdc..869e8ecc8 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -311,6 +311,43 @@ proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = # and copyMem(dest, source). This is efficient. result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri)) +proc isCriticalLink(dest: PNode): bool {.inline.} = + #[ + Lins's idea that only "critical" links can introduce a cycle. This is + critical for the performance gurantees that we strive for: If you + traverse a data structure, no tracing will be performed at all. + ORC is about this promise: The GC only touches the memory that the + mutator touches too. + + These constructs cannot possibly create cycles:: + + local = ... + + new(x) + dest = ObjectConstructor(field: noalias(dest)) + + But since 'ObjectConstructor' is already moved into 'dest' all we really have + to look for is assignments to local variables. + ]# + result = dest.kind != nkSym + +proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) = + if c.graph.config.selectedGC == gcOrc: + let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}) + if cyclicType(t): + result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest)) + +proc genMarkCyclic(c: var Con; result, dest: PNode) = + if c.graph.config.selectedGC == gcOrc: + let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}) + if cyclicType(t): + if t.kind == tyRef: + result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest) + else: + let xenv = genBuiltin(c.graph, mAccessEnv, "accessEnv", dest) + xenv.typ = getSysType(c.graph, dest.info, tyPointer) + result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv) + proc genCopyNoCheck(c: var Con; dest, ri: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) result = c.genOp(t, attachedAsgn, dest, ri) @@ -390,7 +427,9 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = v.add(vpart) result.add v - let wasMovedCall = c.genWasMoved(skipConv(n)) + let nn = skipConv(n) + c.genMarkCyclic(result, nn) + let wasMovedCall = c.genWasMoved(nn) result.add wasMovedCall result.add tempAsNode @@ -405,6 +444,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result.add c.genWasMoved(tmp) var m = c.genCopy(tmp, n) m.add p(n, c, s, normal) + c.finishCopy(m, n, isFromSink = true) result.add m if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, @@ -667,6 +707,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = let tmp = c.getTemp(s, n[0].typ, n.info) var m = c.genCopyNoCheck(tmp, n[0]) m.add p(n[0], c, s, normal) + c.finishCopy(m, n[0], isFromSink = false) result = newTree(nkStmtList, c.genWasMoved(tmp), m) var toDisarm = n[0] if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon @@ -941,16 +982,18 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod else: result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) of nkBracket: # array constructor if ri.len > 0 and isDangerousSeq(ri.typ): result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) else: result = c.genSink(dest, p(ri, c, s, consumed), isDecl) of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkSym: + of nkSym: if dest.kind == nkSym and dest.sym == ri.sym: # rule (self-assignment-removal): result = newNodeI(nkEmpty, dest.info) @@ -966,6 +1009,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod else: result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: @@ -983,6 +1027,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod else: result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) proc computeUninit(c: var Con) = if not c.uninitComputed: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 45a66e795..512fb6190 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -65,7 +65,7 @@ proc newAsgnStmt(le, ri: PNode): PNode = result[0] = le result[1] = ri -proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = +proc genBuiltin*(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = result = newNodeI(nkCall, i.info) result.add createMagic(g, name, magic).newSymNode result.add i @@ -248,6 +248,19 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = else: fillBodyObjTImpl(c, t, body, x, y) +proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode = + result = newIntLit(g, info, ord value) + result.typ = getSysType(g, info, tyBool) + +proc getCycleParam(c: TLiftCtx): PNode = + assert c.kind == attachedAsgn + if c.fn.typ.len == 4: + result = c.fn.typ.n.lastSon + assert result.kind == nkSym + assert result.sym.name.s == "cyclic" + else: + result = boolLit(c.g, c.info, true) + proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = #if sfError in op.flags: # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) @@ -261,6 +274,13 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result.add x if y != nil: result.add y + if op.typ.len == 4: + assert y != nil + if c.fn.typ.len == 4: + result.add getCycleParam(c) + else: + # assume the worst: A cycle is created: + result.add boolLit(c.g, y.info, true) proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = result = newNodeIT(nkCall, x.info, op.typ[0]) @@ -526,6 +546,12 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" +proc cyclicType*(t: PType): bool = + case t.kind + of tyRef: result = types.canFormAcycle(t.lastSon) + of tyProc: result = t.callConv == ccClosure + else: result = false + proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = #[ bug #15753 is really subtle. Usually the classical write barrier for reference counting looks like this:: @@ -588,12 +614,13 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) of attachedAsgn: - body.add genIf(c, y, callCodegenProc(c.g, - if isCyclic: "nimIncRefCyclic" else: "nimIncRef", c.info, y)) if isCyclic: + body.add genIf(c, y, callCodegenProc(c.g, + "nimIncRefCyclic", c.info, y, getCycleParam(c))) body.add newAsgnStmt(x, y) body.add genIf(c, cond, actions) else: + body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y)) body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) of attachedDestructor: @@ -649,14 +676,13 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedAsgn: let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y) yenv.typ = getSysType(c.g, c.info, tyPointer) - let incRefProc = - if c.g.config.selectedGC == gcOrc: "nimIncRefCyclic" - else: "nimIncRef" - body.add genIf(c, yenv, callCodegenProc(c.g, incRefProc, c.info, yenv)) if isCyclic: + body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c))) body.add newAsgnStmt(x, y) body.add genIf(c, cond, actions) else: + body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv)) + body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) of attachedDestructor: @@ -888,6 +914,13 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp if kind notin {attachedDestructor, attachedDispose}: result.typ.addParam src + if kind == attachedAsgn and g.config.selectedGC == gcOrc and + cyclicType(typ.skipTypes(abstractInst)): + let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), + nextId(idgen), result, info) + cycleParam.typ = getSysType(g, info, tyBool) + result.typ.addParam cycleParam + var n = newNodeI(nkProcDef, info, bodyPos+1) for i in 0..= roots.len or idx < 0: cprintf("[Bug!] %ld\n", idx) quit 1 roots.d[idx] = roots.d[roots.len-1] - roots.d[idx][0].rootIdx = idx + roots.d[idx][0].rootIdx = idx+1 dec roots.len + s.rootIdx = 0 proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = #[ @@ -245,7 +263,7 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = collectWhite(t) free(s) # watch out, a bug here! ]# - if s.color == colWhite and (s.rc and isCycleCandidate) == 0: + if s.color == colWhite and s.rootIdx == 0: orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty") s.setColor(colBlack) @@ -253,7 +271,7 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = trace(s, desc, j) while j.traceStack.len > 0: let (t, desc) = j.traceStack.pop() - if t.color == colWhite and (t.rc and isCycleCandidate) == 0: + if t.color == colWhite and t.rootIdx == 0: j.toFree.add(t, desc) t.setColor(colBlack) trace(t, desc, j) @@ -284,7 +302,7 @@ proc collectCyclesBacon(j: var GcEnv) = init j.toFree for i in 0 ..< roots.len: let s = roots.d[i][0] - s.rc = s.rc and not isCycleCandidate + s.rootIdx = 0 collectWhite(s, roots.d[i][1], j) for i in 0 ..< j.toFree.len: @@ -341,13 +359,14 @@ proc collectCycles() = getOccupiedMem()) proc registerCycle(s: Cell; desc: PNimTypeV2) = - s.rootIdx = roots.len + s.rootIdx = roots.len+1 if roots.d == nil: init(roots) add(roots, s, desc) if roots.len >= rootsThreshold: collectCycles() - #writeCell("[added root]", s) + when logOrc: + writeCell("[added root]", s, desc) proc GC_runOrc* = ## Forces a cycle collection pass. @@ -379,17 +398,19 @@ proc GC_disableMarkAndSweep*() = ## For ``--gc:orc`` an alias for ``GC_disableOrc``. GC_disableOrc() +when optimizedOrc: + template markedAsCyclic(s: Cell): bool = (s.rc and maybeCycle) != 0 +else: + template markedAsCyclic(s: Cell): bool = true + proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = if isDestroyAction: - if (s.rc and isCycleCandidate) != 0: - s.rc = s.rc and not isCycleCandidate + if s.rootIdx > 0: unregisterCycle(s) else: # do not call 'rememberCycle' again unless this cell # got an 'incRef' event: - #s.setColor colGreen # XXX This is wrong! - if (s.rc and isCycleCandidate) == 0: - s.rc = s.rc or isCycleCandidate + if s.rootIdx == 0 and markedAsCyclic(s): s.setColor colBlack registerCycle(s, desc) diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index 72aa3d4c2..417b67edb 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 4016, deallocCount: 4014)" + outputsub: "(allocCount: 4014, deallocCount: 4012)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ From 2773efa03463edc6c98614d895cc21221080f6cf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Nov 2020 23:06:16 +0100 Subject: [PATCH 1507/4254] fixes db_mysql broken quoting; refs https://github.com/nim-lang/Nim/commit/c16ee37a7106c645a0d17cc6bd8d399e20f61d96#r44209990 [backport:1.4] (#16035) --- lib/impure/db_mysql.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 82f27537c..f0d9d8540 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -130,7 +130,6 @@ proc dbQuote*(s: string): string = of '\r': result.add "\\r" of '\x1a': result.add "\\Z" of '"': result.add "\\\"" - of '%': result.add "\\%" of '\'': result.add "\\'" of '\\': result.add "\\\\" of '_': result.add "\\_" From 557dcfd87d6801138702e087935ad3c7053d5e87 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Nov 2020 14:28:52 -0800 Subject: [PATCH 1508/4254] fix #16033 nim js --gc:arc works and ignores --gc:arc (#16036) --- compiler/commands.nim | 5 ++++- tests/arc/t16033.nim | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/arc/t16033.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 7a94fb612..1ad5ec64c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -499,7 +499,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "project": processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) of "gc": - if conf.backend == backendJs: + if conf.backend == backendJs or conf.command == "js": + # for: bug #16033 + # This might still be imperfect, in rarse corner cases + # (where command is reset in nimscript, maybe). return expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: diff --git a/tests/arc/t16033.nim b/tests/arc/t16033.nim new file mode 100644 index 000000000..59ed22e4d --- /dev/null +++ b/tests/arc/t16033.nim @@ -0,0 +1,10 @@ +discard """ + targets: "c js" + matrix: "--gc:arc" +""" + +# bug #16033 +when defined js: + doAssert not compileOption("gc", "arc") +else: + doAssert compileOption("gc", "arc") From bf8421a2fc7148c41a1073f3e8648d18d78f8f7e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Nov 2020 14:29:32 -0800 Subject: [PATCH 1509/4254] contributing docs: always mentioned referenced issues in PR body (#16038) --- doc/contributing.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 6ddbd65bc..0e87ebc1d 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -378,7 +378,7 @@ General commit rules 1. Important, critical bugfixes that have a tiny chance of breaking somebody's code should be backported to the latest stable release - branch (currently 1.2.x) and maybe also to the 1.0 branch. + branch (currently 1.4.x) and maybe also all the way back to the 1.0.x branch. The commit message should contain the tag ``[backport]`` for "backport to all stable releases" and the tag ``[backport:$VERSION]`` for backporting to the given $VERSION. @@ -417,7 +417,14 @@ General commit rules close it when the PR is committed), wheres issue ``#124`` is referenced (e.g.: partially fixed) and won't close the issue when committed. -6. Commits should be always be rebased against devel (so a fast forward +6. PR body (not just PR title) should contain references to fixed/referenced github + issues, e.g.: `fix #123` or `refs #123`. This is so that you get proper cross + referencing from linked issue to the PR (github won't make those links with just + PR title, and commit messages aren't always sufficient to ensure that, e.g. + can't be changed after a PR is merged). + + +7. Commits should be always be rebased against devel (so a fast forward merge can happen) e.g.: use ``git pull --rebase origin devel``. This is to avoid messing up @@ -426,7 +433,7 @@ General commit rules squash all commits using the script shown in https://github.com/nim-lang/Nim/pull/9356 -7. Do not mix pure formatting changes (e.g. whitespace changes, nimpretty) or +8. Do not mix pure formatting changes (e.g. whitespace changes, nimpretty) or automated changes (e.g. nimfix) with other code changes: these should be in separate commits (and the merge on GitHub should not squash these into 1). From acf8316e502cf46358df220ef4250b7ca96c6c64 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 18 Nov 2020 22:30:28 +0000 Subject: [PATCH 1510/4254] Disallow nil dereference at compile time (#16032) * bring back the semfold of nil * remove space * fix test * proc type can't be dereferenced * disallow nil dereference at compile time * changelog --- changelog.md | 2 +- compiler/semexprs.nim | 5 +++++ compiler/semfold.nim | 4 ++++ tests/misc/tcast.nim | 3 ++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 7cbd4bb66..d53f5b038 100644 --- a/changelog.md +++ b/changelog.md @@ -51,7 +51,7 @@ - The `cstring` doesn't support `[]=` operator in JS backend. - +- nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. ## Compiler changes diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cb119b3e8..608a82715 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1440,6 +1440,11 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode = proc semDeref(c: PContext, n: PNode): PNode = checkSonsLen(n, 1, c.config) n[0] = semExprWithType(c, n[0]) + let a = getConstExpr(c.module, n[0], c.idgen, c.graph) + if a != nil: + if a.kind == nkNilLit: + localError(c.config, n.info, "nil dereference is not allowed") + n[0] = a result = n var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned}) case t.kind diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 9b21c5fa3..b92895b19 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -671,6 +671,10 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode var a = getConstExpr(m, n[1], idgen, g) if a == nil: return result = foldConv(n, a, g, check=true) + of nkDerefExpr, nkHiddenDeref: + let a = getConstExpr(m, n[0], idgen, g) + if a != nil and a.kind == nkNilLit: + localError(g.config, n.info, "nil dereference is not allowed") of nkCast: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index 6c6de6f8d..454801a2d 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -33,7 +33,8 @@ reject: discard cast[ptr](a) # bug #15623 block: if false: - echo cast[ptr int](nil)[] + let x = cast[ptr int](nil) + echo x[] block: if false: From 44442520bc4e402ca8fe5fd60f2601c40f28a9a5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Nov 2020 19:41:01 -0800 Subject: [PATCH 1511/4254] fix numbering in contributing.rst (#16042) --- doc/contributing.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 0e87ebc1d..90330e4f4 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -407,7 +407,6 @@ General commit rules #!/bin/sh git diff --check --cached || exit $? - 5. Describe your commit and use your common sense. Example commit message: @@ -418,11 +417,10 @@ General commit rules (e.g.: partially fixed) and won't close the issue when committed. 6. PR body (not just PR title) should contain references to fixed/referenced github - issues, e.g.: `fix #123` or `refs #123`. This is so that you get proper cross - referencing from linked issue to the PR (github won't make those links with just - PR title, and commit messages aren't always sufficient to ensure that, e.g. - can't be changed after a PR is merged). - + issues, e.g.: `fix #123` or `refs #123`. This is so that you get proper cross + referencing from linked issue to the PR (github won't make those links with just + PR title, and commit messages aren't always sufficient to ensure that, e.g. + can't be changed after a PR is merged). 7. Commits should be always be rebased against devel (so a fast forward merge can happen) From 743f2f5faabecc8ed86837d7ae39319300c68817 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Nov 2020 08:30:23 +0100 Subject: [PATCH 1512/4254] makes parsesql .gcsafe [backport:1.0] (#16039) --- lib/pure/parsesql.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 68e75e5fa..0232baf8d 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -679,8 +679,8 @@ proc getPrecedence(p: SqlParser): int = else: result = - 1 -proc parseExpr(p: var SqlParser): SqlNode -proc parseSelect(p: var SqlParser): SqlNode +proc parseExpr(p: var SqlParser): SqlNode {.gcsafe.} +proc parseSelect(p: var SqlParser): SqlNode {.gcsafe.} proc identOrLiteral(p: var SqlParser): SqlNode = case p.tok.kind @@ -1208,7 +1208,7 @@ proc addIden(s: var SqlWriter, thing: string) = iden = '"' & iden & '"' s.add(iden) -proc ra(n: SqlNode, s: var SqlWriter) +proc ra(n: SqlNode, s: var SqlWriter) {.gcsafe.} proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") = if n.len > 0: From 1bcc3521371ec6a8c136e42d902a0be7c50d9745 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 19 Nov 2020 15:31:54 +0800 Subject: [PATCH 1513/4254] close #14847(add testcase for #14847) (#16045) --- tests/macros/t14847.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/macros/t14847.nim diff --git a/tests/macros/t14847.nim b/tests/macros/t14847.nim new file mode 100644 index 000000000..0e6d0dd2d --- /dev/null +++ b/tests/macros/t14847.nim @@ -0,0 +1,20 @@ +discard """ + output: "98" +""" +import macros + +#bug #14847 +proc hello*(b: string) = + echo b + +macro dispatch(pro: typed, params: untyped): untyped = + var impl = pro.getImpl + let id = ident(pro.strVal & "_coverage") + impl[0] = id + let call = newCall(id, params) + + result = newStmtList() + result.add(impl) + result.add(call) + +dispatch(hello, "98") From 1efd11e2666403fecf1b9b3b933c1adca13d8069 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Nov 2020 13:42:16 +0100 Subject: [PATCH 1514/4254] fixes #15942 [backport:1.2] [backport:1.4] (#16051) --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f0120c435..c2a31b775 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -244,7 +244,7 @@ proc safeLineNm(info: TLineInfo): int = proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) = assert line >= 0 - if optLineDir in conf.options: + if optLineDir in conf.options and line > 0: r.addf("$N#line $2 $1$N", [rope(makeSingleLineCString(filename)), rope(line)]) From b3c3557c338c6cb0992abf9d2d877e927d815ea3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 19 Nov 2020 12:12:51 -0800 Subject: [PATCH 1515/4254] fix #16025 repr now consistent: does not insert trailing newline (#16034) --- changelog.md | 2 + lib/system.nim | 3 + lib/system/repr.nim | 3 +- lib/system/reprjs.nim | 3 +- tests/arc/trepr.nim | 3 + tests/array/tarray.nim | 3 - tests/js/trepr.nim | 73 ++++++++++------------- tests/metatype/tmetatype_various.nim | 3 +- tests/misc/tunsignedconv.nim | 3 +- tests/stdlib/trepr.nim | 87 +++++++++++++++++++--------- tests/stdlib/tstreams.nim | 1 - tests/vm/tmisc_vm.nim | 5 +- 12 files changed, 105 insertions(+), 84 deletions(-) diff --git a/changelog.md b/changelog.md index d53f5b038..4c18ddf1e 100644 --- a/changelog.md +++ b/changelog.md @@ -44,6 +44,8 @@ - `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, determining preferred I/O block size for this file object. +- `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, + see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. ## Language changes diff --git a/lib/system.nim b/lib/system.nim index 1104cb17f..716eb296a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1334,6 +1334,9 @@ proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} = when not defined(nimV2): proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} ## Takes any Nim variable and returns its string representation. + ## No trailing newline is inserted (so `echo` won't add an empty newline). + ## Use `-d:nimLegacyReprWithNewline` to revert to old behavior where newlines + ## were added in some cases. ## ## It works even for complex data graphs with cycles. This is a great ## debugging tool. diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 318e95ebb..ae51a4aab 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -325,5 +325,6 @@ when not defined(useNimRtl): else: var p = p reprAux(result, addr(p), typ, cl) - add result, "\n" + when defined(nimLegacyReprWithNewline): # see PR #16034 + add result, "\n" deinitReprClosure(cl) diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 9c27a4721..36972024a 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -237,4 +237,5 @@ proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} = var cl: ReprClosure initReprClosure(cl) reprAux(result, p, typ, cl) - add(result, "\n") + when defined(nimLegacyReprWithNewline): # see PR #16034 + add result, "\n" diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index 9eb2ed43f..3c1e4129c 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -11,6 +11,9 @@ Obj(member: ref @["hello"]) ref (member: ref @["hello"]) ''' """ + +# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage + import tables type diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index 27288bab3..eadb53ac1 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -1,11 +1,8 @@ discard """ output: ''' [4, 5, 6] - [16, 25, 36] - [16, 25, 36] - apple banana Fruit diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim index eb285f70d..c63b64d3a 100644 --- a/tests/js/trepr.nim +++ b/tests/js/trepr.nim @@ -1,6 +1,4 @@ -discard """ - action: run -""" +# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage block ints: let @@ -137,15 +135,13 @@ block tuples: when defined js: doAssert(repr(ot) == """ [Field0 = true, -Field1 = 120] -""") +Field1 = 120]""") doAssert(repr(t) == """ [Field0 = 42, Field1 = 12.34, Field2 = "tuple", Field3 = [Field0 = true, -Field1 = 120]] -""") +Field1 = 120]]""") block objects: type @@ -162,14 +158,12 @@ block objects: doAssert(repr(oo) == """ [a = true, -b = 120] -""") +b = 120]""") doAssert(repr(o) == """ [a = 42, b = 12.34, c = [a = true, -b = 120]] -""") +b = 120]]""") block arrays: type @@ -183,15 +177,14 @@ block arrays: c = [o, o, o] d = ["hi", "array", "!"] - doAssert(repr(a) == "[0.0, 1.0, 2.0]\n") - doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]\n") + doAssert(repr(a) == "[0.0, 1.0, 2.0]") + doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]") doAssert(repr(c) == """ [[x = 42, y = [0.0, 1.0, 2.0]], [x = 42, y = [0.0, 1.0, 2.0]], [x = 42, -y = [0.0, 1.0, 2.0]]] -""") - doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]\n") +y = [0.0, 1.0, 2.0]]]""") + doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]") block seqs: type @@ -205,15 +198,14 @@ block seqs: c = @[o, o, o] d = @["hi", "array", "!"] - doAssert(repr(a) == "@[0.0, 1.0, 2.0]\n") - doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]\n") + doAssert(repr(a) == "@[0.0, 1.0, 2.0]") + doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]") doAssert(repr(c) == """ @[[x = 42, y = @[0.0, 1.0, 2.0]], [x = 42, y = @[0.0, 1.0, 2.0]], [x = 42, -y = @[0.0, 1.0, 2.0]]] -""") - doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]\n") +y = @[0.0, 1.0, 2.0]]]""") + doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]") block ptrs: type @@ -226,13 +218,12 @@ block ptrs: c = addr a[2] d = AObj() - doAssert(repr(a) == "[12.0, 13.0, 14.0]\n") - doAssert(repr(b) == "ref 0 --> 12.0\n") - doAssert(repr(c) == "ref 2 --> 14.0\n") + doAssert(repr(a) == "[12.0, 13.0, 14.0]") + doAssert(repr(b) == "ref 0 --> 12.0") + doAssert(repr(c) == "ref 2 --> 14.0") doAssert(repr(d) == """ [x = nil, -y = 0] -""") +y = 0]""") block ptrs: type @@ -248,8 +239,7 @@ block ptrs: [x = ref 0 --> [[x = nil, y = 0], [x = nil, y = 0]], -y = 0] -""") +y = 0]""") block procs: proc test(): int = @@ -258,9 +248,9 @@ block procs: ptest = test nilproc: proc(): int - doAssert(repr(test) == "0\n") - doAssert(repr(ptest) == "0\n") - doAssert(repr(nilproc) == "nil\n") + doAssert(repr(test) == "0") + doAssert(repr(ptest) == "0") + doAssert(repr(nilproc) == "nil") block bunch: type @@ -322,8 +312,7 @@ o = [Field0 = [a = "", b = @[]], Field1 = ""], p = nil, -q = nil] -""") +q = nil]""") doAssert(repr(cc) == """ [a = 12, b = 1, @@ -346,8 +335,7 @@ o = [Field0 = [a = "inner", b = @['o', 'b', 'j']], Field1 = "tuple!"], p = 0, -q = "cstringtest"] -""") +q = "cstringtest"]""") block another: type @@ -358,9 +346,9 @@ block another: Size3 = enum s3e=0, s3f=2000000000 - doAssert(repr([s1a, s1b]) == "[s1a, s1b]\n") - doAssert(repr([s2c, s2d]) == "[s2c, s2d]\n") - doAssert(repr([s3e, s3f]) == "[s3e, s3f]\n") + doAssert(repr([s1a, s1b]) == "[s1a, s1b]") + doAssert(repr([s2c, s2d]) == "[s2c, s2d]") + doAssert(repr([s3e, s3f]) == "[s3e, s3f]") block another2: @@ -395,15 +383,13 @@ block another2: y = 13, z = 45, s = ["abc", "xyz"], -e = en6] -""") +e = en6]""") doAssert(repr(q) == """ ref 0 --> [x = 0, y = 13, z = 45, s = ["abc", "xyz"], -e = en6] -""") +e = en6]""") doAssert(repr(s) == """ @[ref 0 --> [x = 0, y = 13, @@ -421,8 +407,7 @@ e = en6], ref 3 --> [x = 0, y = 13, z = 45, s = ["abc", "xyz"], -e = en6]] -""") +e = en6]]""") doAssert(repr(en4) == "en4") doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}") diff --git a/tests/metatype/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim index 0dd948293..9faeeec4a 100644 --- a/tests/metatype/tmetatype_various.nim +++ b/tests/metatype/tmetatype_various.nim @@ -1,6 +1,5 @@ discard """ - output: '''[1, 0, 0, 0, 0, 0, 0, 0] - CTBool[Ct[system.uint32]]''' + output: '''[1, 0, 0, 0, 0, 0, 0, 0] CTBool[Ct[system.uint32]]''' """ block tconstraints: diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index e9a2a2189..b9463b5f0 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -67,8 +67,7 @@ let limit = 1'u64 let rangeVar = 0'u64 ..< limit doAssert repr(rangeVar) == """[a = 0, -b = 0] -""" +b = 0]""" # bug #15210 diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index c1941bd38..1d89d37b2 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -1,36 +1,69 @@ discard """ - output: '''{a, b}{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} -[1, 2, 3, 4, 5, 6]''' + targets: "c cpp js" + matrix: ";--gc:arc" """ -type - TEnum = enum - a, b +# if excessive, could remove 'cpp' from targets -var val = {a, b} -stdout.write(repr(val)) -stdout.writeLine(repr({'a'..'z', 'A'..'Z'})) +from strutils import endsWith, contains -type - TObj {.pure, inheritable.} = object - data: int - TFoo = ref object of TObj - d2: float -var foo: TFoo -new(foo) +template main() = + doAssert repr({3,5}) == "{3, 5}" -when false: - # cannot capture this output as it contains a memory address :-/ - echo foo.repr -#var testseq: seq[string] = @[ -# "a", "b", "c", "d", "e" -#] -#echo(repr(testseq)) + block: + type TEnum = enum a, b + var val = {a, b} + when nimvm: + discard + #[ + # BUG: + {0, 1} + {97..99, 65..67} + ]# + else: + doAssert repr(val) == "{a, b}" + doAssert repr({'a'..'c', 'A'..'C'}) == "{'A', 'B', 'C', 'a', 'b', 'c'}" -# bug #7878 -proc test(variable: var openarray[int]) = - echo repr(variable) + type + TObj {.pure, inheritable.} = object + data: int + TFoo = ref object of TObj + d2: float + var foo: TFoo + new(foo) -var arr = [1, 2, 3, 4, 5, 6] + #[ + BUG: + --gc:arc returns `"abc"` + regular gc returns with address, e.g. 0x1068aae60"abc", but only + for c,cpp backends (not js, vm) + ]# + block: + doAssert repr("abc").endsWith "\"abc\"" + var b: cstring = "def" + doAssert repr(b).endsWith "\"def\"" -test(arr) + block: + var c = @[1,2] + when nimvm: + discard # BUG: this shows [1, 2] instead of @[1, 2] + else: + # BUG (already mentioned above): some backends / gc show address, others don't + doAssert repr(c).endsWith "@[1, 2]" + + let d = @["foo", "bar"] + let s = repr(d) + # depending on backend/gc, we get 0x106a1c350@[0x106a1c390"foo", 0x106a1c3c0"bar"] + doAssert "\"foo\"," in s + + var arr = [1, 2, 3] + doAssert repr(arr) == "[1, 2, 3]" + + block: # bug #7878 + proc reprOpenarray(variable: var openarray[int]): string = repr(variable) + when defined(js): discard # BUG: doesn't work + else: + doAssert reprOpenarray(arr) == "[1, 2, 3]" + +static: main() +main() diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 6979bae38..0fe6b6933 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -4,7 +4,6 @@ discard """ Hello! What is your name? Nice name: Arne fs is: nil - threw exception _heh_ ''' diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim index 6eeecb869..2d3e30c5e 100644 --- a/tests/vm/tmisc_vm.nim +++ b/tests/vm/tmisc_vm.nim @@ -1,7 +1,6 @@ discard """ - output: '''[127, 127, 0, 255] -[127, 127, 0, 255] - + output: ''' +[127, 127, 0, 255][127, 127, 0, 255] (data: 1) ''' From 59332ec2352aa1d1c0fa4401eff7fefe8f4187da Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Fri, 20 Nov 2020 02:09:30 +0200 Subject: [PATCH 1516/4254] Improve enumerate (#16053) * Improve enumerate * updates * add tests --- lib/std/enumerate.nim | 53 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim index 4620af94d..3def653c8 100644 --- a/lib/std/enumerate.nim +++ b/lib/std/enumerate.nim @@ -28,29 +28,62 @@ macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = let c = "abcd" var d: seq[(int, char)] - for i, x in enumerate(97, c): + for (i, x) in enumerate(97, c): d.add((i, x)) assert d == @[(97, 'a'), (98, 'b'), (99, 'c'), (100, 'd')] + template genCounter(x): untyped = + # We strip off the first for loop variable and use it as an integer counter. + # We must immediately decrement it by one, because it gets incremented before + # the loop body - to be able to use the final expression in other macros. + newVarStmt(x, infix(countStart, "-", newLit(1))) + + template genInc(x): untyped = + newCall(bindSym"inc", x) + expectKind x, nnkForStmt # check if the starting count is specified: var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1] result = newStmtList() - # We strip off the first for loop variable and use it as an integer counter. - # We must immediately decrement it by one, because it gets incremented before - # the loop body - to be able to use the final expression in other macros. - result.add newVarStmt(x[0], infix(countStart, "-", newLit(1))) var body = x[^1] if body.kind != nnkStmtList: body = newTree(nnkStmtList, body) - body.insert(0, newCall(bindSym"inc", x[0])) var newFor = newTree(nnkForStmt) - for i in 1..x.len-3: - newFor.add x[i] + if x.len == 3: # single iteration variable + if x[0].kind == nnkVarTuple: # for (x, y, ...) in iter + result.add genCounter(x[0][0]) + body.insert(0, genInc(x[0][0])) + for i in 1 .. x[0].len-2: + newFor.add x[0][i] + else: + error("Missing second for loop variable") # for x in iter + else: # for x, y, ... in iter + result.add genCounter(x[0]) + body.insert(0, genInc(x[0])) + for i in 1 .. x.len-3: + newFor.add x[i] # transform enumerate(X) to 'X' newFor.add x[^2][^1] newFor.add body result.add newFor # now wrap the whole macro in a block to create a new scope - result = quote do: - block: `result` + result = newBlockStmt(result) + +when isMainModule: + let a = @[1, 3, 5, 7] + + block: + var res: seq[(int, int)] + for i, x in enumerate(a): + res.add (i, x) + assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] + block: + var res: seq[(int, int)] + for (i, x) in enumerate(a.items): + res.add (i, x) + assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] + block: + var res: seq[(int, int)] + for i, x in enumerate(3, a): + res.add (i, x) + assert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] From 109cc45398bcdafc22f0a5e49cdfda8234bc46de Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 19 Nov 2020 23:07:51 -0800 Subject: [PATCH 1517/4254] packedsets fix regression introduced in #15564 (#16060) * packedsets fix regression introduced in #15564 * add tests --- lib/std/packedsets.nim | 17 +++++++++-------- tests/stdlib/mintsets.nim | 10 ++++++++++ tests/stdlib/tintsets.nim | 6 ++++++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 tests/stdlib/mintsets.nim create mode 100644 tests/stdlib/tintsets.nim diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index 20002d07f..be0555d3a 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -265,7 +265,7 @@ proc incl*[A](s: var PackedSet[A], other: PackedSet[A]) = assert len(a) == 2 assert 5 in a - for item in other: incl(s, item) + for item in other.items: incl(s, item) proc toPackedSet*[A](x: openArray[A]): PackedSet[A] {.since: (1, 3).} = ## Creates a new PackedSet[A] that contains the elements of `x`. @@ -358,7 +358,7 @@ proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) = assert len(a) == 1 assert 5 notin a - for item in other: + for item in other.items: excl(s, item) proc len*[A](s: PackedSet[A]): int {.inline.} = @@ -367,7 +367,8 @@ proc len*[A](s: PackedSet[A]): int {.inline.} = result = s.elems else: result = 0 - for _ in s: + for _ in s.items: + # pending bug #11167; when fixed, check each explicit `items` to see if it can be removed inc(result) proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool = @@ -488,7 +489,7 @@ proc intersection*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## {3} result = initPackedSet[A]() - for item in s1: + for item in s1.items: if contains(s2, item): incl(result, item) @@ -506,7 +507,7 @@ proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## {1, 2} result = initPackedSet[A]() - for item in s1: + for item in s1.items: if not contains(s2, item): incl(result, item) @@ -522,7 +523,7 @@ proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## {1, 2, 4, 5} result.assign(s1) - for item in s2: + for item in s2.items: if containsOrIncl(result, item): excl(result, item) proc `+`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = @@ -549,7 +550,7 @@ proc disjoint*[A](s1, s2: PackedSet[A]): bool = b.excl(2) assert disjoint(a, b) == true - for item in s1: + for item in s1.items: if contains(s2, item): return false return true @@ -575,7 +576,7 @@ proc `<=`*[A](s1, s2: PackedSet[A]): bool = a.incl(3) assert(not (a <= b)) - for item in s1: + for item in s1.items: if not s2.contains(item): return false return true diff --git a/tests/stdlib/mintsets.nim b/tests/stdlib/mintsets.nim new file mode 100644 index 000000000..b4d9ed516 --- /dev/null +++ b/tests/stdlib/mintsets.nim @@ -0,0 +1,10 @@ +import std/intsets + +proc test1*[]() = + let a = initIntSet() + doAssert len(a) == 0 + +proc test2*[]() = + var a = initIntSet() + var b = initIntSet() + a.incl b diff --git a/tests/stdlib/tintsets.nim b/tests/stdlib/tintsets.nim new file mode 100644 index 000000000..191ef117e --- /dev/null +++ b/tests/stdlib/tintsets.nim @@ -0,0 +1,6 @@ +import ./mintsets + +block: # bug https://github.com/nim-lang/Nim/pull/15564#issuecomment-729878104 + # related to bug #11167 + test1() + test2() From 6cf5ca1dc2c1c0388e0998a24d26f4a9c9b7e60e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 20 Nov 2020 16:06:18 +0800 Subject: [PATCH 1518/4254] alternative way to fix #16022 (#16064) [backport:1.4] * alternative way to fix #16022 * add testcase for #16022 [backport:1.4] --- lib/core/typeinfo.nim | 4 ++-- tests/stdlib/tmarshal.nim | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 00f7c176c..ca531b4b9 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -327,10 +327,10 @@ proc setPointer*(x: Any, y: pointer) = ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. assert x.rawType.kind in pointerLike - if y != nil: + if y != nil and x.rawType.kind != tyPointer: genericAssign(x.value, y, x.rawType) else: - cast[ppointer](x.value)[] = nil + cast[ppointer](x.value)[] = y proc fieldsAux(p: pointer, n: ptr TNimNode, ret: var seq[tuple[name: cstring, any: Any]]) = diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index 315036631..d76be73f3 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -7,6 +7,7 @@ omega 200 Some(null) None[JsonNode] (numeric: "") +hello world ''' joinable: false """ @@ -138,7 +139,7 @@ block: echo ($$a2).to[:Option[JsonNode]] -# bug #15620 +# bug #15620 block: let str = """{"numeric": null}""" @@ -148,3 +149,9 @@ block: let test = to[LegacyEntry](str) echo test + +# bug #16022 +block: + let p: proc () = proc () = echo "hello world" + let poc = (to[typeof(p)]($$p)) + poc() From 7815ed69d4a3fc7b96c397c7820cef290f5b0a4d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 20 Nov 2020 01:51:14 -0800 Subject: [PATCH 1519/4254] rename loadConfigsAndRunMainCommand => loadConfigsAndProcessCmdLine, reflect reality (#16057) --- compiler/cmdlinehelper.nim | 2 +- compiler/nim.nim | 2 +- drnim/drnim.nim | 2 +- nimsuggest/nimsuggest.nim | 4 ++-- tools/nimfind.nim | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index d5a26717d..ffbb0d40b 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -57,7 +57,7 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = else: conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir()) -proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef; +proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: ConfigRef; graph: ModuleGraph): bool = if self.suggestMode: conf.command = "nimsuggest" diff --git a/compiler/nim.nim b/compiler/nim.nim index 9ff0eedbc..e3725f803 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -79,7 +79,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = self.processCmdLineAndProjectPath(conf) var graph = newModuleGraph(cache, conf) - if not self.loadConfigsAndRunMainCommand(cache, conf, graph): + if not self.loadConfigsAndProcessCmdLine(cache, conf, graph): return mainCommand(graph) if conf.hasHint(hintGCStats): echo(GC_getStatistics()) diff --git a/drnim/drnim.nim b/drnim/drnim.nim index b4761a398..d68175c83 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1269,7 +1269,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = self.processCmdLineAndProjectPath(conf) var graph = newModuleGraph(cache, conf) - if not self.loadConfigsAndRunMainCommand(cache, conf, graph): return + if not self.loadConfigsAndProcessCmdLine(cache, conf, graph): return mainCommand(graph) if conf.hasHint(hintGCStats): echo(GC_getStatistics()) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index afc692241..d438e663c 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -644,7 +644,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = myLog("START " & conf.projectFull.string) var graph = newModuleGraph(cache, conf) - if self.loadConfigsAndRunMainCommand(cache, conf, graph): + if self.loadConfigsAndProcessCmdLine(cache, conf, graph): mainCommand(graph) when isMainModule: @@ -723,7 +723,7 @@ else: myLog("START " & conf.projectFull.string) var graph = newModuleGraph(cache, conf) - if self.loadConfigsAndRunMainCommand(cache, conf, graph): + if self.loadConfigsAndProcessCmdLine(cache, conf, graph): mockCommand(graph) if gLogging: for it in conf.searchPaths: diff --git a/tools/nimfind.nim b/tools/nimfind.nim index f13e86aaa..b120ccd1f 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -228,7 +228,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = conf.prefixDir = AbsoluteDir"" var graph = newModuleGraph(cache, conf) - if self.loadConfigsAndRunMainCommand(cache, conf, graph): + if self.loadConfigsAndProcessCmdLine(cache, conf, graph): mainCommand(graph) handleCmdLine(newIdentCache(), newConfigRef()) From 81a03238eda4955dba2a6949aa6f3fe62d186ea7 Mon Sep 17 00:00:00 2001 From: satoru Date: Fri, 20 Nov 2020 17:55:14 +0800 Subject: [PATCH 1520/4254] colors: Reuse the HexDigits constant in strutils (#16065) Co-authored-by: Xuecong Liao --- lib/pure/colors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index dbcb1b4a2..57b854103 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -475,7 +475,7 @@ proc isColor*(name: string): bool = if name.len == 0: return false if name[0] == '#': for i in 1 .. name.len-1: - if name[i] notin {'0'..'9', 'a'..'f', 'A'..'F'}: return false + if name[i] notin HexDigits: return false result = true else: result = binarySearch(colorNames, name, colorNameCmp) >= 0 From 1ad7e4f30b687564d76272fcd25f13cf98ff3d69 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 20 Nov 2020 12:31:06 +0100 Subject: [PATCH 1521/4254] fix #16047 (#16066) --- doc/tut1.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 415a44f5f..cb4dc1cc9 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -472,13 +472,15 @@ innermost construct, unless a label of a block is given: echo "looping" break # leaves the loop, but not the block echo "still in block" + echo "outside the block" block myblock2: echo "entering block" while true: echo "looping" break myblock2 # leaves the block (and the loop) - echo "still in block" + echo "still in block" # it won't be printed + echo "outside the block" Continue statement From 07ad608fb2a9387fefc61a8eef9e0777660516a9 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 20 Nov 2020 14:11:41 +0100 Subject: [PATCH 1522/4254] Retain backwards compatibility after #16057 (#16068) * Retain backwards compatibility * Fix typo --- compiler/cmdlinehelper.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index ffbb0d40b..4f1ede5d1 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -84,3 +84,7 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi graph.suggestMode = self.suggestMode return true + +proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef; graph: ModuleGraph): bool = + ## Alias for loadConfigsAndProcessCmdLine, here for backwards compatibility + loadConfigsAndProcessCmdLine(self, cache, conf, graph) From fcb2ec4ed69fe924e7e3899e0084f534124255d4 Mon Sep 17 00:00:00 2001 From: cooldome Date: Fri, 20 Nov 2020 13:58:16 +0000 Subject: [PATCH 1523/4254] fix #15958 (#15970) [backport:1.4] * fix #15958 * also cover openArray and VarArgs * more tests * cover even more types * cover even more types * Trigger build * Trigger build * cover sets passed as arrays --- compiler/ccgtypes.nim | 3 ++- tests/lent/tbasic_lent_check.nim | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e3f832d68..142fec056 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -282,7 +282,8 @@ proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = result = false # first parameter and return type is 'lent T'? --> use pass by pointer if s.position == 0 and retType != nil and retType.kind == tyLent: - result = pt.kind != tyVar + result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or + pt.kind == tySet and mapSetType(conf, pt) == ctArray) proc fillResult(conf: ConfigRef; param: PNode) = fillLoc(param.sym.loc, locParam, param, ~"Result", diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index 4389cbc6e..e22f7bb50 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -1,4 +1,5 @@ discard """ + targets: "c cpp" output: "1" """ @@ -14,3 +15,41 @@ proc main = doAssert(not compiles(passToVar(viewInto(x)))) main() + + +#------------------------------------------------------------------------------ +# issue #15958 + +block: + proc byLent[T](a: T): lent T = a + let a = [11,12] + let b = @[21,23] + let ss = {1, 2, 3, 5} + doAssert byLent(a) == [11,12] + doAssert byLent(a).unsafeAddr == a.unsafeAddr + doAssert byLent(b) == @[21,23] + doAssert byLent(b).unsafeAddr == b.unsafeAddr + doAssert byLent(ss) == {1, 2, 3, 5} + doAssert byLent(ss).unsafeAddr == ss.unsafeAddr + + let r = new(float) + r[] = 10.0 + doAssert byLent(r)[] == 10.0 + + let p = create(float) + p[] = 20.0 + doAssert byLent(p)[] == 20.0 + + proc byLent2[T](a: openarray[T]): lent T = a[0] + doAssert byLent2(a) == 11 + doAssert byLent2(a).unsafeAddr == a[0].unsafeAddr + doAssert byLent2(b) == 21 + doAssert byLent2(b).unsafeAddr == b[0].unsafeAddr + + proc byLent3[T](a: varargs[T]): lent T = a[1] + let + x = 10 + y = 20 + z = 30 + doAssert byLent3(x, y, z) == 20 + From d9038ed792b923cfbb9593ab82825fdb48728adc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 20 Nov 2020 18:14:15 +0100 Subject: [PATCH 1524/4254] fixes #15671 [backport:1.4] (#15690) * fixes #15671 [backport:1.4] * progress --- compiler/typeallowed.nim | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index e163b914a..c81819250 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -52,7 +52,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = nil if typ == nil: return nil if containsOrIncl(marker, typ.id): return nil - var t = skipTypes(typ, abstractInst-{tyTypeDesc}) + var t = skipTypes(typ, abstractInst-{tyTypeDesc, tySink}) case t.kind of tyVar, tyLent: if kind in {skProc, skFunc, skConst} and (views notin c.features): @@ -60,7 +60,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, elif t.kind == tyLent and kind != skResult and (views notin c.features): result = t else: - var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc}) + var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc, tySink}) case t2.kind of tyVar, tyLent: if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap @@ -70,6 +70,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, of tyUncheckedArray: if kind != skParam and views notin c.features: result = t else: result = typeAllowedAux(marker, t2[0], kind, c, flags) + of tySink: + result = t else: if kind notin {skParam, skResult} and views notin c.features: result = t else: result = typeAllowedAux(marker, t2, kind, c, flags) @@ -125,12 +127,18 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = t else: result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray}) - of tyVarargs, tySink: + of tyVarargs: # you cannot nest openArrays/sinks/etc. if kind != skParam or taIsOpenArray in flags: result = t else: result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray}) + of tySink: + # you cannot nest openArrays/sinks/etc. + if kind != skParam or taIsOpenArray in flags or t[0].kind in {tySink, tyLent, tyVar}: + result = t + else: + result = typeAllowedAux(marker, t[0], kind, c, flags) of tyUncheckedArray: if kind != skParam and taHeap notin flags: result = t From 5e8ac485a28f12cf66fb6637e4ef86a9afc117e8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 20 Nov 2020 14:16:59 -0800 Subject: [PATCH 1525/4254] followup #15970 strenghten regression tests (#16075) * followup #15970 strenghten regression tests * _ --- tests/lent/tbasic_lent_check.nim | 27 +++++++++++++++------------ tests/misc/taddr.nim | 5 ++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index e22f7bb50..049fa276a 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -1,5 +1,5 @@ discard """ - targets: "c cpp" + targets: "c cpp js" output: "1" """ @@ -16,29 +16,28 @@ proc main = main() - -#------------------------------------------------------------------------------ -# issue #15958 - -block: +template main2 = # bug #15958 proc byLent[T](a: T): lent T = a let a = [11,12] - let b = @[21,23] + let b = @[21,23] let ss = {1, 2, 3, 5} doAssert byLent(a) == [11,12] doAssert byLent(a).unsafeAddr == a.unsafeAddr doAssert byLent(b) == @[21,23] - doAssert byLent(b).unsafeAddr == b.unsafeAddr + when not defined(js): # pending bug #16073 + doAssert byLent(b).unsafeAddr == b.unsafeAddr doAssert byLent(ss) == {1, 2, 3, 5} doAssert byLent(ss).unsafeAddr == ss.unsafeAddr let r = new(float) r[] = 10.0 - doAssert byLent(r)[] == 10.0 + when not defined(js): # pending bug #16073 + doAssert byLent(r)[] == 10.0 - let p = create(float) - p[] = 20.0 - doAssert byLent(p)[] == 20.0 + when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372 + let p = create(float) + p[] = 20.0 + doAssert byLent(p)[] == 20.0 proc byLent2[T](a: openarray[T]): lent T = a[0] doAssert byLent2(a) == 11 @@ -53,3 +52,7 @@ block: z = 30 doAssert byLent3(x, y, z) == 20 +main2() +when false: + # bug: Error: unhandled exception: 'node' is not accessible using discriminant 'kind' of type 'TFullReg' [FieldDefect] + static: main2() diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim index 4d0aebc01..17fccfabe 100644 --- a/tests/misc/taddr.nim +++ b/tests/misc/taddr.nim @@ -97,9 +97,8 @@ block: doAssert a2 == 10 block: - when not defined(cpp): # pending bug #15958 - let a = [11,12] - doAssert byLent(a) == [11,12] + let a = [11,12] + doAssert byLent(a) == [11,12] # bug #15958 let a2 = (11,) doAssert byLent(a2) == (11,) From f3887dea2cc1969981fc62d5c91f1bafef755582 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 22 Nov 2020 04:16:35 +0800 Subject: [PATCH 1526/4254] heapqueue minor improvement (#16088) --- lib/pure/collections/heapqueue.nim | 72 +++++------------------------- tests/stdlib/theapqueue.nim | 53 ++++++++++++++++++++++ 2 files changed, 63 insertions(+), 62 deletions(-) create mode 100644 tests/stdlib/theapqueue.nim diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index ca0666651..244ccbbee 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -57,26 +57,26 @@ type HeapQueue*[T] = object data: seq[T] proc initHeapQueue*[T](): HeapQueue[T] = - ## Create a new empty heap. + ## Creates a new empty heap. ## ## See also: ## * `toHeapQueue proc <#toHeapQueue,openArray[T]>`_ discard proc len*[T](heap: HeapQueue[T]): int {.inline.} = - ## Return the number of elements of `heap`. + ## Returns the number of elements of `heap`. heap.data.len proc `[]`*[T](heap: HeapQueue[T], i: Natural): T {.inline.} = - ## Access the i-th element of `heap`. + ## Accesses the i-th element of `heap`. heap.data[i] proc heapCmp[T](x, y: T): bool {.inline.} = return (x < y) proc siftdown[T](heap: var HeapQueue[T], startpos, p: int) = - ## 'heap' is a heap at all indices >= startpos, except possibly for pos. pos - ## is the index of a leaf with a possibly out-of-order value. Restore the + ## 'heap' is a heap at all indices >= startpos, except possibly for `pos`. `pos` + ## is the index of a leaf with a possibly out-of-order value. Restores the ## heap invariant. var pos = p var newitem = heap[pos] @@ -114,7 +114,7 @@ proc siftup[T](heap: var HeapQueue[T], p: int) = siftdown(heap, startpos, pos) proc push*[T](heap: var HeapQueue[T], item: T) = - ## Push `item` onto heap, maintaining the heap invariant. + ## Pushes `item` onto heap, maintaining the heap invariant. heap.data.add(item) siftdown(heap, 0, len(heap)-1) @@ -133,7 +133,7 @@ proc toHeapQueue*[T](x: openArray[T]): HeapQueue[T] {.since: (1, 3).} = result.push(item) proc pop*[T](heap: var HeapQueue[T]): T = - ## Pop and return the smallest item from `heap`, + ## Pops and returns the smallest item from `heap`, ## maintaining the heap invariant. let lastelt = heap.data.pop() if heap.len > 0: @@ -158,7 +158,7 @@ proc del*[T](heap: var HeapQueue[T], index: Natural) = heap.siftup(index) proc replace*[T](heap: var HeapQueue[T], item: T): T = - ## Pop and return the current smallest value, and add the new item. + ## Pops and returns the current smallest value, and add the new item. ## This is more efficient than pop() followed by push(), and can be ## more appropriate when using a fixed-size heap. Note that the value ## returned may be larger than item! That constrains reasonable uses of @@ -179,7 +179,7 @@ proc pushpop*[T](heap: var HeapQueue[T], item: T): T = siftup(heap, 0) proc clear*[T](heap: var HeapQueue[T]) = - ## Remove all elements from `heap`, making it empty. + ## Removes all elements from `heap`, making it empty. runnableExamples: var heap = initHeapQueue[int]() heap.push(1) @@ -188,7 +188,7 @@ proc clear*[T](heap: var HeapQueue[T]) = heap.data.setLen(0) proc `$`*[T](heap: HeapQueue[T]): string = - ## Turn a heap into its string representation. + ## Turns a heap into its string representation. runnableExamples: var heap = initHeapQueue[int]() heap.push(1) @@ -199,55 +199,3 @@ proc `$`*[T](heap: HeapQueue[T]): string = if result.len > 1: result.add(", ") result.addQuoted(x) result.add("]") - -when isMainModule: - proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = - var tmp = h - result = @[] - while tmp.len > 0: - result.add(pop(tmp)) - - block: # Simple sanity test - var heap = initHeapQueue[int]() - let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] - for item in data: - push(heap, item) - doAssert(heap == data.toHeapQueue) - doAssert(heap[0] == 0) - doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) - - block: # Test del - var heap = initHeapQueue[int]() - let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] - for item in data: push(heap, item) - - heap.del(0) - doAssert(heap[0] == 1) - - heap.del(heap.find(7)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) - - heap.del(heap.find(5)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) - - heap.del(heap.find(6)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) - - heap.del(heap.find(2)) - doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) - - doAssert(heap.find(2) == -1) - - block: # Test del last - var heap = initHeapQueue[int]() - let data = [1, 2, 3] - for item in data: push(heap, item) - - heap.del(2) - doAssert(heap.toSortedSeq == @[1, 2]) - - heap.del(1) - doAssert(heap.toSortedSeq == @[1]) - - heap.del(0) - doAssert(heap.toSortedSeq == @[]) diff --git a/tests/stdlib/theapqueue.nim b/tests/stdlib/theapqueue.nim new file mode 100644 index 000000000..20e23e878 --- /dev/null +++ b/tests/stdlib/theapqueue.nim @@ -0,0 +1,53 @@ +import heapqueue + + +proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = + var tmp = h + result = @[] + while tmp.len > 0: + result.add(pop(tmp)) + +block: # Simple sanity test + var heap = initHeapQueue[int]() + let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] + for item in data: + push(heap, item) + doAssert(heap == data.toHeapQueue) + doAssert(heap[0] == 0) + doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + +block: # Test del + var heap = initHeapQueue[int]() + let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] + for item in data: push(heap, item) + + heap.del(0) + doAssert(heap[0] == 1) + + heap.del(heap.find(7)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) + + heap.del(heap.find(5)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) + + heap.del(heap.find(6)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) + + heap.del(heap.find(2)) + doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) + + doAssert(heap.find(2) == -1) + +block: # Test del last + var heap = initHeapQueue[int]() + let data = [1, 2, 3] + for item in data: push(heap, item) + + heap.del(2) + doAssert(heap.toSortedSeq == @[1, 2]) + + heap.del(1) + doAssert(heap.toSortedSeq == @[1]) + + heap.del(0) + doAssert(heap.toSortedSeq == @[]) From dd57d46f2f3a35878f48a1cd19bc85541f85c463 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 22 Nov 2020 04:20:33 +0800 Subject: [PATCH 1527/4254] complex minor improvement (#16086) --- lib/pure/complex.nim | 150 ++++++-------------------------------- tests/stdlib/tcomplex.nim | 108 +++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 129 deletions(-) create mode 100644 tests/stdlib/tcomplex.nim diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index d57adeb92..d1056e6e8 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -42,38 +42,38 @@ template im*(arg: float32): Complex32 = complex[float32](0, arg) template im*(arg: float64): Complex64 = complex[float64](0, arg) proc abs*[T](z: Complex[T]): T = - ## Return the distance from (0,0) to ``z``. + ## Returns the distance from (0,0) to ``z``. result = hypot(z.re, z.im) proc abs2*[T](z: Complex[T]): T = - ## Return the squared distance from (0,0) to ``z``. + ## Returns the squared distance from (0,0) to ``z``. result = z.re*z.re + z.im*z.im proc conjugate*[T](z: Complex[T]): Complex[T] = - ## Conjugate of complex number ``z``. + ## Conjugates of complex number ``z``. result.re = z.re result.im = -z.im proc inv*[T](z: Complex[T]): Complex[T] = - ## Multiplicative inverse of complex number ``z``. + ## Multiplicatives inverse of complex number ``z``. conjugate(z) / abs2(z) proc `==` *[T](x, y: Complex[T]): bool = - ## Compare two complex numbers ``x`` and ``y`` for equality. + ## Compares two complex numbers ``x`` and ``y`` for equality. result = x.re == y.re and x.im == y.im proc `+` *[T](x: T; y: Complex[T]): Complex[T] = - ## Add a real number to a complex number. + ## Adds a real number to a complex number. result.re = x + y.re result.im = y.im proc `+` *[T](x: Complex[T]; y: T): Complex[T] = - ## Add a complex number to a real number. + ## Adds a complex number to a real number. result.re = x.re + y result.im = x.im proc `+` *[T](x, y: Complex[T]): Complex[T] = - ## Add two complex numbers. + ## Adds two complex numbers. result.re = x.re + y.re result.im = x.im + y.im @@ -83,30 +83,30 @@ proc `-` *[T](z: Complex[T]): Complex[T] = result.im = -z.im proc `-` *[T](x: T; y: Complex[T]): Complex[T] = - ## Subtract a complex number from a real number. + ## Subtracts a complex number from a real number. x + (-y) proc `-` *[T](x: Complex[T]; y: T): Complex[T] = - ## Subtract a real number from a complex number. + ## Subtracts a real number from a complex number. result.re = x.re - y result.im = x.im proc `-` *[T](x, y: Complex[T]): Complex[T] = - ## Subtract two complex numbers. + ## Subtracts two complex numbers. result.re = x.re - y.re result.im = x.im - y.im proc `/` *[T](x: Complex[T]; y: T): Complex[T] = - ## Divide complex number ``x`` by real number ``y``. + ## Divides complex number ``x`` by real number ``y``. result.re = x.re / y result.im = x.im / y proc `/` *[T](x: T; y: Complex[T]): Complex[T] = - ## Divide real number ``x`` by complex number ``y``. + ## Divides real number ``x`` by complex number ``y``. result = x * inv(y) proc `/` *[T](x, y: Complex[T]): Complex[T] = - ## Divide ``x`` by ``y``. + ## Divides ``x`` by ``y``. var r, den: T if abs(y.re) < abs(y.im): r = y.re / y.im @@ -120,39 +120,39 @@ proc `/` *[T](x, y: Complex[T]): Complex[T] = result.im = (x.im - r * x.re) / den proc `*` *[T](x: T; y: Complex[T]): Complex[T] = - ## Multiply a real number and a complex number. + ## Multiplies a real number and a complex number. result.re = x * y.re result.im = x * y.im proc `*` *[T](x: Complex[T]; y: T): Complex[T] = - ## Multiply a complex number with a real number. + ## Multiplies a complex number with a real number. result.re = x.re * y result.im = x.im * y proc `*` *[T](x, y: Complex[T]): Complex[T] = - ## Multiply ``x`` with ``y``. + ## Multiplies ``x`` with ``y``. result.re = x.re * y.re - x.im * y.im result.im = x.im * y.re + x.re * y.im proc `+=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Add ``y`` to ``x``. + ## Adds ``y`` to ``x``. x.re += y.re x.im += y.im proc `-=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Subtract ``y`` from ``x``. + ## Subtracts ``y`` from ``x``. x.re -= y.re x.im -= y.im proc `*=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Multiply ``y`` to ``x``. + ## Multiplies ``y`` to ``x``. let im = x.im * y.re + x.re * y.im x.re = x.re * y.re - x.im * y.im x.im = im proc `/=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Divide ``x`` by ``y`` in place. + ## Divides ``x`` by ``y`` in place. x = x / y @@ -346,111 +346,3 @@ proc `$`*(z: Complex): string = result = "(" & $z.re & ", " & $z.im & ")" {.pop.} - - -when isMainModule: - proc `=~`[T](x, y: Complex[T]): bool = - result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6 - - proc `=~`[T](x: Complex[T]; y: T): bool = - result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6 - - var - z: Complex64 = complex(0.0, 0.0) - oo: Complex64 = complex(1.0, 1.0) - a: Complex64 = complex(1.0, 2.0) - b: Complex64 = complex(-1.0, -2.0) - m1: Complex64 = complex(-1.0, 0.0) - i: Complex64 = complex(0.0, 1.0) - one: Complex64 = complex(1.0, 0.0) - tt: Complex64 = complex(10.0, 20.0) - ipi: Complex64 = complex(0.0, -PI) - - doAssert(a/2.0 =~ complex(0.5, 1.0)) - doAssert(a == a) - doAssert((a-a) == z) - doAssert((a+b) == z) - doAssert((a+b) =~ 0.0) - doAssert((a/b) == m1) - doAssert((1.0/a) =~ complex(0.2, -0.4)) - doAssert((a*b) == complex(3.0, -4.0)) - doAssert(10.0*a == tt) - doAssert(a*10.0 == tt) - doAssert(tt/10.0 == a) - doAssert(oo+(-1.0) == i) - doAssert( (-1.0)+oo == i) - doAssert(abs(oo) == sqrt(2.0)) - doAssert(conjugate(a) == complex(1.0, -2.0)) - doAssert(sqrt(m1) == i) - doAssert(exp(ipi) =~ m1) - - doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068)) - doAssert(pow(z, a) =~ complex(0.0, 0.0)) - doAssert(pow(z, z) =~ complex(1.0, 0.0)) - doAssert(pow(a, one) =~ a) - doAssert(pow(a, m1) =~ complex(0.2, -0.4)) - doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0)) - doAssert(pow(a, 2) =~ complex(-3.0, 4.0)) - doAssert(not(pow(a, 2.0) =~ a)) - - doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090)) - doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234)) - doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811)) - - doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161)) - doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180)) - doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335)) - doAssert(cot(a) =~ 1.0 / tan(a)) - doAssert(sec(a) =~ 1.0 / cos(a)) - doAssert(csc(a) =~ 1.0 / sin(a)) - doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998)) - doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100)) - doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525)) - doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525)) - doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288)) - doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291)) - - doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778)) - doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040)) - doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725)) - doAssert(sech(a) =~ 1.0 / cosh(a)) - doAssert(csch(a) =~ 1.0 / sinh(a)) - doAssert(coth(a) =~ 1.0 / tanh(a)) - doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242)) - doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775)) - doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617)) - doAssert(arcsech(a) =~ arccosh(1.0/a)) - doAssert(arccsch(a) =~ arcsinh(1.0/a)) - doAssert(arccoth(a) =~ arctanh(1.0/a)) - - doAssert(phase(a) == 1.1071487177940904) - var t = polar(a) - doAssert(rect(t.r, t.phi) =~ a) - doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) - - - var - i64: Complex32 = complex(0.0f, 1.0f) - a64: Complex32 = 2.0f*i64 + 1.0.float32 - b64: Complex32 = complex(-1.0'f32, -2.0'f32) - - doAssert(a64 == a64) - doAssert(a64 == -b64) - doAssert(a64 + b64 =~ 0.0'f32) - doAssert(not(pow(a64, b64) =~ a64)) - doAssert(pow(a64, 0.5f) =~ sqrt(a64)) - doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32)) - doAssert(sin(arcsin(b64)) =~ b64) - doAssert(cosh(arccosh(a64)) =~ a64) - - doAssert(phase(a64) - 1.107149f < 1e-6) - var t64 = polar(a64) - doAssert(rect(t64.r, t64.phi) =~ a64) - doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f)) - doAssert(sizeof(a64) == 8) - doAssert(sizeof(a) == 16) - - doAssert 123.0.im + 456.0 == complex64(456, 123) - - var localA = complex(0.1'f32) - doAssert localA.im is float32 diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim new file mode 100644 index 000000000..8c9fa3055 --- /dev/null +++ b/tests/stdlib/tcomplex.nim @@ -0,0 +1,108 @@ +import complex, math + + +proc `=~`[T](x, y: Complex[T]): bool = + result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6 + +proc `=~`[T](x: Complex[T]; y: T): bool = + result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6 + +var + z: Complex64 = complex(0.0, 0.0) + oo: Complex64 = complex(1.0, 1.0) + a: Complex64 = complex(1.0, 2.0) + b: Complex64 = complex(-1.0, -2.0) + m1: Complex64 = complex(-1.0, 0.0) + i: Complex64 = complex(0.0, 1.0) + one: Complex64 = complex(1.0, 0.0) + tt: Complex64 = complex(10.0, 20.0) + ipi: Complex64 = complex(0.0, -PI) + +doAssert(a/2.0 =~ complex(0.5, 1.0)) +doAssert(a == a) +doAssert((a-a) == z) +doAssert((a+b) == z) +doAssert((a+b) =~ 0.0) +doAssert((a/b) == m1) +doAssert((1.0/a) =~ complex(0.2, -0.4)) +doAssert((a*b) == complex(3.0, -4.0)) +doAssert(10.0*a == tt) +doAssert(a*10.0 == tt) +doAssert(tt/10.0 == a) +doAssert(oo+(-1.0) == i) +doAssert( (-1.0)+oo == i) +doAssert(abs(oo) == sqrt(2.0)) +doAssert(conjugate(a) == complex(1.0, -2.0)) +doAssert(sqrt(m1) == i) +doAssert(exp(ipi) =~ m1) + +doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068)) +doAssert(pow(z, a) =~ complex(0.0, 0.0)) +doAssert(pow(z, z) =~ complex(1.0, 0.0)) +doAssert(pow(a, one) =~ a) +doAssert(pow(a, m1) =~ complex(0.2, -0.4)) +doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0)) +doAssert(pow(a, 2) =~ complex(-3.0, 4.0)) +doAssert(not(pow(a, 2.0) =~ a)) + +doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090)) +doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234)) +doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811)) + +doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161)) +doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180)) +doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335)) +doAssert(cot(a) =~ 1.0 / tan(a)) +doAssert(sec(a) =~ 1.0 / cos(a)) +doAssert(csc(a) =~ 1.0 / sin(a)) +doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998)) +doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100)) +doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525)) +doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525)) +doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288)) +doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291)) + +doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778)) +doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040)) +doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725)) +doAssert(sech(a) =~ 1.0 / cosh(a)) +doAssert(csch(a) =~ 1.0 / sinh(a)) +doAssert(coth(a) =~ 1.0 / tanh(a)) +doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242)) +doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775)) +doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617)) +doAssert(arcsech(a) =~ arccosh(1.0/a)) +doAssert(arccsch(a) =~ arcsinh(1.0/a)) +doAssert(arccoth(a) =~ arctanh(1.0/a)) + +doAssert(phase(a) == 1.1071487177940904) +var t = polar(a) +doAssert(rect(t.r, t.phi) =~ a) +doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) + + +var + i64: Complex32 = complex(0.0f, 1.0f) + a64: Complex32 = 2.0f*i64 + 1.0.float32 + b64: Complex32 = complex(-1.0'f32, -2.0'f32) + +doAssert(a64 == a64) +doAssert(a64 == -b64) +doAssert(a64 + b64 =~ 0.0'f32) +doAssert(not(pow(a64, b64) =~ a64)) +doAssert(pow(a64, 0.5f) =~ sqrt(a64)) +doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32)) +doAssert(sin(arcsin(b64)) =~ b64) +doAssert(cosh(arccosh(a64)) =~ a64) + +doAssert(phase(a64) - 1.107149f < 1e-6) +var t64 = polar(a64) +doAssert(rect(t64.r, t64.phi) =~ a64) +doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f)) +doAssert(sizeof(a64) == 8) +doAssert(sizeof(a) == 16) + +doAssert 123.0.im + 456.0 == complex64(456, 123) + +var localA = complex(0.1'f32) +doAssert localA.im is float32 From 3040f0550534848f61aa87d42e195e3fb5a70262 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 22 Nov 2020 04:26:51 +0800 Subject: [PATCH 1528/4254] xmltree minor improvement (#16085) --- lib/pure/xmltree.nim | 90 ++------------------------------------- tests/stdlib/txmltree.nim | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 87 deletions(-) create mode 100644 tests/stdlib/txmltree.nim diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index df8db1bb7..6ad90b042 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -312,7 +312,7 @@ proc add*(father, son: XmlNode) {.inline.} = add(father.s, son) proc insert*(father, son: XmlNode, index: int) {.inline.} = - ## Insert the child `son` to a given position in `father`. + ## Inserts the child `son` to a given position in `father`. ## ## `father` and `son` must be of `xnElement` kind. ## @@ -335,7 +335,7 @@ proc insert*(father, son: XmlNode, index: int) {.inline.} = insert(father.s, son, len(father.s)) proc delete*(n: XmlNode, i: Natural) = - ## Delete the `i`'th child of `n`. + ## Deletes the `i`'th child of `n`. ## ## See also: ## * `add proc <#add,XmlNode,XmlNode>`_ @@ -388,7 +388,7 @@ proc `[]`*(n: var XmlNode, i: int): var XmlNode {.inline.} = result = n.s[i] proc clear*(n: var XmlNode) = - ## Recursively clear all children of an XmlNode. + ## Recursively clears all children of an XmlNode. ## ## .. code-block:: ## var g = newElement("myTag") @@ -788,87 +788,3 @@ macro `<>`*(x: untyped): untyped = ## Nim rules. ## result = xmlConstructor(x) - - -when isMainModule: - var - x: XmlNode - - x = <>a(href = "http://nim-lang.org", newText("Nim rules.")) - assert $x == """Nim rules.""" - - x = <>outer(<>inner()) - assert $x == """ - -""" - - x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4())) - assert $x == """ - - - - - - -""" - - x = <>l0(<>l1(<>l2(<>l3(<>l4())))) - assert $x == """ - - - - - - - -""" - - x = <>l0(<>l1p1(), <>l1p2(), <>l1p3()) - assert $x == """ - - - -""" - - x = <>l0(<>l1(<>l2p1(), <>l2p2())) - assert $x == """ - - - - -""" - - x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4())) - assert $x == """ - - - - - - - - - - - - - - -""" - - let - innermost = newElement("innermost") - middle = newXmlTree("middle", [innermost]) - innermost.add newText("innermost text") - x = newXmlTree("outer", [middle]) - assert $x == """ - - innermost text - -""" - - x = newElement("myTag") - x.add newText("my text") - x.add newElement("sonTag") - x.add newEntity("my entity") - assert $x == "my text&my entity;" diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim new file mode 100644 index 000000000..034435dd7 --- /dev/null +++ b/tests/stdlib/txmltree.nim @@ -0,0 +1,85 @@ +import xmltree + + +block: + var + x: XmlNode + + x = <>a(href = "http://nim-lang.org", newText("Nim rules.")) + assert $x == """Nim rules.""" + + x = <>outer(<>inner()) + assert $x == """ + +""" + + x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4())) + assert $x == """ + + + + + + +""" + + x = <>l0(<>l1(<>l2(<>l3(<>l4())))) + assert $x == """ + + + + + + + +""" + + x = <>l0(<>l1p1(), <>l1p2(), <>l1p3()) + assert $x == """ + + + +""" + + x = <>l0(<>l1(<>l2p1(), <>l2p2())) + assert $x == """ + + + + +""" + + x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4())) + assert $x == """ + + + + + + + + + + + + + + +""" + + let + innermost = newElement("innermost") + middle = newXmlTree("middle", [innermost]) + innermost.add newText("innermost text") + x = newXmlTree("outer", [middle]) + assert $x == """ + + innermost text + +""" + + x = newElement("myTag") + x.add newText("my text") + x.add newElement("sonTag") + x.add newEntity("my entity") + assert $x == "my text&my entity;" From c9371ef59dc1c0b1037e0798dae8f0a90661db5d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 22 Nov 2020 04:30:04 +0800 Subject: [PATCH 1529/4254] deques minor improvement (#16084) --- lib/pure/collections/deques.nim | 147 ++++---------------------------- tests/stdlib/tdeque.nim | 111 ++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 129 deletions(-) create mode 100644 tests/stdlib/tdeque.nim diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index c3eeb3156..6df34bd3a 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -77,7 +77,7 @@ template checkIfInitialized(deq: typed) = initImpl(deq, defaultInitialSize) proc initDeque*[T](initialSize: int = 4): Deque[T] = - ## Create a new empty deque. + ## Creates a new empty deque. ## ## Optionally, the initial capacity can be reserved via `initialSize` ## as a performance optimization. @@ -103,7 +103,7 @@ proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} = result.addLast(item) proc len*[T](deq: Deque[T]): int {.inline.} = - ## Return the number of elements of `deq`. + ## Returns the number of elements of `deq`. result = deq.count template emptyCheck(deq) = @@ -123,7 +123,7 @@ template xBoundsCheck(deq, i) = "Out of bounds: " & $i & " < 0") proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = - ## Access the i-th element of `deq`. + ## Accesses the i-th element of `deq`. runnableExamples: var a = initDeque[int]() for i in 1 .. 5: @@ -136,7 +136,7 @@ proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = return deq.data[(deq.head + i) and deq.mask] proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} = - ## Access the i-th element of `deq` and return a mutable + ## Accesses the i-th element of `deq` and return a mutable ## reference to it. runnableExamples: var a = initDeque[int]() @@ -150,7 +150,7 @@ proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} = return deq.data[(deq.head + i) and deq.mask] proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = - ## Change the i-th element of `deq`. + ## Changes the i-th element of `deq`. runnableExamples: var a = initDeque[int]() for i in 1 .. 5: @@ -164,7 +164,7 @@ proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = deq.data[(deq.head + i) and deq.mask] = val proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = - ## Access the backwards indexed i-th element. + ## Accesses the backwards indexed i-th element. ## ## `deq[^1]` is the last element. runnableExamples: @@ -179,7 +179,7 @@ proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = return deq[deq.len - int(i)] proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} = - ## Access the backwards indexed i-th element. + ## Accesses the backwards indexed i-th element. ## ## `deq[^1]` is the last element. runnableExamples: @@ -194,7 +194,7 @@ proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} = return deq[deq.len - int(i)] proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = - ## Change the backwards indexed i-th element. + ## Changes the backwards indexed i-th element. ## ## `deq[^1]` is the last element. runnableExamples: @@ -210,7 +210,7 @@ proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = deq[deq.len - int(i)] = x iterator items*[T](deq: Deque[T]): T = - ## Yield every element of `deq`. + ## Yields every element of `deq`. ## ## **Examples:** ## @@ -232,7 +232,7 @@ iterator items*[T](deq: Deque[T]): T = i = (i + 1) and deq.mask iterator mitems*[T](deq: var Deque[T]): var T = - ## Yield every element of `deq`, which can be modified. + ## Yields every element of `deq`, which can be modified. runnableExamples: var a = initDeque[int]() for i in 1 .. 5: @@ -248,7 +248,7 @@ iterator mitems*[T](deq: var Deque[T]): var T = i = (i + 1) and deq.mask iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = - ## Yield every (position, value) of `deq`. + ## Yields every (position, value) of `deq`. ## ## **Examples:** ## @@ -270,7 +270,7 @@ iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = i = (i + 1) and deq.mask proc contains*[T](deq: Deque[T], item: T): bool {.inline.} = - ## Return true if `item` is in `deq` or false if not found. + ## Returns true if `item` is in `deq` or false if not found. ## ## Usually used via the ``in`` operator. ## It is the equivalent of ``deq.find(item) >= 0``. @@ -298,7 +298,7 @@ proc expandIfNeeded[T](deq: var Deque[T]) = deq.head = 0 proc addFirst*[T](deq: var Deque[T], item: T) = - ## Add an `item` to the beginning of the `deq`. + ## Adds an `item` to the beginning of the `deq`. ## ## See also: ## * `addLast proc <#addLast,Deque[T],T>`_ @@ -318,7 +318,7 @@ proc addFirst*[T](deq: var Deque[T], item: T) = deq.data[deq.head] = item proc addLast*[T](deq: var Deque[T], item: T) = - ## Add an `item` to the end of the `deq`. + ## Adds an `item` to the end of the `deq`. ## ## See also: ## * `addFirst proc <#addFirst,Deque[T],T>`_ @@ -421,7 +421,7 @@ template destroy(x: untyped) = reset(x) proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = - ## Remove and returns the first element of the `deq`. + ## Removes and returns the first element of the `deq`. ## ## See also: ## * `addFirst proc <#addFirst,Deque[T],T>`_ @@ -446,7 +446,7 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = deq.head = (deq.head + 1) and deq.mask proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = - ## Remove and returns the last element of the `deq`. + ## Removes and returns the last element of the `deq`. ## ## See also: ## * `addFirst proc <#addFirst,Deque[T],T>`_ @@ -489,7 +489,7 @@ proc clear*[T](deq: var Deque[T]) {.inline.} = deq.tail = deq.head proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = - ## Remove `fromFirst` elements from the front of the deque and + ## Removes `fromFirst` elements from the front of the deque and ## `fromLast` elements from the back. ## ## If the supplied number of elements exceeds the total number of elements @@ -520,120 +520,9 @@ proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = dec deq.count, fromFirst + fromLast proc `$`*[T](deq: Deque[T]): string = - ## Turn a deque into its string representation. + ## Turns a deque into its string representation. result = "[" for x in deq: if result.len > 1: result.add(", ") result.addQuoted(x) result.add("]") - - - -when isMainModule: - var deq = initDeque[int](1) - deq.addLast(4) - deq.addFirst(9) - deq.addFirst(123) - var first = deq.popFirst() - deq.addLast(56) - assert(deq.peekLast() == 56) - deq.addLast(6) - assert(deq.peekLast() == 6) - var second = deq.popFirst() - deq.addLast(789) - assert(deq.peekLast() == 789) - - assert first == 123 - assert second == 9 - assert($deq == "[4, 56, 6, 789]") - assert deq == [4, 56, 6, 789].toDeque - - assert deq[0] == deq.peekFirst and deq.peekFirst == 4 - #assert deq[^1] == deq.peekLast and deq.peekLast == 789 - deq[0] = 42 - deq[deq.len - 1] = 7 - - assert 6 in deq and 789 notin deq - assert deq.find(6) >= 0 - assert deq.find(789) < 0 - - block: - var d = initDeque[int](1) - d.addLast 7 - d.addLast 8 - d.addLast 10 - d.addFirst 5 - d.addFirst 2 - d.addFirst 1 - d.addLast 20 - d.shrink(fromLast = 2) - doAssert($d == "[1, 2, 5, 7, 8]") - d.shrink(2, 1) - doAssert($d == "[5, 7]") - d.shrink(2, 2) - doAssert d.len == 0 - - for i in -2 .. 10: - if i in deq: - assert deq.contains(i) and deq.find(i) >= 0 - else: - assert(not deq.contains(i) and deq.find(i) < 0) - - when compileOption("boundChecks"): - try: - echo deq[99] - assert false - except IndexDefect: - discard - - try: - assert deq.len == 4 - for i in 0 ..< 5: deq.popFirst() - assert false - except IndexDefect: - discard - - # grabs some types of resize error. - deq = initDeque[int]() - for i in 1 .. 4: deq.addLast i - deq.popFirst() - deq.popLast() - for i in 5 .. 8: deq.addFirst i - assert $deq == "[8, 7, 6, 5, 2, 3]" - - # Similar to proc from the documentation example - proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. - var deq = initDeque[int]() - assert deq.len == 0 - for i in 1 .. a: deq.addLast i - - if b < deq.len: # checking before indexed access. - assert deq[b] == b + 1 - - # The following two lines don't need any checking on access due to the logic - # of the program, but that would not be the case if `a` could be 0. - assert deq.peekFirst == 1 - assert deq.peekLast == a - - while deq.len > 0: # checking if the deque is empty - assert deq.popFirst() > 0 - - #foo(0,0) - foo(8, 5) - foo(10, 9) - foo(1, 1) - foo(2, 1) - foo(1, 5) - foo(3, 2) - - import sets - block t13310: - proc main() = - var q = initDeque[HashSet[int16]](2) - q.addFirst([1'i16].toHashSet) - q.addFirst([2'i16].toHashSet) - q.addFirst([3'i16].toHashSet) - assert $q == "[{3}, {2}, {1}]" - - static: - main() diff --git a/tests/stdlib/tdeque.nim b/tests/stdlib/tdeque.nim new file mode 100644 index 000000000..50e5d0ab1 --- /dev/null +++ b/tests/stdlib/tdeque.nim @@ -0,0 +1,111 @@ +import deques + + +var deq = initDeque[int](1) +deq.addLast(4) +deq.addFirst(9) +deq.addFirst(123) +var first = deq.popFirst() +deq.addLast(56) +assert(deq.peekLast() == 56) +deq.addLast(6) +assert(deq.peekLast() == 6) +var second = deq.popFirst() +deq.addLast(789) +assert(deq.peekLast() == 789) + +assert first == 123 +assert second == 9 +assert($deq == "[4, 56, 6, 789]") +assert deq == [4, 56, 6, 789].toDeque + +assert deq[0] == deq.peekFirst and deq.peekFirst == 4 +#assert deq[^1] == deq.peekLast and deq.peekLast == 789 +deq[0] = 42 +deq[deq.len - 1] = 7 + +assert 6 in deq and 789 notin deq +assert deq.find(6) >= 0 +assert deq.find(789) < 0 + +block: + var d = initDeque[int](1) + d.addLast 7 + d.addLast 8 + d.addLast 10 + d.addFirst 5 + d.addFirst 2 + d.addFirst 1 + d.addLast 20 + d.shrink(fromLast = 2) + doAssert($d == "[1, 2, 5, 7, 8]") + d.shrink(2, 1) + doAssert($d == "[5, 7]") + d.shrink(2, 2) + doAssert d.len == 0 + +for i in -2 .. 10: + if i in deq: + assert deq.contains(i) and deq.find(i) >= 0 + else: + assert(not deq.contains(i) and deq.find(i) < 0) + +when compileOption("boundChecks"): + try: + echo deq[99] + assert false + except IndexDefect: + discard + + try: + assert deq.len == 4 + for i in 0 ..< 5: deq.popFirst() + assert false + except IndexDefect: + discard + +# grabs some types of resize error. +deq = initDeque[int]() +for i in 1 .. 4: deq.addLast i +deq.popFirst() +deq.popLast() +for i in 5 .. 8: deq.addFirst i +assert $deq == "[8, 7, 6, 5, 2, 3]" + +# Similar to proc from the documentation example +proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. + var deq = initDeque[int]() + assert deq.len == 0 + for i in 1 .. a: deq.addLast i + + if b < deq.len: # checking before indexed access. + assert deq[b] == b + 1 + + # The following two lines don't need any checking on access due to the logic + # of the program, but that would not be the case if `a` could be 0. + assert deq.peekFirst == 1 + assert deq.peekLast == a + + while deq.len > 0: # checking if the deque is empty + assert deq.popFirst() > 0 + +#foo(0,0) +foo(8, 5) +foo(10, 9) +foo(1, 1) +foo(2, 1) +foo(1, 5) +foo(3, 2) + +import sets + +block t13310: + proc main() = + var q = initDeque[HashSet[int16]](2) + q.addFirst([1'i16].toHashSet) + q.addFirst([2'i16].toHashSet) + q.addFirst([3'i16].toHashSet) + assert $q == "[{3}, {2}, {1}]" + + static: + main() From f1764aaa9ed2a4e3488ccc5632aed77e3cae8cbf Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 22 Nov 2020 04:50:23 +0800 Subject: [PATCH 1530/4254] sets minor improvement (#16087) --- lib/pure/collections/sets.nim | 270 +------------------------------- tests/collections/thashsets.nim | 261 ++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 269 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 98dedc5ff..18f91f516 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -321,7 +321,7 @@ proc missingOrExcl*[A](s: var HashSet[A], key: A): bool = exclImpl(s, key) proc pop*[A](s: var HashSet[A]): A = - ## Remove and return an arbitrary element from the set `s`. + ## Removes and returns an arbitrary element from the set `s`. ## ## Raises KeyError if the set `s` is empty. ## @@ -915,271 +915,3 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = forAllOrderedPairs: yield (idx, s.data[h].key) - -# ----------------------------------------------------------------------- - - - -when isMainModule and not defined(release): - proc testModule() = - ## Internal micro test to validate docstrings and such. - block lenTest: - var values: HashSet[int] - assert values.len == 0 - assert values.card == 0 - - block setIterator: - type pair = tuple[a, b: int] - var a, b = initHashSet[pair]() - a.incl((2, 3)) - a.incl((3, 2)) - a.incl((2, 3)) - for x, y in a.items: - b.incl((x - 2, y + 1)) - assert a.len == b.card - assert a.len == 2 - #echo b - - block setContains: - var values = initHashSet[int]() - assert(not values.contains(2)) - values.incl(2) - assert values.contains(2) - values.excl(2) - assert(not values.contains(2)) - - values.incl(4) - var others = toHashSet([6, 7]) - values.incl(others) - assert values.len == 3 - - values.init - assert values.containsOrIncl(2) == false - assert values.containsOrIncl(2) == true - var - a = toHashSet([1, 2]) - b = toHashSet([1]) - b.incl(2) - assert a == b - - block exclusions: - var s = toHashSet([2, 3, 6, 7]) - s.excl(2) - s.excl(2) - assert s.len == 3 - - var - numbers = toHashSet([1, 2, 3, 4, 5]) - even = toHashSet([2, 4, 6, 8]) - numbers.excl(even) - #echo numbers - # --> {1, 3, 5} - - block toSeqAndString: - var a = toHashSet([2, 7, 5]) - var b = initHashSet[int](a.len) - for x in [2, 7, 5]: b.incl(x) - assert($a == $b) - #echo a - #echo toHashSet(["no", "esc'aping", "is \" provided"]) - - #block orderedToSeqAndString: - # echo toOrderedSet([2, 4, 5]) - # echo toOrderedSet(["no", "esc'aping", "is \" provided"]) - - block setOperations: - var - a = toHashSet(["a", "b"]) - b = toHashSet(["b", "c"]) - c = union(a, b) - assert c == toHashSet(["a", "b", "c"]) - var d = intersection(a, b) - assert d == toHashSet(["b"]) - var e = difference(a, b) - assert e == toHashSet(["a"]) - var f = symmetricDifference(a, b) - assert f == toHashSet(["a", "c"]) - assert d < a and d < b - assert((a < a) == false) - assert d <= a and d <= b - assert((a <= a)) - # Alias test. - assert a + b == toHashSet(["a", "b", "c"]) - assert a * b == toHashSet(["b"]) - assert a - b == toHashSet(["a"]) - assert a -+- b == toHashSet(["a", "c"]) - assert disjoint(a, b) == false - assert disjoint(a, b - a) == true - - block mapSet: - var a = toHashSet([1, 2, 3]) - var b = a.map(proc (x: int): string = $x) - assert b == toHashSet(["1", "2", "3"]) - - block lenTest: - var values: OrderedSet[int] - assert values.len == 0 - assert values.card == 0 - - block setIterator: - type pair = tuple[a, b: int] - var a, b = initOrderedSet[pair]() - a.incl((2, 3)) - a.incl((3, 2)) - a.incl((2, 3)) - for x, y in a.items: - b.incl((x - 2, y + 1)) - assert a.len == b.card - assert a.len == 2 - - block setPairsIterator: - var s = toOrderedSet([1, 3, 5, 7]) - var items = newSeq[tuple[a: int, b: int]]() - for idx, item in s: items.add((idx, item)) - assert items == @[(0, 1), (1, 3), (2, 5), (3, 7)] - - block exclusions: - var s = toOrderedSet([1, 2, 3, 6, 7, 4]) - - s.excl(3) - s.excl(3) - s.excl(1) - s.excl(4) - - var items = newSeq[int]() - for item in s: items.add item - assert items == @[2, 6, 7] - - block: #9005 - var s = initOrderedSet[(int, int)]() - for i in 0 .. 30: incl(s, (i, 0)) - for i in 0 .. 30: excl(s, (i, 0)) - doAssert s.len == 0 - - #block orderedSetIterator: - # var a = initOrderedSet[int]() - # for value in [9, 2, 1, 5, 1, 8, 4, 2]: - # a.incl(value) - # for value in a.items: - # echo "Got ", value - - block setContains: - var values = initOrderedSet[int]() - assert(not values.contains(2)) - values.incl(2) - assert values.contains(2) - - block toSeqAndString: - var a = toOrderedSet([2, 4, 5]) - var b = initOrderedSet[int]() - for x in [2, 4, 5]: b.incl(x) - assert($a == $b) - assert(a == b) # https://github.com/Araq/Nim/issues/1413 - - block initBlocks: - var a: OrderedSet[int] - a.init(4) - a.incl(2) - a.init - assert a.len == 0 - a = initOrderedSet[int](4) - a.incl(2) - assert a.len == 1 - - var b: HashSet[int] - b.init(4) - b.incl(2) - b.init - assert b.len == 0 - b = initHashSet[int](4) - b.incl(2) - assert b.len == 1 - - block missingOrExcl: - var s = toOrderedSet([2, 3, 6, 7]) - assert s.missingOrExcl(4) == true - assert s.missingOrExcl(6) == false - - block orderedSetEquality: - type pair = tuple[a, b: int] - - var aa = initOrderedSet[pair]() - var bb = initOrderedSet[pair]() - - var x = (a: 1, b: 2) - var y = (a: 3, b: 4) - - aa.incl(x) - aa.incl(y) - - bb.incl(x) - bb.incl(y) - assert aa == bb - - block setsWithoutInit: - var - a: HashSet[int] - b: HashSet[int] - c: HashSet[int] - d: HashSet[int] - e: HashSet[int] - - doAssert a.containsOrIncl(3) == false - doAssert a.contains(3) - doAssert a.len == 1 - doAssert a.containsOrIncl(3) - a.incl(3) - doAssert a.len == 1 - a.incl(6) - doAssert a.len == 2 - - b.incl(5) - doAssert b.len == 1 - b.excl(5) - b.excl(c) - doAssert b.missingOrExcl(5) - doAssert b.disjoint(c) - - d = b + c - doAssert d.len == 0 - d = b * c - doAssert d.len == 0 - d = b - c - doAssert d.len == 0 - d = b -+- c - doAssert d.len == 0 - - doAssert (d < e) == false - doAssert d <= e - doAssert d == e - - block setsWithoutInit: - var - a: OrderedSet[int] - b: OrderedSet[int] - c: OrderedSet[int] - d: HashSet[int] - - - doAssert a.containsOrIncl(3) == false - doAssert a.contains(3) - doAssert a.len == 1 - doAssert a.containsOrIncl(3) - a.incl(3) - doAssert a.len == 1 - a.incl(6) - doAssert a.len == 2 - - b.incl(5) - doAssert b.len == 1 - doAssert b.missingOrExcl(5) == false - doAssert b.missingOrExcl(5) - - doAssert c.missingOrExcl(9) - d.incl(c) - doAssert d.len == 0 - - when not defined(testing): - echo "Micro tests run successfully." - - testModule() diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim index 4ab3a66b7..359eaa51e 100644 --- a/tests/collections/thashsets.nim +++ b/tests/collections/thashsets.nim @@ -119,3 +119,264 @@ block hashForOrderdSet: reversed = !$reversed doAssert hash(r) == reversed doAssert hash(s1) != reversed + + +proc testModule() = + ## Internal micro test to validate docstrings and such. + block lenTest: + var values: HashSet[int] + doAssert values.len == 0 + doAssert values.card == 0 + + block setIterator: + type pair = tuple[a, b: int] + var a, b = initHashSet[pair]() + a.incl((2, 3)) + a.incl((3, 2)) + a.incl((2, 3)) + for x, y in a.items: + b.incl((x - 2, y + 1)) + doAssert a.len == b.card + doAssert a.len == 2 + #echo b + + block setContains: + var values = initHashSet[int]() + doAssert(not values.contains(2)) + values.incl(2) + doAssert values.contains(2) + values.excl(2) + doAssert(not values.contains(2)) + + values.incl(4) + var others = toHashSet([6, 7]) + values.incl(others) + doAssert values.len == 3 + + values.init + doAssert values.containsOrIncl(2) == false + doAssert values.containsOrIncl(2) == true + var + a = toHashSet([1, 2]) + b = toHashSet([1]) + b.incl(2) + doAssert a == b + + block exclusions: + var s = toHashSet([2, 3, 6, 7]) + s.excl(2) + s.excl(2) + doAssert s.len == 3 + + var + numbers = toHashSet([1, 2, 3, 4, 5]) + even = toHashSet([2, 4, 6, 8]) + numbers.excl(even) + #echo numbers + # --> {1, 3, 5} + + block toSeqAndString: + var a = toHashSet([2, 7, 5]) + var b = initHashSet[int](a.len) + for x in [2, 7, 5]: b.incl(x) + doAssert($a == $b) + #echo a + #echo toHashSet(["no", "esc'aping", "is \" provided"]) + + #block orderedToSeqAndString: + # echo toOrderedSet([2, 4, 5]) + # echo toOrderedSet(["no", "esc'aping", "is \" provided"]) + + block setOperations: + var + a = toHashSet(["a", "b"]) + b = toHashSet(["b", "c"]) + c = union(a, b) + doAssert c == toHashSet(["a", "b", "c"]) + var d = intersection(a, b) + doAssert d == toHashSet(["b"]) + var e = difference(a, b) + doAssert e == toHashSet(["a"]) + var f = symmetricDifference(a, b) + doAssert f == toHashSet(["a", "c"]) + doAssert d < a and d < b + doAssert((a < a) == false) + doAssert d <= a and d <= b + doAssert((a <= a)) + # Alias test. + doAssert a + b == toHashSet(["a", "b", "c"]) + doAssert a * b == toHashSet(["b"]) + doAssert a - b == toHashSet(["a"]) + doAssert a -+- b == toHashSet(["a", "c"]) + doAssert disjoint(a, b) == false + doAssert disjoint(a, b - a) == true + + block mapSet: + var a = toHashSet([1, 2, 3]) + var b = a.map(proc (x: int): string = $x) + doAssert b == toHashSet(["1", "2", "3"]) + + block lenTest: + var values: OrderedSet[int] + doAssert values.len == 0 + doAssert values.card == 0 + + block setIterator: + type pair = tuple[a, b: int] + var a, b = initOrderedSet[pair]() + a.incl((2, 3)) + a.incl((3, 2)) + a.incl((2, 3)) + for x, y in a.items: + b.incl((x - 2, y + 1)) + doAssert a.len == b.card + doAssert a.len == 2 + + block setPairsIterator: + var s = toOrderedSet([1, 3, 5, 7]) + var items = newSeq[tuple[a: int, b: int]]() + for idx, item in s: items.add((idx, item)) + doAssert items == @[(0, 1), (1, 3), (2, 5), (3, 7)] + + block exclusions: + var s = toOrderedSet([1, 2, 3, 6, 7, 4]) + + s.excl(3) + s.excl(3) + s.excl(1) + s.excl(4) + + var items = newSeq[int]() + for item in s: items.add item + doAssert items == @[2, 6, 7] + + block: #9005 + var s = initOrderedSet[(int, int)]() + for i in 0 .. 30: incl(s, (i, 0)) + for i in 0 .. 30: excl(s, (i, 0)) + doAssert s.len == 0 + + #block orderedSetIterator: + # var a = initOrderedSet[int]() + # for value in [9, 2, 1, 5, 1, 8, 4, 2]: + # a.incl(value) + # for value in a.items: + # echo "Got ", value + + block setContains: + var values = initOrderedSet[int]() + doAssert(not values.contains(2)) + values.incl(2) + doAssert values.contains(2) + + block toSeqAndString: + var a = toOrderedSet([2, 4, 5]) + var b = initOrderedSet[int]() + for x in [2, 4, 5]: b.incl(x) + doAssert($a == $b) + doAssert(a == b) # https://github.com/Araq/Nim/issues/1413 + + block initBlocks: + var a: OrderedSet[int] + a.init(4) + a.incl(2) + a.init + doAssert a.len == 0 + a = initOrderedSet[int](4) + a.incl(2) + doAssert a.len == 1 + + var b: HashSet[int] + b.init(4) + b.incl(2) + b.init + doAssert b.len == 0 + b = initHashSet[int](4) + b.incl(2) + doAssert b.len == 1 + + block missingOrExcl: + var s = toOrderedSet([2, 3, 6, 7]) + doAssert s.missingOrExcl(4) == true + doAssert s.missingOrExcl(6) == false + + block orderedSetEquality: + type pair = tuple[a, b: int] + + var aa = initOrderedSet[pair]() + var bb = initOrderedSet[pair]() + + var x = (a: 1, b: 2) + var y = (a: 3, b: 4) + + aa.incl(x) + aa.incl(y) + + bb.incl(x) + bb.incl(y) + doAssert aa == bb + + block setsWithoutInit: + var + a: HashSet[int] + b: HashSet[int] + c: HashSet[int] + d: HashSet[int] + e: HashSet[int] + + doAssert a.containsOrIncl(3) == false + doAssert a.contains(3) + doAssert a.len == 1 + doAssert a.containsOrIncl(3) + a.incl(3) + doAssert a.len == 1 + a.incl(6) + doAssert a.len == 2 + + b.incl(5) + doAssert b.len == 1 + b.excl(5) + b.excl(c) + doAssert b.missingOrExcl(5) + doAssert b.disjoint(c) + + d = b + c + doAssert d.len == 0 + d = b * c + doAssert d.len == 0 + d = b - c + doAssert d.len == 0 + d = b -+- c + doAssert d.len == 0 + + doAssert (d < e) == false + doAssert d <= e + doAssert d == e + + block setsWithoutInit: + var + a: OrderedSet[int] + b: OrderedSet[int] + c: OrderedSet[int] + d: HashSet[int] + + + doAssert a.containsOrIncl(3) == false + doAssert a.contains(3) + doAssert a.len == 1 + doAssert a.containsOrIncl(3) + a.incl(3) + doAssert a.len == 1 + a.incl(6) + doAssert a.len == 2 + + b.incl(5) + doAssert b.len == 1 + doAssert b.missingOrExcl(5) == false + doAssert b.missingOrExcl(5) + + doAssert c.missingOrExcl(9) + d.incl(c) + doAssert d.len == 0 + +testModule() From 2841cc6e97da3822eb778b0cbd138ebd1fc5cec0 Mon Sep 17 00:00:00 2001 From: Bad Dog Date: Sun, 22 Nov 2020 02:11:05 -0500 Subject: [PATCH 1531/4254] add gram to important packages (#16037) --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 22d58ba3e..ffc626589 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -44,6 +44,7 @@ pkg1 "glob" pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" pkg1 "gnuplot", "nim c gnuplot.nim" +pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" pkg1 "hts", "nim c -o:htss src/hts.nim" # pkg1 "httpauth" pkg1 "illwill", "nimble examples" From 6f1a72069a6992850813cd99d4d3aec4e595c438 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 23 Nov 2020 00:16:42 +0800 Subject: [PATCH 1532/4254] fix #9695 asyncmacro: tfuturevar fails when activated [backport: 1.0] (#16090) * fix asyncmacro * Apply suggestions from code review * Update lib/pure/asyncmacro.nim --- lib/pure/asyncmacro.nim | 3 ++- tests/async/tfuturevar.nim | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 579e9fede..a70508736 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -118,7 +118,8 @@ proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} = for i in 1 ..< len(params): expectKind(params[i], nnkIdentDefs) if params[i][1].kind == nnkBracketExpr and - params[i][1][0].eqIdent("futurevar"): + params[i][1][0].eqIdent(FutureVar.astToStr): + ## eqIdent: first char is case sensitive!!! result.add(params[i][0]) proc isInvalidReturnType(typeName: string): bool = diff --git a/tests/async/tfuturevar.nim b/tests/async/tfuturevar.nim index 9e3134261..b70f1d166 100644 --- a/tests/async/tfuturevar.nim +++ b/tests/async/tfuturevar.nim @@ -1,8 +1,3 @@ -discard """ -action: compile -""" -# XXX: action should be run! - import asyncdispatch proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} = From 6a37c0682ad30701aeef22e146d5cd5bff33b830 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 23 Nov 2020 04:01:17 +0800 Subject: [PATCH 1533/4254] ast minor (#16079) --- compiler/ast.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/ast.nim b/compiler/ast.nim index c75a149c0..da3f3e7d7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1834,6 +1834,7 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType = proc toRef*(typ: PType; idgen: IdGenerator): PType = ## If ``typ`` is a tyObject then it is converted into a `ref ` and ## returned. Otherwise ``typ`` is simply returned as-is. + result = typ if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject: result = newType(tyRef, nextId(idgen), typ.owner) rawAddSon(result, typ) From ab2c082cb3e9e411571fa0936776762bc0c8fd94 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 23 Nov 2020 18:27:09 +0800 Subject: [PATCH 1534/4254] fix rope index (#16100) * fix rope index * add testcase --- lib/pure/ropes.nim | 2 +- tests/stdlib/tropes.nim | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tropes.nim diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 41d6211b4..0797bbe06 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -204,8 +204,8 @@ proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} = if x.left.length > j: x = x.left else: + dec(j, x.left.length) x = x.right - dec(j, x.len) iterator leaves*(r: Rope): string = ## iterates over any leaf string in the rope `r`. diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim new file mode 100644 index 000000000..9678e26c3 --- /dev/null +++ b/tests/stdlib/tropes.nim @@ -0,0 +1,66 @@ +import ropes + + +block: + let r: Rope = nil + doAssert r[0] == '\0' + +block: + var + r1 = rope("Hello") + r2 = rope("Nim-Lang") + + let r = r1 & r2 + let s = $r + for i in 0 ..< r.len: + doAssert r[i] == s[i] + + doAssert r[66] == '\0' + +block: + let r = rope("Hello, Nim-Lang") + + let s = $r + for i in 0 ..< r.len: + doAssert r[i] == s[i] + + doAssert r[66] == '\0' + +block: + var r: Rope + r.add rope("Nim ") + r.add rope("is ") + r.add rope("a ") + r.add rope("great ") + r.add rope("language") + + let s = $r + for i in 0 ..< r.len: + doAssert r[i] == s[i] + + doAssert r[66] == '\0' + +block: + var r: Rope + r.add rope("My Conquest") + r.add rope(" is ") + r.add rope("the Sea of Stars") + + let s = $r + for i in 0 ..< r.len: + doAssert r[i] == s[i] + + doAssert r[66] == '\0' + +block: + var r: Rope + r.add rope("My Conquest") + r.add rope(" is ") + r.add rope("the Sea of Stars") + + var i: int + for item in r: + doAssert r[i] == item + inc i + + doAssert r[66] == '\0' From 79ec1bdcbb6a9d957def958bc9eff3b4c4a7f1d4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 23 Nov 2020 18:36:05 +0800 Subject: [PATCH 1535/4254] correct errors in xmltree docs (#16104) --- lib/pure/xmltree.nim | 153 ++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 6ad90b042..62a62eb4b 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -9,26 +9,22 @@ ## A simple XML tree generator. ## -## .. code-block:: -## import xmltree -## -## var g = newElement("myTag") -## g.add newText("some text") -## g.add newComment("this is comment") -## -## var h = newElement("secondTag") -## h.add newEntity("some entity") -## -## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes -## let k = newXmlTree("treeTag", [g, h], att) -## -## echo k -## # -## # some text -## # &some entity; -## # -## -## +runnableExamples: + var g = newElement("myTag") + g.add newText("some text") + g.add newComment("this is comment") + + var h = newElement("secondTag") + h.add newEntity("some entity") + + let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + let k = newXmlTree("treeTag", [g, h], att) + + doAssert $k == """ + some text + &some entity; +""" + ## **See also:** ## * `xmlparser module `_ for high-level XML parsing ## * `parsexml module `_ for low-level XML parsing @@ -146,21 +142,20 @@ proc newXmlTree*(tag: string, children: openArray[XmlNode], ## See also: ## * `newElement proc <#newElement,string>`_ ## * [<> macro](#<>.m,untyped) - ## - ## .. code-block:: - ## var g = newElement("myTag") - ## g.add newText("some text") - ## g.add newComment("this is comment") - ## var h = newElement("secondTag") - ## h.add newEntity("some entity") - ## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - ## let k = newXmlTree("treeTag", [g, h], att) - ## - ## echo k - ## ## - ## ## some text - ## ## &some entity; - ## ## + + runnableExamples: + var g = newElement("myTag") + g.add newText("some text") + g.add newComment("this is comment") + var h = newElement("secondTag") + h.add newEntity("some entity") + let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + let k = newXmlTree("treeTag", [g, h], att) + + doAssert $k == """ + some text + &some entity; +""" result = newXmlNode(xnElement) result.fTag = tag @@ -390,26 +385,24 @@ proc `[]`*(n: var XmlNode, i: int): var XmlNode {.inline.} = proc clear*(n: var XmlNode) = ## Recursively clears all children of an XmlNode. ## - ## .. code-block:: - ## var g = newElement("myTag") - ## g.add newText("some text") - ## g.add newComment("this is comment") - ## - ## var h = newElement("secondTag") - ## h.add newEntity("some entity") - ## - ## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - ## var k = newXmlTree("treeTag", [g, h], att) - ## - ## echo k - ## ## - ## ## some text - ## ## &some entity; - ## ## - ## - ## clear(k) - ## echo k - ## ## + runnableExamples: + var g = newElement("myTag") + g.add newText("some text") + g.add newComment("this is comment") + + var h = newElement("secondTag") + h.add newEntity("some entity") + + let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + var k = newXmlTree("treeTag", [g, h], att) + + doAssert $k == """ + some text + &some entity; +""" + + clear(k) + doAssert $k == """""" for i in 0 ..< n.len: clear(n[i]) @@ -419,25 +412,24 @@ proc clear*(n: var XmlNode) = iterator items*(n: XmlNode): XmlNode {.inline.} = ## Iterates over all direct children of `n`. - ## - ## **Examples:** - ## - ## .. code-block:: - ## var g = newElement("myTag") - ## g.add newText("some text") - ## g.add newComment("this is comment") - ## - ## var h = newElement("secondTag") - ## h.add newEntity("some entity") - ## g.add h - ## - ## assert $g == "some text&some entity;" - ## for x in g: # the same as `for x in items(g):` - ## echo x - ## - ## # some text - ## # - ## # &some entity; + + runnableExamples: + var g = newElement("myTag") + g.add newText("some text") + g.add newComment("this is comment") + + var h = newElement("secondTag") + h.add newEntity("some entity") + g.add h + + assert $g == "some text&some entity;" + + # for x in g: # the same as `for x in items(g):` + # echo x + + # some text + # + # &some entity; assert n.k == xnElement for i in 0 .. n.len-1: yield n[i] @@ -451,13 +443,12 @@ proc toXmlAttributes*(keyValuePairs: varargs[tuple[key, val: string]]): XmlAttributes = ## Converts `{key: value}` pairs into `XmlAttributes`. ## - ## .. code-block:: - ## let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes - ## var j = newElement("myTag") - ## j.attrs = att - ## - ## echo j - ## ## + runnableExamples: + let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes + var j = newElement("myTag") + j.attrs = att + + doAssert $j == """""" newStringTable(keyValuePairs) From ffccdf3c1a91e3a4ac79b209ae4f034ad253d97b Mon Sep 17 00:00:00 2001 From: RokkuCode Date: Mon, 23 Nov 2020 15:15:55 +0100 Subject: [PATCH 1536/4254] fixes #16080 (#16091) [backport:1.2] * fixes #16080 db_sqlite: Error: undeclared field: 'untypedLen' * redacting fix --- lib/impure/db_sqlite.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index ce57996be..5c79b8c2a 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -855,7 +855,7 @@ macro untypedLen(args: varargs[untyped]): int = template exec*(db: DbConn, stmtName: SqlPrepared, args: varargs[typed]): untyped = - when args.untypedLen > 0: + when untypedLen(args) > 0: if reset(stmtName.PStmt) != SQLITE_OK: dbError(db) if clear_bindings(stmtName.PStmt) != SQLITE_OK: From 7fc0c3dfbf5e27805fa75745acabf5ce2f0af693 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 24 Nov 2020 00:49:40 +0800 Subject: [PATCH 1537/4254] ref #5617 add lineinfo to complete (#16102) --- lib/pure/asyncmacro.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index a70508736..dd2393a63 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -11,6 +11,13 @@ import macros, strutils, asyncfutures + +# TODO: Ref https://github.com/nim-lang/Nim/issues/5617 +# TODO: Add more line infos +proc newCallWithLineInfo(fromNode: NimNode; theProc: NimNode, args: varargs[NimNode]): NimNode = + result = newCall(theProc, args) + result.copyLineInfo(fromNode) + template createCb(retFutureSym, iteratorNameSym, strName, identName, futureVarCompletions: untyped) = bind finished @@ -52,15 +59,13 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode], # Add calls to complete each FutureVar parameter. for ident in futureVarIdents: # Only complete them if they have not been completed already by the user. - # TODO: Once https://github.com/nim-lang/Nim/issues/5617 is fixed. - # TODO: Add line info to the complete() call! # In the meantime, this was really useful for debugging :) #result.add(newCall(newIdentNode("echo"), newStrLitNode(fromNode.lineinfo))) result.add newIfStmt( ( newCall(newIdentNode("not"), newDotExpr(ident, newIdentNode("finished"))), - newCall(newIdentNode("complete"), ident) + newCallWithLineInfo(fromNode, newIdentNode("complete"), ident) ) ) From 0c6c4be0e783893cc21352fa686fb18c158d3e43 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 24 Nov 2020 02:23:52 +0800 Subject: [PATCH 1538/4254] fix ropes format errors (#16106) [backport:1.0] * fix rope index * add testcase * fix ropes format --- lib/pure/ropes.nim | 2 +- tests/stdlib/tropes.nim | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 0797bbe06..a39533e58 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -262,7 +262,7 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {. while true: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) - if frmt[i] notin {'0'..'9'}: break + if i >= frmt.len or frmt[i] notin {'0'..'9'}: break add(result, args[j-1]) of '{': inc(i) diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim index 9678e26c3..0c95d5c5f 100644 --- a/tests/stdlib/tropes.nim +++ b/tests/stdlib/tropes.nim @@ -64,3 +64,10 @@ block: inc i doAssert r[66] == '\0' + +block: + let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")] + doAssert $r1 == "Nim is a great language" + + let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")] + doAssert $r2 == "Nim is a great language" From a764a5b9bced8159d61647c42f6168a44453faff Mon Sep 17 00:00:00 2001 From: kemifl Date: Mon, 23 Nov 2020 19:53:57 +0100 Subject: [PATCH 1539/4254] fix #14056 (#16071) fix #14056, incorporate review comments --- lib/pure/xmlparser.nim | 20 ++++++++++---------- tests/stdlib/tmitems.nim | 29 +++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 2a2d19dca..3d9c288ed 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -99,11 +99,11 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = of xmlEof: discard proc parseXml*(s: Stream, filename: string, - errors: var seq[string]): XmlNode = + errors: var seq[string], options: set[XmlParseOption] = {reportComments}): XmlNode = ## Parses the XML from stream ``s`` and returns a ``XmlNode``. Every ## occurred parsing error is added to the ``errors`` sequence. var x: XmlParser - open(x, s, filename, {reportComments}) + open(x, s, filename, options) while true: x.next() case x.kind @@ -118,32 +118,32 @@ proc parseXml*(s: Stream, filename: string, break close(x) -proc parseXml*(s: Stream): XmlNode = +proc parseXml*(s: Stream, options: set[XmlParseOption] = {reportComments}): XmlNode = ## Parses the XML from stream ``s`` and returns a ``XmlNode``. All parsing ## errors are turned into an ``XmlError`` exception. var errors: seq[string] = @[] - result = parseXml(s, "unknown_xml_doc", errors) + result = parseXml(s, "unknown_xml_doc", errors, options) if errors.len > 0: raiseInvalidXml(errors) -proc parseXml*(str: string): XmlNode = +proc parseXml*(str: string, options: set[XmlParseOption] = {reportComments}): XmlNode = ## Parses the XML from string ``str`` and returns a ``XmlNode``. All parsing ## errors are turned into an ``XmlError`` exception. - parseXml(newStringStream(str)) + parseXml(newStringStream(str), options) -proc loadXml*(path: string, errors: var seq[string]): XmlNode = +proc loadXml*(path: string, errors: var seq[string], options: set[XmlParseOption] = {reportComments}): XmlNode = ## Loads and parses XML from file specified by ``path``, and returns ## a ``XmlNode``. Every occurred parsing error is added to the ``errors`` ## sequence. var s = newFileStream(path, fmRead) if s == nil: raise newException(IOError, "Unable to read file: " & path) - result = parseXml(s, path, errors) + result = parseXml(s, path, errors, options) -proc loadXml*(path: string): XmlNode = +proc loadXml*(path: string, options: set[XmlParseOption] = {reportComments}): XmlNode = ## Loads and parses XML from file specified by ``path``, and returns ## a ``XmlNode``. All parsing errors are turned into an ``XmlError`` ## exception. var errors: seq[string] = @[] - result = loadXml(path, errors) + result = loadXml(path, errors, options) if errors.len > 0: raiseInvalidXml(errors) when isMainModule: diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim index 17265e1f7..c0ced7cab 100644 --- a/tests/stdlib/tmitems.nim +++ b/tests/stdlib/tmitems.nim @@ -16,7 +16,18 @@ fpqeew -''' + + + This is a Docbook title + + This is a Docbook paragraph containing emphasized, + literal and replaceable + text. Sometimes scrunched together like this: + literalreplaceable + and sometimes not: + literal replaceable + +''' """ block: @@ -123,7 +134,7 @@ block: x.num += 10 echo j -import xmltree, xmlparser, streams, strtabs +import xmltree, xmlparser, parsexml, streams, strtabs block: var d = parseXml(newStringStream """ @@ -134,3 +145,17 @@ block: x = <>Student(Name=x.attrs["Name"] & "foo") d[1].attrs["Name"] = "bar" echo d + +block: + var d = parseXml(newStringStream """ + This is a Docbook title + + This is a Docbook paragraph containing emphasized, + literal and replaceable + text. Sometimes scrunched together like this: + literalreplaceable + and sometimes not: + literal replaceable + +""",{reportComments, reportWhitespace}) + echo d From e4d0f9f3de3b62549fd6503e724a047abbadf03f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 24 Nov 2020 05:56:30 +0800 Subject: [PATCH 1540/4254] typeinfo minor improvement (#16083) * typeinfo minor improvement * minor * Update lib/core/typeinfo.nim * rename typeinfo --- lib/core/typeinfo.nim | 163 +++++++------------- tests/cpp/{ttypeinfo.nim => ttypeinfo1.nim} | 0 tests/stdlib/ttypeinfo.nim | 60 +++++++ 3 files changed, 112 insertions(+), 111 deletions(-) rename tests/cpp/{ttypeinfo.nim => ttypeinfo1.nim} (100%) create mode 100644 tests/stdlib/ttypeinfo.nim diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index ca531b4b9..fff237718 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -142,7 +142,7 @@ proc newAny(value: pointer, rawType: PNimType): Any {.inline.} = when declared(system.VarSlot): proc toAny*(x: VarSlot): Any {.inline.} = - ## constructs a ``Any`` object from a variable slot ``x``. + ## Constructs a ``Any`` object from a variable slot ``x``. ## This captures `x`'s address, so `x` can be modified with its ## ``Any`` wrapper! The client needs to ensure that the wrapper ## **does not** live longer than `x`! @@ -151,31 +151,31 @@ when declared(system.VarSlot): result.rawType = x.typ proc toAny*[T](x: var T): Any {.inline.} = - ## constructs a ``Any`` object from `x`. This captures `x`'s address, so + ## Constructs a ``Any`` object from `x`. This captures `x`'s address, so ## `x` can be modified with its ``Any`` wrapper! The client needs to ensure ## that the wrapper **does not** live longer than `x`! newAny(addr(x), cast[PNimType](getTypeInfo(x))) proc kind*(x: Any): AnyKind {.inline.} = - ## get the type kind + ## Gets the type kind. result = AnyKind(ord(x.rawType.kind)) proc size*(x: Any): int {.inline.} = - ## returns the size of `x`'s type. + ## Returns the size of `x`'s type. result = x.rawType.size proc baseTypeKind*(x: Any): AnyKind {.inline.} = - ## get the base type's kind; ``akNone`` is returned if `x` has no base type. + ## Gets the base type's kind; ``akNone`` is returned if `x` has no base type. if x.rawType.base != nil: result = AnyKind(ord(x.rawType.base.kind)) proc baseTypeSize*(x: Any): int {.inline.} = - ## returns the size of `x`'s basetype. + ## Returns the size of `x`'s basetype. if x.rawType.base != nil: result = x.rawType.base.size proc invokeNew*(x: Any) = - ## performs ``new(x)``. `x` needs to represent a ``ref``. + ## Performs ``new(x)``. `x` needs to represent a ``ref``. assert x.rawType.kind == tyRef when defined(gcDestructors): cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size, x.rawType.base.align) @@ -184,7 +184,7 @@ proc invokeNew*(x: Any) = genericAssign(x.value, addr(z), x.rawType) proc invokeNewSeq*(x: Any, len: int) = - ## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``. + ## Performs ``newSeq(x, len)``. `x` needs to represent a ``seq``. assert x.rawType.kind == tySequence when defined(gcDestructors): var s = cast[ptr NimSeqV2Reimpl](x.value) @@ -196,7 +196,7 @@ proc invokeNewSeq*(x: Any, len: int) = genericShallowAssign(x.value, addr(z), x.rawType) proc extendSeq*(x: Any) = - ## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``. + ## Performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``. assert x.rawType.kind == tySequence when defined(gcDestructors): var s = cast[ptr NimSeqV2Reimpl](x.value) @@ -212,7 +212,7 @@ proc extendSeq*(x: Any) = #genericShallowAssign(x.value, addr(z), x.rawType) proc setObjectRuntimeType*(x: Any) = - ## this needs to be called to set `x`'s runtime object type field. + ## This needs to be called to set `x`'s runtime object type field. assert x.rawType.kind == tyObject when defined(gcDestructors): cast[ppointer](x.value)[] = x.rawType.typeInfoV2 @@ -227,7 +227,7 @@ proc align(address, alignment: int): int = result = (address + (alignment - 1)) and not (alignment - 1) proc `[]`*(x: Any, i: int): Any = - ## accessor for an any `x` that represents an array or a sequence. + ## Accessor for an any `x` that represents an array or a sequence. case x.rawType.kind of tyArray: let bs = x.rawType.base.size @@ -253,7 +253,7 @@ proc `[]`*(x: Any, i: int): Any = else: assert false proc `[]=`*(x: Any, i: int, y: Any) = - ## accessor for an any `x` that represents an array or a sequence. + ## Accessor for an any `x` that represents an array or a sequence. case x.rawType.kind of tyArray: var bs = x.rawType.base.size @@ -282,7 +282,7 @@ proc `[]=`*(x: Any, i: int, y: Any) = else: assert false proc len*(x: Any): int = - ## len for an any `x` that represents an array or a sequence. + ## `len` for an any `x` that represents an array or a sequence. case x.rawType.kind of tyArray: result = x.rawType.size div x.rawType.base.size @@ -299,7 +299,7 @@ proc len*(x: Any): int = proc base*(x: Any): Any = - ## returns base Any (useful for inherited object types). + ## Returns base Any (useful for inherited object types). result.rawType = x.rawType.base result.value = x.value @@ -316,14 +316,14 @@ const tySequence, tyProc} proc getPointer*(x: Any): pointer = - ## retrieve the pointer value out of `x`. ``x`` needs to be of kind + ## Retrieves the pointer value out of `x`. ``x`` needs to be of kind ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. assert x.rawType.kind in pointerLike result = cast[ppointer](x.value)[] proc setPointer*(x: Any, y: pointer) = - ## sets the pointer value of `x`. ``x`` needs to be of kind + ## Sets the pointer value of `x`. ``x`` needs to be of kind ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. assert x.rawType.kind in pointerLike @@ -347,7 +347,7 @@ proc fieldsAux(p: pointer, n: ptr TNimNode, if m != nil: fieldsAux(p, m, ret) iterator fields*(x: Any): tuple[name: string, any: Any] = - ## iterates over every active field of the any `x` that represents an object + ## Iterates over every active field of the any `x` that represents an object ## or a tuple. assert x.rawType.kind in {tyTuple, tyObject} var p = x.value @@ -401,7 +401,7 @@ proc getFieldNode(p: pointer, n: ptr TNimNode, if m != nil: result = getFieldNode(p, m, name) proc `[]=`*(x: Any, fieldName: string, value: Any) = - ## sets a field of `x`; `x` represents an object or a tuple. + ## Sets a field of `x`; `x` represents an object or a tuple. var t = x.rawType # XXX BUG: does not work yet, however is questionable anyway when false: @@ -415,7 +415,7 @@ proc `[]=`*(x: Any, fieldName: string, value: Any) = raise newException(ValueError, "invalid field name: " & fieldName) proc `[]`*(x: Any, fieldName: string): Any = - ## gets a field of `x`; `x` represents an object or a tuple. + ## Gets a field of `x`; `x` represents an object or a tuple. var t = x.rawType # XXX BUG: does not work yet, however is questionable anyway when false: @@ -431,44 +431,44 @@ proc `[]`*(x: Any, fieldName: string): Any = raise newException(ValueError, "invalid field name: " & fieldName) proc `[]`*(x: Any): Any = - ## dereference operation for the any `x` that represents a ptr or a ref. + ## Dereference operation for the any `x` that represents a ptr or a ref. assert x.rawType.kind in {tyRef, tyPtr} result.value = cast[ppointer](x.value)[] result.rawType = x.rawType.base proc `[]=`*(x, y: Any) = - ## dereference operation for the any `x` that represents a ptr or a ref. + ## Dereference operation for the any `x` that represents a ptr or a ref. assert x.rawType.kind in {tyRef, tyPtr} assert y.rawType == x.rawType.base genericAssign(cast[ppointer](x.value)[], y.value, y.rawType) proc getInt*(x: Any): int = - ## retrieve the int value out of `x`. `x` needs to represent an int. + ## Retrieves the int value out of `x`. `x` needs to represent an int. assert skipRange(x.rawType).kind == tyInt result = cast[ptr int](x.value)[] proc getInt8*(x: Any): int8 = - ## retrieve the int8 value out of `x`. `x` needs to represent an int8. + ## Retrieves the int8 value out of `x`. `x` needs to represent an int8. assert skipRange(x.rawType).kind == tyInt8 result = cast[ptr int8](x.value)[] proc getInt16*(x: Any): int16 = - ## retrieve the int16 value out of `x`. `x` needs to represent an int16. + ## Retrieves the int16 value out of `x`. `x` needs to represent an int16. assert skipRange(x.rawType).kind == tyInt16 result = cast[ptr int16](x.value)[] proc getInt32*(x: Any): int32 = - ## retrieve the int32 value out of `x`. `x` needs to represent an int32. + ## Retrieves the int32 value out of `x`. `x` needs to represent an int32. assert skipRange(x.rawType).kind == tyInt32 result = cast[ptr int32](x.value)[] proc getInt64*(x: Any): int64 = - ## retrieve the int64 value out of `x`. `x` needs to represent an int64. + ## Retrieves the int64 value out of `x`. `x` needs to represent an int64. assert skipRange(x.rawType).kind == tyInt64 result = cast[ptr int64](x.value)[] proc getBiggestInt*(x: Any): BiggestInt = - ## retrieve the integer value out of `x`. `x` needs to represent + ## Retrieves the integer value out of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. ## The value might be sign-extended to ``BiggestInt``. var t = skipRange(x.rawType) @@ -494,7 +494,7 @@ proc getBiggestInt*(x: Any): BiggestInt = else: assert false proc setBiggestInt*(x: Any, y: BiggestInt) = - ## sets the integer value of `x`. `x` needs to represent + ## Sets the integer value of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. var t = skipRange(x.rawType) case t.kind @@ -519,36 +519,36 @@ proc setBiggestInt*(x: Any, y: BiggestInt) = else: assert false proc getUInt*(x: Any): uint = - ## retrieve the uint value out of `x`, `x` needs to represent an uint. + ## Retrieves the uint value out of `x`, `x` needs to represent an uint. assert skipRange(x.rawType).kind == tyUInt result = cast[ptr uint](x.value)[] proc getUInt8*(x: Any): uint8 = - ## retrieve the uint8 value out of `x`, `x` needs to represent an + ## Retrieves the uint8 value out of `x`, `x` needs to represent an ## uint8. assert skipRange(x.rawType).kind == tyUInt8 result = cast[ptr uint8](x.value)[] proc getUInt16*(x: Any): uint16 = - ## retrieve the uint16 value out of `x`, `x` needs to represent an + ## Retrieves the uint16 value out of `x`, `x` needs to represent an ## uint16. assert skipRange(x.rawType).kind == tyUInt16 result = cast[ptr uint16](x.value)[] proc getUInt32*(x: Any): uint32 = - ## retrieve the uint32 value out of `x`, `x` needs to represent an + ## Retrieves the uint32 value out of `x`, `x` needs to represent an ## uint32. assert skipRange(x.rawType).kind == tyUInt32 result = cast[ptr uint32](x.value)[] proc getUInt64*(x: Any): uint64 = - ## retrieve the uint64 value out of `x`, `x` needs to represent an + ## Retrieves the uint64 value out of `x`, `x` needs to represent an ## uint64. assert skipRange(x.rawType).kind == tyUInt64 result = cast[ptr uint64](x.value)[] proc getBiggestUint*(x: Any): uint64 = - ## retrieve the unsigned integer value out of `x`. `x` needs to + ## Retrieves the unsigned integer value out of `x`. `x` needs to ## represent an unsigned integer. var t = skipRange(x.rawType) case t.kind @@ -560,7 +560,7 @@ proc getBiggestUint*(x: Any): uint64 = else: assert false proc setBiggestUint*(x: Any; y: uint64) = - ## sets the unsigned integer value of `c`. `c` needs to represent an + ## Sets the unsigned integer value of `c`. `c` needs to represent an ## unsigned integer. var t = skipRange(x.rawType) case t.kind: @@ -572,25 +572,25 @@ proc setBiggestUint*(x: Any; y: uint64) = else: assert false proc getChar*(x: Any): char = - ## retrieve the char value out of `x`. `x` needs to represent a char. + ## Retrieves the char value out of `x`. `x` needs to represent a char. var t = skipRange(x.rawType) assert t.kind == tyChar result = cast[ptr char](x.value)[] proc getBool*(x: Any): bool = - ## retrieve the bool value out of `x`. `x` needs to represent a bool. + ## Retrieves the bool value out of `x`. `x` needs to represent a bool. var t = skipRange(x.rawType) assert t.kind == tyBool result = cast[ptr bool](x.value)[] proc skipRange*(x: Any): Any = - ## skips the range information of `x`. + ## Skips the range information of `x`. assert x.rawType.kind == tyRange result.rawType = x.rawType.base result.value = x.value proc getEnumOrdinal*(x: Any, name: string): int = - ## gets the enum field ordinal from `name`. `x` needs to represent an enum + ## Gets the enum field ordinal from `name`. `x` needs to represent an enum ## but is only used to access the type information. In case of an error ## ``low(int)`` is returned. var typ = skipRange(x.rawType) @@ -606,7 +606,7 @@ proc getEnumOrdinal*(x: Any, name: string): int = result = low(int) proc getEnumField*(x: Any, ordinalValue: int): string = - ## gets the enum field name as a string. `x` needs to represent an enum + ## Gets the enum field name as a string. `x` needs to represent an enum ## but is only used to access the type information. The field name of ## `ordinalValue` is returned. var typ = skipRange(x.rawType) @@ -624,26 +624,26 @@ proc getEnumField*(x: Any, ordinalValue: int): string = result = $e proc getEnumField*(x: Any): string = - ## gets the enum field name as a string. `x` needs to represent an enum. + ## Gets the enum field name as a string. `x` needs to represent an enum. result = getEnumField(x, getBiggestInt(x).int) proc getFloat*(x: Any): float = - ## retrieve the float value out of `x`. `x` needs to represent an float. + ## Retrieves the float value out of `x`. `x` needs to represent an float. assert skipRange(x.rawType).kind == tyFloat result = cast[ptr float](x.value)[] proc getFloat32*(x: Any): float32 = - ## retrieve the float32 value out of `x`. `x` needs to represent an float32. + ## Retrieves the float32 value out of `x`. `x` needs to represent an float32. assert skipRange(x.rawType).kind == tyFloat32 result = cast[ptr float32](x.value)[] proc getFloat64*(x: Any): float64 = - ## retrieve the float64 value out of `x`. `x` needs to represent an float64. + ## Retrieves the float64 value out of `x`. `x` needs to represent an float64. assert skipRange(x.rawType).kind == tyFloat64 result = cast[ptr float64](x.value)[] proc getBiggestFloat*(x: Any): BiggestFloat = - ## retrieve the float value out of `x`. `x` needs to represent + ## Retrieves the float value out of `x`. `x` needs to represent ## some float. The value is extended to ``BiggestFloat``. case skipRange(x.rawType).kind of tyFloat: result = BiggestFloat(cast[ptr float](x.value)[]) @@ -652,7 +652,7 @@ proc getBiggestFloat*(x: Any): BiggestFloat = else: assert false proc setBiggestFloat*(x: Any, y: BiggestFloat) = - ## sets the float value of `x`. `x` needs to represent + ## Sets the float value of `x`. `x` needs to represent ## some float. case skipRange(x.rawType).kind of tyFloat: cast[ptr float](x.value)[] = y @@ -661,7 +661,7 @@ proc setBiggestFloat*(x: Any, y: BiggestFloat) = else: assert false proc getString*(x: Any): string = - ## retrieve the string value out of `x`. `x` needs to represent a string. + ## Retrieves the string value out of `x`. `x` needs to represent a string. assert x.rawType.kind == tyString when defined(gcDestructors): result = cast[ptr string](x.value)[] @@ -670,23 +670,23 @@ proc getString*(x: Any): string = result = cast[ptr string](x.value)[] proc setString*(x: Any, y: string) = - ## sets the string value of `x`. `x` needs to represent a string. + ## Sets the string value of `x`. `x` needs to represent a string. assert x.rawType.kind == tyString cast[ptr string](x.value)[] = y # also correct for gcDestructors proc getCString*(x: Any): cstring = - ## retrieve the cstring value out of `x`. `x` needs to represent a cstring. + ## Retrieves the cstring value out of `x`. `x` needs to represent a cstring. assert x.rawType.kind == tyCString result = cast[ptr cstring](x.value)[] proc assign*(x, y: Any) = - ## copies the value of `y` to `x`. The assignment operator for ``Any`` + ## Copies the value of `y` to `x`. The assignment operator for ``Any`` ## does NOT do this; it performs a shallow copy instead! assert y.rawType == x.rawType genericAssign(x.value, y.value, y.rawType) iterator elements*(x: Any): int = - ## iterates over every element of `x` that represents a Nim bitset. + ## Iterates over every element of `x` that represents a Nim bitset. assert x.rawType.kind == tySet var typ = x.rawType var p = x.value @@ -708,7 +708,7 @@ iterator elements*(x: Any): int = yield i+typ.node.len proc inclSetElement*(x: Any, elem: int) = - ## includes an element `elem` in `x`. `x` needs to represent a Nim bitset. + ## Includes an element `elem` in `x`. `x` needs to represent a Nim bitset. assert x.rawType.kind == tySet var typ = x.rawType var p = x.value @@ -730,62 +730,3 @@ proc inclSetElement*(x: Any, elem: int) = else: var a = cast[pbyteArray](p) a[e shr 3] = toU8(a[e shr 3] or (1 shl (e and 7))) - -when isMainModule: - type - TE = enum - blah, blah2 - - TestObj = object - test, asd: int - case test2: TE - of blah: - help: string - else: - nil - - var test = @[0,1,2,3,4] - var x = toAny(test) - var y = 78 - x[4] = toAny(y) - assert cast[ptr int](x[2].value)[] == 2 - - var test2: tuple[name: string, s: int] = ("test", 56) - var x2 = toAny(test2) - var i = 0 - for n, a in fields(x2): - case i - of 0: assert n == "name" and $a.kind == "akString" - of 1: assert n == "s" and $a.kind == "akInt" - else: assert false - inc i - - var test3: TestObj - test3.test = 42 - test3 = TestObj(test2: blah2) - var x3 = toAny(test3) - i = 0 - for n, a in fields(x3): - case i - of 0: assert n == "test" and $a.kind == "akInt" - of 1: assert n == "asd" and $a.kind == "akInt" - of 2: assert n == "test2" and $a.kind == "akEnum" - else: assert false - inc i - - var test4: ref string - new(test4) - test4[] = "test" - var x4 = toAny(test4) - assert($x4[].kind() == "akString") - - block: - # gimme a new scope dammit - var myarr: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] - var m = toAny(myArr) - for i in 0 .. m.len-1: - for j in 0 .. m[i].len-1: - echo getString(m[i][j]) diff --git a/tests/cpp/ttypeinfo.nim b/tests/cpp/ttypeinfo1.nim similarity index 100% rename from tests/cpp/ttypeinfo.nim rename to tests/cpp/ttypeinfo1.nim diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim new file mode 100644 index 000000000..3155a0f88 --- /dev/null +++ b/tests/stdlib/ttypeinfo.nim @@ -0,0 +1,60 @@ +import typeinfo + +type + TE = enum + blah, blah2 + + TestObj = object + test, asd: int + case test2: TE + of blah: + help: string + else: + nil + + +var test = @[0,1,2,3,4] +var x = toAny(test) +var y = 78 +x[4] = toAny(y) +assert x[2].getInt == 2 + +var test2: tuple[name: string, s: int] = ("test", 56) +var x2 = toAny(test2) +var i = 0 +for n, a in fields(x2): + case i + of 0: assert n == "Field0" and $a.kind == "akString" + of 1: assert n == "Field1" and $a.kind == "akInt" + else: assert false + inc i + +var test3: TestObj +test3.test = 42 +test3 = TestObj(test2: blah2) +var x3 = toAny(test3) +i = 0 +for n, a in fields(x3): + case i + of 0: assert n == "test" and $a.kind == "akInt" + of 1: assert n == "asd" and $a.kind == "akInt" + of 2: assert n == "test2" and $a.kind == "akEnum" + else: assert false + inc i + +var test4: ref string +new(test4) +test4[] = "test" +var x4 = toAny(test4) +assert($x4[].kind() == "akString") + +block: + # gimme a new scope dammit + var myarr: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] + var m = toAny(myArr) + for i in 0 .. m.len-1: + for j in 0 .. m[i].len-1: + doAssert getString(m[i][j]) == myArr[i][j] From 823a71380d9c52c224669fe0dfcf5601619978bd Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:37:41 +0800 Subject: [PATCH 1541/4254] fix #16103 (#16109) [backport:1.0] * fix #16103 * docs --- lib/impure/nre.nim | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 4696f7322..bd17c713e 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -68,7 +68,6 @@ from pcre import nil import nre/private/util import tables from strutils import `%` -from math import ceil import options from unicode import runeLenAt @@ -742,8 +741,25 @@ proc replace*(str: string, pattern: Regex, sub: string): string = replaceImpl(str, pattern, formatStr(sub, match.captures[name], match.captures[id - 1])) -let SpecialCharMatcher = re"([\\+*?[^\]$(){}=!<>|:-])" -proc escapeRe*(str: string): string = - ## Escapes the string so it doesn’t match any special characters. +proc escapeRe*(str: string): string {.gcsafe.} = + ## Escapes the string so it doesn't match any special characters. ## Incompatible with the Extra flag (``X``). - str.replace(SpecialCharMatcher, "\\$1") + ## + ## Escaped char: `\ + * ? [ ^ ] $ ( ) { } = ! < > | : -` + runnableExamples: + doAssert escapeRe("fly+wind") == "fly\\+wind" + doAssert escapeRe("!") == "\\!" + doAssert escapeRe("nim*") == "nim\\*" + + #([\\+*?[^\]$(){}=!<>|:-]) + const SpecialCharMatcher = {'\\', '+', '*', '?', '[', '^', ']', '$', '(', + ')', '{', '}', '=', '!', '<', '>', '|', ':', + '-'} + + for c in items(str): + case c + of SpecialCharMatcher: + result.add("\\") + result.add(c) + else: + result.add(c) From f8b9d8c1904c662f07e5ee1138357695a1df9ac3 Mon Sep 17 00:00:00 2001 From: "Andrey R (cooldome)" Date: Tue, 24 Nov 2020 11:53:55 +0000 Subject: [PATCH 1542/4254] fix #16110 --- tests/macros/tgetimpl.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index d231a4336..54fd2b3e5 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -65,3 +65,22 @@ macro check_gen_proc(ex: typed): (bool, bool) = let a = @[1,2,3] assert: check_gen_proc(len(a)) == (false, true) + + +#--------------------------------------------------------------- +# issue #16110 + +macro check(x: type): untyped = + let z = getType(x) + let y = getImpl(z[1]) + echo z.treeRepr + expectKind(z[1], nnkSym) + expectKind(y[0], nnkSym) + doAssert(y[0] == z[1]) + +type + TirePtr = ptr object + code: int + +var z: TirePtr +check(typeof(z[])) \ No newline at end of file From 2bab2a2cd8476423414819db3ad79309f6033e13 Mon Sep 17 00:00:00 2001 From: "Andrey R (cooldome)" Date: Tue, 24 Nov 2020 11:58:02 +0000 Subject: [PATCH 1543/4254] fix #16110 --- compiler/semstmts.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index cd7428b62..713867b76 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1278,7 +1278,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"), nextId c.idgen, getCurrOwner(c), s.info) - obj.ast = a + obj.ast = a.copyTree + obj.ast[0] = newSymNode(obj) if sfPure in s.flags: obj.flags.incl sfPure obj.typ = st.lastSon From baae8ef38fc932060f225c96146f4579135e1152 Mon Sep 17 00:00:00 2001 From: "Andrey R (cooldome)" Date: Tue, 24 Nov 2020 12:10:43 +0000 Subject: [PATCH 1544/4254] Revert "fix #16110" This reverts commit 2bab2a2cd8476423414819db3ad79309f6033e13. --- compiler/semstmts.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 713867b76..cd7428b62 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1278,8 +1278,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"), nextId c.idgen, getCurrOwner(c), s.info) - obj.ast = a.copyTree - obj.ast[0] = newSymNode(obj) + obj.ast = a if sfPure in s.flags: obj.flags.incl sfPure obj.typ = st.lastSon From 9a2a83ad71ce3766a7b19d7a04613291e6007546 Mon Sep 17 00:00:00 2001 From: "Andrey R (cooldome)" Date: Tue, 24 Nov 2020 12:11:13 +0000 Subject: [PATCH 1545/4254] Revert "fix #16110" This reverts commit f8b9d8c1904c662f07e5ee1138357695a1df9ac3. --- tests/macros/tgetimpl.nim | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index 54fd2b3e5..d231a4336 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -65,22 +65,3 @@ macro check_gen_proc(ex: typed): (bool, bool) = let a = @[1,2,3] assert: check_gen_proc(len(a)) == (false, true) - - -#--------------------------------------------------------------- -# issue #16110 - -macro check(x: type): untyped = - let z = getType(x) - let y = getImpl(z[1]) - echo z.treeRepr - expectKind(z[1], nnkSym) - expectKind(y[0], nnkSym) - doAssert(y[0] == z[1]) - -type - TirePtr = ptr object - code: int - -var z: TirePtr -check(typeof(z[])) \ No newline at end of file From 9a86198ed5c27c11bf005588bd4e70927d30230e Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 24 Nov 2020 14:26:52 +0100 Subject: [PATCH 1546/4254] fix export links in the documentation (#16114) [backport:1.4] * fix export links in the documentation * fix `len` problem --- compiler/docgen.nim | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 57fdad12a..6ee03e292 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -718,7 +718,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string = of skTemplate: result.add(".t") of skConverter: result.add(".c") else: discard - if n.len > paramsPos and n[paramsPos].kind == nkFormalParams: + if n.safeLen > paramsPos and n[paramsPos].kind == nkFormalParams: let params = renderParamTypes(n[paramsPos]) if params.len > 0: result.add(defaultParamSeparator) @@ -968,13 +968,17 @@ proc exportSym(d: PDoc; s: PSym) = elif s.kind != skModule and s.owner != nil: let module = originatingModule(s) if belongsToPackage(d.conf, module): - let external = externalDep(d, module) + let + complexSymbol = complexName(s.kind, s.ast, s.name.s) + symbolOrIdRope = rope(d.newUniquePlainSymbol(complexSymbol)) + external = externalDep(d, module) if d.section[k] != nil: d.section[k].add(", ") # XXX proper anchor generation here dispA(d.conf, d.section[k], - "$1", + "$1", "$1", [rope esc(d.target, s.name.s), - rope changeFileExt(external, "html")]) + rope changeFileExt(external, "html"), + symbolOrIdRope]) proc documentNewEffect(cache: IdentCache; n: PNode): PNode = let s = n[namePos].sym @@ -1077,7 +1081,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = if it.kind == nkSym: if d.module != nil and d.module == it.sym.owner: generateDoc(d, it.sym.ast, orig, kForceExport) - else: + elif it.sym.ast != nil: exportSym(d, it.sym) of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept" of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0]) From afb8b69c0a61fbc821cd3ce014c017a3523bd3d2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 24 Nov 2020 21:29:34 +0800 Subject: [PATCH 1547/4254] improve document for heapqueue (#16107) --- lib/pure/collections/heapqueue.nim | 103 ++++++++++++++++++----------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index 244ccbbee..00e7a3b9d 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -6,50 +6,48 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. -##[ - The `heapqueue` module implements a - `heap data structure`_ - that can be used as a - `priority queue`_. - Heaps are arrays for which `a[k] <= a[2*k+1]` and `a[k] <= a[2*k+2]` for - all `k`, counting elements from 0. The interesting property of a heap is that - `a[0]` is always its smallest element. - Basic usage - ----------- - .. code-block:: Nim - import heapqueue +## The `heapqueue` module implements a +## `heap data structure`_ +## that can be used as a +## `priority queue`_. +## Heaps are arrays for which `a[k] <= a[2*k+1]` and `a[k] <= a[2*k+2]` for +## all `k`, counting elements from 0. The interesting property of a heap is that +## `a[0]` is always its smallest element. +## +## Basic usage +## ----------- +## - var heap = initHeapQueue[int]() - heap.push(8) - heap.push(2) - heap.push(5) - # The first element is the lowest element - assert heap[0] == 2 - # Remove and return the lowest element - assert heap.pop() == 2 - # The lowest element remaining is 5 - assert heap[0] == 5 +runnableExamples: + var heap = initHeapQueue[int]() + heap.push(8) + heap.push(2) + heap.push(5) + # The first element is the lowest element + assert heap[0] == 2 + # Remove and return the lowest element + assert heap.pop() == 2 + # The lowest element remaining is 5 + assert heap[0] == 5 - Usage with custom object - ------------------------ - To use a `HeapQueue` with a custom object, the `<` operator must be - implemented. +## Usage with custom object +## ------------------------ +## To use a `HeapQueue` with a custom object, the `<` operator must be +## implemented. - .. code-block:: Nim - import heapqueue +runnableExamples: + type Job = object + priority: int - type Job = object - priority: int + proc `<`(a, b: Job): bool = a.priority < b.priority - proc `<`(a, b: Job): bool = a.priority < b.priority + var jobs = initHeapQueue[Job]() + jobs.push(Job(priority: 1)) + jobs.push(Job(priority: 2)) - var jobs = initHeapQueue[Job]() - jobs.push(Job(priority: 1)) - jobs.push(Job(priority: 2)) + assert jobs[0].priority == 1 - assert jobs[0].priority == 1 -]## import std/private/since type HeapQueue*[T] = object @@ -135,6 +133,9 @@ proc toHeapQueue*[T](x: openArray[T]): HeapQueue[T] {.since: (1, 3).} = proc pop*[T](heap: var HeapQueue[T]): T = ## Pops and returns the smallest item from `heap`, ## maintaining the heap invariant. + runnableExamples: + var heap = toHeapQueue([9, 5, 8]) + assert heap.pop() == 5 let lastelt = heap.data.pop() if heap.len > 0: result = heap[0] @@ -145,12 +146,22 @@ proc pop*[T](heap: var HeapQueue[T]): T = proc find*[T](heap: HeapQueue[T], x: T): int {.since: (1, 3).} = ## Linear scan to find index of item ``x`` or -1 if not found. + runnableExamples: + var heap = toHeapQueue([9, 5, 8]) + assert heap.find(5) == 0 + assert heap.find(9) == 1 + assert heap.find(777) == -1 result = -1 for i in 0 ..< heap.len: if heap[i] == x: return i proc del*[T](heap: var HeapQueue[T], index: Natural) = ## Removes the element at `index` from `heap`, maintaining the heap invariant. + runnableExamples: + var heap = toHeapQueue([9, 5, 8]) + heap.del(1) + assert heap[0] == 5 + assert heap[1] == 8 swap(heap.data[^1], heap.data[index]) let newLen = heap.len - 1 heap.data.setLen(newLen) @@ -163,16 +174,28 @@ proc replace*[T](heap: var HeapQueue[T], item: T): T = ## more appropriate when using a fixed-size heap. Note that the value ## returned may be larger than item! That constrains reasonable uses of ## this routine unless written as part of a conditional replacement: - ## - ## .. code-block:: nim - ## if item > heap[0]: - ## item = replace(heap, item) + runnableExamples: + var heap = initHeapQueue[int]() + heap.push(5) + heap.push(12) + assert heap.replace(6) == 5 + assert heap.len == 2 + assert heap[0] == 6 + assert heap.replace(4) == 6 result = heap[0] heap.data[0] = item siftup(heap, 0) proc pushpop*[T](heap: var HeapQueue[T], item: T): T = ## Fast version of a push followed by a pop. + runnableExamples: + var heap = initHeapQueue[int]() + heap.push(5) + heap.push(12) + assert heap.pushpop(6) == 5 + assert heap.len == 2 + assert heap[0] == 6 + assert heap.pushpop(4) == 4 result = item if heap.len > 0 and heapCmp(heap.data[0], item): swap(result, heap.data[0]) From 1d14b2c9e61c5e9389f8b52839814156dcf259dd Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 24 Nov 2020 14:49:14 +0000 Subject: [PATCH 1548/4254] fix #16110 (#16117) --- compiler/semstmts.nim | 3 ++- tests/macros/tgetimpl.nim | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index cd7428b62..713867b76 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1278,7 +1278,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"), nextId c.idgen, getCurrOwner(c), s.info) - obj.ast = a + obj.ast = a.copyTree + obj.ast[0] = newSymNode(obj) if sfPure in s.flags: obj.flags.incl sfPure obj.typ = st.lastSon diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index d231a4336..de655561b 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -65,3 +65,21 @@ macro check_gen_proc(ex: typed): (bool, bool) = let a = @[1,2,3] assert: check_gen_proc(len(a)) == (false, true) + +#--------------------------------------------------------------- +# issue #16110 + +macro check(x: type): untyped = + let z = getType(x) + let y = getImpl(z[1]) + echo z.treeRepr + expectKind(z[1], nnkSym) + expectKind(y[0], nnkSym) + doAssert(y[0] == z[1]) + +type + TirePtr = ptr object + code: int + +var z: TirePtr +check(typeof(z[])) \ No newline at end of file From d306a04466b7f1129620dc3ab35443119ed4c867 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 24 Nov 2020 16:09:00 +0100 Subject: [PATCH 1549/4254] fixes #16069; [backport:1.2] [backport:1.4] (#16115) * fixes #16069; refs https://github.com/nim-lang/RFCs/issues/257 [backport:1.2] [backport:1.4] * make tests green again --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 1 + compiler/semfold.nim | 1 + compiler/transf.nim | 5 +++++ compiler/trees.nim | 2 +- tests/arc/topt_no_cursor.nim | 2 +- tests/misc/taddr.nim | 11 ----------- tests/vm/tconstobj.nim | 20 +++++++++++++++++++- 8 files changed, 29 insertions(+), 15 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index da3f3e7d7..2e710fd21 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1122,7 +1122,7 @@ proc safeLen*(n: PNode): int {.inline.} = proc safeArrLen*(n: PNode): int {.inline.} = ## works for array-like objects (strings passed as openArray in VM). - if n.kind in {nkStrLit..nkTripleStrLit}:result = n.strVal.len + if n.kind in {nkStrLit..nkTripleStrLit}: result = n.strVal.len elif n.kind in {nkNone..nkFloat128Lit}: result = 0 else: result = n.len diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ec28eb1ec..ef3ceae62 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -881,6 +881,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = [rdLoc(test), strLit, raiseInstr(p)]) proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = + assert e[0].kind == nkDotExpr if optFieldCheck in p.options: var a: TLoc genRecordFieldAux(p, e[0], d, a) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index b92895b19..958d8c14e 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -685,6 +685,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkBracketExpr: result = foldArrayAccess(m, n, idgen, g) of nkDotExpr: result = foldFieldAccess(m, n, idgen, g) of nkCheckedFieldExpr: + assert n[0].kind == nkDotExpr result = foldFieldAccess(m, n[0], idgen, g) of nkStmtListExpr: var i = 0 diff --git a/compiler/transf.nim b/compiler/transf.nim index 42a78c8e3..ae233d322 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1002,6 +1002,11 @@ proc transform(c: PTransf, n: PNode): PNode = return n of nkExceptBranch: result = transformExceptBranch(c, n) + of nkCheckedFieldExpr: + result = transformSons(c, n) + if result[0].kind != nkDotExpr: + # simplfied beyond a dot expression --> simplify further. + result = result[0] else: result = transformSons(c, n) when false: diff --git a/compiler/trees.nim b/compiler/trees.nim index 63459babe..05c060595 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -211,6 +211,6 @@ proc stupidStmtListExpr*(n: PNode): bool = proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} = # symbols that expand to a complex constant (array, etc.) should not be # inlined, unless it's the empty array: - result = orig.kind == nkSym and + result = orig.kind != cnst.kind and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and cnst.len > ord(cnst.kind == nkObjConstr) diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index d5811e91e..3d37e6269 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -46,7 +46,7 @@ var lvalue lnext _ -`=copy`(lresult, [123]) +lresult = @[123] _ = ( let blitTmp = lresult blitTmp, ";") diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim index 17fccfabe..49a577798 100644 --- a/tests/misc/taddr.nim +++ b/tests/misc/taddr.nim @@ -102,17 +102,6 @@ block: let a2 = (11,) doAssert byLent(a2) == (11,) - block: - when (defined(c) or defined(cpp)) and defined(release): - discard # probably not a bug since optimizer is free to pass by value, and `unsafeAddr` is used - else: - var a = @[12] - doAssert byPtr(a)[] == @[12] - let a2 = [13] - doAssert byPtr(a2)[] == [13] - let a3 = 14 - doAssert byPtr(a3)[] == 14 - block: proc byLent2[T](a: seq[T]): lent T = a[1] var a = @[20,21,22] diff --git a/tests/vm/tconstobj.nim b/tests/vm/tconstobj.nim index 93d0e1d7d..7dc20a0ba 100644 --- a/tests/vm/tconstobj.nim +++ b/tests/vm/tconstobj.nim @@ -3,6 +3,7 @@ discard """ (name: "hello") (-1, 0) (FirstName: "James", LastName: "Franco") +[1, 2, 3] ''' """ @@ -74,4 +75,21 @@ static: # issue #11861 static: # issue #15662 proc a(T: typedesc) = echo T.type - a((int, int)) \ No newline at end of file + a((int, int)) + +# bug #16069 +type + E = enum + val1, val2 + Obj = object + case k: E + of val1: + x: array[3, int] + of val2: + y: uint32 + +const + foo = [1, 2, 3] + arr = Obj(k: val1, x: foo) + +echo arr.x From cbc793b30b10b8e82af7313ac8cd438abf97f7d7 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 02:06:41 +0800 Subject: [PATCH 1550/4254] move tests to testament (#16101) * move tests to testament * minor * fix random * disable test random --- lib/pure/algorithm.nim | 98 ---------- lib/pure/collections/critbits.nim | 63 ------ lib/pure/collections/tables.nim | 314 ------------------------------ lib/pure/cookies.nim | 15 -- lib/pure/fenv.nim | 8 - lib/pure/hashes.nim | 43 ---- lib/pure/httpcore.nim | 25 --- lib/pure/math.nim | 125 ------------ lib/pure/md5.nim | 7 - lib/pure/options.nim | 141 -------------- lib/pure/parsecsv.nim | 32 --- lib/pure/parseutils.nim | 43 ---- lib/pure/punycode.nim | 6 - lib/pure/random.nim | 54 ----- lib/pure/rationals.nim | 97 --------- lib/pure/stats.nim | 47 ----- lib/pure/streams.nim | 14 -- lib/pure/strformat.nim | 142 -------------- lib/pure/strmisc.nim | 21 -- lib/pure/strscans.nim | 112 ----------- lib/pure/strtabs.nim | 12 -- lib/pure/strutils.nim | 217 --------------------- lib/pure/unicode.nim | 216 -------------------- lib/pure/unidecode/unidecode.nim | 5 - lib/pure/uri.nim | 285 --------------------------- lib/std/enumerate.nim | 19 -- lib/std/monotimes.nim | 16 -- lib/std/sha1.nim | 13 -- tests/stdlib/talgorithm.nim | 97 +++++++++ tests/stdlib/tcookies.nim | 15 ++ tests/stdlib/tcritbits.nim | 61 ++++++ tests/stdlib/tenumerate.nim | 19 ++ tests/stdlib/tfenv.nim | 8 + tests/stdlib/thashes.nim | 87 ++++++--- tests/stdlib/thttpcore.nim | 42 ++-- tests/stdlib/tmath.nim | 126 ++++++++++++ tests/stdlib/tmd5.nim | 7 + tests/stdlib/tmonotimes.nim | 16 ++ tests/stdlib/toptions.nim | 144 +++++++++++++- tests/stdlib/tparsecsv.nim | 31 +++ tests/stdlib/tparseutils.nim | 43 ++++ tests/stdlib/tpunycode.nim | 5 + tests/stdlib/trandom.nim | 59 ++++++ tests/stdlib/trationals.nim | 98 ++++++++++ tests/stdlib/tsha1.nim | 13 ++ tests/stdlib/tstats.nim | 46 +++++ tests/stdlib/tstreams.nim | 14 ++ tests/stdlib/tstrformat.nim | 139 ++++++++++++- tests/stdlib/tstrmiscs.nim | 22 +++ tests/stdlib/tstrscans.nim | 112 +++++++++++ tests/stdlib/tstrtabs.nim | 12 ++ tests/stdlib/tstrutil.nim | 217 +++++++++++++++++++++ tests/stdlib/ttables.nim | 311 +++++++++++++++++++++++++++++ tests/stdlib/tunicode.nim | 215 ++++++++++++++++++++ tests/stdlib/tunidecode.nim | 3 +- tests/stdlib/turi.nim | 285 ++++++++++++++++++++++++++- 56 files changed, 2205 insertions(+), 2232 deletions(-) create mode 100644 tests/stdlib/tcookies.nim create mode 100644 tests/stdlib/tcritbits.nim create mode 100644 tests/stdlib/tenumerate.nim create mode 100644 tests/stdlib/tfenv.nim create mode 100644 tests/stdlib/tmd5.nim create mode 100644 tests/stdlib/tmonotimes.nim create mode 100644 tests/stdlib/tparsecsv.nim create mode 100644 tests/stdlib/tparseutils.nim create mode 100644 tests/stdlib/tpunycode.nim create mode 100644 tests/stdlib/trandom.nim create mode 100644 tests/stdlib/trationals.nim create mode 100644 tests/stdlib/tsha1.nim create mode 100644 tests/stdlib/tstats.nim create mode 100644 tests/stdlib/tstrmiscs.nim create mode 100644 tests/stdlib/ttables.nim create mode 100644 tests/stdlib/tunicode.nim diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index ff835b57a..2430e7330 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -665,36 +665,6 @@ proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} = result = true -when isMainModule: - # Tests for lowerBound - var arr = @[1, 2, 3, 5, 6, 7, 8, 9] - assert arr.lowerBound(0) == 0 - assert arr.lowerBound(4) == 3 - assert arr.lowerBound(5) == 3 - assert arr.lowerBound(10) == 8 - arr = @[1, 5, 10] - assert arr.lowerBound(4) == 1 - assert arr.lowerBound(5) == 1 - assert arr.lowerBound(6) == 2 - # Tests for isSorted - var srt1 = [1, 2, 3, 4, 4, 4, 4, 5] - var srt2 = ["iello", "hello"] - var srt3 = [1.0, 1.0, 1.0] - var srt4: seq[int] - assert srt1.isSorted(cmp) == true - assert srt2.isSorted(cmp) == false - assert srt3.isSorted(cmp) == true - assert srt4.isSorted(cmp) == true - var srtseq = newSeq[int]() - assert srtseq.isSorted(cmp) == true - # Tests for reversed - var arr1 = @[0, 1, 2, 3, 4] - assert arr1.reversed() == @[4, 3, 2, 1, 0] - for i in 0 .. high(arr1): - assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] - assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] - - proc rotateInternal[T](arg: var openArray[T]; first, middle, last: int): int = ## A port of std::rotate from c++. Ported from `this reference `_. result = first + last - middle @@ -852,71 +822,3 @@ proc rotatedLeft*[T](arg: openArray[T]; dist: int): seq[T] = let arglen = arg.len let distLeft = ((dist mod arglen) + arglen) mod arglen arg.rotatedInternal(0, distLeft, arg.len) - -when isMainModule: - var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - let list2 = list.rotatedLeft(1 ..< 9, 3) - let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10] - - doAssert list.rotateLeft(1 ..< 9, 3) == 6 - doAssert list == expected - doAssert list2 == @expected - - var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx" - - doAssert s0.rotateLeft(3 ..< 10, 3) == 7 - doAssert s0 == "xxxdefgabcxxx" - doAssert s1.rotateLeft(3 ..< 10, 2) == 8 - doAssert s1 == "xxxcdefgabxxx" - doAssert s2.rotateLeft(3 ..< 10, 4) == 6 - doAssert s2 == "xxxefgabcdxxx" - doAssert s3.rotateLeft(3 ..< 10, -3) == 6 - doAssert s3 == "xxxefgabcdxxx" - doAssert s4.rotateLeft(3 ..< 10, -10) == 6 - doAssert s4 == "xxxefgabcdxxx" - doAssert s5.rotateLeft(3 ..< 10, 11) == 6 - doAssert s5 == "xxxefgabcdxxx" - - block product: - doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input" - doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input" - doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element" - doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1, - 3]], "two elements" - doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6], - @[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements" - doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty" - - block lowerBound: - doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2 - doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4 - doAssert lowerBound([1, 2, 3, 10], 11) == 4 - - block upperBound: - doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2 - doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4 - doAssert upperBound([1, 2, 3, 5], 3) == 3 - - block fillEmptySeq: - var s = newSeq[int]() - s.fill(0) - - block testBinarySearch: - var noData: seq[int] - doAssert binarySearch(noData, 7) == -1 - let oneData = @[1] - doAssert binarySearch(oneData, 1) == 0 - doAssert binarySearch(onedata, 7) == -1 - let someData = @[1, 3, 4, 7] - doAssert binarySearch(someData, 1) == 0 - doAssert binarySearch(somedata, 7) == 3 - doAssert binarySearch(someData, -1) == -1 - doAssert binarySearch(someData, 5) == -1 - doAssert binarySearch(someData, 13) == -1 - let moreData = @[1, 3, 5, 7, 4711] - doAssert binarySearch(moreData, -1) == -1 - doAssert binarySearch(moreData, 1) == 0 - doAssert binarySearch(moreData, 5) == 2 - doAssert binarySearch(moreData, 6) == -1 - doAssert binarySearch(moreData, 4711) == 4 - doAssert binarySearch(moreData, 4712) == -1 diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 4611c2540..695f44646 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -567,66 +567,3 @@ runnableExamples: doAssert critbitAsDict["key"] == -int.high critbitAsDict["key"] = int.high doAssert critbitAsDict["key"] == int.high - - -when isMainModule: - import sequtils - - var r: CritBitTree[void] - r.incl "abc" - r.incl "xyz" - r.incl "def" - r.incl "definition" - r.incl "prefix" - r.incl "foo" - - doAssert r.contains"def" - - r.excl "def" - assert r.missingOrExcl("foo") == false - assert "foo" notin toSeq(r.items) - - assert r.missingOrExcl("foo") == true - - assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] - - assert toSeq(r.itemsWithPrefix("de")) == @["definition"] - var c = CritBitTree[int]() - - c.inc("a") - assert c["a"] == 1 - - c.inc("a", 4) - assert c["a"] == 5 - - c.inc("a", -5) - assert c["a"] == 0 - - c.inc("b", 2) - assert c["b"] == 2 - - c.inc("c", 3) - assert c["c"] == 3 - - c.inc("a", 1) - assert c["a"] == 1 - - var cf = CritBitTree[float]() - - cf.incl("a", 1.0) - assert cf["a"] == 1.0 - - cf.incl("b", 2.0) - assert cf["b"] == 2.0 - - cf.incl("c", 3.0) - assert cf["c"] == 3.0 - - assert cf.len == 3 - cf.excl("c") - assert cf.len == 2 - - var cb: CritBitTree[string] - cb.incl("help", "help") - for k in cb.keysWithPrefix("helpp"): - doAssert false, "there is no prefix helpp" diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index e94e2a00b..a0efcdce2 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -2873,317 +2873,3 @@ iterator mvalues*[A](t: CountTableRef[A]): var int = if t.data[h].val != 0: yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") - - - - -when isMainModule: - type - Person = object - firstName, lastName: string - - proc hash(x: Person): Hash = - ## Piggyback on the already available string hash proc. - ## - ## Without this proc nothing works! - result = x.firstName.hash !& x.lastName.hash - result = !$result - - var - salaries = initTable[Person, int]() - p1, p2: Person - p1.firstName = "Jon" - p1.lastName = "Ross" - salaries[p1] = 30_000 - p2.firstName = "소진" - p2.lastName = "박" - salaries[p2] = 45_000 - var - s2 = initOrderedTable[Person, int]() - s3 = initCountTable[Person]() - s2[p1] = 30_000 - s2[p2] = 45_000 - s3[p1] = 30_000 - s3[p2] = 45_000 - - block: # Ordered table should preserve order after deletion - var - s4 = initOrderedTable[int, int]() - s4[1] = 1 - s4[2] = 2 - s4[3] = 3 - - var prev = 0 - for i in s4.values: - doAssert(prev < i) - prev = i - - s4.del(2) - doAssert(2 notin s4) - doAssert(s4.len == 2) - prev = 0 - for i in s4.values: - doAssert(prev < i) - prev = i - - block: # Deletion from OrderedTable should account for collision groups. See issue #5057. - # The bug is reproducible only with exact keys - const key1 = "boy_jackpot.inGamma" - const key2 = "boy_jackpot.outBlack" - - var t = { - key1: 0, - key2: 0 - }.toOrderedTable() - - t.del(key1) - assert(t.len == 1) - assert(key2 in t) - - var - t1 = initCountTable[string]() - t2 = initCountTable[string]() - t1.inc("foo") - t1.inc("bar", 2) - t1.inc("baz", 3) - t2.inc("foo", 4) - t2.inc("bar") - t2.inc("baz", 11) - merge(t1, t2) - assert(t1["foo"] == 5) - assert(t1["bar"] == 3) - assert(t1["baz"] == 14) - - let - t1r = newCountTable[string]() - t2r = newCountTable[string]() - t1r.inc("foo") - t1r.inc("bar", 2) - t1r.inc("baz", 3) - t2r.inc("foo", 4) - t2r.inc("bar") - t2r.inc("baz", 11) - merge(t1r, t2r) - assert(t1r["foo"] == 5) - assert(t1r["bar"] == 3) - assert(t1r["baz"] == 14) - - var - t1l = initCountTable[string]() - t2l = initCountTable[string]() - t1l.inc("foo") - t1l.inc("bar", 2) - t1l.inc("baz", 3) - t2l.inc("foo", 4) - t2l.inc("bar") - t2l.inc("baz", 11) - - block: - const testKey = "TESTKEY" - let t: CountTableRef[string] = newCountTable[string]() - - # Before, does not compile with error message: - #test_counttable.nim(7, 43) template/generic instantiation from here - #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here - #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode - doAssert 0 == t[testKey] - t.inc(testKey, 3) - doAssert 3 == t[testKey] - - block: - # Clear tests - var clearTable = newTable[int, string]() - clearTable[42] = "asd" - clearTable[123123] = "piuyqwb " - doAssert clearTable[42] == "asd" - clearTable.clear() - doAssert(not clearTable.hasKey(123123)) - doAssert clearTable.getOrDefault(42) == "" - - block: #5482 - var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() - var b = newOrderedTable[string, string](initialSize = 2) - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - assert a == b - - block: #5482 - var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() - var b = newOrderedTable[string, string](initialSize = 2) - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - assert a == b - - block: #5487 - var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() - var b = newOrderedTable[string, string]() # notice, default size! - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - assert a == b - - block: #5487 - var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() - var b = newOrderedTable[string, string]() # notice, default size! - b["wrong?"] = "foo" - b["wrong?"] = "foo2" - assert a == b - - block: - var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() - var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() - var c = newOrderedTable[string, string]() # notice, default size! - c["wrong?"] = "foo" - c["wrong?"] = "foo2" - assert a == b - assert a == c - - block: #6250 - let - a = {3: 1}.toOrderedTable - b = {3: 2}.toOrderedTable - assert((a == b) == false) - assert((b == a) == false) - - block: #6250 - let - a = {3: 2}.toOrderedTable - b = {3: 2}.toOrderedTable - assert((a == b) == true) - assert((b == a) == true) - - block: # CountTable.smallest - let t = toCountTable([0, 0, 5, 5, 5]) - doAssert t.smallest == (0, 2) - - block: #10065 - let t = toCountTable("abracadabra") - doAssert t['z'] == 0 - - var t_mut = toCountTable("abracadabra") - doAssert t_mut['z'] == 0 - # the previous read may not have modified the table. - doAssert t_mut.hasKey('z') == false - t_mut['z'] = 1 - doAssert t_mut['z'] == 1 - doAssert t_mut.hasKey('z') == true - - block: #12813 #13079 - var t = toCountTable("abracadabra") - doAssert len(t) == 5 - - t['a'] = 0 # remove a key - doAssert len(t) == 4 - - block: - var tp: Table[string, string] = initTable[string, string]() - doAssert "test1" == tp.getOrDefault("test1", "test1") - tp["test2"] = "test2" - doAssert "test2" == tp.getOrDefault("test2", "test1") - var tr: TableRef[string, string] = newTable[string, string]() - doAssert "test1" == tr.getOrDefault("test1", "test1") - tr["test2"] = "test2" - doAssert "test2" == tr.getOrDefault("test2", "test1") - var op: OrderedTable[string, string] = initOrderedTable[string, string]() - doAssert "test1" == op.getOrDefault("test1", "test1") - op["test2"] = "test2" - doAssert "test2" == op.getOrDefault("test2", "test1") - var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]() - doAssert "test1" == orf.getOrDefault("test1", "test1") - orf["test2"] = "test2" - doAssert "test2" == orf.getOrDefault("test2", "test1") - - block tableWithoutInit: - var - a: Table[string, int] - b: Table[string, int] - c: Table[string, int] - d: Table[string, int] - e: Table[string, int] - - a["a"] = 7 - doAssert a.hasKey("a") - doAssert a.len == 1 - doAssert a["a"] == 7 - a["a"] = 9 - doAssert a.len == 1 - doAssert a["a"] == 9 - - doAssert b.hasKeyOrPut("b", 5) == false - doAssert b.hasKey("b") - doAssert b.hasKeyOrPut("b", 8) - doAssert b["b"] == 5 - - doAssert c.getOrDefault("a") == 0 - doAssert c.getOrDefault("a", 3) == 3 - c["a"] = 6 - doAssert c.getOrDefault("a", 3) == 6 - - doAssert d.mgetOrPut("a", 3) == 3 - doAssert d.mgetOrPut("a", 6) == 3 - - var x = 99 - doAssert e.pop("a", x) == false - doAssert x == 99 - e["a"] = 77 - doAssert e.pop("a", x) - doAssert x == 77 - - block orderedTableWithoutInit: - var - a: OrderedTable[string, int] - b: OrderedTable[string, int] - c: OrderedTable[string, int] - d: OrderedTable[string, int] - - a["a"] = 7 - doAssert a.hasKey("a") - doAssert a.len == 1 - doAssert a["a"] == 7 - a["a"] = 9 - doAssert a.len == 1 - doAssert a["a"] == 9 - - doAssert b.hasKeyOrPut("b", 5) == false - doAssert b.hasKey("b") - doAssert b.hasKeyOrPut("b", 8) - doAssert b["b"] == 5 - - doAssert c.getOrDefault("a") == 0 - doAssert c.getOrDefault("a", 3) == 3 - c["a"] = 6 - doAssert c.getOrDefault("a", 3) == 6 - - doAssert d.mgetOrPut("a", 3) == 3 - doAssert d.mgetOrPut("a", 6) == 3 - - block countTableWithoutInit: - var - a: CountTable[string] - b: CountTable[string] - c: CountTable[string] - d: CountTable[string] - e: CountTable[string] - - a["a"] = 7 - doAssert a.hasKey("a") - doAssert a.len == 1 - doAssert a["a"] == 7 - a["a"] = 9 - doAssert a.len == 1 - doAssert a["a"] == 9 - - doAssert b["b"] == 0 - b.inc("b") - doAssert b["b"] == 1 - - doAssert c.getOrDefault("a") == 0 - doAssert c.getOrDefault("a", 3) == 3 - c["a"] = 6 - doAssert c.getOrDefault("a", 3) == 6 - - e["f"] = 3 - merge(d, e) - doAssert d.hasKey("f") - d.inc("f") - merge(d, e) - doAssert d["f"] == 7 diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index eaff86ae6..7e686d44f 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -59,18 +59,3 @@ proc setCookie*(key, value: string, expires: DateTime|Time, return setCookie(key, value, domain, path, format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"), noname, secure, httpOnly) - -when isMainModule: - let expire = fromUnix(0) + 1.seconds - - let cookies = [ - setCookie("test", "value", expire), - setCookie("test", "value", expire.local), - setCookie("test", "value", expire.utc) - ] - let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT" - doAssert cookies == [expected, expected, expected] - - let table = parseCookies("uid=1; kp=2") - doAssert table["uid"] == "1" - doAssert table["kp"] == "2" diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index 53b3e3b50..abddaf4cb 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -178,11 +178,3 @@ template maximumPositiveValue*(T: typedesc[float64]): float64 = DBL_MAX template epsilon*(T: typedesc[float64]): float64 = DBL_EPSILON ## The difference between 1.0 and the smallest number greater than ## 1.0 that can be represented in a 64-bit floating-point type. - - -when isMainModule: - func is_significant(x: float): bool = - if x > minimumPositiveValue(float) and x < maximumPositiveValue(float): true - else: false - - doAssert is_significant(10.0) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 3191d4030..667f27e95 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -485,46 +485,3 @@ proc hash*[A](x: set[A]): Hash = for it in items(x): result = result !& hash(it) result = !$result - - -when isMainModule: - block empty: - var - a = "" - b = newSeq[char]() - c = newSeq[int]() - d = cstring"" - e = "abcd" - doAssert hash(a) == 0 - doAssert hash(b) == 0 - doAssert hash(c) == 0 - doAssert hash(d) == 0 - doAssert hashIgnoreCase(a) == 0 - doAssert hashIgnoreStyle(a) == 0 - doAssert hash(e, 3, 2) == 0 - block sameButDifferent: - doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) - doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234") - doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234") - doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234") - block smallSize: # no multibyte hashing - let - xx = @['H', 'i'] - ii = @[72'u8, 105] - ss = "Hi" - doAssert hash(xx) == hash(ii) - doAssert hash(xx) == hash(ss) - doAssert hash(xx) == hash(xx, 0, xx.high) - doAssert hash(ss) == hash(ss, 0, ss.high) - block largeSize: # longer than 4 characters - let - xx = @['H', 'e', 'l', 'l', 'o'] - xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's'] - ssl = "Helloweens" - doAssert hash(xxl) == hash(ssl) - doAssert hash(xxl) == hash(xxl, 0, xxl.high) - doAssert hash(ssl) == hash(ssl, 0, ssl.high) - doAssert hash(xx) == hash(xxl, 0, 4) - doAssert hash(xx) == hash(ssl, 0, 4) - doAssert hash(xx, 0, 3) == hash(xxl, 0, 3) - doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 401e78b9b..7ead64d83 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -345,28 +345,3 @@ func is5xx*(code: HttpCode): bool {.inline.} = func `$`*(httpMethod: HttpMethod): string = return (system.`$`(httpMethod))[4 .. ^1].toUpperAscii() - -when isMainModule: - var test = newHttpHeaders() - test["Connection"] = @["Upgrade", "Close"] - doAssert test["Connection", 0] == "Upgrade" - doAssert test["Connection", 1] == "Close" - test.add("Connection", "Test") - doAssert test["Connection", 2] == "Test" - doAssert "upgrade" in test["Connection"] - - # Bug #5344. - doAssert parseHeader("foobar: ") == ("foobar", @[""]) - let (key, value) = parseHeader("foobar: ") - test = newHttpHeaders() - test[key] = value - doAssert test["foobar"] == "" - - doAssert parseHeader("foobar:") == ("foobar", @[""]) - - block: # test title case - var testTitleCase = newHttpHeaders(titleCase=true) - testTitleCase.add("content-length", "1") - doAssert testTitleCase.hasKey("Content-Length") - for key, val in testTitleCase: - doAssert key == "Content-Length" diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 59368fbd2..af31a5785 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -1101,128 +1101,3 @@ proc lcm*[T](x: openArray[T]): T {.since: (1, 1).} = while i < x.len: result = lcm(result, x[i]) inc(i) - -when isMainModule and not defined(js) and not windowsCC89: - # Check for no side effect annotation - proc mySqrt(num: float): float {.noSideEffect.} = - return sqrt(num) - - # check gamma function - assert(gamma(5.0) == 24.0) # 4! - assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 - assert(erf(6.0) > erf(5.0)) - assert(erfc(6.0) < erfc(5.0)) - -when isMainModule: - # Function for approximate comparison of floats - proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) - - block: # prod - doAssert prod([1, 2, 3, 4]) == 24 - doAssert prod([1.5, 3.4]) == 5.1 - let x: seq[float] = @[] - doAssert prod(x) == 1.0 - - block: # round() tests - # Round to 0 decimal places - doAssert round(54.652) ==~ 55.0 - doAssert round(54.352) ==~ 54.0 - doAssert round(-54.652) ==~ -55.0 - doAssert round(-54.352) ==~ -54.0 - doAssert round(0.0) ==~ 0.0 - - block: # splitDecimal() tests - doAssert splitDecimal(54.674).intpart ==~ 54.0 - doAssert splitDecimal(54.674).floatpart ==~ 0.674 - doAssert splitDecimal(-693.4356).intpart ==~ -693.0 - doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356 - doAssert splitDecimal(0.0).intpart ==~ 0.0 - doAssert splitDecimal(0.0).floatpart ==~ 0.0 - - block: # trunc tests for vcc - doAssert(trunc(-1.1) == -1) - doAssert(trunc(1.1) == 1) - doAssert(trunc(-0.1) == -0) - doAssert(trunc(0.1) == 0) - - #special case - doAssert(classify(trunc(1e1000000)) == fcInf) - doAssert(classify(trunc(-1e1000000)) == fcNegInf) - doAssert(classify(trunc(0.0/0.0)) == fcNan) - doAssert(classify(trunc(0.0)) == fcZero) - - #trick the compiler to produce signed zero - let - f_neg_one = -1.0 - f_zero = 0.0 - f_nan = f_zero / f_zero - - doAssert(classify(trunc(f_neg_one*f_zero)) == fcNegZero) - - doAssert(trunc(-1.1'f32) == -1) - doAssert(trunc(1.1'f32) == 1) - doAssert(trunc(-0.1'f32) == -0) - doAssert(trunc(0.1'f32) == 0) - doAssert(classify(trunc(1e1000000'f32)) == fcInf) - doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf) - doAssert(classify(trunc(f_nan.float32)) == fcNan) - doAssert(classify(trunc(0.0'f32)) == fcZero) - - block: # sgn() tests - assert sgn(1'i8) == 1 - assert sgn(1'i16) == 1 - assert sgn(1'i32) == 1 - assert sgn(1'i64) == 1 - assert sgn(1'u8) == 1 - assert sgn(1'u16) == 1 - assert sgn(1'u32) == 1 - assert sgn(1'u64) == 1 - assert sgn(-12342.8844'f32) == -1 - assert sgn(123.9834'f64) == 1 - assert sgn(0'i32) == 0 - assert sgn(0'f32) == 0 - assert sgn(NegInf) == -1 - assert sgn(Inf) == 1 - assert sgn(NaN) == 0 - - block: # fac() tests - try: - discard fac(-1) - except AssertionDefect: - discard - - doAssert fac(0) == 1 - doAssert fac(1) == 1 - doAssert fac(2) == 2 - doAssert fac(3) == 6 - doAssert fac(4) == 24 - - block: # floorMod/floorDiv - doAssert floorDiv(8, 3) == 2 - doAssert floorMod(8, 3) == 2 - - doAssert floorDiv(8, -3) == -3 - doAssert floorMod(8, -3) == -1 - - doAssert floorDiv(-8, 3) == -3 - doAssert floorMod(-8, 3) == 1 - - doAssert floorDiv(-8, -3) == 2 - doAssert floorMod(-8, -3) == -2 - - doAssert floorMod(8.0, -3.0) ==~ -1.0 - doAssert floorMod(-8.5, 3.0) ==~ 0.5 - - block: # log - doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0) - doAssert log2(8.0'f64) == 3.0'f64 - doAssert log2(4.0'f64) == 2.0'f64 - doAssert log2(2.0'f64) == 1.0'f64 - doAssert log2(1.0'f64) == 0.0'f64 - doAssert classify(log2(0.0'f64)) == fcNegInf - - doAssert log2(8.0'f32) == 3.0'f32 - doAssert log2(4.0'f32) == 2.0'f32 - doAssert log2(2.0'f32) == 1.0'f32 - doAssert log2(1.0'f32) == 0.0'f32 - doAssert classify(log2(0.0'f32)) == fcNegInf diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index 1ea71afd2..ba944ba81 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -278,12 +278,5 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) = zeroMem(addr(c), sizeof(MD5Context)) -when isMainModule: - assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "a3cca2b2aa1e3b5b3b5aad99a8529074") - assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "7e716d0e702df0505fc72e2b89467910") - assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") - when defined(nimHasStyleChecks): {.pop.} #{.push styleChecks: off.} diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 076cf3707..8de4430c1 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -371,144 +371,3 @@ proc unsafeGet*[T](self: Option[T]): lent T {.inline.}= ## Generally, using `get proc <#get,Option[T]>`_ is preferred. assert self.isSome result = self.val - -when isMainModule: - import unittest, sequtils - - # RefPerson is used to test that overloaded `==` operator is not called by - # options. It is defined here in the global scope, because otherwise the test - # will not even consider the `==` operator. Different bug? - type RefPerson = ref object - name: string - - proc `==`(a, b: RefPerson): bool = - assert(not a.isNil and not b.isNil) - a.name == b.name - - suite "options": - # work around a bug in unittest - let intNone = none(int) - let stringNone = none(string) - - test "example": - proc find(haystack: string, needle: char): Option[int] = - for i, c in haystack: - if c == needle: - return some i - - check("abc".find('c').get() == 2) - - let result = "team".find('i') - - check result == intNone - check result.isNone - - test "some": - check some(6).get() == 6 - check some("a").unsafeGet() == "a" - check some(6).isSome - check some("a").isSome - - test "none": - expect UnpackDefect: - discard none(int).get() - check(none(int).isNone) - check(not none(string).isSome) - - test "equality": - check some("a") == some("a") - check some(7) != some(6) - check some("a") != stringNone - check intNone == intNone - - when compiles(some("a") == some(5)): - check false - when compiles(none(string) == none(int)): - check false - - test "get with a default value": - check(some("Correct").get("Wrong") == "Correct") - check(stringNone.get("Correct") == "Correct") - - test "$": - check($(some("Correct")) == "Some(\"Correct\")") - check($(stringNone) == "None[string]") - - test "map with a void result": - var procRan = 0 - some(123).map(proc (v: int) = procRan = v) - check procRan == 123 - intNone.map(proc (v: int) = check false) - - test "map": - check(some(123).map(proc (v: int): int = v * 2) == some(246)) - check(intNone.map(proc (v: int): int = v * 2).isNone) - - test "filter": - check(some(123).filter(proc (v: int): bool = v == 123) == some(123)) - check(some(456).filter(proc (v: int): bool = v == 123).isNone) - check(intNone.filter(proc (v: int): bool = check false).isNone) - - test "flatMap": - proc addOneIfNotZero(v: int): Option[int] = - if v != 0: - result = some(v + 1) - else: - result = none(int) - - check(some(1).flatMap(addOneIfNotZero) == some(2)) - check(some(0).flatMap(addOneIfNotZero) == none(int)) - check(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) - - proc maybeToString(v: int): Option[string] = - if v != 0: - result = some($v) - else: - result = none(string) - - check(some(1).flatMap(maybeToString) == some("1")) - - proc maybeExclaim(v: string): Option[string] = - if v != "": - result = some v & "!" - else: - result = none(string) - - check(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) - check(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) - - test "SomePointer": - var intref: ref int - check(option(intref).isNone) - intref.new - check(option(intref).isSome) - - let tmp = option(intref) - check(sizeof(tmp) == sizeof(ptr int)) - - var prc = proc (x: int): int = x + 1 - check(option(prc).isSome) - prc = nil - check(option(prc).isNone) - - test "none[T]": - check(none[int]().isNone) - check(none(int) == none[int]()) - - test "$ on typed with .name": - type Named = object - name: string - - let nobody = none(Named) - check($nobody == "None[Named]") - - test "$ on type with name()": - type Person = object - myname: string - - let noperson = none(Person) - check($noperson == "None[Person]") - - test "Ref type with overloaded `==`": - let p = some(RefPerson.new()) - check p.isSome diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 2c0dbb802..4a7117dc5 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -357,35 +357,3 @@ when not defined(testing) and isMainModule: for val in items(x.row): echo "##", val, "##" close(x) - -when isMainModule: - import os - import strutils - block: # Tests for reading the header row - let content = "\nOne,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n" - writeFile("temp.csv", content) - - var p: CsvParser - p.open("temp.csv") - p.readHeaderRow() - while p.readRow(): - let zeros = repeat('0', p.currRow-2) - doAssert p.rowEntry("One") == "1" & zeros - doAssert p.rowEntry("Two") == "2" & zeros - doAssert p.rowEntry("Three") == "3" & zeros - doAssert p.rowEntry("Four") == "4" & zeros - p.close() - - when not defined(testing): - var parser: CsvParser - parser.open("temp.csv") - parser.readHeaderRow() - while parser.readRow(): - echo "new row: " - for col in items(parser.headers): - echo "##", col, ":", parser.rowEntry(col), "##" - parser.close() - removeFile("temp.csv") - - # Tidy up - removeFile("temp.csv") diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 4b123117a..29159816d 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -651,47 +651,4 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, break i = j -when isMainModule: - import sequtils - let input = "$test{} $this is ${an{ example}} " - let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"), - (ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")] - doAssert toSeq(interpolatedFragments(input)) == expected - - var value = 0 - discard parseHex("0x38", value) - doAssert value == 56 - - value = -1 - doAssert(parseSaturatedNatural("848", value) == 3) - doAssert value == 848 - - value = -1 - discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value) - doAssert value == high(int) - - value = -1 - discard parseSaturatedNatural("9223372036854775808", value) - doAssert value == high(int) - - value = -1 - discard parseSaturatedNatural("9223372036854775807", value) - doAssert value == high(int) - - value = -1 - discard parseSaturatedNatural("18446744073709551616", value) - doAssert value == high(int) - - value = -1 - discard parseSaturatedNatural("18446744073709551615", value) - doAssert value == high(int) - - value = -1 - doAssert(parseSaturatedNatural("1_000_000", value) == 9) - doAssert value == 1_000_000 - - var i64Value: int64 - discard parseBiggestInt("9223372036854775807", i64Value) - doAssert i64Value == 9223372036854775807 - {.pop.} diff --git a/lib/pure/punycode.nim b/lib/pure/punycode.nim index fc80fabfd..e9e11a1c3 100644 --- a/lib/pure/punycode.nim +++ b/lib/pure/punycode.nim @@ -206,9 +206,3 @@ runnableExamples: doAssert decode("Mnchen-3ya-") == "Mnchen-3ya" doAssert decode("Mnchen-Ost-9db") == "München-Ost" doAssert decode("Bahnhof Mnchen-Ost-u6b") == "Bahnhof München-Ost" - - -when isMainModule: - assert(decode(encode("", "bücher")) == "bücher") - assert(decode(encode("münchen")) == "münchen") - assert encode("xn--", "münchen") == "xn--mnchen-3ya" diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 3d9948d08..683140cd8 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -651,57 +651,3 @@ when not defined(nimscript) and not defined(standalone): randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond) {.pop.} - -when isMainModule: - import stats - - proc main = - var occur: array[1000, int] - - var x = 8234 - for i in 0..100_000: - x = rand(high(occur)) - inc occur[x] - for i, oc in occur: - if oc < 69: - doAssert false, "too few occurrences of " & $i - elif oc > 150: - doAssert false, "too many occurrences of " & $i - - when false: - var rs: RunningStat - for j in 1..5: - for i in 1 .. 1_000: - rs.push(gauss()) - echo("mean: ", rs.mean, - " stdDev: ", rs.standardDeviation(), - " min: ", rs.min, - " max: ", rs.max) - rs.clear() - - var a = [0, 1] - shuffle(a) - doAssert a[0] == 1 - doAssert a[1] == 0 - - doAssert rand(0) == 0 - doAssert sample("a") == 'a' - - when compileOption("rangeChecks"): - try: - discard rand(-1) - doAssert false - except RangeDefect: - discard - - try: - discard rand(-1.0) - doAssert false - except RangeDefect: - discard - - - # don't use causes integer overflow - doAssert compiles(rand[int](low(int) .. high(int))) - - main() diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index c7af91edd..38a88ebc3 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -279,100 +279,3 @@ proc hash*[T](x: Rational[T]): Hash = h = h !& hash(copy.num) h = h !& hash(copy.den) result = !$h - -when isMainModule: - var - z = Rational[int](num: 0, den: 1) - o = initRational(num = 1, den = 1) - a = initRational(1, 2) - b = -1 // -2 - m1 = -1 // 1 - tt = 10 // 2 - - assert(a == a) - assert( (a-a) == z) - assert( (a+b) == o) - assert( (a/b) == o) - assert( (a*b) == 1 // 4) - assert( (3/a) == 6 // 1) - assert( (a/3) == 1 // 6) - assert(a*b == 1 // 4) - assert(tt*z == z) - assert(10*a == tt) - assert(a*10 == tt) - assert(tt/10 == a) - assert(a-m1 == 3 // 2) - assert(a+m1 == -1 // 2) - assert(m1+tt == 16 // 4) - assert(m1-tt == 6 // -1) - - assert(z < o) - assert(z <= o) - assert(z == z) - assert(cmp(z, o) < 0) - assert(cmp(o, z) > 0) - - assert(o == o) - assert(o >= o) - assert(not(o > o)) - assert(cmp(o, o) == 0) - assert(cmp(z, z) == 0) - assert(hash(o) == hash(o)) - - assert(a == b) - assert(a >= b) - assert(not(b > a)) - assert(cmp(a, b) == 0) - assert(hash(a) == hash(b)) - - var x = 1//3 - - x *= 5//1 - assert(x == 5//3) - x += 2 // 9 - assert(x == 17//9) - x -= 9//18 - assert(x == 25//18) - x /= 1//2 - assert(x == 50//18) - - var y = 1//3 - - y *= 4 - assert(y == 4//3) - y += 5 - assert(y == 19//3) - y -= 2 - assert(y == 13//3) - y /= 9 - assert(y == 13//27) - - assert toRational(5) == 5//1 - assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 - assert toInt(z) == 0 - - when sizeof(int) == 8: - assert toRational(0.98765432) == 2111111029 // 2137499919 - assert toRational(PI) == 817696623 // 260280919 - when sizeof(int) == 4: - assert toRational(0.98765432) == 80 // 81 - assert toRational(PI) == 355 // 113 - - assert toRational(0.1) == 1 // 10 - assert toRational(0.9) == 9 // 10 - - assert toRational(0.0) == 0 // 1 - assert toRational(-0.25) == 1 // -4 - assert toRational(3.2) == 16 // 5 - assert toRational(0.33) == 33 // 100 - assert toRational(0.22) == 11 // 50 - assert toRational(10.0) == 10 // 1 - - assert (1//1) div (3//10) == 3 - assert (-1//1) div (3//10) == -3 - assert (3//10) mod (1//1) == 3//10 - assert (-3//10) mod (1//1) == -3//10 - assert floorDiv(1//1, 3//10) == 3 - assert floorDiv(-1//1, 3//10) == -4 - assert floorMod(3//10, 1//1) == 3//10 - assert floorMod(-3//10, 1//1) == 7//10 diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 8684cb60a..20fd1fdcd 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -335,50 +335,3 @@ runnableExamples: doAssert statistics.skewnessS() === 1.018350154434631 doAssert statistics.kurtosis() === -1.0 doAssert statistics.kurtosisS() === -0.7000000000000008 - - -when isMainModule: - proc clean(x: float): float = - result = round(1.0e8*x).float * 1.0e-8 - - var rs: RunningStat - rs.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) - doAssert(rs.n == 8) - doAssert(clean(rs.mean) == 2.0) - doAssert(clean(rs.variance()) == 1.5) - doAssert(clean(rs.varianceS()) == 1.71428571) - doAssert(clean(rs.skewness()) == 0.81649658) - doAssert(clean(rs.skewnessS()) == 1.01835015) - doAssert(clean(rs.kurtosis()) == -1.0) - doAssert(clean(rs.kurtosisS()) == -0.7000000000000001) - - var rs1, rs2: RunningStat - rs1.push(@[1.0, 2.0, 1.0, 4.0]) - rs2.push(@[1.0, 4.0, 1.0, 2.0]) - let rs3 = rs1 + rs2 - doAssert(clean(rs3.mom2) == clean(rs.mom2)) - doAssert(clean(rs3.mom3) == clean(rs.mom3)) - doAssert(clean(rs3.mom4) == clean(rs.mom4)) - rs1 += rs2 - doAssert(clean(rs1.mom2) == clean(rs.mom2)) - doAssert(clean(rs1.mom3) == clean(rs.mom3)) - doAssert(clean(rs1.mom4) == clean(rs.mom4)) - rs1.clear() - rs1.push(@[1.0, 2.2, 1.4, 4.9]) - doAssert(rs1.sum == 9.5) - doAssert(rs1.mean() == 2.375) - - when not defined(cpu32): - # XXX For some reason on 32bit CPUs these results differ - var rr: RunningRegress - rr.push(@[0.0, 1.0, 2.8, 3.0, 4.0], @[0.0, 1.0, 2.3, 3.0, 4.0]) - doAssert(rr.slope() == 0.9695585996955861) - doAssert(rr.intercept() == -0.03424657534246611) - doAssert(rr.correlation() == 0.9905100362239381) - var rr1, rr2: RunningRegress - rr1.push(@[0.0, 1.0], @[0.0, 1.0]) - rr2.push(@[2.8, 3.0, 4.0], @[2.3, 3.0, 4.0]) - let rr3 = rr1 + rr2 - doAssert(rr3.correlation() == rr.correlation()) - doAssert(clean(rr3.slope()) == clean(rr.slope())) - doAssert(clean(rr3.intercept()) == clean(rr.intercept())) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index dc00271a5..de3f41f09 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1520,17 +1520,3 @@ when false: var handle = open(filename, flags) if handle < 0: raise newEOS("posix.open() call failed") result = newFileHandleStream(handle) - -when isMainModule and defined(testing): - var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran") - assert(ss.getPosition == 0) - assert(ss.peekStr(5) == "The q") - assert(ss.getPosition == 0) # haven't moved - assert(ss.readStr(5) == "The q") - assert(ss.getPosition == 5) # did move - assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") - assert(ss.getPosition == 5) # haven't moved - var str = newString(100) - assert(ss.peekLine(str)) - assert(str == "uick brown fox jumped over the lazy dog.") - assert(ss.getPosition == 5) # haven't moved diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index c37b6b1c0..ddf996e48 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -660,145 +660,3 @@ macro fmt*(pattern: string; openChar, closeChar: char): untyped = doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" doAssert """ ""{"123+123"}"" """.fmt('"', '"') == " \"{246}\" " strformatImpl(pattern, openChar.intVal.char, closeChar.intVal.char) - -when isMainModule: - template check(actual, expected: string) = - doAssert actual == expected - - from strutils import toUpperAscii, repeat - - # Basic tests - let s = "string" - check &"{0} {s}", "0 string" - check &"{s[0..2].toUpperAscii}", "STR" - check &"{-10:04}", "-010" - check &"{-10:<04}", "-010" - check &"{-10:>04}", "-010" - check &"0x{10:02X}", "0x0A" - - check &"{10:#04X}", "0x0A" - - check &"""{"test":#>5}""", "#test" - check &"""{"test":>5}""", " test" - - check &"""{"test":#^7}""", "#test##" - - check &"""{"test": <5}""", "test " - check &"""{"test":<5}""", "test " - check &"{1f:.3f}", "1.000" - check &"Hello, {s}!", "Hello, string!" - - # Tests for identifiers without parenthesis - check &"{s} works{s}", "string worksstring" - check &"{s:>7}", " string" - doAssert(not compiles(&"{s_works}")) # parsed as identifier `s_works` - - # Misc general tests - check &"{{}}", "{}" - check &"{0}%", "0%" - check &"{0}%asdf", "0%asdf" - check &("\n{\"\\n\"}\n"), "\n\n\n" - check &"""{"abc"}s""", "abcs" - - # String tests - check &"""{"abc"}""", "abc" - check &"""{"abc":>4}""", " abc" - check &"""{"abc":<4}""", "abc " - check &"""{"":>4}""", " " - check &"""{"":<4}""", " " - - # Int tests - check &"{12345}", "12345" - check &"{ - 12345}", "-12345" - check &"{12345:6}", " 12345" - check &"{12345:>6}", " 12345" - check &"{12345:4}", "12345" - check &"{12345:08}", "00012345" - check &"{-12345:08}", "-0012345" - check &"{0:0}", "0" - check &"{0:02}", "00" - check &"{-1:3}", " -1" - check &"{-1:03}", "-01" - check &"{10}", "10" - check &"{16:#X}", "0x10" - check &"{16:^#7X}", " 0x10 " - check &"{16:^+#7X}", " +0x10 " - - # Hex tests - check &"{0:x}", "0" - check &"{-0:x}", "0" - check &"{255:x}", "ff" - check &"{255:X}", "FF" - check &"{-255:x}", "-ff" - check &"{-255:X}", "-FF" - check &"{255:x} uNaffeCteD CaSe", "ff uNaffeCteD CaSe" - check &"{255:X} uNaffeCteD CaSe", "FF uNaffeCteD CaSe" - check &"{255:4x}", " ff" - check &"{255:04x}", "00ff" - check &"{-255:4x}", " -ff" - check &"{-255:04x}", "-0ff" - - # Float tests - check &"{123.456}", "123.456" - check &"{-123.456}", "-123.456" - check &"{123.456:.3f}", "123.456" - check &"{123.456:+.3f}", "+123.456" - check &"{-123.456:+.3f}", "-123.456" - check &"{-123.456:.3f}", "-123.456" - check &"{123.456:1g}", "123.456" - check &"{123.456:.1f}", "123.5" - check &"{123.456:.0f}", "123." - check &"{123.456:>9.3f}", " 123.456" - check &"{123.456:9.3f}", " 123.456" - check &"{123.456:>9.4f}", " 123.4560" - check &"{123.456:>9.0f}", " 123." - check &"{123.456:<9.4f}", "123.4560 " - - # Float (scientific) tests - check &"{123.456:e}", "1.234560e+02" - check &"{123.456:>13e}", " 1.234560e+02" - check &"{123.456:<13e}", "1.234560e+02 " - check &"{123.456:.1e}", "1.2e+02" - check &"{123.456:.2e}", "1.23e+02" - check &"{123.456:.3e}", "1.235e+02" - - # Note: times.format adheres to the format protocol. Test that this - # works: - import times - - var dt = initDateTime(01, mJan, 2000, 00, 00, 00) - check &"{dt:yyyy-MM-dd}", "2000-01-01" - - var tm = fromUnix(0) - discard &"{tm}" - - var noww = now() - check &"{noww}", $noww - - # Unicode string tests - check &"""{"αβγ"}""", "αβγ" - check &"""{"αβγ":>5}""", " αβγ" - check &"""{"αβγ":<5}""", "αβγ " - check &"""a{"a"}α{"α"}€{"€"}𐍈{"𐍈"}""", "aaαα€€𐍈𐍈" - check &"""a{"a":2}α{"α":2}€{"€":2}𐍈{"𐍈":2}""", "aa αα €€ 𐍈𐍈 " - # Invalid unicode sequences should be handled as plain strings. - # Invalid examples taken from: https://stackoverflow.com/a/3886015/1804173 - let invalidUtf8 = [ - "\xc3\x28", "\xa0\xa1", - "\xe2\x28\xa1", "\xe2\x82\x28", - "\xf0\x28\x8c\xbc", "\xf0\x90\x28\xbc", "\xf0\x28\x8c\x28" - ] - for s in invalidUtf8: - check &"{s:>5}", repeat(" ", 5-s.len) & s - - # bug #11089 - let flfoo: float = 1.0 - check &"{flfoo}", "1.0" - - # bug #11092 - check &"{high(int64)}", "9223372036854775807" - check &"{low(int64)}", "-9223372036854775808" - - doAssert fmt"{'a'} {'b'}" == "a b" - - echo("All tests ok") diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 061c2063b..5060deb78 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -84,24 +84,3 @@ proc rpartition*(s: string, sep: string): (string, string, string) doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") return partition(s, sep, right = true) - -when isMainModule: - doAssert expandTabs("\t", 4) == " " - doAssert expandTabs("\tfoo\t", 4) == " foo " - doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" - doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " - doAssert expandTabs("", 4) == "" - doAssert expandTabs("", 0) == "" - doAssert expandTabs("\t\t\t", 0) == "" - - doAssert partition("foo:bar", ":") == ("foo", ":", "bar") - doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") - doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") - doAssert partition("foobarbar", "foo") == ("", "foo", "barbar") - doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "") - - doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar") - doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "") - doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar") - doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar") - doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index f078b0d20..f7032f428 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -633,115 +633,3 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = result.add res when defined(debugScanp): echo repr result - - -when isMainModule: - proc twoDigits(input: string; x: var int; start: int): int = - if start+1 < input.len and input[start] == '0' and input[start+1] == '0': - result = 2 - x = 13 - else: - result = 0 - - proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int = - result = 0 - while start+result < input.len and input[start+result] in seps: inc result - - proc demangle(s: string; res: var string; start: int): int = - while result+start < s.len and s[result+start] in {'_', '@'}: inc result - res = "" - while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_': - res.add s[result+start] - inc result - while result+start < s.len and s[result+start] > ' ': - inc result - - proc parseGDB(resp: string): seq[string] = - const - digits = {'0'..'9'} - hexdigits = digits + {'a'..'f', 'A'..'F'} - whites = {' ', '\t', '\C', '\L'} - result = @[] - var idx = 0 - while true: - var prc = "" - var info = "" - if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "), - demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')', - *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_))): - result.add prc & " " & info - else: - break - - var key, val: string - var intval: int - var floatval: float - doAssert scanf("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f", key, val, intval, floatVal) - doAssert key == "abc" - doAssert val == "xyz" - doAssert intval == 89 - doAssert floatVal == 33.25 - - var binval: int - var octval: int - var hexval: int - doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) - doAssert binval == 0b0101 - doAssert octval == 0o1234 - doAssert hexval == 0xabcd - - let xx = scanf("$abc", "$$$i", intval) - doAssert xx == false - - - let xx2 = scanf("$1234", "$$$i", intval) - doAssert xx2 - - let yy = scanf(";.--Breakpoint00 [output]", - "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", - intVal, key) - doAssert yy - doAssert key == "output" - doAssert intVal == 13 - - var ident = "" - var idx = 0 - let zz = scanp("foobar x x x xWZ", idx, +{'a'..'z'} -> add(ident, $_), *(*{ - ' ', '\t'}, "x"), ~'U', "Z") - doAssert zz - doAssert ident == "foobar" - - const digits = {'0'..'9'} - var year = 0 - var idx2 = 0 - if scanp("201655-8-9", idx2, `digits`{4, 6} -> (year = year * 10 + ord($_) - - ord('0')), "-8", "-9"): - doAssert year == 201655 - - const gdbOut = """ - #0 @foo_96013_1208911747@8 (x0=...) - at c:/users/anwender/projects/nim/temp.nim:11 - #1 0x00417754 in tempInit000 () at c:/users/anwender/projects/nim/temp.nim:13 - #2 0x0041768d in NimMainInner () - at c:/users/anwender/projects/nim/lib/system.nim:2605 - #3 0x004176b1 in NimMain () - at c:/users/anwender/projects/nim/lib/system.nim:2613 - #4 0x004176db in main (argc=1, args=0x712cc8, env=0x711ca8) - at c:/users/anwender/projects/nim/lib/system.nim:2620""" - const result = @["foo c:/users/anwender/projects/nim/temp.nim:11", - "tempInit000 c:/users/anwender/projects/nim/temp.nim:13", - "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605", - "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613", - "main c:/users/anwender/projects/nim/lib/system.nim:2620"] - #doAssert parseGDB(gdbOut) == result - - # bug #6487 - var count = 0 - - proc test(): string = - inc count - result = ",123123" - - var a: int - discard scanf(test(), ",$i", a) - doAssert count == 1 diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 7b726e134..7cf668d19 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -420,15 +420,3 @@ proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {. else: add(result, f[i]) inc(i) - -when isMainModule: - var x = {"k": "v", "11": "22", "565": "67"}.newStringTable - assert x["k"] == "v" - assert x["11"] == "22" - assert x["565"] == "67" - x["11"] = "23" - assert x["11"] == "23" - - x.clear(modeCaseInsensitive) - x["11"] = "22" - assert x["11"] == "22" diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 0eff80863..f0b447de7 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2920,220 +2920,3 @@ proc isEmptyOrWhitespace*(s: string): bool {.noSideEffect, rtl, extern: "nsuIsEmptyOrWhitespace".} = ## Checks if `s` is empty or consists entirely of whitespace characters. result = s.allCharsInSet(Whitespace) - - -when isMainModule: - proc nonStaticTests = - doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - when not defined(js): - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 - doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" - doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" - doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in - ["1,0e-11", "1,0e-011"] - # bug #6589 - when not defined(js): - doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" - - doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" - doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" - - block: # formatSize tests - when not defined(js): - doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" - doAssert formatSize(4096) == "4KiB" - doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" - doAssert formatSize(4096, includeSpace = true) == "4 KiB" - doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" - - block: # formatEng tests - doAssert formatEng(0, 2, trim = false) == "0.00" - doAssert formatEng(0, 2) == "0" - doAssert formatEng(53, 2, trim = false) == "53.00" - doAssert formatEng(0.053, 2, trim = false) == "53.00e-3" - doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3" - doAssert formatEng(0.053, 4, trim = true) == "53e-3" - doAssert formatEng(0.053, 0) == "53e-3" - doAssert formatEng(52731234) == "52.731234e6" - doAssert formatEng(-52731234) == "-52.731234e6" - doAssert formatEng(52731234, 1) == "52.7e6" - doAssert formatEng(-52731234, 1) == "-52.7e6" - doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6" - doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6" - - doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV" - doAssert formatEng(4.1, siPrefix = true, unit = "V", - useUnitSpace = true) == "4.1 V" - doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space - doAssert formatEng(4100, siPrefix = true) == "4.1 k" - doAssert formatEng(4.1, siPrefix = true, unit = "", - useUnitSpace = true) == "4.1 " # Includes space - doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k" - doAssert formatEng(4100) == "4.1e3" - doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V" - doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 " - # Don't use SI prefix as number is too big - doAssert formatEng(3.1e22, siPrefix = true, unit = "a", - useUnitSpace = true) == "31e21 a" - # Don't use SI prefix as number is too small - doAssert formatEng(3.1e-25, siPrefix = true, unit = "A", - useUnitSpace = true) == "310e-27 A" - - proc staticTests = - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#') == "##1232" - - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#') == "1232##" - - doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == - "The cat eats fish." - - doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " - doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" - - doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" - doAssert "oo".replace("", "abc") == "oo" - - type MyEnum = enum enA, enB, enC, enuD, enE - doAssert parseEnum[MyEnum]("enu_D") == enuD - - doAssert parseEnum("invalid enum value", enC) == enC - - doAssert center("foo", 13) == " foo " - doAssert center("foo", 0) == "foo" - doAssert center("foo", 3, fillChar = 'a') == "foo" - doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" - - doAssert count("foofoofoo", "foofoo") == 1 - doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 - doAssert count("foofoofoo", 'f') == 3 - doAssert count("foofoofoobar", {'f', 'b'}) == 4 - - doAssert strip(" foofoofoo ") == "foofoofoo" - doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" - doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" - doAssert strip("stripme but don't strip this stripme", - chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == - " but don't strip this " - doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" - doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" - - doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" - - doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" - doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", - "PEOPLE!")) == "HELLO PEOPLE!" - doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" - - doAssert isAlphaAscii('r') - doAssert isAlphaAscii('A') - doAssert(not isAlphaAscii('$')) - - doAssert isAlphaNumeric('3') - doAssert isAlphaNumeric('R') - doAssert(not isAlphaNumeric('!')) - - doAssert isDigit('3') - doAssert(not isDigit('a')) - doAssert(not isDigit('%')) - - doAssert isSpaceAscii('\t') - doAssert isSpaceAscii('\l') - doAssert(not isSpaceAscii('A')) - - doAssert(isEmptyOrWhitespace("")) - doAssert(isEmptyOrWhitespace(" ")) - doAssert(isEmptyOrWhitespace("\t\l \v\r\f")) - doAssert(not isEmptyOrWhitespace("ABc \td")) - - doAssert isLowerAscii('a') - doAssert isLowerAscii('z') - doAssert(not isLowerAscii('A')) - doAssert(not isLowerAscii('5')) - doAssert(not isLowerAscii('&')) - doAssert(not isLowerAscii(' ')) - - doAssert isUpperAscii('A') - doAssert(not isUpperAscii('b')) - doAssert(not isUpperAscii('5')) - doAssert(not isUpperAscii('%')) - - doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] - doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"] - doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[ - " foo bar", ""] - doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] - doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] - - doAssert(unescape(r"\x013", "", "") == "\x013") - - doAssert join(["foo", "bar", "baz"]) == "foobarbaz" - doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" - doAssert join([1, 2, 3]) == "123" - doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" - - doAssert """~~!!foo -~~!!bar -~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" - - doAssert """~~!!foo -~~!!bar -~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" - doAssert """~~foo -~~ bar -~~ baz""".unindent(4, "~") == "foo\n bar\n baz" - doAssert """foo -bar - baz - """.unindent(4) == "foo\nbar\nbaz\n" - doAssert """foo - bar - baz - """.unindent(2) == "foo\n bar\n baz\n" - doAssert """foo - bar - baz - """.unindent(100) == "foo\nbar\nbaz\n" - - doAssert """foo - foo - bar - """.unindent() == "foo\nfoo\nbar\n" - - let s = " this is an example " - let s2 = ":this;is;an:example;;" - - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example", - "", ""] - doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] - doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] - doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] - - doAssert s.splitWhitespace() == @["this", "is", "an", "example"] - doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "] - doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "] - doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "] - doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"] - - block: # startsWith / endsWith char tests - var s = "abcdef" - doAssert s.startsWith('a') - doAssert s.startsWith('b') == false - doAssert s.endsWith('f') - doAssert s.endsWith('a') == false - doAssert s.endsWith('\0') == false - - #echo("strutils tests passed") - - nonStaticTests() - staticTests() - static: staticTests() diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 8839a7767..a28e98caf 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1169,219 +1169,3 @@ proc alignLeft*(s: string, count: Natural, padding = ' '.Rune): string {. result.add padStr else: result = s - - -when isMainModule: - - proc asRune(s: static[string]): Rune = - ## Compile-time conversion proc for converting string literals to a Rune - ## value. Returns the first Rune of the specified string. - ## - ## Shortcuts code like ``"å".runeAt(0)`` to ``"å".asRune`` and returns a - ## compile-time constant. - if s.len == 0: Rune(0) - else: s.runeAt(0) - - let - someString = "öÑ" - someRunes = toRunes(someString) - compared = (someString == $someRunes) - doAssert compared == true - - proc testReplacements(word: string): string = - case word - of "two": - return "2" - of "foo": - return "BAR" - of "βeta": - return "beta" - of "alpha": - return "αlpha" - else: - return "12345" - - doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta" - doAssert translate(" two not foo βeta ", testReplacements) == " 2 12345 BAR beta " - - doAssert title("foo bar") == "Foo Bar" - doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma" - doAssert title("") == "" - - doAssert capitalize("βeta") == "Βeta" - doAssert capitalize("foo") == "Foo" - doAssert capitalize("") == "" - - doAssert swapCase("FooBar") == "fOObAR" - doAssert swapCase(" ") == " " - doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA" - doAssert swapCase("a✓B") == "A✓b" - doAssert swapCase("Јамогујестистаклоитоминештети") == "јАМОГУЈЕСТИСТАКЛОИТОМИНЕШТЕТИ" - doAssert swapCase("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ὝΑΛΟΝΦΑΓΕῖΝΔΎΝΑΜΑΙΤΟῦΤΟΟὔΜΕΒΛΆΠΤΕΙ" - doAssert swapCase("Կրնամապակիուտեևինծիանհանգիստչըներ") == "կՐՆԱՄԱՊԱԿԻՈՒՏԵևԻՆԾԻԱՆՀԱՆԳԻՍՏՉԸՆԵՐ" - doAssert swapCase("") == "" - - doAssert isAlpha("r") - doAssert isAlpha("α") - doAssert isAlpha("ϙ") - doAssert isAlpha("ஶ") - doAssert(not isAlpha("$")) - doAssert(not isAlpha("")) - - doAssert isAlpha("Βeta") - doAssert isAlpha("Args") - doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽") - doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") - doAssert isAlpha("Јамогујестистаклоитоминештети") - doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ") - doAssert(not isAlpha("$Foo✓")) - doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞")) - - doAssert isSpace("\t") - doAssert isSpace("\l") - doAssert(not isSpace("Β")) - doAssert(not isSpace("Βeta")) - - doAssert isSpace("\t\l \v\r\f") - doAssert isSpace(" ") - doAssert(not isSpace("")) - doAssert(not isSpace("ΑΓc \td")) - - doAssert(not isLower(' '.Rune)) - - doAssert(not isUpper(' '.Rune)) - - doAssert toUpper("Γ") == "Γ" - doAssert toUpper("b") == "B" - doAssert toUpper("α") == "Α" - doAssert toUpper("✓") == "✓" - doAssert toUpper("ϙ") == "Ϙ" - doAssert toUpper("") == "" - - doAssert toUpper("ΑΒΓ") == "ΑΒΓ" - doAssert toUpper("AAccβ") == "AACCΒ" - doAssert toUpper("A✓$β") == "A✓$Β" - - doAssert toLower("a") == "a" - doAssert toLower("γ") == "γ" - doAssert toLower("Γ") == "γ" - doAssert toLower("4") == "4" - doAssert toLower("Ϙ") == "ϙ" - doAssert toLower("") == "" - - doAssert toLower("abcdγ") == "abcdγ" - doAssert toLower("abCDΓ") == "abcdγ" - doAssert toLower("33aaΓ") == "33aaγ" - - doAssert reversed("Reverse this!") == "!siht esreveR" - doAssert reversed("先秦兩漢") == "漢兩秦先" - doAssert reversed("as⃝df̅") == "f̅ds⃝a" - doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" - doAssert reversed("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ιετπάλβεμὔοοτῦοτιαμανύδνῖεγαϕνολαὕ" - doAssert reversed("Јамогујестистаклоитоминештети") == "итетшенимотиолкатситсејугомаЈ" - doAssert reversed("Կրնամապակիուտեևինծիանհանգիստչըներ") == "րենըչտսիգնահնաիծնիևետւոիկապամանրԿ" - doAssert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅") - const test = "as⃝" - doAssert lastRune(test, test.len-1)[1] == 3 - doAssert graphemeLen("è", 0) == 2 - - # test for rune positioning and runeSubStr() - let s = "Hänsel ««: 10,00€" - - var t = "" - for c in s.utf8: - t.add c - - doAssert(s == t) - - doAssert(runeReverseOffset(s, 1) == (20, 18)) - doAssert(runeReverseOffset(s, 19) == (-1, 18)) - - doAssert(runeStrAtPos(s, 0) == "H") - doAssert(runeSubStr(s, 0, 1) == "H") - doAssert(runeStrAtPos(s, 10) == ":") - doAssert(runeSubStr(s, 10, 1) == ":") - doAssert(runeStrAtPos(s, 9) == "«") - doAssert(runeSubStr(s, 9, 1) == "«") - doAssert(runeStrAtPos(s, 17) == "€") - doAssert(runeSubStr(s, 17, 1) == "€") - # echo runeStrAtPos(s, 18) # index error - - doAssert(runeSubStr(s, 0) == "Hänsel ««: 10,00€") - doAssert(runeSubStr(s, -18) == "Hänsel ««: 10,00€") - doAssert(runeSubStr(s, 10) == ": 10,00€") - doAssert(runeSubStr(s, 18) == "") - doAssert(runeSubStr(s, 0, 10) == "Hänsel ««") - - doAssert(runeSubStr(s, 12) == "10,00€") - doAssert(runeSubStr(s, -6) == "10,00€") - - doAssert(runeSubStr(s, 12, 5) == "10,00") - doAssert(runeSubStr(s, 12, -1) == "10,00") - doAssert(runeSubStr(s, -6, 5) == "10,00") - doAssert(runeSubStr(s, -6, -1) == "10,00") - - doAssert(runeSubStr(s, 0, 100) == "Hänsel ««: 10,00€") - doAssert(runeSubStr(s, -100, 100) == "Hänsel ««: 10,00€") - doAssert(runeSubStr(s, 0, -100) == "") - doAssert(runeSubStr(s, 100, -100) == "") - - block splitTests: - let s = " this is an example " - let s2 = ":this;is;an:example;;" - let s3 = ":this×is×an:example××" - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps = [':'.Rune, ';'.Rune]) == @["", "this", "is", "an", - "example", "", ""] - doAssert s3.split(seps = [':'.Rune, "×".asRune]) == @["", "this", "is", - "an", "example", "", ""] - doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] - doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example "] - doAssert s3.split("×".runeAt(0)) == @[":this", "is", "an:example", "", ""] - - block stripTests: - doAssert(strip("") == "") - doAssert(strip(" ") == "") - doAssert(strip("y") == "y") - doAssert(strip(" foofoofoo ") == "foofoofoo") - doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo") - - block: - let stripTestRunes = ['b'.Rune, 'a'.Rune, 'r'.Rune] - doAssert(strip("barfoofoofoobar", runes = stripTestRunes) == "foofoofoo") - doAssert(strip("sfoofoofoos", leading = false, runes = ['s'.Rune]) == "sfoofoofoo") - doAssert(strip("sfoofoofoos", trailing = false, runes = ['s'.Rune]) == "foofoofoos") - - block: - let stripTestRunes = ["«".asRune, "»".asRune] - doAssert(strip("«TEXT»", runes = stripTestRunes) == "TEXT") - doAssert(strip("copyright©", leading = false, runes = ["©".asRune]) == "copyright") - doAssert(strip("¿Question?", trailing = false, runes = ["¿".asRune]) == "Question?") - doAssert(strip("×text×", leading = false, runes = ["×".asRune]) == "×text") - doAssert(strip("×text×", trailing = false, runes = ["×".asRune]) == "text×") - - block repeatTests: - doAssert repeat('c'.Rune, 5) == "ccccc" - doAssert repeat("×".asRune, 5) == "×××××" - - block alignTests: - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#'.Rune) == "##1232" - doAssert align("1232", 6, "×".asRune) == "××1232" - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#'.Rune) == "1232##" - doAssert alignLeft("1232", 6, "×".asRune) == "1232××" - - block differentSizes: - # upper and lower variants have different number of bytes - doAssert toLower("AẞC") == "aßc" - doAssert toLower("ȺẞCD") == "ⱥßcd" - doAssert toUpper("ⱥbc") == "ȺBC" - doAssert toUpper("rsⱦuv") == "RSȾUV" - doAssert swapCase("ⱥbCd") == "ȺBcD" - doAssert swapCase("XyꟆaB") == "xYᶎAb" - doAssert swapCase("aᵹcᲈd") == "AꝽCꙊD" diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim index 30aaa7cd8..9a10ccc00 100644 --- a/lib/pure/unidecode/unidecode.nim +++ b/lib/pure/unidecode/unidecode.nim @@ -66,8 +66,3 @@ proc unidecode*(s: string): string = var c = int(r) if c <=% 127: add(result, chr(c)) elif c <% translationTable.len: add(result, translationTable[c-128]) - -when isMainModule: - #loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") - doAssert unidecode("Äußerst") == "Ausserst" - doAssert unidecode("北京") == "Bei Jing " diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 3e107a6b8..15d0996a7 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -503,288 +503,3 @@ proc getDataUri*(data, mime: string, encoding = "utf-8"): string {.since: (1, 3) runnableExamples: static: doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" assert encoding.len > 0 and mime.len > 0 # Must *not* be URL-Safe, see RFC-2397 result = "data:" & mime & ";charset=" & encoding & ";base64," & base64.encode(data) - - -when isMainModule: - block: - const test1 = "abc\L+def xyz" - doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" - doAssert decodeUrl(encodeUrl(test1)) == test1 - doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz" - doAssert decodeUrl(encodeUrl(test1, false), false) == test1 - doAssert decodeUrl(encodeUrl(test1)) == test1 - - block: - let str = "http://localhost" - let test = parseUri(str) - doAssert test.path == "" - - block: - let str = "http://localhost/" - let test = parseUri(str) - doAssert test.path == "/" - - block: - let str = "http://localhost:8080/test" - let test = parseUri(str) - doAssert test.scheme == "http" - doAssert test.port == "8080" - doAssert test.path == "/test" - doAssert test.hostname == "localhost" - doAssert($test == str) - - block: - let str = "foo://username:password@example.com:8042/over/there" & - "/index.dtb?type=animal&name=narwhal#nose" - let test = parseUri(str) - doAssert test.scheme == "foo" - doAssert test.username == "username" - doAssert test.password == "password" - doAssert test.hostname == "example.com" - doAssert test.port == "8042" - doAssert test.path == "/over/there/index.dtb" - doAssert test.query == "type=animal&name=narwhal" - doAssert test.anchor == "nose" - doAssert($test == str) - - block: - # IPv6 address - let str = "foo://[::1]:1234/bar?baz=true&qux#quux" - let uri = parseUri(str) - doAssert uri.scheme == "foo" - doAssert uri.hostname == "::1" - doAssert uri.port == "1234" - doAssert uri.path == "/bar" - doAssert uri.query == "baz=true&qux" - doAssert uri.anchor == "quux" - - block: - let str = "urn:example:animal:ferret:nose" - let test = parseUri(str) - doAssert test.scheme == "urn" - doAssert test.path == "example:animal:ferret:nose" - doAssert($test == str) - - block: - let str = "mailto:username@example.com?subject=Topic" - let test = parseUri(str) - doAssert test.scheme == "mailto" - doAssert test.username == "username" - doAssert test.hostname == "example.com" - doAssert test.query == "subject=Topic" - doAssert($test == str) - - block: - let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" - let test = parseUri(str) - doAssert test.scheme == "magnet" - doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" - doAssert($test == str) - - block: - let str = "/test/foo/bar?q=2#asdf" - let test = parseUri(str) - doAssert test.scheme == "" - doAssert test.path == "/test/foo/bar" - doAssert test.query == "q=2" - doAssert test.anchor == "asdf" - doAssert($test == str) - - block: - let str = "test/no/slash" - let test = parseUri(str) - doAssert test.path == "test/no/slash" - doAssert($test == str) - - block: - let str = "//git@github.com:dom96/packages" - let test = parseUri(str) - doAssert test.scheme == "" - doAssert test.username == "git" - doAssert test.hostname == "github.com" - doAssert test.port == "dom96" - doAssert test.path == "/packages" - - block: - let str = "file:///foo/bar/baz.txt" - let test = parseUri(str) - doAssert test.scheme == "file" - doAssert test.username == "" - doAssert test.hostname == "" - doAssert test.port == "" - doAssert test.path == "/foo/bar/baz.txt" - - # Remove dot segments tests - block: - doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" - - # Combine tests - block: - let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz")) - doAssert concat.path == "/foo/bar/baz" - doAssert concat.hostname == "google.com" - doAssert concat.scheme == "http" - - block: - let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz")) - doAssert concat.path == "/baz" - doAssert concat.hostname == "google.com" - doAssert concat.scheme == "http" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) - doAssert concat.path == "/foo/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar")) - doAssert concat.path == "/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) - doAssert concat.path == "/foo/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar")) - doAssert concat.path == "/foo/test/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/")) - doAssert concat.path == "/foo/test/bar/" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"), - parseUri("baz")) - doAssert concat.path == "/foo/test/bar/baz" - - # `/` tests - block: - let test = parseUri("http://example.com/foo") / "bar/asd" - doAssert test.path == "/foo/bar/asd" - - block: - let test = parseUri("http://example.com/foo/") / "/bar/asd" - doAssert test.path == "/foo/bar/asd" - - # removeDotSegments tests - block: - # empty test - doAssert removeDotSegments("") == "" - - # bug #3207 - block: - doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq" - - # bug #4959 - block: - let foo = parseUri("http://example.com") / "/baz" - doAssert foo.path == "/baz" - - # bug found on stream 13/10/17 - block: - let foo = parseUri("http://localhost:9515") / "status" - doAssert $foo == "http://localhost:9515/status" - - # bug #6649 #6652 - block: - var foo = parseUri("http://example.com") - foo.hostname = "example.com" - foo.path = "baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com/" - foo.path = "baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com" - foo.path = "/baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com/" - foo.path = "/baz" - doAssert $foo == "http://example.com/baz" - - foo.hostname = "example.com/" - foo.port = "8000" - foo.path = "baz" - doAssert $foo == "http://example.com:8000/baz" - - foo = parseUri("file:/dir/file") - foo.path = "relative" - doAssert $foo == "file:relative" - - # isAbsolute tests - block: - doAssert "www.google.com".parseUri().isAbsolute() == false - doAssert "http://www.google.com".parseUri().isAbsolute() == true - doAssert "file:/dir/file".parseUri().isAbsolute() == true - doAssert "file://localhost/dir/file".parseUri().isAbsolute() == true - doAssert "urn:ISSN:1535-3613".parseUri().isAbsolute() == true - - # path-relative URL *relative - doAssert "about".parseUri().isAbsolute == false - doAssert "about/staff.html".parseUri().isAbsolute == false - doAssert "about/staff.html?".parseUri().isAbsolute == false - doAssert "about/staff.html?parameters".parseUri().isAbsolute == false - - # absolute-path-relative URL *relative - doAssert "/".parseUri().isAbsolute == false - doAssert "/about".parseUri().isAbsolute == false - doAssert "/about/staff.html".parseUri().isAbsolute == false - doAssert "/about/staff.html?".parseUri().isAbsolute == false - doAssert "/about/staff.html?parameters".parseUri().isAbsolute == false - - # scheme-relative URL *relative - doAssert "//username:password@example.com:8888".parseUri().isAbsolute == false - doAssert "//username@example.com".parseUri().isAbsolute == false - doAssert "//example.com".parseUri().isAbsolute == false - doAssert "//example.com/".parseUri().isAbsolute == false - doAssert "//example.com/about".parseUri().isAbsolute == false - doAssert "//example.com/about/staff.html".parseUri().isAbsolute == false - doAssert "//example.com/about/staff.html?".parseUri().isAbsolute == false - doAssert "//example.com/about/staff.html?parameters".parseUri().isAbsolute == false - - # absolute URL *absolute - doAssert "https://username:password@example.com:8888".parseUri().isAbsolute == true - doAssert "https://username@example.com".parseUri().isAbsolute == true - doAssert "https://example.com".parseUri().isAbsolute == true - doAssert "https://example.com/".parseUri().isAbsolute == true - doAssert "https://example.com/about".parseUri().isAbsolute == true - doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true - doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true - doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true - - # encodeQuery tests - block: - doAssert encodeQuery({:}) == "" - doAssert encodeQuery({"foo": "bar"}) == "foo=bar" - doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz" - doAssert encodeQuery({"foo": "bar & baz"}, usePlus = false) == "foo=bar%20%26%20baz" - doAssert encodeQuery({"foo": ""}) == "foo" - doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo=" - doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3" - doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3" - - block: - var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"} - var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux") - doAssert foo == foo1 - - block: - var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""} - var foo1 = parseUri("http://example.com/foo?do=do&bar") - doAssert foo == foo1 - - block dataUriBase64: - doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64," - doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA==" - doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+" - doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" - doAssert getDataUri("leasure.", "text/plain") == "data:text/plain;charset=utf-8;base64,bGVhc3VyZS4=" - doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r" - doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") == - "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==") - doAssert(getDataUri("""The present is theirs - The future, for which I really worked, is mine.""", "text/plain") == - "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu") - - echo("All good!") diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim index 3def653c8..a8f0e1ba7 100644 --- a/lib/std/enumerate.nim +++ b/lib/std/enumerate.nim @@ -68,22 +68,3 @@ macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = result.add newFor # now wrap the whole macro in a block to create a new scope result = newBlockStmt(result) - -when isMainModule: - let a = @[1, 3, 5, 7] - - block: - var res: seq[(int, int)] - for i, x in enumerate(a): - res.add (i, x) - assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] - block: - var res: seq[(int, int)] - for (i, x) in enumerate(a.items): - res.add (i, x) - assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] - block: - var res: seq[(int, int)] - for i, x in enumerate(3, a): - res.add (i, x) - assert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index f819cbc8d..c56bf77b3 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -152,19 +152,3 @@ proc high*(typ: typedesc[MonoTime]): MonoTime = proc low*(typ: typedesc[MonoTime]): MonoTime = ## Returns the lowest representable `MonoTime`. MonoTime(ticks: low(int64)) - -when isMainModule: - let d = initDuration(nanoseconds = 10) - let t1 = getMonoTime() - let t2 = t1 + d - - doAssert t2 - t1 == d - doAssert t1 == t1 - doAssert t1 != t2 - doAssert t2 - d == t1 - doAssert t1 < t2 - doAssert t1 <= t2 - doAssert t1 <= t1 - doAssert not(t2 < t1) - doAssert t1 < high(MonoTime) - doAssert low(MonoTime) < t1 diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 9763b286e..3c1674bcb 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -267,16 +267,3 @@ proc `==`*(a, b: SecureHash): bool = assert a == c # Not a constant-time comparison, but that's acceptable in this context Sha1Digest(a) == Sha1Digest(b) - -when isMainModule: - let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]") - doAssert hash1 == hash1 - doAssert parseSecureHash($hash1) == hash1 - - template checkVector(s, exp: string) = - doAssert secureHash(s) == parseSecureHash(exp) - - checkVector("", "da39a3ee5e6b4b0d3255bfef95601890afd80709") - checkVector("abc", "a9993e364706816aba3e25717850c26c9cd0d89d") - checkVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "84983e441c3bd26ebaae4aa1f95129e5e54670f1") diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 85ae79219..59336e70d 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -16,3 +16,100 @@ proc test() = discard test() + +block: + # Tests for lowerBound + var arr = @[1, 2, 3, 5, 6, 7, 8, 9] + assert arr.lowerBound(0) == 0 + assert arr.lowerBound(4) == 3 + assert arr.lowerBound(5) == 3 + assert arr.lowerBound(10) == 8 + arr = @[1, 5, 10] + assert arr.lowerBound(4) == 1 + assert arr.lowerBound(5) == 1 + assert arr.lowerBound(6) == 2 + # Tests for isSorted + var srt1 = [1, 2, 3, 4, 4, 4, 4, 5] + var srt2 = ["iello", "hello"] + var srt3 = [1.0, 1.0, 1.0] + var srt4: seq[int] + assert srt1.isSorted(cmp) == true + assert srt2.isSorted(cmp) == false + assert srt3.isSorted(cmp) == true + assert srt4.isSorted(cmp) == true + var srtseq = newSeq[int]() + assert srtseq.isSorted(cmp) == true + # Tests for reversed + var arr1 = @[0, 1, 2, 3, 4] + assert arr1.reversed() == @[4, 3, 2, 1, 0] + for i in 0 .. high(arr1): + assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] + assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] + +block: + var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + let list2 = list.rotatedLeft(1 ..< 9, 3) + let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10] + + doAssert list.rotateLeft(1 ..< 9, 3) == 6 + doAssert list == expected + doAssert list2 == @expected + + var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx" + + doAssert s0.rotateLeft(3 ..< 10, 3) == 7 + doAssert s0 == "xxxdefgabcxxx" + doAssert s1.rotateLeft(3 ..< 10, 2) == 8 + doAssert s1 == "xxxcdefgabxxx" + doAssert s2.rotateLeft(3 ..< 10, 4) == 6 + doAssert s2 == "xxxefgabcdxxx" + doAssert s3.rotateLeft(3 ..< 10, -3) == 6 + doAssert s3 == "xxxefgabcdxxx" + doAssert s4.rotateLeft(3 ..< 10, -10) == 6 + doAssert s4 == "xxxefgabcdxxx" + doAssert s5.rotateLeft(3 ..< 10, 11) == 6 + doAssert s5 == "xxxefgabcdxxx" + + block product: + doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input" + doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input" + doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element" + doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1, + 3]], "two elements" + doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6], + @[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements" + doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty" + + block lowerBound: + doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2 + doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4 + doAssert lowerBound([1, 2, 3, 10], 11) == 4 + + block upperBound: + doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2 + doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4 + doAssert upperBound([1, 2, 3, 5], 3) == 3 + + block fillEmptySeq: + var s = newSeq[int]() + s.fill(0) + + block testBinarySearch: + var noData: seq[int] + doAssert binarySearch(noData, 7) == -1 + let oneData = @[1] + doAssert binarySearch(oneData, 1) == 0 + doAssert binarySearch(onedata, 7) == -1 + let someData = @[1, 3, 4, 7] + doAssert binarySearch(someData, 1) == 0 + doAssert binarySearch(somedata, 7) == 3 + doAssert binarySearch(someData, -1) == -1 + doAssert binarySearch(someData, 5) == -1 + doAssert binarySearch(someData, 13) == -1 + let moreData = @[1, 3, 5, 7, 4711] + doAssert binarySearch(moreData, -1) == -1 + doAssert binarySearch(moreData, 1) == 0 + doAssert binarySearch(moreData, 5) == 2 + doAssert binarySearch(moreData, 6) == -1 + doAssert binarySearch(moreData, 4711) == 4 + doAssert binarySearch(moreData, 4712) == -1 diff --git a/tests/stdlib/tcookies.nim b/tests/stdlib/tcookies.nim new file mode 100644 index 000000000..95b431b19 --- /dev/null +++ b/tests/stdlib/tcookies.nim @@ -0,0 +1,15 @@ +import cookies, times, strtabs + +let expire = fromUnix(0) + 1.seconds + +let theCookies = [ + setCookie("test", "value", expire), + setCookie("test", "value", expire.local), + setCookie("test", "value", expire.utc) +] +let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT" +doAssert theCookies == [expected, expected, expected] + +let table = parseCookies("uid=1; kp=2") +doAssert table["uid"] == "1" +doAssert table["kp"] == "2" diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim new file mode 100644 index 000000000..51cbb7bf2 --- /dev/null +++ b/tests/stdlib/tcritbits.nim @@ -0,0 +1,61 @@ +import sequtils, critbits + + +var r: CritBitTree[void] +r.incl "abc" +r.incl "xyz" +r.incl "def" +r.incl "definition" +r.incl "prefix" +r.incl "foo" + +doAssert r.contains"def" + +r.excl "def" +assert r.missingOrExcl("foo") == false +assert "foo" notin toSeq(r.items) + +assert r.missingOrExcl("foo") == true + +assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] + +assert toSeq(r.itemsWithPrefix("de")) == @["definition"] +var c = CritBitTree[int]() + +c.inc("a") +assert c["a"] == 1 + +c.inc("a", 4) +assert c["a"] == 5 + +c.inc("a", -5) +assert c["a"] == 0 + +c.inc("b", 2) +assert c["b"] == 2 + +c.inc("c", 3) +assert c["c"] == 3 + +c.inc("a", 1) +assert c["a"] == 1 + +var cf = CritBitTree[float]() + +cf.incl("a", 1.0) +assert cf["a"] == 1.0 + +cf.incl("b", 2.0) +assert cf["b"] == 2.0 + +cf.incl("c", 3.0) +assert cf["c"] == 3.0 + +assert cf.len == 3 +cf.excl("c") +assert cf.len == 2 + +var cb: CritBitTree[string] +cb.incl("help", "help") +for k in cb.keysWithPrefix("helpp"): + doAssert false, "there is no prefix helpp" diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim new file mode 100644 index 000000000..e5f21bc15 --- /dev/null +++ b/tests/stdlib/tenumerate.nim @@ -0,0 +1,19 @@ +import std/enumerate + +let a = @[1, 3, 5, 7] + +block: + var res: seq[(int, int)] + for i, x in enumerate(a): + res.add (i, x) + assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] +block: + var res: seq[(int, int)] + for (i, x) in enumerate(a.items): + res.add (i, x) + assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] +block: + var res: seq[(int, int)] + for i, x in enumerate(3, a): + res.add (i, x) + assert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] diff --git a/tests/stdlib/tfenv.nim b/tests/stdlib/tfenv.nim new file mode 100644 index 000000000..f58acf1c8 --- /dev/null +++ b/tests/stdlib/tfenv.nim @@ -0,0 +1,8 @@ +import fenv + + +func is_significant(x: float): bool = + if x > minimumPositiveValue(float) and x < maximumPositiveValue(float): true + else: false + +doAssert is_significant(10.0) diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 259ced2aa..d155111ff 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,34 +1,71 @@ +import hashes -discard """ -output: ''' -[Suite] hashes +block hashes: + block hashing: + var dummy = 0.0 + doAssert hash(dummy) == hash(-dummy) -[Suite] hashing + # "VM and runtime should make the same hash value (hashIdentity)" + block: + const hi123 = hashIdentity(123) + doAssert hashIdentity(123) == hi123 -''' -""" + # "VM and runtime should make the same hash value (hashWangYi1)" + block: + const wy123 = hashWangYi1(123) + doAssert hashWangYi1(123) == wy123 -import unittest, hashes + # "hashIdentity value incorrect at 456" + block: + doAssert hashIdentity(456) == 456 -suite "hashes": - suite "hashing": - test "0.0 and -0.0 should have the same hash value": - var dummy = 0.0 - check hash(dummy) == hash(-dummy) + # "hashWangYi1 value incorrect at 456" + block: + when Hash.sizeof < 8: + doAssert hashWangYi1(456) == 1293320666 + else: + doAssert hashWangYi1(456) == -6421749900419628582 - test "VM and runtime should make the same hash value (hashIdentity)": - const hi123 = hashIdentity(123) - check hashIdentity(123) == hi123 +block empty: + var + a = "" + b = newSeq[char]() + c = newSeq[int]() + d = cstring"" + e = "abcd" + doAssert hash(a) == 0 + doAssert hash(b) == 0 + doAssert hash(c) == 0 + doAssert hash(d) == 0 + doAssert hashIgnoreCase(a) == 0 + doAssert hashIgnoreStyle(a) == 0 + doAssert hash(e, 3, 2) == 0 - test "VM and runtime should make the same hash value (hashWangYi1)": - const wy123 = hashWangYi1(123) - check hashWangYi1(123) == wy123 +block sameButDifferent: + doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) + doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234") + doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234") + doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234") - test "hashIdentity value incorrect at 456": - check hashIdentity(456) == 456 +block smallSize: # no multibyte hashing + let + xx = @['H', 'i'] + ii = @[72'u8, 105] + ss = "Hi" + doAssert hash(xx) == hash(ii) + doAssert hash(xx) == hash(ss) + doAssert hash(xx) == hash(xx, 0, xx.high) + doAssert hash(ss) == hash(ss, 0, ss.high) - test "hashWangYi1 value incorrect at 456": - when Hash.sizeof < 8: - check hashWangYi1(456) == 1293320666 - else: - check hashWangYi1(456) == -6421749900419628582 +block largeSize: # longer than 4 characters + let + xx = @['H', 'e', 'l', 'l', 'o'] + xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's'] + ssl = "Helloweens" + doAssert hash(xxl) == hash(ssl) + doAssert hash(xxl) == hash(xxl, 0, xxl.high) + doAssert hash(ssl) == hash(ssl, 0, ssl.high) + doAssert hash(xx) == hash(xxl, 0, 4) + doAssert hash(xx) == hash(ssl, 0, 4) + doAssert hash(xx, 0, 3) == hash(xxl, 0, 3) + doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index cb1a0875f..fd5e1d90c 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -1,19 +1,12 @@ -discard """ -output: "[Suite] httpcore" -""" - -import unittest - import httpcore, strutils -suite "httpcore": - - test "HttpCode": +block: + block HttpCode: assert $Http418 == "418 I'm a teapot" assert Http418.is4xx() == true assert Http418.is2xx() == false - test "headers": + block headers: var h = newHttpHeaders() assert h.len == 0 h.add("Cookie", "foo") @@ -35,7 +28,7 @@ suite "httpcore": assert seq[string](h1["a"]).join(",") == "1,2,3" - test "test cookies with comma": + block test_cookies_with_comma: doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"]) doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"]) @@ -52,7 +45,7 @@ suite "httpcore": doAssert parseHeader("Accept: foo, bar, prologue") == (key: "Accept", value: @["foo", "bar", "prologue"]) doAssert parseHeader("Accept: foo, bar, prologue, starlight") == (key: "Accept", value: @["foo", "bar", "prologue", "starlight"]) - test "add empty sequence to HTTP headers": + block add_empty_sequence_to_HTTP_headers: block: var headers = newHttpHeaders() headers["empty"] = @[] @@ -78,3 +71,28 @@ suite "httpcore": headers["existing"] = @[] headers["existing"] = @["true"] doAssert headers.hasKey("existing") + +block: + var test = newHttpHeaders() + test["Connection"] = @["Upgrade", "Close"] + doAssert test["Connection", 0] == "Upgrade" + doAssert test["Connection", 1] == "Close" + test.add("Connection", "Test") + doAssert test["Connection", 2] == "Test" + doAssert "upgrade" in test["Connection"] + + # Bug #5344. + doAssert parseHeader("foobar: ") == ("foobar", @[""]) + let (key, value) = parseHeader("foobar: ") + test = newHttpHeaders() + test[key] = value + doAssert test["foobar"] == "" + + doAssert parseHeader("foobar:") == ("foobar", @[""]) + + block: # test title case + var testTitleCase = newHttpHeaders(titleCase=true) + testTitleCase.add("content-length", "1") + doAssert testTitleCase.hasKey("Content-Length") + for key, val in testTitleCase: + doAssert key == "Content-Length" diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 0de09a858..ff1f32d36 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -145,3 +145,129 @@ suite "^": check: compiles(5.5 ^ 2.uint) check: compiles(5.5 ^ 2.uint8) check: not compiles(5.5 ^ 2.2) + +block: + when not defined(js): + # Check for no side effect annotation + proc mySqrt(num: float): float {.noSideEffect.} = + return sqrt(num) + + # check gamma function + assert(gamma(5.0) == 24.0) # 4! + assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 + assert(erf(6.0) > erf(5.0)) + assert(erfc(6.0) < erfc(5.0)) + + + # Function for approximate comparison of floats + proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) + + block: # prod + doAssert prod([1, 2, 3, 4]) == 24 + doAssert prod([1.5, 3.4]) == 5.1 + let x: seq[float] = @[] + doAssert prod(x) == 1.0 + + block: # round() tests + # Round to 0 decimal places + doAssert round(54.652) ==~ 55.0 + doAssert round(54.352) ==~ 54.0 + doAssert round(-54.652) ==~ -55.0 + doAssert round(-54.352) ==~ -54.0 + doAssert round(0.0) ==~ 0.0 + + block: # splitDecimal() tests + doAssert splitDecimal(54.674).intpart ==~ 54.0 + doAssert splitDecimal(54.674).floatpart ==~ 0.674 + doAssert splitDecimal(-693.4356).intpart ==~ -693.0 + doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356 + doAssert splitDecimal(0.0).intpart ==~ 0.0 + doAssert splitDecimal(0.0).floatpart ==~ 0.0 + + block: # trunc tests for vcc + doAssert(trunc(-1.1) == -1) + doAssert(trunc(1.1) == 1) + doAssert(trunc(-0.1) == -0) + doAssert(trunc(0.1) == 0) + + #special case + doAssert(classify(trunc(1e1000000)) == fcInf) + doAssert(classify(trunc(-1e1000000)) == fcNegInf) + doAssert(classify(trunc(0.0/0.0)) == fcNan) + doAssert(classify(trunc(0.0)) == fcZero) + + #trick the compiler to produce signed zero + let + f_neg_one = -1.0 + f_zero = 0.0 + f_nan = f_zero / f_zero + + doAssert(classify(trunc(f_neg_one*f_zero)) == fcNegZero) + + doAssert(trunc(-1.1'f32) == -1) + doAssert(trunc(1.1'f32) == 1) + doAssert(trunc(-0.1'f32) == -0) + doAssert(trunc(0.1'f32) == 0) + doAssert(classify(trunc(1e1000000'f32)) == fcInf) + doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf) + doAssert(classify(trunc(f_nan.float32)) == fcNan) + doAssert(classify(trunc(0.0'f32)) == fcZero) + + block: # sgn() tests + assert sgn(1'i8) == 1 + assert sgn(1'i16) == 1 + assert sgn(1'i32) == 1 + assert sgn(1'i64) == 1 + assert sgn(1'u8) == 1 + assert sgn(1'u16) == 1 + assert sgn(1'u32) == 1 + assert sgn(1'u64) == 1 + assert sgn(-12342.8844'f32) == -1 + assert sgn(123.9834'f64) == 1 + assert sgn(0'i32) == 0 + assert sgn(0'f32) == 0 + assert sgn(NegInf) == -1 + assert sgn(Inf) == 1 + assert sgn(NaN) == 0 + + block: # fac() tests + try: + discard fac(-1) + except AssertionDefect: + discard + + doAssert fac(0) == 1 + doAssert fac(1) == 1 + doAssert fac(2) == 2 + doAssert fac(3) == 6 + doAssert fac(4) == 24 + + block: # floorMod/floorDiv + doAssert floorDiv(8, 3) == 2 + doAssert floorMod(8, 3) == 2 + + doAssert floorDiv(8, -3) == -3 + doAssert floorMod(8, -3) == -1 + + doAssert floorDiv(-8, 3) == -3 + doAssert floorMod(-8, 3) == 1 + + doAssert floorDiv(-8, -3) == 2 + doAssert floorMod(-8, -3) == -2 + + doAssert floorMod(8.0, -3.0) ==~ -1.0 + doAssert floorMod(-8.5, 3.0) ==~ 0.5 + + block: # log + doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0) + doAssert log2(8.0'f64) == 3.0'f64 + doAssert log2(4.0'f64) == 2.0'f64 + doAssert log2(2.0'f64) == 1.0'f64 + doAssert log2(1.0'f64) == 0.0'f64 + doAssert classify(log2(0.0'f64)) == fcNegInf + + doAssert log2(8.0'f32) == 3.0'f32 + doAssert log2(4.0'f32) == 2.0'f32 + doAssert log2(2.0'f32) == 1.0'f32 + doAssert log2(1.0'f32) == 0.0'f32 + doAssert classify(log2(0.0'f32)) == fcNegInf diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim new file mode 100644 index 000000000..736fa05a7 --- /dev/null +++ b/tests/stdlib/tmd5.nim @@ -0,0 +1,7 @@ +import md5 + +assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == + "a3cca2b2aa1e3b5b3b5aad99a8529074") +assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == + "7e716d0e702df0505fc72e2b89467910") +assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") diff --git a/tests/stdlib/tmonotimes.nim b/tests/stdlib/tmonotimes.nim new file mode 100644 index 000000000..cf25ef025 --- /dev/null +++ b/tests/stdlib/tmonotimes.nim @@ -0,0 +1,16 @@ +import std/monotimes, times + +let d = initDuration(nanoseconds = 10) +let t1 = getMonoTime() +let t2 = t1 + d + +doAssert t2 - t1 == d +doAssert t1 == t1 +doAssert t1 != t2 +doAssert t2 - d == t1 +doAssert t1 < t2 +doAssert t1 <= t2 +doAssert t1 <= t1 +doAssert not(t2 < t1) +doAssert t1 < high(MonoTime) +doAssert low(MonoTime) < t1 diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim index b982d747d..04544ffb7 100644 --- a/tests/stdlib/toptions.nim +++ b/tests/stdlib/toptions.nim @@ -13,4 +13,146 @@ type let js = """{"foo": {"test": "123"}}""" let parsed = parseJson(js) let a = parsed.to(Test) -echo $(%*a) \ No newline at end of file +echo $(%*a) + + +# RefPerson is used to test that overloaded `==` operator is not called by +# options. It is defined here in the global scope, because otherwise the test +# will not even consider the `==` operator. Different bug? +type RefPerson = ref object + name: string + +proc `==`(a, b: RefPerson): bool = + assert(not a.isNil and not b.isNil) + a.name == b.name + +block options: + # work around a bug in unittest + let intNone = none(int) + let stringNone = none(string) + + block example: + proc find(haystack: string, needle: char): Option[int] = + for i, c in haystack: + if c == needle: + return some i + + doAssert("abc".find('c').get() == 2) + + let result = "team".find('i') + + doAssert result == intNone + doAssert result.isNone + + block some: + doAssert some(6).get() == 6 + doAssert some("a").unsafeGet() == "a" + doAssert some(6).isSome + doAssert some("a").isSome + + block none: + doAssertRaises UnpackDefect: + discard none(int).get() + doAssert(none(int).isNone) + doAssert(not none(string).isSome) + + block equality: + doAssert some("a") == some("a") + doAssert some(7) != some(6) + doAssert some("a") != stringNone + doAssert intNone == intNone + + when compiles(some("a") == some(5)): + doAssert false + when compiles(none(string) == none(int)): + doAssert false + + block get_with_a_default_value: + doAssert(some("Correct").get("Wrong") == "Correct") + doAssert(stringNone.get("Correct") == "Correct") + + block stringify: + doAssert($(some("Correct")) == "Some(\"Correct\")") + doAssert($(stringNone) == "None[string]") + + block map_with_a_void_result: + var procRan = 0 + some(123).map(proc (v: int) = procRan = v) + doAssert procRan == 123 + intNone.map(proc (v: int) = doAssert false) + + block map: + doAssert(some(123).map(proc (v: int): int = v * 2) == some(246)) + doAssert(intNone.map(proc (v: int): int = v * 2).isNone) + + block filter: + doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123)) + doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone) + doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone) + + block flatMap: + proc addOneIfNotZero(v: int): Option[int] = + if v != 0: + result = some(v + 1) + else: + result = none(int) + + doAssert(some(1).flatMap(addOneIfNotZero) == some(2)) + doAssert(some(0).flatMap(addOneIfNotZero) == none(int)) + doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) + + proc maybeToString(v: int): Option[string] = + if v != 0: + result = some($v) + else: + result = none(string) + + doAssert(some(1).flatMap(maybeToString) == some("1")) + + proc maybeExclaim(v: string): Option[string] = + if v != "": + result = some v & "!" + else: + result = none(string) + + doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) + doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) + + block SomePointer: + var intref: ref int + doAssert(option(intref).isNone) + intref.new + doAssert(option(intref).isSome) + + let tmp = option(intref) + doAssert(sizeof(tmp) == sizeof(ptr int)) + + var prc = proc (x: int): int = x + 1 + doAssert(option(prc).isSome) + prc = nil + doAssert(option(prc).isNone) + + block: + doAssert(none[int]().isNone) + doAssert(none(int) == none[int]()) + + # "$ on typed with .name" + block: + type Named = object + name: string + + let nobody = none(Named) + doAssert($nobody == "None[Named]") + + # "$ on type with name()" + block: + type Person = object + myname: string + + let noperson = none(Person) + doAssert($noperson == "None[Person]") + + # "Ref type with overloaded `==`" + block: + let p = some(RefPerson.new()) + doAssert p.isSome diff --git a/tests/stdlib/tparsecsv.nim b/tests/stdlib/tparsecsv.nim new file mode 100644 index 000000000..0d004d45d --- /dev/null +++ b/tests/stdlib/tparsecsv.nim @@ -0,0 +1,31 @@ +include parsecsv +import strutils, os + +block: # Tests for reading the header row + let content = "\nOne,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n" + writeFile("temp.csv", content) + + var p: CsvParser + p.open("temp.csv") + p.readHeaderRow() + while p.readRow(): + let zeros = repeat('0', p.currRow-2) + doAssert p.rowEntry("One") == "1" & zeros + doAssert p.rowEntry("Two") == "2" & zeros + doAssert p.rowEntry("Three") == "3" & zeros + doAssert p.rowEntry("Four") == "4" & zeros + p.close() + + when not defined(testing): + var parser: CsvParser + parser.open("temp.csv") + parser.readHeaderRow() + while parser.readRow(): + echo "new row: " + for col in items(parser.headers): + echo "##", col, ":", parser.rowEntry(col), "##" + parser.close() + removeFile("temp.csv") + + # Tidy up + removeFile("temp.csv") diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim new file mode 100644 index 000000000..3bc54dff1 --- /dev/null +++ b/tests/stdlib/tparseutils.nim @@ -0,0 +1,43 @@ +import parseutils +import sequtils + +let input = "$test{} $this is ${an{ example}} " +let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"), + (ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")] +doAssert toSeq(interpolatedFragments(input)) == expected + +var value = 0 +discard parseHex("0x38", value) +doAssert value == 56 + +value = -1 +doAssert(parseSaturatedNatural("848", value) == 3) +doAssert value == 848 + +value = -1 +discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value) +doAssert value == high(int) + +value = -1 +discard parseSaturatedNatural("9223372036854775808", value) +doAssert value == high(int) + +value = -1 +discard parseSaturatedNatural("9223372036854775807", value) +doAssert value == high(int) + +value = -1 +discard parseSaturatedNatural("18446744073709551616", value) +doAssert value == high(int) + +value = -1 +discard parseSaturatedNatural("18446744073709551615", value) +doAssert value == high(int) + +value = -1 +doAssert(parseSaturatedNatural("1_000_000", value) == 9) +doAssert value == 1_000_000 + +var i64Value: int64 +discard parseBiggestInt("9223372036854775807", i64Value) +doAssert i64Value == 9223372036854775807 diff --git a/tests/stdlib/tpunycode.nim b/tests/stdlib/tpunycode.nim new file mode 100644 index 000000000..998bd3bdf --- /dev/null +++ b/tests/stdlib/tpunycode.nim @@ -0,0 +1,5 @@ +import punycode + +assert(decode(encode("", "bücher")) == "bücher") +assert(decode(encode("münchen")) == "münchen") +assert encode("xn--", "münchen") == "xn--mnchen-3ya" diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim new file mode 100644 index 000000000..c7c6a3f56 --- /dev/null +++ b/tests/stdlib/trandom.nim @@ -0,0 +1,59 @@ +discard """ + action: compile +""" + +import random + +proc main = + var occur: array[1000, int] + + var x = 8234 + for i in 0..100_000: + x = rand(high(occur)) + inc occur[x] + for i, oc in occur: + if oc < 69: + doAssert false, "too few occurrences of " & $i + elif oc > 150: + doAssert false, "too many occurrences of " & $i + + when false: + var rs: RunningStat + for j in 1..5: + for i in 1 .. 1_000: + rs.push(gauss()) + echo("mean: ", rs.mean, + " stdDev: ", rs.standardDeviation(), + " min: ", rs.min, + " max: ", rs.max) + rs.clear() + + var a = [0, 1] + shuffle(a) + doAssert a[0] == 1 + doAssert a[1] == 0 + + doAssert rand(0) == 0 + doAssert sample("a") == 'a' + + when compileOption("rangeChecks"): + try: + discard rand(-1) + doAssert false + except RangeDefect: + discard + + try: + discard rand(-1.0) + doAssert false + except RangeDefect: + discard + + + # don't use causes integer overflow + doAssert compiles(rand[int](low(int) .. high(int))) + +randomize(223) + +for i in 0 .. 10: + main() diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim new file mode 100644 index 000000000..17238af07 --- /dev/null +++ b/tests/stdlib/trationals.nim @@ -0,0 +1,98 @@ +import rationals, math + + +var + z = Rational[int](num: 0, den: 1) + o = initRational(num = 1, den = 1) + a = initRational(1, 2) + b = -1 // -2 + m1 = -1 // 1 + tt = 10 // 2 + +assert(a == a) +assert( (a-a) == z) +assert( (a+b) == o) +assert( (a/b) == o) +assert( (a*b) == 1 // 4) +assert( (3/a) == 6 // 1) +assert( (a/3) == 1 // 6) +assert(a*b == 1 // 4) +assert(tt*z == z) +assert(10*a == tt) +assert(a*10 == tt) +assert(tt/10 == a) +assert(a-m1 == 3 // 2) +assert(a+m1 == -1 // 2) +assert(m1+tt == 16 // 4) +assert(m1-tt == 6 // -1) + +assert(z < o) +assert(z <= o) +assert(z == z) +assert(cmp(z, o) < 0) +assert(cmp(o, z) > 0) + +assert(o == o) +assert(o >= o) +assert(not(o > o)) +assert(cmp(o, o) == 0) +assert(cmp(z, z) == 0) +assert(hash(o) == hash(o)) + +assert(a == b) +assert(a >= b) +assert(not(b > a)) +assert(cmp(a, b) == 0) +assert(hash(a) == hash(b)) + +var x = 1//3 + +x *= 5//1 +assert(x == 5//3) +x += 2 // 9 +assert(x == 17//9) +x -= 9//18 +assert(x == 25//18) +x /= 1//2 +assert(x == 50//18) + +var y = 1//3 + +y *= 4 +assert(y == 4//3) +y += 5 +assert(y == 19//3) +y -= 2 +assert(y == 13//3) +y /= 9 +assert(y == 13//27) + +assert toRational(5) == 5//1 +assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 +assert toInt(z) == 0 + +when sizeof(int) == 8: + assert toRational(0.98765432) == 2111111029 // 2137499919 + assert toRational(PI) == 817696623 // 260280919 +when sizeof(int) == 4: + assert toRational(0.98765432) == 80 // 81 + assert toRational(PI) == 355 // 113 + +assert toRational(0.1) == 1 // 10 +assert toRational(0.9) == 9 // 10 + +assert toRational(0.0) == 0 // 1 +assert toRational(-0.25) == 1 // -4 +assert toRational(3.2) == 16 // 5 +assert toRational(0.33) == 33 // 100 +assert toRational(0.22) == 11 // 50 +assert toRational(10.0) == 10 // 1 + +assert (1//1) div (3//10) == 3 +assert (-1//1) div (3//10) == -3 +assert (3//10) mod (1//1) == 3//10 +assert (-3//10) mod (1//1) == -3//10 +assert floorDiv(1//1, 3//10) == 3 +assert floorDiv(-1//1, 3//10) == -4 +assert floorMod(3//10, 1//1) == 3//10 +assert floorMod(-3//10, 1//1) == 7//10 diff --git a/tests/stdlib/tsha1.nim b/tests/stdlib/tsha1.nim new file mode 100644 index 000000000..7e67ccaf6 --- /dev/null +++ b/tests/stdlib/tsha1.nim @@ -0,0 +1,13 @@ +import std/sha1 + +let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]") +doAssert hash1 == hash1 +doAssert parseSecureHash($hash1) == hash1 + +template checkVector(s, exp: string) = + doAssert secureHash(s) == parseSecureHash(exp) + +checkVector("", "da39a3ee5e6b4b0d3255bfef95601890afd80709") +checkVector("abc", "a9993e364706816aba3e25717850c26c9cd0d89d") +checkVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1") diff --git a/tests/stdlib/tstats.nim b/tests/stdlib/tstats.nim new file mode 100644 index 000000000..37240c884 --- /dev/null +++ b/tests/stdlib/tstats.nim @@ -0,0 +1,46 @@ +include stats + +proc clean(x: float): float = + result = round(1.0e8*x).float * 1.0e-8 + +var rs: RunningStat +rs.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) +doAssert(rs.n == 8) +doAssert(clean(rs.mean) == 2.0) +doAssert(clean(rs.variance()) == 1.5) +doAssert(clean(rs.varianceS()) == 1.71428571) +doAssert(clean(rs.skewness()) == 0.81649658) +doAssert(clean(rs.skewnessS()) == 1.01835015) +doAssert(clean(rs.kurtosis()) == -1.0) +doAssert(clean(rs.kurtosisS()) == -0.7000000000000001) + +var rs1, rs2: RunningStat +rs1.push(@[1.0, 2.0, 1.0, 4.0]) +rs2.push(@[1.0, 4.0, 1.0, 2.0]) +let rs3 = rs1 + rs2 +doAssert(clean(rs3.mom2) == clean(rs.mom2)) +doAssert(clean(rs3.mom3) == clean(rs.mom3)) +doAssert(clean(rs3.mom4) == clean(rs.mom4)) +rs1 += rs2 +doAssert(clean(rs1.mom2) == clean(rs.mom2)) +doAssert(clean(rs1.mom3) == clean(rs.mom3)) +doAssert(clean(rs1.mom4) == clean(rs.mom4)) +rs1.clear() +rs1.push(@[1.0, 2.2, 1.4, 4.9]) +doAssert(rs1.sum == 9.5) +doAssert(rs1.mean() == 2.375) + +when not defined(cpu32): + # XXX For some reason on 32bit CPUs these results differ + var rr: RunningRegress + rr.push(@[0.0, 1.0, 2.8, 3.0, 4.0], @[0.0, 1.0, 2.3, 3.0, 4.0]) + doAssert(rr.slope() == 0.9695585996955861) + doAssert(rr.intercept() == -0.03424657534246611) + doAssert(rr.correlation() == 0.9905100362239381) + var rr1, rr2: RunningRegress + rr1.push(@[0.0, 1.0], @[0.0, 1.0]) + rr2.push(@[2.8, 3.0, 4.0], @[2.3, 3.0, 4.0]) + let rr3 = rr1 + rr2 + doAssert(rr3.correlation() == rr.correlation()) + doAssert(clean(rr3.slope()) == clean(rr.slope())) + doAssert(clean(rr3.intercept()) == clean(rr.intercept())) \ No newline at end of file diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 0fe6b6933..e0310b5f5 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -61,3 +61,17 @@ doAssert a.readDataStr(buffer, 1..3) == 3 echo buffer + +block: + var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran") + assert(ss.getPosition == 0) + assert(ss.peekStr(5) == "The q") + assert(ss.getPosition == 0) # haven't moved + assert(ss.readStr(5) == "The q") + assert(ss.getPosition == 5) # did move + assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") + assert(ss.getPosition == 5) # haven't moved + var str = newString(100) + assert(ss.peekLine(str)) + assert(str == "uick brown fox jumped over the lazy dog.") + assert(ss.getPosition == 5) # haven't moved diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index b1f3340a4..d483093a7 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -6,7 +6,7 @@ output: '''Received (name: "Foo", species: "Bar")''' # issue #7632 import genericstrformat -import strutils +import strutils, times doAssert works(5) == "formatted 5" @@ -376,3 +376,140 @@ block: doAssert fmt"{x.foo(y) =}" == "x.foo(y) =18" doAssert fmt"{x.foo(y)= }" == "x.foo(y)= 18" doAssert fmt"{x.foo(y) = }" == "x.foo(y) = 18" + +block: + template check(actual, expected: string) = + doAssert actual == expected + + # Basic tests + let s = "string" + check &"{0} {s}", "0 string" + check &"{s[0..2].toUpperAscii}", "STR" + check &"{-10:04}", "-010" + check &"{-10:<04}", "-010" + check &"{-10:>04}", "-010" + check &"0x{10:02X}", "0x0A" + + check &"{10:#04X}", "0x0A" + + check &"""{"test":#>5}""", "#test" + check &"""{"test":>5}""", " test" + + check &"""{"test":#^7}""", "#test##" + + check &"""{"test": <5}""", "test " + check &"""{"test":<5}""", "test " + check &"{1f:.3f}", "1.000" + check &"Hello, {s}!", "Hello, string!" + + # Tests for identifiers without parenthesis + check &"{s} works{s}", "string worksstring" + check &"{s:>7}", " string" + doAssert(not compiles(&"{s_works}")) # parsed as identifier `s_works` + + # Misc general tests + check &"{{}}", "{}" + check &"{0}%", "0%" + check &"{0}%asdf", "0%asdf" + check &("\n{\"\\n\"}\n"), "\n\n\n" + check &"""{"abc"}s""", "abcs" + + # String tests + check &"""{"abc"}""", "abc" + check &"""{"abc":>4}""", " abc" + check &"""{"abc":<4}""", "abc " + check &"""{"":>4}""", " " + check &"""{"":<4}""", " " + + # Int tests + check &"{12345}", "12345" + check &"{ - 12345}", "-12345" + check &"{12345:6}", " 12345" + check &"{12345:>6}", " 12345" + check &"{12345:4}", "12345" + check &"{12345:08}", "00012345" + check &"{-12345:08}", "-0012345" + check &"{0:0}", "0" + check &"{0:02}", "00" + check &"{-1:3}", " -1" + check &"{-1:03}", "-01" + check &"{10}", "10" + check &"{16:#X}", "0x10" + check &"{16:^#7X}", " 0x10 " + check &"{16:^+#7X}", " +0x10 " + + # Hex tests + check &"{0:x}", "0" + check &"{-0:x}", "0" + check &"{255:x}", "ff" + check &"{255:X}", "FF" + check &"{-255:x}", "-ff" + check &"{-255:X}", "-FF" + check &"{255:x} uNaffeCteD CaSe", "ff uNaffeCteD CaSe" + check &"{255:X} uNaffeCteD CaSe", "FF uNaffeCteD CaSe" + check &"{255:4x}", " ff" + check &"{255:04x}", "00ff" + check &"{-255:4x}", " -ff" + check &"{-255:04x}", "-0ff" + + # Float tests + check &"{123.456}", "123.456" + check &"{-123.456}", "-123.456" + check &"{123.456:.3f}", "123.456" + check &"{123.456:+.3f}", "+123.456" + check &"{-123.456:+.3f}", "-123.456" + check &"{-123.456:.3f}", "-123.456" + check &"{123.456:1g}", "123.456" + check &"{123.456:.1f}", "123.5" + check &"{123.456:.0f}", "123." + check &"{123.456:>9.3f}", " 123.456" + check &"{123.456:9.3f}", " 123.456" + check &"{123.456:>9.4f}", " 123.4560" + check &"{123.456:>9.0f}", " 123." + check &"{123.456:<9.4f}", "123.4560 " + + # Float (scientific) tests + check &"{123.456:e}", "1.234560e+02" + check &"{123.456:>13e}", " 1.234560e+02" + check &"{123.456:<13e}", "1.234560e+02 " + check &"{123.456:.1e}", "1.2e+02" + check &"{123.456:.2e}", "1.23e+02" + check &"{123.456:.3e}", "1.235e+02" + + # Note: times.format adheres to the format protocol. Test that this + # works: + + var dt = initDateTime(01, mJan, 2000, 00, 00, 00) + check &"{dt:yyyy-MM-dd}", "2000-01-01" + + var tm = fromUnix(0) + discard &"{tm}" + + var noww = now() + check &"{noww}", $noww + + # Unicode string tests + check &"""{"αβγ"}""", "αβγ" + check &"""{"αβγ":>5}""", " αβγ" + check &"""{"αβγ":<5}""", "αβγ " + check &"""a{"a"}α{"α"}€{"€"}𐍈{"𐍈"}""", "aaαα€€𐍈𐍈" + check &"""a{"a":2}α{"α":2}€{"€":2}𐍈{"𐍈":2}""", "aa αα €€ 𐍈𐍈 " + # Invalid unicode sequences should be handled as plain strings. + # Invalid examples taken from: https://stackoverflow.com/a/3886015/1804173 + let invalidUtf8 = [ + "\xc3\x28", "\xa0\xa1", + "\xe2\x28\xa1", "\xe2\x82\x28", + "\xf0\x28\x8c\xbc", "\xf0\x90\x28\xbc", "\xf0\x28\x8c\x28" + ] + for s in invalidUtf8: + check &"{s:>5}", repeat(" ", 5-s.len) & s + + # bug #11089 + let flfoo: float = 1.0 + check &"{flfoo}", "1.0" + + # bug #11092 + check &"{high(int64)}", "9223372036854775807" + check &"{low(int64)}", "-9223372036854775808" + + doAssert fmt"{'a'} {'b'}" == "a b" \ No newline at end of file diff --git a/tests/stdlib/tstrmiscs.nim b/tests/stdlib/tstrmiscs.nim new file mode 100644 index 000000000..2e9131ff8 --- /dev/null +++ b/tests/stdlib/tstrmiscs.nim @@ -0,0 +1,22 @@ +import strmisc + + +doAssert expandTabs("\t", 4) == " " +doAssert expandTabs("\tfoo\t", 4) == " foo " +doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" +doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " +doAssert expandTabs("", 4) == "" +doAssert expandTabs("", 0) == "" +doAssert expandTabs("\t\t\t", 0) == "" + +doAssert partition("foo:bar", ":") == ("foo", ":", "bar") +doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") +doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") +doAssert partition("foobarbar", "foo") == ("", "foo", "barbar") +doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "") + +doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar") +doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "") +doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar") +doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar") +doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index 6f952368c..9d6f51025 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -98,3 +98,115 @@ block issue15064: doAssert scanf(" ", "<$+> $*", nick3, msg3) doAssert nick3 == "abcd" doAssert msg3 == "" + + +block: + proc twoDigits(input: string; x: var int; start: int): int = + if start+1 < input.len and input[start] == '0' and input[start+1] == '0': + result = 2 + x = 13 + else: + result = 0 + + proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int = + result = 0 + while start+result < input.len and input[start+result] in seps: inc result + + proc demangle(s: string; res: var string; start: int): int = + while result+start < s.len and s[result+start] in {'_', '@'}: inc result + res = "" + while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_': + res.add s[result+start] + inc result + while result+start < s.len and s[result+start] > ' ': + inc result + + proc parseGDB(resp: string): seq[string] = + const + digits = {'0'..'9'} + hexdigits = digits + {'a'..'f', 'A'..'F'} + whites = {' ', '\t', '\C', '\L'} + result = @[] + var idx = 0 + while true: + var prc = "" + var info = "" + if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "), + demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')', + *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_))): + result.add prc & " " & info + else: + break + + var key, val: string + var intval: int + var floatval: float + doAssert scanf("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f", key, val, intval, floatVal) + doAssert key == "abc" + doAssert val == "xyz" + doAssert intval == 89 + doAssert floatVal == 33.25 + + var binval: int + var octval: int + var hexval: int + doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) + doAssert binval == 0b0101 + doAssert octval == 0o1234 + doAssert hexval == 0xabcd + + let xx = scanf("$abc", "$$$i", intval) + doAssert xx == false + + + let xx2 = scanf("$1234", "$$$i", intval) + doAssert xx2 + + let yy = scanf(";.--Breakpoint00 [output]", + "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", + intVal, key) + doAssert yy + doAssert key == "output" + doAssert intVal == 13 + + var ident = "" + var idx = 0 + let zz = scanp("foobar x x x xWZ", idx, +{'a'..'z'} -> add(ident, $_), *(*{ + ' ', '\t'}, "x"), ~'U', "Z") + doAssert zz + doAssert ident == "foobar" + + const digits = {'0'..'9'} + var year = 0 + var idx2 = 0 + if scanp("201655-8-9", idx2, `digits`{4, 6} -> (year = year * 10 + ord($_) - + ord('0')), "-8", "-9"): + doAssert year == 201655 + + const gdbOut = """ + #0 @foo_96013_1208911747@8 (x0=...) + at c:/users/anwender/projects/nim/temp.nim:11 + #1 0x00417754 in tempInit000 () at c:/users/anwender/projects/nim/temp.nim:13 + #2 0x0041768d in NimMainInner () + at c:/users/anwender/projects/nim/lib/system.nim:2605 + #3 0x004176b1 in NimMain () + at c:/users/anwender/projects/nim/lib/system.nim:2613 + #4 0x004176db in main (argc=1, args=0x712cc8, env=0x711ca8) + at c:/users/anwender/projects/nim/lib/system.nim:2620""" + const result = @["foo c:/users/anwender/projects/nim/temp.nim:11", + "tempInit000 c:/users/anwender/projects/nim/temp.nim:13", + "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605", + "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613", + "main c:/users/anwender/projects/nim/lib/system.nim:2620"] + doAssert parseGDB(gdbOut) == result + + # bug #6487 + var count = 0 + + proc test(): string = + inc count + result = ",123123" + + var a: int + discard scanf(test(), ",$i", a) + doAssert count == 1 diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim index 5d7e8c762..d4344f95f 100644 --- a/tests/stdlib/tstrtabs.nim +++ b/tests/stdlib/tstrtabs.nim @@ -102,3 +102,15 @@ writeLine(stdout, "length of table ", $tab.len) writeLine(stdout, `%`("$key1 = $key2", tab, {useEnvironment})) tab.clear writeLine(stdout, "length of table ", $tab.len) + +block: + var x = {"k": "v", "11": "22", "565": "67"}.newStringTable + assert x["k"] == "v" + assert x["11"] == "22" + assert x["565"] == "67" + x["11"] = "23" + assert x["11"] == "23" + + x.clear(modeCaseInsensitive) + x["11"] = "22" + assert x["11"] == "22" diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 162b8ea1b..149d9bb87 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -457,3 +457,220 @@ hey assert 0 == indentation "" assert 0 == indentation " \n \n" assert 0 == indentation " " + + +block: + proc nonStaticTests = + doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" + when not defined(js): + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 + doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" + doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" + doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in + ["1,0e-11", "1,0e-011"] + # bug #6589 + when not defined(js): + doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" + + doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" + doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" + + block: # formatSize tests + when not defined(js): + doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 + doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize(4096) == "4KiB" + doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" + doAssert formatSize(4096, includeSpace = true) == "4 KiB" + doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" + + block: # formatEng tests + doAssert formatEng(0, 2, trim = false) == "0.00" + doAssert formatEng(0, 2) == "0" + doAssert formatEng(53, 2, trim = false) == "53.00" + doAssert formatEng(0.053, 2, trim = false) == "53.00e-3" + doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3" + doAssert formatEng(0.053, 4, trim = true) == "53e-3" + doAssert formatEng(0.053, 0) == "53e-3" + doAssert formatEng(52731234) == "52.731234e6" + doAssert formatEng(-52731234) == "-52.731234e6" + doAssert formatEng(52731234, 1) == "52.7e6" + doAssert formatEng(-52731234, 1) == "-52.7e6" + doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6" + doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6" + + doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV" + doAssert formatEng(4.1, siPrefix = true, unit = "V", + useUnitSpace = true) == "4.1 V" + doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space + doAssert formatEng(4100, siPrefix = true) == "4.1 k" + doAssert formatEng(4.1, siPrefix = true, unit = "", + useUnitSpace = true) == "4.1 " # Includes space + doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k" + doAssert formatEng(4100) == "4.1e3" + doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V" + doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 " + # Don't use SI prefix as number is too big + doAssert formatEng(3.1e22, siPrefix = true, unit = "a", + useUnitSpace = true) == "31e21 a" + # Don't use SI prefix as number is too small + doAssert formatEng(3.1e-25, siPrefix = true, unit = "A", + useUnitSpace = true) == "310e-27 A" + + proc staticTests = + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#') == "##1232" + + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#') == "1232##" + + doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == + "The cat eats fish." + + doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " + doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" + + doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" + doAssert "oo".replace("", "abc") == "oo" + + type MyEnum = enum enA, enB, enC, enuD, enE + doAssert parseEnum[MyEnum]("enu_D") == enuD + + doAssert parseEnum("invalid enum value", enC) == enC + + doAssert center("foo", 13) == " foo " + doAssert center("foo", 0) == "foo" + doAssert center("foo", 3, fillChar = 'a') == "foo" + doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" + + doAssert count("foofoofoo", "foofoo") == 1 + doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 + doAssert count("foofoofoo", 'f') == 3 + doAssert count("foofoofoobar", {'f', 'b'}) == 4 + + doAssert strip(" foofoofoo ") == "foofoofoo" + doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" + doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" + doAssert strip("stripme but don't strip this stripme", + chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == + " but don't strip this " + doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" + doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" + + doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" + + doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" + doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", + "PEOPLE!")) == "HELLO PEOPLE!" + doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" + + doAssert isAlphaAscii('r') + doAssert isAlphaAscii('A') + doAssert(not isAlphaAscii('$')) + + doAssert isAlphaNumeric('3') + doAssert isAlphaNumeric('R') + doAssert(not isAlphaNumeric('!')) + + doAssert isDigit('3') + doAssert(not isDigit('a')) + doAssert(not isDigit('%')) + + doAssert isSpaceAscii('\t') + doAssert isSpaceAscii('\l') + doAssert(not isSpaceAscii('A')) + + doAssert(isEmptyOrWhitespace("")) + doAssert(isEmptyOrWhitespace(" ")) + doAssert(isEmptyOrWhitespace("\t\l \v\r\f")) + doAssert(not isEmptyOrWhitespace("ABc \td")) + + doAssert isLowerAscii('a') + doAssert isLowerAscii('z') + doAssert(not isLowerAscii('A')) + doAssert(not isLowerAscii('5')) + doAssert(not isLowerAscii('&')) + doAssert(not isLowerAscii(' ')) + + doAssert isUpperAscii('A') + doAssert(not isUpperAscii('b')) + doAssert(not isUpperAscii('5')) + doAssert(not isUpperAscii('%')) + + doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] + doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"] + doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[ + " foo bar", ""] + doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] + doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] + + doAssert(unescape(r"\x013", "", "") == "\x013") + + doAssert join(["foo", "bar", "baz"]) == "foobarbaz" + doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" + doAssert join([1, 2, 3]) == "123" + doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + + doAssert """~~!!foo +~~!!bar +~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" + + doAssert """~~!!foo +~~!!bar +~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" + doAssert """~~foo +~~ bar +~~ baz""".unindent(4, "~") == "foo\n bar\n baz" + doAssert """foo +bar + baz + """.unindent(4) == "foo\nbar\nbaz\n" + doAssert """foo + bar + baz + """.unindent(2) == "foo\n bar\n baz\n" + doAssert """foo + bar + baz + """.unindent(100) == "foo\nbar\nbaz\n" + + doAssert """foo + foo + bar + """.unindent() == "foo\nfoo\nbar\n" + + let s = " this is an example " + let s2 = ":this;is;an:example;;" + + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example", + "", ""] + doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] + doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] + doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] + + doAssert s.splitWhitespace() == @["this", "is", "an", "example"] + doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "] + doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "] + doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "] + doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"] + + block: # startsWith / endsWith char tests + var s = "abcdef" + doAssert s.startsWith('a') + doAssert s.startsWith('b') == false + doAssert s.endsWith('f') + doAssert s.endsWith('a') == false + doAssert s.endsWith('\0') == false + + #echo("strutils tests passed") + + nonStaticTests() + staticTests() + static: staticTests() \ No newline at end of file diff --git a/tests/stdlib/ttables.nim b/tests/stdlib/ttables.nim new file mode 100644 index 000000000..656d7be6b --- /dev/null +++ b/tests/stdlib/ttables.nim @@ -0,0 +1,311 @@ +import tables, hashes + +type + Person = object + firstName, lastName: string + +proc hash(x: Person): Hash = + ## Piggyback on the already available string hash proc. + ## + ## Without this proc nothing works! + result = x.firstName.hash !& x.lastName.hash + result = !$result + +var + salaries = initTable[Person, int]() + p1, p2: Person +p1.firstName = "Jon" +p1.lastName = "Ross" +salaries[p1] = 30_000 +p2.firstName = "소진" +p2.lastName = "박" +salaries[p2] = 45_000 +var + s2 = initOrderedTable[Person, int]() + s3 = initCountTable[Person]() +s2[p1] = 30_000 +s2[p2] = 45_000 +s3[p1] = 30_000 +s3[p2] = 45_000 + +block: # Ordered table should preserve order after deletion + var + s4 = initOrderedTable[int, int]() + s4[1] = 1 + s4[2] = 2 + s4[3] = 3 + + var prev = 0 + for i in s4.values: + doAssert(prev < i) + prev = i + + s4.del(2) + doAssert(2 notin s4) + doAssert(s4.len == 2) + prev = 0 + for i in s4.values: + doAssert(prev < i) + prev = i + +block: # Deletion from OrderedTable should account for collision groups. See issue #5057. + # The bug is reproducible only with exact keys + const key1 = "boy_jackpot.inGamma" + const key2 = "boy_jackpot.outBlack" + + var t = { + key1: 0, + key2: 0 + }.toOrderedTable() + + t.del(key1) + assert(t.len == 1) + assert(key2 in t) + +var + t1 = initCountTable[string]() + t2 = initCountTable[string]() +t1.inc("foo") +t1.inc("bar", 2) +t1.inc("baz", 3) +t2.inc("foo", 4) +t2.inc("bar") +t2.inc("baz", 11) +merge(t1, t2) +assert(t1["foo"] == 5) +assert(t1["bar"] == 3) +assert(t1["baz"] == 14) + +let + t1r = newCountTable[string]() + t2r = newCountTable[string]() +t1r.inc("foo") +t1r.inc("bar", 2) +t1r.inc("baz", 3) +t2r.inc("foo", 4) +t2r.inc("bar") +t2r.inc("baz", 11) +merge(t1r, t2r) +assert(t1r["foo"] == 5) +assert(t1r["bar"] == 3) +assert(t1r["baz"] == 14) + +var + t1l = initCountTable[string]() + t2l = initCountTable[string]() +t1l.inc("foo") +t1l.inc("bar", 2) +t1l.inc("baz", 3) +t2l.inc("foo", 4) +t2l.inc("bar") +t2l.inc("baz", 11) + +block: + const testKey = "TESTKEY" + let t: CountTableRef[string] = newCountTable[string]() + + # Before, does not compile with error message: + #test_counttable.nim(7, 43) template/generic instantiation from here + #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here + #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode + doAssert 0 == t[testKey] + t.inc(testKey, 3) + doAssert 3 == t[testKey] + +block: + # Clear tests + var clearTable = newTable[int, string]() + clearTable[42] = "asd" + clearTable[123123] = "piuyqwb " + doAssert clearTable[42] == "asd" + clearTable.clear() + doAssert(not clearTable.hasKey(123123)) + doAssert clearTable.getOrDefault(42) == "" + +block: #5482 + var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() + var b = newOrderedTable[string, string](initialSize = 2) + b["wrong?"] = "foo" + b["wrong?"] = "foo2" + assert a == b + +block: #5482 + var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() + var b = newOrderedTable[string, string](initialSize = 2) + b["wrong?"] = "foo" + b["wrong?"] = "foo2" + assert a == b + +block: #5487 + var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() + var b = newOrderedTable[string, string]() # notice, default size! + b["wrong?"] = "foo" + b["wrong?"] = "foo2" + assert a == b + +block: #5487 + var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() + var b = newOrderedTable[string, string]() # notice, default size! + b["wrong?"] = "foo" + b["wrong?"] = "foo2" + assert a == b + +block: + var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() + var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() + var c = newOrderedTable[string, string]() # notice, default size! + c["wrong?"] = "foo" + c["wrong?"] = "foo2" + assert a == b + assert a == c + +block: #6250 + let + a = {3: 1}.toOrderedTable + b = {3: 2}.toOrderedTable + assert((a == b) == false) + assert((b == a) == false) + +block: #6250 + let + a = {3: 2}.toOrderedTable + b = {3: 2}.toOrderedTable + assert((a == b) == true) + assert((b == a) == true) + +block: # CountTable.smallest + let t = toCountTable([0, 0, 5, 5, 5]) + doAssert t.smallest == (0, 2) + +block: #10065 + let t = toCountTable("abracadabra") + doAssert t['z'] == 0 + + var t_mut = toCountTable("abracadabra") + doAssert t_mut['z'] == 0 + # the previous read may not have modified the table. + doAssert t_mut.hasKey('z') == false + t_mut['z'] = 1 + doAssert t_mut['z'] == 1 + doAssert t_mut.hasKey('z') == true + +block: #12813 #13079 + var t = toCountTable("abracadabra") + doAssert len(t) == 5 + + t['a'] = 0 # remove a key + doAssert len(t) == 4 + +block: + var tp: Table[string, string] = initTable[string, string]() + doAssert "test1" == tp.getOrDefault("test1", "test1") + tp["test2"] = "test2" + doAssert "test2" == tp.getOrDefault("test2", "test1") + var tr: TableRef[string, string] = newTable[string, string]() + doAssert "test1" == tr.getOrDefault("test1", "test1") + tr["test2"] = "test2" + doAssert "test2" == tr.getOrDefault("test2", "test1") + var op: OrderedTable[string, string] = initOrderedTable[string, string]() + doAssert "test1" == op.getOrDefault("test1", "test1") + op["test2"] = "test2" + doAssert "test2" == op.getOrDefault("test2", "test1") + var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]() + doAssert "test1" == orf.getOrDefault("test1", "test1") + orf["test2"] = "test2" + doAssert "test2" == orf.getOrDefault("test2", "test1") + +block tableWithoutInit: + var + a: Table[string, int] + b: Table[string, int] + c: Table[string, int] + d: Table[string, int] + e: Table[string, int] + + a["a"] = 7 + doAssert a.hasKey("a") + doAssert a.len == 1 + doAssert a["a"] == 7 + a["a"] = 9 + doAssert a.len == 1 + doAssert a["a"] == 9 + + doAssert b.hasKeyOrPut("b", 5) == false + doAssert b.hasKey("b") + doAssert b.hasKeyOrPut("b", 8) + doAssert b["b"] == 5 + + doAssert c.getOrDefault("a") == 0 + doAssert c.getOrDefault("a", 3) == 3 + c["a"] = 6 + doAssert c.getOrDefault("a", 3) == 6 + + doAssert d.mgetOrPut("a", 3) == 3 + doAssert d.mgetOrPut("a", 6) == 3 + + var x = 99 + doAssert e.pop("a", x) == false + doAssert x == 99 + e["a"] = 77 + doAssert e.pop("a", x) + doAssert x == 77 + +block orderedTableWithoutInit: + var + a: OrderedTable[string, int] + b: OrderedTable[string, int] + c: OrderedTable[string, int] + d: OrderedTable[string, int] + + a["a"] = 7 + doAssert a.hasKey("a") + doAssert a.len == 1 + doAssert a["a"] == 7 + a["a"] = 9 + doAssert a.len == 1 + doAssert a["a"] == 9 + + doAssert b.hasKeyOrPut("b", 5) == false + doAssert b.hasKey("b") + doAssert b.hasKeyOrPut("b", 8) + doAssert b["b"] == 5 + + doAssert c.getOrDefault("a") == 0 + doAssert c.getOrDefault("a", 3) == 3 + c["a"] = 6 + doAssert c.getOrDefault("a", 3) == 6 + + doAssert d.mgetOrPut("a", 3) == 3 + doAssert d.mgetOrPut("a", 6) == 3 + +block countTableWithoutInit: + var + a: CountTable[string] + b: CountTable[string] + c: CountTable[string] + d: CountTable[string] + e: CountTable[string] + + a["a"] = 7 + doAssert a.hasKey("a") + doAssert a.len == 1 + doAssert a["a"] == 7 + a["a"] = 9 + doAssert a.len == 1 + doAssert a["a"] == 9 + + doAssert b["b"] == 0 + b.inc("b") + doAssert b["b"] == 1 + + doAssert c.getOrDefault("a") == 0 + doAssert c.getOrDefault("a", 3) == 3 + c["a"] = 6 + doAssert c.getOrDefault("a", 3) == 6 + + e["f"] = 3 + merge(d, e) + doAssert d.hasKey("f") + d.inc("f") + merge(d, e) + doAssert d["f"] == 7 diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim new file mode 100644 index 000000000..a346106f9 --- /dev/null +++ b/tests/stdlib/tunicode.nim @@ -0,0 +1,215 @@ +import unicode + + +proc asRune(s: static[string]): Rune = + ## Compile-time conversion proc for converting string literals to a Rune + ## value. Returns the first Rune of the specified string. + ## + ## Shortcuts code like ``"å".runeAt(0)`` to ``"å".asRune`` and returns a + ## compile-time constant. + if s.len == 0: Rune(0) + else: s.runeAt(0) + +let + someString = "öÑ" + someRunes = toRunes(someString) + compared = (someString == $someRunes) +doAssert compared == true + +proc testReplacements(word: string): string = + case word + of "two": + return "2" + of "foo": + return "BAR" + of "βeta": + return "beta" + of "alpha": + return "αlpha" + else: + return "12345" + +doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta" +doAssert translate(" two not foo βeta ", testReplacements) == " 2 12345 BAR beta " + +doAssert title("foo bar") == "Foo Bar" +doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma" +doAssert title("") == "" + +doAssert capitalize("βeta") == "Βeta" +doAssert capitalize("foo") == "Foo" +doAssert capitalize("") == "" + +doAssert swapCase("FooBar") == "fOObAR" +doAssert swapCase(" ") == " " +doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA" +doAssert swapCase("a✓B") == "A✓b" +doAssert swapCase("Јамогујестистаклоитоминештети") == "јАМОГУЈЕСТИСТАКЛОИТОМИНЕШТЕТИ" +doAssert swapCase("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ὝΑΛΟΝΦΑΓΕῖΝΔΎΝΑΜΑΙΤΟῦΤΟΟὔΜΕΒΛΆΠΤΕΙ" +doAssert swapCase("Կրնամապակիուտեևինծիանհանգիստչըներ") == "կՐՆԱՄԱՊԱԿԻՈՒՏԵևԻՆԾԻԱՆՀԱՆԳԻՍՏՉԸՆԵՐ" +doAssert swapCase("") == "" + +doAssert isAlpha("r") +doAssert isAlpha("α") +doAssert isAlpha("ϙ") +doAssert isAlpha("ஶ") +doAssert(not isAlpha("$")) +doAssert(not isAlpha("")) + +doAssert isAlpha("Βeta") +doAssert isAlpha("Args") +doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽") +doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") +doAssert isAlpha("Јамогујестистаклоитоминештети") +doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ") +doAssert(not isAlpha("$Foo✓")) +doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞")) + +doAssert isSpace("\t") +doAssert isSpace("\l") +doAssert(not isSpace("Β")) +doAssert(not isSpace("Βeta")) + +doAssert isSpace("\t\l \v\r\f") +doAssert isSpace(" ") +doAssert(not isSpace("")) +doAssert(not isSpace("ΑΓc \td")) + +doAssert(not isLower(' '.Rune)) + +doAssert(not isUpper(' '.Rune)) + +doAssert toUpper("Γ") == "Γ" +doAssert toUpper("b") == "B" +doAssert toUpper("α") == "Α" +doAssert toUpper("✓") == "✓" +doAssert toUpper("ϙ") == "Ϙ" +doAssert toUpper("") == "" + +doAssert toUpper("ΑΒΓ") == "ΑΒΓ" +doAssert toUpper("AAccβ") == "AACCΒ" +doAssert toUpper("A✓$β") == "A✓$Β" + +doAssert toLower("a") == "a" +doAssert toLower("γ") == "γ" +doAssert toLower("Γ") == "γ" +doAssert toLower("4") == "4" +doAssert toLower("Ϙ") == "ϙ" +doAssert toLower("") == "" + +doAssert toLower("abcdγ") == "abcdγ" +doAssert toLower("abCDΓ") == "abcdγ" +doAssert toLower("33aaΓ") == "33aaγ" + +doAssert reversed("Reverse this!") == "!siht esreveR" +doAssert reversed("先秦兩漢") == "漢兩秦先" +doAssert reversed("as⃝df̅") == "f̅ds⃝a" +doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" +doAssert reversed("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ιετπάλβεμὔοοτῦοτιαμανύδνῖεγαϕνολαὕ" +doAssert reversed("Јамогујестистаклоитоминештети") == "итетшенимотиолкатситсејугомаЈ" +doAssert reversed("Կրնամապակիուտեևինծիանհանգիստչըներ") == "րենըչտսիգնահնաիծնիևետւոիկապամանրԿ" +doAssert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅") +const test = "as⃝" +doAssert lastRune(test, test.len-1)[1] == 3 +doAssert graphemeLen("è", 0) == 2 + +# test for rune positioning and runeSubStr() +let s = "Hänsel ««: 10,00€" + +var t = "" +for c in s.utf8: + t.add c + +doAssert(s == t) + +doAssert(runeReverseOffset(s, 1) == (20, 18)) +doAssert(runeReverseOffset(s, 19) == (-1, 18)) + +doAssert(runeStrAtPos(s, 0) == "H") +doAssert(runeSubStr(s, 0, 1) == "H") +doAssert(runeStrAtPos(s, 10) == ":") +doAssert(runeSubStr(s, 10, 1) == ":") +doAssert(runeStrAtPos(s, 9) == "«") +doAssert(runeSubStr(s, 9, 1) == "«") +doAssert(runeStrAtPos(s, 17) == "€") +doAssert(runeSubStr(s, 17, 1) == "€") +# echo runeStrAtPos(s, 18) # index error + +doAssert(runeSubStr(s, 0) == "Hänsel ««: 10,00€") +doAssert(runeSubStr(s, -18) == "Hänsel ««: 10,00€") +doAssert(runeSubStr(s, 10) == ": 10,00€") +doAssert(runeSubStr(s, 18) == "") +doAssert(runeSubStr(s, 0, 10) == "Hänsel ««") + +doAssert(runeSubStr(s, 12) == "10,00€") +doAssert(runeSubStr(s, -6) == "10,00€") + +doAssert(runeSubStr(s, 12, 5) == "10,00") +doAssert(runeSubStr(s, 12, -1) == "10,00") +doAssert(runeSubStr(s, -6, 5) == "10,00") +doAssert(runeSubStr(s, -6, -1) == "10,00") + +doAssert(runeSubStr(s, 0, 100) == "Hänsel ««: 10,00€") +doAssert(runeSubStr(s, -100, 100) == "Hänsel ««: 10,00€") +doAssert(runeSubStr(s, 0, -100) == "") +doAssert(runeSubStr(s, 100, -100) == "") + +block splitTests: + let s = " this is an example " + let s2 = ":this;is;an:example;;" + let s3 = ":this×is×an:example××" + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps = [':'.Rune, ';'.Rune]) == @["", "this", "is", "an", + "example", "", ""] + doAssert s3.split(seps = [':'.Rune, "×".asRune]) == @["", "this", "is", + "an", "example", "", ""] + doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] + doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example "] + doAssert s3.split("×".runeAt(0)) == @[":this", "is", "an:example", "", ""] + +block stripTests: + doAssert(strip("") == "") + doAssert(strip(" ") == "") + doAssert(strip("y") == "y") + doAssert(strip(" foofoofoo ") == "foofoofoo") + doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo") + + block: + let stripTestRunes = ['b'.Rune, 'a'.Rune, 'r'.Rune] + doAssert(strip("barfoofoofoobar", runes = stripTestRunes) == "foofoofoo") + doAssert(strip("sfoofoofoos", leading = false, runes = ['s'.Rune]) == "sfoofoofoo") + doAssert(strip("sfoofoofoos", trailing = false, runes = ['s'.Rune]) == "foofoofoos") + + block: + let stripTestRunes = ["«".asRune, "»".asRune] + doAssert(strip("«TEXT»", runes = stripTestRunes) == "TEXT") + doAssert(strip("copyright©", leading = false, runes = ["©".asRune]) == "copyright") + doAssert(strip("¿Question?", trailing = false, runes = ["¿".asRune]) == "Question?") + doAssert(strip("×text×", leading = false, runes = ["×".asRune]) == "×text") + doAssert(strip("×text×", trailing = false, runes = ["×".asRune]) == "text×") + +block repeatTests: + doAssert repeat('c'.Rune, 5) == "ccccc" + doAssert repeat("×".asRune, 5) == "×××××" + +block alignTests: + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#'.Rune) == "##1232" + doAssert align("1232", 6, "×".asRune) == "××1232" + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#'.Rune) == "1232##" + doAssert alignLeft("1232", 6, "×".asRune) == "1232××" + +block differentSizes: + # upper and lower variants have different number of bytes + doAssert toLower("AẞC") == "aßc" + doAssert toLower("ȺẞCD") == "ⱥßcd" + doAssert toUpper("ⱥbc") == "ȺBC" + doAssert toUpper("rsⱦuv") == "RSȾUV" + doAssert swapCase("ⱥbCd") == "ȺBcD" + doAssert swapCase("XyꟆaB") == "xYᶎAb" + doAssert swapCase("aᵹcᲈd") == "AꝽCꙊD" diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim index 576bfa2cb..7784fffb4 100644 --- a/tests/stdlib/tunidecode.nim +++ b/tests/stdlib/tunidecode.nim @@ -9,6 +9,5 @@ import std/unidecode # #14112 loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") -#assert unidecode("\x53\x17\x4E\xB0") == "Bei Jing" +# assert unidecode("\x53\x17\x4E\xB0") == "Bei Jing" echo unidecode("Äußerst") - diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index 9fb349e88..62fb17e4d 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -6,7 +6,7 @@ discard """ exitcode: 0 timeout: 60.0 """ -import uri +include uri block: @@ -15,3 +15,286 @@ block: doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true let newUrl = parseUri($url) doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true + + +block: + block: + const test1 = "abc\L+def xyz" + doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" + doAssert decodeUrl(encodeUrl(test1)) == test1 + doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz" + doAssert decodeUrl(encodeUrl(test1, false), false) == test1 + doAssert decodeUrl(encodeUrl(test1)) == test1 + + block: + let str = "http://localhost" + let test = parseUri(str) + doAssert test.path == "" + + block: + let str = "http://localhost/" + let test = parseUri(str) + doAssert test.path == "/" + + block: + let str = "http://localhost:8080/test" + let test = parseUri(str) + doAssert test.scheme == "http" + doAssert test.port == "8080" + doAssert test.path == "/test" + doAssert test.hostname == "localhost" + doAssert($test == str) + + block: + let str = "foo://username:password@example.com:8042/over/there" & + "/index.dtb?type=animal&name=narwhal#nose" + let test = parseUri(str) + doAssert test.scheme == "foo" + doAssert test.username == "username" + doAssert test.password == "password" + doAssert test.hostname == "example.com" + doAssert test.port == "8042" + doAssert test.path == "/over/there/index.dtb" + doAssert test.query == "type=animal&name=narwhal" + doAssert test.anchor == "nose" + doAssert($test == str) + + block: + # IPv6 address + let str = "foo://[::1]:1234/bar?baz=true&qux#quux" + let uri = parseUri(str) + doAssert uri.scheme == "foo" + doAssert uri.hostname == "::1" + doAssert uri.port == "1234" + doAssert uri.path == "/bar" + doAssert uri.query == "baz=true&qux" + doAssert uri.anchor == "quux" + + block: + let str = "urn:example:animal:ferret:nose" + let test = parseUri(str) + doAssert test.scheme == "urn" + doAssert test.path == "example:animal:ferret:nose" + doAssert($test == str) + + block: + let str = "mailto:username@example.com?subject=Topic" + let test = parseUri(str) + doAssert test.scheme == "mailto" + doAssert test.username == "username" + doAssert test.hostname == "example.com" + doAssert test.query == "subject=Topic" + doAssert($test == str) + + block: + let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" + let test = parseUri(str) + doAssert test.scheme == "magnet" + doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" + doAssert($test == str) + + block: + let str = "/test/foo/bar?q=2#asdf" + let test = parseUri(str) + doAssert test.scheme == "" + doAssert test.path == "/test/foo/bar" + doAssert test.query == "q=2" + doAssert test.anchor == "asdf" + doAssert($test == str) + + block: + let str = "test/no/slash" + let test = parseUri(str) + doAssert test.path == "test/no/slash" + doAssert($test == str) + + block: + let str = "//git@github.com:dom96/packages" + let test = parseUri(str) + doAssert test.scheme == "" + doAssert test.username == "git" + doAssert test.hostname == "github.com" + doAssert test.port == "dom96" + doAssert test.path == "/packages" + + block: + let str = "file:///foo/bar/baz.txt" + let test = parseUri(str) + doAssert test.scheme == "file" + doAssert test.username == "" + doAssert test.hostname == "" + doAssert test.port == "" + doAssert test.path == "/foo/bar/baz.txt" + + # Remove dot segments tests + block: + doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" + + # Combine tests + block: + let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz")) + doAssert concat.path == "/foo/bar/baz" + doAssert concat.hostname == "google.com" + doAssert concat.scheme == "http" + + block: + let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz")) + doAssert concat.path == "/baz" + doAssert concat.hostname == "google.com" + doAssert concat.scheme == "http" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) + doAssert concat.path == "/foo/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar")) + doAssert concat.path == "/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) + doAssert concat.path == "/foo/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar")) + doAssert concat.path == "/foo/test/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/")) + doAssert concat.path == "/foo/test/bar/" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"), + parseUri("baz")) + doAssert concat.path == "/foo/test/bar/baz" + + # `/` tests + block: + let test = parseUri("http://example.com/foo") / "bar/asd" + doAssert test.path == "/foo/bar/asd" + + block: + let test = parseUri("http://example.com/foo/") / "/bar/asd" + doAssert test.path == "/foo/bar/asd" + + # removeDotSegments tests + block: + # empty test + doAssert removeDotSegments("") == "" + + # bug #3207 + block: + doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq" + + # bug #4959 + block: + let foo = parseUri("http://example.com") / "/baz" + doAssert foo.path == "/baz" + + # bug found on stream 13/10/17 + block: + let foo = parseUri("http://localhost:9515") / "status" + doAssert $foo == "http://localhost:9515/status" + + # bug #6649 #6652 + block: + var foo = parseUri("http://example.com") + foo.hostname = "example.com" + foo.path = "baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com/" + foo.path = "baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com" + foo.path = "/baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com/" + foo.path = "/baz" + doAssert $foo == "http://example.com/baz" + + foo.hostname = "example.com/" + foo.port = "8000" + foo.path = "baz" + doAssert $foo == "http://example.com:8000/baz" + + foo = parseUri("file:/dir/file") + foo.path = "relative" + doAssert $foo == "file:relative" + + # isAbsolute tests + block: + doAssert "www.google.com".parseUri().isAbsolute() == false + doAssert "http://www.google.com".parseUri().isAbsolute() == true + doAssert "file:/dir/file".parseUri().isAbsolute() == true + doAssert "file://localhost/dir/file".parseUri().isAbsolute() == true + doAssert "urn:ISSN:1535-3613".parseUri().isAbsolute() == true + + # path-relative URL *relative + doAssert "about".parseUri().isAbsolute == false + doAssert "about/staff.html".parseUri().isAbsolute == false + doAssert "about/staff.html?".parseUri().isAbsolute == false + doAssert "about/staff.html?parameters".parseUri().isAbsolute == false + + # absolute-path-relative URL *relative + doAssert "/".parseUri().isAbsolute == false + doAssert "/about".parseUri().isAbsolute == false + doAssert "/about/staff.html".parseUri().isAbsolute == false + doAssert "/about/staff.html?".parseUri().isAbsolute == false + doAssert "/about/staff.html?parameters".parseUri().isAbsolute == false + + # scheme-relative URL *relative + doAssert "//username:password@example.com:8888".parseUri().isAbsolute == false + doAssert "//username@example.com".parseUri().isAbsolute == false + doAssert "//example.com".parseUri().isAbsolute == false + doAssert "//example.com/".parseUri().isAbsolute == false + doAssert "//example.com/about".parseUri().isAbsolute == false + doAssert "//example.com/about/staff.html".parseUri().isAbsolute == false + doAssert "//example.com/about/staff.html?".parseUri().isAbsolute == false + doAssert "//example.com/about/staff.html?parameters".parseUri().isAbsolute == false + + # absolute URL *absolute + doAssert "https://username:password@example.com:8888".parseUri().isAbsolute == true + doAssert "https://username@example.com".parseUri().isAbsolute == true + doAssert "https://example.com".parseUri().isAbsolute == true + doAssert "https://example.com/".parseUri().isAbsolute == true + doAssert "https://example.com/about".parseUri().isAbsolute == true + doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true + doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true + doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true + + # encodeQuery tests + block: + doAssert encodeQuery({:}) == "" + doAssert encodeQuery({"foo": "bar"}) == "foo=bar" + doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz" + doAssert encodeQuery({"foo": "bar & baz"}, usePlus = false) == "foo=bar%20%26%20baz" + doAssert encodeQuery({"foo": ""}) == "foo" + doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo=" + doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3" + doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3" + + block: + var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"} + var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux") + doAssert foo == foo1 + + block: + var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""} + var foo1 = parseUri("http://example.com/foo?do=do&bar") + doAssert foo == foo1 + + block dataUriBase64: + doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64," + doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA==" + doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+" + doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" + doAssert getDataUri("leasure.", "text/plain") == "data:text/plain;charset=utf-8;base64,bGVhc3VyZS4=" + doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r" + doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") == + "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==") + doAssert(getDataUri("""The present is theirs + The future, for which I really worked, is mine.""", "text/plain") == + "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu") From d2c6ac4750ffc60631fee2170c7ee4a884210225 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 02:19:03 +0800 Subject: [PATCH 1551/4254] add simple runnableExamples for atomics (#16116) --- lib/pure/concurrency/atomics.nim | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index dc575c6c0..895944177 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -11,6 +11,46 @@ ## ## Unstable API. +runnableExamples: + # Atomic + var loc: Atomic[int] + loc.store(4) + assert loc.load == 4 + loc.store(2) + assert loc.load(moRelaxed) == 2 + loc.store(9) + assert loc.load(moAcquire) == 9 + loc.store(0, moRelease) + assert loc.load == 0 + + assert loc.exchange(7) == 0 + assert loc.load == 7 + + var expected = 7 + assert loc.compareExchange(expected, 5, moRelaxed, moRelaxed) + assert expected == 7 + assert loc.load == 5 + + assert not loc.compareExchange(expected, 12, moRelaxed, moRelaxed) + assert expected == 5 + assert loc.load == 5 + + assert loc.fetchAdd(1) == 5 + assert loc.fetchAdd(2) == 6 + assert loc.fetchSub(3) == 8 + + loc.atomicInc(1) + assert loc.load == 6 + + # AtomicFlag + var flag: AtomicFlag + + assert not flag.testAndSet + assert flag.testAndSet + flag.clear(moRelaxed) + assert not flag.testAndSet + + import macros when defined(cpp) or defined(nimdoc): From 3fed85437b981a01cc368166841d9d89d99434f0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 02:30:17 +0800 Subject: [PATCH 1552/4254] ref #16054 remove typed array (#16077) --- compiler/jsgen.nim | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 3a1ef7fbb..675a24c92 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2598,14 +2598,6 @@ proc genHeader(): Rope = var framePtr = null; var excHandler = 0; var lastJSError = null; - if (typeof Int8Array === 'undefined') Int8Array = Array; - if (typeof Int16Array === 'undefined') Int16Array = Array; - if (typeof Int32Array === 'undefined') Int32Array = Array; - if (typeof Uint8Array === 'undefined') Uint8Array = Array; - if (typeof Uint16Array === 'undefined') Uint16Array = Array; - if (typeof Uint32Array === 'undefined') Uint32Array = Array; - if (typeof Float32Array === 'undefined') Float32Array = Array; - if (typeof Float64Array === 'undefined') Float64Array = Array; """.unindent.format(VersionAsString)) proc addHcrInitGuards(p: PProc, n: PNode, From 19e224866ba6cfe2c6cdc49e435a275b532f0acb Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 02:45:06 +0800 Subject: [PATCH 1553/4254] add simple writeStackTrace for JS backend (#16016) * add simple writeStackTrace for JS backend * add testcase for writeStackTrace * changelog --- changelog.md | 2 ++ lib/system.nim | 2 +- lib/system/jssys.nim | 5 +++++ tests/js/twritestacktrace.nim | 12 ++++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/js/twritestacktrace.nim diff --git a/changelog.md b/changelog.md index 4c18ddf1e..bfbe59e1a 100644 --- a/changelog.md +++ b/changelog.md @@ -47,6 +47,8 @@ - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. +- `writeStackTrace` is available in JS backend now. + ## Language changes - `nimscript` now handles `except Exception as e` diff --git a/lib/system.nim b/lib/system.nim index 716eb296a..be41c1893 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1765,7 +1765,7 @@ when notJSnotNims and defined(nimSeqsV2): {.pop.} -when notJSnotNims: +when not defined(nimscript): proc writeStackTrace*() {.tags: [], gcsafe, raises: [].} ## Writes the current stack trace to ``stderr``. This is only works ## for debug builds. Since it's usually used for debugging, this diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index c4c671ea3..8865558fe 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -105,6 +105,11 @@ proc rawWriteStackTrace(): string = else: result = "No stack traceback available\n" +proc writeStackTrace() = + var trace = rawWriteStackTrace() + trace.setLen(trace.len - 1) + echo trace + proc getStackTrace*(): string = rawWriteStackTrace() proc getStackTrace*(e: ref Exception): string = e.trace diff --git a/tests/js/twritestacktrace.nim b/tests/js/twritestacktrace.nim new file mode 100644 index 000000000..2fe2b1987 --- /dev/null +++ b/tests/js/twritestacktrace.nim @@ -0,0 +1,12 @@ +discard """ + cmd: "nim js --panics:on $file" + output: '''Traceback (most recent call last) +twritestacktrace.nim(12) at module twritestacktrace +twritestacktrace.nim(10) at twritestacktrace.hello +''' +""" + +proc hello() = + writeStackTrace() + +hello() From b7809cc9921421ea0e8326a24d66861748e3136b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 14:42:25 +0800 Subject: [PATCH 1554/4254] improve the documentation of ropes (#16111) --- lib/pure/ropes.nim | 117 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 19 deletions(-) diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index a39533e58..83850e03e 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -33,7 +33,7 @@ type RopeObj {.acyclic.} = object left, right: Rope length: int - data: string # != nil if a leaf + data: string # not empty if a leaf # Note that the left and right pointers are not needed for leafs. # Leaves have relatively high memory overhead (~30 bytes on a 32 @@ -44,7 +44,7 @@ type # pointers. proc len*(a: Rope): int {.rtl, extern: "nro$1".} = - ## the rope's length + ## The rope's length. if a == nil: result = 0 else: result = a.length @@ -127,6 +127,9 @@ proc insertInCache(s: string, tree: Rope): Rope = proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} = ## Converts a string to a rope. + runnableExamples: + var r = rope("I'm a rope") + doAssert $r == "I'm a rope" if s.len == 0: result = nil else: @@ -142,10 +145,16 @@ proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} = proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = ## Converts an int to a rope. + runnableExamples: + var r = rope(429) + doAssert $r == "429" result = rope($i) proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} = ## Converts a float to a rope. + runnableExamples: + var r = rope(4.29) + doAssert $r == "4.29" result = rope($f) proc enableCache*() {.rtl, extern: "nro$1".} = @@ -154,12 +163,19 @@ proc enableCache*() {.rtl, extern: "nro$1".} = cacheEnabled = true proc disableCache*() {.rtl, extern: "nro$1".} = - ## the cache is discarded and disabled. The GC will reuse its used memory. + ## The cache is discarded and disabled. The GC will reuse its used memory. cache = nil cacheEnabled = false proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = - ## the concatenation operator for ropes. + ## The concatenation operator for ropes. + runnableExamples: + var + r1 = rope("Hello, ") + r2 = rope("Nim!") + + let r = r1 & r2 + doAssert $r == "Hello, Nim!" if a == nil: result = b elif b == nil: @@ -171,28 +187,73 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = result.right = b proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = - ## the concatenation operator for ropes. + ## The concatenation operator for ropes. + runnableExamples: + var + r1 = rope("Hello, ") + r2 = "Nim!" + + let r = r1 & r2 + doAssert $r == "Hello, Nim!" result = a & rope(b) proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = - ## the concatenation operator for ropes. + ## The concatenation operator for ropes. + runnableExamples: + var + r1 = "Hello, " + r2 = rope("Nim!") + + let r = r1 & r2 + doAssert $r == "Hello, Nim!" result = rope(a) & b proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = - ## the concatenation operator for an openarray of ropes. - for i in countup(0, high(a)): result = result & a[i] + ## The concatenation operator for an openarray of ropes. + runnableExamples: + let s = @[rope("Hello, "), rope("Nim"), rope("!")] + let r = &s + doAssert $r == "Hello, Nim!" + for item in a: result = result & item proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} = - ## adds `b` to the rope `a`. + ## Adds `b` to the rope `a`. + runnableExamples: + var + r1 = rope("Hello, ") + r2 = rope("Nim!") + + r1.add(r2) + doAssert $r1 == "Hello, Nim!" a = a & b proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} = - ## adds `b` to the rope `a`. + ## Adds `b` to the rope `a`. + runnableExamples: + var + r1 = rope("Hello, ") + r2 = "Nim!" + + r1.add(r2) + doAssert $r1 == "Hello, Nim!" a = a & b proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} = - ## returns the character at position `i` in the rope `r`. This is quite + ## Returns the character at position `i` in the rope `r`. This is quite ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned. + runnableExamples: + let r1 = rope("Hello, Nim!") + + doAssert r1[0] == 'H' + doAssert r1[7] == 'N' + doAssert r1[22] == '\0' + + let r2 = rope("Hello") & rope(", Nim!") + + doAssert r2[0] == 'H' + doAssert r2[7] == 'N' + doAssert r2[22] == '\0' + var x = r var j = i if x == nil: return @@ -208,7 +269,15 @@ proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} = x = x.right iterator leaves*(r: Rope): string = - ## iterates over any leaf string in the rope `r`. + ## Iterates over any leaf string in the rope `r`. + runnableExamples: + let r = rope("Hello") & rope(", Nim!") + let s = ["Hello", ", Nim!"] + var index = 0 + for leave in r.leaves: + doAssert leave == s[index] + inc index + if r != nil: var stack = @[r] while stack.len > 0: @@ -221,20 +290,20 @@ iterator leaves*(r: Rope): string = yield it.data iterator items*(r: Rope): char = - ## iterates over any character in the rope `r`. + ## Iterates over any character in the rope `r`. for s in leaves(r): for c in items(s): yield c proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} = - ## writes a rope to a file. + ## Writes a rope to a file. for s in leaves(r): write(f, s) proc write*(s: Stream, r: Rope) {.rtl, extern: "nroWriteStream".} = - ## writes a rope to a stream. + ## Writes a rope to a stream. for rs in leaves(r): write(s, rs) proc `$`*(r: Rope): string {.rtl, extern: "nroToString".} = - ## converts a rope back to a string. + ## Converts a rope back to a string. result = newStringOfCap(r.len) for s in leaves(r): add(result, s) @@ -242,6 +311,12 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {. rtl, extern: "nroFormat".} = ## `%` substitution operator for ropes. Does not support the ``$identifier`` ## nor ``${identifier}`` notations. + runnableExamples: + let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")] + doAssert $r1 == "Nim is a great language" + + let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")] + doAssert $r2 == "Nim is a great language" var i = 0 var length = len(frmt) result = nil @@ -284,7 +359,11 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {. proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {. rtl, extern: "nro$1".} = - ## shortcut for ``add(c, frmt % args)``. + ## Shortcut for ``add(c, frmt % args)``. + runnableExamples: + var r = rope("Dash: ") + r.addf "$1 $2 $3", [rope("Nim"), rope("is"), rope("a great language")] + doAssert $r == "Dash: Nim is a great language" add(c, frmt % args) when not defined(js) and not defined(nimscript): @@ -292,7 +371,7 @@ when not defined(js) and not defined(nimscript): bufSize = 1024 # 1 KB is reasonable proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} = - ## returns true if the contents of the file `f` equal `r`. + ## Returns true if the contents of the file `f` equal `r`. var buf: array[bufSize, char] bpos = buf.len @@ -321,7 +400,7 @@ when not defined(js) and not defined(nimscript): result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} = - ## returns true if the contents of the file `f` equal `r`. If `f` does not + ## Returns true if the contents of the file `f` equal `r`. If `f` does not ## exist, false is returned. var f: File result = open(f, filename) From 57bd64582ceee697dc4f079baf6a4e6137ff45b4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 14:48:27 +0800 Subject: [PATCH 1555/4254] move tests under the compiler directory to testament (#16096) --- compiler/btrees.nim | 65 ----------- compiler/int128.nim | 187 ------------------------------ compiler/nimblecmd.nim | 27 ----- compiler/pathutils.nim | 16 --- compiler/prefixmatches.nim | 33 ------ tests/compiler/tbrees.nim | 84 ++++++++++++++ tests/compiler/tint128.nim | 184 +++++++++++++++++++++++++++++ tests/compiler/tnimblecmd.nim | 26 +++++ tests/compiler/tpathutils.nim | 18 +++ tests/compiler/tprefixmatches.nim | 32 +++++ 10 files changed, 344 insertions(+), 328 deletions(-) create mode 100644 tests/compiler/tbrees.nim create mode 100644 tests/compiler/tint128.nim create mode 100644 tests/compiler/tnimblecmd.nim create mode 100644 tests/compiler/tpathutils.nim create mode 100644 tests/compiler/tprefixmatches.nim diff --git a/compiler/btrees.nim b/compiler/btrees.nim index 473cbd1b0..5f78c07fe 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -168,68 +168,3 @@ iterator pairs*[Key, Val](b: BTree[Key, Val]): (Key, Val) = yield (k, v) proc len*[Key, Val](b: BTree[Key, Val]): int {.inline.} = b.entries - -when isMainModule: - - import random, tables - - proc main = - var st = initBTree[string, string]() - st.add("www.cs.princeton.edu", "abc") - st.add("www.princeton.edu", "128.112.128.15") - st.add("www.yale.edu", "130.132.143.21") - st.add("www.simpsons.com", "209.052.165.60") - st.add("www.apple.com", "17.112.152.32") - st.add("www.amazon.com", "207.171.182.16") - st.add("www.ebay.com", "66.135.192.87") - st.add("www.cnn.com", "64.236.16.20") - st.add("www.google.com", "216.239.41.99") - st.add("www.nytimes.com", "199.239.136.200") - st.add("www.microsoft.com", "207.126.99.140") - st.add("www.dell.com", "143.166.224.230") - st.add("www.slashdot.org", "66.35.250.151") - st.add("www.espn.com", "199.181.135.201") - st.add("www.weather.com", "63.111.66.11") - st.add("www.yahoo.com", "216.109.118.65") - - assert st.getOrDefault("www.cs.princeton.edu") == "abc" - assert st.getOrDefault("www.harvardsucks.com") == "" - - assert st.getOrDefault("www.simpsons.com") == "209.052.165.60" - assert st.getOrDefault("www.apple.com") == "17.112.152.32" - assert st.getOrDefault("www.ebay.com") == "66.135.192.87" - assert st.getOrDefault("www.dell.com") == "143.166.224.230" - assert(st.entries == 16) - - for k, v in st: - echo k, ": ", v - - when false: - var b2 = initBTree[string, string]() - const iters = 10_000 - for i in 1..iters: - b2.add($i, $(iters - i)) - for i in 1..iters: - let x = b2.getOrDefault($i) - if x != $(iters - i): - echo "got ", x, ", but expected ", iters - i - echo b2.entries - - when true: - var b2 = initBTree[int, string]() - var t2 = initTable[int, string]() - const iters = 100_000 - for i in 1..iters: - let x = rand(high(int)) - if not t2.hasKey(x): - doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x - t2[x] = $x - b2.add(x, $x) - - doAssert b2.entries == t2.len - echo "unique entries ", b2.entries - for k, v in t2: - doAssert $k == v - doAssert b2.getOrDefault(k) == $k - - main() diff --git a/compiler/int128.nim b/compiler/int128.nim index f9b6f1d80..e266b9cd0 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -592,190 +592,3 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} = return maskUInt64(arg) else: assert(false, "masking only implemented for 1, 2, 4 and 8 bytes") - - - - -when isMainModule: - let (a,b) = divMod(Ten,Ten) - - doAssert $One == "1" - doAssert $Ten == "10" - doAssert $Zero == "0" - let c = parseDecimalInt128("12345678989876543210123456789") - doAssert $c == "12345678989876543210123456789" - - var d : array[39, Int128] - d[0] = parseDecimalInt128("1") - d[1] = parseDecimalInt128("10") - d[2] = parseDecimalInt128("100") - d[3] = parseDecimalInt128("1000") - d[4] = parseDecimalInt128("10000") - d[5] = parseDecimalInt128("100000") - d[6] = parseDecimalInt128("1000000") - d[7] = parseDecimalInt128("10000000") - d[8] = parseDecimalInt128("100000000") - d[9] = parseDecimalInt128("1000000000") - d[10] = parseDecimalInt128("10000000000") - d[11] = parseDecimalInt128("100000000000") - d[12] = parseDecimalInt128("1000000000000") - d[13] = parseDecimalInt128("10000000000000") - d[14] = parseDecimalInt128("100000000000000") - d[15] = parseDecimalInt128("1000000000000000") - d[16] = parseDecimalInt128("10000000000000000") - d[17] = parseDecimalInt128("100000000000000000") - d[18] = parseDecimalInt128("1000000000000000000") - d[19] = parseDecimalInt128("10000000000000000000") - d[20] = parseDecimalInt128("100000000000000000000") - d[21] = parseDecimalInt128("1000000000000000000000") - d[22] = parseDecimalInt128("10000000000000000000000") - d[23] = parseDecimalInt128("100000000000000000000000") - d[24] = parseDecimalInt128("1000000000000000000000000") - d[25] = parseDecimalInt128("10000000000000000000000000") - d[26] = parseDecimalInt128("100000000000000000000000000") - d[27] = parseDecimalInt128("1000000000000000000000000000") - d[28] = parseDecimalInt128("10000000000000000000000000000") - d[29] = parseDecimalInt128("100000000000000000000000000000") - d[30] = parseDecimalInt128("1000000000000000000000000000000") - d[31] = parseDecimalInt128("10000000000000000000000000000000") - d[32] = parseDecimalInt128("100000000000000000000000000000000") - d[33] = parseDecimalInt128("1000000000000000000000000000000000") - d[34] = parseDecimalInt128("10000000000000000000000000000000000") - d[35] = parseDecimalInt128("100000000000000000000000000000000000") - d[36] = parseDecimalInt128("1000000000000000000000000000000000000") - d[37] = parseDecimalInt128("10000000000000000000000000000000000000") - d[38] = parseDecimalInt128("100000000000000000000000000000000000000") - - for i in 0..= 0: - doAssert d[i] div d[j] == d[i-j] - - var sum: Int128 - - for it in d: - sum += it - - doAssert $sum == "111111111111111111111111111111111111111" - - for it in d.mitems: - it = -it - - for i in 0..= 0: - doAssert d[i] div d[j] == -d[i-j] - - doAssert $high(Int128) == "170141183460469231731687303715884105727" - doAssert $low(Int128) == "-170141183460469231731687303715884105728" - - var ma = 100'i64 - var mb = 13 - - doAssert toInt128(ma) * toInt128(0) == toInt128(0) - doAssert toInt128(-ma) * toInt128(0) == toInt128(0) - - # sign correctness - doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb)) - doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb)) - doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb)) - doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb)) - - doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div mb), toInt128( mb mod mb)) - doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div mb), toInt128(-mb mod mb)) - doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb)) - doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb)) - - doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div ma), toInt128( mb mod ma)) - doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma)) - doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma)) - doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma)) - - let e = parseDecimalInt128("70997106675279150998592376708984375") - - let strArray = [ - # toHex(e shr 0), toHex(e shr 1), toHex(e shr 2), toHex(e shr 3) - "000dac6d782d266a37300c32591eee37", "0006d636bc1693351b9806192c8f771b", "00036b1b5e0b499a8dcc030c9647bb8d", "0001b58daf05a4cd46e601864b23ddc6", - "0000dac6d782d266a37300c32591eee3", "00006d636bc1693351b9806192c8f771", "000036b1b5e0b499a8dcc030c9647bb8", "00001b58daf05a4cd46e601864b23ddc", - "00000dac6d782d266a37300c32591eee", "000006d636bc1693351b9806192c8f77", "0000036b1b5e0b499a8dcc030c9647bb", "000001b58daf05a4cd46e601864b23dd", - "000000dac6d782d266a37300c32591ee", "0000006d636bc1693351b9806192c8f7", "00000036b1b5e0b499a8dcc030c9647b", "0000001b58daf05a4cd46e601864b23d", - "0000000dac6d782d266a37300c32591e", "00000006d636bc1693351b9806192c8f", "000000036b1b5e0b499a8dcc030c9647", "00000001b58daf05a4cd46e601864b23", - "00000000dac6d782d266a37300c32591", "000000006d636bc1693351b9806192c8", "0000000036b1b5e0b499a8dcc030c964", "000000001b58daf05a4cd46e601864b2", - "000000000dac6d782d266a37300c3259", "0000000006d636bc1693351b9806192c", "00000000036b1b5e0b499a8dcc030c96", "0000000001b58daf05a4cd46e601864b", - "0000000000dac6d782d266a37300c325", "00000000006d636bc1693351b9806192", "000000000036b1b5e0b499a8dcc030c9", "00000000001b58daf05a4cd46e601864", - "00000000000dac6d782d266a37300c32", "000000000006d636bc1693351b980619", "0000000000036b1b5e0b499a8dcc030c", "000000000001b58daf05a4cd46e60186", - "000000000000dac6d782d266a37300c3", "0000000000006d636bc1693351b98061", "00000000000036b1b5e0b499a8dcc030", "0000000000001b58daf05a4cd46e6018", - "0000000000000dac6d782d266a37300c", "00000000000006d636bc1693351b9806", "000000000000036b1b5e0b499a8dcc03", "00000000000001b58daf05a4cd46e601", - "00000000000000dac6d782d266a37300", "000000000000006d636bc1693351b980", "0000000000000036b1b5e0b499a8dcc0", "000000000000001b58daf05a4cd46e60", - "000000000000000dac6d782d266a3730", "0000000000000006d636bc1693351b98", "00000000000000036b1b5e0b499a8dcc", "0000000000000001b58daf05a4cd46e6", - "0000000000000000dac6d782d266a373", "00000000000000006d636bc1693351b9", "000000000000000036b1b5e0b499a8dc", "00000000000000001b58daf05a4cd46e", - "00000000000000000dac6d782d266a37", "000000000000000006d636bc1693351b", "0000000000000000036b1b5e0b499a8d", "000000000000000001b58daf05a4cd46", - "000000000000000000dac6d782d266a3", "0000000000000000006d636bc1693351", "00000000000000000036b1b5e0b499a8", "0000000000000000001b58daf05a4cd4", - "0000000000000000000dac6d782d266a", "00000000000000000006d636bc169335", "000000000000000000036b1b5e0b499a", "00000000000000000001b58daf05a4cd", - "00000000000000000000dac6d782d266", "000000000000000000006d636bc16933", "0000000000000000000036b1b5e0b499", "000000000000000000001b58daf05a4c", - "000000000000000000000dac6d782d26", "0000000000000000000006d636bc1693", "00000000000000000000036b1b5e0b49", "0000000000000000000001b58daf05a4", - "0000000000000000000000dac6d782d2", "00000000000000000000006d636bc169", "000000000000000000000036b1b5e0b4", "00000000000000000000001b58daf05a", - "00000000000000000000000dac6d782d", "000000000000000000000006d636bc16", "0000000000000000000000036b1b5e0b", "000000000000000000000001b58daf05", - "000000000000000000000000dac6d782", "0000000000000000000000006d636bc1", "00000000000000000000000036b1b5e0", "0000000000000000000000001b58daf0", - "0000000000000000000000000dac6d78", "00000000000000000000000006d636bc", "000000000000000000000000036b1b5e", "00000000000000000000000001b58daf", - "00000000000000000000000000dac6d7", "000000000000000000000000006d636b", "0000000000000000000000000036b1b5", "000000000000000000000000001b58da", - "000000000000000000000000000dac6d", "0000000000000000000000000006d636", "00000000000000000000000000036b1b", "0000000000000000000000000001b58d", - "0000000000000000000000000000dac6", "00000000000000000000000000006d63", "000000000000000000000000000036b1", "00000000000000000000000000001b58", - "00000000000000000000000000000dac", "000000000000000000000000000006d6", "0000000000000000000000000000036b", "000000000000000000000000000001b5", - "000000000000000000000000000000da", "0000000000000000000000000000006d", "00000000000000000000000000000036", "0000000000000000000000000000001b", - "0000000000000000000000000000000d", "00000000000000000000000000000006", "00000000000000000000000000000003", "00000000000000000000000000000001", - "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", - "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", - "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", - ] - - for i in 0 ..< 128: - let str1 = toHex(e shr i) - let str2 = strArray[i] - doAssert str1 == str2 - - let strArray2 = [ - "000dac6d782d266a37300c32591eee37", "001b58daf05a4cd46e601864b23ddc6e", "0036b1b5e0b499a8dcc030c9647bb8dc", "006d636bc1693351b9806192c8f771b8", - "00dac6d782d266a37300c32591eee370", "01b58daf05a4cd46e601864b23ddc6e0", "036b1b5e0b499a8dcc030c9647bb8dc0", "06d636bc1693351b9806192c8f771b80", - "0dac6d782d266a37300c32591eee3700", "1b58daf05a4cd46e601864b23ddc6e00", "36b1b5e0b499a8dcc030c9647bb8dc00", "6d636bc1693351b9806192c8f771b800", - "dac6d782d266a37300c32591eee37000", "b58daf05a4cd46e601864b23ddc6e000", "6b1b5e0b499a8dcc030c9647bb8dc000", "d636bc1693351b9806192c8f771b8000", - "ac6d782d266a37300c32591eee370000", "58daf05a4cd46e601864b23ddc6e0000", "b1b5e0b499a8dcc030c9647bb8dc0000", "636bc1693351b9806192c8f771b80000", - "c6d782d266a37300c32591eee3700000", "8daf05a4cd46e601864b23ddc6e00000", "1b5e0b499a8dcc030c9647bb8dc00000", "36bc1693351b9806192c8f771b800000", - "6d782d266a37300c32591eee37000000", "daf05a4cd46e601864b23ddc6e000000", "b5e0b499a8dcc030c9647bb8dc000000", "6bc1693351b9806192c8f771b8000000", - "d782d266a37300c32591eee370000000", "af05a4cd46e601864b23ddc6e0000000", "5e0b499a8dcc030c9647bb8dc0000000", "bc1693351b9806192c8f771b80000000", - "782d266a37300c32591eee3700000000", "f05a4cd46e601864b23ddc6e00000000", "e0b499a8dcc030c9647bb8dc00000000", "c1693351b9806192c8f771b800000000", - "82d266a37300c32591eee37000000000", "05a4cd46e601864b23ddc6e000000000", "0b499a8dcc030c9647bb8dc000000000", "1693351b9806192c8f771b8000000000", - "2d266a37300c32591eee370000000000", "5a4cd46e601864b23ddc6e0000000000", "b499a8dcc030c9647bb8dc0000000000", "693351b9806192c8f771b80000000000", - "d266a37300c32591eee3700000000000", "a4cd46e601864b23ddc6e00000000000", "499a8dcc030c9647bb8dc00000000000", "93351b9806192c8f771b800000000000", - "266a37300c32591eee37000000000000", "4cd46e601864b23ddc6e000000000000", "99a8dcc030c9647bb8dc000000000000", "3351b9806192c8f771b8000000000000", - "66a37300c32591eee370000000000000", "cd46e601864b23ddc6e0000000000000", "9a8dcc030c9647bb8dc0000000000000", "351b9806192c8f771b80000000000000", - "6a37300c32591eee3700000000000000", "d46e601864b23ddc6e00000000000000", "a8dcc030c9647bb8dc00000000000000", "51b9806192c8f771b800000000000000", - "a37300c32591eee37000000000000000", "46e601864b23ddc6e000000000000000", "8dcc030c9647bb8dc000000000000000", "1b9806192c8f771b8000000000000000", - "37300c32591eee370000000000000000", "6e601864b23ddc6e0000000000000000", "dcc030c9647bb8dc0000000000000000", "b9806192c8f771b80000000000000000", - "7300c32591eee3700000000000000000", "e601864b23ddc6e00000000000000000", "cc030c9647bb8dc00000000000000000", "9806192c8f771b800000000000000000", - "300c32591eee37000000000000000000", "601864b23ddc6e000000000000000000", "c030c9647bb8dc000000000000000000", "806192c8f771b8000000000000000000", - "00c32591eee370000000000000000000", "01864b23ddc6e0000000000000000000", "030c9647bb8dc0000000000000000000", "06192c8f771b80000000000000000000", - "0c32591eee3700000000000000000000", "1864b23ddc6e00000000000000000000", "30c9647bb8dc00000000000000000000", "6192c8f771b800000000000000000000", - "c32591eee37000000000000000000000", "864b23ddc6e000000000000000000000", "0c9647bb8dc000000000000000000000", "192c8f771b8000000000000000000000", - "32591eee370000000000000000000000", "64b23ddc6e0000000000000000000000", "c9647bb8dc0000000000000000000000", "92c8f771b80000000000000000000000", - "2591eee3700000000000000000000000", "4b23ddc6e00000000000000000000000", "9647bb8dc00000000000000000000000", "2c8f771b800000000000000000000000", - "591eee37000000000000000000000000", "b23ddc6e000000000000000000000000", "647bb8dc000000000000000000000000", "c8f771b8000000000000000000000000", - "91eee370000000000000000000000000", "23ddc6e0000000000000000000000000", "47bb8dc0000000000000000000000000", "8f771b80000000000000000000000000", - "1eee3700000000000000000000000000", "3ddc6e00000000000000000000000000", "7bb8dc00000000000000000000000000", "f771b800000000000000000000000000", - "eee37000000000000000000000000000", "ddc6e000000000000000000000000000", "bb8dc000000000000000000000000000", "771b8000000000000000000000000000", - "ee370000000000000000000000000000", "dc6e0000000000000000000000000000", "b8dc0000000000000000000000000000", "71b80000000000000000000000000000", - "e3700000000000000000000000000000", "c6e00000000000000000000000000000", "8dc00000000000000000000000000000", "1b800000000000000000000000000000", - "37000000000000000000000000000000", "6e000000000000000000000000000000", "dc000000000000000000000000000000", "b8000000000000000000000000000000", - "70000000000000000000000000000000", "e0000000000000000000000000000000", "c0000000000000000000000000000000", "80000000000000000000000000000000", - ] - - for i in 0 ..< 128: - let str1 = toHex(e shl i) - let str2 = strArray2[i] - doAssert str1 == str2 diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index fbc3fcee1..28398289c 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -134,30 +134,3 @@ proc nimblePath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) = if i != -1: conf.nimblePaths.delete(i) conf.nimblePaths.insert(path, 0) - -when isMainModule: - proc v(s: string): Version = s.newVersion - # #head is special in the sense that it's assumed to always be newest. - doAssert v"1.0" < v"#head" - doAssert v"1.0" < v"1.1" - doAssert v"1.0.1" < v"1.1" - doAssert v"1" < v"1.1" - doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer. - doAssert v"#a111" < v"#head" - - let conf = newConfigRef() - var rr = newStringTable() - addPackage conf, rr, "irc-#a111", unknownLineInfo - addPackage conf, rr, "irc-#head", unknownLineInfo - addPackage conf, rr, "irc-0.1.0", unknownLineInfo - #addPackage conf, rr, "irc", unknownLineInfo - #addPackage conf, rr, "another", unknownLineInfo - addPackage conf, rr, "another-0.1", unknownLineInfo - - addPackage conf, rr, "ab-0.1.3", unknownLineInfo - addPackage conf, rr, "ab-0.1", unknownLineInfo - addPackage conf, rr, "justone-1.0", unknownLineInfo - - doAssert toSeq(rr.chosen) == - @["irc-#head", "another-0.1", "ab-0.1.3", "justone-1.0"] - diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 888e0a572..d8f3613b0 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -99,19 +99,3 @@ when true: proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.} proc writeFile*(x: AbsoluteFile; content: string) {.borrow.} - -when isMainModule: - doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" - doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" - doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" - doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim" - doAssert $RelativeDir"foo/bar" == "foo/bar" - doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar" - doAssert RelativeFile"foo/bar".changeFileExt(".txt") == RelativeFile"foo/bar.txt" - doAssert RelativeFile"foo/bar".addFileExt(".txt") == RelativeFile"foo/bar.txt" - doAssert not RelativeDir"foo/bar".isEmpty - doAssert RelativeDir"".isEmpty - -when isMainModule and defined(windows): - let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim") - doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim" diff --git a/compiler/prefixmatches.nim b/compiler/prefixmatches.nim index b03d1d76e..71ae9a844 100644 --- a/compiler/prefixmatches.nim +++ b/compiler/prefixmatches.nim @@ -54,36 +54,3 @@ proc prefixMatch*(p, s: string): PrefixMatch = else: return PrefixMatch.None return PrefixMatch.None - -when isMainModule: - import macros - - macro check(val, body: untyped): untyped = - result = newStmtList() - expectKind body, nnkStmtList - for b in body: - expectKind b, nnkPar - expectLen b, 2 - let p = b[0] - let s = b[1] - result.add quote do: - echo prefixMatch(`p`, `s`) == `val` - - check PrefixMatch.Prefix: - ("abc", "abc") - ("a", "abc") - ("xyz", "X_yzzzZe") - - check PrefixMatch.Substr: - ("b", "abc") - ("abc", "fooabcabc") - ("abC", "foo_AB_c") - - check PrefixMatch.Abbrev: - ("abc", "AxxxBxxxCxxx") - ("xyz", "X_yabcZe") - - check PrefixMatch.None: - ("foobar", "afkslfjd_as") - ("xyz", "X_yuuZuuZe") - ("ru", "remotes") diff --git a/tests/compiler/tbrees.nim b/tests/compiler/tbrees.nim new file mode 100644 index 000000000..364b51b22 --- /dev/null +++ b/tests/compiler/tbrees.nim @@ -0,0 +1,84 @@ +discard """ + output: ''' +www.amazon.com: 207.171.182.16 +www.apple.com: 17.112.152.32 +www.cnn.com: 64.236.16.20 +www.cs.princeton.edu: abc +www.dell.com: 143.166.224.230 +www.ebay.com: 66.135.192.87 +www.espn.com: 199.181.135.201 +www.google.com: 216.239.41.99 +www.microsoft.com: 207.126.99.140 +www.nytimes.com: 199.239.136.200 +www.princeton.edu: 128.112.128.15 +www.simpsons.com: 209.052.165.60 +www.slashdot.org: 66.35.250.151 +www.weather.com: 63.111.66.11 +www.yahoo.com: 216.109.118.65 +www.yale.edu: 130.132.143.21 +''' +""" + +import compiler/btrees + +import random, tables + +proc main = + var st = initBTree[string, string]() + st.add("www.cs.princeton.edu", "abc") + st.add("www.princeton.edu", "128.112.128.15") + st.add("www.yale.edu", "130.132.143.21") + st.add("www.simpsons.com", "209.052.165.60") + st.add("www.apple.com", "17.112.152.32") + st.add("www.amazon.com", "207.171.182.16") + st.add("www.ebay.com", "66.135.192.87") + st.add("www.cnn.com", "64.236.16.20") + st.add("www.google.com", "216.239.41.99") + st.add("www.nytimes.com", "199.239.136.200") + st.add("www.microsoft.com", "207.126.99.140") + st.add("www.dell.com", "143.166.224.230") + st.add("www.slashdot.org", "66.35.250.151") + st.add("www.espn.com", "199.181.135.201") + st.add("www.weather.com", "63.111.66.11") + st.add("www.yahoo.com", "216.109.118.65") + + assert st.getOrDefault("www.cs.princeton.edu") == "abc" + assert st.getOrDefault("www.harvardsucks.com") == "" + + assert st.getOrDefault("www.simpsons.com") == "209.052.165.60" + assert st.getOrDefault("www.apple.com") == "17.112.152.32" + assert st.getOrDefault("www.ebay.com") == "66.135.192.87" + assert st.getOrDefault("www.dell.com") == "143.166.224.230" + assert(st.len == 16) + + for k, v in st: + echo k, ": ", v + + when false: + var b2 = initBTree[string, string]() + const iters = 10_000 + for i in 1..iters: + b2.add($i, $(iters - i)) + for i in 1..iters: + let x = b2.getOrDefault($i) + if x != $(iters - i): + echo "got ", x, ", but expected ", iters - i + echo b2.len + + when true: + var b2 = initBTree[int, string]() + var t2 = initTable[int, string]() + const iters = 100_000 + for i in 1..iters: + let x = rand(high(int)) + if not t2.hasKey(x): + doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x + t2[x] = $x + b2.add(x, $x) + + doAssert(b2.len == t2.len, "unique entries " & $b2.len) + for k, v in t2: + doAssert $k == v + doAssert b2.getOrDefault(k) == $k + +main() diff --git a/tests/compiler/tint128.nim b/tests/compiler/tint128.nim new file mode 100644 index 000000000..a30b1b1cc --- /dev/null +++ b/tests/compiler/tint128.nim @@ -0,0 +1,184 @@ +import compiler/int128 + +let (a,b) = divMod(Ten,Ten) + +doAssert $One == "1" +doAssert $Ten == "10" +doAssert $Zero == "0" +let c = parseDecimalInt128("12345678989876543210123456789") +doAssert $c == "12345678989876543210123456789" + +var d : array[39, Int128] +d[0] = parseDecimalInt128("1") +d[1] = parseDecimalInt128("10") +d[2] = parseDecimalInt128("100") +d[3] = parseDecimalInt128("1000") +d[4] = parseDecimalInt128("10000") +d[5] = parseDecimalInt128("100000") +d[6] = parseDecimalInt128("1000000") +d[7] = parseDecimalInt128("10000000") +d[8] = parseDecimalInt128("100000000") +d[9] = parseDecimalInt128("1000000000") +d[10] = parseDecimalInt128("10000000000") +d[11] = parseDecimalInt128("100000000000") +d[12] = parseDecimalInt128("1000000000000") +d[13] = parseDecimalInt128("10000000000000") +d[14] = parseDecimalInt128("100000000000000") +d[15] = parseDecimalInt128("1000000000000000") +d[16] = parseDecimalInt128("10000000000000000") +d[17] = parseDecimalInt128("100000000000000000") +d[18] = parseDecimalInt128("1000000000000000000") +d[19] = parseDecimalInt128("10000000000000000000") +d[20] = parseDecimalInt128("100000000000000000000") +d[21] = parseDecimalInt128("1000000000000000000000") +d[22] = parseDecimalInt128("10000000000000000000000") +d[23] = parseDecimalInt128("100000000000000000000000") +d[24] = parseDecimalInt128("1000000000000000000000000") +d[25] = parseDecimalInt128("10000000000000000000000000") +d[26] = parseDecimalInt128("100000000000000000000000000") +d[27] = parseDecimalInt128("1000000000000000000000000000") +d[28] = parseDecimalInt128("10000000000000000000000000000") +d[29] = parseDecimalInt128("100000000000000000000000000000") +d[30] = parseDecimalInt128("1000000000000000000000000000000") +d[31] = parseDecimalInt128("10000000000000000000000000000000") +d[32] = parseDecimalInt128("100000000000000000000000000000000") +d[33] = parseDecimalInt128("1000000000000000000000000000000000") +d[34] = parseDecimalInt128("10000000000000000000000000000000000") +d[35] = parseDecimalInt128("100000000000000000000000000000000000") +d[36] = parseDecimalInt128("1000000000000000000000000000000000000") +d[37] = parseDecimalInt128("10000000000000000000000000000000000000") +d[38] = parseDecimalInt128("100000000000000000000000000000000000000") + +for i in 0..= 0: + doAssert d[i] div d[j] == d[i-j] + +var sum: Int128 + +for it in d: + sum += it + +doAssert $sum == "111111111111111111111111111111111111111" + +for it in d.mitems: + it = -it + +for i in 0..= 0: + doAssert d[i] div d[j] == -d[i-j] + +doAssert $high(Int128) == "170141183460469231731687303715884105727" +doAssert $low(Int128) == "-170141183460469231731687303715884105728" + +var ma = 100'i64 +var mb = 13 + +doAssert toInt128(ma) * toInt128(0) == toInt128(0) +doAssert toInt128(-ma) * toInt128(0) == toInt128(0) + +# sign correctness +doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb)) +doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb)) +doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb)) +doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb)) + +doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div mb), toInt128( mb mod mb)) +doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div mb), toInt128(-mb mod mb)) +doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb)) +doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb)) + +doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div ma), toInt128( mb mod ma)) +doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div ma), toInt128(-mb mod ma)) +doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma)) +doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma)) + +let e = parseDecimalInt128("70997106675279150998592376708984375") + +let strArray = [ + # toHex(e shr 0), toHex(e shr 1), toHex(e shr 2), toHex(e shr 3) + "000dac6d782d266a37300c32591eee37", "0006d636bc1693351b9806192c8f771b", "00036b1b5e0b499a8dcc030c9647bb8d", "0001b58daf05a4cd46e601864b23ddc6", + "0000dac6d782d266a37300c32591eee3", "00006d636bc1693351b9806192c8f771", "000036b1b5e0b499a8dcc030c9647bb8", "00001b58daf05a4cd46e601864b23ddc", + "00000dac6d782d266a37300c32591eee", "000006d636bc1693351b9806192c8f77", "0000036b1b5e0b499a8dcc030c9647bb", "000001b58daf05a4cd46e601864b23dd", + "000000dac6d782d266a37300c32591ee", "0000006d636bc1693351b9806192c8f7", "00000036b1b5e0b499a8dcc030c9647b", "0000001b58daf05a4cd46e601864b23d", + "0000000dac6d782d266a37300c32591e", "00000006d636bc1693351b9806192c8f", "000000036b1b5e0b499a8dcc030c9647", "00000001b58daf05a4cd46e601864b23", + "00000000dac6d782d266a37300c32591", "000000006d636bc1693351b9806192c8", "0000000036b1b5e0b499a8dcc030c964", "000000001b58daf05a4cd46e601864b2", + "000000000dac6d782d266a37300c3259", "0000000006d636bc1693351b9806192c", "00000000036b1b5e0b499a8dcc030c96", "0000000001b58daf05a4cd46e601864b", + "0000000000dac6d782d266a37300c325", "00000000006d636bc1693351b9806192", "000000000036b1b5e0b499a8dcc030c9", "00000000001b58daf05a4cd46e601864", + "00000000000dac6d782d266a37300c32", "000000000006d636bc1693351b980619", "0000000000036b1b5e0b499a8dcc030c", "000000000001b58daf05a4cd46e60186", + "000000000000dac6d782d266a37300c3", "0000000000006d636bc1693351b98061", "00000000000036b1b5e0b499a8dcc030", "0000000000001b58daf05a4cd46e6018", + "0000000000000dac6d782d266a37300c", "00000000000006d636bc1693351b9806", "000000000000036b1b5e0b499a8dcc03", "00000000000001b58daf05a4cd46e601", + "00000000000000dac6d782d266a37300", "000000000000006d636bc1693351b980", "0000000000000036b1b5e0b499a8dcc0", "000000000000001b58daf05a4cd46e60", + "000000000000000dac6d782d266a3730", "0000000000000006d636bc1693351b98", "00000000000000036b1b5e0b499a8dcc", "0000000000000001b58daf05a4cd46e6", + "0000000000000000dac6d782d266a373", "00000000000000006d636bc1693351b9", "000000000000000036b1b5e0b499a8dc", "00000000000000001b58daf05a4cd46e", + "00000000000000000dac6d782d266a37", "000000000000000006d636bc1693351b", "0000000000000000036b1b5e0b499a8d", "000000000000000001b58daf05a4cd46", + "000000000000000000dac6d782d266a3", "0000000000000000006d636bc1693351", "00000000000000000036b1b5e0b499a8", "0000000000000000001b58daf05a4cd4", + "0000000000000000000dac6d782d266a", "00000000000000000006d636bc169335", "000000000000000000036b1b5e0b499a", "00000000000000000001b58daf05a4cd", + "00000000000000000000dac6d782d266", "000000000000000000006d636bc16933", "0000000000000000000036b1b5e0b499", "000000000000000000001b58daf05a4c", + "000000000000000000000dac6d782d26", "0000000000000000000006d636bc1693", "00000000000000000000036b1b5e0b49", "0000000000000000000001b58daf05a4", + "0000000000000000000000dac6d782d2", "00000000000000000000006d636bc169", "000000000000000000000036b1b5e0b4", "00000000000000000000001b58daf05a", + "00000000000000000000000dac6d782d", "000000000000000000000006d636bc16", "0000000000000000000000036b1b5e0b", "000000000000000000000001b58daf05", + "000000000000000000000000dac6d782", "0000000000000000000000006d636bc1", "00000000000000000000000036b1b5e0", "0000000000000000000000001b58daf0", + "0000000000000000000000000dac6d78", "00000000000000000000000006d636bc", "000000000000000000000000036b1b5e", "00000000000000000000000001b58daf", + "00000000000000000000000000dac6d7", "000000000000000000000000006d636b", "0000000000000000000000000036b1b5", "000000000000000000000000001b58da", + "000000000000000000000000000dac6d", "0000000000000000000000000006d636", "00000000000000000000000000036b1b", "0000000000000000000000000001b58d", + "0000000000000000000000000000dac6", "00000000000000000000000000006d63", "000000000000000000000000000036b1", "00000000000000000000000000001b58", + "00000000000000000000000000000dac", "000000000000000000000000000006d6", "0000000000000000000000000000036b", "000000000000000000000000000001b5", + "000000000000000000000000000000da", "0000000000000000000000000000006d", "00000000000000000000000000000036", "0000000000000000000000000000001b", + "0000000000000000000000000000000d", "00000000000000000000000000000006", "00000000000000000000000000000003", "00000000000000000000000000000001", + "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", + "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", + "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", +] + +for i in 0 ..< 128: + let str1 = toHex(e shr i) + let str2 = strArray[i] + doAssert str1 == str2 + +let strArray2 = [ + "000dac6d782d266a37300c32591eee37", "001b58daf05a4cd46e601864b23ddc6e", "0036b1b5e0b499a8dcc030c9647bb8dc", "006d636bc1693351b9806192c8f771b8", + "00dac6d782d266a37300c32591eee370", "01b58daf05a4cd46e601864b23ddc6e0", "036b1b5e0b499a8dcc030c9647bb8dc0", "06d636bc1693351b9806192c8f771b80", + "0dac6d782d266a37300c32591eee3700", "1b58daf05a4cd46e601864b23ddc6e00", "36b1b5e0b499a8dcc030c9647bb8dc00", "6d636bc1693351b9806192c8f771b800", + "dac6d782d266a37300c32591eee37000", "b58daf05a4cd46e601864b23ddc6e000", "6b1b5e0b499a8dcc030c9647bb8dc000", "d636bc1693351b9806192c8f771b8000", + "ac6d782d266a37300c32591eee370000", "58daf05a4cd46e601864b23ddc6e0000", "b1b5e0b499a8dcc030c9647bb8dc0000", "636bc1693351b9806192c8f771b80000", + "c6d782d266a37300c32591eee3700000", "8daf05a4cd46e601864b23ddc6e00000", "1b5e0b499a8dcc030c9647bb8dc00000", "36bc1693351b9806192c8f771b800000", + "6d782d266a37300c32591eee37000000", "daf05a4cd46e601864b23ddc6e000000", "b5e0b499a8dcc030c9647bb8dc000000", "6bc1693351b9806192c8f771b8000000", + "d782d266a37300c32591eee370000000", "af05a4cd46e601864b23ddc6e0000000", "5e0b499a8dcc030c9647bb8dc0000000", "bc1693351b9806192c8f771b80000000", + "782d266a37300c32591eee3700000000", "f05a4cd46e601864b23ddc6e00000000", "e0b499a8dcc030c9647bb8dc00000000", "c1693351b9806192c8f771b800000000", + "82d266a37300c32591eee37000000000", "05a4cd46e601864b23ddc6e000000000", "0b499a8dcc030c9647bb8dc000000000", "1693351b9806192c8f771b8000000000", + "2d266a37300c32591eee370000000000", "5a4cd46e601864b23ddc6e0000000000", "b499a8dcc030c9647bb8dc0000000000", "693351b9806192c8f771b80000000000", + "d266a37300c32591eee3700000000000", "a4cd46e601864b23ddc6e00000000000", "499a8dcc030c9647bb8dc00000000000", "93351b9806192c8f771b800000000000", + "266a37300c32591eee37000000000000", "4cd46e601864b23ddc6e000000000000", "99a8dcc030c9647bb8dc000000000000", "3351b9806192c8f771b8000000000000", + "66a37300c32591eee370000000000000", "cd46e601864b23ddc6e0000000000000", "9a8dcc030c9647bb8dc0000000000000", "351b9806192c8f771b80000000000000", + "6a37300c32591eee3700000000000000", "d46e601864b23ddc6e00000000000000", "a8dcc030c9647bb8dc00000000000000", "51b9806192c8f771b800000000000000", + "a37300c32591eee37000000000000000", "46e601864b23ddc6e000000000000000", "8dcc030c9647bb8dc000000000000000", "1b9806192c8f771b8000000000000000", + "37300c32591eee370000000000000000", "6e601864b23ddc6e0000000000000000", "dcc030c9647bb8dc0000000000000000", "b9806192c8f771b80000000000000000", + "7300c32591eee3700000000000000000", "e601864b23ddc6e00000000000000000", "cc030c9647bb8dc00000000000000000", "9806192c8f771b800000000000000000", + "300c32591eee37000000000000000000", "601864b23ddc6e000000000000000000", "c030c9647bb8dc000000000000000000", "806192c8f771b8000000000000000000", + "00c32591eee370000000000000000000", "01864b23ddc6e0000000000000000000", "030c9647bb8dc0000000000000000000", "06192c8f771b80000000000000000000", + "0c32591eee3700000000000000000000", "1864b23ddc6e00000000000000000000", "30c9647bb8dc00000000000000000000", "6192c8f771b800000000000000000000", + "c32591eee37000000000000000000000", "864b23ddc6e000000000000000000000", "0c9647bb8dc000000000000000000000", "192c8f771b8000000000000000000000", + "32591eee370000000000000000000000", "64b23ddc6e0000000000000000000000", "c9647bb8dc0000000000000000000000", "92c8f771b80000000000000000000000", + "2591eee3700000000000000000000000", "4b23ddc6e00000000000000000000000", "9647bb8dc00000000000000000000000", "2c8f771b800000000000000000000000", + "591eee37000000000000000000000000", "b23ddc6e000000000000000000000000", "647bb8dc000000000000000000000000", "c8f771b8000000000000000000000000", + "91eee370000000000000000000000000", "23ddc6e0000000000000000000000000", "47bb8dc0000000000000000000000000", "8f771b80000000000000000000000000", + "1eee3700000000000000000000000000", "3ddc6e00000000000000000000000000", "7bb8dc00000000000000000000000000", "f771b800000000000000000000000000", + "eee37000000000000000000000000000", "ddc6e000000000000000000000000000", "bb8dc000000000000000000000000000", "771b8000000000000000000000000000", + "ee370000000000000000000000000000", "dc6e0000000000000000000000000000", "b8dc0000000000000000000000000000", "71b80000000000000000000000000000", + "e3700000000000000000000000000000", "c6e00000000000000000000000000000", "8dc00000000000000000000000000000", "1b800000000000000000000000000000", + "37000000000000000000000000000000", "6e000000000000000000000000000000", "dc000000000000000000000000000000", "b8000000000000000000000000000000", + "70000000000000000000000000000000", "e0000000000000000000000000000000", "c0000000000000000000000000000000", "80000000000000000000000000000000", +] + +for i in 0 ..< 128: + let str1 = toHex(e shl i) + let str2 = strArray2[i] + doAssert str1 == str2 diff --git a/tests/compiler/tnimblecmd.nim b/tests/compiler/tnimblecmd.nim new file mode 100644 index 000000000..d39179be1 --- /dev/null +++ b/tests/compiler/tnimblecmd.nim @@ -0,0 +1,26 @@ +include compiler/[nimblecmd] + +proc v(s: string): Version = s.newVersion +# #head is special in the sense that it's assumed to always be newest. +doAssert v"1.0" < v"#head" +doAssert v"1.0" < v"1.1" +doAssert v"1.0.1" < v"1.1" +doAssert v"1" < v"1.1" +doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer. +doAssert v"#a111" < v"#head" + +let conf = newConfigRef() +var rr = newStringTable() +addPackage conf, rr, "irc-#a111", unknownLineInfo +addPackage conf, rr, "irc-#head", unknownLineInfo +addPackage conf, rr, "irc-0.1.0", unknownLineInfo +#addPackage conf, rr, "irc", unknownLineInfo +#addPackage conf, rr, "another", unknownLineInfo +addPackage conf, rr, "another-0.1", unknownLineInfo + +addPackage conf, rr, "ab-0.1.3", unknownLineInfo +addPackage conf, rr, "ab-0.1", unknownLineInfo +addPackage conf, rr, "justone-1.0", unknownLineInfo + +doAssert toSeq(rr.chosen) == + @["irc-#head", "ab-0.1.3", "justone-1.0", "another-0.1"] diff --git a/tests/compiler/tpathutils.nim b/tests/compiler/tpathutils.nim new file mode 100644 index 000000000..47ff0f06a --- /dev/null +++ b/tests/compiler/tpathutils.nim @@ -0,0 +1,18 @@ +import compiler/pathutils +import os, strutils + + +doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" +doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" +doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" +doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim" +doAssert $RelativeDir"foo/bar" == "foo/bar" +doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar" +doAssert RelativeFile"foo/bar".changeFileExt(".txt") == RelativeFile"foo/bar.txt" +doAssert RelativeFile"foo/bar".addFileExt(".txt") == RelativeFile"foo/bar.txt" +doAssert not RelativeDir"foo/bar".isEmpty +doAssert RelativeDir"".isEmpty + +when defined(windows): + let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim") + doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim" diff --git a/tests/compiler/tprefixmatches.nim b/tests/compiler/tprefixmatches.nim new file mode 100644 index 000000000..a89a6f613 --- /dev/null +++ b/tests/compiler/tprefixmatches.nim @@ -0,0 +1,32 @@ +import compiler/prefixmatches +import macros + +macro check(val, body: untyped): untyped = + result = newStmtList() + expectKind body, nnkStmtList + for b in body: + expectKind b, nnkPar + expectLen b, 2 + let p = b[0] + let s = b[1] + result.add quote do: + doAssert prefixMatch(`p`, `s`) == `val` + +check PrefixMatch.Prefix: + ("abc", "abc") + ("a", "abc") + ("xyz", "X_yzzzZe") + +check PrefixMatch.Substr: + ("b", "abc") + ("abc", "fooabcabc") + ("abC", "foo_AB_c") + +check PrefixMatch.Abbrev: + ("abc", "AxxxBxxxCxxx") + ("xyz", "X_yabcZe") + +check PrefixMatch.None: + ("foobar", "afkslfjd_as") + ("xyz", "X_yuuZuuZe") + ("ru", "remotes") From e220f756e795b972b72d4e8b9d729d1d9b73d2e2 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Wed, 25 Nov 2020 11:15:34 +0200 Subject: [PATCH 1556/4254] fix for comparing infinities (#16122) --- lib/pure/math.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index af31a5785..ccd766f46 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -177,6 +177,17 @@ proc almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. runnableExamples: doAssert almostEqual(3.141592653589793, 3.1415926535897936) doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32) + doAssert almostEqual(Inf, Inf) + doAssert almostEqual(-Inf, -Inf) + doAssert almostEqual(Inf, -Inf) == false + doAssert almostEqual(-Inf, Inf) == false + doAssert almostEqual(Inf, NaN) == false + doAssert almostEqual(NaN, NaN) == false + + if x == y: + # short circuit exact equality -- needed to catch two infinities of + # the same sign. And perhaps speeds things up a bit sometimes. + return true let diff = abs(x - y) result = diff <= epsilon(T) * abs(x + y) * T(unitsInLastPlace) or diff < minimumPositiveValue(T) From 7848da7abe683f98019f54f9b99ce531c99e7eaf Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 25 Nov 2020 21:09:03 +0800 Subject: [PATCH 1557/4254] inc and dec are atomic in JS backend (#16129) --- lib/system.nim | 2 +- tests/system/tatomics1.nim | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/system/tatomics1.nim diff --git a/lib/system.nim b/lib/system.nim index be41c1893..68385ef63 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1774,7 +1774,7 @@ when not defined(nimscript): when not declared(sysFatal): include "system/fatal" -when notJSnotNims: +when not defined(nimscript): {.push stackTrace: off, profiler: off.} proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, diff --git a/tests/system/tatomics1.nim b/tests/system/tatomics1.nim new file mode 100644 index 000000000..88ab705a8 --- /dev/null +++ b/tests/system/tatomics1.nim @@ -0,0 +1,9 @@ +discard """ + target: "c cpp js" +""" + +var x = 10 +atomicInc(x) +doAssert x == 11 +atomicDec(x) +doAssert x == 10 From 3e7077ac7d2f4867ecabff09b730b6bc9356979d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 25 Nov 2020 11:48:10 -0800 Subject: [PATCH 1558/4254] fix #14339, #13511, #14420: fixes limited VM support for addr (#16002) * fix #14339: fixes limited VM support for addr * strengthen test * reference bug #16003 * also fixes #13511 * also fixes #14420 --- compiler/vm.nim | 7 ++- tests/macros/tmacros_various.nim | 25 +++++++++ tests/misc/taddr.nim | 80 +++++++++++++++++++++++++++ tests/stdlib/tcritbits.nim | 92 +++++++++++++++++--------------- 4 files changed, 160 insertions(+), 44 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index a6478f3f0..17bbe65fc 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -746,10 +746,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].regAddr = addr(regs[rb]) of opcAddrNode: decodeB(rkNodeAddr) - if regs[rb].kind == rkNode: + case regs[rb].kind + of rkNode: regs[ra].nodeAddr = addr(regs[rb].node) + of rkNodeAddr: # bug #14339 + regs[ra].nodeAddr = regs[rb].nodeAddr else: - stackTrace(c, tos, pc, "limited VM support for 'addr'") + stackTrace(c, tos, pc, "limited VM support for 'addr', got kind: " & $regs[rb].kind) of opcLdDeref: # a = b[] let ra = instr.regA diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 056830837..00d74cb5c 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -245,3 +245,28 @@ xbenchmark: discard inputtest fastSHA("hey") + +block: # bug #13511 + type + Builder = ref object + components: seq[Component] + Component = object + + proc add(builder: var Builder, component: Component) {.compileTime.} = + builder.components.add(component) + + macro debugAst(arg: typed): untyped = + ## just for debugging purpose. + discard arg.treeRepr + return arg + + static: + var component = Component() + var builder = Builder() + + template foo(): untyped = + ## WAS: this doc comment causes compilation failure. + builder + + debugAst: + add(foo(), component) diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim index 49a577798..d743d4b4a 100644 --- a/tests/misc/taddr.nim +++ b/tests/misc/taddr.nim @@ -123,3 +123,83 @@ block: block: # pending bug #15959 when false: proc byLent2[T](a: T): lent type(a[0]) = a[0] + +proc test14420() = # bug #14420 + # s/proc/template/ would hit bug #16005 + block: + type Foo = object + x: float + + proc fn(a: var Foo): var float = + ## WAS: discard <- turn this into a comment (or a `discard`) and error disappears + # result = a.x # this works + a.x # WAS: Error: limited VM support for 'addr' + + proc fn2(a: var Foo): var float = + result = a.x # this works + a.x # WAS: Error: limited VM support for 'addr' + + var a = Foo() + discard fn(a) + discard fn2(a) + + block: + proc byLent2[T](a: T): lent T = + runnableExamples: discard + a + proc byLent3[T](a: T): lent T = + runnableExamples: discard + result = a + var a = 10 + let x3 = byLent3(a) # works + let x2 = byLent2(a) # WAS: Error: internal error: genAddr: nkStmtListExpr + + block: + type MyOption[T] = object + case has: bool + of true: + value: T + of false: + discard + func some[T](val: T): MyOption[T] = + result = MyOption[T](has: true, value: val) + func get[T](opt: MyOption[T]): lent T = + doAssert opt.has + # result = opt.value # this was ok + opt.value # this had the bug + let x = some(10) + doAssert x.get() == 10 + +template test14339() = # bug #14339 + block: + type + Node = ref object + val: int + proc bar(c: Node): var int = + var n = c # was: Error: limited VM support for 'addr' + c.val + var a = Node() + discard a.bar() + block: + type + Node = ref object + val: int + proc bar(c: Node): var int = + var n = c + doAssert n.val == n[].val + n.val + var a = Node(val: 3) + a.bar() = 5 + when nimvm: + doAssert a.val == 5 + else: + when not defined(js): # pending bug #16003 + doAssert a.val == 5 + +template main = + # xxx wrap all other tests here like that so they're also tested in VM + test14420() + test14339() + +static: main() +main() diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim index 51cbb7bf2..4b05cd950 100644 --- a/tests/stdlib/tcritbits.nim +++ b/tests/stdlib/tcritbits.nim @@ -1,61 +1,69 @@ -import sequtils, critbits +import std/[sequtils,critbits] +template main = + var r: CritBitTree[void] + r.incl "abc" + r.incl "xyz" + r.incl "def" + r.incl "definition" + r.incl "prefix" + r.incl "foo" -var r: CritBitTree[void] -r.incl "abc" -r.incl "xyz" -r.incl "def" -r.incl "definition" -r.incl "prefix" -r.incl "foo" + doAssert r.contains"def" -doAssert r.contains"def" + r.excl "def" + assert r.missingOrExcl("foo") == false + assert "foo" notin toSeq(r.items) -r.excl "def" -assert r.missingOrExcl("foo") == false -assert "foo" notin toSeq(r.items) + assert r.missingOrExcl("foo") == true -assert r.missingOrExcl("foo") == true + assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] -assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] + assert toSeq(r.itemsWithPrefix("de")) == @["definition"] + var c = CritBitTree[int]() -assert toSeq(r.itemsWithPrefix("de")) == @["definition"] -var c = CritBitTree[int]() + c.inc("a") + assert c["a"] == 1 -c.inc("a") -assert c["a"] == 1 + c.inc("a", 4) + assert c["a"] == 5 -c.inc("a", 4) -assert c["a"] == 5 + c.inc("a", -5) + assert c["a"] == 0 -c.inc("a", -5) -assert c["a"] == 0 + c.inc("b", 2) + assert c["b"] == 2 -c.inc("b", 2) -assert c["b"] == 2 + c.inc("c", 3) + assert c["c"] == 3 -c.inc("c", 3) -assert c["c"] == 3 + c.inc("a", 1) + assert c["a"] == 1 -c.inc("a", 1) -assert c["a"] == 1 + var cf = CritBitTree[float]() -var cf = CritBitTree[float]() + cf.incl("a", 1.0) + assert cf["a"] == 1.0 -cf.incl("a", 1.0) -assert cf["a"] == 1.0 + cf.incl("b", 2.0) + assert cf["b"] == 2.0 -cf.incl("b", 2.0) -assert cf["b"] == 2.0 + cf.incl("c", 3.0) + assert cf["c"] == 3.0 -cf.incl("c", 3.0) -assert cf["c"] == 3.0 + assert cf.len == 3 + cf.excl("c") + assert cf.len == 2 -assert cf.len == 3 -cf.excl("c") -assert cf.len == 2 + var cb: CritBitTree[string] + cb.incl("help", "help") + for k in cb.keysWithPrefix("helpp"): + doAssert false, "there is no prefix helpp" -var cb: CritBitTree[string] -cb.incl("help", "help") -for k in cb.keysWithPrefix("helpp"): - doAssert false, "there is no prefix helpp" + block: # bug #14339 + var strings: CritBitTree[int] + discard strings.containsOrIncl("foo", 3) + doAssert strings["foo"] == 3 + +main() +static: main() From da753c6a2eded5a382faf22dbf2a2ec1b1fc328f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 26 Nov 2020 10:24:52 +0100 Subject: [PATCH 1559/4254] fixes #15076 (#16143) * fixes #15076 * heapqueue: optimized for ARC * added another test case [backport:1.4] * code cleanup --- compiler/injectdestructors.nim | 8 ++-- lib/pure/collections/heapqueue.nim | 10 ++-- tests/arc/tasyncleak4.nim | 21 +++++++++ tests/arc/tdestroy_in_loopcond.nim | 74 ++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 tests/arc/tasyncleak4.nim create mode 100644 tests/arc/tdestroy_in_loopcond.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 869e8ecc8..34c11e06c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -37,7 +37,7 @@ type g: ControlFlowGraph graph: ModuleGraph otherRead: PNode - inLoop, inSpawn: int + inLoop, inSpawn, inLoopCond: int uninit: IntSet # set of uninit'ed vars uninitComputed: bool idgen: IdGenerator @@ -296,8 +296,8 @@ proc isNoInit(dest: PNode): bool {.inline.} = result = dest.kind == nkSym and sfNoInit in dest.sym.flags proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = - if isUnpackedTuple(dest) or isDecl or - (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)) or + if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or isDecl or + (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or isNoInit(dest): # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) @@ -629,8 +629,10 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = of nkWhileStmt: inc c.inLoop + inc c.inLoopCond result = copyNode(n) result.add p(n[0], c, s, normal) + dec c.inLoopCond var bodyScope = nestedScope(s) let bodyResult = p(n[1], c, bodyScope, normal) result.add processScope(c, bodyScope, bodyResult) diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index 00e7a3b9d..30fa5dae8 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -65,7 +65,7 @@ proc len*[T](heap: HeapQueue[T]): int {.inline.} = ## Returns the number of elements of `heap`. heap.data.len -proc `[]`*[T](heap: HeapQueue[T], i: Natural): T {.inline.} = +proc `[]`*[T](heap: HeapQueue[T], i: Natural): lent T {.inline.} = ## Accesses the i-th element of `heap`. heap.data[i] @@ -111,7 +111,7 @@ proc siftup[T](heap: var HeapQueue[T], p: int) = heap.data[pos] = newitem siftdown(heap, startpos, pos) -proc push*[T](heap: var HeapQueue[T], item: T) = +proc push*[T](heap: var HeapQueue[T], item: sink T) = ## Pushes `item` onto heap, maintaining the heap invariant. heap.data.add(item) siftdown(heap, 0, len(heap)-1) @@ -168,7 +168,7 @@ proc del*[T](heap: var HeapQueue[T], index: Natural) = if index < newLen: heap.siftup(index) -proc replace*[T](heap: var HeapQueue[T], item: T): T = +proc replace*[T](heap: var HeapQueue[T], item: sink T): T = ## Pops and returns the current smallest value, and add the new item. ## This is more efficient than pop() followed by push(), and can be ## more appropriate when using a fixed-size heap. Note that the value @@ -186,7 +186,7 @@ proc replace*[T](heap: var HeapQueue[T], item: T): T = heap.data[0] = item siftup(heap, 0) -proc pushpop*[T](heap: var HeapQueue[T], item: T): T = +proc pushpop*[T](heap: var HeapQueue[T], item: sink T): T = ## Fast version of a push followed by a pop. runnableExamples: var heap = initHeapQueue[int]() @@ -197,7 +197,7 @@ proc pushpop*[T](heap: var HeapQueue[T], item: T): T = assert heap[0] == 6 assert heap.pushpop(4) == 4 result = item - if heap.len > 0 and heapCmp(heap.data[0], item): + if heap.len > 0 and heapCmp(heap.data[0], result): swap(result, heap.data[0]) siftup(heap, 0) diff --git a/tests/arc/tasyncleak4.nim b/tests/arc/tasyncleak4.nim new file mode 100644 index 000000000..58cd7f0b7 --- /dev/null +++ b/tests/arc/tasyncleak4.nim @@ -0,0 +1,21 @@ +discard """ + cmd: "nim c --gc:orc -d:useMalloc $file" + output: '''ok''' + valgrind: "leaks" +""" + +# bug #15076 +import asyncdispatch + +var futures: seq[Future[void]] + +for i in 1..20: + futures.add sleepAsync 1 + futures.add sleepAsync 1 + + futures.all.waitFor() + futures.setLen 0 + +setGlobalDispatcher nil +GC_fullCollect() +echo "ok" diff --git a/tests/arc/tdestroy_in_loopcond.nim b/tests/arc/tdestroy_in_loopcond.nim new file mode 100644 index 000000000..62532664d --- /dev/null +++ b/tests/arc/tdestroy_in_loopcond.nim @@ -0,0 +1,74 @@ +discard """ + output: '''400 true''' + cmd: "nim c --gc:orc $file" +""" + +type HeapQueue*[T] = object + data: seq[T] + + +proc len*[T](heap: HeapQueue[T]): int {.inline.} = + heap.data.len + +proc `[]`*[T](heap: HeapQueue[T], i: Natural): T {.inline.} = + heap.data[i] + +proc push*[T](heap: var HeapQueue[T], item: T) = + heap.data.add(item) + +proc pop*[T](heap: var HeapQueue[T]): T = + result = heap.data.pop + +proc clear*[T](heap: var HeapQueue[T]) = heap.data.setLen 0 + + +type + Future = ref object of RootObj + s: string + callme: proc() + +var called = 0 + +proc consume(f: Future) = + inc called + +proc newFuture(s: string): Future = + var r: Future + r = Future(s: s, callme: proc() = + consume r) + result = r + +var q: HeapQueue[tuple[finishAt: int64, fut: Future]] + +proc sleep(f: int64): Future = + q.push (finishAt: f, fut: newFuture("async-sleep")) + +proc processTimers = + # Pop the timers in the order in which they will expire (smaller `finishAt`). + var count = q.len + let t = high(int64) + while count > 0 and t >= q[0].finishAt: + q.pop().fut.callme() + dec count + +var futures: seq[Future] + +proc main = + for i in 1..200: + futures.add sleep(56020904056300) + futures.add sleep(56020804337500) + #futures.add sleep(2.0) + + #futures.add sleep(4.0) + + processTimers() + #q.pop()[1].callme() + #q.pop()[1].callme() + + futures.setLen 0 + + q.clear() + +main() +GC_fullCollect() +echo called, " ", getOccupiedMem() < 160 From 0b3a45692c26960f528f70d890f2a2d387aac120 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 26 Nov 2020 17:57:05 +0800 Subject: [PATCH 1560/4254] improve docs for prelude (#16135) * improve docs for prelude * better --- lib/prelude.nim | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/prelude.nim b/lib/prelude.nim index d24f35513..47a5af89e 100644 --- a/lib/prelude.nim +++ b/lib/prelude.nim @@ -7,16 +7,17 @@ # distribution, for details about the copyright. # -# This is an include file that simply imports common modules for your -# convenience: -# -# .. code-block:: nim -# include prelude -# -# Same as: -# -# .. code-block:: nim -# import os, strutils, times, parseutils, parseopt, hashes, tables, sets +## This is an include file that simply imports common modules for your +## convenience: +## +## .. code-block:: nim +## include prelude +## +## Same as: +## +## .. code-block:: nim +## import os, strutils, times, parseutils, hashes, tables, sets +## when not defined(js): import parseopt import os, strutils, times, parseutils, hashes, tables, sets when not defined(js): import parseopt From e7e9007c4c061fa690c1978f118cf62badb19bd5 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 26 Nov 2020 18:08:53 +0800 Subject: [PATCH 1561/4254] ref #16054 undefine some stuff in JS backend (#16070) --- lib/system.nim | 91 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 68385ef63..c13b419ef 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1897,53 +1897,54 @@ else: # however, stack-traces are available for most parts # of the code -var - globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} - ## With this hook you can influence exception handling on a global level. - ## If not nil, every 'raise' statement ends up calling this hook. - ## - ## **Warning**: Ordinary application code should never set this hook! - ## You better know what you do when setting this. - ## - ## If ``globalRaiseHook`` returns false, the exception is caught and does - ## not propagate further through the call stack. +when notJSnotNims: + var + globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} + ## With this hook you can influence exception handling on a global level. + ## If not nil, every 'raise' statement ends up calling this hook. + ## + ## **Warning**: Ordinary application code should never set this hook! + ## You better know what you do when setting this. + ## + ## If ``globalRaiseHook`` returns false, the exception is caught and does + ## not propagate further through the call stack. - localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} - ## With this hook you can influence exception handling on a - ## thread local level. - ## If not nil, every 'raise' statement ends up calling this hook. - ## - ## **Warning**: Ordinary application code should never set this hook! - ## You better know what you do when setting this. - ## - ## If ``localRaiseHook`` returns false, the exception - ## is caught and does not propagate further through the call stack. + localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} + ## With this hook you can influence exception handling on a + ## thread local level. + ## If not nil, every 'raise' statement ends up calling this hook. + ## + ## **Warning**: Ordinary application code should never set this hook! + ## You better know what you do when setting this. + ## + ## If ``localRaiseHook`` returns false, the exception + ## is caught and does not propagate further through the call stack. - outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} - ## Set this variable to provide a procedure that should be called - ## in case of an `out of memory`:idx: event. The standard handler - ## writes an error message and terminates the program. - ## - ## `outOfMemHook` can be used to raise an exception in case of OOM like so: - ## - ## .. code-block:: Nim - ## - ## var gOutOfMem: ref EOutOfMemory - ## new(gOutOfMem) # need to be allocated *before* OOM really happened! - ## gOutOfMem.msg = "out of memory" - ## - ## proc handleOOM() = - ## raise gOutOfMem - ## - ## system.outOfMemHook = handleOOM - ## - ## If the handler does not raise an exception, ordinary control flow - ## continues and the program is terminated. - unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} - ## Set this variable to provide a procedure that should be called - ## in case of an `unhandle exception` event. The standard handler - ## writes an error message and terminates the program, except when - ## using `--os:any` + outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `out of memory`:idx: event. The standard handler + ## writes an error message and terminates the program. + ## + ## `outOfMemHook` can be used to raise an exception in case of OOM like so: + ## + ## .. code-block:: Nim + ## + ## var gOutOfMem: ref EOutOfMemory + ## new(gOutOfMem) # need to be allocated *before* OOM really happened! + ## gOutOfMem.msg = "out of memory" + ## + ## proc handleOOM() = + ## raise gOutOfMem + ## + ## system.outOfMemHook = handleOOM + ## + ## If the handler does not raise an exception, ordinary control flow + ## continues and the program is terminated. + unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `unhandle exception` event. The standard handler + ## writes an error message and terminates the program, except when + ## using `--os:any` type PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; From 8c12d3e29d06383f1752b24eeabcbf0439e920d5 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 26 Nov 2020 13:37:34 +0000 Subject: [PATCH 1562/4254] fix #16120 (#16145) --- compiler/sempass2.nim | 106 +++++++++++++++++++++--------------------- tests/arc/t14383.nim | 16 ++++++- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 39ba1b307..35b1473c5 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -755,63 +755,66 @@ proc trackCall(tracked: PEffects; n: PNode) = if n.typ != nil: if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray: createTypeBoundOps(tracked, n.typ, n.info) - if getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) != nil: - return - if a.kind == nkCast and a[1].typ.kind == tyProc: - a = a[1] - # XXX: in rare situations, templates and macros will reach here after - # calling getAst(templateOrMacro()). Currently, templates and macros - # are indistinguishable from normal procs (both have tyProc type) and - # we can detect them only by checking for attached nkEffectList. - if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList: - if a.kind == nkSym: - if a.sym == tracked.owner: tracked.isRecursive = true - # even for recursive calls we need to check the lock levels (!): - mergeLockLevels(tracked, n, a.sym.getLockLevel) - if sfSideEffect in a.sym.flags: markSideEffect(tracked, a) - else: - mergeLockLevels(tracked, n, op.lockLevel) - var effectList = op.n[0] - if a.kind == nkSym and a.sym.kind == skMethod: - propagateEffects(tracked, n, a.sym) - elif isNoEffectList(effectList): - if isForwardedProc(a): - propagateEffects(tracked, n, a.sym) - elif isIndirectCall(a, tracked.owner): - assumeTheWorst(tracked, n, op) - gcsafeAndSideeffectCheck() - else: - mergeRaises(tracked, effectList[exceptionEffects], n) - mergeTags(tracked, effectList[tagEffects], n) - gcsafeAndSideeffectCheck() - if a.kind != nkSym or a.sym.magic != mNBindSym: - for i in 1.. 0: - createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) - createTypeBoundOps(tracked, n[1].typ, n.info) - # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? + # check required for 'nim check': + if n[1].typ.len > 0: + createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) + createTypeBoundOps(tracked, n[1].typ, n.info) + # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? - elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and - optStaticBoundsCheck in tracked.currOptions: - checkBounds(tracked, n[1], n[2]) + elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and + optStaticBoundsCheck in tracked.currOptions: + checkBounds(tracked, n[1], n[2]) + + if a.kind != nkSym or a.sym.magic != mRunnableExamples: + for i in 0.. 0 and a.sym.name.s[0] == '=' and tracked.owner.kind != skMacro: var opKind = find(AttachedOpToStr, a.sym.name.s.normalize) - if a.sym.name.s.normalize == "=": opKind = attachedAsgn.int + if a.sym.name.s == "=": opKind = attachedAsgn.int if opKind != -1: # rebind type bounds operations after createTypeBoundOps call let t = n[1].typ.skipTypes({tyAlias, tyVar}) @@ -821,9 +824,6 @@ proc trackCall(tracked: PEffects; n: PNode) = if op != nil: n[0].sym = op - if a.kind != nkSym or a.sym.magic != mRunnableExamples: - for i in 0.. Date: Thu, 26 Nov 2020 13:44:06 +0000 Subject: [PATCH 1563/4254] More on #16110 (#16130) * fix #16110 * refs #16110 * fix comment * Trigger build * use shallowCopy for efficiency --- compiler/semstmts.nim | 13 +++++++++++-- tests/macros/tgetimpl.nim | 27 +++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 713867b76..d7f66208e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1278,8 +1278,17 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"), nextId c.idgen, getCurrOwner(c), s.info) - obj.ast = a.copyTree - obj.ast[0] = newSymNode(obj) + let symNode = newSymNode(obj) + obj.ast = a.shallowCopy + case a[0].kind + of nkSym: obj.ast[0] = symNode + of nkPragmaExpr: + obj.ast[0] = a[0].shallowCopy + obj.ast[0][0] = symNode + obj.ast[0][1] = a[0][1] + else: assert(false) + obj.ast[1] = a[1] + obj.ast[2] = a[2][0] if sfPure in s.flags: obj.flags.incl sfPure obj.typ = st.lastSon diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index de655561b..de132f253 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -71,15 +71,30 @@ assert: check_gen_proc(len(a)) == (false, true) macro check(x: type): untyped = let z = getType(x) - let y = getImpl(z[1]) - echo z.treeRepr + let y = getImpl(z[1]) + let sym = if y[0].kind == nnkSym: y[0] else: y[0][0] expectKind(z[1], nnkSym) - expectKind(y[0], nnkSym) - doAssert(y[0] == z[1]) + expectKind(sym, nnkSym) + expectKind(y[2], nnkObjectTy) + doAssert(sym == z[1]) type TirePtr = ptr object code: int -var z: TirePtr -check(typeof(z[])) \ No newline at end of file + TireRef* = ref object + code: int + + TireRef2* {.inheritable.} = ref object + code: int + + TireRef3* {.inheritable.} = object + code: int + +var z1: TirePtr +check(typeof(z1[])) +var z2: TireRef +check(typeof(z2[])) +var z3: TireRef2 +check(typeof(z3[])) +check(TireRef3) From cf516713d070277d1455a20a14de705a1513c0d7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 26 Nov 2020 19:05:21 +0100 Subject: [PATCH 1564/4254] fixes https://github.com/status-im/nimbus-eth2/issues/1549 (#16146) * fixes https://github.com/status-im/nimbus-eth2/issues/1549 [backport:1.4] * test fixup --- compiler/ccgcalls.nim | 14 ++++++++------ compiler/cgen.nim | 8 ++++++++ tests/ccgbugs/targ_lefttoright.nim | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 242e9f5cf..948f43ee1 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -249,13 +249,15 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = - if needsTmp and a.lode.typ != nil: - var tmp: TLoc - getTemp(p, a.lode.typ, tmp, needsInit=false) - genAssignment(p, tmp, a, {}) - tmp + # Bug https://github.com/status-im/nimbus-eth2/issues/1549 + # Aliasing is preferred over stack overflows. + # Also don't regress for non ARC-builds, too risky. + if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and + getSize(p.config, a.lode.typ) < 1024: + getTemp(p, a.lode.typ, result, needsInit=false) + genAssignment(p, result, a, {}) else: - a + result = a proc genArgStringToCString(p: BProc, n: PNode, needsTmp: bool): Rope {.inline.} = var a: TLoc diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c2a31b775..15b85097c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -471,6 +471,14 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = result.storage = OnStack result.flags = {} constructLoc(p, result, not needsInit) + when false: + # XXX Introduce a compiler switch in order to detect these easily. + if getSize(p.config, t) > 1024 * 1024: + if p.prc != nil: + echo "ENORMOUS TEMPORARY! ", p.config $ p.prc.info + else: + echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo + writeStackTrace() proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = inc(p.labels) diff --git a/tests/ccgbugs/targ_lefttoright.nim b/tests/ccgbugs/targ_lefttoright.nim index b107b2327..a49b87739 100644 --- a/tests/ccgbugs/targ_lefttoright.nim +++ b/tests/ccgbugs/targ_lefttoright.nim @@ -16,6 +16,7 @@ discard """ 2,2 1,2 ''' + cmd: "nim c --gc:orc $file" """ template test = From 4fdaded227070c651c4eb6a2517041a195617e64 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 26 Nov 2020 20:00:31 +0100 Subject: [PATCH 1565/4254] updated repr tests (#16147) --- tests/ccgbugs/tmissingderef.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim index 26418800a..eb7da3023 100644 --- a/tests/ccgbugs/tmissingderef.nim +++ b/tests/ccgbugs/tmissingderef.nim @@ -1,6 +1,5 @@ discard """ output: '''[10, 0, 0, 0, 0, 0, 0, 0] - 255 1 1 0.5''' From 70a1c4254230eb8f3c4d24ccbc253c0a28065d03 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 27 Nov 2020 03:30:19 +0800 Subject: [PATCH 1566/4254] add `**` to jsffi (#16141) * fix rope index * add testcase * fix ropes format * add `**` to jsffi * add testcase * changelog Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/js/jsffi.nim | 1 + tests/js/tjsffi.nim | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index bfbe59e1a..ba1bc9438 100644 --- a/changelog.md +++ b/changelog.md @@ -47,6 +47,7 @@ - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. +- Added `**` to jsffi. - `writeStackTrace` is available in JS backend now. ## Language changes diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 0dce6f3b9..eedf45bb0 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -180,6 +180,7 @@ proc `>` *(x, y: JsObject): JsObject {.importcpp: "(# > #)".} proc `<` *(x, y: JsObject): JsObject {.importcpp: "(# < #)".} proc `>=` *(x, y: JsObject): JsObject {.importcpp: "(# >= #)".} proc `<=` *(x, y: JsObject): JsObject {.importcpp: "(# <= #)".} +proc `**` *(x, y: JsObject): JsObject {.importcpp: "((#) ** #)".} proc `and`*(x, y: JsObject): JsObject {.importcpp: "(# && #)".} proc `or` *(x, y: JsObject): JsObject {.importcpp: "(# || #)".} proc `not`*(x: JsObject): JsObject {.importcpp: "(!#)".} diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim index af33cee8a..143ac4a25 100644 --- a/tests/js/tjsffi.nim +++ b/tests/js/tjsffi.nim @@ -323,7 +323,6 @@ block: console.log jsarguments[0] block: - echo jsUndefined == jsNull echo jsUndefined == nil echo jsNull == nil @@ -331,3 +330,36 @@ block: echo jsNull.isNil echo jsNull.isNull echo jsUndefined.isUndefined + +block: # test ** + var a = toJs(0) + var b = toJs(0) + doAssert to(a ** b, int) == 1 + a = toJs(1) + b = toJs(1) + doAssert to(a ** b, int) == 1 + a = toJs(-1) + b = toJs(-1) + doAssert to(a ** b, int) == -1 + a = toJs(6) + b = toJs(6) + doAssert to(a ** b, int) == 46656 + a = toJs(5.5) + b = toJs(3) + doAssert to(a ** b, float) == 166.375 + a = toJs(5) + b = toJs(3.0) + doAssert to(a ** b, float) == 125.0 + a = toJs(7.0) + b = toJS(6.0) + doAssert to(a ** b, float) == 117649.0 + a = toJs(8) + b = toJS(-2) + doAssert to(a ** b, float) == 0.015625 + + a = toJs(1) + b = toJs(1) + doAssert to(`**`(a + a, b), int) == 2 + + doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4 + From 13b1b19a83000743df3c844a34652e7ad0d308f5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 26 Nov 2020 11:54:18 -0800 Subject: [PATCH 1567/4254] remove all mentions of doc2, jsondoc2 (except 1 mentioning the alias) (#15683) --- compiler/options.nim | 2 +- compiler/typesrenderer.nim | 2 +- doc/advopt.txt | 4 ++-- doc/docgen.rst | 8 ++++---- doc/docstyle.rst | 2 +- doc/nimc.rst | 2 +- doc/tut2.rst | 2 +- tools/kochdocs.nim | 2 +- tools/nimweb.nim | 6 +++--- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 58d09938c..9fce5f830 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -77,7 +77,7 @@ type # please make sure we have under 32 options optIdeTerse # idetools: use terse descriptions optExcessiveStackTrace # fully qualified module filenames optShowAllMismatches # show all overloading resolution candidates - optWholeProject # for 'doc2': output any dependency + optWholeProject # for 'doc': output any dependency optDocInternal # generate documentation for non-exported symbols optMixedMode # true if some module triggered C++ codegen optListFullPaths # use full paths in toMsgFilename diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 613173252..0da05d70d 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -90,7 +90,7 @@ proc renderParamTypes(found: var seq[string], n: PNode) = ## Recursive helper, adds to `found` any types, or keeps diving the AST. ## ## The normal `doc` generator doesn't include .typ information, so the - ## function won't render types for parameters with default values. The `doc2` + ## function won't render types for parameters with default values. The `doc` ## generator does include the information. case n.kind of nkFormalParams: diff --git a/doc/advopt.txt b/doc/advopt.txt index 1fc0c946e..d87b00f91 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -73,7 +73,7 @@ Advanced options: --clibdir:DIR modify the linker library search path --clib:LIBNAME link an additional C library (you should omit platform-specific extensions) - --project document the whole project (doc2) + --project document the whole project (doc) --docRoot:path `nim doc --docRoot:/foo --project --outdir:docs /foo/sub/main.nim` generates: docs/sub/main.html if path == @pkg, will use nimble file enclosing dir @@ -85,7 +85,7 @@ Advanced options: --docCmd:cmd if `cmd == skip`, skips runnableExamples else, runs runnableExamples with given options, e.g.: `--docCmd:"-d:foo --threads:on"` - --docSeeSrcUrl:url activate 'see source' for doc and doc2 commands + --docSeeSrcUrl:url activate 'see source' for doc command (see doc.item.seesrc in config/nimdoc.cfg) --docInternal also generate documentation for non-exported symbols --lineDir:on|off generation of #line directive on|off diff --git a/doc/docgen.rst b/doc/docgen.rst index 07218982c..612465671 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -193,7 +193,7 @@ Index switch ------------ :: - nim doc2 --index:on filename.nim + nim doc --index:on filename.nim This will generate an index of all the exported symbols in the input Nim module, and put it into a neighboring file with the extension of ``.idx``. The @@ -210,7 +210,7 @@ See source switch ----------------- :: - nim doc2 --git.url: filename.nim + nim doc --git.url: filename.nim With the ``git.url`` switch the *See source* hyperlink will appear below each documented item in your source code pointing to the implementation of that @@ -262,8 +262,8 @@ HTML anchor generation When you run the ``rst2html`` command, all sections in the RST document will get an anchor you can hyperlink to. Usually, you can guess the anchor lower casing the section title and replacing spaces with dashes, and in any case, you -can get it from the table of contents. But when you run the ``doc`` or ``doc2`` -commands to generate API documentation, some symbol get one or two anchors at +can get it from the table of contents. But when you run the ``doc`` +command to generate API documentation, some symbol get one or two anchors at the same time: a numerical identifier, or a plain name plus a complex name. The numerical identifier is just a random number. The number gets assigned diff --git a/doc/docstyle.rst b/doc/docstyle.rst index 9a983097b..50ff81ac3 100644 --- a/doc/docstyle.rst +++ b/doc/docstyle.rst @@ -78,7 +78,7 @@ Whenever an example of usage would be helpful to the user, you should include on doAssert addThree(3, 125, 6) == -122 result = x +% y +% z -The commands ``nim doc`` and ``nim doc2`` will then correctly syntax highlight the Nim code within the documentation. +The command ``nim doc`` will then correctly syntax highlight the Nim code within the documentation. Types ----- diff --git a/doc/nimc.rst b/doc/nimc.rst index 57255a31f..f92e40617 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -516,7 +516,7 @@ can be read in the `Nim Backend Integration document `_. Nim documentation tools ======================= -Nim provides the `doc`:idx: and `doc2`:idx: commands to generate HTML +Nim provides the `doc`:idx: command to generate HTML documentation from ``.nim`` source files. Only exported symbols will appear in the output. For more details `see the docgen documentation `_. diff --git a/doc/tut2.rst b/doc/tut2.rst index 32faf452c..e3b00555d 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -457,7 +457,7 @@ If you want to add the ``{.raises.}`` pragma to existing code, the compiler can also help you. You can add the ``{.effects.}`` pragma statement to your proc and the compiler will output all inferred effects up to that point (exception tracking is part of Nim's effect system). Another more roundabout way to -find out the list of exceptions raised by a proc is to use the Nim ``doc2`` +find out the list of exceptions raised by a proc is to use the Nim ``doc`` command which generates documentation for a whole module and decorates all procs with the list of raised exceptions. You can read more about Nim's `effect system and related pragmas in the manual `_. diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 81ab265f2..0cfedce47 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -265,7 +265,7 @@ proc buildDoc(nimArgs, destPath: string) = [extra, nimArgs2, gitUrl, destPath, d] i.inc for d in items(withoutIndex): - commands[i] = nim & " doc2 $# --git.url:$# -o:$# $#" % + commands[i] = nim & " doc $# --git.url:$# -o:$# $#" % [nimArgs, gitUrl, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 10319be87..f71b5f3be 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -326,7 +326,7 @@ proc buildDoc(c: var TConfigData, destPath: string) = destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(c.srcdoc2): - commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# --index:on $#" % + commands[i] = findNim(c) & " doc $# --git.url:$# -o:$# --index:on $#" % [c.nimArgs, c.gitURL, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc @@ -361,7 +361,7 @@ proc buildAddDoc(c: var TConfigData, destPath: string) = # build additional documentation (without the index): var commands = newSeq[string](c.webdoc.len) for i, doc in pairs(c.webdoc): - commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# $#" % + commands[i] = findNim(c) & " doc $# --git.url:$# -o:$# $#" % [c.nimArgs, c.gitURL, destPath / changeFileExt(splitFile(doc).name, "html"), doc] mexec(commands, c.numProcessors) @@ -537,7 +537,7 @@ proc json2(c: var TConfigData) = var i = 0 for d in items(c.srcdoc2): createDir(destPath / splitFile(d).dir) - commands[i] = findNim(c) & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" % + commands[i] = findNim(c) & " jsondoc $# --git.url:$# -o:$# --index:on $#" % [c.nimArgs, c.gitURL, destPath / changeFileExt(d, "json"), d] i.inc From 9f1c5f64c5a9a3de5f4f39040b3df484de649ef2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 26 Nov 2020 23:16:43 +0100 Subject: [PATCH 1568/4254] fixes #16119 [backport:1.4] (#16149) --- compiler/semstmts.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d7f66208e..d3d8c0fb8 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -477,7 +477,7 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if n.len == 1: result = semLowerLetVarCustomPragma(c, n[0], n) - if result!=nil: return result + if result != nil: return result var b: PNode result = copyNode(n) @@ -513,7 +513,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = def = fitNode(c, typ, def, def.info) #changeType(def.skipConv, typ, check=true) else: - typ = def.typ.skipTypes({tyStatic}).skipIntLit(c.idgen) + typ = def.typ.skipTypes({tyStatic, tySink}).skipIntLit(c.idgen) if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): @@ -1282,7 +1282,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = obj.ast = a.shallowCopy case a[0].kind of nkSym: obj.ast[0] = symNode - of nkPragmaExpr: + of nkPragmaExpr: obj.ast[0] = a[0].shallowCopy obj.ast[0][0] = symNode obj.ast[0][1] = a[0][1] From 52829fc8d1324c8192bc1674ff47e504648675fa Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 26 Nov 2020 15:55:56 -0800 Subject: [PATCH 1569/4254] cmdline: improve command processing (#16056) --- compiler/ast.nim | 2 +- compiler/cgen.nim | 2 +- compiler/cmdlinehelper.nim | 16 ++---- compiler/commands.nim | 57 ++++++++++++++++++---- compiler/lookups.nim | 2 +- compiler/main.nim | 99 +++++++++++++------------------------- compiler/nim.nim | 8 +-- compiler/nimconf.nim | 2 +- compiler/nimeval.nim | 4 +- compiler/nimfix/nimfix.nim | 2 +- compiler/options.nim | 64 +++++++++++++----------- compiler/pragmas.nim | 2 +- compiler/scriptconfig.nim | 3 +- compiler/semexprs.nim | 4 +- compiler/semtypes.nim | 2 +- drnim/drnim.nim | 6 +-- nimsuggest/nimsuggest.nim | 4 +- tools/nimfind.nim | 2 +- 18 files changed, 144 insertions(+), 137 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 2e710fd21..fbad9e44e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -765,7 +765,7 @@ type locOther # location is something other TLocFlag* = enum lfIndirect, # backend introduced a pointer - lfFullExternalName, # only used when 'conf.cmd == cmdPretty': Indicates + lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates # that the symbol has been imported via 'importc: "fullname"' and # no format string. lfNoDeepCopy, # no need for a deep copy diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 15b85097c..a3d3425e3 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1986,7 +1986,7 @@ proc writeModule(m: BModule, pending: bool) = var code = genModule(m, cf) if code != nil or m.config.symbolFiles != disabledSf: when hasTinyCBackend: - if m.config.cmd == cmdRun: + if m.config.cmd == cmdTcc: tccgen.compileCCode($code, m.config) onExit() return diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index 4f1ede5d1..c6a0f200a 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -13,8 +13,6 @@ import options, idents, nimconf, extccomp, commands, msgs, lineinfos, modulegraphs, condsyms, os, pathutils, parseopt -from strutils import normalize - proc prependCurDir*(f: AbsoluteFile): AbsoluteFile = when defined(unix): if os.isAbsolute(f.string): result = f @@ -60,8 +58,8 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: ConfigRef; graph: ModuleGraph): bool = if self.suggestMode: - conf.command = "nimsuggest" - if conf.command == "e": + conf.setCmd cmdIdeTools + if conf.cmd == cmdNimscript: incl(conf.globalOptions, optWasNimscript) loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files @@ -69,17 +67,13 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi let scriptFile = conf.projectFull.changeFileExt("nims") # 'nim foo.nims' means to just run the NimScript file and do nothing more: if fileExists(scriptFile) and scriptFile == conf.projectFull: - if conf.command == "": - conf.command = "e" - return false - elif conf.command.normalize == "e": - return false - + if conf.cmd == cmdNone: conf.setCmd cmdNimscript + if conf.cmd == cmdNimscript: return false # now process command line arguments again, because some options in the # command line can overwrite the config file's settings extccomp.initVars(conf) self.processCmdLine(passCmd2, "", conf) - if conf.command == "": + if conf.cmd == cmdNone: rawMessage(conf, errGenerated, "command missing") graph.suggestMode = self.suggestMode diff --git a/compiler/commands.nim b/compiler/commands.nim index 1ad5ec64c..916dfd66b 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -398,6 +398,48 @@ proc handleCmdInput*(conf: ConfigRef) = conf.projectName = "cmdfile" handleStdinOrCmdInput() +proc parseCommand*(command: string): Command = + case command.normalize + of "c", "cc", "compile", "compiletoc": cmdCompileToC + of "cpp", "compiletocpp": cmdCompileToCpp + of "objc", "compiletooc": cmdCompileToOC + of "js", "compiletojs": cmdCompileToJS + of "r": cmdCrun + of "run": cmdTcc + of "check": cmdCheck + of "e": cmdNimscript + of "doc0": cmdDoc0 + of "doc2", "doc": cmdDoc2 + of "rst2html": cmdRst2html + of "rst2tex": cmdRst2tex + of "jsondoc0": cmdJsondoc0 + of "jsondoc2", "jsondoc": cmdJsondoc + of "ctags": cmdCtags + of "buildindex": cmdBuildindex + of "gendepend": cmdGendepend + of "dump": cmdDump + of "parse": cmdParse + of "scan": cmdScan + of "secret": cmdInteractive + of "nop", "help": cmdNop + of "jsonscript": cmdJsonscript + else: cmdUnknown + +proc setCmd*(conf: ConfigRef, cmd: Command) = + ## sets cmd, backend so subsequent flags can query it (e.g. so --gc:arc can be ignored for backendJs) + # Note that `--backend` can override the backend, so the logic here must remain reversible. + conf.cmd = cmd + case cmd + of cmdCompileToC, cmdCrun, cmdTcc: conf.backend = backendC + of cmdCompileToCpp: conf.backend = backendCpp + of cmdCompileToOC: conf.backend = backendObjc + of cmdCompileToJS: conf.backend = backendJs + else: discard + +proc setCommandEarly*(conf: ConfigRef, command: string) = + conf.command = command + setCmd(conf, command.parseCommand) + proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = var @@ -407,8 +449,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectArg(conf, switch, arg, pass, info) conf.projectIsCmd = true conf.cmdInput = arg # can be empty (a nim file with empty content is valid too) - if conf.command == "": - conf.command = "e" # better than "r" as a default + if conf.cmd == cmdNone: + conf.setCmd cmdNimscript # better than `cmdCrun` as a default conf.implicitCmd = true of "path", "p": expectArg(conf, switch, arg, pass, info) @@ -499,11 +541,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "project": processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) of "gc": - if conf.backend == backendJs or conf.command == "js": - # for: bug #16033 - # This might still be imperfect, in rarse corner cases - # (where command is reset in nimscript, maybe). - return + if conf.backend == backendJs: return # for: bug #16033 expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: case arg.normalize @@ -955,13 +993,12 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endsWith(".nims"): - config.command = "e" + config.setCmd cmdNimscript incl(config.globalOptions, optWasNimscript) config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true - elif pass != passCmd2: - config.command = p.key + elif pass != passCmd2: setCommandEarly(config, p.key) else: if pass == passCmd1: config.commandArgs.add p.key if argsCount == 1: diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 9225706b5..0c624425d 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -85,7 +85,7 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym = result = s else: result = s.owner - if conf.cmd == cmdPretty: + if conf.cmd == cmdNimfix: prettybase.replaceDeprecated(conf, n.info, s, result) else: message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " & diff --git a/compiler/main.nim b/compiler/main.nim index f9b0dd413..6bdbb9efd 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -87,7 +87,7 @@ proc commandCompileToC(graph: ModuleGraph) = if graph.config.errorCounter > 0: return # issue #9933 cgenWriteModules(graph.backend, conf) - if conf.cmd != cmdRun: + if conf.cmd != cmdTcc: extccomp.callCCompiler(conf) # for now we do not support writing out a .json file with the build instructions when HCR is on if not conf.hcrOn: @@ -195,12 +195,8 @@ proc mainCommand*(graph: ModuleGraph) = if conf.selectedGC in {gcArc, gcOrc} and conf.backend != backendCpp: conf.exc = excGoto - var commandAlreadyProcessed = false - - proc compileToBackend(backend: TBackend, cmd = cmdCompileToBackend) = - commandAlreadyProcessed = true - conf.cmd = cmd - customizeForBackend(backend) + proc compileToBackend() = + customizeForBackend(conf.backend) case conf.backend of backendC: commandCompileToC(graph) of backendCpp: commandCompileToC(graph) @@ -213,18 +209,13 @@ proc mainCommand*(graph: ModuleGraph) = quit "compiler wasn't built with documentation generator" else: wantMainModule(conf) - conf.cmd = cmdDoc loadConfigs(DocConfig, cache, conf, graph.idgen) defineSymbol(conf.symbols, "nimdoc") body block: ## command prepass - var docLikeCmd2 = false # includes what calls `docLikeCmd` + some more - case conf.command.normalize - of "r": conf.globalOptions.incl {optRun, optUseNimcache} - of "doc0", "doc2", "doc", "rst2html", "rst2tex", "jsondoc0", "jsondoc2", - "jsondoc", "ctags", "buildindex": docLikeCmd2 = true - else: discard + if conf.cmd == cmdCrun: conf.globalOptions.incl {optRun, optUseNimcache} + if conf.cmd notin cmdBackends + {cmdTcc}: customizeForBackend(backendC) if conf.outDir.isEmpty: # doc like commands can generate a lot of files (especially with --project) # so by default should not end up in $PWD nor in $projectPath. @@ -232,30 +223,22 @@ proc mainCommand*(graph: ModuleGraph) = var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) else: conf.projectPath doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee - if docLikeCmd2: ret = ret / htmldocsDir + if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex}: ret = ret / htmldocsDir ret - ## process all backend commands - case conf.command.normalize - of "c", "cc", "compile", "compiletoc": compileToBackend(backendC) # compile means compileToC currently - of "cpp", "compiletocpp": compileToBackend(backendCpp) - of "objc", "compiletooc": compileToBackend(backendObjc) - of "js", "compiletojs": compileToBackend(backendJs) - of "r": compileToBackend(backendC) # different from `"run"`! - of "run": + ## process all commands + case conf.cmd + of cmdBackends: compileToBackend() + of cmdTcc: when hasTinyCBackend: extccomp.setCC(conf, "tcc", unknownLineInfo) - if conf.backend notin {backendC, backendInvalid}: + if conf.backend != backendC: rawMessage(conf, errGenerated, "'run' requires c backend, got: '$1'" % $conf.backend) - compileToBackend(backendC, cmd = cmdRun) + compileToBackend() else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") - else: customizeForBackend(backendC) # fallback for other commands - - ## process all other commands - case conf.command.normalize # synchronize with `cmdUsingHtmlDocs` - of "doc0": docLikeCmd commandDoc(cache, conf) - of "doc2", "doc": + of cmdDoc0: docLikeCmd commandDoc(cache, conf) + of cmdDoc2: docLikeCmd(): conf.setNoteDefaults(warnLockLevel, false) # issue #13218 conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 @@ -266,30 +249,25 @@ proc mainCommand*(graph: ModuleGraph) = commandDoc2(graph, false) if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions: commandBuildIndex(conf, $conf.outDir) - of "rst2html": + of cmdRst2html: conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218 when defined(leanCompiler): quit "compiler wasn't built with documentation generator" else: - conf.cmd = cmdRst2html loadConfigs(DocConfig, cache, conf, graph.idgen) commandRst2Html(cache, conf) - of "rst2tex": + of cmdRst2tex: when defined(leanCompiler): quit "compiler wasn't built with documentation generator" else: - conf.cmd = cmdRst2tex loadConfigs(DocTexConfig, cache, conf, graph.idgen) commandRst2TeX(cache, conf) - of "jsondoc0": docLikeCmd commandJson(cache, conf) - of "jsondoc2", "jsondoc": docLikeCmd commandDoc2(graph, true) - of "ctags": docLikeCmd commandTags(cache, conf) - of "buildindex": docLikeCmd commandBuildIndex(conf, $conf.projectFull, conf.outFile) - of "gendepend": - conf.cmd = cmdGenDepend - commandGenDepend(graph) - of "dump": - conf.cmd = cmdDump + of cmdJsondoc0: docLikeCmd commandJson(cache, conf) + of cmdJsondoc: docLikeCmd commandDoc2(graph, true) + of cmdCtags: docLikeCmd commandTags(cache, conf) + of cmdBuildindex: docLikeCmd commandBuildIndex(conf, $conf.projectFull, conf.outFile) + of cmdGendepend: commandGenDepend(graph) + of cmdDump: if getConfigVar(conf, "dump.format") == "json": wantMainModule(conf) @@ -332,41 +310,30 @@ proc mainCommand*(graph: ModuleGraph) = msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook}) for it in conf.searchPaths: msgWriteln(conf, it.string) - of "check": - conf.cmd = cmdCheck - commandCheck(graph) - of "parse": - conf.cmd = cmdParse + of cmdCheck: commandCheck(graph) + of cmdParse: wantMainModule(conf) discard parseFile(conf.projectMainIdx, cache, conf) - of "scan": - conf.cmd = cmdScan + of cmdScan: wantMainModule(conf) commandScan(cache, conf) msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") - of "secret": - conf.cmd = cmdInteractive - commandInteractive(graph) - of "e": + of cmdInteractive: commandInteractive(graph) + of cmdNimscript: if conf.projectIsCmd or conf.projectIsStdin: discard elif not fileExists(conf.projectFull): rawMessage(conf, errGenerated, "NimScript file does not exist: " & conf.projectFull.string) elif not conf.projectFull.string.endsWith(".nims"): rawMessage(conf, errGenerated, "not a NimScript file: " & conf.projectFull.string) # main NimScript logic handled in `loadConfigs`. - of "nop", "help": - # prevent the "success" message: - conf.cmd = cmdDump - of "jsonscript": - conf.cmd = cmdJsonScript + of cmdNop: discard + of cmdJsonscript: setOutFile(graph.config) commandJsonScript(graph) - elif commandAlreadyProcessed: discard # already handled - else: + of cmdUnknown, cmdNone, cmdIdeTools, cmdNimfix: rawMessage(conf, errGenerated, "invalid command: " & conf.command) - if conf.errorCounter == 0 and - conf.cmd notin {cmdInterpret, cmdRun, cmdDump}: + if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}: let mem = when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" else: formatSize(getTotalMem()) & " totmem" @@ -378,9 +345,9 @@ proc mainCommand*(graph: ModuleGraph) = let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName var output: string - if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonScript: + if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonscript: output = $conf.jsonBuildFile - elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonScript, cmdCompileToBackend, cmdDoc}: + elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonscript} + cmdDocLike + cmdBackends: # for some cmd we expect a valid absOutFile output = "unknownOutput" else: diff --git a/compiler/nim.nim b/compiler/nim.nim index e3725f803..46654e352 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -64,7 +64,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = if processArgument(pass, p, argsCount, config): break if pass == passCmd2: if {optRun, optWasNimscript} * config.globalOptions == {} and - config.arguments.len > 0 and config.command.normalize notin ["run", "e", "r"]: + config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}: rawMessage(config, errGenerated, errArgsNeedRunOption) proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = @@ -86,19 +86,19 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = #echo(GC_getStatistics()) if conf.errorCounter != 0: return when hasTinyCBackend: - if conf.cmd == cmdRun: + if conf.cmd == cmdTcc: tccgen.run(conf, conf.arguments) if optRun in conf.globalOptions: let output = conf.absOutFile case conf.cmd - of cmdCompileToBackend: + of cmdBackends, cmdTcc: var cmdPrefix = "" case conf.backend of backendC, backendCpp, backendObjc: discard of backendJs: cmdPrefix = findNodeJs() & " " else: doAssert false, $conf.backend execExternalProgram(conf, cmdPrefix & output.quoteShell & ' ' & conf.arguments) - of cmdDoc, cmdRst2html: + of cmdDocLike, cmdRst2html, cmdRst2tex: # bugfix(cmdRst2tex was missing) if conf.arguments.len > 0: # reserved for future use rawMessage(conf, errGenerated, "'$1 cannot handle arguments" % [$conf.cmd]) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index b6ec1bbc8..01a79c1e3 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -301,7 +301,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: if scriptIsProj: showHintConf() configFiles.setLen 0 - if conf.command != "nimsuggest": + if conf.cmd != cmdIdeTools: runNimScriptIfExists(scriptFile, isMain = true) else: if not scriptIsProj: diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 3ffe347c2..b93129852 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -10,7 +10,7 @@ ## exposes the Nim VM to clients. import ast, astalgo, modules, passes, condsyms, - options, sem, semdata, llstream, lineinfos, vm, + options, sem, llstream, lineinfos, vm, vmdef, modulegraphs, idents, os, pathutils, passaux, scriptconfig @@ -153,7 +153,7 @@ proc runRepl*(r: TLLRepl; conf.searchPaths.add(AbsoluteDir p) if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p - conf.cmd = cmdInteractive + conf.cmd = cmdInteractive # see also `setCmd` conf.setErrorMaxHighMaybe initDefines(conf.symbols) defineSymbol(conf.symbols, "nimscript") diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 96007477f..4d93279c9 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -38,7 +38,7 @@ In addition, all command line options of Nim are supported. proc mainCommand = registerPass verbosePass registerPass semPass - conf.cmd = cmdPretty + conf.setCmd cmdNimfix searchPaths.add options.libpath if gProjectFull.len != 0: # current path is always looked first for modules diff --git a/compiler/options.nim b/compiler/options.nim index 9fce5f830..42a907777 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -47,7 +47,7 @@ type # please make sure we have under 32 options TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** gloptNone, optForceFullMake, - optWasNimscript, + optWasNimscript, # redundant with `cmdNimscript`, could be removed optListCmd, optCompileOnly, optNoLinking, optCDebug, # turn on debugging information optGenDynLib, # generate a dynamic library @@ -110,34 +110,44 @@ type TBackend* = enum backendInvalid = "" # for parseEnum backendC = "c" - backendCpp = "cpp" # was cmdCompileToCpp - backendJs = "js" # was cmdCompileToJS - backendObjc = "objc" # was cmdCompileToOC + backendCpp = "cpp" + backendJs = "js" + backendObjc = "objc" # backendNimscript = "nimscript" # this could actually work # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM + Command* = enum ## Nim's commands + cmdNone # not yet processed command + cmdUnknown # command unmapped + cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS + cmdCrun # compile and run in nimache + cmdTcc # run the project via TCC backend + cmdCheck # semantic checking for whole project + cmdParse # parse a single file (for debugging) + cmdScan # scan a single file (for debugging) + cmdIdeTools # ide tools (e.g. nimsuggest) + cmdNimscript # evaluate nimscript + cmdDoc0 + cmdDoc2 + cmdRst2html # convert a reStructuredText file to HTML + cmdRst2tex # convert a reStructuredText file to TeX + cmdJsondoc0 + cmdJsondoc + cmdCtags + cmdBuildindex + cmdGendepend + cmdDump + cmdInteractive # start interactive session + cmdNop + cmdJsonscript # compile a .json build file + cmdNimfix + # old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs) + +const + cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCrun} + cmdDocLike* = {cmdDoc0, cmdDoc2, cmdJsondoc0, cmdJsondoc, cmdCtags, cmdBuildindex} + type - TCommands* = enum # Nim's commands - # **keep binary compatible** - cmdNone, - cmdCompileToC, # deadcode - cmdCompileToCpp, # deadcode - cmdCompileToOC, # deadcode - cmdCompileToJS, # deadcode - cmdCompileToLLVM, # deadcode - cmdInterpret, cmdPretty, cmdDoc, - cmdGenDepend, cmdDump, - cmdCheck, # semantic checking for whole project - cmdParse, # parse a single file (for debugging) - cmdScan, # scan a single file (for debugging) - cmdIdeTools, # ide tools - cmdDef, # def feature (find definition for IDEs) - cmdRst2html, # convert a reStructuredText file to HTML - cmdRst2tex, # convert a reStructuredText file to TeX - cmdInteractive, # start interactive session - cmdRun, # run the project via TCC backend - cmdJsonScript # compile a .json build file - cmdCompileToBackend, # compile to backend in TBackend TStringSeq* = seq[string] TGCMode* = enum # the selected GC gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc, @@ -245,7 +255,7 @@ type evalTemplateCounter*: int evalMacroCounter*: int exitcode*: int8 - cmd*: TCommands # the command + cmd*: Command # raw command parsed as enum cmdInput*: string # input command projectIsCmd*: bool # whether we're compiling from a command input implicitCmd*: bool # whether some flag triggered an implicit `command` @@ -531,7 +541,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osDragonfly, osMacosx} else: discard -proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools} +proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd notin cmdDocLike + {cmdIdeTools} proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc template compilationCachePresent*(conf: ConfigRef): untyped = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1ec0aa112..5ee3dc414 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -155,7 +155,7 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) = localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") when hasFFI: s.cname = $s.loc.r - if c.config.cmd == cmdPretty and '$' notin extname: + if c.config.cmd == cmdNimfix and '$' notin extname: # note that '{.importc.}' is transformed into '{.importc: "$1".}' s.loc.flags.incl(lfFullExternalName) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index a353278d6..ef1ceb12b 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -150,7 +150,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbconf cmpIgnoreCase: setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1)) cbconf setCommand: - conf.command = a.getString 0 + conf.setCommandEarly(a.getString 0) + # xxx move remaining logic to commands.nim or other let arg = a.getString 1 incl(conf.globalOptions, optWasNimscript) if arg.len > 0: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 608a82715..8728af27c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2280,7 +2280,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = magicsAfterOverloadResolution(c, result, flags) of mRunnableExamples: markUsed(c, n.info, s) - if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: + if c.config.cmd in cmdDocLike and n.len >= 2 and n.lastSon.kind == nkStmtList: when false: # some of this dead code was moved to `prepareExamples` if sfMainModule in c.module.flags: @@ -2724,7 +2724,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = let mode = if nfDotField in n.flags: {} else: {checkUndeclared} var s = qualifiedLookUp(c, n[0], mode) if s != nil: - #if c.config.cmd == cmdPretty and n[0].kind == nkDotExpr: + #if c.config.cmd == cmdNimfix and n[0].kind == nkDotExpr: # pretty.checkUse(n[0][1].info, s) case s.kind of skMacro, skTemplate: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 0ec7140e0..a9d00d2ee 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -134,7 +134,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e.position = int(counter) let symNode = newSymNode(e) if optNimV1Emulation notin c.config.globalOptions and identToReplace != nil and - c.config.cmd != cmdDoc: # A hack to produce documentation for enum fields. + c.config.cmd notin cmdDocLike: # A hack to produce documentation for enum fields. identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: diff --git a/drnim/drnim.nim b/drnim/drnim.nim index d68175c83..f2a20fa62 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1223,9 +1223,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var argsCount = 1 config.commandLine.setLen 0 - config.command = "check" - config.cmd = cmdCheck - + config.setCmd cmdCheck while true: parseopt.next(p) case p.kind @@ -1253,7 +1251,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = if processArgument(pass, p, argsCount, config): break if pass == passCmd2: if {optRun, optWasNimscript} * config.globalOptions == {} and - config.arguments.len > 0 and config.command.normalize notin ["run", "e"]: + config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript}: rawMessage(config, errGenerated, errArgsNeedRunOption) proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index d438e663c..2e28a09ee 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -517,7 +517,7 @@ proc mainCommand(graph: ModuleGraph) = clearPasses(graph) registerPass graph, verbosePass registerPass graph, semPass - conf.cmd = cmdIdeTools + conf.setCmd cmdIdeTools wantMainModule(conf) if not fileExists(conf.projectFull): @@ -666,7 +666,7 @@ else: clearPasses(graph) registerPass graph, verbosePass registerPass graph, semPass - conf.cmd = cmdIdeTools + conf.setCmd cmdIdeTools wantMainModule(conf) if not fileExists(conf.projectFull): diff --git a/tools/nimfind.nim b/tools/nimfind.nim index b120ccd1f..9c8247606 100644 --- a/tools/nimfind.nim +++ b/tools/nimfind.nim @@ -158,7 +158,7 @@ proc mainCommand(graph: ModuleGraph) = clearPasses(graph) registerPass graph, verbosePass registerPass graph, semPass - conf.cmd = cmdIdeTools + conf.setCmd cmdIdeTools wantMainModule(conf) setupDb(graph, dbfile) From c0215d8d0dcefaf963f6138e4fcf48dee8ef0199 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 27 Nov 2020 10:53:30 +0800 Subject: [PATCH 1570/4254] clean up changelog (#16155) * fix rope index * add testcase * fix ropes format * add `**` to jsffi * add testcase * changelog * clean up changelog Co-authored-by: Andreas Rumpf --- changelog.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index ba1bc9438..d62e96bbe 100644 --- a/changelog.md +++ b/changelog.md @@ -31,12 +31,12 @@ - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). -- nodejs now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv` +- `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. - `doAssertRaises` now correctly handles foreign exceptions. - Added `asyncdispatch.activeDescriptors` that returns the number of currently - active async event handles/file descriptors + active async event handles/file descriptors. - ``--gc:orc`` is now 10% faster than previously for common workloads. If you have trouble with its changed behavior, compile with ``-d:nimOldOrc``. @@ -44,15 +44,17 @@ - `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, determining preferred I/O block size for this file object. + - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. - Added `**` to jsffi. + - `writeStackTrace` is available in JS backend now. ## Language changes -- `nimscript` now handles `except Exception as e` +- `nimscript` now handles `except Exception as e`. - The `cstring` doesn't support `[]=` operator in JS backend. From 6b77e16c6f86e5c05795fe881a25be3d17e9c22a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 27 Nov 2020 12:41:22 +0800 Subject: [PATCH 1571/4254] tunidecode minor improvement (#16157) --- tests/stdlib/tunidecode.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim index 7784fffb4..be8e0523c 100644 --- a/tests/stdlib/tunidecode.nim +++ b/tests/stdlib/tunidecode.nim @@ -1,6 +1,5 @@ discard """ cmd: "nim $target --hints:on -d:embedUnidecodeTable $options $file" - output: "Ausserst" """ import unidecode @@ -9,5 +8,5 @@ import std/unidecode # #14112 loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") -# assert unidecode("\x53\x17\x4E\xB0") == "Bei Jing" -echo unidecode("Äußerst") +doAssert unidecode("北京") == "Bei Jing " +doAssert unidecode("Äußerst") == "Ausserst" From 3510216c8afeee36e2997bd0f20a2b5f3c70a260 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 27 Nov 2020 18:57:16 +0800 Subject: [PATCH 1572/4254] add testcase (#16156) --- tests/statictypes/tstatictypes.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index fe1d1c8ca..f3a0f0fcb 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -357,3 +357,12 @@ proc fn(N1: static int, N2: static int, T: typedesc): array[N1 * N2, T] = doAssert(len(result) == N1 * N2) let yy = fn(5, 10, float) + + +block: + block: + type Foo[N: static int] = array[cint(0) .. cint(N), float] + type T = Foo[3] + block: + type Foo[N: static int] = array[int32(0) .. int32(N), float] + type T = Foo[3] From c9a10bb9e47c5227b32f49f5876e965cc2308541 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 27 Nov 2020 15:26:57 +0100 Subject: [PATCH 1573/4254] fixes #16154; underlying system.add for seq is the real cause; will be addressed in a follow-up PR (#16161) --- lib/pure/asyncdispatch.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 90345676f..e111f9e7d 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1199,9 +1199,10 @@ else: not p.selector.isEmpty() or p.timers.len != 0 or p.callbacks.len != 0 proc prependSeq(dest: var seq[Callback]; src: sink seq[Callback]) = - let old = move dest + var old = move dest dest = src - dest.add old + for i in 0..high(old): + dest.add(move old[i]) proc processBasicCallbacks( fd: AsyncFD, event: Event From bc1db0d6f163e4aba51f27b2a8cefd05476bd5e4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 28 Nov 2020 03:47:49 +0800 Subject: [PATCH 1574/4254] move rest of tests to testament (#16140) * move rest of tests to testament * Update tests/stdlib/tsums.nim --- lib/packages/docutils/rstgen.nim | 6 -- lib/pure/sugar.nim | 97 -------------------------------- lib/std/editdistance.nim | 41 -------------- lib/std/sums.nim | 24 -------- lib/std/with.nim | 20 ------- lib/std/wordwrap.nim | 44 --------------- tests/stdlib/teditdistance.nim | 40 +++++++++++++ tests/stdlib/trstgen.nim | 7 ++- tests/stdlib/tsugar.nim | 94 +++++++++++++++++++++++++++++++ tests/stdlib/tsums.nim | 22 ++++++++ tests/stdlib/twith.nim | 23 ++++++++ tests/stdlib/twordwrap.nim | 43 ++++++++++++++ 12 files changed, 228 insertions(+), 233 deletions(-) create mode 100644 tests/stdlib/teditdistance.nim create mode 100644 tests/stdlib/tsugar.nim create mode 100644 tests/stdlib/tsums.nim create mode 100644 tests/stdlib/twith.nim create mode 100644 tests/stdlib/twordwrap.nim diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 604cc3ca9..47b4189ba 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1364,9 +1364,3 @@ proc rstToLatex*(rstSource: string; options: RstParseOptions): string {.inline, var rstGenera: RstGenerator rstGenera.initRstGenerator(outLatex, defaultConfig(), "input", options) rstGenera.renderRstToOut(rstParse(rstSource, "", 1, 1, option, options), result) - - -when isMainModule: - assert rstToHtml("*Hello* **world**!", {}, - newStringTable(modeStyleInsensitive)) == - "Hello world!" diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 46dbb1ece..d9c98c360 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -363,100 +363,3 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} = for i in 1 ..< init.len: call.add init[i] result = newTree(nnkStmtListExpr, newVarStmt(res, call), resBody, res) - - -when isMainModule: - since (1, 1): - block dup_with_field: - type - Foo = object - col, pos: int - name: string - - proc inc_col(foo: var Foo) = inc(foo.col) - proc inc_pos(foo: var Foo) = inc(foo.pos) - proc name_append(foo: var Foo, s: string) = foo.name &= s - - let a = Foo(col: 1, pos: 2, name: "foo") - block: - let b = a.dup(inc_col, inc_pos): - _.pos = 3 - name_append("bar") - inc_pos - - doAssert(b == Foo(col: 2, pos: 4, name: "foobar")) - - block: - let b = a.dup(inc_col, pos = 3, name = "bar"): - name_append("bar") - inc_pos - - doAssert(b == Foo(col: 2, pos: 4, name: "barbar")) - - import algorithm - - var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert dup(a, sort(_)) == sorted(a) - doAssert a.dup(sort) == sorted(a) - #Chaining: - var aCopy = a - aCopy.insert(10) - doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy) - - import random - - const b = @[0, 1, 2] - let c = b.dup shuffle() - doAssert c[0] == 1 - doAssert c[1] == 0 - - #test collect - import sets, tables - - let data = @["bird", "word"] # if this gets stuck in your head, its not my fault - assert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"] - assert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == {0: "bird", - 1: "word"}.toTable - assert initHashSet.collect(for d in data.items: {d}) == data.toHashSet - - let x = collect(newSeqOfCap(4)): - for (i, d) in data.pairs: - if i mod 2 == 0: d - assert x == @["bird"] - - # bug #12874 - - let bug1 = collect( - newSeq, - for (i, d) in data.pairs:( - block: - if i mod 2 == 0: - d - else: - d & d - ) - ) - assert bug1 == @["bird", "wordword"] - - import strutils - let y = collect(newSeq): - for (i, d) in data.pairs: - try: parseInt(d) except: 0 - assert y == @[0, 0] - - let z = collect(newSeq): - for (i, d) in data.pairs: - case d - of "bird": "word" - else: d - assert z == @["word", "word"] - - - proc tforum = - let ans = collect(newSeq): - for y in 0..10: - if y mod 5 == 2: - for x in 0..y: - x - - tforum() diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim index f365d4ab2..2c9203d64 100644 --- a/lib/std/editdistance.nim +++ b/lib/std/editdistance.nim @@ -264,44 +264,3 @@ proc editDistanceAscii*(a, b: string): int {.noSideEffect.} = if x > c3: x = c3 row[p] = x result = row[e] - - -when isMainModule: - doAssert editDistance("", "") == 0 - doAssert editDistance("kitten", "sitting") == 3 # from Wikipedia - doAssert editDistance("flaw", "lawn") == 2 # from Wikipedia - - doAssert editDistance("привет", "превет") == 1 - doAssert editDistance("Åge", "Age") == 1 - # editDistance, one string is longer in bytes, but shorter in rune length - # first string: 4 bytes, second: 6 bytes, but only 3 runes - doAssert editDistance("aaaa", "×××") == 4 - - block veryLongStringEditDistanceTest: - const cap = 256 - var - s1 = newStringOfCap(cap) - s2 = newStringOfCap(cap) - while len(s1) < cap: - s1.add 'a' - while len(s2) < cap: - s2.add 'b' - doAssert editDistance(s1, s2) == cap - - block combiningCodePointsEditDistanceTest: - const s = "A\xCC\x8Age" - doAssert editDistance(s, "Age") == 1 - - doAssert editDistanceAscii("", "") == 0 - doAssert editDistanceAscii("kitten", "sitting") == 3 # from Wikipedia - doAssert editDistanceAscii("flaw", "lawn") == 2 # from Wikipedia - - - assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) - assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) - assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) - assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) - assert(editDistance("prefix__hallo_suffix", "prefix") == 14) - assert(editDistance("prefix__hallo_suffix", "suffix") == 14) - assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) - assert(editDistance("main", "malign") == 2) diff --git a/lib/std/sums.nim b/lib/std/sums.nim index 0f8c5ebfb..cc964b91a 100644 --- a/lib/std/sums.nim +++ b/lib/std/sums.nim @@ -60,27 +60,3 @@ runnableExamples: const data = [1, 2, 3, 4, 5, 6, 7, 8, 9] doAssert sumKbn(data) == 45 doAssert sumPairs(data) == 45 - - -when isMainModule: - from math import pow - - var epsilon = 1.0 - while 1.0 + epsilon != 1.0: - epsilon /= 2.0 - let data = @[1.0, epsilon, -epsilon] - assert sumKbn(data) == 1.0 - assert sumPairs(data) != 1.0 # known to fail - assert (1.0 + epsilon) - epsilon != 1.0 - - var tc1: seq[float] - for n in 1 .. 1000: - tc1.add 1.0 / n.float - assert sumKbn(tc1) == 7.485470860550345 - assert sumPairs(tc1) == 7.485470860550345 - - var tc2: seq[float] - for n in 1 .. 1000: - tc2.add pow(-1.0, n.float) / n.float - assert sumKbn(tc2) == -0.6926474305598203 - assert sumPairs(tc2) == -0.6926474305598204 diff --git a/lib/std/with.nim b/lib/std/with.nim index ea26065a1..e6784478c 100644 --- a/lib/std/with.nim +++ b/lib/std/with.nim @@ -36,23 +36,3 @@ macro with*(arg: typed; calls: varargs[untyped]): untyped = result = newNimNode(nnkStmtList, arg) underscoredCalls(result, calls, arg) - -when isMainModule: - type - Foo = object - col, pos: string - name: string - - proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) - proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) - - var f: Foo - with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) - echo f - - f = Foo() - with f: - col = $(2, 3, 4) - pos = $(0.0, 1.0) - _.name = "bar" - echo f diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim index 27df229bf..7dcfc7f59 100644 --- a/lib/std/wordwrap.nim +++ b/lib/std/wordwrap.nim @@ -72,47 +72,3 @@ proc wrapWords*(s: string, maxLineWidth = 80, for k in i..A1 headerA2 """ + + +assert rstToHtml("*Hello* **world**!", {}, + newStringTable(modeStyleInsensitive)) == + "Hello world!" diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim new file mode 100644 index 000000000..a6fd70f34 --- /dev/null +++ b/tests/stdlib/tsugar.nim @@ -0,0 +1,94 @@ +import sugar + +block dup_with_field: + type + Foo = object + col, pos: int + name: string + + proc inc_col(foo: var Foo) = inc(foo.col) + proc inc_pos(foo: var Foo) = inc(foo.pos) + proc name_append(foo: var Foo, s: string) = foo.name &= s + + let a = Foo(col: 1, pos: 2, name: "foo") + block: + let b = a.dup(inc_col, inc_pos): + _.pos = 3 + name_append("bar") + inc_pos + + doAssert(b == Foo(col: 2, pos: 4, name: "foobar")) + + block: + let b = a.dup(inc_col, pos = 3, name = "bar"): + name_append("bar") + inc_pos + + doAssert(b == Foo(col: 2, pos: 4, name: "barbar")) + +import algorithm + +var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] +doAssert dup(a, sort(_)) == sorted(a) +doAssert a.dup(sort) == sorted(a) +#Chaining: +var aCopy = a +aCopy.insert(10) +doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy) + +import random + +const b = @[0, 1, 2] +let c = b.dup shuffle() +doAssert c.len == 3 + +#test collect +import sets, tables + +let data = @["bird", "word"] # if this gets stuck in your head, its not my fault +assert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"] +assert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == {0: "bird", + 1: "word"}.toTable +assert initHashSet.collect(for d in data.items: {d}) == data.toHashSet + +let x = collect(newSeqOfCap(4)): + for (i, d) in data.pairs: + if i mod 2 == 0: d +assert x == @["bird"] + +# bug #12874 + +let bug1 = collect( + newSeq, + for (i, d) in data.pairs:( + block: + if i mod 2 == 0: + d + else: + d & d + ) +) +assert bug1 == @["bird", "wordword"] + +import strutils +let y = collect(newSeq): + for (i, d) in data.pairs: + try: parseInt(d) except: 0 +assert y == @[0, 0] + +let z = collect(newSeq): + for (i, d) in data.pairs: + case d + of "bird": "word" + else: d +assert z == @["word", "word"] + + +proc tforum = + let ans = collect(newSeq): + for y in 0..10: + if y mod 5 == 2: + for x in 0..y: + x + +tforum() diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim new file mode 100644 index 000000000..979ffc391 --- /dev/null +++ b/tests/stdlib/tsums.nim @@ -0,0 +1,22 @@ +import std/sums +from math import pow + +var epsilon = 1.0 +while 1.0 + epsilon != 1.0: + epsilon /= 2.0 +let data = @[1.0, epsilon, -epsilon] +assert sumKbn(data) == 1.0 +# assert sumPairs(data) != 1.0 # known to fail in 64 bits +assert (1.0 + epsilon) - epsilon != 1.0 + +var tc1: seq[float] +for n in 1 .. 1000: + tc1.add 1.0 / n.float +assert sumKbn(tc1) == 7.485470860550345 +assert sumPairs(tc1) == 7.485470860550345 + +var tc2: seq[float] +for n in 1 .. 1000: + tc2.add pow(-1.0, n.float) / n.float +assert sumKbn(tc2) == -0.6926474305598203 +assert sumPairs(tc2) == -0.6926474305598204 diff --git a/tests/stdlib/twith.nim b/tests/stdlib/twith.nim new file mode 100644 index 000000000..80382f7c4 --- /dev/null +++ b/tests/stdlib/twith.nim @@ -0,0 +1,23 @@ +import std/with + +type + Foo = object + col, pos: string + name: string + +proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) +proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) + +var f: Foo +with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) +doAssert f.col == "(2, 3, 4)" +doAssert f.pos == "(0.0, 1.0)" + +f = Foo() +with f: + col = $(2, 3, 4) + pos = $(0.0, 1.0) + _.name = "bar" +doAssert f.col == "(2, 3, 4)" +doAssert f.pos == "(0.0, 1.0)" +doAssert f.name == "bar" diff --git a/tests/stdlib/twordwrap.nim b/tests/stdlib/twordwrap.nim new file mode 100644 index 000000000..c90dd9581 --- /dev/null +++ b/tests/stdlib/twordwrap.nim @@ -0,0 +1,43 @@ +import std/wordwrap + +when true: + let + inp = """ this is a long text -- muchlongerthan10chars and here + it goes""" + outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes" + doAssert wrapWords(inp, 10, false) == outp + + let + longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow""" + longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow" + doAssert wrapWords(longInp, 8, true) == longOutp + +# test we don't break Umlauts into invalid bytes: +let fies = "äöüöäöüöäöüöäöüööäöüöäößßßßüöäößßßßßß" +let fiesRes = "ä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nö\nä\nö\nü\nö\nä\nö\nß\nß\nß\nß\nü\nö\nä\nö\nß\nß\nß\nß\nß\nß" +doAssert wrapWords(fies, 1, true) == fiesRes + +let longlongword = """abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüö +äzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüüöäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiqfglwcßqfgxvlcwgtfhiaoen +rsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocfqclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdrtnaetdr +iaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ +ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε""" +let longlongwordRes = """ +abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp +psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüöäzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüü +öäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiq +fglwcßqfgxvlcwgtfhiaoenrsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocf +qclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdr +tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψ +ρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ +ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε""" +doAssert wrapWords(longlongword) == longlongwordRes + +# bug #14579 +const input60 = """ +This string is wrapped to 60 characters. If we call +wrapwords on it it will be re-wrapped to 80 characters. +""" +const input60Res = """This string is wrapped to 60 characters. If we call wrapwords on it it will be +re-wrapped to 80 characters.""" +doAssert wrapWords(input60) == input60Res \ No newline at end of file From c55552522710ef918e1adfd7a0f90ee0834b277f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 28 Nov 2020 04:04:36 +0800 Subject: [PATCH 1575/4254] fix #13115 (#15930) * fix #13115 * fix testament --- lib/system/ansi_c.nim | 5 +++++ lib/system/excpt.nim | 25 +++++++++++++++---------- tests/exception/t13115.nim | 13 +++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 tests/exception/t13115.nim diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 0b4b25992..4839407c1 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -154,6 +154,11 @@ proc c_fwrite*(buf: pointer, size, n: csize_t, f: CFilePtr): cint {. proc c_fflush(f: CFilePtr): cint {. importc: "fflush", header: "".} +proc rawWriteString*(f: CFilePtr, s: cstring, length: int) {.compilerproc, nonReloadable, inline.} = + # we cannot throw an exception here! + discard c_fwrite(s, 1, cast[csize_t](length), f) + discard c_fflush(f) + proc rawWrite*(f: CFilePtr, s: cstring) {.compilerproc, nonReloadable, inline.} = # we cannot throw an exception here! discard c_fwrite(s, 1, cast[csize_t](s.len), f) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 04c5d3ce8..f73a88e30 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -26,13 +26,17 @@ when defined(windows): when not defined(windows) or not defined(guiapp): proc writeToStdErr(msg: cstring) = rawWrite(cstderr, msg) + proc writeToStdErr(msg: cstring, length: int) = + rawWriteString(cstderr, msg, length) else: proc MessageBoxA(hWnd: pointer, lpText, lpCaption: cstring, uType: int): int32 {. header: "", nodecl.} proc writeToStdErr(msg: cstring) = discard MessageBoxA(nil, msg, nil, 0) + proc writeToStdErr(msg: cstring, length: int) = + discard MessageBoxA(nil, msg, nil, 0) -proc showErrorMessage(data: cstring) {.gcsafe, raises: [].} = +proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = var toWrite = true if errorMessageWriter != nil: try: @@ -45,7 +49,7 @@ proc showErrorMessage(data: cstring) {.gcsafe, raises: [].} = # stderr not available by default, use the LOG session echo data else: - writeToStdErr(data) + writeToStdErr(data, length) proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.} proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.} @@ -359,7 +363,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = if onUnhandledException != nil: onUnhandledException(buf) else: - showErrorMessage(buf) + showErrorMessage(buf, buf.len) `=destroy`(buf) else: # ugly, but avoids heap allocations :-) @@ -388,7 +392,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = if onUnhandledException != nil: onUnhandledException($tbuf()) else: - showErrorMessage(tbuf()) + showErrorMessage(tbuf(), L) proc reportUnhandledError(e: ref Exception) {.nodestroy.} = if unhandledExceptionHook != nil: @@ -500,9 +504,9 @@ proc writeStackTrace() = when hasSomeStackTrace: var s = "" rawWriteStackTrace(s) - cast[proc (s: cstring) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)(s) + cast[proc (s: cstring, length: int) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)(s, s.len) else: - cast[proc (s: cstring) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)("No stack traceback available\n") + cast[proc (s: cstring, length: int) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)("No stack traceback available\n", 32) proc getStackTrace(): string = when hasSomeStackTrace: @@ -535,10 +539,11 @@ const nimCallDepthLimit {.intdefine.} = 2000 proc callDepthLimitReached() {.noinline.} = writeStackTrace() - showErrorMessage("Error: call depth limit reached in a debug build (" & + let msg = "Error: call depth limit reached in a debug build (" & $nimCallDepthLimit & " function calls). You can change it with " & "-d:nimCallDepthLimit= but really try to avoid deep " & - "recursions instead.\n") + "recursions instead.\n" + showErrorMessage(msg, msg.len) quit(1) proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = @@ -622,14 +627,14 @@ when not defined(noSignalHandler) and not defined(useNimRtl): var buf = newStringOfCap(2000) rawWriteStackTrace(buf) processSignal(sign, buf.add) # nice hu? currying a la Nim :-) - showErrorMessage(buf) + showErrorMessage(buf, buf.len) when not usesDestructors: GC_enable() else: var msg: cstring template asgn(y) = msg = y processSignal(sign, asgn) - showErrorMessage(msg) + showErrorMessage(msg, msg.len) quit(1) # always quit when SIGABRT proc registerSignalHandler() = diff --git a/tests/exception/t13115.nim b/tests/exception/t13115.nim new file mode 100644 index 000000000..9d88bbeda --- /dev/null +++ b/tests/exception/t13115.nim @@ -0,0 +1,13 @@ +discard """ + exitcode: 1 + targets: "c" + matrix: "-d:debug; -d:release" + outputsub: '''t13115.nim(13) t13115 +Error: unhandled exception: This char is''' + outputsub: ''' and works fine! [Exception]''' +""" + +const b_null: char = 0.char +var msg = "This char is `" & $b_null & "` and works fine!" + +raise newException(Exception, msg) \ No newline at end of file From 157e7820f1bf120d0015f3b564ccc45c42ab03f4 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sat, 28 Nov 2020 01:05:19 +0200 Subject: [PATCH 1576/4254] Add package manu to tested packages (#16121) * Add package manu to tested packages * Bump --- testament/important_packages.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index ffc626589..2da10e749 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -11,7 +11,7 @@ var packages2*: seq[tuple[name, cmd: string; url: string, useHead: bool]] = @[] # pkg1 "alea" pkg1 "argparse" pkg1 "arraymancer", "nim c tests/tests_cpu.nim" -#pkg1 "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" +# pkg1 "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" pkg1 "awk" pkg1 "bigints", url = "https://github.com/Araq/nim-bigints" pkg1 "binaryheap", "nim c -r binaryheap.nim" @@ -56,6 +56,7 @@ pkg1 "karax", "nim c -r tests/tester.nim" pkg1 "kdtree", "nimble test", "https://github.com/jblindsay/kdtree" pkg1 "loopfusion" pkg1 "macroutils" +pkg1 "manu" pkg1 "markdown" pkg1 "memo" pkg1 "msgpack4nim", "nim c -r tests/test_spec.nim" From b809562c7cc38e391c1e3240d8ca77ba035c3f75 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 28 Nov 2020 00:09:31 -0800 Subject: [PATCH 1577/4254] make megatest consistent with unjoined tests wrt newlines, honor newlines in output spec (#16151) * fix megatest newlines * still allow missing trailing newline for now but in a more strict way than before --- testament/categories.nim | 22 ++++---- testament/specs.nim | 2 +- testament/testament.nim | 14 +++-- tests/arc/tstrformat.nim | 4 +- tests/async/tasyncfilewrite.nim | 3 +- tests/ccgbugs/tret_arg_init.nim | 2 + tests/concepts/treversable.nim | 2 +- tests/destructor/ttuple.nim | 2 +- tests/exception/texcas.nim | 5 +- tests/exception/texceptions.nim | 1 + tests/generics/treentranttypes.nim | 8 --- tests/js/tunittests.nim | 4 +- tests/lookups/test.nim | 2 +- tests/macros/tastrepr.nim | 1 + tests/magics/t10307.nim | 5 +- tests/metatype/tmatrix3.nim | 2 +- tests/metatype/ttensor.nim | 6 +- tests/misc/temptyecho.nim | 4 ++ tests/objects/tobject.nim | 2 +- tests/overload/tstatic_with_converter.nim | 5 +- tests/specialops/tdotops.nim | 4 +- tests/statictypes/tpassthruarith.nim | 4 -- tests/stdlib/talgorithm.nim | 2 +- tests/stdlib/tcgi.nim | 1 + tests/stdlib/tmath.nim | 5 +- tests/stdlib/tnet_ll.nim | 1 + tests/stdlib/tnre.nim | 4 +- tests/stdlib/tparseuints.nim | 13 +++-- tests/stdlib/trst.nim | 1 + tests/stdlib/tsequtils.nim | 3 - tests/stdlib/tunittest.nim | 68 +++++++++++------------ tests/system/tenum_array_repr.nim | 2 - tests/template/tgensymregression.nim | 2 - 33 files changed, 110 insertions(+), 96 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 0d19842ec..4f6e40659 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -591,12 +591,14 @@ proc isJoinableSpec(spec: TSpec): bool = if spec.file.readFile.contains "when isMainModule": result = false -proc norm(s: var string) = - while true: - let tmp = s.replace("\n\n", "\n") - if tmp == s: break - s = tmp - s = s.strip +when false: + proc norm(s: var string) = + ## strip empty newlines + while true: + let tmp = s.replace("\n\n", "\n") + if tmp == s: break + s = tmp + s = s.strip proc quoted(a: string): string = # todo: consider moving to system.nim @@ -654,16 +656,16 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = echo buf.string quit(failString & "megatest execution failed") - norm buf.string const outputExceptedFile = "outputExpected.txt" const outputGottenFile = "outputGotten.txt" writeFile(outputGottenFile, buf.string) var outputExpected = "" for i, runSpec in specs: outputExpected.add marker & runSpec.file & "\n" - outputExpected.add runSpec.output.strip - outputExpected.add '\n' - norm outputExpected + if runSpec.output.len > 0: + outputExpected.add runSpec.output + if not runSpec.output.endsWith "\n": + outputExpected.add '\n' if buf.string != outputExpected: writeFile(outputExceptedFile, outputExpected) diff --git a/testament/specs.nim b/testament/specs.nim index eaae598bb..37fe12275 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -280,7 +280,7 @@ proc parseSpec*(filename: string): TSpec = of "output": if result.outputCheck != ocSubstr: result.outputCheck = ocEqual - result.output = strip(e.value) + result.output = e.value of "input": result.input = e.value of "outputsub": diff --git a/testament/testament.nim b/testament/testament.nim index 2912b03ab..94f66c2db 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -469,6 +469,10 @@ proc checkDisabled(r: var TResults, test: TTest): bool = var count = 0 +proc equalModuloLastNewline(a, b: string): bool = + # allow lazy output spec that omits last newline, but really those should be fixed instead + result = a == b or b.endsWith("\n") and a == b[0 ..< ^1] + proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, target: TTarget, nimcache: string, extraOptions = "") = test.startTime = epochTime() @@ -513,16 +517,18 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, if exitCode != 0: exitCode = 1 let bufB = if expected.sortoutput: - var x = splitLines(strip(buf.string)) + var buf2 = buf.string + buf2.stripLineEnd + var x = splitLines(buf2) sort(x, system.cmp) - join(x, "\n") + join(x, "\n") & "\n" else: - strip(buf.string) + buf.string if exitCode != expected.exitCode: r.addResult(test, target, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode & "\n\nOutput:\n" & bufB, reExitcodesDiffer) - elif (expected.outputCheck == ocEqual and expected.output != bufB) or + elif (expected.outputCheck == ocEqual and not expected.output.equalModuloLastNewline(bufB)) or (expected.outputCheck == ocSubstr and expected.output notin bufB): given.err = reOutputsDiffer r.addResult(test, target, expected.output, bufB, reOutputsDiffer) diff --git a/tests/arc/tstrformat.nim b/tests/arc/tstrformat.nim index 00d7a6679..641f323da 100644 --- a/tests/arc/tstrformat.nim +++ b/tests/arc/tstrformat.nim @@ -1,5 +1,7 @@ discard """ - output: '''verstuff''' + output: ''' +verstuff +''' cmd: "nim c --gc:arc $file" """ diff --git a/tests/async/tasyncfilewrite.nim b/tests/async/tasyncfilewrite.nim index 3baf2bbc6..72a2df0b0 100644 --- a/tests/async/tasyncfilewrite.nim +++ b/tests/async/tasyncfilewrite.nim @@ -1,7 +1,8 @@ discard """ output: '''string 1 string 2 -string 3''' +string 3 +''' """ # bug #5532 import os, asyncfile, asyncdispatch diff --git a/tests/ccgbugs/tret_arg_init.nim b/tests/ccgbugs/tret_arg_init.nim index 5cd67de3e..e39e5a0de 100644 --- a/tests/ccgbugs/tret_arg_init.nim +++ b/tests/ccgbugs/tret_arg_init.nim @@ -1,6 +1,8 @@ discard """ output: ''' + + ''' """ diff --git a/tests/concepts/treversable.nim b/tests/concepts/treversable.nim index 6ebc077d9..d30ba0a3c 100644 --- a/tests/concepts/treversable.nim +++ b/tests/concepts/treversable.nim @@ -3,7 +3,7 @@ discard """ output: ''' z e - ''' +''' """ type diff --git a/tests/destructor/ttuple.nim b/tests/destructor/ttuple.nim index 5a2126105..d0ea72c60 100644 --- a/tests/destructor/ttuple.nim +++ b/tests/destructor/ttuple.nim @@ -2,7 +2,7 @@ discard """ output: '''5.0 10.0 =destroy -=destroy +=destroy ''' """ diff --git a/tests/exception/texcas.nim b/tests/exception/texcas.nim index 7108e334c..ad6819f11 100644 --- a/tests/exception/texcas.nim +++ b/tests/exception/texcas.nim @@ -1,8 +1,9 @@ discard """ targets: "c cpp" - output: '''Hello + output: ''' Hello - ''' +Hello +''' """ proc test[T]() = try: diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim index 5d4d0fa9e..adee5d1d5 100644 --- a/tests/exception/texceptions.nim +++ b/tests/exception/texceptions.nim @@ -1,5 +1,6 @@ discard """ output: ''' + BEFORE FINALLY diff --git a/tests/generics/treentranttypes.nim b/tests/generics/treentranttypes.nim index 31fa25293..40ff1647b 100644 --- a/tests/generics/treentranttypes.nim +++ b/tests/generics/treentranttypes.nim @@ -2,21 +2,13 @@ discard """ output: ''' (10, ("test", 1.2)) 3x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0], [2.0, 0.0, 5.0]] - 2x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]] - 2x3 Literal [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]] - 2x3 Matrix [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x2 ArrayArray[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x3 ArrayVector[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x3 VectorVector [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x3 VectorArray [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - @[1, 2] @[1, 2] @[1, 2]@[3, 4] diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim index 7c2e70563..0d934a82b 100644 --- a/tests/js/tunittests.nim +++ b/tests/js/tunittests.nim @@ -1,7 +1,9 @@ discard """ output: ''' + [Suite] Bacon - [OK] >:)''' + [OK] >:) +''' """ import unittest diff --git a/tests/lookups/test.nim b/tests/lookups/test.nim index 97dfa131a..dfacaf5b5 100644 --- a/tests/lookups/test.nim +++ b/tests/lookups/test.nim @@ -1,7 +1,7 @@ discard """ output: ''' -[Suite] memoization +[Suite] memoization ''' """ diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim index e4271f019..759ca55b5 100644 --- a/tests/macros/tastrepr.nim +++ b/tests/macros/tastrepr.nim @@ -1,5 +1,6 @@ discard """ output: ''' + var data = @[(1, "one"), (2, "two")] for (i, d) in pairs(data): discard diff --git a/tests/magics/t10307.nim b/tests/magics/t10307.nim index 111b0d221..b5bbfdfa8 100644 --- a/tests/magics/t10307.nim +++ b/tests/magics/t10307.nim @@ -4,7 +4,8 @@ discard """ res: yes yes running someProc(false) -res: +res: + ''' """ @@ -20,4 +21,4 @@ echo "running someProc(true)" echo someProc(true) echo "running someProc(false)" -echo someProc(false) \ No newline at end of file +echo someProc(false) diff --git a/tests/metatype/tmatrix3.nim b/tests/metatype/tmatrix3.nim index a143e2bc9..28e85fcee 100644 --- a/tests/metatype/tmatrix3.nim +++ b/tests/metatype/tmatrix3.nim @@ -1,5 +1,5 @@ discard """ - output: "" + output: "\n" """ type Matrix[M,N: static[int]] = array[M, array[N, float]] diff --git a/tests/metatype/ttensor.nim b/tests/metatype/ttensor.nim index f2f24ba8c..89a0bf007 100644 --- a/tests/metatype/ttensor.nim +++ b/tests/metatype/ttensor.nim @@ -1,13 +1,11 @@ discard """ - output: '''before tensor2: + output: ''' +before tensor2: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0] - before tensor3: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0] - after tensor3: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0] - a3: [1000.0, 1001.0, 1002.0, 1003.0, 1004.0, 1005.0, 1006.0, 1007.0, 1008.0, 1009.0, 1010.0, 1011.0, 1012.0, 1013.0, 1014.0, 1015.0, 1016.0, 1017.0, 1018.0, 1019.0, 1020.0, 1021.0, 1022.0, 1023.0, 1024.0, 1025.0, 1026.0]''' """ diff --git a/tests/misc/temptyecho.nim b/tests/misc/temptyecho.nim index 5f1aa6515..a3c407897 100644 --- a/tests/misc/temptyecho.nim +++ b/tests/misc/temptyecho.nim @@ -1,2 +1,6 @@ +discard """ +output: "\n" +""" + echo() diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim index a79c2bdfd..d166d5385 100644 --- a/tests/objects/tobject.nim +++ b/tests/objects/tobject.nim @@ -1,5 +1,5 @@ discard """ -output: "[Suite] object basic methods" +output: "\n[Suite] object basic methods" """ import unittest diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim index 2871744eb..8209e8399 100644 --- a/tests/overload/tstatic_with_converter.nim +++ b/tests/overload/tstatic_with_converter.nim @@ -1,6 +1,8 @@ discard """ output: ''' -9.0''' +9.0 + +''' """ ### bug #6773 @@ -41,6 +43,7 @@ proc `^`(x: vfloat, exp: static[float]): vfloat = proc `$`(x: vfloat): string = let y = cast[ptr float](unsafeAddr x) + # xxx not sure if intentional in this issue, but this returns "" echo y[] let x = set1(9.0) diff --git a/tests/specialops/tdotops.nim b/tests/specialops/tdotops.nim index 227204f51..b1c75ab33 100644 --- a/tests/specialops/tdotops.nim +++ b/tests/specialops/tdotops.nim @@ -1,5 +1,6 @@ discard """ output: ''' + 10 assigning z = 20 reading field y @@ -12,7 +13,8 @@ no params call to b 100 one param call to c with 10 100 -0 4''' +0 4 +''' """ type diff --git a/tests/statictypes/tpassthruarith.nim b/tests/statictypes/tpassthruarith.nim index 857e5b0af..33e4e0303 100644 --- a/tests/statictypes/tpassthruarith.nim +++ b/tests/statictypes/tpassthruarith.nim @@ -1,13 +1,9 @@ discard """ output: ''' [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - [1, 2, 3, 4] ''' """ diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 59336e70d..9dec68f03 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -1,6 +1,6 @@ discard """ output:'''@["3", "2", "1"] - ''' +''' """ #12928,10456 import sequtils, strutils, algorithm, json diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index 222a3bf6d..cec188e35 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,5 +1,6 @@ discard """ output: ''' + [Suite] Test cgi module (key: "a", value: "1") (key: "b", value: "0") diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index ff1f32d36..ac5ce4c90 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,6 +1,8 @@ discard """ action: run - output: '''[Suite] random int + output: ''' + +[Suite] random int [Suite] random float @@ -9,7 +11,6 @@ discard """ [Suite] random sample [Suite] ^ - ''' """ diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index 2ac272fd1..affa21947 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -1,6 +1,7 @@ discard """ action: run output: ''' + [Suite] inet_ntop tests ''' """ diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim index 0929956cb..d2dc1a7c5 100644 --- a/tests/stdlib/tnre.nim +++ b/tests/stdlib/tnre.nim @@ -4,7 +4,9 @@ discard """ # codes to differ and be reported as a failure output: - '''[Suite] Test NRE initialization + ''' + +[Suite] Test NRE initialization [Suite] captures diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim index 6b228d933..72041da66 100644 --- a/tests/stdlib/tparseuints.nim +++ b/tests/stdlib/tparseuints.nim @@ -1,13 +1,14 @@ discard """ action: run output: ''' -[Suite] parseutils''' + +[Suite] parseutils +''' """ import unittest, strutils suite "parseutils": - test "uint": - check: parseBiggestUInt("0") == 0'u64 - check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64 - expect(ValueError): - discard parseBiggestUInt("18446744073709551616") + check: parseBiggestUInt("0") == 0'u64 + check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64 + expect(ValueError): + discard parseBiggestUInt("18446744073709551616") diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 797010a22..6a6e6fdc0 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -1,5 +1,6 @@ discard """ output: ''' + [Suite] RST include directive ''' """ diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index ea3f06982..efcc9f126 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -455,6 +455,3 @@ block: yield i doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6 - -when not defined(testing): - echo "Finished doc tests" diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 9ef689e32..8e82a0c97 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -1,5 +1,7 @@ discard """ - output: '''[Suite] suite with only teardown + output: ''' + +[Suite] suite with only teardown [Suite] suite with only setup @@ -16,7 +18,6 @@ discard """ [Suite] test suite [Suite] test name filtering - ''' """ @@ -141,38 +142,37 @@ suite "test suite": check(a == b) -when defined(testing): - suite "test name filtering": - test "test name": - check matchFilter("suite1", "foo", "") - check matchFilter("suite1", "foo", "foo") - check matchFilter("suite1", "foo", "::") - check matchFilter("suite1", "foo", "*") - check matchFilter("suite1", "foo", "::foo") - check matchFilter("suite1", "::foo", "::foo") +suite "test name filtering": + test "test name": + check matchFilter("suite1", "foo", "") + check matchFilter("suite1", "foo", "foo") + check matchFilter("suite1", "foo", "::") + check matchFilter("suite1", "foo", "*") + check matchFilter("suite1", "foo", "::foo") + check matchFilter("suite1", "::foo", "::foo") - test "test name - glob": - check matchFilter("suite1", "foo", "f*") - check matchFilter("suite1", "foo", "*oo") - check matchFilter("suite1", "12345", "12*345") - check matchFilter("suite1", "q*wefoo", "q*wefoo") - check false == matchFilter("suite1", "foo", "::x") - check false == matchFilter("suite1", "foo", "::x*") - check false == matchFilter("suite1", "foo", "::*x") - # overlap - check false == matchFilter("suite1", "12345", "123*345") - check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f") + test "test name - glob": + check matchFilter("suite1", "foo", "f*") + check matchFilter("suite1", "foo", "*oo") + check matchFilter("suite1", "12345", "12*345") + check matchFilter("suite1", "q*wefoo", "q*wefoo") + check false == matchFilter("suite1", "foo", "::x") + check false == matchFilter("suite1", "foo", "::x*") + check false == matchFilter("suite1", "foo", "::*x") + # overlap + check false == matchFilter("suite1", "12345", "123*345") + check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f") - test "suite name": - check matchFilter("suite1", "foo", "suite1::") - check false == matchFilter("suite1", "foo", "suite2::") - check matchFilter("suite1", "qwe::foo", "qwe::foo") - check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo") + test "suite name": + check matchFilter("suite1", "foo", "suite1::") + check false == matchFilter("suite1", "foo", "suite2::") + check matchFilter("suite1", "qwe::foo", "qwe::foo") + check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo") - test "suite name - glob": - check matchFilter("suite1", "foo", "::*") - check matchFilter("suite1", "foo", "*::*") - check matchFilter("suite1", "foo", "*::foo") - check false == matchFilter("suite1", "foo", "*ite2::") - check matchFilter("suite1", "q**we::foo", "q**we::foo") - check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e") + test "suite name - glob": + check matchFilter("suite1", "foo", "::*") + check matchFilter("suite1", "foo", "*::*") + check matchFilter("suite1", "foo", "*::foo") + check false == matchFilter("suite1", "foo", "*ite2::") + check matchFilter("suite1", "q**we::foo", "q**we::foo") + check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e") diff --git a/tests/system/tenum_array_repr.nim b/tests/system/tenum_array_repr.nim index 3634692e3..39b1a5f9a 100644 --- a/tests/system/tenum_array_repr.nim +++ b/tests/system/tenum_array_repr.nim @@ -2,10 +2,8 @@ discard """ output: ''' 1 [a, b] - 2 [c, d] - 4 [e, f]''' """ diff --git a/tests/template/tgensymregression.nim b/tests/template/tgensymregression.nim index f84c96403..2a5dca934 100644 --- a/tests/template/tgensymregression.nim +++ b/tests/template/tgensymregression.nim @@ -1,8 +1,6 @@ discard """ output: '''[0.0, 0.0, 0.0] - [0.0, 0.0, 0.0, 0.0] - 5050 123''' """ From 1d786c0a54d3ec914d16079d5e228605fbcb2cb6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 28 Nov 2020 10:33:36 -0800 Subject: [PATCH 1578/4254] fix #14242 `testament r tests/js/foo` now works; testament now honors --targets (#16163) * fix #14242 `testament r tests/js/foo` now works; testament now honors --targets * fix shouldfail --- testament/categories.nim | 14 +++++++------- testament/specs.nim | 8 ++++---- testament/testament.nim | 14 +++++++++----- tests/testament/tshould_not_work.nim | 28 ++++++++++++++-------------- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 4f6e40659..3429b760a 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -563,13 +563,13 @@ proc `&.?`(a, b: string): string = # candidate for the stdlib? result = if b.startsWith(a): b else: a & b -proc processSingleTest(r: var TResults, cat: Category, options, test: string) = - let test = testsDir &.? cat.string / test - let target = if cat.string.normalize == "js": targetJS else: targetC - if fileExists(test): - testSpec r, makeTest(test, options, cat), {target} - else: - doAssert false, test & " test does not exist" +proc processSingleTest(r: var TResults, cat: Category, options, test: string, targets: set[TTarget], targetsSet: bool) = + var targets = targets + if not targetsSet: + let target = if cat.string.normalize == "js": targetJS else: targetC + targets = {target} + doAssert fileExists(test), test & " test does not exist" + testSpec r, makeTest(test, options, cat), targets proc isJoinableSpec(spec: TSpec): bool = result = not spec.sortoutput and diff --git a/testament/specs.nim b/testament/specs.nim index 37fe12275..c60ed7e20 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -57,10 +57,10 @@ type reInvalidSpec # test had problems to parse the spec TTarget* = enum - targetC = "C" - targetCpp = "C++" - targetObjC = "ObjC" - targetJS = "JS" + targetC = "c" + targetCpp = "cpp" + targetObjC = "objc" + targetJS = "js" InlineError* = object kind*: string diff --git a/testament/testament.nim b/testament/testament.nim index 94f66c2db..c014a79a6 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -81,6 +81,7 @@ let pegOfInterest = pegLineError / pegOtherError var gTargets = {low(TTarget)..high(TTarget)} +var targetsSet = false proc isSuccess(input: string): bool = # not clear how to do the equivalent of pkg/regex's: re"FOO(.*?)BAR" in pegs @@ -691,6 +692,7 @@ proc main() = of "targets": targetsStr = p.val.string gTargets = parseTargets(targetsStr) + targetsSet = true of "nim": compilerPrefix = addFileExt(p.val.string, ExeExt) of "directory": @@ -800,14 +802,16 @@ proc main() = p.next processPattern(r, pattern, p.cmdLineRest.string, simulate) of "r", "run": + # "/pathto/tests/stdlib/nre/captures.nim" -> "stdlib" + "tests/stdlib/nre/captures.nim" var subPath = p.key.string - if subPath.isAbsolute: subPath = subPath.relativePath(getCurrentDir()) + let nimRoot = currentSourcePath / "../.." + # makes sure points to this regardless of cwd or which nim is used to compile this. + doAssert existsDir(nimRoot/testsDir) # sanity check + if subPath.isAbsolute: subPath = subPath.relativePath(nimRoot) # at least one directory is required in the path, to use as a category name - let pathParts = split(subPath, {DirSep, AltSep}) - # "stdlib/nre/captures.nim" -> "stdlib" + "nre/captures.nim" + let pathParts = subPath.relativePath(testsDir).split({DirSep, AltSep}) let cat = Category(pathParts[0]) - subPath = joinPath(pathParts[1..^1]) - processSingleTest(r, cat, p.cmdLineRest.string, subPath) + processSingleTest(r, cat, p.cmdLineRest.string, subPath, gTargets, targetsSet) of "html": generateHtml(resultsFile, optFailing) else: diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index e4d3c7be7..a7a877fe8 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -2,36 +2,36 @@ discard """ cmd: "testament/testament --directory:testament --colors:off --backendLogging:off --nim:../compiler/nim category shouldfail" action: compile nimout: ''' -FAIL: tests/shouldfail/tccodecheck.nim C +FAIL: tests/shouldfail/tccodecheck.nim c Failure: reCodegenFailure Expected: baz -FAIL: tests/shouldfail/tcolumn.nim C +FAIL: tests/shouldfail/tcolumn.nim c Failure: reLinesDiffer -FAIL: tests/shouldfail/terrormsg.nim C +FAIL: tests/shouldfail/terrormsg.nim c Failure: reMsgsDiffer -FAIL: tests/shouldfail/texitcode1.nim C +FAIL: tests/shouldfail/texitcode1.nim c Failure: reExitcodesDiffer -FAIL: tests/shouldfail/tfile.nim C +FAIL: tests/shouldfail/tfile.nim c Failure: reFilesDiffer -FAIL: tests/shouldfail/tline.nim C +FAIL: tests/shouldfail/tline.nim c Failure: reLinesDiffer -FAIL: tests/shouldfail/tmaxcodesize.nim C +FAIL: tests/shouldfail/tmaxcodesize.nim c Failure: reCodegenFailure max allowed size: 1 -FAIL: tests/shouldfail/tnimout.nim C +FAIL: tests/shouldfail/tnimout.nim c Failure: reMsgsDiffer -FAIL: tests/shouldfail/toutput.nim C +FAIL: tests/shouldfail/toutput.nim c Failure: reOutputsDiffer -FAIL: tests/shouldfail/toutputsub.nim C +FAIL: tests/shouldfail/toutputsub.nim c Failure: reOutputsDiffer -FAIL: tests/shouldfail/treject.nim C +FAIL: tests/shouldfail/treject.nim c Failure: reFilesDiffer -FAIL: tests/shouldfail/tsortoutput.nim C +FAIL: tests/shouldfail/tsortoutput.nim c Failure: reOutputsDiffer -FAIL: tests/shouldfail/ttimeout.nim C +FAIL: tests/shouldfail/ttimeout.nim c Failure: reTimeout -FAIL: tests/shouldfail/tvalgrind.nim C +FAIL: tests/shouldfail/tvalgrind.nim c Failure: reExitcodesDiffer ''' """ From d29eddf92a1b8147c4709fd828f77152c1f3aab2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 28 Nov 2020 11:59:08 -0800 Subject: [PATCH 1579/4254] experimental/diff: move isMainModule block to tests/stdlib/tdiff.nim (#16172) --- lib/experimental/diff.nim | 80 --------------------------------------- tests/stdlib/tdiff.nim | 73 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 80 deletions(-) create mode 100644 tests/stdlib/tdiff.nim diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim index 5a69687a3..d1274d771 100644 --- a/lib/experimental/diff.nim +++ b/lib/experimental/diff.nim @@ -331,83 +331,3 @@ proc diffText*(textA, textB: string): seq[Item] = optimize(dataA) optimize(dataB) result = createDiffs(dataA, dataB) - -when isMainModule: - - proc testHelper(f: seq[Item]): string = - for it in f: - result.add( - $it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*" - ) - - proc main() = - var a, b: string - - stdout.writeLine("Diff Self Test...") - - # test all changes - a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n') - b = "0,1,2,3,4,5,6,7,8,9".replace(',', '\n') - assert(testHelper(diffText(a, b)) == - "12.10.0.0*", - "all-changes test failed.") - stdout.writeLine("all-changes test passed.") - # test all same - a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n') - b = a - assert(testHelper(diffText(a, b)) == - "", - "all-same test failed.") - stdout.writeLine("all-same test passed.") - - # test snake - a = "a,b,c,d,e,f".replace(',', '\n') - b = "b,c,d,e,f,x".replace(',', '\n') - assert(testHelper(diffText(a, b)) == - "1.0.0.0*0.1.6.5*", - "snake test failed.") - stdout.writeLine("snake test passed.") - - # 2002.09.20 - repro - a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".replace(',', '\n') - b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".replace(',', '\n') - assert(testHelper(diffText(a, b)) == - "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*", - "repro20020920 test failed.") - stdout.writeLine("repro20020920 test passed.") - - # 2003.02.07 - repro - a = "F".replace(',', '\n') - b = "0,F,1,2,3,4,5,6,7".replace(',', '\n') - assert(testHelper(diffText(a, b)) == - "0.1.0.0*0.7.1.2*", - "repro20030207 test failed.") - stdout.writeLine("repro20030207 test passed.") - - # Muegel - repro - a = "HELLO\nWORLD" - b = "\n\nhello\n\n\n\nworld\n" - assert(testHelper(diffText(a, b)) == - "2.8.0.0*", - "repro20030409 test failed.") - stdout.writeLine("repro20030409 test passed.") - - # test some differences - a = "a,b,-,c,d,e,f,f".replace(',', '\n') - b = "a,b,x,c,e,f".replace(',', '\n') - assert(testHelper(diffText(a, b)) == - "1.1.2.2*1.0.4.4*1.0.7.6*", - "some-changes test failed.") - stdout.writeLine("some-changes test passed.") - - # test one change within long chain of repeats - a = "a,a,a,a,a,a,a,a,a,a".replace(',', '\n') - b = "a,a,a,a,-,a,a,a,a,a".replace(',', '\n') - assert(testHelper(diffText(a, b)) == - "0.1.4.4*1.0.9.10*", - "long chain of repeats test failed.") - - stdout.writeLine("End.") - stdout.flushFile - - main() diff --git a/tests/stdlib/tdiff.nim b/tests/stdlib/tdiff.nim new file mode 100644 index 000000000..694ac6198 --- /dev/null +++ b/tests/stdlib/tdiff.nim @@ -0,0 +1,73 @@ +discard """ + targets: "c js" +""" + +import experimental/diff +import std/strutils + +proc testHelper(f: seq[Item]): string = + for it in f: + result.add( + $it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*" + ) + +proc main() = + var a, b: string + + # Diff Self Test + # test all changes + a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n') + b = "0,1,2,3,4,5,6,7,8,9".replace(',', '\n') + doAssert(testHelper(diffText(a, b)) == + "12.10.0.0*", + "all-changes test failed.") + # test all same + a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n') + b = a + doAssert(testHelper(diffText(a, b)) == + "", + "all-same test failed.") + + # test snake + a = "a,b,c,d,e,f".replace(',', '\n') + b = "b,c,d,e,f,x".replace(',', '\n') + doAssert(testHelper(diffText(a, b)) == + "1.0.0.0*0.1.6.5*", + "snake test failed.") + + # 2002.09.20 - repro + a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".replace(',', '\n') + b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".replace(',', '\n') + doAssert(testHelper(diffText(a, b)) == + "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*", + "repro20020920 test failed.") + + # 2003.02.07 - repro + a = "F".replace(',', '\n') + b = "0,F,1,2,3,4,5,6,7".replace(',', '\n') + doAssert(testHelper(diffText(a, b)) == + "0.1.0.0*0.7.1.2*", + "repro20030207 test failed.") + + # Muegel - repro + a = "HELLO\nWORLD" + b = "\n\nhello\n\n\n\nworld\n" + doAssert(testHelper(diffText(a, b)) == + "2.8.0.0*", + "repro20030409 test failed.") + + # test some differences + a = "a,b,-,c,d,e,f,f".replace(',', '\n') + b = "a,b,x,c,e,f".replace(',', '\n') + doAssert(testHelper(diffText(a, b)) == + "1.1.2.2*1.0.4.4*1.0.7.6*", + "some-changes test failed.") + + # test one change within long chain of repeats + a = "a,a,a,a,a,a,a,a,a,a".replace(',', '\n') + b = "a,a,a,a,-,a,a,a,a,a".replace(',', '\n') + doAssert(testHelper(diffText(a, b)) == + "0.1.4.4*1.0.9.10*", + "long chain of repeats test failed.") +main() +static: main() From 6114df3c24e9c23bfbdbaa204bb100de9d170995 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 29 Nov 2020 10:42:50 -0800 Subject: [PATCH 1580/4254] testament: error instead of silently overwrite a spec (#16166) --- testament/specs.nim | 18 +++++++++++++----- testament/testament.nim | 5 ++--- tests/casestmt/tcaseexpr1.nim | 26 ++++++++++++++++---------- tests/exception/t13115.nim | 9 ++++----- tests/generics/tmetafield.nim | 20 ++++++++++++++++---- 5 files changed, 51 insertions(+), 27 deletions(-) diff --git a/testament/specs.nim b/testament/specs.nim index c60ed7e20..d2f37b96c 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -8,7 +8,7 @@ # import sequtils, parseutils, strutils, os, streams, parsecfg, - tables, hashes + tables, hashes, sets type TestamentData* = ref object # better to group globals under 1 object; could group the other ones here too @@ -82,7 +82,7 @@ type tline*, tcolumn*: int exitCode*: int msg*: string - ccodeCheck*: string + ccodeCheck*: seq[string] maxCodeSize*: int err*: TResultEnum inCurrentBatch*: bool @@ -244,11 +244,19 @@ proc parseSpec*(filename: string): TSpec = var ss = newStringStream(specStr) var p: CfgParser open(p, ss, filename, 1) + var flags: HashSet[string] while true: var e = next(p) case e.kind of cfgKeyValuePair: - case normalize(e.key) + let key = e.key.normalize + const whiteListMulti = ["disabled", "ccodecheck"] + ## list of flags that are correctly handled when passed multiple times + ## (instead of being overwritten) + if key notin whiteListMulti: + doAssert key notin flags, $(key, filename) + flags.incl key + case key of "action": case e.value.normalize of "compile": @@ -298,7 +306,7 @@ proc parseSpec*(filename: string): TSpec = result.msg = e.value if result.action != actionRun: result.action = actionCompile - of "errormsg", "errmsg": + of "errormsg", "errmsg": # xxx just use errormsg, no need for such aliases result.msg = e.value result.action = actionReject of "nimout": @@ -361,7 +369,7 @@ proc parseSpec*(filename: string): TSpec = else: result.cmd = e.value of "ccodecheck": - result.ccodeCheck = e.value + result.ccodeCheck.add e.value of "maxcodesize": discard parseInt(e.value, result.maxCodeSize) of "timeout": diff --git a/testament/testament.nim b/testament/testament.nim index c014a79a6..f2ac9c338 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -402,9 +402,8 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st try: let genFile = generatedFile(test, target) let contents = readFile(genFile).string - let check = spec.ccodeCheck - if check.len > 0: - if check[0] == '\\': + for check in spec.ccodeCheck: + if check.len > 0 and check[0] == '\\': # little hack to get 'match' support: if not contents.match(check.peg): given.err = reCodegenFailure diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim index 3d4b6c087..82af2410b 100644 --- a/tests/casestmt/tcaseexpr1.nim +++ b/tests/casestmt/tcaseexpr1.nim @@ -1,17 +1,23 @@ discard """ - errormsg: "type mismatch: got but expected 'int'" - line: 33 - file: "tcaseexpr1.nim" - - errormsg: "not all cases are covered; missing: {C}" - line: 27 - file: "tcaseexpr1.nim" + cmd: "nim check $options $file" + action: "reject" + nimout: ''' +tcaseexpr1.nim(33, 10) Error: not all cases are covered; missing: {C} +''' """ -# NOTE: This spec is wrong. Spec doesn't support multiple error -# messages. The first one is simply overridden by the second one. -# This just has never been noticed. +#[ +# xxx make nimout comparison use nimoutCheck instead of: +elif expected.nimout.len > 0 and expected.nimout.normalizeMsg notin given.nimout.normalizeMsg: +and then use nimout: ''' +tcaseexpr1.nim(33, 10) Error: not all cases are covered2; missing: {C} +tcaseexpr1.nim(39, 12) Error: type mismatch: got but expected 'int literal(10)' +''' +]# + + +# line 20 type E = enum A, B, C diff --git a/tests/exception/t13115.nim b/tests/exception/t13115.nim index 9d88bbeda..53e078076 100644 --- a/tests/exception/t13115.nim +++ b/tests/exception/t13115.nim @@ -2,12 +2,11 @@ discard """ exitcode: 1 targets: "c" matrix: "-d:debug; -d:release" - outputsub: '''t13115.nim(13) t13115 -Error: unhandled exception: This char is''' outputsub: ''' and works fine! [Exception]''' """ -const b_null: char = 0.char -var msg = "This char is `" & $b_null & "` and works fine!" +# bug #13115 +# xxx bug: doesn't yet work for cpp -raise newException(Exception, msg) \ No newline at end of file +var msg = "This char is `" & '\0' & "` and works fine!" +raise newException(Exception, msg) diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim index 7a2375abe..cf30a936d 100644 --- a/tests/generics/tmetafield.nim +++ b/tests/generics/tmetafield.nim @@ -1,10 +1,23 @@ discard """ cmd: "nim check $options $file" - errormsg: "'proc' is not a concrete type" - errormsg: "'Foo' is not a concrete type." - errormsg: "invalid type: 'proc' in this context: 'TBaseMed'" + action: "reject" + nimout: ''' +tmetafield.nim(26, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()' +tmetafield.nim(27, 5) Error: 'Foo' is not a concrete type +tmetafield.nim(29, 5) Error: invalid type: 'proc' in this context: 'TBaseMed' for var +''' """ +# bug #188 + + + + + + + + +# line 20 type Foo[T] = object x: T @@ -15,4 +28,3 @@ type var a: TBaseMed -# issue 188 From 31a8cf16bbad69efbfbc6f7a593f2141cba06381 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 29 Nov 2020 17:32:34 -0800 Subject: [PATCH 1581/4254] testament spec: remove errmsg alias of errormsg (#16188) --- testament/specs.nim | 2 +- testament/tests/shouldfail/tfile.nim | 2 +- tests/async/tdiscardableproc.nim | 2 +- tests/destructor/tdestructor_too_late.nim | 2 +- tests/errmsgs/t8610.nim | 2 +- tests/errmsgs/t9768.nim | 2 +- tests/errmsgs/tstaticexprscope.nim | 2 +- tests/errmsgs/ttypeAllowed.nim | 2 +- tests/lent/tnot_allowed_lent.nim | 2 +- tests/lent/tnot_allowed_lent2.nim | 2 +- tests/nimble/tnimblepathdollar_fault.nim | 2 +- tests/proc/tfunc_type.nim | 2 +- tests/proc/tillegalreturntype.nim | 2 +- tests/varres/tprevent_forloopvar_mutations.nim | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/testament/specs.nim b/testament/specs.nim index d2f37b96c..e15dcb85c 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -306,7 +306,7 @@ proc parseSpec*(filename: string): TSpec = result.msg = e.value if result.action != actionRun: result.action = actionCompile - of "errormsg", "errmsg": # xxx just use errormsg, no need for such aliases + of "errormsg": result.msg = e.value result.action = actionReject of "nimout": diff --git a/testament/tests/shouldfail/tfile.nim b/testament/tests/shouldfail/tfile.nim index a6c2ad359..20d4bd1f3 100644 --- a/testament/tests/shouldfail/tfile.nim +++ b/testament/tests/shouldfail/tfile.nim @@ -1,5 +1,5 @@ discard """ -errmsg: "undeclared identifier: 'undefined'" +errormsg: "undeclared identifier: 'undefined'" file: "notthisfile.nim" """ diff --git a/tests/async/tdiscardableproc.nim b/tests/async/tdiscardableproc.nim index 80286ece0..93cd83be9 100644 --- a/tests/async/tdiscardableproc.nim +++ b/tests/async/tdiscardableproc.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded" + errormsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded" """ import async diff --git a/tests/destructor/tdestructor_too_late.nim b/tests/destructor/tdestructor_too_late.nim index d279280ba..76d1dde84 100644 --- a/tests/destructor/tdestructor_too_late.nim +++ b/tests/destructor/tdestructor_too_late.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)" + errormsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)" """ type Obj* = object v*: int diff --git a/tests/errmsgs/t8610.nim b/tests/errmsgs/t8610.nim index 6a253f7ab..d3405bc91 100644 --- a/tests/errmsgs/t8610.nim +++ b/tests/errmsgs/t8610.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "invalid type: 'type int' for const" + errormsg: "invalid type: 'type int' for const" """ ## issue #8610 const Foo = int diff --git a/tests/errmsgs/t9768.nim b/tests/errmsgs/t9768.nim index d369150a5..b72a158c7 100644 --- a/tests/errmsgs/t9768.nim +++ b/tests/errmsgs/t9768.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "unhandled exception:" + errormsg: "unhandled exception:" file: "system/fatal.nim" nimout: ''' stack trace: (most recent call last) diff --git a/tests/errmsgs/tstaticexprscope.nim b/tests/errmsgs/tstaticexprscope.nim index 7af5bf9b3..6969e389e 100644 --- a/tests/errmsgs/tstaticexprscope.nim +++ b/tests/errmsgs/tstaticexprscope.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "undeclared identifier: 'z'" + errormsg: "undeclared identifier: 'z'" line: 11 """ diff --git a/tests/errmsgs/ttypeAllowed.nim b/tests/errmsgs/ttypeAllowed.nim index 9efbc6ead..516b616e0 100644 --- a/tests/errmsgs/ttypeAllowed.nim +++ b/tests/errmsgs/ttypeAllowed.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim check $file" -errmsg: "" +errormsg: "" nimout: ''' ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for let ttypeAllowed.nim(17, 7) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for const diff --git a/tests/lent/tnot_allowed_lent.nim b/tests/lent/tnot_allowed_lent.nim index 2de18d4af..a1db6d184 100644 --- a/tests/lent/tnot_allowed_lent.nim +++ b/tests/lent/tnot_allowed_lent.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "expression has no address" + errormsg: "expression has no address" """ type MyObject = object diff --git a/tests/lent/tnot_allowed_lent2.nim b/tests/lent/tnot_allowed_lent2.nim index e61cae922..d0c958df3 100644 --- a/tests/lent/tnot_allowed_lent2.nim +++ b/tests/lent/tnot_allowed_lent2.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "'x' cannot be assigned to" + errormsg: "'x' cannot be assigned to" line: 10 """ diff --git a/tests/nimble/tnimblepathdollar_fault.nim b/tests/nimble/tnimblepathdollar_fault.nim index 628802030..3f0270123 100644 --- a/tests/nimble/tnimblepathdollar_fault.nim +++ b/tests/nimble/tnimblepathdollar_fault.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "cannot open file: pkgA/module" + errormsg: "cannot open file: pkgA/module" """ # see nims file; comment out `switch("noNimblePath")` there and there would be no error diff --git a/tests/proc/tfunc_type.nim b/tests/proc/tfunc_type.nim index 2a583fcb9..93697acb1 100644 --- a/tests/proc/tfunc_type.nim +++ b/tests/proc/tfunc_type.nim @@ -1,6 +1,6 @@ discard """ - errmsg: "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead" + errormsg: "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead" """ type diff --git a/tests/proc/tillegalreturntype.nim b/tests/proc/tillegalreturntype.nim index e26c44bea..799cad53a 100644 --- a/tests/proc/tillegalreturntype.nim +++ b/tests/proc/tillegalreturntype.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim check $file" - errmsg: "" + errormsg: "" nimout: ''' tillegalreturntype.nim(11, 11) Error: return type 'typed' is only valid for macros and templates tillegalreturntype.nim(14, 11) Error: return type 'untyped' is only valid for macros and templates diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index ac62608af..15f31d8a3 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "type mismatch: got " + errormsg: "type mismatch: got " line: 17 nimout: '''type mismatch: got but expected one of: From 358963193f31fd762b8e26ea4cad162c950785db Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 30 Nov 2020 09:41:50 +0800 Subject: [PATCH 1582/4254] cleanup old codes (#16173) --- tests/tuples/tuple_with_nil.nim | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim index b3ed2a96b..7136c8cab 100644 --- a/tests/tuples/tuple_with_nil.nim +++ b/tests/tuples/tuple_with_nil.nim @@ -1,23 +1,16 @@ import macros -from strutils import IdentStartChars import parseutils import unicode import math -import fenv import pegs import streams type - FormatError = object of Exception ## Error in the format string. + FormatError = object of CatchableError ## 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) + write(W, 'c') FmtAlign = enum ## Format alignment faDefault ## default for given format type From dd5405cbcf7b12a41bd14591fdb2c706c87bf42f Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 30 Nov 2020 08:54:49 +0100 Subject: [PATCH 1583/4254] disable testing of `argparse` package until it is fixed --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 2da10e749..6d89df3e5 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -9,7 +9,7 @@ var packages2*: seq[tuple[name, cmd: string; url: string, useHead: bool]] = @[] # packages A-M # pkg1 "alea" -pkg1 "argparse" +# pkg1 "argparse" pkg1 "arraymancer", "nim c tests/tests_cpu.nim" # pkg1 "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" pkg1 "awk" From 735c06d7f12ee3e4733754f57a1710e9d0dba5d9 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 30 Nov 2020 17:18:47 +0800 Subject: [PATCH 1584/4254] small runnableExamples changes (#16181) --- lib/pure/algorithm.nim | 58 ++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 2430e7330..f2e4848df 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -11,36 +11,34 @@ ## ## Basic usage ## =========== -## -## .. code-block:: -## import algorithm -## -## type People = tuple -## year: int -## name: string -## -## var a: seq[People] -## -## a.add((2000, "John")) -## a.add((2005, "Marie")) -## a.add((2010, "Jane")) -## -## # Sorting with default system.cmp -## a.sort() -## assert a == @[(year: 2000, name: "John"), (year: 2005, name: "Marie"), -## (year: 2010, name: "Jane")] -## -## proc myCmp(x, y: People): int = -## if x.name < y.name: -1 -## elif x.name == y.name: 0 -## else: 1 -## -## # Sorting with custom proc -## a.sort(myCmp) -## assert a == @[(year: 2010, name: "Jane"), (year: 2000, name: "John"), -## (year: 2005, name: "Marie")] -## -## +## + +runnableExamples: + type People = tuple + year: int + name: string + + var a: seq[People] + + a.add((2000, "John")) + a.add((2005, "Marie")) + a.add((2010, "Jane")) + + # Sorting with default system.cmp + a.sort() + assert a == @[(year: 2000, name: "John"), (year: 2005, name: "Marie"), + (year: 2010, name: "Jane")] + + proc myCmp(x, y: People): int = + if x.name < y.name: -1 + elif x.name == y.name: 0 + else: 1 + + # Sorting with custom proc + a.sort(myCmp) + assert a == @[(year: 2010, name: "Jane"), (year: 2000, name: "John"), + (year: 2005, name: "Marie")] + ## See also ## ======== ## * `sequtils module`_ for working with the built-in seq type From 5a43a20f53d826e5f5e47ca49aa7423fd9cba21b Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 1 Dec 2020 01:24:12 +0800 Subject: [PATCH 1585/4254] toXXAscii use xor op, saving 30%~50% time (#16193) * toXXAscii use xor op, saving 30%~50% time * Update lib/pure/strutils.nim Co-authored-by: hlaaftana <10591326+hlaaftana@users.noreply.github.com> * Update lib/pure/strutils.nim Co-authored-by: Andreas Rumpf Co-authored-by: hlaaftana <10591326+hlaaftana@users.noreply.github.com> --- lib/pure/strutils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f0b447de7..8cbc947bf 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -209,7 +209,7 @@ proc toLowerAscii*(c: char): char {.noSideEffect, doAssert toLowerAscii('A') == 'a' doAssert toLowerAscii('e') == 'e' if c in {'A'..'Z'}: - result = chr(ord(c) + (ord('a') - ord('A'))) + result = char(uint8(c) xor 0b0010_0000'u8) else: result = c @@ -248,7 +248,7 @@ proc toUpperAscii*(c: char): char {.noSideEffect, doAssert toUpperAscii('a') == 'A' doAssert toUpperAscii('E') == 'E' if c in {'a'..'z'}: - result = chr(ord(c) - (ord('a') - ord('A'))) + result = char(uint8(c) xor 0b0010_0000'u8) else: result = c From bb4b27a2ca414f06fbb9d14ff76fa02a088ac141 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 30 Nov 2020 17:45:37 +0000 Subject: [PATCH 1586/4254] fix #16185 (#16195) * fix #16185 * fix test * fix comment * fix comment * better approach --- compiler/injectdestructors.nim | 121 +++++++++++++++++---------------- compiler/trees.nim | 15 ++++ tests/arc/t14383.nim | 51 +++++++++++++- 3 files changed, 126 insertions(+), 61 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 34c11e06c..eba270eea 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -19,7 +19,7 @@ import lineinfos, parampatterns, sighashes, liftdestructors, optimizer, varpartitions -from trees import exprStructuralEquivalent, getRoot +from trees import exprStructuralEquivalent, getRoot, sameLocation type Scope = object # well we do scope-based memory management. \ @@ -969,67 +969,68 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind) proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNode = - case ri.kind - of nkCallKinds: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkBracketExpr: - if isUnpackedTuple(ri[0]): - # unpacking of tuple: take over the elements - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and - not aliases(dest, ri): - # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkBracket: - # array constructor - if ri.len > 0 and isDangerousSeq(ri.typ): - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - else: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkSym: - if dest.kind == nkSym and dest.sym == ri.sym: - # rule (self-assignment-removal): - result = newNodeI(nkEmpty, dest.info) - elif isSinkParam(ri.sym) and isLastRead(ri, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - elif ri.sym.kind != skParam and ri.sym.owner == c.owner and - isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: - result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) - of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: - template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) - # We know the result will be a stmt so we use that fact to optimize - handleNestedTempl(ri, process, willProduceStmt = true) - of nkRaiseStmt: - result = pRaiseStmt(ri, c, s) + if sameLocation(dest, ri): + # rule (self-assignment-removal): + result = newNodeI(nkEmpty, dest.info) else: - if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and - canBeMoved(c, dest.typ): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + case ri.kind + of nkCallKinds: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkBracketExpr: + if isUnpackedTuple(ri[0]): + # unpacking of tuple: take over the elements + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and + not aliases(dest, ri): + # Rule 3: `=sink`(x, z); wasMoved(z) + var snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + of nkBracket: + # array constructor + if ri.len > 0 and isDangerousSeq(ri.typ): + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + else: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkSym: + if isSinkParam(ri.sym) and isLastRead(ri, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + elif ri.sym.kind != skParam and ri.sym.owner == c.owner and + isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: + result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) + of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: + template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) + # We know the result will be a stmt so we use that fact to optimize + handleNestedTempl(ri, process, willProduceStmt = true) + of nkRaiseStmt: + result = pRaiseStmt(ri, c, s) else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) + if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and + canBeMoved(c, dest.typ): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) proc computeUninit(c: var Con) = if not c.uninitComputed: diff --git a/compiler/trees.nim b/compiler/trees.nim index 05c060595..eb88f8d67 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -54,6 +54,21 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = strictSymEquality): return result = true +proc sameLocation*(a, b: PNode): bool = + if a == b: true + elif a == nil or b == nil: false + elif a.kind == b.kind: + case a.kind: + of nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref, + nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv: + sameLocation(a[0], b[0]) + of nkDotExpr, nkBracketExpr: + sameLocation(a[0], b[0]) and sameLocation(a[1], b[1]) + of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b[1]) + of nkNone..nkNilLit: exprStructuralEquivalent(a, b, strictSymEquality = true) + else: false + else: false + proc sameTree*(a, b: PNode): bool = if a == b: result = true diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim index 85f90d1c8..0ce7b7d10 100644 --- a/tests/arc/t14383.nim +++ b/tests/arc/t14383.nim @@ -125,4 +125,53 @@ proc main = let rankdef = avals echo avals.len, " ", rankdef.len -main() \ No newline at end of file +main() + + + + +#------------------------------------------------------------------------------ +# Issue #16185, complex self-assingment elimination +#------------------------------------------------------------------------------ + +type + CpuStorage*[T] = ref CpuStorageObj[T] + CpuStorageObj[T] = object + size*: int + raw_buffer*: ptr UncheckedArray[T] + Tensor[T] = object + buf*: CpuStorage[T] + TestObject = object + x: Tensor[float] + +proc `=destroy`[T](s: var CpuStorageObj[T]) = + if s.raw_buffer != nil: + s.raw_buffer.deallocShared() + s.size = 0 + s.raw_buffer = nil + +proc `=`[T](a: var CpuStorageObj[T]; b: CpuStorageObj[T]) {.error.} + +proc allocCpuStorage[T](s: var CpuStorage[T], size: int) = + new(s) + s.raw_buffer = cast[ptr UncheckedArray[T]](allocShared0(sizeof(T) * size)) + s.size = size + +proc newTensor[T](size: int): Tensor[T] = + allocCpuStorage(result.buf, size) + +proc `[]`[T](t: Tensor[T], idx: int): T = t.buf.raw_buffer[idx] +proc `[]=`[T](t: Tensor[T], idx: int, val: T) = t.buf.raw_buffer[idx] = val + +proc toTensor[T](s: seq[T]): Tensor[T] = + result = newTensor[T](s.len) + for i, x in s: + result[i] = x + +proc main2() = + var t: TestObject + t.x = toTensor(@[1.0, 2, 3, 4]) + t.x = t.x + doAssert(t.x.buf != nil) # self-assignment above should be eliminated + +main2() From 2e4b6b94e675a7de96fcf2b3e8ed4224dccd5747 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Nov 2020 23:36:38 +0100 Subject: [PATCH 1587/4254] Revert "fix #16185 (#16195)" (#16197) This reverts commit bb4b27a2ca414f06fbb9d14ff76fa02a088ac141. --- compiler/injectdestructors.nim | 121 ++++++++++++++++----------------- compiler/trees.nim | 15 ---- tests/arc/t14383.nim | 51 +------------- 3 files changed, 61 insertions(+), 126 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index eba270eea..34c11e06c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -19,7 +19,7 @@ import lineinfos, parampatterns, sighashes, liftdestructors, optimizer, varpartitions -from trees import exprStructuralEquivalent, getRoot, sameLocation +from trees import exprStructuralEquivalent, getRoot type Scope = object # well we do scope-based memory management. \ @@ -969,68 +969,67 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind) proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNode = - if sameLocation(dest, ri): - # rule (self-assignment-removal): - result = newNodeI(nkEmpty, dest.info) - else: - case ri.kind - of nkCallKinds: + case ri.kind + of nkCallKinds: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkBracketExpr: + if isUnpackedTuple(ri[0]): + # unpacking of tuple: take over the elements result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkBracketExpr: - if isUnpackedTuple(ri[0]): - # unpacking of tuple: take over the elements - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and - not aliases(dest, ri): - # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkBracket: - # array constructor - if ri.len > 0 and isDangerousSeq(ri.typ): - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - else: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkSym: - if isSinkParam(ri.sym) and isLastRead(ri, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - elif ri.sym.kind != skParam and ri.sym.owner == c.owner and - isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: - result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) - of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: - template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) - # We know the result will be a stmt so we use that fact to optimize - handleNestedTempl(ri, process, willProduceStmt = true) - of nkRaiseStmt: - result = pRaiseStmt(ri, c, s) + elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and + not aliases(dest, ri): + # Rule 3: `=sink`(x, z); wasMoved(z) + var snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and - canBeMoved(c, dest.typ): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + of nkBracket: + # array constructor + if ri.len > 0 and isDangerousSeq(ri.typ): + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + else: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkSym: + if dest.kind == nkSym and dest.sym == ri.sym: + # rule (self-assignment-removal): + result = newNodeI(nkEmpty, dest.info) + elif isSinkParam(ri.sym) and isLastRead(ri, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + elif ri.sym.kind != skParam and ri.sym.owner == c.owner and + isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: + result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) + of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: + template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) + # We know the result will be a stmt so we use that fact to optimize + handleNestedTempl(ri, process, willProduceStmt = true) + of nkRaiseStmt: + result = pRaiseStmt(ri, c, s) + else: + if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and + canBeMoved(c, dest.typ): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) proc computeUninit(c: var Con) = if not c.uninitComputed: diff --git a/compiler/trees.nim b/compiler/trees.nim index eb88f8d67..05c060595 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -54,21 +54,6 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = strictSymEquality): return result = true -proc sameLocation*(a, b: PNode): bool = - if a == b: true - elif a == nil or b == nil: false - elif a.kind == b.kind: - case a.kind: - of nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref, - nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv: - sameLocation(a[0], b[0]) - of nkDotExpr, nkBracketExpr: - sameLocation(a[0], b[0]) and sameLocation(a[1], b[1]) - of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b[1]) - of nkNone..nkNilLit: exprStructuralEquivalent(a, b, strictSymEquality = true) - else: false - else: false - proc sameTree*(a, b: PNode): bool = if a == b: result = true diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim index 0ce7b7d10..85f90d1c8 100644 --- a/tests/arc/t14383.nim +++ b/tests/arc/t14383.nim @@ -125,53 +125,4 @@ proc main = let rankdef = avals echo avals.len, " ", rankdef.len -main() - - - - -#------------------------------------------------------------------------------ -# Issue #16185, complex self-assingment elimination -#------------------------------------------------------------------------------ - -type - CpuStorage*[T] = ref CpuStorageObj[T] - CpuStorageObj[T] = object - size*: int - raw_buffer*: ptr UncheckedArray[T] - Tensor[T] = object - buf*: CpuStorage[T] - TestObject = object - x: Tensor[float] - -proc `=destroy`[T](s: var CpuStorageObj[T]) = - if s.raw_buffer != nil: - s.raw_buffer.deallocShared() - s.size = 0 - s.raw_buffer = nil - -proc `=`[T](a: var CpuStorageObj[T]; b: CpuStorageObj[T]) {.error.} - -proc allocCpuStorage[T](s: var CpuStorage[T], size: int) = - new(s) - s.raw_buffer = cast[ptr UncheckedArray[T]](allocShared0(sizeof(T) * size)) - s.size = size - -proc newTensor[T](size: int): Tensor[T] = - allocCpuStorage(result.buf, size) - -proc `[]`[T](t: Tensor[T], idx: int): T = t.buf.raw_buffer[idx] -proc `[]=`[T](t: Tensor[T], idx: int, val: T) = t.buf.raw_buffer[idx] = val - -proc toTensor[T](s: seq[T]): Tensor[T] = - result = newTensor[T](s.len) - for i, x in s: - result[i] = x - -proc main2() = - var t: TestObject - t.x = toTensor(@[1.0, 2, 3, 4]) - t.x = t.x - doAssert(t.x.buf != nil) # self-assignment above should be eliminated - -main2() +main() \ No newline at end of file From 1d1b3f79fdccfdd359781dbde3c5aea3b67bf05b Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Tue, 1 Dec 2020 14:01:36 +0300 Subject: [PATCH 1588/4254] fix broken => for typed procs with pragmas (#16190) * fix broken => for typed procs with pragmas * add more sugar tests * add ending quote --- lib/pure/sugar.nim | 15 ++++++--------- tests/macros/tclosuremacro.nim | 13 +++++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index d9c98c360..047104972 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -17,10 +17,7 @@ proc checkPragma(ex, prag: var NimNode) = since (1, 3): if ex.kind == nnkPragmaExpr: prag = ex[1] - if ex[0].kind == nnkPar and ex[0].len == 1: - ex = ex[0][0] - else: - ex = ex[0] + ex = ex[0] proc createProcType(p, b: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkProcTy) @@ -66,12 +63,12 @@ macro `=>`*(p, b: untyped): untyped = type Bot = object - call: proc (): string {.nosideEffect.} + call: proc (name: string): string {.noSideEffect.} var myBot = Bot() - myBot.call = () {.nosideEffect.} => "I'm a bot." - doAssert myBot.call() == "I'm a bot." + myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot." + doAssert myBot.call("John") == "Hello John, I'm a bot." var params = @[ident"auto"] @@ -89,7 +86,7 @@ macro `=>`*(p, b: untyped): untyped = checkPragma(p, pragma) # check again after -> transform since (1, 3): - if p.kind == nnkCall: + if p.kind in {nnkCall, nnkObjConstr}: # foo(x, y) => x + y kind = nnkProcDef name = p[0] @@ -129,7 +126,7 @@ macro `=>`*(p, b: untyped): untyped = error("Expected proc type (->) got (" & c[0].strVal & ").", c) break else: - error("Incorrect procedure parameter list.", c) + error("Incorrect procedure parameter.", c) params.add(identDefs) of nnkIdent: var identDefs = newNimNode(nnkIdentDefs) diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim index 5c41c317a..2a7847b9e 100644 --- a/tests/macros/tclosuremacro.nim +++ b/tests/macros/tclosuremacro.nim @@ -71,3 +71,16 @@ m: echo "yes" sugarWithPragma() {.m.} => echo "sugarWithPragma called" + +typedParamAndPragma(x, y: int) {.used.} -> int => x + y +doAssert typedParamAndPragma(1, 2) == 3 + +type + Bot = object + call: proc (): string {.noSideEffect.} + +var myBot = Bot() +myBot.call = () {.noSideEffect.} => "I'm a bot." +doAssert myBot.call() == "I'm a bot." + + From c65f95417a85a04707712a3b481ffa0b94c99437 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 2 Dec 2020 03:19:39 +0800 Subject: [PATCH 1589/4254] better addInt (#16160) * better addint * Update lib/system/strmantle.nim Co-authored-by: Juan Carlos --- lib/system/strmantle.nim | 96 +++++++++++++++++++++++++++++++------ tests/system/tstrmantle.nim | 46 ++++++++++++++++++ 2 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 tests/system/tstrmantle.nim diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index fa6ff411b..b5d275e25 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -9,6 +9,72 @@ # Compilerprocs for strings that do not depend on the string implementation. +const digitsTable = "0001020304050607080910111213141516171819" & + "2021222324252627282930313233343536373839" & + "4041424344454647484950515253545556575859" & + "6061626364656667686970717273747576777879" & + "8081828384858687888990919293949596979899" + # Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c + # Generates: + # .. code-block:: nim + # var res = "" + # for i in 0 .. 99: + # if i < 10: + # res.add "0" & $i + # else: + # res.add $i + # doAssert res == digitsTable + + +func digits10(num: uint64): int {.noinline.} = + if num < 10: + result = 1 + elif num < 100: + result = 2 + elif num < 1_000: + result = 3 + elif num < 10_000: + result = 4 + elif num < 100_000: + result = 5 + elif num < 1_000_000: + result = 6 + elif num < 10_000_000: + result = 7 + elif num < 100_000_000: + result = 8 + elif num < 1_000_000_000: + result = 9 + elif num < 10_000_000_000'u64: + result = 10 + elif num < 100_000_000_000'u64: + result = 11 + elif num < 1_000_000_000_000'u64: + result = 12 + else: + result = 12 + digits10(num div 1_000_000_000_000'u64) + +template numToString(result: var string, origin: uint64, length: int) = + var num = origin + var next = length - 1 + const nbatch = 100 + + while num >= nbatch: + let originNum = num + num = num div nbatch + let index = (originNum - num * nbatch) shl 1 + result[next] = digitsTable[index + 1] + result[next - 1] = digitsTable[index] + dec(next, 2) + + # process last 1-2 digits + if num < 10: + result[next] = chr(ord('0') + num) + else: + let index = num * 2 + result[next] = digitsTable[index + 1] + result[next - 1] = digitsTable[index] + proc cmpStrings(a, b: string): int {.inline, compilerproc.} = let alen = a.len let blen = b.len @@ -49,22 +115,22 @@ proc addInt*(result: var string; x: int64) = ## b = 45 ## a.addInt(b) # a <- "12345" let base = result.len - setLen(result, base + sizeof(x)*4) - var i = 0 - var y = x - while true: - var d = y div 10 - result[base+i] = chr(abs(int(y - d*10)) + ord('0')) - inc(i) - y = d - if y == 0: break + var length: int + var num: uint64 + if x < 0: - result[base+i] = '-' - inc(i) - setLen(result, base+i) - # mirror the string: - for j in 0..i div 2 - 1: - swap(result[base+j], result[base+i-j-1]) + if x == low(int64): + num = uint64(x) + else: + num = uint64(-x) + length = base + digits10(num) + 1 + setLen(result, length) + result[base] = '-' + else: + num = uint64(x) + length = base + digits10(num) + setLen(result, length) + numToString(result, num, length) proc nimIntToStr(x: int): string {.compilerRtl.} = result = newStringOfCap(sizeof(x)*4) diff --git a/tests/system/tstrmantle.nim b/tests/system/tstrmantle.nim new file mode 100644 index 000000000..5b232193e --- /dev/null +++ b/tests/system/tstrmantle.nim @@ -0,0 +1,46 @@ +var res = newStringOfCap(24) + +for i in 0 .. 9: + res.addInt int64(i) + +doAssert res == "0123456789" + +res = newStringOfCap(24) + +for i in -9 .. 0: + res.addInt int64(i) + +doAssert res == "-9-8-7-6-5-4-3-2-10" + +res = newStringOfCap(24) +res.addInt high(int64) +doAssert res == "9223372036854775807" + +res = newStringOfCap(24) +res.addInt low(int64) +doAssert res == "-9223372036854775808" + +res = newStringOfCap(12) +res.addInt high(int32) +doAssert res == "2147483647" + +res = newStringOfCap(12) +res.addInt low(int32) +doAssert res == "-2147483648" + +res = newStringOfCap(12) +res.addInt high(int16) +doAssert res == "32767" + +res = newStringOfCap(212) +res.addInt low(int16) +doAssert res == "-32768" + + +res = newStringOfCap(12) +res.addInt high(int8) +doAssert res == "127" + +res = newStringOfCap(12) +res.addInt low(int8) +doAssert res == "-128" From fd9870568020939aae902ef5ccb26d12e45673b6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 1 Dec 2020 11:34:53 -0800 Subject: [PATCH 1590/4254] error instead of echo when testament category is empty; fix realtimeGC (#16162) --- testament/categories.nim | 4 ++- tests/realtimeGC/cmain.c | 4 ++- tests/realtimeGC/main.nim.cfg | 6 ----- tests/realtimeGC/readme.txt | 23 +++++----------- tests/realtimeGC/shared.nim | 5 ---- tests/realtimeGC/shared.nim.cfg | 5 ---- tests/realtimeGC/{nmain.nim => tmain.nim} | 32 ++++++++++++++--------- 7 files changed, 32 insertions(+), 47 deletions(-) delete mode 100644 tests/realtimeGC/main.nim.cfg delete mode 100644 tests/realtimeGC/shared.nim.cfg rename tests/realtimeGC/{nmain.nim => tmain.nim} (50%) diff --git a/testament/categories.nim b/testament/categories.nim index 3429b760a..c48d611b1 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -748,7 +748,9 @@ proc processCategory(r: var TResults, cat: Category, testSpec r, test inc testsRun if testsRun == 0: - echo "[Warning] - Invalid category specified \"", cat.string, "\", no tests were run" + const whiteListedDirs = ["deps"] + doAssert cat.string in whiteListedDirs, + "Invalid category specified: '$#' not in whilelist: $#" % [cat.string, $whiteListedDirs] proc processPattern(r: var TResults, pattern, options: string; simulate: bool) = var testsRun = 0 diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c index 0d4bb096a..4bc5bd026 100644 --- a/tests/realtimeGC/cmain.c +++ b/tests/realtimeGC/cmain.c @@ -1,3 +1,5 @@ +/* xxx consider removing, this seems redundant with tmain.nim */ + #ifdef WIN #include #else @@ -28,7 +30,7 @@ int main(int argc, char* argv[]) status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status"); count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count"); checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem"); -#else /* OSX || NIX */ +#else /* OSX || NIX xxx: OSX assumes dylib*/ hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY); status = (pFunc) dlsym(hndl, (char const*)"status"); count = (pFunc) dlsym(hndl, (char const*)"count"); diff --git a/tests/realtimeGC/main.nim.cfg b/tests/realtimeGC/main.nim.cfg deleted file mode 100644 index fed4fa471..000000000 --- a/tests/realtimeGC/main.nim.cfg +++ /dev/null @@ -1,6 +0,0 @@ - ---app:console ---threads:on - --d:release --d:useRealtimeGC diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt index b2e37a1f0..b2788520e 100644 --- a/tests/realtimeGC/readme.txt +++ b/tests/realtimeGC/readme.txt @@ -1,21 +1,10 @@ Test the realtime GC without linking nimrtl.dll/so. -Note, this is a long running test, default is 35 minutes. To change the -the run time see RUNTIME in nmain.nim and cmain.c. +To build by hand and run the test for 35 minutes: + $ nim r --threads:on -d:runtimeSecs:2100 tests/realtimeGC/nmain.nim -You can build shared.nim, nmain.nim, and cmain.c by running make (nix systems) -or make.bat (Windows systems). They both assume GCC and that it's in your -path. Output: shared.(dll/so), cmain(.exe), nmain(.exe). - -To run the test: execute either nmain or cmain in a shell window. - -To build by hand: - - - build the shared object (shared.nim): - - $ nim c tests/realtimeGC/shared.nim - - - build the client executables: - - $ nim c --threads:on tests/realtimeGC/nmain.nim +``` +xxx do we still need tests/realtimeGC/cmain.c? +if so, tests/realtimeGC/cmain.c needs to updated and factorized with nmain.nim to avoid duplication (even if it's a C file) +``` $ gcc -o tests/realtimeGC/cmain tests/realtimeGC/cmain.c -ldl diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim index 1abe42089..8b5c05e47 100644 --- a/tests/realtimeGC/shared.nim +++ b/tests/realtimeGC/shared.nim @@ -1,8 +1,3 @@ -discard """ -cmd: "nim $target --debuginfo --hints:on --app:lib $options $file" -action: compile -""" - import strutils # Global state, accessing with threads, no locks. Don't do this at diff --git a/tests/realtimeGC/shared.nim.cfg b/tests/realtimeGC/shared.nim.cfg deleted file mode 100644 index e153b26fa..000000000 --- a/tests/realtimeGC/shared.nim.cfg +++ /dev/null @@ -1,5 +0,0 @@ ---app:lib ---threads:on - --d:release --d:useRealtimeGC diff --git a/tests/realtimeGC/nmain.nim b/tests/realtimeGC/tmain.nim similarity index 50% rename from tests/realtimeGC/nmain.nim rename to tests/realtimeGC/tmain.nim index c9f558dbc..f1515a549 100644 --- a/tests/realtimeGC/nmain.nim +++ b/tests/realtimeGC/tmain.nim @@ -1,18 +1,27 @@ discard """ - cmd: "nim $target --debuginfo $options $file" - output: "Done" + cmd: "nim $target --threads:on -d:release -d:useRealtimeGC $options $file" + joinable:false """ -import times, os, threadpool +#[ +was: cmd: "nim $target --debuginfo $options $file" +these dont' seem needed --debuginfo +nor these from the previous main.nim.cfg: --app:console +]# -const RUNTIME = 15 * 60 # 15 minutes +import times, os, strformat, strutils +from stdtest/specialpaths import buildDir +# import threadpool -when defined(windows): - const dllname = "./tests/realtimeGC/shared.dll" -elif defined(macosx): - const dllname = "./tests/realtimeGC/libshared.dylib" -else: - const dllname = "./tests/realtimeGC/libshared.so" +const runtimeSecs {.intdefine.} = 5 + +const file = "shared.nim" +const dllname = buildDir / (DynlibFormat % file) + +static: + let nim = getCurrentCompilerExe() + let (output, exitCode) = gorgeEx(fmt"{nim} c -o:{dllname} --debuginfo --app:lib --threads:on -d:release -d:useRealtimeGC {file}") + doAssert exitCode == 0, output proc status() {.importc: "status", dynlib: dllname.} proc count() {.importc: "count", dynlib: dllname.} @@ -20,7 +29,7 @@ proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.} proc process() = let startTime = getTime() - let runTime = cast[Time](RUNTIME) # + let runTime = cast[Time](runtimeSecs) var accumTime: Time while accumTime < runTime: for i in 0..10: @@ -41,6 +50,5 @@ proc main() = # for i in 0..0: # spawn process() # sync() - echo("Done") main() From 62eb1312a099aeae0115beb038ed8449ccd095a7 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 2 Dec 2020 04:06:37 +0800 Subject: [PATCH 1591/4254] minor improve the docs of parsecfg (#16208) --- lib/pure/parsecfg.nim | 52 ++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 15868c219..319f8f625 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -## The ``parsecfg`` module implements a high performance configuration file -## parser. The configuration file's syntax is similar to the Windows ``.ini`` +## The `parsecfg` module implements a high performance configuration file +## parser. The configuration file's syntax is similar to the Windows `.ini` ## format, but much more powerful, as it is not a line based parser. String ## literals, raw string literals and triple quoted string literals are supported ## as in the Nim programming language. @@ -116,9 +116,9 @@ include "system/inclrtl" type CfgEventKind* = enum ## enumeration of all events that may occur when parsing cfgEof, ## end of file reached - cfgSectionStart, ## a ``[section]`` has been parsed - cfgKeyValuePair, ## a ``key=value`` pair has been detected - cfgOption, ## a ``--key=value`` command line option + cfgSectionStart, ## a `[section]` has been parsed + cfgKeyValuePair, ## a `key=value` pair has been detected + cfgOption, ## a `--key=value` command line option cfgError ## an error occurred during parsing CfgEvent* = object of RootObj ## describes a parsing event @@ -126,12 +126,12 @@ type of cfgEof: nil of cfgSectionStart: section*: string ## `section` contains the name of the - ## parsed section start (syntax: ``[section]``) + ## parsed section start (syntax: `[section]`) of cfgKeyValuePair, cfgOption: key*, value*: string ## contains the (key, value) pair if an option - ## of the form ``--key: value`` or an ordinary - ## ``key= value`` pair has been parsed. - ## ``value==""`` if it was not specified in the + ## of the form `--key: value` or an ordinary + ## `key= value` pair has been parsed. + ## `value==""` if it was not specified in the ## configuration file. of cfgError: ## the parser encountered an error: `msg` msg*: string ## contains the error message. No exceptions @@ -157,7 +157,7 @@ proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.} proc open*(c: var CfgParser, input: Stream, filename: string, lineOffset = 0) {.rtl, extern: "npc$1".} = - ## initializes the parser with an input stream. `Filename` is only used + ## Initializes the parser with an input stream. `Filename` is only used ## for nice error messages. `lineOffset` can be used to influence the line ## number information in the generated error messages. lexbase.open(c, input) @@ -168,19 +168,19 @@ proc open*(c: var CfgParser, input: Stream, filename: string, rawGetTok(c, c.tok) proc close*(c: var CfgParser) {.rtl, extern: "npc$1".} = - ## closes the parser `c` and its associated input stream. + ## Closes the parser `c` and its associated input stream. lexbase.close(c) proc getColumn*(c: CfgParser): int {.rtl, extern: "npc$1".} = - ## get the current column the parser has arrived at. + ## Gets the current column the parser has arrived at. result = getColNumber(c, c.bufpos) proc getLine*(c: CfgParser): int {.rtl, extern: "npc$1".} = - ## get the current line the parser has arrived at. + ## Gets the current line the parser has arrived at. result = c.lineNumber proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} = - ## get the filename of the file that the parser processes. + ## Gets the filename of the file that the parser processes. result = c.filename proc handleHexChar(c: var CfgParser, xi: var int) = @@ -367,19 +367,19 @@ proc rawGetTok(c: var CfgParser, tok: var Token) = else: getSymbol(c, tok) proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = - ## returns a properly formatted error message containing current line and + ## Returns a properly formatted error message containing current line and ## column information. result = `%`("$1($2, $3) Error: $4", [c.filename, $getLine(c), $getColumn(c), msg]) proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = - ## returns a properly formatted warning message containing current line and + ## Returns a properly formatted warning message containing current line and ## column information. result = `%`("$1($2, $3) Warning: $4", [c.filename, $getLine(c), $getColumn(c), msg]) proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} = - ## returns a properly formatted warning message containing that + ## Returns a properly formatted warning message containing that ## an entry is ignored. case e.kind of cfgSectionStart: result = c.warningStr("section ignored: " & e.section) @@ -410,7 +410,7 @@ proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent = rawGetTok(c, c.tok) proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} = - ## retrieves the first/next event. This controls the parser. + ## Retrieves the first/next event. This controls the parser. case c.tok.kind of tkEof: result = CfgEvent(kind: cfgEof) @@ -442,12 +442,12 @@ type Config* = OrderedTableRef[string, OrderedTableRef[string, string]] proc newConfig*(): Config = - ## Create a new configuration table. + ## Creates a new configuration table. ## Useful when wanting to create a configuration file. result = newOrderedTable[string, OrderedTableRef[string, string]]() proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = - ## Load the specified configuration from stream into a new Config instance. + ## Loadw the specified configuration from stream into a new Config instance. ## `filename` parameter is only used for nicer error messages. var dict = newOrderedTable[string, OrderedTableRef[string, string]]() var curSection = "" ## Current section, @@ -480,7 +480,7 @@ proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = result = dict proc loadConfig*(filename: string): Config = - ## Load the specified configuration file into a new Config instance. + ## Loads the specified configuration file into a new Config instance. let file = open(filename, fmRead) let fileStream = newFileStream(file) defer: fileStream.close() @@ -505,7 +505,7 @@ proc replace(s: string): string = result = d proc writeConfig*(dict: Config, stream: Stream) = - ## Writes the contents of the table to the specified stream + ## Writes the contents of the table to the specified stream. ## ## **Note:** Comment statement will be ignored. for section, sectionData in dict.pairs(): @@ -546,7 +546,8 @@ proc writeConfig*(dict: Config, stream: Stream) = proc `$`*(dict: Config): string = ## Writes the contents of the table to string. - ## Note: Comment statement will be ignored. + ## + ## **Note:** Comment statement will be ignored. let stream = newStringStream() defer: stream.close() dict.writeConfig(stream) @@ -554,7 +555,8 @@ proc `$`*(dict: Config): string = proc writeConfig*(dict: Config, filename: string) = ## Writes the contents of the table to the specified configuration file. - ## Note: Comment statement will be ignored. + ## + ## **Note:** Comment statement will be ignored. let file = open(filename, fmWrite) defer: file.close() let fileStream = newFileStream(file) @@ -584,7 +586,7 @@ proc delSection*(dict: var Config, section: string) = dict.del(section) proc delSectionKey*(dict: var Config, section, key: string) = - ## Delete the key of the specified section. + ## Deletes the key of the specified section. if dict.hasKey(section): if dict[section].hasKey(key): if dict[section].len == 1: From e0b4f05053e87b5b498c53338eed643787783b18 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 1 Dec 2020 12:12:40 -0800 Subject: [PATCH 1592/4254] nimout now consistently uses nimoutCheck (#16189) --- testament/lib/stdtest/testutils.nim | 11 +++++++++++ testament/testament.nim | 16 ++++------------ tests/casestmt/tcaseexpr1.nim | 16 ++++++++-------- tests/stdlib/ttestutils.nim | 6 ++++++ 4 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 tests/stdlib/ttestutils.nim diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 8083a63e8..34aa3b751 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -1,4 +1,5 @@ import std/private/miscdollars +import std/strutils template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = ## API to deal with flaky or failing tests. This avoids disabling entire tests @@ -23,3 +24,13 @@ template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = msg2.add " FLAKY_FAILURE " msg2.add $expr & " " & msg echo msg2 + +proc greedyOrderedSubsetLines*(lhs, rhs: string): bool = + ## returns true if each stripped line in `lhs` appears in rhs, using a greedy matching. + let rhs = rhs.strip + var currentPos = 0 + for line in lhs.strip.splitLines: + currentPos = rhs.find(line.strip, currentPos) + if currentPos < 0: + return false + return true diff --git a/testament/testament.nim b/testament/testament.nim index f2ac9c338..58b3a8040 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -15,6 +15,7 @@ import algorithm, times, md5, sequtils, azure, intsets from std/sugar import dup import compiler/nodejs +import lib/stdtest/testutils var useColors = true var backendLogging = true @@ -364,7 +365,7 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarg checkForInlineErrors(r, expected, given, test, target) elif strip(expected.msg) notin strip(given.msg): r.addResult(test, target, expected.msg, given.msg, reMsgsDiffer) - elif expected.nimout.len > 0 and expected.nimout.normalizeMsg notin given.nimout.normalizeMsg: + elif expected.nimout.len > 0 and not greedyOrderedSubsetLines(expected.nimout, given.nimout): r.addResult(test, target, expected.nimout, given.nimout, reMsgsDiffer) elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: @@ -422,17 +423,8 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st echo getCurrentExceptionMsg() proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) = - let giv = given.nimout.strip - var currentPos = 0 - # Only check that nimout contains all expected lines in that order. - # There may be more output in nimout. It is ignored here. - for line in expectedNimout.strip.splitLines: - currentPos = giv.find(line.strip, currentPos) - if currentPos < 0: - given.err = reMsgsDiffer - break - - + if not greedyOrderedSubsetLines(expectedNimout, given.nimout): + given.err = reMsgsDiffer proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, expected: TSpec; r: var TResults) = diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim index 82af2410b..4f5bbf100 100644 --- a/tests/casestmt/tcaseexpr1.nim +++ b/tests/casestmt/tcaseexpr1.nim @@ -3,18 +3,18 @@ discard """ action: "reject" nimout: ''' tcaseexpr1.nim(33, 10) Error: not all cases are covered; missing: {C} +tcaseexpr1.nim(39, 12) Error: type mismatch: got but expected 'int literal(10)' ''' """ -#[ -# xxx make nimout comparison use nimoutCheck instead of: -elif expected.nimout.len > 0 and expected.nimout.normalizeMsg notin given.nimout.normalizeMsg: -and then use nimout: ''' -tcaseexpr1.nim(33, 10) Error: not all cases are covered2; missing: {C} -tcaseexpr1.nim(39, 12) Error: type mismatch: got but expected 'int literal(10)' -''' -]# + + + + + + + # line 20 diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim new file mode 100644 index 000000000..1a50d311b --- /dev/null +++ b/tests/stdlib/ttestutils.nim @@ -0,0 +1,6 @@ +import stdtest/testutils + +block: # greedyOrderedSubsetLines + doAssert greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") + doAssert not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order + doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs From ae9fe2b2f996abbab1f7f7d037a955a7cffa9b6a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 Dec 2020 22:34:52 +0100 Subject: [PATCH 1593/4254] ORC: API extensions (#16126) * ORC: API extensions * ORC: exploit a common special case --- lib/system/orc.nim | 59 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index b0497a836..4bd8952b7 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -71,7 +71,7 @@ type when useJumpStack: jumpStack: CellSeq # Lins' jump stack in order to speed up traversals toFree: CellSeq - freed, touched: int + freed, touched, edges, rcSum: int proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = if desc.traceImpl != nil: @@ -174,11 +174,14 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = if s.color != colGray: s.setColor colGray inc j.touched + # keep in mind that refcounts are zero based so add 1 here: + inc j.rcSum, (s.rc shr rcShift) + 1 orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty") trace(s, desc, j) while j.traceStack.len > 0: let (t, desc) = j.traceStack.pop() dec t.rc, rcIncrement + inc j.edges when useJumpStack: if (t.rc shr rcShift) >= 0 and (t.rc and jumpStackFlag) == 0: t.rc = t.rc or jumpStackFlag @@ -188,6 +191,8 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = if t.color != colGray: t.setColor colGray inc j.touched + # we already decremented its refcount so account for that: + inc j.rcSum, (t.rc shr rcShift) + 2 trace(t, desc, j) proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = @@ -254,8 +259,10 @@ when false: cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n", msg, s, s.rootIdx, s.rc shr rcShift, s.color) -proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = +proc collectColor(s: Cell; desc: PNimTypeV2; col: int; j: var GcEnv) = #[ + was: 'collectWhite'. + proc collectWhite(s: Cell) = if s.color == colWhite and not buffered(s): s.setColor(colBlack) @@ -263,7 +270,7 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = collectWhite(t) free(s) # watch out, a bug here! ]# - if s.color == colWhite and s.rootIdx == 0: + if s.color == col and s.rootIdx == 0: orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty") s.setColor(colBlack) @@ -271,12 +278,12 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) = trace(s, desc, j) while j.traceStack.len > 0: let (t, desc) = j.traceStack.pop() - if t.color == colWhite and t.rootIdx == 0: + if t.color == col and t.rootIdx == 0: j.toFree.add(t, desc) t.setColor(colBlack) trace(t, desc, j) -proc collectCyclesBacon(j: var GcEnv) = +proc collectCyclesBacon(j: var GcEnv; lowMark: int) = # pretty direct translation from # https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf # Fig. 2. Synchronous Cycle Collection @@ -290,20 +297,27 @@ proc collectCyclesBacon(j: var GcEnv) = s.buffered = false collectWhite(s) ]# + let last = roots.len - 1 when logOrc: - for i in 0 ..< roots.len: + for i in countdown(last, lowMark): writeCell("root", roots.d[i][0], roots.d[i][1]) - for i in 0 ..< roots.len: + for i in countdown(last, lowMark): markGray(roots.d[i][0], roots.d[i][1], j) - for i in 0 ..< roots.len: - scan(roots.d[i][0], roots.d[i][1], j) + + var colToCollect = colWhite + if j.rcSum == j.edges: + # short-cut: we know everything is garbage: + colToCollect = colGray + else: + for i in countdown(last, lowMark): + scan(roots.d[i][0], roots.d[i][1], j) init j.toFree for i in 0 ..< roots.len: let s = roots.d[i][0] s.rootIdx = 0 - collectWhite(s, roots.d[i][1], j) + collectColor(s, roots.d[i][1], colToCollect, j) for i in 0 ..< j.toFree.len: free(j.toFree.d[i][0], j.toFree.d[i][1]) @@ -320,6 +334,19 @@ when defined(nimStressOrc): else: var rootsThreshold = defaultThreshold +proc partialCollect(lowMark: int) = + if roots.len < 10 + lowMark: return + when logOrc: + cfprintf(cstderr, "[partialCollect] begin\n") + var j: GcEnv + init j.traceStack + collectCyclesBacon(j, lowMark) + when logOrc: + cfprintf(cstderr, "[partialCollect] end; freed %ld touched: %ld work: %ld\n", j.freed, j.touched, + roots.len - lowMark) + roots.len = lowMark + deinit j.traceStack + proc collectCycles() = ## Collect cycles. when logOrc: @@ -329,14 +356,14 @@ proc collectCycles() = init j.traceStack when useJumpStack: init j.jumpStack - collectCyclesBacon(j) + collectCyclesBacon(j, 0) while j.jumpStack.len > 0: let (t, desc) = j.jumpStack.pop # not in jump stack anymore! t.rc = t.rc and not jumpStackFlag deinit j.jumpStack else: - collectCyclesBacon(j) + collectCyclesBacon(j, 0) deinit j.traceStack deinit roots @@ -355,8 +382,8 @@ proc collectCycles() = elif rootsThreshold < high(int) div 4: rootsThreshold = rootsThreshold * 3 div 2 when logOrc: - cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld\n", j.freed, rootsThreshold, j.touched, - getOccupiedMem()) + cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld rcSum: %ld edges: %ld\n", j.freed, rootsThreshold, j.touched, + getOccupiedMem(), j.rcSum, j.edges) proc registerCycle(s: Cell; desc: PNimTypeV2) = s.rootIdx = roots.len+1 @@ -384,6 +411,10 @@ proc GC_disableOrc*() = when not defined(nimStressOrc): rootsThreshold = high(int) +proc GC_prepareOrc*(): int {.inline.} = roots.len + +proc GC_partialCollect*(limit: int) = + partialCollect(limit) proc GC_fullCollect* = ## Forces a full garbage collection pass. With ``--gc:orc`` triggers the cycle From cabfc7ec5cee16f9fca401716e429d3631dbe85c Mon Sep 17 00:00:00 2001 From: treeform Date: Tue, 1 Dec 2020 14:29:15 -0800 Subject: [PATCH 1594/4254] Don't add content-length header on GET request when there is no body. (#16196) * Don't add content-length header on GET request when there is no body. * Add space between the not and the (. * Take Dom's suggestion. --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 0cf19f031..880c05765 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -980,7 +980,7 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, var data: seq[string] if multipart != nil and multipart.content.len > 0: data = await client.format(multipart) - else: + elif httpMethod in ["POST", "PATCH", "PUT"] or body.len != 0: client.headers["Content-Length"] = $body.len when client is AsyncHttpClient: From 9fa5826d62156c1f6fdc765403bea2d3a098c10e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 2 Dec 2020 10:23:38 +0800 Subject: [PATCH 1595/4254] minor typo (#16225) --- lib/pure/parsecfg.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 319f8f625..9b140a809 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -447,7 +447,7 @@ proc newConfig*(): Config = result = newOrderedTable[string, OrderedTableRef[string, string]]() proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = - ## Loadw the specified configuration from stream into a new Config instance. + ## Loads the specified configuration from stream into a new Config instance. ## `filename` parameter is only used for nicer error messages. var dict = newOrderedTable[string, OrderedTableRef[string, string]]() var curSection = "" ## Current section, From 84f2ad3068cb77247ee6a263b2d375685b28b850 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 1 Dec 2020 21:09:08 -0800 Subject: [PATCH 1596/4254] add test for --eval; fix a minor bug (#16224) --- compiler/commands.nim | 1 + tests/misc/trunner.nim | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/compiler/commands.nim b/compiler/commands.nim index 916dfd66b..11bf628b4 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -450,6 +450,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.projectIsCmd = true conf.cmdInput = arg # can be empty (a nim file with empty content is valid too) if conf.cmd == cmdNone: + conf.command = "e" conf.setCmd cmdNimscript # better than `cmdCrun` as a default conf.implicitCmd = true of "path", "p": diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 018916e67..e288a56c7 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -216,3 +216,9 @@ mmain.html let file = testsDir / "misc/mimportc.nim" let cmd = fmt"{nim} r -b:cpp --hints:off --nimcache:{nimcache} --warningAsError:ProveInit {file}" check execCmdEx(cmd) == ("witness\n", 0) + + block: # nim --eval + let opt = "--hints:off" + check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0) + check fmt"""{nim} r {opt} --eval:"echo defined(c)"""".execCmdEx == ("true\n", 0) + check fmt"""{nim} r -b:js {opt} --eval:"echo defined(js)"""".execCmdEx == ("true\n", 0) From 5c23ba75456086e660d4baa1c43ec90ef8a2319d Mon Sep 17 00:00:00 2001 From: ihlec Date: Wed, 2 Dec 2020 09:15:29 +0100 Subject: [PATCH 1597/4254] fixed article duplication typos (#16216) --- compiler/nimlexbase.nim | 2 +- doc/manual.rst | 2 +- doc/regexprs.txt | 2 +- lib/packages/docutils/rstgen.nim | 2 +- lib/pure/collections/sequtils.nim | 2 +- lib/pure/math.nim | 2 +- lib/pure/streams.nim | 2 +- tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim | 2 +- tests/realtimeGC/readme.txt | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index 6132e6f66..99d07d093 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -61,7 +61,7 @@ proc handleCR*(L: var TBaseLexer, pos: int): int # position to continue the scanning from. `pos` must be the position # of the CR. proc handleLF*(L: var TBaseLexer, pos: int): int - # Call this if you scanned over LF in the buffer; it returns the the + # Call this if you scanned over LF in the buffer; it returns the # position to continue the scanning from. `pos` must be the position # of the LF. # implementation diff --git a/doc/manual.rst b/doc/manual.rst index 1a23c5997..97dbbda13 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1948,7 +1948,7 @@ Nim supports these `calling conventions`:idx:\: hardware stack. `inline`:idx: - The inline convention means the the caller should not call the procedure, + The inline convention means the caller should not call the procedure, but inline its code directly. Note that Nim does not inline, but leaves this to the C compiler; it generates ``__inline`` procedures. This is only a hint for the compiler: it may completely ignore it and diff --git a/doc/regexprs.txt b/doc/regexprs.txt index 83dbd2eeb..b7370d858 100644 --- a/doc/regexprs.txt +++ b/doc/regexprs.txt @@ -224,7 +224,7 @@ current matching point is at the end of the subject string, all of them fail, since there is no character to match. For compatibility with Perl, ``\s`` does not match the VT character (code 11). -This makes it different from the the POSIX "space" class. The ``\s`` characters +This makes it different from the POSIX "space" class. The ``\s`` characters are HT (9), LF (10), FF (12), CR (13), and space (32). A "word" character is an underscore or any character less than 256 that is diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 47b4189ba..d6bd26ad7 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -112,7 +112,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, ## it helps to prettify the generated index if no title is found. ## ## The ``RstParseOptions``, ``FindFileHandler`` and ``MsgHandler`` types - ## are defined in the the `packages/docutils/rst module `_. + ## are defined in the `packages/docutils/rst module `_. ## ``options`` selects the behaviour of the rst parser. ## ## ``findFile`` is a proc used by the rst ``include`` directive among others. diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index ea2c02b8c..71558fe0d 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1101,7 +1101,7 @@ macro mapLiterals*(constructor, op: untyped; iterator items*[T](xs: iterator: T): T = ## iterates over each element yielded by a closure iterator. This may ## not seem particularly useful on its own, but this allows closure - ## iterators to be used by the the mapIt, filterIt, allIt, anyIt, etc. + ## iterators to be used by the mapIt, filterIt, allIt, anyIt, etc. ## templates. for x in xs(): yield x diff --git a/lib/pure/math.nim b/lib/pure/math.nim index ccd766f46..8f5b9a6f5 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -622,7 +622,7 @@ when not defined(js): # C ## Note: Not available for JS backend. proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} - ## Computes the the `gamma function `_ for ``x``. + ## Computes the `gamma function `_ for ``x``. ## ## Note: Not available for JS backend. ## diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index de3f41f09..62a074bd8 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -346,7 +346,7 @@ proc write*[T](s: Stream, x: T) = writeData(s, unsafeAddr(x), sizeof(x)) proc write*(s: Stream, x: string) = - ## Writes the string `x` to the the stream `s`. No length field or + ## Writes the string `x` to the stream `s`. No length field or ## terminating zero is written. runnableExamples: var strm = newStringStream("") diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index 552b3e756..6eb1b3844 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -106,7 +106,7 @@ type #/ Collision begin event function callback type. #/ Returning false from a begin callback causes the collision to be ignored until - #/ the the separate callback is called when the objects stop colliding. + #/ the separate callback is called when the objects stop colliding. TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{. cdecl.} #/ Collision pre-solve event function callback type. diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt index b2788520e..c5837ee14 100644 --- a/tests/realtimeGC/readme.txt +++ b/tests/realtimeGC/readme.txt @@ -7,4 +7,4 @@ To build by hand and run the test for 35 minutes: xxx do we still need tests/realtimeGC/cmain.c? if so, tests/realtimeGC/cmain.c needs to updated and factorized with nmain.nim to avoid duplication (even if it's a C file) ``` - $ gcc -o tests/realtimeGC/cmain tests/realtimeGC/cmain.c -ldl + $ gcc -o tests/realtimeGC/cmain tests/realtimeGC/cmain.c -ldl \ No newline at end of file From e875f27ee6f57a24e0c9be36f3ab2d8780085a0c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 2 Dec 2020 16:34:34 +0800 Subject: [PATCH 1598/4254] [docs minor] better comparisons docs (#16201) --- lib/system/comparisons.nim | 179 ++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 90 deletions(-) diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 60ac554a6..71096addd 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -1,24 +1,24 @@ # comparison operators: -proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} +proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} = ## Checks whether values within the *same enum* have the same underlying value. - ## - ## .. code-block:: Nim - ## type - ## Enum1 = enum - ## Field1 = 3, Field2 - ## Enum2 = enum - ## Place1, Place2 = 3 - ## var - ## e1 = Field1 - ## e2 = Enum1(Place2) - ## echo (e1 == e2) # true - ## echo (e1 == Place2) # raises error -proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} - ## .. code-block:: Nim - ## var # this is a wildly dangerous example - ## a = cast[pointer](0) - ## b = cast[pointer](nil) - ## echo (a == b) # true due to the special meaning of `nil`/0 as a pointer + runnableExamples: + type + Enum1 = enum + Field1 = 3, Field2 + Enum2 = enum + Place1, Place2 = 3 + var + e1 = Field1 + e2 = Enum1(Place2) + assert e1 == e2 + assert not compiles(e1 == Place2) # raises error +proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} = + ## Checks for equality between two `pointer` variables. + runnableExamples: + var # this is a wildly dangerous example + a = cast[pointer](0) + b = cast[pointer](nil) + assert a == b # true due to the special meaning of `nil`/0 as a pointer proc `==`*(x, y: string): bool {.magic: "EqStr", noSideEffect.} ## Checks for equality between two `string` variables. @@ -26,13 +26,11 @@ proc `==`*(x, y: char): bool {.magic: "EqCh", noSideEffect.} ## Checks for equality between two `char` variables. proc `==`*(x, y: bool): bool {.magic: "EqB", noSideEffect.} ## Checks for equality between two `bool` variables. -proc `==`*[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} +proc `==`*[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} = ## Checks for equality between two variables of type `set`. - ## - ## .. code-block:: Nim - ## var a = {1, 2, 2, 3} # duplication in sets is ignored - ## var b = {1, 2, 3} - ## echo (a == b) # true + runnableExamples: + assert {1, 2, 2, 3} == {1, 2, 3} # duplication in sets is ignored + proc `==`*[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} ## Checks that two `ref` variables refer to the same item. proc `==`*[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} @@ -41,87 +39,87 @@ proc `==`*[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} ## Checks that two `proc` variables refer to the same procedure. proc `<=`*[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.} -proc `<=`*(x, y: string): bool {.magic: "LeStr", noSideEffect.} +proc `<=`*(x, y: string): bool {.magic: "LeStr", noSideEffect.} = ## Compares two strings and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = "abc" - ## b = "abd" - ## c = "ZZZ" - ## assert a <= b - ## assert a <= a - ## assert (a <= c) == false -proc `<=`*(x, y: char): bool {.magic: "LeCh", noSideEffect.} + runnableExamples: + let + a = "abc" + b = "abd" + c = "ZZZ" + assert a <= b + assert a <= a + assert not (a <= c) + +proc `<=`*(x, y: char): bool {.magic: "LeCh", noSideEffect.} = ## Compares two chars and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = 'a' - ## b = 'b' - ## c = 'Z' - ## assert a <= b - ## assert a <= a - ## assert (a <= c) == false -proc `<=`*[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} + runnableExamples: + let + a = 'a' + b = 'b' + c = 'Z' + assert a <= b + assert a <= a + assert not (a <= c) + +proc `<=`*[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} = ## Returns true if `x` is a subset of `y`. ## ## A subset `x` has all of its members in `y` and `y` doesn't necessarily ## have more members than `x`. That is, `x` can be equal to `y`. - ## - ## .. code-block:: Nim - ## let - ## a = {3, 5} - ## b = {1, 3, 5, 7} - ## c = {2} - ## assert a <= b - ## assert a <= a - ## assert (a <= c) == false + runnableExamples: + let + a = {3, 5} + b = {1, 3, 5, 7} + c = {2} + assert a <= b + assert a <= a + assert not (a <= c) + proc `<=`*(x, y: bool): bool {.magic: "LeB", noSideEffect.} proc `<=`*[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.} proc `<=`*(x, y: pointer): bool {.magic: "LePtr", noSideEffect.} proc `<`*[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.} -proc `<`*(x, y: string): bool {.magic: "LtStr", noSideEffect.} +proc `<`*(x, y: string): bool {.magic: "LtStr", noSideEffect.} = ## Compares two strings and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = "abc" - ## b = "abd" - ## c = "ZZZ" - ## assert a < b - ## assert (a < a) == false - ## assert (a < c) == false -proc `<`*(x, y: char): bool {.magic: "LtCh", noSideEffect.} + runnableExamples: + let + a = "abc" + b = "abd" + c = "ZZZ" + assert a < b + assert not (a < a) + assert not (a < c) + +proc `<`*(x, y: char): bool {.magic: "LtCh", noSideEffect.} = ## Compares two chars and returns true if `x` is lexicographically ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = 'a' - ## b = 'b' - ## c = 'Z' - ## assert a < b - ## assert (a < a) == false - ## assert (a < c) == false -proc `<`*[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} + runnableExamples: + let + a = 'a' + b = 'b' + c = 'Z' + assert a < b + assert not (a < a) + assert not (a < c) + +proc `<`*[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} = ## Returns true if `x` is a strict or proper subset of `y`. ## ## A strict or proper subset `x` has all of its members in `y` but `y` has ## more elements than `y`. - ## - ## .. code-block:: Nim - ## let - ## a = {3, 5} - ## b = {1, 3, 5, 7} - ## c = {2} - ## assert a < b - ## assert (a < a) == false - ## assert (a < c) == false + runnableExamples: + let + a = {3, 5} + b = {1, 3, 5, 7} + c = {2} + assert a < b + assert not (a < a) + assert not (a < c) + proc `<`*(x, y: bool): bool {.magic: "LtB", noSideEffect.} proc `<`*[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.} proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} @@ -252,11 +250,12 @@ proc max*[T](x: openArray[T]): T = proc clamp*[T](x, a, b: T): T = - ## Limits the value ``x`` within the interval [a, b]. - ## - ## .. code-block:: Nim - ## assert((1.4).clamp(0.0, 1.0) == 1.0) - ## assert((0.5).clamp(0.0, 1.0) == 0.5) + ## Limits the value `x` within the interval [a, b]. + ## This proc is equivalent to `max(a, min(b, x))`. + runnableExamples: + assert (1.4).clamp(0.0, 1.0) == 1.0 + assert (0.5).clamp(0.0, 1.0) == 0.5 + assert 4.clamp(1, 3) == max(1, min(3, 4)) if x < a: return a if x > b: return b return x From c0b76ef3cb08dc8d1547ed5d791427ba0c146802 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 2 Dec 2020 15:36:08 +0100 Subject: [PATCH 1599/4254] fix #16164, render doc comments (#16230) * fix #16164, render doc comments * add a test --- compiler/options.nim | 2 +- nimdoc/testproject/expected/testproject.html | 11 ++++++++++- nimdoc/testproject/expected/testproject.idx | 1 + nimdoc/testproject/expected/theindex.html | 4 ++++ nimdoc/testproject/testproject.nim | 3 +++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 42a907777..bf0a9a4ee 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -541,7 +541,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osDragonfly, osMacosx} else: discard -proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd notin cmdDocLike + {cmdIdeTools} +proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in cmdDocLike + {cmdIdeTools} proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc template compilationCachePresent*(conf: ConfigRef): untyped = diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index d9132d087..ee09b46af 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -120,7 +120,9 @@ function main() {
    • Vars @@ -427,6 +429,13 @@ Some shapes.

      Vars

      + +
      someVariable: bool
      +
      + +This should be visible. + +
      aVariable: array[1, int]
      diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 8d132acc4..5714efac0 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -1,3 +1,4 @@ +someVariable testproject.html#someVariable testproject: someVariable C_A testproject.html#C_A testproject: C_A C_B testproject.html#C_B testproject: C_B C_C testproject.html#C_C testproject: C_C diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 34d24e900..03d9c72fe 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -244,6 +244,10 @@ function main() {
    • utils: someType(): SomeType
    +
    someVariable:
    testNimDocTrailingExample:
    • testproject: testNimDocTrailingExample()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 3cb7fddc5..eea399f82 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -9,6 +9,9 @@ runnableExamples: # bug #11078 for x in "xx": discard + +var someVariable*: bool ## This should be visible. + when true: ## top2 runnableExamples: From 148d614dffbc93f1d8e6e6de3e8e64f64115ccdd Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 2 Dec 2020 23:24:59 +0800 Subject: [PATCH 1600/4254] js module also uses runnableExamples (#16229) --- lib/js/jsffi.nim | 51 ++++++++++++++++++++++-------------------------- lib/js/jsre.nim | 21 +++++++++----------- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index eedf45bb0..5140ff372 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -12,26 +12,25 @@ ## and ``JsAssoc`` together with the provided macros allows for smoother ## interfacing with JavaScript, allowing for example quick and easy imports of ## JavaScript variables: -## -## .. code-block:: nim -## -## # Here, we are using jQuery for just a few calls and do not want to wrap the -## # whole library: -## -## # import the document object and the console -## var document {.importc, nodecl.}: JsObject -## var console {.importc, nodecl.}: JsObject -## # import the "$" function -## proc jq(selector: JsObject): JsObject {.importcpp: "$$(#)".} -## -## # Use jQuery to make the following code run, after the document is ready. -## # This uses an experimental ``.()`` operator for ``JsObject``, to emit -## # JavaScript calls, when no corresponding proc exists for ``JsObject``. -## proc main = -## jq(document).ready(proc() = -## console.log("Hello JavaScript!") -## ) -## + +runnableExamples: + # Here, we are using jQuery for just a few calls and do not want to wrap the + # whole library: + + # import the document object and the console + var document {.importc, nodecl.}: JsObject + var console {.importc, nodecl.}: JsObject + # import the "$" function + proc jq(selector: JsObject): JsObject {.importcpp: "$$(#)".} + + # Use jQuery to make the following code run, after the document is ready. + # This uses an experimental ``.()`` operator for ``JsObject``, to emit + # JavaScript calls, when no corresponding proc exists for ``JsObject``. + proc main = + jq(document).ready(proc() = + console.log("Hello JavaScript!") + ) + when not defined(js) and not defined(nimdoc) and not defined(nimsuggest): {.fatal: "Module jsFFI is designed to be used with the JavaScript backend.".} @@ -221,14 +220,10 @@ proc `==`*(x, y: JsRoot): bool {.importcpp: "(# === #)".} macro `.`*(obj: JsObject, field: untyped): JsObject = ## Experimental dot accessor (get) for type JsObject. ## Returns the value of a property of name `field` from a JsObject `x`. - ## - ## Example: - ## - ## .. code-block:: nim - ## - ## let obj = newJsObject() - ## obj.a = 20 - ## console.log(obj.a) # puts 20 onto the console. + runnableExamples: + let obj = newJsObject() + obj.a = 20 + assert obj.a.to(int) == 20 if validJsName($field): let importString = "#." & $field result = quote do: diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index ff80056ea..f5c3cc1ac 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -1,17 +1,14 @@ ## Regular Expressions for the JavaScript target. ## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions -## -## Examples -## ======== -## -## .. code-block::nim -## let jsregex: RegExp = newRegExp(r"\s+", r"i") -## jsregex.compile(r"\w+", r"i") -## doAssert jsregex.test(r"nim javascript") -## doAssert jsregex.exec(r"nim javascript") == @["nim".cstring] -## doAssert jsregex.toString() == r"/\w+/i" -## jsregex.compile(r"[0-9]", r"i") -## doAssert jsregex.test(r"0123456789abcd") + +runnableExamples: + let jsregex: RegExp = newRegExp(r"\s+", r"i") + jsregex.compile(r"\w+", r"i") + doAssert jsregex.test(r"nim javascript") + doAssert jsregex.exec(r"nim javascript") == @["nim".cstring] + doAssert jsregex.toString() == r"/\w+/i" + jsregex.compile(r"[0-9]", r"i") + doAssert jsregex.test(r"0123456789abcd") when not defined(js) and not defined(Nimdoc): From d2bf0fb43c40253e3959715fb1fdf866c04559c2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 3 Dec 2020 00:06:23 +0800 Subject: [PATCH 1601/4254] small style changes and clarify clamp (#16228) * [docs minor]better comparisons docs * switch from PRNG to random module * apply suggestions * not compile * Revert "switch from PRNG to random module" This reverts commit 83b4d8946d7d677edac43b7675c41e230ba4e382. * small style changes and clarify clamp --- lib/system/comparisons.nim | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 71096addd..d9c7f6782 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -4,14 +4,14 @@ proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} = runnableExamples: type Enum1 = enum - Field1 = 3, Field2 + field1 = 3, field2 Enum2 = enum - Place1, Place2 = 3 + place1, place2 = 3 var - e1 = Field1 - e2 = Enum1(Place2) + e1 = field1 + e2 = Enum1(place2) assert e1 == e2 - assert not compiles(e1 == Place2) # raises error + assert not compiles(e1 == place2) # raises error proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} = ## Checks for equality between two `pointer` variables. runnableExamples: @@ -251,7 +251,9 @@ proc max*[T](x: openArray[T]): T = proc clamp*[T](x, a, b: T): T = ## Limits the value `x` within the interval [a, b]. - ## This proc is equivalent to `max(a, min(b, x))`. + ## This proc is equivalent to but fatser than `max(a, min(b, x))`. + ## + ## **Note that** `a < b` is assuemed and no check for it. runnableExamples: assert (1.4).clamp(0.0, 1.0) == 1.0 assert (0.5).clamp(0.0, 1.0) == 0.5 From af984a3db969d28961a9e765190c091c9aa30880 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 2 Dec 2020 17:18:51 +0100 Subject: [PATCH 1602/4254] Fix typo and improve grammar for clamps note --- lib/system/comparisons.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index d9c7f6782..a20e21064 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -253,7 +253,7 @@ proc clamp*[T](x, a, b: T): T = ## Limits the value `x` within the interval [a, b]. ## This proc is equivalent to but fatser than `max(a, min(b, x))`. ## - ## **Note that** `a < b` is assuemed and no check for it. + ## **Note:** `a < b` is assumed and will not be checked. runnableExamples: assert (1.4).clamp(0.0, 1.0) == 1.0 assert (0.5).clamp(0.0, 1.0) == 0.5 From 139075e96565f4b7436e8d2368f85f11852aa668 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 3 Dec 2020 02:30:55 +0800 Subject: [PATCH 1603/4254] move decode_helpers to std/private (#16209) --- lib/pure/cgi.nim | 2 +- lib/pure/uri.nim | 2 +- lib/{pure/includes => std/private}/decode_helpers.nim | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) rename lib/{pure/includes => std/private}/decode_helpers.nim (69%) diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index 1f0e0736a..cb64a3b1b 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -32,7 +32,7 @@ import strutils, os, strtabs, cookies, uri export uri.encodeUrl, uri.decodeUrl -include includes/decode_helpers +import std/private/decode_helpers proc addXmlChar(dest: var string, c: char) {.inline.} = case c diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 15d0996a7..5b16bfcb1 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -47,7 +47,7 @@ import std/private/since import strutils, parseutils, base64 -include includes/decode_helpers +import std/private/decode_helpers type diff --git a/lib/pure/includes/decode_helpers.nim b/lib/std/private/decode_helpers.nim similarity index 69% rename from lib/pure/includes/decode_helpers.nim rename to lib/std/private/decode_helpers.nim index 74fe37d07..586c7cae6 100644 --- a/lib/pure/includes/decode_helpers.nim +++ b/lib/std/private/decode_helpers.nim @@ -1,14 +1,12 @@ -# Include file that implements 'decodePercent' and friends. Do not import it! - -proc handleHexChar(c: char, x: var int, f: var bool) {.inline.} = +proc handleHexChar*(c: char, x: var int, f: var bool) {.inline.} = case c of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) else: f = true -proc decodePercent(s: string, i: var int): char = - ## Converts `%xx` hexadecimal to the charracter with ordinal number `xx`. +proc decodePercent*(s: openArray[char], i: var int): char = + ## Converts `%xx` hexadecimal to the character with ordinal number `xx`. ## ## If `xx` is not a valid hexadecimal value, it is left intact: only the ## leading `%` is returned as-is, and `xx` characters will be processed in the From 629b22e3d50e9903512ec893174eb797d9ed431b Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Wed, 2 Dec 2020 20:48:16 +0100 Subject: [PATCH 1604/4254] styleCheck: Fix error for `sugar` and `std/with` (#16176) With this commit, we no longer see an error if we pass `--styleCheck:error` when compiling a file that contains `import sugar` or `import std/with`. The problem was that those modules (and only those modules) import `std/private/underscored_calls`, which contained a styleCheck issue: its spelling of `nnkArgList` didn't match the `nnkArglist` spelling in `macros.nim`. This commit fixes the issue by renaming `nnkArgList` to `nnkArglist` repo-wide. The other way around would be a breaking change for code that used `nnkArglist` and `--styleCheck:error`. Fixes: #16174 --- doc/manual_experimental.rst | 2 +- lib/std/private/underscored_calls.nim | 2 +- tests/astspec/tastspec.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index caf3dfb48..dadcf62d4 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1250,7 +1250,7 @@ all the arguments, but also the matched operators in reverse polish notation: echo x + y * z - x This passes the expression ``x + y * z - x`` to the ``optM`` macro as -an ``nnkArgList`` node containing:: +an ``nnkArglist`` node containing:: Arglist Sym "x" diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim index f0bcbcc74..6d0a99ab5 100644 --- a/lib/std/private/underscored_calls.nim +++ b/lib/std/private/underscored_calls.nim @@ -39,7 +39,7 @@ proc underscoredCall(n, arg0: NimNode): NimNode = result.add arg0 proc underscoredCalls*(result, calls, arg0: NimNode) = - expectKind calls, {nnkArgList, nnkStmtList, nnkStmtListExpr} + expectKind calls, {nnkArglist, nnkStmtList, nnkStmtListExpr} for call in calls: if call.kind in {nnkStmtList, nnkStmtListExpr}: diff --git a/tests/astspec/tastspec.nim b/tests/astspec/tastspec.nim index e2cfed277..3413d32f3 100644 --- a/tests/astspec/tastspec.nim +++ b/tests/astspec/tastspec.nim @@ -929,7 +929,7 @@ static: (x & y & z) is string ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst: - of nnkTypeDef(_, _, nnkTypeClassTy(nnkArgList, _, _, nnkStmtList)): + of nnkTypeDef(_, _, nnkTypeClassTy(nnkArglist, _, _, nnkStmtList)): # note this isn't nnkConceptTy! echo "ok" From 849bc36edac47d5f62222ffc6beb015a770fc1f6 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 3 Dec 2020 19:15:36 +0800 Subject: [PATCH 1605/4254] merge two parsecfg tests into one (#16237) * try to fix #16206 * merge two parsecfg tests into one * Revert "fix" This reverts commit 668bdec2c499cf9967abfb7aad24975a04b092eb. * Revert "try to fix #16206" This reverts commit c399cc2153190299c9cbb0ad83f6ce85a7bbbb89. --- tests/stdlib/tparscfg.nim | 56 ----------------------- tests/stdlib/tparsecfg.nim | 91 +++++++++++++++++++++++++++++++------- 2 files changed, 74 insertions(+), 73 deletions(-) delete mode 100644 tests/stdlib/tparscfg.nim diff --git a/tests/stdlib/tparscfg.nim b/tests/stdlib/tparscfg.nim deleted file mode 100644 index ddb9b02b7..000000000 --- a/tests/stdlib/tparscfg.nim +++ /dev/null @@ -1,56 +0,0 @@ -discard """ - targets: "c js" -""" -import parsecfg, streams - -## Creating a configuration file. -var dict1=newConfig() -dict1.setSectionKey("","charset","utf-8") -dict1.setSectionKey("Package","name","hello") -dict1.setSectionKey("Package","--threads","on") -dict1.setSectionKey("Author","name","lihf8515") -dict1.setSectionKey("Author","qq","10214028") -dict1.setSectionKey("Author","email","lihaifeng@wxm.com") -var ss = newStringStream() -dict1.writeConfig(ss) - -## Reading a configuration file. -var dict2 = loadConfig(newStringStream(ss.data)) -var charset = dict2.getSectionValue("","charset") -var threads = dict2.getSectionValue("Package","--threads") -var pname = dict2.getSectionValue("Package","name") -var name = dict2.getSectionValue("Author","name") -var qq = dict2.getSectionValue("Author","qq") -var email = dict2.getSectionValue("Author","email") -doAssert charset == "utf-8" -doAssert threads == "on" -doAssert pname == "hello" -doAssert name == "lihf8515" -doAssert qq == "10214028" -doAssert email == "lihaifeng@wxm.com" - -## Modifying a configuration file. -var dict3 = loadConfig(newStringStream(ss.data)) -dict3.setSectionKey("Author","name","lhf") -doAssert $dict3 == """charset=utf-8 -[Package] -name=hello ---threads:on -[Author] -name=lhf -qq=10214028 -email="lihaifeng@wxm.com" -""" - -## Deleting a section key in a configuration file. -var dict4 = loadConfig(newStringStream(ss.data)) -dict4.delSectionKey("Author","email") -doAssert $dict4 == """charset=utf-8 -[Package] -name=hello ---threads:on -[Author] -name=lihf8515 -qq=10214028 -""" - diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim index 1c214e5d2..45dea0531 100644 --- a/tests/stdlib/tparsecfg.nim +++ b/tests/stdlib/tparsecfg.nim @@ -1,23 +1,80 @@ discard """ - output: '''OK''' + targets: "c js" """ -#bug #6046 -import parsecfg +import parsecfg, streams -var config = newConfig() -config.setSectionKey("foo","bar","-1") -config.setSectionKey("foo","foo","abc") -config.writeConfig("test.ini") +when not defined(js): + # bug #6046 + var config = newConfig() + config.setSectionKey("foo", "bar", "-1") + config.setSectionKey("foo", "foo", "abc") -# test.ini now contains -# [foo] -# bar=-1 -# foo=abc + from stdtest/specialpaths import buildDir + import os -var config2 = loadConfig("test.ini") -let bar = config2.getSectionValue("foo","bar") -let foo = config2.getSectionValue("foo","foo") -assert(bar == "-1") -assert(foo == "abc") -echo "OK" + const file = buildDir / "tparsecfg.ini" + config.writeConfig(file) + + # file now contains + # [foo] + # bar=-1 + # foo=abc + + var config2 = loadConfig(file) + let bar = config2.getSectionValue("foo", "bar") + let foo = config2.getSectionValue("foo", "foo") + assert(bar == "-1") + assert(foo == "abc") + + +## Creating a configuration file. +var dict1 = newConfig() +dict1.setSectionKey("", "charset", "utf-8") +dict1.setSectionKey("Package", "name", "hello") +dict1.setSectionKey("Package", "--threads", "on") +dict1.setSectionKey("Author", "name", "lihf8515") +dict1.setSectionKey("Author", "qq", "10214028") +dict1.setSectionKey("Author", "email", "lihaifeng@wxm.com") +var ss = newStringStream() +dict1.writeConfig(ss) + +## Reading a configuration file. +var dict2 = loadConfig(newStringStream(ss.data)) +var charset = dict2.getSectionValue("", "charset") +var threads = dict2.getSectionValue("Package", "--threads") +var pname = dict2.getSectionValue("Package", "name") +var name = dict2.getSectionValue("Author", "name") +var qq = dict2.getSectionValue("Author", "qq") +var email = dict2.getSectionValue("Author", "email") +doAssert charset == "utf-8" +doAssert threads == "on" +doAssert pname == "hello" +doAssert name == "lihf8515" +doAssert qq == "10214028" +doAssert email == "lihaifeng@wxm.com" + +## Modifying a configuration file. +var dict3 = loadConfig(newStringStream(ss.data)) +dict3.setSectionKey("Author", "name", "lhf") +doAssert $dict3 == """charset=utf-8 +[Package] +name=hello +--threads:on +[Author] +name=lhf +qq=10214028 +email="lihaifeng@wxm.com" +""" + +## Deleting a section key in a configuration file. +var dict4 = loadConfig(newStringStream(ss.data)) +dict4.delSectionKey("Author", "email") +doAssert $dict4 == """charset=utf-8 +[Package] +name=hello +--threads:on +[Author] +name=lihf8515 +qq=10214028 +""" From 23447ffdce7415e2313654a61bdd9a23803f6538 Mon Sep 17 00:00:00 2001 From: Aditya Siram Date: Thu, 3 Dec 2020 06:40:28 -0600 Subject: [PATCH 1606/4254] Fixes #16219, `hasArgOfName` ignoring argument sets. (#16233) * Fixes #16219, `hasArgOfName` ignoring argument sets. * Fix test and simplify ident traversal. * Moved test into a block and removed some boilerplate. * Fix some argument formatting. * use ..< * Change the preceding line too Co-authored-by: Clyybber --- lib/core/macros.nim | 8 ++++---- tests/stdlib/tmacros.nim | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 tests/stdlib/tmacros.nim diff --git a/lib/core/macros.nim b/lib/core/macros.nim index d2985bc72..97c3a46c5 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1434,10 +1434,10 @@ proc expectIdent*(n: NimNode, name: string) {.compileTime, since: (1,1).} = proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}= ## Search ``nnkFormalParams`` for an argument. expectKind(params, nnkFormalParams) - for i in 1 ..< params.len: - template node: untyped = params[i] - if name.eqIdent( $ node[0]): - return true + for i in 1.. Date: Thu, 3 Dec 2020 21:47:44 +0800 Subject: [PATCH 1607/4254] better setops docs (#16236) * js module also uses runnableExamples * better setops docs * Update lib/system/setops.nim * better * Update lib/system/setops.nim * Update lib/system/setops.nim * better * better --- lib/system/setops.nim | 136 ++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 72 deletions(-) diff --git a/lib/system/setops.nim b/lib/system/setops.nim index 97f042d93..755eafdb8 100644 --- a/lib/system/setops.nim +++ b/lib/system/setops.nim @@ -1,94 +1,86 @@ -proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.} - ## Includes element ``y`` in the set ``x``. +func incl*[T](x: var set[T], y: T) {.magic: "Incl".} = + ## Includes element `y` in the set `x`. ## - ## This is the same as ``x = x + {y}``, but it might be more efficient. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5} - ## a.incl(2) # a <- {1, 2, 3, 5} - ## a.incl(4) # a <- {1, 2, 3, 4, 5} + ## This is the same as `x = x + {y}`, but it might be more efficient. + runnableExamples: + var a = {1, 3, 5} + a.incl(2) + assert a == {1, 2, 3, 5} + a.incl(4) + assert a == {1, 2, 3, 4, 5} template incl*[T](x: var set[T], y: set[T]) = - ## Includes the set ``y`` in the set ``x``. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5, 7} - ## var b = {4, 5, 6} - ## a.incl(b) # a <- {1, 3, 4, 5, 6, 7} + ## Includes the set `y` in the set `x`. + runnableExamples: + var a = {1, 3, 5, 7} + var b = {4, 5, 6} + a.incl(b) + assert a == {1, 3, 4, 5, 6, 7} x = x + y -proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.} - ## Excludes element ``y`` from the set ``x``. +func excl*[T](x: var set[T], y: T) {.magic: "Excl".} = + ## Excludes element `y` from the set `x`. ## - ## This is the same as ``x = x - {y}``, but it might be more efficient. - ## - ## .. code-block:: Nim - ## var b = {2, 3, 5, 6, 12, 545} - ## b.excl(5) # b <- {2, 3, 6, 12, 545} + ## This is the same as `x = x - {y}`, but it might be more efficient. + runnableExamples: + var b = {2, 3, 5, 6, 12, 545} + b.excl(5) + assert b == {2, 3, 6, 12, 545} template excl*[T](x: var set[T], y: set[T]) = - ## Excludes the set ``y`` from the set ``x``. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5, 7} - ## var b = {3, 4, 5} - ## a.excl(b) # a <- {1, 7} + ## Excludes the set `y` from the set `x`. + runnableExamples: + var a = {1, 3, 5, 7} + var b = {3, 4, 5} + a.excl(b) + assert a == {1, 7} x = x - y -proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.} - ## Returns the cardinality of the set ``x``, i.e. the number of elements +func card*[T](x: set[T]): int {.magic: "Card".} = + ## Returns the cardinality of the set `x`, i.e. the number of elements ## in the set. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5, 7} - ## echo card(a) # => 4 + runnableExamples: + var a = {1, 3, 5, 7} + assert card(a) == 4 + var b = {1, 3, 5, 7, 5} + assert card(b) == 4 # repeated 5 doesn't count -proc len*[T](x: set[T]): int {.magic: "Card", noSideEffect.} +func len*[T](x: set[T]): int {.magic: "Card".} ## An alias for `card(x)`. -proc `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.} +func `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet".} = ## This operator computes the intersection of two sets. - ## - ## .. code-block:: Nim - ## let - ## a = {1, 2, 3} - ## b = {2, 3, 4} - ## echo a * b # => {2, 3} -proc `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet", noSideEffect.} - ## This operator computes the union of two sets. - ## - ## .. code-block:: Nim - ## let - ## a = {1, 2, 3} - ## b = {2, 3, 4} - ## echo a + b # => {1, 2, 3, 4} -proc `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet", noSideEffect.} - ## This operator computes the difference of two sets. - ## - ## .. code-block:: Nim - ## let - ## a = {1, 2, 3} - ## b = {2, 3, 4} - ## echo a - b # => {1} + runnableExamples: + assert {1, 2, 3} * {2, 3, 4} == {2, 3} -proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} - ## One should overload this proc if one wants to overload the ``in`` operator. +func `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet".} = + ## This operator computes the union of two sets. + runnableExamples: + assert {1, 2, 3} + {2, 3, 4} == {1, 2, 3, 4} + +func `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet".} = + ## This operator computes the difference of two sets. + runnableExamples: + assert {1, 2, 3} - {2, 3, 4} == {1} + +func contains*[T](x: set[T], y: T): bool {.magic: "InSet".} = + ## One should overload this proc if one wants to overload the `in` operator. ## - ## The parameters are in reverse order! ``a in b`` is a template for - ## ``contains(b, a)``. + ## The parameters are in reverse order! `a in b` is a template for + ## `contains(b, a)`. ## This is because the unification algorithm that Nim uses for overload ## resolution works from left to right. - ## But for the ``in`` operator that would be the wrong direction for this + ## But for the `in` operator that would be the wrong direction for this ## piece of code: - ## - ## .. code-block:: Nim - ## var s: set[range['a'..'z']] = {'a'..'c'} - ## assert s.contains('c') - ## assert 'b' in s - ## - ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would - ## have been bound to ``char``. But ``s`` is not compatible to type - ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This - ## is achieved by reversing the parameters for ``contains``; ``in`` then + runnableExamples: + var s: set[range['a'..'z']] = {'a'..'c'} + assert s.contains('c') + assert 'b' in s + assert 'd' notin s + assert set['a'..'z'] is set[range['a'..'z']] + ## If `in` had been declared as `[T](elem: T, s: set[T])` then `T` would + ## have been bound to `char`. But `s` is not compatible to type + ## `set[char]`! The solution is to bind `T` to `range['a'..'z']`. This + ## is achieved by reversing the parameters for `contains`; `in` then ## passes its arguments in reverse order. From c731f7ab149a539782b0b000853ecef058bc3dde Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 3 Dec 2020 07:55:43 -0800 Subject: [PATCH 1608/4254] fixes #15939, fixes #15464, fixes #16169, fixes #16226 VM now supports `addr(mystring[ind])` (index + index assignment) (#15987) * fix #15939, fix #15464 VM now supports `addr(mystring[ind])` (index + index assignment), var char return etc * cleanups * cstring tests * add test for bug #15464 * improve test coverage --- changelog.md | 1 + compiler/vm.nim | 21 +++++++++++++- compiler/vmdef.nim | 1 + compiler/vmgen.nim | 10 ++++--- tests/misc/taddr.nim | 66 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index d62e96bbe..5b22a174b 100644 --- a/changelog.md +++ b/changelog.md @@ -69,6 +69,7 @@ - Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`. +- VM now supports `addr(mystring[ind])` (index + index assignment) ## Tool changes diff --git a/compiler/vm.nim b/compiler/vm.nim index 17bbe65fc..34d76f21e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -20,6 +20,7 @@ import from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate +from magicsys import getSysType const traceCode = defined(nimVMDebug) @@ -123,7 +124,7 @@ proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: b else: r.ensureKind(rkind) let val = cast[ptr T](address)[] - when T is SomeInteger: + when T is SomeInteger | char: r.field = BiggestInt(val) else: r.field = val @@ -131,6 +132,7 @@ proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: b ## see also typeinfo.getBiggestInt case typ.kind + of tyChar: fun(intVal, char, rkInt) of tyInt: fun(intVal, int, rkInt) of tyInt8: fun(intVal, int8, rkInt) of tyInt16: fun(intVal, int16, rkInt) @@ -677,6 +679,23 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].intVal = s[idx].ord else: stackTrace(c, tos, pc, formatErrorIndexBound(idx, s.len-1)) + of opcLdStrIdxAddr: + # a = addr(b[c]); similar to opcLdArrAddr + decodeBC(rkNode) + if regs[rc].intVal > high(int): + stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int))) + let idx = regs[rc].intVal.int + let s = regs[rb].node.strVal.addr # or `byaddr` + if idx <% s[].len: + # `makePtrType` not accessible from vm.nim + let typ = newType(tyPtr, nextId c.idgen, c.module.owner) + typ.add getSysType(c.graph, c.debug[pc], tyChar) + let node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit + node.intVal = cast[int](s[][idx].addr) + node.flags.incl nfIsPtr + regs[ra].node = node + else: + stackTrace(c, tos, pc, formatErrorIndexBound(idx, s[].len-1)) of opcWrArr: # a[b] = c decodeBC(rkNode) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 202087af7..6d6c55250 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -78,6 +78,7 @@ type opcWrDeref, opcWrStrIdx, opcLdStrIdx, # a = b[c] + opcLdStrIdxAddr, # a = addr(b[c]) opcAddInt, opcAddImmInt, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 84ff1a91d..29ab8739d 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1654,8 +1654,8 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; let a = c.genx(n[0], flags) let b = c.genIndex(n[1], n[0].typ) if dest < 0: dest = c.getTemp(n.typ) - if opc == opcLdArr and {gfNodeAddr} * flags != {}: - c.gABC(n, opcLdArrAddr, dest, a, b) + if opc in {opcLdArrAddr, opcLdStrIdxAddr} and gfNodeAddr in flags: + c.gABC(n, opc, dest, a, b) elif needsRegLoad(): var cc = c.getTemp(n.typ) c.gABC(n, opc, cc, a, b) @@ -1749,11 +1749,13 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind if arrayType in {tyString, tyCString}: - genArrAccessOpcode(c, n, dest, opcLdStrIdx, {}) + let opc = if gfNodeAddr in flags: opcLdStrIdxAddr else: opcLdStrIdx + genArrAccessOpcode(c, n, dest, opc, flags) elif arrayType == tyTypeDesc: c.genTypeLit(n.typ, dest) else: - genArrAccessOpcode(c, n, dest, opcLdArr, flags) + let opc = if gfNodeAddr in flags: opcLdArrAddr else: opcLdArr + genArrAccessOpcode(c, n, dest, opc, flags) proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) = if t != nil and t.len > 0 and t[0] != nil: diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim index d743d4b4a..bac26896d 100644 --- a/tests/misc/taddr.nim +++ b/tests/misc/taddr.nim @@ -196,10 +196,76 @@ template test14339() = # bug #14339 when not defined(js): # pending bug #16003 doAssert a.val == 5 +template testStatic15464() = # bug #15464 + proc access(s: var seq[char], i: int): var char = s[i] + proc access(s: var string, i: int): var char = s[i] + static: + var s = @['a', 'b', 'c'] + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + static: + var s = "abc" + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + +proc test15464() = # bug #15464 (v2) + proc access(s: var seq[char], i: int): var char = s[i] + proc access(s: var string, i: int): var char = s[i] + block: + var s = @['a', 'b', 'c'] + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + block: + var s = "abc" + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + +block: # bug #15939 + block: + const foo = "foo" + proc proc1(s: var string) = + if s[^1] notin {'a'..'z'}: + s = "" + proc proc2(f: string): string = + result = f + proc1(result) + const bar = proc2(foo) + doAssert bar == "foo" + +proc test15939() = # bug #15939 (v2) + template fn(a) = + let pa = a[0].addr + doAssert pa != nil + doAssert pa[] == 'a' + pa[] = 'x' + doAssert pa[] == 'x' + doAssert a == "xbc" + when not defined js: # otherwise overflows + let pa2 = cast[ptr char](cast[int](pa) + 1) + doAssert pa2[] == 'b' + pa2[] = 'B' + doAssert a == "xBc" + + # mystring[ind].addr + var a = "abc" + fn(a) + + # mycstring[ind].addr + template cstringTest = + var a2 = "abc" + var b2 = a2.cstring + fn(b2) + when nimvm: cstringTest() + else: # can't take address of cstring element in js + when not defined(js): cstringTest() + template main = # xxx wrap all other tests here like that so they're also tested in VM test14420() test14339() + test15464() + test15939() +testStatic15464() static: main() main() From e223a05123144ae8a030b2c22f4b7d8b23784314 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 3 Dec 2020 19:09:54 +0300 Subject: [PATCH 1609/4254] minor fix to Posix part of walkDir (#16234) * change break->continue and rewrite one-yield-style * use case statement for clarity * Tiny nit Co-authored-by: Clyybber --- lib/pure/os.nim | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index aa2a1aaa8..77499deea 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2120,21 +2120,27 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): y = path var k = pcFile + template kSetGeneric() = # pure Posix component `k` resolution + if lstat(path, s) < 0'i32: continue # don't yield + elif S_ISDIR(s.st_mode): + k = pcDir + elif S_ISLNK(s.st_mode): + k = getSymlinkFileKind(path) + when defined(linux) or defined(macosx) or defined(bsd) or defined(genode) or defined(nintendoswitch): - if x.d_type != DT_UNKNOWN: - if x.d_type == DT_DIR: k = pcDir - if x.d_type == DT_LNK: - if dirExists(path): k = pcLinkToDir - else: k = pcLinkToFile - yield (k, y) - continue + case x.d_type + of DT_DIR: k = pcDir + of DT_LNK: + if dirExists(path): k = pcLinkToDir + else: k = pcLinkToFile + of DT_UNKNOWN: + kSetGeneric() + else: # e.g. DT_REG etc + discard # leave it as pcFile + else: # assuming that field `d_type` is not present + kSetGeneric() - if lstat(path, s) < 0'i32: break - if S_ISDIR(s.st_mode): - k = pcDir - elif S_ISLNK(s.st_mode): - k = getSymlinkFileKind(path) yield (k, y) iterator walkDirRec*(dir: string, From 545c406cbeb9d312e29f7363727c0eb9b37b7da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alf-Andr=C3=A9=20Walla?= Date: Thu, 3 Dec 2020 17:33:42 +0100 Subject: [PATCH 1610/4254] Add 32-bit RISC-V support (#16231) --- compiler/installer.ini | 2 +- compiler/platform.nim | 3 ++- lib/system.nim | 2 +- lib/system/platforms.nim | 4 +++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index f0756ab3e..ecd1f7475 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -6,7 +6,7 @@ Name: "Nim" Version: "$version" Platforms: """ windows: i386;amd64 - linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64 + linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64 macosx: i386;amd64;powerpc64 solaris: i386;amd64;sparc;sparc64 freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el diff --git a/compiler/platform.nim b/compiler/platform.nim index 78c523c1a..714946315 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -193,7 +193,7 @@ type cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430, - cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuEsp, cpuWasm32 + cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32 type TEndian* = enum @@ -226,6 +226,7 @@ const (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64), (name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64), (name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), + (name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)] diff --git a/lib/system.nim b/lib/system.nim index c13b419ef..76bcd4eec 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1068,7 +1068,7 @@ const ## Possible values: ## `"i386"`, `"alpha"`, `"powerpc"`, `"powerpc64"`, `"powerpc64el"`, ## `"sparc"`, `"amd64"`, `"mips"`, `"mipsel"`, `"arm"`, `"arm64"`, - ## `"mips64"`, `"mips64el"`, `"riscv64"`. + ## `"mips64"`, `"mips64el"`, `"riscv32"`, `"riscv64"`. seqShallowFlag = low(int) strlitFlag = 1 shl (sizeof(int)*8 - 2) # later versions of the codegen \ diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim index 6e39dc7f2..59a1333f1 100644 --- a/lib/system/platforms.nim +++ b/lib/system/platforms.nim @@ -33,7 +33,8 @@ type vm, ## Some Virtual machine: Nim's VM or JavaScript avr, ## AVR based processor msp430, ## TI MSP430 microcontroller - riscv64 ## RISC-V 64-bit processor + riscv32, ## RISC-V 32-bit processor + riscv64, ## RISC-V 64-bit processor wasm32 ## WASM, 32-bit OsPlatform* {.pure.} = enum ## the OS this program will run on. @@ -91,6 +92,7 @@ const elif defined(vm): CpuPlatform.vm elif defined(avr): CpuPlatform.avr elif defined(msp430): CpuPlatform.msp430 + elif defined(riscv32): CpuPlatform.riscv32 elif defined(riscv64): CpuPlatform.riscv64 elif defined(wasm32): CpuPlatform.wasm32 else: CpuPlatform.none From 2220aaeaef74cb6018f4689af8f280db22cb30dd Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 3 Dec 2020 17:34:30 +0100 Subject: [PATCH 1611/4254] add support for parsing chars in `scanf` macro (#16240) --- changelog.md | 4 ++++ lib/pure/parseutils.nim | 4 ++++ lib/pure/strscans.nim | 7 +++++++ tests/stdlib/tstrscans.nim | 19 ++++++++++++++++++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 5b22a174b..05958118b 100644 --- a/changelog.md +++ b/changelog.md @@ -52,6 +52,9 @@ - `writeStackTrace` is available in JS backend now. +- `strscans.scanf` now supports parsing single characters. + + ## Language changes - `nimscript` now handles `except Exception as e`. @@ -60,6 +63,7 @@ - nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. + ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 29159816d..ccfac2a7e 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -241,6 +241,10 @@ proc parseIdent*(s: string, start = 0): string = while i < s.len and s[i] in IdentChars: inc(i) result = substr(s, start, i-1) +proc parseChar*(s: string, ident: var char, start = 0): int = + ident = s[start] + result = 1 + proc skipWhitespace*(s: string, start = 0): int {.inline.} = ## Skips the whitespace starting at ``s[start]``. Returns the number of ## skipped characters. diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index f7032f428..347dbc2ef 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -37,6 +37,7 @@ substrings starting with ``$``. These constructions are available: ``$h`` Matches a hex integer. This uses ``parseutils.parseHex``. ``$f`` Matches a floating pointer number. Uses ``parseFloat``. ``$w`` Matches an ASCII identifier: ``[A-Za-z_][A-Za-z_0-9]*``. +``$c`` Matches a single ASCII character. ``$s`` Skips optional whitespace. ``$$`` Matches a single dollar sign. ``$.`` Matches if the end of the input string has been reached. @@ -345,6 +346,12 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: matchError inc i + of 'c': + if i < results.len and getType(results[i]).typeKind == ntyChar: + matchBind "parseChar" + else: + matchError + inc i of 'b': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseBin" diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index 9d6f51025..8ca167837 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -2,7 +2,7 @@ discard """ output: "" """ -import strscans +import strscans, strutils block ParsePasswd: proc parsePasswd(content: string): seq[string] = @@ -210,3 +210,20 @@ block: var a: int discard scanf(test(), ",$i", a) doAssert count == 1 + + +block: + let input = """1-3 s: abc +15-18 9: def +15-18 A: ghi +15-18 _: jkl +""" + var + lo, hi: int + w: string + c: char + res: int + for line in input.splitLines: + if line.scanf("$i-$i $c: $w", lo, hi, c, w): + inc res + doAssert res == 4 From 808ab7eae22536167445818c9a4650d36e87d39a Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Thu, 3 Dec 2020 21:32:18 +0200 Subject: [PATCH 1612/4254] add collect with infered init, refs #16078 fixes #14332 (#16089) * changelog * add testcase, fixes #14332 --- changelog.md | 3 ++ lib/pure/sugar.nim | 100 ++++++++++++++++++++++++++-------------- tests/stdlib/tsugar.nim | 22 +++++++-- 3 files changed, 88 insertions(+), 37 deletions(-) diff --git a/changelog.md b/changelog.md index 05958118b..bb49dc7f6 100644 --- a/changelog.md +++ b/changelog.md @@ -22,6 +22,9 @@ literals remain in the "raw" string form so that client code can easily treat small and large numbers uniformly. +- Added an overload for the `collect` macro that inferes the container type based + on the syntax of the last expression. Works with std seqs, tables and sets. + - Added `randState` template that exposes the default random number generator. Useful for library authors. diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 047104972..686729515 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -58,7 +58,7 @@ macro `=>`*(p, b: untyped): untyped = runnableExamples: proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) - + doAssert passTwoAndTwo((x, y) => x + y) == 4 type @@ -270,54 +270,79 @@ since (1, 1): underscoredCalls(result, calls, tmp) result.add tmp - -proc transLastStmt(n, res, bracketExpr: NimNode): (NimNode, NimNode, NimNode) {.since: (1, 1).} = +proc trans(n, res, bracketExpr: NimNode): (NimNode, NimNode, NimNode) {.since: (1, 1).} = # Looks for the last statement of the last statement, etc... case n.kind - of nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt: + of nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt, nnkWhenStmt: result[0] = copyNimTree(n) result[1] = copyNimTree(n) result[2] = copyNimTree(n) - for i in ord(n.kind == nnkCaseStmt)..= 1: - (result[0][^1], result[1][^1], result[2][^1]) = transLastStmt(n[^1], res, bracketExpr) + (result[0][^1], result[1][^1], result[2][^1]) = trans(n[^1], + res, bracketExpr) of nnkTableConstr: result[1] = n[0][0] result[2] = n[0][1] + if bracketExpr.len == 0: + bracketExpr.add(ident"initTable") # don't import tables if bracketExpr.len == 1: - bracketExpr.add([newCall(bindSym"typeof", newEmptyNode()), newCall( - bindSym"typeof", newEmptyNode())]) + bracketExpr.add([newCall(bindSym"typeof", + newEmptyNode()), newCall(bindSym"typeof", newEmptyNode())]) template adder(res, k, v) = res[k] = v result[0] = getAst(adder(res, n[0][0], n[0][1])) of nnkCurly: result[2] = n[0] + if bracketExpr.len == 0: + bracketExpr.add(ident"initHashSet") if bracketExpr.len == 1: bracketExpr.add(newCall(bindSym"typeof", newEmptyNode())) template adder(res, v) = res.incl(v) result[0] = getAst(adder(res, n[0])) else: result[2] = n + if bracketExpr.len == 0: + bracketExpr.add(bindSym"newSeq") if bracketExpr.len == 1: bracketExpr.add(newCall(bindSym"typeof", newEmptyNode())) template adder(res, v) = res.add(v) result[0] = getAst(adder(res, n)) +proc collectImpl(init, body: NimNode): NimNode {.since: (1, 1).} = + let res = genSym(nskVar, "collectResult") + var bracketExpr: NimNode + if init != nil: + expectKind init, {nnkCall, nnkIdent, nnkSym} + bracketExpr = newTree(nnkBracketExpr, + if init.kind == nnkCall: freshIdentNodes(init[0]) else: freshIdentNodes(init)) + else: + bracketExpr = newTree(nnkBracketExpr) + let (resBody, keyType, valueType) = trans(body, res, bracketExpr) + if bracketExpr.len == 3: + bracketExpr[1][1] = keyType + bracketExpr[2][1] = valueType + else: + bracketExpr[1][1] = valueType + let call = newTree(nnkCall, bracketExpr) + if init != nil and init.kind == nnkCall: + for i in 1 ..< init.len: + call.add init[i] + result = newTree(nnkStmtListExpr, newVarStmt(res, call), resBody, res) + macro collect*(init, body: untyped): untyped {.since: (1, 1).} = - ## Comprehension for seq/set/table collections. ``init`` is - ## the init call, and so custom collections are supported. + ## Comprehension for seqs/sets/tables. ## - ## The last statement of ``body`` has special syntax that specifies - ## the collection's add operation. Use ``{e}`` for set's ``incl``, - ## ``{k: v}`` for table's ``[]=`` and ``e`` for seq's ``add``. - ## - ## The ``init`` proc can be called with any number of arguments, - ## i.e. ``initTable(initialSize)``. + ## The last expression of `body` has special syntax that specifies + ## the collection's add operation. Use `{e}` for set's `incl`, + ## `{k: v}` for table's `[]=` and `e` for seq's `add`. + # analyse the body, find the deepest expression 'it' and replace it via + # 'result.add it' runnableExamples: import sets, tables let data = @["bird", "word"] @@ -343,20 +368,27 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} = for i, d in data.pairs: {i: d} assert z == {0: "bird", 1: "word"}.toTable - # analyse the body, find the deepest expression 'it' and replace it via - # 'result.add it' - let res = genSym(nskVar, "collectResult") - expectKind init, {nnkCall, nnkIdent, nnkSym} - let bracketExpr = newTree(nnkBracketExpr, - if init.kind == nnkCall: init[0] else: init) - let (resBody, keyType, valueType) = transLastStmt(body, res, bracketExpr) - if bracketExpr.len == 3: - bracketExpr[1][1] = keyType - bracketExpr[2][1] = valueType - else: - bracketExpr[1][1] = valueType - let call = newTree(nnkCall, bracketExpr) - if init.kind == nnkCall: - for i in 1 ..< init.len: - call.add init[i] - result = newTree(nnkStmtListExpr, newVarStmt(res, call), resBody, res) + result = collectImpl(init, body) + +macro collect*(body: untyped): untyped {.since: (1, 5).} = + ## Same as `collect` but without an `init` parameter. + runnableExamples: + import sets, tables + # Seq: + let data = @["bird", "word"] + let k = collect: + for i, d in data.pairs: + if i mod 2 == 0: d + + assert k == @["bird"] + ## HashSet: + let n = collect: + for d in data.items: {d} + + assert n == data.toHashSet + ## Table: + let m = collect: + for i, d in data.pairs: {i: d} + + assert m == {0: "bird", 1: "word"}.toTable + result = collectImpl(nil, body) \ No newline at end of file diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index a6fd70f34..cca1fe75a 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -40,7 +40,8 @@ import random const b = @[0, 1, 2] let c = b.dup shuffle() -doAssert c.len == 3 +doAssert b[0] == 0 +doAssert b[1] == 1 #test collect import sets, tables @@ -83,12 +84,27 @@ let z = collect(newSeq): else: d assert z == @["word", "word"] - proc tforum = let ans = collect(newSeq): for y in 0..10: if y mod 5 == 2: for x in 0..y: x - tforum() + +block: + let x = collect: + for d in data.items: + when d is int: "word" + else: d + assert x == @["bird", "word"] +assert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")] +assert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0] +assert collect(for (i, d) in pairs(data): {i: d}) == {1: "word", + 0: "bird"}.toTable +assert collect(for d in data.items: {d}) == data.toHashSet + +# bug #14332 +template foo = + discard collect(newSeq, for i in 1..3: i) +foo() \ No newline at end of file From e4e5a0c65ab10f48746f8f9b2417e8ca69724a04 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 4 Dec 2020 05:59:17 +0800 Subject: [PATCH 1613/4254] cleanup docs and tests (#16235) * js module also uses runnableExamples * cleanup docs and tests --- lib/system/comparisons.nim | 2 +- tests/system/tstrmantle.nim | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index a20e21064..c57cfa965 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -253,7 +253,7 @@ proc clamp*[T](x, a, b: T): T = ## Limits the value `x` within the interval [a, b]. ## This proc is equivalent to but fatser than `max(a, min(b, x))`. ## - ## **Note:** `a < b` is assumed and will not be checked. + ## **Note:** `a <= b` is assumed and will not be checked. runnableExamples: assert (1.4).clamp(0.0, 1.0) == 1.0 assert (0.5).clamp(0.0, 1.0) == 0.5 diff --git a/tests/system/tstrmantle.nim b/tests/system/tstrmantle.nim index 5b232193e..1f195adde 100644 --- a/tests/system/tstrmantle.nim +++ b/tests/system/tstrmantle.nim @@ -5,42 +5,42 @@ for i in 0 .. 9: doAssert res == "0123456789" -res = newStringOfCap(24) +res.setLen(0) for i in -9 .. 0: res.addInt int64(i) doAssert res == "-9-8-7-6-5-4-3-2-10" -res = newStringOfCap(24) +res.setLen(0) res.addInt high(int64) doAssert res == "9223372036854775807" -res = newStringOfCap(24) +res.setLen(0) res.addInt low(int64) doAssert res == "-9223372036854775808" -res = newStringOfCap(12) +res.setLen(0) res.addInt high(int32) doAssert res == "2147483647" -res = newStringOfCap(12) +res.setLen(0) res.addInt low(int32) doAssert res == "-2147483648" -res = newStringOfCap(12) +res.setLen(0) res.addInt high(int16) doAssert res == "32767" -res = newStringOfCap(212) +res.setLen(0) res.addInt low(int16) doAssert res == "-32768" -res = newStringOfCap(12) +res.setLen(0) res.addInt high(int8) doAssert res == "127" -res = newStringOfCap(12) +res.setLen(0) res.addInt low(int8) doAssert res == "-128" From 6877e0c8a3881e86ed40ddac3acba8926c8fc6ca Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Fri, 4 Dec 2020 10:50:17 +0300 Subject: [PATCH 1614/4254] RST tables: fix latex col number; allow less than three of `=` (#16040) --- doc/nep1.rst | 4 +- lib/packages/docutils/rst.nim | 97 +++++++++--- lib/packages/docutils/rstgen.nim | 3 +- nimdoc/rst2html/source/rst_examples.rst | 4 +- tests/stdlib/trstgen.nim | 186 +++++++++++++++++++++++- 5 files changed, 263 insertions(+), 31 deletions(-) diff --git a/doc/nep1.rst b/doc/nep1.rst index 1ab45d680..73e4d8433 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -1,6 +1,6 @@ -============================================== +========================================================== Nim Enhancement Proposal #1 - Standard Library Style Guide -============================================== +========================================================== :Author: Clay Sweetser, Dominik Picheta :Version: |nimversion| diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index a72ee17b6..bc3efa272 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -101,7 +101,12 @@ const type TokType = enum - tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther + tkEof, tkIndent, + tkWhite, tkWord, + tkAdornment, # used for chapter adornment, transitions and + # horizontal table borders + tkPunct, # one or many punctuation characters + tkOther Token = object # a RST token kind*: TokType # the type of the token ival*: int # the indentation or parsed integer value @@ -114,6 +119,7 @@ type bufpos*: int line*, col*, baseIndent*: int skipPounds*: bool + adornmentLine*: bool proc getThing(L: var Lexer, tok: var Token, s: set[char]) = tok.kind = tkWord @@ -127,8 +133,26 @@ proc getThing(L: var Lexer, tok: var Token, s: set[char]) = inc L.col, pos - L.bufpos L.bufpos = pos -proc getAdornment(L: var Lexer, tok: var Token) = - tok.kind = tkAdornment +proc isCurrentLineAdornment(L: var Lexer): bool = + var pos = L.bufpos + let c = L.buf[pos] + while true: + inc pos + if L.buf[pos] in {'\c', '\l', '\0'}: + break + if c == '+': # grid table + if L.buf[pos] notin {'-', '=', '+'}: + return false + else: # section adornment or table horizontal border + if L.buf[pos] notin {c, ' ', '\t', '\v', '\f'}: + return false + result = true + +proc getPunctAdornment(L: var Lexer, tok: var Token) = + if L.adornmentLine: + tok.kind = tkAdornment + else: + tok.kind = tkPunct tok.line = L.line tok.col = L.col var pos = L.bufpos @@ -139,6 +163,8 @@ proc getAdornment(L: var Lexer, tok: var Token) = if L.buf[pos] != c: break inc L.col, pos - L.bufpos L.bufpos = pos + if tok.symbol == "\\": tok.kind = tkPunct + # nim extension: standalone \ can not be adornment proc getBracket(L: var Lexer, tok: var Token) = tok.kind = tkPunct @@ -189,6 +215,8 @@ proc getIndent(L: var Lexer, tok: var Token) = proc rawGetTok(L: var Lexer, tok: var Token) = tok.symbol = "" tok.ival = 0 + if L.col == 0: + L.adornmentLine = false var c = L.buf[L.bufpos] case c of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9': @@ -200,11 +228,13 @@ proc rawGetTok(L: var Lexer, tok: var Token) = rawGetTok(L, tok) # ignore spaces before \n of '\x0D', '\x0A': getIndent(L, tok) + L.adornmentLine = false of '!', '\"', '#', '$', '%', '&', '\'', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '\\', '^', '_', '`', '|', '~': - getAdornment(L, tok) - if tok.symbol.len <= 3: tok.kind = tkPunct + if L.col == 0: + L.adornmentLine = L.isCurrentLineAdornment() + getPunctAdornment(L, tok) of '(', ')', '[', ']', '{', '}': getBracket(L, tok) else: @@ -730,7 +760,7 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = of tkEof: rstMessage(p, meExpected, "```") break - of tkPunct: + of tkPunct, tkAdornment: if currentTok(p).symbol == "```": inc p.idx break @@ -822,6 +852,10 @@ proc parseInline(p: var RstParser, father: PRstNode) = return parseUrl(p, father) of tkAdornment, tkOther, tkWhite: + if roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": + inc p.idx + father.add(parseMarkdownCodeblock(p)) + return if roSupportSmilies in p.s.options: let n = parseSmiley(p) if n != nil: @@ -1011,6 +1045,18 @@ proc tokenAfterNewline(p: RstParser): int = break else: inc result +proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool = + var headlineLen = 0 + if p.idx < adornmentIdx: # underline + for i in p.idx ..< adornmentIdx-1: # adornmentIdx-1 is a linebreak + headlineLen += p.tok[i].symbol.len + else: # overline + var i = p.idx + 2 + while p.tok[i].kind notin {tkEof, tkIndent}: + headlineLen += p.tok[i].symbol.len + inc i + return p.tok[adornmentIdx].symbol.len >= headlineLen + proc isLineBlock(p: RstParser): bool = var j = tokenAfterNewline(p) result = currentTok(p).col == p.tok[j].col and p.tok[j].symbol == "|" or @@ -1052,13 +1098,26 @@ proc findPipe(p: RstParser, start: int): bool = inc i proc whichSection(p: RstParser): RstNodeKind = + if currentTok(p).kind in {tkAdornment, tkPunct}: + # for punctuation sequences that can be both tkAdornment and tkPunct + if roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": + return rnCodeBlock + elif currentTok(p).symbol == "::": + return rnLiteralBlock + elif currentTok(p).symbol == ".." and predNL(p): + return rnDirective case currentTok(p).kind of tkAdornment: - if match(p, p.idx + 1, "ii"): result = rnTransition + if match(p, p.idx + 1, "ii") and currentTok(p).symbol.len >= 4: + result = rnTransition + elif match(p, p.idx, "+a+"): + result = rnGridTable + rstMessage(p, meGridTableNotImplemented) elif match(p, p.idx + 1, " a"): result = rnTable - elif match(p, p.idx + 1, "i"): result = rnOverline - elif isMarkdownHeadline(p): - result = rnHeadline + elif currentTok(p).symbol == "|" and isLineBlock(p): + result = rnLineBlock + elif match(p, p.idx + 1, "i") and isAdornmentHeadline(p, p.idx): + result = rnOverline else: result = rnLeaf of tkPunct: @@ -1067,27 +1126,18 @@ proc whichSection(p: RstParser): RstNodeKind = elif roSupportMarkdown in p.s.options and predNL(p) and match(p, p.idx, "| w") and findPipe(p, p.idx+3): result = rnMarkdownTable - elif currentTok(p).symbol == "```": - result = rnCodeBlock + elif currentTok(p).symbol == "|" and isLineBlock(p): + result = rnLineBlock elif match(p, tokenAfterNewline(p), "ai"): result = rnHeadline - elif currentTok(p).symbol == "::": - result = rnLiteralBlock elif predNL(p) and currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: result = rnBulletList - elif currentTok(p).symbol == "|" and isLineBlock(p): - result = rnLineBlock - elif currentTok(p).symbol == ".." and predNL(p): - result = rnDirective elif match(p, p.idx, ":w:") and predNL(p): # (currentTok(p).symbol == ":") result = rnFieldList elif match(p, p.idx, "(e) ") or match(p, p.idx, "e. "): result = rnEnumList - elif match(p, p.idx, "+a+"): - result = rnGridTable - rstMessage(p, meGridTableNotImplemented) elif isDefList(p): result = rnDefList elif isOptionList(p): @@ -1095,7 +1145,10 @@ proc whichSection(p: RstParser): RstNodeKind = else: result = rnParagraph of tkWord, tkOther, tkWhite: - if match(p, tokenAfterNewline(p), "ai"): result = rnHeadline + let tokIdx = tokenAfterNewline(p) + if match(p, tokIdx, "ai"): + if isAdornmentHeadline(p, tokIdx): result = rnHeadline + else: result = rnParagraph elif match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList elif isDefList(p): result = rnDefList else: result = rnParagraph diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index d6bd26ad7..d88f2ed77 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1009,7 +1009,8 @@ proc renderContainer(d: PDoc, n: PRstNode, result: var string) = proc texColumns(n: PRstNode): string = result = "" - for i in countup(1, len(n)): add(result, "|X") + let nColumns = if n.sons.len > 0: len(n.sons[0]) else: 1 + for i in countup(1, nColumns): add(result, "|X") proc renderField(d: PDoc, n: PRstNode, result: var string) = var b = false diff --git a/nimdoc/rst2html/source/rst_examples.rst b/nimdoc/rst2html/source/rst_examples.rst index c8d15aef8..54f0124c8 100644 --- a/nimdoc/rst2html/source/rst_examples.rst +++ b/nimdoc/rst2html/source/rst_examples.rst @@ -1,6 +1,6 @@ -========== +================ Not a Nim Manual -========== +================ :Authors: Andreas Rumpf, Zahary Karadjov :Version: |nimversion| diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 946104e7c..1bf73e146 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -6,7 +6,7 @@ outputsub: "" import ../../lib/packages/docutils/rstgen import ../../lib/packages/docutils/rst -import unittest, strtabs +import unittest, strutils, strtabs suite "YAML syntax highlighting": test "Basics": @@ -144,6 +144,12 @@ suite "YAML syntax highlighting": ?not a map key""" +suite "RST/Markdown general": + test "RST emphasis": + assert rstToHtml("*Hello* **world**!", {}, + newStringTable(modeStyleInsensitive)) == + "Hello world!" + test "Markdown links": let a = rstToHtml("(( [Nim](https://nim-lang.org/) ))", {roSupportMarkdown}, defaultConfig()) @@ -178,7 +184,179 @@ not in table""" assert output2 == """
      A1 headerA2
      """ + test "RST tables": + let input1 = """ +Test 2 column/4 rows table: +==== === +H0 H1 +==== === +A0 A1 +==== === +A2 A3 +==== === +A4 A5 +==== === """ + let output1 = rstToLatex(input1, {}) + assert "{|X|X|}" in output1 # 2 columns + assert count(output1, "\\\\") == 4 # 4 rows + for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]: + assert cell in output1 -assert rstToHtml("*Hello* **world**!", {}, - newStringTable(modeStyleInsensitive)) == - "Hello world!" + let input2 = """ +Now test 3 columns / 2 rows, and also borders containing 4 =, 3 =, 1 = signs: + +==== === = +H0 H1 H +==== === = +A0 A1 X + Ax Y +==== === = """ + let output2 = rstToLatex(input2, {}) + assert "{|X|X|X|}" in output2 # 3 columns + assert count(output2, "\\\\") == 2 # 2 rows + for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]: + assert cell in output2 + + + test "RST adornments": + let input1 = """ +Check that a few punctuation symbols are not parsed as adornments: +:word1: word2 .... word3 """ + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + discard output1 + + test "RST sections": + let input1 = """ +Long chapter name +''''''''''''''''''' +""" + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + assert "Long chapter name" in output1 and "" in output1 + + test "Markdown code block": + let input1 = """ +``` +let x = 1 +``` """ + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + assert "" in output1 + assert "other line
      " in output1 + let output1l = rstToLatex(input1, {}) + assert "line block\\\\" in output1l + assert "other line\\\\" in output1l From edce5897a52aac308fbe9b14f155139f15da02cd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 4 Dec 2020 17:47:41 +0100 Subject: [PATCH 1615/4254] fixes #16214 [backport] (#16252) --- lib/system/alloc.nim | 8 ++++---- lib/system/mmdisp.nim | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 95658c49a..76c744f59 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -253,7 +253,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer = sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6" var old = a.llmem # can be nil and is correct with nil a.llmem = cast[PLLChunk](osAllocPages(PageSize)) - when defined(avlcorruption): + when defined(nimAvlcorruption): trackLocation(a.llmem, PageSize) incCurrMem(a, PageSize) a.llmem.size = PageSize - sizeof(LLChunk) @@ -276,7 +276,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode = a.freeAvlNodes = a.freeAvlNodes.link[0] else: result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode))) - when defined(avlcorruption): + when defined(nimAvlcorruption): cprintf("tracking location: %p\n", result) result.key = key result.upperBound = upperBound @@ -284,7 +284,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode = result.link[0] = bottom result.link[1] = bottom result.level = 1 - #when defined(avlcorruption): + #when defined(nimAvlcorruption): # track("allocAvlNode", result, sizeof(AvlNode)) sysAssert(bottom == addr(a.bottomData), "bottom data") sysAssert(bottom.link[0] == bottom, "bottom link[0]") @@ -1017,7 +1017,7 @@ when defined(nimTypeNames): template instantiateForRegion(allocator: untyped) {.dirty.} = {.push stackTrace: off.} - when defined(fulldebug): + when defined(nimFulldebug): proc interiorAllocatedPtr*(p: pointer): pointer = result = interiorAllocatedPtr(allocator, p) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 5fe1960d1..8589b678d 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -17,10 +17,10 @@ const debugGC = false # we wish to debug the GC... logGC = false traceGC = false # extensive debugging - alwaysCycleGC = defined(smokeCycles) - alwaysGC = defined(fulldebug) # collect after every memory + alwaysCycleGC = defined(nimSmokeCycles) + alwaysGC = defined(nimFulldebug) # collect after every memory # allocation (for debugging) - leakDetector = defined(leakDetector) + leakDetector = defined(nimLeakDetector) overwriteFree = defined(nimBurnFree) # overwrite memory with 0xFF before free trackAllocationSource = leakDetector @@ -30,7 +30,7 @@ const coalescRight = true coalescLeft = true logAlloc = false - useCellIds = defined(corruption) + useCellIds = defined(nimCorruption) type PPointer = ptr pointer From 8178388a78a013c990e2a7a8e97e4595449e5944 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 Dec 2020 00:36:06 +0100 Subject: [PATCH 1616/4254] fixes #16249 [backport:1.4] (#16251) --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a3d3425e3..c4544bbc5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2044,7 +2044,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil: discard cgsym(m, "nimTestErrorFlag") - if {optGenStaticLib, optGenDynLib} * m.config.globalOptions == {}: + if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}: for i in countdown(high(graph.globalDestructors), 0): n.add graph.globalDestructors[i] if passes.skipCodegen(m.config, n): return From d7f244180e84e4fd0fe7cd34298c8082bba14069 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 5 Dec 2020 18:41:08 +0100 Subject: [PATCH 1617/4254] Retry commands in testament again (#16262) --- testament/categories.nim | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index c48d611b1..c894bc9f9 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -482,6 +482,17 @@ proc makeSupTest(test, options: string, cat: Category): TTest = result.options = options result.startTime = epochTime() +const maxRetries = 3 +template retryCommand(call): untyped = + var res: typeof(call) + var backoff = 1 + for i in 0.. Date: Sun, 6 Dec 2020 05:05:16 +0800 Subject: [PATCH 1618/4254] bring back argparse (#16242) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 6d89df3e5..2da10e749 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -9,7 +9,7 @@ var packages2*: seq[tuple[name, cmd: string; url: string, useHead: bool]] = @[] # packages A-M # pkg1 "alea" -# pkg1 "argparse" +pkg1 "argparse" pkg1 "arraymancer", "nim c tests/tests_cpu.nim" # pkg1 "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" pkg1 "awk" From af7f7726fe727b68238533f690fb7cd98552e4e4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 Dec 2020 23:15:17 +0100 Subject: [PATCH 1619/4254] ORC: make the adaptive strategy the default in order to fight memory consumption (#16250) * ORC: make the adaptive strategy the default in order to fight memory consumption * added missing test case --- lib/system/orc.nim | 19 +++++++++++++------ tests/arc/tasyncleak.nim | 2 +- tests/arc/torcbench.nim | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 tests/arc/torcbench.nim diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 4bd8952b7..803f3d410 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -39,7 +39,8 @@ template setColor(c, col) = c.rc = c.rc and not colorMask or col const - optimizedOrc = not defined(nimOldOrc) + optimizedOrc = false # not defined(nimOldOrc) +# XXX Still incorrect, see tests/arc/tdestroy_in_loopcond proc nimIncRefCyclic(p: pointer; cyclic: bool) {.compilerRtl, inl.} = let h = head(p) @@ -72,6 +73,7 @@ type jumpStack: CellSeq # Lins' jump stack in order to speed up traversals toFree: CellSeq freed, touched, edges, rcSum: int + keepThreshold: bool proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = if desc.traceImpl != nil: @@ -309,6 +311,8 @@ proc collectCyclesBacon(j: var GcEnv; lowMark: int) = if j.rcSum == j.edges: # short-cut: we know everything is garbage: colToCollect = colGray + # remember the fact that we got so lucky: + j.keepThreshold = true else: for i in countdown(last, lowMark): scan(roots.d[i][0], roots.d[i][1], j) @@ -327,7 +331,7 @@ proc collectCyclesBacon(j: var GcEnv; lowMark: int) = #roots.len = 0 const - defaultThreshold = when defined(nimAdaptiveOrc): 128 else: 10_000 + defaultThreshold = when defined(nimFixedOrc): 10_000 else: 128 when defined(nimStressOrc): const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8 @@ -335,7 +339,8 @@ else: var rootsThreshold = defaultThreshold proc partialCollect(lowMark: int) = - if roots.len < 10 + lowMark: return + when false: + if roots.len < 10 + lowMark: return when logOrc: cfprintf(cstderr, "[partialCollect] begin\n") var j: GcEnv @@ -373,9 +378,11 @@ proc collectCycles() = # of the cycle collector's effectiveness: # we're effective when we collected 50% or more of the nodes # we touched. If we're effective, we can reset the threshold: - if j.freed * 2 >= j.touched: - when defined(nimAdaptiveOrc): - rootsThreshold = max(rootsThreshold div 2, 16) + if j.keepThreshold and rootsThreshold <= defaultThreshold: + discard + elif j.freed * 2 >= j.touched: + when not defined(nimFixedOrc): + rootsThreshold = max(rootsThreshold div 3 * 2, 16) else: rootsThreshold = defaultThreshold #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index 417b67edb..eb0c45213 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 4014, deallocCount: 4012)" + outputsub: "(allocCount: 4302, deallocCount: 4300)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ diff --git a/tests/arc/torcbench.nim b/tests/arc/torcbench.nim new file mode 100644 index 000000000..4c9e65fee --- /dev/null +++ b/tests/arc/torcbench.nim @@ -0,0 +1,38 @@ +discard """ + output: '''true peak memory: true''' + cmd: "nim c --gc:orc -d:release $file" +""" + +import lists, strutils, times + +type + Base = ref object of RootObj + + Node = ref object of Base + parent: DoublyLinkedList[string] + le, ri: Node + self: Node # in order to create a cycle + +proc buildTree(parent: DoublyLinkedList[string]; depth: int): Node = + if depth == 0: + result = nil + elif depth == 1: + result = Node(parent: parent, le: nil, ri: nil, self: nil) + when not defined(gcArc): + result.self = result + else: + result = Node(parent: parent, le: buildTree(parent, depth - 1), ri: buildTree(parent, depth - 2), self: nil) + result.self = result + +proc main() = + for i in countup(1, 100): + var leakList = initDoublyLinkedList[string]() + for j in countup(1, 5000): + leakList.append(newString(200)) + #GC_fullCollect() + for i in 0..400: + discard buildTree(leakList, 8) + +main() +GC_fullCollect() +echo getOccupiedMem() < 10 * 1024 * 1024, " peak memory: ", getMaxMem() < 10 * 1024 * 1024 From 1aaa67fc18879bd2aa8ae8f5e7dc763f826c73b6 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 6 Dec 2020 12:51:29 +0800 Subject: [PATCH 1620/4254] [docs minor] remove unicode in docs comments (#16267) --- lib/pure/uri.nim | 2 +- lib/system/atomics.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 5b16bfcb1..e993c240d 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -11,7 +11,7 @@ ## ## A Uniform Resource Identifier (URI) provides a simple and extensible ## means for identifying a resource. A URI can be further classified -## as a locator, a name, or both. The term “Uniform Resource Locator” +## as a locator, a name, or both. The term "Uniform Resource Locator" ## (URL) refers to the subset of URIs. ## ## Basic usage diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index 15e8a56a7..f69cb753d 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -125,8 +125,8 @@ when someGcc and hasThreadSupport: proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {. importc: "__atomic_test_and_set", nodecl.} ## This built-in function performs an atomic test-and-set operation on the byte at p. - ## The byte is set to some implementation defined nonzero “set” value and the return - ## value is true if and only if the previous contents were “set”. + ## The byte is set to some implementation defined nonzero "set" value and the return + ## value is true if and only if the previous contents were "set". ## All memory models are valid. proc atomicClear*(p: pointer, mem: AtomMemModel) {. From 48d7c40553f0769c22b4b47f8079dd96c3e23323 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 6 Dec 2020 16:50:46 +0800 Subject: [PATCH 1621/4254] fix #16206 (#16207) * better docs and tests * a bit better only clean trailing whitespace --- lib/pure/parsecfg.nim | 70 +++++++++++++++++++++++++++++- tests/stdlib/tparsecfg.nim | 89 ++++++++++++++++++++++++++++++-------- 2 files changed, 141 insertions(+), 18 deletions(-) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 9b140a809..c87010122 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -107,6 +107,70 @@ ## var dict = loadConfig("config.ini") ## dict.delSectionKey("Author","email") ## dict.writeConfig("config.ini") +## +## Supported INI File structure +## ---------------------------- +## The examples below are supported: +## + +# taken from https://docs.python.org/3/library/configparser.html#supported-ini-file-structure +runnableExamples: + import streams + + var dict = loadConfig(newStringStream("""[Simple Values] + key=value + spaces in keys=allowed + spaces in values=allowed as well + spaces around the delimiter = obviously + you can also use : to delimit keys from values + [All Values Are Strings] + values like this: 19990429 + or this: 3.14159265359 + are they treated as numbers : no + integers floats and booleans are held as: strings + can use the API to get converted values directly: true + [No Values] + key_without_value + # empty string value is not allowed = + [ Seletion A ] + space around section name will be ignored + [You can use comments] + # like this + ; or this + # By default only in an empty line. + # Inline comments can be harmful because they prevent users + # from using the delimiting characters as parts of values. + # That being said, this can be customized. + [Sections Can Be Indented] + can_values_be_as_well = True + does_that_mean_anything_special = False + purpose = formatting for readability + # Did I mention we can indent comments, too? + """) + ) + + let section1 = "Simple Values" + doAssert dict.getSectionValue(section1, "key") == "value" + doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed" + doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well" + doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously" + doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values" + + let section2 = "All Values Are Strings" + doAssert dict.getSectionValue(section2, "values like this") == "19990429" + doAssert dict.getSectionValue(section2, "or this") == "3.14159265359" + doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no" + doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings" + doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true" + + let section3 = "Seletion A" + doAssert dict.getSectionValue(section3, + "space around section name will be ignored", "not an empty value") == "" + + let section4 = "Sections Can Be Indented" + doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True" + doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" + doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability" import strutils, lexbase, streams, tables @@ -151,7 +215,7 @@ type # implementation const - SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', '/', '\\', '-'} + SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', ' ', '\x80'..'\xFF', '.', '/', '\\', '-'} proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.} @@ -306,6 +370,10 @@ proc getSymbol(c: var CfgParser, tok: var Token) = add(tok.literal, c.buf[pos]) inc(pos) if not (c.buf[pos] in SymChars): break + + while tok.literal.len > 0 and tok.literal[^1] == ' ': + tok.literal.setLen(tok.literal.len - 1) + c.bufpos = pos tok.kind = tkSymbol diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim index 45dea0531..bbf88ee03 100644 --- a/tests/stdlib/tparsecfg.nim +++ b/tests/stdlib/tparsecfg.nim @@ -5,28 +5,27 @@ discard """ import parsecfg, streams when not defined(js): - # bug #6046 - var config = newConfig() - config.setSectionKey("foo", "bar", "-1") - config.setSectionKey("foo", "foo", "abc") - from stdtest/specialpaths import buildDir import os + # bug #6046 + block: + var config = newConfig() + config.setSectionKey("foo", "bar", "-1") + config.setSectionKey("foo", "foo", "abc") - const file = buildDir / "tparsecfg.ini" - config.writeConfig(file) + const file = buildDir / "tparsecfg.ini" + config.writeConfig(file) - # file now contains - # [foo] - # bar=-1 - # foo=abc - - var config2 = loadConfig(file) - let bar = config2.getSectionValue("foo", "bar") - let foo = config2.getSectionValue("foo", "foo") - assert(bar == "-1") - assert(foo == "abc") + # file now contains + # [foo] + # bar=-1 + # foo=abc + var config2 = loadConfig(file) + let bar = config2.getSectionValue("foo", "bar") + let foo = config2.getSectionValue("foo", "foo") + assert(bar == "-1") + assert(foo == "abc") ## Creating a configuration file. var dict1 = newConfig() @@ -78,3 +77,59 @@ name=hello name=lihf8515 qq=10214028 """ + +block: + var dict = loadConfig(newStringStream("""[Simple Values] + key=value + spaces in keys=allowed + spaces in values=allowed as well + spaces around the delimiter = obviously + you can also use : to delimit keys from values + [All Values Are Strings] + values like this: 19990429 + or this: 3.14159265359 + are they treated as numbers : no + integers floats and booleans are held as: strings + can use the API to get converted values directly: true + [No Values] + key_without_value + # empty string value is not allowed = + [ Seletion A ] + space around section name will be ignored + [You can use comments] + # like this + ; or this + # By default only in an empty line. + # Inline comments can be harmful because they prevent users + # from using the delimiting characters as parts of values. + # That being said, this can be customized. + [Sections Can Be Indented] + can_values_be_as_well = True + does_that_mean_anything_special = False + purpose = formatting for readability + # Did I mention we can indent comments, too? + """) + ) + + let section1 = "Simple Values" + doAssert dict.getSectionValue(section1, "key") == "value" + doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed" + doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well" + doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously" + doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values" + + let section2 = "All Values Are Strings" + doAssert dict.getSectionValue(section2, "values like this") == "19990429" + doAssert dict.getSectionValue(section2, "or this") == "3.14159265359" + doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no" + doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings" + doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true" + + let section3 = "Seletion A" + doAssert dict.getSectionValue(section3, + "space around section name will be ignored", "not an empty value") == "" + + let section4 = "Sections Can Be Indented" + doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True" + doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" + doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability" From 1e320bc8c5112b152ebc3092331b8b1fe0ae5191 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 6 Dec 2020 16:54:32 +0800 Subject: [PATCH 1622/4254] [docs minor]space for code-block (#16266) * [docs minor]space for code-block * correct more errors * to runnableExamples * add newline --- compiler/astalgo.nim | 4 ++-- compiler/sigmatch.nim | 4 +++- compiler/vmgen.nim | 2 +- lib/pure/unidecode/unidecode.nim | 12 +++--------- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 832f8819a..300089d81 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -222,9 +222,9 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym = ## gensym'ed and then they have '\`' suffix that we need to ## ignore, see compiler / evaltempl.nim, snippet: ## - ##..code-block:: nim + ## .. code-block:: nim ## - ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), + ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), ## if c.instLines: actual.info else: templ.info) for i in 1.. Date: Sun, 6 Dec 2020 10:13:19 +0100 Subject: [PATCH 1623/4254] nimdoc: Initialize theme switch and pragma dots on DOMContentLoaded (#16247) The default HTML template for nimdoc currently initializes the dark mode switch and pragma dots when the onload event is fired. But since the onload event does not fire until all external resources (images, stylesheets, fonts, etc.) have been loaded, the light theme is shown for a brief moment before the document is fully loaded, and it switches to the dark theme. This is quite jarring, especially on slower internet connections. So let's instead initialize these things on the DOMContentLoaded event, which is fired right after the document has been parsed and the initial DOM structure is ready. This means that we now display the dark mode immediately, without having to wait for external resources to load first. For reference, see: - https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event - https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event I have updated the snapshot tests in `nimdoc/`, and done some manual testing of both the theme switch and the pragma dots, to confirm that this does not break anything. Please let me know if I've missed anything. --- config/nimdoc.cfg | 4 +++- nimdoc/rst2html/expected/rst_examples.html | 4 +++- nimdoc/test_out_index_dot_html/expected/index.html | 4 +++- nimdoc/test_out_index_dot_html/expected/theindex.html | 4 +++- nimdoc/testproject/expected/subdir/subdir_b/utils.html | 4 +++- nimdoc/testproject/expected/testproject.html | 4 +++- nimdoc/testproject/expected/theindex.html | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index e4b485ca0..585b3cc49 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -268,10 +268,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      $title

      diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 8a08e8df5..0b9207688 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -56,10 +56,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      Not a Nim Manual

      diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 65241d356..35a5dfb56 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -56,10 +56,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      foo

      diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index b2863f99a..aa9ca2645 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -56,10 +56,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      Index

      diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 40de645e3..27cef017b 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -56,10 +56,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      subdir/subdir_b/utils

      diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index ee09b46af..a32e1180c 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -56,10 +56,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      testproject

      diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 03d9c72fe..978560e0f 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -56,10 +56,12 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); - +

      Index

      From 57d2c293d3f3fd86c003b35b215f701bfa22dbd1 Mon Sep 17 00:00:00 2001 From: Pietro Peterlongo Date: Sun, 6 Dec 2020 10:14:55 +0100 Subject: [PATCH 1624/4254] fix parseChar see #16240 (#16245) * fix parseChar * do not introduce new double backticks --- lib/pure/parseutils.nim | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index ccfac2a7e..5ceff26a0 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -211,6 +211,7 @@ proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, proc parseIdent*(s: string, ident: var string, start = 0): int = ## Parses an identifier and stores it in ``ident``. Returns ## the number of the parsed characters or 0 in case of an error. + ## If error, the value of `ident` is not changed. runnableExamples: var res: string doAssert parseIdent("Hello World", res, 0) == 5 @@ -241,9 +242,19 @@ proc parseIdent*(s: string, start = 0): string = while i < s.len and s[i] in IdentChars: inc(i) result = substr(s, start, i-1) -proc parseChar*(s: string, ident: var char, start = 0): int = - ident = s[start] - result = 1 +proc parseChar*(s: string, c: var char, start = 0): int = + ## Parses a single character, stores it in `c` and returns 1. + ## In case of error (if start >= s.len) it returns 0 + ## and the value of `c` is unchanged. + runnableExamples: + var c: char + doAssert "nim".parseChar(c, 3) == 0 + doAssert c == '\0' + doAssert "nim".parseChar(c, 0) == 1 + doAssert c == 'n' + if start < s.len: + c = s[start] + result = 1 proc skipWhitespace*(s: string, start = 0): int {.inline.} = ## Skips the whitespace starting at ``s[start]``. Returns the number of From baf37b5cc71c14e1772e55e29147c9223b4521d7 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 7 Dec 2020 17:41:25 +0800 Subject: [PATCH 1625/4254] use funcs and fix links in strutils (#16277) * use funcs and inline in strutils * use funcs --- lib/pure/strutils.nim | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 8cbc947bf..94d63984c 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -121,8 +121,7 @@ const ## doAssert "01234".find(invalid) == -1 ## doAssert "01A34".find(invalid) == 2 -proc isAlphaAscii*(c: char): bool {.noSideEffect, - rtl, extern: "nsuIsAlphaAsciiChar".} = +func isAlphaAscii*(c: char): bool {.rtl, extern: "nsuIsAlphaAsciiChar".} = ## Checks whether or not character `c` is alphabetical. ## ## This checks a-z, A-Z ASCII characters only. @@ -133,8 +132,7 @@ proc isAlphaAscii*(c: char): bool {.noSideEffect, doAssert isAlphaAscii('8') == false return c in Letters -proc isAlphaNumeric*(c: char): bool {.noSideEffect, - rtl, extern: "nsuIsAlphaNumericChar".} = +func isAlphaNumeric*(c: char): bool {.rtl, extern: "nsuIsAlphaNumericChar".} = ## Checks whether or not `c` is alphanumeric. ## ## This checks a-z, A-Z, 0-9 ASCII characters only. @@ -144,8 +142,7 @@ proc isAlphaNumeric*(c: char): bool {.noSideEffect, doAssert isAlphaNumeric(' ') == false return c in Letters+Digits -proc isDigit*(c: char): bool {.noSideEffect, - rtl, extern: "nsuIsDigitChar".} = +func isDigit*(c: char): bool {.rtl, extern: "nsuIsDigitChar".} = ## Checks whether or not `c` is a number. ## ## This checks 0-9 ASCII characters only. @@ -154,8 +151,7 @@ proc isDigit*(c: char): bool {.noSideEffect, doAssert isDigit('8') == true return c in Digits -proc isSpaceAscii*(c: char): bool {.noSideEffect, - rtl, extern: "nsuIsSpaceAsciiChar".} = +func isSpaceAscii*(c: char): bool {.rtl, extern: "nsuIsSpaceAsciiChar".} = ## Checks whether or not `c` is a whitespace character. runnableExamples: doAssert isSpaceAscii('n') == false @@ -163,8 +159,7 @@ proc isSpaceAscii*(c: char): bool {.noSideEffect, doAssert isSpaceAscii('\t') == true return c in Whitespace -proc isLowerAscii*(c: char): bool {.noSideEffect, - rtl, extern: "nsuIsLowerAsciiChar".} = +func isLowerAscii*(c: char): bool {.rtl, extern: "nsuIsLowerAsciiChar".} = ## Checks whether or not `c` is a lower case character. ## ## This checks ASCII characters only. @@ -178,8 +173,7 @@ proc isLowerAscii*(c: char): bool {.noSideEffect, doAssert isLowerAscii('7') == false return c in {'a'..'z'} -proc isUpperAscii*(c: char): bool {.noSideEffect, - rtl, extern: "nsuIsUpperAsciiChar".} = +func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = ## Checks whether or not `c` is an upper case character. ## ## This checks ASCII characters only. @@ -203,7 +197,7 @@ proc toLowerAscii*(c: char): char {.noSideEffect, ## character. ## ## See also: - ## * `isLowerAscii proc<#isLowerAscii,char>`_ + ## * `isLowerAscii func<#isLowerAscii,char>`_ ## * `toLowerAscii proc<#toLowerAscii,string>`_ for converting a string runnableExamples: doAssert toLowerAscii('A') == 'a' @@ -241,7 +235,7 @@ proc toUpperAscii*(c: char): char {.noSideEffect, ## character. ## ## See also: - ## * `isLowerAscii proc<#isLowerAscii,char>`_ + ## * `isUpperAscii func<#isUpperAscii,char>`_ ## * `toUpperAscii proc<#toUpperAscii,string>`_ for converting a string ## * `capitalizeAscii proc<#capitalizeAscii,string>`_ runnableExamples: From 94bb816de35953674a3895999838fc67169f8310 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 7 Dec 2020 10:50:30 +0100 Subject: [PATCH 1626/4254] OSX: support for M1 [backport:1.0] (#16279) --- compiler/installer.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index ecd1f7475..2f11d0df9 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -7,7 +7,7 @@ Version: "$version" Platforms: """ windows: i386;amd64 linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64 - macosx: i386;amd64;powerpc64 + macosx: i386;amd64;powerpc64;arm64 solaris: i386;amd64;sparc;sparc64 freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el netbsd: i386;amd64 From 71e2a9e569ab3380fd057e4fc16e6d4ccd66f1f4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 7 Dec 2020 23:38:13 +0800 Subject: [PATCH 1627/4254] use generics in random (#16283) * use generics in random * fix --- lib/pure/random.nim | 48 ++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 683140cd8..0ee75e027 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -217,8 +217,7 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. ## ## See also: - ## * `rand proc<#rand,int>`_ that returns an integer using the default - ## random number generator + ## * `rand proc<#rand,T>`_ `T` are integers, floats, and enums without holes. ## * `rand proc<#rand,Rand,range[]>`_ that returns a float ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type @@ -233,28 +232,6 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = if x <= randMax - (randMax mod Ui(max)): return int(x mod (uint64(max)+1u64)) -proc rand*(max: int): int {.benign.} = - ## Returns a random integer in the range `0..max`. - ## - ## If `randomize<#randomize>`_ has not been called, the sequence of random - ## numbers returned from this proc will always be the same. - ## - ## This proc uses the default random number generator. Thus, it is **not** - ## thread-safe. - ## - ## See also: - ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a - ## provided state - ## * `rand proc<#rand,float>`_ that returns a float - ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice - ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type - runnableExamples: - randomize(123) - doAssert rand(100) == 0 - doAssert rand(100) == 96 - doAssert rand(100) == 66 - rand(state, max) - proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = ## Returns a random floating point number in the range `0.0..max` ## using the given state. @@ -276,8 +253,10 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = let u = (0x3FFu64 shl 52u64) or (x shr 12u64) result = (cast[float](u) - 1.0) * max -proc rand*(max: float): float {.benign.} = - ## Returns a random floating point number in the range `0.0..max`. +proc rand*[T: Ordinal or SomeFloat](max: T): T {.benign.} = + ## Returns a random floating point number in the range `T(0) .. max`. + ## + ## Allowed types for `T` are integers, floats, and enums without holes. ## ## If `randomize<#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. @@ -286,16 +265,21 @@ proc rand*(max: float): float {.benign.} = ## thread-safe. ## ## See also: + ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a + ## provided state ## * `rand proc<#rand,Rand,range[]>`_ that returns a float using a ## provided state - ## * `rand proc<#rand,int>`_ that returns an integer ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: - randomize(234) + randomize(123) + doAssert rand(100) == 0 + doAssert rand(100) == 96 + doAssert rand(100) == 66 + let f = rand(1.0) ## f = 8.717181376738381e-07 - rand(state, max) + result = T(rand(state, max)) proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = ## For a slice `a..b`, returns a value in the range `a..b` using the given @@ -335,8 +319,7 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = ## See also: ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice and uses ## a provided state - ## * `rand proc<#rand,int>`_ that returns an integer - ## * `rand proc<#rand,float>`_ that returns a floating point number + ## * `rand proc<#rand,T>`_ `T` are integers, floats, and enums without holes. ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(345) @@ -355,8 +338,7 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T = ## thread-safe. ## ## See also: - ## * `rand proc<#rand,int>`_ that returns an integer - ## * `rand proc<#rand,float>`_ that returns a floating point number + ## * `rand proc<#rand,T>`_ `T` are integers, floats, and enums without holes. ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice runnableExamples: randomize(567) From 84fea7c1445475aba51d889668f250b0261443e4 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 7 Dec 2020 17:07:12 +0100 Subject: [PATCH 1628/4254] strutils.nim: Use `func` everywhere (#16281) * strutils.nim: procs with {.noSideEffect.} -> func * strutils.nim: procs without {.noSideEffect.} -> func * strutils.nim: proc -> func for links * strutils.nim: proc -> func in doc comments * test: add strutils to strictFuncs test * test: proc -> func in errmsg test --- lib/pure/strutils.nim | 619 ++++++++++----------- tests/effects/tstrict_funcs.nim | 4 +- tests/errmsgs/tunknown_named_parameter.nim | 6 +- 3 files changed, 299 insertions(+), 330 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 94d63984c..c937cd259 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -113,7 +113,7 @@ const ## A set with all the possible characters. ## ## Not very useful by its own, you can use it to create *inverted* sets to - ## make the `find proc<#find,string,set[char],Natural,int>`_ + ## make the `find func<#find,string,set[char],Natural,int>`_ ## find **invalid** characters in strings. Example: ## ## .. code-block:: nim @@ -166,7 +166,7 @@ func isLowerAscii*(c: char): bool {.rtl, extern: "nsuIsLowerAsciiChar".} = ## Use `Unicode module`_ for UTF-8 support. ## ## See also: - ## * `toLowerAscii proc<#toLowerAscii,char>`_ + ## * `toLowerAscii func<#toLowerAscii,char>`_ runnableExamples: doAssert isLowerAscii('e') == true doAssert isLowerAscii('E') == false @@ -180,7 +180,7 @@ func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = ## Use `Unicode module`_ for UTF-8 support. ## ## See also: - ## * `toUpperAscii proc<#toUpperAscii,char>`_ + ## * `toUpperAscii func<#toUpperAscii,char>`_ runnableExamples: doAssert isUpperAscii('e') == false doAssert isUpperAscii('E') == true @@ -188,8 +188,7 @@ func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = return c in {'A'..'Z'} -proc toLowerAscii*(c: char): char {.noSideEffect, - rtl, extern: "nsuToLowerAsciiChar".} = +func toLowerAscii*(c: char): char {.rtl, extern: "nsuToLowerAsciiChar".} = ## Returns the lower case version of character ``c``. ## ## This works only for the letters ``A-Z``. See `unicode.toLower @@ -198,7 +197,7 @@ proc toLowerAscii*(c: char): char {.noSideEffect, ## ## See also: ## * `isLowerAscii func<#isLowerAscii,char>`_ - ## * `toLowerAscii proc<#toLowerAscii,string>`_ for converting a string + ## * `toLowerAscii func<#toLowerAscii,string>`_ for converting a string runnableExamples: doAssert toLowerAscii('A') == 'a' doAssert toLowerAscii('e') == 'e' @@ -212,8 +211,7 @@ template toImpl(call) = for i in 0..len(s) - 1: result[i] = call(s[i]) -proc toLowerAscii*(s: string): string {.noSideEffect, - rtl, extern: "nsuToLowerAsciiStr".} = +func toLowerAscii*(s: string): string {.rtl, extern: "nsuToLowerAsciiStr".} = ## Converts string `s` into lower case. ## ## This works only for the letters ``A-Z``. See `unicode.toLower @@ -221,13 +219,12 @@ proc toLowerAscii*(s: string): string {.noSideEffect, ## character. ## ## See also: - ## * `normalize proc<#normalize,string>`_ + ## * `normalize func<#normalize,string>`_ runnableExamples: doAssert toLowerAscii("FooBar!") == "foobar!" toImpl toLowerAscii -proc toUpperAscii*(c: char): char {.noSideEffect, - rtl, extern: "nsuToUpperAsciiChar".} = +func toUpperAscii*(c: char): char {.rtl, extern: "nsuToUpperAsciiChar".} = ## Converts character `c` into upper case. ## ## This works only for the letters ``A-Z``. See `unicode.toUpper @@ -236,8 +233,8 @@ proc toUpperAscii*(c: char): char {.noSideEffect, ## ## See also: ## * `isUpperAscii func<#isUpperAscii,char>`_ - ## * `toUpperAscii proc<#toUpperAscii,string>`_ for converting a string - ## * `capitalizeAscii proc<#capitalizeAscii,string>`_ + ## * `toUpperAscii func<#toUpperAscii,string>`_ for converting a string + ## * `capitalizeAscii func<#capitalizeAscii,string>`_ runnableExamples: doAssert toUpperAscii('a') == 'A' doAssert toUpperAscii('E') == 'E' @@ -246,8 +243,7 @@ proc toUpperAscii*(c: char): char {.noSideEffect, else: result = c -proc toUpperAscii*(s: string): string {.noSideEffect, - rtl, extern: "nsuToUpperAsciiStr".} = +func toUpperAscii*(s: string): string {.rtl, extern: "nsuToUpperAsciiStr".} = ## Converts string `s` into upper case. ## ## This works only for the letters ``A-Z``. See `unicode.toUpper @@ -255,27 +251,26 @@ proc toUpperAscii*(s: string): string {.noSideEffect, ## character. ## ## See also: - ## * `capitalizeAscii proc<#capitalizeAscii,string>`_ + ## * `capitalizeAscii func<#capitalizeAscii,string>`_ runnableExamples: doAssert toUpperAscii("FooBar!") == "FOOBAR!" toImpl toUpperAscii -proc capitalizeAscii*(s: string): string {.noSideEffect, - rtl, extern: "nsuCapitalizeAscii".} = +func capitalizeAscii*(s: string): string {.rtl, extern: "nsuCapitalizeAscii".} = ## Converts the first character of string `s` into upper case. ## ## This works only for the letters ``A-Z``. ## Use `Unicode module`_ for UTF-8 support. ## ## See also: - ## * `toUpperAscii proc<#toUpperAscii,char>`_ + ## * `toUpperAscii func<#toUpperAscii,char>`_ runnableExamples: doAssert capitalizeAscii("foo") == "Foo" doAssert capitalizeAscii("-bar") == "-bar" if s.len == 0: result = "" else: result = toUpperAscii(s[0]) & substr(s, 1) -proc nimIdentNormalize*(s: string): string = +func nimIdentNormalize*(s: string): string = ## Normalizes the string `s` as a Nim identifier. ## ## That means to convert to lower case and remove any '_' on all characters @@ -295,15 +290,14 @@ proc nimIdentNormalize*(s: string): string = inc j if j != s.len: setLen(result, j) -proc normalize*(s: string): string {.noSideEffect, - rtl, extern: "nsuNormalize".} = +func normalize*(s: string): string {.rtl, extern: "nsuNormalize".} = ## Normalizes the string `s`. ## ## That means to convert it to lower case and remove any '_'. This ## should NOT be used to normalize Nim identifier names. ## ## See also: - ## * `toLowerAscii proc<#toLowerAscii,string>`_ + ## * `toLowerAscii func<#toLowerAscii,string>`_ runnableExamples: doAssert normalize("Foo_bar") == "foobar" doAssert normalize("Foo Bar") == "foo bar" @@ -318,8 +312,7 @@ proc normalize*(s: string): string {.noSideEffect, inc j if j != s.len: setLen(result, j) -proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreCase".} = +func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} = ## Compares two strings in a case insensitive manner. Returns: ## ## | 0 if a == b @@ -340,8 +333,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, {.push checks: off, line_trace: off.} # this is a hot-spot in the compiler! # thus we compile without checks here -proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreStyle".} = +func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} = ## Semantically the same as ``cmp(normalize(a), normalize(b))``. It ## is just optimized to not allocate temporary strings. This should ## NOT be used to compare Nim identifier names. @@ -378,7 +370,7 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, # --------- Private templates for different split separators ----------- -proc substrEq(s: string, pos: int, substr: string): bool = +func substrEq(s: string, pos: int, substr: string): bool = var i = 0 var length = substr.len while i < length and pos+i < s.len and s[pos+i] == substr[i]: @@ -456,7 +448,7 @@ iterator split*(s: string, sep: char, maxsplit: int = -1): string = ## * `rsplit iterator<#rsplit.i,string,char,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `split proc<#split,string,char,int>`_ + ## * `split func<#split,string,char,int>`_ splitCommon(s, sep, maxsplit, 1) iterator split*(s: string, seps: set[char] = Whitespace, @@ -505,7 +497,7 @@ iterator split*(s: string, seps: set[char] = Whitespace, ## * `rsplit iterator<#rsplit.i,string,set[char],int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `split proc<#split,string,set[char],int>`_ + ## * `split func<#split,string,set[char],int>`_ splitCommon(s, seps, maxsplit, 1) iterator split*(s: string, sep: string, maxsplit: int = -1): string = @@ -529,7 +521,7 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string = ## * `rsplit iterator<#rsplit.i,string,string,int,bool>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `split proc<#split,string,string,int>`_ + ## * `split func<#split,string,string,int>`_ splitCommon(s, sep, maxsplit, sep.len) @@ -579,7 +571,7 @@ iterator rsplit*(s: string, sep: char, ## * `split iterator<#split.i,string,char,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `rsplit proc<#rsplit,string,char,int>`_ + ## * `rsplit func<#rsplit,string,char,int>`_ rsplitCommon(s, sep, maxsplit, 1) iterator rsplit*(s: string, seps: set[char] = Whitespace, @@ -604,7 +596,7 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace, ## * `split iterator<#split.i,string,set[char],int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `rsplit proc<#rsplit,string,set[char],int>`_ + ## * `rsplit func<#rsplit,string,set[char],int>`_ rsplitCommon(s, seps, maxsplit, 1) iterator rsplit*(s: string, sep: string, maxsplit: int = -1, @@ -629,7 +621,7 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1, ## * `split iterator<#split.i,string,string,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `rsplit proc<#rsplit,string,string,int>`_ + ## * `rsplit func<#rsplit,string,string,int>`_ rsplitCommon(s, sep, maxsplit, sep.len) iterator splitLines*(s: string, keepEol = false): string = @@ -659,7 +651,7 @@ iterator splitLines*(s: string, keepEol = false): string = ## ## See also: ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ - ## * `splitLines proc<#splitLines,string>`_ + ## * `splitLines func<#splitLines,string>`_ var first = 0 var last = 0 var eolpos = 0 @@ -716,43 +708,43 @@ iterator splitWhitespace*(s: string, maxsplit: int = -1): string = ## ## See also: ## * `splitLines iterator<#splitLines.i,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ oldSplit(s, Whitespace, maxsplit) -proc split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.noSideEffect, - rtl, extern: "nsuSplitChar".} = +func split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, + extern: "nsuSplitChar".} = ## The same as the `split iterator <#split.i,string,char,int>`_ (see its - ## documentation), but is a proc that returns a sequence of substrings. + ## documentation), but is a func that returns a sequence of substrings. ## ## See also: ## * `split iterator <#split.i,string,char,int>`_ - ## * `rsplit proc<#rsplit,string,char,int>`_ - ## * `splitLines proc<#splitLines,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `rsplit func<#rsplit,string,char,int>`_ + ## * `splitLines func<#splitLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a,b,c".split(',') == @["a", "b", "c"] doAssert "".split(' ') == @[""] accResult(split(s, sep, maxsplit)) -proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] {. - noSideEffect, rtl, extern: "nsuSplitCharSet".} = +func split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[ + string] {.rtl, extern: "nsuSplitCharSet".} = ## The same as the `split iterator <#split.i,string,set[char],int>`_ (see its - ## documentation), but is a proc that returns a sequence of substrings. + ## documentation), but is a func that returns a sequence of substrings. ## ## See also: ## * `split iterator <#split.i,string,set[char],int>`_ - ## * `rsplit proc<#rsplit,string,set[char],int>`_ - ## * `splitLines proc<#splitLines,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `rsplit func<#rsplit,string,set[char],int>`_ + ## * `splitLines func<#splitLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a,b;c".split({',', ';'}) == @["a", "b", "c"] doAssert "".split({' '}) == @[""] accResult(split(s, seps, maxsplit)) -proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEffect, - rtl, extern: "nsuSplitString".} = +func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, + extern: "nsuSplitString".} = ## Splits the string `s` into substrings using a string separator. ## ## Substrings are separated by the string `sep`. This is a wrapper around the @@ -760,9 +752,9 @@ proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEff ## ## See also: ## * `split iterator <#split.i,string,string,int>`_ - ## * `rsplit proc<#rsplit,string,string,int>`_ - ## * `splitLines proc<#splitLines,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `rsplit func<#rsplit,string,string,int>`_ + ## * `splitLines func<#splitLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a,b,c".split(",") == @["a", "b", "c"] doAssert "a man a plan a canal panama".split("a ") == @["", "man ", "plan ", "canal panama"] @@ -774,9 +766,9 @@ proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEff accResult(split(s, sep, maxsplit)) -proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] - {.noSideEffect, rtl, extern: "nsuRSplitChar".} = - ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a proc +func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, + extern: "nsuRSplitChar".} = + ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a func ## that returns a sequence of substrings. ## ## A possible common use case for `rsplit` is path manipulation, @@ -795,17 +787,17 @@ proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] ## ## See also: ## * `rsplit iterator <#rsplit.i,string,char,int>`_ - ## * `split proc<#split,string,char,int>`_ - ## * `splitLines proc<#splitLines,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `split func<#split,string,char,int>`_ + ## * `splitLines func<#splitLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ accResult(rsplit(s, sep, maxsplit)) result.reverse() -proc rsplit*(s: string, seps: set[char] = Whitespace, +func rsplit*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] - {.noSideEffect, rtl, extern: "nsuRSplitCharSet".} = + {.rtl, extern: "nsuRSplitCharSet".} = ## The same as the `rsplit iterator <#rsplit.i,string,set[char],int>`_, but is a - ## proc that returns a sequence of substrings. + ## func that returns a sequence of substrings. ## ## A possible common use case for `rsplit` is path manipulation, ## particularly on systems that don't use a common delimiter. @@ -823,15 +815,15 @@ proc rsplit*(s: string, seps: set[char] = Whitespace, ## ## See also: ## * `rsplit iterator <#rsplit.i,string,set[char],int>`_ - ## * `split proc<#split,string,set[char],int>`_ - ## * `splitLines proc<#splitLines,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `split func<#split,string,set[char],int>`_ + ## * `splitLines func<#splitLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ accResult(rsplit(s, seps, maxsplit)) result.reverse() -proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] - {.noSideEffect, rtl, extern: "nsuRSplitString".} = - ## The same as the `rsplit iterator <#rsplit.i,string,string,int,bool>`_, but is a proc +func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, + extern: "nsuRSplitString".} = + ## The same as the `rsplit iterator <#rsplit.i,string,string,int,bool>`_, but is a func ## that returns a sequence of substrings. ## ## A possible common use case for `rsplit` is path manipulation, @@ -850,9 +842,9 @@ proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] ## ## See also: ## * `rsplit iterator <#rsplit.i,string,string,int,bool>`_ - ## * `split proc<#split,string,string,int>`_ - ## * `splitLines proc<#splitLines,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ + ## * `split func<#split,string,string,int>`_ + ## * `splitLines func<#splitLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ runnableExamples: doAssert "a largely spaced sentence".rsplit(" ", maxsplit = 1) == @[ "a largely spaced", "sentence"] @@ -865,29 +857,28 @@ proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] accResult(rsplit(s, sep, maxsplit)) result.reverse() -proc splitLines*(s: string, keepEol = false): seq[string] {.noSideEffect, - rtl, extern: "nsuSplitLines".} = +func splitLines*(s: string, keepEol = false): seq[string] {.rtl, + extern: "nsuSplitLines".} = ## The same as the `splitLines iterator<#splitLines.i,string>`_ (see its - ## documentation), but is a proc that returns a sequence of substrings. + ## documentation), but is a func that returns a sequence of substrings. ## ## See also: ## * `splitLines iterator<#splitLines.i,string>`_ - ## * `splitWhitespace proc<#splitWhitespace,string,int>`_ - ## * `countLines proc<#countLines,string>`_ + ## * `splitWhitespace func<#splitWhitespace,string,int>`_ + ## * `countLines func<#countLines,string>`_ accResult(splitLines(s, keepEol = keepEol)) -proc splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.noSideEffect, - rtl, extern: "nsuSplitWhitespace".} = +func splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.rtl, + extern: "nsuSplitWhitespace".} = ## The same as the `splitWhitespace iterator <#splitWhitespace.i,string,int>`_ - ## (see its documentation), but is a proc that returns a sequence of substrings. + ## (see its documentation), but is a func that returns a sequence of substrings. ## ## See also: ## * `splitWhitespace iterator <#splitWhitespace.i,string,int>`_ - ## * `splitLines proc<#splitLines,string>`_ + ## * `splitLines func<#splitLines,string>`_ accResult(splitWhitespace(s, maxsplit)) -proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect, - rtl, extern: "nsuToBin".} = +func toBin*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToBin".} = ## Converts `x` into its binary representation. ## ## The resulting string is always `len` characters long. No leading ``0b`` @@ -909,14 +900,13 @@ proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect, inc shift mask = mask shl BiggestUInt(1) -proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect, - rtl, extern: "nsuToOct".} = +func toOct*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToOct".} = ## Converts `x` into its octal representation. ## ## The resulting string is always `len` characters long. No leading ``0o`` ## prefix is generated. ## - ## Do not confuse it with `toOctal proc<#toOctal,char>`_. + ## Do not confuse it with `toOctal func<#toOctal,char>`_. runnableExamples: let a = 62 @@ -934,7 +924,7 @@ proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect, inc shift, 3 mask = mask shl BiggestUInt(3) -proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.noSideEffect.} = +func toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string = const HexChars = "0123456789ABCDEF" var n = x @@ -945,7 +935,7 @@ proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.no # handle negative overflow if n == 0 and handleNegative: n = not(BiggestUInt 0) -proc toHex*[T: SomeInteger](x: T, len: Positive): string {.noSideEffect.} = +func toHex*[T: SomeInteger](x: T, len: Positive): string = ## Converts `x` to its hexadecimal representation. ## ## The resulting string will be exactly `len` characters long. No prefix like @@ -961,21 +951,21 @@ proc toHex*[T: SomeInteger](x: T, len: Positive): string {.noSideEffect.} = doAssert toHex(-8, 6) == "FFFFF8" toHexImpl(cast[BiggestUInt](x), len, x < 0) -proc toHex*[T: SomeInteger](x: T): string {.noSideEffect.} = +func toHex*[T: SomeInteger](x: T): string = ## Shortcut for ``toHex(x, T.sizeof * 2)`` runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" doAssert toHex(1984'i16) == "07C0" toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) -proc toHex*(s: string): string {.noSideEffect, rtl.} = +func toHex*(s: string): string {.rtl.} = ## Converts a bytes string to its hexadecimal representation. ## ## The output is twice the input long. No prefix like ## ``0x`` is generated. ## ## See also: - ## * `parseHexStr proc<#parseHexStr,string>`_ for the reverse operation + ## * `parseHexStr func<#parseHexStr,string>`_ for the reverse operation runnableExamples: let a = "1" @@ -993,13 +983,13 @@ proc toHex*(s: string): string {.noSideEffect, rtl.} = n = n shr 4 result[pos * 2] = HexChars[n] -proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} = +func toOctal*(c: char): string {.rtl, extern: "nsuToOctal".} = ## Converts a character `c` to its octal representation. ## ## The resulting string may not have a leading zero. Its length is always ## exactly 3. ## - ## Do not confuse it with `toOct proc<#toOct,BiggestInt,Positive>`_. + ## Do not confuse it with `toOct func<#toOct,BiggestInt,Positive>`_. runnableExamples: doAssert toOctal('1') == "061" doAssert toOctal('A') == "101" @@ -1012,7 +1002,7 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} = result[i] = chr(val mod 8 + ord('0')) val = val div 8 -proc fromBin*[T: SomeInteger](s: string): T = +func fromBin*[T: SomeInteger](s: string): T = ## Parses a binary integer value from a string `s`. ## ## If `s` is not a valid binary integer, `ValueError` is raised. `s` can have @@ -1035,7 +1025,7 @@ proc fromBin*[T: SomeInteger](s: string): T = if p != s.len or p == 0: raise newException(ValueError, "invalid binary integer: " & s) -proc fromOct*[T: SomeInteger](s: string): T = +func fromOct*[T: SomeInteger](s: string): T = ## Parses an octal integer value from a string `s`. ## ## If `s` is not a valid octal integer, `ValueError` is raised. `s` can have @@ -1058,7 +1048,7 @@ proc fromOct*[T: SomeInteger](s: string): T = if p != s.len or p == 0: raise newException(ValueError, "invalid oct integer: " & s) -proc fromHex*[T: SomeInteger](s: string): T = +func fromHex*[T: SomeInteger](s: string): T = ## Parses a hex integer value from a string `s`. ## ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have @@ -1081,8 +1071,8 @@ proc fromHex*[T: SomeInteger](s: string): T = if p != s.len or p == 0: raise newException(ValueError, "invalid hex integer: " & s) -proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect, - rtl, extern: "nsuIntToStr".} = +func intToStr*(x: int, minchars: Positive = 1): string {.rtl, + extern: "nsuIntToStr".} = ## Converts `x` to its decimal representation. ## ## The resulting string will be minimally `minchars` characters long. This is @@ -1096,8 +1086,7 @@ proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect, if x < 0: result = '-' & result -proc parseInt*(s: string): int {.noSideEffect, - rtl, extern: "nsuParseInt".} = +func parseInt*(s: string): int {.rtl, extern: "nsuParseInt".} = ## Parses a decimal integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. @@ -1108,8 +1097,8 @@ proc parseInt*(s: string): int {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) -proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, - rtl, extern: "nsuParseBiggestInt".} = +func parseBiggestInt*(s: string): BiggestInt {.rtl, + extern: "nsuParseBiggestInt".} = ## Parses a decimal integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. @@ -1118,8 +1107,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) -proc parseUInt*(s: string): uint {.noSideEffect, - rtl, extern: "nsuParseUInt".} = +func parseUInt*(s: string): uint {.rtl, extern: "nsuParseUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. @@ -1128,8 +1116,8 @@ proc parseUInt*(s: string): uint {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, - rtl, extern: "nsuParseBiggestUInt".} = +func parseBiggestUInt*(s: string): BiggestUInt {.rtl, + extern: "nsuParseBiggestUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. @@ -1138,8 +1126,7 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -proc parseFloat*(s: string): float {.noSideEffect, - rtl, extern: "nsuParseFloat".} = +func parseFloat*(s: string): float {.rtl, extern: "nsuParseFloat".} = ## Parses a decimal floating point value contained in `s`. ## ## If `s` is not a valid floating point number, `ValueError` is raised. @@ -1152,8 +1139,7 @@ proc parseFloat*(s: string): float {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid float: " & s) -proc parseBinInt*(s: string): int {.noSideEffect, - rtl, extern: "nsuParseBinInt".} = +func parseBinInt*(s: string): int {.rtl, extern: "nsuParseBinInt".} = ## Parses a binary integer value contained in `s`. ## ## If `s` is not a valid binary integer, `ValueError` is raised. `s` can have @@ -1171,8 +1157,7 @@ proc parseBinInt*(s: string): int {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid binary integer: " & s) -proc parseOctInt*(s: string): int {.noSideEffect, - rtl, extern: "nsuParseOctInt".} = +func parseOctInt*(s: string): int {.rtl, extern: "nsuParseOctInt".} = ## Parses an octal integer value contained in `s`. ## ## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one @@ -1183,8 +1168,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid oct integer: " & s) -proc parseHexInt*(s: string): int {.noSideEffect, - rtl, extern: "nsuParseHexInt".} = +func parseHexInt*(s: string): int {.rtl, extern: "nsuParseHexInt".} = ## Parses a hexadecimal integer value contained in `s`. ## ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one @@ -1195,7 +1179,7 @@ proc parseHexInt*(s: string): int {.noSideEffect, if L != s.len or L == 0: raise newException(ValueError, "invalid hex integer: " & s) -proc generateHexCharToValueMap(): string = +func generateHexCharToValueMap(): string = ## Generate a string to map a hex digit to uint value result = "" for inp in 0..255: @@ -1210,15 +1194,14 @@ proc generateHexCharToValueMap(): string = const hexCharToValueMap = generateHexCharToValueMap() -proc parseHexStr*(s: string): string {.noSideEffect, - rtl, extern: "nsuParseHexStr".} = +func parseHexStr*(s: string): string {.rtl, extern: "nsuParseHexStr".} = ## Convert hex-encoded string to byte string, e.g.: ## ## Raises ``ValueError`` for an invalid hex values. The comparison is ## case-insensitive. ## ## See also: - ## * `toHex proc<#toHex,string>`_ for the reverse operation + ## * `toHex func<#toHex,string>`_ for the reverse operation runnableExamples: let a = "41" @@ -1242,7 +1225,7 @@ proc parseHexStr*(s: string): string {.noSideEffect, else: result[pos div 2] = chr(val + buf shl 4) -proc parseBool*(s: string): bool = +func parseBool*(s: string): bool = ## Parses a value into a `bool`. ## ## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then @@ -1258,7 +1241,7 @@ proc parseBool*(s: string): bool = of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) -proc parseEnum*[T: enum](s: string): T = +func parseEnum*[T: enum](s: string): T = ## Parses an enum ``T``. This errors at compile time, if the given enum ## type contains multiple fields with the same string value. ## @@ -1278,7 +1261,7 @@ proc parseEnum*[T: enum](s: string): T = genEnumCaseStmt(T, s, default = nil, ord(low(T)), ord(high(T)), nimIdentNormalize) -proc parseEnum*[T: enum](s: string, default: T): T = +func parseEnum*[T: enum](s: string, default: T): T = ## Parses an enum ``T``. This errors at compile time, if the given enum ## type contains multiple fields with the same string value. ## @@ -1297,8 +1280,7 @@ proc parseEnum*[T: enum](s: string, default: T): T = genEnumCaseStmt(T, s, default, ord(low(T)), ord(high(T)), nimIdentNormalize) -proc repeat*(c: char, count: Natural): string {.noSideEffect, - rtl, extern: "nsuRepeatChar".} = +func repeat*(c: char, count: Natural): string {.rtl, extern: "nsuRepeatChar".} = ## Returns a string of length `count` consisting only of ## the character `c`. runnableExamples: @@ -1307,8 +1289,7 @@ proc repeat*(c: char, count: Natural): string {.noSideEffect, result = newString(count) for i in 0..count-1: result[i] = c -proc repeat*(s: string, n: Natural): string {.noSideEffect, - rtl, extern: "nsuRepeatStr".} = +func repeat*(s: string, n: Natural): string {.rtl, extern: "nsuRepeatStr".} = ## Returns string `s` concatenated `n` times. runnableExamples: doAssert "+ foo +".repeat(3) == "+ foo ++ foo ++ foo +" @@ -1316,15 +1297,15 @@ proc repeat*(s: string, n: Natural): string {.noSideEffect, result = newStringOfCap(n * s.len) for i in 1..n: result.add(s) -proc spaces*(n: Natural): string {.inline.} = - ## Returns a string with `n` space characters. You can use this proc +func spaces*(n: Natural): string {.inline.} = + ## Returns a string with `n` space characters. You can use this func ## to left align strings. ## ## See also: - ## * `align proc<#align,string,Natural,char>`_ - ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ - ## * `indent proc<#indent,string,Natural,string>`_ - ## * `center proc<#center,string,int,char>`_ + ## * `align func<#align,string,Natural,char>`_ + ## * `alignLeft func<#alignLeft,string,Natural,char>`_ + ## * `indent func<#indent,string,Natural,string>`_ + ## * `center func<#center,string,int,char>`_ runnableExamples: let width = 15 @@ -1336,20 +1317,20 @@ proc spaces*(n: Natural): string {.inline.} = "This is a very long string|" repeat(' ', n) -proc align*(s: string, count: Natural, padding = ' '): string {. - noSideEffect, rtl, extern: "nsuAlignString".} = +func align*(s: string, count: Natural, padding = ' '): string {.rtl, + extern: "nsuAlignString".} = ## Aligns a string `s` with `padding`, so that it is of length `count`. ## ## `padding` characters (by default spaces) are added before `s` resulting in ## right alignment. If ``s.len >= count``, no spaces are added and `s` is ## returned unchanged. If you need to left align a string use the `alignLeft - ## proc <#alignLeft,string,Natural,char>`_. + ## func<#alignLeft,string,Natural,char>`_. ## ## See also: - ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ - ## * `spaces proc<#spaces,Natural>`_ - ## * `indent proc<#indent,string,Natural,string>`_ - ## * `center proc<#center,string,int,char>`_ + ## * `alignLeft func<#alignLeft,string,Natural,char>`_ + ## * `spaces func<#spaces,Natural>`_ + ## * `indent func<#indent,string,Natural,string>`_ + ## * `center func<#center,string,int,char>`_ runnableExamples: assert align("abc", 4) == " abc" assert align("a", 0) == "a" @@ -1363,20 +1344,19 @@ proc align*(s: string, count: Natural, padding = ' '): string {. else: result = s -proc alignLeft*(s: string, count: Natural, padding = ' '): string {. - noSideEffect.} = +func alignLeft*(s: string, count: Natural, padding = ' '): string = ## Left-Aligns a string `s` with `padding`, so that it is of length `count`. ## ## `padding` characters (by default spaces) are added after `s` resulting in ## left alignment. If ``s.len >= count``, no spaces are added and `s` is ## returned unchanged. If you need to right align a string use the `align - ## proc <#align,string,Natural,char>`_. + ## func<#align,string,Natural,char>`_. ## ## See also: - ## * `align proc<#align,string,Natural,char>`_ - ## * `spaces proc<#spaces,Natural>`_ - ## * `indent proc<#indent,string,Natural,string>`_ - ## * `center proc<#center,string,int,char>`_ + ## * `align func<#align,string,Natural,char>`_ + ## * `spaces func<#spaces,Natural>`_ + ## * `indent func<#indent,string,Natural,string>`_ + ## * `center func<#center,string,int,char>`_ runnableExamples: assert alignLeft("abc", 4) == "abc " assert alignLeft("a", 0) == "a" @@ -1391,8 +1371,8 @@ proc alignLeft*(s: string, count: Natural, padding = ' '): string {. else: result = s -proc center*(s: string, width: int, fillChar: char = ' '): string {. - noSideEffect, rtl, extern: "nsuCenterString".} = +func center*(s: string, width: int, fillChar: char = ' '): string {.rtl, + extern: "nsuCenterString".} = ## Return the contents of `s` centered in a string `width` long using ## `fillChar` (default: space) as padding. ## @@ -1400,10 +1380,10 @@ proc center*(s: string, width: int, fillChar: char = ' '): string {. ## to `s.len`. ## ## See also: - ## * `align proc<#align,string,Natural,char>`_ - ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ - ## * `spaces proc<#spaces,Natural>`_ - ## * `indent proc<#indent,string,Natural,string>`_ + ## * `align func<#align,string,Natural,char>`_ + ## * `alignLeft func<#alignLeft,string,Natural,char>`_ + ## * `spaces func<#spaces,Natural>`_ + ## * `indent func<#indent,string,Natural,string>`_ runnableExamples: let a = "foo" doAssert a.center(2) == "foo" @@ -1426,18 +1406,18 @@ proc center*(s: string, width: int, fillChar: char = ' '): string {. # the string s should go result[i] = fillChar -proc indent*(s: string, count: Natural, padding: string = " "): string - {.noSideEffect, rtl, extern: "nsuIndent".} = +func indent*(s: string, count: Natural, padding: string = " "): string {.rtl, + extern: "nsuIndent".} = ## Indents each line in ``s`` by ``count`` amount of ``padding``. ## ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `align proc<#align,string,Natural,char>`_ - ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ - ## * `spaces proc<#spaces,Natural>`_ - ## * `unindent proc<#unindent,string,Natural,string>`_ - ## * `dedent proc<#dedent,string,Natural>`_ + ## * `align func<#align,string,Natural,char>`_ + ## * `alignLeft func<#alignLeft,string,Natural,char>`_ + ## * `spaces func<#spaces,Natural>`_ + ## * `unindent func<#unindent,string,Natural,string>`_ + ## * `dedent func<#dedent,string,Natural>`_ runnableExamples: doAssert indent("First line\c\l and second line.", 2) == " First line\l and second line." @@ -1451,18 +1431,18 @@ proc indent*(s: string, count: Natural, padding: string = " "): string result.add(line) i.inc -proc unindent*(s: string, count: Natural = int.high, padding: string = " "): string - {.noSideEffect, rtl, extern: "nsuUnindent".} = +func unindent*(s: string, count: Natural = int.high, + padding: string = " "): string {.rtl, extern: "nsuUnindent".} = ## Unindents each line in ``s`` by ``count`` amount of ``padding``. ## ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `dedent proc<#dedent,string,Natural>`_ - ## * `align proc<#align,string,Natural,char>`_ - ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ - ## * `spaces proc<#spaces,Natural>`_ - ## * `indent proc<#indent,string,Natural,string>`_ + ## * `dedent func<#dedent,string,Natural>`_ + ## * `align func<#align,string,Natural,char>`_ + ## * `alignLeft func<#alignLeft,string,Natural,char>`_ + ## * `spaces func<#spaces,Natural>`_ + ## * `indent func<#indent,string,Natural,string>`_ runnableExamples: let x = """ Hello @@ -1484,7 +1464,7 @@ proc unindent*(s: string, count: Natural = int.high, padding: string = " "): str result.add(line[indentCount*padding.len .. ^1]) i.inc -proc indentation*(s: string): Natural {.since: (1, 3).} = +func indentation*(s: string): Natural {.since: (1, 3).} = ## Returns the amount of indentation all lines of ``s`` have in common, ## ignoring lines that consist only of whitespace. result = int.high @@ -1497,22 +1477,22 @@ proc indentation*(s: string): Natural {.since: (1, 3).} = if result == int.high: result = 0 -proc dedent*(s: string, count: Natural = indentation(s)): string - {.noSideEffect, rtl, extern: "nsuDedent", since: (1, 3).} = +func dedent*(s: string, count: Natural = indentation(s)): string {.rtl, + extern: "nsuDedent", since: (1, 3).} = ## Unindents each line in ``s`` by ``count`` amount of ``padding``. ## The only difference between this and the - ## `unindent proc<#unindent,string,Natural,string>`_ is that this by default + ## `unindent func<#unindent,string,Natural,string>`_ is that this by default ## only cuts off the amount of indentation that all lines of ``s`` share as ## opposed to all indentation. It only supports spaces as padding. ## ## **Note:** This does not preserve the new line characters used in ``s``. ## ## See also: - ## * `unindent proc<#unindent,string,Natural,string>`_ - ## * `align proc<#align,string,Natural,char>`_ - ## * `alignLeft proc<#alignLeft,string,Natural,char>`_ - ## * `spaces proc<#spaces,Natural>`_ - ## * `indent proc<#indent,string,Natural,string>`_ + ## * `unindent func<#unindent,string,Natural,string>`_ + ## * `align func<#align,string,Natural,char>`_ + ## * `alignLeft func<#alignLeft,string,Natural,char>`_ + ## * `spaces func<#spaces,Natural>`_ + ## * `indent func<#indent,string,Natural,string>`_ runnableExamples: let x = """ Hello @@ -1522,8 +1502,7 @@ proc dedent*(s: string, count: Natural = indentation(s)): string doAssert x == "Hello\n There\n" unindent(s, count, " ") -proc delete*(s: var string, first, last: int) {.noSideEffect, - rtl, extern: "nsuDelete".} = +func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete".} = ## Deletes in `s` (must be declared as ``var``) the characters at positions ## ``first ..last`` (both ends included). ## @@ -1550,29 +1529,28 @@ proc delete*(s: var string, first, last: int) {.noSideEffect, setLen(s, newLen) -proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} = +func startsWith*(s: string, prefix: char): bool {.inline.} = ## Returns true if ``s`` starts with character ``prefix``. ## ## See also: - ## * `endsWith proc<#endsWith,string,char>`_ - ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ - ## * `removePrefix proc<#removePrefix,string,char>`_ + ## * `endsWith func<#endsWith,string,char>`_ + ## * `continuesWith func<#continuesWith,string,string,Natural>`_ + ## * `removePrefix func<#removePrefix,string,char>`_ runnableExamples: let a = "abracadabra" doAssert a.startsWith('a') == true doAssert a.startsWith('b') == false result = s.len > 0 and s[0] == prefix -proc startsWith*(s, prefix: string): bool {.noSideEffect, - rtl, extern: "nsuStartsWith".} = +func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} = ## Returns true if ``s`` starts with string ``prefix``. ## ## If ``prefix == ""`` true is returned. ## ## See also: - ## * `endsWith proc<#endsWith,string,string>`_ - ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ - ## * `removePrefix proc<#removePrefix,string,string>`_ + ## * `endsWith func<#endsWith,string,string>`_ + ## * `continuesWith func<#continuesWith,string,string,Natural>`_ + ## * `removePrefix func<#removePrefix,string,string>`_ runnableExamples: let a = "abracadabra" doAssert a.startsWith("abra") == true @@ -1583,29 +1561,28 @@ proc startsWith*(s, prefix: string): bool {.noSideEffect, if i >= s.len or s[i] != prefix[i]: return false inc(i) -proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} = +func endsWith*(s: string, suffix: char): bool {.inline.} = ## Returns true if ``s`` ends with ``suffix``. ## ## See also: - ## * `startsWith proc<#startsWith,string,char>`_ - ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ - ## * `removeSuffix proc<#removeSuffix,string,char>`_ + ## * `startsWith func<#startsWith,string,char>`_ + ## * `continuesWith func<#continuesWith,string,string,Natural>`_ + ## * `removeSuffix func<#removeSuffix,string,char>`_ runnableExamples: let a = "abracadabra" doAssert a.endsWith('a') == true doAssert a.endsWith('b') == false result = s.len > 0 and s[s.high] == suffix -proc endsWith*(s, suffix: string): bool {.noSideEffect, - rtl, extern: "nsuEndsWith".} = +func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} = ## Returns true if ``s`` ends with ``suffix``. ## ## If ``suffix == ""`` true is returned. ## ## See also: - ## * `startsWith proc<#startsWith,string,string>`_ - ## * `continuesWith proc<#continuesWith,string,string,Natural>`_ - ## * `removeSuffix proc<#removeSuffix,string,string>`_ + ## * `startsWith func<#startsWith,string,string>`_ + ## * `continuesWith func<#continuesWith,string,string,Natural>`_ + ## * `removeSuffix func<#removeSuffix,string,string>`_ runnableExamples: let a = "abracadabra" doAssert a.endsWith("abra") == true @@ -1617,15 +1594,15 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect, inc(i) if i >= suffix.len: return true -proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect, - rtl, extern: "nsuContinuesWith".} = +func continuesWith*(s, substr: string, start: Natural): bool {.rtl, + extern: "nsuContinuesWith".} = ## Returns true if ``s`` continues with ``substr`` at position ``start``. ## ## If ``substr == ""`` true is returned. ## ## See also: - ## * `startsWith proc<#startsWith,string,string>`_ - ## * `endsWith proc<#endsWith,string,string>`_ + ## * `startsWith func<#startsWith,string,string>`_ + ## * `endsWith func<#endsWith,string,string>`_ runnableExamples: let a = "abracadabra" doAssert a.continuesWith("ca", 4) == true @@ -1638,13 +1615,13 @@ proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect, inc(i) -proc removePrefix*(s: var string, chars: set[char] = Newlines) {. - rtl, extern: "nsuRemovePrefixCharSet".} = +func removePrefix*(s: var string, chars: set[char] = Newlines) {.rtl, + extern: "nsuRemovePrefixCharSet".} = ## Removes all characters from `chars` from the start of the string `s` ## (in-place). ## ## See also: - ## * `removeSuffix proc<#removeSuffix,string,set[char]>`_ + ## * `removeSuffix func<#removeSuffix,string,set[char]>`_ runnableExamples: var userInput = "\r\n*~Hello World!" userInput.removePrefix @@ -1660,27 +1637,27 @@ proc removePrefix*(s: var string, chars: set[char] = Newlines) {. while start < s.len and s[start] in chars: start += 1 if start > 0: s.delete(0, start - 1) -proc removePrefix*(s: var string, c: char) {. - rtl, extern: "nsuRemovePrefixChar".} = +func removePrefix*(s: var string, c: char) {.rtl, + extern: "nsuRemovePrefixChar".} = ## Removes all occurrences of a single character (in-place) from the start ## of a string. ## ## See also: - ## * `removeSuffix proc<#removeSuffix,string,char>`_ - ## * `startsWith proc<#startsWith,string,char>`_ + ## * `removeSuffix func<#removeSuffix,string,char>`_ + ## * `startsWith func<#startsWith,string,char>`_ runnableExamples: var ident = "pControl" ident.removePrefix('p') doAssert ident == "Control" removePrefix(s, chars = {c}) -proc removePrefix*(s: var string, prefix: string) {. - rtl, extern: "nsuRemovePrefixString".} = +func removePrefix*(s: var string, prefix: string) {.rtl, + extern: "nsuRemovePrefixString".} = ## Remove the first matching prefix (in-place) from a string. ## ## See also: - ## * `removeSuffix proc<#removeSuffix,string,string>`_ - ## * `startsWith proc<#startsWith,string,string>`_ + ## * `removeSuffix func<#removeSuffix,string,string>`_ + ## * `startsWith func<#startsWith,string,string>`_ runnableExamples: var answers = "yesyes" answers.removePrefix("yes") @@ -1688,13 +1665,13 @@ proc removePrefix*(s: var string, prefix: string) {. if s.startsWith(prefix): s.delete(0, prefix.len - 1) -proc removeSuffix*(s: var string, chars: set[char] = Newlines) {. - rtl, extern: "nsuRemoveSuffixCharSet".} = +func removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl, + extern: "nsuRemoveSuffixCharSet".} = ## Removes all characters from `chars` from the end of the string `s` ## (in-place). ## ## See also: - ## * `removePrefix proc<#removePrefix,string,set[char]>`_ + ## * `removePrefix func<#removePrefix,string,set[char]>`_ runnableExamples: var userInput = "Hello World!*~\r\n" userInput.removeSuffix @@ -1711,14 +1688,14 @@ proc removeSuffix*(s: var string, chars: set[char] = Newlines) {. while last > -1 and s[last] in chars: last -= 1 s.setLen(last + 1) -proc removeSuffix*(s: var string, c: char) {. - rtl, extern: "nsuRemoveSuffixChar".} = +func removeSuffix*(s: var string, c: char) {.rtl, + extern: "nsuRemoveSuffixChar".} = ## Removes all occurrences of a single character (in-place) from the end ## of a string. ## ## See also: - ## * `removePrefix proc<#removePrefix,string,char>`_ - ## * `endsWith proc<#endsWith,string,char>`_ + ## * `removePrefix func<#removePrefix,string,char>`_ + ## * `endsWith func<#endsWith,string,char>`_ runnableExamples: var table = "users" table.removeSuffix('s') @@ -1730,13 +1707,13 @@ proc removeSuffix*(s: var string, c: char) {. removeSuffix(s, chars = {c}) -proc removeSuffix*(s: var string, suffix: string) {. - rtl, extern: "nsuRemoveSuffixString".} = +func removeSuffix*(s: var string, suffix: string) {.rtl, + extern: "nsuRemoveSuffixString".} = ## Remove the first matching suffix (in-place) from a string. ## ## See also: - ## * `removePrefix proc<#removePrefix,string,string>`_ - ## * `endsWith proc<#endsWith,string,string>`_ + ## * `removePrefix func<#removePrefix,string,string>`_ + ## * `endsWith func<#endsWith,string,string>`_ runnableExamples: var answers = "yeses" answers.removeSuffix("es") @@ -1747,8 +1724,7 @@ proc removeSuffix*(s: var string, suffix: string) {. s.setLen(newLen) -proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0) - {.noSideEffect, inline.} = +func addSep*(dest: var string, sep = ", ", startLen: Natural = 0) {.inline.} = ## Adds a separator to `dest` only if its length is bigger than `startLen`. ## ## A shorthand for: @@ -1770,7 +1746,7 @@ proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0) if dest.len > startLen: add(dest, sep) -proc allCharsInSet*(s: string, theSet: set[char]): bool = +func allCharsInSet*(s: string, theSet: set[char]): bool = ## Returns true if every character of `s` is in the set `theSet`. runnableExamples: doAssert allCharsInSet("aeea", {'a', 'e'}) == true @@ -1780,7 +1756,7 @@ proc allCharsInSet*(s: string, theSet: set[char]): bool = if c notin theSet: return false return true -proc abbrev*(s: string, possibilities: openArray[string]): int = +func abbrev*(s: string, possibilities: openArray[string]): int = ## Returns the index of the first item in ``possibilities`` which starts ## with ``s``, if not ambiguous. ## @@ -1802,8 +1778,8 @@ proc abbrev*(s: string, possibilities: openArray[string]): int = # --------------------------------------------------------------------------- -proc join*(a: openArray[string], sep: string = ""): string {. - noSideEffect, rtl, extern: "nsuJoinSep".} = +func join*(a: openArray[string], sep: string = ""): string {.rtl, + extern: "nsuJoinSep".} = ## Concatenates all strings in the container `a`, separating them with `sep`. runnableExamples: doAssert join(["A", "B", "Conclusion"], " -> ") == "A -> B -> Conclusion" @@ -1819,8 +1795,7 @@ proc join*(a: openArray[string], sep: string = ""): string {. else: result = "" -proc join*[T: not string](a: openArray[T], sep: string = ""): string {. - noSideEffect, rtl.} = +func join*[T: not string](a: openArray[T], sep: string = ""): string {.rtl.} = ## Converts all elements in the container `a` to strings using `$`, ## and concatenates them with `sep`. runnableExamples: @@ -1835,8 +1810,8 @@ proc join*[T: not string](a: openArray[T], sep: string = ""): string {. type SkipTable* = array[char, int] -proc initSkipTable*(a: var SkipTable, sub: string) - {.noSideEffect, rtl, extern: "nsuInitSkipTable".} = +func initSkipTable*(a: var SkipTable, sub: string) {.rtl, + extern: "nsuInitSkipTable".} = ## Preprocess table `a` for `sub`. let m = len(sub) var i = 0 @@ -1854,8 +1829,8 @@ proc initSkipTable*(a: var SkipTable, sub: string) for i in 0 ..< m - 1: a[sub[i]] = m - 1 - i -proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int - {.noSideEffect, rtl, extern: "nsuFindStrA".} = +func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. + rtl, extern: "nsuFindStrA".} = ## Searches for `sub` in `s` inside range `start..last` using preprocessed ## table `a`. If `last` is unspecified, it defaults to `s.high` (the last ## element). @@ -1884,14 +1859,14 @@ proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int return -1 when not (defined(js) or defined(nimdoc) or defined(nimscript)): - proc c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. + func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. importc: "memchr", header: "".} const hasCStringBuiltin = true else: const hasCStringBuiltin = false -proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffect, - rtl, extern: "nsuFindChar".} = +func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, + extern: "nsuFindChar".} = ## Searches for `sub` in `s` inside range ``start..last`` (both ends included). ## If `last` is unspecified, it defaults to `s.high` (the last element). ## @@ -1900,8 +1875,8 @@ proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffe ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `rfind proc<#rfind,string,char,Natural>`_ - ## * `replace proc<#replace,string,char,char>`_ + ## * `rfind func<#rfind,string,char,Natural>`_ + ## * `replace func<#replace,string,char,char>`_ let last = if last == 0: s.high else: last when nimvm: for i in int(start)..last: @@ -1918,8 +1893,8 @@ proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffe if sub == s[i]: return i return -1 -proc find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.noSideEffect, - rtl, extern: "nsuFindCharSet".} = +func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. + rtl, extern: "nsuFindCharSet".} = ## Searches for `chars` in `s` inside range ``start..last`` (both ends included). ## If `last` is unspecified, it defaults to `s.high` (the last element). ## @@ -1928,15 +1903,15 @@ proc find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.noS ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `rfind proc<#rfind,string,set[char],Natural>`_ - ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ + ## * `rfind func<#rfind,string,set[char],Natural>`_ + ## * `multiReplace func<#multiReplace,string,varargs[]>`_ let last = if last == 0: s.high else: last for i in int(start)..last: if s[i] in chars: return i return -1 -proc find*(s, sub: string, start: Natural = 0, last = 0): int {.noSideEffect, - rtl, extern: "nsuFindStr".} = +func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, + extern: "nsuFindStr".} = ## Searches for `sub` in `s` inside range ``start..last`` (both ends included). ## If `last` is unspecified, it defaults to `s.high` (the last element). ## @@ -1945,16 +1920,16 @@ proc find*(s, sub: string, start: Natural = 0, last = 0): int {.noSideEffect, ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `rfind proc<#rfind,string,string,Natural>`_ - ## * `replace proc<#replace,string,string,string>`_ + ## * `rfind func<#rfind,string,string,Natural>`_ + ## * `replace func<#replace,string,string,string>`_ if sub.len > s.len: return -1 if sub.len == 1: return find(s, sub[0], start, last) var a {.noinit.}: SkipTable initSkipTable(a, sub) result = find(a, s, sub, start, last) -proc rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.noSideEffect, - rtl, extern: "nsuRFindChar".} = +func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, + extern: "nsuRFindChar".} = ## Searches for `sub` in `s` inside range ``start..last`` (both ends included) ## in reverse -- starting at high indexes and moving lower to the first ## character or ``start``. If `last` is unspecified, it defaults to `s.high` @@ -1965,14 +1940,14 @@ proc rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.noSideEf ## Use `s[start..last].find` for a ``start``-origin index. ## ## See also: - ## * `find proc<#find,string,char,Natural,int>`_ + ## * `find func<#find,string,char,Natural,int>`_ let last = if last == -1: s.high else: last for i in countdown(last, start): if sub == s[i]: return i return -1 -proc rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {.noSideEffect, - rtl, extern: "nsuRFindCharSet".} = +func rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. + rtl, extern: "nsuRFindCharSet".} = ## Searches for `chars` in `s` inside range ``start..last`` (both ends ## included) in reverse -- starting at high indexes and moving lower to the ## first character or ``start``. If `last` is unspecified, it defaults to @@ -1983,14 +1958,14 @@ proc rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {.n ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `find proc<#find,string,set[char],Natural,int>`_ + ## * `find func<#find,string,set[char],Natural,int>`_ let last = if last == -1: s.high else: last for i in countdown(last, start): if s[i] in chars: return i return -1 -proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect, - rtl, extern: "nsuRFindStr".} = +func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, + extern: "nsuRFindStr".} = ## Searches for `sub` in `s` inside range ``start..last`` (both ends included) ## included) in reverse -- starting at high indexes and moving lower to the ## first character or ``start``. If `last` is unspecified, it defaults to @@ -2001,7 +1976,7 @@ proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect, ## Use `s[start..last].rfind` for a ``start``-origin index. ## ## See also: - ## * `find proc<#find,string,string,Natural,int>`_ + ## * `find func<#find,string,string,Natural,int>`_ if sub.len == 0: return -1 let last = if last == -1: s.high else: last @@ -2016,35 +1991,34 @@ proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect, return -1 -proc count*(s: string, sub: char): int {.noSideEffect, - rtl, extern: "nsuCountChar".} = +func count*(s: string, sub: char): int {.rtl, extern: "nsuCountChar".} = ## Count the occurrences of the character `sub` in the string `s`. ## ## See also: - ## * `countLines proc<#countLines,string>`_ + ## * `countLines func<#countLines,string>`_ result = 0 for c in s: if c == sub: inc result -proc count*(s: string, subs: set[char]): int {.noSideEffect, - rtl, extern: "nsuCountCharSet".} = +func count*(s: string, subs: set[char]): int {.rtl, + extern: "nsuCountCharSet".} = ## Count the occurrences of the group of character `subs` in the string `s`. ## ## See also: - ## * `countLines proc<#countLines,string>`_ + ## * `countLines func<#countLines,string>`_ doAssert card(subs) > 0 result = 0 for c in s: if c in subs: inc result -proc count*(s: string, sub: string, overlapping: bool = false): int {. - noSideEffect, rtl, extern: "nsuCountString".} = +func count*(s: string, sub: string, overlapping: bool = false): int {.rtl, + extern: "nsuCountString".} = ## Count the occurrences of a substring `sub` in the string `s`. ## Overlapping occurrences of `sub` only count when `overlapping` ## is set to true (default: false). ## ## See also: - ## * `countLines proc<#countLines,string>`_ + ## * `countLines func<#countLines,string>`_ doAssert sub.len > 0 result = 0 var i = 0 @@ -2055,8 +2029,7 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {. else: i += sub.len inc result -proc countLines*(s: string): int {.noSideEffect, - rtl, extern: "nsuCountLines".} = +func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = ## Returns the number of lines in the string `s`. ## ## This is the same as ``len(splitLines(s))``, but much more efficient @@ -2068,7 +2041,7 @@ proc countLines*(s: string): int {.noSideEffect, ## A line can be an empty string. ## ## See also: - ## * `splitLines proc<#splitLines,string>`_ + ## * `splitLines func<#splitLines,string>`_ runnableExamples: doAssert countLines("First line\l and second line.") == 2 result = 1 @@ -2083,30 +2056,30 @@ proc countLines*(s: string): int {.noSideEffect, inc i -proc contains*(s, sub: string): bool {.noSideEffect.} = +func contains*(s, sub: string): bool = ## Same as ``find(s, sub) >= 0``. ## ## See also: - ## * `find proc<#find,string,string,Natural,int>`_ + ## * `find func<#find,string,string,Natural,int>`_ return find(s, sub) >= 0 -proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} = +func contains*(s: string, chars: set[char]): bool = ## Same as ``find(s, chars) >= 0``. ## ## See also: - ## * `find proc<#find,string,set[char],Natural,int>`_ + ## * `find func<#find,string,set[char],Natural,int>`_ return find(s, chars) >= 0 -proc replace*(s, sub: string, by = ""): string {.noSideEffect, - rtl, extern: "nsuReplaceStr".} = +func replace*(s, sub: string, by = ""): string {.rtl, + extern: "nsuReplaceStr".} = ## Replaces `sub` in `s` by the string `by`. ## ## See also: - ## * `find proc<#find,string,string,Natural,int>`_ - ## * `replace proc<#replace,string,char,char>`_ for replacing + ## * `find func<#find,string,string,Natural,int>`_ + ## * `replace func<#replace,string,char,char>`_ for replacing ## single characters - ## * `replaceWord proc<#replaceWord,string,string,string>`_ - ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ + ## * `replaceWord func<#replaceWord,string,string,string>`_ + ## * `multiReplace func<#multiReplace,string,varargs[]>`_ result = "" let subLen = sub.len if subLen == 0: @@ -2139,17 +2112,17 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect, # copy the rest: add result, substr(s, i) -proc replace*(s: string, sub, by: char): string {.noSideEffect, - rtl, extern: "nsuReplaceChar".} = +func replace*(s: string, sub, by: char): string {.rtl, + extern: "nsuReplaceChar".} = ## Replaces `sub` in `s` by the character `by`. ## ## Optimized version of `replace <#replace,string,string,string>`_ for ## characters. ## ## See also: - ## * `find proc<#find,string,char,Natural,int>`_ - ## * `replaceWord proc<#replaceWord,string,string,string>`_ - ## * `multiReplace proc<#multiReplace,string,varargs[]>`_ + ## * `find func<#find,string,char,Natural,int>`_ + ## * `replaceWord func<#replaceWord,string,string,string>`_ + ## * `multiReplace func<#multiReplace,string,varargs[]>`_ result = newString(s.len) var i = 0 while i < s.len: @@ -2157,8 +2130,8 @@ proc replace*(s: string, sub, by: char): string {.noSideEffect, else: result[i] = s[i] inc(i) -proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, - rtl, extern: "nsuReplaceWord".} = +func replaceWord*(s, sub: string, by = ""): string {.rtl, + extern: "nsuReplaceWord".} = ## Replaces `sub` in `s` by the string `by`. ## ## Each occurrence of `sub` has to be surrounded by word boundaries @@ -2188,8 +2161,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, # copy the rest: add result, substr(s, i) -proc multiReplace*(s: string, replacements: varargs[(string, string)]): - string {.noSideEffect.} = +func multiReplace*(s: string, replacements: varargs[(string, string)]): string = ## Same as replace, but specialized for doing multiple replacements in a single ## pass through the input string. ## @@ -2224,8 +2196,8 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): -proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect, - rtl, extern: "nsuInsertSep".} = +func insertSep*(s: string, sep = '_', digits = 3): string {.rtl, + extern: "nsuInsertSep".} = ## Inserts the separator `sep` after `digits` characters (default: 3) ## from right to left. ## @@ -2258,8 +2230,8 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect, inc(j) dec(L) -proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, - rtl, extern: "nsuEscape".} = +func escape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, + extern: "nsuEscape".} = ## Escapes a string `s`. See `system.addEscapedChar ## `_ for the escaping scheme. ## @@ -2267,7 +2239,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, ## Both may be empty strings. ## ## See also: - ## * `unescape proc<#unescape,string,string,string>`_ for the opposite + ## * `unescape func<#unescape,string,string,string>`_ for the opposite ## operation result = newStringOfCap(s.len + s.len shr 2) result.add(prefix) @@ -2282,11 +2254,11 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, else: add(result, c) add(result, suffix) -proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, - rtl, extern: "nsuUnescape".} = +func unescape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, + extern: "nsuUnescape".} = ## Unescapes a string `s`. ## - ## This complements `escape proc<#escape,string,string,string>`_ + ## This complements `escape func<#escape,string,string,string>`_ ## as it performs the opposite operations. ## ## If `s` does not begin with ``prefix`` and end with ``suffix`` a @@ -2325,8 +2297,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, raise newException(ValueError, "String does not end in: " & suffix) -proc validIdentifier*(s: string): bool {.noSideEffect, - rtl, extern: "nsuValidIdentifier".} = +func validIdentifier*(s: string): bool {.rtl, extern: "nsuValidIdentifier".} = ## Returns true if `s` is a valid identifier. ## ## A valid identifier starts with a character of the set `IdentStartChars` @@ -2342,8 +2313,8 @@ proc validIdentifier*(s: string): bool {.noSideEffect, # floating point formatting: when not defined(js): - proc c_sprintf(buf, frmt: cstring): cint {.header: "", - importc: "sprintf", varargs, noSideEffect.} + func c_sprintf(buf, frmt: cstring): cint {.header: "", + importc: "sprintf", varargs} type FloatFormatMode* = enum @@ -2352,10 +2323,9 @@ type ffDecimal, ## use decimal floating point notation ffScientific ## use scientific notation (using ``e`` character) -proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, +func formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, precision: range[-1..32] = 16; - decimalSep = '.'): string {. - noSideEffect, rtl, extern: "nsu$1".} = + decimalSep = '.'): string {.rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## ## If ``format == ffDecimal`` then precision is the number of digits to @@ -2432,9 +2402,9 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, result[^2] = result[^1] result.setLen(result.len - 1) -proc formatFloat*(f: float, format: FloatFormatMode = ffDefault, +func formatFloat*(f: float, format: FloatFormatMode = ffDefault, precision: range[-1..32] = 16; decimalSep = '.'): string {. - noSideEffect, rtl, extern: "nsu$1".} = + rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## ## If ``format == ffDecimal`` then precision is the number of digits to @@ -2453,7 +2423,7 @@ proc formatFloat*(f: float, format: FloatFormatMode = ffDefault, result = formatBiggestFloat(f, format, precision, decimalSep) -proc trimZeros*(x: var string; decimalSep = '.') {.noSideEffect.} = +func trimZeros*(x: var string; decimalSep = '.') = ## Trim trailing zeros from a formatted floating point ## value `x` (must be declared as ``var``). ## @@ -2477,10 +2447,10 @@ type bpIEC, # use the IEC/ISO standard prefixes such as kibi bpColloquial # use the colloquial kilo, mega etc -proc formatSize*(bytes: int64, +func formatSize*(bytes: int64, decimalSep = '.', prefix = bpIEC, - includeSpace = false): string {.noSideEffect.} = + includeSpace = false): string = ## Rounds and formats `bytes`. ## ## By default, uses the IEC/ISO standard binary prefixes, so 1024 will be @@ -2533,13 +2503,13 @@ proc formatSize*(bytes: int64, result &= prefixes[matchedIndex] result &= "B" -proc formatEng*(f: BiggestFloat, +func formatEng*(f: BiggestFloat, precision: range[0..32] = 10, trim: bool = true, siPrefix: bool = false, unit: string = "", decimalSep = '.', - useUnitSpace = false): string {.noSideEffect.} = + useUnitSpace = false): string = ## Converts a floating point value `f` to a string using engineering notation. ## ## Numbers in of the range -1000.0`_). + ## `% func<#%25,string,openArray[string]>`_). result = newStringOfCap(formatstr.len + a.len) addf(result, formatstr, [a]) -proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, - rtl, extern: "nsuFormatVarargs".} = +func format*(formatstr: string, a: varargs[string, `$`]): string {.rtl, + extern: "nsuFormatVarargs".} = ## This is the same as ``formatstr % a`` (see - ## `% proc<#%25,string,openArray[string]>`_) except that it supports + ## `% func<#%25,string,openArray[string]>`_) except that it supports ## auto stringification. ## ## See also: @@ -2814,9 +2784,8 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, addf(result, formatstr, a) -proc strip*(s: string, leading = true, trailing = true, - chars: set[char] = Whitespace): string - {.noSideEffect, rtl, extern: "nsuStrip".} = +func strip*(s: string, leading = true, trailing = true, + chars: set[char] = Whitespace): string {.rtl, extern: "nsuStrip".} = ## Strips leading or trailing `chars` (default: whitespace characters) ## from `s` and returns the resulting string. ## @@ -2825,7 +2794,7 @@ proc strip*(s: string, leading = true, trailing = true, ## If both are false, the string is returned unchanged. ## ## See also: - ## * `stripLineEnd proc<#stripLineEnd,string>`_ + ## * `stripLineEnd func<#stripLineEnd,string>`_ runnableExamples: let a = " vhellov " let b = strip(a) @@ -2850,7 +2819,7 @@ proc strip*(s: string, leading = true, trailing = true, while last >= 0 and s[last] in chars: dec(last) result = substr(s, first, last) -proc stripLineEnd*(s: var string) = +func stripLineEnd*(s: var string) = ## Returns ``s`` stripped from one of these suffixes: ## ``\r, \n, \r\n, \f, \v`` (at most once instance). ## For example, can be useful in conjunction with ``osproc.execCmdEx``. @@ -2910,7 +2879,7 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ break i = j -proc isEmptyOrWhitespace*(s: string): bool {.noSideEffect, rtl, +func isEmptyOrWhitespace*(s: string): bool {.rtl, extern: "nsuIsEmptyOrWhitespace".} = ## Checks if `s` is empty or consists entirely of whitespace characters. result = s.allCharsInSet(Whitespace) diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 0028e7d7e..715278f51 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim c --experimental:strictFuncs --experimental:views $file" """ -import tables, streams, nre, parsecsv, uri, httpcore +import tables, streams, nre, parsecsv, uri, httpcore, strutils type Contig2Reads = TableRef[string, seq[string]] @@ -26,4 +26,4 @@ block: result[x.len] = move(y) var x = @[0, 1] - let z = x &&& 2 \ No newline at end of file + let z = x &&& 2 diff --git a/tests/errmsgs/tunknown_named_parameter.nim b/tests/errmsgs/tunknown_named_parameter.nim index 829ab9497..d3dd6cd2d 100644 --- a/tests/errmsgs/tunknown_named_parameter.nim +++ b/tests/errmsgs/tunknown_named_parameter.nim @@ -2,15 +2,15 @@ discard """ cmd: "nim check $file" errormsg: "type mismatch: got " nimout: ''' -proc rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] +func rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: char but expression '{':'}' is of type: set[char] -proc rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] +func rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] first type mismatch at position: 2 required type for sep: string but expression '{':'}' is of type: set[char] -proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[ +func rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[ string] first type mismatch at position: 3 unknown named parameter: maxsplits From 2297b9623843bb4c1dbd201a8fb57f9ec334c164 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 7 Dec 2020 23:26:14 +0100 Subject: [PATCH 1629/4254] math.nim: Use `func` everywhere (#16285) * math.nim: procs with {.noSideEffect} -> funcs * math.nim: procs without {.noSideEffect.} -> funcs * math.nim: proc -> func in links * math.nim: proc -> func in doc comments * test: add `math` to strictFuncs test --- lib/pure/math.nim | 526 ++++++++++++++++---------------- tests/effects/tstrict_funcs.nim | 10 +- 2 files changed, 271 insertions(+), 265 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 8f5b9a6f5..b2433d309 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -58,7 +58,7 @@ import std/private/since import bitops, fenv -proc binom*(n, k: int): int {.noSideEffect.} = +func binom*(n, k: int): int = ## Computes the `binomial coefficient `_. runnableExamples: doAssert binom(6, 2) == binom(6, 4) @@ -71,17 +71,17 @@ proc binom*(n, k: int): int {.noSideEffect.} = for i in countup(2, k): result = (result * (n + 1 - i)) div i -proc createFactTable[N: static[int]]: array[N, int] = +func createFactTable[N: static[int]]: array[N, int] = result[0] = 1 for i in 1 ..< N: result[i] = result[i - 1] * i -proc fac*(n: int): int = +func fac*(n: int): int = ## Computes the `factorial `_ of ## a non-negative integer ``n``. ## ## See also: - ## * `prod proc <#prod,openArray[T]>`_ + ## * `prod func <#prod,openArray[T]>`_ runnableExamples: doAssert fac(3) == 6 doAssert fac(4) == 24 @@ -124,7 +124,7 @@ const type FloatClass* = enum ## Describes the class a floating point value belongs to. ## This is the type that is returned by - ## `classify proc <#classify,float>`_. + ## `classify func <#classify,float>`_. fcNormal, ## value is an ordinary nonzero floating point value fcSubnormal, ## value is a subnormal (a very small) floating point value fcZero, ## value is zero @@ -133,7 +133,7 @@ type fcInf, ## value is positive infinity fcNegInf ## value is negative infinity -proc classify*(x: float): FloatClass = +func classify*(x: float): FloatClass = ## Classifies a floating point value. ## ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_. @@ -158,8 +158,8 @@ proc classify*(x: float): FloatClass = return fcSubnormal return fcNormal -proc almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. - since: (1, 5), inline, noSideEffect.} = +func almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. + since: (1, 5), inline.} = ## Checks if two float values are almost equal, using ## `machine epsilon `_. ## @@ -192,13 +192,13 @@ proc almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. result = diff <= epsilon(T) * abs(x + y) * T(unitsInLastPlace) or diff < minimumPositiveValue(T) -proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = +func isPowerOfTwo*(x: int): bool = ## Returns ``true``, if ``x`` is a power of two, ``false`` otherwise. ## ## Zero and negative numbers are not a power of two. ## ## See also: - ## * `nextPowerOfTwo proc<#nextPowerOfTwo,int>`_ + ## * `nextPowerOfTwo func<#nextPowerOfTwo,int>`_ runnableExamples: doAssert isPowerOfTwo(16) == true doAssert isPowerOfTwo(5) == false @@ -206,13 +206,13 @@ proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = doAssert isPowerOfTwo(-16) == false return (x > 0) and ((x and (x - 1)) == 0) -proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = +func nextPowerOfTwo*(x: int): int = ## Returns ``x`` rounded up to the nearest power of two. ## ## Zero and negative numbers get rounded up to 1. ## ## See also: - ## * `isPowerOfTwo proc<#isPowerOfTwo,int>`_ + ## * `isPowerOfTwo func<#isPowerOfTwo,int>`_ runnableExamples: doAssert nextPowerOfTwo(16) == 16 doAssert nextPowerOfTwo(5) == 8 @@ -230,40 +230,40 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = result = result or (result shr 1) result += 1 + ord(x <= 0) -proc sum*[T](x: openArray[T]): T {.noSideEffect.} = +func sum*[T](x: openArray[T]): T = ## Computes the sum of the elements in ``x``. ## ## If ``x`` is empty, 0 is returned. ## ## See also: - ## * `prod proc <#prod,openArray[T]>`_ - ## * `cumsum proc <#cumsum,openArray[T]>`_ - ## * `cumsummed proc <#cumsummed,openArray[T]>`_ + ## * `prod func <#prod,openArray[T]>`_ + ## * `cumsum func <#cumsum,openArray[T]>`_ + ## * `cumsummed func <#cumsummed,openArray[T]>`_ runnableExamples: doAssert sum([1, 2, 3, 4]) == 10 doAssert sum([-1.5, 2.7, -0.1]) == 1.1 for i in items(x): result = result + i -proc prod*[T](x: openArray[T]): T {.noSideEffect.} = +func prod*[T](x: openArray[T]): T = ## Computes the product of the elements in ``x``. ## ## If ``x`` is empty, 1 is returned. ## ## See also: - ## * `sum proc <#sum,openArray[T]>`_ - ## * `fac proc <#fac,int>`_ + ## * `sum func <#sum,openArray[T]>`_ + ## * `fac func <#fac,int>`_ runnableExamples: doAssert prod([1, 2, 3, 4]) == 24 doAssert prod([-4, 3, 5]) == -60 result = 1.T for i in items(x): result = result * i -proc cumsummed*[T](x: openArray[T]): seq[T] = +func cumsummed*[T](x: openArray[T]): seq[T] = ## Return cumulative (aka prefix) summation of ``x``. ## ## See also: - ## * `sum proc <#sum,openArray[T]>`_ - ## * `cumsum proc <#cumsum,openArray[T]>`_ for the in-place version + ## * `sum func <#sum,openArray[T]>`_ + ## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version runnableExamples: let a = [1, 2, 3, 4] doAssert cumsummed(a) == @[1, 3, 6, 10] @@ -271,13 +271,13 @@ proc cumsummed*[T](x: openArray[T]): seq[T] = result[0] = x[0] for i in 1 ..< x.len: result[i] = result[i-1] + x[i] -proc cumsum*[T](x: var openArray[T]) = +func cumsum*[T](x: var openArray[T]) = ## Transforms ``x`` in-place (must be declared as `var`) into its ## cumulative (aka prefix) summation. ## ## See also: - ## * `sum proc <#sum,openArray[T]>`_ - ## * `cumsummed proc <#cumsummed,openArray[T]>`_ for a version which + ## * `sum func <#sum,openArray[T]>`_ + ## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which ## returns cumsummed sequence runnableExamples: var a = [1, 2, 3, 4] @@ -285,40 +285,39 @@ proc cumsum*[T](x: var openArray[T]) = doAssert a == @[1, 3, 6, 10] for i in 1 ..< x.len: x[i] = x[i-1] + x[i] -{.push noSideEffect.} when not defined(js): # C - proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "".} - proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} + func sqrt*(x: float32): float32 {.importc: "sqrtf", header: "".} + func sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} ## Computes the square root of ``x``. ## ## See also: - ## * `cbrt proc <#cbrt,float64>`_ for cubic root + ## * `cbrt func <#cbrt,float64>`_ for cubic root ## ## .. code-block:: nim ## echo sqrt(4.0) ## 2.0 ## echo sqrt(1.44) ## 1.2 ## echo sqrt(-4.0) ## nan - proc cbrt*(x: float32): float32 {.importc: "cbrtf", header: "".} - proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} + func cbrt*(x: float32): float32 {.importc: "cbrtf", header: "".} + func cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} ## Computes the cubic root of ``x``. ## ## See also: - ## * `sqrt proc <#sqrt,float64>`_ for square root + ## * `sqrt func <#sqrt,float64>`_ for square root ## ## .. code-block:: nim ## echo cbrt(8.0) ## 2.0 ## echo cbrt(2.197) ## 1.3 ## echo cbrt(-27.0) ## -3.0 - proc ln*(x: float32): float32 {.importc: "logf", header: "".} - proc ln*(x: float64): float64 {.importc: "log", header: "".} + func ln*(x: float32): float32 {.importc: "logf", header: "".} + func ln*(x: float64): float64 {.importc: "log", header: "".} ## Computes the `natural logarithm `_ ## of ``x``. ## ## See also: - ## * `log proc <#log,T,T>`_ - ## * `log10 proc <#log10,float64>`_ - ## * `log2 proc <#log2,float64>`_ - ## * `exp proc <#exp,float64>`_ + ## * `log func <#log,T,T>`_ + ## * `log10 func <#log10,float64>`_ + ## * `log2 func <#log2,float64>`_ + ## * `exp func <#exp,float64>`_ ## ## .. code-block:: nim ## echo ln(exp(4.0)) ## 4.0 @@ -326,23 +325,23 @@ when not defined(js): # C ## echo ln(0.0) ## -inf ## echo ln(-7.0) ## nan else: # JS - proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} - proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} + func sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} + func sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} - proc cbrt*(x: float32): float32 {.importc: "Math.cbrt", nodecl.} - proc cbrt*(x: float64): float64 {.importc: "Math.cbrt", nodecl.} + func cbrt*(x: float32): float32 {.importc: "Math.cbrt", nodecl.} + func cbrt*(x: float64): float64 {.importc: "Math.cbrt", nodecl.} - proc ln*(x: float32): float32 {.importc: "Math.log", nodecl.} - proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.} + func ln*(x: float32): float32 {.importc: "Math.log", nodecl.} + func ln*(x: float64): float64 {.importc: "Math.log", nodecl.} -proc log*[T: SomeFloat](x, base: T): T = +func log*[T: SomeFloat](x, base: T): T = ## Computes the logarithm of ``x`` to base ``base``. ## ## See also: - ## * `ln proc <#ln,float64>`_ - ## * `log10 proc <#log10,float64>`_ - ## * `log2 proc <#log2,float64>`_ - ## * `exp proc <#exp,float64>`_ + ## * `ln func <#ln,float64>`_ + ## * `log10 func <#log10,float64>`_ + ## * `log2 func <#log2,float64>`_ + ## * `exp func <#exp,float64>`_ ## ## .. code-block:: nim ## echo log(9.0, 3.0) ## 2.0 @@ -353,256 +352,256 @@ proc log*[T: SomeFloat](x, base: T): T = ln(x) / ln(base) when not defined(js): # C - proc log10*(x: float32): float32 {.importc: "log10f", header: "".} - proc log10*(x: float64): float64 {.importc: "log10", header: "".} + func log10*(x: float32): float32 {.importc: "log10f", header: "".} + func log10*(x: float64): float64 {.importc: "log10", header: "".} ## Computes the common logarithm (base 10) of ``x``. ## ## See also: - ## * `ln proc <#ln,float64>`_ - ## * `log proc <#log,T,T>`_ - ## * `log2 proc <#log2,float64>`_ - ## * `exp proc <#exp,float64>`_ + ## * `ln func <#ln,float64>`_ + ## * `log func <#log,T,T>`_ + ## * `log2 func <#log2,float64>`_ + ## * `exp func <#exp,float64>`_ ## ## .. code-block:: nim ## echo log10(100.0) ## 2.0 ## echo log10(0.0) ## nan ## echo log10(-100.0) ## -inf - proc exp*(x: float32): float32 {.importc: "expf", header: "".} - proc exp*(x: float64): float64 {.importc: "exp", header: "".} + func exp*(x: float32): float32 {.importc: "expf", header: "".} + func exp*(x: float64): float64 {.importc: "exp", header: "".} ## Computes the exponential function of ``x`` (e^x). ## ## See also: - ## * `ln proc <#ln,float64>`_ - ## * `log proc <#log,T,T>`_ - ## * `log10 proc <#log10,float64>`_ - ## * `log2 proc <#log2,float64>`_ + ## * `ln func <#ln,float64>`_ + ## * `log func <#log,T,T>`_ + ## * `log10 func <#log10,float64>`_ + ## * `log2 func <#log2,float64>`_ ## ## .. code-block:: nim ## echo exp(1.0) ## 2.718281828459045 ## echo ln(exp(4.0)) ## 4.0 ## echo exp(0.0) ## 1.0 ## echo exp(-1.0) ## 0.3678794411714423 - proc sin*(x: float32): float32 {.importc: "sinf", header: "".} - proc sin*(x: float64): float64 {.importc: "sin", header: "".} + func sin*(x: float32): float32 {.importc: "sinf", header: "".} + func sin*(x: float64): float64 {.importc: "sin", header: "".} ## Computes the sine of ``x``. ## ## See also: - ## * `cos proc <#cos,float64>`_ - ## * `tan proc <#tan,float64>`_ - ## * `arcsin proc <#arcsin,float64>`_ - ## * `sinh proc <#sinh,float64>`_ + ## * `cos func <#cos,float64>`_ + ## * `tan func <#tan,float64>`_ + ## * `arcsin func <#arcsin,float64>`_ + ## * `sinh func <#sinh,float64>`_ ## ## .. code-block:: nim ## echo sin(PI / 6) ## 0.4999999999999999 ## echo sin(degToRad(90.0)) ## 1.0 - proc cos*(x: float32): float32 {.importc: "cosf", header: "".} - proc cos*(x: float64): float64 {.importc: "cos", header: "".} + func cos*(x: float32): float32 {.importc: "cosf", header: "".} + func cos*(x: float64): float64 {.importc: "cos", header: "".} ## Computes the cosine of ``x``. ## ## See also: - ## * `sin proc <#sin,float64>`_ - ## * `tan proc <#tan,float64>`_ - ## * `arccos proc <#arccos,float64>`_ - ## * `cosh proc <#cosh,float64>`_ + ## * `sin func <#sin,float64>`_ + ## * `tan func <#tan,float64>`_ + ## * `arccos func <#arccos,float64>`_ + ## * `cosh func <#cosh,float64>`_ ## ## .. code-block:: nim ## echo cos(2 * PI) ## 1.0 ## echo cos(degToRad(60.0)) ## 0.5000000000000001 - proc tan*(x: float32): float32 {.importc: "tanf", header: "".} - proc tan*(x: float64): float64 {.importc: "tan", header: "".} + func tan*(x: float32): float32 {.importc: "tanf", header: "".} + func tan*(x: float64): float64 {.importc: "tan", header: "".} ## Computes the tangent of ``x``. ## ## See also: - ## * `sin proc <#sin,float64>`_ - ## * `cos proc <#cos,float64>`_ - ## * `arctan proc <#arctan,float64>`_ - ## * `tanh proc <#tanh,float64>`_ + ## * `sin func <#sin,float64>`_ + ## * `cos func <#cos,float64>`_ + ## * `arctan func <#arctan,float64>`_ + ## * `tanh func <#tanh,float64>`_ ## ## .. code-block:: nim ## echo tan(degToRad(45.0)) ## 0.9999999999999999 ## echo tan(PI / 4) ## 0.9999999999999999 - proc sinh*(x: float32): float32 {.importc: "sinhf", header: "".} - proc sinh*(x: float64): float64 {.importc: "sinh", header: "".} + func sinh*(x: float32): float32 {.importc: "sinhf", header: "".} + func sinh*(x: float64): float64 {.importc: "sinh", header: "".} ## Computes the `hyperbolic sine `_ of ``x``. ## ## See also: - ## * `cosh proc <#cosh,float64>`_ - ## * `tanh proc <#tanh,float64>`_ - ## * `arcsinh proc <#arcsinh,float64>`_ - ## * `sin proc <#sin,float64>`_ + ## * `cosh func <#cosh,float64>`_ + ## * `tanh func <#tanh,float64>`_ + ## * `arcsinh func <#arcsinh,float64>`_ + ## * `sin func <#sin,float64>`_ ## ## .. code-block:: nim ## echo sinh(0.0) ## 0.0 ## echo sinh(1.0) ## 1.175201193643801 ## echo sinh(degToRad(90.0)) ## 2.301298902307295 - proc cosh*(x: float32): float32 {.importc: "coshf", header: "".} - proc cosh*(x: float64): float64 {.importc: "cosh", header: "".} + func cosh*(x: float32): float32 {.importc: "coshf", header: "".} + func cosh*(x: float64): float64 {.importc: "cosh", header: "".} ## Computes the `hyperbolic cosine `_ of ``x``. ## ## See also: - ## * `sinh proc <#sinh,float64>`_ - ## * `tanh proc <#tanh,float64>`_ - ## * `arccosh proc <#arccosh,float64>`_ - ## * `cos proc <#cos,float64>`_ + ## * `sinh func <#sinh,float64>`_ + ## * `tanh func <#tanh,float64>`_ + ## * `arccosh func <#arccosh,float64>`_ + ## * `cos func <#cos,float64>`_ ## ## .. code-block:: nim ## echo cosh(0.0) ## 1.0 ## echo cosh(1.0) ## 1.543080634815244 ## echo cosh(degToRad(90.0)) ## 2.509178478658057 - proc tanh*(x: float32): float32 {.importc: "tanhf", header: "".} - proc tanh*(x: float64): float64 {.importc: "tanh", header: "".} + func tanh*(x: float32): float32 {.importc: "tanhf", header: "".} + func tanh*(x: float64): float64 {.importc: "tanh", header: "".} ## Computes the `hyperbolic tangent `_ of ``x``. ## ## See also: - ## * `sinh proc <#sinh,float64>`_ - ## * `cosh proc <#cosh,float64>`_ - ## * `arctanh proc <#arctanh,float64>`_ - ## * `tan proc <#tan,float64>`_ + ## * `sinh func <#sinh,float64>`_ + ## * `cosh func <#cosh,float64>`_ + ## * `arctanh func <#arctanh,float64>`_ + ## * `tan func <#tan,float64>`_ ## ## .. code-block:: nim ## echo tanh(0.0) ## 0.0 ## echo tanh(1.0) ## 0.7615941559557649 ## echo tanh(degToRad(90.0)) ## 0.9171523356672744 - proc arccos*(x: float32): float32 {.importc: "acosf", header: "".} - proc arccos*(x: float64): float64 {.importc: "acos", header: "".} + func arccos*(x: float32): float32 {.importc: "acosf", header: "".} + func arccos*(x: float64): float64 {.importc: "acos", header: "".} ## Computes the arc cosine of ``x``. ## ## See also: - ## * `arcsin proc <#arcsin,float64>`_ - ## * `arctan proc <#arctan,float64>`_ - ## * `arctan2 proc <#arctan2,float64,float64>`_ - ## * `cos proc <#cos,float64>`_ + ## * `arcsin func <#arcsin,float64>`_ + ## * `arctan func <#arctan,float64>`_ + ## * `arctan2 func <#arctan2,float64,float64>`_ + ## * `cos func <#cos,float64>`_ ## ## .. code-block:: nim ## echo radToDeg(arccos(0.0)) ## 90.0 ## echo radToDeg(arccos(1.0)) ## 0.0 - proc arcsin*(x: float32): float32 {.importc: "asinf", header: "".} - proc arcsin*(x: float64): float64 {.importc: "asin", header: "".} + func arcsin*(x: float32): float32 {.importc: "asinf", header: "".} + func arcsin*(x: float64): float64 {.importc: "asin", header: "".} ## Computes the arc sine of ``x``. ## ## See also: - ## * `arccos proc <#arccos,float64>`_ - ## * `arctan proc <#arctan,float64>`_ - ## * `arctan2 proc <#arctan2,float64,float64>`_ - ## * `sin proc <#sin,float64>`_ + ## * `arccos func <#arccos,float64>`_ + ## * `arctan func <#arctan,float64>`_ + ## * `arctan2 func <#arctan2,float64,float64>`_ + ## * `sin func <#sin,float64>`_ ## ## .. code-block:: nim ## echo radToDeg(arcsin(0.0)) ## 0.0 ## echo radToDeg(arcsin(1.0)) ## 90.0 - proc arctan*(x: float32): float32 {.importc: "atanf", header: "".} - proc arctan*(x: float64): float64 {.importc: "atan", header: "".} + func arctan*(x: float32): float32 {.importc: "atanf", header: "".} + func arctan*(x: float64): float64 {.importc: "atan", header: "".} ## Calculate the arc tangent of ``x``. ## ## See also: - ## * `arcsin proc <#arcsin,float64>`_ - ## * `arccos proc <#arccos,float64>`_ - ## * `arctan2 proc <#arctan2,float64,float64>`_ - ## * `tan proc <#tan,float64>`_ + ## * `arcsin func <#arcsin,float64>`_ + ## * `arccos func <#arccos,float64>`_ + ## * `arctan2 func <#arctan2,float64,float64>`_ + ## * `tan func <#tan,float64>`_ ## ## .. code-block:: nim ## echo arctan(1.0) ## 0.7853981633974483 ## echo radToDeg(arctan(1.0)) ## 45.0 - proc arctan2*(y, x: float32): float32 {.importc: "atan2f", + func arctan2*(y, x: float32): float32 {.importc: "atan2f", header: "".} - proc arctan2*(y, x: float64): float64 {.importc: "atan2", header: "".} + func arctan2*(y, x: float64): float64 {.importc: "atan2", header: "".} ## Calculate the arc tangent of ``y`` / ``x``. ## ## It produces correct results even when the resulting angle is near ## pi/2 or -pi/2 (``x`` near 0). ## ## See also: - ## * `arcsin proc <#arcsin,float64>`_ - ## * `arccos proc <#arccos,float64>`_ - ## * `arctan proc <#arctan,float64>`_ - ## * `tan proc <#tan,float64>`_ + ## * `arcsin func <#arcsin,float64>`_ + ## * `arccos func <#arccos,float64>`_ + ## * `arctan func <#arctan,float64>`_ + ## * `tan func <#tan,float64>`_ ## ## .. code-block:: nim ## echo arctan2(1.0, 0.0) ## 1.570796326794897 ## echo radToDeg(arctan2(1.0, 0.0)) ## 90.0 - proc arcsinh*(x: float32): float32 {.importc: "asinhf", header: "".} - proc arcsinh*(x: float64): float64 {.importc: "asinh", header: "".} + func arcsinh*(x: float32): float32 {.importc: "asinhf", header: "".} + func arcsinh*(x: float64): float64 {.importc: "asinh", header: "".} ## Computes the inverse hyperbolic sine of ``x``. - proc arccosh*(x: float32): float32 {.importc: "acoshf", header: "".} - proc arccosh*(x: float64): float64 {.importc: "acosh", header: "".} + func arccosh*(x: float32): float32 {.importc: "acoshf", header: "".} + func arccosh*(x: float64): float64 {.importc: "acosh", header: "".} ## Computes the inverse hyperbolic cosine of ``x``. - proc arctanh*(x: float32): float32 {.importc: "atanhf", header: "".} - proc arctanh*(x: float64): float64 {.importc: "atanh", header: "".} + func arctanh*(x: float32): float32 {.importc: "atanhf", header: "".} + func arctanh*(x: float64): float64 {.importc: "atanh", header: "".} ## Computes the inverse hyperbolic tangent of ``x``. else: # JS - proc log10*(x: float32): float32 {.importc: "Math.log10", nodecl.} - proc log10*(x: float64): float64 {.importc: "Math.log10", nodecl.} - proc log2*(x: float32): float32 {.importc: "Math.log2", nodecl.} - proc log2*(x: float64): float64 {.importc: "Math.log2", nodecl.} - proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.} - proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} + func log10*(x: float32): float32 {.importc: "Math.log10", nodecl.} + func log10*(x: float64): float64 {.importc: "Math.log10", nodecl.} + func log2*(x: float32): float32 {.importc: "Math.log2", nodecl.} + func log2*(x: float64): float64 {.importc: "Math.log2", nodecl.} + func exp*(x: float32): float32 {.importc: "Math.exp", nodecl.} + func exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} - proc sin*[T: float32|float64](x: T): T {.importc: "Math.sin", nodecl.} - proc cos*[T: float32|float64](x: T): T {.importc: "Math.cos", nodecl.} - proc tan*[T: float32|float64](x: T): T {.importc: "Math.tan", nodecl.} + func sin*[T: float32|float64](x: T): T {.importc: "Math.sin", nodecl.} + func cos*[T: float32|float64](x: T): T {.importc: "Math.cos", nodecl.} + func tan*[T: float32|float64](x: T): T {.importc: "Math.tan", nodecl.} - proc sinh*[T: float32|float64](x: T): T {.importc: "Math.sinh", nodecl.} - proc cosh*[T: float32|float64](x: T): T {.importc: "Math.cosh", nodecl.} - proc tanh*[T: float32|float64](x: T): T {.importc: "Math.tanh", nodecl.} + func sinh*[T: float32|float64](x: T): T {.importc: "Math.sinh", nodecl.} + func cosh*[T: float32|float64](x: T): T {.importc: "Math.cosh", nodecl.} + func tanh*[T: float32|float64](x: T): T {.importc: "Math.tanh", nodecl.} - proc arcsin*[T: float32|float64](x: T): T {.importc: "Math.asin", nodecl.} - proc arccos*[T: float32|float64](x: T): T {.importc: "Math.acos", nodecl.} - proc arctan*[T: float32|float64](x: T): T {.importc: "Math.atan", nodecl.} - proc arctan2*[T: float32|float64](y, x: T): T {.importc: "Math.atan2", nodecl.} + func arcsin*[T: float32|float64](x: T): T {.importc: "Math.asin", nodecl.} + func arccos*[T: float32|float64](x: T): T {.importc: "Math.acos", nodecl.} + func arctan*[T: float32|float64](x: T): T {.importc: "Math.atan", nodecl.} + func arctan2*[T: float32|float64](y, x: T): T {.importc: "Math.atan2", nodecl.} - proc arcsinh*[T: float32|float64](x: T): T {.importc: "Math.asinh", nodecl.} - proc arccosh*[T: float32|float64](x: T): T {.importc: "Math.acosh", nodecl.} - proc arctanh*[T: float32|float64](x: T): T {.importc: "Math.atanh", nodecl.} + func arcsinh*[T: float32|float64](x: T): T {.importc: "Math.asinh", nodecl.} + func arccosh*[T: float32|float64](x: T): T {.importc: "Math.acosh", nodecl.} + func arctanh*[T: float32|float64](x: T): T {.importc: "Math.atanh", nodecl.} -proc cot*[T: float32|float64](x: T): T = 1.0 / tan(x) +func cot*[T: float32|float64](x: T): T = 1.0 / tan(x) ## Computes the cotangent of ``x`` (1 / tan(x)). -proc sec*[T: float32|float64](x: T): T = 1.0 / cos(x) +func sec*[T: float32|float64](x: T): T = 1.0 / cos(x) ## Computes the secant of ``x`` (1 / cos(x)). -proc csc*[T: float32|float64](x: T): T = 1.0 / sin(x) +func csc*[T: float32|float64](x: T): T = 1.0 / sin(x) ## Computes the cosecant of ``x`` (1 / sin(x)). -proc coth*[T: float32|float64](x: T): T = 1.0 / tanh(x) +func coth*[T: float32|float64](x: T): T = 1.0 / tanh(x) ## Computes the hyperbolic cotangent of ``x`` (1 / tanh(x)). -proc sech*[T: float32|float64](x: T): T = 1.0 / cosh(x) +func sech*[T: float32|float64](x: T): T = 1.0 / cosh(x) ## Computes the hyperbolic secant of ``x`` (1 / cosh(x)). -proc csch*[T: float32|float64](x: T): T = 1.0 / sinh(x) +func csch*[T: float32|float64](x: T): T = 1.0 / sinh(x) ## Computes the hyperbolic cosecant of ``x`` (1 / sinh(x)). -proc arccot*[T: float32|float64](x: T): T = arctan(1.0 / x) +func arccot*[T: float32|float64](x: T): T = arctan(1.0 / x) ## Computes the inverse cotangent of ``x``. -proc arcsec*[T: float32|float64](x: T): T = arccos(1.0 / x) +func arcsec*[T: float32|float64](x: T): T = arccos(1.0 / x) ## Computes the inverse secant of ``x``. -proc arccsc*[T: float32|float64](x: T): T = arcsin(1.0 / x) +func arccsc*[T: float32|float64](x: T): T = arcsin(1.0 / x) ## Computes the inverse cosecant of ``x``. -proc arccoth*[T: float32|float64](x: T): T = arctanh(1.0 / x) +func arccoth*[T: float32|float64](x: T): T = arctanh(1.0 / x) ## Computes the inverse hyperbolic cotangent of ``x``. -proc arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x) +func arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x) ## Computes the inverse hyperbolic secant of ``x``. -proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x) +func arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x) ## Computes the inverse hyperbolic cosecant of ``x``. const windowsCC89 = defined(windows) and defined(bcc) when not defined(js): # C - proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "".} - proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} + func hypot*(x, y: float32): float32 {.importc: "hypotf", header: "".} + func hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} ## Computes the hypotenuse of a right-angle triangle with ``x`` and ## ``y`` as its base and height. Equivalent to ``sqrt(x*x + y*y)``. ## ## .. code-block:: nim ## echo hypot(4.0, 3.0) ## 5.0 - proc pow*(x, y: float32): float32 {.importc: "powf", header: "".} - proc pow*(x, y: float64): float64 {.importc: "pow", header: "".} + func pow*(x, y: float32): float32 {.importc: "powf", header: "".} + func pow*(x, y: float64): float64 {.importc: "pow", header: "".} ## Computes x to power raised of y. ## - ## To compute power between integers (e.g. 2^6), use `^ proc<#^,T,Natural>`_. + ## To compute power between integers (e.g. 2^6), use `^ func<#^,T,Natural>`_. ## ## See also: - ## * `^ proc<#^,T,Natural>`_ - ## * `sqrt proc <#sqrt,float64>`_ - ## * `cbrt proc <#cbrt,float64>`_ + ## * `^ func<#^,T,Natural>`_ + ## * `sqrt func <#sqrt,float64>`_ + ## * `cbrt func <#cbrt,float64>`_ ## ## .. code-block:: nim ## echo pow(100, 1.5) ## 1000.0 @@ -610,38 +609,38 @@ when not defined(js): # C # TODO: add C89 version on windows when not windowsCC89: - proc erf*(x: float32): float32 {.importc: "erff", header: "".} - proc erf*(x: float64): float64 {.importc: "erf", header: "".} + func erf*(x: float32): float32 {.importc: "erff", header: "".} + func erf*(x: float64): float64 {.importc: "erf", header: "".} ## Computes the `error function `_ for ``x``. ## ## Note: Not available for JS backend. - proc erfc*(x: float32): float32 {.importc: "erfcf", header: "".} - proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} + func erfc*(x: float32): float32 {.importc: "erfcf", header: "".} + func erfc*(x: float64): float64 {.importc: "erfc", header: "".} ## Computes the `complementary error function `_ for ``x``. ## ## Note: Not available for JS backend. - proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} - proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} + func gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} + func gamma*(x: float64): float64 {.importc: "tgamma", header: "".} ## Computes the `gamma function `_ for ``x``. ## ## Note: Not available for JS backend. ## ## See also: - ## * `lgamma proc <#lgamma,float64>`_ for a natural log of gamma function + ## * `lgamma func <#lgamma,float64>`_ for a natural log of gamma function ## ## .. code-block:: Nim ## echo gamma(1.0) # 1.0 ## echo gamma(4.0) # 6.0 ## echo gamma(11.0) # 3628800.0 ## echo gamma(-1.0) # nan - proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} - proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} + func lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} + func lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} ## Computes the natural log of the gamma function for ``x``. ## ## Note: Not available for JS backend. ## ## See also: - ## * `gamma proc <#gamma,float64>`_ for gamma function + ## * `gamma func <#gamma,float64>`_ for gamma function ## ## .. code-block:: Nim ## echo lgamma(1.0) # 1.0 @@ -649,29 +648,29 @@ when not defined(js): # C ## echo lgamma(11.0) # 15.10441257307552 ## echo lgamma(-1.0) # inf - proc floor*(x: float32): float32 {.importc: "floorf", header: "".} - proc floor*(x: float64): float64 {.importc: "floor", header: "".} + func floor*(x: float32): float32 {.importc: "floorf", header: "".} + func floor*(x: float64): float64 {.importc: "floor", header: "".} ## Computes the floor function (i.e., the largest integer not greater than ``x``). ## ## See also: - ## * `ceil proc <#ceil,float64>`_ - ## * `round proc <#round,float64>`_ - ## * `trunc proc <#trunc,float64>`_ + ## * `ceil func <#ceil,float64>`_ + ## * `round func <#round,float64>`_ + ## * `trunc func <#trunc,float64>`_ ## ## .. code-block:: nim ## echo floor(2.1) ## 2.0 ## echo floor(2.9) ## 2.0 ## echo floor(-3.5) ## -4.0 - proc ceil*(x: float32): float32 {.importc: "ceilf", header: "".} - proc ceil*(x: float64): float64 {.importc: "ceil", header: "".} + func ceil*(x: float32): float32 {.importc: "ceilf", header: "".} + func ceil*(x: float64): float64 {.importc: "ceil", header: "".} ## Computes the ceiling function (i.e., the smallest integer not smaller ## than ``x``). ## ## See also: - ## * `floor proc <#floor,float64>`_ - ## * `round proc <#round,float64>`_ - ## * `trunc proc <#trunc,float64>`_ + ## * `floor func <#floor,float64>`_ + ## * `round func <#round,float64>`_ + ## * `trunc func <#trunc,float64>`_ ## ## .. code-block:: nim ## echo ceil(2.1) ## 3.0 @@ -681,7 +680,7 @@ when not defined(js): # C when windowsCC89: # MSVC 2010 don't have trunc/truncf # this implementation was inspired by Go-lang Math.Trunc - proc truncImpl(f: float64): float64 = + func truncImpl(f: float64): float64 = const mask: uint64 = 0x7FF shift: uint64 = 64 - 12 @@ -701,7 +700,7 @@ when not defined(js): # C result = cast[float64](x) - proc truncImpl(f: float32): float32 = + func truncImpl(f: float32): float32 = const mask: uint32 = 0xFF shift: uint32 = 32 - 9 @@ -721,57 +720,57 @@ when not defined(js): # C result = cast[float32](x) - proc trunc*(x: float64): float64 = + func trunc*(x: float64): float64 = if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x result = truncImpl(x) - proc trunc*(x: float32): float32 = + func trunc*(x: float32): float32 = if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x result = truncImpl(x) - proc round*[T: float32|float64](x: T): T = + func round*[T: float32|float64](x: T): T = ## Windows compilers prior to MSVC 2012 do not implement 'round', ## 'roundl' or 'roundf'. result = if x < 0.0: ceil(x - T(0.5)) else: floor(x + T(0.5)) else: - proc round*(x: float32): float32 {.importc: "roundf", header: "".} - proc round*(x: float64): float64 {.importc: "round", header: "".} + func round*(x: float32): float32 {.importc: "roundf", header: "".} + func round*(x: float64): float64 {.importc: "round", header: "".} ## Rounds a float to zero decimal places. ## - ## Used internally by the `round proc <#round,T,int>`_ + ## Used internally by the `round func <#round,T,int>`_ ## when the specified number of places is 0. ## ## See also: - ## * `round proc <#round,T,int>`_ for rounding to the specific + ## * `round func <#round,T,int>`_ for rounding to the specific ## number of decimal places - ## * `floor proc <#floor,float64>`_ - ## * `ceil proc <#ceil,float64>`_ - ## * `trunc proc <#trunc,float64>`_ + ## * `floor func <#floor,float64>`_ + ## * `ceil func <#ceil,float64>`_ + ## * `trunc func <#trunc,float64>`_ ## ## .. code-block:: nim ## echo round(3.4) ## 3.0 ## echo round(3.5) ## 4.0 ## echo round(4.5) ## 5.0 - proc trunc*(x: float32): float32 {.importc: "truncf", header: "".} - proc trunc*(x: float64): float64 {.importc: "trunc", header: "".} + func trunc*(x: float32): float32 {.importc: "truncf", header: "".} + func trunc*(x: float64): float64 {.importc: "trunc", header: "".} ## Truncates ``x`` to the decimal point. ## ## See also: - ## * `floor proc <#floor,float64>`_ - ## * `ceil proc <#ceil,float64>`_ - ## * `round proc <#round,float64>`_ + ## * `floor func <#floor,float64>`_ + ## * `ceil func <#ceil,float64>`_ + ## * `round func <#round,float64>`_ ## ## .. code-block:: nim ## echo trunc(PI) # 3.0 ## echo trunc(-1.85) # -1.0 - proc `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "".} - proc `mod`*(x, y: float64): float64 {.importc: "fmod", header: "".} + func `mod`*(x, y: float32): float32 {.importc: "fmodf", header: "".} + func `mod`*(x, y: float64): float64 {.importc: "fmod", header: "".} ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). ## ## See also: - ## * `floorMod proc <#floorMod,T,T>`_ for Python-like (% operator) behavior + ## * `floorMod func <#floorMod,T,T>`_ for Python-like (% operator) behavior ## ## .. code-block:: nim ## ( 6.5 mod 2.5) == 1.5 @@ -780,20 +779,20 @@ when not defined(js): # C ## (-6.5 mod -2.5) == -1.5 else: # JS - proc hypot*(x, y: float32): float32 {.importc: "Math.hypot", varargs, nodecl.} - proc hypot*(x, y: float64): float64 {.importc: "Math.hypot", varargs, nodecl.} - proc pow*(x, y: float32): float32 {.importc: "Math.pow", nodecl.} - proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} - proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.} - proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} - proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} - proc ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} - proc round*(x: float): float {.importc: "Math.round", nodecl.} - proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} - proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} + func hypot*(x, y: float32): float32 {.importc: "Math.hypot", varargs, nodecl.} + func hypot*(x, y: float64): float64 {.importc: "Math.hypot", varargs, nodecl.} + func pow*(x, y: float32): float32 {.importc: "Math.pow", nodecl.} + func pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} + func floor*(x: float32): float32 {.importc: "Math.floor", nodecl.} + func floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} + func ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} + func ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} + func round*(x: float): float {.importc: "Math.round", nodecl.} + func trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} + func trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} - proc `mod`*(x, y: float32): float32 {.importcpp: "# % #".} - proc `mod`*(x, y: float64): float64 {.importcpp: "# % #".} + func `mod`*(x, y: float32): float32 {.importcpp: "# % #".} + func `mod`*(x, y: float64): float64 {.importcpp: "# % #".} ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). ## ## .. code-block:: nim @@ -802,7 +801,7 @@ else: # JS ## ( 6.5 mod -2.5) == 1.5 ## (-6.5 mod -2.5) == -1.5 -proc round*[T: float32|float64](x: T, places: int): T = +func round*[T: float32|float64](x: T, places: int): T = ## Decimal rounding on a binary floating point number. ## ## This function is NOT reliable. Floating point numbers cannot hold @@ -823,7 +822,7 @@ proc round*[T: float32|float64](x: T, places: int): T = var mult = pow(10.0, places.T) result = round(x*mult)/mult -proc floorDiv*[T: SomeInteger](x, y: T): T = +func floorDiv*[T: SomeInteger](x, y: T): T = ## Floor division is conceptually defined as ``floor(x / y)``. ## ## This is different from the `system.div `_ @@ -832,7 +831,7 @@ proc floorDiv*[T: SomeInteger](x, y: T): T = ## ## See also: ## * `system.div proc `_ for integer division - ## * `floorMod proc <#floorMod,T,T>`_ for Python-like (% operator) behavior + ## * `floorMod func <#floorMod,T,T>`_ for Python-like (% operator) behavior ## ## .. code-block:: nim ## echo floorDiv( 13, 3) # 4 @@ -843,14 +842,14 @@ proc floorDiv*[T: SomeInteger](x, y: T): T = let r = x mod y if (r > 0 and y < 0) or (r < 0 and y > 0): result.dec 1 -proc floorMod*[T: SomeNumber](x, y: T): T = +func floorMod*[T: SomeNumber](x, y: T): T = ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``. ## - ## This proc behaves the same as the ``%`` operator in Python. + ## This func behaves the same as the ``%`` operator in Python. ## ## See also: - ## * `mod proc <#mod,float64,float64>`_ - ## * `floorDiv proc <#floorDiv,T,T>`_ + ## * `mod func <#mod,float64,float64>`_ + ## * `floorDiv func <#floorDiv,T,T>`_ ## ## .. code-block:: nim ## echo floorMod( 13, 3) # 1 @@ -861,11 +860,11 @@ proc floorMod*[T: SomeNumber](x, y: T): T = if (result > 0 and y < 0) or (result < 0 and y > 0): result += y when not defined(js): - proc c_frexp*(x: float32, exponent: var int32): float32 {. - importc: "frexp", header: "".} - proc c_frexp*(x: float64, exponent: var int32): float64 {. - importc: "frexp", header: "".} - proc frexp*[T, U](x: T, exponent: var U): T = + func c_frexp*(x: float32, exponent: var int32): float32 {. + importc: "frexp", header: "".} + func c_frexp*(x: float64, exponent: var int32): float64 {. + importc: "frexp", header: "".} + func frexp*[T, U](x: T, exponent: var U): T = ## Split a number into mantissa and exponent. ## ## ``frexp`` calculates the mantissa m (a float greater than or equal to 0.5 @@ -892,21 +891,21 @@ when not defined(js): if frac == 0.5: return T(exp - 1) log10(frac)*(1/ln2) + T(exp) - proc log2*(x: float32): float32 = log2Impl(x) - proc log2*(x: float64): float64 = log2Impl(x) + func log2*(x: float32): float32 = log2Impl(x) + func log2*(x: float64): float64 = log2Impl(x) ## Log2 returns the binary logarithm of x. ## The special cases are the same as for Log. else: - proc log2*(x: float32): float32 {.importc: "log2f", header: "".} - proc log2*(x: float64): float64 {.importc: "log2", header: "".} + func log2*(x: float32): float32 {.importc: "log2f", header: "".} + func log2*(x: float64): float64 {.importc: "log2", header: "".} ## Computes the binary logarithm (base 2) of ``x``. ## ## See also: - ## * `log proc <#log,T,T>`_ - ## * `log10 proc <#log10,float64>`_ - ## * `ln proc <#ln,float64>`_ - ## * `exp proc <#exp,float64>`_ + ## * `log func <#log,T,T>`_ + ## * `log10 func <#log10,float64>`_ + ## * `ln func <#ln,float64>`_ + ## * `exp func <#exp,float64>`_ ## ## .. code-block:: Nim ## echo log2(8.0) # 3.0 @@ -915,7 +914,7 @@ when not defined(js): ## echo log2(-2.0) # nan else: - proc frexp*[T: float32|float64](x: T, exponent: var int): T = + func frexp*[T: float32|float64](x: T, exponent: var int): T = if x == 0.0: exponent = 0 result = 0.0 @@ -931,7 +930,7 @@ else: if exponent == 1024 and result == 0.0: result = 0.99999999999999988898 -proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = +func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = ## Breaks ``x`` into an integer and a fractional part. ## ## Returns a tuple containing ``intpart`` and ``floatpart`` representing @@ -952,29 +951,28 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = result.intpart = -result.intpart result.floatpart = -result.floatpart -{.pop.} -proc degToRad*[T: float32|float64](d: T): T {.inline.} = +func degToRad*[T: float32|float64](d: T): T {.inline.} = ## Convert from degrees to radians. ## ## See also: - ## * `radToDeg proc <#radToDeg,T>`_ + ## * `radToDeg func <#radToDeg,T>`_ ## runnableExamples: doAssert degToRad(180.0) == 3.141592653589793 result = T(d) * RadPerDeg -proc radToDeg*[T: float32|float64](d: T): T {.inline.} = +func radToDeg*[T: float32|float64](d: T): T {.inline.} = ## Convert from radians to degrees. ## ## See also: - ## * `degToRad proc <#degToRad,T>`_ + ## * `degToRad func <#degToRad,T>`_ ## runnableExamples: doAssert radToDeg(2 * PI) == 360.0 result = T(d) / RadPerDeg -proc sgn*[T: SomeNumber](x: T): int {.inline.} = +func sgn*[T: SomeNumber](x: T): int {.inline.} = ## Sign function. ## ## Returns: @@ -991,17 +989,17 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = {.pop.} {.pop.} -proc `^`*[T: SomeNumber](x: T, y: Natural): T = +func `^`*[T: SomeNumber](x: T, y: Natural): T = ## Computes ``x`` to the power ``y``. ## ## Exponent ``y`` must be non-negative, use - ## `pow proc <#pow,float64,float64>`_ for negative exponents. + ## `pow func <#pow,float64,float64>`_ for negative exponents. ## ## See also: - ## * `pow proc <#pow,float64,float64>`_ for negative exponent or + ## * `pow func <#pow,float64,float64>`_ for negative exponent or ## floats - ## * `sqrt proc <#sqrt,float64>`_ - ## * `cbrt proc <#cbrt,float64>`_ + ## * `sqrt func <#sqrt,float64>`_ + ## * `cbrt func <#cbrt,float64>`_ ## runnableExamples: assert -3.0^0 == 1.0 @@ -1026,7 +1024,7 @@ proc `^`*[T: SomeNumber](x: T, y: Natural): T = break x *= x -proc gcd*[T](x, y: T): T = +func gcd*[T](x, y: T): T = ## Computes the greatest common (positive) divisor of ``x`` and ``y``. ## ## Note that for floats, the result cannot always be interpreted as @@ -1034,8 +1032,8 @@ proc gcd*[T](x, y: T): T = ## where N and M are positive integers." ## ## See also: - ## * `gcd proc <#gcd,SomeInteger,SomeInteger>`_ for integer version - ## * `lcm proc <#lcm,T,T>`_ + ## * `gcd func <#gcd,SomeInteger,SomeInteger>`_ for integer version + ## * `lcm func <#lcm,T,T>`_ runnableExamples: doAssert gcd(13.5, 9.0) == 4.5 var (x, y) = (x, y) @@ -1044,13 +1042,13 @@ proc gcd*[T](x, y: T): T = swap x, y abs x -proc gcd*(x, y: SomeInteger): SomeInteger = +func gcd*(x, y: SomeInteger): SomeInteger = ## Computes the greatest common (positive) divisor of ``x`` and ``y``, ## using binary GCD (aka Stein's) algorithm. ## ## See also: - ## * `gcd proc <#gcd,T,T>`_ for floats version - ## * `lcm proc <#lcm,T,T>`_ + ## * `gcd func <#gcd,T,T>`_ for floats version + ## * `lcm func <#lcm,T,T>`_ runnableExamples: doAssert gcd(12, 8) == 4 doAssert gcd(17, 63) == 1 @@ -1077,11 +1075,11 @@ proc gcd*(x, y: SomeInteger): SomeInteger = x -= y y shl shift -proc gcd*[T](x: openArray[T]): T {.since: (1, 1).} = +func gcd*[T](x: openArray[T]): T {.since: (1, 1).} = ## Computes the greatest common (positive) divisor of the elements of ``x``. ## ## See also: - ## * `gcd proc <#gcd,T,T>`_ for integer version + ## * `gcd func <#gcd,T,T>`_ for integer version runnableExamples: doAssert gcd(@[13.5, 9.0]) == 4.5 result = x[0] @@ -1090,21 +1088,21 @@ proc gcd*[T](x: openArray[T]): T {.since: (1, 1).} = result = gcd(result, x[i]) inc(i) -proc lcm*[T](x, y: T): T = +func lcm*[T](x, y: T): T = ## Computes the least common multiple of ``x`` and ``y``. ## ## See also: - ## * `gcd proc <#gcd,T,T>`_ + ## * `gcd func <#gcd,T,T>`_ runnableExamples: doAssert lcm(24, 30) == 120 doAssert lcm(13, 39) == 39 x div gcd(x, y) * y -proc lcm*[T](x: openArray[T]): T {.since: (1, 1).} = +func lcm*[T](x: openArray[T]): T {.since: (1, 1).} = ## Computes the least common multiple of the elements of ``x``. ## ## See also: - ## * `gcd proc <#gcd,T,T>`_ for integer version + ## * `gcd func <#gcd,T,T>`_ for integer version runnableExamples: doAssert lcm(@[24, 30]) == 120 result = x[0] diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 715278f51..532c6e75e 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -2,7 +2,15 @@ discard """ cmd: "nim c --experimental:strictFuncs --experimental:views $file" """ -import tables, streams, nre, parsecsv, uri, httpcore, strutils +import tables, streams, parsecsv +# We import the below modules to check that they compile with `strictFuncs`. +# They are otherwise unused in this file. +import + httpcore, + math, + nre, + strutils, + uri type Contig2Reads = TableRef[string, seq[string]] From 4c533b2d92162980dc8fac2332b0eb0739dbda25 Mon Sep 17 00:00:00 2001 From: Xabier Bello Date: Tue, 8 Dec 2020 10:44:07 +0100 Subject: [PATCH 1630/4254] Added Python to highlite module. (#16286) * Added Python to highlite module. * Added the keywords for Python * Refactored the 'pythonLikeNextToken' into 'nimNextToken': - `lang` property added to GeneralTokenizer object, is set in `getNextToken`. - `nimNextToken` accepts `keywords` parameter, used for languages different from Nim. - Multiline comment available only for `langNim`. --- lib/packages/docutils/highlite.nim | 44 ++++++++++++++++++++---------- tests/stdlib/trstgen.nim | 24 +++++++++++++--- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index df74dd980..fcc42add0 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -45,6 +45,9 @@ import from algorithm import binarySearch type + SourceLanguage* = enum + langNone, langNim, langCpp, langCsharp, langC, langJava, + langYaml, langPython TokenClass* = enum gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber, gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit, @@ -59,14 +62,11 @@ type buf: cstring pos: int state: TokenClass - - SourceLanguage* = enum - langNone, langNim, langCpp, langCsharp, langC, langJava, - langYaml + lang: SourceLanguage const sourceLanguageToStr*: array[SourceLanguage, string] = ["none", - "Nim", "C++", "C#", "C", "Java", "Yaml"] + "Nim", "C++", "C#", "C", "Java", "Yaml", "Python"] tokenClassToStr*: array[TokenClass, string] = ["Eof", "None", "Whitespace", "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", @@ -101,6 +101,7 @@ proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: cstring) = g.start = 0 g.length = 0 g.state = low(TokenClass) + g.lang = low(SourceLanguage) var pos = 0 # skip initial whitespace: while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos) g.pos = pos @@ -161,7 +162,13 @@ const OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', '|', '=', '%', '&', '$', '@', '~', ':'} -proc nimNextToken(g: var GeneralTokenizer) = +proc isKeyword(x: openArray[string], y: string): int = + binarySearch(x, y) + +proc isKeywordIgnoreCase(x: openArray[string], y: string): int = + binarySearch(x, y, cmpIgnoreCase) + +proc nimNextToken(g: var GeneralTokenizer, keywords: openArray[string] = @[]) = const hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'} octChars = {'0'..'7', '_'} @@ -207,7 +214,7 @@ proc nimNextToken(g: var GeneralTokenizer) = if g.buf[pos] == '#': inc(pos) isDoc = true - if g.buf[pos] == '[': + if g.buf[pos] == '[' and g.lang == langNim: g.kind = gtLongComment var nesting = 0 while true: @@ -265,7 +272,10 @@ proc nimNextToken(g: var GeneralTokenizer) = inc(pos) if g.buf[pos] == '\"': inc(pos) else: - g.kind = nimGetKeyword(id) + if g.lang == langNim: + g.kind = nimGetKeyword(id) + elif isKeyword(keywords, id) >= 0: + g.kind = gtKeyword of '0': inc(pos) case g.buf[pos] @@ -394,12 +404,6 @@ proc generalStrLit(g: var GeneralTokenizer, position: int): int = inc(pos) result = pos -proc isKeyword(x: openArray[string], y: string): int = - binarySearch(x, y) - -proc isKeywordIgnoreCase(x: openArray[string], y: string): int = - binarySearch(x, y, cmpIgnoreCase) - type TokenizerFlag = enum hasPreprocessor, hasNestedComments @@ -886,7 +890,18 @@ proc yamlNextToken(g: var GeneralTokenizer) = g.length = pos - g.pos g.pos = pos +proc pythonNextToken(g: var GeneralTokenizer) = + const + keywords: array[0..34, string] = [ + "False", "None", "True", "and", "as", "assert", "async", "await", + "break", "class", "continue", "def", "del", "elif", "else", "except", + "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", + "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", + "with", "yield"] + nimNextToken(g, keywords) + proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) = + g.lang = lang case lang of langNone: assert false of langNim: nimNextToken(g) @@ -895,6 +910,7 @@ proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) = of langC: cNextToken(g) of langJava: javaNextToken(g) of langYaml: yamlNextToken(g) + of langPython: pythonNextToken(g) when isMainModule: var keywords: seq[string] diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 1bf73e146..8b12a89c4 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -188,13 +188,13 @@ not in table""" let input1 = """ Test 2 column/4 rows table: ==== === -H0 H1 +H0 H1 ==== === -A0 A1 +A0 A1 ==== === -A2 A3 +A2 A3 ==== === -A4 A5 +A4 A5 ==== === """ let output1 = rstToLatex(input1, {}) assert "{|X|X|}" in output1 # 2 columns @@ -360,3 +360,19 @@ Test1 let output1l = rstToLatex(input1, {}) assert "line block\\\\" in output1l assert "other line\\\\" in output1l + +suite "RST/Code highlight": + test "Basic Python code highlight": + let pythonCode = """ + .. code-block:: python + + def f_name(arg=42): + print(f"{arg}") + + """ + + let expected = """

      def f_name(arg=42): + print(f"{arg}")

      """ + + check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) == + strip(expected) From a32acc351e929286e1df4a058f397dffcb6435ef Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 9 Dec 2020 09:36:46 +0800 Subject: [PATCH 1631/4254] Revert "use generics in random (#16283)" (#16291) This reverts commit 71e2a9e569ab3380fd057e4fc16e6d4ccd66f1f4. --- lib/pure/random.nim | 48 +++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 0ee75e027..683140cd8 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -217,7 +217,8 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. ## ## See also: - ## * `rand proc<#rand,T>`_ `T` are integers, floats, and enums without holes. + ## * `rand proc<#rand,int>`_ that returns an integer using the default + ## random number generator ## * `rand proc<#rand,Rand,range[]>`_ that returns a float ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type @@ -232,6 +233,28 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = if x <= randMax - (randMax mod Ui(max)): return int(x mod (uint64(max)+1u64)) +proc rand*(max: int): int {.benign.} = + ## Returns a random integer in the range `0..max`. + ## + ## If `randomize<#randomize>`_ has not been called, the sequence of random + ## numbers returned from this proc will always be the same. + ## + ## This proc uses the default random number generator. Thus, it is **not** + ## thread-safe. + ## + ## See also: + ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a + ## provided state + ## * `rand proc<#rand,float>`_ that returns a float + ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type + runnableExamples: + randomize(123) + doAssert rand(100) == 0 + doAssert rand(100) == 96 + doAssert rand(100) == 66 + rand(state, max) + proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = ## Returns a random floating point number in the range `0.0..max` ## using the given state. @@ -253,10 +276,8 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = let u = (0x3FFu64 shl 52u64) or (x shr 12u64) result = (cast[float](u) - 1.0) * max -proc rand*[T: Ordinal or SomeFloat](max: T): T {.benign.} = - ## Returns a random floating point number in the range `T(0) .. max`. - ## - ## Allowed types for `T` are integers, floats, and enums without holes. +proc rand*(max: float): float {.benign.} = + ## Returns a random floating point number in the range `0.0..max`. ## ## If `randomize<#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. @@ -265,21 +286,16 @@ proc rand*[T: Ordinal or SomeFloat](max: T): T {.benign.} = ## thread-safe. ## ## See also: - ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a - ## provided state ## * `rand proc<#rand,Rand,range[]>`_ that returns a float using a ## provided state + ## * `rand proc<#rand,int>`_ that returns an integer ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: - randomize(123) - doAssert rand(100) == 0 - doAssert rand(100) == 96 - doAssert rand(100) == 66 - + randomize(234) let f = rand(1.0) ## f = 8.717181376738381e-07 - result = T(rand(state, max)) + rand(state, max) proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = ## For a slice `a..b`, returns a value in the range `a..b` using the given @@ -319,7 +335,8 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = ## See also: ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice and uses ## a provided state - ## * `rand proc<#rand,T>`_ `T` are integers, floats, and enums without holes. + ## * `rand proc<#rand,int>`_ that returns an integer + ## * `rand proc<#rand,float>`_ that returns a floating point number ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(345) @@ -338,7 +355,8 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T = ## thread-safe. ## ## See also: - ## * `rand proc<#rand,T>`_ `T` are integers, floats, and enums without holes. + ## * `rand proc<#rand,int>`_ that returns an integer + ## * `rand proc<#rand,float>`_ that returns a floating point number ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice runnableExamples: randomize(567) From 40255f6721154c35a8f66653826928123178f1bb Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 9 Dec 2020 10:56:28 +0100 Subject: [PATCH 1632/4254] put both funcs and procs under the same section in the documentation (#16301) * both funcs and procs are under the same section in the documentation * update the test --- compiler/docgen.nim | 10 ++---- nimdoc/testproject/expected/testproject.html | 35 +++++++------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6ee03e292..7b3b62174 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1045,12 +1045,9 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = let pragmaNode = findPragma(n, wDeprecated) d.modDeprecationMsg.add(genDeprecationMsg(d, pragmaNode)) of nkCommentStmt: d.modDesc.add(genComment(d, n)) - of nkProcDef: + of nkProcDef, nkFuncDef: when useEffectSystem: documentRaises(d.cache, n) genItemAux(skProc) - of nkFuncDef: - when useEffectSystem: documentRaises(d.cache, n) - genItemAux(skFunc) of nkMethodDef: when useEffectSystem: documentRaises(d.cache, n) genItemAux(skMethod) @@ -1101,12 +1098,9 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = d.add %*{"comment": genComment(d, n)} else: d.modDesc.add(genComment(d, n)) - of nkProcDef: + of nkProcDef, nkFuncDef: when useEffectSystem: documentRaises(d.cache, n) d.add genJsonItem(d, n, n[namePos], skProc) - of nkFuncDef: - when useEffectSystem: documentRaises(d.cache, n) - d.add genJsonItem(d, n, n[namePos], skFunc) of nkMethodDef: when useEffectSystem: documentRaises(d.cache, n) d.add genJsonItem(d, n, n[namePos], skMethod) diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index a32e1180c..2bf8855c7 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -262,6 +262,11 @@ window.addEventListener('DOMContentLoaded', main);
    • z4
    • +
    +
      z8
    • -
    • - Funcs - -
    • Methods
        @@ -509,6 +503,13 @@ This is deprecated without message. This is deprecated with a message. +
    + +
    func someFunc() {...}{.raises: [], tags: [].}
    +
    + +My someFunc. Stuff in quotes here. Some link +
    proc fromUtils3() {...}{.raises: [], tags: [].}
    @@ -795,18 +796,6 @@ ok1 - -
    -

    Funcs

    -
    - -
    func someFunc() {...}{.raises: [], tags: [].}
    -
    - -My someFunc. Stuff in quotes here. Some link - -
    -

    Methods

    From 140ebe6019d097eacd5bb81f2937647d2b7d9954 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Wed, 9 Dec 2020 10:57:12 +0100 Subject: [PATCH 1633/4254] complex.nim: Use `func` everywhere (#16294) --- lib/pure/complex.nim | 120 ++++++++++++++++---------------- tests/effects/tstrict_funcs.nim | 1 + 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index d1056e6e8..04e5e8e56 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -24,15 +24,15 @@ type Complex32* = Complex[float32] ## Alias for a pair of 32-bit floats. -proc complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] = +func complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] = result.re = re result.im = im -proc complex32*(re: float32; im: float32 = 0.0): Complex[float32] = +func complex32*(re: float32; im: float32 = 0.0): Complex[float32] = result.re = re result.im = im -proc complex64*(re: float64; im: float64 = 0.0): Complex[float64] = +func complex64*(re: float64; im: float64 = 0.0): Complex[float64] = result.re = re result.im = im @@ -41,71 +41,71 @@ template im*(arg: typedesc[float64]): Complex64 = complex[float64](0, 1) template im*(arg: float32): Complex32 = complex[float32](0, arg) template im*(arg: float64): Complex64 = complex[float64](0, arg) -proc abs*[T](z: Complex[T]): T = +func abs*[T](z: Complex[T]): T = ## Returns the distance from (0,0) to ``z``. result = hypot(z.re, z.im) -proc abs2*[T](z: Complex[T]): T = +func abs2*[T](z: Complex[T]): T = ## Returns the squared distance from (0,0) to ``z``. result = z.re*z.re + z.im*z.im -proc conjugate*[T](z: Complex[T]): Complex[T] = +func conjugate*[T](z: Complex[T]): Complex[T] = ## Conjugates of complex number ``z``. result.re = z.re result.im = -z.im -proc inv*[T](z: Complex[T]): Complex[T] = +func inv*[T](z: Complex[T]): Complex[T] = ## Multiplicatives inverse of complex number ``z``. conjugate(z) / abs2(z) -proc `==` *[T](x, y: Complex[T]): bool = +func `==` *[T](x, y: Complex[T]): bool = ## Compares two complex numbers ``x`` and ``y`` for equality. result = x.re == y.re and x.im == y.im -proc `+` *[T](x: T; y: Complex[T]): Complex[T] = +func `+` *[T](x: T; y: Complex[T]): Complex[T] = ## Adds a real number to a complex number. result.re = x + y.re result.im = y.im -proc `+` *[T](x: Complex[T]; y: T): Complex[T] = +func `+` *[T](x: Complex[T]; y: T): Complex[T] = ## Adds a complex number to a real number. result.re = x.re + y result.im = x.im -proc `+` *[T](x, y: Complex[T]): Complex[T] = +func `+` *[T](x, y: Complex[T]): Complex[T] = ## Adds two complex numbers. result.re = x.re + y.re result.im = x.im + y.im -proc `-` *[T](z: Complex[T]): Complex[T] = +func `-` *[T](z: Complex[T]): Complex[T] = ## Unary minus for complex numbers. result.re = -z.re result.im = -z.im -proc `-` *[T](x: T; y: Complex[T]): Complex[T] = +func `-` *[T](x: T; y: Complex[T]): Complex[T] = ## Subtracts a complex number from a real number. x + (-y) -proc `-` *[T](x: Complex[T]; y: T): Complex[T] = +func `-` *[T](x: Complex[T]; y: T): Complex[T] = ## Subtracts a real number from a complex number. result.re = x.re - y result.im = x.im -proc `-` *[T](x, y: Complex[T]): Complex[T] = +func `-` *[T](x, y: Complex[T]): Complex[T] = ## Subtracts two complex numbers. result.re = x.re - y.re result.im = x.im - y.im -proc `/` *[T](x: Complex[T]; y: T): Complex[T] = +func `/` *[T](x: Complex[T]; y: T): Complex[T] = ## Divides complex number ``x`` by real number ``y``. result.re = x.re / y result.im = x.im / y -proc `/` *[T](x: T; y: Complex[T]): Complex[T] = +func `/` *[T](x: T; y: Complex[T]): Complex[T] = ## Divides real number ``x`` by complex number ``y``. result = x * inv(y) -proc `/` *[T](x, y: Complex[T]): Complex[T] = +func `/` *[T](x, y: Complex[T]): Complex[T] = ## Divides ``x`` by ``y``. var r, den: T if abs(y.re) < abs(y.im): @@ -119,44 +119,44 @@ proc `/` *[T](x, y: Complex[T]): Complex[T] = result.re = (x.re + r * x.im) / den result.im = (x.im - r * x.re) / den -proc `*` *[T](x: T; y: Complex[T]): Complex[T] = +func `*` *[T](x: T; y: Complex[T]): Complex[T] = ## Multiplies a real number and a complex number. result.re = x * y.re result.im = x * y.im -proc `*` *[T](x: Complex[T]; y: T): Complex[T] = +func `*` *[T](x: Complex[T]; y: T): Complex[T] = ## Multiplies a complex number with a real number. result.re = x.re * y result.im = x.im * y -proc `*` *[T](x, y: Complex[T]): Complex[T] = +func `*` *[T](x, y: Complex[T]): Complex[T] = ## Multiplies ``x`` with ``y``. result.re = x.re * y.re - x.im * y.im result.im = x.im * y.re + x.re * y.im -proc `+=` *[T](x: var Complex[T]; y: Complex[T]) = +func `+=` *[T](x: var Complex[T]; y: Complex[T]) = ## Adds ``y`` to ``x``. x.re += y.re x.im += y.im -proc `-=` *[T](x: var Complex[T]; y: Complex[T]) = +func `-=` *[T](x: var Complex[T]; y: Complex[T]) = ## Subtracts ``y`` from ``x``. x.re -= y.re x.im -= y.im -proc `*=` *[T](x: var Complex[T]; y: Complex[T]) = +func `*=` *[T](x: var Complex[T]; y: Complex[T]) = ## Multiplies ``y`` to ``x``. let im = x.im * y.re + x.re * y.im x.re = x.re * y.re - x.im * y.im x.im = im -proc `/=` *[T](x: var Complex[T]; y: Complex[T]) = +func `/=` *[T](x: var Complex[T]; y: Complex[T]) = ## Divides ``x`` by ``y`` in place. x = x / y -proc sqrt*[T](z: Complex[T]): Complex[T] = +func sqrt*[T](z: Complex[T]): Complex[T] = ## Square root for a complex number ``z``. var x, y, w, r: T @@ -179,7 +179,7 @@ proc sqrt*[T](z: Complex[T]): Complex[T] = result.im = if z.im >= 0.0: w else: -w result.re = z.im / (result.im + result.im) -proc exp*[T](z: Complex[T]): Complex[T] = +func exp*[T](z: Complex[T]): Complex[T] = ## ``e`` raised to the power ``z``. var rho = exp(z.re) @@ -187,20 +187,20 @@ proc exp*[T](z: Complex[T]): Complex[T] = result.re = rho * cos(theta) result.im = rho * sin(theta) -proc ln*[T](z: Complex[T]): Complex[T] = +func ln*[T](z: Complex[T]): Complex[T] = ## Returns the natural log of ``z``. result.re = ln(abs(z)) result.im = arctan2(z.im, z.re) -proc log10*[T](z: Complex[T]): Complex[T] = +func log10*[T](z: Complex[T]): Complex[T] = ## Returns the log base 10 of ``z``. result = ln(z) / ln(10.0) -proc log2*[T](z: Complex[T]): Complex[T] = +func log2*[T](z: Complex[T]): Complex[T] = ## Returns the log base 2 of ``z``. result = ln(z) / ln(2.0) -proc pow*[T](x, y: Complex[T]): Complex[T] = +func pow*[T](x, y: Complex[T]): Complex[T] = ## ``x`` raised to the power ``y``. if x.re == 0.0 and x.im == 0.0: if y.re == 0.0 and y.im == 0.0: @@ -222,118 +222,118 @@ proc pow*[T](x, y: Complex[T]): Complex[T] = result.re = s * cos(r) result.im = s * sin(r) -proc pow*[T](x: Complex[T]; y: T): Complex[T] = +func pow*[T](x: Complex[T]; y: T): Complex[T] = ## Complex number ``x`` raised to the power ``y``. pow(x, complex[T](y)) -proc sin*[T](z: Complex[T]): Complex[T] = +func sin*[T](z: Complex[T]): Complex[T] = ## Returns the sine of ``z``. result.re = sin(z.re) * cosh(z.im) result.im = cos(z.re) * sinh(z.im) -proc arcsin*[T](z: Complex[T]): Complex[T] = +func arcsin*[T](z: Complex[T]): Complex[T] = ## Returns the inverse sine of ``z``. result = -im(T) * ln(im(T) * z + sqrt(T(1.0) - z*z)) -proc cos*[T](z: Complex[T]): Complex[T] = +func cos*[T](z: Complex[T]): Complex[T] = ## Returns the cosine of ``z``. result.re = cos(z.re) * cosh(z.im) result.im = -sin(z.re) * sinh(z.im) -proc arccos*[T](z: Complex[T]): Complex[T] = +func arccos*[T](z: Complex[T]): Complex[T] = ## Returns the inverse cosine of ``z``. result = -im(T) * ln(z + sqrt(z*z - T(1.0))) -proc tan*[T](z: Complex[T]): Complex[T] = +func tan*[T](z: Complex[T]): Complex[T] = ## Returns the tangent of ``z``. result = sin(z) / cos(z) -proc arctan*[T](z: Complex[T]): Complex[T] = +func arctan*[T](z: Complex[T]): Complex[T] = ## Returns the inverse tangent of ``z``. result = T(0.5)*im(T) * (ln(T(1.0) - im(T)*z) - ln(T(1.0) + im(T)*z)) -proc cot*[T](z: Complex[T]): Complex[T] = +func cot*[T](z: Complex[T]): Complex[T] = ## Returns the cotangent of ``z``. result = cos(z)/sin(z) -proc arccot*[T](z: Complex[T]): Complex[T] = +func arccot*[T](z: Complex[T]): Complex[T] = ## Returns the inverse cotangent of ``z``. result = T(0.5)*im(T) * (ln(T(1.0) - im(T)/z) - ln(T(1.0) + im(T)/z)) -proc sec*[T](z: Complex[T]): Complex[T] = +func sec*[T](z: Complex[T]): Complex[T] = ## Returns the secant of ``z``. result = T(1.0) / cos(z) -proc arcsec*[T](z: Complex[T]): Complex[T] = +func arcsec*[T](z: Complex[T]): Complex[T] = ## Returns the inverse secant of ``z``. result = -im(T) * ln(im(T) * sqrt(1.0 - 1.0/(z*z)) + T(1.0)/z) -proc csc*[T](z: Complex[T]): Complex[T] = +func csc*[T](z: Complex[T]): Complex[T] = ## Returns the cosecant of ``z``. result = T(1.0) / sin(z) -proc arccsc*[T](z: Complex[T]): Complex[T] = +func arccsc*[T](z: Complex[T]): Complex[T] = ## Returns the inverse cosecant of ``z``. result = -im(T) * ln(sqrt(T(1.0) - T(1.0)/(z*z)) + im(T)/z) -proc sinh*[T](z: Complex[T]): Complex[T] = +func sinh*[T](z: Complex[T]): Complex[T] = ## Returns the hyperbolic sine of ``z``. result = T(0.5) * (exp(z) - exp(-z)) -proc arcsinh*[T](z: Complex[T]): Complex[T] = +func arcsinh*[T](z: Complex[T]): Complex[T] = ## Returns the inverse hyperbolic sine of ``z``. result = ln(z + sqrt(z*z + 1.0)) -proc cosh*[T](z: Complex[T]): Complex[T] = +func cosh*[T](z: Complex[T]): Complex[T] = ## Returns the hyperbolic cosine of ``z``. result = T(0.5) * (exp(z) + exp(-z)) -proc arccosh*[T](z: Complex[T]): Complex[T] = +func arccosh*[T](z: Complex[T]): Complex[T] = ## Returns the inverse hyperbolic cosine of ``z``. result = ln(z + sqrt(z*z - T(1.0))) -proc tanh*[T](z: Complex[T]): Complex[T] = +func tanh*[T](z: Complex[T]): Complex[T] = ## Returns the hyperbolic tangent of ``z``. result = sinh(z) / cosh(z) -proc arctanh*[T](z: Complex[T]): Complex[T] = +func arctanh*[T](z: Complex[T]): Complex[T] = ## Returns the inverse hyperbolic tangent of ``z``. result = T(0.5) * (ln((T(1.0)+z) / (T(1.0)-z))) -proc sech*[T](z: Complex[T]): Complex[T] = +func sech*[T](z: Complex[T]): Complex[T] = ## Returns the hyperbolic secant of ``z``. result = T(2.0) / (exp(z) + exp(-z)) -proc arcsech*[T](z: Complex[T]): Complex[T] = +func arcsech*[T](z: Complex[T]): Complex[T] = ## Returns the inverse hyperbolic secant of ``z``. result = ln(1.0/z + sqrt(T(1.0)/z+T(1.0)) * sqrt(T(1.0)/z-T(1.0))) -proc csch*[T](z: Complex[T]): Complex[T] = +func csch*[T](z: Complex[T]): Complex[T] = ## Returns the hyperbolic cosecant of ``z``. result = T(2.0) / (exp(z) - exp(-z)) -proc arccsch*[T](z: Complex[T]): Complex[T] = +func arccsch*[T](z: Complex[T]): Complex[T] = ## Returns the inverse hyperbolic cosecant of ``z``. result = ln(T(1.0)/z + sqrt(T(1.0)/(z*z) + T(1.0))) -proc coth*[T](z: Complex[T]): Complex[T] = +func coth*[T](z: Complex[T]): Complex[T] = ## Returns the hyperbolic cotangent of ``z``. result = cosh(z) / sinh(z) -proc arccoth*[T](z: Complex[T]): Complex[T] = +func arccoth*[T](z: Complex[T]): Complex[T] = ## Returns the inverse hyperbolic cotangent of ``z``. result = T(0.5) * (ln(T(1.0) + T(1.0)/z) - ln(T(1.0) - T(1.0)/z)) -proc phase*[T](z: Complex[T]): T = +func phase*[T](z: Complex[T]): T = ## Returns the phase of ``z``. arctan2(z.im, z.re) -proc polar*[T](z: Complex[T]): tuple[r, phi: T] = +func polar*[T](z: Complex[T]): tuple[r, phi: T] = ## Returns ``z`` in polar coordinates. (r: abs(z), phi: phase(z)) -proc rect*[T](r, phi: T): Complex[T] = +func rect*[T](r, phi: T): Complex[T] = ## Returns the complex number with polar coordinates ``r`` and ``phi``. ## ## | ``result.re = r * cos(phi)`` @@ -341,7 +341,7 @@ proc rect*[T](r, phi: T): Complex[T] = complex(r * cos(phi), r * sin(phi)) -proc `$`*(z: Complex): string = +func `$`*(z: Complex): string = ## Returns ``z``'s string representation as ``"(re, im)"``. result = "(" & $z.re & ", " & $z.im & ")" diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 532c6e75e..89ac68108 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -6,6 +6,7 @@ import tables, streams, parsecsv # We import the below modules to check that they compile with `strictFuncs`. # They are otherwise unused in this file. import + complex, httpcore, math, nre, From c43dca29013127c29578a241881d23d49c37231f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 9 Dec 2020 18:19:02 +0800 Subject: [PATCH 1634/4254] disbale deprecated CI in fork repo (#16299) --- appveyor.yml => appveyor.yml.disabled | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yml => appveyor.yml.disabled (100%) diff --git a/appveyor.yml b/appveyor.yml.disabled similarity index 100% rename from appveyor.yml rename to appveyor.yml.disabled From 6f57ebae349f073d696761fbba6d3f24f4b3dde9 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Wed, 9 Dec 2020 12:11:16 +0100 Subject: [PATCH 1635/4254] sequtils.nim: Use `func` (#16293) * sequtils.nim: proc -> func * sequtils.nim: proc -> func in links * sequtils.nim: proc -> func in non-link doc comments * test: add `sequtils` to strictFuncs test --- lib/pure/collections/sequtils.nim | 92 +++++++++++++++---------------- lib/pure/collections/sets.nim | 2 +- tests/effects/tstrict_funcs.nim | 1 + 3 files changed, 48 insertions(+), 47 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 71558fe0d..a7e392026 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -110,12 +110,12 @@ macro evalOnceAs(expAlias, exp: untyped, newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)], body = val, procType = nnkTemplateDef)) -proc concat*[T](seqs: varargs[seq[T]]): seq[T] = +func concat*[T](seqs: varargs[seq[T]]): seq[T] = ## Takes several sequences' items and returns them inside a new sequence. ## All sequences must be of the same type. ## ## See also: - ## * `distribute proc<#distribute,seq[T],Positive>`_ for a reverse + ## * `distribute func<#distribute,seq[T],Positive>`_ for a reverse ## operation ## runnableExamples: @@ -135,7 +135,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] = result[i] = itm inc(i) -proc count*[T](s: openArray[T], x: T): int = +func count*[T](s: openArray[T], x: T): int = ## Returns the number of occurrences of the item `x` in the container `s`. ## runnableExamples: @@ -150,7 +150,7 @@ proc count*[T](s: openArray[T], x: T): int = if itm == x: inc result -proc cycle*[T](s: openArray[T], n: Natural): seq[T] = +func cycle*[T](s: openArray[T], n: Natural): seq[T] = ## Returns a new sequence with the items of the container `s` repeated ## `n` times. ## `n` must be a non-negative number (zero or more). @@ -168,7 +168,7 @@ proc cycle*[T](s: openArray[T], n: Natural): seq[T] = result[o] = e inc o -proc repeat*[T](x: T, n: Natural): seq[T] = +func repeat*[T](x: T, n: Natural): seq[T] = ## Returns a new sequence with the item `x` repeated `n` times. ## `n` must be a non-negative number (zero or more). ## @@ -181,7 +181,7 @@ proc repeat*[T](x: T, n: Natural): seq[T] = for i in 0 ..< n: result[i] = x -proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = +func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = ## Returns a new sequence without duplicates. ## ## Setting the optional argument ``isSorted`` to ``true`` (default: false) @@ -209,7 +209,7 @@ proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = for itm in items(s): if not result.contains(itm): result.add(itm) -proc minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = +func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = ## Returns the index of the minimum value of `s`. ## ``T`` needs to have a ``<`` operator. runnableExamples: @@ -226,7 +226,7 @@ proc minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = for i in 1..high(s): if s[i] < s[result]: result = i -proc maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = +func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = ## Returns the index of the maximum value of `s`. ## ``T`` needs to have a ``<`` operator. runnableExamples: @@ -245,7 +245,7 @@ proc maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = template zipImpl(s1, s2, retType: untyped): untyped = - proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = + func zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = ## Returns a new sequence with a combination of the two input containers. ## ## The input containers can be of different types. @@ -288,7 +288,7 @@ when (NimMajor, NimMinor) <= (1, 0): else: zipImpl(s1, s2, seq[(S, T)]) -proc unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = +func unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = ## Returns a tuple of two sequences split out from a sequence of 2-field tuples. runnableExamples: let @@ -303,19 +303,19 @@ proc unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = result[0][i] = s[i][0] result[1][i] = s[i][1] -proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = +func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = ## Splits and distributes a sequence `s` into `num` sub-sequences. ## ## Returns a sequence of `num` sequences. For *some* input values this is the - ## inverse of the `concat <#concat,varargs[seq[T]]>`_ proc. + ## inverse of the `concat <#concat,varargs[seq[T]]>`_ func. ## The input sequence `s` can be empty, which will produce ## `num` empty sequences. ## ## If `spread` is false and the length of `s` is not a multiple of `num`, the - ## proc will max out the first sub-sequence with ``1 + len(s) div num`` + ## func will max out the first sub-sequence with ``1 + len(s) div num`` ## entries, leaving the remainder of elements to the last sequence. ## - ## On the other hand, if `spread` is true, the proc will distribute evenly + ## On the other hand, if `spread` is true, the func will distribute evenly ## the remainder of the division across all sequences, which makes the result ## more suited to multithreading where you are passing equal sized work units ## to a thread pool and want to maximize core usage. @@ -360,7 +360,7 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = result[i].add(s[g]) first = last -proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): +func map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): seq[S]{.inline.} = ## Returns a new sequence with the results of `op` proc applied to every ## item in the container `s`. @@ -374,7 +374,7 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): ## See also: ## * `sugar.collect macro`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ - ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version + ## * `apply func<#apply,openArray[T],proc(T)_2>`_ for the in-place version ## runnableExamples: let @@ -386,7 +386,7 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): for i in 0 ..< s.len: result[i] = op(s[i]) -proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) +func apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## @@ -397,7 +397,7 @@ proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) ## ## See also: ## * `applyIt template<#applyIt.t,untyped,untyped>`_ - ## * `map proc<#map,openArray[T],proc(T)>`_ + ## * `map func<#map,openArray[T],proc(T)>`_ ## runnableExamples: var a = @["1", "2", "3", "4"] @@ -406,7 +406,7 @@ proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) for i in 0 ..< s.len: op(s[i]) -proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) +func apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## @@ -417,7 +417,7 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) ## ## See also: ## * `applyIt template<#applyIt.t,untyped,untyped>`_ - ## * `map proc<#map,openArray[T],proc(T)>`_ + ## * `map func<#map,openArray[T],proc(T)>`_ ## runnableExamples: var a = @["1", "2", "3", "4"] @@ -426,7 +426,7 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) for i in 0 ..< s.len: s[i] = op(s[i]) -proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = +func apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = ## Same as `apply` but for proc that do not return and do not mutate `s` directly. runnableExamples: apply([0, 1, 2, 3, 4], proc(item: int) = echo item) for i in 0 ..< s.len: op(s[i]) @@ -440,7 +440,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## ## See also: ## * `sugar.collect macro`_ - ## * `fliter proc<#filter,openArray[T],proc(T)>`_ + ## * `fliter func<#filter,openArray[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## runnableExamples: @@ -454,7 +454,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = if pred(s[i]): yield s[i] -proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] +func filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] {.inline.} = ## Returns a new sequence with all the items of `s` that fulfilled the ## predicate `pred` (function that returns a `bool`). @@ -466,7 +466,7 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] ## * `sugar.collect macro`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ - ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ for the in-place version + ## * `keepIf func<#keepIf,seq[T],proc(T)>`_ for the in-place version ## runnableExamples: let @@ -481,19 +481,19 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] if pred(s[i]): result.add(s[i]) -proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) +func keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) {.inline.} = ## Keeps the items in the passed sequence `s` if they fulfilled the ## predicate `pred` (function that returns a `bool`). ## ## Note that `s` must be declared as a ``var``. ## - ## Similar to the `filter proc<#filter,openArray[T],proc(T)>`_, + ## Similar to the `filter func<#filter,openArray[T],proc(T)>`_, ## but modifies the sequence directly. ## ## See also: ## * `keepItIf template<#keepItIf.t,seq,untyped>`_ - ## * `filter proc<#filter,openArray[T],proc(T)>`_ + ## * `filter func<#filter,openArray[T],proc(T)>`_ ## runnableExamples: var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] @@ -511,7 +511,7 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) inc(pos) setLen(s, pos) -proc delete*[T](s: var seq[T]; first, last: Natural) = +func delete*[T](s: var seq[T]; first, last: Natural) = ## Deletes in the items of a sequence `s` at positions ``first..last`` ## (including both ends of a range). ## This modifies `s` itself, it does not return a copy. @@ -536,7 +536,7 @@ proc delete*[T](s: var seq[T]; first, last: Natural) = inc(j) setLen(s, newLen) -proc insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = +func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = ## Inserts items from `src` into `dest` at position `pos`. This modifies ## `dest` itself, it does not return a copy. ## @@ -574,7 +574,7 @@ template filterIt*(s, pred: untyped): untyped = ## Returns a new sequence with all the items of `s` that fulfilled the ## predicate `pred`. ## - ## Unlike the `filter proc<#filter,openArray[T],proc(T)>`_ and + ## Unlike the `filter func<#filter,openArray[T],proc(T)>`_ and ## `filter iterator<#filter.i,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using the ``it`` variable ## for testing, like: ``filterIt("abcxyz", it == 'x')``. @@ -584,7 +584,7 @@ template filterIt*(s, pred: untyped): untyped = ## ## See also: ## * `sugar.collect macro`_ - ## * `fliter proc<#filter,openArray[T],proc(T)>`_ + ## * `fliter func<#filter,openArray[T],proc(T)>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## runnableExamples: @@ -604,12 +604,12 @@ template keepItIf*(varSeq: seq, pred: untyped) = ## Keeps the items in the passed sequence (must be declared as a ``var``) ## if they fulfilled the predicate. ## - ## Unlike the `keepIf proc<#keepIf,seq[T],proc(T)>`_, + ## Unlike the `keepIf func<#keepIf,seq[T],proc(T)>`_, ## the predicate needs to be an expression using ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``. ## ## See also: - ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ + ## * `keepIf func<#keepIf,seq[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## runnableExamples: @@ -648,13 +648,13 @@ since (1, 1): if pred: result += 1 result -proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = +func all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = ## Iterates through a container and checks if every item fulfills the ## predicate. ## ## See also: ## * `allIt template<#allIt.t,untyped,untyped>`_ - ## * `any proc<#any,openArray[T],proc(T)>`_ + ## * `any func<#any,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] @@ -670,12 +670,12 @@ template allIt*(s, pred: untyped): bool = ## Iterates through a container and checks if every item fulfills the ## predicate. ## - ## Unlike the `all proc<#all,openArray[T],proc(T)>`_, + ## Unlike the `all func<#all,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using ## the ``it`` variable for testing, like: ``allIt("abba", it == 'a')``. ## ## See also: - ## * `all proc<#all,openArray[T],proc(T)>`_ + ## * `all func<#all,openArray[T],proc(T)>`_ ## * `anyIt template<#anyIt.t,untyped,untyped>`_ ## runnableExamples: @@ -690,13 +690,13 @@ template allIt*(s, pred: untyped): bool = break result -proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = +func any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = ## Iterates through a container and checks if some item fulfills the ## predicate. ## ## See also: ## * `anyIt template<#anyIt.t,untyped,untyped>`_ - ## * `all proc<#all,openArray[T],proc(T)>`_ + ## * `all func<#all,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] @@ -712,12 +712,12 @@ template anyIt*(s, pred: untyped): bool = ## Iterates through a container and checks if some item fulfills the ## predicate. ## - ## Unlike the `any proc<#any,openArray[T],proc(T)>`_, + ## Unlike the `any func<#any,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using ## the ``it`` variable for testing, like: ``anyIt("abba", it == 'a')``. ## ## See also: - ## * `any proc<#any,openArray[T],proc(T)>`_ + ## * `any func<#any,openArray[T],proc(T)>`_ ## * `allIt template<#allIt.t,untyped,untyped>`_ ## runnableExamples: @@ -840,7 +840,7 @@ template foldl*(sequence, operation: untyped): untyped = procs = @["proc", "Is", "Also", "Fine"] - proc foo(acc, cur: string): string = + func foo(acc, cur: string): string = result = acc & cur assert addition == 25, "Addition is (((5)+9)+11)" @@ -944,7 +944,7 @@ template mapIt*(s: typed, op: untyped): untyped = ## ## See also: ## * `sugar.collect macro`_ - ## * `map proc<#map,openArray[T],proc(T)>`_ + ## * `map func<#map,openArray[T],proc(T)>`_ ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version ## runnableExamples: @@ -1005,14 +1005,14 @@ template mapIt*(s: typed, op: untyped): untyped = map(s, f) template applyIt*(varSeq, op: untyped) = - ## Convenience template around the mutable ``apply`` proc to reduce typing. + ## Convenience template around the mutable ``apply`` func to reduce typing. ## ## The template injects the ``it`` variable which you can use directly in an ## expression. The expression has to return the same type as the sequence you ## are mutating. ## ## See also: - ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ + ## * `apply func<#apply,openArray[T],proc(T)_2>`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## runnableExamples: @@ -1048,7 +1048,7 @@ template newSeqWith*(len: int, init: untyped): untyped = result[i] = init result -proc mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; +func mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; filter = nnkLiterals): NimNode = if constructor.kind in filter: result = newNimNode(nnkCall, lineInfoFrom = constructor) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 18f91f516..faa2f8c71 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -16,7 +16,7 @@ ## ## Common usages of sets: ## * removing duplicates from a container by converting it with `toHashSet proc -## <#toHashSet,openArray[A]>`_ (see also `sequtils.deduplicate proc +## <#toHashSet,openArray[A]>`_ (see also `sequtils.deduplicate func ## `_) ## * membership testing ## * mathematical operations on two sets, such as diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 89ac68108..7a0f1ee32 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -10,6 +10,7 @@ import httpcore, math, nre, + sequtils, strutils, uri From 9ce2f87a0a02d85e943b2b181bcae66fbd644f11 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 9 Dec 2020 19:18:32 +0800 Subject: [PATCH 1636/4254] clean up old codes (#16284) * clean up old codes * fix docs and links * clean --- compiler/condsyms.nim | 1 - lib/system/iterators_1.nim | 249 +++++++++++++++---------------------- 2 files changed, 103 insertions(+), 147 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ee849435f..131f32f32 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -58,7 +58,6 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimGenericInOutFlags") when false: defineSymbol("nimHasOpt") defineSymbol("nimNoArrayToCstringConversion") - defineSymbol("nimNewRoof") defineSymbol("nimHasRunnableExamples") defineSymbol("nimNewDot") defineSymbol("nimHasNilChecks") diff --git a/lib/system/iterators_1.nim b/lib/system/iterators_1.nim index 262bd6aab..2bc58c2b7 100644 --- a/lib/system/iterators_1.nim +++ b/lib/system/iterators_1.nim @@ -9,15 +9,20 @@ iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = ## ## `T` may be any ordinal type, `step` may only be positive. ## - ## **Note**: This fails to count to ``low(int)`` if T = int for + ## **Note**: This fails to count to `low(int)` if T = int for ## efficiency reasons. - ## - ## .. code-block:: Nim - ## for i in countdown(7, 3): - ## echo i # => 7; 6; 5; 4; 3 - ## - ## for i in countdown(9, 2, 3): - ## echo i # => 9; 6; 3 + runnableExamples: + import sugar + let x = collect(newSeq): + for i in countdown(7, 3): + i + + assert x == @[7, 6, 5, 4, 3] + + let y = collect(newseq): + for i in countdown(9, 2, 3): + i + assert y == @[9, 6, 3] when T is (uint|uint64): var res = a while res >= b: @@ -35,148 +40,100 @@ iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = yield res dec(res, step) -when defined(nimNewRoof): - iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = - ## Counts from ordinal value `a` to `b` (inclusive) with the given - ## step count. - ## - ## `T` may be any ordinal type, `step` may only be positive. - ## - ## **Note**: This fails to count to ``high(int)`` if T = int for - ## efficiency reasons. - ## - ## .. code-block:: Nim - ## for i in countup(3, 7): - ## echo i # => 3; 4; 5; 6; 7 - ## - ## for i in countup(2, 9, 3): - ## echo i # => 2; 5; 8 - mixin inc - when T is IntLikeForCount and T is Ordinal: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res, step) - else: - var res = a - while res <= b: - yield res - inc(res, step) +iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = + ## Counts from ordinal value `a` to `b` (inclusive) with the given + ## step count. + ## + ## `T` may be any ordinal type, `step` may only be positive. + ## + ## **Note**: This fails to count to `high(int)` if T = int for + ## efficiency reasons. + runnableExamples: + import sugar + let x = collect(newSeq): + for i in countup(3, 7): + i + + assert x == @[3, 4, 5, 6, 7] - iterator `..`*[T](a, b: T): T {.inline.} = - ## An alias for `countup(a, b, 1)`. + let y = collect(newseq): + for i in countup(2, 9, 3): + i + assert y == @[2, 5, 8] + mixin inc + when T is IntLikeForCount and T is Ordinal: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res, step) + else: + var res = a + while res <= b: + yield res + inc(res, step) + +iterator `..`*[T](a, b: T): T {.inline.} = + ## An alias for `countup(a, b, 1)`. + ## + ## See also: + ## * [..<](#..<.i,T,T) + runnableExamples: + import sugar + + let x = collect(newSeq): + for i in 3 .. 7: + i + + assert x == @[3, 4, 5, 6, 7] + mixin inc + when T is IntLikeForCount and T is Ordinal: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res) + else: + var res = a + while res <= b: + yield res + inc(res) + +template dotdotImpl(t) {.dirty.} = + iterator `..`*(a, b: t): t {.inline.} = + ## A type specialized version of `..` for convenience so that + ## mixing integer types works better. ## ## See also: ## * [..<](#..<.i,T,T) - ## - ## .. code-block:: Nim - ## for i in 3 .. 7: - ## echo i # => 3; 4; 5; 6; 7 - mixin inc - when T is IntLikeForCount and T is Ordinal: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res) - else: - var res = a - while res <= b: - yield res - inc(res) + var res = a + while res <= b: + yield res + inc(res) - template dotdotImpl(t) {.dirty.} = - iterator `..`*(a, b: t): t {.inline.} = - ## A type specialized version of ``..`` for convenience so that - ## mixing integer types works better. - ## - ## See also: - ## * [..<](#..<.i,T,T) - var res = a - while res <= b: - yield res - inc(res) +dotdotImpl(int64) +dotdotImpl(int32) +dotdotImpl(uint64) +dotdotImpl(uint32) - dotdotImpl(int64) - dotdotImpl(int32) - dotdotImpl(uint64) - dotdotImpl(uint32) +iterator `..<`*[T](a, b: T): T {.inline.} = + mixin inc + var i = a + while i < b: + yield i + inc i - iterator `..<`*[T](a, b: T): T {.inline.} = - mixin inc - var i = a - while i < b: - yield i - inc i - - template dotdotLessImpl(t) {.dirty.} = - iterator `..<`*(a, b: t): t {.inline.} = - ## A type specialized version of ``..<`` for convenience so that - ## mixing integer types works better. - var res = a - while res < b: - yield res - inc(res) - - dotdotLessImpl(int64) - dotdotLessImpl(int32) - dotdotLessImpl(uint64) - dotdotLessImpl(uint32) - -else: # not defined(nimNewRoof) - iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = - ## Counts from ordinal value `a` up to `b` (inclusive) with the given - ## step count. - ## - ## `S`, `T` may be any ordinal type, `step` may only be positive. - ## - ## **Note**: This fails to count to ``high(int)`` if T = int for - ## efficiency reasons. - ## - ## .. code-block:: Nim - ## for i in countup(3, 7): - ## echo i # => 3; 4; 5; 6; 7 - ## - ## for i in countup(2, 9, 3): - ## echo i # => 2; 5; 8 - when T is IntLikeForCount and T is Ordinal: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res, step) - else: - var res = T(a) - while res <= b: - yield res - inc(res, step) - - iterator `..`*[S, T](a: S, b: T): T {.inline.} = - ## An alias for `countup(a, b, 1)`. - ## - ## See also: - ## * [..<](#..<.i,T,T) - ## - ## .. code-block:: Nim - ## for i in 3 .. 7: - ## echo i # => 3; 4; 5; 6; 7 - mixin inc - when T is IntLikeForCount and T is Ordinal: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res) - else: - var res = T(a) - while res <= b: - yield res - inc(res) - - iterator `..<`*[S, T](a: S, b: T): T {.inline.} = - mixin inc - var i = T(a) - while i < b: - yield i - inc i +template dotdotLessImpl(t) {.dirty.} = + iterator `..<`*(a, b: t): t {.inline.} = + ## A type specialized version of `..<` for convenience so that + ## mixing integer types works better. + var res = a + while res < b: + yield res + inc(res) +dotdotLessImpl(int64) +dotdotLessImpl(int32) +dotdotLessImpl(uint64) +dotdotLessImpl(uint32) iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T {. inline, magic: "OmpParFor", sideEffect.} = @@ -189,9 +146,9 @@ iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T ## for further information. ## ## Note that the compiler maps that to - ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as + ## the `#pragma omp parallel for` construct of `OpenMP`:idx: and as ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of ``||`` will get proper support by Nim's code generator + ## versions of `||` will get proper support by Nim's code generator ## and GC. discard @@ -207,8 +164,8 @@ iterator `||`*[S, T](a: S, b: T, step: Positive, annotation: static string = "pa ## for further information. ## ## Note that the compiler maps that to - ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as + ## the `#pragma omp parallel for` construct of `OpenMP`:idx: and as ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of ``||`` will get proper support by Nim's code generator + ## versions of `||` will get proper support by Nim's code generator ## and GC. discard From 17a835a7b27c557ebb89c3d1bb44a9e5e6ce8ffb Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Wed, 9 Dec 2020 15:11:51 +0000 Subject: [PATCH 1637/4254] Zsh completion (#16261) * Add --cpu to zsh completion * Add --gc to zsh completion * Add --os to zsh completion * Add --panics to zsh completion * Add --verbosity to zsh completion * Add --hints to zsh completion * Update tools/nim.zsh-completion Co-authored-by: Juan Carlos * Update tools/nim.zsh-completion Co-authored-by: Andreas Rumpf --- tools/nim.zsh-completion | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tools/nim.zsh-completion b/tools/nim.zsh-completion index 38ed93f73..f7aeb72c6 100644 --- a/tools/nim.zsh-completion +++ b/tools/nim.zsh-completion @@ -68,6 +68,80 @@ _nim() { '*--app=gui[generate a GUI app]' \ '*--app=lib[generate a dynamic library]' \ '*--app=staticlib[generate a static library]' \ + '*--cpu=alpha[compile for Alpha architecture]' \ + '*--cpu=amd64[compile for x86_64 architecture]' \ + '*--cpu=arm[compile for ARM architecture]' \ + '*--cpu=arm64[compile for ARM64 architecture]' \ + '*--cpu=avr[compile for AVR architecture]' \ + '*--cpu=esp[compile for ESP architecture]' \ + '*--cpu=hppa[compile for HPPA architecture]' \ + '*--cpu=i386[compile for i386 architecture]' \ + '*--cpu=ia64[compile for ia64 architecture]' \ + '*--cpu=js[compile to JavaScript]' \ + '*--cpu=m68k[compile for m68k architecture]' \ + '*--cpu=mips[compile for MIPS architecture]' \ + '*--cpu=mipsel[compile for MIPS EL architecture]' \ + '*--cpu=mips64[compile for MIPS64 architecture]' \ + '*--cpu=mips64el[compile for MIPS64 EL architecture]' \ + '*--cpu=msp430[compile for msp430 architecture]' \ + '*--cpu=nimvm[compile for Nim VM]' \ + '*--cpu=powerpc[compile for PowerPC architecture]' \ + '*--cpu=powerpc64[compile for PowerPC64 architecture]' \ + '*--cpu=powerpc64el[compile for PowerPC64 EL architecture]' \ + '*--cpu=riscv32[compile for RISC-V 32 architecture]' \ + '*--cpu=riscv64[compile for RISC-V 64 architecture]' \ + '*--cpu=sparc[compile for SPARC architecture]' \ + '*--cpu=sparc64[compile for SPARC64 architecture]' \ + '*--cpu=vm[compile for Nim VM]' \ + '*--cpu=wasm32[compile to WASM 32]' \ + '*--gc=refc[use reference counting garbage collection]' \ + '*--gc=arc[use ARC garbage collection]' \ + '*--gc=orc[use ORC garbage collection]' \ + '*--gc=markAndSweep[use mark-and-sweep garbage collection]' \ + '*--gc=boehm[use Boehm garbage collection]' \ + '*--gc=go[use Go garbage collection]' \ + '*--gc=regions[use region-based memory management]' \ + '*--gc=none[disable garbage collection]' \ + '*--os=Standalone[generate a stand-alone executable]' \ + '*--os=AIX[compile for AIX]' \ + '*--os=Amiga[compile for Amiga OS]' \ + '*--os=Android[compile for Android]' \ + '*--os=Any[compile for any OS]' \ + '*--os=Atari[compile for Atari]' \ + '*--os=DOS[compile for DOS]' \ + '*--os=DragonFly[compile for DragonFly]' \ + '*--os=FreeBSD[compile for FreeBSD]' \ + '*--os=FreeRTOS[compile for FreeRTOS]' \ + '*--os=Genode[compile for Genode]' \ + '*--os=Haiku[compile for Haiku]' \ + '*--os=iOS[compile for iOS]' \ + '*--os=Irix[compile for Irix]' \ + '*--os=Linux[compile for Linux]' \ + '*--os=MacOS[compile for MacOS]' \ + '*--os=MacOSX[compile for MacOSX]' \ + '*--os=MorphOS[compile for MorphOS]' \ + '*--os=NetBSD[compile for NetBSD]' \ + '*--os=Netware[compile for Netware]' \ + '*--os=NimVM[compile for NimVM]' \ + '*--os=NintendoSwitch[compile for NintendoSwitch]' \ + '*--os=OS2[compile for OS2]' \ + '*--os=OpenBSD[compile for OpenBSD]' \ + '*--os=PalmOS[compile for PalmOS]' \ + '*--os=QNX[compile for QNX]' \ + '*--os=SkyOS[compile for SkyOS]' \ + '*--os=Solaris[compile for Solaris]' \ + '*--os=VxWorks[compile for VxWorks]' \ + '*--os=Windows[compile for Windows]' \ + '*--os=JS[generate javascript]' \ + '*--panics=off[turn panics into process terminations: off by default]' \ + '*--panics=on[turn panics into process terminations]' \ + '*--verbosity=0[set verbosity to 0]' \ + '*--verbosity=1[set verbosity to 1 (default)]' \ + '*--verbosity=2[set verbosity to 2]' \ + '*--verbosity=3[set verbosity to 3]' \ + '*--hints=on[print compilation hints]' \ + '*--hints=off[disable compilation hints]' \ + '*--hints=list[print compilation hints list]' \ ':filename:_files -g"*.nim"' } From 87e634aab3182d6e9022f108bd6936a58682f01c Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Wed, 9 Dec 2020 16:17:50 +0100 Subject: [PATCH 1638/4254] rationals.nim: Use `func` everywhere (#16302) --- lib/pure/rationals.nim | 82 ++++++++++++++++----------------- tests/effects/tstrict_funcs.nim | 1 + 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 38a88ebc3..2a1a97d3b 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -18,28 +18,28 @@ type Rational*[T] = object ## a rational number, consisting of a numerator and denominator num*, den*: T -proc initRational*[T: SomeInteger](num, den: T): Rational[T] = +func initRational*[T: SomeInteger](num, den: T): Rational[T] = ## Create a new rational number. assert(den != 0, "a denominator of zero value is invalid") result.num = num result.den = den -proc `//`*[T](num, den: T): Rational[T] = initRational[T](num, den) +func `//`*[T](num, den: T): Rational[T] = initRational[T](num, den) ## A friendlier version of `initRational`. Example usage: ## ## .. code-block:: nim ## var x = 1//3 + 1//5 -proc `$`*[T](x: Rational[T]): string = +func `$`*[T](x: Rational[T]): string = ## Turn a rational number into a string. result = $x.num & "/" & $x.den -proc toRational*[T: SomeInteger](x: T): Rational[T] = +func toRational*[T: SomeInteger](x: T): Rational[T] = ## Convert some integer `x` to a rational number. result.num = x result.den = 1 -proc toRational*(x: float, +func toRational*(x: float, n: int = high(int) shr (sizeof(int) div 2 * 8)): Rational[int] = ## Calculates the best rational numerator and denominator ## that approximates to `x`, where the denominator is @@ -74,16 +74,16 @@ proc toRational*(x: float, ai = int(x) result = m11 // m21 -proc toFloat*[T](x: Rational[T]): float = +func toFloat*[T](x: Rational[T]): float = ## Convert a rational number `x` to a float. x.num / x.den -proc toInt*[T](x: Rational[T]): int = +func toInt*[T](x: Rational[T]): int = ## Convert a rational number `x` to an int. Conversion rounds towards 0 if ## `x` does not contain an integer value. x.num div x.den -proc reduce*[T: SomeInteger](x: var Rational[T]) = +func reduce*[T: SomeInteger](x: var Rational[T]) = ## Reduce rational `x`. let common = gcd(x.num, x.den) if x.den > 0: @@ -95,97 +95,97 @@ proc reduce*[T: SomeInteger](x: var Rational[T]) = else: raise newException(DivByZeroDefect, "division by zero") -proc `+` *[T](x, y: Rational[T]): Rational[T] = +func `+` *[T](x, y: Rational[T]): Rational[T] = ## Add two rational numbers. let common = lcm(x.den, y.den) result.num = common div x.den * x.num + common div y.den * y.num result.den = common reduce(result) -proc `+` *[T](x: Rational[T], y: T): Rational[T] = +func `+` *[T](x: Rational[T], y: T): Rational[T] = ## Add rational `x` to int `y`. result.num = x.num + y * x.den result.den = x.den -proc `+` *[T](x: T, y: Rational[T]): Rational[T] = +func `+` *[T](x: T, y: Rational[T]): Rational[T] = ## Add int `x` to rational `y`. result.num = x * y.den + y.num result.den = y.den -proc `+=` *[T](x: var Rational[T], y: Rational[T]) = +func `+=` *[T](x: var Rational[T], y: Rational[T]) = ## Add rational `y` to rational `x`. let common = lcm(x.den, y.den) x.num = common div x.den * x.num + common div y.den * y.num x.den = common reduce(x) -proc `+=` *[T](x: var Rational[T], y: T) = +func `+=` *[T](x: var Rational[T], y: T) = ## Add int `y` to rational `x`. x.num += y * x.den -proc `-` *[T](x: Rational[T]): Rational[T] = +func `-` *[T](x: Rational[T]): Rational[T] = ## Unary minus for rational numbers. result.num = -x.num result.den = x.den -proc `-` *[T](x, y: Rational[T]): Rational[T] = +func `-` *[T](x, y: Rational[T]): Rational[T] = ## Subtract two rational numbers. let common = lcm(x.den, y.den) result.num = common div x.den * x.num - common div y.den * y.num result.den = common reduce(result) -proc `-` *[T](x: Rational[T], y: T): Rational[T] = +func `-` *[T](x: Rational[T], y: T): Rational[T] = ## Subtract int `y` from rational `x`. result.num = x.num - y * x.den result.den = x.den -proc `-` *[T](x: T, y: Rational[T]): Rational[T] = +func `-` *[T](x: T, y: Rational[T]): Rational[T] = ## Subtract rational `y` from int `x`. result.num = x * y.den - y.num result.den = y.den -proc `-=` *[T](x: var Rational[T], y: Rational[T]) = +func `-=` *[T](x: var Rational[T], y: Rational[T]) = ## Subtract rational `y` from rational `x`. let common = lcm(x.den, y.den) x.num = common div x.den * x.num - common div y.den * y.num x.den = common reduce(x) -proc `-=` *[T](x: var Rational[T], y: T) = +func `-=` *[T](x: var Rational[T], y: T) = ## Subtract int `y` from rational `x`. x.num -= y * x.den -proc `*` *[T](x, y: Rational[T]): Rational[T] = +func `*` *[T](x, y: Rational[T]): Rational[T] = ## Multiply two rational numbers. result.num = x.num * y.num result.den = x.den * y.den reduce(result) -proc `*` *[T](x: Rational[T], y: T): Rational[T] = +func `*` *[T](x: Rational[T], y: T): Rational[T] = ## Multiply rational `x` with int `y`. result.num = x.num * y result.den = x.den reduce(result) -proc `*` *[T](x: T, y: Rational[T]): Rational[T] = +func `*` *[T](x: T, y: Rational[T]): Rational[T] = ## Multiply int `x` with rational `y`. result.num = x * y.num result.den = y.den reduce(result) -proc `*=` *[T](x: var Rational[T], y: Rational[T]) = +func `*=` *[T](x: var Rational[T], y: Rational[T]) = ## Multiply rationals `y` to `x`. x.num *= y.num x.den *= y.den reduce(x) -proc `*=` *[T](x: var Rational[T], y: T) = +func `*=` *[T](x: var Rational[T], y: T) = ## Multiply int `y` to rational `x`. x.num *= y reduce(x) -proc reciprocal*[T](x: Rational[T]): Rational[T] = +func reciprocal*[T](x: Rational[T]): Rational[T] = ## Calculate the reciprocal of `x`. (1/x) if x.num > 0: result.num = x.den @@ -196,63 +196,63 @@ proc reciprocal*[T](x: Rational[T]): Rational[T] = else: raise newException(DivByZeroDefect, "division by zero") -proc `/`*[T](x, y: Rational[T]): Rational[T] = +func `/`*[T](x, y: Rational[T]): Rational[T] = ## Divide rationals `x` by `y`. result.num = x.num * y.den result.den = x.den * y.num reduce(result) -proc `/`*[T](x: Rational[T], y: T): Rational[T] = +func `/`*[T](x: Rational[T], y: T): Rational[T] = ## Divide rational `x` by int `y`. result.num = x.num result.den = x.den * y reduce(result) -proc `/`*[T](x: T, y: Rational[T]): Rational[T] = +func `/`*[T](x: T, y: Rational[T]): Rational[T] = ## Divide int `x` by Rational `y`. result.num = x * y.den result.den = y.num reduce(result) -proc `/=`*[T](x: var Rational[T], y: Rational[T]) = +func `/=`*[T](x: var Rational[T], y: Rational[T]) = ## Divide rationals `x` by `y` in place. x.num *= y.den x.den *= y.num reduce(x) -proc `/=`*[T](x: var Rational[T], y: T) = +func `/=`*[T](x: var Rational[T], y: T) = ## Divide rational `x` by int `y` in place. x.den *= y reduce(x) -proc cmp*(x, y: Rational): int = +func cmp*(x, y: Rational): int = ## Compares two rationals. (x - y).num -proc `<` *(x, y: Rational): bool = +func `<` *(x, y: Rational): bool = (x - y).num < 0 -proc `<=` *(x, y: Rational): bool = +func `<=` *(x, y: Rational): bool = (x - y).num <= 0 -proc `==` *(x, y: Rational): bool = +func `==` *(x, y: Rational): bool = (x - y).num == 0 -proc abs*[T](x: Rational[T]): Rational[T] = +func abs*[T](x: Rational[T]): Rational[T] = result.num = abs x.num result.den = abs x.den -proc `div`*[T: SomeInteger](x, y: Rational[T]): T = +func `div`*[T: SomeInteger](x, y: Rational[T]): T = ## Computes the rational truncated division. (x.num * y.den) div (y.num * x.den) -proc `mod`*[T: SomeInteger](x, y: Rational[T]): Rational[T] = +func `mod`*[T: SomeInteger](x, y: Rational[T]): Rational[T] = ## Computes the rational modulo by truncated division (remainder). ## This is same as ``x - (x div y) * y``. result = ((x.num * y.den) mod (y.num * x.den)) // (x.den * y.den) reduce(result) -proc floorDiv*[T: SomeInteger](x, y: Rational[T]): T = +func floorDiv*[T: SomeInteger](x, y: Rational[T]): T = ## Computes the rational floor division. ## ## Floor division is conceptually defined as ``floor(x / y)``. @@ -261,15 +261,15 @@ proc floorDiv*[T: SomeInteger](x, y: Rational[T]): T = ## rounds down. floorDiv(x.num * y.den, y.num * x.den) -proc floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] = +func floorMod*[T: SomeInteger](x, y: Rational[T]): Rational[T] = ## Computes the rational modulo by floor division (modulo). ## ## This is same as ``x - floorDiv(x, y) * y``. - ## This proc behaves the same as the ``%`` operator in python. + ## This func behaves the same as the ``%`` operator in python. result = floorMod(x.num * y.den, y.num * x.den) // (x.den * y.den) reduce(result) -proc hash*[T](x: Rational[T]): Hash = +func hash*[T](x: Rational[T]): Hash = ## Computes hash for rational `x` # reduce first so that hash(x) == hash(y) for x == y var copy = x diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 7a0f1ee32..d30326123 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -10,6 +10,7 @@ import httpcore, math, nre, + rationals, sequtils, strutils, uri From f344a704123a4b55e2b3b8a4f736a6739d0683bb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 9 Dec 2020 07:19:39 -0800 Subject: [PATCH 1639/4254] fix #16150 improve type mismatch errors (#16152) * fix #16150 improve type mismatch errors * allow -d:nimLegacyTypeMismatch * address comment --- changelog.md | 2 ++ compiler/sem.nim | 2 +- compiler/semcall.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/semfields.nim | 5 +++-- compiler/types.nim | 7 +++++-- tests/config.nims | 1 + 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index bb49dc7f6..0e96c868a 100644 --- a/changelog.md +++ b/changelog.md @@ -77,6 +77,8 @@ - Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`. - VM now supports `addr(mystring[ind])` (index + index assignment) +- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous + behavior. ## Tool changes diff --git a/compiler/sem.nim b/compiler/sem.nim index f90d9e1f9..0fec8b7e3 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -96,7 +96,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: result = indexTypesMatch(c, formal, arg.typ, arg) if result == nil: - typeMismatch(c.config, info, formal, arg.typ) + typeMismatch(c.config, info, formal, arg.typ, arg) # error correction: result = copyTree(arg) result.typ = formal diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 70a7e099c..1e8da0298 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -476,7 +476,7 @@ proc inferWithMetatype(c: PContext, formal: PType, result.typ = generateTypeInstance(c, m.bindings, arg.info, formal.skipTypes({tyCompositeTypeClass})) else: - typeMismatch(c.config, arg.info, formal, arg.typ) + typeMismatch(c.config, arg.info, formal, arg.typ, arg) # error correction: result = copyTree(arg) result.typ = formal diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8728af27c..3bbf353b1 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1745,7 +1745,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = c.p.resultSym.typ = rhsTyp c.p.owner.typ[0] = rhsTyp else: - typeMismatch(c.config, n.info, lhs.typ, rhsTyp) + typeMismatch(c.config, n.info, lhs.typ, rhsTyp, rhs) borrowCheck(c, n, lhs, rhs) n[1] = fitNode(c, le, rhs, goodLineInfo(n[1])) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index d7563e33f..602a7199d 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -127,9 +127,10 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = localError(c.config, n.info, errGenerated, "no object or tuple type") return result for i in 1.." % actualStr + if conf.isDefined("nimLegacyTypeMismatch"): + msg.add " got <$1>" % actualStr + else: + msg.add " got '$1' for '$2'" % [actualStr, n.renderTree] if verbose: msg.addDeclaredLoc(conf, actual) msg.add "\n" diff --git a/tests/config.nims b/tests/config.nims index 640df9cad..ac5e019f5 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -8,3 +8,4 @@ switch("path", "$lib/../testament/lib") switch("colors", "off") switch("listFullPaths", "off") switch("excessiveStackTrace", "off") +switch("define", "nimLegacyTypeMismatch") From 82bb4db4b72e4ca61e2853755fd8ed8527c1a42a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 9 Dec 2020 15:57:52 -0800 Subject: [PATCH 1640/4254] unittest: use defines instead of env vars (#16165) * unittest: use defines instead of env vars * use defines in testament * fixup Co-authored-by: Andreas Rumpf --- lib/pure/unittest.nim | 90 +++++++++++++++++++++++--------------- testament/testament.nim | 3 -- tests/config.nims | 5 +++ tests/js/tunittests.nim | 13 ------ tests/stdlib/ttimes.nim | 6 --- tests/stdlib/tunittest.nim | 1 + 6 files changed, 61 insertions(+), 57 deletions(-) delete mode 100644 tests/js/tunittests.nim diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index c0b2e7c1e..ab45f78dc 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -139,21 +139,19 @@ type ConsoleOutputFormatter* = ref object of OutputFormatter colorOutput: bool ## Have test results printed in color. - ## Default is true for the non-js target, - ## for which ``stdout`` is a tty. - ## Setting the environment variable - ## ``NIMTEST_COLOR`` to ``always`` or - ## ``never`` changes the default for the - ## non-js target to true or false respectively. - ## The deprecated environment variable - ## ``NIMTEST_NO_COLOR``, when set, - ## changes the default to true, if - ## ``NIMTEST_COLOR`` is undefined. + ## Default is `auto` depending on `isatty(stdout)`, or override it with + ## `-d:nimUnittestColor:auto|on|off`. + ## + ## Deprecated: Setting the environment variable `NIMTEST_COLOR` to `always` + ## or `never` changes the default for the non-js target to true or false respectively. + ## Deprecated: the environment variable `NIMTEST_NO_COLOR`, when set, changes the + ## default to true, if `NIMTEST_COLOR` is undefined. outputLevel: OutputLevel ## Set the verbosity of test results. - ## Default is ``PRINT_ALL``, unless - ## the ``NIMTEST_OUTPUT_LVL`` environment - ## variable is set for the non-js target. + ## Default is `PRINT_ALL`, or override with: + ## `-d:nimUnittestOutputLevel:PRINT_ALL|PRINT_FAILURES|PRINT_NONE`. + ## + ## Deprecated: the `NIMTEST_OUTPUT_LVL` environment variable is set for the non-js target. isInSuite: bool isInTest: bool @@ -166,17 +164,31 @@ type var abortOnError* {.threadvar.}: bool ## Set to true in order to quit ## immediately on fail. Default is false, - ## unless the ``NIMTEST_ABORT_ON_ERROR`` - ## environment variable is set for - ## the non-js target. + ## or override with `-d:nimUnittestAbortOnError:on|off`. + ## + ## Deprecated: can also override depending on whether + ## `NIMTEST_ABORT_ON_ERROR` environment variable is set. checkpoints {.threadvar.}: seq[string] formatters {.threadvar.}: seq[OutputFormatter] testsFilters {.threadvar.}: HashSet[string] disabledParamFiltering {.threadvar.}: bool +const + outputLevelDefault = PRINT_ALL + nimUnittestOutputLevel {.strdefine.} = $outputLevelDefault + nimUnittestColor {.strdefine.} = "auto" ## auto|on|off + nimUnittestAbortOnError {.booldefine.} = false + +template deprecateEnvVarHere() = + # xxx issue a runtime warning to deprecate this envvar. + discard + +abortOnError = nimUnittestAbortOnError when declared(stdout): - abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") + if existsEnv("NIMTEST_ABORT_ON_ERROR"): + deprecateEnvVarHere() + abortOnError = true method suiteStarted*(formatter: OutputFormatter, suiteName: string) {.base, gcsafe.} = discard @@ -202,36 +214,44 @@ proc delOutputFormatter*(formatter: OutputFormatter) = proc resetOutputFormatters* {.since: (1, 1).} = formatters = @[] -proc newConsoleOutputFormatter*(outputLevel: OutputLevel = OutputLevel.PRINT_ALL, +proc newConsoleOutputFormatter*(outputLevel: OutputLevel = outputLevelDefault, colorOutput = true): ConsoleOutputFormatter = ConsoleOutputFormatter( outputLevel: outputLevel, colorOutput: colorOutput ) -proc defaultConsoleFormatter*(): ConsoleOutputFormatter = +proc colorOutput(): bool = + let color = nimUnittestColor + case color + of "auto": + when declared(stdout): result = isatty(stdout) + else: result = false + of "on": result = true + of "off": result = false + else: doAssert false, $color + when declared(stdout): - # Reading settings - # On a terminal this branch is executed - var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string - var colorOutput = isatty(stdout) if existsEnv("NIMTEST_COLOR"): + deprecateEnvVarHere() let colorEnv = getEnv("NIMTEST_COLOR") if colorEnv == "never": - colorOutput = false + result = false elif colorEnv == "always": - colorOutput = true + result = true elif existsEnv("NIMTEST_NO_COLOR"): - colorOutput = false - var outputLevel = OutputLevel.PRINT_ALL - if envOutLvl.len > 0: - for opt in countup(low(OutputLevel), high(OutputLevel)): - if $opt == envOutLvl: - outputLevel = opt - break - result = newConsoleOutputFormatter(outputLevel, colorOutput) - else: - result = newConsoleOutputFormatter() + deprecateEnvVarHere() + result = false + +proc defaultConsoleFormatter*(): ConsoleOutputFormatter = + var colorOutput = colorOutput() + var outputLevel = nimUnittestOutputLevel.parseEnum[:OutputLevel] + when declared(stdout): + const a = "NIMTEST_OUTPUT_LVL" + if existsEnv(a): + # xxx issue a warning to deprecate this envvar. + outputLevel = getEnv(a).parseEnum[:OutputLevel] + result = newConsoleOutputFormatter(outputLevel, colorOutput) method suiteStarted*(formatter: ConsoleOutputFormatter, suiteName: string) = template rawPrint() = echo("\n[Suite] ", suiteName) diff --git a/testament/testament.nim b/testament/testament.nim index 58b3a8040..a301b018c 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -661,9 +661,6 @@ proc loadSkipFrom(name: string): seq[string] = result.add sline proc main() = - os.putEnv "NIMTEST_COLOR", "never" - os.putEnv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" - azure.init() backend.open() var optPrintResults = false diff --git a/tests/config.nims b/tests/config.nims index ac5e019f5..e0b8502ee 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -8,4 +8,9 @@ switch("path", "$lib/../testament/lib") switch("colors", "off") switch("listFullPaths", "off") switch("excessiveStackTrace", "off") + +# for std/unittest +switch("define", "nimUnittestOutputLevel:PRINT_FAILURES") +switch("define", "nimUnittestColor:off") + switch("define", "nimLegacyTypeMismatch") diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim deleted file mode 100644 index 0d934a82b..000000000 --- a/tests/js/tunittests.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: ''' - -[Suite] Bacon - [OK] >:) -''' -""" - -import unittest - -suite "Bacon": - test ">:)": - check(true == true) diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index e6305b2d0..4d89ffa1a 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -7,12 +7,6 @@ import times, strutils, unittest when not defined(js): import os -# Normally testament configures unittest with environment variables, -# but that doesn't work for the JS target. So instead we must set the correct -# settings here. -addOutputFormatter( - newConsoleOutputFormatter(PRINT_FAILURES, colorOutput = false)) - proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} = let offset = hours * 3600 + minutes * 60 + seconds diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 8e82a0c97..4b82df67b 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -19,6 +19,7 @@ discard """ [Suite] test name filtering ''' +targets: "c js" """ import unittest, sequtils From 73299b048f57838d83a3a8159909386a0905e553 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 10 Dec 2020 14:58:42 +0800 Subject: [PATCH 1641/4254] enable tests for random (#16297) --- tests/stdlib/trandom.nim | 73 ++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index c7c6a3f56..f8797944e 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -1,59 +1,66 @@ discard """ - action: compile + joinable: false + targets: "c js" """ -import random +import std/[random, stats] + +randomize(233) proc main = var occur: array[1000, int] - var x = 8234 for i in 0..100_000: - x = rand(high(occur)) + let x = rand(high(occur)) inc occur[x] - for i, oc in occur: - if oc < 69: - doAssert false, "too few occurrences of " & $i - elif oc > 150: - doAssert false, "too many occurrences of " & $i - when false: - var rs: RunningStat - for j in 1..5: - for i in 1 .. 1_000: - rs.push(gauss()) - echo("mean: ", rs.mean, - " stdDev: ", rs.standardDeviation(), - " min: ", rs.min, - " max: ", rs.max) - rs.clear() + doAssert max(occur) <= 140 and min(occur) >= 60 # gives some slack var a = [0, 1] shuffle(a) - doAssert a[0] == 1 - doAssert a[1] == 0 + doAssert a in [[0,1], [1,0]] doAssert rand(0) == 0 doAssert sample("a") == 'a' when compileOption("rangeChecks"): - try: + doAssertRaises(RangeDefect): discard rand(-1) - doAssert false - except RangeDefect: - discard - try: + doAssertRaises(RangeDefect): discard rand(-1.0) - doAssert false - except RangeDefect: - discard - # don't use causes integer overflow doAssert compiles(rand[int](low(int) .. high(int))) -randomize(223) -for i in 0 .. 10: - main() +main() + +import math + +block: + when not defined(js): + doAssert almostEqual(rand(12.5), 4.012897747078944) + doAssert almostEqual(rand(2233.3322), 879.702755321298) + + type DiceRoll = range[0..6] + doAssert rand(DiceRoll).int == 4 + +var rs: RunningStat +for j in 1..5: + for i in 1 .. 100_000: + rs.push(gauss()) + doAssert abs(rs.mean-0) < 0.08, $rs.mean + doAssert abs(rs.standardDeviation()-1.0) < 0.1 + let bounds = [3.5, 5.0] + for a in [rs.max, -rs.min]: + doAssert a >= bounds[0] and a <= bounds[1] + rs.clear() + +block: + type DiceRoll = range[3..6] + var flag = false + for i in 0..<100: + if rand(5.DiceRoll) < 3: + flag = true + doAssert flag # because of: rand(max: int): int From 1a07f572f4871244efb657ff5ebcb27636a0b18e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 10 Dec 2020 15:24:44 -0800 Subject: [PATCH 1642/4254] unbreak CI, disable fidget, refs #16315 (#16316) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 2da10e749..361ecaa88 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -37,7 +37,7 @@ pkg1 "delaunay" pkg1 "docopt" pkg1 "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg1 "elvis" -pkg1 "fidget" +# pkg1 "fidget" # pending bug #16315 and https://github.com/guzba/supersnappy/issues/3 pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "glob" From bc84bd5d66e62c0e39ed781ddeb6a03e6d4163b2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 11 Dec 2020 13:02:43 +0800 Subject: [PATCH 1643/4254] bring back fidget (#16319) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 361ecaa88..2da10e749 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -37,7 +37,7 @@ pkg1 "delaunay" pkg1 "docopt" pkg1 "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg1 "elvis" -# pkg1 "fidget" # pending bug #16315 and https://github.com/guzba/supersnappy/issues/3 +pkg1 "fidget" pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "glob" From bb1c962286922487c5243ca7304fd95fdd27ea53 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 11 Dec 2020 01:35:05 -0800 Subject: [PATCH 1644/4254] fix partially #13115 (now works for cpp; but still fails for js on openbsd) (#16167) * fix partially #13115 properly (works for c,js,cpp,vm; still fails for js on openbsd) * address comment: also test with -d:danger, -d:debug --- lib/system/excpt.nim | 32 +++++++++++++++++--------- tests/exception/t13115.nim | 46 +++++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index f73a88e30..aec25e3f3 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -13,6 +13,8 @@ import std/private/miscdollars import stacktraces +const noStacktraceAvailable = "No stack traceback available\n" + var errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign, nimcall.}) @@ -36,6 +38,10 @@ else: proc writeToStdErr(msg: cstring, length: int) = discard MessageBoxA(nil, msg, nil, 0) +proc writeToStdErr(msg: string) {.inline.} = + # fix bug #13115: handles correctly '\0' unlike default implicit conversion to cstring + writeToStdErr(msg.cstring, msg.len) + proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = var toWrite = true if errorMessageWriter != nil: @@ -51,6 +57,9 @@ proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = else: writeToStdErr(data, length) +proc showErrorMessage2(data: string) {.inline.} = + showErrorMessage(data.cstring, data.len) + proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.} proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.} proc chckRangeF(x, a, b: float): float {.inline, compilerproc, benign.} @@ -123,11 +132,11 @@ proc popSafePoint {.compilerRtl, inl.} = proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} = e.up = currException currException = e - #showErrorMessage "A" + #showErrorMessage2 "A" proc popCurrentException {.compilerRtl, inl.} = currException = currException.up - #showErrorMessage "B" + #showErrorMessage2 "B" proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = discard "only for bootstrapping compatbility" @@ -305,7 +314,7 @@ when hasSomeStackTrace: auxWriteStackTraceWithOverride(s) elif NimStackTrace: if framePtr == nil: - add(s, "No stack traceback available\n") + add(s, noStacktraceAvailable) else: add(s, "Traceback (most recent call last)\n") auxWriteStackTrace(framePtr, s) @@ -313,7 +322,7 @@ when hasSomeStackTrace: add(s, "Traceback from system (most recent call last)\n") auxWriteStackTraceWithBacktrace(s) else: - add(s, "No stack traceback available\n") + add(s, noStacktraceAvailable) proc rawWriteStackTrace(s: var seq[StackTraceEntry]) = when defined(nimStackTraceOverride): @@ -363,7 +372,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = if onUnhandledException != nil: onUnhandledException(buf) else: - showErrorMessage(buf, buf.len) + showErrorMessage2(buf) `=destroy`(buf) else: # ugly, but avoids heap allocations :-) @@ -504,16 +513,16 @@ proc writeStackTrace() = when hasSomeStackTrace: var s = "" rawWriteStackTrace(s) - cast[proc (s: cstring, length: int) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)(s, s.len) else: - cast[proc (s: cstring, length: int) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)("No stack traceback available\n", 32) + let s = noStacktraceAvailable + cast[proc (s: string) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage2)(s) proc getStackTrace(): string = when hasSomeStackTrace: result = "" rawWriteStackTrace(result) else: - result = "No stack traceback available\n" + result = noStacktraceAvailable proc getStackTrace(e: ref Exception): string = if not isNil(e): @@ -543,7 +552,7 @@ proc callDepthLimitReached() {.noinline.} = $nimCallDepthLimit & " function calls). You can change it with " & "-d:nimCallDepthLimit= but really try to avoid deep " & "recursions instead.\n" - showErrorMessage(msg, msg.len) + showErrorMessage2(msg) quit(1) proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = @@ -627,13 +636,16 @@ when not defined(noSignalHandler) and not defined(useNimRtl): var buf = newStringOfCap(2000) rawWriteStackTrace(buf) processSignal(sign, buf.add) # nice hu? currying a la Nim :-) - showErrorMessage(buf, buf.len) + showErrorMessage2(buf) when not usesDestructors: GC_enable() else: var msg: cstring template asgn(y) = msg = y processSignal(sign, asgn) + # xxx use string for msg instead of cstring, and here use showErrorMessage2(msg) + # unless there's a good reason to use cstring in signal handler to avoid + # using gc? showErrorMessage(msg, msg.len) quit(1) # always quit when SIGABRT diff --git a/tests/exception/t13115.nim b/tests/exception/t13115.nim index 53e078076..ee1daed26 100644 --- a/tests/exception/t13115.nim +++ b/tests/exception/t13115.nim @@ -1,12 +1,38 @@ -discard """ - exitcode: 1 - targets: "c" - matrix: "-d:debug; -d:release" - outputsub: ''' and works fine! [Exception]''' -""" +const msg = "This char is `" & '\0' & "` and works fine!" -# bug #13115 -# xxx bug: doesn't yet work for cpp +when defined nim_t13115: + # bug #13115 + template fn = + raise newException(Exception, msg) + when defined nim_t13115_static: + static: fn() + fn() +else: + import std/[osproc,strformat,os,strutils] + proc main = + const nim = getCurrentCompilerExe() + const file = currentSourcePath + for b in "c js cpp".split: + when defined(openbsd): + if b == "js": + # xxx bug: pending #13115 + # remove special case once nodejs updated >= 12.16.2 + # refs https://github.com/nim-lang/Nim/pull/16167#issuecomment-738270751 + continue -var msg = "This char is `" & '\0' & "` and works fine!" -raise newException(Exception, msg) + # save CI time by avoiding mostly redundant combinations as far as this bug is concerned + var opts = case b + of "c": @["", "-d:nim_t13115_static", "-d:danger", "-d:debug"] + of "js": @["", "-d:nim_t13115_static"] + else: @[""] + + for opt in opts: + let cmd = fmt"{nim} r -b:{b} -d:nim_t13115 {opt} --hints:off {file}" + let (outp, exitCode) = execCmdEx(cmd) + when defined windows: + # `\0` not preserved on windows + doAssert "` and works fine!" in outp, cmd & "\n" & msg + else: + doAssert msg in outp, cmd & "\n" & msg + doAssert exitCode == 1 + main() From 0b73106ccf983565d34654ee8b1167827b53b01a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 11 Dec 2020 02:01:43 -0800 Subject: [PATCH 1645/4254] add math.isNaN (#16179) * add math.isNaN * isNaN now works with --passc:-ffast-math; tests * Update lib/pure/math.nim Co-authored-by: Andreas Rumpf --- changelog.md | 2 ++ lib/js/dom.nim | 1 + lib/pure/math.nim | 21 +++++++++++++++++++++ tests/stdlib/tmath.nim | 31 ++++++++++++++++++++++++++----- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 0e96c868a..ab323337c 100644 --- a/changelog.md +++ b/changelog.md @@ -58,6 +58,8 @@ - `strscans.scanf` now supports parsing single characters. +- Added `math.isNaN`. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/js/dom.nim b/lib/js/dom.nim index b73a85291..b74a58a1a 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1683,6 +1683,7 @@ proc decodeURIComponent*(uri: cstring): cstring {.importc, nodecl.} proc encodeURIComponent*(uri: cstring): cstring {.importc, nodecl.} proc isFinite*(x: BiggestFloat): bool {.importc, nodecl.} proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.} + ## see also `math.isNaN`. proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.} diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b2433d309..5f3261f1a 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -58,6 +58,10 @@ import std/private/since import bitops, fenv +when defined(c) or defined(cpp): + proc c_isnan(x: float): bool {.importc: "isnan", header: "".} + # a generic like `x: SomeFloat` might work too if this is implemented via a C macro. + func binom*(n, k: int): int = ## Computes the `binomial coefficient `_. runnableExamples: @@ -133,10 +137,27 @@ type fcInf, ## value is positive infinity fcNegInf ## value is negative infinity +func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = + ## Returns whether `x` is a `NaN`, more efficiently than via `classify(x) == fcNan`. + ## Works even with: `--passc:-ffast-math`. + runnableExamples: + doAssert NaN.isNaN + doAssert not Inf.isNaN + doAssert isNaN(Inf - Inf) + doAssert not isNan(3.1415926) + doAssert not isNan(0'f32) + + template fn: untyped = result = x != x + when nimvm: fn() + else: + when defined(js): fn() + else: result = c_isnan(x) + func classify*(x: float): FloatClass = ## Classifies a floating point value. ## ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_. + ## Doesn't work with: `--passc:-ffast-math`. runnableExamples: doAssert classify(0.3) == fcNormal doAssert classify(0.0) == fcZero diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index ac5ce4c90..18e42cbdc 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -12,8 +12,11 @@ discard """ [Suite] ^ ''' +matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" """ +# xxx: fix bugs for js then add: targets:"c js" + import math, random, os import unittest import sets, tables @@ -37,12 +40,16 @@ suite "random int": var rand: int for i in 1..1000: rand = rand(100..1000) - check rand < 1000 + when defined(js): # xxx bug: otherwise fails + check rand <= 1000 + else: + check rand < 1000 check rand >= 100 test " again gives new numbers": var rand1 = rand(1000000) - os.sleep(200) + when not defined(js): + os.sleep(200) var rand2 = rand(1000000) check rand1 != rand2 @@ -72,7 +79,8 @@ suite "random float": test " again gives new numbers": var rand1:float = rand(1000000.0) - os.sleep(200) + when not defined(js): + os.sleep(200) var rand2:float = rand(1000000.0) check rand1 != rand2 @@ -151,6 +159,7 @@ block: when not defined(js): # Check for no side effect annotation proc mySqrt(num: float): float {.noSideEffect.} = + # xxx unused return sqrt(num) # check gamma function @@ -194,7 +203,8 @@ block: #special case doAssert(classify(trunc(1e1000000)) == fcInf) doAssert(classify(trunc(-1e1000000)) == fcNegInf) - doAssert(classify(trunc(0.0/0.0)) == fcNan) + when not defined(nimTmathCase2): + doAssert(classify(trunc(0.0/0.0)) == fcNan) doAssert(classify(trunc(0.0)) == fcZero) #trick the compiler to produce signed zero @@ -211,7 +221,8 @@ block: doAssert(trunc(0.1'f32) == 0) doAssert(classify(trunc(1e1000000'f32)) == fcInf) doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf) - doAssert(classify(trunc(f_nan.float32)) == fcNan) + when not defined(nimTmathCase2): + doAssert(classify(trunc(f_nan.float32)) == fcNan) doAssert(classify(trunc(0.0'f32)) == fcZero) block: # sgn() tests @@ -272,3 +283,13 @@ block: doAssert log2(2.0'f32) == 1.0'f32 doAssert log2(1.0'f32) == 0.0'f32 doAssert classify(log2(0.0'f32)) == fcNegInf + +template main = + # xxx wrap all under `main` so it also gets tested in vm. + block: # isNaN + doAssert NaN.isNaN + doAssert not Inf.isNaN + doAssert isNaN(Inf - Inf) + +main() +static: main() From b1c232aca1baf7d9ccc6c7a86e9ac5a127bc2354 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 12 Dec 2020 00:33:29 -0800 Subject: [PATCH 1646/4254] improve tests for collections (#16328) * improve tests for collections * remove remaining code blocks in deques.nim * improve runnableExamples --- lib/pure/collections/deques.nim | 108 ++++++++++------------ tests/collections/tcollections.nim | 69 ++------------ tests/stdlib/tcritbits.nim | 18 ++++ tests/stdlib/tdeque.nim | 111 ----------------------- tests/stdlib/tdeques.nim | 139 +++++++++++++++++++++++++++++ tests/stdlib/tlists.nim | 24 ++++- 6 files changed, 227 insertions(+), 242 deletions(-) delete mode 100644 tests/stdlib/tdeque.nim create mode 100644 tests/stdlib/tdeques.nim diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 6df34bd3a..f6d0f945e 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -18,35 +18,32 @@ ## ## As such, a check to see if the deque is empty is needed before any ## access, unless your program logic guarantees it indirectly. -## -## .. code-block:: Nim -## import deques -## -## var a = initDeque[int]() -## -## doAssertRaises(IndexDefect, echo a[0]) -## -## for i in 1 .. 5: -## a.addLast(10*i) -## assert $a == "[10, 20, 30, 40, 50]" -## -## assert a.peekFirst == 10 -## assert a.peekLast == 50 -## assert len(a) == 5 -## -## assert a.popFirst == 10 -## assert a.popLast == 50 -## assert len(a) == 3 -## -## a.addFirst(11) -## a.addFirst(22) -## a.addFirst(33) -## assert $a == "[33, 22, 11, 20, 30, 40]" -## -## a.shrink(fromFirst = 1, fromLast = 2) -## assert $a == "[22, 11, 20]" -## -## + +runnableExamples: + var a = initDeque[int]() + + doAssertRaises(IndexDefect, echo a[0]) + + for i in 1 .. 5: + a.addLast(10*i) + assert $a == "[10, 20, 30, 40, 50]" + + assert a.peekFirst == 10 + assert a.peekLast == 50 + assert len(a) == 5 + + assert a.popFirst == 10 + assert a.popLast == 50 + assert len(a) == 3 + + a.addFirst(11) + a.addFirst(22) + a.addFirst(33) + assert $a == "[33, 22, 11, 20, 30, 40]" + + a.shrink(fromFirst = 1, fromLast = 2) + assert $a == "[22, 11, 20]" + ## **See also:** ## * `lists module `_ for singly and doubly linked lists and rings ## * `channels module `_ for inter-thread communication @@ -211,21 +208,14 @@ proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = iterator items*[T](deq: Deque[T]): T = ## Yields every element of `deq`. - ## - ## **Examples:** - ## - ## .. code-block:: - ## var a = initDeque[int]() - ## for i in 1 .. 3: - ## a.addLast(10*i) - ## - ## for x in a: # the same as: for x in items(a): - ## echo x - ## - ## # 10 - ## # 20 - ## # 30 - ## + runnableExamples: + var a = initDeque[int]() + for i in 1 .. 3: + a.addLast(10*i) + from sugar import collect + doAssert collect(for x in a: x) == [10, 20, 30] + # same as above: + doAssert collect(for x in items(a): x) == [10, 20, 30] var i = deq.head for c in 0 ..< deq.count: yield deq.data[i] @@ -249,21 +239,12 @@ iterator mitems*[T](deq: var Deque[T]): var T = iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = ## Yields every (position, value) of `deq`. - ## - ## **Examples:** - ## - ## .. code-block:: - ## var a = initDeque[int]() - ## for i in 1 .. 3: - ## a.addLast(10*i) - ## - ## for k, v in pairs(a): - ## echo "key: ", k, ", value: ", v - ## - ## # key: 0, value: 10 - ## # key: 1, value: 20 - ## # key: 2, value: 30 - ## + runnableExamples: + var a = initDeque[int]() + for i in 1 .. 3: + a.addLast(10*i) + from sugar import collect + doAssert collect(for k, v in pairs(a): (k, v)) == @[(0, 10), (1, 20), (2, 30)] var i = deq.head for c in 0 ..< deq.count: yield (c, deq.data[i]) @@ -274,10 +255,11 @@ proc contains*[T](deq: Deque[T], item: T): bool {.inline.} = ## ## Usually used via the ``in`` operator. ## It is the equivalent of ``deq.find(item) >= 0``. - ## - ## .. code-block:: Nim - ## if x in q: - ## assert q.contains(x) + runnableExamples: + var q = [7, 9].toDeque + assert 7 in q + assert q.contains 7 + assert 8 notin q for e in deq: if e == item: return true return false diff --git a/tests/collections/tcollections.nim b/tests/collections/tcollections.nim index 1e2858fb4..7677f7c1a 100644 --- a/tests/collections/tcollections.nim +++ b/tests/collections/tcollections.nim @@ -1,9 +1,10 @@ discard """ - output: "" + targets: "c js" """ -import sets, tables, deques, lists, critbits, sequtils +# see also: tdeques, tlists, tcritbits +import sets, tables, sequtils block tapply: var x = @[1, 2, 3] @@ -12,19 +13,6 @@ block tapply: x.applyIt(it+5000) doAssert x == @[5111, 5112, 5113] - -block tdeques: - proc index(self: Deque[int], idx: Natural): int = - self[idx] - - proc main = - var testDeque = initDeque[int]() - testDeque.addFirst(1) - assert testDeque.index(0) == 1 - - main() - - block tmapit: var x = @[1, 2, 3] # This mapIt call will run with preallocation because ``len`` is available. @@ -75,6 +63,8 @@ doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}" doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}""" doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}""" +# see also: tcritbitsToString, tlistsToString + # Tests for tables when defined(nimIntHash1): doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}""" @@ -83,55 +73,6 @@ else: let tabStr = $({"1": 1, "2": 2}.toTable) doAssert (tabStr == """{"2": 2, "1": 1}""" or tabStr == """{"1": 1, "2": 2}""") -# Tests for deques -block: - var d = initDeque[int]() - d.addLast(1) - doAssert $d == "[1]" -block: - var d = initDeque[string]() - d.addLast("1") - doAssert $d == """["1"]""" -block: - var d = initDeque[char]() - d.addLast('1') - doAssert $d == "['1']" - -# Tests for lists -block: - var l = initDoublyLinkedList[int]() - l.append(1) - l.append(2) - l.append(3) - doAssert $l == "[1, 2, 3]" -block: - var l = initDoublyLinkedList[string]() - l.append("1") - l.append("2") - l.append("3") - doAssert $l == """["1", "2", "3"]""" -block: - var l = initDoublyLinkedList[char]() - l.append('1') - l.append('2') - l.append('3') - doAssert $l == """['1', '2', '3']""" - -# Tests for critbits -block: - var t: CritBitTree[int] - t["a"] = 1 - doAssert $t == """{"a": 1}""" -block: - var t: CritBitTree[string] - t["a"] = "1" - doAssert $t == """{"a": "1"}""" -block: - var t: CritBitTree[char] - t["a"] = '1' - doAssert $t == """{"a": '1'}""" - - # Test escaping behavior block: var s = "" diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim index 4b05cd950..7b2dde1c8 100644 --- a/tests/stdlib/tcritbits.nim +++ b/tests/stdlib/tcritbits.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + import std/[sequtils,critbits] template main = @@ -65,5 +69,19 @@ template main = discard strings.containsOrIncl("foo", 3) doAssert strings["foo"] == 3 + block tcritbitsToString: + block: + var t: CritBitTree[int] + t["a"] = 1 + doAssert $t == """{"a": 1}""" + block: + var t: CritBitTree[string] + t["a"] = "1" + doAssert $t == """{"a": "1"}""" + block: + var t: CritBitTree[char] + t["a"] = '1' + doAssert $t == """{"a": '1'}""" + main() static: main() diff --git a/tests/stdlib/tdeque.nim b/tests/stdlib/tdeque.nim deleted file mode 100644 index 50e5d0ab1..000000000 --- a/tests/stdlib/tdeque.nim +++ /dev/null @@ -1,111 +0,0 @@ -import deques - - -var deq = initDeque[int](1) -deq.addLast(4) -deq.addFirst(9) -deq.addFirst(123) -var first = deq.popFirst() -deq.addLast(56) -assert(deq.peekLast() == 56) -deq.addLast(6) -assert(deq.peekLast() == 6) -var second = deq.popFirst() -deq.addLast(789) -assert(deq.peekLast() == 789) - -assert first == 123 -assert second == 9 -assert($deq == "[4, 56, 6, 789]") -assert deq == [4, 56, 6, 789].toDeque - -assert deq[0] == deq.peekFirst and deq.peekFirst == 4 -#assert deq[^1] == deq.peekLast and deq.peekLast == 789 -deq[0] = 42 -deq[deq.len - 1] = 7 - -assert 6 in deq and 789 notin deq -assert deq.find(6) >= 0 -assert deq.find(789) < 0 - -block: - var d = initDeque[int](1) - d.addLast 7 - d.addLast 8 - d.addLast 10 - d.addFirst 5 - d.addFirst 2 - d.addFirst 1 - d.addLast 20 - d.shrink(fromLast = 2) - doAssert($d == "[1, 2, 5, 7, 8]") - d.shrink(2, 1) - doAssert($d == "[5, 7]") - d.shrink(2, 2) - doAssert d.len == 0 - -for i in -2 .. 10: - if i in deq: - assert deq.contains(i) and deq.find(i) >= 0 - else: - assert(not deq.contains(i) and deq.find(i) < 0) - -when compileOption("boundChecks"): - try: - echo deq[99] - assert false - except IndexDefect: - discard - - try: - assert deq.len == 4 - for i in 0 ..< 5: deq.popFirst() - assert false - except IndexDefect: - discard - -# grabs some types of resize error. -deq = initDeque[int]() -for i in 1 .. 4: deq.addLast i -deq.popFirst() -deq.popLast() -for i in 5 .. 8: deq.addFirst i -assert $deq == "[8, 7, 6, 5, 2, 3]" - -# Similar to proc from the documentation example -proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. - var deq = initDeque[int]() - assert deq.len == 0 - for i in 1 .. a: deq.addLast i - - if b < deq.len: # checking before indexed access. - assert deq[b] == b + 1 - - # The following two lines don't need any checking on access due to the logic - # of the program, but that would not be the case if `a` could be 0. - assert deq.peekFirst == 1 - assert deq.peekLast == a - - while deq.len > 0: # checking if the deque is empty - assert deq.popFirst() > 0 - -#foo(0,0) -foo(8, 5) -foo(10, 9) -foo(1, 1) -foo(2, 1) -foo(1, 5) -foo(3, 2) - -import sets - -block t13310: - proc main() = - var q = initDeque[HashSet[int16]](2) - q.addFirst([1'i16].toHashSet) - q.addFirst([2'i16].toHashSet) - q.addFirst([3'i16].toHashSet) - assert $q == "[{3}, {2}, {1}]" - - static: - main() diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim new file mode 100644 index 000000000..db392c6cc --- /dev/null +++ b/tests/stdlib/tdeques.nim @@ -0,0 +1,139 @@ +discard """ + targets: "c js" +""" + +import std/deques + +block: + proc index(self: Deque[int], idx: Natural): int = + self[idx] + + proc main = + var testDeque = initDeque[int]() + testDeque.addFirst(1) + assert testDeque.index(0) == 1 + + main() + +block: + var d = initDeque[int]() + d.addLast(1) + doAssert $d == "[1]" +block: + var d = initDeque[string]() + d.addLast("1") + doAssert $d == """["1"]""" +block: + var d = initDeque[char]() + d.addLast('1') + doAssert $d == "['1']" + +block: + var deq = initDeque[int](1) + deq.addLast(4) + deq.addFirst(9) + deq.addFirst(123) + var first = deq.popFirst() + deq.addLast(56) + assert(deq.peekLast() == 56) + deq.addLast(6) + assert(deq.peekLast() == 6) + var second = deq.popFirst() + deq.addLast(789) + assert(deq.peekLast() == 789) + + assert first == 123 + assert second == 9 + assert($deq == "[4, 56, 6, 789]") + assert deq == [4, 56, 6, 789].toDeque + + assert deq[0] == deq.peekFirst and deq.peekFirst == 4 + #assert deq[^1] == deq.peekLast and deq.peekLast == 789 + deq[0] = 42 + deq[deq.len - 1] = 7 + + assert 6 in deq and 789 notin deq + assert deq.find(6) >= 0 + assert deq.find(789) < 0 + + block: + var d = initDeque[int](1) + d.addLast 7 + d.addLast 8 + d.addLast 10 + d.addFirst 5 + d.addFirst 2 + d.addFirst 1 + d.addLast 20 + d.shrink(fromLast = 2) + doAssert($d == "[1, 2, 5, 7, 8]") + d.shrink(2, 1) + doAssert($d == "[5, 7]") + d.shrink(2, 2) + doAssert d.len == 0 + + for i in -2 .. 10: + if i in deq: + assert deq.contains(i) and deq.find(i) >= 0 + else: + assert(not deq.contains(i) and deq.find(i) < 0) + + when compileOption("boundChecks"): + try: + echo deq[99] + assert false + except IndexDefect: + discard + + try: + assert deq.len == 4 + for i in 0 ..< 5: deq.popFirst() + assert false + except IndexDefect: + discard + + # grabs some types of resize error. + deq = initDeque[int]() + for i in 1 .. 4: deq.addLast i + deq.popFirst() + deq.popLast() + for i in 5 .. 8: deq.addFirst i + assert $deq == "[8, 7, 6, 5, 2, 3]" + + # Similar to proc from the documentation example + proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. + var deq = initDeque[int]() + assert deq.len == 0 + for i in 1 .. a: deq.addLast i + + if b < deq.len: # checking before indexed access. + assert deq[b] == b + 1 + + # The following two lines don't need any checking on access due to the logic + # of the program, but that would not be the case if `a` could be 0. + assert deq.peekFirst == 1 + assert deq.peekLast == a + + while deq.len > 0: # checking if the deque is empty + assert deq.popFirst() > 0 + + #foo(0,0) + foo(8, 5) + foo(10, 9) + foo(1, 1) + foo(2, 1) + foo(1, 5) + foo(3, 2) + +import sets + +block t13310: + proc main() = + var q = initDeque[HashSet[int16]](2) + q.addFirst([1'i16].toHashSet) + q.addFirst([2'i16].toHashSet) + q.addFirst([3'i16].toHashSet) + assert $q == "[{3}, {2}, {1}]" + + static: + main() diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index a288af781..fe814bb92 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -1,5 +1,5 @@ discard """ - output: '''true''' + targets: "c js" """ import lists @@ -62,6 +62,22 @@ block DoublyLinkedRingTest1: assert($L == "[]") assert(4 notin L) - -echo "true" - +block tlistsToString: + block: + var l = initDoublyLinkedList[int]() + l.append(1) + l.append(2) + l.append(3) + doAssert $l == "[1, 2, 3]" + block: + var l = initDoublyLinkedList[string]() + l.append("1") + l.append("2") + l.append("3") + doAssert $l == """["1", "2", "3"]""" + block: + var l = initDoublyLinkedList[char]() + l.append('1') + l.append('2') + l.append('3') + doAssert $l == """['1', '2', '3']""" From d15f63a0f2d431a516601530196ac01c26e00f53 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Sat, 12 Dec 2020 05:35:18 -0300 Subject: [PATCH 1647/4254] Fix #14259 #15621 (#16322) [backport:1.4] * IPv6 text representation according to RFC 5952 * Revert IPv6 text representation according to RFC 5952 * fix #14259 #15621 fix #14259 #15621 * Update lib/system/io.nim * reverted IoHandle removal * adaptation of types for WinAPI Co-authored-by: Andreas Rumpf --- lib/system/io.nim | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index c3b2976fb..b3e1725b4 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -278,7 +278,12 @@ elif defined(posix) and not defined(lwip) and not defined(nimscript): proc c_fcntl(fd: cint, cmd: cint): cint {. importc: "fcntl", header: "", varargs.} elif defined(windows): - const HANDLE_FLAG_INHERIT = culong 0x1 + type + WinDWORD = culong + WinBOOL = cint + + const HANDLE_FLAG_INHERIT = 1.WinDWORD + proc getOsfhandle(fd: cint): int {. importc: "_get_osfhandle", header: "".} @@ -286,8 +291,10 @@ elif defined(windows): IoHandle = distinct pointer ## Windows' HANDLE type. Defined as an untyped pointer but is **not** ## one. Named like this to avoid collision with other `system` modules. - proc setHandleInformation(handle: IoHandle, mask, flags: culong): cint {. - importc: "SetHandleInformation", header: "".} + + proc setHandleInformation(hObject: IoHandle, dwMask, dwFlags: WinDWORD): + WinBOOL {.stdcall, dynlib: "kernel32", + importc: "SetHandleInformation".} const BufSize = 4000 @@ -346,7 +353,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w result = c_fcntl(f, F_SETFD, flags) != -1 else: result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT, - culong inheritable) != 0 + inheritable.WinDWORD) != 0 proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} = From 5a58440ebe4ba794f0127ebb6ad33824a92dfb58 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sat, 12 Dec 2020 15:29:20 -0700 Subject: [PATCH 1648/4254] Added strscans.scanTuple (#16300) * Added since and changelog --- changelog.md | 1 + lib/pure/strscans.nim | 51 +++++++++++++++++++++++++++++++++++++- tests/stdlib/tstrscans.nim | 51 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index ab323337c..688b87da8 100644 --- a/changelog.md +++ b/changelog.md @@ -56,6 +56,7 @@ - `writeStackTrace` is available in JS backend now. - `strscans.scanf` now supports parsing single characters. +- `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. - Added `math.isNaN`. diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 347dbc2ef..9c55bf3e3 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -284,6 +284,7 @@ efficiency and perform different checks. import macros, parseutils +import std/private/since proc conditionsToIfChain(n, idx, res: NimNode; start: int): NimNode = assert n.kind == nnkStmtList @@ -465,6 +466,54 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: result.add res +macro scanTuple*(input: untyped; pattern: static[string]; matcherTypes: varargs[untyped]): untyped {.since: (1, 5).}= + ## Works identically as scanf, but instead of predeclaring variables it returns a tuple. + ## Tuple is started with a bool which indicates if the scan was successful + ## followed by the requested data. + ## If using a user defined matcher, provide the types in order they appear after pattern: + ## `line.scanTuple("${yourMatcher()}", int)` + runnableExamples: + let (success, year, month, day, time) = scanTuple("1000-01-01 00:00:00", "$i-$i-$i$s$+") + if success: + assert year == 1000 + assert month == 1 + assert day == 1 + assert time == "00:00:00" + var + p = 0 + userMatches = 0 + arguments: seq[NimNode] + result = newStmtList() + template addVar(typ: string) = + let varIdent = ident("temp" & $arguments.len) + result.add(newNimNode(nnkVarSection).add(newIdentDefs(varIdent, ident(typ), newEmptyNode()))) + arguments.add(varIdent) + while p < pattern.len: + if pattern[p] == '$': + inc p + case pattern[p] + of 'w', '*', '+': + addVar("string") + of 'c': + addVar("char") + of 'b', 'o', 'i', 'h': + addVar("int") + of 'f': + addVar("float") + of '{': + if userMatches < matcherTypes.len: + let varIdent = ident("temp" & $arguments.len) + result.add(newNimNode(nnkVarSection).add(newIdentDefs(varIdent, matcherTypes[userMatches], newEmptyNode()))) + arguments.add(varIdent) + inc userMatches + else: discard + inc p + result.add newPar(newCall(ident("scanf"), input, newStrLitNode(pattern))) + for arg in arguments: + result[^1][0].add arg + result[^1].add arg + result = newBlockStmt(result) + template atom*(input: string; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). ## EOF is matched as ``'\0'``. @@ -639,4 +688,4 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = result.add toIfChain(conds, idx, res, 0) result.add res when defined(debugScanp): - echo repr result + echo repr result \ No newline at end of file diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index 8ca167837..d443c5dda 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -227,3 +227,54 @@ block: if line.scanf("$i-$i $c: $w", lo, hi, c, w): inc res doAssert res == 4 + +block: + #whenscanf testing + let input = """1-3 s: abc +15-18 9: def +15-18 A: ghi +15-18 _: jkl +""" + proc twoDigits(input: string; x: var int; start: int): int = + if start+1 < input.len and input[start] == '0' and input[start+1] == '0': + result = 2 + x = 13 + else: + result = 0 + + proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int = + result = 0 + while start+result < input.len and input[start+result] in seps: inc result + + var res = 0 + for line in input.splitLines: + let (success, lo, hi, c ,w) = scanTuple(line, "$i-$i $c: $w") + if success: + inc res + doAssert res == 4 + + let (_, key, val, intval, floatVal) = scanTuple("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f") + doAssert key == "abc" + doAssert val == "xyz" + doAssert intval == 89 + doAssert floatVal == 33.25 + + + let (_, binVal, octVal, hexVal) = scanTuple("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) + doAssert binval == 0b0101 + doAssert octval == 0o1234 + doAssert hexval == 0xabcd + + var (xx,_) = scanTuple("$abc", "$$$i") + doAssert xx == false + + + let (xx2, _) = block: scanTuple("$1234", "$$$i") + doAssert xx2 + + var (yy, intval2, key2) = scanTuple(";.--Breakpoint00 [output]", + "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", + int) + doAssert yy + doAssert key2 == "output" + doAssert intVal2 == 13 \ No newline at end of file From 5514b299ebc1de4ef0c1c182d4f21a02e3c2fa90 Mon Sep 17 00:00:00 2001 From: Bung Date: Sun, 13 Dec 2020 11:52:38 +0800 Subject: [PATCH 1649/4254] add testcase for #15937 (#15933) * test for issue #15624 and PR #15915 for patch #13823 * Update thashes.nim no need mention PR #15915, fixed in https://github.com/nim-lang/Nim/pull/15937 * rebase to devel(issue maybe fixed), ignore ouputs * Apply suggestions from code review Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- tests/stdlib/thashes.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index d155111ff..92154825e 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,3 +1,7 @@ +discard """ + targets: '''c c++ js''' +""" + import hashes block hashes: @@ -13,8 +17,10 @@ block hashes: # "VM and runtime should make the same hash value (hashWangYi1)" block: const wy123 = hashWangYi1(123) + doAssert wy123 != 0 doAssert hashWangYi1(123) == wy123 + # "hashIdentity value incorrect at 456" block: doAssert hashIdentity(456) == 456 From 7e1ae35195c9b1397d569ebb3b3a0d11fdcb16f4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 14 Dec 2020 01:58:29 -0800 Subject: [PATCH 1650/4254] testament: error instead of silently ignore invalid targets; remove pointless alias target vs targets; document matrix; DRY (#16343) * testament: error instead of silently ignore invalid targets * s/target/targets/ * fix test; refs #16344 * address comments * Update testament/specs.nim Co-authored-by: Andreas Rumpf --- doc/testament.rst | 9 ++++++--- testament/specs.nim | 20 ++++++------------- tests/align/talign.nim | 2 +- tests/arc/trtree.nim | 2 +- tests/ccgbugs/tmissingvolatile.nim | 2 +- tests/ccgbugs/tprogmem.nim | 2 +- tests/ccgbugs2/tinefficient_const_table.nim | 2 +- tests/closure/tclosure.nim | 2 +- tests/compiler/tcppCompileToNamespace.nim | 1 - tests/coroutines/texceptions.nim | 2 +- tests/coroutines/tgc.nim | 2 +- tests/coroutines/titerators.nim | 2 +- tests/coroutines/twait.nim | 2 +- tests/cpp/tevalorder.nim | 2 +- tests/destructor/tmove_objconstr.nim | 2 +- .../destructor/tuse_result_prevents_sinks.nim | 2 +- tests/exception/t9657.nim | 2 +- tests/flags/tgenscript.nim | 2 +- tests/iter/titervaropenarray.nim | 2 +- tests/objects/tobjcov.nim | 2 +- tests/stdlib/t10231.nim | 2 +- tests/stdlib/thashes.nim | 2 +- tests/stdlib/ttimes.nim | 2 +- tests/system/tatomics1.nim | 2 +- 24 files changed, 33 insertions(+), 39 deletions(-) diff --git a/doc/testament.rst b/doc/testament.rst index 1a1909022..253afb33d 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -152,8 +152,11 @@ Example "template" **to edit** and write a Testament unittest: # Timeout seconds to run the test. Fractional values are supported. timeout: 1.5 - # Targets to run the test into (C, C++, JavaScript, etc). - target: "c js" + # Targets to run the test into (c, cpp, objc, js). + targets: "c js" + + # flags with which to run the test, delimited by `;` + matrix: "; -d:release; -d:caseFoo -d:release" # Conditions that will skip this test. Use of multiple "disabled" clauses # is permitted. @@ -221,7 +224,7 @@ JavaScript tests: .. code-block:: nim discard """ - target: "js" + targets: "js" """ when defined(js): import jsconsole diff --git a/testament/specs.nim b/testament/specs.nim index e15dcb85c..a7f0fd4bb 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -218,7 +218,7 @@ proc parseTargets*(value: string): set[TTarget] = of "cpp", "c++": result.incl(targetCpp) of "objc": result.incl(targetObjC) of "js": result.incl(targetJS) - else: echo "target ignored: " & v + else: raise newException(ValueError, "invalid target: '$#'" % v) proc addLine*(self: var string; a: string) = self.add a @@ -377,19 +377,11 @@ proc parseSpec*(filename: string): TSpec = result.timeout = parseFloat(e.value) except ValueError: result.parseErrors.addLine "cannot interpret as a float: ", e.value - of "target", "targets": - for v in e.value.normalize.splitWhitespace: - case v - of "c": - result.targets.incl(targetC) - of "cpp", "c++": - result.targets.incl(targetCpp) - of "objc": - result.targets.incl(targetObjC) - of "js": - result.targets.incl(targetJS) - else: - result.parseErrors.addLine "cannot interpret as a target: ", e.value + of "targets", "target": + try: + result.targets.incl parseTargets(e.value) + except ValueError as e: + result.parseErrors.addLine e.msg of "matrix": for v in e.value.split(';'): result.matrix.add(v.strip) diff --git a/tests/align/talign.nim b/tests/align/talign.nim index e0503cc70..3b8f6b4df 100644 --- a/tests/align/talign.nim +++ b/tests/align/talign.nim @@ -1,6 +1,6 @@ discard """ ccodeCheck: "\\i @'NIM_ALIGN(128) NI mylocal1' .*" -target: "c cpp" +targets: "c cpp" output: "align ok" """ diff --git a/tests/arc/trtree.nim b/tests/arc/trtree.nim index 986268f51..5659a5bdc 100644 --- a/tests/arc/trtree.nim +++ b/tests/arc/trtree.nim @@ -1,7 +1,7 @@ discard """ output: '''1 [2, 3, 4, 7] [0, 0]''' - target: "c" + targets: "c" joinable: false disabled: 32bit cmd: "nim c --gc:arc $file" diff --git a/tests/ccgbugs/tmissingvolatile.nim b/tests/ccgbugs/tmissingvolatile.nim index 60b1771dc..1eccdc6b1 100644 --- a/tests/ccgbugs/tmissingvolatile.nim +++ b/tests/ccgbugs/tmissingvolatile.nim @@ -2,7 +2,7 @@ discard """ output: "1" cmd: r"nim c --hints:on $options -d:release $file" ccodecheck: "'NI volatile state;'" - target: "C" + targets: "c" """ # bug #1539 diff --git a/tests/ccgbugs/tprogmem.nim b/tests/ccgbugs/tprogmem.nim index 884ca158a..58a20583a 100644 --- a/tests/ccgbugs/tprogmem.nim +++ b/tests/ccgbugs/tprogmem.nim @@ -2,7 +2,7 @@ discard """ output: "5" cmd: r"nim c --hints:on $options -d:release $file" ccodecheck: "'/*PROGMEM*/ myLetVariable = {'" - target: "C" + targets: "c" """ var myLetVariable {.exportc, codegenDecl: "$# /*PROGMEM*/ $#".} = [1, 2, 3] diff --git a/tests/ccgbugs2/tinefficient_const_table.nim b/tests/ccgbugs2/tinefficient_const_table.nim index a1b89e220..8ab895cb0 100644 --- a/tests/ccgbugs2/tinefficient_const_table.nim +++ b/tests/ccgbugs2/tinefficient_const_table.nim @@ -6,7 +6,7 @@ of words''' cmd: r"nim c --hints:on $options -d:release $file" ccodecheck: "! @'genericSeqAssign'" - target: "c" + targets: "c" """ # bug #4354 diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim index 7e2ec7a77..546d7026d 100644 --- a/tests/closure/tclosure.nim +++ b/tests/closure/tclosure.nim @@ -1,5 +1,5 @@ discard """ - target: "c" + targets: "c" output: ''' 1 3 6 11 20 foo foo88 diff --git a/tests/compiler/tcppCompileToNamespace.nim b/tests/compiler/tcppCompileToNamespace.nim index 1d0977236..4e895c38b 100644 --- a/tests/compiler/tcppCompileToNamespace.nim +++ b/tests/compiler/tcppCompileToNamespace.nim @@ -1,6 +1,5 @@ discard """ cmd: "nim cpp --cppCompileToNamespace:foo $options -r $file" -target: cpp """ # Theoretically nim could just ignore the flag cppCompileToNamespace diff --git a/tests/coroutines/texceptions.nim b/tests/coroutines/texceptions.nim index 7b5d57ec0..31feffdff 100644 --- a/tests/coroutines/texceptions.nim +++ b/tests/coroutines/texceptions.nim @@ -1,5 +1,5 @@ discard """ - target: "c" + targets: "c" disabled: true """ diff --git a/tests/coroutines/tgc.nim b/tests/coroutines/tgc.nim index 46f4f8e83..311ec5efc 100644 --- a/tests/coroutines/tgc.nim +++ b/tests/coroutines/tgc.nim @@ -1,5 +1,5 @@ discard """ - target: "c" + targets: "c" """ import coro diff --git a/tests/coroutines/titerators.nim b/tests/coroutines/titerators.nim index d12a5debe..1ea134811 100644 --- a/tests/coroutines/titerators.nim +++ b/tests/coroutines/titerators.nim @@ -1,5 +1,5 @@ discard """ - target: "c" + targets: "c" disabled: true """ diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim index b88801869..348007afb 100644 --- a/tests/coroutines/twait.nim +++ b/tests/coroutines/twait.nim @@ -1,6 +1,6 @@ discard """ output: "Exit 1\nExit 2" - target: "c" + targets: "c" """ import coro diff --git a/tests/cpp/tevalorder.nim b/tests/cpp/tevalorder.nim index f130cef6c..4764f3aca 100644 --- a/tests/cpp/tevalorder.nim +++ b/tests/cpp/tevalorder.nim @@ -2,7 +2,7 @@ discard """ output: '''0 1 2''' -target: "cpp" +targets: "cpp" """ # bug #8202 diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 16d0daa22..5faaabb8b 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -8,7 +8,7 @@ test destroyed 0 4 Pony is dying!''' joinable: false -target: "C" +targets: "c" """ # bug #4214 diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim index 6eac5c902..d2777bd97 100644 --- a/tests/destructor/tuse_result_prevents_sinks.nim +++ b/tests/destructor/tuse_result_prevents_sinks.nim @@ -1,6 +1,6 @@ discard """ output: "" - target: "C" + targets: "c" """ # bug #9594 diff --git a/tests/exception/t9657.nim b/tests/exception/t9657.nim index 514d29353..6ac525a70 100644 --- a/tests/exception/t9657.nim +++ b/tests/exception/t9657.nim @@ -1,7 +1,7 @@ discard """ action: run exitcode: 1 - target: "c cpp" + targets: "c cpp" disabled: "openbsd" disabled: "netbsd" """ diff --git a/tests/flags/tgenscript.nim b/tests/flags/tgenscript.nim index bf83ab972..d58395a40 100644 --- a/tests/flags/tgenscript.nim +++ b/tests/flags/tgenscript.nim @@ -1,5 +1,5 @@ discard """ - target: "c" + targets: "c" action: compile """ diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim index 4469fdcf5..ad1192bd8 100644 --- a/tests/iter/titervaropenarray.nim +++ b/tests/iter/titervaropenarray.nim @@ -1,6 +1,6 @@ discard """ output: "123" - targets: "C" + targets: "c" """ # Try to break the transformation pass: iterator iterAndZero(a: var openArray[int]): int = diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim index 6c587e04d..a12f74702 100644 --- a/tests/objects/tobjcov.nim +++ b/tests/objects/tobjcov.nim @@ -1,6 +1,6 @@ discard """ action: compile -target: "c" +targets: "c" """ # Covariance is not type safe: diff --git a/tests/stdlib/t10231.nim b/tests/stdlib/t10231.nim index 2bb64b475..3b2b684f3 100644 --- a/tests/stdlib/t10231.nim +++ b/tests/stdlib/t10231.nim @@ -1,5 +1,5 @@ discard """ - target: cpp + targets: "cpp" action: run exitcode: 0 """ diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 92154825e..520b27e26 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,5 +1,5 @@ discard """ - targets: '''c c++ js''' + targets: "c cpp js" """ import hashes diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 4d89ffa1a..a7677edf9 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -1,5 +1,5 @@ discard """ - target: "c js" + targets: "c js" """ import times, strutils, unittest diff --git a/tests/system/tatomics1.nim b/tests/system/tatomics1.nim index 88ab705a8..217fd07fa 100644 --- a/tests/system/tatomics1.nim +++ b/tests/system/tatomics1.nim @@ -1,5 +1,5 @@ discard """ - target: "c cpp js" + targets: "c cpp js" """ var x = 10 From 9ac2ee7b8d80a6b4a6369626018492142889d158 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Mon, 14 Dec 2020 07:07:55 -0300 Subject: [PATCH 1651/4254] Fix #11506 (#16348) fixes the problem of compiling vccexe.exe when it is in use. --- koch.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 628c81098..5da262884 100644 --- a/koch.nim +++ b/koch.nim @@ -156,7 +156,13 @@ proc bundleNimsuggest(args: string) = options = "-d:release -d:danger " & args) proc buildVccTool(args: string) = - nimCompileFold("Compile Vcc", "tools/vccexe/vccexe.nim ", options = args) + let input = "tools/vccexe/vccexe.nim" + if contains(args, "--cc:vcc"): + nimCompileFold("Compile Vcc", input, "build", options = args) + let fileName = input.splitFile.name + moveFile(exe("build" / fileName), exe("bin" / fileName)) + else: + nimCompileFold("Compile Vcc", input, options = args) proc bundleNimpretty(args: string) = nimCompileFold("Compile nimpretty", "nimpretty/nimpretty.nim", From 4850f9b5969d52980177400a75af890f72d579d0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 14 Dec 2020 02:17:24 -0800 Subject: [PATCH 1652/4254] fix #16265; fix #13999 (HCR on OSX); cgen now does not line wrap string litterals (#16329) * fix #16265: cgen now does not line wrap string litterals which, in combination with other hacks, caused a really obscure looking bug * fix #13999; nimhcr_integration.nim now works for osx * try to make appveyor CI disappear * disable openbsd + add diagnostic for openbsd * enable for openbsd * PTEMP * re-disable openbsd --- compiler/cgen.nim | 3 +++ compiler/msgs.nim | 8 +++++--- tests/dll/nimhcr_integration.nim | 17 +++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c4544bbc5..220b8e3c1 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1556,6 +1556,9 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = # nasty nasty hack to get the command line functionality working with HCR # register the 2 variables on behalf of the os module which might not even # be loaded (in which case it will get collected but that is not a problem) + # EDIT: indeed, this hack, in combination with another un-necessary one + # (`makeCString` was doing line wrap of string litterals) was root cause for + # bug #16265. let osModulePath = ($systemModulePath).replace("stdlib_system", "stdlib_os").rope g.mainDatInit.addf("\thcrAddModule($1);\n", [osModulePath]) g.mainDatInit.add("\tint* cmd_count;\n") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index d0209db5d..1a005788e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -34,13 +34,15 @@ proc toCChar*(c: char; result: var string) = result.add c proc makeCString*(s: string): Rope = - const MaxLineLength = 64 result = nil var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1) res.add("\"") for i in 0.. 0 let (stdout, exitcode) = execCmdEx(cmd) if exitcode != 0: echo "COMPILATION ERROR!" From 555cfd1d59e773e92a7158b7c3b5908017f1ddac Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 14 Dec 2020 02:37:27 -0800 Subject: [PATCH 1653/4254] fix #16330 tshould_not_work (#16342) --- testament/testament.nim | 4 ++-- tests/testament/tshould_not_work.nim | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/testament/testament.nim b/testament/testament.nim index a301b018c..7b1a25bf0 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -144,7 +144,7 @@ proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, options.add " " & extraOptions result = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell, - "filedir", filename.getFileDir()]) + "filedir", filename.getFileDir(), "nim", compilerPrefix]) proc callCompiler(cmdTemplate, filename, options, nimcache: string, target: TTarget, extraOptions = ""): TSpec = @@ -682,7 +682,7 @@ proc main() = gTargets = parseTargets(targetsStr) targetsSet = true of "nim": - compilerPrefix = addFileExt(p.val.string, ExeExt) + compilerPrefix = addFileExt(p.val.string.absolutePath, ExeExt) of "directory": setCurrentDir(p.val.string) of "colors": diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index a7a877fe8..a0b4d6a36 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -1,5 +1,5 @@ discard """ -cmd: "testament/testament --directory:testament --colors:off --backendLogging:off --nim:../compiler/nim category shouldfail" +cmd: "testament/testament --directory:testament --colors:off --backendLogging:off --nim:$nim category shouldfail" action: compile nimout: ''' FAIL: tests/shouldfail/tccodecheck.nim c @@ -35,5 +35,3 @@ FAIL: tests/shouldfail/tvalgrind.nim c Failure: reExitcodesDiffer ''' """ - -# xxx `--nim:../compiler/nim`, doesn't seem correct (and should also honor `testament --nim`) From 5e8e948ffce951d8284fe38489cd880255e56e7b Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 14 Dec 2020 07:50:45 -0300 Subject: [PATCH 1654/4254] Clean out dead code (#16345) --- tools/nimrepl.nim | 172 ---------------------------------------------- 1 file changed, 172 deletions(-) delete mode 100644 tools/nimrepl.nim diff --git a/tools/nimrepl.nim b/tools/nimrepl.nim deleted file mode 100644 index ac82d8b75..000000000 --- a/tools/nimrepl.nim +++ /dev/null @@ -1,172 +0,0 @@ -# -# -# Nim REPL -# (c) Copyright 2012 Dominik Picheta -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import glib2, gtk2, gdk2, os, osproc, dialogs, strutils - -when defined(tinyc): - const runCmd = "run" -else: - const runCmd = "c -r" - -var nimExe = findExe("nim") -if nimExe.len == 0: nimExe = "../bin" / addFileExt("nim", os.ExeExt) - -proc execCode(code: string): string = - var f: File - if open(f, "temp.nim", fmWrite): - f.write(code) - f.close() - result = osproc.execProcess( - "$# $# --verbosity:0 --hint[Conf]:off temp.nim" % [nimExe, runCmd], - options = {poStdErrToStdOut}) - else: - result = "cannot open file 'temp.nim'" - -var shiftPressed = false -var w: gtk2.PWindow -var inputTextBuffer: PTextBuffer -var outputTextBuffer: PTextBuffer - -proc destroy(widget: PWidget, data: pointer){.cdecl.} = - main_quit() - -proc fileOpenClicked(menuitem: PMenuItem, userdata: pointer) {.cdecl.} = - var path = chooseFileToOpen(w) - if path != "": - var file = readFile(path) - if file != nil: - set_text(inputTextBuffer, file, len(file).gint) - else: - error(w, "Unable to read from file") - -proc fileSaveClicked(menuitem: PMenuItem, userdata: pointer) {.cdecl.} = - var path = chooseFileToSave(w) - - if path == "": return - var startIter: TTextIter - var endIter: TTextIter - get_start_iter(inputTextBuffer, addr(startIter)) - get_end_iter(inputTextBuffer, addr(endIter)) - var inputText = get_text(inputTextBuffer, addr(startIter), - addr(endIter), false) - var f: File - if open(f, path, fmWrite): - f.write(inputText) - f.close() - else: - error(w, "Unable to write to file") - -proc inputKeyPressed(widget: PWidget, event: PEventKey, - userdata: pointer): bool {.cdecl.} = - if ($keyval_name(event.keyval)).tolower() == "shift_l": - # SHIFT is pressed - shiftPressed = true - -proc setError(msg: string) = - outputTextBuffer.setText(msg, msg.len.gint) - -proc inputKeyReleased(widget: PWidget, event: PEventKey, - userdata: pointer): bool {.cdecl.} = - #echo(keyval_name(event.keyval)) - if ($keyval_name(event.keyval)).tolower() == "shift_l": - # SHIFT is released - shiftPressed = false - - if ($keyval_name(event.keyval)).tolower() == "return": - #echo($keyval_name(event.keyval), "Shift_L") - # Enter pressed - if not shiftPressed: - var startIter: TTextIter - var endIter: TTextIter - get_start_iter(inputTextBuffer, addr(startIter)) - get_end_iter(inputTextBuffer, addr(endIter)) - var inputText = get_text(inputTextBuffer, addr(startIter), - addr(endIter), false) - - try: - var r = execCode($inputText) - set_text(outputTextBuffer, r, len(r).gint) - except IOError: - setError("Error: Could not open file temp.nim") - - -proc initControls() = - w = window_new(gtk2.WINDOW_TOPLEVEL) - set_default_size(w, 500, 600) - set_title(w, "Nim REPL") - discard signal_connect(w, "destroy", SIGNAL_FUNC(nimrepl.destroy), nil) - - # MainBox (vbox) - var mainBox = vbox_new(false, 0) - add(w, mainBox) - - # TopMenu (MenuBar) - var topMenu = menu_bar_new() - show(topMenu) - - var fileMenu = menu_new() - var openMenuItem = menu_item_new("Open") - append(fileMenu, openMenuItem) - show(openMenuItem) - discard signal_connect(openMenuItem, "activate", - SIGNAL_FUNC(fileOpenClicked), nil) - var saveMenuItem = menu_item_new("Save...") - append(fileMenu, saveMenuItem) - show(saveMenuItem) - discard signal_connect(saveMenuItem, "activate", - SIGNAL_FUNC(fileSaveClicked), nil) - var fileMenuItem = menu_item_new("File") - - - set_submenu(fileMenuItem, fileMenu) - show(fileMenuItem) - append(topMenu, fileMenuItem) - - pack_start(mainBox, topMenu, false, false, 0) - - # VPaned - Separates the InputTextView and the OutputTextView - var paned = vpaned_new() - set_position(paned, 450) - pack_start(mainBox, paned, true, true, 0) - show(paned) - - # Init the TextBuffers - inputTextBuffer = text_buffer_new(nil) - outputTextBuffer = text_buffer_new(nil) - - # InputTextView (TextView) - var inputScrolledWindow = scrolled_window_new(nil, nil) - set_policy(inputScrolledWindow, POLICY_AUTOMATIC, POLICY_AUTOMATIC) - var inputTextView = text_view_new(inputTextBuffer) - add_with_viewport(inputScrolledWindow, inputTextView) - add1(paned, inputScrolledWindow) - show(inputScrolledWindow) - show(inputTextView) - - discard signal_connect(inputTextView, "key-release-event", - SIGNAL_FUNC(inputKeyReleased), nil) - discard signal_connect(inputTextView, "key-press-event", - SIGNAL_FUNC(inputKeyPressed), nil) - - # OutputTextView (TextView) - var outputScrolledWindow = scrolled_window_new(nil, nil) - set_policy(outputScrolledWindow, POLICY_AUTOMATIC, POLICY_AUTOMATIC) - var outputTextView = text_view_new(outputTextBuffer) - add_with_viewport(outputScrolledWindow, outputTextView) - add2(paned, outputScrolledWindow) - show(outputScrolledWindow) - show(outputTextView) - - show(w) - show(mainBox) - -nim_init() -initControls() -main() - From b6443c96a0114994fe43e266b358b24c183c1017 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Mon, 14 Dec 2020 13:28:03 +0100 Subject: [PATCH 1655/4254] fix #16334 (#16335) * fix #16334 * rename isstdout -> isStdout * separate lastMsgWasDot for stdout and stderr * simplify logic --- compiler/msgs.nim | 14 +++++++++----- compiler/options.nim | 6 +++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 1a005788e..d027ce960 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -16,11 +16,15 @@ import strutils2 type InstantiationInfo* = typeof(instantiationInfo()) template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) -template flushDot(conf, stdorr) = +template toStdOrrKind(stdOrr): untyped = + if stdOrr == stdout: stdOrrStdout else: stdOrrStderr + +template flushDot(conf, stdOrr) = ## safe to call multiple times - if conf.lastMsgWasDot: - conf.lastMsgWasDot = false - write(stdorr, "\n") + let stdOrrKind = stdOrr.toStdOrrKind() + if stdOrrKind in conf.lastMsgWasDot: + conf.lastMsgWasDot.excl stdOrrKind + write(stdOrr, "\n") proc toCChar*(c: char; result: var string) = case c @@ -357,7 +361,7 @@ proc msgWrite(conf: ConfigRef; s: string) = stderr write(stdOrr, s) flushFile(stdOrr) - conf.lastMsgWasDot = true # subsequent writes need `flushDot` + conf.lastMsgWasDot.incl stdOrr.toStdOrrKind() # subsequent writes need `flushDot` template styledMsgWriteln*(args: varargs[typed]) = if not isNil(conf.writelnHook): diff --git a/compiler/options.nim b/compiler/options.nim index bf0a9a4ee..73c4c627d 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -240,6 +240,10 @@ type ProfileData* = ref object data*: TableRef[TLineInfo, ProfileInfo] + StdOrrKind* = enum + stdOrrStdout + stdOrrStderr + ConfigRef* = ref object ## every global configuration ## fields marked with '*' are subject to ## the incremental compilation mechanisms @@ -304,7 +308,7 @@ type projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/ projectFull*: AbsoluteFile # projectPath/projectName projectIsStdin*: bool # whether we're compiling from stdin - lastMsgWasDot*: bool # the last compiler message was a single '.' + lastMsgWasDot*: set[StdOrrKind] # the last compiler message was a single '.' projectMainIdx*: FileIndex # the canonical path id of the main module projectMainIdx2*: FileIndex # consider merging with projectMainIdx command*: string # the main command (e.g. cc, check, scan, etc) From 8f6e07a9a2b8aaa05671b3e3bdd4f95f5c2f1b71 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 14 Dec 2020 09:38:02 -0600 Subject: [PATCH 1656/4254] clean the docs of sequtils (#16332) --- lib/pure/collections/sequtils.nim | 186 ++++++++++++++---------------- 1 file changed, 89 insertions(+), 97 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index a7e392026..449faadc7 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -7,19 +7,19 @@ # distribution, for details about the copyright. # -## Although this module has ``seq`` in its name, it implements operations +## Although this module has `seq` in its name, it implements operations ## not only for `seq`:idx: type, but for three built-in container types under -## the ``openArray`` umbrella: +## the `openArray` umbrella: ## * sequences ## * strings ## * array ## ## The system module defines several common functions, such as: -## * ``newSeq[T]`` for creating new sequences of type ``T`` -## * ``@`` for converting arrays and strings to sequences -## * ``add`` for adding new elements to strings and sequences -## * ``&`` for string and seq concatenation -## * ``in`` (alias for ``contains``) and ``notin`` for checking if an item is +## * `newSeq[T]` for creating new sequences of type `T` +## * `@` for converting arrays and strings to sequences +## * `add` for adding new elements to strings and sequences +## * `&` for string and seq concatenation +## * `in` (alias for `contains`) and `notin` for checking if an item is ## in a container ## ## This module builds upon that, providing additional functionality in form of @@ -37,41 +37,40 @@ ## ## The chaining of functions is possible thanks to the ## `method call syntax`_. -## -## .. code-block:: -## import sequtils, sugar -## -## # Creating a sequence from 1 to 10, multiplying each member by 2, -## # keeping only the members which are not divisible by 6. -## let -## foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0) -## bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0) -## baz = collect(newSeq): -## for i in 1..10: -## let j = 2*i -## if j mod 6 != 0: -## j -## -## doAssert foo == bar -## doAssert foo == baz -## echo foo # @[2, 4, 8, 10, 14, 16, 20] -## -## echo foo.any(x => x > 17) # true -## echo bar.allIt(it < 20) # false -## echo foo.foldl(a + b) # 74; sum of all members -## -## .. code-block:: -## import sequtils -## from strutils import join -## -## let -## vowels = @"aeiou" # creates a sequence @['a', 'e', 'i', 'o', 'u'] -## foo = "sequtils is an awesome module" -## -## echo foo.filterIt(it notin vowels).join # "sqtls s n wsm mdl" -## -## ---- -## + +runnableExamples: + import sugar + + # Creating a sequence from 1 to 10, multiplying each member by 2, + # keeping only the members which are not divisible by 6. + let + foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0) + bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0) + baz = collect: + for i in 1..10: + let j = 2*i + if j mod 6 != 0: + j + + doAssert foo == bar + doAssert foo == baz + doAssert foo == @[2, 4, 8, 10, 14, 16, 20] + + doAssert foo.any(x => x > 17) + doAssert not bar.allIt(it < 20) + doAssert foo.foldl(a + b) == 74 # sum of all members + + +runnableExamples: + from strutils import join + + let + vowels = @"aeiou" + foo = "sequtils is an awesome module" + + doAssert (vowels is seq[char]) and (vowels == @['a', 'e', 'i', 'o', 'u']) + doAssert foo.filterIt(it notin vowels).join == "sqtls s n wsm mdl" + ## **See also**: ## * `strutils module`_ for common string functions ## * `sugar module`_ for syntactic sugar macros @@ -90,12 +89,12 @@ when not defined(nimhygiene): macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped = - ## Injects ``expAlias`` in caller scope, to avoid bugs involving multiple + ## Injects `expAlias` in caller scope, to avoid bugs involving multiple ## substitution in macro arguments such as ## https://github.com/nim-lang/Nim/issues/7187 - ## ``evalOnceAs(myAlias, myExp)`` will behave as ``let myAlias = myExp`` - ## except when ``letAssigneable`` is false (e.g. to handle openArray) where - ## it just forwards ``exp`` unchanged + ## `evalOnceAs(myAlias, myExp)` will behave as `let myAlias = myExp` + ## except when `letAssigneable` is false (e.g. to handle openArray) where + ## it just forwards `exp` unchanged expectKind(expAlias, nnkIdent) var val = exp @@ -428,7 +427,10 @@ func apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) func apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = ## Same as `apply` but for proc that do not return and do not mutate `s` directly. - runnableExamples: apply([0, 1, 2, 3, 4], proc(item: int) = echo item) + runnableExamples: + var message: string + apply([0, 1, 2, 3, 4], proc(item: int) = message.addInt item) + assert message == "01234" for i in 0 ..< s.len: op(s[i]) iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = @@ -576,8 +578,8 @@ template filterIt*(s, pred: untyped): untyped = ## ## Unlike the `filter func<#filter,openArray[T],proc(T)>`_ and ## `filter iterator<#filter.i,openArray[T],proc(T)>`_, - ## the predicate needs to be an expression using the ``it`` variable - ## for testing, like: ``filterIt("abcxyz", it == 'x')``. + ## the predicate needs to be an expression using the `it` variable + ## for testing, like: `filterIt("abcxyz", it == 'x')`. ## ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro ## from the `sugar` module. @@ -601,12 +603,12 @@ template filterIt*(s, pred: untyped): untyped = result template keepItIf*(varSeq: seq, pred: untyped) = - ## Keeps the items in the passed sequence (must be declared as a ``var``) + ## Keeps the items in the passed sequence (must be declared as a `var`) ## if they fulfilled the predicate. ## ## Unlike the `keepIf func<#keepIf,seq[T],proc(T)>`_, ## the predicate needs to be an expression using - ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``. + ## the `it` variable for testing, like: `keepItIf("abcxyz", it == 'x')`. ## ## See also: ## * `keepIf func<#keepIf,seq[T],proc(T)>`_ @@ -634,7 +636,7 @@ since (1, 1): ## Returns a count of all the items that fulfilled the predicate. ## ## The predicate needs to be an expression using - ## the ``it`` variable for testing, like: ``countIt(@[1, 2, 3], it > 2)``. + ## the `it` variable for testing, like: `countIt(@[1, 2, 3], it > 2)`. ## runnableExamples: let numbers = @[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6] @@ -672,7 +674,7 @@ template allIt*(s, pred: untyped): bool = ## ## Unlike the `all func<#all,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using - ## the ``it`` variable for testing, like: ``allIt("abba", it == 'a')``. + ## the `it` variable for testing, like: `allIt("abba", it == 'a')`. ## ## See also: ## * `all func<#all,openArray[T],proc(T)>`_ @@ -714,7 +716,7 @@ template anyIt*(s, pred: untyped): bool = ## ## Unlike the `any func<#any,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using - ## the ``it`` variable for testing, like: ``anyIt("abba", it == 'a')``. + ## the `it` variable for testing, like: `anyIt("abba", it == 'a')`. ## ## See also: ## * `any func<#any,openArray[T],proc(T)>`_ @@ -817,10 +819,10 @@ template foldl*(sequence, operation: untyped): untyped = ## The sequence is required to have at least a single element. Debug versions ## of your program will assert in this situation but release versions will ## happily go ahead. If the sequence has a single element it will be returned - ## without applying ``operation``. + ## without applying `operation`. ## - ## The ``operation`` parameter should be an expression which uses the - ## variables ``a`` and ``b`` for each step of the fold. Since this is a left + ## The `operation` parameter should be an expression which uses the + ## variables `a` and `b` for each step of the fold. Since this is a left ## fold, for non associative binary operations like subtraction think that ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) - ## 3). @@ -863,12 +865,12 @@ template foldl*(sequence, operation: untyped): untyped = template foldl*(sequence, operation, first): untyped = ## Template to fold a sequence from left to right, returning the accumulation. ## - ## This version of ``foldl`` gets a **starting parameter**. This makes it possible + ## This version of `foldl` gets a **starting parameter**. This makes it possible ## to accumulate the sequence into a different type than the sequence elements. ## - ## The ``operation`` parameter should be an expression which uses the variables - ## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the - ## start value (the first ``a``) and therefor defines the type of the result. + ## The `operation` parameter should be an expression which uses the variables + ## `a` and `b` for each step of the fold. The `first` parameter is the + ## start value (the first `a`) and therefor defines the type of the result. ## ## See also: ## * `foldr template<#foldr.t,untyped,untyped>`_ @@ -893,10 +895,10 @@ template foldr*(sequence, operation: untyped): untyped = ## The sequence is required to have at least a single element. Debug versions ## of your program will assert in this situation but release versions will ## happily go ahead. If the sequence has a single element it will be returned - ## without applying ``operation``. + ## without applying `operation`. ## - ## The ``operation`` parameter should be an expression which uses the - ## variables ``a`` and ``b`` for each step of the fold. Since this is a right + ## The `operation` parameter should be an expression which uses the + ## variables `a` and `b` for each step of the fold. Since this is a right ## fold, for non associative binary operations like subtraction think that ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 - ## (3))). @@ -936,7 +938,7 @@ template mapIt*(s: typed, op: untyped): untyped = ## Since the input is not modified you can use it to ## transform the type of the elements in the input container. ## - ## The template injects the ``it`` variable which you can use directly in an + ## The template injects the `it` variable which you can use directly in an ## expression. ## ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro @@ -1005,9 +1007,9 @@ template mapIt*(s: typed, op: untyped): untyped = map(s, f) template applyIt*(varSeq, op: untyped) = - ## Convenience template around the mutable ``apply`` func to reduce typing. + ## Convenience template around the mutable `apply` func to reduce typing. ## - ## The template injects the ``it`` variable which you can use directly in an + ## The template injects the `it` variable which you can use directly in an ## expression. The expression has to return the same type as the sequence you ## are mutating. ## @@ -1064,42 +1066,32 @@ func mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; macro mapLiterals*(constructor, op: untyped; nested = true): untyped = - ## Applies ``op`` to each of the **atomic** literals like ``3`` - ## or ``"abc"`` in the specified ``constructor`` AST. This can + ## Applies `op` to each of the **atomic** literals like `3` + ## or `"abc"` in the specified `constructor` AST. This can ## be used to map every array element to some target type: - ## - ## Example: - ## - ## .. code-block:: - ## let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) - ## doAssert x is array[4, int] - ## - ## Short notation for: - ## - ## .. code-block:: - ## let x = [int(0.1), int(1.2), int(2.3), int(3.4)] - ## - ## If ``nested`` is true (which is the default), the literals are replaced - ## everywhere in the ``constructor`` AST, otherwise only the first level + runnableExamples: + let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) + doAssert x is array[4, int] + doAssert x == [int(0.1), int(1.2), int(2.3), int(3.4)] + ## If `nested` is true (which is the default), the literals are replaced + ## everywhere in the `constructor` AST, otherwise only the first level ## is considered: - ## - ## .. code-block:: - ## let a = mapLiterals((1.2, (2.3, 3.4), 4.8), int) - ## let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false) - ## assert a == (1, (2, 3), 4) - ## assert b == (1, (2.3, 3.4), 4) - ## - ## let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`) - ## let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false) - ## assert c == ("1", ("2", "3"), "4", ("5", "6")) - ## assert d == ("1", (2, 3), "4", (5, 6)) - ## - ## There are no constraints for the ``constructor`` AST, it + runnableExamples: + let a = mapLiterals((1.2, (2.3, 3.4), 4.8), int) + let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false) + assert a == (1, (2, 3), 4) + assert b == (1, (2.3, 3.4), 4) + + let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`) + let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false) + assert c == ("1", ("2", "3"), "4", ("5", "6")) + assert d == ("1", (2, 3), "4", (5, 6)) + ## There are no constraints for the `constructor` AST, it ## works for nested tuples of arrays of sets etc. result = mapLitsImpl(constructor, op, nested.boolVal) iterator items*[T](xs: iterator: T): T = - ## iterates over each element yielded by a closure iterator. This may + ## Iterates over each element yielded by a closure iterator. This may ## not seem particularly useful on its own, but this allows closure ## iterators to be used by the mapIt, filterIt, allIt, anyIt, etc. ## templates. From 2728711dd3dbe8b1c2cd7dd6f15f696b58b77ea6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 14 Dec 2020 08:49:39 -0800 Subject: [PATCH 1657/4254] fix #16248 forward --lib to runnableExamples (#16350) --- compiler/docgen.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 7b3b62174..824fafd6b 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -468,10 +468,11 @@ proc runAllExamples(d: PDoc) = writeFile(outp, group.code) # most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override # via command line - let cmd = "$nim $backend -r --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [ + let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [ "nim", os.getAppFilename(), "backend", $d.conf.backend, "path", quoteShell(d.conf.projectPath), + "libpath", quoteShell(d.conf.libpath), "nimcache", quoteShell(outputDir), "file", quoteShell(outp), "rdoccmd", group.rdoccmd, From e843492b1334ded1d8fcd0e0eb6dc94fcf970aba Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 14 Dec 2020 20:10:39 +0300 Subject: [PATCH 1658/4254] doc/rst2html: some few fixes for enumerated and bullet lists (#16295) * fix bullet/enumarated lists with many blank lines * fix enumerated list parsing * fix parse failure when next line after list empty * implement arbitrary start of enumerator * check that enumerators are in order * remove redundant start=x if x=1 or a * add some doc on implemented features * update start in rst_examples.rst * allow upper-case letters + more docs --- config/nimdoc.tex.cfg | 1 + lib/packages/docutils/rst.nim | 137 ++++++++++++++++---- lib/packages/docutils/rstast.nim | 2 +- lib/packages/docutils/rstgen.nim | 54 +++++++- nimdoc/rst2html/expected/rst_examples.html | 14 ++- tests/stdlib/trstgen.nim | 138 +++++++++++++++++++++ 6 files changed, 309 insertions(+), 37 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 76fef4afa..3e5e5d38b 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -50,6 +50,7 @@ doc.file = """ \usepackage{fancyvrb, courier} \usepackage{tabularx} \usepackage{hyperref} +\usepackage{enumitem} \begin{document} \title{$title $version} diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index bc3efa272..709173526 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -11,6 +11,59 @@ ## subset is implemented. Some features of the `markdown`:idx: wiki syntax are ## also supported. ## +## Supported RST features: +## +## * body elements +## + sections +## + transitions +## + paragraphs +## + bullet lists using \+, \*, \- +## + enumerated lists using arabic numerals or alphabet +## characters: 1. ... 2. ... *or* a. ... b. ... *or* A. ... B. ... +## + definition lists +## + field lists +## + option lists +## + indented literal blocks +## + simple tables +## + directives +## - image, figure +## - code-block +## - substitution definitions: replace and image +## - ... a few more +## + comments +## * inline markup +## + *emphasis*, **strong emphasis**, `interpreted text`, +## ``inline literals``, hyperlink references, substitution references, +## standalone hyperlinks +## +## Additional features: +## +## * ***triple emphasis*** (bold and italic) using \*\*\* +## +## Optional additional features, turned on by ``options: RstParseOption`` in +## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_: +## +## * emoji / smiley symbols +## * markdown tables +## * markdown code blocks +## * markdown links +## * markdown headlines +## +## Limitations: +## +## * no Unicode support in character width calculations +## * body elements +## - no roman numerals in enumerated lists +## - no quoted literal blocks +## - no doctest blocks +## - no grid tables +## - directives: no support for admonitions (notes, caution) +## - no footnotes & citations support +## - no inline internal targets +## * inline markup +## - no simple-inline-markup +## - no embedded URI and aliases +## ## **Note:** Import ``packages/docutils/rst`` to use this module import @@ -569,7 +622,9 @@ proc match(p: RstParser, start: int, expr: string): bool = # 'p' tkPunct # 'T' always true # 'E' whitespace, indent or eof - # 'e' tkWord or '#' (for enumeration lists) + # 'e' any enumeration sequence or '#' (for enumeration lists) + # 'x' a..z or '#' (for enumeration lists) + # 'n' 0..9 or '#' (for enumeration lists) var i = 0 var j = start var last = expr.len - 1 @@ -583,12 +638,16 @@ proc match(p: RstParser, start: int, expr: string): bool = of 'o': result = p.tok[j].kind == tkOther of 'T': result = true of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent} - of 'e': + of 'e', 'x', 'n': result = p.tok[j].kind == tkWord or p.tok[j].symbol == "#" if result: case p.tok[j].symbol[0] - of 'a'..'z', 'A'..'Z', '#': result = p.tok[j].symbol.len == 1 - of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'}) + of '#': result = true + of 'a'..'z', 'A'..'Z': + result = expr[i] in {'e', 'x'} and p.tok[j].symbol.len == 1 + of '0'..'9': + result = expr[i] in {'e', 'n'} and + allCharsInSet(p.tok[j].symbol, {'0'..'9'}) else: result = false else: var c = expr[i] @@ -1465,33 +1524,55 @@ proc parseDefinitionList(p: var RstParser): PRstNode = proc parseEnumList(p: var RstParser): PRstNode = const - wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "] - wildpos: array[0..2, int] = [1, 0, 0] - result = nil + wildcards: array[0..5, string] = ["(n) ", "n) ", "n. ", + "(x) ", "x) ", "x. "] + # enumerator patterns, where 'x' means letter and 'n' means number + wildToken: array[0..5, int] = [4, 3, 3, 4, 3, 3] # number of tokens + wildIndex: array[0..5, int] = [1, 0, 0, 1, 0, 0] + # position of enumeration sequence (number/letter) in enumerator + result = newRstNode(rnEnumList) + let col = currentTok(p).col var w = 0 - while w <= 2: + while w < wildcards.len: if match(p, p.idx, wildcards[w]): break inc w - if w <= 2: - var col = currentTok(p).col - result = newRstNode(rnEnumList) - inc p.idx, wildpos[w] + 3 - var j = tokenAfterNewline(p) - if p.tok[j].col == currentTok(p).col or match(p, j, wildcards[w]): - pushInd(p, currentTok(p).col) - while true: - var item = newRstNode(rnEnumItem) - parseSection(p, item) - result.add(item) - if currentTok(p).kind == tkIndent and currentTok(p).ival == col and - match(p, p.idx + 1, wildcards[w]): - inc p.idx, wildpos[w] + 4 - else: - break - popInd(p) + assert w < wildcards.len + for i in 0 ..< wildToken[w]-1: # add first enumerator with (, ), and . + if p.tok[p.idx + i].symbol == "#": + result.text.add "1" else: - dec p.idx, wildpos[w] + 3 - result = nil + result.text.add p.tok[p.idx + i].symbol + var prevEnum = p.tok[p.idx + wildIndex[w]].symbol + inc p.idx, wildToken[w] + while true: + var item = newRstNode(rnEnumItem) + pushInd(p, currentTok(p).col) + parseSection(p, item) + popInd(p) + result.add(item) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col and + match(p, p.idx+1, wildcards[w]): + let enumerator = p.tok[p.idx + 1 + wildIndex[w]].symbol + # check that it's in sequence: enumerator == next(prevEnum) + if "n" in wildcards[w]: # arabic numeral + let prevEnumI = try: parseInt(prevEnum) except: 1 + let curEnum = + if enumerator == "#": prevEnumI + 1 + else: (try: parseInt(enumerator) except: 1) + if curEnum - prevEnumI != 1: + break + prevEnum = enumerator + else: # a..z + let prevEnumI = ord(prevEnum[0]) + let curEnum = + if enumerator == "#": prevEnumI + 1 + else: ord(enumerator[0]) + if curEnum - prevEnumI != 1: + break + prevEnum = $chr(curEnum) + inc p.idx, 1 + wildToken[w] + else: + break proc sonKind(father: PRstNode, i: int): RstNodeKind = result = rnLeaf @@ -1511,6 +1592,8 @@ proc parseSection(p: var RstParser, result: PRstNode) = result.add(a) popInd(p) else: + while currentTok(p).kind != tkEof and nextTok(p).kind == tkIndent: + inc p.idx # skip blank lines leave = true break if leave or currentTok(p).kind == tkEof: break diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 8b2159aeb..5e2d21c04 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -69,7 +69,7 @@ type RstNode* {.acyclic, final.} = object ## an RST node's description kind*: RstNodeKind ## the node's kind text*: string ## valid for leafs in the AST; and the title of - ## the document or the section + ## the document or the section; and rnEnumList level*: int ## valid for some node kinds sons*: RstNodeSeq ## the node's sons diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index d88f2ed77..4d056a83e 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1029,6 +1029,56 @@ proc renderField(d: PDoc, n: PRstNode, result: var string) = if not b: renderAux(d, n, "$1\n", "$1", result) +proc renderEnumList(d: PDoc, n: PRstNode, result: var string) = + var + specifier = "" + specStart = "" + i1 = 0 + pre = "" + i2 = n.text.len-1 + post = "" + if n.text[0] == '(': + i1 = 1 + pre = "(" + if n.text[^1] == ')' or n.text[^1] == '.': + i2 = n.text.len-2 + post = $n.text[^1] + let enumR = i1 .. i2 # enumerator range without surrounding (, ), . + if d.target == outLatex: + result.add ("\n%"&n.text&"\n") + # use enumerate parameters from package enumitem + if n.text[i1].isDigit: + var labelDef = "" + if pre != "" or post != "": + labelDef = "label=" & pre & "\\arabic*" & post & "," + if n.text[enumR] != "1": + specStart = "start=$1" % [n.text[enumR]] + if labelDef != "" or specStart != "": + specifier = "[$1$2]" % [labelDef, specStart] + else: + let (first, labelDef) = + if n.text[i1].isUpperAscii: ('A', "label=" & pre & "\\Alph*" & post) + else: ('a', "label=" & pre & "\\alph*" & post) + if n.text[i1] != first: + specStart = ",start=" & $(ord(n.text[i1]) - ord(first) + 1) + specifier = "[$1$2]" % [labelDef, specStart] + else: # HTML + # TODO: implement enumerator formatting using pre and post ( and ) for HTML + if n.text[i1].isDigit: + if n.text[enumR] != "1": + specStart = " start=\"$1\"" % [n.text[enumR]] + specifier = "class=\"simple\"" & specStart + else: + let (first, labelDef) = + if n.text[i1].isUpperAscii: ('A', "class=\"upperalpha simple\"") + else: ('a', "class=\"loweralpha simple\"") + if n.text[i1] != first: + specStart = " start=\"$1\"" % [ $(ord(n.text[i1]) - ord(first) + 1) ] + specifier = labelDef & specStart + renderAux(d, n, "
      $1
    \n", + "\\begin{enumerate}" & specifier & "$1\\end{enumerate}\n", + result) + proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = if n == nil: return case n.kind @@ -1042,9 +1092,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = "\\begin{itemize}$1\\end{itemize}\n", result) of rnBulletItem, rnEnumItem: renderAux(d, n, "
  • $1
  • \n", "\\item $1\n", result) - of rnEnumList: - renderAux(d, n, "
      $1
    \n", - "\\begin{enumerate}$1\\end{enumerate}\n", result) + of rnEnumList: renderEnumList(d, n, result) of rnDefList: renderAux(d, n, "
    $1
    \n", "\\begin{description}$1\\end{description}\n", result) diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 0b9207688..a95fac0bd 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -274,15 +274,17 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements
  • An input parameter should not be aliased with a global or thread local variable updated by the called proc.
  • One problem with rules 3 and 4 is that they affect specific global or thread local variables, but Nim's effect tracking only tracks "uses no global variable" via .noSideEffect. The rules 3 and 4 can also be approximated by a different rule:

    -
    1. A global or thread local variable (or a location derived from such a location) can only passed to a parameter of a .noSideEffect proc.
    2. +
      1. A global or thread local variable (or a location derived from such a location) can only passed to a parameter of a .noSideEffect proc.

      These two procs are the two modus operandi of the real-time garbage collector:

      -

      (1) GC_SetMaxPause Mode

      -

      You can call GC_SetMaxPause at program startup and then each triggered garbage collector run tries to not take longer than maxPause time. However, it is possible (and common) that the work is nevertheless not evenly distributed as each call to new can trigger the garbage collector and thus take maxPause time.

      -

      (2) GC_step Mode

      -

      This allows the garbage collector to perform some work for up to us time. This is useful to call in the main loop to ensure the garbage collector can do its work. To bind all garbage collector activity to a GC_step call, deactivate the garbage collector with GC_disable at program startup. If strongAdvice is set to true, then the garbage collector will be forced to perform the collection cycle. Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. You may also specify the current stack size via stackSize parameter. It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

      +
      1. GC_SetMaxPause Mode

        +

        You can call GC_SetMaxPause at program startup and then each triggered garbage collector run tries to not take longer than maxPause time. However, it is possible (and common) that the work is nevertheless not evenly distributed as each call to new can trigger the garbage collector and thus take maxPause time.

        +
      2. +
      3. GC_step Mode

        +

        This allows the garbage collector to perform some work for up to us time. This is useful to call in the main loop to ensure the garbage collector can do its work. To bind all garbage collector activity to a GC_step call, deactivate the garbage collector with GC_disable at program startup. If strongAdvice is set to true, then the garbage collector will be forced to perform the collection cycle. Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. You may also specify the current stack size via stackSize parameter. It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

        It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size.

        -

      + +

    These procs provide a "best effort" real-time guarantee; in particular the cycle collector is not aware of deadlines. Deactivate it to get more predictable real-time behaviour. Tests show that a 1ms max pause time will be met in almost all cases on modern CPUs (with the cycle collector disabled).

    Time measurement with garbage collectors

    The garbage collectors' way of measuring time uses (see lib/system/timers.nim for the implementation):

    diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 8b12a89c4..f3a8aa59a 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -361,6 +361,144 @@ Test1 assert "line block\\\\" in output1l assert "other line\\\\" in output1l + test "RST enumerated lists": + let input1 = dedent """ + 1. line1 + 1 + 2. line2 + 2 + + 3. line3 + 3 + + + 4. line4 + 4 + + + + 5. line5 + 5 + """ + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + for i in 1..5: + assert ($i & ". line" & $i) notin output1 + assert ("
  • line" & $i & " " & $i & "
  • ") in output1 + + let input2 = dedent """ + 3. line3 + + 4. line4 + + + 5. line5 + + + + 7. line7 + + + + + 8. line8 + """ + let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + for i in [3, 4, 5, 7, 8]: + assert ($i & ". line" & $i) notin output2 + assert ("
  • line" & $i & "
  • ") in output2 + + # check that nested enumerated lists work + let input3 = dedent """ + 1. a) string1 + 2. string2 + """ + let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) + assert count(output3, "
      ") == 2 + assert "
    1. string1
    2. " in output3 and "
    3. string2
    4. " in output3 + + let input4 = dedent """ + Check that enumeration specifiers are respected + + 9. string1 + 10. string2 + 12. string3 + + b) string4 + c) string5 + e) string6 + """ + let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig()) + assert count(output4, "
        ") == 4 + for enumerator in [9, 12]: + assert "start=\"$1\"" % [$enumerator] in output4 + for enumerator in [2, 5]: # 2=b, 5=e + assert "start=\"$1\"" % [$enumerator] in output4 + + let input5 = dedent """ + Check that auto-numbered enumeration lists work. + + #. string1 + #. string2 + #. string3 + """ + let output5 = rstToHtml(input5, {roSupportMarkdown}, defaultConfig()) + assert count(output5, "
          ") == 1 + assert count(output5, "
        1. ") == 3 + + let input6 = dedent """ + ... And for alphabetic enumerators too! + + b. string1 + #. string2 + #. string3 + """ + let output6 = rstToHtml(input6, {roSupportMarkdown}, defaultConfig()) + assert count(output6, "
            ") == 1 + assert count(output6, "
          1. ") == 3 + assert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6 + + let input7 = dedent """ + ... And for uppercase alphabetic enumerators. + + C. string1 + #. string2 + #. string3 + """ + let output7 = rstToHtml(input7, {roSupportMarkdown}, defaultConfig()) + assert count(output7, "
              ") == 1 + assert count(output7, "
            1. ") == 3 + assert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7 + + test "RST bullet lists": + let input1 = dedent """ + * line1 + 1 + * line2 + 2 + + * line3 + 3 + + + * line4 + 4 + + + + * line5 + 5 + """ + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + for i in 1..5: + assert ("
            2. line" & $i & " " & $i & "
            3. ") in output1 + assert count(output1, "
                ") == 1 + suite "RST/Code highlight": test "Basic Python code highlight": let pythonCode = """ From f3d57761abc425f546985af407f178d71db20b78 Mon Sep 17 00:00:00 2001 From: Elliot Waite Date: Mon, 14 Dec 2020 11:13:12 -0800 Subject: [PATCH 1659/4254] Fix broken links in docs (#16336) * Fix broken links in docs * Fix rand HSlice links --- doc/docgen.rst | 2 +- doc/manual.rst | 4 +-- doc/tut1.rst | 4 +-- lib/js/dom.nim | 2 +- lib/pure/asyncdispatch.nim | 2 +- lib/pure/collections/sets.nim | 20 +++++------ lib/pure/collections/tables.nim | 54 ++++++++++++++--------------- lib/pure/concurrency/threadpool.nim | 2 +- lib/pure/httpclient.nim | 4 +-- lib/pure/logging.nim | 8 ++--- lib/pure/net.nim | 2 +- lib/pure/osproc.nim | 2 +- lib/pure/random.nim | 28 +++++++++------ lib/pure/smtp.nim | 4 +-- lib/pure/unicode.nim | 2 +- lib/std/jsonutils.nim | 8 ++--- lib/std/packedsets.nim | 6 ++-- lib/system.nim | 24 ++++++------- lib/system/assertions.nim | 2 +- lib/system/memalloc.nim | 24 ++++++------- lib/system_overview.rst | 42 +++++++++++----------- 21 files changed, 126 insertions(+), 120 deletions(-) diff --git a/doc/docgen.rst b/doc/docgen.rst index 612465671..bbf0838bb 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -316,7 +316,7 @@ symbols in the `system module `_. * ``proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}`` **=>** `#len,seq[T] `_ * ``iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}`` **=>** - `#pairs.i,seq[T] `_ + `#pairs.i,seq[T] `_ * ``template newException[](exceptn: typedesc; message: string; parentException: ref Exception = nil): untyped`` **=>** `#newException.t,typedesc,string,ref.Exception diff --git a/doc/manual.rst b/doc/manual.rst index 97dbbda13..cb35ee885 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1778,7 +1778,7 @@ dereferencing operations for reference types: Automatic dereferencing can be performed for the first argument of a routine call, but this is an experimental feature and is described `here -`_. +`_. In order to simplify structural type checking, recursive tuples are not valid: @@ -3653,7 +3653,7 @@ Creating closures in loops Since closures capture local variables by reference it is often not wanted behavior inside loop bodies. See `closureScope `_ and `capture -`_ for details on how to change this behavior. +`_ for details on how to change this behavior. Anonymous Procs --------------- diff --git a/doc/tut1.rst b/doc/tut1.rst index cb4dc1cc9..397782330 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1315,11 +1315,11 @@ Sequence variables are initialized with ``@[]``. The ``for`` statement can be used with one or two variables when used with a sequence. When you use the one variable form, the variable will hold the value provided by the sequence. The ``for`` statement is looping over the results -from the `items() `_ iterator from the `system +from the `items() `_ iterator from the `system `_ module. But if you use the two-variable form, the first variable will hold the index position and the second variable will hold the value. Here the ``for`` statement is looping over the results from the -`pairs() `_ iterator from the `system +`pairs() `_ iterator from the `system `_ module. Examples: .. code-block:: nim diff --git a/lib/js/dom.nim b/lib/js/dom.nim index b74a58a1a..4dbb4f77a 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -107,7 +107,7 @@ type timing*: PerformanceTiming Range* {.importc.} = ref object - ## see `docs{https://developer.mozilla.org/en-US/docs/Web/API/Range}`_ + ## see `docs`_ collapsed*: bool commonAncestorContainer*: Node endContainer*: Node diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index e111f9e7d..1b3548268 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -235,7 +235,7 @@ template implementSetInheritable() {.dirty.} = ## Returns ``true`` on success. ## ## This procedure is not guaranteed to be available for all platforms. - ## Test for availability with `declared()`_. + ## Test for availability with `declared() `_. fd.FileHandle.setInheritable(inheritable) when defined(windows) or defined(nimdoc): diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index faa2f8c71..a9df9ded8 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -64,7 +64,7 @@ type HashSet*[A] {.myShallow.} = object ## \ ## A generic hash set. ## - ## Use `init proc <#init,HashSet[A],int>`_ or `initHashSet proc <#initHashSet,int>`_ + ## Use `init proc <#init,HashSet[A]>`_ or `initHashSet proc <#initHashSet,int>`_ ## before calling other procs on it. data: KeyValuePairSeq[A] counter: int @@ -76,8 +76,8 @@ type OrderedSet*[A] {.myShallow.} = object ## \ ## A generic hash set that remembers insertion order. ## - ## Use `init proc <#init,OrderedSet[A],int>`_ or `initOrderedSet proc - ## <#initOrderedSet,int>`_ before calling other procs on it. + ## Use `init proc <#init,OrderedSet[A]>`_ or `initOrderedSet proc + ## <#initOrderedSet>`_ before calling other procs on it. data: OrderedKeyValuePairSeq[A] counter, first, last: int SomeSet*[A] = HashSet[A] | OrderedSet[A] @@ -104,7 +104,7 @@ proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) = ## existing values and calling `excl() <#excl,HashSet[A],A>`_ on them. ## ## See also: - ## * `initHashSet proc <#initHashSet,int>`_ + ## * `initHashSet proc <#initHashSet>`_ ## * `toHashSet proc <#toHashSet,openArray[A]>`_ runnableExamples: var a: HashSet[int] @@ -113,7 +113,7 @@ proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) = initImpl(s, initialSize) proc initHashSet*[A](initialSize = defaultInitialSize): HashSet[A] = - ## Wrapper around `init proc <#init,HashSet[A],int>`_ for initialization of + ## Wrapper around `init proc <#init,HashSet[A]>`_ for initialization of ## hash sets. ## ## Returns an empty hash set you can assign directly in ``var`` blocks in a @@ -209,7 +209,7 @@ proc toHashSet*[A](keys: openArray[A]): HashSet[A] = ## Duplicates are removed. ## ## See also: - ## * `initHashSet proc <#initHashSet,int>`_ + ## * `initHashSet proc <#initHashSet>`_ runnableExamples: let a = toHashSet([5, 3, 2]) @@ -601,7 +601,7 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] {.deprecated: proc isValid*[A](s: HashSet[A]): bool {.deprecated: "Deprecated since v0.20; sets are initialized by default".} = ## Returns `true` if the set has been initialized (with `initHashSet proc - ## <#initHashSet,int>`_ or `init proc <#init,HashSet[A],int>`_). + ## <#initHashSet>`_ or `init proc <#init,HashSet[A]>`_). ## ## **Examples:** ## @@ -640,7 +640,7 @@ proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) = ## existing values and calling `excl() <#excl,HashSet[A],A>`_ on them. ## ## See also: - ## * `initOrderedSet proc <#initOrderedSet,int>`_ + ## * `initOrderedSet proc <#initOrderedSet>`_ ## * `toOrderedSet proc <#toOrderedSet,openArray[A]>`_ runnableExamples: var a: OrderedSet[int] @@ -649,7 +649,7 @@ proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) = initImpl(s, initialSize) proc initOrderedSet*[A](initialSize = defaultInitialSize): OrderedSet[A] = - ## Wrapper around `init proc <#init,OrderedSet[A],int>`_ for initialization of + ## Wrapper around `init proc <#init,OrderedSet[A]>`_ for initialization of ## ordered hash sets. ## ## Returns an empty ordered hash set you can assign directly in ``var`` blocks @@ -674,7 +674,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = ## Duplicates are removed. ## ## See also: - ## * `initOrderedSet proc <#initOrderedSet,int>`_ + ## * `initOrderedSet proc <#initOrderedSet>`_ runnableExamples: let a = toOrderedSet([5, 3, 2]) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index a0efcdce2..d7376b065 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -135,7 +135,7 @@ ## ## The same could have been achieved by manually iterating over a container ## and increasing each key's value with `inc proc -## <#inc,CountTable[A],A,Positive>`_: +## <#inc,CountTable[A],A,int>`_: ## ## .. code-block:: ## import tables @@ -230,13 +230,13 @@ type ## `data` and `counter` are internal implementation details which ## can't be accessed. ## - ## For creating an empty Table, use `initTable proc<#initTable,int>`_. + ## For creating an empty Table, use `initTable proc<#initTable>`_. data: KeyValuePairSeq[A, B] counter: int TableRef*[A, B] = ref Table[A, B] ## Ref version of `Table<#Table>`_. ## ## For creating a new empty TableRef, use `newTable proc - ## <#newTable,int>`_. + ## <#newTable>`_. const defaultInitialSize* = 32 @@ -293,7 +293,7 @@ proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] = ## ## See also: ## * `toTable proc<#toTable,openArray[]>`_ - ## * `newTable proc<#newTable,int>`_ for creating a `TableRef` + ## * `newTable proc<#newTable>`_ for creating a `TableRef` runnableExamples: let a = initTable[int, string]() @@ -322,7 +322,7 @@ proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] = ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `initTable proc<#initTable,int>`_ + ## * `initTable proc<#initTable>`_ ## * `newTable proc<#newTable,openArray[]>`_ for a `TableRef` version runnableExamples: let a = [('a', 5), ('b', 9)] @@ -771,7 +771,7 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B {.deprecated: ## Iterates over any value in the table ``t`` that belongs to the given ``key``. ## ## Used if you have a table with duplicate keys (as a result of using - ## `add proc<#add,Table[A,B],A,B>`_). + ## `add proc<#add,Table[A,B],A,sinkB>`_). ## runnableExamples: import sequtils, algorithm @@ -801,7 +801,7 @@ proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = ## See also: ## * `newTable proc<#newTable,openArray[]>`_ for creating a `TableRef` ## from a collection of `(key, value)` pairs - ## * `initTable proc<#initTable,int>`_ for creating a `Table` + ## * `initTable proc<#initTable>`_ for creating a `Table` runnableExamples: let a = newTable[int, string]() @@ -816,7 +816,7 @@ proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `newTable proc<#newTable,int>`_ + ## * `newTable proc<#newTable>`_ ## * `toTable proc<#toTable,openArray[]>`_ for a `Table` version runnableExamples: let a = [('a', 5), ('b', 9)] @@ -845,7 +845,7 @@ proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,TableRef[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,TableRef[A,B],A,B>`_ for inserting a new + ## * `[]= proc<#[]=,TableRef[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ for checking if a key is in ## the table @@ -1008,7 +1008,7 @@ proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated: ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,TableRef[A,B],A,B>`_ for inserting a new + ## Use `[]= proc<#[]=,TableRef[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. t[].add(key, val) @@ -1228,14 +1228,14 @@ type ## Hash table that remembers insertion order. ## ## For creating an empty OrderedTable, use `initOrderedTable proc - ## <#initOrderedTable,int>`_. + ## <#initOrderedTable>`_. data: OrderedKeyValuePairSeq[A, B] counter, first, last: int OrderedTableRef*[A, B] = ref OrderedTable[A, B] ## Ref version of ## `OrderedTable<#OrderedTable>`_. ## ## For creating a new empty OrderedTableRef, use `newOrderedTable proc - ## <#newOrderedTable,int>`_. + ## <#newOrderedTable>`_. # ------------------------------ helpers --------------------------------- @@ -1294,7 +1294,7 @@ proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A, ## ## See also: ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_ - ## * `newOrderedTable proc<#newOrderedTable,int>`_ for creating an + ## * `newOrderedTable proc<#newOrderedTable>`_ for creating an ## `OrderedTableRef` runnableExamples: let @@ -1324,7 +1324,7 @@ proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] = ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `initOrderedTable proc<#initOrderedTable,int>`_ + ## * `initOrderedTable proc<#initOrderedTable>`_ ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for an ## `OrderedTableRef` version runnableExamples: @@ -1347,7 +1347,7 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new + ## * `[]= proc<#[]=,OrderedTable[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for checking if a ## key is in the table @@ -1369,7 +1369,7 @@ proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,OrderedTable[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new + ## * `[]= proc<#[]=,OrderedTable[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,OrderedTable[A,B],A>`_ for checking if a ## key is in the table @@ -1495,7 +1495,7 @@ proc add*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) {.deprecated: ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,OrderedTable[A,B],A,B>`_ for inserting a new + ## Use `[]= proc<#[]=,OrderedTable[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. addImpl(enlarge) @@ -1796,7 +1796,7 @@ proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableR ## See also: ## * `newOrderedTable proc<#newOrderedTable,openArray[]>`_ for creating ## an `OrderedTableRef` from a collection of `(key, value)` pairs - ## * `initOrderedTable proc<#initOrderedTable,int>`_ for creating an + ## * `initOrderedTable proc<#initOrderedTable>`_ for creating an ## `OrderedTable` runnableExamples: let @@ -1811,7 +1811,7 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] ## ``pairs`` is a container consisting of ``(key, value)`` tuples. ## ## See also: - ## * `newOrderedTable proc<#newOrderedTable,int>`_ + ## * `newOrderedTable proc<#newOrderedTable>`_ ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_ for an ## `OrderedTable` version runnableExamples: @@ -1835,7 +1835,7 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,OrderedTableRef[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,OrderedTableRef[A,B],A,B>`_ for inserting a new + ## * `[]= proc<#[]=,OrderedTableRef[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ for checking if ## a key is in the table @@ -1981,7 +1981,7 @@ proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) {.deprecated: ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,OrderedTableRef[A,B],A,B>`_ for inserting a new + ## Use `[]= proc<#[]=,OrderedTableRef[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. t[].add(key, val) @@ -2208,7 +2208,7 @@ type ## Hash table that counts the number of each key. ## ## For creating an empty CountTable, use `initCountTable proc - ## <#initCountTable,int>`_. + ## <#initCountTable>`_. data: seq[tuple[key: A, val: int]] counter: int isSorted: bool @@ -2216,7 +2216,7 @@ type ## `CountTable<#CountTable>`_. ## ## For creating a new empty CountTableRef, use `newCountTable proc - ## <#newCountTable,int>`_. + ## <#newCountTable>`_. # ------------------------------ helpers --------------------------------- @@ -2260,7 +2260,7 @@ proc initCountTable*[A](initialSize = defaultInitialSize): CountTable[A] = ## ## See also: ## * `toCountTable proc<#toCountTable,openArray[A]>`_ - ## * `newCountTable proc<#newCountTable,int>`_ for creating a + ## * `newCountTable proc<#newCountTable>`_ for creating a ## `CountTableRef` initImpl(result, initialSize) @@ -2294,7 +2294,7 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = ## ## See also: ## * `[] proc<#[],CountTable[A],A>`_ for retrieving a value of a key - ## * `inc proc<#inc,CountTable[A],A,Positive>`_ for incrementing a + ## * `inc proc<#inc,CountTable[A],A,int>`_ for incrementing a ## value of a key assert(not t.isSorted, "CountTable must not be used after sorting") assert val >= 0 @@ -2617,7 +2617,7 @@ proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = ## See also: ## * `newCountTable proc<#newCountTable,openArray[A]>`_ for creating ## a `CountTableRef` from a collection - ## * `initCountTable proc<#initCountTable,int>`_ for creating a + ## * `initCountTable proc<#initCountTable>`_ for creating a ## `CountTable` new(result) result[] = initCountTable[A](initialSize) @@ -2635,7 +2635,7 @@ proc `[]`*[A](t: CountTableRef[A], key: A): int = ## See also: ## * `getOrDefault<#getOrDefault,CountTableRef[A],A,int>`_ to return ## a custom value if the key doesn't exist - ## * `inc proc<#inc,CountTableRef[A],A>`_ to inc even if missing + ## * `inc proc<#inc,CountTableRef[A],A,int>`_ to inc even if missing ## * `[]= proc<#[]%3D,CountTableRef[A],A,int>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,CountTableRef[A],A>`_ for checking if a key diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index f0269f526..34a65ead2 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -468,7 +468,7 @@ template spawnX*(call) = ## Spawns a new task if a CPU core is ready, otherwise executes the ## call in the calling thread. ## - ## Usually it is advised to use `spawn proc <#spawn,typed>`_ in order to + ## Usually it is advised to use `spawn proc <#spawn,sinktyped>`_ in order to ## not block the producer for an unknown amount of time. ## ## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 880c05765..3093f5564 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -129,7 +129,7 @@ ## A set of directories and files from the `ssl_certs `_ ## module are scanned to locate CA certificates. ## -## See `newContext `_ to tweak or disable certificate validation. +## See `newContext `_ to tweak or disable certificate validation. ## ## Timeouts ## ======== @@ -565,7 +565,7 @@ proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, ## default is 5. ## ## ``sslContext`` specifies the SSL context to use for HTTPS requests. - ## See `SSL/TLS support <##ssl-tls-support>`_ + ## See `SSL/TLS support <#sslslashtls-support>`_ ## ## ``proxy`` specifies an HTTP proxy to use for this HTTP client's ## connections. diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index fa6285a04..06987d395 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -246,7 +246,7 @@ when not defined(js): ## rotation. ## ## Create a new ``RollingFileLogger`` with the `newRollingFileLogger proc - ## <#newRollingFileLogger,FileMode,int,int>`_. + ## <#newRollingFileLogger,FileMode,Positive,int>`_. ## ## **Note:** This logger is not available for the JavaScript backend. ## @@ -395,7 +395,7 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_ ## that accepts a filename - ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_ + ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,Positive,int>`_ ## ## **Examples:** ## @@ -460,7 +460,7 @@ when not defined(js): ## * `newConsoleLogger proc<#newConsoleLogger>`_ ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_ ## that accepts a filename - ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_ + ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,Positive,int>`_ ## ## **Examples:** ## @@ -496,7 +496,7 @@ when not defined(js): ## See also: ## * `newConsoleLogger proc<#newConsoleLogger>`_ ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle - ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_ + ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,Positive,int>`_ ## ## **Examples:** ## diff --git a/lib/pure/net.nim b/lib/pure/net.nim index cd509463a..02441e8a0 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -21,7 +21,7 @@ ## ## In order to use the SSL procedures defined in this module, you will need to ## compile your application with the ``-d:ssl`` flag. See the -## `newContext`_ +## `newContext`_ ## procedure for additional details. ## ## Examples diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index a7c6c3754..d6943c7f8 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -106,7 +106,7 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", ## This operation is also often called `system`:idx:. ## ## See also: - ## * `execCmdEx proc <#execCmdEx,string,set[ProcessOption]>`_ + ## * `execCmdEx proc <#execCmdEx,string,set[ProcessOption],StringTableRef,string,string>`_ ## * `startProcess proc ## <#startProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## * `execProcess proc diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 683140cd8..d599727c3 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -11,7 +11,7 @@ ## ## Its implementation is based on the ``xoroshiro128+`` ## (xor/rotate/shift/rotate) library. -## * More information: http://xoroshiro.di.unimi.it/ +## * More information: http://xoroshiro.di.unimi.it ## * C implementation: http://xoroshiro.di.unimi.it/xoroshiro128plus.c ## ## **Do not use this module for cryptographic purposes!** @@ -135,7 +135,8 @@ proc next*(r: var Rand): uint64 = ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer between zero and ## a given upper bound ## * `rand proc<#rand,Rand,range[]>`_ that returns a float - ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type ## * `skipRandomNumbers proc<#skipRandomNumbers,Rand>`_ runnableExamples: @@ -220,7 +221,8 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = ## * `rand proc<#rand,int>`_ that returns an integer using the default ## random number generator ## * `rand proc<#rand,Rand,range[]>`_ that returns a float - ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: var r = initRand(123) @@ -246,7 +248,8 @@ proc rand*(max: int): int {.benign.} = ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a ## provided state ## * `rand proc<#rand,float>`_ that returns a float - ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(123) @@ -263,7 +266,8 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = ## * `rand proc<#rand,float>`_ that returns a float using the default ## random number generator ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer - ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: var r = initRand(234) @@ -289,7 +293,8 @@ proc rand*(max: float): float {.benign.} = ## * `rand proc<#rand,Rand,range[]>`_ that returns a float using a ## provided state ## * `rand proc<#rand,int>`_ that returns an integer - ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(234) @@ -304,8 +309,8 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = ## Allowed types for `T` are integers, floats, and enums without holes. ## ## See also: - ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice and uses the - ## default random number generator + ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice and uses the default random number generator ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer ## * `rand proc<#rand,Rand,range[]>`_ that returns a float ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type @@ -333,8 +338,8 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = ## thread-safe. ## ## See also: - ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice and uses - ## a provided state + ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice and uses a provided state ## * `rand proc<#rand,int>`_ that returns an integer ## * `rand proc<#rand,float>`_ that returns a floating point number ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type @@ -357,7 +362,8 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T = ## See also: ## * `rand proc<#rand,int>`_ that returns an integer ## * `rand proc<#rand,float>`_ that returns a floating point number - ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice + ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ + ## that accepts a slice runnableExamples: randomize(567) doAssert rand(int8) == 55 diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 5eafc6680..c0b6665b2 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -99,7 +99,7 @@ proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = ## this is if you are implementing any ## `SMTP extensions`_. ## - ## See `checkReply(reply)<#checkReply,,string>`_. + ## See `checkReply(reply)<#checkReply,AsyncSmtp,string>`_. result = await smtp.sock.recvLine() if smtp.debug: @@ -211,7 +211,7 @@ proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = return retFuture proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = - ## Calls `debugRecv<#debugRecv>`_ and checks that the received + ## Calls `debugRecv<#debugRecv,AsyncSmtp>`_ and checks that the received ## data starts with ``reply``. If the received data does not start ## with ``reply``, then a ``QUIT`` command will be sent to the SMTP ## server and a ``ReplyError`` exception will be raised. diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index a28e98caf..8939186a7 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -813,7 +813,7 @@ proc toRunes*(s: string): seq[Rune] = ## Obtains a sequence containing the Runes in ``s``. ## ## See also: - ## * `$ proc <#$,seq[T][Rune]>`_ for a reverse operation + ## * `$ proc <#$,Rune>`_ for a reverse operation runnableExamples: let a = toRunes("aáä") doAssert a == @["a".runeAt(0), "á".runeAt(0), "ä".runeAt(0)] diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 50dcd9675..24935f511 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -278,7 +278,7 @@ proc fromJsonHook*[K, V](t: var (Table[K, V] | OrderedTable[K, V]), ## Enables `fromJson` for `Table` and `OrderedTable` types. ## ## See also: - ## * `toJsonHook proc<#toJsonHook,(Table[K,V]|OrderedTable[K,V])>`_ + ## * `toJsonHook proc<#toJsonHook>`_ runnableExamples: import tables, json var foo: tuple[t: Table[string, int], ot: OrderedTable[string, int]] @@ -298,7 +298,7 @@ proc toJsonHook*[K, V](t: (Table[K, V] | OrderedTable[K, V])): JsonNode = ## Enables `toJson` for `Table` and `OrderedTable` types. ## ## See also: - ## * `fromJsonHook proc<#fromJsonHook,(Table[K,V]|OrderedTable[K,V]),JsonNode>`_ + ## * `fromJsonHook proc<#fromJsonHook,,JsonNode>`_ runnableExamples: import tables, json let foo = ( @@ -383,7 +383,7 @@ proc fromJsonHook*(a: var StringTableRef, b: JsonNode) = ## Enables `fromJson` for `StringTableRef` type. ## ## See also: - ## * `toJsonHook` proc<#toJsonHook,StringTableRef>`_ + ## * `toJsonHook proc<#toJsonHook,StringTableRef>`_ runnableExamples: import strtabs, json var t = newStringTable(modeCaseSensitive) @@ -401,7 +401,7 @@ proc toJsonHook*(a: StringTableRef): JsonNode = ## Enables `toJson` for `StringTableRef` type. ## ## See also: - ## * `fromJsonHook` proc<#fromJsonHook,StringTableRef,JsonNode>`_ + ## * `fromJsonHook proc<#fromJsonHook,StringTableRef,JsonNode>`_ runnableExamples: import strtabs, json let t = newStringTable("name", "John", "surname", "Doe", modeCaseSensitive) diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index be0555d3a..a1402a7ff 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -165,7 +165,7 @@ proc initPackedSet*[A]: PackedSet[A] = ## A must be Ordinal ## ## See also: - ## * `toPackedSet[A] proc <#toPackedSet[A],openArray[int]>`_ + ## * `toPackedSet[A] proc <#toPackedSet,openArray[A]>`_ runnableExamples: var a = initPackedSet[int]() assert len(a) == 0 @@ -273,7 +273,7 @@ proc toPackedSet*[A](x: openArray[A]): PackedSet[A] {.since: (1, 3).} = ## Duplicates are removed. ## ## See also: - ## * `initPackedSet[A] proc <#initPackedSet[A]>`_ + ## * `initPackedSet[A] proc <#initPackedSet>`_ runnableExamples: var a = toPackedSet([5, 6, 7]) @@ -418,7 +418,7 @@ proc isNil*[A](x: PackedSet[A]): bool {.inline.} = x.head.isNil and x.elems == 0 proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = ## Copies `src` to `dest`. - ## `dest` does not need to be initialized by `initPackedSet[A] proc <#initPackedSet[A]>`_. + ## `dest` does not need to be initialized by `initPackedSet[A] proc <#initPackedSet>`_. runnableExamples: var a = initPackedSet[int]() diff --git a/lib/system.nim b/lib/system.nim index 76bcd4eec..7eb161666 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -96,7 +96,7 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## defined. ## ## `x` is an external symbol introduced through the compiler's - ## `-d:x switch `_ to enable + ## `-d:x switch `_ to enable ## build time conditionals: ## ## .. code-block:: Nim @@ -1152,7 +1152,7 @@ when defined(nimdoc): ## Stops the program immediately with an exit code. ## ## Before stopping the program the "exit procedures" are called in the - ## opposite order they were added with `addExitProc `_. + ## opposite order they were added with `addExitProc `_. ## ``quit`` never returns and ignores any exception that may have been raised ## by the quit procedures. It does *not* call the garbage collector to free ## all the memory, unless a quit procedure calls `GC_fullCollect @@ -1225,7 +1225,7 @@ when defined(gcDestructors): ## respected. ## ## See also: - ## * `& proc <#&,seq[T][T],seq[T][T]>`_ + ## * `& proc <#&,seq[T],seq[T]>`_ ## ## .. code-block:: Nim ## var s: seq[string] = @["test2","test2"] @@ -1250,7 +1250,7 @@ else: ## respected. ## ## See also: - ## * `& proc <#&,seq[T][T],seq[T][T]>`_ + ## * `& proc <#&,seq[T],seq[T]>`_ ## ## .. code-block:: Nim ## var s: seq[string] = @["test2","test2"] @@ -1274,7 +1274,7 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = ## This is an `O(1)` operation. ## ## See also: - ## * `delete <#delete,seq[T][T],Natural>`_ for preserving the order + ## * `delete <#delete,seq[T],Natural>`_ for preserving the order ## ## .. code-block:: Nim ## var i = @[1, 2, 3, 4, 5] @@ -1289,7 +1289,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = ## This is an `O(n)` operation. ## ## See also: - ## * `del <#delete,seq[T][T],Natural>`_ for O(1) operation + ## * `del <#delete,seq[T],Natural>`_ for O(1) operation ## ## .. code-block:: Nim ## var i = @[1, 2, 3, 4, 5] @@ -1575,7 +1575,7 @@ proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", nilError.} ## Requires `--nilseqs:on`. ## ## See also: - ## * `isNil(seq[T]) <#isNil,seq[T][T]>`_ + ## * `isNil(seq[T]) <#isNil,seq[T]>`_ proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} @@ -1602,7 +1602,7 @@ when defined(nimSeqsV2): ## Requires copying of the sequences. ## ## See also: - ## * `add(var seq[T], openArray[T]) <#add,seq[T][T],openArray[T]>`_ + ## * `add(var seq[T], openArray[T]) <#add,seq[T],openArray[T]>`_ ## ## .. code-block:: Nim ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) @@ -1618,7 +1618,7 @@ when defined(nimSeqsV2): ## Requires copying of the sequence. ## ## See also: - ## * `add(var seq[T], T) <#add,seq[T][T],T>`_ + ## * `add(var seq[T], T) <#add,seq[T],sinkT>`_ ## ## .. code-block:: Nim ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) @@ -1647,7 +1647,7 @@ else: ## Requires copying of the sequences. ## ## See also: - ## * `add(var seq[T], openArray[T]) <#add,seq[T][T],openArray[T]>`_ + ## * `add(var seq[T], openArray[T]) <#add,seq[T],openArray[T]>`_ ## ## .. code-block:: Nim ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) @@ -1663,7 +1663,7 @@ else: ## Requires copying of the sequence. ## ## See also: - ## * `add(var seq[T], T) <#add,seq[T][T],T>`_ + ## * `add(var seq[T], T) <#add,seq[T],sinkT>`_ ## ## .. code-block:: Nim ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) @@ -2950,7 +2950,7 @@ template closureScope*(body: untyped): untyped = ## their current iteration values. ## ## Note: This template may not work in some cases, use - ## `capture `_ instead. + ## `capture `_ instead. ## ## Example: ## diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 1a4fda123..4c25d2a56 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -48,7 +48,7 @@ template assert*(cond: untyped, msg = "") = ## ## The compiler may not generate any code at all for ``assert`` if it is ## advised to do so through the ``-d:danger`` or ``--assertions:off`` - ## `command line switches `_. + ## `command line switches `_. ## ## .. code-block:: nim ## static: assert 1 == 9, "This assertion generates code when not built with -d:danger or --assertions:off" diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index 5f4304502..f5e8b2363 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -77,16 +77,16 @@ when hasAlloc and not defined(js): template alloc*(size: Natural): pointer = ## Allocates a new memory block with at least ``size`` bytes. ## - ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ + ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. ## 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 <#allocShared,Natural>`_ to allocate from a shared heap. + ## Use `allocShared <#allocShared.t,Natural>`_ to allocate from a shared heap. ## ## See also: - ## * `alloc0 <#alloc0,Natural>`_ + ## * `alloc0 <#alloc0.t,Natural>`_ incStat(allocCount) allocImpl(size) @@ -108,13 +108,13 @@ when hasAlloc and not defined(js): template alloc0*(size: Natural): pointer = ## Allocates a new memory block with at least ``size`` bytes. ## - ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ + ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. ## The block is initialized with all bytes containing zero, so it is - ## somewhat safer than `alloc <#alloc,Natural>`_. + ## somewhat safer than `alloc <#alloc.t,Natural>`_. ## ## The allocated memory belongs to its allocating thread! - ## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap. + ## Use `allocShared0 <#allocShared0.t,Natural>`_ to allocate from a shared heap. incStat(allocCount) alloc0Impl(size) @@ -140,7 +140,7 @@ when hasAlloc and not defined(js): ## `dealloc(block) <#dealloc,pointer>`_. ## ## The allocated memory belongs to its allocating thread! - ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate + ## Use `reallocShared <#reallocShared.t,pointer,Natural>`_ to reallocate ## from a shared heap. reallocImpl(p, newSize) @@ -157,7 +157,7 @@ when hasAlloc and not defined(js): ## somewhat safer then realloc ## ## The allocated memory belongs to its allocating thread! - ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate + ## Use `reallocShared <#reallocShared.t,pointer,Natural>`_ to reallocate ## from a shared heap. realloc0Impl(p, oldSize, newSize) @@ -193,14 +193,14 @@ when hasAlloc and not defined(js): ## least ``size`` bytes. ## ## The block has to be freed with - ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ + ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ ## or `deallocShared(block) <#deallocShared,pointer>`_. ## ## The block is not initialized, so reading from it before writing ## to it is undefined behaviour! ## ## See also: - ## `allocShared0 <#allocShared0,Natural>`_. + ## `allocShared0 <#allocShared0.t,Natural>`_. incStat(allocCount) allocSharedImpl(size) @@ -225,12 +225,12 @@ when hasAlloc and not defined(js): ## least ``size`` bytes. ## ## The block has to be freed with - ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ + ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ ## or `deallocShared(block) <#deallocShared,pointer>`_. ## ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than - ## `allocShared <#allocShared,Natural>`_. + ## `allocShared <#allocShared.t,Natural>`_. incStat(allocCount) allocShared0Impl(size) diff --git a/lib/system_overview.rst b/lib/system_overview.rst index 9125c29ba..2e437e596 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -53,9 +53,9 @@ Proc Usage and a given capacity `setLen<#setLen,seq[T],Natural>`_ Set the length of a sequence `len<#len,seq[T]>`_ Return the length of a sequence -`@<#@>`_ Turn an array into a sequence -`add<#add,seq[T],>`_ Add an item to the sequence -`insert<#insert,seq[T],>`_ Insert an item at a specific position +`@<#@,openArray[T]>`_ Turn an array into a sequence +`add<#add,seq[T],sinkT>`_ Add an item to the sequence +`insert<#insert,seq[T],sinkT>`_ Insert an item at a specific position `delete<#delete,seq[T],Natural>`_ Delete an item while preserving the order of elements (`O(n)` operation) `del<#del,seq[T],Natural>`_ `O(1)` removal, doesn't preserve the order @@ -152,21 +152,21 @@ Proc Usage Misc ---- -============================================= ============================================ -Proc Usage -============================================= ============================================ -`is<#is,T,S>`_ Check if two arguments are of the same type -`isnot<#isnot.t,untyped,untyped>`_ Negated version of `is` -`!=<#!%3D.t,untyped,untyped>`_ Not equals -`addr<#addr,T>`_ Take the address of a memory location -`T and F<#and,bool,bool>`_ Boolean `and` -`T or F<#or,bool,bool>`_ Boolean `or` -`T xor F<#xor,bool,bool>`_ Boolean `xor` (exclusive or) -`not T<#not,bool>`_ Boolean `not` -`a[^x]<#^.t,int>`_ Take the element at the reversed index `x` -`a .. b<#..,T,U>`_ Binary slice that constructs an interval - `[a, b]` -`a ..^ b<#..^.t,untyped,untyped>`_ Interval `[a, b]` but `b` as reversed index -[a ..< b](#..<.t,untyped,untyped) Interval `[a, b)` (excluded upper bound) -[runnableExamples](#runnableExamples,untyped) Create testable documentation -============================================= ============================================ +==================================================== ============================================ +Proc Usage +==================================================== ============================================ +`is<#is,T,S>`_ Check if two arguments are of the same type +`isnot<#isnot.t,untyped,untyped>`_ Negated version of `is` +`!=<#!%3D.t,untyped,untyped>`_ Not equals +`addr<#addr,T>`_ Take the address of a memory location +`T and F<#and,bool,bool>`_ Boolean `and` +`T or F<#or,bool,bool>`_ Boolean `or` +`T xor F<#xor,bool,bool>`_ Boolean `xor` (exclusive or) +`not T<#not,bool>`_ Boolean `not` +`a[^x]<#^.t,int>`_ Take the element at the reversed index `x` +`a .. b<#..,sinkT,sinkU>`_ Binary slice that constructs an interval + `[a, b]` +`a ..^ b<#..^.t,untyped,untyped>`_ Interval `[a, b]` but `b` as reversed index +[a ..< b](#..<.t,untyped,untyped) Interval `[a, b)` (excluded upper bound) +[runnableExamples](#runnableExamples,string,untyped) Create testable documentation +==================================================== ============================================ From 233c6a2fba9e6b93f8c19a242265beabf34b215c Mon Sep 17 00:00:00 2001 From: lqdev Date: Mon, 14 Dec 2020 20:13:43 +0100 Subject: [PATCH 1660/4254] disabled sink openArray[T] for adding to seqs (#16352) [backport:1.4] --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 7eb161666..57b46a937 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1215,7 +1215,7 @@ when defined(nimscript) or not defined(nimSeqsV2): ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. -when defined(gcDestructors): +when false: # defined(gcDestructors): proc add*[T](x: var seq[T], y: sink openArray[T]) {.noSideEffect.} = ## Generic proc for adding a container `y` to a container `x`. ## From 38eb021f81589c11453bf5b175f4395d6b25ef86 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 14 Dec 2020 20:14:49 +0100 Subject: [PATCH 1661/4254] sequtils.nim: Change some `func` back to `proc` (#16309) This commit changes the funcs that take a `proc` parameter back to procs. This reverts some of commit 6f57ebae349f: sequtils.nim: Use `func` (#16293) See also: - https://github.com/nim-lang/Nim/issues/16303 - https://github.com/nim-lang/Nim/pull/16304 --- lib/pure/collections/sequtils.nim | 56 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 449faadc7..7aa885794 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -359,7 +359,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = result[i].add(s[g]) first = last -func map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): +proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): seq[S]{.inline.} = ## Returns a new sequence with the results of `op` proc applied to every ## item in the container `s`. @@ -373,7 +373,7 @@ func map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): ## See also: ## * `sugar.collect macro`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ - ## * `apply func<#apply,openArray[T],proc(T)_2>`_ for the in-place version + ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version ## runnableExamples: let @@ -385,7 +385,7 @@ func map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): for i in 0 ..< s.len: result[i] = op(s[i]) -func apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) +proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## @@ -396,7 +396,7 @@ func apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) ## ## See also: ## * `applyIt template<#applyIt.t,untyped,untyped>`_ - ## * `map func<#map,openArray[T],proc(T)>`_ + ## * `map proc<#map,openArray[T],proc(T)>`_ ## runnableExamples: var a = @["1", "2", "3", "4"] @@ -405,7 +405,7 @@ func apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) for i in 0 ..< s.len: op(s[i]) -func apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) +proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## @@ -416,7 +416,7 @@ func apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) ## ## See also: ## * `applyIt template<#applyIt.t,untyped,untyped>`_ - ## * `map func<#map,openArray[T],proc(T)>`_ + ## * `map proc<#map,openArray[T],proc(T)>`_ ## runnableExamples: var a = @["1", "2", "3", "4"] @@ -425,7 +425,7 @@ func apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) for i in 0 ..< s.len: s[i] = op(s[i]) -func apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = +proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = ## Same as `apply` but for proc that do not return and do not mutate `s` directly. runnableExamples: var message: string @@ -442,7 +442,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## ## See also: ## * `sugar.collect macro`_ - ## * `fliter func<#filter,openArray[T],proc(T)>`_ + ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## runnableExamples: @@ -456,7 +456,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = if pred(s[i]): yield s[i] -func filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] +proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] {.inline.} = ## Returns a new sequence with all the items of `s` that fulfilled the ## predicate `pred` (function that returns a `bool`). @@ -468,7 +468,7 @@ func filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] ## * `sugar.collect macro`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ - ## * `keepIf func<#keepIf,seq[T],proc(T)>`_ for the in-place version + ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ for the in-place version ## runnableExamples: let @@ -483,19 +483,19 @@ func filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] if pred(s[i]): result.add(s[i]) -func keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) +proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) {.inline.} = ## Keeps the items in the passed sequence `s` if they fulfilled the ## predicate `pred` (function that returns a `bool`). ## ## Note that `s` must be declared as a ``var``. ## - ## Similar to the `filter func<#filter,openArray[T],proc(T)>`_, + ## Similar to the `filter proc<#filter,openArray[T],proc(T)>`_, ## but modifies the sequence directly. ## ## See also: ## * `keepItIf template<#keepItIf.t,seq,untyped>`_ - ## * `filter func<#filter,openArray[T],proc(T)>`_ + ## * `filter proc<#filter,openArray[T],proc(T)>`_ ## runnableExamples: var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] @@ -576,7 +576,7 @@ template filterIt*(s, pred: untyped): untyped = ## Returns a new sequence with all the items of `s` that fulfilled the ## predicate `pred`. ## - ## Unlike the `filter func<#filter,openArray[T],proc(T)>`_ and + ## Unlike the `filter proc<#filter,openArray[T],proc(T)>`_ and ## `filter iterator<#filter.i,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using the `it` variable ## for testing, like: `filterIt("abcxyz", it == 'x')`. @@ -586,7 +586,7 @@ template filterIt*(s, pred: untyped): untyped = ## ## See also: ## * `sugar.collect macro`_ - ## * `fliter func<#filter,openArray[T],proc(T)>`_ + ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## runnableExamples: @@ -606,12 +606,12 @@ template keepItIf*(varSeq: seq, pred: untyped) = ## Keeps the items in the passed sequence (must be declared as a `var`) ## if they fulfilled the predicate. ## - ## Unlike the `keepIf func<#keepIf,seq[T],proc(T)>`_, + ## Unlike the `keepIf proc<#keepIf,seq[T],proc(T)>`_, ## the predicate needs to be an expression using ## the `it` variable for testing, like: `keepItIf("abcxyz", it == 'x')`. ## ## See also: - ## * `keepIf func<#keepIf,seq[T],proc(T)>`_ + ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## runnableExamples: @@ -650,13 +650,13 @@ since (1, 1): if pred: result += 1 result -func all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = +proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = ## Iterates through a container and checks if every item fulfills the ## predicate. ## ## See also: ## * `allIt template<#allIt.t,untyped,untyped>`_ - ## * `any func<#any,openArray[T],proc(T)>`_ + ## * `any proc<#any,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] @@ -672,12 +672,12 @@ template allIt*(s, pred: untyped): bool = ## Iterates through a container and checks if every item fulfills the ## predicate. ## - ## Unlike the `all func<#all,openArray[T],proc(T)>`_, + ## Unlike the `all proc<#all,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using ## the `it` variable for testing, like: `allIt("abba", it == 'a')`. ## ## See also: - ## * `all func<#all,openArray[T],proc(T)>`_ + ## * `all proc<#all,openArray[T],proc(T)>`_ ## * `anyIt template<#anyIt.t,untyped,untyped>`_ ## runnableExamples: @@ -692,13 +692,13 @@ template allIt*(s, pred: untyped): bool = break result -func any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = +proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = ## Iterates through a container and checks if some item fulfills the ## predicate. ## ## See also: ## * `anyIt template<#anyIt.t,untyped,untyped>`_ - ## * `all func<#all,openArray[T],proc(T)>`_ + ## * `all proc<#all,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] @@ -714,12 +714,12 @@ template anyIt*(s, pred: untyped): bool = ## Iterates through a container and checks if some item fulfills the ## predicate. ## - ## Unlike the `any func<#any,openArray[T],proc(T)>`_, + ## Unlike the `any proc<#any,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using ## the `it` variable for testing, like: `anyIt("abba", it == 'a')`. ## ## See also: - ## * `any func<#any,openArray[T],proc(T)>`_ + ## * `any proc<#any,openArray[T],proc(T)>`_ ## * `allIt template<#allIt.t,untyped,untyped>`_ ## runnableExamples: @@ -946,7 +946,7 @@ template mapIt*(s: typed, op: untyped): untyped = ## ## See also: ## * `sugar.collect macro`_ - ## * `map func<#map,openArray[T],proc(T)>`_ + ## * `map proc<#map,openArray[T],proc(T)>`_ ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version ## runnableExamples: @@ -1007,14 +1007,14 @@ template mapIt*(s: typed, op: untyped): untyped = map(s, f) template applyIt*(varSeq, op: untyped) = - ## Convenience template around the mutable `apply` func to reduce typing. + ## Convenience template around the mutable `apply` proc to reduce typing. ## ## The template injects the `it` variable which you can use directly in an ## expression. The expression has to return the same type as the sequence you ## are mutating. ## ## See also: - ## * `apply func<#apply,openArray[T],proc(T)_2>`_ + ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## runnableExamples: From 1082d62b089e54a584e15b0f97a4b247e214d9ef Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 14 Dec 2020 16:20:21 -0700 Subject: [PATCH 1662/4254] Adds toSet to create sets from iterables (#16276) --- changelog.md | 2 ++ lib/std/setutils.nim | 32 ++++++++++++++++++++++++++++++++ tests/stdlib/tsetutils.nim | 14 ++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 lib/std/setutils.nim create mode 100644 tests/stdlib/tsetutils.nim diff --git a/changelog.md b/changelog.md index 688b87da8..eec754a89 100644 --- a/changelog.md +++ b/changelog.md @@ -58,6 +58,8 @@ - `strscans.scanf` now supports parsing single characters. - `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. +- Added `setutils.toSet` that can take any iterable and convert it to a built-in set, + if the iterable yields a built-in settable type. - Added `math.isNaN`. diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim new file mode 100644 index 000000000..c6385180e --- /dev/null +++ b/lib/std/setutils.nim @@ -0,0 +1,32 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Nim Contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module adds functionality to the built-in `set` type. +## See also std/packedsets, std/sets + +import typetraits + +#[ + type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8 + ## The allowed types of a built-in set. +]# + +template toSet*(iter: untyped): untyped = + ## Return a built-in set from the elements of iterable `iter` + runnableExamples: + assert "helloWorld".toSet == {'W', 'd', 'e', 'h', 'l', 'o', 'r'} + assert toSet([10u16, 20, 30]) == {10u16, 20, 30} + assert [30u8, 100, 10].toSet == {10u8, 30, 100} + assert toSet(@[1321i16, 321, 90]) == {90i16, 321, 1321} + assert toSet([false]) == {false} + assert toSet(0u8..10) == {0u8..10} + var result: set[elementType(iter)] + for x in iter: + incl(result, x) + result diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim new file mode 100644 index 000000000..d99807f92 --- /dev/null +++ b/tests/stdlib/tsetutils.nim @@ -0,0 +1,14 @@ +discard """ + targets: "c js" +""" +import std/setutils + +template main = + doAssert "abcbb".toSet == {'a', 'b', 'c'} + doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13} + doAssert toSet(0u16..30) == {0u16..30} + type A = distinct char + doAssert [A('x')].toSet == {A('x')} + +main() +static: main() \ No newline at end of file From 9ede9566620b4d301f3209e76be0a0c5dba5d1fc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 15 Dec 2020 05:55:41 -0800 Subject: [PATCH 1663/4254] improve tstrutils: test c, cpp, js, vm; cleanups (#16357) * renamed: tests/stdlib/tstrutil.nim -> tests/stdlib/tstrutils.nim * improve test * enable tstrutils for js, vm --- tests/stdlib/tstrutil.nim | 676 ------------------------------------ tests/stdlib/tstrutils.nim | 689 +++++++++++++++++++++++++++++++++++++ 2 files changed, 689 insertions(+), 676 deletions(-) delete mode 100644 tests/stdlib/tstrutil.nim create mode 100644 tests/stdlib/tstrutils.nim diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim deleted file mode 100644 index 149d9bb87..000000000 --- a/tests/stdlib/tstrutil.nim +++ /dev/null @@ -1,676 +0,0 @@ -# test the new strutils module - -import - strutils - -template rejectParse(e) = - try: - discard e - raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e)) - except ValueError: discard - -proc testStrip() = - doAssert strip(" ha ") == "ha" - -proc testRemoveSuffix = - var s = "hello\n\r" - s.removeSuffix - assert s == "hello" - s.removeSuffix - assert s == "hello" - - s = "hello\n\n" - s.removeSuffix - assert s == "hello" - - s = "hello\r" - s.removeSuffix - assert s == "hello" - - s = "hello \n there" - s.removeSuffix - assert s == "hello \n there" - - s = "hello" - s.removeSuffix("llo") - assert s == "he" - s.removeSuffix('e') - assert s == "h" - - s = "hellos" - s.removeSuffix({'s','z'}) - assert s == "hello" - s.removeSuffix({'l','o'}) - assert s == "he" - - s = "aeiou" - s.removeSuffix("") - assert s == "aeiou" - - s = "" - s.removeSuffix("") - assert s == "" - - s = " " - s.removeSuffix - assert s == " " - - s = " " - s.removeSuffix("") - assert s == " " - - s = " " - s.removeSuffix(" ") - assert s == " " - - s = " " - s.removeSuffix(' ') - assert s == "" - - # Contrary to Chomp in other languages - # empty string does not change behaviour - s = "hello\r\n\r\n" - s.removeSuffix("") - assert s == "hello\r\n\r\n" - -proc testRemovePrefix = - var s = "\n\rhello" - s.removePrefix - assert s == "hello" - s.removePrefix - assert s == "hello" - - s = "\n\nhello" - s.removePrefix - assert s == "hello" - - s = "\rhello" - s.removePrefix - assert s == "hello" - - s = "hello \n there" - s.removePrefix - assert s == "hello \n there" - - s = "hello" - s.removePrefix("hel") - assert s == "lo" - s.removePrefix('l') - assert s == "o" - - s = "hellos" - s.removePrefix({'h','e'}) - assert s == "llos" - s.removePrefix({'l','o'}) - assert s == "s" - - s = "aeiou" - s.removePrefix("") - assert s == "aeiou" - - s = "" - s.removePrefix("") - assert s == "" - - s = " " - s.removePrefix - assert s == " " - - s = " " - s.removePrefix("") - assert s == " " - - s = " " - s.removePrefix(" ") - assert s == " " - - s = " " - s.removePrefix(' ') - assert s == "" - - # Contrary to Chomp in other languages - # empty string does not change behaviour - s = "\r\n\r\nhello" - s.removePrefix("") - assert s == "\r\n\r\nhello" - -proc main() = - testStrip() - testRemoveSuffix() - testRemovePrefix() - var ret: seq[string] # or use `toSeq` - for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p - doAssert ret == @["/home/a1", "xyz", "/usr/bin"] - -proc testDelete = - var s = "0123456789ABCDEFGH" - delete(s, 4, 5) - assert s == "01236789ABCDEFGH" - delete(s, s.len-1, s.len-1) - assert s == "01236789ABCDEFG" - delete(s, 0, 0) - assert s == "1236789ABCDEFG" - -proc testFind = - assert "0123456789ABCDEFGH".find('A') == 10 - assert "0123456789ABCDEFGH".find('A', 5) == 10 - assert "0123456789ABCDEFGH".find('A', 5, 10) == 10 - assert "0123456789ABCDEFGH".find('A', 5, 9) == -1 - assert "0123456789ABCDEFGH".find("A") == 10 - assert "0123456789ABCDEFGH".find("A", 5) == 10 - assert "0123456789ABCDEFGH".find("A", 5, 10) == 10 - assert "0123456789ABCDEFGH".find("A", 5, 9) == -1 - assert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 - assert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 - assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 - assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 - -proc testRFind = - assert "0123456789ABCDEFGAH".rfind('A') == 17 - assert "0123456789ABCDEFGAH".rfind('A', last=13) == 10 - assert "0123456789ABCDEFGAH".rfind('H', last=13) == -1 - assert "0123456789ABCDEFGAH".rfind("A") == 17 - assert "0123456789ABCDEFGAH".rfind("A", last=13) == 10 - assert "0123456789ABCDEFGAH".rfind("H", last=13) == -1 - assert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17 - assert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12 - assert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1 - assert "0123456789ABCDEFGAH".rfind('A', start=18) == -1 - assert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17 - assert "0123456789ABCDEFGAH".rfind("0", start=0) == 0 - assert "0123456789ABCDEFGAH".rfind("0", start=1) == -1 - assert "0123456789ABCDEFGAH".rfind("H", start=11) == 18 - assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9 - assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1 - -proc testTrimZeros() = - var x = "1200" - x.trimZeros() - assert x == "1200" - x = "120.0" - x.trimZeros() - assert x == "120" - x = "0." - x.trimZeros() - assert x == "0" - x = "1.0e2" - x.trimZeros() - assert x == "1e2" - x = "78.90" - x.trimZeros() - assert x == "78.9" - x = "1.23e4" - x.trimZeros() - assert x == "1.23e4" - x = "1.01" - x.trimZeros() - assert x == "1.01" - x = "1.1001" - x.trimZeros() - assert x == "1.1001" - x = "0.0" - x.trimZeros() - assert x == "0" - x = "0.01" - x.trimZeros() - assert x == "0.01" - x = "1e0" - x.trimZeros() - assert x == "1e0" - -proc testSplitLines() = - let fixture = "a\nb\rc\r\nd" - assert len(fixture.splitLines) == 4 - assert splitLines(fixture) == @["a", "b", "c", "d"] - assert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] - -proc testCountLines = - proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len - assertCountLines("") - assertCountLines("\n") - assertCountLines("\n\n") - assertCountLines("abc") - assertCountLines("abc\n123") - assertCountLines("abc\n123\n") - assertCountLines("\nabc\n123") - assertCountLines("\nabc\n123\n") - -proc testParseInts = - # binary - assert "0b1111".parseBinInt == 15 - assert "0B1111".parseBinInt == 15 - assert "1111".parseBinInt == 15 - assert "1110".parseBinInt == 14 - assert "1_1_1_1".parseBinInt == 15 - assert "0b1_1_1_1".parseBinInt == 15 - rejectParse "".parseBinInt - rejectParse "_".parseBinInt - rejectParse "0b".parseBinInt - rejectParse "0b1234".parseBinInt - # hex - assert "0x72".parseHexInt == 114 - assert "0X72".parseHexInt == 114 - assert "#72".parseHexInt == 114 - assert "72".parseHexInt == 114 - assert "FF".parseHexInt == 255 - assert "ff".parseHexInt == 255 - assert "fF".parseHexInt == 255 - assert "0x7_2".parseHexInt == 114 - rejectParse "".parseHexInt - rejectParse "_".parseHexInt - rejectParse "0x".parseHexInt - rejectParse "0xFFG".parseHexInt - rejectParse "reject".parseHexInt - # octal - assert "0o17".parseOctInt == 15 - assert "0O17".parseOctInt == 15 - assert "17".parseOctInt == 15 - assert "10".parseOctInt == 8 - assert "0o1_0_0".parseOctInt == 64 - rejectParse "".parseOctInt - rejectParse "_".parseOctInt - rejectParse "0o".parseOctInt - rejectParse "9".parseOctInt - rejectParse "0o9".parseOctInt - rejectParse "reject".parseOctInt - -testDelete() -testFind() -testRFind() -testTrimZeros() -testSplitLines() -testCountLines() -testParseInts() - -assert(insertSep($1000_000) == "1_000_000") -assert(insertSep($232) == "232") -assert(insertSep($12345, ',') == "12,345") -assert(insertSep($0) == "0") - -assert "/1/2/3".rfind('/') == 4 -assert "/1/2/3".rfind('/', last=1) == 0 -assert "/1/2/3".rfind('0') == -1 - -assert(toHex(100i16, 32) == "00000000000000000000000000000064") -assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") - -assert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") -assert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") -assert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") - -assert "".parseHexStr == "" -assert "00Ff80".parseHexStr == "\0\xFF\x80" -try: - discard "00Ff8".parseHexStr - assert false, "Should raise ValueError" -except ValueError: - discard - -try: - discard "0k".parseHexStr - assert false, "Should raise ValueError" -except ValueError: - discard - -assert "".toHex == "" -assert "\x00\xFF\x80".toHex == "00FF80" -assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" - -assert(' '.repeat(8) == " ") -assert(" ".repeat(8) == " ") -assert(spaces(8) == " ") - -assert(' '.repeat(0) == "") -assert(" ".repeat(0) == "") -assert(spaces(0) == "") - -# bug #11369 - -var num: int64 = -1 -assert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" -assert num.toOct(24) == "001777777777777777777777" - - -# bug #8911 -when true: - static: - let a = "" - let a2 = a.replace("\n", "\\n") - -when true: - static: - let b = "b" - let b2 = b.replace("\n", "\\n") - -when true: - let c = "" - let c2 = c.replace("\n", "\\n") - -main() -#OUT ha/home/a1xyz/usr/bin - - -# `parseEnum`, ref issue #14030 -# check enum defined at top level -type - Foo = enum - A = -10 - B = "bb" - C = (-5, "ccc") - D = 15 - E = "ee" # check that we count enum fields correctly - -block: - let a = parseEnum[Foo]("A") - let b = parseEnum[Foo]("bb") - let c = parseEnum[Foo]("ccc") - let d = parseEnum[Foo]("D") - let e = parseEnum[Foo]("ee") - doAssert a == A - doAssert b == B - doAssert c == C - doAssert d == D - doAssert e == E - try: - let f = parseEnum[Foo]("Bar") - doAssert false - except ValueError: - discard - - # finally using default - let g = parseEnum[Foo]("Bar", A) - doAssert g == A - -block: - # check enum defined in block - type - Bar = enum - V - W = "ww" - X = (3, "xx") - Y = 10 - Z = "zz" # check that we count enum fields correctly - - let a = parseEnum[Bar]("V") - let b = parseEnum[Bar]("ww") - let c = parseEnum[Bar]("xx") - let d = parseEnum[Bar]("Y") - let e = parseEnum[Bar]("zz") - doAssert a == V - doAssert b == W - doAssert c == X - doAssert d == Y - doAssert e == Z - try: - let f = parseEnum[Bar]("Baz") - doAssert false - except ValueError: - discard - - # finally using default - let g = parseEnum[Bar]("Baz", V) - doAssert g == V - -block: - # check ambiguous enum fails to parse - type - Ambig = enum - f1 = "A" - f2 = "B" - f3 = "A" - - doAssert not compiles((let a = parseEnum[Ambig]("A"))) - -block: - # check almost ambiguous enum - type - AlmostAmbig = enum - f1 = "someA" - f2 = "someB" - f3 = "SomeA" - - let a = parseEnum[AlmostAmbig]("someA") - let b = parseEnum[AlmostAmbig]("someB") - let c = parseEnum[AlmostAmbig]("SomeA") - doAssert a == f1 - doAssert b == f2 - doAssert c == f3 - -block: - assert 0 == indentation """ -hey - low - there -""" - assert 2 == indentation """ - hey - low - there -""" - assert 2 == indentation """ hey - low - there -""" - assert 2 == indentation """ hey - low - there""" - assert 0 == indentation "" - assert 0 == indentation " \n \n" - assert 0 == indentation " " - - -block: - proc nonStaticTests = - doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - when not defined(js): - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 - doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" - doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" - doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in - ["1,0e-11", "1,0e-011"] - # bug #6589 - when not defined(js): - doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" - - doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" - doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" - - block: # formatSize tests - when not defined(js): - doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" - doAssert formatSize(4096) == "4KiB" - doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" - doAssert formatSize(4096, includeSpace = true) == "4 KiB" - doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" - - block: # formatEng tests - doAssert formatEng(0, 2, trim = false) == "0.00" - doAssert formatEng(0, 2) == "0" - doAssert formatEng(53, 2, trim = false) == "53.00" - doAssert formatEng(0.053, 2, trim = false) == "53.00e-3" - doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3" - doAssert formatEng(0.053, 4, trim = true) == "53e-3" - doAssert formatEng(0.053, 0) == "53e-3" - doAssert formatEng(52731234) == "52.731234e6" - doAssert formatEng(-52731234) == "-52.731234e6" - doAssert formatEng(52731234, 1) == "52.7e6" - doAssert formatEng(-52731234, 1) == "-52.7e6" - doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6" - doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6" - - doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV" - doAssert formatEng(4.1, siPrefix = true, unit = "V", - useUnitSpace = true) == "4.1 V" - doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space - doAssert formatEng(4100, siPrefix = true) == "4.1 k" - doAssert formatEng(4.1, siPrefix = true, unit = "", - useUnitSpace = true) == "4.1 " # Includes space - doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k" - doAssert formatEng(4100) == "4.1e3" - doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V" - doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 " - # Don't use SI prefix as number is too big - doAssert formatEng(3.1e22, siPrefix = true, unit = "a", - useUnitSpace = true) == "31e21 a" - # Don't use SI prefix as number is too small - doAssert formatEng(3.1e-25, siPrefix = true, unit = "A", - useUnitSpace = true) == "310e-27 A" - - proc staticTests = - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#') == "##1232" - - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#') == "1232##" - - doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == - "The cat eats fish." - - doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " - doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" - - doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" - doAssert "oo".replace("", "abc") == "oo" - - type MyEnum = enum enA, enB, enC, enuD, enE - doAssert parseEnum[MyEnum]("enu_D") == enuD - - doAssert parseEnum("invalid enum value", enC) == enC - - doAssert center("foo", 13) == " foo " - doAssert center("foo", 0) == "foo" - doAssert center("foo", 3, fillChar = 'a') == "foo" - doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" - - doAssert count("foofoofoo", "foofoo") == 1 - doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 - doAssert count("foofoofoo", 'f') == 3 - doAssert count("foofoofoobar", {'f', 'b'}) == 4 - - doAssert strip(" foofoofoo ") == "foofoofoo" - doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" - doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" - doAssert strip("stripme but don't strip this stripme", - chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == - " but don't strip this " - doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" - doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" - - doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" - - doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" - doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", - "PEOPLE!")) == "HELLO PEOPLE!" - doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" - - doAssert isAlphaAscii('r') - doAssert isAlphaAscii('A') - doAssert(not isAlphaAscii('$')) - - doAssert isAlphaNumeric('3') - doAssert isAlphaNumeric('R') - doAssert(not isAlphaNumeric('!')) - - doAssert isDigit('3') - doAssert(not isDigit('a')) - doAssert(not isDigit('%')) - - doAssert isSpaceAscii('\t') - doAssert isSpaceAscii('\l') - doAssert(not isSpaceAscii('A')) - - doAssert(isEmptyOrWhitespace("")) - doAssert(isEmptyOrWhitespace(" ")) - doAssert(isEmptyOrWhitespace("\t\l \v\r\f")) - doAssert(not isEmptyOrWhitespace("ABc \td")) - - doAssert isLowerAscii('a') - doAssert isLowerAscii('z') - doAssert(not isLowerAscii('A')) - doAssert(not isLowerAscii('5')) - doAssert(not isLowerAscii('&')) - doAssert(not isLowerAscii(' ')) - - doAssert isUpperAscii('A') - doAssert(not isUpperAscii('b')) - doAssert(not isUpperAscii('5')) - doAssert(not isUpperAscii('%')) - - doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] - doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"] - doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[ - " foo bar", ""] - doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] - doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] - - doAssert(unescape(r"\x013", "", "") == "\x013") - - doAssert join(["foo", "bar", "baz"]) == "foobarbaz" - doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" - doAssert join([1, 2, 3]) == "123" - doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" - - doAssert """~~!!foo -~~!!bar -~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" - - doAssert """~~!!foo -~~!!bar -~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" - doAssert """~~foo -~~ bar -~~ baz""".unindent(4, "~") == "foo\n bar\n baz" - doAssert """foo -bar - baz - """.unindent(4) == "foo\nbar\nbaz\n" - doAssert """foo - bar - baz - """.unindent(2) == "foo\n bar\n baz\n" - doAssert """foo - bar - baz - """.unindent(100) == "foo\nbar\nbaz\n" - - doAssert """foo - foo - bar - """.unindent() == "foo\nfoo\nbar\n" - - let s = " this is an example " - let s2 = ":this;is;an:example;;" - - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example", - "", ""] - doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] - doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] - doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] - - doAssert s.splitWhitespace() == @["this", "is", "an", "example"] - doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "] - doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "] - doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "] - doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"] - - block: # startsWith / endsWith char tests - var s = "abcdef" - doAssert s.startsWith('a') - doAssert s.startsWith('b') == false - doAssert s.endsWith('f') - doAssert s.endsWith('a') == false - doAssert s.endsWith('\0') == false - - #echo("strutils tests passed") - - nonStaticTests() - staticTests() - static: staticTests() \ No newline at end of file diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim new file mode 100644 index 000000000..b62c82ffb --- /dev/null +++ b/tests/stdlib/tstrutils.nim @@ -0,0 +1,689 @@ +discard """ + targets: "c cpp js" +""" + +import std/strutils + +# xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed + +template rejectParse(e) = + try: + discard e + raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e)) + except ValueError: discard + +template disableVm(body) = + when nimvm: discard + else: body + +template main() = + block: # strip + doAssert strip(" ha ") == "ha" + doAssert strip(" foofoofoo ") == "foofoofoo" + doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" + doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" + doAssert strip("stripme but don't strip this stripme", + chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == + " but don't strip this " + doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" + doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" + + block: # split + var ret: seq[string] # or use `toSeq` or `collect` + for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p + doAssert ret == @["/home/a1", "xyz", "/usr/bin"] + + let s = " this is an example " + let s2 = ":this;is;an:example;;" + + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example", + "", ""] + doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] + doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] + doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] + + block: # splitLines + let fixture = "a\nb\rc\r\nd" + assert len(fixture.splitLines) == 4 + assert splitLines(fixture) == @["a", "b", "c", "d"] + assert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] + + block: # rsplit + doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] + doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"] + doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[ + " foo bar", ""] + doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] + doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] + + block: # splitWhitespace + let s = " this is an example " + doAssert s.splitWhitespace() == @["this", "is", "an", "example"] + doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "] + doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "] + doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "] + doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"] + + block: # removeSuffix + var s = "hello\n\r" + s.removeSuffix + assert s == "hello" + s.removeSuffix + assert s == "hello" + + s = "hello\n\n" + s.removeSuffix + assert s == "hello" + + s = "hello\r" + s.removeSuffix + assert s == "hello" + + s = "hello \n there" + s.removeSuffix + assert s == "hello \n there" + + s = "hello" + s.removeSuffix("llo") + assert s == "he" + s.removeSuffix('e') + assert s == "h" + + s = "hellos" + s.removeSuffix({'s','z'}) + assert s == "hello" + s.removeSuffix({'l','o'}) + assert s == "he" + + s = "aeiou" + s.removeSuffix("") + assert s == "aeiou" + + s = "" + s.removeSuffix("") + assert s == "" + + s = " " + s.removeSuffix + assert s == " " + + s = " " + s.removeSuffix("") + assert s == " " + + s = " " + s.removeSuffix(" ") + assert s == " " + + s = " " + s.removeSuffix(' ') + assert s == "" + + # Contrary to Chomp in other languages + # empty string does not change behaviour + s = "hello\r\n\r\n" + s.removeSuffix("") + assert s == "hello\r\n\r\n" + + block: # removePrefix + var s = "\n\rhello" + s.removePrefix + assert s == "hello" + s.removePrefix + assert s == "hello" + + s = "\n\nhello" + s.removePrefix + assert s == "hello" + + s = "\rhello" + s.removePrefix + assert s == "hello" + + s = "hello \n there" + s.removePrefix + assert s == "hello \n there" + + s = "hello" + s.removePrefix("hel") + assert s == "lo" + s.removePrefix('l') + assert s == "o" + + s = "hellos" + s.removePrefix({'h','e'}) + assert s == "llos" + s.removePrefix({'l','o'}) + assert s == "s" + + s = "aeiou" + s.removePrefix("") + assert s == "aeiou" + + s = "" + s.removePrefix("") + assert s == "" + + s = " " + s.removePrefix + assert s == " " + + s = " " + s.removePrefix("") + assert s == " " + + s = " " + s.removePrefix(" ") + assert s == " " + + s = " " + s.removePrefix(' ') + assert s == "" + + # Contrary to Chomp in other languages + # empty string does not change behaviour + s = "\r\n\r\nhello" + s.removePrefix("") + assert s == "\r\n\r\nhello" + + block: # delete + var s = "0123456789ABCDEFGH" + delete(s, 4, 5) + assert s == "01236789ABCDEFGH" + delete(s, s.len-1, s.len-1) + assert s == "01236789ABCDEFG" + delete(s, 0, 0) + assert s == "1236789ABCDEFG" + + block: # find + assert "0123456789ABCDEFGH".find('A') == 10 + assert "0123456789ABCDEFGH".find('A', 5) == 10 + assert "0123456789ABCDEFGH".find('A', 5, 10) == 10 + assert "0123456789ABCDEFGH".find('A', 5, 9) == -1 + assert "0123456789ABCDEFGH".find("A") == 10 + assert "0123456789ABCDEFGH".find("A", 5) == 10 + assert "0123456789ABCDEFGH".find("A", 5, 10) == 10 + assert "0123456789ABCDEFGH".find("A", 5, 9) == -1 + assert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 + assert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 + assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 + assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 + + block: # rfind + assert "0123456789ABCDEFGAH".rfind('A') == 17 + assert "0123456789ABCDEFGAH".rfind('A', last=13) == 10 + assert "0123456789ABCDEFGAH".rfind('H', last=13) == -1 + assert "0123456789ABCDEFGAH".rfind("A") == 17 + assert "0123456789ABCDEFGAH".rfind("A", last=13) == 10 + assert "0123456789ABCDEFGAH".rfind("H", last=13) == -1 + assert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17 + assert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12 + assert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1 + assert "0123456789ABCDEFGAH".rfind('A', start=18) == -1 + assert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17 + assert "0123456789ABCDEFGAH".rfind("0", start=0) == 0 + assert "0123456789ABCDEFGAH".rfind("0", start=1) == -1 + assert "0123456789ABCDEFGAH".rfind("H", start=11) == 18 + assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9 + assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1 + + assert "/1/2/3".rfind('/') == 4 + assert "/1/2/3".rfind('/', last=1) == 0 + assert "/1/2/3".rfind('0') == -1 + + block: # trimZeros + var x = "1200" + x.trimZeros() + assert x == "1200" + x = "120.0" + x.trimZeros() + assert x == "120" + x = "0." + x.trimZeros() + assert x == "0" + x = "1.0e2" + x.trimZeros() + assert x == "1e2" + x = "78.90" + x.trimZeros() + assert x == "78.9" + x = "1.23e4" + x.trimZeros() + assert x == "1.23e4" + x = "1.01" + x.trimZeros() + assert x == "1.01" + x = "1.1001" + x.trimZeros() + assert x == "1.1001" + x = "0.0" + x.trimZeros() + assert x == "0" + x = "0.01" + x.trimZeros() + assert x == "0.01" + x = "1e0" + x.trimZeros() + assert x == "1e0" + + block: # countLines + proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len + assertCountLines("") + assertCountLines("\n") + assertCountLines("\n\n") + assertCountLines("abc") + assertCountLines("abc\n123") + assertCountLines("abc\n123\n") + assertCountLines("\nabc\n123") + assertCountLines("\nabc\n123\n") + + block: # parseBinInt, parseHexInt, parseOctInt + # binary + assert "0b1111".parseBinInt == 15 + assert "0B1111".parseBinInt == 15 + assert "1111".parseBinInt == 15 + assert "1110".parseBinInt == 14 + assert "1_1_1_1".parseBinInt == 15 + assert "0b1_1_1_1".parseBinInt == 15 + rejectParse "".parseBinInt + rejectParse "_".parseBinInt + rejectParse "0b".parseBinInt + rejectParse "0b1234".parseBinInt + # hex + assert "0x72".parseHexInt == 114 + assert "0X72".parseHexInt == 114 + assert "#72".parseHexInt == 114 + assert "72".parseHexInt == 114 + assert "FF".parseHexInt == 255 + assert "ff".parseHexInt == 255 + assert "fF".parseHexInt == 255 + assert "0x7_2".parseHexInt == 114 + rejectParse "".parseHexInt + rejectParse "_".parseHexInt + rejectParse "0x".parseHexInt + rejectParse "0xFFG".parseHexInt + rejectParse "reject".parseHexInt + # octal + assert "0o17".parseOctInt == 15 + assert "0O17".parseOctInt == 15 + assert "17".parseOctInt == 15 + assert "10".parseOctInt == 8 + assert "0o1_0_0".parseOctInt == 64 + rejectParse "".parseOctInt + rejectParse "_".parseOctInt + rejectParse "0o".parseOctInt + rejectParse "9".parseOctInt + rejectParse "0o9".parseOctInt + rejectParse "reject".parseOctInt + + block: # parseHexStr + assert "".parseHexStr == "" + assert "00Ff80".parseHexStr == "\0\xFF\x80" + try: + discard "00Ff8".parseHexStr + assert false, "Should raise ValueError" + except ValueError: + discard + + try: + discard "0k".parseHexStr + assert false, "Should raise ValueError" + except ValueError: + discard + + assert "".toHex == "" + assert "\x00\xFF\x80".toHex == "00FF80" + assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" + + block: # toHex + assert(toHex(100i16, 32) == "00000000000000000000000000000064") + assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") + when not defined js: + assert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") + assert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") + assert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") + + block: # insertSep + assert(insertSep($1000_000) == "1_000_000") + assert(insertSep($232) == "232") + assert(insertSep($12345, ',') == "12,345") + assert(insertSep($0) == "0") + + block: # repeat, spaces + assert(' '.repeat(8) == " ") + assert(" ".repeat(8) == " ") + assert(spaces(8) == " ") + + assert(' '.repeat(0) == "") + assert(" ".repeat(0) == "") + assert(spaces(0) == "") + + block: # toBin, toOct + block:# bug #11369 + var num: int64 = -1 + when not defined js: + assert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" + assert num.toOct(24) == "001777777777777777777777" + + block: # replace + doAssert "oo".replace("", "abc") == "oo" + # bug #8911 + static: + let a = "" + let a2 = a.replace("\n", "\\n") + + static: + let b = "b" + let b2 = b.replace("\n", "\\n") + + block: + let c = "" + let c2 = c.replace("\n", "\\n") + + block: # replaceWord + doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " + doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" + doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" + + block: # multiReplace + doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" + doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", + "PEOPLE!")) == "HELLO PEOPLE!" + doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" + + # `parseEnum`, ref issue #14030 + # check enum defined at top level # xxx this is probably irrelevant, and pollutes scope + # for remaining tests + type + Foo = enum + A = -10 + B = "bb" + C = (-5, "ccc") + D = 15 + E = "ee" # check that we count enum fields correctly + + block: # parseEnum + block: + let a = parseEnum[Foo]("A") + let b = parseEnum[Foo]("bb") + let c = parseEnum[Foo]("ccc") + let d = parseEnum[Foo]("D") + let e = parseEnum[Foo]("ee") + doAssert a == A + doAssert b == B + doAssert c == C + doAssert d == D + doAssert e == E + try: + let f = parseEnum[Foo]("Bar") + doAssert false + except ValueError: + discard + + # finally using default + let g = parseEnum[Foo]("Bar", A) + doAssert g == A + + block: # check enum defined in block + type + Bar = enum + V + W = "ww" + X = (3, "xx") + Y = 10 + Z = "zz" # check that we count enum fields correctly + + let a = parseEnum[Bar]("V") + let b = parseEnum[Bar]("ww") + let c = parseEnum[Bar]("xx") + let d = parseEnum[Bar]("Y") + let e = parseEnum[Bar]("zz") + doAssert a == V + doAssert b == W + doAssert c == X + doAssert d == Y + doAssert e == Z + try: + let f = parseEnum[Bar]("Baz") + doAssert false + except ValueError: + discard + + # finally using default + let g = parseEnum[Bar]("Baz", V) + doAssert g == V + + block: # check ambiguous enum fails to parse + type + Ambig = enum + f1 = "A" + f2 = "B" + f3 = "A" + + doAssert not compiles((let a = parseEnum[Ambig]("A"))) + + block: # check almost ambiguous enum + type + AlmostAmbig = enum + f1 = "someA" + f2 = "someB" + f3 = "SomeA" + + let a = parseEnum[AlmostAmbig]("someA") + let b = parseEnum[AlmostAmbig]("someB") + let c = parseEnum[AlmostAmbig]("SomeA") + doAssert a == f1 + doAssert b == f2 + doAssert c == f3 + + block: # parseEnum TODO: merge above + type MyEnum = enum enA, enB, enC, enuD, enE + doAssert parseEnum[MyEnum]("enu_D") == enuD + + doAssert parseEnum("invalid enum value", enC) == enC + + block: # indentation + assert 0 == indentation """ +hey + low + there +""" + assert 2 == indentation """ + hey + low + there +""" + assert 2 == indentation """ hey + low + there +""" + assert 2 == indentation """ hey + low + there""" + assert 0 == indentation "" + assert 0 == indentation " \n \n" + assert 0 == indentation " " + + block: # indent + doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" + + block: # unindent + doAssert """~~!!foo +~~!!bar +~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" + + doAssert """~~!!foo +~~!!bar +~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" + doAssert """~~foo +~~ bar +~~ baz""".unindent(4, "~") == "foo\n bar\n baz" + doAssert """foo +bar + baz + """.unindent(4) == "foo\nbar\nbaz\n" + doAssert """foo + bar + baz + """.unindent(2) == "foo\n bar\n baz\n" + doAssert """foo + bar + baz + """.unindent(100) == "foo\nbar\nbaz\n" + + doAssert """foo + foo + bar + """.unindent() == "foo\nfoo\nbar\n" + + block: # formatBiggestFloat + disableVm: + doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" + when not defined(js): + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 + doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" + doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" + doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in + ["1,0e-11", "1,0e-011"] + block: # formatFloat + disableVm: + # bug #6589 + when not defined(js): + doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" + + block: # `%` + doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" + doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" + doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == + "The cat eats fish." + + block: # formatSize + disableVm: + when not defined(js): + doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 + doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize(4096) == "4KiB" + doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" + doAssert formatSize(4096, includeSpace = true) == "4 KiB" + doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" + + block: # formatEng + disableVm: + doAssert formatEng(0, 2, trim = false) == "0.00" + doAssert formatEng(0, 2) == "0" + doAssert formatEng(53, 2, trim = false) == "53.00" + doAssert formatEng(0.053, 2, trim = false) == "53.00e-3" + doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3" + doAssert formatEng(0.053, 4, trim = true) == "53e-3" + doAssert formatEng(0.053, 0) == "53e-3" + doAssert formatEng(52731234) == "52.731234e6" + doAssert formatEng(-52731234) == "-52.731234e6" + doAssert formatEng(52731234, 1) == "52.7e6" + doAssert formatEng(-52731234, 1) == "-52.7e6" + doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6" + doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6" + + doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV" + doAssert formatEng(4.1, siPrefix = true, unit = "V", + useUnitSpace = true) == "4.1 V" + doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space + doAssert formatEng(4100, siPrefix = true) == "4.1 k" + doAssert formatEng(4.1, siPrefix = true, unit = "", + useUnitSpace = true) == "4.1 " # Includes space + doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k" + doAssert formatEng(4100) == "4.1e3" + doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V" + doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 " + # Don't use SI prefix as number is too big + doAssert formatEng(3.1e22, siPrefix = true, unit = "a", + useUnitSpace = true) == "31e21 a" + # Don't use SI prefix as number is too small + doAssert formatEng(3.1e-25, siPrefix = true, unit = "A", + useUnitSpace = true) == "310e-27 A" + + block: # align + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#') == "##1232" + + block: # alignLeft + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#') == "1232##" + + block: # center + doAssert center("foo", 13) == " foo " + doAssert center("foo", 0) == "foo" + doAssert center("foo", 3, fillChar = 'a') == "foo" + doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" + + block: # count + doAssert count("foofoofoo", "foofoo") == 1 + doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 + doAssert count("foofoofoo", 'f') == 3 + doAssert count("foofoofoobar", {'f', 'b'}) == 4 + + block: # isAlphaAscii + doAssert isAlphaAscii('r') + doAssert isAlphaAscii('A') + doAssert(not isAlphaAscii('$')) + + block: # isAlphaNumeric + doAssert isAlphaNumeric('3') + doAssert isAlphaNumeric('R') + doAssert(not isAlphaNumeric('!')) + + block: # isDigit + doAssert isDigit('3') + doAssert(not isDigit('a')) + doAssert(not isDigit('%')) + + block: # isSpaceAscii + doAssert isSpaceAscii('\t') + doAssert isSpaceAscii('\l') + doAssert(not isSpaceAscii('A')) + + block: # isEmptyOrWhitespace + doAssert(isEmptyOrWhitespace("")) + doAssert(isEmptyOrWhitespace(" ")) + doAssert(isEmptyOrWhitespace("\t\l \v\r\f")) + doAssert(not isEmptyOrWhitespace("ABc \td")) + + block: # isLowerAscii + doAssert isLowerAscii('a') + doAssert isLowerAscii('z') + doAssert(not isLowerAscii('A')) + doAssert(not isLowerAscii('5')) + doAssert(not isLowerAscii('&')) + doAssert(not isLowerAscii(' ')) + + block: # isUpperAscii + doAssert isUpperAscii('A') + doAssert(not isUpperAscii('b')) + doAssert(not isUpperAscii('5')) + doAssert(not isUpperAscii('%')) + + block: # unescape + doAssert(unescape(r"\x013", "", "") == "\x013") + + block: # join + doAssert join(["foo", "bar", "baz"]) == "foobarbaz" + doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" + doAssert join([1, 2, 3]) == "123" + doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + + block: # startsWith / endsWith + var s = "abcdef" + doAssert s.startsWith('a') + doAssert s.startsWith('b') == false + doAssert s.endsWith('f') + doAssert s.endsWith('a') == false + doAssert s.endsWith('\0') == false + +static: main() +main() From 9ef7c0182058141b81a41e32b699be8f2e42f3e9 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Tue, 15 Dec 2020 05:57:11 -0800 Subject: [PATCH 1664/4254] Syntax (RST) fix Internals of the Compiler (#16341) 'Rebuilding the Compiler' and a few other sections required syntax fixes: * new lines before and after lists to fix rendering * use internal reference instead of Markdown style link --- doc/intern.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/intern.rst b/doc/intern.rst index 3f8a2ce56..5de0c35d5 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -118,20 +118,22 @@ Rebuilding the compiler After an initial build via `sh build_all.sh` on posix or `build_all.bat` on windows, you can rebuild the compiler as follows: + * `nim c koch` if you need to rebuild koch * `./koch boot -d:release` this ensures the compiler can rebuild itself (use `koch` instead of `./koch` on windows), which builds the compiler 3 times. A faster approach if you don't need to run the full bootstrapping implied by `koch boot`, is the following: + * `pathto/nim c --lib:lib -d:release -o:bin/nim_temp compiler/nim.nim` + Where `pathto/nim` is any nim binary sufficiently recent (e.g. `bin/nim_cources` built during bootstrap or `$HOME/.nimble/bin/nim` installed by `choosenim 1.2.0`) You can pass any additional options such as `-d:leanCompiler` if you don't need certain features or `-d:debug --stacktrace:on --excessiveStackTrace --stackTraceMsgs` -for debugging the compiler. See also -[Debugging the compiler](intern.html#debugging-the-compiler). +for debugging the compiler. See also `Debugging the compiler`_. Debugging the compiler ====================== @@ -174,8 +176,7 @@ To create a new compiler for each run, use ``koch temp``:: ``koch temp`` creates a debug build of the compiler, which is useful to create stacktraces for compiler debugging. See also -[Rebuilding the compiler](intern.html#rebuilding-the-compiler) if you need -more control. +`Rebuilding the compiler`_ if you need more control. Bisecting for regressions ========================= @@ -189,8 +190,7 @@ current commit.:: You can also bisect using custom options to build the compiler, for example if you don't need a debug version of the compiler (which runs slower), you can replace -`./koch temp` by explicit compilation command, see -[Rebuilding the compiler](intern.html#rebuilding-the-compiler). +`./koch temp` by explicit compilation command, see `Rebuilding the compiler`_. The compiler's architecture =========================== From 3b963a8150e3c541859931a1ef9ecb338e46907f Mon Sep 17 00:00:00 2001 From: Maurizio Tomasi Date: Wed, 16 Dec 2020 17:05:59 +0100 Subject: [PATCH 1665/4254] Add note about minimum Node.js version (#16370) Fix the error message --- doc/backends.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/backends.rst b/doc/backends.rst index b50c7e38f..070cadbfd 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -93,7 +93,10 @@ file. However, you can also run the code with `nodejs`:idx: nim js -d:nodejs -r examples/hallo.nim +If you experience errors saying that ``globalThis`` is not defined, be +sure to run a recent version of Node.js (at least 12.0). + Interfacing =========== From 979148e863c4142a00632059f3e2a57f4ab0f960 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 17 Dec 2020 08:01:36 +0100 Subject: [PATCH 1666/4254] refactorings to prepare the compiler for IC (#15935) * added ic specific Nim code; WIP * make the symbol import mechanism lazy; WIP * ensure that modules can be imported multiple times * ambiguity checking * handle converters and TR macros properly * make 'enum' test category green again * special logic for semi-pure enums * makes nimsuggest tests green again * fixes nimdata * makes nimpy green again * makes more important packages work --- compiler/ast.nim | 4 +- compiler/ic/bitabs.nim | 119 ++++++ compiler/ic/design.rst | 42 +++ compiler/ic/from_packed_ast.nim | 12 + compiler/ic/packed_ast.nim | 461 ++++++++++++++++++++++++ compiler/ic/to_packed_ast.nim | 90 +++++ compiler/importer.nim | 167 +++++++-- compiler/lookups.nim | 301 +++++++++++++--- compiler/main.nim | 6 +- compiler/modulegraphs.nim | 35 +- compiler/modules.nim | 10 +- compiler/plugins/locals.nim | 3 +- compiler/pragmas.nim | 4 +- compiler/rod.nim | 2 +- compiler/sem.nim | 8 +- compiler/semdata.nim | 24 +- compiler/semexprs.nim | 31 +- compiler/semgnrc.nim | 12 +- compiler/semstmts.nim | 10 +- compiler/semtypes.nim | 8 +- compiler/suggest.nim | 50 +-- lib/system.nim | 2 +- testament/important_packages.nim | 4 +- tests/modules/mforwarded_pure_enum.nim | 3 + tests/modules/mforwarded_pure_enum2.nim | 4 + tests/modules/tfowarded_pure_enum.nim | 7 + 26 files changed, 1241 insertions(+), 178 deletions(-) create mode 100644 compiler/ic/bitabs.nim create mode 100644 compiler/ic/design.rst create mode 100644 compiler/ic/from_packed_ast.nim create mode 100644 compiler/ic/packed_ast.nim create mode 100644 compiler/ic/to_packed_ast.nim create mode 100644 tests/modules/mforwarded_pure_enum.nim create mode 100644 tests/modules/mforwarded_pure_enum2.nim create mode 100644 tests/modules/tfowarded_pure_enum.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index fbad9e44e..4ca5035ed 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -799,6 +799,7 @@ type libHeader, libDynamic TLib* = object # also misused for headers! + # keep in sync with PackedLib kind*: TLibKind generated*: bool # needed for the backends: isOverriden*: bool @@ -823,7 +824,7 @@ type PScope* = ref TScope PLib* = ref TLib - TSym* {.acyclic.} = object of TIdObj + TSym* {.acyclic.} = object of TIdObj # Keep in sync with PackedSym # proc and type instantiations are cached in the generic symbol case kind*: TSymKind of skType, skGenericParam: @@ -904,6 +905,7 @@ type # types are identical iff they have the # same id; there may be multiple copies of a type # in memory! + # Keep in sync with PackedType kind*: TTypeKind # kind of type callConv*: TCallingConvention # for procs flags*: TTypeFlags # flags of the type diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim new file mode 100644 index 000000000..91221ea49 --- /dev/null +++ b/compiler/ic/bitabs.nim @@ -0,0 +1,119 @@ +## A BiTable is a table that can be seen as an optimized pair +## of (Table[LitId, Val], Table[Val, LitId]). + +import hashes + +type + LitId* = distinct uint32 + + BiTable*[T] = object + vals: seq[T] # indexed by LitId + keys: seq[LitId] # indexed by hash(val) + +proc nextTry(h, maxHash: Hash): Hash {.inline.} = + result = (h + 1) and maxHash + +template maxHash(t): untyped = high(t.keys) +template isFilled(x: LitId): bool = x.uint32 > 0'u32 + +proc `$`*(x: LitId): string {.borrow.} +proc `<`*(x, y: LitId): bool {.borrow.} +proc `<=`*(x, y: LitId): bool {.borrow.} +proc `==`*(x, y: LitId): bool {.borrow.} +proc hash*(x: LitId): Hash {.borrow.} + + +proc len*[T](t: BiTable[T]): int = t.vals.len + +proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) + +const + idStart = 256 # Ids do not start with 0 but with this value. The IR needs it. + +template idToIdx(x: LitId): int = x.int - idStart + +proc enlarge[T](t: var BiTable[T]) = + var n: seq[LitId] + newSeq(n, len(t.keys) * 2) + swap(t.keys, n) + for i in 0..high(n): + let eh = n[i] + if isFilled(eh): + var j = hash(t.vals[idToIdx eh]) and maxHash(t) + while isFilled(t.keys[j]): + j = nextTry(j, maxHash(t)) + t.keys[j] = move n[i] + +proc getKeyId*[T](t: BiTable[T]; v: T): LitId = + let origH = hash(v) + var h = origH and maxHash(t) + if t.keys.len != 0: + while true: + let litId = t.keys[h] + if not isFilled(litId): break + if t.vals[idToIdx t.keys[h]] == v: return litId + h = nextTry(h, maxHash(t)) + return LitId(0) + +proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId = + let origH = hash(v) + var h = origH and maxHash(t) + if t.keys.len != 0: + while true: + let litId = t.keys[h] + if not isFilled(litId): break + if t.vals[idToIdx t.keys[h]] == v: return litId + h = nextTry(h, maxHash(t)) + # not found, we need to insert it: + if mustRehash(t.keys.len, t.vals.len): + enlarge(t) + # recompute where to insert: + h = origH and maxHash(t) + while true: + let litId = t.keys[h] + if not isFilled(litId): break + h = nextTry(h, maxHash(t)) + else: + setLen(t.keys, 16) + h = origH and maxHash(t) + + result = LitId(t.vals.len + idStart) + t.keys[h] = result + t.vals.add v + + +proc `[]`*[T](t: var BiTable[T]; LitId: LitId): var T {.inline.} = + let idx = idToIdx LitId + assert idx < t.vals.len + result = t.vals[idx] + +proc `[]`*[T](t: BiTable[T]; LitId: LitId): lent T {.inline.} = + let idx = idToIdx LitId + assert idx < t.vals.len + result = t.vals[idx] + +when isMainModule: + + var t: BiTable[string] + + echo getOrIncl(t, "hello") + + echo getOrIncl(t, "hello") + echo getOrIncl(t, "hello3") + echo getOrIncl(t, "hello4") + echo getOrIncl(t, "helloasfasdfdsa") + echo getOrIncl(t, "hello") + echo getKeyId(t, "hello") + echo getKeyId(t, "none") + + for i in 0 ..< 100_000: + discard t.getOrIncl($i & "___" & $i) + + for i in 0 ..< 100_000: + assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4 + echo t.vals.len + + echo t.vals[0] + echo t.vals[1004] diff --git a/compiler/ic/design.rst b/compiler/ic/design.rst new file mode 100644 index 000000000..1a33f6a27 --- /dev/null +++ b/compiler/ic/design.rst @@ -0,0 +1,42 @@ +==================================== + Incremental Recompilations +==================================== + +We split the Nim compiler into a frontend and a backend. +The frontend produces a set of `.rod` files. Every `.nim` module +produces its own `.rod` file. + +- The IR must be a faithful representation of the AST in memory. +- The backend can do its own caching but doesn't have to. +- We know by comparing 'nim check compiler/nim' against 'nim c compiler/nim' + that 2/3 of the compiler's runtime is spent in the frontend. Hence we + implement IC for the frontend first and only later for the backend. The + backend will recompile everything until we implement its own caching + mechanisms. + +Advantage of the "set of files" vs the previous global database: +- By construction, we either read from the `.rod` file or from the + `.nim` file, there can be no inconsistency. There can also be no + partial updates. +- No dependency to external packages (SQLite). SQLite simply is too + slow and the old way of serialization was too slow too. We use a + format designed for Nim and expect to base further tools on this + file format. + +References to external modules must be (moduleId, symId) pairs. +The symbol IDs are module specific. This way no global ID increment +mechanism needs to be implemented that we could get wrong. ModuleIds +are rod-file specific too. + + +Configuration setup changes +--------------------------- + +For a MVP these are not detected. Later the configuration will be +stored in every `.rod` file. + + +Global state +------------ + +Global persistent state will be kept in a project specific `.rod` file. diff --git a/compiler/ic/from_packed_ast.nim b/compiler/ic/from_packed_ast.nim new file mode 100644 index 000000000..cb2ecee79 --- /dev/null +++ b/compiler/ic/from_packed_ast.nim @@ -0,0 +1,12 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import std / [hashes, tables] +import bitabs +import ".." / [ast, lineinfos, options, pathutils] diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim new file mode 100644 index 000000000..ef609e8c8 --- /dev/null +++ b/compiler/ic/packed_ast.nim @@ -0,0 +1,461 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Packed AST representation, mostly based on a seq of nodes. +## For IC support. Far future: Rewrite the compiler passes to +## use this representation directly in all the transformations, +## it is superior. + +import std / [hashes, tables] +import bitabs +import ".." / [ast, lineinfos, options, pathutils] + +const + localNamePos* = 0 + localExportMarkerPos* = 1 + localPragmaPos* = 2 + localTypePos* = 3 + localValuePos* = 4 + + typeNamePos* = 0 + typeExportMarkerPos* = 1 + typeGenericParamsPos* = 2 + typePragmaPos* = 3 + typeBodyPos* = 4 + + routineNamePos* = 0 + routineExportMarkerPos* = 1 + routinePatternPos* = 2 + routineGenericParamsPos* = 3 + routineParamsPos* = 4 + routineResultPos* = 5 + routinePragmasPos* = 6 + routineBodyPos* = 7 + +const + nkModuleRef = nkNone # pair of (ModuleId, SymId) + +type + SymId* = distinct int32 + TypeId* = distinct int32 + ModuleId* = distinct int32 + NodePos* = distinct int + + NodeId* = distinct int32 + + PackedLineInfo* = object + line*: uint16 + col*: int16 + file*: LitId + + PackedLib* = object + kind*: TLibKind + generated*: bool + isOverriden*: bool + name*: LitId + path*: NodeId + + PackedSym* = object + kind*: TSymKind + name*: LitId + typeId*: TypeId + flags*: TSymFlags + magic*: TMagic + info*: PackedLineInfo + ast*: NodePos + owner*: ItemId + guard*: ItemId + bitsize*: int + alignment*: int # for alignment + options*: TOptions + position*: int + offset*: int + externalName*: LitId # instead of TLoc + annex*: PackedLib + when hasFFI: + cname*: LitId + constraint*: NodeId + + PackedType* = object + kind*: TTypeKind + nodekind*: TNodeKind + flags*: TTypeFlags + types*: int32 + nodes*: int32 + methods*: int32 + nodeflags*: TNodeFlags + info*: PackedLineInfo + sym*: ItemId + owner*: ItemId + attachedOps*: array[TTypeAttachedOp, ItemId] + size*: BiggestInt + align*: int16 + paddingAtEnd*: int16 + lockLevel*: TLockLevel # lock level as required for deadlock checking + # not serialized: loc*: TLoc because it is backend-specific + typeInst*: TypeId + nonUniqueId*: ItemId + + Node* = object # 20 bytes + kind*: TNodeKind + flags*: TNodeFlags + operand*: int32 # for kind in {nkSym, nkSymDef}: SymId + # for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId + # for kind in nkInt32Lit: direct value + # for non-atom kinds: the number of nodes (for easy skipping) + typeId*: TypeId + info*: PackedLineInfo + + ModulePhase* = enum + preLookup, lookedUpTopLevelStmts + + Module* = object + name*: string + file*: AbsoluteFile + ast*: PackedTree + phase*: ModulePhase + iface*: Table[string, seq[SymId]] # 'seq' because of overloading + + Program* = ref object + modules*: seq[Module] + + Shared* = ref object # shared between different versions of 'Module'. + # (though there is always exactly one valid + # version of a module) + syms*: seq[PackedSym] + types*: seq[seq[Node]] + strings*: BiTable[string] # we could share these between modules. + integers*: BiTable[BiggestInt] + floats*: BiTable[BiggestFloat] + config*: ConfigRef + #thisModule*: ModuleId + #program*: Program + + PackedTree* = object ## usually represents a full Nim module + nodes*: seq[Node] + toPosition*: Table[SymId, NodePos] + sh*: Shared + +proc `==`*(a, b: SymId): bool {.borrow.} +proc hash*(a: SymId): Hash {.borrow.} + +proc `==`*(a, b: NodePos): bool {.borrow.} +proc `==`*(a, b: TypeId): bool {.borrow.} +proc `==`*(a, b: ModuleId): bool {.borrow.} + +proc declareSym*(tree: var PackedTree; kind: TSymKind; + name: LitId; info: PackedLineInfo): SymId = + result = SymId(tree.sh.syms.len) + tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info) + +proc newTreeFrom*(old: PackedTree): PackedTree = + result.nodes = @[] + result.sh = old.sh + +proc litIdFromName*(tree: PackedTree; name: string): LitId = + result = tree.sh.strings.getOrIncl(name) + +proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) = + tree.nodes.add Node(kind: kind, operand: int32 getOrIncl(tree.sh.strings, token), info: info) + +proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) = + tree.nodes.add Node(kind: kind, operand: 0, info: info) + +proc throwAwayLastNode*(tree: var PackedTree) = + tree.nodes.setLen(tree.nodes.len-1) + +proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) = + tree.nodes.add Node(kind: nkIdent, operand: int32(s), info: info) + +proc addSym*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = + tree.nodes.add Node(kind: nkSym, operand: int32(s), info: info) + +proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) = + tree.nodes.add Node(kind: nkInt32Lit, operand: int32(s), info: info) + +proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = + tree.nodes.add Node(kind: nkSym, operand: int32(s), info: info) + +proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit + +proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) = + # and this is why the IR is superior. We can copy subtrees + # via a linear scan. + let pos = n.int + let L = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand + let d = dest.nodes.len + dest.nodes.setLen(d + L) + for i in 0.. nkNilLit + let distance = int32(tree.nodes.len - pos) + tree.nodes[pos].operand = distance + +proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len + +proc `[]`*(tree: PackedTree; i: int): lent Node {.inline.} = tree.nodes[i] + +proc nextChild(tree: PackedTree; pos: var int) {.inline.} = + if tree.nodes[pos].kind > nkNilLit: + assert tree.nodes[pos].operand > 0 + inc pos, tree.nodes[pos].operand + else: + inc pos + +iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos = + var pos = n.int + assert tree.nodes[pos].kind > nkNilLit + let last = pos + tree.nodes[pos].operand + inc pos + while pos < last: + yield NodePos pos + nextChild tree, pos + +iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos = + let patchPos = prepare(dest, tree, n) + for x in sonsReadonly(tree, n): yield x + patch dest, patchPos + +iterator isons*(dest: var PackedTree; tree: PackedTree; n: NodePos): (int, NodePos) = + var i = 0 + for ch0 in sons(dest, tree, n): + yield (i, ch0) + inc i + +iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos = + var pos = n.int + assert tree.nodes[pos].kind > nkNilLit + let last = pos + tree.nodes[pos].operand + inc pos + if pos < last: + nextChild tree, pos + while pos < last: + yield NodePos pos + nextChild tree, pos + +iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos = + var count = 0 + for child in sonsReadonly(tree, n): + inc count + var pos = n.int + assert tree.nodes[pos].kind > nkNilLit + let last = pos + tree.nodes[pos].operand + inc pos + while pos < last and count > 2: + yield NodePos pos + dec count + nextChild tree, pos + +proc parentImpl(tree: PackedTree; n: NodePos): NodePos = + # finding the parent of a node is rather easy: + var pos = n.int - 1 + while pos >= 0 and isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int): + dec pos + assert pos >= 0, "node has no parent" + result = NodePos(pos) + +template parent*(n: NodePos): NodePos = parentImpl(tree, n) + +proc hasXsons*(tree: PackedTree; n: NodePos; x: int): bool = + var count = 0 + if tree.nodes[n.int].kind > nkNilLit: + for child in sonsReadonly(tree, n): inc count + result = count == x + +proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool = + if tree.nodes[n.int].kind > nkNilLit: + var count = 0 + for child in sonsReadonly(tree, n): + inc count + if count >= x: return true + return false + +proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} = NodePos(n.int+1) +proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} = tree.nodes[n.int].kind +proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} = LitId tree.nodes[n.int].operand +proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} = tree.nodes[n.int].info + +proc span(tree: PackedTree; pos: int): int {.inline.} = + if isAtom(tree, pos): 1 else: tree.nodes[pos].operand + +proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) = + assert(not isAtom(tree, n.int)) + let a = n.int+1 + let b = a + span(tree, a) + result = (NodePos a, NodePos b) + +proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) = + assert(not isAtom(tree, n.int)) + let a = n.int+1 + let b = a + span(tree, a) + let c = b + span(tree, b) + result = (NodePos a, NodePos b, NodePos c) + +proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos = + if tree.nodes[n.int].kind > nkNilLit: + var count = 0 + for child in sonsReadonly(tree, n): + if count == i: return child + inc count + assert false, "node has no i-th child" + +proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} = tree.sh.strings[lit] + +template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind +template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info +template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand + +template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand + +proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1) + +proc strLit*(tree: PackedTree; n: NodePos): lent string = + assert n.kind == nkStrLit + result = tree.sh.strings[LitId tree.nodes[n.int].operand] + +proc strVal*(tree: PackedTree; n: NodePos): string = + assert n.kind == nkStrLit + result = tree.sh.strings[LitId tree.nodes[n.int].operand] + #result = cookedStrLit(raw) + +proc filenameVal*(tree: PackedTree; n: NodePos): string = + case n.kind + of nkStrLit: + result = strVal(tree, n) + of nkIdent: + result = tree.sh.strings[n.litId] + of nkSym: + result = tree.sh.strings[tree.sh.syms[int n.symId].name] + else: + result = "" + +proc identAsStr*(tree: PackedTree; n: NodePos): lent string = + assert n.kind == nkIdent + result = tree.sh.strings[LitId tree.nodes[n.int].operand] + +const + externIntLit* = {nkCharLit, + nkIntLit, + nkInt8Lit, + nkInt16Lit, + nkInt64Lit, + nkUIntLit, + nkUInt8Lit, + nkUInt16Lit, + nkUInt32Lit, + nkUInt64Lit} # nkInt32Lit is missing by design! + + externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt64Lit} + externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit} + directIntLit* = nkInt32Lit + +proc toString*(tree: PackedTree; n: NodePos; nesting: int; result: var string) = + let pos = n.int + if result.len > 0 and result[^1] notin {' ', '\n'}: + result.add ' ' + + result.add $tree[pos].kind + case tree.nodes[pos].kind + of nkNone, nkEmpty, nkNilLit, nkType: discard + of nkIdent, nkStrLit..nkTripleStrLit: + result.add " " + result.add tree.sh.strings[LitId tree.nodes[pos].operand] + of nkSym: + result.add " " + result.add tree.sh.strings[tree.sh.syms[tree.nodes[pos].operand].name] + of directIntLit: + result.add " " + result.addInt tree.nodes[pos].operand + of externSIntLit: + result.add " " + result.addInt tree.sh.integers[LitId tree.nodes[pos].operand] + of externUIntLit: + result.add " " + result.add $cast[uint64](tree.sh.integers[LitId tree.nodes[pos].operand]) + else: + result.add "(\n" + for i in 1..(nesting+1)*2: result.add ' ' + for child in sonsReadonly(tree, n): + toString(tree, child, nesting + 1, result) + result.add "\n" + for i in 1..nesting*2: result.add ' ' + result.add ")" + #for i in 1..nesting*2: result.add ' ' + + +proc toString*(tree: PackedTree; n: NodePos): string = + result = "" + toString(tree, n, 0, result) + +proc debug*(tree: PackedTree) = + stdout.write toString(tree, NodePos 0) + +proc identIdImpl(tree: PackedTree; n: NodePos): LitId = + if n.kind == nkIdent: + result = n.litId + elif n.kind == nkSym: + result = tree.sh.syms[int n.symId].name + else: + result = LitId(0) + +template identId*(n: NodePos): LitId = identIdImpl(tree, n) + +template copyInto*(dest, n, body) = + let patchPos = prepare(dest, tree, n) + body + patch dest, patchPos + +template copyIntoKind*(dest, kind, info, body) = + let patchPos = prepare(dest, kind, info) + body + patch dest, patchPos + +proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool = + let litId = tree.sh.strings.getKeyId(pragma) + if litId == LitId(0): + return false + assert n.kind == nkPragma + for ch0 in sonsReadonly(tree, n): + if ch0.kind == nkExprColonExpr: + if ch0.firstSon.identId == litId: + return true + elif ch0.identId == litId: + return true + +when false: + proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) = + let patchPos = prepare(dest, nkError, n.info) + dest.add nkStrLit, msg, n.info + copyTree(dest, tree, n) + patch dest, patchPos diff --git a/compiler/ic/to_packed_ast.nim b/compiler/ic/to_packed_ast.nim new file mode 100644 index 000000000..85fec9081 --- /dev/null +++ b/compiler/ic/to_packed_ast.nim @@ -0,0 +1,90 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import std / [hashes, tables] +import packed_ast, bitabs +import ".." / [ast, idents, lineinfos, options, pathutils, msgs] + +type + Context = object + thisModule: int32 + lastFile: FileIndex # remember the last lookup entry. + lastLit: LitId + filenames: Table[FileIndex, LitId] + +proc toLitId(x: FileIndex; ir: var PackedTree; c: var Context): LitId = + if x == c.lastFile: + result = c.lastLit + else: + result = c.filenames.getOrDefault(x) + if result == LitId(0): + let p = msgs.toFullPath(ir.sh.config, x) + result = getOrIncl(ir.sh.strings, p) + c.filenames[x] = result + c.lastFile = x + c.lastLit = result + +proc toPackedInfo(x: TLineInfo; ir: var PackedTree; c: var Context): PackedLineInfo = + PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, ir, c)) + +proc toPackedType(t: PType; ir: var PackedTree; c: var Context): TypeId = + result = TypeId(0) + +proc toPackedSym(s: PSym; ir: var PackedTree; c: var Context): SymId = + result = SymId(0) + +proc toPackedSymNode(n: PNode; ir: var PackedTree; c: var Context) = + assert n.kind == nkSym + let t = toPackedType(n.typ, ir, c) + + if n.sym.itemId.module == c.thisModule: + # it is a symbol that belongs to the module we're currently + # packing: + let sid = toPackedSym(n.sym, ir, c) + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32(sid), + typeId: t, info: toPackedInfo(n.info, ir, c)) + else: + # store it as an external module reference: + # nkModuleRef + discard + + +proc toPackedNode*(n: PNode; ir: var PackedTree; c: var Context) = + template toP(x: TLineInfo): PackedLineInfo = toPackedInfo(x, ir, c) + + case n.kind + of nkNone, nkEmpty, nkNilLit: + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: 0, + typeId: toPackedType(n.typ, ir, c), info: toP n.info) + of nkIdent: + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.strings, n.ident.s), + typeId: toPackedType(n.typ, ir, c), info: toP n.info) + of nkSym: + toPackedSymNode(n, ir, c) + of directIntLit: + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32(n.intVal), + typeId: toPackedType(n.typ, ir, c), info: toP n.info) + of externIntLit: + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.integers, n.intVal), + typeId: toPackedType(n.typ, ir, c), info: toP n.info) + of nkStrLit..nkTripleStrLit: + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.strings, n.strVal), + typeId: toPackedType(n.typ, ir, c), info: toP n.info) + of nkFloatLit..nkFloat128Lit: + ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.floats, n.floatVal), + typeId: toPackedType(n.typ, ir, c), info: toP n.info) + else: + let patchPos = ir.prepare(n.kind, n.flags, toPackedType(n.typ, ir, c), toP n.info) + for i in 0.. 0: + result = candidates[0] + amb = candidates.len > 1 + if amb and checkAmbiguity in flags: + errorUseQualifier(c, n.info, candidates) + if result == nil: + let candidates = allPureEnumFields(c, ident) + if candidates.len > 0: + result = candidates[0] + amb = candidates.len > 1 + if amb and checkAmbiguity in flags: + errorUseQualifier(c, n.info, candidates) + if result == nil and checkUndeclared in flags: fixSpelling(n, ident, searchInScopes) errorUndeclaredIdentifier(c, n.info, ident.s) result = errorSym(c, n) - elif checkAmbiguity in flags and result != nil and result.id in c.ambiguousSymbols: + elif checkAmbiguity in flags and result != nil and amb: errorUseQualifier(c, n.info, result) + c.isAmbiguous = amb of nkSym: result = n.sym - if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id): - errorUseQualifier(c, n.info, n.sym) of nkDotExpr: result = nil - var m = qualifiedLookUp(c, n[0], (flags*{checkUndeclared})+{checkModule}) + var m = qualifiedLookUp(c, n[0], (flags * {checkUndeclared}) + {checkModule}) if m != nil and m.kind == skModule: var ident: PIdent = nil if n[1].kind == nkIdent: @@ -379,18 +493,29 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = if result != nil and result.kind == skStub: loadStub(result) proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = + o.importIdx = -1 + o.marked = initIntSet() case n.kind of nkIdent, nkAccQuoted: var ident = considerQuotedIdent(c, n) - o.scope = c.currentScope + var scope = c.currentScope o.mode = oimNoQualifier while true: - result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n, c.config) + result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config) if result != nil: + o.currentScope = scope break else: - o.scope = o.scope.parent - if o.scope == nil: break + scope = scope.parent + if scope == nil: + for i in 0..c.imports.high: + result = initIdentIter(o.it, o.marked, c.imports[i], ident).skipAlias(n, c.config) + if result != nil: + o.currentScope = nil + o.importIdx = i + return result + return nil + of nkSym: result = n.sym o.mode = oimDone @@ -422,31 +547,69 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.mode = oimDone return nil o.symChoiceIndex = 1 - o.inSymChoice = initIntSet() - incl(o.inSymChoice, result.id) + o.marked = initIntSet() + incl(o.marked, result.id) else: discard when false: if result != nil and result.kind == skStub: loadStub(result) proc lastOverloadScope*(o: TOverloadIter): int = case o.mode - of oimNoQualifier: result = if o.scope.isNil: -1 else: o.scope.depthLevel + of oimNoQualifier: + result = if o.importIdx >= 0: 0 + elif o.currentScope.isNil: -1 + else: o.currentScope.depthLevel of oimSelfModule: result = 1 of oimOtherModule: result = 0 else: result = -1 +proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym = + assert o.currentScope == nil + var idx = o.importIdx+1 + o.importIdx = c.imports.len # assume the other imported modules lack this symbol too + while idx < c.imports.len: + result = initIdentIter(o.it, o.marked, c.imports[idx], o.it.name).skipAlias(n, c.config) + if result != nil: + # oh, we were wrong, some other module had the symbol, so remember that: + o.importIdx = idx + break + inc idx + +proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym = + assert o.currentScope == nil + while o.importIdx < c.imports.len: + result = initIdentIter(o.it, o.marked, c.imports[o.importIdx], o.it.name).skipAlias(n, c.config) + #while result != nil and result.id in o.marked: + # result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]) + if result != nil: + #assert result.id notin o.marked + return result + inc o.importIdx + proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = case o.mode of oimDone: result = nil of oimNoQualifier: - if o.scope != nil: - result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n, c.config) + if o.currentScope != nil: + assert o.importIdx < 0 + result = nextIdentIter(o.it, o.currentScope.symbols).skipAlias(n, c.config) while result == nil: - o.scope = o.scope.parent - if o.scope == nil: break - result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n, c.config) - # BUGFIX: o.it.name <-> n.ident + o.currentScope = o.currentScope.parent + if o.currentScope != nil: + result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config) + # BUGFIX: o.it.name <-> n.ident + else: + o.importIdx = 0 + if c.imports.len > 0: + result = initIdentIter(o.it, o.marked, c.imports[o.importIdx], o.it.name).skipAlias(n, c.config) + if result == nil: + result = nextOverloadIterImports(o, c, n) + break + elif o.importIdx < c.imports.len: + result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]).skipAlias(n, c.config) + if result == nil: + result = nextOverloadIterImports(o, c, n) else: result = nil of oimSelfModule: @@ -456,26 +619,48 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = of oimSymChoice: if o.symChoiceIndex < n.len: result = n[o.symChoiceIndex].sym - incl(o.inSymChoice, result.id) + incl(o.marked, result.id) inc o.symChoiceIndex elif n.kind == nkOpenSymChoice: # try 'local' symbols too for Koenig's lookup: o.mode = oimSymChoiceLocalLookup - o.scope = c.currentScope - result = firstIdentExcluding(o.it, o.scope.symbols, - n[0].sym.name, o.inSymChoice).skipAlias(n, c.config) + o.currentScope = c.currentScope + result = firstIdentExcluding(o.it, o.currentScope.symbols, + n[0].sym.name, o.marked).skipAlias(n, c.config) while result == nil: - o.scope = o.scope.parent - if o.scope == nil: break - result = firstIdentExcluding(o.it, o.scope.symbols, - n[0].sym.name, o.inSymChoice).skipAlias(n, c.config) + o.currentScope = o.currentScope.parent + if o.currentScope != nil: + result = firstIdentExcluding(o.it, o.currentScope.symbols, + n[0].sym.name, o.marked).skipAlias(n, c.config) + else: + o.importIdx = 0 + result = symChoiceExtension(o, c, n) + break + if result != nil: + incl o.marked, result.id of oimSymChoiceLocalLookup: - result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n, c.config) - while result == nil: - o.scope = o.scope.parent - if o.scope == nil: break - result = firstIdentExcluding(o.it, o.scope.symbols, - n[0].sym.name, o.inSymChoice).skipAlias(n, c.config) + if o.currentScope != nil: + result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config) + while result == nil: + o.currentScope = o.currentScope.parent + if o.currentScope != nil: + result = firstIdentExcluding(o.it, o.currentScope.symbols, + n[0].sym.name, o.marked).skipAlias(n, c.config) + else: + o.importIdx = 0 + result = symChoiceExtension(o, c, n) + break + if result != nil: + incl o.marked, result.id + + elif o.importIdx < c.imports.len: + result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]).skipAlias(n, c.config) + #assert result.id notin o.marked + #while result != nil and result.id in o.marked: + # result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config) + if result == nil: + inc o.importIdx + result = symChoiceExtension(o, c, n) when false: if result != nil and result.kind == skStub: loadStub(result) diff --git a/compiler/main.nim b/compiler/main.nim index 6bdbb9efd..73676ffd5 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -31,9 +31,9 @@ proc semanticPasses(g: ModuleGraph) = proc writeDepsFile(g: ModuleGraph) = let fname = g.config.nimcacheDir / RelativeFile(g.config.projectName & ".deps") let f = open(fname.string, fmWrite) - for m in g.modules: - if m != nil: - f.writeLine(toFullPath(g.config, m.position.FileIndex)) + for m in g.ifaces: + if m.module != nil: + f.writeLine(toFullPath(g.config, m.module.position.FileIndex)) for k in g.inclToMod.keys: if g.getModule(k).isNil: # don't repeat includes which are also modules f.writeLine(toFullPath(g.config, k)) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 9e7a487cf..abbefa9b6 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -28,11 +28,20 @@ import ast, intsets, tables, options, lineinfos, hashes, idents, incremental, btrees, md5 +import ic / packed_ast + type SigHash* = distinct MD5Digest + Iface* = object ## data we don't want to store directly in the + ## ast.PSym type for s.kind == skModule + module*: PSym ## module this "Iface" belongs to + converters*: seq[PSym] + patterns*: seq[PSym] + pureEnums*: seq[PSym] + ModuleGraph* = ref object - modules*: seq[PSym] ## indexed by int32 fileIdx + ifaces*: seq[Iface] ## indexed by int32 fileIdx packageSyms*: TStrTable deps*: IntSet # the dependency graph or potentially its transitive closure. importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies @@ -171,13 +180,21 @@ proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = result.magic = m result.flags = {sfNeverRaises} +proc registerModule*(g: ModuleGraph; m: PSym) = + assert m != nil + assert m.kind == skModule + + if m.position >= g.ifaces.len: + setLen(g.ifaces, m.position + 1) + g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[]) + proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result = ModuleGraph() result.idgen = IdGenerator(module: -1'i32, item: 0'i32) initStrTable(result.packageSyms) result.deps = initIntSet() result.importDeps = initTable[FileIndex, seq[FileIndex]]() - result.modules = @[] + result.ifaces = @[] result.importStack = @[] result.inclToMod = initTable[FileIndex, FileIndex]() result.config = config @@ -201,7 +218,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = proc resetAllModules*(g: ModuleGraph) = initStrTable(g.packageSyms) g.deps = initIntSet() - g.modules = @[] + g.ifaces = @[] g.importStack = @[] g.inclToMod = initTable[FileIndex, FileIndex]() g.usageSym = nil @@ -211,8 +228,8 @@ proc resetAllModules*(g: ModuleGraph) = initStrTable(g.exposed) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = - if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len: - result = g.modules[fileIdx.int32] + if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len: + result = g.ifaces[fileIdx.int32].module proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b @@ -233,7 +250,7 @@ proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = ## returns 'fileIdx' if the file belonging to this index is ## directly used as a module or else the module that first ## references this include file. - if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len and g.modules[fileIdx.int32] != nil: + if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len and g.ifaces[fileIdx.int32].module != nil: result = fileIdx else: result = g.inclToMod.getOrDefault(fileIdx) @@ -257,11 +274,11 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = # cleared but D still needs to be remembered as 'dirty'. if g.invalidTransitiveClosure: g.invalidTransitiveClosure = false - transitiveClosure(g.deps, g.modules.len) + transitiveClosure(g.deps, g.ifaces.len) # every module that *depends* on this file is also dirty: - for i in 0i32..= graph.modules.len: - setLen(graph.modules, int(fileIdx) + 1) - graph.modules[result.position] = result + graph.registerModule(result) initStrTable(result.tab) - strTableAdd(result.tab, result) # a module knows itself + when false: + strTableAdd(result.tab, result) # a module knows itself + # This is now implemented via + # c.moduleScope.addSym(module) # a module knows itself + # in sem.nim, around line 527 strTableAdd(packSym.tab, result) proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = diff --git a/compiler/plugins/locals.nim b/compiler/plugins/locals.nim index efa8b1e94..6b0594197 100644 --- a/compiler/plugins/locals.nim +++ b/compiler/plugins/locals.nim @@ -19,8 +19,7 @@ proc semLocals*(c: PContext, n: PNode): PNode = tupleType.n = newNodeI(nkRecList, n.info) let owner = getCurrOwner(c) # for now we skip openarrays ... - for scope in walkScopes(c.currentScope): - if scope == c.topLevelScope: break + for scope in localScopesFrom(c, c.currentScope): for it in items(scope.symbols): if it.kind in skLocalVars and it.typ.skipTypes({tyGenericInst, tyVar}).kind notin diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 5ee3dc414..dca8a94e9 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -559,7 +559,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = if c < 0: sub = substr(str, b + 1) else: sub = substr(str, b + 1, c - 1) if sub != "": - var e = searchInScopes(con, getIdent(con.cache, sub)) + var amb = false + var e = searchInScopes(con, getIdent(con.cache, sub), amb) + # XXX what to do here if 'amb' is true? if e != nil: when false: if e.kind == skStub: loadStub(e) diff --git a/compiler/rod.nim b/compiler/rod.nim index 13a4a53c9..711f5b2cb 100644 --- a/compiler/rod.nim +++ b/compiler/rod.nim @@ -22,7 +22,7 @@ when not nimIncremental: template storeRemaining*(g: ModuleGraph; module: PSym) = discard - template registerModule*(g: ModuleGraph; module: PSym) = discard + #template registerModule*(g: ModuleGraph; module: PSym) = discard else: include rodimpl diff --git a/compiler/sem.nim b/compiler/sem.nim index 0fec8b7e3..e95f3799c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -522,8 +522,10 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext pushProcCon(c, module) pushOwner(c, c.module) - c.importTable = openScope(c) - c.importTable.addSym(module) # a module knows itself + + c.moduleScope = openScope(c) + c.moduleScope.addSym(module) # a module knows itself + if sfSystemModule in module.flags: graph.systemModule = module c.topLevelScope = openScope(c) @@ -557,7 +559,7 @@ proc isEmptyTree(n: PNode): bool = proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if c.topStmts == 0 and not isImportSystemStmt(c.graph, n): if sfSystemModule notin c.module.flags and not isEmptyTree(n): - c.importTable.addSym c.graph.systemModule # import the "System" identifier + c.moduleScope.addSym c.graph.systemModule # import the "System" identifier importAllSymbols(c, c.graph.systemModule) inc c.topStmts else: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 8d1c25e4d..a6660e14c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -70,13 +70,25 @@ type TExprFlags* = set[TExprFlag] + ImportMode* = enum + importAll, importSet, importExcept + ImportedModule* = object + m*: PSym + case mode*: ImportMode + of importAll: discard + of importSet: + imported*: IntSet + of importExcept: + exceptSet*: IntSet + PContext* = ref TContext TContext* = object of TPassContext # a context represents the module # that is currently being compiled enforceVoidContext*: PType module*: PSym # the module sym belonging to the context currentScope*: PScope # current scope - importTable*: PScope # scope for all imported symbols + moduleScope*: PScope # scope for modules + imports*: seq[ImportedModule] # scope for all imported symbols topLevelScope*: PScope # scope for all top-level symbols p*: PProcCon # procedure context matchedConcept*: ptr TMatchedConcept # the current concept being matched @@ -85,9 +97,6 @@ type # can access private object fields instCounter*: int # to prevent endless instantiations templInstCounter*: ref int # gives every template instantiation a unique id - - ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot - # store this info in the syms themselves!) inGenericContext*: int # > 0 if we are in a generic type inStaticContext*: int # > 0 if we are inside a static: block inUnrolledContext*: int # > 0 if we are unrolling a loop @@ -134,6 +143,7 @@ type signatures*: TStrTable recursiveDep*: string suggestionsMade*: bool + isAmbiguous*: bool # little hack features*: set[Feature] inTypeContext*: int typesWithOps*: seq[(PType, PType)] #\ @@ -238,7 +248,6 @@ proc popOptionEntry*(c: PContext) = proc newContext*(graph: ModuleGraph; module: PSym): PContext = new(result) result.enforceVoidContext = PType(kind: tyTyped) - result.ambiguousSymbols = initIntSet() result.optionStack = @[newOptionEntry(graph.config)] result.libs = @[] result.module = module @@ -263,9 +272,14 @@ proc inclSym(sq: var seq[PSym], s: PSym) = proc addConverter*(c: PContext, conv: PSym) = inclSym(c.converters, conv) + inclSym(c.graph.ifaces[c.module.position].converters, conv) + +proc addPureEnum*(c: PContext, e: PSym) = + inclSym(c.graph.ifaces[c.module.position].pureEnums, e) proc addPattern*(c: PContext, p: PSym) = inclSym(c.patterns, p) + inclSym(c.graph.ifaces[c.module.position].patterns, p) proc newLib*(kind: TLibKind): PLib = new(result) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3bbf353b1..bcb48515f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -495,7 +495,8 @@ proc semOpAux(c: PContext, n: PNode) = proc overloadedCallOpr(c: PContext, n: PNode): PNode = # quick check if there is *any* () operator overloaded: var par = getIdent(c.cache, "()") - if searchInScopes(c, par) == nil: + var amb = false + if searchInScopes(c, par, amb) == nil: result = nil else: result = newNodeI(nkCall, n.info) @@ -653,7 +654,8 @@ proc hasUnresolvedArgs(c: PContext, n: PNode): bool = return isUnresolvedSym(n.sym) of nkIdent, nkAccQuoted: let ident = considerQuotedIdent(c, n) - let sym = searchInScopes(c, ident) + var amb = false + let sym = searchInScopes(c, ident, amb) if sym != nil: return isUnresolvedSym(sym) else: @@ -1880,10 +1882,12 @@ proc semDefined(c: PContext, n: PNode): PNode = proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = case n.kind of nkIdent, nkAccQuoted: + var amb = false + let ident = considerQuotedIdent(c, n) result = if onlyCurrentScope: - localSearchInScope(c, considerQuotedIdent(c, n)) + localSearchInScope(c, ident) else: - searchInScopes(c, considerQuotedIdent(c, n)) + searchInScopes(c, ident, amb) of nkDotExpr: result = nil if onlyCurrentScope: return @@ -2531,6 +2535,11 @@ proc semExportExcept(c: PContext, n: PNode): PNode = markUsed(c, n.info, exported) proc semExport(c: PContext, n: PNode): PNode = + proc specialSyms(c: PContext; s: PSym) {.inline.} = + if s.kind == skConverter: addConverter(c, s) + elif s.kind == skType and s.typ != nil and s.typ.kind == tyEnum and sfPure in s.flags: + addPureEnum(c, s) + result = newNodeI(nkExportStmt, n.info) for i in 0.. 0: + let s = candidates[0] # XXX take into account the other candidates! isMacro = s.kind in {skTemplate, skMacro} if withinBind in flags or s.id in ctx.toBind: result = newDot(result, symChoice(c, n, s, scClosed)) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d3d8c0fb8..b4026f3d7 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -298,8 +298,7 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = changeType(c, result, typ, check=false) proc findShadowedVar(c: PContext, v: PSym): PSym = - for scope in walkScopes(c.currentScope.parent): - if scope == c.topLevelScope: break + for scope in localScopesFrom(c, c.currentScope.parent): let shadowed = strTableGet(scope.symbols, v.name) if shadowed != nil and shadowed.kind in skLocalVars: return shadowed @@ -451,7 +450,9 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = n.kind == nkConstSection and w in constPragmas: return nil - let sym = searchInScopes(c, ident) + var amb = false + let sym = searchInScopes(c, ident, amb) + # XXX what if amb is true? if sym == nil or sfCustomPragma in sym.flags: return nil # skip if not in scope; skip `template myAttr() {.pragma.}` let lhs = b[0] @@ -1476,7 +1477,8 @@ proc semProcAnnotation(c: PContext, prc: PNode; if strTableGet(c.userPragmas, ident) != nil: continue # User defined pragma else: - let sym = searchInScopes(c, ident) + var amb = false + let sym = searchInScopes(c, ident, amb) if sym != nil and sfCustomPragma in sym.flags: continue # User custom pragma diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index a9d00d2ee..827087c3d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -146,10 +146,12 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = onDef(e.info, e) if sfGenSym notin e.flags: if not isPure: addDecl(c, e) - else: importPureEnumField(c, e) + else: declarePureEnumField(c, e) if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil): wrongRedefinition(c, e.info, e.name.s, conflict.info) inc(counter) + if isPure and sfExported in result.sym.flags: + addPureEnum(c, result.sym) if tfNotNil in e.typ.flags and not hasNull: result.flags.incl tfRequiresInit @@ -1593,7 +1595,9 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode = if strTableGet(c.userPragmas, ident) != nil: discard "User-defined pragma" else: - let sym = searchInScopes(c, ident) + var amb = false + let sym = searchInScopes(c, ident, amb) + # XXX: What to do here if amb is true? if sym != nil and sfCustomPragma in sym.flags: discard "Custom user pragma" else: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index be337af12..186b23cd9 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -271,17 +271,12 @@ proc getQuality(s: PSym): range[0..100] = return 100 template wholeSymTab(cond, section: untyped) {.dirty.} = - var isLocal = true - var scopeN = 0 - for scope in walkScopes(c.currentScope): - if scope == c.topLevelScope: isLocal = false - dec scopeN - for item in scope.symbols: - let it = item - var pm: PrefixMatch - if cond: - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it), - pm, c.inTypeContext > 0, scopeN)) + for (item, scopeN, isLocal) in allSyms(c): + let it = item + var pm: PrefixMatch + if cond: + outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it), + pm, c.inTypeContext > 0, scopeN)) proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) = for i in 0.. 0, scopeN)) - #if scope == c.topLevelScope and f.isNil: break + for (it, scopeN, isLocal) in allSyms(c): + var pm: PrefixMatch + if filterSym(it, f, pm): + outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, n.info, 0, pm, + c.inTypeContext > 0, scopeN)) proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) = # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but @@ -656,17 +645,12 @@ proc suggestSentinel*(c: PContext) = inc(c.compilesContextId) var outputs: Suggestions = @[] # suggest everything: - var isLocal = true - var scopeN = 0 - for scope in walkScopes(c.currentScope): - if scope == c.topLevelScope: isLocal = false - dec scopeN - for it in items(scope.symbols): - var pm: PrefixMatch - if filterSymNoOpr(it, nil, pm): - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, - newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), 0, - PrefixMatch.None, false, scopeN)) + for (it, scopeN, isLocal) in allSyms(c): + var pm: PrefixMatch + if filterSymNoOpr(it, nil, pm): + outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, + newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), 0, + PrefixMatch.None, false, scopeN)) dec(c.compilesContextId) produceOutput(outputs, c.config) diff --git a/lib/system.nim b/lib/system.nim index 57b46a937..afd8e467d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -627,7 +627,7 @@ proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.} ## the sequence instead of adding them. Example: ## ## .. code-block:: Nim - ## var inputStrings : seq[string] + ## var inputStrings: seq[string] ## newSeq(inputStrings, 3) ## assert len(inputStrings) == 3 ## inputStrings[0] = "The fourth" diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 2da10e749..aae560939 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -76,7 +76,9 @@ pkg2 "nigui", "nim c -o:niguii -r src/nigui.nim" pkg2 "NimData", "nim c -o:nimdataa src/nimdata.nim" pkg2 "nimes", "nim c src/nimes.nim" pkg2 "nimfp", "nim c -o:nfp -r src/fp.nim" -pkg2 "nimgame2", "nim c nimgame2/nimgame.nim" +when false: + pkg2 "nimgame2", "nim c nimgame2/nimgame.nim" + # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg2 "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" pkg2 "nimlsp" pkg2 "nimly", "nim c -r tests/test_readme_example.nim" diff --git a/tests/modules/mforwarded_pure_enum.nim b/tests/modules/mforwarded_pure_enum.nim new file mode 100644 index 000000000..3f03390a5 --- /dev/null +++ b/tests/modules/mforwarded_pure_enum.nim @@ -0,0 +1,3 @@ + +import mforwarded_pure_enum2 +export mforwarded_pure_enum2.PureEnum diff --git a/tests/modules/mforwarded_pure_enum2.nim b/tests/modules/mforwarded_pure_enum2.nim new file mode 100644 index 000000000..e5d5d2a71 --- /dev/null +++ b/tests/modules/mforwarded_pure_enum2.nim @@ -0,0 +1,4 @@ + +type + PureEnum* {.pure.} = enum + x, y, z diff --git a/tests/modules/tfowarded_pure_enum.nim b/tests/modules/tfowarded_pure_enum.nim new file mode 100644 index 000000000..1d2c4f342 --- /dev/null +++ b/tests/modules/tfowarded_pure_enum.nim @@ -0,0 +1,7 @@ +discard """ + output: '''z''' +""" + +import mforwarded_pure_enum as t2 + +echo z From b87bcb6d9245dbb700abb420fe1c8a84a844adbf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 17 Dec 2020 13:35:02 +0100 Subject: [PATCH 1667/4254] fixes #16359 [backport] (#16377) --- lib/pure/includes/oserr.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index 138aa127d..673422973 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -114,7 +114,7 @@ proc osLastError*(): OSErrorCode {.sideEffect.} = when defined(nimscript): discard elif defined(windows): - result = OSErrorCode(getLastError()) + result = cast[OSErrorCode](getLastError()) else: result = OSErrorCode(errno) {.pop.} From 8cd3655deeb369cac325b3ab2a466c110ce2bb27 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 17 Dec 2020 06:37:32 -0600 Subject: [PATCH 1668/4254] make the docs of strutils a bit better (#16368) --- lib/pure/strutils.nim | 303 +++++++++++++++++++++--------------------- 1 file changed, 150 insertions(+), 153 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index c937cd259..04ba71315 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -9,46 +9,43 @@ ## The system module defines several common functions for working with strings, ## such as: -## * ``$`` for converting other data-types to strings -## * ``&`` for string concatenation -## * ``add`` for adding a new character or a string to the existing one -## * ``in`` (alias for ``contains``) and ``notin`` for checking if a character +## * `$` for converting other data-types to strings +## * `&` for string concatenation +## * `add` for adding a new character or a string to the existing one +## * `in` (alias for `contains`) and `notin` for checking if a character ## is in a string ## ## This module builds upon that, providing additional functionality in form of ## procedures, iterators and templates for strings. -## -## .. code-block:: -## import strutils -## -## let -## numbers = @[867, 5309] -## multiLineString = "first line\nsecond line\nthird line" -## -## let jenny = numbers.join("-") -## assert jenny == "867-5309" -## -## assert splitLines(multiLineString) == -## @["first line", "second line", "third line"] -## assert split(multiLineString) == @["first", "line", "second", -## "line", "third", "line"] -## assert indent(multiLineString, 4) == -## " first line\n second line\n third line" -## assert 'z'.repeat(5) == "zzzzz" -## + +runnableExamples: + let + numbers = @[867, 5309] + multiLineString = "first line\nsecond line\nthird line" + + let jenny = numbers.join("-") + assert jenny == "867-5309" + + assert splitLines(multiLineString) == + @["first line", "second line", "third line"] + assert split(multiLineString) == @["first", "line", "second", + "line", "third", "line"] + assert indent(multiLineString, 4) == + " first line\n second line\n third line" + assert 'z'.repeat(5) == "zzzzz" + ## The chaining of functions is possible thanks to the ## `method call syntax`_: -## -## .. code-block:: -## import strutils -## from sequtils import map -## -## let jenny = "867-5309" -## assert jenny.split('-').map(parseInt) == @[867, 5309] -## -## assert "Beetlejuice".indent(1).repeat(3).strip == -## "Beetlejuice Beetlejuice Beetlejuice" -## + +runnableExamples: + from sequtils import map + + let jenny = "867-5309" + assert jenny.split('-').map(parseInt) == @[867, 5309] + + assert "Beetlejuice".indent(1).repeat(3).strip == + "Beetlejuice Beetlejuice Beetlejuice" + ## This module is available for the `JavaScript target ## `_. ## @@ -69,7 +66,7 @@ ## * `ropes module`_ for rope data type, which can represent very ## long strings efficiently ## * `re module`_ for regular expression (regex) support -## * `strscans`_ for ``scanf`` and ``scanp`` macros, which offer +## * `strscans`_ for `scanf` and `scanp` macros, which offer ## easier substring extraction than regular expressions @@ -88,26 +85,26 @@ import std/private/since const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} ## All the characters that count as whitespace (space, tab, vertical tab, - ## carriage return, new line, form feed) + ## carriage return, new line, form feed). Letters* = {'A'..'Z', 'a'..'z'} - ## the set of letters + ## The set of letters. Digits* = {'0'..'9'} - ## the set of digits + ## The set of digits. HexDigits* = {'0'..'9', 'A'..'F', 'a'..'f'} - ## the set of hexadecimal digits + ## The set of hexadecimal digits. IdentChars* = {'a'..'z', 'A'..'Z', '0'..'9', '_'} - ## the set of characters an identifier can consist of + ## The set of characters an identifier can consist of. IdentStartChars* = {'a'..'z', 'A'..'Z', '_'} - ## the set of characters an identifier can start with + ## The set of characters an identifier can start with. Newlines* = {'\13', '\10'} - ## the set of characters a newline terminator can start with (carriage - ## return, line feed) + ## The set of characters a newline terminator can start with (carriage + ## return, line feed). AllChars* = {'\x00'..'\xFF'} ## A set with all the possible characters. @@ -189,9 +186,9 @@ func isUpperAscii*(c: char): bool {.rtl, extern: "nsuIsUpperAsciiChar".} = func toLowerAscii*(c: char): char {.rtl, extern: "nsuToLowerAsciiChar".} = - ## Returns the lower case version of character ``c``. + ## Returns the lower case version of character `c`. ## - ## This works only for the letters ``A-Z``. See `unicode.toLower + ## This works only for the letters `A-Z`. See `unicode.toLower ## `_ for a version that works for any Unicode ## character. ## @@ -214,7 +211,7 @@ template toImpl(call) = func toLowerAscii*(s: string): string {.rtl, extern: "nsuToLowerAsciiStr".} = ## Converts string `s` into lower case. ## - ## This works only for the letters ``A-Z``. See `unicode.toLower + ## This works only for the letters `A-Z`. See `unicode.toLower ## `_ for a version that works for any Unicode ## character. ## @@ -227,7 +224,7 @@ func toLowerAscii*(s: string): string {.rtl, extern: "nsuToLowerAsciiStr".} = func toUpperAscii*(c: char): char {.rtl, extern: "nsuToUpperAsciiChar".} = ## Converts character `c` into upper case. ## - ## This works only for the letters ``A-Z``. See `unicode.toUpper + ## This works only for the letters `A-Z`. See `unicode.toUpper ## `_ for a version that works for any Unicode ## character. ## @@ -246,7 +243,7 @@ func toUpperAscii*(c: char): char {.rtl, extern: "nsuToUpperAsciiChar".} = func toUpperAscii*(s: string): string {.rtl, extern: "nsuToUpperAsciiStr".} = ## Converts string `s` into upper case. ## - ## This works only for the letters ``A-Z``. See `unicode.toUpper + ## This works only for the letters `A-Z`. See `unicode.toUpper ## `_ for a version that works for any Unicode ## character. ## @@ -259,7 +256,7 @@ func toUpperAscii*(s: string): string {.rtl, extern: "nsuToUpperAsciiStr".} = func capitalizeAscii*(s: string): string {.rtl, extern: "nsuCapitalizeAscii".} = ## Converts the first character of string `s` into upper case. ## - ## This works only for the letters ``A-Z``. + ## This works only for the letters `A-Z`. ## Use `Unicode module`_ for UTF-8 support. ## ## See also: @@ -334,7 +331,7 @@ func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} = # thus we compile without checks here func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} = - ## Semantically the same as ``cmp(normalize(a), normalize(b))``. It + ## Semantically the same as `cmp(normalize(a), normalize(b))`. It ## is just optimized to not allocate temporary strings. This should ## NOT be used to compare Nim identifier names. ## Use `macros.eqIdent`_ for that. @@ -629,8 +626,8 @@ iterator splitLines*(s: string, keepEol = false): string = ## ## Every `character literal `_ ## newline combination (CR, LF, CR-LF) is supported. The result strings - ## contain no trailing end of line characters unless parameter ``keepEol`` - ## is set to ``true``. + ## contain no trailing end of line characters unless parameter `keepEol` + ## is set to `true`. ## ## Example: ## @@ -674,9 +671,9 @@ iterator splitLines*(s: string, keepEol = false): string = first = last iterator splitWhitespace*(s: string, maxsplit: int = -1): string = - ## Splits the string ``s`` at whitespace stripping leading and trailing - ## whitespace if necessary. If ``maxsplit`` is specified and is positive, - ## no more than ``maxsplit`` splits is made. + ## Splits the string `s` at whitespace stripping leading and trailing + ## whitespace if necessary. If `maxsplit` is specified and is positive, + ## no more than `maxsplit` splits is made. ## ## The following code: ## @@ -881,7 +878,7 @@ func splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.rtl, func toBin*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToBin".} = ## Converts `x` into its binary representation. ## - ## The resulting string is always `len` characters long. No leading ``0b`` + ## The resulting string is always `len` characters long. No leading `0b` ## prefix is generated. runnableExamples: let @@ -903,7 +900,7 @@ func toBin*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToBin".} = func toOct*(x: BiggestInt, len: Positive): string {.rtl, extern: "nsuToOct".} = ## Converts `x` into its octal representation. ## - ## The resulting string is always `len` characters long. No leading ``0o`` + ## The resulting string is always `len` characters long. No leading `0o` ## prefix is generated. ## ## Do not confuse it with `toOctal func<#toOctal,char>`_. @@ -939,7 +936,7 @@ func toHex*[T: SomeInteger](x: T, len: Positive): string = ## Converts `x` to its hexadecimal representation. ## ## The resulting string will be exactly `len` characters long. No prefix like - ## ``0x`` is generated. `x` is treated as an unsigned value. + ## `0x` is generated. `x` is treated as an unsigned value. runnableExamples: let a = 62'u64 @@ -952,7 +949,7 @@ func toHex*[T: SomeInteger](x: T, len: Positive): string = toHexImpl(cast[BiggestUInt](x), len, x < 0) func toHex*[T: SomeInteger](x: T): string = - ## Shortcut for ``toHex(x, T.sizeof * 2)`` + ## Shortcut for `toHex(x, T.sizeof * 2)` runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" doAssert toHex(1984'i16) == "07C0" @@ -962,7 +959,7 @@ func toHex*(s: string): string {.rtl.} = ## Converts a bytes string to its hexadecimal representation. ## ## The output is twice the input long. No prefix like - ## ``0x`` is generated. + ## `0x` is generated. ## ## See also: ## * `parseHexStr func<#parseHexStr,string>`_ for the reverse operation @@ -1130,7 +1127,7 @@ func parseFloat*(s: string): float {.rtl, extern: "nsuParseFloat".} = ## Parses a decimal floating point value contained in `s`. ## ## If `s` is not a valid floating point number, `ValueError` is raised. - ##``NAN``, ``INF``, ``-INF`` are also supported (case insensitive comparison). + ##`NAN`, `INF`, `-INF` are also supported (case insensitive comparison). runnableExamples: doAssert parseFloat("3.14") == 3.14 doAssert parseFloat("inf") == 1.0/0 @@ -1143,7 +1140,7 @@ func parseBinInt*(s: string): int {.rtl, extern: "nsuParseBinInt".} = ## Parses a binary integer value contained in `s`. ## ## If `s` is not a valid binary integer, `ValueError` is raised. `s` can have - ## one of the following optional prefixes: ``0b``, ``0B``. Underscores within + ## one of the following optional prefixes: `0b`, `0B`. Underscores within ## `s` are ignored. runnableExamples: let @@ -1161,7 +1158,7 @@ func parseOctInt*(s: string): int {.rtl, extern: "nsuParseOctInt".} = ## Parses an octal integer value contained in `s`. ## ## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one - ## of the following optional prefixes: ``0o``, ``0O``. Underscores within + ## of the following optional prefixes: `0o`, `0O`. Underscores within ## `s` are ignored. result = 0 let L = parseutils.parseOct(s, result, 0) @@ -1172,7 +1169,7 @@ func parseHexInt*(s: string): int {.rtl, extern: "nsuParseHexInt".} = ## Parses a hexadecimal integer value contained in `s`. ## ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one - ## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores + ## of the following optional prefixes: `0x`, `0X`, `#`. Underscores ## within `s` are ignored. result = 0 let L = parseutils.parseHex(s, result, 0) @@ -1180,24 +1177,24 @@ func parseHexInt*(s: string): int {.rtl, extern: "nsuParseHexInt".} = raise newException(ValueError, "invalid hex integer: " & s) func generateHexCharToValueMap(): string = - ## Generate a string to map a hex digit to uint value + ## Generates a string to map a hex digit to uint value. result = "" for inp in 0..255: let ch = chr(inp) let o = - case ch: - of '0'..'9': inp - ord('0') - of 'a'..'f': inp - ord('a') + 10 - of 'A'..'F': inp - ord('A') + 10 - else: 17 # indicates an invalid hex char + case ch + of '0'..'9': inp - ord('0') + of 'a'..'f': inp - ord('a') + 10 + of 'A'..'F': inp - ord('A') + 10 + else: 17 # indicates an invalid hex char result.add chr(o) const hexCharToValueMap = generateHexCharToValueMap() func parseHexStr*(s: string): string {.rtl, extern: "nsuParseHexStr".} = - ## Convert hex-encoded string to byte string, e.g.: + ## Converts hex-encoded string to byte string, e.g.: ## - ## Raises ``ValueError`` for an invalid hex values. The comparison is + ## Raises `ValueError` for an invalid hex values. The comparison is ## case-insensitive. ## ## See also: @@ -1228,10 +1225,10 @@ func parseHexStr*(s: string): string {.rtl, extern: "nsuParseHexStr".} = func parseBool*(s: string): bool = ## Parses a value into a `bool`. ## - ## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then - ## returns `true`. If ``s`` is one of the following values: ``n, no, false, - ## 0, off``, then returns `false`. If ``s`` is something else a - ## ``ValueError`` exception is raised. + ## If `s` is one of the following values: `y, yes, true, 1, on`, then + ## returns `true`. If `s` is one of the following values: `n, no, false, + ## 0, off`, then returns `false`. If `s` is something else a + ## `ValueError` exception is raised. runnableExamples: let a = "n" doAssert parseBool(a) == false @@ -1242,10 +1239,10 @@ func parseBool*(s: string): bool = else: raise newException(ValueError, "cannot interpret as a bool: " & s) func parseEnum*[T: enum](s: string): T = - ## Parses an enum ``T``. This errors at compile time, if the given enum + ## Parses an enum `T`. This errors at compile time, if the given enum ## type contains multiple fields with the same string value. ## - ## Raises ``ValueError`` for an invalid value in `s`. The comparison is + ## Raises `ValueError` for an invalid value in `s`. The comparison is ## done in a style insensitive way. runnableExamples: type @@ -1262,7 +1259,7 @@ func parseEnum*[T: enum](s: string): T = genEnumCaseStmt(T, s, default = nil, ord(low(T)), ord(high(T)), nimIdentNormalize) func parseEnum*[T: enum](s: string, default: T): T = - ## Parses an enum ``T``. This errors at compile time, if the given enum + ## Parses an enum `T`. This errors at compile time, if the given enum ## type contains multiple fields with the same string value. ## ## Uses `default` for an invalid value in `s`. The comparison is done in a @@ -1322,7 +1319,7 @@ func align*(s: string, count: Natural, padding = ' '): string {.rtl, ## Aligns a string `s` with `padding`, so that it is of length `count`. ## ## `padding` characters (by default spaces) are added before `s` resulting in - ## right alignment. If ``s.len >= count``, no spaces are added and `s` is + ## right alignment. If `s.len >= count`, no spaces are added and `s` is ## returned unchanged. If you need to left align a string use the `alignLeft ## func<#alignLeft,string,Natural,char>`_. ## @@ -1348,7 +1345,7 @@ func alignLeft*(s: string, count: Natural, padding = ' '): string = ## Left-Aligns a string `s` with `padding`, so that it is of length `count`. ## ## `padding` characters (by default spaces) are added after `s` resulting in - ## left alignment. If ``s.len >= count``, no spaces are added and `s` is + ## left alignment. If `s.len >= count`, no spaces are added and `s` is ## returned unchanged. If you need to right align a string use the `align ## func<#align,string,Natural,char>`_. ## @@ -1408,9 +1405,9 @@ func center*(s: string, width: int, fillChar: char = ' '): string {.rtl, func indent*(s: string, count: Natural, padding: string = " "): string {.rtl, extern: "nsuIndent".} = - ## Indents each line in ``s`` by ``count`` amount of ``padding``. + ## Indents each line in `s` by `count` amount of `padding`. ## - ## **Note:** This does not preserve the new line characters used in ``s``. + ## **Note:** This does not preserve the new line characters used in `s`. ## ## See also: ## * `align func<#align,string,Natural,char>`_ @@ -1433,9 +1430,9 @@ func indent*(s: string, count: Natural, padding: string = " "): string {.rtl, func unindent*(s: string, count: Natural = int.high, padding: string = " "): string {.rtl, extern: "nsuUnindent".} = - ## Unindents each line in ``s`` by ``count`` amount of ``padding``. + ## Unindents each line in `s` by `count` amount of `padding`. ## - ## **Note:** This does not preserve the new line characters used in ``s``. + ## **Note:** This does not preserve the new line characters used in `s`. ## ## See also: ## * `dedent func<#dedent,string,Natural>`_ @@ -1465,7 +1462,7 @@ func unindent*(s: string, count: Natural = int.high, i.inc func indentation*(s: string): Natural {.since: (1, 3).} = - ## Returns the amount of indentation all lines of ``s`` have in common, + ## Returns the amount of indentation all lines of `s` have in common, ## ignoring lines that consist only of whitespace. result = int.high for line in s.splitLines: @@ -1479,13 +1476,13 @@ func indentation*(s: string): Natural {.since: (1, 3).} = func dedent*(s: string, count: Natural = indentation(s)): string {.rtl, extern: "nsuDedent", since: (1, 3).} = - ## Unindents each line in ``s`` by ``count`` amount of ``padding``. + ## Unindents each line in `s` by `count` amount of `padding`. ## The only difference between this and the ## `unindent func<#unindent,string,Natural,string>`_ is that this by default - ## only cuts off the amount of indentation that all lines of ``s`` share as + ## only cuts off the amount of indentation that all lines of `s` share as ## opposed to all indentation. It only supports spaces as padding. ## - ## **Note:** This does not preserve the new line characters used in ``s``. + ## **Note:** This does not preserve the new line characters used in `s`. ## ## See also: ## * `unindent func<#unindent,string,Natural,string>`_ @@ -1503,8 +1500,8 @@ func dedent*(s: string, count: Natural = indentation(s)): string {.rtl, unindent(s, count, " ") func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete".} = - ## Deletes in `s` (must be declared as ``var``) the characters at positions - ## ``first ..last`` (both ends included). + ## Deletes in `s` (must be declared as `var`) the characters at positions + ## `first .. last` (both ends included). ## ## This modifies `s` itself, it does not return a copy. runnableExamples: @@ -1530,7 +1527,7 @@ func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete".} = func startsWith*(s: string, prefix: char): bool {.inline.} = - ## Returns true if ``s`` starts with character ``prefix``. + ## Returns true if `s` starts with character `prefix`. ## ## See also: ## * `endsWith func<#endsWith,string,char>`_ @@ -1543,9 +1540,9 @@ func startsWith*(s: string, prefix: char): bool {.inline.} = result = s.len > 0 and s[0] == prefix func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} = - ## Returns true if ``s`` starts with string ``prefix``. + ## Returns true if `s` starts with string `prefix`. ## - ## If ``prefix == ""`` true is returned. + ## If `prefix == ""` true is returned. ## ## See also: ## * `endsWith func<#endsWith,string,string>`_ @@ -1562,7 +1559,7 @@ func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} = inc(i) func endsWith*(s: string, suffix: char): bool {.inline.} = - ## Returns true if ``s`` ends with ``suffix``. + ## Returns true if `s` ends with `suffix`. ## ## See also: ## * `startsWith func<#startsWith,string,char>`_ @@ -1575,9 +1572,9 @@ func endsWith*(s: string, suffix: char): bool {.inline.} = result = s.len > 0 and s[s.high] == suffix func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} = - ## Returns true if ``s`` ends with ``suffix``. + ## Returns true if `s` ends with `suffix`. ## - ## If ``suffix == ""`` true is returned. + ## If `suffix == ""` true is returned. ## ## See also: ## * `startsWith func<#startsWith,string,string>`_ @@ -1596,9 +1593,9 @@ func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} = func continuesWith*(s, substr: string, start: Natural): bool {.rtl, extern: "nsuContinuesWith".} = - ## Returns true if ``s`` continues with ``substr`` at position ``start``. + ## Returns true if `s` continues with `substr` at position `start`. ## - ## If ``substr == ""`` true is returned. + ## If `substr == ""` true is returned. ## ## See also: ## * `startsWith func<#startsWith,string,string>`_ @@ -1757,8 +1754,8 @@ func allCharsInSet*(s: string, theSet: set[char]): bool = return true func abbrev*(s: string, possibilities: openArray[string]): int = - ## Returns the index of the first item in ``possibilities`` which starts - ## with ``s``, if not ambiguous. + ## Returns the index of the first item in `possibilities` which starts + ## with `s`, if not ambiguous. ## ## Returns -1 if no item has been found and -2 if multiple items match. runnableExamples: @@ -1867,12 +1864,12 @@ else: func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, extern: "nsuFindChar".} = - ## Searches for `sub` in `s` inside range ``start..last`` (both ends included). + ## Searches for `sub` in `s` inside range `start..last` (both ends included). ## If `last` is unspecified, it defaults to `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to ``s[0]``, not ``start``. - ## Use `s[start..last].rfind` for a ``start``-origin index. + ## Otherwise the index returned is relative to `s[0]`, not `start`. + ## Use `s[start..last].rfind` for a `start`-origin index. ## ## See also: ## * `rfind func<#rfind,string,char,Natural>`_ @@ -1895,12 +1892,12 @@ func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. rtl, extern: "nsuFindCharSet".} = - ## Searches for `chars` in `s` inside range ``start..last`` (both ends included). + ## Searches for `chars` in `s` inside range `start..last` (both ends included). ## If `last` is unspecified, it defaults to `s.high` (the last element). ## ## If `s` contains none of the characters in `chars`, -1 is returned. - ## Otherwise the index returned is relative to ``s[0]``, not ``start``. - ## Use `s[start..last].find` for a ``start``-origin index. + ## Otherwise the index returned is relative to `s[0]`, not `start`. + ## Use `s[start..last].find` for a `start`-origin index. ## ## See also: ## * `rfind func<#rfind,string,set[char],Natural>`_ @@ -1912,12 +1909,12 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, extern: "nsuFindStr".} = - ## Searches for `sub` in `s` inside range ``start..last`` (both ends included). + ## Searches for `sub` in `s` inside range `start..last` (both ends included). ## If `last` is unspecified, it defaults to `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to ``s[0]``, not ``start``. - ## Use `s[start..last].find` for a ``start``-origin index. + ## Otherwise the index returned is relative to `s[0]`, not `start`. + ## Use `s[start..last].find` for a `start`-origin index. ## ## See also: ## * `rfind func<#rfind,string,string,Natural>`_ @@ -1930,14 +1927,14 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, extern: "nsuRFindChar".} = - ## Searches for `sub` in `s` inside range ``start..last`` (both ends included) + ## Searches for `sub` in `s` inside range `start..last` (both ends included) ## in reverse -- starting at high indexes and moving lower to the first - ## character or ``start``. If `last` is unspecified, it defaults to `s.high` + ## character or `start`. If `last` is unspecified, it defaults to `s.high` ## (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to ``s[0]``, not ``start``. - ## Use `s[start..last].find` for a ``start``-origin index. + ## Otherwise the index returned is relative to `s[0]`, not `start`. + ## Use `s[start..last].find` for a `start`-origin index. ## ## See also: ## * `find func<#find,string,char,Natural,int>`_ @@ -1948,14 +1945,14 @@ func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, func rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. rtl, extern: "nsuRFindCharSet".} = - ## Searches for `chars` in `s` inside range ``start..last`` (both ends + ## Searches for `chars` in `s` inside range `start..last` (both ends ## included) in reverse -- starting at high indexes and moving lower to the - ## first character or ``start``. If `last` is unspecified, it defaults to + ## first character or `start`. If `last` is unspecified, it defaults to ## `s.high` (the last element). ## ## If `s` contains none of the characters in `chars`, -1 is returned. - ## Otherwise the index returned is relative to ``s[0]``, not ``start``. - ## Use `s[start..last].rfind` for a ``start``-origin index. + ## Otherwise the index returned is relative to `s[0]`, not `start`. + ## Use `s[start..last].rfind` for a `start`-origin index. ## ## See also: ## * `find func<#find,string,set[char],Natural,int>`_ @@ -1966,14 +1963,14 @@ func rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, extern: "nsuRFindStr".} = - ## Searches for `sub` in `s` inside range ``start..last`` (both ends included) + ## Searches for `sub` in `s` inside range `start..last` (both ends included) ## included) in reverse -- starting at high indexes and moving lower to the - ## first character or ``start``. If `last` is unspecified, it defaults to + ## first character or `start`. If `last` is unspecified, it defaults to ## `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - ## Otherwise the index returned is relative to ``s[0]``, not ``start``. - ## Use `s[start..last].rfind` for a ``start``-origin index. + ## Otherwise the index returned is relative to `s[0]`, not `start`. + ## Use `s[start..last].rfind` for a `start`-origin index. ## ## See also: ## * `find func<#find,string,string,Natural,int>`_ @@ -1992,7 +1989,7 @@ func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, func count*(s: string, sub: char): int {.rtl, extern: "nsuCountChar".} = - ## Count the occurrences of the character `sub` in the string `s`. + ## Counts the occurrences of the character `sub` in the string `s`. ## ## See also: ## * `countLines func<#countLines,string>`_ @@ -2002,7 +1999,7 @@ func count*(s: string, sub: char): int {.rtl, extern: "nsuCountChar".} = func count*(s: string, subs: set[char]): int {.rtl, extern: "nsuCountCharSet".} = - ## Count the occurrences of the group of character `subs` in the string `s`. + ## Counts the occurrences of the group of character `subs` in the string `s`. ## ## See also: ## * `countLines func<#countLines,string>`_ @@ -2013,7 +2010,7 @@ func count*(s: string, subs: set[char]): int {.rtl, func count*(s: string, sub: string, overlapping: bool = false): int {.rtl, extern: "nsuCountString".} = - ## Count the occurrences of a substring `sub` in the string `s`. + ## Counts the occurrences of a substring `sub` in the string `s`. ## Overlapping occurrences of `sub` only count when `overlapping` ## is set to true (default: false). ## @@ -2032,7 +2029,7 @@ func count*(s: string, sub: string, overlapping: bool = false): int {.rtl, func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = ## Returns the number of lines in the string `s`. ## - ## This is the same as ``len(splitLines(s))``, but much more efficient + ## This is the same as `len(splitLines(s))`, but much more efficient ## because it doesn't modify the string creating temporal objects. Every ## `character literal `_ ## newline combination (CR, LF, CR-LF) is supported. @@ -2057,14 +2054,14 @@ func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = func contains*(s, sub: string): bool = - ## Same as ``find(s, sub) >= 0``. + ## Same as `find(s, sub) >= 0`. ## ## See also: ## * `find func<#find,string,string,Natural,int>`_ return find(s, sub) >= 0 func contains*(s: string, chars: set[char]): bool = - ## Same as ``find(s, chars) >= 0``. + ## Same as `find(s, chars) >= 0`. ## ## See also: ## * `find func<#find,string,set[char],Natural,int>`_ @@ -2135,7 +2132,7 @@ func replaceWord*(s, sub: string, by = ""): string {.rtl, ## Replaces `sub` in `s` by the string `by`. ## ## Each occurrence of `sub` has to be surrounded by word boundaries - ## (comparable to ``\b`` in regular expressions), otherwise it is not + ## (comparable to `\b` in regular expressions), otherwise it is not ## replaced. if sub.len == 0: return s const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} @@ -2261,7 +2258,7 @@ func unescape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, ## This complements `escape func<#escape,string,string,string>`_ ## as it performs the opposite operations. ## - ## If `s` does not begin with ``prefix`` and end with ``suffix`` a + ## If `s` does not begin with `prefix` and end with `suffix` a ## ValueError exception will be raised. result = newStringOfCap(s.len) var i = prefix.len @@ -2318,24 +2315,24 @@ when not defined(js): type FloatFormatMode* = enum - ## the different modes of floating point formatting + ## The different modes of floating point formatting. ffDefault, ## use the shorter floating point notation ffDecimal, ## use decimal floating point notation - ffScientific ## use scientific notation (using ``e`` character) + ffScientific ## use scientific notation (using `e` character) func formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, precision: range[-1..32] = 16; decimalSep = '.'): string {.rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## - ## If ``format == ffDecimal`` then precision is the number of digits to + ## If `format == ffDecimal` then precision is the number of digits to ## be printed after the decimal point. - ## If ``format == ffScientific`` then precision is the maximum number + ## If `format == ffScientific` then precision is the maximum number ## of significant digits to be printed. ## `precision`'s default value is the maximum number of meaningful digits - ## after the decimal point for Nim's ``biggestFloat`` type. + ## after the decimal point for Nim's `biggestFloat` type. ## - ## If ``precision == -1``, it tries to format it nicely. + ## If `precision == -1`, it tries to format it nicely. runnableExamples: let x = 123.456 doAssert x.formatBiggestFloat() == "123.4560000000000" @@ -2407,14 +2404,14 @@ func formatFloat*(f: float, format: FloatFormatMode = ffDefault, rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## - ## If ``format == ffDecimal`` then precision is the number of digits to + ## If `format == ffDecimal` then precision is the number of digits to ## be printed after the decimal point. - ## If ``format == ffScientific`` then precision is the maximum number + ## If `format == ffScientific` then precision is the maximum number ## of significant digits to be printed. ## `precision`'s default value is the maximum number of meaningful digits - ## after the decimal point for Nim's ``float`` type. + ## after the decimal point for Nim's `float` type. ## - ## If ``precision == -1``, it tries to format it nicely. + ## If `precision == -1`, it tries to format it nicely. runnableExamples: let x = 123.456 doAssert x.formatFloat() == "123.4560000000000" @@ -2425,7 +2422,7 @@ func formatFloat*(f: float, format: FloatFormatMode = ffDefault, func trimZeros*(x: var string; decimalSep = '.') = ## Trim trailing zeros from a formatted floating point - ## value `x` (must be declared as ``var``). + ## value `x` (must be declared as `var`). ## ## This modifies `x` itself, it does not return a copy. runnableExamples: @@ -2443,7 +2440,7 @@ func trimZeros*(x: var string; decimalSep = '.') = x.delete(pos, last) type - BinaryPrefixMode* = enum ## the different names for binary prefixes + BinaryPrefixMode* = enum ## The different names for binary prefixes. bpIEC, # use the IEC/ISO standard prefixes such as kibi bpColloquial # use the colloquial kilo, mega etc @@ -2656,7 +2653,7 @@ func invalidFormatString() {.noinline.} = func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, extern: "nsuAddf".} = - ## The same as ``add(s, formatstr % a)``, but more efficient. + ## The same as `add(s, formatstr % a)`, but more efficient. const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'} var i = 0 var num = 0 @@ -2735,17 +2732,17 @@ func `%` *(formatstr: string, a: openArray[string]): string {.rtl, ## .. code-block:: nim ## "The cat eats fish." ## - ## The substitution variables (the thing after the ``$``) are enumerated - ## from 1 to ``a.len``. - ## To produce a verbatim ``$``, use ``$$``. - ## The notation ``$#`` can be used to refer to the next substitution + ## The substitution variables (the thing after the `$`) are enumerated + ## from 1 to `a.len`. + ## To produce a verbatim `$`, use `$$`. + ## The notation `$#` can be used to refer to the next substitution ## variable: ## ## .. code-block:: nim ## "$# eats $#." % ["The cat", "fish"] ## ## Substitution variables can also be words (that is - ## ``[A-Za-z_]+[A-Za-z0-9_]*``) in which case the arguments in `a` with even + ## `[A-Za-z_]+[A-Za-z0-9_]*`) in which case the arguments in `a` with even ## indices are keys and with odd indices are the corresponding values. ## An example: ## @@ -2767,14 +2764,14 @@ func `%` *(formatstr: string, a: openArray[string]): string {.rtl, func `%` *(formatstr, a: string): string {.rtl, extern: "nsuFormatSingleElem".} = - ## This is the same as ``formatstr % [a]`` (see + ## This is the same as `formatstr % [a]` (see ## `% func<#%25,string,openArray[string]>`_). result = newStringOfCap(formatstr.len + a.len) addf(result, formatstr, [a]) func format*(formatstr: string, a: varargs[string, `$`]): string {.rtl, extern: "nsuFormatVarargs".} = - ## This is the same as ``formatstr % a`` (see + ## This is the same as `formatstr % a` (see ## `% func<#%25,string,openArray[string]>`_) except that it supports ## auto stringification. ## @@ -2820,9 +2817,9 @@ func strip*(s: string, leading = true, trailing = true, result = substr(s, first, last) func stripLineEnd*(s: var string) = - ## Returns ``s`` stripped from one of these suffixes: - ## ``\r, \n, \r\n, \f, \v`` (at most once instance). - ## For example, can be useful in conjunction with ``osproc.execCmdEx``. + ## Returns `s` stripped from one of these suffixes: + ## `\r, \n, \r\n, \f, \v` (at most once instance). + ## For example, can be useful in conjunction with `osproc.execCmdEx`. ## aka: `chomp`:idx: runnableExamples: var s = "foo\n\n" From e1e069dd6c4e3439ee568686a2aed0a58bd771b0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 17 Dec 2020 06:41:05 -0600 Subject: [PATCH 1669/4254] use hexchar in stdlib (#16290) --- lib/pure/parsecfg.nim | 24 ++++++------------------ lib/pure/parsejson.nim | 13 +++---------- lib/pure/parsesql.nim | 24 ++++++------------------ lib/pure/pegs.nim | 20 +++++--------------- lib/std/private/decode_helpers.nim | 25 +++++++++++++++++++------ nimsuggest/sexp.nim | 10 ++-------- tests/stdlib/tdecode_helpers.nim | 27 +++++++++++++++++++++++++++ 7 files changed, 68 insertions(+), 75 deletions(-) create mode 100644 tests/stdlib/tdecode_helpers.nim diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index c87010122..79cf522f0 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -172,8 +172,8 @@ runnableExamples: doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability" -import - strutils, lexbase, streams, tables +import strutils, lexbase, streams, tables +import std/private/decode_helpers include "system/inclrtl" @@ -247,20 +247,6 @@ proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} = ## Gets the filename of the file that the parser processes. result = c.filename -proc handleHexChar(c: var CfgParser, xi: var int) = - case c.buf[c.bufpos] - of '0'..'9': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) - inc(c.bufpos) - of 'a'..'f': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) - inc(c.bufpos) - of 'A'..'F': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) - inc(c.bufpos) - else: - discard - proc handleDecChars(c: var CfgParser, xi: var int) = while c.buf[c.bufpos] in {'0'..'9'}: xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0')) @@ -305,8 +291,10 @@ proc getEscapedChar(c: var CfgParser, tok: var Token) = of 'x', 'X': inc(c.bufpos) var xi = 0 - handleHexChar(c, xi) - handleHexChar(c, xi) + if handleHexChar(c.buf[c.bufpos], xi): + inc(c.bufpos) + if handleHexChar(c.buf[c.bufpos], xi): + inc(c.bufpos) add(tok.literal, chr(xi)) of '0'..'9': var xi = 0 diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim index 18e6037f3..8a0e04298 100644 --- a/lib/pure/parsejson.nim +++ b/lib/pure/parsejson.nim @@ -11,8 +11,8 @@ ## and exported by the ``json`` standard library ## module, but can also be used in its own right. -import - strutils, lexbase, streams, unicode +import strutils, lexbase, streams, unicode +import std/private/decode_helpers type JsonEventKind* = enum ## enumeration of all events that may occur when parsing @@ -162,18 +162,11 @@ proc errorMsgExpected*(my: JsonParser, e: string): string = result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), e & " expected"] -proc handleHexChar(c: char, x: var int): bool = - result = true # Success - case c - of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) - of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: result = false # error - proc parseEscapedUTF16*(buf: cstring, pos: var int): int = result = 0 #UTF-16 escape is always 4 bytes. for _ in 0..3: + # if char in '0' .. '9', 'a' .. 'f', 'A' .. 'F' if handleHexChar(buf[pos], result): inc(pos) else: diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 0232baf8d..23d43dfe0 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -12,8 +12,8 @@ ## ## Unstable API. -import - strutils, lexbase +import strutils, lexbase +import std/private/decode_helpers # ------------------- scanner ------------------------------------------------- @@ -72,20 +72,6 @@ proc getColumn(L: SqlLexer): int = proc getLine(L: SqlLexer): int = result = L.lineNumber -proc handleHexChar(c: var SqlLexer, xi: var int) = - case c.buf[c.bufpos] - of '0'..'9': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) - inc(c.bufpos) - of 'a'..'f': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) - inc(c.bufpos) - of 'A'..'F': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) - inc(c.bufpos) - else: - discard - proc handleOctChar(c: var SqlLexer, xi: var int) = if c.buf[c.bufpos] in {'0'..'7'}: xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0')) @@ -130,8 +116,10 @@ proc getEscapedChar(c: var SqlLexer, tok: var Token) = of 'x', 'X': inc(c.bufpos) var xi = 0 - handleHexChar(c, xi) - handleHexChar(c, xi) + if handleHexChar(c.buf[c.bufpos], xi): + inc(c.bufpos) + if handleHexChar(c.buf[c.bufpos], xi): + inc(c.bufpos) add(tok.literal, chr(xi)) of '0'..'7': var xi = 0 diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 8abd3deb5..f9868b619 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -21,6 +21,7 @@ const useUnicode = true ## change this to deactivate proper UTF-8 support import strutils, macros +import std/private/decode_helpers when useUnicode: import unicode @@ -1466,19 +1467,6 @@ proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = var col = if col < 0: getColumn(L) else: col result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] -proc handleHexChar(c: var PegLexer, xi: var int) = - case c.buf[c.bufpos] - of '0'..'9': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) - inc(c.bufpos) - of 'a'..'f': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) - inc(c.bufpos) - of 'A'..'F': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) - inc(c.bufpos) - else: discard - proc getEscapedChar(c: var PegLexer, tok: var Token) = inc(c.bufpos) if c.bufpos >= len(c.buf): @@ -1515,8 +1503,10 @@ proc getEscapedChar(c: var PegLexer, tok: var Token) = tok.kind = tkInvalid return var xi = 0 - handleHexChar(c, xi) - handleHexChar(c, xi) + if handleHexChar(c.buf[c.bufpos], xi): + inc(c.bufpos) + if handleHexChar(c.buf[c.bufpos], xi): + inc(c.bufpos) if xi == 0: tok.kind = tkInvalid else: add(tok.literal, chr(xi)) of '0'..'9': diff --git a/lib/std/private/decode_helpers.nim b/lib/std/private/decode_helpers.nim index 586c7cae6..e28651690 100644 --- a/lib/std/private/decode_helpers.nim +++ b/lib/std/private/decode_helpers.nim @@ -1,9 +1,25 @@ -proc handleHexChar*(c: char, x: var int, f: var bool) {.inline.} = +proc handleHexChar*(c: char, x: var int): bool {.inline.} = + ## Converts `%xx` hexadecimal to the ordinal number and adds the result to `x`. + ## Returns `true` if `c` is hexadecimal. + ## + ## When `c` is hexadecimal, the proc is equal to `x = x shl 4 + hex2Int(c)`. + runnableExamples: + var x = 0 + assert handleHexChar('a', x) + assert x == 10 + + assert handleHexChar('B', x) + assert x == 171 # 10 shl 4 + 11 + + assert not handleHexChar('?', x) + assert x == 171 # unchanged + result = true case c of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: f = true + else: + result = false proc decodePercent*(s: openArray[char], i: var int): char = ## Converts `%xx` hexadecimal to the character with ordinal number `xx`. @@ -14,9 +30,6 @@ proc decodePercent*(s: openArray[char], i: var int): char = result = '%' if i+2 < s.len: var x = 0 - var failed = false - handleHexChar(s[i+1], x, failed) - handleHexChar(s[i+2], x, failed) - if not failed: + if handleHexChar(s[i+1], x) and handleHexChar(s[i+2], x): result = chr(x) inc(i, 2) diff --git a/nimsuggest/sexp.nim b/nimsuggest/sexp.nim index a4368a558..cee538b6e 100644 --- a/nimsuggest/sexp.nim +++ b/nimsuggest/sexp.nim @@ -12,6 +12,8 @@ import hashes, strutils, lexbase, streams, unicode, macros +import std/private/decode_helpers + type SexpEventKind* = enum ## enumeration of all events that may occur when parsing sexpError, ## an error occurred during parsing @@ -113,14 +115,6 @@ proc errorMsgExpected*(my: SexpParser, e: string): string = ## other error messages result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"] -proc handleHexChar(c: char, x: var int): bool = - result = true # Success - case c - of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) - of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: result = false # error - proc parseString(my: var SexpParser): TTokKind = result = tkString var pos = my.bufpos + 1 diff --git a/tests/stdlib/tdecode_helpers.nim b/tests/stdlib/tdecode_helpers.nim new file mode 100644 index 000000000..626a014fc --- /dev/null +++ b/tests/stdlib/tdecode_helpers.nim @@ -0,0 +1,27 @@ +import std/private/decode_helpers + + +block: + var i = 0 + let c = decodePercent("%t9", i) + doAssert (i, c) == (0, '%') + +block: + var i = 0 + let c = decodePercent("19", i) + doAssert (i, c) == (0, '%') + +block: + var i = 0 + let c = decodePercent("%19", i) + doAssert (i, c) == (2, '\x19') + +block: + var i = 0 + let c = decodePercent("%A9", i) + doAssert (i, c) == (2, '\xA9') + +block: + var i = 0 + let c = decodePercent("%Aa", i) + doAssert (i, c) == (2, '\xAA') From 5d8f862bc644e1db076e7e8cc8a2fe8c99009329 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 17 Dec 2020 14:14:16 -0600 Subject: [PATCH 1670/4254] fix #16364 (#16379) [backport] * fix #16364 * add comments * Update tools/dochack/dochack.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- tools/dochack/dochack.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 471212a50..4a491cf88 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -268,15 +268,13 @@ var template normalize(x: cstring): cstring = x.toLower.replace("_", "") proc escapeCString(x: var cstring) = + # Original strings are already escaped except HTML tags, so + # we only escape `<` and `>`. var s = "" for c in x: case c - of '&': s.add("&") of '<': s.add("<") of '>': s.add(">") - of '"': s.add(""") - of '\'': s.add("'") - of '/': s.add("/") else: s.add(c) x = s.cstring From 868c31e88a68ce16c5c0d9283a41fb3cfcec4c41 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 17 Dec 2020 23:21:55 +0100 Subject: [PATCH 1671/4254] fixes #16365 [backport] (#16381) --- lib/system/strs_v2.nim | 13 ++++----- tests/destructor/tnewruntime_strutils.nim | 32 ++++++++++++++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index f51791da2..fe117997b 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -40,21 +40,22 @@ proc resize(old: int): int {.inline.} = else: result = old * 3 div 2 # for large arrays * 3/2 is better proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = + let newLen = s.len + addlen if isLiteral(s): let oldP = s.p # can't mutate a literal, so we need a fresh copy here: when compileOption("threads"): - s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen))) + s.p = cast[ptr NimStrPayload](allocShared0(contentSize(newLen))) else: - s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len + addlen))) - s.p.cap = s.len + addlen + s.p = cast[ptr NimStrPayload](alloc0(contentSize(newLen))) + s.p.cap = newLen if s.len > 0: # we are about to append, so there is no need to copy the \0 terminator: - copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len) + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen)) else: let oldCap = s.p.cap and not strlitFlag - if s.len + addlen > oldCap: - let newCap = max(s.len + addlen, resize(oldCap)) + if newLen > oldCap: + let newCap = max(newLen, resize(oldCap)) when compileOption("threads"): s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap))) else: diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index b0bceb4b5..0725718d7 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -2,7 +2,10 @@ discard """ valgrind: true cmd: '''nim c -d:nimAllocStats --newruntime -d:useMalloc $file''' output: ''' -@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]''' +@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] +14 +First tasks completed. +Second tasks completed.''' """ import strutils, os, std / wordwrap @@ -211,3 +214,30 @@ staticTests() # bug #12965 let xaa = @[""].join() let xbb = @["", ""].join() + +# bug #16365 + +# Task 1: +when true: + # Task 1_a: + var test_string_a = "name_something" + echo test_string_a.len() + let new_len_a = test_string_a.len - "_something".len() + test_string_a.setLen new_len_a + + echo "First tasks completed." + +# Task 2: +when true: + # Task 2_a + var test_string: string + let some_string = "something" + for i in some_string.items: + test_string.add $i + + # Task 2_b + var test_string_b = "name_something" + let new_len_b = test_string_b.len - "_something".len() + test_string_b.setLen new_len_b + + echo "Second tasks completed." From df17cf5e9e1afae333d9ab755d19d1c9d4d60a0f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 17 Dec 2020 23:53:43 -0800 Subject: [PATCH 1672/4254] misc cleanups (#16383) --- compiler/docgen.nim | 7 ++++--- compiler/modulegraphs.nim | 2 +- lib/system.nim | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 824fafd6b..d21db7634 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -7,20 +7,21 @@ # distribution, for details about the copyright. # -# This is the documentation generator. It is currently pretty simple: No -# semantic checking is done for the code. Cross-references are generated +# This is the documentation generator. Cross-references are generated # by knowing how the anchors are going to be named. import ast, strutils, strtabs, options, msgs, os, ropes, idents, wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, packages/docutils/rst, packages/docutils/rstgen, - json, xmltree, cgi, trees, types, + json, xmltree, trees, types, typesrenderer, astalgo, lineinfos, intsets, pathutils, trees, tables, nimpaths, renderverbatim, osproc +from uri import encodeUrl from std/private/globs import nativeToUnixPath + const exportSection = skField docCmdSkip = "skip" diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index abbefa9b6..e3c54eeae 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -28,7 +28,7 @@ import ast, intsets, tables, options, lineinfos, hashes, idents, incremental, btrees, md5 -import ic / packed_ast +# import ic / packed_ast type SigHash* = distinct MD5Digest diff --git a/lib/system.nim b/lib/system.nim index afd8e467d..0797b7caf 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -873,9 +873,9 @@ else: template ``*(t: untyped): untyped = t template disarm*(x: typed) = - ## Useful for ``disarming`` dangling pointers explicitly for the - ## --newruntime. Regardless of whether --newruntime is used or not - ## this sets the pointer or callback ``x`` to ``nil``. This is an + ## Useful for `disarming` dangling pointers explicitly for `--newruntime`. + ## Regardless of whether `--newruntime` is used or not + ## this sets the pointer or callback `x` to `nil`. This is an ## experimental API! x = nil From 23d23ecb081be6702d74024be8f96d92d9f88a59 Mon Sep 17 00:00:00 2001 From: Matt Haggard Date: Fri, 18 Dec 2020 04:06:13 -0500 Subject: [PATCH 1673/4254] Make 'echo' raise IOErrors when appropriate (#16367) * Make 'echo' raise IOError when fwrite/fflush fail * Fix fwrite return value comparison * Add test for echo raising error and don't fail to release locks in echo * Fix exitcode expectation * Make 'echo' raise IOError on Windows if it fails * Add nimLegacyEchoNoRaise for prior no-IOError echo behavior * Use checkErrMaybe template --- changelog.md | 3 +++ lib/system/io.nim | 24 ++++++++++++++++-------- tests/exception/t16366.nim | 11 +++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 tests/exception/t16366.nim diff --git a/changelog.md b/changelog.md index eec754a89..01eff1cd7 100644 --- a/changelog.md +++ b/changelog.md @@ -63,6 +63,9 @@ - Added `math.isNaN`. +- `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior + silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/system/io.nim b/lib/system/io.nim index b3e1725b4..22059c0a8 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -223,6 +223,9 @@ when defined(windows): # But we cannot call printf directly as the string might contain \0. # So we have to loop over all the sections separated by potential \0s. var i = c_fprintf(f, "%s", s) + if i < 0: + if doRaise: raiseEIO("cannot write string to file") + return while i < s.len: if s[i] == '\0': let w = c_fputc('\0', f) @@ -780,6 +783,13 @@ when declared(stdout): not defined(nintendoswitch) and not defined(freertos) and hostOS != "any" + const echoDoRaise = not defined(nimLegacyEchoNoRaise) # see PR #16366 + + template checkErrMaybe(succeeded: bool): untyped = + if not succeeded: + when echoDoRaise: + checkErr(stdout) + proc echoBinSafe(args: openArray[string]) {.compilerproc.} = when defined(androidNDK): var s = "" @@ -792,20 +802,18 @@ when declared(stdout): proc flockfile(f: File) {.importc, nodecl.} proc funlockfile(f: File) {.importc, nodecl.} flockfile(stdout) + defer: funlockfile(stdout) when defined(windows) and compileOption("threads"): acquireSys echoLock + defer: releaseSys echoLock for s in args: when defined(windows): - writeWindows(stdout, s) + writeWindows(stdout, s, doRaise = echoDoRaise) else: - discard c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout) + checkErrMaybe(c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout) == s.len) const linefeed = "\n" - discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) - discard c_fflush(stdout) - when stdOutLock: - funlockfile(stdout) - when defined(windows) and compileOption("threads"): - releaseSys echoLock + checkErrMaybe(c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) == linefeed.len) + checkErrMaybe(c_fflush(stdout) == 0) when defined(windows) and not defined(nimscript) and not defined(js): diff --git a/tests/exception/t16366.nim b/tests/exception/t16366.nim new file mode 100644 index 000000000..4bcad79ed --- /dev/null +++ b/tests/exception/t16366.nim @@ -0,0 +1,11 @@ +discard """ + action: run + exitcode: 0 + targets: "c cpp" + disabled: openbsd +""" + +echo "foo1" +close stdout +doAssertRaises(IOError): + echo "foo" From dcdbae798c366134cac3d00419fee9ea3dd7bf70 Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Fri, 18 Dec 2020 18:17:19 +0900 Subject: [PATCH 1674/4254] Fix osproc so that it doesn't close pipe/process/thread handles twice (#16385) [backport] * Add error check to closeHandle and fix closing handle twice in osproc * Fix compile error on Linux --- lib/pure/osproc.nim | 58 +++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index d6943c7f8..9c198e6fa 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -414,6 +414,8 @@ proc execProcesses*(cmds: openArray[string], raiseOSError(err) if rexit >= 0: + when defined(windows): + let processHandle = q[rexit].fProcessHandle result = max(result, abs(q[rexit].peekExitCode())) if afterRunEvent != nil: afterRunEvent(idxs[rexit], q[rexit]) close(q[rexit]) @@ -428,7 +430,7 @@ proc execProcesses*(cmds: openArray[string], else: when defined(windows): for k in 0..wcount - 1: - if w[k] == q[rexit].fProcessHandle: + if w[k] == processHandle: w[k] = w[wcount - 1] w[wcount - 1] = 0 dec(wcount) @@ -525,10 +527,17 @@ when defined(Windows) and not defined(useNimRtl): handle: Handle atTheEnd: bool + proc closeHandleCheck(handle: Handle) {.inline.} = + if handle.closeHandle() == 0: + raiseOSError(osLastError()) + + proc fileClose[T: Handle | FileHandle](h: var T) {.inline.} = + if h > 4: + closeHandleCheck(h) + h = INVALID_HANDLE_VALUE.T + proc hsClose(s: Stream) = - # xxx here + elsewhere: check instead of discard; ignoring errors leads to - # hard to track bugs - discard FileHandleStream(s).handle.closeHandle + FileHandleStream(s).handle.fileClose() proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd @@ -633,8 +642,8 @@ when defined(Windows) and not defined(useNimRtl): stdin = myDup(pipeIn, 0) stdout = myDup(pipeOut, 0) - discard closeHandle(pipeIn) - discard closeHandle(pipeOut) + closeHandleCheck(pipeIn) + closeHandleCheck(pipeOut) stderr = stdout proc createPipeHandles(rdHandle, wrHandle: var Handle) = @@ -645,9 +654,6 @@ when defined(Windows) and not defined(useNimRtl): if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32: raiseOSError(osLastError()) - proc fileClose(h: Handle) {.inline.} = - if h > 4: discard closeHandle(h) - proc startProcess(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut}): @@ -742,13 +748,31 @@ when defined(Windows) and not defined(useNimRtl): result.id = procInfo.dwProcessId result.exitFlag = false + proc closeThreadAndProcessHandle(p: Process) = + if p.fThreadHandle != 0: + closeHandleCheck(p.fThreadHandle) + p.fThreadHandle = 0 + + if p.fProcessHandle != 0: + closeHandleCheck(p.fProcessHandle) + p.fProcessHandle = 0 + proc close(p: Process) = if poParentStreams notin p.options: - discard closeHandle(p.inHandle) - discard closeHandle(p.outHandle) - discard closeHandle(p.errHandle) - discard closeHandle(p.fThreadHandle) - discard closeHandle(p.fProcessHandle) + if p.inStream == nil: + p.inHandle.fileClose() + else: + # p.inHandle can be already closed via inputStream. + p.inStream.close + + # You may NOT close outputStream and errorStream. + assert p.outStream == nil or FileHandleStream(p.outStream).handle != INVALID_HANDLE_VALUE + assert p.errStream == nil or FileHandleStream(p.errStream).handle != INVALID_HANDLE_VALUE + + if p.outHandle != p.errHandle: + p.errHandle.fileClose() + p.outHandle.fileClose() + p.closeThreadAndProcessHandle() proc suspend(p: Process) = discard suspendThread(p.fThreadHandle) @@ -782,8 +806,7 @@ when defined(Windows) and not defined(useNimRtl): if status != STILL_ACTIVE: p.exitFlag = true p.exitStatus = status - discard closeHandle(p.fThreadHandle) - discard closeHandle(p.fProcessHandle) + p.closeThreadAndProcessHandle() result = status else: result = -1 @@ -799,8 +822,7 @@ when defined(Windows) and not defined(useNimRtl): discard getExitCodeProcess(p.fProcessHandle, status) p.exitFlag = true p.exitStatus = status - discard closeHandle(p.fThreadHandle) - discard closeHandle(p.fProcessHandle) + p.closeThreadAndProcessHandle() result = status proc inputStream(p: Process): Stream = From 90dbb6f3fbab684afad729903ff322a9792e1706 Mon Sep 17 00:00:00 2001 From: Code Hz Date: Fri, 18 Dec 2020 17:40:43 +0800 Subject: [PATCH 1675/4254] removing `out T` from docs since it no longer working (#16378) [backport] * remove `out T` from docs see https://github.com/nim-lang/Nim/issues/16131 * remove `out T` in title * remove entire paragraph --- doc/manual.rst | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index cb35ee885..fd0ac0529 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2499,13 +2499,13 @@ matches) is preferred: gen(ri) # "ref T" -Overloading based on 'var T' / 'out T' +Overloading based on 'var T' -------------------------------------- -If the formal parameter ``f`` is of type ``var T`` (or ``out T``) -in addition to the ordinary -type checking, the argument is checked to be an `l-value`:idx:. -``var T`` (or ``out T``) matches better than just ``T`` then. +If the formal parameter ``f`` is of type ``var T`` +in addition to the ordinary type checking, +the argument is checked to be an `l-value`:idx:. +``var T`` matches better than just ``T`` then. .. code-block:: nim proc sayHi(x: int): string = @@ -2524,17 +2524,6 @@ type checking, the argument is checked to be an `l-value`:idx:. # 13 -An l-value matches ``var T`` and ``out T`` equally well, hence -the following is ambiguous: - -.. code-block:: nim - - proc p(x: out string) = x = "" - proc p(x: var string) = x = "" - var v: string - p(v) # ambiguous - - Lazy type resolution for untyped -------------------------------- @@ -4975,7 +4964,7 @@ of "typedesc"-ness is stripped off: Generic inference restrictions ------------------------------ -The types ``var T``, ``out T`` and ``typedesc[T]`` cannot be inferred in a generic +The types ``var T`` and ``typedesc[T]`` cannot be inferred in a generic instantiation. The following is not allowed: .. code-block:: nim @@ -6155,10 +6144,10 @@ noSideEffect pragma The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side effects. This means that the proc/iterator only changes locations that are reachable from its parameters and the return value only depends on the -arguments. If none of its parameters have the type ``var T`` or ``out T`` -or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static -error to mark a proc/iterator to have no side effect if the compiler cannot -verify this. +arguments. If none of its parameters have the type ``var T`` or ``ref T`` +or ``ptr T`` this means no locations are modified. It is a static error to +mark a proc/iterator to have no side effect if the compiler cannot verify +this. As a special semantic rule, the built-in `debugEcho `_ pretends to be free of side effects, From 78acf1becb20a26637d0ac03bd8fcc6296aaa0f8 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 18 Dec 2020 09:29:36 -0600 Subject: [PATCH 1676/4254] fix cmpIgnoreStyle bug (#16392) --- lib/core/typeinfo.nim | 1 + tests/stdlib/ttypeinfo.nim | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index fff237718..c15f6dc1f 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -372,6 +372,7 @@ proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = else: result = c var i = 0 var j = 0 + if a[0] != b[0]: return 1 while true: while a[i] == '_': inc(i) while b[j] == '_': inc(j) # BUGFIX: typo diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim index 3155a0f88..fc0bd3e53 100644 --- a/tests/stdlib/ttypeinfo.nim +++ b/tests/stdlib/ttypeinfo.nim @@ -58,3 +58,14 @@ block: for i in 0 .. m.len-1: for j in 0 .. m[i].len-1: doAssert getString(m[i][j]) == myArr[i][j] + +block: + type + Test = enum + Hello, he_llo + + var x = hello + var y = x.toAny + + doAssert getEnumOrdinal(y, "Hello") == 0 + doAssert getEnumOrdinal(y, "hello") == 1 From 0b7847ba3cbbc2baaeeedf6bbe66823079686662 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 18 Dec 2020 09:45:51 -0600 Subject: [PATCH 1677/4254] active windows tests and use doAssert (#16395) --- tests/stdlib/tstreams.nim | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index e0310b5f5..c2ceed624 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -12,7 +12,6 @@ I AM GROOT ''' -disabled: "windows" """ @@ -64,14 +63,14 @@ echo buffer block: var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran") - assert(ss.getPosition == 0) - assert(ss.peekStr(5) == "The q") - assert(ss.getPosition == 0) # haven't moved - assert(ss.readStr(5) == "The q") - assert(ss.getPosition == 5) # did move - assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") - assert(ss.getPosition == 5) # haven't moved + doAssert(ss.getPosition == 0) + doAssert(ss.peekStr(5) == "The q") + doAssert(ss.getPosition == 0) # haven't moved + doAssert(ss.readStr(5) == "The q") + doAssert(ss.getPosition == 5) # did move + doAssert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") + doAssert(ss.getPosition == 5) # haven't moved var str = newString(100) - assert(ss.peekLine(str)) - assert(str == "uick brown fox jumped over the lazy dog.") - assert(ss.getPosition == 5) # haven't moved + doAssert(ss.peekLine(str)) + doAssert(str == "uick brown fox jumped over the lazy dog.") + doAssert(ss.getPosition == 5) # haven't moved From 9674eb3ca67042bb6feb442ce4bcfc64933b5ab4 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 19 Dec 2020 12:33:10 +0300 Subject: [PATCH 1678/4254] RST enumlist followup (#16382) * fix matching of enumerator #) * RST: markdown list with auto-enumerator `1` --- lib/packages/docutils/rst.nim | 25 ++++++++++++++------ tests/stdlib/trstgen.nim | 44 +++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 709173526..0d86edcdb 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -48,6 +48,10 @@ ## * markdown code blocks ## * markdown links ## * markdown headlines +## * using ``1`` as auto-enumerator in enumerated lists like RST ``#`` +## (auto-enumerator ``1`` can not be used with ``#`` in the same list) +## +## **Note:** By default nim has ``roSupportMarkdown`` turned **on**. ## ## Limitations: ## @@ -1195,7 +1199,8 @@ proc whichSection(p: RstParser): RstNodeKind = elif match(p, p.idx, ":w:") and predNL(p): # (currentTok(p).symbol == ":") result = rnFieldList - elif match(p, p.idx, "(e) ") or match(p, p.idx, "e. "): + elif match(p, p.idx, "(e) ") or match(p, p.idx, "e) ") or + match(p, p.idx, "e. "): result = rnEnumList elif isDefList(p): result = rnDefList @@ -1537,8 +1542,12 @@ proc parseEnumList(p: var RstParser): PRstNode = if match(p, p.idx, wildcards[w]): break inc w assert w < wildcards.len + let autoEnums = if roSupportMarkdown in p.s.options: @["#", "1"] else: @["#"] + var prevAE = "" # so as not allow mixing auto-enumerators `1` and `#` + var curEnum = 1 for i in 0 ..< wildToken[w]-1: # add first enumerator with (, ), and . if p.tok[p.idx + i].symbol == "#": + prevAE = "#" result.text.add "1" else: result.text.add p.tok[p.idx + i].symbol @@ -1556,17 +1565,19 @@ proc parseEnumList(p: var RstParser): PRstNode = # check that it's in sequence: enumerator == next(prevEnum) if "n" in wildcards[w]: # arabic numeral let prevEnumI = try: parseInt(prevEnum) except: 1 - let curEnum = - if enumerator == "#": prevEnumI + 1 - else: (try: parseInt(enumerator) except: 1) + if enumerator in autoEnums: + if prevAE != "" and enumerator != prevAE: + break + prevAE = enumerator + curEnum = prevEnumI + 1 + else: curEnum = (try: parseInt(enumerator) except: 1) if curEnum - prevEnumI != 1: break prevEnum = enumerator else: # a..z let prevEnumI = ord(prevEnum[0]) - let curEnum = - if enumerator == "#": prevEnumI + 1 - else: ord(enumerator[0]) + if enumerator == "#": curEnum = prevEnumI + 1 + else: curEnum = ord(enumerator[0]) if curEnum - prevEnumI != 1: break prevEnum = $chr(curEnum) diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index f3a8aa59a..85a96056a 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -440,13 +440,30 @@ Test1 Check that auto-numbered enumeration lists work. #. string1 + + #. string2 + + #. string3 + + #) string5 + #) string6 + """ + let output5 = rstToHtml(input5, {roSupportMarkdown}, defaultConfig()) + assert count(output5, "
                  ") == 2 + assert count(output5, "
                1. ") == 5 + + let input5a = dedent """ + Auto-numbered RST list can start with 1 even when Markdown support is on. + + 1. string1 #. string2 #. string3 """ - let output5 = rstToHtml(input5, {roSupportMarkdown}, defaultConfig()) - assert count(output5, "
                    ") == 1 - assert count(output5, "
                  1. ") == 3 + let output5a = rstToHtml(input5a, {roSupportMarkdown}, defaultConfig()) + assert count(output5a, "
                      ") == 1 + assert count(output5a, "
                    1. ") == 3 let input6 = dedent """ ... And for alphabetic enumerators too! @@ -474,6 +491,25 @@ Test1 assert count(output7, "
                    2. ") == 3 assert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7 + test "Markdown enumerated lists": + let input1 = dedent """ + Below are 2 enumerated lists: Markdown-style (5 items) and RST (1 item) + 1. line1 + 1. line2 + 1. line3 + 1. line4 + + 1. line5 + + #. lineA + """ + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + for i in 1..5: + assert ($i & ". line" & $i) notin output1 + assert ("
                    3. line" & $i & "
                    4. ") in output1 + assert count(output1, "
                        ") == 2 + test "RST bullet lists": let input1 = dedent """ * line1 From 051477b314acae9141eb697ff369385643f1bbbf Mon Sep 17 00:00:00 2001 From: Peter Salvi Date: Sun, 20 Dec 2020 13:09:35 +0100 Subject: [PATCH 1679/4254] O(1) concatenation of singly- and doubly linked lists. (#16362) * O(1) concatenation of singly- and doubly linked lists. There is also new `toSinglyLinkedList` and `toDoublyLinkedList` functions for conversion from `openArray`s, similarly to `toHashSet` or `toTable`. * Add `sequtils` import to runnable examples with `toSeq`. * Added missing call to runnable examples. * Add .since annotation, changelog, and tests. * Rename `lists.concat` as an overload to `lists.append`. * Renamed `append` to `add` in lists. * Remove faulty `add` for `DoublyLinkedList`s. * Improved tests for lists. * `lists.add` moves the second list; added `lists.copy` for shallow copy. * More tests for `lists.add` and `lists.copy`. * More compact tests for lists with templates. * List concatenation with copying (`add`) and moving (tentatively `addMove`) * Renamed `addMove` to `addMoved`; renamed arguments according to the style guide. * Added extended example to `lists.copy`. * Corrected .since annotations to 1.6 * Add .since annotation, changelog, and tests. * Rename `lists.concat` as an overload to `lists.append`. * Renamed `append` to `add` in lists. * Remove faulty `add` for `DoublyLinkedList`s. * `lists.add` moves the second list; added `lists.copy` for shallow copy. * More tests for `lists.add` and `lists.copy`. * List concatenation with copying (`add`) and moving (tentatively `addMove`) * Renamed `addMove` to `addMoved`; renamed arguments according to the style guide. * Since declarations changed to (1,5,1). * Add .since annotation, changelog, and tests. * Rename `lists.concat` as an overload to `lists.append`. * Renamed `append` to `add` in lists. * Remove faulty `add` for `DoublyLinkedList`s. * `lists.add` moves the second list; added `lists.copy` for shallow copy. * More tests for `lists.add` and `lists.copy`. * List concatenation with copying (`add`) and moving (tentatively `addMove`) * Renamed `addMove` to `addMoved`; renamed arguments according to the style guide. * Changelog update. * Fix rebasing errors. * Self-adding with `lists.addMove` results in a cycle now. Added some extra tests. --- changelog.md | 5 ++ lib/pure/collections/lists.nim | 146 +++++++++++++++++++++++++++++++++ tests/stdlib/tlists.nim | 69 +++++++++++++++- 3 files changed, 219 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 01eff1cd7..89d8fd423 100644 --- a/changelog.md +++ b/changelog.md @@ -66,6 +66,11 @@ - `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. +- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList` + and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements + shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes + its argument, `addMoved`, is also supplied. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index bd22949bf..8af0ed826 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -72,6 +72,7 @@ ## * `deques module `_ for double-ended queues ## * `sharedlist module `_ for shared singly-linked lists +import std/private/since when not defined(nimhygiene): {.pragma: dirty.} @@ -178,6 +179,26 @@ proc newSinglyLinkedNode*[T](value: T): (SinglyLinkedNode[T]) = new(result) result.value = value +func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = + ## Creates a new `SinglyLinkedList` from members of `elems`. + runnableExamples: + import sequtils + let a = [1, 2, 3, 4, 5].toSinglyLinkedList + assert a.toSeq == [1, 2, 3, 4, 5] + result = initSinglyLinkedList[T]() + for elem in elems.items: + result.append(elem) + +func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = + ## Creates a new `DoublyLinkedList` from members of `elems`. + runnableExamples: + import sequtils + let a = [1, 2, 3, 4, 5].toDoublyLinkedList + assert a.toSeq == [1, 2, 3, 4, 5] + result = initDoublyLinkedList[T]() + for elem in elems.items: + result.append(elem) + template itemsListImpl() {.dirty.} = var it = L.head while it != nil: @@ -435,7 +456,60 @@ proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = assert a.contains(9) prepend(L, newSinglyLinkedNode(value)) +func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = + ## Creates a shallow copy of `a`. + runnableExamples: + import sequtils + type Foo = ref object + x: int + var + f = Foo(x: 1) + a = [f].toSinglyLinkedList + let b = a.copy + a.add [f].toSinglyLinkedList + assert a.toSeq == [f, f] + assert b.toSeq == [f] # b isn't modified... + f.x = 42 + assert a.head.value.x == 42 + assert b.head.value.x == 42 # ... but the elements are not deep copied + let c = [1, 2, 3].toSinglyLinkedList + assert $c == $c.copy + result = initSinglyLinkedList[T]() + for x in a.items: + result.append(x) + +proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = + ## Moves `b` to the end of `a`. Efficiency: O(1). + ## Note that `b` becomes empty after the operation unless it has the same address as `a`. + ## Self-adding results in a cycle. + ## + ## See also: + ## * `add proc <#add,T,T>`_ + ## for adding a copy of a list + runnableExamples: + import sequtils, std/enumerate, std/sugar + var + a = [1, 2, 3].toSinglyLinkedList + b = [4, 5].toSinglyLinkedList + c = [0, 1].toSinglyLinkedList + a.addMoved b + assert a.toSeq == [1, 2, 3, 4, 5] + assert b.toSeq == [] + c.addMoved c + let s = collect: + for i, ci in enumerate(c): + if i == 6: break + ci + assert s == [0, 1, 0, 1, 0, 1] + if a.tail != nil: + a.tail.next = b.head + a.tail = b.tail + if a.head == nil: + a.head = b.head + if a.addr != b.addr: + b.head = nil + b.tail = nil proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). @@ -523,6 +597,78 @@ proc prepend*[T](L: var DoublyLinkedList[T], value: T) = assert a.contains(9) prepend(L, newDoublyLinkedNode(value)) +func copy*[T](a: DoublyLinkedList[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = + ## Creates a shallow copy of `a`. + runnableExamples: + type Foo = ref object + x: int + var f = Foo(x: 1) + let + a = [f].toDoublyLinkedList + b = a.copy + f.x = 42 + assert a.head.value.x == 42 + assert b.head.value.x == 42 + + let c = [1, 2, 3].toDoublyLinkedList + assert $c == $c.copy + result = initDoublyLinkedList[T]() + for x in a.items: + result.append(x) + +proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = + ## Moves `b` to the end of `a`. Efficiency: O(1). + ## Note that `b` becomes empty after the operation unless it has the same address as `a`. + ## Self-adding results in a cycle. + ## + ## See also: + ## * `add proc <#add,T,T>`_ + ## for adding a copy of a list + runnableExamples: + import sequtils, std/enumerate, std/sugar + var + a = [1, 2, 3].toDoublyLinkedList + b = [4, 5].toDoublyLinkedList + c = [0, 1].toDoublyLinkedList + a.addMoved b + assert a.toSeq == [1, 2, 3, 4, 5] + assert b.toSeq == [] + c.addMoved c + let s = collect: + for i, ci in enumerate(c): + if i == 6: break + ci + assert s == [0, 1, 0, 1, 0, 1] + if b.head != nil: + b.head.prev = a.tail + if a.tail != nil: + a.tail.next = b.head + a.tail = b.tail + if a.head == nil: + a.head = b.head + if a.addr != b.addr: + b.head = nil + b.tail = nil + +proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = + ## Appends a shallow copy of `b` to the end of `a`. + ## + ## See also: + ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ + ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ + ## for moving the second list instead of copying + runnableExamples: + import sequtils + var a = [1, 2, 3].toSinglyLinkedList + let b = [4, 5].toSinglyLinkedList + a.add b + assert a.toSeq == [1, 2, 3, 4, 5] + assert b.toSeq == [4, 5] + a.add a + assert a.toSeq == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] + var tmp = b.copy + a.addMoved tmp + proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## Removes a node `n` from `L`. Efficiency: O(1). runnableExamples: diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index fe814bb92..59ac8d7ee 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -2,7 +2,7 @@ discard """ targets: "c js" """ -import lists +import lists, sequtils, std/enumerate, std/sugar const data = [1, 2, 3, 4, 5, 6] @@ -81,3 +81,70 @@ block tlistsToString: l.append('2') l.append('3') doAssert $l == """['1', '2', '3']""" + +template testCommon(initList, toList) = + + block: # toSinglyLinkedList, toDoublyLinkedList + let l = seq[int].default + doAssert l.toList.toSeq == [] + doAssert [1].toList.toSeq == [1] + doAssert [1, 2, 3].toList.toSeq == [1, 2, 3] + + block copy: + doAssert array[0, int].default.toList.copy.toSeq == [] + doAssert [1].toList.copy.toSeq == [1] + doAssert [1, 2].toList.copy.toSeq == [1, 2] + doAssert [1, 2, 3].toList.copy.toSeq == [1, 2, 3] + type Foo = ref object + x: int + var f0 = Foo(x: 0) + let f1 = Foo(x: 1) + var a = [f0].toList + var b = a.copy + b.append f1 + doAssert a.toSeq == [f0] + doAssert b.toSeq == [f0, f1] + f0.x = 42 + assert a.head.value.x == 42 + assert b.head.value.x == 42 + + block: # add, addMoved + block: + var + l0 = initList[int]() + l1 = [1].toList + l2 = [2, 3].toList + l3 = [4, 5, 6].toList + l0.add l3 + l1.add l3 + l2.addMoved l3 + doAssert l0.toSeq == [4, 5, 6] + doAssert l1.toSeq == [1, 4, 5, 6] + doAssert l2.toSeq == [2, 3, 4, 5, 6] + doAssert l3.toSeq == [] + l2.add l3 # re-adding l3 that was destroyed is now a no-op + doAssert l2.toSeq == [2, 3, 4, 5, 6] + doAssert l3.toSeq == [] + block: + var + l0 = initList[int]() + l1 = [1].toList + l2 = [2, 3].toList + l3 = [4, 5, 6].toList + l3.addMoved l0 + l2.addMoved l1 + doAssert l3.toSeq == [4, 5, 6] + doAssert l2.toSeq == [2, 3, 1] + l3.add l0 + doAssert l3.toSeq == [4, 5, 6] + block: + var c = [0, 1].toList + c.addMoved c + let s = collect: + for i, ci in enumerate(c): + if i == 6: break + ci + doAssert s == [0, 1, 0, 1, 0, 1] + +testCommon initSinglyLinkedList, toSinglyLinkedList +testCommon initDoublyLinkedList, toDoublyLinkedList From d435bfcb3bf4882626686d53da238a38d4c753e1 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 20 Dec 2020 20:59:32 -0600 Subject: [PATCH 1680/4254] disable ggplot and plotly (#16418) --- testament/important_packages.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index aae560939..ebe7bcf01 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -41,7 +41,7 @@ pkg1 "fidget" pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "glob" -pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" +# pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pending bug #16418 # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" pkg1 "gnuplot", "nim c gnuplot.nim" pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" @@ -99,7 +99,7 @@ pkg2 "optionsutils" pkg2 "ormin", "nim c -o:orminn ormin.nim" pkg2 "parsetoml" pkg2 "patty" -pkg2 "plotly", "nim c examples/all.nim" +# pkg2 "plotly", "nim c examples/all.nim" # pending bug #16418 pkg2 "pnm" pkg2 "polypbren" pkg2 "prologue", "nimble tcompile" From d00a4121297fbb8824cffeecd7aab132a5769b11 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 20 Dec 2020 21:53:27 -0600 Subject: [PATCH 1681/4254] docs minor for math (#16407) --- lib/pure/math.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 5f3261f1a..0e6ffe053 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -144,8 +144,8 @@ func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = doAssert NaN.isNaN doAssert not Inf.isNaN doAssert isNaN(Inf - Inf) - doAssert not isNan(3.1415926) - doAssert not isNan(0'f32) + doAssert not isNaN(3.1415926) + doAssert not isNaN(0'f32) template fn: untyped = result = x != x when nimvm: fn() From 29c9a1c14b67ababca7b8ad7f80a0b84d74cfc9b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 21 Dec 2020 03:34:00 -0600 Subject: [PATCH 1682/4254] bring back important packages; closes #16419 (#16424) --- testament/important_packages.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index ebe7bcf01..aae560939 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -41,7 +41,7 @@ pkg1 "fidget" pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "glob" -# pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pending bug #16418 +pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" pkg1 "gnuplot", "nim c gnuplot.nim" pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" @@ -99,7 +99,7 @@ pkg2 "optionsutils" pkg2 "ormin", "nim c -o:orminn ormin.nim" pkg2 "parsetoml" pkg2 "patty" -# pkg2 "plotly", "nim c examples/all.nim" # pending bug #16418 +pkg2 "plotly", "nim c examples/all.nim" pkg2 "pnm" pkg2 "polypbren" pkg2 "prologue", "nimble tcompile" From 297c8e403d110dd872e070563328f4e0c734cd01 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Mon, 21 Dec 2020 18:41:56 +0100 Subject: [PATCH 1683/4254] styleCheck: Fix some inconsistent identifiers (#16177) --- lib/experimental/diff.nim | 4 ++-- lib/js/dom.nim | 10 +++++----- lib/js/jsffi.nim | 4 ++-- lib/nimhcr.nim | 4 ++-- lib/pure/asyncmacro.nim | 2 +- lib/pure/concurrency/threadpool.nim | 24 +++++++++++------------ lib/pure/ioselects/ioselectors_poll.nim | 2 +- lib/pure/ioselects/ioselectors_select.nim | 2 +- lib/pure/memfiles.nim | 4 ++-- lib/pure/nativesockets.nim | 2 +- lib/pure/net.nim | 8 ++++---- lib/pure/punycode.nim | 8 ++++---- lib/pure/selectors.nim | 2 +- lib/pure/smtp.nim | 16 +++++++-------- lib/pure/ssl_certs.nim | 4 ++-- lib/pure/stats.nim | 4 ++-- lib/system/gc_regions.nim | 8 ++++---- lib/system/mm/go.nim | 4 ++-- lib/system/nimscript.nim | 2 +- lib/system/sysspawn.nim | 14 ++++++------- 20 files changed, 64 insertions(+), 64 deletions(-) diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim index d1274d771..9a92aba72 100644 --- a/lib/experimental/diff.nim +++ b/lib/experimental/diff.nim @@ -138,7 +138,7 @@ proc sms(dataA: var DiffData; lowerA, upperA: int; dataB: DiffData; lowerB, uppe for D in 0 .. maxD: # Extend the forward path. - for k in countUp(downK - D, downK + D, 2): + for k in countup(downK - D, downK + D, 2): # find the only or better starting point var x: int if k == downK - D: @@ -164,7 +164,7 @@ proc sms(dataA: var DiffData; lowerA, upperA: int; dataB: DiffData; lowerB, uppe y: downVector[downOffset + k] - k) # Extend the reverse path. - for k in countUp(upK - D, upK + D, 2): + for k in countup(upK - D, upK + D, 2): # find the only or better starting point var x: int if k == upK + D: diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 4dbb4f77a..d4e8ce86a 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1460,8 +1460,8 @@ else: proc createTextNode*(d: Document, identifier: cstring): Node {.importcpp.} proc createComment*(d: Document, data: cstring): Node {.importcpp.} -proc setTimeout*(action: proc(); ms: int): Timeout {.importc, nodecl.} -proc clearTimeout*(t: Timeout) {.importc, nodecl.} +proc setTimeout*(action: proc(); ms: int): TimeOut {.importc, nodecl.} +proc clearTimeout*(t: TimeOut) {.importc, nodecl.} {.push importcpp.} @@ -1719,9 +1719,9 @@ proc offsetTop*(e: Node): int {.importcpp: "#.offsetTop", nodecl.} proc offsetLeft*(e: Node): int {.importcpp: "#.offsetLeft", nodecl.} since (1, 3): - func newDomParser*(): DOMParser {.importcpp: "new DOMParser()".} + func newDomParser*(): DomParser {.importcpp: "new DOMParser()".} ## DOM Parser constructor. - func parseFromString*(this: DOMParser; str: cstring; mimeType: cstring): Document {.importcpp.} + func parseFromString*(this: DomParser; str: cstring; mimeType: cstring): Document {.importcpp.} ## Parse from string to `Document`. proc newDomException*(): DomException {.importcpp: "new DomException()", constructor.} @@ -1733,7 +1733,7 @@ since (1, 3): proc newFileReader*(): FileReader {.importcpp: "new FileReader()", constructor.} ## File Reader constructor - proc error*(f: FileReader): DOMException {.importcpp: "#.error", nodecl.} + proc error*(f: FileReader): DomException {.importcpp: "#.error", nodecl.} ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/error proc readyState*(f: FileReader): FileReaderState {.importcpp: "#.readyState", nodecl.} ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readyState diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 5140ff372..9fe934f89 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -380,7 +380,7 @@ iterator pairs*[K: JsKey, V](assoc: JsAssoc[K, V]): (K,V) = yield (k.toJsKey(K), v) {.emit: "}".} -iterator items*[K, V](assoc: JSAssoc[K, V]): V = +iterator items*[K, V](assoc: JsAssoc[K, V]): V = ## Yields the `values` in a JsAssoc. var v: V {.emit: "for (var k in `assoc`) {".} @@ -389,7 +389,7 @@ iterator items*[K, V](assoc: JSAssoc[K, V]): V = yield v {.emit: "}".} -iterator keys*[K: JsKey, V](assoc: JSAssoc[K, V]): K = +iterator keys*[K: JsKey, V](assoc: JsAssoc[K, V]): K = ## Yields the `keys` in a JsAssoc. var k: cstring {.emit: "for (var `k` in `assoc`) {".} diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 89bece6dc..fcc0ffdbe 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -230,7 +230,7 @@ when defined(createNimHcr): when defined(testNimHcr): return ($arg).splitFile.name.splitFile.name else: return $arg - {.pragma: nimhcr, compilerProc, exportc, dynlib.} + {.pragma: nimhcr, compilerproc, exportc, dynlib.} # XXX these types are CPU specific and need ARM etc support type @@ -622,7 +622,7 @@ elif defined(hotcodereloading) or defined(testNimHcr): elif defined(macosx): "libnimhcr." & dllExt else: "libnimhcr." & dllExt - {.pragma: nimhcr, compilerProc, importc, dynlib: nimhcrLibname.} + {.pragma: nimhcr, compilerproc, importc, dynlib: nimhcrLibname.} proc hcrRegisterProc*(module: cstring, name: cstring, fn: pointer): pointer {.nimhcr.} diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index dd2393a63..c60c5e4ca 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -182,7 +182,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = elif returnType.kind == nnkEmpty: baseType = returnType else: - verifyReturnType(repr(returnType), returntype) + verifyReturnType(repr(returnType), returnType) let subtypeIsVoid = returnType.kind == nnkEmpty or (baseType.kind == nnkIdent and returnType[1].eqIdent("void")) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 34a65ead2..a4460165d 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -54,7 +54,7 @@ proc signal(cv: var Semaphore) = const CacheLineSize = 32 # true for most archs type - Barrier {.compilerProc.} = object + Barrier {.compilerproc.} = object entered: int cv: Semaphore # Semaphore takes 3 words at least when sizeof(int) < 8: @@ -63,26 +63,26 @@ type cacheAlign2: array[CacheLineSize-sizeof(int), byte] interest: bool # whether the master is interested in the "all done" event -proc barrierEnter(b: ptr Barrier) {.compilerProc, inline.} = +proc barrierEnter(b: ptr Barrier) {.compilerproc, inline.} = # due to the signaling between threads, it is ensured we are the only # one with access to 'entered' so we don't need 'atomicInc' here: inc b.entered # also we need no 'fence' instructions here as soon 'nimArgsPassingDone' # will be called which already will perform a fence for us. -proc barrierLeave(b: ptr Barrier) {.compilerProc, inline.} = +proc barrierLeave(b: ptr Barrier) {.compilerproc, inline.} = atomicInc b.left when not defined(x86): fence() # We may not have seen the final value of b.entered yet, # so we need to check for >= instead of ==. if b.interest and b.left >= b.entered: signal(b.cv) -proc openBarrier(b: ptr Barrier) {.compilerProc, inline.} = +proc openBarrier(b: ptr Barrier) {.compilerproc, inline.} = b.entered = 0 b.left = 0 b.interest = false -proc closeBarrier(b: ptr Barrier) {.compilerProc.} = +proc closeBarrier(b: ptr Barrier) {.compilerproc.} = fence() if b.left != b.entered: b.cv.initSemaphore() @@ -114,7 +114,7 @@ type FlowVarObj[T] = object of FlowVarBaseObj blob: T - FlowVar*{.compilerProc.}[T] = ref FlowVarObj[T] ## A data flow variable. + FlowVar*{.compilerproc.}[T] = ref FlowVarObj[T] ## A data flow variable. ToFreeQueue = object len: int @@ -212,14 +212,14 @@ proc `=destroy`[T](fv: var FlowVarObj[T]) = finished(fv) `=destroy`(fv.blob) -proc nimCreateFlowVar[T](): FlowVar[T] {.compilerProc.} = +proc nimCreateFlowVar[T](): FlowVar[T] {.compilerproc.} = new(result) -proc nimFlowVarCreateSemaphore(fv: FlowVarBase) {.compilerProc.} = +proc nimFlowVarCreateSemaphore(fv: FlowVarBase) {.compilerproc.} = fv.cv.initSemaphore() fv.usesSemaphore = true -proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} = +proc nimFlowVarSignal(fv: FlowVarBase) {.compilerproc.} = if fv.ai != nil: acquire(fv.ai.cv.L) fv.ai.idx = fv.idx @@ -305,7 +305,7 @@ proc isReady*(fv: FlowVarBase): bool = else: result = true -proc nimArgsPassingDone(p: pointer) {.compilerProc.} = +proc nimArgsPassingDone(p: pointer) {.compilerproc.} = let w = cast[ptr Worker](p) signal(w.taskStarted) @@ -489,7 +489,7 @@ var initLock stateLock -proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} = +proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerproc.} = # implementation of 'spawn' that is used by the code generator. while true: if selectWorker(readyWorker, fn, data): return @@ -574,7 +574,7 @@ var initLock distinguishedLock -proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} = +proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerproc.} = acquire(distinguishedLock) if not distinguishedData[id].initialized: activateDistinguishedThread(id) diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 00e2f3fe9..6b10e19ae 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -209,7 +209,7 @@ proc close*(ev: SelectEvent) = raiseIOSelectorsError(osLastError()) proc selectInto*[T](s: Selector[T], timeout: int, - results: var openarray[ReadyKey]): int = + results: var openArray[ReadyKey]): int = var maxres = MAX_POLL_EVENTS if maxres > len(results): maxres = len(results) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 2fd9ac0ba..6f216ac85 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -305,7 +305,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = s.delKey(fd) proc selectInto*[T](s: Selector[T], timeout: int, - results: var openarray[ReadyKey]): int = + results: var openArray[ReadyKey]): int = var tv = Timeval() var ptv = addr tv var rset, wset, eset: FdSet diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 09db80936..5e6571e11 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -232,8 +232,8 @@ proc open*(filename: string, mode: FileMode = fmRead, if newFileSize != -1: flags = flags or O_CREAT or O_TRUNC - var permissions_mode = S_IRUSR or S_IWUSR - result.handle = open(filename, flags, permissions_mode) + var permissionsMode = S_IRUSR or S_IWUSR + result.handle = open(filename, flags, permissionsMode) else: result.handle = open(filename, flags) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 1f597f8eb..f1445fca5 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -209,7 +209,7 @@ proc getProtoByName*(name: string): int {.since: (1, 3, 5).} = let protoent = posix.getprotobyname(name.cstring) if protoent == nil: - raise newException(OsError, "protocol not found") + raise newException(OSError, "protocol not found") result = protoent.p_proto.int diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 02441e8a0..7b92a5e0d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -551,7 +551,7 @@ when defineSsl: proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, certFile = "", keyFile = "", cipherList = CiphersIntermediate, - caDir = "", caFile = ""): SSLContext = + caDir = "", caFile = ""): SslContext = ## Creates an SSL context. ## ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 @@ -644,7 +644,7 @@ when defineSsl: if not found: raise newException(IOError, "No SSL/TLS CA certificates found.") - result = SSLContext(context: newCTX, referencedData: initHashSet[int](), + result = SslContext(context: newCTX, referencedData: initHashSet[int](), extraInternal: new(SslContextExtraInternal)) proc getExtraInternal(ctx: SslContext): SslContextExtraInternal = @@ -750,7 +750,7 @@ when defineSsl: ## Wildcards match only in the left-most label. ## When name starts with a dot it will be matched by a certificate valid for any subdomain when not defined(nimDisableCertificateValidation) and not defined(windows): - assert socket.isSSL + assert socket.isSsl let certificate = socket.sslHandle.SSL_get_peer_certificate() if certificate.isNil: raiseSSLError("No SSL certificate found.") @@ -763,7 +763,7 @@ when defineSsl: if match != 1: raiseSSLError("SSL Certificate check failed.") - proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket, + proc wrapConnectedSocket*(ctx: SslContext, socket: Socket, handshake: SslHandshakeType, hostname: string = "") = ## Wraps a connected socket in an SSL context. This function effectively diff --git a/lib/pure/punycode.nim b/lib/pure/punycode.nim index e9e11a1c3..dfeeea35e 100644 --- a/lib/pure/punycode.nim +++ b/lib/pure/punycode.nim @@ -161,13 +161,13 @@ proc decode*(encoded: string): string {.raises: [PunyError].} = break w *= Base - t k += Base - bias = adapt(i - oldi, runelen(result) + 1, oldi == 0) + bias = adapt(i - oldi, runeLen(result) + 1, oldi == 0) - if i div (runelen(result) + 1) > high(int32) - n: + if i div (runeLen(result) + 1) > high(int32) - n: raise newException(PunyError, "Value too large") - n += i div (runelen(result) + 1) - i = i mod (runelen(result) + 1) + n += i div (runeLen(result) + 1) + i = i mod (runeLen(result) + 1) insert(result, $Rune(n), i) inc i diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 933b5491a..20bf1b3b0 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -162,7 +162,7 @@ when defined(nimdoc): ## Unregisters file/socket descriptor ``fd`` from selector ``s``. proc selectInto*[T](s: Selector[T], timeout: int, - results: var openarray[ReadyKey]): int = + results: var openArray[ReadyKey]): int = ## Waits for events registered in selector ``s``. ## ## The ``timeout`` argument specifies the maximum number of milliseconds diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index c0b6665b2..66d181d40 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -112,17 +112,17 @@ proc quitExcpt(smtp: Smtp, msg: string) = const compiledWithSsl = defined(ssl) when not defined(ssl): - let defaultSSLContext: SSLContext = nil + let defaultSSLContext: SslContext = nil else: - var defaultSSLContext {.threadvar.}: SSLContext + var defaultSSLContext {.threadvar.}: SslContext - proc getSSLContext(): SSLContext = + proc getSSLContext(): SslContext = if defaultSSLContext == nil: defaultSSLContext = newContext(verifyMode = CVerifyNone) result = defaultSSLContext proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], - otherHeaders: openarray[tuple[name, value: string]]): Message = + otherHeaders: openArray[tuple[name, value: string]]): Message = ## Creates a new MIME compliant message. ## ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain @@ -172,7 +172,7 @@ proc `$`*(msg: Message): string = result.add(msg.msgBody) proc newSmtp*(useSsl = false, debug = false, - sslContext: SSLContext = nil): Smtp = + sslContext: SslContext = nil): Smtp = ## Creates a new ``Smtp`` instance. new result result.debug = debug @@ -187,7 +187,7 @@ proc newSmtp*(useSsl = false, debug = false, {.error: "SMTP module compiled without SSL support".} proc newAsyncSmtp*(useSsl = false, debug = false, - sslContext: SSLContext = nil): AsyncSmtp = + sslContext: SslContext = nil): AsyncSmtp = ## Creates a new ``AsyncSmtp`` instance. new result result.debug = debug @@ -222,7 +222,7 @@ proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = ## `SMTP extensions`_. var line = await smtp.debugRecv() - if not line.startswith(reply): + if not line.startsWith(reply): await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line) proc helo*(smtp: Smtp | AsyncSmtp) {.multisync.} = @@ -239,7 +239,7 @@ proc connect*(smtp: Smtp | AsyncSmtp, await smtp.checkReply("220") await smtp.helo() -proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SSLContext = nil) {.multisync.} = +proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SslContext = nil) {.multisync.} = ## Put the SMTP connection in TLS (Transport Layer Security) mode. ## May fail with ReplyError await smtp.debugSend("STARTTLS\c\L") diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index d04244307..c1003f445 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -20,7 +20,7 @@ import strutils # FWIW look for files before scanning entire dirs. -const certificate_paths = [ +const certificatePaths = [ # Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo # NetBSD (security/mozilla-rootcerts) # SLES10/SLES11, https://golang.org/issue/12139 @@ -77,7 +77,7 @@ iterator scanSSLCertificates*(useEnvVars = false): string = else: when not defined(haiku): - for p in certificate_paths: + for p in certificatePaths: if p.endsWith(".pem") or p.endsWith(".crt"): if fileExists(p): yield p diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 20fd1fdcd..af6cffef2 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -103,7 +103,7 @@ proc push*(s: var RunningStat, x: int) = ## and the other push operation is called. s.push(toFloat(x)) -proc push*(s: var RunningStat, x: openarray[float|int]) = +proc push*(s: var RunningStat, x: openArray[float|int]) = ## pushes all values of `x` for processing. ## ## Int values of `x` are simply converted to ``float`` and @@ -277,7 +277,7 @@ proc push*(r: var RunningRegress, x, y: int) {.inline.} = ## and the other push operation is called. r.push(toFloat(x), toFloat(y)) -proc push*(r: var RunningRegress, x, y: openarray[float|int]) = +proc push*(r: var RunningRegress, x, y: openArray[float|int]) = ## pushes two sets of values `x` and `y` for processing. assert(x.len == y.len) for i in 0.. Date: Mon, 21 Dec 2020 17:05:21 -0800 Subject: [PATCH 1684/4254] [backport => 1.0] fix #16428 vmops now works for generic procs (#16429) * fix #16428 vmops now works for generic procs * remove duplication --- compiler/vmgen.nim | 12 ++---------- lib/pure/math.nim | 2 ++ tests/vm/tvmops.nim | 4 ++++ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 9086b17d9..2fbb78c8f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1954,14 +1954,6 @@ proc genProc*(c: PCtx; s: PSym): int proc matches(s: PSym; x: string): bool = let y = x.split('.') - var s = s - for i in 1..y.len: - if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"): - return false - s = s.owner - result = true - -proc matches(s: PSym; y: varargs[string]): bool = var s = s for i in 1..y.len: if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"): @@ -2024,11 +2016,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = elif s.kind == skMethod: localError(c.config, n.info, "cannot call method " & s.name.s & " at compile time") - elif matches(s, "stdlib", "marshal", "to"): + elif matches(s, "stdlib.marshal.to"): # XXX marshal load&store should not be opcodes, but use the # general callback mechanisms. genMarshalLoad(c, n, dest) - elif matches(s, "stdlib", "marshal", "$$"): + elif matches(s, "stdlib.marshal.$$"): genMarshalStore(c, n, dest) else: genCall(c, n, dest) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 0e6ffe053..c05e47545 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -567,6 +567,8 @@ else: # JS func tanh*[T: float32|float64](x: T): T {.importc: "Math.tanh", nodecl.} func arcsin*[T: float32|float64](x: T): T {.importc: "Math.asin", nodecl.} + # keep this as generic or update test in `tvmops.nim` to make sure we + # keep testing that generic importc procs work func arccos*[T: float32|float64](x: T): T {.importc: "Math.acos", nodecl.} func arctan*[T: float32|float64](x: T): T {.importc: "Math.atan", nodecl.} func arctan2*[T: float32|float64](y, x: T): T {.importc: "Math.atan2", nodecl.} diff --git a/tests/vm/tvmops.nim b/tests/vm/tvmops.nim index 6442c49d6..c8febd982 100644 --- a/tests/vm/tvmops.nim +++ b/tests/vm/tvmops.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c cpp js" +""" + #[ test for vmops.nim ]# From 7256afb00d4451f96b525039b39109d21561a14d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 22 Dec 2020 04:18:13 -0600 Subject: [PATCH 1685/4254] mark abs as inline (#16432) --- lib/system.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 0797b7caf..85ef15e08 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2029,15 +2029,15 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.} ## `_ instead. {.push stackTrace: off.} -proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} = +func abs*(x: int): int {.magic: "AbsI", inline.} = if x < 0: -x else: x -proc abs*(x: int8): int8 {.magic: "AbsI", noSideEffect.} = +func abs*(x: int8): int8 {.magic: "AbsI", inline.} = if x < 0: -x else: x -proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} = +func abs*(x: int16): int16 {.magic: "AbsI", inline.} = if x < 0: -x else: x -proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} = +func abs*(x: int32): int32 {.magic: "AbsI", inline.} = if x < 0: -x else: x -proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} = +func abs*(x: int64): int64 {.magic: "AbsI", inline.} = ## Returns the absolute value of `x`. ## ## If `x` is ``low(x)`` (that is -MININT for its type), From 6e2c2d11db1c753c7129337ac0453ee42b57ff3d Mon Sep 17 00:00:00 2001 From: shadowninja55 <49539636+shadowninja55@users.noreply.github.com> Date: Tue, 22 Dec 2020 21:23:45 -0500 Subject: [PATCH 1686/4254] add sequtils to prelude (#16431) * add sequtils to prelude i would argue that sequtils is used just as often as the other imports in prelude, and it'd be nice for it to be included. * updated doc comment to add sequtils * added sequtils import to changelog --- changelog.md | 2 ++ lib/prelude.nim | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 89d8fd423..c2a146c01 100644 --- a/changelog.md +++ b/changelog.md @@ -70,6 +70,8 @@ and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes its argument, `addMoved`, is also supplied. + +- Added `sequtils` import to `prelude`. ## Language changes diff --git a/lib/prelude.nim b/lib/prelude.nim index 47a5af89e..4d8c7d7f0 100644 --- a/lib/prelude.nim +++ b/lib/prelude.nim @@ -16,8 +16,8 @@ ## Same as: ## ## .. code-block:: nim -## import os, strutils, times, parseutils, hashes, tables, sets +## import os, strutils, times, parseutils, hashes, tables, sets, sequtils ## when not defined(js): import parseopt -import os, strutils, times, parseutils, hashes, tables, sets +import os, strutils, times, parseutils, hashes, tables, sets, sequtils when not defined(js): import parseopt From c8fadf2c749604fe7a4a4ca2e41f74bded3daa10 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 22 Dec 2020 19:12:35 -0800 Subject: [PATCH 1687/4254] disable pkg/criterion refs https://github.com/disruptek/criterion/issues/3 (#16443) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index aae560939..f57045298 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -31,7 +31,7 @@ pkg1 "cligen", "nim c --path:. -r cligen.nim" pkg1 "combparser", "nimble test --gc:orc" pkg1 "compactdict" pkg1 "comprehension", "nimble test", "https://github.com/alehander42/comprehension" -pkg1 "criterion" +# pkg1 "criterion" # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) pkg1 "dashing", "nim c tests/functional.nim" pkg1 "delaunay" pkg1 "docopt" From 8d913a5921d7245ad80e92a040b5bc8ba6f97f44 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 22 Dec 2020 22:27:34 -0600 Subject: [PATCH 1688/4254] add zippy to important packages (#16442) * add zippy to important packages * minor --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index f57045298..5a9775bad 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -136,3 +136,4 @@ pkg2 "with" pkg2 "ws" pkg2 "yaml", "nim build" pkg2 "zero_functional", "nim c -r -d:nimWorkaround14447 test.nim" +pkg2 "zippy" From 417c2509c42367edc4130a8761fae80d529d8574 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 23 Dec 2020 04:57:48 -0600 Subject: [PATCH 1689/4254] strip minor improvement (#16444) * strip minor improvement * add more tests * Update tests/stdlib/tstrutils.nim Co-authored-by: Timothee Cour --- lib/pure/strutils.nim | 2 +- tests/stdlib/tstrutils.nim | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 04ba71315..0028ac4fb 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2813,7 +2813,7 @@ func strip*(s: string, leading = true, trailing = true, if leading: while first <= last and s[first] in chars: inc(first) if trailing: - while last >= 0 and s[last] in chars: dec(last) + while last >= first and s[last] in chars: dec(last) result = substr(s, first, last) func stripLineEnd*(s: var string) = diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index b62c82ffb..8d6fe75ae 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -28,6 +28,19 @@ template main() = doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" + block: + let a = "xxxxxx" + doAssert a.strip(chars={'x'}).len == 0 + + doAssert "".strip(chars={'x'}).len == 0 + doAssert " ".strip(chars={'x'}) == " " + doAssert "xxx xxx".strip(chars={'x'}) == " " + doAssert "xxx wind".strip(chars={'x'}) == " wind" + doAssert "xxx iii".strip(chars={'i'}) == "xxx " + doAssert "x".strip(leading = false, chars={'x'}).len == 0 + doAssert "x".strip(trailing = false, chars={'x'}).len == 0 + doAssert "x".strip(leading = false, trailing = false, chars={'x'}) == "x" + block: # split var ret: seq[string] # or use `toSeq` or `collect` for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p From b1c3dab2089bb4327627c2152a1148b299f1a930 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 23 Dec 2020 05:04:38 -0600 Subject: [PATCH 1690/4254] add `euclDiv` and `euclMod` to `math` (#16414) * add `euclDiv` and `euclMod` to `math` * use abs * Update lib/pure/math.nim Co-authored-by: Clyybber --- changelog.md | 2 ++ lib/pure/math.nim | 26 ++++++++++++++++++++++++++ tests/stdlib/tmath.nim | 28 ++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/changelog.md b/changelog.md index c2a146c01..a74e06373 100644 --- a/changelog.md +++ b/changelog.md @@ -73,6 +73,8 @@ - Added `sequtils` import to `prelude`. +- Added `euclDiv` and `euclMod` to `math`. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/pure/math.nim b/lib/pure/math.nim index c05e47545..5b19a8ec0 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -882,6 +882,32 @@ func floorMod*[T: SomeNumber](x, y: T): T = result = x mod y if (result > 0 and y < 0) or (result < 0 and y > 0): result += y +func euclDiv*[T: SomeInteger](x, y: T): T {.since: (1, 5, 1).} = + ## Returns euclidean division of `x` by `y`. + runnableExamples: + assert euclDiv(13, 3) == 4 + assert euclDiv(-13, 3) == -5 + assert euclDiv(13, -3) == -4 + assert euclDiv(-13, -3) == 5 + result = x div y + if x mod y < 0: + if y > 0: + dec result + else: + inc result + +func euclMod*[T: SomeNumber](x, y: T): T {.since: (1, 5, 1).} = + ## Returns euclidean modulo of `x` by `y`. + ## `euclMod(x, y)` is non-negative. + runnableExamples: + assert euclMod(13, 3) == 1 + assert euclMod(-13, 3) == 2 + assert euclMod(13, -3) == 1 + assert euclMod(-13, -3) == 2 + result = x mod y + if result < 0: + result += abs(y) + when not defined(js): func c_frexp*(x: float32, exponent: var int32): float32 {. importc: "frexp", header: "".} diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 18e42cbdc..43d19f9e0 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -270,6 +270,34 @@ block: doAssert floorMod(8.0, -3.0) ==~ -1.0 doAssert floorMod(-8.5, 3.0) ==~ 0.5 + block: # euclDiv/euclMod + doAssert euclDiv(8, 3) == 2 + doAssert euclMod(8, 3) == 2 + + doAssert euclDiv(8, -3) == -2 + doAssert euclMod(8, -3) == 2 + + doAssert euclDiv(-8, 3) == -3 + doAssert euclMod(-8, 3) == 1 + + doAssert euclDiv(-8, -3) == 3 + doAssert euclMod(-8, -3) == 1 + + doAssert euclMod(8.0, -3.0) ==~ 2.0 + doAssert euclMod(-8.5, 3.0) ==~ 0.5 + + doAssert euclDiv(9, 3) == 3 + doAssert euclMod(9, 3) == 0 + + doAssert euclDiv(9, -3) == -3 + doAssert euclMod(9, -3) == 0 + + doAssert euclDiv(-9, 3) == -3 + doAssert euclMod(-9, 3) == 0 + + doAssert euclDiv(-9, -3) == 3 + doAssert euclMod(-9, -3) == 0 + block: # log doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0) doAssert log2(8.0'f64) == 3.0'f64 From a29bbeee41e43f00ba7a3b1951445ff5d21ccc52 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 23 Dec 2020 17:26:37 -0300 Subject: [PATCH 1691/4254] Add missing HTTP codes (#16454) --- changelog.md | 2 ++ lib/pure/httpcore.nim | 57 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index a74e06373..a6a865514 100644 --- a/changelog.md +++ b/changelog.md @@ -74,6 +74,8 @@ - Added `sequtils` import to `prelude`. - Added `euclDiv` and `euclMod` to `math`. +- Added `httpcore.is1xx` and missing HTTP codes. + ## Language changes diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 7ead64d83..9287e9864 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -11,7 +11,7 @@ ## ``asynchttpserver`` modules. ## ## Unstable API. - +import std/private/since import tables, strutils, parseutils type @@ -52,6 +52,8 @@ type const Http100* = HttpCode(100) Http101* = HttpCode(101) + Http102* = HttpCode(102) ## https://tools.ietf.org/html/rfc2518.html WebDAV + Http103* = HttpCode(103) ## https://tools.ietf.org/html/rfc8297.html Early hints Http200* = HttpCode(200) Http201* = HttpCode(201) Http202* = HttpCode(202) @@ -59,6 +61,9 @@ const Http204* = HttpCode(204) Http205* = HttpCode(205) Http206* = HttpCode(206) + Http207* = HttpCode(207) ## https://tools.ietf.org/html/rfc4918.html WebDAV + Http208* = HttpCode(208) ## https://tools.ietf.org/html/rfc5842.html WebDAV, Section 7.1 + Http226* = HttpCode(226) ## https://tools.ietf.org/html/rfc3229.html Delta encoding, Section 10.4.1 Http300* = HttpCode(300) Http301* = HttpCode(301) Http302* = HttpCode(302) @@ -69,6 +74,7 @@ const Http308* = HttpCode(308) Http400* = HttpCode(400) Http401* = HttpCode(401) + Http402* = HttpCode(402) ## https://tools.ietf.org/html/rfc7231.html Payment required, Section 6.5.2 Http403* = HttpCode(403) Http404* = HttpCode(404) Http405* = HttpCode(405) @@ -87,6 +93,9 @@ const Http418* = HttpCode(418) Http421* = HttpCode(421) Http422* = HttpCode(422) + Http423* = HttpCode(423) ## https://tools.ietf.org/html/rfc4918.html WebDAV, Section 11.3 + Http424* = HttpCode(424) ## https://tools.ietf.org/html/rfc4918.html WebDAV, Section 11.3 + Http425* = HttpCode(425) ## https://tools.ietf.org/html/rfc8470.html Early data Http426* = HttpCode(426) Http428* = HttpCode(428) Http429* = HttpCode(429) @@ -98,6 +107,12 @@ const Http503* = HttpCode(503) Http504* = HttpCode(504) Http505* = HttpCode(505) + Http506* = HttpCode(506) ## https://tools.ietf.org/html/rfc2295.html Content negotiation, Section 8.1 + Http507* = HttpCode(507) ## https://tools.ietf.org/html/rfc4918.html WebDAV, Section 11.5 + Http508* = HttpCode(508) ## https://tools.ietf.org/html/rfc5842.html WebDAV, Section 7.2 + Http510* = HttpCode(510) ## https://tools.ietf.org/html/rfc2774.html Extension framework, Section 7 + Http511* = HttpCode(511) ## https://tools.ietf.org/html/rfc6585.html Additional status code, Section 6 + const httpNewLine* = "\c\L" const headerLimit* = 10_000 @@ -267,6 +282,8 @@ func `$`*(code: HttpCode): string = case code.int of 100: "100 Continue" of 101: "101 Switching Protocols" + of 102: "102 Processing" + of 103: "103 Early Hints" of 200: "200 OK" of 201: "201 Created" of 202: "202 Accepted" @@ -274,6 +291,9 @@ func `$`*(code: HttpCode): string = of 204: "204 No Content" of 205: "205 Reset Content" of 206: "206 Partial Content" + of 207: "207 Multi-Status" + of 208: "208 Already Reported" + of 226: "226 IM Used" of 300: "300 Multiple Choices" of 301: "301 Moved Permanently" of 302: "302 Found" @@ -284,6 +304,7 @@ func `$`*(code: HttpCode): string = of 308: "308 Permanent Redirect" of 400: "400 Bad Request" of 401: "401 Unauthorized" + of 402: "402 Payment Required" of 403: "403 Forbidden" of 404: "404 Not Found" of 405: "405 Method Not Allowed" @@ -302,6 +323,9 @@ func `$`*(code: HttpCode): string = of 418: "418 I'm a teapot" of 421: "421 Misdirected Request" of 422: "422 Unprocessable Entity" + of 423: "423 Locked" + of 424: "424 Failed Dependency" + of 425: "425 Too Early" of 426: "426 Upgrade Required" of 428: "428 Precondition Required" of 429: "429 Too Many Requests" @@ -313,6 +337,11 @@ func `$`*(code: HttpCode): string = of 503: "503 Service Unavailable" of 504: "504 Gateway Timeout" of 505: "505 HTTP Version Not Supported" + of 506: "506 Variant Also Negotiates" + of 507: "507 Insufficient Storage" + of 508: "508 Loop Detected" + of 510: "510 Not Extended" + of 511: "511 Network Authentication Required" else: $(int(code)) func `==`*(a, b: HttpCode): bool {.borrow.} @@ -327,6 +356,13 @@ proc `==`*(rawCode: string, code: HttpCode): bool ## string form of itself. return cmpIgnoreCase(rawCode, $code) == 0 +func is1xx*(code: HttpCode): bool {.inline, since: (1, 5).} = + ## Determines whether ``code`` is a 1xx HTTP status code. + runnableExamples: + doAssert is1xx(HttpCode(103)) + + code.int in {100 .. 199} + func is2xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 2xx HTTP status code. code.int in {200 .. 299} @@ -343,5 +379,20 @@ func is5xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 5xx HTTP status code. code.int in {500 .. 599} -func `$`*(httpMethod: HttpMethod): string = - return (system.`$`(httpMethod))[4 .. ^1].toUpperAscii() +func `$`*(httpMethod: HttpMethod): string {.inline.} = + runnableExamples: + doAssert $HttpHead == "HEAD" + doAssert $HttpPatch == "PATCH" + doAssert $HttpGet == "GET" + doAssert $HttpPost == "POST" + + result = case httpMethod + of HttpHead: "HEAD" + of HttpGet: "GET" + of HttpPost: "POST" + of HttpPut: "PUT" + of HttpDelete: "DELETE" + of HttpTrace: "TRACE" + of HttpOptions: "OPTIONS" + of HttpConnect: "CONNECT" + of HttpPatch: "PATCH" From e84354666ac141959104f50be3fb22f1932dbaf4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 26 Dec 2020 14:28:56 -0800 Subject: [PATCH 1692/4254] fix #16346 rst2html now honors SuccessX (#16347) * fix #16346 SuccessX rst2html * cleanups * _ * _ * _ --- compiler/commands.nim | 7 +++++++ compiler/options.nim | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 11bf628b4..4b8755ab4 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -439,6 +439,13 @@ proc setCmd*(conf: ConfigRef, cmd: Command) = proc setCommandEarly*(conf: ConfigRef, command: string) = conf.command = command setCmd(conf, command.parseCommand) + # command early customizations + # must be handled here to honor subsequent `--hint:x:on|off` + case conf.cmd + of cmdRst2html, cmdRst2tex: # xxx see whether to add others: cmdGendepend, etc. + conf.foreignPackageNotes = {hintSuccessX} + else: + conf.foreignPackageNotes = foreignPackageNotesDefault proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = diff --git a/compiler/options.nim b/compiler/options.nim index 73c4c627d..a5f262f01 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -424,6 +424,8 @@ template newPackageCache*(): untyped = proc newProfileData(): ProfileData = ProfileData(data: newTable[TLineInfo, ProfileInfo]()) +const foreignPackageNotesDefault* = {hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting} + proc newConfigRef*(): ConfigRef = result = ConfigRef( selectedGC: gcRefc, @@ -435,8 +437,7 @@ proc newConfigRef*(): ConfigRef = arcToExpand: newStringTable(modeStyleInsensitive), m: initMsgConfig(), cppDefines: initHashSet[string](), - headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, - hintQuitCalled, hintExecuting}, + headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: foreignPackageNotesDefault, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], configVars: newStringTable(modeStyleInsensitive), symbols: newStringTable(modeStyleInsensitive), @@ -490,8 +491,7 @@ proc newPartialConfigRef*(): ConfigRef = verbosity: 1, options: DefaultOptions, globalOptions: DefaultGlobalOptions, - foreignPackageNotes: {hintProcessing, warnUnknownMagic, - hintQuitCalled, hintExecuting}, + foreignPackageNotes: foreignPackageNotesDefault, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) proc cppDefine*(c: ConfigRef; define: string) = From 1e859fa320e6f6a0fa3773c1ecf37707dd656b6c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 02:04:58 -0600 Subject: [PATCH 1693/4254] minor (#16478) --- compiler/llstream.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 6df927c60..bd335c23d 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -110,7 +110,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int = s.rd = 0 var line = newStringOfCap(120) var triples = 0 - while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line): + while readLineFromStdin(if s.s.len == 0: "\n>>> " else: "... ", line): s.s.add(line) s.s.add("\n") inc triples, countTriples(line) From 1d615dfda7102c5d7f190b077c0ae87abac34228 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 02:16:53 -0600 Subject: [PATCH 1694/4254] fix #16474 `unittest.check type1 is type2` gives CT error (#16476) * fix #16474 * more tests --- lib/pure/unittest.nim | 3 ++- tests/stdlib/tunittestpass.nim | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tunittestpass.nim diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index ab45f78dc..18b09e4c0 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -669,7 +669,8 @@ macro check*(conditions: untyped): untyped = let paramAst = exp[i] if exp[i].kind == nnkIdent: result.printOuts.add getAst(print(argStr, paramAst)) - if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr, nnkPar}: + if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr, nnkPar} and + (exp[i].typeKind notin {ntyTypeDesc} or $exp[0] notin ["is", "isnot"]): let callVar = newIdentNode(":c" & $counter) result.assigns.add getAst(asgn(callVar, paramAst)) result.check[i] = callVar diff --git a/tests/stdlib/tunittestpass.nim b/tests/stdlib/tunittestpass.nim new file mode 100644 index 000000000..cff37a3b7 --- /dev/null +++ b/tests/stdlib/tunittestpass.nim @@ -0,0 +1,19 @@ +discard """ + targets: "c js" +""" + + +import unittest + +block: + check (type(1.0)) is float + check type(1.0) is float + check (typeof(1)) isnot float + check typeof(1) isnot float + + check 1.0 is float + check 1 isnot float + + type T = type(0.1) + check T is float + check T isnot int From fa1a04188ffdc66f1edc909e5b465e548532617a Mon Sep 17 00:00:00 2001 From: Jonah Snider Date: Sun, 27 Dec 2020 00:33:51 -0800 Subject: [PATCH 1695/4254] Avoid creating a holey array in makeNimstrLit for JS target (#16461) * Avoid creating a holey array in makeNimstrLit * Use array index instead of push --- lib/system/jssys.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 8865558fe..e2ceedc2c 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -189,9 +189,8 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ - var ln = `c`.length; - var result = new Array(ln); - for (var i = 0; i < ln; ++i) { + var result = []; + for (var i = 0; i < `c`.length; ++i) { result[i] = `c`.charCodeAt(i); } return result; From 4cf605dcf6bdeacbb3f2ff8c7f17f5ff1afbe316 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Sun, 27 Dec 2020 01:08:28 -0800 Subject: [PATCH 1696/4254] nimsuggest: fix and re-enable old tests (#16401) A number of nimsuggest tests were disabled for various reasons, sometimes due to brittleness. These tests have been fixed where needed and most have are now enabled -- details below. The updates are meant to provide better regression coverage for future nimsuggest improvements. To avoid brittleness some tests were refactored. Impact: * test coverage has now increased * faster execution of the test suite * tests are less likely to break due to stdlib changes Re-enabled Test & Test Description: * `tchk1.nim`: check (chk) via nimsuggest works at end of file * `tdot4.nim`: prioritize already used completion * `tinclude.nim`: definition lookup (def) with includes * `tstrutils.nim` -> `tdef2.nim`: test template definition lookup (def) * `tsug_regression.nim`: regression test for [nimsuggest #52](https://github.com/nim-lang/nimsuggest/issues/52) * `ttemplate_highlight.nim`: per the file name * `twithin_macro_prefix.nim`: suggest within a macro with a prefix Tests Not Re-Enabled: * `twithin_macro.nim` still disabled as it doesn't provide a good test signal * EPC highlight tests remain disabled -- requires out of scope tester changes Additional Notes: * todos added in comments for follow-up work --- nimsuggest/tests/fixtures/mclass_macro.nim | 164 ++++++++++++++++ .../{dep_v1.nim => fixtures/mdep_v1.nim} | 0 .../{dep_v2.nim => fixtures/mdep_v2.nim} | 0 nimsuggest/tests/fixtures/mfakeassert.nim | 5 + nimsuggest/tests/fixtures/minclude_import.nim | 15 ++ .../tests/fixtures/minclude_include.nim | 4 + nimsuggest/tests/fixtures/minclude_types.nim | 6 + nimsuggest/tests/fixtures/mstrutils.nim | 19 ++ nimsuggest/tests/tchk1.nim | 9 +- nimsuggest/tests/tdef2.nim | 13 ++ nimsuggest/tests/tdot3.nim | 4 +- nimsuggest/tests/tdot4.nim | 22 ++- nimsuggest/tests/tinclude.nim | 23 ++- nimsuggest/tests/tstrutils.nim | 10 - nimsuggest/tests/tsug_regression.nim | 13 +- ..._highlight.nim => ttemplate_highlight.nim} | 0 nimsuggest/tests/ttype_decl.nim | 7 +- nimsuggest/tests/twithin_macro.nim | 177 +----------------- nimsuggest/tests/twithin_macro_prefix.nim | 177 ++---------------- 19 files changed, 292 insertions(+), 376 deletions(-) create mode 100644 nimsuggest/tests/fixtures/mclass_macro.nim rename nimsuggest/tests/{dep_v1.nim => fixtures/mdep_v1.nim} (100%) rename nimsuggest/tests/{dep_v2.nim => fixtures/mdep_v2.nim} (100%) create mode 100644 nimsuggest/tests/fixtures/mfakeassert.nim create mode 100644 nimsuggest/tests/fixtures/minclude_import.nim create mode 100644 nimsuggest/tests/fixtures/minclude_include.nim create mode 100644 nimsuggest/tests/fixtures/minclude_types.nim create mode 100644 nimsuggest/tests/fixtures/mstrutils.nim create mode 100644 nimsuggest/tests/tdef2.nim delete mode 100644 nimsuggest/tests/tstrutils.nim rename nimsuggest/tests/{disabled_ttemplate_highlight.nim => ttemplate_highlight.nim} (100%) diff --git a/nimsuggest/tests/fixtures/mclass_macro.nim b/nimsuggest/tests/fixtures/mclass_macro.nim new file mode 100644 index 000000000..cfca0bf3f --- /dev/null +++ b/nimsuggest/tests/fixtures/mclass_macro.nim @@ -0,0 +1,164 @@ + +import macros + +macro class*(head, body: untyped): untyped = + # The macro is immediate, since all its parameters are untyped. + # This means, it doesn't resolve identifiers passed to it. + + var typeName, baseName: NimNode + + # flag if object should be exported + var exported: bool + + if head.kind == nnkInfix and head[0].kind == nnkIdent and $head[0] == "of": + # `head` is expression `typeName of baseClass` + # echo head.treeRepr + # -------------------- + # Infix + # Ident !"of" + # Ident !"Animal" + # Ident !"RootObj" + typeName = head[1] + baseName = head[2] + + elif head.kind == nnkInfix and head[0].kind == nnkIdent and + $head[0] == "*" and head[2].kind == nnkPrefix and + head[2][0].kind == nnkIdent and $head[2][0] == "of": + # `head` is expression `typeName* of baseClass` + # echo head.treeRepr + # -------------------- + # Infix + # Ident !"*" + # Ident !"Animal" + # Prefix + # Ident !"of" + # Ident !"RootObj" + typeName = head[1] + baseName = head[2][1] + exported = true + + else: + quit "Invalid node: " & head.lispRepr + + # The following prints out the AST structure: + # + # import macros + # dumptree: + # type X = ref object of Y + # z: int + # -------------------- + # StmtList + # TypeSection + # TypeDef + # Ident !"X" + # Empty + # RefTy + # ObjectTy + # Empty + # OfInherit + # Ident !"Y" + # RecList + # IdentDefs + # Ident !"z" + # Ident !"int" + # Empty + + # create a type section in the result + result = newNimNode(nnkStmtList) + result.add( + if exported: + # mark `typeName` with an asterisk + quote do: + type `typeName`* = ref object of `baseName` + else: + quote do: + type `typeName` = ref object of `baseName` + ) + + # echo treeRepr(body) + # -------------------- + # StmtList + # VarSection + # IdentDefs + # Ident !"name" + # Ident !"string" + # Empty + # IdentDefs + # Ident !"age" + # Ident !"int" + # Empty + # MethodDef + # Ident !"vocalize" + # Empty + # Empty + # FormalParams + # Ident !"string" + # Empty + # Empty + # StmtList + # StrLit ... + # MethodDef + # Ident !"age_human_yrs" + # Empty + # Empty + # FormalParams + # Ident !"int" + # Empty + # Empty + # StmtList + # DotExpr + # Ident !"this" + # Ident !"age" + + # var declarations will be turned into object fields + var recList = newNimNode(nnkRecList) + + # expected name of constructor + let ctorName = newIdentNode("new" & $typeName) + + # Iterate over the statements, adding `this: T` + # to the parameters of functions, unless the + # function is a constructor + for node in body.children: + case node.kind: + + of nnkMethodDef, nnkProcDef: + # check if it is the ctor proc + if node.name.kind != nnkAccQuoted and node.name.basename == ctorName: + # specify the return type of the ctor proc + node.params[0] = typeName + else: + # inject `self: T` into the arguments + node.params.insert(1, newIdentDefs(ident("self"), typeName)) + result.add(node) + + of nnkVarSection: + # variables get turned into fields of the type. + for n in node.children: + recList.add(n) + + else: + result.add(node) + + # Inspect the tree structure: + # + # echo result.treeRepr + # -------------------- + # StmtList + # TypeSection + # TypeDef + # Ident !"Animal" + # Empty + # RefTy + # ObjectTy + # Empty + # OfInherit + # Ident !"RootObj" + # Empty <= We want to replace this + # MethodDef + # ... + + result[0][0][2][0][2] = recList + + # Lets inspect the human-readable version of the output + #echo repr(result) diff --git a/nimsuggest/tests/dep_v1.nim b/nimsuggest/tests/fixtures/mdep_v1.nim similarity index 100% rename from nimsuggest/tests/dep_v1.nim rename to nimsuggest/tests/fixtures/mdep_v1.nim diff --git a/nimsuggest/tests/dep_v2.nim b/nimsuggest/tests/fixtures/mdep_v2.nim similarity index 100% rename from nimsuggest/tests/dep_v2.nim rename to nimsuggest/tests/fixtures/mdep_v2.nim diff --git a/nimsuggest/tests/fixtures/mfakeassert.nim b/nimsuggest/tests/fixtures/mfakeassert.nim new file mode 100644 index 000000000..765831ba7 --- /dev/null +++ b/nimsuggest/tests/fixtures/mfakeassert.nim @@ -0,0 +1,5 @@ +# Template for testing defs + +template fakeAssert*(cond: untyped, msg: string = "") = + ## template to allow def lookup testing + if not cond: quit(1) diff --git a/nimsuggest/tests/fixtures/minclude_import.nim b/nimsuggest/tests/fixtures/minclude_import.nim new file mode 100644 index 000000000..5fa9e5142 --- /dev/null +++ b/nimsuggest/tests/fixtures/minclude_import.nim @@ -0,0 +1,15 @@ +# Creates an awkward set of dependencies between this, import, and include. +# This pattern appears in the compiler, compiler/(sem|ast|semexprs).nim. + +import mfakeassert +import minclude_types + +proc say*(g: Greet): string = + fakeAssert(true, "always works") + g.greeting & ", " & g.subject & "!" + +include minclude_include + +proc say*(): string = + fakeAssert(1 + 1 == 2, "math works") + say(create()) diff --git a/nimsuggest/tests/fixtures/minclude_include.nim b/nimsuggest/tests/fixtures/minclude_include.nim new file mode 100644 index 000000000..23f9892cc --- /dev/null +++ b/nimsuggest/tests/fixtures/minclude_include.nim @@ -0,0 +1,4 @@ +# this file is included and relies on imports within the include + +proc create*(greeting: string = "Hello", subject: string = "World"): Greet = + Greet(greeting: greeting, subject: subject) diff --git a/nimsuggest/tests/fixtures/minclude_types.nim b/nimsuggest/tests/fixtures/minclude_types.nim new file mode 100644 index 000000000..3e85ee540 --- /dev/null +++ b/nimsuggest/tests/fixtures/minclude_types.nim @@ -0,0 +1,6 @@ +# types used by minclude_* (import or include), to find with def in include + +type + Greet* = object + greeting*: string + subject*: string \ No newline at end of file diff --git a/nimsuggest/tests/fixtures/mstrutils.nim b/nimsuggest/tests/fixtures/mstrutils.nim new file mode 100644 index 000000000..d6f25571b --- /dev/null +++ b/nimsuggest/tests/fixtures/mstrutils.nim @@ -0,0 +1,19 @@ +import mfakeassert + +func rereplace*(s, sub: string; by: string = ""): string {.used.} = + ## competes for priority in suggestion, here first, but never used in test + + fakeAssert(true, "always works") + result = by + +func replace*(s, sub: string; by: string = ""): string = + ## this is a test version of strutils.replace, it simply returns `by` + + fakeAssert("".len == 0, "empty string is empty") + result = by + +func rerereplace*(s, sub: string; by: string = ""): string {.used.} = + ## isn't used and appears last, lowest priority + + fakeAssert(false, "never works") + result = by diff --git a/nimsuggest/tests/tchk1.nim b/nimsuggest/tests/tchk1.nim index 2b60ed094..c28b88b9b 100644 --- a/nimsuggest/tests/tchk1.nim +++ b/nimsuggest/tests/tchk1.nim @@ -15,14 +15,13 @@ proc main = #[!]# discard """ -disabled:true $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;-1;;-1;;"tchk1 [Processing]";;0 -chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but found \'keyword template\'";;0 -chk;;skUnknown;;;;Error;;$file;;14;;0;;"complex statement requires indentation";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tchk1 [Processing]";;0 +chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but got \'keyword template\'";;0 +chk;;skUnknown;;;;Error;;$file;;14;;0;;"nestable statement requires indentation";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0 chk;;skUnknown;;;;Error;;$file;;17;;0;;"invalid indentation";;0 chk;;skUnknown;;;;Hint;;$file;;12;;9;;"\'foo\' is declared but not used [XDeclaredButNotUsed]";;0 -chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'tchk1.main()[declared in tchk1.nim(14, 5)]\' is declared but not used [XDeclaredButNotUsed]";;0 +chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'main\' is declared but not used [XDeclaredButNotUsed]";;0 """ diff --git a/nimsuggest/tests/tdef2.nim b/nimsuggest/tests/tdef2.nim new file mode 100644 index 000000000..299b83a3d --- /dev/null +++ b/nimsuggest/tests/tdef2.nim @@ -0,0 +1,13 @@ +# Test def with template and boundaries for the cursor + +import fixtures/mstrutils + +discard """ +$nimsuggest --tester $file +>def $path/fixtures/mstrutils.nim:6:4 +def;;skTemplate;;mfakeassert.fakeAssert;;template (cond: untyped, msg: string);;*fixtures/mfakeassert.nim;;3;;9;;"template to allow def lookup testing";;100 +>def $path/fixtures/mstrutils.nim:12:3 +def;;skTemplate;;mfakeassert.fakeAssert;;template (cond: untyped, msg: string);;*fixtures/mfakeassert.nim;;3;;9;;"template to allow def lookup testing";;100 +>def $path/fixtures/mstrutils.nim:18:11 +def;;skTemplate;;mfakeassert.fakeAssert;;template (cond: untyped, msg: string);;*fixtures/mfakeassert.nim;;3;;9;;"template to allow def lookup testing";;100 +""" diff --git a/nimsuggest/tests/tdot3.nim b/nimsuggest/tests/tdot3.nim index 15fc1cd1c..30dd60591 100644 --- a/nimsuggest/tests/tdot3.nim +++ b/nimsuggest/tests/tdot3.nim @@ -9,14 +9,14 @@ proc main(f: Foo) = # this way, the line numbers more often stay the same discard """ -!copy dep_v1.nim dep.nim +!copy fixtures/mdep_v1.nim dep.nim $nimsuggest --tester $file >sug $1 sug;;skField;;x;;int;;*dep.nim;;8;;4;;"";;100;;None sug;;skField;;y;;int;;*dep.nim;;8;;8;;"";;100;;None sug;;skProc;;tdot3.main;;proc (f: Foo);;$file;;5;;5;;"";;100;;None -!copy dep_v2.nim dep.nim +!copy fixtures/mdep_v2.nim dep.nim >mod $path/dep.nim >sug $1 sug;;skField;;x;;int;;*dep.nim;;8;;4;;"";;100;;None diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim index 762534310..e1ff96553 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -1,17 +1,21 @@ -discard """ -disabled:true -$nimsuggest --tester --maxresults:2 $file ->sug $1 -sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;10;;5;;"";;100;;None -sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1506;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None -""" +# Test that already used suggestions are prioritized -import strutils +from system import string, echo +import fixtures/mstrutils proc main(inp: string): string = # use replace here and see if it occurs in the result, it should gain # priority: result = inp.replace(" ", "a").replace("b", "c") - echo "string literal here".#[!]# + +# priority still tested, but limit results to avoid failures from other output +discard """ +$nimsuggest --tester --maxresults:2 $file +>sug $1 +sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;6;;5;;"";;100;;None +sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None +""" + +# TODO - determine appropriate behaviour for further suggest output and test it diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 0fda43911..23aa2d727 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -1,8 +1,19 @@ +# import that has an include, def calls must work into and out of includes +import fixtures/minclude_import + +proc go() = + discard create().say() + +go() + discard """ -disabled:true -$nimsuggest --tester compiler/nim.nim ->def compiler/semexprs.nim:25:50 -def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 ->def compiler/semexprs.nim:25:50 -def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 +$nimsuggest --tester $file +>def $path/tinclude.nim:5:14 +def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, locks: 0.};;*fixtures/minclude_include.nim;;3;;5;;"";;100 +>def $path/fixtures/minclude_include.nim:3:71 +def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 +>def $path/fixtures/minclude_include.nim:3:71 +def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 """ + +# TODO test/fix if the first `def` is not first or repeated we get no results diff --git a/nimsuggest/tests/tstrutils.nim b/nimsuggest/tests/tstrutils.nim deleted file mode 100644 index 9462c3d99..000000000 --- a/nimsuggest/tests/tstrutils.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ -disabled:true -$nimsuggest --tester lib/pure/strutils.nim ->def lib/pure/strutils.nim:2529:6 -def;;skTemplate;;system.doAssert;;proc (cond: bool, msg: string): typed;;*/lib/system.nim;;*;;9;;"same as `assert` but is always turned on and not affected by the\x0A``--assertions`` command line switch.";;100 -""" - -# Line 2529 in strutils.nim is doAssert and this is unlikely to change -# soon since there are a whole lot of doAsserts there. - diff --git a/nimsuggest/tests/tsug_regression.nim b/nimsuggest/tests/tsug_regression.nim index 1607f5244..ba2034bd3 100644 --- a/nimsuggest/tests/tsug_regression.nim +++ b/nimsuggest/tests/tsug_regression.nim @@ -17,13 +17,14 @@ proc main = map0.#[!]# discard """ -disabled:true $nimsuggest --tester $file >sug $1 -sug;;skProc;;tables.getOrDefault;;proc (t: Table[getOrDefault.A, getOrDefault.B], key: A): B;;$lib/pure/collections/tables.nim;;178;;5;;"";;100;;None -sug;;skProc;;tables.hasKey;;proc (t: Table[hasKey.A, hasKey.B], key: A): bool;;$lib/pure/collections/tables.nim;;233;;5;;"returns true iff `key` is in the table `t`.";;100;;None -sug;;skProc;;tables.add;;proc (t: var Table[add.A, add.B], key: A, val: B);;$lib/pure/collections/tables.nim;;309;;5;;"puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.";;100;;None -sug;;skIterator;;tables.allValues;;iterator (t: Table[allValues.A, allValues.B], key: A): B{.inline.};;$lib/pure/collections/tables.nim;;225;;9;;"iterates over any value in the table `t` that belongs to the given `key`.";;100;;None -sug;;skProc;;tables.clear;;proc (t: var Table[clear.A, clear.B]);;$lib/pure/collections/tables.nim;;121;;5;;"Resets the table so that it is empty.";;100;;None +sug;;skProc;;tables.hasKey;;proc (t: Table[hasKey.A, hasKey.B], key: A): bool;;*/lib/pure/collections/tables.nim;;374;;5;;"Returns true if*";;100;;None +sug;;skProc;;tables.add;;proc (t: var Table[add.A, add.B], key: A, val: sink B);;*/lib/pure/collections/tables.nim;;505;;5;;"Puts a new*";;100;;None +sug;;skIterator;;tables.allValues;;iterator (t: Table[allValues.A, allValues.B], key: A): B{.inline.};;*/lib/pure/collections/tables.nim;;769;;9;;"Iterates over any*";;100;;None +sug;;skProc;;tables.clear;;proc (t: var Table[clear.A, clear.B]);;*/lib/pure/collections/tables.nim;;567;;5;;"Resets the table so that it is empty.*";;100;;None +sug;;skProc;;tables.contains;;proc (t: Table[contains.A, contains.B], key: A): bool;;*/lib/pure/collections/tables.nim;;392;;5;;"Alias of `hasKey*";;100;;None * """ + +# TODO: test/fix suggestion sorting - deprecated suggestions should rank lower diff --git a/nimsuggest/tests/disabled_ttemplate_highlight.nim b/nimsuggest/tests/ttemplate_highlight.nim similarity index 100% rename from nimsuggest/tests/disabled_ttemplate_highlight.nim rename to nimsuggest/tests/ttemplate_highlight.nim diff --git a/nimsuggest/tests/ttype_decl.nim b/nimsuggest/tests/ttype_decl.nim index 6d9817ed2..d7ed63ed0 100644 --- a/nimsuggest/tests/ttype_decl.nim +++ b/nimsuggest/tests/ttype_decl.nim @@ -1,10 +1,9 @@ discard """ -disabled:true $nimsuggest --tester --maxresults:3 $file >sug $1 -sug;;skType;;ttype_decl.Other;;Other;;$file;;11;;2;;"";;0;;None -sug;;skType;;system.int;;int;;$lib/system/basic_types.nim;;2;;2;;"";;0;;None -sug;;skType;;system.string;;string;;$lib/system.nim;;34;;2;;"";;0;;None +sug;;skType;;ttype_decl.Other;;Other;;$file;;10;;2;;"";;0;;None +sug;;skType;;system.int;;int;;*/lib/system/basic_types.nim;;2;;2;;"";;0;;None +sug;;skType;;system.string;;string;;*/lib/system.nim;;34;;2;;"";;0;;None """ import strutils type diff --git a/nimsuggest/tests/twithin_macro.nim b/nimsuggest/tests/twithin_macro.nim index 9c36ffd0f..2f5e278c4 100644 --- a/nimsuggest/tests/twithin_macro.nim +++ b/nimsuggest/tests/twithin_macro.nim @@ -1,166 +1,5 @@ - -import macros - -macro class*(head, body: untyped): untyped = - # The macro is immediate, since all its parameters are untyped. - # This means, it doesn't resolve identifiers passed to it. - - var typeName, baseName: NimNode - - # flag if object should be exported - var exported: bool - - if head.kind == nnkInfix and head[0].ident == !"of": - # `head` is expression `typeName of baseClass` - # echo head.treeRepr - # -------------------- - # Infix - # Ident !"of" - # Ident !"Animal" - # Ident !"RootObj" - typeName = head[1] - baseName = head[2] - - elif head.kind == nnkInfix and head[0].ident == !"*" and - head[2].kind == nnkPrefix and head[2][0].ident == !"of": - # `head` is expression `typeName* of baseClass` - # echo head.treeRepr - # -------------------- - # Infix - # Ident !"*" - # Ident !"Animal" - # Prefix - # Ident !"of" - # Ident !"RootObj" - typeName = head[1] - baseName = head[2][1] - exported = true - - else: - quit "Invalid node: " & head.lispRepr - - # The following prints out the AST structure: - # - # import macros - # dumptree: - # type X = ref object of Y - # z: int - # -------------------- - # StmtList - # TypeSection - # TypeDef - # Ident !"X" - # Empty - # RefTy - # ObjectTy - # Empty - # OfInherit - # Ident !"Y" - # RecList - # IdentDefs - # Ident !"z" - # Ident !"int" - # Empty - - # create a type section in the result - result = - if exported: - # mark `typeName` with an asterisk - quote do: - type `typeName`* = ref object of `baseName` - else: - quote do: - type `typeName` = ref object of `baseName` - - # echo treeRepr(body) - # -------------------- - # StmtList - # VarSection - # IdentDefs - # Ident !"name" - # Ident !"string" - # Empty - # IdentDefs - # Ident !"age" - # Ident !"int" - # Empty - # MethodDef - # Ident !"vocalize" - # Empty - # Empty - # FormalParams - # Ident !"string" - # Empty - # Empty - # StmtList - # StrLit ... - # MethodDef - # Ident !"age_human_yrs" - # Empty - # Empty - # FormalParams - # Ident !"int" - # Empty - # Empty - # StmtList - # DotExpr - # Ident !"this" - # Ident !"age" - - # var declarations will be turned into object fields - var recList = newNimNode(nnkRecList) - - # expected name of constructor - let ctorName = newIdentNode("new" & $typeName) - - # Iterate over the statements, adding `this: T` - # to the parameters of functions, unless the - # function is a constructor - for node in body.children: - case node.kind: - - of nnkMethodDef, nnkProcDef: - # check if it is the ctor proc - if node.name.kind != nnkAccQuoted and node.name.basename == ctorName: - # specify the return type of the ctor proc - node.params[0] = typeName - else: - # inject `self: T` into the arguments - node.params.insert(1, newIdentDefs(ident("self"), typeName)) - result.add(node) - - of nnkVarSection: - # variables get turned into fields of the type. - for n in node.children: - recList.add(n) - - else: - result.add(node) - - # Inspect the tree structure: - # - # echo result.treeRepr - # -------------------- - # StmtList - # TypeSection - # TypeDef - # Ident !"Animal" - # Empty - # RefTy - # ObjectTy - # Empty - # OfInherit - # Ident !"RootObj" - # Empty <= We want to replace this - # MethodDef - # ... - - result[0][0][2][0][2] = recList - - # Lets inspect the human-readable version of the output - #echo repr(result) - -# --- +from system import string, int, seq, `&`, `$`, `*`, `@`, echo, add, items, RootObj +import fixtures/mclass_macro class Animal of RootObj: var name: string @@ -205,10 +44,12 @@ discard """ disabled:true $nimsuggest --tester $file >sug $1 -sug;;skField;;age;;int;;$file;;167;;6;;"";;100;;None -sug;;skField;;name;;string;;$file;;166;;6;;"";;100;;None -sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100;;None -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;168;;9;;"";;100;;None -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;184;;9;;"";;100;;None +sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;None +sug;;skField;;name;;string;;$file;;5;;6;;"";;100;;None +sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;None +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;7;;9;;"";;100;;None +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;23;;9;;"";;100;;None sug;;skMacro;;twithin_macro.class;;proc (head: untyped, body: untyped): untyped{.gcsafe, locks: .};;$file;;4;;6;;"";;50;;None* """ + +# TODO: disabled due to semantic error reporting in nimsuggest results diff --git a/nimsuggest/tests/twithin_macro_prefix.nim b/nimsuggest/tests/twithin_macro_prefix.nim index 1402b762a..1c06397c5 100644 --- a/nimsuggest/tests/twithin_macro_prefix.nim +++ b/nimsuggest/tests/twithin_macro_prefix.nim @@ -1,166 +1,5 @@ - -import macros - -macro class*(head, body: untyped): untyped = - # The macro is immediate, since all its parameters are untyped. - # This means, it doesn't resolve identifiers passed to it. - - var typeName, baseName: NimNode - - # flag if object should be exported - var exported: bool - - if head.kind == nnkInfix and head[0].ident == !"of": - # `head` is expression `typeName of baseClass` - # echo head.treeRepr - # -------------------- - # Infix - # Ident !"of" - # Ident !"Animal" - # Ident !"RootObj" - typeName = head[1] - baseName = head[2] - - elif head.kind == nnkInfix and head[0].ident == !"*" and - head[2].kind == nnkPrefix and head[2][0].ident == !"of": - # `head` is expression `typeName* of baseClass` - # echo head.treeRepr - # -------------------- - # Infix - # Ident !"*" - # Ident !"Animal" - # Prefix - # Ident !"of" - # Ident !"RootObj" - typeName = head[1] - baseName = head[2][1] - exported = true - - else: - quit "Invalid node: " & head.lispRepr - - # The following prints out the AST structure: - # - # import macros - # dumptree: - # type X = ref object of Y - # z: int - # -------------------- - # StmtList - # TypeSection - # TypeDef - # Ident !"X" - # Empty - # RefTy - # ObjectTy - # Empty - # OfInherit - # Ident !"Y" - # RecList - # IdentDefs - # Ident !"z" - # Ident !"int" - # Empty - - # create a type section in the result - result = - if exported: - # mark `typeName` with an asterisk - quote do: - type `typeName`* = ref object of `baseName` - else: - quote do: - type `typeName` = ref object of `baseName` - - # echo treeRepr(body) - # -------------------- - # StmtList - # VarSection - # IdentDefs - # Ident !"name" - # Ident !"string" - # Empty - # IdentDefs - # Ident !"age" - # Ident !"int" - # Empty - # MethodDef - # Ident !"vocalize" - # Empty - # Empty - # FormalParams - # Ident !"string" - # Empty - # Empty - # StmtList - # StrLit ... - # MethodDef - # Ident !"age_human_yrs" - # Empty - # Empty - # FormalParams - # Ident !"int" - # Empty - # Empty - # StmtList - # DotExpr - # Ident !"this" - # Ident !"age" - - # var declarations will be turned into object fields - var recList = newNimNode(nnkRecList) - - # expected name of constructor - let ctorName = newIdentNode("new" & $typeName) - - # Iterate over the statements, adding `this: T` - # to the parameters of functions, unless the - # function is a constructor - for node in body.children: - case node.kind: - - of nnkMethodDef, nnkProcDef: - # check if it is the ctor proc - if node.name.kind != nnkAccQuoted and node.name.basename == ctorName: - # specify the return type of the ctor proc - node.params[0] = typeName - else: - # inject `self: T` into the arguments - node.params.insert(1, newIdentDefs(ident("self"), typeName)) - result.add(node) - - of nnkVarSection: - # variables get turned into fields of the type. - for n in node.children: - recList.add(n) - - else: - result.add(node) - - # Inspect the tree structure: - # - # echo result.treeRepr - # -------------------- - # StmtList - # TypeSection - # TypeDef - # Ident !"Animal" - # Empty - # RefTy - # ObjectTy - # Empty - # OfInherit - # Ident !"RootObj" - # Empty <= We want to replace this - # MethodDef - # ... - - result[0][0][2][0][2] = recList - - # Lets inspect the human-readable version of the output - #echo repr(result) - -# --- +from system import string, int, seq, `&`, `$`, `*`, `@`, echo, add, RootObj +import fixtures/mclass_macro class Animal of RootObj: var name: string @@ -202,9 +41,15 @@ echo r.age_human_yrs() echo r discard """ -disabled:true $nimsuggest --tester $file >sug $1 -sug;;skField;;age;;int;;$file;;167;;6;;"";;100;;Prefix -sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100;;Prefix +sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;Prefix +sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;Prefix """ + +#[ +TODO: additional calls to `>sug $1` produces different output with errors, + possibly related to cached results from the first analysis, which refers + to expanded macros/templates which rely on imported symbols from `system` + module that are not present in this module. +]# From 3f9a2ebea5c0b02bcfcfe77ada36c33187bbf8bb Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 03:13:57 -0600 Subject: [PATCH 1697/4254] fix nim js cmp fails at CT (#16473) --- lib/system.nim | 10 ++-------- lib/system/jssys.nim | 7 ++++++- tests/misc/tstrtabs.nim | 20 ++++++++++++++++++++ tests/stdlib/tstring.nim | 36 +++++++++++++++++++++--------------- 4 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 tests/misc/tstrtabs.nim diff --git a/lib/system.nim b/lib/system.nim index 85ef15e08..fb008dc45 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2394,14 +2394,8 @@ when notJSnotNims: """.} when defined(js): - when not defined(nimscript): - include "system/jssys" - include "system/reprjs" - else: - proc cmp(x, y: string): int = - if x == y: return 0 - if x < y: return -1 - return 1 + include "system/jssys" + include "system/reprjs" when defined(js) or defined(nimscript): proc addInt*(result: var string; x: int64) = diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index e2ceedc2c..5f18f01cb 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -340,7 +340,12 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} = """ proc cmp(x, y: string): int = - return cmpStrings(x, y) + when nimvm: + if x == y: result = 0 + elif x < y: result = -1 + else: result = 1 + else: + result = cmpStrings(x, y) proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} = asm """ diff --git a/tests/misc/tstrtabs.nim b/tests/misc/tstrtabs.nim new file mode 100644 index 000000000..2f7eda9f7 --- /dev/null +++ b/tests/misc/tstrtabs.nim @@ -0,0 +1,20 @@ +discard """ + targets: "c cpp js" +""" + +import std/strtabs + +proc fun()= + let ret = newStringTable(modeCaseSensitive) + ret["foo"] = "bar" + + doAssert $ret == "{foo: bar}" + + let b = ret["foo"] + doAssert b == "bar" + +proc main()= + static: fun() + fun() + +main() diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index ff3d41b49..4d5a15940 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -1,16 +1,14 @@ discard """ - output: '''OK -@[@[], @[], @[], @[], @[]] -''' + targets: "c cpp js" """ + const characters = "abcdefghijklmnopqrstuvwxyz" const numbers = "1234567890" -var s: string - proc test_string_slice() = # test "slice of length == len(characters)": # replace characters completely by numbers + var s: string s = characters s[0..^1] = numbers doAssert s == numbers @@ -51,11 +49,13 @@ proc test_string_slice() = s[2..0] = numbers doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz" - # bug #6223 - doAssertRaises(IndexDefect): - discard s[0..999] + when nimvm: + discard + else: + # bug #6223 + doAssertRaises(IndexDefect): + discard s[0..999] - echo("OK") proc test_string_cmp() = let world = "hello\0world" @@ -76,9 +76,6 @@ proc test_string_cmp() = doAssert cmp(world, hello) > 0 doAssert cmp(world, goodbye) > 0 -test_string_slice() -test_string_cmp() - #-------------------------- # bug #7816 @@ -87,9 +84,9 @@ import sequtils proc tester[T](x: T) = let test = toSeq(0..4).map(i => newSeq[int]()) - echo test + doAssert $test == "@[@[], @[], @[], @[], @[]]" + -tester(1) # #14497 func reverse*(a: string): string = @@ -97,4 +94,13 @@ func reverse*(a: string): string = for i in 0 ..< a.len div 2: swap(result[i], result[^(i + 1)]) -doAssert reverse("hello") == "olleh" + +proc main() = + test_string_slice() + test_string_cmp() + + tester(1) + doAssert reverse("hello") == "olleh" + +static: main() +main() From b57df6d0b335595d3197eb6907fb8d1a8237fc7e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 03:15:57 -0600 Subject: [PATCH 1698/4254] Don't use `unittest.suite` and `unittest.test` (#16464) --- doc/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 90330e4f4..34c963410 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -47,7 +47,7 @@ which only gets executed when the tester is building the file. Each test should be in a separate ``block:`` statement, such that each has its own scope. Use boolean conditions and ``doAssert`` for the testing by itself, don't rely on echo statements or similar; in particular, avoid -things like `echo "done"`. +things like `echo "done"`. Don't use `unittest.suite` and `unittest.test`. Sample test: From 626c2bc6589101bd1b0231a2608e32b51f73abba Mon Sep 17 00:00:00 2001 From: treeform Date: Sun, 27 Dec 2020 01:45:30 -0800 Subject: [PATCH 1699/4254] Add docs for nnkHiddenStdConv (#16408) Add it to devel branch this time. I hope this works. --- doc/astspec.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/astspec.txt b/doc/astspec.txt index c41aee96f..019b735f5 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1392,6 +1392,17 @@ Macro declaration Macros behave like templates, but ``nnkTemplateDef`` is replaced with ``nnkMacroDef``. +Hidden Standard Conversion +-------------------------- + +.. code-block:: nim + var f: float = 1 + +The type of "f" is ``float`` but the type of "1" is actually ``int``. Inserting +``int`` into a ``float`` is a type error. Nim inserts the ``nnkHiddenStdConv`` +node around the ``nnkIntLit`` node so that the new node has the correct type of +``float``. This works for any auto converted nodes and makes the conversion +explicit. Special node kinds ================== From 2bdc479622c465e570fdb87df112dd56ddc9030f Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 27 Dec 2020 13:16:12 +0300 Subject: [PATCH 1700/4254] RST: implement admonitions (#16438) --- config/nimdoc.tex.cfg | 9 ++ doc/nimdoc.css | 34 +++++++ lib/packages/docutils/rst.nim | 155 ++++++++++++++++++++----------- lib/packages/docutils/rstast.nim | 22 ++++- lib/packages/docutils/rstgen.nim | 24 +++++ tests/stdlib/trstgen.nim | 49 ++++++++++ 6 files changed, 239 insertions(+), 54 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 3e5e5d38b..6d7ae413d 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -52,6 +52,15 @@ doc.file = """ \usepackage{hyperref} \usepackage{enumitem} +\usepackage{xcolor} +\usepackage[tikz]{mdframed} +\usetikzlibrary{shadows} +\mdfsetup{% +linewidth=3, +topline=false, +rightline=false, +bottomline=false} + \begin{document} \title{$title $version} \author{$author} diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 2d9533ceb..7d4a399e1 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -14,6 +14,9 @@ Modified by Boyd Greenfield and narimiran --primary-background: #fff; --secondary-background: ghostwhite; --third-background: #e8e8e8; + --info-background: #50c050; + --warning-background: #c0a000; + --error-background: #e04040; --border: #dde; --text: #222; --anchor: #07b; @@ -39,6 +42,9 @@ Modified by Boyd Greenfield and narimiran --primary-background: #171921; --secondary-background: #1e202a; --third-background: #2b2e3b; + --info-background: #008000; + --warning-background: #807000; + --error-background: #c03000; --border: #0e1014; --text: #fff; --anchor: #8be9fd; @@ -609,6 +615,34 @@ table.borderless td, table.borderless th { The right padding separates the table cells. */ padding: 0 0.5em 0 0 !important; } +.admonition { + padding: 0.3em; + background-color: var(--secondary-background); + border-left: 0.4em solid #7f7f84; + margin-bottom: 0.5em; + -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); +} +.admonition-info { + border-color: var(--info-background); +} +.admonition-info-text { + color: var(--info-background); +} +.admonition-warning { + border-color: var(--warning-background); +} +.admonition-warning-text { + color: var(--warning-background); +} +.admonition-error { + border-color: var(--error-background); +} +.admonition-error-text { + color: var(--error-background); +} + .first { /* Override more specific margin styles with "! important". */ margin-top: 0 !important; } diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 0d86edcdb..7dbcaf482 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -7,11 +7,18 @@ # distribution, for details about the copyright. # -## This module implements a `reStructuredText`:idx: parser. A large -## subset is implemented. Some features of the `markdown`:idx: wiki syntax are -## also supported. +## This module implements a `reStructuredText`:idx: (RST) parser. A large +## subset is implemented. Some features of the `markdown`:idx: syntax are +## also supported. Nim can output the result to HTML (command ``rst2html``) +## or Latex (command ``rst2tex``). ## -## Supported RST features: +## If you are new to RST please consider reading the following: +## +## 1) a short `quick introduction`_ +## 2) an `RST reference`_: a comprehensive cheatsheet for RST +## 3) a more formal 50-page `RST specification`_. +## +## Supported standard RST features: ## ## * body elements ## + sections @@ -25,20 +32,29 @@ ## + option lists ## + indented literal blocks ## + simple tables -## + directives -## - image, figure -## - code-block -## - substitution definitions: replace and image -## - ... a few more +## + directives (see official documentation in `RST directives list`_): +## - ``image``, ``figure`` for including images and videos +## - ``code`` +## - ``contents`` (table of contents), ``container``, ``raw`` +## - ``include`` +## - admonitions: "attention", "caution", "danger", "error", "hint", +## "important", "note", "tip", "warning", "admonition" +## - substitution definitions: `replace` and `image` ## + comments ## * inline markup -## + *emphasis*, **strong emphasis**, `interpreted text`, +## + *emphasis*, **strong emphasis**, ## ``inline literals``, hyperlink references, substitution references, ## standalone hyperlinks +## + \`interpreted text\` with roles ``:literal:``, ``:strong:``, +## ``emphasis``, ``:sub:``/``:subscript:``, ``:sup:``/``:supscript:`` +## (see `RST roles list`_ for description). ## ## Additional features: ## +## * directives: ``code-block``, ``title``, ``index`` ## * ***triple emphasis*** (bold and italic) using \*\*\* +## * ``:idx:`` role for \`interpreted text\` to include the link to this +## text into an index (example: `Nim index`_). ## ## Optional additional features, turned on by ``options: RstParseOption`` in ## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_: @@ -51,7 +67,11 @@ ## * using ``1`` as auto-enumerator in enumerated lists like RST ``#`` ## (auto-enumerator ``1`` can not be used with ``#`` in the same list) ## -## **Note:** By default nim has ``roSupportMarkdown`` turned **on**. +## .. Note:: By default Nim has ``roSupportMarkdown`` and +## ``roSupportRawDirective`` turned **on**. +## +## .. warning:: Using Nim-specific features can cause other RST implementations +## to fail on your document. ## ## Limitations: ## @@ -61,14 +81,32 @@ ## - no quoted literal blocks ## - no doctest blocks ## - no grid tables -## - directives: no support for admonitions (notes, caution) +## - some directives are missing (check official `RST directives list`_): +## ``parsed-literal``, ``sidebar``, ``topic``, ``math``, ``rubric``, +## ``epigraph``, ``highlights``, ``pull-quote``, ``compound``, +## ``table``, ``csv-table``, ``list-table``, ``section-numbering``, +## ``header``, ``footer``, ``meta``, ``class`` +## - no ``role`` directives and no custom interpreted text roles +## - some standard roles are not supported (check `RST roles list`_) ## - no footnotes & citations support ## - no inline internal targets ## * inline markup ## - no simple-inline-markup ## - no embedded URI and aliases ## -## **Note:** Import ``packages/docutils/rst`` to use this module +## .. _quick introduction: https://docutils.sourceforge.io/docs/user/rst/quickstart.html +## .. _RST reference: https://docutils.sourceforge.io/docs/user/rst/quickref.html +## .. _RST specification: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html +## .. _RST directives list: https://docutils.sourceforge.io/docs/ref/rst/directives.html +## .. _RST roles list: https://docutils.sourceforge.io/docs/ref/rst/roles.html +## .. _Nim index: https://nim-lang.org/docs/theindex.html +## +## See `Nim DocGen Tools Guide `_ for the details about +## ``nim doc``, ``nim rst2html`` and ``nim rst2tex`` commands. +## +## .. note:: Import ``packages/docutils/rst`` to use this module. +## +## See also `packages/docutils/rstgen module `_. import os, strutils, rstast @@ -947,6 +985,7 @@ proc getDirective(p: var RstParser): string = result = "" # error else: result = "" + result = result.toLowerAscii() proc parseComment(p: var RstParser): PRstNode = case currentTok(p).kind @@ -968,21 +1007,6 @@ proc parseComment(p: var RstParser): PRstNode = while currentTok(p).kind notin {tkIndent, tkEof}: inc p.idx result = nil -type - DirKind = enum # must be ordered alphabetically! - dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents, - dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle - -const - DirIds: array[0..12, string] = ["", "author", "authors", "code", - "code-block", "container", "contents", "figure", "image", "include", - "index", "raw", "title"] - -proc getDirKind(s: string): DirKind = - let i = find(DirIds, s) - if i >= 0: result = DirKind(i) - else: result = dkNone - proc parseLine(p: var RstParser, father: PRstNode) = while true: case currentTok(p).kind @@ -1191,7 +1215,8 @@ proc whichSection(p: RstParser): RstNodeKind = result = rnMarkdownTable elif currentTok(p).symbol == "|" and isLineBlock(p): result = rnLineBlock - elif match(p, tokenAfterNewline(p), "ai"): + elif match(p, tokenAfterNewline(p), "ai") and + isAdornmentHeadline(p, tokenAfterNewline(p)): result = rnHeadline elif predNL(p) and currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: @@ -1664,8 +1689,8 @@ proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode = ## Parses arguments and options for a directive block. ## ## A directive block will always have three sons: the arguments for the - ## directive (rnDirArg), the options (rnFieldList) and the block - ## (rnLineBlock). This proc parses the two first nodes, the block is left to + ## directive (rnDirArg), the options (rnFieldList) and the directive + ## content block. This proc parses the two first nodes, the 3rd is left to ## the outer `parseDirective` call. ## ## Both rnDirArg and rnFieldList children nodes might be nil, so you need to @@ -1703,12 +1728,20 @@ proc indFollows(p: RstParser): bool = proc parseDirective(p: var RstParser, flags: DirFlags, contentParser: SectionParser): PRstNode = - ## Returns a generic rnDirective tree. + ## A helper proc that does main work for specific directive procs. + ## Always returns a generic rnDirective tree with these 3 children: ## - ## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil. + ## 1) rnDirArg + ## 2) rnFieldList + ## 3) a node returned by `contentParser`. + ## + ## .. warning:: Any of the 3 children may be nil. result = parseDirective(p, flags) - if not isNil(contentParser) and indFollows(p): - pushInd(p, currentTok(p).ival) + if not isNil(contentParser): + var nextIndent = p.tok[tokenAfterNewline(p)-1].ival + if nextIndent <= currInd(p): # parse only this line + nextIndent = currentTok(p).col + pushInd(p, nextIndent) var content = contentParser(p) popInd(p) result.add(content) @@ -1814,7 +1847,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = n.add(newRstNode(rnLeaf, readFile(path))) result.sons[2] = n - # Extend the field block if we are using our custom extension. + # Extend the field block if we are using our custom Nim extension. if nimExtension: # Create a field block if the input block didn't have any. if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList) @@ -1856,6 +1889,11 @@ proc dirIndex(p: var RstParser): PRstNode = result = parseDirective(p, {}, parseSectionWrapper) result.kind = rnIndex +proc dirAdmonition(p: var RstParser, d: string): PRstNode = + result = parseDirective(p, {}, parseSectionWrapper) + result.kind = rnAdmonition + result.text = d + proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind, contentParser: SectionParser) = var filename = getFieldValue(result, "file") @@ -1891,29 +1929,42 @@ proc dirRaw(p: var RstParser): PRstNode = else: dirRawAux(p, result, rnRaw, parseSectionWrapper) +proc selectDir(p: var RstParser, d: string): PRstNode = + result = nil + case d + of "admonition", "attention", "caution": result = dirAdmonition(p, d) + of "code": result = dirCodeBlock(p) + of "code-block": result = dirCodeBlock(p, nimExtension = true) + of "container": result = dirContainer(p) + of "contents": result = dirContents(p) + of "danger", "error": result = dirAdmonition(p, d) + of "figure": result = dirFigure(p) + of "hint": result = dirAdmonition(p, d) + of "image": result = dirImage(p) + of "important": result = dirAdmonition(p, d) + of "include": result = dirInclude(p) + of "index": result = dirIndex(p) + of "note": result = dirAdmonition(p, d) + of "raw": + if roSupportRawDirective in p.s.options: + result = dirRaw(p) + else: + rstMessage(p, meInvalidDirective, d) + of "tip": result = dirAdmonition(p, d) + of "title": result = dirTitle(p) + of "warning": result = dirAdmonition(p, d) + else: + rstMessage(p, meInvalidDirective, d) + proc parseDotDot(p: var RstParser): PRstNode = + # parse "explicit markup blocks" result = nil var col = currentTok(p).col inc p.idx var d = getDirective(p) if d != "": pushInd(p, col) - case getDirKind(d) - of dkInclude: result = dirInclude(p) - of dkImage: result = dirImage(p) - of dkFigure: result = dirFigure(p) - of dkTitle: result = dirTitle(p) - of dkContainer: result = dirContainer(p) - of dkContents: result = dirContents(p) - of dkRaw: - if roSupportRawDirective in p.s.options: - result = dirRaw(p) - else: - rstMessage(p, meInvalidDirective, d) - of dkCode: result = dirCodeBlock(p) - of dkCodeBlock: result = dirCodeBlock(p, nimExtension = true) - of dkIndex: result = dirIndex(p) - else: rstMessage(p, meInvalidDirective, d) + result = selectDir(p, d) popInd(p) elif match(p, p.idx, " _"): # hyperlink target: diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 5e2d21c04..f01bcada1 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -41,8 +41,11 @@ type rnLabel, # used for footnotes and other things rnFootnote, # a footnote rnCitation, # similar to footnote - rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive - rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock, + rnStandaloneHyperlink, rnHyperlink, rnRef, + rnDirective, # a general directive + rnDirArg, # a directive argument (for some directives). + # here are directives that are not rnDirective: + rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock, rnAdmonition, rnRawHtml, rnRawLatex, rnContainer, # ``container`` directive rnIndex, # index directve: @@ -70,6 +73,7 @@ type kind*: RstNodeKind ## the node's kind text*: string ## valid for leafs in the AST; and the title of ## the document or the section; and rnEnumList + ## and rnAdmonition level*: int ## valid for some node kinds sons*: RstNodeSeq ## the node's sons @@ -316,3 +320,17 @@ proc renderRstToJson*(node: PRstNode): string = ## "sons":optional node array ## } renderRstToJsonNode(node).pretty + +proc renderRstToStr*(node: PRstNode, indent=0): string = + ## Writes the parsed RST `node` into a compact string + ## representation in the format (one line per every sub-node): + ## ``indent - kind - text - level (if non-zero)`` + ## (suitable for debugging of RST parsing). + if node == nil: + result.add " ".repeat(indent) & "[nil]\n" + return + result.add " ".repeat(indent) & $node.kind & "\t" & + (if node.text == "": "" else: "'" & node.text & "'") & + (if node.level == 0: "" else: "\tlevel=" & $node.level) & "\n" + for son in node.sons: + result.add renderRstToStr(son, indent=indent+2) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 4d056a83e..5aa2b03d4 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1079,6 +1079,29 @@ proc renderEnumList(d: PDoc, n: PRstNode, result: var string) = "\\begin{enumerate}" & specifier & "$1\\end{enumerate}\n", result) +proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) = + var + htmlCls = "admonition_warning" + texSz = "\\large" + texColor = "orange" + case n.text + of "hint", "note", "tip": + htmlCls = "admonition-info"; texSz = "\\normalsize"; texColor = "green" + of "attention", "admonition", "important", "warning": + htmlCls = "admonition-warning"; texSz = "\\large"; texColor = "orange" + of "danger", "error": + htmlCls = "admonition-error"; texSz = "\\Large"; texColor = "red" + else: discard + let txt = n.text.capitalizeAscii() + let htmlHead = "
                        " + renderAux(d, n, + htmlHead & "" & txt & + ":\n" & "$1
                        \n", + "\n\n\\begin{mdframed}[linecolor=" & texColor & "]\n" & + "{" & texSz & "\\color{" & texColor & "}{\\textbf{" & txt & ":}}} " & + "$1\n\\end{mdframed}\n", + result) + proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = if n == nil: return case n.kind @@ -1143,6 +1166,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnBlockQuote: renderAux(d, n, "

                        $1

                        \n", "\\begin{quote}$1\\end{quote}\n", result) + of rnAdmonition: renderAdmonition(d, n, result) of rnTable, rnGridTable, rnMarkdownTable: renderAux(d, n, "$1
                        ", diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 85a96056a..3283af8c6 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -535,6 +535,55 @@ Test1 assert count(output1, "
                          ") == 1 + test "RST admonitions": + # check that all admonitions are implemented + let input0 = dedent """ + .. admonition:: endOf admonition + .. attention:: endOf attention + .. caution:: endOf caution + .. danger:: endOf danger + .. error:: endOf error + .. hint:: endOf hint + .. important:: endOf important + .. note:: endOf note + .. tip:: endOf tip + .. warning:: endOf warning + """ + let output0 = rstToHtml(input0, {roSupportMarkdown}, defaultConfig()) + for a in ["admonition", "attention", "caution", "danger", "error", "hint", + "important", "note", "tip", "warning" ]: + assert "endOf " & a & "
    " in output0 + + # Test that admonition does not swallow up the next paragraph. + let input1 = dedent """ + .. error:: endOfError + + Test paragraph. + """ + let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + assert "endOfError" in output1 + assert "

    Test paragraph.

    " in output1 + assert "class=\"admonition admonition-error\"" in output1 + + # Test that second line is parsed as continuation of the first line. + let input2 = dedent """ + .. error:: endOfError + Test2p. + + Test paragraph. + """ + let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + assert "endOfError Test2p." in output2 + assert "

    Test paragraph.

    " in output2 + assert "class=\"admonition admonition-error\"" in output2 + + let input3 = dedent """ + .. note:: endOfNote + """ + let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) + assert "endOfNote" in output3 + assert "class=\"admonition admonition-info\"" in output3 + suite "RST/Code highlight": test "Basic Python code highlight": let pythonCode = """ From 689504081f476ec23ebfd7123ad2f8b27c387a97 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 04:59:32 -0600 Subject: [PATCH 1701/4254] follow #15357 and move decodeQuery (#15860) * follow #15357 and move decodeQuery * solve problem one * minor * deprecate decodeData * add changelog and since * add testcase for decodeQuery --- changelog.md | 1 + lib/pure/cgi.nim | 50 +++++++++++------------------------ lib/pure/uri.nim | 43 ++++++++++++++++++++++++++++++ tests/stdlib/tdecodequery.nim | 7 +++++ 4 files changed, 67 insertions(+), 34 deletions(-) create mode 100644 tests/stdlib/tdecodequery.nim diff --git a/changelog.md b/changelog.md index a6a865514..6b12891c5 100644 --- a/changelog.md +++ b/changelog.md @@ -55,6 +55,7 @@ - `writeStackTrace` is available in JS backend now. +- Added `decodeQuery` to `std/uri`. - `strscans.scanf` now supports parsing single characters. - `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index cb64a3b1b..d3a762911 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -32,8 +32,10 @@ import strutils, os, strtabs, cookies, uri export uri.encodeUrl, uri.decodeUrl + import std/private/decode_helpers + proc addXmlChar(dest: var string, c: char) {.inline.} = case c of '&': add(dest, "&") @@ -53,18 +55,15 @@ proc xmlEncode*(s: string): string = for i in 0..len(s)-1: addXmlChar(result, s[i]) type - CgiError* = object of IOError ## exception that is raised if a CGI error occurs + CgiError* = object of IOError ## Exception that is raised if a CGI error occurs RequestMethod* = enum ## the used request method methodNone, ## no REQUEST_METHOD environment variable methodPost, ## query uses the POST method methodGet ## query uses the GET method proc cgiError*(msg: string) {.noreturn.} = - ## raises an ECgi exception with message `msg`. - var e: ref CgiError - new(e) - e.msg = msg - raise e + ## Raises a ``CgiError`` exception with message `msg`. + raise newException(CgiError, msg) proc getEncodedData(allowedMethods: set[RequestMethod]): string = case getEnv("REQUEST_METHOD").string @@ -88,40 +87,23 @@ proc getEncodedData(allowedMethods: set[RequestMethod]): string = iterator decodeData*(data: string): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. - proc parseData(data: string, i: int, field: var string): int = - result = i - while result < data.len: - case data[result] - of '%': add(field, decodePercent(data, result)) - of '+': add(field, ' ') - of '=', '&': break - else: add(field, data[result]) - inc(result) - - var i = 0 - var name = "" - var value = "" - # decode everything in one pass: - while i < data.len: - setLen(name, 0) # reuse memory - i = parseData(data, i, name) - setLen(value, 0) # reuse memory - if i < data.len and data[i] == '=': - inc(i) # skip '=' - i = parseData(data, i, value) - yield (name.TaintedString, value.TaintedString) - if i < data.len: - if data[i] == '&': inc(i) - else: cgiError("'&' expected") + try: + for (key, value) in uri.decodeQuery(data): + yield (key, value) + except UriParseError as e: + cgiError(e.msg) iterator decodeData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. If the client does not use a method listed in the - ## `allowedMethods` set, an `ECgi` exception is raised. + ## `allowedMethods` set, a ``CgiError`` exception is raised. let data = getEncodedData(allowedMethods) - for key, value in decodeData(data): - yield (key, value) + try: + for (key, value) in uri.decodeQuery(data): + yield (key, value) + except UriParseError as e: + cgiError(e.msg) proc readData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): StringTableRef = diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index e993c240d..7f553be1a 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -59,6 +59,13 @@ type opaque*: bool isIpv6: bool # not expose it for compatibility. + UriParseError* = object of ValueError + + +proc uriParseError*(msg: string) {.noreturn.} = + ## Raises a ``UriParseError`` exception with message `msg`. + raise newException(UriParseError, msg) + func encodeUrl*(s: string, usePlus = true): string = ## Encodes a URL according to RFC3986. ## @@ -153,6 +160,42 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add('=') result.add(encodeUrl(val, usePlus)) +iterator decodeQuery*(data: string): tuple[key, value: TaintedString] = + ## Reads and decodes query string ``data`` and yields the (key, value) pairs the + ## data consists of. + runnableExamples: + import std/sugar + let s = collect(newSeq): + for k, v in decodeQuery("foo=1&bar=2"): (k, v) + doAssert s == @[("foo", "1"), ("bar", "2")] + + proc parseData(data: string, i: int, field: var string): int = + result = i + while result < data.len: + case data[result] + of '%': add(field, decodePercent(data, result)) + of '+': add(field, ' ') + of '=', '&': break + else: add(field, data[result]) + inc(result) + + var i = 0 + var name = "" + var value = "" + # decode everything in one pass: + while i < data.len: + setLen(name, 0) # reuse memory + i = parseData(data, i, name) + setLen(value, 0) # reuse memory + if i < data.len and data[i] == '=': + inc(i) # skip '=' + i = parseData(data, i, value) + yield (name.TaintedString, value.TaintedString) + if i < data.len: + if data[i] == '&': inc(i) + else: + uriParseError("'&' expected at index '$#' for '$#'" % [$i, data]) + func parseAuthority(authority: string, result: var Uri) = var i = 0 var inPort = false diff --git a/tests/stdlib/tdecodequery.nim b/tests/stdlib/tdecodequery.nim new file mode 100644 index 000000000..ae180742f --- /dev/null +++ b/tests/stdlib/tdecodequery.nim @@ -0,0 +1,7 @@ +import std/[uri, sequtils] + + +block: + doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] + doAssertRaises(UriParseError): + discard toSeq(decodeQuery("a=1&b=2c=6")) From 0c8ce2dccf6f779dae01a6a66cf7a29b50796481 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 27 Dec 2020 08:02:10 -0300 Subject: [PATCH 1702/4254] Save some alloc on base64 using encodeSize (#16465) --- lib/pure/base64.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 40c9af905..2abdc805d 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -193,6 +193,7 @@ proc encodeMime*(s: string, lineLen = 75, newLine = "\r\n"): string = ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encodeMime("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" + result = newStringOfCap(encodeSize(s.len)) for i, c in encode(s): if i != 0 and (i mod lineLen == 0): result.add(newLine) From 357729639ff970ba934a0dea2ae06ff063e37910 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 27 Dec 2020 05:35:01 -0800 Subject: [PATCH 1703/4254] fix #16469 vm float constants: do not conflate -0.0 and 0.0 (#16470) * fix #16469 vm float constants: do not conflate -0.0 and 0.0 * fix test for 32bit --- compiler/vmgen.nim | 7 ++++++- tests/float/tfloatnan.nim | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 2fbb78c8f..9f36fc736 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -453,7 +453,12 @@ proc sameConstant*(a, b: PNode): bool = of nkSym: result = a.sym == b.sym of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal + of nkFloatLit..nkFloat64Lit: + result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) + # refs bug #16469 + # if we wanted to only distinguish 0.0 vs -0.0: + # if a.floatVal == 0.0: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) + # else: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkType, nkNilLit: result = a.typ == b.typ of nkEmpty: result = true diff --git a/tests/float/tfloatnan.nim b/tests/float/tfloatnan.nim index 8f384c3d9..9e3dd94f6 100644 --- a/tests/float/tfloatnan.nim +++ b/tests/float/tfloatnan.nim @@ -15,7 +15,7 @@ echo "Nim: ", f32, " (float)" let f64: float64 = NaN echo "Nim: ", f64, " (double)" -block: # issue #10305 +block: # bug #10305 # with `-O3 -ffast-math`, generated C/C++ code is not nan compliant # user can pass `--passC:-ffast-math` if he doesn't care. proc fun() = @@ -42,3 +42,16 @@ block: # issue #10305 fun() fun2(0) +template main() = + # xxx move all tests under here + block: # bug #16469 + let a1 = 0.0 + let a2 = -0.0 + let a3 = 1.0 / a1 + let a4 = 1.0 / a2 + doAssert a3 == Inf + doAssert a4 == -Inf + doAssert $(a1, a2, a3, a4) == "(0.0, -0.0, inf, -inf)" + +static: main() +main() From 271f68259b5c42f515a707cd51bd500a298ec4a0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 07:45:57 -0600 Subject: [PATCH 1704/4254] remove some noises in tests (#16448) --- tests/metatype/utypeclasses.nim | 4 +- tests/objects/tobject.nim | 10 +--- tests/stdlib/nre/captures.nim | 16 ++--- tests/stdlib/nre/escape.nim | 4 +- tests/stdlib/nre/find.nim | 12 ++-- tests/stdlib/nre/init.nim | 10 ++-- tests/stdlib/nre/match.nim | 8 +-- tests/stdlib/nre/misc.nim | 6 +- tests/stdlib/nre/replace.nim | 8 +-- tests/stdlib/nre/split.nim | 14 ++--- tests/stdlib/tmath.nim | 55 +++++++---------- tests/stdlib/tnet.nim | 30 +++++----- tests/stdlib/tnre.nim | 19 ------ tests/stdlib/tparseuints.nim | 9 +-- tests/stdlib/ttimes.nim | 102 ++++++++++++++++---------------- tests/system/tio.nim | 8 +-- tests/template/utemplates.nim | 6 +- 17 files changed, 140 insertions(+), 181 deletions(-) diff --git a/tests/metatype/utypeclasses.nim b/tests/metatype/utypeclasses.nim index 06bab375e..f94b39742 100644 --- a/tests/metatype/utypeclasses.nim +++ b/tests/metatype/utypeclasses.nim @@ -3,11 +3,11 @@ import unittest proc concat(a, b): string = result = $a & $b -test "if proc param types are not supplied, the params are assumed to be generic": +block: # if proc param types are not supplied, the params are assumed to be generic check concat(1, "test") == "1test" check concat(1, 20) == "120" check concat("foo", "bar") == "foobar" -test "explicit param types can still be specified": +block: # explicit param types can still be specified check concat[cstring, cstring]("x", "y") == "xy" diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim index d166d5385..543a86376 100644 --- a/tests/objects/tobject.nim +++ b/tests/objects/tobject.nim @@ -1,7 +1,3 @@ -discard """ -output: "\n[Suite] object basic methods" -""" - import unittest type Obj = object @@ -10,12 +6,12 @@ type Obj = object proc makeObj(x: int): Obj = result.foo = x -suite "object basic methods": - test "it should convert an object to a string": +block: # object basic methods + block: # it should convert an object to a string var obj = makeObj(1) # Should be "obj: (foo: 1)" or similar. check($obj == "(foo: 1)") - test "it should test equality based on fields": + block: # it should test equality based on fields check(makeObj(1) == makeObj(1)) # bug #10203 diff --git a/tests/stdlib/nre/captures.nim b/tests/stdlib/nre/captures.nim index bd5e83ecc..acc141baf 100644 --- a/tests/stdlib/nre/captures.nim +++ b/tests/stdlib/nre/captures.nim @@ -1,12 +1,12 @@ import unittest, optional_nonstrict include nre -suite "captures": - test "map capture names to numbers": +block: # captures + block: # map capture names to numbers check(getNameToNumberTable(re("(?1(?2(?3))(?'v4'4))()")) == { "v1" : 0, "v2" : 1, "v3" : 2, "v4" : 3 }.toTable()) - test "capture bounds are correct": + block: # capture bounds are correct let ex1 = re("([0-9])") check("1 23".find(ex1).matchBounds == 0 .. 0) check("1 23".find(ex1).captureBounds[0] == 0 .. 0) @@ -20,7 +20,7 @@ suite "captures": let ex3 = re("([0-9]+)") check("824".find(ex3).captureBounds[0] == 0 .. 2) - test "named captures": + block: # named captures let ex1 = "foobar".find(re("(?foo)(?bar)")) check(ex1.captures["foo"] == "foo") check(ex1.captures["bar"] == "bar") @@ -32,7 +32,7 @@ suite "captures": expect KeyError: discard ex2.captures["bar"] - test "named capture bounds": + block: # named capture bounds let ex1 = "foo".find(re("(?foo)(?bar)?")) check("foo" in ex1.captureBounds) check(ex1.captureBounds["foo"] == 0..2) @@ -40,12 +40,12 @@ suite "captures": expect KeyError: discard ex1.captures["bar"] - test "capture count": + block: # capture count let ex1 = re("(?foo)(?bar)?") check(ex1.captureCount == 2) check(ex1.captureNameId == {"foo" : 0, "bar" : 1}.toTable()) - test "named capture table": + block: # named capture table let ex1 = "foo".find(re("(?foo)(?bar)?")) check(ex1.captures.toTable == {"foo" : "foo"}.toTable()) check(ex1.captureBounds.toTable == {"foo" : 0..2}.toTable()) @@ -53,7 +53,7 @@ suite "captures": let ex2 = "foobar".find(re("(?foo)(?bar)?")) check(ex2.captures.toTable == {"foo" : "foo", "bar" : "bar"}.toTable()) - test "capture sequence": + block: # capture sequence let ex1 = "foo".find(re("(?foo)(?bar)?")) check(ex1.captures.toSeq == @[some("foo"), none(string)]) check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])]) diff --git a/tests/stdlib/nre/escape.nim b/tests/stdlib/nre/escape.nim index db5e8a001..5e7dc0c0e 100644 --- a/tests/stdlib/nre/escape.nim +++ b/tests/stdlib/nre/escape.nim @@ -1,7 +1,7 @@ import nre, unittest -suite "escape strings": - test "escape strings": +block: # escape strings + block: # escape strings check("123".escapeRe() == "123") check("[]".escapeRe() == r"\[\]") check("()".escapeRe() == r"\(\)") diff --git a/tests/stdlib/nre/find.nim b/tests/stdlib/nre/find.nim index caa953ff4..7e7555d73 100644 --- a/tests/stdlib/nre/find.nim +++ b/tests/stdlib/nre/find.nim @@ -3,23 +3,23 @@ import nre except toSeq import optional_nonstrict import times, strutils -suite "find": - test "find text": +block: # find + block: # find text check("3213a".find(re"[a-z]").match == "a") check(toSeq(findIter("1 2 3 4 5 6 7 8 ", re" ")).map( proc (a: RegexMatch): string = a.match ) == @[" ", " ", " ", " ", " ", " ", " ", " "]) - test "find bounds": + block: # find bounds check(toSeq(findIter("1 2 3 4 5 ", re" ")).map( proc (a: RegexMatch): Slice[int] = a.matchBounds ) == @[1..1, 3..3, 5..5, 7..7, 9..9]) - test "overlapping find": + block: # overlapping find check("222".findAll(re"22") == @["22"]) check("2222".findAll(re"22") == @["22", "22"]) - test "len 0 find": + block: # len 0 find check("".findAll(re"\ ") == newSeq[string]()) check("".findAll(re"") == @[""]) check("abc".findAll(re"") == @["", "", "", ""]) @@ -27,7 +27,7 @@ suite "find": check("word\r\lword".findAll(re"(*ANYCRLF)(?m)$") == @["", ""]) check("слово слово".findAll(re"(*U)\b") == @["", "", "", ""]) - test "bail early": + block: # bail early ## we expect nothing to be found and we should be bailing out early which means that ## the timing difference between searching in small and large data should be well ## within a tolerance margin diff --git a/tests/stdlib/nre/init.nim b/tests/stdlib/nre/init.nim index 26e668104..f0c8e0a00 100644 --- a/tests/stdlib/nre/init.nim +++ b/tests/stdlib/nre/init.nim @@ -1,12 +1,12 @@ import unittest include nre -suite "Test NRE initialization": - test "correct initialization": +block: # Test NRE initialization + block: # correct initialization check(re("[0-9]+") != nil) check(re("(?i)[0-9]+") != nil) - test "options": + block: # options check(extractOptions("(*NEVER_UTF)") == ("", pcre.NEVER_UTF, true)) check(extractOptions("(*UTF8)(*ANCHORED)(*UCP)z") == @@ -19,14 +19,14 @@ suite "Test NRE initialization": check(extractOptions("(*LIMIT_MATCH=6)(*ANCHORED)z") == ("(*LIMIT_MATCH=6)z", pcre.ANCHORED, true)) - test "incorrect options": + block: # incorrect options for s in ["CR", "(CR", "(*CR", "(*abc)", "(*abc)CR", "(?i)", "(*LIMIT_MATCH=5", "(*NO_AUTO_POSSESS=5)"]: let ss = s & "(*NEVER_UTF)" check(extractOptions(ss) == (ss, 0, true)) - test "invalid regex": + block: # invalid regex expect(SyntaxError): discard re("[0-9") try: discard re("[0-9") diff --git a/tests/stdlib/nre/match.nim b/tests/stdlib/nre/match.nim index 06b69fd04..7e09a4b2f 100644 --- a/tests/stdlib/nre/match.nim +++ b/tests/stdlib/nre/match.nim @@ -1,12 +1,12 @@ include nre, unittest, optional_nonstrict -suite "match": - test "upper bound must be inclusive": +block: # match + block: # upper bound must be inclusive check("abc".match(re"abc", endpos = -1) == none(RegexMatch)) check("abc".match(re"abc", endpos = 1) == none(RegexMatch)) check("abc".match(re"abc", endpos = 2) != none(RegexMatch)) - test "match examples": + block: # match examples check("abc".match(re"(\w)").captures[0] == "a") check("abc".match(re"(?\w)").captures["letter"] == "a") check("abc".match(re"(\w)\w").captures[-1] == "ab") @@ -14,5 +14,5 @@ suite "match": check("abc".match(re"").captureBounds[-1] == 0 .. -1) check("abc".match(re"abc").captureBounds[-1] == 0 .. 2) - test "match test cases": + block: # match test cases check("123".match(re"").matchBounds == 0 .. -1) diff --git a/tests/stdlib/nre/misc.nim b/tests/stdlib/nre/misc.nim index f4a88b639..dbb0ecdf9 100644 --- a/tests/stdlib/nre/misc.nim +++ b/tests/stdlib/nre/misc.nim @@ -1,11 +1,11 @@ import unittest, nre, strutils, optional_nonstrict -suite "Misc tests": - test "unicode": +block: # Misc tests + block: # unicode check("".find(re"(*UTF8)").match == "") check("перевірка".replace(re"(*U)\w", "") == "") - test "empty or non-empty match": + block: # empty or non-empty match check("abc".findall(re"|.").join(":") == ":a::b::c:") check("abc".findall(re".|").join(":") == "a:b:c:") diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim index 6f3436410..5cf659f21 100644 --- a/tests/stdlib/nre/replace.nim +++ b/tests/stdlib/nre/replace.nim @@ -1,13 +1,13 @@ include nre import unittest -suite "replace": - test "replace with 0-length strings": +block: # replace + block: # replace with 0-length strings check("".replace(re"1", proc (v: RegexMatch): string = "1") == "") check(" ".replace(re"", proc (v: RegexMatch): string = "1") == "1 1") check("".replace(re"", proc (v: RegexMatch): string = "1") == "1") - test "regular replace": + block: # regular replace check("123".replace(re"\d", "foo") == "foofoofoo") check("123".replace(re"(\d)", "$1$1") == "112233") check("123".replace(re"(\d)(\d)", "$1$2") == "123") @@ -15,7 +15,7 @@ suite "replace": check("123".replace(re"(?\d)(\d)", "$foo$#$#") == "1123") check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") - test "replacing missing captures should throw instead of segfaulting": + block: # replacing missing captures should throw instead of segfaulting expect IndexDefect: discard "ab".replace(re"(a)|(b)", "$1$2") expect IndexDefect: discard "b".replace(re"(a)?(b)", "$1$2") expect KeyError: discard "b".replace(re"(a)?", "${foo}") diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim index 9d57ea7d8..3cd57bb82 100644 --- a/tests/stdlib/nre/split.nim +++ b/tests/stdlib/nre/split.nim @@ -1,8 +1,8 @@ import unittest, strutils include nre -suite "string splitting": - test "splitting strings": +block: # string splitting + block: # splitting strings check("1 2 3 4 5 6 ".split(re" ") == @["1", "2", "3", "4", "5", "6", ""]) check("1 2 ".split(re(" ")) == @["1", "", "2", "", ""]) check("1 2".split(re(" ")) == @["1", "2"]) @@ -10,22 +10,22 @@ suite "string splitting": check("".split(re"foo") == @[""]) check("9".split(re"\son\s") == @["9"]) - test "captured patterns": + block: # captured patterns check("12".split(re"(\d)") == @["", "1", "", "2", ""]) - test "maxsplit": + block: # maxsplit check("123".split(re"", maxsplit = 2) == @["1", "23"]) check("123".split(re"", maxsplit = 1) == @["123"]) check("123".split(re"", maxsplit = -1) == @["1", "2", "3"]) - test "split with 0-length match": + block: # split with 0-length match check("12345".split(re("")) == @["1", "2", "3", "4", "5"]) check("".split(re"") == newSeq[string]()) check("word word".split(re"\b") == @["word", " ", "word"]) check("word\r\lword".split(re"(*ANYCRLF)(?m)$") == @["word", "\r\lword"]) check("слово слово".split(re"(*U)(\b)") == @["", "слово", "", " ", "", "слово", ""]) - test "perl split tests": + block: # perl split tests check("forty-two" .split(re"") .join(",") == "f,o,r,t,y,-,t,w,o") check("forty-two" .split(re"", 3) .join(",") == "f,o,rty-two") check("split this string" .split(re" ") .join(",") == "split,this,string") @@ -47,7 +47,7 @@ suite "string splitting": check("" .split(re"") .len == 0) check(":" .split(re"") .len == 1) - test "start position": + block: # start position check("abc".split(re"", start = 1) == @["b", "c"]) check("abc".split(re"", start = 2) == @["c"]) check("abc".split(re"", start = 3) == newSeq[string]()) diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 43d19f9e0..0f66a94d1 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,18 +1,6 @@ discard """ action: run - output: ''' - -[Suite] random int - -[Suite] random float - -[Suite] cumsum - -[Suite] random sample - -[Suite] ^ -''' -matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" + matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" """ # xxx: fix bugs for js then add: targets:"c js" @@ -21,22 +9,22 @@ import math, random, os import unittest import sets, tables -suite "random int": - test "there might be some randomness": +block: # random int + block: # there might be some randomness var set = initHashSet[int](128) for i in 1..1000: incl(set, rand(high(int))) check len(set) == 1000 - test "single number bounds work": + block: # single number bounds work var rand: int for i in 1..1000: rand = rand(1000) check rand < 1000 check rand > -1 - test "slice bounds work": + block: # slice bounds work var rand: int for i in 1..1000: rand = rand(100..1000) @@ -45,8 +33,8 @@ suite "random int": else: check rand < 1000 check rand >= 100 - test " again gives new numbers": + block: # again gives new numbers var rand1 = rand(1000000) when not defined(js): os.sleep(200) @@ -55,28 +43,29 @@ suite "random int": check rand1 != rand2 -suite "random float": - test "there might be some randomness": +block: # random float + block: # there might be some randomness var set = initHashSet[float](128) for i in 1..100: incl(set, rand(1.0)) check len(set) == 100 - test "single number bounds work": + block: # single number bounds work var rand: float for i in 1..1000: rand = rand(1000.0) check rand < 1000.0 check rand > -1.0 - test "slice bounds work": + block: # slice bounds work var rand: float for i in 1..1000: rand = rand(100.0..1000.0) check rand < 1000.0 check rand >= 100.0 - test " again gives new numbers": + + block: # again gives new numbers var rand1:float = rand(1000000.0) when not defined(js): @@ -85,27 +74,27 @@ suite "random float": var rand2:float = rand(1000000.0) check rand1 != rand2 -suite "cumsum": - test "cumsum int seq return": +block: # cumsum + block: # cumsum int seq return let counts = [ 1, 2, 3, 4 ] check counts.cumsummed == [ 1, 3, 6, 10 ] - test "cumsum float seq return": + block: # cumsum float seq return let counts = [ 1.0, 2.0, 3.0, 4.0 ] check counts.cumsummed == [ 1.0, 3.0, 6.0, 10.0 ] - test "cumsum int in-place": + block: # cumsum int in-place var counts = [ 1, 2, 3, 4 ] counts.cumsum check counts == [ 1, 3, 6, 10 ] - test "cumsum float in-place": + block: # cumsum float in-place var counts = [ 1.0, 2.0, 3.0, 4.0 ] counts.cumsum check counts == [ 1.0, 3.0, 6.0, 10.0 ] -suite "random sample": - test "non-uniform array sample unnormalized int CDF": +block: # random sample + block: # "non-uniform array sample unnormalized int CDF let values = [ 10, 20, 30, 40, 50 ] # values let counts = [ 4, 3, 2, 1, 0 ] # weights aka unnormalized probabilities var histo = initCountTable[int]() @@ -127,7 +116,7 @@ suite "random sample": let stdDev = sqrt(n * p * (1.0 - p)) check abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev - test "non-uniform array sample normalized float CDF": + block: # non-uniform array sample normalized float CDF let values = [ 10, 20, 30, 40, 50 ] # values let counts = [ 0.4, 0.3, 0.2, 0.1, 0 ] # probabilities var histo = initCountTable[int]() @@ -146,8 +135,8 @@ suite "random sample": # NOTE: like unnormalized int CDF test, P(wholeTestFails) =~ 0.01. check abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev -suite "^": - test "compiles for valid types": +block: # ^ + block: # compiles for valid types check: compiles(5 ^ 2) check: compiles(5.5 ^ 2) check: compiles(5.5 ^ 2.int8) diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 2dd22796c..b19d31f6c 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -5,48 +5,48 @@ outputsub: "" import net, nativesockets import unittest -suite "isIpAddress tests": - test "127.0.0.1 is valid": +block: # isIpAddress tests + block: # 127.0.0.1 is valid check isIpAddress("127.0.0.1") == true - test "ipv6 localhost is valid": + block: # ipv6 localhost is valid check isIpAddress("::1") == true - test "fqdn is not an ip address": + block: # fqdn is not an ip address check isIpAddress("example.com") == false - test "random string is not an ipaddress": + block: # random string is not an ipaddress check isIpAddress("foo bar") == false - test "5127.0.0.1 is invalid": + block: # 5127.0.0.1 is invalid check isIpAddress("5127.0.0.1") == false - test "ipv6 is valid": + block: # ipv6 is valid check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true - test "invalid ipv6": + block: # invalid ipv6 check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false -suite "parseIpAddress tests": - test "127.0.0.1 is valid": +block: # parseIpAddress tests + block: # 127.0.0.1 is valid discard parseIpAddress("127.0.0.1") - test "ipv6 localhost is valid": + block: # ipv6 localhost is valid discard parseIpAddress("::1") - test "fqdn is not an ip address": + block: # fqdn is not an ip address expect(ValueError): discard parseIpAddress("example.com") - test "random string is not an ipaddress": + block: # random string is not an ipaddress expect(ValueError): discard parseIpAddress("foo bar") - test "ipv6 is valid": + block: # ipv6 is valid discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") - test "invalid ipv6": + block: # invalid ipv6 expect(ValueError): discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim index d2dc1a7c5..f13c16052 100644 --- a/tests/stdlib/tnre.nim +++ b/tests/stdlib/tnre.nim @@ -2,25 +2,6 @@ discard """ # Since the tests for nre are all bundled together we treat failure in one test as an nre failure # When running 'testament/tester' a failed check() in the test suite will cause the exit # codes to differ and be reported as a failure - - output: - ''' - -[Suite] Test NRE initialization - -[Suite] captures - -[Suite] find - -[Suite] string splitting - -[Suite] match - -[Suite] replace - -[Suite] escape strings - -[Suite] Misc tests''' """ import nre diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim index 72041da66..ef8c782b3 100644 --- a/tests/stdlib/tparseuints.nim +++ b/tests/stdlib/tparseuints.nim @@ -1,13 +1,6 @@ -discard """ - action: run - output: ''' - -[Suite] parseutils -''' -""" import unittest, strutils -suite "parseutils": +block: # parseutils check: parseBiggestUInt("0") == 0'u64 check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64 expect(ValueError): diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index a7677edf9..dc9468def 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -116,7 +116,7 @@ template usingTimezone(tz: string, body: untyped) = body putEnv("TZ", oldZone) -suite "ttimes": +block: # ttimes # Generate tests for multiple timezone files where available # Set the TZ env var for each test @@ -143,7 +143,7 @@ suite "ttimes": test "parseTest": runTimezoneTests() - test "dst handling": + block: # dst handling usingTimezone("Europe/Stockholm"): # In case of an impossible time, the time is moved to after the # impossible time period @@ -163,7 +163,7 @@ suite "ttimes": check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) == "2017-10-21 01:00 +02:00" - test "issue #6520": + block: # issue #6520 usingTimezone("Europe/Stockholm"): var local = fromUnix(1469275200).local var utc = fromUnix(1469275200).utc @@ -172,19 +172,19 @@ suite "ttimes": local.utcOffset = 0 check claimedOffset == utc.toTime - local.toTime - test "issue #5704": + block: # issue #5704 usingTimezone("Asia/Seoul"): let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime - parse("19000101-000000", "yyyyMMdd-hhmmss").toTime check diff == initDuration(seconds = 2208986872) - test "issue #6465": + block: # issue #6465 usingTimezone("Europe/Stockholm"): let dt = parse("2017-03-25 12:00", "yyyy-MM-dd hh:mm") check $(dt + initTimeInterval(days = 1)) == "2017-03-26T12:00:00+02:00" check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00" - test "adding/subtracting time across dst": + block: # adding/subtracting time across dst usingTimezone("Europe/Stockholm"): let dt1 = initDateTime(26, mMar, 2017, 03, 00, 00) check $(dt1 - 1.seconds) == "2017-03-26T01:59:59+01:00" @@ -192,55 +192,55 @@ suite "ttimes": var dt2 = initDateTime(29, mOct, 2017, 02, 59, 59) check $(dt2 + 1.seconds) == "2017-10-29T02:00:00+01:00" - test "datetime before epoch": + block: # datetime before epoch check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52Z" - test "incorrect inputs: empty string": + block: # incorrect inputs: empty string parseTestExcp("", "yyyy-MM-dd") - test "incorrect inputs: year": + block: # incorrect inputs: year parseTestExcp("20-02-19", "yyyy-MM-dd") - test "incorrect inputs: month number": + block: # incorrect inputs: month number parseTestExcp("2018-2-19", "yyyy-MM-dd") - test "incorrect inputs: month name": + block: # incorrect inputs: month name parseTestExcp("2018-Fe", "yyyy-MMM-dd") - test "incorrect inputs: day": + block: # incorrect inputs: day parseTestExcp("2018-02-1", "yyyy-MM-dd") - test "incorrect inputs: day of week": + block: # incorrect inputs: day of week parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd") - test "incorrect inputs: hour": + block: # incorrect inputs: hour parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm") - test "incorrect inputs: minute": + block: # incorrect inputs: minute parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm") - test "incorrect inputs: second": + block: # incorrect inputs: second parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss") - test "incorrect inputs: timezone (z)": + block: # incorrect inputs: timezone (z) parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z") - test "incorrect inputs: timezone (zz) 1": + block: # incorrect inputs: timezone (zz) 1 parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz") - test "incorrect inputs: timezone (zz) 2": + block: # incorrect inputs: timezone (zz) 2 parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz") - test "incorrect inputs: timezone (zzz) 1": + block: # incorrect inputs: timezone (zzz) 1 parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz") - test "incorrect inputs: timezone (zzz) 2": + block: # incorrect inputs: timezone (zzz) 2 parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz") - test "incorrect inputs: timezone (zzz) 3": + block: # incorrect inputs: timezone (zzz) 3 parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz") - test "incorrect inputs: year (yyyy/uuuu)": + block: # incorrect inputs: year (yyyy/uuuu) parseTestExcp("-0001", "yyyy") parseTestExcp("-0001", "YYYY") parseTestExcp("1", "yyyy") @@ -249,7 +249,7 @@ suite "ttimes": parseTestExcp("12345", "uuuu") parseTestExcp("-1 BC", "UUUU g") - test "incorrect inputs: invalid sign": + block: # incorrect inputs: invalid sign parseTestExcp("+1", "YYYY") parseTestExcp("+1", "dd") parseTestExcp("+1", "MM") @@ -257,10 +257,10 @@ suite "ttimes": parseTestExcp("+1", "mm") parseTestExcp("+1", "ss") - test "_ as a separator": + block: # _ as a separator discard parse("2000_01_01", "YYYY'_'MM'_'dd") - test "dynamic timezone": + block: # dynamic timezone let tz = staticTz(seconds = -9000) let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz) check dt.utcOffset == -9000 @@ -269,13 +269,13 @@ suite "ttimes": check $dt.utc == "2000-01-01T09:30:00Z" check $dt.utc.inZone(tz) == $dt - test "isLeapYear": + block: # isLeapYear check isLeapYear(2016) check (not isLeapYear(2015)) check isLeapYear(2000) check (not isLeapYear(1900)) - test "TimeInterval": + block: # TimeInterval let t = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997 # Interval tests let t2 = t - 2.years @@ -287,7 +287,7 @@ suite "ttimes": check (t + 1.hours).toTime.toUnix == t.toTime.toUnix + 60 * 60 check (t - 1.hours).toTime.toUnix == t.toTime.toUnix - 60 * 60 - test "TimeInterval - months": + block: # TimeInterval - months var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc()) check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00Z" dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc()) @@ -296,7 +296,7 @@ suite "ttimes": # This happens due to monthday overflow. It's consistent with Phobos. check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00Z" - test "duration": + block: # duration let d = initDuration check d(hours = 48) + d(days = 5) == d(weeks = 1) let dt = initDateTime(01, mFeb, 2000, 00, 00, 00, 0, utc()) + d(milliseconds = 1) @@ -316,7 +316,7 @@ suite "ttimes": check (initDuration(seconds = 1, nanoseconds = 3) <= initDuration(seconds = 1, nanoseconds = 1)).not - test "large/small dates": + block: # large/small dates discard initDateTime(1, mJan, -35_000, 12, 00, 00, utc()) # with local tz discard initDateTime(1, mJan, -35_000, 12, 00, 00) @@ -328,7 +328,7 @@ suite "ttimes": let dt2 = dt + 35_001.years check $dt2 == "0001-01-01T12:00:01Z" - test "compare datetimes": + block: # compare datetimes var dt1 = now() var dt2 = dt1 check dt1 == dt2 @@ -336,7 +336,7 @@ suite "ttimes": dt2 = dt2 + 1.seconds check dt1 < dt2 - test "adding/subtracting TimeInterval": + block: # adding/subtracting TimeInterval # add/subtract TimeIntervals and Time/TimeInfo let now = getTime().utc let isSpecial = now.isLeapDay @@ -374,14 +374,14 @@ suite "ttimes": check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 - test "issue 7620": + block: # issue 7620 let layout = "M/d/yyyy' 'h:mm:ss' 'tt' 'z" let t7620_am = parse("4/15/2017 12:01:02 AM +0", layout, utc()) check t7620_am.format(layout) == "4/15/2017 12:01:02 AM Z" let t7620_pm = parse("4/15/2017 12:01:02 PM +0", layout, utc()) check t7620_pm.format(layout) == "4/15/2017 12:01:02 PM Z" - test "format": + block: # format var dt = initDateTime(1, mJan, -0001, 17, 01, 02, 123_456_789, staticTz(hours = 1, minutes = 2, seconds = 3)) @@ -450,7 +450,7 @@ suite "ttimes": doAssert dt.format("zz") == tz[2] doAssert dt.format("zzz") == tz[3] - test "format locale": + block: # format locale let loc = DateTimeLocale( MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"], MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"], @@ -467,7 +467,7 @@ suite "ttimes": check dt.format("MMM", loc) == "Fir" check dt.format("MMMM", loc) == "Firsty" - test "parse": + block: # parse check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z" parseTestExcp("+120180101", "yyyyMMdd") @@ -488,7 +488,7 @@ suite "ttimes": parseTestExcp("2000 A", "yyyy g") - test "parse locale": + block: # parse locale let loc = DateTimeLocale( MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"], MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"], @@ -498,7 +498,7 @@ suite "ttimes": check $parse("02 Fir 2019", "dd MMM yyyy", utc(), loc) == "2019-01-02T00:00:00Z" check $parse("Fourthy 6, 2017", "MMMM d, yyyy", utc(), loc) == "2017-04-06T00:00:00Z" - test "timezoneConversion": + block: # timezoneConversion var l = now() let u = l.utc l = u.local @@ -506,7 +506,7 @@ suite "ttimes": check l.timezone == local() check u.timezone == utc() - test "getDayOfWeek": + block: # getDayOfWeek check getDayOfWeek(01, mJan, 0000) == dSat check getDayOfWeek(01, mJan, -0023) == dSat check getDayOfWeek(21, mSep, 1900) == dFri @@ -515,29 +515,29 @@ suite "ttimes": check getDayOfWeek(01, mJan, 2000) == dSat check getDayOfWeek(01, mJan, 2021) == dFri - test "between - simple": + block: # between - simple let x = initDateTime(10, mJan, 2018, 13, 00, 00) let y = initDateTime(11, mJan, 2018, 12, 00, 00) doAssert x + between(x, y) == y - test "between - dst start": + block: # between - dst start usingTimezone("Europe/Stockholm"): let x = initDateTime(25, mMar, 2018, 00, 00, 00) let y = initDateTime(25, mMar, 2018, 04, 00, 00) doAssert x + between(x, y) == y - test "between - empty interval": + block: # between - empty interval let x = now() let y = x doAssert x + between(x, y) == y - test "between - dst end": + block: # between - dst end usingTimezone("Europe/Stockholm"): let x = initDateTime(27, mOct, 2018, 02, 00, 00) let y = initDateTime(28, mOct, 2018, 01, 00, 00) doAssert x + between(x, y) == y - test "between - long day": + block: # between - long day usingTimezone("Europe/Stockholm"): # This day is 25 hours long in Europe/Stockholm let x = initDateTime(28, mOct, 2018, 00, 30, 00) @@ -545,7 +545,7 @@ suite "ttimes": doAssert between(x, y) == 24.hours + 30.minutes doAssert x + between(x, y) == y - test "between - offset change edge case": + block: # between - offset change edge case # This test case is important because in this case # `x + between(x.utc, y.utc) == y` is not true, which is very rare. usingTimezone("America/Belem"): @@ -554,19 +554,19 @@ suite "ttimes": doAssert x + between(x, y) == y doAssert y + between(y, x) == x - test "between - all units": + block: # between - all units let x = initDateTime(1, mJan, 2000, 00, 00, 00, utc()) let ti = initTimeInterval(1, 1, 1, 1, 1, 1, 1, 1, 1, 1) let y = x + ti doAssert between(x, y) == ti doAssert between(y, x) == -ti - test "between - monthday overflow": + block: # between - monthday overflow let x = initDateTime(31, mJan, 2001, 00, 00, 00, utc()) let y = initDateTime(1, mMar, 2001, 00, 00, 00, utc()) doAssert x + between(x, y) == y - test "between - misc": + block: # between - misc block: let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc()) let y = initDateTime(01, mJan, 2001, 00, 00, 00, utc()) @@ -608,7 +608,7 @@ suite "ttimes": doAssert x + between(x, y) == y doAssert between(x, y) == 1.months + 1.weeks - test "default DateTime": # https://github.com/nim-lang/RFCs/issues/211 + block: # default DateTime https://github.com/nim-lang/RFCs/issues/211 var num = 0 for ai in Month: num.inc check num == 12 @@ -634,7 +634,7 @@ suite "ttimes": expect(AssertionDefect): discard a.format initTimeFormat("yyyy") expect(AssertionDefect): discard between(a, a) - test "inX procs": + block: # inX procs doAssert initDuration(seconds = 1).inSeconds == 1 doAssert initDuration(seconds = -1).inSeconds == -1 doAssert initDuration(seconds = -1, nanoseconds = 1).inSeconds == 0 diff --git a/tests/system/tio.nim b/tests/system/tio.nim index c4d041560..52a21837a 100644 --- a/tests/system/tio.nim +++ b/tests/system/tio.nim @@ -22,12 +22,12 @@ proc echoLoop(str: string): string = while not output.atEnd: result.add(output.readLine) -suite "io": - suite "readAll": - test "stdin": +block: # io + block: # readAll + block: # stdin check: echoLoop(STRING_DATA) == STRING_DATA - test "file": + block: # file check: readFile(TEST_FILE).strip == STRING_DATA diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim index 017166250..7674ba7c0 100644 --- a/tests/template/utemplates.nim +++ b/tests/template/utemplates.nim @@ -3,11 +3,11 @@ import unittest template t(a: int): string = "int" template t(a: string): string = "string" -test "templates can be overloaded": +block: # templates can be overloaded check t(10) == "int" check t("test") == "string" -test "previous definitions can be further overloaded or hidden in local scopes": +block: # previous definitions can be further overloaded or hidden in local scopes template t(a: bool): string = "bool" check t(true) == "bool" @@ -17,7 +17,7 @@ test "previous definitions can be further overloaded or hidden in local scopes": check t(10) == "inner int" check t("test") == "string" -test "templates can be redefined multiple times": +block: # templates can be redefined multiple times template customAssert(cond: bool, msg: string): typed {.dirty.} = if not cond: fail(msg) From 792e4a0392519c7921a0afedb029d02b5485ca64 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 09:08:48 -0600 Subject: [PATCH 1705/4254] Revert #16478 (#16483) * minor * Revert "minor" This reverts commit ef1807cbb468bffdcfffb41f023644b57fb0fe11. --- compiler/llstream.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index bd335c23d..6df927c60 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -110,7 +110,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int = s.rd = 0 var line = newStringOfCap(120) var triples = 0 - while readLineFromStdin(if s.s.len == 0: "\n>>> " else: "... ", line): + while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line): s.s.add(line) s.s.add("\n") inc triples, countTriples(line) From e718a4a058f9a9d0c9c8ce1d388040de7c14271d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 27 Dec 2020 12:46:21 -0600 Subject: [PATCH 1706/4254] follow #15860 clean cgi module (#16487) * follow #15860 clean cgi module * follow #15860 clean cgi module --- lib/pure/cgi.nim | 97 +++++++++++++++++++-------------------- tests/gc/growobjcrash.nim | 7 +-- tests/stdlib/tcgi.nim | 30 ++++-------- 3 files changed, 57 insertions(+), 77 deletions(-) diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index d3a762911..8d827f555 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -29,13 +29,10 @@ ## writeLine(stdout, "your password: " & myData["password"]) ## writeLine(stdout, "") -import strutils, os, strtabs, cookies, uri +import std/[strutils, os, strtabs, cookies, uri] export uri.encodeUrl, uri.decodeUrl -import std/private/decode_helpers - - proc addXmlChar(dest: var string, c: char) {.inline.} = case c of '&': add(dest, "&") @@ -46,23 +43,23 @@ proc addXmlChar(dest: var string, c: char) {.inline.} = proc xmlEncode*(s: string): string = ## Encodes a value to be XML safe: - ## * ``"`` is replaced by ``"`` - ## * ``<`` is replaced by ``<`` - ## * ``>`` is replaced by ``>`` - ## * ``&`` is replaced by ``&`` + ## * `"` is replaced by `"` + ## * `<` is replaced by `<` + ## * `>` is replaced by `>` + ## * `&` is replaced by `&` ## * every other character is carried over. result = newStringOfCap(s.len + s.len shr 2) for i in 0..len(s)-1: addXmlChar(result, s[i]) type - CgiError* = object of IOError ## Exception that is raised if a CGI error occurs - RequestMethod* = enum ## the used request method + CgiError* = object of IOError ## Exception that is raised if a CGI error occurs. + RequestMethod* = enum ## The used request method. methodNone, ## no REQUEST_METHOD environment variable methodPost, ## query uses the POST method methodGet ## query uses the GET method proc cgiError*(msg: string) {.noreturn.} = - ## Raises a ``CgiError`` exception with message `msg`. + ## Raises a `CgiError` exception with message `msg`. raise newException(CgiError, msg) proc getEncodedData(allowedMethods: set[RequestMethod]): string = @@ -97,7 +94,7 @@ iterator decodeData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. If the client does not use a method listed in the - ## `allowedMethods` set, a ``CgiError`` exception is raised. + ## `allowedMethods` set, a `CgiError` exception is raised. let data = getEncodedData(allowedMethods) try: for (key, value) in uri.decodeQuery(data): @@ -107,155 +104,155 @@ iterator decodeData*(allowedMethods: set[RequestMethod] = proc readData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): StringTableRef = - ## Read CGI data. If the client does not use a method listed in the - ## `allowedMethods` set, an `ECgi` exception is raised. + ## Reads CGI data. If the client does not use a method listed in the + ## `allowedMethods` set, a `CgiError` exception is raised. result = newStringTable() for name, value in decodeData(allowedMethods): result[name.string] = value.string proc readData*(data: string): StringTableRef = - ## Read CGI data from a string. + ## Reads CGI data from a string. result = newStringTable() for name, value in decodeData(data): result[name.string] = value.string proc validateData*(data: StringTableRef, validKeys: varargs[string]) = - ## validates data; raises `ECgi` if this fails. This checks that each variable + ## Validates data; raises `CgiError` if this fails. This checks that each variable ## name of the CGI `data` occurs in the `validKeys` array. for key, val in pairs(data): if find(validKeys, key) < 0: cgiError("unknown variable name: " & key) proc getContentLength*(): string = - ## returns contents of the ``CONTENT_LENGTH`` environment variable + ## Returns contents of the `CONTENT_LENGTH` environment variable. return getEnv("CONTENT_LENGTH").string proc getContentType*(): string = - ## returns contents of the ``CONTENT_TYPE`` environment variable + ## Returns contents of the `CONTENT_TYPE` environment variable. return getEnv("CONTENT_Type").string proc getDocumentRoot*(): string = - ## returns contents of the ``DOCUMENT_ROOT`` environment variable + ## Returns contents of the `DOCUMENT_ROOT` environment variable. return getEnv("DOCUMENT_ROOT").string proc getGatewayInterface*(): string = - ## returns contents of the ``GATEWAY_INTERFACE`` environment variable + ## Returns contents of the `GATEWAY_INTERFACE` environment variable. return getEnv("GATEWAY_INTERFACE").string proc getHttpAccept*(): string = - ## returns contents of the ``HTTP_ACCEPT`` environment variable + ## Returns contents of the `HTTP_ACCEPT` environment variable. return getEnv("HTTP_ACCEPT").string proc getHttpAcceptCharset*(): string = - ## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable + ## Returns contents of the `HTTP_ACCEPT_CHARSET` environment variable. return getEnv("HTTP_ACCEPT_CHARSET").string proc getHttpAcceptEncoding*(): string = - ## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable + ## Returns contents of the `HTTP_ACCEPT_ENCODING` environment variable. return getEnv("HTTP_ACCEPT_ENCODING").string proc getHttpAcceptLanguage*(): string = - ## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable + ## Returns contents of the `HTTP_ACCEPT_LANGUAGE` environment variable. return getEnv("HTTP_ACCEPT_LANGUAGE").string proc getHttpConnection*(): string = - ## returns contents of the ``HTTP_CONNECTION`` environment variable + ## Returns contents of the `HTTP_CONNECTION` environment variable. return getEnv("HTTP_CONNECTION").string proc getHttpCookie*(): string = - ## returns contents of the ``HTTP_COOKIE`` environment variable + ## Returns contents of the `HTTP_COOKIE` environment variable. return getEnv("HTTP_COOKIE").string proc getHttpHost*(): string = - ## returns contents of the ``HTTP_HOST`` environment variable + ## Returns contents of the `HTTP_HOST` environment variable. return getEnv("HTTP_HOST").string proc getHttpReferer*(): string = - ## returns contents of the ``HTTP_REFERER`` environment variable + ## Returns contents of the `HTTP_REFERER` environment variable. return getEnv("HTTP_REFERER").string proc getHttpUserAgent*(): string = - ## returns contents of the ``HTTP_USER_AGENT`` environment variable + ## Returns contents of the `HTTP_USER_AGENT` environment variable. return getEnv("HTTP_USER_AGENT").string proc getPathInfo*(): string = - ## returns contents of the ``PATH_INFO`` environment variable + ## Returns contents of the `PATH_INFO` environment variable. return getEnv("PATH_INFO").string proc getPathTranslated*(): string = - ## returns contents of the ``PATH_TRANSLATED`` environment variable + ## Returns contents of the `PATH_TRANSLATED` environment variable. return getEnv("PATH_TRANSLATED").string proc getQueryString*(): string = - ## returns contents of the ``QUERY_STRING`` environment variable + ## Returns contents of the `QUERY_STRING` environment variable. return getEnv("QUERY_STRING").string proc getRemoteAddr*(): string = - ## returns contents of the ``REMOTE_ADDR`` environment variable + ## Returns contents of the `REMOTE_ADDR` environment variable. return getEnv("REMOTE_ADDR").string proc getRemoteHost*(): string = - ## returns contents of the ``REMOTE_HOST`` environment variable + ## Returns contents of the `REMOTE_HOST` environment variable. return getEnv("REMOTE_HOST").string proc getRemoteIdent*(): string = - ## returns contents of the ``REMOTE_IDENT`` environment variable + ## Returns contents of the `REMOTE_IDENT` environment variable. return getEnv("REMOTE_IDENT").string proc getRemotePort*(): string = - ## returns contents of the ``REMOTE_PORT`` environment variable + ## Returns contents of the `REMOTE_PORT` environment variable. return getEnv("REMOTE_PORT").string proc getRemoteUser*(): string = - ## returns contents of the ``REMOTE_USER`` environment variable + ## Returns contents of the `REMOTE_USER` environment variable. return getEnv("REMOTE_USER").string proc getRequestMethod*(): string = - ## returns contents of the ``REQUEST_METHOD`` environment variable + ## Returns contents of the `REQUEST_METHOD` environment variable. return getEnv("REQUEST_METHOD").string proc getRequestURI*(): string = - ## returns contents of the ``REQUEST_URI`` environment variable + ## Returns contents of the `REQUEST_URI` environment variable. return getEnv("REQUEST_URI").string proc getScriptFilename*(): string = - ## returns contents of the ``SCRIPT_FILENAME`` environment variable + ## Returns contents of the `SCRIPT_FILENAME` environment variable. return getEnv("SCRIPT_FILENAME").string proc getScriptName*(): string = - ## returns contents of the ``SCRIPT_NAME`` environment variable + ## Returns contents of the `SCRIPT_NAME` environment variable. return getEnv("SCRIPT_NAME").string proc getServerAddr*(): string = - ## returns contents of the ``SERVER_ADDR`` environment variable + ## Returns contents of the `SERVER_ADDR` environment variable. return getEnv("SERVER_ADDR").string proc getServerAdmin*(): string = - ## returns contents of the ``SERVER_ADMIN`` environment variable + ## Returns contents of the `SERVER_ADMIN` environment variable. return getEnv("SERVER_ADMIN").string proc getServerName*(): string = - ## returns contents of the ``SERVER_NAME`` environment variable + ## Returns contents of the `SERVER_NAME` environment variable. return getEnv("SERVER_NAME").string proc getServerPort*(): string = - ## returns contents of the ``SERVER_PORT`` environment variable + ## Returns contents of the `SERVER_PORT` environment variable. return getEnv("SERVER_PORT").string proc getServerProtocol*(): string = - ## returns contents of the ``SERVER_PROTOCOL`` environment variable + ## Returns contents of the `SERVER_PROTOCOL` environment variable. return getEnv("SERVER_PROTOCOL").string proc getServerSignature*(): string = - ## returns contents of the ``SERVER_SIGNATURE`` environment variable + ## Returns contents of the `SERVER_SIGNATURE` environment variable. return getEnv("SERVER_SIGNATURE").string proc getServerSoftware*(): string = - ## returns contents of the ``SERVER_SOFTWARE`` environment variable + ## Returns contents of the `SERVER_SOFTWARE` environment variable. return getEnv("SERVER_SOFTWARE").string proc setTestData*(keysvalues: varargs[string]) = - ## fills the appropriate environment variables to test your CGI application. + ## Fills the appropriate environment variables to test your CGI application. ## This can only simulate the 'GET' request method. `keysvalues` should ## provide embedded (name, value)-pairs. Example: ## @@ -273,7 +270,7 @@ proc setTestData*(keysvalues: varargs[string]) = putEnv("QUERY_STRING", query) proc writeContentType*() = - ## call this before starting to send your HTML data to `stdout`. This + ## Calls this before starting to send your HTML data to `stdout`. This ## implements this part of the CGI protocol: ## ## .. code-block:: Nim diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index 84fd30a4f..ff1aa7e98 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -1,8 +1,4 @@ -discard """ - output: "works" -""" - -import cgi, strtabs +import std/[cgi, strtabs] proc handleRequest(query: string): StringTableRef = iterator foo(): StringTableRef {.closure.} = @@ -26,4 +22,3 @@ proc main = quit "but now a leak" main() -echo "works" diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index cec188e35..993728712 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,25 +1,10 @@ -discard """ - output: ''' +import std/unittest +import std/[cgi, strtabs, sugar] -[Suite] Test cgi module -(key: "a", value: "1") -(key: "b", value: "0") -(key: "c", value: "3") -(key: "d", value: "") -(key: "e", value: "") -(key: "a", value: "5") -(key: "a", value: "t e x t") -(key: "e", value: "http://w3schools.com/my test.asp?name=ståle&car=saab") -''' -""" - -import unittest -import cgi, strtabs - -suite "Test cgi module": +block: # Test cgi module const queryString = "foo=bar&фу=бар&checked=✓&list=1,2,3&with_space=text%20with%20space" - test "test query parsing with readData": + block: # test query parsing with readData let parsedQuery = readData(queryString) check parsedQuery["foo"] == "bar" @@ -34,5 +19,8 @@ suite "Test cgi module": # bug #15369 let queryString = "a=1&b=0&c=3&d&e&a=5&a=t%20e%20x%20t&e=http%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab" -for pair in decodeData(queryString): - echo pair +doAssert collect(for pair in decodeData(queryString): pair) == + @[("a", "1"), ("b", "0"), ("c", "3"), + ("d", ""),("e", ""), ("a", "5"), ("a", "t e x t"), + ("e", "http://w3schools.com/my test.asp?name=ståle&car=saab") +] From fbc8a40c7a351ff7c0f2dc0608bc8926f89d8537 Mon Sep 17 00:00:00 2001 From: cooldome Date: Sun, 27 Dec 2020 21:05:33 +0200 Subject: [PATCH 1707/4254] fix #15043 (#16441) [backport:1.4] * fix #15043 * Trigger build --- compiler/lambdalifting.nim | 12 +++++++----- tests/arc/trepr.nim | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 95e50d00f..4f3823f8a 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -238,10 +238,11 @@ proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = result = conf.backend == backendJs and not isCompileTime proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) = - createTypeBoundOps(g, nil, refType.lastSon, info, idgen) - createTypeBoundOps(g, nil, refType, info, idgen) - if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions: - owner.flags.incl sfInjectDestructors + if owner.kind != skMacro: + createTypeBoundOps(g, nil, refType.lastSon, info, idgen) + createTypeBoundOps(g, nil, refType, info, idgen) + if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions: + owner.flags.incl sfInjectDestructors proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) @@ -613,7 +614,8 @@ proc rawClosureCreation(owner: PSym; let fieldAccess = indirectAccess(env, local, env.info) # add ``env.param = param`` result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info)) - createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen) + if owner.kind != skMacro: + createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen) if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions: owner.flags.incl sfInjectDestructors diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index 3c1e4129c..50d433208 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -71,3 +71,19 @@ proc p2 = discard repr p2 + +##################################################################### +# bug #15043 + +import macros + +macro extract(): untyped = + result = newStmtList() + var x: seq[tuple[node: NimNode]] + + proc test(n: NimNode) {.closure.} = + x.add (node: n) + + test(parseExpr("discard")) + +extract() From f9a15dbae909f4521cd506bedf7ec500c4f4d9f8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 28 Dec 2020 03:19:47 -0800 Subject: [PATCH 1708/4254] fix `nim secret` dots interfering with prompt (#16491) * fix nim secret dots * cleanups --- compiler/llstream.nim | 6 +++++- compiler/main.nim | 3 ++- compiler/msgs.nim | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 6df927c60..b768e6c83 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -20,6 +20,7 @@ when hasRstdin: import rdstdin type TLLRepl* = proc (s: PLLStream, buf: pointer, bufLen: int): int + OnPrompt* = proc() {.closure.} TLLStreamKind* = enum # enum of different stream implementations llsNone, # null stream: reading and writing has no effect llsString, # stream encapsulates a string @@ -32,6 +33,7 @@ type rd*, wr*: int # for string streams lineOffset*: int # for fake stdin line numbers repl*: TLLRepl # gives stdin control to clients + onPrompt*: OnPrompt PLLStream* = ref TLLStream @@ -55,12 +57,13 @@ proc llStreamOpen*(): PLLStream = result.kind = llsNone proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int -proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin): PLLStream = +proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream = new(result) result.kind = llsStdIn result.s = "" result.lineOffset = -1 result.repl = r + result.onPrompt = onPrompt proc llStreamClose*(s: PLLStream) = case s.kind @@ -133,6 +136,7 @@ proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int = of llsFile: result = readBuffer(s.f, buf, bufLen) of llsStdIn: + if s.onPrompt!=nil: s.onPrompt() result = s.repl(s, buf, bufLen) proc llStreamReadLine*(s: PLLStream, line: var string): bool = diff --git a/compiler/main.nim b/compiler/main.nim index 73676ffd5..74c19bf10 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -138,7 +138,8 @@ proc commandInteractive(graph: ModuleGraph) = var m = graph.makeStdinModule() incl(m.flags, sfMainModule) var idgen = IdGenerator(module: m.itemId.module, item: m.itemId.item) - processModule(graph, m, idgen, llStreamOpenStdIn()) + let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config, stderr)) + processModule(graph, m, idgen, s) proc commandScan(cache: IdentCache, config: ConfigRef) = var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index d027ce960..6d6e21204 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -19,9 +19,9 @@ template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) template toStdOrrKind(stdOrr): untyped = if stdOrr == stdout: stdOrrStdout else: stdOrrStderr -template flushDot(conf, stdOrr) = +template flushDot*(conf, stdOrr) = ## safe to call multiple times - let stdOrrKind = stdOrr.toStdOrrKind() + let stdOrrKind = toStdOrrKind(stdOrr) if stdOrrKind in conf.lastMsgWasDot: conf.lastMsgWasDot.excl stdOrrKind write(stdOrr, "\n") From 6d442a40a6f89572052d61aeb73ec26d1f3451ce Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 28 Dec 2020 07:13:21 -0600 Subject: [PATCH 1709/4254] use doAssert in tests (#16486) --- tests/arc/tarcmisc.nim | 4 +- tests/arc/tasyncawait.nim | 2 +- tests/arc/tasyncleak2.nim | 2 +- tests/assign/tassign.nim | 4 +- tests/async/t12221.nim | 4 +- tests/async/tasync_gcsafe.nim | 2 +- tests/async/tasync_gcunsafe.nim | 2 +- tests/async/tasyncawait.nim | 2 +- tests/async/tasynceagain.nim | 4 +- tests/async/tasyncnetudp.nim | 4 +- tests/async/tasyncssl.nim | 4 +- tests/ccgbugs/t9286.nim | 4 +- tests/ccgbugs/twrong_tupleconv.nim | 2 +- tests/collections/tseq.nim | 2 +- tests/collections/ttables.nim | 94 ++++----- tests/collections/ttablesthreads.nim | 110 +++++----- tests/compiler/tbrees.nim | 14 +- tests/destructor/tcomplexobjconstr.nim | 16 +- tests/fields/tfielditerator.nim | 12 +- tests/generics/tgenerics_issues.nim | 8 +- tests/generics/tgenerics_various.nim | 38 ++-- tests/generics/tparser_generator.nim | 16 +- tests/lexer/tintegerliterals.nim | 14 +- tests/m14634.nim | 6 +- tests/metatype/twildtypedesc.nim | 10 +- tests/misc/tunsignedcomp.nim | 192 ++++++++--------- tests/newconfig/tfoo.nims | 44 ++-- tests/niminaction/Chapter3/various3.nim | 26 +-- tests/objvariant/tconstructionorder.nim | 20 +- tests/osproc/tclose.nim | 8 +- tests/parser/ttypeclasses.nim | 50 ++--- tests/pragmas/tbitsize.nim | 10 +- tests/pragmas/tcustom_pragma.nim | 60 +++--- tests/sets/tsets_various.nim | 122 +++++------ tests/statictypes/tstatictypes.nim | 18 +- tests/stdlib/t14139.nim | 2 +- tests/stdlib/talgorithm.nim | 30 +-- tests/stdlib/tcritbits.nim | 32 +-- tests/stdlib/tdeques.nim | 50 ++--- tests/stdlib/teditdistance.nim | 16 +- tests/stdlib/tenumerate.nim | 6 +- tests/stdlib/thtmlparser.nim | 2 +- tests/stdlib/thttpcore.nim | 30 +-- tests/stdlib/tlists.nim | 34 +-- tests/stdlib/tmath.nim | 38 ++-- tests/stdlib/tmd5.nim | 6 +- tests/stdlib/tos.nim | 16 +- tests/stdlib/tparsecfg.nim | 4 +- tests/stdlib/tparsopt.nim | 2 +- tests/stdlib/tpegs.nim | 2 +- tests/stdlib/tpunycode.nim | 6 +- tests/stdlib/trationals.nim | 126 ++++++------ tests/stdlib/trst.nim | 10 +- tests/stdlib/trstgen.nim | 152 +++++++------- tests/stdlib/tsequtils.nim | 166 +++++++-------- tests/stdlib/tsharedtable.nim | 6 +- tests/stdlib/tstrformat.nim | 4 +- tests/stdlib/tstrtabs.nim | 10 +- tests/stdlib/tstrutils.nim | 262 ++++++++++++------------ tests/stdlib/tsugar.nim | 24 +-- tests/stdlib/tsums.nim | 14 +- tests/stdlib/ttables.nim | 36 ++-- tests/stdlib/ttypeinfo.nim | 18 +- tests/stdlib/tunittest.nim | 2 +- tests/stdlib/txmltree.nim | 18 +- tests/types/tisop.nim | 10 +- tests/vm/tableinstatic.nim | 2 +- tests/vm/tissues.nim | 2 +- tests/vm/toverflowopcaddimmint.nim | 2 +- tests/vm/toverflowopcaddint.nim | 2 +- tests/vm/toverflowopcmulint.nim | 2 +- tests/vm/toverflowopcsubimmint.nim | 2 +- tests/vm/toverflowopcsubint.nim | 2 +- tests/vm/tstringnil.nim | 2 +- tests/vm/tvarsection.nim | 4 +- tests/vm/tvmmisc.nim | 24 +-- tests/vm/twrong_concat.nim | 2 +- tests/vm/twrongarray.nim | 2 +- 78 files changed, 1056 insertions(+), 1056 deletions(-) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 8d857921e..55803085f 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -135,8 +135,8 @@ let n = @["c", "b"] q = @[("c", "2"), ("b", "1")] -assert n.sortedByIt(it) == @["b", "c"], "fine" -assert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" +doAssert n.sortedByIt(it) == @["b", "c"], "fine" +doAssert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" #------------------------------------------------------------------------------ diff --git a/tests/arc/tasyncawait.nim b/tests/arc/tasyncawait.nim index f29b8d2b2..75d9bc9b5 100644 --- a/tests/arc/tasyncawait.nim +++ b/tests/arc/tasyncawait.nim @@ -62,7 +62,7 @@ proc main = let mem = getOccupiedMem() main() -assert msgCount == swarmSize * messagesToSend +doAssert msgCount == swarmSize * messagesToSend echo "result: ", msgCount GC_fullCollect() echo "memory: ", formatSize(getOccupiedMem() - mem) diff --git a/tests/arc/tasyncleak2.nim b/tests/arc/tasyncleak2.nim index 4d8486b3b..a8d71f1ee 100644 --- a/tests/arc/tasyncleak2.nim +++ b/tests/arc/tasyncleak2.nim @@ -84,5 +84,5 @@ proc main(): Future[void] = for i in 0..9: waitFor main() GC_fullCollect() - assert getOccupiedMem() < 1024 + doAssert getOccupiedMem() < 1024 echo "success" diff --git a/tests/assign/tassign.nim b/tests/assign/tassign.nim index 0589b0214..c95114015 100644 --- a/tests/assign/tassign.nim +++ b/tests/assign/tassign.nim @@ -93,9 +93,9 @@ block tgenericassign: var ret: seq[tuple[name: string, a: TAny]] = @[] for i in 0 .. 8000: var tup = ($name, newAny(nil, nil)) - assert(tup[0] == "example") + doAssert(tup[0] == "example") ret.add(tup) - assert(ret[ret.len()-1][0] == "example") + doAssert(ret[ret.len()-1][0] == "example") diff --git a/tests/async/t12221.nim b/tests/async/t12221.nim index 70e192356..e8bd9c11a 100644 --- a/tests/async/t12221.nim +++ b/tests/async/t12221.nim @@ -5,9 +5,9 @@ proc doubleSleep(hardSleep: int) {.async.} = sleep(hardSleep) template assertTime(target, timeTook: float): untyped {.dirty.} = - assert(timeTook*1000 > target - 1000, "Took too short, should've taken " & + doAssert(timeTook*1000 > target - 1000, "Took too short, should've taken " & $target & "ms, but took " & $(timeTook*1000) & "ms") - assert(timeTook*1000 < target + 1000, "Took too long, should've taken " & + doAssert(timeTook*1000 < target + 1000, "Took too long, should've taken " & $target & "ms, but took " & $(timeTook*1000) & "ms") var diff --git a/tests/async/tasync_gcsafe.nim b/tests/async/tasync_gcsafe.nim index 89df6456a..bc0eb4271 100644 --- a/tests/async/tasync_gcsafe.nim +++ b/tests/async/tasync_gcsafe.nim @@ -7,7 +7,7 @@ discard """ ''' """ -assert compileOption("threads"), "this test will not do anything useful without --threads:on" +doAssert compileOption("threads"), "this test will not do anything useful without --threads:on" import asyncdispatch diff --git a/tests/async/tasync_gcunsafe.nim b/tests/async/tasync_gcunsafe.nim index 55b66aaef..00c92b109 100644 --- a/tests/async/tasync_gcunsafe.nim +++ b/tests/async/tasync_gcunsafe.nim @@ -4,7 +4,7 @@ discard """ file: "asyncmacro.nim" """ -assert compileOption("threads"), "this test will not do anything useful without --threads:on" +doAssert compileOption("threads"), "this test will not do anything useful without --threads:on" import asyncdispatch diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index aec4ce523..f658a15ed 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -52,5 +52,5 @@ while true: poll() if clientCount == swarmSize: break -assert msgCount == swarmSize * messagesToSend +doAssert msgCount == swarmSize * messagesToSend doAssert msgCount == 2000 diff --git a/tests/async/tasynceagain.nim b/tests/async/tasynceagain.nim index aebd4ef16..94c3645dc 100644 --- a/tests/async/tasynceagain.nim +++ b/tests/async/tasynceagain.nim @@ -21,12 +21,12 @@ proc runServer() {.async.} = var lastN = 0 while true: let frame = await client.recv(FrameSize) - assert frame.len == FrameSize + doAssert frame.len == FrameSize let n = frame[0..<6].parseInt() echo "RCVD #", n, ": ", frame[0..80], "..." if n != lastN + 1: echo &"******** ERROR: Server received #{n}, but last was #{lastN}!" - assert n == lastN + 1 + doAssert n == lastN + 1 lastN = n await sleepAsync 100 diff --git a/tests/async/tasyncnetudp.nim b/tests/async/tasyncnetudp.nim index 3494def37..ef6dfc5e1 100644 --- a/tests/async/tasyncnetudp.nim +++ b/tests/async/tasyncnetudp.nim @@ -84,7 +84,7 @@ while true: if recvCount == swarmSize * messagesToSend: break -assert msgCount == swarmSize * messagesToSend -assert sendports == recvports +doAssert msgCount == swarmSize * messagesToSend +doAssert sendports == recvports echo msgCount \ No newline at end of file diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index c948ee9b7..a582818eb 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -69,5 +69,5 @@ when defined(ssl): elif defined(linux) and int.sizeof == 8: # currently: msgCount == 10 flakyAssert cond() - assert msgCount > 0 - else: assert cond(), $msgCount + doAssert msgCount > 0 + else: doAssert cond(), $msgCount diff --git a/tests/ccgbugs/t9286.nim b/tests/ccgbugs/t9286.nim index 8a45a7bf6..2fec23307 100644 --- a/tests/ccgbugs/t9286.nim +++ b/tests/ccgbugs/t9286.nim @@ -7,7 +7,7 @@ type Foo = ref object i: int proc next(foo: Foo): Option[Foo] = - try: assert(foo.i == 0) + try: doAssert(foo.i == 0) except: return # 2º: none return some(foo) # 1º: some @@ -17,6 +17,6 @@ proc test = while isSome(opt) and foo.i < 10: inc(foo.i) opt = next(foo) # 2º None - assert foo.i == 1, $foo.i + doAssert foo.i == 1, $foo.i test() diff --git a/tests/ccgbugs/twrong_tupleconv.nim b/tests/ccgbugs/twrong_tupleconv.nim index 7b1e58083..7a887d183 100644 --- a/tests/ccgbugs/twrong_tupleconv.nim +++ b/tests/ccgbugs/twrong_tupleconv.nim @@ -6,7 +6,7 @@ iterator myitems*[T](a: var seq[T]): var T {.inline.} = while i < L: yield a[i] inc(i) - assert(len(a) == L, "the length of the seq changed while iterating over it") + doAssert(len(a) == L, "the length of the seq changed while iterating over it") # Works fine var xs = @[1,2,3] diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim index 263a571bf..88d6dc79b 100644 --- a/tests/collections/tseq.nim +++ b/tests/collections/tseq.nim @@ -24,7 +24,7 @@ block tseq2: # multiply two int sequences: for i in 0..len(a)-1: result[i] = a[i] * b[i] - assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) + doAssert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 338a83fed..61197e9f0 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -50,20 +50,20 @@ block thashes: var t = initTable[int,int]() t[0] = 42 t[1] = t[0] + 1 - assert(t[0] == 42) - assert(t[1] == 43) + doAssert(t[0] == 42) + doAssert(t[1] == 43) let t2 = {1: 1, 2: 2}.toTable - assert(t2[2] == 2) + doAssert(t2[2] == 2) # Test with char block: var t = initTable[char,int]() t['0'] = 42 t['1'] = t['0'] + 1 - assert(t['0'] == 42) - assert(t['1'] == 43) + doAssert(t['0'] == 42) + doAssert(t['1'] == 43) let t2 = {'1': 1, '2': 2}.toTable - assert(t2['2'] == 2) + doAssert(t2['2'] == 2) # Test with enum block: @@ -72,10 +72,10 @@ block thashes: var t = initTable[E,int]() t[eA] = 42 t[eB] = t[eA] + 1 - assert(t[eA] == 42) - assert(t[eB] == 43) + doAssert(t[eA] == 42) + doAssert(t[eB] == 43) let t2 = {eA: 1, eB: 2}.toTable - assert(t2[eB] == 2) + doAssert(t2[eB] == 2) # Test with range block: @@ -84,10 +84,10 @@ block thashes: var t = initTable[R,int]() # causes warning, why? t[1] = 42 # causes warning, why? t[2] = t[1] + 1 - assert(t[1] == 42) - assert(t[2] == 43) + doAssert(t[1] == 42) + doAssert(t[2] == 43) let t2 = {1.R: 1, 2.R: 2}.toTable - assert(t2[2.R] == 2) + doAssert(t2[2.R] == 2) # Test which combines the generics for tuples + ordinals block: @@ -96,10 +96,10 @@ block thashes: var t = initTable[(string, E, int, char), int]() t[("a", eA, 0, '0')] = 42 t[("b", eB, 1, '1')] = t[("a", eA, 0, '0')] + 1 - assert(t[("a", eA, 0, '0')] == 42) - assert(t[("b", eB, 1, '1')] == 43) + doAssert(t[("a", eA, 0, '0')] == 42) + doAssert(t[("b", eB, 1, '1')] == 43) let t2 = {("a", eA, 0, '0'): 1, ("b", eB, 1, '1'): 2}.toTable - assert(t2[("b", eB, 1, '1')] == 2) + doAssert(t2[("b", eB, 1, '1')] == 2) # Test to check if overloading is possible # Unfortunately, this does not seem to work for int @@ -165,9 +165,9 @@ block tableconstr: ignoreExpr({2: 3, "key": "value"}) # NEW: - assert 56 in 50..100 + doAssert 56 in 50..100 - assert 56 in ..60 + doAssert 56 in ..60 block ttables2: @@ -239,8 +239,8 @@ block tablesref: t[(1,1)] = "11" for x in 0..1: for y in 0..1: - assert t[(x,y)] == $x & $y - assert t.sortedPairs == + doAssert t[(x,y)] == $x & $y + doAssert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")] block tableTest2: @@ -253,31 +253,31 @@ block tablesref: t["012"] = 67.9 t["123"] = 1.5 # test overwriting - assert t["123"] == 1.5 + doAssert t["123"] == 1.5 try: echo t["111"] # deleted except KeyError: discard - assert(not hasKey(t, "111")) - assert "111" notin t + doAssert(not hasKey(t, "111")) + doAssert "111" notin t for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): assert t[key] == val.toFloat + for key, val in items(data): doAssert t[key] == val.toFloat block orderedTableTest1: var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): assert t[key] == val + for key, val in items(data): doAssert t[key] == val var i = 0 # `pairs` needs to yield in insertion order: for key, val in pairs(t): - assert key == data[i][0] - assert val == data[i][1] + doAssert key == data[i][0] + doAssert val == data[i][1] inc(i) for key, val in mpairs(t): val = 99 - for val in mvalues(t): assert val == 99 + for val in mvalues(t): doAssert val == 99 block countTableTest1: var s = data.toTable @@ -286,11 +286,11 @@ block tablesref: for x in [t, r]: for k in s.keys: x.inc(k) - assert x[k] == 1 + doAssert x[k] == 1 x.inc("90", 3) x.inc("12", 2) x.inc("34", 1) - assert t.largest()[0] == "90" + doAssert t.largest()[0] == "90" t.sort() r.sort(SortOrder.Ascending) @@ -301,9 +301,9 @@ block tablesref: var i = 0 for (k, v) in ps: case i - of 0: assert k == "90" and v == 4 - of 1: assert k == "12" and v == 3 - of 2: assert k == "34" and v == 2 + of 0: doAssert k == "90" and v == 4 + of 1: doAssert k == "12" and v == 3 + of 2: doAssert k == "34" and v == 2 else: break inc i @@ -327,17 +327,17 @@ block tablesref: block nilTest: var i, j: TableRef[int, int] = nil - assert i == j + doAssert i == j j = newTable[int, int]() - assert i != j - assert j != i + doAssert i != j + doAssert j != i i = newTable[int, int]() - assert i == j + doAssert i == j proc orderedTableSortTest() = var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): assert t[key] == val + for key, val in items(data): doAssert t[key] == val proc cmper(x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key) t.sort(cmper) var i = 0 @@ -369,25 +369,25 @@ block tablesref: t["test"] = 1.2345 t["111"] = 1.000043 t["123"] = 1.23 - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearOrderedTableTest: var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearCountTableTest: var t = newCountTable[string]() t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 orderedTableSortTest() echo "3" @@ -415,7 +415,7 @@ block: # https://github.com/nim-lang/Nim/issues/13496 doAssert sortedPairs(t) == @[(15, 1), (17, 3), (19, 2)] var s = newSeq[int]() for v in t.values: s.add(v) - assert s.len == 3 + doAssert s.len == 3 doAssert sortedItems(s) == @[1, 2, 3] when t is OrderedTable|OrderedTableRef: doAssert toSeq(t.keys) == @[15, 19, 17] @@ -433,14 +433,14 @@ block: # https://github.com/nim-lang/Nim/issues/13496 block testNonPowerOf2: var a = initTable[int, int](7) a[1] = 10 - assert a[1] == 10 + doAssert a[1] == 10 var b = initTable[int, int](9) b[1] = 10 - assert b[1] == 10 + doAssert b[1] == 10 block emptyOrdered: var t1: OrderedTable[int, string] var t2: OrderedTable[int, string] - assert t1 == t2 + doAssert t1 == t2 diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim index 9f7d77719..2a4e1bf42 100644 --- a/tests/collections/ttablesthreads.nim +++ b/tests/collections/ttablesthreads.nim @@ -48,8 +48,8 @@ block tableTest1: t[(1,1)] = "11" for x in 0..1: for y in 0..1: - assert t[(x,y)] == $x & $y - assert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")] + doAssert t[(x,y)] == $x & $y + doAssert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")] block tableTest2: var t = initTable[string, float]() @@ -61,74 +61,74 @@ block tableTest2: t["012"] = 67.9 t["123"] = 1.5 # test overwriting - assert t["123"] == 1.5 + doAssert t["123"] == 1.5 try: echo t["111"] # deleted except KeyError: discard - assert(not hasKey(t, "111")) + doAssert(not hasKey(t, "111")) - assert "123" in t - assert("111" notin t) + doAssert "123" in t + doAssert("111" notin t) for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): assert t[key] == val.toFloat + for key, val in items(data): doAssert t[key] == val.toFloat - assert(not t.hasKeyOrPut("456", 4.0)) # test absent key - assert t.hasKeyOrPut("012", 3.0) # test present key + doAssert(not t.hasKeyOrPut("456", 4.0)) # test absent key + doAssert t.hasKeyOrPut("012", 3.0) # test present key var x = t.mgetOrPut("111", 1.5) # test absent key x = x * 2 - assert x == 3.0 + doAssert x == 3.0 x = t.mgetOrPut("test", 1.5) # test present key x = x * 2 - assert x == 2 * 1.2345 + doAssert x == 2 * 1.2345 block orderedTableTest1: var t = initOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): assert t[key] == val + for key, val in items(data): doAssert t[key] == val var i = 0 # `pairs` needs to yield in insertion order: for key, val in pairs(t): - assert key == data[i][0] - assert val == data[i][1] + doAssert key == data[i][0] + doAssert val == data[i][1] inc(i) for key, val in mpairs(t): val = 99 - for val in mvalues(t): assert val == 99 + for val in mvalues(t): doAssert val == 99 block orderedTableTest2: var s = initOrderedTable[string, int]() t = initOrderedTable[string, int]() - assert s == t + doAssert s == t for key, val in items(data): t[key] = val - assert s != t + doAssert s != t for key, val in items(sorteddata): s[key] = val - assert s != t + doAssert s != t t.clear() - assert s != t + doAssert s != t for key, val in items(sorteddata): t[key] = val - assert s == t + doAssert s == t block countTableTest1: var s = data.toTable var t = initCountTable[string]() for k in s.keys: t.inc(k) - for k in t.keys: assert t[k] == 1 + for k in t.keys: doAssert t[k] == 1 t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - assert t.largest()[0] == "90" + doAssert t.largest()[0] == "90" t.sort() var i = 0 for k, v in t.pairs: case i - of 0: assert k == "90" and v == 4 - of 1: assert k == "12" and v == 3 - of 2: assert k == "34" and v == 2 + of 0: doAssert k == "90" and v == 4 + of 1: doAssert k == "12" and v == 3 + of 2: doAssert k == "34" and v == 2 else: break inc i @@ -136,19 +136,19 @@ block countTableTest2: var s = initCountTable[int]() t = initCountTable[int]() - assert s == t + doAssert s == t s.inc(1) - assert s != t + doAssert s != t t.inc(2) - assert s != t + doAssert s != t t.inc(1) - assert s != t + doAssert s != t s.inc(2) - assert s == t + doAssert s == t s.inc(1) - assert s != t + doAssert s != t t.inc(1) - assert s == t + doAssert s == t block mpairsTableTest1: var t = initTable[string, int]() @@ -162,9 +162,9 @@ block mpairsTableTest1: for k, v in t.pairs: if k == "a" or k == "c": - assert v == 9 + doAssert v == 9 else: - assert v != 1 and v != 3 + doAssert v != 1 and v != 3 block SyntaxTest: var x = toTable[int, string]({:}) @@ -174,10 +174,10 @@ block zeroHashKeysTest: let initialLen = t.len var testTable = t testTable[nullHashKey] = value - assert testTable[nullHashKey] == value - assert testTable.len == initialLen + 1 + doAssert testTable[nullHashKey] == value + doAssert testTable.len == initialLen + 1 testTable.del(nullHashKey) - assert testTable.len == initialLen + doAssert testTable.len == initialLen # with empty table doZeroHashValueTest(toTable[int,int]({:}), 0, 42) @@ -194,46 +194,46 @@ block zeroHashKeysTest: block clearTableTest: var t = data.toTable - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearOrderedTableTest: var t = data.toOrderedTable - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearCountTableTest: var t = initCountTable[string]() t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block withKeyTest: var t: SharedTable[int, int] t.init() t.withKey(1) do (k: int, v: var int, pairExists: var bool): - assert(v == 0) + doAssert(v == 0) pairExists = true v = 42 - assert(t.mget(1) == 42) + doAssert(t.mget(1) == 42) t.withKey(1) do (k: int, v: var int, pairExists: var bool): - assert(v == 42) + doAssert(v == 42) pairExists = false try: discard t.mget(1) - assert(false, "KeyError expected") + doAssert(false, "KeyError expected") except KeyError: discard t.withKey(2) do (k: int, v: var int, pairExists: var bool): pairExists = false try: discard t.mget(2) - assert(false, "KeyError expected") + doAssert(false, "KeyError expected") except KeyError: discard @@ -242,20 +242,20 @@ block takeTest: t["key"] = 123 var val = 0 - assert(t.take("key", val)) - assert(val == 123) + doAssert(t.take("key", val)) + doAssert(val == 123) val = -1 - assert(not t.take("key", val)) - assert(val == -1) + doAssert(not t.take("key", val)) + doAssert(val == -1) - assert(not t.take("otherkey", val)) - assert(val == -1) + doAssert(not t.take("otherkey", val)) + doAssert(val == -1) proc orderedTableSortTest() = var t = initOrderedTable[string, int](2) for key, val in items(data): t[key] = val - for key, val in items(data): assert t[key] == val + for key, val in items(data): doAssert t[key] == val t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key)) var i = 0 # `pairs` needs to yield in sorted order: diff --git a/tests/compiler/tbrees.nim b/tests/compiler/tbrees.nim index 364b51b22..5f6482ed9 100644 --- a/tests/compiler/tbrees.nim +++ b/tests/compiler/tbrees.nim @@ -42,14 +42,14 @@ proc main = st.add("www.weather.com", "63.111.66.11") st.add("www.yahoo.com", "216.109.118.65") - assert st.getOrDefault("www.cs.princeton.edu") == "abc" - assert st.getOrDefault("www.harvardsucks.com") == "" + doAssert st.getOrDefault("www.cs.princeton.edu") == "abc" + doAssert st.getOrDefault("www.harvardsucks.com") == "" - assert st.getOrDefault("www.simpsons.com") == "209.052.165.60" - assert st.getOrDefault("www.apple.com") == "17.112.152.32" - assert st.getOrDefault("www.ebay.com") == "66.135.192.87" - assert st.getOrDefault("www.dell.com") == "143.166.224.230" - assert(st.len == 16) + doAssert st.getOrDefault("www.simpsons.com") == "209.052.165.60" + doAssert st.getOrDefault("www.apple.com") == "17.112.152.32" + doAssert st.getOrDefault("www.ebay.com") == "66.135.192.87" + doAssert st.getOrDefault("www.dell.com") == "143.166.224.230" + doAssert(st.len == 16) for k, v in st: echo k, ": ", v diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim index fd112b6e2..aea0ad1fe 100644 --- a/tests/destructor/tcomplexobjconstr.nim +++ b/tests/destructor/tcomplexobjconstr.nim @@ -20,16 +20,16 @@ type of true: y*: float var x = new(MyObject2) -assert x of MyObject2 -assert x.subobj of MyObject1 -assert x.more[2] of MyObject1 -assert x.more[2] of RootObj +doAssert x of MyObject2 +doAssert x.subobj of MyObject1 +doAssert x.more[2] of MyObject1 +doAssert x.more[2] of RootObj var y: MyObject2 -assert y of MyObject2 -assert y.subobj of MyObject1 -assert y.more[2] of MyObject1 -assert y.more[2] of RootObj +doAssert y of MyObject2 +doAssert y.subobj of MyObject1 +doAssert y.more[2] of MyObject1 +doAssert y.more[2] of RootObj echo "true" diff --git a/tests/fields/tfielditerator.nim b/tests/fields/tfielditerator.nim index 877e4454c..d1fbf02f9 100644 --- a/tests/fields/tfielditerator.nim +++ b/tests/fields/tfielditerator.nim @@ -60,12 +60,12 @@ block titerator1: for key, val in fieldPairs(x): echo key, ": ", val - assert x != y - assert x == x - assert(not (x < x)) - assert x <= x - assert y < x - assert y <= x + doAssert x != y + doAssert x == x + doAssert(not (x < x)) + doAssert x <= x + doAssert y < x + doAssert y <= x block titerator2: diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 812f339b9..365afd407 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -55,8 +55,8 @@ block t88: let c = ChildClass[string].new("Base", "Child") - assert c.baseMethod == "Base" - assert c.overriddenMethod == "Child" + doAssert c.baseMethod == "Base" + doAssert c.overriddenMethod == "Child" @@ -128,7 +128,7 @@ block t1789: bar: array[N, T] proc `[]`[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T = - assert high(n) == N-1 + doAssert high(n) == N-1 result = f.bar[n] var b: Bar[3, int] @@ -734,7 +734,7 @@ block t1684: proc newDerived(idx: int): DerivedType {.inline.} = DerivedType(idx: idx) let d = newDerived(2) - assert(d.index == 2) + doAssert(d.index == 2) diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim index 22d3cff7a..285108cd3 100644 --- a/tests/generics/tgenerics_various.nim +++ b/tests/generics/tgenerics_various.nim @@ -58,23 +58,23 @@ block tgenericdefaults: var x1: TFoo[int, float] static: - assert type(x1.x) is int - assert type(x1.y) is float - assert type(x1.z) is int + doAssert type(x1.x) is int + doAssert type(x1.y) is float + doAssert type(x1.z) is int var x2: TFoo[string, R = float, U = seq[int]] static: - assert type(x2.x) is string - assert type(x2.y) is seq[int] - assert type(x2.z) is float + doAssert type(x2.x) is string + doAssert type(x2.y) is seq[int] + doAssert type(x2.z) is float var x3: TBar[float] static: - assert type(x3.x) is float - assert type(x3.y) is array[4, float] - assert type(x3.z) is float + doAssert type(x3.x) is float + doAssert type(x3.y) is array[4, float] + doAssert type(x3.z) is float @@ -150,31 +150,31 @@ block tsharedcases: doAssert high(f2.data2) == 3 # int8.len - 1 == 3 static: - assert high(f1.data1) == ord(C) - assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high + doAssert high(f1.data1) == ord(C) + doAssert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high - assert high(f2.data1) == 126 - assert high(f2.data2) == 3 + doAssert high(f2.data1) == 126 + doAssert high(f2.data2) == 3 - assert high(f1.data3) == 6 # length of MyEnum - assert high(f2.data3) == 4 # length of int8 + doAssert high(f1.data3) == 6 # length of MyEnum + doAssert high(f2.data3) == 4 # length of int8 - assert f2.data3[0] is float + doAssert f2.data3[0] is float block tmap_auto: let x = map(@[1, 2, 3], x => x+10) - assert x == @[11, 12, 13] + doAssert x == @[11, 12, 13] let y = map(@[(1,"a"), (2,"b"), (3,"c")], x => $x[0] & x[1]) - assert y == @["1a", "2b", "3c"] + doAssert y == @["1a", "2b", "3c"] proc eatsTwoArgProc[T,S,U](a: T, b: S, f: proc(t: T, s: S): U): U = f(a,b) let z = eatsTwoArgProc(1, "a", (t,s) => $t & s) - assert z == "1a" + doAssert z == "1a" diff --git a/tests/generics/tparser_generator.nim b/tests/generics/tparser_generator.nim index 8f8fea382..ac921c0e5 100644 --- a/tests/generics/tparser_generator.nim +++ b/tests/generics/tparser_generator.nim @@ -147,7 +147,7 @@ proc literal*[N, T, P](pattern: P, kind: N): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = if start == len(text): return -1 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) when P is string or P is seq[N]: debug(debugLex, "Literal[" & $kind & "]: testing " & $pattern & " at " & $start & ": " & $text[start..start+len(pattern)-1]) if text.continuesWith(pattern, start): @@ -177,7 +177,7 @@ proc token[N, T](pattern: T, kind: N): Rule[N, T] = debug(debugLex, "Token[" & $kind & "]: testing " & pattern & " at " & $start) if start == len(text): return -1 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) let m = text.match(re(pattern), start) if m.isSome: let node = initNode(start, len(m.get.match), kind) @@ -192,7 +192,7 @@ proc chartest[N, T, S](testfunc: proc(s: S): bool, kind: N): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = if start == len(text): return -1 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) if testfunc(text[start]): nodes.add(initNode(start, 1, kind)) result = 1 @@ -252,11 +252,11 @@ proc fail*[N, T](message: string, kind: N): Rule[N, T] = proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = var mynodes = newSeq[Node[N]]() - assert(not isNil(left.parser), "Left hand side parser is nil") + doAssert(not isNil(left.parser), "Left hand side parser is nil") let leftlength = left.parser(text, start, mynodes) if leftlength == -1: return leftlength - assert(not isNil(right.parser), "Right hand side parser is nil") + doAssert(not isNil(right.parser), "Right hand side parser is nil") let rightlength = right.parser(text, start+leftlength, mynodes) if rightlength == -1: return rightlength @@ -267,13 +267,13 @@ proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = proc `/`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = var mynodes = newSeq[Node[N]]() - assert(not isNil(left.parser), "Left hand side of / is not fully defined") + doAssert(not isNil(left.parser), "Left hand side of / is not fully defined") let leftlength = left.parser(text, start, mynodes) if leftlength != -1: nodes.add(mynodes) return leftlength mynodes = newSeq[Node[N]]() - assert(not isNil(right.parser), "Right hand side of / is not fully defined") + doAssert(not isNil(right.parser), "Right hand side of / is not fully defined") let rightlength = right.parser(text, start, mynodes) if rightlength == -1: return rightlength @@ -360,7 +360,7 @@ proc `/`*[N, T](rule: Rule[N, T]): Rule[N, T] = result = newRule[N, T](parser, rule.kind) proc `->`*(rule: Rule, production: Rule) = - assert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") + doAssert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") rule.parser = production.parser template grammar*[K](Kind, Text, Symbol: typedesc; default: K, code: untyped): typed {.hint[XDeclaredButNotUsed]: off.} = diff --git a/tests/lexer/tintegerliterals.nim b/tests/lexer/tintegerliterals.nim index 7420db144..fd401b71b 100644 --- a/tests/lexer/tintegerliterals.nim +++ b/tests/lexer/tintegerliterals.nim @@ -1,9 +1,9 @@ # test the valid literals -assert 0b10 == 2 -assert 0B10 == 2 -assert 0x10 == 16 -assert 0X10 == 16 -assert 0o10 == 8 +doAssert 0b10 == 2 +doAssert 0B10 == 2 +doAssert 0x10 == 16 +doAssert 0X10 == 16 +doAssert 0o10 == 8 # the following is deprecated: -assert 0c10 == 8 -assert 0C10 == 8 +doAssert 0c10 == 8 +doAssert 0C10 == 8 diff --git a/tests/m14634.nim b/tests/m14634.nim index 56a3d9034..f19f02f0c 100644 --- a/tests/m14634.nim +++ b/tests/m14634.nim @@ -20,7 +20,7 @@ when not defined(windows): # the test fails. var rc1 = selector.select(t) var rc2 = selector.select(t) - assert len(rc1) <= 1 and len(rc2) <= 1 + doAssert len(rc1) <= 1 and len(rc2) <= 1 data.s1 += ord(len(rc1) == 1) data.s2 += ord(len(rc2) == 1) selector.unregister(timer) @@ -32,9 +32,9 @@ when not defined(windows): # this can't be too large as it'll actually wait that long: # timer_notification_test.n * t2 var rc5 = selector.select(t2) - assert len(rc4) + len(rc5) <= 1 + doAssert len(rc4) + len(rc5) <= 1 data.s3 += ord(len(rc4) + len(rc5) == 1) - assert(selector.isEmpty()) + doAssert(selector.isEmpty()) selector.close() proc timerNotificationTest() = diff --git a/tests/metatype/twildtypedesc.nim b/tests/metatype/twildtypedesc.nim index 268bff0d8..d1c5ffba5 100644 --- a/tests/metatype/twildtypedesc.nim +++ b/tests/metatype/twildtypedesc.nim @@ -17,8 +17,8 @@ proc unpack[T](v: string): T = var s = "123" -assert(unpack[string](s) is string) -assert(unpack[int](s) is int) +doAssert(unpack[string](s) is string) +doAssert(unpack[int](s) is int) echo unpack[int](s) echo unpack[string](s) @@ -37,7 +37,7 @@ proc unit(t: typedesc[int]): t = 0 proc unit(t: typedesc[string]): t = "" proc unit(t: typedesc[float]): t = 0.0 -assert unit(int) == 0 -assert unit(string) == "" -assert unit(float) == 0.0 +doAssert unit(int) == 0 +doAssert unit(string) == "" +doAssert unit(float) == 0.0 diff --git a/tests/misc/tunsignedcomp.nim b/tests/misc/tunsignedcomp.nim index 19c8876b1..970c4ae9d 100644 --- a/tests/misc/tunsignedcomp.nim +++ b/tests/misc/tunsignedcomp.nim @@ -10,127 +10,127 @@ discard """ # unsigned < signed -assert 10'u8 < 20'i8 -assert 10'u8 < 20'i16 -assert 10'u8 < 20'i32 -assert 10'u8 < 20'i64 +doAssert 10'u8 < 20'i8 +doAssert 10'u8 < 20'i16 +doAssert 10'u8 < 20'i32 +doAssert 10'u8 < 20'i64 -assert 10'u16 < 20'i8 -assert 10'u16 < 20'i16 -assert 10'u16 < 20'i32 -assert 10'u16 < 20'i64 +doAssert 10'u16 < 20'i8 +doAssert 10'u16 < 20'i16 +doAssert 10'u16 < 20'i32 +doAssert 10'u16 < 20'i64 -assert 10'u32 < 20'i8 -assert 10'u32 < 20'i16 -assert 10'u32 < 20'i32 -assert 10'u32 < 20'i64 +doAssert 10'u32 < 20'i8 +doAssert 10'u32 < 20'i16 +doAssert 10'u32 < 20'i32 +doAssert 10'u32 < 20'i64 -# assert 10'u64 < 20'i8 -# assert 10'u64 < 20'i16 -# assert 10'u64 < 20'i32 -# assert 10'u64 < 20'i64 +# doAssert 10'u64 < 20'i8 +# doAssert 10'u64 < 20'i16 +# doAssert 10'u64 < 20'i32 +# doAssert 10'u64 < 20'i64 # signed < unsigned -assert 10'i8 < 20'u8 -assert 10'i8 < 20'u16 -assert 10'i8 < 20'u32 -# assert 10'i8 < 20'u64 +doAssert 10'i8 < 20'u8 +doAssert 10'i8 < 20'u16 +doAssert 10'i8 < 20'u32 +# doAssert 10'i8 < 20'u64 -assert 10'i16 < 20'u8 -assert 10'i16 < 20'u16 -assert 10'i16 < 20'u32 -# assert 10'i16 < 20'u64 +doAssert 10'i16 < 20'u8 +doAssert 10'i16 < 20'u16 +doAssert 10'i16 < 20'u32 +# doAssert 10'i16 < 20'u64 -assert 10'i32 < 20'u8 -assert 10'i32 < 20'u16 -assert 10'i32 < 20'u32 -# assert 10'i32 < 20'u64 +doAssert 10'i32 < 20'u8 +doAssert 10'i32 < 20'u16 +doAssert 10'i32 < 20'u32 +# doAssert 10'i32 < 20'u64 -assert 10'i64 < 20'u8 -assert 10'i64 < 20'u16 -assert 10'i64 < 20'u32 -# assert 10'i64 < 20'u64 +doAssert 10'i64 < 20'u8 +doAssert 10'i64 < 20'u16 +doAssert 10'i64 < 20'u32 +# doAssert 10'i64 < 20'u64 # unsigned <= signed -assert 10'u8 <= 20'i8 -assert 10'u8 <= 20'i16 -assert 10'u8 <= 20'i32 -assert 10'u8 <= 20'i64 +doAssert 10'u8 <= 20'i8 +doAssert 10'u8 <= 20'i16 +doAssert 10'u8 <= 20'i32 +doAssert 10'u8 <= 20'i64 -assert 10'u16 <= 20'i8 -assert 10'u16 <= 20'i16 -assert 10'u16 <= 20'i32 -assert 10'u16 <= 20'i64 +doAssert 10'u16 <= 20'i8 +doAssert 10'u16 <= 20'i16 +doAssert 10'u16 <= 20'i32 +doAssert 10'u16 <= 20'i64 -assert 10'u32 <= 20'i8 -assert 10'u32 <= 20'i16 -assert 10'u32 <= 20'i32 -assert 10'u32 <= 20'i64 +doAssert 10'u32 <= 20'i8 +doAssert 10'u32 <= 20'i16 +doAssert 10'u32 <= 20'i32 +doAssert 10'u32 <= 20'i64 -# assert 10'u64 <= 20'i8 -# assert 10'u64 <= 20'i16 -# assert 10'u64 <= 20'i32 -# assert 10'u64 <= 20'i64 +# doAssert 10'u64 <= 20'i8 +# doAssert 10'u64 <= 20'i16 +# doAssert 10'u64 <= 20'i32 +# doAssert 10'u64 <= 20'i64 # signed <= unsigned -assert 10'i8 <= 20'u8 -assert 10'i8 <= 20'u16 -assert 10'i8 <= 20'u32 -# assert 10'i8 <= 20'u64 +doAssert 10'i8 <= 20'u8 +doAssert 10'i8 <= 20'u16 +doAssert 10'i8 <= 20'u32 +# doAssert 10'i8 <= 20'u64 -assert 10'i16 <= 20'u8 -assert 10'i16 <= 20'u16 -assert 10'i16 <= 20'u32 -# assert 10'i16 <= 20'u64 +doAssert 10'i16 <= 20'u8 +doAssert 10'i16 <= 20'u16 +doAssert 10'i16 <= 20'u32 +# doAssert 10'i16 <= 20'u64 -assert 10'i32 <= 20'u8 -assert 10'i32 <= 20'u16 -assert 10'i32 <= 20'u32 -# assert 10'i32 <= 20'u64 +doAssert 10'i32 <= 20'u8 +doAssert 10'i32 <= 20'u16 +doAssert 10'i32 <= 20'u32 +# doAssert 10'i32 <= 20'u64 -assert 10'i64 <= 20'u8 -assert 10'i64 <= 20'u16 -assert 10'i64 <= 20'u32 -# assert 10'i64 <= 20'u64 +doAssert 10'i64 <= 20'u8 +doAssert 10'i64 <= 20'u16 +doAssert 10'i64 <= 20'u32 +# doAssert 10'i64 <= 20'u64 # signed == unsigned -assert 10'i8 == 10'u8 -assert 10'i8 == 10'u16 -assert 10'i8 == 10'u32 -# assert 10'i8 == 10'u64 +doAssert 10'i8 == 10'u8 +doAssert 10'i8 == 10'u16 +doAssert 10'i8 == 10'u32 +# doAssert 10'i8 == 10'u64 -assert 10'i16 == 10'u8 -assert 10'i16 == 10'u16 -assert 10'i16 == 10'u32 -# assert 10'i16 == 10'u64 +doAssert 10'i16 == 10'u8 +doAssert 10'i16 == 10'u16 +doAssert 10'i16 == 10'u32 +# doAssert 10'i16 == 10'u64 -assert 10'i32 == 10'u8 -assert 10'i32 == 10'u16 -assert 10'i32 == 10'u32 -# assert 10'i32 == 10'u64 +doAssert 10'i32 == 10'u8 +doAssert 10'i32 == 10'u16 +doAssert 10'i32 == 10'u32 +# doAssert 10'i32 == 10'u64 -assert 10'i64 == 10'u8 -assert 10'i64 == 10'u16 -assert 10'i64 == 10'u32 -# assert 10'i64 == 10'u64 +doAssert 10'i64 == 10'u8 +doAssert 10'i64 == 10'u16 +doAssert 10'i64 == 10'u32 +# doAssert 10'i64 == 10'u64 # unsigned == signed -assert 10'u8 == 10'i8 -assert 10'u8 == 10'i16 -assert 10'u8 == 10'i32 -# assert 10'u8 == 10'i64 +doAssert 10'u8 == 10'i8 +doAssert 10'u8 == 10'i16 +doAssert 10'u8 == 10'i32 +# doAssert 10'u8 == 10'i64 -assert 10'u16 == 10'i8 -assert 10'u16 == 10'i16 -assert 10'u16 == 10'i32 -# assert 10'u16 == 10'i64 +doAssert 10'u16 == 10'i8 +doAssert 10'u16 == 10'i16 +doAssert 10'u16 == 10'i32 +# doAssert 10'u16 == 10'i64 -assert 10'u32 == 10'i8 -assert 10'u32 == 10'i16 -assert 10'u32 == 10'i32 -# assert 10'u32 == 10'i64 +doAssert 10'u32 == 10'i8 +doAssert 10'u32 == 10'i16 +doAssert 10'u32 == 10'i32 +# doAssert 10'u32 == 10'i64 -# assert 10'u64 == 10'i8 -# assert 10'u64 == 10'i16 -# assert 10'u64 == 10'i32 -# assert 10'u64 == 10'i64 +# doAssert 10'u64 == 10'i8 +# doAssert 10'u64 == 10'i16 +# doAssert 10'u64 == 10'i32 +# doAssert 10'u64 == 10'i64 diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index a53e777d4..6f0048afb 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -51,56 +51,56 @@ doAssert(existsEnv("dummy") == false) # issue #7393 let wd = getCurrentDir() cd("..") -assert wd != getCurrentDir() +doAssert wd != getCurrentDir() cd(wd) -assert wd == getCurrentDir() +doAssert wd == getCurrentDir() when false: # this doesn't work in a 'koch testintall' environment - assert findExe("nim") != "" + doAssert findExe("nim") != "" # general tests mode = ScriptMode.Verbose -assert getCommand() == "c" +doAssert getCommand() == "c" setCommand("cpp") -assert getCommand() == "cpp" +doAssert getCommand() == "cpp" setCommand("c") -assert cmpic("HeLLO", "hello") == 0 +doAssert cmpic("HeLLO", "hello") == 0 -assert fileExists("tests/newconfig/tfoo.nims") == true -assert dirExists("tests") == true +doAssert fileExists("tests/newconfig/tfoo.nims") == true +doAssert dirExists("tests") == true -assert fileExists("tests/newconfig/tfoo.nims") == true -assert dirExists("tests") == true +doAssert fileExists("tests/newconfig/tfoo.nims") == true +doAssert dirExists("tests") == true discard selfExe() when defined(windows): - assert toExe("nim") == "nim.exe" - assert toDll("nim") == "nim.dll" + doAssert toExe("nim") == "nim.exe" + doAssert toDll("nim") == "nim.dll" else: - assert toExe("nim") == "nim" - assert toDll("nim") == "libnim.so" + doAssert toExe("nim") == "nim" + doAssert toDll("nim") == "libnim.so" rmDir("tempXYZ") doAssertRaises(OSError): rmDir("tempXYZ", checkDir = true) -assert dirExists("tempXYZ") == false +doAssert dirExists("tempXYZ") == false mkDir("tempXYZ") -assert dirExists("tempXYZ") == true -assert fileExists("tempXYZ/koch.nim") == false +doAssert dirExists("tempXYZ") == true +doAssert fileExists("tempXYZ/koch.nim") == false when false: # this doesn't work in a 'koch testintall' environment cpFile("koch.nim", "tempXYZ/koch.nim") - assert fileExists("tempXYZ/koch.nim") == true + doAssert fileExists("tempXYZ/koch.nim") == true cpDir("nimsuggest", "tempXYZ/.") - assert dirExists("tempXYZ/tests") == true - assert fileExists("tempXYZ/nimsuggest.nim") == true + doAssert dirExists("tempXYZ/tests") == true + doAssert fileExists("tempXYZ/nimsuggest.nim") == true rmFile("tempXYZ/koch.nim") - assert fileExists("tempXYZ/koch.nim") == false + doAssert fileExists("tempXYZ/koch.nim") == false rmDir("tempXYZ") -assert dirExists("tempXYZ") == false +doAssert dirExists("tempXYZ") == false diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim index 849ea71d8..4e028a048 100644 --- a/tests/niminaction/Chapter3/various3.nim +++ b/tests/niminaction/Chapter3/various3.nim @@ -7,7 +7,7 @@ Future is no longer empty, 42 import threadpool proc foo: string = "Dog" var x: FlowVar[string] = spawn foo() -assert(^x == "Dog") +doAssert(^x == "Dog") block: type @@ -19,20 +19,20 @@ block: discard var obj = Box(empty: false, contents: "Hello") - assert obj.contents == "Hello" + doAssert obj.contents == "Hello" var obj2 = Box(empty: true) doAssertRaises(FieldDefect): echo(obj2.contents) import json -assert parseJson("null").kind == JNull -assert parseJson("true").kind == JBool -assert parseJson("42").kind == JInt -assert parseJson("3.14").kind == JFloat -assert parseJson("\"Hi\"").kind == JString -assert parseJson("""{ "key": "value" }""").kind == JObject -assert parseJson("[1, 2, 3, 4]").kind == JArray +doAssert parseJson("null").kind == JNull +doAssert parseJson("true").kind == JBool +doAssert parseJson("42").kind == JInt +doAssert parseJson("3.14").kind == JFloat +doAssert parseJson("\"Hi\"").kind == JString +doAssert parseJson("""{ "key": "value" }""").kind == JObject +doAssert parseJson("[1, 2, 3, 4]").kind == JArray import json let data = """ @@ -40,15 +40,15 @@ let data = """ """ let obj = parseJson(data) -assert obj.kind == JObject -assert obj["username"].kind == JString -assert obj["username"].str == "Dominik" +doAssert obj.kind == JObject +doAssert obj["username"].kind == JString +doAssert obj["username"].str == "Dominik" block: proc count10(): int = for i in 0 ..< 10: result.inc - assert count10() == 10 + doAssert count10() == 10 type Point = tuple[x, y: int] diff --git a/tests/objvariant/tconstructionorder.nim b/tests/objvariant/tconstructionorder.nim index 19ddea7a1..5ca484884 100644 --- a/tests/objvariant/tconstructionorder.nim +++ b/tests/objvariant/tconstructionorder.nim @@ -23,22 +23,22 @@ type # This will test that all the values are what we expect. proc assertTree(root: Node) = # check root of tree - assert root.kind == Operator - assert root.operator == '*' + doAssert root.kind == Operator + doAssert root.operator == '*' # check left subtree - assert root.left.value == 5 - assert root.left.kind == Literal + doAssert root.left.value == 5 + doAssert root.left.kind == Literal # check right subtree - assert root.right.kind == Operator - assert root.right.operator == '+' + doAssert root.right.kind == Operator + doAssert root.right.operator == '+' - assert root.right.left.value == 5 - assert root.right.left.kind == Literal + doAssert root.right.left.value == 5 + doAssert root.right.left.kind == Literal - assert root.right.right.value == 10 - assert root.right.right.kind == Literal + doAssert root.right.right.value == 10 + doAssert root.right.right.kind == Literal proc newLiteralNode(value: int): Node = result = Node( diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim index d466b466a..1c99237c7 100644 --- a/tests/osproc/tclose.nim +++ b/tests/osproc/tclose.nim @@ -13,12 +13,12 @@ when defined(linux): let initCount = countFds() let p = osproc.startProcess("echo", options={poUsePath}) - assert countFds() == initCount + 3 + doAssert countFds() == initCount + 3 p.close - assert countFds() == initCount + doAssert countFds() == initCount let p1 = osproc.startProcess("echo", options={poUsePath}) discard p1.inputStream - assert countFds() == initCount + 3 + doAssert countFds() == initCount + 3 p.close - assert countFds() == initCount + doAssert countFds() == initCount diff --git a/tests/parser/ttypeclasses.nim b/tests/parser/ttypeclasses.nim index 06146dcb6..e6e7a48b8 100644 --- a/tests/parser/ttypeclasses.nim +++ b/tests/parser/ttypeclasses.nim @@ -16,31 +16,31 @@ var z: ptr int const C = @[1, 2, 3] static: - assert x is ref - assert y is distinct - assert z is ptr - assert C is static - assert C[1] is static[int] - assert C[0] is static[SomeInteger] - assert C isnot static[string] - assert C is SEQ|OBJ - assert C isnot OBJ|TPL - assert int is int - assert int is T - assert int is SomeInteger - assert seq[int] is type - assert seq[int] is type[seq] - assert seq[int] isnot type[seq[float]] - assert i isnot type[int] - assert type(i) is type[int] - assert x isnot T - assert y isnot S - assert z isnot enum - assert x isnot object - assert y isnot tuple - assert z isnot seq + doAssert x is ref + doAssert y is distinct + doAssert z is ptr + doAssert C is static + doAssert C[1] is static[int] + doAssert C[0] is static[SomeInteger] + doAssert C isnot static[string] + doAssert C is SEQ|OBJ + doAssert C isnot OBJ|TPL + doAssert int is int + doAssert int is T + doAssert int is SomeInteger + doAssert seq[int] is type + doAssert seq[int] is type[seq] + doAssert seq[int] isnot type[seq[float]] + doAssert i isnot type[int] + doAssert type(i) is type[int] + doAssert x isnot T + doAssert y isnot S + doAssert z isnot enum + doAssert x isnot object + doAssert y isnot tuple + doAssert z isnot seq # XXX: These cases don't work properly at the moment: - # assert type[int] isnot int - # assert type(int) isnot int + # doAssert type[int] isnot int + # doAssert type(int) isnot int diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim index 7a44944d2..39aee445f 100644 --- a/tests/pragmas/tbitsize.nim +++ b/tests/pragmas/tbitsize.nim @@ -10,13 +10,13 @@ type var b: bits -assert b.flag == 0 +doAssert b.flag == 0 b.flag = 1 -assert b.flag == 1 +doAssert b.flag == 1 b.flag = 2 -assert b.flag == 0 +doAssert b.flag == 0 b.opts = 7 -assert b.opts == 7 +doAssert b.opts == 7 b.opts = 9 -assert b.opts == -7 +doAssert b.opts == -7 diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index a4a200c34..e9dac753d 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -8,7 +8,7 @@ block: proc myProc():int {.myAttr.} = 2 const hasMyAttr = myProc.hasCustomPragma(myAttr) static: - assert(hasMyAttr) + doAssert(hasMyAttr) block: template myAttr(a: string) {.pragma.} @@ -19,8 +19,8 @@ block: var o: MyObj static: - assert o.myField2.hasCustomPragma(myAttr) - assert(not o.myField1.hasCustomPragma(myAttr)) + doAssert o.myField2.hasCustomPragma(myAttr) + doAssert(not o.myField1.hasCustomPragma(myAttr)) import custom_pragma block: # A bit more advanced case @@ -42,31 +42,31 @@ block: # A bit more advanced case var s: MySerializable const aDefVal = s.a.getCustomPragmaVal(defaultValue) - static: assert(aDefVal == 5) + static: doAssert(aDefVal == 5) const aSerKey = s.a.getCustomPragmaVal(serializationKey) - static: assert(aSerKey == "asdf") + static: doAssert(aSerKey == "asdf") const cSerKey = getCustomPragmaVal(s.field.c, serializationKey) - static: assert(cSerKey == "cc") + static: doAssert(cSerKey == "cc") const procSerKey = getCustomPragmaVal(myproc, serializationKey) - static: assert(procSerKey == "myprocSS") + static: doAssert(procSerKey == "myprocSS") - static: assert(hasCustomPragma(myproc, alternativeKey)) + static: doAssert(hasCustomPragma(myproc, alternativeKey)) const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue) - static: assert(hasFieldCustomPragma == false) + static: doAssert(hasFieldCustomPragma == false) # pragma on an object static: - assert Subfield.hasCustomPragma(defaultValue) - assert(Subfield.getCustomPragmaVal(defaultValue) == "catman") + doAssert Subfield.hasCustomPragma(defaultValue) + doAssert(Subfield.getCustomPragmaVal(defaultValue) == "catman") - assert hasCustomPragma(type(s.field), defaultValue) + doAssert hasCustomPragma(type(s.field), defaultValue) proc foo(s: var MySerializable) = - static: assert(s.a.getCustomPragmaVal(defaultValue) == 5) + static: doAssert(s.a.getCustomPragmaVal(defaultValue) == 5) foo(s) @@ -91,8 +91,8 @@ block: # ref types leftSerKey = getCustomPragmaVal(s.left, serializationKey) rightSerKey = getCustomPragmaVal(s.right, serializationKey) static: - assert leftSerKey == "l" - assert rightSerKey == "r" + doAssert leftSerKey == "l" + doAssert rightSerKey == "r" var specS = SpecialNodeRef() @@ -100,25 +100,25 @@ block: # ref types dataDefVal = hasCustomPragma(specS.data, defaultValue) specLeftSerKey = hasCustomPragma(specS.left, serializationKey) static: - assert dataDefVal == true - assert specLeftSerKey == true + doAssert dataDefVal == true + doAssert specLeftSerKey == true var ptrS = NodePtr(nil) const ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey) static: - assert ptrRightSerKey == "r" + doAssert ptrRightSerKey == "r" var f = MyFile() const fileDefVal = f.getCustomPragmaVal(defaultValue) filePathDefVal = f.path.getCustomPragmaVal(defaultValue) static: - assert fileDefVal == "closed" - assert filePathDefVal == "invalid" + doAssert fileDefVal == "closed" + doAssert filePathDefVal == "invalid" static: - assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false + doAssert TypeWithoutPragma.hasCustomPragma(defaultValue) == false block: type @@ -144,9 +144,9 @@ block: nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue) static: - assert hasIntSerKey - assert strSerKey == "string" - assert nestedItemDefVal == "Nimmers of the world, unite!" + doAssert hasIntSerKey + doAssert strSerKey == "string" + doAssert nestedItemDefVal == "Nimmers of the world, unite!" block: template simpleAttr {.pragma.} @@ -154,7 +154,7 @@ block: type Annotated {.simpleAttr.} = object proc generic_proc[T]() = - assert Annotated.hasCustomPragma(simpleAttr) + doAssert Annotated.hasCustomPragma(simpleAttr) #-------------------------------------------------------------------------- @@ -252,7 +252,7 @@ block: block: macro expectedAst(expectedRepr: static[string], input: untyped): untyped = - assert input.treeRepr & "\n" == expectedRepr + doAssert input.treeRepr & "\n" == expectedRepr return input const procTypeAst = """ @@ -270,7 +270,7 @@ ProcTy type Foo = proc (x: int) {.expectedAst(procTypeAst), async.} - static: assert Foo is proc(x: int): Future[void] + static: doAssert Foo is proc(x: int): Future[void] const asyncProcTypeAst = """ ProcTy @@ -288,7 +288,7 @@ ProcTy type Bar = proc (s: string) {.async, expectedAst(asyncProcTypeAst).} - static: assert Bar is proc(x: string): Future[void] + static: doAssert Bar is proc(x: string): Future[void] const typeAst = """ TypeDef @@ -310,7 +310,7 @@ TypeDef Baz {.expectedAst(typeAst).} = object x: string - static: assert Baz.x is string + static: doAssert Baz.x is string const procAst = """ ProcDef @@ -333,7 +333,7 @@ ProcDef proc bar(s: string): string {.expectedAst(procAst).} = return s - static: assert bar("x") == "x" + static: doAssert bar("x") == "x" #------------------------------------------------------ # bug #13909 diff --git a/tests/sets/tsets_various.nim b/tests/sets/tsets_various.nim index c27d8e124..3e468c8f9 100644 --- a/tests/sets/tsets_various.nim +++ b/tests/sets/tsets_various.nim @@ -58,13 +58,13 @@ block tsets2: var t = initHashSet[tuple[x, y: int]]() t.incl((0,0)) t.incl((1,0)) - assert(not t.containsOrIncl((0,1))) + doAssert(not t.containsOrIncl((0,1))) t.incl((1,1)) for x in 0..1: for y in 0..1: - assert((x,y) in t) - #assert($t == + doAssert((x,y) in t) + #doAssert($t == # "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}") block setTest2: @@ -76,31 +76,31 @@ block tsets2: t.incl("012") t.incl("123") # test duplicates - assert "123" in t - assert "111" notin t # deleted + doAssert "123" in t + doAssert "111" notin t # deleted - assert t.missingOrExcl("000") - assert "000" notin t - assert t.missingOrExcl("012") == false - assert "012" notin t + doAssert t.missingOrExcl("000") + doAssert "000" notin t + doAssert t.missingOrExcl("012") == false + doAssert "012" notin t - assert t.containsOrIncl("012") == false - assert t.containsOrIncl("012") - assert "012" in t # added back + doAssert t.containsOrIncl("012") == false + doAssert t.containsOrIncl("012") + doAssert "012" in t # added back for key in items(data): t.incl(key) - for key in items(data): assert key in t + for key in items(data): doAssert key in t for key in items(data): t.excl(key) - for key in items(data): assert key notin t + for key in items(data): doAssert key notin t block orderedSetTest1: var t = data.toOrderedSet - for key in items(data): assert key in t + for key in items(data): doAssert key in t var i = 0 # `items` needs to yield in insertion order: for key in items(t): - assert key == data[i] + doAssert key == data[i] inc(i) @@ -117,22 +117,22 @@ block tsets3: s1_s3 = s1 + s3 s2_s3 = s2 + s3 - assert s1_s2.len == 7 - assert s1_s3.len == 8 - assert s2_s3.len == 6 + doAssert s1_s2.len == 7 + doAssert s1_s3.len == 8 + doAssert s2_s3.len == 6 for i in s1: - assert i in s1_s2 - assert i in s1_s3 + doAssert i in s1_s2 + doAssert i in s1_s3 for i in s2: - assert i in s1_s2 - assert i in s2_s3 + doAssert i in s1_s2 + doAssert i in s2_s3 for i in s3: - assert i in s1_s3 - assert i in s2_s3 + doAssert i in s1_s3 + doAssert i in s2_s3 - assert((s1 + s1) == s1) - assert((s2 + s1) == s1_s2) + doAssert((s1 + s1) == s1) + doAssert((s2 + s1) == s1_s2) block intersection: let @@ -140,22 +140,22 @@ block tsets3: s1_s3 = intersection(s1, s3) s2_s3 = s2 * s3 - assert s1_s2.len == 3 - assert s1_s3.len == 0 - assert s2_s3.len == 2 + doAssert s1_s2.len == 3 + doAssert s1_s3.len == 0 + doAssert s2_s3.len == 2 for i in s1_s2: - assert i in s1 - assert i in s2 + doAssert i in s1 + doAssert i in s2 for i in s1_s3: - assert i in s1 - assert i in s3 + doAssert i in s1 + doAssert i in s3 for i in s2_s3: - assert i in s2 - assert i in s3 + doAssert i in s2 + doAssert i in s3 - assert((s2 * s2) == s2) - assert((s3 * s2) == s2_s3) + doAssert((s2 * s2) == s2) + doAssert((s3 * s2) == s2_s3) block symmetricDifference: let @@ -163,22 +163,22 @@ block tsets3: s1_s3 = s1 -+- s3 s2_s3 = s2 -+- s3 - assert s1_s2.len == 4 - assert s1_s3.len == 8 - assert s2_s3.len == 4 + doAssert s1_s2.len == 4 + doAssert s1_s3.len == 8 + doAssert s2_s3.len == 4 for i in s1: - assert i in s1_s2 xor i in s2 - assert i in s1_s3 xor i in s3 + doAssert i in s1_s2 xor i in s2 + doAssert i in s1_s3 xor i in s3 for i in s2: - assert i in s1_s2 xor i in s1 - assert i in s2_s3 xor i in s3 + doAssert i in s1_s2 xor i in s1 + doAssert i in s2_s3 xor i in s3 for i in s3: - assert i in s1_s3 xor i in s1 - assert i in s2_s3 xor i in s2 + doAssert i in s1_s3 xor i in s1 + doAssert i in s2_s3 xor i in s2 - assert((s3 -+- s3) == initHashSet[int]()) - assert((s3 -+- s1) == s1_s3) + doAssert((s3 -+- s3) == initHashSet[int]()) + doAssert((s3 -+- s1) == s1_s3) block difference: let @@ -186,23 +186,23 @@ block tsets3: s1_s3 = difference(s1, s3) s2_s3 = s2 - s3 - assert s1_s2.len == 2 - assert s1_s3.len == 5 - assert s2_s3.len == 3 + doAssert s1_s2.len == 2 + doAssert s1_s3.len == 5 + doAssert s2_s3.len == 3 for i in s1: - assert i in s1_s2 xor i in s2 - assert i in s1_s3 xor i in s3 + doAssert i in s1_s2 xor i in s2 + doAssert i in s1_s3 xor i in s3 for i in s2: - assert i in s2_s3 xor i in s3 + doAssert i in s2_s3 xor i in s3 - assert((s2 - s2) == initHashSet[int]()) + doAssert((s2 - s2) == initHashSet[int]()) block disjoint: - assert(not disjoint(s1, s2)) - assert disjoint(s1, s3) - assert(not disjoint(s2, s3)) - assert(not disjoint(s2, s2)) + doAssert(not disjoint(s1, s2)) + doAssert disjoint(s1, s3) + doAssert(not disjoint(s2, s3)) + doAssert(not disjoint(s2, s2)) block: # https://github.com/nim-lang/Nim/issues/13496 template testDel(body) = @@ -217,7 +217,7 @@ block: # https://github.com/nim-lang/Nim/issues/13496 doAssert sortedItems(t) == @[15, 17, 19] var s = newSeq[int]() for v in t: s.add(v) - assert s.len == 3 + doAssert s.len == 3 doAssert sortedItems(s) == @[15, 17, 19] when t is OrderedSet: doAssert sortedPairs(t) == @[(a: 0, b: 15), (a: 1, b: 19), (a: 2, b: 17)] diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index f3a0f0fcb..8817e07a0 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -17,14 +17,14 @@ Val1 import macros -template ok(x) = assert(x) -template no(x) = assert(not x) +template ok(x) = doAssert(x) +template no(x) = doAssert(not x) template accept(x) = - static: assert(compiles(x)) + static: doAssert(compiles(x)) template reject(x) = - static: assert(not compiles(x)) + static: doAssert(not compiles(x)) proc plus(a, b: int): int = a + b @@ -54,8 +54,8 @@ when true: b: static[int], c: static int) = static: - assert a.isStatic and b.isStatic and c.isStatic - assert isStatic(a + plus(b, c)) + doAssert a.isStatic and b.isStatic and c.isStatic + doAssert isStatic(a + plus(b, c)) echo "staticAlialProc instantiated with ", a, b, c when b mod a == 0: @@ -111,9 +111,9 @@ when true: var aw3: ArrayWrapper3[(10, "str")] static: - assert aw1.data.high == 5 - assert aw2.data.high == 6 - assert aw3.data.high == 9 + doAssert aw1.data.high == 5 + doAssert aw2.data.high == 6 + doAssert aw3.data.high == 9 # #6077 block: diff --git a/tests/stdlib/t14139.nim b/tests/stdlib/t14139.nim index 78e0f6645..07d2ff137 100644 --- a/tests/stdlib/t14139.nim +++ b/tests/stdlib/t14139.nim @@ -6,4 +6,4 @@ test_queue.push(7) test_queue.push(3) test_queue.push(9) let i = test_queue.pushpop(10) -assert i == 3 +doAssert i == 3 diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 9dec68f03..148a65289 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -20,31 +20,31 @@ test() block: # Tests for lowerBound var arr = @[1, 2, 3, 5, 6, 7, 8, 9] - assert arr.lowerBound(0) == 0 - assert arr.lowerBound(4) == 3 - assert arr.lowerBound(5) == 3 - assert arr.lowerBound(10) == 8 + doAssert arr.lowerBound(0) == 0 + doAssert arr.lowerBound(4) == 3 + doAssert arr.lowerBound(5) == 3 + doAssert arr.lowerBound(10) == 8 arr = @[1, 5, 10] - assert arr.lowerBound(4) == 1 - assert arr.lowerBound(5) == 1 - assert arr.lowerBound(6) == 2 + doAssert arr.lowerBound(4) == 1 + doAssert arr.lowerBound(5) == 1 + doAssert arr.lowerBound(6) == 2 # Tests for isSorted var srt1 = [1, 2, 3, 4, 4, 4, 4, 5] var srt2 = ["iello", "hello"] var srt3 = [1.0, 1.0, 1.0] var srt4: seq[int] - assert srt1.isSorted(cmp) == true - assert srt2.isSorted(cmp) == false - assert srt3.isSorted(cmp) == true - assert srt4.isSorted(cmp) == true + doAssert srt1.isSorted(cmp) == true + doAssert srt2.isSorted(cmp) == false + doAssert srt3.isSorted(cmp) == true + doAssert srt4.isSorted(cmp) == true var srtseq = newSeq[int]() - assert srtseq.isSorted(cmp) == true + doAssert srtseq.isSorted(cmp) == true # Tests for reversed var arr1 = @[0, 1, 2, 3, 4] - assert arr1.reversed() == @[4, 3, 2, 1, 0] + doAssert arr1.reversed() == @[4, 3, 2, 1, 0] for i in 0 .. high(arr1): - assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] - assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] + doAssert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] + doAssert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] block: var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim index 7b2dde1c8..b350cb280 100644 --- a/tests/stdlib/tcritbits.nim +++ b/tests/stdlib/tcritbits.nim @@ -16,48 +16,48 @@ template main = doAssert r.contains"def" r.excl "def" - assert r.missingOrExcl("foo") == false - assert "foo" notin toSeq(r.items) + doAssert r.missingOrExcl("foo") == false + doAssert "foo" notin toSeq(r.items) - assert r.missingOrExcl("foo") == true + doAssert r.missingOrExcl("foo") == true - assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] + doAssert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] - assert toSeq(r.itemsWithPrefix("de")) == @["definition"] + doAssert toSeq(r.itemsWithPrefix("de")) == @["definition"] var c = CritBitTree[int]() c.inc("a") - assert c["a"] == 1 + doAssert c["a"] == 1 c.inc("a", 4) - assert c["a"] == 5 + doAssert c["a"] == 5 c.inc("a", -5) - assert c["a"] == 0 + doAssert c["a"] == 0 c.inc("b", 2) - assert c["b"] == 2 + doAssert c["b"] == 2 c.inc("c", 3) - assert c["c"] == 3 + doAssert c["c"] == 3 c.inc("a", 1) - assert c["a"] == 1 + doAssert c["a"] == 1 var cf = CritBitTree[float]() cf.incl("a", 1.0) - assert cf["a"] == 1.0 + doAssert cf["a"] == 1.0 cf.incl("b", 2.0) - assert cf["b"] == 2.0 + doAssert cf["b"] == 2.0 cf.incl("c", 3.0) - assert cf["c"] == 3.0 + doAssert cf["c"] == 3.0 - assert cf.len == 3 + doAssert cf.len == 3 cf.excl("c") - assert cf.len == 2 + doAssert cf.len == 2 var cb: CritBitTree[string] cb.incl("help", "help") diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim index db392c6cc..99208d4cf 100644 --- a/tests/stdlib/tdeques.nim +++ b/tests/stdlib/tdeques.nim @@ -11,7 +11,7 @@ block: proc main = var testDeque = initDeque[int]() testDeque.addFirst(1) - assert testDeque.index(0) == 1 + doAssert testDeque.index(0) == 1 main() @@ -35,26 +35,26 @@ block: deq.addFirst(123) var first = deq.popFirst() deq.addLast(56) - assert(deq.peekLast() == 56) + doAssert(deq.peekLast() == 56) deq.addLast(6) - assert(deq.peekLast() == 6) + doAssert(deq.peekLast() == 6) var second = deq.popFirst() deq.addLast(789) - assert(deq.peekLast() == 789) + doAssert(deq.peekLast() == 789) - assert first == 123 - assert second == 9 - assert($deq == "[4, 56, 6, 789]") - assert deq == [4, 56, 6, 789].toDeque + doAssert first == 123 + doAssert second == 9 + doAssert($deq == "[4, 56, 6, 789]") + doAssert deq == [4, 56, 6, 789].toDeque - assert deq[0] == deq.peekFirst and deq.peekFirst == 4 - #assert deq[^1] == deq.peekLast and deq.peekLast == 789 + doAssert deq[0] == deq.peekFirst and deq.peekFirst == 4 + #doAssert deq[^1] == deq.peekLast and deq.peekLast == 789 deq[0] = 42 deq[deq.len - 1] = 7 - assert 6 in deq and 789 notin deq - assert deq.find(6) >= 0 - assert deq.find(789) < 0 + doAssert 6 in deq and 789 notin deq + doAssert deq.find(6) >= 0 + doAssert deq.find(789) < 0 block: var d = initDeque[int](1) @@ -74,21 +74,21 @@ block: for i in -2 .. 10: if i in deq: - assert deq.contains(i) and deq.find(i) >= 0 + doAssert deq.contains(i) and deq.find(i) >= 0 else: - assert(not deq.contains(i) and deq.find(i) < 0) + doAssert(not deq.contains(i) and deq.find(i) < 0) when compileOption("boundChecks"): try: echo deq[99] - assert false + doAssert false except IndexDefect: discard try: - assert deq.len == 4 + doAssert deq.len == 4 for i in 0 ..< 5: deq.popFirst() - assert false + doAssert false except IndexDefect: discard @@ -98,24 +98,24 @@ block: deq.popFirst() deq.popLast() for i in 5 .. 8: deq.addFirst i - assert $deq == "[8, 7, 6, 5, 2, 3]" + doAssert $deq == "[8, 7, 6, 5, 2, 3]" # Similar to proc from the documentation example proc foo(a, b: Positive) = # assume random positive values for `a` and `b`. var deq = initDeque[int]() - assert deq.len == 0 + doAssert deq.len == 0 for i in 1 .. a: deq.addLast i if b < deq.len: # checking before indexed access. - assert deq[b] == b + 1 + doAssert deq[b] == b + 1 # The following two lines don't need any checking on access due to the logic # of the program, but that would not be the case if `a` could be 0. - assert deq.peekFirst == 1 - assert deq.peekLast == a + doAssert deq.peekFirst == 1 + doAssert deq.peekLast == a while deq.len > 0: # checking if the deque is empty - assert deq.popFirst() > 0 + doAssert deq.popFirst() > 0 #foo(0,0) foo(8, 5) @@ -133,7 +133,7 @@ block t13310: q.addFirst([1'i16].toHashSet) q.addFirst([2'i16].toHashSet) q.addFirst([3'i16].toHashSet) - assert $q == "[{3}, {2}, {1}]" + doAssert $q == "[{3}, {2}, {1}]" static: main() diff --git a/tests/stdlib/teditdistance.nim b/tests/stdlib/teditdistance.nim index 5a8acd513..433535635 100644 --- a/tests/stdlib/teditdistance.nim +++ b/tests/stdlib/teditdistance.nim @@ -30,11 +30,11 @@ doAssert editDistanceAscii("kitten", "sitting") == 3 # from Wikipedia doAssert editDistanceAscii("flaw", "lawn") == 2 # from Wikipedia -assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) -assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) -assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) -assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) -assert(editDistance("prefix__hallo_suffix", "prefix") == 14) -assert(editDistance("prefix__hallo_suffix", "suffix") == 14) -assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) -assert(editDistance("main", "malign") == 2) \ No newline at end of file +doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) +doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) +doAssert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) +doAssert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) +doAssert(editDistance("prefix__hallo_suffix", "prefix") == 14) +doAssert(editDistance("prefix__hallo_suffix", "suffix") == 14) +doAssert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) +doAssert(editDistance("main", "malign") == 2) \ No newline at end of file diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim index e5f21bc15..7a1c2d10a 100644 --- a/tests/stdlib/tenumerate.nim +++ b/tests/stdlib/tenumerate.nim @@ -6,14 +6,14 @@ block: var res: seq[(int, int)] for i, x in enumerate(a): res.add (i, x) - assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] + doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] block: var res: seq[(int, int)] for (i, x) in enumerate(a.items): res.add (i, x) - assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] + doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] block: var res: seq[(int, int)] for i, x in enumerate(3, a): res.add (i, x) - assert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] + doAssert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] diff --git a/tests/stdlib/thtmlparser.nim b/tests/stdlib/thtmlparser.nim index 2ac7b4004..f35785b25 100644 --- a/tests/stdlib/thtmlparser.nim +++ b/tests/stdlib/thtmlparser.nim @@ -47,7 +47,7 @@ block t2813: for n in tree.findAll("table"): n.findAll("tr", rows) # len = 2 break - assert tree.findAll("tr").len == rows.len + doAssert tree.findAll("tr").len == rows.len block t2814: diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index fd5e1d90c..6f88e9536 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -2,31 +2,31 @@ import httpcore, strutils block: block HttpCode: - assert $Http418 == "418 I'm a teapot" - assert Http418.is4xx() == true - assert Http418.is2xx() == false + doAssert $Http418 == "418 I'm a teapot" + doAssert Http418.is4xx() == true + doAssert Http418.is2xx() == false block headers: var h = newHttpHeaders() - assert h.len == 0 + doAssert h.len == 0 h.add("Cookie", "foo") - assert h.len == 1 - assert h.hasKey("cooKIE") - assert h["Cookie"] == "foo" - assert h["cookie"] == "foo" + doAssert h.len == 1 + doAssert h.hasKey("cooKIE") + doAssert h["Cookie"] == "foo" + doAssert h["cookie"] == "foo" h["cookie"] = @["bar", "x"] - assert h["Cookie"] == "bar" - assert h["Cookie", 1] == "x" - assert h["Cookie"].contains("BaR") == true - assert h["Cookie"].contains("X") == true - assert "baR" in h["cookiE"] + doAssert h["Cookie"] == "bar" + doAssert h["Cookie", 1] == "x" + doAssert h["Cookie"].contains("BaR") == true + doAssert h["Cookie"].contains("X") == true + doAssert "baR" in h["cookiE"] h.del("coOKie") - assert h.len == 0 + doAssert h.len == 0 # Test that header constructor works with repeated values let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"}) - assert seq[string](h1["a"]).join(",") == "1,2,3" + doAssert seq[string](h1["a"]).join(",") == "1,2,3" block test_cookies_with_comma: doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 59ac8d7ee..b5a3d3f7e 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -11,16 +11,16 @@ block SinglyLinkedListTest1: var L: SinglyLinkedList[int] for d in items(data): L.prepend(d) for d in items(data): L.append(d) - assert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]") + doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]") - assert(4 in L) + doAssert(4 in L) block SinglyLinkedListTest2: var L: SinglyLinkedList[string] for d in items(data): L.prepend($d) - assert($L == """["6", "5", "4", "3", "2", "1"]""") + doAssert($L == """["6", "5", "4", "3", "2", "1"]""") - assert("4" in L) + doAssert("4" in L) block DoublyLinkedListTest1: @@ -28,39 +28,39 @@ block DoublyLinkedListTest1: for d in items(data): L.prepend(d) for d in items(data): L.append(d) L.remove(L.find(1)) - assert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") + doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") - assert(4 in L) + doAssert(4 in L) block SinglyLinkedRingTest1: var L: SinglyLinkedRing[int] L.prepend(4) - assert($L == "[4]") + doAssert($L == "[4]") L.prepend(4) - assert($L == "[4, 4]") - assert(4 in L) + doAssert($L == "[4, 4]") + doAssert(4 in L) block DoublyLinkedRingTest1: var L: DoublyLinkedRing[int] L.prepend(4) - assert($L == "[4]") + doAssert($L == "[4]") L.prepend(4) - assert($L == "[4, 4]") - assert(4 in L) + doAssert($L == "[4, 4]") + doAssert(4 in L) L.append(3) L.append(5) - assert($L == "[4, 4, 3, 5]") + doAssert($L == "[4, 4, 3, 5]") L.remove(L.find(3)) L.remove(L.find(5)) L.remove(L.find(4)) L.remove(L.find(4)) - assert($L == "[]") - assert(4 notin L) + doAssert($L == "[]") + doAssert(4 notin L) block tlistsToString: block: @@ -105,8 +105,8 @@ template testCommon(initList, toList) = doAssert a.toSeq == [f0] doAssert b.toSeq == [f0, f1] f0.x = 42 - assert a.head.value.x == 42 - assert b.head.value.x == 42 + doAssert a.head.value.x == 42 + doAssert b.head.value.x == 42 block: # add, addMoved block: diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 0f66a94d1..64a4ff0ca 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -152,10 +152,10 @@ block: return sqrt(num) # check gamma function - assert(gamma(5.0) == 24.0) # 4! - assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 - assert(erf(6.0) > erf(5.0)) - assert(erfc(6.0) < erfc(5.0)) + doAssert(gamma(5.0) == 24.0) # 4! + doAssert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 + doAssert(erf(6.0) > erf(5.0)) + doAssert(erfc(6.0) < erfc(5.0)) # Function for approximate comparison of floats @@ -215,21 +215,21 @@ block: doAssert(classify(trunc(0.0'f32)) == fcZero) block: # sgn() tests - assert sgn(1'i8) == 1 - assert sgn(1'i16) == 1 - assert sgn(1'i32) == 1 - assert sgn(1'i64) == 1 - assert sgn(1'u8) == 1 - assert sgn(1'u16) == 1 - assert sgn(1'u32) == 1 - assert sgn(1'u64) == 1 - assert sgn(-12342.8844'f32) == -1 - assert sgn(123.9834'f64) == 1 - assert sgn(0'i32) == 0 - assert sgn(0'f32) == 0 - assert sgn(NegInf) == -1 - assert sgn(Inf) == 1 - assert sgn(NaN) == 0 + doAssert sgn(1'i8) == 1 + doAssert sgn(1'i16) == 1 + doAssert sgn(1'i32) == 1 + doAssert sgn(1'i64) == 1 + doAssert sgn(1'u8) == 1 + doAssert sgn(1'u16) == 1 + doAssert sgn(1'u32) == 1 + doAssert sgn(1'u64) == 1 + doAssert sgn(-12342.8844'f32) == -1 + doAssert sgn(123.9834'f64) == 1 + doAssert sgn(0'i32) == 0 + doAssert sgn(0'f32) == 0 + doAssert sgn(NegInf) == -1 + doAssert sgn(Inf) == 1 + doAssert sgn(NaN) == 0 block: # fac() tests try: diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim index 736fa05a7..88a7b8d37 100644 --- a/tests/stdlib/tmd5.nim +++ b/tests/stdlib/tmd5.nim @@ -1,7 +1,7 @@ import md5 -assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == +doAssert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == "a3cca2b2aa1e3b5b3b5aad99a8529074") -assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == +doAssert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == "7e716d0e702df0505fc72e2b89467910") -assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") +doAssert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 019303ebf..c053c16f2 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -468,19 +468,19 @@ block isRelativeTo: doAssert not isRelativeTo("/foo2", "/foo") block: # quoteShellWindows - assert quoteShellWindows("aaa") == "aaa" - assert quoteShellWindows("aaa\"") == "aaa\\\"" - assert quoteShellWindows("") == "\"\"" + doAssert quoteShellWindows("aaa") == "aaa" + doAssert quoteShellWindows("aaa\"") == "aaa\\\"" + doAssert quoteShellWindows("") == "\"\"" block: # quoteShellWindows - assert quoteShellPosix("aaa") == "aaa" - assert quoteShellPosix("aaa a") == "'aaa a'" - assert quoteShellPosix("") == "''" - assert quoteShellPosix("a'a") == "'a'\"'\"'a'" + doAssert quoteShellPosix("aaa") == "aaa" + doAssert quoteShellPosix("aaa a") == "'aaa a'" + doAssert quoteShellPosix("") == "''" + doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'" block: # quoteShell when defined(posix): - assert quoteShell("") == "''" + doAssert quoteShell("") == "''" block: # normalizePathEnd # handle edge cases correctly: shouldn't affect whether path is diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim index bbf88ee03..5c077bbda 100644 --- a/tests/stdlib/tparsecfg.nim +++ b/tests/stdlib/tparsecfg.nim @@ -24,8 +24,8 @@ when not defined(js): var config2 = loadConfig(file) let bar = config2.getSectionValue("foo", "bar") let foo = config2.getSectionValue("foo", "foo") - assert(bar == "-1") - assert(foo == "abc") + doAssert(bar == "-1") + doAssert(foo == "abc") ## Creating a configuration file. var dict1 = newConfig() diff --git a/tests/stdlib/tparsopt.nim b/tests/stdlib/tparsopt.nim index 948bc8d5f..54a470cb3 100644 --- a/tests/stdlib/tparsopt.nim +++ b/tests/stdlib/tparsopt.nim @@ -27,7 +27,7 @@ for kind, key, val in getopt(): of "version", "v": writeVersion() else: writeLine(stdout, "Unknown command line option: ", key, ": ", val) - of cmdEnd: assert(false) # cannot happen + of cmdEnd: doAssert(false) # cannot happen if filename == "": # no filename has been given, so we show the help: writeHelp() diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index 2990a44a5..99b7dc6f4 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -146,4 +146,4 @@ block: echo "Event parser output" echo "-------------------" let pLen = parseArithExpr(txt) - assert txt.len == pLen + doAssert txt.len == pLen diff --git a/tests/stdlib/tpunycode.nim b/tests/stdlib/tpunycode.nim index 998bd3bdf..596c5ef63 100644 --- a/tests/stdlib/tpunycode.nim +++ b/tests/stdlib/tpunycode.nim @@ -1,5 +1,5 @@ import punycode -assert(decode(encode("", "bücher")) == "bücher") -assert(decode(encode("münchen")) == "münchen") -assert encode("xn--", "münchen") == "xn--mnchen-3ya" +doAssert(decode(encode("", "bücher")) == "bücher") +doAssert(decode(encode("münchen")) == "münchen") +doAssert encode("xn--", "münchen") == "xn--mnchen-3ya" diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim index 17238af07..23c15b884 100644 --- a/tests/stdlib/trationals.nim +++ b/tests/stdlib/trationals.nim @@ -9,90 +9,90 @@ var m1 = -1 // 1 tt = 10 // 2 -assert(a == a) -assert( (a-a) == z) -assert( (a+b) == o) -assert( (a/b) == o) -assert( (a*b) == 1 // 4) -assert( (3/a) == 6 // 1) -assert( (a/3) == 1 // 6) -assert(a*b == 1 // 4) -assert(tt*z == z) -assert(10*a == tt) -assert(a*10 == tt) -assert(tt/10 == a) -assert(a-m1 == 3 // 2) -assert(a+m1 == -1 // 2) -assert(m1+tt == 16 // 4) -assert(m1-tt == 6 // -1) +doAssert(a == a) +doAssert( (a-a) == z) +doAssert( (a+b) == o) +doAssert( (a/b) == o) +doAssert( (a*b) == 1 // 4) +doAssert( (3/a) == 6 // 1) +doAssert( (a/3) == 1 // 6) +doAssert(a*b == 1 // 4) +doAssert(tt*z == z) +doAssert(10*a == tt) +doAssert(a*10 == tt) +doAssert(tt/10 == a) +doAssert(a-m1 == 3 // 2) +doAssert(a+m1 == -1 // 2) +doAssert(m1+tt == 16 // 4) +doAssert(m1-tt == 6 // -1) -assert(z < o) -assert(z <= o) -assert(z == z) -assert(cmp(z, o) < 0) -assert(cmp(o, z) > 0) +doAssert(z < o) +doAssert(z <= o) +doAssert(z == z) +doAssert(cmp(z, o) < 0) +doAssert(cmp(o, z) > 0) -assert(o == o) -assert(o >= o) -assert(not(o > o)) -assert(cmp(o, o) == 0) -assert(cmp(z, z) == 0) -assert(hash(o) == hash(o)) +doAssert(o == o) +doAssert(o >= o) +doAssert(not(o > o)) +doAssert(cmp(o, o) == 0) +doAssert(cmp(z, z) == 0) +doAssert(hash(o) == hash(o)) -assert(a == b) -assert(a >= b) -assert(not(b > a)) -assert(cmp(a, b) == 0) -assert(hash(a) == hash(b)) +doAssert(a == b) +doAssert(a >= b) +doAssert(not(b > a)) +doAssert(cmp(a, b) == 0) +doAssert(hash(a) == hash(b)) var x = 1//3 x *= 5//1 -assert(x == 5//3) +doAssert(x == 5//3) x += 2 // 9 -assert(x == 17//9) +doAssert(x == 17//9) x -= 9//18 -assert(x == 25//18) +doAssert(x == 25//18) x /= 1//2 -assert(x == 50//18) +doAssert(x == 50//18) var y = 1//3 y *= 4 -assert(y == 4//3) +doAssert(y == 4//3) y += 5 -assert(y == 19//3) +doAssert(y == 19//3) y -= 2 -assert(y == 13//3) +doAssert(y == 13//3) y /= 9 -assert(y == 13//27) +doAssert(y == 13//27) -assert toRational(5) == 5//1 -assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 -assert toInt(z) == 0 +doAssert toRational(5) == 5//1 +doAssert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 +doAssert toInt(z) == 0 when sizeof(int) == 8: - assert toRational(0.98765432) == 2111111029 // 2137499919 - assert toRational(PI) == 817696623 // 260280919 + doAssert toRational(0.98765432) == 2111111029 // 2137499919 + doAssert toRational(PI) == 817696623 // 260280919 when sizeof(int) == 4: - assert toRational(0.98765432) == 80 // 81 - assert toRational(PI) == 355 // 113 + doAssert toRational(0.98765432) == 80 // 81 + doAssert toRational(PI) == 355 // 113 -assert toRational(0.1) == 1 // 10 -assert toRational(0.9) == 9 // 10 +doAssert toRational(0.1) == 1 // 10 +doAssert toRational(0.9) == 9 // 10 -assert toRational(0.0) == 0 // 1 -assert toRational(-0.25) == 1 // -4 -assert toRational(3.2) == 16 // 5 -assert toRational(0.33) == 33 // 100 -assert toRational(0.22) == 11 // 50 -assert toRational(10.0) == 10 // 1 +doAssert toRational(0.0) == 0 // 1 +doAssert toRational(-0.25) == 1 // -4 +doAssert toRational(3.2) == 16 // 5 +doAssert toRational(0.33) == 33 // 100 +doAssert toRational(0.22) == 11 // 50 +doAssert toRational(10.0) == 10 // 1 -assert (1//1) div (3//10) == 3 -assert (-1//1) div (3//10) == -3 -assert (3//10) mod (1//1) == 3//10 -assert (-3//10) mod (1//1) == -3//10 -assert floorDiv(1//1, 3//10) == 3 -assert floorDiv(-1//1, 3//10) == -4 -assert floorMod(3//10, 1//1) == 3//10 -assert floorMod(-3//10, 1//1) == 7//10 +doAssert (1//1) div (3//10) == 3 +doAssert (-1//1) div (3//10) == -3 +doAssert (3//10) mod (1//1) == 3//10 +doAssert (-3//10) mod (1//1) == -3//10 +doAssert floorDiv(1//1, 3//10) == 3 +doAssert floorDiv(-1//1, 3//10) == -4 +doAssert floorMod(3//10, 1//1) == 3//10 +doAssert floorMod(-3//10, 1//1) == 7//10 diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 6a6e6fdc0..0645e4150 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -16,7 +16,7 @@ suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") let input = ".. include:: other.rst" - assert "test1" == rstTohtml(input, {}, defaultConfig()) + doAssert "test1" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include starting from": @@ -30,7 +30,7 @@ OtherStart .. include:: other.rst :start-after: OtherStart """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include everything before": @@ -44,7 +44,7 @@ And this should **NOT** be visible in `docs.html` .. include:: other.rst :end-before: OtherEnd """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") @@ -62,7 +62,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") @@ -82,5 +82,5 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 3283af8c6..c3388ab7d 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -22,7 +22,7 @@ suite "YAML syntax highlighting": : value ...""" let output = rstTohtml(input, {}, defaultConfig()) - assert output == """
    %YAML 1.2
    +    doAssert output == """
    %YAML 1.2
     ---
     a string: string
     a list:
    @@ -48,7 +48,7 @@ suite "YAML syntax highlighting":
           |+ # comment after header
          allowed, since more indented than parent"""
         let output = rstToHtml(input, {}, defaultConfig())
    -    assert output == """
    a literal block scalar: |
    +    doAssert output == """
    a literal block scalar: |
       some text
       # not a comment
      # a comment, since less indented
    @@ -74,7 +74,7 @@ suite "YAML syntax highlighting":
         ...
         %TAG ! !foo:"""
         let output = rstToHtml(input, {}, defaultConfig())
    -    assert output == """
    %YAML 1.2
    +    doAssert output == """
    %YAML 1.2
     ---
     %not a directive
     ...
    @@ -95,7 +95,7 @@ suite "YAML syntax highlighting":
           not numbers: [ 42e, 0023, +32.37, 8 ball]
         }"""
         let output = rstToHtml(input, {}, defaultConfig())
    -    assert output == """
    {
    +    doAssert output == """
    {
       "quoted string": 42,
       'single quoted string': false,
       [ list, "with", 'entries' ]: 73.32e-73,
    @@ -112,7 +112,7 @@ suite "YAML syntax highlighting":
         alias: *anchor
         """
         let output = rstToHtml(input, {}, defaultConfig())
    -    assert output == """
    --- !!map
    +    doAssert output == """
    --- !!map
     !!str string: !<tag:yaml.org,2002:int> 42
     ? &anchor !!seq []:
     : !localtag foo
    @@ -132,7 +132,7 @@ suite "YAML syntax highlighting":
           ?not a map key
         """
         let output = rstToHtml(input, {}, defaultConfig())
    -    assert output == """
    ...
    +    doAssert output == """
    ...
      %a string:
       a:string:not:a:map
     ...
    @@ -146,7 +146,7 @@ suite "YAML syntax highlighting":
     
     suite "RST/Markdown general":
       test "RST emphasis":
    -    assert rstToHtml("*Hello* **world**!", {},
    +    doAssert rstToHtml("*Hello* **world**!", {},
           newStringTable(modeStyleInsensitive)) ==
           "Hello world!"
     
    @@ -156,9 +156,9 @@ suite "RST/Markdown general":
           b = rstToHtml("(([Nim](https://nim-lang.org/)))", {roSupportMarkdown}, defaultConfig())
           c = rstToHtml("[[Nim](https://nim-lang.org/)]", {roSupportMarkdown}, defaultConfig())
     
    -    assert a == """(( Nim ))"""
    -    assert b == """((Nim))"""
    -    assert c == """[Nim]"""
    +    doAssert a == """(( Nim ))"""
    +    doAssert b == """((Nim))"""
    +    doAssert c == """[Nim]"""
     
       test "Markdown tables":
         let input1 = """
    @@ -170,7 +170,7 @@ suite "RST/Markdown general":
     |              | F2 without pipe
     not in table"""
         let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
    -    assert output1 == """
    +    doAssert output1 == """
    A1 headerA2 | not fooled
    @@ -181,7 +181,7 @@ not in table""" | A1 header | A2 | | --- | --- |""" let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) - assert output2 == """
    A1 headerA2 | not fooled
    C1C2 bold
    D1 code |D2
    E1 | text
    + doAssert output2 == """
    A1 headerA2
    A1 headerA2
    """ test "RST tables": @@ -197,10 +197,10 @@ A2 A3 A4 A5 ==== === """ let output1 = rstToLatex(input1, {}) - assert "{|X|X|}" in output1 # 2 columns - assert count(output1, "\\\\") == 4 # 4 rows + doAssert "{|X|X|}" in output1 # 2 columns + doAssert count(output1, "\\\\") == 4 # 4 rows for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]: - assert cell in output1 + doAssert cell in output1 let input2 = """ Now test 3 columns / 2 rows, and also borders containing 4 =, 3 =, 1 = signs: @@ -212,10 +212,10 @@ A0 A1 X Ax Y ==== === = """ let output2 = rstToLatex(input2, {}) - assert "{|X|X|X|}" in output2 # 3 columns - assert count(output2, "\\\\") == 2 # 2 rows + doAssert "{|X|X|X|}" in output2 # 3 columns + doAssert count(output2, "\\\\") == 2 # 2 rows for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]: - assert cell in output2 + doAssert cell in output2 test "RST adornments": @@ -231,7 +231,7 @@ Long chapter name ''''''''''''''''''' """ let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) - assert "Long chapter name" in output1 and "" in output1 + doAssert "
    " in output1
     
       test "Markdown code block":
         let input1 = """
    @@ -317,7 +317,7 @@ Test literal block
     let x = 1
     ``` """
         let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
    -    assert "" in output1
    -    assert "other line
    " in output1 + doAssert "line block
    " in output1 + doAssert "other line
    " in output1 let output1l = rstToLatex(input1, {}) - assert "line block\\\\" in output1l - assert "other line\\\\" in output1l + doAssert "line block\\\\" in output1l + doAssert "other line\\\\" in output1l test "RST enumerated lists": let input1 = dedent """ @@ -382,8 +382,8 @@ Test1 """ let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) for i in 1..5: - assert ($i & ". line" & $i) notin output1 - assert ("
  • line" & $i & " " & $i & "
  • ") in output1 + doAssert ($i & ". line" & $i) notin output1 + doAssert ("
  • line" & $i & " " & $i & "
  • ") in output1 let input2 = dedent """ 3. line3 @@ -404,8 +404,8 @@ Test1 """ let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) for i in [3, 4, 5, 7, 8]: - assert ($i & ". line" & $i) notin output2 - assert ("
  • line" & $i & "
  • ") in output2 + doAssert ($i & ". line" & $i) notin output2 + doAssert ("
  • line" & $i & "
  • ") in output2 # check that nested enumerated lists work let input3 = dedent """ @@ -413,9 +413,9 @@ Test1 2. string2 """ let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) - assert count(output3, "
      ") == 2 - assert "
    1. string1
    2. " in output3 and "
    3. string2
    4. " in output3 + doAssert count(output3, "
        ") == 2 + doAssert "
      1. string1
      2. " in output3 and "
      3. string2
      4. " in output3 let input4 = dedent """ Check that enumeration specifiers are respected @@ -429,12 +429,12 @@ Test1 e) string6 """ let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig()) - assert count(output4, "
          ") == 4 + doAssert count(output4, "
            ") == 4 for enumerator in [9, 12]: - assert "start=\"$1\"" % [$enumerator] in output4 + doAssert "start=\"$1\"" % [$enumerator] in output4 for enumerator in [2, 5]: # 2=b, 5=e - assert "start=\"$1\"" % [$enumerator] in output4 + doAssert "start=\"$1\"" % [$enumerator] in output4 let input5 = dedent """ Check that auto-numbered enumeration lists work. @@ -449,9 +449,9 @@ Test1 #) string6 """ let output5 = rstToHtml(input5, {roSupportMarkdown}, defaultConfig()) - assert count(output5, "
              ") == 2 - assert count(output5, "
            1. ") == 5 + doAssert count(output5, "
                ") == 2 + doAssert count(output5, "
              1. ") == 5 let input5a = dedent """ Auto-numbered RST list can start with 1 even when Markdown support is on. @@ -461,9 +461,9 @@ Test1 #. string3 """ let output5a = rstToHtml(input5a, {roSupportMarkdown}, defaultConfig()) - assert count(output5a, "
                  ") == 1 - assert count(output5a, "
                1. ") == 3 + doAssert count(output5a, "
                    ") == 1 + doAssert count(output5a, "
                  1. ") == 3 let input6 = dedent """ ... And for alphabetic enumerators too! @@ -473,10 +473,10 @@ Test1 #. string3 """ let output6 = rstToHtml(input6, {roSupportMarkdown}, defaultConfig()) - assert count(output6, "
                      ") == 1 - assert count(output6, "
                    1. ") == 3 - assert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6 + doAssert count(output6, "
                        ") == 1 + doAssert count(output6, "
                      1. ") == 3 + doAssert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6 let input7 = dedent """ ... And for uppercase alphabetic enumerators. @@ -486,10 +486,10 @@ Test1 #. string3 """ let output7 = rstToHtml(input7, {roSupportMarkdown}, defaultConfig()) - assert count(output7, "
                          ") == 1 - assert count(output7, "
                        1. ") == 3 - assert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7 + doAssert count(output7, "
                            ") == 1 + doAssert count(output7, "
                          1. ") == 3 + doAssert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7 test "Markdown enumerated lists": let input1 = dedent """ @@ -505,10 +505,10 @@ Test1 """ let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) for i in 1..5: - assert ($i & ". line" & $i) notin output1 - assert ("
                          2. line" & $i & "
                          3. ") in output1 - assert count(output1, "
                              ") == 2 + doAssert ($i & ". line" & $i) notin output1 + doAssert ("
                            1. line" & $i & "
                            2. ") in output1 + doAssert count(output1, "
                                ") == 2 test "RST bullet lists": let input1 = dedent """ @@ -531,9 +531,9 @@ Test1 """ let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) for i in 1..5: - assert ("
                              1. line" & $i & " " & $i & "
                              2. ") in output1 - assert count(output1, "
                                  ") == 1 + doAssert ("
                                • line" & $i & " " & $i & "
                                • ") in output1 + doAssert count(output1, "
                                    ") == 1 test "RST admonitions": # check that all admonitions are implemented @@ -552,7 +552,7 @@ Test1 let output0 = rstToHtml(input0, {roSupportMarkdown}, defaultConfig()) for a in ["admonition", "attention", "caution", "danger", "error", "hint", "important", "note", "tip", "warning" ]: - assert "endOf " & a & "" in output0 + doAssert "endOf " & a & "" in output0 # Test that admonition does not swallow up the next paragraph. let input1 = dedent """ @@ -561,9 +561,9 @@ Test1 Test paragraph. """ let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) - assert "endOfError" in output1 - assert "

                                    Test paragraph.

                                    " in output1 - assert "class=\"admonition admonition-error\"" in output1 + doAssert "endOfError" in output1 + doAssert "

                                    Test paragraph.

                                    " in output1 + doAssert "class=\"admonition admonition-error\"" in output1 # Test that second line is parsed as continuation of the first line. let input2 = dedent """ @@ -573,16 +573,16 @@ Test1 Test paragraph. """ let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) - assert "endOfError Test2p." in output2 - assert "

                                    Test paragraph.

                                    " in output2 - assert "class=\"admonition admonition-error\"" in output2 + doAssert "endOfError Test2p." in output2 + doAssert "

                                    Test paragraph.

                                    " in output2 + doAssert "class=\"admonition admonition-error\"" in output2 let input3 = dedent """ .. note:: endOfNote """ let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) - assert "endOfNote" in output3 - assert "class=\"admonition admonition-info\"" in output3 + doAssert "endOfNote" in output3 + doAssert "class=\"admonition admonition-info\"" in output3 suite "RST/Code highlight": test "Basic Python code highlight": diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index efcc9f126..94f6c3b08 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -15,7 +15,7 @@ block: # concat test s2 = @[4, 5] s3 = @[6, 7] total = concat(s1, s2, s3) - assert total == @[1, 2, 3, 4, 5, 6, 7] + doAssert total == @[1, 2, 3, 4, 5, 6, 7] block: # count test let @@ -35,18 +35,18 @@ block: # count test ar3 = count(a2, 'y') ar4 = count(a2, 'x') ar5 = count(a2, 'a') - assert r0 == 0 - assert r1 == 1 - assert r2 == 2 - assert r3 == 0 - assert r4 == 1 - assert r5 == 2 - assert ar0 == 0 - assert ar1 == 1 - assert ar2 == 2 - assert ar3 == 0 - assert ar4 == 1 - assert ar5 == 2 + doAssert r0 == 0 + doAssert r1 == 1 + doAssert r2 == 2 + doAssert r3 == 0 + doAssert r4 == 1 + doAssert r5 == 2 + doAssert ar0 == 0 + doAssert ar1 == 1 + doAssert ar2 == 2 + doAssert ar3 == 0 + doAssert ar4 == 1 + doAssert ar5 == 2 block: # cycle tests let @@ -62,9 +62,9 @@ block: # cycle tests doAssert c.cycle(0) == @[] block: # repeat tests - assert repeat(10, 5) == @[10, 10, 10, 10, 10] - assert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]] - assert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]] + doAssert repeat(10, 5) == @[10, 10, 10, 10, 10] + doAssert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]] + doAssert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]] block: # deduplicates test let @@ -80,14 +80,14 @@ block: # deduplicates test unique6 = deduplicate(dup2, true) unique7 = deduplicate(dup3.sorted, true) unique8 = deduplicate(dup4, true) - assert unique1 == @[1, 3, 4, 2, 8] - assert unique2 == @["a", "c", "d"] - assert unique3 == @[1, 3, 4, 2, 8] - assert unique4 == @["a", "c", "d"] - assert unique5 == @[1, 2, 3, 4, 8] - assert unique6 == @["a", "c", "d"] - assert unique7 == @[1, 2, 3, 4, 8] - assert unique8 == @["a", "c", "d"] + doAssert unique1 == @[1, 3, 4, 2, 8] + doAssert unique2 == @["a", "c", "d"] + doAssert unique3 == @[1, 3, 4, 2, 8] + doAssert unique4 == @["a", "c", "d"] + doAssert unique5 == @[1, 2, 3, 4, 8] + doAssert unique6 == @["a", "c", "d"] + doAssert unique7 == @[1, 2, 3, 4, 8] + doAssert unique8 == @["a", "c", "d"] block: # zip test let @@ -100,29 +100,29 @@ block: # zip test zip1 = zip(short, long) zip2 = zip(short, words) zip3 = zip(ashort, along) - assert zip1 == @[(1, 6), (2, 5), (3, 4)] - assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] - assert zip3 == @[(1, 6), (2, 5), (3, 4)] - assert zip1[2][1] == 4 - assert zip2[2][1] == "three" - assert zip3[2][1] == 4 + doAssert zip1 == @[(1, 6), (2, 5), (3, 4)] + doAssert zip2 == @[(1, "one"), (2, "two"), (3, "three")] + doAssert zip3 == @[(1, 6), (2, 5), (3, 4)] + doAssert zip1[2][1] == 4 + doAssert zip2[2][1] == "three" + doAssert zip3[2][1] == 4 when (NimMajor, NimMinor) <= (1, 0): let # In Nim 1.0.x and older, zip returned a seq of tuple strictly # with fields named "a" and "b". zipAb = zip(ashort, awords) - assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] - assert zipAb[2].b == "three" + doAssert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] + doAssert zipAb[2].b == "three" else: let # As zip returns seq of anonymous tuples, they can be assigned # to any variable that's a sequence of named tuples too. zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) - assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] - assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] - assert zipXy[2].y == "three" - assert zipMn[2].n == "three" + doAssert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] + doAssert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] + doAssert zipXy[2].y == "three" + doAssert zipMn[2].n == "three" block: # distribute tests let numbers = @[1, 2, 3, 4, 5, 6, 7] @@ -156,13 +156,13 @@ block: # map test anumbers = [1, 4, 5, 8, 9, 7, 4] m1 = map(numbers, proc(x: int): int = 2*x) m2 = map(anumbers, proc(x: int): int = 2*x) - assert m1 == @[2, 8, 10, 16, 18, 14, 8] - assert m2 == @[2, 8, 10, 16, 18, 14, 8] + doAssert m1 == @[2, 8, 10, 16, 18, 14, 8] + doAssert m2 == @[2, 8, 10, 16, 18, 14, 8] block: # apply test var a = @["1", "2", "3", "4"] apply(a, proc(x: var string) = x &= "42") - assert a == @["142", "242", "342", "442"] + doAssert a == @["142", "242", "342", "442"] block: # filter proc test let @@ -172,34 +172,34 @@ block: # filter proc test f2 = filter(colors) do (x: string) -> bool: x.len > 5 f3 = filter(acolors, proc(x: string): bool = x.len < 6) f4 = filter(acolors) do (x: string) -> bool: x.len > 5 - assert f1 == @["red", "black"] - assert f2 == @["yellow"] - assert f3 == @["red", "black"] - assert f4 == @["yellow"] + doAssert f1 == @["red", "black"] + doAssert f2 == @["yellow"] + doAssert f3 == @["red", "black"] + doAssert f4 == @["yellow"] block: # filter iterator test let numbers = @[1, 4, 5, 8, 9, 7, 4] let anumbers = [1, 4, 5, 8, 9, 7, 4] - assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == + doAssert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == @[4, 8, 4] - assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) == + doAssert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) == @[4, 8, 4] block: # keepIf test var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] keepIf(floats, proc(x: float): bool = x > 10) - assert floats == @[13.0, 12.5, 10.1] + doAssert floats == @[13.0, 12.5, 10.1] block: # delete tests let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] dest.delete(3, 8) - assert outcome == dest, """\ + doAssert outcome == dest, """\ Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] is [1,1,1,1,1,1,1,1]""" var x = @[1, 2, 3] x.delete(100, 100) - assert x == @[1, 2, 3] + doAssert x == @[1, 2, 3] block: # insert tests var dest = @[1, 1, 1, 1, 1, 1, 1, 1] @@ -207,7 +207,7 @@ block: # insert tests src = @[2, 2, 2, 2, 2, 2] outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] dest.insert(src, 3) - assert dest == outcome, """\ + doAssert dest == outcome, """\ Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1] at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]""" @@ -216,57 +216,57 @@ block: # filterIt test temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] acceptable = filterIt(temperatures, it < 50 and it > -10) notAcceptable = filterIt(temperatures, it > 50 or it < -10) - assert acceptable == @[-2.0, 24.5, 44.31] - assert notAcceptable == @[-272.15, 99.9, -113.44] + doAssert acceptable == @[-2.0, 24.5, 44.31] + doAssert notAcceptable == @[-272.15, 99.9, -113.44] block: # keepItIf test var candidates = @["foo", "bar", "baz", "foobar"] keepItIf(candidates, it.len == 3 and it[0] == 'b') - assert candidates == @["bar", "baz"] + doAssert candidates == @["bar", "baz"] block: # all let numbers = @[1, 4, 5, 8, 9, 7, 4] anumbers = [1, 4, 5, 8, 9, 7, 4] len0seq: seq[int] = @[] - assert all(numbers, proc (x: int): bool = return x < 10) == true - assert all(numbers, proc (x: int): bool = return x < 9) == false - assert all(len0seq, proc (x: int): bool = return false) == true - assert all(anumbers, proc (x: int): bool = return x < 10) == true - assert all(anumbers, proc (x: int): bool = return x < 9) == false + doAssert all(numbers, proc (x: int): bool = return x < 10) == true + doAssert all(numbers, proc (x: int): bool = return x < 9) == false + doAssert all(len0seq, proc (x: int): bool = return false) == true + doAssert all(anumbers, proc (x: int): bool = return x < 10) == true + doAssert all(anumbers, proc (x: int): bool = return x < 9) == false block: # allIt let numbers = @[1, 4, 5, 8, 9, 7, 4] anumbers = [1, 4, 5, 8, 9, 7, 4] len0seq: seq[int] = @[] - assert allIt(numbers, it < 10) == true - assert allIt(numbers, it < 9) == false - assert allIt(len0seq, false) == true - assert allIt(anumbers, it < 10) == true - assert allIt(anumbers, it < 9) == false + doAssert allIt(numbers, it < 10) == true + doAssert allIt(numbers, it < 9) == false + doAssert allIt(len0seq, false) == true + doAssert allIt(anumbers, it < 10) == true + doAssert allIt(anumbers, it < 9) == false block: # any let numbers = @[1, 4, 5, 8, 9, 7, 4] anumbers = [1, 4, 5, 8, 9, 7, 4] len0seq: seq[int] = @[] - assert any(numbers, proc (x: int): bool = return x > 8) == true - assert any(numbers, proc (x: int): bool = return x > 9) == false - assert any(len0seq, proc (x: int): bool = return true) == false - assert any(anumbers, proc (x: int): bool = return x > 8) == true - assert any(anumbers, proc (x: int): bool = return x > 9) == false + doAssert any(numbers, proc (x: int): bool = return x > 8) == true + doAssert any(numbers, proc (x: int): bool = return x > 9) == false + doAssert any(len0seq, proc (x: int): bool = return true) == false + doAssert any(anumbers, proc (x: int): bool = return x > 8) == true + doAssert any(anumbers, proc (x: int): bool = return x > 9) == false block: # anyIt let numbers = @[1, 4, 5, 8, 9, 7, 4] anumbers = [1, 4, 5, 8, 9, 7, 4] len0seq: seq[int] = @[] - assert anyIt(numbers, it > 8) == true - assert anyIt(numbers, it > 9) == false - assert anyIt(len0seq, true) == false - assert anyIt(anumbers, it > 8) == true - assert anyIt(anumbers, it > 9) == false + doAssert anyIt(numbers, it > 8) == true + doAssert anyIt(numbers, it > 9) == false + doAssert anyIt(len0seq, true) == false + doAssert anyIt(anumbers, it > 8) == true + doAssert anyIt(anumbers, it > 9) == false block: # toSeq test block: @@ -275,7 +275,7 @@ block: # toSeq test oddNumbers = toSeq(filter(numeric) do (x: int) -> bool: if x mod 2 == 1: result = true) - assert oddNumbers == @[1, 3, 5, 7, 9] + doAssert oddNumbers == @[1, 3, 5, 7, 9] block: doAssert [1, 2].toSeq == @[1, 2] @@ -350,10 +350,10 @@ block: # foldl tests multiplication = foldl(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldl(words, a & b) - assert addition == 25, "Addition is (((5)+9)+11)" - assert subtraction == -15, "Subtraction is (((5)-9)-11)" - assert multiplication == 495, "Multiplication is (((5)*9)*11)" - assert concatenation == "nimiscool" + doAssert addition == 25, "Addition is (((5)+9)+11)" + doAssert subtraction == -15, "Subtraction is (((5)-9)-11)" + doAssert multiplication == 495, "Multiplication is (((5)*9)*11)" + doAssert concatenation == "nimiscool" block: # foldr tests let @@ -363,10 +363,10 @@ block: # foldr tests multiplication = foldr(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldr(words, a & b) - assert addition == 25, "Addition is (5+(9+(11)))" - assert subtraction == 7, "Subtraction is (5-(9-(11)))" - assert multiplication == 495, "Multiplication is (5*(9*(11)))" - assert concatenation == "nimiscool" + doAssert addition == 25, "Addition is (5+(9+(11)))" + doAssert subtraction == 7, "Subtraction is (5-(9-(11)))" + doAssert multiplication == 495, "Multiplication is (5*(9*(11)))" + doAssert concatenation == "nimiscool" doAssert toSeq(1..3).foldr(a + b) == 6 # issue #14404 block: # mapIt + applyIt test @@ -376,8 +376,8 @@ block: # mapIt + applyIt test strings = nums.identity.mapIt($(4 * it)) doAssert counter == 1 nums.applyIt(it * 3) - assert nums[0] + nums[3] == 15 - assert strings[2] == "12" + doAssert nums[0] + nums[3] == 15 + doAssert strings[2] == "12" block: # newSeqWith tests var seq2D = newSeqWith(4, newSeq[bool](2)) diff --git a/tests/stdlib/tsharedtable.nim b/tests/stdlib/tsharedtable.nim index ce6aa96df..0a8f7bcc0 100644 --- a/tests/stdlib/tsharedtable.nim +++ b/tests/stdlib/tsharedtable.nim @@ -11,9 +11,9 @@ block: init(table) table[1] = 10 - assert table.mget(1) == 10 - assert table.mgetOrPut(3, 7) == 7 - assert table.mgetOrPut(3, 99) == 7 + doAssert table.mget(1) == 10 + doAssert table.mgetOrPut(3, 7) == 7 + doAssert table.mgetOrPut(3, 99) == 7 deinitSharedTable(table) import sequtils, algorithm diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index d483093a7..be5f1f304 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -202,10 +202,10 @@ doAssert fmt"{nat=:3X}" == "nat= 40" proc my_proc = const value = "value" const a = &"{value}" - assert a == value + doAssert a == value const b = &"{value=}" - assert b == "value=" & value + doAssert b == "value=" & value my_proc() diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim index d4344f95f..f629c183c 100644 --- a/tests/stdlib/tstrtabs.nim +++ b/tests/stdlib/tstrtabs.nim @@ -105,12 +105,12 @@ writeLine(stdout, "length of table ", $tab.len) block: var x = {"k": "v", "11": "22", "565": "67"}.newStringTable - assert x["k"] == "v" - assert x["11"] == "22" - assert x["565"] == "67" + doAssert x["k"] == "v" + doAssert x["11"] == "22" + doAssert x["565"] == "67" x["11"] = "23" - assert x["11"] == "23" + doAssert x["11"] == "23" x.clear(modeCaseInsensitive) x["11"] = "22" - assert x["11"] == "22" + doAssert x["11"] == "22" diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 8d6fe75ae..a6248d1e3 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -58,9 +58,9 @@ template main() = block: # splitLines let fixture = "a\nb\rc\r\nd" - assert len(fixture.splitLines) == 4 - assert splitLines(fixture) == @["a", "b", "c", "d"] - assert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] + doAssert len(fixture.splitLines) == 4 + doAssert splitLines(fixture) == @["a", "b", "c", "d"] + doAssert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] block: # rsplit doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"] @@ -83,207 +83,207 @@ template main() = block: # removeSuffix var s = "hello\n\r" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s = "hello\n\n" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s = "hello\r" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s = "hello \n there" s.removeSuffix - assert s == "hello \n there" + doAssert s == "hello \n there" s = "hello" s.removeSuffix("llo") - assert s == "he" + doAssert s == "he" s.removeSuffix('e') - assert s == "h" + doAssert s == "h" s = "hellos" s.removeSuffix({'s','z'}) - assert s == "hello" + doAssert s == "hello" s.removeSuffix({'l','o'}) - assert s == "he" + doAssert s == "he" s = "aeiou" s.removeSuffix("") - assert s == "aeiou" + doAssert s == "aeiou" s = "" s.removeSuffix("") - assert s == "" + doAssert s == "" s = " " s.removeSuffix - assert s == " " + doAssert s == " " s = " " s.removeSuffix("") - assert s == " " + doAssert s == " " s = " " s.removeSuffix(" ") - assert s == " " + doAssert s == " " s = " " s.removeSuffix(' ') - assert s == "" + doAssert s == "" # Contrary to Chomp in other languages # empty string does not change behaviour s = "hello\r\n\r\n" s.removeSuffix("") - assert s == "hello\r\n\r\n" + doAssert s == "hello\r\n\r\n" block: # removePrefix var s = "\n\rhello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s = "\n\nhello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s = "\rhello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s = "hello \n there" s.removePrefix - assert s == "hello \n there" + doAssert s == "hello \n there" s = "hello" s.removePrefix("hel") - assert s == "lo" + doAssert s == "lo" s.removePrefix('l') - assert s == "o" + doAssert s == "o" s = "hellos" s.removePrefix({'h','e'}) - assert s == "llos" + doAssert s == "llos" s.removePrefix({'l','o'}) - assert s == "s" + doAssert s == "s" s = "aeiou" s.removePrefix("") - assert s == "aeiou" + doAssert s == "aeiou" s = "" s.removePrefix("") - assert s == "" + doAssert s == "" s = " " s.removePrefix - assert s == " " + doAssert s == " " s = " " s.removePrefix("") - assert s == " " + doAssert s == " " s = " " s.removePrefix(" ") - assert s == " " + doAssert s == " " s = " " s.removePrefix(' ') - assert s == "" + doAssert s == "" # Contrary to Chomp in other languages # empty string does not change behaviour s = "\r\n\r\nhello" s.removePrefix("") - assert s == "\r\n\r\nhello" + doAssert s == "\r\n\r\nhello" block: # delete var s = "0123456789ABCDEFGH" delete(s, 4, 5) - assert s == "01236789ABCDEFGH" + doAssert s == "01236789ABCDEFGH" delete(s, s.len-1, s.len-1) - assert s == "01236789ABCDEFG" + doAssert s == "01236789ABCDEFG" delete(s, 0, 0) - assert s == "1236789ABCDEFG" + doAssert s == "1236789ABCDEFG" block: # find - assert "0123456789ABCDEFGH".find('A') == 10 - assert "0123456789ABCDEFGH".find('A', 5) == 10 - assert "0123456789ABCDEFGH".find('A', 5, 10) == 10 - assert "0123456789ABCDEFGH".find('A', 5, 9) == -1 - assert "0123456789ABCDEFGH".find("A") == 10 - assert "0123456789ABCDEFGH".find("A", 5) == 10 - assert "0123456789ABCDEFGH".find("A", 5, 10) == 10 - assert "0123456789ABCDEFGH".find("A", 5, 9) == -1 - assert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 - assert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 - assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 - assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 + doAssert "0123456789ABCDEFGH".find('A') == 10 + doAssert "0123456789ABCDEFGH".find('A', 5) == 10 + doAssert "0123456789ABCDEFGH".find('A', 5, 10) == 10 + doAssert "0123456789ABCDEFGH".find('A', 5, 9) == -1 + doAssert "0123456789ABCDEFGH".find("A") == 10 + doAssert "0123456789ABCDEFGH".find("A", 5) == 10 + doAssert "0123456789ABCDEFGH".find("A", 5, 10) == 10 + doAssert "0123456789ABCDEFGH".find("A", 5, 9) == -1 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 block: # rfind - assert "0123456789ABCDEFGAH".rfind('A') == 17 - assert "0123456789ABCDEFGAH".rfind('A', last=13) == 10 - assert "0123456789ABCDEFGAH".rfind('H', last=13) == -1 - assert "0123456789ABCDEFGAH".rfind("A") == 17 - assert "0123456789ABCDEFGAH".rfind("A", last=13) == 10 - assert "0123456789ABCDEFGAH".rfind("H", last=13) == -1 - assert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17 - assert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12 - assert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1 - assert "0123456789ABCDEFGAH".rfind('A', start=18) == -1 - assert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17 - assert "0123456789ABCDEFGAH".rfind("0", start=0) == 0 - assert "0123456789ABCDEFGAH".rfind("0", start=1) == -1 - assert "0123456789ABCDEFGAH".rfind("H", start=11) == 18 - assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9 - assert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1 + doAssert "0123456789ABCDEFGAH".rfind('A') == 17 + doAssert "0123456789ABCDEFGAH".rfind('A', last=13) == 10 + doAssert "0123456789ABCDEFGAH".rfind('H', last=13) == -1 + doAssert "0123456789ABCDEFGAH".rfind("A") == 17 + doAssert "0123456789ABCDEFGAH".rfind("A", last=13) == 10 + doAssert "0123456789ABCDEFGAH".rfind("H", last=13) == -1 + doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17 + doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12 + doAssert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1 + doAssert "0123456789ABCDEFGAH".rfind('A', start=18) == -1 + doAssert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17 + doAssert "0123456789ABCDEFGAH".rfind("0", start=0) == 0 + doAssert "0123456789ABCDEFGAH".rfind("0", start=1) == -1 + doAssert "0123456789ABCDEFGAH".rfind("H", start=11) == 18 + doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9 + doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1 - assert "/1/2/3".rfind('/') == 4 - assert "/1/2/3".rfind('/', last=1) == 0 - assert "/1/2/3".rfind('0') == -1 + doAssert "/1/2/3".rfind('/') == 4 + doAssert "/1/2/3".rfind('/', last=1) == 0 + doAssert "/1/2/3".rfind('0') == -1 block: # trimZeros var x = "1200" x.trimZeros() - assert x == "1200" + doAssert x == "1200" x = "120.0" x.trimZeros() - assert x == "120" + doAssert x == "120" x = "0." x.trimZeros() - assert x == "0" + doAssert x == "0" x = "1.0e2" x.trimZeros() - assert x == "1e2" + doAssert x == "1e2" x = "78.90" x.trimZeros() - assert x == "78.9" + doAssert x == "78.9" x = "1.23e4" x.trimZeros() - assert x == "1.23e4" + doAssert x == "1.23e4" x = "1.01" x.trimZeros() - assert x == "1.01" + doAssert x == "1.01" x = "1.1001" x.trimZeros() - assert x == "1.1001" + doAssert x == "1.1001" x = "0.0" x.trimZeros() - assert x == "0" + doAssert x == "0" x = "0.01" x.trimZeros() - assert x == "0.01" + doAssert x == "0.01" x = "1e0" x.trimZeros() - assert x == "1e0" + doAssert x == "1e0" block: # countLines - proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len + proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len assertCountLines("") assertCountLines("\n") assertCountLines("\n\n") @@ -295,36 +295,36 @@ template main() = block: # parseBinInt, parseHexInt, parseOctInt # binary - assert "0b1111".parseBinInt == 15 - assert "0B1111".parseBinInt == 15 - assert "1111".parseBinInt == 15 - assert "1110".parseBinInt == 14 - assert "1_1_1_1".parseBinInt == 15 - assert "0b1_1_1_1".parseBinInt == 15 + doAssert "0b1111".parseBinInt == 15 + doAssert "0B1111".parseBinInt == 15 + doAssert "1111".parseBinInt == 15 + doAssert "1110".parseBinInt == 14 + doAssert "1_1_1_1".parseBinInt == 15 + doAssert "0b1_1_1_1".parseBinInt == 15 rejectParse "".parseBinInt rejectParse "_".parseBinInt rejectParse "0b".parseBinInt rejectParse "0b1234".parseBinInt # hex - assert "0x72".parseHexInt == 114 - assert "0X72".parseHexInt == 114 - assert "#72".parseHexInt == 114 - assert "72".parseHexInt == 114 - assert "FF".parseHexInt == 255 - assert "ff".parseHexInt == 255 - assert "fF".parseHexInt == 255 - assert "0x7_2".parseHexInt == 114 + doAssert "0x72".parseHexInt == 114 + doAssert "0X72".parseHexInt == 114 + doAssert "#72".parseHexInt == 114 + doAssert "72".parseHexInt == 114 + doAssert "FF".parseHexInt == 255 + doAssert "ff".parseHexInt == 255 + doAssert "fF".parseHexInt == 255 + doAssert "0x7_2".parseHexInt == 114 rejectParse "".parseHexInt rejectParse "_".parseHexInt rejectParse "0x".parseHexInt rejectParse "0xFFG".parseHexInt rejectParse "reject".parseHexInt # octal - assert "0o17".parseOctInt == 15 - assert "0O17".parseOctInt == 15 - assert "17".parseOctInt == 15 - assert "10".parseOctInt == 8 - assert "0o1_0_0".parseOctInt == 64 + doAssert "0o17".parseOctInt == 15 + doAssert "0O17".parseOctInt == 15 + doAssert "17".parseOctInt == 15 + doAssert "10".parseOctInt == 8 + doAssert "0o1_0_0".parseOctInt == 64 rejectParse "".parseOctInt rejectParse "_".parseOctInt rejectParse "0o".parseOctInt @@ -333,53 +333,53 @@ template main() = rejectParse "reject".parseOctInt block: # parseHexStr - assert "".parseHexStr == "" - assert "00Ff80".parseHexStr == "\0\xFF\x80" + doAssert "".parseHexStr == "" + doAssert "00Ff80".parseHexStr == "\0\xFF\x80" try: discard "00Ff8".parseHexStr - assert false, "Should raise ValueError" + doAssert false, "Should raise ValueError" except ValueError: discard try: discard "0k".parseHexStr - assert false, "Should raise ValueError" + doAssert false, "Should raise ValueError" except ValueError: discard - assert "".toHex == "" - assert "\x00\xFF\x80".toHex == "00FF80" - assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" + doAssert "".toHex == "" + doAssert "\x00\xFF\x80".toHex == "00FF80" + doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" block: # toHex - assert(toHex(100i16, 32) == "00000000000000000000000000000064") - assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") + doAssert(toHex(100i16, 32) == "00000000000000000000000000000064") + doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") when not defined js: - assert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") - assert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") - assert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") + doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") + doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") + doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") block: # insertSep - assert(insertSep($1000_000) == "1_000_000") - assert(insertSep($232) == "232") - assert(insertSep($12345, ',') == "12,345") - assert(insertSep($0) == "0") + doAssert(insertSep($1000_000) == "1_000_000") + doAssert(insertSep($232) == "232") + doAssert(insertSep($12345, ',') == "12,345") + doAssert(insertSep($0) == "0") block: # repeat, spaces - assert(' '.repeat(8) == " ") - assert(" ".repeat(8) == " ") - assert(spaces(8) == " ") + doAssert(' '.repeat(8) == " ") + doAssert(" ".repeat(8) == " ") + doAssert(spaces(8) == " ") - assert(' '.repeat(0) == "") - assert(" ".repeat(0) == "") - assert(spaces(0) == "") + doAssert(' '.repeat(0) == "") + doAssert(" ".repeat(0) == "") + doAssert(spaces(0) == "") block: # toBin, toOct block:# bug #11369 var num: int64 = -1 when not defined js: - assert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" - assert num.toOct(24) == "001777777777777777777777" + doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" + doAssert num.toOct(24) == "001777777777777777777777" block: # replace doAssert "oo".replace("", "abc") == "oo" @@ -499,26 +499,26 @@ template main() = doAssert parseEnum("invalid enum value", enC) == enC block: # indentation - assert 0 == indentation """ + doAssert 0 == indentation """ hey low there """ - assert 2 == indentation """ + doAssert 2 == indentation """ hey low there """ - assert 2 == indentation """ hey + doAssert 2 == indentation """ hey low there """ - assert 2 == indentation """ hey + doAssert 2 == indentation """ hey low there""" - assert 0 == indentation "" - assert 0 == indentation " \n \n" - assert 0 == indentation " " + doAssert 0 == indentation "" + doAssert 0 == indentation " \n \n" + doAssert 0 == indentation " " block: # indent doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index cca1fe75a..2f79a9174 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -47,15 +47,15 @@ doAssert b[1] == 1 import sets, tables let data = @["bird", "word"] # if this gets stuck in your head, its not my fault -assert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"] -assert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == {0: "bird", +doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"] +doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) == {0: "bird", 1: "word"}.toTable -assert initHashSet.collect(for d in data.items: {d}) == data.toHashSet +doAssert initHashSet.collect(for d in data.items: {d}) == data.toHashSet let x = collect(newSeqOfCap(4)): for (i, d) in data.pairs: if i mod 2 == 0: d -assert x == @["bird"] +doAssert x == @["bird"] # bug #12874 @@ -69,20 +69,20 @@ let bug1 = collect( d & d ) ) -assert bug1 == @["bird", "wordword"] +doAssert bug1 == @["bird", "wordword"] import strutils let y = collect(newSeq): for (i, d) in data.pairs: try: parseInt(d) except: 0 -assert y == @[0, 0] +doAssert y == @[0, 0] let z = collect(newSeq): for (i, d) in data.pairs: case d of "bird": "word" else: d -assert z == @["word", "word"] +doAssert z == @["word", "word"] proc tforum = let ans = collect(newSeq): @@ -97,12 +97,12 @@ block: for d in data.items: when d is int: "word" else: d - assert x == @["bird", "word"] -assert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")] -assert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0] -assert collect(for (i, d) in pairs(data): {i: d}) == {1: "word", + doAssert x == @["bird", "word"] +doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")] +doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0] +doAssert collect(for (i, d) in pairs(data): {i: d}) == {1: "word", 0: "bird"}.toTable -assert collect(for d in data.items: {d}) == data.toHashSet +doAssert collect(for d in data.items: {d}) == data.toHashSet # bug #14332 template foo = diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim index 979ffc391..4c29d3e10 100644 --- a/tests/stdlib/tsums.nim +++ b/tests/stdlib/tsums.nim @@ -5,18 +5,18 @@ var epsilon = 1.0 while 1.0 + epsilon != 1.0: epsilon /= 2.0 let data = @[1.0, epsilon, -epsilon] -assert sumKbn(data) == 1.0 -# assert sumPairs(data) != 1.0 # known to fail in 64 bits -assert (1.0 + epsilon) - epsilon != 1.0 +doAssert sumKbn(data) == 1.0 +# doAssert sumPairs(data) != 1.0 # known to fail in 64 bits +doAssert (1.0 + epsilon) - epsilon != 1.0 var tc1: seq[float] for n in 1 .. 1000: tc1.add 1.0 / n.float -assert sumKbn(tc1) == 7.485470860550345 -assert sumPairs(tc1) == 7.485470860550345 +doAssert sumKbn(tc1) == 7.485470860550345 +doAssert sumPairs(tc1) == 7.485470860550345 var tc2: seq[float] for n in 1 .. 1000: tc2.add pow(-1.0, n.float) / n.float -assert sumKbn(tc2) == -0.6926474305598203 -assert sumPairs(tc2) == -0.6926474305598204 +doAssert sumKbn(tc2) == -0.6926474305598203 +doAssert sumPairs(tc2) == -0.6926474305598204 diff --git a/tests/stdlib/ttables.nim b/tests/stdlib/ttables.nim index 656d7be6b..c1ae89b32 100644 --- a/tests/stdlib/ttables.nim +++ b/tests/stdlib/ttables.nim @@ -59,8 +59,8 @@ block: # Deletion from OrderedTable should account for collision groups. See iss }.toOrderedTable() t.del(key1) - assert(t.len == 1) - assert(key2 in t) + doAssert(t.len == 1) + doAssert(key2 in t) var t1 = initCountTable[string]() @@ -72,9 +72,9 @@ t2.inc("foo", 4) t2.inc("bar") t2.inc("baz", 11) merge(t1, t2) -assert(t1["foo"] == 5) -assert(t1["bar"] == 3) -assert(t1["baz"] == 14) +doAssert(t1["foo"] == 5) +doAssert(t1["bar"] == 3) +doAssert(t1["baz"] == 14) let t1r = newCountTable[string]() @@ -86,9 +86,9 @@ t2r.inc("foo", 4) t2r.inc("bar") t2r.inc("baz", 11) merge(t1r, t2r) -assert(t1r["foo"] == 5) -assert(t1r["bar"] == 3) -assert(t1r["baz"] == 14) +doAssert(t1r["foo"] == 5) +doAssert(t1r["bar"] == 3) +doAssert(t1r["baz"] == 14) var t1l = initCountTable[string]() @@ -127,28 +127,28 @@ block: #5482 var b = newOrderedTable[string, string](initialSize = 2) b["wrong?"] = "foo" b["wrong?"] = "foo2" - assert a == b + doAssert a == b block: #5482 var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() var b = newOrderedTable[string, string](initialSize = 2) b["wrong?"] = "foo" b["wrong?"] = "foo2" - assert a == b + doAssert a == b block: #5487 var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() var b = newOrderedTable[string, string]() # notice, default size! b["wrong?"] = "foo" b["wrong?"] = "foo2" - assert a == b + doAssert a == b block: #5487 var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable() var b = newOrderedTable[string, string]() # notice, default size! b["wrong?"] = "foo" b["wrong?"] = "foo2" - assert a == b + doAssert a == b block: var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() @@ -156,22 +156,22 @@ block: var c = newOrderedTable[string, string]() # notice, default size! c["wrong?"] = "foo" c["wrong?"] = "foo2" - assert a == b - assert a == c + doAssert a == b + doAssert a == c block: #6250 let a = {3: 1}.toOrderedTable b = {3: 2}.toOrderedTable - assert((a == b) == false) - assert((b == a) == false) + doAssert((a == b) == false) + doAssert((b == a) == false) block: #6250 let a = {3: 2}.toOrderedTable b = {3: 2}.toOrderedTable - assert((a == b) == true) - assert((b == a) == true) + doAssert((a == b) == true) + doAssert((b == a) == true) block: # CountTable.smallest let t = toCountTable([0, 0, 5, 5, 5]) diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim index fc0bd3e53..61c661a58 100644 --- a/tests/stdlib/ttypeinfo.nim +++ b/tests/stdlib/ttypeinfo.nim @@ -17,16 +17,16 @@ var test = @[0,1,2,3,4] var x = toAny(test) var y = 78 x[4] = toAny(y) -assert x[2].getInt == 2 +doAssert x[2].getInt == 2 var test2: tuple[name: string, s: int] = ("test", 56) var x2 = toAny(test2) var i = 0 for n, a in fields(x2): case i - of 0: assert n == "Field0" and $a.kind == "akString" - of 1: assert n == "Field1" and $a.kind == "akInt" - else: assert false + of 0: doAssert n == "Field0" and $a.kind == "akString" + of 1: doAssert n == "Field1" and $a.kind == "akInt" + else: doAssert false inc i var test3: TestObj @@ -36,17 +36,17 @@ var x3 = toAny(test3) i = 0 for n, a in fields(x3): case i - of 0: assert n == "test" and $a.kind == "akInt" - of 1: assert n == "asd" and $a.kind == "akInt" - of 2: assert n == "test2" and $a.kind == "akEnum" - else: assert false + of 0: doAssert n == "test" and $a.kind == "akInt" + of 1: doAssert n == "asd" and $a.kind == "akInt" + of 2: doAssert n == "test2" and $a.kind == "akEnum" + else: doAssert false inc i var test4: ref string new(test4) test4[] = "test" var x4 = toAny(test4) -assert($x4[].kind() == "akString") +doAssert($x4[].kind() == "akString") block: # gimme a new scope dammit diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 4b82df67b..505fb41a3 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -56,7 +56,7 @@ proc defectiveRobot() = of 1: raise newException(OSError, "CANNOT COMPUTE!") of 2: discard parseInt("Hello World!") of 3: raise newException(IOError, "I can't do that Dave.") - else: assert 2 + 2 == 5 + else: doAssert 2 + 2 == 5 test "unittest expect": expect IOError, OSError, ValueError, AssertionDefect: defectiveRobot() diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim index 034435dd7..d2f713269 100644 --- a/tests/stdlib/txmltree.nim +++ b/tests/stdlib/txmltree.nim @@ -6,15 +6,15 @@ block: x: XmlNode x = <>a(href = "http://nim-lang.org", newText("Nim rules.")) - assert $x == """Nim rules.""" + doAssert $x == """Nim rules.""" x = <>outer(<>inner()) - assert $x == """ + doAssert $x == """ """ x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4())) - assert $x == """ + doAssert $x == """ @@ -24,7 +24,7 @@ block: """ x = <>l0(<>l1(<>l2(<>l3(<>l4())))) - assert $x == """ + doAssert $x == """ @@ -35,14 +35,14 @@ block: """ x = <>l0(<>l1p1(), <>l1p2(), <>l1p3()) - assert $x == """ + doAssert $x == """ """ x = <>l0(<>l1(<>l2p1(), <>l2p2())) - assert $x == """ + doAssert $x == """ @@ -50,7 +50,7 @@ block: """ x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4())) - assert $x == """ + doAssert $x == """ @@ -72,7 +72,7 @@ block: middle = newXmlTree("middle", [innermost]) innermost.add newText("innermost text") x = newXmlTree("outer", [middle]) - assert $x == """ + doAssert $x == """ innermost text @@ -82,4 +82,4 @@ block: x.add newText("my text") x.add newElement("sonTag") x.add newEntity("my entity") - assert $x == "my text&my entity;" + doAssert $x == "my text&my entity;" diff --git a/tests/types/tisop.nim b/tests/types/tisop.nim index ad5928016..5f9cba0d8 100644 --- a/tests/types/tisop.nim +++ b/tests/types/tisop.nim @@ -27,22 +27,22 @@ macro m(t: typedesc): typedesc = result = int var f: TFoo[int, int] -static: assert(f.y.type.name == "string") +static: doAssert(f.y.type.name == "string") when compiles(f.z): {.error: "Foo should not have a `z` field".} proc p(a, b: auto) = when a.type is int: - static: assert false + static: doAssert false var f: TFoo[m(a.type), b.type] static: - assert f.x.type.name == "int" + doAssert f.x.type.name == "int" echo f.y.type.name - assert f.y.type.name == "float" + doAssert f.y.type.name == "float" echo f.z.type.name - assert f.z.type.name == "float" + doAssert f.z.type.name == "float" p(A, f) diff --git a/tests/vm/tableinstatic.nim b/tests/vm/tableinstatic.nim index 4080a5286..934c3a8dd 100644 --- a/tests/vm/tableinstatic.nim +++ b/tests/vm/tableinstatic.nim @@ -35,4 +35,4 @@ static: otherTable["hallo"] = "123" otherTable["welt"] = "456" - assert otherTable == {"hallo": "123", "welt": "456"}.newTable + doAssert otherTable == {"hallo": "123", "welt": "456"}.newTable diff --git a/tests/vm/tissues.nim b/tests/vm/tissues.nim index 063559d2e..1cf3afc00 100644 --- a/tests/vm/tissues.nim +++ b/tests/vm/tissues.nim @@ -25,4 +25,4 @@ block t4952: static: let tree = newTree(nnkExprColonExpr) let t = (n: tree) - assert: t.n.kind == tree.kind + doAssert: t.n.kind == tree.kind diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim index c36b9ed9b..4ff614e5b 100644 --- a/tests/vm/toverflowopcaddimmint.nim +++ b/tests/vm/toverflowopcaddimmint.nim @@ -7,5 +7,5 @@ static: var x = int64.high discard x + 1 - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim index 6d96afc78..d494245b1 100644 --- a/tests/vm/toverflowopcaddint.nim +++ b/tests/vm/toverflowopcaddint.nim @@ -8,5 +8,5 @@ static: x = int64.high y = 1 discard x + y - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim index 5607c59a7..936eea6c2 100644 --- a/tests/vm/toverflowopcmulint.nim +++ b/tests/vm/toverflowopcmulint.nim @@ -7,5 +7,5 @@ static: var x = 1'i64 shl 62 discard x * 2 - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim index 09d6f745b..08356590c 100644 --- a/tests/vm/toverflowopcsubimmint.nim +++ b/tests/vm/toverflowopcsubimmint.nim @@ -6,5 +6,5 @@ static: proc p = var x = int64.low discard x - 1 - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim index 8d114f200..74e34c6a4 100644 --- a/tests/vm/toverflowopcsubint.nim +++ b/tests/vm/toverflowopcsubint.nim @@ -8,5 +8,5 @@ static: x = int64.low y = 1 discard x - y - assert false + doAssert false p() diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim index df408910e..d5dd4f4c9 100644 --- a/tests/vm/tstringnil.nim +++ b/tests/vm/tstringnil.nim @@ -47,4 +47,4 @@ macro suite(suiteName, suiteDesc, suiteBloc: untyped): typed = # Test above suite basics, "Description of such": test(t5, ""): - assert false + doAssert false diff --git a/tests/vm/tvarsection.nim b/tests/vm/tvarsection.nim index d1c4926a0..a45be6164 100644 --- a/tests/vm/tvarsection.nim +++ b/tests/vm/tvarsection.nim @@ -9,7 +9,7 @@ var d = "abc" static: - assert a == 2 - assert c == 3 + doAssert a == 2 + doAssert c == 3 echo b, d diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index e4d6c308f..005f7e255 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -22,11 +22,11 @@ import algorithm static: var numArray = [1, 2, 3, 4, -1] numArray.sort(cmp) - assert numArray == [-1, 1, 2, 3, 4] + doAssert numArray == [-1, 1, 2, 3, 4] var str = "cba" str.sort(cmp) - assert str == "abc" + doAssert str == "abc" # #6086 import math, sequtils, sugar @@ -42,7 +42,7 @@ block: var a = f() const b = f() - assert a == b + doAssert a == b block: proc f(): seq[char] = @@ -50,7 +50,7 @@ block: var runTime = f() const compTime = f() - assert runTime == compTime + doAssert runTime == compTime # #6083 block: @@ -64,24 +64,24 @@ block: result[i] = tmp const fact1000 = abc() - assert fact1000 == @[1, 2] + doAssert fact1000 == @[1, 2] # Tests for VM ops block: static: # for joint test, the project path is different, so I disabled it: when false: - assert "vm" in getProjectPath() + doAssert "vm" in getProjectPath() let b = getEnv("UNSETENVVAR") - assert b == "" - assert existsEnv("UNSERENVVAR") == false + doAssert b == "" + doAssert existsEnv("UNSERENVVAR") == false putEnv("UNSETENVVAR", "VALUE") - assert getEnv("UNSETENVVAR") == "VALUE" - assert existsEnv("UNSETENVVAR") == true + doAssert getEnv("UNSETENVVAR") == "VALUE" + doAssert existsEnv("UNSETENVVAR") == true - assert fileExists("MISSINGFILE") == false - assert dirExists("MISSINGDIR") == false + doAssert fileExists("MISSINGFILE") == false + doAssert dirExists("MISSINGDIR") == false # #7210 block: diff --git a/tests/vm/twrong_concat.nim b/tests/vm/twrong_concat.nim index 538ea2527..b9cca8341 100644 --- a/tests/vm/twrong_concat.nim +++ b/tests/vm/twrong_concat.nim @@ -23,6 +23,6 @@ static: sameBug(objs) # sameBug(objs) echo objs[0].field - assert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated! + doAssert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated! echo "success" diff --git a/tests/vm/twrongarray.nim b/tests/vm/twrongarray.nim index c1514d0e9..7f24290e2 100644 --- a/tests/vm/twrongarray.nim +++ b/tests/vm/twrongarray.nim @@ -14,4 +14,4 @@ when false: proc two(dummy: int, size: int) = var x: array[size * 1, int] # compiles, but shouldn't? - #assert(x.len == size) # just for fun + # doAssert(x.len == size) # just for fun From e70ac0f34c9f195f6e423b3ac7e54b912e62c71d Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 29 Dec 2020 05:32:11 +0300 Subject: [PATCH 1710/4254] RST: fix directive with fields (#16490) (#16493) * RST: fix directive with fields (#16490) * Update tests/stdlib/trstgen.nim Co-authored-by: Clyybber --- lib/packages/docutils/rst.nim | 3 ++- tests/stdlib/trstgen.nim | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 7dbcaf482..698d76da1 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1737,7 +1737,8 @@ proc parseDirective(p: var RstParser, flags: DirFlags, ## ## .. warning:: Any of the 3 children may be nil. result = parseDirective(p, flags) - if not isNil(contentParser): + if not isNil(contentParser) and + (currentTok(p).kind != tkIndent or indFollows(p)): var nextIndent = p.tok[tokenAfterNewline(p)-1].ival if nextIndent <= currInd(p): # parse only this line nextIndent = currentTok(p).col diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index c3388ab7d..54a3db202 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -535,6 +535,17 @@ Test1 doAssert count(output1, "
                                      ") == 1 + test "Nim (RST extension) code-block": + # check that presence of fields doesn't consume the following text as + # its code (which is a literal block) + let input0 = dedent """ + .. code-block:: nim + :number-lines: 0 + + Paragraph1""" + let output0 = rstToHtml(input0, {roSupportMarkdown}, defaultConfig()) + doAssert "

                                      Paragraph1

                                      " in output0 + test "RST admonitions": # check that all admonitions are implemented let input0 = dedent """ From 672dc5cd87790dc7f44ad62ae66f07e96e665409 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 29 Dec 2020 11:31:11 +0200 Subject: [PATCH 1711/4254] Nil type check implementation (#15287) * Nil checking * Enable current older not nil checking again, run new checking only under flag, skip our test * Enable tests, work on try/except and bugs, fix notnil tests * Enable strictNotNil tests (currently with lowercase category) and add some expected output * Work on try/except/finally: still some things unclear and a lot of code can raise out of try * Fix the notnil build by going back to the old version of a test which I shouldn't have changed * Fix test : use action compile * Work on mutation and aliasing: not finished * Render var parititions graph, try to understand it, fix a nilcheck if bug * Rebase, progress on working with partitions * Improve time logic * Fix some bugs, use graph indices instead of symbol in nil map * Fix bugs, test simpler ident aliasing for now, support two mutation levels * Support ContentMutation and ReAssignment: for now just detect possible re assignment for var parameters of calls * Enable several simple passing tests * Cleanup a bit, fix condition/branch infix-related bug * Remove some files, address some comments by Araq * Use internalError and no quit for now * Separate tests with expected warnings and with expected ok, fix a bug with if with a single branch related to copyMap * Fix new data structures, bugs: make tests pass, disable some for now * Work on fixing errors with non-sym nodes, aliasing: tests fail * Work on alias support: simple set-based logic, todo more tests and ref sets? * Use ref sets: TODO can we think of handle seq-s similar to varpartitions' Araq ones * Handle defers in one place, stop raising in reverse to make an async test compile with strictNotNil, add a commented out test * Dot expressions: call/reassignment. Other refactorings and distinct, SeqOfDistinct support. Checkout an older varpartitions * Work on field tracking * Backup : trying to fix bugs when running some stdlib stuff for running an async test * Start a section about strict not nil checking in experimental manual * Fix experimental strict not nil manual section and move it to another file based on Araq feedback * Fix unstructured flow and double warning problems, fix manual, cleanup * Fix if/elif/else : take in account structure according to Araq feedback * Refactor a bit * Work on bracket expr support, re-enable tests, clarify in manual/tests/implementation static index support for now * Work on compiling stdlib and compiler with strictNotNil * Small fixes to the manual for strictNotNil * Fix idgen for strict check nil rebase * Enable some simple tests, remove old stuff, comment out code/print * Copy the original varpartitions source instead of my changes * Remove some files --- compiler/ast.nim | 13 +- compiler/lineinfos.nim | 3 +- compiler/nilcheck.nim | 1381 ++++++++++++++++++ compiler/options.nim | 3 +- compiler/semobjconstr.nim | 1 + compiler/sempass2.nim | 5 +- compiler/semtypes.nim | 11 +- compiler/treetab.nim | 10 +- compiler/varpartitions.nim | 2 +- doc/manual_experimental.rst | 1 + doc/manual_experimental_strictnotnil.rst | 235 +++ tests/strictnotnil/tnilcheck.nim | 382 +++++ tests/strictnotnil/tnilcheck_no_warnings.nim | 182 +++ 13 files changed, 2215 insertions(+), 14 deletions(-) create mode 100644 compiler/nilcheck.nim create mode 100644 doc/manual_experimental_strictnotnil.rst create mode 100644 tests/strictnotnil/tnilcheck.nim create mode 100644 tests/strictnotnil/tnilcheck_no_warnings.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 4ca5035ed..8acf08284 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1004,7 +1004,7 @@ const ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple, tySequence} NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, - tyProc, tyError} + tyProc, tyError} # TODO PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, skIterator, @@ -1387,6 +1387,7 @@ proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = echo "KNID ", kind writeStackTrace() + proc mergeLoc(a: var TLoc, b: TLoc) = if a.k == low(typeof(a.k)): a.k = b.k if a.storage == low(typeof(a.storage)): a.storage = b.storage @@ -1952,9 +1953,13 @@ proc canRaise*(fn: PNode): bool = elif fn.kind == nkSym and fn.sym.magic == mEcho: result = true else: - result = fn.typ != nil and fn.typ.n != nil and ((fn.typ.n[0].len < effectListLen) or - (fn.typ.n[0][exceptionEffects] != nil and - fn.typ.n[0][exceptionEffects].safeLen > 0)) + # TODO check for n having sons? or just return false for now if not + if fn.typ != nil and fn.typ.n != nil and fn.typ.n[0].kind == nkSym: + result = false + else: + result = fn.typ != nil and fn.typ.n != nil and ((fn.typ.n[0].len < effectListLen) or + (fn.typ.n[0][exceptionEffects] != nil and + fn.typ.n[0][exceptionEffects].safeLen > 0)) proc toHumanStrImpl[T](kind: T, num: static int): string = result = $kind diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index f9ea90caf..9e0fe68fc 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -56,7 +56,7 @@ type warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed", warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition", warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores", - warnUser = "User", + warnUser = "User", warnStrictNotNil = "StrictNotNil", hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", @@ -129,6 +129,7 @@ const warnCycleCreated: "$1", warnObservableStores: "observable stores to '$1'", warnUser: "$1", + warnStrictNotNil: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` hintSuccessX: "${loc} lines; ${sec}s; $mem; $build build; proj: $project; out: $output", diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim new file mode 100644 index 000000000..23f403589 --- /dev/null +++ b/compiler/nilcheck.nim @@ -0,0 +1,1381 @@ +# +# +# The Nim Compiler +# (c) Copyright 2017 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes +import sequtils, strutils, std / sets + +# IMPORTANT: notes not up to date, i'll update this comment again +# +# notes: +# +# Env: int => nilability +# a = b +# nilability a <- nilability b +# deref a +# if Nil error is nil +# if MaybeNil error might be nil, hint add if isNil +# if Safe fine +# fun(arg: A) +# nilability arg <- for ref MaybeNil, for not nil or others Safe +# map is env? +# a or b +# each one forks a different env +# result = union(envL, envR) +# a and b +# b forks a's env +# if a: code +# result = union(previousEnv after not a, env after code) +# if a: b else: c +# result = union(env after b, env after c) +# result = b +# nilability result <- nilability b, if return type is not nil and result not safe, error +# return b +# as result = b +# try: a except: b finally: c +# in b and c env is union of all possible try first n lines, after union of a and b and c +# keep in mind canRaise and finally +# case a: of b: c +# similar to if +# call(arg) +# if it returns ref, assume it's MaybeNil: hint that one can add not nil to the return type +# call(var arg) # zahary comment +# if arg is ref, assume it's MaybeNil after call +# loop +# union of env for 0, 1, 2 iterations as Herb Sutter's paper +# why 2? +# return +# if something: stop (break return etc) +# is equivalent to if something: .. else: remain +# new(ref) +# ref becomes Safe +# objConstr(a: b) +# returns safe +# each check returns its nilability and map + +type + SeqOfDistinct[T, U] = distinct seq[U] + +# TODO use distinct base type instead of int? +func `[]`[T, U](a: SeqOfDistinct[T, U], index: T): U = + (seq[U])(a)[index.int] + +proc `[]=`[T, U](a: var SeqOfDistinct[T, U], index: T, value: U) = + ((seq[U])(a))[index.int] = value + +func `[]`[T, U](a: var SeqOfDistinct[T, U], index: T): var U = + (seq[U])(a)[index.int] + +func len[T, U](a: SeqOfDistinct[T, U]): T = + (seq[U])(a).len.T + +func low[T, U](a: SeqOfDistinct[T, U]): T = + (seq[U])(a).low.T + +func high[T, U](a: SeqOfDistinct[T, U]): T = + (seq[U])(a).high.T + +proc setLen[T, U](a: var SeqOfDistinct[T, U], length: T) = + ((seq[U])(a)).setLen(length.Natural) + + +proc newSeqOfDistinct[T, U](length: T = 0.T): SeqOfDistinct[T, U] = + (SeqOfDistinct[T, U])(newSeq[U](length.int)) + +func newSeqOfDistinct[T, U](length: int = 0): SeqOfDistinct[T, U] = + # newSeqOfDistinct(length.T) + # ? newSeqOfDistinct[T, U](length.T) + (SeqOfDistinct[T, U])(newSeq[U](length)) + +iterator items[T, U](a: SeqOfDistinct[T, U]): U = + for element in (seq[U])(a): + yield element + +iterator pairs[T, U](a: SeqOfDistinct[T, U]): (T, U) = + for i, element in (seq[U])(a): + yield (i.T, element) + +func `$`[T, U](a: SeqOfDistinct[T, U]): string = + $((seq[U])(a)) + +proc add*[T, U](a: var SeqOfDistinct[T, U], value: U) = + ((seq[U])(a)).add(value) + +type + ## a hashed representation of a node: should be equal for structurally equal nodes + Symbol = distinct int + + ## the index of an expression in the pre-indexed sequence of those + ExprIndex = distinct int16 + + ## the set index + SetIndex = distinct int + + ## transition kind: + ## what was the reason for changing the nilability of an expression + ## useful for error messages and showing why an expression is being detected as nil / maybe nil + TransitionKind = enum TArg, TAssign, TType, TNil, TVarArg, TResult, TSafe, TPotentialAlias, TDependant + + ## keep history for each transition + History = object + info: TLineInfo ## the location + nilability: Nilability ## the nilability + kind: TransitionKind ## what kind of transition was that + node: PNode ## the node of the expression + + ## the context for the checker: an instance for each procedure + NilCheckerContext = ref object + # abstractTime: AbstractTime + # partitions: Partitions + # symbolGraphs: Table[Symbol, ] + symbolIndices: Table[Symbol, ExprIndex] ## index for each symbol + expressions: SeqOfDistinct[ExprIndex, PNode] ## a sequence of pre-indexed expressions + dependants: SeqOfDistinct[ExprIndex, IntSet] ## expr indices for expressions which are compound and based on others + warningLocations: HashSet[TLineInfo] ## warning locations to check we don't warn twice for stuff like warnings in for loops + idgen: IdGenerator ## id generator + config: ConfigRef ## the config of the compiler + + ## a map that is containing the current nilability for usually a branch + ## and is pointing optionally to a parent map: they make a stack of maps + NilMap = ref object + expressions: SeqOfDistinct[ExprIndex, Nilability] ## the expressions with the same order as in NilCheckerContext + history: SeqOfDistinct[ExprIndex, seq[History]] ## history for each of them + # what about gc and refs? + setIndices: SeqOfDistinct[ExprIndex, SetIndex] ## set indices for each expression + sets: SeqOfDistinct[SetIndex, IntSet] ## disjoint sets with the aliased expressions + parent: NilMap ## the parent map + + ## Nilability : if a value is nilable. + ## we have maybe nil and nil, so we can differentiate between + ## cases where we know for sure a value is nil and not + ## otherwise we can have Safe, MaybeNil + ## Parent: is because we just use a sequence with the same length + ## instead of a table, and we need to check if something was initialized + ## at all: if Parent is set, then you need to check the parent nilability + ## if the parent is nil, then for now we return MaybeNil + ## unreachable is the result of add(Safe, Nil) and others + ## it is a result of no states left, so it's usually e.g. in unreachable else branches? + Nilability* = enum Parent, Safe, MaybeNil, Nil, Unreachable + + ## check + Check = object + nilability: Nilability + map: NilMap + elements: seq[(PNode, Nilability)] + + +# useful to have known resultId so we can set it in the beginning and on return +const resultId: Symbol = (-1).Symbol +const resultExprIndex: ExprIndex = 0.ExprIndex +const noSymbol = (-2).Symbol + +func `<`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 < b.int16 + +func `<=`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 <= b.int16 + +func `>`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 > b.int16 + +func `>=`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 >= b.int16 + +func `==`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 == b.int16 + +func `$`*(a: ExprIndex): string = + $(a.int16) + +func `+`*(a: ExprIndex, b: ExprIndex): ExprIndex = + (a.int16 + b.int16).ExprIndex + +# TODO overflowing / < 0? +func `-`*(a: ExprIndex, b: ExprIndex): ExprIndex = + (a.int16 - b.int16).ExprIndex + +func `$`*(a: SetIndex): string = + $(a.int) + +func `==`*(a: SetIndex, b: SetIndex): bool = + a.int == b.int + +func `+`*(a: SetIndex, b: SetIndex): SetIndex = + (a.int + b.int).SetIndex + +# TODO over / under limit? +func `-`*(a: SetIndex, b: SetIndex): SetIndex = + (a.int - b.int).SetIndex + +proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check +proc checkCondition(n: PNode, ctx: NilCheckerContext, map: NilMap, reverse: bool, base: bool): NilMap + +# the NilMap structure + +proc newNilMap(parent: NilMap = nil, count: int = -1): NilMap = + var expressionsCount = 0 + if count != -1: + expressionsCount = count + elif not parent.isNil: + expressionsCount = parent.expressions.len.int + result = NilMap( + expressions: newSeqOfDistinct[ExprIndex, Nilability](expressionsCount), + history: newSeqOfDistinct[ExprIndex, seq[History]](expressionsCount), + setIndices: newSeqOfDistinct[ExprIndex, SetIndex](expressionsCount), + parent: parent) + if parent.isNil: + for i, expr in result.expressions: + result.setIndices[i] = i.SetIndex + var newSet = initIntSet() + newSet.incl(i.int) + result.sets.add(newSet) + else: + for i, exprs in parent.sets: + result.sets.add(exprs) + for i, index in parent.setIndices: + result.setIndices[i] = index + # result.sets = parent.sets + # if not parent.isNil: + # # optimize []? + # result.expressions = parent.expressions + # result.history = parent.history + # result.sets = parent.sets + # result.base = if parent.isNil: result else: parent.base + +proc `[]`(map: NilMap, index: ExprIndex): Nilability = + if index < 0.ExprIndex or index >= map.expressions.len: + return MaybeNil + var now = map + while not now.isNil: + if now.expressions[index] != Parent: + return now.expressions[index] + now = now.parent + return MaybeNil + +proc history(map: NilMap, index: ExprIndex): seq[History] = + if index < map.expressions.len: + map.history[index] + else: + @[] + + +# helpers for debugging + +# import macros + +# echo-s only when nilDebugInfo is defined +# macro aecho*(a: varargs[untyped]): untyped = +# var e = nnkCall.newTree(ident"echo") +# for b in a: +# e.add(b) +# result = quote: +# when defined(nilDebugInfo): +# `e` + +# end of helpers for debugging + + +proc symbol(n: PNode): Symbol +func `$`(map: NilMap): string +proc reverseDirect(map: NilMap): NilMap +proc checkBranch(n: PNode, ctx: NilCheckerContext, map: NilMap): Check +proc hasUnstructuredControlFlowJump(n: PNode): bool + +proc symbol(n: PNode): Symbol = + ## returns a Symbol for each expression + ## the goal is to get an unique Symbol + ## but we have to ensure hashTree does it as we expect + case n.kind: + of nkIdent: + # TODO ensure no idents get passed to symbol + result = noSymbol + of nkSym: + if n.sym.kind == skResult: # credit to disruptek for showing me that + result = resultId + else: + result = n.sym.id.Symbol + of nkHiddenAddr, nkAddr: + result = symbol(n[0]) + else: + result = hashTree(n).Symbol + # echo "symbol ", n, " ", n.kind, " ", result.int + +func `$`(map: NilMap): string = + var now = map + var stack: seq[NilMap] = @[] + while not now.isNil: + stack.add(now) + now = now.parent + result.add("### start\n") + for i in 0 .. stack.len - 1: + now = stack[i] + result.add(" ###\n") + for index, value in now.expressions: + result.add(&" {index} {value}\n") + result.add "### end\n" + +proc namedMapDebugInfo(ctx: NilCheckerContext, map: NilMap): string = + result = "" + var now = map + var stack: seq[NilMap] = @[] + while not now.isNil: + stack.add(now) + now = now.parent + result.add("### start\n") + for i in 0 .. stack.len - 1: + now = stack[i] + result.add(" ###\n") + for index, value in now.expressions: + let name = ctx.expressions[index] + result.add(&" {name} {index} {value}\n") + result.add("### end\n") + +proc namedSetsDebugInfo(ctx: NilCheckerContext, map: NilMap): string = + result = "### sets " + for index, setIndex in map.setIndices: + var aliasSet = map.sets[setIndex] + result.add("{") + let expressions = aliasSet.mapIt($ctx.expressions[it.ExprIndex]) + result.add(join(expressions, ", ")) + result.add("} ") + result.add("\n") + +proc namedMapAndSetsDebugInfo(ctx: NilCheckerContext, map: NilMap): string = + result = namedMapDebugInfo(ctx, map) & namedSetsDebugInfo(ctx, map) + + + +const noExprIndex = (-1).ExprIndex +const noSetIndex = (-1).SetIndex + +proc `==`(a: Symbol, b: Symbol): bool = + a.int == b.int + +func `$`(a: Symbol): string = + $(a.int) + +template isConstBracket(n: PNode): bool = + n.kind == nkBracketExpr and n[1].kind in nkLiterals + +proc index(ctx: NilCheckerContext, n: PNode): ExprIndex = + # echo "n ", n, " ", n.kind + let a = symbol(n) + if ctx.symbolIndices.hasKey(a): + return ctx.symbolIndices[a] + else: + #for a, e in ctx.expressions: + # echo a, " ", e + #echo n.kind + # internalError(ctx.config, n.info, "expected " & $a & " " & $n & " to have a index") + return noExprIndex + # + #ctx.symbolIndices[symbol(n)] + + +proc aliasSet(ctx: NilCheckerContext, map: NilMap, n: PNode): IntSet = + result = map.sets[map.setIndices[ctx.index(n)]] + +proc aliasSet(ctx: NilCheckerContext, map: NilMap, index: ExprIndex): IntSet = + result = map.sets[map.setIndices[index]] + + + +proc store(map: NilMap, ctx: NilCheckerContext, index: ExprIndex, value: Nilability, kind: TransitionKind, info: TLineInfo, node: PNode = nil) = + if index == noExprIndex: + return + map.expressions[index] = value + map.history[index].add(History(info: info, kind: kind, node: node, nilability: value)) + #echo node, " ", index, " ", value + #echo ctx.namedMapAndSetsDebugInfo(map) + #for a, b in map.sets: + # echo a, " ", b + # echo map + + var exprAliases = aliasSet(ctx, map, index) + for a in exprAliases: + if a.ExprIndex != index: + #echo "alias ", a, " ", index + map.expressions[a.ExprIndex] = value + if value == Safe: + map.history[a.ExprIndex] = @[] + else: + map.history[a.ExprIndex].add(History(info: info, kind: TPotentialAlias, node: node, nilability: value)) + +proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) = + #echo "move out ", target + var targetIndex = ctx.index(target) + var targetSetIndex = map.setIndices[targetIndex] + if targetSetIndex != noSetIndex: + var targetSet = map.sets[targetSetIndex] + if targetSet.len > 1: + var other: ExprIndex + + for element in targetSet: + if element.ExprIndex != targetIndex: + other = element.ExprIndex + break + # map.sets[element].excl(targetIndex) + map.sets[map.setIndices[other]].excl(targetIndex.int) + var newSet = initIntSet() + newSet.incl(targetIndex.int) + map.sets.add(newSet) + map.setIndices[targetIndex] = map.sets.len - 1.SetIndex + +proc moveOutDependants(ctx: NilCheckerContext, map: NilMap, node: PNode) = + let index = ctx.index(node) + for dependant in ctx.dependants[index]: + moveOut(ctx, map, ctx.expressions[dependant.ExprIndex]) + +proc storeDependants(ctx: NilCheckerContext, map: NilMap, node: PNode, value: Nilability) = + let index = ctx.index(node) + for dependant in ctx.dependants[index]: + map.store(ctx, dependant.ExprIndex, value, TDependant, node.info, node) + +proc move(ctx: NilCheckerContext, map: NilMap, target: PNode, assigned: PNode) = + #echo "move ", target, " ", assigned + var targetIndex = ctx.index(target) + var assignedIndex: ExprIndex + var targetSetIndex = map.setIndices[targetIndex] + var assignedSetIndex: SetIndex + if assigned.kind == nkSym: + assignedIndex = ctx.index(assigned) + assignedSetIndex = map.setIndices[assignedIndex] + else: + assignedIndex = noExprIndex + assignedSetIndex = noSetIndex + if assignedIndex == noExprIndex: + moveOut(ctx, map, target) + elif targetSetIndex != assignedSetIndex: + map.sets[targetSetIndex].excl(targetIndex.int) + map.sets[assignedSetIndex].incl(targetIndex.int) + map.setIndices[targetIndex] = assignedSetIndex + +# proc hasKey(map: NilMap, ): bool = +# var now = map +# result = false +# while not now.isNil: +# if now.locals.hasKey(graphIndex): +# return true +# now = now.previous + +iterator pairs(map: NilMap): (ExprIndex, Nilability) = + for index, value in map.expressions: + yield (index, map[index]) + +proc copyMap(map: NilMap): NilMap = + if map.isNil: + return nil + result = newNilMap(map.parent) # no need for copy? if we change only this + result.expressions = map.expressions + result.history = map.history + result.sets = map.sets + result.setIndices = map.setIndices + +using + n: PNode + conf: ConfigRef + ctx: NilCheckerContext + map: NilMap + +proc typeNilability(typ: PType): Nilability + +# maybe: if canRaise, return MaybeNil ? +# no, because the target might be safe already +# with or without an exception +proc checkCall(n, ctx, map): Check = + # checks each call + # special case for new(T) -> result is always Safe + # for the others it depends on the return type of the call + # check args and handle possible mutations + + var isNew = false + result.map = map + for i, child in n: + discard check(child, ctx, map) + + if i > 0: + # var args make a new map with MaybeNil for our node + # as it might have been mutated + # TODO similar for normal refs and fields: find dependent exprs: brackets + + if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ[0].kind == tyRef: + if not isNew: + result.map = newNilMap(map) + isNew = true + # result.map[$child] = MaybeNil + var arg = child + while arg.kind == nkHiddenAddr: + arg = arg[0] + let a = ctx.index(arg) + if a != noExprIndex: + moveOut(ctx, result.map, arg) + moveOutDependants(ctx, result.map, arg) + result.map.store(ctx, a, MaybeNil, TVarArg, n.info, arg) + storeDependants(ctx, result.map, arg, MaybeNil) + elif not child.typ.isNil and child.typ.kind == tyRef: + if child.kind in {nkSym, nkDotExpr} or isConstBracket(child): + let a = ctx.index(child) + if ctx.dependants[a].len > 0: + if not isNew: + result.map = newNilMap(map) + isNew = true + moveOutDependants(ctx, result.map, child) + storeDependants(ctx, result.map, child, MaybeNil) + + if n[0].kind == nkSym and n[0].sym.magic == mNew: + # new hidden deref? + var value = if n[1].kind == nkHiddenDeref: n[1][0] else: n[1] + let b = ctx.index(value) + result.map.store(ctx, b, Safe, TAssign, value.info, value) + result.nilability = Safe + else: + # echo "n ", n, " ", n.typ.isNil + if not n.typ.isNil: + result.nilability = typeNilability(n.typ) + else: + result.nilability = Safe + # echo result.map + +template event(b: History): string = + case b.kind: + of TArg: "param with nilable type" + of TNil: "it returns true for isNil" + of TAssign: "assigns a value which might be nil" + of TVarArg: "passes it as a var arg which might change to nil" + of TResult: "it is nil by default" + of TType: "it has ref type" + of TSafe: "it is safe here as it returns false for isNil" + of TPotentialAlias: "it might be changed directly or through an alias" + of TDependant: "it might be changed because its base might be changed" + +proc derefWarning(n, ctx, map; kind: Nilability) = + ## a warning for potentially unsafe dereference + if n.info in ctx.warningLocations: + return + ctx.warningLocations.incl(n.info) + var a: seq[History] + if n.kind == nkSym: + a = history(map, ctx.index(n)) + var res = "" + var issue = case kind: + of Nil: "it is nil" + of MaybeNil: "it might be nil" + of Unreachable: "it is unreachable" + else: "" + res.add("can't deref " & $n & ", " & issue) + if a.len > 0: + res.add("\n") + for b in a: + res.add(" " & event(b) & " on line " & $b.info.line & ":" & $b.info.col) + message(ctx.config, n.info, warnStrictNotNil, res) + +proc handleNilability(check: Check; n, ctx, map) = + ## handle the check: + ## register a warning(error?) for Nil/MaybeNil + case check.nilability: + of Nil: + derefWarning(n, ctx, map, Nil) + of MaybeNil: + derefWarning(n, ctx, map, MaybeNil) + of Unreachable: + derefWarning(n, ctx, map, Unreachable) + else: + when defined(nilDebugInfo): + message(ctx.config, n.info, hintUser, "can deref " & $n) + +proc checkDeref(n, ctx, map): Check = + ## check dereference: deref n should be ok only if n is Safe + result = check(n[0], ctx, map) + + handleNilability(result, n[0], ctx, map) + + +proc checkRefExpr(n, ctx; check: Check): Check = + ## check ref expressions: TODO not sure when this happens + result = check + if n.typ.kind != tyRef: + result.nilability = typeNilability(n.typ) + elif tfNotNil notin n.typ.flags: + # echo "ref key ", n, " ", n.kind + if n.kind in {nkSym, nkDotExpr} or isConstBracket(n): + let key = ctx.index(n) + result.nilability = result.map[key] + elif n.kind == nkBracketExpr: + # sometimes false positive + result.nilability = MaybeNil + else: + # sometimes maybe false positive + result.nilability = MaybeNil + +proc checkDotExpr(n, ctx, map): Check = + ## check dot expressions: make sure we can dereference the base + result = check(n[0], ctx, map) + result = checkRefExpr(n, ctx, result) + +proc checkBracketExpr(n, ctx, map): Check = + ## check bracket expressions: make sure we can dereference the base + result = check(n[0], ctx, map) + # if might be deref: [] == *(a + index) for cstring + handleNilability(result, n[0], ctx, map) + result = check(n[1], ctx, result.map) + result = checkRefExpr(n, ctx, result) + # echo n, " ", result.nilability + + +template union(l: Nilability, r: Nilability): Nilability = + ## unify two states + if l == r: + l + else: + MaybeNil + +template add(l: Nilability, r: Nilability): Nilability = + if l == r: # Safe Safe -> Safe etc + l + elif l == Parent: # Parent Safe -> Safe etc + r + elif r == Parent: # Safe Parent -> Safe etc + l + elif l == Unreachable or r == Unreachable: # Safe Unreachable -> Unreachable etc + Unreachable + elif l == MaybeNil: # Safe MaybeNil -> Safe etc + r + elif r == MaybeNil: # MaybeNil Nil -> Nil etc + l + else: # Safe Nil -> Unreachable etc + Unreachable + +proc findCommonParent(l: NilMap, r: NilMap): NilMap = + result = l.parent + while not result.isNil: + var rparent = r.parent + while not rparent.isNil: + if result == rparent: + return result + rparent = rparent.parent + result = result.parent + +proc union(ctx: NilCheckerContext, l: NilMap, r: NilMap): NilMap = + ## unify two maps from different branches + ## combine their locals + ## what if they are from different parts of the same tree + ## e.g. + ## a -> b -> c + ## -> b1 + ## common then? + ## + if l.isNil: + return r + elif r.isNil: + return l + + let common = findCommonParent(l, r) + result = newNilMap(common, ctx.expressions.len.int) + + for index, value in l: + let h = history(r, index) + let info = if h.len > 0: h[^1].info else: TLineInfo(line: 0) # assert h.len > 0 + # echo "history", name, value, r[name], h[^1].info.line + result.store(ctx, index, union(value, r[index]), TAssign, info) + +proc add(ctx: NilCheckerContext, l: NilMap, r: NilMap): NilMap = + #echo "add " + #echo namedMapDebugInfo(ctx, l) + #echo " : " + #echo namedMapDebugInfo(ctx, r) + if l.isNil: + return r + elif r.isNil: + return l + + let common = findCommonParent(l, r) + result = newNilMap(common, ctx.expressions.len.int) + + for index, value in l: + let h = history(r, index) + let info = if h.len > 0: h[^1].info else: TLineInfo(line: 0) + # TODO: refactor and also think: is TAssign a good one + result.store(ctx, index, add(value, r[index]), TAssign, info) + + #echo "result" + #echo namedMapDebugInfo(ctx, result) + #echo "" + #echo "" + + +proc checkAsgn(target: PNode, assigned: PNode; ctx, map): Check = + ## check assignment + ## update map based on `assigned` + if assigned.kind != nkEmpty: + result = check(assigned, ctx, map) + else: + result = Check(nilability: typeNilability(target.typ), map: map) + + # we need to visit and check those, but we don't use the result for now + # is it possible to somehow have another event happen here? + discard check(target, ctx, map) + + if result.map.isNil: + result.map = map + if target.kind in {nkSym, nkDotExpr} or isConstBracket(target): + let t = ctx.index(target) + move(ctx, map, target, assigned) + case assigned.kind: + of nkNilLit: + result.map.store(ctx, t, Nil, TAssign, target.info, target) + else: + result.map.store(ctx, t, result.nilability, TAssign, target.info, target) + moveOutDependants(ctx, map, target) + storeDependants(ctx, map, target, MaybeNil) + if assigned.kind in {nkObjConstr, nkTupleConstr}: + for (element, value) in result.elements: + var elementNode = nkDotExpr.newTree(nkHiddenDeref.newTree(target), element) + if symbol(elementNode) in ctx.symbolIndices: + var elementIndex = ctx.index(elementNode) + result.map.store(ctx, elementIndex, value, TAssign, target.info, elementNode) + + +proc checkReturn(n, ctx, map): Check = + ## check return + # return n same as result = n; return ? + result = check(n[0], ctx, map) + result.map.store(ctx, resultExprIndex, result.nilability, TAssign, n.info) + + +proc checkIf(n, ctx, map): Check = + ## check branches based on condition + var mapIf: NilMap = map + + # first visit the condition + + # the structure is not If(Elif(Elif, Else), Else) + # it is + # If(Elif, Elif, Else) + + var mapCondition = checkCondition(n.sons[0].sons[0], ctx, mapIf, false, true) + + # the state of the conditions: negating conditions before the current one + var layerHistory = newNilMap(mapIf) + # the state after branch effects + var afterLayer: NilMap + # the result nilability for expressions + var nilability = Safe + + for branch in n.sons: + var branchConditionLayer = newNilMap(layerHistory) + var branchLayer: NilMap + var code: PNode + if branch.kind in {nkIfStmt, nkElifBranch}: + var mapCondition = checkCondition(branch[0], ctx, branchConditionLayer, false, true) + let reverseMapCondition = reverseDirect(mapCondition) + layerHistory = ctx.add(layerHistory, reverseMapCondition) + branchLayer = mapCondition + code = branch[1] + else: + branchLayer = layerHistory + code = branch + + let branchCheck = checkBranch(code, ctx, branchLayer) + # handles nil afterLayer -> returns branchCheck.map + afterLayer = ctx.union(afterLayer, branchCheck.map) + nilability = if n.kind == nkIfStmt: Safe else: union(nilability, branchCheck.nilability) + if n.sons.len > 1: + result.map = afterLayer + result.nilability = nilability + else: + if not hasUnstructuredControlFlowJump(n[0][1]): + # here it matters what happend inside, because + # we might continue in the parent branch after entering this one + # either we enter the branch, so we get mapIf and effect of branch -> afterLayer + # or we dont , so we get mapIf and (not condition) effect -> layerHistory + result.map = ctx.union(layerHistory, afterLayer) + result.nilability = Safe # no expr? + else: + # similar to else: because otherwise we are jumping out of + # the branch, so no union with the mapIf (we dont continue if the condition was true) + # here it also doesn't matter for the parent branch what happened in the branch, e.g. assigning to nil + # as if we continue there, we haven't entered the branch probably + # so we don't do an union with afterLayer + # layerHistory has the effect of mapIf and (not condition) + result.map = layerHistory + result.nilability = Safe + +proc checkFor(n, ctx, map): Check = + ## check for loops + ## try to repeat the unification of the code twice + ## to detect what can change after a several iterations + ## approach based on discussions with Zahary/Araq + ## similar approach used for other loops + var m = map.copyMap() + var map0 = map.copyMap() + #echo namedMapDebugInfo(ctx, map) + m = check(n.sons[2], ctx, map).map.copyMap() + if n[0].kind == nkSym: + m.store(ctx, ctx.index(n[0]), typeNilability(n[0].typ), TAssign, n[0].info) + # echo namedMapDebugInfo(ctx, map) + var check2 = check(n.sons[2], ctx, m) + var map2 = check2.map + + result.map = ctx.union(map0, m) + result.map = ctx.union(result.map, map2) + result.nilability = Safe + +# check: +# while code: +# code2 + +# if code: +# code2 +# if code: +# code2 + +# if code: +# code2 + +# check(code), check(code2 in code's map) + +proc checkWhile(n, ctx, map): Check = + ## check while loops + ## try to repeat the unification of the code twice + var m = checkCondition(n[0], ctx, map, false, false) + var map0 = map.copyMap() + m = check(n.sons[1], ctx, m).map + var map1 = m.copyMap() + var check2 = check(n.sons[1], ctx, m) + var map2 = check2.map + + result.map = ctx.union(map0, map1) + result.map = ctx.union(result.map, map2) + result.nilability = Safe + +proc checkInfix(n, ctx, map): Check = + ## check infix operators in condition + ## a and b : map is based on a; next b + ## a or b : map is an union of a and b's + ## a == b : use checkCondition + ## else: no change, just check args + if n[0].kind == nkSym: + var mapL: NilMap + var mapR: NilMap + if n[0].sym.magic notin {mAnd, mEqRef}: + mapL = checkCondition(n[1], ctx, map, false, false) + mapR = checkCondition(n[2], ctx, map, false, false) + case n[0].sym.magic: + of mOr: + result.map = ctx.union(mapL, mapR) + of mAnd: + result.map = checkCondition(n[1], ctx, map, false, false) + result.map = checkCondition(n[2], ctx, result.map, false, false) + of mEqRef: + if n[2].kind == nkIntLit: + if $n[2] == "true": + result.map = checkCondition(n[1], ctx, map, false, false) + elif $n[2] == "false": + result.map = checkCondition(n[1], ctx, map, true, false) + elif n[1].kind == nkIntLit: + if $n[1] == "true": + result.map = checkCondition(n[2], ctx, map, false, false) + elif $n[1] == "false": + result.map = checkCondition(n[2], ctx, map, true, false) + + if result.map.isNil: + result.map = map + else: + result.map = map + else: + result.map = map + result.nilability = Safe + +proc checkIsNil(n, ctx, map; isElse: bool = false): Check = + ## check isNil calls + ## update the map depending on if it is not isNil or isNil + result.map = newNilMap(map) + let value = n[1] + result.map.store(ctx, ctx.index(n[1]), if not isElse: Nil else: Safe, TArg, n.info, n) + +proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode = + var name = case magic: + of mEqRef: "==" + of mAnd: "and" + of mOr: "or" + else: "" + + var cache = newIdentCache() + var op = newSym(skVar, cache.getIdent(name), nextId ctx.idgen, nil, r.info) + + op.magic = magic + result = nkInfix.newTree( + newSymNode(op, r.info), + l, + r) + result.typ = newType(tyBool, nextId ctx.idgen, nil) + +proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode = + var cache = newIdentCache() + var op = newSym(skVar, cache.getIdent("not"), nextId ctx.idgen, nil, node.info) + + op.magic = mNot + result = nkPrefix.newTree( + newSymNode(op, node.info), + node) + result.typ = newType(tyBool, nextId ctx.idgen, nil) + +proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode = + infix(ctx, l, r, mEqRef) + +proc infixOr(ctx: NilCheckerContext, l: PNode, r: PNode): PNode = + infix(ctx, l, r, mOr) + +proc checkCase(n, ctx, map): Check = + # case a: + # of b: c + # of b2: c2 + # is like + # if a == b: + # c + # elif a == b2: + # c2 + # also a == true is a , a == false is not a + let base = n[0] + result.map = map.copyMap() + result.nilability = Safe + var a: PNode + for child in n: + case child.kind: + of nkOfBranch: + if child.len < 2: + # echo "case with of with < 2 ", n + continue # TODO why does this happen + let branchBase = child[0] # TODO a, b or a, b..c etc + let code = child[^1] + let test = infixEq(ctx, base, branchBase) + if a.isNil: + a = test + else: + a = infixOr(ctx, a, test) + let conditionMap = checkCondition(test, ctx, map.copyMap(), false, false) + let newCheck = checkBranch(code, ctx, conditionMap) + result.map = ctx.union(result.map, newCheck.map) + result.nilability = union(result.nilability, newCheck.nilability) + of nkElifBranch: + discard "TODO: maybe adapt to be similar to checkIf" + of nkElse: + let mapElse = checkCondition(prefixNot(ctx, a), ctx, map.copyMap(), false, false) + let newCheck = checkBranch(child[0], ctx, mapElse) + result.map = ctx.union(result.map, newCheck.map) + result.nilability = union(result.nilability, newCheck.nilability) + else: + discard + +# notes +# try: +# a +# b +# except: +# c +# finally: +# d +# +# if a doesnt raise, this is not an exit point: +# so find what raises and update the map with that +# (a, b); c; d +# if nothing raises, except shouldn't happen +# .. might be a false positive tho, if canRaise is not conservative? +# so don't visit it +# +# nested nodes can raise as well: I hope nim returns canRaise for +# their parents +# +# a lot of stuff can raise +proc checkTry(n, ctx, map): Check = + var newMap = map.copyMap() + var currentMap = map + # we don't analyze except if nothing canRaise in try + var canRaise = false + var hasFinally = false + # var tryNodes: seq[PNode] + # if n[0].kind == nkStmtList: + # tryNodes = toSeq(n[0]) + # else: + # tryNodes = @[n[0]] + # for i, child in tryNodes: + # let (childNilability, childMap) = check(child, conf, currentMap) + # echo childMap + # currentMap = childMap + # # TODO what about nested + # if child.canRaise: + # newMap = union(newMap, childMap) + # canRaise = true + # else: + # newMap = childMap + let tryCheck = check(n[0], ctx, currentMap) + newMap = ctx.union(currentMap, tryCheck.map) + canRaise = n[0].canRaise + + var afterTryMap = newMap + for a, branch in n: + if a > 0: + case branch.kind: + of nkFinally: + newMap = ctx.union(afterTryMap, newMap) + let childCheck = check(branch[0], ctx, newMap) + newMap = ctx.union(newMap, childCheck.map) + hasFinally = true + of nkExceptBranch: + if canRaise: + let childCheck = check(branch[^1], ctx, newMap) + newMap = ctx.union(newMap, childCheck.map) + else: + discard + if not hasFinally: + # we might have not hit the except branches + newMap = ctx.union(afterTryMap, newMap) + result = Check(nilability: Safe, map: newMap) + +proc hasUnstructuredControlFlowJump(n: PNode): bool = + ## if the node contains a direct stop + ## as a continue/break/raise/return: then it means + ## we should reverse some of the map in the code after the condition + ## similar to else + # echo "n ", n, " ", n.kind + case n.kind: + of nkStmtList: + for child in n: + if hasUnstructuredControlFlowJump(child): + return true + of nkReturnStmt, nkBreakStmt, nkContinueStmt, nkRaiseStmt: + return true + of nkIfStmt, nkIfExpr, nkElifExpr, nkElse: + return false + else: + discard + return false + +proc reverse(value: Nilability): Nilability = + case value: + of Nil: Safe + of MaybeNil: MaybeNil + of Safe: Nil + of Parent: Parent + of Unreachable: Unreachable + +proc reverse(kind: TransitionKind): TransitionKind = + case kind: + of TNil: TSafe + of TSafe: TNil + of TPotentialAlias: TPotentialAlias + else: + kind + # raise newException(ValueError, "expected TNil or TSafe") + +proc reverseDirect(map: NilMap): NilMap = + # we create a new layer + # reverse the values only in this layer: + # because conditions should've stored their changes there + # b: Safe (not b.isNil) + # b: Parent Parent + # b: Nil (b.isNil) + + # layer block + # [ Parent ] [ Parent ] + # if -> if state + # layer -> reverse + # older older0 new + # older new + # [ b Nil ] [ Parent ] + # elif + # [ b Nil, c Nil] [ Parent ] + # + + # if b.isNil: + # # [ b Safe] + # c = A() # Safe + # elif not b.isNil: + # # [ b Safe ] + [b Nil] MaybeNil Unreachable + # # Unreachable defer can't deref b, it is unreachable + # discard + # else: + # b + + +# if + + + + # if: we just pass the map with a new layer for its block + # elif: we just pass the original map but with a new layer is the reverse of the previous popped layer (?) + # elif: + # else: we just pass the original map but with a new layer which is initialized as the reverse of the + # top layer of else + # else: + # + # [ b MaybeNil ] [b Parent] [b Parent] [b Safe] [b Nil] [] + # Safe + # c == 1 + # b Parent + # c == 2 + # b Parent + # not b.isNil + # b Safe + # c == 3 + # b Nil + # (else) + # b Nil + + result = map.copyMap() + for index, value in result.expressions: + result.expressions[index] = reverse(value) + if result.history[index].len > 0: + result.history[index][^1].kind = reverse(result.history[index][^1].kind) + result.history[index][^1].nilability = result.expressions[index] + +proc checkCondition(n, ctx, map; reverse: bool, base: bool): NilMap = + ## check conditions : used for if, some infix operators + ## isNil(a) + ## it returns a new map: you need to reverse all the direct elements for else + + # echo "condition ", n, " ", n.kind + if n.kind == nkCall: + result = newNilMap(map) + for element in n: + if element.kind == nkHiddenDeref and n[0].kind == nkSym and n[0].sym.magic == mIsNil: + result = check(element[0], ctx, result).map + else: + result = check(element, ctx, result).map + + if n[0].kind == nkSym and n[0].sym.magic == mIsNil: + # isNil(arg) + var arg = n[1] + while arg.kind == nkHiddenDeref: + arg = arg[0] + if arg.kind in {nkSym, nkDotExpr} or isConstBracket(arg): + let a = ctx.index(arg) + result.store(ctx, a, if not reverse: Nil else: Safe, if not reverse: TNil else: TSafe, n.info, arg) + else: + discard + else: + discard + elif n.kind == nkPrefix and n[0].kind == nkSym and n[0].sym.magic == mNot: + result = checkCondition(n[1], ctx, map, not reverse, false) + elif n.kind == nkInfix: + result = newNilMap(map) + result = checkInfix(n, ctx, result).map + else: + result = check(n, ctx, map).map + result = newNilMap(map) + assert not result.isNil + assert not result.parent.isNil + +proc checkResult(n, ctx, map) = + let resultNilability = map[resultExprIndex] + case resultNilability: + of Nil: + message(ctx.config, n.info, warnStrictNotNil, "return value is nil") + of MaybeNil: + message(ctx.config, n.info, warnStrictNotNil, "return value might be nil") + of Unreachable: + message(ctx.config, n.info, warnStrictNotNil, "return value is unreachable") + of Safe, Parent: + discard + +proc checkBranch(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = + result = check(n, ctx, map) + + +# Faith! + +proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = + assert not map.isNil + + # echo "check n ", n, " ", n.kind + # echo "map ", namedMapDebugInfo(ctx, map) + case n.kind: + of nkSym: + result = Check(nilability: map[ctx.index(n)], map: map) + of nkCallKinds: + if n.sons[0].kind == nkSym: + let callSym = n.sons[0].sym + case callSym.magic: + of mAnd, mOr: + result = checkInfix(n, ctx, map) + of mIsNil: + result = checkIsNil(n, ctx, map) + else: + result = checkCall(n, ctx, map) + else: + result = checkCall(n, ctx, map) + of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkExprColonExpr, nkExprEqExpr, + nkCast: + result = check(n.sons[1], ctx, map) + of nkStmtList, nkStmtListExpr, nkChckRangeF, nkChckRange64, nkChckRange, + nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkElse: + result.map = map + if n.kind in {nkObjConstr, nkTupleConstr}: + # TODO deeper nested elements? + # A(field: B()) # + # field: Safe -> + var elements: seq[(PNode, Nilability)] + for i, child in n: + result = check(child, ctx, result.map) + if i > 0: + if child.kind == nkExprColonExpr: + elements.add((child[0], result.nilability)) + result.elements = elements + result.nilability = Safe + else: + for child in n: + result = check(child, ctx, result.map) + + of nkDotExpr: + result = checkDotExpr(n, ctx, map) + of nkDerefExpr, nkHiddenDeref: + result = checkDeref(n, ctx, map) + of nkAddr, nkHiddenAddr: + result = check(n.sons[0], ctx, map) + of nkIfStmt, nkIfExpr: + result = checkIf(n, ctx, map) + of nkAsgn: + result = checkAsgn(n[0], n[1], ctx, map) + of nkVarSection: + result.map = map + for child in n: + result = checkAsgn(child[0], child[2], ctx, result.map) + of nkForStmt: + result = checkFor(n, ctx, map) + of nkCaseStmt: + result = checkCase(n, ctx, map) + of nkReturnStmt: + result = checkReturn(n, ctx, map) + of nkBracketExpr: + result = checkBracketExpr(n, ctx, map) + of nkTryStmt: + result = checkTry(n, ctx, map) + of nkWhileStmt: + result = checkWhile(n, ctx, map) + of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, + nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, + nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: + + discard "don't follow this : same as varpartitions" + result = Check(nilability: Nil, map: map) + else: + + var elementMap = map.copyMap() + var elementCheck: Check + elementCheck.map = elementMap + for element in n: + elementCheck = check(element, ctx, elementCheck.map) + + result = Check(nilability: Nil, map: elementCheck.map) + + + + +proc typeNilability(typ: PType): Nilability = + assert not typ.isNil + # echo "typeNilability ", $typ.flags, " ", $typ.kind + result = if tfNotNil in typ.flags: + Safe + elif typ.kind in {tyRef, tyCString, tyPtr, tyPointer}: + # + # tyVar ? tyVarargs ? tySink ? tyLent ? + # TODO spec? tests? + MaybeNil + else: + Safe + # echo " result ", result + +proc preVisitNode(ctx: NilCheckerContext, node: PNode, conf: ConfigRef) = + # echo "visit node ", node + if node.kind in {nkSym, nkDotExpr} or isConstBracket(node): + let nodeSymbol = symbol(node) + if not ctx.symbolIndices.hasKey(nodeSymbol): + ctx.symbolIndices[nodeSymbol] = ctx.expressions.len + ctx.expressions.add(node) + if node.kind in {nkDotExpr, nkBracketExpr}: + if node.kind == nkDotExpr and (not node.typ.isNil and node.typ.kind == tyRef and tfNotNil notin node.typ.flags) or + node.kind == nkBracketExpr: + let index = ctx.symbolIndices[nodeSymbol] + var baseIndex = noExprIndex + # deref usually? + # ok, we hit another case + var base = if node[0].kind notin {nkSym, nkIdent}: node[0][0] else: node[0] + if base.kind != nkIdent: + let baseSymbol = symbol(base) + if not ctx.symbolIndices.hasKey(baseSymbol): + baseIndex = ctx.expressions.len # next visit should add it + else: + baseIndex = ctx.symbolIndices[baseSymbol] + if ctx.dependants.len <= baseIndex: + ctx.dependants.setLen(baseIndex + 1.ExprIndex) + ctx.dependants[baseIndex].incl(index.int) + case node.kind: + of nkSym, nkEmpty, nkNilLit, nkType, nkIdent, nkCharLit .. nkUInt64Lit, nkFloatLit .. nkFloat64Lit, nkStrLit .. nkTripleStrLit: + discard + of nkDotExpr: + # visit only the base + ctx.preVisitNode(node[0], conf) + else: + for element in node: + ctx.preVisitNode(element, conf) + +proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) = + ctx.symbolIndices = {resultId: resultExprIndex}.toTable() + var cache = newIdentCache() + ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)]) + var emptySet: IntSet # set[ExprIndex] + ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet]) + for i, arg in s.typ.n.sons: + if i > 0: + if arg.kind != nkSym: + continue + let argSymbol = symbol(arg) + if not ctx.symbolIndices.hasKey(argSymbol): + ctx.symbolIndices[argSymbol] = ctx.expressions.len + ctx.expressions.add(arg) + ctx.preVisitNode(body, conf) + if ctx.dependants.len < ctx.expressions.len: + ctx.dependants.setLen(ctx.expressions.len) + # echo ctx.symbolIndices + # echo ctx.expressions + # echo ctx.dependants + +proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = + let line = s.ast.info.line + let fileIndex = s.ast.info.fileIndex.int + var filename = conf.m.fileInfos[fileIndex].fullPath.string + + var context = NilCheckerContext(config: conf, idgen: idgen) + context.preVisit(s, body, conf) + var map = newNilMap(nil, context.symbolIndices.len) + + for i, child in s.typ.n.sons: + if i > 0: + if child.kind != nkSym: + continue + map.store(context, context.index(child), typeNilability(child.typ), TArg, child.info, child) + + map.store(context, resultExprIndex, if not s.typ[0].isNil and s.typ[0].kind == tyRef: Nil else: Safe, TResult, s.ast.info) + + # echo "checking ", s.name.s, " ", filename + + let res = check(body, context, map) + var canCheck = resultExprIndex in res.map.history.low .. res.map.history.high + if res.nilability == Safe and canCheck and res.map.history[resultExprIndex].len <= 1: + res.map.store(context, resultExprIndex, Safe, TAssign, s.ast.info) + else: + if res.nilability == Safe: + res.map.store(context, resultExprIndex, Safe, TAssign, s.ast.info) + + # TODO check for nilability result + # (ANotNil, BNotNil) : + # do we check on asgn nilability at all? + + if not s.typ[0].isNil and s.typ[0].kind == tyRef and tfNotNil in s.typ[0].flags: + checkResult(s.ast, context, res.map) diff --git a/compiler/options.nim b/compiler/options.nim index a5f262f01..87796539c 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -176,7 +176,8 @@ type ## Note: this feature can't be localized with {.push.} vmopsDanger, strictFuncs, - views + views, + strictNotNil LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 42529e1e5..792488c9f 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -153,6 +153,7 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode, if assignment == nil: constrCtx.missingFields.add r.sym + proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, flags: TExprFlags): InitStatus = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 35b1473c5..c0ae7471d 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, varpartitions, typeallowed + modulegraphs, varpartitions, typeallowed, nilcheck when defined(useDfa): import dfa @@ -1344,7 +1344,10 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = when defined(useDfa): if s.name.s == "testp": dataflowAnalysis(s, body) + when false: trackWrites(s, body) + if strictNotNil in c.features and s.kind == skProc: + checkNil(s, body, g.config, c.idgen) proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef, diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 827087c3d..d09b4c5bf 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -917,6 +917,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = # check every except the last is an object: for i in isCall..= low(int)) and (n.intVal <= high(int)): result = result !& int(n.intVal) @@ -33,6 +34,9 @@ proc hashTree(n: PNode): Hash = else: for i in 0.. + +In the second case it would check builtin and imported modules as well. + +It checks the nilability of ref-like types and makes dereferencing safer based on flow typing and ``not nil`` annotations. + +Its implementation is different than the ``notnil`` one: defined under ``strictNotNil``. Keep in mind the difference in option names, be careful with distinguishing them. + +We check several kinds of types for nilability: + +- ref types +- pointer types +- proc types +- cstrings + +nil +------- + +The default kind of nilability types is the nilable kind: they can have the value ``nil``. +If you have a non-nilable type ``T``, you can use ``T nil`` to get a nilable type for it. + + +not nil +-------- + +You can annotate a type where nil isn't a valid value with ``not nil``. + +.. code-block:: nim + type + NilableObject = ref object + a: int + Object = NilableObject not nil + + Proc = (proc (x, y: int)) + + proc p(x: Object) = + echo x.a # ensured to dereference without an error + # compiler catches this: + p(nil) + # and also this: + var x: NilableObject + if x.isNil: + p(x) + else: + p(x) # ok + + + +If a type can include ``nil`` as a valid value, dereferencing values of the type +is checked by the compiler: if a value which might be nil is derefenced, this produces a warning by default, you can turn this into an error using the compiler options ``--warningAsError:strictNotNil`` + +If a type is nilable, you should dereference its values only after a ``isNil`` or equivalent check. + +local turn on/off +--------------------- + +You can still turn off nil checking on function/module level by using a ``{.strictNotNil: off}.`` pragma. +Note: test that/TODO for code/manual. + +nilability state +----------------- + +Currently a nilable value can be ``Safe``, ``MaybeNil`` or ``Nil`` : we use internally ``Parent`` and ``Unreachable`` but this is an implementation detail(a parent layer has the actual nilability). + +``Safe`` means it shouldn't be nil at that point: e.g. after assignment to a non-nil value or ``not a.isNil`` check +``MaybeNil`` means it might be nil, but it might not be nil: e.g. an argument, a call argument or a value after an ``if`` and ``else``. +``Nil`` means it should be nil at that point; e.g. after an assignment to ``nil`` or a ``.isNil`` check. + +``Unreachable`` means it shouldn't be possible to access this in this branch: so we do generate a warning as well. + +We show an error for each dereference (``[]``, ``.field``, ``[index]`` ``()`` etc) which is of a tracked expression which is +in ``MaybeNil`` or ``Nil`` state. + + +type nilability +---------------- + +Types are either nilable or non-nilable. +When you pass a param or a default value, we use the type : for nilable types we return ``MaybeNil`` +and for non-nilable ``Safe``. + +TODO: fix the manual here. (This is not great, as default values for non-nilables and nilables are usually actually ``nil`` , so we should think a bit more about this section.) + +params rules +------------ + +Param's nilability is detected based on type nilability. We use the type of the argument to detect the nilability. + + +assignment rules +----------------- + +Let's say we have ``left = right``. + +When we assign, we pass the right's nilability to the left's expression. There should be special handling of aliasing and compound expressions which we specify in their sections. (Assignment is a possible alias ``move`` or ``move out``). + +call args rules +----------------- + +When we call with arguments, we have two cases when we might change the nilability. + +.. code-block:: nim + callByVar(a) + +Here ``callByVar`` can re-assign ``a``, so this might change ``a``'s nilability, so we change it to ``MaybeNil``. +This is also a possible aliasing ``move out`` (moving out of a current alias set). + +.. code-block:: nim + call(a) + +Here ``call`` can change a field or element of ``a``, so if we have a dependant expression of ``a`` : e.g. ``a.field``. Dependats become ``MaybeNil``. + + +branches rules +--------------- + +Branches are the reason we do nil checking like this: with flow checking. +Sources of brancing are ``if``, ``while``, ``for``, ``and``, ``or``, ``case``, ``try`` and combinations with ``return``, ``break``, ``continue`` and ``raise`` + +We create a new layer/"scope" for each branch where we map expressions to nilability. This happens when we "fork": usually on the beginning of a construct. +When branches "join" we usually unify their expression maps or/and nilabilities. + +Merging usually merges maps and alias sets: nilabilities are merged like this: + +.. code-block:: nim + template union(l: Nilability, r: Nilability): Nilability = + ## unify two states + if l == r: + l + else: + MaybeNil + +Special handling is for ``.isNil`` and `` == nil``, also for ``not``, ``and`` and ``or``. + +``not`` reverses the nilability, ``and`` is similar to "forking" : the right expression is checked in the layer resulting from the left one and ``or`` is similar to "merging": the right and left expression should be both checked in the original layer. + +``isNil``, ``== nil`` make expressions ``Nil``. If there is a ``not`` or ``!= nil``, they make them ``Safe``. +We also reverse the nilability in the opposite branch: e.g. ``else``. + +compound expressions: field, index expressions +----------------------------------------------- + +We want to track also field(dot) and index(bracket) expressions. + +We track some of those compound expressions which might be nilable as dependants of their bases: ``a.field`` is changed if ``a`` is moved (re-assigned), +similarly ``a[index]`` is dependent on ``a`` and ``a.field.field`` on ``a.field``. + +When we move the base, we update dependants to ``MaybeNil``. Otherwise we usually start with type nilability. + +When we call args, we update the nilability of their dependants to ``MaybeNil`` as the calls usually can change them. +We might need to check for ``strictFuncs`` pure funcs and not do that then. + +For field expressions ``a.field``, we calculate an integer value based on a hash of the tree and just accept equivalent trees as equivalent expressions. + +For item expression ``a[index]``, we also calculate an integer value based on a hash of the tree and accept equivalent trees as equivalent expressions: for static values only. +For now we support only constant indices: we dont track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the ``{.warning[StrictCheckNotNil]:off}.``. + +For bracket expressions, in the future we might count ``a[]`` as the same general expression. +This means we should should the index but otherwise handle it the same for assign (maybe "aliasing" all the non-static elements) and differentiate only for static: e.g. ``a[0]`` and ``a[1]``. + +element tracking +----------------- + +When we assign an object construction, we should track the fields as well: + + +.. code-block:: nim + var a = Nilable(field: Nilable()) # a : Safe, a.field: Safe + +Usually we just track the result of an expression: probably this should apply for elements in other cases as well. +Also related to tracking initialization of expressions/fields. + +unstructured control flow rules +------------------------- + +Unstructured control flow keywords as ``return``, ``break``, ``continue``, ``raise`` mean that we jump from a branch out. +This means that if there is code after the finishing of the branch, it would be ran if one hasn't hit the direct parent branch of those: so it is similar to an ``else``. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g. + +.. code-block:: nim + for a in c: + if not a.isNil: + b() + break + code # here a: Nil , because if not, we would have breaked + + +aliasing +------------ + +We support alias detection for local expressions. + +We track sets of aliased expressions. We start with all nilable local expressions in separate sets. +Assignments and other changes to nilability can move / move out expressions of sets. + +``move``: Moving ``left`` to ``right`` means we remove ``left`` from its current set and unify it with the ``right``'s set. +This means it stops being aliased with its previous aliases. + +.. code-block:: nim + var left = b + left = right # moving left to right + +``move out``: Moving out ``left`` might remove it from the current set and ensure that it's in its own set as a single element. +e.g. + + +.. code-block:: nim + var left = b + left = nil # moving out + + +initialization of non nilable and nilable values +------------------------------------------------- + +TODO + +warnings and errors +--------------------- + +We show an error for each dereference (`[]`, `.field`, `[index]` `()` etc) which is of a tracked expression which is +in ``MaybeNil`` or ``Nil`` state. + +We might also show a history of the transitions and the reasons for them that might change the nilability of the expression. + diff --git a/tests/strictnotnil/tnilcheck.nim b/tests/strictnotnil/tnilcheck.nim new file mode 100644 index 000000000..5b9292522 --- /dev/null +++ b/tests/strictnotnil/tnilcheck.nim @@ -0,0 +1,382 @@ +discard """ +cmd: "nim check $file" +action: "reject" +""" + +import tables + +{.experimental: "strictNotNil".} + +type + Nilable* = ref object + a*: int + field*: Nilable + + NonNilable* = Nilable not nil + + Nilable2* = nil NonNilable + + +# proc `[]`(a: Nilable, b: int): Nilable = +# nil + + +# Nilable tests + + + +# test deref +proc testDeref(a: Nilable) = + echo a.a > 0 #[tt.Warning + ^ can't deref a, it might be nil + ]# + + + +# # # test if else +proc testIfElse(a: Nilable) = + if a.isNil: + echo a.a #[tt.Warning + ^ can't deref a, it is nil + ]# + else: + echo a.a # ok + +proc testIfNoElse(a: Nilable) = + if a.isNil: + echo a.a #[tt.Warning + ^ can't deref a, it is nil + ]# + echo a.a #[tt.Warning + ^ can't deref a, it might be nil + ]# + +proc testIfReturn(a: Nilable) = + if not a.isNil: + return + echo a.a #[tt.Warning + ^ can't deref a, it is nil + ]# + +proc testIfBreak(a: seq[Nilable]) = + for b in a: + if not b.isNil: + break + echo b.a #[tt.Warning + ^ can't deref b, it is nil + ]# + +proc testIfContinue(a: seq[Nilable]) = + for b in a: + if not b.isNil: + continue + echo b.a #[tt.Warning + ^ can't deref b, it is nil + ]# + +proc testIfRaise(a: Nilable) = + if not a.isNil: + raise newException(ValueError, "") + echo a.a #[tt.Warning + ^ can't deref a, it is nil + ]# + +proc testIfElif(a: Nilable) = + var c = 0 + if c == 0: + echo a.a #[tt.Warning + ^ can't deref a, it might be nil + ]# + elif c == 1: + echo a.a #[tt.Warning + ^ can't deref a, it might be nil + ]# + elif not a.isNil: + echo a.a # ok + elif c == 2: + echo 0 + else: + echo a.a #[tt.Warning + ^ can't deref a, it is nil + ]# + +proc testAssignUnify(a: Nilable, b: int) = + var a2 = a + if b == 0: + a2 = Nilable() + echo a2.a #[tt.Warning + ^ can't deref a2, it might be nil + ]# + + +# # test assign in branch and unifiying that with the main block after end of branch +proc testAssignUnifyNil(a: Nilable, b: int) = + var a2 = a + if b == 0: + a2 = nil + echo a2.a #[tt.Warning + ^ can't deref a2, it might be nil + ]# + +# test loop +proc testForLoop(a: Nilable) = + var b = Nilable() + for i in 0 .. 5: + echo b.a #[tt.Warning + ^ can't deref b, it might be nil + ]# + if i == 2: + b = a + echo b.a #[tt.Warning + ^ can't deref b, it might be nil + ]# + + + +# # TODO implement this after discussion +# # proc testResultCompoundNonNilableElement(a: Nilable): (NonNilable, NonNilable) = #[t t.Warning +# # ^ result might be not initialized, so it or an element might be nil +# # ]# +# # if not a.isNil: +# # result[0] = a #[t t.Warning +# # ^ can't assign nilable to non nilable: it might be nil +# # #] + +# # proc testNonNilDeref(a: NonNilable) = +# # echo a.a # ok + + + +# # # not only calls: we can use partitions for dependencies for field aliases +# # # so we can detect on change what does this affect or was this mutated between us and the original field + +# # proc testRootAliasField(a: Nilable) = +# # var aliasA = a +# # if not a.isNil and not a.field.isNil: +# # aliasA.field = nil +# # # a.field = nil +# # # aliasA = nil +# # echo a.field.a # [tt.Warning +# # ^ can't deref a.field, it might be nil +# # ]# + + +proc testAliasChanging(a: Nilable) = + var b = a + var aliasA = b + b = Nilable() + if not b.isNil: + echo aliasA.a #[tt.Warning + ^ can't deref aliasA, it might be nil + ]# + +# # TODO +# # proc testAliasUnion(a: Nilable) = +# # var a2 = a +# # var b = a2 +# # if a.isNil: +# # b = Nilable() +# # a2 = nil +# # else: +# # a2 = Nilable() +# # b = a2 +# # if not b.isNil: +# # echo a2.a #[ tt.Warning +# # ^ can't deref a2, it might be nil +# # ]# + +# # TODO after alias support +# #proc callVar(a: var Nilable) = +# # a.field = nil + + +# # TODO ptr support +# # proc testPtrAlias(a: Nilable) = +# # # pointer to a: hm. +# # # alias to a? +# # var ptrA = a.unsafeAddr # {0, 1} +# # if not a.isNil: # {0, 1} +# # ptrA[] = nil # {0, 1} 0: MaybeNil 1: MaybeNil +# # echo a.a #[ tt.Warning +# # ^ can't deref a, it might be nil +# # ]# + +# # TODO field stuff +# # currently it just doesnt support dot, so accidentally it shows a warning but because that +# # not alias i think +# # proc testFieldAlias(a: Nilable) = +# # var b = a # {0, 1} {2} +# # if not a.isNil and not a.field.isNil: # {0, 1} {2} +# # callVar(b) # {0, 1} {2} 0: Safe 1: Safe +# # echo a.field.a #[ tt.Warning +# # ^ can't deref a.field, it might be nil +# # ]# +# # +# # proc testUniqueHashTree(a: Nilable): Nilable = +# # # TODO what would be a clash +# # var field = 0 +# # if not a.isNil and not a.field.isNil: +# # # echo a.field.a +# # echo a[field].a +# # result = Nilable() + +# # proc testSeparateShadowingResult(a: Nilable): Nilable = +# # result = Nilable() +# # if not a.isNil: +# # var result: Nilable = nil +# # echo result.a + + +proc testCStringDeref(a: cstring) = + echo a[0] #[tt.Warning + ^ can't deref a, it might be nil + ]# + + +proc testNilablePtr(a: ptr int) = + if not a.isNil: + echo a[] # ok + echo a[] #[tt.Warning + ^ can't deref a, it might be nil + ]# + +# # proc testNonNilPtr(a: ptr int not nil) = +# # echo a[] # ok + +proc raiseCall: NonNilable = #[tt.Warning +^ return value is nil +]# + raise newException(ValueError, "raise for test") + +# proc testTryCatch(a: Nilable) = +# var other = a +# try: +# other = raiseCall() +# except: +# discard +# echo other.a #[ tt.Warning +# ^ can't deref other, it might be nil +# ]# + +# # proc testTryCatchDetectNoRaise(a: Nilable) = +# # var other = Nilable() +# # try: +# # other = nil +# # other = a +# # other = Nilable() +# # except: +# # other = nil +# # echo other.a # ok + +# # proc testTryCatchDetectFinally = +# # var other = Nilable() +# # try: +# # other = nil +# # other = Nilable() +# # except: +# # other = Nilable() +# # finally: +# # other = nil +# # echo other.a # can't deref other: it is nil + +# # proc testTryCatchDetectNilableWithRaise(b: bool) = +# # var other = Nilable() +# # try: +# # if b: +# # other = nil +# # else: +# # other = Nilable() +# # var other2 = raiseCall() +# # except: +# # echo other.a # ok + +# # echo other.a # can't deref a: it might be nil + +# # proc testRaise(a: Nilable) = +# # if a.isNil: +# # raise newException(ValueError, "a == nil") +# # echo a.a # ok + + +# # proc testBlockScope(a: Nilable) = +# # var other = a +# # block: +# # var other = Nilable() +# # echo other.a # ok +# # echo other.a # can't deref other: it might be nil + +# # ok we can't really get the nil value from here, so should be ok +# # proc testDirectRaiseCall: NonNilable = +# # var a = raiseCall() +# # result = NonNilable() + +# # proc testStmtList = +# # var a = Nilable() +# # block: +# # a = nil +# # a = Nilable() +# # echo a.a # ok + +proc callChange(a: Nilable) = + if not a.isNil: + a.field = nil + +proc testCallChangeField = + var a = Nilable() + a.field = Nilable() + callChange(a) + echo a.field.a #[ tt.Warning + ^ can't deref a.field, it might be nil + ]# + +proc testReassignVarWithField = + var a = Nilable() + a.field = Nilable() + echo a.field.a # ok + a = Nilable() + echo a.field.a #[ tt.Warning + ^ can't deref a.field, it might be nil + ]# + + +proc testItemDeref(a: var seq[Nilable]) = + echo a[0].a #[tt.Warning + ^ can't deref a[0], it might be nil + ]# + a[0] = Nilable() # good: now .. if we dont track, how do we know + echo a[0].a # ok + echo a[1].a #[tt.Warning + ^ can't deref a[1], it might be nil + ]# + var b = 1 + if a[b].isNil: + echo a[1].a #[tt.Warning + ^ can't deref a[1], it might be nil + ]# + var c = 0 + echo a[c].a #[tt.Warning + ^ can't deref a[c], it might be nil + ]# + + # known false positive + if not a[b].isNil: + echo a[b].a #[tt.Warning + ^ can't deref a[b], it might be nil + ]# + + const c = 0 + if a[c].isNil: + echo a[0].a #[tt.Warning + ^ can't deref a[0], it is nil + ]# + a[c] = Nilable() + echo a[0].a # ok + + + +# # # proc test10(a: Nilable) = +# # # if not a.isNil and not a.b.isNil: +# # # c_memset(globalA.addr, 0, globalA.sizeOf.csize_t) +# # # globalA = nil +# # # echo a.a # can't deref a: it might be nil + diff --git a/tests/strictnotnil/tnilcheck_no_warnings.nim b/tests/strictnotnil/tnilcheck_no_warnings.nim new file mode 100644 index 000000000..5ec9bc575 --- /dev/null +++ b/tests/strictnotnil/tnilcheck_no_warnings.nim @@ -0,0 +1,182 @@ +discard """ +cmd: "nim check --warningAsError:StrictNotNil $file" +action: "compile" +""" + +import tables + +{.experimental: "strictNotNil".} + +type + Nilable* = ref object + a*: int + field*: Nilable + + NonNilable* = Nilable not nil + + Nilable2* = nil NonNilable + + +# proc `[]`(a: Nilable, b: int): Nilable = +# nil + + +# Nilable tests + + + +# # test and +proc testAnd(a: Nilable) = + echo not a.isNil and a.a > 0 # ok + + +# test else branch and inferring not isNil +# proc testElse(a: Nilable, b: int) = +# if a.isNil: +# echo 0 +# else: +# echo a.a + +# test that here we can infer that n can't be nil anymore +proc testNotNilAfterAssign(a: Nilable, b: int) = + var n = a # a: MaybeNil n: MaybeNil + if n.isNil: # n: Safe a: MaybeNil + n = Nilable() # n: Safe a: MaybeNil + echo n.a # ok + +proc callVar(a: var Nilable) = + a = nil + +proc testVarAlias(a: Nilable) = # a: 0 aliasA: 1 {0} {1} + var aliasA = a # {0, 1} 0 MaybeNil 1 MaybeNil + if not a.isNil: # {0, 1} 0 Safe 1 Safe + callVar(aliasA) # {0, 1} 0 MaybeNil 1 MaybeNil + # if aliasA stops being in alias: it might be nil, but then a is still not nil + # if not: it cant be nil as it still points here + echo a.a # ok + +proc testAliasCheck(a: Nilable) = + var aliasA = a + if not a.isNil: + echo aliasA.a # ok + +proc testFieldCheck(a: Nilable) = + if not a.isNil and not a.field.isNil: + echo a.field.a # ok + +proc testTrackField = + var a = Nilable(field: Nilable()) + echo a.field.a # ok + +proc testNonNilDeref(a: NonNilable) = + echo a.a # ok + +# # not only calls: we can use partitions for dependencies for field aliases +# # so we can detect on change what does this affect or was this mutated between us and the original field + + +# proc testUniqueHashTree(a: Nilable): Nilable = +# # TODO what would be a clash +# var field = 0 +# if not a.isNil and not a.field.isNil: +# # echo a.field.a +# echo a[field].a +# result = Nilable() + +proc testSeparateShadowingResult(a: Nilable): Nilable = + result = Nilable() + if not a.isNil: + var result: Nilable = nil + echo result.a + + +proc testNonNilCString(a: cstring not nil) = + echo a[0] # ok + +proc testNonNilPtr(a: ptr int not nil) = + echo a[] # ok + + +# proc testTryCatchDetectNoRaise(a: Nilable) = +# var other = Nilable() +# try: +# other = nil +# other = a +# other = Nilable() +# except: +# other = nil +# echo other.a # ok + +# proc testTryCatchDetectFinally = +# var other = Nilable() +# try: +# other = nil +# other = Nilable() +# except: +# other = Nilable() +# finally: +# other = nil +# echo other.a # can't deref other: it is nil + +# proc testTryCatchDetectNilableWithRaise(b: bool) = +# var other = Nilable() +# try: +# if b: +# other = nil +# else: +# other = Nilable() +# var other2 = raiseCall() +# except: +# echo other.a # ok + +# echo other.a # can't deref a: it might be nil + +proc testRaise(a: Nilable) = + if a.isNil: + raise newException(ValueError, "a == nil") + echo a.a # ok + +# proc testBlockScope(a: Nilable) = +# var other = a +# block: +# var other = Nilable() +# echo other.a # ok +# echo other.a # can't deref other: it might be nil + +# # (ask Araq about this: not supported yet) ok we can't really get the nil value from here, so should be ok +# proc testDirectRaiseCall: NonNilable = +# var a = raiseCall() +# result = NonNilable() + +proc testStmtList = + var a = Nilable() + block: + a = nil + a = Nilable() + echo a.a # ok + +proc testItemDerefNoWarning(a: var seq[Nilable]) = + a[0] = Nilable() # good: now .. if we dont track, how do we know + echo a[0].a # ok + var b = 1 + + const c = 0 + a[c] = Nilable() + echo a[0].a # ok + +# proc callChange(a: Nilable) = +# a.field = nil + +# proc testCallAlias = +# var a = Nilable(field: Nilable()) +# callChange(a) +# echo a.field.a # can't deref a.field, it might be nil + +# # proc test10(a: Nilable) = +# # if not a.isNil and not a.b.isNil: +# # c_memset(globalA.addr, 0, globalA.sizeOf.csize_t) +# # globalA = nil +# # echo a.a # can't deref a: it might be nil + +var nilable: Nilable +var withField = Nilable(a: 0, field: Nilable()) From c9886a49528c08784b1f8e1f7b907024170973dc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 29 Dec 2020 02:12:05 -0800 Subject: [PATCH 1712/4254] use -d:nimCompilerStackraceHints in more places (#16400) --- compiler/ccgexprs.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ef3ceae62..45044e0ff 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -9,6 +9,9 @@ # included from cgen.nim +when defined(nimCompilerStackraceHints): + import std/stackframes + proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, result: var Rope; count: var int; isConst: bool, info: TLineInfo) @@ -2643,6 +2646,8 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = d.storage = OnStatic proc expr(p: BProc, n: PNode, d: var TLoc) = + when defined(nimCompilerStackraceHints): + setFrameMsg p.config$n.info & " " & $n.kind p.currLineInfo = n.info case n.kind From fc1a4faf568424b221e6690257ee96c66e68408e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 29 Dec 2020 04:26:10 -0800 Subject: [PATCH 1713/4254] improve turi.nim tests: js, vm; merge tdecodequery.nim (#16500) * improve turi tests: js, vm; merge tdecodequery.nim * improve test * add test in js, improve test * remove matrix: "--styleCheck:hint --panics:on" * fixup --- tests/stdlib/tdecodequery.nim | 7 - tests/stdlib/turi.nim | 344 +++++++++++++++++----------------- 2 files changed, 169 insertions(+), 182 deletions(-) delete mode 100644 tests/stdlib/tdecodequery.nim diff --git a/tests/stdlib/tdecodequery.nim b/tests/stdlib/tdecodequery.nim deleted file mode 100644 index ae180742f..000000000 --- a/tests/stdlib/tdecodequery.nim +++ /dev/null @@ -1,7 +0,0 @@ -import std/[uri, sequtils] - - -block: - doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] - doAssertRaises(UriParseError): - discard toSeq(decodeQuery("a=1&b=2c=6")) diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index 62fb17e4d..6354850fc 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -1,24 +1,14 @@ discard """ - cmd: "nim c -r --styleCheck:hint --panics:on $options $file" - targets: "c" - nimout: "" - action: "run" - exitcode: 0 - timeout: 60.0 + targets: "c js" + joinable: false # because of `include uri` """ -include uri +# import std/uri # pending https://github.com/nim-lang/Nim/pull/11865 +include uri # because of `removeDotSegments` +from std/sequtils import toSeq -block: - let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" - let url = parseUri(org) - doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true - let newUrl = parseUri($url) - doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true - - -block: - block: +template main() = + block: # encodeUrl, decodeUrl const test1 = "abc\L+def xyz" doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" doAssert decodeUrl(encodeUrl(test1)) == test1 @@ -26,178 +16,177 @@ block: doAssert decodeUrl(encodeUrl(test1, false), false) == test1 doAssert decodeUrl(encodeUrl(test1)) == test1 - block: - let str = "http://localhost" - let test = parseUri(str) - doAssert test.path == "" + block: # parseUri + block: + let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" + let url = parseUri(org) + doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true + let newUrl = parseUri($url) + doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true - block: - let str = "http://localhost/" - let test = parseUri(str) - doAssert test.path == "/" + block: + let str = "http://localhost" + let test = parseUri(str) + doAssert test.path == "" - block: - let str = "http://localhost:8080/test" - let test = parseUri(str) - doAssert test.scheme == "http" - doAssert test.port == "8080" - doAssert test.path == "/test" - doAssert test.hostname == "localhost" - doAssert($test == str) + block: + let str = "http://localhost/" + let test = parseUri(str) + doAssert test.path == "/" - block: - let str = "foo://username:password@example.com:8042/over/there" & - "/index.dtb?type=animal&name=narwhal#nose" - let test = parseUri(str) - doAssert test.scheme == "foo" - doAssert test.username == "username" - doAssert test.password == "password" - doAssert test.hostname == "example.com" - doAssert test.port == "8042" - doAssert test.path == "/over/there/index.dtb" - doAssert test.query == "type=animal&name=narwhal" - doAssert test.anchor == "nose" - doAssert($test == str) + block: + let str = "http://localhost:8080/test" + let test = parseUri(str) + doAssert test.scheme == "http" + doAssert test.port == "8080" + doAssert test.path == "/test" + doAssert test.hostname == "localhost" + doAssert($test == str) - block: - # IPv6 address - let str = "foo://[::1]:1234/bar?baz=true&qux#quux" - let uri = parseUri(str) - doAssert uri.scheme == "foo" - doAssert uri.hostname == "::1" - doAssert uri.port == "1234" - doAssert uri.path == "/bar" - doAssert uri.query == "baz=true&qux" - doAssert uri.anchor == "quux" + block: + let str = "foo://username:password@example.com:8042/over/there" & + "/index.dtb?type=animal&name=narwhal#nose" + let test = parseUri(str) + doAssert test.scheme == "foo" + doAssert test.username == "username" + doAssert test.password == "password" + doAssert test.hostname == "example.com" + doAssert test.port == "8042" + doAssert test.path == "/over/there/index.dtb" + doAssert test.query == "type=animal&name=narwhal" + doAssert test.anchor == "nose" + doAssert($test == str) - block: - let str = "urn:example:animal:ferret:nose" - let test = parseUri(str) - doAssert test.scheme == "urn" - doAssert test.path == "example:animal:ferret:nose" - doAssert($test == str) + block: + # IPv6 address + let str = "foo://[::1]:1234/bar?baz=true&qux#quux" + let uri = parseUri(str) + doAssert uri.scheme == "foo" + doAssert uri.hostname == "::1" + doAssert uri.port == "1234" + doAssert uri.path == "/bar" + doAssert uri.query == "baz=true&qux" + doAssert uri.anchor == "quux" - block: - let str = "mailto:username@example.com?subject=Topic" - let test = parseUri(str) - doAssert test.scheme == "mailto" - doAssert test.username == "username" - doAssert test.hostname == "example.com" - doAssert test.query == "subject=Topic" - doAssert($test == str) + block: + let str = "urn:example:animal:ferret:nose" + let test = parseUri(str) + doAssert test.scheme == "urn" + doAssert test.path == "example:animal:ferret:nose" + doAssert($test == str) - block: - let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" - let test = parseUri(str) - doAssert test.scheme == "magnet" - doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" - doAssert($test == str) + block: + let str = "mailto:username@example.com?subject=Topic" + let test = parseUri(str) + doAssert test.scheme == "mailto" + doAssert test.username == "username" + doAssert test.hostname == "example.com" + doAssert test.query == "subject=Topic" + doAssert($test == str) - block: - let str = "/test/foo/bar?q=2#asdf" - let test = parseUri(str) - doAssert test.scheme == "" - doAssert test.path == "/test/foo/bar" - doAssert test.query == "q=2" - doAssert test.anchor == "asdf" - doAssert($test == str) + block: + let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" + let test = parseUri(str) + doAssert test.scheme == "magnet" + doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar" + doAssert($test == str) - block: - let str = "test/no/slash" - let test = parseUri(str) - doAssert test.path == "test/no/slash" - doAssert($test == str) + block: + let str = "/test/foo/bar?q=2#asdf" + let test = parseUri(str) + doAssert test.scheme == "" + doAssert test.path == "/test/foo/bar" + doAssert test.query == "q=2" + doAssert test.anchor == "asdf" + doAssert($test == str) - block: - let str = "//git@github.com:dom96/packages" - let test = parseUri(str) - doAssert test.scheme == "" - doAssert test.username == "git" - doAssert test.hostname == "github.com" - doAssert test.port == "dom96" - doAssert test.path == "/packages" + block: + let str = "test/no/slash" + let test = parseUri(str) + doAssert test.path == "test/no/slash" + doAssert($test == str) - block: - let str = "file:///foo/bar/baz.txt" - let test = parseUri(str) - doAssert test.scheme == "file" - doAssert test.username == "" - doAssert test.hostname == "" - doAssert test.port == "" - doAssert test.path == "/foo/bar/baz.txt" + block: + let str = "//git@github.com:dom96/packages" + let test = parseUri(str) + doAssert test.scheme == "" + doAssert test.username == "git" + doAssert test.hostname == "github.com" + doAssert test.port == "dom96" + doAssert test.path == "/packages" - # Remove dot segments tests - block: + block: + let str = "file:///foo/bar/baz.txt" + let test = parseUri(str) + doAssert test.scheme == "file" + doAssert test.username == "" + doAssert test.hostname == "" + doAssert test.port == "" + doAssert test.path == "/foo/bar/baz.txt" + + block: # combine + block: + let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz")) + doAssert concat.path == "/foo/bar/baz" + doAssert concat.hostname == "google.com" + doAssert concat.scheme == "http" + + block: + let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz")) + doAssert concat.path == "/baz" + doAssert concat.hostname == "google.com" + doAssert concat.scheme == "http" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) + doAssert concat.path == "/foo/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar")) + doAssert concat.path == "/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) + doAssert concat.path == "/foo/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar")) + doAssert concat.path == "/foo/test/bar" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/")) + doAssert concat.path == "/foo/test/bar/" + + block: + let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"), + parseUri("baz")) + doAssert concat.path == "/foo/test/bar/baz" + + block: # `/` + block: + let test = parseUri("http://example.com/foo") / "bar/asd" + doAssert test.path == "/foo/bar/asd" + + block: + let test = parseUri("http://example.com/foo/") / "/bar/asd" + doAssert test.path == "/foo/bar/asd" + + block: # removeDotSegments doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" + doAssert removeDotSegments("") == "" # empty test - # Combine tests - block: - let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz")) - doAssert concat.path == "/foo/bar/baz" - doAssert concat.hostname == "google.com" - doAssert concat.scheme == "http" - - block: - let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz")) - doAssert concat.path == "/baz" - doAssert concat.hostname == "google.com" - doAssert concat.scheme == "http" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) - doAssert concat.path == "/foo/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar")) - doAssert concat.path == "/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar")) - doAssert concat.path == "/foo/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar")) - doAssert concat.path == "/foo/test/bar" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/")) - doAssert concat.path == "/foo/test/bar/" - - block: - let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"), - parseUri("baz")) - doAssert concat.path == "/foo/test/bar/baz" - - # `/` tests - block: - let test = parseUri("http://example.com/foo") / "bar/asd" - doAssert test.path == "/foo/bar/asd" - - block: - let test = parseUri("http://example.com/foo/") / "/bar/asd" - doAssert test.path == "/foo/bar/asd" - - # removeDotSegments tests - block: - # empty test - doAssert removeDotSegments("") == "" - - # bug #3207 - block: + block: # bug #3207 doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq" - # bug #4959 - block: + block: # bug #4959 let foo = parseUri("http://example.com") / "/baz" doAssert foo.path == "/baz" - # bug found on stream 13/10/17 - block: + block: # bug found on stream 13/10/17 let foo = parseUri("http://localhost:9515") / "status" doAssert $foo == "http://localhost:9515/status" - # bug #6649 #6652 - block: + block: # bug #6649 #6652 var foo = parseUri("http://example.com") foo.hostname = "example.com" foo.path = "baz" @@ -224,8 +213,7 @@ block: foo.path = "relative" doAssert $foo == "file:relative" - # isAbsolute tests - block: + block: # isAbsolute tests doAssert "www.google.com".parseUri().isAbsolute() == false doAssert "http://www.google.com".parseUri().isAbsolute() == true doAssert "file:/dir/file".parseUri().isAbsolute() == true @@ -265,8 +253,7 @@ block: doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true - # encodeQuery tests - block: + block: # encodeQuery tests doAssert encodeQuery({:}) == "" doAssert encodeQuery({"foo": "bar"}) == "foo=bar" doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz" @@ -276,17 +263,17 @@ block: doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3" doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3" + block: # `?` block: var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"} var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux") doAssert foo == foo1 - block: var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""} var foo1 = parseUri("http://example.com/foo?do=do&bar") doAssert foo == foo1 - block dataUriBase64: + block: # getDataUri, dataUriBase64 doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64," doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA==" doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+" @@ -295,6 +282,13 @@ block: doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r" doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") == "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==") - doAssert(getDataUri("""The present is theirs - The future, for which I really worked, is mine.""", "text/plain") == + doAssert(getDataUri("The present is theirs\n The future, for which I really worked, is mine.", "text/plain") == "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu") + + block: # decodeQuery + doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] + doAssertRaises(UriParseError): + discard toSeq(decodeQuery("a=1&b=2c=6")) + +static: main() +main() From d5a3c2c2da2e3b2f6deeb2c1cd5430db90bc4fd5 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Tue, 29 Dec 2020 14:27:08 +0200 Subject: [PATCH 1714/4254] Added cmpMem export (#16484) * added cmpMem export * updates * fix test * Tiny changelog change * Add a dot. Co-authored-by: Clyybber --- changelog.md | 6 ++- lib/system.nim | 2 + lib/system/memalloc.nim | 107 ++++++++++++++++++++++----------------- tests/stdlib/tmemory.nim | 15 ++++++ 4 files changed, 81 insertions(+), 49 deletions(-) create mode 100644 tests/stdlib/tmemory.nim diff --git a/changelog.md b/changelog.md index 6b12891c5..035ba46b8 100644 --- a/changelog.md +++ b/changelog.md @@ -36,6 +36,8 @@ - `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. +- Added `cmpMem` to `system`. + - `doAssertRaises` now correctly handles foreign exceptions. - Added `asyncdispatch.activeDescriptors` that returns the number of currently @@ -57,7 +59,7 @@ - Added `decodeQuery` to `std/uri`. - `strscans.scanf` now supports parsing single characters. -- `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. +- `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. - Added `setutils.toSet` that can take any iterable and convert it to a built-in set, if the iterable yields a built-in settable type. @@ -71,7 +73,7 @@ and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes its argument, `addMoved`, is also supplied. - + - Added `sequtils` import to `prelude`. - Added `euclDiv` and `euclMod` to `math`. diff --git a/lib/system.nim b/lib/system.nim index fb008dc45..b6f7d655a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2182,6 +2182,8 @@ when notJSnotNims: memTrackerOp("moveMem", dest, size) proc equalMem(a, b: pointer, size: Natural): bool = nimCmpMem(a, b, size) == 0 + proc cmpMem(a, b: pointer, size: Natural): int = + nimCmpMem(a, b, size) when not defined(js): proc cmp(x, y: string): int = diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index f5e8b2363..ffb5190ca 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -1,38 +1,51 @@ when notJSnotNims: proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, tags: [], locks: 0, raises: [].} - ## Overwrites the contents of the memory at ``p`` with the value 0. + ## Overwrites the contents of the memory at `p` with the value 0. ## - ## Exactly ``size`` bytes will be overwritten. Like any procedure + ## Exactly `size` bytes will be overwritten. Like any procedure ## dealing with raw memory this is **unsafe**. proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign, tags: [], locks: 0, raises: [].} - ## Copies the contents from the memory at ``source`` to the memory - ## at ``dest``. - ## Exactly ``size`` bytes will be copied. The memory + ## Copies the contents from the memory at `source` to the memory + ## at `dest`. + ## Exactly `size` bytes will be copied. The memory ## regions may not overlap. Like any procedure dealing with raw ## memory this is **unsafe**. proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign, tags: [], locks: 0, raises: [].} - ## Copies the contents from the memory at ``source`` to the memory - ## at ``dest``. + ## Copies the contents from the memory at `source` to the memory + ## at `dest`. ## - ## Exactly ``size`` bytes will be copied. The memory - ## regions may overlap, ``moveMem`` handles this case appropriately - ## and is thus somewhat more safe than ``copyMem``. Like any procedure + ## Exactly `size` bytes will be copied. The memory + ## regions may overlap, `moveMem` handles this case appropriately + ## and is thus somewhat more safe than `copyMem`. Like any procedure ## dealing with raw memory this is still **unsafe**, though. proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, tags: [], locks: 0, raises: [].} - ## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will + ## Compares the memory blocks `a` and `b`. `size` bytes will ## be compared. ## ## If the blocks are equal, `true` is returned, `false` ## otherwise. Like any procedure dealing with raw memory this is ## **unsafe**. + proc cmpMem*(a, b: pointer, size: Natural): int {.inline, noSideEffect, + tags: [], locks: 0, raises: [].} + ## Compares the memory blocks `a` and `b`. `size` bytes will + ## be compared. + ## + ## Returns: + ## * a value less than zero, if `a < b` + ## * a value greater than zero, if `a > b` + ## * zero, if `a == b` + ## + ## Like any procedure dealing with raw memory this is + ## **unsafe**. + when hasAlloc and not defined(js): proc allocImpl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} @@ -75,7 +88,7 @@ when hasAlloc and not defined(js): proc getAllocStats*(): AllocStats = discard template alloc*(size: Natural): pointer = - ## Allocates a new memory block with at least ``size`` bytes. + ## Allocates a new memory block with at least `size` bytes. ## ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -91,7 +104,7 @@ when hasAlloc and not defined(js): allocImpl(size) proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = - ## Allocates a new memory block with at least ``T.sizeof * size`` bytes. + ## Allocates a new memory block with at least `T.sizeof * size` bytes. ## ## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -106,7 +119,7 @@ when hasAlloc and not defined(js): cast[ptr T](alloc(T.sizeof * size)) template alloc0*(size: Natural): pointer = - ## Allocates a new memory block with at least ``size`` bytes. + ## Allocates a new memory block with at least `size` bytes. ## ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -119,7 +132,7 @@ when hasAlloc and not defined(js): alloc0Impl(size) proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = - ## Allocates a new memory block with at least ``T.sizeof * size`` bytes. + ## Allocates a new memory block with at least `T.sizeof * size` bytes. ## ## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -134,8 +147,8 @@ when hasAlloc and not defined(js): ## 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 ``newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. + ## In either way the block has at least `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(block) <#dealloc,pointer>`_. ## @@ -148,8 +161,8 @@ when hasAlloc and not defined(js): ## 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 ``newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. + ## In either way the block has at least `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(block) <#dealloc,pointer>`_. ## @@ -165,9 +178,9 @@ when hasAlloc and not defined(js): ## 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** ``resize`` calls ``dealloc(p)``. - ## In other cases the block has to be freed with ``free``. + ## In either way the block has at least `T.sizeof * newSize` bytes. + ## If `newSize == 0` and `p` is not **nil** `resize` calls `dealloc(p)`. + ## In other cases the block has to be freed with `free`. ## ## The allocated memory belongs to its allocating thread! ## Use `resizeShared <#resizeShared,ptr.T,Natural>`_ to reallocate @@ -175,8 +188,8 @@ when hasAlloc and not defined(js): cast[ptr T](realloc(p, T.sizeof * newSize)) proc dealloc*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = - ## Frees the memory allocated with ``alloc``, ``alloc0`` or - ## ``realloc``. + ## Frees the memory allocated with `alloc`, `alloc0` or + ## `realloc`. ## ## **This procedure is dangerous!** ## If one forgets to free the memory a leak occurs; if one tries to @@ -190,7 +203,7 @@ when hasAlloc and not defined(js): template allocShared*(size: Natural): pointer = ## Allocates a new memory block on the shared heap with at - ## least ``size`` bytes. + ## least `size` bytes. ## ## The block has to be freed with ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ @@ -207,7 +220,7 @@ when hasAlloc and not defined(js): proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [], benign, raises: [].} = ## Allocates a new memory block on the shared heap with at - ## least ``T.sizeof * size`` bytes. + ## least `T.sizeof * size` bytes. ## ## The block has to be freed with ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or @@ -222,7 +235,7 @@ when hasAlloc and not defined(js): template allocShared0*(size: Natural): pointer = ## Allocates a new memory block on the shared heap with at - ## least ``size`` bytes. + ## least `size` bytes. ## ## The block has to be freed with ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ @@ -236,7 +249,7 @@ when hasAlloc and not defined(js): 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. + ## least `T.sizeof * size` bytes. ## ## The block has to be freed with ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or @@ -251,9 +264,9 @@ when hasAlloc and not defined(js): ## 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 ``newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls - ## ``deallocShared(p)``. + ## In either way the block has at 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 <#deallocShared,pointer>`_. reallocSharedImpl(p, newSize) @@ -265,9 +278,9 @@ when hasAlloc and not defined(js): ## containing zero, so it is somewhat safer then reallocShared ## ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least ``newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls - ## ``deallocShared(p)``. + ## In either way the block has at 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 <#deallocShared,pointer>`_. reallocShared0Impl(p, oldSize, newSize) @@ -276,16 +289,16 @@ when hasAlloc and not defined(js): ## 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** ``resizeShared`` calls - ## ``freeShared(p)``. + ## In either way the block has at least `T.sizeof * newSize` bytes. + ## If `newSize == 0` and `p` is not **nil** `resizeShared` calls + ## `freeShared(p)`. ## In other cases the block has to be freed with ## `freeShared <#freeShared,ptr.T>`_. cast[ptr T](reallocShared(p, T.sizeof * newSize)) proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = - ## Frees the memory allocated with ``allocShared``, ``allocShared0`` or - ## ``reallocShared``. + ## Frees the memory allocated with `allocShared`, `allocShared0` or + ## `reallocShared`. ## ## **This procedure is dangerous!** ## If one forgets to free the memory a leak occurs; if one tries to @@ -295,8 +308,8 @@ when hasAlloc and not defined(js): deallocSharedImpl(p) proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} = - ## Frees the memory allocated with ``createShared``, ``createSharedU`` or - ## ``resizeShared``. + ## 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 @@ -304,7 +317,7 @@ when hasAlloc and not defined(js): ## or other memory may be corrupted. deallocShared(p) - include bitmasks + include bitmasks template `+!`(p: pointer, s: SomeInteger): pointer = cast[pointer](cast[int](p) +% int(s)) @@ -318,7 +331,7 @@ when hasAlloc and not defined(js): result = allocShared(size) else: result = alloc(size) - else: + else: # allocate (size + align - 1) necessary for alignment, # plus 2 bytes to store offset when compileOption("threads"): @@ -326,7 +339,7 @@ when hasAlloc and not defined(js): else: let base = alloc(size + align - 1 + sizeof(uint16)) # memory layout: padding + offset (2 bytes) + user_data - # in order to deallocate: read offset at user_data - 2 bytes, + # in order to deallocate: read offset at user_data - 2 bytes, # then deallocate user_data - offset let offset = align - (cast[int](base) and (align - 1)) cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) @@ -338,7 +351,7 @@ when hasAlloc and not defined(js): result = allocShared0(size) else: result = alloc0(size) - else: + else: # see comments for alignedAlloc when compileOption("threads"): let base = allocShared0(size + align - 1 + sizeof(uint16)) @@ -348,13 +361,13 @@ when hasAlloc and not defined(js): cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) result = base +! offset - proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = + proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = if align <= MemAlign: when compileOption("threads"): deallocShared(p) else: dealloc(p) - else: + else: # read offset at p - 2 bytes, then deallocate (p - offset) pointer let offset = cast[ptr uint16](p -! sizeof(uint16))[] when compileOption("threads"): diff --git a/tests/stdlib/tmemory.nim b/tests/stdlib/tmemory.nim new file mode 100644 index 000000000..25b5d526a --- /dev/null +++ b/tests/stdlib/tmemory.nim @@ -0,0 +1,15 @@ + +block: # cmpMem + type + SomeHash = array[15, byte] + + var + a: SomeHash + b: SomeHash + + a[^1] = byte(1) + let c = a + + doAssert cmpMem(a.addr, b.addr, sizeof(SomeHash)) > 0 + doAssert cmpMem(b.addr, a.addr, sizeof(SomeHash)) < 0 + doAssert cmpMem(a.addr, c.unsafeAddr, sizeof(SomeHash)) == 0 From 732419ae907208b0b484911b996893097402a6c7 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 29 Dec 2020 06:44:48 -0600 Subject: [PATCH 1715/4254] improve examples in manual (#16497) * improve examples in manual * Update doc/manual.rst Co-authored-by: Clyybber * Update tests/cpp/ttemplatetype.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- doc/manual.rst | 4 +++- tests/cpp/ttemplatetype.nim | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index fd0ac0529..9fabee1e8 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7062,8 +7062,10 @@ one can import C++'s templates rather easily without the need for a pattern language for object types: .. code-block:: nim + :test: "nim cpp $1" + type - StdMap {.importcpp: "std::map", header: "".} [K, V] = object + StdMap[K, V] {.importcpp: "std::map", header: "".} = object proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. importcpp: "#[#] = #", header: "".} diff --git a/tests/cpp/ttemplatetype.nim b/tests/cpp/ttemplatetype.nim index ef24e4cdc..bf243ac43 100644 --- a/tests/cpp/ttemplatetype.nim +++ b/tests/cpp/ttemplatetype.nim @@ -3,7 +3,7 @@ discard """ """ type - Map {.importcpp: "std::map", header: "".} [T,U] = object + Map[T,U] {.importcpp: "std::map", header: "".} = object proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.} From 89a2390f8bcf8615466aea9fd2653f57829404c4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 29 Dec 2020 08:50:22 -0600 Subject: [PATCH 1716/4254] fix printing negative zero in JS backend (#16505) --- lib/system/jssys.nim | 4 +++- tests/misc/tnegativezero.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/misc/tnegativezero.nim diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 5f18f01cb..64c766482 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -495,11 +495,13 @@ proc negInt64(a: int64): int64 {.compilerproc.} = proc nimFloatToString(a: float): cstring {.compilerproc.} = ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 + # print `-0.0` properly asm """ function nimOnlyDigitsOrMinus(n) { return n.toString().match(/^-?\d+$/); } - if (Number.isSafeInteger(`a`)) `result` = `a`+".0" + if (Number.isSafeInteger(`a`)) + `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" else { `result` = `a`+"" if(nimOnlyDigitsOrMinus(`result`)){ diff --git a/tests/misc/tnegativezero.nim b/tests/misc/tnegativezero.nim new file mode 100644 index 000000000..a443e40cf --- /dev/null +++ b/tests/misc/tnegativezero.nim @@ -0,0 +1,30 @@ +discard """ + targets: "c cpp js" +""" + +proc main()= + block: + let a = -0.0 + doAssert $a == "-0.0" + doAssert $(-0.0) == "-0.0" + + block: + let a = 0.0 + when nimvm: discard ## TODO VM print wrong -0.0 + else: + doAssert $a == "0.0" + doAssert $(0.0) == "0.0" + + block: + let b = -0 + doAssert $b == "0" + doAssert $(-0) == "0" + + block: + let b = 0 + doAssert $b == "0" + doAssert $(0) == "0" + + +static: main() +main() From 95f599ca2d94e4d58055390c4b9c7761bbd60d01 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 29 Dec 2020 09:20:47 -0600 Subject: [PATCH 1717/4254] move asciitables to std/private/ (#16498) * move asciitables * minor --- compiler/dfa.nim | 3 ++- compiler/vmgen.nim | 2 +- {compiler => lib/std/private}/asciitables.nim | 8 ++++---- tests/compiler/tasciitables.nim | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) rename {compiler => lib/std/private}/asciitables.nim (89%) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index d07122552..efd826594 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -29,7 +29,8 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, types, intsets, lineinfos, renderer, asciitables +import ast, types, intsets, lineinfos, renderer +import std/private/asciitables from patterns import sameTrees diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 9f36fc736..efb657d17 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -35,7 +35,7 @@ const debugEchoCode* = defined(nimVMDebug) when debugEchoCode: - import asciitables + import std/private/asciitables when hasFFI: import evalffi diff --git a/compiler/asciitables.nim b/lib/std/private/asciitables.nim similarity index 89% rename from compiler/asciitables.nim rename to lib/std/private/asciitables.nim index 39bb26a5c..cbc595651 100644 --- a/compiler/asciitables.nim +++ b/lib/std/private/asciitables.nim @@ -1,6 +1,6 @@ #[ -move to std/asciitables.nim once stable, or to a nimble paackage -once compiler can depend on nimble +move to std/asciitables.nim once stable, or to a fusion package +once compiler can depend on fusion ]# type Cell* = object @@ -8,7 +8,7 @@ type Cell* = object width*, row*, col*, ncols*, nrows*: int iterator parseTableCells*(s: string, delim = '\t'): Cell = - ## iterates over all cells in a `delim`-delimited `s`, after a 1st + ## Iterates over all cells in a `delim`-delimited `s`, after a 1st ## pass that computes number of rows, columns, and width of each column. var widths: seq[int] var cell: Cell @@ -69,7 +69,7 @@ iterator parseTableCells*(s: string, delim = '\t'): Cell = finishRow() proc alignTable*(s: string, delim = '\t', fill = ' ', sep = " "): string = - ## formats a `delim`-delimited `s` representing a table; each cell is aligned + ## Formats a `delim`-delimited `s` representing a table; each cell is aligned ## to a width that's computed for each column; consecutive columns are ## delimited by `sep`, and alignment space is filled using `fill`. ## More customized formatting can be done by calling `parseTableCells` directly. diff --git a/tests/compiler/tasciitables.nim b/tests/compiler/tasciitables.nim index 80d648508..2f3b7bf2f 100644 --- a/tests/compiler/tasciitables.nim +++ b/tests/compiler/tasciitables.nim @@ -1,5 +1,5 @@ import stdtest/unittest_light -import compiler/asciitables +import std/private/asciitables import strformat From 1df0c04a1c273237bef01b520d3c7dd1017b1611 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 29 Dec 2020 22:30:20 -0600 Subject: [PATCH 1718/4254] disable grams (#16511) --- testament/important_packages.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 5a9775bad..dca8c5a4f 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -44,7 +44,8 @@ pkg1 "glob" pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" pkg1 "gnuplot", "nim c gnuplot.nim" -pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" +# pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" + # pending https://github.com/nim-lang/Nim/issues/16509 pkg1 "hts", "nim c -o:htss src/hts.nim" # pkg1 "httpauth" pkg1 "illwill", "nimble examples" From 2f4d00fb98beaf6bb2e155e9da7dc7194038b5f3 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:51:17 -0600 Subject: [PATCH 1719/4254] fix #16502 (#16512) --- lib/system/io.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 22059c0a8..270779272 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -783,7 +783,7 @@ when declared(stdout): not defined(nintendoswitch) and not defined(freertos) and hostOS != "any" - const echoDoRaise = not defined(nimLegacyEchoNoRaise) # see PR #16366 + const echoDoRaise = not defined(nimLegacyEchoNoRaise) and not defined(guiapp) # see PR #16366 template checkErrMaybe(succeeded: bool): untyped = if not succeeded: From 8508c4e1c262567ecc093de8b645cec677ce5afd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 30 Dec 2020 05:58:41 -0800 Subject: [PATCH 1720/4254] fix `hintProcessing` dots interference with `static:echo` and `hintCC`; add tests for `nim secret`, add tests for hintProcessing, misc other bug fixes (#16495) * fix dots interfering with static:echo * add tests * fix hintProcessing dots for hintCC * improve trunner tests * fix bug: readLineFromStdin now writes prompt to stdout, consistent with linenoise and rdstdin * disable a failing test for windows --- compiler/extccomp.nim | 5 +++- compiler/llstream.nim | 4 +-- compiler/main.nim | 2 +- compiler/msgs.nim | 12 ++++---- compiler/options.nim | 5 +++- compiler/vm.nim | 6 ++-- tests/misc/trunner.nim | 64 ++++++++++++++++++++++++++++++++++++------ 7 files changed, 77 insertions(+), 21 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e37e867da..14b961ee1 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -848,7 +848,10 @@ proc callCCompiler*(conf: ConfigRef) = var cmds: TStringSeq var prettyCmds: TStringSeq let prettyCb = proc (idx: int) = - if prettyCmds[idx].len > 0: echo prettyCmds[idx] + if prettyCmds[idx].len > 0: + flushDot(conf) + # xxx should probably use stderr like other compiler messages, not stdout + echo prettyCmds[idx] for idx, it in conf.toCompile: # call the C compiler for the .c file: diff --git a/compiler/llstream.nim b/compiler/llstream.nim index b768e6c83..bfc377a16 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -75,10 +75,10 @@ proc llStreamClose*(s: PLLStream) = when not declared(readLineFromStdin): # fallback implementation: proc readLineFromStdin(prompt: string, line: var string): bool = - stderr.write(prompt) + stdout.write(prompt) result = readLine(stdin, line) if not result: - stderr.write("\n") + stdout.write("\n") quit(0) proc endsWith*(x: string, s: set[char]): bool = diff --git a/compiler/main.nim b/compiler/main.nim index 74c19bf10..c94c4323f 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -138,7 +138,7 @@ proc commandInteractive(graph: ModuleGraph) = var m = graph.makeStdinModule() incl(m.flags, sfMainModule) var idgen = IdGenerator(module: m.itemId.module, item: m.itemId.item) - let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config, stderr)) + let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config)) processModule(graph, m, idgen, s) proc commandScan(cache: IdentCache, config: ConfigRef) = diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6d6e21204..afb51da09 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -19,8 +19,10 @@ template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) template toStdOrrKind(stdOrr): untyped = if stdOrr == stdout: stdOrrStdout else: stdOrrStderr -template flushDot*(conf, stdOrr) = +proc flushDot*(conf: ConfigRef) = ## safe to call multiple times + # xxx one edge case not yet handled is when `printf` is called at CT with `compiletimeFFI`. + let stdOrr = if optStdout in conf.globalOptions: stdout else: stderr let stdOrrKind = toStdOrrKind(stdOrr) if stdOrrKind in conf.lastMsgWasDot: conf.lastMsgWasDot.excl stdOrrKind @@ -311,12 +313,12 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = conf.writelnHook(s) elif optStdout in conf.globalOptions or msgStdout in flags: if eStdOut in conf.m.errorOutputs: - flushDot(conf, stdout) + flushDot(conf) writeLine(stdout, s) flushFile(stdout) else: if eStdErr in conf.m.errorOutputs: - flushDot(conf, stderr) + flushDot(conf) writeLine(stderr, s) # On Windows stderr is fully-buffered when piped, regardless of C std. when defined(windows): @@ -368,11 +370,11 @@ template styledMsgWriteln*(args: varargs[typed]) = callIgnoringStyle(callWritelnHook, nil, args) elif optStdout in conf.globalOptions: if eStdOut in conf.m.errorOutputs: - flushDot(conf, stdout) + flushDot(conf) callIgnoringStyle(writeLine, stdout, args) flushFile(stdout) elif eStdErr in conf.m.errorOutputs: - flushDot(conf, stderr) + flushDot(conf) if optUseColors in conf.globalOptions: callStyledWriteLineStderr(args) else: diff --git a/compiler/options.nim b/compiler/options.nim index 87796539c..1de6d531a 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -368,8 +368,11 @@ proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) = if enabled: incl(conf.notes, note) else: excl(conf.notes, note) proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = + # ternary states instead of binary states would simplify logic if optHints notin conf.options: false - elif note in {hintConf}: # could add here other special notes like hintSource + elif note in {hintConf, hintProcessing}: + # could add here other special notes like hintSource + # these notes apply globally. note in conf.mainPackageNotes else: note in conf.notes diff --git a/compiler/vm.nim b/compiler/vm.nim index 34d76f21e..1004826ea 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1153,14 +1153,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = stackTrace(c, tos, pc, "node is not a proc symbol") of opcEcho: let rb = instr.regB - if rb == 1: - msgWriteln(c.config, regs[ra].node.strVal, {msgStdout}) + template fn(s) = msgWriteln(c.config, s, {msgStdout}) + if rb == 1: fn(regs[ra].node.strVal) else: var outp = "" for i in ra..ra+rb-1: #if regs[i].kind != rkNode: debug regs[i] outp.add(regs[i].node.strVal) - msgWriteln(c.config, outp, {msgStdout}) + fn(outp) of opcContainsSet: decodeBC(rkInt) regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index e288a56c7..530561cd9 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -12,10 +12,18 @@ from std/sequtils import toSeq,mapIt from std/algorithm import sorted import stdtest/[specialpaths, unittest_light] from std/private/globs import nativeToUnixPath - +from strutils import startsWith, strip, removePrefix +from std/sugar import dup import "$lib/../compiler/nimpaths" +proc isDots(a: string): bool = + ## test for `hintProcessing` dots + a.startsWith(".") and a.strip(chars = {'.'}) == "" + const + defaultHintsOff = "--hint:successx:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" + # useful when you want to turn only some hints on, and some common ones off. + # pending https://github.com/timotheecour/Nim/issues/453, simplify to: `--hints:off` nim = getCurrentCompilerExe() mode = when defined(c): "c" @@ -93,10 +101,9 @@ else: # don't run twice the same test check exitCode == 0 let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPath).sorted.join("\n") let context = $(i, ret, cmd) - var expected = "" case i of 0,5: - let htmlFile = htmldocsDir/"mmain.html" + let htmlFile = htmldocsDir/mainFname check htmlFile in outp # sanity check for `hintSuccessX` assertEquals ret, fmt""" {dotdotMangle}/imp.html @@ -106,7 +113,7 @@ imp.html imp.idx imp2.html imp2.idx -mmain.html +{mainFname} mmain.idx {nimdocOutCss} {theindexFname}""", context @@ -119,21 +126,21 @@ tests/nimdoc/sub/imp.html tests/nimdoc/sub/imp.idx tests/nimdoc/sub/imp2.html tests/nimdoc/sub/imp2.idx -tests/nimdoc/sub/mmain.html +tests/nimdoc/sub/{mainFname} tests/nimdoc/sub/mmain.idx {theindexFname}""" of 2, 3: assertEquals ret, fmt""" {docHackJsFname} -mmain.html +{mainFname} mmain.idx {nimdocOutCss}""", context of 4: assertEquals ret, fmt""" {docHackJsFname} {nimdocOutCss} -sub/mmain.html +sub/{mainFname} sub/mmain.idx""", context of 6: assertEquals ret, fmt""" -mmain.html +{mainFname} {nimdocOutCss}""", context else: doAssert false @@ -222,3 +229,44 @@ mmain.html check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0) check fmt"""{nim} r {opt} --eval:"echo defined(c)"""".execCmdEx == ("true\n", 0) check fmt"""{nim} r -b:js {opt} --eval:"echo defined(js)"""".execCmdEx == ("true\n", 0) + + block: # `hintProcessing` dots should not interfere with `static: echo` + friends + let cmd = fmt"""{nim} r {defaultHintsOff} --hint:processing -f --eval:"static: echo 1+1"""" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + template check3(cond) = doAssert cond, $(outp,) + doAssert exitCode == 0 + let lines = outp.splitLines + check3 lines.len == 3 + when not defined(windows): # xxx: on windows, dots not properly handled, gives: `....2\n\n` + check3 lines[0].isDots + check3 lines[1] == "2" + check3 lines[2] == "" + else: + check3 "2" in outp + + block: # nim secret + let opt = fmt"{defaultHintsOff} --hint:processing" + template check3(cond) = doAssert cond, $(outp,) + for extra in ["", "--stdout"]: + let cmd = fmt"""{nim} secret {opt} {extra}""" + # xxx minor bug: `nim --hint:QuitCalled:off secret` ignores the hint cmdline flag + template run(input2): untyped = + execCmdEx(cmd, options = {poStdErrToStdOut}, input = input2) + block: + let (outp, exitCode) = run """echo 1+2; import strutils; echo strip(" ab "); quit()""" + let lines = outp.splitLines + when not defined(windows): + check3 lines.len == 5 + check3 lines[0].isDots + check3 lines[1].dup(removePrefix(">>> ")) == "3" # prompt depends on `nimUseLinenoise` + check3 lines[2].isDots + check3 lines[3] == "ab" + check3 lines[4] == "" + else: + check3 "3" in outp + check3 "ab" in outp + doAssert exitCode == 0 + block: + let (outp, exitCode) = run "echo 1+2; quit(2)" + check3 "3" in outp + doAssert exitCode == 2 From 84a7544988ffd8d26ff50c8a9417acbededf03fb Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Wed, 30 Dec 2020 06:02:51 -0800 Subject: [PATCH 1721/4254] nim-gdb.py fixes mostly for nimsuggest debugging (#16479) These fixes were primarily developed to assist in nimsuggest debugging. There is nothing intentionally specific done for nimsuggest, but beyond the automated tests all practical testing was done with nimsuggest. Undoubltedly these will also assist in other debugging scenarios. The current nim-dbg.py script was broken in a few ways: - failed to provide detailed value information for common types (see below) - was not passing existing tests - could not produce type summary information Broken types now working somewhat better: - sequences with ref types like strings - sequences with value types like ints - arrays with ref types like strings - tables with int or string keys Other improvements: - slightly more test coverage Future considerations: - this, data used by it, should be something the compiler can generates - account for different memory layouts ([arc/orc differ](https://github.com/nim-lang/Nim/pull/16479#issuecomment-751469536)) Attempts at improving nim-gdb.py More tests, few fixes for seq and type printing Tables debugging fixed added further tests Fixed type printing --- .../untestable/gdb/gdb_pretty_printer_test.py | 26 ++- .../gdb/gdb_pretty_printer_test_program.nim | 55 +++++-- tools/nim-gdb.py | 151 +++++++++++------- 3 files changed, 156 insertions(+), 76 deletions(-) diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index f002941ec..5b34bcb3d 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -6,31 +6,47 @@ import gdb # frontends might still be broken. gdb.execute("source ../../../tools/nim-gdb.py") -# debug all instances of the generic function `myDebug`, should be 8 +# debug all instances of the generic function `myDebug`, should be 14 gdb.execute("rbreak myDebug") gdb.execute("run") outputs = [ 'meTwo', + '""', '"meTwo"', '{meOne, meThree}', 'MyOtherEnum(1)', '5', 'array = {1, 2, 3, 4, 5}', + 'seq(0, 0)', + 'seq(0, 10)', + 'array = {"one", "two"}', + 'seq(3, 3) = {1, 2, 3}', 'seq(3, 3) = {"one", "two", "three"}', - 'Table(3, 64) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', + 'Table(3, 64) = {[4] = "four", [5] = "five", [6] = "six"}', + 'Table(3, 8) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', ] for i, expected in enumerate(outputs): + gdb.write(f"{i+1}) expecting: {expected}: ", gdb.STDLOG) + gdb.flush() + functionSymbol = gdb.selected_frame().block().function assert functionSymbol.line == 21 - if i == 5: + if i == 6: # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack gdb.execute("up") - output = str(gdb.parse_and_eval("myArray")) + raw = gdb.parse_and_eval("myArray") + elif i == 9: + # myOtherArray is passed as pointer to int to myDebug. I look up myOtherArray up in the stack + gdb.execute("up") + raw = gdb.parse_and_eval("myOtherArray") else: - output = str(gdb.parse_and_eval("arg")) + raw = gdb.parse_and_eval("arg") + + output = str(raw) assert output == expected, output + " != " + expected + gdb.write(f"passed\n", gdb.STDLOG) gdb.execute("continue") diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim index 458435c1a..c376ef89a 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim +++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim @@ -23,29 +23,56 @@ proc myDebug[T](arg: T): void = proc testProc(): void = var myEnum = meTwo - myDebug(myEnum) + myDebug(myEnum) #1 + + # create a string, but don't allocate it + var myString: string + myDebug(myString) #2 + # create a string object but also make the NTI for MyEnum is generated - var myString = $myEnum - myDebug(myString) + myString = $myEnum + myDebug(myString) #3 + var mySet = {meOne,meThree} - myDebug(mySet) + myDebug(mySet) #4 # for MyOtherEnum there is no NTI. This tests the fallback for the pretty printer. var moEnum = moTwo - myDebug(moEnum) + myDebug(moEnum) #5 + var moSet = {moOne,moThree} - myDebug(moSet) + myDebug(moSet) #6 let myArray = [1,2,3,4,5] - myDebug(myArray) - let mySeq = @["one","two","three"] - myDebug(mySeq) + myDebug(myArray) #7 - var myTable = initTable[string, int]() - myTable["one"] = 1 - myTable["two"] = 2 - myTable["three"] = 3 - myDebug(myTable) + # implicitly initialized seq test + var mySeq: seq[string] + myDebug(mySeq) #8 + + # len not equal to capacity + let myOtherSeq = newSeqOfCap[string](10) + myDebug(myOtherSeq) #9 + + let myOtherArray = ["one","two"] + myDebug(myOtherArray) #10 + + # numeric sec + var mySeq3 = @[1,2,3] + myDebug(mySeq3) #11 + + # seq had to grow + var mySeq4 = @["one","two","three"] + myDebug(mySeq4) #12 + + var myTable = initTable[int, string]() + myTable[4] = "four" + myTable[5] = "five" + myTable[6] = "six" + myDebug(myTable) #13 + + var myOtherTable = {"one": 1, "two": 2, "three": 3}.toTable + myDebug(myOtherTable) #14 echo(counter) diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py index e994531b6..8143b94d5 100644 --- a/tools/nim-gdb.py +++ b/tools/nim-gdb.py @@ -34,6 +34,14 @@ def getNimRti(type_name): except: return None +def getNameFromNimRti(rti_val): + """ Return name (or None) given a Nim RTI ``gdb.Value`` """ + try: + # sometimes there isn't a name field -- example enums + return rti['name'].string(encoding="utf-8", errors="ignore") + except: + return None + class NimTypeRecognizer: # this type map maps from types that are generated in the C files to # how they are called in nim. To not mix up the name ``int`` from @@ -42,30 +50,25 @@ class NimTypeRecognizer: # ``int``. type_map_static = { - 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', 'NI64': 'int64', - 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', 'NU64': 'uint64', + 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', + 'NI64': 'int64', + + 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', + 'NU64': 'uint64', + 'NF': 'float', 'NF32': 'float32', 'NF64': 'float64', - 'NIM_BOOL': 'bool', 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', - 'NimStringDesc': 'string' + + 'NIM_BOOL': 'bool', + + 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string' } - # Normally gdb distinguishes between the command `ptype` and - # `whatis`. `ptype` prints a very detailed view of the type, and - # `whatis` a very brief representation of the type. I haven't - # figured out a way to know from the type printer that is - # implemented here how to know if a type printer should print the - # short representation or the long representation. As a hacky - # workaround I just say I am not resposible for printing pointer - # types (seq and string are exception as they are semantically - # values). this way the default type printer will handle pointer - # types and dive into the members of that type. So I can still - # control with `ptype myval` and `ptype *myval` if I want to have - # detail or not. I this this method stinks but I could not figure - # out a better solution. - - object_type_pattern = re.compile("^(\w*):ObjectType$") + # object_type_pattern = re.compile("^(\w*):ObjectType$") def recognize(self, type_obj): + # skip things we can't handle like functions + if type_obj.code in [gdb.TYPE_CODE_FUNC, gdb.TYPE_CODE_VOID]: + return None tname = None if type_obj.tag is not None: @@ -75,44 +78,43 @@ class NimTypeRecognizer: # handle pointer types if not tname: - if type_obj.code == gdb.TYPE_CODE_PTR: + target_type = type_obj + if type_obj.code in [gdb.TYPE_CODE_PTR]: target_type = type_obj.target() - target_type_name = target_type.name - if target_type_name: - # visualize 'string' as non pointer type (unpack pointer type). - if target_type_name == "NimStringDesc": - tname = target_type_name # could also just return 'string' - # visualize 'seq[T]' as non pointer type. - if target_type_name.find('tySequence_') == 0: - tname = target_type_name - if not tname: - # We are not resposible for this type printing. - # Basically this means we don't print pointer types. - return None + if target_type.name: + # visualize 'string' as non pointer type (unpack pointer type). + if target_type.name == "NimStringDesc": + tname = target_type.name # could also just return 'string' + else: + rti = getNimRti(target_type.name) + if rti: + return getNameFromNimRti(rti) - result = self.type_map_static.get(tname, None) - if result: - return result + if tname: + result = self.type_map_static.get(tname, None) + if result: + return result - rti = getNimRti(tname) - if rti: - return rti['name'].string("utf-8", "ignore") - else: - return None + rti = getNimRti(tname) + if rti: + return getNameFromNimRti(rti) + + return None class NimTypePrinter: """Nim type printer. One printer for all Nim types.""" - # enabling and disabling of type printers can be done with the # following gdb commands: # # enable type-printer NimTypePrinter # disable type-printer NimTypePrinter + # relevant docs: https://sourceware.org/gdb/onlinedocs/gdb/Type-Printing-API.html name = "NimTypePrinter" - def __init__ (self): + + def __init__(self): self.enabled = True def instantiate(self): @@ -309,9 +311,25 @@ class NimStringPrinter: def to_string(self): if self.val: l = int(self.val['Sup']['len']) - return self.val['data'][0].address.string("utf-8", "ignore", l) + return self.val['data'].lazy_string(encoding="utf-8", length=l) else: - return "" + return "" + +# class NimStringPrinter: +# pattern = re.compile(r'^NimStringDesc$') + +# def __init__(self, val): +# self.val = val + +# def display_hint(self): +# return 'string' + +# def to_string(self): +# if self.val: +# l = int(self.val['Sup']['len']) +# return self.val['data'].lazy_string(encoding="utf-8", length=l) +# else: +# return "" class NimRopePrinter: pattern = re.compile(r'^tyObject_RopeObj__([A-Za-z0-9]*) \*$') @@ -372,14 +390,15 @@ class NimEnumPrinter: pattern = re.compile(r'^tyEnum_(\w*)__([A-Za-z0-9]*)$') def __init__(self, val): - self.val = val - match = self.pattern.match(self.val.type.name) + self.val = val + typeName = self.val.type.name + match = self.pattern.match(typeName) self.typeNimName = match.group(1) typeInfoName = "NTI__" + match.group(2) + "_" self.nti = gdb.lookup_global_symbol(typeInfoName) if self.nti is None: - printErrorOnce(typeInfoName, "NimEnumPrinter: lookup global symbol '" + typeInfoName + " failed for " + self.val.type.name + ".\n") + printErrorOnce(typeInfoName, f"NimEnumPrinter: lookup global symbol '{typeInfoName}' failed for {typeName}.\n") def to_string(self): if self.nti: @@ -476,11 +495,31 @@ class NimSeqPrinter: def children(self): if self.val: - length = int(self.val['Sup']['len']) - #align = len(str(length - 1)) - for i in range(length): - yield ("data[{0}]".format(i), self.val["data"][i]) + val = self.val + valType = val.type + length = int(val['Sup']['len']) + if length <= 0: + return + + dataType = valType['data'].type + data = val['data'] + + if self.val.type.name is None: + dataType = valType['data'].type.target().pointer() + data = val['data'].cast(dataType) + + inaccessible = False + for i in range(length): + if inaccessible: + return + try: + str(data[i]) + yield "data[{0}]".format(i), data[i] + except RuntimeError: + inaccessible = True + yield "data[{0}]".format(i), "inaccessible" + ################################################################################ class NimArrayPrinter: @@ -524,9 +563,9 @@ class NimStringTablePrinter: def children(self): if self.val: - data = NimSeqPrinter(self.val['data']) + data = NimSeqPrinter(self.val['data'].dereference()) for idxStr, entry in data.children(): - if int(entry['Field2']) > 0: + if int(entry['Field0']) != 0: yield (idxStr + ".Field0", entry['Field0']) yield (idxStr + ".Field1", entry['Field1']) @@ -537,7 +576,6 @@ class NimTablePrinter: def __init__(self, val): self.val = val - # match = self.pattern.match(self.val.type.name) def display_hint(self): return 'map' @@ -556,11 +594,10 @@ class NimTablePrinter: if self.val: data = NimSeqPrinter(self.val['data']) for idxStr, entry in data.children(): - if int(entry['Field0']) > 0: + if int(entry['Field0']) != 0: yield (idxStr + '.Field1', entry['Field1']) yield (idxStr + '.Field2', entry['Field2']) - ################################################################ # this is untested, therefore disabled @@ -651,7 +688,7 @@ def register_nim_pretty_printers_for_object(objfile): if nimMainSym and nimMainSym.symtab.objfile == objfile: print("set Nim pretty printers for ", objfile.filename) - objfile.type_printers = [NimTypePrinter()] + gdb.types.register_type_printer(objfile, NimTypePrinter()) objfile.pretty_printers = [makematcher(var) for var in list(globals().values()) if hasattr(var, 'pattern')] # Register pretty printers for all objfiles that are already loaded. From 73f778e441cd4229af4115f762bd597a8a20fb74 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 30 Dec 2020 08:06:50 -0600 Subject: [PATCH 1722/4254] follow #16505 move and active tests (#16508) * fix printing negative zero in JS backend * move tests --- tests/misc/tnegativezero.nim | 30 ------------------------------ tests/system/tdollars.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 30 deletions(-) delete mode 100644 tests/misc/tnegativezero.nim diff --git a/tests/misc/tnegativezero.nim b/tests/misc/tnegativezero.nim deleted file mode 100644 index a443e40cf..000000000 --- a/tests/misc/tnegativezero.nim +++ /dev/null @@ -1,30 +0,0 @@ -discard """ - targets: "c cpp js" -""" - -proc main()= - block: - let a = -0.0 - doAssert $a == "-0.0" - doAssert $(-0.0) == "-0.0" - - block: - let a = 0.0 - when nimvm: discard ## TODO VM print wrong -0.0 - else: - doAssert $a == "0.0" - doAssert $(0.0) == "0.0" - - block: - let b = -0 - doAssert $b == "0" - doAssert $(-0) == "0" - - block: - let b = 0 - doAssert $b == "0" - doAssert $(0) == "0" - - -static: main() -main() diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 6ddec911f..1b2602ad0 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -77,3 +77,29 @@ block: # #14350 for JS doAssert cstr == nil doAssert cstr.isNil doAssert cstr != cstring("") + + +proc main()= + block: + let a = -0.0 + doAssert $a == "-0.0" + doAssert $(-0.0) == "-0.0" + + block: + let a = 0.0 + doAssert $a == "0.0" + doAssert $(0.0) == "0.0" + + block: + let b = -0 + doAssert $b == "0" + doAssert $(-0) == "0" + + block: + let b = 0 + doAssert $b == "0" + doAssert $(0) == "0" + + +static: main() +main() From 515cd454207ed9066c08ac8ef42407ae5ba62bc8 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 30 Dec 2020 08:09:30 -0600 Subject: [PATCH 1723/4254] Add math.copySign (#16406) * add math.copySign * fix + tests --- changelog.md | 1 + compiler/vmops.nim | 6 +++++ lib/pure/math.nim | 38 ++++++++++++++++++++++++++++++++ tests/stdlib/tmath.nim | 50 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 035ba46b8..bbc83ff25 100644 --- a/changelog.md +++ b/changelog.md @@ -69,6 +69,7 @@ - `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. +- Added `math.copySign`. - Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList` and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 47df3d24f..3e859d3d7 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -13,6 +13,9 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, floor, ceil, `mod` +when declared(math.copySign): + from math import copySign + from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename from md5 import getMD5 from sighashes import symBodyDigest @@ -168,6 +171,9 @@ proc registerAdditionalOps*(c: PCtx) = wrap1f_math(floor) wrap1f_math(ceil) + when declared(copySign): + wrap2f_math(copySign) + wrap1s(getMD5, md5op) proc `mod Wrapper`(a: VmArgs) {.nimcall.} = diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 5b19a8ec0..76052ec3b 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -62,6 +62,9 @@ when defined(c) or defined(cpp): proc c_isnan(x: float): bool {.importc: "isnan", header: "".} # a generic like `x: SomeFloat` might work too if this is implemented via a C macro. + proc c_copysign(x, y: cfloat): cfloat {.importc: "copysignf", header: "".} + proc c_copysign(x, y: cdouble): cdouble {.importc: "copysign", header: "".} + func binom*(n, k: int): int = ## Computes the `binomial coefficient `_. runnableExamples: @@ -153,6 +156,40 @@ func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = when defined(js): fn() else: result = c_isnan(x) +func copySign*[T: SomeFloat](x, y: T): T {.inline, since: (1, 5, 1).} = + ## Returns a value with the magnitude of `x` and the sign of `y`; + ## this works even if x or y are NaN or zero, both of which can carry a sign. + runnableExamples: + doAssert copySign(1.0, -0.0) == -1.0 + doAssert copySign(0.0, -0.0) == -0.0 + doAssert copySign(-1.0, 0.0) == 1.0 + doAssert copySign(10.0, 0.0) == 10.0 + + doAssert copySign(Inf, -1.0) == -Inf + doAssert copySign(-Inf, 1.0) == Inf + doAssert copySign(-1.0, NaN) == 1.0 + doAssert copySign(10.0, NaN) == 10.0 + + doAssert copySign(NaN, 0.0).isNaN + doAssert copySign(NaN, -0.0).isNaN + + # fails in VM and JS backend + doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 + + # TODO use signbit for examples + template impl() = + if y > 0.0 or (y == 0.0 and 1.0 / y > 0.0): + result = abs(x) + elif y <= 0.0: + result = -abs(x) + else: # must be NaN + result = abs(x) + + when defined(js): impl() + else: + when nimvm: impl() + else: result = c_copysign(x, y) + func classify*(x: float): FloatClass = ## Classifies a floating point value. ## @@ -1159,3 +1196,4 @@ func lcm*[T](x: openArray[T]): T {.since: (1, 1).} = while i < x.len: result = lcm(result, x[i]) inc(i) + diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 64a4ff0ca..1b6fb4e9f 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -308,5 +308,53 @@ template main = doAssert not Inf.isNaN doAssert isNaN(Inf - Inf) -main() + block: # copySign + doAssert copySign(10.0, -1.0) == -10.0 + doAssert copySign(-10.0, -1.0) == -10.0 + doAssert copySign(-10.0, 1.0) == 10.0 + doAssert copySign(float(10), -1.0) == -10.0 + + doAssert copySign(10.0'f64, -1.0) == -10.0 + doAssert copySign(-10.0'f64, -1.0) == -10.0 + doAssert copySign(-10.0'f64, 1.0) == 10.0 + doAssert copySign(10'f64, -1.0) == -10.0 + + doAssert copySign(10.0'f32, -1.0) == -10.0 + doAssert copySign(-10.0'f32, -1.0) == -10.0 + doAssert copySign(-10.0'f32, 1.0) == 10.0 + doAssert copySign(10'f32, -1.0) == -10.0 + + doAssert copySign(Inf, -1.0) == -Inf + doAssert copySign(-Inf, 1.0) == Inf + doAssert copySign(Inf, 1.0) == Inf + doAssert copySign(-Inf, -1.0) == -Inf + doAssert copySign(Inf, 0.0) == Inf + doAssert copySign(Inf, -0.0) == -Inf + doAssert copySign(-Inf, 0.0) == Inf + doAssert copySign(-Inf, -0.0) == -Inf + doAssert copySign(1.0, -0.0) == -1.0 + doAssert copySign(0.0, -0.0) == -0.0 + doAssert copySign(-1.0, 0.0) == 1.0 + doAssert copySign(10.0, 0.0) == 10.0 + doAssert copySign(-1.0, NaN) == 1.0 + doAssert copySign(10.0, NaN) == 10.0 + + doAssert copySign(NaN, NaN).isNaN + doAssert copySign(-NaN, NaN).isNaN + doAssert copySign(NaN, -NaN).isNaN + doAssert copySign(-NaN, -NaN).isNaN + doAssert copySign(NaN, 0.0).isNaN + doAssert copySign(NaN, -0.0).isNaN + doAssert copySign(-NaN, 0.0).isNaN + doAssert copySign(-NaN, -0.0).isNaN + + when nimvm: + discard + else: + when not defined(js): + doAssert copySign(-1.0, -NaN) == 1.0 + doAssert copySign(10.0, -NaN) == 10.0 + doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 # fails in VM + static: main() +main() From b8658a3e242f7304f7b0320089ef5aa0d5375c25 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 30 Dec 2020 11:10:50 -0300 Subject: [PATCH 1724/4254] Add assertions for jsconsole (#16460) --- changelog.md | 1 + lib/js/jsconsole.nim | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index bbc83ff25..c6a1d17d9 100644 --- a/changelog.md +++ b/changelog.md @@ -79,6 +79,7 @@ - Added `euclDiv` and `euclMod` to `math`. - Added `httpcore.is1xx` and missing HTTP codes. +- Added `jsconsole.jsAssert` for JavaScript target. ## Language changes diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index 35afd95ad..5b9893e75 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -10,10 +10,12 @@ ## Wrapper for the `console` object for the `JavaScript backend ## `_. +import std/private/since, std/private/miscdollars # toLocation + when not defined(js) and not defined(Nimdoc): {.error: "This module only works on the JavaScript platform".} -type Console* = ref object of RootObj +type Console* = ref object of JsRoot proc log*(console: Console) {.importcpp, varargs.} ## https://developer.mozilla.org/docs/Web/API/Console/log @@ -67,4 +69,34 @@ proc timeLog*(console: Console, label = "".cstring) {.importcpp.} proc table*(console: Console) {.importcpp, varargs.} ## https://developer.mozilla.org/docs/Web/API/Console/table +since (1, 5): + type InstantiationInfo = tuple[filename: string, line: int, column: int] + + func getMsg(info: InstantiationInfo; msg: string): string = + var temp = "" + temp.toLocation(info.filename, info.line, info.column + 1) + result.addQuoted(temp) + result.add ',' + result.addQuoted(msg) + + template jsAssert*(console: Console; assertion) = + ## JavaScript `console.assert`, for NodeJS this prints to stderr, + ## assert failure just prints to console and do not quit the program, + ## this is not meant to be better or even equal than normal assertions, + ## is just for when you need faster performance *and* assertions, + ## otherwise use the normal assertions for better user experience. + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/assert + runnableExamples: + console.jsAssert(42 == 42) # OK + console.jsAssert(42 != 42) # Fail, prints "Assertion failed" and continues + console.jsAssert('`' == '\n' and '\t' == '\0') # Message correctly formatted + assert 42 == 42 # Normal assertions keep working + + const + loc = instantiationInfo(fullPaths = compileOption("excessiveStackTrace")) + msg = getMsg(loc, astToStr(assertion)).cstring + {.line: loc.}: + {.emit: ["console.assert(", assertion, ", ", msg, ");"].} + + var console* {.importc, nodecl.}: Console From 805917768dea1b223a3aab3131d5c76f862b4984 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 30 Dec 2020 09:26:49 -0600 Subject: [PATCH 1725/4254] use runnableExamples in options (#16503) --- lib/pure/options.nim | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 8de4430c1..195da1008 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -23,38 +23,29 @@ ## Let's start with an example: a procedure that finds the index of a character ## in a string. ## -## .. code-block:: nim -## -## import options -## -## proc find(haystack: string, needle: char): Option[int] = -## for i, c in haystack: -## if c == needle: -## return some(i) -## return none(int) # This line is actually optional, -## # because the default is empty -## -## .. code-block:: nim -## -## let found = "abc".find('c') -## assert found.isSome and found.get() == 2 -## +runnableExamples: + proc find(haystack: string, needle: char): Option[int] = + for i, c in haystack: + if c == needle: + return some(i) + return none(int) # This line is actually optional, + # because the default is empty + + let found = "abc".find('c') + assert found.isSome and found.get() == 2 + ## The `get` operation demonstrated above returns the underlying value, or ## raises `UnpackDefect` if there is no value. Note that `UnpackDefect` ## inherits from `system.Defect`, and should therefore never be caught. ## Instead, rely on checking if the option contains a value with ## `isSome <#isSome,Option[T]>`_ and `isNone <#isNone,Option[T]>`_ procs. -## +## ## How to deal with an absence of a value: -## -## .. code-block:: nim -## -## let result = "team".find('i') -## -## # Nothing was found, so the result is `none`. -## assert(result == none(int)) -## # It has no value: -## assert(result.isNone) + +runnableExamples: + let result = none(int) + # It has no value: + assert(result.isNone) import typetraits From b42e7c0ef909a9712e4e8f87be304db5c105e721 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 30 Dec 2020 10:30:43 -0600 Subject: [PATCH 1726/4254] make the docs of arithmetics better (#16510) * fix * Update lib/system/arithmetics.nim Co-authored-by: Timothee Cour * Apply suggestions from code review Co-authored-by: Timothee Cour * Apply suggestions from code review Co-authored-by: Timothee Cour Co-authored-by: Timothee Cour --- lib/system/arithmetics.nim | 229 +++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 124 deletions(-) diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index f6c1b69ff..4242cd1e3 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -1,48 +1,44 @@ -proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} - ## Returns the ``y``-th successor (default: 1) of the value ``x``. - ## ``T`` has to be an `ordinal type <#Ordinal>`_. +proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} = + ## Returns the `y`-th successor (default: 1) of the value `x`. ## - ## If such a value does not exist, ``OverflowDefect`` is raised + ## If such a value does not exist, `OverflowDefect` is raised ## or a compile time error occurs. - ## - ## .. code-block:: Nim - ## let x = 5 - ## echo succ(5) # => 6 - ## echo succ(5, 3) # => 8 + runnableExamples: + assert succ(5) == 6 + assert succ(5, 3) == 8 -proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} - ## Returns the ``y``-th predecessor (default: 1) of the value ``x``. - ## ``T`` has to be an `ordinal type <#Ordinal>`_. +proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} = + ## Returns the `y`-th predecessor (default: 1) of the value `x`. ## - ## If such a value does not exist, ``OverflowDefect`` is raised + ## If such a value does not exist, `OverflowDefect` is raised ## or a compile time error occurs. - ## - ## .. code-block:: Nim - ## let x = 5 - ## echo pred(5) # => 4 - ## echo pred(5, 3) # => 2 + runnableExamples: + assert pred(5) == 4 + assert pred(5, 3) == 2 -proc inc*[T: Ordinal](x: var T, y = 1) {.magic: "Inc", noSideEffect.} - ## Increments the ordinal ``x`` by ``y``. +proc inc*[T: Ordinal](x: var T, y = 1) {.magic: "Inc", noSideEffect.} = + ## Increments the ordinal `x` by `y`. ## - ## If such a value does not exist, ``OverflowDefect`` is raised or a compile - ## time error occurs. This is a short notation for: ``x = succ(x, y)``. - ## - ## .. code-block:: Nim - ## var i = 2 - ## inc(i) # i <- 3 - ## inc(i, 3) # i <- 6 + ## If such a value does not exist, `OverflowDefect` is raised or a compile + ## time error occurs. This is a short notation for: `x = succ(x, y)`. + runnableExamples: + var i = 2 + inc(i) + assert i == 3 + inc(i, 3) + assert i == 6 -proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} - ## Decrements the ordinal ``x`` by ``y``. +proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} = + ## Decrements the ordinal `x` by `y`. ## - ## If such a value does not exist, ``OverflowDefect`` is raised or a compile - ## time error occurs. This is a short notation for: ``x = pred(x, y)``. - ## - ## .. code-block:: Nim - ## var i = 2 - ## dec(i) # i <- 1 - ## dec(i, 3) # i <- -2 + ## If such a value does not exist, `OverflowDefect` is raised or a compile + ## time error occurs. This is a short notation for: `x = pred(x, y)`. + runnableExamples: + var i = 2 + dec(i) + assert i == 1 + dec(i, 3) + assert i == -2 @@ -51,38 +47,38 @@ proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} when defined(nimNoZeroExtendMagic): proc ze*(x: int8): int {.deprecated.} = - ## zero extends a smaller integer type to ``int``. This treats `x` as + ## zero extends a smaller integer type to `int`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int](uint(cast[uint8](x))) proc ze*(x: int16): int {.deprecated.} = - ## zero extends a smaller integer type to ``int``. This treats `x` as + ## zero extends a smaller integer type to `int`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int](uint(cast[uint16](x))) proc ze64*(x: int8): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## zero extends a smaller integer type to `int64`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int64](uint64(cast[uint8](x))) proc ze64*(x: int16): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## zero extends a smaller integer type to `int64`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int64](uint64(cast[uint16](x))) proc ze64*(x: int32): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## zero extends a smaller integer type to `int64`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int64](uint64(cast[uint32](x))) proc ze64*(x: int): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## zero extends a smaller integer type to `int64`. This treats `x` as + ## unsigned. Does nothing if the size of an `int` is the same as `int64`. ## (This is the case on 64 bit processors.) ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int64](uint64(cast[uint](x))) @@ -94,46 +90,46 @@ when defined(nimNoZeroExtendMagic): cast[int8](x) proc toU16*(x: int): int16 {.deprecated.} = - ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## treats `x` as unsigned and converts it to an `int16` by taking the last ## 16 bits from `x`. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int16](x) proc toU32*(x: int64): int32 {.deprecated.} = - ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## treats `x` as unsigned and converts it to an `int32` by taking the ## last 32 bits from `x`. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. cast[int32](x) elif not defined(js): proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int``. This treats `x` as + ## zero extends a smaller integer type to `int`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int``. This treats `x` as + ## zero extends a smaller integer type to `int`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## zero extends a smaller integer type to `int64`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## zero extends a smaller integer type to `int64`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## zero extends a smaller integer type to `int64`. This treats `x` as ## unsigned. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## zero extends a smaller integer type to `int64`. This treats `x` as + ## unsigned. Does nothing if the size of an `int` is the same as `int64`. ## (This is the case on 64 bit processors.) ## **Deprecated since version 0.19.9**: Use unsigned integers instead. @@ -143,12 +139,12 @@ elif not defined(js): ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## treats `x` as unsigned and converts it to an `int16` by taking the last ## 16 bits from `x`. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## treats `x` as unsigned and converts it to an `int32` by taking the ## last 32 bits from `x`. ## **Deprecated since version 0.19.9**: Use unsigned integers instead. @@ -167,20 +163,13 @@ proc `-`*(x: int16): int16 {.magic: "UnaryMinusI", noSideEffect.} proc `-`*(x: int32): int32 {.magic: "UnaryMinusI", noSideEffect.} proc `-`*(x: int64): int64 {.magic: "UnaryMinusI64", noSideEffect.} -proc `not`*(x: int): int {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: int): int {.magic: "BitnotI", noSideEffect.} = ## Computes the `bitwise complement` of the integer `x`. - ## - ## .. code-block:: Nim - ## var - ## a = 0'u8 - ## b = 0'i8 - ## c = 1000'u16 - ## d = 1000'i16 - ## - ## echo not a # => 255 - ## echo not b # => -1 - ## echo not c # => 64535 - ## echo not d # => -1001 + runnableExamples: + assert not 0'u8 == 255 + assert not 0'i8 == -1 + assert not 1000'u16 == 64535 + assert not 1000'i16 == -1001 proc `not`*(x: int8): int8 {.magic: "BitnotI", noSideEffect.} proc `not`*(x: int16): int16 {.magic: "BitnotI", noSideEffect.} proc `not`*(x: int32): int32 {.magic: "BitnotI", noSideEffect.} @@ -207,34 +196,32 @@ proc `*`*(x, y: int16): int16 {.magic: "MulI", noSideEffect.} proc `*`*(x, y: int32): int32 {.magic: "MulI", noSideEffect.} proc `*`*(x, y: int64): int64 {.magic: "MulI", noSideEffect.} -proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} +proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} = ## Computes the integer division. ## - ## This is roughly the same as ``trunc(x/y)``. - ## - ## .. code-block:: Nim - ## ( 1 div 2) == 0 - ## ( 2 div 2) == 1 - ## ( 3 div 2) == 1 - ## ( 7 div 3) == 2 - ## (-7 div 3) == -2 - ## ( 7 div -3) == -2 - ## (-7 div -3) == 2 + ## This is roughly the same as `math.trunc(x/y).int`. + runnableExamples: + assert (1 div 2) == 0 + assert (2 div 2) == 1 + assert (3 div 2) == 1 + assert (7 div 3) == 2 + assert (-7 div 3) == -2 + assert (7 div -3) == -2 + assert (-7 div -3) == 2 proc `div`*(x, y: int8): int8 {.magic: "DivI", noSideEffect.} proc `div`*(x, y: int16): int16 {.magic: "DivI", noSideEffect.} proc `div`*(x, y: int32): int32 {.magic: "DivI", noSideEffect.} proc `div`*(x, y: int64): int64 {.magic: "DivI", noSideEffect.} -proc `mod`*(x, y: int): int {.magic: "ModI", noSideEffect.} +proc `mod`*(x, y: int): int {.magic: "ModI", noSideEffect.} = ## Computes the integer modulo operation (remainder). ## - ## This is the same as ``x - (x div y) * y``. - ## - ## .. code-block:: Nim - ## ( 7 mod 5) == 2 - ## (-7 mod 5) == -2 - ## ( 7 mod -5) == 2 - ## (-7 mod -5) == -2 + ## This is the same as `x - (x div y) * y`. + runnableExamples: + assert (7 mod 5) == 2 + assert (-7 mod 5) == -2 + assert (7 mod -5) == 2 + assert (-7 mod -5) == -2 proc `mod`*(x, y: int8): int8 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int16): int16 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.} @@ -248,7 +235,7 @@ when defined(nimOldShiftRight) or not defined(nimAshr): proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} else: - proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} = ## Computes the `shift right` operation of `x` and `y`, filling ## vacant bit positions with the sign bit. ## @@ -256,38 +243,36 @@ else: ## is different than in *C*. ## ## See also: - ## * `ashr proc <#ashr,int,SomeInteger>`_ for arithmetic shift right - ## - ## .. code-block:: Nim - ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 - ## 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 - ## 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 - ## -1 shr 5 == -1 - ## 1 shr 5 == 0 - ## 16 shr 2 == 4 - ## -16 shr 2 == -4 + ## * `ashr func<#ashr,int,SomeInteger>`_ for arithmetic shift right + runnableExamples: + assert 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 + assert 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 + assert 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 + assert -1 shr 5 == -1 + assert 1 shr 5 == 0 + assert 16 shr 2 == 4 + assert -16 shr 2 == -4 proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} -proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} = ## Computes the `shift left` operation of `x` and `y`. ## ## **Note**: `Operator precedence `_ ## is different than in *C*. - ## - ## .. code-block:: Nim - ## 1'i32 shl 4 == 0x0000_0010 - ## 1'i64 shl 4 == 0x0000_0000_0000_0010 + runnableExamples: + assert 1'i32 shl 4 == 0x0000_0010 + assert 1'i64 shl 4 == 0x0000_0000_0000_0010 proc `shl`*(x: int8, y: SomeInteger): int8 {.magic: "ShlI", noSideEffect.} proc `shl`*(x: int16, y: SomeInteger): int16 {.magic: "ShlI", noSideEffect.} proc `shl`*(x: int32, y: SomeInteger): int32 {.magic: "ShlI", noSideEffect.} proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.} when defined(nimAshr): - proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} = ## Shifts right by pushing copies of the leftmost bit in from the left, ## and let the rightmost bits fall off. ## @@ -295,12 +280,11 @@ when defined(nimAshr): ## call syntax for it. ## ## See also: - ## * `shr proc <#shr,int,SomeInteger>`_ - ## - ## .. code-block:: Nim - ## ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8 - ## ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8 - ## ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8 + ## * `shr func<#shr,int,SomeInteger>`_ + runnableExamples: + assert ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8 + assert ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8 + assert ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8 proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} proc ashr*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} @@ -309,34 +293,31 @@ else: # used for bootstrapping the compiler proc ashr*[T](x: T, y: SomeInteger): T = discard -proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} = ## Computes the `bitwise and` of numbers `x` and `y`. - ## - ## .. code-block:: Nim - ## (0b0011 and 0b0101) == 0b0001 - ## (0b0111 and 0b1100) == 0b0100 + runnableExamples: + assert (0b0011 and 0b0101) == 0b0001 + assert (0b0111 and 0b1100) == 0b0100 proc `and`*(x, y: int8): int8 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int16): int16 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int32): int32 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int64): int64 {.magic: "BitandI", noSideEffect.} -proc `or`*(x, y: int): int {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: int): int {.magic: "BitorI", noSideEffect.} = ## Computes the `bitwise or` of numbers `x` and `y`. - ## - ## .. code-block:: Nim - ## (0b0011 or 0b0101) == 0b0111 - ## (0b0111 or 0b1100) == 0b1111 + runnableExamples: + assert (0b0011 or 0b0101) == 0b0111 + assert (0b0111 or 0b1100) == 0b1111 proc `or`*(x, y: int8): int8 {.magic: "BitorI", noSideEffect.} proc `or`*(x, y: int16): int16 {.magic: "BitorI", noSideEffect.} proc `or`*(x, y: int32): int32 {.magic: "BitorI", noSideEffect.} proc `or`*(x, y: int64): int64 {.magic: "BitorI", noSideEffect.} -proc `xor`*(x, y: int): int {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: int): int {.magic: "BitxorI", noSideEffect.} = ## Computes the `bitwise xor` of numbers `x` and `y`. - ## - ## .. code-block:: Nim - ## (0b0011 xor 0b0101) == 0b0110 - ## (0b0111 xor 0b1100) == 0b1011 + runnableExamples: + assert (0b0011 xor 0b0101) == 0b0110 + assert (0b0111 xor 0b1100) == 0b1011 proc `xor`*(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.} proc `xor`*(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.} From 876fa3e62e41cd366b89137cc3c4f6b5b8b2bee8 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Wed, 30 Dec 2020 21:41:25 -0300 Subject: [PATCH 1727/4254] adding missing commas in std/bitops (#16520) adding missing commas between the importc and header pragmas of some procs. --- lib/pure/bitops.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 4f22388f3..855289e84 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -477,11 +477,11 @@ when useGCC_builtins: elif useVCC_builtins: # Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer. proc builtin_popcnt16(a2: uint16): uint16 {. - importc: "__popcnt16"header: "", noSideEffect.} + importc: "__popcnt16", header: "", noSideEffect.} proc builtin_popcnt32(a2: uint32): uint32 {. - importc: "__popcnt"header: "", noSideEffect.} + importc: "__popcnt", header: "", noSideEffect.} proc builtin_popcnt64(a2: uint64): uint64 {. - importc: "__popcnt64"header: "", noSideEffect.} + importc: "__popcnt64", header: "", noSideEffect.} # Search the mask data from most significant bit (MSB) to least significant bit (LSB) for a set bit (1). proc bitScanReverse(index: ptr culong, mask: culong): cuchar {. @@ -506,9 +506,9 @@ elif useICC_builtins: # see also: https://software.intel.com/en-us/node/523362 # Count the number of bits set to 1 in an integer a, and return that count in dst. proc builtin_popcnt32(a: cint): cint {. - importc: "_popcnt"header: "", noSideEffect.} + importc: "_popcnt", header: "", noSideEffect.} proc builtin_popcnt64(a: uint64): cint {. - importc: "_popcnt64"header: "", noSideEffect.} + importc: "_popcnt64", header: "", noSideEffect.} # Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined. proc bitScanForward(p: ptr uint32, b: uint32): cuchar {. From 17992fca1dc0b3674dce123296b277551bbca1db Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 30 Dec 2020 20:29:22 -0800 Subject: [PATCH 1728/4254] disable ggplotnim, refs #16523 (#16524) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index dca8c5a4f..65104e1fe 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -41,7 +41,7 @@ pkg1 "fidget" pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "glob" -pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" +# pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pending bug #16523 # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" pkg1 "gnuplot", "nim c gnuplot.nim" # pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" From 5984f7a7dda5e6fb3119cd5705d5758e1b8f3fc7 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 31 Dec 2020 13:20:04 +0300 Subject: [PATCH 1729/4254] RST: improve line blocks (#16518) --- lib/packages/docutils/rst.nim | 24 +++++++++----- lib/packages/docutils/rstast.nim | 5 +-- lib/packages/docutils/rstgen.nim | 16 +++++++-- nimdoc/rst2html/expected/rst_examples.html | 2 +- tests/stdlib/trstgen.nim | 38 +++++++++++++++++++--- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 698d76da1..8d16edc61 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1147,7 +1147,8 @@ proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool = proc isLineBlock(p: RstParser): bool = var j = tokenAfterNewline(p) result = currentTok(p).col == p.tok[j].col and p.tok[j].symbol == "|" or - p.tok[j].col > currentTok(p).col + p.tok[j].col > currentTok(p).col or + p.tok[j].symbol == "\n" proc predNL(p: RstParser): bool = result = true @@ -1245,21 +1246,28 @@ proc whichSection(p: RstParser): RstNodeKind = proc parseLineBlock(p: var RstParser): PRstNode = result = nil - if nextTok(p).kind == tkWhite: + if nextTok(p).kind in {tkWhite, tkIndent}: var col = currentTok(p).col result = newRstNode(rnLineBlock) - pushInd(p, p.tok[p.idx + 2].col) - inc p.idx, 2 while true: var item = newRstNode(rnLineBlockItem) - parseSection(p, item) + if nextTok(p).kind == tkWhite: + if nextTok(p).symbol.len > 1: # pass additional indentation after '| ' + item.text = nextTok(p).symbol + inc p.idx, 2 + pushInd(p, p.tok[p.idx].col) + parseSection(p, item) + popInd(p) + else: # tkIndent => add an empty line + item.text = "\n" + inc p.idx, 1 result.add(item) if currentTok(p).kind == tkIndent and currentTok(p).ival == col and - nextTok(p).symbol == "|" and p.tok[p.idx + 2].kind == tkWhite: - inc p.idx, 3 + nextTok(p).symbol == "|" and + p.tok[p.idx + 2].kind in {tkWhite, tkIndent}: + inc p.idx, 1 else: break - popInd(p) proc parseParagraph(p: var RstParser, result: PRstNode) = while true: diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index f01bcada1..e4e192fa3 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -35,7 +35,8 @@ type rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock, rnLineBlock, # the | thingie - rnLineBlockItem, # sons of the | thing + rnLineBlockItem, # a son of rnLineBlock - one line inside it. + # When `RstNode` text="\n" the line's empty rnBlockQuote, # text just indented rnTable, rnGridTable, rnMarkdownTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, rnLabel, # used for footnotes and other things @@ -73,7 +74,7 @@ type kind*: RstNodeKind ## the node's kind text*: string ## valid for leafs in the AST; and the title of ## the document or the section; and rnEnumList - ## and rnAdmonition + ## and rnAdmonition; and rnLineBlockItem level*: int ## valid for some node kinds sons*: RstNodeSeq ## the node's sons diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 5aa2b03d4..52125b52c 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1160,9 +1160,21 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnQuotedLiteralBlock: doAssert false, "renderRstToOut" of rnLineBlock: - renderAux(d, n, "

                                      $1

                                      ", "$1\n\n", result) + if n.sons.len == 1 and n.sons[0].text == "\n": + # whole line block is one empty line, no need to add extra spacing + renderAux(d, n, "

                                      $1

                                      ", "\n\n$1", result) + else: # add extra spacing around the line block for Latex + renderAux(d, n, "

                                      $1

                                      ", "\n\\vspace{0.5em}\n$1\\vspace{0.5em}\n", result) of rnLineBlockItem: - renderAux(d, n, "$1
                                      ", "$1\\\\\n", result) + if n.text.len == 0: # normal case - no additional indentation + renderAux(d, n, "$1
                                      ", "\\noindent $1\n\n", result) + elif n.text == "\n": # add one empty line + renderAux(d, n, "
                                      ", "\\vspace{1em}\n", result) + else: # additional indentation w.r.t. '| ' + let indent = $(0.5 * (n.text.len - 1).toFloat) & "em" + renderAux(d, n, + "$1
                                      ", + "\\noindent\\hspace{" & indent & "}$1\n\n", result) of rnBlockQuote: renderAux(d, n, "

                                      $1

                                      \n", "\\begin{quote}$1\\end{quote}\n", result) diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index a95fac0bd..23d192009 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -215,7 +215,7 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements

                                      Apart from built-in operations like array indexing, memory allocation, etc. the raise statement is the only way to raise an exception.

                                      typedesc used as a parameter type also introduces an implicit generic. typedesc has its own set of rules:

                                      The !=, >, >=, in, notin, isnot operators are in fact templates:

                                      -

                                      a > b is transformed into b < a.
                                      a in b is transformed into contains(b, a).
                                      notin and isnot have the obvious meanings.

                                      A template where every parameter is untyped is called an immediate template. For historical reasons templates can be explicitly annotated with an immediate pragma and then these templates do not take part in overloading resolution and the parameters' types are ignored by the compiler. Explicit immediate templates are now deprecated.

                                      +

                                      a > b is transformed into b < a.
                                      a in b is transformed into contains(b, a).
                                      notin and isnot have the obvious meanings.

                                      A template where every parameter is untyped is called an immediate template. For historical reasons templates can be explicitly annotated with an immediate pragma and then these templates do not take part in overloading resolution and the parameters' types are ignored by the compiler. Explicit immediate templates are now deprecated.

                                      Symbol lookup in generics

                                      Open and Closed symbols

                                      The symbol binding rules in generics are slightly subtle: There are "open" and "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation context, an "open" symbol can. Per default overloaded symbols are open and every other symbol is closed.

                                      diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 54a3db202..7acb23c5b 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -355,11 +355,41 @@ Test1 rstGenera.renderRstToOut(rstParse(input1, "", 1, 1, option, {}), output1) doAssert rstGenera.meta[metaTitle] == "Test1" # check that title was not overwritten to '|' - doAssert "line block
                                      " in output1 - doAssert "other line
                                      " in output1 + doAssert output1 == "



                                      line block
                                      other line

                                      " let output1l = rstToLatex(input1, {}) - doAssert "line block\\\\" in output1l - doAssert "other line\\\\" in output1l + doAssert "line block\n\n" in output1l + doAssert "other line\n\n" in output1l + doAssert output1l.count("\\vspace") == 2 + 2 # +2 surrounding paddings + + let input2 = dedent""" + Paragraph1 + + | + + Paragraph2""" + + let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + doAssert "Paragraph1


                                      Paragraph2

                                      \n" == output2 + + let input3 = dedent""" + | xxx + | yyy + | zzz""" + + let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) + doAssert "xxx
                                      " in output3 + doAssert "yyy
                                      " in output3 + doAssert "zzz
                                      " in output3 + + # check that '| ' with a few spaces is still parsed as new line + let input4 = dedent""" + | xxx + | + | zzz""" + + let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig()) + doAssert "xxx

                                      " in output4 + doAssert "zzz
                                      " in output4 test "RST enumerated lists": let input1 = dedent """ From 5fb56a3b2c83b62d72c72a9d56ef1333671bc2b6 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 31 Dec 2020 04:54:40 -0600 Subject: [PATCH 1730/4254] refactor cmpIgnoreStyle and cmpIgnoreCase (#16399) * init * support strutils * more * better * Call len once per string/cstring * Change var to let * Compare ternary on first char * More appropriate param name * fix * better * one test * impl * more efficient * minor Co-authored-by: Clyybber --- lib/core/macros.nim | 19 +------ lib/core/typeinfo.nim | 26 +++------ lib/pure/cstrutils.nim | 90 +++++++++++++++----------------- lib/pure/strutils.nim | 30 ++--------- lib/std/private/strimpl.nim | 53 +++++++++++++++++++ tests/js/tstdlib_various.nim | 17 +----- tests/stdlib/tcstrutils.nim | 30 +++++++++++ tests/stdlib/tstdlib_various.nim | 23 +------- 8 files changed, 141 insertions(+), 147 deletions(-) create mode 100644 lib/std/private/strimpl.nim create mode 100644 tests/stdlib/tcstrutils.nim diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 97c3a46c5..748464061 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1389,25 +1389,10 @@ when defined(nimVmEqIdent): ## these nodes will be unwrapped. else: + from std/private/strimpl import cmpIgnoreStyleImpl # this procedure is optimized for native code, it should not be compiled to nimVM bytecode. proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = - proc toLower(c: char): char {.inline.} = - if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) - else: result = c - var i = 0 - var j = 0 - # first char is case sensitive - if a[0] != b[0]: return 1 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLower(a[i]) - var bb = toLower(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) - + cmpIgnoreStyleImpl(a, b, true) proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 ## Check if two idents are equal. diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index c15f6dc1f..9b7e32466 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -91,6 +91,8 @@ when not defined(gcDestructors): else: include system/seqs_v2_reimpl +from std/private/strimpl import cmpIgnoreStyleImpl + when not defined(js): template rawType(x: Any): PNimType = cast[PNimType](x.rawTypePtr) @@ -366,36 +368,22 @@ iterator fields*(x: Any): tuple[name: string, any: Any] = for name, any in items(ret): yield ($name, any) -proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = - proc toLower(c: char): char {.inline.} = - if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) - else: result = c - var i = 0 - var j = 0 - if a[0] != b[0]: return 1 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLower(a[i]) - var bb = toLower(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) +proc cmpNimIdentifier(a, b: cstring): int {.noSideEffect.} = + cmpIgnoreStyleImpl(a, b, true) proc getFieldNode(p: pointer, n: ptr TNimNode, name: cstring): ptr TNimNode = case n.kind of nkNone: assert(false) of nkSlot: - if cmpIgnoreStyle(n.name, name) == 0: + if cmpNimIdentifier(n.name, name) == 0: result = n of nkList: for i in 0..n.len-1: result = getFieldNode(p, n.sons[i], name) if result != nil: break of nkCase: - if cmpIgnoreStyle(n.name, name) == 0: + if cmpNimIdentifier(n.name, name) == 0: result = n else: var m = selectBranch(p, n) @@ -599,7 +587,7 @@ proc getEnumOrdinal*(x: Any, name: string): int = var n = typ.node var s = n.sons for i in 0 .. n.len-1: - if cmpIgnoreStyle($s[i].name, name) == 0: + if cmpNimIdentifier($s[i].name, name) == 0: if ntfEnumHole notin typ.flags: return i else: diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index 601508e2e..a95c13fb5 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -12,12 +12,8 @@ ## save allocations. include "system/inclrtl" +import std/private/strimpl -proc toLowerAscii(c: char): char {.inline.} = - if c in {'A'..'Z'}: - result = chr(ord(c) + (ord('a') - ord('A'))) - else: - result = c when defined(js): proc startsWith*(s, prefix: cstring): bool {.noSideEffect, @@ -25,7 +21,13 @@ when defined(js): proc endsWith*(s, suffix: cstring): bool {.noSideEffect, importjs: "#.endsWith(#)".} - + + proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect.} = + cmpIgnoreStyleImpl(a, b) + + proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect.} = + cmpIgnoreCaseImpl(a, b) + # JS string has more operations that might warrant its own module: # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String else: @@ -57,45 +59,39 @@ else: inc(i) if suffix[i] == '\0': return true -proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreStyle".} = - ## Semantically the same as ``cmp(normalize($a), normalize($b))``. It - ## is just optimized to not allocate temporary strings. This should - ## NOT be used to compare Nim identifier names. use `macros.eqIdent` - ## for that. Returns: - ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - ## - ## Not supported for JS backend, use `strutils.cmpIgnoreStyle - ## `_ instead. - var i = 0 - var j = 0 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) + proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, + rtl, extern: "csuCmpIgnoreStyle".} = + ## Semantically the same as ``cmp(normalize($a), normalize($b))``. It + ## is just optimized to not allocate temporary strings. This should + ## NOT be used to compare Nim identifier names. use `macros.eqIdent` + ## for that. Returns: + ## + ## | 0 if a == b + ## | < 0 if a < b + ## | > 0 if a > b + var i = 0 + var j = 0 + while true: + while a[i] == '_': inc(i) + while b[j] == '_': inc(j) # BUGFIX: typo + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[j]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) + inc(j) -proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreCase".} = - ## Compares two strings in a case insensitive manner. Returns: - ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - ## - ## Not supported for JS backend, use `strutils.cmpIgnoreCase - ## `_ instead. - var i = 0 - while true: - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[i]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) + proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, + rtl, extern: "csuCmpIgnoreCase".} = + ## Compares two strings in a case insensitive manner. Returns: + ## + ## | 0 if a == b + ## | < 0 if a < b + ## | > 0 if a > b + var i = 0 + while true: + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[i]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 0028ac4fb..b1418a3ec 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -81,6 +81,8 @@ when defined(nimVmExportFixed): include "system/inclrtl" import std/private/since +from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl + const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} @@ -319,13 +321,7 @@ func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} = doAssert cmpIgnoreCase("FooBar", "foobar") == 0 doAssert cmpIgnoreCase("bar", "Foo") < 0 doAssert cmpIgnoreCase("Foo5", "foo4") > 0 - var i = 0 - var m = min(a.len, b.len) - while i < m: - result = ord(toLowerAscii(a[i])) - ord(toLowerAscii(b[i])) - if result != 0: return - inc(i) - result = a.len - b.len + cmpIgnoreCaseImpl(a, b) {.push checks: off, line_trace: off.} # this is a hot-spot in the compiler! # thus we compile without checks here @@ -344,25 +340,7 @@ func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} = runnableExamples: doAssert cmpIgnoreStyle("foo_bar", "FooBar") == 0 doAssert cmpIgnoreStyle("foo_bar_5", "FooBar4") > 0 - var i = 0 - var j = 0 - while true: - while i < a.len and a[i] == '_': inc i - while j < b.len and b[j] == '_': inc j - var aa = if i < a.len: toLowerAscii(a[i]) else: '\0' - var bb = if j < b.len: toLowerAscii(b[j]) else: '\0' - result = ord(aa) - ord(bb) - if result != 0: return result - # the characters are identical: - if i >= a.len: - # both cursors at the end: - if j >= b.len: return 0 - # not yet at the end of 'b': - return -1 - elif j >= b.len: - return 1 - inc i - inc j + cmpIgnoreStyleImpl(a, b) {.pop.} # --------- Private templates for different split separators ----------- diff --git a/lib/std/private/strimpl.nim b/lib/std/private/strimpl.nim new file mode 100644 index 000000000..ae752165a --- /dev/null +++ b/lib/std/private/strimpl.nim @@ -0,0 +1,53 @@ +func toLowerAscii*(c: char): char {.inline.} = + if c in {'A'..'Z'}: + result = chr(ord(c) + (ord('a') - ord('A'))) + else: + result = c + +template firstCharCaseSensitiveImpl(a, b: typed, aLen, bLen: int) = + if aLen == 0 or bLen == 0: + return aLen - bLen + if a[0] != b[0]: return ord(a[0]) - ord(b[0]) + +template cmpIgnoreStyleImpl*(a, b: typed, firstCharCaseSensitive: static bool = false) = + # a, b are string or cstring + let aLen = a.len + let bLen = b.len + var i = 0 + var j = 0 + when firstCharCaseSensitive: + firstCharCaseSensitiveImpl(a, b, aLen, bLen) + inc i + inc j + while true: + while i < aLen and a[i] == '_': inc i + while j < bLen and b[j] == '_': inc j + let aa = if i < aLen: toLowerAscii(a[i]) else: '\0' + let bb = if j < bLen: toLowerAscii(b[j]) else: '\0' + result = ord(aa) - ord(bb) + if result != 0: return result + # the characters are identical: + if i >= aLen: + # both cursors at the end: + if j >= bLen: return 0 + # not yet at the end of 'b': + return -1 + elif j >= bLen: + return 1 + inc i + inc j + +template cmpIgnoreCaseImpl*(a, b: typed, firstCharCaseSensitive: static bool = false) = + # a, b are string or cstring + let aLen = a.len + let bLen = b.len + var i = 0 + when firstCharCaseSensitive: + firstCharCaseSensitiveImpl(a, b, aLen, bLen) + inc i + var m = min(aLen, bLen) + while i < m: + result = ord(toLowerAscii(a[i])) - ord(toLowerAscii(b[i])) + if result != 0: return + inc i + result = aLen - bLen diff --git a/tests/js/tstdlib_various.nim b/tests/js/tstdlib_various.nim index d19f40c39..a1bb63d46 100644 --- a/tests/js/tstdlib_various.nim +++ b/tests/js/tstdlib_various.nim @@ -29,7 +29,7 @@ Hi Andreas! How do you feel, Rumpf? """ import - critbits, cstrutils, sets, strutils, tables, random, algorithm, ropes, + critbits, sets, strutils, tables, random, algorithm, ropes, lists, htmlgen, xmltree, strtabs @@ -177,18 +177,3 @@ block txmltree: ]) ]) doAssert(y.innerText == "foobar") - - - -block tcstrutils: - let s = cstring "abcdef" - doAssert s.startsWith("a") - doAssert not s.startsWith("b") - doAssert s.endsWith("f") - doAssert not s.endsWith("a") - - let a = cstring "abracadabra" - doAssert a.startsWith("abra") - doAssert not a.startsWith("bra") - doAssert a.endsWith("abra") - doAssert not a.endsWith("dab") diff --git a/tests/stdlib/tcstrutils.nim b/tests/stdlib/tcstrutils.nim new file mode 100644 index 000000000..1daf32aa5 --- /dev/null +++ b/tests/stdlib/tcstrutils.nim @@ -0,0 +1,30 @@ +discard """ + targets: "c cpp js" +""" + +import cstrutils + + +block tcstrutils: + let s = cstring "abcdef" + doAssert s.startsWith("a") + doAssert not s.startsWith("b") + doAssert s.endsWith("f") + doAssert not s.endsWith("a") + + let a = cstring "abracadabra" + doAssert a.startsWith("abra") + doAssert not a.startsWith("bra") + doAssert a.endsWith("abra") + doAssert not a.endsWith("dab") + + doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0 + doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0 + doAssert cmpIgnoreCase(cstring "Foo5", "foo4") > 0 + + doAssert cmpIgnoreStyle(cstring "foo_bar", "FooBar") == 0 + doAssert cmpIgnoreStyle(cstring "foo_bar_5", "FooBar4") > 0 + + doAssert cmpIgnoreCase(cstring "", cstring "") == 0 + doAssert cmpIgnoreCase(cstring "", cstring "Hello") < 0 + doAssert cmpIgnoreCase(cstring "wind", cstring "") > 0 diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim index cddd43f6e..b153fd2ba 100644 --- a/tests/stdlib/tstdlib_various.nim +++ b/tests/stdlib/tstdlib_various.nim @@ -38,7 +38,7 @@ true """ import - critbits, cstrutils, sets, strutils, tables, random, algorithm, re, ropes, + critbits, sets, strutils, tables, random, algorithm, re, ropes, segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs @@ -245,24 +245,3 @@ block txmltree: ]) ]) doAssert(y.innerText == "foobar") - - -block tcstrutils: - let s = cstring "abcdef" - doAssert s.startsWith("a") - doAssert not s.startsWith("b") - doAssert s.endsWith("f") - doAssert not s.endsWith("a") - - let a = cstring "abracadabra" - doAssert a.startsWith("abra") - doAssert not a.startsWith("bra") - doAssert a.endsWith("abra") - doAssert not a.endsWith("dab") - - doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0 - doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0 - doAssert cmpIgnoreCase(cstring "Foo5", "foo4") > 0 - - doAssert cmpIgnoreStyle(cstring "foo_bar", "FooBar") == 0 - doAssert cmpIgnoreStyle(cstring "foo_bar_5", "FooBar4") > 0 From 9d4a1f95544c6c7c58829384cf8045e3803faab0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 1 Jan 2021 03:59:19 -0600 Subject: [PATCH 1731/4254] fix #16494 (#16513) * fix #16494 * fix * fix * fix * fix * fix * fix performance * add comments * improve performance * Update lib/system.nim Co-authored-by: Timothee Cour * Update lib/system.nim Co-authored-by: Timothee Cour * Update tests/stdlib/tmath_misc.nim Co-authored-by: Timothee Cour * Update tests/stdlib/tmath_misc.nim Co-authored-by: Timothee Cour Co-authored-by: Timothee Cour --- lib/system.nim | 24 ++++++++++++++++++++---- tests/stdlib/tmath_misc.nim | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tests/stdlib/tmath_misc.nim diff --git a/lib/system.nim b/lib/system.nim index b6f7d655a..29c137b63 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1522,10 +1522,26 @@ include "system/iterators_1" {.push stackTrace: off.} -proc abs*(x: float64): float64 {.noSideEffect, inline.} = - if x < 0.0: -x else: x -proc abs*(x: float32): float32 {.noSideEffect, inline.} = - if x < 0.0: -x else: x + +when defined(js): + proc js_abs[T: SomeNumber](x: T): T {.importc: "Math.abs".} +else: + proc c_fabs(x: cdouble): cdouble {.importc: "fabs", header: "".} + proc c_fabsf(x: cfloat): cfloat {.importc: "fabsf", header: "".} + +proc abs*[T: float64 | float32](x: T): T {.noSideEffect, inline.} = + when nimvm: + if x < 0.0: result = -x + elif x == 0.0: result = 0.0 # handle 0.0, -0.0 + else: result = x # handle NaN, > 0 + else: + when defined(js): result = js_abs(x) + else: + when T is float64: + result = c_fabs(x) + else: + result = c_fabsf(x) + proc min*(x, y: float32): float32 {.noSideEffect, inline.} = if x <= y or y != y: x else: y proc min*(x, y: float64): float64 {.noSideEffect, inline.} = diff --git a/tests/stdlib/tmath_misc.nim b/tests/stdlib/tmath_misc.nim new file mode 100644 index 000000000..978e3e94d --- /dev/null +++ b/tests/stdlib/tmath_misc.nim @@ -0,0 +1,24 @@ +discard """ + targets: "c js" +""" + +# TODO merge this to tmath.nim once tmath.nim supports js target + +import math + +proc main() = + block: + doAssert 1.0 / abs(-0.0) == Inf + doAssert 1.0 / abs(0.0) == Inf + doAssert -1.0 / abs(-0.0) == -Inf + doAssert -1.0 / abs(0.0) == -Inf + doAssert abs(0.0) == 0.0 + doAssert abs(0.0'f32) == 0.0'f32 + + doAssert abs(Inf) == Inf + doAssert abs(-Inf) == Inf + doAssert abs(NaN).isNaN + doAssert abs(-NaN).isNaN + +static: main() +main() From eb25d7dd712bd339f11becbf5499d04930382a30 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 1 Jan 2021 11:32:41 -0600 Subject: [PATCH 1732/4254] enable ggplotnim (#16538) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 65104e1fe..dca8c5a4f 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -41,7 +41,7 @@ pkg1 "fidget" pkg1 "fragments", "nim c -r fragments/dsl.nim" pkg1 "gara" pkg1 "glob" -# pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pending bug #16523 +pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" # pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup" pkg1 "gnuplot", "nim c gnuplot.nim" # pkg1 "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" From 4a479f4a6eb2f9c5a3665d95fa86d993fdb66281 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 1 Jan 2021 11:33:35 -0600 Subject: [PATCH 1733/4254] update contributing.rst (#16530) * update docs * Apply suggestions from code review * Update doc/contributing.rst --- doc/contributing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index 34c963410..d1837ac14 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -239,7 +239,7 @@ not guaranteed to stay in sync, so ``runnableExamples`` is usually preferred: .. code-block:: nim proc someproc*(): string = - ## Return "something" + ## Returns "something" ## ## .. code-block:: ## echo someproc() # "something" @@ -262,12 +262,12 @@ first appearance of the proc. echo "hello" The preferred documentation style is to begin with a capital letter and use -the imperative (command) form. That is, between: +the third-person singular. That is, between: .. code-block:: nim proc hello*(): string = - ## Return "hello" + ## Returns "hello" result = "hello" or @@ -275,7 +275,7 @@ or .. code-block:: nim proc hello*(): string = - ## says hello + ## say hello result = "hello" the first is preferred. From e67059a03a02b53919fafd0f99eb59baa9ad9a53 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Fri, 1 Jan 2021 17:36:20 +0000 Subject: [PATCH 1734/4254] Add short description on GC (#16535) --- doc/gc.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index 804481cd9..a19ad0671 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -14,10 +14,15 @@ Nim's Memory Management Introduction ============ -This document describes how the multi-paradigm memory management strategies work. -How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, -and how the memory management strategies that are not garbage collectors work. +A memory-management algorithm optimal for every use-case cannot exist. +Nim provides multiple paradigms for needs ranging from large multi-threaded +applications, to games, hard-realtime systems and small microcontrollers. +This document describes how the management strategies work; +How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, +and how the memory management strategies other than garbage collectors work. + +.. note:: the default GC is incremental, thread-local and not "stop-the-world" Multi-paradigm Memory Management Strategies =========================================== From b5101b23b5291d12ebbee4b8de37ac128ce9b7f4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 1 Jan 2021 12:01:07 -0600 Subject: [PATCH 1735/4254] refactor the tests of options (#16527) --- tests/stdlib/toptions.nim | 269 ++++++++++++++++++++++---------------- 1 file changed, 154 insertions(+), 115 deletions(-) diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim index 04544ffb7..4764ce05f 100644 --- a/tests/stdlib/toptions.nim +++ b/tests/stdlib/toptions.nim @@ -1,19 +1,8 @@ discard """ - output: '''{"foo":{"test":"123"}}''' + targets: "c js" """ -import json, options - -type - Foo = ref object - test: string - Test = object - foo: Option[Foo] - -let js = """{"foo": {"test": "123"}}""" -let parsed = parseJson(js) -let a = parsed.to(Test) -echo $(%*a) +import std/[json, options] # RefPerson is used to test that overloaded `==` operator is not called by @@ -26,133 +15,183 @@ proc `==`(a, b: RefPerson): bool = assert(not a.isNil and not b.isNil) a.name == b.name -block options: - # work around a bug in unittest - let intNone = none(int) - let stringNone = none(string) - block example: - proc find(haystack: string, needle: char): Option[int] = - for i, c in haystack: - if c == needle: - return some i +template disableJsVm(body) = + # something doesn't work in JS VM + when defined(js): + when nimvm: discard + else: body + else: + body - doAssert("abc".find('c').get() == 2) +proc main() = + type + Foo = ref object + test: string + Test = object + foo: Option[Foo] - let result = "team".find('i') + let js = """{"foo": {"test": "123"}}""" + let parsed = parseJson(js) + let a = parsed.to(Test) + doAssert $(%*a) == """{"foo":{"test":"123"}}""" - doAssert result == intNone - doAssert result.isNone + block options: + # work around a bug in unittest + let intNone = none(int) + let stringNone = none(string) - block some: - doAssert some(6).get() == 6 - doAssert some("a").unsafeGet() == "a" - doAssert some(6).isSome - doAssert some("a").isSome + block example: + proc find(haystack: string, needle: char): Option[int] = + for i, c in haystack: + if c == needle: + return some i - block none: - doAssertRaises UnpackDefect: - discard none(int).get() - doAssert(none(int).isNone) - doAssert(not none(string).isSome) + doAssert("abc".find('c').get() == 2) - block equality: - doAssert some("a") == some("a") - doAssert some(7) != some(6) - doAssert some("a") != stringNone - doAssert intNone == intNone + let result = "team".find('i') - when compiles(some("a") == some(5)): - doAssert false - when compiles(none(string) == none(int)): - doAssert false + doAssert result == intNone + doAssert result.isNone - block get_with_a_default_value: - doAssert(some("Correct").get("Wrong") == "Correct") - doAssert(stringNone.get("Correct") == "Correct") + block some: + doAssert some(6).get() == 6 + doAssert some("a").unsafeGet() == "a" + doAssert some(6).isSome + doAssert some("a").isSome - block stringify: - doAssert($(some("Correct")) == "Some(\"Correct\")") - doAssert($(stringNone) == "None[string]") + block none: + doAssertRaises UnpackDefect: + discard none(int).get() + doAssert(none(int).isNone) + doAssert(not none(string).isSome) - block map_with_a_void_result: - var procRan = 0 - some(123).map(proc (v: int) = procRan = v) - doAssert procRan == 123 - intNone.map(proc (v: int) = doAssert false) + block equality: + doAssert some("a") == some("a") + doAssert some(7) != some(6) + doAssert some("a") != stringNone + doAssert intNone == intNone - block map: - doAssert(some(123).map(proc (v: int): int = v * 2) == some(246)) - doAssert(intNone.map(proc (v: int): int = v * 2).isNone) + when compiles(some("a") == some(5)): + doAssert false + when compiles(none(string) == none(int)): + doAssert false - block filter: - doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123)) - doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone) - doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone) + block get_with_a_default_value: + doAssert(some("Correct").get("Wrong") == "Correct") + doAssert(stringNone.get("Correct") == "Correct") - block flatMap: - proc addOneIfNotZero(v: int): Option[int] = - if v != 0: - result = some(v + 1) - else: - result = none(int) + block stringify: + doAssert($(some("Correct")) == "Some(\"Correct\")") + doAssert($(stringNone) == "None[string]") - doAssert(some(1).flatMap(addOneIfNotZero) == some(2)) - doAssert(some(0).flatMap(addOneIfNotZero) == none(int)) - doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) + disableJsVm: + block map_with_a_void_result: + var procRan = 0 + # TODO closure anonymous functions doesn't work in VM with JS + # Error: cannot evaluate at compile time: procRan + some(123).map(proc (v: int) = procRan = v) + doAssert procRan == 123 + intNone.map(proc (v: int) = doAssert false) - proc maybeToString(v: int): Option[string] = - if v != 0: - result = some($v) - else: - result = none(string) + block map: + doAssert(some(123).map(proc (v: int): int = v * 2) == some(246)) + doAssert(intNone.map(proc (v: int): int = v * 2).isNone) - doAssert(some(1).flatMap(maybeToString) == some("1")) + block filter: + doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123)) + doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone) + doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone) - proc maybeExclaim(v: string): Option[string] = - if v != "": - result = some v & "!" - else: - result = none(string) + block flatMap: + proc addOneIfNotZero(v: int): Option[int] = + if v != 0: + result = some(v + 1) + else: + result = none(int) - doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) - doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) + doAssert(some(1).flatMap(addOneIfNotZero) == some(2)) + doAssert(some(0).flatMap(addOneIfNotZero) == none(int)) + doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) - block SomePointer: - var intref: ref int - doAssert(option(intref).isNone) - intref.new - doAssert(option(intref).isSome) + proc maybeToString(v: int): Option[string] = + if v != 0: + result = some($v) + else: + result = none(string) - let tmp = option(intref) - doAssert(sizeof(tmp) == sizeof(ptr int)) + doAssert(some(1).flatMap(maybeToString) == some("1")) - var prc = proc (x: int): int = x + 1 - doAssert(option(prc).isSome) - prc = nil - doAssert(option(prc).isNone) + proc maybeExclaim(v: string): Option[string] = + if v != "": + result = some v & "!" + else: + result = none(string) - block: - doAssert(none[int]().isNone) - doAssert(none(int) == none[int]()) + doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) + doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) - # "$ on typed with .name" - block: - type Named = object - name: string + block SomePointer: + var intref: ref int + doAssert(option(intref).isNone) + intref.new + doAssert(option(intref).isSome) - let nobody = none(Named) - doAssert($nobody == "None[Named]") + let tmp = option(intref) + doAssert(sizeof(tmp) == sizeof(ptr int)) - # "$ on type with name()" - block: - type Person = object - myname: string + var prc = proc (x: int): int = x + 1 + doAssert(option(prc).isSome) + prc = nil + doAssert(option(prc).isNone) - let noperson = none(Person) - doAssert($noperson == "None[Person]") + block: + doAssert(none[int]().isNone) + doAssert(none(int) == none[int]()) - # "Ref type with overloaded `==`" - block: - let p = some(RefPerson.new()) - doAssert p.isSome + # "$ on typed with .name" + block: + type Named = object + name: string + + let nobody = none(Named) + doAssert($nobody == "None[Named]") + + # "$ on type with name()" + block: + type Person = object + myname: string + + let noperson = none(Person) + doAssert($noperson == "None[Person]") + + # "Ref type with overloaded `==`" + block: + let p = some(RefPerson.new()) + doAssert p.isSome + + block: # test cstring + block: + let x = some("".cstring) + doAssert x.isSome + doAssert x.get == "" + + block: + let x = some("12345".cstring) + doAssert x.isSome + doAssert x.get == "12345" + + block: + let x = "12345".cstring + let y = some(x) + doAssert y.isSome + doAssert y.get == "12345" + + block: + let x = none(cstring) + doAssert x.isNone + doAssert $x == "None[cstring]" + + +static: main() +main() From 5953fbd8347838f162d64e4acdc259fd372210a3 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Fri, 1 Jan 2021 18:01:45 +0000 Subject: [PATCH 1736/4254] link to POSIX sendSignal from osproc.kill docs (#16475) and from osproc.terminate docs --- lib/pure/osproc.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9c198e6fa..9cac8e232 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -187,6 +187,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## * `suspend proc <#suspend,Process>`_ ## * `resume proc <#resume,Process>`_ ## * `kill proc <#kill,Process>`_ + ## * `posix_utils.sendSignal(pid: Pid, signal: int) `_ proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Kill the process `p`. @@ -198,6 +199,7 @@ proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## * `suspend proc <#suspend,Process>`_ ## * `resume proc <#resume,Process>`_ ## * `terminate proc <#terminate,Process>`_ + ## * `posix_utils.sendSignal(pid: Pid, signal: int) `_ proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} ## Returns true if the process `p` is still running. Returns immediately. From bc0b4fbc9e422ab87104610d879f02fe08771b74 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 1 Jan 2021 12:28:59 -0600 Subject: [PATCH 1737/4254] happy new year 2021 (#16537) --- copying.txt | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/copying.txt b/copying.txt index a7ba3143f..a498a9525 100644 --- a/copying.txt +++ b/copying.txt @@ -1,7 +1,7 @@ ===================================================== Nim -- a Compiler for Nim. https://nim-lang.org/ -Copyright (C) 2006-2020 Andreas Rumpf. All rights reserved. +Copyright (C) 2006-2021 Andreas Rumpf. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index bfd153143..fa7a2d86d 100644 --- a/readme.md +++ b/readme.md @@ -204,7 +204,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2020 Andreas Rumpf, all rights reserved. +Copyright © 2006-2021 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org From d069c08d2b077abfb6e7e73e516448de4faa89ef Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 1 Jan 2021 12:39:05 -0600 Subject: [PATCH 1738/4254] follow up #16399 clean up docs (#16539) * follow up #16399 clean up docs * more --- lib/pure/cstrutils.nim | 71 ++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index a95c13fb5..390aac00b 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -## This module supports helper routines for working with ``cstring`` -## without having to convert ``cstring`` to ``string`` in order to +## This module supports helper routines for working with `cstring` +## without having to convert `cstring` to `string` in order to ## save allocations. include "system/inclrtl" @@ -16,41 +16,45 @@ import std/private/strimpl when defined(js): - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, - importjs: "#.startsWith(#)".} + func startsWith*(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".} - proc endsWith*(s, suffix: cstring): bool {.noSideEffect, - importjs: "#.endsWith(#)".} + func endsWith*(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".} - proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect.} = + func cmpIgnoreStyle*(a, b: cstring): int = cmpIgnoreStyleImpl(a, b) - proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect.} = + func cmpIgnoreCase*(a, b: cstring): int = cmpIgnoreCaseImpl(a, b) # JS string has more operations that might warrant its own module: # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String else: - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, - rtl, extern: "csuStartsWith".} = - ## Returns true if ``s`` starts with ``prefix``. + func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} = + ## Returns true if `s` starts with `prefix`. ## - ## If ``prefix == ""`` true is returned. + ## If `prefix == ""` true is returned. ## - ## JS backend uses native ``String.prototype.startsWith``. + ## JS backend uses native `String.prototype.startsWith`. + runnableExamples: + assert startsWith(cstring"Hello, Nimion", cstring"Hello") + assert not startsWith(cstring"Hello, Nimion", cstring"Nimion") + var i = 0 while true: if prefix[i] == '\0': return true if s[i] != prefix[i]: return false inc(i) - proc endsWith*(s, suffix: cstring): bool {.noSideEffect, - rtl, extern: "csuEndsWith".} = - ## Returns true if ``s`` ends with ``suffix``. + func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} = + ## Returns true if `s` ends with `suffix`. ## - ## If ``suffix == ""`` true is returned. - ## - ## JS backend uses native ``String.prototype.endsWith``. + ## If `suffix == ""` true is returned. + ## + ## JS backend uses native `String.prototype.endsWith`. + runnableExamples: + assert endsWith(cstring"Hello, Nimion", cstring"Nimion") + assert not endsWith(cstring"Hello, Nimion", cstring"Hello") + let slen = s.len var i = 0 var j = slen - len(suffix) @@ -59,16 +63,18 @@ else: inc(i) if suffix[i] == '\0': return true - proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreStyle".} = - ## Semantically the same as ``cmp(normalize($a), normalize($b))``. It + func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} = + ## Semantically the same as `cmp(normalize($a), normalize($b))`. It ## is just optimized to not allocate temporary strings. This should ## NOT be used to compare Nim identifier names. use `macros.eqIdent` ## for that. Returns: ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b + ## .. code-block:: + ## 0 if a == b + ## < 0 if a < b + ## > 0 if a > b + runnableExamples: + assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0 var i = 0 var j = 0 while true: @@ -81,13 +87,18 @@ else: inc(i) inc(j) - proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreCase".} = + func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} = ## Compares two strings in a case insensitive manner. Returns: ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b + ## .. code-block:: + ## 0 if a == b + ## < 0 if a < b + ## > 0 if a > b + runnableExamples: + assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0 + assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0 + assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0 + var i = 0 while true: var aa = toLowerAscii(a[i]) From b254d91cd0099c1e0bc15126c52bd6485575ec5a Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Fri, 1 Jan 2021 18:41:49 +0000 Subject: [PATCH 1739/4254] reuse const (#16422) --- lib/pure/osproc.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9cac8e232..bc447eb67 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -981,7 +981,7 @@ elif not defined(useNimRtl): when not defined(android): "/bin/sh" else: "/system/bin/sh" data.sysCommand = useShPath - sysArgsRaw = @[data.sysCommand, "-c", command] + sysArgsRaw = @[useShPath, "-c", command] assert args.len == 0, "`args` has to be empty when using poEvalCommand." else: data.sysCommand = command From 505d04389ad5c83b50001e3108d89fcdec9c462f Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 1 Jan 2021 15:44:06 -0300 Subject: [PATCH 1740/4254] Documentation only Testament unittest (#16532) * Link Testament from unittest doc * Update lib/pure/unittest.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- lib/pure/unittest.nim | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 18b09e4c0..c387e14e1 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -9,11 +9,6 @@ ## :Author: Zahary Karadjov ## -## **Note**: Instead of ``unittest.nim``, please consider to use -## the ``testament`` tool which offers process isolation for your tests. -## Also ``when isMainModule: doAssert conditionHere`` is usually a -## much simpler solution for testing purposes. -## ## This module implements boilerplate to make unit testing easy. ## ## The test status and name is printed after any output or traceback. @@ -22,9 +17,18 @@ ## parent test as failed. Setup and teardown are inherited. Setup can be ## overridden locally. ## -## Compiled test files as well as ``nim c -r `` +## Compiled test files as well as `nim c -r ` ## exit with 0 for success (no failed tests) or 1 for failure. ## +## Testament +## ========= +## +## Instead of `unittest`, please consider using +## `the Testament tool `_ which offers process isolation for your tests. +## +## Alternatively using `when isMainModule: doAssert conditionHere` is usually a +## much simpler solution for testing purposes. +## ## Running a single test ## ===================== ## @@ -39,7 +43,7 @@ ## Running a single test suite ## =========================== ## -## Specify the suite name delimited by ``"::"``. +## Specify the suite name delimited by `"::"`. ## ## .. code:: ## @@ -50,7 +54,7 @@ ## ## A single ``"*"`` can be used for globbing. ## -## Delimit the end of a suite name with ``"::"``. +## Delimit the end of a suite name with `"::"`. ## ## Tests matching **any** of the arguments are executed. ## @@ -92,7 +96,7 @@ ## discard v[4] ## ## echo "suite teardown: run once after the tests" -## +## ## Limitations/Bugs ## ================ ## Since `check` will rewrite some expressions for supporting checkpoints From 0d0e43469f060818ec09d74de5b0bb7ded891898 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 1 Jan 2021 13:55:22 -0800 Subject: [PATCH 1741/4254] fix #14340 (#16386) --- compiler/ccgexprs.nim | 4 +++- tests/vm/tvmmisc.nim | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 45044e0ff..53b2832f0 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3094,7 +3094,9 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope else: result = genConstSeq(p, n, typ, isConst) of tyProc: - if typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit: + if typ.callConv == ccClosure and n.safeLen > 1 and n[1].kind == nkNilLit: + # n.kind could be: nkClosure, nkTupleConstr and maybe others; `n.safeLen` + # guards against the case of `nkSym`, refs bug #14340. # Conversion: nimcall -> closure. # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} # this behaviour is needed since closure_var = nil must be diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 005f7e255..c1e563806 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -306,6 +306,23 @@ block: # bug #8007 const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)] doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" +block: # bug #14340 + block: + proc opl3EnvelopeCalcSin0() = discard + type EnvelopeSinfunc = proc() + # const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok + const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug + const envelopeSin = [EnvelopeCalcSin0] + var a = 0 + envelopeSin[a]() + + block: + type Mutator = proc() {.noSideEffect, gcsafe, locks: 0.} + proc mutator0() = discard + const mTable = [Mutator(mutator0)] + var i=0 + mTable[i]() + block: # VM wrong register free causes errors in unrelated code block: # bug #15597 #[ From 73a8b950cb6abf36a0d29c210bb7db302ae68325 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 2 Jan 2021 07:30:39 +0100 Subject: [PATCH 1742/4254] big steps torwards an efficient, simple IC implementation (#16543) * reworked ID handling * the packed AST now has its own ID mechanism * basic serialization code works * extract rodfiles to its own module * rodfiles: store and compare configs * rodfiles: store dependencies * store config at the end * precise dependency tracking * dependency tracking for rodfiles * completed loading of PSym, PType, etc * removed dead code * bugfix: do not realloc seqs when taking addr into an element * make IC opt-in for now * makes tcompilerapi green again * final cleanups Co-authored-by: Andy Davidoff --- compiler/ast.nim | 31 +- compiler/ccgexprs.nim | 2 +- compiler/ccgtypes.nim | 12 +- compiler/cgmeth.nim | 6 +- compiler/closureiters.nim | 12 +- compiler/commands.nim | 5 - compiler/enumtostr.nim | 16 +- compiler/evaltempl.nim | 2 +- compiler/ic/bitabs.nim | 49 +- compiler/ic/design.rst | 11 +- compiler/ic/from_packed_ast.nim | 12 - compiler/ic/packed_ast.nim | 330 ++++++---- compiler/ic/rodfiles.nim | 143 ++++ compiler/ic/to_packed_ast.nim | 692 +++++++++++++++++-- compiler/importer.nim | 3 +- compiler/incremental.nim | 198 ------ compiler/injectdestructors.nim | 6 +- compiler/lambdalifting.nim | 28 +- compiler/liftdestructors.nim | 20 +- compiler/lookups.nim | 2 +- compiler/lowerings.nim | 18 +- compiler/magicsys.nim | 16 +- compiler/main.nim | 5 +- compiler/modulegraphs.nim | 12 +- compiler/modules.nim | 8 +- compiler/nilcheck.nim | 128 ++-- compiler/options.nim | 4 + compiler/passes.nim | 139 ++-- compiler/plugins/itersgen.nim | 4 +- compiler/plugins/locals.nim | 2 +- compiler/pragmas.nim | 10 +- compiler/rod.nim | 31 - compiler/rodimpl.nim | 950 --------------------------- compiler/sem.nim | 20 +- compiler/semdata.nim | 45 +- compiler/semexprs.nim | 10 +- compiler/semfields.nim | 2 +- compiler/semfold.nim | 4 +- compiler/semgnrc.nim | 2 +- compiler/seminst.nim | 13 +- compiler/semmagic.nim | 24 +- compiler/semparallel.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 13 +- compiler/semtempl.nim | 2 +- compiler/semtypes.nim | 20 +- compiler/semtypinst.nim | 6 +- compiler/sigmatch.nim | 10 +- compiler/sinkparameter_inference.nim | 2 +- compiler/spawn.nim | 34 +- compiler/transf.nim | 6 +- compiler/types.nim | 4 +- compiler/vm.nim | 6 +- compiler/vmdeps.nim | 4 +- compiler/vmmarshal.nim | 2 +- lib/js/jsffi.nim | 4 +- tests/compilerapi/tcompilerapi.nim | 2 +- 57 files changed, 1429 insertions(+), 1717 deletions(-) delete mode 100644 compiler/ic/from_packed_ast.nim create mode 100644 compiler/ic/rodfiles.nim delete mode 100644 compiler/incremental.nim delete mode 100644 compiler/rod.nim delete mode 100644 compiler/rodimpl.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 8acf08284..ccf4fe497 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1074,18 +1074,35 @@ template id*(a: PIdObj): int = (x.itemId.module.int shl moduleShift) + x.itemId.item.int type - IdGenerator* = ref ItemId # unfortunately, we really need the 'shared mutable' aspect here. + IdGenerator* = ref object # unfortunately, we really need the 'shared mutable' aspect here. + module*: int32 + symId*: int32 + typeId*: int32 + +proc hash*(x: ItemId): Hash = + var h: Hash = hash(x.module) + h = h !& hash(x.item) + result = !$h const PackageModuleId* = -3'i32 proc idGeneratorFromModule*(m: PSym): IdGenerator = assert m.kind == skModule - result = IdGenerator(module: m.itemId.module, item: m.itemId.item) + result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) -proc nextId*(x: IdGenerator): ItemId {.inline.} = - inc x.item - result = x[] +proc nextSymId*(x: IdGenerator): ItemId {.inline.} = + inc x.symId + result = ItemId(module: x.module, item: x.symId) + +proc nextTypeId*(x: IdGenerator): ItemId {.inline.} = + inc x.typeId + result = ItemId(module: x.module, item: x.typeId) + +when false: + proc nextId*(x: IdGenerator): ItemId {.inline.} = + inc x.item + result = x[] when false: proc storeBack*(dest: var IdGenerator; src: IdGenerator) {.inline.} = @@ -1831,7 +1848,7 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType = ## returned. Otherwise ``typ`` is simply returned as-is. result = typ if typ.kind != kind: - result = newType(kind, nextId(idgen), typ.owner) + result = newType(kind, nextTypeId(idgen), typ.owner) rawAddSon(result, typ) proc toRef*(typ: PType; idgen: IdGenerator): PType = @@ -1839,7 +1856,7 @@ proc toRef*(typ: PType; idgen: IdGenerator): PType = ## returned. Otherwise ``typ`` is simply returned as-is. result = typ if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject: - result = newType(tyRef, nextId(idgen), typ.owner) + result = newType(tyRef, nextTypeId(idgen), typ.owner) rawAddSon(result, typ) proc toObject*(typ: PType): PType = diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 53b2832f0..b8a8d21b0 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1772,7 +1772,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "genArrayLen()") proc makePtrType(baseType: PType; idgen: IdGenerator): PType = - result = newType(tyPtr, nextId idgen, baseType.owner) + result = newType(tyPtr, nextTypeId idgen, baseType.owner) addSonSkipIntLit(result, baseType, idgen) proc makeAddr(n: PNode; idgen: IdGenerator): PNode = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 142fec056..ab12bad1e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1267,9 +1267,9 @@ proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = proc fakeClosureType(m: BModule; owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] - result = newType(tyTuple, nextId m.idgen, owner) - result.rawAddSon(newType(tyPointer, nextId m.idgen, owner)) - var r = newType(tyRef, nextId m.idgen, owner) + result = newType(tyTuple, nextTypeId m.idgen, owner) + result.rawAddSon(newType(tyPointer, nextTypeId m.idgen, owner)) + var r = newType(tyRef, nextTypeId m.idgen, owner) let obj = createObj(m.g.graph, m.idgen, owner, owner.info, final=false) r.rawAddSon(obj) result.rawAddSon(r) @@ -1396,9 +1396,9 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = result = prefixTI.rope & result & ")".rope proc openArrayToTuple(m: BModule; t: PType): PType = - result = newType(tyTuple, nextId m.idgen, t.owner) - let p = newType(tyPtr, nextId m.idgen, t.owner) - let a = newType(tyUncheckedArray, nextId m.idgen, t.owner) + result = newType(tyTuple, nextTypeId m.idgen, t.owner) + let p = newType(tyPtr, nextTypeId m.idgen, t.owner) + let a = newType(tyUncheckedArray, nextTypeId m.idgen, t.owner) a.add t.lastSon p.add a result.add p diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index a0c16f2ed..5c5d35093 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -108,10 +108,10 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = s.ast[dispatcherPos] = dispatcher proc createDispatcher(s: PSym; idgen: IdGenerator): PSym = - var disp = copySym(s, nextId(idgen)) + var disp = copySym(s, nextSymId(idgen)) incl(disp.flags, sfDispatcher) excl(disp.flags, sfExported) - disp.typ = copyType(disp.typ, nextId(idgen), disp.typ.owner) + disp.typ = copyType(disp.typ, nextTypeId(idgen), disp.typ.owner) # we can't inline the dispatcher itself (for now): if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall disp.ast = copyTree(s.ast) @@ -119,7 +119,7 @@ proc createDispatcher(s: PSym; idgen: IdGenerator): PSym = disp.loc.r = nil if s.typ[0] != nil: if disp.ast.len > resultPos: - disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextId(idgen)) + disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen)) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 48088a609..43dfc69ae 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -177,7 +177,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode = ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt))) proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym = - result = newSym(skVar, getIdent(ctx.g.cache, name), nextId(ctx.idgen), ctx.fn, ctx.fn.info) + result = newSym(skVar, getIdent(ctx.g.cache, name), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info) result.typ = typ assert(not typ.isNil) @@ -1118,9 +1118,9 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode= n[i] = ctx.skipThroughEmptyStates(n[i]) proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: PSym): PType = - result = newType(tyArray, nextId(idgen), owner) + result = newType(tyArray, nextTypeId(idgen), owner) - let rng = newType(tyRange, nextId(idgen), owner) + let rng = newType(tyRange, nextTypeId(idgen), owner) rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n)) rng.rawAddSon(t) @@ -1314,7 +1314,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode = let idefs = copyNode(it) for v in 0..it.len-3: if it[v].kind == nkSym: - let x = copySym(it[v].sym, nextId(c.idgen)) + let x = copySym(it[v].sym, nextSymId(c.idgen)) c.tab[it[v].sym.id] = x idefs.add newSymNode(x) else: @@ -1393,9 +1393,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: # Lambda lifting was not done yet. Use temporary :state sym, which will # be handled specially by lambda lifting. Local temp vars (if needed) # should follow the same logic. - ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextId(idgen), fn, fn.info) + ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextSymId(idgen), fn, fn.info) ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen) - ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextId(idgen), fn, fn.info) + ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info) var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen) var n = preprocess(pc, n.toStmtList) #echo "transformed into ", n diff --git a/compiler/commands.nim b/compiler/commands.nim index 4b8755ab4..b52148668 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -31,7 +31,6 @@ import wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos, pathutils, strtabs -from incremental import nimIncremental from ast import eqTypeFlags, tfGcSafe, tfNoSideEffect # but some have deps to imported modules. Yay. @@ -799,10 +798,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; helpOnError(conf, pass) of "symbolfiles": discard "ignore for backwards compat" of "incremental": - when not nimIncremental: - localError(conf, info, "the compiler was not built with " & - "incremental compilation features; bootstrap with " & - "-d:nimIncremental to enable") case arg.normalize of "on": conf.symbolFiles = v2Sf of "off": conf.symbolFiles = disabledSf diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 3274462d7..9bfa7001a 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -2,15 +2,15 @@ import ast, idents, lineinfos, modulegraphs, magicsys proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "$"), nextId idgen, t.owner, info) + result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) dest.typ = t - let res = newSym(skResult, getIdent(g.cache, "result"), nextId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) res.typ = getSysType(g, info, tyString) - result.typ = newType(tyProc, nextId idgen, t.owner) + result.typ = newType(tyProc, nextTypeId idgen, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) @@ -63,15 +63,15 @@ proc searchObjCase(t: PType; field: PSym): PNode = doAssert result != nil proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextId idgen, t.owner, info) + result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) dest.typ = field.typ - let res = newSym(skResult, getIdent(g.cache, "result"), nextId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) res.typ = getSysType(g, info, tyUInt8) - result.typ = newType(tyProc, nextId idgen, t.owner) + result.typ = newType(tyProc, nextTypeId idgen, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 218a597d8..691d33a2c 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: - x = copySym(s, nextId(c.idgen)) + x = copySym(s, nextSymId(c.idgen)) # sem'check needs to set the owner properly later, see bug #9476 x.owner = nil # c.genSymOwner #if x.kind == skParam and x.owner.kind == skModule: diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim index 91221ea49..1f75b7759 100644 --- a/compiler/ic/bitabs.nim +++ b/compiler/ic/bitabs.nim @@ -1,7 +1,7 @@ ## A BiTable is a table that can be seen as an optimized pair ## of (Table[LitId, Val], Table[Val, LitId]). -import hashes +import hashes, rodfiles type LitId* = distinct uint32 @@ -30,7 +30,9 @@ proc mustRehash(length, counter: int): bool {.inline.} = result = (length * 2 < counter * 3) or (length - counter < 4) const - idStart = 256 # Ids do not start with 0 but with this value. The IR needs it. + idStart = 256 ## + ## Ids do not start with 0 but with this value. The IR needs it. + ## TODO: explain why template idToIdx(x: LitId): int = x.int - idStart @@ -94,6 +96,21 @@ proc `[]`*[T](t: BiTable[T]; LitId: LitId): lent T {.inline.} = assert idx < t.vals.len result = t.vals[idx] +proc hash*[T](t: BiTable[T]): Hash = + ## as the keys are hashes of the values, we simply use them instead + var h: Hash = 0 + for i, n in pairs t.keys: + h = h !& hash((i, n)) + result = !$h + +proc store*[T](f: var RodFile; t: BiTable[T]) = + storeSeq(f, t.vals) + storeSeq(f, t.keys) + +proc load*[T](f: var RodFile; t: var BiTable[T]) = + loadSeq(f, t.vals) + loadSeq(f, t.keys) + when isMainModule: var t: BiTable[string] @@ -113,7 +130,35 @@ when isMainModule: for i in 0 ..< 100_000: assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4 + echo "begin" echo t.vals.len echo t.vals[0] echo t.vals[1004] + + echo "middle" + + var tf: BiTable[float] + + discard tf.getOrIncl(0.4) + discard tf.getOrIncl(16.4) + discard tf.getOrIncl(32.4) + echo getKeyId(tf, 32.4) + + var f2 = open("testblah.bin", fmWrite) + echo store(f2, tf) + f2.close + + var f1 = open("testblah.bin", fmRead) + + var t2: BiTable[float] + + echo f1.load(t2) + echo t2.vals.len + + echo getKeyId(t2, 32.4) + + echo "end" + + + f1.close diff --git a/compiler/ic/design.rst b/compiler/ic/design.rst index 1a33f6a27..60434e4b8 100644 --- a/compiler/ic/design.rst +++ b/compiler/ic/design.rst @@ -29,14 +29,13 @@ mechanism needs to be implemented that we could get wrong. ModuleIds are rod-file specific too. -Configuration setup changes ---------------------------- - -For a MVP these are not detected. Later the configuration will be -stored in every `.rod` file. - Global state ------------ Global persistent state will be kept in a project specific `.rod` file. + +Rod File Format +--------------- + +It's a simple binary file format. `rodfiles.nim` contains some details. diff --git a/compiler/ic/from_packed_ast.nim b/compiler/ic/from_packed_ast.nim deleted file mode 100644 index cb2ecee79..000000000 --- a/compiler/ic/from_packed_ast.nim +++ /dev/null @@ -1,12 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import std / [hashes, tables] -import bitabs -import ".." / [ast, lineinfos, options, pathutils] diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index ef609e8c8..546e495c5 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -12,9 +12,9 @@ ## use this representation directly in all the transformations, ## it is superior. -import std / [hashes, tables] +import std / [hashes, tables, strtabs, md5] import bitabs -import ".." / [ast, lineinfos, options, pathutils] +import ".." / [ast, options] const localNamePos* = 0 @@ -39,16 +39,29 @@ const routineBodyPos* = 7 const - nkModuleRef = nkNone # pair of (ModuleId, SymId) + nkModuleRef* = nkNone # pair of (ModuleId, SymId) type SymId* = distinct int32 - TypeId* = distinct int32 ModuleId* = distinct int32 NodePos* = distinct int NodeId* = distinct int32 + PackedItemId* = object + module*: LitId # 0 if it's this module + item*: int32 # same as the in-memory representation + + TypeId* = PackedItemId + +const + nilTypeId* = PackedItemId(module: LitId(0), item: -1.int32) + nilItemId* = PackedItemId(module: LitId(0), item: -1.int32) + +const + emptyNodeId* = NodeId(-1) + +type PackedLineInfo* = object line*: uint16 col*: int16 @@ -64,13 +77,13 @@ type PackedSym* = object kind*: TSymKind name*: LitId - typeId*: TypeId + typ*: TypeId flags*: TSymFlags magic*: TMagic info*: PackedLineInfo - ast*: NodePos - owner*: ItemId - guard*: ItemId + ast*: NodeId + owner*: PackedItemId + guard*: PackedItemId bitsize*: int alignment*: int # for alignment options*: TOptions @@ -84,25 +97,25 @@ type PackedType* = object kind*: TTypeKind - nodekind*: TNodeKind + callConv*: TCallingConvention + #nodekind*: TNodeKind flags*: TTypeFlags - types*: int32 - nodes*: int32 - methods*: int32 - nodeflags*: TNodeFlags - info*: PackedLineInfo - sym*: ItemId - owner*: ItemId - attachedOps*: array[TTypeAttachedOp, ItemId] + types*: seq[TypeId] + n*: NodeId + methods*: seq[(int, PackedItemId)] + #nodeflags*: TNodeFlags + sym*: PackedItemId + owner*: PackedItemId + attachedOps*: array[TTypeAttachedOp, PackedItemId] size*: BiggestInt align*: int16 paddingAtEnd*: int16 lockLevel*: TLockLevel # lock level as required for deadlock checking # not serialized: loc*: TLoc because it is backend-specific typeInst*: TypeId - nonUniqueId*: ItemId + nonUniqueId*: int32 - Node* = object # 20 bytes + PackedNode* = object # 20 bytes kind*: TNodeKind flags*: TNodeFlags operand*: int32 # for kind in {nkSym, nkSymDef}: SymId @@ -115,72 +128,73 @@ type ModulePhase* = enum preLookup, lookedUpTopLevelStmts - Module* = object + GenericKey* = object + module*: int32 name*: string - file*: AbsoluteFile - ast*: PackedTree - phase*: ModulePhase - iface*: Table[string, seq[SymId]] # 'seq' because of overloading + types*: seq[MD5Digest] # is this a joke? - Program* = ref object - modules*: seq[Module] + PackedTree* = object ## usually represents a full Nim module + nodes*: seq[PackedNode] + #sh*: Shared Shared* = ref object # shared between different versions of 'Module'. # (though there is always exactly one valid # version of a module) syms*: seq[PackedSym] - types*: seq[seq[Node]] + types*: seq[PackedType] strings*: BiTable[string] # we could share these between modules. integers*: BiTable[BiggestInt] floats*: BiTable[BiggestFloat] - config*: ConfigRef - #thisModule*: ModuleId - #program*: Program + #config*: ConfigRef - PackedTree* = object ## usually represents a full Nim module - nodes*: seq[Node] - toPosition*: Table[SymId, NodePos] - sh*: Shared +proc hash*(key: GenericKey): Hash = + var h: Hash = 0 + h = h !& hash(key.module) + h = h !& hash(key.name) + h = h !& hash(key.types) + result = !$h proc `==`*(a, b: SymId): bool {.borrow.} proc hash*(a: SymId): Hash {.borrow.} proc `==`*(a, b: NodePos): bool {.borrow.} -proc `==`*(a, b: TypeId): bool {.borrow.} -proc `==`*(a, b: ModuleId): bool {.borrow.} - -proc declareSym*(tree: var PackedTree; kind: TSymKind; - name: LitId; info: PackedLineInfo): SymId = - result = SymId(tree.sh.syms.len) - tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info) +#proc `==`*(a, b: TypeId): bool {.borrow.} +proc `==`*(a, b: NodeId): bool {.borrow.} proc newTreeFrom*(old: PackedTree): PackedTree = result.nodes = @[] - result.sh = old.sh + when false: result.sh = old.sh -proc litIdFromName*(tree: PackedTree; name: string): LitId = - result = tree.sh.strings.getOrIncl(name) +when false: + proc declareSym*(tree: var PackedTree; kind: TSymKind; + name: LitId; info: PackedLineInfo): SymId = + result = SymId(tree.sh.syms.len) + tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info) -proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) = - tree.nodes.add Node(kind: kind, operand: int32 getOrIncl(tree.sh.strings, token), info: info) + proc litIdFromName*(tree: PackedTree; name: string): LitId = + result = tree.sh.strings.getOrIncl(name) -proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) = - tree.nodes.add Node(kind: kind, operand: 0, info: info) + proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) = + tree.nodes.add PackedNode(kind: kind, info: info, + operand: int32 getOrIncl(tree.sh.strings, token)) + + proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) = + tree.nodes.add PackedNode(kind: kind, operand: 0, info: info) proc throwAwayLastNode*(tree: var PackedTree) = tree.nodes.setLen(tree.nodes.len-1) proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) = - tree.nodes.add Node(kind: nkIdent, operand: int32(s), info: info) + tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info) -proc addSym*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = - tree.nodes.add Node(kind: nkSym, operand: int32(s), info: info) +proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) = + tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info) proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) = - tree.nodes.add Node(kind: nkInt32Lit, operand: int32(s), info: info) + tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info) proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = - tree.nodes.add Node(kind: nkSym, operand: int32(s), info: info) + tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info) proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit @@ -194,11 +208,12 @@ proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) = for i in 0.. nkNilLit: @@ -247,7 +264,8 @@ iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos = for x in sonsReadonly(tree, n): yield x patch dest, patchPos -iterator isons*(dest: var PackedTree; tree: PackedTree; n: NodePos): (int, NodePos) = +iterator isons*(dest: var PackedTree; tree: PackedTree; + n: NodePos): (int, NodePos) = var i = 0 for ch0 in sons(dest, tree, n): yield (i, ch0) @@ -301,10 +319,19 @@ proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool = if count >= x: return true return false -proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} = NodePos(n.int+1) -proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} = tree.nodes[n.int].kind -proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} = LitId tree.nodes[n.int].operand -proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} = tree.nodes[n.int].info +proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} = + NodePos(n.int+1) +proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} = + tree.nodes[n.int].kind +proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} = + LitId tree.nodes[n.int].operand +proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} = + tree.nodes[n.int].info + +template typ*(n: NodePos): PackedItemId = + tree.nodes[n.int].typeId +template flags*(n: NodePos): TNodeFlags = + tree.nodes[n.int].flags proc span(tree: PackedTree; pos: int): int {.inline.} = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand @@ -330,7 +357,9 @@ proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos = inc count assert false, "node has no i-th child" -proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} = tree.sh.strings[lit] +when false: + proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} = + tree.sh.strings[lit] template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info @@ -340,29 +369,30 @@ template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1) -proc strLit*(tree: PackedTree; n: NodePos): lent string = - assert n.kind == nkStrLit - result = tree.sh.strings[LitId tree.nodes[n.int].operand] +when false: + proc strLit*(tree: PackedTree; n: NodePos): lent string = + assert n.kind == nkStrLit + result = tree.sh.strings[LitId tree.nodes[n.int].operand] -proc strVal*(tree: PackedTree; n: NodePos): string = - assert n.kind == nkStrLit - result = tree.sh.strings[LitId tree.nodes[n.int].operand] - #result = cookedStrLit(raw) + proc strVal*(tree: PackedTree; n: NodePos): string = + assert n.kind == nkStrLit + result = tree.sh.strings[LitId tree.nodes[n.int].operand] + #result = cookedStrLit(raw) -proc filenameVal*(tree: PackedTree; n: NodePos): string = - case n.kind - of nkStrLit: - result = strVal(tree, n) - of nkIdent: - result = tree.sh.strings[n.litId] - of nkSym: - result = tree.sh.strings[tree.sh.syms[int n.symId].name] - else: - result = "" + proc filenameVal*(tree: PackedTree; n: NodePos): string = + case n.kind + of nkStrLit: + result = strVal(tree, n) + of nkIdent: + result = tree.sh.strings[n.litId] + of nkSym: + result = tree.sh.strings[tree.sh.syms[int n.symId].name] + else: + result = "" -proc identAsStr*(tree: PackedTree; n: NodePos): lent string = - assert n.kind == nkIdent - result = tree.sh.strings[LitId tree.nodes[n.int].operand] + proc identAsStr*(tree: PackedTree; n: NodePos): lent string = + assert n.kind == nkIdent + result = tree.sh.strings[LitId tree.nodes[n.int].operand] const externIntLit* = {nkCharLit, @@ -380,7 +410,8 @@ const externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit} directIntLit* = nkInt32Lit -proc toString*(tree: PackedTree; n: NodePos; nesting: int; result: var string) = +proc toString*(tree: PackedTree; n: NodePos; sh: Shared; nesting: int; + result: var string) = let pos = n.int if result.len > 0 and result[^1] notin {' ', '\n'}: result.add ' ' @@ -390,46 +421,47 @@ proc toString*(tree: PackedTree; n: NodePos; nesting: int; result: var string) = of nkNone, nkEmpty, nkNilLit, nkType: discard of nkIdent, nkStrLit..nkTripleStrLit: result.add " " - result.add tree.sh.strings[LitId tree.nodes[pos].operand] + result.add sh.strings[LitId tree.nodes[pos].operand] of nkSym: result.add " " - result.add tree.sh.strings[tree.sh.syms[tree.nodes[pos].operand].name] + result.add sh.strings[sh.syms[tree.nodes[pos].operand].name] of directIntLit: result.add " " result.addInt tree.nodes[pos].operand of externSIntLit: result.add " " - result.addInt tree.sh.integers[LitId tree.nodes[pos].operand] + result.addInt sh.integers[LitId tree.nodes[pos].operand] of externUIntLit: result.add " " - result.add $cast[uint64](tree.sh.integers[LitId tree.nodes[pos].operand]) + result.add $cast[uint64](sh.integers[LitId tree.nodes[pos].operand]) else: result.add "(\n" for i in 1..(nesting+1)*2: result.add ' ' for child in sonsReadonly(tree, n): - toString(tree, child, nesting + 1, result) + toString(tree, child, sh, nesting + 1, result) result.add "\n" for i in 1..nesting*2: result.add ' ' result.add ")" #for i in 1..nesting*2: result.add ' ' -proc toString*(tree: PackedTree; n: NodePos): string = +proc toString*(tree: PackedTree; n: NodePos; sh: Shared): string = result = "" - toString(tree, n, 0, result) + toString(tree, n, sh, 0, result) -proc debug*(tree: PackedTree) = - stdout.write toString(tree, NodePos 0) +proc debug*(tree: PackedTree; sh: Shared) = + stdout.write toString(tree, NodePos 0, sh) -proc identIdImpl(tree: PackedTree; n: NodePos): LitId = - if n.kind == nkIdent: - result = n.litId - elif n.kind == nkSym: - result = tree.sh.syms[int n.symId].name - else: - result = LitId(0) +when false: + proc identIdImpl(tree: PackedTree; n: NodePos): LitId = + if n.kind == nkIdent: + result = n.litId + elif n.kind == nkSym: + result = tree.sh.syms[int n.symId].name + else: + result = LitId(0) -template identId*(n: NodePos): LitId = identIdImpl(tree, n) + template identId*(n: NodePos): LitId = identIdImpl(tree, n) template copyInto*(dest, n, body) = let patchPos = prepare(dest, tree, n) @@ -441,17 +473,20 @@ template copyIntoKind*(dest, kind, info, body) = body patch dest, patchPos -proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool = - let litId = tree.sh.strings.getKeyId(pragma) - if litId == LitId(0): - return false - assert n.kind == nkPragma - for ch0 in sonsReadonly(tree, n): - if ch0.kind == nkExprColonExpr: - if ch0.firstSon.identId == litId: +when false: + proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool = + let litId = tree.sh.strings.getKeyId(pragma) + if litId == LitId(0): + return false + assert n.kind == nkPragma + for ch0 in sonsReadonly(tree, n): + if ch0.kind == nkExprColonExpr: + if ch0.firstSon.identId == litId: + return true + elif ch0.identId == litId: return true - elif ch0.identId == litId: - return true + +proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len when false: proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) = @@ -459,3 +494,68 @@ when false: dest.add nkStrLit, msg, n.info copyTree(dest, tree, n) patch dest, patchPos + + proc hash*(table: StringTableRef): Hash = + ## XXX: really should be introduced into strtabs... + var h: Hash = 0 + for pair in pairs table: + h = h !& hash(pair) + result = !$h + + proc hash*(config: ConfigRef): Hash = + ## XXX: vet and/or extend this + var h: Hash = 0 + h = h !& hash(config.selectedGC) + h = h !& hash(config.features) + h = h !& hash(config.legacyFeatures) + h = h !& hash(config.configVars) + h = h !& hash(config.symbols) + result = !$h + + # XXX: lazy hashes for now + type + LazyHashes = PackedSym or PackedType or PackedLib or + PackedLineInfo or PackedTree or PackedNode + + proc hash*(sh: Shared): Hash + proc hash*(s: LazyHashes): Hash + proc hash*(s: seq[LazyHashes]): Hash + + proc hash*(s: LazyHashes): Hash = + var h: Hash = 0 + for k, v in fieldPairs(s): + h = h !& hash((k, v)) + result = !$h + + proc hash*(s: seq[LazyHashes]): Hash = + ## critically, we need to hash the indices alongside their values + var h: Hash = 0 + for i, n in pairs s: + h = h !& hash((i, n)) + result = !$h + + proc hash*(sh: Shared): Hash = + ## might want to edit this... + # XXX: these have too many references + when false: + var h: Hash = 0 + h = h !& hash(sh.syms) + h = h !& hash(sh.types) + h = h !& hash(sh.strings) + h = h !& hash(sh.integers) + h = h !& hash(sh.floats) + h = h !& hash(sh.config) + result = !$h + + proc hash*(m: Module): Hash = + var h: Hash = 0 + h = h !& hash(m.name) + h = h !& hash(m.ast) + result = !$h + + template safeItemId*(x: typed; f: untyped): ItemId = + ## yield a valid ItemId value for the field of a nillable type + if x.isNil: + nilItemId + else: + x.`f` diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim new file mode 100644 index 000000000..99ce183f2 --- /dev/null +++ b/compiler/ic/rodfiles.nim @@ -0,0 +1,143 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +from typetraits import supportsCopyMem + +type + RodSection* = enum + versionSection + configSection + stringsSection + checkSumsSection + depsSection + integersSection + floatsSection + topLevelSection + bodiesSection + symsSection + typesSection + + RodFileError* = enum + ok, tooBig, ioFailure, wrongHeader, wrongSection, configMismatch, + includeFileChanged + + RodFile* = object + f*: File + currentSection*: RodSection # for error checking + err*: RodFileError # little experiment to see if this works + # better than exceptions. + +const + RodVersion = 1 + cookie = [byte(0), byte('R'), byte('O'), byte('D'), + byte(0), byte(0), byte(0), byte(RodVersion)] + +proc storePrim*(f: var RodFile; s: string) = + if f.err != ok: return + if s.len >= high(int32): + f.err = tooBig + return + var lenPrefix = int32(s.len) + if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): + f.err = ioFailure + else: + if s.len != 0: + if writeBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len: + f.err = ioFailure + +proc storePrim*[T](f: var RodFile; x: T) = + if f.err != ok: return + when supportsCopyMem(T): + if writeBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): + f.err = ioFailure + elif T is tuple: + for y in fields(x): + storePrim(f, y) + else: + {.error: "unsupported type for 'storePrim'".} + +proc storeSeq*[T](f: var RodFile; s: seq[T]) = + if f.err != ok: return + if s.len >= high(int32): + f.err = tooBig + return + var lenPrefix = int32(s.len) + if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): + f.err = ioFailure + else: + for i in 0.. 0: + if readBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len: + f.err = ioFailure + +proc loadPrim*[T](f: var RodFile; x: var T) = + if f.err != ok: return + when supportsCopyMem(T): + if readBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): + f.err = ioFailure + elif T is tuple: + for y in fields(x): + loadPrim(f, y) + else: + {.error: "unsupported type for 'loadPrim'".} + +proc loadSeq*[T](f: var RodFile; s: var seq[T]) = + if f.err != ok: return + var lenPrefix = int32(0) + if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): + f.err = ioFailure + else: + s = newSeq[T](lenPrefix) + for i in 0.. TypeId + symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId + config*: ConfigRef + +template primConfigFields(fn: untyped) {.dirty.} = + fn backend + fn selectedGC + fn cCompiler + fn options + fn globalOptions + +proc definedSymbolsAsString(config: ConfigRef): string = + result = newStringOfCap(200) + result.add "config" + for d in definedSymbolNames(config.symbols): + result.add ' ' + result.add d + +proc rememberConfig(c: var PackedEncoder; config: ConfigRef) = + c.m.definedSymbols = definedSymbolsAsString(config) + + template rem(x) = + c.m.cfg.x = config.x + primConfigFields rem + +proc configIdentical(m: PackedModule; config: ConfigRef): bool = + result = m.definedSymbols == definedSymbolsAsString(config) + template eq(x) = + result = result and m.cfg.x == config.x + primConfigFields eq + +proc hashFileCached(conf: ConfigRef; fileIdx: FileIndex): string = + result = msgs.getHash(conf, fileIdx) + if result.len == 0: + let fullpath = msgs.toFullPath(conf, fileIdx) + result = $secureHashFile(fullpath) + msgs.setHash(conf, fileIdx, result) + +proc toLitId(x: FileIndex; c: var PackedEncoder): LitId = + ## store a file index as a literal if x == c.lastFile: result = c.lastLit else: result = c.filenames.getOrDefault(x) if result == LitId(0): - let p = msgs.toFullPath(ir.sh.config, x) - result = getOrIncl(ir.sh.strings, p) + let p = msgs.toFullPath(c.config, x) + result = getOrIncl(c.m.sh.strings, p) c.filenames[x] = result c.lastFile = x c.lastLit = result + assert result != LitId(0) -proc toPackedInfo(x: TLineInfo; ir: var PackedTree; c: var Context): PackedLineInfo = - PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, ir, c)) +proc toFileIndex(x: LitId; m: PackedModule; config: ConfigRef): FileIndex = + result = msgs.fileInfoIdx(config, AbsoluteFile m.sh.strings[x]) -proc toPackedType(t: PType; ir: var PackedTree; c: var Context): TypeId = - result = TypeId(0) +proc includesIdentical(m: var PackedModule; config: ConfigRef): bool = + for it in mitems(m.includes): + if hashFileCached(config, toFileIndex(it[0], m, config)) != it[1]: + return false + result = true -proc toPackedSym(s: PSym; ir: var PackedTree; c: var Context): SymId = - result = SymId(0) +proc initEncoder*(c: var PackedEncoder; m: PSym; config: ConfigRef) = + ## setup a context for serializing to packed ast + c.m.sh = Shared() + c.thisModule = m.itemId.module + c.config = config + c.m.bodies = newTreeFrom(c.m.topLevel) + c.m.hidden = newTreeFrom(c.m.topLevel) -proc toPackedSymNode(n: PNode; ir: var PackedTree; c: var Context) = + let thisNimFile = FileIndex c.thisModule + var h = msgs.getHash(config, thisNimFile) + if h.len == 0: + let fullpath = msgs.toFullPath(config, thisNimFile) + if isAbsolute(fullpath): + # For NimScript compiler API support the main Nim file might be from a stream. + h = $secureHashFile(fullpath) + msgs.setHash(config, thisNimFile, h) + c.m.includes.add((toLitId(thisNimFile, c), h)) # the module itself + +proc addIncludeFileDep*(c: var PackedEncoder; f: FileIndex) = + c.m.includes.add((toLitId(f, c), hashFileCached(c.config, f))) + +proc addImportFileDep*(c: var PackedEncoder; f: FileIndex) = + c.m.imports.add toLitId(f, c) + +proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder) +proc toPackedSym*(s: PSym; c: var PackedEncoder): PackedItemId +proc toPackedType(t: PType; c: var PackedEncoder): PackedItemId + +proc flush(c: var PackedEncoder) = + ## serialize any pending types or symbols from the context + while true: + if c.pendingTypes.len > 0: + discard toPackedType(c.pendingTypes.pop, c) + elif c.pendingSyms.len > 0: + discard toPackedSym(c.pendingSyms.pop, c) + else: + break + +proc toLitId(x: string; c: var PackedEncoder): LitId = + ## store a string as a literal + result = getOrIncl(c.m.sh.strings, x) + +proc toLitId(x: BiggestInt; c: var PackedEncoder): LitId = + ## store an integer as a literal + result = getOrIncl(c.m.sh.integers, x) + +proc toPackedInfo(x: TLineInfo; c: var PackedEncoder): PackedLineInfo = + PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c)) + +proc safeItemId(s: PSym; c: var PackedEncoder): PackedItemId {.inline.} = + ## given a symbol, produce an ItemId with the correct properties + ## for local or remote symbols, packing the symbol as necessary + if s == nil: + result = nilItemId + elif s.itemId.module == c.thisModule: + result = PackedItemId(module: LitId(0), item: s.itemId.item) + else: + result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c), + item: s.itemId.item) + +proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder) = + ## add a remote symbol reference to the tree + let info = n.info.toPackedInfo(c) + ir.nodes.add PackedNode(kind: nkModuleRef, operand: 2.int32, # 2 kids... + typeId: toPackedType(n.typ, c), info: info) + ir.nodes.add PackedNode(kind: nkInt32Lit, info: info, + operand: toLitId(n.sym.itemId.module.FileIndex, c).int32) + ir.nodes.add PackedNode(kind: nkInt32Lit, info: info, + operand: n.sym.itemId.item) + +proc addMissing(c: var PackedEncoder; p: PSym) = + ## consider queuing a symbol for later addition to the packed tree + if p != nil and p.itemId.module == c.thisModule: + if p.itemId.item notin c.symMarker: + c.pendingSyms.add p + +proc addMissing(c: var PackedEncoder; p: PType) = + ## consider queuing a type for later addition to the packed tree + if p != nil and p.uniqueId.module == c.thisModule: + if p.uniqueId.item notin c.typeMarker: + c.pendingTypes.add p + +template storeNode(dest, src, field) = + var nodeId: NodeId + if src.field != nil: + nodeId = getNodeId(c.m.bodies) + toPackedNode(src.field, c.m.bodies, c) + else: + nodeId = emptyNodeId + dest.field = nodeId + +proc toPackedType(t: PType; c: var PackedEncoder): PackedItemId = + ## serialize a ptype + if t.isNil: return nilTypeId + + if t.uniqueId.module != c.thisModule: + # XXX Assert here that it already was serialized in the foreign module! + # it is a foreign type: + return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c), item: t.uniqueId.item) + + if not c.typeMarker.containsOrIncl(t.uniqueId.item): + if t.uniqueId.item >= c.m.sh.types.len: + setLen c.m.sh.types, t.uniqueId.item+1 + + var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv, + size: t.size, align: t.align, nonUniqueId: t.itemId.item, + paddingAtEnd: t.paddingAtEnd, lockLevel: t.lockLevel) + storeNode(p, t, n) + + for op, s in pairs t.attachedOps: + c.addMissing s + p.attachedOps[op] = s.safeItemId(c) + + p.typeInst = t.typeInst.toPackedType(c) + for kid in items t.sons: + p.types.add kid.toPackedType(c) + for i, s in items t.methods: + c.addMissing s + p.methods.add (i, s.safeItemId(c)) + c.addMissing t.sym + p.sym = t.sym.safeItemId(c) + c.addMissing t.owner + p.owner = t.owner.safeItemId(c) + + # fill the reserved slot, nothing else: + c.m.sh.types[t.uniqueId.item] = p + + result = PackedItemId(module: LitId(0), item: t.uniqueId.item) + +proc toPackedLib(l: PLib; c: var PackedEncoder): PackedLib = + ## the plib hangs off the psym via the .annex field + if l.isNil: return + result.kind = l.kind + result.generated = l.generated + result.isOverriden = l.isOverriden + result.name = toLitId($l.name, c) + storeNode(result, l, path) + +proc toPackedSym*(s: PSym; c: var PackedEncoder): PackedItemId = + ## serialize a psym + if s.isNil: return nilItemId + + if s.itemId.module != c.thisModule: + # XXX Assert here that it already was serialized in the foreign module! + # it is a foreign symbol: + return PackedItemId(module: toLitId(s.itemId.module.FileIndex, c), item: s.itemId.item) + + if not c.symMarker.containsOrIncl(s.itemId.item): + if s.itemId.item >= c.m.sh.syms.len: + setLen c.m.sh.syms, s.itemId.item+1 + + var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c), magic: s.magic, + position: s.position, offset: s.offset, options: s.options, + name: s.name.s.toLitId(c)) + + storeNode(p, s, ast) + storeNode(p, s, constraint) + + if s.kind in {skLet, skVar, skField, skForVar}: + c.addMissing s.guard + p.guard = s.guard.safeItemId(c) + p.bitsize = s.bitsize + p.alignment = s.alignment + + p.externalName = toLitId(if s.loc.r.isNil: "" else: $s.loc.r, c) + c.addMissing s.typ + p.typ = s.typ.toPackedType(c) + c.addMissing s.owner + p.owner = s.owner.safeItemId(c) + p.annex = toPackedLib(s.annex, c) + when hasFFI: + p.cname = toLitId(s.cname, c) + + # fill the reserved slot, nothing else: + c.m.sh.syms[s.itemId.item] = p + + result = PackedItemId(module: LitId(0), item: s.itemId.item) + +proc toSymNode(n: PNode; ir: var PackedTree; c: var PackedEncoder) = + ## store a local or remote psym reference in the tree assert n.kind == nkSym - let t = toPackedType(n.typ, ir, c) - - if n.sym.itemId.module == c.thisModule: + template s: PSym = n.sym + let id = s.toPackedSym(c).item + if s.itemId.module == c.thisModule: # it is a symbol that belongs to the module we're currently # packing: - let sid = toPackedSym(n.sym, ir, c) - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32(sid), - typeId: t, info: toPackedInfo(n.info, ir, c)) + ir.addSym(id, toPackedInfo(n.info, c)) else: # store it as an external module reference: - # nkModuleRef - discard - - -proc toPackedNode*(n: PNode; ir: var PackedTree; c: var Context) = - template toP(x: TLineInfo): PackedLineInfo = toPackedInfo(x, ir, c) + addModuleRef(n, ir, c) +proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder) = + ## serialize a node into the tree + if n.isNil: return + let info = toPackedInfo(n.info, c) case n.kind - of nkNone, nkEmpty, nkNilLit: - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: 0, - typeId: toPackedType(n.typ, ir, c), info: toP n.info) + of nkNone, nkEmpty, nkNilLit, nkType: + ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, operand: 0, + typeId: toPackedType(n.typ, c), info: info) of nkIdent: - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.strings, n.ident.s), - typeId: toPackedType(n.typ, ir, c), info: toP n.info) + ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, + operand: int32 getOrIncl(c.m.sh.strings, n.ident.s), + typeId: toPackedType(n.typ, c), info: info) of nkSym: - toPackedSymNode(n, ir, c) + toSymNode(n, ir, c) of directIntLit: - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32(n.intVal), - typeId: toPackedType(n.typ, ir, c), info: toP n.info) + ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, + operand: int32(n.intVal), + typeId: toPackedType(n.typ, c), info: info) of externIntLit: - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.integers, n.intVal), - typeId: toPackedType(n.typ, ir, c), info: toP n.info) + ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, + operand: int32 getOrIncl(c.m.sh.integers, n.intVal), + typeId: toPackedType(n.typ, c), info: info) of nkStrLit..nkTripleStrLit: - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.strings, n.strVal), - typeId: toPackedType(n.typ, ir, c), info: toP n.info) + ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, + operand: int32 getOrIncl(c.m.sh.strings, n.strVal), + typeId: toPackedType(n.typ, c), info: info) of nkFloatLit..nkFloat128Lit: - ir.nodes.add Node(kind: n.kind, flags: n.flags, operand: int32 getOrIncl(ir.sh.floats, n.floatVal), - typeId: toPackedType(n.typ, ir, c), info: toP n.info) + ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, + operand: int32 getOrIncl(c.m.sh.floats, n.floatVal), + typeId: toPackedType(n.typ, c), info: info) else: - let patchPos = ir.prepare(n.kind, n.flags, toPackedType(n.typ, ir, c), toP n.info) + let patchPos = ir.prepare(n.kind, n.flags, + toPackedType(n.typ, c), info) for i in 0..= g.len: + g.setLen(m+1) + + case g[m].status + of undefined: + g[m].status = loading + let fullpath = msgs.toFullPath(conf, fileIdx) + let rod = toRodFile(conf, AbsoluteFile fullpath) + let err = loadRodFile(rod, g[m].fromDisk, conf) + if err == ok: + result = false + # check its dependencies: + for dep in g[m].fromDisk.imports: + let fid = toFileIndex(dep, g[m].fromDisk, conf) + # Warning: we need to traverse the full graph, so + # do **not use break here**! + if needsRecompile(g, conf, fid): + result = true + + g[m].status = if result: outdated else: loaded + else: + loadError(err, rod) + g[m].status = outdated + result = true + of loading, loaded: + result = false + of outdated: + result = true + +# ------------------------------------------------------------------------- + +proc storeError(err: RodFileError; filename: AbsoluteFile) = + echo "Error: ", $err, "; couldn't write to ", filename.string + removeFile(filename.string) + +proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder) = + rememberConfig(encoder, encoder.config) + + var f = rodfiles.create(filename.string) + f.storeHeader() + f.storeSection configSection + f.storePrim encoder.m.definedSymbols + f.storePrim encoder.m.cfg + + f.storeSection stringsSection + f.store encoder.m.sh.strings + + f.storeSection checkSumsSection + f.storeSeq encoder.m.includes + + f.storeSection depsSection + f.storeSeq encoder.m.imports + + f.storeSection integersSection + f.store encoder.m.sh.integers + + f.storeSection floatsSection + f.store encoder.m.sh.floats + + f.storeSection topLevelSection + f.storeSeq encoder.m.topLevel.nodes + + f.storeSection bodiesSection + f.storeSeq encoder.m.bodies.nodes + + f.storeSection symsSection + f.storeSeq encoder.m.sh.syms + + f.storeSection typesSection + f.storeSeq encoder.m.sh.types + close(f) + if f.err != ok: + loadError(f.err, filename) + + when true: + # basic loader testing: + var m2: PackedModule + discard loadRodFile(filename, m2, encoder.config) + +# ---------------------------------------------------------------------------- + +type + PackedDecoder* = object + thisModule*: int32 + lastLit*: LitId + lastFile*: FileIndex # remember the last lookup entry. + config*: ConfigRef + ident: IdentCache + +proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; t: PackedItemId): PType +proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedItemId): PSym + +proc toFileIndexCached(c: var PackedDecoder; g: var PackedModuleGraph; f: LitId): FileIndex = + if c.lastLit == f: + result = c.lastFile + else: + result = toFileIndex(f, g[c.thisModule].fromDisk, c.config) + c.lastLit = f + c.lastFile = result + +proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; + x: PackedLineInfo): TLineInfo = + assert g[c.thisModule].status == loaded + result = TLineInfo(line: x.line, col: x.col, + fileIndex: toFileIndexCached(c, g, x.file)) + +proc loadNodes(c: var PackedDecoder; g: var PackedModuleGraph; + tree: PackedTree; n: NodePos): PNode = + let k = n.kind + result = newNodeIT(k, translateLineInfo(c, g, n.info), + loadType(c, g, n.typ)) + result.flags = n.flags + + case k + of nkEmpty, nkNilLit, nkType: + discard + of nkIdent: + result.ident = getIdent(c.ident, g[c.thisModule].fromDisk.sh.strings[n.litId]) + of nkSym: + result.sym = loadSym(c, g, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand)) + of directIntLit: + result.intVal = tree.nodes[n.int].operand + of externIntLit: + result.intVal = g[c.thisModule].fromDisk.sh.integers[n.litId] + of nkStrLit..nkTripleStrLit: + result.strVal = g[c.thisModule].fromDisk.sh.strings[n.litId] + of nkFloatLit..nkFloat128Lit: + result.floatVal = g[c.thisModule].fromDisk.sh.floats[n.litId] + of nkModuleRef: + let (n1, n2) = sons2(tree, n) + assert n1.kind == nkInt32Lit + assert n2.kind == nkInt32Lit + transitionNoneToSym(result) + result.sym = loadSym(c, g, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)) + else: + for n0 in sonsReadonly(tree, n): + result.add loadNodes(c, g, tree, n0) + +proc moduleIndex*(c: var PackedDecoder; g: var PackedModuleGraph; + s: PackedItemId): int32 {.inline.} = + result = if s.module == LitId(0): c.thisModule + else: toFileIndexCached(c, g, s.module).int32 + +proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; + s: PackedSym; si, item: int32): PSym = + result = PSym(itemId: ItemId(module: si, item: item), + kind: s.kind, magic: s.magic, flags: s.flags, + info: translateLineInfo(c, g, s.info), + options: s.options, + position: s.position, + name: getIdent(c.ident, g[si].fromDisk.sh.strings[s.name]) + ) + +template loadAstBody(p, field) = + if p.field != emptyNodeId: + result.field = loadNodes(c, g, g[si].fromDisk.bodies, NodePos p.field) + +proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph; + si, item: int32; l: PackedLib): PLib = + # XXX: hack; assume a zero LitId means the PackedLib is all zero (empty) + if l.name.int == 0: + result = nil + else: + result = PLib(generated: l.generated, isOverriden: l.isOverriden, + kind: l.kind, name: rope g[si].fromDisk.sh.strings[l.name]) + loadAstBody(l, path) + +proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; + s: PackedSym; si, item: int32; result: PSym) = + result.typ = loadType(c, g, s.typ) + loadAstBody(s, constraint) + loadAstBody(s, ast) + result.annex = loadLib(c, g, si, item, s.annex) + when hasFFI: + result.cname = g[si].fromDisk.sh.strings[s.cname] + + if s.kind in {skLet, skVar, skField, skForVar}: + result.guard = loadSym(c, g, s.guard) + result.bitsize = s.bitsize + result.alignment = s.alignment + result.owner = loadSym(c, g, s.owner) + let externalName = g[si].fromDisk.sh.strings[s.externalName] + if externalName != "": + result.loc.r = rope externalName + +proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedItemId): PSym = + if s == nilTypeId: + result = nil + else: + let si = moduleIndex(c, g, s) + assert g[si].status == loaded + if not g[si].symsInit: + g[si].symsInit = true + setLen g[si].syms, g[si].fromDisk.sh.syms.len + + if g[si].syms[s.item] == nil: + let packed = addr(g[si].fromDisk.sh.syms[s.item]) + result = symHeaderFromPacked(c, g, packed[], si, s.item) + # store it here early on, so that recursions work properly: + g[si].syms[s.item] = result + symBodyFromPacked(c, g, packed[], si, s.item, result) + else: + result = g[si].syms[s.item] + +proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; + t: PackedType; si, item: int32): PType = + result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind, + flags: t.flags, size: t.size, align: t.align, + paddingAtEnd: t.paddingAtEnd, lockLevel: t.lockLevel, + uniqueId: ItemId(module: si, item: item)) + +proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; + t: PackedType; si, item: int32; result: PType) = + result.sym = loadSym(c, g, t.sym) + result.owner = loadSym(c, g, t.owner) + for op, item in pairs t.attachedOps: + result.attachedOps[op] = loadSym(c, g, item) + result.typeInst = loadType(c, g, t.typeInst) + for son in items t.types: + result.sons.add loadType(c, g, son) + loadAstBody(t, n) + for gen, id in items t.methods: + result.methods.add((gen, loadSym(c, g, id))) + +proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; t: PackedItemId): PType = + if t == nilTypeId: + result = nil + else: + let si = moduleIndex(c, g, t) + assert g[si].status == loaded + if not g[si].typesInit: + g[si].typesInit = true + setLen g[si].types, g[si].fromDisk.sh.types.len + + if g[si].types[t.item] == nil: + let packed = addr(g[si].fromDisk.sh.types[t.item]) + result = typeHeaderFromPacked(c, g, packed[], si, t.item) + # store it here early on, so that recursions work properly: + g[si].types[t.item] = result + typeBodyFromPacked(c, g, packed[], si, t.item, result) + else: + result = g[si].types[t.item] + + +when false: + proc initGenericKey*(s: PSym; types: seq[PType]): GenericKey = + result.module = s.owner.itemId.module + result.name = s.name.s + result.types = mapIt types: hashType(it, {CoType, CoDistinct}).MD5Digest + + proc addGeneric*(m: var Module; c: var PackedEncoder; key: GenericKey; s: PSym) = + ## add a generic to the module + if key notin m.generics: + m.generics[key] = toPackedSym(s, m.ast, c) + toPackedNode(s.ast, m.ast, c) diff --git a/compiler/importer.nim b/compiler/importer.nim index a055e16b7..645c03b2b 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -220,12 +220,13 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym = localError(c.config, n.info, "module alias must be an identifier") elif n[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... - result = createModuleAlias(realModule, nextId c.idgen, n[1].ident, realModule.info, + result = createModuleAlias(realModule, nextSymId c.idgen, n[1].ident, realModule.info, c.config.options) proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = let f = checkModuleName(c.config, n) if f != InvalidFileIdx: + addImportFileDep(c, f) let L = c.graph.importStack.len let recursion = c.graph.importStack.find(f) c.graph.importStack.add f diff --git a/compiler/incremental.nim b/compiler/incremental.nim deleted file mode 100644 index 8b3a9bf55..000000000 --- a/compiler/incremental.nim +++ /dev/null @@ -1,198 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2018 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Basic type definitions the module graph needs in order to support -## incremental compilations. - -const nimIncremental* = defined(nimIncremental) - -import options, lineinfos - -when nimIncremental: - import ast, msgs, intsets, btrees, db_sqlite, std / sha1, pathutils - from strutils import parseInt - from os import isAbsolute - - type - Writer* = object - sstack*: seq[PSym] # a stack of symbols to process - tstack*: seq[PType] # a stack of types to process - tmarks*, smarks*: IntSet - forwardedSyms*: seq[PSym] - - Reader* = object - syms*: BTree[int, PSym] - types*: BTree[int, PType] - - IncrementalCtx* = object - db*: DbConn - w*: Writer - r*: Reader - configChanged*: bool - - proc init*(incr: var IncrementalCtx) = - incr.w.sstack = @[] - incr.w.tstack = @[] - incr.w.tmarks = initIntSet() - incr.w.smarks = initIntSet() - incr.w.forwardedSyms = @[] - incr.r.syms = initBTree[int, PSym]() - incr.r.types = initBTree[int, PType]() - - - proc hashFileCached*(conf: ConfigRef; fileIdx: FileIndex; fullpath: AbsoluteFile): string = - result = msgs.getHash(conf, fileIdx) - if result.len == 0 and isAbsolute(string fullpath): - result = $secureHashFile(string fullpath) - msgs.setHash(conf, fileIdx, result) - - proc toDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; fileIdx: FileIndex): int = - if fileIdx == FileIndex(-1): return -1 - let fullpath = toFullPath(conf, fileIdx) - let row = incr.db.getRow(sql"select id, fullhash from filenames where fullpath = ?", - fullpath) - let id = row[0] - let fullhash = hashFileCached(conf, fileIdx, AbsoluteFile fullpath) - if id.len == 0: - result = int incr.db.insertID(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)", - int(fileIdx), fullpath, fullhash) - else: - if row[1] != fullhash: - incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath) - result = parseInt(id) - - proc fromDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; dbId: int): FileIndex = - if dbId == -1: return FileIndex(-1) - let fullpath = incr.db.getValue(sql"select fullpath from filenames where id = ?", dbId) - doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId - result = fileInfoIdx(conf, AbsoluteFile fullpath) - - - proc addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef; - module, fileIdx: FileIndex; - isIncludeFile: bool) = - if conf.symbolFiles != v2Sf: return - - let a = toDbFileId(incr, conf, module) - let b = toDbFileId(incr, conf, fileIdx) - - incr.db.exec(sql"insert into deps(module, dependency, isIncludeFile) values (?, ?, ?)", - a, b, ord(isIncludeFile)) - - # --------------- Database model --------------------------------------------- - - proc createDb*(db: DbConn) = - db.exec(sql""" - create table if not exists controlblock( - idgen integer not null - ); - """) - - db.exec(sql""" - create table if not exists config( - config varchar(8000) not null - ); - """) - - db.exec(sql""" - create table if not exists filenames( - id integer primary key, - nimid integer not null, - fullpath varchar(8000) not null, - fullHash varchar(256) not null - ); - """) - db.exec sql"create index if not exists FilenameIx on filenames(fullpath);" - - db.exec(sql""" - create table if not exists modules( - id integer primary key, - nimid integer not null, - fullpath varchar(8000) not null, - interfHash varchar(256) not null, - fullHash varchar(256) not null, - - created timestamp not null default (DATETIME('now')) - );""") - db.exec(sql"""create unique index if not exists SymNameIx on modules(fullpath);""") - - db.exec(sql""" - create table if not exists deps( - id integer primary key, - module integer not null, - dependency integer not null, - isIncludeFile integer not null, - foreign key (module) references filenames(id), - foreign key (dependency) references filenames(id) - );""") - db.exec(sql"""create index if not exists DepsIx on deps(module);""") - - db.exec(sql""" - create table if not exists types( - id integer primary key, - nimid integer not null, - module integer not null, - data blob not null, - foreign key (module) references module(id) - ); - """) - db.exec sql"create index TypeByModuleIdx on types(module);" - db.exec sql"create index TypeByNimIdIdx on types(nimid);" - - db.exec(sql""" - create table if not exists syms( - id integer primary key, - nimid integer not null, - module integer not null, - name varchar(256) not null, - data blob not null, - exported int not null, - foreign key (module) references module(id) - ); - """) - db.exec sql"create index if not exists SymNameIx on syms(name);" - db.exec sql"create index SymByNameAndModuleIdx on syms(name, module);" - db.exec sql"create index SymByModuleIdx on syms(module);" - db.exec sql"create index SymByNimIdIdx on syms(nimid);" - - - db.exec(sql""" - create table if not exists toplevelstmts( - id integer primary key, - position integer not null, - module integer not null, - data blob not null, - foreign key (module) references module(id) - ); - """) - db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);" - db.exec sql"create index TopLevelStmtByPositionIdx on toplevelstmts(position);" - - db.exec(sql""" - create table if not exists statics( - id integer primary key, - module integer not null, - data blob not null, - foreign key (module) references module(id) - ); - """) - db.exec sql"create index StaticsByModuleIdx on toplevelstmts(module);" - db.exec sql"insert into controlblock(idgen) values (0)" - - -else: - type - IncrementalCtx* = object - - template init*(incr: IncrementalCtx) = discard - - template addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef; - module, fileIdx: FileIndex; - isIncludeFile: bool) = - discard diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 34c11e06c..76a063faa 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -62,7 +62,7 @@ template dbg(body) = body proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = - let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextId c.idgen, c.owner, info) + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info) sym.typ = typ s.vars.add(sym) result = newSymNode(sym) @@ -252,7 +252,7 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = localError(c.graph.config, ri.info, errGenerated, m) proc makePtrType(c: var Con, baseType: PType): PType = - result = newType(tyPtr, nextId c.idgen, c.owner) + result = newType(tyPtr, nextTypeId c.idgen, c.owner) addSonSkipIntLit(result, baseType, c.idgen) proc genOp(c: var Con; op: PSym; dest: PNode): PNode = @@ -415,7 +415,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) - var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextId c.idgen, c.owner, n.info) + var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info) temp.typ = n.typ var v = newNodeI(nkLetSection, n.info) let tempAsNode = newSymNode(temp) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 4f3823f8a..8eaa9e1e2 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -130,14 +130,14 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator) var n = newNodeI(nkRange, iter.info) n.add newIntNode(nkIntLit, -1) n.add newIntNode(nkIntLit, 0) - result = newType(tyRange, nextId(idgen), iter) + result = newType(tyRange, nextTypeId(idgen), iter) result.n = n var intType = nilOrSysInt(g) - if intType.isNil: intType = newType(tyInt, nextId(idgen), iter) + if intType.isNil: intType = newType(tyInt, nextTypeId(idgen), iter) rawAddSon(result, intType) proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = - result = newSym(skField, getIdent(g.cache, ":state"), nextId(idgen), iter, iter.info) + result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info) result.typ = createClosureIterStateType(g, iter, idgen) proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = @@ -151,7 +151,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym result = iter.ast[resultPos].sym else: # XXX a bit hacky: - result = newSym(skResult, getIdent(g.cache, ":result"), nextId(idgen), iter, iter.info, {}) + result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {}) result.typ = iter.typ[0] incl(result.flags, sfUsed) iter.ast.add newSymNode(result) @@ -259,7 +259,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen) env = indirectAccess(newSymNode(it), hp, hp.info) else: - let e = newSym(skLet, iter.name, nextId(idgen), owner, n.info) + let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info) e.typ = hp.typ e.flags = hp.flags env = newSymNode(e) @@ -330,7 +330,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = result = c.ownerToType.getOrDefault(owner.id) if result.isNil: - result = newType(tyRef, nextId(c.idgen), owner) + result = newType(tyRef, nextTypeId(c.idgen), owner) let obj = createEnvObj(c.graph, c.idgen, owner, info) rawAddSon(result, obj) c.ownerToType[owner.id] = result @@ -338,7 +338,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; proc asOwnedRef(c: var DetectionPass; t: PType): PType = if optOwnedRefs in c.graph.config.globalOptions: assert t.kind == tyRef - result = newType(tyOwned, nextId(c.idgen), t.owner) + result = newType(tyOwned, nextTypeId(c.idgen), t.owner) result.flags.incl tfHasOwned result.rawAddSon t else: @@ -347,7 +347,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType = proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = var r = c.getEnvTypeForOwner(owner, info) - result = newType(tyPtr, nextId(c.idgen), owner) + result = newType(tyPtr, nextTypeId(c.idgen), owner) rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr})) proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = @@ -375,7 +375,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags: localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor") else: - let result = newSym(skField, upIdent, nextId(c.idgen), obj.owner, obj.owner.info) + let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info) result.typ = fieldType when false: if c.graph.config.selectedGC == gcDestructors: @@ -413,7 +413,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner let t = c.getEnvTypeForOwner(owner, info) if cp == nil: - cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextId(c.idgen), fn, fn.info) + cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info) incl(cp.flags, sfFromGeneric) cp.typ = t addHiddenParam(fn, cp) @@ -539,7 +539,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = result = n proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode = - var v = newSym(skVar, getIdent(cache, envName), nextId(idgen), owner, info) + var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = typ result = newSymNode(v) @@ -563,7 +563,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass; result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen) c.envVars[owner.id] = result if optOwnedRefs in d.graph.config.globalOptions: - var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextId d.idgen, owner, info) + var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType c.unownedEnvVars[owner.id] = newSymNode(v) @@ -647,7 +647,7 @@ proc closureCreationForIter(iter: PNode; d: var DetectionPass; c: var LiftingPass): PNode = result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ) let owner = iter.sym.skipGenericOwner - var v = newSym(skVar, getIdent(d.graph.cache, envName), nextId(d.idgen), owner, iter.info) + var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info) incl(v.flags, sfShadowed) v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ) var vnode: PNode @@ -937,7 +937,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): let iter = op.sym let hp = getHiddenParam(g, iter) - env = newSym(skLet, iter.name, nextId(idgen), owner, body.info) + env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info) env.typ = hp.typ env.flags = hp.flags diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 512fb6190..5ffa25e53 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -222,7 +222,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = # for every field (dependent on dest.kind): # `=` dest.field, src.field # =destroy(blob) - var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextId c.idgen, c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) temp.typ = x.typ incl(temp.flags, sfFromGeneric) var v = newNodeI(nkVarSection, c.info) @@ -317,7 +317,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; if optSeqDestructors in c.g.config.globalOptions: var op = field let destructorOverriden = destructorOverriden(t) - if op != nil and op != c.fn and + if op != nil and op != c.fn and (sfOverriden in op.flags or destructorOverriden): if sfError in op.flags: incl c.fn.flags, sfError @@ -412,7 +412,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = result = true proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = - var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextId(c.idgen), c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info) temp.typ = getSysType(c.g, body.info, tyInt) incl(temp.flags, sfFromGeneric) @@ -422,7 +422,7 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = body.add v proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode = - var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextId(c.idgen), c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info) temp.typ = value.typ incl(temp.flags, sfFromGeneric) @@ -899,17 +899,17 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp info: TLineInfo; idgen: IdGenerator): PSym = let procname = getIdent(g.cache, AttachedOpToStr[kind]) - result = newSym(skProc, procname, nextId(idgen), owner, info) - let dest = newSym(skParam, getIdent(g.cache, "dest"), nextId(idgen), result, info) + result = newSym(skProc, procname, nextSymId(idgen), owner, info) + let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(idgen), result, info) let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), - nextId(idgen), result, info) + nextSymId(idgen), result, info) dest.typ = makeVarType(typ.owner, typ, idgen) if kind == attachedTrace: src.typ = getSysType(g, info, tyPointer) else: src.typ = typ - result.typ = newProcType(info, nextId(idgen), owner) + result.typ = newProcType(info, nextTypeId(idgen), owner) result.typ.addParam dest if kind notin {attachedDestructor, attachedDispose}: result.typ.addParam src @@ -917,7 +917,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp if kind == attachedAsgn and g.config.selectedGC == gcOrc and cyclicType(typ.skipTypes(abstractInst)): let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), - nextId(idgen), result, info) + nextSymId(idgen), result, info) cycleParam.typ = getSysType(g, info, tyBool) result.typ.addParam cycleParam @@ -983,7 +983,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, a.addMemReset = true let discrimantDest = result.typ.n[1].sym - let dst = newSym(skVar, getIdent(g.cache, "dest"), nextId(idgen), result, info) + let dst = newSym(skVar, getIdent(g.cache, "dest"), nextSymId(idgen), result, info) dst.typ = makePtrType(typ.owner, typ, idgen) let dstSym = newSymNode(dst) let d = newDeref(dstSym) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index fba032c1e..3c0aabe9a 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -227,7 +227,7 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(c, m) else: getIdent(c.cache, "err:" & renderTree(m)) - result = newSym(skError, ident, nextId(c.idgen), getCurrOwner(c), n.info, {}) + result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {}) result.typ = errorType(c) incl(result.flags, sfDiscardable) # pretend it's from the top level scope to prevent cascading errors: diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index e9e704075..37405d8d9 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -71,7 +71,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextId(idgen), + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -91,7 +91,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P ## freely, multiple times. This is frequently required and such a builtin would also be ## handy to have in macros.nim. The value that can be reused is 'result.lastSon'! result = newNodeIT(nkStmtListExpr, value.info, value.typ) - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextId(idgen), + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -117,7 +117,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(g.cache, "_"), nextId(idgen), owner, value.info, owner.options) + var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options) var v = newNodeI(nkLetSection, value.info) let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) @@ -135,7 +135,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = result = newNodeI(nkStmtList, n.info) # note: cannot use 'skTemp' here cause we really need the copy for the VM :-( - var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextId(idgen), owner, n.info, owner.options) + var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options) temp.typ = n[1].typ incl(temp.flags, sfFromGeneric) incl(temp.flags, sfGenSym) @@ -154,7 +154,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod result.add newFastAsgnStmt(n[2], tempAsNode) proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType = - result = newType(tyObject, nextId(idgen), owner) + result = newType(tyObject, nextTypeId(idgen), owner) if final: rawAddSon(result, nil) incl result.flags, tfFinal @@ -162,7 +162,7 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s), - nextId(idgen), + nextSymId(idgen), owner, info, owner.options) incl s.flags, sfAnon s.typ = result @@ -225,7 +225,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) = # because of 'gensym' support, we have to mangle the name with its ID. # This is hacky but the clean solution is much more complex than it looks. var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), - nextId(idgen), s.owner, s.info, s.options) + nextSymId(idgen), s.owner, s.info, s.options) field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) field.typ = t @@ -239,7 +239,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) = proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} = result = lookupInRecord(obj.n, s.itemId) if result == nil: - var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextId(idgen), + var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen), s.owner, s.info, s.options) field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) @@ -326,7 +326,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode = proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode = result = newNodeI(nkAddr, n.info, 1) result[0] = n - result.typ = newType(typeKind, nextId(idgen), n.typ.owner) + result.typ = newType(typeKind, nextTypeId(idgen), n.typ.owner) result.typ.rawAddSon(n.typ) proc genDeref*(n: PNode; k = nkHiddenDeref): PNode = diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 71003371e..d700ab9a7 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -21,7 +21,7 @@ proc registerSysType*(g: ModuleGraph; t: PType) = if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType = - result = newType(kind, nextId(g.idgen), g.systemModule) + result = newType(kind, nextTypeId(g.idgen), g.systemModule) result.size = size result.align = size.int16 @@ -29,8 +29,8 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = result = strTableGet(g.systemModule.tab, getIdent(g.cache, name)) if result == nil: localError(g.config, info, "system module needs: " & name) - result = newSym(skError, getIdent(g.cache, name), nextId(g.idgen), g.systemModule, g.systemModule.info, {}) - result.typ = newType(tyError, nextId(g.idgen), g.systemModule) + result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) + result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) if result.kind == skAlias: result = result.owner proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = @@ -45,8 +45,8 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy r = nextIdentIter(ti, g.systemModule.tab) if result != nil: return result localError(g.config, info, "system module needs: " & name) - result = newSym(skError, id, nextId(g.idgen), g.systemModule, g.systemModule.info, {}) - result.typ = newType(tyError, nextId(g.idgen), g.systemModule) + result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) + result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType = result = getSysSym(g, info, name).typ @@ -101,12 +101,12 @@ proc getIntLitType*(g: ModuleGraph; literal: PNode): PType = result = g.intTypeCache[value.int] if result == nil: let ti = getSysType(g, literal.info, tyInt) - result = copyType(ti, nextId(g.idgen), ti.owner) + result = copyType(ti, nextTypeId(g.idgen), ti.owner) result.n = literal g.intTypeCache[value.int] = result else: let ti = getSysType(g, literal.info, tyInt) - result = copyType(ti, nextId(g.idgen), ti.owner) + result = copyType(ti, nextTypeId(g.idgen), ti.owner) result.n = literal proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType = @@ -116,7 +116,7 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType = proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} = if t.n != nil and t.kind in {tyInt, tyFloat}: - result = copyType(t, nextId(id), t.owner) + result = copyType(t, nextTypeId(id), t.owner) result.n = nil else: result = t diff --git a/compiler/main.nim b/compiler/main.nim index c94c4323f..868198268 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -19,7 +19,7 @@ import cgen, json, nversion, platform, nimconf, passaux, depends, vm, modules, - modulegraphs, tables, rod, lineinfos, pathutils, vmprofiler + modulegraphs, tables, lineinfos, pathutils, vmprofiler when not defined(leanCompiler): import jsgen, docgen, docgen2 @@ -137,7 +137,7 @@ proc commandInteractive(graph: ModuleGraph) = else: var m = graph.makeStdinModule() incl(m.flags, sfMainModule) - var idgen = IdGenerator(module: m.itemId.module, item: m.itemId.item) + var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config)) processModule(graph, m, idgen, s) @@ -165,7 +165,6 @@ proc mainCommand*(graph: ModuleGraph) = let conf = graph.config let cache = graph.cache - setupModuleCache(graph) # In "nim serve" scenario, each command must reset the registered passes clearPasses(graph) conf.lastCmdTime = epochTime() diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index e3c54eeae..5544668cc 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -9,7 +9,7 @@ ## This module implements the module graph data structure. The module graph ## represents a complete Nim project. Single modules can either be kept in RAM -## or stored in a Sqlite database. +## or stored in a rod-file. ## ## The caching of modules is critical for 'nimsuggest' and is tricky to get ## right. If module E is being edited, we need autocompletion (and type @@ -26,7 +26,7 @@ ## import ast, intsets, tables, options, lineinfos, hashes, idents, - incremental, btrees, md5 + btrees, md5 # import ic / packed_ast @@ -67,7 +67,6 @@ type intTypeCache*: array[-5..64, PType] opContains*, opNot*: PSym emptyNode*: PNode - incr*: IncrementalCtx canonTypes*: Table[SigHash, PType] symBodyHashes*: Table[int, SigHash] # symId to digest mapping importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.} @@ -176,7 +175,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = g.doStopCompile != nil and g.doStopCompile() proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = - result = newSym(skProc, getIdent(g.cache, name), nextId(g.idgen), nil, unknownLineInfo, {}) + result = newSym(skProc, getIdent(g.cache, name), nextSymId(g.idgen), nil, unknownLineInfo, {}) result.magic = m result.flags = {sfNeverRaises} @@ -190,7 +189,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) = proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result = ModuleGraph() - result.idgen = IdGenerator(module: -1'i32, item: 0'i32) + result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32) initStrTable(result.packageSyms) result.deps = initIntSet() result.importDeps = initTable[FileIndex, seq[FileIndex]]() @@ -206,7 +205,6 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.opNot = createMagic(result, "not", mNot) result.opContains = createMagic(result, "contains", mInSet) result.emptyNode = newNode(nkEmpty) - init(result.incr) result.recordStmt = proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.} = discard result.cacheSeqs = initTable[string, PNode]() @@ -235,7 +233,6 @@ proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = assert m.position == m.info.fileIndex.int32 - addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false) if g.suggestMode: g.deps.incl m.position.dependsOn(dep.int) # we compute the transitive closure later when querying the graph lazily. @@ -243,7 +240,6 @@ proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = #invalidTransitiveClosure = true proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) = - addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true) discard hasKeyOrPut(g.inclToMod, includeFile, module) proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = diff --git a/compiler/modules.nim b/compiler/modules.nim index 132f3788d..a8a9c4df8 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -11,7 +11,7 @@ import ast, astalgo, magicsys, msgs, options, - idents, lexer, passes, syntaxes, llstream, modulegraphs, rod, + idents, lexer, passes, syntaxes, llstream, modulegraphs, lineinfos, pathutils, tables proc resetSystemArtifacts*(g: ModuleGraph) = @@ -93,8 +93,10 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P discard processModule(graph, result, idGeneratorFromModule(result), s) if result == nil: let filename = AbsoluteFile toFullPath(graph.config, fileIdx) - result = loadModuleSym(graph, fileIdx, filename) - if result == nil: + when false: + # XXX entry point for module loading from the rod file + result = loadModuleSym(graph, fileIdx, filename) + when true: result = newModule(graph, fileIdx) result.flags.incl flags registerModule(graph, result) diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 23f403589..d0ef45d04 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -11,9 +11,9 @@ import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, iden import sequtils, strutils, std / sets # IMPORTANT: notes not up to date, i'll update this comment again -# +# # notes: -# +# # Env: int => nilability # a = b # nilability a <- nilability b @@ -111,7 +111,7 @@ type Symbol = distinct int ## the index of an expression in the pre-indexed sequence of those - ExprIndex = distinct int16 + ExprIndex = distinct int16 ## the set index SetIndex = distinct int @@ -131,7 +131,7 @@ type ## the context for the checker: an instance for each procedure NilCheckerContext = ref object # abstractTime: AbstractTime - # partitions: Partitions + # partitions: Partitions # symbolGraphs: Table[Symbol, ] symbolIndices: Table[Symbol, ExprIndex] ## index for each symbol expressions: SeqOfDistinct[ExprIndex, PNode] ## a sequence of pre-indexed expressions @@ -360,7 +360,7 @@ func `$`(a: Symbol): string = $(a.int) template isConstBracket(n: PNode): bool = - n.kind == nkBracketExpr and n[1].kind in nkLiterals + n.kind == nkBracketExpr and n[1].kind in nkLiterals proc index(ctx: NilCheckerContext, n: PNode): ExprIndex = # echo "n ", n, " ", n.kind @@ -373,7 +373,7 @@ proc index(ctx: NilCheckerContext, n: PNode): ExprIndex = #echo n.kind # internalError(ctx.config, n.info, "expected " & $a & " " & $n & " to have a index") return noExprIndex - # + # #ctx.symbolIndices[symbol(n)] @@ -384,7 +384,7 @@ proc aliasSet(ctx: NilCheckerContext, map: NilMap, index: ExprIndex): IntSet = result = map.sets[map.setIndices[index]] - + proc store(map: NilMap, ctx: NilCheckerContext, index: ExprIndex, value: Nilability, kind: TransitionKind, info: TLineInfo, node: PNode = nil) = if index == noExprIndex: return @@ -414,7 +414,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) = var targetSet = map.sets[targetSetIndex] if targetSet.len > 1: var other: ExprIndex - + for element in targetSet: if element.ExprIndex != targetIndex: other = element.ExprIndex @@ -440,7 +440,7 @@ proc move(ctx: NilCheckerContext, map: NilMap, target: PNode, assigned: PNode) = #echo "move ", target, " ", assigned var targetIndex = ctx.index(target) var assignedIndex: ExprIndex - var targetSetIndex = map.setIndices[targetIndex] + var targetSetIndex = map.setIndices[targetIndex] var assignedSetIndex: SetIndex if assigned.kind == nkSym: assignedIndex = ctx.index(assigned) @@ -497,12 +497,12 @@ proc checkCall(n, ctx, map): Check = result.map = map for i, child in n: discard check(child, ctx, map) - + if i > 0: # var args make a new map with MaybeNil for our node # as it might have been mutated # TODO similar for normal refs and fields: find dependent exprs: brackets - + if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ[0].kind == tyRef: if not isNew: result.map = newNilMap(map) @@ -526,7 +526,7 @@ proc checkCall(n, ctx, map): Check = isNew = true moveOutDependants(ctx, result.map, child) storeDependants(ctx, result.map, child, MaybeNil) - + if n[0].kind == nkSym and n[0].sym.magic == mNew: # new hidden deref? var value = if n[1].kind == nkHiddenDeref: n[1][0] else: n[1] @@ -552,7 +552,7 @@ template event(b: History): string = of TSafe: "it is safe here as it returns false for isNil" of TPotentialAlias: "it might be changed directly or through an alias" of TDependant: "it might be changed because its base might be changed" - + proc derefWarning(n, ctx, map; kind: Nilability) = ## a warning for potentially unsafe dereference if n.info in ctx.warningLocations: @@ -587,14 +587,14 @@ proc handleNilability(check: Check; n, ctx, map) = else: when defined(nilDebugInfo): message(ctx.config, n.info, hintUser, "can deref " & $n) - + proc checkDeref(n, ctx, map): Check = ## check dereference: deref n should be ok only if n is Safe result = check(n[0], ctx, map) - + handleNilability(result, n[0], ctx, map) - + proc checkRefExpr(n, ctx; check: Check): Check = ## check ref expressions: TODO not sure when this happens result = check @@ -625,7 +625,7 @@ proc checkBracketExpr(n, ctx, map): Check = result = check(n[1], ctx, result.map) result = checkRefExpr(n, ctx, result) # echo n, " ", result.nilability - + template union(l: Nilability, r: Nilability): Nilability = ## unify two states @@ -654,7 +654,7 @@ proc findCommonParent(l: NilMap, r: NilMap): NilMap = result = l.parent while not result.isNil: var rparent = r.parent - while not rparent.isNil: + while not rparent.isNil: if result == rparent: return result rparent = rparent.parent @@ -666,17 +666,17 @@ proc union(ctx: NilCheckerContext, l: NilMap, r: NilMap): NilMap = ## what if they are from different parts of the same tree ## e.g. ## a -> b -> c - ## -> b1 + ## -> b1 ## common then? - ## + ## if l.isNil: return r elif r.isNil: return l - + let common = findCommonParent(l, r) result = newNilMap(common, ctx.expressions.len.int) - + for index, value in l: let h = history(r, index) let info = if h.len > 0: h[^1].info else: TLineInfo(line: 0) # assert h.len > 0 @@ -715,11 +715,11 @@ proc checkAsgn(target: PNode, assigned: PNode; ctx, map): Check = result = check(assigned, ctx, map) else: result = Check(nilability: typeNilability(target.typ), map: map) - + # we need to visit and check those, but we don't use the result for now # is it possible to somehow have another event happen here? discard check(target, ctx, map) - + if result.map.isNil: result.map = map if target.kind in {nkSym, nkDotExpr} or isConstBracket(target): @@ -738,8 +738,8 @@ proc checkAsgn(target: PNode, assigned: PNode; ctx, map): Check = if symbol(elementNode) in ctx.symbolIndices: var elementIndex = ctx.index(elementNode) result.map.store(ctx, elementIndex, value, TAssign, target.info, elementNode) - - + + proc checkReturn(n, ctx, map): Check = ## check return # return n same as result = n; return ? @@ -750,9 +750,9 @@ proc checkReturn(n, ctx, map): Check = proc checkIf(n, ctx, map): Check = ## check branches based on condition var mapIf: NilMap = map - + # first visit the condition - + # the structure is not If(Elif(Elif, Else), Else) # it is # If(Elif, Elif, Else) @@ -765,7 +765,7 @@ proc checkIf(n, ctx, map): Check = var afterLayer: NilMap # the result nilability for expressions var nilability = Safe - + for branch in n.sons: var branchConditionLayer = newNilMap(layerHistory) var branchLayer: NilMap @@ -779,7 +779,7 @@ proc checkIf(n, ctx, map): Check = else: branchLayer = layerHistory code = branch - + let branchCheck = checkBranch(code, ctx, branchLayer) # handles nil afterLayer -> returns branchCheck.map afterLayer = ctx.union(afterLayer, branchCheck.map) @@ -796,7 +796,7 @@ proc checkIf(n, ctx, map): Check = result.map = ctx.union(layerHistory, afterLayer) result.nilability = Safe # no expr? else: - # similar to else: because otherwise we are jumping out of + # similar to else: because otherwise we are jumping out of # the branch, so no union with the mapIf (we dont continue if the condition was true) # here it also doesn't matter for the parent branch what happened in the branch, e.g. assigning to nil # as if we continue there, we haven't entered the branch probably @@ -820,7 +820,7 @@ proc checkFor(n, ctx, map): Check = # echo namedMapDebugInfo(ctx, map) var check2 = check(n.sons[2], ctx, m) var map2 = check2.map - + result.map = ctx.union(map0, m) result.map = ctx.union(result.map, map2) result.nilability = Safe @@ -848,11 +848,11 @@ proc checkWhile(n, ctx, map): Check = var map1 = m.copyMap() var check2 = check(n.sons[1], ctx, m) var map2 = check2.map - + result.map = ctx.union(map0, map1) result.map = ctx.union(result.map, map2) result.nilability = Safe - + proc checkInfix(n, ctx, map): Check = ## check infix operators in condition ## a and b : map is based on a; next b @@ -882,7 +882,7 @@ proc checkInfix(n, ctx, map): Check = result.map = checkCondition(n[2], ctx, map, false, false) elif $n[1] == "false": result.map = checkCondition(n[2], ctx, map, true, false) - + if result.map.isNil: result.map = map else: @@ -906,24 +906,24 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode = else: "" var cache = newIdentCache() - var op = newSym(skVar, cache.getIdent(name), nextId ctx.idgen, nil, r.info) + var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info) op.magic = magic result = nkInfix.newTree( newSymNode(op, r.info), l, r) - result.typ = newType(tyBool, nextId ctx.idgen, nil) + result.typ = newType(tyBool, nextTypeId ctx.idgen, nil) proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode = var cache = newIdentCache() - var op = newSym(skVar, cache.getIdent("not"), nextId ctx.idgen, nil, node.info) + var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info) op.magic = mNot result = nkPrefix.newTree( newSymNode(op, node.info), node) - result.typ = newType(tyBool, nextId ctx.idgen, nil) + result.typ = newType(tyBool, nextTypeId ctx.idgen, nil) proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode = infix(ctx, l, r, mEqRef) @@ -1016,7 +1016,7 @@ proc checkTry(n, ctx, map): Check = let tryCheck = check(n[0], ctx, currentMap) newMap = ctx.union(currentMap, tryCheck.map) canRaise = n[0].canRaise - + var afterTryMap = newMap for a, branch in n: if a > 0: @@ -1026,7 +1026,7 @@ proc checkTry(n, ctx, map): Check = let childCheck = check(branch[0], ctx, newMap) newMap = ctx.union(newMap, childCheck.map) hasFinally = true - of nkExceptBranch: + of nkExceptBranch: if canRaise: let childCheck = check(branch[^1], ctx, newMap) newMap = ctx.union(newMap, childCheck.map) @@ -1069,7 +1069,7 @@ proc reverse(kind: TransitionKind): TransitionKind = of TNil: TSafe of TSafe: TNil of TPotentialAlias: TPotentialAlias - else: + else: kind # raise newException(ValueError, "expected TNil or TSafe") @@ -1079,41 +1079,41 @@ proc reverseDirect(map: NilMap): NilMap = # because conditions should've stored their changes there # b: Safe (not b.isNil) # b: Parent Parent - # b: Nil (b.isNil) + # b: Nil (b.isNil) # layer block # [ Parent ] [ Parent ] - # if -> if state + # if -> if state # layer -> reverse # older older0 new # older new # [ b Nil ] [ Parent ] # elif # [ b Nil, c Nil] [ Parent ] - # + # - # if b.isNil: + # if b.isNil: # # [ b Safe] # c = A() # Safe - # elif not b.isNil: + # elif not b.isNil: # # [ b Safe ] + [b Nil] MaybeNil Unreachable # # Unreachable defer can't deref b, it is unreachable # discard # else: - # b + # b - -# if + +# if # if: we just pass the map with a new layer for its block # elif: we just pass the original map but with a new layer is the reverse of the previous popped layer (?) - # elif: + # elif: # else: we just pass the original map but with a new layer which is initialized as the reverse of the # top layer of else # else: - # + # # [ b MaybeNil ] [b Parent] [b Parent] [b Safe] [b Nil] [] # Safe # c == 1 @@ -1181,7 +1181,7 @@ proc checkResult(n, ctx, map) = of Unreachable: message(ctx.config, n.info, warnStrictNotNil, "return value is unreachable") of Safe, Parent: - discard + discard proc checkBranch(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = result = check(n, ctx, map) @@ -1191,7 +1191,7 @@ proc checkBranch(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = assert not map.isNil - + # echo "check n ", n, " ", n.kind # echo "map ", namedMapDebugInfo(ctx, map) case n.kind: @@ -1218,7 +1218,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = if n.kind in {nkObjConstr, nkTupleConstr}: # TODO deeper nested elements? # A(field: B()) # - # field: Safe -> + # field: Safe -> var elements: seq[(PNode, Nilability)] for i, child in n: result = check(child, ctx, result.map) @@ -1230,7 +1230,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = else: for child in n: result = check(child, ctx, result.map) - + of nkDotExpr: result = checkDotExpr(n, ctx, map) of nkDerefExpr, nkHiddenDeref: @@ -1261,7 +1261,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: - + discard "don't follow this : same as varpartitions" result = Check(nilability: Nil, map: map) else: @@ -1275,17 +1275,17 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = result = Check(nilability: Nil, map: elementCheck.map) - - + + proc typeNilability(typ: PType): Nilability = assert not typ.isNil # echo "typeNilability ", $typ.flags, " ", $typ.kind result = if tfNotNil in typ.flags: Safe elif typ.kind in {tyRef, tyCString, tyPtr, tyPointer}: - # + # # tyVar ? tyVarargs ? tySink ? tyLent ? - # TODO spec? tests? + # TODO spec? tests? MaybeNil else: Safe @@ -1354,7 +1354,7 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = var context = NilCheckerContext(config: conf, idgen: idgen) context.preVisit(s, body, conf) var map = newNilMap(nil, context.symbolIndices.len) - + for i, child in s.typ.n.sons: if i > 0: if child.kind != nkSym: @@ -1362,7 +1362,7 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = map.store(context, context.index(child), typeNilability(child.typ), TArg, child.info, child) map.store(context, resultExprIndex, if not s.typ[0].isNil and s.typ[0].kind == tyRef: Nil else: Safe, TResult, s.ast.info) - + # echo "checking ", s.name.s, " ", filename let res = check(body, context, map) @@ -1374,7 +1374,7 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = res.map.store(context, resultExprIndex, Safe, TAssign, s.ast.info) # TODO check for nilability result - # (ANotNil, BNotNil) : + # (ANotNil, BNotNil) : # do we check on asgn nilability at all? if not s.typ[0].isNil and s.typ[0].kind == tyRef and tfNotNil in s.typ[0].flags: diff --git a/compiler/options.nim b/compiler/options.nim index 1de6d531a..4a013f8fc 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -722,6 +722,10 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, result = subdir / RelativeFile f.string.splitPath.tail #echo "completeGeneratedFilePath(", f, ") = ", result +proc toRodFile*(conf: ConfigRef; f: AbsoluteFile): AbsoluteFile = + result = changeFileExt(completeGeneratedFilePath(conf, + withPackageName(conf, f)), RodExt) + proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile = for it in conf.searchPaths: if suppressStdlib and it.string.startsWith(conf.libpath.string): diff --git a/compiler/passes.nim b/compiler/passes.nim index f266d2a6b..997a10cd8 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -13,7 +13,7 @@ import options, ast, llstream, msgs, idents, - syntaxes, modulegraphs, reorder, rod, + syntaxes, modulegraphs, reorder, lineinfos, pathutils type @@ -119,88 +119,65 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; s: PLLStream fileIdx = module.fileIdx prepareConfigNotes(graph, module) - if module.id < 0: - # new module caching mechanism: - for i in 0..') - -proc encodeType(g: ModuleGraph, t: PType, result: var string) = - if t == nil: - # nil nodes have to be stored too: - result.add("[]") - return - # we need no surrounding [] here because the type is in a line of its own - if t.kind == tyForward: internalError(g.config, "encodeType: tyForward") - # for the new rodfile viewer we use a preceding [ so that the data section - # can easily be disambiguated: - result.add('[') - encodeVInt(ord(t.kind), result) - result.add('+') - encodeVInt(t.uniqueId, result) - if t.id != t.uniqueId: - result.add('+') - encodeVInt(t.id, result) - if t.n != nil: - encodeNode(g, unknownLineInfo, t.n, result) - if t.flags != {}: - result.add('$') - encodeVInt(cast[int32](t.flags), result) - if t.callConv != low(t.callConv): - result.add('?') - encodeVInt(ord(t.callConv), result) - if t.owner != nil: - result.add('*') - encodeVInt(t.owner.id, result) - pushSym(w, t.owner) - if t.sym != nil: - result.add('&') - encodeVInt(t.sym.id, result) - pushSym(w, t.sym) - if t.size != - 1: - result.add('/') - encodeVBiggestInt(t.size, result) - if t.align != 2: - result.add('=') - encodeVInt(t.align, result) - if t.lockLevel.ord != UnspecifiedLockLevel.ord: - result.add('\14') - encodeVInt(t.lockLevel.int16, result) - if t.paddingAtEnd != 0: - result.add('\15') - encodeVInt(t.paddingAtEnd, result) - for a in t.attachedOps: - result.add('\16') - if a == nil: - encodeVInt(-1, result) - else: - encodeVInt(a.id, result) - pushSym(w, a) - for i, s in items(t.methods): - result.add('\19') - encodeVInt(i, result) - result.add('\20') - encodeVInt(s.id, result) - pushSym(w, s) - encodeLoc(g, t.loc, result) - if t.typeInst != nil: - result.add('\21') - encodeVInt(t.typeInst.uniqueId, result) - pushType(w, t.typeInst) - for i in 0.. 100_000: - doAssert false, "loop never ends!" - if w.sstack.len > 0: - let s = w.sstack.pop() - when false: - echo "popped ", s.name.s, " ", s.id - storeSym(g, s) - elif w.tstack.len > 0: - let t = w.tstack.pop() - storeType(g, t) - when false: - echo "popped type ", typeToString(t), " ", t.uniqueId - else: - break - inc i - -proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) = - if g.config.symbolFiles == disabledSf: return - var buf = newStringOfCap(160) - encodeNode(g, module.info, n, buf) - db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)", - abs(module.id), module.offset, buf) - inc module.offset - transitiveClosure(g) - -proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) = - storeNode(g, module, n) - -proc storeFilename(g: ModuleGraph; fullpath: AbsoluteFile; fileIdx: FileIndex) = - let id = db.getValue(sql"select id from filenames where fullpath = ?", fullpath.string) - if id.len == 0: - let fullhash = hashFileCached(g.config, fileIdx, fullpath) - db.exec(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)", - int(fileIdx), fullpath.string, fullhash) - -proc storeRemaining*(g: ModuleGraph; module: PSym) = - if g.config.symbolFiles == disabledSf: return - var stillForwarded: seq[PSym] = @[] - for s in w.forwardedSyms: - if sfForward notin s.flags: - storeSym(g, s) - else: - stillForwarded.add s - swap w.forwardedSyms, stillForwarded - transitiveClosure(g) - var nimid = 0 - for x in items(g.config.m.fileInfos): - storeFilename(g, x.fullPath, FileIndex(nimid)) - inc nimid - -# ---------------- decoder ----------------------------------- - -type - BlobReader = object - s: string - pos: int - -using - b: var BlobReader - g: ModuleGraph - -proc loadSym(g; id: int, info: TLineInfo): PSym -proc loadType(g; id: int, info: TLineInfo): PType - -proc decodeLineInfo(g; b; info: var TLineInfo) = - if b.s[b.pos] == '?': - inc(b.pos) - if b.s[b.pos] == ',': info.col = -1'i16 - else: info.col = int16(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == ',': - inc(b.pos) - if b.s[b.pos] == ',': info.line = 0'u16 - else: info.line = uint16(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == ',': - inc(b.pos) - #info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos)) - info.fileIndex = FileIndex decodeVInt(b.s, b.pos) - -proc skipNode(b) = - # ')' itself cannot be part of a string literal so that this is correct. - assert b.s[b.pos] == '(' - var par = 0 - var pos = b.pos+1 - while true: - case b.s[pos] - of ')': - if par == 0: break - dec par - of '(': inc par - else: discard - inc pos - b.pos = pos+1 # skip ')' - -proc decodeNodeLazyBody(g; b; fInfo: TLineInfo, - belongsTo: PSym): PNode = - result = nil - if b.s[b.pos] == '(': - inc(b.pos) - if b.s[b.pos] == ')': - inc(b.pos) - return # nil node - result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo) - decodeLineInfo(g, b, result.info) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '^': - inc(b.pos) - var id = decodeVInt(b.s, b.pos) - result.typ = loadType(g, id, result.info) - case result.kind - of nkCharLit..nkUInt64Lit: - if b.s[b.pos] == '!': - inc(b.pos) - result.intVal = decodeVBiggestInt(b.s, b.pos) - of nkFloatLit..nkFloat64Lit: - if b.s[b.pos] == '!': - inc(b.pos) - var fl = decodeStr(b.s, b.pos) - result.floatVal = parseFloat(fl) - of nkStrLit..nkTripleStrLit: - if b.s[b.pos] == '!': - inc(b.pos) - result.strVal = decodeStr(b.s, b.pos) - else: - result.strVal = "" - of nkIdent: - if b.s[b.pos] == '!': - inc(b.pos) - var fl = decodeStr(b.s, b.pos) - result.ident = g.cache.getIdent(fl) - else: - internalError(g.config, result.info, "decodeNode: nkIdent") - of nkSym: - if b.s[b.pos] == '!': - inc(b.pos) - var id = decodeVInt(b.s, b.pos) - result.sym = loadSym(g, id, result.info) - else: - internalError(g.config, result.info, "decodeNode: nkSym") - else: - var i = 0 - while b.s[b.pos] != ')': - when false: - if belongsTo != nil and i == bodyPos: - addSonNilAllowed(result, nil) - belongsTo.offset = b.pos - skipNode(b) - else: - discard - addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil)) - inc i - if b.s[b.pos] == ')': inc(b.pos) - else: internalError(g.config, result.info, "decodeNode: ')' missing") - else: - internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos) - -proc decodeNode(g; b; fInfo: TLineInfo): PNode = - result = decodeNodeLazyBody(g, b, fInfo, nil) - -proc decodeLoc(g; b; loc: var TLoc, info: TLineInfo) = - if b.s[b.pos] == '<': - inc(b.pos) - if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: - loc.k = TLocKind(decodeVInt(b.s, b.pos)) - else: - loc.k = low(loc.k) - if b.s[b.pos] == '*': - inc(b.pos) - loc.storage = TStorageLoc(decodeVInt(b.s, b.pos)) - else: - loc.storage = low(loc.storage) - if b.s[b.pos] == '$': - inc(b.pos) - loc.flags = cast[TLocFlags](int32(decodeVInt(b.s, b.pos))) - else: - loc.flags = {} - if b.s[b.pos] == '^': - inc(b.pos) - loc.lode = decodeNode(g, b, info) - # rrGetType(b, decodeVInt(b.s, b.pos), info) - else: - loc.lode = nil - if b.s[b.pos] == '!': - inc(b.pos) - loc.r = rope(decodeStr(b.s, b.pos)) - else: - loc.r = nil - if b.s[b.pos] == '>': inc(b.pos) - else: internalError(g.config, info, "decodeLoc " & b.s[b.pos]) - -proc loadBlob(g; query: SqlQuery; id: int): BlobReader = - let blob = db.getValue(query, id) - if blob.len == 0: - internalError(g.config, "symbolfiles: cannot find ID " & $ id) - result = BlobReader(pos: 0) - shallowCopy(result.s, blob) - # ensure we can read without index checks: - result.s.add '\0' - -proc loadType(g; id: int; info: TLineInfo): PType = - result = g.incr.r.types.getOrDefault(id) - if result != nil: return result - var b = loadBlob(g, sql"select data from types where nimid = ?", id) - - if b.s[b.pos] == '[': - inc(b.pos) - if b.s[b.pos] == ']': - inc(b.pos) - return # nil type - new(result) - result.kind = TTypeKind(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '+': - inc(b.pos) - result.uniqueId = decodeVInt(b.s, b.pos) - setId(result.uniqueId) - #if debugIds: registerID(result) - else: - internalError(g.config, info, "decodeType: no id") - if b.s[b.pos] == '+': - inc(b.pos) - result.id = decodeVInt(b.s, b.pos) - else: - result.id = result.uniqueId - # here this also avoids endless recursion for recursive type - g.incr.r.types.add(result.uniqueId, result) - if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '?': - inc(b.pos) - result.callConv = TCallingConvention(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '*': - inc(b.pos) - result.owner = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '&': - inc(b.pos) - result.sym = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '/': - inc(b.pos) - result.size = decodeVInt(b.s, b.pos) - else: - result.size = -1 - if b.s[b.pos] == '=': - inc(b.pos) - result.align = decodeVInt(b.s, b.pos).int16 - else: - result.align = 2 - - if b.s[b.pos] == '\14': - inc(b.pos) - result.lockLevel = decodeVInt(b.s, b.pos).TLockLevel - else: - result.lockLevel = UnspecifiedLockLevel - - if b.s[b.pos] == '\15': - inc(b.pos) - result.paddingAtEnd = decodeVInt(b.s, b.pos).int16 - - for a in low(result.attachedOps)..high(result.attachedOps): - if b.s[b.pos] == '\16': - inc(b.pos) - let id = decodeVInt(b.s, b.pos) - if id >= 0: - result.attachedOps[a] = loadSym(g, id, info) - - while b.s[b.pos] == '\19': - inc(b.pos) - let x = decodeVInt(b.s, b.pos) - doAssert b.s[b.pos] == '\20' - inc(b.pos) - let y = loadSym(g, decodeVInt(b.s, b.pos), info) - result.methods.add((x, y)) - decodeLoc(g, b, result.loc, info) - if b.s[b.pos] == '\21': - inc(b.pos) - let d = decodeVInt(b.s, b.pos) - result.typeInst = loadType(g, d, info) - while b.s[b.pos] == '^': - inc(b.pos) - if b.s[b.pos] == '(': - inc(b.pos) - if b.s[b.pos] == ')': inc(b.pos) - else: internalError(g.config, info, "decodeType ^(" & b.s[b.pos]) - rawAddSon(result, nil) - else: - let d = decodeVInt(b.s, b.pos) - result.sons.add loadType(g, d, info) - -proc decodeLib(g; b; info: TLineInfo): PLib = - result = nil - if b.s[b.pos] == '|': - new(result) - inc(b.pos) - result.kind = TLibKind(decodeVInt(b.s, b.pos)) - if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 1") - inc(b.pos) - result.name = rope(decodeStr(b.s, b.pos)) - if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 2") - inc(b.pos) - result.path = decodeNode(g, b, info) - -proc decodeInstantiations(g; b; info: TLineInfo; - s: var seq[PInstantiation]) = - while b.s[b.pos] == '\15': - inc(b.pos) - var ii: PInstantiation - new ii - ii.sym = loadSym(g, decodeVInt(b.s, b.pos), info) - ii.concreteTypes = @[] - while b.s[b.pos] == '\17': - inc(b.pos) - ii.concreteTypes.add loadType(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '\20': - inc(b.pos) - ii.compilesId = decodeVInt(b.s, b.pos) - s.add ii - -proc loadSymFromBlob(g; b; info: TLineInfo): PSym = - if b.s[b.pos] == '{': - inc(b.pos) - if b.s[b.pos] == '}': - inc(b.pos) - return # nil sym - var k = TSymKind(decodeVInt(b.s, b.pos)) - var id: int - if b.s[b.pos] == '+': - inc(b.pos) - id = decodeVInt(b.s, b.pos) - setId(id) - else: - internalError(g.config, info, "decodeSym: no id") - var ident: PIdent - if b.s[b.pos] == '&': - inc(b.pos) - ident = g.cache.getIdent(decodeStr(b.s, b.pos)) - else: - internalError(g.config, info, "decodeSym: no ident") - #echo "decoding: {", ident.s - result = PSym(id: id, kind: k, name: ident) - # read the rest of the symbol description: - g.incr.r.syms.add(result.id, result) - if b.s[b.pos] == '^': - inc(b.pos) - result.typ = loadType(g, decodeVInt(b.s, b.pos), info) - decodeLineInfo(g, b, result.info) - if b.s[b.pos] == '*': - inc(b.pos) - result.owner = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TSymFlags](decodeVBiggestInt(b.s, b.pos)) - if b.s[b.pos] == '@': - inc(b.pos) - result.magic = TMagic(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '!': - inc(b.pos) - result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '%': - inc(b.pos) - result.position = decodeVInt(b.s, b.pos) - if b.s[b.pos] == '`': - inc(b.pos) - result.offset = decodeVInt(b.s, b.pos) - else: - result.offset = -1 - decodeLoc(g, b, result.loc, result.info) - result.annex = decodeLib(g, b, info) - if b.s[b.pos] == '#': - inc(b.pos) - result.constraint = decodeNode(g, b, unknownLineInfo) - case result.kind - of skType, skGenericParam: - while b.s[b.pos] == '\14': - inc(b.pos) - result.typeInstCache.add loadType(g, decodeVInt(b.s, b.pos), result.info) - of routineKinds: - decodeInstantiations(g, b, result.info, result.procInstCache) - if b.s[b.pos] == '\16': - inc(b.pos) - result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '\24': - inc b.pos - result.transformedBody = decodeNode(g, b, result.info) - #result.transformedBody = nil - of skModule, skPackage: - decodeInstantiations(g, b, result.info, result.usedGenerics) - of skLet, skVar, skField, skForVar: - if b.s[b.pos] == '\18': - inc(b.pos) - result.guard = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '\19': - inc(b.pos) - result.bitsize = decodeVInt(b.s, b.pos).int16 - else: discard - - if b.s[b.pos] == '(': - #if result.kind in routineKinds: - # result.ast = nil - #else: - result.ast = decodeNode(g, b, result.info) - if sfCompilerProc in result.flags: - registerCompilerProc(g, result) - #echo "loading ", result.name.s - -proc loadSym(g; id: int; info: TLineInfo): PSym = - result = g.incr.r.syms.getOrDefault(id) - if result != nil: return result - var b = loadBlob(g, sql"select data from syms where nimid = ?", id) - result = loadSymFromBlob(g, b, info) - doAssert id == result.id, "symbol ID is not consistent!" - -proc registerModule*(g; module: PSym) = - g.incr.r.syms.add(abs module.id, module) - -proc loadModuleSymTab(g; module: PSym) = - ## goal: fill module.tab - g.incr.r.syms.add(module.id, module) - for row in db.fastRows(sql"select nimid, data from syms where module = ? and exported = 1", abs(module.id)): - let id = parseInt(row[0]) - var s = g.incr.r.syms.getOrDefault(id) - if s == nil: - var b = BlobReader(pos: 0) - shallowCopy(b.s, row[1]) - # ensure we can read without index checks: - b.s.add '\0' - s = loadSymFromBlob(g, b, module.info) - assert s != nil - if s.kind != skField: - strTableAdd(module.tab, s) - if sfSystemModule in module.flags: - g.systemModule = module - -proc replay(g: ModuleGraph; module: PSym; n: PNode) = - # XXX check if we need to replay nkStaticStmt here. - case n.kind - #of nkStaticStmt: - #evalStaticStmt(module, g, n[0], module) - #of nkVarSection, nkLetSection: - # nkVarSections are already covered by the vmgen which produces nkStaticStmt - of nkMethodDef: - methodDef(g, n[namePos].sym, fromCache=true) - of nkCommentStmt: - # pragmas are complex and can be user-overriden via templates. So - # instead of using the original ``nkPragma`` nodes, we rely on the - # fact that pragmas.nim was patched to produce specialized recorded - # statements for us in the form of ``nkCommentStmt`` with (key, value) - # pairs. Ordinary nkCommentStmt nodes never have children so this is - # not ambiguous. - # Fortunately only a tiny subset of the available pragmas need to - # be replayed here. This is always a subset of ``pragmas.stmtPragmas``. - if n.len >= 2: - internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit - case n[0].strVal - of "hint": message(g.config, n.info, hintUser, n[1].strVal) - of "warning": message(g.config, n.info, warnUser, n[1].strVal) - of "error": localError(g.config, n.info, errUser, n[1].strVal) - of "compile": - internalAssert g.config, n.len == 4 and n[2].kind == nkStrLit - let cname = AbsoluteFile n[1].strVal - var cf = Cfile(nimname: splitFile(cname).name, cname: cname, - obj: AbsoluteFile n[2].strVal, - flags: {CfileFlag.External}, - customArgs: n[3].strVal) - extccomp.addExternalFileToCompile(g.config, cf) - of "link": - extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal) - of "passl": - extccomp.addLinkOption(g.config, n[1].strVal) - of "passc": - extccomp.addCompileOption(g.config, n[1].strVal) - of "localpassc": - extccomp.addLocalCompileOption(g.config, n[1].strVal, toFullPathConsiderDirty(g.config, module.info.fileIndex)) - of "cppdefine": - options.cppDefine(g.config, n[1].strVal) - of "inc": - let destKey = n[1].strVal - let by = n[2].intVal - let v = getOrDefault(g.cacheCounters, destKey) - g.cacheCounters[destKey] = v+by - of "put": - let destKey = n[1].strVal - let key = n[2].strVal - let val = n[3] - if not contains(g.cacheTables, destKey): - g.cacheTables[destKey] = initBTree[string, PNode]() - if not contains(g.cacheTables[destKey], key): - g.cacheTables[destKey].add(key, val) - else: - internalError(g.config, n.info, "key already exists: " & key) - of "incl": - let destKey = n[1].strVal - let val = n[2] - if not contains(g.cacheSeqs, destKey): - g.cacheSeqs[destKey] = newTree(nkStmtList, val) - else: - block search: - for existing in g.cacheSeqs[destKey]: - if exprStructuralEquivalent(existing, val, strictSymEquality=true): - break search - g.cacheSeqs[destKey].add val - of "add": - let destKey = n[1].strVal - let val = n[2] - if not contains(g.cacheSeqs, destKey): - g.cacheSeqs[destKey] = newTree(nkStmtList, val) - else: - g.cacheSeqs[destKey].add val - else: - internalAssert g.config, false - of nkImportStmt: - for x in n: - internalAssert g.config, x.kind == nkSym - let modpath = AbsoluteFile toFullPath(g.config, x.sym.info) - let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, modpath)) - internalAssert g.config, imported.id < 0 - of nkStmtList, nkStmtListExpr: - for x in n: replay(g, module, x) - of nkExportStmt: - for x in n: - doAssert x.kind == nkSym - strTableAdd(module.tab, x.sym) - else: discard "nothing to do for this node" - -proc loadNode*(g: ModuleGraph; module: PSym): PNode = - loadModuleSymTab(g, module) - result = newNodeI(nkStmtList, module.info) - for row in db.rows(sql"select data from toplevelstmts where module = ? order by position asc", - abs module.id): - var b = BlobReader(pos: 0) - # ensure we can read without index checks: - b.s = row[0] & '\0' - result.add decodeNode(g, b, module.info) - db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId) - replay(g, module, result) - -proc setupModuleCache*(g: ModuleGraph) = - # historical note: there used to be a `rodfiles` dir with special tests - # for incremental compilation via symbol files. This was likely replaced by ic. - if g.config.symbolFiles == disabledSf: return - g.recordStmt = recordStmt - let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db" - if g.config.symbolFiles == writeOnlySf: - removeFile(dbfile) - createDir getNimcacheDir(g.config) - let ec = encodeConfig(g) - if not fileExists(dbfile): - db = open(connection=string dbfile, user="nim", password="", - database="nim") - createDb(db) - db.exec(sql"insert into config(config) values (?)", ec) - else: - db = open(connection=string dbfile, user="nim", password="", - database="nim") - let oldConfig = db.getValue(sql"select config from config") - g.incr.configChanged = oldConfig != ec - # ensure the filename IDs stay consistent: - for row in db.rows(sql"select fullpath, nimid from filenames order by nimid"): - let id = fileInfoIdx(g.config, AbsoluteFile row[0]) - doAssert id.int == parseInt(row[1]) - db.exec(sql"update config set config = ?", ec) - db.exec(sql"pragma journal_mode=off") - # This MUST be turned off, otherwise it's way too slow even for testing purposes: - db.exec(sql"pragma SYNCHRONOUS=off") - db.exec(sql"pragma LOCKING_MODE=exclusive") - let lastId = db.getValue(sql"select max(idgen) from controlblock") - if lastId.len > 0: - idgen.setId(parseInt lastId) diff --git a/compiler/sem.nim b/compiler/sem.nim index e95f3799c..d5ae5a21d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,7 +16,7 @@ import procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, plugins/active, rod, lineinfos, strtabs, int128, + lowerings, plugins/active, lineinfos, strtabs, int128, isolation_check, typeallowed from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward @@ -124,8 +124,8 @@ proc commonType*(c: PContext; x, y: PType): PType = # turn any concrete typedesc into the abstract typedesc type if a.len == 0: result = a else: - result = newType(tyTypeDesc, nextId(c.idgen), a.owner) - rawAddSon(result, newType(tyNone, nextId(c.idgen), a.owner)) + result = newType(tyTypeDesc, nextTypeId(c.idgen), a.owner) + rawAddSon(result, newType(tyNone, nextTypeId(c.idgen), a.owner)) elif b.kind in {tyArray, tySet, tySequence} and a.kind == b.kind: # check for seq[empty] vs. seq[int] @@ -137,7 +137,7 @@ proc commonType*(c: PContext; x, y: PType): PType = let aEmpty = isEmptyContainer(a[i]) let bEmpty = isEmptyContainer(b[i]) if aEmpty != bEmpty: - if nt.isNil: nt = copyType(a, nextId(c.idgen), a.owner) + if nt.isNil: nt = copyType(a, nextTypeId(c.idgen), a.owner) nt[i] = if aEmpty: b[i] else: a[i] if not nt.isNil: result = nt #elif b[idx].kind == tyEmpty: return x @@ -176,7 +176,7 @@ proc commonType*(c: PContext; x, y: PType): PType = # ill-formed AST, no need for additional tyRef/tyPtr if k != tyNone and x.kind != tyGenericInst: let r = result - result = newType(k, nextId(c.idgen), r.owner) + result = newType(k, nextTypeId(c.idgen), r.owner) result.addSonSkipIntLit(r, c.idgen) proc endsInNoReturn(n: PNode): bool = @@ -193,7 +193,7 @@ proc commonType*(c: PContext; x: PType, y: PNode): PType = commonType(c, x, y.typ) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(c, n), nextId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) when defined(nimsuggest): suggestDecl(c, n, result) @@ -216,7 +216,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # template; we must fix it here: see #909 result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(c, n), nextId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) when defined(nimsuggest): @@ -255,7 +255,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym = if t.sym != nil: return t.sym - result = newSym(skType, getIdent(c.cache, "AnonType"), nextId c.idgen, t.owner, info) + result = newSym(skType, getIdent(c.cache, "AnonType"), nextSymId c.idgen, t.owner, info) result.flags.incl sfAnon result.typ = t @@ -616,7 +616,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = else: result = newNodeI(nkEmpty, n.info) #if c.config.cmd == cmdIdeTools: findSuggest(c, n) - rod.storeNode(c.graph, c.module, result) + storeRodNode(c, result) proc reportUnusedModules(c: PContext) = for i in 0..high(c.unusedImports): @@ -638,7 +638,7 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = result.add(c.module.ast) popOwner(c) popProcCon(c) - storeRemaining(c.graph, c.module) + saveRodFile(c) const semPass* = makePass(myOpen, myProcess, myClose, isFrontend = true) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index a6660e14c..da38a6fc2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -11,7 +11,9 @@ import intsets, options, ast, astalgo, msgs, idents, renderer, - magicsys, vmdef, modulegraphs, lineinfos, sets + magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils + +import ic / to_packed_ast type TOptionEntry* = object # entries to put on a stack for pragma parsing @@ -77,9 +79,9 @@ type case mode*: ImportMode of importAll: discard of importSet: - imported*: IntSet + imported*: IntSet # of PIdent.id of importExcept: - exceptSet*: IntSet + exceptSet*: IntSet # of PIdent.id PContext* = ref TContext TContext* = object of TPassContext # a context represents the module @@ -140,6 +142,7 @@ type selfName*: PIdent cache*: IdentCache graph*: ModuleGraph + encoder*: PackedEncoder signatures*: TStrTable recursiveDep*: string suggestionsMade*: bool @@ -264,6 +267,16 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext = initStrTable(result.signatures) result.typesWithOps = @[] result.features = graph.config.features + if graph.config.symbolFiles != disabledSf: + initEncoder result.encoder, module, graph.config + +proc addIncludeFileDep*(c: PContext; f: FileIndex) = + if c.config.symbolFiles != disabledSf: + addIncludeFileDep(c.encoder, f) + +proc addImportFileDep*(c: PContext; f: FileIndex) = + if c.config.symbolFiles != disabledSf: + addImportFileDep(c.encoder, f) proc inclSym(sq: var seq[PSym], s: PSym) = for i in 0.. ord(high(TSymKind)): internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") - var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextId c.idgen, c.module.owner, c.debug[pc]) + var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextSymId c.idgen, c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) regs[ra].node.flags.incl nfIsRef @@ -2257,7 +2257,7 @@ const evalMacroLimit = 1000 proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) - result.typ = newType(tyError, nextId idgen, owner) + result.typ = newType(tyError, nextTypeId idgen, owner) result.typ.flags.incl tfCheckedForDestructor proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int; diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 8083ae179..f8765c4dc 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -26,7 +26,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): str proc atomicTypeX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo; idgen: IdGenerator): PNode = - let sym = newSym(skType, getIdent(cache, name), nextId(idgen), t.owner, info) + let sym = newSym(skType, getIdent(cache, name), nextSymId(idgen), t.owner, info) sym.magic = m sym.typ = t result = newSymNode(sym) @@ -47,7 +47,7 @@ proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; inf for i in 0..= result.len: setLen(result.sons, pos + 1) let fieldNode = newNode(nkExprColonExpr) - fieldNode.add newSymNode(newSym(skField, ident, nextId(idgen), nil, unknownLineInfo)) + fieldNode.add newSymNode(newSym(skField, ident, nextSymId(idgen), nil, unknownLineInfo)) fieldNode.add loadAny(p, field.typ, tab, cache, conf, idgen) result[pos] = fieldNode if p.kind == jsonObjectEnd: next(p) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 9fe934f89..15727c9f7 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -455,9 +455,9 @@ macro `{}`*(typ: typedesc, xs: varargs[untyped]): auto = # from a proc, `this` being the first argument. proc replaceSyms(n: NimNode): NimNode = - if n.kind == nnkSym: + if n.kind == nnkSym: result = newIdentNode($n) - else: + else: result = n for i in 0.. Date: Sat, 2 Jan 2021 04:10:38 -0300 Subject: [PATCH 1743/4254] Add mimetypes.mimesLongest (#16480) * Allow single alloc mimetypes ops * Allow single alloc mimetypes ops * Update lib/pure/mimetypes.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * https://github.com/nim-lang/Nim/pull/16480#issuecomment-752630190 * https://github.com/nim-lang/Nim/pull/16480#issuecomment-752630190 * https://github.com/nim-lang/Nim/pull/16480#issuecomment-753349661 * update changelog Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- changelog.md | 3 +++ lib/pure/mimetypes.nim | 29 ++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index c6a1d17d9..b10b9607a 100644 --- a/changelog.md +++ b/changelog.md @@ -81,6 +81,9 @@ - Added `httpcore.is1xx` and missing HTTP codes. - Added `jsconsole.jsAssert` for JavaScript target. +- Added `mimetypes.mimesExtMaxLen` thats equal to the length of the longest "ext" from `mimes`. +- Added `mimetypes.mimesMaxLen` thats equal to the length of the longest "mime" from `mimes`. + ## Language changes diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index 206783929..880ccdff1 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -8,7 +8,7 @@ # ## This module implements a mimetypes database -import strtabs +import strtabs, std/private/since from strutils import startsWith, toLowerAscii, strip type @@ -1917,6 +1917,33 @@ func register*(mimedb: var MimeDB, ext: string, mimetype: string) = {.noSideEffect.}: mimedb.mimes[ext.toLowerAscii()] = mimetype.toLowerAscii() + +since (1, 5): + func mimesLongest(): array[2, int] {.compiletime.} = + runnableExamples: + static: + doAssert mimesLongest() >= (ext: 24, mime: 73) + var currentKeyLength, currentValLength: int + for item in mimes: + currentKeyLength = item[0].len + currentValLength = item[1].len + if currentKeyLength > result[0]: result[0] = currentKeyLength + if currentValLength > result[1]: result[1] = currentValLength + + const + ctValue = mimesLongest() # Use 2 const instead of func, save tuple unpack. + mimesExtMaxLen*: int = ctValue[0] ## \ + ## The length of the longest "ext" from `mimes`, + ## this is useful for optimizations with `newStringOfCap` and `newString`. + mimesMaxLen*: int = ctValue[1] ## \ + ## The length of the longest "mime" from `mimes`, + ## this is useful for optimizations with `newStringOfCap` and `newString`. + ## + ## See also: + ## * `newStringOfCap `_ + ## * `newString `_ + + runnableExamples: static: block: From 854ff26ac5a140b2f2cb509cef5a7aac551f6c34 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 2 Jan 2021 01:33:59 -0800 Subject: [PATCH 1744/4254] fix #16206, `nim r / nim -r` recompiles if cwd changes (#16349) --- compiler/extccomp.nim | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 14b961ee1..87b38092e 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1026,6 +1026,8 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = lit $(%* conf.projectIsCmd) lit ",\L\"cmdInput\": " lit $(%* conf.cmdInput) + lit ",\L\"currentDir\": " + lit $(%* getCurrentDir()) if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): lit ",\L\"cmdline\": " @@ -1046,14 +1048,23 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol result = false try: let data = json.parseFile(jsonFile.string) - if not data.hasKey("depfiles") or not data.hasKey("cmdline"): + for key in "depfiles cmdline stdinInput currentDir".split: + if not data.hasKey(key): return true + if getCurrentDir() != data["currentDir"].getStr: + # fixes bug #16271 + # Note that simply comparing `expandFilename(projectFile)` would + # not be sufficient in case other flags depend implicitly on `getCurrentDir`, + # and would require much more care. Simply re-compiling is safer for now. + # A better strategy for future work would be to cache (with an LRU cache) + # the N most recent unique build instructions, as done with `rdmd`, + # which is both robust and avoids recompilation when switching back and forth + # between projects, see https://github.com/timotheecour/Nim/issues/199 return true let oldCmdLine = data["cmdline"].getStr if conf.commandLine != oldCmdLine: return true if hashNimExe() != data["nimexe"].getStr: return true - if not data.hasKey("stdinInput"): return true let stdinInput = data["stdinInput"].getBool let projectIsCmd = data["projectIsCmd"].getBool if conf.projectIsStdin or stdinInput: From d8b1ffc85733a2189a91deafe00d67af690028de Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 2 Jan 2021 07:32:37 -0600 Subject: [PATCH 1745/4254] fix #16542 (#16549) * fix #16542 --- lib/pure/hashes.nim | 23 +++++++++++++++++++++-- tests/stdlib/thashes.nim | 31 ++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 667f27e95..da72f2fab 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -195,10 +195,29 @@ else: ## Efficient hashing of integers. hashWangYi1(uint64(ord(x))) +when defined(js): + proc asBigInt(x: float): int64 = + # result is a `BigInt` type in js, but we cheat the type system + # and say it is a `int64` type. + # TODO refactor it using bigInt once jsBigInt is ready, pending pr #1640 + asm """ + const buffer = new ArrayBuffer(8); + const floatBuffer = new Float64Array(buffer); + const uintBuffer = new BigUint64Array(buffer); + floatBuffer[0] = `x`; + `result` = uintBuffer[0];""" + proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. - var y = x + 0.0 # for denormalization - result = hash(cast[ptr Hash](addr(y))[]) + let y = x + 0.0 # for denormalization + when nimvm: + # workaround a JS VM bug: bug #16547 + result = hashWangYi1(cast[int64](float64(y))) + else: + when not defined(js): + result = hashWangYi1(cast[Hash](y)) + else: + result = hashWangYi1(asBigInt(y)) # Forward declarations before methods that hash containers. This allows # containers to contain other containers diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 520b27e26..9c9287784 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -2,7 +2,7 @@ discard """ targets: "c cpp js" """ -import hashes +import std/hashes block hashes: block hashing: @@ -75,3 +75,32 @@ block largeSize: # longer than 4 characters doAssert hash(xx) == hash(ssl, 0, 4) doAssert hash(xx, 0, 3) == hash(xxl, 0, 3) doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) + +proc main() = + doAssert hash(0.0) == hash(0) + when sizeof(int) == 8: + block: + var s: seq[Hash] + for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]: + let b = hash(a) + doAssert b notin s + s.add b + when defined(js): + doAssert hash(0.345602) == 2035867618 + doAssert hash(234567.45) == -20468103 + doAssert hash(-9999.283456) == -43247422 + doAssert hash(84375674.0) == 707542256 + else: + doAssert hash(0.345602) == 387936373221941218 + doAssert hash(234567.45) == -8179139172229468551 + doAssert hash(-9999.283456) == 5876943921626224834 + doAssert hash(84375674.0) == 1964453089107524848 + else: + doAssert hash(0.345602) != 0 + doAssert hash(234567.45) != 0 + doAssert hash(-9999.283456) != 0 + doAssert hash(84375674.0) != 0 + + +static: main() +main() From b8775bff575fb6860d43806b8070b904229927bf Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 2 Jan 2021 10:11:46 -0600 Subject: [PATCH 1746/4254] fix `is "closure"` (#16552) --- compiler/semexprs.nim | 3 +-- tests/stdlib/thashes.nim | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9eccdef45..1e5772189 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -408,8 +408,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = of "closure": let t = skipTypes(t1, abstractRange) res = t.kind == tyProc and - t.callConv == ccClosure and - tfIterator notin t.flags + t.callConv == ccClosure of "iterator": let t = skipTypes(t1, abstractRange) res = t.kind == tyProc and diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 9c9287784..b8a2c2c6a 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -4,6 +4,15 @@ discard """ import std/hashes + +when not defined(js) and not defined(cpp): + block: + var x = 12 + iterator hello(): int {.closure.} = + yield x + + discard hash(hello) + block hashes: block hashing: var dummy = 0.0 From e869767aa72a71e673c2e8fdc51925f28c13d432 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 2 Jan 2021 10:13:01 -0600 Subject: [PATCH 1747/4254] fix #16061 (#16551) --- lib/pure/hashes.nim | 14 ++++++++++---- tests/stdlib/thashes.nim | 7 ++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index da72f2fab..dde4be128 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -297,6 +297,9 @@ proc murmurHash(x: openArray[byte]): Hash = h1 = h1 xor (h1 shr 16) return cast[Hash](h1) +proc hashVmImpl(x: cstring, sPos, ePos: int): Hash = + doAssert false, "implementation override in compiler/vmops.nim" + proc hashVmImpl(x: string, sPos, ePos: int): Hash = doAssert false, "implementation override in compiler/vmops.nim" @@ -341,11 +344,14 @@ proc hash*(x: cstring): Hash = inc i result = !$result else: - when not defined(js) and defined(nimToOpenArrayCString): - murmurHash(toOpenArrayByte(x, 0, x.high)) + when nimvm: + hashVmImpl(x, 0, high(x)) else: - let xx = $x - murmurHash(toOpenArrayByte(xx, 0, high(xx))) + when not defined(js) and defined(nimToOpenArrayCString): + murmurHash(toOpenArrayByte(x, 0, x.high)) + else: + let xx = $x + murmurHash(toOpenArrayByte(xx, 0, high(xx))) proc hash*(sBuf: string, sPos, ePos: int): Hash = ## Efficient hashing of a string buffer, from starting diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index b8a2c2c6a..17640387a 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -86,8 +86,13 @@ block largeSize: # longer than 4 characters doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) proc main() = + + doAssert hash(0.0) == hash(0) - when sizeof(int) == 8: + doAssert hash(cstring"abracadabra") == 97309975 + doAssert hash(cstring"abracadabra") == hash("abracadabra") + + when sizeof(int) == 8 or defined(js): block: var s: seq[Hash] for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]: From 2eccef7ad6dd2941bcc78692b499b4cb269e9a2a Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sat, 2 Jan 2021 20:28:59 +0100 Subject: [PATCH 1748/4254] Algorithm improvements (#16529) * Improve documentation for algorithm Remove unused import in algorithm tests Improve formatting * Reapply fix for reverse on empty openArray * Use 3rd person singular Add more explanations. --- lib/pure/algorithm.nim | 276 +++++++++++++++++++----------------- tests/stdlib/talgorithm.nim | 4 +- 2 files changed, 144 insertions(+), 136 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index f2e4848df..029e9abf8 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -7,11 +7,11 @@ # distribution, for details about the copyright. # -## This module implements some common generic algorithms. +## This module implements some common generic algorithms on `openArray`s. ## ## Basic usage ## =========== -## +## runnableExamples: type People = tuple @@ -30,9 +30,7 @@ runnableExamples: (year: 2010, name: "Jane")] proc myCmp(x, y: People): int = - if x.name < y.name: -1 - elif x.name == y.name: 0 - else: 1 + cmp(x.name, y.name) # Sorting with custom proc a.sort(myCmp) @@ -49,18 +47,18 @@ type Descending, Ascending proc `*`*(x: int, order: SortOrder): int {.inline.} = - ## Flips ``x`` if ``order == Descending``. - ## If ``order == Ascending`` then ``x`` is returned. + ## Flips the sign of `x` if `order == Descending`. + ## If `order == Ascending` then `x` is returned. ## - ## ``x`` is supposed to be the result of a comparator, i.e. - ## | ``< 0`` for *less than*, - ## | ``== 0`` for *equal*, - ## | ``> 0`` for *greater than*. + ## `x` is supposed to be the result of a comparator, i.e. + ## | `< 0` for *less than*, + ## | `== 0` for *equal*, + ## | `> 0` for *greater than*. runnableExamples: - assert `*`(-123, Descending) == 123 - assert `*`(123, Descending) == -123 - assert `*`(-123, Ascending) == -123 - assert `*`(123, Ascending) == 123 + assert -123 * Descending == 123 + assert 123 * Descending == -123 + assert -123 * Ascending == -123 + assert 123 * Ascending == 123 var y = order.ord - 1 result = (x xor y) - y @@ -71,9 +69,9 @@ template fillImpl[T](a: var openArray[T], first, last: int, value: T) = inc(x) proc fill*[T](a: var openArray[T], first, last: Natural, value: T) = - ## Fills the slice ``a[first..last]`` with ``value``. + ## Assigns `value` to all elements of the slice `a[first..last]`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. runnableExamples: var a: array[6, int] a.fill(1, 3, 9) @@ -84,7 +82,7 @@ proc fill*[T](a: var openArray[T], first, last: Natural, value: T) = fillImpl(a, first, last, value) proc fill*[T](a: var openArray[T], value: T) = - ## Fills the container ``a`` with ``value``. + ## Assigns `value` to all elements of the container `a`. runnableExamples: var a: array[6, int] a.fill(9) @@ -95,13 +93,13 @@ proc fill*[T](a: var openArray[T], value: T) = proc reverse*[T](a: var openArray[T], first, last: Natural) = - ## Reverses the slice ``a[first..last]``. + ## Reverses the slice `a[first..last]`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. ## ## **See also:** - ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a ``seq[T]`` - ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a ``seq[T]`` + ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a `seq[T]` + ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a `seq[T]` runnableExamples: var a = [1, 2, 3, 4, 5, 6] a.reverse(1, 3) @@ -117,23 +115,24 @@ proc reverse*[T](a: var openArray[T], first, last: Natural) = inc(x) proc reverse*[T](a: var openArray[T]) = - ## Reverses the contents of the container ``a``. + ## Reverses the contents of the container `a`. ## ## **See also:** - ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a ``seq[T]`` - ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a ``seq[T]`` + ## * `reversed proc<#reversed,openArray[T],Natural,int>`_ reverse a slice and returns a `seq[T]` + ## * `reversed proc<#reversed,openArray[T]>`_ reverse and returns a `seq[T]` runnableExamples: var a = [1, 2, 3, 4, 5, 6] a.reverse() assert a == [6, 5, 4, 3, 2, 1] a.reverse() assert a == [1, 2, 3, 4, 5, 6] + # the max is needed, since a.high is -1 if a is empty reverse(a, 0, max(0, a.high)) proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = - ## Returns the reverse of the slice ``a[first..last]``. + ## Returns the reverse of the slice `a[first..last]`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. ## ## **See also:** ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice @@ -143,7 +142,7 @@ proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = a = [1, 2, 3, 4, 5, 6] b = a.reversed(1, 3) assert b == @[4, 3, 2] - assert last >= first-1 + assert last >= first - 1 var i = last - first var x = first.int result = newSeq[T](i + 1) @@ -153,7 +152,7 @@ proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = inc(x) proc reversed*[T](a: openArray[T]): seq[T] = - ## Returns the reverse of the container ``a``. + ## Returns the reverse of the container `a`. ## ## **See also:** ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice @@ -166,19 +165,20 @@ proc reversed*[T](a: openArray[T]): seq[T] = reversed(a, 0, a.high) proc binarySearch*[T, K](a: openArray[T], key: K, - cmp: proc (x: T, y: K): int {.closure.}): int = - ## Binary search for ``key`` in ``a``. Returns -1 if not found. + cmp: proc (x: T, y: K): int {.closure.}): int = + ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found. + ## Assumes that `a` is sorted according to `cmp`. ## - ## ``cmp`` is the comparator function to use, the expected return values are - ## the same as that of system.cmp. + ## `cmp` is the comparator function to use, the expected return values are + ## the same as those of system.cmp. runnableExamples: assert binarySearch(["a", "b", "c", "d"], "d", system.cmp[string]) == 3 - assert binarySearch(["a", "b", "d", "c"], "d", system.cmp[string]) == 2 - if a.len == 0: - return -1 - + assert binarySearch(["a", "b", "c", "d"], "c", system.cmp[string]) == 2 let len = a.len + if len == 0: + return -1 + if len == 1: if cmp(a[0], key) == 0: return 0 @@ -196,7 +196,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K, if cmpRes == 0: return i - if cmpRes < 1: + if cmpRes < 0: result = i step = step shr 1 if cmp(a[result], key) != 0: result = -1 @@ -216,30 +216,32 @@ proc binarySearch*[T, K](a: openArray[T], key: K, if result >= len or cmp(a[result], key) != 0: result = -1 proc binarySearch*[T](a: openArray[T], key: T): int = - ## Binary search for ``key`` in ``a``. Returns -1 if not found. + ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found. + ## Assumes that `a` is sorted. runnableExamples: assert binarySearch([0, 1, 2, 3, 4], 4) == 4 - assert binarySearch([0, 1, 4, 2, 3], 4) == 2 + assert binarySearch([0, 1, 2, 3, 4], 2) == 2 binarySearch(a, key, cmp[T]) const onlySafeCode = true -proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. - closure.}): int = - ## Returns a position to the first element in the ``a`` that is greater than - ## ``key``, or last if no such element is found. +proc lowerBound*[T, K](a: openArray[T], key: K, + cmp: proc(x: T, k: K): int {.closure.}): int = + ## Returns the index of the first element in `a` that is not less than + ## (i.e. greater or equal to) `key`, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## ``insert(thing, elm, lowerBound(thing, elm))`` + ## `insert(thing, elm, lowerBound(thing, elm))` ## the sequence will still be sorted. + ## Assumes that `a` is sorted according to `cmp`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. ## - ## The version uses ``cmp`` to compare the elements. - ## The expected return values are the same as that of ``system.cmp``. + ## This version uses `cmp` to compare the elements. + ## The expected return values are the same as those of `system.cmp`. ## ## **See also:** - ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order + ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order ## * `upperBound proc<#upperBound,openArray[T],T>`_ runnableExamples: var arr = @[1, 2, 3, 5, 6, 7, 8, 9] @@ -261,33 +263,35 @@ proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. count = step proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T]) - ## Returns a position to the first element in the ``a`` that is greater than - ## ``key``, or last if no such element is found. + ## Returns the index of the first element in `a` that is not less than + ## (i.e. greater or equal to) `key`, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## ``insert(thing, elm, lowerBound(thing, elm))`` + ## `insert(thing, elm, lowerBound(thing, elm))` ## the sequence will still be sorted. + ## Assumes that `a` is sorted. ## - ## The version uses the default comparison function ``cmp``. + ## This version uses the default comparison function `cmp`. ## ## **See also:** - ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order + ## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order ## * `upperBound proc<#upperBound,openArray[T],T>`_ -proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. - closure.}): int = - ## Returns a position to the first element in the ``a`` that is not less - ## (i.e. greater or equal to) than ``key``, or last if no such element is found. +proc upperBound*[T, K](a: openArray[T], key: K, + cmp: proc(x: T, k: K): int {.closure.}): int = + ## Returns the index of the first element in `a` that is greater than + ## `key`, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## ``insert(thing, elm, upperBound(thing, elm))`` + ## `insert(thing, elm, upperBound(thing, elm))` ## the sequence will still be sorted. + ## Assumes that `a` is sorted according to `cmp`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. ## - ## The version uses ``cmp`` to compare the elements. The expected - ## return values are the same as that of ``system.cmp``. + ## This version uses `cmp` to compare the elements. The expected + ## return values are the same as those of `system.cmp`. ## ## **See also:** - ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order + ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order ## * `lowerBound proc<#lowerBound,openArray[T],T>`_ runnableExamples: var arr = @[1, 2, 3, 5, 6, 7, 8, 9] @@ -309,19 +313,20 @@ proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. count = step proc upperBound*[T](a: openArray[T], key: T): int = upperBound(a, key, cmp[T]) - ## Returns a position to the first element in the ``a`` that is not less - ## (i.e. greater or equal to) than ``key``, or last if no such element is found. + ## Returns the index of the first element in `a` that is greater than + ## `key`, or last if no such element is found. ## In other words if you have a sorted sequence and you call - ## ``insert(thing, elm, upperBound(thing, elm))`` + ## `insert(thing, elm, upperBound(thing, elm))` ## the sequence will still be sorted. + ## Assumes that `a` is sorted. ## - ## The version uses the default comparison function ``cmp``. + ## This version uses the default comparison function `cmp`. ## ## **See also:** - ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order + ## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by `cmp` in the specified order ## * `lowerBound proc<#lowerBound,openArray[T],T>`_ -template `<-` (a, b) = +template `<-`(a, b) = when defined(gcDestructors): a = move b elif onlySafeCode: @@ -331,10 +336,10 @@ template `<-` (a, b) = proc merge[T](a, b: var openArray[T], lo, m, hi: int, cmp: proc (x, y: T): int {.closure.}, order: SortOrder) = - # optimization: If max(left) <= min(right) there is nothing to do! - # 1 2 3 4 ## 5 6 7 8 + # Optimization: If max(left) <= min(right) there is nothing to do! + # 1 2 3 4 ## 5 6 7 8 # -> O(n) for sorted arrays. - # On random data this safes up to 40% of merge calls + # On random data this saves up to 40% of merge calls. if cmp(a[m], a[m+1]) * order <= 0: return var j = lo # copy a[j..m] into b: @@ -372,14 +377,15 @@ func sort*[T](a: var openArray[T], cmp: proc (x, y: T): int {.closure.}, order = SortOrder.Ascending) = ## Default Nim sort (an implementation of merge sort). The sorting - ## is guaranteed to be stable and the worst case is guaranteed to - ## be O(n log n). + ## is guaranteed to be stable (that is, equal elements stay in the same order) + ## and the worst case is guaranteed to be O(n log n). + ## Sorts by `cmp` in the specified `order`. ## ## The current implementation uses an iterative ## mergesort to achieve this. It uses a temporary sequence of - ## length ``a.len div 2``. If you do not wish to provide your own - ## ``cmp``, you may use ``system.cmp`` or instead call the overloaded - ## version of ``sort``, which uses ``system.cmp``. + ## length `a.len div 2`. If you do not wish to provide your own + ## `cmp`, you may use `system.cmp` or instead call the overloaded + ## version of `sort`, which uses `system.cmp`. ## ## .. code-block:: nim ## @@ -400,7 +406,7 @@ func sort*[T](a: var openArray[T], ## ## **See also:** ## * `sort proc<#sort,openArray[T]>`_ - ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by ``cmp`` in the specified order + ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by `cmp` in the specified order ## * `sorted proc<#sorted,openArray[T]>`_ ## * `sortedByIt template<#sortedByIt.t,untyped,untyped>`_ runnableExamples: @@ -411,8 +417,7 @@ func sort*[T](a: var openArray[T], sort(d, myCmp) assert d == ["fo", "qux", "boo", "barr"] var n = a.len - var b: seq[T] - newSeq(b, n div 2) + var b = newSeq[T](n div 2) var s = 1 while s < n: var m = n-1-s @@ -423,17 +428,17 @@ func sort*[T](a: var openArray[T], proc sort*[T](a: var openArray[T], order = SortOrder.Ascending) = sort[T](a, system.cmp[T], order) - ## Shortcut version of ``sort`` that uses ``system.cmp[T]`` as the comparison function. + ## Shortcut version of `sort` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ - ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by ``cmp`` in the specified order + ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by `cmp` in the specified order ## * `sorted proc<#sorted,openArray[T]>`_ ## * `sortedByIt template<#sortedByIt.t,untyped,untyped>`_ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, order = SortOrder.Ascending): seq[T] = - ## Returns ``a`` sorted by ``cmp`` in the specified ``order``. + ## Returns `a` sorted by `cmp` in the specified `order`. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ @@ -454,7 +459,7 @@ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, sort(result, cmp, order) proc sorted*[T](a: openArray[T], order = SortOrder.Ascending): seq[T] = - ## Shortcut version of ``sorted`` that uses ``system.cmp[T]`` as the comparison function. + ## Shortcut version of `sorted` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ @@ -472,18 +477,18 @@ proc sorted*[T](a: openArray[T], order = SortOrder.Ascending): seq[T] = sorted[T](a, system.cmp[T], order) template sortedByIt*(seq1, op: untyped): untyped = - ## Convenience template around the ``sorted`` proc to reduce typing. + ## Convenience template around the `sorted` proc to reduce typing. ## - ## The template injects the ``it`` variable which you can use directly in an + ## The template injects the `it` variable which you can use directly in an ## expression. ## - ## Because the underlying ``cmp()`` is defined for tuples you can do + ## Because the underlying `cmp()` is defined for tuples you can also do ## a nested sort. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ ## * `sort proc<#sort,openArray[T]>`_ - ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by ``cmp`` in the specified order + ## * `sorted proc<#sorted,openArray[T],proc(T,T)>`_ sorted by `cmp` in the specified order ## * `sorted proc<#sorted,openArray[T]>`_ runnableExamples: type Person = tuple[name: string, age: int] @@ -510,9 +515,9 @@ template sortedByIt*(seq1, op: untyped): untyped = func isSorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, order = SortOrder.Ascending): bool = - ## Checks to see whether ``a`` is already sorted in ``order`` - ## using ``cmp`` for the comparison. Parameters identical - ## to ``sort``. Requires O(n) time. + ## Checks to see whether `a` is already sorted in `order` + ## using `cmp` for the comparison. The parameters are identical + ## to `sort`. Requires O(n) time. ## ## **See also:** ## * `isSorted proc<#isSorted,openArray[T]>`_ @@ -535,7 +540,7 @@ func isSorted*[T](a: openArray[T], return false proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = - ## Shortcut version of ``isSorted`` that uses ``system.cmp[T]`` as the comparison function. + ## Shortcut version of `isSorted` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** ## * `isSorted func<#isSorted,openArray[T],proc(T,T)>`_ @@ -555,8 +560,10 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = isSorted(a, system.cmp[T], order) proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = - ## Produces the Cartesian product of the array. Warning: complexity - ## may explode. + ## Produces the Cartesian product of the array. + ## Every element of the result is a combination of one element from each seq in `x`, + ## with the ith element coming from `x[i]`. + ## Warning: complexity may explode. runnableExamples: assert product(@[@[1], @[2]]) == @[@[1, 2]] assert product(@[@["A", "K"], @["Q"]]) == @[@["K", "Q"], @["A", "Q"]] @@ -567,34 +574,33 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = result = @x return var - indexes = newSeq[int](x.len) + indices = newSeq[int](x.len) initial = newSeq[int](x.len) index = 0 - var next = newSeq[T]() - next.setLen(x.len) + var next = newSeq[T](x.len) for i in 0..(x.len-1): if len(x[i]) == 0: return - initial[i] = len(x[i])-1 - indexes = initial + initial[i] = len(x[i]) - 1 + indices = initial while true: - while indexes[index] == -1: - indexes[index] = initial[index] + while indices[index] == -1: + indices[index] = initial[index] index += 1 if index == x.len: return - indexes[index] -= 1 - for ni, i in indexes: + indices[index] -= 1 + for ni, i in indices: next[ni] = x[ni][i] result.add(next) index = 0 - indexes[index] -= 1 + indices[index] -= 1 proc nextPermutation*[T](x: var openArray[T]): bool {.discardable.} = - ## Calculates the next lexicographic permutation, directly modifying ``x``. + ## Calculates the next lexicographic permutation, directly modifying `x`. ## The result is whether a permutation happened, otherwise we have reached ## the last-ordered permutation. ## ## If you start with an unsorted array/seq, the repeated permutations - ## will **not** give you all permutations but stop with last. + ## will **not** give you all permutations but stop with the last. ## ## **See also:** ## * `prevPermutation proc<#prevPermutation,openArray[T]>`_ @@ -630,7 +636,7 @@ proc nextPermutation*[T](x: var openArray[T]): bool {.discardable.} = proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} = ## Calculates the previous lexicographic permutation, directly modifying - ## ``x``. The result is whether a permutation happened, otherwise we have + ## `x`. The result is whether a permutation happened, otherwise we have ## reached the first-ordered permutation. ## ## **See also:** @@ -664,7 +670,8 @@ proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} = result = true proc rotateInternal[T](arg: var openArray[T]; first, middle, last: int): int = - ## A port of std::rotate from c++. Ported from `this reference `_. + ## A port of std::rotate from C++. + ## Ported from [this reference](http://www.cplusplus.com/reference/algorithm/rotate/). result = first + last - middle if first == middle or middle == last: @@ -716,30 +723,30 @@ proc rotatedInternal[T](arg: openArray[T]; first, middle, last: int): seq[T] = result[i] = arg[i] proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int]; - dist: int): int {.discardable.} = + dist: int): int {.discardable.} = ## Performs a left rotation on a range of elements. If you want to rotate - ## right, use a negative ``dist``. Specifically, ``rotateLeft`` rotates - ## the elements at ``slice`` by ``dist`` positions. + ## right, use a negative `dist`. Specifically, `rotateLeft` rotates + ## the elements at `slice` by `dist` positions. ## - ## | The element at index ``slice.a + dist`` will be at index ``slice.a``. - ## | The element at index ``slice.b`` will be at ``slice.a + dist -1``. - ## | The element at index ``slice.a`` will be at ``slice.b + 1 - dist``. - ## | The element at index ``slice.a + dist - 1`` will be at ``slice.b``. + ## | The element at index `slice.a + dist` will be at index `slice.a`. + ## | The element at index `slice.b` will be at `slice.a + dist - 1`. + ## | The element at index `slice.a` will be at `slice.b + 1 - dist`. + ## | The element at index `slice.a + dist - 1` will be at `slice.b`. ## - ## Elements outside of ``slice`` will be left unchanged. - ## The time complexity is linear to ``slice.b - slice.a + 1``. - ## If an invalid range (``HSlice``) is passed, it raises IndexDefect. + ## Elements outside of `slice` will be left unchanged. + ## The time complexity is linear to `slice.b - slice.a + 1`. + ## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`. ## - ## ``slice`` + ## `slice` ## The indices of the element range that should be rotated. ## - ## ``dist`` + ## `dist` ## The distance in amount of elements that the data should be rotated. ## Can be negative, can be any number. ## ## **See also:** ## * `rotateLeft proc<#rotateLeft,openArray[T],int>`_ for a version which rotates the whole container - ## * `rotatedLeft proc<#rotatedLeft,openArray[T],HSlice[int,int],int>`_ for a version which returns a ``seq[T]`` + ## * `rotatedLeft proc<#rotatedLeft,openArray[T],HSlice[int,int],int>`_ for a version which returns a `seq[T]` runnableExamples: var a = [0, 1, 2, 3, 4, 5] a.rotateLeft(1 .. 4, 3) @@ -751,15 +758,16 @@ proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int]; doAssertRaises(IndexDefect, a.rotateLeft(1 .. 7, 2)) let sliceLen = slice.b + 1 - slice.a let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen - arg.rotateInternal(slice.a, slice.a+distLeft, slice.b + 1) + arg.rotateInternal(slice.a, slice.a + distLeft, slice.b + 1) proc rotateLeft*[T](arg: var openArray[T]; dist: int): int {.discardable.} = - ## Default arguments for slice, so that this procedure operates on the entire - ## ``arg``, and not just on a part of it. + ## Same as `rotateLeft`, but with default arguments for slice, + ## so that this procedure operates on the entire + ## `arg`, and not just on a part of it. ## ## **See also:** ## * `rotateLeft proc<#rotateLeft,openArray[T],HSlice[int,int],int>`_ for a version which rotates a range - ## * `rotatedLeft proc<#rotatedLeft,openArray[T],int>`_ for a version which returns a ``seq[T]`` + ## * `rotatedLeft proc<#rotatedLeft,openArray[T],int>`_ for a version which returns a `seq[T]` runnableExamples: var a = [1, 2, 3, 4, 5] a.rotateLeft(2) @@ -773,17 +781,17 @@ proc rotateLeft*[T](arg: var openArray[T]; dist: int): int {.discardable.} = arg.rotateInternal(0, distLeft, arglen) proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int], - dist: int): seq[T] = - ## Same as ``rotateLeft``, just with the difference that it does - ## not modify the argument. It creates a new ``seq`` instead. + dist: int): seq[T] = + ## Same as `rotateLeft`, just with the difference that it does + ## not modify the argument. It creates a new `seq` instead. ## - ## Elements outside of ``slice`` will be left unchanged. - ## If an invalid range (``HSlice``) is passed, it raises IndexDefect. + ## Elements outside of `slice` will be left unchanged. + ## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`. ## - ## ``slice`` + ## `slice` ## The indices of the element range that should be rotated. ## - ## ``dist`` + ## `dist` ## The distance in amount of elements that the data should be rotated. ## Can be negative, can be any number. ## @@ -803,8 +811,8 @@ proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int], arg.rotatedInternal(slice.a, slice.a+distLeft, slice.b+1) proc rotatedLeft*[T](arg: openArray[T]; dist: int): seq[T] = - ## Same as ``rotateLeft``, just with the difference that it does - ## not modify the argument. It creates a new ``seq`` instead. + ## Same as `rotateLeft`, just with the difference that it does + ## not modify the argument. It creates a new `seq` instead. ## ## **See also:** ## * `rotateLeft proc<#rotateLeft,openArray[T],int>`_ for the in-place version of this proc diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 148a65289..47a8d327b 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -3,7 +3,7 @@ discard """ ''' """ #12928,10456 -import sequtils, strutils, algorithm, json +import sequtils, algorithm, json proc test() = try: @@ -14,7 +14,7 @@ proc test() = echo prefixes except: discard - + test() block: From 471aab86a0b793afe34a36b41e4366a686b589b9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 2 Jan 2021 12:41:44 -0800 Subject: [PATCH 1749/4254] fix #16526 run config.nims before foo.nim.cfg (#16557) * fix #16526 run config.nims before foo.nim.cfg * add test --- compiler/nimconf.nim | 4 ++-- tests/misc/trunner.nim | 19 +++++++++++++++++++ tests/newconfig/bar/config.nims | 0 tests/newconfig/bar/mfoo.nim | 0 tests/newconfig/bar/mfoo.nim.cfg | 0 tests/newconfig/bar/mfoo.nims | 0 tests/newconfig/bar/nim.cfg | 0 7 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/newconfig/bar/config.nims create mode 100644 tests/newconfig/bar/mfoo.nim create mode 100644 tests/newconfig/bar/mfoo.nim.cfg create mode 100644 tests/newconfig/bar/mfoo.nims create mode 100644 tests/newconfig/bar/nim.cfg diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 01a79c1e3..1691e7ccf 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -281,6 +281,8 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: if optSkipProjConfigFile notin conf.globalOptions: readConfigFile(pd / cfg) + if cfg == DefaultConfig: + runNimScriptIfExists(pd / DefaultConfigNims) if conf.projectName.len != 0: # new project wide config file: @@ -289,8 +291,6 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: projectConfig = changeFileExt(conf.projectFull, "nim.cfg") readConfigFile(projectConfig) - if cfg == DefaultConfig: - runNimScriptIfExists(pd / DefaultConfigNims) let scriptFile = conf.projectFull.changeFileExt("nims") let scriptIsProj = scriptFile == conf.projectFull diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 530561cd9..874ad66d6 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -224,6 +224,25 @@ sub/mmain.idx""", context let cmd = fmt"{nim} r -b:cpp --hints:off --nimcache:{nimcache} --warningAsError:ProveInit {file}" check execCmdEx(cmd) == ("witness\n", 0) + block: # config.nims, nim.cfg, hintConf, bug #16557 + let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf tests/newconfig/bar/mfoo.nim" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + doAssert exitCode == 0 + let dir = getCurrentDir() + let files = """ +config/nim.cfg +config/config.nims +tests/config.nims +tests/newconfig/bar/nim.cfg +tests/newconfig/bar/config.nims +tests/newconfig/bar/mfoo.nim.cfg +tests/newconfig/bar/mfoo.nims""".splitLines + var expected = "" + for a in files: + let b = dir / a + expected.add &"Hint: used config file '{b}' [Conf]\n" + doAssert outp == expected, outp & "\n" & expected + block: # nim --eval let opt = "--hints:off" check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0) diff --git a/tests/newconfig/bar/config.nims b/tests/newconfig/bar/config.nims new file mode 100644 index 000000000..e69de29bb diff --git a/tests/newconfig/bar/mfoo.nim b/tests/newconfig/bar/mfoo.nim new file mode 100644 index 000000000..e69de29bb diff --git a/tests/newconfig/bar/mfoo.nim.cfg b/tests/newconfig/bar/mfoo.nim.cfg new file mode 100644 index 000000000..e69de29bb diff --git a/tests/newconfig/bar/mfoo.nims b/tests/newconfig/bar/mfoo.nims new file mode 100644 index 000000000..e69de29bb diff --git a/tests/newconfig/bar/nim.cfg b/tests/newconfig/bar/nim.cfg new file mode 100644 index 000000000..e69de29bb From cf714c129f7dd598863d1cc588e685df2438c658 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 2 Jan 2021 21:47:26 +0100 Subject: [PATCH 1750/4254] Make config processing order test more robust --- tests/misc/trunner.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 874ad66d6..3f5b10f97 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -225,7 +225,7 @@ sub/mmain.idx""", context check execCmdEx(cmd) == ("witness\n", 0) block: # config.nims, nim.cfg, hintConf, bug #16557 - let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf tests/newconfig/bar/mfoo.nim" + let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf --skipParentCfg tests/newconfig/bar/mfoo.nim" let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) doAssert exitCode == 0 let dir = getCurrentDir() From c71f5650c65026cf7c213b3a508fc16e89bc1ad2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 2 Jan 2021 22:55:08 -0600 Subject: [PATCH 1751/4254] Revert "Make config processing order test more robust" (#16561) This reverts commit cf714c129f7dd598863d1cc588e685df2438c658. --- tests/misc/trunner.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 3f5b10f97..874ad66d6 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -225,7 +225,7 @@ sub/mmain.idx""", context check execCmdEx(cmd) == ("witness\n", 0) block: # config.nims, nim.cfg, hintConf, bug #16557 - let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf --skipParentCfg tests/newconfig/bar/mfoo.nim" + let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf tests/newconfig/bar/mfoo.nim" let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) doAssert exitCode == 0 let dir = getCurrentDir() From 2aed4186989e0c9192eadcc28f989d41f92237b0 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 3 Jan 2021 10:02:12 +0300 Subject: [PATCH 1752/4254] Fix #16554 (#16564) --- lib/pure/collections/critbits.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 695f44646..a4e727909 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -531,13 +531,14 @@ func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = else: c.root.byte else: 0 -func toCritBitTree*[A, B](pairs: openArray[(A, B)]): CritBitTree[A] {.since: (1, 3).} = +func toCritBitTree*[T](pairs: openArray[(string, T)]): CritBitTree[T] {.since: (1, 3).} = ## Creates a new `CritBitTree` that contains the given `pairs`. runnableExamples: doAssert {"a": "0", "b": "1", "c": "2"}.toCritBitTree is CritBitTree[string] + doAssert {"a": 0, "b": 1, "c": 2}.toCritBitTree is CritBitTree[int] for item in pairs: result.incl item[0], item[1] -func toCritBitTree*[T](items: openArray[T]): CritBitTree[void] {.since: (1, 3).} = +func toCritBitTree*(items: openArray[string]): CritBitTree[void] {.since: (1, 3).} = ## Creates a new `CritBitTree` that contains the given `items`. runnableExamples: doAssert ["a", "b", "c"].toCritBitTree is CritBitTree[void] From 76f92265d91ea7490dc434a82459ae93f5e8ff9e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 3 Jan 2021 04:05:59 -0600 Subject: [PATCH 1753/4254] fix #8412 (#16563) * Revert "Make config processing order test more robust" This reverts commit cf714c129f7dd598863d1cc588e685df2438c658. * enable tmath tests * fix #8412 * Revert "enable tmath tests" This reverts commit 293b63f57ef71e6c43b9faf24883c998c40a9484. * add tests * fix --- lib/system.nim | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 29c137b63..618fd5dd7 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2394,16 +2394,22 @@ when notJSnotNims: proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw proc pointer of the closure `x`. This is ## useful for interfacing closures with C. - {.emit: """ - `result` = `x`.ClP_0; - """.} + when T is "closure": + {.emit: """ + `result` = `x`.ClP_0; + """.} + else: + {.error: "Only closure function and iterator are allowed!".} proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw environment pointer of the closure `x`. This is ## useful for interfacing closures with C. - {.emit: """ - `result` = `x`.ClE_0; - """.} + when T is "closure": + {.emit: """ + `result` = `x`.ClE_0; + """.} + else: + {.error: "Only closure function and iterator are allowed!".} proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = ## can be used to determine if a first class iterator has finished. From c82c67dc69a32a18a94c7c4de8efed3eb609d8c1 Mon Sep 17 00:00:00 2001 From: Roman Inflianskas Date: Sun, 3 Jan 2021 15:00:22 +0200 Subject: [PATCH 1754/4254] fix #12958 (#16565) Sync between Linux kernel code (header: https://github.com/torvalds/linux/blob/master/tools/include/uapi/linux/sched.h) and the linux module in lib. `CLONE_STOPPED` was marked as deprecated, as it was removed in the Linux kernel upstream. Fixes #12958. --- lib/posix/linux.nim | 47 ++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim index 680b61461..5ce9bf2fb 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -1,24 +1,35 @@ import posix +## Flags of `clone` syscall. +## See `clone syscall manual +## `_ for more information. const - CSIGNAL* = 0x000000FF - CLONE_VM* = 0x00000100 - CLONE_FS* = 0x00000200 - CLONE_FILES* = 0x00000400 - CLONE_SIGHAND* = 0x00000800 - CLONE_PTRACE* = 0x00002000 - CLONE_VFORK* = 0x00004000 - CLONE_PARENT* = 0x00008000 - CLONE_THREAD* = 0x00010000 - CLONE_NEWNS* = 0x00020000 - CLONE_SYSVSEM* = 0x00040000 - CLONE_SETTLS* = 0x00080000 - CLONE_PARENT_SETTID* = 0x00100000 - CLONE_CHILD_CLEARTID* = 0x00200000 - CLONE_DETACHED* = 0x00400000 - CLONE_UNTRACED* = 0x00800000 - CLONE_CHILD_SETTID* = 0x01000000 - CLONE_STOPPED* = 0x02000000 + CSIGNAL* = 0x000000FF'i32 + CLONE_VM* = 0x00000100'i32 + CLONE_FS* = 0x00000200'i32 + CLONE_FILES* = 0x00000400'i32 + CLONE_SIGHAND* = 0x00000800'i32 + CLONE_PIDFD* = 0x00001000'i32 + CLONE_PTRACE* = 0x00002000'i32 + CLONE_VFORK* = 0x00004000'i32 + CLONE_PARENT* = 0x00008000'i32 + CLONE_THREAD* = 0x00010000'i32 + CLONE_NEWNS* = 0x00020000'i32 + CLONE_SYSVSEM* = 0x00040000'i32 + CLONE_SETTLS* = 0x00080000'i32 + CLONE_PARENT_SETTID* = 0x00100000'i32 + CLONE_CHILD_CLEARTID* = 0x00200000'i32 + CLONE_DETACHED* = 0x00400000'i32 + CLONE_UNTRACED* = 0x00800000'i32 + CLONE_CHILD_SETTID* = 0x01000000'i32 + CLONE_NEWCGROUP* = 0x02000000'i32 + CLONE_NEWUTS* = 0x04000000'i32 + CLONE_NEWIPC* = 0x08000000'i32 + CLONE_NEWUSER* = 0x10000000'i32 + CLONE_NEWPID* = 0x20000000'i32 + CLONE_NEWNET* = 0x40000000'i32 + CLONE_IO* = 0x80000000'i32 + CLONE_STOPPED* {.deprecated.} = 0x02000000'i32 # fn should be of type proc (a2: pointer): void {.cdecl.} proc clone*(fn: pointer; child_stack: pointer; flags: cint; From a0134671eeed3cfac1e9035568cbdec41825da8d Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 3 Jan 2021 19:15:56 +0100 Subject: [PATCH 1755/4254] Make test independent of repo location (#16571) * Make test independent of repo location * Fix differently --- tests/misc/trunner.nim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 874ad66d6..63aac0ede 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -230,8 +230,6 @@ sub/mmain.idx""", context doAssert exitCode == 0 let dir = getCurrentDir() let files = """ -config/nim.cfg -config/config.nims tests/config.nims tests/newconfig/bar/nim.cfg tests/newconfig/bar/config.nims @@ -241,7 +239,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines for a in files: let b = dir / a expected.add &"Hint: used config file '{b}' [Conf]\n" - doAssert outp == expected, outp & "\n" & expected + doAssert outp.endsWith expected, outp & "\n" & expected block: # nim --eval let opt = "--hints:off" From 763fef59fa9bf618f9b546dcb199872b5d8ee890 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 4 Jan 2021 07:25:05 +0100 Subject: [PATCH 1756/4254] Improve documentation for critbits (#16568) --- lib/pure/collections/critbits.nim | 242 +++++++++++++----------------- 1 file changed, 107 insertions(+), 135 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index a4e727909..113939567 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -8,10 +8,32 @@ # ## This module implements a `crit bit tree`:idx: which is an efficient -## container for a sorted set of strings, or for a sorted mapping of strings. Based on the excellent paper -## by Adam Langley. +## container for a sorted set of strings, or for a sorted mapping of strings. Based on the +## [excellent paper by Adam Langley](https://www.imperialviolet.org/binary/critbit.pdf). ## (A crit bit tree is a form of `radix tree`:idx: or `patricia trie`:idx:.) +runnableExamples: + from sequtils import toSeq + + var critbitAsSet: CritBitTree[void] = ["kitten", "puppy"].toCritBitTree + doAssert critbitAsSet.len == 2 + critbitAsSet.incl("") + doAssert "" in critbitAsSet + critbitAsSet.excl("") + doAssert "" notin critbitAsSet + doAssert toSeq(critbitAsSet.items) == @["kitten", "puppy"] + let same = ["puppy", "kitten", "puppy"].toCritBitTree + doAssert toSeq(same.keys) == toSeq(critbitAsSet.keys) + + var critbitAsDict: CritBitTree[int] = {"key1": 42}.toCritBitTree + doAssert critbitAsDict.len == 1 + critbitAsDict["key2"] = 0 + doAssert "key2" in critbitAsDict + doAssert critbitAsDict["key2"] == 0 + critbitAsDict.excl("key1") + doAssert "key1" notin critbitAsDict + doAssert toSeq(critbitAsDict.pairs) == @[("key2", 0)] + import std/private/since type @@ -28,17 +50,15 @@ type Node[T] = ref NodeObj[T] CritBitTree*[T] = object ## The crit bit tree can either be used ## as a mapping from strings to - ## some type ``T`` or as a set of - ## strings if ``T`` is void. + ## some type `T` or as a set of + ## strings if `T` is `void`. root: Node[T] count: int func len*[T](c: CritBitTree[T]): int {.inline.} = ## Returns the number of elements in `c` in O(1). runnableExamples: - var c: CritBitTree[void] - incl(c, "key1") - incl(c, "key2") + let c = ["key1", "key2"].toCritBitTree doAssert c.len == 2 result = c.count @@ -144,7 +164,7 @@ proc excl*[T](c: var CritBitTree[T], key: string) = ## Removes `key` (and its associated value) from the set `c`. ## If the `key` does not exist, nothing happens. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,CritBitTree[void],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ runnableExamples: @@ -157,9 +177,9 @@ proc excl*[T](c: var CritBitTree[T], key: string) = proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = ## Returns true if `c` does not contain the given `key`. If the key - ## does exist, c.excl(key) is performed. + ## does exist, `c.excl(key)` is performed. ## - ## See also: + ## **See also:** ## * `excl proc <#excl,CritBitTree[T],string>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ @@ -178,10 +198,10 @@ proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = result = c.count == oldCount proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = - ## Returns true if `c` contains the given `key`. If the key does not exist - ## ``c[key] = val`` is performed. + ## Returns true if `c` contains the given `key`. If the key does not exist, + ## `c[key] = val` is performed. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,CritBitTree[void],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ @@ -204,10 +224,10 @@ proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = if not result: n.val = val proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = - ## Returns true if `c` contains the given `key`. If the key does not exist + ## Returns true if `c` contains the given `key`. If the key does not exist, ## it is inserted into `c`. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,CritBitTree[void],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ @@ -240,7 +260,7 @@ proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = proc incl*(c: var CritBitTree[void], key: string) = ## Includes `key` in `c`. ## - ## See also: + ## **See also:** ## * `excl proc <#excl,CritBitTree[T],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ runnableExamples: @@ -253,7 +273,7 @@ proc incl*(c: var CritBitTree[void], key: string) = proc incl*[T](c: var CritBitTree[T], key: string, val: T) = ## Inserts `key` with value `val` into `c`. ## - ## See also: + ## **See also:** ## * `excl proc <#excl,CritBitTree[T],string>`_ ## * `incl proc <#incl,CritBitTree[void],string>`_ runnableExamples: @@ -265,16 +285,11 @@ proc incl*[T](c: var CritBitTree[T], key: string, val: T) = n.val = val proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = - ## Puts a (key, value)-pair into `t`. + ## Alias for `incl <#incl,CritBitTree[T],string,T>`_. ## - ## See also: + ## **See also:** ## * `[] proc <#[],CritBitTree[T],string>`_ ## * `[] proc <#[],CritBitTree[T],string_2>`_ - runnableExamples: - var c: CritBitTree[int] - c["key"] = 42 - doAssert c["key"] == 42 - var n = rawInsert(c, key) n.val = val @@ -286,20 +301,20 @@ template get[T](c: CritBitTree[T], key: string): T = n.val func `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = - ## Retrieves the value at ``c[key]``. If `key` is not in `t`, the - ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether + ## Retrieves the value at `c[key]`. If `key` is not in `t`, the + ## `KeyError` exception is raised. One can check with `hasKey` whether ## the key exists. ## - ## See also: + ## **See also:** ## * `[] proc <#[],CritBitTree[T],string_2>`_ ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) func `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline.} = - ## Retrieves the value at ``c[key]``. The value can be modified. - ## If `key` is not in `t`, the ``KeyError`` exception is raised. + ## Retrieves the value at `c[key]`. The value can be modified. + ## If `key` is not in `t`, the `KeyError` exception is raised. ## - ## See also: + ## **See also:** ## * `[] proc <#[],CritBitTree[T],string>`_ ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) @@ -320,27 +335,24 @@ iterator leaves[T](n: Node[T]): Node[T] = iterator keys*[T](c: CritBitTree[T]): string = ## Yields all keys in lexicographical order. runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var keys: seq[string] - for key in c.keys: - keys.add(key) - doAssert keys == @["key1", "key2"] + from sequtils import toSeq + + let c = {"key1": 1, "key2": 2}.toCritBitTree + doAssert toSeq(c.keys) == @["key1", "key2"] for x in leaves(c.root): yield x.key iterator values*[T](c: CritBitTree[T]): T = ## Yields all values of `c` in the lexicographical order of the ## corresponding keys. + ## + ## **See also:** + ## * `mvalues iterator <#mvalues.i,CritBitTree[T]>`_ runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var vals: seq[int] - for val in c.values: - vals.add(val) - doAssert vals == @[1, 2] + from sequtils import toSeq + + let c = {"key1": 1, "key2": 2}.toCritBitTree + doAssert toSeq(c.values) == @[1, 2] for x in leaves(c.root): yield x.val @@ -348,40 +360,33 @@ iterator mvalues*[T](c: var CritBitTree[T]): var T = ## Yields all values of `c` in the lexicographical order of the ## corresponding keys. The values can be modified. ## - ## See also: + ## **See also:** ## * `values iterator <#values.i,CritBitTree[T]>`_ for x in leaves(c.root): yield x.val iterator items*[T](c: CritBitTree[T]): string = - ## Yields all keys in lexicographical order. - runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var keys: seq[string] - for key in c.items: - keys.add(key) - doAssert keys == @["key1", "key2"] - + ## Alias for `keys <#keys.i,CritBitTree[T]>`_. for x in leaves(c.root): yield x.key iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] = - ## Yields all (key, value)-pairs of `c`. + ## Yields all `(key, value)`-pairs of `c` in the lexicographical order of the + ## corresponding keys. + ## + ## **See also:** + ## * `mpairs iterator <#mpairs.i,CritBitTree[T]>`_ runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var ps: seq[tuple[key: string, val: int]] - for p in c.pairs: - ps.add(p) - doAssert ps == @[(key: "key1", val: 1), (key: "key2", val: 2)] + from sequtils import toSeq + + let c = {"key1": 1, "key2": 2}.toCritBitTree + doAssert toSeq(c.pairs) == @[(key: "key1", val: 1), (key: "key2", val: 2)] for x in leaves(c.root): yield (x.key, x.val) iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] = - ## Yields all (key, value)-pairs of `c`. The yielded values can be modified. + ## Yields all `(key, value)`-pairs of `c` in the lexicographical order of the + ## corresponding keys. The yielded values can be modified. ## - ## See also: + ## **See also:** ## * `pairs iterator <#pairs.i,CritBitTree[T]>`_ for x in leaves(c.root): yield (x.key, x.val) @@ -401,33 +406,14 @@ proc allprefixedAux[T](c: CritBitTree[T], key: string; if i >= p.key.len or p.key[i] != key[i]: return result = top -iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string; - longestMatch = false): string = - ## Yields all keys starting with `prefix`. If `longestMatch` is true, - ## the longest match is returned, it doesn't have to be a complete match then. - runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var keys: seq[string] - for key in c.itemsWithPrefix("key"): - keys.add(key) - doAssert keys == @["key1", "key2"] - - let top = allprefixedAux(c, prefix, longestMatch) - for x in leaves(top): yield x.key - iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): string = ## Yields all keys starting with `prefix`. runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var keys: seq[string] - for key in c.keysWithPrefix("key"): - keys.add(key) - doAssert keys == @["key1", "key2"] + from sequtils import toSeq + + let c = {"key1": 42, "key2": 43}.toCritBitTree + doAssert toSeq(c.keysWithPrefix("key")) == @["key1", "key2"] let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.key @@ -436,14 +422,14 @@ iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): T = ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. + ## + ## **See also:** + ## * `mvaluesWithPrefix iterator <#mvaluesWithPrefix.i,CritBitTree[T],string>`_ runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var vals: seq[int] - for val in c.valuesWithPrefix("key"): - vals.add(val) - doAssert vals == @[42, 43] + from sequtils import toSeq + + let c = {"key1": 42, "key2": 43}.toCritBitTree + doAssert toSeq(c.valuesWithPrefix("key")) == @[42, 43] let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.val @@ -453,43 +439,52 @@ iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string; ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. The values can be modified. ## - ## See also: + ## **See also:** ## * `valuesWithPrefix iterator <#valuesWithPrefix.i,CritBitTree[T],string>`_ let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield x.val +iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string; + longestMatch = false): string = + ## Alias for `keysWithPrefix <#keysWithPrefix.i,CritBitTree[T],string>`_. + let top = allprefixedAux(c, prefix, longestMatch) + for x in leaves(top): yield x.key + iterator pairsWithPrefix*[T](c: CritBitTree[T], prefix: string; longestMatch = false): tuple[key: string, val: T] = ## Yields all (key, value)-pairs of `c` starting with `prefix`. + ## + ## **See also:** + ## * `mpairsWithPrefix iterator <#mpairsWithPrefix.i,CritBitTree[T],string>`_ runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var ps: seq[tuple[key: string, val: int]] - for p in c.pairsWithPrefix("key"): - ps.add(p) - doAssert ps == @[(key: "key1", val: 42), (key: "key2", val: 43)] + from sequtils import toSeq + + let c = {"key1": 42, "key2": 43}.toCritBitTree + doAssert toSeq(c.pairsWithPrefix("key")) == @[(key: "key1", val: 42), (key: "key2", val: 43)] let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) iterator mpairsWithPrefix*[T](c: var CritBitTree[T], prefix: string; - longestMatch = false): tuple[key: string, val: var T] = + longestMatch = false): tuple[key: string, val: var T] = ## Yields all (key, value)-pairs of `c` starting with `prefix`. ## The yielded values can be modified. ## - ## See also: + ## **See also:** ## * `pairsWithPrefix iterator <#pairsWithPrefix.i,CritBitTree[T],string>`_ let top = allprefixedAux(c, prefix, longestMatch) for x in leaves(top): yield (x.key, x.val) func `$`*[T](c: CritBitTree[T]): string = - ## Turns `c` into a string representation. Example outputs: - ## ``{keyA: value, keyB: value}``, ``{:}`` - ## If `T` is void the outputs look like: - ## ``{keyA, keyB}``, ``{}``. + ## Turns `c` into a string representation. + runnableExamples: + doAssert $CritBitTree[int].default == "{:}" + doAssert $toCritBitTree({"key1": 1, "key2": 2}) == """{"key1": 1, "key2": 2}""" + doAssert $CritBitTree[void].default == "{}" + doAssert $toCritBitTree(["key1", "key2"]) == """{"key1", "key2"}""" + if c.len == 0: when T is void: result = "{}" @@ -516,7 +511,7 @@ func `$`*[T](c: CritBitTree[T]): string = result.add("}") func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = - ## Returns longest common prefix length of all keys of `c`. + ## Returns the length of the longest common prefix of all keys in `c`. ## If `c` is empty, returns 0. runnableExamples: var c: CritBitTree[void] @@ -536,35 +531,12 @@ func toCritBitTree*[T](pairs: openArray[(string, T)]): CritBitTree[T] {.since: ( runnableExamples: doAssert {"a": "0", "b": "1", "c": "2"}.toCritBitTree is CritBitTree[string] doAssert {"a": 0, "b": 1, "c": 2}.toCritBitTree is CritBitTree[int] + for item in pairs: result.incl item[0], item[1] func toCritBitTree*(items: openArray[string]): CritBitTree[void] {.since: (1, 3).} = ## Creates a new `CritBitTree` that contains the given `items`. runnableExamples: doAssert ["a", "b", "c"].toCritBitTree is CritBitTree[void] + for item in items: result.incl item - - -runnableExamples: - static: - block: - var critbitAsSet: CritBitTree[void] - doAssert critbitAsSet.len == 0 - incl critbitAsSet, "kitten" - doAssert critbitAsSet.len == 1 - incl critbitAsSet, "puppy" - doAssert critbitAsSet.len == 2 - incl critbitAsSet, "kitten" - doAssert critbitAsSet.len == 2 - incl critbitAsSet, "" - doAssert critbitAsSet.len == 3 - block: - var critbitAsDict: CritBitTree[int] - critbitAsDict["key"] = 42 - doAssert critbitAsDict["key"] == 42 - critbitAsDict["key"] = 0 - doAssert critbitAsDict["key"] == 0 - critbitAsDict["key"] = -int.high - doAssert critbitAsDict["key"] == -int.high - critbitAsDict["key"] = int.high - doAssert critbitAsDict["key"] == int.high From c80261bc00c2be59216f945e7915699f6adab690 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 4 Jan 2021 03:24:52 -0600 Subject: [PATCH 1757/4254] fix #12311 (#16578) --- lib/system.nim | 11 +++++++---- tests/system/tsystem_misc.nim | 7 +++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 618fd5dd7..e220ba7a3 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2412,10 +2412,13 @@ when notJSnotNims: {.error: "Only closure function and iterator are allowed!".} proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = - ## can be used to determine if a first class iterator has finished. - {.emit: """ - `result` = ((NI*) `x`.ClE_0)[1] < 0; - """.} + ## It can be used to determine if a first class iterator has finished. + when T is "iterator": + {.emit: """ + `result` = ((NI*) `x`.ClE_0)[1] < 0; + """.} + else: + {.error: "Only closure iterator is allowed!".} when defined(js): include "system/jssys" diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 508715905..cb879d3b3 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -210,3 +210,10 @@ block: # Ordinal # doAssert enum is Ordinal # fails # doAssert Ordinal is SomeOrdinal # doAssert SomeOrdinal is Ordinal + +block: + proc p() = discard + + doAssert not compiles(echo p.rawProc.repr) + doAssert not compiles(echo p.rawEnv.repr) + doAssert not compiles(echo p.finished) From 435f829348e12642540277ebeebe88fa6f289f80 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 4 Jan 2021 11:04:30 +0100 Subject: [PATCH 1758/4254] Improve sequtils documentation (#16559) * Improve sequtils documentation Uncomment assertions in tests * Use present tense --- lib/pure/collections/sequtils.nim | 157 +++++++++++++++--------------- tests/stdlib/tsequtils.nim | 6 +- 2 files changed, 81 insertions(+), 82 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 7aa885794..9d41a5389 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -8,13 +8,13 @@ # ## Although this module has `seq` in its name, it implements operations -## not only for `seq`:idx: type, but for three built-in container types under -## the `openArray` umbrella: +## not only for the `seq`:idx: type, but for three built-in container types +## under the `openArray` umbrella: ## * sequences ## * strings ## * array ## -## The system module defines several common functions, such as: +## The `system` module defines several common functions, such as: ## * `newSeq[T]` for creating new sequences of type `T` ## * `@` for converting arrays and strings to sequences ## * `add` for adding new elements to strings and sequences @@ -27,15 +27,15 @@ ## languages. ## ## For functional style programming you have different options at your disposal: -## * `sugar.collect macro`_ -## * pass `anonymous proc`_ -## * import `sugar module`_ and use -## `=> macro.m,untyped,untyped>`_ +## * the `sugar.collect macro`_ +## * pass an `anonymous proc`_ +## * import the `sugar module`_ and use +## the `=> macro.m,untyped,untyped>`_ ## * use `...It templates<#18>`_ ## (`mapIt<#mapIt.t,typed,untyped>`_, ## `filterIt<#filterIt.t,untyped,untyped>`_, etc.) ## -## The chaining of functions is possible thanks to the +## Chaining of functions is possible thanks to the ## `method call syntax`_. runnableExamples: @@ -44,11 +44,11 @@ runnableExamples: # Creating a sequence from 1 to 10, multiplying each member by 2, # keeping only the members which are not divisible by 6. let - foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0) - bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0) + foo = toSeq(1..10).map(x => x * 2).filter(x => x mod 6 != 0) + bar = toSeq(1..10).mapIt(it * 2).filterIt(it mod 6 != 0) baz = collect: for i in 1..10: - let j = 2*i + let j = 2 * i if j mod 6 != 0: j @@ -71,7 +71,8 @@ runnableExamples: doAssert (vowels is seq[char]) and (vowels == @['a', 'e', 'i', 'o', 'u']) doAssert foo.filterIt(it notin vowels).join == "sqtls s n wsm mdl" -## **See also**: +## See also +## ======== ## * `strutils module`_ for common string functions ## * `sugar module`_ for syntactic sugar macros ## * `algorithm module`_ for common generic algorithms @@ -90,11 +91,11 @@ when not defined(nimhygiene): macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped = ## Injects `expAlias` in caller scope, to avoid bugs involving multiple - ## substitution in macro arguments such as - ## https://github.com/nim-lang/Nim/issues/7187 + ## substitution in macro arguments such as + ## https://github.com/nim-lang/Nim/issues/7187. ## `evalOnceAs(myAlias, myExp)` will behave as `let myAlias = myExp` ## except when `letAssigneable` is false (e.g. to handle openArray) where - ## it just forwards `exp` unchanged + ## it just forwards `exp` unchanged. expectKind(expAlias, nnkIdent) var val = exp @@ -113,7 +114,7 @@ func concat*[T](seqs: varargs[seq[T]]): seq[T] = ## Takes several sequences' items and returns them inside a new sequence. ## All sequences must be of the same type. ## - ## See also: + ## **See also:** ## * `distribute func<#distribute,seq[T],Positive>`_ for a reverse ## operation ## @@ -183,7 +184,7 @@ func repeat*[T](x: T, n: Natural): seq[T] = func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = ## Returns a new sequence without duplicates. ## - ## Setting the optional argument ``isSorted`` to ``true`` (default: false) + ## Setting the optional argument `isSorted` to true (default: false) ## uses a faster algorithm for deduplication. ## runnableExamples: @@ -210,7 +211,7 @@ func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = ## Returns the index of the minimum value of `s`. - ## ``T`` needs to have a ``<`` operator. + ## `T` needs to have a `<` operator. runnableExamples: let a = @[1, 2, 3, 4] @@ -227,7 +228,7 @@ func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = ## Returns the index of the maximum value of `s`. - ## ``T`` needs to have a ``<`` operator. + ## `T` needs to have a `<` operator. runnableExamples: let a = @[1, 2, 3, 4] @@ -251,9 +252,9 @@ template zipImpl(s1, s2, retType: untyped): untyped = ## If one container is shorter, the remaining items in the longer container ## are discarded. ## - ## **Note**: For Nim 1.0.x and older version, ``zip`` returned a seq of - ## named tuple with fields ``a`` and ``b``. For Nim versions 1.1.x and newer, - ## ``zip`` returns a seq of unnamed tuples. + ## **Note**: For Nim 1.0.x and older version, `zip` returned a seq of + ## named tuples with fields `a` and `b`. For Nim versions 1.1.x and newer, + ## `zip` returns a seq of unnamed tuples. runnableExamples: let short = @[1, 2, 3] @@ -311,7 +312,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = ## `num` empty sequences. ## ## If `spread` is false and the length of `s` is not a multiple of `num`, the - ## func will max out the first sub-sequence with ``1 + len(s) div num`` + ## func will max out the first sub-sequence with `1 + len(s) div num` ## entries, leaving the remainder of elements to the last sequence. ## ## On the other hand, if `spread` is true, the func will distribute evenly @@ -361,16 +362,16 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): seq[S]{.inline.} = - ## Returns a new sequence with the results of `op` proc applied to every + ## Returns a new sequence with the results of the `op` proc applied to every ## item in the container `s`. ## - ## Since the input is not modified you can use it to + ## Since the input is not modified, you can use it to ## transform the type of the elements in the input container. ## ## Instead of using `map` and `filter`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version @@ -387,14 +388,13 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) {.inline.} = - ## Applies `op` to every item in `s` modifying it directly. + ## Applies `op` to every item in `s`, modifying it directly. ## - ## Note that container `s` must be declared as a ``var`` - ## and it is required for your input and output types to - ## be the same, since `s` is modified in-place. - ## The parameter function takes a ``var T`` type parameter. + ## Note that the container `s` must be declared as a `var`, + ## since `s` is modified in-place. + ## The parameter function takes a `var T` type parameter. ## - ## See also: + ## **See also:** ## * `applyIt template<#applyIt.t,untyped,untyped>`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## @@ -409,12 +409,12 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## - ## Note that container `s` must be declared as a ``var`` + ## Note that the container `s` must be declared as a `var` ## and it is required for your input and output types to ## be the same, since `s` is modified in-place. - ## The parameter function takes and returns a ``T`` type variable. + ## The parameter function takes and returns a `T` type variable. ## - ## See also: + ## **See also:** ## * `applyIt template<#applyIt.t,untyped,untyped>`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## @@ -426,7 +426,8 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) for i in 0 ..< s.len: s[i] = op(s[i]) proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = - ## Same as `apply` but for proc that do not return and do not mutate `s` directly. + ## Same as `apply` but for a proc that does not return anything + ## and does not mutate `s` directly. runnableExamples: var message: string apply([0, 1, 2, 3, 4], proc(item: int) = message.addInt item) @@ -435,12 +436,12 @@ proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1 iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = ## Iterates through a container `s` and yields every item that fulfills the - ## predicate `pred` (function that returns a `bool`). + ## predicate `pred` (a function that returns a `bool`). ## ## Instead of using `map` and `filter`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ @@ -458,13 +459,13 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] {.inline.} = - ## Returns a new sequence with all the items of `s` that fulfilled the - ## predicate `pred` (function that returns a `bool`). + ## Returns a new sequence with all the items of `s` that fulfill the + ## predicate `pred` (a function that returns a `bool`). ## ## Instead of using `map` and `filter`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ @@ -485,15 +486,15 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) {.inline.} = - ## Keeps the items in the passed sequence `s` if they fulfilled the - ## predicate `pred` (function that returns a `bool`). + ## Keeps the items in the passed sequence `s` if they fulfill the + ## predicate `pred` (a function that returns a `bool`). ## - ## Note that `s` must be declared as a ``var``. + ## Note that `s` must be declared as a `var`. ## ## Similar to the `filter proc<#filter,openArray[T],proc(T)>`_, ## but modifies the sequence directly. ## - ## See also: + ## **See also:** ## * `keepItIf template<#keepItIf.t,seq,untyped>`_ ## * `filter proc<#filter,openArray[T],proc(T)>`_ ## @@ -514,8 +515,8 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) setLen(s, pos) func delete*[T](s: var seq[T]; first, last: Natural) = - ## Deletes in the items of a sequence `s` at positions ``first..last`` - ## (including both ends of a range). + ## Deletes the items of a sequence `s` at positions `first..last` + ## (including both ends of the range). ## This modifies `s` itself, it does not return a copy. ## runnableExamples: @@ -527,8 +528,8 @@ func delete*[T](s: var seq[T]; first, last: Natural) = if first >= s.len: return var i = first - var j = min(len(s), last+1) - var newLen = len(s)-j+i + var j = min(len(s), last + 1) + var newLen = len(s) - j + i while i < newLen: when defined(gcDestructors): s[i] = move(s[j]) @@ -542,7 +543,7 @@ func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = ## Inserts items from `src` into `dest` at position `pos`. This modifies ## `dest` itself, it does not return a copy. ## - ## Notice that `src` and `dest` must be of the same type. + ## Note that the elements of `src` and `dest` must be of the same type. ## runnableExamples: var dest = @[1, 1, 1, 1, 1, 1, 1, 1] @@ -573,7 +574,7 @@ func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = template filterIt*(s, pred: untyped): untyped = - ## Returns a new sequence with all the items of `s` that fulfilled the + ## Returns a new sequence with all the items of `s` that fulfill the ## predicate `pred`. ## ## Unlike the `filter proc<#filter,openArray[T],proc(T)>`_ and @@ -584,7 +585,7 @@ template filterIt*(s, pred: untyped): untyped = ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `fliter proc<#filter,openArray[T],proc(T)>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ @@ -604,13 +605,13 @@ template filterIt*(s, pred: untyped): untyped = template keepItIf*(varSeq: seq, pred: untyped) = ## Keeps the items in the passed sequence (must be declared as a `var`) - ## if they fulfilled the predicate. + ## if they fulfill the predicate. ## ## Unlike the `keepIf proc<#keepIf,seq[T],proc(T)>`_, ## the predicate needs to be an expression using ## the `it` variable for testing, like: `keepItIf("abcxyz", it == 'x')`. ## - ## See also: + ## **See also:** ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## @@ -633,7 +634,7 @@ template keepItIf*(varSeq: seq, pred: untyped) = since (1, 1): template countIt*(s, pred: untyped): int = - ## Returns a count of all the items that fulfilled the predicate. + ## Returns a count of all the items that fulfill the predicate. ## ## The predicate needs to be an expression using ## the `it` variable for testing, like: `countIt(@[1, 2, 3], it > 2)`. @@ -654,19 +655,19 @@ proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = ## Iterates through a container and checks if every item fulfills the ## predicate. ## - ## See also: + ## **See also:** ## * `allIt template<#allIt.t,untyped,untyped>`_ ## * `any proc<#any,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] - assert all(numbers, proc (x: int): bool = return x < 10) == true - assert all(numbers, proc (x: int): bool = return x < 9) == false + assert all(numbers, proc (x: int): bool = x < 10) == true + assert all(numbers, proc (x: int): bool = x < 9) == false for i in s: if not pred(i): return false - return true + true template allIt*(s, pred: untyped): bool = ## Iterates through a container and checks if every item fulfills the @@ -676,7 +677,7 @@ template allIt*(s, pred: untyped): bool = ## the predicate needs to be an expression using ## the `it` variable for testing, like: `allIt("abba", it == 'a')`. ## - ## See also: + ## **See also:** ## * `all proc<#all,openArray[T],proc(T)>`_ ## * `anyIt template<#anyIt.t,untyped,untyped>`_ ## @@ -693,32 +694,32 @@ template allIt*(s, pred: untyped): bool = result proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = - ## Iterates through a container and checks if some item fulfills the - ## predicate. + ## Iterates through a container and checks if at least one item + ## fulfills the predicate. ## - ## See also: + ## **See also:** ## * `anyIt template<#anyIt.t,untyped,untyped>`_ ## * `all proc<#all,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] - assert any(numbers, proc (x: int): bool = return x > 8) == true - assert any(numbers, proc (x: int): bool = return x > 9) == false + assert any(numbers, proc (x: int): bool = x > 8) == true + assert any(numbers, proc (x: int): bool = x > 9) == false for i in s: if pred(i): return true - return false + false template anyIt*(s, pred: untyped): bool = - ## Iterates through a container and checks if some item fulfills the - ## predicate. + ## Iterates through a container and checks if at least one item + ## fulfills the predicate. ## ## Unlike the `any proc<#any,openArray[T],proc(T)>`_, ## the predicate needs to be an expression using ## the `it` variable for testing, like: `anyIt("abba", it == 'a')`. ## - ## See also: + ## **See also:** ## * `any proc<#any,openArray[T],proc(T)>`_ ## * `allIt template<#allIt.t,untyped,untyped>`_ ## @@ -827,7 +828,7 @@ template foldl*(sequence, operation: untyped): untyped = ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) - ## 3). ## - ## See also: + ## **See also:** ## * `foldl template<#foldl.t,,,>`_ with a starting parameter ## * `foldr template<#foldr.t,untyped,untyped>`_ ## @@ -872,7 +873,7 @@ template foldl*(sequence, operation, first): untyped = ## `a` and `b` for each step of the fold. The `first` parameter is the ## start value (the first `a`) and therefor defines the type of the result. ## - ## See also: + ## **See also:** ## * `foldr template<#foldr.t,untyped,untyped>`_ ## runnableExamples: @@ -903,7 +904,7 @@ template foldr*(sequence, operation: untyped): untyped = ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 - ## (3))). ## - ## See also: + ## **See also:** ## * `foldl template<#foldl.t,untyped,untyped>`_ ## * `foldl template<#foldl.t,,,>`_ with a starting parameter ## @@ -932,7 +933,7 @@ template foldr*(sequence, operation: untyped): untyped = result template mapIt*(s: typed, op: untyped): untyped = - ## Returns a new sequence with the results of `op` proc applied to every + ## Returns a new sequence with the results of the `op` proc applied to every ## item in the container `s`. ## ## Since the input is not modified you can use it to @@ -944,7 +945,7 @@ template mapIt*(s: typed, op: untyped): untyped = ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version @@ -1010,10 +1011,10 @@ template applyIt*(varSeq, op: untyped) = ## Convenience template around the mutable `apply` proc to reduce typing. ## ## The template injects the `it` variable which you can use directly in an - ## expression. The expression has to return the same type as the sequence you - ## are mutating. + ## expression. The expression has to return the same type as the elements + ## of the sequence you are mutating. ## - ## See also: + ## **See also:** ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## @@ -1081,7 +1082,7 @@ macro mapLiterals*(constructor, op: untyped; let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false) assert a == (1, (2, 3), 4) assert b == (1, (2.3, 3.4), 4) - + let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`) let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false) assert c == ("1", ("2", "3"), "4", ("5", "6")) diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index 94f6c3b08..385e6e651 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -410,13 +410,11 @@ block: # mapIt with direct openArray template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10) counter = 0 doAssert foo2(openArray[int]([identity(1), identity(2)])) == @[10, 20] - # TODO: this fails; not sure how to fix this case - # doAssert counter == 2 + doAssert counter == 2 counter = 0 doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1, 2] - # ditto - # doAssert counter == 2 + doAssert counter == 2 block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468 # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type From acf3715ea808d6ca5cfd94a340205d588fd50969 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 4 Jan 2021 04:34:13 -0600 Subject: [PATCH 1759/4254] continue #15456 add #pragma directives compiler support (#16472) * continue #15456 * follow the advice from juan_carlos --- compiler/ccgstmts.nim | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 367e693e9..8c419caac 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -653,12 +653,19 @@ proc genParForStmt(p: BProc, t: PNode) = initLocExpr(p, call[2], rangeB) # $n at the beginning because of #9710 - if call.len == 4: # `||`(a, b, annotation) - lineF(p, cpsStmts, "$n#pragma omp $4$n" & - "for ($1 = $2; $1 <= $3; ++$1)", - [forLoopVar.loc.rdLoc, - rangeA.rdLoc, rangeB.rdLoc, - call[3].getStr.rope]) + if call.len == 4: # procName(a, b, annotation) + if call[0].sym.name.s == "||": # `||`(a, b, annotation) + lineF(p, cpsStmts, "$n#pragma omp $4$n" & + "for ($1 = $2; $1 <= $3; ++$1)", + [forLoopVar.loc.rdLoc, + rangeA.rdLoc, rangeB.rdLoc, + call[3].getStr.rope]) + else: + lineF(p, cpsStmts, "$n#pragma $4$n" & + "for ($1 = $2; $1 <= $3; ++$1)", + [forLoopVar.loc.rdLoc, + rangeA.rdLoc, rangeB.rdLoc, + call[3].getStr.rope]) else: # `||`(a, b, step, annotation) var step: TLoc initLocExpr(p, call[3], step) From 7c2c1ad0724c1a20063a7669912cdaf8767145e0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 4 Jan 2021 04:40:56 -0600 Subject: [PATCH 1760/4254] enable tmath tests for JS backend (#16562) --- tests/stdlib/tmath.nim | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 1b6fb4e9f..4176f70e8 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,13 +1,12 @@ discard """ - action: run - matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" + targets: "c cpp js" """ -# xxx: fix bugs for js then add: targets:"c js" +## xxx enable matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" -import math, random, os -import unittest -import sets, tables +import std/[math, random, os] +import std/[unittest] +import std/[sets, tables] block: # random int block: # there might be some randomness From 349574d5745944ed2183b196113026f804393f29 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 4 Jan 2021 11:21:36 -0300 Subject: [PATCH 1761/4254] Add posix_utils.osReleaseFile (#16452) * Add posix_utils.osReleaseFile * Update lib/posix/posix_utils.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Update lib/posix/posix_utils.nim Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Add a basic sanity test * Add a basic sanity test * Add a basic sanity test * Add a basic sanity test * https://github.com/nim-lang/Nim/pull/16452#issuecomment-753364096 * Update lib/posix/posix_utils.nim Co-authored-by: Andreas Rumpf * Update lib/posix/posix_utils.nim Co-authored-by: Andreas Rumpf * Update changelog.md Co-authored-by: Andreas Rumpf Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: Andreas Rumpf --- changelog.md | 5 +++++ lib/posix/posix_utils.nim | 22 +++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index b10b9607a..11ac33872 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,11 @@ - Added `mimetypes.mimesMaxLen` thats equal to the length of the longest "mime" from `mimes`. + +- Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs. + https://www.freedesktop.org/software/systemd/man/os-release.html + + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index d083e20b9..7fd8b1fc9 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -11,7 +11,8 @@ # Where possible, contribute OS-independent procs in `os `_ instead. -import posix +import posix, parsecfg, os +import std/private/since type Uname* = object sysname*, nodename*, release*, version*, machine*: string @@ -107,3 +108,22 @@ proc mkdtemp*(prefix: string): string = if mkdtemp(tmpl) == nil: raise newException(OSError, $strerror(errno)) return $tmpl + +proc osReleaseFile*(): Config {.since: (1, 5).} = + ## Gets system identification from `os-release` file and returns it as a `parsecfg.Config`. + ## You also need to import the `parsecfg` module to gain access to this object. + ## The `os-release` file is an official Freedesktop.org open standard. + ## Available in Linux and BSD distributions, except Android and Android-based Linux. + ## `os-release` file is not available on Windows and OS X by design. + ## * https://www.freedesktop.org/software/systemd/man/os-release.html + runnableExamples: + import parsecfg + when defined(linux): + let data = osReleaseFile() + doAssert data.getSectionValue("", "NAME").len > 0 ## the data is up to each distro. + + # We do not use a {.strdefine.} because Standard says it *must* be that path. + for osReleaseFile in ["/etc/os-release", "/usr/lib/os-release"]: + if fileExists(osReleaseFile): + return loadConfig(osReleaseFile) + raise newException(IOError, "File not found: /etc/os-release, /usr/lib/os-release") From 0d67ad0bf38a69d110558a6eaa525e25cbf90648 Mon Sep 17 00:00:00 2001 From: Neelesh Chandola Date: Mon, 4 Jan 2021 22:16:39 +0530 Subject: [PATCH 1762/4254] Add backwards index overload for `[]` for JsonNode (#16501) * Add backwards index overload for `[]` for JsonNode * Add since Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> * Add docs, example, and changelog Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- changelog.md | 2 ++ lib/pure/json.nim | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/changelog.md b/changelog.md index 11ac33872..b97fcdd03 100644 --- a/changelog.md +++ b/changelog.md @@ -89,6 +89,8 @@ - Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs. https://www.freedesktop.org/software/systemd/man/os-release.html +- Added `BackwardsIndex` overload for `JsonNode`. + ## Language changes diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 063fad8b4..a9d0ed4cb 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -496,6 +496,19 @@ proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} = assert(node.kind == JArray) return node.elems[index] +proc `[]`*(node: JsonNode, index: BackwardsIndex): JsonNode {.inline, since: (1, 5, 1).} = + ## Gets the node at `array.len-i` in an array through the `^` operator. + ## + ## i.e. `j[^i]` is a shortcut for `j[j.len-i]`. + runnableExamples: + let + j = parseJson("[1,2,3,4,5]") + + doAssert j[^1].getInt == 5 + doAssert j[^2].getInt == 4 + + `[]`(node, node.len - int(index)) + proc hasKey*(node: JsonNode, key: string): bool = ## Checks if `key` exists in `node`. assert(node.kind == JObject) From 9531afac48aff3d5f0a6093742f60c95b043b08f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 4 Jan 2021 11:27:58 -0600 Subject: [PATCH 1763/4254] fix #16499 (#16514) --- lib/system/fatal.nim | 24 ++++++++++++++---------- tests/assert/tassert_c.nim | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index 761e0dd69..64ec9cda3 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -30,16 +30,20 @@ elif (defined(nimQuirky) or defined(nimPanics)) and not defined(nimscript): proc name(t: typedesc): string {.magic: "TypeTrait".} proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = - writeStackTrace() - var buf = newStringOfCap(200) - add(buf, "Error: unhandled exception: ") - add(buf, message) - add(buf, arg) - add(buf, " [") - add(buf, name exceptn) - add(buf, "]\n") - cstderr.rawWrite buf - quit 1 + when nimvm: + # TODO when doAssertRaises works in CT, add a test for it + raise (ref exceptn)(msg: message & arg) + else: + writeStackTrace() + var buf = newStringOfCap(200) + add(buf, "Error: unhandled exception: ") + add(buf, message) + add(buf, arg) + add(buf, " [") + add(buf, name exceptn) + add(buf, "]\n") + cstderr.rawWrite buf + quit 1 proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = sysFatal(exceptn, message, "") diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index c6a2eadb1..024175cbf 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -8,7 +8,7 @@ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo assertions.nim(30) failedAssertImpl assertions.nim(23) raiseAssert -fatal.nim(49) sysFatal""" +fatal.nim(53) sysFatal""" proc tmatch(x, p: string): bool = var i = 0 From 80c8f06663658e12fcdcd2d36a0ee38683de552a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 4 Jan 2021 18:41:02 +0100 Subject: [PATCH 1764/4254] Add test for static proc/lambda params (#16584) --- tests/statictypes/tstatictypes.nim | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 8817e07a0..41c060138 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -366,3 +366,19 @@ block: block: type Foo[N: static int] = array[int32(0) .. int32(N), float] type T = Foo[3] + + +#------------------------------------------------------------------------------------------ +# static proc/lambda param +func isSorted2[T](a: openArray[T], cmp: static proc(x, y: T): bool {.inline.}): bool = + result = true + for i in 0.. Date: Mon, 4 Jan 2021 19:44:50 +0100 Subject: [PATCH 1765/4254] make --gc:arc --exceptions:quirky work again [backport:1.4] (#16583) * make --gc:arc --exceptions:quirky work again [backport:1.4] * fixes #16404 [backport:1.4] --- compiler/commands.nim | 4 ++++ compiler/main.nim | 2 -- lib/system/embedded.nim | 10 ++++++++++ lib/system/strmantle.nim | 20 ++++++++++---------- tests/manyloc/standalone/panicoverride.nim | 5 ----- tests/manyloc/standalone2/panicoverride.nim | 14 ++++++++++++++ tests/manyloc/standalone2/tavr.nim | 7 +++++++ tests/manyloc/standalone2/tavr.nim.cfg | 4 ++++ 8 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 tests/manyloc/standalone2/panicoverride.nim create mode 100644 tests/manyloc/standalone2/tavr.nim create mode 100644 tests/manyloc/standalone2/tavr.nim.cfg diff --git a/compiler/commands.nim b/compiler/commands.nim index b52148668..9fb9b7e6e 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -572,6 +572,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: defineSymbol(conf.symbols, "nimSeqsV2") defineSymbol(conf.symbols, "nimV2") + if conf.exc == excNone and conf.backend != backendCpp: + conf.exc = excGoto of "orc": conf.selectedGC = gcOrc defineSymbol(conf.symbols, "gcdestructors") @@ -581,6 +583,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: defineSymbol(conf.symbols, "nimSeqsV2") defineSymbol(conf.symbols, "nimV2") + if conf.exc == excNone and conf.backend != backendCpp: + conf.exc = excGoto of "hooks": conf.selectedGC = gcHooks defineSymbol(conf.symbols, "gchooks") diff --git a/compiler/main.nim b/compiler/main.nim index 868198268..4c67aaea7 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -192,8 +192,6 @@ proc mainCommand*(graph: ModuleGraph) = # A better solution might be to fix system.nim undefSymbol(conf.symbols, "useNimRtl") of backendInvalid: doAssert false - if conf.selectedGC in {gcArc, gcOrc} and conf.backend != backendCpp: - conf.exc = excGoto proc compileToBackend() = customizeForBackend(conf.backend) diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index c4f15a336..258558c3f 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -44,3 +44,13 @@ proc setControlCHook(hook: proc () {.noconv.}) = discard proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = sysFatal(ReraiseDefect, "exception handling is not available") + +when gotoBasedExceptions: + var nimInErrorMode {.threadvar.}: bool + + proc nimErrorFlag(): ptr bool {.compilerRtl, inl.} = + result = addr(nimInErrorMode) + + proc nimTestErrorFlag() {.compilerRtl.} = + if nimInErrorMode: + sysFatal(ReraiseDefect, "exception handling is not available") diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index b5d275e25..7553f921b 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -24,26 +24,26 @@ const digitsTable = "0001020304050607080910111213141516171819" & # else: # res.add $i # doAssert res == digitsTable - + func digits10(num: uint64): int {.noinline.} = - if num < 10: + if num < 10'u64: result = 1 - elif num < 100: + elif num < 100'u64: result = 2 - elif num < 1_000: + elif num < 1_000'u64: result = 3 - elif num < 10_000: + elif num < 10_000'u64: result = 4 - elif num < 100_000: + elif num < 100_000'u64: result = 5 - elif num < 1_000_000: + elif num < 1_000_000'u64: result = 6 - elif num < 10_000_000: + elif num < 10_000_000'u64: result = 7 - elif num < 100_000_000: + elif num < 100_000_000'u64: result = 8 - elif num < 1_000_000_000: + elif num < 1_000_000_000'u64: result = 9 elif num < 10_000_000_000'u64: result = 10 diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index d9b3f4388..c0b8bb030 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -11,9 +11,4 @@ proc panic(s: string) {.noreturn.} = rawoutput(s) exit(1) -# Alternatively we also could implement these 2 here: -# -# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.} -# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.} - {.pop.} diff --git a/tests/manyloc/standalone2/panicoverride.nim b/tests/manyloc/standalone2/panicoverride.nim new file mode 100644 index 000000000..c0b8bb030 --- /dev/null +++ b/tests/manyloc/standalone2/panicoverride.nim @@ -0,0 +1,14 @@ + +proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} +proc exit(code: int) {.importc, header: "", cdecl.} + +{.push stack_trace: off, profiler:off.} + +proc rawoutput(s: string) = + printf("%s\n", s) + +proc panic(s: string) {.noreturn.} = + rawoutput(s) + exit(1) + +{.pop.} diff --git a/tests/manyloc/standalone2/tavr.nim b/tests/manyloc/standalone2/tavr.nim new file mode 100644 index 000000000..6cbc5c699 --- /dev/null +++ b/tests/manyloc/standalone2/tavr.nim @@ -0,0 +1,7 @@ +# bug #16404 + +proc printf(frmt: cstring) {.varargs, header: "", cdecl.} + +var x = 0 +inc x +printf("hi %ld\n", x+4777) diff --git a/tests/manyloc/standalone2/tavr.nim.cfg b/tests/manyloc/standalone2/tavr.nim.cfg new file mode 100644 index 000000000..e5291969d --- /dev/null +++ b/tests/manyloc/standalone2/tavr.nim.cfg @@ -0,0 +1,4 @@ +--gc:arc +--cpu:avr +--os:standalone +--compileOnly From 00144ee4e9857ad578597bed3f51176f252d6b13 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 4 Jan 2021 10:45:46 -0800 Subject: [PATCH 1766/4254] fix #16576: honor matrix in testament by making such tests non joinable (#16577) * refs #16576: honor matrix in testament by making such tests non joinable * add tests + misc fixes * fix test for i386 with -d:danger --- testament/categories.nim | 10 ++++++++-- testament/specs.nim | 1 + testament/testament.nim | 13 +++++++------ tests/stdlib/tmath.nim | 10 ++++++---- tests/testament/t16576.nim | 7 +++++++ tests/testament/tjoinable.nim | 8 ++++++++ 6 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 tests/testament/t16576.nim create mode 100644 tests/testament/tjoinable.nim diff --git a/testament/categories.nim b/testament/categories.nim index c894bc9f9..39f0aaa27 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -49,6 +49,7 @@ proc isTestFile*(file: string): bool = # ---------------- IC tests --------------------------------------------- +# xxx deadcode proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) = const tooltests = ["compiler/nim.nim", "tools/nimgrep.nim"] @@ -583,6 +584,8 @@ proc processSingleTest(r: var TResults, cat: Category, options, test: string, ta testSpec r, makeTest(test, options, cat), targets proc isJoinableSpec(spec: TSpec): bool = + # xxx simplify implementation using a whitelist of fields that are allowed to be + # set to non-default values (use `fieldPairs`), to avoid issues like bug #16576. result = not spec.sortoutput and spec.action == actionRun and not fileExists(spec.file.changeFileExt("cfg")) and @@ -595,6 +598,7 @@ proc isJoinableSpec(spec: TSpec): bool = spec.exitCode == 0 and spec.input.len == 0 and spec.nimout.len == 0 and + spec.matrix.len == 0 and spec.outputCheck != ocSubstr and spec.ccodeCheck.len == 0 and (spec.targets == {} or spec.targets == {targetC}) @@ -656,7 +660,7 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = writeFile(megatestFile, megatest) let root = getCurrentDir() - let args = ["c", "--nimCache:" & outDir, "-d:testing", "--listCmd", "--path:" & root, megatestFile] + let args = ["c", "--nimCache:" & outDir, "-d:testing", "-d:nimMegatest", "--listCmd", "--path:" & root, megatestFile] var (cmdLine, buf, exitCode) = execCmdEx2(command = compilerPrefix, args = args, input = "") if exitCode != 0: echo "$ " & cmdLine & "\n" & buf.string @@ -759,7 +763,9 @@ proc processCategory(r: var TResults, cat: Category, testSpec r, test inc testsRun if testsRun == 0: - const whiteListedDirs = ["deps"] + const whiteListedDirs = ["deps", "htmldocs", "pkgs"] + # `pkgs` because bug #16556 creates `pkgs` dirs and this can affect some users + # that try an old version of choosenim. doAssert cat.string in whiteListedDirs, "Invalid category specified: '$#' not in whilelist: $#" % [cat.string, $whiteListedDirs] diff --git a/testament/specs.nim b/testament/specs.nim index a7f0fd4bb..58fe7bf4f 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -71,6 +71,7 @@ type disabled, enabled, leaking TSpec* = object + # xxx make sure `isJoinableSpec` takes into account each field here. action*: TTestAction file*, cmd*: string input*: string diff --git a/testament/testament.nim b/testament/testament.nim index 7b1a25bf0..5686da81c 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -88,11 +88,12 @@ proc isSuccess(input: string): bool = # not clear how to do the equivalent of pkg/regex's: re"FOO(.*?)BAR" in pegs input.startsWith("Hint: ") and input.endsWith("[SuccessX]") -proc normalizeMsg(s: string): string = - result = newStringOfCap(s.len+1) - for x in splitLines(s): - if result.len > 0: result.add '\L' - result.add x.strip +when false: # deadcode + proc normalizeMsg(s: string): string = + result = newStringOfCap(s.len+1) + for x in splitLines(s): + if result.len > 0: result.add '\L' + result.add x.strip proc getFileDir(filename: string): string = result = filename.splitFile().dir @@ -794,7 +795,7 @@ proc main() = var subPath = p.key.string let nimRoot = currentSourcePath / "../.." # makes sure points to this regardless of cwd or which nim is used to compile this. - doAssert existsDir(nimRoot/testsDir) # sanity check + doAssert dirExists(nimRoot/testsDir) # sanity check if subPath.isAbsolute: subPath = subPath.relativePath(nimRoot) # at least one directory is required in the path, to use as a category name let pathParts = subPath.relativePath(testsDir).split({DirSep, AltSep}) diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 4176f70e8..16c274032 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,8 +1,10 @@ discard """ targets: "c cpp js" + matrix:"; -d:danger" """ -## xxx enable matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" +# xxx: there should be a test with `-d:nimTmathCase2 -d:danger --passc:-ffast-math`, +# but it requires disabling certain lines with `when not defined(nimTmathCase2)` import std/[math, random, os] import std/[unittest] @@ -156,13 +158,13 @@ block: doAssert(erf(6.0) > erf(5.0)) doAssert(erfc(6.0) < erfc(5.0)) - - # Function for approximate comparison of floats proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) + # Function for approximate comparison of floats + # xxx use `almostEqual` block: # prod doAssert prod([1, 2, 3, 4]) == 24 - doAssert prod([1.5, 3.4]) == 5.1 + doAssert prod([1.5, 3.4]).almostEqual 5.1 let x: seq[float] = @[] doAssert prod(x) == 1.0 diff --git a/tests/testament/t16576.nim b/tests/testament/t16576.nim new file mode 100644 index 000000000..8d0dd57e3 --- /dev/null +++ b/tests/testament/t16576.nim @@ -0,0 +1,7 @@ +discard """ + matrix:"-d:nimTest_t16576" +""" + +# bug #16576 +doAssert defined(nimTest_t16576) +doAssert not defined(nimMegatest) diff --git a/tests/testament/tjoinable.nim b/tests/testament/tjoinable.nim new file mode 100644 index 000000000..7a0ad7985 --- /dev/null +++ b/tests/testament/tjoinable.nim @@ -0,0 +1,8 @@ +discard """ + output: "ok" +""" + +# checks that this is joinable +doAssert defined(testing) +doAssert defined(nimMegatest) +echo "ok" # intentional to make sure this doesn't prevent `isJoinableSpec` From fe20492f0524aa640d468e31b7b44ebab4ae47ad Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 4 Jan 2021 12:54:33 -0600 Subject: [PATCH 1767/4254] clean up the docs of some modules under lib/js (#16579) --- lib/js/asyncjs.nim | 30 ++++++++--------- lib/js/dom.nim | 2 +- lib/js/dom_extensions.nim | 2 +- lib/js/jsconsole.nim | 2 +- lib/js/jscore.nim | 4 +-- lib/js/jsffi.nim | 68 +++++++++++++++++++-------------------- lib/js/jsre.nim | 2 +- tools/kochdocs.nim | 1 - 8 files changed, 55 insertions(+), 56 deletions(-) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 219b1bed5..76b948e6a 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -11,11 +11,11 @@ ## and libraries, writing async procedures in Nim and converting callback-based code ## to promises. ## -## A Nim procedure is asynchronous when it includes the ``{.async.}`` pragma. It -## should always have a ``Future[T]`` return type or not have a return type at all. -## A ``Future[void]`` return type is assumed by default. +## A Nim procedure is asynchronous when it includes the `{.async.}` pragma. It +## should always have a `Future[T]` return type or not have a return type at all. +## A `Future[void]` return type is assumed by default. ## -## This is roughly equivalent to the ``async`` keyword in JavaScript code. +## This is roughly equivalent to the `async` keyword in JavaScript code. ## ## .. code-block:: nim ## proc loadGame(name: string): Future[Game] {.async.} = @@ -28,14 +28,14 @@ ## // code ## } ## -## A call to an asynchronous procedure usually needs ``await`` to wait for -## the completion of the ``Future``. +## A call to an asynchronous procedure usually needs `await` to wait for +## the completion of the `Future`. ## ## .. code-block:: nim ## var game = await loadGame(name) ## ## Often, you might work with callback-based API-s. You can wrap them with -## asynchronous procedures using promises and ``newPromise``: +## asynchronous procedures using promises and `newPromise`: ## ## .. code-block:: nim ## proc loadGame(name: string): Future[Game] = @@ -44,7 +44,7 @@ ## resolve(game) ## return promise ## -## Forward definitions work properly, you just need to always add the ``{.async.}`` pragma: +## Forward definitions work properly, you just need to always add the `{.async.}` pragma: ## ## .. code-block:: nim ## proc loadGame(name: string): Future[Game] {.async.} @@ -57,10 +57,10 @@ ## If you need to use this module with older versions of JavaScript, you can ## use a tool that backports the resulting JavaScript code, as babel. -import jsffi -import macros +import std/jsffi +import std/macros -when not defined(js) and not defined(nimdoc) and not defined(nimsuggest): +when not defined(js) and not defined(nimsuggest): {.fatal: "Module asyncjs is designed to be used with the JavaScript backend.".} type @@ -69,7 +69,7 @@ type ## Wraps the return type of an asynchronous procedure. PromiseJs* {.importcpp: "Promise".} = ref object - ## A JavaScript Promise + ## A JavaScript Promise. proc replaceReturn(node: var NimNode) = @@ -139,7 +139,7 @@ proc generateJsasync(arg: NimNode): NimNode = macro async*(arg: untyped): untyped = ## Macro which converts normal procedures into - ## javascript-compatible async procedures + ## javascript-compatible async procedures. if arg.kind == nnkStmtList: result = newStmtList() for oneProc in arg: @@ -149,8 +149,8 @@ macro async*(arg: untyped): untyped = proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".} ## A helper for wrapping callback-based functions - ## into promises and async procedures + ## into promises and async procedures. proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importcpp: "(new Promise(#))".} ## A helper for wrapping callback-based functions - ## into promises and async procedures + ## into promises and async procedures. diff --git a/lib/js/dom.nim b/lib/js/dom.nim index d4e8ce86a..59d1381c7 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -10,7 +10,7 @@ ## Declaration of the Document Object Model for the `JavaScript backend ## `_. import std/private/since -when not defined(js) and not defined(Nimdoc): +when not defined(js): {.error: "This module only works on the JavaScript platform".} const diff --git a/lib/js/dom_extensions.nim b/lib/js/dom_extensions.nim index 851ec0c5f..f7d37f4bf 100644 --- a/lib/js/dom_extensions.nim +++ b/lib/js/dom_extensions.nim @@ -1,4 +1,4 @@ -import dom +import std/dom {.push importcpp.} proc elementsFromPoint*(n: DocumentOrShadowRoot; x, y: float): seq[Element] diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index 5b9893e75..87dd9eeec 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -12,7 +12,7 @@ import std/private/since, std/private/miscdollars # toLocation -when not defined(js) and not defined(Nimdoc): +when not defined(js): {.error: "This module only works on the JavaScript platform".} type Console* = ref object of JsRoot diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 2e2bd2402..3af33b535 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -11,10 +11,10 @@ ## ## Unless your application has very ## specific requirements and solely targets JavaScript, you should be using -## the relevant functions in the ``math``, ``json``, and ``times`` stdlib +## the relevant functions in the `math`, `json`, and `times` stdlib ## modules instead. -when not defined(js) and not defined(Nimdoc): +when not defined(js): {.error: "This module only works on the JavaScript platform".} type diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 15727c9f7..8220013c1 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -8,8 +8,8 @@ # ## This Module implements types and macros to facilitate the wrapping of, and -## interaction with JavaScript libraries. Using the provided types ``JsObject`` -## and ``JsAssoc`` together with the provided macros allows for smoother +## interaction with JavaScript libraries. Using the provided types `JsObject` +## and `JsAssoc` together with the provided macros allows for smoother ## interfacing with JavaScript, allowing for example quick and easy imports of ## JavaScript variables: @@ -24,18 +24,18 @@ runnableExamples: proc jq(selector: JsObject): JsObject {.importcpp: "$$(#)".} # Use jQuery to make the following code run, after the document is ready. - # This uses an experimental ``.()`` operator for ``JsObject``, to emit - # JavaScript calls, when no corresponding proc exists for ``JsObject``. + # This uses an experimental `.()` operator for `JsObject`, to emit + # JavaScript calls, when no corresponding proc exists for `JsObject`. proc main = jq(document).ready(proc() = console.log("Hello JavaScript!") ) -when not defined(js) and not defined(nimdoc) and not defined(nimsuggest): +when not defined(js) and not defined(nimsuggest): {.fatal: "Module jsFFI is designed to be used with the JavaScript backend.".} -import macros, tables +import std/[macros, tables] const setImpl = "#[#] = #" @@ -93,21 +93,21 @@ type var jsArguments* {.importc: "arguments", nodecl}: JsObject - ## JavaScript's arguments pseudo-variable + ## JavaScript's arguments pseudo-variable. jsNull* {.importc: "null", nodecl.}: JsObject - ## JavaScript's null literal + ## JavaScript's null literal. jsUndefined* {.importc: "undefined", nodecl.}: JsObject - ## JavaScript's undefined literal + ## JavaScript's undefined literal. jsDirname* {.importc: "__dirname", nodecl.}: cstring - ## JavaScript's __dirname pseudo-variable + ## JavaScript's __dirname pseudo-variable. jsFilename* {.importc: "__filename", nodecl.}: cstring - ## JavaScript's __filename pseudo-variable + ## JavaScript's __filename pseudo-variable. proc isNull*[T](x: T): bool {.noSideEffect, importcpp: "(# === null)".} - ## check if a value is exactly null + ## Checks if a value is exactly null. proc isUndefined*[T](x: T): bool {.noSideEffect, importcpp: "(# === undefined)".} - ## check if a value is exactly undefined + ## Checks if a value is exactly undefined. # Exceptions type @@ -122,7 +122,7 @@ type # New proc newJsObject*: JsObject {.importcpp: "{@}".} - ## Creates a new empty JsObject + ## Creates a new empty JsObject. proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {.importcpp: "{@}".} ## Creates a new empty JsAssoc with key type `K` and value type `V`. @@ -137,20 +137,20 @@ proc jsTypeOf*(x: JsObject): cstring {.importcpp: "typeof(#)".} proc jsNew*(x: auto): JsObject {.importcpp: "(new #)".} ## Turns a regular function call into an invocation of the - ## JavaScript's `new` operator + ## JavaScript's `new` operator. proc jsDelete*(x: auto): JsObject {.importcpp: "(delete #)".} - ## JavaScript's `delete` operator + ## JavaScript's `delete` operator. proc require*(module: cstring): JsObject {.importc.} - ## JavaScript's `require` function + ## JavaScript's `require` function. # Conversion to and from JsObject proc to*(x: JsObject, T: typedesc): T {.importcpp: "(#)".} ## Converts a JsObject `x` to type `T`. proc toJs*[T](val: T): JsObject {.importcpp: "(#)".} - ## Converts a value of any type to type JsObject + ## Converts a value of any type to type JsObject. template toJs*(s: string): JsObject = cstring(s).toJs @@ -161,7 +161,7 @@ macro jsFromAst*(n: untyped): untyped = return quote: toJs(`result`) proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".} - ## Concatenation operator for JavaScript strings + ## Concatenation operator for JavaScript strings. proc `+` *(x, y: JsObject): JsObject {.importcpp: "(# + #)".} proc `-` *(x, y: JsObject): JsObject {.importcpp: "(# - #)".} @@ -186,24 +186,24 @@ proc `not`*(x: JsObject): JsObject {.importcpp: "(!#)".} proc `in` *(x, y: JsObject): JsObject {.importcpp: "(# in #)".} proc `[]`*(obj: JsObject, field: cstring): JsObject {.importcpp: getImpl.} - ## Return the value of a property of name `field` from a JsObject `obj`. + ## Returns the value of a property of name `field` from a JsObject `obj`. proc `[]`*(obj: JsObject, field: int): JsObject {.importcpp: getImpl.} - ## Return the value of a property of name `field` from a JsObject `obj`. + ## Returns the value of a property of name `field` from a JsObject `obj`. proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {.importcpp: setImpl.} - ## Set the value of a property of name `field` in a JsObject `obj` to `v`. + ## Sets the value of a property of name `field` in a JsObject `obj` to `v`. proc `[]=`*[T](obj: JsObject, field: int, val: T) {.importcpp: setImpl.} - ## Set the value of a property of name `field` in a JsObject `obj` to `v`. + ## Sets the value of a property of name `field` in a JsObject `obj` to `v`. proc `[]`*[K: JsKey, V](obj: JsAssoc[K, V], field: K): V {.importcpp: getImpl.} - ## Return the value of a property of name `field` from a JsAssoc `obj`. + ## Returns the value of a property of name `field` from a JsAssoc `obj`. proc `[]=`*[K: JsKey, V](obj: JsAssoc[K, V], field: K, val: V) {.importcpp: setImpl.} - ## Set the value of a property of name `field` in a JsAssoc `obj` to `v`. + ## Sets the value of a property of name `field` in a JsAssoc `obj` to `v`. proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V = obj[cstring(field)] @@ -212,7 +212,7 @@ proc `[]=`*[V](obj: JsAssoc[cstring, V], field: string, val: V) = obj[cstring(field)] = val proc `==`*(x, y: JsRoot): bool {.importcpp: "(# === #)".} - ## Compare two JsObjects or JsAssocs. Be careful though, as this is comparison + ## Compares two JsObjects or JsAssocs. Be careful though, as this is comparison ## like in JavaScript, so if your JsObjects are in fact JavaScript Objects, ## and not strings or numbers, this is a *comparison of references*. @@ -341,7 +341,7 @@ macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V], # Iterators: iterator pairs*(obj: JsObject): (cstring, JsObject) = - ## Yields tuples of type ``(cstring, JsObject)``, with the first entry + ## Yields tuples of type `(cstring, JsObject)`, with the first entry ## being the `name` of a fields in the JsObject and the second being its ## value wrapped into a JsObject. var k: cstring @@ -370,7 +370,7 @@ iterator keys*(obj: JsObject): cstring = {.emit: "}".} iterator pairs*[K: JsKey, V](assoc: JsAssoc[K, V]): (K,V) = - ## Yields tuples of type ``(K, V)``, with the first entry + ## Yields tuples of type `(K, V)`, with the first entry ## being a `key` in the JsAssoc and the second being its corresponding value. var k: cstring var v: V @@ -400,16 +400,16 @@ iterator keys*[K: JsKey, V](assoc: JsAssoc[K, V]): K = # Literal generation macro `{}`*(typ: typedesc, xs: varargs[untyped]): auto = - ## Takes a ``typedesc`` as its first argument, and a series of expressions of - ## type ``key: value``, and returns a value of the specified type with each - ## field ``key`` set to ``value``, as specified in the arguments of ``{}``. + ## Takes a `typedesc` as its first argument, and a series of expressions of + ## type `key: value`, and returns a value of the specified type with each + ## field `key` set to `value`, as specified in the arguments of `{}`. ## ## Example: ## ## .. code-block:: nim ## ## # Let's say we have a type with a ton of fields, where some fields do not - ## # need to be set, and we do not want those fields to be set to ``nil``: + ## # need to be set, and we do not want those fields to be set to `nil`: ## type ## ExtremelyHugeType = ref object ## a, b, c, d, e, f, g: int @@ -464,7 +464,7 @@ proc replaceSyms(n: NimNode): NimNode = macro bindMethod*(procedure: typed): auto = ## Takes the name of a procedure and wraps it into a lambda missing the first - ## argument, which passes the JavaScript builtin ``this`` as the first + ## argument, which passes the JavaScript builtin `this` as the first ## argument to the procedure. Returns the resulting lambda. ## ## Example: @@ -477,7 +477,7 @@ macro bindMethod*(procedure: typed): auto = ## return this.a + 42; ## }; ## - ## We can achieve this using the ``bindMethod`` macro: + ## We can achieve this using the `bindMethod` macro: ## ## .. code-block:: nim ## let obj = JsObject{ a: 10 } diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index f5c3cc1ac..7be7221bc 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -11,7 +11,7 @@ runnableExamples: doAssert jsregex.test(r"0123456789abcd") -when not defined(js) and not defined(Nimdoc): +when not defined(js): {.error: "This module only works on the JavaScript platform".} type RegExp* {.importjs.} = object ## Regular Expressions for JavaScript target. diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 0cfedce47..81117dd52 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -136,7 +136,6 @@ lib/wrappers/openssl.nim lib/posix/posix.nim lib/posix/linux.nim lib/posix/termios.nim -lib/js/jscore.nim """.splitWhitespace() # some of these are include files so shouldn't be docgen'd From d2f4f25b5660454c2483ab1249195b3a3d037588 Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 4 Jan 2021 21:46:36 +0100 Subject: [PATCH 1768/4254] fix #16506 by changing the example (#16580) Co-authored-by: Andreas Rumpf --- lib/pure/asynchttpserver.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index f3f59baf8..4500d994e 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -35,7 +35,7 @@ ## server.listen Port(8080) ## while true: ## if server.shouldAcceptRequest(): -## asyncCheck server.acceptRequest(cb) +## await server.acceptRequest(cb) ## else: ## poll() ## @@ -382,7 +382,7 @@ when not defined(testing) and isMainModule: server.listen Port(5555) while true: if server.shouldAcceptRequest(): - asyncCheck server.acceptRequest(cb) + await server.acceptRequest(cb) else: poll() From b2a53795dcfa96445e27eaea2147d2596a8e4994 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 5 Jan 2021 05:29:21 -0800 Subject: [PATCH 1769/4254] merge tmath_misc.nim into tmath.nim (#16591) --- tests/stdlib/tmath.nim | 13 +++++++++++++ tests/stdlib/tmath_misc.nim | 24 ------------------------ 2 files changed, 13 insertions(+), 24 deletions(-) delete mode 100644 tests/stdlib/tmath_misc.nim diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 16c274032..a4b493b93 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -357,5 +357,18 @@ template main = doAssert copySign(10.0, -NaN) == 10.0 doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 # fails in VM + block: + doAssert 1.0 / abs(-0.0) == Inf + doAssert 1.0 / abs(0.0) == Inf + doAssert -1.0 / abs(-0.0) == -Inf + doAssert -1.0 / abs(0.0) == -Inf + doAssert abs(0.0) == 0.0 + doAssert abs(0.0'f32) == 0.0'f32 + + doAssert abs(Inf) == Inf + doAssert abs(-Inf) == Inf + doAssert abs(NaN).isNaN + doAssert abs(-NaN).isNaN + static: main() main() diff --git a/tests/stdlib/tmath_misc.nim b/tests/stdlib/tmath_misc.nim deleted file mode 100644 index 978e3e94d..000000000 --- a/tests/stdlib/tmath_misc.nim +++ /dev/null @@ -1,24 +0,0 @@ -discard """ - targets: "c js" -""" - -# TODO merge this to tmath.nim once tmath.nim supports js target - -import math - -proc main() = - block: - doAssert 1.0 / abs(-0.0) == Inf - doAssert 1.0 / abs(0.0) == Inf - doAssert -1.0 / abs(-0.0) == -Inf - doAssert -1.0 / abs(0.0) == -Inf - doAssert abs(0.0) == 0.0 - doAssert abs(0.0'f32) == 0.0'f32 - - doAssert abs(Inf) == Inf - doAssert abs(-Inf) == Inf - doAssert abs(NaN).isNaN - doAssert abs(-NaN).isNaN - -static: main() -main() From 9f1dd5c00f3ef5fdf221732bc2a70553b21426e5 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 5 Jan 2021 15:52:24 +0100 Subject: [PATCH 1770/4254] Make tmath test more strict (#16593) Don't use approximate equality when comparing numbers that are representable with perfect precision. --- tests/stdlib/tmath.nim | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index a4b493b93..fbc6b80ad 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -170,19 +170,19 @@ block: block: # round() tests # Round to 0 decimal places - doAssert round(54.652) ==~ 55.0 - doAssert round(54.352) ==~ 54.0 - doAssert round(-54.652) ==~ -55.0 - doAssert round(-54.352) ==~ -54.0 - doAssert round(0.0) ==~ 0.0 + doAssert round(54.652) == 55.0 + doAssert round(54.352) == 54.0 + doAssert round(-54.652) == -55.0 + doAssert round(-54.352) == -54.0 + doAssert round(0.0) == 0.0 block: # splitDecimal() tests - doAssert splitDecimal(54.674).intpart ==~ 54.0 + doAssert splitDecimal(54.674).intpart == 54.0 doAssert splitDecimal(54.674).floatpart ==~ 0.674 - doAssert splitDecimal(-693.4356).intpart ==~ -693.0 + doAssert splitDecimal(-693.4356).intpart == -693.0 doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356 - doAssert splitDecimal(0.0).intpart ==~ 0.0 - doAssert splitDecimal(0.0).floatpart ==~ 0.0 + doAssert splitDecimal(0.0).intpart == 0.0 + doAssert splitDecimal(0.0).floatpart == 0.0 block: # trunc tests for vcc doAssert(trunc(-1.1) == -1) @@ -257,8 +257,8 @@ block: doAssert floorDiv(-8, -3) == 2 doAssert floorMod(-8, -3) == -2 - doAssert floorMod(8.0, -3.0) ==~ -1.0 - doAssert floorMod(-8.5, 3.0) ==~ 0.5 + doAssert floorMod(8.0, -3.0) == -1.0 + doAssert floorMod(-8.5, 3.0) == 0.5 block: # euclDiv/euclMod doAssert euclDiv(8, 3) == 2 @@ -273,8 +273,8 @@ block: doAssert euclDiv(-8, -3) == 3 doAssert euclMod(-8, -3) == 1 - doAssert euclMod(8.0, -3.0) ==~ 2.0 - doAssert euclMod(-8.5, 3.0) ==~ 0.5 + doAssert euclMod(8.0, -3.0) == 2.0 + doAssert euclMod(-8.5, 3.0) == 0.5 doAssert euclDiv(9, 3) == 3 doAssert euclMod(9, 3) == 0 From 3b2f94810e4826c4eef4d517175a8b6a0a8a45a2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 5 Jan 2021 08:21:06 -0800 Subject: [PATCH 1771/4254] remove duplication in asynchttpserver examples (#16586) * remove duplication in asynchttpserver examples * fixup * add comment showing how to run snippet locally --- lib/pure/asynchttpserver.nim | 76 +++++++++++++----------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 4500d994e..d9f5a3a0f 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -13,34 +13,34 @@ ## for testing applications locally. Because of this, when deploying your ## application in production you should use a reverse proxy (for example nginx) ## instead of allowing users to connect directly to this server. -## -## Example -## ======= -## -## This example will create an HTTP server on port 8080. The server will -## respond to all requests with a ``200 OK`` response code and "Hello World" -## as the response body. -## -## .. code-block:: Nim -## -## import asynchttpserver, asyncdispatch -## -## proc main {.async.} = -## var server = newAsyncHttpServer() -## proc cb(req: Request) {.async.} = -## let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", -## "Content-type": "text/plain; charset=utf-8"} -## await req.respond(Http200, "Hello World", headers.newHttpHeaders()) -## -## server.listen Port(8080) -## while true: -## if server.shouldAcceptRequest(): -## await server.acceptRequest(cb) -## else: -## poll() -## -## asyncCheck main() -## runForever() + +runnableExamples: + # This example will create an HTTP server on port 8080. The server will + # respond to all requests with a `200 OK` response code and "Hello World" + # as the response body. Run locally with: + # `nim doc --doccmd:-d:nimAsynchttpserverEnableTest --lib:lib lib/pure/asynchttpserver.nim` + import asyncdispatch + if defined(nimAsynchttpserverEnableTest): + proc main {.async.} = + const port = 8080 + var server = newAsyncHttpServer() + proc cb(req: Request) {.async.} = + echo (req.reqMethod, req.url, req.headers) + let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", + "Content-type": "text/plain; charset=utf-8"} + await req.respond(Http200, "Hello World", headers.newHttpHeaders()) + + echo "test this with: curl localhost:" & $port & "/" + server.listen Port(port) + while true: + if server.shouldAcceptRequest(): + await server.acceptRequest(cb) + else: + # too many concurrent connections, `maxFDs` exceeded + poll() + + asyncCheck main() + runForever() import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore @@ -368,23 +368,3 @@ proc serve*(server: AsyncHttpServer, port: Port, proc close*(server: AsyncHttpServer) = ## Terminates the async http server instance. server.socket.close() - -when not defined(testing) and isMainModule: - proc main {.async.} = - var server = newAsyncHttpServer() - proc cb(req: Request) {.async.} = - #echo(req.reqMethod, " ", req.url) - #echo(req.headers) - let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", - "Content-type": "text/plain; charset=utf-8"} - await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - - server.listen Port(5555) - while true: - if server.shouldAcceptRequest(): - await server.acceptRequest(cb) - else: - poll() - - asyncCheck main() - runForever() From b24d6d4b6a57a14aba0b22a9ea888a4adb19928c Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 5 Jan 2021 13:45:58 -0300 Subject: [PATCH 1772/4254] Remove old untested undocumented examples (#16595) --- examples/allany.nim | 24 ----------- examples/extract_keyval_pairs_pegs.nim | 7 --- examples/extract_keyval_pairs_re.nim | 8 ---- examples/hallo.nim | 3 -- examples/maximum.nim | 6 --- examples/myfile.txt | 11 ----- examples/readme.txt | 2 - examples/statcsv.nim | 60 -------------------------- examples/talk/dsl.nim | 33 -------------- examples/talk/formatoptimizer.nim | 55 ----------------------- examples/talk/hoisting.nim | 23 ---------- examples/talk/lazyeval.nim | 12 ------ examples/talk/quasiquote.nim | 11 ----- examples/talk/tags.nim | 9 ---- examples/tunit.nim | 47 -------------------- 15 files changed, 311 deletions(-) delete mode 100644 examples/allany.nim delete mode 100644 examples/extract_keyval_pairs_pegs.nim delete mode 100644 examples/extract_keyval_pairs_re.nim delete mode 100644 examples/hallo.nim delete mode 100644 examples/maximum.nim delete mode 100644 examples/myfile.txt delete mode 100644 examples/readme.txt delete mode 100644 examples/statcsv.nim delete mode 100644 examples/talk/dsl.nim delete mode 100644 examples/talk/formatoptimizer.nim delete mode 100644 examples/talk/hoisting.nim delete mode 100644 examples/talk/lazyeval.nim delete mode 100644 examples/talk/quasiquote.nim delete mode 100644 examples/talk/tags.nim delete mode 100644 examples/tunit.nim diff --git a/examples/allany.nim b/examples/allany.nim deleted file mode 100644 index 8a5ab81f0..000000000 --- a/examples/allany.nim +++ /dev/null @@ -1,24 +0,0 @@ -# All and any - -template all(container, cond: untyped): bool = - var result = true - for it in items(container): - if not cond(it): - result = false - break - result - -template any(container, cond: untyped): bool = - var result = false - for it in items(container): - if cond(it): - result = true - break - result - -if all("mystring", {'a'..'z'}.contains) and any("myohmy", 'y'.`==`): - echo "works" -else: - echo "does not work" - - diff --git a/examples/extract_keyval_pairs_pegs.nim b/examples/extract_keyval_pairs_pegs.nim deleted file mode 100644 index 2a5643276..000000000 --- a/examples/extract_keyval_pairs_pegs.nim +++ /dev/null @@ -1,7 +0,0 @@ -# Filter key=value pairs from "myfile.txt" -import pegs - -for x in lines("myfile.txt"): - if x =~ peg"{\ident} \s* '=' \s* {.*}": - echo "Key: ", matches[0], - " Value: ", matches[1] diff --git a/examples/extract_keyval_pairs_re.nim b/examples/extract_keyval_pairs_re.nim deleted file mode 100644 index a594c0fa8..000000000 --- a/examples/extract_keyval_pairs_re.nim +++ /dev/null @@ -1,8 +0,0 @@ -# Filter key=value pairs from "myfile.txt" -import re - -for x in lines("myfile.txt"): - if x =~ re"(\w+)=(.*)": - echo "Key: ", matches[0], " Value: ", matches[1] - - diff --git a/examples/hallo.nim b/examples/hallo.nim deleted file mode 100644 index d94da8c1f..000000000 --- a/examples/hallo.nim +++ /dev/null @@ -1,3 +0,0 @@ -# Hello world program - -echo "Hello World" diff --git a/examples/maximum.nim b/examples/maximum.nim deleted file mode 100644 index 3c43a48c9..000000000 --- a/examples/maximum.nim +++ /dev/null @@ -1,6 +0,0 @@ -# Shows how the method call syntax can be used to chain calls conveniently. - -import strutils, sequtils - -echo "Give a list of numbers (separated by spaces): " -stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!") diff --git a/examples/myfile.txt b/examples/myfile.txt deleted file mode 100644 index fb7cda984..000000000 --- a/examples/myfile.txt +++ /dev/null @@ -1,11 +0,0 @@ -kladsfa - -asdflksadlfasf - - -adsfljksadfl - - -key=/usr/bin/value -key2=/ha/ha - diff --git a/examples/readme.txt b/examples/readme.txt deleted file mode 100644 index 42446faea..000000000 --- a/examples/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -In this directory you can find several examples for how to use the Nim -library. diff --git a/examples/statcsv.nim b/examples/statcsv.nim deleted file mode 100644 index 983cd555f..000000000 --- a/examples/statcsv.nim +++ /dev/null @@ -1,60 +0,0 @@ -# Example program to show the parsecsv module -# This program reads a CSV file and computes sum, mean, minimum, maximum and -# the standard deviation of its columns. -# The CSV file can have a header which is then used for the output. - -import os, streams, parsecsv, strutils, math, stats - -if paramCount() < 1: - quit("Usage: statcsv filename[.csv]") - -var filename = addFileExt(paramStr(1), "csv") -var s = newFileStream(filename, fmRead) -if s == nil: quit("cannot open the file " & filename) - -var - x: CsvParser - header: seq[string] - res: seq[RunningStat] -open(x, s, filename, separator=';', skipInitialSpace = true) -while readRow(x): - if processedRows(x) == 1: - newSeq(res, x.row.len) # allocate space for the result - if validIdentifier(x.row[0]): - # header line: - header = x.row - else: - newSeq(header, x.row.len) - for i in 0..x.row.len-1: header[i] = "Col " & $(i+1) - else: - # data line: - for i in 0..x.row.len-1: - push(res[i], parseFloat(x.row[i])) -x.close() - -# Write results: -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(header[i]) -stdout.write("\nSum") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].sum) -stdout.write("\nMean") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].mean) -stdout.write("\nMin") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].min) -stdout.write("\nMax") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].max) -stdout.write("\nStdDev") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].standardDeviation) -stdout.write("\n") - diff --git a/examples/talk/dsl.nim b/examples/talk/dsl.nim deleted file mode 100644 index 2dde51790..000000000 --- a/examples/talk/dsl.nim +++ /dev/null @@ -1,33 +0,0 @@ - -import strutils - -template html(name, matter: untyped) = - proc name(): string = - result = "" - matter - result.add("") - -template nestedTag(tag: untyped) = - template tag(matter: typed) = - result.add("<" & astToStr(tag) & ">") - matter - result.add("") - -template simpleTag(tag: untyped) = - template tag(matter: untyped) = - result.add("<$1>$2" % [astToStr(tag), matter]) - -nestedTag body -nestedTag head -nestedTag ul -simpleTag title -simpleTag li - -html mainPage: - head: - title "now look at this" - body: - ul: - li "Nim is quite capable" - -echo mainPage() diff --git a/examples/talk/formatoptimizer.nim b/examples/talk/formatoptimizer.nim deleted file mode 100644 index 6e3d0c2c3..000000000 --- a/examples/talk/formatoptimizer.nim +++ /dev/null @@ -1,55 +0,0 @@ -## This is the example that optimizes a modified "hello world" - -import macros - -proc invalidFormatString() = - echo "invalidFormatString" - -template formatImpl(handleChar: untyped) = - var i = 0 - while i < f.len: - if f[i] == '$': - case f[i+1] - of '1'..'9': - var j = 0 - i += 1 - while f[i] in {'0'..'9'}: - j = j * 10 + ord(f[i]) - ord('0') - i += 1 - result.add(a[j-1]) - else: - invalidFormatString() - else: - result.add(handleChar(f[i])) - i += 1 - -proc `%`*(f: string, a: openArray[string]): string = - template identity(x: untyped): untyped = x - result = "" - formatImpl(identity) - -macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped = - result = newNimNode(nnkBracket) - #newCall("&") - let f = f.strVal - formatImpl(newLit) - result = nestList(newIdentNode("&"), result) - -template optAdd1{x = y; add(x, z)}(x, y, z: string) = - x = y & z - -#template optAdd2{x.add(y); x.add(z)}(x, y, z: string) = -# x.add(y & z) - -proc `/&` [T: object](x: T): string = - result = "(" - for name, value in fieldPairs(x): - result.add("$1: $2\n" % [name, $value]) - result.add(")") - -type - MyObject = object - a, b: int - s: string -let obj = MyObject(a: 3, b: 4, s: "abc") -echo(/&obj) diff --git a/examples/talk/hoisting.nim b/examples/talk/hoisting.nim deleted file mode 100644 index 54e00884f..000000000 --- a/examples/talk/hoisting.nim +++ /dev/null @@ -1,23 +0,0 @@ -type - Regex = distinct string - -const maxSubpatterns = 10 - -proc re(x: string): Regex = - result = Regex(x) - -proc match(s: string, pattern: Regex, captures: var openArray[string]): bool = - true - -template optRe{re(x)}(x: string{lit}): Regex = - var g {.global.} = re(x) - g - -template `=~`(s: string, pattern: Regex): bool = - when not declaredInScope(matches): - var matches {.inject.}: array[maxSubPatterns, string] - match(s, pattern, matches) - -for line in lines("input.txt"): - if line =~ re"(\w+)=(\w+)": - echo "key-value pair; key: ", matches[0], " value: ", matches[1] diff --git a/examples/talk/lazyeval.nim b/examples/talk/lazyeval.nim deleted file mode 100644 index 77d963834..000000000 --- a/examples/talk/lazyeval.nim +++ /dev/null @@ -1,12 +0,0 @@ - -const - debug = true - -template log(msg: string) = - if debug: - echo msg -var - x = 1 - y = 2 - -log("x: " & $x & ", y: " & $y) diff --git a/examples/talk/quasiquote.nim b/examples/talk/quasiquote.nim deleted file mode 100644 index b3c7bb971..000000000 --- a/examples/talk/quasiquote.nim +++ /dev/null @@ -1,11 +0,0 @@ - -import macros - -macro check(ex: untyped): typed = - var info = ex.lineinfo - var expString = ex.toStrLit - result = quote do: - if not `ex`: - echo `info`, ": Check failed: ", `expString` - -check 1 < 2 diff --git a/examples/talk/tags.nim b/examples/talk/tags.nim deleted file mode 100644 index 8bf3450c9..000000000 --- a/examples/talk/tags.nim +++ /dev/null @@ -1,9 +0,0 @@ - -template htmlTag(tag: untyped) = - proc tag(): string = "<" & astToStr(tag) & ">" - -htmlTag(br) -htmlTag(html) - -echo br() -echo html() \ No newline at end of file diff --git a/examples/tunit.nim b/examples/tunit.nim deleted file mode 100644 index e8ff8a952..000000000 --- a/examples/tunit.nim +++ /dev/null @@ -1,47 +0,0 @@ - -import - unittest, macros - -var - a = 1 - b = 22 - c = 1 - d = 3 - -suite "my suite": - setup: - echo "suite setup" - var testVar = "from setup" - - teardown: - echo "suite teardown" - - test "first suite test": - testVar = "modified" - echo "test var: " & testVar - check a > b - - test "second suite test": - echo "test var: " & testVar - -proc foo: bool = - echo "running foo" - return true - -proc err = - raise newException(ArithmeticDefect, "some exception") - -test "final test": - echo "inside suite-less test" - - check: - a == c - foo() - d > 10 - -test "arithmetic failure": - expect(ArithmeticDefect): - err() - - expect(ArithmeticDefect, CatchableError): - discard foo() From df9e74b510a84b0050ffe022e77d42c6f949c2bc Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 5 Jan 2021 10:47:10 -0600 Subject: [PATCH 1773/4254] fix #9125 (#16582) * fix #9125 * Update tests/stdlib/tmath.nim Co-authored-by: Timothee Cour * back Co-authored-by: Andreas Rumpf Co-authored-by: Timothee Cour --- changelog.md | 5 +++-- lib/pure/math.nim | 12 +++++++++++- tests/stdlib/tmath.nim | 30 ++++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index b97fcdd03..306cf54d3 100644 --- a/changelog.md +++ b/changelog.md @@ -84,13 +84,14 @@ - Added `mimetypes.mimesExtMaxLen` thats equal to the length of the longest "ext" from `mimes`. - Added `mimetypes.mimesMaxLen` thats equal to the length of the longest "mime" from `mimes`. - - - Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs. https://www.freedesktop.org/software/systemd/man/os-release.html - Added `BackwardsIndex` overload for `JsonNode`. +- `math.round` now is rounded "away from zero" in JS backend which is consistent +with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. + ## Language changes diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 76052ec3b..a6a3676b9 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -847,7 +847,17 @@ else: # JS func floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} func ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} func ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} - func round*(x: float): float {.importc: "Math.round", nodecl.} + + when (NimMajor, NimMinor) < (1, 5) or defined(nimLegacyJsRound): + func round*(x: float): float {.importc: "Math.round", nodecl.} + else: + func jsRound(x: float): float {.importc: "Math.round", nodecl.} + func round*[T: float64 | float32](x: T): T = + if x >= 0: result = jsRound(x) + else: + result = ceil(x) + if result - x >= T(0.5): + result -= T(1.0) func trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} func trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index fbc6b80ad..e5cb58eba 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -10,6 +10,10 @@ import std/[math, random, os] import std/[unittest] import std/[sets, tables] + +# Function for approximate comparison of floats +proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) + block: # random int block: # there might be some randomness var set = initHashSet[int](128) @@ -158,10 +162,6 @@ block: doAssert(erf(6.0) > erf(5.0)) doAssert(erfc(6.0) < erfc(5.0)) - proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) - # Function for approximate comparison of floats - # xxx use `almostEqual` - block: # prod doAssert prod([1, 2, 3, 4]) == 24 doAssert prod([1.5, 3.4]).almostEqual 5.1 @@ -349,6 +349,28 @@ template main = doAssert copySign(-NaN, 0.0).isNaN doAssert copySign(-NaN, -0.0).isNaN + block: # round() tests + # Round to 0 decimal places + doAssert round(54.652) == 55.0 + doAssert round(54.352) == 54.0 + doAssert round(-54.652) == -55.0 + doAssert round(-54.352) == -54.0 + doAssert round(0.0) == 0.0 + doAssert 1 / round(0.0) == Inf + doAssert 1 / round(-0.0) == -Inf + doAssert round(Inf) == Inf + doAssert round(-Inf) == -Inf + doAssert round(NaN).isNaN + doAssert round(-NaN).isNaN + doAssert round(-0.5) == -1.0 + doAssert round(0.5) == 1.0 + doAssert round(-1.5) == -2.0 + doAssert round(1.5) == 2.0 + doAssert round(-2.5) == -3.0 + doAssert round(2.5) == 3.0 + doAssert round(2.5'f32) == 3.0'f32 + doAssert round(2.5'f64) == 3.0'f64 + when nimvm: discard else: From 0c4bd65e8d2d81a5e52624215e864f7846eb320b Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:50:15 +0100 Subject: [PATCH 1774/4254] Improve documentation for complex (#16588) * Improve documentation for complex Add missing doc comments * Add runnableExample Add links for principal values Optimize `-` Change var to let * Use std prefix for imports --- lib/pure/complex.nim | 272 +++++++++++++++++++++++--------------- tests/stdlib/tcomplex.nim | 12 +- 2 files changed, 171 insertions(+), 113 deletions(-) diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 04e5e8e56..b9371c1e1 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -7,106 +7,155 @@ # distribution, for details about the copyright. # -## This module implements complex numbers. -## Complex numbers are currently implemented as generic on a 64-bit or 32-bit float. +## This module implements complex numbers +## and basic mathematical operations on them. +## +## Complex numbers are currently generic over 64-bit or 32-bit floats. + +runnableExamples: + from std/math import almostEqual, sqrt + + func almostEqual(a, b: Complex): bool = + almostEqual(a.re, b.re) and almostEqual(a.im, b.im) + + let + z1 = complex(1.0, 2.0) + z2 = complex(3.0, -4.0) + + assert almostEqual(z1 + z2, complex(4.0, -2.0)) + assert almostEqual(z1 - z2, complex(-2.0, 6.0)) + assert almostEqual(z1 * z2, complex(11.0, 2.0)) + assert almostEqual(z1 / z2, complex(-0.2, 0.4)) + + assert almostEqual(abs(z1), sqrt(5.0)) + assert almostEqual(conjugate(z1), complex(1.0, -2.0)) + + let (r, phi) = z1.polar + assert almostEqual(rect(r, phi), z1) {.push checks: off, line_dir: off, stack_trace: off, debugger: off.} # the user does not want to trace a part of the standard library! -import math +import std/math type Complex*[T: SomeFloat] = object - re*, im*: T ## A complex number, consisting of a real and an imaginary part. + re*, im*: T Complex64* = Complex[float64] - ## Alias for a pair of 64-bit floats. + ## Alias for a complex number using 64-bit floats. Complex32* = Complex[float32] - ## Alias for a pair of 32-bit floats. + ## Alias for a complex number using 32-bit floats. func complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] = + ## Returns a `Complex[T]` with real part `re` and imaginary part `im`. result.re = re result.im = im -func complex32*(re: float32; im: float32 = 0.0): Complex[float32] = +func complex32*(re: float32; im: float32 = 0.0): Complex32 = + ## Returns a `Complex32` with real part `re` and imaginary part `im`. result.re = re result.im = im -func complex64*(re: float64; im: float64 = 0.0): Complex[float64] = +func complex64*(re: float64; im: float64 = 0.0): Complex64 = + ## Returns a `Complex64` with real part `re` and imaginary part `im`. result.re = re result.im = im -template im*(arg: typedesc[float32]): Complex32 = complex[float32](0, 1) -template im*(arg: typedesc[float64]): Complex64 = complex[float64](0, 1) -template im*(arg: float32): Complex32 = complex[float32](0, arg) -template im*(arg: float64): Complex64 = complex[float64](0, arg) +template im*(arg: typedesc[float32]): Complex32 = complex32(0, 1) + ## Returns the imaginary unit (`complex32(0, 1)`). +template im*(arg: typedesc[float64]): Complex64 = complex64(0, 1) + ## Returns the imaginary unit (`complex64(0, 1)`). +template im*(arg: float32): Complex32 = complex32(0, arg) + ## Returns `arg` as an imaginary number (`complex32(0, arg)`). +template im*(arg: float64): Complex64 = complex64(0, arg) + ## Returns `arg` as an imaginary number (`complex64(0, arg)`). func abs*[T](z: Complex[T]): T = - ## Returns the distance from (0,0) to ``z``. + ## Returns the absolute value of `z`, + ## that is the distance from (0, 0) to `z`. result = hypot(z.re, z.im) func abs2*[T](z: Complex[T]): T = - ## Returns the squared distance from (0,0) to ``z``. - result = z.re*z.re + z.im*z.im + ## Returns the squared absolute value of `z`, + ## that is the squared distance from (0, 0) to `z`. + ## This is more efficient than `abs(z) ^ 2`. + result = z.re * z.re + z.im * z.im func conjugate*[T](z: Complex[T]): Complex[T] = - ## Conjugates of complex number ``z``. + ## Returns the complex conjugate of `z` (`complex(z.re, -z.im)`). result.re = z.re result.im = -z.im func inv*[T](z: Complex[T]): Complex[T] = - ## Multiplicatives inverse of complex number ``z``. + ## Returns the multiplicative inverse of `z` (`1/z`). conjugate(z) / abs2(z) -func `==` *[T](x, y: Complex[T]): bool = - ## Compares two complex numbers ``x`` and ``y`` for equality. +func `==`*[T](x, y: Complex[T]): bool = + ## Compares two complex numbers for equality. result = x.re == y.re and x.im == y.im -func `+` *[T](x: T; y: Complex[T]): Complex[T] = +func `+`*[T](x: T; y: Complex[T]): Complex[T] = ## Adds a real number to a complex number. result.re = x + y.re result.im = y.im -func `+` *[T](x: Complex[T]; y: T): Complex[T] = +func `+`*[T](x: Complex[T]; y: T): Complex[T] = ## Adds a complex number to a real number. result.re = x.re + y result.im = x.im -func `+` *[T](x, y: Complex[T]): Complex[T] = +func `+`*[T](x, y: Complex[T]): Complex[T] = ## Adds two complex numbers. result.re = x.re + y.re result.im = x.im + y.im -func `-` *[T](z: Complex[T]): Complex[T] = +func `-`*[T](z: Complex[T]): Complex[T] = ## Unary minus for complex numbers. result.re = -z.re result.im = -z.im -func `-` *[T](x: T; y: Complex[T]): Complex[T] = +func `-`*[T](x: T; y: Complex[T]): Complex[T] = ## Subtracts a complex number from a real number. - x + (-y) + result.re = x - y.re + result.im = -y.im -func `-` *[T](x: Complex[T]; y: T): Complex[T] = +func `-`*[T](x: Complex[T]; y: T): Complex[T] = ## Subtracts a real number from a complex number. result.re = x.re - y result.im = x.im -func `-` *[T](x, y: Complex[T]): Complex[T] = +func `-`*[T](x, y: Complex[T]): Complex[T] = ## Subtracts two complex numbers. result.re = x.re - y.re result.im = x.im - y.im -func `/` *[T](x: Complex[T]; y: T): Complex[T] = - ## Divides complex number ``x`` by real number ``y``. +func `*`*[T](x: T; y: Complex[T]): Complex[T] = + ## Multiplies a real number with a complex number. + result.re = x * y.re + result.im = x * y.im + +func `*`*[T](x: Complex[T]; y: T): Complex[T] = + ## Multiplies a complex number with a real number. + result.re = x.re * y + result.im = x.im * y + +func `*`*[T](x, y: Complex[T]): Complex[T] = + ## Multiplies two complex numbers. + result.re = x.re * y.re - x.im * y.im + result.im = x.im * y.re + x.re * y.im + +func `/`*[T](x: Complex[T]; y: T): Complex[T] = + ## Divides a complex number by a real number. result.re = x.re / y result.im = x.im / y -func `/` *[T](x: T; y: Complex[T]): Complex[T] = - ## Divides real number ``x`` by complex number ``y``. +func `/`*[T](x: T; y: Complex[T]): Complex[T] = + ## Divides a real number by a complex number. result = x * inv(y) -func `/` *[T](x, y: Complex[T]): Complex[T] = - ## Divides ``x`` by ``y``. +func `/`*[T](x, y: Complex[T]): Complex[T] = + ## Divides two complex numbers. var r, den: T if abs(y.re) < abs(y.im): r = y.re / y.im @@ -119,45 +168,32 @@ func `/` *[T](x, y: Complex[T]): Complex[T] = result.re = (x.re + r * x.im) / den result.im = (x.im - r * x.re) / den -func `*` *[T](x: T; y: Complex[T]): Complex[T] = - ## Multiplies a real number and a complex number. - result.re = x * y.re - result.im = x * y.im -func `*` *[T](x: Complex[T]; y: T): Complex[T] = - ## Multiplies a complex number with a real number. - result.re = x.re * y - result.im = x.im * y - -func `*` *[T](x, y: Complex[T]): Complex[T] = - ## Multiplies ``x`` with ``y``. - result.re = x.re * y.re - x.im * y.im - result.im = x.im * y.re + x.re * y.im - - -func `+=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Adds ``y`` to ``x``. +func `+=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Adds `y` to `x`. x.re += y.re x.im += y.im -func `-=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Subtracts ``y`` from ``x``. +func `-=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Subtracts `y` from `x`. x.re -= y.re x.im -= y.im -func `*=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Multiplies ``y`` to ``x``. +func `*=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Multiplies `x` by `y`. let im = x.im * y.re + x.re * y.im x.re = x.re * y.re - x.im * y.im x.im = im -func `/=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Divides ``x`` by ``y`` in place. +func `/=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Divides `x` by `y` in place. x = x / y func sqrt*[T](z: Complex[T]): Complex[T] = - ## Square root for a complex number ``z``. + ## Computes the + ## ([principal](https://en.wikipedia.org/wiki/Square_root#Principal_square_root_of_a_complex_number)) + ## square root of a complex number `z`. var x, y, w, r: T if z.re == 0.0 and z.im == 0.0: @@ -180,28 +216,36 @@ func sqrt*[T](z: Complex[T]): Complex[T] = result.re = z.im / (result.im + result.im) func exp*[T](z: Complex[T]): Complex[T] = - ## ``e`` raised to the power ``z``. - var + ## Computes the exponential function (`e^z`). + let rho = exp(z.re) theta = z.im result.re = rho * cos(theta) result.im = rho * sin(theta) func ln*[T](z: Complex[T]): Complex[T] = - ## Returns the natural log of ``z``. + ## Returns the + ## ([principal value](https://en.wikipedia.org/wiki/Complex_logarithm#Principal_value) + ## of the) natural logarithm of `z`. result.re = ln(abs(z)) result.im = arctan2(z.im, z.re) func log10*[T](z: Complex[T]): Complex[T] = - ## Returns the log base 10 of ``z``. + ## Returns the logarithm base 10 of `z`. + ## + ## **See also:** + ## * `ln func<#ln,Complex[T]>`_ result = ln(z) / ln(10.0) func log2*[T](z: Complex[T]): Complex[T] = - ## Returns the log base 2 of ``z``. + ## Returns the logarithm base 2 of `z`. + ## + ## **See also:** + ## * `ln func<#ln,Complex[T]>`_ result = ln(z) / ln(2.0) func pow*[T](x, y: Complex[T]): Complex[T] = - ## ``x`` raised to the power ``y``. + ## `x` raised to the power of `y`. if x.re == 0.0 and x.im == 0.0: if y.re == 0.0 and y.im == 0.0: result.re = 1.0 @@ -214,7 +258,7 @@ func pow*[T](x, y: Complex[T]): Complex[T] = elif y.re == -1.0 and y.im == 0.0: result = T(1.0) / x else: - var + let rho = abs(x) theta = arctan2(x.im, x.re) s = pow(rho, y.re) * exp(-y.im * theta) @@ -223,126 +267,140 @@ func pow*[T](x, y: Complex[T]): Complex[T] = result.im = s * sin(r) func pow*[T](x: Complex[T]; y: T): Complex[T] = - ## Complex number ``x`` raised to the power ``y``. + ## The complex number `x` raised to the power of the real number `y`. pow(x, complex[T](y)) func sin*[T](z: Complex[T]): Complex[T] = - ## Returns the sine of ``z``. + ## Returns the sine of `z`. result.re = sin(z.re) * cosh(z.im) result.im = cos(z.re) * sinh(z.im) func arcsin*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse sine of ``z``. + ## Returns the inverse sine of `z`. result = -im(T) * ln(im(T) * z + sqrt(T(1.0) - z*z)) func cos*[T](z: Complex[T]): Complex[T] = - ## Returns the cosine of ``z``. + ## Returns the cosine of `z`. result.re = cos(z.re) * cosh(z.im) result.im = -sin(z.re) * sinh(z.im) func arccos*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cosine of ``z``. + ## Returns the inverse cosine of `z`. result = -im(T) * ln(z + sqrt(z*z - T(1.0))) func tan*[T](z: Complex[T]): Complex[T] = - ## Returns the tangent of ``z``. + ## Returns the tangent of `z`. result = sin(z) / cos(z) func arctan*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse tangent of ``z``. + ## Returns the inverse tangent of `z`. result = T(0.5)*im(T) * (ln(T(1.0) - im(T)*z) - ln(T(1.0) + im(T)*z)) func cot*[T](z: Complex[T]): Complex[T] = - ## Returns the cotangent of ``z``. + ## Returns the cotangent of `z`. result = cos(z)/sin(z) func arccot*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cotangent of ``z``. + ## Returns the inverse cotangent of `z`. result = T(0.5)*im(T) * (ln(T(1.0) - im(T)/z) - ln(T(1.0) + im(T)/z)) func sec*[T](z: Complex[T]): Complex[T] = - ## Returns the secant of ``z``. + ## Returns the secant of `z`. result = T(1.0) / cos(z) func arcsec*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse secant of ``z``. + ## Returns the inverse secant of `z`. result = -im(T) * ln(im(T) * sqrt(1.0 - 1.0/(z*z)) + T(1.0)/z) func csc*[T](z: Complex[T]): Complex[T] = - ## Returns the cosecant of ``z``. + ## Returns the cosecant of `z`. result = T(1.0) / sin(z) func arccsc*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cosecant of ``z``. + ## Returns the inverse cosecant of `z`. result = -im(T) * ln(sqrt(T(1.0) - T(1.0)/(z*z)) + im(T)/z) func sinh*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic sine of ``z``. + ## Returns the hyperbolic sine of `z`. result = T(0.5) * (exp(z) - exp(-z)) func arcsinh*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic sine of ``z``. + ## Returns the inverse hyperbolic sine of `z`. result = ln(z + sqrt(z*z + 1.0)) func cosh*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cosine of ``z``. + ## Returns the hyperbolic cosine of `z`. result = T(0.5) * (exp(z) + exp(-z)) func arccosh*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic cosine of ``z``. + ## Returns the inverse hyperbolic cosine of `z`. result = ln(z + sqrt(z*z - T(1.0))) func tanh*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic tangent of ``z``. + ## Returns the hyperbolic tangent of `z`. result = sinh(z) / cosh(z) func arctanh*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic tangent of ``z``. + ## Returns the inverse hyperbolic tangent of `z`. result = T(0.5) * (ln((T(1.0)+z) / (T(1.0)-z))) -func sech*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic secant of ``z``. - result = T(2.0) / (exp(z) + exp(-z)) - -func arcsech*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic secant of ``z``. - result = ln(1.0/z + sqrt(T(1.0)/z+T(1.0)) * sqrt(T(1.0)/z-T(1.0))) - -func csch*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cosecant of ``z``. - result = T(2.0) / (exp(z) - exp(-z)) - -func arccsch*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic cosecant of ``z``. - result = ln(T(1.0)/z + sqrt(T(1.0)/(z*z) + T(1.0))) - func coth*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cotangent of ``z``. + ## Returns the hyperbolic cotangent of `z`. result = cosh(z) / sinh(z) func arccoth*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse hyperbolic cotangent of ``z``. + ## Returns the inverse hyperbolic cotangent of `z`. result = T(0.5) * (ln(T(1.0) + T(1.0)/z) - ln(T(1.0) - T(1.0)/z)) +func sech*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic secant of `z`. + result = T(2.0) / (exp(z) + exp(-z)) + +func arcsech*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic secant of `z`. + result = ln(1.0/z + sqrt(T(1.0)/z+T(1.0)) * sqrt(T(1.0)/z-T(1.0))) + +func csch*[T](z: Complex[T]): Complex[T] = + ## Returns the hyperbolic cosecant of `z`. + result = T(2.0) / (exp(z) - exp(-z)) + +func arccsch*[T](z: Complex[T]): Complex[T] = + ## Returns the inverse hyperbolic cosecant of `z`. + result = ln(T(1.0)/z + sqrt(T(1.0)/(z*z) + T(1.0))) + func phase*[T](z: Complex[T]): T = - ## Returns the phase of ``z``. + ## Returns the phase (or argument) of `z`, that is the angle in polar representation. + ## + ## | `result = arctan2(z.im, z.re)` arctan2(z.im, z.re) func polar*[T](z: Complex[T]): tuple[r, phi: T] = - ## Returns ``z`` in polar coordinates. + ## Returns `z` in polar coordinates. + ## + ## | `result.r = abs(z)` + ## | `result.phi = phase(z)` + ## + ## **See also:** + ## * `rect func<#rect,T,T>`_ for the inverse operation (r: abs(z), phi: phase(z)) func rect*[T](r, phi: T): Complex[T] = - ## Returns the complex number with polar coordinates ``r`` and ``phi``. + ## Returns the complex number with polar coordinates `r` and `phi`. ## - ## | ``result.re = r * cos(phi)`` - ## | ``result.im = r * sin(phi)`` + ## | `result.re = r * cos(phi)` + ## | `result.im = r * sin(phi)` + ## + ## **See also:** + ## * `polar func<#polar,Complex[T]>`_ for the inverse operation complex(r * cos(phi), r * sin(phi)) func `$`*(z: Complex): string = - ## Returns ``z``'s string representation as ``"(re, im)"``. + ## Returns `z`'s string representation as `"(re, im)"`. + runnableExamples: + doAssert $complex(1.0, 2.0) == "(1.0, 2.0)" + result = "(" & $z.re & ", " & $z.im & ")" {.pop.} diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim index 8c9fa3055..15267b905 100644 --- a/tests/stdlib/tcomplex.nim +++ b/tests/stdlib/tcomplex.nim @@ -1,4 +1,4 @@ -import complex, math +import std/[complex, math] proc `=~`[T](x, y: Complex[T]): bool = @@ -7,7 +7,7 @@ proc `=~`[T](x, y: Complex[T]): bool = proc `=~`[T](x: Complex[T]; y: T): bool = result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6 -var +let z: Complex64 = complex(0.0, 0.0) oo: Complex64 = complex(1.0, 1.0) a: Complex64 = complex(1.0, 2.0) @@ -76,12 +76,12 @@ doAssert(arccsch(a) =~ arcsinh(1.0/a)) doAssert(arccoth(a) =~ arctanh(1.0/a)) doAssert(phase(a) == 1.1071487177940904) -var t = polar(a) +let t = polar(a) doAssert(rect(t.r, t.phi) =~ a) doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) -var +let i64: Complex32 = complex(0.0f, 1.0f) a64: Complex32 = 2.0f*i64 + 1.0.float32 b64: Complex32 = complex(-1.0'f32, -2.0'f32) @@ -96,7 +96,7 @@ doAssert(sin(arcsin(b64)) =~ b64) doAssert(cosh(arccosh(a64)) =~ a64) doAssert(phase(a64) - 1.107149f < 1e-6) -var t64 = polar(a64) +let t64 = polar(a64) doAssert(rect(t64.r, t64.phi) =~ a64) doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f)) doAssert(sizeof(a64) == 8) @@ -104,5 +104,5 @@ doAssert(sizeof(a) == 16) doAssert 123.0.im + 456.0 == complex64(456, 123) -var localA = complex(0.1'f32) +let localA = complex(0.1'f32) doAssert localA.im is float32 From c04f305bf791ee5ecfd17f5a40d009d9c6b6f07a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 5 Jan 2021 10:52:26 -0600 Subject: [PATCH 1775/4254] make cstrutils work in VM (#16590) * make cstrutils work in VM * more --- lib/pure/cstrutils.nim | 180 +++++++++++++++++++----------------- lib/pure/strutils.nim | 15 +-- lib/std/private/strimpl.nim | 29 +++++- tests/stdlib/tcstrutils.nim | 12 ++- 4 files changed, 132 insertions(+), 104 deletions(-) diff --git a/lib/pure/cstrutils.nim b/lib/pure/cstrutils.nim index 390aac00b..cdef7c804 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -16,93 +16,103 @@ import std/private/strimpl when defined(js): - func startsWith*(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".} + func jsStartsWith(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".} + func jsEndsWith(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".} - func endsWith*(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".} - func cmpIgnoreStyle*(a, b: cstring): int = +func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} = + ## Returns true if `s` starts with `prefix`. + ## + ## JS backend uses native `String.prototype.startsWith`. + runnableExamples: + assert startsWith(cstring"Hello, Nimion", cstring"Hello") + assert not startsWith(cstring"Hello, Nimion", cstring"Nimion") + assert startsWith(cstring"Hello", cstring"") + when nimvm: + startsWithImpl(s, prefix) + else: + when defined(js): + result = jsStartsWith(s, prefix) + else: + var i = 0 + while true: + if prefix[i] == '\0': return true + if s[i] != prefix[i]: return false + inc(i) + +func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} = + ## Returns true if `s` ends with `suffix`. + ## + ## JS backend uses native `String.prototype.endsWith`. + runnableExamples: + assert endsWith(cstring"Hello, Nimion", cstring"Nimion") + assert not endsWith(cstring"Hello, Nimion", cstring"Hello") + assert endsWith(cstring"Hello", cstring"") + when nimvm: + endsWithImpl(s, suffix) + else: + when defined(js): + result = jsEndsWith(s, suffix) + else: + let slen = s.len + var i = 0 + var j = slen - len(suffix) + while i+j <% slen: + if s[i+j] != suffix[i]: return false + inc(i) + if suffix[i] == '\0': return true + +func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} = + ## Semantically the same as `cmp(normalize($a), normalize($b))`. It + ## is just optimized to not allocate temporary strings. This should + ## NOT be used to compare Nim identifier names. use `macros.eqIdent` + ## for that. Returns: + ## + ## .. code-block:: + ## 0 if a == b + ## < 0 if a < b + ## > 0 if a > b + runnableExamples: + assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0 + when nimvm: cmpIgnoreStyleImpl(a, b) + else: + when defined(js): + cmpIgnoreStyleImpl(a, b) + else: + var i = 0 + var j = 0 + while true: + while a[i] == '_': inc(i) + while b[j] == '_': inc(j) # BUGFIX: typo + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[j]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) + inc(j) - func cmpIgnoreCase*(a, b: cstring): int = +func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} = + ## Compares two strings in a case insensitive manner. Returns: + ## + ## .. code-block:: + ## 0 if a == b + ## < 0 if a < b + ## > 0 if a > b + runnableExamples: + assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0 + assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0 + assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0 + when nimvm: cmpIgnoreCaseImpl(a, b) - - # JS string has more operations that might warrant its own module: - # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String -else: - func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} = - ## Returns true if `s` starts with `prefix`. - ## - ## If `prefix == ""` true is returned. - ## - ## JS backend uses native `String.prototype.startsWith`. - runnableExamples: - assert startsWith(cstring"Hello, Nimion", cstring"Hello") - assert not startsWith(cstring"Hello, Nimion", cstring"Nimion") - - var i = 0 - while true: - if prefix[i] == '\0': return true - if s[i] != prefix[i]: return false - inc(i) - - func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} = - ## Returns true if `s` ends with `suffix`. - ## - ## If `suffix == ""` true is returned. - ## - ## JS backend uses native `String.prototype.endsWith`. - runnableExamples: - assert endsWith(cstring"Hello, Nimion", cstring"Nimion") - assert not endsWith(cstring"Hello, Nimion", cstring"Hello") - - let slen = s.len - var i = 0 - var j = slen - len(suffix) - while i+j <% slen: - if s[i+j] != suffix[i]: return false - inc(i) - if suffix[i] == '\0': return true - - func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} = - ## Semantically the same as `cmp(normalize($a), normalize($b))`. It - ## is just optimized to not allocate temporary strings. This should - ## NOT be used to compare Nim identifier names. use `macros.eqIdent` - ## for that. Returns: - ## - ## .. code-block:: - ## 0 if a == b - ## < 0 if a < b - ## > 0 if a > b - runnableExamples: - assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0 - var i = 0 - var j = 0 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) - - func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} = - ## Compares two strings in a case insensitive manner. Returns: - ## - ## .. code-block:: - ## 0 if a == b - ## < 0 if a < b - ## > 0 if a > b - runnableExamples: - assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0 - assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0 - assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0 - - var i = 0 - while true: - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[i]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) + else: + when defined(js): + cmpIgnoreCaseImpl(a, b) + else: + var i = 0 + while true: + var aa = toLowerAscii(a[i]) + var bb = toLowerAscii(b[i]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index b1418a3ec..a25df9e42 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -81,7 +81,7 @@ when defined(nimVmExportFixed): include "system/inclrtl" import std/private/since -from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl +from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl const @@ -1530,11 +1530,7 @@ func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} = let a = "abracadabra" doAssert a.startsWith("abra") == true doAssert a.startsWith("bra") == false - var i = 0 - while true: - if i >= prefix.len: return true - if i >= s.len or s[i] != prefix[i]: return false - inc(i) + startsWithImpl(s, prefix) func endsWith*(s: string, suffix: char): bool {.inline.} = ## Returns true if `s` ends with `suffix`. @@ -1562,12 +1558,7 @@ func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} = let a = "abracadabra" doAssert a.endsWith("abra") == true doAssert a.endsWith("dab") == false - var i = 0 - var j = len(s) - len(suffix) - while i+j >= 0 and i+j < s.len: - if s[i+j] != suffix[i]: return false - inc(i) - if i >= suffix.len: return true + endsWithImpl(s, suffix) func continuesWith*(s, substr: string, start: Natural): bool {.rtl, extern: "nsuContinuesWith".} = diff --git a/lib/std/private/strimpl.nim b/lib/std/private/strimpl.nim index ae752165a..3fa0dc1d3 100644 --- a/lib/std/private/strimpl.nim +++ b/lib/std/private/strimpl.nim @@ -4,13 +4,13 @@ func toLowerAscii*(c: char): char {.inline.} = else: result = c -template firstCharCaseSensitiveImpl(a, b: typed, aLen, bLen: int) = +template firstCharCaseSensitiveImpl[T: string | cstring](a, b: T, aLen, bLen: int) = if aLen == 0 or bLen == 0: return aLen - bLen if a[0] != b[0]: return ord(a[0]) - ord(b[0]) -template cmpIgnoreStyleImpl*(a, b: typed, firstCharCaseSensitive: static bool = false) = - # a, b are string or cstring +template cmpIgnoreStyleImpl*[T: string | cstring](a, b: T, + firstCharCaseSensitive: static bool = false) = let aLen = a.len let bLen = b.len var i = 0 @@ -37,8 +37,8 @@ template cmpIgnoreStyleImpl*(a, b: typed, firstCharCaseSensitive: static bool = inc i inc j -template cmpIgnoreCaseImpl*(a, b: typed, firstCharCaseSensitive: static bool = false) = - # a, b are string or cstring +template cmpIgnoreCaseImpl*[T: string | cstring](a, b: T, + firstCharCaseSensitive: static bool = false) = let aLen = a.len let bLen = b.len var i = 0 @@ -51,3 +51,22 @@ template cmpIgnoreCaseImpl*(a, b: typed, firstCharCaseSensitive: static bool = f if result != 0: return inc i result = aLen - bLen + +template startsWithImpl*[T: string | cstring](s, prefix: T) = + let prefixLen = prefix.len + let sLen = s.len + var i = 0 + while true: + if i >= prefixLen: return true + if i >= sLen or s[i] != prefix[i]: return false + inc(i) + +template endsWithImpl*[T: string | cstring](s, suffix: T) = + let suffixLen = suffix.len + let sLen = s.len + var i = 0 + var j = sLen - suffixLen + while i+j >= 0 and i+j < sLen: + if s[i+j] != suffix[i]: return false + inc(i) + if i >= suffixLen: return true diff --git a/tests/stdlib/tcstrutils.nim b/tests/stdlib/tcstrutils.nim index 1daf32aa5..ba3b1de68 100644 --- a/tests/stdlib/tcstrutils.nim +++ b/tests/stdlib/tcstrutils.nim @@ -2,21 +2,25 @@ discard """ targets: "c cpp js" """ -import cstrutils +import std/cstrutils -block tcstrutils: +proc main() = let s = cstring "abcdef" doAssert s.startsWith("a") doAssert not s.startsWith("b") doAssert s.endsWith("f") doAssert not s.endsWith("a") + doAssert s.startsWith("") + doAssert s.endsWith("") let a = cstring "abracadabra" doAssert a.startsWith("abra") doAssert not a.startsWith("bra") doAssert a.endsWith("abra") doAssert not a.endsWith("dab") + doAssert a.startsWith("") + doAssert a.endsWith("") doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0 doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0 @@ -28,3 +32,7 @@ block tcstrutils: doAssert cmpIgnoreCase(cstring "", cstring "") == 0 doAssert cmpIgnoreCase(cstring "", cstring "Hello") < 0 doAssert cmpIgnoreCase(cstring "wind", cstring "") > 0 + + +static: main() +main() From 2c2baa9fad1d144c42baf30ed004decdf8bb0483 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 5 Jan 2021 20:51:51 +0100 Subject: [PATCH 1776/4254] Link the header (#16597) --- lib/pure/fenv.nim | 6 ++++-- tests/stdlib/tfenv.nim | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index abddaf4cb..1a895bfa8 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -9,6 +9,8 @@ ## Floating-point environment. Handling of floating-point rounding and ## exceptions (overflow, division by zero, etc.). +## The types, vars and procs are bindings for the C standard library +## [](https://en.cppreference.com/w/c/numeric/fenv) header. when defined(Posix) and not defined(genode): {.passl: "-lm".} @@ -35,8 +37,8 @@ var FE_UPWARD* {.importc, header: "".}: cint ## round toward +Inf FE_DFL_ENV* {.importc, header: "".}: cint - ## macro of type pointer to fenv_t to be used as the argument - ## to functions taking an argument of type fenv_t; in this + ## macro of type pointer to `fenv_t` to be used as the argument + ## to functions taking an argument of type `fenv_t`; in this ## case the default environment will be used type diff --git a/tests/stdlib/tfenv.nim b/tests/stdlib/tfenv.nim index f58acf1c8..5bcd1ea7c 100644 --- a/tests/stdlib/tfenv.nim +++ b/tests/stdlib/tfenv.nim @@ -1,8 +1,7 @@ -import fenv +import std/fenv func is_significant(x: float): bool = - if x > minimumPositiveValue(float) and x < maximumPositiveValue(float): true - else: false + x > minimumPositiveValue(float) and x < maximumPositiveValue(float) doAssert is_significant(10.0) From d721f5cecad90a0aa7e2ea144607ffafdf647e31 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Wed, 6 Jan 2021 02:23:59 +0000 Subject: [PATCH 1777/4254] fix syntax in macros documentation (#16604) --- doc/astspec.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/astspec.txt b/doc/astspec.txt index 019b735f5..e7bbcecc2 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1033,7 +1033,7 @@ AST: nnkEmpty(), # no pragmas here nnkOfInherit( nnkIdent("RootObj") # inherits from RootObj - ) + ), nnkEmpty() ) ) From 58b9191354aa99ac2d17f9a7db3bdf239c7bce6b Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 6 Jan 2021 10:47:03 +0000 Subject: [PATCH 1778/4254] fix #16516 method dispatch for sink args (#16594) * fix #16516 * fix comment * Trigger build --- compiler/cgmeth.nim | 2 +- tests/method/tmethod_issues.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 5c5d35093..a995804c7 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -67,7 +67,7 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult = while true: aa = skipTypes(aa, {tyGenericInst, tyAlias}) bb = skipTypes(bb, {tyGenericInst, tyAlias}) - if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent}: + if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent, tySink}: aa = aa.lastSon bb = bb.lastSon else: diff --git a/tests/method/tmethod_issues.nim b/tests/method/tmethod_issues.nim index 80f54caee..df4c3771a 100644 --- a/tests/method/tmethod_issues.nim +++ b/tests/method/tmethod_issues.nim @@ -2,6 +2,8 @@ discard """ output: ''' wof! wof! +type A +type B ''' """ @@ -126,3 +128,34 @@ var obj2 = Class2() obj1.test(obj2) obj2.test(obj1) + + +# ------------------------------------------------------- +# issue #16516 + +type + A = ref object of RootObj + x: int + + B = ref object of A + +method foo(v: sink A, lst: var seq[A]) {.base,locks:0.} = + echo "type A" + lst.add v + +method foo(v: sink B, lst: var seq[A]) = + echo "type B" + lst.add v + +proc main() = + let + a = A(x: 5) + b: A = B(x: 5) + + var lst: seq[A] + + foo(a, lst) + foo(b, lst) + +main() + From 0d5cab77f65df1431ed417a666ba49136af3b2c1 Mon Sep 17 00:00:00 2001 From: inv2004 Date: Wed, 6 Jan 2021 20:42:49 +0300 Subject: [PATCH 1779/4254] jsonutils: fromJson forward opt param fix (#16612) --- lib/std/jsonutils.nim | 8 ++++---- tests/stdlib/tjsonutils.nim | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 24935f511..4dca024c1 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -201,17 +201,17 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = if b.kind == JNull: a = nil else: a = T() - fromJson(a[], b) + fromJson(a[], b, opt) elif T is array: checkJson a.len == b.len, $(a.len, b.len, $T) var i = 0 for ai in mitems(a): - fromJson(ai, b[i]) + fromJson(ai, b[i], opt) i.inc elif T is seq: a.setLen b.len for i, val in b.getElems: - fromJson(a[i], val) + fromJson(a[i], val, opt) elif T is object: template fun(key, typ): untyped {.used.} = if b.hasKey key: @@ -237,7 +237,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = checkJson b.kind == JArray, $(b.kind) # we could customize whether to allow JNull var i = 0 for val in fields(a): - fromJson(val, b[i]) + fromJson(val, b[i], opt) i.inc checkJson b.len == i, $(b.len, i, $T, b) # could customize else: diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 28f05ecbe..f56c32719 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -118,6 +118,20 @@ template fn() = testRoundtrip(Foo[int](t1: false, z2: 7)): """{"t1":false,"z2":7}""" # pending https://github.com/nim-lang/Nim/issues/14698, test with `type Foo[T] = ref object` + block: # bug: pass opt params in fromJson + type Foo = object + a: int + b: string + c: float + var f: seq[Foo] + try: + fromJson(f, parseJson """[{"b": "bbb"}]""") + doAssert false + except ValueError: + doAssert true + fromJson(f, parseJson """[{"b": "bbb"}]""", Joptions(allowExtraKeys: true, allowMissingKeys: true)) + doAssert f == @[Foo(a: 0, b: "bbb", c: 0.0)] + block testHashSet: testRoundtrip(HashSet[string]()): "[]" testRoundtrip([""].toHashSet): """[""]""" From c21360e67accbbad0c24c84432fdb4506f68c881 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 6 Jan 2021 10:28:17 -0800 Subject: [PATCH 1780/4254] macros.quote: document hard to use `op`; add more useful examples (#16489) * macros.quote: document hard to use `op`; add more useful examples * add back doc comment removed in a60305fbf3897cd90680e693dd4c0db2334d85d4 * address comment * fixup * clarify quoting rules * Update lib/core/macros.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- lib/core/macros.nim | 94 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 23 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 748464061..204123f41 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -566,34 +566,82 @@ proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEf ## macro FooMacro() = ## var ast = getAst(BarTemplate()) -proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} +proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} = ## Quasi-quoting operator. ## Accepts an expression or a block and returns the AST that represents it. ## Within the quoted AST, you are able to interpolate NimNode expressions ## from the surrounding scope. If no operator is given, quoting is done using ## backticks. Otherwise, the given operator must be used as a prefix operator - ## for any interpolated expression. - ## - ## Example: - ## - ## .. code-block:: nim - ## - ## macro check(ex: untyped) = - ## # this is a simplified version of the check macro from the - ## # unittest module. - ## - ## # If there is a failed check, we want to make it easy for - ## # the user to jump to the faulty line in the code, so we - ## # get the line info here: - ## var info = ex.lineinfo - ## - ## # We will also display the code string of the failed check: - ## var expString = ex.toStrLit - ## - ## # Finally we compose the code to implement the check: - ## result = quote do: - ## if not `ex`: - ## echo `info` & ": Check failed: " & `expString` + ## for any interpolated expression. The original meaning of the interpolation + ## operator may be obtained by escaping it (by prefixing it with itself) when used + ## as a unary operator: + ## e.g. `@` is escaped as `@@`, `&%` is escaped as `&%&%` and so on; see examples. + runnableExamples: + macro check(ex: untyped) = + # this is a simplified version of the check macro from the + # unittest module. + + # If there is a failed check, we want to make it easy for + # the user to jump to the faulty line in the code, so we + # get the line info here: + var info = ex.lineinfo + + # We will also display the code string of the failed check: + var expString = ex.toStrLit + + # Finally we compose the code to implement the check: + result = quote do: + if not `ex`: + echo `info` & ": Check failed: " & `expString` + check 1 + 1 == 2 + + runnableExamples: + # example showing how to define a symbol that requires backtick without + # quoting it. + var destroyCalled = false + macro bar() = + let s = newTree(nnkAccQuoted, ident"=destroy") + # let s = ident"`=destroy`" # this would not work + result = quote do: + type Foo = object + # proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work + proc `s`(a: var Foo) = destroyCalled = true + block: + let a = Foo() + bar() + doAssert destroyCalled + + runnableExamples: + # custom `op` + var destroyCalled = false + macro bar() = + var x = 1.5 + result = quote("@") do: + type Foo = object + proc `=destroy`(a: var Foo) = + doAssert @x == 1.5 + doAssert compiles(@x == 1.5) + let b1 = @[1,2] + let b2 = @@[1,2] + doAssert $b1 == "[1, 2]" + doAssert $b2 == "@[1, 2]" + destroyCalled = true + block: + let a = Foo() + bar() + doAssert destroyCalled + + proc `&%`(x: int): int = 1 + proc `&%`(x, y: int): int = 2 + + macro bar2() = + var x = 3 + result = quote("&%") do: + var y = &%x # quoting operator + doAssert &%&%y == 1 # unary operator => need to escape + doAssert y &% y == 2 # binary operator => no need to escape + doAssert y == 3 + bar2() proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} = ## Checks that `n` is of kind `k`. If this is not the case, From 8a3b6190c3559061ca43cd73faba1a44170b1ee6 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Wed, 6 Jan 2021 20:16:26 +0100 Subject: [PATCH 1781/4254] Improve documentation for deques (#16589) --- lib/pure/collections/deques.nim | 262 +++++++++++++------------------- 1 file changed, 106 insertions(+), 156 deletions(-) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index f6d0f945e..7614b9d20 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -7,25 +7,24 @@ # distribution, for details about the copyright. # -## Implementation of a `deque`:idx: (double-ended queue). -## The underlying implementation uses a ``seq``. +## An implementation of a `deque`:idx: (double-ended queue). +## The underlying implementation uses a `seq`. ## -## None of the procs that get an individual value from the deque can be used +## Note that none of the procs that get an individual value from the deque should be used ## on an empty deque. -## If compiled with `boundChecks` option, those procs will raise an `IndexDefect` +## If compiled with the `boundChecks` option, those procs will raise an `IndexDefect` ## on such access. This should not be relied upon, as `-d:danger` or `--checks:off` will -## disable those checks and may return garbage or crash the program. +## disable those checks and then the procs may return garbage or crash the program. ## ## As such, a check to see if the deque is empty is needed before any ## access, unless your program logic guarantees it indirectly. runnableExamples: - var a = initDeque[int]() + var a = [10, 20, 30, 40].toDeque - doAssertRaises(IndexDefect, echo a[0]) + doAssertRaises(IndexDefect, echo a[4]) - for i in 1 .. 5: - a.addLast(10*i) + a.addLast(50) assert $a == "[10, 20, 30, 40, 50]" assert a.peekFirst == 10 @@ -44,7 +43,8 @@ runnableExamples: a.shrink(fromFirst = 1, fromLast = 2) assert $a == "[22, 11, 20]" -## **See also:** +## See also +## ======== ## * `lists module `_ for singly and doubly linked lists and rings ## * `channels module `_ for inter-thread communication @@ -54,9 +54,10 @@ import math type Deque*[T] = object - ## A double-ended queue backed with a ringed seq buffer. + ## A double-ended queue backed with a ringed `seq` buffer. ## - ## To initialize an empty deque use `initDeque proc <#initDeque,int>`_. + ## To initialize an empty deque, + ## use the `initDeque proc <#initDeque,int>`_. data: seq[T] head, tail, count, mask: int @@ -65,7 +66,7 @@ const template initImpl(result: typed, initialSize: int) = let correctSize = nextPowerOfTwo(initialSize) - result.mask = correctSize-1 + result.mask = correctSize - 1 newSeq(result.data, correctSize) template checkIfInitialized(deq: typed) = @@ -73,27 +74,27 @@ template checkIfInitialized(deq: typed) = if deq.mask == 0: initImpl(deq, defaultInitialSize) -proc initDeque*[T](initialSize: int = 4): Deque[T] = +proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] = ## Creates a new empty deque. ## ## Optionally, the initial capacity can be reserved via `initialSize` - ## as a performance optimization. + ## as a performance optimization + ## (default: `defaultInitialSize <#defaultInitialSize>`_). ## The length of a newly created deque will still be 0. ## - ## See also: + ## **See also:** ## * `toDeque proc <#toDeque,openArray[T]>`_ result.initImpl(initialSize) proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} = ## Creates a new deque that contains the elements of `x` (in the same order). ## - ## See also: + ## **See also:** ## * `initDeque proc <#initDeque,int>`_ runnableExamples: - var a = toDeque([7, 8, 9]) + let a = toDeque([7, 8, 9]) assert len(a) == 3 - assert a.popFirst == 7 - assert len(a) == 2 + assert $a == "[7, 8, 9]" result.initImpl(x.len) for item in items(x): @@ -120,11 +121,9 @@ template xBoundsCheck(deq, i) = "Out of bounds: " & $i & " < 0") proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = - ## Accesses the i-th element of `deq`. + ## Accesses the `i`-th element of `deq`. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + let a = [10, 20, 30, 40, 50].toDeque assert a[0] == 10 assert a[3] == 40 doAssertRaises(IndexDefect, echo a[8]) @@ -133,25 +132,20 @@ proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = return deq.data[(deq.head + i) and deq.mask] proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} = - ## Accesses the i-th element of `deq` and return a mutable + ## Accesses the `i`-th element of `deq` and returns a mutable ## reference to it. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) - assert a[0] == 10 - assert a[3] == 40 - doAssertRaises(IndexDefect, echo a[8]) + var a = [10, 20, 30, 40, 50].toDeque + inc(a[0]) + assert a[0] == 11 xBoundsCheck(deq, i) return deq.data[(deq.head + i) and deq.mask] proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = - ## Changes the i-th element of `deq`. + ## Sets the `i`-th element of `deq` to `val`. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque a[0] = 99 a[3] = 66 assert $a == "[99, 20, 30, 66, 50]" @@ -161,13 +155,11 @@ proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = deq.data[(deq.head + i) and deq.mask] = val proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = - ## Accesses the backwards indexed i-th element. + ## Accesses the backwards indexed `i`-th element. ## ## `deq[^1]` is the last element. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + let a = [10, 20, 30, 40, 50].toDeque assert a[^1] == 50 assert a[^4] == 20 doAssertRaises(IndexDefect, echo a[^9]) @@ -176,28 +168,24 @@ proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = return deq[deq.len - int(i)] proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} = - ## Accesses the backwards indexed i-th element. + ## Accesses the backwards indexed `i`-th element and returns a mutable + ## reference to it. ## ## `deq[^1]` is the last element. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) - assert a[^1] == 50 - assert a[^4] == 20 - doAssertRaises(IndexDefect, echo a[^9]) + var a = [10, 20, 30, 40, 50].toDeque + inc(a[^1]) + assert a[^1] == 51 xBoundsCheck(deq, deq.len - int(i)) return deq[deq.len - int(i)] proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = - ## Changes the backwards indexed i-th element. + ## Sets the backwards indexed `i`-th element of `deq` to `x`. ## ## `deq[^1]` is the last element. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque a[^1] = 99 a[^3] = 77 assert $a == "[10, 20, 77, 40, 99]" @@ -208,14 +196,15 @@ proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = iterator items*[T](deq: Deque[T]): T = ## Yields every element of `deq`. + ## + ## **See also:** + ## * `mitems iterator <#mitems,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 3: - a.addLast(10*i) - from sugar import collect - doAssert collect(for x in a: x) == [10, 20, 30] - # same as above: - doAssert collect(for x in items(a): x) == [10, 20, 30] + from sequtils import toSeq + + let a = [10, 20, 30, 40, 50].toDeque + assert toSeq(a.items) == @[10, 20, 30, 40, 50] + var i = deq.head for c in 0 ..< deq.count: yield deq.data[i] @@ -223,13 +212,14 @@ iterator items*[T](deq: Deque[T]): T = iterator mitems*[T](deq: var Deque[T]): var T = ## Yields every element of `deq`, which can be modified. + ## + ## **See also:** + ## * `items iterator <#items,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" for x in mitems(a): - x = 5*x - 1 + x = 5 * x - 1 assert $a == "[49, 99, 149, 199, 249]" var i = deq.head @@ -238,13 +228,13 @@ iterator mitems*[T](deq: var Deque[T]): var T = i = (i + 1) and deq.mask iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = - ## Yields every (position, value) of `deq`. + ## Yields every `(position, value)`-pair of `deq`. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 3: - a.addLast(10*i) - from sugar import collect - doAssert collect(for k, v in pairs(a): (k, v)) == @[(0, 10), (1, 20), (2, 30)] + from sequtils import toSeq + + let a = [10, 20, 30].toDeque + assert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)] + var i = deq.head for c in 0 ..< deq.count: yield (c, deq.data[i]) @@ -253,13 +243,14 @@ iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = proc contains*[T](deq: Deque[T], item: T): bool {.inline.} = ## Returns true if `item` is in `deq` or false if not found. ## - ## Usually used via the ``in`` operator. - ## It is the equivalent of ``deq.find(item) >= 0``. + ## Usually used via the `in` operator. + ## It is the equivalent of `deq.find(item) >= 0`. runnableExamples: - var q = [7, 9].toDeque + let q = [7, 9].toDeque assert 7 in q - assert q.contains 7 + assert q.contains(7) assert 8 notin q + for e in deq: if e == item: return true return false @@ -280,18 +271,14 @@ proc expandIfNeeded[T](deq: var Deque[T]) = deq.head = 0 proc addFirst*[T](deq: var Deque[T], item: T) = - ## Adds an `item` to the beginning of the `deq`. + ## Adds an `item` to the beginning of `deq`. ## - ## See also: + ## **See also:** ## * `addLast proc <#addLast,Deque[T],T>`_ - ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `peekLast proc <#peekLast,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: var a = initDeque[int]() for i in 1 .. 5: - a.addFirst(10*i) + a.addFirst(10 * i) assert $a == "[50, 40, 30, 20, 10]" expandIfNeeded(deq) @@ -300,18 +287,14 @@ proc addFirst*[T](deq: var Deque[T], item: T) = deq.data[deq.head] = item proc addLast*[T](deq: var Deque[T], item: T) = - ## Adds an `item` to the end of the `deq`. + ## Adds an `item` to the end of `deq`. ## - ## See also: + ## **See also:** ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `peekLast proc <#peekLast,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: var a = initDeque[int]() for i in 1 .. 5: - a.addLast(10*i) + a.addLast(10 * i) assert $a == "[10, 20, 30, 40, 50]" expandIfNeeded(deq) @@ -322,16 +305,11 @@ proc addLast*[T](deq: var Deque[T], item: T) = proc peekFirst*[T](deq: Deque[T]): T {.inline.} = ## Returns the first element of `deq`, but does not remove it from the deque. ## - ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ + ## **See also:** + ## * `peekFirst proc <#peekFirst,Deque[T]_2>`_ which returns a mutable reference ## * `peekLast proc <#peekLast,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + let a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.peekFirst == 10 assert len(a) == 5 @@ -342,16 +320,11 @@ proc peekFirst*[T](deq: Deque[T]): T {.inline.} = proc peekLast*[T](deq: Deque[T]): T {.inline.} = ## Returns the last element of `deq`, but does not remove it from the deque. ## - ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ + ## **See also:** + ## * `peekLast proc <#peekLast,Deque[T]_2>`_ which returns a mutable reference ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + let a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.peekLast == 50 assert len(a) == 5 @@ -360,41 +333,31 @@ proc peekLast*[T](deq: Deque[T]): T {.inline.} = result = deq.data[(deq.tail - 1) and deq.mask] proc peekFirst*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = - ## Returns the first element of `deq`, but does not remove it from the deque. + ## Returns a mutable reference to the first element of `deq`, + ## but does not remove it from the deque. ## - ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ - ## * `peekLast proc <#peekLast,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ + ## **See also:** + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `peekLast proc <#peekLast,Deque[T]_2>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) - assert $a == "[10, 20, 30, 40, 50]" - assert a.peekFirst == 10 - assert len(a) == 5 + var a = [10, 20, 30, 40, 50].toDeque + a.peekFirst() = 99 + assert $a == "[99, 20, 30, 40, 50]" emptyCheck(deq) result = deq.data[deq.head] proc peekLast*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = - ## Returns the last element of `deq`, but does not remove it from the deque. + ## Returns a mutable reference to the last element of `deq`, + ## but does not remove it from the deque. ## - ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ - ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `popLast proc <#popLast,Deque[T]>`_ + ## **See also:** + ## * `peekFirst proc <#peekFirst,Deque[T]_2>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) - assert $a == "[10, 20, 30, 40, 50]" - assert a.peekLast == 50 - assert len(a) == 5 + var a = [10, 20, 30, 40, 50].toDeque + a.peekLast() = 99 + assert $a == "[10, 20, 30, 40, 99]" emptyCheck(deq) result = deq.data[(deq.tail - 1) and deq.mask] @@ -406,17 +369,10 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = ## Removes and returns the first element of the `deq`. ## ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ - ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `peekLast proc <#peekLast,Deque[T]>`_ ## * `popLast proc <#popLast,Deque[T]>`_ - ## * `clear proc <#clear,Deque[T]>`_ ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.popFirst == 10 assert $a == "[20, 30, 40, 50]" @@ -430,18 +386,11 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = ## Removes and returns the last element of the `deq`. ## - ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ - ## * `peekFirst proc <#peekFirst,Deque[T]>`_ - ## * `peekLast proc <#peekLast,Deque[T]>`_ + ## **See also:** ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `clear proc <#clear,Deque[T]>`_ ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.popLast == 50 assert $a == "[10, 20, 30, 40]" @@ -455,14 +404,11 @@ proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = proc clear*[T](deq: var Deque[T]) {.inline.} = ## Resets the deque so that it is empty. ## - ## See also: - ## * `clear proc <#clear,Deque[T]>`_ + ## **See also:** ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addFirst(10*i) - assert $a == "[50, 40, 30, 20, 10]" + var a = [10, 20, 30, 40, 50].toDeque + assert $a == "[10, 20, 30, 40, 50]" clear(a) assert len(a) == 0 @@ -477,15 +423,15 @@ proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = ## If the supplied number of elements exceeds the total number of elements ## in the deque, the deque will remain empty. ## - ## See also: + ## **See also:** ## * `clear proc <#clear,Deque[T]>`_ + ## * `popFirst proc <#popFirst,Deque[T]>`_ + ## * `popLast proc <#popLast,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addFirst(10*i) - assert $a == "[50, 40, 30, 20, 10]" + var a = [10, 20, 30, 40, 50].toDeque + assert $a == "[10, 20, 30, 40, 50]" a.shrink(fromFirst = 2, fromLast = 1) - assert $a == "[30, 20]" + assert $a == "[30, 40]" if fromFirst + fromLast > deq.count: clear(deq) @@ -503,6 +449,10 @@ proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = proc `$`*[T](deq: Deque[T]): string = ## Turns a deque into its string representation. + runnableExamples: + let a = [10, 20, 30].toDeque + assert $a == "[10, 20, 30]" + result = "[" for x in deq: if result.len > 1: result.add(", ") From 21dfa04cbf638f4059244b4cecf1906b84889a1e Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Wed, 6 Jan 2021 11:26:16 -0800 Subject: [PATCH 1782/4254] fixes nim-lang/nimsuggest#119 outline includes (#16608) nimsuggest outline should account for includes, now it does: - the module prefix will be of the module doing the including - the filename will be of the module that was included - adds a test case for it --- compiler/suggest.nim | 16 +++++++++++++--- nimsuggest/tests/tinclude.nim | 10 ++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 186b23cd9..73929f813 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -491,9 +491,19 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; findUsages(conf, info, s, usageSym) elif conf.ideCmd == ideHighlight and info.fileIndex == conf.m.trackPos.fileIndex: suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) - elif conf.ideCmd == ideOutline and info.fileIndex == conf.m.trackPos.fileIndex and - isDecl: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) + elif conf.ideCmd == ideOutline and isDecl: + # if a module is included then the info we have is inside the include and + # we need to walk up the owners until we find the outer most module, + # which will be the last skModule prior to an skPackage. + var + parentFileIndex = info.fileIndex # assume we're in the correct module + parentModule = s.owner + while parentModule != nil and parentModule.kind == skModule: + parentFileIndex = parentModule.info.fileIndex + parentModule = parentModule.owner + + if parentFileIndex == conf.m.trackPos.fileIndex: + suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) proc extractPragma(s: PSym): PNode = if s.kind in routineKinds: diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 23aa2d727..b67440b9e 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -1,4 +1,6 @@ -# import that has an include, def calls must work into and out of includes +# import that has an include: +# * def calls must work into and out of includes +# * outline calls on the import must show included members import fixtures/minclude_import proc go() = @@ -8,12 +10,16 @@ go() discard """ $nimsuggest --tester $file ->def $path/tinclude.nim:5:14 +>def $path/tinclude.nim:7:14 def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, locks: 0.};;*fixtures/minclude_include.nim;;3;;5;;"";;100 >def $path/fixtures/minclude_include.nim:3:71 def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 >def $path/fixtures/minclude_include.nim:3:71 def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 +>outline $path/fixtures/minclude_import.nim +outline;;skProc;;minclude_import.say;;*fixtures/minclude_import.nim;;7;;5;;"";;100 +outline;;skProc;;minclude_import.create;;*fixtures/minclude_include.nim;;3;;5;;"";;100 +outline;;skProc;;minclude_import.say;;*fixtures/minclude_import.nim;;13;;5;;"";;100 """ # TODO test/fix if the first `def` is not first or repeated we get no results From 025ca660f7fe396ec6794137c29845feaf7ab9a3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 6 Jan 2021 11:28:24 -0800 Subject: [PATCH 1783/4254] [backport 1.0] add backend support for js bigint (#16606) * add backend support for js bigint * cleanup * add tests * add -d:nimHasJsBigIntBackend * cleanup * more tests --- compiler/condsyms.nim | 1 + compiler/jsgen.nim | 5 +++- tests/js/tbigint_backend.nim | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/js/tbigint_backend.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 131f32f32..55f2b4a0f 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -123,3 +123,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasEffectTraitsModule") defineSymbol("nimHasCastPragmaBlocks") defineSymbol("nimHasDeclaredLocs") + defineSymbol("nimHasJsBigIntBackend") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 675a24c92..4b369210d 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1677,7 +1677,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: - result = putToSeq("0", indirect) + if $t.sym.loc.r == "bigint": + result = putToSeq("0n", indirect) + else: + result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) of tyRange, tyGenericInst, tyAlias, tySink, tyOwned: diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim new file mode 100644 index 000000000..db7ebb065 --- /dev/null +++ b/tests/js/tbigint_backend.nim @@ -0,0 +1,58 @@ +proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".} + ## Returns the name of the JsObject's JavaScript type as a cstring. + # xxx replace jsffi.jsTypeOf with this definition and add tests + +type JsBigIntImpl {.importc: "bigint".} = int +type JsBigInt = distinct JsBigIntImpl + +doAssert JsBigInt isnot int +func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} +func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} +func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} +func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".} +func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".} +func inc2*(x: var JsBigInt) {.importjs: "#++".} +func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".} +func `$`*(this: JsBigInt): string = + $toCstring(this) + +block: + doAssert defined(nimHasJsBigIntBackend) + let z1 = big"10" + let z2 = big"15" + doAssert z1 == big"10" + doAssert z1 == z1 + doAssert z1 != z2 + var s: seq[cstring] + for i in z1 .. z2: + s.add $i + doAssert s == @["10".cstring, "11", "12", "13", "14", "15"] + block: + var a=big"3" + a.inc + doAssert a == big"4" + block: + var z: JsBigInt + doAssert $z == "0" + doAssert z.jsTypeOf == "bigint" # would fail without codegen change + doAssert z != big(1) + doAssert z == big"0" # ditto + + # ditto below + block: + let z: JsBigInt = big"1" + doAssert $z == "1" + doAssert z.jsTypeOf == "bigint" + doAssert z == big"1" + + block: + let z = JsBigInt.default + doAssert $z == "0" + doAssert z.jsTypeOf == "bigint" + doAssert z == big"0" + + block: + var a: seq[JsBigInt] + a.setLen 3 + doAssert a[^1].jsTypeOf == "bigint" + doAssert a[^1] == big"0" From d34d023da1d7af972366c3af58a144b395964b4c Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Wed, 6 Jan 2021 20:29:22 +0100 Subject: [PATCH 1784/4254] Minor docs/format changes (cpuinfo, volatile) (#16602) --- lib/pure/concurrency/cpuinfo.nim | 19 +++++++++---------- lib/pure/volatile.nim | 4 ++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 3e5695360..57d13fde3 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -7,7 +7,11 @@ # distribution, for details about the copyright. # -## This module implements procs to determine the number of CPUs / cores. +## This module implements a proc to determine the number of CPUs / cores. + +runnableExamples: + doAssert countProcessors() > 0 + include "system/inclrtl" @@ -15,15 +19,15 @@ when not defined(windows): import posix when defined(freebsd) or defined(macosx): - {.emit:"#include ".} + {.emit: "#include ".} when defined(openbsd) or defined(netbsd): - {.emit:"#include ".} + {.emit: "#include ".} when defined(macosx) or defined(bsd): # we HAVE to emit param.h before sysctl.h so we cannot use .header here # either. The amount of archaic bullshit in Poonix based OSes is just insane. - {.emit:"#include ".} + {.emit: "#include ".} const CTL_HW = 6 HW_AVAILCPU = 25 @@ -47,7 +51,7 @@ when defined(haiku): header: "".} proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = - ## returns the number of the processors/cores the machine has. + ## Returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. when defined(windows): type @@ -95,8 +99,3 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = else: result = sysconf(SC_NPROCESSORS_ONLN) if result <= 0: result = 0 - - -runnableExamples: - block: - doAssert countProcessors() > 0 diff --git a/lib/pure/volatile.nim b/lib/pure/volatile.nim index 208f0fcaa..7fdf40e4b 100644 --- a/lib/pure/volatile.nim +++ b/lib/pure/volatile.nim @@ -12,7 +12,7 @@ template volatileLoad*[T](src: ptr T): T = ## Generates a volatile load of the value stored in the container `src`. - ## Note that this only effects code generation on `C` like backends + ## Note that this only effects code generation on `C` like backends. when nimvm: src[] else: @@ -26,7 +26,7 @@ template volatileLoad*[T](src: ptr T): T = template volatileStore*[T](dest: ptr T, val: T) = ## Generates a volatile store into the container `dest` of the value ## `val`. Note that this only effects code generation on `C` like - ## backends + ## backends. when nimvm: dest[] = val else: From 04b765c16d4a53c03f8d41c9b9ad97ac4ac8189e Mon Sep 17 00:00:00 2001 From: inv2004 Date: Thu, 7 Jan 2021 05:09:02 +0300 Subject: [PATCH 1785/4254] Jsonutils: pass opt for object in object (#16615) * jsonutils: fromJson forward opt param fix * jsonutils: object in object test + fix: opt pass --- lib/std/jsonutils.nim | 2 +- tests/stdlib/tjsonutils.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 4dca024c1..b9e47bd70 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -119,7 +119,7 @@ template fromJsonFields(newObj, oldObj, json, discKeys, opt) = when key notin discKeys: if json.hasKey key: numMatched.inc - fromJson(val, json[key]) + fromJson(val, json[key], opt) elif opt.allowMissingKeys: # if there are no discriminant keys the `oldObj` must always have the # same keys as the new one. Otherwise we must check, because they could diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index f56c32719..06d01a9fb 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -123,6 +123,9 @@ template fn() = a: int b: string c: float + type Bar = object + foo: Foo + boo: string var f: seq[Foo] try: fromJson(f, parseJson """[{"b": "bbb"}]""") @@ -131,6 +134,9 @@ template fn() = doAssert true fromJson(f, parseJson """[{"b": "bbb"}]""", Joptions(allowExtraKeys: true, allowMissingKeys: true)) doAssert f == @[Foo(a: 0, b: "bbb", c: 0.0)] + var b: Bar + fromJson(b, parseJson """{"foo": {"b": "bbb"}}""", Joptions(allowExtraKeys: true, allowMissingKeys: true)) + doAssert b == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0)) block testHashSet: testRoundtrip(HashSet[string]()): "[]" From 4754806fb5d6afb034dc2d27959353ec579b08e4 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 7 Jan 2021 07:39:56 +0000 Subject: [PATCH 1786/4254] Fixes the asynchttpserver example some more (#16599) I dislike this example a lot (busy looping for FDs to be closed is a very poor waste of resources) but at least with these changes it's a little bit better. --- lib/pure/asynchttpserver.nim | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index d9f5a3a0f..29a695379 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -18,29 +18,28 @@ runnableExamples: # This example will create an HTTP server on port 8080. The server will # respond to all requests with a `200 OK` response code and "Hello World" # as the response body. Run locally with: - # `nim doc --doccmd:-d:nimAsynchttpserverEnableTest --lib:lib lib/pure/asynchttpserver.nim` + # `nim doc --doccmd:-d:nimAsyncHttpServerEnableTest --lib:lib lib/pure/asynchttpserver.nim` import asyncdispatch - if defined(nimAsynchttpserverEnableTest): + if defined(nimAsyncHttpServerEnableTest): proc main {.async.} = const port = 8080 var server = newAsyncHttpServer() proc cb(req: Request) {.async.} = echo (req.reqMethod, req.url, req.headers) - let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", - "Content-type": "text/plain; charset=utf-8"} + let headers = {"Content-type": "text/plain; charset=utf-8"} await req.respond(Http200, "Hello World", headers.newHttpHeaders()) echo "test this with: curl localhost:" & $port & "/" - server.listen Port(port) + server.listen(Port(port)) while true: if server.shouldAcceptRequest(): await server.acceptRequest(cb) else: # too many concurrent connections, `maxFDs` exceeded - poll() + # wait 500ms for FDs to be closed + await sleepAsync(500) - asyncCheck main() - runForever() + waitFor main() import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore From bab0aa6ecf8b91f9befaebefd0d4d5adeaac3ac3 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 7 Jan 2021 01:48:02 -0600 Subject: [PATCH 1787/4254] add math.signbit (#16592) --- changelog.md | 3 +++ compiler/vmops.nim | 6 ++++++ lib/pure/math.nim | 27 ++++++++++++++++++++++++++- tests/stdlib/tmath.nim | 10 ++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 306cf54d3..4e9b8c162 100644 --- a/changelog.md +++ b/changelog.md @@ -93,6 +93,9 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. + +- Added `math.signbit`. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 3e859d3d7..504a352b5 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -16,6 +16,9 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, when declared(math.copySign): from math import copySign +when declared(math.signbit): + from math import signbit + from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename from md5 import getMD5 from sighashes import symBodyDigest @@ -174,6 +177,9 @@ proc registerAdditionalOps*(c: PCtx) = when declared(copySign): wrap2f_math(copySign) + when declared(signbit): + wrap1f_math(signbit) + wrap1s(getMD5, md5op) proc `mod Wrapper`(a: VmArgs) {.nimcall.} = diff --git a/lib/pure/math.nim b/lib/pure/math.nim index a6a3676b9..bcda68afe 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -56,7 +56,7 @@ import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import bitops, fenv +import std/[bitops, fenv] when defined(c) or defined(cpp): proc c_isnan(x: float): bool {.importc: "isnan", header: "".} @@ -65,6 +65,8 @@ when defined(c) or defined(cpp): proc c_copysign(x, y: cfloat): cfloat {.importc: "copysignf", header: "".} proc c_copysign(x, y: cdouble): cdouble {.importc: "copysign", header: "".} + proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "".} + func binom*(n, k: int): int = ## Computes the `binomial coefficient `_. runnableExamples: @@ -156,6 +158,29 @@ func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = when defined(js): fn() else: result = c_isnan(x) +when defined(js): + proc toBitsImpl(x: float): array[2, uint32] = + asm """ + const buffer = new ArrayBuffer(8); + const floatBuffer = new Float64Array(buffer); + const uintBuffer = new Uint32Array(buffer); + floatBuffer[0] = `x`; + `result` = uintBuffer + """ + +proc signbit*(x: SomeFloat): bool {.inline, since: (1, 5, 1).} = + ## Returns true if `x` is negative, false otherwise. + runnableExamples: + doAssert not signbit(0.0) + doAssert signbit(-0.0) + doAssert signbit(-0.1) + doAssert not signbit(0.1) + when defined(js): + let uintBuffer = toBitsImpl(x) + result = (uintBuffer[1] shr 31) != 0 + else: + result = c_signbit(x) != 0 + func copySign*[T: SomeFloat](x, y: T): T {.inline, since: (1, 5, 1).} = ## Returns a value with the magnitude of `x` and the sign of `y`; ## this works even if x or y are NaN or zero, both of which can carry a sign. diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index e5cb58eba..62fdcd19f 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -304,6 +304,16 @@ block: template main = # xxx wrap all under `main` so it also gets tested in vm. + block: # signbit + doAssert not signbit(0.0) + doAssert signbit(-0.0) + doAssert signbit(-0.1) + doAssert not signbit(0.1) + + doAssert not signbit(Inf) + doAssert signbit(-Inf) + doAssert not signbit(NaN) + block: # isNaN doAssert NaN.isNaN doAssert not Inf.isNaN From 89a21e4ec71e705833d2aacd069e291cf41a19c6 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 7 Jan 2021 02:38:31 -0600 Subject: [PATCH 1788/4254] oids: switch from PRNG to random module (#16203) * switch from PRNG to random module * fix the regression * comments + tests * runnableExamples * make oids better --- lib/pure/oids.nim | 39 +++++++++++++++++++-------------------- tests/stdlib/toids.nim | 6 ++++++ 2 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 tests/stdlib/toids.nim diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index d3a7c4fb6..957a8193a 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -12,24 +12,24 @@ ## produce a globally distributed unique ID. This implementation was extracted ## from the Mongodb interface and it thus binary compatible with a Mongo OID. ## -## This implementation calls ``math.randomize()`` for the first call of +## This implementation calls `initRand()` for the first call of ## ``genOid``. -import hashes, times, endians +import hashes, times, endians, random type - Oid* = object ## an OID + Oid* = object ## An OID. time: int32 ## fuzz: int32 ## count: int32 ## proc `==`*(oid1: Oid, oid2: Oid): bool = - ## Compare two Mongo Object IDs for equality + ## Compares two Mongo Object IDs for equality. return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) proc hash*(oid: Oid): Hash = - ## Generate hash of Oid for use in hashtables + ## Generates hash of Oid for use in hashtables. var h: Hash = 0 h = h !& hash(oid.time) h = h !& hash(oid.fuzz) @@ -44,7 +44,7 @@ proc hexbyte*(hex: char): int = else: discard proc parseOid*(str: cstring): Oid = - ## parses an OID. + ## Parses an OID. var bytes = cast[cstring](addr(result.time)) var i = 0 while i < 12: @@ -52,6 +52,7 @@ proc parseOid*(str: cstring): Oid = inc(i) proc oidToString*(oid: Oid, str: cstring) = + ## Converts an oid to `str` which must have space allocated for 25 elements. const hex = "0123456789abcdef" # work around a compiler bug: var str = str @@ -66,35 +67,33 @@ proc oidToString*(oid: Oid, str: cstring) = str[24] = '\0' proc `$`*(oid: Oid): string = + ## Converts an oid to string. result = newString(24) oidToString(oid, result) -proc rand(): cint {.importc: "rand", header: "", nodecl.} -proc srand(seed: cint) {.importc: "srand", header: "", nodecl.} - -var t = getTime().toUnix.int32 -srand(t) var - incr: int = rand() - fuzz: int32 = rand() + t = getTime().toUnix.int32 + seed = initRand(t) + incr: int = seed.rand(int.high) + +let fuzz = cast[int32](seed.rand(high(int))) proc genOid*(): Oid = - ## generates a new OID. + ## Generates a new OID. + runnableExamples: + doAssert ($genOid()).len == 24 + if false: doAssert $genOid() == "5fc7f546ddbbc84800006aaf" t = getTime().toUnix.int32 - var i = int32(atomicInc(incr)) + var i = cast[int32](atomicInc(incr)) bigEndian32(addr result.time, addr(t)) result.fuzz = fuzz bigEndian32(addr result.count, addr(i)) proc generatedTime*(oid: Oid): Time = - ## returns the generated timestamp of the OID. + ## Returns the generated timestamp of the OID. var tmp: int32 var dummy = oid.time bigEndian32(addr(tmp), addr(dummy)) result = fromUnix(tmp) - -when not defined(testing) and isMainModule: - let xo = genOid() - echo xo.generatedTime diff --git a/tests/stdlib/toids.nim b/tests/stdlib/toids.nim new file mode 100644 index 000000000..f162dbe57 --- /dev/null +++ b/tests/stdlib/toids.nim @@ -0,0 +1,6 @@ +import std/oids + + +block: # genOid + let x = genOid() + doAssert ($x).len == 24 From 0e7902b976fbd0e566f0fb5f4915695aca406451 Mon Sep 17 00:00:00 2001 From: PMunch Date: Thu, 7 Jan 2021 16:09:57 +0100 Subject: [PATCH 1789/4254] Implements streams for sockets (#15729) --- changelog.md | 2 + lib/std/socketstreams.nim | 181 ++++++++++++++++++++++++++++++++ tests/stdlib/tsocketstreams.nim | 64 +++++++++++ 3 files changed, 247 insertions(+) create mode 100644 lib/std/socketstreams.nim create mode 100644 tests/stdlib/tsocketstreams.nim diff --git a/changelog.md b/changelog.md index 4e9b8c162..afe49f1f3 100644 --- a/changelog.md +++ b/changelog.md @@ -91,6 +91,8 @@ - `math.round` now is rounded "away from zero" in JS backend which is consistent with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. +- Added `socketstream` module that wraps sockets in the stream interface + diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim new file mode 100644 index 000000000..5c882858d --- /dev/null +++ b/lib/std/socketstreams.nim @@ -0,0 +1,181 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2021 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module provides an implementation of the streams interface for sockets. +## It contains two separate implementations, a +## `ReadSocketStream <#ReadSocketStream>`_ and a +## `WriteSocketStream <#WriteSocketStream>`_. +## +## The `ReadSocketStream` only supports reading, peeking, and seeking. +## It reads into a buffer, so even by +## seeking backwards it will only read the same position a single time from the +## underlying socket. To clear the buffer and free the data read into it you +## can call `resetStream`, this will also reset the position back to 0 but +## won't do anything to the underlying socket. +## +## The `WriteSocketStream` allows both reading and writing, but it performs the +## reads on the internal buffer. So by writing to the buffer you can then read +## back what was written but without receiving anything from the socket. You +## can also set the position and overwrite parts of the buffer, and to send +## anything over the socket you need to call `flush` at which point you can't +## write anything to the buffer before the point of the flush (but it can still +## be read). Again to empty the underlying buffer you need to call +## `resetStream`. +## +## Examples +## ======== +## +## .. code-block:: Nim +## import std/socketstreams +## +## var +## socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) +## stream = newReadSocketStream(socket) +## socket.sendTo("127.0.0.1", Port(12345), "SOME REQUEST") +## echo stream.readLine() # Will call `recv` +## stream.setPosition(0) +## echo stream.readLine() # Will return the read line from the buffer +## stream.resetStream() # Buffer is now empty, position is 0 +## echo stream.readLine() # Will call `recv` again +## stream.close() # Closes the socket +## +## .. code-block:: Nim +## +## import std/socketstreams +## +## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) +## socket.connect("127.0.0.1", Port(12345)) +## var sendStream = newWriteSocketStream(socket) +## sendStream.write "NOM" +## sendStream.setPosition(1) +## echo sendStream.peekStr(2) # OM +## sendStream.write "I" +## sendStream.setPosition(0) +## echo sendStream.readStr(3) # NIM +## echo sendStream.getPosition() # 3 +## sendStream.flush() # This actually performs the writing to the socket +## sendStream.setPosition(1) +## sendStream.write "I" # Throws an error as we can't write into an already sent buffer + +import net, streams + +type + ReadSocketStream* = ref ReadSocketStreamObj + ReadSocketStreamObj* = object of StreamObj + data: Socket + pos: int + buf: seq[byte] + WriteSocketStream* = ref WriteSocketStreamObj + WriteSocketStreamObj* = object of ReadSocketStreamObj + lastFlush: int + +proc rsAtEnd(s: Stream): bool = + return false + +proc rsSetPosition(s: Stream, pos: int) = + var s = ReadSocketStream(s) + s.pos = pos + +proc rsGetPosition(s: Stream): int = + var s = ReadSocketStream(s) + return s.pos + +proc rsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + let s = ReadSocketStream(s) + if bufLen > 0: + let oldLen = s.buf.len + s.buf.setLen(max(s.pos + bufLen, s.buf.len)) + if s.pos + bufLen > oldLen: + result = s.data.recv(s.buf[oldLen].addr, s.buf.len - oldLen) + if result > 0: + result += oldLen - s.pos + else: + result = bufLen + copyMem(buffer, s.buf[s.pos].addr, result) + +proc rsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = s.rsPeekData(buffer, bufLen) + var s = ReadSocketStream(s) + s.pos += bufLen + +proc rsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = + var s = ReadSocketStream(s) + result = slice.b + 1 - slice.a + if result > 0: + result = s.rsReadData(buffer[slice.a].addr, result) + inc(s.pos, result) + else: + result = 0 + +proc wsWriteData(s: Stream, buffer: pointer, bufLen: int) = + var s = WriteSocketStream(s) + if s.pos < s.lastFlush: + raise newException(IOError, "Unable to write into buffer that has already been sent") + if s.buf.len < s.pos + bufLen: + s.buf.setLen(s.pos + bufLen) + copyMem(s.buf[s.pos].addr, buffer, bufLen) + s.pos += bufLen + +proc wsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + var s = WriteSocketStream(s) + result = bufLen + if result > 0: + if s.pos > s.buf.len or s.pos == s.buf.len or s.pos + bufLen > s.buf.len: + raise newException(IOError, "Unable to read past end of write buffer") + else: + copyMem(buffer, s.buf[s.pos].addr, bufLen) + +proc wsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = s.wsPeekData(buffer, bufLen) + var s = ReadSocketStream(s) + s.pos += bufLen + +proc wsAtEnd(s: Stream): bool = + var s = WriteSocketStream(s) + return s.pos == s.buf.len + +proc wsFlush(s: Stream) = + var s = WriteSocketStream(s) + discard s.data.send(s.buf[s.lastFlush].addr, s.buf.len - s.lastFlush) + s.lastFlush = s.buf.len + +proc rsClose(s: Stream) = + {.cast(tags: []).}: + var s = ReadSocketStream(s) + s.data.close() + +proc newReadSocketStream*(s: Socket): owned ReadSocketStream = + result = ReadSocketStream(data: s, pos: 0, + closeImpl: rsClose, + atEndImpl: rsAtEnd, + setPositionImpl: rsSetPosition, + getPositionImpl: rsGetPosition, + readDataImpl: rsReadData, + peekDataImpl: rsPeekData, + readDataStrImpl: rsReadDataStr) + +proc resetStream*(s: ReadSocketStream) = + s.buf = @[] + s.pos = 0 + +proc newWriteSocketStream*(s: Socket): owned WriteSocketStream = + result = WriteSocketStream(data: s, pos: 0, + closeImpl: rsClose, + atEndImpl: wsAtEnd, + setPositionImpl: rsSetPosition, + getPositionImpl: rsGetPosition, + writeDataImpl: wsWriteData, + readDataImpl: wsReadData, + peekDataImpl: wsPeekData, + flushImpl: wsFlush) + +proc resetStream*(s: WriteSocketStream) = + s.buf = @[] + s.pos = 0 + s.lastFlush = 0 diff --git a/tests/stdlib/tsocketstreams.nim b/tests/stdlib/tsocketstreams.nim new file mode 100644 index 000000000..0cf952810 --- /dev/null +++ b/tests/stdlib/tsocketstreams.nim @@ -0,0 +1,64 @@ +discard """ + output: ''' +OM +NIM +3 +NIM +NIM +Hello server! +Hi there client! +'''""" +import std/socketstreams, net, streams + +block UDP: + var recvSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + var recvStream = newReadSocketStream(recvSocket) + recvSocket.bindAddr(Port(12345), "127.0.0.1") + + var sendSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + sendSocket.connect("127.0.0.1", Port(12345)) + var sendStream = newWriteSocketStream(sendSocket) + sendStream.write "NOM\n" + sendStream.setPosition(1) + echo sendStream.peekStr(2) + sendStream.write "I" + sendStream.setPosition(0) + echo sendStream.readStr(3) + echo sendStream.getPosition() + sendStream.flush() + + echo recvStream.readLine() + recvStream.setPosition(0) + echo recvStream.readLine() + recvStream.close() + +block TCP: + var server = newSocket() + server.setSockOpt(OptReusePort, true) + server.bindAddr(Port(12345)) + server.listen() + + var + client = newSocket() + clientRequestStream = newWriteSocketStream(client) + clientResponseStream = newReadSocketStream(client) + client.connect("127.0.0.1", Port(12345)) + clientRequestStream.writeLine("Hello server!") + clientRequestStream.flush() + + var + incoming: Socket + address: string + server.acceptAddr(incoming, address) + var + serverRequestStream = newReadSocketStream(incoming) + serverResponseStream = newWriteSocketStream(incoming) + echo serverRequestStream.readLine() + serverResponseStream.writeLine("Hi there client!") + serverResponseStream.flush() + serverResponseStream.close() + serverRequestStream.close() + + echo clientResponseStream.readLine() + clientResponseStream.close() + clientRequestStream.close() From cbf227d9493be1e82f3abec1d019ce397163635c Mon Sep 17 00:00:00 2001 From: haxscramper Date: Thu, 7 Jan 2021 21:14:50 +0300 Subject: [PATCH 1790/4254] [FIX] Update fusion master commit hash (#16630) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 5da262884..95c9c6161 100644 --- a/koch.nim +++ b/koch.nim @@ -11,7 +11,7 @@ const NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master - FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" + FusionStableCommit = "372ee4313827ef9f2ea388840f7d6b46c2b1b014" when not defined(windows): const From 0da4cb93d1924d99a91491c2ec6124d9ec2a413b Mon Sep 17 00:00:00 2001 From: rockcavera Date: Thu, 7 Jan 2021 15:16:26 -0300 Subject: [PATCH 1791/4254] minor fix (#16624) --- tests/stdlib/tbitops.nim.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stdlib/tbitops.nim.cfg b/tests/stdlib/tbitops.nim.cfg index f0d7668a7..013e8d38e 100644 --- a/tests/stdlib/tbitops.nim.cfg +++ b/tests/stdlib/tbitops.nim.cfg @@ -1 +1 @@ --d:noUndefinedBitOps +-d:noUndefinedBitOpts From 796498525a3d1197cd6468e4eb45b1fb47a702af Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 7 Jan 2021 20:26:40 +0100 Subject: [PATCH 1792/4254] IC: next steps (#16550) * cleanups * ast.nim: cleanups * IC: no more sym.tab field, stored externally in the module graph * nimble compiles again * rodfiles: store bitwidth of integers and the endianness in the cookie because we serialize 'int' directly * rodfiles: added compilerproc and export sections * rodfiles: added all the missing sections * rodfiles: track the missing information * IC: architecture for lazy loading of proc bodies * make tests green again * completed the lazy loading of proc bodies * symbol lookup integration, part 1 * symbol lookup integration, part 2 * symbol lookup integration, part 3 * make tcompilerapi work again * rodfiles: fixed config change handling --- compiler/ast.nim | 19 - ...nicalizer.nim => canonicalizer_unused.nim} | 0 compiler/ccgexprs.nim | 4 +- compiler/ccgtypes.nim | 12 +- compiler/commands.nim | 17 +- compiler/evaltempl.nim | 2 +- compiler/ic/packed_ast.nim | 23 - compiler/ic/rodfiles.nim | 48 +- compiler/ic/to_packed_ast.nim | 433 +++++++++++++----- compiler/idents.nim | 5 + compiler/importer.nim | 27 +- compiler/jsgen.nim | 6 +- compiler/lookups.nim | 56 +-- compiler/magicsys.nim | 7 +- compiler/modulegraphs.nim | 102 ++++- compiler/modules.nim | 70 +-- compiler/nimeval.nim | 13 +- compiler/packagehandling.nim | 3 +- compiler/passes.nim | 8 +- compiler/plugins/itersgen.nim | 4 +- compiler/pragmas.nim | 4 + compiler/sem.nim | 3 +- compiler/semdata.nim | 22 +- compiler/semexprs.nim | 28 +- compiler/semfields.nim | 2 +- compiler/semgnrc.nim | 2 +- compiler/seminst.nim | 4 +- compiler/semstmts.nim | 12 +- compiler/semtempl.nim | 2 +- compiler/semtypes.nim | 4 +- compiler/sighashes.nim | 2 +- compiler/suggest.nim | 77 ++-- compiler/transf.nim | 15 +- compiler/vm.nim | 2 +- compiler/vmgen.nim | 13 +- nimsuggest/nimsuggest.nim | 2 +- 36 files changed, 653 insertions(+), 400 deletions(-) rename compiler/{canonicalizer.nim => canonicalizer_unused.nim} (100%) diff --git a/compiler/ast.nim b/compiler/ast.nim index ccf4fe497..de4ab5b77 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -833,18 +833,6 @@ type procInstCache*: seq[PInstantiation] gcUnsafetyReason*: PSym # for better error messages wrt gcsafe transformedBody*: PNode # cached body after transf pass - of skModule, skPackage: - # modules keep track of the generic symbols they use from other modules. - # this is because in incremental compilation, when a module is about to - # be replaced with a newer version, we must decrement the usage count - # of all previously used generics. - # For 'import as' we copy the module symbol but shallowCopy the 'tab' - # and set the 'usedGenerics' to ... XXX gah! Better set module.name - # instead? But this doesn't work either. --> We need an skModuleAlias? - # No need, just leave it as skModule but set the owner accordingly and - # check for the owner when touching 'usedGenerics'. - usedGenerics*: seq[PInstantiation] - tab*: TStrTable # interface table for modules of skLet, skVar, skField, skForVar: guard*: PSym bitsize*: int @@ -1455,8 +1443,6 @@ proc copySym*(s: PSym; id: ItemId): PSym = result.typ = s.typ result.flags = s.flags result.magic = s.magic - if s.kind == skModule: - copyStrTable(result.tab, s.tab) result.options = s.options result.position = s.position result.loc = s.loc @@ -1474,13 +1460,10 @@ proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo; result.ast = s.ast #result.id = s.id # XXX figure out what to do with the ID. result.flags = s.flags - system.shallowCopy(result.tab, s.tab) result.options = s.options result.position = s.position result.loc = s.loc result.annex = s.annex - # XXX once usedGenerics is used, ensure module aliases keep working! - assert s.usedGenerics.len == 0 proc initStrTable*(x: var TStrTable) = x.counter = 0 @@ -1915,8 +1898,6 @@ template incompleteType*(t: PType): bool = template typeCompleted*(s: PSym) = incl s.flags, sfNoForward -template getBody*(s: PSym): PNode = s.ast[bodyPos] - template detailedInfo*(sym: PSym): string = sym.name.s diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer_unused.nim similarity index 100% rename from compiler/canonicalizer.nim rename to compiler/canonicalizer_unused.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b8a8d21b0..440ecdc7f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1292,7 +1292,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = genAssignment(p, a, b, {}) else: let ti = genTypeInfoV1(p.module, typ, a.lode.info) - if bt.destructor != nil and not isTrivialProc(bt.destructor): + if bt.destructor != nil and not isTrivialProc(p.module.g.graph, bt.destructor): # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: @@ -2204,7 +2204,7 @@ proc genDestroy(p: BProc; n: PNode) = else: discard "nothing to do" else: let t = n[1].typ.skipTypes(abstractVar) - if t.destructor != nil and t.destructor.ast[bodyPos].len != 0: + if t.destructor != nil and getBody(p.module.g.graph, t.destructor).len != 0: internalError(p.config, n.info, "destructor turned out to be not trivial") discard "ignore calls to the default destructor" diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index ab12bad1e..798eaf7f9 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -36,14 +36,6 @@ proc mangleField(m: BModule; name: PIdent): string = if isKeyword(name): result.add "_0" -when false: - proc hashOwner(s: PSym): SigHash = - var m = s - while m.kind != skModule: m = m.owner - let p = m.owner - assert p.kind == skPackage - result = gDebugInfo.register(p.name.s, m.name.s) - proc mangleName(m: BModule; s: PSym): Rope = result = s.loc.r if result == nil: @@ -1313,11 +1305,11 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope = it = it[0] result = makeCString(res) -proc isTrivialProc(s: PSym): bool {.inline.} = s.ast[bodyPos].len == 0 +proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0 proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = let theProc = t.attachedOps[op] - if theProc != nil and not isTrivialProc(theProc): + if theProc != nil and not isTrivialProc(m.g.graph, theProc): # the prototype of a destructor is ``=destroy(x: var T)`` and that of a # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # convention at least: diff --git a/compiler/commands.nim b/compiler/commands.nim index 9fb9b7e6e..adb85bdd7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -801,14 +801,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectNoArg(conf, switch, arg, pass, info) helpOnError(conf, pass) of "symbolfiles": discard "ignore for backwards compat" - of "incremental": - case arg.normalize - of "on": conf.symbolFiles = v2Sf - of "off": conf.symbolFiles = disabledSf - of "writeonly": conf.symbolFiles = writeOnlySf - of "readonly": conf.symbolFiles = readOnlySf - of "v2": conf.symbolFiles = v2Sf - else: localError(conf, info, "invalid option for --incremental: " & arg) + of "incremental", "ic": + if pass in {passCmd2, passPP}: + case arg.normalize + of "on": conf.symbolFiles = v2Sf + of "off": conf.symbolFiles = disabledSf + of "writeonly": conf.symbolFiles = writeOnlySf + of "readonly": conf.symbolFiles = readOnlySf + of "v2": conf.symbolFiles = v2Sf + else: localError(conf, info, "invalid option for --incremental: " & arg) of "skipcfg": processOnOffSwitchG(conf, {optSkipSystemConfigFile}, arg, pass, info) of "skipprojcfg": diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 691d33a2c..a85314ac2 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; ctx.instID = instID[] ctx.idgen = idgen - let body = tmpl.getBody + let body = tmpl.ast[bodyPos] #echo "instantion of ", renderTree(body, {renderIds}) if isAtom(body): result = newNodeI(nkPar, body.info) diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 546e495c5..cbfb0c5d1 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -16,28 +16,6 @@ import std / [hashes, tables, strtabs, md5] import bitabs import ".." / [ast, options] -const - localNamePos* = 0 - localExportMarkerPos* = 1 - localPragmaPos* = 2 - localTypePos* = 3 - localValuePos* = 4 - - typeNamePos* = 0 - typeExportMarkerPos* = 1 - typeGenericParamsPos* = 2 - typePragmaPos* = 3 - typeBodyPos* = 4 - - routineNamePos* = 0 - routineExportMarkerPos* = 1 - routinePatternPos* = 2 - routineGenericParamsPos* = 3 - routineParamsPos* = 4 - routineResultPos* = 5 - routinePragmasPos* = 6 - routineBodyPos* = 7 - const nkModuleRef* = nkNone # pair of (ModuleId, SymId) @@ -55,7 +33,6 @@ type TypeId* = PackedItemId const - nilTypeId* = PackedItemId(module: LitId(0), item: -1.int32) nilItemId* = PackedItemId(module: LitId(0), item: -1.int32) const diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 99ce183f2..725262120 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -18,6 +18,14 @@ type depsSection integersSection floatsSection + exportsSection + reexportsSection + compilerProcsSection + trmacrosSection + convertersSection + methodsSection + pureEnumsSection + macroUsagesSection topLevelSection bodiesSection symsSection @@ -36,26 +44,30 @@ type const RodVersion = 1 cookie = [byte(0), byte('R'), byte('O'), byte('D'), - byte(0), byte(0), byte(0), byte(RodVersion)] + byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)] + +proc setError(f: var RodFile; err: RodFileError) {.inline.} = + f.err = err + #raise newException(IOError, "IO error") proc storePrim*(f: var RodFile; s: string) = if f.err != ok: return if s.len >= high(int32): - f.err = tooBig + setError f, tooBig return var lenPrefix = int32(s.len) if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): - f.err = ioFailure + setError f, ioFailure else: if s.len != 0: if writeBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len: - f.err = ioFailure + setError f, ioFailure proc storePrim*[T](f: var RodFile; x: T) = if f.err != ok: return when supportsCopyMem(T): if writeBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): - f.err = ioFailure + setError f, ioFailure elif T is tuple: for y in fields(x): storePrim(f, y) @@ -65,11 +77,11 @@ proc storePrim*[T](f: var RodFile; x: T) = proc storeSeq*[T](f: var RodFile; s: seq[T]) = if f.err != ok: return if s.len >= high(int32): - f.err = tooBig + setError f, tooBig return var lenPrefix = int32(s.len) if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): - f.err = ioFailure + setError f, ioFailure else: for i in 0.. 0: if readBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len: - f.err = ioFailure + setError f, ioFailure proc loadPrim*[T](f: var RodFile; x: var T) = if f.err != ok: return when supportsCopyMem(T): if readBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): - f.err = ioFailure + setError f, ioFailure elif T is tuple: for y in fields(x): loadPrim(f, y) @@ -100,7 +112,7 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) = if f.err != ok: return var lenPrefix = int32(0) if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): - f.err = ioFailure + setError f, ioFailure else: s = newSeq[T](lenPrefix) for i in 0..= g.len: - g.setLen(m+1) - - case g[m].status - of undefined: - g[m].status = loading - let fullpath = msgs.toFullPath(conf, fileIdx) - let rod = toRodFile(conf, AbsoluteFile fullpath) - let err = loadRodFile(rod, g[m].fromDisk, conf) - if err == ok: - result = false - # check its dependencies: - for dep in g[m].fromDisk.imports: - let fid = toFileIndex(dep, g[m].fromDisk, conf) - # Warning: we need to traverse the full graph, so - # do **not use break here**! - if needsRecompile(g, conf, fid): - result = true - - g[m].status = if result: outdated else: loaded - else: - loadError(err, rod) - g[m].status = outdated - result = true - of loading, loaded: - result = false - of outdated: - result = true - # ------------------------------------------------------------------------- proc storeError(err: RodFileError; filename: AbsoluteFile) = @@ -465,7 +471,7 @@ proc storeError(err: RodFileError; filename: AbsoluteFile) = removeFile(filename.string) proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder) = - rememberConfig(encoder, encoder.config) + #rememberConfig(encoder, encoder.config) var f = rodfiles.create(filename.string) f.storeHeader() @@ -473,40 +479,50 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder) = f.storePrim encoder.m.definedSymbols f.storePrim encoder.m.cfg - f.storeSection stringsSection - f.store encoder.m.sh.strings + template storeSeqSection(section, data) {.dirty.} = + f.storeSection section + f.storeSeq data - f.storeSection checkSumsSection - f.storeSeq encoder.m.includes + template storeTabSection(section, data) {.dirty.} = + f.storeSection section + f.store data - f.storeSection depsSection - f.storeSeq encoder.m.imports + storeTabSection stringsSection, encoder.m.sh.strings - f.storeSection integersSection - f.store encoder.m.sh.integers + storeSeqSection checkSumsSection, encoder.m.includes - f.storeSection floatsSection - f.store encoder.m.sh.floats + storeSeqSection depsSection, encoder.m.imports - f.storeSection topLevelSection - f.storeSeq encoder.m.topLevel.nodes + storeTabSection integersSection, encoder.m.sh.integers + storeTabSection floatsSection, encoder.m.sh.floats - f.storeSection bodiesSection - f.storeSeq encoder.m.bodies.nodes + storeSeqSection exportsSection, encoder.m.exports - f.storeSection symsSection - f.storeSeq encoder.m.sh.syms + storeSeqSection reexportsSection, encoder.m.reexports - f.storeSection typesSection - f.storeSeq encoder.m.sh.types + storeSeqSection compilerProcsSection, encoder.m.compilerProcs + + storeSeqSection trmacrosSection, encoder.m.trmacros + storeSeqSection convertersSection, encoder.m.converters + storeSeqSection methodsSection, encoder.m.methods + storeSeqSection pureEnumsSection, encoder.m.pureEnums + storeSeqSection macroUsagesSection, encoder.m.macroUsages + + storeSeqSection topLevelSection, encoder.m.topLevel.nodes + + storeSeqSection bodiesSection, encoder.m.bodies.nodes + storeSeqSection symsSection, encoder.m.sh.syms + + storeSeqSection typesSection, encoder.m.sh.types close(f) if f.err != ok: - loadError(f.err, filename) + storeError(f.err, filename) - when true: + when false: # basic loader testing: var m2: PackedModule discard loadRodFile(filename, m2, encoder.config) + echo "loaded ", filename.string # ---------------------------------------------------------------------------- @@ -516,7 +532,25 @@ type lastLit*: LitId lastFile*: FileIndex # remember the last lookup entry. config*: ConfigRef - ident: IdentCache + cache: IdentCache + +type + ModuleStatus* = enum + undefined, + loading, + loaded, + outdated + + LoadedModule* = object + status*: ModuleStatus + symsInit, typesInit: bool + fromDisk: PackedModule + syms: seq[PSym] # indexed by itemId + types: seq[PType] + module*: PSym # the one true module symbol. + iface: Table[PIdent, seq[PackedItemId]] # PackedItemId so that it works with reexported symbols too + + PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; t: PackedItemId): PType proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedItemId): PSym @@ -546,7 +580,7 @@ proc loadNodes(c: var PackedDecoder; g: var PackedModuleGraph; of nkEmpty, nkNilLit, nkType: discard of nkIdent: - result.ident = getIdent(c.ident, g[c.thisModule].fromDisk.sh.strings[n.litId]) + result.ident = getIdent(c.cache, g[c.thisModule].fromDisk.sh.strings[n.litId]) of nkSym: result.sym = loadSym(c, g, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand)) of directIntLit: @@ -567,6 +601,31 @@ proc loadNodes(c: var PackedDecoder; g: var PackedModuleGraph; for n0 in sonsReadonly(tree, n): result.add loadNodes(c, g, tree, n0) +proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; + tree: PackedTree; n: NodePos): PNode = + # do not load the body of the proc. This will be done later in + # getProcBody, if required. + let k = n.kind + result = newNodeIT(k, translateLineInfo(c, g, n.info), + loadType(c, g, n.typ)) + result.flags = n.flags + assert k in {nkProcDef, nkMethodDef, nkIteratorDef, nkFuncDef, nkConverterDef} + var i = 0 + for n0 in sonsReadonly(tree, n): + if i != bodyPos: + result.add loadNodes(c, g, tree, n0) + else: + result.add nil + inc i + +proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; + tree: PackedTree; n: NodePos): PNode = + var i = 0 + for n0 in sonsReadonly(tree, n): + if i == bodyPos: + result = loadNodes(c, g, tree, n0) + inc i + proc moduleIndex*(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedItemId): int32 {.inline.} = result = if s.module == LitId(0): c.thisModule @@ -579,13 +638,17 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; info: translateLineInfo(c, g, s.info), options: s.options, position: s.position, - name: getIdent(c.ident, g[si].fromDisk.sh.strings[s.name]) + name: getIdent(c.cache, g[si].fromDisk.sh.strings[s.name]) ) template loadAstBody(p, field) = if p.field != emptyNodeId: result.field = loadNodes(c, g, g[si].fromDisk.bodies, NodePos p.field) +template loadAstBodyLazy(p, field) = + if p.field != emptyNodeId: + result.field = loadProcHeader(c, g, g[si].fromDisk.bodies, NodePos p.field) + proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph; si, item: int32; l: PackedLib): PLib = # XXX: hack; assume a zero LitId means the PackedLib is all zero (empty) @@ -600,7 +663,10 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedSym; si, item: int32; result: PSym) = result.typ = loadType(c, g, s.typ) loadAstBody(s, constraint) - loadAstBody(s, ast) + if result.kind in {skProc, skFunc, skIterator, skConverter, skMethod}: + loadAstBodyLazy(s, ast) + else: + loadAstBody(s, ast) result.annex = loadLib(c, g, si, item, s.annex) when hasFFI: result.cname = g[si].fromDisk.sh.strings[s.cname] @@ -615,7 +681,7 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; result.loc.r = rope externalName proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedItemId): PSym = - if s == nilTypeId: + if s == nilItemId: result = nil else: let si = moduleIndex(c, g, s) @@ -626,10 +692,16 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; s: PackedItemId): P if g[si].syms[s.item] == nil: let packed = addr(g[si].fromDisk.sh.syms[s.item]) - result = symHeaderFromPacked(c, g, packed[], si, s.item) - # store it here early on, so that recursions work properly: - g[si].syms[s.item] = result - symBodyFromPacked(c, g, packed[], si, s.item, result) + + if packed.kind != skModule: + result = symHeaderFromPacked(c, g, packed[], si, s.item) + # store it here early on, so that recursions work properly: + g[si].syms[s.item] = result + symBodyFromPacked(c, g, packed[], si, s.item, result) + else: + result = g[si].module + assert result != nil + else: result = g[si].syms[s.item] @@ -654,7 +726,7 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; result.methods.add((gen, loadSym(c, g, id))) proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; t: PackedItemId): PType = - if t == nilTypeId: + if t == nilItemId: result = nil else: let si = moduleIndex(c, g, t) @@ -672,15 +744,142 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; t: PackedItemId): else: result = g[si].types[t.item] +proc setupLookupTables(m: var LoadedModule; conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex) = + m.iface = initTable[PIdent, seq[PackedItemId]]() + for e in m.fromDisk.exports: + let nameLit = e[0] + m.iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(PackedItemId(module: LitId(0), item: e[1])) + for re in m.fromDisk.reexports: + let nameLit = re[0] + m.iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(re[1]) -when false: - proc initGenericKey*(s: PSym; types: seq[PType]): GenericKey = - result.module = s.owner.itemId.module - result.name = s.name.s - result.types = mapIt types: hashType(it, {CoType, CoDistinct}).MD5Digest + let filename = AbsoluteFile toFullPath(conf, fileIdx) + # We cannot call ``newSym`` here, because we have to circumvent the ID + # mechanism, which we do in order to assign each module a persistent ID. + m.module = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32), + name: getIdent(cache, splitFile(filename).name), + info: newLineInfo(fileIdx, 1, 1)) + +proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; + fileIdx: FileIndex): bool = + let m = int(fileIdx) + if m >= g.len: + g.setLen(m+1) + + case g[m].status + of undefined: + g[m].status = loading + let fullpath = msgs.toFullPath(conf, fileIdx) + let rod = toRodFile(conf, AbsoluteFile fullpath) + let err = loadRodFile(rod, g[m].fromDisk, conf) + if err == ok: + result = false + # check its dependencies: + for dep in g[m].fromDisk.imports: + let fid = toFileIndex(dep, g[m].fromDisk, conf) + # Warning: we need to traverse the full graph, so + # do **not use break here**! + if needsRecompile(g, conf, cache, fid): + result = true + + if not result: + setupLookupTables(g[m], conf, cache, fileIdx) + g[m].status = if result: outdated else: loaded + else: + loadError(err, rod) + g[m].status = outdated + result = true + of loading, loaded: + result = false + of outdated: + result = true + +proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; + fileIdx: FileIndex): PSym = + ## Returns 'nil' if the module needs to be recompiled. + if needsRecompile(g, conf, cache, fileIdx): + result = nil + else: + result = g[int fileIdx].module + assert result != nil + +template setupDecoder() {.dirty.} = + var decoder = PackedDecoder( + thisModule: int32(module), + lastLit: LitId(0), + lastFile: FileIndex(-1), + config: config, + cache: cache) + +proc loadProcBody*(config: ConfigRef, cache: IdentCache; + g: var PackedModuleGraph; s: PSym): PNode = + let mId = s.itemId.module + var decoder = PackedDecoder( + thisModule: mId, + lastLit: LitId(0), + lastFile: FileIndex(-1), + config: config, + cache: cache) + let pos = g[mId].fromDisk.sh.syms[s.itemId.item].ast + assert pos != emptyNodeId + result = loadProcBody(decoder, g, g[mId].fromDisk.bodies, NodePos pos) + +type + RodIter* = object + decoder: PackedDecoder + values: seq[PackedItemId] + i: int + +proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache; + g: var PackedModuleGraph; module: FileIndex; + name: PIdent): PSym = + it.decoder = PackedDecoder( + thisModule: int32(module), + lastLit: LitId(0), + lastFile: FileIndex(-1), + config: config, + cache: cache) + it.values = g[int module].iface.getOrDefault(name) + it.i = 0 + if it.i < it.values.len: + result = loadSym(it.decoder, g, it.values[it.i]) + inc it.i + +proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache; + g: var PackedModuleGraph; module: FileIndex): PSym = + it.decoder = PackedDecoder( + thisModule: int32(module), + lastLit: LitId(0), + lastFile: FileIndex(-1), + config: config, + cache: cache) + it.values = @[] + for v in g[int module].iface.values: + it.values.add v + it.i = 0 + if it.i < it.values.len: + result = loadSym(it.decoder, g, it.values[it.i]) + inc it.i + +proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym = + if it.i < it.values.len: + result = loadSym(it.decoder, g, it.values[it.i]) + inc it.i + +iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache; + g: var PackedModuleGraph; module: FileIndex; + name: PIdent): PSym = + setupDecoder() + let values = g[int module].iface.getOrDefault(name) + for pid in values: + let s = loadSym(decoder, g, pid) + assert s != nil + yield s + +proc interfaceSymbol*(config: ConfigRef, cache: IdentCache; + g: var PackedModuleGraph; module: FileIndex; + name: PIdent): PSym = + setupDecoder() + let values = g[int module].iface.getOrDefault(name) + result = loadSym(decoder, g, values[0]) - proc addGeneric*(m: var Module; c: var PackedEncoder; key: GenericKey; s: PSym) = - ## add a generic to the module - if key notin m.generics: - m.generics[key] = toPackedSym(s, m.ast, c) - toPackedNode(s.ast, m.ast, c) diff --git a/compiler/idents.nim b/compiler/idents.nim index 1e8c912d9..d2a84fd36 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -113,3 +113,8 @@ proc newIdentCache*(): IdentCache = proc whichKeyword*(id: PIdent): TSpecialWord = if id.id < 0: result = wInvalid else: result = TSpecialWord(id.id) + +proc hash*(x: PIdent): Hash {.inline.} = x.h +proc `==`*(a, b: PIdent): bool {.inline.} = + if a.isNil or b.isNil: result = system.`==`(a, b) + else: result = a.id == b.id diff --git a/compiler/importer.nim b/compiler/importer.nim index 645c03b2b..0fde13eb9 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -11,7 +11,8 @@ import intsets, ast, astalgo, msgs, options, idents, lookups, - semdata, modulepaths, sigmatch, lineinfos, sets + semdata, modulepaths, sigmatch, lineinfos, sets, + modulegraphs proc readExceptSet*(c: PContext, n: PNode): IntSet = assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} @@ -108,7 +109,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) = proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) = let ident = lookups.considerQuotedIdent(c, n) - let s = strTableGet(fromMod.tab, ident) + let s = someSym(c.graph, fromMod, ident) if s == nil: errorUndeclaredIdentifier(c, n.info, ident.s) else: @@ -118,16 +119,16 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) = # for an enumeration we have to add all identifiers if multiImport: # for a overloadable syms add all overloaded routines - var it: TIdentIter - var e = initIdentIter(it, fromMod.tab, s.name) + var it: ModuleIter + var e = initModuleIter(it, c.graph, fromMod, s.name) while e != nil: if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3") if s.kind in ExportableSymKinds: rawImportSymbol(c, e, fromMod, importSet) - e = nextIdentIter(it, fromMod.tab) + e = nextModuleIter(it, c.graph) else: rawImportSymbol(c, s, fromMod, importSet) - suggestSym(c.config, n.info, s, c.graph.usageSym, false) + suggestSym(c.graph, n.info, s, c.graph.usageSym, false) proc addImport(c: PContext; im: sink ImportedModule) = for i in 0..high(c.imports): @@ -176,18 +177,6 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet) addUnnamedIt(c, fromMod, it.id notin exceptSet) - when false: - var i: TTabIter - var s = initTabIter(i, fromMod.tab) - while s != nil: - if s.kind != skModule: - if s.kind != skEnumField: - if s.kind notin ExportableSymKinds: - internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s) - if exceptSet.isNil or s.name.id notin exceptSet: - rawImportSymbol(c, s, fromMod) - s = nextIter(i, fromMod.tab) - proc importAllSymbols*(c: PContext, fromMod: PSym) = c.addImport ImportedModule(m: fromMod, mode: importAll) addUnnamedIt(c, fromMod, true) @@ -256,7 +245,7 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s & " is deprecated") else: message(c.config, n.info, warnDeprecated, result.name.s & " is deprecated") - suggestSym(c.config, n.info, result, c.graph.usageSym, false) + suggestSym(c.graph, n.info, result, c.graph.usageSym, false) importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 4b369210d..f588f9555 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -887,7 +887,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = var v = copyNode(e[0]) inc(totalRange, int(e[1].intVal - v.intVal)) if totalRange > 65535: - localError(p.config, n.info, + localError(p.config, n.info, "Your case statement contains too many branches, consider using if/else instead!") while v.intVal <= e[1].intVal: gen(p, v, cond) @@ -1076,7 +1076,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = useMagic(p, "nimCopy") # supports proc getF(): var T if x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].kind in nkCallKinds: - lineF(p, "nimCopy($1, $2, $3);$n", + lineF(p, "nimCopy($1, $2, $3);$n", [a.res, b.res, genTypeInfo(p, y.typ)]) else: lineF(p, "$1 = nimCopy($1, $2, $3);$n", @@ -1426,7 +1426,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = if lfNoDecl in s.loc.flags or s.magic != mNone or {sfImportc, sfInfixCall} * s.flags != {}: discard - elif s.kind == skMethod and s.getBody.kind == nkEmpty: + elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty: # we cannot produce code for the dispatcher yet: discard elif sfForward in s.flags: diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 3c0aabe9a..cf6f07b7c 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,7 +11,8 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, nimfix/prettybase, lineinfos, strutils + renderer, nimfix/prettybase, lineinfos, strutils, + modulegraphs proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -107,8 +108,9 @@ proc localSearchInScope*(c: PContext, s: PIdent): PSym = scope = scope.parent result = strTableGet(scope.symbols, s) -proc initIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule; name: PIdent): PSym = - result = initIdentIter(ti, im.m.tab, name) +proc initIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule; name: PIdent; + g: ModuleGraph): PSym = + result = initModuleIter(ti, g, im.m, name) while result != nil: let b = case im.mode @@ -117,11 +119,12 @@ proc initIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule; n of importExcept: name.id notin im.exceptSet if b and not containsOrIncl(marked, result.id): return result - result = nextIdentIter(ti, im.m.tab) + result = nextModuleIter(ti, g) -proc nextIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule): PSym = +proc nextIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule; + g: ModuleGraph): PSym = while true: - result = nextIdentIter(ti, im.m.tab) + result = nextModuleIter(ti, g) if result == nil: return nil case im.mode of importAll: @@ -134,17 +137,17 @@ proc nextIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule): if result.name.id notin im.exceptSet and not containsOrIncl(marked, result.id): return result -iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent): PSym = - var ti: TIdentIter - var candidate = initIdentIter(ti, marked, im, name) +iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent; g: ModuleGraph): PSym = + var ti: ModuleIter + var candidate = initIdentIter(ti, marked, im, name, g) while candidate != nil: yield candidate - candidate = nextIdentIter(ti, marked, im) + candidate = nextIdentIter(ti, marked, im, g) iterator importedItems*(c: PContext; name: PIdent): PSym = var marked = initIntSet() for im in c.imports.mitems: - for s in symbols(im, marked, name): + for s in symbols(im, marked, name, c.graph): yield s proc allPureEnumFields(c: PContext; name: PIdent): seq[PSym] = @@ -169,15 +172,15 @@ iterator allSyms*(c: PContext): (PSym, int, bool) = dec scopeN isLocal = false for im in c.imports.mitems: - for s in im.m.tab.data: - if s != nil: - yield (s, scopeN, isLocal) + for s in modulegraphs.allSyms(c.graph, im.m): + assert s != nil + yield (s, scopeN, isLocal) proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym = var marked = initIntSet() result = nil for im in c.imports.mitems: - for s in symbols(im, marked, name): + for s in symbols(im, marked, name, c.graph): if result == nil: result = s else: @@ -214,7 +217,7 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy if result.len == 0: var marked = initIntSet() for im in c.imports.mitems: - for s in symbols(im, marked, s): + for s in symbols(im, marked, s, c.graph): if s.kind in filter: result.add s @@ -240,6 +243,7 @@ type oimSymChoiceLocalLookup TOverloadIter* = object it*: TIdentIter + mit*: ModuleIter m*: PSym mode*: TOverloadIterMode symChoiceIndex*: int @@ -306,7 +310,7 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) = proc addInterfaceDeclAux(c: PContext, sym: PSym) = if sfExported in sym.flags: # add to interface: - if c.module != nil: strTableAdd(c.module.tab, sym) + if c.module != nil: exportSym(c, sym) else: internalError(c.config, sym.info, "addInterfaceDeclAux") proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) = @@ -475,7 +479,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config) else: - result = strTableGet(m.tab, ident).skipAlias(n, c.config) + result = someSym(c.graph, m, ident).skipAlias(n, c.config) if result == nil and checkUndeclared in flags: fixSpelling(n[1], ident, searchInScopes) errorUndeclaredIdentifier(c, n[1].info, ident.s) @@ -509,7 +513,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = scope = scope.parent if scope == nil: for i in 0..c.imports.high: - result = initIdentIter(o.it, o.marked, c.imports[i], ident).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config) if result != nil: o.currentScope = nil o.importIdx = i @@ -535,7 +539,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = ident).skipAlias(n, c.config) o.mode = oimSelfModule else: - result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n, c.config) + result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config) else: noidentError(c.config, n[1], n) result = errorSym(c, n[1]) @@ -568,7 +572,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym var idx = o.importIdx+1 o.importIdx = c.imports.len # assume the other imported modules lack this symbol too while idx < c.imports.len: - result = initIdentIter(o.it, o.marked, c.imports[idx], o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config) if result != nil: # oh, we were wrong, some other module had the symbol, so remember that: o.importIdx = idx @@ -578,7 +582,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym = assert o.currentScope == nil while o.importIdx < c.imports.len: - result = initIdentIter(o.it, o.marked, c.imports[o.importIdx], o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config) #while result != nil and result.id in o.marked: # result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]) if result != nil: @@ -602,12 +606,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = else: o.importIdx = 0 if c.imports.len > 0: - result = initIdentIter(o.it, o.marked, c.imports[o.importIdx], o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config) if result == nil: result = nextOverloadIterImports(o, c, n) break elif o.importIdx < c.imports.len: - result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]).skipAlias(n, c.config) + result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config) if result == nil: result = nextOverloadIterImports(o, c, n) else: @@ -615,7 +619,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = of oimSelfModule: result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config) of oimOtherModule: - result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config) + result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config) of oimSymChoice: if o.symChoiceIndex < n.len: result = n[o.symChoiceIndex].sym @@ -654,7 +658,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = incl o.marked, result.id elif o.importIdx < c.imports.len: - result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]).skipAlias(n, c.config) + result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config) #assert result.id notin o.marked #while result != nil and result.id in o.marked: # result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index d700ab9a7..e79be6776 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -26,7 +26,7 @@ proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType = result.align = size.int16 proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = - result = strTableGet(g.systemModule.tab, getIdent(g.cache, name)) + result = systemModuleSym(g, getIdent(g.cache, name)) if result == nil: localError(g.config, info, "system module needs: " & name) result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) @@ -34,15 +34,12 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = if result.kind == skAlias: result = result.owner proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = - var ti: TIdentIter let id = getIdent(g.cache, name) - var r = initIdentIter(ti, g.systemModule.tab, id) - while r != nil: + for r in systemModuleSyms(g, id): if r.magic == m: # prefer the tyInt variant: if r.typ[0] != nil and r.typ[0].kind == tyInt: return r result = r - r = nextIdentIter(ti, g.systemModule.tab) if result != nil: return result localError(g.config, info, "system module needs: " & name) result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 5544668cc..ab3ef5ab8 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -10,25 +10,11 @@ ## This module implements the module graph data structure. The module graph ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -## -## The caching of modules is critical for 'nimsuggest' and is tricky to get -## right. If module E is being edited, we need autocompletion (and type -## checking) for E but we don't want to recompile depending -## modules right away for faster turnaround times. Instead we mark the module's -## dependencies as 'dirty'. Let D be a dependency of E. If D is dirty, we -## need to recompile it and all of its dependencies that are marked as 'dirty'. -## 'nimsuggest sug' actually is invoked for the file being edited so we know -## its content changed and there is no need to compute any checksums. -## Instead of a recursive algorithm, we use an iterative algorithm: -## -## - If a module gets recompiled, its dependencies need to be updated. -## - Its dependent module stays the same. -## -import ast, intsets, tables, options, lineinfos, hashes, idents, +import ast, astalgo, intsets, tables, options, lineinfos, hashes, idents, btrees, md5 -# import ic / packed_ast +import ic / to_packed_ast type SigHash* = distinct MD5Digest @@ -39,9 +25,12 @@ type converters*: seq[PSym] patterns*: seq[PSym] pureEnums*: seq[PSym] + interf: TStrTable ModuleGraph* = ref object ifaces*: seq[Iface] ## indexed by int32 fileIdx + packed: PackedModuleGraph + startupPackedConfig*: PackedConfig packageSyms*: TStrTable deps*: IntSet # the dependency graph or potentially its transitive closure. importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies @@ -64,6 +53,7 @@ type sysTypes*: array[TTypeKind, PType] compilerprocs*: TStrTable exposed*: TStrTable + packageTypes*: TStrTable intTypeCache*: array[-5..64, PType] opContains*, opNot*: PSym emptyNode*: PNode @@ -132,6 +122,62 @@ proc toBase64a(s: cstring, len: int): string = result.add cb64[a shr 2] result.add cb64[(a and 3) shl 4] +template semtab*(m: PSym; g: ModuleGraph): TStrTable = + g.ifaces[m.position].interf + +proc cachedModule(g: ModuleGraph; m: PSym): bool {.inline.} = + m.position < g.packed.len and g.packed[m.position].status == loaded + +type + ModuleIter* = object + fromRod: bool + modIndex: int + ti: TIdentIter + rodIt: RodIter + +proc initModuleIter*(mi: var ModuleIter; g: ModuleGraph; m: PSym; name: PIdent): PSym = + assert m.kind == skModule + mi.modIndex = m.position + mi.fromRod = mi.modIndex < g.packed.len and g.packed[mi.modIndex].status == loaded + if mi.fromRod: + result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name) + else: + result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interf, name) + +proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym = + if mi.fromRod: + result = nextRodIter(mi.rodIt, g.packed) + else: + result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interf) + +iterator allSyms*(g: ModuleGraph; m: PSym): PSym = + if cachedModule(g, m): + var rodIt: RodIter + var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position) + while r != nil: + yield r + r = nextRodIter(rodIt, g.packed) + else: + for s in g.ifaces[m.position].interf.data: + if s != nil: + yield s + +proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym = + if cachedModule(g, m): + result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name) + else: + result = strTableGet(g.ifaces[m.position].interf, name) + +proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym = + result = someSym(g, g.systemModule, name) + +iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym = + var mi: ModuleIter + var r = initModuleIter(mi, g, g.systemModule, name) + while r != nil: + yield r + r = nextModuleIter(mi, g) + proc `$`*(u: SigHash): string = toBase64a(cast[cstring](unsafeAddr u), sizeof(u)) @@ -186,6 +232,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) = if m.position >= g.ifaces.len: setLen(g.ifaces, m.position + 1) g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[]) + initStrTable(g.ifaces[m.position].interf) proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result = ModuleGraph() @@ -202,6 +249,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.methods = @[] initStrTable(result.compilerprocs) initStrTable(result.exposed) + initStrTable(result.packageTypes) result.opNot = createMagic(result, "not", mNot) result.opContains = createMagic(result, "contains", mInSet) result.emptyNode = newNode(nkEmpty) @@ -226,8 +274,11 @@ proc resetAllModules*(g: ModuleGraph) = initStrTable(g.exposed) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = - if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len: - result = g.ifaces[fileIdx.int32].module + if fileIdx.int32 >= 0: + if fileIdx.int32 < g.packed.len and g.packed[fileIdx.int32].status == loaded: + result = g.packed[fileIdx.int32].module + elif fileIdx.int32 < g.ifaces.len: + result = g.ifaces[fileIdx.int32].module proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b @@ -280,3 +331,18 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = proc isDirty*(g: ModuleGraph; m: PSym): bool = result = g.suggestMode and sfDirty in m.flags + +proc getBody*(g: ModuleGraph; s: PSym): PNode {.inline.} = + result = s.ast[bodyPos] + if result == nil and g.config.symbolFiles in {readOnlySf, v2Sf}: + result = loadProcBody(g.config, g.cache, g.packed, s) + s.ast[bodyPos] = result + assert result != nil + +proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex): PSym = + ## Returns 'nil' if the module needs to be recompiled. + if g.config.symbolFiles in {readOnlySf, v2Sf}: + result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx) + +proc configComplete*(g: ModuleGraph) = + rememberStartupConfig(g.startupPackedConfig, g.config) diff --git a/compiler/modules.nim b/compiler/modules.nim index a8a9c4df8..deb0174b5 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -31,43 +31,49 @@ proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym = pck = getPackageName(graph.config, filename.string) pck2 = if pck.len > 0: pck else: "unknown" pack = getIdent(graph.cache, pck2) - var packSym = graph.packageSyms.strTableGet(pack) - if packSym == nil: - packSym = newSym(skPackage, getIdent(graph.cache, pck2), packageId(), nil, info) - initStrTable(packSym.tab) - graph.packageSyms.strTableAdd(packSym) + result = graph.packageSyms.strTableGet(pack) + if result == nil: + result = newSym(skPackage, getIdent(graph.cache, pck2), packageId(), nil, info) + #initStrTable(packSym.tab) + graph.packageSyms.strTableAdd(result) else: - let existing = strTableGet(packSym.tab, name) - if existing != nil and existing.info.fileIndex != info.fileIndex: - when false: - # we used to produce an error: - localError(graph.config, info, - "module names need to be unique per Nimble package; module clashes with " & - toFullPath(graph.config, existing.info.fileIndex)) - else: - # but starting with version 0.20 we now produce a fake Nimble package instead - # to resolve the conflicts: - let pck3 = fakePackageName(graph.config, filename) - # this makes the new `packSym`'s owner be the original `packSym` - packSym = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), packSym, info) - initStrTable(packSym.tab) - graph.packageSyms.strTableAdd(packSym) - result = packSym + # we now produce a fake Nimble package instead + # to resolve the conflicts: + let pck3 = fakePackageName(graph.config, filename) + # this makes the new `packSym`'s owner be the original `packSym` + result = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), result, info) + #initStrTable(packSym.tab) + graph.packageSyms.strTableAdd(result) + + when false: + let existing = strTableGet(packSym.tab, name) + if existing != nil and existing.info.fileIndex != info.fileIndex: + when false: + # we used to produce an error: + localError(graph.config, info, + "module names need to be unique per Nimble package; module clashes with " & + toFullPath(graph.config, existing.info.fileIndex)) + else: + # but starting with version 0.20 we now produce a fake Nimble package instead + # to resolve the conflicts: + let pck3 = fakePackageName(graph.config, filename) + # this makes the new `packSym`'s owner be the original `packSym` + packSym = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), packSym, info) + #initStrTable(packSym.tab) + graph.packageSyms.strTableAdd(packSym) proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = let packSym = getPackage(graph, fileIdx) result.owner = packSym result.position = int fileIdx - graph.registerModule(result) - - initStrTable(result.tab) + #initStrTable(result.tab(graph)) when false: strTableAdd(result.tab, result) # a module knows itself # This is now implemented via # c.moduleScope.addSym(module) # a module knows itself # in sem.nim, around line 527 - strTableAdd(packSym.tab, result) + #strTableAdd(packSym.tab, result) proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = let filename = AbsoluteFile toFullPath(graph.config, fileIdx) @@ -79,6 +85,7 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = if not isNimIdentifier(result.name.s): rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s) partialInitModule(result, graph, fileIdx, filename) + graph.registerModule(result) proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym = var flags = flags @@ -92,21 +99,20 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput) discard processModule(graph, result, idGeneratorFromModule(result), s) if result == nil: + result = moduleFromRodFile(graph, fileIdx) let filename = AbsoluteFile toFullPath(graph.config, fileIdx) - when false: - # XXX entry point for module loading from the rod file - result = loadModuleSym(graph, fileIdx, filename) - when true: + if result == nil: result = newModule(graph, fileIdx) result.flags.incl flags registerModule(graph, result) + processModuleAux() else: partialInitModule(result, graph, fileIdx, filename) - processModuleAux() + # XXX replay the pragmas here! elif graph.isDirty(result): result.flags.excl sfDirty # reset module fields: - initStrTable(result.tab) + initStrTable(result.semtab(graph)) result.ast = nil processModuleAux() graph.markClientsDirty(fileIdx) @@ -152,6 +158,8 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = connectCallbacks(graph) let conf = graph.config wantMainModule(conf) + configComplete(graph) + let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim") let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx conf.projectMainIdx2 = projectFile diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index b93129852..0170c9949 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -24,11 +24,8 @@ type iterator exportedSymbols*(i: Interpreter): PSym = assert i != nil assert i.mainModule != nil, "no main module selected" - var it: TTabIter - var s = initTabIter(it, i.mainModule.tab) - while s != nil: + for s in modulegraphs.allSyms(i.graph, i.mainModule): yield s - s = nextIter(it, i.mainModule.tab) proc selectUniqueSymbol*(i: Interpreter; name: string; symKinds: set[TSymKind] = {skLet, skVar}): PSym = @@ -37,14 +34,14 @@ proc selectUniqueSymbol*(i: Interpreter; name: string; assert i != nil assert i.mainModule != nil, "no main module selected" let n = getIdent(i.graph.cache, name) - var it: TIdentIter - var s = initIdentIter(it, i.mainModule.tab, n) + var it: ModuleIter + var s = initModuleIter(it, i.graph, i.mainModule, n) result = nil while s != nil: if s.kind in symKinds: if result == nil: result = s else: return nil # ambiguous - s = nextIdentIter(it, i.mainModule.tab) + s = nextModuleIter(it, i.graph) proc selectRoutine*(i: Interpreter; name: string): PSym = ## Selects a declared routine (proc/func/etc) from the main module. @@ -70,7 +67,7 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) = ## This can also be used to *reload* the script. assert i != nil assert i.mainModule != nil, "no main module selected" - initStrTable(i.mainModule.tab) + initStrTable(i.mainModule.semtab(i.graph)) i.mainModule.ast = nil let s = if scriptStream != nil: scriptStream diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index a781f1d51..4af0c28fa 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -44,7 +44,8 @@ proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string = # in different directory get different name and they can be # placed in a directory. # foo-#head/../bar becomes @foo-@hhead@s..@sbar - result = "@m" & relativeTo(path, conf.projectPath).string.multiReplace({$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"}) + result = "@m" & relativeTo(path, conf.projectPath).string.multiReplace( + {$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"}) proc demanglePackageName*(path: string): string = result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"}) diff --git a/compiler/passes.nim b/compiler/passes.nim index 997a10cd8..e3885540e 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -110,6 +110,12 @@ proc prepareConfigNotes(graph: ModuleGraph; module: PSym) = proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} = result = module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange") +proc partOfStdlib(x: PSym): bool = + var it = x.owner + while it != nil and it.kind == skPackage and it.owner != nil: + it = it.owner + result = it != nil and it.name.s == "stdlib" + proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; stream: PLLStream): bool {.discardable.} = if graph.stopCompile(): return true @@ -131,7 +137,7 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; while true: openParser(p, fileIdx, s, graph.cache, graph.config) - if module.owner == nil or module.owner.name.s != "stdlib" or module.name.s == "distros": + if not partOfStdlib(module) or module.name.s == "distros": # XXX what about caching? no processing then? what if I change the # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index 78c79bf59..24e26b2b7 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -9,7 +9,7 @@ ## Plugin to transform an inline iterator into a data structure. -import ".." / [ast, lookups, semdata, lambdalifting, msgs] +import ".." / [ast, modulegraphs, lookups, semdata, lambdalifting, msgs] proc iterToProcImpl*(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) @@ -29,7 +29,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode = localError(c.config, n[2].info, "type must be a non-generic ref|ptr to object with state field") return - let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t, c.idgen) + let body = liftIterToProc(c.graph, iter.sym, getBody(c.graph, iter.sym), t, c.idgen) let prc = newSym(skProc, n[3].ident, nextSymId c.idgen, iter.sym.owner, iter.sym.info) prc.typ = copyType(iter.sym.typ, nextTypeId c.idgen, prc) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index a79a471de..c1627fe0c 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -14,6 +14,8 @@ import wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, types, lookups, lineinfos, pathutils, linter +from ic / to_packed_ast import addCompilerProc + const FirstCallConv* = wNimcall LastCallConv* = wNoconv @@ -702,6 +704,8 @@ proc markCompilerProc(c: PContext; s: PSym) = incl(s.flags, sfCompilerProc) incl(s.flags, sfUsed) registerCompilerProc(c.graph, s) + if c.config.symbolFiles != disabledSf: + addCompilerProc(c.encoder, s) proc deprecatedStmt(c: PContext; outerPragma: PNode) = let pragma = outerPragma[1] diff --git a/compiler/sem.nim b/compiler/sem.nim index d5ae5a21d..6f3b15867 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -19,7 +19,8 @@ import lowerings, plugins/active, lineinfos, strtabs, int128, isolation_check, typeallowed -from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward +from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward, + systemModuleSym, semtab, getBody, someSym, allSyms when defined(nimfix): import nimfix/prettybase diff --git a/compiler/semdata.nim b/compiler/semdata.nim index da38a6fc2..f2f074447 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -268,7 +268,7 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext = result.typesWithOps = @[] result.features = graph.config.features if graph.config.symbolFiles != disabledSf: - initEncoder result.encoder, module, graph.config + initEncoder result.encoder, module, graph.config, graph.startupPackedConfig proc addIncludeFileDep*(c: PContext; f: FileIndex) = if c.config.symbolFiles != disabledSf: @@ -286,15 +286,29 @@ proc inclSym(sq: var seq[PSym], s: PSym) = proc addConverter*(c: PContext, conv: PSym) = inclSym(c.converters, conv) inclSym(c.graph.ifaces[c.module.position].converters, conv) - #addConverter(c.graph, c.module, conv) # upcoming + if c.config.symbolFiles != disabledSf: + addConverter(c.encoder, conv) proc addPureEnum*(c: PContext, e: PSym) = inclSym(c.graph.ifaces[c.module.position].pureEnums, e) + if c.config.symbolFiles != disabledSf: + addPureEnum(c.encoder, e) proc addPattern*(c: PContext, p: PSym) = inclSym(c.patterns, p) inclSym(c.graph.ifaces[c.module.position].patterns, p) - #addPattern(c.graph, c.module, p) # upcoming + if c.config.symbolFiles != disabledSf: + addTrmacro(c.encoder, p) + +proc exportSym*(c: PContext; s: PSym) = + strTableAdd(c.module.semtab(c.graph), s) + if c.config.symbolFiles != disabledSf: + addExported(c.encoder, s) + +proc reexportSym*(c: PContext; s: PSym) = + strTableAdd(c.module.semtab(c.graph), s) + if c.config.symbolFiles != disabledSf: + addReexport(c.encoder, s) proc newLib*(kind: TLibKind): PLib = new(result) @@ -489,4 +503,4 @@ proc storeRodNode*(c: PContext, n: PNode) = proc saveRodFile*(c: PContext) = if c.config.symbolFiles != disabledSf: - saveRodFile(toRodFile(c.config, c.filename.AbsoluteFile), c.encoder) + saveRodFile(toRodFile(c.config, AbsoluteFile toFullPath(c.config, FileIndex c.module.position)), c.encoder) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 1e5772189..4a04cfb6d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1014,7 +1014,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc buildEchoStmt(c: PContext, n: PNode): PNode = # we MUST not check 'n' for semantics again here! But for now we give up: result = newNodeI(nkCall, n.info) - var e = strTableGet(c.graph.systemModule.tab, getIdent(c.cache, "echo")) + let e = systemModuleSym(c.graph, getIdent(c.cache, "echo")) if e != nil: result.add(newSymNode(e)) else: @@ -1897,7 +1897,7 @@ proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident) else: - result = strTableGet(m.tab, ident) + result = someSym(c.graph, m, ident) of nkSym: result = n.sym of nkOpenSymChoice, nkClosedSymChoice: @@ -2504,7 +2504,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode = elif labl.owner == nil: labl.owner = c.p.owner n[0] = newSymNode(labl, n[0].info) - suggestSym(c.config, n[0].info, labl, c.graph.usageSym) + suggestSym(c.graph, n[0].info, labl, c.graph.usageSym) styleCheckDef(c.config, labl) onDef(n[0].info, labl) n[1] = semExpr(c, n[1], flags) @@ -2522,15 +2522,12 @@ proc semExportExcept(c: PContext, n: PNode): PNode = let exceptSet = readExceptSet(c, n) let exported = moduleName.sym result = newNodeI(nkExportStmt, n.info) - strTableAdd(c.module.tab, exported) - var i: TTabIter - var s = initTabIter(i, exported.tab) - while s != nil: + reexportSym(c, exported) + for s in allSyms(c.graph, exported): if s.kind in ExportableSymKinds+{skModule} and s.name.id notin exceptSet and sfError notin s.flags: - strTableAdd(c.module.tab, s) + reexportSym(c, s) result.add newSymNode(s, n.info) - s = nextIter(i, exported.tab) markUsed(c, n.info, exported) proc semExport(c: PContext, n: PNode): PNode = @@ -2548,15 +2545,12 @@ proc semExport(c: PContext, n: PNode): PNode = localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a)) elif s.kind == skModule: # forward everything from that module: - strTableAdd(c.module.tab, s) - var ti: TTabIter - var it = initTabIter(ti, s.tab) - while it != nil: + reexportSym(c, s) + for it in allSyms(c.graph, s): if it.kind in ExportableSymKinds+{skModule}: - strTableAdd(c.module.tab, it) + reexportSym(c, it) result.add newSymNode(it, a.info) specialSyms(c, it) - it = nextIter(ti, s.tab) markUsed(c, n.info, s) else: while s != nil: @@ -2565,7 +2559,7 @@ proc semExport(c: PContext, n: PNode): PNode = "; enum field cannot be exported individually") if s.kind in ExportableSymKinds+{skModule} and sfError notin s.flags: result.add(newSymNode(s, a.info)) - strTableAdd(c.module.tab, s) + reexportSym(c, s) markUsed(c, n.info, s) specialSyms(c, s) if s.kind == skType and sfPure notin s.flags: @@ -2575,7 +2569,7 @@ proc semExport(c: PContext, n: PNode): PNode = var e = etyp.n[j].sym if e.kind != skEnumField: internalError(c.config, s.info, "rawImportSymbol") - strTableAdd(c.module.tab, e) + reexportSym(c, e) s = nextOverloadIter(o, c, a) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 7e8fffc01..93184c568 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -106,7 +106,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = # so that 'break' etc. work as expected, we produce # a 'while true: stmt; break' loop ... result = newNodeI(nkWhileStmt, n.info, 2) - var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent(c.cache, "true")) + var trueSymbol = systemModuleSym(c.graph, getIdent(c.cache, "true")) if trueSymbol == nil: localError(c.config, n.info, "system needs: 'true'") trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), nextSymId c.idgen, getCurrOwner(c), n.info) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 1f633549a..dfbb022c8 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -481,7 +481,7 @@ proc semGenericStmt(c: PContext, n: PNode, if sfGenSym in s.flags and s.ast == nil: body = n[bodyPos] else: - body = s.getBody + body = getBody(c.graph, s) else: body = n[bodyPos] n[bodyPos] = semGenericStmtScope(c, body, flags, ctx) closeScope(c) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 3f1cdace3..d273cac14 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -160,7 +160,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) = pushInfoContext(c.config, oldPrc.info) openScope(c) var n = oldPrc.ast - n[bodyPos] = copyTree(s.getBody) + n[bodyPos] = copyTree(getBody(c.graph, s)) instantiateBody(c, n, oldPrc.typ.n, oldPrc, s) closeScope(c) popInfoContext(c.config) @@ -383,7 +383,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, if n[pragmasPos].kind != nkEmpty: pragma(c, result, n[pragmasPos], allRoutinePragmas) if isNil(n[bodyPos]): - n[bodyPos] = copyTree(fn.getBody) + n[bodyPos] = copyTree(getBody(c.graph, fn)) if c.inGenericContext == 0: instantiateBody(c, n, fn.typ.n, result, fn) sideEffectsCheck(c, result) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c2c59bb31..a76116b1c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -66,7 +66,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = x.info = n.info incl(s.flags, sfUsed) n[0] = x - suggestSym(c.config, x.info, s, c.graph.usageSym) + suggestSym(c.graph, x.info, s, c.graph.usageSym) onUse(x.info, s) else: localError(c.config, n.info, errInvalidControlFlowX % s.name.s) @@ -332,7 +332,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = discard result = n.info let info = getLineInfo(n) - suggestSym(c.config, info, result, c.graph.usageSym) + suggestSym(c.graph, info, result, c.graph.usageSym) proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and v.typ.requiresInit: @@ -1055,14 +1055,14 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = if pkg.isNil or pkg.kind != skPackage: localError(c.config, name.info, "unknown package name: " & pkgName.s) else: - let typsym = pkg.tab.strTableGet(typName) + let typsym = c.graph.packageTypes.strTableGet(typName) if typsym.isNil: s = semIdentDef(c, name[1], skType) onDef(name[1].info, s) s.typ = newTypeS(tyObject, c) s.typ.sym = s s.flags.incl sfForward - pkg.tab.strTableAdd s + c.graph.packageTypes.strTableAdd s addInterfaceDecl(c, s) elif typsym.kind == skType and sfForward in typsym.flags: s = typsym @@ -1088,7 +1088,7 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = if not isTopLevel(c) or pkg.isNil: localError(c.config, name.info, "only top level types in a package can be 'package'") else: - let typsym = pkg.tab.strTableGet(s.name) + let typsym = c.graph.packageTypes.strTableGet(s.name) if typsym != nil: if sfForward notin typsym.flags or sfNoForward notin typsym.flags: typeCompleted(typsym) @@ -1956,7 +1956,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not comesFromShadowScope: excl(proto.flags, sfForward) incl(proto.flags, sfWasForwarded) - suggestSym(c.config, s.info, proto, c.graph.usageSym) + suggestSym(c.graph, s.info, proto, c.graph.usageSym) closeScope(c) # close scope with wrong parameter symbols openScope(c) # open scope for old (correct) parameter symbols if proto.ast[genericParamsPos].kind != nkEmpty: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 14c3b9a11..65dc95916 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -250,7 +250,7 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode = else: result = newSymNode(s, n.info) # Issue #12832 when defined(nimsuggest): - suggestSym(c.config, n.info, s, c.graph.usageSym, false) + suggestSym(c.graph, n.info, s, c.graph.usageSym, false) if {optStyleHint, optStyleError} * c.config.globalOptions != {}: styleCheckUse(c.config, n.info, s) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 99c588657..64113a4c6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -140,7 +140,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if result.sym != nil and sfExported in result.sym.flags: incl(e.flags, sfUsed) incl(e.flags, sfExported) - if not isPure: strTableAdd(c.module.tab, e) + if not isPure: exportSym(c, e) result.n.add symNode styleCheckDef(c.config, e) onDef(e.info, e) @@ -779,7 +779,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, n[i][1].info else: n[i].info - suggestSym(c.config, info, f, c.graph.usageSym) + suggestSym(c.graph, info, f, c.graph.usageSym) f.typ = typ f.position = pos f.options = c.config.options diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 9a16cc3e0..156bc66d7 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -371,7 +371,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash = if sym.ast != nil: md5Init(c) c.md5Update(cast[cstring](result.addr), sizeof(result)) - hashBodyTree(graph, c, sym.ast[bodyPos]) + hashBodyTree(graph, c, getBody(graph, sym)) c.md5Final(result.MD5Digest) graph.symBodyHashes[sym.id] = result diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 73929f813..560d20b3f 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -56,10 +56,10 @@ proc findDocComment(n: PNode): PNode = elif n.kind in {nkAsgn, nkFastAsgn} and n.len == 2: result = findDocComment(n[1]) -proc extractDocComment(s: PSym): string = +proc extractDocComment(g: ModuleGraph; s: PSym): string = var n = findDocComment(s.ast) if n.isNil and s.kind in routineKinds and s.ast != nil: - n = findDocComment(s.ast[bodyPos]) + n = findDocComment(getBody(g, s)) if not n.isNil: result = n.comment.replace("\n##", "\n").strip else: @@ -117,7 +117,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int elif sourceIdent != ident: result = 0 -proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; +proc symToSuggest(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; inTypeContext: bool; scope: int; useSuppliedInfo = false): Suggest = @@ -136,7 +136,7 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info if u.fileIndex == info.fileIndex: inc c result.localUsages = c result.symkind = byte s.kind - if optIdeTerse notin conf.globalOptions: + if optIdeTerse notin g.config.globalOptions: result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner @@ -156,20 +156,20 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info else: result.forth = "" when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): - result.doc = s.extractDocComment + result.doc = extractDocComment(g, s) let infox = if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}: info else: s.info - result.filePath = toFullPath(conf, infox) + result.filePath = toFullPath(g.config, infox) result.line = toLinenumber(infox) result.column = toColumn(infox) - result.version = conf.suggestVersion + result.version = g.config.suggestVersion result.tokenLen = if section != ideHighlight: s.name.s.len else: - getTokenLenFromSource(conf, s.name.s, infox) + getTokenLenFromSource(g.config, s.name.s, infox) proc `$`*(suggest: Suggest): string = result = $suggest.section @@ -261,7 +261,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = var pm: PrefixMatch if filterSym(s, f, pm) and fieldVisible(c, s): - outputs.add(symToSuggest(c.config, s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) + outputs.add(symToSuggest(c.graph, s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) proc getQuality(s: PSym): range[0..100] = if s.typ != nil and s.typ.len > 1: @@ -275,7 +275,7 @@ template wholeSymTab(cond, section: untyped) {.dirty.} = let it = item var pm: PrefixMatch if cond: - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it), + outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, section, info, getQuality(it), pm, c.inTypeContext > 0, scopeN)) proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) = @@ -346,7 +346,7 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = for (it, scopeN, isLocal) in allSyms(c): var pm: PrefixMatch if filterSym(it, f, pm): - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, n.info, 0, pm, + outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, n.info, 0, pm, c.inTypeContext > 0, scopeN)) proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) = @@ -365,10 +365,10 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) let m = c.graph.importModuleCallback(c.graph, c.module, fileInfoIdx(c.config, fullPath)) if m == nil: typ = nil else: - for it in items(n.sym.tab): + for it in allSyms(c.graph, n.sym): if filterSym(it, field, pm): - outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) - outputs.add(symToSuggest(c.config, m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, + outputs.add(symToSuggest(c.graph, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) + outputs.add(symToSuggest(c.graph, m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, c.inTypeContext > 0, -99)) if typ == nil: @@ -378,11 +378,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it, field, pm): - outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.graph, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: - for it in items(n.sym.tab): + for it in allSyms(c.graph, n.sym): if filterSym(it, field, pm): - outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.graph, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: # fallback: suggestEverything(c, n, field, outputs) @@ -440,27 +440,27 @@ when defined(nimsuggest): if infoB.infoToInt == infoAsInt: return s.allUsages.add(info) -proc findUsages(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = - if conf.suggestVersion == 1: - if usageSym == nil and isTracked(info, conf.m.trackPos, s.name.s.len): +proc findUsages(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) = + if g.config.suggestVersion == 1: + if usageSym == nil and isTracked(info, g.config.m.trackPos, s.name.s.len): usageSym = s - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) + suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) elif s == usageSym: - if conf.lastLineInfo != info: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) - conf.lastLineInfo = info + if g.config.lastLineInfo != info: + suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) + g.config.lastLineInfo = info when defined(nimsuggest): - proc listUsages*(conf: ConfigRef; s: PSym) = + proc listUsages*(g: ModuleGraph; s: PSym) = #echo "usages ", s.allUsages.len for info in s.allUsages: let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse - suggestResult(conf, symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) + suggestResult(g.config, symToSuggest(g, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) -proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = +proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) = if s.isNil: return - if isTracked(info, conf.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags): - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym)) + if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags): + suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym)) if sfForward notin s.flags: suggestQuit() else: @@ -472,8 +472,9 @@ proc ensureIdx[T](x: var T, y: int) = proc ensureSeq[T](x: var seq[T]) = if x == nil: newSeq(x, 0) -proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = +proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' + let conf = g.config when defined(nimsuggest): if conf.suggestVersion == 0: if s.allUsages.len == 0: @@ -482,15 +483,15 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; s.addNoDup(info) if conf.ideCmd == ideUse: - findUsages(conf, info, s, usageSym) + findUsages(g, info, s, usageSym) elif conf.ideCmd == ideDef: - findDefinition(conf, info, s, usageSym) + findDefinition(g, info, s, usageSym) elif conf.ideCmd == ideDus and s != nil: if isTracked(info, conf.m.trackPos, s.name.s.len): - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) - findUsages(conf, info, s, usageSym) + suggestResult(conf, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) + findUsages(g, info, s, usageSym) elif conf.ideCmd == ideHighlight and info.fileIndex == conf.m.trackPos.fileIndex: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) + suggestResult(conf, symToSuggest(g, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) elif conf.ideCmd == ideOutline and isDecl: # if a module is included then the info we have is inside the include and # we need to walk up the owners until we find the outer most module, @@ -503,7 +504,7 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; parentModule = parentModule.owner if parentFileIndex == conf.m.trackPos.fileIndex: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) + suggestResult(conf, symToSuggest(g, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) proc extractPragma(s: PSym): PNode = if s.kind in routineKinds: @@ -572,7 +573,7 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) = if sfError in s.flags: userError(conf, info, s) when defined(nimsuggest): - suggestSym(conf, info, s, c.graph.usageSym, false) + suggestSym(c.graph, info, s, c.graph.usageSym, false) if {optStyleHint, optStyleError} * conf.globalOptions != {}: styleCheckUse(conf, info, s) markOwnerModuleAsUsed(c, s) @@ -658,7 +659,7 @@ proc suggestSentinel*(c: PContext) = for (it, scopeN, isLocal) in allSyms(c): var pm: PrefixMatch if filterSymNoOpr(it, nil, pm): - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, + outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), 0, PrefixMatch.None, false, scopeN)) diff --git a/compiler/transf.nim b/compiler/transf.nim index 461db9e89..e9ab6b47d 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -126,7 +126,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = var tc = c.transCon if sfBorrow in s.flags and s.kind in routineKinds: # simply exchange the symbol: - b = s.getBody + b = getBody(c.graph, s) if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym, n.info) elif c.inlining > 0: @@ -594,7 +594,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = else: for i in 0.. Date: Thu, 7 Jan 2021 20:57:11 +0100 Subject: [PATCH 1793/4254] Improve documentation for the md5 module (#16631) --- lib/pure/md5.nim | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index ba944ba81..11c324548 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -7,11 +7,14 @@ # distribution, for details about the copyright. # -## Module for computing `MD5 checksums `_. +## Module for computing [MD5 checksums](https://en.wikipedia.org/wiki/MD5). ## -## **See also:** -## * `base64 module`_ implements a base64 encoder and decoder -## * `std/sha1 module `_ for a sha1 encoder and decoder +## **Note:** The procs in this module can be used at compile time. +## +## See also +## ======== +## * `base64 module`_ implements a Base64 encoder and decoder +## * `std/sha1 module `_ for a SHA-1 encoder and decoder ## * `hashes module`_ for efficient computations of hash values ## for diverse Nim types @@ -22,8 +25,8 @@ type MD5State = array[0..3, uint32] MD5Block = array[0..15, uint32] MD5CBits = array[0..7, uint8] - MD5Digest* = array[0..15, uint8] ## \ - ## MD5 checksum of a string, obtained with `toMD5 proc <#toMD5,string>`_. + MD5Digest* = array[0..15, uint8] + ## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_. MD5Buffer = array[0..63, uint8] MD5Context* {.final.} = object state: MD5State @@ -180,7 +183,7 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], proc toMD5*(s: string): MD5Digest = ## Computes the `MD5Digest` value for a string `s`. ## - ## See also: + ## **See also:** ## * `getMD5 proc <#getMD5,string>`_ which returns a string representation ## of the `MD5Digest` ## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string @@ -202,10 +205,8 @@ proc `$`*(d: MD5Digest): string = proc getMD5*(s: string): string = ## Computes an MD5 value of `s` and returns its string representation. - ## .. note:: - ## available at compile time ## - ## See also: + ## **See also:** ## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string runnableExamples: assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72" @@ -226,9 +227,9 @@ proc `==`*(D1, D2: MD5Digest): bool = proc md5Init*(c: var MD5Context) = - ## Initializes a `MD5Context`. + ## Initializes an `MD5Context`. ## - ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this ## function explicitly. c.state[0] = 0x67452301'u32 c.state[1] = 0xEFCDAB89'u32 @@ -241,7 +242,7 @@ proc md5Init*(c: var MD5Context) = proc md5Update*(c: var MD5Context, input: cstring, len: int) = ## Updates the `MD5Context` with the `input` data of length `len`. ## - ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this ## function explicitly. var input = input var Index = int((c.count[0] shr 3) and 0x3F) @@ -263,7 +264,7 @@ proc md5Update*(c: var MD5Context, input: cstring, len: int) = proc md5Final*(c: var MD5Context, digest: var MD5Digest) = ## Finishes the `MD5Context` and stores the result in `digest`. ## - ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this ## function explicitly. var Bits: MD5CBits From 596da7f9a0d6303738d368e119e49461591bfe71 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 8 Jan 2021 11:29:32 +0300 Subject: [PATCH 1794/4254] happy new year 2021 again (#16638) --- compiler/options.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/options.nim b/compiler/options.nim index 4a013f8fc..6cdb5db63 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -19,7 +19,7 @@ const useEffectSystem* = true useWriteTracking* = false hasFFI* = defined(nimHasLibFFI) - copyrightYear* = "2020" + copyrightYear* = "2021" type # please make sure we have under 32 options # (improves code efficiency a lot!) From add1ccb6cb4ad4b444a5cfa3ef5573b0c1d47d09 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 8 Jan 2021 13:36:03 +0100 Subject: [PATCH 1795/4254] compiler: minor refactoring (#16633) --- compiler/main.nim | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 4c67aaea7..438f90ba6 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -211,18 +211,17 @@ proc mainCommand*(graph: ModuleGraph) = defineSymbol(conf.symbols, "nimdoc") body - block: ## command prepass - if conf.cmd == cmdCrun: conf.globalOptions.incl {optRun, optUseNimcache} - if conf.cmd notin cmdBackends + {cmdTcc}: customizeForBackend(backendC) - if conf.outDir.isEmpty: - # doc like commands can generate a lot of files (especially with --project) - # so by default should not end up in $PWD nor in $projectPath. - conf.outDir = block: - var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) - else: conf.projectPath - doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee - if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex}: ret = ret / htmldocsDir - ret + ## command prepass + if conf.cmd == cmdCrun: conf.globalOptions.incl {optRun, optUseNimcache} + if conf.cmd notin cmdBackends + {cmdTcc}: customizeForBackend(backendC) + if conf.outDir.isEmpty: + # doc like commands can generate a lot of files (especially with --project) + # so by default should not end up in $PWD nor in $projectPath. + var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) + else: conf.projectPath + doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee + if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex}: ret = ret / htmldocsDir + conf.outDir = ret ## process all commands case conf.cmd From 38b8d080f29021d2685e09d552c2a7753ef25484 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 8 Jan 2021 07:42:38 -0600 Subject: [PATCH 1796/4254] close #1550 add testcase (#16640) --- tests/iter/t1550.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/iter/t1550.nim diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim new file mode 100644 index 000000000..8ad96f0da --- /dev/null +++ b/tests/iter/t1550.nim @@ -0,0 +1,20 @@ +type + A[T] = iterator(x: T): T {.gcsafe, closure.} + +iterator aimp[T](x: T): T {.gcsafe, closure.} = + var total = 0 + while (total < 100): + yield total + total += x + +iterator bimp(y: A[int], z:int): int {.gcsafe, closure.} = + for i in y(z): + yield i + +for x in aimp[int](3): + discard x + +var y = aimp[int] +var z = bimp +for x in z(y, 1): + discard x \ No newline at end of file From bfcb7c1621ba4cadb228125e924f1fe6bf91e20c Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 8 Jan 2021 11:48:23 -0700 Subject: [PATCH 1797/4254] DELETE requests should always have a content-length header (#16618) * DELETE requests should always have a content-length header Not having DELETE in this list is causing hanging when trying to close webdriver sessions in [halonium](https://github.com/halonium/halonium/issues/10) and likely any other implementation of the webdriver protocol. Both at least chromedriver and geckodriver are affected by this issue. * Change the content length calculation to match the http spec For reference: https://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#Entity-Body --- lib/pure/httpclient.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 3093f5564..70f3327b1 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -980,8 +980,11 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, var data: seq[string] if multipart != nil and multipart.content.len > 0: data = await client.format(multipart) - elif httpMethod in ["POST", "PATCH", "PUT"] or body.len != 0: - client.headers["Content-Length"] = $body.len + else: + if body.len != 0: + client.headers["Content-Length"] = $body.len + elif httpMethod notin ["GET", "HEAD"] and not client.headers.hasKey("Content-Length"): + client.headers["Content-Length"] = "0" when client is AsyncHttpClient: if not client.parseBodyFut.isNil: From 2a426ca8e2d64e4e415c20e97a6fbc8563ab1b2f Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 8 Jan 2021 14:04:17 -0600 Subject: [PATCH 1798/4254] kochdocs: fusion needs the js backend too (#16644) --- tools/kochdocs.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 81117dd52..75bb4443f 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -15,7 +15,9 @@ const var nimExe*: string -template isJsOnly(file: string): bool = file.isRelativeTo("lib/js") +template isJsOnly(file: string): bool = + file.isRelativeTo("lib/js") or + file.isRelativeTo("lib/fusion/js") proc exe*(f: string): string = result = addFileExt(f, ExeExt) From ffb130b59c3f3d03e694b76af37563b070e28af0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 8 Jan 2021 14:09:58 -0800 Subject: [PATCH 1799/4254] skip docs for `lib/fusion` (docs already run in fusion repo) (#16645) * run CI docs on koch.nim changes to avoid future regressions * kochdocs: skip lib/fusion --- .github/workflows/ci_docs.yml | 2 +- tools/kochdocs.nim | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 74ca804f3..fcc89dfc1 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -26,7 +26,7 @@ on: - 'tools/dochack/dochack.nim' - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' - + - 'koch.nim' jobs: build: diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 75bb4443f..f258087e7 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -15,9 +15,7 @@ const var nimExe*: string -template isJsOnly(file: string): bool = - file.isRelativeTo("lib/js") or - file.isRelativeTo("lib/fusion/js") +template isJsOnly(file: string): bool = file.isRelativeTo("lib/js") proc exe*(f: string): string = result = addFileExt(f, ExeExt) @@ -187,7 +185,8 @@ lib/system/widestrs.nim """.splitWhitespace() proc follow(a: PathEntry): bool = - a.path.lastPathPart notin ["nimcache", "htmldocs", "includes", "deprecated", "genode"] + result = a.path.lastPathPart notin ["nimcache", "htmldocs", "includes", "deprecated", "genode"] and + not a.path.isRelativeTo("lib/fusion") for entry in walkDirRecFilter("lib", follow = follow): let a = entry.path if entry.kind != pcFile or a.splitFile.ext != ".nim" or From b7ff0b2a1128dc976379102e180ae883641d6c82 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sat, 9 Jan 2021 00:24:41 +0100 Subject: [PATCH 1800/4254] Use func in lenientops (#16641) --- lib/pure/lenientops.nim | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/pure/lenientops.nim b/lib/pure/lenientops.nim index f73df5e5f..a8fc78e39 100644 --- a/lib/pure/lenientops.nim +++ b/lib/pure/lenientops.nim @@ -8,49 +8,49 @@ # ## This module offers implementations of common binary operations -## like ``+``, ``-``, ``*``, ``/`` and comparison operations, +## like `+`, `-`, `*`, `/` and comparison operations, ## which work for mixed float/int operands. ## All operations convert the integer operand into the ## type of the float operand. For numerical expressions, the return ## type is always the type of the float involved in the expression, ## i.e., there is no auto conversion from float32 to float64. ## -## Note: In general, auto-converting from int to float loses +## **Note:** In general, auto-converting from int to float loses ## information, which is why these operators live in a separate ## module. Use with care. ## ## Regarding binary comparison, this module only provides unequal operators. -## The equality operator ``==`` is omitted, because depending on the use case +## The equality operator `==` is omitted, because depending on the use case ## either casting to float or rounding to int might be preferred, and users ## should make an explicit choice. -proc `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) + f -proc `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f + F(i) -proc `-`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `-`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) - f -proc `-`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `-`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f - F(i) -proc `*`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `*`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) * f -proc `*`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `*`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f * F(i) -proc `/`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `/`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) / f -proc `/`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `/`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f / F(i) -proc `<`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.noSideEffect, inline.} = +func `<`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.inline.} = F(i) < f -proc `<`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.noSideEffect, inline.} = +func `<`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.inline.} = f < F(i) -proc `<=`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.noSideEffect, inline.} = +func `<=`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.inline.} = F(i) <= f -proc `<=`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.noSideEffect, inline.} = +func `<=`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.inline.} = f <= F(i) # Note that we must not defined `>=` and `>`, because system.nim already has a From dbff2cd938b326279de0f3f97b2dd8c54a90468a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 9 Jan 2021 04:54:26 -0600 Subject: [PATCH 1801/4254] close #4834 add testcase (#16649) --- tests/cpp/t4834.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/cpp/t4834.nim diff --git a/tests/cpp/t4834.nim b/tests/cpp/t4834.nim new file mode 100644 index 000000000..0275b1b70 --- /dev/null +++ b/tests/cpp/t4834.nim @@ -0,0 +1,17 @@ +discard """ + targets: "cpp" +""" + +# issue #4834 +block: + defer: + let x = 0 + + +proc main() = + block: + defer: + raise newException(Exception, "foo") + +doAssertRaises(Exception): + main() From 65df5762a1f2011497350da0713a7bca05343326 Mon Sep 17 00:00:00 2001 From: vabresto <77133146+vabresto@users.noreply.github.com> Date: Sun, 10 Jan 2021 06:42:23 -0500 Subject: [PATCH 1802/4254] Add support for Transfer-Encoding: chunked (#16636) * Add support for Transfer-Encoding: chunked * Minor whitespace fixes * Use recv instead of recvLineInto * Undo changes to httpcore, inline changes --- lib/pure/asynchttpserver.nim | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 29a695379..86688d4b5 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -142,6 +142,17 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = proc sendStatus(client: AsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L\c\L") +func hasChunkedEncoding(request: Request): bool = + ## Searches for a chunked transfer encoding + const transferEncoding = "Transfer-Encoding" + + if request.headers.hasKey(transferEncoding): + for encoding in seq[string](request.headers[transferEncoding]): + if "chunked" == encoding.strip: + # Returns true if it is both an HttpPost and has chunked encoding + return request.reqMethod == HttpPost + return false + proc processRequest( server: AsyncHttpServer, req: FutureVar[Request], @@ -261,6 +272,39 @@ proc processRequest( if request.body.len != contentLength: await request.respond(Http400, "Bad Request. Content-Length does not match actual.") return true + elif hasChunkedEncoding(request): + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding + var sizeOrData = 0 + var bytesToRead = 0 + request.body = "" + + while true: + lineFut.mget.setLen(0) + lineFut.clean() + + # The encoding format alternates between specifying a number of bytes to read + # and the data to be read, of the previously specified size + if sizeOrData mod 2 == 0: + # Expect a number of chars to read + await client.recvLineInto(lineFut, maxLength = maxLine) + try: + bytesToRead = lineFut.mget.parseHexInt + except ValueError: + # Malformed request + await request.respond(Http411, ("Invalid chunked transfer encoding - " & + "chunk data size must be hex encoded")) + return true + else: + if bytesToRead == 0: + # Done reading chunked data + break + + # Read bytesToRead and add to body + # Note we add +2 because the line must be terminated by \r\n + let chunk = await client.recv(bytesToRead + 2) + request.body = request.body & chunk + + inc sizeOrData elif request.reqMethod == HttpPost: await request.respond(Http411, "Content-Length required.") return true From 7bde6aa37f52695736917a070bc25097f0cb0b34 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sun, 10 Jan 2021 15:40:53 +0200 Subject: [PATCH 1803/4254] Httpclient improvements (#15919) * Allow passing Uri instead of strings * Teach httpclient about 308 * Deprecate request proc where httpMethod is string * More use of HttpMethod enum Also fix handling of 308, I forgot to add the hunk to the previous commit. * Well behaved redirect handler * Also remove Transfer-Encoding * Removed unused proc * Secure redirection rules Strip sensitive headers for cross-domain redirects. * Allow httpMethod to be a string again This way unknown http verbs can be used without any problem. * Respect user-specified Host header * Missed multipart argument. * Try another method * add changelog * Fix hidden deprecation warning, parseEnum failing * This is wrong * Have to do it manually, parseEnum is not suitable * Review comments * update Co-authored-by: LemonBoy Co-authored-by: Dominik Picheta --- changelog.md | 3 + lib/pure/httpclient.nim | 189 ++++++++++++++++++++++------------- lib/pure/httpcore.nim | 57 ++++------- tests/stdlib/thttpclient.nim | 8 +- 4 files changed, 147 insertions(+), 110 deletions(-) diff --git a/changelog.md b/changelog.md index afe49f1f3..0705d0090 100644 --- a/changelog.md +++ b/changelog.md @@ -34,6 +34,9 @@ - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). +- various functions in `httpclient` now accept `url` of type `Uri`. Moreover `request` function's + `httpMethod` argument of type `string` was deprecated in favor of `HttpMethod` enum type. + - `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. - Added `cmpMem` to `system`. diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 70f3327b1..ea847ef8d 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -325,10 +325,14 @@ proc getDefaultSSL(): SslContext = result = defaultSslContext doAssert result != nil, "failure to initialize the SSL context" -proc newProxy*(url: string, auth = ""): Proxy = +proc newProxy*(url: string; auth = ""): Proxy = ## Constructs a new ``TProxy`` object. result = Proxy(url: parseUri(url), auth: auth) +proc newProxy*(url: Uri; auth = ""): Proxy = + ## Constructs a new ``TProxy`` object. + result = Proxy(url: url, auth: auth) + proc newMultipartData*: MultipartData {.inline.} = ## Constructs a new ``MultipartData`` object. MultipartData() @@ -457,29 +461,23 @@ proc sendFile(socket: Socket | AsyncSocket, await socket.send(buffer) file.close() -proc redirection(status: string): bool = - const redirectionNRs = ["301", "302", "303", "307", "308"] - for i in items(redirectionNRs): - if status.startsWith(i): - return true - -proc getNewLocation(lastURL: string, headers: HttpHeaders): string = - result = headers.getOrDefault"Location" - if result == "": httpError("location header expected") +proc getNewLocation(lastURL: Uri, headers: HttpHeaders): Uri = + let newLocation = headers.getOrDefault"Location" + if newLocation == "": httpError("location header expected") # Relative URLs. (Not part of the spec, but soon will be.) - let r = parseUri(result) - if r.hostname == "" and r.path != "": - var parsed = parseUri(lastURL) - parsed.path = r.path - parsed.query = r.query - parsed.anchor = r.anchor - result = $parsed + let parsedLocation = parseUri(newLocation) + if parsedLocation.hostname == "" and parsedLocation.path != "": + result = lastURL + result.path = parsedLocation.path + result.query = parsedLocation.query + result.anchor = parsedLocation.anchor + else: + result = parsedLocation -proc generateHeaders(requestUrl: Uri, httpMethod: string, headers: HttpHeaders, +proc generateHeaders(requestUrl: Uri, httpMethod: HttpMethod, headers: HttpHeaders, proxy: Proxy): string = # GET - let upperMethod = httpMethod.toUpperAscii() - result = upperMethod + result = $httpMethod result.add ' ' if proxy.isNil or requestUrl.scheme == "https": @@ -898,7 +896,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient, connectUrl.hostname = url.hostname connectUrl.port = if url.port != "": url.port else: "443" - let proxyHeaderString = generateHeaders(connectUrl, $HttpConnect, + let proxyHeaderString = generateHeaders(connectUrl, HttpConnect, newHttpHeaders(), client.proxy) await client.socket.send(proxyHeaderString) let proxyResp = await parseResponse(client, false) @@ -967,14 +965,12 @@ proc override(fallback, override: HttpHeaders): HttpHeaders = for k, vs in override.table: result[k] = vs -proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, - body = "", headers: HttpHeaders = nil, +proc requestAux(client: HttpClient | AsyncHttpClient, url: Uri, + httpMethod: HttpMethod, body = "", headers: HttpHeaders = nil, multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = # Helper that actually makes the request. Does not handle redirects. - let requestUrl = parseUri(url) - - if requestUrl.scheme == "": + if url.scheme == "": raise newException(ValueError, "No uri scheme supplied.") var data: seq[string] @@ -992,13 +988,13 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, await client.parseBodyFut client.parseBodyFut = nil - await newConnection(client, requestUrl) + await newConnection(client, url) let newHeaders = client.headers.override(headers) if not newHeaders.hasKey("user-agent") and client.userAgent.len > 0: newHeaders["User-Agent"] = client.userAgent - let headerString = generateHeaders(requestUrl, httpMethod, newHeaders, + let headerString = generateHeaders(url, httpMethod, newHeaders, client.proxy) await client.socket.send(headerString) @@ -1020,12 +1016,13 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, elif body.len > 0: await client.socket.send(body) - let getBody = httpMethod.toLowerAscii() notin ["head", "connect"] and + let getBody = httpMethod notin {HttpHead, HttpConnect} and client.getBody result = await parseResponse(client, getBody) -proc request*(client: HttpClient | AsyncHttpClient, url: string, - httpMethod: string, body = "", headers: HttpHeaders = nil, +proc request*(client: HttpClient | AsyncHttpClient, url: Uri | string, + httpMethod: HttpMethod | string = HttpGet, body = "", + headers: HttpHeaders = nil, multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a request @@ -1040,33 +1037,87 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string, ## ## You need to make sure that the ``url`` doesn't contain any newline ## characters. Failing to do so will raise ``AssertionDefect``. - doAssert(not url.contains({'\c', '\L'}), "url shouldn't contain any newline characters") + ## + ## **Deprecated since v1.5**: use HttpMethod enum instead; string parameter httpMethod is deprecated + when url is string: + doAssert(not url.contains({'\c', '\L'}), "url shouldn't contain any newline characters") + let url = parseUri(url) + + when httpMethod is string: + {.warning: + "Deprecated since v1.5; use HttpMethod enum instead; string parameter httpMethod is deprecated".} + let httpMethod = case httpMethod + of "HEAD": + HttpHead + of "GET": + HttpGet + of "POST": + HttpPost + of "PUT": + HttpPut + of "DELETE": + HttpDelete + of "TRACE": + HttpTrace + of "OPTIONS": + HttpOptions + of "CONNECT": + HttpConnect + of "PATCH": + HttpPatch + else: + raise newException(ValueError, "Invalid HTTP method name: " & httpMethod) result = await client.requestAux(url, httpMethod, body, headers, multipart) var lastURL = url for i in 1..client.maxRedirects: - if result.status.redirection(): - let redirectTo = getNewLocation(lastURL, result.headers) - # Guarantee method for HTTP 307: see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307 - var meth = if result.status == "307": httpMethod else: "GET" - result = await client.requestAux(redirectTo, meth, body, headers, multipart) - lastURL = redirectTo + let statusCode = result.code -proc request*(client: HttpClient | AsyncHttpClient, url: string, - httpMethod = HttpGet, body = "", headers: HttpHeaders = nil, - multipart: MultipartData = nil): Future[Response | AsyncResponse] - {.multisync.} = - ## Connects to the hostname specified by the URL and performs a request - ## using the method specified. - ## - ## Connection will be kept alive. Further requests on the same ``client`` to - ## the same hostname will not require a new connection to be made. The - ## connection can be closed by using the ``close`` procedure. - ## - ## When a request is made to a different hostname, the current connection will - ## be closed. - result = await request(client, url, $httpMethod, body, headers, multipart) + if statusCode notin {Http301, Http302, Http303, Http307, Http308}: + break + + let redirectTo = getNewLocation(lastURL, result.headers) + var redirectMethod: HttpMethod + var redirectBody: string + # For more informations about the redirect methods see: + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections + case statusCode + of Http301, Http302, Http303: + # The method is changed to GET unless it is GET or HEAD (RFC2616) + if httpMethod notin {HttpGet, HttpHead}: + redirectMethod = HttpGet + else: + redirectMethod = httpMethod + # The body is stripped away + redirectBody = "" + # Delete any header value associated with the body + if not headers.isNil(): + headers.del("Content-Length") + headers.del("Content-Type") + headers.del("Transfer-Encoding") + of Http307, Http308: + # The method and the body are unchanged + redirectMethod = httpMethod + redirectBody = body + else: + # Unreachable + doAssert(false) + + # Check if the redirection is to the same domain or a sub-domain (foo.com + # -> sub.foo.com) + if redirectTo.hostname != lastURL.hostname and + not redirectTo.hostname.endsWith("." & lastURL.hostname): + # Perform some cleanup of the header values + if headers != nil: + # Delete the Host header + headers.del("Host") + # Do not send any sensitive info to a unknown host + headers.del("Authorization") + + result = await client.requestAux(redirectTo, redirectMethod, redirectBody, + headers, multipart) + lastURL = redirectTo proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync.} = ## Returns the content of a response as a string. @@ -1079,79 +1130,79 @@ proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync return await resp.bodyStream.readAll() proc head*(client: HttpClient | AsyncHttpClient, - url: string): Future[Response | AsyncResponse] {.multisync.} = + url: Uri | string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a HEAD request. ## ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpHead) proc get*(client: HttpClient | AsyncHttpClient, - url: string): Future[Response | AsyncResponse] {.multisync.} = + url: Uri | string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a GET request. ## ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpGet) proc getContent*(client: HttpClient | AsyncHttpClient, - url: string): Future[string] {.multisync.} = + url: Uri | string): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a GET request. let resp = await get(client, url) return await responseContent(resp) proc delete*(client: HttpClient | AsyncHttpClient, - url: string): Future[Response | AsyncResponse] {.multisync.} = + url: Uri | string): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a DELETE request. ## This procedure uses httpClient values such as ``client.maxRedirects``. result = await client.request(url, HttpDelete) proc deleteContent*(client: HttpClient | AsyncHttpClient, - url: string): Future[string] {.multisync.} = + url: Uri | string): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a DELETE request. let resp = await delete(client, url) return await responseContent(resp) -proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc post*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a POST request. ## This procedure uses httpClient values such as ``client.maxRedirects``. - result = await client.request(url, $HttpPost, body, multipart=multipart) + result = await client.request(url, HttpPost, body, multipart=multipart) -proc postContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc postContent*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a POST request. let resp = await post(client, url, body, multipart) return await responseContent(resp) -proc put*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc put*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a PUT request. ## This procedure uses httpClient values such as ``client.maxRedirects``. - result = await client.request(url, $HttpPut, body, multipart=multipart) + result = await client.request(url, HttpPut, body, multipart=multipart) -proc putContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc putContent*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL andreturns the content of a PUT request. let resp = await put(client, url, body, multipart) return await responseContent(resp) -proc patch*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc patch*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = ## Connects to the hostname specified by the URL and performs a PATCH request. ## This procedure uses httpClient values such as ``client.maxRedirects``. - result = await client.request(url, $HttpPatch, body, multipart=multipart) + result = await client.request(url, HttpPatch, body, multipart=multipart) -proc patchContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc patchContent*(client: HttpClient | AsyncHttpClient, url: Uri | string, body = "", multipart: MultipartData = nil): Future[string] {.multisync.} = ## Connects to the hostname specified by the URL and returns the content of a PATCH request. let resp = await patch(client, url, body, multipart) return await responseContent(resp) -proc downloadFile*(client: HttpClient, url: string, filename: string) = +proc downloadFile*(client: HttpClient, url: Uri | string, filename: string) = ## Downloads ``url`` and saves it to ``filename``. client.getBody = false defer: @@ -1167,10 +1218,10 @@ proc downloadFile*(client: HttpClient, url: string, filename: string) = if resp.code.is4xx or resp.code.is5xx: raise newException(HttpRequestError, resp.status) -proc downloadFile*(client: AsyncHttpClient, url: string, +proc downloadFile*(client: AsyncHttpClient, url: Uri | string, filename: string): Future[void] = proc downloadFileEx(client: AsyncHttpClient, - url, filename: string): Future[void] {.async.} = + url: Uri | string, filename: string): Future[void] {.async.} = ## Downloads ``url`` and saves it to ``filename``. client.getBody = false let resp = await client.get(url) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 9287e9864..774de1260 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -29,24 +29,26 @@ type HttpVer11, HttpVer10 - HttpMethod* = enum ## the requested HttpMethod - HttpHead, ## Asks for the response identical to the one that would - ## correspond to a GET request, but without the response - ## body. - HttpGet, ## Retrieves the specified resource. - HttpPost, ## Submits data to be processed to the identified - ## resource. The data is included in the body of the - ## request. - HttpPut, ## Uploads a representation of the specified resource. - HttpDelete, ## Deletes the specified resource. - HttpTrace, ## Echoes back the received request, so that a client - ## can see what intermediate servers are adding or - ## changing in the request. - HttpOptions, ## Returns the HTTP methods that the server supports - ## for specified address. - HttpConnect, ## Converts the request connection to a transparent - ## TCP/IP tunnel, usually used for proxies. - HttpPatch ## Applies partial modifications to a resource. + HttpMethod* = enum ## the requested HttpMethod + HttpHead = "HEAD" ## Asks for the response identical to the one that + ## would correspond to a GET request, but without + ## the response body. + HttpGet = "GET" ## Retrieves the specified resource. + HttpPost = "POST" ## Submits data to be processed to the identified + ## resource. The data is included in the body of + ## the request. + HttpPut = "PUT" ## Uploads a representation of the specified + ## resource. + HttpDelete = "DELETE" ## Deletes the specified resource. + HttpTrace = "TRACE" ## Echoes back the received request, so that a + ## client + ## can see what intermediate servers are adding or + ## changing in the request. + HttpOptions = "OPTIONS" ## Returns the HTTP methods that the server + ## supports for specified address. + HttpConnect = "CONNECT" ## Converts the request connection to a transparent + ## TCP/IP tunnel, usually used for proxies. + HttpPatch = "PATCH" ## Applies partial modifications to a resource. const @@ -150,7 +152,6 @@ func newHttpHeaders*(keyValuePairs: else: result.table[key] = @[pair.val] - func `$`*(headers: HttpHeaders): string {.inline.} = $headers.table @@ -378,21 +379,3 @@ func is4xx*(code: HttpCode): bool {.inline.} = func is5xx*(code: HttpCode): bool {.inline.} = ## Determines whether ``code`` is a 5xx HTTP status code. code.int in {500 .. 599} - -func `$`*(httpMethod: HttpMethod): string {.inline.} = - runnableExamples: - doAssert $HttpHead == "HEAD" - doAssert $HttpPatch == "PATCH" - doAssert $HttpGet == "GET" - doAssert $HttpPost == "POST" - - result = case httpMethod - of HttpHead: "HEAD" - of HttpGet: "GET" - of HttpPost: "POST" - of HttpPut: "PUT" - of HttpDelete: "DELETE" - of HttpTrace: "TRACE" - of HttpOptions: "OPTIONS" - of HttpConnect: "CONNECT" - of HttpPatch: "PATCH" diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim index 6a634d90f..4881370ee 100644 --- a/tests/stdlib/thttpclient.nim +++ b/tests/stdlib/thttpclient.nim @@ -39,7 +39,7 @@ proc makeIPv6HttpServer(hostname: string, port: Port, proc asyncTest() {.async.} = var client = newAsyncHttpClient() - var resp = await client.request("http://example.com/") + var resp = await client.request("http://example.com/", HttpGet) doAssert(resp.code.is2xx) var body = await resp.body body = await resp.body # Test caching @@ -48,7 +48,7 @@ proc asyncTest() {.async.} = resp = await client.request("http://example.com/404") doAssert(resp.code.is4xx) doAssert(resp.code == Http404) - doAssert(resp.status == Http404) + doAssert(resp.status == $Http404) resp = await client.request("https://google.com/") doAssert(resp.code.is2xx or resp.code.is3xx) @@ -102,14 +102,14 @@ proc asyncTest() {.async.} = proc syncTest() = var client = newHttpClient() - var resp = client.request("http://example.com/") + var resp = client.request("http://example.com/", HttpGet) doAssert(resp.code.is2xx) doAssert("Example Domain" in resp.body) resp = client.request("http://example.com/404") doAssert(resp.code.is4xx) doAssert(resp.code == Http404) - doAssert(resp.status == Http404) + doAssert(resp.status == $Http404) resp = client.request("https://google.com/") doAssert(resp.code.is2xx or resp.code.is3xx) From f82100ac93ddb8977d2a404d2cd85975114f50ab Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 10 Jan 2021 10:19:40 -0600 Subject: [PATCH 1804/4254] fix broken CI (#16663) --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index ea847ef8d..6acf8d9cd 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -979,7 +979,7 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: Uri, else: if body.len != 0: client.headers["Content-Length"] = $body.len - elif httpMethod notin ["GET", "HEAD"] and not client.headers.hasKey("Content-Length"): + elif httpMethod notin [HttpGet, HttpHead] and not client.headers.hasKey("Content-Length"): client.headers["Content-Length"] = "0" when client is AsyncHttpClient: From 2c6f5ae6815367dcb44e441c8f3bda2e2513b061 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 10 Jan 2021 15:51:29 -0600 Subject: [PATCH 1805/4254] fix #16650 (#16660) --- compiler/semfold.nim | 7 ++++++- tests/system/tostring.nim | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 3d0a9d0ae..4cc2dcba0 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -15,6 +15,8 @@ import platform, math, msgs, idents, renderer, types, commands, magicsys, modulegraphs, strtabs, lineinfos +from system/memory import nimCStrLen + proc errorType*(g: ModuleGraph): PType = ## creates a type representing an error state result = newType(tyError, nextTypeId(g.idgen), g.owners[^1]) @@ -133,7 +135,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = if a.kind == nkNilLit: result = newIntNodeT(Zero, n, g) elif a.kind in {nkStrLit..nkTripleStrLit}: - result = newIntNodeT(toInt128(a.strVal.len), n, g) + if a.typ.kind == tyString: + result = newIntNodeT(toInt128(a.strVal.len), n, g) + elif a.typ.kind == tyCString: + result = newIntNodeT(toInt128(nimCStrLen(a.strVal)), n, g) else: result = newIntNodeT(toInt128(a.len), n, g) of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index 4ff363075..fa82acc3b 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -1,7 +1,3 @@ -discard """ - output: "DONE: tostring.nim" -""" - doAssert "@[23, 45]" == $(@[23, 45]) doAssert "[32, 45]" == $([32, 45]) doAssert """@["", "foo", "bar"]""" == $(@["", "foo", "bar"]) @@ -108,7 +104,7 @@ bar(nilstring) static: stringCompare() -# bug 8847 +# issue #8847 var a2: cstring = "fo\"o2" block: @@ -116,5 +112,14 @@ block: s.addQuoted a2 doAssert s == "\"fo\\\"o2\"" - -echo "DONE: tostring.nim" +# issue #16650 +template fn() = + doAssert len(cstring"ab\0c") == 5 + doAssert len(cstring("ab\0c")) == 2 + when nimvm: + discard + else: + let c = cstring("ab\0c") + doAssert len(c) == 2 +fn() +static: fn() From 510e383d9233641a82ef25d3e3fe3e2eba3a4388 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 00:26:52 -0600 Subject: [PATCH 1806/4254] add error messages (#16679) --- testament/testament.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/testament.nim b/testament/testament.nim index 5686da81c..314a83936 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -795,7 +795,7 @@ proc main() = var subPath = p.key.string let nimRoot = currentSourcePath / "../.." # makes sure points to this regardless of cwd or which nim is used to compile this. - doAssert dirExists(nimRoot/testsDir) # sanity check + doAssert(dirExists(nimRoot/testsDir), nimRoot/testsDir & " doesn't exist!") # sanity check if subPath.isAbsolute: subPath = subPath.relativePath(nimRoot) # at least one directory is required in the path, to use as a category name let pathParts = subPath.relativePath(testsDir).split({DirSep, AltSep}) From 0286a0879bc44e5267a5fd36e6f4aac8f78713ea Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 11 Jan 2021 09:09:38 +0000 Subject: [PATCH 1807/4254] fix #16651 (#16658) * fix #16651 --- compiler/semtypes.nim | 7 +++++++ tests/converter/tgenericconverter.nim | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 64113a4c6..45f20da9b 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1059,6 +1059,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, # disable the bindOnce behavior for the type class result = recurse(paramType.base, true) + of tyTuple: + for i in 0.. Date: Mon, 11 Jan 2021 01:16:20 -0800 Subject: [PATCH 1808/4254] fix #16555, fixes #16405: len, high honors '\0' for cstring in vm (#16610) --- compiler/vm.nim | 4 ++++ compiler/vmdef.nim | 1 + compiler/vmgen.nim | 12 +++++++----- lib/system.nim | 20 +++++++++++++------- tests/stdlib/thashes.nim | 18 ++++++++++++++++-- tests/stdlib/tstring.nim | 34 +++++++++++++++++++++++++++++++++- 6 files changed, 74 insertions(+), 15 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 0f75faee3..b8df456e0 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -872,6 +872,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeBImm(rkInt) assert regs[rb].kind == rkNode regs[ra].intVal = regs[rb].node.strVal.len - imm + of opcLenCstring: + decodeBImm(rkInt) + assert regs[rb].kind == rkNode + regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm of opcIncl: decodeB(rkNode) let b = regs[rb].regToNode diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 6d6c55250..eab18f417 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -86,6 +86,7 @@ type opcSubImmInt, opcLenSeq, opcLenStr, + opcLenCstring, opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt, opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 46931eb54..6790276a9 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1034,7 +1034,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mLengthOpenArray, mLengthArray, mLengthSeq: genUnaryABI(c, n, dest, opcLenSeq) of mLengthStr: - genUnaryABI(c, n, dest, opcLenStr) + case n[1].typ.kind + of tyString: genUnaryABI(c, n, dest, opcLenStr) + of tyCString: genUnaryABI(c, n, dest, opcLenCstring) + else: doAssert false, $n[1].typ.kind of mIncl, mExcl: unused(c, n, dest) var d = c.genx(n[1]) @@ -1178,10 +1181,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = if dest < 0: dest = c.getTemp(n.typ) let tmp = c.genx(n[1]) case n[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind: - of tyString, tyCString: - c.gABI(n, opcLenStr, dest, tmp, 1) - else: - c.gABI(n, opcLenSeq, dest, tmp, 1) + of tyString: c.gABI(n, opcLenStr, dest, tmp, 1) + of tyCString: c.gABI(n, opcLenCstring, dest, tmp, 1) + else: c.gABI(n, opcLenSeq, dest, tmp, 1) c.freeTemp(tmp) of mEcho: unused(c, n, dest) diff --git a/lib/system.nim b/lib/system.nim index e220ba7a3..25184eb15 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -701,18 +701,24 @@ proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} ## var str = "Hello world!" ## echo len(str) # => 12 -proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} - ## Returns the length of a compatible string. This is sometimes - ## an O(n) operation. +proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} = + ## Returns the length of a compatible string. This is an O(n) operation except + ## in js at runtime. ## ## **Note:** On the JS backend this currently counts UTF-16 code points ## instead of bytes at runtime (not at compile time). For now, if you ## need the byte length of the UTF-8 encoding, convert to string with ## `$` first then call `len`. - ## - ## .. code-block:: Nim - ## var str: cstring = "Hello world!" - ## len(str) # => 12 + runnableExamples: + doAssert len(cstring"abc") == 3 + doAssert len(cstring r"ab\0c") == 5 # \0 is escaped + doAssert len(cstring"ab\0c") == 5 # ditto + var a: cstring = "ab\0c" + when defined(js): doAssert a.len == 4 # len ignores \0 for js + else: doAssert a.len == 2 # \0 is a null terminator + static: + var a2: cstring = "ab\0c" + doAssert a2.len == 2 # \0 is a null terminator, even in js vm proc len*(x: (type array)|array): int {.magic: "LengthArray", noSideEffect.} ## Returns the length of an array or an array type. diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 17640387a..ce7bb7d8c 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -86,8 +86,6 @@ block largeSize: # longer than 4 characters doAssert hash(xx, 0, 3) == hash(ssl, 0, 3) proc main() = - - doAssert hash(0.0) == hash(0) doAssert hash(cstring"abracadabra") == 97309975 doAssert hash(cstring"abracadabra") == hash("abracadabra") @@ -115,6 +113,22 @@ proc main() = doAssert hash(-9999.283456) != 0 doAssert hash(84375674.0) != 0 + block: # bug #16555 + proc fn(): auto = + # avoids hardcoding values + var a = "abc\0def" + var b = a.cstring + result = (hash(a), hash(b)) + doAssert result[0] != result[1] + when not defined(js): + doAssert fn() == static(fn()) + else: + # xxx this is a tricky case; consistency of hashes for cstring's containing + # '\0\' matters for c backend but less for js backend since such strings + # are much less common in js backend; we make vm for js backend consistent + # with c backend instead of js backend because FFI code (or other) could + # run at CT, expecting c semantics. + discard static: main() main() diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 4d5a15940..fcbacc533 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -96,11 +96,43 @@ func reverse*(a: string): string = proc main() = + # xxx put all tests here to test in VM and RT test_string_slice() test_string_cmp() tester(1) - doAssert reverse("hello") == "olleh" + + block: # reverse + doAssert reverse("hello") == "olleh" + + block: # len, high + var a = "ab\0cd" + var b = a.cstring + doAssert a.len == 5 + block: # bug #16405 + when defined(js): + when nimvm: doAssert b.len == 2 + else: doAssert b.len == 5 + else: doAssert b.len == 2 + + doAssert a.high == a.len - 1 + doAssert b.high == b.len - 1 + + doAssert "".len == 0 + doAssert "".high == -1 + doAssert "".cstring.len == 0 + doAssert "".cstring.high == -1 + + var c: cstring = nil + template impl() = + doAssert c.len == 0 + doAssert c.high == -1 + when defined js: + when nimvm: impl() + else: + # xxx pending bug #16674 + discard + else: impl() static: main() main() From bbc96f974d643b5ab4e2b9d2855e94ef30ed3ee4 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 11 Jan 2021 01:18:01 -0800 Subject: [PATCH 1809/4254] fixed nim-lang/nimsuggest#82 pure enum field sug (#16676) - previous code wasn't account for tyEnum being wrapped in tyTypeDesc - now pure enum fields are suggested --- compiler/suggest.nim | 21 +++++++++++---------- nimsuggest/tests/tsug_enum.nim | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 nimsuggest/tests/tsug_enum.nim diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 560d20b3f..283690080 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -386,17 +386,17 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) else: # fallback: suggestEverything(c, n, field, outputs) - elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: - # look up if the identifier belongs to the enum: - var t = typ - while t != nil: - suggestSymList(c, t.n, field, n.info, outputs) - t = t[0] - suggestOperations(c, n, field, typ, outputs) else: - let orig = typ # skipTypes(typ, {tyGenericInst, tyAlias, tySink}) - typ = skipTypes(typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) - if typ.kind == tyObject: + let orig = typ + typ = skipTypes(orig, {tyTypeDesc, tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) + + if typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: + # look up if the identifier belongs to the enum: + var t = typ + while t != nil: + suggestSymList(c, t.n, field, n.info, outputs) + t = t[0] + elif typ.kind == tyObject: var t = typ while true: suggestObject(c, t.n, field, n.info, outputs) @@ -404,6 +404,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) t = skipTypes(t[0], skipPtrs) elif typ.kind == tyTuple and typ.n != nil: suggestSymList(c, typ.n, field, n.info, outputs) + suggestOperations(c, n, field, orig, outputs) if typ != orig: suggestOperations(c, n, field, typ, outputs) diff --git a/nimsuggest/tests/tsug_enum.nim b/nimsuggest/tests/tsug_enum.nim new file mode 100644 index 000000000..97a225f16 --- /dev/null +++ b/nimsuggest/tests/tsug_enum.nim @@ -0,0 +1,18 @@ +## suggestions for enums + +type + LogLevel {.pure.} = enum + debug, log, warn, error + + FooBar = enum + fbFoo, fbBar + +echo fbFoo, fbBar + +echo LogLevel.deb#[!]# + +discard """ +$nimsuggest --tester $file +>sug $1 +sug;;skEnumField;;debug;;LogLevel;;*nimsuggest/tests/tsug_enum.nim;;5;;4;;"";;100;;Prefix +""" \ No newline at end of file From 5897ed9d3d5ca5f84423e87a70addc8c6764923e Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 11 Jan 2021 10:53:15 +0100 Subject: [PATCH 1810/4254] Improve documentation of strmisc (#16665) Simplify examples --- lib/pure/strmisc.nim | 60 ++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 5060deb78..c8cd839be 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -8,12 +8,12 @@ # ## This module contains various string utility routines that are uncommonly -## used in comparison to `strutils `_. +## used in comparison to the ones in `strutils `_. -import strutils +import std/strutils -proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = - ## Expand tab characters in `s` replacing them by spaces. +func expandTabs*(s: string, tabSize: int = 8): string = + ## Expands tab characters in `s`, replacing them by spaces. ## ## The amount of inserted spaces for each tab character is the difference ## between the current column number and the next tab position. Tab positions @@ -24,9 +24,7 @@ proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = runnableExamples: doAssert expandTabs("\t", 4) == " " doAssert expandTabs("\tfoo\t", 4) == " foo " - doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" - doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " - doAssert expandTabs("ab\tcd\n\txy\t", 3) == "ab cd\n xy " + doAssert expandTabs("a\tb\n\txy\t", 3) == "a b\n xy " result = newStringOfCap(s.len + s.len shr 2) var pos = 0 @@ -50,37 +48,39 @@ proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = if c == '\l': pos = 0 -proc partition*(s: string, sep: string, - right: bool = false): (string, string, string) - {.noSideEffect.} = - ## Split the string at the first or last occurrence of `sep` into a 3-tuple +func partition*(s: string, sep: string, + right: bool = false): (string, string, string) = + ## Splits the string at the first (if `right` is false) + ## or last (if `right` is true) occurrence of `sep` into a 3-tuple. ## - ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or - ## (`s`, "", "") if `sep` is not found and `right` is false or - ## ("", "", `s`) if `sep` is not found and `right` is true + ## Returns a 3-tuple of strings, `(beforeSep, sep, afterSep)` or + ## `(s, "", "")` if `sep` is not found and `right` is false or + ## `("", "", s)` if `sep` is not found and `right` is true. + ## + ## **See also:** + ## * `rpartition proc <#rpartition,string,string>`_ runnableExamples: - doAssert partition("foo:bar", ":") == ("foo", ":", "bar") - doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") - doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") - doAssert partition("foobarbar", "foo") == ("", "foo", "barbar") - doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "") + doAssert partition("foo:bar:baz", ":") == ("foo", ":", "bar:baz") + doAssert partition("foo:bar:baz", ":", right = true) == ("foo:bar", ":", "baz") + doAssert partition("foobar", ":") == ("foobar", "", "") + doAssert partition("foobar", ":", right = true) == ("", "", "foobar") let position = if right: s.rfind(sep) else: s.find(sep) if position != -1: return (s[0 ..< position], sep, s[position + sep.len ..< s.len]) return if right: ("", "", s) else: (s, "", "") -proc rpartition*(s: string, sep: string): (string, string, string) - {.noSideEffect.} = - ## Split the string at the last occurrence of `sep` into a 3-tuple +func rpartition*(s: string, sep: string): (string, string, string) = + ## Splits the string at the last occurrence of `sep` into a 3-tuple. ## - ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or - ## ("", "", `s`) if `sep` is not found + ## Returns a 3-tuple of strings, `(beforeSep, sep, afterSep)` or + ## `("", "", s)` if `sep` is not found. This is the same as + ## `partition(s, sep, right = true)`. + ## + ## **See also:** + ## * `partition proc <#partition,string,string,bool>`_ runnableExamples: - doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar") - doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "") - doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar") - doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar") - doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "") + doAssert rpartition("foo:bar:baz", ":") == ("foo:bar", ":", "baz") + doAssert rpartition("foobar", ":") == ("", "", "foobar") - return partition(s, sep, right = true) + partition(s, sep, right = true) From be6e8916faa51d227d51e1291d1f24751385b010 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 04:39:38 -0600 Subject: [PATCH 1811/4254] fix negative nan (#16628) --- compiler/jsgen.nim | 5 ++++- compiler/rodutils.nim | 13 +++++++++++-- tests/stdlib/tmath.nim | 16 ++++++++++++++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index f588f9555..10a33423e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2485,7 +2485,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = let f = n.floatVal case classify(f) of fcNan: - r.res = rope"NaN" + if signbit(f): + r.res = rope"-NaN" + else: + r.res = rope"NaN" of fcNegZero: r.res = rope"-0.0" of fcZero: diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 7070e6c3f..353992fca 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -8,7 +8,7 @@ # ## Serialization utilities for the compiler. -import strutils, math +import std/[strutils, math] # bcc on windows doesn't have C99 functions when defined(windows) and defined(bcc): @@ -33,10 +33,19 @@ when defined(windows) and defined(bcc): proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "", nodecl, varargs.} + +when not declared(signbit): + proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "".} + proc signbit*(x: SomeFloat): bool {.inline.} = + result = c_signbit(x) != 0 + proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = case classify(f) of fcNan: - result = "NAN" + if signbit(f): + result = "-NAN" + else: + result = "NAN" of fcNegZero: result = "-0.0" & literalPostfix of fcZero: diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 62fdcd19f..edab62a66 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -319,6 +319,18 @@ template main = doAssert not Inf.isNaN doAssert isNaN(Inf - Inf) + block: # signbit + let x1 = NaN + let x2 = -NaN + let x3 = -x1 + + doAssert isNaN(x1) + doAssert isNaN(x2) + doAssert isNaN(x3) + doAssert not signbit(x1) + doAssert signbit(x2) + doAssert signbit(x3) + block: # copySign doAssert copySign(10.0, -1.0) == -10.0 doAssert copySign(-10.0, -1.0) == -10.0 @@ -385,8 +397,8 @@ template main = discard else: when not defined(js): - doAssert copySign(-1.0, -NaN) == 1.0 - doAssert copySign(10.0, -NaN) == 10.0 + doAssert copySign(-1.0, -NaN) == -1.0 + doAssert copySign(10.0, -NaN) == -10.0 doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0 # fails in VM block: From aa185c0e9b4904b305496bd1f83cbbadf2fbfa36 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 08:07:48 -0600 Subject: [PATCH 1812/4254] fix #13517 (#16681) --- compiler/vm.nim | 6 +++--- tests/distinct/tdistinct_issues.nim | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index b8df456e0..00f0aca7c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -429,13 +429,13 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): return true of tyUInt..tyUInt64: dest.ensureKind(rkInt) - case skipTypes(srctyp, abstractRange).kind + let styp = srctyp.skipTypes(abstractRange) # skip distinct types(dest type could do this too if needed) + case styp.kind of tyFloat..tyFloat64: dest.intVal = int(src.floatVal) else: - let srcDist = (sizeof(src.intVal) - srctyp.size) * 8 + let srcDist = (sizeof(src.intVal) - styp.size) * 8 let destDist = (sizeof(dest.intVal) - desttyp.size) * 8 - var value = cast[BiggestUInt](src.intVal) value = (value shl srcDist) shr srcDist value = (value shl destDist) shr destDist diff --git a/tests/distinct/tdistinct_issues.nim b/tests/distinct/tdistinct_issues.nim index ce71344d0..747cf0b8d 100644 --- a/tests/distinct/tdistinct_issues.nim +++ b/tests/distinct/tdistinct_issues.nim @@ -65,3 +65,17 @@ block t9322: proc mystr(s: string) = echo s mystr($Fix("apr")) + + +block: # bug #13517 + type MyUint64 = distinct uint64 + + proc `==`(a: MyUint64, b: uint64): bool = uint64(a) == b + + block: + doAssert MyUint64.high is MyUint64 + doAssert MyUint64.high == 18446744073709551615'u64 + + static: + doAssert MyUint64.high is MyUint64 + doAssert MyUint64.high == 18446744073709551615'u64 From 0c128259bb01cde8ed27430929b0a01c5ee7b88c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 08:13:13 -0600 Subject: [PATCH 1813/4254] close #7097 add testcase (#16682) --- tests/converter/t7097.nim | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/converter/t7097.nim diff --git a/tests/converter/t7097.nim b/tests/converter/t7097.nim new file mode 100644 index 000000000..fdb573588 --- /dev/null +++ b/tests/converter/t7097.nim @@ -0,0 +1,38 @@ +type + Byte* = uint8 + Bytes* = seq[Byte] + + BytesRange* = object + bytes: Bytes + ibegin, iend: int + +proc initBytesRange*(s: var Bytes, ibegin = 0, iend = -1): BytesRange = + let e = if iend < 0: s.len + iend + 1 + else: iend + assert ibegin > 0 and e <= s.len + + shallow(s) + result.bytes = s + result.ibegin = ibegin + result.iend = e + +template `[]=`*(r: var BytesRange, i: int, v: Byte) = + r.bytes[r.ibegin + i] = v + +converter fromSeq*(s: Bytes): BytesRange = + var seqCopy = s + return initBytesRange(seqCopy) + +type + Reader* = object + data: BytesRange + position: int + +proc readerFromHex*(input: string): Reader = + let totalBytes = input.len div 2 + var backingStore = newSeq[Byte](totalBytes) + result.data = initBytesRange(backingStore) + + for i in 0 ..< totalBytes: + var nextByte = 0 + result.data[i] = Byte(nextByte) # <-------- instantiated from here From 5af13c5aceaedf211ff59113384bcb6a85c35c2b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 11:02:32 -0600 Subject: [PATCH 1814/4254] close #9655 add testcase (#16683) --- tests/ccgbugs/t9655.nim | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ccgbugs/t9655.nim diff --git a/tests/ccgbugs/t9655.nim b/tests/ccgbugs/t9655.nim new file mode 100644 index 000000000..29fb903a4 --- /dev/null +++ b/tests/ccgbugs/t9655.nim @@ -0,0 +1,30 @@ +discard """ + action: "compile" +""" + +import std/[asynchttpserver, asyncdispatch] +import std/[strformat] + +proc main() = + let local = "123" + + proc serveIndex(req: Request) {.async, gcsafe.} = + await req.respond(Http200, &"{local}") + + proc serve404(req: Request) {.async, gcsafe.} = + echo req.url.path + await req.respond(Http404, "not found") + + proc serve(req: Request) {.async, gcsafe.} = + let handler = case req.url.path: + of "/": + serveIndex + else: + serve404 + await handler(req) + + let server = newAsyncHttpServer() + waitFor server.serve(Port(8080), serve, address = "127.0.0.1") + +when isMainModule: + main() From da28df6113cdc552ad2ef3a029638efd9bfdadf2 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 11:02:53 -0600 Subject: [PATCH 1815/4254] remove deprecated specs (#16684) --- testament/specs.nim | 4 ---- testament/tests/shouldfail/tmsg.nim | 6 ------ 2 files changed, 10 deletions(-) delete mode 100644 testament/tests/shouldfail/tmsg.nim diff --git a/testament/specs.nim b/testament/specs.nim index 58fe7bf4f..48fe51658 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -303,10 +303,6 @@ proc parseSpec*(filename: string): TSpec = of "exitcode": discard parseInt(e.value, result.exitCode) result.action = actionRun - of "msg": - result.msg = e.value - if result.action != actionRun: - result.action = actionCompile of "errormsg": result.msg = e.value result.action = actionReject diff --git a/testament/tests/shouldfail/tmsg.nim b/testament/tests/shouldfail/tmsg.nim deleted file mode 100644 index 4ad17fa95..000000000 --- a/testament/tests/shouldfail/tmsg.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ -msg: "Hello World" -""" - -static: - echo "something else" From 335f849c36c4d7e618de277f6da64d8c1fdcc1c9 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jan 2021 12:00:57 -0600 Subject: [PATCH 1816/4254] close #9901 add testcase (#16662) * close #9901 add testcase * follow advice --- tests/misc/tproveinit.nim | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/misc/tproveinit.nim diff --git a/tests/misc/tproveinit.nim b/tests/misc/tproveinit.nim new file mode 100644 index 000000000..c9f688309 --- /dev/null +++ b/tests/misc/tproveinit.nim @@ -0,0 +1,18 @@ +discard """ + joinable: false +""" + +{.warningAsError[ProveInit]:on.} +template main() = + proc fn(): var int = + discard + discard fn() +doAssert not compiles(main()) + +# bug #9901 +import std/[sequtils, times] +proc parseMyDates(line: string): DateTime = + result = parse(line, "yyyy-MM-dd") +var dateStrings = @["2018-12-01", "2018-12-02", "2018-12-03"] +var parsed = dateStrings.map(parseMyDates) +discard parsed From fd5c8ef20845a511ad4e0af8dd8ad4331bf46ffc Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 11 Jan 2021 21:51:04 +0300 Subject: [PATCH 1817/4254] RST: implement internal targets (#16614) --- compiler/docgen.nim | 2 +- config/nimdoc.cfg | 3 +- lib/packages/docutils/rst.nim | 168 +++++++++++++++++++++++-------- lib/packages/docutils/rstast.nim | 14 ++- lib/packages/docutils/rstgen.nim | 135 +++++++++++++++---------- tests/stdlib/trstgen.nim | 158 +++++++++++++++++++++++++++++ 6 files changed, 379 insertions(+), 101 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d21db7634..f07adc428 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -560,7 +560,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: Runnab "\n\\textbf{$1}\n", [msg.rope]) inc d.listingCounter let id = $d.listingCounter - dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"]) + dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) var dest2 = "" renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) dest.add dest2 diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 585b3cc49..ff4dac781 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -206,7 +206,8 @@ $moduledesc $content """ -doc.listing_start = "
                                      "
                                      +# $1 - number of listing in document, $2 - language (e.g. langNim), $3 - anchor
                                      +doc.listing_start = ""
                                       doc.listing_end = "
                                      " # * $analytics: Google analytics location, includes -Create a ``calculator.nim`` file with the following content (or reuse the one +Create a `calculator.nim` file with the following content (or reuse the one from the previous section): .. code-block:: nim @@ -209,9 +211,9 @@ from the previous section): when isMainModule: echo addTwoIntegers(3, 7) -Compile the Nim code to JavaScript with ``nim js -o:calculator.js -calculator.nim`` and open ``host.html`` in a browser. If the browser supports -javascript, you should see the value ``10`` in the browser's console. Use the +Compile the Nim code to JavaScript with `nim js -o:calculator.js +calculator.nim` and open `host.html` in a browser. If the browser supports +javascript, you should see the value `10` in the browser's console. Use the `dom module `_ for specific DOM querying and modification procs or take a look at `karax `_ for how to develop browser-based applications. @@ -222,29 +224,29 @@ Backend code calling Nim Backend code can interface with Nim code exposed through the `exportc pragma `_. The -``exportc`` pragma is the *generic* way of making Nim symbols available to +`exportc` pragma is the *generic* way of making Nim symbols available to the backends. By default, the Nim compiler will mangle all the Nim symbols to -avoid any name collision, so the most significant thing the ``exportc`` pragma +avoid any name collision, so the most significant thing the `exportc` pragma does is maintain the Nim symbol name, or if specified, use an alternative symbol for the backend in case the symbol rules don't match. The JavaScript target doesn't have any further interfacing considerations since it also has garbage collection, but the C targets require you to -initialize Nim's internals, which is done calling a ``NimMain`` function. +initialize Nim's internals, which is done calling a `NimMain` function. Also, C code requires you to specify a forward declaration for functions or the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. -The Nim compiler can generate a C interface header through the ``--header`` +The Nim compiler can generate a C interface header through the `--header` command-line switch. The generated header will contain all the exported -symbols and the ``NimMain`` proc which you need to call before any other +symbols and the `NimMain` proc which you need to call before any other Nim code. Nim invocation example from C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a ``fib.nim`` file with the following content: +Create a `fib.nim` file with the following content: .. code-block:: nim @@ -254,7 +256,7 @@ Create a ``fib.nim`` file with the following content: else: result = fib(a - 1) + fib(a - 2) -Create a ``maths.c`` file with the following content: +Create a `maths.c` file with the following content: .. code-block:: c @@ -277,30 +279,30 @@ program:: $ gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c The first command runs the Nim compiler with three special options to avoid -generating a ``main()`` function in the generated files, avoid linking the +generating a `main()` function in the generated files, avoid linking the object files into a final binary, and explicitly generate a header file for C -integration. All the generated files are placed into the ``nimcache`` -directory. That's why the next command compiles the ``maths.c`` source plus -all the ``.c`` files from ``nimcache``. In addition to this path, you also -have to tell the C compiler where to find Nim's ``nimbase.h`` header file. +integration. All the generated files are placed into the `nimcache` +directory. That's why the next command compiles the `maths.c` source plus +all the `.c` files from `nimcache`. In addition to this path, you also +have to tell the C compiler where to find Nim's `nimbase.h` header file. -Instead of depending on the generation of the individual ``.c`` files you can +Instead of depending on the generation of the individual `.c` files you can also ask the Nim compiler to generate a statically linked library:: $ nim c --app:staticLib --noMain --header fib.nim $ gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c The Nim compiler will handle linking the source files generated in the -``nimcache`` directory into the ``libfib.nim.a`` static library, which you can +`nimcache` directory into the `libfib.nim.a` static library, which you can then link into your C program. Note that these commands are generic and will vary for each system. For instance, on Linux systems you will likely need to -use ``-ldl`` too to link in required dlopen functionality. +use `-ldl` too to link in required dlopen functionality. Nim invocation example from JavaScript ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a ``mhost.html`` file with the following content: +Create a `mhost.html` file with the following content: .. code-block:: @@ -311,7 +313,7 @@ Create a ``mhost.html`` file with the following content: -Create a ``fib.nim`` file with the following content (or reuse the one +Create a `fib.nim` file with the following content (or reuse the one from the previous section): .. code-block:: nim @@ -322,10 +324,10 @@ from the previous section): else: result = fib(a - 1) + fib(a - 2) -Compile the Nim code to JavaScript with ``nim js -o:fib.js fib.nim`` and -open ``mhost.html`` in a browser. If the browser supports javascript, you -should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned -earlier, JavaScript doesn't require an initialization call to ``NimMain`` or +Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim` and +open `mhost.html` in a browser. If the browser supports javascript, you +should see an alert box displaying the text `Fib for 9 is 34`. As mentioned +earlier, JavaScript doesn't require an initialization call to `NimMain` or a similar function and you can call the exported Nim proc directly. @@ -335,14 +337,14 @@ Nimcache naming logic The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default name for the directory depends on the used backend and on your OS but you can -use the ``--nimcache`` `compiler switch +use the `--nimcache` `compiler switch `_ to change it. Memory management ================= -In the previous sections, the ``NimMain()`` function reared its head. Since +In the previous sections, the `NimMain()` function reared its head. Since JavaScript already provides automatic memory management, you can freely pass objects between the two languages without problems. In C and derivate languages you need to be careful about what you do and how you share memory. The @@ -357,15 +359,15 @@ Strings and C strings The manual mentions that `Nim strings are implicitly convertible to cstrings `_ which makes interaction usually painless. Most C functions accepting a Nim string converted to a -``cstring`` will likely not need to keep this string around and by the time +`cstring` will likely not need to keep this string around and by the time they return the string won't be needed anymore. However, for the rare cases where a Nim string has to be preserved and made available to the C backend -as a ``cstring``, you will need to manually prevent the string data from being +as a `cstring`, you will need to manually prevent the string data from being freed with `GC_ref `_ and `GC_unref `_. A similar thing happens with C code invoking Nim code which returns a -``cstring``. Consider the following proc: +`cstring`. Consider the following proc: .. code-block:: nim @@ -373,8 +375,8 @@ A similar thing happens with C code invoking Nim code which returns a result = "Hey there C code! " & $rand(100) Since Nim's garbage collector is not aware of the C code, once the -``gimme`` proc has finished it can reclaim the memory of the ``cstring``. -However, from a practical standpoint, the C code invoking the ``gimme`` +`gimme` proc has finished it can reclaim the memory of the `cstring`. +However, from a practical standpoint, the C code invoking the `gimme` function directly will be able to use it since Nim's garbage collector has not had a chance to run *yet*. This gives you enough time to make a copy for the C side of the program, as calling any further Nim procs *might* trigger @@ -397,14 +399,14 @@ Again, if you are wrapping a library which *mallocs* and *frees* data structures, you need to expose the appropriate *free* function to Nim so you can clean it up. And of course, once cleaned you should avoid accessing it from Nim (or C for that matter). Typically C data structures have their own -``malloc_structure`` and ``free_structure`` specific functions, so wrapping +`malloc_structure` and `free_structure` specific functions, so wrapping these for the Nim side should be enough. Thread coordination ------------------- -When the ``NimMain()`` function is called Nim initializes the garbage +When the `NimMain()` function is called Nim initializes the garbage collector to the current thread, which is usually the main thread of your application. If your C code later spawns a different thread and calls Nim code, the garbage collector will fail to work properly and you will crash. diff --git a/doc/destructors.rst b/doc/destructors.rst index 4f06de455..01e2d2ee9 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ================================== Nim Destructors and Move Semantics ================================== @@ -16,7 +18,7 @@ not use classical GC algorithms anymore but is based on destructors and move semantics. The new runtime's advantages are that Nim programs become oblivious to the involved heap sizes and programs are easier to write to make effective use of multi-core machines. As a nice bonus, files and sockets and -the like will not require manual ``close`` calls anymore. +the like will not require manual `close` calls anymore. This document aims to be a precise specification about how move semantics and destructors work in Nim. @@ -89,12 +91,12 @@ written as: Lifetime-tracking hooks ======================= -The memory management for Nim's standard ``string`` and ``seq`` types as +The memory management for Nim's standard `string` and `seq` types as well as other standard collections is performed via so-called "Lifetime-tracking hooks", which are particular `type bound operators `_. -There are 3 different hooks for each (generic or concrete) object type ``T`` (``T`` can also be a -``distinct`` type) that are called implicitly by the compiler. +There are 3 different hooks for each (generic or concrete) object type `T` (`T` can also be a +`distinct` type) that are called implicitly by the compiler. (Note: The word "hook" here does not imply any kind of dynamic binding or runtime indirections, the implicit calls are statically bound and @@ -109,14 +111,14 @@ other associated resources. Variables are destroyed via this hook when they go out of scope or when the routine they were declared in is about to return. -The prototype of this hook for a type ``T`` needs to be: +The prototype of this hook for a type `T` needs to be: .. code-block:: nim proc `=destroy`(x: var T) -The general pattern in ``=destroy`` looks like: +The general pattern in `=destroy` looks like: .. code-block:: nim @@ -133,20 +135,20 @@ The general pattern in ``=destroy`` looks like: A `=sink` hook moves an object around, the resources are stolen from the source and passed to the destination. It is ensured that the source's destructor does not free the resources afterward by setting the object to its default value -(the value the object's state started in). Setting an object ``x`` back to its -default value is written as ``wasMoved(x)``. When not provided the compiler +(the value the object's state started in). Setting an object `x` back to its +default value is written as `wasMoved(x)`. When not provided the compiler is using a combination of `=destroy` and `copyMem` instead. This is efficient hence users rarely need to implement their own `=sink` operator, it is enough to provide `=destroy` and `=copy`, compiler will take care of the rest. -The prototype of this hook for a type ``T`` needs to be: +The prototype of this hook for a type `T` needs to be: .. code-block:: nim proc `=sink`(dest: var T; source: T) -The general pattern in ``=sink`` looks like: +The general pattern in `=sink` looks like: .. code-block:: nim @@ -156,25 +158,25 @@ The general pattern in ``=sink`` looks like: dest.field = source.field -**Note**: ``=sink`` does not need to check for self-assignments. +**Note**: `=sink` does not need to check for self-assignments. How self-assignments are handled is explained later in this document. `=copy` hook --------------- -The ordinary assignment in Nim conceptually copies the values. The ``=copy`` hook -is called for assignments that couldn't be transformed into ``=sink`` +The ordinary assignment in Nim conceptually copies the values. The `=copy` hook +is called for assignments that couldn't be transformed into `=sink` operations. -The prototype of this hook for a type ``T`` needs to be: +The prototype of this hook for a type `T` needs to be: .. code-block:: nim proc `=copy`(dest: var T; source: T) -The general pattern in ``=copy`` looks like: +The general pattern in `=copy` looks like: .. code-block:: nim @@ -186,48 +188,48 @@ The general pattern in ``=copy`` looks like: dest.field = duplicateResource(source.field) -The ``=copy`` proc can be marked with the ``{.error.}`` pragma. Then any assignment +The `=copy` proc can be marked with the `{.error.}` pragma. Then any assignment that otherwise would lead to a copy is prevented at compile-time. This looks like: .. code-block:: nim proc `=copy`(dest: var T; source: T) {.error.} -but a custom error message (e.g., ``{.error: "custom error".}``) will not be emitted -by the compiler. Notice that there is no ``=`` before the ``{.error.}`` pragma. +but a custom error message (e.g., `{.error: "custom error".}`) will not be emitted +by the compiler. Notice that there is no `=` before the `{.error.}` pragma. Move semantics ============== A "move" can be regarded as an optimized copy operation. If the source of the copy operation is not used afterward, the copy can be replaced by a move. This -document uses the notation ``lastReadOf(x)`` to describe that ``x`` is not +document uses the notation `lastReadOf(x)` to describe that `x` is not used afterwards. This property is computed by a static control flow analysis -but can also be enforced by using ``system.move`` explicitly. +but can also be enforced by using `system.move` explicitly. Swap ==== The need to check for self-assignments and also the need to destroy previous -objects inside ``=copy`` and ``=sink`` is a strong indicator to treat -``system.swap`` as a builtin primitive of its own that simply swaps every -field in the involved objects via ``copyMem`` or a comparable mechanism. -In other words, ``swap(a, b)`` is **not** implemented -as ``let tmp = move(b); b = move(a); a = move(tmp)``. +objects inside `=copy` and `=sink` is a strong indicator to treat +`system.swap` as a builtin primitive of its own that simply swaps every +field in the involved objects via `copyMem` or a comparable mechanism. +In other words, `swap(a, b)` is **not** implemented +as `let tmp = move(b); b = move(a); a = move(tmp)`. This has further consequences: * Objects that contain pointers that point to the same object are not supported by Nim's model. Otherwise swapped objects would end up in an inconsistent state. -* Seqs can use ``realloc`` in the implementation. +* Seqs can use `realloc` in the implementation. Sink parameters =============== -To move a variable into a collection usually ``sink`` parameters are involved. -A location that is passed to a ``sink`` parameter should not be used afterward. +To move a variable into a collection usually `sink` parameters are involved. +A location that is passed to a `sink` parameter should not be used afterward. This is ensured by a static analysis over a control flow graph. If it cannot be proven to be the last usage of the location, a copy is done instead and this copy is then passed to the sink parameter. @@ -235,9 +237,9 @@ copy is then passed to the sink parameter. A sink parameter *may* be consumed once in the proc's body but doesn't have to be consumed at all. The reason for this is that signatures -like ``proc put(t: var Table; k: sink Key, v: sink Value)`` should be possible -without any further overloads and ``put`` might not take ownership of ``k`` if -``k`` already exists in the table. Sink parameters enable an affine type system, +like `proc put(t: var Table; k: sink Key, v: sink Value)` should be possible +without any further overloads and `put` might not take ownership of `k` if +`k` already exists in the table. Sink parameters enable an affine type system, not a linear type system. The employed static analysis is limited and only concerned with local variables; @@ -254,7 +256,7 @@ however, object and tuple fields are treated as separate entities: echo tup[1] -Sometimes it is required to explicitly ``move`` a value into its final position: +Sometimes it is required to explicitly `move` a value into its final position: .. code-block:: nim @@ -294,9 +296,9 @@ Rewrite rules **Note**: There are two different allowed implementation strategies: -1. The produced ``finally`` section can be a single section that is wrapped +1. The produced `finally` section can be a single section that is wrapped around the complete routine body. -2. The produced ``finally`` section is wrapped around the enclosing scope. +2. The produced `finally` section is wrapped around the enclosing scope. The current implementation follows strategy (2). This means that resources are destroyed at the scope exit. @@ -359,13 +361,13 @@ Object and array construction ============================= Object and array construction is treated as a function call where the -function has ``sink`` parameters. +function has `sink` parameters. Destructor removal ================== -``wasMoved(x);`` followed by a `=destroy(x)` operation cancel each other +`wasMoved(x);` followed by a `=destroy(x)` operation cancel each other out. An implementation is encouraged to exploit this in order to improve efficiency and code sizes. The current implementation does perform this optimization. @@ -374,22 +376,22 @@ optimization. Self assignments ================ -``=sink`` in combination with ``wasMoved`` can handle self-assignments but +`=sink` in combination with `wasMoved` can handle self-assignments but it's subtle. -The simple case of ``x = x`` cannot be turned -into ``=sink(x, x); wasMoved(x)`` because that would lose ``x``'s value. +The simple case of `x = x` cannot be turned +into `=sink(x, x); wasMoved(x)` because that would lose `x`'s value. The solution is that simple self-assignments that consist of -- Symbols: ``x = x`` -- Field access: ``x.f = x.f`` -- Array, sequence or string access with indices known at compile-time: ``x[0] = x[0]`` +- Symbols: `x = x` +- Field access: `x.f = x.f` +- Array, sequence or string access with indices known at compile-time: `x[0] = x[0]` are transformed into an empty statement that does nothing. The compiler is free to optimize further cases. -The complex case looks like a variant of ``x = f(x)``, we consider -``x = select(rand() < 0.5, x, y)`` here: +The complex case looks like a variant of `x = f(x)`, we consider +`x = select(rand() < 0.5, x, y)` here: .. code-block:: nim @@ -450,17 +452,17 @@ self-assignments. Lent type ========= -``proc p(x: sink T)`` means that the proc ``p`` takes ownership of ``x``. +`proc p(x: sink T)` means that the proc `p` takes ownership of `x`. To eliminate even more creation/copy <-> destruction pairs, a proc's return -type can be annotated as ``lent T``. This is useful for "getter" accessors +type can be annotated as `lent T`. This is useful for "getter" accessors that seek to allow an immutable view into a container. -The ``sink`` and ``lent`` annotations allow us to remove most (if not all) +The `sink` and `lent` annotations allow us to remove most (if not all) superfluous copies and destructions. -``lent T`` is like ``var T`` a hidden pointer. It is proven by the compiler +`lent T` is like `var T` a hidden pointer. It is proven by the compiler that the pointer does not outlive its origin. No destructor call is injected -for expressions of type ``lent T`` or of type ``var T``. +for expressions of type `lent T` or of type `var T`. .. code-block:: nim @@ -494,9 +496,9 @@ for expressions of type ``lent T`` or of type ``var T``. The .cursor annotation ====================== -Under the ``--gc:arc|orc`` modes Nim's `ref` type is implemented via the same runtime +Under the `--gc:arc|orc` modes Nim's `ref` type is implemented via the same runtime "hooks" and thus via reference counting. This means that cyclic structures cannot be freed -immediately (``--gc:orc`` ships with a cycle collector). With the ``.cursor`` annotation +immediately (`--gc:orc` ships with a cycle collector). With the `.cursor` annotation one can break up cycles declaratively: .. code-block:: nim @@ -510,7 +512,7 @@ But please notice that this is not C++'s weak_ptr, it means the right field is n involved in the reference counting, it is a raw pointer without runtime checks. Automatic reference counting also has the disadvantage that it introduces overhead -when iterating over linked structures. The ``.cursor`` annotation can also be used +when iterating over linked structures. The `.cursor` annotation can also be used to avoid this overhead: .. code-block:: nim @@ -521,11 +523,11 @@ to avoid this overhead: it = it.next -In fact, ``.cursor`` more generally prevents object construction/destruction pairs +In fact, `.cursor` more generally prevents object construction/destruction pairs and so can also be useful in other contexts. The alternative solution would be to -use raw pointers (``ptr``) instead which is more cumbersome and also more dangerous -for Nim's evolution: Later on, the compiler can try to prove ``.cursor`` annotations -to be safe, but for ``ptr`` the compiler has to remain silent about possible +use raw pointers (`ptr`) instead which is more cumbersome and also more dangerous +for Nim's evolution: Later on, the compiler can try to prove `.cursor` annotations +to be safe, but for `ptr` the compiler has to remain silent about possible problems. @@ -556,13 +558,13 @@ indirections: Hook lifting ============ -The hooks of a tuple type ``(A, B, ...)`` are generated by lifting the -hooks of the involved types ``A``, ``B``, ... to the tuple type. In -other words, a copy ``x = y`` is implemented -as ``x[0] = y[0]; x[1] = y[1]; ...``, likewise for ``=sink`` and ``=destroy``. +The hooks of a tuple type `(A, B, ...)` are generated by lifting the +hooks of the involved types `A`, `B`, ... to the tuple type. In +other words, a copy `x = y` is implemented +as `x[0] = y[0]; x[1] = y[1]; ...`, likewise for `=sink` and `=destroy`. -Other value-based compound types like ``object`` and ``array`` are handled -correspondingly. For ``object`` however, the compiler-generated hooks +Other value-based compound types like `object` and `array` are handled +correspondingly. For `object` however, the compiler-generated hooks can be overridden. This can also be important to use an alternative traversal of the involved data structure that is more efficient or in order to avoid deep recursions. @@ -588,18 +590,18 @@ The ability to override a hook leads to a phase ordering problem: discard -The solution is to define ``proc `=destroy`[T](f: var Foo[T])`` before +The solution is to define `proc `=destroy`[T](f: var Foo[T])` before it is used. The compiler generates implicit hooks for all types in *strategic places* so that an explicitly provided hook that comes too "late" can be detected reliably. These *strategic places* have been derived from the rewrite rules and are as follows: -- In the construct ``let/var x = ...`` (var/let binding) - hooks are generated for ``typeof(x)``. -- In ``x = ...`` (assignment) hooks are generated for ``typeof(x)``. -- In ``f(...)`` (function call) hooks are generated for ``typeof(f(...))``. -- For every sink parameter ``x: sink T`` the hooks are generated - for ``typeof(x)``. +- In the construct `let/var x = ...` (var/let binding) + hooks are generated for `typeof(x)`. +- In `x = ...` (assignment) hooks are generated for `typeof(x)`. +- In `f(...)` (function call) hooks are generated for `typeof(f(...))`. +- For every sink parameter `x: sink T` the hooks are generated + for `typeof(x)`. nodestroy pragma @@ -645,20 +647,18 @@ Instead the variable simply points to the literal. The literal is shared between different variables which are pointing to it. The copy operation is deferred until the first write. -```nim -var x = "abc" # no copy -var y = x # no copy -``` +.. code-block:: nim + var x = "abc" # no copy + var y = x # no copy The string literal "abc" is stored in static memory and not allocated on the heap. The variable `x` points to the literal and the variable `y` points to the literal too. There is no copy during assigning operations. -```nim -var x = "abc" # no copy -var y = x # no copy -y[0] = 'h' # copy -``` +.. code-block:: nim + var x = "abc" # no copy + var y = x # no copy + y[0] = 'h' # copy The program above shows when the copy operations happen. When mutating the variable `y`, the Nim compiler creates a fresh copy of `x`, @@ -670,37 +670,34 @@ and the variable `y` becomes a mutable string. Let's look at a silly example demonstrating this behaviour: -```nim -var x = "abc" -var y = x +.. code-block:: nim + var x = "abc" + var y = x -moveMem(addr y[0], addr x[0], 3) -``` + moveMem(addr y[0], addr x[0], 3) The program fails because we need to prepare a fresh copy for the variable `y`. `prepareMutation` should be called before the address operation. -```nim -var x = "abc" -var y = x +.. code-block:: nim + var x = "abc" + var y = x -prepareMutation(y) -moveMem(addr y[0], addr x[0], 3) -assert y == "abc" -``` + prepareMutation(y) + moveMem(addr y[0], addr x[0], 3) + assert y == "abc" Now `prepareMutation` solves the problem. It manually creates a fresh copy and makes the variable `y` mutable. -```nim -var x = "abc" -var y = x +.. code-block:: nim + var x = "abc" + var y = x -prepareMutation(y) -moveMem(addr y[0], addr x[0], 3) -moveMem(addr y[0], addr x[0], 3) -moveMem(addr y[0], addr x[0], 3) -assert y == "abc" -``` + prepareMutation(y) + moveMem(addr y[0], addr x[0], 3) + moveMem(addr y[0], addr x[0], 3) + moveMem(addr y[0], addr x[0], 3) + assert y == "abc" No matter how many times `moveMem` is called, the program compiles and runs. diff --git a/doc/docgen.rst b/doc/docgen.rst index e383bd8d0..c002ddb83 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== Nim DocGen Tools Guide =================================== @@ -15,7 +17,7 @@ This document describes the `documentation generation tools`:idx: built into the `Nim compiler `_, which can generate HTML and JSON output from input .nim files and projects, as well as HTML and LaTeX from input RST (reStructuredText) files. The output documentation will include the module -dependencies (``import``), any top-level documentation comments (##), and +dependencies (`import`), any top-level documentation comments (##), and exported symbols (*), including procedures, types, and variables. Quick start @@ -125,12 +127,12 @@ Document Types HTML ---- -The generation of HTML documents is done via the ``doc`` command. This command +The generation of HTML documents is done via the `doc` command. This command takes either a single .nim file, outputting a single .html file with the same base filename, or multiple .nim files, outputting multiple .html files and, optionally, an index file. -The ``doc`` command:: +The `doc` command:: nim doc sample Partial Output:: @@ -146,12 +148,12 @@ compiler. JSON ---- -The generation of JSON documents is done via the ``jsondoc`` command. This command +The generation of JSON documents is done via the `jsondoc` command. This command takes in a .nim file and outputs a .json file with the same base filename. Note -that this tool is built off of the ``doc`` command (previously ``doc2``), and +that this tool is built off of the `doc` command (previously `doc2`), and contains the same information. -The ``jsondoc`` command:: +The `jsondoc` command:: nim jsondoc sample Output:: @@ -171,10 +173,10 @@ Output:: ] } -Similarly to the old ``doc`` command, the old ``jsondoc`` command has been -renamed to ``jsondoc0``. +Similarly to the old `doc` command, the old `jsondoc` command has been +renamed to `jsondoc0`. -The ``jsondoc0`` command:: +The `jsondoc0` command:: nim jsondoc0 sample Output:: @@ -190,8 +192,8 @@ Output:: } ] -Note that the ``jsondoc`` command outputs it's JSON without pretty-printing it, -while ``jsondoc0`` outputs pretty-printed JSON. +Note that the `jsondoc` command outputs it's JSON without pretty-printing it, +while `jsondoc0` outputs pretty-printed JSON. Related Options =============== @@ -203,7 +205,7 @@ Project switch nim doc --project filename.nim This will recursively generate documentation of all nim modules imported -into the input module that belong to the Nimble package that ``filename.nim`` +into the input module that belong to the Nimble package that `filename.nim` belongs to. @@ -214,13 +216,13 @@ Index switch nim doc --index:on filename.nim This will generate an index of all the exported symbols in the input Nim -module, and put it into a neighboring file with the extension of ``.idx``. The +module, and put it into a neighboring file with the extension of `.idx`. The index file is line-oriented (newlines have to be escaped). Each line represents a tab-separated record of several columns, the first two mandatory, the rest optional. See the `Index (idx) file format`_ section for details. Once index files have been generated for one or more modules, the Nim -compiler command ``buildIndex directory`` can be run to go over all the index +compiler command `buildIndex directory` can be run to go over all the index files in the specified directory to generate a `theindex.html `_ file. @@ -230,28 +232,28 @@ See source switch :: nim doc --git.url: filename.nim -With the ``git.url`` switch the *See source* hyperlink will appear below each +With the `git.url` switch the *See source* hyperlink will appear below each documented item in your source code pointing to the implementation of that item on a GitHub repository. You can click the link to see the implementation of the item. -The ``git.commit`` switch overrides the hardcoded `devel` branch in config/nimdoc.cfg. +The `git.commit` switch overrides the hardcoded `devel` branch in config/nimdoc.cfg. This is useful to link to a different branch e.g. `--git.commit:master`, or to a tag e.g. `--git.commit:1.2.3` or a commit. Source URLs are generated as `href="${url}/tree/${commit}/${path}#L${line}"` by default and this compatible with GitHub but not with GitLab. -Similarly, ``git.devel`` switch overrides the hardcoded `devel` branch for the `Edit` link which is also useful if you have a different working branch than `devel` e.g. `--git.devel:master`. +Similarly, `git.devel` switch overrides the hardcoded `devel` branch for the `Edit` link which is also useful if you have a different working branch than `devel` e.g. `--git.devel:master`. Edit URLs are generated as `href="${url}/tree/${devel}/${path}#L${line}"` by default. -You can edit ``config/nimdoc.cfg`` and modify the ``doc.item.seesrc`` value with a hyperlink to your own code repository. +You can edit `config/nimdoc.cfg` and modify the `doc.item.seesrc` value with a hyperlink to your own code repository. -In the case of Nim's own documentation, the ``commit`` value is just a commit +In the case of Nim's own documentation, the `commit` value is just a commit hash to append to a formatted URL to https://github.com/nim-lang/Nim. The -``tools/nimweb.nim`` helper queries the current git commit hash during the doc +`tools/nimweb.nim` helper queries the current git commit hash during the doc generation, but since you might be working on an unpublished repository, it -also allows specifying a ``githash`` value in ``web/website.ini`` to force a +also allows specifying a `githash` value in `web/website.ini` to force a specific commit in the output. @@ -259,9 +261,9 @@ Other Input Formats =================== The *Nim compiler* also has support for RST (reStructuredText) files with -the ``rst2html`` and ``rst2tex`` commands. Documents like this one are +the `rst2html` and `rst2tex` commands. Documents like this one are initially written in a dialect of RST which adds support for nim source code -highlighting with the ``.. code-block:: nim`` prefix. ``code-block`` also +highlighting with the `.. code-block:: nim` prefix. `code-block` also supports highlighting of C++ and some other c-like languages. Usage:: @@ -270,17 +272,17 @@ Usage:: Output:: You're reading it! -The ``rst2tex`` command is invoked identically to ``rst2html``, but outputs +The `rst2tex` command is invoked identically to `rst2html`, but outputs a .tex file instead of .html. HTML anchor generation ====================== -When you run the ``rst2html`` command, all sections in the RST document will +When you run the `rst2html` command, all sections in the RST document will get an anchor you can hyperlink to. Usually, you can guess the anchor lower casing the section title and replacing spaces with dashes, and in any case, you -can get it from the table of contents. But when you run the ``doc`` +can get it from the table of contents. But when you run the `doc` command to generate API documentation, some symbol get one or two anchors at the same time: a numerical identifier, or a plain name plus a complex name. @@ -312,31 +314,31 @@ suffix may be added depending on the type of the callable: Callable type Suffix ------------- -------------- proc *empty string* -macro ``.m`` -method ``.e`` -iterator ``.i`` -template ``.t`` -converter ``.c`` +macro `.m` +method `.e` +iterator `.i` +template `.t` +converter `.c` ------------- -------------- -The relationship of type to suffix is made by the proc ``complexName`` in the -``compiler/docgen.nim`` file. Here are some examples of complex names for +The relationship of type to suffix is made by the proc `complexName` in the +`compiler/docgen.nim` file. Here are some examples of complex names for symbols in the `system module `_. -* ``type SomeSignedInt = int | int8 | int16 | int32 | int64`` **=>** +* `type SomeSignedInt = int | int8 | int16 | int32 | int64` **=>** `#SomeSignedInt `_ -* ``var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}`` **=>** +* `var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}` **=>** `#globalRaiseHook `_ -* ``const NimVersion = "0.0.0"`` **=>** +* `const NimVersion = "0.0.0"` **=>** `#NimVersion `_ -* ``proc getTotalMem(): int {.rtl, raises: [], tags: [].}`` **=>** +* `proc getTotalMem(): int {.rtl, raises: [], tags: [].}` **=>** `#getTotalMem, `_ -* ``proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}`` **=>** +* `proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}` **=>** `#len,seq[T] `_ -* ``iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}`` **=>** +* `iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}` **=>** `#pairs.i,seq[T] `_ -* ``template newException[](exceptn: typedesc; message: string; - parentException: ref Exception = nil): untyped`` **=>** +* `template newException[](exceptn: typedesc; message: string; + parentException: ref Exception = nil): untyped` **=>** `#newException.t,typedesc,string,ref.Exception `_ @@ -344,13 +346,13 @@ symbols in the `system module `_. Index (idx) file format ======================= -Files with the ``.idx`` extension are generated when you use the `Index +Files with the `.idx` extension are generated when you use the `Index switch <#related-options-index-switch>`_ along with commands to generate documentation from source or text files. You can programmatically generate indices with the `setIndexTerm() `_ and `writeIndexFile() `_ procs. -The purpose of ``idx`` files is to hold the interesting symbols and their HTML +The purpose of `idx` files is to hold the interesting symbols and their HTML references so they can be later concatenated into a big index file with `mergeIndexes() `_. This section documents the file format in detail. @@ -362,7 +364,7 @@ columns is: 1. Mandatory term being indexed. Terms can include quoting according to Nim's rules (e.g. \`^\`). -2. Base filename plus anchor hyperlink (e.g. ``algorithm.html#*,int,SortOrder``). +2. Base filename plus anchor hyperlink (e.g. `algorithm.html#*,int,SortOrder`). 3. Optional human-readable string to display as a hyperlink. If the value is not present or is the empty string, the hyperlink will be rendered using the term. Prefix whitespace indicates that this entry is @@ -371,8 +373,8 @@ columns is: this as a tooltip after hovering a moment over the hyperlink. The index generation tools try to differentiate between documentation -generated from ``.nim`` files and documentation generated from ``.txt`` or -``.rst`` files. The former are always closely related to source code and +generated from `.nim` files and documentation generated from `.txt` or +`.rst` files. The former are always closely related to source code and consist mainly of API entries. The latter are generic documents meant for human reading. @@ -391,7 +393,7 @@ the index file with their third column having as much prefix spaces as their level is in the TOC (at least 1 character). The prefix whitespace helps to filter TOC entries from API or text symbols. This is important because the amount of spaces is used to replicate the hierarchy for document TOCs in the -final index, and TOC entries found in ``.nim`` files are discarded. +final index, and TOC entries found in `.nim` files are discarded. Additional resources @@ -402,8 +404,8 @@ Additional resources `RST Quick Reference `_ -The output for HTML and LaTeX comes from the ``config/nimdoc.cfg`` and -``config/nimdoc.tex.cfg`` configuration files. You can add and modify these +The output for HTML and LaTeX comes from the `config/nimdoc.cfg` and +`config/nimdoc.tex.cfg` configuration files. You can add and modify these files to your project to change the look of the docgen output. You can import the `packages/docutils/rstgen module `_ in your diff --git a/doc/docstyle.rst b/doc/docstyle.rst index 090032b98..7f3fa8cf2 100644 --- a/doc/docstyle.rst +++ b/doc/docstyle.rst @@ -6,7 +6,7 @@ General Guidelines * See also `nep1`_ which should probably be merged here. * Authors should document anything that is exported; documentation for private - procs can be useful too (visible via ``nim doc --docInternal foo.nim``). + procs can be useful too (visible via `nim doc --docInternal foo.nim`). * Within documentation, a period (`.`) should follow each sentence (or sentence fragment) in a comment block. The documentation may be limited to one sentence fragment, but if multiple sentences are within the documentation, each sentence after the first should be complete and in present tense. @@ -15,7 +15,7 @@ General Guidelines and `nim doc` supports it. Likewise with rst files: `nim rst2html` will render those as monospace, and adding `.. default-role:: code` to an rst file will also make those render as monospace when rendered directly in tools such as github. -* In nim sources, for links, prefer `[link text](link.html)` to ``` `link text`_ ``` +* In nim sources, for links, prefer `[link text](link.html)` to `` `link text`_ `` since the syntax is simpler and markdown is more common (likewise, `nim rst2html` also supports it in rst files). .. code-block:: nim @@ -28,8 +28,8 @@ General Guidelines Module-level documentation -------------------------- -Documentation of a module is placed at the top of the module itself. Each line of documentation begins with double hashes (``##``). -Sometimes ``##[ multiline docs containing code ]##`` is preferable, see ``lib/pure/times.nim``. +Documentation of a module is placed at the top of the module itself. Each line of documentation begins with double hashes (`##`). +Sometimes `##[ multiline docs containing code ]##` is preferable, see `lib/pure/times.nim`. Code samples are encouraged, and should follow the general RST syntax: .. code-block:: Nim @@ -80,7 +80,7 @@ Whenever an example of usage would be helpful to the user, you should include on doAssert addThree(3, 125, 6) == -122 result = x +% y +% z -The command ``nim doc`` will then correctly syntax highlight the Nim code within the documentation. +The command `nim doc` will then correctly syntax highlight the Nim code within the documentation. Types ----- @@ -116,8 +116,8 @@ Make sure to place the documentation beside or within the object. .. code-block:: Nim type - ## Bad: this documentation disappears because it annotates the ``type`` keyword - ## above, not ``NamedQueue``. + ## Bad: this documentation disappears because it annotates the `type` keyword + ## above, not `NamedQueue`. NamedQueue*[T] = object name*: string ## This becomes the main documentation for the object, which ## is not what we want. @@ -127,7 +127,7 @@ Make sure to place the documentation beside or within the object. Var, Let, and Const ------------------- -When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the ``type`` sections. +When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the `type` sections. .. code-block:: Nim @@ -137,9 +137,9 @@ When declaring module-wide constants and values, documentation is encouraged. Th [1,2,3], [2,3,1], [3,1,2], - ] ## Doc comment for ``SpreadArray``. + ] ## Doc comment for `SpreadArray`. -Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (``#``). +Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (`#`). .. code-block:: Nim diff --git a/doc/drnim.rst b/doc/drnim.rst index ee6e0ea17..d33a6066e 100644 --- a/doc/drnim.rst +++ b/doc/drnim.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== DrNim User Guide =================================== @@ -18,7 +20,7 @@ DrNim's command-line options are the same as the Nim compiler's. DrNim currently only checks the sections of your code that are marked -via ``staticBoundChecks: on``: +via `staticBoundChecks: on`: .. code-block:: nim @@ -31,9 +33,9 @@ overflow errors are *not* prevented. Overflows will be checked for in the future. Later versions of the **Nim compiler** will **assume** that the checks inside -the ``staticBoundChecks: on`` environment have been proven correct and so +the `staticBoundChecks: on` environment have been proven correct and so it will **omit** the runtime checks. If you do not want this behavior, use -instead ``{.push staticBoundChecks: defined(nimDrNim).}``. This way the +instead `{.push staticBoundChecks: defined(nimDrNim).}`. This way the Nim compiler remains unaware of the performed proofs but DrNim will prove your code. @@ -41,7 +43,7 @@ your code. Installation ============ -Run ``koch drnim``, the executable will afterwards be in ``$nim/bin/drnim``. +Run `koch drnim`, the executable will afterwards be in `$nim/bin/drnim`. Motivating Example @@ -67,7 +69,7 @@ detects it and produces the following error message:: cannot prove: i <= len(a) + -1; counter example: i -> 0 a.len -> 0 [IndexCheck] -In other words for ``i == 0`` and ``a.len == 0`` (for example!) there would be +In other words for `i == 0` and `a.len == 0` (for example!) there would be an index out of bounds error. @@ -82,37 +84,37 @@ DrNim adds 4 additional annotations (pragmas) to Nim: - `assume`:idx: These pragmas are ignored by the Nim compiler so that they don't have to -be disabled via ``when defined(nimDrNim)``. +be disabled via `when defined(nimDrNim)`. Invariant --------- -An ``invariant`` is a proposition that must be true after every loop +An `invariant` is a proposition that must be true after every loop iteration, it's tied to the loop body it's part of. Requires -------- -A ``requires`` annotation describes what the function expects to be true -before it's called so that it can perform its operation. A ``requires`` +A `requires` annotation describes what the function expects to be true +before it's called so that it can perform its operation. A `requires` annotation is also called a `precondition`:idx:. Ensures ------- -An ``ensures`` annotation describes what will be true after the function -call. An ``ensures`` annotation is also called a `postcondition`:idx:. +An `ensures` annotation describes what will be true after the function +call. An `ensures` annotation is also called a `postcondition`:idx:. Assume ------ -An ``assume`` annotation describes what DrNim should **assume** to be true +An `assume` annotation describes what DrNim should **assume** to be true in this section of the program. It is an unsafe escape mechanism comparable -to Nim's ``cast`` statement. Use it only when you really know better +to Nim's `cast` statement. Use it only when you really know better than DrNim. You should add a comment to a paper that proves the proposition you assume. @@ -143,12 +145,12 @@ Example: insertionSort Unfortunately, the invariants required to prove that this code is correct take more code than the imperative instructions. However, this effort can be compensated by the fact that the result needs very little testing. Be aware though that -DrNim only proves that after ``insertionSort`` this condition holds:: +DrNim only proves that after `insertionSort` this condition holds:: forall(i in 1..``. -A ``prop`` is either a comparison or a compound:: +The basic syntax is `ensures|requires|invariant: `. +A `prop` is either a comparison or a compound:: prop = nim_bool_expression | prop 'and' prop @@ -186,17 +188,17 @@ A ``prop`` is either a comparison or a compound:: quantifier = 'in' nim_iteration_expression -``nim_iteration_expression`` here is an ordinary expression of Nim code -that describes an iteration space, for example ``1..4`` or ``1.. a.len``. +`nim_bool_expression` here is an ordinary expression of Nim code of +type `bool` like `a == 3` or `23 > a.len`. The supported subset of Nim code that can be used in these expressions -is currently underspecified but ``let`` variables, function parameters -and ``result`` (which represents the function's final result) are amenable +is currently underspecified but `let` variables, function parameters +and `result` (which represents the function's final result) are amenable for verification. The expressions must not have any side-effects and must terminate. -The operators ``forall``, ``exists``, ``->``, ``<->`` have to imported -from ``std / logic``. +The operators `forall`, `exists`, `->`, `<->` have to imported +from `std / logic`. diff --git a/doc/estp.rst b/doc/estp.rst index 805a84eb7..8146562b6 100644 --- a/doc/estp.rst +++ b/doc/estp.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================================== Embedded Stack Trace Profiler (ESTP) User Guide =================================================== @@ -10,21 +12,21 @@ Nim comes with a platform independent profiler - the Embedded Stack Trace Profiler (ESTP). The profiler is *embedded* into your executable. To activate the profiler you need to do: -* compile your program with the ``--profiler:on --stackTrace:on`` command +* compile your program with the `--profiler:on --stackTrace:on` command line options -* import the ``nimprof`` module +* import the `nimprof` module * run your program as usual. -You can in fact look at ``nimprof``'s source code to see how to implement +You can in fact look at `nimprof`'s source code to see how to implement your own profiler. -The setting ``--profiler:on`` defines the conditional symbol ``profiler``. +The setting `--profiler:on` defines the conditional symbol `profiler`. After your program has finished the profiler will create a -file ``profile_results.txt`` containing the profiling results. +file `profile_results.txt` containing the profiling results. Since the profiler works by examining stack traces, it's essential that -the option ``--stackTrace:on`` is active! Unfortunately this means that a +the option `--stackTrace:on` is active! Unfortunately this means that a profiling build is much slower than a release build. @@ -35,12 +37,12 @@ You can also use ESTP as a memory profiler to see which stack traces allocate the most memory and thus create the most GC pressure. It may also help to find memory leaks. To activate the memory profiler you need to do: -* compile your program with the ``--profiler:off --stackTrace:on -d:memProfiler`` - command line options. Yes it's ``--profiler:off``. -* import the ``nimprof`` module +* compile your program with the `--profiler:off --stackTrace:on -d:memProfiler` + command line options. Yes it's `--profiler:off`. +* import the `nimprof` module * run your program as usual. -Define the symbol ``ignoreAllocationSize`` so that only the number of +Define the symbol `ignoreAllocationSize` so that only the number of allocations is counted and the sizes of the memory allocations do not matter. @@ -51,7 +53,7 @@ The results file lists stack traces ordered by significance. The following example file has been generated by profiling the Nim compiler itself: It shows that in total 5.4% of the runtime has been spent -in ``crcFromRope`` or its children. +in `crcFromRope` or its children. In general the stack traces show you immediately where the problem is because the trace acts like an explanation; in traditional profilers you can only find diff --git a/doc/filters.rst b/doc/filters.rst index 40346ecaf..52704411f 100644 --- a/doc/filters.rst +++ b/doc/filters.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================== Source Code Filters =================== @@ -8,7 +10,7 @@ A `Source Code Filter (SCF)` transforms the input character stream to an in-mem output stream before parsing. A filter can be used to provide templating systems or preprocessors. -To use a filter for a source file the ``#?`` notation is used:: +To use a filter for a source file the `#?` notation is used:: #? stdtmpl(subsChar = '$', metaChar = '#') #proc generateXML(name, age: string): string = @@ -21,9 +23,9 @@ To use a filter for a source file the ``#?`` notation is used:: As the example shows, passing arguments to a filter can be done just like an ordinary procedure call with named or positional arguments. The available parameters depend on the invoked filter. Before version 0.12.0 of -the language ``#!`` was used instead of ``#?``. +the language `#!` was used instead of `#?`. -**Hint:** With ``--hint[codeBegin]:on`` or ``--verbosity:2`` +**Hint:** With `--hint[codeBegin]:on` or `--verbosity:2` (or higher) while compiling or `nim check`, Nim lists the processed code after each filter application. @@ -32,8 +34,8 @@ Usage First, put your SCF code in a separate file with filters specified in the first line. **Note:** You can name your SCF file with any file extension you want, but the -conventional extension is ``.nimf`` -(it used to be ``.tmpl`` but that was too generic, for example preventing github to +conventional extension is `.nimf` +(it used to be `.tmpl` but that was too generic, for example preventing github to recognize it as Nim source file). If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf` @@ -47,7 +49,7 @@ In your `main.nim`: Pipe operator ============= -Filters can be combined with the ``|`` pipe operator:: +Filters can be combined with the `|` pipe operator:: #? strip(startswith="<") | stdtmpl #proc generateXML(name, age: string): string = @@ -68,10 +70,10 @@ The replace filter replaces substrings in each line. Parameters and their defaults: - ``sub: string = ""`` + `sub: string = ""` the substring that is searched for - ``by: string = ""`` + `by: string = ""` the string the substring is replaced with @@ -83,14 +85,14 @@ each line. Parameters and their defaults: - ``startswith: string = ""`` + `startswith: string = ""` strip only the lines that start with *startswith* (ignoring leading whitespace). If empty every line is stripped. - ``leading: bool = true`` + `leading: bool = true` strip leading whitespace - ``trailing: bool = true`` + `trailing: bool = true` strip trailing whitespace @@ -99,25 +101,25 @@ StdTmpl filter The stdtmpl filter provides a simple templating engine for Nim. The filter uses a line based parser: Lines prefixed with a *meta character* -(default: ``#``) contain Nim code, other lines are verbatim. Because +(default: `#`) contain Nim code, other lines are verbatim. Because indentation-based parsing is not suited for a templating engine, control flow -statements need ``end X`` delimiters. +statements need `end X` delimiters. Parameters and their defaults: - ``metaChar: char = '#'`` + `metaChar: char = '#'` prefix for a line that contains Nim code - ``subsChar: char = '$'`` + `subsChar: char = '$'` prefix for a Nim expression within a template line - ``conc: string = " & "`` + `conc: string = " & "` the operation for concatenation - ``emit: string = "result.add"`` + `emit: string = "result.add"` the operation to emit a string literal - ``toString: string = "$"`` + `toString: string = "$"` the operation that is applied to each expression Example:: @@ -174,18 +176,18 @@ The filter transforms this into: Each line that does not start with the meta character (ignoring leading -whitespace) is converted to a string literal that is added to ``result``. +whitespace) is converted to a string literal that is added to `result`. The substitution character introduces a Nim expression *e* within the string literal. *e* is converted to a string with the *toString* operation -which defaults to ``$``. For strong type checking, set ``toString`` to the +which defaults to `$`. For strong type checking, set `toString` to the empty string. *e* must match this PEG pattern:: e <- [a-zA-Z\128-\255][a-zA-Z0-9\128-\255_.]* / '{' x '}' x <- '{' x+ '}' / [^}]* -To produce a single substitution character it has to be doubled: ``$$`` -produces ``$``. +To produce a single substitution character it has to be doubled: `$$` +produces `$`. The template engine is quite flexible. It is easy to produce a procedure that writes the template code directly to a file:: diff --git a/doc/gc.rst b/doc/gc.rst index 29b9a4131..4455afcbe 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ======================= Nim's Memory Management ======================= @@ -27,37 +29,37 @@ and how the memory management strategies other than garbage collectors work. Multi-paradigm Memory Management Strategies =========================================== -To choose the memory management strategy use the ``--gc:`` switch. +To choose the memory management strategy use the `--gc:` switch. -- ``--gc:refc``. This is the default GC. It's a +- `--gc:refc`. This is the default GC. It's a deferred reference counting based garbage collector with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. -- ``--gc:markAndSweep``. Simple Mark-And-Sweep based garbage collector. Heaps are thread-local. -- ``--gc:boehm``. Boehm based garbage collector, it offers a shared heap. -- ``--gc:go``. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. -- ``--gc:arc``. Plain reference counting with +- `--gc:markAndSweep`. Simple Mark-And-Sweep based garbage collector. Heaps are thread-local. +- `--gc:boehm`. Boehm based garbage collector, it offers a shared heap. +- `--gc:go`. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. +- `--gc:arc`. Plain reference counting with `move semantic optimizations `_, offers a shared heap. It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles cause memory leaks, beware. -- ``--gc:orc``. Same as ``--gc:arc`` but adds a cycle collector based on "trial deletion". +- `--gc:orc`. Same as `--gc:arc` but adds a cycle collector based on "trial deletion". Unfortunately, that makes its performance profile hard to reason about so it is less useful for hard real-time systems. -- ``--gc:none``. No memory management strategy nor a garbage collector. Allocated memory is - simply never freed. You should use ``--gc:arc`` instead. +- `--gc:none`. No memory management strategy nor a garbage collector. Allocated memory is + simply never freed. You should use `--gc:arc` instead. ================== ======== ================= ============== =================== Memory Management Heap Reference Cycles Stop-The-World Command line switch ================== ======== ================= ============== =================== -RefC Local Cycle Collector No ``--gc:refc`` -Mark & Sweep Local Cycle Collector No ``--gc:markAndSweep`` -ARC Shared Leak No ``--gc:arc`` -ORC Shared Cycle Collector No ``--gc:orc`` -Boehm Shared Cycle Collector Yes ``--gc:boehm`` -Go Shared Cycle Collector Yes ``--gc:go`` -None Manual Manual Manual ``--gc:none`` +RefC Local Cycle Collector No `--gc:refc` +Mark & Sweep Local Cycle Collector No `--gc:markAndSweep` +ARC Shared Leak No `--gc:arc` +ORC Shared Cycle Collector No `--gc:orc` +Boehm Shared Cycle Collector Yes `--gc:boehm` +Go Shared Cycle Collector Yes `--gc:go` +None Manual Manual Manual `--gc:none` ================== ======== ================= ============== =================== JavaScript's garbage collector is used for the `JavaScript and NodeJS @@ -73,14 +75,14 @@ Cycle collector --------------- The cycle collector can be en-/disabled independently from the other parts of -the garbage collector with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. +the garbage collector with `GC_enableMarkAndSweep` and `GC_disableMarkAndSweep`. Soft real-time support ---------------------- To enable real-time support, the symbol `useRealtimeGC`:idx: needs to be -defined via ``--define:useRealtimeGC`` (you can put this into your config +defined via `--define:useRealtimeGC` (you can put this into your config file as well). With this switch the garbage collector supports the following operations: @@ -88,29 +90,29 @@ With this switch the garbage collector supports the following operations: proc GC_setMaxPause*(maxPauseInUs: int) proc GC_step*(us: int, strongAdvice = false, stackSize = -1) -The unit of the parameters ``maxPauseInUs`` and ``us`` is microseconds. +The unit of the parameters `maxPauseInUs` and `us` is microseconds. These two procs are the two modus operandi of the real-time garbage collector: (1) GC_SetMaxPause Mode - You can call ``GC_SetMaxPause`` at program startup and then each triggered - garbage collector run tries to not take longer than ``maxPause`` time. However, it is + You can call `GC_SetMaxPause` at program startup and then each triggered + garbage collector run tries to not take longer than `maxPause` time. However, it is possible (and common) that the work is nevertheless not evenly distributed - as each call to ``new`` can trigger the garbage collector and thus take ``maxPause`` + as each call to `new` can trigger the garbage collector and thus take `maxPause` time. (2) GC_step Mode - This allows the garbage collector to perform some work for up to ``us`` time. + This allows the garbage collector to perform some work for up to `us` time. This is useful to call in the main loop to ensure the garbage collector can do its work. - To bind all garbage collector activity to a ``GC_step`` call, - deactivate the garbage collector with ``GC_disable`` at program startup. - If ``strongAdvice`` is set to ``true``, + To bind all garbage collector activity to a `GC_step` call, + deactivate the garbage collector with `GC_disable` at program startup. + If `strongAdvice` is set to `true`, then the garbage collector will be forced to perform the collection cycle. Otherwise, the garbage collector may decide not to do anything, if there is not much garbage to collect. - You may also specify the current stack size via ``stackSize`` parameter. + You may also specify the current stack size via `stackSize` parameter. It can improve performance when you know that there are no unique Nim references below a certain point on the stack. Make sure the size you specify is greater than the potential worst-case size. @@ -130,16 +132,16 @@ Time measurement with garbage collectors ---------------------------------------- The garbage collectors' way of measuring time uses -(see ``lib/system/timers.nim`` for the implementation): +(see `lib/system/timers.nim` for the implementation): -1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. -2) ``mach_absolute_time`` on Mac OS X. -3) ``gettimeofday`` on Posix systems. +1) `QueryPerformanceCounter` and `QueryPerformanceFrequency` on Windows. +2) `mach_absolute_time` on Mac OS X. +3) `gettimeofday` on Posix systems. As such it supports a resolution of nanoseconds internally; however, the API uses microseconds for convenience. -Define the symbol ``reportMissedDeadlines`` to make the +Define the symbol `reportMissedDeadlines` to make the garbage collector output whenever it missed a deadline. The reporting will be enhanced and supported by the API in later versions of the collector. @@ -148,9 +150,9 @@ Tweaking the garbage collector ------------------------------ The collector checks whether there is still time left for its work after -every ``workPackage``'th iteration. This is currently set to 100 which means +every `workPackage`'th iteration. This is currently set to 100 which means that up to 100 objects are traversed and freed before it checks again. Thus -``workPackage`` affects the timing granularity and may need to be tweaked in +`workPackage` affects the timing granularity and may need to be tweaked in highly specialized environments or for older hardware. @@ -158,22 +160,22 @@ Keeping track of memory ======================= If you need to pass around memory allocated by Nim to C, you can use the -procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them +procs `GC_ref` and `GC_unref` to mark objects as referenced to avoid them being freed by the garbage collector. Other useful procs from `system `_ you can use to keep track of memory are: -* ``getTotalMem()`` Returns the amount of total memory managed by the garbage collector. -* ``getOccupiedMem()`` Bytes reserved by the garbage collector and used by objects. -* ``getFreeMem()`` Bytes reserved by the garbage collector and not in use. -* ``GC_getStatistics()`` Garbage collector statistics as a human-readable string. +* `getTotalMem()` Returns the amount of total memory managed by the garbage collector. +* `getOccupiedMem()` Bytes reserved by the garbage collector and used by objects. +* `getFreeMem()` Bytes reserved by the garbage collector and not in use. +* `GC_getStatistics()` Garbage collector statistics as a human-readable string. These numbers are usually only for the running thread, not for the whole heap, -with the exception of ``--gc:boehm`` and ``--gc:go``. +with the exception of `--gc:boehm` and `--gc:go`. -In addition to ``GC_ref`` and ``GC_unref`` you can avoid the garbage collector by manually -allocating memory with procs like ``alloc``, ``alloc0``, ``allocShared``, ``allocShared0`` or ``allocCStringArray``. +In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually +allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`. The garbage collector won't try to free them, you need to call their respective *dealloc* pairs -(``dealloc``, ``deallocShared``, ``deallocCStringArray``, etc) +(`dealloc`, `deallocShared`, `deallocCStringArray`, etc) when you are done with them or they will leak. @@ -182,12 +184,12 @@ Heap dump The heap dump feature is still in its infancy, but it already proved useful for us, so it might be useful for you. To get a heap dump, compile -with ``-d:nimTypeNames`` and call ``dumpNumberOfInstances`` at a strategic place in your program. +with `-d:nimTypeNames` and call `dumpNumberOfInstances` at a strategic place in your program. This produces a list of the used types in your program and for every type the total amount of object instances for this type as well as the total amount of bytes these instances take up. The numbers count the number of objects in all garbage collector heaps, they refer to all running threads, not only to the current thread. (The current thread -would be the thread that calls ``dumpNumberOfInstances``.) This might +would be the thread that calls `dumpNumberOfInstances`.) This might change in later versions. diff --git a/doc/hcr.rst b/doc/hcr.rst index 6dc65b1cd..7e9d71da3 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== Hot code reloading =================================== @@ -19,8 +21,8 @@ so we have to use a helper module where the major logic we want to change during development resides. In this example, we use SDL2 to create a window and we reload the logic -code when ``F9`` is pressed. The important lines are marked with ``#***``. -To install SDL2 you can use ``nimble install sdl2``. +code when `F9` is pressed. The important lines are marked with `#***`. +To install SDL2 you can use `nimble install sdl2`. .. code-block:: nim @@ -125,7 +127,7 @@ Then recompile the project, but do not restart or quit the mymain.exe program! nim c --hotcodereloading:on mymain.nim -Now give the ``mymain`` SDL window the focus, press F9, and watch the +Now give the `mymain` SDL window the focus, press F9, and watch the updated version of the program. @@ -133,8 +135,8 @@ updated version of the program. Reloading API ============= -One can use the special event handlers ``beforeCodeReload`` and -``afterCodeReload`` to reset the state of a particular variable or to force +One can use the special event handlers `beforeCodeReload` and +`afterCodeReload` to reset the state of a particular variable or to force the execution of certain statements: .. code-block:: Nim @@ -178,8 +180,8 @@ It's expected that most projects will implement the reloading with a suitable build-system triggered IPC notification mechanism, but a polling solution is also possible through the provided `hasAnyModuleChanged()`:idx: API. -In order to access ``beforeCodeReload``, ``afterCodeReload``, ``hasModuleChanged`` -or ``hasAnyModuleChanged`` one must import the `hotcodereloading`:idx: module. +In order to access `beforeCodeReload`, `afterCodeReload`, `hasModuleChanged` +or `hasAnyModuleChanged` one must import the `hotcodereloading`:idx: module. Native code targets @@ -187,11 +189,11 @@ Native code targets Native projects using the hot code reloading option will be implicitly compiled with the `-d:useNimRtl` option and they will depend on both -the ``nimrtl`` library and the ``nimhcr`` library which implements the -hot code reloading run-time. Both libraries can be found in the ``lib`` +the `nimrtl` library and the `nimhcr` library which implements the +hot code reloading run-time. Both libraries can be found in the `lib` folder of Nim and can be compiled into dynamic libraries to satisfy runtime demands of the example code above. An example of compiling -``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed +`nimhcr.nim` and `nimrtl.nim` when the source dir of Nim is installed with choosenim follows. :: @@ -208,16 +210,16 @@ with choosenim follows. # source directory (.dll for Windows, .so for Unix, .dylib for MacOS) All modules of the project will be compiled to separate dynamic link -libraries placed in the ``nimcache`` directory. Please note that during +libraries placed in the `nimcache` directory. Please note that during the execution of the program, the hot code reloading run-time will load only copies of these libraries in order to not interfere with any newly issued build commands. The main module of the program is considered non-reloadable. Please note that procs from reloadable modules should not appear in the call stack of -program while ``performCodeReload`` is being called. Thus, the main module +program while `performCodeReload` is being called. Thus, the main module is a suitable place for implementing a program loop capable of calling -``performCodeReload``. +`performCodeReload`. Please note that reloading won't be possible when any of the type definitions in the program has been changed. When closure iterators are used (directly or diff --git a/doc/idetools.rst b/doc/idetools.rst index 27926b14f..dcafaf45f 100644 --- a/doc/idetools.rst +++ b/doc/idetools.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ================================ Nim IDE Integration Guide ================================ @@ -18,8 +20,8 @@ Note: this is mostly outdated, see instead `nimsuggest `_ Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the -``idetools`` command of `the compiler `_, any IDE -can query a ``.nim`` source file and obtain useful information like +`idetools` command of `the compiler `_, any IDE +can query a `.nim` source file and obtain useful information like definition of symbols or suggestions for completion. This document will guide you through the available options. If you @@ -36,7 +38,7 @@ Specifying the location of the query ------------------------------------ All of the available idetools commands require you to specify a -query location through the ``--track`` or ``--trackDirty`` switches. +query location through the `--track` or `--trackDirty` switches. The general idetools invocations are:: nim idetools --track:FILE,LINE,COL proj.nim @@ -45,35 +47,35 @@ Or:: nim idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL proj.nim -``proj.nim`` +`proj.nim` This is the main *project* filename. Most of the time you will pass in the same as **FILE**, but for bigger projects this is the file which is used as main entry point for the program, the one which users compile to generate a final binary. -```` +`` This would be any of the other idetools available options, like - ``--def`` or ``--suggest`` explained in the following sections. + `--def` or `--suggest` explained in the following sections. -``COL`` +`COL` An integer with the column you are going to query. For the compiler columns start at zero, so the first column will be **0** and the last in an 80 column terminal will be **79**. -``LINE`` +`LINE` An integer with the line you are going to query. For the compiler lines start at **1**. -``FILE`` +`FILE` The file you want to perform the query on. Usually you will pass in the same value as **proj.nim**. -``DIRTY_FILE`` +`DIRTY_FILE` The **FILE** parameter is enough for static analysis, but IDEs tend to have *unsaved buffers* where the user may still be in the middle of typing a line. In such situations the IDE can save the current contents to a temporary file and then use the - ``--trackDirty`` switch. + `--trackDirty` switch. Dirty files are likely to contain errors and they are usually compiled partially only to the point needed to service the @@ -91,7 +93,7 @@ Or:: Definitions ----------- -The ``--def`` idetools switch performs a query about the definition +The `--def` idetools switch performs a query about the definition of a specific symbol. If available, idetools will answer with the type, source file, line/column information and other accessory data if available like a docstring. With this information an IDE can @@ -112,7 +114,7 @@ can't find any valid symbol matching the position of the query. Suggestions ----------- -The ``--suggest`` idetools switch performs a query about possible +The `--suggest` idetools switch performs a query about possible completion symbols at some point in the file. IDEs can easily provide an autocompletion feature where the IDE scans the current file (and related ones, if it knows about the language being edited and follows @@ -134,7 +136,7 @@ Idetools will try to return the suggestions sorted first by scope Invocation context ------------------ -The ``--context`` idetools switch is very similar to the suggestions +The `--context` idetools switch is very similar to the suggestions switch, but instead of being used after the user has typed a dot character, this one is meant to be used after the user has typed an opening brace to start typing parameters. @@ -143,7 +145,7 @@ an opening brace to start typing parameters. Symbol usages ------------- -The ``--usages`` idetools switch lists all usages of the symbol at +The `--usages` idetools switch lists all usages of the symbol at a position. IDEs can use this to find all the places in the file where the symbol is used and offer the user to rename it in all places at the same time. Again, a pure string based search and @@ -207,15 +209,15 @@ Idetools outputs is always returned on single lines separated by tab characters (``\t``). The values of each column are: 1. Three characters indicating the type of returned answer (e.g. - def for definition, ``sug`` for suggestion, etc). -2. Type of the symbol. This can be ``skProc``, ``skLet``, and just - about any of the enums defined in the module ``compiler/ast.nim``. + def for definition, `sug` for suggestion, etc). +2. Type of the symbol. This can be `skProc`, `skLet`, and just + about any of the enums defined in the module `compiler/ast.nim`. 3. Full qualified path of the symbol. If you are querying a symbol - defined in the ``proj.nim`` file, this would have the form - ``proj.symbolName``. + defined in the `proj.nim` file, this would have the form + `proj.symbolName`. 4. Type/signature. For variables and enums this will contain the type of the symbol, for procs, methods and templates this will - contain the full unique signature (e.g. ``proc (File)``). + contain the full unique signature (e.g. `proc (File)`). 5. Full path to the file containing the symbol. 6. Line where the symbol is located in the file. Lines start to count at **1**. @@ -374,8 +376,8 @@ While at the language level a method is differentiated from others by the parameters and return value, the signature of the method returned by idetools returns also the pragmas for the method. -Note that at the moment the word ``proc`` is returned for the -signature of the found method instead of the expected ``method``. +Note that at the moment the word `proc` is returned for the +signature of the found method instead of the expected `method`. This may change in the future. | **Third column**: module + [n scope nesting] + method name. @@ -517,7 +519,7 @@ Test suite ========== To verify that idetools is working properly there are files in the -``tests/caas/`` directory which provide unit testing. If you find +`tests/caas/` directory which provide unit testing. If you find odd idetools behaviour and are able to reproduce it, you are welcome to report it as a bug and add a test to the suite to avoid future regressions. @@ -533,27 +535,27 @@ run it manually. First you have to compile the tester:: $ cd my/nim/checkout/tests $ nim c testament/caasdriver.nim -Running the ``caasdriver`` without parameters will attempt to process +Running the `caasdriver` without parameters will attempt to process all the test cases in all three operation modes. If a test succeeds nothing will be printed and the process will exit with zero. If any test fails, the specific line of the test preceding the failure and the failure itself will be dumped to stdout, along with a final indicator of the success state and operation mode. You can pass the -parameter ``verbose`` to force all output even on successful tests. +parameter `verbose` to force all output even on successful tests. -The normal operation mode is called ``ProcRun`` and it involves +The normal operation mode is called `ProcRun` and it involves starting a process for each command or query, similar to running -manually the Nim compiler from the commandline. The ``CaasRun`` -mode starts a server process to answer all queries. The ``SymbolProcRun`` +manually the Nim compiler from the commandline. The `CaasRun` +mode starts a server process to answer all queries. The `SymbolProcRun` mode is used by compiler developers. This means that running all -tests involves processing all ``*.txt`` files three times, which +tests involves processing all `*.txt` files three times, which can be quite time consuming. If you don't want to run all the test case files you can pass any -substring as a parameter to ``caasdriver``. Only files matching the +substring as a parameter to `caasdriver`. Only files matching the passed substring will be run. The filtering doesn't use any globbing metacharacters, it's a plain match. For example, to run only -``*-compile*.txt`` tests in verbose mode:: +`*-compile*.txt` tests in verbose mode:: ./caasdriver verbose -compile @@ -561,18 +563,18 @@ metacharacters, it's a plain match. For example, to run only Test case file format --------------------- -All the ``tests/caas/*.txt`` files encode a session with the compiler: +All the `tests/caas/*.txt` files encode a session with the compiler: * The first line indicates the main project file. -* Lines starting with ``>`` indicate a command to be sent to the +* Lines starting with `>` indicate a command to be sent to the compiler and the lines following a command include checks for - expected or forbidden output (``!`` for forbidden). + expected or forbidden output (`!` for forbidden). -* If a line starts with ``#`` it will be ignored completely, so you +* If a line starts with `#` it will be ignored completely, so you can use that for comments. -* Since some cases are specific to either ``ProcRun`` or ``CaasRun`` +* Since some cases are specific to either `ProcRun` or `CaasRun` modes, you can prefix a line with the mode and the line will be processed only in that mode. diff --git a/doc/intern.rst b/doc/intern.rst index 0eb70e143..2456b25fd 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================================= Internals of the Nim Compiler ========================================= @@ -19,19 +21,19 @@ The Nim project's directory structure is: ============ =================================================== Path Purpose ============ =================================================== -``bin`` generated binary files -``build`` generated C code for the installation -``compiler`` the Nim compiler itself; note that this +`bin` generated binary files +`build` generated C code for the installation +`compiler` the Nim compiler itself; note that this code has been translated from a bootstrapping version written in Pascal, so the code is **not** a poster child of good Nim code -``config`` configuration files for Nim -``dist`` additional packages for the distribution -``doc`` the documentation; it is a bunch of +`config` configuration files for Nim +`dist` additional packages for the distribution +`doc` the documentation; it is a bunch of reStructuredText files -``lib`` the Nim library -``web`` website of Nim; generated by ``nimweb`` - from the ``*.txt`` and ``*.nimf`` files +`lib` the Nim library +`web` website of Nim; generated by `nimweb` + from the `*.txt` and `*.nimf` files ============ =================================================== @@ -53,7 +55,7 @@ And for a debug version compatible with GDB:: nim c koch.nim ./koch boot --debuginfo --linedir:on -The ``koch`` program is Nim's maintenance script. It is a replacement for +The `koch` program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. More information about its options can be found in the `koch `_ documentation. @@ -67,8 +69,8 @@ Coding Guidelines * Max line length is 80 characters. * Provide spaces around binary operators if that enhances readability. * Use a space after a colon, but not before it. -* [deprecated] Start types with a capital ``T``, unless they are - pointers/references which start with ``P``. +* [deprecated] Start types with a capital `T`, unless they are + pointers/references which start with `P`. See also the `API naming design `_ document. @@ -81,12 +83,12 @@ portable programming language (within certain limits) and Nim generates C code, porting the code generator is not necessary. POSIX-compliant systems on conventional hardware are usually pretty easy to -port: Add the platform to ``platform`` (if it is not already listed there), +port: Add the platform to `platform` (if it is not already listed there), check that the OS, System modules work and recompile Nim. The only case where things aren't as easy is when the garbage collector needs some assembler tweaking to work. The standard -version of the GC uses C's ``setjmp`` function to store all registers +version of the GC uses C's `setjmp` function to store all registers on the hardware stack. It may be necessary that the new platform needs to replace this generic code by some assembler code. @@ -111,7 +113,7 @@ Complex assignments We already know the type information as a graph in the compiler. Thus we need to serialize this graph as RTTI for C code generation. -Look at the file ``lib/system/hti.nim`` for more information. +Look at the file `lib/system/hti.nim` for more information. Rebuilding the compiler ======================== @@ -139,7 +141,7 @@ Debugging the compiler ====================== You can of course use GDB or Visual Studio to debug the -compiler (via ``--debuginfo --lineDir:on``). However, there +compiler (via `--debuginfo --lineDir:on`). However, there are also lots of procs that aid in debugging: @@ -170,19 +172,19 @@ These procs may not be imported by a module. You can import them directly for de from renderer import renderTree from msgs import `??` -To create a new compiler for each run, use ``koch temp``:: +To create a new compiler for each run, use `koch temp`:: ./koch temp c /tmp/test.nim -``koch temp`` creates a debug build of the compiler, which is useful +`koch temp` creates a debug build of the compiler, which is useful to create stacktraces for compiler debugging. See also `Rebuilding the compiler`_ if you need more control. Bisecting for regressions ========================= -``koch temp`` returns 125 as the exit code in case the compiler -compilation fails. This exit code tells ``git bisect`` to skip the +`koch temp` returns 125 as the exit code in case the compiler +compilation fails. This exit code tells `git bisect` to skip the current commit.:: git bisect start bad-commit good-commit @@ -219,15 +221,15 @@ examples how the AST represents each syntactic structure. How the RTL is compiled ======================= -The ``system`` module contains the part of the RTL which needs support by +The `system` module contains the part of the RTL which needs support by compiler magic (and the stuff that needs to be in it because the spec says so). The C code generator generates the C code for it, just like any other -module. However, calls to some procedures like ``addInt`` are inserted by -the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``) -with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are -needed by the code generator. A ``magic`` proc is not the same as a -``compilerproc``: A ``magic`` is a proc that needs compiler magic for its -semantic checking, a ``compilerproc`` is a proc that is used by the code +module. However, calls to some procedures like `addInt` are inserted by +the CCG. Therefore the module `magicsys` contains a table (`compilerprocs`) +with all symbols that are marked as `compilerproc`. `compilerprocs` are +needed by the code generator. A `magic` proc is not the same as a +`compilerproc`: A `magic` is a proc that needs compiler magic for its +semantic checking, a `compilerproc` is a proc that is used by the code generator. @@ -254,7 +256,7 @@ This solves the problem without having to special case the logic that fills the internal seqs which are affected by the pragmas. In fact, this describes how the AST should be stored in the database, -as a "shallow" tree. Let's assume we compile module ``m`` with the +as a "shallow" tree. Let's assume we compile module `m` with the following contents: .. code-block:: nim @@ -279,21 +281,21 @@ Conceptually this is the AST we store for the module: static: echo "static" -The symbol's ``ast`` field is loaded lazily, on demand. This is where most +The symbol's `ast` field is loaded lazily, on demand. This is where most savings come from, only the shallow outer AST is reconstructed immediately. -It is also important that the replay involves the ``import`` statement so +It is also important that the replay involves the `import` statement so that dependencies are resolved properly. Shared global compiletime state ------------------------------- -Nim allows ``.global, compiletime`` variables that can be filled by macro +Nim allows `.global, compiletime` variables that can be filled by macro invocations across different modules. This feature breaks modularity in a severe way. Plenty of different solutions have been proposed: -- Restrict the types of global compiletime variables to ``Set[T]`` or +- Restrict the types of global compiletime variables to `Set[T]` or similar unordered, only-growable collections so that we can track the module's write effects to these variables and reapply the changes in a different order. @@ -306,7 +308,7 @@ severe way. Plenty of different solutions have been proposed: Since we adopt the "replay the top level statements" idea, the natural solution to this problem is to emit pseudo top level statements that reflect the mutations done to the global variable. However, this is -MUCH harder than it sounds, for example ``squeaknim`` uses this +MUCH harder than it sounds, for example `squeaknim` uses this snippet: .. code-block:: nim @@ -314,12 +316,12 @@ snippet: "\t^self externalCallFailed\C!\C\C") stCode.add(st & "\C\t\"Generated by NimSqueak\"\C\t" & apicall) -We can "replay" ``stCode.add`` only if the values of ``st`` -and ``apicall`` are known. And even then a hash table's ``add`` with its +We can "replay" `stCode.add` only if the values of `st` +and `apicall` are known. And even then a hash table's `add` with its hashing mechanism is too hard to replay. -In practice, things are worse still, consider ``someGlobal[i][j].add arg``. -We only know the root is ``someGlobal`` but the concrete path to the data +In practice, things are worse still, consider `someGlobal[i][j].add arg`. +We only know the root is `someGlobal` but the concrete path to the data is unknown as is the value that is added. We could compute a "diff" between the global states and use that to compute a symbol patchset, but this is quite some work, expensive to do at runtime (it would need to run after @@ -342,7 +344,7 @@ an alien API and works with some existing Nimble packages, at least. On the other hand, in Nim's future I would like to replace the VM by native code. A diff algorithm wouldn't work for that. -Instead the native code would work with an API like ``put``, ``get``: +Instead the native code would work with an API like `put`, `get`: .. code-block:: nim @@ -350,7 +352,7 @@ Instead the native code would work with an API like ``put``, ``get``: proc cacheGet*(key: string): NimNode The API should embrace the AST diffing notion: See the -module ``macrocache`` for the final details. +module `macrocache` for the final details. @@ -382,9 +384,9 @@ too. Type converters fall into this category: if 1: echo "ugly, but should work" -If in the above example module ``B`` is re-compiled, but ``A`` is not then -``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced -in ``B`` *explicitly*. +If in the above example module `B` is re-compiled, but `A` is not then +`B` needs to be aware of `toBool` even though `toBool` is not referenced +in `B` *explicitly*. Both the multi method and the type converter problems are solved by the AST replay implementation. @@ -395,7 +397,7 @@ Generics We cache generic instantiations and need to ensure this caching works well with the incremental compilation feature. Since the cache is -attached to the ``PSym`` datastructure, it should work without any +attached to the `PSym` datastructure, it should work without any special logic. @@ -405,22 +407,22 @@ Backend issues - Init procs must not be "forgotten" to be called. - Files must not be "forgotten" to be linked. - Method dispatchers are global. -- DLL loading via ``dlsym`` is global. +- DLL loading via `dlsym` is global. - Emulated thread vars are global. However the biggest problem is that dead code elimination breaks modularity! -To see why, consider this scenario: The module ``G`` (for example the huge +To see why, consider this scenario: The module `G` (for example the huge Gtk2 module...) is compiled with dead code elimination turned on. So none -of ``G``'s procs is generated at all. +of `G`'s procs is generated at all. -Then module ``B`` is compiled that requires ``G.P1``. Ok, no problem, -``G.P1`` is loaded from the symbol file and ``G.c`` now contains ``G.P1``. +Then module `B` is compiled that requires `G.P1`. Ok, no problem, +`G.P1` is loaded from the symbol file and `G.c` now contains `G.P1`. -Then module ``A`` (that depends on ``B`` and ``G``) is compiled and ``B`` -and ``G`` are left unchanged. ``A`` requires ``G.P2``. +Then module `A` (that depends on `B` and `G`) is compiled and `B` +and `G` are left unchanged. `A` requires `G.P2`. -So now ``G.c`` MUST contain both ``P1`` and ``P2``, but we haven't even -loaded ``P1`` from the symbol file, nor do we want to because we then quickly +So now `G.c` MUST contain both `P1` and `P2`, but we haven't even +loaded `P1` from the symbol file, nor do we want to because we then quickly would restore large parts of the whole program. @@ -428,7 +430,7 @@ Solution ~~~~~~~~ The backend must have some logic so that if the currently processed module -is from the compilation cache, the ``ast`` field is not accessed. Instead +is from the compilation cache, the `ast` field is not accessed. Instead the generated C(++) for the symbol's body needs to be cached too and inserted back into the produced C file. This approach seems to deal with all the outlined problems above. @@ -444,8 +446,8 @@ in mind: keeps allocating memory! Thus a stack overflow may happen, hiding the real issue. * What seem to be C code generation problems is often a bug resulting from - not producing prototypes, so that some types default to ``cint``. Testing - without the ``-w`` option helps! + not producing prototypes, so that some types default to `cint`. Testing + without the `-w` option helps! The Garbage Collector @@ -464,9 +466,9 @@ code generation. Each cell has a header consisting of a RC and a pointer to its type descriptor. However the program does not know about these, so they are placed at -negative offsets. In the GC code the type ``PCell`` denotes a pointer +negative offsets. In the GC code the type `PCell` denotes a pointer decremented by the right offset, so that the header can be accessed easily. It -is extremely important that ``pointer`` is not confused with a ``PCell`` +is extremely important that `pointer` is not confused with a `PCell` as this would lead to a memory corruption. @@ -474,9 +476,9 @@ The CellSet data structure -------------------------- The GC depends on an extremely efficient datastructure for storing a -set of pointers - this is called a ``TCellSet`` in the source code. +set of pointers - this is called a `TCellSet` in the source code. Inserting, deleting and searching are done in constant time. However, -modifying a ``TCellSet`` during traversal leads to undefined behaviour. +modifying a `TCellSet` during traversal leads to undefined behaviour. .. code-block:: Nim type @@ -559,11 +561,11 @@ Code generation for closures is implemented by `lambda lifting`:idx:. Design ------ -A ``closure`` proc var can call ordinary procs of the default Nim calling +A `closure` proc var can call ordinary procs of the default Nim calling convention. But not the other way round! A closure is implemented as a -``tuple[prc, env]``. ``env`` can be nil implying a call without a closure. -This means that a call through a closure generates an ``if`` but the -interoperability is worth the cost of the ``if``. Thunk generation would be +`tuple[prc, env]`. `env` can be nil implying a call without a closure. +This means that a call through a closure generates an `if` but the +interoperability is worth the cost of the `if`. Thunk generation would be possible too, but it's slightly more effort to implement. Tests with GCC on Amd64 showed that it's really beneficial if the @@ -579,7 +581,7 @@ A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require an *additional* closure generation... Ok, not really, but it requires to pass the function to call. So we'd end up with 2 indirect calls instead of one. Another much more severe problem which this solution is that it's not GC-safe -to pass a proc pointer around via a generic ``ref`` type. +to pass a proc pointer around via a generic `ref` type. Example code: @@ -695,15 +697,15 @@ Accumulator Internals --------- -Lambda lifting is implemented as part of the ``transf`` pass. The ``transf`` +Lambda lifting is implemented as part of the `transf` pass. The `transf` pass generates code to setup the environment and to pass it around. However, this pass does not change the types! So we have some kind of mismatch here; on the one hand the proc expression becomes an explicit tuple, on the other hand the tyProc(ccClosure) type is not changed. For C code generation it's also -important the hidden formal param is ``void*`` and not something more +important the hidden formal param is `void*` and not something more specialized. However the more specialized env type needs to passed to the -backend somehow. We deal with this by modifying ``s.ast[paramPos]`` to contain -the formal hidden parameter, but not ``s.typ``! +backend somehow. We deal with this by modifying `s.ast[paramPos]` to contain +the formal hidden parameter, but not `s.typ`! Integer literals: diff --git a/doc/koch.rst b/doc/koch.rst index c92e29812..1eb02d785 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =============================== Nim maintenance script =============================== @@ -17,7 +19,7 @@ Introduction The `koch`:idx: program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. -The word *koch* means *cook* in German. ``koch`` is used mainly to build the +The word *koch* means *cook* in German. `koch` is used mainly to build the Nim compiler, but it can also be used for other tasks. This document describes the supported commands and their options. @@ -39,8 +41,8 @@ options: Use the linenoise library for interactive mode (not needed on Windows). After compilation is finished you will hopefully end up with the nim -compiler in the ``bin`` directory. You can add Nim's ``bin`` directory to -your ``$PATH`` or use the install command to place it where it will be +compiler in the `bin` directory. You can add Nim's `bin` directory to +your `$PATH` or use the install command to place it where it will be found. csource command @@ -54,33 +56,33 @@ temp command ------------ The temp command builds the Nim compiler but with a different final name -(``nim_temp``), so it doesn't overwrite your normal compiler. You can use +(`nim_temp`), so it doesn't overwrite your normal compiler. You can use this command to test different options, the same you would issue for the `boot command <#commands-boot-command>`_. test command ------------ -The `test`:idx: command can also be invoked with the alias ``tests``. This -command will compile and run ``testament/tester.nim``, which is the main -driver of Nim's test suite. You can pass options to the ``test`` command, +The `test`:idx: command can also be invoked with the alias `tests`. This +command will compile and run `testament/tester.nim`, which is the main +driver of Nim's test suite. You can pass options to the `test` command, they will be forwarded to the tester. See its source code for available options. web command ----------- -The `web`:idx: command converts the documentation in the ``doc`` directory +The `web`:idx: command converts the documentation in the `doc` directory from rst to HTML. It also repeats the same operation but places the result in -the ``web/upload`` which can be used to update the website at +the `web/upload` which can be used to update the website at https://nim-lang.org. By default, the documentation will be built in parallel using the number of available CPU cores. If any documentation build sub-commands fail, they will be rerun in serial fashion so that meaningful error output can be gathered for -inspection. The ``--parallelBuild:n`` switch or configuration option can be +inspection. The `--parallelBuild:n` switch or configuration option can be used to force a specific number of parallel jobs or run everything serially -from the start (``n == 1``). +from the start (`n == 1`). pdf command ----------- diff --git a/doc/lib.rst b/doc/lib.rst index 2a4c2c03c..3202c5a53 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ==================== Nim Standard Library ==================== @@ -9,7 +11,7 @@ Nim Standard Library Nim's library is divided into *pure libraries*, *impure libraries*, and *wrappers*. -Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary +Pure libraries do not depend on any external `*.dll` or `lib*.so` binary while impure libraries do. A wrapper is an impure library that is a very low-level interface to a C library. @@ -37,11 +39,11 @@ Automatic imports * `threads `_ Basic Nim thread support. **Note:** This is part of the system module. Do not - import it explicitly. Enabled with ``--threads:on``. + import it explicitly. Enabled with `--threads:on`. * `channels `_ Nim message passing support for threads. **Note:** This is part of the - system module. Do not import it explicitly. Enabled with ``--threads:on``. + system module. Do not import it explicitly. Enabled with `--threads:on`. Core @@ -86,14 +88,14 @@ Algorithms This module implements some common generic algorithms like sort or binary search. * `std/enumutils `_ - This module adds functionality for the built-in ``enum`` type. + This module adds functionality for the built-in `enum` type. * `sequtils `_ - This module implements operations for the built-in ``seq`` type + This module implements operations for the built-in `seq` type which were inspired by functional programming languages. * `std/setutils `_ - This module adds functionality for the built-in ``set`` type. + This module adds functionality for the built-in `set` type. Collections @@ -105,7 +107,7 @@ Collections * `deques `_ Implementation of a double-ended queue. - The underlying implementation uses a ``seq``. + The underlying implementation uses a `seq`. * `heapqueue `_ Implementation of a heap data structure that can be used as a priority queue. @@ -140,7 +142,7 @@ String handling --------------- * `cstrutils `_ - Utilities for ``cstring`` handling. + Utilities for `cstring` handling. * `std/editdistance `_ This module contains an algorithm to compute the edit distance between two @@ -148,7 +150,7 @@ String handling * `encodings `_ Converts between different character encodings. On UNIX, this uses - the ``iconv`` library, on Windows the Windows API. + the `iconv` library, on Windows the Windows API. * `parseutils `_ This module contains helpers for parsing tokens, numbers, identifiers, etc. @@ -166,17 +168,17 @@ String handling * `strformat `_ Macro based standard string interpolation/formatting. Inspired by - Python's ``f``-strings. + Python's `f`-strings. * `strmisc `_ This module contains uncommon string handling operations that do not fit with the commonly used operations in strutils. * `strscans `_ - This module contains a ``scanf`` macro for convenient parsing of mini languages. + This module contains a `scanf` macro for convenient parsing of mini languages. * `strtabs `_ - The ``strtabs`` module implements an efficient hash table that is a mapping + The `strtabs` module implements an efficient hash table that is a mapping from strings to strings. Supports a case-sensitive, case-insensitive and style-insensitive modes. @@ -200,10 +202,10 @@ Time handling ------------- * `std/monotimes `_ - The ``monotimes`` module implements monotonic timestamps. + The `monotimes` module implements monotonic timestamps. * `times `_ - The ``times`` module contains support for working with time. + The `times` module contains support for working with time. Generic Operating System Services @@ -225,7 +227,7 @@ Generic Operating System Services data structures. * `memfiles `_ - This module provides support for memory-mapped files (Posix's ``mmap``) + This module provides support for memory-mapped files (Posix's `mmap`) on the different operating systems. * `os `_ @@ -234,12 +236,12 @@ Generic Operating System Services commands, etc. * `osproc `_ - Module for process communication beyond ``os.execShellCmd``. + Module for process communication beyond `os.execShellCmd`. * `streams `_ This module provides a stream interface and two implementations thereof: - the ``FileStream`` and the ``StringStream`` which implement the stream - interface for Nim file objects (``File``) and strings. Other modules + the `FileStream` and the `StringStream` which implement the stream + interface for Nim file objects (`File`) and strings. Other modules may provide other implementations for this standard stream interface. * `terminal `_ @@ -288,22 +290,22 @@ Internet Protocols and Support * `asyncfile `_ This module implements asynchronous file reading and writing using - ``asyncdispatch``. + `asyncdispatch`. * `asyncftpclient `_ - This module implements an asynchronous FTP client using the ``asyncnet`` + This module implements an asynchronous FTP client using the `asyncnet` module. * `asynchttpserver `_ - This module implements an asynchronous HTTP server using the ``asyncnet`` + This module implements an asynchronous HTTP server using the `asyncnet` module. * `asyncnet `_ - This module implements asynchronous sockets based on the ``asyncdispatch`` + This module implements asynchronous sockets based on the `asyncdispatch` module. * `asyncstreams `_ - This module provides ``FutureStream`` - a future that acts as a queue. + This module provides `FutureStream` - a future that acts as a queue. * `cgi `_ This module implements helpers for CGI applications. @@ -323,7 +325,7 @@ Internet Protocols and Support * `net `_ This module implements a high-level sockets API. It replaces the - ``sockets`` module. + `sockets` module. * `selectors `_ This module implements a selector API with backends specific to each OS. @@ -357,23 +359,23 @@ Parsers scheme for lexers and parsers. This is used by the diverse parsing modules. * `parsecfg `_ - The ``parsecfg`` module implements a high-performance configuration file - parser. The configuration file's syntax is similar to the Windows ``.ini`` + The `parsecfg` module implements a high-performance configuration file + parser. The configuration file's syntax is similar to the Windows `.ini` format, but much more powerful, as it is not a line based parser. String literals, raw string literals, and triple quote string literals are supported as in the Nim programming language. * `parsecsv `_ - The ``parsecsv`` module implements a simple high-performance CSV parser. + The `parsecsv` module implements a simple high-performance CSV parser. * `parseopt `_ - The ``parseopt`` module implements a command line option parser. + The `parseopt` module implements a command line option parser. * `parsesql `_ - The ``parsesql`` module implements a simple high-performance SQL parser. + The `parsesql` module implements a simple high-performance SQL parser. * `parsexml `_ - The ``parsexml`` module implements a simple high performance XML/HTML parser. + The `parsexml` module implements a simple high performance XML/HTML parser. The only encoding that is supported is UTF-8. The parser has been designed to be somewhat error-correcting, so that even some "wild HTML" found on the web can be parsed with it. @@ -458,7 +460,7 @@ Miscellaneous This module implements a simple logger. * `segfaults `_ - Turns access violations or segfaults into a ``NilAccessDefect`` exception. + Turns access violations or segfaults into a `NilAccessDefect` exception. * `sugar `_ This module implements nice syntactic sugar based on Nim's macro system. @@ -480,11 +482,11 @@ Modules for JS backend Declaration of the Document Object Model for the JS backend. * `jsconsole `_ - Wrapper for the ``console`` object. + Wrapper for the `console` object. * `jscore `_ The wrapper of core JavaScript functions. For most purposes, you should be using - the ``math``, ``json``, and ``times`` stdlib modules instead of this module. + the `math`, `json`, and `times` stdlib modules instead of this module. * `jsffi `_ Types and macros for easier interaction with JavaScript. diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.rst index c6de8cf7c..e34993e3e 100644 --- a/doc/manual/var_t_return.rst +++ b/doc/manual/var_t_return.rst @@ -1,6 +1,8 @@ -Memory safety for returning by ``var T`` is ensured by a simple borrowing -rule: If ``result`` does not refer to a location pointing to the heap -(that is in ``result = X`` the ``X`` involves a ``ptr`` or ``ref`` access) +.. default-role:: code + +Memory safety for returning by `var T` is ensured by a simple borrowing +rule: If `result` does not refer to a location pointing to the heap +(that is in `result = X` the `X` involves a `ptr` or `ref` access) then it has to be derived from the routine's first parameter: .. code-block:: nim @@ -11,10 +13,10 @@ then it has to be derived from the routine's first parameter: var x: int # we know 'forward' provides a view into the location derived from # its first argument 'x'. - result = forward(x) # Error: location is derived from ``x`` + result = forward(x) # Error: location is derived from `x` # which is not p's first parameter and lives # on the stack. -In other words, the lifetime of what ``result`` points to is attached to the +In other words, the lifetime of what `result` points to is attached to the lifetime of the first parameter and that is enough knowledge to verify memory safety at the call site. diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index b76839842..cf2e0c247 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================= Nim Experimental Features ========================= @@ -12,8 +14,8 @@ About this document =================== This document describes features of Nim that are to be considered experimental. -Some of these are not covered by the ``.experimental`` pragma or -``--experimental`` switch because they are already behind a special syntax and +Some of these are not covered by the `.experimental` pragma or +`--experimental` switch because they are already behind a special syntax and one may want to use Nim libraries using these features without using them oneself. @@ -28,13 +30,13 @@ Every Nim module resides in a (nimble) package. An object type can be attached to the package it resides in. If that is done, the type can be referenced from other modules as an `incomplete`:idx: object type. This feature allows to break up recursive type dependencies across module boundaries. Incomplete -object types are always passed ``byref`` and can only be used in pointer like -contexts (``var/ref/ptr IncompleteObject``) in general since the compiler does +object types are always passed `byref` and can only be used in pointer like +contexts (`var/ref/ptr IncompleteObject`) in general since the compiler does not yet know the size of the object. To complete an incomplete object -the ``package`` pragma has to be used. ``package`` implies ``byref``. +the `package` pragma has to be used. `package` implies `byref`. -As long as a type ``T`` is incomplete, neither ``sizeof(T)`` nor runtime -type information for ``T`` is available. +As long as a type `T` is incomplete, neither `sizeof(T)` nor runtime +type information for `T` is available. Example: @@ -63,8 +65,8 @@ Example: Void type ========= -The ``void`` type denotes the absence of any type. Parameters of -type ``void`` are treated as non-existent, ``void`` as a return type means that +The `void` type denotes the absence of any type. Parameters of +type `void` are treated as non-existent, `void` as a return type means that the procedure does not return a value: .. code-block:: nim @@ -73,7 +75,7 @@ the procedure does not return a value: nothing() # writes "ha" to stdout -The ``void`` type is particularly useful for generic code: +The `void` type is particularly useful for generic code: .. code-block:: nim proc callProc[T](p: proc (x: T), x: T) = @@ -88,7 +90,7 @@ The ``void`` type is particularly useful for generic code: callProc[int](intProc, 12) callProc[void](emptyProc) -However, a ``void`` type cannot be inferred in generic code: +However, a `void` type cannot be inferred in generic code: .. code-block:: nim callProc(emptyProc) @@ -96,8 +98,8 @@ However, a ``void`` type cannot be inferred in generic code: # but expected one of: # callProc(p: proc (T), x: T) -The ``void`` type is only valid for parameters and return types; other symbols -cannot have the type ``void``. +The `void` type is only valid for parameters and return types; other symbols +cannot have the type `void`. @@ -105,19 +107,19 @@ Covariance ========== Covariance in Nim can be introduced only through pointer-like types such -as ``ptr`` and ``ref``. Sequence, Array and OpenArray types, instantiated +as `ptr` and `ref`. Sequence, Array and OpenArray types, instantiated with pointer-like types will be considered covariant if and only if they -are also immutable. The introduction of a ``var`` modifier or additional -``ptr`` or ``ref`` indirections would result in invariant treatment of +are also immutable. The introduction of a `var` modifier or additional +`ptr` or `ref` indirections would result in invariant treatment of these types. -``proc`` types are currently always invariant, but future versions of Nim +`proc` types are currently always invariant, but future versions of Nim may relax this rule. User-defined generic types may also be covariant with respect to some of their parameters. By default, all generic params are considered invariant, -but you may choose the apply the prefix modifier ``in`` to a parameter to -make it contravariant or ``out`` to make it covariant: +but you may choose the apply the prefix modifier `in` to a parameter to +make it contravariant or `out` to make it covariant: .. code-block:: nim type @@ -166,10 +168,10 @@ values: # to point to a ComboBox On the other hand, in the `RingBuffer` example above, the designated generic -param is used to instantiate the non-pointer ``seq`` type, which means that +param is used to instantiate the non-pointer `seq` type, which means that the resulting generic type will have covariance that mimics an array or -sequence (i.e. it will be covariant only when instantiated with ``ptr`` and -``ref`` types): +sequence (i.e. it will be covariant only when instantiated with `ptr` and +`ref` types): .. code-block:: nim @@ -196,7 +198,7 @@ as `seq[AnnotatedPtr[T]]` or `RingBuffer[AnnotatedPtr[T]]` will also be considered covariant and you can create new pointer-like types by instantiating other user-defined pointer-like types. -The contravariant parameters introduced with the ``in`` modifier are currently +The contravariant parameters introduced with the `in` modifier are currently useful only when interfacing with imported types having such semantics. @@ -204,7 +206,7 @@ Automatic dereferencing ======================= Automatic dereferencing is performed for the first argument of a routine call. -This feature has to be enabled via ``{.experimental: "implicitDeref".}``: +This feature has to be enabled via `{.experimental: "implicitDeref".}`: .. code-block:: nim {.experimental: "implicitDeref".} @@ -257,7 +259,7 @@ preface definitions inside a module. Please note that if a callable symbol is never used in this scenario, its body will never be compiled. This is the default behavior leading to best compilation times, but if exhaustive compilation of all definitions is - required, using ``nim check`` provides this option as well. + required, using `nim check` provides this option as well. Example: @@ -290,10 +292,10 @@ what code is executed at the top level: .. TODO: Let's table this for now. This is an *experimental feature* and so the - specific manner in which ``declared`` operates with it can be decided in + specific manner in which `declared` operates with it can be decided in eventuality, because right now it works a bit weirdly. - The values of expressions involving ``declared`` are decided *before* the + The values of expressions involving `declared` are decided *before* the code reordering process, and not after. As an example, the output of this code is the same as it would be with code reordering disabled. @@ -325,7 +327,7 @@ Named argument overloading ========================== Routines with the same type signature can be called differently if a parameter -has different names. This does not need an ``experimental`` switch, but is an +has different names. This does not need an `experimental` switch, but is an unstable feature. .. code-block::nim @@ -344,7 +346,7 @@ Do notation =========== As a special more convenient notation, proc expressions involved in procedure -calls can use the ``do`` keyword: +calls can use the `do` keyword: .. code-block:: nim sort(cities) do (x,y: string) -> int: @@ -359,13 +361,13 @@ calls can use the ``do`` keyword: if not `ex`: echo `info`, ": Check failed: ", `expString` -``do`` is written after the parentheses enclosing the regular proc params. +`do` is written after the parentheses enclosing the regular proc params. The proc expression represented by the do block is appended to them. In calls using the command syntax, the do block will bind to the immediately preceding expression, transforming it in a call. -``do`` with parentheses is an anonymous ``proc``; however a ``do`` without -parentheses is just a block of code. The ``do`` notation can be used to +`do` with parentheses is an anonymous `proc`; however a `do` without +parentheses is just a block of code. The `do` notation can be used to pass multiple blocks to a macro: .. code-block:: nim @@ -385,7 +387,7 @@ dot operators ------------- **Note**: Dot operators are still experimental and so need to be enabled -via ``{.experimental: "dotOperators".}``. +via `{.experimental: "dotOperators".}`. Nim offers a special family of dot operators that can be used to intercept and rewrite proc call and field access attempts, referring @@ -398,7 +400,7 @@ When Nim encounters an expression that cannot be resolved by the standard overload resolution rules, the current scope will be searched for a dot operator that can be matched against a re-written form of the expression, where the unknown field or proc name is passed to -an ``untyped`` parameter: +an `untyped` parameter: .. code-block:: nim a.b # becomes `.`(a, b) @@ -471,10 +473,10 @@ Not nil annotation ================== **Note:** This is an experimental feature. It can be enabled with -``{.experimental: "notnil"}``. +`{.experimental: "notnil"}`. -All types for which ``nil`` is a valid value can be annotated with the ``not -nil`` annotation to exclude ``nil`` as a valid value: +All types for which `nil` is a valid value can be annotated with the `not +nil` annotation to exclude `nil` as a valid value: .. code-block:: nim {.experimental: "notnil"} @@ -526,9 +528,9 @@ The concept is a match if: a) all of the expressions within the body can be compiled for the tested type b) all statically evaluable boolean expressions in the body must be true -The identifiers following the ``concept`` keyword represent instances of the +The identifiers following the `concept` keyword represent instances of the currently matched type. You can apply any of the standard type modifiers such -as ``var``, ``ref``, ``ptr`` and ``static`` to denote a more specific type of +as `var`, `ref`, `ptr` and `static` to denote a more specific type of instance. You can also apply the `type` modifier to create a named instance of the type itself: @@ -546,9 +548,9 @@ the presence of callable symbols with specific signatures: OutputStream = concept var s s.write(string) -In order to check for symbols accepting ``type`` params, you must prefix -the type with the explicit ``type`` modifier. The named instance of the -type, following the ``concept`` keyword is also considered to have the +In order to check for symbols accepting `type` params, you must prefix +the type with the explicit `type` modifier. The named instance of the +type, following the `concept` keyword is also considered to have the explicit modifier and will be matched only as a type. .. code-block:: nim @@ -570,7 +572,7 @@ explicit modifier and will be matched only as a type. -x is T x - y is T -Please note that the ``is`` operator allows one to easily verify the precise +Please note that the `is` operator allows one to easily verify the precise type signatures of the required operations, but since type inference and default parameters are still applied in the concept body, it's also possible to describe usage protocols that do not reveal implementation details. @@ -586,7 +588,7 @@ By default, the compiler will report the matching errors in concepts only when no other overload can be selected and a normal compilation error is produced. When you need to understand why the compiler is not matching a particular concept and, as a result, a wrong overload is selected, you can apply the -``explain`` pragma to either the concept body or a particular call-site. +`explain` pragma to either the concept body or a particular call-site. .. code-block:: nim type @@ -670,7 +672,7 @@ resembles the way generic parameters of callable symbols are inferred on call sites. Unbound types can appear both as params to calls such as `s.push(T)` and -on the right-hand side of the ``is`` operator in cases such as `x.pop is T` +on the right-hand side of the `is` operator in cases such as `x.pop is T` and `x.data is seq[T]`. Unbound static params will be inferred from expressions involving the `==` @@ -684,8 +686,8 @@ operator and also when types dependent on them are being matched: The Nim compiler includes a simple linear equation solver, allowing it to infer static params in some situations where integer arithmetic is involved. -Just like in regular type classes, Nim discriminates between ``bind once`` -and ``bind many`` types when matching the concept. You can add the ``distinct`` +Just like in regular type classes, Nim discriminates between `bind once` +and `bind many` types when matching the concept. You can add the `distinct` modifier to any of the otherwise inferable types to get a type that will be matched without permanently inferring it. This may be useful when you need to match several procs accepting the same wide class of types: @@ -708,7 +710,7 @@ to match several procs accepting the same wide class of types: type Enum = distinct Enumerable o.baz is Enum -On the other hand, using ``bind once`` types allows you to test for equivalent +On the other hand, using `bind once` types allows you to test for equivalent types used in multiple signatures, without actually requiring any concrete types, thus allowing you to encode implementation-defined types: @@ -804,7 +806,7 @@ concept, we say that the outer concept is a refinement of the inner concept and thus it is more-specific. When both concepts are matched in a call during overload resolution, Nim will assign a higher precedence to the most specific one. As an alternative way of defining concept refinements, you can use the -object inheritance syntax involving the ``of`` keyword: +object inheritance syntax involving the `of` keyword: .. code-block:: nim type @@ -895,8 +897,8 @@ object inheritance syntax involving the ``of`` keyword: any type can implement an unlimited number of protocols or interfaces not originally envisioned by the type's author. - Any concept type can be turned into a VTable type by using the ``vtref`` - or the ``vtptr`` compiler magics. Under the hood, these magics generate + Any concept type can be turned into a VTable type by using the `vtref` + or the `vtptr` compiler magics. Under the hood, these magics generate a converter type class, which converts the regular instances of the matching types to the corresponding VTable type. @@ -928,8 +930,8 @@ object inheritance syntax involving the ``of`` keyword: but it will include a smaller number of captured procs. A completely empty vtable will be reported as an error. - The ``vtref`` magic produces types which can be bound to ``ref`` types and - the ``vtptr`` magic produced types bound to ``ptr`` types. + The `vtref` magic produces types which can be bound to `ref` types and + the `vtptr` magic produced types bound to `ptr` types. Type bound operations @@ -944,12 +946,12 @@ There are 4 operations that are bound to a type: These operations can be *overridden* instead of *overloaded*. This means the implementation is automatically lifted to structured types. For instance if type -``T`` has an overridden assignment operator ``=`` this operator is also used -for assignments of the type ``seq[T]``. Since these operations are bound to a +`T` has an overridden assignment operator `=` this operator is also used +for assignments of the type `seq[T]`. Since these operations are bound to a type they have to be bound to a nominal type for reasons of simplicity of -implementation: This means an overridden ``deepCopy`` for ``ref T`` is really -bound to ``T`` and not to ``ref T``. This also means that one cannot override -``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a +implementation: This means an overridden `deepCopy` for `ref T` is really +bound to `T` and not to `ref T`. This also means that one cannot override +`deepCopy` for both `ptr T` and `ref T` at the same time; instead a helper distinct or object type has to be used for one pointer type. Assignments, moves and destruction are specified in @@ -959,9 +961,9 @@ the `destructors `_ document. deepCopy -------- -``=deepCopy`` is a builtin that is invoked whenever data is passed to -a ``spawn``'ed proc to ensure memory safety. The programmer can override its -behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the +`=deepCopy` is a builtin that is invoked whenever data is passed to +a `spawn`'ed proc to ensure memory safety. The programmer can override its +behaviour for a specific `ref` or `ptr` type `T`. (Later versions of the language may weaken this restriction.) The signature has to be: @@ -972,7 +974,7 @@ The signature has to be: This mechanism will be used by most data structures that support shared memory like channels to implement thread safe automatic memory management. -The builtin ``deepCopy`` can even clone closures and their environments. See +The builtin `deepCopy` can even clone closures and their environments. See the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details. @@ -982,7 +984,7 @@ Case statement macros Macros named `case` can rewrite `case` statements for certain types in order to implement `pattern matching`:idx:. The following example implements a simplistic form of pattern matching for tuples, leveraging the existing -equality operator for tuples (as provided in ``system.==``): +equality operator for tuples (as provided in `system.==`): .. code-block:: nim :test: "nim c $1" @@ -1013,7 +1015,7 @@ equality operator for tuples (as provided in ``system.==``): Currently case statement macros must be enabled explicitly -via ``{.experimental: "caseStmtMacros".}``. +via `{.experimental: "caseStmtMacros".}`. `case` macros are subject to overload resolution. The type of the `case` statement's selector expression is matched against the type @@ -1039,10 +1041,10 @@ compilation pipeline with user defined optimizations: let x = 3 echo x * 2 -The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the -curlies is the pattern to match against. The operators ``*``, ``**``, -``|``, ``~`` have a special meaning in patterns if they are written in infix -notation, so to match verbatim against ``*`` the ordinary function call syntax +The compiler now rewrites `x * 2` as `x + x`. The code inside the +curlies is the pattern to match against. The operators `*`, `**`, +`|`, `~` have a special meaning in patterns if they are written in infix +notation, so to match verbatim against `*` the ordinary function call syntax needs to be used. Term rewriting macro are applied recursively, up to a limit. This means that @@ -1080,7 +1082,7 @@ You can make one overload matching with a constraint and one without, and the one with a constraint will have precedence, and so you can handle both cases differently. -So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We +So what about `2 * a`? We should tell the compiler `*` is commutative. We cannot really do that however as the following code only swaps arguments blindly: @@ -1092,59 +1094,59 @@ What optimizers really need to do is a *canonicalization*: .. code-block:: nim template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a -The ``int{lit}`` parameter pattern matches against an expression of -type ``int``, but only if it's a literal. +The `int{lit}` parameter pattern matches against an expression of +type `int`, but only if it's a literal. Parameter constraints --------------------- -The `parameter constraint`:idx: expression can use the operators ``|`` (or), -``&`` (and) and ``~`` (not) and the following predicates: +The `parameter constraint`:idx: expression can use the operators `|` (or), +`&` (and) and `~` (not) and the following predicates: =================== ===================================================== Predicate Meaning =================== ===================================================== -``atom`` The matching node has no children. -``lit`` The matching node is a literal like "abc", 12. -``sym`` The matching node must be a symbol (a bound +`atom` The matching node has no children. +`lit` The matching node is a literal like "abc", 12. +`sym` The matching node must be a symbol (a bound identifier). -``ident`` The matching node must be an identifier (an unbound +`ident` The matching node must be an identifier (an unbound identifier). -``call`` The matching AST must be a call/apply expression. -``lvalue`` The matching AST must be an lvalue. -``sideeffect`` The matching AST must have a side effect. -``nosideeffect`` The matching AST must have no side effect. -``param`` A symbol which is a parameter. -``genericparam`` A symbol which is a generic parameter. -``module`` A symbol which is a module. -``type`` A symbol which is a type. -``var`` A symbol which is a variable. -``let`` A symbol which is a ``let`` variable. -``const`` A symbol which is a constant. -``result`` The special ``result`` variable. -``proc`` A symbol which is a proc. -``method`` A symbol which is a method. -``iterator`` A symbol which is an iterator. -``converter`` A symbol which is a converter. -``macro`` A symbol which is a macro. -``template`` A symbol which is a template. -``field`` A symbol which is a field in a tuple or an object. -``enumfield`` A symbol which is a field in an enumeration. -``forvar`` A for loop variable. -``label`` A label (used in ``block`` statements). -``nk*`` The matching AST must have the specified kind. - (Example: ``nkIfStmt`` denotes an ``if`` statement.) -``alias`` States that the marked parameter needs to alias +`call` The matching AST must be a call/apply expression. +`lvalue` The matching AST must be an lvalue. +`sideeffect` The matching AST must have a side effect. +`nosideeffect` The matching AST must have no side effect. +`param` A symbol which is a parameter. +`genericparam` A symbol which is a generic parameter. +`module` A symbol which is a module. +`type` A symbol which is a type. +`var` A symbol which is a variable. +`let` A symbol which is a `let` variable. +`const` A symbol which is a constant. +`result` The special `result` variable. +`proc` A symbol which is a proc. +`method` A symbol which is a method. +`iterator` A symbol which is an iterator. +`converter` A symbol which is a converter. +`macro` A symbol which is a macro. +`template` A symbol which is a template. +`field` A symbol which is a field in a tuple or an object. +`enumfield` A symbol which is a field in an enumeration. +`forvar` A for loop variable. +`label` A label (used in `block` statements). +`nk*` The matching AST must have the specified kind. + (Example: `nkIfStmt` denotes an `if` statement.) +`alias` States that the marked parameter needs to alias with *some* other parameter. -``noalias`` States that *every* other parameter must not alias +`noalias` States that *every* other parameter must not alias with the marked parameter. =================== ===================================================== Predicates that share their name with a keyword have to be escaped with backticks. -The ``alias`` and ``noalias`` predicates refer not only to the matching AST, +The `alias` and `noalias` predicates refer not only to the matching AST, but also to every other bound parameter; syntactically they need to occur after the ordinary AST predicates: @@ -1158,14 +1160,14 @@ the ordinary AST predicates: Pattern operators ----------------- -The operators ``*``, ``**``, ``|``, ``~`` have a special meaning in patterns +The operators `*`, `**`, `|`, `~` have a special meaning in patterns if they are written in infix notation. -The ``|`` operator +The `|` operator ~~~~~~~~~~~~~~~~~~ -The ``|`` operator if used as infix operator creates an ordered choice: +The `|` operator if used as infix operator creates an ordered choice: .. code-block:: nim template t{0|1}(): untyped = 3 @@ -1182,15 +1184,15 @@ constant folding, so the following does not work: echo 1 The reason is that the compiler already transformed the 1 into "1" for -the ``echo`` statement. However, a term rewriting macro should not change the -semantics anyway. In fact they can be deactivated with the ``--patterns:off`` -command line option or temporarily with the ``patterns`` pragma. +the `echo` statement. However, a term rewriting macro should not change the +semantics anyway. In fact they can be deactivated with the `--patterns:off` +command line option or temporarily with the `patterns` pragma. -The ``{}`` operator +The `{}` operator ~~~~~~~~~~~~~~~~~~~ -A pattern expression can be bound to a pattern parameter via the ``expr{param}`` +A pattern expression can be bound to a pattern parameter via the `expr{param}` notation: .. code-block:: nim @@ -1200,10 +1202,10 @@ notation: echo a -The ``~`` operator +The `~` operator ~~~~~~~~~~~~~~~~~~ -The ``~`` operator is the **not** operator in patterns: +The `~` operator is the **not** operator in patterns: .. code-block:: nim template t{x = (~x){y} and (~x){z}}(x, y, z: bool) = @@ -1218,11 +1220,11 @@ The ``~`` operator is the **not** operator in patterns: echo a -The ``*`` operator +The `*` operator ~~~~~~~~~~~~~~~~~~ -The ``*`` operator can *flatten* a nested binary expression like ``a & b & c`` -to ``&(a, b, c)``: +The `*` operator can *flatten* a nested binary expression like `a & b & c` +to `&(a, b, c)`: .. code-block:: nim var @@ -1243,19 +1245,19 @@ to ``&(a, b, c)``: The second operator of `*` must be a parameter; it is used to gather all the -arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"`` -is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) -which is flattened into a call expression; thus the invocation of ``optConc`` +arguments. The expression `"my" && (space & "awe" && "some " ) && "concat"` +is passed to `optConc` in `a` as a special list (of kind `nkArgList`) +which is flattened into a call expression; thus the invocation of `optConc` produces: .. code-block:: nim `&&`("my", space & "awe", "some ", "concat") -The ``**`` operator +The `**` operator ~~~~~~~~~~~~~~~~~~~ -The ``**`` is much like the ``*`` operator, except that it gathers not only +The `**` is much like the `*` operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation: .. code-block:: nim @@ -1280,8 +1282,8 @@ all the arguments, but also the matched operators in reverse polish notation: echo x + y * z - x -This passes the expression ``x + y * z - x`` to the ``optM`` macro as -an ``nnkArglist`` node containing:: +This passes the expression `x + y * z - x` to the `optM` macro as +an `nnkArglist` node containing:: Arglist Sym "x" @@ -1292,14 +1294,14 @@ an ``nnkArglist`` node containing:: Sym "x" Sym "-" -(Which is the reverse polish notation of ``x + y * z - x``.) +(Which is the reverse polish notation of `x + y * z - x`.) Parameters ---------- Parameters in a pattern are type checked in the matching process. If a -parameter is of the type ``varargs`` it is treated specially and it can match +parameter is of the type `varargs` it is treated specially and it can match 0 or more arguments in the AST to be matched against: .. code-block:: nim @@ -1341,9 +1343,9 @@ The following example shows how some form of hoisting can be implemented: echo match("(a b c)", peg"'(' @ ')'") echo match("W_HI_Le", peg"\y 'while'") -The ``optPeg`` template optimizes the case of a peg constructor with a string +The `optPeg` template optimizes the case of a peg constructor with a string literal, so that the pattern will only be parsed once at program startup and -stored in a global ``gl`` which is then re-used. This optimization is called +stored in a global `gl` which is then re-used. This optimization is called hoisting because it is comparable to classical loop hoisting. @@ -1369,7 +1371,7 @@ constraints affect ordinary overloading resolution then: optLit(constant) optLit(variable) -However, the constraints ``alias`` and ``noalias`` are not available in +However, the constraints `alias` and `noalias` are not available in ordinary routines. @@ -1377,26 +1379,26 @@ Parallel & Spawn ================ Nim has two flavors of parallelism: -1) `Structured`:idx: parallelism via the ``parallel`` statement. -2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement. +1) `Structured`:idx: parallelism via the `parallel` statement. +2) `Unstructured`:idx: parallelism via the standalone `spawn` statement. Nim has a builtin thread pool that can be used for CPU intensive tasks. For -IO intensive tasks the ``async`` and ``await`` features should be +IO intensive tasks the `async` and `await` features should be used instead. Both parallel and spawn need the `threadpool `_ module to work. -Somewhat confusingly, ``spawn`` is also used in the ``parallel`` statement -with slightly different semantics. ``spawn`` always takes a call expression of -the form ``f(a, ...)``. Let ``T`` be ``f``'s return type. If ``T`` is ``void`` -then ``spawn``'s return type is also ``void`` otherwise it is ``FlowVar[T]``. +Somewhat confusingly, `spawn` is also used in the `parallel` statement +with slightly different semantics. `spawn` always takes a call expression of +the form `f(a, ...)`. Let `T` be `f`'s return type. If `T` is `void` +then `spawn`'s return type is also `void` otherwise it is `FlowVar[T]`. -Within a ``parallel`` section sometimes the ``FlowVar[T]`` is eliminated -to ``T``. This happens when ``T`` does not contain any GC'ed memory. -The compiler can ensure the location in ``location = spawn f(...)`` is not -read prematurely within a ``parallel`` section and so there is no need for -the overhead of an indirection via ``FlowVar[T]`` to ensure correctness. +Within a `parallel` section sometimes the `FlowVar[T]` is eliminated +to `T`. This happens when `T` does not contain any GC'ed memory. +The compiler can ensure the location in `location = spawn f(...)` is not +read prematurely within a `parallel` section and so there is no need for +the overhead of an indirection via `FlowVar[T]` to ensure correctness. -**Note**: Currently exceptions are not propagated between ``spawn``'ed tasks! +**Note**: Currently exceptions are not propagated between `spawn`'ed tasks! Spawn statement @@ -1415,25 +1417,25 @@ Spawn statement sync() For reasons of type safety and implementation simplicity the expression -that ``spawn`` takes is restricted: +that `spawn` takes is restricted: -* It must be a call expression ``f(a, ...)``. -* ``f`` must be ``gcsafe``. -* ``f`` must not have the calling convention ``closure``. -* ``f``'s parameters may not be of type ``var``. - This means one has to use raw ``ptr``'s for data passing reminding the +* It must be a call expression `f(a, ...)`. +* `f` must be `gcsafe`. +* `f` must not have the calling convention `closure`. +* `f`'s parameters may not be of type `var`. + This means one has to use raw `ptr`'s for data passing reminding the programmer to be careful. -* ``ref`` parameters are deeply copied which is a subtle semantic change and +* `ref` parameters are deeply copied which is a subtle semantic change and can cause performance problems but ensures memory safety. This deep copy - is performed via ``system.deepCopy`` and so can be overridden. -* For *safe* data exchange between ``f`` and the caller a global ``TChannel`` + is performed via `system.deepCopy` and so can be overridden. +* For *safe* data exchange between `f` and the caller a global `TChannel` needs to be used. However, since spawn can return a result, often no further communication is required. -``spawn`` executes the passed expression on the thread pool and returns -a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading -with the ``^`` operator is **blocking**. However, one can use ``blockUntilAny`` to +`spawn` executes the passed expression on the thread pool and returns +a `data flow variable`:idx: `FlowVar[T]` that can be read from. The reading +with the `^` operator is **blocking**. However, one can use `blockUntilAny` to wait on multiple flow variables at the same time: .. code-block:: nim @@ -1450,8 +1452,8 @@ wait on multiple flow variables at the same time: discard blockUntilAny(responses) Data flow variables ensure that no data races -are possible. Due to technical limitations not every type ``T`` is possible in -a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq`` +are possible. Due to technical limitations not every type `T` is possible in +a data flow variable: `T` has to be of the type `ref`, `string`, `seq` or of a type that doesn't contain a type that is garbage collected. This restriction is not hard to work-around in practice. @@ -1483,7 +1485,7 @@ Example: The parallel statement is the preferred mechanism to introduce parallelism in a -Nim program. A subset of the Nim language is valid within a ``parallel`` +Nim program. A subset of the Nim language is valid within a `parallel` section. This subset is checked during semantic analysis to be free of data races. A sophisticated `disjoint checker`:idx: ensures that no data races are possible even though shared memory is extensively supported! @@ -1491,25 +1493,25 @@ possible even though shared memory is extensively supported! The subset is in fact the full language with the following restrictions / changes: -* ``spawn`` within a ``parallel`` section has special semantics. -* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where - ``dest`` is part of the pattern ``dest = spawn f(...)`` has to be +* `spawn` within a `parallel` section has special semantics. +* Every location of the form `a[i]` and `a[i..j]` and `dest` where + `dest` is part of the pattern `dest = spawn f(...)` has to be provably disjoint. This is called the *disjoint check*. -* Every other complex location ``loc`` that is used in a spawned - proc (``spawn f(loc)``) has to be immutable for the duration of - the ``parallel`` section. This is called the *immutability check*. Currently +* Every other complex location `loc` that is used in a spawned + proc (`spawn f(loc)`) has to be immutable for the duration of + the `parallel` section. This is called the *immutability check*. Currently it is not specified what exactly "complex location" means. We need to make this an optimization! * Every array access has to be provably within bounds. This is called the *bounds check*. * Slices are optimized so that no copy is performed. This optimization is not - yet performed for ordinary slices outside of a ``parallel`` section. + yet performed for ordinary slices outside of a `parallel` section. Guards and locks ================ -Apart from ``spawn`` and ``parallel`` Nim also provides all the common low level +Apart from `spawn` and `parallel` Nim also provides all the common low level concurrency mechanisms like locks, atomic intrinsics or condition variables. Nim significantly improves on the safety of these features via additional @@ -1528,13 +1530,13 @@ Guards and the locks section Protecting global variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Object fields and global variables can be annotated via a ``guard`` pragma: +Object fields and global variables can be annotated via a `guard` pragma: .. code-block:: nim var glock: TLock var gdata {.guard: glock.}: int -The compiler then ensures that every access of ``gdata`` is within a ``locks`` +The compiler then ensures that every access of `gdata` is within a `locks` section: .. code-block:: nim @@ -1547,11 +1549,11 @@ section: {.locks: [glock].}: echo gdata -Top level accesses to ``gdata`` are always allowed so that it can be initialized +Top level accesses to `gdata` are always allowed so that it can be initialized conveniently. It is *assumed* (but not enforced) that every top level statement is executed before any concurrent action happens. -The ``locks`` section deliberately looks ugly because it has no runtime +The `locks` section deliberately looks ugly because it has no runtime semantics and should not be used directly! It should only be used in templates that also implement some form of locking at runtime: @@ -1580,7 +1582,7 @@ model low level lockfree mechanisms: echo atomicRead(atomicCounter) -The ``locks`` pragma takes a list of lock expressions ``locks: [a, b, ...]`` +The `locks` pragma takes a list of lock expressions `locks: [a, b, ...]` in order to support *multi lock* statements. Why these are essential is explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. @@ -1588,7 +1590,7 @@ explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. Protecting general locations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``guard`` annotation can also be used to protect fields within an object. +The `guard` annotation can also be used to protect fields within an object. The guard then needs to be another field within the same object or a global variable. @@ -1606,7 +1608,7 @@ expressivity of the language: lock counters[i].L: inc counters[i].v -The access to field ``x.v`` is allowed since its guard ``x.L`` is active. +The access to field `x.v` is allowed since its guard `x.L` is active. After template expansion, this amounts to: .. code-block:: nim @@ -1619,10 +1621,10 @@ After template expansion, this amounts to: finally: pthread_mutex_unlock(counters[i].L) -There is an analysis that checks that ``counters[i].L`` is the lock that -corresponds to the protected location ``counters[i].v``. This analysis is called +There is an analysis that checks that `counters[i].L` is the lock that +corresponds to the protected location `counters[i].v`. This analysis is called `path analysis`:idx: because it deals with paths to locations -like ``obj.field[i].fieldB[j]``. +like `obj.field[i].fieldB[j]`. The path analysis is **currently unsound**, but that doesn't make it useless. Two paths are considered equivalent if they are syntactically the same. @@ -1644,10 +1646,10 @@ potential deadlocks during semantic analysis. A lock level is an constant integer in the range 0..1_000. Lock level 0 means that no lock is acquired at all. -If a section of code holds a lock of level ``M`` than it can also acquire any -lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks +If a section of code holds a lock of level `M` than it can also acquire any +lock of level `N < M`. Another lock of level `M` cannot be acquired. Locks of the same level can only be acquired *at the same time* within a -single ``locks`` section: +single `locks` section: .. code-block:: nim var a, b: TLock[2] @@ -1672,8 +1674,8 @@ single ``locks`` section: Here is how a typical multilock statement can be implemented in Nim. Note how -the runtime check is required to ensure a global ordering for two locks ``a`` -and ``b`` of the same lock level: +the runtime check is required to ensure a global ordering for two locks `a` +and `b` of the same lock level: .. code-block:: nim template multilock(a, b: ptr TLock; body: untyped) = @@ -1691,9 +1693,9 @@ and ``b`` of the same lock level: pthread_mutex_unlock(b) -Whole routines can also be annotated with a ``locks`` pragma that takes a lock +Whole routines can also be annotated with a `locks` pragma that takes a lock level. This then means that the routine may acquire locks of up to this level. -This is essential so that procs can be called within a ``locks`` section: +This is essential so that procs can be called within a `locks` section: .. code-block:: nim proc p() {.locks: 3.} = discard @@ -1704,17 +1706,17 @@ This is essential so that procs can be called within a ``locks`` section: p() -As usual ``locks`` is an inferred effect and there is a subtype -relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` +As usual `locks` is an inferred effect and there is a subtype +relation: `proc () {.locks: N.}` is a subtype of `proc () {.locks: M.}` iff (M <= N). -The ``locks`` pragma can also take the special value ``"unknown"``. This +The `locks` pragma can also take the special value `"unknown"`. This is useful in the context of dynamic method dispatching. In the following -example, the compiler can infer a lock level of 0 for the ``base`` case. +example, the compiler can infer a lock level of 0 for the `base` case. However, one of the overloaded methods calls a procvar which is -potentially locking. Thus, the lock level of calling ``g.testMethod`` +potentially locking. Thus, the lock level of calling `g.testMethod` cannot be inferred statically, leading to compiler warnings. By using -``{.locks: "unknown".}``, the base method can be marked explicitly as +`{.locks: "unknown".}`, the base method can be marked explicitly as having unknown lock level as well: .. code-block:: nim @@ -1736,8 +1738,8 @@ they will rewrite as long as there is a match. There was no way to ensure some rewrite happens only once, e.g. when rewriting term to same term plus extra content. -``noRewrite`` pragma can actually prevent further rewriting on marked code, -e.g. with given example ``echo("ab")`` will be rewritten just once: +`noRewrite` pragma can actually prevent further rewriting on marked code, +e.g. with given example `echo("ab")` will be rewritten just once: .. code-block:: nim template pwnEcho{echo(x)}(x: untyped) = @@ -1745,7 +1747,7 @@ e.g. with given example ``echo("ab")`` will be rewritten just once: echo "ab" -``noRewrite`` pragma can be useful to control term-rewriting macros recursion. +`noRewrite` pragma can be useful to control term-rewriting macros recursion. Aliasing restrictions in parameter passing @@ -1755,8 +1757,8 @@ Aliasing restrictions in parameter passing implementation and need to be fleshed out further. "Aliasing" here means that the underlying storage locations overlap in memory -at runtime. An "output parameter" is a parameter of type ``var T``, -an input parameter is any parameter that is not of type ``var``. +at runtime. An "output parameter" is a parameter of type `var T`, +an input parameter is any parameter that is not of type `var`. 1. Two output parameters should never be aliased. 2. An input and an output parameter should not be aliased. @@ -1767,25 +1769,25 @@ an input parameter is any parameter that is not of type ``var``. One problem with rules 3 and 4 is that they affect specific global or thread local variables, but Nim's effect tracking only tracks "uses no global variable" -via ``.noSideEffect``. The rules 3 and 4 can also be approximated by a different rule: +via `.noSideEffect`. The rules 3 and 4 can also be approximated by a different rule: 5. A global or thread local variable (or a location derived from such a location) - can only passed to a parameter of a ``.noSideEffect`` proc. + can only passed to a parameter of a `.noSideEffect` proc. Noalias annotation ================== -Since version 1.4 of the Nim compiler, there is a ``.noalias`` annotation for variables -and parameters. It is mapped directly to C/C++'s ``restrict`` keyword and means that +Since version 1.4 of the Nim compiler, there is a `.noalias` annotation for variables +and parameters. It is mapped directly to C/C++'s `restrict` keyword and means that the underlying pointer is pointing to a unique location in memory, no other aliases to this location exist. It is *unchecked* that this alias restriction is followed, if the restriction is violated, the backend optimizer is free to miscompile the code. This is an **unsafe** language feature. Ideally in later versions of the language, the restriction will be enforced at -compile time. (Which is also why the name ``noalias`` was choosen instead of a more -verbose name like ``unsafeAssumeNoAlias``.) +compile time. (Which is also why the name `noalias` was choosen instead of a more +verbose name like `unsafeAssumeNoAlias`.) Strict funcs @@ -1796,7 +1798,7 @@ to the existing rule that a side effect is calling a function with side effects the following rule is also enforced: Any mutation to an object does count as a side effect if that object is reachable -via a parameter that is not declared as a ``var`` parameter. +via a parameter that is not declared as a `var` parameter. For example: @@ -1830,14 +1832,14 @@ the `view types section <#view-types-algorithm>`_. View types ========== -**Note**: ``--experimental:views`` is more effective -with ``--experimental:strictFuncs``. +**Note**: `--experimental:views` is more effective +with `--experimental:strictFuncs`. A view type is a type that is or contains one of the following types: -- ``var T`` (mutable view into ``T``) -- ``lent T`` (immutable view into ``T``) -- ``openArray[T]`` (pair of (pointer to array of ``T``, size)) +- `var T` (mutable view into `T`) +- `lent T` (immutable view into `T`) +- `openArray[T]` (pair of (pointer to array of `T`, size)) For example: @@ -1850,7 +1852,7 @@ For example: View4 = Table[openArray[char], int] -Exceptions to this rule are types constructed via ``ptr`` or ``proc``. +Exceptions to this rule are types constructed via `ptr` or `proc`. For example, the following types are **not** view types: .. code-block:: nim @@ -1861,13 +1863,13 @@ For example, the following types are **not** view types: NotView3 = ptr array[4, var int] -A *mutable* view type is a type that is or contains a ``var T`` type. +A *mutable* view type is a type that is or contains a `var T` type. An *immutable* view type is a view type that is not a mutable view type. A *view* is a symbol (a let, var, const, etc.) that has a view type. Since version 1.4 Nim allows view types to be used as local variables. -This feature needs to be enabled via ``{.experimental: "views".}``. +This feature needs to be enabled via `{.experimental: "views".}`. A local variable of a view type *borrows* from the locations and it is statically enforced that the view does not outlive the location @@ -1901,47 +1903,47 @@ For example: A local variable of a view type can borrow from a location -derived from a parameter, another local variable, a global ``const`` or ``let`` -symbol or a thread-local ``var`` or ``let``. +derived from a parameter, another local variable, a global `const` or `let` +symbol or a thread-local `var` or `let`. -Let ``p`` the proc that is analysed for the correctness of the borrow operation. +Let `p` the proc that is analysed for the correctness of the borrow operation. -Let ``source`` be one of: +Let `source` be one of: -- A formal parameter of ``p``. Note that this does not cover parameters of +- A formal parameter of `p`. Note that this does not cover parameters of inner procs. -- The ``result`` symbol of ``p``. -- A local ``var`` or ``let`` or ``const`` of ``p``. Note that this does +- The `result` symbol of `p`. +- A local `var` or `let` or `const` of `p`. Note that this does not cover locals of inner procs. -- A thread-local ``var`` or ``let``. -- A global ``let`` or ``const``. +- A thread-local `var` or `let`. +- A global `let` or `const`. - A constant array/seq/object/tuple constructor. Path expressions ---------------- -A location derived from ``source`` is then defined as a path expression that -has ``source`` as the owner. A path expression ``e`` is defined recursively: +A location derived from `source` is then defined as a path expression that +has `source` as the owner. A path expression `e` is defined recursively: -- ``source`` itself is a path expression. -- Container access like ``e[i]`` is a path expression. -- Tuple access ``e[0]`` is a path expression. -- Object field access ``e.field`` is a path expression. -- ``system.toOpenArray(e, ...)`` is a path expression. -- Pointer dereference ``e[]`` is a path expression. -- An address ``addr e``, ``unsafeAddr e`` is a path expression. -- A type conversion ``T(e)`` is a path expression. -- A cast expression ``cast[T](e)`` is a path expression. -- ``f(e, ...)`` is a path expression if ``f``'s return type is a view type. - Because the view can only have been borrowed from ``e``, we then know - that owner of ``f(e, ...)`` is ``e``. +- `source` itself is a path expression. +- Container access like `e[i]` is a path expression. +- Tuple access `e[0]` is a path expression. +- Object field access `e.field` is a path expression. +- `system.toOpenArray(e, ...)` is a path expression. +- Pointer dereference `e[]` is a path expression. +- An address `addr e`, `unsafeAddr e` is a path expression. +- A type conversion `T(e)` is a path expression. +- A cast expression `cast[T](e)` is a path expression. +- `f(e, ...)` is a path expression if `f`'s return type is a view type. + Because the view can only have been borrowed from `e`, we then know + that owner of `f(e, ...)` is `e`. If a view type is used as a return type, the location must borrow from a location that is derived from the first parameter that is passed to the proc. See https://nim-lang.org/docs/manual.html#procedures-var-return-type for -details about how this is done for ``var T``. +details about how this is done for `var T`. A mutable view can borrow from a mutable location, an immutable view can borrow from both a mutable or an immutable location. @@ -1979,8 +1981,8 @@ The scope of the view does not matter: The analysis requires as much precision about mutations as is reasonably obtainable, so it is more effective with the experimental `strict funcs <#strict-funcs>`_ -feature. In other words ``--experimental:views`` works better -with ``--experimental:strictFuncs``. +feature. In other words `--experimental:views` works better +with `--experimental:strictFuncs`. The analysis is currently control flow insensitive: @@ -1992,8 +1994,8 @@ The analysis is currently control flow insensitive: s.setLen 0 echo v.field -In this example, the compiler assumes that ``s.setLen 0`` invalidates the -borrow operation of ``v`` even though a human being can easily see that it +In this example, the compiler assumes that `s.setLen 0` invalidates the +borrow operation of `v` even though a human being can easily see that it will never do that at runtime. @@ -2016,9 +2018,9 @@ A borrow operation ends with the last usage of the view variable. Reborrows --------- -A view ``v`` can borrow from multiple different locations. However, the borrow -is always the full span of ``v``'s lifetime and every location that is borrowed -from is sealed during ``v``'s lifetime. +A view `v` can borrow from multiple different locations. However, the borrow +is always the full span of `v`'s lifetime and every location that is borrowed +from is sealed during `v`'s lifetime. Algorithm @@ -2034,41 +2036,41 @@ a notion of an "abstract time", in the implementation it's a simple integer that incremented for every visited node. In the second pass information about the underlying object "graphs" is computed. -Let ``v`` be a parameter or a local variable. Let ``G(v)`` be the graph -that ``v`` belongs to. A graph is defined by the set of variables that belong -to the graph. Initially for all ``v``: ``G(v) = {v}``. Every variable can only +Let `v` be a parameter or a local variable. Let `G(v)` be the graph +that `v` belongs to. A graph is defined by the set of variables that belong +to the graph. Initially for all `v`: `G(v) = {v}`. Every variable can only be part of a single graph. -Assignments like ``a = b`` "connect" two variables, both variables end up in the -same graph ``{a, b} = G(a) = G(b)``. Unfortunately, the pattern to look for is +Assignments like `a = b` "connect" two variables, both variables end up in the +same graph `{a, b} = G(a) = G(b)`. Unfortunately, the pattern to look for is much more complex than that and can involve multiple assignment targets and sources:: f(x, y) = g(a, b) -connects ``x`` and ``y`` to ``a`` and ``b``: ``G(x) = G(y) = G(a) = G(b) = {x, y, a, b}``. +connects `x` and `y` to `a` and `b`: `G(x) = G(y) = G(a) = G(b) = {x, y, a, b}`. A type based alias analysis rules out some of these combinations, for example -a ``string`` value cannot possibly be connected to a ``seq[int]``. +a `string` value cannot possibly be connected to a `seq[int]`. -A pattern like ``v[] = value`` or ``v.field = value`` marks ``G(v)`` as mutated. +A pattern like `v[] = value` or `v.field = value` marks `G(v)` as mutated. After the second pass a set of disjoint graphs was computed. For strict functions it is then enforced that there is no graph that is both mutated and has an element that is an immutable parameter (that is a parameter that is not -of type ``var T``). +of type `var T`). -For borrow checking a different set of checks is performed. Let ``v`` be the view -and ``b`` the location that is borrowed from. +For borrow checking a different set of checks is performed. Let `v` be the view +and `b` the location that is borrowed from. -- The lifetime of ``v`` must not exceed ``b``'s lifetime. Note: The lifetime of +- The lifetime of `v` must not exceed `b`'s lifetime. Note: The lifetime of a parameter is the complete proc body. -- If ``v`` is a mutable view and ``v`` is used to actually mutate the - borrowed location, then ``b`` has to be a mutable location. +- If `v` is a mutable view and `v` is used to actually mutate the + borrowed location, then `b` has to be a mutable location. Note: If it is not actually used for mutation, borrowing a mutable view from an immutable location is allowed! This allows for many important idioms and will be justified in an upcoming RFC. -- During ``v``'s lifetime, ``G(b)`` can only be modified by ``v`` (and only if - ``v`` is a mutable view). -- If ``v`` is ``result`` then ``b`` has to be a location derived from the first +- During `v`'s lifetime, `G(b)` can only be modified by `v` (and only if + `v` is a mutable view). +- If `v` is `result` then `b` has to be a location derived from the first formal parameter or from a constant location. - A view cannot be used for a read or a write access before it was assigned to. diff --git a/doc/manual_experimental_strictnotnil.rst b/doc/manual_experimental_strictnotnil.rst index 10b59a74e..c7c045683 100644 --- a/doc/manual_experimental_strictnotnil.rst +++ b/doc/manual_experimental_strictnotnil.rst @@ -1,3 +1,4 @@ +.. default-role:: code Strict not nil checking ========================= @@ -14,9 +15,9 @@ or In the second case it would check builtin and imported modules as well. -It checks the nilability of ref-like types and makes dereferencing safer based on flow typing and ``not nil`` annotations. +It checks the nilability of ref-like types and makes dereferencing safer based on flow typing and `not nil` annotations. -Its implementation is different than the ``notnil`` one: defined under ``strictNotNil``. Keep in mind the difference in option names, be careful with distinguishing them. +Its implementation is different than the `notnil` one: defined under `strictNotNil`. Keep in mind the difference in option names, be careful with distinguishing them. We check several kinds of types for nilability: @@ -28,14 +29,14 @@ We check several kinds of types for nilability: nil ------- -The default kind of nilability types is the nilable kind: they can have the value ``nil``. -If you have a non-nilable type ``T``, you can use ``T nil`` to get a nilable type for it. +The default kind of nilability types is the nilable kind: they can have the value `nil`. +If you have a non-nilable type `T`, you can use `T nil` to get a nilable type for it. not nil -------- -You can annotate a type where nil isn't a valid value with ``not nil``. +You can annotate a type where nil isn't a valid value with `not nil`. .. code-block:: nim type @@ -58,40 +59,40 @@ You can annotate a type where nil isn't a valid value with ``not nil``. -If a type can include ``nil`` as a valid value, dereferencing values of the type -is checked by the compiler: if a value which might be nil is derefenced, this produces a warning by default, you can turn this into an error using the compiler options ``--warningAsError:strictNotNil`` +If a type can include `nil` as a valid value, dereferencing values of the type +is checked by the compiler: if a value which might be nil is derefenced, this produces a warning by default, you can turn this into an error using the compiler options `--warningAsError:strictNotNil` -If a type is nilable, you should dereference its values only after a ``isNil`` or equivalent check. +If a type is nilable, you should dereference its values only after a `isNil` or equivalent check. local turn on/off --------------------- -You can still turn off nil checking on function/module level by using a ``{.strictNotNil: off}.`` pragma. +You can still turn off nil checking on function/module level by using a `{.strictNotNil: off}.` pragma. Note: test that/TODO for code/manual. nilability state ----------------- -Currently a nilable value can be ``Safe``, ``MaybeNil`` or ``Nil`` : we use internally ``Parent`` and ``Unreachable`` but this is an implementation detail(a parent layer has the actual nilability). +Currently a nilable value can be `Safe`, `MaybeNil` or `Nil` : we use internally `Parent` and `Unreachable` but this is an implementation detail(a parent layer has the actual nilability). -``Safe`` means it shouldn't be nil at that point: e.g. after assignment to a non-nil value or ``not a.isNil`` check -``MaybeNil`` means it might be nil, but it might not be nil: e.g. an argument, a call argument or a value after an ``if`` and ``else``. -``Nil`` means it should be nil at that point; e.g. after an assignment to ``nil`` or a ``.isNil`` check. +`Safe` means it shouldn't be nil at that point: e.g. after assignment to a non-nil value or `not a.isNil` check +`MaybeNil` means it might be nil, but it might not be nil: e.g. an argument, a call argument or a value after an `if` and `else`. +`Nil` means it should be nil at that point; e.g. after an assignment to `nil` or a `.isNil` check. -``Unreachable`` means it shouldn't be possible to access this in this branch: so we do generate a warning as well. +`Unreachable` means it shouldn't be possible to access this in this branch: so we do generate a warning as well. -We show an error for each dereference (``[]``, ``.field``, ``[index]`` ``()`` etc) which is of a tracked expression which is -in ``MaybeNil`` or ``Nil`` state. +We show an error for each dereference (`[]`, `.field`, `[index]` `()` etc) which is of a tracked expression which is +in `MaybeNil` or `Nil` state. type nilability ---------------- Types are either nilable or non-nilable. -When you pass a param or a default value, we use the type : for nilable types we return ``MaybeNil`` -and for non-nilable ``Safe``. +When you pass a param or a default value, we use the type : for nilable types we return `MaybeNil` +and for non-nilable `Safe`. -TODO: fix the manual here. (This is not great, as default values for non-nilables and nilables are usually actually ``nil`` , so we should think a bit more about this section.) +TODO: fix the manual here. (This is not great, as default values for non-nilables and nilables are usually actually `nil` , so we should think a bit more about this section.) params rules ------------ @@ -102,9 +103,9 @@ Param's nilability is detected based on type nilability. We use the type of the assignment rules ----------------- -Let's say we have ``left = right``. +Let's say we have `left = right`. -When we assign, we pass the right's nilability to the left's expression. There should be special handling of aliasing and compound expressions which we specify in their sections. (Assignment is a possible alias ``move`` or ``move out``). +When we assign, we pass the right's nilability to the left's expression. There should be special handling of aliasing and compound expressions which we specify in their sections. (Assignment is a possible alias `move` or `move out`). call args rules ----------------- @@ -114,20 +115,20 @@ When we call with arguments, we have two cases when we might change the nilabili .. code-block:: nim callByVar(a) -Here ``callByVar`` can re-assign ``a``, so this might change ``a``'s nilability, so we change it to ``MaybeNil``. -This is also a possible aliasing ``move out`` (moving out of a current alias set). +Here `callByVar` can re-assign `a`, so this might change `a`'s nilability, so we change it to `MaybeNil`. +This is also a possible aliasing `move out` (moving out of a current alias set). .. code-block:: nim call(a) -Here ``call`` can change a field or element of ``a``, so if we have a dependant expression of ``a`` : e.g. ``a.field``. Dependats become ``MaybeNil``. +Here `call` can change a field or element of `a`, so if we have a dependant expression of `a` : e.g. `a.field`. Dependats become `MaybeNil`. branches rules --------------- Branches are the reason we do nil checking like this: with flow checking. -Sources of brancing are ``if``, ``while``, ``for``, ``and``, ``or``, ``case``, ``try`` and combinations with ``return``, ``break``, ``continue`` and ``raise`` +Sources of brancing are `if`, `while`, `for`, `and`, `or`, `case`, `try` and combinations with `return`, `break`, `continue` and `raise` We create a new layer/"scope" for each branch where we map expressions to nilability. This happens when we "fork": usually on the beginning of a construct. When branches "join" we usually unify their expression maps or/and nilabilities. @@ -142,33 +143,33 @@ Merging usually merges maps and alias sets: nilabilities are merged like this: else: MaybeNil -Special handling is for ``.isNil`` and `` == nil``, also for ``not``, ``and`` and ``or``. +Special handling is for `.isNil` and ` == nil`, also for `not`, `and` and `or`. -``not`` reverses the nilability, ``and`` is similar to "forking" : the right expression is checked in the layer resulting from the left one and ``or`` is similar to "merging": the right and left expression should be both checked in the original layer. +`not` reverses the nilability, `and` is similar to "forking" : the right expression is checked in the layer resulting from the left one and `or` is similar to "merging": the right and left expression should be both checked in the original layer. -``isNil``, ``== nil`` make expressions ``Nil``. If there is a ``not`` or ``!= nil``, they make them ``Safe``. -We also reverse the nilability in the opposite branch: e.g. ``else``. +`isNil`, `== nil` make expressions `Nil`. If there is a `not` or `!= nil`, they make them `Safe`. +We also reverse the nilability in the opposite branch: e.g. `else`. compound expressions: field, index expressions ----------------------------------------------- We want to track also field(dot) and index(bracket) expressions. -We track some of those compound expressions which might be nilable as dependants of their bases: ``a.field`` is changed if ``a`` is moved (re-assigned), -similarly ``a[index]`` is dependent on ``a`` and ``a.field.field`` on ``a.field``. +We track some of those compound expressions which might be nilable as dependants of their bases: `a.field` is changed if `a` is moved (re-assigned), +similarly `a[index]` is dependent on `a` and `a.field.field` on `a.field`. -When we move the base, we update dependants to ``MaybeNil``. Otherwise we usually start with type nilability. +When we move the base, we update dependants to `MaybeNil`. Otherwise we usually start with type nilability. -When we call args, we update the nilability of their dependants to ``MaybeNil`` as the calls usually can change them. -We might need to check for ``strictFuncs`` pure funcs and not do that then. +When we call args, we update the nilability of their dependants to `MaybeNil` as the calls usually can change them. +We might need to check for `strictFuncs` pure funcs and not do that then. -For field expressions ``a.field``, we calculate an integer value based on a hash of the tree and just accept equivalent trees as equivalent expressions. +For field expressions `a.field`, we calculate an integer value based on a hash of the tree and just accept equivalent trees as equivalent expressions. -For item expression ``a[index]``, we also calculate an integer value based on a hash of the tree and accept equivalent trees as equivalent expressions: for static values only. -For now we support only constant indices: we dont track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the ``{.warning[StrictCheckNotNil]:off}.``. +For item expression `a[index]`, we also calculate an integer value based on a hash of the tree and accept equivalent trees as equivalent expressions: for static values only. +For now we support only constant indices: we dont track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the `{.warning[StrictCheckNotNil]:off}.`. -For bracket expressions, in the future we might count ``a[]`` as the same general expression. -This means we should should the index but otherwise handle it the same for assign (maybe "aliasing" all the non-static elements) and differentiate only for static: e.g. ``a[0]`` and ``a[1]``. +For bracket expressions, in the future we might count `a[]` as the same general expression. +This means we should should the index but otherwise handle it the same for assign (maybe "aliasing" all the non-static elements) and differentiate only for static: e.g. `a[0]` and `a[1]`. element tracking ----------------- @@ -185,8 +186,8 @@ Also related to tracking initialization of expressions/fields. unstructured control flow rules ------------------------------- -Unstructured control flow keywords as ``return``, ``break``, ``continue``, ``raise`` mean that we jump from a branch out. -This means that if there is code after the finishing of the branch, it would be ran if one hasn't hit the direct parent branch of those: so it is similar to an ``else``. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g. +Unstructured control flow keywords as `return`, `break`, `continue`, `raise` mean that we jump from a branch out. +This means that if there is code after the finishing of the branch, it would be ran if one hasn't hit the direct parent branch of those: so it is similar to an `else`. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g. .. code-block:: nim for a in c: @@ -204,14 +205,14 @@ We support alias detection for local expressions. We track sets of aliased expressions. We start with all nilable local expressions in separate sets. Assignments and other changes to nilability can move / move out expressions of sets. -``move``: Moving ``left`` to ``right`` means we remove ``left`` from its current set and unify it with the ``right``'s set. +`move`: Moving `left` to `right` means we remove `left` from its current set and unify it with the `right`'s set. This means it stops being aliased with its previous aliases. .. code-block:: nim var left = b left = right # moving left to right -``move out``: Moving out ``left`` might remove it from the current set and ensure that it's in its own set as a single element. +`move out`: Moving out `left` might remove it from the current set and ensure that it's in its own set as a single element. e.g. @@ -229,7 +230,7 @@ warnings and errors --------------------- We show an error for each dereference (`[]`, `.field`, `[index]` `()` etc) which is of a tracked expression which is -in ``MaybeNil`` or ``Nil`` state. +in `MaybeNil` or `Nil` state. We might also show a history of the transitions and the reasons for them that might change the nilability of the expression. diff --git a/doc/nep1.rst b/doc/nep1.rst index 4a31524f6..3bae6a00b 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================================================== Nim Enhancement Proposal #1 - Standard Library Style Guide ========================================================== @@ -124,11 +126,11 @@ Naming Conventions - In the age of HTTP, HTML, FTP, TCP, IP, UTF, WWW it is foolish to pretend these are somewhat special words requiring all uppercase. Instead treat them - as what they are: Real words. So it's ``parseUrl`` rather than - ``parseURL``, ``checkHttpHeader`` instead of ``checkHTTPHeader`` etc. + as what they are: Real words. So it's `parseUrl` rather than + `parseURL`, `checkHttpHeader` instead of `checkHTTPHeader` etc. -- Operations like ``mitems`` or ``mpairs`` (or the now deprecated ``mget``) - that allow a *mutating view* into some data structure should start with an ``m``. +- Operations like `mitems` or `mpairs` (or the now deprecated `mget`) + that allow a *mutating view* into some data structure should start with an `m`. - When both in-place mutation and 'returns transformed copy' are available the latter is a past participle of the former: @@ -136,8 +138,8 @@ Naming Conventions - sort and sorted - rotate and rotated -- When the 'returns transformed copy' version already exists like ``strutils.replace`` - an in-place version should get an ``-In`` suffix (``replaceIn`` for this example). +- When the 'returns transformed copy' version already exists like `strutils.replace` + an in-place version should get an `-In` suffix (`replaceIn` for this example). - Use `subjectVerb`, not `verbSubject`, e.g.: `fileExists`, not `existsFile`. @@ -153,25 +155,25 @@ to keep the names short but meaningful. ------------------- ------------ -------------------------------------- English word To use Notes ------------------- ------------ -------------------------------------- -initialize initFoo initializes a value type ``Foo`` -new newFoo initializes a reference type ``Foo`` - via ``new`` +initialize initFoo initializes a value type `Foo` +new newFoo initializes a reference type `Foo` + via `new` this or self self for method like procs, e.g.: `proc fun(self: Foo, a: int)` rationale: `self` is more unique in English than `this`, and `foo` would not be DRY. find find should return the position where something was found; for a bool result - use ``contains`` -contains contains often short for ``find() >= 0`` -append add use ``add`` instead of ``append`` + use `contains` +contains contains often short for `find() >= 0` +append add use `add` instead of `append` compare cmp should return an int with the - ``< 0`` ``== 0`` or ``> 0`` semantics; - for a bool result use ``sameXYZ`` -put put, ``[]=`` consider overloading ``[]=`` for put -get get, ``[]`` consider overloading ``[]`` for get; - consider to not use ``get`` as a - prefix: ``len`` instead of ``getLen`` + `< 0` `== 0` or `> 0` semantics; + for a bool result use `sameXYZ` +put put, `[]=` consider overloading `[]=` for put +get get, `[]` consider overloading `[]` for get; + consider to not use `get` as a + prefix: `len` instead of `getLen` length len also used for *number of elements* size size, len size should refer to a byte size capacity cap @@ -236,8 +238,8 @@ Coding Conventions - Use a proc when possible, only using the more powerful facilities of macros, templates, iterators, and converters when necessary. -- Use the ``let`` statement (not the ``var`` statement) when declaring variables that - do not change within their scope. Using the ``let`` statement ensures that +- Use the `let` statement (not the `var` statement) when declaring variables that + do not change within their scope. Using the `let` statement ensures that variables remain immutable, and gives those who read the code a better idea of the code's purpose. diff --git a/doc/nimc.rst b/doc/nimc.rst index ea173691f..aad889591 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== Nim Compiler User Guide =================================== @@ -45,8 +47,8 @@ Advanced command-line switches are: List of warnings ---------------- -Each warning can be activated individually with ``--warning[NAME]:on|off`` or -in a ``push`` pragma. +Each warning can be activated individually with `--warning[NAME]:on|off` or +in a `push` pragma. ========================== ============================================ Name Description @@ -60,7 +62,7 @@ ConfigDeprecated The project makes use of a deprecated config file. SmallLshouldNotBeUsed The letter 'l' should not be used as an identifier. -EachIdentIsTuple The code contains a confusing ``var`` +EachIdentIsTuple The code contains a confusing `var` declaration. User Some user-defined warning. ========================== ============================================ @@ -69,8 +71,8 @@ User Some user-defined warning. List of hints ------------- -Each hint can be activated individually with ``--hint[NAME]:on|off`` or in a -``push`` pragma. +Each hint can be activated individually with `--hint[NAME]:on|off` or in a +`push` pragma. ========================== ============================================ Name Description @@ -129,52 +131,52 @@ Level Description Compile-time symbols -------------------- -Through the ``-d:x`` or ``--define:x`` switch you can define compile-time +Through the `-d:x` or `--define:x` switch you can define compile-time symbols for conditional compilation. The defined switches can be checked in source code with the `when statement `_ and `defined proc `_. The typical use of this switch is -to enable builds in release mode (``-d:release``) where optimizations are -enabled for better performance. Another common use is the ``-d:ssl`` switch to +to enable builds in release mode (`-d:release`) where optimizations are +enabled for better performance. Another common use is the `-d:ssl` switch to activate SSL sockets. -Additionally, you may pass a value along with the symbol: ``-d:x=y`` +Additionally, you may pass a value along with the symbol: `-d:x=y` which may be used in conjunction with the `compile-time define pragmas`_ to override symbols during build time. Compile-time symbols are completely **case insensitive** and underscores are -ignored too. ``--define:FOO`` and ``--define:foo`` are identical. +ignored too. `--define:FOO` and `--define:foo` are identical. -Compile-time symbols starting with the ``nim`` prefix are reserved for the +Compile-time symbols starting with the `nim` prefix are reserved for the implementation and should not be used elsewhere. Configuration files ------------------- -**Note:** The *project file name* is the name of the ``.nim`` file that is +**Note:** The *project file name* is the name of the `.nim` file that is passed as a command-line argument to the compiler. -The ``nim`` executable processes configuration files in the following +The `nim` executable processes configuration files in the following directories (in this order; later files overwrite previous settings): -1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. -2) If environment variable ``XDG_CONFIG_HOME`` is defined, ``$XDG_CONFIG_HOME/nim/nim.cfg`` or ``~/.config/nim/nim.cfg`` (POSIX) or ``%APPDATA%/nim/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. -3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command-line option. -4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command-line option. -5) A project can also have a project-specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command-line option. +1) `$nim/config/nim.cfg`, `/etc/nim/nim.cfg` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the `--skipCfg` command line option. +2) If environment variable `XDG_CONFIG_HOME` is defined, `$XDG_CONFIG_HOME/nim/nim.cfg` or `~/.config/nim/nim.cfg` (POSIX) or `%APPDATA%/nim/nim.cfg` (Windows). This file can be skipped with the `--skipUserCfg` command line option. +3) `$parentDir/nim.cfg` where `$parentDir` stands for any parent directory of the project file's path. These files can be skipped with the `--skipParentCfg` command-line option. +4) `$projectDir/nim.cfg` where `$projectDir` stands for the project file's path. This file can be skipped with the `--skipProjCfg` command-line option. +5) A project can also have a project-specific configuration file named `$project.nim.cfg` that resides in the same directory as `$project.nim`. This file can be skipped with the `--skipProjCfg` command-line option. Command-line settings have priority over configuration file settings. The default build of a project is a `debug build`:idx:. To compile a -`release build`:idx: define the ``release`` symbol:: +`release build`:idx: define the `release` symbol:: nim c -d:release myproject.nim - To compile a `dangerous release build`:idx: define the ``danger`` symbol:: + To compile a `dangerous release build`:idx: define the `danger` symbol:: nim c -d:danger myproject.nim @@ -186,10 +188,10 @@ Nim has the concept of a global search path (PATH) that is queried to determine where to find imported modules or include files. If multiple files are found an ambiguity error is produced. -``nim dump`` shows the contents of the PATH. +`nim dump` shows the contents of the PATH. However before the PATH is used the current directory is checked for the -file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the +file's existence. So if PATH contains `$lib` and `$lib/bar` and the directory structure looks like this:: $lib/x.nim @@ -198,27 +200,27 @@ directory structure looks like this:: foo/main.nim other.nim -And ``main`` imports ``x``, ``foo/x`` is imported. If ``other`` imports ``x`` -then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match but ``$lib/x.nim`` is used +And `main` imports `x`, `foo/x` is imported. If `other` imports `x` +then both `$lib/x.nim` and `$lib/bar/x.nim` match but `$lib/x.nim` is used as it is the first match. Generated C code directory -------------------------- The generated files that Nim produces all go into a subdirectory called -``nimcache``. Its full path is +`nimcache`. Its full path is -- ``$XDG_CACHE_HOME/nim/$projectname(_r|_d)`` or ``~/.cache/nim/$projectname(_r|_d)`` +- `$XDG_CACHE_HOME/nim/$projectname(_r|_d)` or `~/.cache/nim/$projectname(_r|_d)` on Posix -- ``$HOME/nimcache/$projectname(_r|_d)`` on Windows. +- `$HOME/nimcache/$projectname(_r|_d)` on Windows. -The ``_r`` suffix is used for release builds, ``_d`` is for debug builds. +The `_r` suffix is used for release builds, `_d` is for debug builds. This makes it easy to delete all generated files. -The ``--nimcache`` +The `--nimcache` `compiler switch <#compiler-usage-commandminusline-switches>`_ can be used to -to change the ``nimcache`` directory. +to change the `nimcache` directory. However, the generated C code is not platform-independent. C code generated for Linux does not compile on Windows, for instance. The comment on top of the @@ -232,16 +234,16 @@ To change the compiler from the default compiler (at the command line):: nim c --cc:llvm_gcc --compile_only myfile.nim -This uses the configuration defined in ``config\nim.cfg`` for ``lvm_gcc``. +This uses the configuration defined in ``config\nim.cfg`` for `lvm_gcc`. If nimcache already contains compiled code from a different compiler for the same project, -add the ``-f`` flag to force all files to be recompiled. +add the `-f` flag to force all files to be recompiled. The default compiler is defined at the top of ``config\nim.cfg``. -Changing this setting affects the compiler used by ``koch`` to (re)build Nim. +Changing this setting affects the compiler used by `koch` to (re)build Nim. -To use the ``CC`` environment variable, use ``nim c --cc:env myfile.nim``. To use the -``CXX`` environment variable, use ``nim cpp --cc:env myfile.nim``. ``--cc:env`` is available +To use the `CC` environment variable, use `nim c --cc:env myfile.nim`. To use the +`CXX` environment variable, use `nim cpp --cc:env myfile.nim`. `--cc:env` is available since Nim version 1.4. @@ -252,7 +254,7 @@ To cross compile, use for example:: nim c --cpu:i386 --os:linux --compileOnly --genScript myproject.nim -Then move the C code and the compile script ``compile_myproject.sh`` to your +Then move the C code and the compile script `compile_myproject.sh` to your Linux i386 machine and run the script. Another way is to make Nim invoke a cross compiler toolchain:: @@ -260,8 +262,8 @@ Another way is to make Nim invoke a cross compiler toolchain:: nim c --cpu:arm --os:linux myproject.nim For cross compilation, the compiler invokes a C compiler named -like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration -system is used to provide meaningful defaults. For example for ``ARM`` your +like `$cpu.$os.$cc` (for example arm.linux.gcc) and the configuration +system is used to provide meaningful defaults. For example for `ARM` your configuration file should contain something like:: arm.linux.gcc.path = "/usr/bin" @@ -275,7 +277,7 @@ To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain:: nim c -d:mingw myproject.nim -Use ``--cpu:i386`` or ``--cpu:amd64`` to switch the CPU architecture. +Use `--cpu:i386` or `--cpu:amd64` to switch the CPU architecture. The MinGW-w64 toolchain can be installed as follows:: @@ -295,7 +297,7 @@ The first one is to treat Android as a simple Linux and use directly on android as if it was Linux. These programs are console-only programs that can't be distributed in the Play Store. -Use regular ``nim c`` inside termux to make Android terminal programs. +Use regular `nim c` inside termux to make Android terminal programs. Normal Android apps are written in Java, to use Nim inside an Android app you need a small Java stub that calls out to a native library written in @@ -303,16 +305,16 @@ Nim using the `NDK `_. You can also use `native-activity `_ to have the Java stub be auto-generated for you. -Use ``nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on`` to +Use `nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on` to generate the C source files you need to include in your Android Studio project. Add the generated C files to CMake build script in your Android project. Then do the final compile with Android Studio which uses Gradle to call CMake to compile the project. -Because Nim is part of a library it can't have its own c style ``main()`` -so you would need to define your own ``android_main`` and init the Java +Because Nim is part of a library it can't have its own c style `main()` +so you would need to define your own `android_main` and init the Java environment, or use a library like SDL2 or GLFM to do it. After the Android -stuff is done, it's very important to call ``NimMain()`` in order to +stuff is done, it's very important to call `NimMain()` in order to initialize Nim's garbage collector and to run the top level statements of your program. @@ -331,14 +333,14 @@ Normal languages for iOS development are Swift and Objective C. Both of these use LLVM and can be compiled into object files linked together with C, C++ or Objective C code produced by Nim. -Use ``nim c -c --os:ios --noMain:on`` to generate C files and include them in +Use `nim c -c --os:ios --noMain:on` to generate C files and include them in your XCode project. Then you can use XCode to compile, link, package and sign everything. -Because Nim is part of a library it can't have its own c style ``main()`` so you -would need to define `main` that calls ``autoreleasepool`` and -``UIApplicationMain`` to do it, or use a library like SDL2 or GLFM. After -the iOS setup is done, it's very important to call ``NimMain()`` to +Because Nim is part of a library it can't have its own c style `main()` so you +would need to define `main` that calls `autoreleasepool` and +`UIApplicationMain` to do it, or use a library like SDL2 or GLFM. After +the iOS setup is done, it's very important to call `NimMain()` to initialize Nim's garbage collector and to run the top-level statements of your program. @@ -356,8 +358,8 @@ Cross-compilation for Nintendo Switch ===================================== Simply add --os:nintendoswitch -to your usual ``nim c`` or ``nim cpp`` command and set the ``passC`` -and ``passL`` command line switches to something like: +to your usual `nim c` or `nim cpp` command and set the `passC` +and `passL` command line switches to something like: .. code-block:: console nim c ... --passC="-I$DEVKITPRO/libnx/include" ... @@ -378,8 +380,8 @@ For example, with the above-mentioned config:: nim c --os:nintendoswitch switchhomebrew.nim -This will generate a file called ``switchhomebrew.elf`` which can then be turned into -an nro file with the ``elf2nro`` tool in the DevkitPro release. Examples can be found at +This will generate a file called `switchhomebrew.elf` which can then be turned into +an nro file with the `elf2nro` tool in the DevkitPro release. Examples can be found at `the nim-libnx github repo `_. There are a few things that don't work because the DevkitPro libraries don't support them. @@ -399,62 +401,62 @@ DLL generation Nim supports the generation of DLLs. However, there must be only one instance of the GC per process/address space. This instance is contained in -``nimrtl.dll``. This means that every generated Nim DLL depends -on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:: +`nimrtl.dll`. This means that every generated Nim DLL depends +on `nimrtl.dll`. To generate the "nimrtl.dll" file, use the command:: nim c -d:release lib/nimrtl.nim -To link against ``nimrtl.dll`` use the command:: +To link against `nimrtl.dll` use the command:: nim c -d:useNimRtl myprog.nim -**Note**: Currently the creation of ``nimrtl.dll`` with thread support has +**Note**: Currently the creation of `nimrtl.dll` with thread support has never been tested and is unlikely to work! Additional compilation switches =============================== -The standard library supports a growing number of ``useX`` conditional defines +The standard library supports a growing number of `useX` conditional defines affecting how some features are implemented. This section tries to give a complete list. ====================== ========================================================= Define Effect ====================== ========================================================= -``release`` Turns on the optimizer. +`release` Turns on the optimizer. More aggressive optimizations are possible, e.g.: - ``--passC:-ffast-math`` (but see issue #10305) -``danger`` Turns off all runtime checks and turns on the optimizer. -``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``. -``useNimRtl`` Compile and link against ``nimrtl.dll``. -``useMalloc`` Makes Nim use C's `malloc`:idx: instead of Nim's + `--passC:-ffast-math` (but see issue #10305) +`danger` Turns off all runtime checks and turns on the optimizer. +`useFork` Makes `osproc` use `fork` instead of `posix_spawn`. +`useNimRtl` Compile and link against `nimrtl.dll`. +`useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's own memory manager, albeit prefixing each allocation with its size to support clearing memory on reallocation. - This only works with ``gc:none``, ``gc:arc`` and - ``--gc:orc``. -``useRealtimeGC`` Enables support of Nim's GC for *soft* realtime + This only works with `gc:none`, `gc:arc` and + `--gc:orc`. +`useRealtimeGC` Enables support of Nim's GC for *soft* realtime systems. See the documentation of the `gc `_ for further information. -``logGC`` Enable GC logging to stdout. -``nodejs`` The JS target is actually ``node.js``. -``ssl`` Enables OpenSSL support for the sockets module. -``memProfiler`` Enables memory profiling for the native GC. -``uClibc`` Use uClibc instead of libc. (Relevant for Unix-like OSes) -``checkAbi`` When using types from C headers, add checks that compare +`logGC` Enable GC logging to stdout. +`nodejs` The JS target is actually `node.js`. +`ssl` Enables OpenSSL support for the sockets module. +`memProfiler` Enables memory profiling for the native GC. +`uClibc` Use uClibc instead of libc. (Relevant for Unix-like OSes) +`checkAbi` When using types from C headers, add checks that compare what's in the Nim file with what's in the C header. This may become enabled by default in the future. -``tempDir`` This symbol takes a string as its value, like - ``--define:tempDir:/some/temp/path`` to override the - temporary directory returned by ``os.getTempDir()``. +`tempDir` This symbol takes a string as its value, like + `--define:tempDir:/some/temp/path` to override the + temporary directory returned by `os.getTempDir()`. The value **should** end with a directory separator character. (Relevant for the Android platform) -``useShPath`` This symbol takes a string as its value, like - ``--define:useShPath:/opt/sh/bin/sh`` to override the - path for the ``sh`` binary, in cases where it is not - located in the default location ``/bin/sh``. -``noSignalHandler`` Disable the crash handler from ``system.nim``. -``globalSymbols`` Load all ``{.dynlib.}`` libraries with the ``RTLD_GLOBAL`` +`useShPath` This symbol takes a string as its value, like + `--define:useShPath:/opt/sh/bin/sh` to override the + path for the `sh` binary, in cases where it is not + located in the default location `/bin/sh`. +`noSignalHandler` Disable the crash handler from `system.nim`. +`globalSymbols` Load all `{.dynlib.}` libraries with the `RTLD_GLOBAL` flag on Posix systems to resolve symbols in subsequently loaded libraries. ====================== ========================================================= @@ -471,20 +473,20 @@ generator and are subject to change. LineDir option -------------- -The ``lineDir`` option can be turned on or off. If turned on the -generated C code contains ``#line`` directives. This may be helpful for +The `lineDir` option can be turned on or off. If turned on the +generated C code contains `#line` directives. This may be helpful for debugging with GDB. StackTrace option ----------------- -If the ``stackTrace`` option is turned on, the generated C contains code to +If the `stackTrace` option is turned on, the generated C contains code to ensure that proper stack traces are given if the program crashes or some uncaught exception is raised. LineTrace option ---------------- -The ``lineTrace`` option implies the ``stackTrace`` option. If turned on, +The `lineTrace` option implies the `stackTrace` option. If turned on, the generated C contains code to ensure that proper stack traces with line number information are given if the program crashes or an uncaught exception is raised. @@ -493,10 +495,10 @@ is raised. DynlibOverride ============== -By default Nim's ``dynlib`` pragma causes the compiler to generate -``GetProcAddress`` (or their Unix counterparts) -calls to bind to a DLL. With the ``dynlibOverride`` command line switch this -can be prevented and then via ``--passL`` the static library can be linked +By default Nim's `dynlib` pragma causes the compiler to generate +`GetProcAddress` (or their Unix counterparts) +calls to bind to a DLL. With the `dynlibOverride` command line switch this +can be prevented and then via `--passL` the static library can be linked against. For instance, to link statically against Lua this command might work on Linux:: @@ -506,8 +508,8 @@ on Linux:: Backend language options ======================== -The typical compiler usage involves using the ``compile`` or ``c`` command to -transform a ``.nim`` file into one or more ``.c`` files which are then +The typical compiler usage involves using the `compile` or `c` command to +transform a `.nim` file into one or more `.c` files which are then compiled with the platform's C compiler into a static binary. However, there are other commands to compile to C++, Objective-C, or JavaScript. More details can be read in the `Nim Backend Integration document `_. @@ -517,7 +519,7 @@ Nim documentation tools ======================= Nim provides the `doc`:idx: command to generate HTML -documentation from ``.nim`` source files. Only exported symbols will appear in +documentation from `.nim` source files. Only exported symbols will appear in the output. For more details `see the docgen documentation `_. Nim idetools integration @@ -533,15 +535,15 @@ for further information. The Nim compiler supports an interactive mode. This is also known as a `REPL`:idx: (*read eval print loop*). If Nim has been built with the - ``-d:nimUseLinenoise`` switch, it uses the GNU readline library for terminal + `-d:nimUseLinenoise` switch, it uses the GNU readline library for terminal input management. To start Nim in interactive mode use the command - ``nim secret``. To quit use the ``quit()`` command. To determine whether an input + `nim secret`. To quit use the `quit()` command. To determine whether an input line is an incomplete statement to be continued these rules are used: 1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace). 2. The line starts with a space (indentation). 3. The line is within a triple quoted string literal. However, the detection - does not work if the line contains more than one ``"""``. + does not work if the line contains more than one `"""`. Nim for embedded systems @@ -552,22 +554,22 @@ modern PC hardware and operating systems with ample memory, it is very well possible to run Nim code and a good part of the Nim standard libraries on small embedded microprocessors with only a few kilobytes of memory. -A good start is to use the ``any`` operating target together with the -``malloc`` memory allocator and the ``arc`` garbage collector. For example: +A good start is to use the `any` operating target together with the +`malloc` memory allocator and the `arc` garbage collector. For example: -``nim c --os:any --gc:arc -d:useMalloc [...] x.nim`` +`nim c --os:any --gc:arc -d:useMalloc [...] x.nim` -- ``--gc:arc`` will enable the reference counting memory management instead +- `--gc:arc` will enable the reference counting memory management instead of the default garbage collector. This enables Nim to use heap memory which is required for strings and seqs, for example. -- The ``--os:any`` target makes sure Nim does not depend on any specific +- The `--os:any` target makes sure Nim does not depend on any specific operating system primitives. Your platform should support only some basic - ANSI C library ``stdlib`` and ``stdio`` functions which should be available + ANSI C library `stdlib` and `stdio` functions which should be available on almost any platform. -- The ``-d:useMalloc`` option configures Nim to use only the standard C memory - manage primitives ``malloc()``, ``free()``, ``realloc()``. +- The `-d:useMalloc` option configures Nim to use only the standard C memory + manage primitives `malloc()`, `free()`, `realloc()`. If your platform does not provide these functions it should be trivial to provide an implementation for them and link these to your program. @@ -577,10 +579,10 @@ additional flags to both the Nim compiler and the C compiler and/or linker to optimize the build for size. For example, the following flags can be used when targeting a gcc compiler: -``--opt:size --passC:-flto --passL:-flto`` +`--opt:size --passC:-flto --passL:-flto` -The ``--opt:size`` flag instructs Nim to optimize code generation for small -size (with the help of the C compiler), the ``flto`` flags enable link-time +The `--opt:size` flag instructs Nim to optimize code generation for small +size (with the help of the C compiler), the `flto` flags enable link-time optimization in the compiler and linker. Check the `Cross-compilation` section for instructions on how to compile the @@ -600,7 +602,7 @@ The Nim programming language has no concept of Posix's signal handling mechanisms. However, the standard library offers some rudimentary support for signal handling, in particular, segmentation faults are turned into fatal errors that produce a stack trace. This can be disabled with the -``-d:noSignalHandler`` switch. +`-d:noSignalHandler` switch. Optimizing for Nim @@ -642,7 +644,7 @@ However, it is not efficient to do: .. code-block:: Nim var s = varA # assignment has to copy the whole string into a new buffer! -For ``let`` symbols a copy is not always necessary: +For `let` symbols a copy is not always necessary: .. code-block:: Nim let s = varA # may only copy a pointer if it safe to do so @@ -656,7 +658,7 @@ objects as `shallow`:idx:\: shallow(s) # mark 's' as a shallow string var x = s # now might not copy the string! -Usage of ``shallow`` is always safe once you know the string won't be modified +Usage of `shallow` is always safe once you know the string won't be modified anymore, similar to Ruby's `freeze`:idx:. diff --git a/doc/nimfix.rst b/doc/nimfix.rst index 62064fe69..d105346da 100644 --- a/doc/nimfix.rst +++ b/doc/nimfix.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ===================== Nimfix User Guide ===================== @@ -14,12 +16,12 @@ It performs 3 different actions: 1. It makes your code case consistent. 2. It renames every symbol that has a deprecation rule. So if a module has a - rule ``{.deprecated: [TFoo: Foo].}`` then ``TFoo`` is replaced by ``Foo``. + rule `{.deprecated: [TFoo: Foo].}` then `TFoo` is replaced by `Foo`. 3. It can also check that your identifiers adhere to the official style guide - and optionally modify them to do so (via ``--styleCheck:auto``). + and optionally modify them to do so (via `--styleCheck:auto`). -Note that ``nimfix`` defaults to **overwrite** your code unless you -use ``--overwriteFiles:off``! But hey, if you do not use a version control +Note that `nimfix` defaults to **overwrite** your code unless you +use `--overwriteFiles:off`! But hey, if you do not use a version control system by this day and age, your project is already in big trouble. diff --git a/doc/nimgrep.rst b/doc/nimgrep.rst index 791ead162..5b0fe0dbb 100644 --- a/doc/nimgrep.rst +++ b/doc/nimgrep.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================= nimgrep User's manual ========================= @@ -22,7 +24,7 @@ Compile nimgrep with the command:: nim c -d:release tools/nimgrep.nim -And copy the executable somewhere in your ``$PATH``. +And copy the executable somewhere in your `$PATH`. Command line switches diff --git a/doc/niminst.rst b/doc/niminst.rst index adb5e6f1f..3ccb47cc8 100644 --- a/doc/niminst.rst +++ b/doc/niminst.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================= niminst User's manual ========================= @@ -31,8 +33,8 @@ configuration file. Here's an example of how the syntax looks like: :literal: The value of a key-value pair can reference user-defined variables via -the ``$variable`` notation: They can be defined in the command line with the -``--var:name=value`` switch. This is useful to not hard-coding the +the `$variable` notation: They can be defined in the command line with the +`--var:name=value` switch. This is useful to not hard-coding the program's version number into the configuration file, for instance. It follows a description of each possible section and how it affects the @@ -47,28 +49,28 @@ contain the following key-value pairs: ==================== ======================================================= Key description ==================== ======================================================= -``Name`` the project's name; this needs to be a single word -``DisplayName`` the project's long name; this can contain spaces. If - not specified, this is the same as ``Name``. -``Version`` the project's version -``OS`` the OSes to generate C code for; for example: - ``"windows;linux;macosx"`` -``CPU`` the CPUs to generate C code for; for example: - ``"i386;amd64;powerpc"`` -``Authors`` the project's authors -``Description`` the project's description -``App`` the application's type: "Console" or "GUI". If +`Name` the project's name; this needs to be a single word +`DisplayName` the project's long name; this can contain spaces. If + not specified, this is the same as `Name`. +`Version` the project's version +`OS` the OSes to generate C code for; for example: + `"windows;linux;macosx"` +`CPU` the CPUs to generate C code for; for example: + `"i386;amd64;powerpc"` +`Authors` the project's authors +`Description` the project's description +`App` the application's type: "Console" or "GUI". If "Console", niminst generates a special batch file for Windows to open up the command-line shell. -``License`` the filename of the application's license +`License` the filename of the application's license ==================== ======================================================= -``files`` key +`files` key ------------- -Many sections support the ``files`` key. Listed filenames -can be separated by semicolon or the ``files`` key can be repeated. Wildcards +Many sections support the `files` key. Listed filenames +can be separated by semicolon or the `files` key can be repeated. Wildcards in filenames are supported. If it is a directory name, all files in the directory are used:: @@ -80,63 +82,63 @@ directory are used:: Config section -------------- -The ``config`` section currently only supports the ``files`` key. Listed files +The `config` section currently only supports the `files` key. Listed files will be installed into the OS's configuration directory. Documentation section --------------------- -The ``documentation`` section supports the ``files`` key. +The `documentation` section supports the `files` key. Listed files will be installed into the OS's native documentation directory -(which might be ``$appdir/doc``). +(which might be `$appdir/doc`). -There is a ``start`` key which determines whether the Windows installer -generates a link to e.g. the ``index.html`` of your documentation. +There is a `start` key which determines whether the Windows installer +generates a link to e.g. the `index.html` of your documentation. Other section ------------- -The ``other`` section currently only supports the ``files`` key. +The `other` section currently only supports the `files` key. Listed files will be installed into the application installation directory -(``$appdir``). +(`$appdir`). Lib section ----------- -The ``lib`` section currently only supports the ``files`` key. +The `lib` section currently only supports the `files` key. Listed files will be installed into the OS's native library directory -(which might be ``$appdir/lib``). +(which might be `$appdir/lib`). Windows section --------------- -The ``windows`` section supports the ``files`` key for Windows-specific files. +The `windows` section supports the `files` key for Windows-specific files. Listed files will be installed into the application installation directory -(``$appdir``). +(`$appdir`). Other possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``BinPath`` paths to add to the Windows ``%PATH%`` environment +`BinPath` paths to add to the Windows `%PATH%` environment variable. Example: ``BinPath: r"bin;dist\mingw\bin"`` -``InnoSetup`` boolean flag whether an Inno Setup installer should be - generated for Windows. Example: ``InnoSetup: "Yes"`` +`InnoSetup` boolean flag whether an Inno Setup installer should be + generated for Windows. Example: `InnoSetup: "Yes"` ==================== ======================================================= UnixBin section --------------- -The ``UnixBin`` section currently only supports the ``files`` key. +The `UnixBin` section currently only supports the `files` key. Listed files will be installed into the OS's native bin directory -(e.g. ``/usr/local/bin``). The exact location depends on the -installation path the user specifies when running the ``install.sh`` script. +(e.g. `/usr/local/bin`). The exact location depends on the +installation path the user specifies when running the `install.sh` script. Unix section @@ -147,11 +149,11 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``InstallScript`` boolean flag whether an installation shell script - should be generated. Example: ``InstallScript: "Yes"`` -``UninstallScript`` boolean flag whether a de-installation shell script +`InstallScript` boolean flag whether an installation shell script + should be generated. Example: `InstallScript: "Yes"` +`UninstallScript` boolean flag whether a de-installation shell script should be generated. - Example: ``UninstallScript: "Yes"`` + Example: `UninstallScript: "Yes"` ==================== ======================================================= @@ -163,10 +165,10 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``path`` Path to Inno Setup. +`path` Path to Inno Setup. Example: ``path = r"c:\inno setup 5\iscc.exe"`` -``flags`` Flags to pass to Inno Setup. - Example: ``flags = "/Q"`` +`flags` Flags to pass to Inno Setup. + Example: `flags = "/Q"` ==================== ======================================================= @@ -178,9 +180,9 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``path`` Path to the C compiler. -``flags`` Flags to pass to the C Compiler. - Example: ``flags = "-w"`` +`path` Path to the C compiler. +`flags` Flags to pass to the C Compiler. + Example: `flags = "-w"` ==================== ======================================================= diff --git a/doc/nims.rst b/doc/nims.rst index aa13d134a..f81637d73 100644 --- a/doc/nims.rst +++ b/doc/nims.rst @@ -1,30 +1,32 @@ +.. default-role:: code + ================================ NimScript ================================ -Strictly speaking, ``NimScript`` is the subset of Nim that can be evaluated +Strictly speaking, `NimScript` is the subset of Nim that can be evaluated by Nim's builtin virtual machine (VM). This VM is used for Nim's compiletime function evaluation features. -The ``nim`` executable processes the ``.nims`` configuration files in +The `nim` executable processes the `.nims` configuration files in the following directories (in this order; later files overwrite previous settings): -1) If environment variable ``XDG_CONFIG_HOME`` is defined, - ``$XDG_CONFIG_HOME/nim/config.nims`` or - ``~/.config/nim/config.nims`` (POSIX) or - ``%APPDATA%/nim/config.nims`` (Windows). This file can be skipped - with the ``--skipUserCfg`` command line option. -2) ``$parentDir/config.nims`` where ``$parentDir`` stands for any +1) If environment variable `XDG_CONFIG_HOME` is defined, + `$XDG_CONFIG_HOME/nim/config.nims` or + `~/.config/nim/config.nims` (POSIX) or + `%APPDATA%/nim/config.nims` (Windows). This file can be skipped + with the `--skipUserCfg` command line option. +2) `$parentDir/config.nims` where `$parentDir` stands for any parent directory of the project file's path. These files can be - skipped with the ``--skipParentCfg`` command line option. -3) ``$projectDir/config.nims`` where ``$projectDir`` stands for the - project's path. This file can be skipped with the ``--skipProjCfg`` + skipped with the `--skipParentCfg` command line option. +3) `$projectDir/config.nims` where `$projectDir` stands for the + project's path. This file can be skipped with the `--skipProjCfg` command line option. 4) A project can also have a project specific configuration file named - ``$project.nims`` that resides in the same directory as - ``$project.nim``. This file can be skipped with the same - ``--skipProjCfg`` command line option. + `$project.nims` that resides in the same directory as + `$project.nim`. This file can be skipped with the same + `--skipProjCfg` command line option. For available procs and implementation details see `nimscript `_. @@ -36,13 +38,13 @@ NimScript is subject to some limitations caused by the implementation of the VM (virtual machine): * Nim's FFI (foreign function interface) is not available in NimScript. This - means that any stdlib module which relies on ``importc`` can not be used in + means that any stdlib module which relies on `importc` can not be used in the VM. -* ``ptr`` operations are are hard to emulate with the symbolic representation +* `ptr` operations are are hard to emulate with the symbolic representation the VM uses. They are available and tested extensively but there are bugs left. -* ``var T`` function arguments rely on ``ptr`` operations internally and might +* `var T` function arguments rely on `ptr` operations internally and might also be problematic in some cases. * More than one level of `ref` is generally not supported (for example, the type @@ -50,7 +52,7 @@ NimScript is subject to some limitations caused by the implementation of the VM * Multimethods are not available. -* ``random.randomize()`` requires an ``int64`` explicitly passed as argument, you *must* pass a Seed integer. +* `random.randomize()` requires an `int64` explicitly passed as argument, you *must* pass a Seed integer. Standard library modules @@ -109,11 +111,11 @@ See also: NimScript as a configuration file ================================= -A command-line switch ``--FOO`` is written as ``switch("FOO")`` in -NimScript. Similarly, command-line ``--FOO:VAL`` translates to -``switch("FOO", "VAL")``. +A command-line switch `--FOO` is written as `switch("FOO")` in +NimScript. Similarly, command-line `--FOO:VAL` translates to +`switch("FOO", "VAL")`. -Here are few examples of using the ``switch`` proc: +Here are few examples of using the `switch` proc: .. code-block:: nim # command-line: --opt:size @@ -123,7 +125,7 @@ Here are few examples of using the ``switch`` proc: # command-line: --forceBuild switch("forceBuild") -NimScripts also support ``--`` templates for convenience, which look +NimScripts also support `--` templates for convenience, which look like command-line switches written as-is in the NimScript file. So the above example can be rewritten as: @@ -133,17 +135,17 @@ above example can be rewritten as: --forceBuild **Note**: In general, the *define* switches can also be set in -NimScripts using ``switch`` or ``--``, as shown in above -examples. Only the ``release`` define (``-d:release``) cannot be set +NimScripts using `switch` or `--`, as shown in above +examples. Only the `release` define (`-d:release`) cannot be set in NimScripts. NimScript as a build tool ========================= -The ``task`` template that the ``system`` module defines allows a NimScript +The `task` template that the `system` module defines allows a NimScript file to be used as a build tool. The following example defines a -task ``build`` that is an alias for the ``c`` command: +task `build` that is an alias for the `c` command: .. code-block:: nim task build, "builds an example": @@ -155,11 +157,11 @@ In fact, as a convention the following tasks should be available: ========= =================================================== Task Description ========= =================================================== -``help`` List all the available NimScript tasks along with their docstrings. -``build`` Build the project with the required - backend (``c``, ``cpp`` or ``js``). -``tests`` Runs the tests belonging to the project. -``bench`` Runs benchmarks belonging to the project. +`help` List all the available NimScript tasks along with their docstrings. +`build` Build the project with the required + backend (`c`, `cpp` or `js`). +`tests` Runs the tests belonging to the project. +`bench` Runs benchmarks belonging to the project. ========= =================================================== @@ -178,7 +180,7 @@ Standalone NimScript ==================== NimScript can also be used directly as a portable replacement for Bash and -Batch files. Use ``nim myscript.nims`` to run ``myscript.nims``. For example, +Batch files. Use `nim myscript.nims` to run `myscript.nims`. For example, installation of Nimble could be accomplished with this simple script: .. code-block:: nim @@ -196,8 +198,8 @@ installation of Nimble could be accomplished with this simple script: mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe -On Unix, you can also use the shebang ``#!/usr/bin/env nim``, as long as your filename -ends with ``.nims``: +On Unix, you can also use the shebang `#!/usr/bin/env nim`, as long as your filename +ends with `.nims`: .. code-block:: nim @@ -206,7 +208,7 @@ ends with ``.nims``: echo "hello world" -Use ``#!/usr/bin/env -S nim --hints:off`` to disable hints. +Use `#!/usr/bin/env -S nim --hints:off` to disable hints. Benefits @@ -268,7 +270,7 @@ Powerful Metaprogramming NimScript can use Nim's templates, macros, types, concepts, effect tracking system, and more, you can create modules that work on compiled Nim and also on interpreted NimScript. -``func`` will still check for side effects, ``debugEcho`` also works as expected, +`func` will still check for side effects, `debugEcho` also works as expected, making it ideal for functional scripting metaprogramming. This is an example of a third party module that uses macros and templates to @@ -315,7 +317,7 @@ See the following NimScript: echo CompileDate -``likely()``, ``unlikely()``, ``static:`` and ``{.compiletime.}`` +`likely()`, `unlikely()`, `static:` and `{.compiletime.}` will produce no code at all when run on NimScript, but still no error nor warning is produced and the code just works. diff --git a/doc/nimsuggest.rst b/doc/nimsuggest.rst index 8db7c233b..509f72e8a 100644 --- a/doc/nimsuggest.rst +++ b/doc/nimsuggest.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ================================ Nim IDE Integration Guide ================================ @@ -11,8 +13,8 @@ Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the -``nimsuggest`` tool, any IDE -can query a ``.nim`` source file and obtain useful information like +`nimsuggest` tool, any IDE +can query a `.nim` source file and obtain useful information like definition of symbols or suggestions for completion. This document will guide you through the available options. If you @@ -33,50 +35,50 @@ Nimsuggest is part of Nim's core. Build it via:: Nimsuggest invocation ===================== -Run it via ``nimsuggest --stdin --debug myproject.nim``. Nimsuggest is a -server that takes queries that are related to ``myproject``. There is some -support so that you can throw random ``.nim`` files which are not part -of ``myproject`` at Nimsuggest too, but usually the query refer to modules/files -that are part of ``myproject``. +Run it via `nimsuggest --stdin --debug myproject.nim`. Nimsuggest is a +server that takes queries that are related to `myproject`. There is some +support so that you can throw random `.nim` files which are not part +of `myproject` at Nimsuggest too, but usually the query refer to modules/files +that are part of `myproject`. -``--stdin`` means that Nimsuggest reads the query from ``stdin``. This is great +`--stdin` means that Nimsuggest reads the query from `stdin`. This is great for testing things out and playing with it but for an editor communication via sockets is more reasonable so that is the default. It listens to port 6000 by default. -Nimsuggest is basically a frontend for the nim compiler so ``--path`` flags and +Nimsuggest is basically a frontend for the nim compiler so `--path` flags and `config files `_ can be used to specify additional dependencies like -``nimsuggest --stdin --debug --path:"dependencies" myproject.nim``. +`nimsuggest --stdin --debug --path:"dependencies" myproject.nim`. Specifying the location of the query ------------------------------------ Nimsuggest then waits for queries to process. A query consists of a -cryptic 3 letter "command" ``def`` or ``con`` or ``sug`` or ``use`` followed by +cryptic 3 letter "command" `def` or `con` or `sug` or `use` followed by a location. A query location consists of: -``file.nim`` +`file.nim` This is the name of the module or include file the query refers to. -``dirtyfile.nim`` +`dirtyfile.nim` This is optional. - The ``file`` parameter is enough for static analysis, but IDEs + The `file` parameter is enough for static analysis, but IDEs tend to have *unsaved buffers* where the user may still be in the middle of typing a line. In such situations the IDE can save the current contents to a temporary file and then use the - ``dirtyfile.nim`` option to tell Nimsuggest that ``foobar.nim`` should - be taken from ``temporary/foobar.nim``. + `dirtyfile.nim` option to tell Nimsuggest that `foobar.nim` should + be taken from `temporary/foobar.nim`. -``line`` +`line` An integer with the line you are going to query. For the compiler lines start at **1**. -``col`` +`col` An integer with the column you are going to query. For the compiler columns start at **0**. @@ -84,7 +86,7 @@ a location. A query location consists of: Definitions ----------- -The ``def`` Nimsuggest command performs a query about the definition +The `def` Nimsuggest command performs a query about the definition of a specific symbol. If available, Nimsuggest will answer with the type, source file, line/column information and other accessory data if available like a docstring. With this information an IDE can @@ -105,7 +107,7 @@ can't find any valid symbol matching the position of the query. Suggestions ----------- -The ``sug`` Nimsuggest command performs a query about possible +The `sug` Nimsuggest command performs a query about possible completion symbols at some point in the file. The typical usage scenario for this option is to call it after the @@ -118,7 +120,7 @@ Nimsuggest will try to return the suggestions sorted first by scope Invocation context ------------------ -The ``con`` Nimsuggest command is very similar to the suggestions +The `con` Nimsuggest command is very similar to the suggestions command, but instead of being used after the user has typed a dot character, this one is meant to be used after the user has typed an opening brace to start typing parameters. @@ -127,7 +129,7 @@ an opening brace to start typing parameters. Symbol usages ------------- -The ``use`` Nimsuggest command lists all usages of the symbol at +The `use` Nimsuggest command lists all usages of the symbol at a position. IDEs can use this to find all the places in the file where the symbol is used and offer the user to rename it in all places at the same time. @@ -145,15 +147,15 @@ Nimsuggest output is always returned on single lines separated by tab characters (``\t``). The values of each column are: 1. Three characters indicating the type of returned answer (e.g. - ``def`` for definition, ``sug`` for suggestion, etc). -2. Type of the symbol. This can be ``skProc``, ``skLet``, and just - about any of the enums defined in the module ``compiler/ast.nim``. + `def` for definition, `sug` for suggestion, etc). +2. Type of the symbol. This can be `skProc`, `skLet`, and just + about any of the enums defined in the module `compiler/ast.nim`. 3. Fully qualified path of the symbol. If you are querying a symbol - defined in the ``proj.nim`` file, this would have the form - ``proj.symbolName``. + defined in the `proj.nim` file, this would have the form + `proj.symbolName`. 4. Type/signature. For variables and enums this will contain the type of the symbol, for procs, methods and templates this will - contain the full unique signature (e.g. ``proc (File)``). + contain the full unique signature (e.g. `proc (File)`). 5. Full path to the file containing the symbol. 6. Line where the symbol is located in the file. Lines start to count at **1**. diff --git a/doc/testament.rst b/doc/testament.rst index 5db68bfa7..04c966ffe 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -1,3 +1,5 @@ +.. default-role:: code + Testament is an advanced automatic unittests runner for Nim tests, is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, C++, ObjectiveC, JavaScript, etc), @@ -9,29 +11,29 @@ so can be useful to run your tests, even the most complex ones. Test files location =================== -By default Testament looks for test files on ``"./tests/*.nim"``. -You can overwrite this pattern glob using ``pattern ``. +By default Testament looks for test files on `"./tests/*.nim"`. +You can overwrite this pattern glob using `pattern `. The default working directory path can be changed using -``--directory:"folder/subfolder/"``. +`--directory:"folder/subfolder/"`. -Testament uses the ``nim`` compiler on ``PATH``. -You can change that using ``--nim:"folder/subfolder/nim"``. -Running JavaScript tests with ``--targets:"js"`` requires a working NodeJS on -``PATH``. +Testament uses the `nim` compiler on `PATH`. +You can change that using `--nim:"folder/subfolder/nim"`. +Running JavaScript tests with `--targets:"js"` requires a working NodeJS on +`PATH`. Options ======= -* ``--print`` Also print results to the console -* ``--simulate`` See what tests would be run but don't run them (for debugging) -* ``--failing`` Only show failing/ignored tests -* ``--targets:"c cpp js objc"`` Run tests for specified targets (default: all) -* ``--nim:path`` Use a particular nim executable (default: ``$PATH/nim``) -* ``--directory:dir`` Change to directory dir before reading the tests or doing anything else. -* ``--colors:on|off`` Turn messages coloring on|off. -* ``--backendLogging:on|off`` Disable or enable backend logging. By default turned on. -* ``--skipFrom:file`` Read tests to skip from ``file`` - one test per line, # comments ignored +* `--print` Also print results to the console +* `--simulate` See what tests would be run but don't run them (for debugging) +* `--failing` Only show failing/ignored tests +* `--targets:"c cpp js objc"` Run tests for specified targets (default: all) +* `--nim:path` Use a particular nim executable (default: `$PATH/nim`) +* `--directory:dir` Change to directory dir before reading the tests or doing anything else. +* `--colors:on|off` Turn messages coloring on|off. +* `--backendLogging:on|off` Disable or enable backend logging. By default turned on. +* `--skipFrom:file` Read tests to skip from `file` - one test per line, # comments ignored Running a single test @@ -68,7 +70,7 @@ To search for tests deeper in a directory, use HTML Reports ============ -Generate HTML Reports ``testresults.html`` from unittests, +Generate HTML Reports `testresults.html` from unittests, you have to run at least 1 test *before* generating a report: .. code:: @@ -172,7 +174,7 @@ Example "template" **to edit** and write a Testament unittest: assert 42 == 42, "Assert error message" -* As you can see the "Spec" is just a ``discard """ """``. +* As you can see the "Spec" is just a `discard """ """`. * Spec has sane defaults, so you don't need to provide them all, any simple assert will work just fine. * `This is not the full spec of Testament, check the Testament Spec on GitHub, see parseSpec(). `_ * `Nim itself uses Testament, so there are plenty of test examples. `_ diff --git a/doc/tools.rst b/doc/tools.rst index f231cdc7d..e0044e1ca 100644 --- a/doc/tools.rst +++ b/doc/tools.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ======================== Tools available with Nim ======================== @@ -9,11 +11,11 @@ The standard distribution ships with the following tools: document explaining how it works. - | `Documentation generator `_ - | The builtin document generator ``nim doc`` generates HTML documentation - from ``.nim`` source files. + | The builtin document generator `nim doc` generates HTML documentation + from `.nim` source files. - | `Nimsuggest for IDE support `_ - | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file + | Through the `nimsuggest` tool, any IDE can query a `.nim` source file and obtain useful information like the definition of symbols or suggestions for completion. @@ -27,11 +29,11 @@ The standard distribution ships with the following tools: | Nim search and replace utility. - | nimpretty - | ``nimpretty`` is a Nim source code beautifier, + | `nimpretty` is a Nim source code beautifier, to format code according to the official style guide. - | `testament `_ - | ``testament`` is an advanced automatic *unittests runner* for Nim tests, + | `testament` is an advanced automatic *unittests runner* for Nim tests, is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, JS, etc), `simulated Dry-Runs `_, diff --git a/doc/tut1.rst b/doc/tut1.rst index 171b2f918..d2d6f8fe7 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ===================== Nim Tutorial (Part I) ===================== @@ -46,7 +48,7 @@ Save this code to the file "greetings.nim". Now compile and run it:: nim compile --run greetings.nim -With the ``--run`` `switch `_ Nim +With the `--run` `switch `_ Nim executes the file automatically after compilation. You can give your program command-line arguments by appending them after the filename:: @@ -61,7 +63,7 @@ To compile a release version use:: nim c -d:release greetings.nim By default, the Nim compiler generates a large number of runtime checks -aiming for your debugging pleasure. With ``-d:release`` some checks are +aiming for your debugging pleasure. With `-d:release` some checks are `turned off and optimizations are turned on `_. @@ -70,8 +72,8 @@ syntax: statements which are not indented are executed when the program starts. Indentation is Nim's way of grouping statements. Indentation is done with spaces only, tabulators are not allowed. -String literals are enclosed in double-quotes. The ``var`` statement declares -a new variable named ``name`` of type ``string`` with the value that is +String literals are enclosed in double-quotes. The `var` statement declares +a new variable named `name` of type `string` with the value that is returned by the `readLine `_ procedure. Since the compiler knows that `readLine `_ returns a string, you can leave out the type in the declaration (this is called `local type @@ -85,7 +87,7 @@ Note that this is basically the only form of type inference that exists in Nim: it is a good compromise between brevity and readability. The "hello world" program contains several identifiers that are already known -to the compiler: ``echo``, `readLine `_, etc. +to the compiler: `echo`, `readLine `_, etc. These built-ins are declared in the system_ module which is implicitly imported by any other module. @@ -102,7 +104,7 @@ String and character literals ----------------------------- String literals are enclosed in double-quotes; character literals in single -quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t`` +quotes. Special characters are escaped with ``\\``: ``\n`` means newline, ``\t`` means tabulator, etc. There are also *raw* string literals: .. code-block:: Nim @@ -111,8 +113,8 @@ means tabulator, etc. There are also *raw* string literals: In raw literals, the backslash is not an escape character. The third and last way to write string literals is *long-string literals*. -They are written with three quotes: ``""" ... """``; they can span over -multiple lines and the ``\`` is not an escape character either. They are very +They are written with three quotes: `""" ... """`; they can span over +multiple lines and the ``\\`` is not an escape character either. They are very useful for embedding HTML code templates for example. @@ -120,7 +122,7 @@ Comments -------- Comments start anywhere outside a string or character literal with the -hash character ``#``. Documentation comments start with ``##``: +hash character `#`. Documentation comments start with `##`: .. code-block:: nim :test: "nim c $1" @@ -133,7 +135,7 @@ Documentation comments are tokens; they are only allowed at certain places in the input file as they belong to the syntax tree! This feature enables simpler documentation generators. -Multiline comments are started with ``#[`` and terminated with ``]#``. Multiline +Multiline comments are started with `#[` and terminated with `]#`. Multiline comments can also be nested. .. code-block:: nim @@ -152,10 +154,10 @@ Numbers ------- Numerical literals are written as in most other languages. As a special twist, -underscores are allowed for better readability: ``1_000_000`` (one million). +underscores are allowed for better readability: `1_000_000` (one million). A number that contains a dot (or 'e' or 'E') is a floating-point literal: -``1.0e9`` (one billion). Hexadecimal literals are prefixed with ``0x``, -binary literals with ``0b`` and octal literals with ``0o``. A leading zero +`1.0e9` (one billion). Hexadecimal literals are prefixed with `0x`, +binary literals with `0b` and octal literals with `0o`. A leading zero alone does not produce an octal. @@ -164,9 +166,9 @@ The var statement The var statement declares a new local or global variable: .. code-block:: - var x, y: int # declares x and y to have the type ``int`` + var x, y: int # declares x and y to have the type `int` -Indentation can be used after the ``var`` keyword to list a whole section of +Indentation can be used after the `var` keyword to list a whole section of variables: .. code-block:: @@ -187,7 +189,7 @@ to a storage location: var x = "abc" # introduces a new variable `x` and assigns a value to it x = "xyz" # assigns a new value to `x` -``=`` is the *assignment operator*. The assignment operator can be +`=` is the *assignment operator*. The assignment operator can be overloaded. You can declare multiple variables with a single assignment statement and all the variables will have the same value: @@ -219,7 +221,7 @@ constant declaration at compile time: :test: "nim c $1" const x = "abc" # the constant x contains the string "abc" -Indentation can be used after the ``const`` keyword to list a whole section of +Indentation can be used after the `const` keyword to list a whole section of constants: .. code-block:: @@ -233,7 +235,7 @@ constants: The let statement ================= -The ``let`` statement works like the ``var`` statement but the declared +The `let` statement works like the `var` statement but the declared symbols are *single assignment* variables: After the initialization their value cannot change: @@ -241,8 +243,8 @@ value cannot change: let x = "abc" # introduces a new variable `x` and binds a value to it x = "xyz" # Illegal: assignment to `x` -The difference between ``let`` and ``const`` is: ``let`` introduces a variable -that can not be re-assigned, ``const`` means "enforce compile time evaluation +The difference between `let` and `const` is: `let` introduces a variable +that can not be re-assigned, `const` means "enforce compile time evaluation and put it into a data section": .. code-block:: @@ -276,9 +278,9 @@ The if statement is one way to branch the control flow: else: echo "Hi, ", name, "!" -There can be zero or more ``elif`` parts, and the ``else`` part is optional. -The keyword ``elif`` is short for ``else if``, and is useful to avoid -excessive indentation. (The ``""`` is the empty string. It contains no +There can be zero or more `elif` parts, and the `else` part is optional. +The keyword `elif` is short for `else if`, and is useful to avoid +excessive indentation. (The `""` is the empty string. It contains no characters.) @@ -301,7 +303,7 @@ a multi-branch: else: echo "Hi, ", name, "!" -As it can be seen, for an ``of`` branch a comma-separated list of values is also +As it can be seen, for an `of` branch a comma-separated list of values is also allowed. The case statement can deal with integers, other ordinal types, and strings. @@ -319,8 +321,8 @@ For integers or other ordinal types value ranges are also possible: of 3, 8: echo "The number is 3 or 8" However, the above code does not compile: the reason is that you have to cover -every value that ``n`` may contain, but the code only handles the values -``0..8``. Since it is not very practical to list every other possible integer +every value that `n` may contain, but the code only handles the values +`0..8`. Since it is not very practical to list every other possible integer (though it is possible thanks to the range notation), we fix this by telling the compiler that for every other value nothing should be done: @@ -334,7 +336,7 @@ the compiler that for every other value nothing should be done: The empty `discard statement <#procedures-discard-statement>`_ is a *do nothing* statement. The compiler knows that a case statement with an else part cannot fail and thus the error disappears. Note that it is impossible to cover -all possible string values: that is why string cases always need an ``else`` +all possible string values: that is why string cases always need an `else` branch. In general, the case statement is used for subrange types or enumerations where @@ -355,7 +357,7 @@ The while statement is a simple looping construct: while name == "": echo "Please tell me your name: " name = readLine(stdin) - # no ``var``, because we do not declare a new variable here + # no `var`, because we do not declare a new variable here The example uses a while loop to keep asking the users for their name, as long as the user types in nothing (only presses RETURN). @@ -364,7 +366,7 @@ as the user types in nothing (only presses RETURN). For statement ------------- -The ``for`` statement is a construct to loop over any element an *iterator* +The `for` statement is a construct to loop over any element an *iterator* provides. The example uses the built-in `countup `_ iterator: @@ -375,10 +377,10 @@ provides. The example uses the built-in `countup echo i # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines -The variable ``i`` is implicitly declared by the -``for`` loop and has the type ``int``, because that is what `countup -`_ returns. ``i`` runs through the values -1, 2, .., 10. Each value is ``echo``-ed. This code does the same: +The variable `i` is implicitly declared by the +`for` loop and has the type `int`, because that is what `countup +`_ returns. `i` runs through the values +1, 2, .., 10. Each value is `echo`-ed. This code does the same: .. code-block:: nim echo "Counting to 10: " @@ -403,7 +405,7 @@ Since counting up occurs so often in programs, Nim also has a `.. for i in 1 .. 10: ... -Zero-indexed counting has two shortcuts ``..<`` and ``.. ^1`` +Zero-indexed counting has two shortcuts `..<` and `.. ^1` (`backward index operator `_) to simplify counting to one less than the higher index: @@ -426,8 +428,8 @@ or ... Other useful iterators for collections (like arrays and sequences) are -* ``items`` and ``mitems``, which provides immutable and mutable elements respectively, and -* ``pairs`` and ``mpairs`` which provides the element and an index number (immutable and mutable respectively) +* `items` and `mitems`, which provides immutable and mutable elements respectively, and +* `pairs` and `mpairs` which provides the element and an index number (immutable and mutable respectively) .. code-block:: nim :test: "nim c $1" @@ -439,7 +441,7 @@ Other useful iterators for collections (like arrays and sequences) are Scopes and the block statement ------------------------------ Control flow statements have a feature not covered yet: they open a -new scope. This means that in the following example, ``x`` is not accessible +new scope. This means that in the following example, `x` is not accessible outside the loop: .. code-block:: nim @@ -450,7 +452,7 @@ outside the loop: echo x # does not work A while (for) statement introduces an implicit block. Identifiers -are only visible within the block they have been declared. The ``block`` +are only visible within the block they have been declared. The `block` statement can be used to open a new block explicitly: .. code-block:: nim @@ -460,13 +462,13 @@ statement can be used to open a new block explicitly: var x = "hi" echo x # does not work either -The block's *label* (``myblock`` in the example) is optional. +The block's *label* (`myblock` in the example) is optional. Break statement --------------- -A block can be left prematurely with a ``break`` statement. The break statement -can leave a ``while``, ``for``, or a ``block`` statement. It leaves the +A block can be left prematurely with a `break` statement. The break statement +can leave a `while`, `for`, or a `block` statement. It leaves the innermost construct, unless a label of a block is given: .. code-block:: nim @@ -490,7 +492,7 @@ innermost construct, unless a label of a block is given: Continue statement ------------------ -Like in many other programming languages, a ``continue`` statement starts +Like in many other programming languages, a `continue` statement starts the next iteration immediately: .. code-block:: nim @@ -518,17 +520,17 @@ Example: else: echo "unknown operating system" -The ``when`` statement is almost identical to the ``if`` statement, but with these +The `when` statement is almost identical to the `if` statement, but with these differences: * Each condition must be a constant expression since it is evaluated by the compiler. * The statements within a branch do not open a new scope. * The compiler checks the semantics and produces code *only* for the statements - that belong to the first condition that evaluates to ``true``. + that belong to the first condition that evaluates to `true`. -The ``when`` statement is useful for writing platform-specific code, similar to -the ``#ifdef`` construct in the C programming language. +The `when` statement is useful for writing platform-specific code, similar to +the `#ifdef` construct in the C programming language. Statements and indentation @@ -539,8 +541,8 @@ indentation rules. In Nim, there is a distinction between *simple statements* and *complex statements*. *Simple statements* cannot contain other statements: -Assignment, procedure calls, or the ``return`` statement are all simple -statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can +Assignment, procedure calls, or the `return` statement are all simple +statements. *Complex statements* like `if`, `when`, `for`, `while` can contain other statements. To avoid ambiguities, complex statements must always be indented, but single simple statements do not: @@ -575,7 +577,7 @@ contain indentation at certain places for better readability: As a rule of thumb, indentation within expressions is allowed after operators, an open parenthesis and after commas. -With parenthesis and semicolons ``(;)`` you can use statements where only +With parenthesis and semicolons `(;)` you can use statements where only an expression is allowed: .. code-block:: nim @@ -590,7 +592,7 @@ Procedures To define new commands like `echo `_ and `readLine `_ in the examples, the concept of a `procedure` is needed. (Some languages call them *methods* or *functions*.) -In Nim new procedures are defined with the ``proc`` keyword: +In Nim new procedures are defined with the `proc` keyword: .. code-block:: nim :test: "nim c $1" @@ -607,26 +609,26 @@ In Nim new procedures are defined with the ``proc`` keyword: else: echo "I think you know what the problem is just as well as I do." -This example shows a procedure named ``yes`` that asks the user a ``question`` +This example shows a procedure named `yes` that asks the user a `question` and returns true if they answered "yes" (or something similar) and returns -false if they answered "no" (or something similar). A ``return`` statement +false if they answered "no" (or something similar). A `return` statement leaves the procedure (and therefore the while loop) immediately. The -``(question: string): bool`` syntax describes that the procedure expects a -parameter named ``question`` of type ``string`` and returns a value of type -``bool``. The ``bool`` type is built-in: the only valid values for ``bool`` are -``true`` and ``false``. -The conditions in if or while statements must be of type ``bool``. +`(question: string): bool` syntax describes that the procedure expects a +parameter named `question` of type `string` and returns a value of type +`bool`. The `bool` type is built-in: the only valid values for `bool` are +`true` and `false`. +The conditions in if or while statements must be of type `bool`. -Some terminology: in the example ``question`` is called a (formal) *parameter*, -``"Should I..."`` is called an *argument* that is passed to this parameter. +Some terminology: in the example `question` is called a (formal) *parameter*, +`"Should I..."` is called an *argument* that is passed to this parameter. Result variable --------------- -A procedure that returns a value has an implicit ``result`` variable declared -that represents the return value. A ``return`` statement with no expression is -shorthand for ``return result``. The ``result`` value is always returned -automatically at the end of a procedure if there is no ``return`` statement at +A procedure that returns a value has an implicit `result` variable declared +that represents the return value. A `return` statement with no expression is +shorthand for `return result`. The `result` value is always returned +automatically at the end of a procedure if there is no `return` statement at the exit. .. code-block:: nim @@ -641,15 +643,15 @@ the exit. echo sumTillNegative(3, 4, 5) # echos 12 echo sumTillNegative(3, 4 , -1 , 6) # echos 7 -The ``result`` variable is already implicitly declared at the start of the +The `result` variable is already implicitly declared at the start of the function, so declaring it again with 'var result', for example, would shadow it with a normal variable of the same name. The result variable is also already initialized with the type's default value. Note that referential data types will -be ``nil`` at the start of the procedure, and thus may require manual +be `nil` at the start of the procedure, and thus may require manual initialization. -A procedure that does not have any ``return`` statement and does not use the -special ``result`` variable returns the value of its last expression. For example, +A procedure that does not have any `return` statement and does not use the +special `result` variable returns the value of its last expression. For example, this procedure .. code-block:: nim @@ -664,7 +666,7 @@ Parameters Parameters are immutable in the procedure body. By default, their value cannot be changed because this allows the compiler to implement parameter passing in the most efficient way. If a mutable variable is needed inside the procedure, it has -to be declared with ``var`` in the procedure body. Shadowing the parameter name +to be declared with `var` in the procedure body. Shadowing the parameter name is possible, and actually an idiom: .. code-block:: nim @@ -675,7 +677,7 @@ is possible, and actually an idiom: echo s[i] If the procedure needs to modify the argument for the -caller, a ``var`` parameter can be used: +caller, a `var` parameter can be used: .. code-block:: nim :test: "nim c $1" @@ -689,7 +691,7 @@ caller, a ``var`` parameter can be used: echo x echo y -In the example, ``res`` and ``remainder`` are `var parameters`. +In the example, `res` and `remainder` are `var parameters`. Var parameters can be modified by the procedure and the changes are visible to the caller. Note that the above example would better make use of a tuple as a return value instead of using var parameters. @@ -698,7 +700,7 @@ a tuple as a return value instead of using var parameters. Discard statement ----------------- To call a procedure that returns a value just for its side effects and ignoring -its return value, a ``discard`` statement **must** be used. Nim does not +its return value, a `discard` statement **must** be used. Nim does not allow silently throwing away a return value: .. code-block:: nim @@ -706,7 +708,7 @@ allow silently throwing away a return value: The return value can be ignored implicitly if the called proc/iterator has -been declared with the ``discardable`` pragma: +been declared with the `discardable` pragma: .. code-block:: nim :test: "nim c $1" @@ -732,7 +734,7 @@ that it is clear which argument belongs to which parameter: var w = createWindow(show = true, title = "My Application", x = 0, y = 0, height = 600, width = 800) -Now that we use named arguments to call ``createWindow`` the argument order +Now that we use named arguments to call `createWindow` the argument order does not matter anymore. Mixing named arguments with ordered arguments is also possible, but not very readable: @@ -745,7 +747,7 @@ The compiler checks that each parameter receives exactly one argument. Default values -------------- -To make the ``createWindow`` proc easier to use it should provide `default +To make the `createWindow` proc easier to use it should provide `default values`; these are values that are used as arguments if the caller does not specify them: @@ -757,11 +759,11 @@ specify them: var w = createWindow(title = "My Application", height = 600, width = 800) -Now the call to ``createWindow`` only needs to set the values that differ +Now the call to `createWindow` only needs to set the values that differ from the defaults. Note that type inference works for parameters with default values; there is -no need to write ``title: string = "unknown"``, for example. +no need to write `title: string = "unknown"`, for example. Overloaded procedures @@ -783,8 +785,8 @@ Nim provides the ability to overload procedures similar to C++: assert toString(13) == "positive" # calls the toString(x: int) proc assert toString(true) == "yep" # calls the toString(x: bool) proc -(Note that ``toString`` is usually the `$ `_ operator in -Nim.) The compiler chooses the most appropriate proc for the ``toString`` +(Note that `toString` is usually the `$ `_ operator in +Nim.) The compiler chooses the most appropriate proc for the `toString` calls. How this overloading resolution algorithm works exactly is not discussed here (it will be specified in the manual soon). However, it does not lead to nasty surprises and is based on a quite simple unification @@ -794,31 +796,31 @@ algorithm. Ambiguous calls are reported as errors. Operators --------- The Nim library makes heavy use of overloading - one reason for this is that -each operator like ``+`` is just an overloaded proc. The parser lets you -use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``). +each operator like `+` is just an overloaded proc. The parser lets you +use operators in `infix notation` (`a + b`) or `prefix notation` (`+ a`). An infix operator always receives two arguments, a prefix operator always one. (Postfix operators are not possible, because this would be ambiguous: does -``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means -``(a) @ (@b)``, because there are no postfix operators in Nim.) +`a @ @ b` mean `(a) @ (@b)` or `(a@) @ (b)`? It always means +`(a) @ (@b)`, because there are no postfix operators in Nim.) -Apart from a few built-in keyword operators such as ``and``, ``or``, ``not``, +Apart from a few built-in keyword operators such as `and`, `or`, `not`, operators always consist of these characters: ``+ - * \ / < > = @ $ ~ & % ! ? ^ . |`` User-defined operators are allowed. Nothing stops you from defining your own -``@!?+~`` operator, but doing so may reduce readability. +`@!?+~` operator, but doing so may reduce readability. The operator's precedence is determined by its first character. The details can be found in the manual. -To define a new operator enclose the operator in backticks "``": +To define a new operator enclose the operator in backticks "`": .. code-block:: nim proc `$` (x: myDataType): string = ... # now the $ operator also works with myDataType, overloading resolution # ensures that $ works for built-in types just like before -The "``" notation can also be used to call an operator just like any other +The "`" notation can also be used to call an operator just like any other procedure: .. code-block:: nim @@ -851,10 +853,10 @@ However, this cannot be done for mutually recursive procedures: else: n == 0 or odd(n-1) -Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be +Here `odd` depends on `even` and vice versa. Thus `even` needs to be introduced to the compiler before it is completely defined. The syntax for -such a forward declaration is simple: just omit the ``=`` and the -procedure's body. The ``assert`` just adds border conditions, and will be +such a forward declaration is simple: just omit the `=` and the +procedure's body. The `assert` just adds border conditions, and will be covered later in `Modules`_ section. Later versions of the language will weaken the requirements for forward @@ -886,9 +888,9 @@ supports this loop? Lets try: inc(res) However, this does not work. The problem is that the procedure should not -only ``return``, but return and **continue** after an iteration has +only `return`, but return and **continue** after an iteration has finished. This *return and continue* is called a `yield` statement. Now -the only thing left to do is to replace the ``proc`` keyword by ``iterator`` +the only thing left to do is to replace the `proc` keyword by `iterator` and here it is - our first iterator: .. code-block:: nim @@ -903,19 +905,19 @@ Iterators look very similar to procedures, but there are several important differences: * Iterators can only be called from for loops. -* Iterators cannot contain a ``return`` statement (and procs cannot contain a - ``yield`` statement). -* Iterators have no implicit ``result`` variable. +* Iterators cannot contain a `return` statement (and procs cannot contain a + `yield` statement). +* Iterators have no implicit `result` variable. * Iterators do not support recursion. * Iterators cannot be forward declared, because the compiler must be able to inline an iterator. (This restriction will be gone in a future version of the compiler.) -However, you can also use a ``closure`` iterator to get a different set of +However, you can also use a `closure` iterator to get a different set of restrictions. See `first-class iterators `_ for details. Iterators can have the same name and parameters as a proc since essentially they have their own namespaces. Therefore it is common practice to wrap iterators in procs of the same name which accumulate the result of the -iterator and return it as a sequence, like ``split`` from the `strutils module +iterator and return it as a sequence, like `split` from the `strutils module `_. @@ -928,12 +930,12 @@ that are available for them in detail. Booleans -------- -Nim's boolean type is called ``bool`` and consists of the two -pre-defined values ``true`` and ``false``. Conditions in while, +Nim's boolean type is called `bool` and consists of the two +pre-defined values `true` and `false`. Conditions in while, if, elif, and when statements must be of type bool. -The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined -for the bool type. The ``and`` and ``or`` operators perform short-circuit +The operators `not, and, or, xor, <, <=, >, >=, !=, ==` are defined +for the bool type. The `and` and `or` operators perform short-circuit evaluation. For example: .. code-block:: nim @@ -945,7 +947,7 @@ evaluation. For example: Characters ---------- -The `character type` is called ``char``. Its size is always one byte, so +The `character type` is called `char`. Its size is always one byte, so it cannot represent most UTF-8 characters, but it *can* represent one of the bytes that makes up a multi-byte UTF-8 character. The reason for this is efficiency: for the overwhelming majority of use-cases, @@ -953,57 +955,57 @@ the resulting programs will still handle UTF-8 properly as UTF-8 was especially designed for this. Character literals are enclosed in single quotes. -Chars can be compared with the ``==``, ``<``, ``<=``, ``>``, ``>=`` operators. -The ``$`` operator converts a ``char`` to a ``string``. Chars cannot be mixed -with integers; to get the ordinal value of a ``char`` use the ``ord`` proc. -Converting from an integer to a ``char`` is done with the ``chr`` proc. +Chars can be compared with the `==`, `<`, `<=`, `>`, `>=` operators. +The `$` operator converts a `char` to a `string`. Chars cannot be mixed +with integers; to get the ordinal value of a `char` use the `ord` proc. +Converting from an integer to a `char` is done with the `chr` proc. Strings ------- String variables are **mutable**, so appending to a string is possible, and quite efficient. Strings in Nim are both zero-terminated and have a -length field. A string's length can be retrieved with the builtin ``len`` +length field. A string's length can be retrieved with the builtin `len` procedure; the length never counts the terminating zero. Accessing the terminating zero is an error, it only exists so that a Nim string can be converted -to a ``cstring`` without doing a copy. +to a `cstring` without doing a copy. -The assignment operator for strings copies the string. You can use the ``&`` -operator to concatenate strings and ``add`` to append to a string. +The assignment operator for strings copies the string. You can use the `&` +operator to concatenate strings and `add` to append to a string. Strings are compared using their lexicographical order. All the comparison operators are supported. By convention, all strings are UTF-8 encoded, but this is not enforced. For example, when reading strings from binary files, they are merely -a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of -``s``, not the i-th *unichar*. +a sequence of bytes. The index operation `s[i]` means the i-th *char* of +`s`, not the i-th *unichar*. -A string variable is initialized with the empty string ``""``. +A string variable is initialized with the empty string `""`. Integers -------- Nim has these integer types built-in: -``int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64``. +`int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64`. -The default integer type is ``int``. Integer literals can have a *type suffix* +The default integer type is `int`. Integer literals can have a *type suffix* to specify a non-default integer type: .. code-block:: nim :test: "nim c $1" let - x = 0 # x is of type ``int`` - y = 0'i8 # y is of type ``int8`` - z = 0'i64 # z is of type ``int64`` - u = 0'u # u is of type ``uint`` + x = 0 # x is of type `int` + y = 0'i8 # y is of type `int8` + z = 0'i64 # z is of type `int64` + u = 0'u # u is of type `uint` Most often integers are used for counting objects that reside in memory, so -``int`` has the same size as a pointer. +`int` has the same size as a pointer. -The common operators ``+ - * div mod < <= == != > >=`` are defined for -integers. The ``and or xor not`` operators are also defined for integers and -provide *bitwise* operations. Left bit shifting is done with the ``shl``, right -shifting with the ``shr`` operator. Bit shifting operators always treat their +The common operators `+ - * div mod < <= == != > >=` are defined for +integers. The `and or xor not` operators are also defined for integers and +provide *bitwise* operations. Left bit shifting is done with the `shl`, right +shifting with the `shr` operator. Bit shifting operators always treat their arguments as *unsigned*. For `arithmetic bit shifts`:idx: ordinary multiplication or division can be used. @@ -1018,10 +1020,10 @@ cannot be detected at compile time). Floats ------ -Nim has these floating-point types built-in: ``float float32 float64``. +Nim has these floating-point types built-in: `float float32 float64`. -The default float type is ``float``. In the current implementation, -``float`` is always 64-bits. +The default float type is `float`. In the current implementation, +`float` is always 64-bits. Float literals can have a *type suffix* to specify a non-default float type: @@ -1029,11 +1031,11 @@ type: .. code-block:: nim :test: "nim c $1" var - x = 0.0 # x is of type ``float`` - y = 0.0'f32 # y is of type ``float32`` - z = 0.0'f64 # z is of type ``float64`` + x = 0.0 # x is of type `float` + y = 0.0'f32 # y is of type `float32` + z = 0.0'f64 # z is of type `float64` -The common operators ``+ - * / < <= == != > >=`` are defined for +The common operators `+ - * / < <= == != > >=` are defined for floats and follow the IEEE-754 standard. Automatic type conversion in expressions with different kinds of floating-point types is performed: the smaller type is converted to the larger. Integer @@ -1061,13 +1063,13 @@ Internal type representation As mentioned earlier, the built-in `$ `_ (stringify) operator turns any basic type into a string, which you can then print to the console -using the ``echo`` proc. However, advanced types, and your own custom types, -won't work with the ``$`` operator until you define it for them. +using the `echo` proc. However, advanced types, and your own custom types, +won't work with the `$` operator until you define it for them. Sometimes you just want to debug the current value of a complex type without -having to write its ``$`` operator. You can use then the `repr +having to write its `$` operator. You can use then the `repr `_ proc which works with any type and even complex data graphs with cycles. The following example shows that even for basic types -there is a difference between the ``$`` and ``repr`` outputs: +there is a difference between the `$` and `repr` outputs: .. code-block:: nim :test: "nim c $1" @@ -1092,7 +1094,7 @@ there is a difference between the ``$`` and ``repr`` outputs: Advanced types ============== -In Nim new types can be defined within a ``type`` statement: +In Nim new types can be defined within a `type` statement: .. code-block:: nim :test: "nim c $1" @@ -1101,7 +1103,7 @@ In Nim new types can be defined within a ``type`` statement: biggestFloat = float64 # biggest float type that is available Enumeration and object types may only be defined within a -``type`` statement. +`type` statement. Enumerations @@ -1124,9 +1126,9 @@ at runtime by 0, the second by 1, and so on. For example: All the comparison operators can be used with enumeration types. An enumeration's symbol can be qualified to avoid ambiguities: -``Direction.south``. +`Direction.south`. -The ``$`` operator can convert any enumeration value to its name, and the ``ord`` +The `$` operator can convert any enumeration value to its name, and the `ord` proc can convert it to its underlying integer value. For better interfacing to other programming languages, the symbols of enum @@ -1136,7 +1138,7 @@ must be in ascending order. Ordinal types ------------- -Enumerations, integer types, ``char`` and ``bool`` (and +Enumerations, integer types, `char` and `bool` (and subranges) are called ordinal types. Ordinal types have quite a few special operations: @@ -1144,16 +1146,16 @@ a few special operations: ----------------- -------------------------------------------------------- Operation Comment ----------------- -------------------------------------------------------- -``ord(x)`` returns the integer value that is used to +`ord(x)` returns the integer value that is used to represent `x`'s value -``inc(x)`` increments `x` by one -``inc(x, n)`` increments `x` by `n`; `n` is an integer -``dec(x)`` decrements `x` by one -``dec(x, n)`` decrements `x` by `n`; `n` is an integer -``succ(x)`` returns the successor of `x` -``succ(x, n)`` returns the `n`'th successor of `x` -``pred(x)`` returns the predecessor of `x` -``pred(x, n)`` returns the `n`'th predecessor of `x` +`inc(x)` increments `x` by one +`inc(x, n)` increments `x` by `n`; `n` is an integer +`dec(x)` decrements `x` by one +`dec(x, n)` decrements `x` by `n`; `n` is an integer +`succ(x)` returns the successor of `x` +`succ(x, n)` returns the `n`'th successor of `x` +`pred(x)` returns the predecessor of `x` +`pred(x, n)` returns the `n`'th predecessor of `x` ----------------- -------------------------------------------------------- @@ -1174,17 +1176,17 @@ A subrange type is a range of values from an integer or enumeration type MySubrange = range[0..5] -``MySubrange`` is a subrange of ``int`` which can only hold the values 0 -to 5. Assigning any other value to a variable of type ``MySubrange`` is a +`MySubrange` is a subrange of `int` which can only hold the values 0 +to 5. Assigning any other value to a variable of type `MySubrange` is a compile-time or runtime error. Assignments from the base type to one of its subrange types (and vice versa) are allowed. -The ``system`` module defines the important `Natural `_ -type as ``range[0..high(int)]`` (`high `_ returns +The `system` module defines the important `Natural `_ +type as `range[0..high(int)]` (`high `_ returns the maximal value). Other programming languages may suggest the use of unsigned integers for natural numbers. This is often **unwise**: you don't want unsigned arithmetic (which wraps around) just because the numbers cannot be negative. -Nim's ``Natural`` type helps to avoid this common programming error. +Nim's `Natural` type helps to avoid this common programming error. Sets @@ -1197,7 +1199,7 @@ Arrays An array is a simple fixed-length container. Each element in an array has the same type. The array's index type can be any ordinal type. -Arrays can be constructed using ``[]``: +Arrays can be constructed using `[]`: .. code-block:: nim :test: "nim c $1" @@ -1210,10 +1212,10 @@ Arrays can be constructed using ``[]``: for i in low(x)..high(x): echo x[i] -The notation ``x[i]`` is used to access the i-th element of ``x``. +The notation `x[i]` is used to access the i-th element of `x`. Array access is always bounds checked (at compile-time or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -``--bound_checks:off`` command line switch. +`--bound_checks:off` command line switch. Arrays are value types, like any other Nim type. The assignment operator copies the whole array contents. @@ -1263,9 +1265,9 @@ subdivided into height levels accessed through their integer index: #tower[north][east] = on #tower[0][1] = on -Note how the built-in ``len`` proc returns only the array's first dimension -length. Another way of defining the ``LightTower`` to better illustrate its -nested nature would be to omit the previous definition of the ``LevelSetting`` +Note how the built-in `len` proc returns only the array's first dimension +length. Another way of defining the `LightTower` to better illustrate its +nested nature would be to omit the previous definition of the `LevelSetting` type and instead write it embedded directly as the type of the first dimension: .. code-block:: nim @@ -1295,13 +1297,13 @@ Sequences are similar to arrays but of dynamic length which may change during runtime (like strings). Since sequences are resizable they are always allocated on the heap and garbage collected. -Sequences are always indexed with an ``int`` starting at position 0. The `len +Sequences are always indexed with an `int` starting at position 0. The `len `_, `low `_ and `high `_ operations are available for sequences too. -The notation ``x[i]`` can be used to access the i-th element of ``x``. +The notation `x[i]` can be used to access the i-th element of `x`. -Sequences can be constructed by the array constructor ``[]`` in conjunction -with the array to sequence operator ``@``. Another way to allocate space for +Sequences can be constructed by the array constructor `[]` in conjunction +with the array to sequence operator `@`. Another way to allocate space for a sequence is to call the built-in `newSeq `_ procedure. A sequence may be passed to an openarray parameter. @@ -1315,15 +1317,15 @@ Example: x: seq[int] # a reference to a sequence of integers x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap -Sequence variables are initialized with ``@[]``. +Sequence variables are initialized with `@[]`. -The ``for`` statement can be used with one or two variables when used with a +The `for` statement can be used with one or two variables when used with a sequence. When you use the one variable form, the variable will hold the value -provided by the sequence. The ``for`` statement is looping over the results +provided by the sequence. The `for` statement is looping over the results from the `items() `_ iterator from the `system `_ module. But if you use the two-variable form, the first variable will hold the index position and the second variable will hold the -value. Here the ``for`` statement is looping over the results from the +value. Here the `for` statement is looping over the results from the `pairs() `_ iterator from the `system `_ module. Examples: @@ -1348,7 +1350,7 @@ Open arrays Often fixed-size arrays turn out to be too inflexible; procedures should be able to deal with arrays of different sizes. The `openarray`:idx: type allows -this. Openarrays are always indexed with an ``int`` starting at position 0. +this. Openarrays are always indexed with an `int` starting at position 0. The `len `_, `low `_ and `high `_ operations are available for open arrays too. Any array with a compatible base type can be passed to an @@ -1377,7 +1379,7 @@ supported because this is seldom needed and cannot be done efficiently. Varargs ------- -A ``varargs`` parameter is like an openarray parameter. However, it is +A `varargs` parameter is like an openarray parameter. However, it is also a means to implement passing a variable number of arguments to a procedure. The compiler converts the list of arguments to an array automatically: @@ -1409,7 +1411,7 @@ type conversions in this context: myWriteln(stdout, [$123, $"abc", $4.0]) In this example `$ `_ is applied to any argument that is passed -to the parameter ``a``. Note that `$ `_ applied to strings is a +to the parameter `a`. Note that `$ `_ applied to strings is a nop. @@ -1441,7 +1443,7 @@ To understand some of the different ways of specifying the indices of strings, arrays, sequences, etc., it must be remembered that Nim uses zero-based indices. -So the string ``b`` is of length 19, and two different ways of specifying the +So the string `b` is of length 19, and two different ways of specifying the indices are .. code-block:: nim @@ -1451,22 +1453,22 @@ indices are 0 11 17 using indices ^19 ^8 ^2 using ^ syntax -where ``b[0 .. ^1]`` is equivalent to ``b[0 .. b.len-1]`` and ``b[0 ..< b.len]``, and it -can be seen that the ``^1`` provides a short-hand way of specifying the ``b.len-1``. See +where `b[0 .. ^1]` is equivalent to `b[0 .. b.len-1]` and `b[0 ..< b.len]`, and it +can be seen that the `^1` provides a short-hand way of specifying the `b.len-1`. See the `backwards index operator `_. In the above example, because the string ends in a period, to get the portion of the string that is "useless" and replace it with "useful". -``b[11 .. ^2]`` is the portion "useless", and ``b[11 .. ^2] = "useful"`` replaces the +`b[11 .. ^2]` is the portion "useless", and `b[11 .. ^2] = "useful"` replaces the "useless" portion with "useful", giving the result "Slices are useful." -Note 1: alternate ways of writing this are ``b[^8 .. ^2] = "useful"`` or -as ``b[11 .. b.len-2] = "useful"`` or as ``b[11 ..< b.len-1] = "useful"``. +Note 1: alternate ways of writing this are `b[^8 .. ^2] = "useful"` or +as `b[11 .. b.len-2] = "useful"` or as `b[11 ..< b.len-1] = "useful"`. -Note 2: As the ``^`` template returns a `distinct int `_ -of type ``BackwardsIndex``, we can have a ``lastIndex`` constant defined as ``const lastIndex = ^1``, -and later used as ``b[0 .. lastIndex]``. +Note 2: As the `^` template returns a `distinct int `_ +of type `BackwardsIndex`, we can have a `lastIndex` constant defined as `const lastIndex = ^1`, +and later used as `b[0 .. lastIndex]`. Objects ------- @@ -1476,7 +1478,7 @@ structure with a name is the object type. An object is a value type, which means that when an object is assigned to a new variable all its components are copied as well. -Each object type ``Foo`` has a constructor ``Foo(field: value, ...)`` +Each object type `Foo` has a constructor `Foo(field: value, ...)` where all of its fields can be initialized. Unspecified fields will get their default value. @@ -1510,7 +1512,7 @@ get their default value. Object fields that should be visible from outside the defining module have to -be marked with ``*``. +be marked with `*`. .. code-block:: nim :test: "nim c $1" @@ -1529,15 +1531,15 @@ Unlike object types though, tuple types are structurally typed, meaning different tuple-types are *equivalent* if they specify fields of the same type and of the same name in the same order. -The constructor ``()`` can be used to construct tuples. The order of the +The constructor `()` can be used to construct tuples. The order of the fields in the constructor must match the order in the tuple's definition. But unlike objects, a name for the tuple type may not be used here. -Like the object type the notation ``t.field`` is used to access a +Like the object type the notation `t.field` is used to access a tuple's field. Another notation that is not available for objects is -``t[i]`` to access the ``i``'th field. Here ``i`` must be a constant +`t[i]` to access the `i`'th field. Here `i` must be a constant integer. .. code-block:: nim @@ -1641,9 +1643,9 @@ untraced references are *unsafe*. However, for certain low-level operations Traced references are declared with the **ref** keyword; untraced references are declared with the **ptr** keyword. -The empty ``[]`` subscript notation can be used to *de-refer* a reference, -meaning to retrieve the item the reference points to. The ``.`` (access a -tuple/object field operator) and ``[]`` (array/string/sequence index operator) +The empty `[]` subscript notation can be used to *de-refer* a reference, +meaning to retrieve the item the reference points to. The `.` (access a +tuple/object field operator) and `[]` (array/string/sequence index operator) operators perform implicit dereferencing operations for reference types: .. code-block:: nim @@ -1659,18 +1661,18 @@ operators perform implicit dereferencing operations for reference types: n.data = 9 # no need to write n[].data; in fact n[].data is highly discouraged! -To allocate a new traced object, the built-in procedure ``new`` must be used. -To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and -``realloc`` can be used. The `system `_ +To allocate a new traced object, the built-in procedure `new` must be used. +To deal with untraced memory, the procedures `alloc`, `dealloc` and +`realloc` can be used. The `system `_ module's documentation contains further details. -If a reference points to *nothing*, it has the value ``nil``. +If a reference points to *nothing*, it has the value `nil`. Procedural type --------------- A procedural type is a (somewhat abstract) pointer to a procedure. -``nil`` is an allowed value for a variable of a procedural type. +`nil` is an allowed value for a variable of a procedural type. Nim uses procedural types to achieve `functional`:idx: programming techniques. @@ -1708,7 +1710,7 @@ Nim supports splitting a program into pieces with a module concept. Each module is in its own file. Modules enable `information hiding`:idx: and `separate compilation`:idx:. A module may gain access to the symbols of another module by using the `import`:idx: statement. Only top-level symbols that are marked -with an asterisk (``*``) are exported: +with an asterisk (`*`) are exported: .. code-block:: nim # Module A @@ -1722,19 +1724,19 @@ with an asterisk (``*``) are exported: for i in 0..len(a)-1: result[i] = a[i] * b[i] when isMainModule: - # test the new ``*`` operator for sequences: + # test the new `*` operator for sequences: assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) -The above module exports ``x`` and ``*``, but not ``y``. +The above module exports `x` and `*`, but not `y`. A module's top-level statements are executed at the start of the program. This can be used to initialize complex data structures for example. -Each module has a special magic constant ``isMainModule`` that is true if the +Each module has a special magic constant `isMainModule` that is true if the module is compiled as the main file. This is very useful to embed tests within the module as shown by the above example. -A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. And if +A symbol of a module *can* be *qualified* with the `module.symbol` syntax. And if a symbol is ambiguous, it *must* be qualified. A symbol is ambiguous if it is defined in two (or more) different modules and both modules are imported by a third one: @@ -1781,9 +1783,9 @@ rules apply: Excluding symbols ----------------- -The normal ``import`` statement will bring in all exported symbols. +The normal `import` statement will bring in all exported symbols. These can be limited by naming symbols that should be excluded using -the ``except`` qualifier. +the `except` qualifier. .. code-block:: nim import mymodule except y @@ -1792,14 +1794,14 @@ the ``except`` qualifier. From statement -------------- -We have already seen the simple ``import`` statement that just imports all +We have already seen the simple `import` statement that just imports all exported symbols. An alternative that only imports listed symbols is the -``from import`` statement: +`from import` statement: .. code-block:: nim from mymodule import x, y, z -The ``from`` statement can also force namespace qualification on +The `from` statement can also force namespace qualification on symbols, thereby making symbols available, but needing to be qualified in order to be used. @@ -1826,8 +1828,8 @@ define a shorter alias to use when qualifying symbols. Include statement ----------------- -The ``include`` statement does something fundamentally different than -importing a module: it merely includes the contents of a file. The ``include`` +The `include` statement does something fundamentally different than +importing a module: it merely includes the contents of a file. The `include` statement is useful to split up a large module into several files: .. code-block:: nim diff --git a/doc/tut2.rst b/doc/tut2.rst index e0d1bdb32..3aef6bb0f 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ====================== Nim Tutorial (Part II) ====================== @@ -24,7 +26,7 @@ Pragmas Pragmas are Nim's method to give the compiler additional information/ commands without introducing a massive number of new keywords. Pragmas are -enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial +enclosed in the special `{.` and `.}` curly dot brackets. This tutorial does not cover pragmas. See the `manual `_ or `user guide `_ for a description of the available pragmas. @@ -45,11 +47,11 @@ Inheritance Inheritance in Nim is entirely optional. To enable inheritance with runtime type information the object needs to inherit from -``RootObj``. This can be done directly, or indirectly by -inheriting from an object that inherits from ``RootObj``. Usually -types with inheritance are also marked as ``ref`` types even though +`RootObj`. This can be done directly, or indirectly by +inheriting from an object that inherits from `RootObj`. Usually +types with inheritance are also marked as `ref` types even though this isn't strictly enforced. To check at runtime if an object is of a certain -type, the ``of`` operator can be used. +type, the `of` operator can be used. .. code-block:: nim :test: "nim c $1" @@ -69,16 +71,16 @@ type, the ``of`` operator can be used. student = Student(name: "Anton", age: 5, id: 2) echo student[] -Inheritance is done with the ``object of`` syntax. Multiple inheritance is -currently not supported. If an object type has no suitable ancestor, ``RootObj`` +Inheritance is done with the `object of` syntax. Multiple inheritance is +currently not supported. If an object type has no suitable ancestor, `RootObj` can be used as its ancestor, but this is only a convention. Objects that have -no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma -to introduce new object roots apart from ``system.RootObj``. (This is used +no ancestor are implicitly `final`. You can use the `inheritable` pragma +to introduce new object roots apart from `system.RootObj`. (This is used in the GTK wrapper for instance.) Ref objects should be used whenever inheritance is used. It isn't strictly -necessary, but with non-ref objects assignments such as ``let person: Person = -Student(id: 123)`` will truncate subclass fields. +necessary, but with non-ref objects assignments such as `let person: Person = +Student(id: 123)` will truncate subclass fields. **Note**: Composition (*has-a* relation) is often preferable to inheritance (*is-a* relation) for simple code reuse. Since objects are value types in @@ -111,7 +113,7 @@ Example: Type conversions ---------------- Nim distinguishes between `type casts`:idx: and `type conversions`:idx:. -Casts are done with the ``cast`` operator and force the compiler to +Casts are done with the `cast` operator and force the compiler to interpret a bit pattern to be of another type. Type conversions are a much more polite way to convert a type into another: @@ -119,15 +121,15 @@ They preserve the abstract *value*, not necessarily the *bit-pattern*. If a type conversion is not possible, the compiler complains or an exception is raised. -The syntax for type conversions is ``destination_type(expression_to_convert)`` +The syntax for type conversions is `destination_type(expression_to_convert)` (like an ordinary call): .. code-block:: nim proc getID(x: Person): int = Student(x).id -The ``InvalidObjectConversionDefect`` exception is raised if ``x`` is not a -``Student``. +The `InvalidObjectConversionDefect` exception is raised if `x` is not a +`Student`. Object variants @@ -150,7 +152,7 @@ An example: nkSub, # a subtraction nkIf # an if statement Node = ref object - case kind: NodeKind # the ``kind`` field is the discriminator + case kind: NodeKind # the `kind` field is the discriminator of nkInt: intVal: int of nkFloat: floatVal: float of nkString: strVal: string @@ -173,9 +175,9 @@ Method call syntax ------------------ There is a syntactic sugar for calling routines: -The syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``. +The syntax `obj.method(args)` can be used instead of `method(obj, args)`. If there are no remaining arguments, the parentheses can be omitted: -``obj.len`` (instead of ``len(obj)``). +`obj.len` (instead of `len(obj)`). This method call syntax is not restricted to objects, it can be used for any type: @@ -229,10 +231,10 @@ is needed: new s s.host = 34 # same as `host=`(s, 34) -(The example also shows ``inline`` procedures.) +(The example also shows `inline` procedures.) -The ``[]`` array access operator can be overloaded to provide +The `[]` array access operator can be overloaded to provide `array properties`:idx:\ : .. code-block:: nim @@ -258,14 +260,14 @@ The ``[]`` array access operator can be overloaded to provide else: assert(false) The example is silly, since a vector is better modelled by a tuple which -already provides ``v[]`` access. +already provides `v[]` access. Dynamic dispatch ---------------- Procedures always use static dispatch. For dynamic dispatch replace the -``proc`` keyword by ``method``: +`proc` keyword by `method`: .. code-block:: nim :test: "nim c $1" @@ -289,12 +291,12 @@ Procedures always use static dispatch. For dynamic dispatch replace the echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) -Note that in the example the constructors ``newLit`` and ``newPlus`` are procs -because it makes more sense for them to use static binding, but ``eval`` is a +Note that in the example the constructors `newLit` and `newPlus` are procs +because it makes more sense for them to use static binding, but `eval` is a method because it requires dynamic binding. **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -``--multimethods:on`` when compiling. +`--multimethods:on` when compiling. In a multi-method all parameters that have an object type are used for the dispatching: @@ -324,7 +326,7 @@ dispatching: As the example demonstrates, invocation of a multi-method cannot be ambiguous: Collide 2 is preferred over collide 1 because the resolution works from left to -right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``. +right. Thus `Unit, Thing` is preferred over `Thing, Unit`. **Performance note**: Nim does not produce a virtual method table, but generates dispatch trees. This avoids the expensive indirect branch for method @@ -338,19 +340,19 @@ Exceptions In Nim exceptions are objects. By convention, exception types are suffixed with 'Error'. The `system `_ module defines an exception hierarchy that you might want to stick to. Exceptions derive from -``system.Exception``, which provides the common interface. +`system.Exception`, which provides the common interface. Exceptions have to be allocated on the heap because their lifetime is unknown. The compiler will prevent you from raising an exception created on the stack. All raised exceptions should at least specify the reason for being raised in -the ``msg`` field. +the `msg` field. A convention is that exceptions should be raised in *exceptional* cases, they should not be used as an alternative method of control flow. Raise statement --------------- -Raising an exception is done with the ``raise`` statement: +Raising an exception is done with the `raise` statement: .. code-block:: nim :test: "nim c $1" @@ -360,9 +362,9 @@ Raising an exception is done with the ``raise`` statement: e.msg = "the request to the OS failed" raise e -If the ``raise`` keyword is not followed by an expression, the last exception +If the `raise` keyword is not followed by an expression, the last exception is *re-raised*. For the purpose of avoiding repeating this common code pattern, -the template ``newException`` in the ``system`` module can be used: +the template `newException` in the `system` module can be used: .. code-block:: nim raise newException(OSError, "the request to the OS failed") @@ -371,7 +373,7 @@ the template ``newException`` in the ``system`` module can be used: Try statement ------------- -The ``try`` statement handles exceptions: +The `try` statement handles exceptions: .. code-block:: nim :test: "nim c $1" @@ -399,23 +401,23 @@ The ``try`` statement handles exceptions: finally: close(f) -The statements after the ``try`` are executed unless an exception is -raised. Then the appropriate ``except`` part is executed. +The statements after the `try` are executed unless an exception is +raised. Then the appropriate `except` part is executed. -The empty ``except`` part is executed if there is an exception that is -not explicitly listed. It is similar to an ``else`` part in ``if`` +The empty `except` part is executed if there is an exception that is +not explicitly listed. It is similar to an `else` part in `if` statements. -If there is a ``finally`` part, it is always executed after the +If there is a `finally` part, it is always executed after the exception handlers. -The exception is *consumed* in an ``except`` part. If an exception is not +The exception is *consumed* in an `except` part. If an exception is not handled, it is propagated through the call stack. This means that often -the rest of the procedure - that is not within a ``finally`` clause - +the rest of the procedure - that is not within a `finally` clause - is not executed (if an exception occurs). If you need to *access* the actual exception object or message inside an -``except`` branch you can use the `getCurrentException() +`except` branch you can use the `getCurrentException() `_ and `getCurrentExceptionMsg() `_ procs from the `system `_ module. Example: @@ -433,10 +435,10 @@ module. Example: Annotating procs with raised exceptions --------------------------------------- -Through the use of the optional ``{.raises.}`` pragma you can specify that a +Through the use of the optional `{.raises.}` pragma you can specify that a proc is meant to raise a specific set of exceptions, or none at all. If the -``{.raises.}`` pragma is used, the compiler will verify that this is true. For -instance, if you specify that a proc raises ``IOError``, and at some point it +`{.raises.}` pragma is used, the compiler will verify that this is true. For +instance, if you specify that a proc raises `IOError`, and at some point it (or one of the procs it calls) starts raising a new exception the compiler will prevent that proc from compiling. Usage example: @@ -453,11 +455,11 @@ stopped validating the pragma and the raised exception not being caught, along with the file and line where the uncaught exception is being raised, which may help you locate the offending code which has changed. -If you want to add the ``{.raises.}`` pragma to existing code, the compiler can -also help you. You can add the ``{.effects.}`` pragma statement to your proc and +If you want to add the `{.raises.}` pragma to existing code, the compiler can +also help you. You can add the `{.effects.}` pragma statement to your proc and the compiler will output all inferred effects up to that point (exception tracking is part of Nim's effect system). Another more roundabout way to -find out the list of exceptions raised by a proc is to use the Nim ``doc`` +find out the list of exceptions raised by a proc is to use the Nim `doc` command which generates documentation for a whole module and decorates all procs with the list of raised exceptions. You can read more about Nim's `effect system and related pragmas in the manual `_. @@ -468,14 +470,14 @@ Generics Generics are Nim's means to parametrize procs, iterators or types with `type parameters`:idx:. Generic parameters are written within square -brackets, for example ``Foo[T]``. They are most useful for efficient type safe +brackets, for example `Foo[T]`. They are most useful for efficient type safe containers: .. code-block:: nim :test: "nim c $1" type BinaryTree*[T] = ref object # BinaryTree is a generic type with - # generic param ``T`` + # generic param `T` le, ri: BinaryTree[T] # left and right subtrees; may be nil data: T # the data stored in a node @@ -491,8 +493,8 @@ containers: else: var it = root while it != nil: - # compare the data items; uses the generic ``cmp`` proc - # that works for any type that has a ``==`` and ``<`` operator + # compare the data items; uses the generic `cmp` proc + # that works for any type that has a `==` and `<` operator var c = cmp(it.data, n.data) if c < 0: if it.le == nil: @@ -522,19 +524,19 @@ containers: n = n.le # and follow the left pointer var - root: BinaryTree[string] # instantiate a BinaryTree with ``string`` - add(root, newNode("hello")) # instantiates ``newNode`` and ``add`` - add(root, "world") # instantiates the second ``add`` proc + root: BinaryTree[string] # instantiate a BinaryTree with `string` + add(root, newNode("hello")) # instantiates `newNode` and `add` + add(root, "world") # instantiates the second `add` proc for str in preorder(root): stdout.writeLine(str) The example shows a generic binary tree. Depending on context, the brackets are used either to introduce type parameters or to instantiate a generic proc, iterator or type. As the example shows, generics work with overloading: the -best match of ``add`` is used. The built-in ``add`` procedure for sequences -is not hidden and is used in the ``preorder`` iterator. +best match of `add` is used. The built-in `add` procedure for sequences +is not hidden and is used in the `preorder` iterator. -There is a special ``[:T]`` syntax when using generics with the method call syntax: +There is a special `[:T]` syntax when using generics with the method call syntax: .. code-block:: nim :test: "nim c $1" @@ -567,14 +569,14 @@ Example: assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) -The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact -templates: this has the benefit that if you overload the ``==`` operator, -the ``!=`` operator is available automatically and does the right thing. (Except +The `!=`, `>`, `>=`, `in`, `notin`, `isnot` operators are in fact +templates: this has the benefit that if you overload the `==` operator, +the `!=` operator is available automatically and does the right thing. (Except for IEEE floating point numbers - NaN breaks basic boolean logic.) -``a > b`` is transformed into ``b < a``. -``a in b`` is transformed into ``contains(b, a)``. -``notin`` and ``isnot`` have the obvious meanings. +`a > b` is transformed into `b < a`. +`a in b` is transformed into `contains(b, a)`. +`notin` and `isnot` have the obvious meanings. Templates are especially useful for lazy evaluation purposes. Consider a simple proc for logging: @@ -591,11 +593,11 @@ simple proc for logging: x = 4 log("x has the value: " & $x) -This code has a shortcoming: if ``debug`` is set to false someday, the quite -expensive ``$`` and ``&`` operations are still performed! (The argument +This code has a shortcoming: if `debug` is set to false someday, the quite +expensive `$` and `&` operations are still performed! (The argument evaluation for procedures is *eager*). -Turning the ``log`` proc into a template solves this problem: +Turning the `log` proc into a template solves this problem: .. code-block:: nim :test: "nim c $1" @@ -609,15 +611,15 @@ Turning the ``log`` proc into a template solves this problem: x = 4 log("x has the value: " & $x) -The parameters' types can be ordinary types or the meta types ``untyped``, -``typed``, or ``type``. ``type`` suggests that only a type symbol may be given -as an argument, and ``untyped`` means symbol lookups and type resolution is not +The parameters' types can be ordinary types or the meta types `untyped`, +`typed`, or `type`. `type` suggests that only a type symbol may be given +as an argument, and `untyped` means symbol lookups and type resolution is not performed before the expression is passed to the template. If the template has no explicit return type, -``void`` is used for consistency with procs and methods. +`void` is used for consistency with procs and methods. -To pass a block of statements to a template, use ``untyped`` for the last parameter: +To pass a block of statements to a template, use `untyped` for the last parameter: .. code-block:: nim :test: "nim c $1" @@ -638,10 +640,10 @@ To pass a block of statements to a template, use ``untyped`` for the last parame txt.writeLine("line 1") txt.writeLine("line 2") -In the example the two ``writeLine`` statements are bound to the ``body`` -parameter. The ``withFile`` template contains boilerplate code and helps to +In the example the two `writeLine` statements are bound to the `body` +parameter. The `withFile` template contains boilerplate code and helps to avoid a common bug: to forget to close the file. Note how the -``let fn = filename`` statement ensures that ``filename`` is evaluated only +`let fn = filename` statement ensures that `filename` is evaluated only once. Example: Lifting Procs @@ -653,7 +655,7 @@ Example: Lifting Procs template liftScalarProc(fname) = ## Lift a proc taking one scalar parameter and returning a - ## scalar value (eg ``proc sssss[T](x: T): float``), + ## scalar value (eg `proc sssss[T](x: T): float`), ## to provide templated procs that can handle a single ## parameter of seq[T] or nested seq[seq[]] or the same type ## @@ -675,15 +677,15 @@ Compilation to JavaScript Nim code can be compiled to JavaScript. However in order to write JavaScript-compatible code you should remember the following: -- ``addr`` and ``ptr`` have slightly different semantic meaning in JavaScript. +- `addr` and `ptr` have slightly different semantic meaning in JavaScript. It is recommended to avoid those if you're not sure how they are translated to JavaScript. -- ``cast[T](x)`` in JavaScript is translated to ``(x)``, except for casting +- `cast[T](x)` in JavaScript is translated to `(x)`, except for casting between signed/unsigned ints, in which case it behaves as static cast in C language. -- ``cstring`` in JavaScript means JavaScript string. It is a good practice to - use ``cstring`` only when it is semantically appropriate. E.g. don't use - ``cstring`` as a binary data buffer. +- `cstring` in JavaScript means JavaScript string. It is a good practice to + use `cstring` only when it is semantically appropriate. E.g. don't use + `cstring` as a binary data buffer. Part 3 diff --git a/doc/tut3.rst b/doc/tut3.rst index b0a3d8232..358a9b45e 100644 --- a/doc/tut3.rst +++ b/doc/tut3.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ======================= Nim Tutorial (Part III) ======================= diff --git a/lib/system_overview.rst b/lib/system_overview.rst index 5e4b171fe..d6cbe1a35 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -1,3 +1,5 @@ +.. default-role:: code + The System module imports several separate modules, and their documentation is in separate files: @@ -36,7 +38,7 @@ Proc Usage * `strutils module `_ for common string functions * `strformat module `_ for string interpolation and formatting * `unicode module `_ for Unicode UTF-8 handling -* `strscans `_ for ``scanf`` and ``scanp`` macros, which offer +* `strscans `_ for `scanf` and `scanp` macros, which offer easier substring extraction than regular expressions * `strtabs module `_ for efficient hash tables (dictionaries, in some programming languages) mapping from strings to strings From 9e1a2e9b63fff3d3445a04600b431a42c800a0c8 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 19 Mar 2021 03:15:37 -0300 Subject: [PATCH 2226/4254] improve jsconsole (#17414) * Add jsconsole.dir * Update lib/js/jsconsole.nim Co-authored-by: Timothee Cour Co-authored-by: Timothee Cour --- changelog.md | 2 ++ lib/js/jsconsole.nim | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/changelog.md b/changelog.md index 4080f789c..219a66ae7 100644 --- a/changelog.md +++ b/changelog.md @@ -237,6 +237,8 @@ - In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, unless `-d:nimLegacyHomeDir` is specified (for a transition period). +- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. + ## Language changes diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index b8a361af1..bf43adddd 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -110,5 +110,15 @@ since (1, 5): {.line: loc.}: {.emit: ["console.assert(", assertion, ", ", msg, ");"].} + func dir*(console: Console; obj: auto) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/dir + + func dirxml*(console: Console; obj: auto) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/dirxml + + func timeStamp*(console: Console; label: cstring) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeStamp + ## ..warning:: non-standard + var console* {.importc, nodecl.}: Console From 452366982d8ef7d8ebed5cd95c034a14ee2f56c0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 18 Mar 2021 23:17:09 -0700 Subject: [PATCH 2227/4254] fix #16901: sidebar groups now works with all routines, not just proc,func (#17416) * fix #16901: sidebar groups now works with all routines, not just proc,func * fix tests --- compiler/docgen.nim | 2 +- .../expected/subdir/subdir_b/utils.html | 19 +++- nimdoc/testproject/expected/testproject.html | 104 +++++++++++++----- 3 files changed, 91 insertions(+), 34 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 37831c72c..57d5e7b01 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1245,7 +1245,7 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope = renderTocEntries(d[], j, 1, tmp) var toc = tmp.rope for i in TSymKind: - var shouldSort = i in {skProc, skFunc} and groupedToc + var shouldSort = i in routineKinds and groupedToc genSection(d, i, shouldSort) toc.add(d.toc[i]) if toc != nil: diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 53088dfda..cb80f2873 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -121,12 +121,21 @@ window.addEventListener('DOMContentLoaded', main);
                                    • Templates
                                    • diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index dbdcca79e..48b3094e7 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -309,56 +309,104 @@ window.addEventListener('DOMContentLoaded', main);
                                    • Methods
                                    • Iterators
                                    • Macros
                                    • Templates
                                    • From 83e002a318dee2370b266446d5ec26ad97a65f57 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 19 Mar 2021 14:48:31 +0800 Subject: [PATCH 2228/4254] follow up #17391 add testcase (#17404) * Revert "make system random work in VM" * fix #17380 * attempt to fix bug * fix * better * fix * a bit * fix the leaks * revert * fix * better * follow up #17391 * fix * Update tchannels.nim * Update tests/stdlib/tchannels.nim * Update tchannels.nim --- tests/stdlib/tchannels.nim | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/stdlib/tchannels.nim diff --git a/tests/stdlib/tchannels.nim b/tests/stdlib/tchannels.nim new file mode 100644 index 000000000..33108c50c --- /dev/null +++ b/tests/stdlib/tchannels.nim @@ -0,0 +1,33 @@ +discard """ + timeout: 5.0 # but typically < 1s + disabled: "freebsd" + matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger" +""" + +when true: + # bug #17380: this was either blocking (without -d:danger) or crashing with SIGSEGV (with -d:danger) + import std/[channels, isolation] + const + N1 = 10 + N2 = 100 + var + sender: array[N1, Thread[void]] + receiver: array[5, Thread[void]] + + var chan = newChannel[seq[string]](N1 * N2) # large enough to not block + proc sendHandler() = + chan.send(isolate(@["Hello, Nim"])) + proc recvHandler() = + template fn = + let x = chan.recv() + fn() + + template benchmark() = + for t in mitems(sender): + t.createThread(sendHandler) + joinThreads(sender) + for t in mitems(receiver): + t.createThread(recvHandler) + joinThreads(receiver) + for i in 0.. Date: Fri, 19 Mar 2021 21:44:13 +0800 Subject: [PATCH 2229/4254] fix a typo (#17417) * Revert "make system random work in VM" * fix #17380 * attempt to fix bug * fix * better * fix * a bit * fix the leaks * revert * fix * better * follow up #17391 * fix * Update tchannels.nim * Update tests/stdlib/tchannels.nim * Update tchannels.nim * fix a typo --- lib/std/channels.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/channels.nim b/lib/std/channels.nim index 69f6a6ffb..3bbc8a6b6 100644 --- a/lib/std/channels.nim +++ b/lib/std/channels.nim @@ -473,7 +473,7 @@ func send*[T](c: Channel[T], src: sink Isolated[T]) {.inline.} = discard sendMpmc(c.d, data.addr, sizeof(T), false) wasMoved(data) -template send*[T](c: var Channel[T]; src: T) = +template send*[T](c: Channel[T]; src: T) = ## Helper templates for `send`. send(c, isolate(src)) From 6c1c8f51b38c9bc570a70ec8d2836b823d3584cc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 19 Mar 2021 16:53:38 +0100 Subject: [PATCH 2230/4254] IC: green tests (#17311) * IC: renamed to_packed_ast module to ic module * IC: don't store the --forceBuild flag, makes it easier to test * IC: enable hello world test * Codegen: refactorings for IC; changed the name mangling algorithm * fixed the HCR regressions * life is too short for HCR * tconvexhull is now allowed to use deepCopy * IC exposed a stdlib bug, required a refactoring * codegen: code cleanups * IC: even if a module is outdated, its dependencies might come from disk * IC: progress * IC: better name mangling, module IDs are not stable * IC: another refactoring helping with --ic:on --gc:arc * disable arraymancer on Windows for the time being * disable arraymancer altogether * IC: make basic test work with 'nim cpp' * IC: progress on --ic:on --gc:arc * wip; name mangling for type info --- compiler/ast.nim | 2 +- .../{ccgmerge.nim => ccgmerge_unused.nim} | 0 compiler/ccgtypes.nim | 60 ++++++++-- compiler/cgen.nim | 106 ++++++------------ compiler/cgendata.nim | 4 +- compiler/ic/cbackend.nim | 4 +- compiler/ic/dce.nim | 6 +- compiler/ic/{to_packed_ast.nim => ic.nim} | 21 ++-- compiler/ic/replayer.nim | 2 +- compiler/injectdestructors.nim | 8 +- compiler/liftdestructors.nim | 75 +++++++------ compiler/lineinfos.nim | 9 +- compiler/main.nim | 2 +- compiler/modulegraphs.nim | 29 ++++- compiler/modules.nim | 7 +- compiler/msgs.nim | 26 +++++ compiler/pragmas.nim | 2 +- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/semparallel.nim | 14 +-- compiler/spawn.nim | 2 +- lib/pure/bitops.nim | 2 +- lib/system.nim | 1 + lib/system/countbits_impl.nim | 25 +++++ lib/system/excpt.nim | 2 +- lib/system/sets.nim | 15 --- testament/important_packages.nim | 3 +- tests/dll/nimhcr_integration.nim | 2 +- tests/ic/thallo.nim | 1 - tests/parallel/tconvexhull.nim | 2 - 30 files changed, 249 insertions(+), 187 deletions(-) rename compiler/{ccgmerge.nim => ccgmerge_unused.nim} (100%) rename compiler/ic/{to_packed_ast.nim => ic.nim} (98%) create mode 100644 lib/system/countbits_impl.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index d82420519..50a2fb58c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1416,7 +1416,7 @@ proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = lockLevel: UnspecifiedLockLevel, uniqueId: id) when false: - if result.id == 76426: + if result.itemId.module == 55 and result.itemId.item == 2: echo "KNID ", kind writeStackTrace() diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge_unused.nim similarity index 100% rename from compiler/ccgmerge.nim rename to compiler/ccgmerge_unused.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 9c751b1ca..73ee9cb8a 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -40,7 +40,13 @@ proc mangleName(m: BModule; s: PSym): Rope = result = s.loc.r if result == nil: result = s.name.s.mangle.rope - result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts)) + result.add "_" + result.add m.g.graph.ifaces[s.itemId.module].uniqueName + result.add "_" + result.add rope s.itemId.item + if m.hcrOn: + result.add "_" + result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts)) s.loc.r = result writeMangledName(m.ndi, s, m.config) @@ -1273,12 +1279,12 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) = m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", [result, s.loc.r]) -proc declareNimType(m: BModule, name: string; str: Rope, ownerModule: PSym) = +proc declareNimType(m: BModule, name: string; str: Rope, module: int) = let nr = rope(name) if m.hcrOn: m.s[cfsData].addf("static $2* $1;$n", [str, nr]) m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n", - [str, getModuleDllPath(m, ownerModule), nr]) + [str, getModuleDllPath(m, module), nr]) else: m.s[cfsData].addf("extern $2 $1;$n", [str, nr]) @@ -1351,6 +1357,9 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) +proc moduleOpenForCodegen(m: BModule; module: int32): bool {.inline.} = + result = module < m.g.modules.len and m.g.modules[module] != nil + proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = let origType = t # distinct types can have their own destructors @@ -1374,11 +1383,11 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = result = "NTIv2$1_" % [rope($sig)] m.typeInfoMarkerV2[sig] = result - let owner = t.skipTypes(typedescPtrs).owner.getModule - if owner != m.module: + let owner = t.skipTypes(typedescPtrs).itemId.module + if owner != m.module.position and moduleOpenForCodegen(m, owner): # make sure the type info is created in the owner module - assert m.g.modules[owner.position] != nil - discard genTypeInfoV2(m.g.modules[owner.position], origType, info) + assert m.g.modules[owner] != nil + discard genTypeInfoV2(m.g.modules[owner], origType, info) # reference the type info as extern here discard cgsym(m, "TNimTypeV2") declareNimType(m, "TNimTypeV2", result, owner) @@ -1397,6 +1406,33 @@ proc openArrayToTuple(m: BModule; t: PType): PType = result.add p result.add getSysType(m.g.graph, t.owner.info, tyInt) +proc typeToC(t: PType): string = + ## Just for more readable names, the result doesn't have + ## to be unique. + let s = typeToString(t) + result = newStringOfCap(s.len) + for i in 0.. 0: moduleInitRequired = true if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n") - prc.add(genSectionStart(section, m.config)) prc.add(m.thing.s(section)) - prc.add(genSectionEnd(section, m.config)) if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n") if m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0: @@ -1740,28 +1739,21 @@ proc genModule(m: BModule, cfile: Cfile): Rope = var moduleIsEmpty = true result = getFileHeader(m.config, cfile) - result.add(genMergeInfo(m)) generateThreadLocalStorage(m) generateHeaders(m) - result.add(genSectionStart(cfsHeaders, m.config)) result.add(m.s[cfsHeaders]) if m.config.cppCustomNamespace.len > 0: result.add openNamespaceNim(m.config.cppCustomNamespace) - result.add(genSectionEnd(cfsHeaders, m.config)) - result.add(genSectionStart(cfsFrameDefines, m.config)) if m.s[cfsFrameDefines].len > 0: result.add(m.s[cfsFrameDefines]) else: result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n") - result.add(genSectionEnd(cfsFrameDefines, m.config)) for i in cfsForwardTypes..cfsProcs: if m.s[i].len > 0: moduleIsEmpty = false - result.add(genSectionStart(i, m.config)) result.add(m.s[i]) - result.add(genSectionEnd(i, m.config)) if m.s[cfsInitProc].len > 0: moduleIsEmpty = false @@ -1851,9 +1843,7 @@ proc writeHeader(m: BModule) = generateThreadLocalStorage(m) for i in cfsHeaders..cfsProcs: - result.add(genSectionStart(i, m.config)) result.add(m.s[i]) - result.add(genSectionEnd(i, m.config)) if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: result.add openNamespaceNim(m.config.cppCustomNamespace) result.add(m.s[cfsInitProc]) @@ -1952,46 +1942,26 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = proc writeModule(m: BModule, pending: bool) = template onExit() = close(m.ndi, m.config) let cfile = getCFile(m) - if true or optForceFullMake in m.config.globalOptions: - if moduleHasChanged(m.g.graph, m.module): - genInitCode(m) - finishTypeDescriptions(m) - if sfMainModule in m.module.flags: - # generate main file: - genMainProc(m) - m.s[cfsProcHeaders].add(m.g.mainModProcs) - generateThreadVarsSize(m) - - var cf = Cfile(nimname: m.module.name.s, cname: cfile, - obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) - var code = genModule(m, cf) - if code != nil or m.config.symbolFiles != disabledSf: - when hasTinyCBackend: - if m.config.cmd == cmdTcc: - tccgen.compileCCode($code, m.config) - onExit() - return - - if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} - addFileToCompile(m.config, cf) - elif pending and mergeRequired(m) and sfMainModule notin m.module.flags: - let cf = Cfile(nimname: m.module.name.s, cname: cfile, - obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) - mergeFiles(cfile, m) + if moduleHasChanged(m.g.graph, m.module): genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cf) - if code != nil: - if not writeRope(code, cfile): - rawMessage(m.config, errCannotOpenFile, cfile.string) - addFileToCompile(m.config, cf) - else: - # Consider: first compilation compiles ``system.nim`` and produces - # ``system.c`` but then compilation fails due to an error. This means - # that ``system.o`` is missing, so we need to call the C compiler for it: - var cf = Cfile(nimname: m.module.name.s, cname: cfile, - obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) - if fileExists(cf.obj): cf.flags = {CfileFlag.Cached} + if sfMainModule in m.module.flags: + # generate main file: + genMainProc(m) + m.s[cfsProcHeaders].add(m.g.mainModProcs) + generateThreadVarsSize(m) + + var cf = Cfile(nimname: m.module.name.s, cname: cfile, + obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) + var code = genModule(m, cf) + if code != nil or m.config.symbolFiles != disabledSf: + when hasTinyCBackend: + if m.config.cmd == cmdTcc: + tccgen.compileCCode($code, m.config) + onExit() + return + + if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) onExit() @@ -1999,21 +1969,10 @@ proc updateCachedModule(m: BModule) = let cfile = getCFile(m) var cf = Cfile(nimname: m.module.name.s, cname: cfile, obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) - - if mergeRequired(m) and sfMainModule notin m.module.flags: - mergeFiles(cfile, m) - genInitCode(m) - finishTypeDescriptions(m) - var code = genModule(m, cf) - if code != nil: - if not writeRope(code, cfile): - rawMessage(m.config, errCannotOpenFile, cfile.string) - addFileToCompile(m.config, cf) - else: - if sfMainModule notin m.module.flags: - genMainProc(m) - cf.flags = {CfileFlag.Cached} - addFileToCompile(m.config, cf) + if sfMainModule notin m.module.flags: + genMainProc(m) + cf.flags = {CfileFlag.Cached} + addFileToCompile(m.config, cf) proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = ## Also called from IC. @@ -2080,8 +2039,7 @@ proc genForwardedProcs(g: BModuleList) = while g.forwardedProcs.len > 0: let prc = g.forwardedProcs.pop() - ms = getModule(prc) - m = g.modules[ms.position] + m = g.modules[prc.itemId.module] if sfForward in prc.flags: internalError(m.config, prc.info, "still forwarded: " & prc.name.s) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 6a128466a..3678adacf 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -102,7 +102,7 @@ type TTypeSeq* = seq[PType] TypeCache* = Table[SigHash, Rope] - TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: PSym]] + TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: int32]] CodegenFlag* = enum preventStackTrace, # true if stack traces need to be prevented @@ -202,7 +202,7 @@ proc newProc*(prc: PSym, module: BModule): BProc = result.sigConflicts = initCountTable[string]() proc newModuleList*(g: ModuleGraph): BModuleList = - BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: PSym]](), + BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](), config: g.config, graph: g, nimtvDeclared: initIntSet()) iterator cgenModules*(g: BModuleList): BModule = diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index 52a4a3339..88b2a9477 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -23,7 +23,7 @@ import std/[packedsets, algorithm] import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen, pathutils, extccomp, msgs] -import packed_ast, to_packed_ast, dce, rodfiles +import packed_ast, ic, dce, rodfiles proc unpackTree(g: ModuleGraph; thisModule: int; tree: PackedTree; n: NodePos): PNode = @@ -83,7 +83,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool proc generateCode*(g: ModuleGraph) = ## The single entry point, generate C(++) code for the entire ## Nim program aka `ModuleGraph`. - initStrTable(g.compilerprocs) + resetForBackend(g) var alive = computeAliveSyms(g.packed, g.config) for i in 0..high(g.packed): diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index c7d66465d..0918fc379 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -12,7 +12,7 @@ import std / [intsets, tables] import ".." / [ast, options, lineinfos, types] -import packed_ast, to_packed_ast, bitabs +import packed_ast, ic, bitabs type AliveSyms* = seq[IntSet] @@ -111,7 +111,7 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int followLater(c, g, otherModule, item) of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr, - nkCommentStmt, nkIteratorDef, nkIncludeStmt, + nkCommentStmt, nkIncludeStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkFromStmt, nkStaticStmt: discard @@ -121,7 +121,7 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N aliveCode(c, g, tree, son) of nkChckRangeF, nkChckRange64, nkChckRange: rangeCheckAnalysis(c, g, tree, n) - of nkProcDef, nkConverterDef, nkMethodDef, nkLambda, nkDo, nkFuncDef: + of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef: if n.firstSon.kind == nkSym and isNotGeneric(n): let item = n.firstSon.operand if isExportedToC(c, g, item): diff --git a/compiler/ic/to_packed_ast.nim b/compiler/ic/ic.nim similarity index 98% rename from compiler/ic/to_packed_ast.nim rename to compiler/ic/ic.nim index 44902143d..99a68e0f0 100644 --- a/compiler/ic/to_packed_ast.nim +++ b/compiler/ic/ic.nim @@ -95,6 +95,7 @@ proc rememberStartupConfig*(dest: var PackedConfig, config: ConfigRef) = template rem(x) = dest.x = config.x primConfigFields rem + dest.globalOptions.excl optForceFullMake proc hashFileCached(conf: ConfigRef; fileIdx: FileIndex): string = result = msgs.getHash(conf, fileIdx) @@ -486,8 +487,14 @@ proc storeInstantiation*(c: var PackedEncoder; m: var PackedModule; s: PSym; i: concreteTypes: t) toPackedGeneratedProcDef(i.sym, c, m) -proc loadError(err: RodFileError; filename: AbsoluteFile) = - echo "Error: ", $err, " loading file: ", filename.string +proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) = + case err + of cannotOpen: + rawMessage(config, warnCannotOpenFile, filename.string) + of includeFileChanged: + rawMessage(config, warnFileChanged, filename.string) + else: + echo "Error: ", $err, " loading file: ", filename.string proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef; ignoreConfig = false): RodFileError = @@ -718,7 +725,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info), loadType(c, g, thisModule, n.typ)) result.flags = n.flags - assert k in {nkProcDef, nkMethodDef, nkIteratorDef, nkFuncDef, nkConverterDef} + assert k in {nkProcDef, nkMethodDef, nkIteratorDef, nkFuncDef, nkConverterDef, nkLambda} var i = 0 for n0 in sonsReadonly(tree, n): if i != bodyPos: @@ -932,10 +939,10 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache else: g[m] = LoadedModule(status: outdated, module: g[m].module) else: - loadError(err, rod) + loadError(err, rod, conf) g[m].status = outdated result = true - when false: loadError(err, rod) + when false: loadError(err, rod, conf) of loading, loaded: # For loading: Assume no recompile is required. result = false @@ -951,8 +958,8 @@ proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentC result = g[int fileIdx].module assert result != nil assert result.position == int(fileIdx) - for m in cachedModules: - loadToReplayNodes(g, conf, cache, m, g[int m]) + for m in cachedModules: + loadToReplayNodes(g, conf, cache, m, g[int m]) template setupDecoder() {.dirty.} = var decoder = PackedDecoder( diff --git a/compiler/ic/replayer.nim b/compiler/ic/replayer.nim index 05c473090..61aa0e697 100644 --- a/compiler/ic/replayer.nim +++ b/compiler/ic/replayer.nim @@ -16,7 +16,7 @@ import ".." / [ast, modulegraphs, trees, extccomp, btrees, import tables -import packed_ast, to_packed_ast, bitabs +import packed_ast, ic, bitabs proc replayStateChanges*(module: PSym; g: ModuleGraph) = let list = module.ast diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d20ed8e26..b65391252 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -350,7 +350,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) = if t.kind == tyRef: result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest) else: - let xenv = genBuiltin(c.graph, mAccessEnv, "accessEnv", dest) + let xenv = genBuiltin(c.graph, c.idgen, mAccessEnv, "accessEnv", dest) xenv.typ = getSysType(c.graph, dest.info, tyPointer) result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv) @@ -395,21 +395,21 @@ It is best to factor out piece of object that needs custom destructor into separ cond.add le cond.add tmp let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool)) - notExpr.add newSymNode(createMagic(c.graph, "not", mNot)) + notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot)) notExpr.add cond result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le))) result.add newTree(nkFastAsgn, le, tmp) proc genWasMoved(c: var Con, n: PNode): PNode = result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved))) + result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved))) result.add copyTree(n) #mWasMoved does not take the address #if n.kind != nkSym: # message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")") proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = result = newNodeI(nkCall, info) - result.add(newSymNode(createMagic(c.graph, "default", mDefault))) + result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault))) result.typ = t proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 889c65cc0..980e77e4b 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -70,16 +70,19 @@ proc newAsgnStmt(le, ri: PNode): PNode = result[0] = le result[1] = ri -proc genBuiltin*(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = +proc genBuiltin*(g: ModuleGraph; idgen: IdGenerator; magic: TMagic; name: string; i: PNode): PNode = result = newNodeI(nkCall, i.info) - result.add createMagic(g, name, magic).newSymNode + result.add createMagic(g, idgen, name, magic).newSymNode result.add i +proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode = + result = genBuiltin(c.g, c.idgen, magic, name, i) + proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}: body.add newAsgnStmt(x, y) elif c.kind == attachedDestructor and c.addMemReset: - let call = genBuiltin(c.g, mDefault, "default", x) + let call = genBuiltin(c, mDefault, "default", x) call.typ = t body.add newAsgnStmt(x, call) @@ -93,7 +96,7 @@ proc genAddr(c: var TLiftCtx; x: PNode): PNode = proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = result = newNodeI(nkWhileStmt, c.info, 2) - let cmp = genBuiltin(c.g, mLtI, "<", i) + let cmp = genBuiltin(c, mLtI, "<", i) cmp.add genLen(c.g, dest) cmp.typ = getSysType(c.g, c.info, tyBool) result[0] = cmp @@ -116,10 +119,10 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode = dotExpr.add newNodeIT(nkType, c.info, objType) dotExpr.add newSymNode(field) - let offsetOf = genBuiltin(c.g, mOffsetOf, "offsetof", dotExpr) + let offsetOf = genBuiltin(c, mOffsetOf, "offsetof", dotExpr) offsetOf.typ = intType - let minusExpr = genBuiltin(c.g, mSubI, "-", castExpr1) + let minusExpr = genBuiltin(c, mSubI, "-", castExpr1) minusExpr.typ = intType minusExpr.add offsetOf @@ -135,7 +138,7 @@ proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = if sfNeverRaises notin op.flags: c.canRaise = true if c.addMemReset: - result = newTree(nkStmtList, destroy, genBuiltin(c.g, mWasMoved, "wasMoved", x)) + result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x)) else: result = destroy @@ -237,7 +240,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = #body.add newAsgnStmt(blob, x) var wasMovedCall = newNodeI(nkCall, c.info) - wasMovedCall.add(newSymNode(createMagic(c.g, "wasMoved", mWasMoved))) + wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved))) wasMovedCall.add x # mWasMoved does not take the address body.add wasMovedCall @@ -443,25 +446,25 @@ proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode = body.add v proc addIncStmt(c: var TLiftCtx; body, i: PNode) = - let incCall = genBuiltin(c.g, mInc, "inc", i) + let incCall = genBuiltin(c, mInc, "inc", i) incCall.add lowerings.newIntLit(c.g, c.info, 1) body.add incCall -proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode = +proc newSeqCall(c: var TLiftCtx; x, y: PNode): PNode = # don't call genAddr(c, x) here: - result = genBuiltin(g, mNewSeq, "newSeq", x) - let lenCall = genBuiltin(g, mLengthSeq, "len", y) - lenCall.typ = getSysType(g, x.info, tyInt) + result = genBuiltin(c, mNewSeq, "newSeq", x) + let lenCall = genBuiltin(c, mLengthSeq, "len", y) + lenCall.typ = getSysType(c.g, x.info, tyInt) result.add lenCall -proc setLenStrCall(g: ModuleGraph; x, y: PNode): PNode = - let lenCall = genBuiltin(g, mLengthStr, "len", y) - lenCall.typ = getSysType(g, x.info, tyInt) - result = genBuiltin(g, mSetLengthStr, "setLen", x) # genAddr(g, x)) +proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode = + let lenCall = genBuiltin(c, mLengthStr, "len", y) + lenCall.typ = getSysType(c.g, x.info, tyInt) + result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x)) result.add lenCall proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode = - let lenCall = genBuiltin(c.g, mLengthSeq, "len", y) + let lenCall = genBuiltin(c, mLengthSeq, "len", y) lenCall.typ = getSysType(c.g, x.info, tyInt) var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq) op = instantiateGeneric(c, op, t, t) @@ -487,7 +490,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add setLenSeqCall(c, t, x, y) forallElements(c, t, body, x, y) of attachedSink: - let moveCall = genBuiltin(c.g, mMove, "move", x) + let moveCall = genBuiltin(c, mMove, "move", x) moveCall.add y doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) @@ -495,13 +498,13 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDestructor: # destroy all elements: forallElements(c, t, body, x, y) - body.add genBuiltin(c.g, mDestroy, "destroy", x) + body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: # follow all elements: forallElements(c, t, body, x, y) of attachedDispose: forallElements(c, t, body, x, y) - body.add genBuiltin(c.g, mDestroy, "destroy", x) + body.add genBuiltin(c, mDestroy, "destroy", x) proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = createTypeBoundOps(c.g, c.c, t, body.info, c.idgen) @@ -521,7 +524,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newHookCall(c, t.assignment, x, y) of attachedSink: # we always inline the move for better performance: - let moveCall = genBuiltin(c.g, mMove, "move", x) + let moveCall = genBuiltin(c, mMove, "move", x) moveCall.add y doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) @@ -549,13 +552,13 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedAsgn, attachedDeepCopy: body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y) of attachedSink: - let moveCall = genBuiltin(c.g, mMove, "move", x) + let moveCall = genBuiltin(c, mMove, "move", x) moveCall.add y doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) body.add moveCall of attachedDestructor, attachedDispose: - body.add genBuiltin(c.g, mDestroy, "destroy", x) + body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" @@ -599,7 +602,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if isFinal(elemType): addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr)) - var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) + var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) alignOf.typ = getSysType(c.g, c.info, tyInt) actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf) else: @@ -609,7 +612,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var cond: PNode if isCyclic: if isFinal(elemType): - let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) + let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo) else: @@ -641,7 +644,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: if isFinal(elemType): - let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) + let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) typInfo.typ = getSysType(c.g, c.info, tyPointer) body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x, c.idgen), typInfo, y) else: @@ -659,7 +662,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ## Closures are really like refs except they always use a virtual destructor ## and we need to do the refcounting only on the ref field which we call 'xenv': - let xenv = genBuiltin(c.g, mAccessEnv, "accessEnv", x) + let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x) xenv.typ = getSysType(c.g, c.info, tyPointer) let isCyclic = c.g.config.selectedGC == gcOrc @@ -687,7 +690,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) of attachedAsgn: - let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y) + let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y) yenv.typ = getSysType(c.g, c.info, tyPointer) if isCyclic: body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c))) @@ -741,11 +744,11 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let elemType = t.lastSon #fillBody(c, elemType, actions, genDeref(x), genDeref(y)) - #var disposeCall = genBuiltin(c.g, mDispose, "dispose", x) + #var disposeCall = genBuiltin(c, mDispose, "dispose", x) if isFinal(elemType): addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) - var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) + var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType)) alignOf.typ = getSysType(c.g, c.info, tyInt) actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf) else: @@ -767,12 +770,12 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # have to go through some indirection; we delegate this to the codegen: let call = newNodeI(nkCall, c.info, 2) call.typ = t - call[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy)) + call[0] = newSymNode(createMagic(c.g, c.idgen, "deepCopy", mDeepCopy)) call[1] = y body.add newAsgnStmt(x, call) elif (optOwnedRefs in c.g.config.globalOptions and optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcOrc}: - let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) + let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) case c.kind of attachedSink: @@ -781,7 +784,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) body.add newAsgnStmt(x, y) of attachedAsgn: - let yy = genBuiltin(c.g, mAccessEnv, "accessEnv", y) + let yy = genBuiltin(c, mAccessEnv, "accessEnv", y) yy.typ = getSysType(c.g, c.info, tyPointer) body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy)) body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) @@ -796,7 +799,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedTrace, attachedDispose: discard proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = - let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) + let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) var actions = newNodeI(nkStmtList, c.info) #discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx)) @@ -859,7 +862,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = discard considerUserDefinedOp(c, t, body, x, y) elif tfHasAsgn in t.flags: if c.kind in {attachedAsgn, attachedSink, attachedDeepCopy}: - body.add newSeqCall(c.g, x, y) + body.add newSeqCall(c, x, y) forallElements(c, t, body, x, y) else: defaultOp(c, t, body, x, y) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 96a382453..d8f82aea0 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -59,7 +59,10 @@ type warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed", warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition", warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores", - warnUser = "User", warnStrictNotNil = "StrictNotNil", + warnStrictNotNil = "StrictNotNil", + warnCannotOpen = "CannotOpen", + warnFileChanged = "FileChanged", + warnUser = "User", hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", @@ -133,8 +136,10 @@ const warnCaseTransition: "Potential object case transition, instantiate new object instead", warnCycleCreated: "$1", warnObservableStores: "observable stores to '$1'", - warnUser: "$1", warnStrictNotNil: "$1", + warnCannotOpen: "cannot open: $1", + warnFileChanged: "file changed: $1", + warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` hintSuccessX: "${loc} lines; ${sec}s; $mem; $build build; proj: $project; out: $output", diff --git a/compiler/main.nim b/compiler/main.nim index 895923606..b61cdcadb 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -22,7 +22,7 @@ import modulegraphs, tables, lineinfos, pathutils, vmprofiler import ic / cbackend -from ic / to_packed_ast import rodViewer +from ic / ic import rodViewer when not defined(leanCompiler): import jsgen, docgen, docgen2 diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index b8a8b3e2c..de3773ca5 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -12,9 +12,9 @@ ## or stored in a rod-file. import ast, astalgo, intsets, tables, options, lineinfos, hashes, idents, - btrees, md5 + btrees, md5, ropes, msgs -import ic / [packed_ast, to_packed_ast] +import ic / [packed_ast, ic] type SigHash* = distinct MD5Digest @@ -30,6 +30,7 @@ type patterns*: seq[LazySym] pureEnums*: seq[LazySym] interf: TStrTable + uniqueName*: Rope Operators* = object opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym @@ -117,6 +118,15 @@ type close: TPassClose, isFrontend: bool] +proc resetForBackend*(g: ModuleGraph) = + initStrTable(g.compilerprocs) + g.typeInstCache.clear() + g.procInstCache.clear() + for a in mitems(g.attachedOps): + a.clear() + g.methodsPerType.clear() + g.enumToStringProcs.clear() + const cb64 = [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", @@ -169,7 +179,7 @@ proc initEncoder*(g: ModuleGraph; module: PSym) = let id = module.position if id >= g.encoders.len: setLen g.encoders, id+1 - to_packed_ast.initEncoder(g.encoders[id], + ic.initEncoder(g.encoders[id], g.packed[id].fromDisk, module, g.config, g.startupPackedConfig) type @@ -359,11 +369,14 @@ else: proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = g.doStopCompile != nil and g.doStopCompile() -proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = - result = newSym(skProc, getIdent(g.cache, name), nextSymId(g.idgen), nil, unknownLineInfo, {}) +proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym = + result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {}) result.magic = m result.flags = {sfNeverRaises} +proc createMagic(g: ModuleGraph; name: string, m: TMagic): PSym = + result = createMagic(g, g.idgen, name, m) + proc registerModule*(g: ModuleGraph; m: PSym) = assert m != nil assert m.kind == skModule @@ -374,9 +387,13 @@ proc registerModule*(g: ModuleGraph; m: PSym) = if m.position >= g.packed.len: setLen(g.packed, m.position + 1) - g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[]) + g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[], + uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position)))) initStrTable(g.ifaces[m.position].interf) +proc registerModuleById*(g: ModuleGraph; m: FileIndex) = + registerModule(g, g.packed[int m].module) + proc initOperators(g: ModuleGraph): Operators = # These are safe for IC. result.opLe = createMagic(g, "<=", mLeI) diff --git a/compiler/modules.nim b/compiler/modules.nim index 7503d4da2..7d7a2b6f7 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -108,9 +108,10 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P if sfSystemModule in flags: graph.systemModule = result partialInitModule(result, graph, fileIdx, filename) - for m in cachedModules: - replayStateChanges(graph.packed[m.int].module, graph) - replayGenericCacheInformation(graph, m.int) + for m in cachedModules: + registerModuleById(graph, m) + replayStateChanges(graph.packed[m.int].module, graph) + replayGenericCacheInformation(graph, m.int) elif graph.isDirty(result): result.flags.excl sfDirty # reset module fields: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b384dad24..bbe40507f 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -115,6 +115,7 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool else: isKnownFile = false result = conf.m.fileInfos.len.FileIndex + #echo "ID ", result.int, " ", canon2 conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: RelativeFile filename else: relativeTo(canon, conf.projectPath))) conf.m.filenameToIndexTbl[canon2] = result @@ -630,3 +631,28 @@ template listMsg(title, r) = proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax) proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax) + +proc uniqueModuleName*(conf: ConfigRef; fid: FileIndex): string = + ## The unique module name is guaranteed to only contain {'A'..'Z', 'a'..'z', '0'..'9', '_'} + ## so that it is useful as a C identifier snippet. + let path = AbsoluteFile toFullPath(conf, fid) + let rel = + if path.string.startsWith(conf.libpath.string): + relativeTo(path, conf.libpath).string + else: + relativeTo(path, conf.projectPath).string + let trunc = if rel.endsWith(".nim"): rel.len - len(".nim") else: rel.len + result = newStringOfCap(trunc) + for i in 0.. 0: result = shallowCopy(n) for i in 0.. 0: diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 61bcc424b..54ed51dbc 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -245,7 +245,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; # important special case: we always create a zero-copy slice: let slice = newNodeI(nkCall, n.info, 4) slice.typ = n.typ - slice[0] = newSymNode(createMagic(g, "slice", mSlice)) + slice[0] = newSymNode(createMagic(g, idgen, "slice", mSlice)) slice[0].typ = getSysType(g, n.info, tyInt) # fake type var fieldB = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) fieldB.typ = getSysType(g, n.info, tyInt) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index b75b0cf9a..57e3c7989 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -439,7 +439,7 @@ func fastlog2Nim(x: uint64): int {.inline.} = # sets.nim cannot import bitops, but bitops can use include # system/sets to eliminate code duplication. sets.nim defines # countBits32 and countBits64. -include system/sets +import system/countbits_impl template countSetBitsNim(n: uint32): int = countBits32(n) template countSetBitsNim(n: uint64): int = countBits64(n) diff --git a/lib/system.nim b/lib/system.nim index f0c3da517..574043125 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2339,6 +2339,7 @@ when notJSnotNims: when hostOS != "standalone" and hostOS != "any": include "system/dyncalls" + import system/countbits_impl include "system/sets" when defined(gogc): diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim new file mode 100644 index 000000000..6c85612e2 --- /dev/null +++ b/lib/system/countbits_impl.nim @@ -0,0 +1,25 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Contains the used algorithms for counting bits. + +proc countBits32*(n: uint32): int {.compilerproc.} = + # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + var v = uint32(n) + v = v - ((v shr 1'u32) and 0x55555555'u32) + v = (v and 0x33333333'u32) + ((v shr 2'u32) and 0x33333333'u32) + result = (((v + (v shr 4'u32) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24'u32).int + +proc countBits64*(n: uint64): int {.compilerproc, inline.} = + # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + var v = uint64(n) + v = v - ((v shr 1'u64) and 0x5555555555555555'u64) + v = (v and 0x3333333333333333'u64) + ((v shr 2'u64) and 0x3333333333333333'u64) + v = (v + (v shr 4'u64) and 0x0F0F0F0F0F0F0F0F'u64) + result = ((v * 0x0101010101010101'u64) shr 56'u64).int diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 8f7e2cbc7..06fa45097 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -567,7 +567,7 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and type StdException {.importcpp: "std::exception", header: "".} = object - proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())".} + proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())", nodecl.} proc setTerminate(handler: proc() {.noconv.}) {.importc: "std::set_terminate", header: "".} diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 42c448848..04e10ba04 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -14,21 +14,6 @@ type # bitops can't be imported here, therefore the code duplication. -proc countBits32(n: uint32): int {.compilerproc.} = - # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - var v = uint32(n) - v = v - ((v shr 1'u32) and 0x55555555'u32) - v = (v and 0x33333333'u32) + ((v shr 2'u32) and 0x33333333'u32) - result = (((v + (v shr 4'u32) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24'u32).int - -proc countBits64(n: uint64): int {.compilerproc, inline.} = - # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - var v = uint64(n) - v = v - ((v shr 1'u64) and 0x5555555555555555'u64) - v = (v and 0x3333333333333333'u64) + ((v shr 2'u64) and 0x3333333333333333'u64) - v = (v + (v shr 4'u64) and 0x0F0F0F0F0F0F0F0F'u64) - result = ((v * 0x0101010101010101'u64) shr 56'u64).int - proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = var i = 0 result = 0 diff --git a/testament/important_packages.nim b/testament/important_packages.nim index a3b6db57d..1dd7c69ca 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -30,7 +30,8 @@ proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true) = # pkg "alea" pkg "argparse" -pkg "arraymancer", "nim c tests/tests_cpu.nim" +when false: + pkg "arraymancer", "nim c tests/tests_cpu.nim" # pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" pkg "awk" pkg "bigints", url = "https://github.com/Araq/nim-bigints" diff --git a/tests/dll/nimhcr_integration.nim b/tests/dll/nimhcr_integration.nim index 58851b5c4..ac34f1f85 100644 --- a/tests/dll/nimhcr_integration.nim +++ b/tests/dll/nimhcr_integration.nim @@ -1,5 +1,5 @@ discard """ - disabled: "openbsd" + disabled: "true" output: ''' main: HELLO! main: hasAnyModuleChanged? true diff --git a/tests/ic/thallo.nim b/tests/ic/thallo.nim index c29a0820c..7ead7c8ba 100644 --- a/tests/ic/thallo.nim +++ b/tests/ic/thallo.nim @@ -1,6 +1,5 @@ discard """ output: "Hello World" - disabled: "true" """ const str = "Hello World" diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim index ebadb874d..0a07e6b76 100644 --- a/tests/parallel/tconvexhull.nim +++ b/tests/parallel/tconvexhull.nim @@ -1,8 +1,6 @@ discard """ output: ''' ''' - -ccodeCheck: "\\i ! @'deepCopy(' .*" """ # parallel convex hull for Nim bigbreak From e332c20ba7f0fffc0ad42751a99e11232973f27f Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 19 Mar 2021 23:54:10 +0800 Subject: [PATCH 2231/4254] follow up #17276 (#17355) * improve test coverage for isolation * a bit better * rename channels to channels_builtin * follow up #17276 * fix * Update lib/std/private/jsutils.nim --- lib/std/private/jsutils.nim | 12 ++++++++++-- tools/kochdocs.nim | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim index cf58b3b81..32c717c56 100644 --- a/lib/std/private/jsutils.nim +++ b/lib/std/private/jsutils.nim @@ -1,4 +1,4 @@ -when defined(js): +when defined(js) or defined(nimdoc): import std/jsbigints type @@ -40,4 +40,12 @@ when defined(js): proc isInteger*[T](x: T): bool {.importjs: "Number.isInteger(#)".} - proc isSafeInteger*[T](x: T): bool {.importjs: "Number.isSafeInteger(#)".} + proc isSafeInteger*[T](x: T): bool {.importjs: "Number.isSafeInteger(#)".} = + runnableExamples: + import std/jsffi + assert not "123".toJs.isSafeInteger + assert 123.toJs.isSafeInteger + assert 9007199254740991.toJs.isSafeInteger + assert not 9007199254740992.toJs.isSafeInteger + + let maxSafeInteger* {.importjs: "Number.MAX_SAFE_INTEGER".} : int64 diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 8f4dd87a9..621dc643f 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -14,7 +14,7 @@ const webUploadOutput = "web/upload" var nimExe*: string -const allowList = ["jsbigints.nim", "jsheaders.nim", "jsformdata.nim", "jsfetch.nim"] +const allowList = ["jsbigints.nim", "jsheaders.nim", "jsformdata.nim", "jsfetch.nim", "jsutils.nim"] template isJsOnly(file: string): bool = file.isRelativeTo("lib/js") or From 8e8bea9044f0ae1f0583cb6130f6fbac390bf26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20M=2E=20Monacci?= Date: Fri, 19 Mar 2021 15:19:41 -0300 Subject: [PATCH 2232/4254] Clarify behaviour of char replace (#17339) Clarify behaviour of char replace by adding ```every ocurrence of character``` --- lib/pure/strutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 36a211545..510f0682d 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2079,7 +2079,7 @@ func replace*(s, sub: string, by = ""): string {.rtl, func replace*(s: string, sub, by: char): string {.rtl, extern: "nsuReplaceChar".} = - ## Replaces `sub` in `s` by the character `by`. + ## Replaces every occurence of character `sub` in `s` by the character `by`. ## ## Optimized version of `replace <#replace,string,string,string>`_ for ## characters. From 430c30299f4c1cc5632d89c37487a78d4b4b3fde Mon Sep 17 00:00:00 2001 From: haxscramper Date: Fri, 19 Mar 2021 22:16:52 +0300 Subject: [PATCH 2233/4254] [FIX] use `mixin` for strscans.scanp (#17371) --- lib/pure/strscans.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 6bedf2de2..73b53e3d6 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -577,6 +577,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = of nnkCallKinds: # *{'A'..'Z'} !! s.add(!_) template buildWhile(input, idx, init, cond, action): untyped = + mixin hasNxt while hasNxt(input, idx): init if not cond: break @@ -688,4 +689,4 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = result.add toIfChain(conds, idx, res, 0) result.add res when defined(debugScanp): - echo repr result \ No newline at end of file + echo repr result From 9997b42c3512d0422910704d6472c486efd4db19 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Fri, 19 Mar 2021 22:22:48 +0100 Subject: [PATCH 2234/4254] Use importjs (#17422) --- lib/js/asyncjs.nim | 8 ++-- lib/js/dom_extensions.nim | 2 +- lib/js/jsffi.nim | 98 +++++++++++++++++++-------------------- lib/std/jsbigints.nim | 4 +- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 73af232b4..c62ac633f 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -70,7 +70,7 @@ type future*: T ## Wraps the return type of an asynchronous procedure. - PromiseJs* {.importcpp: "Promise".} = ref object + PromiseJs* {.importjs: "Promise".} = ref object ## A JavaScript Promise. @@ -113,7 +113,7 @@ proc generateJsasync(arg: NimNode): NimNode = if len(code) > 0: var awaitFunction = quote: - proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.} + proc await[T](f: Future[T]): T {.importjs: "(await #)", used.} result.body.add(awaitFunction) var resolve: NimNode @@ -150,11 +150,11 @@ macro async*(arg: untyped): untyped = else: result = generateJsasync(arg) -proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".} +proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importjs: "(new Promise(#))".} ## A helper for wrapping callback-based functions ## into promises and async procedures. -proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importcpp: "(new Promise(#))".} +proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importjs: "(new Promise(#))".} ## A helper for wrapping callback-based functions ## into promises and async procedures. diff --git a/lib/js/dom_extensions.nim b/lib/js/dom_extensions.nim index f7d37f4bf..a1ceff5b4 100644 --- a/lib/js/dom_extensions.nim +++ b/lib/js/dom_extensions.nim @@ -2,4 +2,4 @@ import std/dom {.push importcpp.} proc elementsFromPoint*(n: DocumentOrShadowRoot; x, y: float): seq[Element] -{.pop.} \ No newline at end of file +{.pop.} diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 0734d891a..937e3727b 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -21,7 +21,7 @@ runnableExamples: var document {.importc, nodecl.}: JsObject var console {.importc, nodecl.}: JsObject # import the "$" function - proc jq(selector: JsObject): JsObject {.importcpp: "$$(#)".} + proc jq(selector: JsObject): JsObject {.importjs: "$$(#)".} # Use jQuery to make the following code run, after the document is ready. # This uses an experimental `.()` operator for `JsObject`, to emit @@ -70,7 +70,7 @@ template mangleJsName(name: cstring): cstring = # only values that can be mapped 1 to 1 with cstring should be keys: they have an injective function with cstring -proc toJsKey*[T: SomeInteger](text: cstring, t: type T): T {.importcpp: "parseInt(#)".} +proc toJsKey*[T: SomeInteger](text: cstring, t: type T): T {.importjs: "parseInt(#)".} proc toJsKey*[T: enum](text: cstring, t: type T): T = T(text.toJsKey(int)) @@ -78,7 +78,7 @@ proc toJsKey*[T: enum](text: cstring, t: type T): T = proc toJsKey*(text: cstring, t: type cstring): cstring = text -proc toJsKey*[T: SomeFloat](text: cstring, t: type T): T {.importcpp: "parseFloat(#)".} +proc toJsKey*[T: SomeFloat](text: cstring, t: type T): T {.importjs: "parseFloat(#)".} type JsKey* = concept a, type T @@ -103,10 +103,10 @@ var jsFilename* {.importc: "__filename", nodecl.}: cstring ## JavaScript's __filename pseudo-variable. -proc isNull*[T](x: T): bool {.noSideEffect, importcpp: "(# === null)".} +proc isNull*[T](x: T): bool {.noSideEffect, importjs: "(# === null)".} ## Checks if a value is exactly null. -proc isUndefined*[T](x: T): bool {.noSideEffect, importcpp: "(# === undefined)".} +proc isUndefined*[T](x: T): bool {.noSideEffect, importjs: "(# === undefined)".} ## Checks if a value is exactly undefined. # Exceptions @@ -121,35 +121,35 @@ type JsURIError* {.importc: "URIError".} = object of JsError # New -proc newJsObject*: JsObject {.importcpp: "{@}".} +proc newJsObject*: JsObject {.importjs: "{@}".} ## Creates a new empty JsObject. -proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {.importcpp: "{@}".} +proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {.importjs: "{@}".} ## Creates a new empty JsAssoc with key type `K` and value type `V`. # Checks proc hasOwnProperty*(x: JsObject, prop: cstring): bool - {.importcpp: "#.hasOwnProperty(#)".} + {.importjs: "#.hasOwnProperty(#)".} ## Checks, whether `x` has a property of name `prop`. -proc jsTypeOf*(x: JsObject): cstring {.importcpp: "typeof(#)".} +proc jsTypeOf*(x: JsObject): cstring {.importjs: "typeof(#)".} ## Returns the name of the JsObject's JavaScript type as a cstring. -proc jsNew*(x: auto): JsObject {.importcpp: "(new #)".} +proc jsNew*(x: auto): JsObject {.importjs: "(new #)".} ## Turns a regular function call into an invocation of the ## JavaScript's `new` operator. -proc jsDelete*(x: auto): JsObject {.importcpp: "(delete #)".} +proc jsDelete*(x: auto): JsObject {.importjs: "(delete #)".} ## JavaScript's `delete` operator. proc require*(module: cstring): JsObject {.importc.} ## JavaScript's `require` function. # Conversion to and from JsObject -proc to*(x: JsObject, T: typedesc): T {.importcpp: "(#)".} +proc to*(x: JsObject, T: typedesc): T {.importjs: "(#)".} ## Converts a JsObject `x` to type `T`. -proc toJs*[T](val: T): JsObject {.importcpp: "(#)".} +proc toJs*[T](val: T): JsObject {.importjs: "(#)".} ## Converts a value of any type to type JsObject. template toJs*(s: string): JsObject = cstring(s).toJs @@ -160,50 +160,50 @@ macro jsFromAst*(n: untyped): untyped = result = newProc(procType = nnkDo, body = result) return quote: toJs(`result`) -proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".} +proc `&`*(a, b: cstring): cstring {.importjs: "(# + #)".} ## Concatenation operator for JavaScript strings. -proc `+` *(x, y: JsObject): JsObject {.importcpp: "(# + #)".} -proc `-` *(x, y: JsObject): JsObject {.importcpp: "(# - #)".} -proc `*` *(x, y: JsObject): JsObject {.importcpp: "(# * #)".} -proc `/` *(x, y: JsObject): JsObject {.importcpp: "(# / #)".} -proc `%` *(x, y: JsObject): JsObject {.importcpp: "(# % #)".} -proc `+=` *(x, y: JsObject): JsObject {.importcpp: "(# += #)", discardable.} -proc `-=` *(x, y: JsObject): JsObject {.importcpp: "(# -= #)", discardable.} -proc `*=` *(x, y: JsObject): JsObject {.importcpp: "(# *= #)", discardable.} -proc `/=` *(x, y: JsObject): JsObject {.importcpp: "(# /= #)", discardable.} -proc `%=` *(x, y: JsObject): JsObject {.importcpp: "(# %= #)", discardable.} -proc `++` *(x: JsObject): JsObject {.importcpp: "(++#)".} -proc `--` *(x: JsObject): JsObject {.importcpp: "(--#)".} -proc `>` *(x, y: JsObject): JsObject {.importcpp: "(# > #)".} -proc `<` *(x, y: JsObject): JsObject {.importcpp: "(# < #)".} -proc `>=` *(x, y: JsObject): JsObject {.importcpp: "(# >= #)".} -proc `<=` *(x, y: JsObject): JsObject {.importcpp: "(# <= #)".} -proc `**` *(x, y: JsObject): JsObject {.importcpp: "((#) ** #)".} +proc `+` *(x, y: JsObject): JsObject {.importjs: "(# + #)".} +proc `-` *(x, y: JsObject): JsObject {.importjs: "(# - #)".} +proc `*` *(x, y: JsObject): JsObject {.importjs: "(# * #)".} +proc `/` *(x, y: JsObject): JsObject {.importjs: "(# / #)".} +proc `%` *(x, y: JsObject): JsObject {.importjs: "(# % #)".} +proc `+=` *(x, y: JsObject): JsObject {.importjs: "(# += #)", discardable.} +proc `-=` *(x, y: JsObject): JsObject {.importjs: "(# -= #)", discardable.} +proc `*=` *(x, y: JsObject): JsObject {.importjs: "(# *= #)", discardable.} +proc `/=` *(x, y: JsObject): JsObject {.importjs: "(# /= #)", discardable.} +proc `%=` *(x, y: JsObject): JsObject {.importjs: "(# %= #)", discardable.} +proc `++` *(x: JsObject): JsObject {.importjs: "(++#)".} +proc `--` *(x: JsObject): JsObject {.importjs: "(--#)".} +proc `>` *(x, y: JsObject): JsObject {.importjs: "(# > #)".} +proc `<` *(x, y: JsObject): JsObject {.importjs: "(# < #)".} +proc `>=` *(x, y: JsObject): JsObject {.importjs: "(# >= #)".} +proc `<=` *(x, y: JsObject): JsObject {.importjs: "(# <= #)".} +proc `**` *(x, y: JsObject): JsObject {.importjs: "((#) ** #)".} # (#) needed, refs https://github.com/nim-lang/Nim/pull/16409#issuecomment-760550812 -proc `and`*(x, y: JsObject): JsObject {.importcpp: "(# && #)".} -proc `or` *(x, y: JsObject): JsObject {.importcpp: "(# || #)".} -proc `not`*(x: JsObject): JsObject {.importcpp: "(!#)".} -proc `in` *(x, y: JsObject): JsObject {.importcpp: "(# in #)".} +proc `and`*(x, y: JsObject): JsObject {.importjs: "(# && #)".} +proc `or` *(x, y: JsObject): JsObject {.importjs: "(# || #)".} +proc `not`*(x: JsObject): JsObject {.importjs: "(!#)".} +proc `in` *(x, y: JsObject): JsObject {.importjs: "(# in #)".} -proc `[]`*(obj: JsObject, field: cstring): JsObject {.importcpp: getImpl.} +proc `[]`*(obj: JsObject, field: cstring): JsObject {.importjs: getImpl.} ## Returns the value of a property of name `field` from a JsObject `obj`. -proc `[]`*(obj: JsObject, field: int): JsObject {.importcpp: getImpl.} +proc `[]`*(obj: JsObject, field: int): JsObject {.importjs: getImpl.} ## Returns the value of a property of name `field` from a JsObject `obj`. -proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {.importcpp: setImpl.} +proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {.importjs: setImpl.} ## Sets the value of a property of name `field` in a JsObject `obj` to `v`. -proc `[]=`*[T](obj: JsObject, field: int, val: T) {.importcpp: setImpl.} +proc `[]=`*[T](obj: JsObject, field: int, val: T) {.importjs: setImpl.} ## Sets the value of a property of name `field` in a JsObject `obj` to `v`. proc `[]`*[K: JsKey, V](obj: JsAssoc[K, V], field: K): V - {.importcpp: getImpl.} + {.importjs: getImpl.} ## Returns the value of a property of name `field` from a JsAssoc `obj`. proc `[]=`*[K: JsKey, V](obj: JsAssoc[K, V], field: K, val: V) - {.importcpp: setImpl.} + {.importjs: setImpl.} ## Sets the value of a property of name `field` in a JsAssoc `obj` to `v`. proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V = @@ -212,7 +212,7 @@ proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V = proc `[]=`*[V](obj: JsAssoc[cstring, V], field: string, val: V) = obj[cstring(field)] = val -proc `==`*(x, y: JsRoot): bool {.importcpp: "(# === #)".} +proc `==`*(x, y: JsRoot): bool {.importjs: "(# === #)".} ## Compares two JsObjects or JsAssocs. Be careful though, as this is comparison ## like in JavaScript, so if your JsObjects are in fact JavaScript Objects, ## and not strings or numbers, this is a *comparison of references*. @@ -229,7 +229,7 @@ macro `.`*(obj: JsObject, field: untyped): JsObject = let importString = "#." & $field result = quote do: proc helper(o: JsObject): JsObject - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`) else: if not mangledNames.hasKey($field): @@ -237,7 +237,7 @@ macro `.`*(obj: JsObject, field: untyped): JsObject = let importString = "#." & mangledNames[$field] result = quote do: proc helper(o: JsObject): JsObject - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`) macro `.=`*(obj: JsObject, field, value: untyped): untyped = @@ -247,7 +247,7 @@ macro `.=`*(obj: JsObject, field, value: untyped): untyped = let importString = "#." & $field & " = #" result = quote do: proc helper(o: JsObject, v: auto) - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`, `value`) else: if not mangledNames.hasKey($field): @@ -255,7 +255,7 @@ macro `.=`*(obj: JsObject, field, value: untyped): untyped = let importString = "#." & mangledNames[$field] & " = #" result = quote do: proc helper(o: JsObject, v: auto) - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`, `value`) macro `.()`*(obj: JsObject, @@ -286,7 +286,7 @@ macro `.()`*(obj: JsObject, importString = "#." & mangledNames[$field] & "(@)" result = quote: proc helper(o: JsObject): JsObject - {.importcpp: `importString`, gensym, discardable.} + {.importjs: `importString`, gensym, discardable.} helper(`obj`) for idx in 0 ..< args.len: let paramName = newIdentNode("param" & $idx) @@ -306,7 +306,7 @@ macro `.`*[K: cstring, V](obj: JsAssoc[K, V], importString = "#." & mangledNames[$field] result = quote do: proc helper(o: type(`obj`)): `obj`.V - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`) macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], @@ -323,7 +323,7 @@ macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], importString = "#." & mangledNames[$field] & " = #" result = quote do: proc helper(o: type(`obj`), v: `obj`.V) - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`, `value`) macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V], diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim index 21bb9e1a0..ccf14080b 100644 --- a/lib/std/jsbigints.nim +++ b/lib/std/jsbigints.nim @@ -3,8 +3,8 @@ when not defined(js): {.fatal: "Module jsbigints is designed to be used with the JavaScript backend.".} -type JsBigIntImpl {.importc: "bigint".} = int # https://github.com/nim-lang/Nim/pull/16606 -type JsBigInt* = distinct JsBigIntImpl ## Arbitrary precision integer for JavaScript target. +type JsBigIntImpl {.importjs: "bigint".} = int # https://github.com/nim-lang/Nim/pull/16606 +type JsBigInt* = distinct JsBigIntImpl ## Arbitrary precision integer for JavaScript target. func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} = ## Constructor for `JsBigInt`. From b70e33f5bbb7b9c146c97d39aabae57504f4ee75 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Sat, 20 Mar 2021 13:22:50 +0100 Subject: [PATCH 2235/4254] strutils: improve doc comments for `replace` funcs (#17427) This commit fixes mispellings of "occurrence" introduced by: - 76a3b350ce0f (#17337) - 8e8bea9044f0 (#17339) and adds the same "every occurrence of" in the `replaceWord` func. Other changes: - Prefer "replace with" to "replace by". - Be more consistent with "the" - prefer "of the character" given that we wrote "by the character". - Try to be more consistent with writing the types - add "the string `sub`" given that we wrote "the character `sub`". --- lib/pure/strutils.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 510f0682d..4098749ce 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2037,7 +2037,7 @@ func contains*(s: string, chars: set[char]): bool = func replace*(s, sub: string, by = ""): string {.rtl, extern: "nsuReplaceStr".} = - ## Replaces every occurence of `sub` in `s` by the string `by`. + ## Replaces every occurrence of the string `sub` in `s` with the string `by`. ## ## See also: ## * `find func<#find,string,string,Natural,int>`_ @@ -2079,7 +2079,8 @@ func replace*(s, sub: string, by = ""): string {.rtl, func replace*(s: string, sub, by: char): string {.rtl, extern: "nsuReplaceChar".} = - ## Replaces every occurence of character `sub` in `s` by the character `by`. + ## Replaces every occurrence of the character `sub` in `s` with the character + ## `by`. ## ## Optimized version of `replace <#replace,string,string,string>`_ for ## characters. @@ -2097,7 +2098,7 @@ func replace*(s: string, sub, by: char): string {.rtl, func replaceWord*(s, sub: string, by = ""): string {.rtl, extern: "nsuReplaceWord".} = - ## Replaces `sub` in `s` by the string `by`. + ## Replaces every occurrence of the string `sub` in `s` with the string `by`. ## ## Each occurrence of `sub` has to be surrounded by word boundaries ## (comparable to `\b` in regular expressions), otherwise it is not From eca0b8754458e6d57a0ebc248ae0d1d024e1723c Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sun, 21 Mar 2021 02:30:57 +0100 Subject: [PATCH 2236/4254] Close #8545 by add a test case (#17432) Co-authored-by: Timothee Cour --- tests/misc/t8545.nim | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/misc/t8545.nim diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim new file mode 100644 index 000000000..89957e1d3 --- /dev/null +++ b/tests/misc/t8545.nim @@ -0,0 +1,23 @@ +discard """ + targets: "c cpp js" +""" + +# bug #8545 + +template bar(a: static[bool]): untyped = int + +proc main() = + proc foo1(a: static[bool]): auto = 1 + doAssert foo1(true) == 1 + + proc foo2(a: static[bool]): bar(a) = 1 + doAssert foo2(true) == 1 + + proc foo3(a: static[bool]): bar(cast[static[bool]](a)) = 1 + doAssert foo3(true) == 1 + + proc foo4(a: static[bool]): bar(static(a)) = 1 + doAssert foo4(true) == 1 + +static: main() +main() From c5b109233a1ffe283d460be40575bdaf5beb0104 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Sun, 21 Mar 2021 12:34:10 +0300 Subject: [PATCH 2237/4254] Add documentation to the `macrocache` module (#17431) * Add docs to macrocache * use hint * Use incl in the incl example * add macrocache to lib * consistency * Update doc/lib.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * apply suggestions * clarify the warning Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- doc/lib.rst | 3 + lib/core/macrocache.nim | 191 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 179 insertions(+), 15 deletions(-) diff --git a/doc/lib.rst b/doc/lib.rst index 3202c5a53..9d715b1c7 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -64,6 +64,9 @@ Core * `locks `_ Locks and condition variables for Nim. +* `macrocache `_ + Provides an API for macros to collect compile-time information across modules. + * `macros `_ Contains the AST API and documentation of Nim for writing macros. diff --git a/lib/core/macrocache.nim b/lib/core/macrocache.nim index 8fe1fa603..e376ad87f 100644 --- a/lib/core/macrocache.nim +++ b/lib/core/macrocache.nim @@ -7,38 +7,199 @@ # distribution, for details about the copyright. # -## This module provides an API for macros that need to collect compile -## time information across module boundaries in global variables. -## Starting with version 0.19 of Nim this is not directly supported anymore -## as it breaks incremental compilations. -## Instead the API here needs to be used. +## This module provides an API for macros to collect compile-time information +## across module boundaries. It should be used instead of global `{.compileTime.}` +## variables as those break incremental compilation. +## +## The main feature of this module is that if you create `CacheTable`s or +## any other `Cache` types with the same name in different modules, their +## content will be shared, meaning that you can fill a `CacheTable` in +## one module, and iterate over its contents in another. + +runnableExamples: + import std/macros + + const mcTable = CacheTable"myTable" + const mcSeq = CacheSeq"mySeq" + const mcCounter = CacheCounter"myCounter" + + static: + # add new key "val" with the value `myval` + let myval = newLit("hello ic") + mcTable["val"] = myval + assert mcTable["val"].kind == nnkStrLit + + # Can access the same cache from different static contexts + # All the information is retained + static: + # get value from `mcTable` and add it to `mcSeq` + mcSeq.add(mcTable["val"]) + assert mcSeq.len == 1 + + static: + assert mcSeq[0].strVal == "hello ic" + + # increase `mcCounter` by 3 + mcCounter.inc(3) + assert mcCounter.value == 3 + type CacheSeq* = distinct string + ## Compile-time sequence of `NimNode`s. CacheTable* = distinct string + ## Compile-time table of key-value pairs. + ## + ## Keys are `string`s and values are `NimNode`s. CacheCounter* = distinct string + ## Compile-time counter, uses `int` for storing the count. -proc value*(c: CacheCounter): int {.magic: "NccValue".} -proc inc*(c: CacheCounter; by = 1) {.magic: "NccInc".} +proc value*(c: CacheCounter): int {.magic: "NccValue".} = + ## Returns the value of a counter `c`. + runnableExamples: + static: + let counter = CacheCounter"valTest" + # default value is 0 + assert counter.value == 0 -proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} -proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} -proc len*(s: CacheSeq): int {.magic: "NcsLen".} -proc `[]`*(s: CacheSeq; i: int): NimNode {.magic: "NcsAt".} + inc counter + assert counter.value == 1 + +proc inc*(c: CacheCounter; by = 1) {.magic: "NccInc".} = + ## Increments the counter `c` with the value `by`. + runnableExamples: + static: + let counter = CacheCounter"incTest" + inc counter + inc counter, 5 + + assert counter.value == 6 + +proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} = + ## Adds `value` to `s`. + runnableExamples: + import std/macros + const mySeq = CacheSeq"addTest" + + static: + mySeq.add(newLit(5)) + mySeq.add(newLit("hello ic")) + + assert mySeq.len == 2 + assert mySeq[1].strVal == "hello ic" + +proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} = + ## Adds `value` to `s`. + ## + ## .. hint:: This doesn't do anything if `value` is already in `s`. + runnableExamples: + import std/macros + const mySeq = CacheSeq"inclTest" + + static: + mySeq.incl(newLit(5)) + mySeq.incl(newLit(5)) + + # still one element + assert mySeq.len == 1 + +proc len*(s: CacheSeq): int {.magic: "NcsLen".} = + ## Returns the length of `s`. + runnableExamples: + import std/macros + + const mySeq = CacheSeq"lenTest" + static: + let val = newLit("helper") + mySeq.add(val) + assert mySeq.len == 1 + + mySeq.add(val) + assert mySeq.len == 2 + +proc `[]`*(s: CacheSeq; i: int): NimNode {.magic: "NcsAt".} = + ## Returns the `i`th value from `s`. + runnableExamples: + import std/macros + + const mySeq = CacheSeq"subTest" + static: + mySeq.add(newLit(42)) + assert mySeq[0].intVal == 42 iterator items*(s: CacheSeq): NimNode = + ## Iterates over each item in `s`. + runnableExamples: + import std/macros + const myseq = CacheSeq"itemsTest" + + static: + myseq.add(newLit(5)) + myseq.add(newLit(42)) + + for val in myseq: + # check that all values in `myseq` are int literals + assert val.kind == nnkIntLit + for i in 0 ..< len(s): yield s[i] -proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} - ## 'key' has to be unique! +proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} = + ## Inserts a `(key, value)` pair into `t`. + ## + ## .. warning:: `key` has to be unique! Assigning `value` to a `key` that is already + ## in the table will result in a compiler error. + runnableExamples: + import std/macros -proc len*(t: CacheTable): int {.magic: "NctLen".} -proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} + const mcTable = CacheTable"subTest" + static: + # assign newLit(5) to the key "value" + mcTable["value"] = newLit(5) + + # check that we can get the value back + assert mcTable["value"].kind == nnkIntLit + +proc len*(t: CacheTable): int {.magic: "NctLen".} = + ## Returns the number of elements in `t`. + runnableExamples: + import std/macros + + const dataTable = CacheTable"lenTest" + static: + dataTable["key"] = newLit(5) + assert dataTable.len == 1 + +proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} = + ## Retrieves the `NimNode` value at `t[key]`. + runnableExamples: + import std/macros + + const mcTable = CacheTable"subTest" + static: + mcTable["toAdd"] = newStmtList() + + # get the NimNode back + assert mcTable["toAdd"].kind == nnkStmtList proc hasNext(t: CacheTable; iter: int): bool {.magic: "NctHasNext".} proc next(t: CacheTable; iter: int): (string, NimNode, int) {.magic: "NctNext".} iterator pairs*(t: CacheTable): (string, NimNode) = + ## Iterates over all `(key, value)` pairs in `t`. + runnableExamples: + import std/macros + const mytabl = CacheTable"values" + + static: + mytabl["intVal"] = newLit(5) + mytabl["otherVal"] = newLit(6) + for key, val in mytabl: + # make sure that we actually get the same keys + assert key in ["intVal", "otherVal"] + + # all vals are int literals + assert val.kind == nnkIntLit + var h = 0 while hasNext(t, h): let (a, b, h2) = next(t, h) From 05743bc9f72f2e3cbf4b17f5974a811637f03241 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 21 Mar 2021 02:35:00 -0700 Subject: [PATCH 2238/4254] improve jsutils docs (#17421) * improve jsutils docs * address comments --- lib/std/private/jsutils.nim | 52 ++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim index 32c717c56..836b3512a 100644 --- a/lib/std/private/jsutils.nim +++ b/lib/std/private/jsutils.nim @@ -1,4 +1,4 @@ -when defined(js) or defined(nimdoc): +when defined(js): import std/jsbigints type @@ -14,7 +14,6 @@ when defined(js) or defined(nimdoc): func newUint32Array*(buffer: ArrayBuffer): Uint32Array {.importjs: "new Uint32Array(#)".} func newBigUint64Array*(buffer: ArrayBuffer): BigUint64Array {.importjs: "new BigUint64Array(#)".} - func newUint8Array*(n: int): Uint8Array {.importjs: "new Uint8Array(#)".} func `[]`*(arr: Uint32Array, i: int): uint32 {.importjs: "#[#]".} @@ -22,12 +21,22 @@ when defined(js) or defined(nimdoc): func `[]`*(arr: BigUint64Array, i: int): JsBigInt {.importjs: "#[#]".} func `[]=`*(arr: Float64Array, i: int, v: float) {.importjs: "#[#] = #".} - - proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".} - ## Returns the name of the JsObject's JavaScript type as a cstring. - # xxx replace jsffi.jsTypeOf with this definition and add tests + proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".} = + ## Returns the name of the JsObject's JavaScript type as a cstring. + # xxx replace jsffi.jsTypeOf with this definition and add tests + runnableExamples: + import std/[jsffi, jsbigints] + assert jsTypeOf(1.toJs) == "number" + assert jsTypeOf(false.toJs) == "boolean" + assert [1].toJs.jsTypeOf == "object" # note the difference with `getProtoName` + assert big"1".toJs.jsTypeOf == "bigint" proc jsConstructorName*[T](a: T): cstring = + runnableExamples: + import std/jsffi + let a = array[2, float64].default + assert jsConstructorName(a) == "Float64Array" + assert jsConstructorName(a.toJs) == "Float64Array" asm """`result` = `a`.constructor.name""" proc hasJsBigInt*(): bool = @@ -36,16 +45,39 @@ when defined(js) or defined(nimdoc): proc hasBigUint64Array*(): bool = asm """`result` = typeof BigUint64Array != 'undefined'""" - proc getProtoName*[T](a: T): cstring {.importjs: "Object.prototype.toString.call(#)".} + proc getProtoName*[T](a: T): cstring {.importjs: "Object.prototype.toString.call(#)".} = + runnableExamples: + import std/[jsffi, jsbigints] + type A = ref object + assert 1.toJs.getProtoName == "[object Number]" + assert "a".toJs.getProtoName == "[object String]" + assert big"1".toJs.getProtoName == "[object BigInt]" + assert false.toJs.getProtoName == "[object Boolean]" + assert (a: 1).toJs.getProtoName == "[object Object]" + assert A.default.toJs.getProtoName == "[object Null]" + assert [1].toJs.getProtoName == "[object Int32Array]" # implementation defined + assert @[1].toJs.getProtoName == "[object Array]" # ditto - proc isInteger*[T](x: T): bool {.importjs: "Number.isInteger(#)".} + const maxSafeInteger* = 9007199254740991 + ## The same as `Number.MAX_SAFE_INTEGER` or `2^53 - 1`. + ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER + runnableExamples: + let a {.importjs: "Number.MAX_SAFE_INTEGER".}: int64 + assert a == maxSafeInteger + + proc isInteger*[T](x: T): bool {.importjs: "Number.isInteger(#)".} = + runnableExamples: + import std/jsffi + assert 1.isInteger + assert not 1.5.isInteger + assert 1.toJs.isInteger + assert not 1.5.toJs.isInteger proc isSafeInteger*[T](x: T): bool {.importjs: "Number.isSafeInteger(#)".} = runnableExamples: import std/jsffi assert not "123".toJs.isSafeInteger + assert 123.isSafeInteger assert 123.toJs.isSafeInteger assert 9007199254740991.toJs.isSafeInteger assert not 9007199254740992.toJs.isSafeInteger - - let maxSafeInteger* {.importjs: "Number.MAX_SAFE_INTEGER".} : int64 From fb38d906a284a088f052e6fc842fb7f2df26a486 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 21 Mar 2021 06:35:55 -0300 Subject: [PATCH 2239/4254] Improve jsre (#17365) * Add dollar for regex * Add dollar for regex * Peer review feedbacks * Peer review feedbacks * Update lib/js/jsre.nim Co-authored-by: Timothee Cour * Update lib/js/jsre.nim Co-authored-by: Timothee Cour * Update lib/js/jsre.nim Co-authored-by: Timothee Cour * Pear review * Beer review * Beer review Co-authored-by: Timothee Cour --- changelog.md | 2 ++ lib/js/jsre.nim | 77 ++++++++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/changelog.md b/changelog.md index 219a66ae7..cc4f54fe0 100644 --- a/changelog.md +++ b/changelog.md @@ -239,6 +239,8 @@ - Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. +- Added dollar `$` and `len` for `jsre.RegExp`. + ## Language changes diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index 7be7221bc..7d51db646 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -1,46 +1,63 @@ ## Regular Expressions for the JavaScript target. ## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions - -runnableExamples: - let jsregex: RegExp = newRegExp(r"\s+", r"i") - jsregex.compile(r"\w+", r"i") - doAssert jsregex.test(r"nim javascript") - doAssert jsregex.exec(r"nim javascript") == @["nim".cstring] - doAssert jsregex.toString() == r"/\w+/i" - jsregex.compile(r"[0-9]", r"i") - doAssert jsregex.test(r"0123456789abcd") - - when not defined(js): {.error: "This module only works on the JavaScript platform".} -type RegExp* {.importjs.} = object ## Regular Expressions for JavaScript target. - flags* {.importjs.}: cstring ## cstring that contains the flags of the RegExp object. - dotAll* {.importjs.}: bool ## Whether `.` matches newlines or not. - global* {.importjs.}: bool ## Whether to test against all possible matches in a string, or only against the first. - ignoreCase* {.importjs.}: bool ## Whether to ignore case while attempting a match in a string. - multiline* {.importjs.}: bool ## Whether to search in strings across multiple lines. - source* {.importjs.}: cstring ## The text of the pattern. - sticky* {.importjs.}: bool ## Whether the search is sticky. - unicode* {.importjs.}: bool ## Whether Unicode features are enabled. - lastIndex* {.importjs.}: cint ## Index at which to start the next match (read/write property). - input* {.importjs.}: cstring ## Read-only and modified on successful match. - lastMatch* {.importjs.}: cstring ## Ditto. - lastParen* {.importjs.}: cstring ## Ditto. - leftContext* {.importjs.}: cstring ## Ditto. - rightContext* {.importjs.}: cstring ## Ditto. +type RegExp* = ref object of JsRoot + ## Regular Expressions for JavaScript target. + ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp + flags*: cstring ## cstring that contains the flags of the RegExp object. + dotAll*: bool ## Whether `.` matches newlines or not. + global*: bool ## Whether to test against all possible matches in a string, or only against the first. + ignoreCase*: bool ## Whether to ignore case while attempting a match in a string. + multiline*: bool ## Whether to search in strings across multiple lines. + source*: cstring ## The text of the pattern. + sticky*: bool ## Whether the search is sticky. + unicode*: bool ## Whether Unicode features are enabled. + lastIndex*: cint ## Index at which to start the next match (read/write property). + input*: cstring ## Read-only and modified on successful match. + lastMatch*: cstring ## Ditto. + lastParen*: cstring ## Ditto. + leftContext*: cstring ## Ditto. + rightContext*: cstring ## Ditto. + func newRegExp*(pattern: cstring; flags: cstring): RegExp {.importjs: "new RegExp(@)".} ## Creates a new RegExp object. +func newRegExp*(pattern: cstring): RegExp {.importjs: "new RegExp(@)".} + func compile*(self: RegExp; pattern: cstring; flags: cstring) {.importjs: "#.compile(@)".} ## Recompiles a regular expression during execution of a script. func exec*(self: RegExp; pattern: cstring): seq[cstring] {.importjs: "#.exec(#)".} ## Executes a search for a match in its string parameter. -func test*(self: RegExp; pattern: cstring): bool {.importjs: "#.test(#)".} - ## Tests for a match in its string parameter. - -func toString*(self: RegExp): cstring {.importjs: "#.toString()".} +func toCstring*(self: RegExp): cstring {.importjs: "#.toString()".} ## Returns a string representing the RegExp object. + +func `$`*(self: RegExp): string = $toCstring(self) + +func test*(self: RegExp; pattern: cstring): bool {.importjs: "#.test(#)", deprecated: "Use contains instead".} + +func toString*(self: RegExp): cstring {.importjs: "#.toString()", deprecated: "Use toCstring instead".} + +func contains*(pattern: cstring; self: RegExp): bool = + ## Tests for a substring match in its string parameter. + runnableExamples: + let jsregex: RegExp = newRegExp(r"bc$", r"i") + assert jsregex in r"abc" + assert jsregex notin r"abcd" + assert "xabc".contains jsregex + asm "`result` = `self`.test(`pattern`);" + + +runnableExamples: + let jsregex: RegExp = newRegExp(r"\s+", r"i") + jsregex.compile(r"\w+", r"i") + assert "nim javascript".contains jsregex + assert jsregex.exec(r"nim javascript") == @["nim".cstring] + assert jsregex.toCstring() == r"/\w+/i" + jsregex.compile(r"[0-9]", r"i") + assert "0123456789abcd".contains jsregex + assert $jsregex == "/[0-9]/i" From fd09ace55796ae6605f34dafecab24cc0d6ac9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derek=20=E5=91=86?= <116649+derekdai@users.noreply.github.com> Date: Sun, 21 Mar 2021 21:29:39 +0800 Subject: [PATCH 2240/4254] prevent bitmasks double included in mmdist if -d:nimArcDebug added (#17436) --- lib/system/cellsets.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index ea00176b5..779f1a91f 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -13,7 +13,8 @@ when defined(gcOrc) or defined(gcArc): type PCell = Cell - include bitmasks + when not declaredInScope(PageShift): + include bitmasks else: type From 5bed7d282ad043d945225fe72adb654d49b4f2ee Mon Sep 17 00:00:00 2001 From: AFaurholt Date: Sun, 21 Mar 2021 18:35:22 +0100 Subject: [PATCH 2241/4254] added more modules to docs lib (#17430) * added more modules * Update doc/lib.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/lib.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/lib.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/lib.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/lib.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * listed alphabetically + link to json module * Added suggestion #17430 Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- doc/lib.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/lib.rst b/doc/lib.rst index 9d715b1c7..62e02815c 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -357,6 +357,9 @@ Parsers * `json `_ High-performance JSON parser. +* `std/jsonutils `_ + This module implements a hookable (de)serialization for arbitrary types. + * `lexbase `_ This is a low-level module that implements an extremely efficient buffering scheme for lexers and parsers. This is used by the diverse parsing modules. @@ -371,6 +374,9 @@ Parsers * `parsecsv `_ The `parsecsv` module implements a simple high-performance CSV parser. +* `parsejson `_ + This module implements a JSON parser. It is used and exported by the `json `_ module, but can also be used in its own right. + * `parseopt `_ The `parseopt` module implements a command line option parser. @@ -459,6 +465,9 @@ Miscellaneous * `coro `_ This module implements experimental coroutines in Nim. +* `std/enumerate `_ + This module implements `enumerate` syntactic sugar based on Nim's macro system. + * `logging `_ This module implements a simple logger. @@ -474,6 +483,10 @@ Miscellaneous * `std/varints `_ Decode variable-length integers that are compatible with SQLite. +* `std/with `_ + This module implements the `with` macro for easy function chaining. + + Modules for JS backend ---------------------- @@ -506,6 +519,7 @@ Regular expressions expressions. The current implementation uses PCRE. + Database support ---------------- @@ -522,6 +536,13 @@ Database support for other databases too. +Generic Operating System Services +--------------------------------- + +* `rdstdin `_ + This module contains code for reading from stdin. + + Wrappers ======== @@ -572,3 +593,11 @@ Network Programming and Internet Protocols * `openssl `_ Wrapper for OpenSSL. + + + +Unstable +======== + +* `atomics `_ + Types and operations for atomic operations and lockless algorithms. From 23fd0984283fe94108dea5d569450f5e0564c59d Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Sun, 21 Mar 2021 16:33:37 -0700 Subject: [PATCH 2242/4254] Fixes #17433; gensym callDef return in templ body (#17445) --- compiler/semtempl.nim | 2 +- tests/template/t17433.nim | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/template/t17433.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 568873269..4bb9f3e6b 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -435,8 +435,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = of nkLetSection: semTemplSomeDecl(c, n, skLet) of nkFormalParams: checkMinSonsLen(n, 1, c.c.config) - n[0] = semTemplBody(c, n[0]) semTemplSomeDecl(c, n, skParam, 1) + n[0] = semTemplBody(c, n[0]) of nkConstSection: for i in 0.. Date: Mon, 22 Mar 2021 07:36:48 +0800 Subject: [PATCH 2243/4254] close #11330 sets uses optimized countSetBits (#17334) * Update lib/pure/bitops.nim * Update lib/system/sets.nim * Apply suggestions from code review Co-authored-by: Andreas Rumpf --- lib/pure/bitops.nim | 88 ++++------------------------------- lib/std/private/vmutils.nim | 17 +++++++ lib/system/countbits_impl.nim | 77 ++++++++++++++++++++++++++++-- lib/system/sets.nim | 1 - 4 files changed, 98 insertions(+), 85 deletions(-) create mode 100644 lib/std/private/vmutils.nim diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 57e3c7989..377602e75 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -27,6 +27,9 @@ import macros import std/private/since +from std/private/vmutils import forwardImpl, toUnsigned + + func bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI".} ## Computes the `bitwise complement` of the integer `x`. @@ -58,34 +61,6 @@ macro bitxor*[T: SomeInteger](x, y: T; z: varargs[T]): T = for extra in z: result = newCall(fn, result, extra) -const useBuiltins = not defined(noIntrinsicsBitOpts) -const noUndefined = defined(noUndefinedBitOpts) -const useGCC_builtins = (defined(gcc) or defined(llvm_gcc) or - defined(clang)) and useBuiltins -const useICC_builtins = defined(icc) and useBuiltins -const useVCC_builtins = defined(vcc) and useBuiltins -const arch64 = sizeof(int) == 8 -const useBuiltinsRotate = (defined(amd64) or defined(i386)) and - (defined(gcc) or defined(clang) or defined(vcc) or - (defined(icl) and not defined(cpp))) and useBuiltins - -template toUnsigned(x: int8): uint8 = cast[uint8](x) -template toUnsigned(x: int16): uint16 = cast[uint16](x) -template toUnsigned(x: int32): uint32 = cast[uint32](x) -template toUnsigned(x: int64): uint64 = cast[uint64](x) -template toUnsigned(x: int): uint = cast[uint](x) - -template forwardImpl(impl, arg) {.dirty.} = - when sizeof(x) <= 4: - when x is SomeSignedInt: - impl(cast[uint32](x.int32)) - else: - impl(x.uint32) - else: - when x is SomeSignedInt: - impl(cast[uint64](x.int64)) - else: - impl(x.uint64) type BitsRange*[T] = range[0..sizeof(T)*8-1] ## A range with all bit positions for type `T`. @@ -436,13 +411,12 @@ func fastlog2Nim(x: uint64): int {.inline.} = v = v or v shr 32 result = lookup[(v * 0x03F6EAF2CD271461'u64) shr 58].int -# sets.nim cannot import bitops, but bitops can use include -# system/sets to eliminate code duplication. sets.nim defines -# countBits32 and countBits64. import system/countbits_impl -template countSetBitsNim(n: uint32): int = countBits32(n) -template countSetBitsNim(n: uint64): int = countBits64(n) +const arch64 = sizeof(int) == 8 +const useBuiltinsRotate = (defined(amd64) or defined(i386)) and + (defined(gcc) or defined(clang) or defined(vcc) or + (defined(icl) and not defined(cpp))) and useBuiltins template parityImpl[T](value: T): int = # formula id from: https://graphics.stanford.edu/%7Eseander/bithacks.html#ParityParallel @@ -459,11 +433,6 @@ template parityImpl[T](value: T): int = when useGCC_builtins: - # Returns the number of set 1-bits in value. - proc builtin_popcount(x: cuint): cint {.importc: "__builtin_popcount", cdecl.} - proc builtin_popcountll(x: culonglong): cint {. - importc: "__builtin_popcountll", cdecl.} - # Returns the bit parity in value proc builtin_parity(x: cuint): cint {.importc: "__builtin_parity", cdecl.} proc builtin_parityll(x: culonglong): cint {.importc: "__builtin_parityll", cdecl.} @@ -481,14 +450,6 @@ when useGCC_builtins: proc builtin_ctzll(x: culonglong): cint {.importc: "__builtin_ctzll", cdecl.} elif useVCC_builtins: - # Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer. - func builtin_popcnt16(a2: uint16): uint16 {. - importc: "__popcnt16", header: "".} - func builtin_popcnt32(a2: uint32): uint32 {. - importc: "__popcnt", header: "".} - func builtin_popcnt64(a2: uint64): uint64 {. - importc: "__popcnt64", header: "".} - # Search the mask data from most significant bit (MSB) to least significant bit (LSB) for a set bit (1). func bitScanReverse(index: ptr culong, mask: culong): cuchar {. importc: "_BitScanReverse", header: "".} @@ -507,15 +468,6 @@ elif useVCC_builtins: index.int elif useICC_builtins: - - # Intel compiler intrinsics: http://fulla.fnal.gov/intel/compiler_c/main_cls/intref_cls/common/intref_allia_misc.htm - # see also: https://software.intel.com/en-us/node/523362 - # Count the number of bits set to 1 in an integer a, and return that count in dst. - func builtin_popcnt32(a: cint): cint {. - importc: "_popcnt", header: "".} - func builtin_popcnt64(a: uint64): cint {. - importc: "_popcnt64", header: "".} - # Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined. func bitScanForward(p: ptr uint32, b: uint32): cuchar {. importc: "_BitScanForward", header: "".} @@ -533,37 +485,13 @@ elif useICC_builtins: discard fnc(index.addr, v) index.int - func countSetBits*(x: SomeInteger): int {.inline.} = ## Counts the set bits in an integer (also called `Hamming weight`:idx:). runnableExamples: doAssert countSetBits(0b0000_0011'u8) == 2 doAssert countSetBits(0b1010_1010'u8) == 4 - # TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT. - # like GCC and MSVC - when x is SomeSignedInt: - let x = x.toUnsigned - when nimvm: - result = forwardImpl(countSetBitsNim, x) - else: - when useGCC_builtins: - when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int - else: result = builtin_popcountll(x.culonglong).int - elif useVCC_builtins: - when sizeof(x) <= 2: result = builtin_popcnt16(x.uint16).int - elif sizeof(x) <= 4: result = builtin_popcnt32(x.uint32).int - elif arch64: result = builtin_popcnt64(x.uint64).int - else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32).int + - builtin_popcnt32((x.uint64 shr 32'u64).uint32).int - elif useICC_builtins: - when sizeof(x) <= 4: result = builtin_popcnt32(x.cint).int - elif arch64: result = builtin_popcnt64(x.uint64).int - else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint).int + - builtin_popcnt32((x.uint64 shr 32'u64).cint).int - else: - when sizeof(x) <= 4: result = countSetBitsNim(x.uint32) - else: result = countSetBitsNim(x.uint64) + result = countSetBitsImpl(x) func popcount*(x: SomeInteger): int {.inline.} = ## Alias for `countSetBits <#countSetBits,SomeInteger>`_ (Hamming weight). diff --git a/lib/std/private/vmutils.nim b/lib/std/private/vmutils.nim new file mode 100644 index 000000000..d54977b4e --- /dev/null +++ b/lib/std/private/vmutils.nim @@ -0,0 +1,17 @@ +template forwardImpl*(impl, arg) {.dirty.} = + when sizeof(x) <= 4: + when x is SomeSignedInt: + impl(cast[uint32](x.int32)) + else: + impl(x.uint32) + else: + when x is SomeSignedInt: + impl(cast[uint64](x.int64)) + else: + impl(x.uint64) + +template toUnsigned*(x: int8): uint8 = cast[uint8](x) +template toUnsigned*(x: int16): uint16 = cast[uint16](x) +template toUnsigned*(x: int32): uint32 = cast[uint32](x) +template toUnsigned*(x: int64): uint64 = cast[uint64](x) +template toUnsigned*(x: int): uint = cast[uint](x) diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim index 6c85612e2..d3c003ff7 100644 --- a/lib/system/countbits_impl.nim +++ b/lib/system/countbits_impl.nim @@ -9,17 +9,86 @@ ## Contains the used algorithms for counting bits. -proc countBits32*(n: uint32): int {.compilerproc.} = +from std/private/vmutils import forwardImpl, toUnsigned + + +const useBuiltins* = not defined(noIntrinsicsBitOpts) +const noUndefined* = defined(noUndefinedBitOpts) +const useGCC_builtins* = (defined(gcc) or defined(llvm_gcc) or + defined(clang)) and useBuiltins +const useICC_builtins* = defined(icc) and useBuiltins +const useVCC_builtins* = defined(vcc) and useBuiltins + +template countBitsImpl(n: uint32): int = # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel var v = uint32(n) v = v - ((v shr 1'u32) and 0x55555555'u32) v = (v and 0x33333333'u32) + ((v shr 2'u32) and 0x33333333'u32) - result = (((v + (v shr 4'u32) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24'u32).int + (((v + (v shr 4'u32) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24'u32).int -proc countBits64*(n: uint64): int {.compilerproc, inline.} = +template countBitsImpl(n: uint64): int = # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel var v = uint64(n) v = v - ((v shr 1'u64) and 0x5555555555555555'u64) v = (v and 0x3333333333333333'u64) + ((v shr 2'u64) and 0x3333333333333333'u64) v = (v + (v shr 4'u64) and 0x0F0F0F0F0F0F0F0F'u64) - result = ((v * 0x0101010101010101'u64) shr 56'u64).int + ((v * 0x0101010101010101'u64) shr 56'u64).int + + +when useGCC_builtins: + # Returns the number of set 1-bits in value. + proc builtin_popcount(x: cuint): cint {.importc: "__builtin_popcount", cdecl.} + proc builtin_popcountll(x: culonglong): cint {. + importc: "__builtin_popcountll", cdecl.} + +elif useVCC_builtins: + # Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer. + func builtin_popcnt16(a2: uint16): uint16 {. + importc: "__popcnt16", header: "".} + func builtin_popcnt32(a2: uint32): uint32 {. + importc: "__popcnt", header: "".} + func builtin_popcnt64(a2: uint64): uint64 {. + importc: "__popcnt64", header: "".} + +elif useICC_builtins: + # Intel compiler intrinsics: http://fulla.fnal.gov/intel/compiler_c/main_cls/intref_cls/common/intref_allia_misc.htm + # see also: https://software.intel.com/en-us/node/523362 + # Count the number of bits set to 1 in an integer a, and return that count in dst. + func builtin_popcnt32(a: cint): cint {. + importc: "_popcnt", header: "".} + func builtin_popcnt64(a: uint64): cint {. + importc: "_popcnt64", header: "".} + + +func countSetBitsImpl*(x: SomeInteger): int {.inline.} = + ## Counts the set bits in an integer (also called `Hamming weight`:idx:). + # TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT. + # like GCC and MSVC + when x is SomeSignedInt: + let x = x.toUnsigned + when nimvm: + result = forwardImpl(countBitsImpl, x) + else: + when useGCC_builtins: + when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int + else: result = builtin_popcountll(x.culonglong).int + elif useVCC_builtins: + when sizeof(x) <= 2: result = builtin_popcnt16(x.uint16).int + elif sizeof(x) <= 4: result = builtin_popcnt32(x.uint32).int + elif arch64: result = builtin_popcnt64(x.uint64).int + else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32).int + + builtin_popcnt32((x.uint64 shr 32'u64).uint32).int + elif useICC_builtins: + when sizeof(x) <= 4: result = builtin_popcnt32(x.cint).int + elif arch64: result = builtin_popcnt64(x.uint64).int + else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint).int + + builtin_popcnt32((x.uint64 shr 32'u64).cint).int + else: + when sizeof(x) <= 4: result = countBitsImpl(x.uint32) + else: result = countBitsImpl(x.uint64) + +proc countBits32*(n: uint32): int {.compilerproc, inline.} = + result = countSetBitsImpl(n) + +proc countBits64*(n: uint64): int {.compilerproc, inline.} = + result = countSetBitsImpl(n) diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 04e10ba04..103c8d343 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -12,7 +12,6 @@ type NimSet = array[0..4*2048-1, uint8] -# bitops can't be imported here, therefore the code duplication. proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = var i = 0 From e5873b3a9300897443f0f2e2db128e3463089003 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 22 Mar 2021 04:46:34 -0700 Subject: [PATCH 2244/4254] semTemplateDef and t17433 clean-ups (#17448) - use `doAssert` in t17433 - use setGenericParamsMisc in semTemplateDef akin to semProcAux - pragma handling in semTemplateDef inline with semProcAux --- compiler/sem.nim | 24 ++++++++++++++++++++++-- compiler/semstmts.nim | 18 ------------------ compiler/semtempl.nim | 36 ++++++++++++++++++------------------ tests/template/t17433.nim | 6 +++--- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 5593f8b02..bb42b5c1b 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -485,11 +485,31 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode = if result.kind != nkIntLit: localError(c.config, n.info, errConstExprExpected) - proc semGenericStmt(c: PContext, n: PNode): PNode proc semConceptBody(c: PContext, n: PNode): PNode -include semtypes, semtempl, semgnrc, semstmts, semexprs +include semtypes + +proc setGenericParamsMisc(c: PContext; n: PNode) = + ## used by call defs (procs, templates, macros, ...) to analyse their generic + ## params, and store the originals in miscPos for better error reporting. + let orig = n[genericParamsPos] + + doAssert orig.kind in {nkEmpty, nkGenericParams} + + if n[genericParamsPos].kind == nkEmpty: + n[genericParamsPos] = newNodeI(nkGenericParams, n.info) + else: + # we keep the original params around for better error messages, see + # issue https://github.com/nim-lang/Nim/issues/1713 + n[genericParamsPos] = semGenericParamList(c, orig) + + if n[miscPos].kind == nkEmpty: + n[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig) + else: + n[miscPos][1] = orig + +include semtempl, semgnrc, semstmts, semexprs proc addCodeForGenerics(c: PContext, n: PNode) = for i in c.lastGenericIdx..=", ">", "incl", "excl", "in", "notin", "isnot"] @@ -608,26 +610,23 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = s.owner.name.s == "vm" and s.name.s == "stackTrace": incl(s.flags, sfCallsite) + s.ast = n + styleCheckDef(c.config, s) - onDef(n[0].info, s) + onDef(n[namePos].info, s) # check parameter list: #s.scope = c.currentScope pushOwner(c, s) openScope(c) - n[namePos] = newSymNode(s, n[namePos].info) - if n[pragmasPos].kind != nkEmpty: - pragma(c, s, n[pragmasPos], templatePragmas) + n[namePos] = newSymNode(s) + pragmaCallable(c, s, n, templatePragmas) + implicitPragmas(c, s, n.info, templatePragmas) - var gp: PNode - if n[genericParamsPos].kind != nkEmpty: - n[genericParamsPos] = semGenericParamList(c, n[genericParamsPos]) - gp = n[genericParamsPos] - else: - gp = newNodeI(nkGenericParams, n.info) + setGenericParamsMisc(c, n) # process parameters: var allUntyped = true if n[paramsPos].kind != nkEmpty: - semParamList(c, n[paramsPos], gp, s) + semParamList(c, n[paramsPos], n[genericParamsPos], s) # a template's parameters are not gensym'ed even if that was originally the # case as we determine whether it's a template parameter in the template # body by the absence of the sfGenSym flag: @@ -636,18 +635,21 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = param.flags.incl sfTemplateParam param.flags.excl sfGenSym if param.typ.kind != tyUntyped: allUntyped = false - if gp.len > 0 and n[genericParamsPos].kind == nkEmpty: - # we have a list of implicit type parameters: - n[genericParamsPos] = gp else: s.typ = newTypeS(tyProc, c) # XXX why do we need tyTyped as a return type again? s.typ.n = newNodeI(nkFormalParams, n.info) rawAddSon(s.typ, newTypeS(tyTyped, c)) s.typ.n.add newNodeIT(nkType, n.info, s.typ[0]) + if n[genericParamsPos].safeLen == 0: + # restore original generic type params as no explicit or implicit were found + n[genericParamsPos] = n[miscPos][1] + n[miscPos] = c.graph.emptyNode if allUntyped: incl(s.flags, sfAllUntyped) + if n[patternPos].kind != nkEmpty: n[patternPos] = semPattern(c, n[patternPos]) + var ctx: TemplCtx ctx.toBind = initIntSet() ctx.toMixin = initIntSet() @@ -662,8 +664,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = semIdeForTemplateOrGeneric(c, n[bodyPos], ctx.cursorInBody) closeScope(c) popOwner(c) - s.ast = n - result = n if sfCustomPragma in s.flags: if n[bodyPos].kind != nkEmpty: localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s) diff --git a/tests/template/t17433.nim b/tests/template/t17433.nim index 121f3c471..053d33ff0 100644 --- a/tests/template/t17433.nim +++ b/tests/template/t17433.nim @@ -7,10 +7,10 @@ from std/macros import expandMacros proc bar(a: typedesc): a = default(a) -assert bar(float) == 0.0 -assert bar(string) == "" +doAssert bar(float) == 0.0 +doAssert bar(string) == "" template main = proc baz(a: typedesc): a = default(a) - assert baz(float) == 0.0 + doAssert baz(float) == 0.0 main() From a75c4b70e86705c98a4006aa8475a10a0ebf94ec Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 22 Mar 2021 18:24:28 -0700 Subject: [PATCH 2245/4254] hint:cc goes to stderr (like all other hints) instead of stdout (#17465) Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- changelog.md | 1 + compiler/extccomp.nim | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index cc4f54fe0..00fc970bf 100644 --- a/changelog.md +++ b/changelog.md @@ -301,6 +301,7 @@ - Added `unsafeIsolate` and `extract` to `std/isolation`. +- `--hint:CC` now goes to stderr (like all other hints) instead of stdout. ## Tool changes diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e95ed893b..e0fd5e206 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -281,6 +281,11 @@ const hExt* = ".h" +template writePrettyCmdsStderr(cmd) = + if cmd.len > 0: + flushDot(conf) + stderr.writeLine(cmd) + proc nameToCC*(name: string): TSystemCC = ## Returns the kind of compiler referred to by `name`, or ccNone ## if the name doesn't refer to any known compiler. @@ -848,11 +853,7 @@ proc callCCompiler*(conf: ConfigRef) = var script: Rope = nil var cmds: TStringSeq var prettyCmds: TStringSeq - let prettyCb = proc (idx: int) = - if prettyCmds[idx].len > 0: - flushDot(conf) - # xxx should probably use stderr like other compiler messages, not stdout - echo prettyCmds[idx] + let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) for idx, it in conf.toCompile: # call the C compiler for the .c file: @@ -1108,9 +1109,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = doAssert toCompile.kind == JArray var cmds: TStringSeq var prettyCmds: TStringSeq - let prettyCb = proc (idx: int) = - if prettyCmds[idx].len > 0: echo prettyCmds[idx] - + let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) for c in toCompile: doAssert c.kind == JArray doAssert c.len >= 2 From 4f9aaee1d9a30976e4ca9bff6fb428960a6b92b0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 00:28:53 -0700 Subject: [PATCH 2246/4254] remove redundant void return in stdlib (#17464) --- lib/posix/linux.nim | 2 +- lib/posix/posix.nim | 2 +- lib/pure/concurrency/threadpool.nim | 4 ++-- lib/pure/coro.nim | 3 +-- lib/pure/json.nim | 2 +- lib/pure/net.nim | 2 +- lib/windows/winlean.nim | 8 ++++---- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim index 5ce9bf2fb..2d6702e87 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -31,7 +31,7 @@ const CLONE_IO* = 0x80000000'i32 CLONE_STOPPED* {.deprecated.} = 0x02000000'i32 -# fn should be of type proc (a2: pointer): void {.cdecl.} +# fn should be of type proc (a2: pointer) {.cdecl.} proc clone*(fn: pointer; child_stack: pointer; flags: cint; arg: pointer; ptid: ptr Pid; tls: pointer; ctid: ptr Pid): cint {.importc, header: "".} diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 520d0caa0..035b4e8fb 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -447,7 +447,7 @@ proc pthread_spin_unlock*(a1: ptr Pthread_spinlock): cint {. proc pthread_testcancel*() {.importc, header: "".} -proc exitnow*(code: int): void {.importc: "_exit", header: "".} +proc exitnow*(code: int) {.importc: "_exit", header: "".} proc access*(a1: cstring, a2: cint): cint {.importc, header: "".} proc alarm*(a1: cint): cint {.importc, header: "".} proc chdir*(a1: cstring): cint {.importc, header: "".} diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 905e668ce..9beb39522 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -451,14 +451,14 @@ proc preferSpawn*(): bool = ## <#spawnX.t>`_ instead. result = gSomeReady.counter > 0 -proc spawn*(call: sink typed): void {.magic: "Spawn".} +proc spawn*(call: sink typed) {.magic: "Spawn".} ## Always spawns a new task, so that the `call` is never executed on ## the calling thread. ## ## `call` has to be a proc call `p(...)` where `p` is gcsafe and has a ## return type that is either `void` or compatible with `FlowVar[T]`. -proc pinnedSpawn*(id: ThreadId; call: sink typed): void {.magic: "Spawn".} +proc pinnedSpawn*(id: ThreadId; call: sink typed) {.magic: "Spawn".} ## Always spawns a new task on the worker thread with `id`, so that ## the `call` is **always** executed on the thread. ## diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 21675928d..af8acf268 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -273,8 +273,7 @@ proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discar coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine))) coro.execContext = CreateFiberEx(stacksize, stacksize, FIBER_FLAG_FLOAT_SWITCH, - (proc(p: pointer): void {.stdcall.} = runCurrentTask()), - nil) + (proc(p: pointer) {.stdcall.} = runCurrentTask()), nil) coro.stack.size = stacksize else: coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine) + stacksize)) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 13cd3fb85..c09af32f3 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1165,7 +1165,7 @@ when defined(nimFixedForwardGeneric): proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = assignDistinctImpl(dst, jsonNode, jsonPath) - proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode): void = + proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode) = if typeExpr.kind == nnkTupleConstr: error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 37e6e8f5a..b37782271 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -200,7 +200,7 @@ when defined(nimHasStyleChecks): proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode, - flags: set[SocketFlag] = {}): void {.gcsafe.} + flags: set[SocketFlag] = {}) {.gcsafe.} proc isDisconnectionError*(flags: set[SocketFlag], lastError: OSErrorCode): bool = diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 1cdb20fe7..6e4c438e6 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -1030,7 +1030,7 @@ const PROCESS_QUERY_LIMITED_INFORMATION* = 0x00001000'i32 PROCESS_SET_LIMITED_INFORMATION* = 0x00002000'i32 type - WAITORTIMERCALLBACK* = proc(para1: pointer, para2: int32): void {.stdcall.} + WAITORTIMERCALLBACK* = proc(para1: pointer, para2: int32) {.stdcall.} proc postQueuedCompletionStatus*(CompletionPort: Handle, dwNumberOfBytesTransferred: DWORD, @@ -1112,7 +1112,7 @@ else: {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} type - LPFIBER_START_ROUTINE* = proc (param: pointer): void {.stdcall.} + LPFIBER_START_ROUTINE* = proc (param: pointer) {.stdcall.} const FIBER_FLAG_FLOAT_SWITCH* = 0x01 @@ -1121,8 +1121,8 @@ proc CreateFiber*(stackSize: int, fn: LPFIBER_START_ROUTINE, param: pointer): po proc CreateFiberEx*(stkCommit: int, stkReserve: int, flags: int32, fn: LPFIBER_START_ROUTINE, param: pointer): pointer {.stdcall, discardable, dynlib: "kernel32", importc.} proc ConvertThreadToFiber*(param: pointer): pointer {.stdcall, discardable, dynlib: "kernel32", importc.} proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, discardable, dynlib: "kernel32", importc.} -proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.} -proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.} +proc DeleteFiber*(fiber: pointer) {.stdcall, discardable, dynlib: "kernel32", importc.} +proc SwitchToFiber*(fiber: pointer) {.stdcall, discardable, dynlib: "kernel32", importc.} proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "windows.h".} proc toFILETIME*(t: int64): FILETIME = From b50776dd2facae166eb9d1bdbcff205c01adc25b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 00:30:41 -0700 Subject: [PATCH 2247/4254] refs #16338 make thttpclient_ssl_remotenetwork.nim less flaky (#17457) --- .../thttpclient_ssl_remotenetwork.nim | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim index eea65bf0b..f56fe274b 100644 --- a/tests/untestable/thttpclient_ssl_remotenetwork.nim +++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim @@ -115,12 +115,23 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win else: # this is unexpected + var fatal = true + var msg = "" if raised: - echo " $# ($#) raised: $#" % [desc, $category, exception_msg] + msg = " $# ($#) raised: $#" % [desc, $category, exception_msg] + if "500 Internal Server Error" in exception_msg: + # refs https://github.com/nim-lang/Nim/issues/16338#issuecomment-804300278 + # we got: `good (good) raised: 500 Internal Server Error` + fatal = false + msg.add " (http 500 => assuming this is not our problem)" else: - echo " $# ($#) did not raise" % [desc, $category] - if category in {good, dubious, bad}: + msg = " $# ($#) did not raise" % [desc, $category] + + if category in {good, dubious, bad} and fatal: + echo "D20210322T121353: error: " & msg fail() + else: + echo "D20210322T121353: warning: " & msg suite "SSL certificate check - httpclient": From d78ebe4a0eadb889255c77f6e375ecec9c706f19 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 00:33:09 -0700 Subject: [PATCH 2248/4254] fix #17454 (#17461) --- lib/core/macros.nim | 20 +++++++++----------- tests/stdlib/tmacros.nim | 5 ++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 491235d8b..8b45ed86b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1287,7 +1287,15 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} = else: badNodeKind someProc, "body=" -proc basename*(a: NimNode): NimNode {.compileTime, benign.} +proc basename*(a: NimNode): NimNode {.raises: [].} = + ## Pull an identifier from prefix/postfix expressions. + case a.kind + of nnkIdent: result = a + of nnkPostfix, nnkPrefix: result = a[1] + of nnkPragmaExpr: result = basename(a[0]) + else: + error("Do not know how to get basename of (" & treeRepr(a) & ")\n" & + repr(a), a) proc `$`*(node: NimNode): string {.compileTime.} = ## Get the string of an identifier node. @@ -1347,16 +1355,6 @@ proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} = a[i + 1] = a[i] a[pos] = b -proc basename*(a: NimNode): NimNode = - ## Pull an identifier from prefix/postfix expressions. - case a.kind - of nnkIdent: result = a - of nnkPostfix, nnkPrefix: result = a[1] - of nnkPragmaExpr: result = basename(a[0]) - else: - error("Do not know how to get basename of (" & treeRepr(a) & ")\n" & - repr(a), a) - proc `basename=`*(a: NimNode; val: string) {.compileTime.}= case a.kind of nnkIdent: diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index 0cc1e340c..effe1032f 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -1,4 +1,4 @@ -import macros +import std/macros block: # hasArgOfName macro m(u: untyped): untyped = @@ -7,3 +7,6 @@ block: # hasArgOfName doAssert not hasArgOfName(params u,"nonexistent") proc p(s: string; i,j,k: int; b: bool; xs,ys: seq[int] = @[]) {.m.} = discard + +block: # bug #17454 + proc f(v: NimNode): string {.raises: [].} = $v From f3a642710989c3f47d5c2131efd69e3dbfedc336 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 00:34:04 -0700 Subject: [PATCH 2249/4254] refs #17292 fix `repr` with `do:` (#17449) * refs #17292 fix `repr` with `do:` * address comment --- compiler/renderer.nim | 13 +++++-- tests/stdlib/trepr.nim | 80 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 13ff6941f..c36eaaf11 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1007,12 +1007,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr: if n.len > 1 and n.lastSon.kind in {nkStmtList, nkStmtListExpr}: accentedName(g, n[0]) - if n.len > 2: + var i = 1 + while i < n.len and n[i].kind notin {nkStmtList, nkStmtListExpr}: i.inc + if i > 1: put(g, tkParLe, "(") - gcomma(g, n, 1, -2) + gcomma(g, n, 1, i - 1 - n.len) put(g, tkParRi, ")") put(g, tkColon, ":") - gsub(g, n, n.len-1) + gsub(g, n, i) + for j in i+1 ..< n.len: + optNL(g) + put(g, tkDo, "do") + put(g, tkColon, ":") + gsub(g, n, j) elif n.len >= 1: case bracketKind(g, n[0]) of bkBracket: diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 1d89d37b2..357854d67 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -6,6 +6,8 @@ discard """ # if excessive, could remove 'cpp' from targets from strutils import endsWith, contains +from std/macros import newLit +macro deb(a): string = newLit a.repr template main() = doAssert repr({3,5}) == "{3, 5}" @@ -65,5 +67,83 @@ template main() = else: doAssert reprOpenarray(arr) == "[1, 2, 3]" + block: # bug #17292 + template foo(a, b, c, d) = discard + block: + let a = deb: + foo(1, 2, 3, 4) + doAssert a == "\nfoo(1, 2, 3, 4)" + block: + let a = deb: + foo(1, 2, 3): 4 + doAssert a == """ + +foo(1, 2, 3): + 4""" + + block: + let a = deb: + foo(1, 2): 3 + do: 4 + doAssert a == """ + +foo(1, 2): + 3 +do: + 4""" + + block: + let a = deb: + foo(1): 3 + do: 3 + do: 4 + doAssert a == """ + +foo(1): + 3 +do: + 3 +do: + 4""" + + block: + let a = deb: + foo(1): + 3 + do: + discard + 3 + do: + discard + 4 + + doAssert a == """ + +foo(1): + 3 +do: + discard + 3 +do: + discard + 4""" + + block: + let a = deb: + foo: 1 + do: 2 + do: 3 + do: 4 + doAssert a == """ + +foo: + 1 +do: + 2 +do: + 3 +do: + 4""" + static: main() main() From 1d19cd660f39b9e76005b849ae1f7ca966278438 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 00:37:15 -0700 Subject: [PATCH 2250/4254] fix #17458 tnetconnect.nim flaky (#17459) * fix tests * fix #17458 --- tests/stdlib/tnetconnect.nim | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim index e27499651..b74545710 100644 --- a/tests/stdlib/tnetconnect.nim +++ b/tests/stdlib/tnetconnect.nim @@ -1,22 +1,26 @@ discard """ - cmd: "nim c -r -d:ssl $file" - exitcode: 0 + matrix: "-d:ssl" """ import std/net +from std/strutils import `%` -# Issue 15215 - https://github.com/nim-lang/Nim/issues/15215 +# bug #15215 proc test() = - var - ctx = newContext() - socket = newSocket() + let ctx = newContext() - wrapSocket(ctx, socket) + proc fn(url: string) = + let socket = newSocket() + defer: close(socket) + connect(socket, url, Port(443), 5000) # typically 20 could be enough + send(socket, "GET / HTTP/1.0\nHost: $#\nConnection: close\n\n" % [url]) + wrapSocket(ctx, socket) - connect(socket, "www.nim-lang.org", Port(443), 5000) - - send(socket, "GET / HTTP/1.0\nHost: www.nim-lang.org\nConnection: close\n\n") - - close(socket) + # trying 2 sites makes it more resilent: refs #17458 this could give: + # Error: unhandled exception: Call to 'connect' timed out. [TimeoutError] + try: + fn("www.nim-lang.org") + except TimeoutError: + fn("www.google.com") test() From d6a16020fe98b467459544ee4cfafe61d681f918 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 23 Mar 2021 08:52:00 +0100 Subject: [PATCH 2251/4254] IC: backend: remember produced type information (#17440) --- compiler/ast.nim | 15 ++++---------- compiler/ccgtypes.nim | 14 ++++++++++--- compiler/ic/cbackend.nim | 43 ++++++++++++++++++++++++++++++++------- compiler/ic/ic.nim | 11 ++++++++-- compiler/ic/rodfiles.nim | 1 + compiler/modulegraphs.nim | 29 ++++++++++++++++++++++---- compiler/passes.nim | 5 +++++ compiler/sem.nim | 2 +- compiler/semdata.nim | 15 +------------- 9 files changed, 93 insertions(+), 42 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 50a2fb58c..1f3d5f129 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1229,17 +1229,10 @@ proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym, result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id, options: options, owner: owner, offset: defaultOffset) when false: - if id.item > 2141: - let s = getStackTrace() - const words = ["createTypeBoundOps", - "initOperators", - "generateInstance", - "semIdentDef", "addLocalDecl"] - for w in words: - if w in s: - x.inc w - return - x.inc "" + if id.module == 48 and id.item == 39: + writeStackTrace() + echo "kind ", symKind, " ", name.s + if owner != nil: echo owner.name.s proc astdef*(s: PSym): PNode = # get only the definition (initializer) portion of the ast diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 73ee9cb8a..e17a55542 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1386,7 +1386,6 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = let owner = t.skipTypes(typedescPtrs).itemId.module if owner != m.module.position and moduleOpenForCodegen(m, owner): # make sure the type info is created in the owner module - assert m.g.modules[owner] != nil discard genTypeInfoV2(m.g.modules[owner], origType, info) # reference the type info as extern here discard cgsym(m, "TNimTypeV2") @@ -1456,18 +1455,27 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = result = "NTI$1$2_" % [rope(typeToC(t)), rope($sig)] m.typeInfoMarker[sig] = result - let owner = t.skipTypes(typedescPtrs).itemId.module + let old = m.g.graph.emittedTypeInfo.getOrDefault($result) + if old != FileIndex(0): + discard cgsym(m, "TNimType") + discard cgsym(m, "TNimNode") + declareNimType(m, "TNimType", result, old.int) + return prefixTI.rope & result & ")".rope + + var owner = t.skipTypes(typedescPtrs).itemId.module if owner != m.module.position and moduleOpenForCodegen(m, owner): # make sure the type info is created in the owner module - assert m.g.modules[owner] != nil discard genTypeInfoV1(m.g.modules[owner], origType, info) # reference the type info as extern here discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") declareNimType(m, "TNimType", result, owner) return prefixTI.rope & result & ")".rope + else: + owner = m.module.position.int32 m.g.typeInfoMarker[sig] = (str: result, owner: owner) + rememberEmittedTypeInfo(m.g.graph, FileIndex(owner), $result) case t.kind of tyEmpty, tyVoid: result = rope"0" diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index 88b2a9477..34ee59d52 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -18,7 +18,7 @@ ## also doing cross-module dependency tracking and DCE that we don't need ## anymore. DCE is now done as prepass over the entire packed module graph. -import std/[packedsets, algorithm] +import std/[packedsets, algorithm, tables] # std/intsets would give `UnusedImport`, pending https://github.com/nim-lang/Nim/issues/14246 import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen, pathutils, extccomp, msgs] @@ -45,6 +45,10 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info)) +proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) = + for x in mitems(m.fromDisk.emittedTypeInfo): + g.emittedTypeInfo[x] = origin + proc addFileToLink(config: ConfigRef; m: PSym) = let filename = AbsoluteFile toFullPath(config, m.position.FileIndex) let ext = @@ -59,11 +63,28 @@ proc addFileToLink(config: ConfigRef; m: PSym) = flags: {CfileFlag.Cached}) addFileToCompile(config, cf) -proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool = +when defined(debugDce): + import std / [os, packedsets] + +proc storeAliveSymsImpl(asymFile: AbsoluteFile; s: seq[int32]) = + var f = rodfiles.create(asymFile.string) + f.storeHeader() + f.storeSection aliveSymsSection + f.storeSeq(s) + close f + +template prepare {.dirty.} = let asymFile = toRodFile(config, AbsoluteFile toFullPath(config, position.FileIndex), ".alivesyms") var s = newSeqOfCap[int32](alive[position].len) for a in items(alive[position]): s.add int32(a) sort(s) + +proc storeAliveSyms(config: ConfigRef; position: int; alive: AliveSyms) = + prepare() + storeAliveSymsImpl(asymFile, s) + +proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool = + prepare() var f2 = rodfiles.open(asymFile.string) f2.loadHeader() f2.loadSection aliveSymsSection @@ -73,12 +94,17 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool if f2.err == ok and oldData == s: result = false else: + when defined(debugDce): + let oldAsSet = toPackedSet[int32](oldData) + let newAsSet = toPackedSet[int32](s) + echo "set of live symbols changed ", asymFile.changeFileExt("rod"), " ", position, " ", f2.err + echo "in old but not in new ", oldAsSet.difference(newAsSet) + echo "in new but not in old ", newAsSet.difference(oldAsSet) + + if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0: + echo "command failed" result = true - var f = rodfiles.create(asymFile.string) - f.storeHeader() - f.storeSection aliveSymsSection - f.storeSeq(s) - close f + storeAliveSymsImpl(asymFile, s) proc generateCode*(g: ModuleGraph) = ## The single entry point, generate C(++) code for the entire @@ -95,6 +121,8 @@ proc generateCode*(g: ModuleGraph) = assert false of storing, outdated: generateCodeForModule(g, g.packed[i], alive) + closeRodFile(g, g.packed[i].module) + storeAliveSyms(g.config, g.packed[i].module.position, alive) of loaded: # Even though this module didn't change, DCE might trigger a change. # Consider this case: Module A uses symbol S from B and B does not use @@ -104,3 +132,4 @@ proc generateCode*(g: ModuleGraph) = generateCodeForModule(g, g.packed[i], alive) else: addFileToLink(g.config, g.packed[i].module) + replayTypeInfo(g, g.packed[i], FileIndex(i)) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 99a68e0f0..230b4d087 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -42,6 +42,8 @@ type methodsPerType*: seq[(PackedItemId, int, PackedItemId)] enumToStringProcs*: seq[(PackedItemId, PackedItemId)] + emittedTypeInfo*: seq[string] + sh*: Shared cfg: PackedConfig @@ -58,7 +60,7 @@ type config*: ConfigRef proc isActive*(e: PackedEncoder): bool = e.config != nil -proc disable*(e: var PackedEncoder) = e.config = nil +proc disable(e: var PackedEncoder) = e.config = nil template primConfigFields(fn: untyped) {.dirty.} = fn backend @@ -552,6 +554,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef loadSeqSection attachedOpsSection, m.attachedOps loadSeqSection methodsPerTypeSection, m.methodsPerType loadSeqSection enumToStringProcsSection, m.enumToStringProcs + loadSeqSection typeInfoSection, m.emittedTypeInfo close(f) result = f.err @@ -614,6 +617,7 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac storeSeqSection attachedOpsSection, m.attachedOps storeSeqSection methodsPerTypeSection, m.methodsPerType storeSeqSection enumToStringProcsSection, m.enumToStringProcs + storeSeqSection typeInfoSection, m.emittedTypeInfo close(f) encoder.disable() @@ -1139,7 +1143,10 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = echo "all symbols" for i in 0..high(m.sh.syms): - echo " ", m.sh.strings[m.sh.syms[i].name], " local ID: ", i + if m.sh.syms[i].name != LitId(0): + echo " ", m.sh.strings[m.sh.syms[i].name], " local ID: ", i, " kind ", m.sh.syms[i].kind + else: + echo " local ID: ", i, " kind ", m.sh.syms[i].kind echo "symbols: ", m.sh.syms.len, " types: ", m.sh.types.len, " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len, diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index fa0a7c734..a518870f8 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -36,6 +36,7 @@ type attachedOpsSection methodsPerTypeSection enumToStringProcsSection + typeInfoSection # required by the backend aliveSymsSection # beware, this is stored in a `.alivesyms` file. RodFileError* = enum diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index de3773ca5..9ac76457c 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -11,9 +11,8 @@ ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -import ast, astalgo, intsets, tables, options, lineinfos, hashes, idents, - btrees, md5, ropes, msgs - +import std / [intsets, tables, hashes, md5] +import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils import ic / [packed_ast, ic] type @@ -60,6 +59,7 @@ type attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc. methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods enumToStringProcs*: Table[ItemId, LazySym] + emittedTypeInfo*: Table[string, FileIndex] startupPackedConfig*: PackedConfig packageSyms*: TStrTable @@ -68,7 +68,6 @@ type importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies suggestMode*: bool # whether we are in nimsuggest mode or not. invalidTransitiveClosure: bool - systemModuleComplete*: bool inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the # first module that included it importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive @@ -435,6 +434,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.canonTypes = initTable[SigHash, PType]() result.symBodyHashes = initTable[int, SigHash]() result.operators = initOperators(result) + result.emittedTypeInfo = initTable[string, FileIndex]() proc resetAllModules*(g: ModuleGraph) = initStrTable(g.packageSyms) @@ -455,6 +455,27 @@ proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = elif fileIdx.int32 < g.ifaces.len: result = g.ifaces[fileIdx.int32].module +proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) = + #assert(not isCachedModule(g, m.int32)) + if g.config.symbolFiles != disabledSf: + #assert g.encoders[m.int32].isActive + g.packed[m.int32].fromDisk.emittedTypeInfo.add ti + +proc closeRodFile*(g: ModuleGraph; m: PSym) = + if g.config.symbolFiles in {readOnlySf, v2Sf}: + # For stress testing we seek to reload the symbols from memory. This + # way much of the logic is tested but the test is reproducible as it does + # not depend on the hard disk contents! + let mint = m.position + saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))), + g.encoders[mint], g.packed[mint].fromDisk) + elif g.config.symbolFiles == stressTest: + # debug code, but maybe a good idea for production? Could reduce the compiler's + # memory consumption considerably at the cost of more loads from disk. + let mint = m.position + simulateCachedModule(g, m, g.packed[mint].fromDisk) + g.packed[mint].status = loaded + proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = diff --git a/compiler/passes.nim b/compiler/passes.nim index 11799b122..3debce1f6 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -187,4 +187,9 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; closeParser(p) if s.kind != llsStdIn: break closePasses(graph, a) + if graph.config.backend notin {backendC, backendCpp, backendObjc}: + # We only write rod files here if no C-like backend is active. + # The C-like backends have been patched to support the IC mechanism. + # They are responsible for closing the rod files. See `cbackend.nim`. + closeRodFile(graph, module) result = true diff --git a/compiler/sem.nim b/compiler/sem.nim index bb42b5c1b..6b3f0c80d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -661,7 +661,7 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = result.add(c.module.ast) popOwner(c) popProcCon(c) - saveRodFile(c) + sealRodFile(c) const semPass* = makePass(myOpen, myProcess, myClose, isFrontend = true) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5cd440cc1..c655047e2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -560,23 +560,10 @@ proc addToGenericCache*(c: PContext; s: PSym; inst: PType) = if c.config.symbolFiles != disabledSf: storeTypeInst(c.encoder, c.packedRepr, s, inst) -proc saveRodFile*(c: PContext) = +proc sealRodFile*(c: PContext) = if c.config.symbolFiles != disabledSf: if c.graph.vm != nil: for (m, n) in PCtx(c.graph.vm).vmstateDiff: if m == c.module: addPragmaComputation(c, n) - if sfSystemModule in c.module.flags: - c.graph.systemModuleComplete = true c.idgen.sealed = true # no further additions are allowed - if c.config.symbolFiles != stressTest: - # For stress testing we seek to reload the symbols from memory. This - # way much of the logic is tested but the test is reproducible as it does - # not depend on the hard disk contents! - saveRodFile(toRodFile(c.config, AbsoluteFile toFullPath(c.config, FileIndex c.module.position)), - c.encoder, c.packedRepr) - else: - # debug code, but maybe a good idea for production? Could reduce the compiler's - # memory consumption considerably at the cost of more loads from disk. - simulateCachedModule(c.graph, c.module, c.packedRepr) - c.graph.packed[c.module.position].status = loaded From 64e6670de45f8f5a470e5cc3ad9ed2cb85f0b57c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 01:31:23 -0700 Subject: [PATCH 2252/4254] fix #16973 ; nim doc now shows correct, canonical import name in title (#16999) * nim doc now shows correct import name in title --- compiler/docgen.nim | 25 +++++++++++----- compiler/options.nim | 29 ++++++++++++------- .../expected/index.html | 4 +-- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 57d5e7b01..dded231d7 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -63,7 +63,22 @@ proc prettyString(a: object): string = for k, v in fieldPairs(a): result.add k & ": " & $v & "\n" -proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): RelativeFile = +proc canonicalImport*(conf: ConfigRef, file: AbsoluteFile): string = + ##[ + Shows the canonical module import, e.g.: + system, std/tables, fusion/pointers, system/assertions, std/private/asciitables + ]## + var ret = getRelativePathFromConfigPath(conf, file, isTitle = true) + let dir = getNimbleFile(conf, $file).parentDir.AbsoluteDir + if not dir.isEmpty: + let relPath = relativeTo(file, dir) + if not relPath.isEmpty and (ret.isEmpty or relPath.string.len < ret.string.len): + ret = relPath + if ret.isEmpty: + ret = relativeTo(file, conf.projectPath) + result = ret.string.nativeToUnixPath.changeFileExt("") + +proc presentationPath*(conf: ConfigRef, file: AbsoluteFile): RelativeFile = ## returns a relative file that will be appended to outDir let file2 = $file template bail() = @@ -97,10 +112,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re bail() if isAbsolute(result.string): result = file.string.splitPath()[1].RelativeFile - if isTitle: - result = result.string.nativeToUnixPath.RelativeFile - else: - result = result.string.replace("..", dotdotMangle).RelativeFile + result = result.string.replace("..", dotdotMangle).RelativeFile doAssert not result.isEmpty doAssert not isAbsolute(result.string) @@ -1259,8 +1271,7 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope = setIndexTerm(d[], external, "", title) else: # Modules get an automatic title for the HTML, but no entry in the index. - # better than `extractFilename(changeFileExt(d.filename, ""))` as it disambiguates dups - title = $presentationPath(d.conf, AbsoluteFile d.filename, isTitle = true).changeFileExt("") + title = canonicalImport(d.conf, AbsoluteFile d.filename) var subtitle = "".rope if d.meta[metaSubtitle] != "": dispA(d.conf, subtitle, "

                                      $1

                                      ", diff --git a/compiler/options.nim b/compiler/options.nim index a2d6a51b3..2d63043df 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -761,8 +761,25 @@ when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): let ret = relativePath(path, base) result = path.len > 0 and not ret.startsWith ".." -proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile): RelativeFile = +const stdlibDirs = [ + "pure", "core", "arch", + "pure/collections", + "pure/concurrency", + "pure/unidecode", "impure", + "wrappers", "wrappers/linenoise", + "windows", "posix", "js"] + +const + pkgPrefix = "pkg/" + stdPrefix = "std/" + +proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile = let f = $f + if isTitle: + for dir in stdlibDirs: + let path = conf.libpath.string / dir / f.lastPathPart + if path.cmpPaths(f) == 0: + return RelativeFile(stdPrefix & f.splitFile.name) template search(paths) = for it in paths: let it = $it @@ -784,18 +801,8 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile result = rawFindFile2(conf, RelativeFile f.toLowerAscii) patchModule(conf) -const stdlibDirs = [ - "pure", "core", "arch", - "pure/collections", - "pure/concurrency", - "pure/unidecode", "impure", - "wrappers", "wrappers/linenoise", - "windows", "posix", "js"] - proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFile = # returns path to module - const pkgPrefix = "pkg/" - const stdPrefix = "std/" var m = addFileExt(modulename, NimExt) if m.startsWith(pkgPrefix): result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true) diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 4646732f1..db7470050 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -17,7 +17,7 @@ -foo +nimdoc/test_out_index_dot_html/foo @@ -64,7 +64,7 @@ window.addEventListener('DOMContentLoaded', main);
                                      -

                                      foo

                                      +

                                      nimdoc/test_out_index_dot_html/foo

                                      From c719d79d232c1dc8d878b0799e1011519652016f Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 23 Mar 2021 17:49:02 +0800 Subject: [PATCH 2253/4254] add algorithm.merge (#16182) * add merge to algorithm * Apply suggestions from code review * Update lib/pure/algorithm.nim * Apply suggestions from code review * Update changelog.md Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- changelog.md | 3 + lib/pure/algorithm.nim | 94 +++++++++++++++++++++ tests/stdlib/talgorithm.nim | 159 +++++++++++++++++++++++++++++++++++- 3 files changed, 255 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 00fc970bf..78817cf85 100644 --- a/changelog.md +++ b/changelog.md @@ -212,6 +212,9 @@ - `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` and `$none(int)` to `"none(int)"` instead of `"None[int]"`. + +- Added `algorithm.merge`. + - Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target. diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index a32df65bb..0410d65ee 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -42,6 +42,8 @@ runnableExamples: ## * `sequtils module`_ for working with the built-in seq type ## * `tables module`_ for sorting tables +import std/private/since + type SortOrder* = enum Descending, Ascending @@ -559,6 +561,98 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = assert isSorted(e) == false isSorted(a, system.cmp[T], order) +proc merge*[T]( + result: var seq[T], + x, y: openArray[T], cmp: proc(x, y: T): int {.closure.} +) {.since: (1, 5, 1).} = + ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted. + ## If you do not wish to provide your own `cmp`, + ## you may use `system.cmp` or instead call the overloaded + ## version of `merge`, which uses `system.cmp`. + ## + ## .. note:: The original data of `result` is not cleared, + ## new data is appended to `result`. + ## + ## **See also:** + ## * `merge proc<#merge,seq[T],openArray[T],openArray[T]>`_ + runnableExamples: + let x = @[1, 3, 6] + let y = @[2, 3, 4] + + block: + var merged = @[7] # new data is appended to merged sequence + merged.merge(x, y, system.cmp[int]) + assert merged == @[7, 1, 2, 3, 3, 4, 6] + + block: + var merged = @[7] # if you only want new data, clear merged sequence first + merged.setLen(0) + merged.merge(x, y, system.cmp[int]) + assert merged.isSorted + assert merged == @[1, 2, 3, 3, 4, 6] + + import std/sugar + + var res: seq[(int, int)] + res.merge([(1, 1)], [(1, 2)], (a, b) => a[0] - b[0]) + assert res == @[(1, 1), (1, 2)] + + assert seq[int].default.dup(merge([1, 3], [2, 4])) == @[1, 2, 3, 4] + + let + sizeX = x.len + sizeY = y.len + oldLen = result.len + + result.setLen(oldLen + sizeX + sizeY) + + var + ix = 0 + iy = 0 + i = oldLen + + while true: + if ix == sizeX: + while iy < sizeY: + result[i] = y[iy] + inc i + inc iy + return + + if iy == sizeY: + while ix < sizeX: + result[i] = x[ix] + inc i + inc ix + return + + let itemX = x[ix] + let itemY = y[iy] + + if cmp(itemX, itemY) > 0: # to have a stable sort + result[i] = itemY + inc iy + else: + result[i] = itemX + inc ix + + inc i + +proc merge*[T](result: var seq[T], x, y: openArray[T]) {.inline, since: (1, 5, 1).} = + ## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function. + ## + ## **See also:** + ## * `merge proc<#merge,seq[T],openArray[T],openArray[T],proc(T,T)>`_ + runnableExamples: + let x = [5, 10, 15, 20, 25] + let y = [50, 40, 30, 20, 10].sorted + + var merged: seq[int] + merged.merge(x, y) + assert merged.isSorted + assert merged == @[5, 10, 10, 15, 20, 20, 25, 30, 40, 50] + merge(result, x, y, system.cmp) + proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = ## Produces the Cartesian product of the array. ## Every element of the result is a combination of one element from each seq in `x`, diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index fecd85820..5bb5a6bdf 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -4,7 +4,8 @@ discard """ ''' """ #12928,10456 -import std/[sequtils, algorithm, json] + +import std/[sequtils, algorithm, json, sugar] proc test() = try: @@ -114,3 +115,159 @@ block: doAssert binarySearch(moreData, 6) == -1 doAssert binarySearch(moreData, 4711) == 4 doAssert binarySearch(moreData, 4712) == -1 + +# merge +proc main() = + block: + var x = @[1, 7, 8, 11, 21, 33, 45, 99] + var y = @[6, 7, 9, 12, 57, 66] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == sorted(x & y) + + block: + var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] + var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] + + var merged: seq[int] + merged.merge(x, y, (x, y) => -system.cmp(x, y)) + doAssert merged.isSorted((x, y) => -system.cmp(x, y)) + doAssert merged == sorted(x & y, SortOrder.Descending) + + block: + var x: seq[int] = @[] + var y = @[1] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.isSorted(SortOrder.Descending) + doAssert merged == @[1] + + block: + var x = [1, 3, 5, 5, 7] + var y: seq[int] = @[] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == @x + + block: + var x = [1, 3, 5, 5, 7] + var y: seq[int] = @[] + + var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34] + merged.merge(x, y) + doAssert merged == @[1, 2, 3, 5, 6, 56, 99, 2, 34, 1, 3, 5, 5, 7] + + + block: + var x: array[0, int] + var y = [1, 4, 6, 7, 9] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == @y + + block: + var x: array[0, int] + var y: array[0, int] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + + block: + var x: array[0, int] + var y: array[0, int] + + var merged: seq[int] = @[99, 99, 99] + merged.setLen(0) + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + + block: + var x: seq[int] + var y: seq[int] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + + block: + type + Record = object + id: int + + proc r(id: int): Record = + Record(id: id) + + proc cmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return -1 + result = 1 + + var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] + var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] + + var merged: seq[Record] = @[] + merged.merge(x, y, cmp) + doAssert merged.isSorted(cmp) + doAssert merged.len == 12 + + block: + type + Record = object + id: int + + proc r(id: int): Record = + Record(id: id) + + proc ascendingCmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return -1 + result = 1 + + proc descendingCmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return 1 + result = -1 + + var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] + var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] + + var merged: seq[Record] + merged.setLen(0) + merged.merge(x, y, ascendingCmp) + doAssert merged.isSorted(ascendingCmp) + doAssert merged == sorted(x & y, ascendingCmp) + + reverse(x) + reverse(y) + + merged.setLen(0) + merged.merge(x, y, descendingCmp) + doAssert merged.isSorted(descendingCmp) + doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending) + + reverse(x) + reverse(y) + merged.setLen(0) + merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) + doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) + doAssert merged == sorted(x & y, ascendingCmp) + + + var x: seq[(int, int)] + x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) + doAssert x == @[(1, 1), (1, 2)] + +static: main() +main() From c27cd83265558195316e0d3b6d13ccadcaecc728 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 23 Mar 2021 02:51:21 -0700 Subject: [PATCH 2254/4254] remove {.compileTime.} for procs with NimNode: redundant because of tfTriggersCompileTime (#17463) --- lib/core/macros.nim | 193 +++++++++++++++++++--------------------- lib/pure/asyncmacro.nim | 13 ++- lib/pure/htmlgen.nim | 4 +- lib/pure/json.nim | 4 +- lib/pure/sugar.nim | 2 +- lib/pure/xmltree.nim | 2 +- 6 files changed, 106 insertions(+), 112 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 8b45ed86b..5a556fc8d 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -404,29 +404,29 @@ proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.} proc hint*(msg: string, n: NimNode = nil) {.magic: "NHint", benign.} ## Writes a hint message at compile time. -proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} = +proc newStrLitNode*(s: string): NimNode {.noSideEffect.} = ## Creates a string literal node from `s`. result = newNimNode(nnkStrLit) result.strVal = s -proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} = +proc newCommentStmtNode*(s: string): NimNode {.noSideEffect.} = ## Creates a comment statement node. result = newNimNode(nnkCommentStmt) result.strVal = s -proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} = +proc newIntLitNode*(i: BiggestInt): NimNode = ## Creates an int literal node from `i`. result = newNimNode(nnkIntLit) result.intVal = i -proc newFloatLitNode*(f: BiggestFloat): NimNode {.compileTime.} = +proc newFloatLitNode*(f: BiggestFloat): NimNode = ## Creates a float literal node from `f`. result = newNimNode(nnkFloatLit) result.floatVal = f {.push warnings: off.} -proc newIdentNode*(i: NimIdent): NimNode {.compileTime, deprecated.} = +proc newIdentNode*(i: NimIdent): NimNode {.deprecated: "use ident(string)".} = ## Creates an identifier node from `i`. result = newNimNode(nnkIdent) result.ident = i @@ -478,7 +478,7 @@ proc callsite*(): NimNode {.magic: "NCallSite", benign, deprecated: "Deprecated since v0.18.1; use varargs[untyped] in the macro prototype instead".} ## Returns the AST of the invocation expression that invoked this macro. -proc toStrLit*(n: NimNode): NimNode {.compileTime.} = +proc toStrLit*(n: NimNode): NimNode = ## Converts the AST `n` to the concrete Nim code and wraps that ## in a string literal node. return newStrLitNode(repr(n)) @@ -504,11 +504,11 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.} ## Copy lineinfo from `info`. -proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} = +proc lineInfoObj*(n: NimNode): LineInfo = ## Returns `LineInfo` of `n`, using absolute path for `filename`. result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn) -proc lineInfo*(arg: NimNode): string {.compileTime.} = +proc lineInfo*(arg: NimNode): string = ## Return line info in the form `filepath(line, column)`. $arg.lineInfoObj @@ -522,14 +522,14 @@ proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.} ## Some builtins set an error flag. This is then turned into a proper ## exception. **Note**: Ordinary application code should not call this. -proc parseExpr*(s: string): NimNode {.noSideEffect, compileTime.} = +proc parseExpr*(s: string): NimNode {.noSideEffect.} = ## Compiles the passed string to its AST representation. ## Expects a single expression. Raises `ValueError` for parsing errors. result = internalParseExpr(s) let x = internalErrorFlag() if x.len > 0: raise newException(ValueError, x) -proc parseStmt*(s: string): NimNode {.noSideEffect, compileTime.} = +proc parseStmt*(s: string): NimNode {.noSideEffect.} = ## Compiles the passed string to its AST representation. ## Expects one or more statements. Raises `ValueError` for parsing errors. result = internalParseStmt(s) @@ -626,25 +626,25 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} = doAssert y == 3 bar2() -proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} = +proc expectKind*(n: NimNode, k: NimNodeKind) = ## Checks that `n` is of kind `k`. If this is not the case, ## compilation aborts with an error message. This is useful for writing ## macros that check the AST that is passed to them. if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind, n) -proc expectMinLen*(n: NimNode, min: int) {.compileTime.} = +proc expectMinLen*(n: NimNode, min: int) = ## Checks that `n` has at least `min` children. If this is not the case, ## compilation aborts with an error message. This is useful for writing ## macros that check its number of arguments. if n.len < min: error("Expected a node with at least " & $min & " children, got " & $n.len, n) -proc expectLen*(n: NimNode, len: int) {.compileTime.} = +proc expectLen*(n: NimNode, len: int) = ## Checks that `n` has exactly `len` children. If this is not the case, ## compilation aborts with an error message. This is useful for writing ## macros that check its number of arguments. if n.len != len: error("Expected a node with " & $len & " children, got " & $n.len, n) -proc expectLen*(n: NimNode, min, max: int) {.compileTime.} = +proc expectLen*(n: NimNode, min, max: int) = ## Checks that `n` has a number of children in the range `min..max`. ## If this is not the case, compilation aborts with an error message. ## This is useful for writing macros that check its number of arguments. @@ -652,13 +652,12 @@ proc expectLen*(n: NimNode, min, max: int) {.compileTime.} = error("Expected a node with " & $min & ".." & $max & " children, got " & $n.len, n) proc newTree*(kind: NimNodeKind, - children: varargs[NimNode]): NimNode {.compileTime.} = + children: varargs[NimNode]): NimNode = ## Produces a new node with children. result = newNimNode(kind) result.add(children) -proc newCall*(theProc: NimNode, - args: varargs[NimNode]): NimNode {.compileTime.} = +proc newCall*(theProc: NimNode, args: varargs[NimNode]): NimNode = ## Produces a new call node. `theProc` is the proc that is called with ## the arguments `args[0..]`. result = newNimNode(nnkCall) @@ -667,7 +666,7 @@ proc newCall*(theProc: NimNode, {.push warnings: off.} -proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime, deprecated: +proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.deprecated: "Deprecated since v0.18.1; use 'newCall(string, ...)' or 'newCall(NimNode, ...)' instead".} = ## Produces a new call node. `theProc` is the proc that is called with ## the arguments `args[0..]`. @@ -678,128 +677,128 @@ proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime, {.pop.} proc newCall*(theProc: string, - args: varargs[NimNode]): NimNode {.compileTime.} = + args: varargs[NimNode]): NimNode = ## Produces a new call node. `theProc` is the proc that is called with ## the arguments `args[0..]`. result = newNimNode(nnkCall) result.add(newIdentNode(theProc)) result.add(args) -proc newLit*(c: char): NimNode {.compileTime.} = +proc newLit*(c: char): NimNode = ## Produces a new character literal node. result = newNimNode(nnkCharLit) result.intVal = ord(c) -proc newLit*(i: int): NimNode {.compileTime.} = +proc newLit*(i: int): NimNode = ## Produces a new integer literal node. result = newNimNode(nnkIntLit) result.intVal = i -proc newLit*(i: int8): NimNode {.compileTime.} = +proc newLit*(i: int8): NimNode = ## Produces a new integer literal node. result = newNimNode(nnkInt8Lit) result.intVal = i -proc newLit*(i: int16): NimNode {.compileTime.} = +proc newLit*(i: int16): NimNode = ## Produces a new integer literal node. result = newNimNode(nnkInt16Lit) result.intVal = i -proc newLit*(i: int32): NimNode {.compileTime.} = +proc newLit*(i: int32): NimNode = ## Produces a new integer literal node. result = newNimNode(nnkInt32Lit) result.intVal = i -proc newLit*(i: int64): NimNode {.compileTime.} = +proc newLit*(i: int64): NimNode = ## Produces a new integer literal node. result = newNimNode(nnkInt64Lit) result.intVal = i -proc newLit*(i: uint): NimNode {.compileTime.} = +proc newLit*(i: uint): NimNode = ## Produces a new unsigned integer literal node. result = newNimNode(nnkUIntLit) result.intVal = BiggestInt(i) -proc newLit*(i: uint8): NimNode {.compileTime.} = +proc newLit*(i: uint8): NimNode = ## Produces a new unsigned integer literal node. result = newNimNode(nnkUInt8Lit) result.intVal = BiggestInt(i) -proc newLit*(i: uint16): NimNode {.compileTime.} = +proc newLit*(i: uint16): NimNode = ## Produces a new unsigned integer literal node. result = newNimNode(nnkUInt16Lit) result.intVal = BiggestInt(i) -proc newLit*(i: uint32): NimNode {.compileTime.} = +proc newLit*(i: uint32): NimNode = ## Produces a new unsigned integer literal node. result = newNimNode(nnkUInt32Lit) result.intVal = BiggestInt(i) -proc newLit*(i: uint64): NimNode {.compileTime.} = +proc newLit*(i: uint64): NimNode = ## Produces a new unsigned integer literal node. result = newNimNode(nnkUInt64Lit) result.intVal = BiggestInt(i) -proc newLit*(b: bool): NimNode {.compileTime.} = +proc newLit*(b: bool): NimNode = ## Produces a new boolean literal node. result = if b: bindSym"true" else: bindSym"false" -proc newLit*(s: string): NimNode {.compileTime.} = +proc newLit*(s: string): NimNode = ## Produces a new string literal node. result = newNimNode(nnkStrLit) result.strVal = s when false: # the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875 - proc newLit*(f: float): NimNode {.compileTime.} = + proc newLit*(f: float): NimNode = ## Produces a new float literal node. result = newNimNode(nnkFloatLit) result.floatVal = f -proc newLit*(f: float32): NimNode {.compileTime.} = +proc newLit*(f: float32): NimNode = ## Produces a new float literal node. result = newNimNode(nnkFloat32Lit) result.floatVal = f -proc newLit*(f: float64): NimNode {.compileTime.} = +proc newLit*(f: float64): NimNode = ## Produces a new float literal node. result = newNimNode(nnkFloat64Lit) result.floatVal = f when declared(float128): - proc newLit*(f: float128): NimNode {.compileTime.} = + proc newLit*(f: float128): NimNode = ## Produces a new float literal node. result = newNimNode(nnkFloat128Lit) result.floatVal = f -proc newLit*(arg: enum): NimNode {.compileTime.} = +proc newLit*(arg: enum): NimNode = result = newCall( arg.typeof.getTypeInst[1], newLit(int(arg)) ) -proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} -proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} -proc newLit*[T](s: set[T]): NimNode {.compileTime.} -proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} +proc newLit*[N,T](arg: array[N,T]): NimNode +proc newLit*[T](arg: seq[T]): NimNode +proc newLit*[T](s: set[T]): NimNode +proc newLit*[T: tuple](arg: T): NimNode -proc newLit*(arg: object): NimNode {.compileTime.} = +proc newLit*(arg: object): NimNode = result = nnkObjConstr.newTree(arg.typeof.getTypeInst[1]) for a, b in arg.fieldPairs: result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) ) -proc newLit*(arg: ref object): NimNode {.compileTime.} = +proc newLit*(arg: ref object): NimNode = ## produces a new ref type literal node. result = nnkObjConstr.newTree(arg.typeof.getTypeInst[1]) for a, b in fieldPairs(arg[]): result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b)) -proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} = +proc newLit*[N,T](arg: array[N,T]): NimNode = result = nnkBracket.newTree for x in arg: result.add newLit(x) -proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} = +proc newLit*[T](arg: seq[T]): NimNode = let bracket = nnkBracket.newTree for x in arg: bracket.add newLit(x) @@ -812,7 +811,7 @@ proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} = var typ = getTypeInst(typeof(arg))[1] result = newCall(typ,result) -proc newLit*[T](s: set[T]): NimNode {.compileTime.} = +proc newLit*[T](s: set[T]): NimNode = result = nnkCurly.newTree for x in s: result.add newLit(x) @@ -824,7 +823,7 @@ proc newLit*[T](s: set[T]): NimNode {.compileTime.} = proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} ## See `typetraits.isNamedTuple` -proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} = +proc newLit*[T: tuple](arg: T): NimNode = ## use -d:nimHasWorkaround14720 to restore behavior prior to PR, forcing ## a named tuple even when `arg` is unnamed. result = nnkTupleConstr.newTree @@ -835,7 +834,7 @@ proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} = for b in arg.fields: result.add newLit(b) -proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} = +proc nestList*(op: NimNode; pack: NimNode): NimNode = ## Nests the list `pack` into a tree of call expressions: ## `[a, b, c]` is transformed into `op(a, op(c, d))`. ## This is also known as fold expression. @@ -845,7 +844,7 @@ proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} = for i in countdown(pack.len - 2, 0): result = newCall(op, pack[i], result) -proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime.} = +proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode = ## Nests the list `pack` into a tree of call expressions: ## `[a, b, c]` is transformed into `op(a, op(c, d))`. ## This is also known as fold expression. @@ -887,21 +886,21 @@ proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indent if isLisp: res.add(")") -proc treeRepr*(n: NimNode): string {.compileTime, benign.} = +proc treeRepr*(n: NimNode): string {.benign.} = ## Convert the AST `n` to a human-readable tree-like string. ## ## See also `repr`, `lispRepr`, and `astGenRepr`. result = "" n.treeTraverse(result, isLisp = false, indented = true) -proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} = +proc lispRepr*(n: NimNode; indented = false): string {.benign.} = ## Convert the AST `n` to a human-readable lisp-like string. ## ## See also `repr`, `treeRepr`, and `astGenRepr`. result = "" n.treeTraverse(result, isLisp = true, indented = indented) -proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = +proc astGenRepr*(n: NimNode): string {.benign.} = ## Convert the AST `n` to the code required to generate that AST. ## ## See also `repr`, `treeRepr`, and `lispRepr`. @@ -1020,56 +1019,56 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## ## Also see `dumpTree` and `dumpLisp`. -proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} = +proc newEmptyNode*(): NimNode {.noSideEffect.} = ## Create a new empty node. result = newNimNode(nnkEmpty) -proc newStmtList*(stmts: varargs[NimNode]): NimNode {.compileTime.}= +proc newStmtList*(stmts: varargs[NimNode]): NimNode= ## Create a new statement list. result = newNimNode(nnkStmtList).add(stmts) -proc newPar*(exprs: varargs[NimNode]): NimNode {.compileTime.}= +proc newPar*(exprs: varargs[NimNode]): NimNode= ## Create a new parentheses-enclosed expression. newNimNode(nnkPar).add(exprs) -proc newBlockStmt*(label, body: NimNode): NimNode {.compileTime.} = +proc newBlockStmt*(label, body: NimNode): NimNode = ## Create a new block statement with label. return newNimNode(nnkBlockStmt).add(label, body) -proc newBlockStmt*(body: NimNode): NimNode {.compileTime.} = +proc newBlockStmt*(body: NimNode): NimNode = ## Create a new block: stmt. return newNimNode(nnkBlockStmt).add(newEmptyNode(), body) -proc newVarStmt*(name, value: NimNode): NimNode {.compileTime.} = +proc newVarStmt*(name, value: NimNode): NimNode = ## Create a new var stmt. return newNimNode(nnkVarSection).add( newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value)) -proc newLetStmt*(name, value: NimNode): NimNode {.compileTime.} = +proc newLetStmt*(name, value: NimNode): NimNode = ## Create a new let stmt. return newNimNode(nnkLetSection).add( newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value)) -proc newConstStmt*(name, value: NimNode): NimNode {.compileTime.} = +proc newConstStmt*(name, value: NimNode): NimNode = ## Create a new const stmt. newNimNode(nnkConstSection).add( newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value)) -proc newAssignment*(lhs, rhs: NimNode): NimNode {.compileTime.} = +proc newAssignment*(lhs, rhs: NimNode): NimNode = return newNimNode(nnkAsgn).add(lhs, rhs) -proc newDotExpr*(a, b: NimNode): NimNode {.compileTime.} = +proc newDotExpr*(a, b: NimNode): NimNode = ## Create new dot expression. ## a.dot(b) -> `a.b` return newNimNode(nnkDotExpr).add(a, b) -proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} = +proc newColonExpr*(a, b: NimNode): NimNode = ## Create new colon expression. ## newColonExpr(a, b) -> `a: b` newNimNode(nnkExprColonExpr).add(a, b) proc newIdentDefs*(name, kind: NimNode; - default = newEmptyNode()): NimNode {.compileTime.} = + default = newEmptyNode()): NimNode = ## Creates a new `nnkIdentDefs` node of a specific kind and value. ## ## `nnkIdentDefs` need to have at least three children, but they can have @@ -1100,11 +1099,11 @@ proc newIdentDefs*(name, kind: NimNode; ## newStrLitNode("Hello")) newNimNode(nnkIdentDefs).add(name, kind, default) -proc newNilLit*(): NimNode {.compileTime.} = +proc newNilLit*(): NimNode = ## New nil literal shortcut. result = newNimNode(nnkNilLit) -proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1] +proc last*(node: NimNode): NimNode = node[node.len-1] ## Return the last item in nodes children. Same as `node[^1]`. @@ -1115,7 +1114,7 @@ const CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv} -proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} = +proc expectKind*(n: NimNode; k: set[NimNodeKind]) = ## Checks that `n` is of kind `k`. If this is not the case, ## compilation aborts with an error message. This is useful for writing ## macros that check the AST that is passed to them. @@ -1125,7 +1124,7 @@ proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()]; body: NimNode = newStmtList(); procType = nnkProcDef; - pragmas: NimNode = newEmptyNode()): NimNode {.compileTime.} = + pragmas: NimNode = newEmptyNode()): NimNode = ## Shortcut for creating a new proc. ## ## The `params` array must start with the return type of the proc, @@ -1142,8 +1141,7 @@ proc newProc*(name = newEmptyNode(); newEmptyNode(), body) -proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): - NimNode {.compileTime.} = +proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): NimNode = ## Constructor for `if` statements. ## ## .. code-block:: nim @@ -1160,7 +1158,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): result.add(newTree(nnkElifBranch, i.cond, i.body)) proc newEnum*(name: NimNode, fields: openArray[NimNode], - public, pure: bool): NimNode {.compileTime.} = + public, pure: bool): NimNode = ## Creates a new enum. `name` must be an ident. Fields are allowed to be ## either idents or EnumFieldDef @@ -1203,7 +1201,7 @@ proc newEnum*(name: NimNode, fields: openArray[NimNode], return typeSect -proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}= +proc copyChildrenTo*(src, dest: NimNode) = ## Copy all children from `src` to `dest`. for i in 0 ..< src.len: dest.add src[i].copyNimTree @@ -1211,7 +1209,7 @@ proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}= template expectRoutine(node: NimNode) = expectKind(node, RoutineNodes) -proc name*(someProc: NimNode): NimNode {.compileTime.} = +proc name*(someProc: NimNode): NimNode = someProc.expectRoutine result = someProc[0] if result.kind == nnkPostfix: @@ -1222,21 +1220,21 @@ proc name*(someProc: NimNode): NimNode {.compileTime.} = elif result.kind == nnkAccQuoted: result = result[0] -proc `name=`*(someProc: NimNode; val: NimNode) {.compileTime.} = +proc `name=`*(someProc: NimNode; val: NimNode) = someProc.expectRoutine if someProc[0].kind == nnkPostfix: someProc[0][1] = val else: someProc[0] = val -proc params*(someProc: NimNode): NimNode {.compileTime.} = +proc params*(someProc: NimNode): NimNode = someProc.expectRoutine result = someProc[3] -proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}= +proc `params=`* (someProc: NimNode; params: NimNode) = someProc.expectRoutine expectKind(params, nnkFormalParams) someProc[3] = params -proc pragma*(someProc: NimNode): NimNode {.compileTime.} = +proc pragma*(someProc: NimNode): NimNode = ## Get the pragma of a proc type. ## These will be expanded. if someProc.kind == nnkProcTy: @@ -1244,7 +1242,7 @@ proc pragma*(someProc: NimNode): NimNode {.compileTime.} = else: someProc.expectRoutine result = someProc[4] -proc `pragma=`*(someProc: NimNode; val: NimNode) {.compileTime.}= +proc `pragma=`*(someProc: NimNode; val: NimNode) = ## Set the pragma of a proc type. expectKind(val, {nnkEmpty, nnkPragma}) if someProc.kind == nnkProcTy: @@ -1253,7 +1251,7 @@ proc `pragma=`*(someProc: NimNode; val: NimNode) {.compileTime.}= someProc.expectRoutine someProc[4] = val -proc addPragma*(someProc, pragma: NimNode) {.compileTime.} = +proc addPragma*(someProc, pragma: NimNode) = ## Adds pragma to routine definition. someProc.expectKind(RoutineNodes + {nnkProcTy}) var pragmaNode = someProc.pragma @@ -1265,7 +1263,7 @@ proc addPragma*(someProc, pragma: NimNode) {.compileTime.} = template badNodeKind(n, f) = error("Invalid node kind " & $n.kind & " for macros.`" & $f & "`", n) -proc body*(someProc: NimNode): NimNode {.compileTime.} = +proc body*(someProc: NimNode): NimNode = case someProc.kind: of RoutineNodes: return someProc[6] @@ -1276,7 +1274,7 @@ proc body*(someProc: NimNode): NimNode {.compileTime.} = else: badNodeKind someProc, "body" -proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} = +proc `body=`*(someProc: NimNode, val: NimNode) = case someProc.kind of RoutineNodes: someProc[6] = val @@ -1287,7 +1285,7 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} = else: badNodeKind someProc, "body=" -proc basename*(a: NimNode): NimNode {.raises: [].} = +proc basename*(a: NimNode): NimNode = ## Pull an identifier from prefix/postfix expressions. case a.kind of nnkIdent: result = a @@ -1297,7 +1295,7 @@ proc basename*(a: NimNode): NimNode {.raises: [].} = error("Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a), a) -proc `$`*(node: NimNode): string {.compileTime.} = +proc `$`*(node: NimNode): string = ## Get the string of an identifier node. case node.kind of nnkPostfix: @@ -1340,7 +1338,7 @@ template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} = break res -proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} = +proc insert*(a: NimNode; pos: int; b: NimNode) = ## Insert node `b` into node `a` at `pos`. if len(a)-1 < pos: # add some empty nodes first @@ -1355,7 +1353,7 @@ proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} = a[i + 1] = a[i] a[pos] = b -proc `basename=`*(a: NimNode; val: string) {.compileTime.}= +proc `basename=`*(a: NimNode; val: string) = case a.kind of nnkIdent: a.strVal = val @@ -1366,32 +1364,29 @@ proc `basename=`*(a: NimNode; val: string) {.compileTime.}= error("Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a), a) -proc postfix*(node: NimNode; op: string): NimNode {.compileTime.} = +proc postfix*(node: NimNode; op: string): NimNode = newNimNode(nnkPostfix).add(ident(op), node) -proc prefix*(node: NimNode; op: string): NimNode {.compileTime.} = +proc prefix*(node: NimNode; op: string): NimNode = newNimNode(nnkPrefix).add(ident(op), node) proc infix*(a: NimNode; op: string; - b: NimNode): NimNode {.compileTime.} = + b: NimNode): NimNode = newNimNode(nnkInfix).add(ident(op), a, b) -proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {. - compileTime.} = +proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] = node.expectKind nnkPostfix result = (node[1], $node[0]) -proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {. - compileTime.} = +proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] = node.expectKind nnkPrefix result = (node[1], $node[0]) -proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string; - right: NimNode] {.compileTime.} = +proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string; right: NimNode] = expectKind(node, nnkInfix) result = (node[1], $node[0], node[2]) -proc copy*(node: NimNode): NimNode {.compileTime.} = +proc copy*(node: NimNode): NimNode = ## An alias for `copyNimTree<#copyNimTree,NimNode>`_. return node.copyNimTree() @@ -1416,14 +1411,14 @@ proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), ## these nodes will be unwrapped. -proc expectIdent*(n: NimNode, name: string) {.compileTime, since: (1,1).} = +proc expectIdent*(n: NimNode, name: string) {.since: (1,1).} = ## Check that `eqIdent(n,name)` holds true. If this is not the ## case, compilation aborts with an error message. This is useful ## for writing macros that check the AST that is passed to them. if not eqIdent(n, name): error("Expected identifier to be `" & name & "` here", n) -proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}= +proc hasArgOfName*(params: NimNode; name: string): bool= ## Search `nnkFormalParams` for an argument. expectKind(params, nnkFormalParams) for i in 1.. Date: Tue, 23 Mar 2021 15:40:30 +0100 Subject: [PATCH 2255/4254] Fixes #17450 (#17474) * Fixes #17450 * Add missing test output --- compiler/injectdestructors.nim | 1 + tests/arc/tmovebug.nim | 14 ++++++++++++++ tests/destructor/tnewruntime_strutils.nim | 13 ++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b65391252..152efd8a1 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -573,6 +573,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt let tmp = c.getTemp(s.parent[], ret.typ, ret.info) tmp.sym.flags.incl sfSingleUsedTemp let cpy = if hasDestructor(c, ret.typ): + s.parent[].final.add c.genDestroy(tmp) moveOrCopy(tmp, ret, c, s, isDecl = true) else: newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 888027186..3ff1c4a0c 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -107,6 +107,8 @@ sink destroy copy destroy +(f: 1) +destroy ''' """ @@ -770,3 +772,15 @@ proc pair(): tuple[a: C, b: C] = discard pair() + +# bug #17450 +proc noConsume(x: OO) {.nosinks.} = echo x + +proc main3 = + var i = 1 + noConsume: + block: + OO(f: i) + +main3() + diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 8e5378f77..9c8d41973 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -5,7 +5,8 @@ discard """ @[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] 14 First tasks completed. -Second tasks completed.''' +Second tasks completed. +test1''' """ import strutils, os, std / wordwrap @@ -241,3 +242,13 @@ when true: test_string_b.setLen new_len_b echo "Second tasks completed." + +# bug #17450 +proc main = + var i = 1 + echo: + block: + "test" & $i + +main() + From 97f51ed7c2fc67bfba9aef9c4b22a1fb450a5cae Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 23 Mar 2021 15:44:20 +0100 Subject: [PATCH 2256/4254] Revert "Fixes #17450 (#17474)" (#17476) This reverts commit 5f0c52048970cb7449937bd19191638c9e9f0c8f. --- compiler/injectdestructors.nim | 1 - tests/arc/tmovebug.nim | 14 -------------- tests/destructor/tnewruntime_strutils.nim | 13 +------------ 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 152efd8a1..b65391252 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -573,7 +573,6 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt let tmp = c.getTemp(s.parent[], ret.typ, ret.info) tmp.sym.flags.incl sfSingleUsedTemp let cpy = if hasDestructor(c, ret.typ): - s.parent[].final.add c.genDestroy(tmp) moveOrCopy(tmp, ret, c, s, isDecl = true) else: newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 3ff1c4a0c..888027186 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -107,8 +107,6 @@ sink destroy copy destroy -(f: 1) -destroy ''' """ @@ -772,15 +770,3 @@ proc pair(): tuple[a: C, b: C] = discard pair() - -# bug #17450 -proc noConsume(x: OO) {.nosinks.} = echo x - -proc main3 = - var i = 1 - noConsume: - block: - OO(f: i) - -main3() - diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 9c8d41973..8e5378f77 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -5,8 +5,7 @@ discard """ @[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] 14 First tasks completed. -Second tasks completed. -test1''' +Second tasks completed.''' """ import strutils, os, std / wordwrap @@ -242,13 +241,3 @@ when true: test_string_b.setLen new_len_b echo "Second tasks completed." - -# bug #17450 -proc main = - var i = 1 - echo: - block: - "test" & $i - -main() - From 833084b671d1df21bd1a958810fc2a1bd13ae1d6 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 23 Mar 2021 16:30:49 +0100 Subject: [PATCH 2257/4254] Fixes #17450 (#17477) * Fixes #17450 * Add missing test output --- compiler/injectdestructors.nim | 1 + tests/arc/tmovebug.nim | 14 ++++++++++++++ tests/destructor/tnewruntime_strutils.nim | 13 ++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b65391252..152efd8a1 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -573,6 +573,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt let tmp = c.getTemp(s.parent[], ret.typ, ret.info) tmp.sym.flags.incl sfSingleUsedTemp let cpy = if hasDestructor(c, ret.typ): + s.parent[].final.add c.genDestroy(tmp) moveOrCopy(tmp, ret, c, s, isDecl = true) else: newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 888027186..3ff1c4a0c 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -107,6 +107,8 @@ sink destroy copy destroy +(f: 1) +destroy ''' """ @@ -770,3 +772,15 @@ proc pair(): tuple[a: C, b: C] = discard pair() + +# bug #17450 +proc noConsume(x: OO) {.nosinks.} = echo x + +proc main3 = + var i = 1 + noConsume: + block: + OO(f: i) + +main3() + diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 8e5378f77..9c8d41973 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -5,7 +5,8 @@ discard """ @[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] 14 First tasks completed. -Second tasks completed.''' +Second tasks completed. +test1''' """ import strutils, os, std / wordwrap @@ -241,3 +242,13 @@ when true: test_string_b.setLen new_len_b echo "Second tasks completed." + +# bug #17450 +proc main = + var i = 1 + echo: + block: + "test" & $i + +main() + From 368422c219dd11018a8a3265921ddc283666e9e2 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 23 Mar 2021 20:12:27 +0300 Subject: [PATCH 2258/4254] update nimgrep documentation (#17415) * update nimgrep documentation * Update doc/nimgrep_cmdline.txt Co-authored-by: Andreas Rumpf --- doc/nimgrep.rst | 66 ++++++++++++++--------- doc/nimgrep_cmdline.txt | 114 ++++++++++++++++++++++++++++++++++++++++ tools/nimgrep.nim | 101 +---------------------------------- 3 files changed, 157 insertions(+), 124 deletions(-) create mode 100644 doc/nimgrep_cmdline.txt diff --git a/doc/nimgrep.rst b/doc/nimgrep.rst index 5b0fe0dbb..52fc4d62a 100644 --- a/doc/nimgrep.rst +++ b/doc/nimgrep.rst @@ -4,17 +4,20 @@ nimgrep User's manual ========================= +.. default-role:: literal + :Author: Andreas Rumpf -:Version: 0.9 +:Version: 1.6.0 +.. contents:: -Nimgrep is a command line tool for search&replace tasks. It can search for +Nimgrep is a command line tool for search and replace tasks. It can search for regex or peg patterns and can search whole directories at once. User confirmation for every single replace operation can be requested. Nimgrep has particularly good support for Nim's -eccentric *style insensitivity*. Apart from that it is a generic text -manipulation tool. +eccentric *style insensitivity* (see option `-y` below). +Apart from that it is a generic text manipulation tool. Installation @@ -30,23 +33,38 @@ And copy the executable somewhere in your `$PATH`. Command line switches ===================== -Usage: - nimgrep [options] [pattern] [replacement] (file/directory)* -Options: - --find, -f find the pattern (default) - --replace, -r replace the pattern - --peg pattern is a peg - --re pattern is a regular expression (default); extended - syntax for the regular expression is always turned on - --recursive process directories recursively - --confirm confirm each occurrence/replacement; there is a chance - to abort any time without touching the file - --stdin read pattern from stdin (to avoid the shell's confusing - quoting rules) - --word, -w the match should have word boundaries (buggy for pegs!) - --ignoreCase, -i be case insensitive - --ignoreStyle, -y be style insensitive - --ext:EX1|EX2|... only search the files with the given extension(s) - --verbose be verbose: list every processed file - --help, -h shows this help - --version, -v shows the version +.. include:: nimgrep_cmdline.txt + +Examples +======== + +All examples below use default PCRE Regex patterns: + ++ To search recursively in Nim files using style-insensitive identifiers:: + + --recursive --ext:'nim|nims' --ignoreStyle + # short: -r --ext:'nim|nims' -y + + .. Note:: we used `'` quotes to avoid special treatment of `|` symbol + for shells like Bash + ++ To exclude version control directories (Git, Mercurial=hg, Subversion=svn) + from the search:: + + --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$' + # short: --ed:'^\.git$' --ed:'^\.hg$' --ed:'^\.svn$' + ++ To search only in paths containing the `tests` sub-directory recursively:: + + --recursive --includeDir:'(^|/)tests($|/)' + # short: -r --id:'(^|/)tests($|/)' + + .. Attention:: note the subtle difference between `--excludeDir` and + `--includeDir`: the former is applied to relative directory entries + and the latter is applied to the whole paths + ++ Nimgrep can search multi-line, e.g. to find files containing `import` + and then `strutils` use:: + + 'import(.|\n)*?strutils' + diff --git a/doc/nimgrep_cmdline.txt b/doc/nimgrep_cmdline.txt new file mode 100644 index 000000000..bbcbcf530 --- /dev/null +++ b/doc/nimgrep_cmdline.txt @@ -0,0 +1,114 @@ + +Usage: + +* To search:: + nimgrep [options] PATTERN [(FILE/DIRECTORY)*/-] +* To replace:: + nimgrep [options] PATTERN --replace REPLACEMENT (FILE/DIRECTORY)*/- +* To list file names:: + nimgrep [options] --filenames [PATTERN] [(FILE/DIRECTORY)*] + +Positional arguments, from left to right: +1) PATTERN is either Regex (default) or Peg if `--peg` is specified. + PATTERN and REPLACEMENT should be skipped when `--stdin` is specified. +2) REPLACEMENT supports `$1`, `$#` notations for captured groups in PATTERN. + + .. DANGER:: `--replace` mode **DOES NOT** ask confirmation + unless `--confirm` is specified! + +3) Final arguments are a list of paths (FILE/DIRECTORY) or a standalone + minus `-` or not specified (empty): + + * empty, current directory `.` is assumed (not with `--replace`) + + .. Note:: so when no FILE/DIRECTORY/`-` is specified nimgrep + does **not** read the pipe, but searches files in the current + dir instead! + * `-`, read buffer once from stdin: pipe or terminal input; + in `--replace` mode the result is directed to stdout; + it's not compatible with `--stdin`, `--filenames`, or `--confirm` + + + For any given DIRECTORY nimgrep searches only its immediate files without + traversing sub-directories unless `--recursive` is specified. + +In replacement mode we require all 3 positional arguments to avoid damaging. + +Options: +* Mode of operation: + --find, -f find the PATTERN (default) + --replace, -! replace the PATTERN to REPLACEMENT, rewriting the files + --confirm confirm each occurrence/replacement; there is a chance + to abort any time without touching the file + --filenames just list filenames. Provide a PATTERN to find it in + the filenames (not in the contents of a file) or run + with empty pattern to just list all files:: + nimgrep --filenames # In current dir + nimgrep --filenames "" DIRECTORY + # Note empty pattern "", lists all files in DIRECTORY + +* Interprete patterns: + --peg PATTERN and PAT are Peg + --re PATTERN and PAT are regular expressions (default) + --rex, -x use the "extended" syntax for the regular expression + so that whitespace is not significant + --word, -w matches should have word boundaries (buggy for pegs!) + --ignoreCase, -i be case insensitive in PATTERN and PAT + --ignoreStyle, -y be style insensitive in PATTERN and PAT + .. Note:: PATERN and patterns PAT (see below in other options) are all either + Regex or Peg simultaneously and options `--rex`, `--word`, `--ignoreCase`, + and `--ignoreStyle` are applied to all of them. + +* File system walk: + --recursive, -r process directories recursively + --follow follow all symlinks when processing recursively + --ext:EX1|EX2|... only search the files with the given extension(s), + empty one ("--ext") means files with missing extension + --noExt:EX1|... exclude files having given extension(s), use empty one to + skip files with no extension (like some binary files are) + --includeFile:PAT search only files whose names contain pattern PAT + --excludeFile:PAT skip files whose names contain pattern PAT + --includeDir:PAT search only files with their whole directory path + containing PAT + --excludeDir:PAT skip directories whose name (not path) + contain pattern PAT + --if,--ef,--id,--ed abbreviations of the 4 options above + --sortTime, -s[:asc|desc] + order files by the last modification time (default: off): + ascending (recent files go last) or descending + +* Filter file content: + --match:PAT select files containing a (not displayed) match of PAT + --noMatch:PAT select files not containing any match of PAT + --bin:on|off|only process binary files? (detected by \0 in first 1K bytes) + (default: on - binary and text files treated the same way) + --text, -t process only text files, the same as `--bin:off` + +* Represent results: + --nocolor output will be given without any colors + --color[:on] force color even if output is redirected (default: auto) + --colorTheme:THEME select color THEME from `simple` (default), + `bnw` (black and white), `ack`, or `gnu` (GNU grep) + --count only print counts of matches for files that matched + --context:N, -c:N print N lines of leading context before every match and + N lines of trailing context after it (default N: 0) + --afterContext:N, -a:N + print N lines of trailing context after every match + --beforeContext:N, -b:N + print N lines of leading context before every match + --group, -g group matches by file + --newLine, -l display every matching line starting from a new line + --cols[:N] limit max displayed columns/width of output lines from + files by N characters, cropping overflows (default: off) + --cols:auto, -% calculate columns from terminal width for every line + --onlyAscii, -@ display only printable ASCII Latin characters 0x20-0x7E + substitutions: 0 -> ^@, 1 -> ^A, ... 0x1F -> ^_, + 0x7F -> '7F, ..., 0xFF -> 'FF + +* Miscellaneous: + --threads:N, -j:N speed up search by N additional workers (default: 0, off) + --stdin read PATTERN from stdin (to avoid the shell's confusing + quoting rules) and, if `--replace` given, REPLACEMENT + --verbose be verbose: list every processed file + --help, -h shows this help + --version, -v shows the version diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index cb46f30b8..a368c40ef 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -16,106 +16,7 @@ const Version & """ (c) 2012-2020 Andreas Rumpf - -Usage: -* To search: - nimgrep [options] PATTERN [(FILE/DIRECTORY)*/-] -* To replace: - nimgrep [options] PATTERN --replace REPLACEMENT (FILE/DIRECTORY)*/- -* To list file names: - nimgrep [options] --filenames [PATTERN] [(FILE/DIRECTORY)*] - -Positional arguments, from left to right: -* PATERN is either Regex (default) or Peg if --peg is specified. - PATTERN and REPLACEMENT should be skipped when --stdin is specified. -* REPLACEMENT supports $1, $# notations for captured groups in PATTERN. - Note: --replace mode DOES NOT ask confirmation unless --confirm is specified! -* Final arguments are a list of paths (FILE/DIRECTORY) or a standalone - minus '-' (pipe) or not specified (empty). Note for the empty case: when - no FILE/DIRECTORY/- is specified nimgrep DOES NOT read the pipe, but - searches files in the current dir instead! - - read buffer once from stdin: pipe or terminal input; - in --replace mode the result is directed to stdout; - it's not compatible with --stdin, --filenames, --confirm - (empty) current directory '.' is assumed (not with --replace) - For any given DIRECTORY nimgrep searches only its immediate files without - traversing sub-directories unless --recursive is specified. - In replacement mode all 3 positional arguments are required to avoid damaging. - -Options: -* Mode of operation: - --find, -f find the PATTERN (default) - --replace, -! replace the PATTERN to REPLACEMENT, rewriting the files - --confirm confirm each occurrence/replacement; there is a chance - to abort any time without touching the file - --filenames just list filenames. Provide a PATTERN to find it in - the filenames (not in the contents of a file) or run - with empty pattern to just list all files: - nimgrep --filenames # In current directory - nimgrep --filenames "" DIRECTORY # Note empty pattern "" - -* Interprete patterns: - --peg PATTERN and PAT are Peg - --re PATTERN and PAT are regular expressions (default) - --rex, -x use the "extended" syntax for the regular expression - so that whitespace is not significant - --word, -w matches should have word boundaries (buggy for pegs!) - --ignoreCase, -i be case insensitive in PATTERN and PAT - --ignoreStyle, -y be style insensitive in PATTERN and PAT - NOTE: PATERN and patterns PAT (see below in other options) are all either - Regex or Peg simultaneously and options --rex, --word, --ignoreCase, - --ignoreStyle are applied to all of them. - -* File system walk: - --recursive, -r process directories recursively - --follow follow all symlinks when processing recursively - --ext:EX1|EX2|... only search the files with the given extension(s), - empty one ("--ext") means files with missing extension - --noExt:EX1|... exclude files having given extension(s), use empty one to - skip files with no extension (like some binary files are) - --includeFile:PAT search only files whose names contain pattern PAT - --excludeFile:PAT skip files whose names contain pattern PAT - --includeDir:PAT search only files with whole directory path containing PAT - --excludeDir:PAT skip directories whose name (not path) contain pattern PAT - --if,--ef,--id,--ed abbreviations of 4 options above - --sortTime order files by the last modification time (default: off): - -s[:asc|desc] ascending (recent files go last) or descending - -* Filter file content: - --match:PAT select files containing a (not displayed) match of PAT - --noMatch:PAT select files not containing any match of PAT - --bin:on|off|only process binary files? (detected by \0 in first 1K bytes) - (default: on - binary and text files treated the same way) - --text, -t process only text files, the same as --bin:off - -* Represent results: - --nocolor output will be given without any colors - --color[:on] force color even if output is redirected (default: auto) - --colorTheme:THEME select color THEME from 'simple' (default), - 'bnw' (black and white) ,'ack', or 'gnu' (GNU grep) - --count only print counts of matches for files that matched - --context:N, -c:N print N lines of leading context before every match and - N lines of trailing context after it (default N: 0) - --afterContext:N, - -a:N print N lines of trailing context after every match - --beforeContext:N, - -b:N print N lines of leading context before every match - --group, -g group matches by file - --newLine, -l display every matching line starting from a new line - --cols[:N] limit max displayed columns/width of output lines from - files by N characters, cropping overflows (default: off) - --cols:auto, -% calculate columns from terminal width for every line - --onlyAscii, -@ display only printable ASCII Latin characters 0x20-0x7E - substitutions: 0 -> ^@, 1 -> ^A, ... 0x1F -> ^_, - 0x7F -> '7F, ..., 0xFF -> 'FF -* Miscellaneous: - --threads:N, -j:N speed up search by N additional workers (default: 0, off) - --stdin read PATTERN from stdin (to avoid the shell's confusing - quoting rules) and, if --replace given, REPLACEMENT - --verbose be verbose: list every processed file - --help, -h shows this help - --version, -v shows the version -""" +""" & slurp "../doc/nimgrep_cmdline.txt" # Limitations / ideas / TODO: # * No unicode support with --cols From 28221e8a33e111d8653c4ff21fad47a7ec6ef54d Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 24 Mar 2021 03:18:36 +0800 Subject: [PATCH 2259/4254] followup #16182 (#17472) * fix nim js cmp fails at CT * followup #16182 --- lib/pure/algorithm.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 0410d65ee..f4b3f46be 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -336,12 +336,12 @@ template `<-`(a, b) = else: copyMem(addr(a), addr(b), sizeof(T)) -proc merge[T](a, b: var openArray[T], lo, m, hi: int, +proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int, cmp: proc (x, y: T): int {.closure.}, order: SortOrder) = # Optimization: If max(left) <= min(right) there is nothing to do! # 1 2 3 4 ## 5 6 7 8 # -> O(n) for sorted arrays. - # On random data this saves up to 40% of merge calls. + # On random data this saves up to 40% of mergeAlt calls. if cmp(a[m], a[m+1]) * order <= 0: return var j = lo # copy a[j..m] into b: @@ -424,7 +424,7 @@ func sort*[T](a: var openArray[T], while s < n: var m = n-1-s while m >= 0: - merge(a, b, max(m-s+1, 0), m, m+s, cmp, order) + mergeAlt(a, b, max(m-s+1, 0), m, m+s, cmp, order) dec(m, s*2) s = s*2 From dbde97f649b0a4d947e15eddfacbde761cd49885 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 23 Mar 2021 23:46:19 +0100 Subject: [PATCH 2260/4254] fixes #16076 (#17486) --- compiler/semfold.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index a3b9a8dde..0d4f6a0bd 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -685,7 +685,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkDerefExpr, nkHiddenDeref: let a = getConstExpr(m, n[0], idgen, g) if a != nil and a.kind == nkNilLit: - localError(g.config, n.info, "nil dereference is not allowed") + result = nil + #localError(g.config, n.info, "nil dereference is not allowed") of nkCast: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return From 8ccde68f132be4dba330eb6ec50f4679e564efac Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 24 Mar 2021 01:01:31 +0100 Subject: [PATCH 2261/4254] closes #17085; boehm has problems with large allocations, that is expected and we don't care (#17487) --- testament/categories.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/categories.nim b/testament/categories.nim index acb3ee0a8..86aa1f8af 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -173,7 +173,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "stackrefleak" test "cyclecollector" - test "trace_globals" + testWithoutBoehm "trace_globals" proc longGCTests(r: var TResults, cat: Category, options: string) = when defined(windows): From c015ecdc37221b374647b3b1503d80519e253d94 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 24 Mar 2021 15:16:41 +0800 Subject: [PATCH 2262/4254] fix #17490 (#17491) --- lib/pure/json.nim | 14 ++++++++++---- tests/stdlib/tjson.nim | 11 +++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 048ed2797..833403d68 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -927,7 +927,7 @@ when defined(js): proc parseNativeJson(x: cstring): JSObject {.importjs: "JSON.parse(#)".} - proc getVarType(x: JSObject): JsonNodeKind = + proc getVarType(x: JSObject, isRawNumber: var bool): JsonNodeKind = result = JNull case $getProtoName(x) # TODO: Implicit returns fail here. of "[object Array]": return JArray @@ -937,6 +937,7 @@ when defined(js): if isSafeInteger(x): return JInt else: + isRawNumber = true return JString else: return JFloat @@ -946,13 +947,13 @@ when defined(js): else: assert false proc len(x: JSObject): int = - assert x.getVarType == JArray asm """ `result` = `x`.length; """ proc convertObject(x: JSObject): JsonNode = - case getVarType(x) + var isRawNumber = false + case getVarType(x, isRawNumber) of JArray: result = newJArray() for i in 0 ..< x.len: @@ -973,7 +974,12 @@ when defined(js): result = newJFloat(x.to(float)) of JString: # Dunno what to do with isUnquoted here - result = newJString($x.to(cstring)) + if isRawNumber: + var value: cstring + {.emit: "`value` = `x`.toString();".} + result = newJRawNumber($value) + else: + result = newJString($x.to(cstring)) of JBool: result = newJBool(x.to(bool)) of JNull: diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index ceb9efb0e..e538baf4f 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -300,3 +300,14 @@ block: # bug #17383 when not defined(js): testRoundtrip(int64.high): "9223372036854775807" testRoundtrip(uint64.high): "18446744073709551615" + + +block: + let a = "18446744073709551615" + let b = a.parseJson + doAssert b.kind == JString + let c = $b + when defined(js): + doAssert c == "18446744073709552000" + else: + doAssert c == "18446744073709551615" From 13a203001434db8f6cc9e4deab10dbfc7f57bd94 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 24 Mar 2021 15:49:05 +0800 Subject: [PATCH 2263/4254] follow up #17486 (#17492) * fix nim js cmp fails at CT * follow up #17486 * test more branches * better --- tests/iter/t16076.nim | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/iter/t16076.nim diff --git a/tests/iter/t16076.nim b/tests/iter/t16076.nim new file mode 100644 index 000000000..2eb409068 --- /dev/null +++ b/tests/iter/t16076.nim @@ -0,0 +1,45 @@ +discard """ + targets: "c js" +""" + +proc main() = + block: # bug #17485 + type + O = ref object + i: int + + iterator t(o: O): int = + if o != nil: + yield o.i + yield 0 + + proc m = + var data = "" + for i in t(nil): + data.addInt i + + doAssert data == "0" + + m() + + + block: # bug #16076 + type + R = ref object + z: int + + var data = "" + + iterator foo(x: int; y: R = nil): int {.inline.} = + if y == nil: + yield x + else: + yield y.z + + for b in foo(10): + data.addInt b + + doAssert data == "10" + +static: main() +main() From 465a41c3083668c37f4bbee1f00fd709d7f35298 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 24 Mar 2021 16:44:24 +0800 Subject: [PATCH 2264/4254] [isolation]fix empty ref object bug (#17471) * fix nim js cmp fails at CT * [Minor]fix empty ref object for isolation * Update compiler/isolation_check.nim * Update compiler/isolation_check.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- compiler/isolation_check.nim | 8 ++++++-- tests/stdlib/tisolation.nim | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 01f0a002a..9c8ca58b4 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -100,7 +100,12 @@ proc checkIsolate*(n: PNode): bool = for it in n: result = checkIsolate(it.lastSon) if not result: break - of nkCaseStmt, nkObjConstr: + of nkCaseStmt: + for i in 1.. Date: Wed, 24 Mar 2021 09:47:11 +0100 Subject: [PATCH 2265/4254] make unary minus part of number literals, refs #17020 (#17488) * make unary minus part of number literals, refs #17020 * fixes regression --- changelog.md | 4 +- compiler/lexer.nim | 87 +++++++++++++++++++++++------------- compiler/semtypes.nim | 2 +- doc/manual.rst | 43 +++++++++++++++--- tests/lexer/tunary_minus.nim | 76 +++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 39 deletions(-) create mode 100644 tests/lexer/tunary_minus.nim diff --git a/changelog.md b/changelog.md index 78817cf85..c0cd97024 100644 --- a/changelog.md +++ b/changelog.md @@ -212,7 +212,7 @@ - `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` and `$none(int)` to `"none(int)"` instead of `"None[int]"`. - + - Added `algorithm.merge`. @@ -263,6 +263,8 @@ - `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages. +- The unary minus in `-1` is now part of the integer literal, it is now parsed as a single token. + This implies that edge cases like `-128'i8` finally work correctly. ## Compiler changes diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 729ba3435..bcd3f0076 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -26,6 +26,7 @@ const SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', '|', '=', '%', '&', '$', '@', '~', ':'} + UnaryMinusWhitelist = {' ', '\t', '\n', '\r', ',', ';', '(', '[', '{'} # don't forget to update the 'highlite' module if these charsets should change @@ -51,22 +52,22 @@ type tkVar = "var", tkWhen = "when", tkWhile = "while", tkXor = "xor", tkYield = "yield", # end of keywords - tkIntLit = "tkIntLit", tkInt8Lit = "tkInt8Lit", tkInt16Lit = "tkInt16Lit", + tkIntLit = "tkIntLit", tkInt8Lit = "tkInt8Lit", tkInt16Lit = "tkInt16Lit", tkInt32Lit = "tkInt32Lit", tkInt64Lit = "tkInt64Lit", - tkUIntLit = "tkUIntLit", tkUInt8Lit = "tkUInt8Lit", tkUInt16Lit = "tkUInt16Lit", + tkUIntLit = "tkUIntLit", tkUInt8Lit = "tkUInt8Lit", tkUInt16Lit = "tkUInt16Lit", tkUInt32Lit = "tkUInt32Lit", tkUInt64Lit = "tkUInt64Lit", tkFloatLit = "tkFloatLit", tkFloat32Lit = "tkFloat32Lit", tkFloat64Lit = "tkFloat64Lit", tkFloat128Lit = "tkFloat128Lit", tkStrLit = "tkStrLit", tkRStrLit = "tkRStrLit", tkTripleStrLit = "tkTripleStrLit", - tkGStrLit = "tkGStrLit", tkGTripleStrLit = "tkGTripleStrLit", tkCharLit = "tkCharLit", - + tkGStrLit = "tkGStrLit", tkGTripleStrLit = "tkGTripleStrLit", tkCharLit = "tkCharLit", + tkParLe = "(", tkParRi = ")", tkBracketLe = "[", tkBracketRi = "]", tkCurlyLe = "{", tkCurlyRi = "}", tkBracketDotLe = "[.", tkBracketDotRi = ".]", tkCurlyDotLe = "{.", tkCurlyDotRi = ".}", tkParDotLe = "(.", tkParDotRi = ".)", tkComma = ",", tkSemiColon = ";", - tkColon = ":", tkColonColon = "::", tkEquals = "=", + tkColon = ":", tkColonColon = "::", tkEquals = "=", tkDot = ".", tkDotDot = "..", tkBracketLeColon = "[:", tkOpr, tkComment, tkAccent = "`", # these are fake tokens used by renderer.nim @@ -348,6 +349,14 @@ proc getNumber(L: var Lexer, result: var Token) = startpos = L.bufpos tokenBegin(result, startpos) + var isPositive = true + if L.buf[L.bufpos] == '-': + eatChar(L, result) + isPositive = true + + template setNumber(field, value) = + field = (if isPositive: value else: -value) + # First stage: find out base, make verifications, build token literal string # {'c', 'C'} is added for deprecation reasons to provide a clear error message if L.buf[L.bufpos] == '0' and L.buf[L.bufpos + 1] in baseCodeChars + {'c', 'C', 'O'}: @@ -459,7 +468,7 @@ proc getNumber(L: var Lexer, result: var Token) = # Third stage, extract actual number L.bufpos = startpos # restore position - var pos: int = startpos + var pos = startpos try: if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars): inc(pos, 2) @@ -500,20 +509,20 @@ proc getNumber(L: var Lexer, result: var Token) = internalError(L.config, getLineInfo(L), "getNumber") case result.tokType - of tkIntLit, tkInt64Lit: result.iNumber = xi - of tkInt8Lit: result.iNumber = ashr(xi shl 56, 56) - of tkInt16Lit: result.iNumber = ashr(xi shl 48, 48) - of tkInt32Lit: result.iNumber = ashr(xi shl 32, 32) - of tkUIntLit, tkUInt64Lit: result.iNumber = xi - of tkUInt8Lit: result.iNumber = xi and 0xff - of tkUInt16Lit: result.iNumber = xi and 0xffff - of tkUInt32Lit: result.iNumber = xi and 0xffffffff + of tkIntLit, tkInt64Lit: setNumber result.iNumber, xi + of tkInt8Lit: setNumber result.iNumber, ashr(xi shl 56, 56) + of tkInt16Lit: setNumber result.iNumber, ashr(xi shl 48, 48) + of tkInt32Lit: setNumber result.iNumber, ashr(xi shl 32, 32) + of tkUIntLit, tkUInt64Lit: setNumber result.iNumber, xi + of tkUInt8Lit: setNumber result.iNumber, xi and 0xff + of tkUInt16Lit: setNumber result.iNumber, xi and 0xffff + of tkUInt32Lit: setNumber result.iNumber, xi and 0xffffffff of tkFloat32Lit: - result.fNumber = (cast[PFloat32](addr(xi)))[] + setNumber result.fNumber, (cast[PFloat32](addr(xi)))[] # note: this code is endian neutral! # XXX: Test this on big endian machine! of tkFloat64Lit, tkFloatLit: - result.fNumber = (cast[PFloat64](addr(xi)))[] + setNumber result.fNumber, (cast[PFloat64](addr(xi)))[] else: internalError(L.config, getLineInfo(L), "getNumber") # Bounds checks. Non decimal literals are allowed to overflow the range of @@ -521,12 +530,13 @@ proc getNumber(L: var Lexer, result: var Token) = # below checks of signed sizes against uint*.high is deliberate: # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK) if result.tokType notin floatTypes: - let outOfRange = case result.tokType: - of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi - of tkInt8Lit: (xi > BiggestInt(uint8.high)) - of tkInt16Lit: (xi > BiggestInt(uint16.high)) - of tkInt32Lit: (xi > BiggestInt(uint32.high)) - else: false + let outOfRange = + case result.tokType + of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi + of tkInt8Lit: (xi > BiggestInt(uint8.high)) + of tkInt16Lit: (xi > BiggestInt(uint16.high)) + of tkInt32Lit: (xi > BiggestInt(uint32.high)) + else: false if outOfRange: #echo "out of range num: ", result.iNumber, " vs ", xi @@ -557,23 +567,23 @@ proc getNumber(L: var Lexer, result: var Token) = raise newException(ValueError, "invalid integer: " & $result.literal) result.iNumber = iNumber - # Explicit bounds checks. Only T.high needs to be considered - # since result.iNumber can't be negative. + # Explicit bounds checks. let outOfRange = case result.tokType - of tkInt8Lit: result.iNumber > int8.high - of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high) - of tkInt16Lit: result.iNumber > int16.high - of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high) - of tkInt32Lit: result.iNumber > int32.high - of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high) + of tkInt8Lit: result.iNumber > int8.high or result.iNumber < int8.low + of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high) or result.iNumber < 0 + of tkInt16Lit: result.iNumber > int16.high or result.iNumber < int16.low + of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high) or result.iNumber < 0 + of tkInt32Lit: result.iNumber > int32.high or result.iNumber < int32.low + of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high) or result.iNumber < 0 else: false - if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos) + if outOfRange: + lexMessageLitNum(L, "number out of range: '$1'", startpos) # Promote int literal to int64? Not always necessary, but more consistent if result.tokType == tkIntLit: - if result.iNumber > high(int32): + if result.iNumber > high(int32) or result.iNumber < low(int32): result.tokType = tkInt64Lit except ValueError: @@ -1278,6 +1288,19 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = let c = L.buf[L.bufpos] if c in SymChars+{'_'}: lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") + of '-': + if L.buf[L.bufpos+1] in {'0'..'9'} and + (L.bufpos-1 == 0 or L.buf[L.bufpos-1] in UnaryMinusWhitelist): + # x)-23 # binary minus + # ,-23 # unary minus + # \n-78 # unary minus? Yes. + # =-3 # parsed as `=-` anyway + getNumber(L, tok) + let c = L.buf[L.bufpos] + if c in SymChars+{'_'}: + lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") + else: + getOperator(L, tok) else: if c in OpChars: getOperator(L, tok) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index dcab9a884..0fce7b417 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -299,7 +299,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType = result = makeRangeWithStaticExpr(c, e.typ.n) elif e.kind in {nkIntLit..nkUInt64Lit}: if e.intVal < 0: - localError(c.config, n[1].info, + localError(c.config, n.info, "Array length can't be negative, but was " & $e.intVal) result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) elif e.kind == nkSym and e.typ.kind == tyStatic: diff --git a/doc/manual.rst b/doc/manual.rst index 1bb47f28b..db1251630 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -499,10 +499,11 @@ Numerical constants are of a single type and have the form:: hexdigit = digit | 'A'..'F' | 'a'..'f' octdigit = '0'..'7' bindigit = '0'..'1' - HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* - DEC_LIT = digit ( ['_'] digit )* - OCT_LIT = '0' 'o' octdigit ( ['_'] octdigit )* - BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* + unary_minus = '-' # See the section about unary minus + HEX_LIT = unary_minus? '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* + DEC_LIT = unary_minus? digit ( ['_'] digit )* + OCT_LIT = unary_minus? '0' 'o' octdigit ( ['_'] octdigit )* + BIN_LIT = unary_minus? '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* INT_LIT = HEX_LIT | DEC_LIT @@ -521,7 +522,7 @@ Numerical constants are of a single type and have the form:: UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64' exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* - FLOAT_LIT = digit (['_'] digit)* (('.' digit (['_'] digit)* [exponent]) |exponent) + FLOAT_LIT = unary_minus? digit (['_'] digit)* (('.' digit (['_'] digit)* [exponent]) |exponent) FLOAT32_SUFFIX = ('f' | 'F') ['32'] FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX @@ -535,6 +536,38 @@ for readability. Integer and floating-point literals may be given in decimal (no prefix), binary (prefix `0b`), octal (prefix `0o`), and hexadecimal (prefix `0x`) notation. +The fact that the unary minus `-` in a number literal like `-1` is considered +to be part of the literal is a late addition to the language. The rationale is that +an expression `-128'i8` should be valid and without this special case, this would +be impossible -- `128` is not a valid `int8` value, only `-128` is. + +For the `unary_minus` rule there are further restrictions that are not covered +in the formal grammar. For `-` to be part of the number literal its immediately +preceeding character has to be in the +set `{' ', '\t', '\n', '\r', ',', ';', '(', '[', '{'}`. This set was designed to +cover most cases in a natural manner. + +In the following examples, `-1` is a single token: + +.. code-block:: nim + + echo -1 + echo(-1) + echo [-1] + echo 3,-1 + + "abc";-1 + +In the following examples, `-1` is parsed as two separate tokens (as `- 1`): + +.. code-block:: nim + + echo x-1 + echo (int)-1 + echo [a]-1 + "abc"-1 + + There exists a literal for each numerical type that is defined. The suffix starting with an apostrophe ('\'') is called a `type suffix`:idx:. Literals without a type suffix are of an integer type diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim new file mode 100644 index 000000000..89f1b79ef --- /dev/null +++ b/tests/lexer/tunary_minus.nim @@ -0,0 +1,76 @@ +discard """ + targets: "c cpp js" +""" + +# Test numeric literals and handling of minus symbol + +import std/[macros, strutils] + +macro lispReprStr*(a: untyped): untyped = newLit(a.lispRepr) + +macro assertAST*(expected: string, struct: untyped): untyped = + var ast = newLit(struct.treeRepr) + result = quote do: + if `ast` != `expected`: + doAssert false, "\nGot:\n" & `ast`.indent(2) & "\nExpected:\n" & `expected`.indent(2) + +const one = 1 +const minusOne = `-`(one) + +# border cases that *should* generate compiler errors: +assertAST dedent """ + StmtList + Asgn + Ident "x" + Command + IntLit 4 + IntLit -1""": + x = 4 -1 +assertAST dedent """ + StmtList + VarSection + IdentDefs + Ident "x" + Ident "uint" + IntLit -1""": + var x: uint = -1 +template bad() = + x = 4 -1 +doAssert not compiles(bad()) + +template main = + block: # check when a minus (-) is a negative sign for a literal + doAssert -1 == minusOne: + "unable to parse a spaced-prefixed negative int" + doAssert lispReprStr(-1) == """(IntLit -1)""" + doAssert -1.0'f64 == minusOne.float64 + doAssert lispReprStr(-1.000'f64) == """(Float64Lit -1.0)""" + doAssert lispReprStr( -1.000'f64) == """(Float64Lit -1.0)""" + doAssert [-1].contains(minusOne): + "unable to handle negatives after square bracket" + doAssert lispReprStr([-1]) == """(Bracket (IntLit -1))""" + doAssert (-1, 2)[0] == minusOne: + "unable to handle negatives after parenthesis" + doAssert lispReprStr((-1, 2)) == """(Par (IntLit -1) (IntLit 2))""" + proc x(): int = + var a = 1;-1 # the -1 should act as the return value + doAssert x() == minusOne: + "unable to handle negatives after semi-colon" + + block: # check when a minus (-) is an unary op + doAssert -one == minusOne: + "unable to a negative prior to identifier" + + block: # check when a minus (-) is a a subtraction op + doAssert 4-1 == 3: + "unable to handle subtraction sans surrounding spaces with a numeric literal" + doAssert 4-one == 3: + "unable to handle subtraction sans surrounding spaces with an identifier" + doAssert 4 - 1 == 3: + "unable to handle subtraction with surrounding spaces with a numeric literal" + doAssert 4 - one == 3: + "unable to handle subtraction with surrounding spaces with an identifier" + + +static: main() +main() From e94aec20da354d4d3bb6db6e4b840549aa0e7bf1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 24 Mar 2021 02:36:15 -0700 Subject: [PATCH 2266/4254] fix #17325 linux 32bit CI; fix #17085 flaky test (#17469) --- azure-pipelines.yml | 10 +++++----- lib/pure/json.nim | 7 ++++--- tests/gc/trace_globals.nim | 13 ++++++++++++- tests/stdlib/tjsonutils.nim | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f65f8ca11..9006cf6e5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,11 +17,11 @@ jobs: Linux_amd64: vmImage: 'ubuntu-16.04' CPU: amd64 - # Linux_i386: - # # bug #17325: fails on 'ubuntu-16.04' because it now errors with: - # # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed - # vmImage: 'ubuntu-18.04' - # CPU: i386 + Linux_i386: + # bug #17325: fails on 'ubuntu-16.04' because it now errors with: + # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed + vmImage: 'ubuntu-18.04' + CPU: i386 OSX_amd64: vmImage: 'macOS-10.15' CPU: amd64 diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 833403d68..7ee5be9c5 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1075,12 +1075,13 @@ when defined(nimFixedForwardGeneric): dst = jsonNode.copy proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - when T is uint|uint64: + when T is uint|uint64 or (not defined(js) and int.sizeof == 4): + verifyJsonKind(jsonNode, {JInt, JString}, jsonPath) case jsonNode.kind of JString: - dst = T(parseBiggestUInt(jsonNode.str)) + let x = parseBiggestUInt(jsonNode.str) + dst = cast[T](x) else: - verifyJsonKind(jsonNode, {JInt}, jsonPath) dst = T(jsonNode.num) else: verifyJsonKind(jsonNode, {JInt}, jsonPath) diff --git a/tests/gc/trace_globals.nim b/tests/gc/trace_globals.nim index d91bc5f35..f62a15692 100644 --- a/tests/gc/trace_globals.nim +++ b/tests/gc/trace_globals.nim @@ -1,11 +1,20 @@ discard """ - output: '''10000000 + output: ''' +10000000 10000000 10000000''' """ # bug #17085 +#[ +refs https://github.com/nim-lang/Nim/issues/17085#issuecomment-786466595 +with --gc:boehm, this warning sometimes gets generated: +Warning: Repeated allocation of very large block (appr. size 14880768): +May lead to memory leak and poor performance. +nim CI now runs this test with `testWithoutBoehm` to avoid running it with --gc:boehm. +]# + proc init(): string = for a in 0..<10000000: result.add 'c' @@ -16,6 +25,8 @@ proc f() = var c {.global.} = init() echo a.len + # `echo` intentional according to + # https://github.com/nim-lang/Nim/pull/17469/files/0c9e94cb6b9ebca9da7cb19a063fba7aa409748e#r600016573 echo b.len echo c.len diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 5cd975cab..63bf97704 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -71,7 +71,7 @@ template fn() = block: let a = (int32.high, uint32.high) testRoundtrip(a): "[2147483647,4294967295]" - when not defined(js): + when int.sizeof > 4: block: let a = (int64.high, uint64.high) testRoundtrip(a): "[9223372036854775807,18446744073709551615]" From 1590d145757416788e99023ab50c5afae6f8ea36 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 24 Mar 2021 02:58:29 -0700 Subject: [PATCH 2267/4254] fix #17260 render `\` properly in nim doc, rst2html (#17315) --- lib/packages/docutils/rst.nim | 21 ++++++++++++++++----- lib/system.nim | 4 ++-- nimdoc/rst2html/expected/rst_examples.html | 2 +- tests/stdlib/trstgen.nim | 22 ++++++++++++++++++++-- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index b5eef7610..11768c7da 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -852,6 +852,9 @@ proc isInlineMarkupEnd(p: RstParser, markup: string): bool = if not result: return # Rule 4: if p.idx > 0: + # see bug #17260; for now `\` must be written ``\``, likewise with sequences + # ending in an un-escaped `\`; `\\` is legal but not `\\\` for example; + # for this reason we can't use `["``", "`"]` here. if markup != "``" and prevTok(p).symbol == "\\": result = false @@ -1089,11 +1092,19 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, if isInlineMarkupEnd(p, postfix): inc p.idx break - elif interpretBackslash: - parseBackslash(p, father) else: - father.add(newLeaf(p)) - inc p.idx + if postfix == "`": + if prevTok(p).symbol == "\\" and currentTok(p).symbol == "`": + father.sons[^1] = newLeaf(p) # instead, we should use lookahead + else: + father.add(newLeaf(p)) + inc p.idx + else: + if interpretBackslash: + parseBackslash(p, father) + else: + father.add(newLeaf(p)) + inc p.idx of tkAdornment, tkWord, tkOther: father.add(newLeaf(p)) inc p.idx @@ -1243,7 +1254,7 @@ proc parseInline(p: var RstParser, father: PRstNode) = father.add(n) elif isInlineMarkupStart(p, "`"): var n = newRstNode(rnInterpretedText) - parseUntil(p, n, "`", true) + parseUntil(p, n, "`", false) # bug #17260 n = parsePostfix(p, n) father.add(n) elif isInlineMarkupStart(p, "|"): diff --git a/lib/system.nim b/lib/system.nim index 574043125..4c31f20a2 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2827,7 +2827,7 @@ when declared(initDebugger): proc addEscapedChar*(s: var string, c: char) {.noSideEffect, inline.} = ## Adds a char to string `s` and applies the following escaping: ## - ## * replaces any `\` by `\\` + ## * replaces any ``\`` by `\\` ## * replaces any `'` by `\'` ## * replaces any `"` by `\"` ## * replaces any `\a` by `\\a` @@ -2838,7 +2838,7 @@ proc addEscapedChar*(s: var string, c: char) {.noSideEffect, inline.} = ## * replaces any `\f` by `\\f` ## * replaces any `\r` by `\\r` ## * replaces any `\e` by `\\e` - ## * replaces any other character not in the set `{'\21..'\126'} + ## * replaces any other character not in the set `{\21..\126}` ## by `\xHH` where `HH` is its hexadecimal value. ## ## The procedure has been designed so that its output is usable for many diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 23d192009..8253289a4 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -300,7 +300,7 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements

                                      However, this does not work. The problem is that the procedure should not only return, but return and continue after an iteration has finished. This return and continue is called a yield statement. Now the only thing left to do is to replace the proc keyword by iterator and here it is - our first iterator:

                                      - +
                                      A1 headerA2 | not fooled
                                      C1C2 bold
                                      D1 code |D2
                                      D1 code \|D2
                                      E1 | text
                                      F2 without pipe

                                      not in table

                                      diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index cf82cdf91..d6055cc11 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -196,9 +196,15 @@ suite "RST/Markdown general": | | F2 without pipe not in table""" let output1 = input1.toHtml - doAssert output1 == """ + #[ + TODO: `\|` inside a table cell should render as `|` + `|` outside a table cell should render as `\|` + consistently with markdown, see https://stackoverflow.com/a/66557930/1426932 + ]# + doAssert output1 == """ +
                                      A1 headerA2 | not fooled
                                      - +
                                      A1 headerA2 | not fooled
                                      C1C2 bold
                                      D1 code |D2
                                      D1 code \|D2
                                      E1 | text
                                      F2 without pipe

                                      not in table

                                      @@ -549,6 +555,18 @@ let x = 1 let output2 = input2.toHtml doAssert "foo.bar""" + check """`foo\`\`bar`""".toHtml == """foo``bar""" + check """`foo\`bar`""".toHtml == """foo`bar""" + check """`\`bar`""".toHtml == """`bar""" + check """`a\b\x\\ar`""".toHtml == """a\b\x\\ar""" + + test "inline literal": + check """``foo.bar``""".toHtml == """foo.bar""" + check """``foo\bar``""".toHtml == """foo\bar""" + check """``f\`o\\o\b`ar``""".toHtml == """f\`o\\o\b`ar""" + test "RST comments": let input1 = """ Check that comment disappears: From 7366a3da37605b230823dd4b6db07abb70dbd40b Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Wed, 24 Mar 2021 03:55:58 -0700 Subject: [PATCH 2268/4254] potential fix for semgeneric formal params (#17494) marked locations where analysis of return formal param is done prior to args. This might fix some subtle bugs. --- compiler/isolation_check.nim | 3 +++ compiler/reorder.nim | 1 + compiler/semgnrc.nim | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 9c8ca58b4..43db5d59b 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -85,6 +85,9 @@ proc checkIsolate*(n: PNode): bool = of nkCharLit..nkNilLit: result = true of nkCallKinds: + # XXX: as long as we don't update the analysis while examining arguments + # we can do an early check of the return type, otherwise this is a + # bug and needs to be moved below if n[0].typ.flags * {tfGcSafe, tfNoSideEffect} == {}: return false for i in 1.. Date: Wed, 24 Mar 2021 14:46:19 +0100 Subject: [PATCH 2269/4254] custom integer literals (#17489) * user defined integer literals; refs #17020 * updated renderer.nim * use mlexerutils helper * imported all test cases from https://github.com/nim-lang/Nim/pull/17020 * final grammar updated --- changelog.md | 2 + compiler/docgen.nim | 2 +- compiler/lexer.nim | 342 +++++++++++------------ compiler/parser.nim | 18 +- compiler/renderer.nim | 18 +- compiler/semstmts.nim | 2 +- doc/grammar.txt | 3 +- doc/manual.rst | 54 +++- tests/lexer/mlexerutils.nim | 9 + tests/lexer/tcustom_numeric_literals.nim | 150 ++++++++++ tests/lexer/tstrlits.nim | 19 -- tests/lexer/tunary_minus.nim | 8 +- 12 files changed, 409 insertions(+), 218 deletions(-) create mode 100644 tests/lexer/mlexerutils.nim create mode 100644 tests/lexer/tcustom_numeric_literals.nim delete mode 100644 tests/lexer/tstrlits.nim diff --git a/changelog.md b/changelog.md index c0cd97024..922b8470a 100644 --- a/changelog.md +++ b/changelog.md @@ -266,6 +266,8 @@ - The unary minus in `-1` is now part of the integer literal, it is now parsed as a single token. This implies that edge cases like `-128'i8` finally work correctly. +- Custom numeric literals are now supported. + ## Compiler changes diff --git a/compiler/docgen.nim b/compiler/docgen.nim index dded231d7..b24a24a2b 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -416,7 +416,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe of tkOpr: dispA(d.conf, result, "$1", "\\spanOperator{$1}", [escLit]) - of tkStrLit..tkTripleStrLit: + of tkStrLit..tkTripleStrLit, tkCustomLit: dispA(d.conf, result, "$1", "\\spanStringLit{$1}", [escLit]) of tkCharLit: diff --git a/compiler/lexer.nim b/compiler/lexer.nim index bcd3f0076..b34b010c2 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -60,6 +60,7 @@ type tkFloat64Lit = "tkFloat64Lit", tkFloat128Lit = "tkFloat128Lit", tkStrLit = "tkStrLit", tkRStrLit = "tkRStrLit", tkTripleStrLit = "tkTripleStrLit", tkGStrLit = "tkGStrLit", tkGTripleStrLit = "tkGTripleStrLit", tkCharLit = "tkCharLit", + tkCustomLit = "tkCustomLit", tkParLe = "(", tkParRi = ")", tkBracketLe = "[", tkBracketRi = "]", tkCurlyLe = "{", tkCurlyRi = "}", @@ -313,8 +314,7 @@ proc getNumber(L: var Lexer, result: var Token) = proc lexMessageLitNum(L: var Lexer, msg: string, startpos: int, msgKind = errGenerated) = # Used to get slightly human friendlier err messages. - const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O', - 'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'} + const literalishChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '.', '\''} var msgPos = L.bufpos var t: Token t.literal = "" @@ -326,15 +326,14 @@ proc getNumber(L: var Lexer, result: var Token) = t.literal.add(L.buf[L.bufpos]) inc(L.bufpos) matchChars(L, t, literalishChars) - if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}: - inc(L.bufpos) + if L.buf[L.bufpos] in literalishChars: t.literal.add(L.buf[L.bufpos]) + inc(L.bufpos) matchChars(L, t, {'0'..'9'}) L.bufpos = msgPos lexMessage(L, msgKind, msg % t.literal) var - startpos, endpos: int xi: BiggestInt isBase10 = true numDigits = 0 @@ -346,7 +345,7 @@ proc getNumber(L: var Lexer, result: var Token) = result.tokType = tkIntLit # int literal until we know better result.literal = "" result.base = base10 - startpos = L.bufpos + let startpos = L.bufpos tokenBegin(result, startpos) var isPositive = true @@ -395,201 +394,187 @@ proc getNumber(L: var Lexer, result: var Token) = discard matchUnderscoreChars(L, result, {'0'..'9'}) if L.buf[L.bufpos] in {'e', 'E'}: result.tokType = tkFloatLit - eatChar(L, result, 'e') + eatChar(L, result) if L.buf[L.bufpos] in {'+', '-'}: eatChar(L, result) discard matchUnderscoreChars(L, result, {'0'..'9'}) - endpos = L.bufpos + let endpos = L.bufpos # Second stage, find out if there's a datatype suffix and handle it var postPos = endpos + if L.buf[postPos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}: + let errPos = postPos + var customLitPossible = false if L.buf[postPos] == '\'': inc(postPos) + customLitPossible = true - case L.buf[postPos] - of 'f', 'F': - inc(postPos) - if (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): - result.tokType = tkFloat32Lit - inc(postPos, 2) - elif (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): - result.tokType = tkFloat64Lit - inc(postPos, 2) - elif (L.buf[postPos] == '1') and - (L.buf[postPos + 1] == '2') and - (L.buf[postPos + 2] == '8'): - result.tokType = tkFloat128Lit - inc(postPos, 3) - else: # "f" alone defaults to float32 - result.tokType = tkFloat32Lit - of 'd', 'D': # ad hoc convenience shortcut for f64 - inc(postPos) - result.tokType = tkFloat64Lit - of 'i', 'I': - inc(postPos) - if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): - result.tokType = tkInt64Lit - inc(postPos, 2) - elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): - result.tokType = tkInt32Lit - inc(postPos, 2) - elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'): - result.tokType = tkInt16Lit - inc(postPos, 2) - elif (L.buf[postPos] == '8'): - result.tokType = tkInt8Lit - inc(postPos) + if L.buf[postPos] in SymChars: + var suffixAsLower = newStringOfCap(10) + var suffix = newStringOfCap(10) + while true: + let c = L.buf[postPos] + suffix.add c + suffixAsLower.add toLowerAscii(c) + inc postPos + if L.buf[postPos] notin SymChars+{'_'}: break + case suffix + of "f", "f32": result.tokType = tkFloat32Lit + of "d", "f64": result.tokType = tkFloat64Lit + of "f128": result.tokType = tkFloat128Lit + of "i8": result.tokType = tkInt8Lit + of "i16": result.tokType = tkInt16Lit + of "i32": result.tokType = tkInt32Lit + of "i64": result.tokType = tkInt64Lit + of "u": result.tokType = tkUIntLit + of "u8": result.tokType = tkUInt8Lit + of "u16": result.tokType = tkUInt16Lit + of "u32": result.tokType = tkUInt32Lit + of "u64": result.tokType = tkUInt64Lit else: - lexMessageLitNum(L, "invalid number: '$1'", startpos) - of 'u', 'U': - inc(postPos) - if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): - result.tokType = tkUInt64Lit - inc(postPos, 2) - elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'): - result.tokType = tkUInt32Lit - inc(postPos, 2) - elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'): - result.tokType = tkUInt16Lit - inc(postPos, 2) - elif (L.buf[postPos] == '8'): - result.tokType = tkUInt8Lit - inc(postPos) - else: - result.tokType = tkUIntLit + if customLitPossible: + # remember the position of the ``'`` so that the parser doesn't + # have to reparse the custom literal: + result.iNumber = len(result.literal) + result.literal.add '\'' + result.literal.add suffix + result.tokType = tkCustomLit + else: + lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) else: - lexMessageLitNum(L, "invalid number: '$1'", startpos) + lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) # Is there still a literalish char awaiting? Then it's an error! if L.buf[postPos] in literalishChars or (L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}): lexMessageLitNum(L, "invalid number: '$1'", startpos) - # Third stage, extract actual number - L.bufpos = startpos # restore position - var pos = startpos - try: - if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars): - inc(pos, 2) - xi = 0 # it is a base prefix + if result.tokType != tkCustomLit: + # Third stage, extract actual number + L.bufpos = startpos # restore position + var pos = startpos + try: + if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars): + inc(pos, 2) + xi = 0 # it is a base prefix - case L.buf[pos - 1] - of 'b', 'B': - result.base = base2 - while pos < endpos: - if L.buf[pos] != '_': - xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0')) - inc(pos) - # 'c', 'C' is deprecated - of 'o', 'c', 'C': - result.base = base8 - while pos < endpos: - if L.buf[pos] != '_': - xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0')) - inc(pos) - of 'x', 'X': - result.base = base16 - while pos < endpos: - case L.buf[pos] - of '_': + case L.buf[pos - 1] + of 'b', 'B': + result.base = base2 + while pos < endpos: + if L.buf[pos] != '_': + xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0')) inc(pos) - of '0'..'9': - xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0')) + # 'c', 'C' is deprecated + of 'o', 'c', 'C': + result.base = base8 + while pos < endpos: + if L.buf[pos] != '_': + xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0')) inc(pos) - of 'a'..'f': - xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10) - inc(pos) - of 'A'..'F': - xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10) - inc(pos) - else: - break + of 'x', 'X': + result.base = base16 + while pos < endpos: + case L.buf[pos] + of '_': + inc(pos) + of '0'..'9': + xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0')) + inc(pos) + of 'a'..'f': + xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10) + inc(pos) + of 'A'..'F': + xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10) + inc(pos) + else: + break + else: + internalError(L.config, getLineInfo(L), "getNumber") + + case result.tokType + of tkIntLit, tkInt64Lit: setNumber result.iNumber, xi + of tkInt8Lit: setNumber result.iNumber, ashr(xi shl 56, 56) + of tkInt16Lit: setNumber result.iNumber, ashr(xi shl 48, 48) + of tkInt32Lit: setNumber result.iNumber, ashr(xi shl 32, 32) + of tkUIntLit, tkUInt64Lit: setNumber result.iNumber, xi + of tkUInt8Lit: setNumber result.iNumber, xi and 0xff + of tkUInt16Lit: setNumber result.iNumber, xi and 0xffff + of tkUInt32Lit: setNumber result.iNumber, xi and 0xffffffff + of tkFloat32Lit: + setNumber result.fNumber, (cast[PFloat32](addr(xi)))[] + # note: this code is endian neutral! + # XXX: Test this on big endian machine! + of tkFloat64Lit, tkFloatLit: + setNumber result.fNumber, (cast[PFloat64](addr(xi)))[] + else: internalError(L.config, getLineInfo(L), "getNumber") + + # Bounds checks. Non decimal literals are allowed to overflow the range of + # the datatype as long as their pattern don't overflow _bitwise_, hence + # below checks of signed sizes against uint*.high is deliberate: + # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK) + if result.tokType notin floatTypes: + let outOfRange = + case result.tokType + of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi + of tkInt8Lit: (xi > BiggestInt(uint8.high)) + of tkInt16Lit: (xi > BiggestInt(uint16.high)) + of tkInt32Lit: (xi > BiggestInt(uint32.high)) + else: false + + if outOfRange: + #echo "out of range num: ", result.iNumber, " vs ", xi + lexMessageLitNum(L, "number out of range: '$1'", startpos) + else: - internalError(L.config, getLineInfo(L), "getNumber") + case result.tokType + of floatTypes: + result.fNumber = parseFloat(result.literal) + of tkUInt64Lit, tkUIntLit: + var iNumber: uint64 + var len: int + try: + len = parseBiggestUInt(result.literal, iNumber) + except ValueError: + raise newException(OverflowDefect, "number out of range: " & $result.literal) + if len != result.literal.len: + raise newException(ValueError, "invalid integer: " & $result.literal) + result.iNumber = cast[int64](iNumber) + else: + var iNumber: int64 + var len: int + try: + len = parseBiggestInt(result.literal, iNumber) + except ValueError: + raise newException(OverflowDefect, "number out of range: " & $result.literal) + if len != result.literal.len: + raise newException(ValueError, "invalid integer: " & $result.literal) + result.iNumber = iNumber - case result.tokType - of tkIntLit, tkInt64Lit: setNumber result.iNumber, xi - of tkInt8Lit: setNumber result.iNumber, ashr(xi shl 56, 56) - of tkInt16Lit: setNumber result.iNumber, ashr(xi shl 48, 48) - of tkInt32Lit: setNumber result.iNumber, ashr(xi shl 32, 32) - of tkUIntLit, tkUInt64Lit: setNumber result.iNumber, xi - of tkUInt8Lit: setNumber result.iNumber, xi and 0xff - of tkUInt16Lit: setNumber result.iNumber, xi and 0xffff - of tkUInt32Lit: setNumber result.iNumber, xi and 0xffffffff - of tkFloat32Lit: - setNumber result.fNumber, (cast[PFloat32](addr(xi)))[] - # note: this code is endian neutral! - # XXX: Test this on big endian machine! - of tkFloat64Lit, tkFloatLit: - setNumber result.fNumber, (cast[PFloat64](addr(xi)))[] - else: internalError(L.config, getLineInfo(L), "getNumber") - - # Bounds checks. Non decimal literals are allowed to overflow the range of - # the datatype as long as their pattern don't overflow _bitwise_, hence - # below checks of signed sizes against uint*.high is deliberate: - # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK) - if result.tokType notin floatTypes: + # Explicit bounds checks. let outOfRange = case result.tokType - of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi - of tkInt8Lit: (xi > BiggestInt(uint8.high)) - of tkInt16Lit: (xi > BiggestInt(uint16.high)) - of tkInt32Lit: (xi > BiggestInt(uint32.high)) + of tkInt8Lit: result.iNumber > int8.high or result.iNumber < int8.low + of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high) or result.iNumber < 0 + of tkInt16Lit: result.iNumber > int16.high or result.iNumber < int16.low + of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high) or result.iNumber < 0 + of tkInt32Lit: result.iNumber > int32.high or result.iNumber < int32.low + of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high) or result.iNumber < 0 else: false if outOfRange: - #echo "out of range num: ", result.iNumber, " vs ", xi lexMessageLitNum(L, "number out of range: '$1'", startpos) - else: - case result.tokType - of floatTypes: - result.fNumber = parseFloat(result.literal) - of tkUInt64Lit, tkUIntLit: - var iNumber: uint64 - var len: int - try: - len = parseBiggestUInt(result.literal, iNumber) - except ValueError: - raise newException(OverflowDefect, "number out of range: " & $result.literal) - if len != result.literal.len: - raise newException(ValueError, "invalid integer: " & $result.literal) - result.iNumber = cast[int64](iNumber) - else: - var iNumber: int64 - var len: int - try: - len = parseBiggestInt(result.literal, iNumber) - except ValueError: - raise newException(OverflowDefect, "number out of range: " & $result.literal) - if len != result.literal.len: - raise newException(ValueError, "invalid integer: " & $result.literal) - result.iNumber = iNumber + # Promote int literal to int64? Not always necessary, but more consistent + if result.tokType == tkIntLit: + if result.iNumber > high(int32) or result.iNumber < low(int32): + result.tokType = tkInt64Lit - # Explicit bounds checks. - let outOfRange = - case result.tokType - of tkInt8Lit: result.iNumber > int8.high or result.iNumber < int8.low - of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high) or result.iNumber < 0 - of tkInt16Lit: result.iNumber > int16.high or result.iNumber < int16.low - of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high) or result.iNumber < 0 - of tkInt32Lit: result.iNumber > int32.high or result.iNumber < int32.low - of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high) or result.iNumber < 0 - else: false - - if outOfRange: - lexMessageLitNum(L, "number out of range: '$1'", startpos) - - # Promote int literal to int64? Not always necessary, but more consistent - if result.tokType == tkIntLit: - if result.iNumber > high(int32) or result.iNumber < low(int32): - result.tokType = tkInt64Lit - - except ValueError: - lexMessageLitNum(L, "invalid number: '$1'", startpos) - except OverflowDefect, RangeDefect: - lexMessageLitNum(L, "number out of range: '$1'", startpos) + except ValueError: + lexMessageLitNum(L, "invalid number: '$1'", startpos) + except OverflowDefect, RangeDefect: + lexMessageLitNum(L, "number out of range: '$1'", startpos) tokenEnd(result, postPos-1) L.bufpos = postPos @@ -830,8 +815,9 @@ proc getString(L: var Lexer, tok: var Token, mode: StringMode) = inc(pos) L.bufpos = pos -proc getCharacter(L: var Lexer, tok: var Token) = +proc getCharacter(L: var Lexer; tok: var Token) = tokenBegin(tok, L.bufpos) + let startPos = L.bufpos inc(L.bufpos) # skip ' var c = L.buf[L.bufpos] case c @@ -842,10 +828,16 @@ proc getCharacter(L: var Lexer, tok: var Token) = else: tok.literal = $c inc(L.bufpos) - if L.buf[L.bufpos] != '\'': - lexMessage(L, errGenerated, "missing closing ' for character literal") - tokenEndIgnore(tok, L.bufpos) - inc(L.bufpos) # skip ' + if L.buf[L.bufpos] == '\'': + tokenEndIgnore(tok, L.bufpos) + inc(L.bufpos) # skip ' + else: + if startPos > 0 and L.buf[startPos-1] == '`': + tok.literal = "'" + L.bufpos = startPos+1 + else: + lexMessage(L, errGenerated, "missing closing ' for character literal") + tokenEndIgnore(tok, L.bufpos) proc getSymbol(L: var Lexer, tok: var Token) = var h: Hash = 0 diff --git a/compiler/parser.nim b/compiler/parser.nim index fe857c81b..b9a6ffb8c 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -355,7 +355,7 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode = let node = newNodeI(nkIdent, lineinfo) node.ident = p.lex.cache.getIdent(accm) result.add(node) - of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit: + of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCustomLit: result.add(newIdentNodeP(p.lex.cache.getIdent($p.tok), p)) getTok(p) else: @@ -627,7 +627,7 @@ proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode = #| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT #| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT #| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT - #| | CHAR_LIT + #| | CHAR_LIT | CUSTOM_NUMERIC_LIT #| | NIL #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT #| identOrLiteral = generalizedLit | symbol | literal @@ -710,6 +710,14 @@ proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode = of tkCharLit: result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p) getTok(p) + of tkCustomLit: + let splitPos = p.tok.iNumber.int + let str = newStrNodeP(nkRStrLit, p.tok.literal.substr(0, splitPos-1), p) + let callee = newIdentNodeP(getIdent(p.lex.cache, p.tok.literal.substr(splitPos)), p) + result = newNodeP(nkDotExpr, p) + result.add str + result.add callee + getTok(p) of tkNil: result = newNodeP(nkNilLit, p) getTok(p) @@ -807,7 +815,7 @@ proc primarySuffix(p: var Parser, r: PNode, result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) - of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, + of tkSymbol, tkAccent, tkIntLit..tkCustomLit, tkNil, tkCast, tkOpr, tkDotDot, tkVar, tkOut, tkStatic, tkType, tkEnum, tkTuple, tkObject, tkProc: # XXX: In type sections we allow the free application of the @@ -1097,7 +1105,7 @@ proc isExprStart(p: Parser): bool = case p.tok.tokType of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor, tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics, - tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, + tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCustomLit, tkVar, tkRef, tkPtr, tkTuple, tkObject, tkWhen, tkCase, tkOut: result = true else: result = false @@ -1498,7 +1506,7 @@ proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode = #| yieldStmt = 'yield' optInd expr? #| discardStmt = 'discard' optInd expr? #| breakStmt = 'break' optInd expr? - #| continueStmt = 'break' optInd expr? + #| continueStmt = 'continue' optInd expr? result = newNodeP(kind, p) getTok(p) if p.tok.tokType == tkComment: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index c36eaaf11..9ca485f6e 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -942,7 +942,7 @@ proc skipHiddenNodes(n: PNode): PNode = else: break proc accentedName(g: var TSrcGen, n: PNode) = - const backticksNeeded = OpChars + {'[', '{'} + const backticksNeeded = OpChars + {'[', '{', '\''} if n == nil: return let isOperator = if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in backticksNeeded: true @@ -976,6 +976,11 @@ proc infixArgument(g: var TSrcGen, n: PNode, i: int) = if needsParenthesis: put(g, tkParRi, ")") +proc isCustomLit(n: PNode): bool = + n.len == 2 and n[0].kind == nkRStrLit and + (n[1].kind == nkIdent and n[1].ident.s.startsWith('\'')) or + (n[1].kind == nkSym and n[1].sym.name.s.startsWith('\'')) + proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if isNil(n): return var @@ -1195,9 +1200,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gcomma(g, n, c) put(g, tkBracketRi, "]") of nkDotExpr: - gsub(g, n, 0) - put(g, tkDot, ".") - gsub(g, n, 1) + if isCustomLit(n): + put(g, tkCustomLit, n[0].strVal) + gsub(g, n, 1) + else: + gsub(g, n, 0) + put(g, tkDot, ".") + if n.len > 1: + accentedName(g, n[1]) of nkBind: putWithSpace(g, tkBind, "bind") gsub(g, n, 0) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index ff8f68ed0..fee43162e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1524,7 +1524,7 @@ proc semProcAnnotation(c: PContext, prc: PNode; return proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} = - ## used for resolving 'auto' in lambdas based on their callsite + ## used for resolving 'auto' in lambdas based on their callsite var n = n let original = n[namePos].sym let s = original #copySym(original, false) diff --git a/doc/grammar.txt b/doc/grammar.txt index 0d5eef179..d4f4a0515 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -46,7 +46,7 @@ literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT | STR_LIT | RSTR_LIT | TRIPLESTR_LIT - | CHAR_LIT + | CHAR_LIT | CUSTOM_NUMERIC_LIT | NIL generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT identOrLiteral = generalizedLit | symbol | literal @@ -100,6 +100,7 @@ postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt | IND{=} 'except' exprList ':' stmt + | IND{=} 'finally' ':' stmt | IND{=} 'else' ':' stmt )* exprStmt = simpleExpr (( '=' optInd expr colonBody? ) diff --git a/doc/manual.rst b/doc/manual.rst index db1251630..a882eb945 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -490,11 +490,17 @@ this. Another reason is that Nim can thus support `array[char, int]` or type is used for Unicode characters, it can represent any Unicode character. `Rune` is declared in the `unicode module `_. +A character literal that does not end in ``'`` interpreted as ``'`` if there +is a preceeding backtick token. There must be no whitespace between the preceeding +backtick token and the character literal. This special rule ensures that a declaration +like ``proc `'customLiteral`(s: string)`` is valid. See also +`Custom Numeric Literals <#custom-numeric-literals>`_. -Numerical constants -------------------- -Numerical constants are of a single type and have the form:: +Numeric Literals +---------------- + +Numeric literals have the form:: hexdigit = digit | 'A'..'F' | 'a'..'f' octdigit = '0'..'7' @@ -530,8 +536,10 @@ Numerical constants are of a single type and have the form:: FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX + CUSTOM_NUMERIC_LIT = (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) '\'' CUSTOM_NUMERIC_SUFFIX -As can be seen in the productions, numerical constants can contain underscores + +As can be seen in the productions, numeric literals can contain underscores for readability. Integer and floating-point literals may be given in decimal (no prefix), binary (prefix `0b`), octal (prefix `0o`), and hexadecimal (prefix `0x`) notation. @@ -579,7 +587,7 @@ is optional if it is not ambiguous (only hexadecimal floating-point literals with a type suffix can be ambiguous). -The type suffixes are: +The pre-defined type suffixes are: ================= ========================= Type Suffix Resulting type of literal @@ -611,6 +619,42 @@ the bit width of the datatype, it is accepted. Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1 instead of causing an overflow error. + +Custom Numeric Literals +~~~~~~~~~~~~~~~~~~~~~~~ + +If the suffix is not predefined, then the suffix is assumed to be a call +to a proc, template, macro or other callable identifier that is passed the +string containing the literal. The callable identifier needs to be declared +with a special ``'`` prefix: + +.. code-block:: nim + + import strutils + type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble" + proc `'u4`(n: string): u4 = + # The leading ' is required. + result = (parseInt(n) and 0x0F).u4 + + var x = 5'u4 + +More formally, a custom numeric literal `123'custom` is transformed +to r"123".`'custom` in the parsing step. There is no AST node kind that +corresponds to this transformation. The transformation naturally handles +the case that additional parameters are passed to the callee: + +.. code-block:: nim + + import strutils + type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble" + proc `'u4`(n: string; moreData: int): u4 = + result = (parseInt(n) and 0x0F).u4 + + var x = 5'u4(123) + +Custom numeric literals are covered by the grammar rule named `CUSTOM_NUMERIC_LIT`. + + Operators --------- diff --git a/tests/lexer/mlexerutils.nim b/tests/lexer/mlexerutils.nim new file mode 100644 index 000000000..eae7a0006 --- /dev/null +++ b/tests/lexer/mlexerutils.nim @@ -0,0 +1,9 @@ +import macros + +macro lispReprStr*(a: untyped): untyped = newLit(a.lispRepr) + +macro assertAST*(expected: string, struct: untyped): untyped = + var ast = newLit(struct.treeRepr) + result = quote do: + if `ast` != `expected`: + doAssert false, "\nGot:\n" & `ast`.indent(2) & "\nExpected:\n" & `expected`.indent(2) \ No newline at end of file diff --git a/tests/lexer/tcustom_numeric_literals.nim b/tests/lexer/tcustom_numeric_literals.nim new file mode 100644 index 000000000..a2f355b4d --- /dev/null +++ b/tests/lexer/tcustom_numeric_literals.nim @@ -0,0 +1,150 @@ +discard """ + targets: "c cpp js" +""" + +# Test tkStrNumLit + +import std/[macros, strutils] +import mlexerutils + +# AST checks + +assertAST dedent """ + StmtList + ProcDef + AccQuoted + Ident "\'" + Ident "wrap" + Empty + Empty + FormalParams + Ident "string" + IdentDefs + Ident "number" + Ident "string" + Empty + Empty + Empty + StmtList + Asgn + Ident "result" + Infix + Ident "&" + Infix + Ident "&" + StrLit "[[" + Ident "number" + StrLit "]]"""": + proc `'wrap`(number: string): string = + result = "[[" & number & "]]" + +assertAST dedent """ + StmtList + DotExpr + RStrLit "-38383839292839283928392839283928392839283.928493849385935898243e-50000" + Ident "\'wrap"""": + -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap + +proc `'wrap`(number: string): string = "[[" & number & "]]" +doAssert lispReprStr(-1'wrap) == """(DotExpr (RStrLit "-1") (Ident "\'wrap"))""" + +template main = + block: # basic suffix usage + template `'twrap`(number: string): untyped = + number.`'wrap` + proc extraContext(): string = + 22.40'wrap + proc `*`(left, right: string): string = + result = left & "times" & right + proc `+`(left, right: string): string = + result = left & "plus" & right + + doAssert 1'wrap == "[[1]]" + doAssert -1'wrap == "[[-1]]": + "unable to resolve a negative integer-suffix pattern" + doAssert 12345.67890'wrap == "[[12345.67890]]" + doAssert 1'wrap*1'wrap == "[[1]]times[[1]]": + "unable to resolve an operator between two suffixed numeric literals" + doAssert 1'wrap+ -1'wrap == "[[1]]plus[[-1]]": # will generate a compiler warning about inconsistent spacing + "unable to resolve a negative suffixed numeric literal following an operator" + doAssert 1'wrap + -1'wrap == "[[1]]plus[[-1]]" + doAssert 1'twrap == "[[1]]" + doAssert extraContext() == "[[22.40]]": + "unable to return a suffixed numeric literal by an implicit return" + doAssert 0x5a3a'wrap == "[[0x5a3a]]" + doAssert 0o5732'wrap == "[[0o5732]]" + doAssert 0b0101111010101'wrap == "[[0b0101111010101]]" + doAssert -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap == "[[-38383839292839283928392839283928392839283.928493849385935898243e-50000]]" + doAssert 1234.56'wrap == "[[1234.56]]": + "unable to properly account for context with suffixed numeric literals" + + block: # verify that the i64, f32, etc builtin suffixes still parse correctly + const expectedF32: float32 = 123.125 + proc `'f9`(number: string): string = # proc starts with 'f' just like 'f32' + "[[" & number & "]]" + proc `'f32a`(number: string): string = # looks even more like 'f32' + "[[" & number & "]]" + proc `'d9`(number: string): string = # proc starts with 'd' just like the d suffix + "[[" & number & "]]" + proc `'i9`(number: string): string = # proc starts with 'i' just like 'i64' + "[[" & number & "]]" + proc `'u9`(number: string): string = # proc starts with 'u' just like 'u8' + "[[" & number & "]]" + + doAssert 123.125f32 == expectedF32: + "failing to support non-quoted legacy f32 floating point suffix" + doAssert 123.125'f32 == expectedF32 + doAssert 123.125e0'f32 == expectedF32 + doAssert 1234.56'wrap == 1234.56'f9 + doAssert 1234.56'wrap == 1234.56'f32a + doAssert 1234.56'wrap == 1234.56'd9 + doAssert 1234.56'wrap == 1234.56'i9 + doAssert 1234.56'wrap == 1234.56'u9 + doAssert lispReprStr(1234.56'u9) == """(DotExpr (RStrLit "1234.56") (Ident "\'u9"))""": + "failed to properly build AST for suffix that starts with u" + doAssert -128'i8 == (-128).int8 + + block: # case checks + doAssert 1E2 == 100: + "lexer not handling upper-case exponent" + doAssert 1.0E2 == 100.0 + doAssert 1e2 == 100 + doAssert 0xdeadBEEF'wrap == "[[0xdeadBEEF]]": + "lexer not maintaining original case" + doAssert 0.1E12'wrap == "[[0.1E12]]" + doAssert 0.0e12'wrap == "[[0.0e12]]" + doAssert 0.0e+12'wrap == "[[0.0e+12]]" + doAssert 0.0e-12'wrap == "[[0.0e-12]]" + doAssert 0e-12'wrap == "[[0e-12]]" + + block: # macro and template usage + template `'foo`(a: string): untyped = (a, 2) + doAssert -12'foo == ("-12", 2) + template `'fooplus`(a: string, b: int): untyped = (a, b) + doAssert -12'fooplus(2) == ("-12", 2) + template `'fooplusopt`(a: string, b: int = 99): untyped = (a, b) + doAssert -12'fooplusopt(2) == ("-12", 2) + doAssert -12'fooplusopt() == ("-12", 99) + doAssert -12'fooplusopt == ("-12", 99) + macro `'bar`(a: static string): untyped = + var infix = newNimNode(nnkInfix) + infix.add newIdentNode("&") + infix.add newLit("got ") + infix.add newLit(a.repr) + result = newNimNode(nnkStmtList) + result.add infix + doAssert -12'bar == "got \"-12\"" + macro deb(a): untyped = newLit(a.repr) + doAssert deb(-12'bar) == "-12'bar" + # macro metawrap(): untyped = + # func wrap1(a: string): string = "{" & a & "}" + # func `'wrap2`(a: string): string = "{" & a & "}" + # result = quote do: + # let a1 = wrap1"-128" + # let a2 = -128'wrap2 + # metawrap() + # doAssert a1 == "{-128}" + # doAssert a2 == "{-128}" + +static: main() +main() diff --git a/tests/lexer/tstrlits.nim b/tests/lexer/tstrlits.nim deleted file mode 100644 index 8e8250a5b..000000000 --- a/tests/lexer/tstrlits.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - output: "a\"\"long string\"\"\"\"\"abc\"def_'2'●𝌆𝌆A" -""" -# Test the new different string literals - -const - tripleEmpty = """"long string"""""""" # "long string """"" - - rawQuote = r"a""" - - raw = r"abc""def" - - escaped = "\x5f'\50'\u25cf\u{1D306}\u{1d306}\u{41}" - - -stdout.write(rawQuote) -stdout.write(tripleEmpty) -stdout.write(raw) -stdout.writeLine(escaped) diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim index 89f1b79ef..0aa861d53 100644 --- a/tests/lexer/tunary_minus.nim +++ b/tests/lexer/tunary_minus.nim @@ -6,13 +6,7 @@ discard """ import std/[macros, strutils] -macro lispReprStr*(a: untyped): untyped = newLit(a.lispRepr) - -macro assertAST*(expected: string, struct: untyped): untyped = - var ast = newLit(struct.treeRepr) - result = quote do: - if `ast` != `expected`: - doAssert false, "\nGot:\n" & `ast`.indent(2) & "\nExpected:\n" & `expected`.indent(2) +import mlexerutils const one = 1 const minusOne = `-`(one) From 355985ac89dd13d5b317744b30842155d9321565 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 24 Mar 2021 22:29:42 +0100 Subject: [PATCH 2270/4254] custom integer literals bugfixes (#17499) * custom integer literals bugfixes * make nimsuggest compile again --- changelog.md | 2 +- compiler/lexer.nim | 9 +++++---- doc/manual.rst | 6 +++++- tests/lexer/tunary_minus.nim | 3 +++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 922b8470a..f180e90f9 100644 --- a/changelog.md +++ b/changelog.md @@ -266,7 +266,7 @@ - The unary minus in `-1` is now part of the integer literal, it is now parsed as a single token. This implies that edge cases like `-128'i8` finally work correctly. -- Custom numeric literals are now supported. +- Custom numeric literals (e.g. `-128'bignum`) are now supported. ## Compiler changes diff --git a/compiler/lexer.nim b/compiler/lexer.nim index b34b010c2..ecf6cb0d9 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -345,13 +345,14 @@ proc getNumber(L: var Lexer, result: var Token) = result.tokType = tkIntLit # int literal until we know better result.literal = "" result.base = base10 - let startpos = L.bufpos - tokenBegin(result, startpos) + tokenBegin(result, L.bufpos) var isPositive = true if L.buf[L.bufpos] == '-': eatChar(L, result) - isPositive = true + isPositive = false + + let startpos = L.bufpos template setNumber(field, value) = field = (if isPositive: value else: -value) @@ -419,7 +420,7 @@ proc getNumber(L: var Lexer, result: var Token) = suffixAsLower.add toLowerAscii(c) inc postPos if L.buf[postPos] notin SymChars+{'_'}: break - case suffix + case suffixAsLower of "f", "f32": result.tokType = tkFloat32Lit of "d", "f64": result.tokType = tkFloat64Lit of "f128": result.tokType = tkFloat128Lit diff --git a/doc/manual.rst b/doc/manual.rst index a882eb945..51c434c7b 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -490,7 +490,7 @@ this. Another reason is that Nim can thus support `array[char, int]` or type is used for Unicode characters, it can represent any Unicode character. `Rune` is declared in the `unicode module `_. -A character literal that does not end in ``'`` interpreted as ``'`` if there +A character literal that does not end in ``'`` is interpreted as ``'`` if there is a preceeding backtick token. There must be no whitespace between the preceeding backtick token and the character literal. This special rule ensures that a declaration like ``proc `'customLiteral`(s: string)`` is valid. See also @@ -538,6 +538,9 @@ Numeric literals have the form:: CUSTOM_NUMERIC_LIT = (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) '\'' CUSTOM_NUMERIC_SUFFIX + # CUSTOM_NUMERIC_SUFFIX is any Nim identifier that is not + # a pre-defined type suffix. + As can be seen in the productions, numeric literals can contain underscores for readability. Integer and floating-point literals may be given in decimal (no @@ -653,6 +656,7 @@ the case that additional parameters are passed to the callee: var x = 5'u4(123) Custom numeric literals are covered by the grammar rule named `CUSTOM_NUMERIC_LIT`. +A custom numeric literal is a single token. Operators diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim index 0aa861d53..639911fcd 100644 --- a/tests/lexer/tunary_minus.nim +++ b/tests/lexer/tunary_minus.nim @@ -51,6 +51,9 @@ template main = doAssert x() == minusOne: "unable to handle negatives after semi-colon" + doAssert -0b111 == -7 + doAssert -0xff == -255 + block: # check when a minus (-) is an unary op doAssert -one == minusOne: "unable to a negative prior to identifier" From 76d391a512b53b731941d6b355fe3431fc6b74c1 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 25 Mar 2021 14:06:30 +0800 Subject: [PATCH 2271/4254] remove unnecessary check (#17502) --- compiler/spawn.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 54ed51dbc..1635f9f83 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -371,8 +371,6 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp fn = indirectAccess(castExpr, field, n.info) elif fn.kind == nkSym and fn.sym.kind == skIterator: localError(g.config, n.info, "iterator in spawn environment is not allowed") - elif fn.typ.callConv == ccClosure: - localError(g.config, n.info, "closure in spawn environment is not allowed") call.add(fn) var varSection = newNodeI(nkVarSection, n.info) From 045400ad92f98363ef8931aea29165b48d07ac16 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 25 Mar 2021 14:07:29 +0800 Subject: [PATCH 2272/4254] ref https://github.com/nim-lang/Nim/pull/17333 (#17495) --- doc/nep1.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/nep1.rst b/doc/nep1.rst index 3bae6a00b..bdf8e0eab 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -157,7 +157,8 @@ English word To use Notes ------------------- ------------ -------------------------------------- initialize initFoo initializes a value type `Foo` new newFoo initializes a reference type `Foo` - via `new` + via `new` or a value type `Foo` + with reference semantics. this or self self for method like procs, e.g.: `proc fun(self: Foo, a: int)` rationale: `self` is more unique in English From 46364e63cd0c292b3a803d1975d48db73f46e8e6 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 25 Mar 2021 10:15:05 +0300 Subject: [PATCH 2273/4254] fix RST parsing after option lists (#17442) --- lib/packages/docutils/rst.nim | 73 ++++++++++++++++++++++++++++++++++- tests/stdlib/trstgen.nim | 49 +++++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 11768c7da..adc83c9af 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -82,6 +82,14 @@ ## * ***triple emphasis*** (bold and italic) using \*\*\* ## * ``:idx:`` role for \`interpreted text\` to include the link to this ## text into an index (example: `Nim index`_). +## * double slash `//` in option lists serves as a prefix for any option that +## starts from a word (without any leading symbols like `-`, `--`, `/`):: +## +## //compile compile the project +## //doc generate documentation +## +## Here the dummy `//` will disappear, while options ``compile`` +## and ``doc`` will be left in the final document. ## ## .. [cmp:Sphinx] similar but different from the directives of ## Python `Sphinx directives`_ extensions @@ -548,6 +556,67 @@ proc pushInd(p: var RstParser, ind: int) = proc popInd(p: var RstParser) = if p.indentStack.len > 1: setLen(p.indentStack, p.indentStack.len - 1) +# Working with indentation in rst.nim +# ----------------------------------- +# +# Every line break has an associated tkIndent. +# The tokenizer writes back the first column of next non-blank line +# in all preceeding tkIndent tokens to the `ival` field of tkIndent. +# +# RST document is separated into body elements (B.E.), every of which +# has a dedicated handler proc (or block of logic when B.E. is a block quote) +# that should follow the next rule: +# Every B.E. handler proc should finish at tkIndent (newline) +# after its B.E. finishes. +# Then its callers (which is `parseSection` or another B.E. handler) +# check for tkIndent ival (without necessity to advance `p.idx`) +# and decide themselves whether they continue processing or also stop. +# +# An example:: +# +# L RST text fragment indentation +# +--------------------+ +# 1 | | <- (empty line at the start of file) no tokens +# 2 |First paragraph. | <- tkIndent has ival=0, and next tkWord has col=0 +# 3 | | <- tkIndent has ival=0 +# 4 |* bullet item and | <- tkIndent has ival=0, and next tkPunct has col=0 +# 5 | its continuation | <- tkIndent has ival=2, and next tkWord has col=2 +# 6 | | <- tkIndent has ival=4 +# 7 | Block quote | <- tkIndent has ival=4, and next tkWord has col=4 +# 8 | | <- tkIndent has ival=0 +# 9 | | <- tkIndent has ival=0 +# 10|Final paragraph | <- tkIndent has ival=0, and tkWord has col=0 +# +--------------------+ +# C:01234 +# +# Here parser starts with initial `indentStack=[0]` and then calls the +# 1st `parseSection`: +# +# - `parseSection` calls `parseParagraph` and "First paragraph" is parsed +# - bullet list handler is started at reaching ``*`` (L4 C0), it +# starts bullet item logic (L4 C2), which calls `pushInd(p, ind=2)`, +# then calls `parseSection` (2nd call, nested) which parses +# paragraph "bullet list and its continuation" and then starts +# a block quote logic (L7 C4). +# The block quote logic calls calls `pushInd(p, ind=4)` and +# calls `parseSection` again, so a (simplified) sequence of calls now is:: +# +# parseSection -> parseBulletList -> +# parseSection (+block quote logic) -> parseSection +# +# 3rd `parseSection` finishes, block quote logic calls `popInd(p)`, +# it returns to bullet item logic, which sees that next tkIndent has +# ival=0 and stops there since the required indentation for a bullet item +# is 2 and 0<2; the bullet item logic calls `popInd(p)`. +# Then bullet list handler checks that next tkWord (L10 C0) has the +# right indentation but does not have ``*`` so stops at tkIndent (L10). +# - 1st `parseSection` invocation calls `parseParagraph` and the +# "Final paragraph" is parsed. +# +# If a B.E. handler has advanced `p.idx` past tkIndent to check +# whether it should continue its processing or not, and decided not to, +# then this B.E. handler should step back (e.g. do `dec p.idx`). + proc initParser(p: var RstParser, sharedState: PSharedState) = p.indentStack = @[0] p.tok = @[] @@ -1912,8 +1981,9 @@ proc parseBulletList(p: var RstParser): PRstNode = proc parseOptionList(p: var RstParser): PRstNode = result = newRstNodeA(p, rnOptionList) + let col = currentTok(p).col while true: - if isOptionList(p): + if currentTok(p).col == col and isOptionList(p): var a = newRstNode(rnOptionGroup) var b = newRstNode(rnDescription) var c = newRstNode(rnOptionListItem) @@ -1936,6 +2006,7 @@ proc parseOptionList(p: var RstParser): PRstNode = c.add(b) result.add(c) else: + dec p.idx # back to tkIndent break proc parseDefinitionList(p: var RstParser): PRstNode = diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index d6055cc11..0f3890faa 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1277,6 +1277,55 @@ Test1 let refline = "Ref. " & ref1 & "! and " & ref2 & ";and " & ref3 & "." doAssert refline in output1 + test "Option lists 1": + # check that "* b" is not consumed by previous bullet item because of + # incorrect indentation handling in option lists + let input = dedent """ + * a + -m desc + -n very long + desc + * b""" + let output = input.toHtml + check(output.count("") == 2) + check(output.count("-mdesc""" in output) + check("""-nvery long desc""" in + output) + + test "Option lists 2": + # check that 2nd option list is not united with the 1st + let input = dedent """ + * a + -m desc + -n very long + desc + -d option""" + let output = input.toHtml + check(output.count("-mdesc""" in output) + check("""-nvery long desc""" in + output) + check("""-doption""" in + output) + + test "Option list 3 (double /)": + let input = dedent """ + * a + //compile compile1 + //doc doc1 + cont + -d option""" + let output = input.toHtml + check(output.count("compilecompile1""" in output) + check("""docdoc1 cont""" in + output) + check("""-doption""" in + output) suite "RST/Code highlight": test "Basic Python code highlight": let pythonCode = """ From 6e0a293dab195c973a45b38d22fdc97575c025fc Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 25 Mar 2021 15:28:06 +0800 Subject: [PATCH 2274/4254] re-enable fidget (#17229) --- testament/important_packages.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 1dd7c69ca..66a2fa09e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -49,6 +49,7 @@ pkg "chronicles", "nim c -o:chr -r chronicles.nim" # when not defined(osx): # testdatagram.nim(560, 54): Check failed # pkg "chronos", "nim c -r -d:release tests/testall" # pending https://github.com/nim-lang/Nim/issues/17130 + pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" pkg "compactdict" @@ -59,7 +60,7 @@ pkg "delaunay" pkg "docopt" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" -# pkg "fidget" # pending https://github.com/treeform/fidget/issues/133 +pkg "fidget" pkg "fragments", "nim c -r fragments/dsl.nim" pkg "fusion" pkg "gara" From 8573160a44439ffe3fbbdd354188db9c976a2081 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 25 Mar 2021 21:05:50 +0800 Subject: [PATCH 2275/4254] lent support for tables (#17505) --- lib/pure/collections/tables.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index f77642349..9387807c0 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -702,7 +702,7 @@ iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: Table[A, B]): A = +iterator keys*[A, B](t: Table[A, B]): lent A = ## Iterates over any key in the table `t`. ## ## See also: @@ -723,7 +723,7 @@ iterator keys*[A, B](t: Table[A, B]): A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: Table[A, B]): B = +iterator values*[A, B](t: Table[A, B]): lent B = ## Iterates over any value in the table `t`. ## ## See also: @@ -1146,7 +1146,7 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: TableRef[A, B]): A = +iterator keys*[A, B](t: TableRef[A, B]): lent A = ## Iterates over any key in the table `t`. ## ## See also: @@ -1167,7 +1167,7 @@ iterator keys*[A, B](t: TableRef[A, B]): A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: TableRef[A, B]): B = +iterator values*[A, B](t: TableRef[A, B]): lent B = ## Iterates over any value in the table `t`. ## ## See also: @@ -1722,7 +1722,7 @@ iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: OrderedTable[A, B]): A = +iterator keys*[A, B](t: OrderedTable[A, B]): lent A = ## Iterates over any key in the table `t` in insertion order. ## ## See also: @@ -1743,7 +1743,7 @@ iterator keys*[A, B](t: OrderedTable[A, B]): A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: OrderedTable[A, B]): B = +iterator values*[A, B](t: OrderedTable[A, B]): lent B = ## Iterates over any value in the table `t` in insertion order. ## ## See also: @@ -2130,7 +2130,7 @@ iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A, B](t: OrderedTableRef[A, B]): A = +iterator keys*[A, B](t: OrderedTableRef[A, B]): lent A = ## Iterates over any key in the table `t` in insertion order. ## ## See also: @@ -2151,7 +2151,7 @@ iterator keys*[A, B](t: OrderedTableRef[A, B]): A = yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") -iterator values*[A, B](t: OrderedTableRef[A, B]): B = +iterator values*[A, B](t: OrderedTableRef[A, B]): lent B = ## Iterates over any value in the table `t` in insertion order. ## ## See also: @@ -2543,7 +2543,7 @@ iterator mpairs*[A](t: var CountTable[A]): (A, var int) = yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") -iterator keys*[A](t: CountTable[A]): A = +iterator keys*[A](t: CountTable[A]): lent A = ## Iterates over any key in the table `t`. ## ## See also: From 42e895feb11515689aaca96f58fcffb366d34bb7 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 26 Mar 2021 12:20:58 +0800 Subject: [PATCH 2276/4254] close #15696 (#17518) --- tests/vm/tvmmisc.nim | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index a485bac2e..f542fa560 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -255,6 +255,31 @@ block: doAssert e == @[] doAssert f == @[] + +block: # bug #10815 + type + Opcode = enum + iChar, iSet + + Inst = object + case code: Opcode + of iChar: + c: char + of iSet: + cs: set[char] + + Patt = seq[Inst] + + + proc `$`(p: Patt): string = + discard + + proc P(): Patt = + result.add Inst(code: iSet) + + const a = P() + doAssert $a == "" + import tables block: # bug #8007 From 8049d0befc8ac7689e98f266df69b5f268fb7683 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 25 Mar 2021 23:07:33 -0700 Subject: [PATCH 2277/4254] testament: remove unused tfile,tline,tcolumn (#17515) --- testament/specs.nim | 8 -------- testament/testament.nim | 30 ++---------------------------- 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/testament/specs.nim b/testament/specs.nim index 6b80fe41d..b5e6de7c2 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -79,8 +79,6 @@ type sortoutput*: bool output*: string line*, column*: int - tfile*: string - tline*, tcolumn*: int exitCode*: int msg*: string ccodeCheck*: seq[string] @@ -277,12 +275,6 @@ proc parseSpec*(filename: string): TSpec = if result.msg.len == 0 and result.nimout.len == 0: result.parseErrors.addLine "errormsg or msg needs to be specified before column" discard parseInt(e.value, result.column) - of "tfile": - result.tfile = e.value - of "tline": - discard parseInt(e.value, result.tline) - of "tcolumn": - discard parseInt(e.value, result.tcolumn) of "output": if result.outputCheck != ocSubstr: result.outputCheck = ocEqual diff --git a/testament/testament.nim b/testament/testament.nim index f45d4043a..6fc7e32ce 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -82,12 +82,6 @@ type let pegLineError = peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}" - - pegLineTemplate = - peg""" - {[^(]*} '(' {\d+} ', ' {\d+} ') ' - 'template/generic instantiation' ( ' of `' [^`]+ '`' )? ' from here' .* - """ pegOtherError = peg"'Error:' \s* {.*}" pegOfInterest = pegLineError / pegOtherError @@ -165,7 +159,6 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, let outp = p.outputStream var suc = "" var err = "" - var tmpl = "" var x = newStringOfCap(120) result.nimout = "" while true: @@ -174,9 +167,6 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, if x =~ pegOfInterest: # `err` should contain the last error/warning message err = x - elif x =~ pegLineTemplate and err == "": - # `tmpl` contains the last template expansion before the error - tmpl = x elif x.isSuccess: suc = x elif not running(p): @@ -187,14 +177,7 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, result.output = "" result.line = 0 result.column = 0 - result.tfile = "" - result.tline = 0 - result.tcolumn = 0 result.err = reNimcCrash - if tmpl =~ pegLineTemplate: - result.tfile = extractFilename(matches[0]) - result.tline = parseInt(matches[1]) - result.tcolumn = parseInt(matches[2]) if err =~ pegLineError: result.file = extractFilename(matches[0]) result.line = parseInt(matches[1]) @@ -374,22 +357,13 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarg r.addResult(test, target, expected.msg, given.msg, reMsgsDiffer) elif expected.nimout.len > 0 and not greedyOrderedSubsetLines(expected.nimout, given.nimout): r.addResult(test, target, expected.nimout, given.nimout, reMsgsDiffer) - elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and + elif extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: r.addResult(test, target, expected.file, given.file, reFilesDiffer) elif expected.line != given.line and expected.line != 0 or expected.column != given.column and expected.column != 0: r.addResult(test, target, $expected.line & ':' & $expected.column, - $given.line & ':' & $given.column, - reLinesDiffer) - elif expected.tfile != "" and extractFilename(expected.tfile) != extractFilename(given.tfile) and - "internal error:" notin expected.msg: - r.addResult(test, target, expected.tfile, given.tfile, reFilesDiffer) - elif expected.tline != given.tline and expected.tline != 0 or - expected.tcolumn != given.tcolumn and expected.tcolumn != 0: - r.addResult(test, target, $expected.tline & ':' & $expected.tcolumn, - $given.tline & ':' & $given.tcolumn, - reLinesDiffer) + $given.line & ':' & $given.column, reLinesDiffer) else: r.addResult(test, target, expected.msg, given.msg, reSuccess) inc(r.passed) From e3e97421438da27267b159b922d7338fa92f1cd8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 26 Mar 2021 08:52:26 +0100 Subject: [PATCH 2278/4254] added a 'koch ic' command for easier adhoc testing of IC (#17508) * added a 'koch ic' command for easier adhoc testing of IC * IC: progress * IC: enable generics test * make tests green --- compiler/ccgtypes.nim | 7 ++----- compiler/cgen.nim | 30 ++++++++++++++++++++++++++++++ compiler/ic/cbackend.nim | 12 +++++++++++- compiler/ic/ic.nim | 22 +++++++++++++++++----- compiler/ic/rodfiles.nim | 1 + compiler/modulegraphs.nim | 16 ++++++++++++++++ koch.nim | 21 +++++++++++++++++++-- tests/ic/tgenerics.nim | 1 - 8 files changed, 96 insertions(+), 14 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e17a55542..b0c3aa3b1 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1357,9 +1357,6 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) -proc moduleOpenForCodegen(m: BModule; module: int32): bool {.inline.} = - result = module < m.g.modules.len and m.g.modules[module] != nil - proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = let origType = t # distinct types can have their own destructors @@ -1384,7 +1381,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = m.typeInfoMarkerV2[sig] = result let owner = t.skipTypes(typedescPtrs).itemId.module - if owner != m.module.position and moduleOpenForCodegen(m, owner): + if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner): # make sure the type info is created in the owner module discard genTypeInfoV2(m.g.modules[owner], origType, info) # reference the type info as extern here @@ -1463,7 +1460,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = return prefixTI.rope & result & ")".rope var owner = t.skipTypes(typedescPtrs).itemId.module - if owner != m.module.position and moduleOpenForCodegen(m, owner): + if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner): # make sure the type info is created in the owner module discard genTypeInfoV1(m.g.modules[owner], origType, info) # reference the type info as extern here diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b88999088..7dfab6a42 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -22,6 +22,7 @@ when not defined(leanCompiler): import strutils except `%` # collides with ropes.`%` +from ic / ic import ModuleBackendFlag from modulegraphs import ModuleGraph, PPassContext from lineinfos import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile @@ -1501,6 +1502,33 @@ proc genMainProc(m: BModule) = if m.config.cppCustomNamespace.len > 0: m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace) +proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) = + ## Called from the IC backend. + if HasDatInitProc in flags: + let datInit = getSomeNameForModule(m) & "DatInit000" + g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) + g.mainDatInit.addf("\t$1();$N", [datInit]) + if HasModuleInitProc in flags: + let init = getSomeNameForModule(m) & "Init000" + g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) + let initCall = "\t$1();$N" % [init] + if sfMainModule in m.flags: + g.mainModInit.add(initCall) + elif sfSystemModule in m.flags: + g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any + else: + g.otherModsInit.add(initCall) + +proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] = + # called from IC. + result = {} + if m.hcrOn or m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0: + result.incl HasModuleInitProc + for i in cfsTypeInit1..cfsDynLibInit: + if m.s[i].len != 0: + result.incl HasDatInitProc + break + proc registerModuleToMain(g: BModuleList; m: BModule) = let init = m.getInitName @@ -1595,6 +1623,7 @@ proc genDatInitCode(m: BModule) = if moduleDatInitRequired: m.s[cfsDatInitProc].add(prc) + #rememberFlag(m.g.graph, m.module, HasDatInitProc) # Very similar to the contents of symInDynamicLib - basically only the # things needed for the hot code reloading runtime procs to be loaded @@ -1725,6 +1754,7 @@ proc genInitCode(m: BModule) = if moduleInitRequired or sfMainModule in m.module.flags: m.s[cfsInitProc].add(prc) + #rememberFlag(m.g.graph, m.module, HasModuleInitProc) genDatInitCode(m) diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index 34ee59d52..9282ac466 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -44,9 +44,11 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive cgen.genTopLevelStmt(bmod, n) finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info)) + m.fromDisk.backendFlags = cgen.whichInitProcs(bmod) proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) = for x in mitems(m.fromDisk.emittedTypeInfo): + #echo "found type ", x, " for file ", int(origin) g.emittedTypeInfo[x] = origin proc addFileToLink(config: ConfigRef; m: PSym) = @@ -112,12 +114,16 @@ proc generateCode*(g: ModuleGraph) = resetForBackend(g) var alive = computeAliveSyms(g.packed, g.config) + when false: + for i in 0..high(g.packed): + echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i)) + for i in 0..high(g.packed): # case statement here to enforce exhaustive checks. case g.packed[i].status of undefined: discard "nothing to do" - of loading: + of loading, stored: assert false of storing, outdated: generateCodeForModule(g, g.packed[i], alive) @@ -133,3 +139,7 @@ proc generateCode*(g: ModuleGraph) = else: addFileToLink(g.config, g.packed[i].module) replayTypeInfo(g, g.packed[i], FileIndex(i)) + + if g.backend == nil: + g.backend = cgendata.newModuleList(g) + registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 230b4d087..8017d8b40 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -22,6 +22,10 @@ type options: TOptions globalOptions: TGlobalOptions + ModuleBackendFlag* = enum + HasDatInitProc + HasModuleInitProc + PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file definedSymbols: string includes: seq[(LitId, string)] # first entry is the module filename itself @@ -43,6 +47,7 @@ type enumToStringProcs*: seq[(PackedItemId, PackedItemId)] emittedTypeInfo*: seq[string] + backendFlags*: set[ModuleBackendFlag] sh*: Shared cfg: PackedConfig @@ -556,6 +561,9 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef loadSeqSection enumToStringProcsSection, m.enumToStringProcs loadSeqSection typeInfoSection, m.emittedTypeInfo + f.loadSection backendFlagsSection + f.loadPrim m.backendFlags + close(f) result = f.err @@ -619,6 +627,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac storeSeqSection enumToStringProcsSection, m.enumToStringProcs storeSeqSection typeInfoSection, m.emittedTypeInfo + f.storeSection backendFlagsSection + f.storePrim m.backendFlags + close(f) encoder.disable() if f.err != ok: @@ -646,7 +657,8 @@ type storing, # state is strictly for stress-testing purposes loading, loaded, - outdated + outdated, + stored # store is complete, no further additions possible LoadedModule* = object status*: ModuleStatus @@ -673,7 +685,7 @@ proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; x: PackedLineInfo): TLineInfo = - assert g[thisModule].status in {loaded, storing} + assert g[thisModule].status in {loaded, storing, stored} result = TLineInfo(line: x.line, col: x.col, fileIndex: toFileIndexCached(c, g, thisModule, x.file)) @@ -806,7 +818,7 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: result = nil else: let si = moduleIndex(c, g, thisModule, s) - assert g[si].status in {loaded, storing} + assert g[si].status in {loaded, storing, stored} if not g[si].symsInit: g[si].symsInit = true setLen g[si].syms, g[si].fromDisk.sh.syms.len @@ -852,7 +864,7 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t result = nil else: let si = moduleIndex(c, g, thisModule, t) - assert g[si].status in {loaded, storing} + assert g[si].status in {loaded, storing, stored} assert t.item > 0 if not g[si].typesInit: @@ -950,7 +962,7 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache of loading, loaded: # For loading: Assume no recompile is required. result = false - of outdated, storing: + of outdated, storing, stored: result = true proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index a518870f8..39a5b6b73 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -37,6 +37,7 @@ type methodsPerTypeSection enumToStringProcsSection typeInfoSection # required by the backend + backendFlagsSection aliveSymsSection # beware, this is stored in a `.alivesyms` file. RodFileError* = enum diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 9ac76457c..e6f5267cd 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -455,11 +455,25 @@ proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = elif fileIdx.int32 < g.ifaces.len: result = g.ifaces[fileIdx.int32].module +proc moduleOpenForCodegen*(g: ModuleGraph; m: FileIndex): bool {.inline.} = + if g.config.symbolFiles == disabledSf: + result = true + else: + result = g.packed[m.int32].status notin {undefined, stored, loaded} + proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) = #assert(not isCachedModule(g, m.int32)) if g.config.symbolFiles != disabledSf: #assert g.encoders[m.int32].isActive + assert g.packed[m.int32].status != stored g.packed[m.int32].fromDisk.emittedTypeInfo.add ti + #echo "added typeinfo ", m.int32, " ", ti, " suspicious ", not g.encoders[m.int32].isActive + +proc rememberFlag*(g: ModuleGraph; m: PSym; flag: ModuleBackendFlag) = + if g.config.symbolFiles != disabledSf: + #assert g.encoders[m.int32].isActive + assert g.packed[m.position].status != stored + g.packed[m.position].fromDisk.backendFlags.incl flag proc closeRodFile*(g: ModuleGraph; m: PSym) = if g.config.symbolFiles in {readOnlySf, v2Sf}: @@ -469,6 +483,8 @@ proc closeRodFile*(g: ModuleGraph; m: PSym) = let mint = m.position saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))), g.encoders[mint], g.packed[mint].fromDisk) + g.packed[mint].status = stored + elif g.config.symbolFiles == stressTest: # debug code, but maybe a good idea for production? Could reduce the compiler's # memory consumption considerably at the cost of more loads from disk. diff --git a/koch.nim b/koch.nim index bf7fb1e62..6f1da8165 100644 --- a/koch.nim +++ b/koch.nim @@ -458,8 +458,8 @@ proc temp(args: string) = inc i let d = getAppDir() - var output = d / "compiler" / "nim".exe - var finalDest = d / "bin" / "nim_temp".exe + let output = d / "compiler" / "nim".exe + let finalDest = d / "bin" / "nim_temp".exe # 125 is the magic number to tell git bisect to skip the current commit. var (bootArgs, programArgs) = splitArgs(args) if "doc" notin programArgs and @@ -483,6 +483,22 @@ proc xtemp(cmd: string) = finally: copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe) +proc icTest(args: string) = + temp("") + let inp = os.parseCmdLine(args)[0] + let content = readFile(inp) + let nimExe = getAppDir() / "bin" / "nim_temp".exe + var i = 0 + for fragment in content.split("#!EDIT!#"): + let file = inp.replace(".nim", "_temp.nim") + writeFile(file, fragment) + var cmd = nimExe & " cpp --ic:on --listcmd " + if i == 0: + cmd.add "-f " + cmd.add quoteShell(file) + exec(cmd) + inc i + proc buildDrNim(args: string) = if not dirExists("dist/nimz3"): exec("git clone https://github.com/zevv/nimz3.git dist/nimz3") @@ -705,6 +721,7 @@ when isMainModule: of "fusion": let suffix = if latest: HeadHash else: FusionStableHash exec("nimble install -y fusion@$#" % suffix) + of "ic": icTest(op.cmdLineRest) else: showHelp() break of cmdEnd: break diff --git a/tests/ic/tgenerics.nim b/tests/ic/tgenerics.nim index bc5c05f4f..138799e85 100644 --- a/tests/ic/tgenerics.nim +++ b/tests/ic/tgenerics.nim @@ -1,6 +1,5 @@ discard """ output: "bar" - disabled: "true" """ import tables From bb3769975b7cbbe2f84c288d7f3363b6bad9ca0e Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 26 Mar 2021 13:05:51 +0100 Subject: [PATCH 2279/4254] Fix #17199 (#17348) * don't zero out in a move in the VM * Add testcases for #17199 * Update tests/arc/tarcmisc.nim Co-authored-by: Timothee Cour * Update tests/vm/tissues.nim Co-authored-by: Timothee Cour * Fix test failures * Fix test * Fix tests Co-authored-by: Andreas Rumpf Co-authored-by: Timothee Cour --- compiler/vmgen.nim | 7 ++++--- tests/arc/tarcmisc.nim | 32 ++++++++++++++++++++++++++++ tests/stdlib/tisolation.nim | 42 ++++++++++++++++++++++++------------- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7d7382d18..bd80df219 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1354,9 +1354,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = if dest < 0: dest = c.getTemp(arg.typ) gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), dest, a) # XXX use ldNullOpcode() here? - c.gABx(n, opcLdNull, a, c.genType(arg.typ)) - c.gABx(n, opcNodeToReg, a, a) - c.genAsgnPatch(arg, a) + # Don't zero out the arg for now #17199 + # c.gABx(n, opcLdNull, a, c.genType(arg.typ)) + # c.gABx(n, opcNodeToReg, a, a) + # c.genAsgnPatch(arg, a) c.freeTemp(a) of mNodeId: c.genUnaryABC(n, dest, opcNodeId) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 55803085f..82751f44c 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -390,3 +390,35 @@ proc newPixelBuffer(): PixelBuffer = discard newPixelBuffer() + +# bug #17199 + +proc passSeq(data: seq[string]) = + # used the system.& proc initially + let wat = data & "hello" + +proc test2 = + let name = @["hello", "world"] + passSeq(name) + doAssert name == @["hello", "world"] + +static: test2() # was buggy +test2() + +proc merge(x: sink seq[string], y: sink string): seq[string] = + newSeq(result, x.len + 1) + for i in 0..x.len-1: + result[i] = move(x[i]) + result[x.len] = move(y) + +proc passSeq2(data: seq[string]) = + # used the system.& proc initially + let wat = merge(data, "hello") + +proc test3 = + let name = @["hello", "world"] + passSeq2(name) + doAssert name == @["hello", "world"] + +static: test3() # was buggy +test3() diff --git a/tests/stdlib/tisolation.nim b/tests/stdlib/tisolation.nim index e43fd558a..c3857f483 100644 --- a/tests/stdlib/tisolation.nim +++ b/tests/stdlib/tisolation.nim @@ -7,7 +7,7 @@ import std/[isolation, json] -proc main() = +proc main(moveZeroesOut: static bool) = block: type Empty = ref object @@ -19,64 +19,76 @@ proc main() = block: # string literals var data = isolate("string") doAssert data.extract == "string" - doAssert data.extract == "" + if moveZeroesOut: + doAssert data.extract == "" block: # string literals var data = isolate("") doAssert data.extract == "" - doAssert data.extract == "" + if moveZeroesOut: + doAssert data.extract == "" block: var src = "string" var data = isolate(move src) doAssert data.extract == "string" - doAssert src.len == 0 + if moveZeroesOut: + doAssert src.len == 0 block: # int literals var data = isolate(1) doAssert data.extract == 1 - doAssert data.extract == 0 + if moveZeroesOut: + doAssert data.extract == 0 block: # float literals var data = isolate(1.6) doAssert data.extract == 1.6 - doAssert data.extract == 0.0 + if moveZeroesOut: + doAssert data.extract == 0.0 block: var data = isolate(@["1", "2"]) doAssert data.extract == @["1", "2"] - doAssert data.extract == @[] + if moveZeroesOut: + doAssert data.extract == @[] block: var data = isolate(@["1", "2", "3", "4", "5"]) doAssert data.extract == @["1", "2", "3", "4", "5"] - doAssert data.extract == @[] + if moveZeroesOut: + doAssert data.extract == @[] block: var data = isolate(@["", ""]) doAssert data.extract == @["", ""] - doAssert data.extract == @[] + if moveZeroesOut: + doAssert data.extract == @[] block: var src = @["1", "2"] var data = isolate(move src) doAssert data.extract == @["1", "2"] - doAssert src.len == 0 + if moveZeroesOut: + doAssert src.len == 0 block: var data = isolate(@[1, 2]) doAssert data.extract == @[1, 2] - doAssert data.extract == @[] + if moveZeroesOut: + doAssert data.extract == @[] block: var data = isolate(["1", "2"]) doAssert data.extract == ["1", "2"] - doAssert data.extract == ["", ""] + if moveZeroesOut: + doAssert data.extract == ["", ""] block: var data = isolate([1, 2]) doAssert data.extract == [1, 2] - doAssert data.extract == [0, 0] + if moveZeroesOut: + doAssert data.extract == [0, 0] block: type @@ -119,5 +131,5 @@ proc main() = doAssert $x == """@[(value: "1234")]""" -static: main() -main() +static: main(moveZeroesOut = false) +main(moveZeroesOut = true) From add771b051128b5eef09b4d77015fbeacf994700 Mon Sep 17 00:00:00 2001 From: narimiran Date: Fri, 26 Mar 2021 13:41:43 +0100 Subject: [PATCH 2280/4254] disable package 'chronicles' until 'chronos' is fixed --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 66a2fa09e..eb0196f70 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -45,7 +45,7 @@ pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" pkg "cello" pkg "chroma" -pkg "chronicles", "nim c -o:chr -r chronicles.nim" +# pkg "chronicles", "nim c -o:chr -r chronicles.nim" # when not defined(osx): # testdatagram.nim(560, 54): Check failed # pkg "chronos", "nim c -r -d:release tests/testall" # pending https://github.com/nim-lang/Nim/issues/17130 From 3e03f6733548fecb328214e0c8632fa4916992ed Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 26 Mar 2021 16:27:55 +0100 Subject: [PATCH 2281/4254] cleaned up the internal documentation (#17524) --- doc/intern.rst | 605 +++++++++------------------------------- lib/system/cellsets.nim | 35 ++- lib/system/gc.nim | 47 ++++ 3 files changed, 220 insertions(+), 467 deletions(-) diff --git a/doc/intern.rst b/doc/intern.rst index 2456b25fd..1e18d975c 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -32,28 +32,29 @@ Path Purpose `doc` the documentation; it is a bunch of reStructuredText files `lib` the Nim library -`web` website of Nim; generated by `nimweb` - from the `*.txt` and `*.nimf` files ============ =================================================== Bootstrapping the compiler ========================== +**Note**: Add ``.`` to your PATH so that `koch` can be used without the `./`. + Compiling the compiler is a simple matter of running:: nim c koch.nim - ./koch boot + koch boot -d:release -For a release version use:: +For a debug version use:: nim c koch.nim - ./koch boot -d:release + koch boot + And for a debug version compatible with GDB:: nim c koch.nim - ./koch boot --debuginfo --linedir:on + koch boot --debuginfo --linedir:on The `koch` program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. @@ -61,12 +62,105 @@ More information about its options can be found in the `koch `_ documentation. +Developing the compiler +======================= + +To create a new compiler for each run, use `koch temp`:: + + koch temp c test.nim + +`koch temp` creates a debug build of the compiler, which is useful +to create stacktraces for compiler debugging. + +You can of course use GDB or Visual Studio to debug the +compiler (via `--debuginfo --lineDir:on`). However, there +are also lots of procs that aid in debugging: + + +.. code-block:: nim + + # dealing with PNode: + echo renderTree(someNode) + debug(someNode) # some JSON representation + + # dealing with PType: + echo typeToString(someType) + debug(someType) + + # dealing with PSym: + echo symbol.name.s + debug(symbol) + + # pretty prints the Nim ast, but annotates symbol IDs: + echo renderTree(someNode, {renderIds}) + if `??`(conf, n.info, "temp.nim"): + # only output when it comes from "temp.nim" + echo renderTree(n) + if `??`(conf, n.info, "temp.nim"): + # why does it process temp.nim here? + writeStackTrace() + +These procs may not already be imported by the module you're editing. +You can import them directly for debugging: + +.. code-block:: nim + from astalgo import debug + from types import typeToString + from renderer import renderTree + from msgs import `??` + + +The compiler's architecture +=========================== + +Nim uses the classic compiler architecture: A lexer/scanner feds tokens to a +parser. The parser builds a syntax tree that is used by the code generators. +This syntax tree is the interface between the parser and the code generator. +It is essential to understand most of the compiler's code. + +Semantic analysis is separated from parsing. + +.. include:: filelist.txt + + +The syntax tree +--------------- +The syntax tree consists of nodes which may have an arbitrary number of +children. Types and symbols are represented by other nodes, because they +may contain cycles. The AST changes its shape after semantic checking. This +is needed to make life easier for the code generators. See the "ast" module +for the type definitions. The `macros `_ module contains many +examples how the AST represents each syntactic structure. + + +Bisecting for regressions +========================= + +`koch temp` returns 125 as the exit code in case the compiler +compilation fails. This exit code tells `git bisect` to skip the +current commit.:: + + git bisect start bad-commit good-commit + git bisect run ./koch temp -r c test-source.nim + +You can also bisect using custom options to build the compiler, for example if +you don't need a debug version of the compiler (which runs slower), you can replace +`./koch temp` by explicit compilation command, see `Rebuilding the compiler`_. + + +Runtimes +======== + +Nim has two different runtimes, the "old runtime" and the "new runtime". The old +runtime supports the old GCs (markAndSweep, refc, Boehm), the new runtime supports +ARC/ORC. The new runtime is active `when defined(nimV2)`. + + Coding Guidelines ================= -* Use CamelCase, not underscored_identifiers. -* Indent with two spaces. -* Max line length is 80 characters. +* We follow Nim's official style guide, see ``_. +* Max line length is 100 characters. * Provide spaces around binary operators if that enhances readability. * Use a space after a colon, but not before it. * [deprecated] Start types with a capital `T`, unless they are @@ -86,9 +180,9 @@ POSIX-compliant systems on conventional hardware are usually pretty easy to port: Add the platform to `platform` (if it is not already listed there), check that the OS, System modules work and recompile Nim. -The only case where things aren't as easy is when the garbage -collector needs some assembler tweaking to work. The standard -version of the GC uses C's `setjmp` function to store all registers +The only case where things aren't as easy is when old runtime's garbage +collectors need some assembler tweaking to work. The default +implementation uses C's `setjmp` function to store all registers on the hardware stack. It may be necessary that the new platform needs to replace this generic code by some assembler code. @@ -96,136 +190,33 @@ replace this generic code by some assembler code. Runtime type information ======================== +**Note**: This section describes the "old runtime". + *Runtime type information* (RTTI) is needed for several aspects of the Nim programming language: Garbage collection - The most important reason for RTTI. Generating - traversal procedures produces bigger code and is likely to be slower on - modern hardware as dynamic procedure binding is hard to predict. + The old GCs use the RTTI for traversing abitrary Nim types, but usually + only the `marker` field which contains a proc that does the traversal. Complex assignments Sequences and strings are implemented as pointers to resizeable buffers, but Nim requires copying for - assignments. Apart from RTTI the compiler could generate copy procedures - for any type that needs one. However, this would make the code bigger and - the RTTI is likely already there for the GC. + assignments. Apart from RTTI the compiler also generates copy procedures + as a specialization. We already know the type information as a graph in the compiler. Thus we need to serialize this graph as RTTI for C code generation. Look at the file `lib/system/hti.nim` for more information. -Rebuilding the compiler + +Magics and compilerProcs ======================== -After an initial build via `sh build_all.sh` on posix or `build_all.bat` on windows, -you can rebuild the compiler as follows: - -* `nim c koch` if you need to rebuild koch -* `./koch boot -d:release` this ensures the compiler can rebuild itself - (use `koch` instead of `./koch` on windows), which builds the compiler 3 times. - -A faster approach if you don't need to run the full bootstrapping implied by `koch boot`, -is the following: - -* `pathto/nim c --lib:lib -d:release -o:bin/nim_temp compiler/nim.nim` - -Where `pathto/nim` is any nim binary sufficiently recent (e.g. `bin/nim_cources` -built during bootstrap or `$HOME/.nimble/bin/nim` installed by `choosenim 1.2.0`) - -You can pass any additional options such as `-d:leanCompiler` if you don't need -certain features or `-d:debug --stacktrace:on --excessiveStackTrace --stackTraceMsgs` -for debugging the compiler. See also `Debugging the compiler`_. - -Debugging the compiler -====================== - -You can of course use GDB or Visual Studio to debug the -compiler (via `--debuginfo --lineDir:on`). However, there -are also lots of procs that aid in debugging: - - -.. code-block:: nim - # pretty prints the Nim AST - echo renderTree(someNode) - # outputs some JSON representation - debug(someNode) - # pretty prints some type - echo typeToString(someType) - debug(someType) - echo symbol.name.s - debug(symbol) - # pretty prints the Nim ast, but annotates symbol IDs: - echo renderTree(someNode, {renderIds}) - if `??`(conf, n.info, "temp.nim"): - # only output when it comes from "temp.nim" - echo renderTree(n) - if `??`(conf, n.info, "temp.nim"): - # why does it process temp.nim here? - writeStackTrace() - -These procs may not be imported by a module. You can import them directly for debugging: - -.. code-block:: nim - from astalgo import debug - from types import typeToString - from renderer import renderTree - from msgs import `??` - -To create a new compiler for each run, use `koch temp`:: - - ./koch temp c /tmp/test.nim - -`koch temp` creates a debug build of the compiler, which is useful -to create stacktraces for compiler debugging. See also -`Rebuilding the compiler`_ if you need more control. - -Bisecting for regressions -========================= - -`koch temp` returns 125 as the exit code in case the compiler -compilation fails. This exit code tells `git bisect` to skip the -current commit.:: - - git bisect start bad-commit good-commit - git bisect run ./koch temp -r c test-source.nim - -You can also bisect using custom options to build the compiler, for example if -you don't need a debug version of the compiler (which runs slower), you can replace -`./koch temp` by explicit compilation command, see `Rebuilding the compiler`_. - -The compiler's architecture -=========================== - -Nim uses the classic compiler architecture: A lexer/scanner feds tokens to a -parser. The parser builds a syntax tree that is used by the code generator. -This syntax tree is the interface between the parser and the code generator. -It is essential to understand most of the compiler's code. - -In order to compile Nim correctly, type-checking has to be separated from -parsing. Otherwise generics cannot work. - -.. include:: filelist.txt - - -The syntax tree ---------------- -The syntax tree consists of nodes which may have an arbitrary number of -children. Types and symbols are represented by other nodes, because they -may contain cycles. The AST changes its shape after semantic checking. This -is needed to make life easier for the code generators. See the "ast" module -for the type definitions. The `macros `_ module contains many -examples how the AST represents each syntactic structure. - - -How the RTL is compiled -======================= - The `system` module contains the part of the RTL which needs support by -compiler magic (and the stuff that needs to be in it because the spec -says so). The C code generator generates the C code for it, just like any other +compiler magic. The C code generator generates the C code for it, just like any other module. However, calls to some procedures like `addInt` are inserted by -the CCG. Therefore the module `magicsys` contains a table (`compilerprocs`) +the generator. Therefore there is a table (`compilerprocs`) with all symbols that are marked as `compilerproc`. `compilerprocs` are needed by the code generator. A `magic` proc is not the same as a `compilerproc`: A `magic` is a proc that needs compiler magic for its @@ -233,325 +224,6 @@ semantic checking, a `compilerproc` is a proc that is used by the code generator. -Compilation cache -================= - -The implementation of the compilation cache is tricky: There are lots -of issues to be solved for the front- and backend. - - -General approach: AST replay ----------------------------- - -We store a module's AST of a successful semantic check in a SQLite -database. There are plenty of features that require a sub sequence -to be re-applied, for example: - -.. code-block:: nim - {.compile: "foo.c".} # even if the module is loaded from the DB, - # "foo.c" needs to be compiled/linked. - -The solution is to **re-play** the module's top level statements. -This solves the problem without having to special case the logic -that fills the internal seqs which are affected by the pragmas. - -In fact, this describes how the AST should be stored in the database, -as a "shallow" tree. Let's assume we compile module `m` with the -following contents: - -.. code-block:: nim - import std/strutils - - var x*: int = 90 - {.compile: "foo.c".} - proc p = echo "p" - proc q = echo "q" - static: - echo "static" - -Conceptually this is the AST we store for the module: - -.. code-block:: nim - import std/strutils - - var x* - {.compile: "foo.c".} - proc p - proc q - static: - echo "static" - -The symbol's `ast` field is loaded lazily, on demand. This is where most -savings come from, only the shallow outer AST is reconstructed immediately. - -It is also important that the replay involves the `import` statement so -that dependencies are resolved properly. - - -Shared global compiletime state -------------------------------- - -Nim allows `.global, compiletime` variables that can be filled by macro -invocations across different modules. This feature breaks modularity in a -severe way. Plenty of different solutions have been proposed: - -- Restrict the types of global compiletime variables to `Set[T]` or - similar unordered, only-growable collections so that we can track - the module's write effects to these variables and reapply the changes - in a different order. -- In every module compilation, reset the variable to its default value. -- Provide a restrictive API that can load/save the compiletime state to - a file. - -(These solutions are not mutually exclusive.) - -Since we adopt the "replay the top level statements" idea, the natural -solution to this problem is to emit pseudo top level statements that -reflect the mutations done to the global variable. However, this is -MUCH harder than it sounds, for example `squeaknim` uses this -snippet: - -.. code-block:: nim - apicall.add(") module: '" & dllName & "'>\C" & - "\t^self externalCallFailed\C!\C\C") - stCode.add(st & "\C\t\"Generated by NimSqueak\"\C\t" & apicall) - -We can "replay" `stCode.add` only if the values of `st` -and `apicall` are known. And even then a hash table's `add` with its -hashing mechanism is too hard to replay. - -In practice, things are worse still, consider `someGlobal[i][j].add arg`. -We only know the root is `someGlobal` but the concrete path to the data -is unknown as is the value that is added. We could compute a "diff" between -the global states and use that to compute a symbol patchset, but this is -quite some work, expensive to do at runtime (it would need to run after -every module has been compiled) and would also break for hash tables. - -We need an API that hides the complex aliasing problems by not relying -on Nim's global variables. The obvious solution is to use string keys -instead of global variables: - -.. code-block:: nim - - proc cachePut*(key: string; value: string) - proc cacheGet*(key: string): string - -However, the values being strings/json is quite problematic: Many -lookup tables that are built at compiletime embed *proc vars* and -types which have no obvious string representation... Seems like -AST diffing is still the best idea as it will not require to use -an alien API and works with some existing Nimble packages, at least. - -On the other hand, in Nim's future I would like to replace the VM -by native code. A diff algorithm wouldn't work for that. -Instead the native code would work with an API like `put`, `get`: - -.. code-block:: nim - - proc cachePut*(key: string; value: NimNode) - proc cacheGet*(key: string): NimNode - -The API should embrace the AST diffing notion: See the -module `macrocache` for the final details. - - - -Methods and type converters ---------------------------- - -In the following -sections *global* means *shared between modules* or *property of the whole -program*. - -Nim contains language features that are *global*. The best example for that -are multi methods: Introducing a new method with the same name and some -compatible object parameter means that the method's dispatcher needs to take -the new method into account. So the dispatching logic is only completely known -after the whole program has been translated! - -Other features that are *implicitly* triggered cause problems for modularity -too. Type converters fall into this category: - -.. code-block:: nim - # module A - converter toBool(x: int): bool = - result = x != 0 - -.. code-block:: nim - # module B - import A - - if 1: - echo "ugly, but should work" - -If in the above example module `B` is re-compiled, but `A` is not then -`B` needs to be aware of `toBool` even though `toBool` is not referenced -in `B` *explicitly*. - -Both the multi method and the type converter problems are solved by the -AST replay implementation. - - -Generics -~~~~~~~~ - -We cache generic instantiations and need to ensure this caching works -well with the incremental compilation feature. Since the cache is -attached to the `PSym` datastructure, it should work without any -special logic. - - -Backend issues --------------- - -- Init procs must not be "forgotten" to be called. -- Files must not be "forgotten" to be linked. -- Method dispatchers are global. -- DLL loading via `dlsym` is global. -- Emulated thread vars are global. - -However the biggest problem is that dead code elimination breaks modularity! -To see why, consider this scenario: The module `G` (for example the huge -Gtk2 module...) is compiled with dead code elimination turned on. So none -of `G`'s procs is generated at all. - -Then module `B` is compiled that requires `G.P1`. Ok, no problem, -`G.P1` is loaded from the symbol file and `G.c` now contains `G.P1`. - -Then module `A` (that depends on `B` and `G`) is compiled and `B` -and `G` are left unchanged. `A` requires `G.P2`. - -So now `G.c` MUST contain both `P1` and `P2`, but we haven't even -loaded `P1` from the symbol file, nor do we want to because we then quickly -would restore large parts of the whole program. - - -Solution -~~~~~~~~ - -The backend must have some logic so that if the currently processed module -is from the compilation cache, the `ast` field is not accessed. Instead -the generated C(++) for the symbol's body needs to be cached too and -inserted back into the produced C file. This approach seems to deal with -all the outlined problems above. - - -Debugging Nim's memory management -================================= - -The following paragraphs are mostly a reminder for myself. Things to keep -in mind: - -* If an assertion in Nim's memory manager or GC fails, the stack trace - keeps allocating memory! Thus a stack overflow may happen, hiding the - real issue. -* What seem to be C code generation problems is often a bug resulting from - not producing prototypes, so that some types default to `cint`. Testing - without the `-w` option helps! - - -The Garbage Collector -===================== - -Introduction ------------- - -I use the term *cell* here to refer to everything that is traced -(sequences, refs, strings). -This section describes how the GC works. - -The basic algorithm is *Deferrent Reference Counting* with cycle detection. -References on the stack are not counted for better performance and easier C -code generation. - -Each cell has a header consisting of a RC and a pointer to its type -descriptor. However the program does not know about these, so they are placed at -negative offsets. In the GC code the type `PCell` denotes a pointer -decremented by the right offset, so that the header can be accessed easily. It -is extremely important that `pointer` is not confused with a `PCell` -as this would lead to a memory corruption. - - -The CellSet data structure --------------------------- - -The GC depends on an extremely efficient datastructure for storing a -set of pointers - this is called a `TCellSet` in the source code. -Inserting, deleting and searching are done in constant time. However, -modifying a `TCellSet` during traversal leads to undefined behaviour. - -.. code-block:: Nim - type - TCellSet # hidden - - proc cellSetInit(s: var TCellSet) # initialize a new set - proc cellSetDeinit(s: var TCellSet) # empty the set and free its memory - proc incl(s: var TCellSet, elem: PCell) # include an element - proc excl(s: var TCellSet, elem: PCell) # exclude an element - - proc `in`(elem: PCell, s: TCellSet): bool # tests membership - - iterator elements(s: TCellSet): (elem: PCell) - - -All the operations have to perform efficiently. Because a Cellset can -become huge a hash table alone is not suitable for this. - -We use a mixture of bitset and hash table for this. The hash table maps *pages* -to a page descriptor. The page descriptor contains a bit for any possible cell -address within this page. So including a cell is done as follows: - -- Find the page descriptor for the page the cell belongs to. -- Set the appropriate bit in the page descriptor indicating that the - cell points to the start of a memory block. - -Removing a cell is analogous - the bit has to be set to zero. -Single page descriptors are never deleted from the hash table. This is not -needed as the data structures needs to be rebuilt periodically anyway. - -Complete traversal is done in this way:: - - for each page descriptor d: - for each bit in d: - if bit == 1: - traverse the pointer belonging to this bit - - -Further complications ---------------------- - -In Nim the compiler cannot always know if a reference -is stored on the stack or not. This is caused by var parameters. -Consider this example: - -.. code-block:: Nim - proc setRef(r: var ref TNode) = - new(r) - - proc usage = - var - r: ref TNode - setRef(r) # here we should not update the reference counts, because - # r is on the stack - setRef(r.left) # here we should update the refcounts! - -We have to decide at runtime whether the reference is on the stack or not. -The generated code looks roughly like this: - -.. code-block:: C - void setref(TNode** ref) { - unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode))) - } - void usage(void) { - setRef(&r) - setRef(&r->left) - } - -Note that for systems with a continuous stack (which most systems have) -the check whether the ref is on the stack is very cheap (only two -comparisons). - - Code generation for closures ============================ @@ -598,14 +270,14 @@ This should produce roughly this code: .. code-block:: nim type - PEnv = ref object + Env = ref object x: int # data - proc anon(y: int, c: PEnv): int = + proc anon(y: int, c: Env): int = return y + c.x proc add(x: int): tuple[prc, data] = - var env: PEnv + var env: Env new env env.x = x result = (anon, env) @@ -630,25 +302,25 @@ This should produce roughly this code: .. code-block:: nim type - PEnvX = ref object + EnvX = ref object x: int # data - PEnvY = ref object + EnvY = ref object y: int - ex: PEnvX + ex: EnvX - proc lambdaZ(z: int, ey: PEnvY): int = + proc lambdaZ(z: int, ey: EnvY): int = return ey.ex.x + ey.y + z - proc lambdaY(y: int, ex: PEnvX): tuple[prc, data: PEnvY] = - var ey: PEnvY + proc lambdaY(y: int, ex: EnvX): tuple[prc, data: EnvY] = + var ey: EnvY new ey ey.y = y ey.ex = ex result = (lambdaZ, ey) - proc add(x: int): tuple[prc, data: PEnvX] = - var ex: PEnvX + proc add(x: int): tuple[prc, data: EnvX] = + var ex: EnvX ex.x = x result = (labmdaY, ex) @@ -663,17 +335,11 @@ More useful is escape analysis and stack allocation of the environment, however. -Alternative ------------ - -Process the closure of all inner procs in one pass and accumulate the -environments. This is however not always possible. - - Accumulator ----------- .. code-block:: nim + proc getAccumulator(start: int): proc (): int {.closure} = var i = start return lambda: int = @@ -708,20 +374,26 @@ backend somehow. We deal with this by modifying `s.ast[paramPos]` to contain the formal hidden parameter, but not `s.typ`! -Integer literals: ------------------ +Notes on type and AST representation +==================================== + +To be expanded. + + +Integer literals +---------------- In Nim, there is a redundant way to specify the type of an integer literal. First of all, it should be unsurprising that every node has a node kind. The node of an integer literal can be any of the -following values: +following values:: nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit, nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit On top of that, there is also the `typ` field for the type. It the kind of the `typ` field can be one of the following ones, and it -should be matching the literal kind: +should be matching the literal kind:: tyInt, tyInt8, tyInt16, tyInt32, tyInt64, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64 @@ -777,6 +449,7 @@ pointing back to the integer literal node in the ast containing the integer value. These are the properties that hold true for integer literal types. +:: n.kind == nkIntLit n.typ.kind == tyInt n.typ.n == n diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index 779f1a91f..a0f1fabf9 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -7,7 +7,40 @@ # distribution, for details about the copyright. # -# Efficient set of pointers for the GC (and repr) + +#[ + +Efficient set of pointers for the GC (and repr) +----------------------------------------------- + +The GC depends on an extremely efficient datastructure for storing a +set of pointers - this is called a `CellSet` in the source code. +Inserting, deleting and searching are done in constant time. However, +modifying a `CellSet` during traversal leads to undefined behaviour. + +All operations on a CellSet have to perform efficiently. Because a Cellset can +become huge a hash table alone is not suitable for this. + +We use a mixture of bitset and hash table for this. The hash table maps *pages* +to a page descriptor. The page descriptor contains a bit for any possible cell +address within this page. So including a cell is done as follows: + +- Find the page descriptor for the page the cell belongs to. +- Set the appropriate bit in the page descriptor indicating that the + cell points to the start of a memory block. + +Removing a cell is analogous - the bit has to be set to zero. +Single page descriptors are never deleted from the hash table. This is not +needed as the data structures needs to be rebuilt periodically anyway. + +Complete traversal is done in this way:: + + for each page descriptor d: + for each bit in d: + if bit == 1: + traverse the pointer belonging to this bit + +]# when defined(gcOrc) or defined(gcArc): type diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 1f7164266..ae29f3466 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -12,6 +12,53 @@ # Refcounting + Mark&Sweep. Complex algorithms avoided. # Been there, done that, didn't work. +#[ + +A *cell* is anything that is traced by the GC +(sequences, refs, strings, closures). + +The basic algorithm is *Deferrent Reference Counting* with cycle detection. +References on the stack are not counted for better performance and easier C +code generation. + +Each cell has a header consisting of a RC and a pointer to its type +descriptor. However the program does not know about these, so they are placed at +negative offsets. In the GC code the type `PCell` denotes a pointer +decremented by the right offset, so that the header can be accessed easily. It +is extremely important that `pointer` is not confused with a `PCell`. + +In Nim the compiler cannot always know if a reference +is stored on the stack or not. This is caused by var parameters. +Consider this example: + +.. code-block:: Nim + proc setRef(r: var ref TNode) = + new(r) + + proc usage = + var + r: ref TNode + setRef(r) # here we should not update the reference counts, because + # r is on the stack + setRef(r.left) # here we should update the refcounts! + +We have to decide at runtime whether the reference is on the stack or not. +The generated code looks roughly like this: + +.. code-block:: C + void setref(TNode** ref) { + unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode))) + } + void usage(void) { + setRef(&r) + setRef(&r->left) + } + +Note that for systems with a continuous stack (which most systems have) +the check whether the ref is on the stack is very cheap (only two +comparisons). +]# + {.push profiler:off.} const From b1b767ed0db19b337ab41fab9241227d23aaae38 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 27 Mar 2021 16:51:57 +0800 Subject: [PATCH 2282/4254] close #17157 add testcase (#17531) --- tests/proc/t17157.nim | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/proc/t17157.nim diff --git a/tests/proc/t17157.nim b/tests/proc/t17157.nim new file mode 100644 index 000000000..020e93fce --- /dev/null +++ b/tests/proc/t17157.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "'untyped' is only allowed in templates and macros or magic procs" +""" + +template something(op: proc (v: untyped): void): void = + discard From 8ed6de4fe6517dc4db38ab5dea898c0016d1c08a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 27 Mar 2021 02:22:42 -0700 Subject: [PATCH 2283/4254] fix flaky tnetconnect which sometimes failed with: No route to host [OSError] (#17526) --- tests/stdlib/tnetconnect.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim index b74545710..3a80df19f 100644 --- a/tests/stdlib/tnetconnect.nim +++ b/tests/stdlib/tnetconnect.nim @@ -17,10 +17,11 @@ proc test() = wrapSocket(ctx, socket) # trying 2 sites makes it more resilent: refs #17458 this could give: - # Error: unhandled exception: Call to 'connect' timed out. [TimeoutError] + # * Call to 'connect' timed out. [TimeoutError] + # * No route to host [OSError] try: fn("www.nim-lang.org") - except TimeoutError: + except TimeoutError, OSError: fn("www.google.com") test() From a65189a739c59fcc0d7b3f8fdcb2cf8bed432f68 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 27 Mar 2021 02:28:11 -0700 Subject: [PATCH 2284/4254] nnkArglist => nnkArgList + special case stylecheck:error (#17529) * nnkArglist => nnkArgList * special case stylecheck:error --- compiler/linter.nim | 8 +++++--- compiler/msgs.nim | 6 +++--- doc/astspec.txt | 2 +- doc/manual_experimental.rst | 2 +- lib/core/macros.nim | 2 +- lib/pure/htmlgen.nim | 2 +- lib/std/private/underscored_calls.nim | 2 +- tests/astspec/tastspec.nim | 2 +- tests/casestmt/tincompletecaseobject.nim | 4 ++-- tests/macros/tmacros_issues.nim | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/linter.nim b/compiler/linter.nim index 1ae1fb097..9af4f468e 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -125,9 +125,11 @@ proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) = return let newName = s.name.s - let oldName = differs(conf, info, newName) - if oldName.len > 0: - lintReport(conf, info, newName, oldName) + let badName = differs(conf, info, newName) + if badName.len > 0: + # special rules for historical reasons + let forceHint = badName == "nnkArgList" and newName == "nnkArglist" or badName == "nnkArglist" and newName == "nnkArgList" + lintReport(conf, info, newName, badName, forceHint = forceHint) proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = let wanted = $w diff --git a/compiler/msgs.nim b/compiler/msgs.nim index bbe40507f..24855ae18 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -612,9 +612,9 @@ template internalAssert*(conf: ConfigRef, e: bool) = let arg = info2.toFileLineCol internalErrorImpl(conf, unknownLineInfo, arg, info2) -template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) = - let m = "'$2' should be: '$1'" % [beau, got] - let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName +template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, forceHint = false) = + let m = "'$1' should be: '$2'" % [got, beau] + let msg = if optStyleError in conf.globalOptions and not forceHint: errGenerated else: hintName liMessage(conf, info, msg, m, doNothing, instLoc()) proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = diff --git a/doc/astspec.txt b/doc/astspec.txt index c49f7bcc2..b4b8b34b5 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1135,7 +1135,7 @@ AST: .. code-block:: nim # ... nnkTypeClassTy( # note this isn't nnkConceptTy! - nnkArglist( + nnkArgList( # ... idents for x, y, z ) # ... diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index cf2e0c247..fc46a2a14 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1283,7 +1283,7 @@ all the arguments, but also the matched operators in reverse polish notation: echo x + y * z - x This passes the expression `x + y * z - x` to the `optM` macro as -an `nnkArglist` node containing:: +an `nnkArgList` node containing:: Arglist Sym "x" diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 5a556fc8d..8d6258e80 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -78,7 +78,7 @@ type nnkSharedTy, # 'shared T' nnkEnumTy, nnkEnumFieldDef, - nnkArglist, nnkPattern + nnkArgList, nnkPattern nnkHiddenTryStmt, nnkClosure, nnkGotoState, diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index 163f9303b..89eb24bb9 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -322,7 +322,7 @@ macro html*(e: varargs[untyped]): untyped = macro hr*(): untyped = ## Generates the HTML `hr` element. - result = xmlCheckedTag(newNimNode(nnkArglist), "hr", commonAttr, "", true) + result = xmlCheckedTag(newNimNode(nnkArgList), "hr", commonAttr, "", true) macro i*(e: varargs[untyped]): untyped = ## Generates the HTML `i` element. diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim index 6d0a99ab5..f0bcbcc74 100644 --- a/lib/std/private/underscored_calls.nim +++ b/lib/std/private/underscored_calls.nim @@ -39,7 +39,7 @@ proc underscoredCall(n, arg0: NimNode): NimNode = result.add arg0 proc underscoredCalls*(result, calls, arg0: NimNode) = - expectKind calls, {nnkArglist, nnkStmtList, nnkStmtListExpr} + expectKind calls, {nnkArgList, nnkStmtList, nnkStmtListExpr} for call in calls: if call.kind in {nnkStmtList, nnkStmtListExpr}: diff --git a/tests/astspec/tastspec.nim b/tests/astspec/tastspec.nim index 3413d32f3..e2cfed277 100644 --- a/tests/astspec/tastspec.nim +++ b/tests/astspec/tastspec.nim @@ -929,7 +929,7 @@ static: (x & y & z) is string ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst: - of nnkTypeDef(_, _, nnkTypeClassTy(nnkArglist, _, _, nnkStmtList)): + of nnkTypeDef(_, _, nnkTypeClassTy(nnkArgList, _, _, nnkStmtList)): # note this isn't nnkConceptTy! echo "ok" diff --git a/tests/casestmt/tincompletecaseobject.nim b/tests/casestmt/tincompletecaseobject.nim index 909ee4e1c..aa5deda7a 100644 --- a/tests/casestmt/tincompletecaseobject.nim +++ b/tests/casestmt/tincompletecaseobject.nim @@ -1,6 +1,6 @@ discard """ errormsg: ''' -not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArglist, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr} +not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArgList, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr} ''' """ @@ -62,7 +62,7 @@ type nnkSharedTy, # 'shared T' nnkEnumTy, nnkEnumFieldDef, - nnkArglist, nnkPattern + nnkArgList, nnkPattern nnkReturnToken, nnkClosure, nnkGotoState, diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index 19c706a82..a964f46ba 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -64,7 +64,7 @@ block t7723: block t8706: macro varargsLen(args:varargs[untyped]): untyped = - doAssert args.kind == nnkArglist + doAssert args.kind == nnkArgList doAssert args.len == 0 result = newLit(args.len) From 30959e24bd8840f16472d1f621e1a349d9ccae78 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sat, 27 Mar 2021 10:36:39 +0100 Subject: [PATCH 2285/4254] Update security policy (#17522) * Update security policy * Update security.md Co-authored-by: Dominik Picheta Co-authored-by: Andreas Rumpf Co-authored-by: Dominik Picheta --- security.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/security.md b/security.md index e8d31b1b9..72a1a3e3d 100644 --- a/security.md +++ b/security.md @@ -2,7 +2,10 @@ ## Supported Versions -Security fixes are provided in new releases and bugfix releases. +Security advisories are published at: +https://github.com/nim-lang/security/security/advisories?state=published + +Security fixes are provided in new releases and in bugfix releases. We do not backport security fixes to older releases. @@ -10,8 +13,8 @@ We do not backport security fixes to older releases. ## Reporting a Vulnerability -Please do not report vulnerabilities via GitHub issues. - -If you have discovered a vulnerability, it is best to notify us about it via +If you have discovered a vulnerability, please notify us about it via security@nim-lang.org in order to set up a meeting where we can discuss the next steps. + +Please do not report vulnerabilities via GitHub issues. From cf5ce7616b3b2dcbe734dee7f48133c5dcf332f9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 27 Mar 2021 12:21:57 +0100 Subject: [PATCH 2286/4254] IC: bugfix (#17533) * cleanups * IC: bugfix --- compiler/ic/ic.nim | 7 +++++-- compiler/transf.nim | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 8017d8b40..b5fed7d4e 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -28,6 +28,7 @@ type PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file definedSymbols: string + moduleFlags: TSymFlags includes: seq[(LitId, string)] # first entry is the module filename itself imports: seq[LitId] # the modules this module depends on toReplay: PackedTree # pragmas and VM specific state to replay. @@ -139,6 +140,7 @@ proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; co m.sh = Shared() c.thisModule = moduleSym.itemId.module c.config = config + m.moduleFlags = moduleSym.flags m.bodies = newTreeFrom(m.topLevel) m.toReplay = newTreeFrom(m.topLevel) @@ -511,6 +513,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef f.loadSection configSection f.loadPrim m.definedSymbols + f.loadPrim m.moduleFlags f.loadPrim m.cfg if f.err == ok and not configIdentical(m, config) and not ignoreConfig: @@ -581,6 +584,7 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac f.storeHeader() f.storeSection configSection f.storePrim m.definedSymbols + f.storePrim m.moduleFlags f.storePrim m.cfg template storeSeqSection(section, data) {.dirty.} = @@ -909,8 +913,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa info: newLineInfo(fileIdx, 1, 1), position: int(fileIdx)) m.module.owner = newPackage(conf, cache, fileIdx) - if fileIdx == conf.projectMainIdx2: - m.module.flags.incl sfMainModule + m.module.flags = m.fromDisk.moduleFlags proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex; m: var LoadedModule) = diff --git a/compiler/transf.nim b/compiler/transf.nim index d2d9156aa..48c737f46 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -29,8 +29,7 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, cache: bool): import closureiters, lambdalifting type - PTransCon = ref TTransCon - TTransCon{.final.} = object # part of TContext; stackable + PTransCon = ref object # part of TContext; stackable mapping: TIdNodeTable # mapping from symbols to nodes owner: PSym # current owner forStmt: PNode # current for stmt @@ -40,7 +39,7 @@ type # if we encounter the 2nd yield statement next: PTransCon # for stacking - TTransfContext = object + PTransf = ref object module: PSym transCon: PTransCon # top of a TransCon stack inlining: int # > 0 if we are in inlining context (copy vars) @@ -49,7 +48,6 @@ type deferDetected, tooEarly: bool graph: ModuleGraph idgen: IdGenerator - PTransf = ref TTransfContext proc newTransNode(a: PNode): PNode {.inline.} = result = shallowCopy(a) From 9c52009de61a119dda2def870e5fb21581dafc9a Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 28 Mar 2021 01:12:11 +0800 Subject: [PATCH 2287/4254] close #7012 add testcase (#17537) --- tests/tuples/t7012.nim | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/tuples/t7012.nim diff --git a/tests/tuples/t7012.nim b/tests/tuples/t7012.nim new file mode 100644 index 000000000..32d441ddd --- /dev/null +++ b/tests/tuples/t7012.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "illegal recursion in type 'Node'" +""" + +type Node[T] = tuple + next: ref Node[T] +var n: Node[int] \ No newline at end of file From d3705b253c155a6f129a7f26ea9435a0ab45143f Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 28 Mar 2021 01:18:35 +0800 Subject: [PATCH 2288/4254] close #5792 with testcase (#17536) --- tests/sets/t5792.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/sets/t5792.nim diff --git a/tests/sets/t5792.nim b/tests/sets/t5792.nim new file mode 100644 index 000000000..efc38b1bc --- /dev/null +++ b/tests/sets/t5792.nim @@ -0,0 +1,17 @@ +discard """ + matrix: "--gc:refc; --gc:arc" +""" + +type + T = enum + a + b + c + U = object + case k: T + of a: + x: int + of {b, c} - {a}: + y: int + +discard U(k: b, y: 1) From bbe4cf4703903081553fe066ece5a57a5f190493 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 27 Mar 2021 12:03:14 -0700 Subject: [PATCH 2289/4254] followup custom literals (#17500) --- compiler/condsyms.nim | 1 + compiler/ic/packed_ast.nim | 1 + compiler/lexer.nim | 25 ++++----- doc/manual.rst | 2 +- tests/lexer/tcustom_numeric_literals.nim | 69 ++++++++++++++++++------ tests/lexer/tstrlits.nim | 19 +++++++ tests/lexer/tunary_minus.nim | 10 +++- 7 files changed, 94 insertions(+), 33 deletions(-) create mode 100644 tests/lexer/tstrlits.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index aa955e763..8d11dae7c 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -130,3 +130,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasWarningAsError") defineSymbol("nimHasHintAsError") defineSymbol("nimHasSpellSuggest") + defineSymbol("nimHasCustomLiterals") diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 353cc3a42..1075664cb 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -333,6 +333,7 @@ template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1) when false: + # xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below? proc strLit*(tree: PackedTree; n: NodePos): lent string = assert n.kind == nkStrLit result = tree.sh.strings[LitId tree.nodes[n.int].operand] diff --git a/compiler/lexer.nim b/compiler/lexer.nim index ecf6cb0d9..cca7765e5 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -412,14 +412,12 @@ proc getNumber(L: var Lexer, result: var Token) = customLitPossible = true if L.buf[postPos] in SymChars: - var suffixAsLower = newStringOfCap(10) var suffix = newStringOfCap(10) while true: - let c = L.buf[postPos] - suffix.add c - suffixAsLower.add toLowerAscii(c) + suffix.add L.buf[postPos] inc postPos if L.buf[postPos] notin SymChars+{'_'}: break + let suffixAsLower = suffix.toLowerAscii case suffixAsLower of "f", "f32": result.tokType = tkFloat32Lit of "d", "f64": result.tokType = tkFloat64Lit @@ -433,16 +431,15 @@ proc getNumber(L: var Lexer, result: var Token) = of "u16": result.tokType = tkUInt16Lit of "u32": result.tokType = tkUInt32Lit of "u64": result.tokType = tkUInt64Lit + elif customLitPossible: + # remember the position of the `'` so that the parser doesn't + # have to reparse the custom literal: + result.iNumber = len(result.literal) + result.literal.add '\'' + result.literal.add suffix + result.tokType = tkCustomLit else: - if customLitPossible: - # remember the position of the ``'`` so that the parser doesn't - # have to reparse the custom literal: - result.iNumber = len(result.literal) - result.literal.add '\'' - result.literal.add suffix - result.tokType = tkCustomLit - else: - lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) + lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) else: lexMessageLitNum(L, "invalid number suffix: '$1'", errPos) @@ -467,7 +464,7 @@ proc getNumber(L: var Lexer, result: var Token) = if L.buf[pos] != '_': xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0')) inc(pos) - # 'c', 'C' is deprecated + # 'c', 'C' is deprecated (a warning is issued elsewhere) of 'o', 'c', 'C': result.base = base8 while pos < endpos: diff --git a/doc/manual.rst b/doc/manual.rst index 51c434c7b..fdc744bc7 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -536,7 +536,7 @@ Numeric literals have the form:: FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX - CUSTOM_NUMERIC_LIT = (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) '\'' CUSTOM_NUMERIC_SUFFIX + CUSTOM_NUMERIC_LIT = (FLOAT_LIT | INT_LIT) '\'' CUSTOM_NUMERIC_SUFFIX # CUSTOM_NUMERIC_SUFFIX is any Nim identifier that is not # a pre-defined type suffix. diff --git a/tests/lexer/tcustom_numeric_literals.nim b/tests/lexer/tcustom_numeric_literals.nim index a2f355b4d..17933950a 100644 --- a/tests/lexer/tcustom_numeric_literals.nim +++ b/tests/lexer/tcustom_numeric_literals.nim @@ -46,6 +46,7 @@ assertAST dedent """ -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap proc `'wrap`(number: string): string = "[[" & number & "]]" +proc wrap2(number: string): string = "[[" & number & "]]" doAssert lispReprStr(-1'wrap) == """(DotExpr (RStrLit "-1") (Ident "\'wrap"))""" template main = @@ -126,25 +127,59 @@ template main = doAssert -12'fooplusopt(2) == ("-12", 2) doAssert -12'fooplusopt() == ("-12", 99) doAssert -12'fooplusopt == ("-12", 99) - macro `'bar`(a: static string): untyped = - var infix = newNimNode(nnkInfix) - infix.add newIdentNode("&") - infix.add newLit("got ") - infix.add newLit(a.repr) - result = newNimNode(nnkStmtList) - result.add infix - doAssert -12'bar == "got \"-12\"" + macro `'bar`(a: static string): untyped = newLit(a.repr) + doAssert -12'bar == "\"-12\"" macro deb(a): untyped = newLit(a.repr) doAssert deb(-12'bar) == "-12'bar" - # macro metawrap(): untyped = - # func wrap1(a: string): string = "{" & a & "}" - # func `'wrap2`(a: string): string = "{" & a & "}" - # result = quote do: - # let a1 = wrap1"-128" - # let a2 = -128'wrap2 - # metawrap() - # doAssert a1 == "{-128}" - # doAssert a2 == "{-128}" + + block: # bug 1 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 + macro deb1(a): untyped = newLit a.repr + macro deb2(a): untyped = newLit a.lispRepr + doAssert deb1(-12'wrap) == "-12'wrap" + doAssert deb1(-12'nonexistant) == "-12'nonexistant" + doAssert deb2(-12'nonexistant) == """(DotExpr (RStrLit "-12") (Ident "\'nonexistant"))""" + when false: # xxx bug: + # this holds: + doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Sym "wrap2"))""" + doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Sym "\'wrap"))""" + # but instead this should hold: + doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))""" + doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))""" + + block: # bug 2 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 + template toSuf(`'suf`): untyped = + let x = -12'suf + x + doAssert toSuf(`'wrap`) == "[[-12]]" + + block: # bug 10 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 + proc `myecho`(a: auto): auto = a + template fn1(): untyped = + let a = "abc" + -12'wrap + template fn2(): untyped = + `myecho` -12'wrap + template fn3(): untyped = + -12'wrap + doAssert fn1() == "[[-12]]" + doAssert fn2() == "[[-12]]" + doAssert fn3() == "[[-12]]" + + when false: # xxx this fails; bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947 + #[ + possible workaround: use `genAst` (https://github.com/nim-lang/Nim/pull/17426) and this: + let a3 = `'wrap3`("-128") + ]# + block: + macro metawrap(): untyped = + func wrap1(a: string): string = "{" & a & "}" + func `'wrap3`(a: string): string = "{" & a & "}" + result = quote do: + let a1 = wrap1"-128" + let a2 = -128'wrap3 + metawrap() + doAssert a1 == "{-128}" + doAssert a2 == "{-128}" static: main() main() diff --git a/tests/lexer/tstrlits.nim b/tests/lexer/tstrlits.nim new file mode 100644 index 000000000..8e8250a5b --- /dev/null +++ b/tests/lexer/tstrlits.nim @@ -0,0 +1,19 @@ +discard """ + output: "a\"\"long string\"\"\"\"\"abc\"def_'2'●𝌆𝌆A" +""" +# Test the new different string literals + +const + tripleEmpty = """"long string"""""""" # "long string """"" + + rawQuote = r"a""" + + raw = r"abc""def" + + escaped = "\x5f'\50'\u25cf\u{1D306}\u{1d306}\u{41}" + + +stdout.write(rawQuote) +stdout.write(tripleEmpty) +stdout.write(raw) +stdout.writeLine(escaped) diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim index 639911fcd..87b3cb52d 100644 --- a/tests/lexer/tunary_minus.nim +++ b/tests/lexer/tunary_minus.nim @@ -51,8 +51,17 @@ template main = doAssert x() == minusOne: "unable to handle negatives after semi-colon" + block: doAssert -0b111 == -7 doAssert -0xff == -255 + doAssert -128'i8 == (-128).int8 + doAssert $(-128'i8) == "-128" + doAssert -32768'i16 == int16.low + doAssert -2147483648'i32 == int32.low + when int.sizeof > 4: + doAssert -9223372036854775808 == int.low + when not defined(js): + doAssert -9223372036854775808 == int64.low block: # check when a minus (-) is an unary op doAssert -one == minusOne: @@ -68,6 +77,5 @@ template main = doAssert 4 - one == 3: "unable to handle subtraction with surrounding spaces with an identifier" - static: main() main() From d96469037ecc1ee7982b420cbe6ce34e91d18b01 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sat, 27 Mar 2021 18:43:24 -0600 Subject: [PATCH 2290/4254] Fixed embedded nimscript imports (#17425) --- compiler/options.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 2d63043df..2c8d43733 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -812,10 +812,11 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi for candidate in stdlibDirs: let path = (conf.libpath.string / candidate / stripped) if fileExists(path): - m = path + result = AbsoluteFile path break - let currentPath = currentModule.splitFile.dir - result = AbsoluteFile currentPath / m + else: # If prefixed with std/ why would we add the current module path! + let currentPath = currentModule.splitFile.dir + result = AbsoluteFile currentPath / m if not fileExists(result): result = findFile(conf, m) patchModule(conf) From b77a420d3eb118cc92443e925f48996fe419f662 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Sun, 28 Mar 2021 02:11:51 -0300 Subject: [PATCH 2291/4254] set const arch64 to fix compiling with vcc/icc (#17539) --- lib/system/countbits_impl.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim index d3c003ff7..e0338f8f9 100644 --- a/lib/system/countbits_impl.nim +++ b/lib/system/countbits_impl.nim @@ -18,6 +18,7 @@ const useGCC_builtins* = (defined(gcc) or defined(llvm_gcc) or defined(clang)) and useBuiltins const useICC_builtins* = defined(icc) and useBuiltins const useVCC_builtins* = defined(vcc) and useBuiltins +const arch64 = sizeof(int) == 8 template countBitsImpl(n: uint32): int = # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel From 6a355a4db05addb01fc02df0243c540f100bf107 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 28 Mar 2021 00:29:06 -0700 Subject: [PATCH 2292/4254] nim: unbreak CI; testament: add allowedFailure logic for tests that may fail but should still run (#17513) --- testament/categories.nim | 7 +++-- testament/important_packages.nim | 47 ++++++++++++++++---------------- testament/testament.nim | 16 +++++++---- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 86aa1f8af..af6331dde 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -448,7 +448,10 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = (outp, status) = execCmdEx(cmd, workingDir = workingDir2) status == QuitSuccess if not ok: - addResult(r, test, targetC, "", cmd & "\n" & outp, reFailed) + if pkg.allowFailure: + inc r.passed + inc r.failedButAllowed + addResult(r, test, targetC, "", cmd & "\n" & outp, reFailed, allowFailure = pkg.allowFailure) continue outp @@ -461,7 +464,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = discard tryCommand("nimble install --depsOnly -y", maxRetries = 3) discard tryCommand(pkg.cmd, reFailed = reBuildFailed) inc r.passed - r.addResult(test, targetC, "", "", reSuccess) + r.addResult(test, targetC, "", "", reSuccess, allowFailure = pkg.allowFailure) errors = r.total - r.passed if errors == 0: diff --git a/testament/important_packages.nim b/testament/important_packages.nim index eb0196f70..8a8d6ffd0 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -22,22 +22,26 @@ When this is the case, a workaround is to test this package here by adding `--pa type NimblePackage* = object name*, cmd*, url*: string useHead*: bool + allowFailure*: bool + ## When true, we still run the test but the test is allowed to fail. + ## This is useful for packages that currently fail but that we still want to + ## run in CI, e.g. so that we can monitor when they start working again and + ## are reminded about those failures without making CI fail for unrelated PRs. var packages*: seq[NimblePackage] -proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true) = - packages.add NimblePackage(name: name, cmd: cmd, url: url, useHead: useHead) +proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true, allowFailure = false) = + packages.add NimblePackage(name: name, cmd: cmd, url: url, useHead: useHead, allowFailure: allowFailure) -# pkg "alea" +pkg "alea", allowFailure = true pkg "argparse" -when false: - pkg "arraymancer", "nim c tests/tests_cpu.nim" -# pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim" +pkg "arraymancer", "nim c tests/tests_cpu.nim", allowFailure = true +pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim", allowFailure = true pkg "awk" pkg "bigints", url = "https://github.com/Araq/nim-bigints" pkg "binaryheap", "nim c -r binaryheap.nim" pkg "BipBuffer" -# pkg "blscurve" # pending https://github.com/status-im/nim-blscurve/issues/39 +pkg "blscurve", allowFailure = true # pending https://github.com/status-im/nim-blscurve/issues/39 pkg "bncurve" pkg "brainfuck", "nim c -d:release -r tests/compile.nim" pkg "bump", "nim c --gc:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump" @@ -45,16 +49,13 @@ pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" pkg "cello" pkg "chroma" -# pkg "chronicles", "nim c -o:chr -r chronicles.nim" -# when not defined(osx): # testdatagram.nim(560, 54): Check failed -# pkg "chronos", "nim c -r -d:release tests/testall" - # pending https://github.com/nim-lang/Nim/issues/17130 - +pkg "chronicles", "nim c -o:chr -r chronicles.nim", allowFailure = true # pending https://github.com/status-im/nim-chronos/issues/169 +pkg "chronos", "nim c -r -d:release tests/testall", allowFailure = true # pending https://github.com/nim-lang/Nim/issues/17130 pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" pkg "compactdict" pkg "comprehension", "nimble test", "https://github.com/alehander42/comprehension" -# pkg "criterion" # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) +pkg "criterion", allowFailure = true # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) pkg "dashing", "nim c tests/functional.nim" pkg "delaunay" pkg "docopt" @@ -66,12 +67,12 @@ pkg "fusion" pkg "gara" pkg "glob" pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" -# pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup" +pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true pkg "gnuplot", "nim c gnuplot.nim" # pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" # pending https://github.com/nim-lang/Nim/issues/16509 pkg "hts", "nim c -o:htss src/hts.nim" -# pkg "httpauth" +pkg "httpauth", allowFailure = true pkg "illwill", "nimble examples" pkg "inim" pkg "itertools", "nim doc src/itertools.nim" @@ -87,28 +88,28 @@ pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" pkg "neo", "nim c -d:blas=openblas tests/all.nim" -# pkg "nesm", "nimble tests" # notice plural 'tests' -# pkg "nico" +pkg "nesm", "nimble tests", allowFailure = true # notice plural 'tests' +pkg "nico", allowFailure = true pkg "nicy", "nim c -r src/nicy.nim" pkg "nigui", "nim c -o:niguii -r src/nigui.nim" pkg "nimcrypto", "nim r --path:. tests/testall.nim" # `--path:.` workaround needed, see D20210308T165435 pkg "NimData", "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", "nim c src/nimes.nim" pkg "nimfp", "nim c -o:nfp -r src/fp.nim" -# pkg "nimgame2", "nim c nimgame2/nimgame.nim" # XXX Doesn't work with deprecated 'randomize', will create a PR. +pkg "nimgame2", "nim c nimgame2/nimgame.nim", allowFailure = true # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" pkg "nimlsp" pkg "nimly", "nim c -r tests/test_readme_example.nim" -# pkg "nimongo", "nimble test_ci" -# pkg "nimph", "nimble test", "https://github.com/disruptek/nimph" +pkg "nimongo", "nimble test_ci", allowFailure = true +pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true pkg "nimpy", "nim c -r tests/nimfrompy.nim" pkg "nimquery" pkg "nimsl" pkg "nimsvg" pkg "nimterop", "nimble minitest" pkg "nimwc", "nim c nimwc.nim" -# pkg "nimx", "nim c --threads:on test/main.nim" -# pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" +pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true +pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter", allowFailure = true pkg "norm", "nim c -r tests/sqlite/trows.nim" pkg "npeg", "nimble testarc" pkg "numericalnim", "nim c -r tests/test_integrate.nim" @@ -150,7 +151,7 @@ pkg "unicodedb", "nim c -d:release -r tests/tests.nim" pkg "unicodeplus", "nim c -d:release -r tests/tests.nim" pkg "unpack" pkg "websocket", "nim c websocket.nim" -# pkg "winim" +pkg "winim", allowFailure = true pkg "with" pkg "ws" pkg "yaml", "nim build" diff --git a/testament/testament.nim b/testament/testament.nim index 6fc7e32ce..462c0a57c 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -66,7 +66,8 @@ proc isNimRepoTests(): bool = type Category = distinct string TResults = object - total, passed, skipped: int + total, passed, failedButAllowed, skipped: int + ## xxx rename passed to passedOrAllowedFailure data: string TTest = object name: string @@ -212,6 +213,7 @@ proc callCCompiler(cmdTemplate, filename, options: string, proc initResults: TResults = result.total = 0 result.passed = 0 + result.failedButAllowed = 0 result.skipped = 0 result.data = "" @@ -239,16 +241,20 @@ template maybeStyledEcho(args: varargs[untyped]): untyped = proc `$`(x: TResults): string = - result = ("Tests passed: $1 / $3
                                      \n" & - "Tests skipped: $2 / $3
                                      \n") % - [$x.passed, $x.skipped, $x.total] + result = """ +Tests passed or allowed to fail: $2 / $1
                                      +Tests failed and allowed to fail: $3 / $1
                                      +Tests skipped: $4 / $1
                                      +""" % [$x.total, $x.passed, $x.failedButAllowed, $x.skipped] proc addResult(r: var TResults, test: TTest, target: TTarget, - expected, given: string, successOrig: TResultEnum) = + expected, given: string, successOrig: TResultEnum, allowFailure = false) = # test.name is easier to find than test.name.extractFilename # A bit hacky but simple and works with tests/testament/tshould_not_work.nim var name = test.name.replace(DirSep, '/') name.add ' ' & $target + if allowFailure: + name.add " (allowed to fail) " if test.options.len > 0: name.add ' ' & test.options let duration = epochTime() - test.startTime From c86fdfa1ee2cbba201b0a6182212ced5e218dc65 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 28 Mar 2021 15:57:22 +0800 Subject: [PATCH 2293/4254] add testcase for #9466 (#17538) --- tests/notnil/tnotnil5.nim | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/notnil/tnotnil5.nim diff --git a/tests/notnil/tnotnil5.nim b/tests/notnil/tnotnil5.nim new file mode 100644 index 000000000..2dcb7f7c3 --- /dev/null +++ b/tests/notnil/tnotnil5.nim @@ -0,0 +1,28 @@ +discard """ + matrix: "--threads:on" +""" + +{.experimental: "parallel".} +{.experimental: "notnil".} +import threadpool + +type + AO = object + x: int + + A = ref AO not nil + +proc process(a: A): A = + return A(x: a.x+1) + +proc processMany(ayys: openArray[A]): seq[A] = + var newAs: seq[FlowVar[A]] + + parallel: + for a in ayys: + newAs.add(spawn process(a)) + for newAflow in newAs: + let newA = ^newAflow + if isNil(newA): + return @[] + result.add(newA) From eb3ed44009fdfea3e67608b68a049c265124d643 Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Sun, 28 Mar 2021 12:44:16 +0200 Subject: [PATCH 2294/4254] system: fix link in `delete` proc (#17550) The `delete` proc had a "See also" link that linked to itself. --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 4c31f20a2..27f976119 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1321,7 +1321,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = ## This is an `O(n)` operation. ## ## See also: - ## * `del <#delete,seq[T],Natural>`_ for O(1) operation + ## * `del <#del,seq[T],Natural>`_ for O(1) operation ## ## .. code-block:: Nim ## var i = @[1, 2, 3, 4, 5] From 207bcabdf29dbaa954a3db778cbd9e4d59ca37ae Mon Sep 17 00:00:00 2001 From: Ardek Romak Date: Sun, 28 Mar 2021 19:57:40 +0300 Subject: [PATCH 2295/4254] Add a getter for all defined Sections in parsecfg (#15450) --- changelog.md | 2 ++ lib/pure/parsecfg.nim | 6 ++++++ tests/stdlib/tparsecfg.nim | 23 +++++++++-------------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index f180e90f9..d3335c2a3 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,8 @@ ## Standard library additions and changes +- Added `sections` iterator in `parsecfg`. + - Make custom op in macros.quote work for all statements. - On Windows the SSL library now checks for valid certificates. diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 23bb09ac4..7f22a9857 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -174,6 +174,7 @@ runnableExamples: import strutils, lexbase, streams, tables import std/private/decode_helpers +import std/private/since include "system/inclrtl" @@ -649,3 +650,8 @@ proc delSectionKey*(dict: var Config, section, key: string) = dict.del(section) else: dict[section].del(key) + +iterator sections*(dict: Config): lent string {.since: (1, 5).} = + ## Iterates through the sections in the `dict`. + for section in dict.keys: + yield section diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim index 5c077bbda..b2e57ac3d 100644 --- a/tests/stdlib/tparsecfg.nim +++ b/tests/stdlib/tparsecfg.nim @@ -2,7 +2,7 @@ discard """ targets: "c js" """ -import parsecfg, streams +import parsecfg, streams, sequtils when not defined(js): from stdtest/specialpaths import buildDir @@ -39,19 +39,14 @@ var ss = newStringStream() dict1.writeConfig(ss) ## Reading a configuration file. -var dict2 = loadConfig(newStringStream(ss.data)) -var charset = dict2.getSectionValue("", "charset") -var threads = dict2.getSectionValue("Package", "--threads") -var pname = dict2.getSectionValue("Package", "name") -var name = dict2.getSectionValue("Author", "name") -var qq = dict2.getSectionValue("Author", "qq") -var email = dict2.getSectionValue("Author", "email") -doAssert charset == "utf-8" -doAssert threads == "on" -doAssert pname == "hello" -doAssert name == "lihf8515" -doAssert qq == "10214028" -doAssert email == "lihaifeng@wxm.com" +let dict2 = loadConfig(newStringStream(ss.data)) +doAssert dict2.getSectionValue("", "charset") == "utf-8" +doAssert dict2.getSectionValue("Package", "--threads") == "on" +doAssert dict2.getSectionValue("Package", "name") == "hello" +doAssert dict2.getSectionValue("Author", "name") == "lihf8515" +doAssert dict2.getSectionValue("Author", "qq") == "10214028" +doAssert dict2.getSectionValue("Author", "email") == "lihaifeng@wxm.com" +doAssert toSeq(dict2.sections) == @["", "Package", "Author"] ## Modifying a configuration file. var dict3 = loadConfig(newStringStream(ss.data)) From a5600e49df71463cda6bd0a062e02c8bdd48da0c Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 07:40:37 +0800 Subject: [PATCH 2296/4254] close #9622 add testcase (#17557) * fix nim js cmp fails at CT * close #9622 add testcase --- tests/vm/t9622.nim | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/vm/t9622.nim diff --git a/tests/vm/t9622.nim b/tests/vm/t9622.nim new file mode 100644 index 000000000..214ab0f19 --- /dev/null +++ b/tests/vm/t9622.nim @@ -0,0 +1,30 @@ +discard """ + targets: "c cpp" + matrix: "--gc:refc; --gc:arc" +""" + +type + GlobNodeKind = enum + LiteralIdent, + Group + + GlobNode = object + case kind: GlobNodeKind + of LiteralIdent: + value: string + of Group: + values: seq[string] + + PathSegment = object + children: seq[GlobNode] + + GlobPattern = seq[PathSegment] + +proc parseImpl(): GlobPattern = + if result.len == 0: + result.add PathSegment() + result[^1].children.add GlobNode(kind: LiteralIdent) + +block: + const pattern = parseImpl() + doAssert $pattern == """@[(children: @[(kind: LiteralIdent, value: "")])]""" From a36816fc047d4ab2c4f80056c207f117a635a5d4 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 09:11:07 +0800 Subject: [PATCH 2297/4254] follow up #17539 (#17548) * fix nim js cmp fails at CT * follow up #17539 --- lib/pure/bitops.nim | 1 - lib/system/countbits_impl.nim | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 377602e75..4ef190c1b 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -413,7 +413,6 @@ func fastlog2Nim(x: uint64): int {.inline.} = import system/countbits_impl -const arch64 = sizeof(int) == 8 const useBuiltinsRotate = (defined(amd64) or defined(i386)) and (defined(gcc) or defined(clang) or defined(vcc) or (defined(icl) and not defined(cpp))) and useBuiltins diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim index e0338f8f9..184f97bd4 100644 --- a/lib/system/countbits_impl.nim +++ b/lib/system/countbits_impl.nim @@ -18,7 +18,7 @@ const useGCC_builtins* = (defined(gcc) or defined(llvm_gcc) or defined(clang)) and useBuiltins const useICC_builtins* = defined(icc) and useBuiltins const useVCC_builtins* = defined(vcc) and useBuiltins -const arch64 = sizeof(int) == 8 +const arch64* = sizeof(int) == 8 template countBitsImpl(n: uint32): int = # generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel From e5be216ccbf1e3453e0076f2f260ddda85a5f27a Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 11:21:27 +0800 Subject: [PATCH 2298/4254] [docs]close #12580 (#17549) --- lib/system/memalloc.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index fca1db91d..f8ebc8c5f 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -188,8 +188,8 @@ when hasAlloc and not defined(js): cast[ptr T](realloc(p, T.sizeof * newSize)) proc dealloc*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = - ## Frees the memory allocated with `alloc`, `alloc0` or - ## `realloc`. + ## Frees the memory allocated with `alloc`, `alloc0`, + ## `realloc`, `create` or `createU`. ## ## **This procedure is dangerous!** ## If one forgets to free the memory a leak occurs; if one tries to From b36182b0a4ca13d90c1a19de5b9945289c4f25fd Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 29 Mar 2021 11:49:19 +0300 Subject: [PATCH 2299/4254] Free the certificate after checking in `checkCertName` (#17558) [backport:1.2] * Fix small leak in checkCertName * Size is not needed either * Free the certificate after checking --- lib/pure/net.nim | 7 ++++--- lib/wrappers/openssl.nim | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index b37782271..bb1a14cfd 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -770,10 +770,11 @@ when defineSsl: raiseSSLError("No SSL certificate found.") const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint - const size = 1024 - var peername: string = newString(size) + # https://www.openssl.org/docs/man1.1.1/man3/X509_check_host.html let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint, - X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, peername) + X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, nil) + # https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_certificate.html + X509_free(certificate) if match != 1: raiseSSLError("SSL Certificate check failed.") diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 313ce7d19..ec4740bab 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -809,6 +809,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows): proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.} + proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.} + # Certificates store type PX509_STORE* = SslPtr From 085580a2c8f303acf1654731ebc7dba7e6e501a7 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 16:50:58 +0800 Subject: [PATCH 2300/4254] fix #14010(fix std/registry + arc) (#17551) * fix nim js cmp fails at CT * fix #14010 * Update tests/stdlib/tregistry.nim Co-authored-by: Timothee Cour * Update tregistry.nim Co-authored-by: Timothee Cour --- lib/windows/registry.nim | 18 ++++++++++-------- tests/stdlib/tregistry.nim | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 tests/stdlib/tregistry.nim diff --git a/lib/windows/registry.nim b/lib/windows/registry.nim index c17f2f455..ab7d0b1fe 100644 --- a/lib/windows/registry.nim +++ b/lib/windows/registry.nim @@ -54,16 +54,18 @@ proc getUnicodeValue*(path, key: string; handle: HKEY): string = var newHandle: HKEY call regOpenKeyEx(handle, hh, 0, KEY_READ or KEY_WOW64_64KEY, newHandle) call regGetValue(newHandle, nil, kk, flags, nil, nil, addr bufsize) - var res = newWideCString("", bufsize) - call regGetValue(newHandle, nil, kk, flags, nil, cast[pointer](res), - addr bufsize) - result = res $ bufsize + if bufSize > 0: + var res = newWideCString(bufsize) + call regGetValue(newHandle, nil, kk, flags, nil, addr res[0], + addr bufsize) + result = res $ bufsize call regCloseKey(newHandle) else: - var res = newWideCString("", bufsize) - call regGetValue(handle, hh, kk, flags, nil, cast[pointer](res), - addr bufsize) - result = res $ bufsize + if bufSize > 0: + var res = newWideCString(bufsize) + call regGetValue(handle, hh, kk, flags, nil, addr res[0], + addr bufsize) + result = res $ bufsize proc regSetValue(key: HKEY, lpSubKey, lpValueName: WideCString, dwType: int32; lpData: WideCString; cbData: int32): int32 {. diff --git a/tests/stdlib/tregistry.nim b/tests/stdlib/tregistry.nim new file mode 100644 index 000000000..8bf084f6d --- /dev/null +++ b/tests/stdlib/tregistry.nim @@ -0,0 +1,15 @@ +discard """ + disabled: "unix" + matrix: "--gc:refc; --gc:arc" +""" + +when defined(windows): + import std/registry + + block: # bug #14010 + let path = "Environment" + let key = "D20210328T202842_key" + let val = "D20210328T202842_val" + let handle = HKEY_CURRENT_USER + setUnicodeValue("Environment", key, val, handle) + doAssert getUnicodeValue(path, key, handle) == val From e45b1e3f36f2c4778967410137bb87b8691e6c8c Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 29 Mar 2021 10:24:15 +0100 Subject: [PATCH 2301/4254] Fix net.readLine infine loop #17534 (#17535) * Fix net.readLine infine loop #17534 * fix #17534 add return to template --- lib/pure/net.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index bb1a14cfd..ca109dc22 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1535,6 +1535,7 @@ proc readLine*(socket: Socket, line: var string, timeout = -1, if flags.isDisconnectionError(lastError): setLen(line, 0) socket.socketError(n, lastError = lastError, flags = flags) + return var waited: Duration From ab57e7f244fb44fbd283de1fcb16c9c9a6fece42 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 29 Mar 2021 12:42:34 +0200 Subject: [PATCH 2302/4254] added a simple 'koch branchdone' command to speed up my workflow (#17563) --- koch.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/koch.nim b/koch.nim index 6f1da8165..3b00d3564 100644 --- a/koch.nim +++ b/koch.nim @@ -664,6 +664,13 @@ proc showHelp() = quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)), CompileDate, CompileTime], QuitSuccess) +proc branchDone() = + let thisBranch = execProcess("git symbolic-ref --short HEAD").strip() + if thisBranch != "devel" and thisBranch != "": + exec("git checkout devel") + exec("git branch -D " & thisBranch) + exec("git pull --rebase") + when isMainModule: var op = initOptParser() var @@ -722,6 +729,7 @@ when isMainModule: let suffix = if latest: HeadHash else: FusionStableHash exec("nimble install -y fusion@$#" % suffix) of "ic": icTest(op.cmdLineRest) + of "branchdone": branchDone() else: showHelp() break of cmdEnd: break From 9e3960e83dea1b00fe670fc78e74cfd6fafd53b2 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:44:31 +0200 Subject: [PATCH 2303/4254] Small doc improvements for `std/with` (#17556) --- lib/std/with.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/std/with.nim b/lib/std/with.nim index 79afd61a4..c7338b4e4 100644 --- a/lib/std/with.nim +++ b/lib/std/with.nim @@ -12,15 +12,16 @@ ## and https://github.com/nim-lang/RFCs/issues/192 for details leading to this ## particular design. ## -## **Since** version 1.2. +## **Since:** version 1.2. import macros, private / underscored_calls macro with*(arg: typed; calls: varargs[untyped]): untyped = - ## This macro provides the `chaining`:idx: of function calls. + ## This macro provides `chaining`:idx: of function calls. ## It does so by patching every call in `calls` to ## use `arg` as the first argument. - ## **This evaluates `arg` multiple times!** + ## + ## .. caution:: This evaluates `arg` multiple times! runnableExamples: var x = "yay" with x: From 8b26b3ad0d6c9458ac31170a95d956347a55627e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 29 Mar 2021 03:46:53 -0700 Subject: [PATCH 2304/4254] remove docutils.nimble (not a real nimble package, and affected canonical imports) (#17544) * remove docutils.nimble (not a real nimble package, and affected canonical imports) * cleanup redundant references --- lib/packages/docutils/docutils.nimble | 4 ---- lib/packages/docutils/docutils.nimble.old | 7 +++++++ lib/packages/docutils/highlite.nim | 2 -- lib/packages/docutils/rst.nim | 3 --- lib/packages/docutils/rstast.nim | 2 -- lib/packages/docutils/rstgen.nim | 2 -- 6 files changed, 7 insertions(+), 13 deletions(-) delete mode 100644 lib/packages/docutils/docutils.nimble create mode 100644 lib/packages/docutils/docutils.nimble.old diff --git a/lib/packages/docutils/docutils.nimble b/lib/packages/docutils/docutils.nimble deleted file mode 100644 index f1683c515..000000000 --- a/lib/packages/docutils/docutils.nimble +++ /dev/null @@ -1,4 +0,0 @@ -version = "0.10.0" -author = "Andreas Rumpf" -description = "Nim's reStructuredText processor." -license = "MIT" diff --git a/lib/packages/docutils/docutils.nimble.old b/lib/packages/docutils/docutils.nimble.old new file mode 100644 index 000000000..f97c3bdde --- /dev/null +++ b/lib/packages/docutils/docutils.nimble.old @@ -0,0 +1,7 @@ +# xxx disabled this as this isn't really a nimble package and it affects logic +# used to compute canonical imports, refs https://github.com/nim-lang/Nim/pull/16999#issuecomment-805442914 + +version = "0.10.0" +author = "Andreas Rumpf" +description = "Nim's reStructuredText processor." +license = "MIT" diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 8c91e0a8e..2655a7ea3 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -11,8 +11,6 @@ ## Currently only few languages are supported, other languages may be added. ## The interface supports one language nested in another. ## -## **Note:** Import `packages/docutils/highlite` to use this module -## ## You can use this to build your own syntax highlighting, check this example: ## ## .. code::nim diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index adc83c9af..6845f61b9 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -142,9 +142,6 @@ ## See `packages/docutils/rstgen module `_ to know how to ## generate HTML or Latex strings to embed them into your documents. ## -## .. Tip:: Import ``packages/docutils/rst`` to use this module -## programmatically. -## ## .. _quick introduction: https://docutils.sourceforge.io/docs/user/rst/quickstart.html ## .. _RST reference: https://docutils.sourceforge.io/docs/user/rst/quickref.html ## .. _RST specification: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index c68df7daa..ff34da2d1 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -8,8 +8,6 @@ # ## This module implements an AST for the `reStructuredText`:idx: parser. -## -## **Note:** Import ``packages/docutils/rstast`` to use this module import strutils, json diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index c52a0fdcc..30c7f3080 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -38,8 +38,6 @@ ## * The same goes for footnotes/citations links: they point to themselves. ## No backreferences are generated since finding all references of a footnote ## can be done by simply searching for [footnoteName]. -## -## .. Tip: Import ``packages/docutils/rstgen`` to use this module import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, algorithm, parseutils From c6dc9c02551e93fd4c53e48fd7fa8a0df7843267 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 29 Mar 2021 03:48:00 -0700 Subject: [PATCH 2305/4254] fixes #17437 - crash where error reporting > 1 (#17547) * fixes #17437 * Fix bug reference comment Co-authored-by: Timothee Cour * [skip ci] describe why we have hasError Co-authored-by: Timothee Cour --- compiler/semobjconstr.nim | 16 ++++++++++++---- tests/objects/t17437.nim | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 tests/objects/t17437.nim diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 792488c9f..dea187ea7 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -380,7 +380,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = if t == nil: localError(c.config, n.info, errGenerated, "object constructor needs an object type") - return + return errorNode(c, result) t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned}) if t.kind == tyRef: @@ -392,17 +392,19 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result.typ.flags.incl tfHasOwned if t.kind != tyObject: localError(c.config, n.info, errGenerated, "object constructor needs an object type") - return + return errorNode(c, result) # Check if the object is fully initialized by recursively testing each # field (if this is a case object, initialized fields in two different # branches will be reported as an error): var constrCtx = initConstrContext(t, result) let initResult = semConstructTypeAux(c, constrCtx, flags) + var hasError = false # needed to split error detect/report for better msgs # It's possible that the object was not fully initialized while # specifying a .requiresInit. pragma: if constrCtx.missingFields.len > 0: + hasError = true localError(c.config, result.info, "The $1 type requires the following fields to be initialized: $2.", [t.sym.name.s, listSymbolNames(constrCtx.missingFields)]) @@ -415,6 +417,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = if nfSem notin field.flags: if field.kind != nkExprColonExpr: invalidObjConstr(c, field) + hasError = true continue let id = considerQuotedIdent(c, field[0]) # This node was not processed. There are two possible reasons: @@ -423,10 +426,15 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = let prevId = considerQuotedIdent(c, result[j][0]) if prevId.id == id.id: localError(c.config, field.info, errFieldInitTwice % id.s) - return + hasError = true + break # 2) No such field exists in the constructed type localError(c.config, field.info, errUndeclaredFieldX % id.s) - return + hasError = true + break if initResult == initFull: incl result.flags, nfAllFieldsSet + + # wrap in an error see #17437 + if hasError: result = errorNode(c, result) diff --git a/tests/objects/t17437.nim b/tests/objects/t17437.nim new file mode 100644 index 000000000..b5c0e0525 --- /dev/null +++ b/tests/objects/t17437.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim check $file" + errormsg: "" + nimout: ''' +t17437.nim(20, 16) Error: undeclared identifier: 'x' +t17437.nim(20, 16) Error: expression 'x' has no type (or is ambiguous) +t17437.nim(20, 19) Error: incorrect object construction syntax +t17437.nim(20, 19) Error: incorrect object construction syntax +t17437.nim(20, 12) Error: expression '' has no type (or is ambiguous) +''' +""" + +# bug #17437 invalid object construction should result in error + +type + V = ref object + x, y: int + +proc m = + var v = V(x: x, y) + +m() From 89e0e0f27fe937b0eb7386f6f49f4b66f1d27edb Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 29 Mar 2021 14:06:23 +0300 Subject: [PATCH 2306/4254] Small doc fixes in net (#17566) --- lib/pure/net.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ca109dc22..9be9c6acb 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1427,7 +1427,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): int = ## Higher-level version of `recv`. ## - ## Reads **up to** `size` bytes from `socket` into `buf`. + ## Reads **up to** `size` bytes from `socket` into `data`. ## ## For buffered sockets this function will attempt to read all the requested ## data. It will read this data in `BufferSize` chunks. @@ -1444,8 +1444,6 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, ## A timeout may be specified in milliseconds, if enough data is not received ## within the time specified a TimeoutError exception will be raised. ## - ## **Note**: `data` must be initialised. - ## ## .. warning:: Only the `SafeDisconn` flag is currently supported. data.setLen(size) result = @@ -1464,7 +1462,7 @@ proc recv*(socket: Socket, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): string {.inline.} = ## Higher-level version of `recv` which returns a string. ## - ## Reads **up to** `size` bytes from `socket` into `buf`. + ## Reads **up to** `size` bytes from `socket` into the result. ## ## For buffered sockets this function will attempt to read all the requested ## data. It will read this data in `BufferSize` chunks. From 04520c0ce4ed38a3fbae37731a4979480144c77b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 29 Mar 2021 04:07:14 -0700 Subject: [PATCH 2307/4254] remove std/ prefix from doc/lib.rst now that canonical import is shown in module docs (#17543) * remove std/ prefix from doc/lib.rst now that canonical import is shown in module docs * cleanup top docs for std/sha1 --- doc/lib.rst | 26 +++++++++++++------------- lib/std/sha1.nim | 27 ++++++++++----------------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/doc/lib.rst b/doc/lib.rst index 62e02815c..15b4f70d6 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -90,14 +90,14 @@ Algorithms * `algorithm `_ This module implements some common generic algorithms like sort or binary search. -* `std/enumutils `_ +* `enumutils `_ This module adds functionality for the built-in `enum` type. * `sequtils `_ This module implements operations for the built-in `seq` type which were inspired by functional programming languages. -* `std/setutils `_ +* `setutils `_ This module adds functionality for the built-in `set` type. @@ -125,7 +125,7 @@ Collections * `options `_ The option type encapsulates an optional value. -* `std/packedsets `_ +* `packedsets `_ Efficient implementation of a set of ordinals as a sparse bit set. * `sets `_ @@ -147,7 +147,7 @@ String handling * `cstrutils `_ Utilities for `cstring` handling. -* `std/editdistance `_ +* `editdistance `_ This module contains an algorithm to compute the edit distance between two Unicode strings. @@ -197,14 +197,14 @@ String handling It provides a single proc that does Unicode to ASCII transliterations. Based on Python's Unidecode module. -* `std/wordwrap `_ +* `wordwrap `_ This module contains an algorithm to wordwrap a Unicode string. Time handling ------------- -* `std/monotimes `_ +* `monotimes `_ The `monotimes` module implements monotonic timestamps. * `times `_ @@ -272,7 +272,7 @@ Math libraries * `random `_ Fast and tiny random number generator. -* `std/sysrand `_ +* `sysrand `_ Cryptographically secure pseudorandom number generator. * `rationals `_ @@ -281,7 +281,7 @@ Math libraries * `stats `_ Statistical analysis -* `std/sums `_ +* `sums `_ Accurate summation functions. @@ -357,7 +357,7 @@ Parsers * `json `_ High-performance JSON parser. -* `std/jsonutils `_ +* `jsonutils `_ This module implements a hookable (de)serialization for arbitrary types. * `lexbase `_ @@ -448,7 +448,7 @@ Hashing produce a globally distributed unique ID. This implementation was extracted from the Mongodb interface and it thus binary compatible with a Mongo OID. -* `std/sha1 `_ +* `sha1 `_ This module implements a sha1 encoder and decoder. @@ -465,7 +465,7 @@ Miscellaneous * `coro `_ This module implements experimental coroutines in Nim. -* `std/enumerate `_ +* `enumerate `_ This module implements `enumerate` syntactic sugar based on Nim's macro system. * `logging `_ @@ -480,10 +480,10 @@ Miscellaneous * `unittest `_ Implements a Unit testing DSL. -* `std/varints `_ +* `varints `_ Decode variable-length integers that are compatible with SQLite. -* `std/with `_ +* `with `_ This module implements the `with` macro for easy function chaining. diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index b74b285f8..9c5efed1f 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -6,33 +6,26 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## **Note:** Import `std/sha1` to use this module. -## ## [SHA-1 (Secure Hash Algorithm 1)](https://en.wikipedia.org/wiki/SHA-1) ## is a cryptographic hash function which takes an input and produces ## a 160-bit (20-byte) hash value known as a message digest. ## -## Basic usage -## =========== -## -runnableExamples: - let accessName = secureHash("John Doe") - assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362" - -## .. code-block:: -## let -## a = secureHashFile("myFile.nim") -## b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") -## -## if a == b: -## echo "Files match" -## ## See also ## ======== ## * `base64 module`_ implements a Base64 encoder and decoder ## * `hashes module`_ for efficient computations of hash values for diverse Nim types ## * `md5 module`_ implements the MD5 checksum algorithm +runnableExamples: + let accessName = secureHash("John Doe") + assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362" + +runnableExamples("-r:off"): + let + a = secureHashFile("myFile.nim") + b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") + assert a == b, "files don't match" + import std/strutils from std/endians import bigEndian32, bigEndian64 From 81e54c1d30b7651851b9de56d76b9af81e192504 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 20:22:29 +0800 Subject: [PATCH 2308/4254] Add `hasClosure` to `std/typetraits` (#17501) * fix nim js cmp fails at CT * Add `hasClosure` to `std/effecttraits` * type * Update changelog.md Co-authored-by: Timothee Cour * Update lib/std/effecttraits.nim Co-authored-by: Timothee Cour Co-authored-by: Andreas Rumpf --- changelog.md | 2 + compiler/vmops.nim | 4 ++ lib/pure/typetraits.nim | 11 +++++ tests/stdlib/ttypetraits.nim | 92 ++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 tests/stdlib/ttypetraits.nim diff --git a/changelog.md b/changelog.md index d3335c2a3..be130f780 100644 --- a/changelog.md +++ b/changelog.md @@ -246,6 +246,8 @@ - Added dollar `$` and `len` for `jsre.RegExp`. +- Added `hasClosure` to `std/typetraits`. + ## Language changes diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 5748b41b3..04356fc76 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -316,3 +316,7 @@ proc registerAdditionalOps*(c: PCtx) = let fn = getNode(a, 0) setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or (fn.kind == nkSym and fn.sym.kind == skFunc)) + + registerCallback c, "stdlib.typetraits.hasClosureImpl", proc (a: VmArgs) = + let fn = getNode(a, 0) + setResult(a, fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure)) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 6827e23b1..2527dc26e 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -263,3 +263,14 @@ since (1, 1): type T2 = T genericParamsImpl(T2) + + +proc hasClosureImpl(n: NimNode): bool = discard "see compiler/vmops.nim" + +proc hasClosure*(fn: NimNode): bool {.since: (1, 5, 1).} = + ## Return true if the func/proc/etc `fn` has `closure`. + ## `fn` has to be a resolved symbol of kind `nnkSym`. This + ## implies that the macro that calls this proc should accept `typed` + ## arguments and not `untyped` arguments. + expectKind fn, nnkSym + result = hasClosureImpl(fn) diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim new file mode 100644 index 000000000..de8259ab0 --- /dev/null +++ b/tests/stdlib/ttypetraits.nim @@ -0,0 +1,92 @@ +discard """ + targets: "c cpp js" +""" + +import std/typetraits + + + +macro testClosure(fn: typed, flag: static bool) = + if flag: + doAssert hasClosure(fn) + else: + doAssert not hasClosure(fn) + +block: + proc h1() = + echo 1 + + testClosure(h1, false) + + proc h2() {.nimcall.} = + echo 2 + + testClosure(h2, false) + + +block: + proc fn(): auto = + proc hello() {.nimcall.} = + echo 3 + hello + + let name = fn() + testClosure(name, false) + +block: + proc fn(): auto = + proc hello() = + echo 3 + hello + + let name = fn() + testClosure(name, false) + +block: + proc fn(): auto = + var x = 0 + proc hello() = + echo 3 + inc x + hello + + let name = fn() + testClosure(name, true) + +block: + proc fn(): auto = + var x = 0 + proc hello() {.closure.} = + echo 3 + inc x + hello + + let name = fn() + testClosure(name, true) + +block: + proc fn(): auto = + var x = 0 + proc hello() {.closure.} = + echo 3 + inc x + hello + + let name = fn() + testClosure(name, true) + + let name2 = name + testClosure(name2, true) + +block: + iterator hello(): int = + yield 1 + + testClosure(hello, false) + +when not defined(js): + block: + iterator hello(): int {.closure.}= + yield 1 + + testClosure(hello, true) From e2269f9216e7d46bd446448c7bbeb5fd8ca38d1f Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 20:39:49 +0800 Subject: [PATCH 2309/4254] [docs]fix #17473 (#17565) * fix nim js cmp fails at CT * Add `hasClosure` to `std/effecttraits` * type * Update changelog.md Co-authored-by: Timothee Cour * fix #14011 * Delete ttypetraits.nim * Apply suggestions from code review * fix #17473 * Revert "fix #14011" This reverts commit 0eed97a84b172b198bf4e6de69c04b84ef9d9f93. * Update lib/system.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Timothee Cour Co-authored-by: Andreas Rumpf Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/strutils.nim | 12 ++++++++++-- lib/system.nim | 5 +++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 4098749ce..3680b11de 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2198,13 +2198,21 @@ func insertSep*(s: string, sep = '_', digits = 3): string {.rtl, func escape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, extern: "nsuEscape".} = - ## Escapes a string `s`. See `system.addEscapedChar - ## `_ for the escaping scheme. + ## Escapes a string `s`. + ## + ## .. note:: The escaping scheme is different from + ## `system.addEscapedChar`. + ## + ## * replaces `'\0'..'\31'` and `'\127'..'\255'` by `\xHH` where `HH` is its hexadecimal value + ## * replaces ``\`` by `\\` + ## * replaces `'` by `\'` + ## * replaces `"` by `\"` ## ## The resulting string is prefixed with `prefix` and suffixed with `suffix`. ## Both may be empty strings. ## ## See also: + ## * `addEscapedChar proc`_ ## * `unescape func<#unescape,string,string,string>`_ for the opposite ## operation result = newStringOfCap(s.len + s.len shr 2) diff --git a/lib/system.nim b/lib/system.nim index 27f976119..ba27da0c7 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2839,12 +2839,13 @@ proc addEscapedChar*(s: var string, c: char) {.noSideEffect, inline.} = ## * replaces any `\r` by `\\r` ## * replaces any `\e` by `\\e` ## * replaces any other character not in the set `{\21..\126}` - ## by `\xHH` where `HH` is its hexadecimal value. + ## by `\xHH` where `HH` is its hexadecimal value ## ## The procedure has been designed so that its output is usable for many ## different common syntaxes. ## - ## **Note**: This is **not correct** for producing Ansi C code! + ## .. warning:: This is **not correct** for producing ANSI C code! + ## case c of '\a': s.add "\\a" # \x07 of '\b': s.add "\\b" # \x08 From 1a407402a4614fc9100617f71c2d3c9b8a8367a5 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 29 Mar 2021 16:03:54 +0200 Subject: [PATCH 2310/4254] Typo in vm.nim --- compiler/vm.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index c2ff798a7..d97d2d6e6 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2221,7 +2221,7 @@ proc setupCompileTimeVar*(module: PSym; idgen: IdGenerator; g: ModuleGraph; n: P discard evalConstExprAux(module, idgen, g, nil, n, emStaticStmt) proc prepareVMValue(arg: PNode): PNode = - ## strip nkExprColonExpr from tuple values recurively. That is how + ## strip nkExprColonExpr from tuple values recursively. That is how ## they are expected to be stored in the VM. # Early abort without copy. No transformation takes place. From cfff27529e4ec129daad602d945a2b222145e922 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 29 Mar 2021 16:23:19 +0200 Subject: [PATCH 2311/4254] added nkError to the AST (#17567) * added nkError to the AST * Update lib/core/macros.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update compiler/ast.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- compiler/ast.nim | 1 + compiler/errorhandling.nim | 79 +++++++++++++++++++++++++++++++++++ compiler/renderer.nim | 4 ++ compiler/sempass2.nim | 4 +- lib/core/macros.nim | 3 +- tests/misc/tinvalidnewseq.nim | 2 +- 6 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 compiler/errorhandling.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 1f3d5f129..7d13956e9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -221,6 +221,7 @@ type nkBreakState, # special break statement for easier code generation nkFuncDef, # a func nkTupleConstr # a tuple constructor + nkError # erroneous AST node nkModuleRef # for .rod file support: A (moduleId, itemId) pair nkReplayAction # for .rod file support: A replay action nkNilRodNode # for .rod file support: a 'nil' PNode diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim new file mode 100644 index 000000000..d7092d477 --- /dev/null +++ b/compiler/errorhandling.nim @@ -0,0 +1,79 @@ +# +# +# The Nim Compiler +# (c) Copyright 2021 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains support code for new-styled error +## handling via an `nkError` node kind. + +import ast, renderer, options, lineinfos, strutils, types + +type + ErrorKind* = enum ## expand as you need. + RawTypeMismatchError + ExpressionCannotBeCalled + CustomError + WrongNumberOfArguments + AmbiguousCall + +proc errorSubNode*(n: PNode): PNode = + case n.kind + of nkEmpty..nkNilLit: + result = nil + of nkError: + result = n + else: + result = nil + for i in 0.. 1 + let wrongNode = n[0] + case ErrorKind(n[1].intVal) + of RawTypeMismatchError: + result = "type mismatch" + of ExpressionCannotBeCalled: + result = "expression '$1' cannot be called" % wrongNode[0].renderTree + of CustomError: + result = n[2].strVal + of WrongNumberOfArguments: + result = "wrong number of arguments" + of AmbiguousCall: + let a = n[2].sym + let b = n[3].sym + var args = "(" + for i in 1.. 1: args.add(", ") + args.add(typeToString(wrongNode[i].typ)) + args.add(")") + result = "ambiguous call; both $1 and $2 match for: $3" % [ + getProcHeader(config, a), + getProcHeader(config, b), + args] diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 9ca485f6e..9a599f6fc 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1645,6 +1645,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsons(g, n, c, 0) of nkTypeClassTy: gTypeClassTy(g, n) + of nkError: + putWithSpace(g, tkSymbol, "error") + #gcomma(g, n, c) + gsub(g, n[0], c) else: #nkNone, nkExplicitTypeListCall: internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')') diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f269afe4c..a1572c85e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, varpartitions, typeallowed, nilcheck + modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling when defined(useDfa): import dfa @@ -1136,6 +1136,8 @@ proc track(tracked: PEffects, n: PNode) = dec tracked.leftPartOfAsgn for i in 1 ..< n.len: track(tracked, n[i]) inc tracked.leftPartOfAsgn + of nkError: + localError(tracked.config, n.info, errorToString(tracked.config, n)) else: for i in 0.. Date: Mon, 29 Mar 2021 07:25:27 -0700 Subject: [PATCH 2312/4254] fix https://github.com/nim-lang/RFCs/issues/352: show top-level import for top-level runnableExamples in generated docs (#17542) * fix https://github.com/nim-lang/RFCs/issues/352: show top-level import for top-level runnableExamples in generated docs * use canonical imoprt * fix test --- compiler/docgen.nim | 25 +++++++++++++------- nimdoc/testproject/expected/testproject.html | 12 ++++++---- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index b24a24a2b..f1a9750b7 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -505,7 +505,7 @@ proc runAllExamples(d: PDoc) = proc quoted(a: string): string = result.addQuoted(a) -proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = +proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, code: string] = ## returns `rdoccmd` and source code for this runnableExamples var rdoccmd = "" if n.len < 2 or n.len > 3: globalError(d.conf, n.info, "runnableExamples invalid") @@ -556,7 +556,14 @@ $3 if rdoccmd notin d.exampleGroups: d.exampleGroups[rdoccmd] = ExampleGroup(rdoccmd: rdoccmd, docCmd: d.conf.docCmd, index: d.exampleGroups.len) d.exampleGroups[rdoccmd].code.add "import $1\n" % outp.string.quoted - result = (rdoccmd, code) + + var codeShown: string + if topLevel: # refs https://github.com/nim-lang/RFCs/issues/352 + let title = canonicalImport(d.conf, AbsoluteFile d.filename) + codeShown = "import $#\n$#" % [title, code] + else: + codeShown = code + result = (rdoccmd, codeShown) when false: proc extractImports(n: PNode; result: PNode) = if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}: @@ -576,7 +583,7 @@ type RunnableState = enum rsRunnable rsDone -proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: RunnableState): RunnableState = +proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: RunnableState, topLevel: bool): RunnableState = ##[ Simple state machine to tell whether we render runnableExamples and doc comments. This is to ensure that we can interleave runnableExamples and doc comments freely; @@ -601,7 +608,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: Runnab of nkCallKinds: if isRunnableExamples(n[0]) and n.len >= 2 and n.lastSon.kind == nkStmtList and state in {rsStart, rsComment, rsRunnable}: - let (rdoccmd, code) = prepareExample(d, n) + let (rdoccmd, code) = prepareExample(d, n, topLevel) var msg = "Example:" if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd dispA(d.conf, dest, "\n

                                      $1

                                      \n", @@ -652,19 +659,19 @@ proc getRoutineBody(n: PNode): PNode = proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var Rope) = var n = n var state = rsStart - template fn(n2) = - state = getAllRunnableExamplesImpl(d, n2, dest, state) + template fn(n2, topLevel) = + state = getAllRunnableExamplesImpl(d, n2, dest, state, topLevel) dest.add genComment(d, n).rope case n.kind of routineDefs: n = n.getRoutineBody case n.kind - of nkCommentStmt, nkCallKinds: fn(n) + of nkCommentStmt, nkCallKinds: fn(n, topLevel = false) else: for i in 0..This is the top level module.

                                      Example:

                                      -
                                      import subdir / subdir_b / utils
                                      +
                                      import testproject
                                      +import subdir / subdir_b / utils
                                       doAssert bar(3, 4) == 7
                                       foo(enumValueA, enumValueB)
                                       # bug #11078
                                       for x in "xx": discard
                                      top2

                                      Example:

                                      -
                                      discard "in top2"
                                      top2 after +
                                      import testproject
                                      +discard "in top2"
                                      top2 after

                                      Example:

                                      -
                                      discard "in top3"
                                      top3 after +
                                      import testproject
                                      +discard "in top3"
                                      top3 after

                                      Example:

                                      -
                                      assert 3*2 == 6

                                      +
                                      import testproject
                                      +assert 3*2 == 6

                                      Imports

                                      From 7ad49950bd5ec05f145dc43ae35f51127ea76366 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 29 Mar 2021 23:54:28 +0800 Subject: [PATCH 2313/4254] [os:standalone]fix #14011 (#17564) --- lib/system/chcks.nim | 10 ++++++++-- tests/gc/panicoverride.nim | 14 ++++++++++++++ tests/gc/tstandalone.nim | 14 ++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/gc/panicoverride.nim create mode 100644 tests/gc/tstandalone.nim diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index e0a8bd78e..255d97cb2 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -29,10 +29,16 @@ proc raiseFieldError(f: string) {.compilerproc, noinline.} = sysFatal(FieldDefect, f) proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} = - sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) + when defined(standalone): + sysFatal(RangeDefect, "value out of range") + else: + sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} = - sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) + when defined(standalone): + sysFatal(RangeDefect, "value out of range") + else: + sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} = # todo: better error reporting diff --git a/tests/gc/panicoverride.nim b/tests/gc/panicoverride.nim new file mode 100644 index 000000000..0f28b0b72 --- /dev/null +++ b/tests/gc/panicoverride.nim @@ -0,0 +1,14 @@ + +proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} +proc exit(code: int) {.importc, header: "", cdecl.} + +{.push stack_trace: off, profiler:off.} + +proc rawoutput(s: string) = + printf("%s\n", s) + +proc panic(s: string) {.noreturn.} = + rawoutput(s) + exit(1) + +{.pop.} \ No newline at end of file diff --git a/tests/gc/tstandalone.nim b/tests/gc/tstandalone.nim new file mode 100644 index 000000000..41dad9ba4 --- /dev/null +++ b/tests/gc/tstandalone.nim @@ -0,0 +1,14 @@ +discard """ + matrix: "--os:standalone --gc:none" + exitcode: 1 + output: "value out of range" +""" + +type + rangeType = range[0..1] + +var + r: rangeType = 0 + i = 2 + +r = rangeType(i) From 3f9c51a332dc798e1f4d61480ca8b6048ab281cd Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 30 Mar 2021 00:28:55 +0800 Subject: [PATCH 2314/4254] [nim check]fix #17460 (#17569) --- compiler/semstmts.nim | 2 ++ tests/errmsgs/t17460.nim | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/errmsgs/t17460.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index fee43162e..bbfd49e2a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -726,6 +726,8 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if n[0].kind == nkVarTuple: if n[0].len-1 != iterAfterVarLent.len: localError(c.config, n[0].info, errWrongNumberOfVariables) + return errorNode(c, n) + for i in 0.. Date: Mon, 29 Mar 2021 19:32:49 +0300 Subject: [PATCH 2315/4254] RST: enable parsing of prefix roles (ref #17340) (#17514) --- doc/contributing.rst | 9 ++++++++ lib/packages/docutils/rst.nim | 38 +++++++++++++++++--------------- tests/stdlib/trstgen.nim | 41 +++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/doc/contributing.rst b/doc/contributing.rst index b7188a436..279a4ee94 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -285,6 +285,15 @@ or the first is preferred. +When you specify an *RST role* (highlighting/interpretation marker) do it +in the postfix form for uniformity, that is after \`text in backticks\`. +For example an ``:idx:`` role for referencing a topic ("SQLite" in the +example below) from `Nim Index`_ can be used in doc comment this way: + +.. code-block:: nim + ## A higher level `SQLite`:idx: database wrapper. + +.. _`Nim Index`: https://nim-lang.org/docs/theindex.html Best practices ============== diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 6845f61b9..d331c2c12 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -68,7 +68,7 @@ ## substitution references, standalone hyperlinks, ## internal links (inline and outline) ## + \`interpreted text\` with roles ``:literal:``, ``:strong:``, -## ``emphasis``, ``:sub:``/``:subscript:``, ``:sup:``/``:supscript:`` +## ``emphasis``, ``:sub:``/``:subscript:``, ``:sup:``/``:superscript:`` ## (see `RST roles list`_ for description). ## + inline internal targets ## @@ -1018,6 +1018,16 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) = for i in countup(0, sep - incr): a.add(n.sons[i]) for i in countup(sep + 1, n.len - 2): b.add(n.sons[i]) +proc whichRole(sym: string): RstNodeKind = + case sym + of "idx": result = rnIdx + of "literal": result = rnInlineLiteral + of "strong": result = rnStrongEmphasis + of "emphasis": result = rnEmphasis + of "sub", "subscript": result = rnSub + of "sup", "superscript": result = rnSup + else: result = rnGeneralRole + proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var newKind = n.kind var newSons = n.sons @@ -1042,22 +1052,8 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = result = newRstNode(newKind, newSons) elif match(p, p.idx, ":w:"): # a role: - if nextTok(p).symbol == "idx": - newKind = rnIdx - elif nextTok(p).symbol == "literal": - newKind = rnInlineLiteral - elif nextTok(p).symbol == "strong": - newKind = rnStrongEmphasis - elif nextTok(p).symbol == "emphasis": - newKind = rnEmphasis - elif nextTok(p).symbol == "sub" or - nextTok(p).symbol == "subscript": - newKind = rnSub - elif nextTok(p).symbol == "sup" or - nextTok(p).symbol == "supscript": - newKind = rnSup - else: - newKind = rnGeneralRole + newKind = whichRole(nextTok(p).symbol) + if newKind == rnGeneralRole: let newN = newRstNode(rnInner, n.sons) newSons = @[newN, newLeaf(nextTok(p).symbol)] inc p.idx, 3 @@ -1318,6 +1314,12 @@ proc parseInline(p: var RstParser, father: PRstNode) = var n = newRstNode(rnInlineLiteral) parseUntil(p, n, "``", false) father.add(n) + elif match(p, p.idx, ":w:") and p.tok[p.idx+3].symbol == "`": + let k = whichRole(nextTok(p).symbol) + let n = newRstNode(k) + inc p.idx, 3 + parseUntil(p, n, "`", false) # bug #17260 + father.add(n) elif isInlineMarkupStart(p, "`"): var n = newRstNode(rnInterpretedText) parseUntil(p, n, "`", false) # bug #17260 @@ -1677,7 +1679,7 @@ proc whichSection(p: RstParser): RstNodeKind = elif predNL(p) and currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: result = rnBulletList - elif match(p, p.idx, ":w:") and predNL(p): + elif match(p, p.idx, ":w:E") and predNL(p): # (currentTok(p).symbol == ":") result = rnFieldList elif match(p, p.idx, "(e) ") or match(p, p.idx, "e) ") or diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 0f3890faa..da01c30d2 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1326,6 +1326,47 @@ Test1 output) check("""-doption""" in output) + + test "Roles: subscript prefix/postfix": + let expected = "See some text." + check "See :subscript:`some text`.".toHtml == expected + check "See `some text`:subscript:.".toHtml == expected + + test "Roles: correct parsing from beginning of line": + let expected = "3He is an isotope of helium." + check """:superscript:`3`\ He is an isotope of helium.""".toHtml == expected + check """:sup:`3`\ He is an isotope of helium.""".toHtml == expected + check """`3`:sup:\ He is an isotope of helium.""".toHtml == expected + check """`3`:superscript:\ He is an isotope of helium.""".toHtml == expected + + test "(not) Roles: check escaping 1": + let expected = """See :subscript:""" & + """some text.""" + check """See \:subscript:`some text`.""".toHtml == expected + check """See :subscript\:`some text`.""".toHtml == expected + + test "(not) Roles: check escaping 2": + check("""See :subscript:\`some text\`.""".toHtml == + "See :subscript:`some text`.") + + test "Field list": + check(":field: text".toHtml == + """""" & + """""" & + """""" & + """""" & "\n
                                      field: text
                                      ") + + test "Field list: body after newline": + let output = dedent """ + :field: + text1""".toHtml + check "field:" in output + check "" in output + + test "Field list (incorrect)": + check ":field:text".toHtml == ":field:text" + suite "RST/Code highlight": test "Basic Python code highlight": let pythonCode = """ From 1f1ef85eb0980f2e1077638a502c0754c3e2b80d Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 30 Mar 2021 02:48:06 +0800 Subject: [PATCH 2316/4254] [std/uri]fix #17481 (#17568) --- lib/pure/uri.nim | 2 +- tests/stdlib/turi.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 920529ecf..4ac04d02e 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -294,7 +294,7 @@ func parseUri*(uri: string, result: var Uri) = var i = 0 # Check if this is a reference URI (relative URI) - let doubleSlash = uri.len > 1 and uri[1] == '/' + let doubleSlash = uri.len > 1 and uri[0] == '/' and uri[1] == '/' if i < uri.len and uri[i] == '/': # Make sure `uri` doesn't begin with '//'. if not doubleSlash: diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index 1a6f37520..d1a30bbfc 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -283,5 +283,16 @@ template main() = doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] doAssert toSeq(decodeQuery("a=1&b=2c=6")) == @[("a", "1"), ("b", "2c=6")] + block: # bug #17481 + let u1 = parseUri("./") + let u2 = parseUri("./path") + let u3 = parseUri("a/path") + doAssert u1.scheme.len == 0 + doAssert u1.path == "./" + doAssert u2.scheme.len == 0 + doAssert u2.path == "./path" + doAssert u3.scheme.len == 0 + doAssert u3.path == "a/path" + static: main() main() From ed126794b6af8b39960a7acc603cee1abc73da4a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 29 Mar 2021 21:16:11 +0200 Subject: [PATCH 2317/4254] Fix #17412 (#17560) * Fix #17412 * Address review --- compiler/ccgtypes.nim | 28 ++----------------------- compiler/ccgutils.nim | 40 ++++++++++++++++++++++++++++++++++-- compiler/liftdestructors.nim | 11 +++++++++- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index b0c3aa3b1..761fd5bf8 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -256,32 +256,8 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) = m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope]) # see `testCodegenABICheck` for example error message it generates -proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = - var pt = skipTypes(s.typ, typedescInst) - assert skResult != s.kind - - if tfByRef in pt.flags: return true - elif tfByCopy in pt.flags: return false - case pt.kind - of tyObject: - if s.typ.sym != nil and sfForward in s.typ.sym.flags: - # forwarded objects are *always* passed by pointers for consistency! - result = true - elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): - result = true # requested anyway - elif (tfFinal in pt.flags) and (pt[0] == nil): - result = false # no need, because no subtyping possible - else: - result = true # ordinary objects are always passed by reference, - # otherwise casting doesn't work - of tyTuple: - result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) - else: - result = false - # first parameter and return type is 'lent T'? --> use pass by pointer - if s.position == 0 and retType != nil and retType.kind == tyLent: - result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or - pt.kind == tySet and mapSetType(conf, pt) == ctArray) +from ccgutils import ccgIntroducedPtr +export ccgIntroducedPtr proc fillResult(conf: ConfigRef; param: PNode) = fillLoc(param.sym.loc, locParam, param, ~"Result", diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index f2a8c1e36..06b75a20f 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,8 +10,8 @@ # This module declares some helpers for the C code generator. import - ast, hashes, strutils, msgs, wordrecg, - platform, trees, options + ast, types, hashes, strutils, msgs, wordrecg, + platform, trees, options, cgendata proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = case n.kind @@ -106,3 +106,39 @@ proc mangle*(name: string): string = requiresUnderscore = true if requiresUnderscore: result.add "_" + +proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = + case int(getSize(conf, typ)) + of 1: result = ctInt8 + of 2: result = ctInt16 + of 4: result = ctInt32 + of 8: result = ctInt64 + else: result = ctArray + +proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = + var pt = skipTypes(s.typ, typedescInst) + assert skResult != s.kind + + if tfByRef in pt.flags: return true + elif tfByCopy in pt.flags: return false + case pt.kind + of tyObject: + if s.typ.sym != nil and sfForward in s.typ.sym.flags: + # forwarded objects are *always* passed by pointers for consistency! + result = true + elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): + result = true # requested anyway + elif (tfFinal in pt.flags) and (pt[0] == nil): + result = false # no need, because no subtyping possible + else: + result = true # ordinary objects are always passed by reference, + # otherwise casting doesn't work + of tyTuple: + result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) + else: + result = false + # first parameter and return type is 'lent T'? --> use pass by pointer + if s.position == 0 and retType != nil and retType.kind == tyLent: + result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or + pt.kind == tySet and mapSetType(conf, pt) == ctArray) + diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 980e77e4b..bb24fed34 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -11,7 +11,7 @@ ## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``). import modulegraphs, lineinfos, idents, ast, renderer, semdata, - sighashes, lowerings, options, types, msgs, magicsys, tables + sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils from trees import isCaseObj @@ -230,6 +230,15 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = # for every field (dependent on dest.kind): # `=` dest.field, src.field # =destroy(blob) + var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) + dummy.typ = y.typ + if ccgIntroducedPtr(c.g.config, dummy, y.typ): + # Because of potential aliasing when the src param is passed by ref, we need to check for equality here, + # because the wasMoved(dest) call would zero out src, if dest aliases src. + var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)), + newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)) + cond.typ = getSysType(c.g, x.info, tyBool) + body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info))) var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) temp.typ = x.typ incl(temp.flags, sfFromGeneric) From 35655cd1899ad2d85ca93ad7482572f0f345d8fb Mon Sep 17 00:00:00 2001 From: Dylan Modesitt Date: Mon, 29 Mar 2021 19:12:58 -0400 Subject: [PATCH 2318/4254] Add hasDataBuffered to asyncnet (#16000) Co-authored-by: flywind Co-authored-by: Timothee Cour --- changelog.md | 2 ++ lib/pure/asyncnet.nim | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/changelog.md b/changelog.md index be130f780..2fbff8b41 100644 --- a/changelog.md +++ b/changelog.md @@ -246,6 +246,8 @@ - Added dollar `$` and `len` for `jsre.RegExp`. +- Added `hasDataBuffered` to `asyncnet`. + - Added `hasClosure` to `std/typetraits`. diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index f36c427de..7aeb99777 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -650,6 +650,11 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. raiseOSError(osLastError()) freeaddrinfo(aiList) +proc hasDataBuffered*(s: AsyncSocket): bool {.since: (1, 5).} = + ## Determines whether an AsyncSocket has data buffered. + # xxx dedup with std/net + s.isBuffered and s.bufLen > 0 and s.currPos != s.bufLen + when defined(posix): proc connectUnix*(socket: AsyncSocket, path: string): owned(Future[void]) = From 159c06e0451f85842b2168886565fa57496a2c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Tue, 30 Mar 2021 02:06:51 +0200 Subject: [PATCH 2319/4254] unify tuple expressions (#13793) * unify tuple expressions * fix test * fix test * apply feedback * Handle empty tuples * Fix rendering named unary tuple * Protect static NimNode against stripping * Slightly less hacky * Revert "Slightly less hacky" This reverts commit 170c5aec0addc029f637afbc948700ca006b7942. * Slightly less hacky * Cleanup * Fix test * Fix another test * Add condsym * Rebase fallout * changelog: Move from compiler changes to language changes * Add stricter tests * Add empty tuple example to doc/astspec * Fix test Co-authored-by: Clyybber --- changelog.md | 3 +++ compiler/condsyms.nim | 1 + compiler/parser.nim | 15 ++++++----- compiler/renderer.nim | 2 +- compiler/vm.nim | 6 +++++ doc/astspec.txt | 45 ++++++++++++++++++++++++++++--- tests/ast_pattern_matching.nim | 4 +-- tests/astspec/tastspec.nim | 36 ++++++++++++++++++++----- tests/compiler/tprefixmatches.nim | 2 +- tests/lexer/tunary_minus.nim | 2 +- tests/macros/tdumpast.nim | 31 +++++++++++++++++++++ tests/parser/tpostexprblocks.nim | 6 ++--- tests/parser/ttypemodifiers.nim | 15 +++++------ 13 files changed, 136 insertions(+), 32 deletions(-) diff --git a/changelog.md b/changelog.md index 2fbff8b41..7452e3182 100644 --- a/changelog.md +++ b/changelog.md @@ -274,6 +274,9 @@ - Custom numeric literals (e.g. `-128'bignum`) are now supported. +- Tuple expressions are now parsed consistently as + `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. + ## Compiler changes diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 8d11dae7c..9ba97a8ed 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -131,3 +131,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasHintAsError") defineSymbol("nimHasSpellSuggest") defineSymbol("nimHasCustomLiterals") + defineSymbol("nimHasUnifiedTuple") diff --git a/compiler/parser.nim b/compiler/parser.nim index b9a6ffb8c..83ea4cbdc 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -421,10 +421,9 @@ proc exprColonEqExprListAux(p: var Parser, endTok: TokType, result: PNode) = var a = exprColonEqExpr(p) result.add(a) if p.tok.tokType != tkComma: break - getTok(p) - # (1,) produces a tuple expression - if endTok == tkParRi and p.tok.tokType == tkParRi and result.kind == nkPar: + elif result.kind == nkPar: result.transitionSonsKind(nkTupleConstr) + getTok(p) skipComment(p, a) optPar(p) eat(p, endTok) @@ -584,7 +583,10 @@ proc parsePar(p: var Parser): PNode = semiStmtList(p, result) elif p.tok.tokType == tkCurlyDotLe: result.add(parseStmtPragma(p)) - elif p.tok.tokType != tkParRi: + elif p.tok.tokType == tkParRi: + # Empty tuple '()' + result.transitionSonsKind(nkTupleConstr) + else: var a = simpleExpr(p) if p.tok.tokType == tkDo: result = postExprBlocks(p, a) @@ -605,13 +607,14 @@ proc parsePar(p: var Parser): PNode = semiStmtList(p, result) else: a = colonOrEquals(p, a) + if a.kind == nkExprColonExpr: + result.transitionSonsKind(nkTupleConstr) result.add(a) if p.tok.tokType == tkComma: getTok(p) skipComment(p, a) # (1,) produces a tuple expression: - if p.tok.tokType == tkParRi: - result.transitionSonsKind(nkTupleConstr) + result.transitionSonsKind(nkTupleConstr) # progress guaranteed while p.tok.tokType != tkParRi and p.tok.tokType != tkEof: var a = exprColonEqExpr(p) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 9a599f6fc..b9ec48185 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1182,7 +1182,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkTupleConstr: put(g, tkParLe, "(") gcomma(g, n, c) - if n.len == 1: put(g, tkComma, ",") + if n.len == 1 and n[0].kind != nkExprColonExpr: put(g, tkComma, ",") put(g, tkParRi, ")") of nkCurly: put(g, tkCurlyLe, "{") diff --git a/compiler/vm.nim b/compiler/vm.nim index d97d2d6e6..baaf0f14e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2228,6 +2228,12 @@ proc prepareVMValue(arg: PNode): PNode = if arg.kind in nkLiterals: return arg + if arg.kind == nkExprColonExpr and arg[0].typ != nil and + arg[0].typ.sym != nil and arg[0].typ.sym.magic == mPNimrodNode: + # Poor mans way of protecting static NimNodes + # XXX: Maybe we need a nkNimNode? + return arg + result = copyNode(arg) if arg.kind == nkTupleConstr: for child in arg: diff --git a/doc/astspec.txt b/doc/astspec.txt index b4b8b34b5..92212bf8c 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -329,19 +329,56 @@ AST: Parentheses ----------- -Parentheses for affecting operator precedence or tuple construction -are built with the ``nnkPar`` node. +Parentheses for affecting operator precedence use the ``nnkPar`` node. Concrete syntax: .. code-block:: nim - (1, 2, (3)) + (a + b) * c AST: .. code-block:: nim - nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3))) + nnkInfix(nnkIdent("*"), + nnkPar( + nnkInfix(nnkIdent("+"), nnkIdent("a"), nnkIdent("b"))), + nnkIdent("c")) +Tuple Constructors +------------------ + +Nodes for tuple construction are built with the ``nnkTupleConstr`` node. + +Concrete syntax: + +.. code-block:: nim + (1, 2, 3) + (a: 1, b: 2, c: 3) + () + +AST: + +.. code-block:: nim + nnkTupleConstr(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) + nnkTupleConstr( + nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)), + nnkExprColonExpr(nnkIdent("b"), nnkIntLit(2)), + nnkExprColonExpr(nnkIdent("c"), nnkIntLit(3))) + +Since the one tuple would be syntactically identical to parentheses +with an expression in them, the parser expects a trailing comma for +them. For tuple constructors with field names, this is not necessary. + +.. code-block:: nim + (1,) + (a: 1) + +AST: + +.. code-block:: nim + nnkTupleConstr(nnkIntLit(1)) + nnkTupleConstr( + nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1))) Curly braces ------------ diff --git a/tests/ast_pattern_matching.nim b/tests/ast_pattern_matching.nim index c08234b9e..d209493b6 100644 --- a/tests/ast_pattern_matching.nim +++ b/tests/ast_pattern_matching.nim @@ -133,8 +133,8 @@ proc matchLengthKind*(arg: NimNode; kind: NimNodeKind; length: int): MatchingErr matchLengthKind(arg, {kind}, length) proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: SomeInteger): MatchingError {.compileTime.} = - let kindFail = not(kind.card == 0 or arg.kind in kind) - let valueFail = arg.intVal != int(value) + template kindFail: bool = not(kind.card == 0 or arg.kind in kind) + template valueFail: bool = arg.intVal != int(value) if kindFail or valueFail: result.node = arg result.kind = WrongKindValue diff --git a/tests/astspec/tastspec.nim b/tests/astspec/tastspec.nim index e2cfed277..33a245b1b 100644 --- a/tests/astspec/tastspec.nim +++ b/tests/astspec/tastspec.nim @@ -327,19 +327,43 @@ static: testArrayAccessOperator(x[y]) - - ## Parentheses scope: - let ast = myquote: - (1, 2, (3)) + (a + b) * c ast.matchAst: - of nnkPar(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkPar(nnkIntLit(intVal = 3))): - echo "ok" + of nnkInfix(ident"*", nnkPar(nnkInfix(ident"+", ident"a", ident"b")), ident"c"): + echo "parentheses ok" + ## Tuple Constructors + + scope: + let ast = myquote: + (1, 2, 3) + (a: 1, b: 2, c: 3) + (1,) + (a: 1) + () + + for it in ast: + echo it.lispRepr + it.matchAst: + of nnkTupleConstr(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)): + echo "simple tuple ok" + of nnkTupleConstr( + nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1)), + nnkExprColonExpr(ident"b", nnkIntLit(intVal = 2)), + nnkExprColonExpr(ident"c", nnkIntLit(intVal = 3)) + ): + echo "named tuple ok" + of nnkTupleConstr(nnkIntLit(intVal = 1)): + echo "one tuple ok" + of nnkTupleConstr(nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1))): + echo "named one tuple ok" + of nnkTupleConstr(): + echo "empty tuple ok" ## Curly braces diff --git a/tests/compiler/tprefixmatches.nim b/tests/compiler/tprefixmatches.nim index a89a6f613..6a3186729 100644 --- a/tests/compiler/tprefixmatches.nim +++ b/tests/compiler/tprefixmatches.nim @@ -5,7 +5,7 @@ macro check(val, body: untyped): untyped = result = newStmtList() expectKind body, nnkStmtList for b in body: - expectKind b, nnkPar + expectKind b, nnkTupleConstr expectLen b, 2 let p = b[0] let s = b[1] diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim index 87b3cb52d..1641e918c 100644 --- a/tests/lexer/tunary_minus.nim +++ b/tests/lexer/tunary_minus.nim @@ -45,7 +45,7 @@ template main = doAssert lispReprStr([-1]) == """(Bracket (IntLit -1))""" doAssert (-1, 2)[0] == minusOne: "unable to handle negatives after parenthesis" - doAssert lispReprStr((-1, 2)) == """(Par (IntLit -1) (IntLit 2))""" + doAssert lispReprStr((-1, 2)) == """(TupleConstr (IntLit -1) (IntLit 2))""" proc x(): int = var a = 1;-1 # the -1 should act as the return value doAssert x() == minusOne: diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim index b9d224ab8..b6bcbe8f0 100644 --- a/tests/macros/tdumpast.nim +++ b/tests/macros/tdumpast.nim @@ -48,3 +48,34 @@ macro fun3(): untyped = int | float | array | seq | object | ptr | pointer | float32 doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr fun3() + +macro fun4() = + let n = quote do: + (a: 1) + doAssert n.repr == "(a: 1)", n.repr +fun4() + +# nkTupleConstr vs nkPar tests: +block: # lispRepr + macro lispRepr2(a: untyped): string = newLit a.lispRepr + + doAssert lispRepr2(()) == """(TupleConstr)""" + doAssert lispRepr2((a: 1)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)))""" + doAssert lispRepr2((a: 1, b: 2)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)) (ExprColonExpr (Ident "b") (IntLit 2)))""" + doAssert lispRepr2((1,)) == """(TupleConstr (IntLit 1))""" + doAssert lispRepr2((1, 2)) == """(TupleConstr (IntLit 1) (IntLit 2))""" + doAssert lispRepr2((1, 2, 3.0)) == """(TupleConstr (IntLit 1) (IntLit 2) (FloatLit 3.0))""" + doAssert lispRepr2((1)) == """(Par (IntLit 1))""" + doAssert lispRepr2((1+2)) == """(Par (Infix (Ident "+") (IntLit 1) (IntLit 2)))""" + +block: # repr + macro repr2(a: untyped): string = newLit a.repr + + doAssert repr2(()) == "()" + doAssert repr2((a: 1)) == "(a: 1)" + doAssert repr2((a: 1, b: 2)) == "(a: 1, b: 2)" + doAssert repr2((1,)) == "(1,)" + doAssert repr2((1, 2)) == "(1, 2)" + doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)" + doAssert repr2((1)) == "(1)" + doAssert repr2((1+2)) == "(1 + 2)" diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim index bc10a72e2..d272c712f 100644 --- a/tests/parser/tpostexprblocks.nim +++ b/tests/parser/tpostexprblocks.nim @@ -464,7 +464,7 @@ StmtList DiscardStmt Empty OfBranch - Par + TupleConstr Ident "a" Ident "b" StmtList @@ -476,7 +476,7 @@ StmtList DiscardStmt Empty ElifBranch - Par + TupleConstr Ident "a" Ident "b" StmtList @@ -488,7 +488,7 @@ StmtList DiscardStmt Empty ExceptBranch - Par + TupleConstr Ident "a" Ident "b" StmtList diff --git a/tests/parser/ttypemodifiers.nim b/tests/parser/ttypemodifiers.nim index 2c322b44b..9a1ccb1a5 100644 --- a/tests/parser/ttypemodifiers.nim +++ b/tests/parser/ttypemodifiers.nim @@ -21,7 +21,7 @@ StmtList Ident "PtrTuple" Empty PtrTy - Par + TupleConstr Ident "int" Ident "string" TypeDef @@ -43,14 +43,14 @@ StmtList Ident "RefTupleType" Empty RefTy - Par + TupleConstr Ident "int" Ident "string" TypeDef Ident "RefTupleVars" Empty RefTy - Par + TupleConstr Ident "a" Ident "b" TypeDef @@ -80,7 +80,7 @@ StmtList Empty Command Ident "static" - Par + TupleConstr Ident "int" Ident "string" TypeDef @@ -155,7 +155,7 @@ StmtList Empty Command Ident "type" - Par + TupleConstr Ident "a" Ident "b" TypeDef @@ -163,7 +163,7 @@ StmtList Empty Command Ident "type" - Par + TupleConstr Ident "int" Ident "string" TypeDef @@ -287,7 +287,7 @@ StmtList IdentDefs Ident "refTuple2" RefTy - Par + TupleConstr Ident "int" Ident "string" Empty @@ -524,4 +524,3 @@ dumpTree: static: staticStmtList1 staticStmtList2 - From 8db93fd0a29dbb950cc14327b31d683c3b0d8926 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Tue, 30 Mar 2021 09:04:17 +0300 Subject: [PATCH 2320/4254] Fix entries in nimc advopt (#17576) --- doc/advopt.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 108c07222..763ac80a6 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -43,8 +43,9 @@ Advanced options: --warning[X]:on|off turn specific warning X on|off --hints:on|off|list turn all hints on|off or list all available --hint[X]:on|off turn specific hint X on|off - --warningAsError[X]:on|off turn specific warning X into an error on|off - --hintAsError[X]:on|off turn specific hint X into an error on|off + --warningAsError[X]:on|off + turn specific warning X into an error on|off + --hintAsError[X]:on|off turn specific hint X into an error on|off --styleCheck:off|hint|error produce hints or errors for Nim identifiers that do not adhere to Nim's official style guide @@ -83,7 +84,8 @@ Advanced options: if path == @default (the default and most useful), will use best match among @pkg,@path. if these are nonexistent, will use project path - -b, --backend:c|cpp|js|objc sets backend to use with commands like `nim doc` or `nim r` + -b, --backend:c|cpp|js|objc + sets backend to use with commands like `nim doc` or `nim r` --docCmd:cmd if `cmd == skip`, skips runnableExamples else, runs runnableExamples with given options, e.g.: `--docCmd:"-d:foo --threads:on"` From a672ec3c9e25159d3482aebfe1d0bb4271910869 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 30 Mar 2021 08:05:37 +0200 Subject: [PATCH 2321/4254] Fix #17299, fix setAffinity for android (#17574) * Fix #17299 * Comment * Fix typo --- lib/system/threadlocalstorage.nim | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/system/threadlocalstorage.nim b/lib/system/threadlocalstorage.nim index 922150fff..cbb74c7df 100644 --- a/lib/system/threadlocalstorage.nim +++ b/lib/system/threadlocalstorage.nim @@ -194,8 +194,23 @@ else: proc cpusetIncl(cpu: cint; s: var CpuSet) {. importc: "CPU_SET", header: schedh.} - proc setAffinity(thread: SysThread; setsize: csize_t; s: var CpuSet) {. - importc: "pthread_setaffinity_np", header: pthreadh.} + when defined(android): + # libc of android doesn't implement pthread_setaffinity_np, + # it exposes pthread_gettid_np though, so we can use that in combination + # with sched_setaffinity to set the thread affinity. + type Pid {.importc: "pid_t", header: "".} = int32 # From posix_other.nim + + proc setAffinityTID(tid: Pid; setsize: csize_t; s: var CpuSet) {. + importc: "sched_setaffinity", header: schedh.} + + proc pthread_gettid_np(thread: SysThread): Pid {. + importc: "pthread_gettid_np", header: pthreadh.} + + proc setAffinity(thread: SysThread; setsize: csize_t; s: var CpuSet) = + setAffinityTID(pthread_gettid_np(thread), setsize, s) + else: + proc setAffinity(thread: SysThread; setsize: csize_t; s: var CpuSet) {. + importc: "pthread_setaffinity_np", header: pthreadh.} const From 9e88425d7c5e3edfcbddedbe062c5f028789a002 Mon Sep 17 00:00:00 2001 From: Ardek Romak Date: Tue, 30 Mar 2021 09:07:45 +0300 Subject: [PATCH 2322/4254] Fix void async in templates (#17562) * Fix https://github.com/nim-lang/Nim/issues/16159 * Add test for async in template * Shorten the expression * Even shorter Co-authored-by: Clyybber --- lib/pure/asyncmacro.nim | 5 +++-- tests/async/tasyncintemplate.nim | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/async/tasyncintemplate.nim diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index eecec4278..336d10aad 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -184,8 +184,9 @@ proc asyncSingleProc(prc: NimNode): NimNode = verifyReturnType(repr(returnType), returnType) let subtypeIsVoid = returnType.kind == nnkEmpty or - (baseType.kind == nnkIdent and returnType[1].eqIdent("void")) - + (baseType.kind in {nnkIdent, nnkSym} and + baseType.eqIdent("void")) + let futureVarIdents = getFutureVarIdents(prc.params) var outerProcBody = newNimNode(nnkStmtList, prc.body) diff --git a/tests/async/tasyncintemplate.nim b/tests/async/tasyncintemplate.nim new file mode 100644 index 000000000..31f4cd95c --- /dev/null +++ b/tests/async/tasyncintemplate.nim @@ -0,0 +1,12 @@ +discard """ + output: 42 +""" + +import asyncdispatch + +template foo() = + proc temp(): Future[int] {.async.} = return 42 + proc tempVoid(): Future[void] {.async.} = echo await temp() + +foo() +waitFor tempVoid() From 40093b4a937d751ef43b5c2ca447677bb858dff4 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 30 Mar 2021 10:20:58 +0200 Subject: [PATCH 2323/4254] [backport:1.2] Avoid inlining of newObj and newObjRC1 calls (#17582) This is taken from: https://github.com/status-im/Nim/commit/af69b3ceae16281efd45cbee4ce1bedd14282304 Full original comment: This is to avoid heavy inlining happening when two allocation calls would occur shortly after each other. This inlining would sometimes be accompanied with an optimisation as the compiler is able to see that cellToUsr ending the first allocation call is shortly followed by an usrToCell call. The pointer arithmetic is redundant and the compiler can eliminate it, leaving only the cell address in a register (and later the stack) instead of the actual pointer to the user data, as one would expect. This combined with a GC collect cycle will cause the stack scan to only notice the cell address, which is of no good due to a usrToCell in the gcMark call which shifts that address to an adjacent cell. This means that the actual cell of importance will not get marked and thus cause a premature collection of that cell. BOOM. --- lib/system/gc.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index ae29f3466..229b26f3c 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -482,7 +482,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) when defined(memProfiler): nimProfile(size) -proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = +proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = result = rawNewObj(typ, size, gch) zeroMem(result, size) when defined(memProfiler): nimProfile(size) @@ -497,7 +497,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = when defined(memProfiler): nimProfile(size) {.pop.} -proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = +proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = # generates a new object and sets its reference counter to 1 incTypeSize typ, size sysAssert(allocInv(gch.region), "newObjRC1 begin") From 3715fc41d54ae5c139fba79f1f61419e320e8ba5 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 30 Mar 2021 16:27:24 +0800 Subject: [PATCH 2324/4254] fix #17512 (#17520) --- compiler/ccgcalls.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 64b883087..2a93cb5af 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -259,6 +259,10 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = else: result = a +proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = + getTemp(p, a.lode.typ, result, needsInit=false) + genAssignment(p, result, a, {}) + proc genArgStringToCString(p: BProc, n: PNode, needsTmp: bool): Rope {.inline.} = var a: TLoc initLocExpr(p, n[0], a) @@ -273,7 +277,10 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rop result = openArrayLoc(p, param.typ, n) elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): initLocExpr(p, n, a) - result = addrLoc(p.config, withTmpIfNeeded(p, a, needsTmp)) + if n.kind in {nkCharLit..nkNilLit}: + result = addrLoc(p.config, literalsNeedsTmp(p, a)) + else: + result = addrLoc(p.config, withTmpIfNeeded(p, a, needsTmp)) elif p.module.compileToCpp and param.typ.kind in {tyVar} and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n[0], a) From f5b1e384a411e1418180ea81bb8fc71bf2feaa26 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 30 Mar 2021 09:17:21 +0200 Subject: [PATCH 2325/4254] parser.nim: simply layout change --- compiler/parser.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 83ea4cbdc..d103d161a 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1990,7 +1990,8 @@ proc parseObject(p: var Parser): PNode = result.add(parseObjectPart(p)) proc parseTypeClassParam(p: var Parser): PNode = - let modifier = case p.tok.tokType + let modifier = + case p.tok.tokType of tkOut, tkVar: nkVarTy of tkPtr: nkPtrTy of tkRef: nkRefTy From af2a7e8cbc3729ac62be64b5683e4a2187160b2f Mon Sep 17 00:00:00 2001 From: rockcavera Date: Tue, 30 Mar 2021 07:24:21 -0300 Subject: [PATCH 2326/4254] Rotation right and left refactored to generics. Continuation of #16622 (#17578) * Rotation right and left refactored to generics Continuation of [16622](https://github.com/nim-lang/Nim/pull/16622) * add runnableExamples --- lib/pure/bitops.nim | 121 ++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 89 deletions(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 4ef190c1b..b5b08985e 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -771,7 +771,9 @@ func rotr[T: SomeUnsignedInt](value: T, rot: int32): T {.inline.} = let rot = rot and mask (value shr rot) or (value shl ((-rot) and mask)) -func shiftTypeToImpl(size: static int, shift: int): auto {.inline.} = +func shiftTypeTo(size: static int, shift: int): auto {.inline.} = + ## Returns the `shift` for the rotation according to the compiler and the + ## `size`. when (defined(vcc) and (size in [4, 8])) or defined(gcc) or defined(icl): cint(shift) elif (defined(vcc) and (size in [1, 2])) or (defined(clang) and size == 1): @@ -784,118 +786,59 @@ func shiftTypeToImpl(size: static int, shift: int): auto {.inline.} = elif size == 8: culonglong(shift) -template shiftTypeTo[T](value: T, shift: int): auto = - ## Returns the `shift` for the rotation according to the compiler and the size - ## of the` value`. - shiftTypeToImpl(sizeof(value), shift) - -func rotateLeftBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} = - ## Left-rotate bits in a 8-bits value. +func rotateLeftBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} = + ## Left-rotate bits in a `value`. runnableExamples: doAssert rotateLeftBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 - - when nimvm: - rotl(value, shift.int32) - else: - when useBuiltinsRotate: - builtin_rotl8(value.cuchar, shiftTypeTo(value, shift)).uint8 - else: - rotl(value, shift.int32) - -func rotateLeftBits*(value: uint16, shift: range[0..16]): uint16 {.inline.} = - ## Left-rotate bits in a 16-bits value. - runnableExamples: doAssert rotateLeftBits(0b00111100_11000011'u16, 8) == 0b11000011_00111100'u16 - - when nimvm: - rotl(value, shift.int32) - else: - when useBuiltinsRotate: - builtin_rotl16(value.cushort, shiftTypeTo(value, shift)).uint16 - else: - rotl(value, shift.int32) - -func rotateLeftBits*(value: uint32, shift: range[0..32]): uint32 {.inline.} = - ## Left-rotate bits in a 32-bits value. - runnableExamples: doAssert rotateLeftBits(0b0000111111110000_1111000000001111'u32, 16) == 0b1111000000001111_0000111111110000'u32 - - when nimvm: - rotl(value, shift.int32) - else: - when useBuiltinsRotate: - builtin_rotl32(value.cuint, shiftTypeTo(value, shift)).uint32 - else: - rotl(value, shift.int32) - -func rotateLeftBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} = - ## Left-rotate bits in a 64-bits value. - runnableExamples: doAssert rotateLeftBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 - when nimvm: rotl(value, shift.int32) else: - when useBuiltinsRotate and defined(amd64): - builtin_rotl64(value.culonglong, shiftTypeTo(value, shift)).uint64 + when useBuiltinsRotate: + const size = sizeof(T) + when size == 1: + builtin_rotl8(value.cuchar, shiftTypeTo(size, shift)).T + elif size == 2: + builtin_rotl16(value.cushort, shiftTypeTo(size, shift)).T + elif size == 4: + builtin_rotl32(value.cuint, shiftTypeTo(size, shift)).T + elif size == 8 and arch64: + builtin_rotl64(value.culonglong, shiftTypeTo(size, shift)).T + else: + rotl(value, shift.int32) else: rotl(value, shift.int32) -func rotateRightBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} = - ## Right-rotate bits in a 8-bits value. +func rotateRightBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} = + ## Right-rotate bits in a `value`. runnableExamples: doAssert rotateRightBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 - - when nimvm: - rotr(value, shift.int32) - else: - when useBuiltinsRotate: - builtin_rotr8(value.cuchar, shiftTypeTo(value, shift)).uint8 - else: - rotr(value, shift.int32) - -func rotateRightBits*(value: uint16, shift: range[0..16]): uint16 {.inline.} = - ## Right-rotate bits in a 16-bits value. - runnableExamples: doAssert rotateRightBits(0b00111100_11000011'u16, 8) == 0b11000011_00111100'u16 - - when nimvm: - rotr(value, shift.int32) - else: - when useBuiltinsRotate: - builtin_rotr16(value.cushort, shiftTypeTo(value, shift)).uint16 - else: - rotr(value, shift.int32) - -func rotateRightBits*(value: uint32, shift: range[0..32]): uint32 {.inline.} = - ## Right-rotate bits in a 32-bits value. - runnableExamples: doAssert rotateRightBits(0b0000111111110000_1111000000001111'u32, 16) == 0b1111000000001111_0000111111110000'u32 - + doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == + 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 when nimvm: rotr(value, shift.int32) else: when useBuiltinsRotate: - builtin_rotr32(value.cuint, shiftTypeTo(value, shift)).uint32 - else: - rotr(value, shift.int32) - -func rotateRightBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} = - ## Right-rotate bits in a 64-bits value. - runnableExamples: - doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == - 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 - - when nimvm: - rotr(value, shift.int32) - else: - when useBuiltinsRotate and defined(amd64): - builtin_rotr64(value.culonglong, shiftTypeTo(value, shift)).uint64 + const size = sizeof(T) + when size == 1: + builtin_rotr8(value.cuchar, shiftTypeTo(size, shift)).T + elif size == 2: + builtin_rotr16(value.cushort, shiftTypeTo(size, shift)).T + elif size == 4: + builtin_rotr32(value.cuint, shiftTypeTo(size, shift)).T + elif size == 8 and arch64: + builtin_rotr64(value.culonglong, shiftTypeTo(size, shift)).T + else: + rotr(value, shift.int32) else: rotr(value, shift.int32) From 5ecbe6737110bd3fb9a85c2582409483fb5494b0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 30 Mar 2021 20:13:18 +0200 Subject: [PATCH 2327/4254] makes DrNim compile again (#17584) --- compiler/modulegraphs.nim | 3 ++- drnim/drnim.nim | 29 +++++++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index e6f5267cd..4430e3baa 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -393,8 +393,9 @@ proc registerModule*(g: ModuleGraph; m: PSym) = proc registerModuleById*(g: ModuleGraph; m: FileIndex) = registerModule(g, g.packed[int m].module) -proc initOperators(g: ModuleGraph): Operators = +proc initOperators*(g: ModuleGraph): Operators = # These are safe for IC. + # Public because it's used by DrNim. result.opLe = createMagic(g, "<=", mLeI) result.opLt = createMagic(g, "<", mLtI) result.opAnd = createMagic(g, "and", mAnd) diff --git a/drnim/drnim.nim b/drnim/drnim.nim index 44eab8625..d549e1d5b 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -68,6 +68,7 @@ type DrnimContext = ref object z3: Z3_context graph: ModuleGraph + idgen: IdGenerator facts: seq[(PNode, VersionScope)] varVersions: seq[int] # this maps variable IDs to their current version. varSyms: seq[PSym] # mirrors 'varVersions' @@ -80,6 +81,7 @@ type DrCon = object graph: ModuleGraph + idgen: IdGenerator mapping: Table[string, Z3_ast] canonParameterNames: bool assumeUniqueness: bool @@ -301,12 +303,12 @@ proc nodeToZ3(c: var DrCon; n: PNode; scope: VersionScope; vars: var seq[PNode]) proc nodeToDomain(c: var DrCon; n, q: PNode; opAnd: PSym): PNode = assert n.kind == nkInfix - let opLe = createMagic(c.graph, "<=", mLeI) + let opLe = createMagic(c.graph, c.idgen, "<=", mLeI) case $n[0] of "..": result = buildCall(opAnd, buildCall(opLe, n[1], q), buildCall(opLe, q, n[2])) of "..<": - let opLt = createMagic(c.graph, "<", mLtI) + let opLt = createMagic(c.graph, c.idgen, "<", mLtI) result = buildCall(opAnd, buildCall(opLe, n[1], q), buildCall(opLt, q, n[2])) else: notImplemented(n) @@ -315,7 +317,7 @@ template quantorToZ3(fn) {.dirty.} = template ctx: untyped = c.up.z3 var bound = newSeq[Z3_app](n.len-2) - let opAnd = createMagic(c.graph, "and", mAnd) + let opAnd = createMagic(c.graph, c.idgen, "and", mAnd) var known: PNode for i in 1..n.len-2: let it = n[i] @@ -333,7 +335,7 @@ template quantorToZ3(fn) {.dirty.} = var dummy: seq[PNode] assert known != nil - let x = nodeToZ3(c, buildCall(createMagic(c.graph, "->", mImplies), + let x = nodeToZ3(c, buildCall(createMagic(c.graph, c.idgen, "->", mImplies), known, n[^1]), scope, dummy) result = fn(ctx, 0, bound.len.cuint, addr(bound[0]), 0, nil, x) @@ -395,8 +397,8 @@ proc nodeToZ3(c: var DrCon; n: PNode; scope: VersionScope; vars: var seq[PNode]) else: notImplemented(n) of mHigh: - let addOpr = createMagic(c.graph, "+", mAddI) - let lenOpr = createMagic(c.graph, "len", mLengthOpenArray) + let addOpr = createMagic(c.graph, c.idgen, "+", mAddI) + let lenOpr = createMagic(c.graph, c.idgen, "len", mLengthOpenArray) let asLenExpr = addOpr.buildCall(lenOpr.buildCall(n[1]), nkIntLit.newIntNode(-1)) result = rec asLenExpr of mLow: @@ -577,8 +579,8 @@ proc addRangeInfo(c: var DrCon, n: PNode; scope: VersionScope, res: var seq[Z3_a res.add nodeToZ3(c, translateEnsures(ensures, n), scope, dummy) return - let x = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), lowBound, n) - let y = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), n, highBound) + let x = newTree(nkInfix, newSymNode createMagic(c.graph, c.idgen, "<=", cmpOp), lowBound, n) + let y = newTree(nkInfix, newSymNode createMagic(c.graph, c.idgen, "<=", cmpOp), n, highBound) var dummy: seq[PNode] res.add nodeToZ3(c, x, scope, dummy) @@ -677,6 +679,7 @@ proc proofEngine(ctx: DrnimContext; assumptions: seq[(PNode, VersionScope)]; toProve: (PNode, VersionScope)): (bool, string) = var c: DrCon c.graph = ctx.graph + c.idgen = ctx.idgen c.assumeUniqueness = assumeUniqueness c.up = ctx result = proofEngineAux(c, assumptions, toProve) @@ -738,10 +741,11 @@ proc compatibleProps(graph: ModuleGraph; formal, actual: PType): bool {.nimcall. var c: DrCon c.graph = graph + c.idgen = graph.idgen c.canonParameterNames = true try: c.up = DrnimContext(z3: setupZ3(), o: initOperators(graph), graph: graph, owner: nil, - opImplies: createMagic(graph, "->", mImplies)) + opImplies: createMagic(graph, c.idgen, "->", mImplies)) template zero: untyped = VersionScope(0) if not frequires.isEmpty: result = not arequires.isEmpty and proofEngineAux(c, @[(frequires, zero)], (arequires, zero))[0] @@ -847,7 +851,7 @@ proc checkLe(c: DrnimContext, a, b: PNode) = of tyChar, tyUInt..tyUInt64: cmpOp = mLeU else: discard - let cmp = newTree(nkInfix, newSymNode createMagic(c.graph, "<=", cmpOp), a, b) + let cmp = newTree(nkInfix, newSymNode createMagic(c.graph, c.idgen, "<=", cmpOp), a, b) cmp.info = a.info discard prove(c, cmp) @@ -1026,7 +1030,7 @@ proc traverseAsgn(c: DrnimContext; n: PNode) = proc replaceByOldParams(fact, le: PNode): PNode = if guards.sameTree(fact, le): result = newNodeIT(nkCall, fact.info, fact.typ) - result.add newSymNode createMagic(c.graph, "old", mOld) + result.add newSymNode createMagic(c.graph, c.idgen, "old", mOld) result.add fact else: result = shallowCopy(fact) @@ -1176,8 +1180,9 @@ proc strongSemCheck(graph: ModuleGraph; owner: PSym; n: PNode) = c.z3 = setupZ3() c.o = initOperators(graph) c.graph = graph + c.idgen = graph.idgen c.owner = owner - c.opImplies = createMagic(c.graph, "->", mImplies) + c.opImplies = createMagic(c.graph, c.idgen, "->", mImplies) try: traverse(c, n) ensuresCheck(c, owner) From 72988509ba0859a5bdfb43a78273c2de26c3d6dc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 30 Mar 2021 11:14:39 -0700 Subject: [PATCH 2328/4254] add getPort to resolve Port(0) (#17559) * add getPort to resolve Port(0) * fixup * use getPort in examples + tests * address comments: do not re-export Port --- changelog.md | 2 + lib/pure/asynchttpserver.nim | 42 ++++++++++++------- testament/lib/stdtest/netutils.nim | 3 +- .../tasynchttpserver_transferencoding.nim | 3 +- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/changelog.md b/changelog.md index 7452e3182..c234bf174 100644 --- a/changelog.md +++ b/changelog.md @@ -71,6 +71,8 @@ - Added `asyncdispatch.activeDescriptors` that returns the number of currently active async event handles/file descriptors. +- Added to `asynchttpserver` `getPort` and `getSocket`. + - `--gc:orc` is now 10% faster than previously for common workloads. If you have trouble with its changed behavior, compile with `-d:nimOldOrc`. diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 38be4ceac..ec464682e 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -15,20 +15,20 @@ ## instead of allowing users to connect directly to this server. runnableExamples("-r:off"): - # This example will create an HTTP server on port 8080. The server will - # respond to all requests with a `200 OK` response code and "Hello World" + # This example will create an HTTP server on an automatically chosen port. + # It will respond to all requests with a `200 OK` response code and "Hello World" # as the response body. import std/asyncdispatch proc main {.async.} = - const port = 8080 var server = newAsyncHttpServer() proc cb(req: Request) {.async.} = echo (req.reqMethod, req.url, req.headers) let headers = {"Content-type": "text/plain; charset=utf-8"} await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - echo "test this with: curl localhost:" & $port & "/" - server.listen(Port(port)) + server.listen(Port(0)) # or Port(8080) to hardcode the standard HTTP port. + let port = server.getPort + echo "test this with: curl localhost:" & $port.uint16 & "/" while true: if server.shouldAcceptRequest(): await server.acceptRequest(cb) @@ -41,6 +41,7 @@ runnableExamples("-r:off"): import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore +from nativesockets import getLocalAddr, AF_INET import std/private/since export httpcore except parseHeader @@ -70,21 +71,32 @@ type maxBody: int ## The maximum content-length that will be read for the body. maxFDs: int -func getSocket*(a: AsyncHttpServer): AsyncSocket {.since: (1, 5, 1).} = - ## Returns the `AsyncHttpServer`s internal `AsyncSocket` instance. - ## - ## Useful for identifying what port the AsyncHttpServer is bound to, if it - ## was chosen automatically. +proc getPort*(self: AsyncHttpServer): Port {.since: (1, 5, 1).} = + ## Returns the port `self` was bound to. + ## + ## Useful for identifying what port `self` is bound to, if it + ## was chosen automatically, for example via `listen(Port(0))`. + runnableExamples: + from std/nativesockets import Port + let server = newAsyncHttpServer() + server.listen(Port(0)) + assert server.getPort.uint16 > 0 + server.close() + result = getLocalAddr(self.socket.getFd, AF_INET)[1] + +func getSocket*(self: AsyncHttpServer): AsyncSocket {.since: (1, 5, 1).} = + ## Field accessor. runnableExamples: - from std/asyncdispatch import Port from std/asyncnet import getFd - from std/nativesockets import getLocalAddr, AF_INET + from std/nativesockets import getLocalAddr, AF_INET, Port let server = newAsyncHttpServer() server.listen(Port(0)) # Socket is not bound until this point - let port = getLocalAddr(server.getSocket.getFd, AF_INET)[1] - doAssert uint16(port) > 0 + # note: a more direct way to get the port is `getPort`. + let (laddr, port) = getLocalAddr(server.getSocket.getFd, AF_INET) + assert uint16(port) > 0 + assert laddr == "0.0.0.0" server.close() - a.socket + self.socket proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = diff --git a/testament/lib/stdtest/netutils.nim b/testament/lib/stdtest/netutils.nim index eb913a56a..5115390e0 100644 --- a/testament/lib/stdtest/netutils.nim +++ b/testament/lib/stdtest/netutils.nim @@ -1,6 +1,7 @@ import std/[nativesockets, asyncdispatch, os] proc bindAvailablePort*(handle: SocketHandle, port = Port(0)): Port = + ## See also `asynchttpserver.getPort`. block: var name: Sockaddr_in name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) @@ -8,5 +9,5 @@ proc bindAvailablePort*(handle: SocketHandle, port = Port(0)): Port = name.sin_addr.s_addr = htonl(INADDR_ANY) if bindAddr(handle, cast[ptr SockAddr](addr(name)), sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError()) + raiseOSError(osLastError(), $port) result = getLocalAddr(handle, AF_INET)[1] diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim index 34f3cef11..bfa0e2f69 100644 --- a/tests/stdlib/tasynchttpserver_transferencoding.nim +++ b/tests/stdlib/tasynchttpserver_transferencoding.nim @@ -27,10 +27,9 @@ template genTest(input, expected) = let server = newAsyncHttpServer() waitFor runSleepLoop(server) - let port = getLocalAddr(server.getSocket.getFd, AF_INET)[1] let data = postBegin & input var socket = newSocket() - socket.connect("127.0.0.1", port) + socket.connect("127.0.0.1", server.getPort) socket.send(data) waitFor sleepAsync(10) socket.close() From 7c09e0c75773a2df6469a2acd94f3090aef83255 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 31 Mar 2021 02:15:14 +0800 Subject: [PATCH 2329/4254] fix #15617(fix compilation failure on -d:useMalloc --gc:none) (#17555) Co-authored-by: Andreas Rumpf Co-authored-by: Timothee Cour --- lib/system/mmdisp.nim | 10 ++++++++++ tests/system/tgcnone.nim | 6 ++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/system/tgcnone.nim diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 96dc86bfd..3317ba627 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -57,6 +57,16 @@ elif defined(gogc): elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc): include system / mm / malloc + when defined(nogc): + proc GC_getStatistics(): string = "" + proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = + result = alloc0(size) + + proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = + result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + elif defined(nogc): include system / mm / none diff --git a/tests/system/tgcnone.nim b/tests/system/tgcnone.nim new file mode 100644 index 000000000..700176d5f --- /dev/null +++ b/tests/system/tgcnone.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--gc:none -d:useMalloc" +""" +# bug #15617 +let x = 4 +doAssert x == 4 From 8ee0eda84156c8d9074b7a42cdedc209cffdc4a4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 31 Mar 2021 01:15:08 -0700 Subject: [PATCH 2330/4254] fix #12282 distinct now does not create erroneous copy in VM (#17594) --- compiler/vmgen.nim | 14 ++++++++++++-- tests/distinct/tdistinct.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bd80df219..f6e385976 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -833,10 +833,20 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = c.genNarrow(n, dest) proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = - if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc: - # don't do anything for lambda lifting conversions: + let t2 = n.typ.skipTypes({tyDistinct}) + let targ2 = arg.typ.skipTypes({tyDistinct}) + + proc implicitConv(): bool = + if sameType(t2, targ2): return true + # xxx consider whether to use t2 and targ2 here + if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc: + # don't do anything for lambda lifting conversions: + return true + + if implicitConv(): gen(c, arg, dest) return + let tmp = c.genx(arg) if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opc, dest, tmp) diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index d64f33443..876975a7c 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: ''' tdistinct 25 @@ -138,3 +139,34 @@ block tRequiresInit: accept: let s = "test" doAssert s == "test" + +type Foo = distinct string + +template main() = + # xxx put everything here to test under RT + VM + block: # bug #12282 + block: + proc test() = + var s: Foo + s.string.add('c') + doAssert s.string == "c" # was failing + test() + + block: + proc add(a: var Foo, b: char) {.borrow.} + proc test() = + var s: Foo + s.add('c') + doAssert s.string == "c" # was ok + test() + + block: + proc add(a: var Foo, b: char) {.borrow.} + proc test() = + var s: string + s.Foo.add('c') + doAssert s.string == "c" # was failing + test() + +static: main() +main() From 6d7d1e60fea201109bdafce550622b5b49e23323 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 31 Mar 2021 02:25:26 -0700 Subject: [PATCH 2331/4254] fix #14585, fix #17589: access to static param now works (#17590) --- compiler/types.nim | 2 +- compiler/vmgen.nim | 2 +- tests/statictypes/tstatic.nim | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/statictypes/tstatic.nim diff --git a/compiler/types.nim b/compiler/types.nim index a0d43ec09..1dbbc3261 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -67,7 +67,7 @@ const tyAlias, tyInferred, tySink, tyOwned} # see also ast.abstractVarRange abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, - tyInferred, tySink, tyOwned} + tyInferred, tySink, tyOwned} # xxx what about tyStatic? abstractInstOwned* = abstractInst + {tyOwned} skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias, tyInferred, tySink, tyLent, tyOwned} diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index f6e385976..be26f98b3 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -980,7 +980,7 @@ proc genBindSym(c: PCtx; n: PNode; dest: var TDest) = proc fitsRegister*(t: PType): bool = assert t != nil - t.skipTypes(abstractInst-{tyTypeDesc}).kind in { + t.skipTypes(abstractInst + {tyStatic} - {tyTypeDesc}).kind in { tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar} proc ldNullOpcode(t: PType): TOpcode = diff --git a/tests/statictypes/tstatic.nim b/tests/statictypes/tstatic.nim new file mode 100644 index 000000000..aaa63534b --- /dev/null +++ b/tests/statictypes/tstatic.nim @@ -0,0 +1,56 @@ +discard """ + targets: "c cpp js" +""" + +template main() = + block: # bug #17589 + #[ + # all those gave some variation of the same bug: + 'intVal' is not accessible using discriminant 'kind' of type 'TFullReg' + 'floatVal' is not accessible using discriminant 'kind' of type 'TFullReg' + ]# + block: + proc f(a: static uint64): uint64 = + a + const x = 3'u64 + static: doAssert f(x) == 3'u64 + doAssert f(x) == 3'u64 + + block: + proc f(a: static uint64): uint64 = + a + const x = 3'u64 + static: doAssert f(x) == 3'u64 + doAssert f(x) == 3'u64 + + block: + proc foo(x: uint8): uint8 = x + proc f(a: static uint8): auto = foo(a) + const x = 3'u8 + static: doAssert f(x) == 3'u8 + doAssert f(x) == 3'u8 + + block: + template foo2(x: float) = + let b = x == 0 + proc foo(x: float) = foo2(x) + proc f(a: static float) = foo(a) + const x = 1.0 + static: f(x) + + block: + proc foo(x: int32) = + let b = x == 0 + proc f(a: static int32) = foo(a) + static: f(32767) # was working + static: f(32768) # was failing because >= int16.high (see isInt16Lit) + + block: # bug #14585 + const foo_m0ninv = 0x1234'u64 + proc foo(m0ninv: static uint64) = + let b = $m0ninv + static: + foo(foo_m0ninv) + +static: main() +main() From b18307f94060d2f672a83d72c557f3856368b73a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 31 Mar 2021 02:27:02 -0700 Subject: [PATCH 2332/4254] fix #17572 (#17586) --- compiler/vm.nim | 3 ++- tests/misc/tunsignedconv.nim | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index baaf0f14e..e3ba2994f 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -415,7 +415,8 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): else: internalError(c.config, "cannot convert to string " & desttyp.typeToString) else: - case skipTypes(desttyp, abstractVarRange).kind + let desttyp = skipTypes(desttyp, abstractVarRange) + case desttyp.kind of tyInt..tyInt64: dest.ensureKind(rkInt) case skipTypes(srctyp, abstractRange).kind diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index b9463b5f0..0acb39106 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -79,3 +79,19 @@ except RangeDefect: success = true doAssert success, "conversion should fail at runtime" + +template main() = + # xxx move all tests under here so it gets tested in CT and RT + block: # bug #17572 + type T = distinct uint64 + func f(x: uint64): auto = + let a = T(x) + (x, a.uint64) + const x = 1'u64 shl 63 or 7 + const b = T(x) + doAssert b.uint64 == 9223372036854775815'u64 + doAssert $b.uint64 == "9223372036854775815" + doAssert f(x) == (9223372036854775815'u64, 9223372036854775815'u64) + +static: main() +main() From ece714773491de1757d9afbda6d499de9b610b31 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 31 Mar 2021 13:26:44 +0200 Subject: [PATCH 2333/4254] better error messages for .raise effect analysis (#17595) --- compiler/sempass2.nim | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index a1572c85e..87d196fad 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -304,8 +304,8 @@ proc addToIntersection(inter: var TIntersection, s: int) = proc throws(tracked, n, orig: PNode) = if n.typ == nil or n.typ.kind != tyError: if orig != nil: - let x = copyNode(n) - x.info = orig.info + let x = copyTree(orig) + x.typ = n.typ tracked.add x else: tracked.add n @@ -329,7 +329,7 @@ proc createTag(g: ModuleGraph; n: PNode): PNode = if not n.isNil: result.info = n.info proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) = - assert e.kind != nkRaiseStmt + #assert e.kind != nkRaiseStmt var aa = a.exc for i in a.bottom.. 0: rr = rr.lastSon + localError(g.config, r.info, errGenerated, renderTree(rr) & " " & msg & typeToString(r.typ)) popInfoContext(g.config) # hint about unnecessarily listed exception types: if hints: From d3529d0d5afb4d30bd7bdcbc49ff77fd5e67ed39 Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 31 Mar 2021 13:34:32 +0200 Subject: [PATCH 2334/4254] [ci skip] minor: fix indentation in manual.rst --- doc/manual.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index fdc744bc7..1fe554437 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6156,12 +6156,12 @@ avoid ambiguity when there are multiple modules with the same path. There are two pseudo directories: 1. `std`: The `std` pseudo directory is the abstract location of Nim's standard -library. For example, the syntax `import std / strutils` is used to unambiguously -refer to the standard library's `strutils` module. + library. For example, the syntax `import std / strutils` is used to unambiguously + refer to the standard library's `strutils` module. 2. `pkg`: The `pkg` pseudo directory is used to unambiguously refer to a Nimble -package. However, for technical details that lie outside the scope of this document, -its semantics are: *Use the search path to look for module name but ignore the standard -library locations*. In other words, it is the opposite of `std`. + package. However, for technical details that lie outside the scope of this document, + its semantics are: *Use the search path to look for module name but ignore the standard + library locations*. In other words, it is the opposite of `std`. From import statement From 0be7f854ed0327c3c2c75e682eddab2b502538bb Mon Sep 17 00:00:00 2001 From: narimiran Date: Wed, 31 Mar 2021 13:45:14 +0200 Subject: [PATCH 2335/4254] [ci skip] correct indentation this time --- doc/manual.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 1fe554437..b1aae2669 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6156,12 +6156,12 @@ avoid ambiguity when there are multiple modules with the same path. There are two pseudo directories: 1. `std`: The `std` pseudo directory is the abstract location of Nim's standard - library. For example, the syntax `import std / strutils` is used to unambiguously - refer to the standard library's `strutils` module. + library. For example, the syntax `import std / strutils` is used to unambiguously + refer to the standard library's `strutils` module. 2. `pkg`: The `pkg` pseudo directory is used to unambiguously refer to a Nimble - package. However, for technical details that lie outside the scope of this document, - its semantics are: *Use the search path to look for module name but ignore the standard - library locations*. In other words, it is the opposite of `std`. + package. However, for technical details that lie outside the scope of this document, + its semantics are: *Use the search path to look for module name but ignore the standard + library locations*. In other words, it is the opposite of `std`. From import statement From 65efa727ffec223fd9e9fa8efcff38246f7b9ad4 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 31 Mar 2021 17:20:42 +0100 Subject: [PATCH 2336/4254] Removes asynchttpserver.getSocket. (#17587) --- lib/pure/asynchttpserver.nim | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index ec464682e..3982edc54 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -84,20 +84,6 @@ proc getPort*(self: AsyncHttpServer): Port {.since: (1, 5, 1).} = server.close() result = getLocalAddr(self.socket.getFd, AF_INET)[1] -func getSocket*(self: AsyncHttpServer): AsyncSocket {.since: (1, 5, 1).} = - ## Field accessor. - runnableExamples: - from std/asyncnet import getFd - from std/nativesockets import getLocalAddr, AF_INET, Port - let server = newAsyncHttpServer() - server.listen(Port(0)) # Socket is not bound until this point - # note: a more direct way to get the port is `getPort`. - let (laddr, port) = getLocalAddr(server.getSocket.getFd, AF_INET) - assert uint16(port) > 0 - assert laddr == "0.0.0.0" - server.close() - self.socket - proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = ## Creates a new `AsyncHttpServer` instance. From 9b67e5c61b50424e66b2a9bc8cc566058c71a223 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 31 Mar 2021 09:24:39 -0700 Subject: [PATCH 2337/4254] jsonutils: support cstring (including as Table key); improve docs (#16062) * jsonutils: support cstring (including as Table key); improve docs * changelog * un-disable a test now that #16061 was fixed --- changelog.md | 2 ++ lib/std/jsonutils.nim | 22 +++++++++++++++++----- tests/stdlib/thashes.nim | 1 + tests/stdlib/tjsonutils.nim | 13 ++++++++----- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index c234bf174..f6dcee833 100644 --- a/changelog.md +++ b/changelog.md @@ -47,6 +47,8 @@ - Added an overload for the `collect` macro that inferes the container type based on the syntax of the last expression. Works with std seqs, tables and sets. +- `jsonutils` now handles `cstring` (including as Table key). + - Added `randState` template that exposes the default random number generator. Useful for library authors. diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index fa61d79db..a5daa9fb4 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -11,7 +11,7 @@ runnableExamples: z1: int8 let a = (1.5'f32, (b: "b2", a: "a2"), 'x', @[Foo(t: true, z1: -3), nil], [{"name": "John"}.newStringTable]) let j = a.toJson - doAssert j.jsonTo(typeof(a)).toJson == j + assert j.jsonTo(typeof(a)).toJson == j import std/[json,strutils,tables,sets,strtabs,options] @@ -197,6 +197,11 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = else: a.distinctBase.fromJson(b) elif T is string|SomeNumber: a = to(b,T) + elif T is cstring: + case b.kind + of JNull: a = nil + of JString: a = b.str + else: checkJson false, $($T, " ", b) elif T is JsonNode: a = b elif T is ref | ptr: if b.kind == JNull: a = nil @@ -273,9 +278,10 @@ proc toJson*[T](a: T): JsonNode = elif T is bool: result = %(a) elif T is SomeInteger: result = %a elif T is Ordinal: result = %(a.ord) + elif T is cstring: (if a == nil: result = newJNull() else: result = % $a) else: result = %a -proc fromJsonHook*[K, V](t: var (Table[K, V] | OrderedTable[K, V]), +proc fromJsonHook*[K: string|cstring, V](t: var (Table[K, V] | OrderedTable[K, V]), jsonNode: JsonNode) = ## Enables `fromJson` for `Table` and `OrderedTable` types. ## @@ -296,21 +302,27 @@ proc fromJsonHook*[K, V](t: var (Table[K, V] | OrderedTable[K, V]), for k, v in jsonNode: t[k] = jsonTo(v, V) -proc toJsonHook*[K, V](t: (Table[K, V] | OrderedTable[K, V])): JsonNode = +proc toJsonHook*[K: string|cstring, V](t: (Table[K, V] | OrderedTable[K, V])): JsonNode = ## Enables `toJson` for `Table` and `OrderedTable` types. ## ## See also: ## * `fromJsonHook proc<#fromJsonHook,,JsonNode>`_ + # pending PR #9217 use: toSeq(a) instead of `collect` in `runnableExamples`. runnableExamples: - import std/[tables, json] + import std/[tables, json, sugar] let foo = ( t: [("two", 2)].toTable, ot: [("one", 1), ("three", 3)].toOrderedTable) assert $toJson(foo) == """{"t":{"two":2},"ot":{"one":1,"three":3}}""" + # if keys are not string|cstring, you can use this: + let a = {10: "foo", 11: "bar"}.newOrderedTable + let a2 = collect: (for k,v in a: (k,v)) + assert $toJson(a2) == """[[10,"foo"],[11,"bar"]]""" result = newJObject() for k, v in pairs(t): - result[k] = toJson(v) + # not sure if $k has overhead for string + result[(when K is string: k else: $k)] = toJson(v) proc fromJsonHook*[A](s: var SomeSet[A], jsonNode: JsonNode) = ## Enables `fromJson` for `HashSet` and `OrderedSet` types. diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index a4487c8c0..044259f88 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -87,6 +87,7 @@ block largeSize: # longer than 4 characters proc main() = doAssert hash(0.0) == hash(0) + # bug #16061 doAssert hash(cstring"abracadabra") == 97309975 doAssert hash(cstring"abracadabra") == hash("abracadabra") diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 63bf97704..eaf5d68f9 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -14,6 +14,7 @@ proc testRoundtrip[T](t: T, expected: string) = doAssert t2.toJson == j import tables, sets, algorithm, sequtils, options, strtabs +from strutils import contains type Foo = ref object id: int @@ -40,27 +41,29 @@ template fn() = # https://github.com/nim-lang/Nim/issues/12282 testRoundtrip(Foo(1.5)): """1.5""" - block: + block: # OrderedTable testRoundtrip({"z": "Z", "y": "Y"}.toOrderedTable): """{"z":"Z","y":"Y"}""" + doAssert toJson({"z": 10, "": 11}.newTable).`$`.contains """"":11""" # allows hash to change + testRoundtrip({"z".cstring: 1, "".cstring: 2}.toOrderedTable): """{"z":1,"":2}""" testRoundtrip({"z": (f1: 'f'), }.toTable): """{"z":{"f1":102}}""" - block: + block: # StringTable testRoundtrip({"name": "John", "city": "Monaco"}.newStringTable): """{"mode":"modeCaseSensitive","table":{"city":"Monaco","name":"John"}}""" block: # complex example let t = {"z": "Z", "y": "Y"}.newStringTable type A = ref object a1: string - let a = (1.1, "fo", 'x', @[10,11], [true, false], [t,newStringTable()], [0'i8,3'i8], -4'i16, (foo: 0.5'f32, bar: A(a1: "abc"), bar2: A.default)) + let a = (1.1, "fo", 'x', @[10,11], [true, false], [t,newStringTable()], [0'i8,3'i8], -4'i16, (foo: 0.5'f32, bar: A(a1: "abc"), bar2: A.default, cstring1: "foo", cstring2: "", cstring3: cstring(nil))) testRoundtrip(a): - """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null}]""" + """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null,"cstring1":"foo","cstring2":"","cstring3":null}]""" block: # edge case when user defined `==` doesn't handle `nil` well, e.g.: # https://github.com/nim-lang/nimble/blob/63695f490728e3935692c29f3d71944d83bb1e83/src/nimblepkg/version.nim#L105 testRoundtrip(@[Foo(id: 10), nil]): """[{"id":10},null]""" - block: + block: # enum type Foo = enum f1, f2, f3, f4, f5 type Bar = enum b1, b2, b3, b4 let a = [f2: b2, f3: b3, f4: b4] From 3f9c26539de010eaa12a879154f60e4bf656e6e3 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 1 Apr 2021 02:54:36 +0800 Subject: [PATCH 2338/4254] close #16786 (#17598) --- tests/async/tasyncintemplate.nim | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/async/tasyncintemplate.nim b/tests/async/tasyncintemplate.nim index 31f4cd95c..0f810b5be 100644 --- a/tests/async/tasyncintemplate.nim +++ b/tests/async/tasyncintemplate.nim @@ -1,12 +1,46 @@ discard """ - output: 42 + output: ''' +42 +1 +2 +3 +4 +''' """ import asyncdispatch +# bug #16159 template foo() = proc temp(): Future[int] {.async.} = return 42 proc tempVoid(): Future[void] {.async.} = echo await temp() foo() waitFor tempVoid() + + +block: # bug #16786 + block: + proc main(a: int|string)= + proc bar(b: int|string) = echo b + bar(a) + main(1) + + block: + proc main(a: int) : Future[void] {.async.} = + proc bar(b: int): Future[void] {.async.} = echo b + await bar(a) + waitFor main(2) + + block: + proc main(a: int) : Future[void] {.async.} = + proc bar(b: int | string): Future[void] {.async.} = echo b + await bar(a) + waitFor main(3) + + block: + # bug + proc main(a: int|string) = + proc bar(b: int): Future[void] {.async.} = echo b + waitFor bar(a) + main(4) From fe9a37f2a57d0e76984b25c3dfe0fbdc94a30d9e Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 1 Apr 2021 02:55:27 +0800 Subject: [PATCH 2339/4254] close #12684 add testcase (#17599) --- tests/compiler/t12684.nim | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compiler/t12684.nim diff --git a/tests/compiler/t12684.nim b/tests/compiler/t12684.nim new file mode 100644 index 000000000..a5f33d2c9 --- /dev/null +++ b/tests/compiler/t12684.nim @@ -0,0 +1,7 @@ +discard """ + cmd: "nim check --hints:off --warnings:off $file" + errormsg: "undeclared identifier: 'Undeclared'" +""" + +var x: Undeclared +import compiler/nimeval From 924ab3adea30b8ffe590d1dd08cc3ff23f4881de Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 1 Apr 2021 14:05:04 +0800 Subject: [PATCH 2340/4254] fix #17190 `nimscript` now accepts arbitrary file extensions for `nim e main.customext` (#17596) * fix #17190 * cah * merge * Update tnimscriptwithnimext.nim * Update tnimscriptwithmacro.nims * Apply suggestions from code review * Delete tnimscriptwithnimext.nim * Update tests/tools/tnimscriptwithmacro.nims * fix * fix * add a test * Apply suggestions from code review Co-authored-by: Timothee Cour * Apply suggestions from code review * Update changelog.md Co-authored-by: Timothee Cour Co-authored-by: Timothee Cour Co-authored-by: Andreas Rumpf --- changelog.md | 2 ++ compiler/main.nim | 2 -- compiler/nimconf.nim | 7 +++++-- tests/misc/trunner.nim | 9 +++++++++ tests/newconfig/foo2/mfoo2.customext | 2 ++ 5 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 tests/newconfig/foo2/mfoo2.customext diff --git a/changelog.md b/changelog.md index f6dcee833..900693644 100644 --- a/changelog.md +++ b/changelog.md @@ -281,6 +281,8 @@ - Tuple expressions are now parsed consistently as `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. +- `nim e` now accepts arbitrary file extensions for the nimscript file, + although `.nims` is still the preferred extension in general. ## Compiler changes diff --git a/compiler/main.nim b/compiler/main.nim index b61cdcadb..26a19063f 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -342,8 +342,6 @@ proc mainCommand*(graph: ModuleGraph) = if conf.projectIsCmd or conf.projectIsStdin: discard elif not fileExists(conf.projectFull): rawMessage(conf, errGenerated, "NimScript file does not exist: " & conf.projectFull.string) - elif not conf.projectFull.string.endsWith(".nims"): - rawMessage(conf, errGenerated, "not a NimScript file: " & conf.projectFull.string) # main NimScript logic handled in `loadConfigs`. of cmdNop: discard of cmdJsonscript: diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 1691e7ccf..b63e5a0ad 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -298,11 +298,14 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: for filename in configFiles: # delayed to here so that `hintConf` is honored rawMessage(conf, hintConf, filename.string) - if scriptIsProj: + if conf.cmd == cmdNimscript: showHintConf() configFiles.setLen 0 if conf.cmd != cmdIdeTools: - runNimScriptIfExists(scriptFile, isMain = true) + if conf.cmd == cmdNimscript: + runNimScriptIfExists(conf.projectFull, isMain = true) + else: + runNimScriptIfExists(scriptFile, isMain = true) else: if not scriptIsProj: runNimScriptIfExists(scriptFile, isMain = true) diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index a66177f28..1895eeb97 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -238,6 +238,15 @@ tests/newconfig/bar/mfoo.nims""".splitLines expected.add &"Hint: used config file '{b}' [Conf]\n" doAssert outp.endsWith expected, outp & "\n" & expected + block: # mfoo2.customext + let filename = testsDir / "newconfig/foo2/mfoo2.customext" + let cmd = fmt"{nim} e --hint:conf {filename}" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + doAssert exitCode == 0 + var expected = &"Hint: used config file '{filename}' [Conf]\n" + doAssert outp.endsWith "123" & "\n" & expected + + block: # nim --eval let opt = "--hints:off" check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0) diff --git a/tests/newconfig/foo2/mfoo2.customext b/tests/newconfig/foo2/mfoo2.customext new file mode 100644 index 000000000..66c8b1d15 --- /dev/null +++ b/tests/newconfig/foo2/mfoo2.customext @@ -0,0 +1,2 @@ +doAssert defined(nimscript) +echo "123" From a7bb973a24fb73d378230216a6bfcfd2f62e4e78 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 31 Mar 2021 23:45:55 -0700 Subject: [PATCH 2341/4254] docgen: render pragmas by default except for a select list (and fix #9074) (#17054) --- compiler/docgen.nim | 22 ++--- compiler/lexer.nim | 2 +- compiler/renderer.nim | 22 ++++- .../expected/index.html | 2 +- .../expected/subdir/subdir_b/utils.html | 2 +- nimdoc/testproject/expected/testproject.html | 82 +++++++++---------- 6 files changed, 76 insertions(+), 56 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f1a9750b7..67f21e1c4 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -446,22 +446,22 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe "\\spanIdentifier{$1}", [escLit]) of tkSpaces, tkInvalid: result.add(literal) - of tkCurlyDotLe: + of tkHideableStart: template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit]) if renderRunnableExamples in renderFlags: fun "$1" - else: fun: "" & # This span is required for the JS to work properly - """{...} + else: + # 1st span is required for the JS to work properly + fun """ + +... - -$1 -""".replace("\n", "") # Must remove newlines because wrapped in a
                                      -    of tkCurlyDotRi:
                                      +""".replace("\n", "")  # Must remove newlines because wrapped in a 
                                      +    of tkHideableEnd:
                                             template fun(s) = dispA(d.conf, result, s, "\\spanOther{$1}", [escLit])
                                             if renderRunnableExamples in renderFlags: fun "$1"
                                      -      else: fun """
                                      -
                                      -$1
                                      -""".replace("\n", "")
                                      +      else: fun ""
                                      +    of tkCurlyDotLe: dispA(d.conf, result, "$1", "\\spanOther{$1}", [escLit])
                                      +    of tkCurlyDotRi: dispA(d.conf, result, "$1", "\\spanOther{$1}", [escLit])
                                           of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
                                              tkBracketDotLe, tkBracketDotRi, tkParDotLe,
                                              tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
                                      diff --git a/compiler/lexer.nim b/compiler/lexer.nim
                                      index cca7765e5..7c7ac4177 100644
                                      --- a/compiler/lexer.nim
                                      +++ b/compiler/lexer.nim
                                      @@ -72,7 +72,7 @@ type
                                           tkDot = ".", tkDotDot = "..", tkBracketLeColon = "[:",
                                           tkOpr, tkComment, tkAccent = "`",
                                           # these are fake tokens used by renderer.nim
                                      -    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
                                      +    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, tkHideableStart, tkHideableEnd
                                       
                                         TokTypes* = set[TokType]
                                       
                                      diff --git a/compiler/renderer.nim b/compiler/renderer.nim
                                      index b9ec48185..3d260f350 100644
                                      --- a/compiler/renderer.nim
                                      +++ b/compiler/renderer.nim
                                      @@ -185,7 +185,7 @@ proc dedent(g: var TSrcGen) =
                                       proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
                                         if kind != tkSpaces:
                                           addPendingNL(g)
                                      -    if s.len > 0:
                                      +    if s.len > 0 or kind in {tkHideableStart, tkHideableEnd}:
                                             addTok(g, kind, s, sym)
                                         else:
                                           g.pendingWhitespace = s.len
                                      @@ -587,13 +587,30 @@ proc putWithSpace(g: var TSrcGen, kind: TokType, s: string) =
                                         put(g, kind, s)
                                         put(g, tkSpaces, Space)
                                       
                                      +proc isHideable(config: ConfigRef, n: PNode): bool =
                                      +  # xxx compare `ident` directly with `getIdent(cache, wRaises)`, but
                                      +  # this requires a `cache`.
                                      +  case n.kind
                                      +  of nkExprColonExpr: result = n[0].kind == nkIdent and n[0].ident.s in ["raises", "tags", "extern"]
                                      +  of nkIdent: result = n.ident.s in ["gcsafe"]
                                      +  else: result = false
                                      +
                                       proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
                                                      theEnd: int = - 1, separator = tkComma) =
                                      +  let inPragma = g.inPragma == 1 # just the top-level
                                      +  var inHideable = false
                                         for i in start..n.len + theEnd:
                                           var c = i < n.len + theEnd
                                           var sublen = lsub(g, n[i]) + ord(c)
                                           if not fits(g, g.lineLen + sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
                                           let oldLen = g.tokens.len
                                      +    if inPragma:
                                      +      if not inHideable and isHideable(g.config, n[i]):
                                      +        inHideable = true
                                      +        put(g, tkHideableStart, "")
                                      +      elif inHideable and not isHideable(g.config, n[i]):
                                      +        inHideable = false
                                      +        put(g, tkHideableEnd, "")
                                           gsub(g, n[i])
                                           if c:
                                             if g.tokens.len > oldLen:
                                      @@ -601,6 +618,9 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
                                             if shouldRenderComment(g) and hasCom(n[i]):
                                               gcoms(g)
                                               optNL(g, ind)
                                      +  if inHideable:
                                      +    put(g, tkHideableEnd, "")
                                      +    inHideable = false
                                       
                                       proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
                                                   theEnd: int = - 1) =
                                      diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html
                                      index db7470050..bac39fd33 100644
                                      --- a/nimdoc/test_out_index_dot_html/expected/index.html
                                      +++ b/nimdoc/test_out_index_dot_html/expected/index.html
                                      @@ -117,7 +117,7 @@ window.addEventListener('DOMContentLoaded', main);
                                       

                                      Procs

                                      -
                                      proc foo() {...}{.raises: [], tags: [].}
                                      +
                                      proc foo() {....raises: [], tags: [].}
                                      I do foo diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index cb80f2873..c1ee9c49d 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -177,7 +177,7 @@ window.addEventListener('DOMContentLoaded', main);

                                      Procs

                                      -
                                      proc someType(): SomeType {...}{.raises: [], tags: [].}
                                      +
                                      proc someType(): SomeType {....raises: [], tags: [].}
                                      constructor. diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 599a904a2..8525048ea 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -444,7 +444,7 @@ window.addEventListener('DOMContentLoaded', main);

                                      Types

                                      -
                                      A {...}{.inject.} = enum
                                      +
                                      A {.inject.} = enum
                                         aA
                                      @@ -452,7 +452,7 @@ The enum A.
                                      -
                                      B {...}{.inject.} = enum
                                      +
                                      B {.inject.} = enum
                                         bB
                                      @@ -542,7 +542,7 @@ This should be visible.
                                      -
                                      proc baz[T](a, b: T): T {...}{.deprecated.}
                                      +
                                      proc baz[T](a, b: T): T {.deprecated.}
                                      Deprecated @@ -552,7 +552,7 @@ This is deprecated without message.
                                      -
                                      proc buzz[T](a, b: T): T {...}{.deprecated: "since v0.20".}
                                      +
                                      proc buzz[T](a, b: T): T {.deprecated: "since v0.20".}
                                      Deprecated: since v0.20 @@ -562,14 +562,14 @@ This is deprecated with a message.
                                      -
                                      func someFunc() {...}{.raises: [], tags: [].}
                                      +
                                      func someFunc() {....raises: [], tags: [].}
                                      My someFunc. Stuff in quotes here. Some link
                                      -
                                      proc fromUtils3() {...}{.raises: [], tags: [].}
                                      +
                                      proc fromUtils3() {....raises: [], tags: [].}
                                      came form utils but should be shown where fromUtilsGen is called @@ -585,14 +585,14 @@ came form utils but should be shown where -
                                      proc z1(): Foo {...}{.raises: [], tags: [].}
                                      +
                                      proc z1(): Foo {....raises: [], tags: [].}
                                      cz1
                                      -
                                      proc z2() {...}{.raises: [], tags: [].}
                                      +
                                      proc z2() {....raises: [], tags: [].}
                                      cz2 @@ -601,49 +601,49 @@ cz2
                                      -
                                      proc z3() {...}{.raises: [], tags: [].}
                                      +
                                      proc z3() {....raises: [], tags: [].}
                                      cz3
                                      -
                                      proc z4() {...}{.raises: [], tags: [].}
                                      +
                                      proc z4() {....raises: [], tags: [].}
                                      cz4
                                      -
                                      proc z5(): int {...}{.raises: [], tags: [].}
                                      +
                                      proc z5(): int {....raises: [], tags: [].}
                                      cz5
                                      -
                                      proc z6(): int {...}{.raises: [], tags: [].}
                                      +
                                      proc z6(): int {....raises: [], tags: [].}
                                      cz6
                                      -
                                      proc z7(): int {...}{.raises: [], tags: [].}
                                      +
                                      proc z7(): int {....raises: [], tags: [].}
                                      cz7
                                      -
                                      proc z8(): int {...}{.raises: [], tags: [].}
                                      +
                                      proc z8(): int {....raises: [], tags: [].}
                                      cz8
                                      -
                                      proc z9() {...}{.raises: [], tags: [].}
                                      +
                                      proc z9() {....raises: [], tags: [].}
                                      @@ -652,7 +652,7 @@ cz8
                                      -
                                      proc z10() {...}{.raises: [], tags: [].}
                                      +
                                      proc z10() {....raises: [], tags: [].}
                                      @@ -661,7 +661,7 @@ cz8
                                      -
                                      proc z11() {...}{.raises: [], tags: [].}
                                      +
                                      proc z11() {....raises: [], tags: [].}
                                      @@ -670,7 +670,7 @@ cz8
                                      -
                                      proc z12(): int {...}{.raises: [], tags: [].}
                                      +
                                      proc z12(): int {....raises: [], tags: [].}
                                      @@ -679,7 +679,7 @@ cz8
                                      -
                                      proc z13() {...}{.raises: [], tags: [].}
                                      +
                                      proc z13() {....raises: [], tags: [].}
                                      cz13 @@ -688,14 +688,14 @@ cz13
                                      -
                                      proc baz() {...}{.raises: [], tags: [].}
                                      +
                                      proc baz() {....raises: [], tags: [].}
                                      -
                                      proc z17() {...}{.raises: [], tags: [].}
                                      +
                                      proc z17() {....raises: [], tags: [].}
                                      cz17 rest @@ -704,7 +704,7 @@ cz17 rest
                                      -
                                      proc p1() {...}{.raises: [], tags: [].}
                                      +
                                      proc p1() {....raises: [], tags: [].}
                                      cp1 @@ -727,7 +727,7 @@ this is a nested doc comment
                                      -
                                      proc addfBug14485() {...}{.raises: [], tags: [].}
                                      +
                                      proc addfBug14485() {....raises: [], tags: [].}
                                      Some proc @@ -746,23 +746,23 @@ Some proc
                                      -
                                      proc c_printf(frmt: cstring): cint {...}{.importc: "printf", header: "<stdio.h>",
                                      -                                     varargs, discardable.}
                                      +
                                      proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
                                      +                                     varargs, discardable.}
                                      the c printf. etc.
                                      -
                                      proc c_nonexistant(frmt: cstring): cint {...}{.importc: "nonexistant",
                                      -    header: "<stdio.h>", varargs, discardable.}
                                      +
                                      proc c_nonexistant(frmt: cstring): cint {.importc: "nonexistant",
                                      +    header: "<stdio.h>", varargs, discardable.}
                                      -
                                      proc low[T: Ordinal | enum | range](x: T): T {...}{.magic: "Low", noSideEffect.}
                                      +
                                      proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}

                                      Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                                      @@ -773,7 +773,7 @@ the c printf. etc.
                                      -
                                      proc low2[T: Ordinal | enum | range](x: T): T {...}{.magic: "Low", noSideEffect.}
                                      +
                                      proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}

                                      Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                                      @@ -786,7 +786,7 @@ the c printf. etc.
                                      -
                                      proc tripleStrLitTest() {...}{.raises: [], tags: [].}
                                      +
                                      proc tripleStrLitTest() {....raises: [], tags: [].}
                                      @@ -829,22 +829,22 @@ at indent 0
                                      -
                                      proc asyncFun1(): Future[int] {...}{.raises: [Exception, ValueError],
                                      -                                tags: [RootEffect].}
                                      +
                                      proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
                                      +                                tags: [RootEffect].}
                                      ok1
                                      -
                                      proc asyncFun2(): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}
                                      +
                                      proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
                                      -
                                      proc asyncFun3(): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}
                                      +
                                      proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
                                      @@ -853,7 +853,7 @@ ok1
                                      -
                                      proc anything() {...}{.raises: [], tags: [].}
                                      +
                                      proc anything() {....raises: [], tags: [].}
                                      There is no block quote after blank lines at the beginning. @@ -865,21 +865,21 @@ There is no block quote after blank lines at the beginning.

                                      Methods

                                      -
                                      method method1(self: Moo) {...}{.raises: [], tags: [].}
                                      +
                                      method method1(self: Moo) {....raises: [], tags: [].}
                                      foo1
                                      -
                                      method method2(self: Moo): int {...}{.raises: [], tags: [].}
                                      +
                                      method method2(self: Moo): int {....raises: [], tags: [].}
                                      foo2
                                      -
                                      method method3(self: Moo): int {...}{.raises: [], tags: [].}
                                      +
                                      method method3(self: Moo): int {....raises: [], tags: [].}
                                      foo3 @@ -891,7 +891,7 @@ foo3

                                      Iterators

                                      -
                                      iterator fromUtils1(): int {...}{.raises: [], tags: [].}
                                      +
                                      iterator fromUtils1(): int {....raises: [], tags: [].}
                                      @@ -902,14 +902,14 @@ foo3
                                      -
                                      iterator iter1(n: int): int {...}{.raises: [], tags: [].}
                                      +
                                      iterator iter1(n: int): int {....raises: [], tags: [].}
                                      foo1
                                      -
                                      iterator iter2(n: int): int {...}{.raises: [], tags: [].}
                                      +
                                      iterator iter2(n: int): int {....raises: [], tags: [].}
                                      foo2 From 6f53579a8ceb7576fb1b31f72c9d584916b4b5d9 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 1 Apr 2021 14:47:59 +0800 Subject: [PATCH 2342/4254] close #9534 add testcase (#17607) --- tests/template/t9534.nim | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/template/t9534.nim diff --git a/tests/template/t9534.nim b/tests/template/t9534.nim new file mode 100644 index 000000000..8d66f42a0 --- /dev/null +++ b/tests/template/t9534.nim @@ -0,0 +1,21 @@ +discard """ + targets: "c cpp" +""" + +# bug #9534 +type + Object = object + data: int + +template test() = + proc methodName(o: Object): int = + var p: pointer + doAssert o.data == 521 + let f {.used.} = cast[proc (o: int): int {.nimcall.}](p) + doAssert o.data == 521 + result = 1314 + + var a = Object(data: 521) + doAssert methodName(a) == 1314 + +test() From a31e601550cc6f9fd9e09b385bfbd869a408cd4b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 31 Mar 2021 23:48:44 -0700 Subject: [PATCH 2343/4254] misc fixes: build_all.sh, changelog (#17601) * fix a bug in build_all.sh: $@ => "$@" * remove getSocket from changelog following #17587 * remove unused import --- build_all.sh | 2 +- changelog.md | 2 +- compiler/errorhandling.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build_all.sh b/build_all.sh index e66980e56..c3c6e68b7 100755 --- a/build_all.sh +++ b/build_all.sh @@ -42,7 +42,7 @@ build_nim_csources(){ echo_run cp bin/nim $nim_csources } -[ -f $nim_csources ] || echo_run build_nim_csources $@ +[ -f $nim_csources ] || echo_run build_nim_csources "$@" # Note: if fails, may need to `cd csources && git pull` echo_run bin/nim c --skipUserCfg --skipParentCfg koch diff --git a/changelog.md b/changelog.md index 900693644..53d30bf36 100644 --- a/changelog.md +++ b/changelog.md @@ -73,7 +73,7 @@ - Added `asyncdispatch.activeDescriptors` that returns the number of currently active async event handles/file descriptors. -- Added to `asynchttpserver` `getPort` and `getSocket`. +- Added `getPort` to `asynchttpserver`. - `--gc:orc` is now 10% faster than previously for common workloads. If you have trouble with its changed behavior, compile with `-d:nimOldOrc`. diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim index d7092d477..cda7ab3f4 100644 --- a/compiler/errorhandling.nim +++ b/compiler/errorhandling.nim @@ -10,7 +10,7 @@ ## This module contains support code for new-styled error ## handling via an `nkError` node kind. -import ast, renderer, options, lineinfos, strutils, types +import ast, renderer, options, strutils, types type ErrorKind* = enum ## expand as you need. From f3c504e49a4e24b7fbdcd5c8eec786fa86616233 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 1 Apr 2021 14:49:10 +0800 Subject: [PATCH 2344/4254] a bit better message (#17606) --- compiler/ccgtypes.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 761fd5bf8..9d95e3f67 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -194,8 +194,8 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: if typ.n != nil: result = mapType(conf, lastSon typ, kind) - else: doAssert(false, "mapType") - else: doAssert(false, "mapType") + else: doAssert(false, "mapType: " & $typ.kind) + else: doAssert(false, "mapType: " & $typ.kind) proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr From e25a487ed6237d30a461137d0a206e1e1a2f62d9 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 1 Apr 2021 18:46:47 +0800 Subject: [PATCH 2345/4254] close #6133 add testcase (#17605) * close #6133 add testcase * b --- tests/system/tstatic.nim | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/system/tstatic.nim diff --git a/tests/system/tstatic.nim b/tests/system/tstatic.nim new file mode 100644 index 000000000..1f1b9dbe3 --- /dev/null +++ b/tests/system/tstatic.nim @@ -0,0 +1,50 @@ +discard """ + targets: "c cpp js" +""" + +import std/strutils + +# bug #6133 +template main() = + block: + block: + proc foo(q: string, a: int): int = + result = q.len + + proc foo(q: static[string]): int = + result = foo(q, 5) + + doAssert foo("123") == 3 + + block: + type E = enum A + + if false: + var e = A + discard $e + + proc foo(a: string): int = + len(a) # 16640 + + proc foo(a: static[bool]): int {.used.} = + discard + + doAssert foo("") == 0 + + block: + proc foo(a: string): int = + len(a) + + proc foo(a: static[bool]): int {.used.} = + discard + + doAssert foo("abc") == 3 + + block: + proc parseInt(f: static[bool]): int {.used.} = discard + + doAssert "123".parseInt == 123 + + +static: main() +main() From f0587e02e255b1fc1a0d0b21aebcacf37ec43c8f Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 1 Apr 2021 12:47:56 +0200 Subject: [PATCH 2346/4254] Fix #17017 (math edge cases) (#17588) * Fix #17017 Add more test cases * USe signbit in example --- lib/pure/math.nim | 18 ++++++++++++----- tests/stdlib/tmath.nim | 45 +++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 74a98e655..2ef7ee102 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -949,18 +949,25 @@ func frexp*[T: float32|float64](x: T): tuple[frac: T, exp: int] {.inline.} = doAssert frexp(8.0) == (0.5, 4) doAssert frexp(-8.0) == (-0.5, 4) doAssert frexp(0.0) == (0.0, 0) + # special cases: - when not defined(windows): - doAssert frexp(-0.0) == (-0.0, 0) # signbit preserved for +-0 - doAssert frexp(Inf).frac == Inf # +- Inf preserved - doAssert frexp(NaN).frac.isNaN + doAssert frexp(-0.0).frac.signbit # signbit preserved for +-0 + doAssert frexp(Inf).frac == Inf # +- Inf preserved + doAssert frexp(NaN).frac.isNaN + when not defined(js): var exp: cint result.frac = c_frexp2(x, exp) result.exp = exp else: if x == 0.0: - result = (0.0, 0) + # reuse signbit implementation + let uintBuffer = toBitsImpl(x) + if (uintBuffer[1] shr 31) != 0: + # x is -0.0 + result = (-0.0, 0) + else: + result = (0.0, 0) elif x < 0.0: result = frexp(-x) result.frac = -result.frac @@ -980,6 +987,7 @@ func frexp*[T: float32|float64](x: T, exponent: var int): T {.inline.} = var x: int doAssert frexp(5.0, x) == 0.625 doAssert x == 3 + (result, exponent) = frexp(x) diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 49b4c82f1..2cf544ddb 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -29,10 +29,6 @@ template main() = doAssert erf(6.0) > erf(5.0) doAssert erfc(6.0) < erfc(5.0) - when not defined(js) and not defined(windows): # xxx pending bug #17017 - doAssert gamma(-1.0).isNaN - - block: # sgn() tests doAssert sgn(1'i8) == 1 doAssert sgn(1'i16) == 1 @@ -46,6 +42,7 @@ template main() = doAssert sgn(123.9834'f64) == 1 doAssert sgn(0'i32) == 0 doAssert sgn(0'f32) == 0 + doAssert sgn(-0.0'f64) == 0 doAssert sgn(NegInf) == -1 doAssert sgn(Inf) == 1 doAssert sgn(NaN) == 0 @@ -358,7 +355,7 @@ template main() = doAssert almostEqual(prod([1.5, 3.4]), 5.1) let x: seq[float] = @[] doAssert prod(x) == 1.0 - + block: # clamp range doAssert clamp(10, 1..5) == 5 doAssert clamp(3, 1..5) == 3 @@ -370,8 +367,42 @@ template main() = doAssert a1.clamp(a2..a4) == a2 doAssert clamp((3, 0), (1, 0) .. (2, 9)) == (2, 9) - when not defined(windows): # xxx pending bug #17017 - doAssert sqrt(-1.0).isNaN + block: # edge cases + doAssert sqrt(-4.0).isNaN + + doAssert ln(0.0) == -Inf + doAssert ln(-0.0) == -Inf + doAssert ln(-12.0).isNaN + + doAssert log10(0.0) == -Inf + doAssert log10(-0.0) == -Inf + doAssert log10(-12.0).isNaN + + doAssert log2(0.0) == -Inf + doAssert log2(-0.0) == -Inf + doAssert log2(-12.0).isNaN + + when nimvm: discard + else: + doAssert frexp(0.0) == (0.0, 0) + doAssert frexp(-0.0) == (-0.0, 0) + doAssert classify(frexp(-0.0)[0]) == fcNegZero + + when not defined(js): + doAssert gamma(0.0) == Inf + doAssert gamma(-0.0) == -Inf + doAssert gamma(-1.0).isNaN + + doAssert lgamma(0.0) == Inf + doAssert lgamma(-0.0) == Inf + doAssert lgamma(-1.0) == Inf + + when nimvm: discard + else: + var exponent: cint + doAssert c_frexp(0.0, exponent) == 0.0 + doAssert c_frexp(-0.0, exponent) == -0.0 + doAssert classify(c_frexp(-0.0, exponent)) == fcNegZero static: main() main() From 2365b5250ec8a8893a376e75ad841d01c327893d Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 2 Apr 2021 12:06:50 +0800 Subject: [PATCH 2347/4254] docs: note regarding emit with backticks (#17608) --- doc/manual.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index b1aae2669..3c71ece95 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7039,9 +7039,9 @@ Example: void fun(){} """.} -For backward compatibility, if the argument to the `emit` statement -is a single string literal, Nim symbols can be referred to via backticks. -This usage is however deprecated. +.. note:: For backward compatibility, if the argument to the `emit` statement + is a single string literal, Nim symbols can be referred to via backticks. + This usage is however deprecated. For a top-level emit statement, the section where in the generated C/C++ file the code should be emitted can be influenced via the From 792a03b7561195b27f5ad2b9654781cc17b86c75 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 2 Apr 2021 15:18:40 +0800 Subject: [PATCH 2348/4254] [docs minor] close #16553 (#17612) Co-authored-by: Timothee Cour --- lib/pure/os.nim | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index d0b3aef1a..0710b8333 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2266,16 +2266,12 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): ## / fileA2.txt ## ## and this code: - ## - ## .. code-block:: Nim - ## for kind, path in walkDir("dirA"): - ## echo(path) - ## - ## produce this output (but not necessarily in this order!):: - ## dirA/dirB - ## dirA/dirC - ## dirA/fileA1.txt - ## dirA/fileA2.txt + runnableExamples("-r:off"): + import std/[strutils, sugar] + # note: order is not guaranteed + # this also works at compile time + assert collect(for k in walkDir("dirA"): k.path).join(" ") == + "dirA/dirB dirA/dirC dirA/fileA2.txt dirA/fileA1.txt" ## ## See also: ## * `walkPattern iterator <#walkPattern.i,string>`_ From 774e66f3d123520c44016ca23fd103538fc3c87d Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 2 Apr 2021 17:56:30 +0800 Subject: [PATCH 2349/4254] close #7875 add testcase (#17611) * close #7875 add testcase * fix --- tests/macros/t7875.nim | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/macros/t7875.nim diff --git a/tests/macros/t7875.nim b/tests/macros/t7875.nim new file mode 100644 index 000000000..7b6e47b86 --- /dev/null +++ b/tests/macros/t7875.nim @@ -0,0 +1,22 @@ +discard """ + nimout: "var mysym`gensym0: MyType[float32]" + joinable: false +""" + +import macros + +type + MyType[T] = object + +# this is totally fine +var mysym: MyType[float32] + +macro foobar(): untyped = + let floatSym = bindSym"float32" + + result = quote do: + var mysym: MyType[`floatSym`] + + echo result.repr + +foobar() From 9abd383a2ae36e50ee23b78654e9d8154db46c84 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 2 Apr 2021 04:11:03 -0700 Subject: [PATCH 2350/4254] new `genAst` as replacement for `quote do` (#17426) * new `macros.genAst`: fixes all issues with `quote do` * add changelog entry * add workaround for https://github.com/nim-lang/Nim/issues/2465#issuecomment-511076669 * add test for #9607 * add kNoExposeLocalInjects option * add test case for nested application of genAst * genAst: automatically call newLit when needed * allow skipping `{}`: genAst: foo * add test that shows this fixes #11986 * add examples showing mixin; add examples showing passing types, macros, templates * move to std/genasts * improve docs --- changelog.md | 3 + lib/core/macros.nim | 5 +- lib/std/genasts.nim | 87 +++++++++++++ tests/stdlib/mgenast.nim | 53 ++++++++ tests/stdlib/tgenast.nim | 269 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 lib/std/genasts.nim create mode 100644 tests/stdlib/mgenast.nim create mode 100644 tests/stdlib/tgenast.nim diff --git a/changelog.md b/changelog.md index 53d30bf36..020d8a350 100644 --- a/changelog.md +++ b/changelog.md @@ -255,6 +255,9 @@ - Added `hasClosure` to `std/typetraits`. +- Added `genasts.genAst` that avoids the problems inherent with `quote do` and can + be used as a replacement. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 795909c6b..49c9a999c 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -539,6 +539,7 @@ proc parseStmt*(s: string): NimNode {.noSideEffect.} = proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEffect.} ## Obtains the AST nodes returned from a macro or template invocation. + ## See also `genasts.genAst`. ## Example: ## ## .. code-block:: nim @@ -559,6 +560,8 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} = ## ## A custom operator interpolation needs accent quoted (``) whenever it resolves ## to a symbol. + ## + ## See also `genasts `_ which avoids some issues with `quote`. runnableExamples: macro check(ex: untyped) = # this is a simplified version of the check macro from the @@ -1419,7 +1422,7 @@ proc expectIdent*(n: NimNode, name: string) {.since: (1,1).} = if not eqIdent(n, name): error("Expected identifier to be `" & name & "` here", n) -proc hasArgOfName*(params: NimNode; name: string): bool= +proc hasArgOfName*(params: NimNode; name: string): bool = ## Search `nnkFormalParams` for an argument. expectKind(params, nnkFormalParams) for i in 1..`_ for details. + # Default is unset, to avoid hijacking of uncaptured local symbols by + # symbols in caller scope. + kNoNewLit, + # don't call call newLit automatically in `genAst` capture parameters + +macro genAstOpt*(options: static set[GenAstOpt], args: varargs[untyped]): untyped = + ## Accepts a list of captured variables `a=b` or `a` and a block and returns the + ## AST that represents it. Local `{.inject.}` symbols (e.g. procs) are captured + ## unless `kDirtyTemplate in options`. + runnableExamples: + # This example shows how one could write a simplified version of `unittest.check`. + import std/[macros, strutils] + macro check2(cond: bool): untyped = + assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind + result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]): + # each local symbol we access must be explicitly captured + if not cond: + doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] + let a = 3 + check2 a*2 == a+3 + if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4' + + runnableExamples: + # This example goes in more details about the capture semantics. + macro fun(a: string, b: static bool): untyped = + let c = 'z' + var d = 11 # implicitly {.gensym.} and needs to be captured for use in `genAst`. + proc localFun(): auto = 12 # implicitly {.inject.}, doesn't need to be captured. + genAst(a, b, c = true): + # `a`, `b` are captured explicitly, `c` is a local definition masking `c = 'z'`. + const b2 = b # macro static param `b` is forwarded here as a static param. + # `echo d` would give: `var not init` because `d` is not captured. + (a & a, b, c, localFun()) # localFun can be called without capture. + assert fun("ab", false) == ("abab", false, true, 12) + + let params = newTree(nnkFormalParams, newEmptyNode()) + let pragmas = + if kDirtyTemplate in options: + nnkPragma.newTree(ident"dirty") + else: + newEmptyNode() + + template newLitMaybe(a): untyped = + when (a is type) or (typeof(a) is (proc | iterator | func | NimNode)): + a # `proc` actually also covers template, macro + else: newLit(a) + + # using `_` as workaround, see https://github.com/nim-lang/Nim/issues/2465#issuecomment-511076669 + let name = genSym(nskTemplate, "_fun") + let call = newCall(name) + for a in args[0..^2]: + var varName: NimNode + var varVal: NimNode + case a.kind + of nnkExprEqExpr: + varName = a[0] + varVal = a[1] + of nnkIdent: + varName = a + varVal = a + else: error("invalid argument kind: " & $a.kind, a) + if kNoNewLit notin options: varVal = newCall(bindSym"newLitMaybe", varVal) + + params.add newTree(nnkIdentDefs, varName, newEmptyNode(), newEmptyNode()) + call.add varVal + + result = newStmtList() + result.add nnkTemplateDef.newTree( + name, + newEmptyNode(), + newEmptyNode(), + params, + pragmas, + newEmptyNode(), + args[^1]) + result.add newCall(bindSym"getAst", call) + +template genAst*(args: varargs[untyped]): untyped = + ## Convenience wrapper around `genAstOpt`. + genAstOpt({}, args) diff --git a/tests/stdlib/mgenast.nim b/tests/stdlib/mgenast.nim new file mode 100644 index 000000000..2b5381891 --- /dev/null +++ b/tests/stdlib/mgenast.nim @@ -0,0 +1,53 @@ +import std/genasts +import std/macros + +# Using a enum instead of, say, int, to make apparent potential bugs related to +# forgetting converting to NimNode via newLit, see bug #9607 + +type Foo* = enum kfoo0, kfoo1, kfoo2, kfoo3, kfoo4 + +proc myLocalPriv(): auto = kfoo1 +proc myLocalPriv2(): auto = kfoo1 +macro bindme2*(): untyped = + genAst: myLocalPriv() +macro bindme3*(): untyped = + ## myLocalPriv must be captured explicitly + genAstOpt({kDirtyTemplate}, myLocalPriv): myLocalPriv() + +macro bindme4*(): untyped = + ## calling this won't compile because `myLocalPriv` isn't captured + genAstOpt({kDirtyTemplate}): myLocalPriv() + +macro bindme5UseExpose*(): untyped = + genAst: myLocalPriv2() + +macro bindme5UseExposeFalse*(): untyped = + genAstOpt({kDirtyTemplate}): myLocalPriv2() + +# example from bug #7889 +from std/streams import newStringStream, readData, writeData + +macro bindme6UseExpose*(): untyped = + genAst: + var tst = "sometext" + var ss = newStringStream("anothertext") + writeData(ss, tst[0].addr, 2) + discard readData(ss, tst[0].addr, 2) + +macro bindme6UseExposeFalse*(): untyped = + ## with `kDirtyTemplate`, requires passing all referenced symbols + ## which can be tedious + genAstOpt({kDirtyTemplate}, newStringStream, writeData, readData): + var tst = "sometext" + var ss = newStringStream("anothertext") + writeData(ss, tst[0].addr, 2) + discard readData(ss, tst[0].addr, 2) + + +proc locafun1(): auto = "in locafun1" +proc locafun2(): auto = "in locafun2" +# locafun3 in caller scope only +macro mixinExample*(): untyped = + genAst: + mixin locafun1 + (locafun1(), locafun2(), locafun3()) diff --git a/tests/stdlib/tgenast.nim b/tests/stdlib/tgenast.nim new file mode 100644 index 000000000..0904b83dd --- /dev/null +++ b/tests/stdlib/tgenast.nim @@ -0,0 +1,269 @@ +# xxx also test on js + +import std/genasts +import std/macros +from std/strformat import `&` +import ./mgenast + +proc main = + block: + macro bar(x0: static Foo, x1: Foo, x2: Foo, xignored: Foo): untyped = + let s0 = "not captured!" + let s1 = "not captured!" + let xignoredLocal = kfoo4 + + # newLit optional: + let x3 = newLit kfoo4 + let x3b = kfoo4 + + result = genAstOpt({kDirtyTemplate}, s1=true, s2="asdf", x0, x1=x1, x2, x3, x3b): + doAssert not declared(xignored) + doAssert not declared(xignoredLocal) + (s1, s2, s0, x0, x1, x2, x3, x3b) + + let s0 = "caller scope!" + + doAssert bar(kfoo1, kfoo2, kfoo3, kfoo4) == + (true, "asdf", "caller scope!", kfoo1, kfoo2, kfoo3, kfoo4, kfoo4) + + block: + # doesn't have limitation mentioned in https://github.com/nim-lang/RFCs/issues/122#issue-401636535 + macro abc(name: untyped): untyped = + result = genAst(name): + type name = object + + abc(Bar) + doAssert Bar.default == Bar() + + block: + # backticks parser limitations / ambiguities not are an issue with `genAst`: + # (#10326 #9745 are fixed but `quote do` still has underlying ambiguity issue + # with backticks) + type Foo = object + a: int + + macro m1(): untyped = + # result = quote do: # Error: undeclared identifier: 'a1' + result = genAst: + template `a1=`(x: var Foo, val: int) = + x.a = val + + m1() + var x0: Foo + x0.a1 = 10 + doAssert x0 == Foo(a: 10) + + block: + # avoids bug #7375 + macro fun(b: static[bool], b2: bool): untyped = + result = newStmtList() + macro foo(c: bool): untyped = + var b = false + result = genAst(b, c): + fun(b, c) + + foo(true) + + block: + # avoids bug #7589 + # since `==` works with genAst, the problem goes away + macro foo2(): untyped = + # result = quote do: # Error: '==' cannot be passed to a procvar + result = genAst: + `==`(3,4) + doAssert not foo2() + + block: + # avoids bug #7726 + # expressions such as `a.len` are just passed as arguments to `genAst`, and + # caller scope is not polluted with definitions such as `let b = newLit a.len` + macro foo(): untyped = + let a = @[1, 2, 3, 4, 5] + result = genAst(a, b = a.len): # shows 2 ways to get a.len + (a.len, b) + doAssert foo() == (5, 5) + + block: + # avoids bug #9607 + proc fun1(info:LineInfo): string = "bar1" + proc fun2(info:int): string = "bar2" + + macro bar2(args: varargs[untyped]): untyped = + let info = args.lineInfoObj + let fun1 = bindSym"fun1" # optional; we can remove this and also the + # capture of fun1, as show in next example + result = genAst(info, fun1): + (fun1(info), fun2(info.line)) + doAssert bar2() == ("bar1", "bar2") + + macro bar3(args: varargs[untyped]): untyped = + let info = args.lineInfoObj + result = genAst(info): + (fun1(info), fun2(info.line)) + doAssert bar3() == ("bar1", "bar2") + + macro bar(args: varargs[untyped]): untyped = + let info = args.lineInfoObj + let fun1 = bindSym"fun1" + let fun2 = bindSym"fun2" + result = genAstOpt({kDirtyTemplate}, info): + (fun1(info), fun2(info.line)) + doAssert bar() == ("bar1", "bar2") + + block: + # example from bug #7889 works + # after changing method call syntax to regular call syntax; this is a + # limitation described in bug #7085 + # note that `quote do` would also work after that change in this example. + doAssert bindme2() == kfoo1 + doAssert bindme3() == kfoo1 + doAssert not compiles(bindme4()) # correctly gives Error: undeclared identifier: 'myLocalPriv' + proc myLocalPriv2(): auto = kfoo2 + doAssert bindme5UseExpose() == kfoo1 + + # example showing hijacking behavior when using `kDirtyTemplate` + doAssert bindme5UseExposeFalse() == kfoo2 + # local `myLocalPriv2` hijacks symbol `mgenast.myLocalPriv2`. In most + # use cases this is probably not what macro writer intends as it's + # surprising; hence `kDirtyTemplate` is not the default. + + when nimvm: # disabled because `newStringStream` is used + discard + else: + bindme6UseExpose() + bindme6UseExposeFalse() + + block: + macro mbar(x3: Foo, x3b: static Foo): untyped = + var x1=kfoo3 + var x2=newLit kfoo3 + var x4=kfoo3 + var xLocal=kfoo3 + + proc funLocal(): auto = kfoo4 + + result = genAst(x1, x2, x3, x4): + # local x1 overrides remote x1 + when false: + # one advantage of using `kDirtyTemplate` is that these would hold: + doAssert not declared xLocal + doAssert not compiles(echo xLocal) + # however, even without it, we at least correctly generate CT error + # if trying to use un-captured symbol; this correctly gives: + # Error: internal error: environment misses: xLocal + echo xLocal + + proc foo1(): auto = + # note that `funLocal` is captured implicitly, according to hygienic + # template rules; with `kDirtyTemplate` it would not unless + # captured in `genAst` capture list explicitly + (a0: xRemote, a1: x1, a2: x2, a3: x3, a4: x4, a5: funLocal()) + + return result + + proc main()= + var xRemote=kfoo1 + var x1=kfoo2 + mbar(kfoo4, kfoo4) + doAssert foo1() == (a0: kfoo1, a1: kfoo3, a2: kfoo3, a3: kfoo4, a4: kfoo3, a5: kfoo4) + + main() + + block: + # With `kDirtyTemplate`, the example from #8220 works. + # See https://nim-lang.github.io/Nim/strformat.html#limitations for + # an explanation of why {.dirty.} is needed. + macro foo(): untyped = + result = genAstOpt({kDirtyTemplate}): + let bar = "Hello, World" + &"Let's interpolate {bar} in the string" + doAssert foo() == "Let's interpolate Hello, World in the string" + + + block: # nested application of genAst + macro createMacro(name, obj, field: untyped): untyped = + result = genAst(obj = newDotExpr(obj, field), lit = 10, name, field): + # can't reuse `result` here, would clash + macro name(arg: untyped): untyped = + genAst(arg2=arg): # somehow `arg2` rename is needed + (obj, astToStr(field), lit, arg2) + + var x = @[1, 2, 3] + createMacro foo, x, len + doAssert (foo 20) == (3, "len", 10, 20) + + block: # test with kNoNewLit + macro bar(): untyped = + let s1 = true + template boo(x): untyped = + fun(x) + result = genAstOpt({kNoNewLit}, s1=newLit(s1), s1b=s1): (s1, s1b) + doAssert bar() == (true, 1) + + block: # sanity check: check passing `{}` also works + macro bar(): untyped = + result = genAstOpt({}, s1=true): s1 + doAssert bar() == true + + block: # test passing function and type symbols + proc z1(): auto = 41 + type Z4 = type(1'i8) + macro bar(Z1: typedesc): untyped = + proc z2(): auto = 42 + proc z3[T](a: T): auto = 43 + let Z2 = genAst(): + type(true) + let z4 = genAst(): + proc myfun(): auto = 44 + myfun + type Z3 = type(1'u8) + result = genAst(z4, Z1, Z2): + # z1, z2, z3, Z3, Z4 are captured automatically + # z1, z2, z3 can optionally be specified in capture list + (z1(), z2(), z3('a'), z4(), $Z1, $Z2, $Z3, $Z4) + type Z1 = type('c') + doAssert bar(Z1) == (41, 42, 43, 44, "char", "bool", "uint8", "int8") + + block: # fix bug #11986 + proc foo(): auto = + var s = { 'a', 'b' } + # var n = quote do: `s` # would print {97, 98} + var n = genAst(s): s + n.repr + static: doAssert foo() == "{'a', 'b'}" + + block: # also from #11986 + macro foo(): untyped = + var s = { 'a', 'b' } + # quote do: + # let t = `s` + # $typeof(t) # set[range 0..65535(int)] + genAst(s): + let t = s + $typeof(t) + doAssert foo() == "set[char]" + + block: + macro foo(): untyped = + type Foo = object + template baz2(a: int): untyped = a*10 + macro baz3(a: int): untyped = newLit 13 + result = newStmtList() + + result.add genAst(Foo, baz2, baz3) do: # shows you can pass types, templates etc + var x: Foo + $($typeof(x), baz2(3), baz3(4)) + + let ret = genAst() do: # shows you don't have to, since they're inject'd + var x: Foo + $($typeof(x), baz2(3), baz3(4)) + doAssert foo() == """("Foo", 30, 13)""" + + block: # illustrates how symbol visiblity can be controlled precisely using `mixin` + proc locafun1(): auto = "in locafun1 (caller scope)" # this will be used because of `mixin locafun1` => explicit hijacking is ok + proc locafun2(): auto = "in locafun2 (caller scope)" # this won't be used => no hijacking + proc locafun3(): auto = "in locafun3 (caller scope)" + doAssert mixinExample() == ("in locafun1 (caller scope)", "in locafun2", "in locafun3 (caller scope)") + +static: main() +main() From 07991d902e6630593ce2db0f34c06bbb2abb336e Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 3 Apr 2021 04:06:29 +0800 Subject: [PATCH 2351/4254] [docs minor] close #17618 (#17620) * [docs minor] close #17618 * Update lib/pure/times.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/times.nim | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index e763b17bb..a92eccc8c 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -313,8 +313,11 @@ type Duration* = object ## Represents a fixed duration of time, meaning a duration ## that has constant length independent of the context. ## - ## To create a new `Duration`, use `initDuration proc + ## To create a new `Duration`, use `initDuration ## <#initDuration,int64,int64,int64,int64,int64,int64,int64,int64>`_. + ## Instead of trying to access the private attributes, use + ## `inSeconds <#inSeconds,Duration>`_ for converting to seconds and + ## `inNanoseconds <#inNanoseconds,Duration>`_ for converting to nanoseconds. seconds: int64 nanosecond: NanosecondRange @@ -622,56 +625,56 @@ template convert(dur: Duration, unit: static[FixedTimeUnit]): int64 = convert(Nanoseconds, unit, dur.nanosecond) proc inWeeks*(dur: Duration): int64 = - ## Convert the duration to the number of whole weeks. + ## Converts the duration to the number of whole weeks. runnableExamples: let dur = initDuration(days = 8) doAssert dur.inWeeks == 1 dur.convert(Weeks) proc inDays*(dur: Duration): int64 = - ## Convert the duration to the number of whole days. + ## Converts the duration to the number of whole days. runnableExamples: let dur = initDuration(hours = -50) doAssert dur.inDays == -2 dur.convert(Days) proc inHours*(dur: Duration): int64 = - ## Convert the duration to the number of whole hours. + ## Converts the duration to the number of whole hours. runnableExamples: let dur = initDuration(minutes = 60, days = 2) doAssert dur.inHours == 49 dur.convert(Hours) proc inMinutes*(dur: Duration): int64 = - ## Convert the duration to the number of whole minutes. + ## Converts the duration to the number of whole minutes. runnableExamples: let dur = initDuration(hours = 2, seconds = 10) doAssert dur.inMinutes == 120 dur.convert(Minutes) proc inSeconds*(dur: Duration): int64 = - ## Convert the duration to the number of whole seconds. + ## Converts the duration to the number of whole seconds. runnableExamples: let dur = initDuration(hours = 2, milliseconds = 10) doAssert dur.inSeconds == 2 * 60 * 60 dur.convert(Seconds) proc inMilliseconds*(dur: Duration): int64 = - ## Convert the duration to the number of whole milliseconds. + ## Converts the duration to the number of whole milliseconds. runnableExamples: let dur = initDuration(seconds = -2) doAssert dur.inMilliseconds == -2000 dur.convert(Milliseconds) proc inMicroseconds*(dur: Duration): int64 = - ## Convert the duration to the number of whole microseconds. + ## Converts the duration to the number of whole microseconds. runnableExamples: let dur = initDuration(seconds = -2) doAssert dur.inMicroseconds == -2000000 dur.convert(Microseconds) proc inNanoseconds*(dur: Duration): int64 = - ## Convert the duration to the number of whole nanoseconds. + ## Converts the duration to the number of whole nanoseconds. runnableExamples: let dur = initDuration(seconds = -2) doAssert dur.inNanoseconds == -2000000000 From e35946f306c31d02869dfc4f191b76893b792700 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Fri, 2 Apr 2021 23:11:44 +0300 Subject: [PATCH 2352/4254] enable syntax highlighting for inline code (#17585) * enable syntax highlighting for inline code * finish '.. default-role' and preliminary '.. role' implementation * more compact check in dirRole * set :literal: as default role for *.rst * Update lib/packages/docutils/rst.nim Co-authored-by: Timothee Cour * use whichRole for setting currRoleKind * Update lib/packages/docutils/rst.nim Co-authored-by: Timothee Cour * rename rnGeneralRole -> rnUnknownRole Co-authored-by: Timothee Cour --- compiler/docgen.nim | 3 +- doc/contributing.rst | 38 ++++++ lib/packages/docutils/rst.nim | 116 +++++++++++++++---- lib/packages/docutils/rstast.nim | 9 +- lib/packages/docutils/rstgen.nim | 33 ++++-- nimdoc/rst2html/expected/rst_examples.html | 6 +- nimdoc/rst2html/source/rst_examples.rst | 4 + nimdoc/testproject/expected/testproject.html | 8 +- tests/stdlib/trstgen.nim | 73 ++++++++++-- 9 files changed, 239 insertions(+), 51 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 67f21e1c4..37d8955f6 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -192,7 +192,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.cache = cache result.outDir = conf.outDir.string initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), - conf.configVars, filename.string, {roSupportRawDirective, roSupportMarkdown}, + conf.configVars, filename.string, + {roSupportRawDirective, roSupportMarkdown, roNimFile}, docgenFindFile, compilerMsgHandler) if conf.configVars.hasKey("doc.googleAnalytics"): diff --git a/doc/contributing.rst b/doc/contributing.rst index 279a4ee94..7ee3aa444 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -295,6 +295,44 @@ example below) from `Nim Index`_ can be used in doc comment this way: .. _`Nim Index`: https://nim-lang.org/docs/theindex.html +Inline monospaced text can be input using \`single backticks\` or +\`\`double backticks\`\`. The former are syntactically highlighted, +the latter are not. +To avoid accidental highlighting follow this rule in `*.nim` files: + +* use single backticks for fragments of code in Nim and other + programming languages, including identifiers, in `*.nim` files. + + For languages other than Nim add a role after final backtick, + e.g. for C++ inline highlighting:: + + `#include `:cpp: + + For a currently unsupported language add the `:code:` role, + like for SQL in this example:: + + `SELECT * FROM ;`:code: + +* prefer double backticks otherwise: + + * for file names: \`\`os.nim\`\` + * for fragments of strings **not** enclosed by `"` and `"` and not + related to code, e.g. text of compiler messages + * for command line options: \`\`--docInternal\`\` + * also when code ends with a standalone ``\`` (otherwise a combination of + ``\`` and a final \` would get escaped) + +.. Note:: `*.rst` files have `:literal:` as their default role. + So for them the rule above is only applicable if the `:nim:` role + is set up manually as the default:: + + .. role:: nim(code) + :language: nim + .. default-role:: nim + + The first 2 lines are for other RST implementations, + including Github one. + Best practices ============== diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index d331c2c12..66efa3a3c 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -78,6 +78,13 @@ ## ## * directives: ``code-block`` [cmp:Sphinx]_, ``title``, ## ``index`` [cmp:Sphinx]_ +## * predefined roles ``:nim:`` (default), ``:c:`` (C programming language), +## ``:python:``, ``:yaml:``, ``:java:``, ``:cpp:`` (C++), ``:csharp`` (C#). +## That is every language that `highlite `_ supports. +## They turn on appropriate syntax highlighting in inline code. +## +## .. Note:: default role for Nim files is ``:nim:``, +## for ``*.rst`` it's currently ``:literal:``. ## ## * ***triple emphasis*** (bold and italic) using \*\*\* ## * ``:idx:`` role for \`interpreted text\` to include the link to this @@ -161,7 +168,9 @@ type roSupportSmilies, ## make the RST parser support smilies like ``:)`` roSupportRawDirective, ## support the ``raw`` directive (don't support ## it for sandboxing) - roSupportMarkdown ## support additional features of Markdown + roSupportMarkdown, ## support additional features of Markdown + roNimFile ## set for Nim files where default interpreted + ## text role should be :nim: RstParseOptions* = set[RstParseOption] @@ -454,6 +463,8 @@ type hTitleCnt: int # =0 if no title, =1 if only main title, # =2 if both title and subtitle are present hCurLevel: int # current section level + currRole: string # current interpreted text role + currRoleKind: RstNodeKind # ... and its node kind subs: seq[Substitution] # substitutions refs: seq[Substitution] # references anchors: seq[AnchorSubst] # internal target substitutions @@ -514,10 +525,36 @@ proc defaultFindFile*(filename: string): string = if fileExists(filename): result = filename else: result = "" +proc defaultRole(options: RstParseOptions): string = + if roNimFile in options: "nim" else: "literal" + +# mirror highlite.nim sourceLanguageToStr with substitutions c++ cpp, c# csharp +const supportedLanguages = ["nim", "yaml", "python", "java", "c", + "cpp", "csharp"] + +proc whichRoleAux(sym: string): RstNodeKind = + let r = sym.toLowerAscii + case r + of "idx": result = rnIdx + of "literal": result = rnInlineLiteral + of "strong": result = rnStrongEmphasis + of "emphasis": result = rnEmphasis + of "sub", "subscript": result = rnSub + of "sup", "superscript": result = rnSup + # literal and code are the same in our implementation + of "code": result = rnInlineLiteral + # c++ currently can be spelled only as cpp, c# only as csharp + elif r in supportedLanguages: + result = rnInlineCode + else: # unknown role + result = rnUnknownRole + proc newSharedState(options: RstParseOptions, findFile: FindFileHandler, msgHandler: MsgHandler): PSharedState = new(result) + result.currRole = defaultRole(options) + result.currRoleKind = whichRoleAux(result.currRole) result.subs = @[] result.refs = @[] result.options = options @@ -1018,15 +1055,28 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) = for i in countup(0, sep - incr): a.add(n.sons[i]) for i in countup(sep + 1, n.len - 2): b.add(n.sons[i]) -proc whichRole(sym: string): RstNodeKind = - case sym - of "idx": result = rnIdx - of "literal": result = rnInlineLiteral - of "strong": result = rnStrongEmphasis - of "emphasis": result = rnEmphasis - of "sub", "subscript": result = rnSub - of "sup", "superscript": result = rnSup - else: result = rnGeneralRole +proc whichRole(p: RstParser, sym: string): RstNodeKind = + result = whichRoleAux(sym) + if result == rnUnknownRole: + rstMessage(p, mwUnsupportedLanguage, p.s.currRole) + +proc toInlineCode(n: PRstNode, language: string): PRstNode = + ## Creates rnInlineCode and attaches `n` contents as code (in 3rd son). + result = newRstNode(rnInlineCode) + let args = newRstNode(rnDirArg) + var lang = language + if language == "cpp": lang = "c++" + elif language == "csharp": lang = "c#" + args.add newLeaf(lang) + result.add args + result.add PRstNode(nil) + var lb = newRstNode(rnLiteralBlock) + var s: string + for i in n.sons: + assert i.kind == rnLeaf + s.add i.text + lb.add newLeaf(s) + result.add lb proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var newKind = n.kind @@ -1052,14 +1102,23 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = result = newRstNode(newKind, newSons) elif match(p, p.idx, ":w:"): # a role: - newKind = whichRole(nextTok(p).symbol) - if newKind == rnGeneralRole: + let roleName = nextTok(p).symbol + newKind = whichRole(p, roleName) + if newKind == rnUnknownRole: let newN = newRstNode(rnInner, n.sons) - newSons = @[newN, newLeaf(nextTok(p).symbol)] + newSons = @[newN, newLeaf(roleName)] + result = newRstNode(newKind, newSons) + elif newKind == rnInlineCode: + result = n.toInlineCode(language=roleName) + else: + result = newRstNode(newKind, newSons) inc p.idx, 3 - result = newRstNode(newKind, newSons) - else: # no change - result = n + else: + if p.s.currRoleKind == rnInlineCode: + result = n.toInlineCode(language=p.s.currRole) + else: + newKind = p.s.currRoleKind + result = newRstNode(newKind, newSons) proc matchVerbatim(p: RstParser, start: int, expr: string): int = result = start @@ -1315,9 +1374,12 @@ proc parseInline(p: var RstParser, father: PRstNode) = parseUntil(p, n, "``", false) father.add(n) elif match(p, p.idx, ":w:") and p.tok[p.idx+3].symbol == "`": - let k = whichRole(nextTok(p).symbol) - let n = newRstNode(k) + let roleName = nextTok(p).symbol + let k = whichRole(p, roleName) + var n = newRstNode(k) inc p.idx, 3 + if k == rnInlineCode: + n = n.toInlineCode(language=roleName) parseUntil(p, n, "`", false) # bug #17260 father.add(n) elif isInlineMarkupStart(p, "`"): @@ -2421,6 +2483,18 @@ proc dirAdmonition(p: var RstParser, d: string): PRstNode = proc dirDefaultRole(p: var RstParser): PRstNode = result = parseDirective(p, rnDefaultRole, {hasArg}, nil) + if result.sons[0].len == 0: p.s.currRole = defaultRole(p.s.options) + else: + assert result.sons[0].sons[0].kind == rnLeaf + p.s.currRole = result.sons[0].sons[0].text + p.s.currRoleKind = whichRole(p, p.s.currRole) + +proc dirRole(p: var RstParser): PRstNode = + result = parseDirective(p, rnDirective, {hasArg, hasOptions}, nil) + # just check that language is supported, TODO: real role association + let lang = getFieldValue(result, "language").strip + if lang != "" and lang notin supportedLanguages: + rstMessage(p, mwUnsupportedLanguage, lang) proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind, contentParser: SectionParser) = @@ -2465,7 +2539,9 @@ proc selectDir(p: var RstParser, d: string): PRstNode = of "code-block": result = dirCodeBlock(p, nimExtension = true) of "container": result = dirContainer(p) of "contents": result = dirContents(p) - of "danger", "error": result = dirAdmonition(p, d) + of "danger": result = dirAdmonition(p, d) + of "default-role": result = dirDefaultRole(p) + of "error": result = dirAdmonition(p, d) of "figure": result = dirFigure(p) of "hint": result = dirAdmonition(p, d) of "image": result = dirImage(p) @@ -2478,10 +2554,10 @@ proc selectDir(p: var RstParser, d: string): PRstNode = result = dirRaw(p) else: rstMessage(p, meInvalidDirective, d) + of "role": result = dirRole(p) of "tip": result = dirAdmonition(p, d) of "title": result = dirTitle(p) of "warning": result = dirAdmonition(p, d) - of "default-role": result = dirDefaultRole(p) else: let tok = p.tok[p.idx-2] # report on directive in ".. directive::" rstMessage(p, meInvalidDirective, d, tok.line, tok.col) diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index ff34da2d1..dd456b577 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -55,12 +55,15 @@ type # * `file#id `_ # * `file#id '_ rnSubstitutionDef, # a definition of a substitution - rnGeneralRole, # Inline markup: + # Inline markup: + rnInlineCode, + rnUnknownRole, # interpreted text with an unknown role rnSub, rnSup, rnIdx, rnEmphasis, # "*" rnStrongEmphasis, # "**" rnTripleEmphasis, # "***" - rnInterpretedText, # "`" + rnInterpretedText, # "`" an auxiliary role for parsing that will + # be converted into other kinds like rnInlineCode rnInlineLiteral, # "``" rnInlineTarget, # "_`target`" rnSubstitutionReferences, # "|" @@ -252,7 +255,7 @@ proc renderRstToRst(d: var RenderContext, n: PRstNode, result: var string) = result.add(" <") renderRstToRst(d, n.sons[1], result) result.add(">`_") - of rnGeneralRole: + of rnUnknownRole: result.add('`') renderRstToRst(d, n.sons[0],result) result.add("`:") diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 30c7f3080..1a16f590e 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -942,7 +942,7 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = result.init if n.isNil: return - assert n.kind == rnCodeBlock + assert n.kind in {rnCodeBlock, rnInlineCode} assert(not n.sons[2].isNil) # Parse the field list for rendering parameters if there are any. @@ -987,8 +987,8 @@ proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string, "
                                      text1
                                      " & ( d.config.getOrDefault"doc.listing_button" % id) -proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = - ## Renders a code block, appending it to `result`. +proc renderCode(d: PDoc, n: PRstNode, result: var string) = + ## Renders a code (code block or inline code), appending it to `result`. ## ## If the code block uses the ``number-lines`` option, a table will be ## generated with two columns, the first being a list of numbers and the @@ -997,7 +997,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = ## may also come from the parser through the internal ``default-language`` ## option to differentiate between a plain code block and Nim's code block ## extension. - assert n.kind == rnCodeBlock + assert n.kind in {rnCodeBlock, rnInlineCode} if n.sons[2] == nil: return var params = d.parseCodeBlockParams(n) var m = n.sons[2].sons[0] @@ -1006,10 +1006,23 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = if params.testCmd.len > 0 and d.onTestSnippet != nil: d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text) - let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text, + var blockStart, blockEnd: string + case d.target + of outHtml: + if n.kind == rnCodeBlock: + (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text, n.anchor.idS) - dispA(d.target, result, blockStart, - "\\begin{rstpre}\n" & n.anchor.idS & "\n", []) + else: # rnInlineCode + blockStart = "" + blockEnd = "" + of outLatex: + if n.kind == rnCodeBlock: + blockStart = "\n\n\\begin{rstpre}" & n.anchor.idS & "\n" + blockEnd = "\n\\end{rstpre}\n" + else: # rnInlineCode + blockStart = "\\texttt{" + blockEnd = "}" + dispA(d.target, result, blockStart, blockStart, []) if params.lang == langNone: if len(params.langStr) > 0: d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr) @@ -1028,7 +1041,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = esc(d.target, substr(m.text, g.start, g.length+g.start-1)), tokenClassToStr[g.kind]]) deinitGeneralTokenizer(g) - dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n") + dispA(d.target, result, blockEnd, blockEnd) proc renderContainer(d: PDoc, n: PRstNode, result: var string) = var tmp = "" @@ -1294,13 +1307,13 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = result.add addNodes(lastSon(n)) of rnImage, rnFigure: renderImage(d, n, result) - of rnCodeBlock: renderCodeBlock(d, n, result) + of rnCodeBlock, rnInlineCode: renderCode(d, n, result) of rnContainer: renderContainer(d, n, result) of rnSubstitutionReferences, rnSubstitutionDef: renderAux(d, n, "|$1|", "|$1|", result) of rnDirective: renderAux(d, n, "", "", result) - of rnGeneralRole: + of rnUnknownRole: var tmp0 = "" var tmp1 = "" renderRstToOut(d, n.sons[0], tmp0) diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 8253289a4..32abc0f80 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -213,7 +213,7 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements

                                      Let T's be p's return type. NRVO applies for T if sizeof(T) >= N (where N is implementation dependent), in other words, it applies for "big" structures.

                                      Apart from built-in operations like array indexing, memory allocation, etc. the raise statement is the only way to raise an exception.

                                      -

                                      typedesc used as a parameter type also introduces an implicit generic. typedesc has its own set of rules:

                                      +

                                      typedesc used as a parameter type also introduces an implicit generic. typedesc has its own set of rules:

                                      The !=, >, >=, in, notin, isnot operators are in fact templates:

                                      a > b is transformed into b < a.
                                      a in b is transformed into contains(b, a).
                                      notin and isnot have the obvious meanings.

                                      A template where every parameter is untyped is called an immediate template. For historical reasons templates can be explicitly annotated with an immediate pragma and then these templates do not take part in overloading resolution and the parameters' types are ignored by the compiler. Explicit immediate templates are now deprecated.

                                      @@ -297,10 +297,10 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements

                                      Introduction

                                      "Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir."

                                      This document is a tutorial for the programming language Nim. This tutorial assumes that you are familiar with basic programming concepts like variables, types, or statements but is kept very basic. The manual contains many more examples of the advanced language features. All code examples in this tutorial, as well as the ones found in the rest of Nim's documentation, follow the Nim style guide.

                                      -

                                      However, this does not work. The problem is that the procedure should not only return, but return and continue after an iteration has finished. This return and continue is called a yield statement. Now the only thing left to do is to replace the proc keyword by iterator and here it is - our first iterator:

                                      +

                                      However, this does not work. The problem is that the procedure should not only return, but return and continue after an iteration has finished. This return and continue is called a yield statement. Now the only thing left to do is to replace the proc keyword by iterator and here it is - our first iterator:

                                      - +
                                      A1 headerA2 | not fooled
                                      C1C2 bold
                                      D1 code \|D2
                                      D1 code \|D2
                                      E1 | text
                                      F2 without pipe

                                      not in table

                                      diff --git a/nimdoc/rst2html/source/rst_examples.rst b/nimdoc/rst2html/source/rst_examples.rst index 54f0124c8..7fa20de6c 100644 --- a/nimdoc/rst2html/source/rst_examples.rst +++ b/nimdoc/rst2html/source/rst_examples.rst @@ -5,6 +5,10 @@ Not a Nim Manual :Authors: Andreas Rumpf, Zahary Karadjov :Version: |nimversion| +.. role:: nim(code) + :language: nim +.. default-role:: nim + .. contents:: diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 8525048ea..ba1791d81 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -565,14 +565,14 @@ This is deprecated with a message.
                                      func someFunc() {....raises: [], tags: [].}
                                      -My someFunc. Stuff in quotes here. Some link +My someFunc. Stuff in quotes here. Some link
                                      proc fromUtils3() {....raises: [], tags: [].}
                                      -came form utils but should be shown where fromUtilsGen is called +came form utils but should be shown where fromUtilsGen is called

                                      Example:

                                      discard 1
                                      @@ -765,7 +765,7 @@ the c printf. etc.
                                      proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
                                      -

                                      Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                                      +

                                      Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                                      See also:

                                      @@ -776,7 +776,7 @@ the c printf. etc.
                                      proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
                                      -

                                      Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                                      +

                                      Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                                      See also:

                                      diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index da01c30d2..ad0c27f05 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -10,7 +10,7 @@ import unittest, strutils, strtabs import std/private/miscdollars proc toHtml(input: string, - rstOptions: RstParseOptions = {roSupportMarkdown}, + rstOptions: RstParseOptions = {roSupportMarkdown, roNimFile}, error: ref string = nil, warnings: ref seq[string] = nil): string = ## If `error` is nil then no errors should be generated. @@ -36,6 +36,11 @@ proc toHtml(input: string, except EParseError: discard +# inline code tags (for parsing originated from highlite.nim) +proc id(str: string): string = """""" & str & "" +proc op(str: string): string = """""" & str & "" +proc pu(str: string): string = """""" & str & "" + suite "YAML syntax highlighting": test "Basics": let input = """.. code-block:: yaml @@ -201,14 +206,14 @@ not in table""" `|` outside a table cell should render as `\|` consistently with markdown, see https://stackoverflow.com/a/66557930/1426932 ]# - doAssert output1 == """ + check(output1 == """ - +
                                      A1 headerA2 | not fooled
                                      C1C2 bold
                                      D1 code \|D2
                                      D1 """ & id"code" & " " & op"\|" & """D2
                                      E1 | text
                                      F2 without pipe

                                      not in table

                                      -""" +""") let input2 = """ | A1 header | A2 | | --- | --- |""" @@ -556,19 +561,66 @@ let x = 1 doAssert "foo.bar
                                      """ - check """`foo\`\`bar`""".toHtml == """foo``bar""" - check """`foo\`bar`""".toHtml == """foo`bar""" - check """`\`bar`""".toHtml == """`bar""" - check """`a\b\x\\ar`""".toHtml == """a\b\x\\ar""" + check("""`foo.bar`""".toHtml == + """""" & + id"foo" & op"." & id"bar" & "") + check("""`foo\`\`bar`""".toHtml == + """""" & + id"foo" & pu"`" & pu"`" & id"bar" & "") + check("""`foo\`bar`""".toHtml == + """""" & + id"foo" & pu"`" & id"bar" & "") + check("""`\`bar`""".toHtml == + """""" & + pu"`" & id"bar" & "") + check("""`a\b\x\\ar`""".toHtml == + """""" & + id"a" & op"""\""" & id"b" & op"""\""" & id"x" & op"""\\""" & id"ar" & + "") test "inline literal": check """``foo.bar``""".toHtml == """foo.bar""" check """``foo\bar``""".toHtml == """foo\bar""" check """``f\`o\\o\b`ar``""".toHtml == """f\`o\\o\b`ar""" + test "default-role": + # nim(default) -> literal -> nim -> code(=literal) + let input = dedent""" + Par1 `value1`. + + .. default-role:: literal + + Par2 `value2`. + + .. default-role:: nim + + Par3 `value3`. + + .. default-role:: code + + Par4 `value4`.""" + let p1 = """Par1 """ & id"value1" & "." + let p2 = """

                                      Par2 value2.

                                      """ + let p3 = """

                                      Par3 """ & id"value3" & ".

                                      " + let p4 = """

                                      Par4 value4.

                                      """ + let expected = p1 & p2 & "\n" & p3 & "\n" & p4 & "\n" + check(input.toHtml == expected) + + test "role directive": + let input = dedent""" + .. role:: y(code) + :language: yaml + + .. role:: brainhelp(code) + :language: brainhelp + """ + var warnings = new seq[string] + let output = input.toHtml(warnings=warnings) + check(warnings[].len == 1 and "language 'brainhelp' not supported" in warnings[0]) + test "RST comments": let input1 = """ + Check that comment disappears: .. @@ -1341,7 +1393,8 @@ Test1 test "(not) Roles: check escaping 1": let expected = """See :subscript:""" & - """some text.""" + """""" & id"some" & " " & id"text" & + "." check """See \:subscript:`some text`.""".toHtml == expected check """See :subscript\:`some text`.""".toHtml == expected From a807233aebcd3759bc3e21b450ed89e1eb6ddace Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 3 Apr 2021 09:26:30 +0800 Subject: [PATCH 2353/4254] fix #17615(runnableExamples silently ignored if placed after some code) (#17619) Co-authored-by: Timothee Cour --- compiler/docgen.nim | 33 +++++++++++--------- lib/experimental/diff.nim | 8 ++--- lib/pure/coro.nim | 2 +- lib/std/jsbigints.nim | 4 +-- lib/wrappers/openssl.nim | 3 +- nimdoc/testproject/expected/testproject.html | 4 ++- nimdoc/testproject/testproject.nim | 4 +-- tests/nimdoc/t17615.nim | 11 +++++++ 8 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 tests/nimdoc/t17615.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 37d8955f6..2f7415241 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -608,20 +608,23 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: Runnab return rsComment of nkCallKinds: if isRunnableExamples(n[0]) and - n.len >= 2 and n.lastSon.kind == nkStmtList and state in {rsStart, rsComment, rsRunnable}: - let (rdoccmd, code) = prepareExample(d, n, topLevel) - var msg = "Example:" - if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd - dispA(d.conf, dest, "\n

                                      $1

                                      \n", - "\n\\textbf{$1}\n", [msg.rope]) - inc d.listingCounter - let id = $d.listingCounter - dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) - var dest2 = "" - renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) - dest.add dest2 - dest.add(d.config.getOrDefault"doc.listing_end" % id) - return rsRunnable + n.len >= 2 and n.lastSon.kind == nkStmtList: + if state in {rsStart, rsComment, rsRunnable}: + let (rdoccmd, code) = prepareExample(d, n, topLevel) + var msg = "Example:" + if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd + dispA(d.conf, dest, "\n

                                      $1

                                      \n", + "\n\\textbf{$1}\n", [msg.rope]) + inc d.listingCounter + let id = $d.listingCounter + dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) + var dest2 = "" + renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) + dest.add dest2 + dest.add(d.config.getOrDefault"doc.listing_end" % id) + return rsRunnable + else: + localError(d.conf, n.info, errUser, "runnableExamples must appear before the first non-comment statement") else: discard return rsDone # change this to `rsStart` if you want to keep generating doc comments @@ -671,7 +674,7 @@ proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var Rope) = else: for i in 0..Example:

                                      discard 4
                                      ok5 ok5b

                                      Example:

                                      -
                                      assert true
                                      in or out? +
                                      assert true
                                      +

                                      Example:

                                      +
                                      discard 1
                                      in or out?
                                      diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 69edb0d23..6b82acb9b 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -330,13 +330,11 @@ when true: # (most) templates ## ok5 ## ok5b runnableExamples: assert true + runnableExamples: discard 1 ## in or out? - # this is an edge case; a newline separate last runnableExamples from - # next doc comment but AST isnt' aware of it; this could change in future discard 8 ## out - runnableExamples: discard 1 when true: # issue #14473 import std/[sequtils] diff --git a/tests/nimdoc/t17615.nim b/tests/nimdoc/t17615.nim new file mode 100644 index 000000000..77ae35a15 --- /dev/null +++ b/tests/nimdoc/t17615.nim @@ -0,0 +1,11 @@ +discard """ + cmd: "nim doc -r $file" + errormsg: "runnableExamples must appear before the first non-comment statement" + line: 10 +""" + +func fn*() = + ## foo + discard + runnableExamples: + assert true From 270964c487e5347c61dade25bec903580483dda5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 2 Apr 2021 22:15:21 -0700 Subject: [PATCH 2354/4254] implement RFCs/294 ; disallow enum <=> enum conversion (#16351) * fix https://github.com/nim-lang/RFCs/issues/294 ; disallow enum <=> enum conversion * fix the runnableExamples that was the instigator of this RFC * legacy -d:nimLegacyConvEnumEnum * use -d:nimLegacyConvEnumEnum in important_package nimgame2 * add test for enum cast * improve changelog * add changelog: Changes affecting backward compatibility * cleanup changelog * fix changelog --- changelog.md | 58 +++++++++++++++++++------------- changelogs/changelog_X_XX_X.md | 4 +++ compiler/semexprs.nim | 5 +++ compiler/sempass2.nim | 6 ++-- compiler/vmgen.nim | 4 +-- lib/system/comparisons.nim | 2 +- testament/important_packages.nim | 5 +-- tests/misc/tcast.nim | 36 +++++++++++++++++--- tests/misc/tconv.nim | 33 +++++++++++++++++- 9 files changed, 115 insertions(+), 38 deletions(-) diff --git a/changelog.md b/changelog.md index 020d8a350..43a15e398 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,40 @@ +## Changes affecting backward compatibility + +- `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, + see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. + +- An enum now can't be converted to another enum directly, you must use `ord` (or `cast`, but + compiler won't help if you misuse it). + ``` + type A = enum a1, a2 + type B = enum b1, b2 + doAssert not compiles(a1.B) + doAssert compiles(a1.ord.B) + ``` + for a transition period, use `-d:nimLegacyConvEnumEnum`. + +- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous + behavior. + +- `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior + silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. + +- `math.round` now is rounded "away from zero" in JS backend which is consistent + with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. + +- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` + characters in the decoded values. Prior versions would raise an error. This is + no longer the case to comply with the HTML spec and other languages + implementations. Old behavior can be obtained with + `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same + underlying code is also updated the same way. + +- In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, + unless `-d:nimLegacyHomeDir` is specified (for a transition period). + ## Standard library additions and changes - Added `sections` iterator in `parsecfg`. @@ -84,9 +118,6 @@ - Added a simpler to use `io.readChars` overload. -- `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, - see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. - - Added `**` to jsffi. - `writeStackTrace` is available in JS backend now. @@ -109,9 +140,6 @@ - Added `math.isNaN`. -- `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior - silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. - - Added `jsbigints` module, arbitrary precision integers for JavaScript target. - Added `math.copySign`. @@ -130,18 +158,8 @@ - Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs. https://www.freedesktop.org/software/systemd/man/os-release.html -- `math.round` now is rounded "away from zero" in JS backend which is consistent - with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. - - Added `socketstream` module that wraps sockets in the stream interface -- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` - characters in the decoded values. Prior versions would raise an error. This is - no longer the case to comply with the HTML spec and other languages - implementations. Old behavior can be obtained with - `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same - underlying code is also updated the same way. - - Added `sugar.dumpToString` which improves on `sugar.dump`. - Added `math.signbit`. @@ -235,7 +253,6 @@ - Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). - - Added `std/channels`. - Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). @@ -243,9 +260,6 @@ - Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time zone offsets without colons, e.g. `UTC+7 -> +0700`. -- In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, - unless `-d:nimLegacyHomeDir` is specified (for a transition period). - - Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. - Added dollar `$` and `len` for `jsre.RegExp`. @@ -254,7 +268,6 @@ - Added `hasClosure` to `std/typetraits`. - - Added `genasts.genAst` that avoids the problems inherent with `quote do` and can be used as a replacement. @@ -304,9 +317,6 @@ - VM now supports `addr(mystring[ind])` (index + index assignment) -- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous - behavior. - - Added `--hintAsError` with similar semantics as `--warningAsError`. - TLS: OSX now uses native TLS (`--tlsEmulation:off`), TLS now works with importcpp non-POD types, diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md index 48520fd44..77b421f33 100644 --- a/changelogs/changelog_X_XX_X.md +++ b/changelogs/changelog_X_XX_X.md @@ -3,10 +3,14 @@ This is an example file. The changes should go to changelog.md! +## Changes affecting backward compatibility + +- `foo` now behaves differently, use `-d:nimLegacyFoo` for previous behavior. ## Standard library additions and changes - Added `example.exampleProc`. + - Changed `example.foo` to take additional `bar` parameter. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 27b78aa6f..71c9e0295 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -163,6 +163,11 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = result = checkConversionBetweenObjects(d.skipTypes(abstractInst), s.skipTypes(abstractInst), pointers) elif (targetBaseTyp.kind in IntegralTypes) and (srcBaseTyp.kind in IntegralTypes): + if targetTyp.kind == tyEnum and srcBaseTyp.kind == tyEnum: + if c.config.isDefined("nimLegacyConvEnumEnum"): + message(c.config, src.info, warnUser, "enum to enum conversion is now deprecated") + else: result = convNotLegal + # `elif` would be incorrect here if targetTyp.kind == tyBool: discard "convOk" elif targetTyp.isOrdinalType: diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 87d196fad..52998c214 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -137,7 +137,7 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) = # we allow accesses nevertheless in top level statements for # easier initialization: #if a.isTopLevel: - # message(n.info, warnUnguardedAccess, renderTree(n)) + # message(a.config, n.info, warnUnguardedAccess, renderTree(n)) #else: if not a.isTopLevel: localError(a.config, n.info, "unguarded access: " & renderTree(n)) @@ -478,7 +478,7 @@ proc getLockLevel(s: PSym): TLockLevel = result = 0.TLockLevel else: result = UnknownLockLevel - #message(s.info, warnUser, "FOR THIS " & s.name.s) + #message(??.config, s.info, warnUser, "FOR THIS " & s.name.s) proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) = if lockLevel >= tracked.currLockLevel: @@ -544,7 +544,7 @@ proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) = let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel else: op.lockLevel #if lockLevel == UnknownLockLevel: - # message(n.info, warnUser, "had to assume the worst here") + # message(??.config, n.info, warnUser, "had to assume the worst here") mergeLockLevels(tracked, n, lockLevel) proc isOwnedProcVar(n: PNode; owner: PSym): bool = diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index be26f98b3..69d7ec4b3 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1435,7 +1435,7 @@ proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) = # permanent, so that it's not used for anything else: c.prc.slots[tmp].kind = slotTempPerm # XXX this is still a hack - #message(n.info, warnUser, "suspicious opcode used") + #message(c.congig, n.info, warnUser, "suspicious opcode used") else: gABC(c, n, opcAddrReg, dest, tmp) c.freeTemp(tmp) @@ -1687,7 +1687,7 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; c.gABC(n, opcNodeToReg, dest, cc) c.freeTemp(cc) else: - #message(n.info, warnUser, "argh") + #message(c.config, n.info, warnUser, "argh") #echo "FLAGS ", flags, " ", fitsRegister(n.typ), " ", typeToString(n.typ) c.gABC(n, opc, dest, a, b) c.freeTemp(a) diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 2e5664a95..7122daa20 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -9,7 +9,7 @@ proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} = place1, place2 = 3 var e1 = field1 - e2 = Enum1(place2) + e2 = place2.ord.Enum1 assert e1 == e2 assert not compiles(e1 == place2) # raises error proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} = diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 8a8d6ffd0..8f096b71e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -96,14 +96,15 @@ pkg "nimcrypto", "nim r --path:. tests/testall.nim" # `--path:.` workaround need pkg "NimData", "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", "nim c src/nimes.nim" pkg "nimfp", "nim c -o:nfp -r src/fp.nim" -pkg "nimgame2", "nim c nimgame2/nimgame.nim", allowFailure = true # XXX Doesn't work with deprecated 'randomize', will create a PR. +pkg "nimgame2", "nim c -d:nimLegacyConvEnumEnum nimgame2/nimgame.nim", allowFailure = true + # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" pkg "nimlsp" pkg "nimly", "nim c -r tests/test_readme_example.nim" pkg "nimongo", "nimble test_ci", allowFailure = true pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true pkg "nimpy", "nim c -r tests/nimfrompy.nim" -pkg "nimquery" +pkg "nimquery", allowFailure = true # pending https://github.com/GULPF/nimquery/pull/10 pkg "nimsl" pkg "nimsvg" pkg "nimterop", "nimble minitest" diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index 454801a2d..6d67b1c52 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -48,7 +48,7 @@ block: var x: ref int = nil doAssert cast[int](cast[ptr int](x)) == 0 -block: +block: # cast of nil block: static: let a = cast[pointer](nil) @@ -71,7 +71,33 @@ block: static: doAssert cast[RootRef](nil).repr == "nil" - # Issue #15730, not fixed yet - # block: - # static: - # doAssert cast[cstring](nil).repr == "nil" + when false: # xxx bug #15730, not fixed yet + block: + static: + doAssert cast[cstring](nil).repr == "nil" + +template main() = + # xxx move all under here to get tested in VM + block: # cast of enum + type Koo = enum k1, k2 + type Goo = enum g1, g2 + type Boo = enum b1 = -1, b2, b3, b4 + type Coo = enum c1 = -1i8, c2, c3, c4 + when nimvm: + # xxx: Error: VM does not support 'cast' from tyEnum to tyEnum + discard + else: + doAssert cast[Koo](k2) == k2 + doAssert cast[Goo](k2) == g2 + doAssert cast[Goo](k2.ord) == g2 + + doAssert b3.ord == 1 + doAssert cast[Koo](b3) == k2 + doAssert cast[Boo](k2) == b3 + + doAssert c3.ord == 1 + doAssert cast[Koo](c3) == k2 + doAssert cast[Coo](k2) == c3 + +static: main() +main() diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index f7d15b0b5..c93fc57f8 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -1,5 +1,13 @@ +discard """ + nimout:''' +tconv.nim(81, 15) Warning: enum to enum conversion is now deprecated [User] +''' +""" + template reject(x) = - static: assert(not compiles(x)) + static: doAssert(not compiles(x)) +template accept(x) = + static: doAssert(compiles(x)) reject: const x = int8(300) @@ -55,3 +63,26 @@ block: # issue 3766 proc r(x: static[R]) = echo x r 3.R + + +block: # https://github.com/nim-lang/RFCs/issues/294 + type Koo = enum k1, k2 + type Goo = enum g1, g2 + + accept: Koo(k2) + accept: k2.Koo + accept: k2.int.Goo + + reject: Goo(k2) + reject: k2.Goo + reject: k2.string + + {.define(nimLegacyConvEnumEnum).} + discard Goo(k2) + accept: Goo(k2) + accept: k2.Goo + reject: k2.string + {.undef(nimLegacyConvEnumEnum).} + + reject: Goo(k2) + reject: k2.Goo From 61c1e35181206b4305b6f57662bd9b2524c0fef8 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 3 Apr 2021 14:17:55 +0800 Subject: [PATCH 2355/4254] close #14806 (#17626) * close #14806 * tiny --- tests/tools/compile/config.nims | 1 + tests/tools/compile/readme.md | 1 + tests/tools/compile/tdeps.nim | 5 +++++ tests/tools/compile/tdetect.nim | 5 +++++ 4 files changed, 12 insertions(+) create mode 100644 tests/tools/compile/config.nims create mode 100644 tests/tools/compile/readme.md create mode 100644 tests/tools/compile/tdeps.nim create mode 100644 tests/tools/compile/tdetect.nim diff --git a/tests/tools/compile/config.nims b/tests/tools/compile/config.nims new file mode 100644 index 000000000..a19545668 --- /dev/null +++ b/tests/tools/compile/config.nims @@ -0,0 +1 @@ +switch("path", "$lib/../") \ No newline at end of file diff --git a/tests/tools/compile/readme.md b/tests/tools/compile/readme.md new file mode 100644 index 000000000..cb5058e02 --- /dev/null +++ b/tests/tools/compile/readme.md @@ -0,0 +1 @@ +Test whether the tools compile. \ No newline at end of file diff --git a/tests/tools/compile/tdeps.nim b/tests/tools/compile/tdeps.nim new file mode 100644 index 000000000..971ca1b8e --- /dev/null +++ b/tests/tools/compile/tdeps.nim @@ -0,0 +1,5 @@ +discard """ + action: compile +""" + +include tools/deps diff --git a/tests/tools/compile/tdetect.nim b/tests/tools/compile/tdetect.nim new file mode 100644 index 000000000..253fc0d39 --- /dev/null +++ b/tests/tools/compile/tdetect.nim @@ -0,0 +1,5 @@ +discard """ + action: compile +""" + +include tools/detect/detect From fe7a76f62fa1563a76e1dcce18e3ee98bcd5d36a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 2 Apr 2021 23:19:17 -0700 Subject: [PATCH 2356/4254] repr: fix rendering of `'big`, `=destroy` etc (#17624) --- compiler/renderer.nim | 22 +++++++++++++++++++--- tests/stdlib/trepr.nim | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 3d260f350..1ca5a41e3 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -51,6 +51,8 @@ type config*: ConfigRef mangler: seq[PSym] +proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string + # We render the source code in a two phases: The first # determines how long the subtree will likely be, the second # phase appends to a buffer that will be the output. @@ -1314,9 +1316,23 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkOpr, "[]") of nkAccQuoted: put(g, tkAccent, "`") - if n.len > 0: gsub(g, n[0]) - for i in 1.. 0 and tmp[0] in {'a'..'z', 'A'..'Z'}: + # handle `=destroy`, `'big' + discard + else: + useSpace = true + elif i > 0: useSpace = true + if useSpace: put(g, tkSpaces, Space) gsub(g, n[i]) put(g, tkAccent, "`") of nkIfExpr: diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 357854d67..bca9b9f91 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -145,5 +145,23 @@ do: do: 4""" + block: # bug #17292 (bug 4) + let a = deb: + proc `=destroy`() = discard + proc `'foo`(): int = discard + proc `foo bar baz`(): int = discard + let a2 = """ + +proc `=destroy`() = + discard + +proc `'foo`(): int = + discard + +proc `foo bar baz`(): int = + discard +""" + doAssert a2 == a + static: main() main() From 4a11a04fba99e868c371be09216dc93ae2fe3cd6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 3 Apr 2021 07:05:37 -0700 Subject: [PATCH 2357/4254] fix #14850: `repr` now correctly renders `do` (#17623) * fix #14850: `repr` now correctly renders `do` * add tests * fix test --- compiler/renderer.nim | 20 +++++++++----- tests/errmsgs/twrongcolon.nim | 4 +-- tests/stdlib/trepr.nim | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 1ca5a41e3..9a867b0a1 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -569,11 +569,11 @@ proc initContext(c: var TContext) = c.spacing = 0 c.flags = {} -proc gsub(g: var TSrcGen, n: PNode, c: TContext) -proc gsub(g: var TSrcGen, n: PNode) = +proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) +proc gsub(g: var TSrcGen, n: PNode, fromStmtList = false) = var c: TContext initContext(c) - gsub(g, n, c) + gsub(g, n, c, fromStmtList = fromStmtList) proc hasCom(n: PNode): bool = result = false @@ -681,7 +681,7 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) = if n[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}: gstmts(g, n[i], c, doIndent=false) else: - gsub(g, n[i]) + gsub(g, n[i], fromStmtList = true) gcoms(g) if doIndent: dedent(g) else: @@ -1003,7 +1003,7 @@ proc isCustomLit(n: PNode): bool = (n[1].kind == nkIdent and n[1].ident.s.startsWith('\'')) or (n[1].kind == nkSym and n[1].sym.name.s.startsWith('\'')) -proc gsub(g: var TSrcGen, n: PNode, c: TContext) = +proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = if isNil(n): return var a: TContext @@ -1040,9 +1040,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParLe, "(") gcomma(g, n, 1, i - 1 - n.len) put(g, tkParRi, ")") - put(g, tkColon, ":") + if fromStmtList: + put(g, tkColon, ":") + else: + put(g, tkSpaces, Space) + put(g, tkDo, "do") + put(g, tkColon, ":") gsub(g, n, i) - for j in i+1 ..< n.len: + i.inc + for j in i ..< n.len: optNL(g) put(g, tkDo, "do") put(g, tkColon, ":") diff --git a/tests/errmsgs/twrongcolon.nim b/tests/errmsgs/twrongcolon.nim index e59e37660..f4f996c3e 100644 --- a/tests/errmsgs/twrongcolon.nim +++ b/tests/errmsgs/twrongcolon.nim @@ -1,7 +1,7 @@ discard """ -errormsg: "in expression ':" +errormsg: "in expression ' do:" nimout: ''' -Error: in expression ': +Error: in expression ' do: 890': identifier expected, but found '' ''' diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index bca9b9f91..3dcbe9b69 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -163,5 +163,54 @@ proc `foo bar baz`(): int = """ doAssert a2 == a + block: # bug #14850 + block: + let a = deb: + template bar(): untyped = + foo1: + discard + 4 + foo2(1): + discard + 4 + foo3(1): + discard + 4 + do: 1 + do: 2 + x.add foo4 + x.add: foo5: 3 + x.add foo6 do: 4 + a.add(foo7 do: + echo "baz" + 4) + + doAssert a == """ + +template bar(): untyped = + foo1: + discard + 4 + foo2(1): + discard + 4 + foo3(1): + discard + 4 + do: + 1 + do: + 2 + x.add foo4 + x.add: + foo5: + 3 + x.add foo6 do: + 4 + a.add(foo7 do: + echo "baz" + 4) +""" + static: main() main() From 66890c3ad476edc54358d5ab9758df218c5c4229 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 4 Apr 2021 01:31:33 +0800 Subject: [PATCH 2358/4254] enable some packages (#17629) --- testament/important_packages.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 8f096b71e..620ad3a00 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -49,7 +49,7 @@ pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" pkg "cello" pkg "chroma" -pkg "chronicles", "nim c -o:chr -r chronicles.nim", allowFailure = true # pending https://github.com/status-im/nim-chronos/issues/169 +pkg "chronicles", "nim c -o:chr -r chronicles.nim" pkg "chronos", "nim c -r -d:release tests/testall", allowFailure = true # pending https://github.com/nim-lang/Nim/issues/17130 pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" @@ -72,7 +72,7 @@ pkg "gnuplot", "nim c gnuplot.nim" # pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" # pending https://github.com/nim-lang/Nim/issues/16509 pkg "hts", "nim c -o:htss src/hts.nim" -pkg "httpauth", allowFailure = true +pkg "httpauth" pkg "illwill", "nimble examples" pkg "inim" pkg "itertools", "nim doc src/itertools.nim" @@ -110,7 +110,7 @@ pkg "nimsvg" pkg "nimterop", "nimble minitest" pkg "nimwc", "nim c nimwc.nim" pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true -pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter", allowFailure = true +pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" pkg "norm", "nim c -r tests/sqlite/trows.nim" pkg "npeg", "nimble testarc" pkg "numericalnim", "nim c -r tests/test_integrate.nim" From 97764c8dc91081875f57029ae3f72d3a503f5e45 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 3 Apr 2021 15:24:01 -0700 Subject: [PATCH 2359/4254] remove un-needed {.push hint[ConvFromXtoItselfNotNeeded]: off.} in asyncfutures, asyncmacro (#17631) --- lib/pure/asyncfutures.nim | 2 -- lib/pure/asyncmacro.nim | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index c0c5c3f07..3c36c3453 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -363,12 +363,10 @@ proc read*[T](future: Future[T] | FutureVar[T]): T = ## this function will fail with a `ValueError` exception. ## ## If the result of the future is an error then that error will be raised. - {.push hint[ConvFromXtoItselfNotNeeded]: off.} when future is Future[T]: let fut = future else: let fut = Future[T](future) - {.pop.} if fut.finished: if fut.error != nil: injectStacktrace(fut) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 336d10aad..aaa5d9acd 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -35,14 +35,11 @@ template createCb(retFutureSym, iteratorNameSym, if next == nil: if not retFutureSym.finished: - let msg = "Async procedure ($1) yielded `nil`, are you await'ing a " & - "`nil` Future?" + let msg = "Async procedure ($1) yielded `nil`, are you await'ing a `nil` Future?" raise newException(AssertionDefect, msg % strName) else: {.gcsafe.}: - {.push hint[ConvFromXtoItselfNotNeeded]: off.} next.addCallback cast[proc() {.closure, gcsafe.}](identName) - {.pop.} except: futureVarCompletions if retFutureSym.finished: From f02e159b56aaa63713991c0a7f8e7125e91c832e Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 4 Apr 2021 21:54:26 +0300 Subject: [PATCH 2360/4254] fix rst option list at EOF (follow-up #17442) (#17638) --- lib/packages/docutils/rst.nim | 2 +- tests/stdlib/trstgen.nim | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 66efa3a3c..dfa2f12be 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -2067,7 +2067,7 @@ proc parseOptionList(p: var RstParser): PRstNode = c.add(b) result.add(c) else: - dec p.idx # back to tkIndent + if currentTok(p).kind != tkEof: dec p.idx # back to tkIndent break proc parseDefinitionList(p: var RstParser): PRstNode = diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index ad0c27f05..57dacdf11 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1362,6 +1362,7 @@ Test1 output) check("""-doption""" in output) + check "

                                      option

                                      " notin output test "Option list 3 (double /)": let input = dedent """ @@ -1378,6 +1379,7 @@ Test1 output) check("""-doption""" in output) + check "

                                      option

                                      " notin output test "Roles: subscript prefix/postfix": let expected = "See some text." From 70a30317f7b0a5711e248e0653b50d1c057bd16b Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 5 Apr 2021 04:47:28 +0800 Subject: [PATCH 2361/4254] fix #16693: testament spec nimout too lax (#16698) Co-authored-by: Timothee Cour --- testament/lib/stdtest/testutils.nim | 33 +++++++++++++------ testament/tests/shouldfail/tccodecheck.nim | 3 +- testament/tests/shouldfail/tcolumn.nim | 7 ++-- testament/tests/shouldfail/terrormsg.nim | 7 ++-- testament/tests/shouldfail/texitcode1.nim | 3 +- testament/tests/shouldfail/tfile.nim | 5 +-- testament/tests/shouldfail/tline.nim | 7 ++-- testament/tests/shouldfail/tmaxcodesize.nim | 3 +- testament/tests/shouldfail/tnimout.nim | 5 +-- testament/tests/shouldfail/toutput.nim | 7 ++-- testament/tests/shouldfail/toutputsub.nim | 3 +- testament/tests/shouldfail/treject.nim | 3 +- testament/tests/shouldfail/tsortoutput.nim | 11 ++++--- testament/tests/shouldfail/ttimeout.nim | 1 + testament/tests/shouldfail/tvalgrind.nim | 5 +-- tests/compilerfeatures/texpandmacro.nim | 2 +- tests/errmsgs/tgcsafety.nim | 2 +- tests/errmsgs/twrongcolon.nim | 2 +- tests/exprs/tresultwarning.nim | 2 +- tests/init/tuninit1.nim | 2 +- tests/objvariant/tcheckedfield1.nim | 2 +- tests/pragmas/thintprocessing.nim | 18 ++++++++++ tests/pragmas/twarning_off.nim | 2 -- tests/stdlib/tcstring.nim | 2 +- tests/stdlib/ttestutils.nim | 5 +++ .../varres/tprevent_forloopvar_mutations.nim | 2 +- tests/vm/tcompiletimetable.nim | 8 +++-- tests/vm/tmisc_vm.nim | 3 +- 28 files changed, 103 insertions(+), 52 deletions(-) create mode 100644 tests/pragmas/thintprocessing.nim diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 36f951272..58d136696 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -1,5 +1,4 @@ import std/private/miscdollars -import std/strutils from std/os import getEnv template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = @@ -26,15 +25,29 @@ template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = msg2.add $expr & " " & msg echo msg2 -proc greedyOrderedSubsetLines*(lhs, rhs: string): bool = - ## returns true if each stripped line in `lhs` appears in rhs, using a greedy matching. - let rhs = rhs.strip - var currentPos = 0 - for line in lhs.strip.splitLines: - currentPos = rhs.find(line.strip, currentPos) - if currentPos < 0: - return false - return true +when not defined(js): + import std/strutils + + proc greedyOrderedSubsetLines*(lhs, rhs: string): bool = + ## Returns true if each stripped line in `lhs` appears in rhs, using a greedy matching. + iterator splitLinesClosure(): string {.closure.} = + for line in splitLines(rhs.strip): + yield line + + var rhsIter = splitLinesClosure + var currentLine = strip(rhsIter()) + + for line in lhs.strip.splitLines: + let line = line.strip + if line.len != 0: + while line != currentLine: + currentLine = strip(rhsIter()) + if rhsIter.finished: + return false + + if rhsIter.finished: + return false + return true template enableRemoteNetworking*: bool = ## Allows contolling whether to run some test at a statement-level granularity. diff --git a/testament/tests/shouldfail/tccodecheck.nim b/testament/tests/shouldfail/tccodecheck.nim index a8d216a5b..7b5f0cce6 100644 --- a/testament/tests/shouldfail/tccodecheck.nim +++ b/testament/tests/shouldfail/tccodecheck.nim @@ -1,5 +1,6 @@ discard """ -ccodecheck: "baz" + targets: "c" + ccodecheck: "baz" """ proc foo(): void {.exportc: "bar".}= diff --git a/testament/tests/shouldfail/tcolumn.nim b/testament/tests/shouldfail/tcolumn.nim index 89482e673..b79ec52a4 100644 --- a/testament/tests/shouldfail/tcolumn.nim +++ b/testament/tests/shouldfail/tcolumn.nim @@ -1,7 +1,8 @@ discard """ -errormsg: "undeclared identifier: 'undeclared'" -line: 8 -column: 7 + errormsg: "undeclared identifier: 'undeclared'" + targets: "c" + line: 9 + column: 7 """ # test should fail because the line directive is wrong diff --git a/testament/tests/shouldfail/terrormsg.nim b/testament/tests/shouldfail/terrormsg.nim index dbbdf5021..e69035235 100644 --- a/testament/tests/shouldfail/terrormsg.nim +++ b/testament/tests/shouldfail/terrormsg.nim @@ -1,7 +1,8 @@ discard """ -errormsg: "wrong error message" -line: 8 -column: 6 + errormsg: "wrong error message" + targets: "c" + line: 9 + column: 6 """ # test should fail because the line directive is wrong diff --git a/testament/tests/shouldfail/texitcode1.nim b/testament/tests/shouldfail/texitcode1.nim index 1b38b4f2e..e5e061578 100644 --- a/testament/tests/shouldfail/texitcode1.nim +++ b/testament/tests/shouldfail/texitcode1.nim @@ -1,3 +1,4 @@ discard """ -exitcode: 1 + targets: "c" + exitcode: 1 """ diff --git a/testament/tests/shouldfail/tfile.nim b/testament/tests/shouldfail/tfile.nim index 20d4bd1f3..9463882f9 100644 --- a/testament/tests/shouldfail/tfile.nim +++ b/testament/tests/shouldfail/tfile.nim @@ -1,6 +1,7 @@ discard """ -errormsg: "undeclared identifier: 'undefined'" -file: "notthisfile.nim" + targets: "c" + errormsg: "undeclared identifier: 'undefined'" + file: "notthisfile.nim" """ echo undefined diff --git a/testament/tests/shouldfail/tline.nim b/testament/tests/shouldfail/tline.nim index f7a09875c..7f7e90896 100644 --- a/testament/tests/shouldfail/tline.nim +++ b/testament/tests/shouldfail/tline.nim @@ -1,7 +1,8 @@ discard """ -errormsg: "undeclared identifier: 'undeclared'" -line: 9 -column: 6 + targets: "c" + errormsg: "undeclared identifier: 'undeclared'" + line: 10 + column: 6 """ # test should fail because the line directive is wrong diff --git a/testament/tests/shouldfail/tmaxcodesize.nim b/testament/tests/shouldfail/tmaxcodesize.nim index 9879e4181..9e2bd9cfb 100644 --- a/testament/tests/shouldfail/tmaxcodesize.nim +++ b/testament/tests/shouldfail/tmaxcodesize.nim @@ -1,5 +1,6 @@ discard """ -maxcodesize: 1 + targets: "c" + maxcodesize: 1 """ echo "Hello World" diff --git a/testament/tests/shouldfail/tnimout.nim b/testament/tests/shouldfail/tnimout.nim index c0e332053..832f134b0 100644 --- a/testament/tests/shouldfail/tnimout.nim +++ b/testament/tests/shouldfail/tnimout.nim @@ -1,6 +1,7 @@ discard """ -nimout: "Hello World!" -action: compile + targets: "c" + nimout: "Hello World!" + action: compile """ static: diff --git a/testament/tests/shouldfail/toutput.nim b/testament/tests/shouldfail/toutput.nim index ac0bc7a46..0fa4d7278 100644 --- a/testament/tests/shouldfail/toutput.nim +++ b/testament/tests/shouldfail/toutput.nim @@ -1,7 +1,8 @@ discard """ -output: ''' -done -''' + targets: "c" + output: ''' + done + ''' """ echo "broken" diff --git a/testament/tests/shouldfail/toutputsub.nim b/testament/tests/shouldfail/toutputsub.nim index 7cc51ee8d..b34f3a8f2 100644 --- a/testament/tests/shouldfail/toutputsub.nim +++ b/testament/tests/shouldfail/toutputsub.nim @@ -1,5 +1,6 @@ discard """ -outputsub: "something else" + outputsub: "something else" + targets: "c" """ echo "Hello World!" diff --git a/testament/tests/shouldfail/treject.nim b/testament/tests/shouldfail/treject.nim index aaf2b4a63..395dc4251 100644 --- a/testament/tests/shouldfail/treject.nim +++ b/testament/tests/shouldfail/treject.nim @@ -1,5 +1,6 @@ discard """ -action: "reject" + action: "reject" + targets: "c" """ # Because we set action="reject", we expect this line not to compile. But the diff --git a/testament/tests/shouldfail/tsortoutput.nim b/testament/tests/shouldfail/tsortoutput.nim index 4ce9ce26d..0c165d21b 100644 --- a/testament/tests/shouldfail/tsortoutput.nim +++ b/testament/tests/shouldfail/tsortoutput.nim @@ -1,9 +1,10 @@ discard """ -sortoutput: true -output: ''' -2 -1 -''' + sortoutput: true + targets: "c" + output: ''' + 2 + 1 + ''' """ # this test should ensure that the output is actually sorted diff --git a/testament/tests/shouldfail/ttimeout.nim b/testament/tests/shouldfail/ttimeout.nim index fd3e1a598..8ffd71aaa 100644 --- a/testament/tests/shouldfail/ttimeout.nim +++ b/testament/tests/shouldfail/ttimeout.nim @@ -1,5 +1,6 @@ discard """ timeout: "0.1" + targets: "c" """ import os diff --git a/testament/tests/shouldfail/tvalgrind.nim b/testament/tests/shouldfail/tvalgrind.nim index 4f699fd3b..5502705b3 100644 --- a/testament/tests/shouldfail/tvalgrind.nim +++ b/testament/tests/shouldfail/tvalgrind.nim @@ -1,6 +1,7 @@ discard """ -valgrind: true -cmd: "nim $target --gc:arc -d:useMalloc $options $file" + valgrind: true + targets: "c" + cmd: "nim $target --gc:arc -d:useMalloc $options $file" """ # this is the same check used by testament/specs.nim whether or not valgrind diff --git a/tests/compilerfeatures/texpandmacro.nim b/tests/compilerfeatures/texpandmacro.nim index 76b0263ae..fea8b571f 100644 --- a/tests/compilerfeatures/texpandmacro.nim +++ b/tests/compilerfeatures/texpandmacro.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --expandMacro:foo $file" - nimout: '''Hint: expanded macro: + nimout: '''texpandmacro.nim(17, 1) Hint: expanded macro: echo ["injected echo"] var x = 4 [ExpandMacro] ''' diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 77515b74f..09ef92e75 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim check $file" errormsg: "type mismatch: got .}>" nimout: ''' -type mismatch: got .}> +tgcsafety.nim(30, 18) Error: type mismatch: got .}> but expected one of: proc serve(server: AsyncHttpServer; port: Port; callback: proc (request: Request): Future[void] {.closure, gcsafe.}; diff --git a/tests/errmsgs/twrongcolon.nim b/tests/errmsgs/twrongcolon.nim index f4f996c3e..20063cbc4 100644 --- a/tests/errmsgs/twrongcolon.nim +++ b/tests/errmsgs/twrongcolon.nim @@ -1,7 +1,7 @@ discard """ errormsg: "in expression ' do:" nimout: ''' -Error: in expression ' do: +twrongcolon.nim(11, 12) Error: in expression ' do: 890': identifier expected, but found '' ''' diff --git a/tests/exprs/tresultwarning.nim b/tests/exprs/tresultwarning.nim index 32934408e..28dabfdb1 100644 --- a/tests/exprs/tresultwarning.nim +++ b/tests/exprs/tresultwarning.nim @@ -1,5 +1,5 @@ discard """ - nimout: "Special variable 'result' is shadowed. [ResultShadowed]" + nimout: "tresultwarning.nim(6, 7) Warning: Special variable 'result' is shadowed. [ResultShadowed]" """ proc test(): string = diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim index fe91733ff..b281bcf89 100644 --- a/tests/init/tuninit1.nim +++ b/tests/init/tuninit1.nim @@ -1,5 +1,5 @@ discard """ - nimout: "Warning: use explicit initialization of 'y' for clarity [Uninit]" + nimout: "tuninit1.nim(35, 11) Warning: use explicit initialization of 'y' for clarity [Uninit]" line:34 action: compile """ diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim index 69b099f24..e1a2e60e6 100644 --- a/tests/objvariant/tcheckedfield1.nim +++ b/tests/objvariant/tcheckedfield1.nim @@ -1,5 +1,5 @@ discard """ - nimout: "Warning: cannot prove that field 'x.s' is accessible [ProveField]" + nimout: "tcheckedfield1.nim(40, 6) Warning: cannot prove that field 'x.s' is accessible [ProveField]" line:51 action: run output: "abc abc" diff --git a/tests/pragmas/thintprocessing.nim b/tests/pragmas/thintprocessing.nim new file mode 100644 index 000000000..c608bc6e4 --- /dev/null +++ b/tests/pragmas/thintprocessing.nim @@ -0,0 +1,18 @@ +discard """ + disabled: windows + matrix: "--hint:processing" + nimout: ''' +compile start +.. +warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] +compile end +''' +""" + +static: + echo "compile start" + +import warn_module + +static: + echo "compile end" diff --git a/tests/pragmas/twarning_off.nim b/tests/pragmas/twarning_off.nim index bada2999b..ccf07b9c4 100644 --- a/tests/pragmas/twarning_off.nim +++ b/tests/pragmas/twarning_off.nim @@ -1,8 +1,6 @@ discard """ - matrix: "--hint:processing" nimout: ''' compile start -.. warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] compile end ''' diff --git a/tests/stdlib/tcstring.nim b/tests/stdlib/tcstring.nim index 98da5d5c4..04a26b53c 100644 --- a/tests/stdlib/tcstring.nim +++ b/tests/stdlib/tcstring.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp js" - matrix: "; --gc:arc" + matrix: "--gc:refc; --gc:arc" """ from std/sugar import collect diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim index 1a50d311b..7e39c9ae3 100644 --- a/tests/stdlib/ttestutils.nim +++ b/tests/stdlib/ttestutils.nim @@ -4,3 +4,8 @@ block: # greedyOrderedSubsetLines doAssert greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") doAssert not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs + + doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") + doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") + doAssert not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5") + doAssert not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix") diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index 15f31d8a3..045dc7cbb 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -1,7 +1,7 @@ discard """ errormsg: "type mismatch: got " line: 17 - nimout: '''type mismatch: got + nimout: '''tprevent_forloopvar_mutations.nim(17, 7) Error: type mismatch: got but expected one of: proc inc[T: Ordinal](x: var T; y = 1) first type mismatch at position: 1 diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim index ece2ddfe9..1db490f1a 100644 --- a/tests/vm/tcompiletimetable.nim +++ b/tests/vm/tcompiletimetable.nim @@ -1,12 +1,16 @@ discard """ - nimout: '''2 + nimout: ''' +2 3 4:2 Got Hi Got Hey +''' + output:''' a b -c''' +c +''' """ # bug #404 diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim index 2d3e30c5e..bbf618622 100644 --- a/tests/vm/tmisc_vm.nim +++ b/tests/vm/tmisc_vm.nim @@ -19,6 +19,7 @@ foo4 (a: 0, b: 0) ''' """ +import std/sets #bug #1009 type @@ -95,8 +96,6 @@ static: simpleTryFinally() # bug #10981 -import sets - proc main = for i in 0..<15: var someSets = @[initHashSet[int]()] From ca405167ed79a6591104de62de6bed077f0698f5 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 5 Apr 2021 09:33:06 +0300 Subject: [PATCH 2362/4254] fix :number-lines: regression (#17639) --- lib/packages/docutils/rstgen.nim | 2 +- tests/stdlib/trstgen.nim | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 1a16f590e..f0a2604ff 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -980,7 +980,7 @@ proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string, result.beginTable.add($line & "\n") line.inc codeLines.dec - result.beginTable.add("" & ( + result.beginTable.add("
                                      " & ( d.config.getOrDefault"doc.listing_start" % [id, sourceLanguageToStr[params.lang], idStr])) result.endTable = (d.config.getOrDefault"doc.listing_end" % id) & diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 57dacdf11..99b8d8db5 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1089,6 +1089,16 @@ Test1 let output0 = input0.toHtml doAssert "

                                      Paragraph1

                                      " in output0 + test "Nim code-block :number-lines:": + let input = dedent """ + .. code-block:: nim + :number-lines: 55 + + x + y + """ + check "
                                      55\n56\n
                                      " in input.toHtml + test "RST admonitions": # check that all admonitions are implemented let input0 = dedent """ From b9c94f22aa6f3b43962f1a1f2a9b27e9cba42069 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 5 Apr 2021 09:42:18 +0200 Subject: [PATCH 2363/4254] Improve the typeinfo module (#17625) Co-authored-by: Timothee Cour --- lib/core/typeinfo.nim | 251 ++++++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 122 deletions(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 1c21e10bf..196ac8fe1 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -9,16 +9,29 @@ ## This module implements an interface to Nim's `runtime type information`:idx: ## (`RTTI`:idx:). See the `marshal `_ module for an example of -## what this module allows you to do. +## what this allows you to do. ## -## Note that even though `Any` and its operations hide the nasty low level -## details from its clients, it remains inherently unsafe! Also, Nim's -## runtime type information will evolve and may eventually be deprecated. -## As an alternative approach to programmatically understanding and -## manipulating types, consider using the `macros `_ package to -## work with the types' AST representation at compile time. See, for example, -## the `getTypeImpl proc`_. As an alternative -## approach to storing arbitrary types at runtime, consider using generics. +## ..note:: Even though `Any` and its operations hide the nasty low level +## details from its users, it remains inherently unsafe! Also, Nim's +## runtime type information will evolve and may eventually be deprecated. +## As an alternative approach to programmatically understanding and +## manipulating types, consider using the `macros `_ module to +## work with the types' AST representation at compile time. See for example +## the `getTypeImpl proc `_. As an alternative +## approach to storing arbitrary types at runtime, consider using generics. + +runnableExamples: + var x: Any + + var i = 42 + x = i.toAny + assert x.kind == akInt + assert x.getInt == 42 + + var s = @[1, 2, 3] + x = s.toAny + assert x.kind == akSequence + assert x.len == 3 {.push hints: off.} @@ -28,44 +41,45 @@ include "system/hti.nim" {.pop.} type - AnyKind* = enum ## what kind of `any` it is - akNone = 0, ## invalid any - akBool = 1, ## any represents a `bool` - akChar = 2, ## any represents a `char` - akEnum = 14, ## any represents an enum - akArray = 16, ## any represents an array - akObject = 17, ## any represents an object - akTuple = 18, ## any represents a tuple - akSet = 19, ## any represents a set - akRange = 20, ## any represents a range - akPtr = 21, ## any represents a ptr - akRef = 22, ## any represents a ref - akSequence = 24, ## any represents a sequence - akProc = 25, ## any represents a proc - akPointer = 26, ## any represents a pointer - akString = 28, ## any represents a string - akCString = 29, ## any represents a cstring - akInt = 31, ## any represents an int - akInt8 = 32, ## any represents an int8 - akInt16 = 33, ## any represents an int16 - akInt32 = 34, ## any represents an int32 - akInt64 = 35, ## any represents an int64 - akFloat = 36, ## any represents a float - akFloat32 = 37, ## any represents a float32 - akFloat64 = 38, ## any represents a float64 - akFloat128 = 39, ## any represents a float128 - akUInt = 40, ## any represents an unsigned int - akUInt8 = 41, ## any represents an unsigned int8 - akUInt16 = 42, ## any represents an unsigned in16 - akUInt32 = 43, ## any represents an unsigned int32 - akUInt64 = 44, ## any represents an unsigned int64 + AnyKind* = enum ## The kind of `Any`. + akNone = 0, ## invalid + akBool = 1, ## bool + akChar = 2, ## char + akEnum = 14, ## enum + akArray = 16, ## array + akObject = 17, ## object + akTuple = 18, ## tuple + akSet = 19, ## set + akRange = 20, ## range + akPtr = 21, ## ptr + akRef = 22, ## ref + akSequence = 24, ## sequence + akProc = 25, ## proc + akPointer = 26, ## pointer + akString = 28, ## string + akCString = 29, ## cstring + akInt = 31, ## int + akInt8 = 32, ## int8 + akInt16 = 33, ## int16 + akInt32 = 34, ## int32 + akInt64 = 35, ## int64 + akFloat = 36, ## float + akFloat32 = 37, ## float32 + akFloat64 = 38, ## float64 + akFloat128 = 39, ## float128 + akUInt = 40, ## uint + akUInt8 = 41, ## uint8 + akUInt16 = 42, ## uin16 + akUInt32 = 43, ## uint32 + akUInt64 = 44, ## uint64 # akOpt = 44+18 ## the builtin 'opt' type. - Any* = object ## can represent any nim value; NOTE: the wrapped - ## value can be modified with its wrapper! This means - ## that `Any` keeps a non-traced pointer to its - ## wrapped value and **must not** live longer than - ## its wrapped value. + Any* = object + ## A type that can represent any nim value. + ## + ## .. danger:: The wrapped value can be modified with its wrapper! This means + ## that `Any` keeps a non-traced pointer to its wrapped value and + ## **must not** live longer than its wrapped value. value: pointer when defined(js): rawType: PNimType @@ -84,9 +98,9 @@ when not defined(gcDestructors): PGenSeq = ptr TGenericSeq when defined(gogc): - const GenericSeqSize = (3 * sizeof(int)) + const GenericSeqSize = 3 * sizeof(int) else: - const GenericSeqSize = (2 * sizeof(int)) + const GenericSeqSize = 2 * sizeof(int) else: include system/seqs_v2_reimpl @@ -103,8 +117,7 @@ when not defined(js): proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.} when not defined(gcDestructors): - proc genericShallowAssign(dest, src: pointer, mt: PNimType) {. - importCompilerProc.} + proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.} proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.} proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.} proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.} @@ -120,7 +133,7 @@ template `+!!`(a, b): untyped = cast[pointer](cast[ByteAddress](a) + b) proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = assert(n.kind == nkCase) var d: int - var a = cast[ByteAddress](aa) + let a = cast[ByteAddress](aa) case n.typ.size of 1: d = ze(cast[ptr int8](a +% n.offset)[]) of 2: d = ze(cast[ptr int16](a +% n.offset)[]) @@ -130,7 +143,7 @@ proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = return d proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = - var discr = getDiscriminant(aa, n) + let discr = getDiscriminant(aa, n) if discr <% n.len: result = n.sons[discr] if result == nil: result = n.sons[n.len] @@ -144,17 +157,17 @@ proc newAny(value: pointer, rawType: PNimType): Any {.inline.} = when declared(system.VarSlot): proc toAny*(x: VarSlot): Any {.inline.} = - ## Constructs a `Any` object from a variable slot `x`. + ## Constructs an `Any` object from a variable slot `x`. ## This captures `x`'s address, so `x` can be modified with its - ## `Any` wrapper! The client needs to ensure that the wrapper + ## `Any` wrapper! The caller needs to ensure that the wrapper ## **does not** live longer than `x`! ## This is provided for easier reflection capabilities of a debugger. result.value = x.address result.rawType = x.typ proc toAny*[T](x: var T): Any {.inline.} = - ## Constructs a `Any` object from `x`. This captures `x`'s address, so - ## `x` can be modified with its `Any` wrapper! The client needs to ensure + ## Constructs an `Any` object from `x`. This captures `x`'s address, so + ## `x` can be modified with its `Any` wrapper! The caller needs to ensure ## that the wrapper **does not** live longer than `x`! newAny(addr(x), cast[PNimType](getTypeInfo(x))) @@ -167,12 +180,12 @@ proc size*(x: Any): int {.inline.} = result = x.rawType.size proc baseTypeKind*(x: Any): AnyKind {.inline.} = - ## Gets the base type's kind; `akNone` is returned if `x` has no base type. + ## Gets the base type's kind. If `x` has no base type, `akNone` is returned. if x.rawType.base != nil: result = AnyKind(ord(x.rawType.base.kind)) proc baseTypeSize*(x: Any): int {.inline.} = - ## Returns the size of `x`'s basetype. + ## Returns the size of `x`'s base type. If `x` has no base type, 0 is returned. if x.rawType.base != nil: result = x.rawType.base.size @@ -301,33 +314,32 @@ proc len*(x: Any): int = proc base*(x: Any): Any = - ## Returns base Any (useful for inherited object types). + ## Returns the base type of `x` (useful for inherited object types). result.rawType = x.rawType.base result.value = x.value proc isNil*(x: Any): bool = - ## `isNil` for an any `x` that represents a cstring, proc or + ## `isNil` for an `x` that represents a cstring, proc or ## some pointer type. assert x.rawType.kind in {tyCString, tyRef, tyPtr, tyPointer, tyProc} result = isNil(cast[ppointer](x.value)[]) -const - pointerLike = when defined(gcDestructors): {tyCString, tyRef, tyPtr, tyPointer, tyProc} - else: {tyString, tyCString, tyRef, tyPtr, tyPointer, - tySequence, tyProc} +const pointerLike = + when defined(gcDestructors): {tyCString, tyRef, tyPtr, tyPointer, tyProc} + else: {tyString, tyCString, tyRef, tyPtr, tyPointer, tySequence, tyProc} proc getPointer*(x: Any): pointer = ## Retrieves the pointer value out of `x`. `x` needs to be of kind ## `akString`, `akCString`, `akProc`, `akRef`, `akPtr`, - ## `akPointer`, `akSequence`. + ## `akPointer` or `akSequence`. assert x.rawType.kind in pointerLike result = cast[ppointer](x.value)[] proc setPointer*(x: Any, y: pointer) = ## Sets the pointer value of `x`. `x` needs to be of kind ## `akString`, `akCString`, `akProc`, `akRef`, `akPtr`, - ## `akPointer`, `akSequence`. + ## `akPointer` or `akSequence`. assert x.rawType.kind in pointerLike if y != nil and x.rawType.kind != tyPointer: genericAssign(x.value, y, x.rawType) @@ -349,15 +361,15 @@ proc fieldsAux(p: pointer, n: ptr TNimNode, if m != nil: fieldsAux(p, m, ret) iterator fields*(x: Any): tuple[name: string, any: Any] = - ## Iterates over every active field of the any `x` that represents an object + ## Iterates over every active field of `x`. `x` needs to represent an object ## or a tuple. assert x.rawType.kind in {tyTuple, tyObject} - var p = x.value + let p = x.value var t = x.rawType # XXX BUG: does not work yet, however is questionable anyway when false: if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] - var ret: seq[tuple[name: cstring, any: Any]] = @[] + var ret: seq[tuple[name: cstring, any: Any]] if t.kind == tyObject: while true: fieldsAux(p, t.node, ret) @@ -368,8 +380,7 @@ iterator fields*(x: Any): tuple[name: string, any: Any] = for name, any in items(ret): yield ($name, any) -proc getFieldNode(p: pointer, n: ptr TNimNode, - name: cstring): ptr TNimNode = +proc getFieldNode(p: pointer, n: ptr TNimNode, name: cstring): ptr TNimNode = case n.kind of nkNone: assert(false) of nkSlot: @@ -383,17 +394,17 @@ proc getFieldNode(p: pointer, n: ptr TNimNode, if cmpNimIdentifier(n.name, name) == 0: result = n else: - var m = selectBranch(p, n) + let m = selectBranch(p, n) if m != nil: result = getFieldNode(p, m, name) proc `[]=`*(x: Any, fieldName: string, value: Any) = - ## Sets a field of `x`; `x` represents an object or a tuple. + ## Sets a field of `x`. `x` needs to represent an object or a tuple. var t = x.rawType # XXX BUG: does not work yet, however is questionable anyway when false: if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] assert x.rawType.kind in {tyTuple, tyObject} - var n = getFieldNode(x.value, t.node, fieldName) + let n = getFieldNode(x.value, t.node, fieldName) if n != nil: assert n.typ == value.rawType genericAssign(x.value +!! n.offset, value.value, value.rawType) @@ -401,13 +412,13 @@ proc `[]=`*(x: Any, fieldName: string, value: Any) = raise newException(ValueError, "invalid field name: " & fieldName) proc `[]`*(x: Any, fieldName: string): Any = - ## Gets a field of `x`; `x` represents an object or a tuple. + ## Gets a field of `x`. `x` needs to represent an object or a tuple. var t = x.rawType # XXX BUG: does not work yet, however is questionable anyway when false: if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] assert x.rawType.kind in {tyTuple, tyObject} - var n = getFieldNode(x.value, t.node, fieldName) + let n = getFieldNode(x.value, t.node, fieldName) if n != nil: result.value = x.value +!! n.offset result.rawType = n.typ @@ -417,39 +428,39 @@ proc `[]`*(x: Any, fieldName: string): Any = raise newException(ValueError, "invalid field name: " & fieldName) proc `[]`*(x: Any): Any = - ## Dereference operation for the any `x` that represents a ptr or a ref. + ## Dereference operator for `Any`. `x` needs to represent a ptr or a ref. assert x.rawType.kind in {tyRef, tyPtr} result.value = cast[ppointer](x.value)[] result.rawType = x.rawType.base proc `[]=`*(x, y: Any) = - ## Dereference operation for the any `x` that represents a ptr or a ref. + ## Dereference operator for `Any`. `x` needs to represent a ptr or a ref. assert x.rawType.kind in {tyRef, tyPtr} assert y.rawType == x.rawType.base genericAssign(cast[ppointer](x.value)[], y.value, y.rawType) proc getInt*(x: Any): int = - ## Retrieves the int value out of `x`. `x` needs to represent an int. + ## Retrieves the `int` value out of `x`. `x` needs to represent an `int`. assert skipRange(x.rawType).kind == tyInt result = cast[ptr int](x.value)[] proc getInt8*(x: Any): int8 = - ## Retrieves the int8 value out of `x`. `x` needs to represent an int8. + ## Retrieves the `int8` value out of `x`. `x` needs to represent an `int8`. assert skipRange(x.rawType).kind == tyInt8 result = cast[ptr int8](x.value)[] proc getInt16*(x: Any): int16 = - ## Retrieves the int16 value out of `x`. `x` needs to represent an int16. + ## Retrieves the `int16` value out of `x`. `x` needs to represent an `int16`. assert skipRange(x.rawType).kind == tyInt16 result = cast[ptr int16](x.value)[] proc getInt32*(x: Any): int32 = - ## Retrieves the int32 value out of `x`. `x` needs to represent an int32. + ## Retrieves the `int32` value out of `x`. `x` needs to represent an `int32`. assert skipRange(x.rawType).kind == tyInt32 result = cast[ptr int32](x.value)[] proc getInt64*(x: Any): int64 = - ## Retrieves the int64 value out of `x`. `x` needs to represent an int64. + ## Retrieves the `int64` value out of `x`. `x` needs to represent an `int64`. assert skipRange(x.rawType).kind == tyInt64 result = cast[ptr int64](x.value)[] @@ -457,7 +468,7 @@ proc getBiggestInt*(x: Any): BiggestInt = ## Retrieves the integer value out of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. ## The value might be sign-extended to `BiggestInt`. - var t = skipRange(x.rawType) + let t = skipRange(x.rawType) case t.kind of tyInt: result = BiggestInt(cast[ptr int](x.value)[]) of tyInt8: result = BiggestInt(cast[ptr int8](x.value)[]) @@ -482,7 +493,7 @@ proc getBiggestInt*(x: Any): BiggestInt = proc setBiggestInt*(x: Any, y: BiggestInt) = ## Sets the integer value of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. - var t = skipRange(x.rawType) + let t = skipRange(x.rawType) case t.kind of tyInt: cast[ptr int](x.value)[] = int(y) of tyInt8: cast[ptr int8](x.value)[] = int8(y) @@ -505,38 +516,34 @@ proc setBiggestInt*(x: Any, y: BiggestInt) = else: assert false proc getUInt*(x: Any): uint = - ## Retrieves the uint value out of `x`, `x` needs to represent an uint. + ## Retrieves the `uint` value out of `x`. `x` needs to represent a `uint`. assert skipRange(x.rawType).kind == tyUInt result = cast[ptr uint](x.value)[] proc getUInt8*(x: Any): uint8 = - ## Retrieves the uint8 value out of `x`, `x` needs to represent an - ## uint8. + ## Retrieves the `uint8` value out of `x`. `x` needs to represent a `uint8`. assert skipRange(x.rawType).kind == tyUInt8 result = cast[ptr uint8](x.value)[] proc getUInt16*(x: Any): uint16 = - ## Retrieves the uint16 value out of `x`, `x` needs to represent an - ## uint16. + ## Retrieves the `uint16` value out of `x`. `x` needs to represent a `uint16`. assert skipRange(x.rawType).kind == tyUInt16 result = cast[ptr uint16](x.value)[] proc getUInt32*(x: Any): uint32 = - ## Retrieves the uint32 value out of `x`, `x` needs to represent an - ## uint32. + ## Retrieves the `uint32` value out of `x`. `x` needs to represent a `uint32`. assert skipRange(x.rawType).kind == tyUInt32 result = cast[ptr uint32](x.value)[] proc getUInt64*(x: Any): uint64 = - ## Retrieves the uint64 value out of `x`, `x` needs to represent an - ## uint64. + ## Retrieves the `uint64` value out of `x`. `x` needs to represent a `uint64`. assert skipRange(x.rawType).kind == tyUInt64 result = cast[ptr uint64](x.value)[] proc getBiggestUint*(x: Any): uint64 = ## Retrieves the unsigned integer value out of `x`. `x` needs to ## represent an unsigned integer. - var t = skipRange(x.rawType) + let t = skipRange(x.rawType) case t.kind of tyUInt: result = uint64(cast[ptr uint](x.value)[]) of tyUInt8: result = uint64(cast[ptr uint8](x.value)[]) @@ -546,9 +553,9 @@ proc getBiggestUint*(x: Any): uint64 = else: assert false proc setBiggestUint*(x: Any; y: uint64) = - ## Sets the unsigned integer value of `c`. `c` needs to represent an + ## Sets the unsigned integer value of `x`. `x` needs to represent an ## unsigned integer. - var t = skipRange(x.rawType) + let t = skipRange(x.rawType) case t.kind: of tyUInt: cast[ptr uint](x.value)[] = uint(y) of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y) @@ -558,14 +565,14 @@ proc setBiggestUint*(x: Any; y: uint64) = else: assert false proc getChar*(x: Any): char = - ## Retrieves the char value out of `x`. `x` needs to represent a char. - var t = skipRange(x.rawType) + ## Retrieves the `char` value out of `x`. `x` needs to represent a `char`. + let t = skipRange(x.rawType) assert t.kind == tyChar result = cast[ptr char](x.value)[] proc getBool*(x: Any): bool = - ## Retrieves the bool value out of `x`. `x` needs to represent a bool. - var t = skipRange(x.rawType) + ## Retrieves the `bool` value out of `x`. `x` needs to represent a `bool`. + let t = skipRange(x.rawType) assert t.kind == tyBool result = cast[ptr bool](x.value)[] @@ -579,10 +586,10 @@ proc getEnumOrdinal*(x: Any, name: string): int = ## Gets the enum field ordinal from `name`. `x` needs to represent an enum ## but is only used to access the type information. In case of an error ## `low(int)` is returned. - var typ = skipRange(x.rawType) + let typ = skipRange(x.rawType) assert typ.kind == tyEnum - var n = typ.node - var s = n.sons + let n = typ.node + let s = n.sons for i in 0 .. n.len-1: if cmpNimIdentifier($s[i].name, name) == 0: if ntfEnumHole notin typ.flags: @@ -595,16 +602,16 @@ proc getEnumField*(x: Any, ordinalValue: int): string = ## Gets the enum field name as a string. `x` needs to represent an enum ## but is only used to access the type information. The field name of ## `ordinalValue` is returned. - var typ = skipRange(x.rawType) + let typ = skipRange(x.rawType) assert typ.kind == tyEnum - var e = ordinalValue + let e = ordinalValue if ntfEnumHole notin typ.flags: if e <% typ.node.len: return $typ.node.sons[e].name else: # ugh we need a slow linear search: - var n = typ.node - var s = n.sons + let n = typ.node + let s = n.sons for i in 0 .. n.len-1: if s[i].offset == e: return $s[i].name result = $e @@ -614,17 +621,17 @@ proc getEnumField*(x: Any): string = result = getEnumField(x, getBiggestInt(x).int) proc getFloat*(x: Any): float = - ## Retrieves the float value out of `x`. `x` needs to represent an float. + ## Retrieves the `float` value out of `x`. `x` needs to represent a `float`. assert skipRange(x.rawType).kind == tyFloat result = cast[ptr float](x.value)[] proc getFloat32*(x: Any): float32 = - ## Retrieves the float32 value out of `x`. `x` needs to represent an float32. + ## Retrieves the `float32` value out of `x`. `x` needs to represent a `float32`. assert skipRange(x.rawType).kind == tyFloat32 result = cast[ptr float32](x.value)[] proc getFloat64*(x: Any): float64 = - ## Retrieves the float64 value out of `x`. `x` needs to represent an float64. + ## Retrieves the `float64` value out of `x`. `x` needs to represent a `float64`. assert skipRange(x.rawType).kind == tyFloat64 result = cast[ptr float64](x.value)[] @@ -647,7 +654,7 @@ proc setBiggestFloat*(x: Any, y: BiggestFloat) = else: assert false proc getString*(x: Any): string = - ## Retrieves the string value out of `x`. `x` needs to represent a string. + ## Retrieves the `string` value out of `x`. `x` needs to represent a `string`. assert x.rawType.kind == tyString when defined(gcDestructors): result = cast[ptr string](x.value)[] @@ -656,12 +663,12 @@ proc getString*(x: Any): string = result = cast[ptr string](x.value)[] proc setString*(x: Any, y: string) = - ## Sets the string value of `x`. `x` needs to represent a string. + ## Sets the `string` value of `x`. `x` needs to represent a `string`. assert x.rawType.kind == tyString cast[ptr string](x.value)[] = y # also correct for gcDestructors proc getCString*(x: Any): cstring = - ## Retrieves the cstring value out of `x`. `x` needs to represent a cstring. + ## Retrieves the `cstring` value out of `x`. `x` needs to represent a `cstring`. assert x.rawType.kind == tyCString result = cast[ptr cstring](x.value)[] @@ -672,10 +679,10 @@ proc assign*(x, y: Any) = genericAssign(x.value, y.value, y.rawType) iterator elements*(x: Any): int = - ## Iterates over every element of `x` that represents a Nim bitset. + ## Iterates over every element of `x`. `x` needs to represent a `set`. assert x.rawType.kind == tySet - var typ = x.rawType - var p = x.value + let typ = x.rawType + let p = x.value # "typ.slots.len" field is for sets the "first" field var u: int64 case typ.size @@ -684,22 +691,22 @@ iterator elements*(x: Any): int = of 4: u = ze64(cast[ptr int32](p)[]) of 8: u = cast[ptr int64](p)[] else: - var a = cast[pbyteArray](p) + let a = cast[pbyteArray](p) for i in 0 .. typ.size*8-1: if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0: - yield i+typ.node.len + yield i + typ.node.len if typ.size <= 8: for i in 0..sizeof(int64)*8-1: if (u and (1'i64 shl int64(i))) != 0'i64: - yield i+typ.node.len + yield i + typ.node.len proc inclSetElement*(x: Any, elem: int) = ## Includes an element `elem` in `x`. `x` needs to represent a Nim bitset. assert x.rawType.kind == tySet - var typ = x.rawType - var p = x.value + let typ = x.rawType + let p = x.value # "typ.slots.len" field is for sets the "first" field - var e = elem - typ.node.len + let e = elem - typ.node.len case typ.size of 1: var a = cast[ptr int8](p) From 526157917598bc603f5e2296f86946b1ba7f2e65 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 5 Apr 2021 02:37:28 -0700 Subject: [PATCH 2364/4254] [nim-gdb] Fixed enums and flag output [ci skip] (#17634) Debugger works for enums again. Additionally, flags work better than before. Reworked object printer as well, but the approach needs much more work or has to be replaced all together. This is mostly to save the work and myself or someone else can revisit it. --- .../untestable/gdb/gdb_pretty_printer_test.py | 5 +- .../gdb/gdb_pretty_printer_test_program.nim | 32 +++ tools/nim-gdb.py | 238 +++++++++++++----- 3 files changed, 204 insertions(+), 71 deletions(-) diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index 5b34bcb3d..8f0f88e85 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -25,6 +25,7 @@ outputs = [ 'seq(3, 3) = {"one", "two", "three"}', 'Table(3, 64) = {[4] = "four", [5] = "five", [6] = "six"}', 'Table(3, 8) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', + '{a = 1, b = "some string"}' ] for i, expected in enumerate(outputs): @@ -32,7 +33,7 @@ for i, expected in enumerate(outputs): gdb.flush() functionSymbol = gdb.selected_frame().block().function - assert functionSymbol.line == 21 + assert functionSymbol.line == 41, str(functionSymbol.line) if i == 6: # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack @@ -47,6 +48,6 @@ for i, expected in enumerate(outputs): output = str(raw) - assert output == expected, output + " != " + expected + assert output == expected, "{0} : output: ({1}) != expected: ({2})".format(i, output, expected) gdb.write(f"passed\n", gdb.STDLOG) gdb.execute("continue") diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim index c376ef89a..d2acdd282 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim +++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim @@ -14,7 +14,27 @@ type moTwo, moThree, moFoure, + + MyObj = object + a*: int + b*: string + + # MyVariant = ref object + # id*: int + # case kind*: MyEnum + # of meOne: mInt*: int + # of meTwo, meThree: discard + # of meFour: + # moInt*: int + # babies*: seq[MyVariant] + # after: float + # MyIntVariant = ref object + # stuff*: int + # case myKind*: range[0..32766] + # of 0: mFloat*: float + # of 2: mString*: string + # else: mBabies*: seq[MyIntVariant] var counter = 0 @@ -74,6 +94,18 @@ proc testProc(): void = var myOtherTable = {"one": 1, "two": 2, "three": 3}.toTable myDebug(myOtherTable) #14 + var obj = MyObj(a: 1, b: "some string") + myDebug(obj) #15 + + # var varObj = MyVariant(id: 13, kind: meFour, moInt: 94, + # babies: @[MyVariant(id: 18, kind: meOne, mInt: 7, after: 1.0), + # MyVariant(id: 21, kind: meThree, after: 2.0)], + # after: 3.0) + # myDebug(varObj) #16 + + # var varObjInt = MyIntVariant(stuff: 5, myKind: 2, mString: "this is my sweet string") + # myDebug(varObjInt) #17 + echo(counter) diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py index 8143b94d5..f35b9a033 100644 --- a/tools/nim-gdb.py +++ b/tools/nim-gdb.py @@ -1,6 +1,7 @@ import gdb import re import sys +import traceback # some feedback that the nim runtime support is loading, isn't a bad # thing at all. @@ -13,14 +14,14 @@ def printErrorOnce(id, message): global errorSet if id not in errorSet: errorSet.add(id) - gdb.write(message, gdb.STDERR) + gdb.write("printErrorOnce: " + message, gdb.STDERR) ################################################################################ ##### Type pretty printers ################################################################################ -type_hash_regex = re.compile("^\w*_([A-Za-z0-9]*)$") +type_hash_regex = re.compile("^([A-Za-z0-9]*)_([A-Za-z0-9]*)_+([A-Za-z0-9]*)$") def getNimRti(type_name): """ Return a ``gdb.Value`` object for the Nim Runtime Information of ``type_name``. """ @@ -28,13 +29,20 @@ def getNimRti(type_name): # Get static const TNimType variable. This should be available for # every non trivial Nim type. m = type_hash_regex.match(type_name) + lookups = [ + "NTI" + m.group(2).lower() + "__" + m.group(3) + "_", + "NTI" + "__" + m.group(3) + "_", + "NTI" + m.group(2).replace("colon", "58").lower() + "__" + m.group(3) + "_" + ] if m: - try: - return gdb.parse_and_eval("NTI__" + m.group(1) + "_") - except: - return None + for l in lookups: + try: + return gdb.parse_and_eval(l) + except: + pass + None -def getNameFromNimRti(rti_val): +def getNameFromNimRti(rti): """ Return name (or None) given a Nim RTI ``gdb.Value`` """ try: # sometimes there isn't a name field -- example enums @@ -192,6 +200,7 @@ class NimStringEqFunction (gdb.Function): NimStringEqFunction() + ################################################################################ ##### GDB Command, equivalent of Nim's $ operator ################################################################################ @@ -315,22 +324,6 @@ class NimStringPrinter: else: return "" -# class NimStringPrinter: -# pattern = re.compile(r'^NimStringDesc$') - -# def __init__(self, val): -# self.val = val - -# def display_hint(self): -# return 'string' - -# def to_string(self): -# if self.val: -# l = int(self.val['Sup']['len']) -# return self.val['data'].lazy_string(encoding="utf-8", length=l) -# else: -# return "" - class NimRopePrinter: pattern = re.compile(r'^tyObject_RopeObj__([A-Za-z0-9]*) \*$') @@ -372,8 +365,8 @@ def reprEnum(e, typ): e = int(e) n = typ["node"] flags = int(typ["flags"]) - # 1 << 2 is {ntfEnumHole} - if ((1 << 2) & flags) == 0: + # 1 << 6 is {ntfEnumHole} + if ((1 << 6) & flags) == 0: o = e - int(n["sons"][0]["offset"]) if o >= 0 and 0 < int(n["len"]): return n["sons"][o]["name"].string("utf-8", "ignore") @@ -386,19 +379,26 @@ def reprEnum(e, typ): return str(e) + " (invalid data!)" +def enumNti(typeNimName, idString): + typeInfoName = "NTI" + typeNimName.lower() + "__" + idString + "_" + nti = gdb.lookup_global_symbol(typeInfoName) + if nti is None: + typeInfoName = "NTI" + "__" + idString + "_" + nti = gdb.lookup_global_symbol(typeInfoName) + return (typeInfoName, nti) + class NimEnumPrinter: - pattern = re.compile(r'^tyEnum_(\w*)__([A-Za-z0-9]*)$') + pattern = re.compile(r'^tyEnum_([A-Za-z0-9]+)__([A-Za-z0-9]*)$') def __init__(self, val): self.val = val typeName = self.val.type.name match = self.pattern.match(typeName) self.typeNimName = match.group(1) - typeInfoName = "NTI__" + match.group(2) + "_" - self.nti = gdb.lookup_global_symbol(typeInfoName) + typeInfoName, self.nti = enumNti(self.typeNimName, match.group(2)) if self.nti is None: - printErrorOnce(typeInfoName, f"NimEnumPrinter: lookup global symbol '{typeInfoName}' failed for {typeName}.\n") + printErrorOnce(typeInfoName, f"NimEnumPrinter: lookup global symbol: '{typeInfoName}' failed for {typeName}.\n") def to_string(self): if self.nti: @@ -414,18 +414,17 @@ class NimSetPrinter: ## the set printer is limited to sets that fit in an integer. Other ## sets are compiled to `NU8 *` (ptr uint8) and are invisible to ## gdb (currently). - pattern = re.compile(r'^tySet_tyEnum_(\w*)_([A-Za-z0-9]*)$') + pattern = re.compile(r'^tySet_tyEnum_([A-Za-z0-9]+)__([A-Za-z0-9]*)$') def __init__(self, val): self.val = val - match = self.pattern.match(self.val.type.name) - self.typeNimName = match.group(1) - - typeInfoName = "NTI__" + match.group(2) + "_" - self.nti = gdb.lookup_global_symbol(typeInfoName) + typeName = self.val.type.name + match = self.pattern.match(typeName) + self.typeNimName = match.group(1) + typeInfoName, self.nti = enumNti(self.typeNimName, match.group(2)) if self.nti is None: - printErrorOnce(typeInfoName, "NimSetPrinter: lookup global symbol '"+ typeInfoName +" failed for " + self.val.type.name + ".\n") + printErrorOnce(typeInfoName, f"NimSetPrinter: lookup global symbol: '{typeInfoName}' failed for {typeName}.\n") def to_string(self): if self.nti: @@ -563,7 +562,7 @@ class NimStringTablePrinter: def children(self): if self.val: - data = NimSeqPrinter(self.val['data'].dereference()) + data = NimSeqPrinter(self.val['data'].referenced_value()) for idxStr, entry in data.children(): if int(entry['Field0']) != 0: yield (idxStr + ".Field0", entry['Field0']) @@ -603,55 +602,156 @@ class NimTablePrinter: # this is untested, therefore disabled # class NimObjectPrinter: -# pattern = re.compile(r'^tyObject_.*$') +# pattern = re.compile(r'^tyObject_([A-Za-z0-9]+)__(_?[A-Za-z0-9]*)(:? \*)?$') # def __init__(self, val): # self.val = val +# self.valType = None +# self.valTypeNimName = None # def display_hint(self): # return 'object' +# def _determineValType(self): +# if self.valType is None: +# vt = self.val.type +# if vt.name is None: +# target = vt.target() +# self.valType = target.pointer() +# self.fields = target.fields() +# self.valTypeName = target.name +# self.isPointer = True +# else: +# self.valType = vt +# self.fields = vt.fields() +# self.valTypeName = vt.name +# self.isPointer = False + # def to_string(self): -# return str(self.val.type) +# if self.valTypeNimName is None: +# self._determineValType() +# match = self.pattern.match(self.valTypeName) +# self.valTypeNimName = match.group(1) + +# return self.valTypeNimName # def children(self): -# if not self.val: -# yield "object", "" -# raise StopIteration +# self._determineValType() +# if self.isPointer and int(self.val) == 0: +# return +# self.baseVal = self.val.referenced_value() if self.isPointer else self.val -# for (i, field) in enumerate(self.val.type.fields()): -# if field.type.code == gdb.TYPE_CODE_UNION: -# yield _union_field -# else: -# yield (field.name, self.val[field]) +# for c in self.handleFields(self.baseVal, getNimRti(self.valTypeName)): +# yield c + +# def handleFields(self, currVal, rti, fields = None): +# rtiSons = None +# discField = (0, None) +# seenSup = False +# if fields is None: +# fields = self.fields +# try: # XXX: remove try after finished debugging this method +# for (i, field) in enumerate(fields): +# if field.name == "Sup": # inherited data +# seenSup = True +# baseRef = rti['base'] +# if baseRef: +# baseRti = baseRef.referenced_value() +# baseVal = currVal['Sup'] +# baseValType = baseVal.type +# if baseValType.name is None: +# baseValType = baseValType.target().pointer() +# baseValFields = baseValType.target().fields() +# else: +# baseValFields = baseValType.fields() + +# for c in self.handleFields(baseVal, baseRti, baseValFields): +# yield c +# else: +# if field.type.code == gdb.TYPE_CODE_UNION: +# # if not rtiSons: +# rtiNode = rti['node'].referenced_value() +# rtiSons = rtiNode['sons'] -# def _union_field(self, i, field): -# rti = getNimRti(self.val.type.name) -# if rti is None: -# return (field.name, "UNION field can't be displayed without RTI") +# if not rtiSons and int(rtiNode['len']) == 0 and str(rtiNode['name']) != "0x0": +# rtiSons = [rti['node']] # sons are dereferenced by the consumer + +# if not rtiSons: +# printErrorOnce(self.valTypeName, f"NimObjectPrinter: UNION field can't be displayed without RTI {self.valTypeName}, using fallback.\n") +# # yield (field.name, self.baseVal[field]) # XXX: this fallback seems wrong +# return # XXX: this should probably continue instead? -# node_sons = rti['node'].dereference()['sons'] -# prev_field = self.val.type.fields()[i - 1] +# if int(rtiNode['len']) != 0 and str(rtiNode['name']) != "0x0": +# gdb.write(f"wtf IT HAPPENED {self.valTypeName}\n", gdb.STDERR) -# descriminant_node = None -# for i in range(int(node['len'])): -# son = node_sons[i].dereference() -# if son['name'].string("utf-8", "ignore") == str(prev_field.name): -# descriminant_node = son -# break -# if descriminant_node is None: -# raise ValueError("Can't find union descriminant field in object RTI") +# discNode = rtiSons[discField[0]].referenced_value() +# if not discNode: +# raise ValueError("Can't find union discriminant field in object RTI") + +# discNodeLen = int(discNode['len']) +# discFieldVal = int(currVal[discField[1].name]) -# if descriminant_node is None: raise ValueError("Can't find union field in object RTI") -# union_node = descriminant_node['sons'][int(self.val[prev_field])].dereference() -# union_val = self.val[field] +# unionNodeRef = None +# if discFieldVal < discNodeLen: +# unionNodeRef = discNode['sons'][discFieldVal] +# if not unionNodeRef: +# unionNodeRef = discNode['sons'][discNodeLen] -# for f1 in union_val.type.fields(): -# for f2 in union_val[f1].type.fields(): -# if str(f2.name) == union_node['name'].string("utf-8", "ignore"): -# return (str(f2.name), union_val[f1][f2]) +# if not unionNodeRef: +# printErrorOnce(self.valTypeName + "no union node", f"wtf is up with sons {self.valTypeName} {unionNodeRef} {rtiNode['offset']} {discNode} {discFieldVal} {discNodeLen} {discField[1].name} {field.name} {field.type}\n") +# continue -# raise ValueError("RTI is absent or incomplete, can't find union definition in RTI") +# unionNode = unionNodeRef.referenced_value() + +# fieldName = "" if field.name == None else field.name.lower() +# unionNodeName = "" if not unionNode['name'] else unionNode['name'].string("utf-8", "ignore") +# if not unionNodeName or unionNodeName.lower() != fieldName: +# unionFieldName = f"_{discField[1].name.lower()}_{int(rti['node'].referenced_value()['len'])}" +# gdb.write(f"wtf i: {i} union: {unionFieldName} field: {fieldName} type: {field.type.name} tag: {field.type.tag}\n", gdb.STDERR) +# else: +# unionFieldName = unionNodeName + +# if discNodeLen == 0: +# yield (unionFieldName, currVal[unionFieldName]) +# else: +# unionNodeLen = int(unionNode['len']) +# if unionNodeLen > 0: +# for u in range(unionNodeLen): +# un = unionNode['sons'][u].referenced_value()['name'].string("utf-8", "ignore") +# yield (un, currVal[unionFieldName][un]) +# else: +# yield(unionNodeName, currVal[unionFieldName]) +# else: +# discIndex = i - 1 if seenSup else i +# discField = (discIndex, field) # discriminant field is the last normal field +# yield (field.name, currVal[field.name]) +# except GeneratorExit: +# raise +# except: +# gdb.write(f"wtf {self.valTypeName} {i} fn: {field.name} df: {discField} rti: {rti} rtiNode: {rti['node'].referenced_value()} rtiSons: {rtiSons} {sys.exc_info()} {traceback.format_tb(sys.exc_info()[2], limit = 10)}\n", gdb.STDERR) +# gdb.write(f"wtf {self.valTypeName} {i} {field.name}\n", gdb.STDERR) + +# # seenSup = False +# # for (i, field) in enumerate(fields): +# # # if field.name: +# # # val = currVal[field.name] +# # # else: +# # # val = None +# # rtiNode = rti['node'].referenced_value() +# # rtiLen = int(rtiNode['len']) +# # if int(rtiNode['len']) > 0: +# # sons = rtiNode['sons'] +# # elif int(rti['len']) == 0 and str(rti['name']) != "0x0": +# # sons = [rti['node']] # sons are dereferenced by the consumer +# # sonsIdx = i - 1 if seenSup else i +# # s = sons[sonsIdx].referenced_value() +# # addr = int(currVal.address) +# # off = addr + int(rtiNode['offset']) +# # seenSup = seenSup or field.name == "Sup" + +# # gdb.write(f"wtf: i: {i} sonsIdx: {sonsIdx} field: {field.name} rtiLen: {rtiLen} rti: {rti} rtiNode: {rtiNode} isUnion: {field.type.code == gdb.TYPE_CODE_UNION} s: {s}\n", gdb.STDERR) + +# raise ################################################################################ From 28de32c8b274d5eb55dd4a777abbcfe1945861d5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 5 Apr 2021 12:19:17 -0700 Subject: [PATCH 2365/4254] document caveats of quit (#17648) --- lib/system.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index ba27da0c7..bd9ae2762 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1185,10 +1185,6 @@ when defined(nimdoc): ## ## Before stopping the program the "exit procedures" are called in the ## opposite order they were added with `addExitProc `_. - ## `quit` never returns and ignores any exception that may have been raised - ## by the quit procedures. It does *not* call the garbage collector to free - ## all the memory, unless a quit procedure calls `GC_fullCollect - ## <#GC_fullCollect>`_. ## ## The proc `quit(QuitSuccess)` is called implicitly when your nim ## program finishes without incident for platforms where this is the @@ -1199,6 +1195,14 @@ when defined(nimdoc): ## have any compile time effect. If you need to stop the compiler inside a ## macro, use the `error `_ or `fatal ## `_ pragmas. + ## + ## .. danger:: In almost all cases, in particular in library code, prefer + ## alternatives, e.g. `doAssert false` or raise a `Defect`. + ## `quit` bypasses regular control flow in particular `defer`, + ## `try`, `catch`, `finally` and `destructors`, and exceptions that may have been + ## raised by an `addExitProc` proc, as well as cleanup code in other threads. + ## It does *not* call the garbage collector to free all the memory, + ## unless an `addExitProc` proc calls `GC_fullCollect <#GC_fullCollect>`_. elif defined(genode): include genode/env From aa4f18eff0344c4de828c1e22e440c0734113086 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 6 Apr 2021 02:11:30 -0700 Subject: [PATCH 2366/4254] items(array)+friends: remove a RT comparison (#17650) --- lib/system/iterators.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index d8af4eed5..86d64d0c7 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -29,8 +29,8 @@ iterator mitems*[T](a: var openArray[T]): var T {.inline.} = iterator items*[IX, T](a: array[IX, T]): T {.inline.} = ## Iterates over each item of `a`. - var i = low(IX) - if i <= high(IX): + when a.len > 0: + var i = low(IX) while true: yield a[i] if i >= high(IX): break @@ -38,8 +38,8 @@ iterator items*[IX, T](a: array[IX, T]): T {.inline.} = iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} = ## Iterates over each item of `a` so that you can modify the yielded value. - var i = low(IX) - if i <= high(IX): + when a.len > 0: + var i = low(IX) while true: yield a[i] if i >= high(IX): break @@ -146,8 +146,8 @@ iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T]{.inline.} iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. - var i = low(IX) - if i <= high(IX): + when a.len > 0: + var i = low(IX) while true: yield (i, a[i]) if i >= high(IX): break @@ -156,8 +156,8 @@ iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} = ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. ## `a[index]` can be modified. - var i = low(IX) - if i <= high(IX): + when a.len > 0: + var i = low(IX) while true: yield (i, a[i]) if i >= high(IX): break From 7bfb9f00022513c2d0f4f93799c07be7e9ffa1e6 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 6 Apr 2021 22:20:01 +0800 Subject: [PATCH 2367/4254] close #17636 (#17643) --- tests/concepts/texplain.nim | 86 +++++++++---------- tests/concepts/twrapconcept.nim | 3 +- .../tdont_return_unowned_from_owned.nim | 4 +- tests/effects/tfuncs_cannot_mutate.nim | 4 +- tests/effects/tfuncs_cannot_mutate_simple.nim | 3 +- tests/errmsgs/t6608.nim | 3 +- tests/errmsgs/tconceptconstraint.nim | 1 - tests/errmsgs/tgenericconstraint.nim | 1 - tests/errmsgs/twrong_at_operator.nim | 3 +- tests/errmsgs/twrongcolon.nim | 3 +- tests/init/tuninit1.nim | 3 +- tests/misc/tnoop.nim | 3 +- tests/objvariant/tcheckedfield1.nim | 3 +- tests/parallel/tgc_unsafe2.nim | 7 +- .../varres/tprevent_forloopvar_mutations.nim | 3 +- tests/views/tcannot_borrow.nim | 5 +- 16 files changed, 60 insertions(+), 75 deletions(-) diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim index de3d540cd..49eb8eb6b 100644 --- a/tests/concepts/texplain.nim +++ b/tests/concepts/texplain.nim @@ -1,45 +1,45 @@ discard """ cmd: "nim c --verbosity:0 --colors:off $file" nimout: ''' -texplain.nim(164, 10) Hint: Non-matching candidates for e(y) +texplain.nim(162, 10) Hint: Non-matching candidates for e(y) proc e(i: int): int first type mismatch at position: 1 required type for i: int but expression 'y' is of type: MatchingType -texplain.nim(167, 7) Hint: Non-matching candidates for e(10) +texplain.nim(165, 7) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression '10' is of type: int literal(10) -texplain.nim(130, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(130, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(130, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(130, 6) ExplainedConcept: expression '' has no type (or is ambiguous) -texplain.nim(130, 5) ExplainedConcept: concept predicate failed -texplain.nim(131, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(131, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(131, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(131, 6) ExplainedConcept: expression '' has no type (or is ambiguous) -texplain.nim(130, 5) ExplainedConcept: concept predicate failed +texplain.nim(128, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(128, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(128, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(128, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(128, 5) ExplainedConcept: concept predicate failed +texplain.nim(129, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(129, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(129, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(129, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(128, 5) ExplainedConcept: concept predicate failed -texplain.nim(170, 10) Hint: Non-matching candidates for e(10) +texplain.nim(168, 10) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression '10' is of type: int literal(10) -texplain.nim(130, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(130, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(130, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(130, 6) ExplainedConcept: expression '' has no type (or is ambiguous) -texplain.nim(130, 5) ExplainedConcept: concept predicate failed -texplain.nim(131, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(131, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(131, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(131, 6) ExplainedConcept: expression '' has no type (or is ambiguous) -texplain.nim(130, 5) ExplainedConcept: concept predicate failed +texplain.nim(128, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(128, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(128, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(128, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(128, 5) ExplainedConcept: concept predicate failed +texplain.nim(129, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(129, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(129, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(129, 6) ExplainedConcept: expression '' has no type (or is ambiguous) +texplain.nim(128, 5) ExplainedConcept: concept predicate failed -texplain.nim(174, 20) Error: type mismatch: got +texplain.nim(172, 20) Error: type mismatch: got but expected one of: proc e(i: int): int first type mismatch at position: 1 @@ -49,11 +49,11 @@ proc e(o: ExplainedConcept): int first type mismatch at position: 1 required type for o: ExplainedConcept but expression 'n' is of type: NonMatchingType -texplain.nim(174, 9) template/generic instantiation of `assert` from here -texplain.nim(130, 5) ExplainedConcept: concept predicate failed +texplain.nim(172, 9) template/generic instantiation of `assert` from here +texplain.nim(128, 5) ExplainedConcept: concept predicate failed expression: e(n) -texplain.nim(175, 20) Error: type mismatch: got +texplain.nim(173, 20) Error: type mismatch: got but expected one of: proc r(i: string): int first type mismatch at position: 1 @@ -63,15 +63,15 @@ proc r(o: RegularConcept): int first type mismatch at position: 1 required type for o: RegularConcept but expression 'n' is of type: NonMatchingType -texplain.nim(175, 9) template/generic instantiation of `assert` from here -texplain.nim(134, 5) RegularConcept: concept predicate failed +texplain.nim(173, 9) template/generic instantiation of `assert` from here +texplain.nim(132, 5) RegularConcept: concept predicate failed proc r[T](a: SomeNumber; b: T; c: auto) first type mismatch at position: 1 required type for a: SomeNumber but expression 'n' is of type: NonMatchingType expression: r(n) -texplain.nim(176, 20) Hint: Non-matching candidates for r(y) +texplain.nim(174, 20) Hint: Non-matching candidates for r(y) proc r(i: string): int first type mismatch at position: 1 required type for i: string @@ -81,28 +81,26 @@ proc r[T](a: SomeNumber; b: T; c: auto) required type for a: SomeNumber but expression 'y' is of type: MatchingType -texplain.nim(184, 2) Error: type mismatch: got +texplain.nim(182, 2) Error: type mismatch: got but expected one of: proc f(o: NestedConcept) first type mismatch at position: 1 required type for o: NestedConcept but expression 'y' is of type: MatchingType -texplain.nim(134, 6) RegularConcept: undeclared field: 'foo' -texplain.nim(134, 6) RegularConcept: undeclared field: '.' -texplain.nim(134, 6) RegularConcept: expression '.' cannot be called -texplain.nim(134, 6) RegularConcept: expression '' has no type (or is ambiguous) -texplain.nim(134, 5) RegularConcept: concept predicate failed -texplain.nim(135, 6) RegularConcept: undeclared field: 'bar' -texplain.nim(135, 6) RegularConcept: undeclared field: '.' -texplain.nim(135, 6) RegularConcept: expression '.' cannot be called -texplain.nim(135, 6) RegularConcept: expression '' has no type (or is ambiguous) -texplain.nim(134, 5) RegularConcept: concept predicate failed -texplain.nim(138, 5) NestedConcept: concept predicate failed +texplain.nim(132, 6) RegularConcept: undeclared field: 'foo' +texplain.nim(132, 6) RegularConcept: undeclared field: '.' +texplain.nim(132, 6) RegularConcept: expression '.' cannot be called +texplain.nim(132, 6) RegularConcept: expression '' has no type (or is ambiguous) +texplain.nim(132, 5) RegularConcept: concept predicate failed +texplain.nim(133, 6) RegularConcept: undeclared field: 'bar' +texplain.nim(133, 6) RegularConcept: undeclared field: '.' +texplain.nim(133, 6) RegularConcept: expression '.' cannot be called +texplain.nim(133, 6) RegularConcept: expression '' has no type (or is ambiguous) +texplain.nim(132, 5) RegularConcept: concept predicate failed +texplain.nim(136, 5) NestedConcept: concept predicate failed expression: f(y)''' errormsg: "type mismatch: got " - line: 184 - """ diff --git a/tests/concepts/twrapconcept.nim b/tests/concepts/twrapconcept.nim index 377b63afe..c3dea2ff9 100644 --- a/tests/concepts/twrapconcept.nim +++ b/tests/concepts/twrapconcept.nim @@ -1,7 +1,6 @@ discard """ errormsg: "type mismatch: got " - line: 21 - nimout: "twrapconcept.nim(11, 5) Foo: concept predicate failed" + nimout: "twrapconcept.nim(10, 5) Foo: concept predicate failed" """ # https://github.com/nim-lang/Nim/issues/5127 diff --git a/tests/destructor/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim index a726960c6..d27626dea 100644 --- a/tests/destructor/tdont_return_unowned_from_owned.nim +++ b/tests/destructor/tdont_return_unowned_from_owned.nim @@ -1,6 +1,7 @@ discard """ cmd: "nim check --newruntime --hints:off $file" - nimout: '''tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type + nimout: ''' +tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type tdont_return_unowned_from_owned.nim(39, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type tdont_return_unowned_from_owned.nim(42, 6) Error: type mismatch: got but expected one of: @@ -16,7 +17,6 @@ tdont_return_unowned_from_owned.nim(51, 13) Error: assignment produces a danglin tdont_return_unowned_from_owned.nim(55, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type ''' errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type" - line: 55 """ diff --git a/tests/effects/tfuncs_cannot_mutate.nim b/tests/effects/tfuncs_cannot_mutate.nim index 4768af2b3..8784cbbb1 100644 --- a/tests/effects/tfuncs_cannot_mutate.nim +++ b/tests/effects/tfuncs_cannot_mutate.nim @@ -2,8 +2,8 @@ discard """ errormsg: "'mutate' can have side effects" nimout: '''an object reachable from 'n' is potentially mutated tfuncs_cannot_mutate.nim(39, 15) the mutation is here -tfuncs_cannot_mutate.nim(37, 7) is the statement that connected the mutation to the parameter''' - line: 33 +tfuncs_cannot_mutate.nim(37, 7) is the statement that connected the mutation to the parameter +''' """ {.experimental: "strictFuncs".} diff --git a/tests/effects/tfuncs_cannot_mutate_simple.nim b/tests/effects/tfuncs_cannot_mutate_simple.nim index 9de20d1ec..a94a8d746 100644 --- a/tests/effects/tfuncs_cannot_mutate_simple.nim +++ b/tests/effects/tfuncs_cannot_mutate_simple.nim @@ -1,8 +1,7 @@ discard """ errormsg: "'edit' can have side effects" nimout: '''an object reachable from 'x' is potentially mutated -tfuncs_cannot_mutate_simple.nim(17, 4) the mutation is here''' - line: 16 +tfuncs_cannot_mutate_simple.nim(16, 4) the mutation is here''' """ {.experimental: "strictFuncs".} diff --git a/tests/errmsgs/t6608.nim b/tests/errmsgs/t6608.nim index 3d82f3cd8..88cbf42fd 100644 --- a/tests/errmsgs/t6608.nim +++ b/tests/errmsgs/t6608.nim @@ -1,10 +1,9 @@ discard """ cmd: "nim c --hints:off $file" errormsg: "type mismatch: got <>" - nimout: '''t6608.nim(14, 4) Error: type mismatch: got <> + nimout: '''t6608.nim(13, 4) Error: type mismatch: got <> but expected one of: AcceptCB = proc (s: string){.closure.}''' - line: 14 """ type diff --git a/tests/errmsgs/tconceptconstraint.nim b/tests/errmsgs/tconceptconstraint.nim index b1977acbc..066ec5bdb 100644 --- a/tests/errmsgs/tconceptconstraint.nim +++ b/tests/errmsgs/tconceptconstraint.nim @@ -1,6 +1,5 @@ discard """ errormsg: "cannot instantiate B" - line: 20 nimout: ''' got: but expected: diff --git a/tests/errmsgs/tgenericconstraint.nim b/tests/errmsgs/tgenericconstraint.nim index b7272e787..b51fb3488 100644 --- a/tests/errmsgs/tgenericconstraint.nim +++ b/tests/errmsgs/tgenericconstraint.nim @@ -1,6 +1,5 @@ discard """ errormsg: "cannot instantiate B" - line: 14 nimout: ''' got: but expected: diff --git a/tests/errmsgs/twrong_at_operator.nim b/tests/errmsgs/twrong_at_operator.nim index d7bfca415..438186f01 100644 --- a/tests/errmsgs/twrong_at_operator.nim +++ b/tests/errmsgs/twrong_at_operator.nim @@ -1,8 +1,7 @@ discard """ errormsg: "type mismatch: got " -line: 22 nimout: ''' -twrong_at_operator.nim(22, 30) Error: type mismatch: got +twrong_at_operator.nim(21, 30) Error: type mismatch: got but expected one of: proc `@`[IDX, T](a: sink array[IDX, T]): seq[T] first type mismatch at position: 1 diff --git a/tests/errmsgs/twrongcolon.nim b/tests/errmsgs/twrongcolon.nim index 20063cbc4..06e802eb7 100644 --- a/tests/errmsgs/twrongcolon.nim +++ b/tests/errmsgs/twrongcolon.nim @@ -1,11 +1,10 @@ discard """ errormsg: "in expression ' do:" nimout: ''' -twrongcolon.nim(11, 12) Error: in expression ' do: +twrongcolon.nim(10, 12) Error: in expression ' do: 890': identifier expected, but found '' ''' -line: 11 """ var n: int : 890 diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim index b281bcf89..9a4161a30 100644 --- a/tests/init/tuninit1.nim +++ b/tests/init/tuninit1.nim @@ -1,6 +1,5 @@ discard """ - nimout: "tuninit1.nim(35, 11) Warning: use explicit initialization of 'y' for clarity [Uninit]" - line:34 + nimout: "tuninit1.nim(34, 11) Warning: use explicit initialization of 'y' for clarity [Uninit]" action: compile """ diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim index 7f5bb1045..f55f2441a 100644 --- a/tests/misc/tnoop.nim +++ b/tests/misc/tnoop.nim @@ -1,9 +1,8 @@ discard """ nimout: ''' - found 'a' [var declared in tnoop.nim(11, 3)] + found 'a' [var declared in tnoop.nim(10, 3)] ''' file: "tnoop.nim" - line: 13 errormsg: "attempting to call routine: 'a'" """ diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim index e1a2e60e6..4a6c49f66 100644 --- a/tests/objvariant/tcheckedfield1.nim +++ b/tests/objvariant/tcheckedfield1.nim @@ -1,6 +1,5 @@ discard """ - nimout: "tcheckedfield1.nim(40, 6) Warning: cannot prove that field 'x.s' is accessible [ProveField]" - line:51 + nimout: "tcheckedfield1.nim(39, 6) Warning: cannot prove that field 'x.s' is accessible [ProveField]" action: run output: "abc abc" """ diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim index 40af728fb..7d98dafcb 100644 --- a/tests/parallel/tgc_unsafe2.nim +++ b/tests/parallel/tgc_unsafe2.nim @@ -1,9 +1,8 @@ discard """ errormsg: "'consumer' is not GC-safe as it calls 'track'" - line: 28 - nimout: '''tgc_unsafe2.nim(22, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2] -tgc_unsafe2.nim(26, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2] -tgc_unsafe2.nim(28, 6) Error: 'consumer' is not GC-safe as it calls 'track' + nimout: '''tgc_unsafe2.nim(21, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2] +tgc_unsafe2.nim(25, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2] +tgc_unsafe2.nim(27, 6) Error: 'consumer' is not GC-safe as it calls 'track' ''' """ diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index 045dc7cbb..96bb208c2 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -1,7 +1,6 @@ discard """ errormsg: "type mismatch: got " - line: 17 - nimout: '''tprevent_forloopvar_mutations.nim(17, 7) Error: type mismatch: got + nimout: '''tprevent_forloopvar_mutations.nim(16, 7) Error: type mismatch: got but expected one of: proc inc[T: Ordinal](x: var T; y = 1) first type mismatch at position: 1 diff --git a/tests/views/tcannot_borrow.nim b/tests/views/tcannot_borrow.nim index d1c194b25..0b8793159 100644 --- a/tests/views/tcannot_borrow.nim +++ b/tests/views/tcannot_borrow.nim @@ -1,8 +1,7 @@ discard """ errormsg: "cannot borrow" - nimout: '''tcannot_borrow.nim(21, 7) Error: cannot borrow meh; what it borrows from is potentially mutated -tcannot_borrow.nim(22, 3) the mutation is here''' - line: 21 + nimout: '''tcannot_borrow.nim(20, 7) Error: cannot borrow meh; what it borrows from is potentially mutated +tcannot_borrow.nim(21, 3) the mutation is here''' """ From c7b4639460dd377ee937e3468df9b7041744302f Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 6 Apr 2021 22:21:58 +0800 Subject: [PATCH 2368/4254] ref #14873 (#17644) * ref #14873 * comment * Update lib/core/locks.nim --- lib/core/locks.nim | 5 +++++ tests/stdlib/tlocks.nim | 6 +++--- tests/stdlib/uselocks.nim | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index bddd6d864..1540e2bcd 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -28,6 +28,11 @@ type {.push stackTrace: off.} + +proc `$`*(lock: Lock): string = + # workaround bug #14873 + result = "()" + proc initLock*(lock: var Lock) {.inline.} = ## Initializes the given lock. when not defined(js): diff --git a/tests/stdlib/tlocks.nim b/tests/stdlib/tlocks.nim index e567cfde8..0815c5d01 100644 --- a/tests/stdlib/tlocks.nim +++ b/tests/stdlib/tlocks.nim @@ -1,10 +1,10 @@ discard """ - output: '''3''' - cmd: "nim $target --threads:on $options $file" + targets: "c cpp js" + matrix: "--threads:on" """ #bug #6049 import uselocks var m = createMyType[int]() -echo $m.use() +doAssert m.use() == 3 diff --git a/tests/stdlib/uselocks.nim b/tests/stdlib/uselocks.nim index cde9641b2..e9d23f9d9 100644 --- a/tests/stdlib/uselocks.nim +++ b/tests/stdlib/uselocks.nim @@ -9,3 +9,7 @@ proc createMyType*[T]: MyType[T] = proc use* (m: var MyType): int = withLock m.lock: result = 3 + +block: + var l: Lock + doAssert $l == "()" From e406e28738cfaebd6e0ff4642daa55c9114bd68a Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 7 Apr 2021 00:01:54 +0800 Subject: [PATCH 2369/4254] fix #16898 #17621 (#17628) * fix #16898 * fix #17621 * Update compiler/semtypes.nim --- compiler/semtypes.nim | 6 ++++-- compiler/typeallowed.nim | 3 ++- tests/lent/t16898.nim | 31 +++++++++++++++++++++++++++++++ tests/lent/t17621.nim | 15 +++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/lent/t16898.nim create mode 100644 tests/lent/t17621.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 0fce7b417..b34dc36e3 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -10,7 +10,7 @@ # this module does the semantic checking of type declarations # included from sem.nim -import math +import std/math const errStringOrIdentNodeExpected = "string or ident node expected" @@ -1171,6 +1171,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, else: discard proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType = + ## Semchecks the type of parameters. if n.kind == nkCurlyExpr: result = semTypeNode(c, n[0], nil) constraint = semNodeKindConstraints(n, c.config, 1) @@ -1226,10 +1227,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if hasType: typ = semParamType(c, a[^2], constraint) # TODO: Disallow typed/untyped in procs in the compiler/stdlib - if kind == skProc and (typ.kind == tyTyped or typ.kind == tyUntyped): + if kind in {skProc, skFunc} and (typ.kind == tyTyped or typ.kind == tyUntyped): if not isMagic(getCurrOwner(c)): localError(c.config, a[^2].info, "'" & typ.sym.name.s & "' is only allowed in templates and macros or magic procs") + if hasDefault: def = a[^1] block determineType: diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index db3735359..9075d9e38 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -57,7 +57,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, of tyVar, tyLent: if kind in {skProc, skFunc, skConst} and (views notin c.features): result = t - elif t.kind == tyLent and kind != skResult and (views notin c.features): + elif t.kind == tyLent and ((kind != skResult and views notin c.features) or + kind == skParam): # lent can't be used as parameters. result = t else: var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc, tySink}) diff --git a/tests/lent/t16898.nim b/tests/lent/t16898.nim new file mode 100644 index 000000000..ea7c934ef --- /dev/null +++ b/tests/lent/t16898.nim @@ -0,0 +1,31 @@ +discard """ + errormsg: "invalid type: 'lent QuadraticExt' in this context: 'proc (r: var QuadraticExt, a: lent QuadraticExt, b: lent QuadraticExt){.noSideEffect, gcsafe, locks: 0.}' for proc" +""" + +# bug #16898 +type + Fp[N: static int, T] = object + big: array[N, T] + +type + QuadraticExt* = concept x + ## Quadratic Extension concept (like complex) + type BaseField = auto + x.c0 is BaseField + x.c1 is BaseField + +{.experimental:"views".} + +func prod(r: var QuadraticExt, a, b: lent QuadraticExt) = + discard + +type + Fp2[N: static int, T] = object + c0, c1: Fp[N, T] + +# This should be passed by reference, +# but concepts do not respect the 24 bytes rule +# or `byref` pragma. +var r, a, b: Fp2[6, uint64] + +prod(r, a, b) diff --git a/tests/lent/t17621.nim b/tests/lent/t17621.nim new file mode 100644 index 000000000..e324a963e --- /dev/null +++ b/tests/lent/t17621.nim @@ -0,0 +1,15 @@ +discard """ + errormsg: "invalid type: 'lent Test' in this context: 'proc (self: lent Test)' for proc" +""" + +# bug #17621 +{.experimental: "views".} + +type Test = ref object + foo: int + +proc modify(self: lent Test) = + self.foo += 1 + +let test = Test(foo: 12) +modify(test) From 020c0a33447287c4d42e67754bae75d01b6160a0 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 6 Apr 2021 18:52:12 +0200 Subject: [PATCH 2370/4254] don't run one example on 32-bit machines (#17655) This example seems to break our 32-bit nightlies builds. This is just a temporary solution (TM) until we figure out a better one. --- lib/pure/math.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 2ef7ee102..03e5040ae 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -951,9 +951,10 @@ func frexp*[T: float32|float64](x: T): tuple[frac: T, exp: int] {.inline.} = doAssert frexp(0.0) == (0.0, 0) # special cases: - doAssert frexp(-0.0).frac.signbit # signbit preserved for +-0 - doAssert frexp(Inf).frac == Inf # +- Inf preserved - doAssert frexp(NaN).frac.isNaN + when sizeof(int) == 8: + doAssert frexp(-0.0).frac.signbit # signbit preserved for +-0 + doAssert frexp(Inf).frac == Inf # +- Inf preserved + doAssert frexp(NaN).frac.isNaN when not defined(js): var exp: cint From 6ab58168661b27778dd6bd64bedf70a7889f5aa0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 6 Apr 2021 13:01:34 -0700 Subject: [PATCH 2371/4254] add compiler/debugutils.nim to help debugging compiler (#17652) * add compiler/debugutils.nim * address comments --- compiler/debugutils.nim | 19 +++++++++++++++++++ compiler/options.nim | 23 ++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 compiler/debugutils.nim diff --git a/compiler/debugutils.nim b/compiler/debugutils.nim new file mode 100644 index 000000000..235c100b3 --- /dev/null +++ b/compiler/debugutils.nim @@ -0,0 +1,19 @@ +##[ +Utilities to help with debugging nim compiler. + +Experimental API, subject to change. +]## + +import options + +var conf0: ConfigRef + +proc onNewConfigRef*(conf: ConfigRef) {.inline.} = + ## Caches `conf`, which can be retrieved with `getConfigRef`. + ## This avoids having to forward `conf` all the way down the call chain to + ## procs that need it during a debugging session. + conf0 = conf + +proc getConfigRef*(): ConfigRef = + ## nil, if -d:nimDebugUtils wasn't specified + result = conf0 diff --git a/compiler/options.nim b/compiler/options.nim index 2c8d43733..0bdb51159 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -446,6 +446,10 @@ proc newProfileData(): ProfileData = const foreignPackageNotesDefault* = { hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting, hintUser, warnUser} +proc isDefined*(conf: ConfigRef; symbol: string): bool + +import debugutils + proc newConfigRef*(): ConfigRef = result = ConfigRef( selectedGC: gcRefc, @@ -504,16 +508,21 @@ proc newConfigRef*(): ConfigRef = # enable colors by default on terminals if terminal.isatty(stderr): incl(result.globalOptions, optUseColors) + when defined(nimDebugUtils): + onNewConfigRef(result) proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. - result = ConfigRef( - selectedGC: gcRefc, - verbosity: 1, - options: DefaultOptions, - globalOptions: DefaultGlobalOptions, - foreignPackageNotes: foreignPackageNotesDefault, - notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) + when defined(nimDebugUtils): + result = getConfigRef() + else: + result = ConfigRef( + selectedGC: gcRefc, + verbosity: 1, + options: DefaultOptions, + globalOptions: DefaultGlobalOptions, + foreignPackageNotes: foreignPackageNotesDefault, + notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define From 34c1c631bb61e8a7dde923c73a2eecbd9d96345a Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 7 Apr 2021 04:08:59 +0800 Subject: [PATCH 2372/4254] close #4451 (#17627) --- doc/estp.rst | 8 ++++++++ lib/pure/nimprof.nim | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/estp.rst b/doc/estp.rst index 8146562b6..fa9977d44 100644 --- a/doc/estp.rst +++ b/doc/estp.rst @@ -21,6 +21,14 @@ You can in fact look at `nimprof`'s source code to see how to implement your own profiler. The setting `--profiler:on` defines the conditional symbol `profiler`. +You can use `when compileOption("profiler")` to make the switch seamless. +If `profiler` is `off`, your program runs normally. Otherwise your program +is profiled. + +```nim +when compileOption("profiler"): + import nimprof +``` After your program has finished the profiler will create a file `profile_results.txt` containing the profiling results. diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 721ae35c3..3b1f703e3 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -9,7 +9,8 @@ ## Profiling support for Nim. This is an embedded profiler that requires ## `--profiler:on`. You only need to import this module to get a profiling -## report at program exit. +## report at program exit. See `Embedded Stack Trace Profiler `_ +## for usage. when not defined(profiler) and not defined(memProfiler): {.error: "Profiling support is turned off! Enable profiling by passing `--profiler:on --stackTrace:on` to the compiler (see the Nim Compiler User Guide for more options).".} From 444658fe5817808d71c06f1b5c272c1132d89bfb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Apr 2021 07:46:45 +0200 Subject: [PATCH 2373/4254] fixes #17656 (#17657) --- compiler/semexprs.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 71c9e0295..c0aa168ef 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2962,7 +2962,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkMixinStmt: discard of nkBindStmt: if c.p != nil: - c.p.localBindStmts.add n + if n.len > 0 and n[0].kind == nkSym: + c.p.localBindStmts.add n else: localError(c.config, n.info, "invalid context for 'bind' statement: " & renderTree(n, {renderNoComments})) From d3702a4dc3f4226ae601f503bc3f2244f9e1bdce Mon Sep 17 00:00:00 2001 From: rockcavera Date: Wed, 7 Apr 2021 02:52:14 -0300 Subject: [PATCH 2374/4254] removing warning imported and not used debugutils (#17660) --- compiler/options.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/options.nim b/compiler/options.nim index 0bdb51159..7408ce675 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -448,7 +448,8 @@ const foreignPackageNotesDefault* = { proc isDefined*(conf: ConfigRef; symbol: string): bool -import debugutils +when defined(nimDebugUtils): + import debugutils proc newConfigRef*(): ConfigRef = result = ConfigRef( From 939df8cbdaf8b65966c60b4e368ba317cf4d194f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Apr 2021 13:40:57 +0200 Subject: [PATCH 2375/4254] ensure the avr example keeps compiling (#17663) * ensure the avr example keeps compiling * Update tests/avr/thello.nim * now compiles properly --- lib/system/embedded.nim | 4 ++++ tests/avr/nim.cfg | 12 ++++++++++++ tests/avr/panicoverride.nim | 13 +++++++++++++ tests/avr/thello.nim | 6 ++++++ 4 files changed, 35 insertions(+) create mode 100644 tests/avr/nim.cfg create mode 100644 tests/avr/panicoverride.nim create mode 100644 tests/avr/thello.nim diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index 258558c3f..e0b053c7b 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -34,6 +34,10 @@ proc quitOrDebug() {.noreturn, importc: "abort", header: "", nodecl.} proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = sysFatal(ReraiseDefect, "exception handling is not available") +proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring, + line: int) {.compilerRtl.} = + sysFatal(ReraiseDefect, "exception handling is not available") + proc reraiseException() {.compilerRtl.} = sysFatal(ReraiseDefect, "no exception to reraise") diff --git a/tests/avr/nim.cfg b/tests/avr/nim.cfg new file mode 100644 index 000000000..d6eba8eda --- /dev/null +++ b/tests/avr/nim.cfg @@ -0,0 +1,12 @@ +avr.standalone.gcc.path = "/usr/bin" +avr.standalone.gcc.exe = "avr-gcc" +avr.standalone.gcc.linkerexe = "avr-gcc" +passC = "-Os" +passC = "-DF_CPU=16000000UL" +passC = "-mmcu=atmega328p" +passL = "-mmcu=atmega328p" +passC = "-flto" +passL = "-flto" +cpu = "avr" +deadCodeElim = "on" +gc = "arc" diff --git a/tests/avr/panicoverride.nim b/tests/avr/panicoverride.nim new file mode 100644 index 000000000..770933ddd --- /dev/null +++ b/tests/avr/panicoverride.nim @@ -0,0 +1,13 @@ +proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} +proc exit(code: int) {.importc, header: "", cdecl.} + +{.push stack_trace: off, profiler:off.} + +proc rawoutput(s: string) = + printf("%s\n", s) + +proc panic(s: string) = + rawoutput(s) + exit(1) + +{.pop.} diff --git a/tests/avr/thello.nim b/tests/avr/thello.nim new file mode 100644 index 000000000..a0191815c --- /dev/null +++ b/tests/avr/thello.nim @@ -0,0 +1,6 @@ +discard """ + cmd: "nim c --compileOnly --os:standalone --exceptions:quirky -d:noSignalHandler -d:danger $file" + action: "compile" +""" + +echo "hi" From 834d5641e88b144c1cf94fa13f567b0a2acda977 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 7 Apr 2021 20:17:48 +0800 Subject: [PATCH 2376/4254] use sink and lent in deques (#17661) * use sink and lent in deques * Update lib/pure/collections/deques.nim Co-authored-by: Andreas Rumpf Co-authored-by: Andreas Rumpf --- lib/pure/collections/deques.nim | 20 ++++++------- tests/stdlib/tdeques.nim | 53 +++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index c8bbb1cc6..d2d53d993 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -50,7 +50,7 @@ runnableExamples: import std/private/since -import math +import std/math type Deque*[T] = object @@ -120,7 +120,7 @@ template xBoundsCheck(deq, i) = raise newException(IndexDefect, "Out of bounds: " & $i & " < 0") -proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = +proc `[]`*[T](deq: Deque[T], i: Natural): lent T {.inline.} = ## Accesses the `i`-th element of `deq`. runnableExamples: let a = [10, 20, 30, 40, 50].toDeque @@ -142,7 +142,7 @@ proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} = xBoundsCheck(deq, i) return deq.data[(deq.head + i) and deq.mask] -proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = +proc `[]=`*[T](deq: var Deque[T], i: Natural, val: sink T) {.inline.} = ## Sets the `i`-th element of `deq` to `val`. runnableExamples: var a = [10, 20, 30, 40, 50].toDeque @@ -154,7 +154,7 @@ proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = xBoundsCheck(deq, i) deq.data[(deq.head + i) and deq.mask] = val -proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = +proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): lent T {.inline.} = ## Accesses the backwards indexed `i`-th element. ## ## `deq[^1]` is the last element. @@ -180,7 +180,7 @@ proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} = xBoundsCheck(deq, deq.len - int(i)) return deq[deq.len - int(i)] -proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = +proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: sink T) {.inline.} = ## Sets the backwards indexed `i`-th element of `deq` to `x`. ## ## `deq[^1]` is the last element. @@ -194,7 +194,7 @@ proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = xBoundsCheck(deq, deq.len - int(i)) deq[deq.len - int(i)] = x -iterator items*[T](deq: Deque[T]): T = +iterator items*[T](deq: Deque[T]): lent T = ## Yields every element of `deq`. ## ## **See also:** @@ -270,7 +270,7 @@ proc expandIfNeeded[T](deq: var Deque[T]) = deq.tail = deq.count deq.head = 0 -proc addFirst*[T](deq: var Deque[T], item: T) = +proc addFirst*[T](deq: var Deque[T], item: sink T) = ## Adds an `item` to the beginning of `deq`. ## ## **See also:** @@ -286,7 +286,7 @@ proc addFirst*[T](deq: var Deque[T], item: T) = deq.head = (deq.head - 1) and deq.mask deq.data[deq.head] = item -proc addLast*[T](deq: var Deque[T], item: T) = +proc addLast*[T](deq: var Deque[T], item: sink T) = ## Adds an `item` to the end of `deq`. ## ## **See also:** @@ -302,7 +302,7 @@ proc addLast*[T](deq: var Deque[T], item: T) = deq.data[deq.tail] = item deq.tail = (deq.tail + 1) and deq.mask -proc peekFirst*[T](deq: Deque[T]): T {.inline.} = +proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} = ## Returns the first element of `deq`, but does not remove it from the deque. ## ## **See also:** @@ -317,7 +317,7 @@ proc peekFirst*[T](deq: Deque[T]): T {.inline.} = emptyCheck(deq) result = deq.data[deq.head] -proc peekLast*[T](deq: Deque[T]): T {.inline.} = +proc peekLast*[T](deq: Deque[T]): lent T {.inline.} = ## Returns the last element of `deq`, but does not remove it from the deque. ## ## **See also:** diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim index 99208d4cf..03e951fce 100644 --- a/tests/stdlib/tdeques.nim +++ b/tests/stdlib/tdeques.nim @@ -1,8 +1,11 @@ discard """ - targets: "c js" + matrix: "--gc:refc; --gc:orc" + targets: "c cpp js" """ import std/deques +from std/sequtils import toSeq + block: proc index(self: Deque[int], idx: Natural): int = @@ -125,7 +128,7 @@ block: foo(1, 5) foo(3, 2) -import sets +import std/sets block t13310: proc main() = @@ -137,3 +140,49 @@ block t13310: static: main() + + +proc main() = + block: + let a = [10, 20, 30].toDeque + doAssert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)] + + block: + let q = [7, 9].toDeque + doAssert 7 in q + doAssert q.contains(7) + doAssert 8 notin q + + block: + let a = [10, 20, 30, 40, 50].toDeque + doAssert $a == "[10, 20, 30, 40, 50]" + doAssert a.peekFirst == 10 + doAssert len(a) == 5 + + block: + let a = [10, 20, 30, 40, 50].toDeque + doAssert $a == "[10, 20, 30, 40, 50]" + doAssert a.peekLast == 50 + doAssert len(a) == 5 + + block: + var a = [10, 20, 30, 40, 50].toDeque + doAssert $a == "[10, 20, 30, 40, 50]" + doAssert a.popFirst == 10 + doAssert $a == "[20, 30, 40, 50]" + + block: + var a = [10, 20, 30, 40, 50].toDeque + doAssert $a == "[10, 20, 30, 40, 50]" + doAssert a.popLast == 50 + doAssert $a == "[10, 20, 30, 40]" + + block: + var a = [10, 20, 30, 40, 50].toDeque + doAssert $a == "[10, 20, 30, 40, 50]" + clear(a) + doAssert len(a) == 0 + + +static: main() +main() From a7d6ba45260d9fee3bdc2761fa67bcd114edac7f Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 8 Apr 2021 01:54:28 +0800 Subject: [PATCH 2377/4254] minor typos (#17668) --- compiler/semparallel.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index b5b0be91b..f696f6a0a 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -460,10 +460,10 @@ proc transformSpawn(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier: result = n proc checkArgs(a: var AnalysisCtx; n: PNode) = - discard "too implement" + discard "to implement" proc generateAliasChecks(a: AnalysisCtx; result: PNode) = - discard "too implement" + discard "to implement" proc liftParallel*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): PNode = # this needs to be called after the 'for' loop elimination From bd7807de4c7f8474b029f36b4d3527f7a03de6e4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Apr 2021 23:26:53 +0200 Subject: [PATCH 2378/4254] fixes #17647 (#17667) --- doc/hcr.rst | 2 +- lib/nimhcr.nim | 8 ++++---- lib/system/gc.nim | 20 ++++++++++---------- lib/system/gc_common.nim | 4 ++-- lib/system/gc_ms.nim | 10 +++++----- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/hcr.rst b/doc/hcr.rst index 7e9d71da3..fd4ba34d4 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -192,7 +192,7 @@ compiled with the `-d:useNimRtl` option and they will depend on both the `nimrtl` library and the `nimhcr` library which implements the hot code reloading run-time. Both libraries can be found in the `lib` folder of Nim and can be compiled into dynamic libraries to satisfy -runtime demands of the example code above. An example of compiling +runtime demands of the example code above. An example of compiling `nimhcr.nim` and `nimrtl.nim` when the source dir of Nim is installed with choosenim follows. diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 42e3266ae..2846f931b 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -209,7 +209,7 @@ when not defined(js) and (defined(hotcodereloading) or else: "so" type HcrProcGetter* = proc (libHandle: pointer, procName: cstring): pointer {.nimcall.} - HcrGcMarkerProc = proc () {.nimcall.} + HcrGcMarkerProc = proc () {.nimcall, raises: [].} HcrModuleInitializer* = proc () {.nimcall.} when defined(createNimHcr): @@ -606,7 +606,7 @@ when defined(createNimHcr): proc hcrGeneration*(): int {.nimhcr.} = generation - proc hcrMarkGlobals*() {.nimhcr, nimcall, gcsafe.} = + proc hcrMarkGlobals*() {.compilerproc, exportc, dynlib, nimcall, gcsafe.} = # This is gcsafe, because it will be registered # only in the GC of the main thread. {.gcsafe.}: @@ -648,10 +648,10 @@ elif defined(hotcodereloading) or defined(testNimHcr): proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) {.nimhcr.} - proc hcrMarkGlobals*() {.nimhcr, nimcall, gcsafe.} + proc hcrMarkGlobals*() {.raises: [], nimhcr, nimcall, gcsafe.} when declared(nimRegisterGlobalMarker): - nimRegisterGlobalMarker(hcrMarkGlobals) + nimRegisterGlobalMarker(cast[GlobalMarkerProc](hcrMarkGlobals)) else: proc hcrHasModuleChanged*(moduleHash: string): bool = diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 229b26f3c..039a627ba 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -94,7 +94,7 @@ type waZctDecRef, waPush #, waDebug - Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} + Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].} # A ref type can have a finalizer that is called before the object's # storage is freed. @@ -219,11 +219,11 @@ template gcTrace(cell, state: untyped) = when traceGC: traceCell(cell, state) # forward declarations: -proc collectCT(gch: var GcHeap) {.benign.} -proc isOnStack(p: pointer): bool {.noinline, benign.} -proc forAllChildren(cell: PCell, op: WalkOp) {.benign.} -proc doOperation(p: pointer, op: WalkOp) {.benign.} -proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} +proc collectCT(gch: var GcHeap) {.benign, raises: [].} +proc isOnStack(p: pointer): bool {.noinline, benign, raises: [].} +proc forAllChildren(cell: PCell, op: WalkOp) {.benign, raises: [].} +proc doOperation(p: pointer, op: WalkOp) {.benign, raises: [].} +proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign, raises: [].} # we need the prototype here for debugging purposes proc incRef(c: PCell) {.inline.} = @@ -636,7 +636,7 @@ proc markS(gch: var GcHeap, c: PCell) = if not containsOrIncl(gch.marked, d): forAllChildren(d, waMarkPrecise) -proc markGlobals(gch: var GcHeap) = +proc markGlobals(gch: var GcHeap) {.raises: [].} = if gch.gcThreadId == 0: for i in 0 .. globalMarkersLen-1: globalMarkers[i]() for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() @@ -691,9 +691,9 @@ proc doOperation(p: pointer, op: WalkOp) = proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = doOperation(d, WalkOp(op)) -proc collectZCT(gch: var GcHeap): bool {.benign.} +proc collectZCT(gch: var GcHeap): bool {.benign, raises: [].} -proc collectCycles(gch: var GcHeap) = +proc collectCycles(gch: var GcHeap) {.raises: [].} = when hasThreadSupport: for c in gch.toDispose: nimGCunref(c) @@ -800,7 +800,7 @@ proc unmarkStackAndRegisters(gch: var GcHeap) = decRef(d[i]) gch.decStack.len = 0 -proc collectCTBody(gch: var GcHeap) = +proc collectCTBody(gch: var GcHeap) {.raises: [].} = when withRealTime: let t0 = getticks() sysAssert(allocInv(gch.region), "collectCT: begin") diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 7596de6fb..ea8857ece 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -415,7 +415,7 @@ else: # end of non-portable code # ---------------------------------------------------------------------------- -proc prepareDealloc(cell: PCell) = +proc prepareDealloc(cell: PCell) {.raises: [].} = when declared(useMarkForDebug): when useMarkForDebug: gcAssert(cell notin gch.marked, "Cell still alive!") @@ -458,7 +458,7 @@ proc deallocHeap*(runFinalizers = true; allowGcAfterwards = true) = initGC() type - GlobalMarkerProc = proc () {.nimcall, benign.} + GlobalMarkerProc = proc () {.nimcall, benign, raises: [].} var globalMarkersLen {.exportc.}: int globalMarkers {.exportc.}: array[0..3499, GlobalMarkerProc] diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 852f5d7aa..b4221f7fd 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -36,7 +36,7 @@ type # local waMarkPrecise # fast precise marking - Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} + Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].} # A ref type can have a finalizer that is called before the object's # storage is freed. @@ -115,10 +115,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0: {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".} # forward declarations: -proc collectCT(gch: var GcHeap; size: int) {.benign.} -proc forAllChildren(cell: PCell, op: WalkOp) {.benign.} -proc doOperation(p: pointer, op: WalkOp) {.benign.} -proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} +proc collectCT(gch: var GcHeap; size: int) {.benign, raises: [].} +proc forAllChildren(cell: PCell, op: WalkOp) {.benign, raises: [].} +proc doOperation(p: pointer, op: WalkOp) {.benign, raises: [].} +proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign, raises: [].} # we need the prototype here for debugging purposes when defined(nimGcRefLeak): From 643dbc743bf6436cdc659ae57e2841e125aaa9de Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 8 Apr 2021 00:54:47 +0200 Subject: [PATCH 2379/4254] use strstr for a faster find implementation (#17672) * use strstr for a faster find implementation * stress the -d:release and -d:danger switches --- doc/tut1.rst | 7 ++++++- lib/pure/strutils.nim | 29 ++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index d2d6f8fe7..cca4e8c0e 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -67,6 +67,11 @@ aiming for your debugging pleasure. With `-d:release` some checks are `turned off and optimizations are turned on `_. +For benchmarking or production code, use the `-d:release` switch. +For comparing the performance with unsafe languages like C, use the `-d:danger` switch +in order to get meaningful, comparable results. Otherwise Nim might be handicapped +by checks that are **not even available** for C. + Though it should be pretty obvious what the program does, I will explain the syntax: statements which are not indented are executed when the program starts. Indentation is Nim's way of grouping statements. Indentation is @@ -626,7 +631,7 @@ Some terminology: in the example `question` is called a (formal) *parameter*, Result variable --------------- A procedure that returns a value has an implicit `result` variable declared -that represents the return value. A `return` statement with no expression is +that represents the return value. A `return` statement with no expression is shorthand for `return result`. The `result` value is always returned automatically at the end of a procedure if there is no `return` statement at the exit. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 3680b11de..bfd53a3a0 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1826,6 +1826,9 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. when not (defined(js) or defined(nimdoc) or defined(nimscript)): func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. importc: "memchr", header: "".} + func c_strstr(haystack, needle: cstring): cstring {. + importc: "strstr", header: "".} + const hasCStringBuiltin = true else: const hasCStringBuiltin = false @@ -1889,9 +1892,29 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, ## * `replace func<#replace,string,string,string>`_ if sub.len > s.len: return -1 if sub.len == 1: return find(s, sub[0], start, last) - var a {.noinit.}: SkipTable - initSkipTable(a, sub) - result = find(a, s, sub, start, last) + + template useSkipTable {.dirty.} = + var a {.noinit.}: SkipTable + initSkipTable(a, sub) + result = find(a, s, sub, start, last) + + when not hasCStringBuiltin: + useSkipTable() + else: + when nimvm: + useSkipTable() + else: + when hasCStringBuiltin: + if last == 0 and s.len > start: + let found = c_strstr(s[start].unsafeAddr, sub) + if not found.isNil: + result = cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) + else: + result = -1 + else: + useSkipTable() + else: + useSkipTable() func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, extern: "nsuRFindChar".} = From 1b03accac78632897065ecfef40a6e40d8dfe328 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 8 Apr 2021 14:08:58 +0200 Subject: [PATCH 2380/4254] Improve endians module (#17674) Extend documentation Add runnableExamples --- lib/pure/endians.nim | 49 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim index 29fde1c80..a0dc97c1d 100644 --- a/lib/pure/endians.nim +++ b/lib/pure/endians.nim @@ -10,6 +10,11 @@ ## This module contains helpers that deal with different byte orders ## (`endian`:idx:). ## +## Endianess is the order of bytes of a value in memory. Big-endian means that +## the most significant byte is stored at the smallest memory address, +## while little endian means that the least-significant byte is stored +## at the smallest address. See also https://en.wikipedia.org/wiki/Endianness. +## ## Unstable API. when defined(gcc) or defined(llvm_gcc) or defined(clang): @@ -47,7 +52,7 @@ else: when useBuiltinSwap: template swapOpImpl(T: typedesc, op: untyped) = - ## We have to use `copyMem` here instead of a simple deference because they + ## We have to use `copyMem` here instead of a simple dereference because they ## may point to a unaligned address. A sufficiently smart compiler _should_ ## be able to elide them when they're not necessary. var tmp: T @@ -56,18 +61,40 @@ when useBuiltinSwap: copyMem(outp, addr tmp, sizeof(T)) proc swapEndian64*(outp, inp: pointer) {.inline, noSideEffect.} = + ## Copies `inp` to `outp`, reversing the byte order. + ## Both buffers are supposed to contain at least 8 bytes. + runnableExamples: + var a = [1'u8, 2, 3, 4, 5, 6, 7, 8] + var b: array[8, uint8] + swapEndian64(addr b, addr a) + assert b == [8'u8, 7, 6, 5, 4, 3, 2, 1] + swapOpImpl(uint64, builtin_bswap64) proc swapEndian32*(outp, inp: pointer) {.inline, noSideEffect.} = + ## Copies `inp` to `outp`, reversing the byte order. + ## Both buffers are supposed to contain at least 4 bytes. + runnableExamples: + var a = [1'u8, 2, 3, 4] + var b: array[4, uint8] + swapEndian32(addr b, addr a) + assert b == [4'u8, 3, 2, 1] + swapOpImpl(uint32, builtin_bswap32) proc swapEndian16*(outp, inp: pointer) {.inline, noSideEffect.} = + ## Copies `inp` to `outp`, reversing the byte order. + ## Both buffers are supposed to contain at least 2 bytes. + runnableExamples: + var a = [1'u8, 2] + var b: array[2, uint8] + swapEndian16(addr b, addr a) + assert b == [2'u8, 1] + swapOpImpl(uint16, builtin_bswap16) else: proc swapEndian64*(outp, inp: pointer) = - ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to - ## contain at least 8 bytes. var i = cast[cstring](inp) var o = cast[cstring](outp) o[0] = i[7] @@ -80,8 +107,6 @@ else: o[7] = i[0] proc swapEndian32*(outp, inp: pointer) = - ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to - ## contain at least 4 bytes. var i = cast[cstring](inp) var o = cast[cstring](outp) o[0] = i[3] @@ -90,8 +115,6 @@ else: o[3] = i[0] proc swapEndian16*(outp, inp: pointer) = - ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to - ## contain at least 2 bytes. var i = cast[cstring](inp) var o = cast[cstring](outp) o[0] = i[1] @@ -106,8 +129,20 @@ when system.cpuEndian == bigEndian: proc bigEndian16*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2) else: proc littleEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8) + ## Copies `inp` to `outp`, storing it in 64-bit little-endian order. + ## Both buffers are supposed to contain at least 8 bytes. proc littleEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4) + ## Copies `inp` to `outp`, storing it in 32-bit little-endian order. + ## Both buffers are supposed to contain at least 4 bytes. proc littleEndian16*(outp, inp: pointer){.inline.} = copyMem(outp, inp, 2) + ## Copies `inp` to `outp`, storing it in 16-bit little-endian order. + ## Both buffers are supposed to contain at least 2 bytes. proc bigEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp) + ## Copies `inp` to `outp`, storing it in 64-bit big-endian order. + ## Both buffers are supposed to contain at least 8 bytes. proc bigEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp) + ## Copies `inp` to `outp`, storing it in 32-bit big-endian order. + ## Both buffers are supposed to contain at least 4 bytes. proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp) + ## Copies `inp` to `outp`, storing it in 16-bit big-endian order. + ## Both buffers are supposed to contain at least 2 bytes. From 4d3f9d3536e84d756f15b708177f289417dca3d2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 8 Apr 2021 17:46:51 +0200 Subject: [PATCH 2381/4254] manual: minor improvements (#17677) * manual: minor improvements * Update doc/manual.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- doc/manual.rst | 94 +++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 3c71ece95..aad8034c8 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -222,7 +222,7 @@ comment: `Documentation comments`:idx: are comments that start with two `##`. Documentation comments are tokens; they are only allowed at certain places in -the input file as they belong to the syntax tree! +the input file as they belong to the syntax tree. Multiline comments @@ -315,8 +315,8 @@ it was not case-sensitive and underscores were ignored and there was not even a distinction between `foo` and `Foo`. -Stropping ---------- +Keywords as identifiers +----------------------- If a keyword is enclosed in backticks it loses its keyword property and becomes an ordinary identifier. @@ -326,12 +326,12 @@ Examples var `var` = "Hello Stropping" .. code-block:: nim - type Type = object - `int`: int + type Obj = object + `type`: int - let `object` = Type(`int`: 9) - assert `object` is Type - assert `object`.`int` == 9 + let `object` = Obj(`type`: 9) + assert `object` is Obj + assert `object`.`type` == 9 var `var` = 42 let `let` = 8 @@ -442,7 +442,7 @@ Terminal symbols in the grammar: `GENERALIZED_STR_LIT`, The construct `identifier"string literal"` (without whitespace between the identifier and the opening quotation mark) is a generalized raw string literal. It is a shortcut for the construct -`identifier(r"string literal")`, so it denotes a procedure call with a +`identifier(r"string literal")`, so it denotes a routine call with a raw string literal as its only argument. Generalized raw string literals are especially convenient for embedding mini languages directly into Nim (for example regular expressions). @@ -457,8 +457,8 @@ Character literals Character literals are enclosed in single quotes `''` and can contain the same escape sequences as strings - with one exception: the platform dependent `newline`:idx: (``\p``) -is not allowed as it may be wider than one character (often it is the pair -CR/LF for example). Here are the valid `escape sequences`:idx: for character +is not allowed as it may be wider than one character (it can be the pair +CR/LF). Here are the valid `escape sequences`:idx: for character literals: ================== =================================================== @@ -482,19 +482,21 @@ literals: exactly two hex digits are allowed ================== =================================================== -A character is not a Unicode character but a single byte. The reason for this -is efficiency: for the overwhelming majority of use-cases, the resulting -programs will still handle UTF-8 properly as UTF-8 was specially designed for -this. Another reason is that Nim can thus support `array[char, int]` or -`set[char]` efficiently as many algorithms rely on this feature. The `Rune` -type is used for Unicode characters, it can represent any Unicode character. +A character is not a Unicode character but a single byte. + +Rationale: It enables the efficient support of `array[char, int]` or +`set[char]`. + +The `Rune` type can represent any Unicode character. `Rune` is declared in the `unicode module `_. A character literal that does not end in ``'`` is interpreted as ``'`` if there is a preceeding backtick token. There must be no whitespace between the preceeding -backtick token and the character literal. This special rule ensures that a declaration -like ``proc `'customLiteral`(s: string)`` is valid. See also -`Custom Numeric Literals <#custom-numeric-literals>`_. +backtick token and the character literal. This special case ensures that a declaration +like ``proc `'customLiteral`(s: string)`` is valid. ``proc `'customLiteral`(s: string)`` +is the same as ``proc `'\''customLiteral`(s: string)``. + +See also `Custom Numeric Literals <#custom-numeric-literals>`_. Numeric Literals @@ -908,37 +910,37 @@ constant expressions that may be surprising to those coming from other statically typed languages. For example, the following code echoes the beginning of the Fibonacci series **at compile-time**. (This is a demonstration of flexibility in defining constants, not a recommended style for solving this -problem!) +problem.) .. code-block:: nim :test: "nim c $1" import std/strformat - var fib_n {.compileTime.}: int - var fib_prev {.compileTime.}: int - var fib_prev_prev {.compileTime.}: int + var fibN {.compileTime.}: int + var fibPrev {.compileTime.}: int + var fibPrevPrev {.compileTime.}: int - proc next_fib(): int = - result = if fib_n < 2: - fib_n + proc nextFib(): int = + result = if fibN < 2: + fibN else: - fib_prev_prev + fib_prev - inc(fib_n) - fib_prev_prev = fib_prev - fib_prev = result + fibPrevPrev + fibPrev + inc(fibN) + fibPrevPrev = fibPrev + fibPrev = result - const f0 = next_fib() - const f1 = next_fib() + const f0 = nextFib() + const f1 = nextFib() - const display_fib = block: - const f2 = next_fib() + const displayFib = block: + const f2 = nextFib() var result = fmt"Fibonacci sequence: {f0}, {f1}, {f2}" for i in 3..12: - add(result, fmt", {next_fib()}") + add(result, fmt", {nextFib()}") result static: - echo display_fib + echo displayFib Restrictions on Compile-Time Execution @@ -1013,7 +1015,9 @@ intXX Literals of these types have the suffix 'iXX. `uint` - the generic `unsigned integer`:idx: type; its size is platform-dependent and has the same size as a pointer. An integer literal with the type suffix `'u` is of this type. + the generic `unsigned integer`:idx: type; its size is platform-dependent and + has the same size as a pointer. An integer literal with the type + suffix `'u` is of this type. uintXX additional unsigned integer types of XX bits use this naming scheme @@ -1199,12 +1203,8 @@ Character type -------------- The character type is named `char` in Nim. Its size is one byte. Thus it cannot represent a UTF-8 character, but a part of it. -The reason for this is efficiency: for the overwhelming majority of use-cases, -the resulting programs will still handle UTF-8 properly as UTF-8 was especially -designed for this. -Another reason is that Nim can support `array[char, int]` or -`set[char]` efficiently as many algorithms rely on this feature. The -`Rune` type is used for Unicode characters, it can represent any Unicode + +The `Rune` type is used for Unicode characters, it can represent any Unicode character. `Rune` is declared in the `unicode module `_. @@ -1232,7 +1232,7 @@ Now the following holds:: # Also allowed: ord(Direction.west) == 3 -Thus, north < east < south < west. The comparison operators can be used +The implied order is: north < east < south < west. The comparison operators can be used with enumeration types. Instead of `north` etc, the enum value can also be qualified with the enum type that it resides in, `Direction.north`. @@ -1248,7 +1248,7 @@ An explicit ordered enum can have *holes*: TokenType = enum a = 2, b = 4, c = 89 # holes are valid -However, it is then not ordinal anymore, so it is not possible to use these +However, it is then not ordinal anymore, so it is impossible to use these enums as an index type for arrays. The procedures `inc`, `dec`, `succ` and `pred` are not available for them either. @@ -7885,4 +7885,4 @@ Threads and exceptions The interaction between threads and exceptions is simple: A *handled* exception in one thread cannot affect any other thread. However, an *unhandled* exception -in one thread terminates the whole *process*! +in one thread terminates the whole *process*. From 42687457b079c16f69b22ff2354590780bd4cf45 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 8 Apr 2021 20:00:14 +0300 Subject: [PATCH 2382/4254] further progress on rst roles & directives (fix #17646) (#17659) * further progress on rst roles & dir-s (fix #17646) * fix documents according to the messages * fix bug 17 from #17340 --- doc/manual_experimental.rst | 2 +- lib/experimental/diff.nim | 4 +- lib/packages/docutils/highlite.nim | 4 +- lib/packages/docutils/rst.nim | 110 ++++++++++++++++++++--------- lib/pure/asyncdispatch.nim | 2 +- lib/pure/asyncftpclient.nim | 6 +- lib/pure/asynchttpserver.nim | 2 +- lib/pure/asyncnet.nim | 2 +- lib/pure/base64.nim | 8 +-- lib/pure/dynlib.nim | 2 +- lib/system/iterators.nim | 2 +- tests/stdlib/trstgen.nim | 36 ++++++++++ 12 files changed, 129 insertions(+), 51 deletions(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index fc46a2a14..51037b509 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -330,7 +330,7 @@ Routines with the same type signature can be called differently if a parameter has different names. This does not need an `experimental` switch, but is an unstable feature. -.. code-block::nim +.. code-block:: Nim proc foo(x: int) = echo "Using x: ", x proc foo(y: int) = diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim index 3462a0fa4..ba4e8ad64 100644 --- a/lib/experimental/diff.nim +++ b/lib/experimental/diff.nim @@ -12,14 +12,14 @@ ## ## A basic example of `diffInt` on 2 arrays of integers: ## -## .. code::nim +## .. code:: Nim ## ## import experimental/diff ## echo diffInt([0, 1, 2, 3, 4, 5, 6, 7, 8], [-1, 1, 2, 3, 4, 5, 666, 7, 42]) ## ## Another short example of `diffText` to diff strings: ## -## .. code::nim +## .. code:: Nim ## ## import experimental/diff ## # 2 samples of text for testing (from "The Call of Cthulhu" by Lovecraft) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 2655a7ea3..94cb2ebde 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -13,7 +13,7 @@ ## ## You can use this to build your own syntax highlighting, check this example: ## -## .. code::nim +## .. code:: Nim ## let code = """for x in $int.high: echo x.ord mod 2 == 0""" ## var toknizr: GeneralTokenizer ## initGeneralTokenizer(toknizr, code) @@ -34,7 +34,7 @@ ## ## The proc `getSourceLanguage` can get the language `enum` from a string: ## -## .. code::nim +## .. code:: Nim ## for l in ["C", "c++", "jAvA", "Nim", "c#"]: echo getSourceLanguage(l) ## diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index dfa2f12be..a8bc04a1a 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -912,6 +912,38 @@ template newLeaf(s: string): PRstNode = newRstLeaf(s) proc newLeaf(p: var RstParser): PRstNode = result = newLeaf(currentTok(p).symbol) +proc validRefnamePunct(x: string): bool = + ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names + x.len == 1 and x[0] in {'-', '_', '.', ':', '+'} + +func getRefnameIdx(p: RstParser, startIdx: int): int = + ## Gets last token index of a refname ("word" in RST terminology): + ## + ## reference names are single words consisting of alphanumerics plus + ## isolated (no two adjacent) internal hyphens, underscores, periods, + ## colons and plus signs; no whitespace or other characters are allowed. + ## + ## Refnames are used for: + ## - reference names + ## - role names + ## - directive names + ## - footnote labels + ## + # TODO: use this func in all other relevant places + var j = startIdx + if p.tok[j].kind == tkWord: + inc j + while p.tok[j].kind == tkPunct and validRefnamePunct(p.tok[j].symbol) and + p.tok[j+1].kind == tkWord: + inc j, 2 + result = j - 1 + +func getRefname(p: RstParser, startIdx: int): (string, int) = + let lastIdx = getRefnameIdx(p, startIdx) + result[1] = lastIdx + for j in startIdx..lastIdx: + result[0].add p.tok[j].symbol + proc getReferenceName(p: var RstParser, endStr: string): PRstNode = var res = newRstNode(rnInner) while true: @@ -1011,7 +1043,10 @@ proc match(p: RstParser, start: int, expr: string): bool = var last = expr.len - 1 while i <= last: case expr[i] - of 'w': result = p.tok[j].kind == tkWord + of 'w': + let lastIdx = getRefnameIdx(p, j) + result = lastIdx >= j + if result: j = lastIdx of ' ': result = p.tok[j].kind == tkWhite of 'i': result = p.tok[j].kind == tkIndent of 'I': result = p.tok[j].kind in {tkIndent, tkEof} @@ -1058,7 +1093,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) = proc whichRole(p: RstParser, sym: string): RstNodeKind = result = whichRoleAux(sym) if result == rnUnknownRole: - rstMessage(p, mwUnsupportedLanguage, p.s.currRole) + rstMessage(p, mwUnsupportedLanguage, sym) proc toInlineCode(n: PRstNode, language: string): PRstNode = ## Creates rnInlineCode and attaches `n` contents as code (in 3rd son). @@ -1078,6 +1113,11 @@ proc toInlineCode(n: PRstNode, language: string): PRstNode = lb.add newLeaf(s) result.add lb +proc toUnknownRole(n: PRstNode, roleName: string): PRstNode = + let newN = newRstNode(rnInner, n.sons) + let newSons = @[newN, newLeaf(roleName)] + result = newRstNode(rnUnknownRole, newSons) + proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var newKind = n.kind var newSons = n.sons @@ -1102,17 +1142,15 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = result = newRstNode(newKind, newSons) elif match(p, p.idx, ":w:"): # a role: - let roleName = nextTok(p).symbol + let (roleName, lastIdx) = getRefname(p, p.idx+1) newKind = whichRole(p, roleName) if newKind == rnUnknownRole: - let newN = newRstNode(rnInner, n.sons) - newSons = @[newN, newLeaf(roleName)] - result = newRstNode(newKind, newSons) + result = n.toUnknownRole(roleName) elif newKind == rnInlineCode: result = n.toInlineCode(language=roleName) else: result = newRstNode(newKind, newSons) - inc p.idx, 3 + p.idx = lastIdx + 2 else: if p.s.currRoleKind == rnInlineCode: result = n.toInlineCode(language=p.s.currRole) @@ -1139,10 +1177,6 @@ proc parseSmiley(p: var RstParser): PRstNode = result.text = val return -proc validRefnamePunct(x: string): bool = - ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names - x.len == 1 and x[0] in {'-', '_', '.', ':', '+'} - proc isUrl(p: RstParser, i: int): bool = result = p.tok[i+1].symbol == ":" and p.tok[i+2].symbol == "//" and p.tok[i+3].kind == tkWord and @@ -1373,14 +1407,18 @@ proc parseInline(p: var RstParser, father: PRstNode) = var n = newRstNode(rnInlineLiteral) parseUntil(p, n, "``", false) father.add(n) - elif match(p, p.idx, ":w:") and p.tok[p.idx+3].symbol == "`": - let roleName = nextTok(p).symbol + elif match(p, p.idx, ":w:") and + (var lastIdx = getRefnameIdx(p, p.idx + 1); + p.tok[lastIdx+2].symbol == "`"): + let (roleName, _) = getRefname(p, p.idx+1) let k = whichRole(p, roleName) var n = newRstNode(k) - inc p.idx, 3 + p.idx = lastIdx + 2 if k == rnInlineCode: n = n.toInlineCode(language=roleName) parseUntil(p, n, "`", false) # bug #17260 + if k == rnUnknownRole: + n = n.toUnknownRole(roleName) father.add(n) elif isInlineMarkupStart(p, "`"): var n = newRstNode(rnInterpretedText) @@ -1438,25 +1476,28 @@ proc parseInline(p: var RstParser, father: PRstNode) = else: discard proc getDirective(p: var RstParser): string = - if currentTok(p).kind == tkWhite and nextTok(p).kind == tkWord: - var j = p.idx - inc p.idx - result = currentTok(p).symbol - inc p.idx - while currentTok(p).kind in {tkWord, tkPunct, tkAdornment, tkOther}: - if currentTok(p).symbol == "::": break - result.add(currentTok(p).symbol) - inc p.idx - if currentTok(p).kind == tkWhite: inc p.idx - if currentTok(p).symbol == "::": - inc p.idx - if currentTok(p).kind == tkWhite: inc p.idx - else: - p.idx = j # set back - result = "" # error - else: - result = "" - result = result.toLowerAscii() + result = "" + if currentTok(p).kind == tkWhite: + let (name, lastIdx) = getRefname(p, p.idx + 1) + let afterIdx = lastIdx + 1 + if name.len > 0: + if p.tok[afterIdx].symbol == "::": + result = name + p.idx = afterIdx + 1 + if currentTok(p).kind == tkWhite: + inc p.idx + elif currentTok(p).kind != tkIndent: + rstMessage(p, mwRstStyle, + "whitespace or newline expected after directive " & name) + result = result.toLowerAscii() + elif p.tok[afterIdx].symbol == ":": + rstMessage(p, mwRstStyle, + "double colon :: may be missing at end of '" & name & "'", + p.tok[afterIdx].line, p.tok[afterIdx].col) + elif p.tok[afterIdx].kind == tkPunct and p.tok[afterIdx].symbol[0] == ':': + rstMessage(p, mwRstStyle, + "too many colons for a directive (should be ::)", + p.tok[afterIdx].line, p.tok[afterIdx].col) proc parseComment(p: var RstParser): PRstNode = case currentTok(p).kind @@ -1711,7 +1752,8 @@ proc whichSection(p: RstParser): RstNodeKind = return rnCodeBlock elif currentTok(p).symbol == "::": return rnLiteralBlock - elif currentTok(p).symbol == ".." and predNL(p): + elif currentTok(p).symbol == ".." and predNL(p) and + nextTok(p).kind in {tkWhite, tkIndent}: return rnDirective case currentTok(p).kind of tkAdornment: diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 55a20270d..3866ebd24 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -42,7 +42,7 @@ ## ## Code to read some data from a socket may look something like this: ## -## .. code-block::nim +## .. code-block:: Nim ## var future = socket.recv(100) ## future.addCallback( ## proc () = diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 0ee45785d..056d65564 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -21,7 +21,7 @@ ## In order to begin any sort of transfer of files you must first ## connect to an FTP server. You can do so with the `connect` procedure. ## -## .. code-block::nim +## .. code-block:: Nim ## import std/[asyncdispatch, asyncftpclient] ## proc main() {.async.} = ## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") @@ -41,7 +41,7 @@ ## working directory before you do so with the `pwd` procedure, you can also ## instead specify an absolute path. ## -## .. code-block::nim +## .. code-block:: Nim ## import std/[asyncdispatch, asyncftpclient] ## proc main() {.async.} = ## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") @@ -62,7 +62,7 @@ ## Procs that take an `onProgressChanged` callback will call this every ## `progressInterval` milliseconds. ## -## .. code-block::nim +## .. code-block:: Nim ## import std/[asyncdispatch, asyncftpclient] ## ## proc onProgressChanged(total, progress: BiggestInt, diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 3982edc54..fd0cad5ca 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -108,7 +108,7 @@ proc respond*(req: Request, code: HttpCode, content: string, ## ## Example: ## - ## .. code-block::nim + ## .. code-block:: Nim ## import std/json ## proc handler(req: Request) {.async.} = ## if req.url.path == "/hello-world": diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 7aeb99777..7ef40a128 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -65,7 +65,7 @@ ## ## The following example demonstrates a simple chat server. ## -## .. code-block::nim +## .. code-block:: Nim ## ## import std/[asyncnet, asyncdispatch] ## diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index bf196b54d..d5c1fda7a 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -23,14 +23,14 @@ ## Encoding data ## ------------- ## -## .. code-block::nim +## .. code-block:: Nim ## import std/base64 ## let encoded = encode("Hello World") ## assert encoded == "SGVsbG8gV29ybGQ=" ## ## Apart from strings you can also encode lists of integers or characters: ## -## .. code-block::nim +## .. code-block:: Nim ## import std/base64 ## let encodedInts = encode([1,2,3]) ## assert encodedInts == "AQID" @@ -41,7 +41,7 @@ ## Decoding data ## ------------- ## -## .. code-block::nim +## .. code-block:: Nim ## import std/base64 ## let decoded = decode("SGVsbG8gV29ybGQ=") ## assert decoded == "Hello World" @@ -49,7 +49,7 @@ ## URL Safe Base64 ## --------------- ## -## .. code-block::nim +## .. code-block:: Nim ## import std/base64 ## doAssert encode("c\xf7>", safe = true) == "Y_c-" ## doAssert encode("c\xf7>", safe = false) == "Y/c+" diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index 3e1d84729..a1a94072c 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -22,7 +22,7 @@ ## If the library fails to load or the function 'greet' is not found, ## it quits with a failure error code. ## -## .. code-block::nim +## .. code-block:: Nim ## ## import std/dynlib ## diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 86d64d0c7..0f79970b8 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -304,7 +304,7 @@ iterator fieldPairs*[T: tuple|object](x: T): tuple[key: string, val: RootObj] {. ## picking the appropriate code to a secondary proc which you overload for ## each field type and pass the `value` to. ## - ## .. warning::: This really transforms the 'for' and unrolls the loop. The + ## .. warning:: This really transforms the 'for' and unrolls the loop. The ## current implementation also has a bug that affects symbol binding in the ## loop body. runnableExamples: diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 99b8d8db5..b403d96c6 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -136,6 +136,25 @@ suite "YAML syntax highlighting": not numbers: [ 42e, 0023, +32.37, 8 ball] }
    """ + test "Directives: warnings": + let input = dedent""" + .. non-existant-warning: Paragraph. + + .. another.wrong:warning::: Paragraph. + """ + var warnings = new seq[string] + let output = input.toHtml(warnings=warnings) + check output == "" + doAssert warnings[].len == 2 + check "(1, 24) Warning: RST style:" in warnings[0] + check "double colon :: may be missing at end of 'non-existant-warning'" in warnings[0] + check "(3, 25) Warning: RST style:" in warnings[1] + check "RST style: too many colons for a directive (should be ::)" in warnings[1] + + test "not a directive": + let input = "..warning:: I am not a warning." + check input.toHtml == input + test "Anchors, Aliases, Tags": let input = """.. code-block:: yaml --- !!map @@ -1403,6 +1422,23 @@ Test1 check """`3`:sup:\ He is an isotope of helium.""".toHtml == expected check """`3`:superscript:\ He is an isotope of helium.""".toHtml == expected + test "Roles: warnings": + let input = dedent""" + See function :py:func:`spam`. + + See also `egg`:py:class:. + """ + var warnings = new seq[string] + let output = input.toHtml(warnings=warnings) + doAssert warnings[].len == 2 + check "(1, 14) Warning: " in warnings[0] + check "language 'py:func' not supported" in warnings[0] + check "(3, 15) Warning: " in warnings[1] + check "language 'py:class' not supported" in warnings[1] + check("""

    See function spam.

    """ & "\n" & + """

    See also egg.

    """ & "\n" == + output) + test "(not) Roles: check escaping 1": let expected = """See :subscript:""" & """""" & id"some" & " " & id"text" & From 9f0f4775524d6167655e089a864cd9fdbd10c806 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 8 Apr 2021 19:41:43 +0200 Subject: [PATCH 2383/4254] Update `sysrand` documentation (#17676) Co-authored-by: Andreas Rumpf --- doc/lib.rst | 8 ++++---- lib/std/sysrand.nim | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/lib.rst b/doc/lib.rst index 15b4f70d6..f09fe16b2 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -272,18 +272,18 @@ Math libraries * `random `_ Fast and tiny random number generator. -* `sysrand `_ - Cryptographically secure pseudorandom number generator. - * `rationals `_ This module implements rational numbers and relevant mathematical operations. * `stats `_ - Statistical analysis + Statistical analysis. * `sums `_ Accurate summation functions. +* `sysrand `_ + Cryptographically secure pseudorandom number generator. + Internet Protocols and Support ------------------------------ diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index c9908143c..4a2cdd10b 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -12,21 +12,21 @@ ## therefore may not be secure. ## ## `std/sysrand` generates random numbers from a secure source provided by the operating system. -## It is also called Cryptographically secure pseudorandom number generator. -## It should be unpredictable enough for cryptographic applications, +## It is a cryptographically secure pseudorandom number generator +## and should be unpredictable enough for cryptographic applications, ## though its exact quality depends on the OS implementation. ## -## | Targets | Implementation| -## | :--- | ----: | -## | Windows | `BCryptGenRandom`_ | -## | Linux | `getrandom`_ | -## | MacOSX | `getentropy`_ | -## | IOS | `SecRandomCopyBytes`_ | -## | OpenBSD | `getentropy openbsd`_ | -## | FreeBSD | `getrandom freebsd`_ | -## | JS(Web Browser) | `getRandomValues`_ | -## | Nodejs | `randomFillSync`_ | -## | Other Unix platforms | `/dev/urandom`_ | +## | Targets | Implementation | +## | :--- | ----: | +## | Windows | `BCryptGenRandom`_ | +## | Linux | `getrandom`_ | +## | MacOSX | `getentropy`_ | +## | iOS | `SecRandomCopyBytes`_ | +## | OpenBSD | `getentropy openbsd`_ | +## | FreeBSD | `getrandom freebsd`_ | +## | JS (Web Browser) | `getRandomValues`_ | +## | Node.js | `randomFillSync`_ | +## | Other Unix platforms | `/dev/urandom`_ | ## ## .. _BCryptGenRandom: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom ## .. _getrandom: https://man7.org/linux/man-pages/man2/getrandom.2.html @@ -195,7 +195,7 @@ elif defined(linux): elif defined(openbsd): proc getentropy(p: pointer, size: cint): cint {.importc: "getentropy", header: "".} - # fills a buffer with high-quality entropy, + # Fills a buffer with high-quality entropy, # which can be used as input for process-context pseudorandom generators like `arc4random`. # The maximum buffer size permitted is 256 bytes. @@ -227,7 +227,7 @@ elif defined(ios): proc secRandomCopyBytes( rnd: SecRandomRef, count: csize_t, bytes: pointer - ): cint {.importc: "SecRandomCopyBytes", header: "".} + ): cint {.importc: "SecRandomCopyBytes", header: "".} ## https://developer.apple.com/documentation/security/1399291-secrandomcopybytes template urandomImpl(result: var int, dest: var openArray[byte]) = @@ -292,7 +292,7 @@ proc urandom*(dest: var openArray[byte]): bool = ## If the call succeeds, returns `true`. ## ## If `dest` is empty, `urandom` immediately returns success, - ## without calling underlying operating system api. + ## without calling the underlying operating system API. ## ## .. warning:: The code hasn't been audited by cryptography experts and ## is provided as-is without guarantees. Use at your own risks. For production From 6ec55ebf48d2b3889cd1391fdd630e65a01c0c91 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 8 Apr 2021 20:29:11 +0200 Subject: [PATCH 2384/4254] Fix rst typo (#17671) --- lib/core/typeinfo.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 196ac8fe1..08d567351 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -11,7 +11,7 @@ ## (`RTTI`:idx:). See the `marshal `_ module for an example of ## what this allows you to do. ## -## ..note:: Even though `Any` and its operations hide the nasty low level +## .. note:: Even though `Any` and its operations hide the nasty low level ## details from its users, it remains inherently unsafe! Also, Nim's ## runtime type information will evolve and may eventually be deprecated. ## As an alternative approach to programmatically understanding and From 2ac45a4794c9d4cc99ef3b154102fd185d35714e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 9 Apr 2021 00:18:07 +0200 Subject: [PATCH 2385/4254] undocument unsupported advanced options (#17678) --- doc/advopt.txt | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 763ac80a6..4842d090e 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -43,7 +43,7 @@ Advanced options: --warning[X]:on|off turn specific warning X on|off --hints:on|off|list turn all hints on|off or list all available --hint[X]:on|off turn specific hint X on|off - --warningAsError[X]:on|off + --warningAsError[X]:on|off turn specific warning X into an error on|off --hintAsError[X]:on|off turn specific hint X into an error on|off --styleCheck:off|hint|error @@ -84,7 +84,7 @@ Advanced options: if path == @default (the default and most useful), will use best match among @pkg,@path. if these are nonexistent, will use project path - -b, --backend:c|cpp|js|objc + -b, --backend:c|cpp|js|objc sets backend to use with commands like `nim doc` or `nim r` --docCmd:cmd if `cmd == skip`, skips runnableExamples else, runs runnableExamples with given options, e.g.: @@ -95,26 +95,22 @@ Advanced options: --lineDir:on|off generation of #line directive on|off --embedsrc:on|off embeds the original source code as comments in the generated output - --threadanalysis:on|off turn thread analysis on|off --tlsEmulation:on|off turn thread local storage emulation on|off --implicitStatic:on|off turn implicit compile time evaluation on|off --trmacros:on|off turn term rewriting macros on|off --multimethods:on|off turn multi-methods on|off - --memTracker:on|off turn memory tracker on|off --hotCodeReloading:on|off turn support for hot code reloading on|off --excessiveStackTrace:on|off stack traces use full file paths --stackTraceMsgs:on|off enable user defined stack frame msgs via `setFrameMsg` - --seqsv2:on|off use the new string/seq implementation based on - destructors --skipCfg:on|off do not read the nim installation's configuration file --skipUserCfg:on|off do not read the user's configuration file --skipParentCfg:on|off do not read the parent dirs' configuration files --skipProjCfg:on|off do not read the project's configuration file --gc:refc|arc|orc|markAndSweep|boehm|go|none|regions select the GC to use; default is 'refc' - --exceptions:setjmp|cpp|goto + --exceptions:setjmp|cpp|goto|quirky select the exception handling implementation --index:on|off turn index file generation on|off --putenv:key=value set an environment variable @@ -149,11 +145,8 @@ Advanced options: --legacy:$2 enable obsolete/legacy language feature --useVersion:1.0|1.2 emulate Nim version X of the Nim compiler, for testing - --profiler:on|off enable profiling; requires `import nimprof`, and - works better with `--stackTrace:on` - see also https://nim-lang.github.io/Nim/estp.html - --benchmarkVM:on|off enable benchmarking of VM code with cpuTime() - --profileVM:on|off enable compile time VM profiler - --sinkInference:on|off en-/disable sink parameter inference (default: on) + --benchmarkVM:on|off turn benchmarking of VM code with cpuTime() on|off + --profileVM:on|off turn compile time VM profiler on|off + --sinkInference:on|off turn sink parameter inference on|off (default: on) --panics:on|off turn panics into process terminations (default: off) --deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc`` From e4b64eee894ddbf41935d3b8aeed1448cd2b5e46 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Fri, 9 Apr 2021 00:40:19 +0200 Subject: [PATCH 2386/4254] Fix small typos (#17680) --- doc/intern.rst | 2 +- lib/js/jsconsole.nim | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/intern.rst b/doc/intern.rst index 1e18d975c..3b1a48b41 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -113,7 +113,7 @@ You can import them directly for debugging: The compiler's architecture =========================== -Nim uses the classic compiler architecture: A lexer/scanner feds tokens to a +Nim uses the classic compiler architecture: A lexer/scanner feeds tokens to a parser. The parser builds a syntax tree that is used by the code generators. This syntax tree is the interface between the parser and the code generator. It is essential to understand most of the compiler's code. diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index bf43adddd..e74127334 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -118,6 +118,7 @@ since (1, 5): func timeStamp*(console: Console; label: cstring) {.importcpp.} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeStamp + ## ## ..warning:: non-standard From 13b958eb45a3569acaa18f9381d28b8f37d42057 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 9 Apr 2021 06:59:25 +0200 Subject: [PATCH 2387/4254] IC: added basic test case for methods (#17679) * IC: added basic test case for methods * IC: better methods test --- compiler/ic/cbackend.nim | 35 ++++++++++++++++++++++++++++------- compiler/ic/ic.nim | 2 +- tests/ic/mbaseobj.nim | 7 +++++++ tests/ic/tmethods.nim | 28 ++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 tests/ic/mbaseobj.nim create mode 100644 tests/ic/tmethods.nim diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index 9282ac466..2f3910b32 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -30,12 +30,16 @@ proc unpackTree(g: ModuleGraph; thisModule: int; var decoder = initPackedDecoder(g.config, g.cache) result = loadNodes(decoder, g.packed, thisModule, tree, n) -proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) = +proc setupBackendModule(g: ModuleGraph; m: var LoadedModule) = if g.backend == nil: g.backend = cgendata.newModuleList(g) - + assert g.backend != nil var bmod = cgen.newModule(BModuleList(g.backend), m.module, g.config) bmod.idgen = idgenFromLoadedModule(m) + +proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) = + var bmod = BModuleList(g.backend).modules[m.module.position] + assert bmod != nil bmod.flags.incl useAliveDataFromDce bmod.alive = move alive[m.module.position] @@ -118,6 +122,27 @@ proc generateCode*(g: ModuleGraph) = for i in 0..high(g.packed): echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i)) + # First pass: Setup all the backend modules for all the modules that have + # changed: + for i in 0..high(g.packed): + # case statement here to enforce exhaustive checks. + case g.packed[i].status + of undefined: + discard "nothing to do" + of loading, stored: + assert false + of storing, outdated: + setupBackendModule(g, g.packed[i]) + of loaded: + # Even though this module didn't change, DCE might trigger a change. + # Consider this case: Module A uses symbol S from B and B does not use + # S itself. A is then edited not to use S either. Thus we have to + # recompile B in order to remove S from the final result. + if aliveSymsChanged(g.config, g.packed[i].module.position, alive): + g.packed[i].loadedButAliveSetChanged = true + setupBackendModule(g, g.packed[i]) + + # Second pass: Code generation. for i in 0..high(g.packed): # case statement here to enforce exhaustive checks. case g.packed[i].status @@ -130,11 +155,7 @@ proc generateCode*(g: ModuleGraph) = closeRodFile(g, g.packed[i].module) storeAliveSyms(g.config, g.packed[i].module.position, alive) of loaded: - # Even though this module didn't change, DCE might trigger a change. - # Consider this case: Module A uses symbol S from B and B does not use - # S itself. A is then edited not to use S either. Thus we have to - # recompile B in order to remove S from the final result. - if aliveSymsChanged(g.config, g.packed[i].module.position, alive): + if g.packed[i].loadedButAliveSetChanged: generateCodeForModule(g, g.packed[i], alive) else: addFileToLink(g.config, g.packed[i].module) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index b5fed7d4e..46bb63e07 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -666,7 +666,7 @@ type LoadedModule* = object status*: ModuleStatus - symsInit, typesInit: bool + symsInit, typesInit, loadedButAliveSetChanged*: bool fromDisk*: PackedModule syms: seq[PSym] # indexed by itemId types: seq[PType] diff --git a/tests/ic/mbaseobj.nim b/tests/ic/mbaseobj.nim new file mode 100644 index 000000000..0f4e4a90d --- /dev/null +++ b/tests/ic/mbaseobj.nim @@ -0,0 +1,7 @@ + +type + Base* = ref object of RootObj + s*: string + +method m*(b: Base) {.base.} = + echo "Base ", b.s diff --git a/tests/ic/tmethods.nim b/tests/ic/tmethods.nim new file mode 100644 index 000000000..251f26889 --- /dev/null +++ b/tests/ic/tmethods.nim @@ -0,0 +1,28 @@ +discard """ + output: '''Base abc''' +""" + +import mbaseobj + +var c = Base(s: "abc") +m c + +#!EDIT!# + +discard """ + output: '''Base abc +Inherited abc''' +""" + +import mbaseobj + +type + Inherited = ref object of Base + +method m(i: Inherited) = + procCall m(Base i) + echo "Inherited ", i.s + +var c = Inherited(s: "abc") +m c + From 826ad2f36f34694277f624933049de2be40e0703 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 9 Apr 2021 00:09:04 -0500 Subject: [PATCH 2388/4254] nep1: guidelines for getters and setters (#17645) * nep1: guidelines for getters and setters * address a comment --- doc/nep1.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/nep1.rst b/doc/nep1.rst index bdf8e0eab..8687725bb 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -301,3 +301,12 @@ Miscellaneous let a = """foo bar """ + +- A getter API for a private field `foo` should preferably be named `foo`, not `getFoo`. + A getter-like API should preferably be named `getFoo`, not `foo` if: + * the API has side effects + * or the cost is not `O(1)` + For in between cases, there is no clear guideline. + +- Likewise with a setter API, replacing `foo` with `foo=` and `getFoo` with `setFoo` + in the above text. From cce1b24b1cc3860ff503668761d2798b1b1d1ef0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 9 Apr 2021 01:00:13 -0500 Subject: [PATCH 2389/4254] ast: add getPIdent (#17684) * ast: add getPIdent * fixup --- compiler/ast.nim | 8 ++++++++ compiler/renderer.nim | 20 +++++++++----------- compiler/reorder.nim | 7 ++----- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 7d13956e9..fffe08cb7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1054,6 +1054,14 @@ const defaultAlignment = -1 defaultOffset = -1 +proc getPIdent*(a: PNode): PIdent {.inline.} = + ## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`. + # xxx consider whether also returning the 1st ident for {nkOpenSymChoice, nkClosedSymChoice} + # which may simplify code. + case a.kind + of nkSym: a.sym.name + of nkIdent: a.ident + else: nil proc getnimblePkg*(a: PSym): PSym = result = a diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 9a867b0a1..78e2fe20e 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -964,14 +964,12 @@ proc skipHiddenNodes(n: PNode): PNode = else: break proc accentedName(g: var TSrcGen, n: PNode) = + # This is for cases where ident should've really been a `nkAccQuoted`, e.g. `:tmp` + # or if user writes a macro with `ident":foo"`. It's unclear whether these should be legal. const backticksNeeded = OpChars + {'[', '{', '\''} if n == nil: return - let isOperator = - if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in backticksNeeded: true - elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in backticksNeeded: true - else: false - - if isOperator: + let ident = n.getPIdent + if ident != nil and ident.s[0] in backticksNeeded: put(g, tkAccent, "`") gident(g, n) put(g, tkAccent, "`") @@ -999,9 +997,9 @@ proc infixArgument(g: var TSrcGen, n: PNode, i: int) = put(g, tkParRi, ")") proc isCustomLit(n: PNode): bool = - n.len == 2 and n[0].kind == nkRStrLit and - (n[1].kind == nkIdent and n[1].ident.s.startsWith('\'')) or - (n[1].kind == nkSym and n[1].sym.name.s.startsWith('\'')) + if n.len == 2 and n[0].kind == nkRStrLit: + let ident = n[1].getPIdent + result = ident != nil and ident.s.startsWith('\'') proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = if isNil(n): return @@ -1234,8 +1232,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = else: gsub(g, n, 0) put(g, tkDot, ".") - if n.len > 1: - accentedName(g, n[1]) + assert n.len == 2, $n.len + accentedName(g, n[1]) of nkBind: putWithSpace(g, tkBind, "bind") gsub(g, n, 0) diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 4ffe4ccf8..65c1fb9ee 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -36,11 +36,8 @@ proc newDepN(id: int, pnode: PNode): DepN = proc accQuoted(cache: IdentCache; n: PNode): PIdent = var id = "" for i in 0.. Date: Fri, 9 Apr 2021 02:37:10 -0500 Subject: [PATCH 2390/4254] make repr handle setters `foo=` (#17683) --- compiler/renderer.nim | 13 ++++++++----- tests/stdlib/trepr.nim | 9 +++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 78e2fe20e..b3b0adc01 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1327,13 +1327,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = of nkIdent: n.ident.s of nkSym: n.sym.name.s else: "" + proc isAlpha(n: PNode): bool = + if n.kind in {nkIdent, nkSym}: + let tmp = n.getStrVal + result = tmp.len > 0 and tmp[0] in {'a'..'z', 'A'..'Z'} var useSpace = false if i == 1 and n[0].kind == nkIdent and n[0].ident.s in ["=", "'"]: - let tmp = n[1].getStrVal - if tmp.len > 0 and tmp[0] in {'a'..'z', 'A'..'Z'}: - # handle `=destroy`, `'big' - discard - else: + if not n[1].isAlpha: # handle `=destroy`, `'big' + useSpace = true + elif i == 1 and n[1].kind == nkIdent and n[1].ident.s == "=": + if not n[0].isAlpha: # handle setters, e.g. `foo=` useSpace = true elif i > 0: useSpace = true if useSpace: put(g, tkSpaces, Space) diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 3dcbe9b69..f72bbb34e 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -163,6 +163,15 @@ proc `foo bar baz`(): int = """ doAssert a2 == a + block: # setters: `foo=` + let a = deb: + proc `foo=`() = discard + doAssert a == """ + +proc `foo=`() = + discard +""" + block: # bug #14850 block: let a = deb: From f25243140baa00db4a663d453a262e41f8d9073f Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 9 Apr 2021 17:51:51 +0800 Subject: [PATCH 2391/4254] add std/tasks (#17447) --- changelog.md | 2 + lib/std/tasks.nim | 272 +++++++++++++++++++++ tests/stdlib/ttasks.nim | 506 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 780 insertions(+) create mode 100644 lib/std/tasks.nim create mode 100644 tests/stdlib/ttasks.nim diff --git a/changelog.md b/changelog.md index 43a15e398..a2879833f 100644 --- a/changelog.md +++ b/changelog.md @@ -264,6 +264,8 @@ - Added dollar `$` and `len` for `jsre.RegExp`. +- Added `std/tasks`. + - Added `hasDataBuffered` to `asyncnet`. - Added `hasClosure` to `std/typetraits`. diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim new file mode 100644 index 000000000..6b7f86ce4 --- /dev/null +++ b/lib/std/tasks.nim @@ -0,0 +1,272 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2021 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module provides basic primitives for creating parallel programs. +## A `Task` should be only owned by a single Thread, it cannot be shared by threads. + +import std/[macros, isolation, typetraits] +import system/ansi_c + +export isolation + + +when compileOption("threads"): + from std/effecttraits import isGcSafe + + +# +# proc hello(a: int, b: string) = +# echo $a & b +# +# let literal = "Nim" +# let t = toTask(hello(521, literal)) +# +# +# is roughly converted to +# +# type +# ScratchObj_369098780 = object +# a: int +# b: string +# +# let scratch_369098762 = cast[ptr ScratchObj_369098780](c_calloc(csize_t 1, +# csize_t sizeof(ScratchObj_369098780))) +# if scratch_369098762.isNil: +# raise newException(OutOfMemDefect, "Could not allocate memory") +# block: +# var isolate_369098776 = isolate(521) +# scratch_369098762.a = extract(isolate_369098776) +# var isolate_369098778 = isolate(literal) +# scratch_369098762.b = extract(isolate_369098778) +# proc hello_369098781(args`gensym3: pointer) {.nimcall.} = +# let objTemp_369098775 = cast[ptr ScratchObj_369098780](args`gensym3) +# let :tmp_369098777 = objTemp_369098775.a +# let :tmp_369098779 = objTemp_369098775.b +# hello(a = :tmp_369098777, b = :tmp_369098779) +# +# proc destroyScratch_369098782(args`gensym3: pointer) {.nimcall.} = +# let obj_369098783 = cast[ptr ScratchObj_369098780](args`gensym3) +# =destroy(obj_369098783[]) +# let t = Task(callback: hello_369098781, args: scratch_369098762, destroy: destroyScratch_369098782) +# + + +type + Task* = object ## `Task` contains the callback and its arguments. + callback: proc (args: pointer) {.nimcall.} + args: pointer + destroy: proc (args: pointer) {.nimcall.} + + +proc `=copy`*(x: var Task, y: Task) {.error.} + +proc `=destroy`*(t: var Task) {.inline.} = + ## Frees the resources allocated for a `Task`. + if t.args != nil: + if t.destroy != nil: + t.destroy(t.args) + c_free(t.args) + +proc invoke*(task: Task) {.inline.} = + ## Invokes the `task`. + task.callback(task.args) + +template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr: NimNode) = + # block: + # var isoTempA = isolate(521) + # scratch.a = extract(isolateA) + # var isoTempB = isolate(literal) + # scratch.b = extract(isolateB) + let isolatedTemp = genSym(nskTemp, "isoTemp") + scratchAssignList.add newVarStmt(isolatedTemp, newCall(newidentNode("isolate"), procParam)) + scratchAssignList.add newAssignment(scratchDotExpr, + newcall(newIdentNode("extract"), isolatedTemp)) + +template addAllNode(assignParam: NimNode, procParam: NimNode) = + let scratchDotExpr = newDotExpr(scratchIdent, formalParams[i][0]) + + checkIsolate(scratchAssignList, procParam, scratchDotExpr) + + let tempNode = genSym(kind = nskTemp, ident = formalParams[i][0].strVal) + callNode.add nnkExprEqExpr.newTree(formalParams[i][0], tempNode) + tempAssignList.add newLetStmt(tempNode, newDotExpr(objTemp, formalParams[i][0])) + scratchRecList.add newIdentDefs(newIdentNode(formalParams[i][0].strVal), assignParam) + +macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task = + ## Converts the call and its arguments to `Task`. + runnableExamples("--gc:orc"): + proc hello(a: int) = echo a + + let b = toTask hello(13) + assert b is Task + + doAssert getTypeInst(e).typeKind == ntyVoid + + when compileOption("threads"): + if not isGcSafe(e[0]): + error("'toTask' takes a GC safe call expression") + + if hasClosure(e[0]): + error("closure call is not allowed") + + if e.len > 1: + let scratchIdent = genSym(kind = nskTemp, ident = "scratch") + let impl = e[0].getTypeInst + + when defined(nimTasksDebug): + echo impl.treeRepr + echo e.treeRepr + let formalParams = impl[0] + + var + scratchRecList = newNimNode(nnkRecList) + scratchAssignList: seq[NimNode] + tempAssignList: seq[NimNode] + callNode: seq[NimNode] + + let + objTemp = genSym(nskTemp, ident = "objTemp") + + for i in 1 ..< formalParams.len: + var param = formalParams[i][1] + + if param.kind == nnkBracketExpr and param[0].eqIdent("sink"): + param = param[0] + + if param.typeKind in {ntyExpr, ntyStmt}: + error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter") + + case param.kind + of nnkVarTy: + error("'toTask'ed function cannot have a 'var' parameter") + of nnkBracketExpr: + if param[0].typeKind == ntyTypeDesc: + callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) + elif param[0].typeKind in {ntyVarargs, ntyOpenArray}: + if param[1].typeKind in {ntyExpr, ntyStmt}: + error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter") + let + seqType = nnkBracketExpr.newTree(newIdentNode("seq"), param[1]) + seqCallNode = newcall("@", e[i]) + addAllNode(seqType, seqCallNode) + else: + addAllNode(param, e[i]) + of nnkBracket, nnkObjConstr: + # passing by static parameters + # so we pass them directly instead of passing by scratchObj + callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) + of nnkSym, nnkPtrTy: + addAllNode(param, e[i]) + of nnkCharLit..nnkNilLit: + callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) + else: + error("not supported type kinds") + + let scratchObjType = genSym(kind = nskType, ident = "ScratchObj") + let scratchObj = nnkTypeSection.newTree( + nnkTypeDef.newTree( + scratchObjType, + newEmptyNode(), + nnkObjectTy.newTree( + newEmptyNode(), + newEmptyNode(), + scratchRecList + ) + ) + ) + + + let scratchObjPtrType = quote do: + cast[ptr `scratchObjType`](c_calloc(csize_t 1, csize_t sizeof(`scratchObjType`))) + + let scratchLetSection = newLetStmt( + scratchIdent, + scratchObjPtrType + ) + + let scratchCheck = quote do: + if `scratchIdent`.isNil: + raise newException(OutOfMemDefect, "Could not allocate memory") + + var stmtList = newStmtList() + stmtList.add(scratchObj) + stmtList.add(scratchLetSection) + stmtList.add(scratchCheck) + stmtList.add(nnkBlockStmt.newTree(newEmptyNode(), newStmtList(scratchAssignList))) + + var functionStmtList = newStmtList() + let funcCall = newCall(e[0], callNode) + functionStmtList.add tempAssignList + functionStmtList.add funcCall + + let funcName = genSym(nskProc, e[0].strVal) + let destroyName = genSym(nskProc, "destroyScratch") + let objTemp2 = genSym(ident = "obj") + let tempNode = quote("@") do: + `=destroy`(@objTemp2[]) + + result = quote do: + `stmtList` + + proc `funcName`(args: pointer) {.nimcall.} = + let `objTemp` = cast[ptr `scratchObjType`](args) + `functionStmtList` + + proc `destroyName`(args: pointer) {.nimcall.} = + let `objTemp2` = cast[ptr `scratchObjType`](args) + `tempNode` + + Task(callback: `funcName`, args: `scratchIdent`, destroy: `destroyName`) + else: + let funcCall = newCall(e[0]) + let funcName = genSym(nskProc, e[0].strVal) + + result = quote do: + proc `funcName`(args: pointer) {.nimcall.} = + `funcCall` + + Task(callback: `funcName`, args: nil) + + when defined(nimTasksDebug): + echo result.repr + +runnableExamples("--gc:orc"): + block: + var num = 0 + proc hello(a: int) = inc num, a + + let b = toTask hello(13) + b.invoke() + assert num == 13 + # A task can be invoked multiple times + b.invoke() + assert num == 26 + + block: + type + Runnable = ref object + data: int + + var data: int + proc hello(a: Runnable) {.nimcall.} = + a.data += 2 + data = a.data + + + when false: + # the parameters of call must be isolated. + let x = Runnable(data: 12) + let b = toTask hello(x) # error ----> expression cannot be isolated: x + b.invoke() + + let b = toTask(hello(Runnable(data: 12))) + b.invoke() + assert data == 14 + b.invoke() + assert data == 16 diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim new file mode 100644 index 000000000..75fed9f9b --- /dev/null +++ b/tests/stdlib/ttasks.nim @@ -0,0 +1,506 @@ +discard """ + targets: "c cpp" + matrix: "--gc:orc" +""" + +import std/[tasks, strformat] + +block: + var s = "" + proc `+`(x: int, y: string) = + s.add $x & y + + let literal = "Nim" + let t = toTask(521 + literal) + t.invoke() + + doAssert s == "521Nim" + +block: + var s = "" + proc `!`(x: int) = + s.add $x + + let t = toTask !12 + t.invoke() + + doAssert s == "12" + + +block: + block: + var called = 0 + proc hello(x: static range[1 .. 5]) = + called += x + + let b = toTask hello(3) + b.invoke() + doAssert called == 3 + b.invoke() + doAssert called == 6 + + block: + var called = 0 + proc hello(x: range[1 .. 5]) = + called += x + + let b = toTask hello(3) + b.invoke() + doAssert called == 3 + b.invoke() + doAssert called == 6 + + block: + var called = 0 + proc hello(x: 1 .. 5) = + called += x + + let b = toTask hello(3) + b.invoke() + doAssert called == 3 + b.invoke() + doAssert called == 6 + + block: + var temp = "" + proc hello(a: int or seq[string]) = + when a is seq[string]: + for s in a: + temp.add s + else: + temp.addInt a + + let x = @["1", "2", "3", "4"] + let b = toTask hello(x) + b.invoke() + doAssert temp == "1234" + b.invoke() + doAssert temp == "12341234" + + + block: + var temp = "" + + proc hello(a: int or string) = + when a is string: + temp.add a + + let x = "!2" + + let b = toTask hello(x) + b.invoke() + doAssert temp == x + + block: + var temp = "" + proc hello(a: int or string) = + when a is string: + temp.add a + + let x = "!2" + let b = toTask hello(x) + b.invoke() + doAssert temp == x + + block: + var x = 0 + proc hello(typ: typedesc) = + x += typ(12) + + let b = toTask hello(int) + b.invoke() + doAssert x == 12 + + block: + var temp = "" + proc hello(a: int or seq[string]) = + when a is seq[string]: + for s in a: + temp.add s + + let x = @["1", "2", "3", "4"] + let b = toTask hello(x) + b.invoke() + doAssert temp == "1234" + + block: + var temp = "" + proc hello(a: int | string) = + when a is string: + temp.add a + + let x = "!2" + let b = toTask hello(x) + b.invoke() + doAssert temp == x + + block: + var x = 0 + proc hello(a: int | string) = + when a is int: + x = a + + let b = toTask hello(12) + b.invoke() + doAssert x == 12 + + block: + var a1: seq[int] + var a2 = 0 + proc hello(c: seq[int], a: int) = + a1 = c + a2 = a + + let x = 12 + var y = @[1, 3, 1, 4, 5, x, 1] + let b = toTask hello(y, 12) + b.invoke() + + doAssert a1 == y + doAssert a2 == x + + block: + var a1: seq[int] + var a2 = 0 + proc hello(c: seq[int], a: int) = + a1 = c + a2 = a + var x = 2 + let b = toTask hello(@[1, 3, 1, 4, 5, x, 1], 12) + b.invoke() + + doAssert a1 == @[1, 3, 1, 4, 5, x, 1] + doAssert a2 == 12 + + block: + var a1: array[7, int] + var a2 = 0 + proc hello(c: array[7, int], a: int) = + a1 = c + a2 = a + + let b = toTask hello([1, 3, 1, 4, 5, 2, 1], 12) + b.invoke() + + doAssert a1 == [1, 3, 1, 4, 5, 2, 1] + doAssert a2 == 12 + + block: + var a1: seq[int] + var a2 = 0 + proc hello(c: seq[int], a: int) = + a1 = c + a2 = a + + let b = toTask hello(@[1, 3, 1, 4, 5, 2, 1], 12) + b.invoke() + + doAssert a1 == @[1, 3, 1, 4, 5, 2, 1] + doAssert a2 == 12 + + block: + var a1: seq[int] + var a2 = 0 + proc hello(a: int, c: seq[int]) = + a1 = c + a2 = a + + let b = toTask hello(8, @[1, 3, 1, 4, 5, 2, 1]) + b.invoke() + + doAssert a1 == @[1, 3, 1, 4, 5, 2, 1] + doAssert a2 == 8 + + let c = toTask 8.hello(@[1, 3, 1, 4, 5, 2, 1]) + c.invoke() + + doAssert a1 == @[1, 3, 1, 4, 5, 2, 1] + doAssert a2 == 8 + + block: + var a1: seq[seq[int]] + var a2: int + proc hello(a: int, c: openArray[seq[int]]) = + a1 = @c + a2 = a + + let b = toTask hello(8, @[@[3], @[4], @[5], @[6], @[12], @[7]]) + b.invoke() + + doAssert a1 == @[@[3], @[4], @[5], @[6], @[12], @[7]] + doAssert a2 == 8 + + block: + var a1: seq[int] + var a2: int + proc hello(a: int, c: openArray[int]) = + a1 = @c + a2 = a + + let b = toTask hello(8, @[3, 4, 5, 6, 12, 7]) + b.invoke() + + doAssert a1 == @[3, 4, 5, 6, 12, 7] + doAssert a2 == 8 + + block: + var a1: seq[int] + var a2: int + proc hello(a: int, c: static varargs[int]) = + a1 = @c + a2 = a + + let b = toTask hello(8, @[3, 4, 5, 6, 12, 7]) + b.invoke() + + doAssert a1 == @[3, 4, 5, 6, 12, 7] + doAssert a2 == 8 + + block: + var a1: seq[int] + var a2: int + proc hello(a: int, c: static varargs[int]) = + a1 = @c + a2 = a + + let b = toTask hello(8, [3, 4, 5, 6, 12, 7]) + b.invoke() + + doAssert a1 == @[3, 4, 5, 6, 12, 7] + doAssert a2 == 8 + + block: + var a1: seq[int] + var a2: int + proc hello(a: int, c: varargs[int]) = + a1 = @c + a2 = a + + let x = 12 + let b = toTask hello(8, 3, 4, 5, 6, x, 7) + b.invoke() + + doAssert a1 == @[3, 4, 5, 6, 12, 7] + doAssert a2 == 8 + + block: + var x = 12 + + proc hello(x: ptr int) = + x[] += 12 + + let b = toTask hello(addr x) + b.invoke() + + doAssert x == 24 + + let c = toTask x.addr.hello + invoke(c) + + doAssert x == 36 + block: + type + Test = ref object + id: int + + var x = 0 + proc hello(a: int, c: static Test) = + x += a + x += c.id + + let b = toTask hello(8, Test(id: 12)) + b.invoke() + + doAssert x == 20 + + block: + type + Test = object + id: int + + var x = 0 + proc hello(a: int, c: static Test) = + x += a + x += c.id + + let b = toTask hello(8, Test(id: 12)) + b.invoke() + doAssert x == 20 + + block: + var x = 0 + proc hello(a: int, c: static seq[int]) = + x += a + for i in c: + x += i + + let b = toTask hello(8, @[3, 4, 5, 6, 12, 7]) + b.invoke() + doAssert x == 45 + + block: + var x = 0 + proc hello(a: int, c: static array[5, int]) = + x += a + for i in c: + x += i + + let b = toTask hello(8, [3, 4, 5, 6, 12]) + b.invoke() + doAssert x == 38 + + block: + var aVal = 0 + var cVal = "" + + proc hello(a: int, c: static string) = + aVal += a + cVal.add c + + var x = 1314 + let b = toTask hello(x, "hello") + b.invoke() + + doAssert aVal == x + doAssert cVal == "hello" + + block: + var aVal = "" + + proc hello(a: static string) = + aVal.add a + let b = toTask hello("hello") + b.invoke() + + doAssert aVal == "hello" + + block: + var aVal = 0 + var cVal = "" + + proc hello(a: static int, c: static string) = + aVal += a + cVal.add c + let b = toTask hello(8, "hello") + b.invoke() + + doAssert aVal == 8 + doAssert cVal == "hello" + + block: + var aVal = 0 + var cVal = 0 + + proc hello(a: static int, c: int) = + aVal += a + cVal += c + + let b = toTask hello(c = 0, a = 8) + b.invoke() + + doAssert aVal == 8 + doAssert cVal == 0 + + block: + var aVal = 0 + var cVal = 0 + + proc hello(a: int, c: static int) = + aVal += a + cVal += c + + let b = toTask hello(c = 0, a = 8) + b.invoke() + + doAssert aVal == 8 + doAssert cVal == 0 + + block: + var aVal = 0 + var cVal = 0 + + proc hello(a: static int, c: static int) = + aVal += a + cVal += c + + let b = toTask hello(0, 8) + b.invoke() + + doAssert aVal == 0 + doAssert cVal == 8 + + block: + var temp = "" + proc hello(x: int, y: seq[string], d = 134) = + temp = fmt"{x=} {y=} {d=}" + + + proc main() = + var x = @["23456"] + let t = toTask hello(2233, x) + t.invoke() + + doAssert temp == """x=2233 y=@["23456"] d=134""" + + main() + + + block: + var temp = "" + proc hello(x: int, y: seq[string], d = 134) = + temp.add fmt"{x=} {y=} {d=}" + + proc ok() = + temp = "ok" + + proc main() = + var x = @["23456"] + let t = toTask hello(2233, x) + t.invoke() + t.invoke() + + doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134""" + + main() + + var x = @["4"] + let m = toTask hello(2233, x, 7) + m.invoke() + + doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134x=2233 y=@["4"] d=7""" + + let n = toTask ok() + n.invoke() + + doAssert temp == "ok" + + block: + var called = 0 + block: + proc hello() = + inc called + + let a = toTask hello() + invoke(a) + + doAssert called == 1 + + block: + proc hello(a: int) = + inc called, a + + let b = toTask hello(13) + let c = toTask hello(a = 14) + b.invoke() + c.invoke() + + doAssert called == 28 + + block: + proc hello(a: int, c: int) = + inc called, a + + let b = toTask hello(c = 0, a = 8) + b.invoke() + + doAssert called == 36 From 86a1dcf92864f50fb1ab076cf58e19a3da81d301 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 9 Apr 2021 15:36:06 +0200 Subject: [PATCH 2392/4254] hashes: Made the runnableExample easier to understand (#17689) --- lib/pure/hashes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index c526c976f..3339adba2 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -21,7 +21,7 @@ runnableExamples: foo: int bar: string - iterator items(x: Something): int = + iterator items(x: Something): Hash = yield hash(x.foo) yield hash(x.bar) From 8aa5991beaa01f25a90d4115ed2495c92221f603 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 9 Apr 2021 16:29:10 +0200 Subject: [PATCH 2393/4254] Genode platform fixes (#17521) * Genode: move dyncall failures to runtime Do not use the "error" pragma to warn that dynamic library loading is not implemented, print a message at runtime and exit. * Genode: use stricter dataspace type in page allocator * Genode: remove compiler configuration from nim.cfg Self-hosting Nim is not supported on Genode and defining the cross-compilation environment can be done externally. * Genode: use new mutex API * Genode: call nim_component_construct as a C procedure * Genode: implement echo for NimStringV2 --- compiler/ccgexprs.nim | 14 ++++++++++---- compiler/cgen.nim | 2 +- config/nim.cfg | 25 +------------------------ lib/genode/alloc.nim | 14 +++++++------- lib/genode_cpp/syslocks.h | 20 +++++++++----------- lib/pure/dynlib.nim | 26 ++++++++++++++++++++++++++ lib/system/dyncalls.nim | 12 ++++++------ 7 files changed, 60 insertions(+), 53 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ea09b3400..3872ed360 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1103,15 +1103,21 @@ proc genEcho(p: BProc, n: PNode) = # echo directly to the Genode LOG session var args: Rope = nil var a: TLoc - for it in n.sons: + for i, it in n.sons: if it.skipConv.kind == nkNilLit: args.add(", \"\"") - else: + elif n.len != 0: initLocExpr(p, it, a) - args.add(ropecg(p.module, ", Genode::Cstring($1->data, $1->len)", [rdLoc(a)])) + if i > 0: + args.add(", ") + case detectStrVersion(p.module) + of 2: + args.add(ropecg(p.module, "Genode::Cstring($1.p->data, $1.len)", [a.rdLoc])) + else: + args.add(ropecg(p.module, "Genode::Cstring($1->data, $1->len)", [a.rdLoc])) p.module.includeHeader("") p.module.includeHeader("") - linefmt(p, cpsStmts, """Genode::log(""$1);$n""", [args]) + linefmt(p, cpsStmts, """Genode::log($1);$n""", [args]) else: if n.len == 0: linefmt(p, cpsStmts, "#echoBinSafe(NIM_NIL, $1);$n", [n.len]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 7dfab6a42..5d6de2a03 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1418,7 +1418,7 @@ proc genMainProc(m: BModule) = GenodeNimMain = "extern Genode::Env *nim_runtime_env;$N" & - "extern void nim_component_construct(Genode::Env*);$N$N" & + "extern \"C\" void nim_component_construct(Genode::Env*);$N$N" & NimMainBody ComponentConstruct = diff --git a/config/nim.cfg b/config/nim.cfg index 39e6c002b..d3ab75825 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -114,7 +114,7 @@ nimblepath="$home/.nimble/pkgs/" clang.options.linker = "-Wl,--as-needed -lnetwork" clang.cpp.options.linker = "-Wl,--as-needed -lnetwork" tcc.options.linker = "-Wl,--as-needed -lnetwork" - @else: + @elif not genode: # -fopenmp gcc.options.linker = "-ldl" gcc.cpp.options.linker = "-ldl" @@ -289,29 +289,6 @@ vcc.cpp.options.size = "/O1" # Configuration for the Tiny C Compiler: tcc.options.always = "-w" -# Configuration for the Genode toolchain -@if genode: - noCppExceptions # avoid std C++ - tlsEmulation:on # no TLS segment register magic - @if i386 or amd64: - gcc.exe = "genode-x86-gcc" - gcc.cpp.exe = "genode-x86-g++" - gcc.cpp.linkerexe = "genode-x86-ld" - @elif arm: - gcc.exe = "genode-arm-gcc" - gcc.cpp.exe = "genode-arm-g++" - gcc.cpp.linkerexe = "genode-arm-ld" - @elif arm64: - gcc.exe = "genode-aarch64-gcc" - gcc.cpp.exe = "genode-aarch64-g++" - gcc.cpp.linkerexe = "genode-aarch64-ld" - @elif riscv64: - gcc.exe = "genode-riscv-gcc" - gcc.cpp.exe = "genode-riscv-g++" - gcc.cpp.linkerexe = "genode-riscv-ld" - @end -@end - @if arm or arm64: --define:nimEmulateOverflowChecks @end diff --git a/lib/genode/alloc.nim b/lib/genode/alloc.nim index a21a3ad7b..3ddd3074b 100644 --- a/lib/genode/alloc.nim +++ b/lib/genode/alloc.nim @@ -17,18 +17,18 @@ when not defined(genode): when not declared(GenodeEnv): include genode/env -type DataspaceCapability {. - importcpp: "Genode::Dataspace_capability", pure.} = object +type RamDataspaceCapability {. + importcpp: "Genode::Ram_dataspace_capability", pure.} = object type Map = object attachment: pointer size: int - ds: DataspaceCapability + ds: RamDataspaceCapability SlabMeta = object next: ptr MapSlab - ds: DataspaceCapability + ds: RamDataspaceCapability MapSlab = object meta: SlabMeta @@ -45,11 +45,11 @@ proc capsAvail(env: GenodeEnv): int {. ## Return the number of available capabilities. ## Each dataspace allocation consumes a capability. -proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {. +proc allocDataspace(env: GenodeEnv; size: int): RamDataspaceCapability {. importcpp: "#->pd().alloc(@)".} ## Allocate a dataspace and its capability. -proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {. +proc attachDataspace(env: GenodeEnv; ds: RamDataspaceCapability): pointer {. importcpp: "#->rm().attach(@)".} ## Attach a dataspace into the component address-space. @@ -57,7 +57,7 @@ proc detachAddress(env: GenodeEnv; p: pointer) {. importcpp: "#->rm().detach(@)".} ## Detach a dataspace from the component address-space. -proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {. +proc freeDataspace(env: GenodeEnv; ds: RamDataspaceCapability) {. importcpp: "#->pd().free(@)".} ## Free a dataspace. diff --git a/lib/genode_cpp/syslocks.h b/lib/genode_cpp/syslocks.h index 8ba39abc2..c50180903 100644 --- a/lib/genode_cpp/syslocks.h +++ b/lib/genode_cpp/syslocks.h @@ -13,7 +13,7 @@ /* Genode includes */ #include -#include +#include namespace Nim { struct SysLock; @@ -22,15 +22,14 @@ namespace Nim { struct Nim::SysLock { - Genode::Lock _lock_a, _lock_b; + Genode::Mutex _mutex_a, _mutex_b; bool _locked; void acquireSys() { - _lock_a.lock(); + Genode::Mutex::Guard guard(_mutex_a); _locked = true; - _lock_a.unlock(); - _lock_b.lock(); + _mutex_b.acquire(); } bool tryAcquireSys() @@ -38,23 +37,22 @@ struct Nim::SysLock if (_locked) return false; - _lock_a.lock(); + Genode::Mutex::Guard guard(_mutex_a); + if (_locked) { - _lock_a.unlock(); return false; } else { _locked = true; - _lock_b.lock(); - _lock_a.unlock(); + _mutex_b.acquire(); return true; } } void releaseSys() { + Genode::Mutex::Guard guard(_mutex_a); _locked = false; - _lock_a.unlock(); - _lock_b.unlock(); + _mutex_b.release(); } }; diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index a1a94072c..3c1466322 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -150,6 +150,32 @@ elif defined(nintendoswitch): proc symAddr(lib: LibHandle, name: cstring): pointer = raise newException(OSError, "symAddr not implemented on Nintendo Switch!") +elif defined(genode): + # + # ========================================================================= + # Not implemented for Genode without POSIX. Raise an error if called. + # ========================================================================= + # + + template raiseErr(prc: string) = + raise newException(OSError, prc & " not implemented, compile with POSIX suport") + + proc dlclose(lib: LibHandle) = + raiseErr(OSError, "dlclose") + proc dlopen(path: cstring, mode: int): LibHandle = + raiseErr(OSError, "dlopen") + proc dlsym(lib: LibHandle, name: cstring): pointer = + raiseErr(OSError, "dlsym") + proc loadLib(path: string, global_symbols = false): LibHandle = + raiseErr(OSError, "loadLib") + proc loadLib(): LibHandle = + raiseErr(OSError, "loadLib") + proc unloadLib(lib: LibHandle) = + raiseErr(OSError, "unloadLib") + proc symAddr(lib: LibHandle, name: cstring): pointer = + raiseErr(OSError, "symAddr") + + elif defined(windows) or defined(dos): # # ======================================================================= diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index b0f326bb5..c14fcf31e 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -167,14 +167,14 @@ elif defined(windows) or defined(dos): elif defined(genode): - proc nimUnloadLibrary(lib: LibHandle) {. - error: "nimUnloadLibrary not implemented".} + proc nimUnloadLibrary(lib: LibHandle) = + raiseAssert("nimUnloadLibrary not implemented") - proc nimLoadLibrary(path: string): LibHandle {. - error: "nimLoadLibrary not implemented".} + proc nimLoadLibrary(path: string): LibHandle = + raiseAssert("nimLoadLibrary not implemented") - proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {. - error: "nimGetProcAddr not implemented".} + proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = + raiseAssert("nimGetProcAddr not implemented") elif defined(nintendoswitch) or defined(freertos): proc nimUnloadLibrary(lib: LibHandle) = From 1822ed384abdbbb5d385b1ad24e23e66936dbf74 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 9 Apr 2021 16:41:49 +0200 Subject: [PATCH 2394/4254] IC: added converter test case (#17688) * IC: added converter test case * IC: make converter example work --- compiler/importer.nim | 9 ++++++--- compiler/modulegraphs.nim | 4 ++++ tests/ic/mdefconverter.nim | 2 ++ tests/ic/tconverter.nim | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 tests/ic/mdefconverter.nim create mode 100644 tests/ic/tconverter.nim diff --git a/compiler/importer.nim b/compiler/importer.nim index cb529795a..f8ee0d483 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -163,14 +163,17 @@ proc addImport(c: PContext; im: sink ImportedModule) = c.imports.add im template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} = - for it in c.graph.ifaces[fromMod.position].converters: + for it in mitems c.graph.ifaces[fromMod.position].converters: if filter: + loadPackedSym(c.graph, it) addConverter(c, it) - for it in c.graph.ifaces[fromMod.position].patterns: + for it in mitems c.graph.ifaces[fromMod.position].patterns: if filter: + loadPackedSym(c.graph, it) addPattern(c, it) - for it in c.graph.ifaces[fromMod.position].pureEnums: + for it in mitems c.graph.ifaces[fromMod.position].pureEnums: if filter: + loadPackedSym(c.graph, it) importPureEnumFields(c, it.sym, it.sym.typ) proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 4430e3baa..02c745018 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -326,6 +326,10 @@ proc loadCompilerProc*(g: ModuleGraph; name: string): PSym = strTableAdd(g.compilerprocs, result) return result +proc loadPackedSym*(g: ModuleGraph; s: var LazySym) = + if s.sym == nil: + s.sym = loadSymFromId(g.config, g.cache, g.packed, s.id.module, s.id.packed) + proc `$`*(u: SigHash): string = toBase64a(cast[cstring](unsafeAddr u), sizeof(u)) diff --git a/tests/ic/mdefconverter.nim b/tests/ic/mdefconverter.nim new file mode 100644 index 000000000..d0a23f801 --- /dev/null +++ b/tests/ic/mdefconverter.nim @@ -0,0 +1,2 @@ + +converter toBool*(x: int): bool = x != 0 diff --git a/tests/ic/tconverter.nim b/tests/ic/tconverter.nim new file mode 100644 index 000000000..aecdf4b48 --- /dev/null +++ b/tests/ic/tconverter.nim @@ -0,0 +1,18 @@ +discard """ + output: "yes" +""" + +import mdefconverter + +echo "yes" + +#!EDIT!# + +discard """ + output: "converted int to bool" +""" + +import mdefconverter + +if 4: + echo "converted int to bool" From 08262206d35a2f171f09681a1abe47485bd79e88 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 10 Apr 2021 01:55:39 -0500 Subject: [PATCH 2395/4254] refs #15667 improve invalid indentation errors, report when & where `=` could be missing (#16397) * refs #15667 improve invalid indentation errors * also show line info where = is missing * add test * add more tests --- compiler/lexer.nim | 1 + compiler/parser.nim | 19 +++++++++++--- tests/parser/t15667.nim | 58 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 tests/parser/t15667.nim diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 7c7ac4177..59b983060 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -163,6 +163,7 @@ proc prettyTok*(tok: Token): string = else: $tok proc printTok*(conf: ConfigRef; tok: Token) = + # xxx factor with toLocation msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok) proc initToken*(L: var Token) = diff --git a/compiler/parser.nim b/compiler/parser.nim index d103d161a..fd9d06de5 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -44,6 +44,9 @@ type hasProgress: bool # some while loop requires progress ensurance lex*: Lexer # The lexer that is used for parsing tok*: Token # The current token + lineStartPrevious*: int + lineNumberPrevious*: int + bufposPrevious*: int inPragma*: int # Pragma level inSemiStmtList*: int emptyNode: PNode @@ -77,7 +80,7 @@ proc eat*(p: var Parser, tokType: TokType) proc skipInd*(p: var Parser) proc optPar*(p: var Parser) proc optInd*(p: var Parser, n: PNode) -proc indAndComment*(p: var Parser, n: PNode) +proc indAndComment*(p: var Parser, n: PNode, maybeMissEquals = false) proc setBaseFlags*(n: PNode, base: NumericalBase) proc parseSymbol*(p: var Parser, mode = smNormal): PNode proc parseTry(p: var Parser; isExpr: bool): PNode @@ -100,6 +103,9 @@ template prettySection(body) = proc getTok(p: var Parser) = ## Get the next token from the parser's lexer, and store it in the parser's ## `tok` member. + p.lineNumberPrevious = p.lex.lineNumber + p.lineStartPrevious = p.lex.lineStart + p.bufposPrevious = p.lex.bufpos rawGetTok(p.lex, p.tok) p.hasProgress = true when defined(nimpretty): @@ -223,9 +229,13 @@ proc parLineInfo(p: Parser): TLineInfo = ## Retrieve the line information associated with the parser's current state. result = getLineInfo(p.lex, p.tok) -proc indAndComment(p: var Parser, n: PNode) = +proc indAndComment(p: var Parser, n: PNode, maybeMissEquals = false) = if p.tok.indent > p.currInd: if p.tok.tokType == tkComment: rawSkipComment(p, n) + elif maybeMissEquals: + let col = p.bufposPrevious - p.lineStartPrevious + var info = newLineInfo(p.lex.fileIdx, p.lineNumberPrevious, col) + parMessage(p, "invalid indentation, maybe you forgot a '=' at $1 ?" % [p.lex.config$info]) else: parMessage(p, errInvalidIndentation) else: skipComment(p, n) @@ -1773,13 +1783,14 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode = else: result.add(p.emptyNode) # empty exception tracking: result.add(p.emptyNode) - if p.tok.tokType == tkEquals and p.validInd: + let maybeMissEquals = p.tok.tokType != tkEquals + if (not maybeMissEquals) and p.validInd: getTok(p) skipComment(p, result) result.add(parseStmt(p)) else: result.add(p.emptyNode) - indAndComment(p, result) + indAndComment(p, result, maybeMissEquals) proc newCommentStmt(p: var Parser): PNode = #| commentStmt = COMMENT diff --git a/tests/parser/t15667.nim b/tests/parser/t15667.nim new file mode 100644 index 000000000..d15178789 --- /dev/null +++ b/tests/parser/t15667.nim @@ -0,0 +1,58 @@ +discard """ + cmd: "nim check $options $file" + action: "reject" + nimout: ''' +t15667.nim(23, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(22, 13) ? +t15667.nim(28, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(26, 13) ? +t15667.nim(33, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(31, 25) ? +t15667.nim(42, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(38, 12) ? +t15667.nim(56, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(55, 13) ? +''' +""" + + + + + + + + +# line 20 +block: + proc fn1() + discard + +block: + proc fn2() + # + discard + +block: + proc fn3() {.exportc.} + # + discard + +block: # complex example + proc asdfasdfsd() {. exportc, + inline + .} # foo + #[ + bar + ]# + discard + +block: # xxx this doesn't work yet (only a bare `invalid indentation` error) + proc fn5() + ## + discard + +block: # ditto + proc fn6*() + ## foo bar + runnableExamples: discard + +block: + proc fn8() + runnableExamples: + discard + discard From 2150cd1826f11c74ce780dc0aaecedbed094230d Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 10 Apr 2021 10:49:01 +0300 Subject: [PATCH 2396/4254] restyle RST option lists (#17637) * WIP: restyle RST option lists * apply similar style to Latex * fix tests * minor visual tweaks * update tests * remove leftover comments --- config/nimdoc.tex.cfg | 11 ++++++- doc/nimdoc.css | 27 +++++++++++++++++ lib/packages/docutils/rst.nim | 2 ++ lib/packages/docutils/rstast.nim | 4 +-- lib/packages/docutils/rstgen.nim | 18 +++++++---- nimdoc/testproject/expected/nimdoc.out.css | 27 +++++++++++++++++ tests/stdlib/trstgen.nim | 35 ++++++++++++++-------- 7 files changed, 103 insertions(+), 21 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 307b280cc..69266f85d 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -50,7 +50,7 @@ doc.file = """ \usepackage{fancyvrb, courier} \usepackage{tabularx} \usepackage{hyperref} -\usepackage{enumitem} % for enumList and rstfootnote +\usepackage{enumitem} % for option list, enumList, and rstfootnote \usepackage{xcolor} \usepackage[tikz]{mdframed} @@ -77,6 +77,15 @@ bottomline=false} \newenvironment{rstpre}{\VerbatimEnvironment\begingroup\begin{Verbatim}[fontsize=\footnotesize , commandchars=\\\{\}]}{\end{Verbatim}\endgroup} \newenvironment{rstfootnote}{\begin{description}[labelindent=1em,leftmargin=1em,labelwidth=2.6em]}{\end{description}} +\ifdim\linewidth<30em + \def\rstoptleftmargin{0.4\linewidth} + \def\rstoptlabelwidth{0.35\linewidth} +\else + \def\rstoptleftmargin{12em} + \def\rstoptlabelwidth{10.5em} +\fi +\newenvironment{rstoptlist}{% +\begin{description}[font=\sffamily\bfseries,style=nextline,leftmargin=\rstoptleftmargin,labelwidth=\rstoptlabelwidth]}{\end{description}} % to pack tabularx into a new environment, special syntax is needed :-( \newenvironment{rsttab}[1]{\tabularx{\linewidth}{#1}}{\endtabularx} diff --git a/doc/nimdoc.css b/doc/nimdoc.css index db9a7ce97..ced791d16 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -511,6 +511,33 @@ div.footnote-label { min-width: 1.7em; } +div.option-list { + border: 0.1em solid var(--border); +} +div.option-list-item { + padding-left: 12em; + padding-right: 0; + padding-bottom: 0.3em; + padding-top: 0.3em; +} +div.odd { + background-color: var(--secondary-background); +} +div.option-list-label { + margin-left: -11.5em; + margin-right: 0em; + min-width: 11.5em; + font-weight: bolder; + display: inline-block; + vertical-align: top; +} +div.option-list-description { + width: calc(100% - 1em); + padding-left: 1em; + padding-right: 0; + display: inline-block; +} + blockquote { font-size: 0.9em; font-style: italic; diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index a8bc04a1a..c2385d517 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -2085,6 +2085,7 @@ proc parseBulletList(p: var RstParser): PRstNode = proc parseOptionList(p: var RstParser): PRstNode = result = newRstNodeA(p, rnOptionList) let col = currentTok(p).col + var order = 1 while true: if currentTok(p).col == col and isOptionList(p): var a = newRstNode(rnOptionGroup) @@ -2107,6 +2108,7 @@ proc parseOptionList(p: var RstParser): PRstNode = if currentTok(p).kind == tkIndent: inc p.idx c.add(a) c.add(b) + c.order = order; inc order result.add(c) else: if currentTok(p).kind != tkEof: dec p.idx # back to tkIndent diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index dd456b577..394cc2698 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -90,7 +90,7 @@ type level*: int ## level of headings starting from 1 (main ## chapter) to larger ones (minor sub-sections) ## level=0 means it's document title or subtitle - of rnFootnote, rnCitation, rnFootnoteRef: + of rnFootnote, rnCitation, rnFootnoteRef, rnOptionListItem: order*: int ## footnote order (for auto-symbol footnotes and ## auto-numbered ones without a label) else: @@ -368,7 +368,7 @@ proc renderRstToStr*(node: PRstNode, indent=0): string = result.add txt of rnHeadline, rnOverline, rnMarkdownHeadline: result.add "\tlevel=" & $node.level - of rnFootnote, rnCitation, rnFootnoteRef: + of rnFootnote, rnCitation, rnFootnoteRef, rnOptionListItem: result.add (if node.order == 0: "" else: "\torder=" & $node.order) else: discard diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index f0a2604ff..1b9334a77 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1165,7 +1165,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "$1\n", "\\begin{description}\n$2\n$1\\end{description}\n", result) of rnDefItem: renderAux(d, n, result) - of rnDefName: renderAux(d, n, "$1\n", "$2\\item[$1] ", result) + of rnDefName: renderAux(d, n, "$1\n", "$2\\item[$1]\\ ", result) of rnDefBody: renderAux(d, n, "$1\n", "$2\n$1\n", result) of rnFieldList: var tmp = "" @@ -1189,14 +1189,20 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnIndex: renderRstToOut(d, n.sons[2], result) of rnOptionList: - renderAux(d, n, "$1", - "\\begin{description}\n$2\n$1\\end{description}\n", result) + renderAux(d, n, "$1", + "\\begin{rstoptlist}$2\n$1\\end{rstoptlist}", result) of rnOptionListItem: - renderAux(d, n, "$1\n", "$1", result) + var addclass = if n.order mod 2 == 1: " odd" else: "" + renderAux(d, n, + "
    $1
    \n", + "$1", result) of rnOptionGroup: - renderAux(d, n, "$1", "\\item[$1]", result) + renderAux(d, n, + "
    $1
    ", + "\\item[$1]", result) of rnDescription: - renderAux(d, n, "$1\n", " $1\n", result) + renderAux(d, n, "
    $1
    ", + " $1\n", result) of rnOption, rnOptionString, rnOptionArgument: doAssert false, "renderRstToOut" of rnLiteralBlock: diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index db9a7ce97..ced791d16 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -511,6 +511,33 @@ div.footnote-label { min-width: 1.7em; } +div.option-list { + border: 0.1em solid var(--border); +} +div.option-list-item { + padding-left: 12em; + padding-right: 0; + padding-bottom: 0.3em; + padding-top: 0.3em; +} +div.odd { + background-color: var(--secondary-background); +} +div.option-list-label { + margin-left: -11.5em; + margin-right: 0em; + min-width: 11.5em; + font-weight: bolder; + display: inline-block; + vertical-align: top; +} +div.option-list-description { + width: calc(100% - 1em); + padding-left: 1em; + padding-right: 0; + display: inline-block; +} + blockquote { font-size: 0.9em; font-style: italic; diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index b403d96c6..ed5d72226 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1255,7 +1255,7 @@ Test1 doAssert "
    ") == 2) - check(output.count("-mdesc""" in output) - check("""-nvery long desc""" in + check(output.count("
    -m
    """ & + """
    desc
    """ in + output) + check("""
    -n
    """ & + """
    very long desc
    """ in output) test "Option lists 2": @@ -1385,11 +1388,15 @@ Test1 -d option""" let output = input.toHtml check(output.count("-mdesc""" in output) - check("""-nvery long desc""" in + check output.count("
    -m
    """ & + """
    desc
    """ in output) - check("""-doption""" in + check("""
    -n
    """ & + """
    very long desc
    """ in + output) + check("""
    -d
    """ & + """
    option
    """ in output) check "

    option

    " notin output @@ -1402,11 +1409,15 @@ Test1 -d option""" let output = input.toHtml check(output.count("compilecompile1""" in output) - check("""docdoc1 cont""" in + check output.count("
    compile
    """ & + """
    compile1
    """ in output) - check("""-doption""" in + check("""
    doc
    """ & + """
    doc1 cont
    """ in + output) + check("""
    -d
    """ & + """
    option
    """ in output) check "

    option

    " notin output From 3aaec0647b6c924ea1da18e8427f13289ebab980 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 11 Apr 2021 11:23:08 +0300 Subject: [PATCH 2397/4254] turn on syntax highlighting in Manual & Tutorial (#17692) * turn on syntax highlighting in Manual & Tutorial * avoid highlighting of "method" * use relative path * 2 more changes --- doc/manual.rst | 192 ++++++++++++++++++------------------ doc/manual/var_t_return.rst | 1 + doc/rstcommon.rst | 6 ++ doc/sets_fragment.txt | 38 +++---- doc/tut1.rst | 34 +++---- doc/tut2.rst | 11 ++- doc/tut3.rst | 4 +- 7 files changed, 149 insertions(+), 137 deletions(-) create mode 100644 doc/rstcommon.rst diff --git a/doc/manual.rst b/doc/manual.rst index aad8034c8..1325d1c5f 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ========== Nim Manual ========== @@ -7,6 +5,8 @@ Nim Manual :Authors: Andreas Rumpf, Zahary Karadjov :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: @@ -127,9 +127,9 @@ compiler may instead choose to allow the program to die with a fatal error. echo "invalid index" The current implementation allows to switch between these different behaviors -via `--panics:on|off`. When panics are turned on, the program dies with a +via ``--panics:on|off``. When panics are turned on, the program dies with a panic, if they are turned off the runtime errors are turned into -exceptions. The benefit of `--panics:on` is that it produces smaller binary +exceptions. The benefit of ``--panics:on`` is that it produces smaller binary code and the compiler has more freedom to optimize the code. An `unchecked runtime error`:idx: is an error that is not guaranteed to be @@ -490,7 +490,7 @@ Rationale: It enables the efficient support of `array[char, int]` or The `Rune` type can represent any Unicode character. `Rune` is declared in the `unicode module `_. -A character literal that does not end in ``'`` is interpreted as ``'`` if there +A character literal that does not end in `'` is interpreted as `'` if there is a preceeding backtick token. There must be no whitespace between the preceeding backtick token and the character literal. This special case ensures that a declaration like ``proc `'customLiteral`(s: string)`` is valid. ``proc `'customLiteral`(s: string)`` @@ -752,7 +752,7 @@ Otherwise, precedence is determined by the first character. Precedence level Operators First character Terminal symbol ================ ======================================================= ================== =============== 10 (highest) `$ ^` OP10 - 9 `* / div mod shl shr %` ``* % \ /`` OP9 + 9 `* / div mod shl shr %` `* % \ /` OP9 8 `+ -` `+ - ~ |` OP8 7 `&` `&` OP7 6 `..` `.` OP6 @@ -1008,7 +1008,7 @@ These integer types are pre-defined: literal that has no type suffix is of this type if it is in the range `low(int32)..high(int32)` otherwise the literal's type is `int64`. -intXX +`int`\ XX additional signed integer types of XX bits use this naming scheme (example: int16 is a 16-bit wide integer). The current implementation supports `int8`, `int16`, `int32`, `int64`. @@ -1019,7 +1019,7 @@ intXX has the same size as a pointer. An integer literal with the type suffix `'u` is of this type. -uintXX +`uint`\ XX additional unsigned integer types of XX bits use this naming scheme (example: uint16 is a 16-bit wide unsigned integer). The current implementation supports `uint8`, `uint16`, `uint32`, @@ -1039,22 +1039,22 @@ the `%` suffix as convention: ====================== ====================================================== operation meaning ====================== ====================================================== -`a +% b` unsigned integer addition -`a -% b` unsigned integer subtraction -`a *% b` unsigned integer multiplication -`a /% b` unsigned integer division -`a %% b` unsigned integer modulo operation -`a <% b` treat `a` and `b` as unsigned and compare -`a <=% b` treat `a` and `b` as unsigned and compare -`ze(a)` extends the bits of `a` with zeros until it has the +`a +% b` unsigned integer addition +`a -% b` unsigned integer subtraction +`a *% b` unsigned integer multiplication +`a /% b` unsigned integer division +`a %% b` unsigned integer modulo operation +`a <% b` treat `a` and `b` as unsigned and compare +`a <=% b` treat `a` and `b` as unsigned and compare +`ze(a)` extends the bits of `a` with zeros until it has the width of the `int` type -`toU8(a)` treats `a` as unsigned and converts it to an +`toU8(a)` treats `a` as unsigned and converts it to an unsigned integer of 8 bits (but still the `int8` type) -`toU16(a)` treats `a` as unsigned and converts it to an +`toU16(a)` treats `a` as unsigned and converts it to an unsigned integer of 16 bits (but still the `int16` type) -`toU32(a)` treats `a` as unsigned and converts it to an +`toU32(a)` treats `a` as unsigned and converts it to an unsigned integer of 32 bits (but still the `int32` type) ====================== ====================================================== @@ -1117,9 +1117,9 @@ The following floating-point types are pre-defined: but now it is always mapped to `float64`. This type should be used in general. -floatXX +`float`\ XX an implementation may define additional floating-point types of XX bits using - this naming scheme (example: float64 is a 64-bit wide float). The current + this naming scheme (example: `float64` is a 64-bit wide float). The current implementation supports `float32` and `float64`. Literals of these types have the suffix 'fXX. @@ -1459,7 +1459,7 @@ The notation `x[i]` can be used to access the i-th element of `x`. Arrays are always bounds checked (statically or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -`--boundChecks:off` command-line switch. +``--boundChecks:off`` command-line switch. An array constructor can have explicit indexes for readability: @@ -1946,7 +1946,8 @@ memory manually: dealloc(d) Without the `reset` call the memory allocated for the `d.s` string would -never be freed. The example also demonstrates two important features for low-level programming: the `sizeof` proc returns the size of a type or value +never be freed. The example also demonstrates two important features for +low-level programming: the `sizeof` proc returns the size of a type or value in bytes. The `cast` operator can circumvent the type system: the compiler is forced to treat the result of the `alloc0` call (which returns an untyped pointer) as if it would have the type `ptr Data`. Casting should only be @@ -2045,7 +2046,7 @@ Nim supports these `calling conventions`:idx:\: C++ class member functions on the x86 architecture. `syscall`:idx: - The syscall convention is the same as `__syscall` in C. It is used for + The syscall convention is the same as `__syscall`:c: in C. It is used for interrupts. `noconv`:idx: @@ -3217,7 +3218,7 @@ Assembler statement The direct embedding of assembler code into Nim code is supported by the unsafe `asm` statement. Identifiers in the assembler code that refer to Nim identifiers shall be enclosed in a special character which can be -specified in the statement's pragmas. The default special character is ``'`'``: +specified in the statement's pragmas. The default special character is `'\`'`: .. code-block:: nim {.push stackTrace:off.} @@ -3261,7 +3262,7 @@ Instead of: Using statement --------------- -The using statement provides syntactic convenience in modules where +The `using` statement provides syntactic convenience in modules where the same parameter names and types are used over and over. Instead of: .. code-block:: nim @@ -3301,8 +3302,8 @@ that are explicitly typed is possible and requires a semicolon between them. If expression ------------- -An `if expression` is almost like an if statement, but it is an expression. -This feature is similar to `ternary operators` in other languages. +An `if` expression is almost like an if statement, but it is an expression. +This feature is similar to *ternary operators* in other languages. Example: .. code-block:: nim @@ -3314,12 +3315,12 @@ required. `Elif` parts are also allowed. When expression --------------- -Just like an `if expression`, but corresponding to the when statement. +Just like an `if` expression, but corresponding to the `when` statement. Case expression --------------- -The `case expression` is again very similar to the case statement: +The `case` expression is again very similar to the case statement: .. code-block:: nim var favoriteFood = case animal @@ -3337,7 +3338,7 @@ the last expression as the result value. Block expression ---------------- -A `block expression` is almost like a block statement, but it is an expression +A `block` expression is almost like a block statement, but it is an expression that uses the last expression under the block as the value. It is similar to the statement list expression, but the statement list expression does not open a new block scope. @@ -3434,7 +3435,7 @@ Type casts should not be confused with *type conversions,* as mentioned in the prior section. Unlike type conversions, a type cast cannot change the underlying bit pattern of the data being casted (aside from that the size of the target type may differ from the source type). Casting resembles *type punning* in other -languages or C++'s `reinterpret_cast` and `bit_cast` features. +languages or C++'s `reinterpret_cast`:cpp: and `bit_cast`:cpp: features. The addr operator ----------------- @@ -3562,7 +3563,7 @@ the operator's position within an expression.) There is no way to declare postfix operators: all postfix operators are built-in and handled by the grammar explicitly. -Any operator can be called like an ordinary proc with the '`opr`' +Any operator can be called like an ordinary proc with the \`opr\` notation. (Thus an operator can have more than two parameters): .. code-block:: nim @@ -3596,9 +3597,9 @@ current module: Method call syntax ------------------ -For object-oriented programming, the syntax `obj.method(args)` can be used -instead of `method(obj, args)`. The parentheses can be omitted if there are no -remaining arguments: `obj.len` (instead of `len(obj)`). +For object-oriented programming, the syntax `obj.methodName(args)` can be used +instead of `methodName(obj, args)`. The parentheses can be omitted if +there are no remaining arguments: `obj.len` (instead of `len(obj)`). This method call syntax is not restricted to objects, it can be used to supply any type of first argument for procedures: @@ -3813,7 +3814,7 @@ simplicity (they require specialized semantic checking):: Thus they act more like keywords than like ordinary identifiers; unlike a keyword however, a redefinition may `shadow`:idx: the definition in -the `system` module. From this list the following should not be written in dot +the system_ module. From this list the following should not be written in dot notation `x.f` since `x` cannot be type-checked before it gets passed to `f`:: @@ -4059,7 +4060,7 @@ Multi-methods -------------- **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -`--multimethods:on` when compiling. +``--multimethods:on`` when compiling. In a multi-method, all parameters that have an object type are used for the dispatching: @@ -4768,7 +4769,7 @@ And so is: The reason for this is that `DivByZeroDefect` inherits from `Defect` and -with `--panics:on` Defects become unrecoverable errors. +with ``--panics:on`` Defects become unrecoverable errors. (Since version 1.4 of the language.) @@ -5567,7 +5568,7 @@ However, this means that the method call syntax is not available for **Note**: The Nim compiler prior to version 1 was more lenient about this -requirement. Use the `--useVersion:0.19` switch for a transition period. +requirement. Use the ``--useVersion:0.19`` switch for a transition period. @@ -6022,7 +6023,7 @@ A module may gain access to symbols of another module by the `import`:idx: statement. `Recursive module dependencies`:idx: are allowed, but are slightly subtle. Only top-level symbols that are marked with an asterisk (`*`) are exported. A valid module name can only be a valid Nim identifier (and thus its -filename is `identifier.nim`). +filename is ``identifier.nim``). The algorithm for compiling modules is: @@ -6484,7 +6485,7 @@ asmNoStackFrame pragma A proc can be marked with the `asmNoStackFrame` pragma to tell the compiler it should not generate a stack frame for the proc. There are also no exit statements like `return result;` generated and the generated C function is -declared as `__declspec(naked)` or `__attribute__((naked))` (depending on +declared as `__declspec(naked)`:c: or `__attribute__((naked))`:c: (depending on the used C compiler). **Note**: This pragma should only be used by procs which consist solely of @@ -6879,7 +6880,7 @@ This pragma has no effect on the JS backend. Volatile pragma --------------- The `volatile` pragma is for variables only. It declares the variable as -`volatile`, whatever that means in C/C++ (its semantics are not well defined +`volatile`:c:, whatever that means in C/C++ (its semantics are not well defined in C/C++). **Note**: This pragma will not exist for the LLVM backend. @@ -6906,7 +6907,7 @@ Header pragma ------------- The `header` pragma is very similar to the `nodecl` pragma: It can be applied to almost any symbol and specifies that it should not be declared -and instead, the generated code should contain an `#include`: +and instead, the generated code should contain an `#include`:c:\: .. code-block:: Nim type @@ -6915,8 +6916,8 @@ and instead, the generated code should contain an `#include`: The `header` pragma always expects a string constant. The string constant contains the header file: As usual for C, a system header file is enclosed -in angle brackets: `<>`. If no angle brackets are given, Nim -encloses the header file in `""` in the generated C code. +in angle brackets: `<>`:c:. If no angle brackets are given, Nim +encloses the header file in `""`:c: in the generated C code. **Note**: This will not work for the LLVM backend. @@ -6924,7 +6925,7 @@ encloses the header file in `""` in the generated C code. IncompleteStruct pragma ----------------------- The `incompleteStruct` pragma tells the compiler to not use the -underlying C `struct` in a `sizeof` expression: +underlying C `struct`:c: in a `sizeof` expression: .. code-block:: Nim type @@ -6941,8 +6942,8 @@ with the project: {.compile: "myfile.cpp".} **Note**: Nim computes a SHA1 checksum and only recompiles the file if it -has changed. One can use the `-f` command-line option to force the recompilation -of the file. +has changed. One can use the ``-f`` command-line option to force +the recompilation of the file. Since 1.4 the `compile` pragma is also available with this syntax: @@ -6964,7 +6965,7 @@ The `link` pragma can be used to link an additional file with the project: PassC pragma ------------ The `passc` pragma can be used to pass additional parameters to the C -compiler like one would using the command-line switch `--passc`: +compiler like one would using the command-line switch ``--passc``: .. code-block:: Nim {.passc: "-Wall -Werror".} @@ -6992,7 +6993,7 @@ the pragma resides in: PassL pragma ------------ The `passL` pragma can be used to pass additional parameters to the linker -like one would be using the command-line switch `--passL`: +like one would be using the command-line switch ``--passL``: .. code-block:: Nim {.passL: "-lSDLmain -lSDL".} @@ -7029,7 +7030,7 @@ Example: embedsC() `nimbase.h` defines `NIM_EXTERNC` C macro that can be used for -`extern "C"` code to work with both `nim c` and `nim cpp`, e.g.: +`extern "C"`:cpp: code to work with both `nim c` and `nim cpp`, e.g.: .. code-block:: Nim proc foobar() {.importc:"$1".} @@ -7044,8 +7045,8 @@ Example: This usage is however deprecated. For a top-level emit statement, the section where in the generated C/C++ file -the code should be emitted can be influenced via the -prefixes `/*TYPESECTION*/` or `/*VARSECTION*/` or `/*INCLUDESECTION*/`: +the code should be emitted can be influenced via the prefixes +`/*TYPESECTION*/`:c: or `/*VARSECTION*/`:c: or `/*INCLUDESECTION*/`:c:\: .. code-block:: Nim {.emit: """/*TYPESECTION*/ @@ -7075,7 +7076,7 @@ Similar to the `importc pragma for C <#foreign-function-interface-importc-pragma>`_, the `importcpp` pragma can be used to import `C++`:idx: methods or C++ symbols in general. The generated code then uses the C++ method calling -syntax: `obj->method(arg)`. In combination with the `header` and `emit` +syntax: `obj->method(arg)`:cpp:. In combination with the `header` and `emit` pragmas this allows *sloppy* interfacing with libraries written in C++: .. code-block:: Nim @@ -7105,16 +7106,16 @@ pragmas this allows *sloppy* interfacing with libraries written in C++: proc run(device: IrrlichtDevice): bool {. header: irr, importcpp: "#.run(@)".} -The compiler needs to be told to generate C++ (command `cpp`) for +The compiler needs to be told to generate C++ (command ``cpp``) for this to work. The conditional symbol `cpp` is defined when the compiler emits C++ code. Namespaces ~~~~~~~~~~ -The *sloppy interfacing* example uses `.emit` to produce `using namespace` +The *sloppy interfacing* example uses `.emit` to produce `using namespace`:cpp: declarations. It is usually much better to instead refer to the imported name -via the `namespace::identifier` notation: +via the `namespace::identifier`:cpp: notation: .. code-block:: nim type @@ -7126,7 +7127,8 @@ Importcpp for enums ~~~~~~~~~~~~~~~~~~~ When `importcpp` is applied to an enum type the numerical enum values are -annotated with the C++ enum type, like in this example: `((TheCppEnum)(3))`. +annotated with the C++ enum type, like in this example: +`((TheCppEnum)(3))`:cpp:. (This turned out to be the simplest way to implement it.) @@ -7136,10 +7138,11 @@ Importcpp for procs Note that the `importcpp` variant for procs uses a somewhat cryptic pattern language for maximum flexibility: -- A hash `#` symbol is replaced by the first or next argument. -- A dot following the hash `#.` indicates that the call should use C++'s dot +- A hash ``#`` symbol is replaced by the first or next argument. +- A dot following the hash ``#.`` indicates that the call should use C++'s dot or arrow notation. -- An at symbol `@` is replaced by the remaining arguments, separated by commas. +- An at symbol ``@`` is replaced by the remaining arguments, + separated by commas. For example: @@ -7155,7 +7158,7 @@ Produces: As a special rule to keep backward compatibility with older versions of the `importcpp` pragma, if there is no special pattern -character (any of `# ' @`) at all, C++'s +character (any of ``# ' @``) at all, C++'s dot or arrow notation is assumed, so the above example can also be written as: .. code-block:: nim @@ -7169,11 +7172,11 @@ capabilities: proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".} -- An apostrophe `'` followed by an integer `i` in the range 0..9 +- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9 is replaced by the i'th parameter *type*. The 0th position is the result type. This can be used to pass types to C++ function templates. Between - the `'` and the digit, an asterisk can be used to get to the base type - of the type. (So it "takes away a star" from the type; `T*` becomes `T`.) + the ``'`` and the digit, an asterisk can be used to get to the base type + of the type. (So it "takes away a star" from the type; `T*`:c: becomes `T`.) Two stars can be used to get to the element type of the element type etc. For example: @@ -7191,12 +7194,12 @@ Produces: x = SystemManager::getSubsystem() -- `#@` is a special case to support a `cnew` operation. It is required so +- ``#@`` is a special case to support a `cnew` operation. It is required so that the call expression is inlined directly, without going through a temporary location. This is only required to circumvent a limitation of the current code generator. -For example C++'s `new` operator can be "imported" like this: +For example C++'s `new`:cpp: operator can be "imported" like this: .. code-block:: nim proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.} @@ -7211,7 +7214,7 @@ Produces: .. code-block:: C x = new Foo(3, 4) -However, depending on the use case `new Foo` can also be wrapped like this +However, depending on the use case `new Foo`:cpp: can also be wrapped like this instead: .. code-block:: nim @@ -7224,7 +7227,8 @@ Wrapping constructors ~~~~~~~~~~~~~~~~~~~~~ Sometimes a C++ class has a private copy constructor and so code like -`Class c = Class(1,2);` must not be generated but instead `Class c(1,2);`. +`Class c = Class(1,2);`:cpp: must not be generated but instead +`Class c(1,2);`:cpp:. For this purpose the Nim proc that wraps a C++ constructor needs to be annotated with the `constructor`:idx: pragma. This pragma also helps to generate faster C++ code since construction then doesn't invoke the copy constructor: @@ -7298,7 +7302,7 @@ ImportJs pragma Similar to the `importcpp pragma for C++ <#implementation-specific-pragmas-importcpp-pragma>`_, the `importjs` pragma can be used to import Javascript methods or symbols in general. The generated code then uses the Javascript method -calling syntax: `obj.method(arg)`. +calling syntax: ``obj.method(arg)``. ImportObjC pragma @@ -7306,7 +7310,7 @@ ImportObjC pragma Similar to the `importc pragma for C <#foreign-function-interface-importc-pragma>`_, the `importobjc` pragma can be used to import `Objective C`:idx: methods. The generated code then uses the -Objective C method calling syntax: `[obj method param1: arg]`. +Objective C method calling syntax: ``[obj method param1: arg]``. In addition with the `header` and `emit` pragmas this allows *sloppy* interfacing with libraries written in Objective C: @@ -7346,8 +7350,8 @@ allows *sloppy* interfacing with libraries written in Objective C: g.greet(12, 34) g.free() -The compiler needs to be told to generate Objective C (command `objc`) for -this to work. The conditional symbol `objc` is defined when the compiler +The compiler needs to be told to generate Objective C (command ``objc``) for +this to work. The conditional symbol ``objc`` is defined when the compiler emits Objective C code. @@ -7392,7 +7396,7 @@ will generate this code: The `.cppNonPod` pragma should be used for non-POD `importcpp` types so that they work properly (in particular regarding constructor and destructor) for -`.threadvar` variables. This requires `--tlsEmulation:off`. +`.threadvar` variables. This requires ``--tlsEmulation:off``. .. code-block:: nim type Foo {.cppNonPod, importcpp, header: "funs.h".} = object @@ -7436,12 +7440,12 @@ pragma description :: nim c -d:FooBar=42 foobar.nim -In the above example, providing the -d flag causes the symbol +In the above example, providing the ``-d`` flag causes the symbol `FooBar` to be overwritten at compile-time, printing out 42. If the -`-d:FooBar=42` were to be omitted, the default value of 5 would be +``-d:FooBar=42`` were to be omitted, the default value of 5 would be used. To see if a value was provided, `defined(FooBar)` can be used. -The syntax `-d:flag` is actually just a shortcut for `-d:flag=true`. +The syntax ``-d:flag`` is actually just a shortcut for ``-d:flag=true``. User-defined pragmas ==================== @@ -7604,7 +7608,7 @@ spelled*: proc printf(formatstr: cstring) {.header: "", importc: "printf", varargs.} When `importc` is applied to a `let` statement it can omit its value which -will then be expected to come from C. This can be used to import a C `const`: +will then be expected to come from C. This can be used to import a C `const`:c:\: .. code-block:: {.emit: "const int cconst = 42;".} @@ -7625,8 +7629,8 @@ is not set to C, other pragmas are available: .. code-block:: Nim proc p(s: cstring) {.importc: "prefix$1".} -In the example, the external name of `p` is set to `prefixp`. Only `$1` -is available and a literal dollar sign must be written as `$$`. +In the example, the external name of `p` is set to `prefixp`. Only ``$1`` +is available and a literal dollar sign must be written as ``$$``. Exportc pragma @@ -7648,8 +7652,8 @@ The string literal passed to `exportc` can be a format string: proc p(s: string) {.exportc: "prefix$1".} = echo s -In the example, the external name of `p` is set to `prefixp`. Only `$1` -is available and a literal dollar sign must be written as `$$`. +In the example, the external name of `p` is set to `prefixp`. Only ``$1`` +is available and a literal dollar sign must be written as ``$$``. If the symbol should also be exported to a dynamic library, the `dynlib` pragma should be used in addition to the `exportc` pragma. See @@ -7665,8 +7669,8 @@ mangling. The string literal passed to `extern` can be a format string: proc p(s: string) {.extern: "prefix$1".} = echo s -In the example, the external name of `p` is set to `prefixp`. Only `$1` -is available and a literal dollar sign must be written as `$$`. +In the example, the external name of `p` is set to `prefixp`. Only ``$1`` +is available and a literal dollar sign must be written as ``$$``. Bycopy pragma @@ -7704,8 +7708,8 @@ strings automatically: Union pragma ------------ The `union` pragma can be applied to any `object` type. It means all -of the object's fields are overlaid in memory. This produces a `union` -instead of a `struct` in the generated C/C++ code. The object declaration +of the object's fields are overlaid in memory. This produces a `union`:c: +instead of a `struct`:c: in the generated C/C++ code. The object declaration then must not use inheritance or any GC'ed memory but this is currently not checked. @@ -7728,7 +7732,7 @@ a static error. Usage with inheritance should be defined and documented. Dynlib pragma for import ------------------------ With the `dynlib` pragma, a procedure or a variable can be imported from -a dynamic library (`.dll` files for Windows, `lib*.so` files for UNIX). +a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The non-optional argument has to be the name of the dynamic library: .. code-block:: Nim @@ -7771,14 +7775,14 @@ string expressions in general: proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} -**Note**: Patterns like `libtcl(|8.5|8.4).so` are only supported in constant +**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant strings, because they are precompiled. **Note**: Passing variables to the `dynlib` pragma will fail at runtime because of order of initialization problems. **Note**: A `dynlib` import can be overridden with -the `--dynlibOverride:name` command-line option. The +the ``--dynlibOverride:name`` command-line option. The `Compiler User Guide `_ contains further information. @@ -7793,15 +7797,15 @@ conjunction with the `exportc` pragma: proc exportme(): int {.cdecl, exportc, dynlib.} This is only useful if the program is compiled as a dynamic library via the -`--app:lib` command-line option. +``--app:lib`` command-line option. Threads ======= -To enable thread support the `--threads:on` command-line switch needs to -be used. The `system` module then contains several threading primitives. +To enable thread support the ``--threads:on`` command-line switch needs to +be used. The system_ module then contains several threading primitives. See the `threads `_ and `channels `_ modules for the low-level thread API. There are also high-level parallelism constructs available. See `spawn `_ for @@ -7842,7 +7846,7 @@ any of its parameters contain a `ref` or `closure` type. This enforces the *no heap sharing restriction*. Routines that are imported from C are always assumed to be `gcsafe`. -To disable the GC-safety checking the `--threadAnalysis:off` command-line +To disable the GC-safety checking the ``--threadAnalysis:off`` command-line switch can be used. This is a temporary workaround to ease the porting effort from old code to the new threading model. diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.rst index e34993e3e..f5c5bc4c0 100644 --- a/doc/manual/var_t_return.rst +++ b/doc/manual/var_t_return.rst @@ -1,4 +1,5 @@ .. default-role:: code +.. include:: ../rstcommon.rst Memory safety for returning by `var T` is ensured by a simple borrowing rule: If `result` does not refer to a location pointing to the heap diff --git a/doc/rstcommon.rst b/doc/rstcommon.rst new file mode 100644 index 000000000..c1503fa96 --- /dev/null +++ b/doc/rstcommon.rst @@ -0,0 +1,6 @@ + +.. role:: nim(code) + :language: nim + +.. default-role:: nim + diff --git a/doc/sets_fragment.txt b/doc/sets_fragment.txt index 8436190a0..84e2fe8c1 100644 --- a/doc/sets_fragment.txt +++ b/doc/sets_fragment.txt @@ -1,13 +1,13 @@ The set type models the mathematical notion of a set. The set's basetype can only be an ordinal type of a certain size, namely: -* ``int8``-``int16`` -* ``uint8``/``byte``-``uint16`` -* ``char`` -* ``enum`` +* `int8`-`int16` +* `uint8`/`byte`-`uint16` +* `char` +* `enum` or equivalent. For signed integers the set's base type is defined to be in the -range ``0 .. MaxSetElements-1`` where ``MaxSetElements`` is currently always +range `0 .. MaxSetElements-1` where `MaxSetElements` is currently always 2^16. The reason is that sets are implemented as high performance bit vectors. @@ -17,7 +17,7 @@ Attempting to declare a set with a larger type will result in an error: var s: set[int64] # Error: set is too large -Sets can be constructed via the set constructor: ``{}`` is the empty set. The +Sets can be constructed via the set constructor: `{}` is the empty set. The empty set is type compatible with any concrete set type. The constructor can also be used to include elements (and ranges of elements): @@ -35,18 +35,18 @@ These operations are supported by sets: ================== ======================================================== operation meaning ================== ======================================================== -``A + B`` union of two sets -``A * B`` intersection of two sets -``A - B`` difference of two sets (A without B's elements) -``A == B`` set equality -``A <= B`` subset relation (A is subset of B or equal to B) -``A < B`` strict subset relation (A is a proper subset of B) -``e in A`` set membership (A contains element e) -``e notin A`` A does not contain element e -``contains(A, e)`` A contains element e -``card(A)`` the cardinality of A (number of elements in A) -``incl(A, elem)`` same as ``A = A + {elem}`` -``excl(A, elem)`` same as ``A = A - {elem}`` +`A + B` union of two sets +`A * B` intersection of two sets +`A - B` difference of two sets (A without B's elements) +`A == B` set equality +`A <= B` subset relation (A is subset of B or equal to B) +`A < B` strict subset relation (A is a proper subset of B) +`e in A` set membership (A contains element e) +`e notin A` A does not contain element e +`contains(A, e)` A contains element e +`card(A)` the cardinality of A (number of elements in A) +`incl(A, elem)` same as `A = A + {elem}` +`excl(A, elem)` same as `A = A - {elem}` ================== ======================================================== Bit fields @@ -54,7 +54,7 @@ Bit fields Sets are often used to define a type for the *flags* of a procedure. This is a cleaner (and type safe) solution than defining integer -constants that have to be ``or``'ed together. +constants that have to be `or`'ed together. Enum, sets and casting can be used together as in: diff --git a/doc/tut1.rst b/doc/tut1.rst index cca4e8c0e..8d80a0520 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ===================== Nim Tutorial (Part I) ===================== @@ -7,6 +5,8 @@ Nim Tutorial (Part I) :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: Introduction @@ -48,7 +48,7 @@ Save this code to the file "greetings.nim". Now compile and run it:: nim compile --run greetings.nim -With the `--run` `switch `_ Nim +With the ``--run`` `switch `_ Nim executes the file automatically after compilation. You can give your program command-line arguments by appending them after the filename:: @@ -63,12 +63,12 @@ To compile a release version use:: nim c -d:release greetings.nim By default, the Nim compiler generates a large number of runtime checks -aiming for your debugging pleasure. With `-d:release` some checks are +aiming for your debugging pleasure. With ``-d:release`` some checks are `turned off and optimizations are turned on `_. -For benchmarking or production code, use the `-d:release` switch. -For comparing the performance with unsafe languages like C, use the `-d:danger` switch +For benchmarking or production code, use the ``-d:release`` switch. +For comparing the performance with unsafe languages like C, use the ``-d:danger`` switch in order to get meaningful, comparable results. Otherwise Nim might be handicapped by checks that are **not even available** for C. @@ -535,7 +535,7 @@ differences: that belong to the first condition that evaluates to `true`. The `when` statement is useful for writing platform-specific code, similar to -the `#ifdef` construct in the C programming language. +the `#ifdef`:c: construct in the C programming language. Statements and indentation @@ -596,7 +596,7 @@ Procedures To define new commands like `echo `_ and `readLine `_ in the examples, the concept of a -`procedure` is needed. (Some languages call them *methods* or *functions*.) +*procedure* is needed. (Some languages call them *methods* or *functions*.) In Nim new procedures are defined with the `proc` keyword: .. code-block:: nim @@ -802,7 +802,7 @@ Operators --------- The Nim library makes heavy use of overloading - one reason for this is that each operator like `+` is just an overloaded proc. The parser lets you -use operators in `infix notation` (`a + b`) or `prefix notation` (`+ a`). +use operators in *infix notation* (`a + b`) or *prefix notation* (`+ a`). An infix operator always receives two arguments, a prefix operator always one. (Postfix operators are not possible, because this would be ambiguous: does `a @ @ b` mean `(a) @ (@b)` or `(a@) @ (b)`? It always means @@ -810,7 +810,7 @@ An infix operator always receives two arguments, a prefix operator always one. Apart from a few built-in keyword operators such as `and`, `or`, `not`, operators always consist of these characters: -``+ - * \ / < > = @ $ ~ & % ! ? ^ . |`` +`+ - * \ / < > = @ $ ~ & % ! ? ^ . |` User-defined operators are allowed. Nothing stops you from defining your own `@!?+~` operator, but doing so may reduce readability. @@ -952,7 +952,7 @@ evaluation. For example: Characters ---------- -The `character type` is called `char`. Its size is always one byte, so +The *character type* is called `char`. Its size is always one byte, so it cannot represent most UTF-8 characters, but it *can* represent one of the bytes that makes up a multi-byte UTF-8 character. The reason for this is efficiency: for the overwhelming majority of use-cases, @@ -1220,7 +1220,7 @@ Arrays can be constructed using `[]`: The notation `x[i]` is used to access the i-th element of `x`. Array access is always bounds checked (at compile-time or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -`--bound_checks:off` command line switch. +``--bound_checks:off`` command line switch. Arrays are value types, like any other Nim type. The assignment operator copies the whole array contents. @@ -1620,11 +1620,11 @@ variables! For example: path = "usr/local/nimc.html" (dir, name, ext) = splitFile(path) baddir, badname, badext = splitFile(path) - echo dir # outputs `usr/local` - echo name # outputs `nimc` - echo ext # outputs `.html` + echo dir # outputs "usr/local" + echo name # outputs "nimc" + echo ext # outputs ".html" # All the following output the same line: - # `(dir: usr/local, name: nimc, ext: .html)` + # "(dir: usr/local, name: nimc, ext: .html)" echo baddir echo badname echo badext @@ -1711,7 +1711,7 @@ Examples are provided in the `manual `_. Modules ======= -Nim supports splitting a program into pieces with a module concept. +Nim supports splitting a program into pieces with a *module* concept. Each module is in its own file. Modules enable `information hiding`:idx: and `separate compilation`:idx:. A module may gain access to the symbols of another module by using the `import`:idx: statement. Only top-level symbols that are marked diff --git a/doc/tut2.rst b/doc/tut2.rst index 3aef6bb0f..2624b2690 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ====================== Nim Tutorial (Part II) ====================== @@ -7,6 +5,8 @@ Nim Tutorial (Part II) :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: @@ -175,7 +175,8 @@ Method call syntax ------------------ There is a syntactic sugar for calling routines: -The syntax `obj.method(args)` can be used instead of `method(obj, args)`. +The syntax `obj.methodName(args)` can be used +instead of `methodName(obj, args)`. If there are no remaining arguments, the parentheses can be omitted: `obj.len` (instead of `len(obj)`). @@ -296,7 +297,7 @@ because it makes more sense for them to use static binding, but `eval` is a method because it requires dynamic binding. **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -`--multimethods:on` when compiling. +``--multimethods:on`` when compiling. In a multi-method all parameters that have an object type are used for the dispatching: @@ -459,7 +460,7 @@ If you want to add the `{.raises.}` pragma to existing code, the compiler can also help you. You can add the `{.effects.}` pragma statement to your proc and the compiler will output all inferred effects up to that point (exception tracking is part of Nim's effect system). Another more roundabout way to -find out the list of exceptions raised by a proc is to use the Nim `doc` +find out the list of exceptions raised by a proc is to use the Nim ``doc`` command which generates documentation for a whole module and decorates all procs with the list of raised exceptions. You can read more about Nim's `effect system and related pragmas in the manual `_. diff --git a/doc/tut3.rst b/doc/tut3.rst index 358a9b45e..6b5a3b5ca 100644 --- a/doc/tut3.rst +++ b/doc/tut3.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ======================= Nim Tutorial (Part III) ======================= @@ -7,6 +5,8 @@ Nim Tutorial (Part III) :Author: Arne Döring :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: From a5b30c94c2dcd0f17b37685d9ce96eee959ba554 Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Sun, 11 Apr 2021 12:07:23 +0100 Subject: [PATCH 2398/4254] [feature] add arbitrary code execution to strformat (#17694) * changed parser to ignore ':' within parens * Update strformat.nim * Update lib/pure/strformat.nim Co-authored-by: flywind Co-authored-by: Andreas Rumpf --- lib/pure/strformat.nim | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 7ab359038..c232c8a46 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -74,6 +74,20 @@ runnableExamples: assert fmt"{123.456:13e}" == " 1.234560e+02" ##[ +# Expressions +]## +runnableExamples: + let x = 3.14 + assert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847" + assert fmt"""{(block: + var res: string + for i in 1..15: + res.add (if i mod 15 == 0: "FizzBuzz" + elif i mod 5 == 0: "Buzz" + elif i mod 3 == 0: "Fizz" + else: $i) & " " + res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz " +##[ # Debugging strings `fmt"{expr=}"` expands to `fmt"expr={expr}"` namely the text of the expression, @@ -557,7 +571,7 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = # XXX: https://github.com/nim-lang/Nim/issues/8405 # When compiling with -d:useNimRtl, certain procs such as `count` from the strutils # module are not accessible at compile-time: - let expectedGrowth = when defined(useNimRtl): 0 else: count(f, '{') * 10 + let expectedGrowth = when defined(useNimRtl): 0 else: count(f, openChar) * 10 result.add newVarStmt(res, newCall(bindSym"newStringOfCap", newLit(f.len + expectedGrowth))) var strlit = "" @@ -573,8 +587,12 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = strlit = "" var subexpr = "" - while i < f.len and f[i] != closeChar and f[i] != ':': - if f[i] == '=': + var inParens = 0 + while i < f.len and f[i] != closeChar and (f[i] != ':' or inParens!=0): + case f[i] + of '(': inc inParens + of ')': dec inParens + of '=': let start = i inc i i += f.skipWhitespace(i) @@ -582,10 +600,11 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i])) else: subexpr.add f[start ..< i] - else: - subexpr.add f[i] - inc i - + continue + else: discard + subexpr.add f[i] + inc i + var x: NimNode try: x = parseExpr(subexpr) @@ -608,11 +627,11 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = doAssert false, "invalid format string: missing '}'" result.add newCall(formatSym, res, x, newLit(options)) elif f[i] == closeChar: - if f[i+1] == closeChar: + if i Date: Sun, 11 Apr 2021 07:25:41 -0500 Subject: [PATCH 2399/4254] iterable[T] (#17196) * fix failing test toSeq in manual which now works * changelog * reject proc fn(a: iterable) * add iterable to spec * remove MCS/UFCS limitation that now works --- changelog.md | 5 + compiler/ast.nim | 6 +- compiler/condsyms.nim | 1 + compiler/jsgen.nim | 2 +- compiler/liftdestructors.nim | 2 +- compiler/linter.nim | 2 +- compiler/semcall.nim | 10 +- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 9 +- compiler/semtypes.nim | 13 +++ compiler/sigmatch.nim | 31 ++++-- compiler/typeallowed.nim | 3 + compiler/types.nim | 11 ++- compiler/vmdeps.nim | 1 + doc/manual.rst | 43 +++++---- lib/system.nim | 4 + testament/lib/stdtest/testutils.nim | 6 ++ tests/types/titerable.nim | 143 ++++++++++++++++++++++++++++ 18 files changed, 254 insertions(+), 40 deletions(-) create mode 100644 tests/types/titerable.nim diff --git a/changelog.md b/changelog.md index a2879833f..2f1d2d816 100644 --- a/changelog.md +++ b/changelog.md @@ -302,6 +302,10 @@ - `nim e` now accepts arbitrary file extensions for the nimscript file, although `.nims` is still the preferred extension in general. +- Added `iterable[T]` type class to match called iterators, which enables writing: + `template fn(a: iterable)` instead of `template fn(a: untyped)` + + ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. @@ -341,6 +345,7 @@ - `--hint:CC` now goes to stderr (like all other hints) instead of stdout. + ## Tool changes - The rst parser now supports markdown table syntax. diff --git a/compiler/ast.nim b/compiler/ast.nim index fffe08cb7..155af6375 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -440,10 +440,12 @@ type tyVoid # now different from tyEmpty, hurray! + tyIterable static: # remind us when TTypeKind stops to fit in a single 64-bit word - assert TTypeKind.high.ord <= 63 + # assert TTypeKind.high.ord <= 63 + discard const tyPureObject* = tyTuple @@ -664,7 +666,7 @@ type mDefault, mUnown, mIsolate, mAccessEnv, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, - mOrdinal, + mOrdinal, mIterableType, mInt, mInt8, mInt16, mInt32, mInt64, mUInt, mUInt8, mUInt16, mUInt32, mUInt64, mFloat, mFloat32, mFloat64, mFloat128, diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 9ba97a8ed..bdecd7e53 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -132,3 +132,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasSpellSuggest") defineSymbol("nimHasCustomLiterals") defineSymbol("nimHasUnifiedTuple") + defineSymbol("nimHasIterable") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 3fc7708bf..ca716b1c0 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -211,7 +211,7 @@ proc mapType(typ: PType): TJSTypeKind = else: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString - of tyConcept: doAssert false + of tyConcept, tyIterable: doAssert false proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index bb24fed34..436665827 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -908,7 +908,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = of tyOrdinal, tyRange, tyInferred, tyGenericInst, tyAlias, tySink: fillBody(c, lastSon(t), body, x, y) - of tyConcept: doAssert false + of tyConcept, tyIterable: doAssert false proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo; diff --git a/compiler/linter.nim b/compiler/linter.nim index 9af4f468e..83dd84699 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -40,7 +40,7 @@ proc beautifyName(s: string, k: TSymKind): string = "pointer", "float", "csize", "csize_t", "cdouble", "cchar", "cschar", "cshort", "cu", "nil", "typedesc", "auto", "any", "range", "openarray", "varargs", "set", "cfloat", "ref", "ptr", - "untyped", "typed", "static", "sink", "lent", "type", "owned"]: + "untyped", "typed", "static", "sink", "lent", "type", "owned", "iterable"]: result.add s[i] else: result.add toUpperAscii(s[i]) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 99979c382..8f29bdf32 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -62,7 +62,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, best, alt: var TCandidate, errors: var CandidateErrors, diagnosticsFlag: bool, - errorsEnabled: bool) = + errorsEnabled: bool, flags: TExprFlags) = var o: TOverloadIter var sym = initOverloadIter(o, c, headSymbol) var scope = o.lastOverloadScope @@ -95,7 +95,11 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, matches(c, n, orig, z) if z.state == csMatch: # little hack so that iterators are preferred over everything else: - if sym.kind == skIterator: inc(z.exactMatches, 200) + if sym.kind == skIterator: + if not (efWantIterator notin flags and efWantIterable in flags): + inc(z.exactMatches, 200) + else: + dec(z.exactMatches, 200) case best.state of csEmpty, csNoMatch: best = z of csMatch: @@ -356,7 +360,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, template pickBest(headSymbol) = pickBestCandidate(c, headSymbol, n, orig, initialBinding, filter, result, alt, errors, efExplain in flags, - errorsEnabled) + errorsEnabled, flags) pickBest(f) let overloadsState = result.state diff --git a/compiler/semdata.nim b/compiler/semdata.nim index c655047e2..51b2cdea1 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -54,7 +54,7 @@ type inst*: PInstantiation TExprFlag* = enum - efLValue, efWantIterator, efInTypeof, + efLValue, efWantIterator, efWantIterable, efInTypeof, efNeedStatic, # Use this in contexts where a static value is mandatory efPreferStatic, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c0aa168ef..256c008c9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -853,7 +853,7 @@ proc semStaticExpr(c: PContext, n: PNode): PNode = proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, flags: TExprFlags): PNode = - if flags*{efInTypeof, efWantIterator} != {}: + if flags*{efInTypeof, efWantIterator, efWantIterable} != {}: # consider: 'for x in pReturningArray()' --> we don't want the restriction # to 'skIterator' anymore; skIterator is preferred in sigmatch already # for typeof support. @@ -877,6 +877,11 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, # error correction, prevents endless for loop elimination in transf. # See bug #2051: result[0] = newSymNode(errorSym(c, n)) + elif callee.kind == skIterator: + if efWantIterable in flags: + let typ = newTypeS(tyIterable, c) + rawAddSon(typ, result.typ) + result.typ = typ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode @@ -1364,7 +1369,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = onUse(n[1].info, s) return - n[0] = semExprWithType(c, n[0], flags+{efDetermineType}) + n[0] = semExprWithType(c, n[0], flags+{efDetermineType, efWantIterable}) #restoreOldStyleType(n[0]) var i = considerQuotedIdent(c, n[1], n) var ty = n[0].typ diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index b34dc36e3..34a90a3f2 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -356,6 +356,15 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, errArrayExpectsTwoTypeParams) result = newOrPrevType(tyError, prev, c) +proc semIterableType(c: PContext, n: PNode, prev: PType): PType = + result = newOrPrevType(tyIterable, prev, c) + if n.len == 2: + let base = semTypeNode(c, n[1], nil) + addSonSkipIntLit(result, base, c.idgen) + else: + localError(c.config, n.info, errXExpectsOneTypeParam % "iterable") + result = newOrPrevType(tyError, prev, c) + proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyOrdinal, prev, c) if n.len == 2: @@ -1844,6 +1853,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of mRange: result = semRange(c, n, prev) of mSet: result = semSet(c, n, prev) of mOrdinal: result = semOrdinal(c, n, prev) + of mIterableType: result = semIterableType(c, n, prev) of mSeq: result = semContainer(c, n, tySequence, "seq", prev) if optSeqDestructors in c.config.globalOptions: @@ -2067,6 +2077,9 @@ proc processMagicType(c: PContext, m: PSym) = of mOrdinal: setMagicIntegral(c.config, m, tyOrdinal, szUncomputedSize) rawAddSon(m.typ, newTypeS(tyNone, c)) + of mIterableType: + setMagicIntegral(c.config, m, tyIterable, 0) + rawAddSon(m.typ, newTypeS(tyNone, c)) of mPNimrodNode: incl m.typ.flags, tfTriggersCompileTime incl m.typ.flags, tfCheckedForDestructor diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 87f7c273b..767f34dda 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1119,6 +1119,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return if x >= isGeneric: isGeneric else: x return isNone + of tyIterable: + if f.kind != tyIterable: return isNone of tyNot: case f.kind of tyNot: @@ -1421,6 +1423,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyAlias, tySink: result = typeRel(c, lastSon(f), a, flags) + of tyIterable: + if a.kind == tyIterable: + if f.len == 1: + result = typeRel(c, lastSon(f), lastSon(a), flags) + else: + # f.len = 3, for some reason + result = isGeneric + else: + result = isNone of tyGenericInst: var prev = PType(idTableGet(c.bindings, f)) let origF = f @@ -2270,14 +2281,18 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode = # a.typ == nil is valid result = a elif a.typ.isNil: - # XXX This is unsound! 'formal' can differ from overloaded routine to - # overloaded routine! - let flags = {efDetermineType, efAllowStmt} - #if formal.kind == tyIter: {efDetermineType, efWantIterator} - #else: {efDetermineType, efAllowStmt} - #elif formal.kind == tyTyped: {efDetermineType, efWantStmt} - #else: {efDetermineType} - result = c.semOperand(c, a, flags) + if formal.kind == tyIterable: + let flags = {efDetermineType, efAllowStmt, efWantIterator, efWantIterable} + result = c.semOperand(c, a, flags) + else: + # XXX This is unsound! 'formal' can differ from overloaded routine to + # overloaded routine! + let flags = {efDetermineType, efAllowStmt} + #if formal.kind == tyIterable: {efDetermineType, efWantIterator} + #else: {efDetermineType, efAllowStmt} + #elif formal.kind == tyTyped: {efDetermineType, efWantStmt} + #else: {efDetermineType} + result = c.semOperand(c, a, flags) else: result = a considerGenSyms(c, result) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 9075d9e38..270e7c028 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -97,6 +97,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = nil of tyUntyped, tyTyped: if kind notin {skParam, skResult} or taNoUntyped in flags: result = t + of tyIterable: + if kind notin {skParam} or taNoUntyped in flags: result = t + # tyIterable is only for templates and macros. of tyStatic: if kind notin {skParam}: result = t of tyVoid: diff --git a/compiler/types.nim b/compiler/types.nim index 1dbbc3261..ce4812506 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -460,8 +460,8 @@ const "lent ", "varargs[$1]", "UncheckedArray[$1]", "Error Type", "BuiltInTypeClass", "UserTypeClass", "UserTypeClassInst", "CompositeTypeClass", "inferred", - "and", "or", "not", "any", "static", "TypeFromExpr", "out ", - "void"] + "and", "or", "not", "any", "static", "TypeFromExpr", "concept", # xxx bugfix + "void", "iterable"] const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo, preferGenericArg, preferResolved, preferMixed} @@ -645,6 +645,11 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyDistinct: result = "distinct " & typeToString(t[0], if prefer == preferModuleInfo: preferModuleInfo else: preferTypeName) + of tyIterable: + # xxx factor this pattern + result = "iterable" + if t.len > 0: + result &= "[" & typeToString(t[0]) & ']' of tyTuple: # we iterate over t.sons here, because t.n may be nil if t.n != nil: @@ -1191,7 +1196,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameTypeOrNilAux(a[0], b[0], c) and sameValue(a.n[0], b.n[0]) and sameValue(a.n[1], b.n[1]) - of tyGenericInst, tyAlias, tyInferred: + of tyGenericInst, tyAlias, tyInferred, tyIterable: cycleCheck() result = sameTypeAux(a.lastSon, b.lastSon, c) of tyNone: result = false diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index a9157bc03..6191f9459 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -287,6 +287,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyAnd: result = mapTypeToBracket("and", mAnd, t, info) of tyOr: result = mapTypeToBracket("or", mOr, t, info) of tyNot: result = mapTypeToBracket("not", mNot, t, info) + of tyIterable: result = mapTypeToBracket("iterable", mIterableType, t, info) of tyAnything: result = atomicType("anything", mNone) of tyInferred: assert false of tyStatic, tyFromExpr: diff --git a/doc/manual.rst b/doc/manual.rst index 1325d1c5f..ea444a0ac 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2645,6 +2645,28 @@ Varargs matching See `Varargs <#types-varargs>`_. +iterable +-------- + +A called `iterator` yielding type `T` can be passed to a template or macro via +a parameter typed as `untyped` (for unresolved expressions) or the type class +`iterable` or `iterable[T]` (after type checking and overload resolution). + +.. code-block:: nim + iterator iota(n: int): int = + for i in 0..`_ for passing iterators to templates and macros. + Converters ========== @@ -5591,24 +5616,6 @@ is used to invoke templates/macros: unknownIdentifier.declareVar -Another common example is this: - -.. code-block:: nim - :test: "nim c $1" - :status: 1 - - from std/sequtils import toSeq - - iterator something: string = - yield "Hello" - yield "World" - - var info = something().toSeq - -The problem here is that the compiler already decided that `something()` as -an iterator is not callable in this context before `toSeq` gets its -chance to convert it into a sequence. - It is also not possible to use fully qualified identifiers with module symbol in method call syntax. The order in which the dot operator binds to symbols prohibits this. diff --git a/lib/system.nim b/lib/system.nim index bd9ae2762..6e84aca66 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -123,6 +123,10 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## # Do here programmer friendly expensive sanity checks. ## # Put here the normal code +when defined(nimHasIterable): + type + iterable*[T] {.magic: IterableType.} ## Represents an expression that yields `T` + when defined(nimHashOrdinalFixed): type Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 58d136696..abffff24c 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -79,3 +79,9 @@ template whenVMorJs*(bodyIf, bodyElse) = else: when defined(js): bodyIf else: bodyElse + +template accept*(a) = + doAssert compiles(a) + +template reject*(a) = + doAssert not compiles(a) diff --git a/tests/types/titerable.nim b/tests/types/titerable.nim new file mode 100644 index 000000000..b0713961d --- /dev/null +++ b/tests/types/titerable.nim @@ -0,0 +1,143 @@ +discard """ + targets: "c js" +""" + +from stdtest/testutils import accept, reject, whenVMorJs + +# toSeq-like templates + +template toSeq2(a: iterable): auto = + var ret: seq[typeof(a)] + for ai in a: ret.add ai + ret + +template toSeq3(a: iterable[string]): auto = + var ret: seq[typeof(a)] + for ai in a: ret.add ai + ret + +template toSeq4[T](a: iterable[T]): auto = + var ret: seq[typeof(a)] + for ai in a: ret.add ai + ret + +template toSeq5[T: SomeInteger](a: iterable[T]): auto = + var ret: seq[typeof(a)] + for ai in a: ret.add ai + ret + +template toSeq6(a: iterable[int | float]): auto = + var ret: seq[typeof(a)] + for ai in a: ret.add ai + ret + +template toSeq7(a: iterable[seq]): auto = + var ret: seq[typeof(a)] + for ai in a: ret.add ai + ret + +template fn7b(a: untyped) = discard +template fn7c(a: typed) = discard +template fn7d(a: auto) = discard +template fn7e[T](a: T) = discard + +template fn8a(a: iterable) = discard +template fn8b[T](a: iterable[T]) = discard +template fn8c(a: iterable[int]) = discard + +template bad1 = + template fn4(a: int, b: iterable[float, int]) = + discard + +template bad2 = + proc fn4(a: iterable) = discard + +template bad3 = + proc fn4(a: iterable[int]) = discard + +template good4 = + template fn1(a: iterable) = discard + template fn2(a: iterable[int]) = discard + +# iterators +iterator iota(n: int): auto = + for i in 0.. Date: Sun, 11 Apr 2021 17:37:32 +0200 Subject: [PATCH 2400/4254] IC: integrity checking (#17695) * IC: integrity checking: the plumbing code * progress * progress + bugfix (yes, the code already found a bug) * implemented integrity checking --- compiler/ic/bitabs.nim | 4 + compiler/ic/ic.nim | 3 +- compiler/ic/integrity.nim | 151 ++++++++++++++++++++++++++++++++++++++ compiler/main.nim | 4 +- compiler/semdata.nim | 3 + compiler/semstmts.nim | 2 +- koch.nim | 2 +- testament/categories.nim | 2 +- 8 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 compiler/ic/integrity.nim diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim index 1f75b7759..0bce30b5d 100644 --- a/compiler/ic/bitabs.nim +++ b/compiler/ic/bitabs.nim @@ -36,6 +36,10 @@ const template idToIdx(x: LitId): int = x.int - idStart +proc hasLitId*[T](t: BiTable[T]; x: LitId): bool = + let idx = idToIdx(x) + result = idx >= 0 and idx < t.vals.len + proc enlarge[T](t: var BiTable[T]) = var n: seq[LitId] newSeq(n, len(t.keys) * 2) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 46bb63e07..6769c6ffe 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -31,7 +31,7 @@ type moduleFlags: TSymFlags includes: seq[(LitId, string)] # first entry is the module filename itself imports: seq[LitId] # the modules this module depends on - toReplay: PackedTree # pragmas and VM specific state to replay. + toReplay*: PackedTree # pragmas and VM specific state to replay. topLevel*: PackedTree # top level statements bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position. #producedGenerics*: Table[GenericKey, SymId] @@ -167,6 +167,7 @@ proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) = m.exports.add((nameId, s.itemId.item)) proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) = + assert c.thisModule == s.itemId.module m.converters.add(s.itemId.item) proc addTrmacro*(c: var PackedEncoder; m: var PackedModule; s: PSym) = diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim new file mode 100644 index 000000000..b4545de94 --- /dev/null +++ b/compiler/ic/integrity.nim @@ -0,0 +1,151 @@ +# +# +# The Nim Compiler +# (c) Copyright 2021 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Integrity checking for a set of .rod files. +## The set must cover a complete Nim project. + +import std / sets +import ".." / [ast, modulegraphs] +import packed_ast, bitabs, ic + +type + CheckedContext = object + g: ModuleGraph + thisModule: int32 + checkedSyms: HashSet[ItemId] + checkedTypes: HashSet[ItemId] + +proc checkType(c: var CheckedContext; typeId: PackedItemId) +proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) +proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) + +proc checkTypeObj(c: var CheckedContext; typ: PackedType) = + for child in typ.types: + checkType(c, child) + if typ.n != emptyNodeId: + checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos typ.n) + if typ.sym != nilItemId: + checkForeignSym(c, typ.sym) + if typ.owner != nilItemId: + checkForeignSym(c, typ.owner) + checkType(c, typ.typeInst) + +proc checkType(c: var CheckedContext; typeId: PackedItemId) = + if typeId == nilItemId: return + let itemId = translateId(typeId, c.g.packed, c.thisModule, c.g.config) + if not c.checkedTypes.containsOrIncl(itemId): + let oldThisModule = c.thisModule + c.thisModule = itemId.module + checkTypeObj c, c.g.packed[itemId.module].fromDisk.sh.types[itemId.item] + c.thisModule = oldThisModule + +proc checkSym(c: var CheckedContext; s: PackedSym) = + if s.name != LitId(0): + assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId s.name + checkType c, s.typ + if s.ast != emptyNodeId: + checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast) + if s.owner != nilItemId: + checkForeignSym(c, s.owner) + +proc checkLocalSym(c: var CheckedContext; item: int32) = + let itemId = ItemId(module: c.thisModule, item: item) + if not c.checkedSyms.containsOrIncl(itemId): + checkSym c, c.g.packed[c.thisModule].fromDisk.sh.syms[item] + +proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) = + let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config) + if not c.checkedSyms.containsOrIncl(itemId): + let oldThisModule = c.thisModule + c.thisModule = itemId.module + checkSym c, c.g.packed[itemId.module].fromDisk.sh.syms[itemId.item] + c.thisModule = oldThisModule + +proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) = + if tree[n.int].typeId != nilItemId: + checkType(c, tree[n.int].typeId) + case n.kind + of nkEmpty, nkNilLit, nkType, nkNilRodNode: + discard + of nkIdent: + assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId + of nkSym: + checkLocalSym(c, tree.nodes[n.int].operand) + of directIntLit: + discard + of externIntLit: + assert c.g.packed[c.thisModule].fromDisk.sh.integers.hasLitId n.litId + of nkStrLit..nkTripleStrLit: + assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId + of nkFloatLit..nkFloat128Lit: + assert c.g.packed[c.thisModule].fromDisk.sh.floats.hasLitId n.litId + of nkModuleRef: + let (n1, n2) = sons2(tree, n) + assert n1.kind == nkInt32Lit + assert n2.kind == nkInt32Lit + checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)) + else: + for n0 in sonsReadonly(tree, n): + checkNode(c, tree, n0) + +proc checkTree(c: var CheckedContext; t: PackedTree) = + for p in allNodes(t): checkNode(c, t, p) + +proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) = + for symId in symIds: + assert symId >= 0 and symId < m.sh.syms.len, $symId & " " & $m.sh.syms.len + +proc checkModule(c: var CheckedContext; m: PackedModule) = + # We check that: + # - Every symbol references existing types and symbols. + # - Every tree node references existing types and symbols. + for i in 0..high(m.sh.syms): + checkLocalSym c, int32(i) + + checkTree c, m.toReplay + checkTree c, m.topLevel + + for e in m.exports: + assert e[1] >= 0 and e[1] < m.sh.syms.len + assert e[0] == m.sh.syms[e[1]].name + + for e in m.compilerProcs: + assert e[1] >= 0 and e[1] < m.sh.syms.len + assert e[0] == m.sh.syms[e[1]].name + + checkLocalSymIds c, m, m.converters + checkLocalSymIds c, m, m.methods + checkLocalSymIds c, m, m.trmacros + checkLocalSymIds c, m, m.pureEnums + #[ + To do: Check all these fields: + + reexports*: seq[(LitId, PackedItemId)] + macroUsages*: seq[(PackedItemId, PackedLineInfo)] + + typeInstCache*: seq[(PackedItemId, PackedItemId)] + procInstCache*: seq[PackedInstantiation] + attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)] + methodsPerType*: seq[(PackedItemId, int, PackedItemId)] + enumToStringProcs*: seq[(PackedItemId, PackedItemId)] + ]# + +proc checkIntegrity*(g: ModuleGraph) = + var c = CheckedContext(g: g) + for i in 0..high(g.packed): + # case statement here to enforce exhaustive checks. + case g.packed[i].status + of undefined: + discard "nothing to do" + of loading: + assert false, "cannot check integrity: Module still loading" + of stored, storing, outdated, loaded: + c.thisModule = int32 i + checkModule(c, g.packed[i].fromDisk) + diff --git a/compiler/main.nim b/compiler/main.nim index 26a19063f..3c5018546 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -21,7 +21,7 @@ import modules, modulegraphs, tables, lineinfos, pathutils, vmprofiler -import ic / cbackend +import ic / [cbackend, integrity] from ic / ic import rodViewer when not defined(leanCompiler): @@ -93,6 +93,8 @@ proc commandCompileToC(graph: ModuleGraph) = if conf.symbolFiles == disabledSf: cgenWriteModules(graph.backend, conf) else: + if isDefined(conf, "nimIcIntegrityChecks"): + checkIntegrity(graph) generateCode(graph) # graph.backend can be nil under IC when nothing changed at all: if graph.backend != nil: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 51b2cdea1..daf1265e8 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -341,6 +341,9 @@ proc addConverter*(c: PContext, conv: LazySym) = assert conv.sym != nil if inclSym(c.converters, conv.sym): add(c.graph.ifaces[c.module.position].converters, conv) + +proc addConverterDef*(c: PContext, conv: LazySym) = + addConverter(c, conv) if c.config.symbolFiles != disabledSf: addConverter(c.encoder, c.packedRepr, conv.sym) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index bbfd49e2a..4c6a745f6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2093,7 +2093,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode = var t = s.typ if t[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter") if t.len != 2: localError(c.config, n.info, "a converter takes exactly one argument") - addConverter(c, LazySym(sym: s)) + addConverterDef(c, LazySym(sym: s)) proc semMacroDef(c: PContext, n: PNode): PNode = checkSonsLen(n, bodyPos + 1, c.config) diff --git a/koch.nim b/koch.nim index 3b00d3564..44d38589b 100644 --- a/koch.nim +++ b/koch.nim @@ -492,7 +492,7 @@ proc icTest(args: string) = for fragment in content.split("#!EDIT!#"): let file = inp.replace(".nim", "_temp.nim") writeFile(file, fragment) - var cmd = nimExe & " cpp --ic:on --listcmd " + var cmd = nimExe & " cpp --ic:on -d:nimIcIntegrityChecks --listcmd " if i == 0: cmd.add "-f " cmd.add quoteShell(file) diff --git a/testament/categories.nim b/testament/categories.nim index af6331dde..618046287 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -488,7 +488,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) tooltests = ["compiler/nim.nim", "tools/nimgrep.nim"] writeOnly = " --incremental:writeonly " readOnly = " --incremental:readonly " - incrementalOn = " --incremental:on " + incrementalOn = " --incremental:on -d:nimIcIntegrityChecks " template test(x: untyped) = testSpecWithNimcache(r, makeRawTest(file, x & options, cat), nimcache) From e710b9cf33939fa20230ab3029ceb735e0a669ad Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 11 Apr 2021 20:14:44 +0200 Subject: [PATCH 2401/4254] macrocache.nim: removed trailing whitespace --- lib/core/macrocache.nim | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/core/macrocache.nim b/lib/core/macrocache.nim index e376ad87f..d4b103793 100644 --- a/lib/core/macrocache.nim +++ b/lib/core/macrocache.nim @@ -10,10 +10,10 @@ ## This module provides an API for macros to collect compile-time information ## across module boundaries. It should be used instead of global `{.compileTime.}` ## variables as those break incremental compilation. -## +## ## The main feature of this module is that if you create `CacheTable`s or ## any other `Cache` types with the same name in different modules, their -## content will be shared, meaning that you can fill a `CacheTable` in +## content will be shared, meaning that you can fill a `CacheTable` in ## one module, and iterate over its contents in another. runnableExamples: @@ -22,20 +22,20 @@ runnableExamples: const mcTable = CacheTable"myTable" const mcSeq = CacheSeq"mySeq" const mcCounter = CacheCounter"myCounter" - + static: # add new key "val" with the value `myval` let myval = newLit("hello ic") mcTable["val"] = myval assert mcTable["val"].kind == nnkStrLit - + # Can access the same cache from different static contexts # All the information is retained static: # get value from `mcTable` and add it to `mcSeq` mcSeq.add(mcTable["val"]) assert mcSeq.len == 1 - + static: assert mcSeq[0].strVal == "hello ic" @@ -49,7 +49,7 @@ type ## Compile-time sequence of `NimNode`s. CacheTable* = distinct string ## Compile-time table of key-value pairs. - ## + ## ## Keys are `string`s and values are `NimNode`s. CacheCounter* = distinct string ## Compile-time counter, uses `int` for storing the count. @@ -80,22 +80,22 @@ proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} = runnableExamples: import std/macros const mySeq = CacheSeq"addTest" - + static: mySeq.add(newLit(5)) mySeq.add(newLit("hello ic")) - + assert mySeq.len == 2 assert mySeq[1].strVal == "hello ic" -proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} = +proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} = ## Adds `value` to `s`. - ## + ## ## .. hint:: This doesn't do anything if `value` is already in `s`. runnableExamples: import std/macros const mySeq = CacheSeq"inclTest" - + static: mySeq.incl(newLit(5)) mySeq.incl(newLit(5)) @@ -113,7 +113,7 @@ proc len*(s: CacheSeq): int {.magic: "NcsLen".} = let val = newLit("helper") mySeq.add(val) assert mySeq.len == 1 - + mySeq.add(val) assert mySeq.len == 2 @@ -132,20 +132,20 @@ iterator items*(s: CacheSeq): NimNode = runnableExamples: import std/macros const myseq = CacheSeq"itemsTest" - + static: myseq.add(newLit(5)) myseq.add(newLit(42)) - + for val in myseq: # check that all values in `myseq` are int literals assert val.kind == nnkIntLit - + for i in 0 ..< len(s): yield s[i] proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} = - ## Inserts a `(key, value)` pair into `t`. - ## + ## Inserts a `(key, value)` pair into `t`. + ## ## .. warning:: `key` has to be unique! Assigning `value` to a `key` that is already ## in the table will result in a compiler error. runnableExamples: @@ -155,11 +155,11 @@ proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} = static: # assign newLit(5) to the key "value" mcTable["value"] = newLit(5) - - # check that we can get the value back - assert mcTable["value"].kind == nnkIntLit -proc len*(t: CacheTable): int {.magic: "NctLen".} = + # check that we can get the value back + assert mcTable["value"].kind == nnkIntLit + +proc len*(t: CacheTable): int {.magic: "NctLen".} = ## Returns the number of elements in `t`. runnableExamples: import std/macros @@ -177,7 +177,7 @@ proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} = const mcTable = CacheTable"subTest" static: mcTable["toAdd"] = newStmtList() - + # get the NimNode back assert mcTable["toAdd"].kind == nnkStmtList @@ -189,8 +189,8 @@ iterator pairs*(t: CacheTable): (string, NimNode) = runnableExamples: import std/macros const mytabl = CacheTable"values" - - static: + + static: mytabl["intVal"] = newLit(5) mytabl["otherVal"] = newLit(6) for key, val in mytabl: From cae183915490846a0ec7dbcd52b29a74c7c59f05 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 11 Apr 2021 21:41:24 +0200 Subject: [PATCH 2402/4254] IC: added tcompiletime_counter test case (#17698) --- tests/ic/mcompiletime_counter.nim | 15 +++++++++++++++ tests/ic/tcompiletime_counter.nim | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/ic/mcompiletime_counter.nim create mode 100644 tests/ic/tcompiletime_counter.nim diff --git a/tests/ic/mcompiletime_counter.nim b/tests/ic/mcompiletime_counter.nim new file mode 100644 index 000000000..6fc7b3f2a --- /dev/null +++ b/tests/ic/mcompiletime_counter.nim @@ -0,0 +1,15 @@ + +import std/macros +import std/macrocache + +const myCounter = CacheCounter"myCounter" + +proc getUniqueId*(): int {.compileTime.} = + inc myCounter + result = myCounter.value + +static: + myCounter.inc(3) + assert myCounter.value == 3 + + diff --git a/tests/ic/tcompiletime_counter.nim b/tests/ic/tcompiletime_counter.nim new file mode 100644 index 000000000..695a6ec27 --- /dev/null +++ b/tests/ic/tcompiletime_counter.nim @@ -0,0 +1,24 @@ +discard """ + output: '''id 4''' +""" + +import mcompiletime_counter + +const intId = getUniqueId() + +echo "id ", intId + +#!EDIT!# + +discard """ + output: '''id 4 5''' +""" + +import mcompiletime_counter + +const + intId = getUniqueId() + floatId = getUniqueId() + +echo "id ", intId, " ", floatId + From 0bc943ad54d707f93d47a6d52bf7d445c45388d8 Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Mon, 12 Apr 2021 06:32:37 +0100 Subject: [PATCH 2403/4254] followup strformat PR. backslash escapes, tests, docs (#17700) * Allow use of colons inside fmt allowing colons inside fmt by replacing the format specifier delimiter lets arbitrary nim code be run within fmt expressions. Co-authored-by: flywind * formatting,documentation,backslash escapes Adding support for evaluating expressions by special-casing parentheses causes this regression: `&"""{ "(hello)" }"""` no longer parses. In addition, code such as &"""{(if open: '(' else: ')')}""" wouldn't work. To enable that, as well as the use of, e.g. Table constructors inside curlies, I've added backslash escapes. This also means that if/for/etc statements, unparenthesized, will work, if the colons are escaped, but i've left that under-documented. It's not exactly elegant having two types of escape, but I believe it's the least bad option. * changelog * added json strformat test * pulled my thumb out and wrote a parser Co-authored-by: Andreas Rumpf Co-authored-by: flywind --- changelogs/changelog_X_XX_X.md | 1 + lib/pure/strformat.nim | 33 ++++++++++++++++--- tests/stdlib/tstrformat.nim | 60 +++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md index 77b421f33..d68ef4c20 100644 --- a/changelogs/changelog_X_XX_X.md +++ b/changelogs/changelog_X_XX_X.md @@ -13,6 +13,7 @@ The changes should go to changelog.md! - Changed `example.foo` to take additional `bar` parameter. +- Added support for evaluating parenthesised expressions in strformat ## Language changes diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index c232c8a46..736b4d501 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -144,6 +144,19 @@ An expression like `&"{key} is {value:arg} {{z}}"` is transformed into: Parts of the string that are enclosed in the curly braces are interpreted as Nim code, to escape a `{` or `}`, double it. +Within a curly expression,however, '{','}', must be escaped with a backslash. + +To enable evaluating Nim expressions within curlies, inside parentheses +colons do not need to be escaped. +]## + +runnableExamples: + let x = "hello" + assert fmt"""{ "\{(" & x & ")\}" }""" == "{(hello)}" + assert fmt"""{{({ x })}}""" == "{(hello)}" + assert fmt"""{ $(\{x:1,"world":2\}) }""" == """[("hello", 1), ("world", 2)]""" + +##[ `&` delegates most of the work to an open overloaded set of `formatValue` procs. The required signature for a type `T` that supports formatting is usually `proc formatValue(result: var string; x: T; specifier: string)`. @@ -289,6 +302,7 @@ keep the hygiene of `myTemplate`, and we do not want `arg1` to be injected into the context where `myTemplate` is expanded, everything is wrapped in a `block`. + # Future directions A curly expression with commas in it like `{x, argA, argB}` could be @@ -588,10 +602,21 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = var subexpr = "" var inParens = 0 - while i < f.len and f[i] != closeChar and (f[i] != ':' or inParens!=0): + var inSingleQuotes = false + var inDoubleQuotes = false + template notEscaped:bool = f[i-1]!='\\' + while i < f.len and f[i] != closeChar and (f[i] != ':' or inParens != 0): case f[i] - of '(': inc inParens - of ')': dec inParens + of '\\': + if i < f.len-1 and f[i+1] in {openChar,closeChar,':'}: inc i + of '\'': + if not inDoubleQuotes and notEscaped: inSingleQuotes = not inSingleQuotes + of '\"': + if notEscaped: inDoubleQuotes = not inDoubleQuotes + of '(': + if not (inSingleQuotes or inDoubleQuotes): inc inParens + of ')': + if not (inSingleQuotes or inDoubleQuotes): dec inParens of '=': let start = i inc i @@ -604,7 +629,7 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = else: discard subexpr.add f[i] inc i - + var x: NimNode try: x = parseExpr(subexpr) diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 86100e421..1863d3138 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -1,7 +1,7 @@ # xxx: test js target import genericstrformat -import std/[strformat, strutils, times] +import std/[strformat, strutils, times, tables, json] proc main() = block: # issue #7632 @@ -284,6 +284,20 @@ proc main() = doAssert fmt"{123.456=:>13e}" == "123.456= 1.234560e+02" doAssert fmt"{123.456=:13e}" == "123.456= 1.234560e+02" + let x = 3.14 + doAssert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847" + doAssert fmt"""{(block: + var res: string + for i in 1..15: + res.add (if i mod 15 == 0: "FizzBuzz" + elif i mod 5 == 0: "Buzz" + elif i mod 3 == 0: "Fizz" + else: $i) & " " + res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz " + + doAssert fmt"""{ "\{(" & msg & ")\}" }""" == "{(hello)}" + doAssert fmt"""{{({ msg })}}""" == "{(hello)}" + doAssert fmt"""{ $(\{msg:1,"world":2\}) }""" == """[("hello", 1), ("world", 2)]""" block: # tests for debug format string var name = "hello" let age = 21 @@ -496,6 +510,50 @@ proc main() = block: # test low(int64) doAssert &"{low(int64):-}" == "-9223372036854775808" + block: #expressions plus formatting + doAssert fmt"{if true\: 123.456 else\: 0=:>9.3f}" == "if true: 123.456 else: 0= 123.456" + doAssert fmt"{(if true: 123.456 else: 0)=}" == "(if true: 123.456 else: 0)=123.456" + doAssert fmt"{if true\: 123.456 else\: 0=:9.3f}" == "if true: 123.456 else: 0= 123.456" + doAssert fmt"{(if true: 123.456 else: 0)=:9.4f}" == "(if true: 123.456 else: 0)= 123.4560" + doAssert fmt"{(if true: 123.456 else: 0)=:>9.0f}" == "(if true: 123.456 else: 0)= 123." + doAssert fmt"{if true\: 123.456 else\: 0=:<9.4f}" == "if true: 123.456 else: 0=123.4560 " + doAssert fmt"""{(case true + of false: 0.0 + of true: 123.456)=:e}""" == """(case true + of false: 0.0 + of true: 123.456)=1.234560e+02""" + + doAssert fmt"""{block\: + var res = 0.000123456 + for _ in 0..5\: + res *= 10 + res=:>13e}""" == """block: + var res = 0.000123456 + for _ in 0..5: + res *= 10 + res= 1.234560e+02""" + #side effects + var x = 5 + doAssert fmt"{(x=7;123.456)=:13e}" == "(x=7;123.456)= 1.234560e+02" + doAssert x==7 + block: #curly bracket expressions and tuples + proc formatValue(result: var string; value:Table|bool|JsonNode; specifier:string) = result.add $value + + doAssert fmt"""{\{"a"\:1,"b"\:2\}.toTable() = }""" == """{"a":1,"b":2}.toTable() = {"a": 1, "b": 2}""" + doAssert fmt"""{(\{3: (1,"hi",0.9),4: (4,"lo",1.1)\}).toTable()}""" == """{3: (1, "hi", 0.9), 4: (4, "lo", 1.1)}""" + doAssert fmt"""{ (%* \{"name": "Isaac", "books": ["Robot Dreams"]\}) }""" == """{"name":"Isaac","books":["Robot Dreams"]}""" + doAssert """%( \%\* {"name": "Isaac"})*""".fmt('%','*') == """{"name":"Isaac"}""" + block: #parens in quotes that fool my syntax highlighter + doAssert fmt"{(if true: ')' else: '(')}" == ")" + doAssert fmt"{(if true: ']' else: ')')}" == "]" + doAssert fmt"""{(if true: "\")\"" else: "\"(")}""" == """")"""" + doAssert &"""{(if true: "\")" else: "")}""" == "\")" + doAssert &"{(if true: \"\\\")\" else: \"\")}" == "\")" + doAssert fmt"""{(if true: "')" else: "")}""" == "')" + doAssert fmt"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" + doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" + doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')" + doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')" # xxx static: main() main() From 8b5769133cf30dae2a6ed15aa3ba9d2f2be713ec Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 12 Apr 2021 14:58:46 +0800 Subject: [PATCH 2404/4254] remove unnecessary assignment (#17702) --- lib/pure/coro.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index ccd9fba4d..e3ed6aadd 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -274,7 +274,6 @@ proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discar coro.execContext = CreateFiberEx(stacksize, stacksize, FIBER_FLAG_FLOAT_SWITCH, (proc(p: pointer) {.stdcall.} = runCurrentTask()), nil) - coro.stack.size = stacksize else: coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine) + stacksize)) coro.stack.top = cast[pointer](cast[ByteAddress](coro) + sizeof(Coroutine)) From 4f5709e32648435ff253b056ac7066240c39d2b7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 13 Apr 2021 07:23:29 +0200 Subject: [PATCH 2405/4254] IC: serialization bugfix (#17701) --- compiler/ic/ic.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 6769c6ffe..32bacba70 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -260,9 +260,9 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): Packed assert t.uniqueId.module >= 0 assert t.uniqueId.item > 0 return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) - assert t.itemId.module >= 0 + assert t.uniqueId.module >= 0 assert t.uniqueId.item > 0 - result = PackedItemId(module: toLitId(t.itemId.module.FileIndex, c, m), item: t.uniqueId.item) + result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) addMissing(c, t) proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId = @@ -318,9 +318,9 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI # fill the reserved slot, nothing else: m.sh.types[t.uniqueId.item] = p - assert t.itemId.module >= 0 + assert t.uniqueId.module >= 0 assert t.uniqueId.item > 0 - result = PackedItemId(module: toLitId(t.itemId.module.FileIndex, c, m), item: t.uniqueId.item) + result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib = ## the plib hangs off the psym via the .annex field From e92c78a9ac0ce0f7a9b2a0fada0c2c2557c40ae2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Apr 2021 00:33:28 -0700 Subject: [PATCH 2406/4254] add number literal jsbigints.big (#17707) --- lib/std/jsbigints.nim | 20 +++++++++++++------- tests/stdlib/tjsbigints.nim | 6 +++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim index 96ba90649..27df8fdad 100644 --- a/lib/std/jsbigints.nim +++ b/lib/std/jsbigints.nim @@ -13,16 +13,22 @@ func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} = doAssert 0b1111100111.big == 0o1747.big and 0o1747.big == 999.big when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard -func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} = +func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".} = ## Constructor for `JsBigInt`. runnableExamples: - doAssert big"-1" == big"1" - big"2" + doAssert -1'big == 1'big - 2'big # supports decimal, binary, octal, hex: - doAssert big"12" == 12.big - doAssert big"0b101" == 0b101.big - doAssert big"0o701" == 0o701.big - doAssert big"0xdeadbeaf" == 0xdeadbeaf.big - doAssert big"0xffffffffffffffff" == (1.big shl 64.big) - 1.big + doAssert -12'big == big"-12" + doAssert 12'big == 12.big + doAssert 0b101'big == 0b101.big + doAssert 0o701'big == 0o701.big + doAssert 0xdeadbeaf'big == 0xdeadbeaf.big + doAssert 0xffffffffffffffff'big == (1'big shl 64'big) - 1'big + doAssert not compiles(static(12'big)) + when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard + +func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} = + ## Alias for `'big` when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard func toCstring*(this: JsBigInt; radix: 2..36): cstring {.importjs: "#.toString(#)".} = diff --git a/tests/stdlib/tjsbigints.nim b/tests/stdlib/tjsbigints.nim index 34c5ddfbf..fcf699c67 100644 --- a/tests/stdlib/tjsbigints.nim +++ b/tests/stdlib/tjsbigints.nim @@ -26,7 +26,7 @@ doAssert big1.toCstring(10) == "2147483647".cstring doAssert big2 ** big3 == big(443556) var huge = big"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" huge.inc -huge = huge + big"-999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" +huge = huge + -999999999999999999999999999999999999999999999999999999999999999999999999999999999999999'big doAssert huge == big"1" var list: seq[JsBigInt] for i in big"0" .. big"5": @@ -40,7 +40,7 @@ for i in big"0" ..< big"5": doAssert list == @[big"0", big"1", big"2", big"3", big"4"] block: - let b = big"2" - doAssert -b ** big"3" == big"-8" + let b = 2'big + doAssert -b ** 3'big == -8'big doAssert -b ** big"2" == big"4" # not -4 because of precedence doAssert -big"3" == big"-3" From 8e6b87a917a5d09a70d1e29f0b06915c29fcac6b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 13 Apr 2021 10:43:16 +0200 Subject: [PATCH 2407/4254] IC: code cleanup (#17708) --- compiler/ic/ic.nim | 57 ++++++++++------------------------------------ 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 32bacba70..e882b7a85 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -254,41 +254,31 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): Packed # we only write one tree into m.bodies after the other. if t.isNil: return nilItemId - if t.uniqueId.module != c.thisModule: - # XXX Assert here that it already was serialized in the foreign module! - # it is a foreign type: - assert t.uniqueId.module >= 0 - assert t.uniqueId.item > 0 - return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) assert t.uniqueId.module >= 0 assert t.uniqueId.item > 0 result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) - addMissing(c, t) + if t.uniqueId.module == c.thisModule: + # the type belongs to this module, so serialize it here, eventually. + addMissing(c, t) proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId = if s.isNil: return nilItemId assert s.itemId.module >= 0 - if s.itemId.module != c.thisModule: - # XXX Assert here that it already was serialized in the foreign module! - # it is a foreign symbol: - assert s.itemId.module >= 0 - return PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) assert s.itemId.module >= 0 result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) - addMissing(c, s) + if s.itemId.module == c.thisModule: + # the sym belongs to this module, so serialize it here, eventually. + addMissing(c, s) proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId = ## serialize a ptype if t.isNil: return nilItemId - if t.uniqueId.module != c.thisModule: - # XXX Assert here that it already was serialized in the foreign module! - # it is a foreign type: - assert t.uniqueId.module >= 0 - assert t.uniqueId.item > 0 - return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) + assert t.uniqueId.module >= 0 + assert t.uniqueId.item > 0 + result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) - if not c.typeMarker.containsOrIncl(t.uniqueId.item): + if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item): if t.uniqueId.item >= m.sh.types.len: setLen m.sh.types, t.uniqueId.item+1 @@ -296,20 +286,9 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI size: t.size, align: t.align, nonUniqueId: t.itemId.item, paddingAtEnd: t.paddingAtEnd, lockLevel: t.lockLevel) storeNode(p, t, n) - - when false: - for op, s in pairs t.attachedOps: - c.addMissing s - p.attachedOps[op] = s.safeItemId(c, m) - p.typeInst = t.typeInst.storeType(c, m) for kid in items t.sons: p.types.add kid.storeType(c, m) - - when false: - for i, s in items t.methods: - c.addMissing s - p.methods.add (i, s.safeItemId(c, m)) c.addMissing t.sym p.sym = t.sym.safeItemId(c, m) c.addMissing t.owner @@ -318,10 +297,6 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI # fill the reserved slot, nothing else: m.sh.types[t.uniqueId.item] = p - assert t.uniqueId.module >= 0 - assert t.uniqueId.item > 0 - result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) - proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib = ## the plib hangs off the psym via the .annex field if l.isNil: return @@ -336,14 +311,9 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId if s.isNil: return nilItemId assert s.itemId.module >= 0 + result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) - if s.itemId.module != c.thisModule: - # XXX Assert here that it already was serialized in the foreign module! - # it is a foreign symbol: - assert s.itemId.module >= 0 - return PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) - - if not c.symMarker.containsOrIncl(s.itemId.item): + if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item): if s.itemId.item >= m.sh.syms.len: setLen m.sh.syms, s.itemId.item+1 @@ -375,9 +345,6 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId # fill the reserved slot, nothing else: m.sh.syms[s.itemId.item] = p - assert s.itemId.module >= 0 - result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) - proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) = ## add a remote symbol reference to the tree let info = n.info.toPackedInfo(c, m) From fe77c3c72fe1fde4f41286158ba612c02083dfe2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Apr 2021 14:16:19 -0700 Subject: [PATCH 2408/4254] megatest: allow duplicate file names, show compilation progress (#17713) * megatest: allow duplicate file names * megatest: show compilation progress --- testament/categories.nim | 17 +++++++++++------ tests/misc/tjoinable.nim | 3 +++ tests/testament/tjoinable.nim | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 tests/misc/tjoinable.nim diff --git a/testament/categories.nim b/testament/categories.nim index 618046287..ee5c46519 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -571,6 +571,11 @@ proc quoted(a: string): string = proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = ## returns a list of tests that have problems + #[ + xxx create a reusable megatest API after abstracting out testament specific code, + refs https://github.com/timotheecour/Nim/issues/655 + and https://github.com/nim-lang/gtk2/pull/28; it's useful in other contexts. + ]# var specs: seq[TSpec] = @[] for kind, dir in walkDir(testsDir): assert testsDir.startsWith(testsDir) @@ -595,16 +600,16 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = var megatest: string # xxx (minor) put outputExceptedFile, outputGottenFile, megatestFile under here or `buildDir` var outDir = nimcacheDir(testsDir / "megatest", "", targetC) - const marker = "megatest:processing: " - + template toMarker(file, i): string = + "megatest:processing: [$1] $2" % [$i, file] for i, runSpec in specs: let file = runSpec.file - let file2 = outDir / ("megatest_$1.nim" % $i) + let file2 = outDir / ("megatest_a_$1.nim" % $i) # `include` didn't work with `trecmod2.nim`, so using `import` - let code = "echo \"$1\", $2\n" % [marker, quoted(file)] + let code = "echo $1\nstatic: echo \"CT:\", $1\n" % [toMarker(file, i).quoted] createDir(file2.parentDir) writeFile(file2, code) - megatest.add "import $1\nimport $2\n" % [quoted(file2), quoted(file)] + megatest.add "import $1\nimport $2 as megatest_b_$3\n" % [file2.quoted, file.quoted, $i] let megatestFile = testsDir / "megatest.nim" # so it uses testsDir / "config.nims" writeFile(megatestFile, megatest) @@ -626,7 +631,7 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = writeFile(outputGottenFile, buf) var outputExpected = "" for i, runSpec in specs: - outputExpected.add marker & runSpec.file & "\n" + outputExpected.add toMarker(runSpec.file, i) & "\n" if runSpec.output.len > 0: outputExpected.add runSpec.output if not runSpec.output.endsWith "\n": diff --git a/tests/misc/tjoinable.nim b/tests/misc/tjoinable.nim new file mode 100644 index 000000000..f23fca0d4 --- /dev/null +++ b/tests/misc/tjoinable.nim @@ -0,0 +1,3 @@ +# checks that megatest allows duplicate names, see also `tests/testament/tjoinable.nim` +doAssert defined(testing) +doAssert defined(nimMegatest) diff --git a/tests/testament/tjoinable.nim b/tests/testament/tjoinable.nim index 7a0ad7985..c651780de 100644 --- a/tests/testament/tjoinable.nim +++ b/tests/testament/tjoinable.nim @@ -3,6 +3,7 @@ discard """ """ # checks that this is joinable +# checks that megatest allows duplicate names, see also `tests/misc/tjoinable.nim` doAssert defined(testing) doAssert defined(nimMegatest) echo "ok" # intentional to make sure this doesn't prevent `isJoinableSpec` From 840e13deb79db7b072595658e6aa8328d55d7889 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Apr 2021 23:50:15 -0700 Subject: [PATCH 2409/4254] type with same name in different scope now works (#17710) * type with same name in different scope now works * fix tests/enum/tenum.nim which was wrong because it was affected by this bug --- compiler/semstmts.nim | 7 ++- compiler/sighashes.nim | 19 ++++-- tests/ccgbugs/tsamename3.nim | 111 +++++++++++++++++++++++++++++++++++ tests/enum/tenum.nim | 5 +- 4 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 tests/ccgbugs/tsamename3.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4c6a745f6..2c257bd3d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1354,8 +1354,11 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = checkConstructedType(c.config, s.info, s.typ) if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil: checkForMetaFields(c, s.typ.n) - # fix bug #5170: ensure locally scoped object types get a unique name: - if s.typ.kind == tyObject and not isTopLevel(c): incl(s.flags, sfGenSym) + + # fix bug #5170, bug #17162, bug #15526: ensure locally scoped types get a unique name: + if s.typ.kind in {tyEnum, tyRef, tyObject} and not isTopLevel(c): + incl(s.flags, sfGenSym) + #instAllTypeBoundOp(c, n.info) diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 156bc66d7..f6df422e6 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -151,15 +151,24 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = c.hashTypeSym(t.sym) else: c.hashSym(t.sym) - if {sfAnon, sfGenSym} * t.sym.flags != {}: + + var symWithFlags: PSym + template hasFlag(sym): bool = + let ret = {sfAnon, sfGenSym} * sym.flags != {} + if ret: symWithFlags = sym + ret + if hasFlag(t.sym) or (t.kind == tyObject and t.owner.kind == skType and t.owner.typ.kind == tyRef and hasFlag(t.owner)): + # for `PFoo:ObjectType`, arising from `type PFoo = ref object` # Generated object names can be identical, so we need to # disambiguate furthermore by hashing the field types and names. if t.n.len > 0: - let oldFlags = t.sym.flags - # Mild hack to prevent endless recursion. - t.sym.flags.excl {sfAnon, sfGenSym} + let oldFlags = symWithFlags.flags + # Hack to prevent endless recursion + # xxx intead, use a hash table to indicate we've already visited a type, which + # would also be more efficient. + symWithFlags.flags.excl {sfAnon, sfGenSym} hashTree(c, t.n, flags + {CoHashTypeInsideNode}) - t.sym.flags = oldFlags + symWithFlags.flags = oldFlags else: # The object has no fields: we _must_ add something here in order to # make the hash different from the one we produce by hashing only the diff --git a/tests/ccgbugs/tsamename3.nim b/tests/ccgbugs/tsamename3.nim new file mode 100644 index 000000000..a69391e5c --- /dev/null +++ b/tests/ccgbugs/tsamename3.nim @@ -0,0 +1,111 @@ +block: # bug #15526 + block: + type Foo = ref object + x1: int + let f1 = Foo(x1: 1) + block: + type Foo = ref object + x2: int + let f2 = Foo(x2: 2) + +block: # ditto + template fn() = + block: + type Foo = ref object + x1: int + let f1 = Foo(x1: 1) + doAssert f1.x1 == 1 + block: + type Foo = ref object + x2: int + let f2 = Foo(x2: 2) + doAssert f2.x2 == 2 + static: fn() + fn() + +block: # bug #17162 + template fn = + var ret: string + block: + type A = enum a0, a1, a2 + for ai in A: + ret.add $ai + block: + type A = enum b0, b1, b2, b3 + for ai in A: + ret.add $ai + doAssert ret == "a0a1a2b0b1b2b3" + + static: fn() # ok + fn() # was bug + +block: # ditto + proc fn = + var ret: string + block: + type A = enum a0, a1, a2 + for ai in A: + ret.add $ai + block: + type A = enum b0, b1, b2, b3 + for ai in A: + ret.add $ai + doAssert ret == "a0a1a2b0b1b2b3" + + static: fn() # ok + fn() # was bug + +block: # bug #5170 + block: + type Foo = object + x1: int + let f1 = Foo(x1: 1) + block: + type Foo = object + x2: int + let f2 = Foo(x2: 2) + +block: # ditto + block: + type Foo = object + bar: bool + var f1: Foo + + block: + type Foo = object + baz: int + var f2: Foo + doAssert f2.baz == 0 + + block: + template fn() = + block: + type Foo = object + x1: int + let f1 = Foo(x1: 1) + doAssert f1.x1 == 1 + block: + type Foo = object + x2: int + let f2 = Foo(x2: 2) + doAssert f2.x2 == 2 + static: fn() + fn() + +when true: # ditto, refs https://github.com/nim-lang/Nim/issues/5170#issuecomment-582712132 + type Foo1 = object # at top level + bar: bool + var f1: Foo1 + + block: + type Foo1 = object + baz: int + var f2: Foo1 + doAssert f2.baz == 0 + +block: # make sure `hashType` doesn't recurse infinitely + type + PFoo = ref object + a, b: PFoo + c: int + var a: PFoo diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index aa338ee2c..97fd4c68c 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -6,7 +6,7 @@ ABCDC foo first0second32third64 my value A1my value Bconc2valueCabc4abc -my value A0my value Bconc1valueCabc3valueC +my value A0my value Bconc1valueCabc3abc ''' """ @@ -124,7 +124,8 @@ block tnamedfields: # trick the optimizer with a variable: var x = valueD echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x - + doAssert $x == $valueD, $x + doAssert $x == "abc", $x block toptions: From 25b4a0ab0a03f35c58bc0dbfff51a344e108bfe3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Apr 2021 00:44:07 -0700 Subject: [PATCH 2410/4254] testament --verbose: prints commands; gitignore ic artifacts (#17716) --- .gitignore | 7 +++++-- testament/testament.nim | 14 +++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e71fdf352..a22a4cd03 100644 --- a/.gitignore +++ b/.gitignore @@ -72,14 +72,17 @@ testament.db .*/ ~* -# testament cruft; TODO: generate these in a gitignore'd dir in the first place. +# testament cruft; TODO: generate these in a gitignore'd dir (./build) in the first place. testresults/ test.txt /test.ini tweeter.db tweeter_test.db -megatest.nim + +/tests/megatest.nim +/tests/ic/*_temp.nim + /outputExpected.txt /outputGotten.txt diff --git a/testament/testament.nim b/testament/testament.nim index 462c0a57c..ee7f67484 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -21,6 +21,11 @@ from lib/stdtest/specialpaths import splitTestFile var useColors = true var backendLogging = true var simulate = false +var optVerbose = false + +proc verboseCmd(cmd: string) = + if optVerbose: + echo "executing: ", cmd const failString* = "FAIL: " # ensures all failures can be searched with 1 keyword in CI logs @@ -38,7 +43,8 @@ Command: Arguments: arguments are passed to the compiler Options: - --print also print results to the console + --print print results to the console + --verbose print commands (compiling and running tests) --simulate see what tests would be run but don't run them (for debugging) --failing only show failing/ignored tests --targets:"c cpp js objc" run tests for specified targets (default: all) @@ -113,6 +119,7 @@ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: str for arg in args: result.cmdLine.add ' ' result.cmdLine.add quoteShell(arg) + verboseCmd(result.cmdLine) var p = startProcess(command, workingDir = workingDir, args = args, options = {poStdErrToStdOut, poUsePath}) var outp = outputStream(p) @@ -155,6 +162,7 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, let c = prepareTestArgs(cmdTemplate, filename, options, nimcache, target, extraOptions) result.cmd = quoteShellCommand(c) + verboseCmd(c.quoteShellCommand) var p = startProcess(command = c[0], args = c[1 .. ^1], options = {poStdErrToStdOut, poUsePath}) let outp = p.outputStream @@ -491,7 +499,6 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, valgrindOptions.add "--leak-check=yes" args = valgrindOptions & exeCmd & args exeCmd = "valgrind" - # xxx honor `testament --verbose` here var (_, buf, exitCode) = execCmdEx2(exeCmd, args, input = expected.input) # Treat all failure codes from nodejs as 1. Older versions of nodejs used # to return other codes, but for us it is sufficient to know that it's not 0. @@ -663,7 +670,8 @@ proc main() = p.next() while p.kind in {cmdLongOption, cmdShortOption}: case p.key.normalize - of "print", "verbose": optPrintResults = true + of "print": optPrintResults = true + of "verbose": optVerbose = true of "failing": optFailing = true of "pedantic": discard # deadcode refs https://github.com/nim-lang/Nim/issues/16731 of "targets": From 3b47a689cfa56d9b54cd1b92dc1b57d3e4094937 Mon Sep 17 00:00:00 2001 From: zah Date: Wed, 14 Apr 2021 13:10:01 +0300 Subject: [PATCH 2411/4254] Remove the use of usrToCell in gcMark [backport:1.2] (#17709) * Remove the use of usrToCell in gcMark [backport:1.2] Recently, we've discovered a GC crash resulting from inlining of the memory allocation procs that allowed the compiler to avoid maintaining any references to the "user pointer" on the stack. Instead, a "cell pointer" appeared there and all field accesses were performed with adjusted offsets. This interfered with the ability of the GC to mark the correct cell in the conservative stack scans which lead to premature collection of objects. More details here: https://github.com/status-im/Nim/commit/af69b3ceae16281efd45cbee4ce1bedd14282304 This commit closes another theoretical loophole that may lead to the same problem. If a short proc is accessing both the object and its reference count in a short sequence of instructions, the compiler may be enticed to reduce the number of registers being used by storing only a single pointer to the object and using offsets when reading and writing fields. A perfectly good strategy would be to store only the cell pointer, so the reference count updates can be performed without applying offsets. Accessing the fields of the object requires offsets anyway, but these can be adjusted at compile-time without any loss. Following this strategy will lead to the same problem of marking a wrong cell during the conservative stack scan, leading to premature collection. The problem is avoided by not using `usrToCell` in `gcMark`. Since the cell discovery logic can already handle interior pointers, the user pointers don't need to be adjusted for the GC to function correctly. --- lib/system/gc.nim | 6 +++--- lib/system/gc_ms.nim | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 039a627ba..e50e80f11 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -710,16 +710,16 @@ proc collectCycles(gch: var GcHeap) {.raises: [].} = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: sysAssert(allocInv(gch.region), "gcMark begin") - var cell = usrToCell(p) - var c = cast[ByteAddress](cell) + var c = cast[ByteAddress](p) if c >% PageSize: # fast check: does it look like a cell? - var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) + var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p)) if objStart != nil: # mark the cell: incRef(objStart) add(gch.decStack, objStart) when false: + let cell = usrToCell(p) if isAllocatedPtr(gch.region, cell): sysAssert false, "allocated pointer but not interior?" # mark the cell: diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index b4221f7fd..c20e93699 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -455,11 +455,10 @@ proc markGlobals(gch: var GcHeap) = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: - var cell = usrToCell(p) - var c = cast[ByteAddress](cell) + var c = cast[ByteAddress](p) if c >% PageSize: # fast check: does it look like a cell? - var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) + var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p)) if objStart != nil: mark(gch, objStart) From 67e28c07f9cdb22a423b0ab08d4868252acc8ea4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 14 Apr 2021 16:44:37 +0200 Subject: [PATCH 2412/4254] IC: first steps towards 'nim check --def --ic:on' (#17714) * IC: first steps towards 'nim check --def --ic:on' * IC navigator: deduplicate output lines * IC navigator: progress * IC navigator: use a different nimcache entry * IC navigator: special logic for templates/macros * IC navigator: proper error messages * IC navigator: prepare for testing code; document only what currently works somewhat --- compiler/commands.nim | 3 + compiler/ic/ic.nim | 28 +++++-- compiler/ic/navigator.nim | 147 +++++++++++++++++++++++++++++++++++++ compiler/ic/packed_ast.nim | 4 +- compiler/main.nim | 15 +++- compiler/msgs.nim | 4 +- compiler/options.nim | 7 +- compiler/sem.nim | 1 + compiler/semdata.nim | 10 +++ compiler/semexprs.nim | 1 + doc/advopt.txt | 3 + 11 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 compiler/ic/navigator.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index f36a4f515..e918979fb 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -859,6 +859,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "usages": expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideUse + of "defusages": + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideDus of "stdout": processOnOffSwitchG(conf, {optStdout}, arg, pass, info) of "listfullpaths": diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index e882b7a85..4613b9cb8 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -89,14 +89,27 @@ proc rememberConfig(c: var PackedEncoder; m: var PackedModule; config: ConfigRef #primConfigFields rem m.cfg = pc +const + debugConfigDiff = defined(debugConfigDiff) + +when debugConfigDiff: + import std / [hashes, tables, intsets, sha1, strutils, sets] + proc configIdentical(m: PackedModule; config: ConfigRef): bool = result = m.definedSymbols == definedSymbolsAsString(config) - #if not result: - # echo "A ", m.definedSymbols, " ", definedSymbolsAsString(config) + when debugConfigDiff: + if not result: + var wordsA = m.definedSymbols.split(Whitespace).toHashSet() + var wordsB = definedSymbolsAsString(config).split(Whitespace).toHashSet() + for c in wordsA - wordsB: + echo "in A but not in B ", c + for c in wordsB - wordsA: + echo "in B but not in A ", c template eq(x) = result = result and m.cfg.x == config.x - #if not result: - # echo "B ", m.cfg.x, " ", config.x + when debugConfigDiff: + if m.cfg.x != config.x: + echo "B ", m.cfg.x, " ", config.x primConfigFields eq proc rememberStartupConfig*(dest: var PackedConfig, config: ConfigRef) = @@ -124,7 +137,7 @@ proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModule): LitId = c.filenames[x] = result c.lastFile = x c.lastLit = result - assert result != LitId(0) + assert result != LitId(0) proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex = result = msgs.fileInfoIdx(config, AbsoluteFile m.sh.strings[x]) @@ -144,6 +157,8 @@ proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; co m.bodies = newTreeFrom(m.topLevel) m.toReplay = newTreeFrom(m.topLevel) + c.lastFile = FileIndex(-10) + let thisNimFile = FileIndex c.thisModule var h = msgs.getHash(config, thisNimFile) if h.len == 0: @@ -464,6 +479,9 @@ proc storeInstantiation*(c: var PackedEncoder; m: var PackedModule; s: PSym; i: concreteTypes: t) toPackedGeneratedProcDef(i.sym, c, m) +proc storeExpansion*(c: var PackedEncoder; m: var PackedModule; info: TLineInfo; s: PSym) = + toPackedNode(newSymNode(s, info), m.bodies, c, m) + proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) = case err of cannotOpen: diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim new file mode 100644 index 000000000..ad2b29f42 --- /dev/null +++ b/compiler/ic/navigator.nim @@ -0,0 +1,147 @@ +# +# +# The Nim Compiler +# (c) Copyright 2021 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Supports the "nim check --ic:on --def --track:FILE,LINE,COL" +## IDE-like features. It uses the set of .rod files to accomplish +## its task. The set must cover a complete Nim project. + +import std / sets + +from os import nil +from std/private/miscdollars import toLocation + +import ".." / [ast, modulegraphs, msgs, options] +import packed_ast, bitabs, ic + +type + NavContext = object + g: ModuleGraph + thisModule: int32 + trackPos: PackedLineInfo + alreadyEmitted: HashSet[string] + outputSep: char # for easier testing, use short filenames and spaces instead of tabs. + +proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool = + if current.file == trackPos.file and current.line == trackPos.line: + let col = trackPos.col + if col >= current.col and col < current.col+tokenLen: + return true + +proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool = + result = s.name != LitId(0) and + isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.sh.strings[s.name].len) + +proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool = + let name = c.g.packed[s.module].fromDisk.sh.syms[s.item].name + result = name != LitId(0) and + isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.sh.strings[name].len) + +const + EmptyItemId = ItemId(module: -1'i32, item: -1'i32) + +proc search(c: var NavContext; tree: PackedTree): ItemId = + # We use the linear representation here directly: + for i in 0..high(tree.nodes): + case tree.nodes[i].kind + of nkSym: + let item = tree.nodes[i].operand + if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.sh.syms[item], tree.nodes[i].info): + return ItemId(module: c.thisModule, item: item) + of nkModuleRef: + if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file: + let (n1, n2) = sons2(tree, NodePos i) + assert n1.kind == nkInt32Lit + assert n2.kind == nkInt32Lit + let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand) + let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config) + if searchForeignSym(c, itemId, tree.nodes[i].info): + return itemId + else: discard + return EmptyItemId + +proc isDecl(tree: PackedTree; n: NodePos): bool = + # XXX This is not correct yet. + const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef, + nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection, + nkIdentDefs, nkEnumTy, nkVarTuple} + result = n.int >= 0 and tree[n.int].kind in declarativeNodes + +proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) = + var m = "" + var file = c.g.packed[c.thisModule].fromDisk.sh.strings[info.file] + if c.outputSep == ' ': + file = os.extractFilename file + toLocation(m, file, info.line.int, info.col.int + ColOffset) + if not c.alreadyEmitted.containsOrIncl(m): + echo (if isDecl: "def" else: "usage"), c.outputSep, m + +proc list(c: var NavContext; tree: PackedTree; sym: ItemId) = + for i in 0..high(tree.nodes): + case tree.nodes[i].kind + of nkSym: + let item = tree.nodes[i].operand + if sym.item == item and sym.module == c.thisModule: + usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i))) + of nkModuleRef: + let (n1, n2) = sons2(tree, NodePos i) + assert n1.kind == nkInt32Lit + assert n2.kind == nkInt32Lit + let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand) + let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config) + if itemId.item == sym.item and sym.module == itemId.module: + usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i))) + else: discard + +proc nav(g: ModuleGraph) = + # translate the track position to a packed position: + let unpacked = g.config.m.trackPos + let mid = unpacked.fileIndex + let fileId = g.packed[int32 mid].fromDisk.sh.strings.getKeyId(toFullPath(g.config, mid)) + + if fileId == LitId(0): + internalError(g.config, unpacked, "cannot find a valid file ID") + return + + var c = NavContext( + g: g, + thisModule: int32 mid, + trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId), + outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t' + ) + var symId = search(c, g.packed[int32 mid].fromDisk.topLevel) + if symId == EmptyItemId: + symId = search(c, g.packed[int32 mid].fromDisk.bodies) + + if symId == EmptyItemId: + localError(g.config, unpacked, "no symbol at this position") + return + + for i in 0..high(g.packed): + # case statement here to enforce exhaustive checks. + case g.packed[i].status + of undefined: + discard "nothing to do" + of loading: + assert false, "cannot check integrity: Module still loading" + of stored, storing, outdated, loaded: + c.thisModule = int32 i + list(c, g.packed[i].fromDisk.topLevel, symId) + list(c, g.packed[i].fromDisk.bodies, symId) + +proc navDefinition*(g: ModuleGraph) = nav(g) +proc navUsages*(g: ModuleGraph) = nav(g) +proc navDefusages*(g: ModuleGraph) = nav(g) + +proc writeRodFiles*(g: ModuleGraph) = + for i in 0..high(g.packed): + case g.packed[i].status + of undefined, loading, stored, loaded: + discard "nothing to do" + of storing, outdated: + closeRodFile(g, g.packed[i].module) diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 1075664cb..5cc3b1476 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -258,9 +258,9 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos = proc parentImpl(tree: PackedTree; n: NodePos): NodePos = # finding the parent of a node is rather easy: var pos = n.int - 1 - while pos >= 0 and isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int): + while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)): dec pos - assert pos >= 0, "node has no parent" + #assert pos >= 0, "node has no parent" result = NodePos(pos) template parent*(n: NodePos): NodePos = parentImpl(tree, n) diff --git a/compiler/main.nim b/compiler/main.nim index 3c5018546..475ba7773 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -21,7 +21,7 @@ import modules, modulegraphs, tables, lineinfos, pathutils, vmprofiler -import ic / [cbackend, integrity] +import ic / [cbackend, integrity, navigator] from ic / ic import rodViewer when not defined(leanCompiler): @@ -54,11 +54,20 @@ proc commandGenDepend(graph: ModuleGraph) = ' ' & changeFileExt(project, "dot").string) proc commandCheck(graph: ModuleGraph) = - graph.config.setErrorMaxHighMaybe - defineSymbol(graph.config.symbols, "nimcheck") + let conf = graph.config + conf.setErrorMaxHighMaybe + defineSymbol(conf.symbols, "nimcheck") semanticPasses(graph) # use an empty backend for semantic checking only compileProject(graph) + if conf.symbolFiles != disabledSf: + case conf.ideCmd + of ideDef: navDefinition(graph) + of ideUse: navUsages(graph) + of ideDus: navDefusages(graph) + else: discard + writeRodFiles(graph) + when not defined(leanCompiler): proc commandDoc2(graph: ModuleGraph; json: bool) = handleDocOutputOptions graph.config diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 24855ae18..452b1cd89 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -418,7 +418,9 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) inc(conf.errorCounter) conf.exitcode = 1'i8 if conf.errorCounter >= conf.errorMax: - quit(conf, msg) + # only really quit when we're not in the new 'nim check --def' mode: + if conf.ideCmd == ideNone: + quit(conf, msg) elif eh == doAbort and conf.cmd != cmdIdeTools: quit(conf, msg) elif eh == doRaise: diff --git a/compiler/options.nim b/compiler/options.nim index 7408ce675..9eeffb4fb 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -685,6 +685,11 @@ proc getOsCacheDir(): string = result = getHomeDir() / genSubDir.string proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir = + proc nimcacheSuffix(conf: ConfigRef): string = + if conf.cmd == cmdCheck: "_check" + elif isDefined(conf, "release") or isDefined(conf, "danger"): "_r" + else: "_d" + # XXX projectName should always be without a file extension! result = if not conf.nimcacheDir.isEmpty: conf.nimcacheDir @@ -692,7 +697,7 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir = conf.projectPath / genSubDir else: AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name & - (if isDefined(conf, "release") or isDefined(conf, "danger"): "_r" else: "_d")) + nimcacheSuffix(conf)) proc pathSubs*(conf: ConfigRef; p, config: string): string = let home = removeTrailingDirSep(os.getHomeDir()) diff --git a/compiler/sem.nim b/compiler/sem.nim index 6b3f0c80d..ccc634b4d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -452,6 +452,7 @@ const proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, flags: TExprFlags = {}): PNode = + rememberExpansion(c, nOrig.info, sym) pushInfoContext(c.config, nOrig.info, sym.detailedInfo) let info = getCallLineInfo(n) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index daf1265e8..6b0dcb0e2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -570,3 +570,13 @@ proc sealRodFile*(c: PContext) = if m == c.module: addPragmaComputation(c, n) c.idgen.sealed = true # no further additions are allowed + +proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) = + ## Templates and macros are very special in Nim; these have + ## inlining semantics so after semantic checking they leave no trace + ## in the sem'checked AST. This is very bad for IDE-like tooling + ## ("find all usages of this template" would not work). We need special + ## logic to remember macro/template expansions. This is done here and + ## delegated to the "rod" file mechanism. + if c.config.symbolFiles != disabledSf: + storeExpansion(c.encoder, c.packedRepr, info, expandedSym) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 256c008c9..cbd4318f7 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -27,6 +27,7 @@ const proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = + rememberExpansion(c, n.info, s) let info = getCallLineInfo(n) markUsed(c, info, s) onUse(info, s) diff --git a/doc/advopt.txt b/doc/advopt.txt index 4842d090e..c7b63d50f 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -15,6 +15,7 @@ Advanced commands: //dump dump all defined conditionals and search paths see also: --dump.format:json (useful with: `| jq`) //check checks the project for syntax and semantic + (can be combined with --track and --defusages) Runtime checks (see -x): --objChecks:on|off turn obj conversion checks on|off @@ -27,6 +28,8 @@ Runtime checks (see -x): --infChecks:on|off turn Inf checks on|off Advanced options: + --track:FILE,LINE,COL set the tracking position for (--defusages) + --defusages find the definition and all usages of a symbol -o:FILE, --out:FILE set the output filename --outdir:DIR set the path where the output file will be written --usenimcache will use `outdir=$$nimcache`, whichever it resolves From 58f44c8b4e6486789a08555dccee6492d32575d4 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 14 Apr 2021 22:45:22 +0800 Subject: [PATCH 2413/4254] Update channels.nim (#17717) --- lib/std/channels.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/channels.nim b/lib/std/channels.nim index 3bbc8a6b6..49def0913 100644 --- a/lib/std/channels.nim +++ b/lib/std/channels.nim @@ -307,8 +307,8 @@ proc sendUnbufferedMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBloc chan.head = 1 - release(chan.headLock) signal(chan.notEmptyCond) + release(chan.headLock) result = true proc sendMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBlocking: bool): bool = @@ -343,8 +343,8 @@ proc sendMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBlocking: bool if chan.tail == 2 * chan.size: chan.tail = 0 - release(chan.tailLock) signal(chan.notEmptyCond) + release(chan.tailLock) result = true proc recvUnbufferedMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bool = @@ -368,8 +368,8 @@ proc recvUnbufferedMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: chan.head = 0 - release(chan.headLock) signal(chan.notFullCond) + release(chan.headLock) result = true proc recvMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bool = @@ -404,8 +404,8 @@ proc recvMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bo if chan.head == 2 * chan.size: chan.head = 0 - release(chan.headLock) signal(chan.notFullCond) + release(chan.headLock) result = true proc channelCloseMpmc(chan: ChannelRaw): bool = From 44657b78c40475e60187b48157bae41ea5371252 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 15 Apr 2021 01:14:14 +0800 Subject: [PATCH 2414/4254] callback cannot be nil (#17718) `Task.callback` cannot be nil, we need to raise it at debug and release mode Situations: - if users create a Task object without using `toTask` and invoke the Task - if users already move the Task and invoke the Task --- lib/std/tasks.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index 6b7f86ce4..aed36f985 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -75,6 +75,7 @@ proc `=destroy`*(t: var Task) {.inline.} = proc invoke*(task: Task) {.inline.} = ## Invokes the `task`. + assert task.callback != nil task.callback(task.args) template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr: NimNode) = From 56c37759d6183aa32d474e669de618ee9c4f7633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Wed, 14 Apr 2021 20:42:09 +0200 Subject: [PATCH 2415/4254] getCustomPragma is split up in more usable chunks (#11526) * getCustomPragma is split up in more usable chunks * changelog entry * fix for style checks * shitty typedesc special casing * Add since annotation and remove typedesc comments * Fix typo * Revert since annotation because it breaks bootstrapping * Export getCustomPragmaNode conditionally * Reduce code duplication * Update since * Update lib/core/macros.nim * Apply suggestions from code review Co-authored-by: Clyybber Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/core/macros.nim | 254 ++++++++++++++++++++----------- tests/pragmas/tcustom_pragma.nim | 30 +++- 3 files changed, 191 insertions(+), 94 deletions(-) diff --git a/changelog.md b/changelog.md index 2f1d2d816..ec1690e06 100644 --- a/changelog.md +++ b/changelog.md @@ -32,6 +32,7 @@ implementations. Old behavior can be obtained with `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same underlying code is also updated the same way. +- Custom pragma values have now an API for use in macros. - In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, unless `-d:nimLegacyHomeDir` is specified (for a transition period). diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 49c9a999c..ebe5a7187 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1474,80 +1474,153 @@ macro expandMacros*(body: typed): untyped = echo body.toStrLit result = body -proc customPragmaNode(n: NimNode): NimNode = - expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkCheckedFieldExpr}) - let - typ = n.getTypeInst() +proc findPragmaExprForFieldSym(arg, fieldSym: NimNode): NimNode = + case arg.kind + of nnkRecList, nnkRecCase: + for it in arg.children: + result = findPragmaExprForFieldSym(it, fieldSym) + if result != nil: + return + of nnkOfBranch: + return findPragmaExprForFieldSym(arg[1], fieldSym) + of nnkElse: + return findPragmaExprForFieldSym(arg[0], fieldSym) + of nnkIdentDefs: + for i in 0 ..< arg.len-2: + let child = arg[i] + result = findPragmaExprForFieldSym(child, fieldSym) + if result != nil: + return + of nnkAccQuoted, nnkIdent, nnkSym, nnkPostfix: + return nil + of nnkPragmaExpr: + var ident = arg[0] + if ident.kind == nnkPostfix: ident = ident[1] + if ident.kind == nnkAccQuoted: ident = ident[0] + if eqIdent(ident, fieldSym): + return arg[1] + else: + error("illegal arg: ", arg) - if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy: - return typ[1][1] - elif typ.typeKind == ntyTypeDesc: - let impl = typ[1].getImpl() - if impl[0].kind == nnkPragmaExpr: - return impl[0][1] +proc getPragmaByName(pragmaExpr: NimNode, name: string): NimNode = + if pragmaExpr.kind == nnkPragma: + for it in pragmaExpr: + if it.kind in nnkPragmaCallKinds: + if eqIdent(it[0], name): + return it + elif it.kind == nnkSym: + if eqIdent(it, name): + return it + +proc getCustomPragmaNodeFromProcSym(sym: NimNode, name: string): NimNode = + sym.expectKind nnkSym + if sym.symKind != nskProc: error("expected proc sym", sym) + + let impl = sym.getImpl + expectKind(impl, nnkProcDef) + result = getPragmaByName(impl[4], name) + +proc getCustomPragmaNodeFromObjFieldSym(sym: NimNode, name: string): NimNode = + sym.expectKind nnkSym + if sym.symKind != nskField: error("expected field sym", sym) + + # note this is not ``getTypeImpl``, because the result of + # ``getTypeImpl`` is cleaned up of any pragma expressions. + let impl = sym.owner.getImpl + impl.expectKind nnkTypeDef + + let objectTy = if impl[2].kind == nnkRefTy: impl[2][0] + else: impl[2] + + # only works on object types + objectTy.expectKind nnkObjectTy + + let recList = objectTy[2] + recList.expectKind nnkRecList + result = getPragmaByName(findPragmaExprForFieldSym(recList, sym), name) + +proc getCustomPragmaNodeFromTypeSym(sym: NimNode, name: string): NimNode = + sym.expectKind nnkSym + if sym.symKind != nskType: error("expected type sym", sym) + let impl = sym.getImpl + if impl.len > 0: + impl.expectKind nnkTypeDef + let pragmaExpr = impl[0] + if pragmaExpr.kind == nnkPragmaExpr: + result = getPragmaByName(pragmaExpr[1], name) + +proc getCustomPragmaNodeFromVarLetSym(sym: NimNode, name: string): NimNode = + sym.expectKind nnkSym + if sym.symKind notin {nskVar, nskLet}: error("expected var/let sym", sym) + let impl = sym.getImpl + impl.expectKind nnkIdentDefs + impl.expectLen 3 + let pragmaExpr = impl[0] + if pragmaExpr.kind == nnkPragmaExpr: + result = getPragmaByName(pragmaExpr[1], name) + +proc getCustomPragmaNode(sym: NimNode, name: string): NimNode = + sym.expectKind nnkSym + case sym.symKind + of nskField: + result = getCustomPragmaNodeFromObjFieldSym(sym, name) + of nskProc: + result = getCustomPragmaNodeFromProcSym(sym, name) + of nskType: + result = getCustomPragmaNodeFromTypeSym(sym, name) + of nskParam: + # When a typedesc parameter is passed to the macro, it will be of nskParam. + let typeInst = getTypeInst(sym) + if typeInst.kind == nnkBracketExpr and eqIdent(typeInst[0], "typeDesc"): + result = getCustomPragmaNodeFromTypeSym(typeInst[1], name) else: - return impl[0] # handle types which don't have macro at all + error("illegal sym kind for argument: " & $sym.symKind, sym) + of nskVar, nskLet: + # I think it is a bad idea to fall back to the typeSym. The API + # explicity requests a var/let symbol, not a type symbol. + result = + getCustomPragmaNodeFromVarLetSym(sym, name) or + getCustomPragmaNodeFromTypeSym(sym.getTypeInst, name) + else: + error("illegal sym kind for argument: " & $sym.symKind, sym) - if n.kind == nnkSym: # either an variable or a proc - let impl = n.getImpl() - if impl.kind in RoutineNodes: - return impl.pragma - elif impl.kind == nnkIdentDefs and impl[0].kind == nnkPragmaExpr: - return impl[0][1] +since (1, 5): + export getCustomPragmaNode + +proc hasCustomPragma*(n: NimNode, name: string): bool = + n.expectKind nnkSym + let pragmaNode = getCustomPragmaNode(n, name) + result = pragmaNode != nil + +proc getCustomPragmaNodeSmart(n: NimNode, name: string): NimNode = + case n.kind + of nnkDotExpr: + result = getCustomPragmaNode(n[1], name) + of nnkCheckedFieldExpr: + expectKind n[0], nnkDotExpr + result = getCustomPragmaNode(n[0][1], name) + of nnkSym: + result = getCustomPragmaNode(n, name) + of nnkTypeOfExpr: + var typeSym = n.getTypeInst + while typeSym.kind == nnkBracketExpr and typeSym[0].eqIdent "typeDesc": + typeSym = typeSym[1] + case typeSym.kind: + of nnkSym: + result = getCustomPragmaNode(typeSym, name) + of nnkProcTy: + # It is a bad idea to support this. The annotation can't be part + # of a symbol. + let pragmaExpr = typeSym[1] + result = getPragmaByName(pragmaExpr, name) else: - let timpl = typ.getImpl() - if timpl.len>0 and timpl[0].len>1: - return timpl[0][1] - else: - return timpl + typeSym.expectKind nnkSym + of nnkBracketExpr: + result = nil #false + else: + n.expectKind({nnkDotExpr, nnkCheckedFieldExpr, nnkSym, nnkTypeOfExpr}) - if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}: - let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1]) - let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0]) - var typDef = getImpl(if typInst.kind == nnkVarTy: typInst[0] else: typInst) - while typDef != nil: - typDef.expectKind(nnkTypeDef) - let typ = typDef[2] - typ.expectKind({nnkRefTy, nnkPtrTy, nnkObjectTy}) - let isRef = typ.kind in {nnkRefTy, nnkPtrTy} - if isRef and typ[0].kind in {nnkSym, nnkBracketExpr}: # defines ref type for another object(e.g. X = ref X) - typDef = getImpl(typ[0]) - else: # object definition, maybe an object directly defined as a ref type - let - obj = (if isRef: typ[0] else: typ) - var identDefsStack = newSeq[NimNode](obj[2].len) - for i in 0.. 0: - var identDefs = identDefsStack.pop() - if identDefs.kind == nnkRecCase: - identDefsStack.add(identDefs[0]) - for i in 1.. 0 and p[0].kind == nnkSym and p[0] == cp): - return newLit(true) - return newLit(false) + result = newLit(getCustomPragmaNodeSmart(n, $cp) != nil) macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = ## Expands to value of custom pragma `cp` of expression `n` which is expected @@ -1586,22 +1654,26 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = ## assert(o.myField.getCustomPragmaVal(serializationKey) == "mf") ## assert(o.getCustomPragmaVal(serializationKey) == "mo") ## assert(MyObj.getCustomPragmaVal(serializationKey) == "mo") - result = nil - let pragmaNode = customPragmaNode(n) - for p in pragmaNode: - if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp: - if p.len == 2: - result = p[1] - else: - let def = p[0].getImpl[3] - result = newTree(nnkPar) - for i in 1 ..< def.len: - let key = def[i][0] - let val = p[i] - result.add newTree(nnkExprColonExpr, key, val) - break - if result.kind == nnkEmpty: - error(n.repr & " doesn't have a pragma named " & cp.repr()) # returning an empty node results in most cases in a cryptic error, + n.expectKind({nnkDotExpr, nnkCheckedFieldExpr, nnkSym, nnkTypeOfExpr}) + let pragmaNode = getCustomPragmaNodeSmart(n, $cp) + + case pragmaNode.kind + of nnkPragmaCallKinds: + assert pragmaNode[0] == cp + if pragmaNode.len == 2: + result = pragmaNode[1] + else: + # create a named tuple expression for pragmas with multiple arguments + let def = pragmaNode[0].getImpl[3] + result = newTree(nnkPar) + for i in 1 ..< def.len: + let key = def[i][0] + let val = pragmaNode[i] + result.add nnkExprColonExpr.newTree(key, val) + of nnkSym: + error("The named pragma " & cp.repr & " in " & n.repr & " has no arguments and therefore no value.") + else: + error(n.repr & " doesn't have a pragma named " & cp.repr, n) macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped = result = newCall(callee) diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index e9dac753d..5342b78e6 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -156,13 +156,20 @@ block: proc generic_proc[T]() = doAssert Annotated.hasCustomPragma(simpleAttr) - #-------------------------------------------------------------------------- # Pragma on proc type -let a: proc(x: int) {.defaultValue(5).} = nil +type + MyAnnotatedProcType {.defaultValue(4).} = proc(x: int) + +let a {.defaultValue(4).}: proc(x: int) = nil +var b: MyAnnotatedProcType = nil +var c: proc(x: int): void {.defaultValue(5).} = nil static: - doAssert hasCustomPragma(a.type, defaultValue) + doAssert hasCustomPragma(a, defaultValue) + doAssert hasCustomPragma(MyAnnotatedProcType, defaultValue) + doAssert hasCustomPragma(b, defaultValue) + doAssert hasCustomPragma(typeof(c), defaultValue) # bug #8371 template thingy {.pragma.} @@ -378,3 +385,20 @@ block: b {.world.}: int discard Hello(a: 1.0, b: 12) + +# issue #11511 +block: + template myAttr {.pragma.} + + type TObj = object + a {.myAttr.}: int + + macro hasMyAttr(t: typedesc): untyped = + let objTy = t.getType[1].getType + let recList = objTy[2] + let sym = recList[0] + assert sym.kind == nnkSym and sym.eqIdent("a") + let hasAttr = sym.hasCustomPragma("myAttr") + newLit(hasAttr) + + doAssert hasMyAttr(TObj) From d6242d7fe19849d6cc7079f0b006065fb2a8a19e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Apr 2021 12:22:22 -0700 Subject: [PATCH 2416/4254] simplify asyncfutures, asyncmacro (#17633) --- lib/pure/asyncfutures.nim | 20 ++++---- lib/pure/asyncmacro.nim | 83 +++++++++----------------------- tests/async/tasyncintemplate.nim | 28 ++++++++--- tests/errmsgs/tgcsafety.nim | 3 +- tests/pragmas/tcustom_pragma.nim | 20 +++----- 5 files changed, 62 insertions(+), 92 deletions(-) diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 3c36c3453..fd62b2703 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -189,24 +189,22 @@ proc add(callbacks: var CallbackList, function: CallbackFunc) = last = last.next last.next = newCallback -proc complete*[T](future: Future[T], val: T) = - ## Completes `future` with value `val`. +proc completeImpl[T, U](future: Future[T], val: U, isVoid: static bool) = #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) assert(future.error == nil) - future.value = val + when not isVoid: + future.value = val future.finished = true future.callbacks.call() when isFutureLoggingEnabled: logFutureFinish(future) -proc complete*(future: Future[void]) = - ## Completes a void `future`. - #assert(not future.finished, "Future already finished, cannot finish twice.") - checkFinished(future) - assert(future.error == nil) - future.finished = true - future.callbacks.call() - when isFutureLoggingEnabled: logFutureFinish(future) +proc complete*[T](future: Future[T], val: T) = + ## Completes `future` with value `val`. + completeImpl(future, val, false) + +proc complete*(future: Future[void], val = Future[void].default) = + completeImpl(future, (), true) proc complete*[T](future: FutureVar[T]) = ## Completes a `FutureVar`. diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index aaa5d9acd..ce538913f 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -11,7 +11,6 @@ import macros, strutils, asyncfutures - # TODO: Ref https://github.com/nim-lang/Nim/issues/5617 # TODO: Add more line infos proc newCallWithLineInfo(fromNode: NimNode; theProc: NimNode, args: varargs[NimNode]): NimNode = @@ -65,10 +64,7 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode], fromNode: NimNode ) ) -proc processBody(node, retFutureSym: NimNode, - subTypeIsVoid: bool, - futureVarIdents: seq[NimNode]): NimNode = - #echo(node.treeRepr) +proc processBody(node, retFutureSym: NimNode, futureVarIdents: seq[NimNode]): NimNode = result = node case node.kind of nnkReturnStmt: @@ -78,14 +74,9 @@ proc processBody(node, retFutureSym: NimNode, result.add createFutureVarCompletions(futureVarIdents, node) if node[0].kind == nnkEmpty: - if not subTypeIsVoid: - result.add newCall(newIdentNode("complete"), retFutureSym, - newIdentNode("result")) - else: - result.add newCall(newIdentNode("complete"), retFutureSym) + result.add newCall(newIdentNode("complete"), retFutureSym, newIdentNode("result")) else: - let x = node[0].processBody(retFutureSym, subTypeIsVoid, - futureVarIdents) + let x = node[0].processBody(retFutureSym, futureVarIdents) if x.kind == nnkYieldStmt: result.add x else: result.add newCall(newIdentNode("complete"), retFutureSym, x) @@ -98,8 +89,7 @@ proc processBody(node, retFutureSym: NimNode, else: discard for i in 0 ..< result.len: - result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, - futureVarIdents) + result[i] = processBody(result[i], retFutureSym, futureVarIdents) # echo result.repr @@ -146,7 +136,7 @@ proc asyncSingleProc(prc: NimNode): NimNode = if prc.kind == nnkProcTy: result = prc if prc[0][0].kind == nnkEmpty: - result[0][0] = parseExpr("Future[void]") + result[0][0] = quote do: Future[void] return result if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: @@ -180,12 +170,7 @@ proc asyncSingleProc(prc: NimNode): NimNode = else: verifyReturnType(repr(returnType), returnType) - let subtypeIsVoid = returnType.kind == nnkEmpty or - (baseType.kind in {nnkIdent, nnkSym} and - baseType.eqIdent("void")) - let futureVarIdents = getFutureVarIdents(prc.params) - var outerProcBody = newNimNode(nnkStmtList, prc.body) # Extract the documentation comment from the original procedure declaration. @@ -213,42 +198,30 @@ proc asyncSingleProc(prc: NimNode): NimNode = # -> # -> complete(retFuture, result) var iteratorNameSym = genSym(nskIterator, $prcName & "Iter") - var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid, - futureVarIdents) + var procBody = prc.body.processBody(retFutureSym, futureVarIdents) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: # fix #13899, defer should not escape its original scope procBody = newStmtList(newTree(nnkBlockStmt, newEmptyNode(), procBody)) - procBody.add(createFutureVarCompletions(futureVarIdents, nil)) + let resultIdent = ident"result" + procBody.insert(0): quote do: + {.push warning[resultshadowed]: off.} + when `subRetType` isnot void: + var `resultIdent`: `subRetType` + else: + var `resultIdent`: Future[void] + {.pop.} + procBody.add quote do: + complete(`retFutureSym`, `resultIdent`) - if not subtypeIsVoid: - procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"), - newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add( - newIdentNode("warning"), newIdentNode("resultshadowed")), - newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.} - - procBody.insert(1, newNimNode(nnkVarSection, prc.body).add( - newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T - - procBody.insert(2, newNimNode(nnkPragma).add( - newIdentNode("pop"))) # -> {.pop.}) - - procBody.add( - newCall(newIdentNode("complete"), - retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result) - else: - # -> complete(retFuture) - procBody.add(newCall(newIdentNode("complete"), retFutureSym)) - - var closureIterator = newProc(iteratorNameSym, [parseExpr("owned(FutureBase)")], + var closureIterator = newProc(iteratorNameSym, [quote do: owned(FutureBase)], procBody, nnkIteratorDef) closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom = prc.body) closureIterator.addPragma(newIdentNode("closure")) # If proc has an explicit gcsafe pragma, we add it to iterator as well. - if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it == - "gcsafe") != nil: + if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it == "gcsafe") != nil: closureIterator.addPragma(newIdentNode("gcsafe")) outerProcBody.add(closureIterator) @@ -266,12 +239,10 @@ proc asyncSingleProc(prc: NimNode): NimNode = outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym) result = prc - - if subtypeIsVoid: - # Add discardable pragma. - if returnType.kind == nnkEmpty: - # Add Future[void] - result.params[0] = parseExpr("owned(Future[void])") + # Add discardable pragma. + if returnType.kind == nnkEmpty: + # xxx consider removing `owned`? it's inconsistent with non-void case + result.params[0] = quote do: owned(Future[void]) # based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 if procBody.kind != nnkEmpty: @@ -279,10 +250,6 @@ proc asyncSingleProc(prc: NimNode): NimNode = `outerProcBody` result.body = body2 - #echo(treeRepr(result)) - #if prcName == "recvLineInto": - # echo(toStrLit(result)) - macro async*(prc: untyped): untyped = ## Macro which processes async procedures into the appropriate ## iterators and yield statements. @@ -352,9 +319,3 @@ macro multisync*(prc: untyped): untyped = result = newStmtList() result.add(asyncSingleProc(asyncPrc)) result.add(sync) - # echo result.repr - -# overload for await as a fallback handler, based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 -# template await*(f: typed): untyped = - # static: - # error "await only available within {.async.}" diff --git a/tests/async/tasyncintemplate.nim b/tests/async/tasyncintemplate.nim index 0f810b5be..4bddb1d18 100644 --- a/tests/async/tasyncintemplate.nim +++ b/tests/async/tasyncintemplate.nim @@ -1,6 +1,8 @@ discard """ output: ''' 42 +43 +43 1 2 3 @@ -8,16 +10,30 @@ discard """ ''' """ +# xxx move to tests/async/tasyncintemplate.nim import asyncdispatch -# bug #16159 -template foo() = - proc temp(): Future[int] {.async.} = return 42 - proc tempVoid(): Future[void] {.async.} = echo await temp() +block: # bug #16159 + template foo() = + proc temp(): Future[int] {.async.} = return 42 + proc tempVoid(): Future[void] {.async.} = echo await temp() + foo() + waitFor tempVoid() -foo() -waitFor tempVoid() +block: # aliasing `void` + template foo() = + type Foo = void + proc temp(): Future[int] {.async.} = return 43 + proc tempVoid(): Future[Foo] {.async.} = echo await temp() + proc tempVoid2() {.async.} = echo await temp() + foo() + waitFor tempVoid() + waitFor tempVoid2() +block: # sanity check + template foo() = + proc bad(): int {.async.} = discard + doAssert not compiles(bad()) block: # bug #16786 block: diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 09ef92e75..563ead2e0 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -6,7 +6,8 @@ tgcsafety.nim(30, 18) Error: type mismatch: got .} diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 5342b78e6..55761d107 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -262,6 +262,10 @@ block: doAssert input.treeRepr & "\n" == expectedRepr return input + macro expectedAstRepr(expectedRepr: static[string], input: untyped): untyped = + doAssert input.repr == expectedRepr + return input + const procTypeAst = """ ProcTy FormalParams @@ -280,20 +284,10 @@ ProcTy static: doAssert Foo is proc(x: int): Future[void] const asyncProcTypeAst = """ -ProcTy - FormalParams - BracketExpr - Ident "Future" - Ident "void" - IdentDefs - Ident "s" - Ident "string" - Empty - Pragma -""" - +proc (s: string): Future[void] {..}""" + # using expectedAst would show `OpenSymChoice` for Future[void], which is fragile. type - Bar = proc (s: string) {.async, expectedAst(asyncProcTypeAst).} + Bar = proc (s: string) {.async, expectedAstRepr(asyncProcTypeAst).} static: doAssert Bar is proc(x: string): Future[void] From eff9d75379d6f9f4a52c2040425dad1f408ede37 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 14 Apr 2021 22:35:18 +0200 Subject: [PATCH 2417/4254] IC: rodfiles: no floats (#17720) --- compiler/ic/ic.nim | 19 ++++++++----------- compiler/ic/integrity.nim | 6 ++---- compiler/ic/packed_ast.nim | 11 +++++++---- compiler/ic/rodfiles.nim | 3 +-- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 4613b9cb8..4f63ce03a 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -224,7 +224,7 @@ proc toLitId(x: string; m: var PackedModule): LitId = proc toLitId(x: BiggestInt; m: var PackedModule): LitId = ## store an integer as a literal - result = getOrIncl(m.sh.integers, x) + result = getOrIncl(m.sh.numbers, x) proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo = PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m)) @@ -400,7 +400,7 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa typeId: storeTypeLater(n.typ, c, m), info: info) of externIntLit: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.sh.integers, n.intVal), + operand: int32 getOrIncl(m.sh.numbers, n.intVal), typeId: storeTypeLater(n.typ, c, m), info: info) of nkStrLit..nkTripleStrLit: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, @@ -408,7 +408,7 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa typeId: storeTypeLater(n.typ, c, m), info: info) of nkFloatLit..nkFloat128Lit: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.sh.floats, n.floatVal), + operand: int32 getOrIncl(m.sh.numbers, cast[BiggestInt](n.floatVal)), typeId: storeTypeLater(n.typ, c, m), info: info) else: let patchPos = ir.prepare(n.kind, n.flags, @@ -521,8 +521,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef loadSeqSection depsSection, m.imports - loadTabSection integersSection, m.sh.integers - loadTabSection floatsSection, m.sh.floats + loadTabSection numbersSection, m.sh.numbers loadSeqSection exportsSection, m.exports @@ -587,8 +586,7 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac storeSeqSection depsSection, m.imports - storeTabSection integersSection, m.sh.integers - storeTabSection floatsSection, m.sh.floats + storeTabSection numbersSection, m.sh.numbers storeSeqSection exportsSection, m.exports @@ -700,11 +698,11 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; of directIntLit: result.intVal = tree.nodes[n.int].operand of externIntLit: - result.intVal = g[thisModule].fromDisk.sh.integers[n.litId] + result.intVal = g[thisModule].fromDisk.sh.numbers[n.litId] of nkStrLit..nkTripleStrLit: result.strVal = g[thisModule].fromDisk.sh.strings[n.litId] of nkFloatLit..nkFloat128Lit: - result.floatVal = g[thisModule].fromDisk.sh.floats[n.litId] + result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.sh.numbers[n.litId]) of nkModuleRef: let (n1, n2) = sons2(tree, n) assert n1.kind == nkInt32Lit @@ -1151,5 +1149,4 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = echo "symbols: ", m.sh.syms.len, " types: ", m.sh.types.len, " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len, - " strings: ", m.sh.strings.len, " integers: ", m.sh.integers.len, - " floats: ", m.sh.floats.len + " strings: ", m.sh.strings.len, " numbers: ", m.sh.numbers.len diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim index b4545de94..a28f2066a 100644 --- a/compiler/ic/integrity.nim +++ b/compiler/ic/integrity.nim @@ -79,12 +79,10 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) = checkLocalSym(c, tree.nodes[n.int].operand) of directIntLit: discard - of externIntLit: - assert c.g.packed[c.thisModule].fromDisk.sh.integers.hasLitId n.litId + of externIntLit, nkFloatLit..nkFloat128Lit: + assert c.g.packed[c.thisModule].fromDisk.sh.numbers.hasLitId n.litId of nkStrLit..nkTripleStrLit: assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId - of nkFloatLit..nkFloat128Lit: - assert c.g.packed[c.thisModule].fromDisk.sh.floats.hasLitId n.litId of nkModuleRef: let (n1, n2) = sons2(tree, n) assert n1.kind == nkInt32Lit diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 5cc3b1476..0649b56ce 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -106,8 +106,8 @@ type syms*: seq[PackedSym] types*: seq[PackedType] strings*: BiTable[string] # we could share these between modules. - integers*: BiTable[BiggestInt] - floats*: BiTable[BiggestFloat] + numbers*: BiTable[BiggestInt] # we also store floats in here so + # that we can assure that every bit is kept #config*: ConfigRef PackedInstantiation* = object @@ -394,10 +394,13 @@ proc toString*(tree: PackedTree; n: NodePos; sh: Shared; nesting: int; result.addInt tree.nodes[pos].operand of externSIntLit: result.add " " - result.addInt sh.integers[LitId tree.nodes[pos].operand] + result.addInt sh.numbers[LitId tree.nodes[pos].operand] of externUIntLit: result.add " " - result.add $cast[uint64](sh.integers[LitId tree.nodes[pos].operand]) + result.add $cast[uint64](sh.numbers[LitId tree.nodes[pos].operand]) + of nkFloatLit..nkFloat128Lit: + result.add " " + result.add $cast[BiggestFloat](sh.numbers[LitId tree.nodes[pos].operand]) else: result.add "(\n" for i in 1..(nesting+1)*2: result.add ' ' diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 39a5b6b73..fbe1cad33 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -16,8 +16,7 @@ type stringsSection checkSumsSection depsSection - integersSection - floatsSection + numbersSection exportsSection reexportsSection compilerProcsSection From ae9231cfebf800886c4febcf0fc7ccc380066108 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Apr 2021 13:45:25 -0700 Subject: [PATCH 2418/4254] fix CI tests/errmsgs/tgcsafety.nim (#17721) --- tests/errmsgs/tgcsafety.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 563ead2e0..6021d19e1 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim check $file" errormsg: "type mismatch: got .}>" nimout: ''' -tgcsafety.nim(30, 18) Error: type mismatch: got .}> +tgcsafety.nim(31, 18) Error: type mismatch: got .}> but expected one of: proc serve(server: AsyncHttpServer; port: Port; callback: proc (request: Request): Future[void] {.closure, gcsafe.}; From f8dce493d36c10bfdfb3bd4ac87eae7b96b97f1a Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 15 Apr 2021 09:12:44 +0300 Subject: [PATCH 2419/4254] rst indentation fixes (ref #17340) (#17715) --- lib/packages/docutils/rst.nim | 95 +++++++---- lib/packages/docutils/rstast.nim | 18 +- nimdoc/rst2html/expected/rst_examples.html | 4 +- tests/stdlib/trst.nim | 185 ++++++++++++++++++++- tests/stdlib/trstgen.nim | 13 +- 5 files changed, 272 insertions(+), 43 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index c2385d517..7c4b92f88 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1532,6 +1532,55 @@ proc parseUntilNewline(p: var RstParser, father: PRstNode) = of tkEof, tkIndent: break proc parseSection(p: var RstParser, result: PRstNode) {.gcsafe.} + +proc tokenAfterNewline(p: RstParser, start: int): int = + result = start + while true: + case p.tok[result].kind + of tkEof: + break + of tkIndent: + inc result + break + else: inc result + +proc tokenAfterNewline(p: RstParser): int {.inline.} = + result = tokenAfterNewline(p, p.idx) + +proc getWrappableIndent(p: RstParser): int = + ## Gets baseline indentation for bodies of field lists and directives. + ## Handles situations like this (with possible de-indent in [case.3]):: + ## + ## :field: definition [case.1] + ## + ## currInd currentTok(p).col + ## | | + ## v v + ## + ## .. Note:: defItem: [case.2] + ## definition + ## + ## ^ + ## | + ## nextIndent + ## + ## .. Note:: - point1 [case.3] + ## - point 2 + ## + ## ^ + ## | + ## nextIndent + if currentTok(p).kind == tkIndent: + result = currentTok(p).ival + else: + var nextIndent = p.tok[tokenAfterNewline(p)-1].ival + if nextIndent <= currInd(p): # parse only this line [case.1] + result = currentTok(p).col + elif nextIndent >= currentTok(p).col: # may be a definition list [case.2] + result = currentTok(p).col + else: + result = nextIndent # [case.3] + proc parseField(p: var RstParser): PRstNode = ## Returns a parsed rnField node. ## @@ -1541,13 +1590,12 @@ proc parseField(p: var RstParser): PRstNode = var fieldname = newRstNode(rnFieldName) parseUntil(p, fieldname, ":", false) var fieldbody = newRstNode(rnFieldBody) - if currentTok(p).kind != tkIndent: parseLine(p, fieldbody) - if currentTok(p).kind == tkIndent: - var indent = currentTok(p).ival - if indent > col: - pushInd(p, indent) - parseSection(p, fieldbody) - popInd(p) + if currentTok(p).kind == tkWhite: inc p.idx + let indent = getWrappableIndent(p) + if indent > col: + pushInd(p, indent) + parseSection(p, fieldbody) + popInd(p) result.add(fieldname) result.add(fieldbody) @@ -1652,20 +1700,6 @@ proc countTitles(p: var RstParser, n: PRstNode) = if p.s.hTitleCnt >= 2: break -proc tokenAfterNewline(p: RstParser, start: int): int = - result = start - while true: - case p.tok[result].kind - of tkEof: - break - of tkIndent: - inc result - break - else: inc result - -proc tokenAfterNewline(p: RstParser): int {.inline.} = - result = tokenAfterNewline(p, p.idx) - proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool = ## check that underline/overline length is enough for the heading. ## No support for Unicode. @@ -1752,7 +1786,7 @@ proc whichSection(p: RstParser): RstNodeKind = return rnCodeBlock elif currentTok(p).symbol == "::": return rnLiteralBlock - elif currentTok(p).symbol == ".." and predNL(p) and + elif currentTok(p).symbol == ".." and nextTok(p).kind in {tkWhite, tkIndent}: return rnDirective case currentTok(p).kind @@ -1780,10 +1814,9 @@ proc whichSection(p: RstParser): RstNodeKind = elif match(p, tokenAfterNewline(p), "aI") and isAdornmentHeadline(p, tokenAfterNewline(p)): result = rnHeadline - elif predNL(p) and - currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: + elif currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: result = rnBulletList - elif match(p, p.idx, ":w:E") and predNL(p): + elif match(p, p.idx, ":w:E"): # (currentTok(p).symbol == ":") result = rnFieldList elif match(p, p.idx, "(e) ") or match(p, p.idx, "e) ") or @@ -2350,9 +2383,11 @@ proc parseDirective(p: var RstParser, k: RstNodeKind, flags: DirFlags): PRstNode parseLine(p, args) result.add(args) if hasOptions in flags: - if currentTok(p).kind == tkIndent and currentTok(p).ival >= 3 and + if currentTok(p).kind == tkIndent and currentTok(p).ival > currInd(p) and nextTok(p).symbol == ":": + pushInd(p, currentTok(p).ival) options = parseFields(p) + popInd(p) result.add(options) proc indFollows(p: RstParser): bool = @@ -2363,11 +2398,9 @@ proc parseBlockContent(p: var RstParser, father: var PRstNode, ## parse the final content part of explicit markup blocks (directives, ## footnotes, etc). Returns true if succeeded. if currentTok(p).kind != tkIndent or indFollows(p): - var nextIndent = p.tok[tokenAfterNewline(p)-1].ival - if nextIndent <= currInd(p): # parse only this line - nextIndent = currentTok(p).col - pushInd(p, nextIndent) - var content = contentParser(p) + let blockIndent = getWrappableIndent(p) + pushInd(p, blockIndent) + let content = contentParser(p) popInd(p) father.add content result = true diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 394cc2698..00f3f2b35 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -350,7 +350,7 @@ proc renderRstToJson*(node: PRstNode): string = proc renderRstToStr*(node: PRstNode, indent=0): string = ## Writes the parsed RST `node` into a compact string ## representation in the format (one line per every sub-node): - ## ``indent - kind - text - level - order - anchor (if non-zero)`` + ## ``indent - kind - [text|level|order|adType] - anchor (if non-zero)`` ## (suitable for debugging of RST parsing). if node == nil: result.add " ".repeat(indent) & "[nil]\n" @@ -358,21 +358,23 @@ proc renderRstToStr*(node: PRstNode, indent=0): string = result.add " ".repeat(indent) & $node.kind case node.kind of rnLeaf, rnSmiley: - result.add (if node.text == "": "" else: "\t'" & node.text & "'") + result.add (if node.text == "": "" else: " '" & node.text & "'") of rnEnumList: - result.add "\tlabelFmt=" & node.labelFmt + result.add " labelFmt=" & node.labelFmt of rnLineBlockItem: var txt: string - if node.lineIndent == "\n": txt = "\t(blank line)" - else: txt = "\tlineIndent=" & $node.lineIndent.len + if node.lineIndent == "\n": txt = " (blank line)" + else: txt = " lineIndent=" & $node.lineIndent.len result.add txt + of rnAdmonition: + result.add " adType=" & node.adType of rnHeadline, rnOverline, rnMarkdownHeadline: - result.add "\tlevel=" & $node.level + result.add " level=" & $node.level of rnFootnote, rnCitation, rnFootnoteRef, rnOptionListItem: - result.add (if node.order == 0: "" else: "\torder=" & $node.order) + result.add (if node.order == 0: "" else: " order=" & $node.order) else: discard - result.add (if node.anchor == "": "" else: "\tanchor='" & node.anchor & "'") + result.add (if node.anchor == "": "" else: " anchor='" & node.anchor & "'") result.add "\n" for son in node.sons: result.add renderRstToStr(son, indent=indent+2) diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 32abc0f80..5c434193e 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -119,8 +119,8 @@ window.addEventListener('DOMContentLoaded', main);
    -

    - +

    Authors: Andreas Rumpf, Zahary Karadjov
    Version: |nimversion|
    +
    Authors:Andreas Rumpf, Zahary Karadjov
    Version:|nimversion|

    "Complexity" seems to be a lot like "energy": you can transfer it from the end-user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran

    About this document

    Note: This document is a draft! Several of Nim's features may need more precise wording. This manual is constantly evolving into a proper specification.

    diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 0645e4150..2398b92a8 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -1,6 +1,8 @@ discard """ output: ''' +[Suite] RST indentation + [Suite] RST include directive ''' """ @@ -9,9 +11,190 @@ discard """ import ../../lib/packages/docutils/rstgen import ../../lib/packages/docutils/rst -import unittest +import ../../lib/packages/docutils/rstast +import unittest, strutils +import std/private/miscdollars import os +proc toAst(input: string, + rstOptions: RstParseOptions = {roSupportMarkdown, roNimFile}, + error: ref string = nil, + warnings: ref seq[string] = nil): string = + ## If `error` is nil then no errors should be generated. + ## The same goes for `warnings`. + proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind, + arg: string) = + let mc = msgkind.whichMsgClass + let a = $msgkind % arg + var message: string + toLocation(message, filename, line, col + ColRstOffset) + message.add " $1: $2" % [$mc, a] + if mc == mcError: + doAssert error != nil, "unexpected RST error '" & message & "'" + error[] = message + # we check only first error because subsequent ones may be meaningless + raise newException(EParseError, message) + else: + doAssert warnings != nil, "unexpected RST warning '" & message & "'" + warnings[].add message + try: + const filen = "input" + + proc myFindFile(filename: string): string = + # we don't find any files in online mode: + result = "" + + var dummyHasToc = false + var rst = rstParse(input, filen, line=LineRstInit, column=ColRstInit, + dummyHasToc, rstOptions, myFindFile, testMsgHandler) + result = renderRstToStr(rst) + except EParseError: + discard + +suite "RST indentation": + test "nested bullet lists": + let input = dedent """ + * - bullet1 + - bullet2 + * - bullet3 + - bullet4 + """ + let output = input.toAst + check(output == dedent""" + rnBulletList + rnBulletItem + rnBulletList + rnBulletItem + rnInner + rnLeaf 'bullet1' + rnBulletItem + rnInner + rnLeaf 'bullet2' + rnBulletItem + rnBulletList + rnBulletItem + rnInner + rnLeaf 'bullet3' + rnBulletItem + rnInner + rnLeaf 'bullet4' + """) + + test "nested markup blocks": + let input = dedent""" + #) .. Hint:: .. Error:: none + #) .. Warning:: term0 + Definition0 + #) some + paragraph1 + #) term1 + Definition1 + term2 + Definition2 + """ + check(input.toAst == dedent""" + rnEnumList labelFmt=1) + rnEnumItem + rnAdmonition adType=hint + [nil] + [nil] + rnAdmonition adType=error + [nil] + [nil] + rnLeaf 'none' + rnEnumItem + rnAdmonition adType=warning + [nil] + [nil] + rnDefList + rnDefItem + rnDefName + rnLeaf 'term0' + rnDefBody + rnInner + rnLeaf 'Definition0' + rnEnumItem + rnInner + rnLeaf 'some' + rnLeaf ' ' + rnLeaf 'paragraph1' + rnEnumItem + rnDefList + rnDefItem + rnDefName + rnLeaf 'term1' + rnDefBody + rnInner + rnLeaf 'Definition1' + rnDefItem + rnDefName + rnLeaf 'term2' + rnDefBody + rnInner + rnLeaf 'Definition2' + """) + + test "code-block parsing": + let input1 = dedent""" + .. code-block:: nim + :test: "nim c $1" + + template additive(typ: typedesc) = + discard + """ + let input2 = dedent""" + .. code-block:: nim + :test: "nim c $1" + + template additive(typ: typedesc) = + discard + """ + let input3 = dedent""" + .. code-block:: nim + :test: "nim c $1" + template additive(typ: typedesc) = + discard + """ + let inputWrong = dedent""" + .. code-block:: nim + :test: "nim c $1" + + template additive(typ: typedesc) = + discard + """ + let ast = dedent""" + rnCodeBlock + rnDirArg + rnLeaf 'nim' + rnFieldList + rnField + rnFieldName + rnLeaf 'test' + rnFieldBody + rnInner + rnLeaf '"' + rnLeaf 'nim' + rnLeaf ' ' + rnLeaf 'c' + rnLeaf ' ' + rnLeaf '$' + rnLeaf '1' + rnLeaf '"' + rnField + rnFieldName + rnLeaf 'default-language' + rnFieldBody + rnLeaf 'Nim' + rnLiteralBlock + rnLeaf 'template additive(typ: typedesc) = + discard' + """ + check input1.toAst == ast + check input2.toAst == ast + check input3.toAst == ast + # "template..." should be parsed as a definition list attached to ":test:": + check inputWrong.toAst != ast + suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index ed5d72226..29747f4e8 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1118,6 +1118,17 @@ Test1 """ check "
    55\n56\n
    " in input.toHtml + test "Nim code-block indentation": + let input = dedent """ + .. code-block:: nim + :number-lines: 55 + + x + """ + let output = input.toHtml + check "
    55\n
    " in output + check "x" in output + test "RST admonitions": # check that all admonitions are implemented let input0 = dedent """ @@ -1466,7 +1477,7 @@ Test1 """""" & """""" & """""" & - """""" & "\n
    field: text
    ") + """text""" & "\n") test "Field list: body after newline": let output = dedent """ From 51a40c1f38a8a03f745f1982cf74091a1c6f7315 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Thu, 15 Apr 2021 13:55:50 +0200 Subject: [PATCH 2420/4254] Fix getCustomPragmaVal for some multi arg pragmas (#17723) * Fix getCustomPragmaVal for some multi arg pragmas * Bootstrap fix --- lib/core/macros.nim | 86 +++++++++++++++++--------------- tests/pragmas/tcustom_pragma.nim | 9 ++++ 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index ebe5a7187..fc68781da 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1474,23 +1474,20 @@ macro expandMacros*(body: typed): untyped = echo body.toStrLit result = body -proc findPragmaExprForFieldSym(arg, fieldSym: NimNode): NimNode = +proc findPragmaNodeInRecList(arg, fieldSym: NimNode): NimNode = case arg.kind of nnkRecList, nnkRecCase: for it in arg.children: - result = findPragmaExprForFieldSym(it, fieldSym) - if result != nil: - return + result = findPragmaNodeInRecList(it, fieldSym) + if result != nil: return of nnkOfBranch: - return findPragmaExprForFieldSym(arg[1], fieldSym) + return findPragmaNodeInRecList(arg[1], fieldSym) of nnkElse: - return findPragmaExprForFieldSym(arg[0], fieldSym) + return findPragmaNodeInRecList(arg[0], fieldSym) of nnkIdentDefs: - for i in 0 ..< arg.len-2: - let child = arg[i] - result = findPragmaExprForFieldSym(child, fieldSym) - if result != nil: - return + for i in 0.. Date: Thu, 15 Apr 2021 15:45:38 +0200 Subject: [PATCH 2421/4254] Fix array's high & low return type for empty arrays (#17705) * fix array.high/low return type * Add test for empty array low return type Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- compiler/semexprs.nim | 2 ++ lib/system.nim | 8 ++++++++ tests/array/tarray.nim | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cbd4318f7..13b53ef32 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -379,6 +379,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = n.typ = getSysType(c.graph, n.info, tyInt) of tyArray: n.typ = typ[0] # indextype + if n.typ.kind == tyRange and emptyRange(n.typ.n[0], n.typ.n[1]): #Invalid range + n.typ = getSysType(c.graph, n.info, tyInt) of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64: n.typ = n[1].typ.skipTypes({tyTypeDesc}) of tyGenericParam: diff --git a/lib/system.nim b/lib/system.nim index 6e84aca66..38f6d64d3 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -348,6 +348,8 @@ proc high*[T](x: openArray[T]): int {.magic: "High", noSideEffect.} proc high*[I, T](x: array[I, T]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array `x`. ## + ## For empty arrays, the return type is `int`. + ## ## See also: ## * `low(array) <#low,array[I,T]>`_ ## @@ -360,6 +362,8 @@ proc high*[I, T](x: array[I, T]): I {.magic: "High", noSideEffect.} proc high*[I, T](x: typedesc[array[I, T]]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array type. ## + ## For empty arrays, the return type is `int`. + ## ## See also: ## * `low(typedesc[array]) <#low,typedesc[array[I,T]]>`_ ## @@ -420,6 +424,8 @@ proc low*[T](x: openArray[T]): int {.magic: "Low", noSideEffect.} proc low*[I, T](x: array[I, T]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array `x`. ## + ## For empty arrays, the return type is `int`. + ## ## See also: ## * `high(array) <#high,array[I,T]>`_ ## @@ -432,6 +438,8 @@ proc low*[I, T](x: array[I, T]): I {.magic: "Low", noSideEffect.} proc low*[I, T](x: typedesc[array[I, T]]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array type. ## + ## For empty arrays, the return type is `int`. + ## ## See also: ## * `high(typedesc[array]) <#high,typedesc[array[I,T]]>`_ ## diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index 81a43f203..2765ad06d 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -587,3 +587,10 @@ block t12466: a[0'u16 + i] = i for i in 0'u16 ..< 8'u16: a[0'u16 + i] = i + +block t17705: + # https://github.com/nim-lang/Nim/pull/17705 + var a = array[0, int].low + a = int(a) + var b = array[0, int].high + b = int(b) From 3f56b9944e5e81338630060bdc89454853340792 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 16 Apr 2021 01:25:03 +0800 Subject: [PATCH 2422/4254] follow up #17536 (#17727) --- tests/sets/t5792.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sets/t5792.nim b/tests/sets/t5792.nim index efc38b1bc..297a1fc15 100644 --- a/tests/sets/t5792.nim +++ b/tests/sets/t5792.nim @@ -14,4 +14,4 @@ type of {b, c} - {a}: y: int -discard U(k: b, y: 1) +doAssert U(k: b, y: 1).y == 1 From 5c12c711f7076d0b095d6ca392de4e11834ceb0f Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 16 Apr 2021 01:25:35 +0800 Subject: [PATCH 2423/4254] follow up #17518 (#17726) --- tests/vm/tvmmisc.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index f542fa560..f0d2c2dbf 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -279,6 +279,14 @@ block: # bug #10815 const a = P() doAssert $a == "" + +when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734 + block: + type CharSet {.union.} = object + cs: set[char] + vs: array[4, uint64] + const a = Charset(cs: {'a'..'z'}) + doAssert a.repr.len > 0 import tables From 95e8ddabb2bcc37e5f1bdd62bcc891b96f80083a Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Thu, 15 Apr 2021 21:45:51 +0100 Subject: [PATCH 2424/4254] followup #17700 put changelog in wrong file (#17729) * Allow use of colons inside fmt allowing colons inside fmt by replacing the format specifier delimiter lets arbitrary nim code be run within fmt expressions. * oops * Update strformat.nim * one space. * Update lib/pure/strformat.nim Co-authored-by: Andreas Rumpf * Update lib/pure/strformat.nim Co-authored-by: Andreas Rumpf * changed parser to ignore ':' within parens * Update strformat.nim * Update lib/pure/strformat.nim Co-authored-by: flywind * formatting,documentation,backslash escapes Adding support for evaluating expressions by special-casing parentheses causes this regression: `&"""{ "(hello)" }"""` no longer parses. In addition, code such as &"""{(if open: '(' else: ')')}""" wouldn't work. To enable that, as well as the use of, e.g. Table constructors inside curlies, I've added backslash escapes. This also means that if/for/etc statements, unparenthesized, will work, if the colons are escaped, but i've left that under-documented. It's not exactly elegant having two types of escape, but I believe it's the least bad option. * not sure about how this works * changelog * changelog * added json strformat test * pulled my thumb out and wrote a parser * more escapes and string tests * ok, now i'm sure it's broken but cant get a failing test * found it * ok, that'll do * did i delete this? * spcng * spacing * messed up where changelogs are supposed to go * ocd Co-authored-by: Andreas Rumpf Co-authored-by: flywind --- changelog.md | 1 + changelogs/changelog_X_XX_X.md | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index ec1690e06..aeaeb598d 100644 --- a/changelog.md +++ b/changelog.md @@ -38,6 +38,7 @@ unless `-d:nimLegacyHomeDir` is specified (for a transition period). ## Standard library additions and changes +- Added support for parenthesized expressions in `strformat` - Added `sections` iterator in `parsecfg`. diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md index d68ef4c20..524599b11 100644 --- a/changelogs/changelog_X_XX_X.md +++ b/changelogs/changelog_X_XX_X.md @@ -13,8 +13,6 @@ The changes should go to changelog.md! - Changed `example.foo` to take additional `bar` parameter. -- Added support for evaluating parenthesised expressions in strformat - ## Language changes From 12783dbcf0075492a3d090e4dc3ead3628c18a3a Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 16 Apr 2021 14:50:44 +0800 Subject: [PATCH 2425/4254] make the copy operation of Thread an error (#17734) --- lib/system/threads.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index def35c238..7fbfe54ab 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -90,6 +90,8 @@ type dataFn: proc (m: TArg) {.nimcall, gcsafe.} data: TArg +proc `=copy`*[TArg](x: var Thread[TArg], y: Thread[TArg]) {.error.} + var threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}] From 8161b02897a75c4b30593dbcc189cbd49d3832ea Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 16 Apr 2021 00:16:39 -0700 Subject: [PATCH 2426/4254] `import foo {.all.}` reboot (#17706) --- changelog.md | 9 ++++ compiler/ast.nim | 8 +-- compiler/ic/ic.nim | 58 ++++++++++++++------ compiler/ic/rodfiles.nim | 1 + compiler/importer.nim | 67 +++++++++++++++++------ compiler/lookups.nim | 12 +++-- compiler/magicsys.nim | 1 + compiler/modulegraphs.nim | 64 ++++++++++++++-------- compiler/modules.nim | 2 +- compiler/nimeval.nim | 2 +- compiler/options.nim | 2 +- compiler/semdata.nim | 8 ++- compiler/semmagic.nim | 5 ++ compiler/semstmts.nim | 1 + compiler/semtypes.nim | 7 +-- compiler/suggest.nim | 13 +++-- compiler/wordrecg.nim | 2 +- lib/std/importutils.nim | 34 ++++++++++++ testament/categories.nim | 1 + tests/ic/mimports.nim | 9 ++++ tests/ic/mimportsb.nim | 4 ++ tests/ic/timports.nim | 29 ++++++++++ tests/importalls/m1.nim | 70 ++++++++++++++++++++++++ tests/importalls/m2.nim | 3 ++ tests/importalls/m3.nim | 5 ++ tests/importalls/m4.nim | 10 ++++ tests/importalls/mt0.nim | 9 ++++ tests/importalls/mt1.nim | 23 ++++++++ tests/importalls/mt2.nim | 104 ++++++++++++++++++++++++++++++++++++ tests/importalls/mt3.nim | 12 +++++ tests/importalls/mt4.nim | 4 ++ tests/importalls/mt4b.nim | 3 ++ tests/importalls/mt5.nim | 9 ++++ tests/importalls/mt6.nim | 13 +++++ tests/importalls/mt7.nim | 14 +++++ tests/importalls/mt8.nim | 23 ++++++++ tests/importalls/mt9.nim | 12 +++++ tests/importalls/tmain2.nim | 7 +++ 38 files changed, 584 insertions(+), 76 deletions(-) create mode 100644 lib/std/importutils.nim create mode 100644 tests/ic/mimports.nim create mode 100644 tests/ic/mimportsb.nim create mode 100644 tests/ic/timports.nim create mode 100644 tests/importalls/m1.nim create mode 100644 tests/importalls/m2.nim create mode 100644 tests/importalls/m3.nim create mode 100644 tests/importalls/m4.nim create mode 100644 tests/importalls/mt0.nim create mode 100644 tests/importalls/mt1.nim create mode 100644 tests/importalls/mt2.nim create mode 100644 tests/importalls/mt3.nim create mode 100644 tests/importalls/mt4.nim create mode 100644 tests/importalls/mt4b.nim create mode 100644 tests/importalls/mt5.nim create mode 100644 tests/importalls/mt6.nim create mode 100644 tests/importalls/mt7.nim create mode 100644 tests/importalls/mt8.nim create mode 100644 tests/importalls/mt9.nim create mode 100644 tests/importalls/tmain2.nim diff --git a/changelog.md b/changelog.md index aeaeb598d..6dcfab9c6 100644 --- a/changelog.md +++ b/changelog.md @@ -307,6 +307,15 @@ - Added `iterable[T]` type class to match called iterators, which enables writing: `template fn(a: iterable)` instead of `template fn(a: untyped)` +- A new import syntax `import foo {.all.}` now allows to import all symbols (public or private) + from `foo`. It works in combination with all pre-existing import features. + This reduces or eliminates the need for workarounds such as using `include` (which has known issues) + when you need a private symbol for testing or making some internal APIs public just because + another internal module needs those. + It also helps mitigate the lack of cyclic imports in some cases. + +- Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields + for an object type in the current scope. ## Compiler changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 155af6375..4c835871f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -605,6 +605,8 @@ type const routineKinds* = {skProc, skFunc, skMethod, skIterator, skConverter, skMacro, skTemplate} + ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds + tfUnion* = tfNoSideEffect tfGcSafe* = tfThread tfObjHasKids* = tfEnumHasHoles @@ -691,7 +693,7 @@ type mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, - mSymIsInstantiationOf, mNodeId + mSymIsInstantiationOf, mNodeId, mPrivateAccess # things that we can evaluate safely at compile time, even if not asked for it: @@ -841,6 +843,7 @@ type depthLevel*: int symbols*: TStrTable parent*: PScope + allowPrivateAccess*: seq[PSym] # # enable access to private fields PScope* = ref TScope @@ -1011,9 +1014,6 @@ const NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tyProc, tyError} # TODO PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM - ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, - skIterator, - skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfDotSetter, nfDotField, nfIsRef, nfIsPtr, nfPreventCg, nfLL, diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 4f63ce03a..1cd03ecfa 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -36,6 +36,7 @@ type bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position. #producedGenerics*: Table[GenericKey, SymId] exports*: seq[(LitId, int32)] + hidden*: seq[(LitId, int32)] reexports*: seq[(LitId, PackedItemId)] compilerProcs*: seq[(LitId, int32)] converters*, methods*, trmacros*, pureEnums*: seq[int32] @@ -177,6 +178,10 @@ proc addIncludeFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) = m.imports.add toLitId(f, c, m) +proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) = + let nameId = getOrIncl(m.sh.strings, s.name.s) + m.hidden.add((nameId, s.itemId.item)) + proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) = let nameId = getOrIncl(m.sh.strings, s.name.s) m.exports.add((nameId, s.itemId.item)) @@ -524,7 +529,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef loadTabSection numbersSection, m.sh.numbers loadSeqSection exportsSection, m.exports - + loadSeqSection hiddenSection, m.hidden loadSeqSection reexportsSection, m.reexports loadSeqSection compilerProcsSection, m.compilerProcs @@ -589,7 +594,7 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac storeTabSection numbersSection, m.sh.numbers storeSeqSection exportsSection, m.exports - + storeSeqSection hiddenSection, m.hidden storeSeqSection reexportsSection, m.reexports storeSeqSection compilerProcsSection, m.compilerProcs @@ -655,7 +660,9 @@ type syms: seq[PSym] # indexed by itemId types: seq[PType] module*: PSym # the one true module symbol. - iface: Table[PIdent, seq[PackedItemId]] # PackedItemId so that it works with reexported symbols too + iface, ifaceHidden: Table[PIdent, seq[PackedItemId]] + # PackedItemId so that it works with reexported symbols too + # ifaceHidden includes private symbols PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex @@ -882,12 +889,22 @@ proc newPackage(config: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex; m: var LoadedModule) = m.iface = initTable[PIdent, seq[PackedItemId]]() - for e in m.fromDisk.exports: + m.ifaceHidden = initTable[PIdent, seq[PackedItemId]]() + template impl(iface, e) = let nameLit = e[0] - m.iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(PackedItemId(module: LitId(0), item: e[1])) - for re in m.fromDisk.reexports: - let nameLit = re[0] - m.iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(re[1]) + let e2 = + when e[1] is PackedItemId: e[1] + else: PackedItemId(module: LitId(0), item: e[1]) + iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(e2) + + for e in m.fromDisk.exports: + m.iface.impl(e) + m.ifaceHidden.impl(e) + for e in m.fromDisk.reexports: + m.iface.impl(e) + m.ifaceHidden.impl(e) + for e in m.fromDisk.hidden: + m.ifaceHidden.impl(e) let filename = AbsoluteFile toFullPath(conf, fileIdx) # We cannot call ``newSym`` here, because we have to circumvent the ID @@ -1053,16 +1070,21 @@ type values: seq[PackedItemId] i, module: int +template interfSelect(a: LoadedModule, importHidden: bool): auto = + var ret = a.iface.addr + if importHidden: ret = a.ifaceHidden.addr + ret[] + proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache; g: var PackedModuleGraph; module: FileIndex; - name: PIdent): PSym = + name: PIdent, importHidden: bool): PSym = it.decoder = PackedDecoder( lastModule: int32(-1), lastLit: LitId(0), lastFile: FileIndex(-1), config: config, cache: cache) - it.values = g[int module].iface.getOrDefault(name) + it.values = g[int module].interfSelect(importHidden).getOrDefault(name) it.i = 0 it.module = int(module) if it.i < it.values.len: @@ -1070,7 +1092,7 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache; inc it.i proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache; - g: var PackedModuleGraph; module: FileIndex): PSym = + g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym = it.decoder = PackedDecoder( lastModule: int32(-1), lastLit: LitId(0), @@ -1079,7 +1101,7 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache; cache: cache) it.values = @[] it.module = int(module) - for v in g[int module].iface.values: + for v in g[int module].interfSelect(importHidden).values: it.values.add v it.i = 0 if it.i < it.values.len: @@ -1093,9 +1115,9 @@ proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym = iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache; g: var PackedModuleGraph; module: FileIndex; - name: PIdent): PSym = + name: PIdent, importHidden: bool): PSym = setupDecoder() - let values = g[int module].iface.getOrDefault(name) + let values = g[int module].interfSelect(importHidden).getOrDefault(name) for pid in values: let s = loadSym(decoder, g, int(module), pid) assert s != nil @@ -1103,9 +1125,9 @@ iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache; proc interfaceSymbol*(config: ConfigRef, cache: IdentCache; g: var PackedModuleGraph; module: FileIndex; - name: PIdent): PSym = + name: PIdent, importHidden: bool): PSym = setupDecoder() - let values = g[int module].iface.getOrDefault(name) + let values = g[int module].interfSelect(importHidden).getOrDefault(name) result = loadSym(decoder, g, int(module), values[0]) proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator = @@ -1140,6 +1162,10 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = echo " ", m.sh.strings[ex[0]] # reexports*: seq[(LitId, PackedItemId)] + echo "hidden: " & $m.hidden.len + for ex in m.hidden: + echo " ", m.sh.strings[ex[0]], " local ID: ", ex[1] + echo "all symbols" for i in 0..high(m.sh.syms): if m.sh.syms[i].name != LitId(0): diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index fbe1cad33..47362da0b 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -18,6 +18,7 @@ type depsSection numbersSection exportsSection + hiddenSection reexportsSection compilerProcsSection trmacrosSection diff --git a/compiler/importer.nim b/compiler/importer.nim index f8ee0d483..692cdb604 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -12,7 +12,7 @@ import intsets, ast, astalgo, msgs, options, idents, lookups, semdata, modulepaths, sigmatch, lineinfos, sets, - modulegraphs + modulegraphs, wordrecg proc readExceptSet*(c: PContext, n: PNode): IntSet = assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} @@ -107,7 +107,25 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) = if s.owner != origin: c.exportIndirections.incl((origin.id, s.id)) +proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) = + template bail = globalError(c.config, n.info, "invalid pragma") + if n.kind == nkPragmaExpr: + if n.len == 2 and n[1].kind == nkPragma: + result[0] = n[0] + for ni in n[1]: + if ni.kind == nkIdent: result[1].add whichKeyword(ni.ident) + else: bail() + else: bail() + else: + result[0] = n + if result[0].safeLen > 0: + (result[0][^1], result[1]) = splitPragmas(c, result[0][^1]) + proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) = + let (n, kws) = splitPragmas(c, n) + if kws.len > 0: + globalError(c.config, n.info, "unexpected pragma") + let ident = lookups.considerQuotedIdent(c, n) let s = someSym(c.graph, fromMod, ident) if s == nil: @@ -204,18 +222,43 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im for i in 0..n.safeLen-1: importForwarded(c, n[i], exceptSet, fromMod, importSet) -proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym = +proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym = result = realModule c.unusedImports.add((realModule, n.info)) + template createModuleAliasImpl(ident): untyped = + createModuleAlias(realModule, nextSymId c.idgen, ident, realModule.info, c.config.options) if n.kind != nkImportAs: discard elif n.len != 2 or n[1].kind != nkIdent: localError(c.config, n.info, "module alias must be an identifier") elif n[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... - result = createModuleAlias(realModule, nextSymId c.idgen, n[1].ident, realModule.info, - c.config.options) + result = createModuleAliasImpl(n[1].ident) + if importHidden: + if result == realModule: # avoids modifying `realModule`, see D20201209T194412. + result = createModuleAliasImpl(realModule.name) + result.options.incl optImportHidden -proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = +proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] = + var ret: typeof(result) + proc processPragma(n2: PNode): PNode = + let (result2, kws) = splitPragmas(c, n2) + result = result2 + for ai in kws: + case ai + of wImportHidden: ret.importHidden = true + else: globalError(c.config, n.info, "invalid pragma, expected: " & ${wImportHidden}) + + if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as": + ret.node = newNodeI(nkImportAs, n.info) + ret.node.add n[1].processPragma + ret.node.add n[2] + else: + ret.node = n.processPragma + return ret + +proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = + let transf = transformImportAs(c, n) + n = transf.node let f = checkModuleName(c.config, n) if f != InvalidFileIdx: addImportFileDep(c, f) @@ -232,7 +275,7 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = c.recursiveDep = err discard pushOptionEntry(c) - result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f)) + result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f), transf.importHidden) popOptionEntry(c) #echo "set back to ", L @@ -252,16 +295,8 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym = importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) -proc transformImportAs(c: PContext; n: PNode): PNode = - if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as": - result = newNodeI(nkImportAs, n.info) - result.add n[1] - result.add n[2] - else: - result = n - proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = - let it = transformImportAs(c, it) + var it = it let m = myImportModule(c, it, importStmtResult) if m != nil: # ``addDecl`` needs to be done before ``importAllSymbols``! @@ -296,7 +331,6 @@ proc evalImport*(c: PContext, n: PNode): PNode = proc evalFrom*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) checkMinSonsLen(n, 2, c.config) - n[0] = transformImportAs(c, n[0]) var m = myImportModule(c, n[0], result) if m != nil: n[0] = newSymNode(m) @@ -311,7 +345,6 @@ proc evalFrom*(c: PContext, n: PNode): PNode = proc evalImportExcept*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) checkMinSonsLen(n, 2, c.config) - n[0] = transformImportAs(c, n[0]) var m = myImportModule(c, n[0], result) if m != nil: n[0] = newSymNode(m) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 15a22c778..7ceadfb96 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -75,7 +75,7 @@ proc closeScope*(c: PContext) = ensureNoMissingOrUnusedSymbols(c, c.currentScope) rawCloseScope(c) -iterator allScopes(scope: PScope): PScope = +iterator allScopes*(scope: PScope): PScope = var current = scope while current != nil: yield current @@ -311,11 +311,17 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) = if conflict != nil: wrongRedefinition(c, sym.info, sym.name.s, conflict.info) -proc addInterfaceDeclAux(c: PContext, sym: PSym) = - if sfExported in sym.flags: +from ic / ic import addHidden + +proc addInterfaceDeclAux*(c: PContext, sym: PSym, forceExport = false) = + if sfExported in sym.flags or forceExport: # add to interface: if c.module != nil: exportSym(c, sym) else: internalError(c.config, sym.info, "addInterfaceDeclAux") + elif sym.kind in ExportableSymKinds and c.module != nil and isTopLevelInsideDeclaration(c, sym): + strTableAdd(semtabAll(c.graph, c.module), sym) + if c.config.symbolFiles != disabledSf: + addHidden(c.encoder, c.packedRepr, sym) proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) = addDeclAt(c, scope, sym) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index e91bdf272..38d2345c8 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -50,6 +50,7 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType = result = g.sysTypes[kind] if result == nil: case kind + of tyVoid: result = sysTypeFromName("void") of tyInt: result = sysTypeFromName("int") of tyInt8: result = sysTypeFromName("int8") of tyInt16: result = sysTypeFromName("int16") diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 02c745018..9df66269b 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -29,6 +29,7 @@ type patterns*: seq[LazySym] pureEnums*: seq[LazySym] interf: TStrTable + interfHidden: TStrTable uniqueName*: Rope Operators* = object @@ -160,9 +161,25 @@ proc toBase64a(s: cstring, len: int): string = result.add cb64[a shr 2] result.add cb64[(a and 3) shl 4] -template semtab*(m: PSym; g: ModuleGraph): TStrTable = +template interfSelect(iface: Iface, importHidden: bool): TStrTable = + var ret = iface.interf.addr # without intermediate ptr, it creates a copy and compiler becomes 15x slower! + if importHidden: ret = iface.interfHidden.addr + ret[] + +template semtab(g: ModuleGraph, m: PSym): TStrTable = g.ifaces[m.position].interf +template semtabAll*(g: ModuleGraph, m: PSym): TStrTable = + g.ifaces[m.position].interfHidden + +proc initStrTables*(g: ModuleGraph, m: PSym) = + initStrTable(semtab(g, m)) + initStrTable(semtabAll(g, m)) + +proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) = + strTableAdd(semtab(g, m), s) + strTableAdd(semtabAll(g, m), s) + proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} = result = module < g.packed.len and g.packed[module].status == loaded @@ -187,39 +204,43 @@ type modIndex: int ti: TIdentIter rodIt: RodIter + importHidden: bool proc initModuleIter*(mi: var ModuleIter; g: ModuleGraph; m: PSym; name: PIdent): PSym = assert m.kind == skModule mi.modIndex = m.position mi.fromRod = isCachedModule(g, mi.modIndex) + mi.importHidden = optImportHidden in m.options if mi.fromRod: - result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name) + result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name, mi.importHidden) else: - result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interf, name) + result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden), name) proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym = if mi.fromRod: result = nextRodIter(mi.rodIt, g.packed) else: - result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interf) + result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden)) iterator allSyms*(g: ModuleGraph; m: PSym): PSym = + let importHidden = optImportHidden in m.options if isCachedModule(g, m): var rodIt: RodIter - var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position) + var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden) while r != nil: yield r r = nextRodIter(rodIt, g.packed) else: - for s in g.ifaces[m.position].interf.data: + for s in g.ifaces[m.position].interfSelect(importHidden).data: if s != nil: yield s proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym = + let importHidden = optImportHidden in m.options if isCachedModule(g, m): - result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name) + result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden) else: - result = strTableGet(g.ifaces[m.position].interf, name) + result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name) proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym = result = someSym(g, g.systemModule, name) @@ -343,26 +364,23 @@ proc hash*(u: SigHash): Hash = proc hash*(x: FileIndex): Hash {.borrow.} +template getPContext(): untyped = + when c is PContext: c + else: c.c + when defined(nimfind): template onUse*(info: TLineInfo; s: PSym) = - when compiles(c.c.graph): - if c.c.graph.onUsage != nil: c.c.graph.onUsage(c.c.graph, s, info) - else: - if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info) + let c = getPContext() + if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info) template onDef*(info: TLineInfo; s: PSym) = - when compiles(c.c.graph): - if c.c.graph.onDefinition != nil: c.c.graph.onDefinition(c.c.graph, s, info) - else: - if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info) + let c = getPContext() + if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info) template onDefResolveForward*(info: TLineInfo; s: PSym) = - when compiles(c.c.graph): - if c.c.graph.onDefinitionResolveForward != nil: - c.c.graph.onDefinitionResolveForward(c.c.graph, s, info) - else: - if c.graph.onDefinitionResolveForward != nil: - c.graph.onDefinitionResolveForward(c.graph, s, info) + let c = getPContext() + if c.graph.onDefinitionResolveForward != nil: + c.graph.onDefinitionResolveForward(c.graph, s, info) else: template onUse*(info: TLineInfo; s: PSym) = discard @@ -392,7 +410,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) = g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[], uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position)))) - initStrTable(g.ifaces[m.position].interf) + initStrTables(g, m) proc registerModuleById*(g: ModuleGraph; m: FileIndex) = registerModule(g, g.packed[int m].module) diff --git a/compiler/modules.nim b/compiler/modules.nim index 7d7a2b6f7..27b93e8df 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -115,7 +115,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P elif graph.isDirty(result): result.flags.excl sfDirty # reset module fields: - initStrTable(result.semtab(graph)) + initStrTables(graph, result) result.ast = nil processModuleAux() graph.markClientsDirty(fileIdx) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 9be595cce..577c7b586 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -67,7 +67,7 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) = ## This can also be used to *reload* the script. assert i != nil assert i.mainModule != nil, "no main module selected" - initStrTable(i.mainModule.semtab(i.graph)) + initStrTables(i.graph, i.mainModule) i.mainModule.ast = nil let s = if scriptStream != nil: scriptStream diff --git a/compiler/options.nim b/compiler/options.nim index 9eeffb4fb..9ba4d62e4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -41,7 +41,7 @@ type # please make sure we have under 32 options optMemTracker, optSinkInference # 'sink T' inference optCursorInference - + optImportHidden TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 6b0dcb0e2..9e7258a69 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -361,12 +361,12 @@ proc addPattern*(c: PContext, p: LazySym) = addTrmacro(c.encoder, c.packedRepr, p.sym) proc exportSym*(c: PContext; s: PSym) = - strTableAdd(c.module.semtab(c.graph), s) + strTableAdds(c.graph, c.module, s) if c.config.symbolFiles != disabledSf: addExported(c.encoder, c.packedRepr, s) proc reexportSym*(c: PContext; s: PSym) = - strTableAdd(c.module.semtab(c.graph), s) + strTableAdds(c.graph, c.module, s) if c.config.symbolFiles != disabledSf: addReexport(c.encoder, c.packedRepr, s) @@ -536,6 +536,10 @@ proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) = proc isTopLevel*(c: PContext): bool {.inline.} = result = c.currentScope.depthLevel <= 2 +proc isTopLevelInsideDeclaration*(c: PContext, sym: PSym): bool {.inline.} = + # for routeKinds the scope isn't closed yet: + c.currentScope.depthLevel <= 2 + ord(sym.kind in routineKinds) + proc pushCaseContext*(c: PContext, caseNode: PNode) = c.p.caseContext.add((caseNode, 0)) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index c80e689a5..d8be85273 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -577,5 +577,10 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if n[1].typ.skipTypes(abstractInst).kind in {tyUInt..tyUInt64}: n[0].sym.magic = mSubU result = n + of mPrivateAccess: + let sym = n[1].typ[0].sym + assert sym != nil + c.currentScope.allowPrivateAccess.add sym + result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) else: result = n diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2c257bd3d..bedc5a7e5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1067,6 +1067,7 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = elif typsym.kind == skType and sfForward in typsym.flags: s = typsym addInterfaceDecl(c, s) + # PRTEMP no onDef here? else: localError(c.config, name.info, typsym.name.s & " is not a type that can be forwarded") s = typsym diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 34a90a3f2..4763f0fd3 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -138,9 +138,10 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: - incl(e.flags, sfUsed) - incl(e.flags, sfExported) - if not isPure: exportSym(c, e) + incl(e.flags, {sfUsed, sfExported}) + if result.sym != nil and not isPure: + addInterfaceDeclAux(c, e, forceExport = sfExported in result.sym.flags) + result.n.add symNode styleCheckDef(c.config, e) onDef(e.info, e) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index cad776015..7a2c0d964 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -253,10 +253,15 @@ proc filterSymNoOpr(s: PSym; prefix: PNode; res: var PrefixMatch): bool {.inline proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = let fmoduleId = getModule(f).id result = sfExported in f.flags or fmoduleId == c.module.id - for module in c.friendModules: - if fmoduleId == module.id: - result = true - break + + if not result: + for module in c.friendModules: + if fmoduleId == module.id: return true + if f.kind == skField: + let symObj = f.owner + for scope in allScopes(c.currentScope): + for sym in scope.allowPrivateAccess: + if symObj.id == sym.id: return true proc getQuality(s: PSym): range[0..100] = result = 100 diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 6a68e2c70..827efcfa0 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -109,7 +109,7 @@ type wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr", wInOut = "inout", wByCopy = "bycopy", wByRef = "byref", wOneWay = "oneway", - wBitsize = "bitsize" + wBitsize = "bitsize", wImportHidden = "all", TSpecialWords* = set[TSpecialWord] diff --git a/lib/std/importutils.nim b/lib/std/importutils.nim new file mode 100644 index 000000000..4efe0e140 --- /dev/null +++ b/lib/std/importutils.nim @@ -0,0 +1,34 @@ +##[ +Utilities related to import and symbol resolution. + +Experimental API, subject to change. +]## + +#[ +Possible future APIs: +* module symbols (https://github.com/nim-lang/Nim/pull/9560) +* whichModule (subsumes canImport / moduleExists) (https://github.com/timotheecour/Nim/issues/376) +* getCurrentPkgDir (https://github.com/nim-lang/Nim/pull/10530) +* import from a computed string + related APIs (https://github.com/nim-lang/Nim/pull/10527) +]# + +when defined(nimImportutilsExample): + type Foo = object + x1: int # private + proc initFoo*(): auto = Foo() + +proc privateAccess*(t: typedesc) {.magic: "PrivateAccess".} = + ## Enables access to private fields of `t` in current scope. + runnableExamples("-d:nimImportutilsExample"): + # here we're importing a module containing: + # type Foo = object + # x1: int # private + # proc initFoo*(): auto = Foo() + var a = initFoo() + block: + assert not compiles(a.x1) + privateAccess(a.type) + a.x1 = 1 # accessible in this scope + block: + assert a.x1 == 1 # still in scope + assert not compiles(a.x1) diff --git a/testament/categories.nim b/testament/categories.nim index ee5c46519..18508d70c 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -500,6 +500,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) const tempExt = "_temp.nim" for it in walkDirRec(testsDir / "ic"): + # for it in ["tests/ic/timports.nim"]: # debugging: to try a specific test if isTestFile(it) and not it.endsWith(tempExt): let nimcache = nimcacheDir(it, options, getTestSpecTarget()) removeDir(nimcache) diff --git a/tests/ic/mimports.nim b/tests/ic/mimports.nim new file mode 100644 index 000000000..50773e001 --- /dev/null +++ b/tests/ic/mimports.nim @@ -0,0 +1,9 @@ +from mimportsb {.all.} import fnb1, hfnb3 + +proc fn1*(): int = 1 +proc fn2*(): int = 2 +proc hfn3(): int = 3 +proc hfn4(): int = 4 +proc hfn5(): int = 5 + +export mimportsb.fnb2, hfnb3 diff --git a/tests/ic/mimportsb.nim b/tests/ic/mimportsb.nim new file mode 100644 index 000000000..3cae925c5 --- /dev/null +++ b/tests/ic/mimportsb.nim @@ -0,0 +1,4 @@ +proc fnb1*(): int = 1 +proc fnb2*(): int = 2 +proc hfnb3(): int = 3 +proc hfnb4(): int = 4 diff --git a/tests/ic/timports.nim b/tests/ic/timports.nim new file mode 100644 index 000000000..518a689f5 --- /dev/null +++ b/tests/ic/timports.nim @@ -0,0 +1,29 @@ +import mimports +doAssert fn1() == 1 +doAssert not declared(hfn3) + +#!EDIT!# + +import mimports {.all.} +doAssert fn1() == 1 +doAssert declared(hfn3) +doAssert hfn3() == 3 +doAssert mimports.hfn4() == 4 + +# reexports +doAssert not declared(fnb1) +doAssert not declared(hfnb4) +doAssert fnb2() == 2 +doAssert hfnb3() == 3 + +#!EDIT!# + +from mimports {.all.} import hfn3 +doAssert not declared(fn1) +from mimports {.all.} as bar import fn1 +doAssert fn1() == 1 +doAssert hfn3() == 3 +doAssert not declared(hfn4) +doAssert declared(mimports.hfn4) +doAssert mimports.hfn4() == 4 +doAssert bar.hfn4() == 4 diff --git a/tests/importalls/m1.nim b/tests/importalls/m1.nim new file mode 100644 index 000000000..b6ccbf5da --- /dev/null +++ b/tests/importalls/m1.nim @@ -0,0 +1,70 @@ +import ./m2 +import ./m3 {.all.} as m3 +from ./m3 as m3Bis import nil + +doAssert m3h2 == 2 +export m3h2 + +export m3Bis.m3p1 + +const foo0* = 2 +const foo1 = bar1 + +const foo1Aux = 2 +export foo1Aux + +doAssert not declared(bar2) +doAssert not compiles(bar2) + +var foo2 = 2 +let foo3 = 2 + +type Foo4 = enum + kg1, kg2 + +type Foo4b {.pure.} = enum + foo4b1, foo4b2 + +type Foo5 = object + z1: string + z2: Foo4 + z3: int + z4*: int + +proc `z3`*(a: Foo5): auto = + a.z3 * 10 + +proc foo6(): auto = 2 +proc foo6b*(): auto = 2 +template foo7: untyped = 2 +macro foo8(): untyped = discard +template foo9(a: int) = discard + +block: + template foo10: untyped = 2 + type Foo11 = enum + kg1b, kg2b + proc foo12(): auto = 2 + +proc initFoo5*(z3: int): Foo5 = Foo5(z3: z3) + +func foo13(): auto = 2 +iterator foo14a(): int = discard +iterator foo14b*(): int = discard +iterator foo14c(): int {.closure.} = discard +iterator foo14d(): int {.inline.} = discard + +# fwd declare +proc foo15(): int +proc foo15(): int = 2 + +proc foo16*(): int +proc foo16(): int = 2 + +proc foo17*(): int +proc foo17*(): int = 2 + +# other +type A1 = distinct int +type A2 = distinct int +converter foo18(x: A1): A2 = discard diff --git a/tests/importalls/m2.nim b/tests/importalls/m2.nim new file mode 100644 index 000000000..186650f68 --- /dev/null +++ b/tests/importalls/m2.nim @@ -0,0 +1,3 @@ +const bar1* = 2 +const bar2 = 2 +const bar3 = 3 diff --git a/tests/importalls/m3.nim b/tests/importalls/m3.nim new file mode 100644 index 000000000..caeae2a01 --- /dev/null +++ b/tests/importalls/m3.nim @@ -0,0 +1,5 @@ +# xxx use below naming convention in other test files: p: public, h: hidden +const m3p1* = 2 +const m3h2 = 2 +const m3h3 = 3 +const m3h4 = 4 diff --git a/tests/importalls/m4.nim b/tests/importalls/m4.nim new file mode 100644 index 000000000..b682b766a --- /dev/null +++ b/tests/importalls/m4.nim @@ -0,0 +1,10 @@ +{.warning[UnusedImport]: off.} # xxx bug: this shouldn't be needed since we have `export m3` +import ./m3 {.all.} +import ./m3 as m3b +export m3b +export m3h3 +export m3.m3h4 + +import ./m2 {.all.} as m2b +export m2b except bar3 + diff --git a/tests/importalls/mt0.nim b/tests/importalls/mt0.nim new file mode 100644 index 000000000..154d30ef9 --- /dev/null +++ b/tests/importalls/mt0.nim @@ -0,0 +1,9 @@ +import ./m1 as m +doAssert compiles(foo0) +doAssert not compiles(foo1) +doAssert foo6b() == 2 +doAssert m3h2 == 2 + +var f = initFoo5(z3=3) +doAssert f.z3 == 30 +doAssert z3(f) == 30 diff --git a/tests/importalls/mt1.nim b/tests/importalls/mt1.nim new file mode 100644 index 000000000..87c4eff16 --- /dev/null +++ b/tests/importalls/mt1.nim @@ -0,0 +1,23 @@ +import ./m1 {.all.} as m +doAssert foo1 == 2 +doAssert m.foo1 == 2 + +doAssert m.m3h2 == 2 +doAssert m3h2 == 2 +doAssert m.foo1Aux == 2 +doAssert m.m3p1 == 2 + +## field access +import std/importutils +privateAccess(Foo5) +# var x = Foo5(z1: "foo", z2: m.kg1) +# doAssert x.z1 == "foo" + +var f0: Foo5 +f0.z3 = 3 +doAssert f0.z3 == 3 +var f = initFoo5(z3=3) +doAssert f.z3 == 3 +doAssert z3(f) == 30 +doAssert m.z3(f) == 30 +doAssert not compiles(mt1.`z3`(f)) # z3 is an imported symbol diff --git a/tests/importalls/mt2.nim b/tests/importalls/mt2.nim new file mode 100644 index 000000000..52edbb69e --- /dev/null +++ b/tests/importalls/mt2.nim @@ -0,0 +1,104 @@ +from ./m1 {.all.} as r1 import foo1 +from ./m1 {.all.} as r2 import foo7 + +block: # different symbol kinds + doAssert foo1 == 2 + doAssert r1.foo1 == 2 + doAssert r1.foo2 == 2 + doAssert compiles(foo1) + doAssert compiles(r1.foo2) + doAssert not compiles(foo2) + doAssert not compiles(m3h2) + doAssert r1.foo3 == 2 + + block: # enum + var a: r1.Foo4 + let a1 = r1.kg1 + doAssert a1 == r1.Foo4.kg1 + type A = r1.Foo4 + doAssert a1 == A.kg1 + doAssert not compiles(kg1) + doAssert compiles(A.kg1) + var witness = false + for ai in r1.Foo4: + doAssert ai == a + doAssert ai == a1 + witness = true + break + doAssert witness + + block: # {.pure.} enum + var a: r1.Foo4b + doAssert not compiles(r1.foo4b1) # because pure + doAssert not compiles(foo4b1) + let a1 = r1.Foo4b.foo4b1 + doAssert a1 == a + type A = r1.Foo4b + doAssert a1 == A.foo4b1 + var witness = false + for ai in A: + doAssert ai == a + doAssert ai == a1 + witness = true + break + doAssert witness + + block: # object + doAssert compiles(r1.Foo5) + var a: r1.Foo5 + doAssert compiles(a.z4) + doAssert not compiles(a.z3) + + block: # remaining symbol kinds + doAssert r1.foo6() == 2 + doAssert r1.foo6b() == 2 + doAssert foo7() == 2 + doAssert r2.foo6b() == 2 + + r1.foo8() + r1.foo9(1) + doAssert r1.foo13() == 2 + for a in r1.foo14a(): discard + for a in r1.foo14b(): discard + for a in r1.foo14c(): discard + for a in r1.foo14d(): discard + doAssert r1.foo15() == 2 + doAssert r1.foo16() == 2 + doAssert r1.foo17() == 2 + doAssert compiles(r1.foo18) + doAssert declared(r1.foo18) + + block: # declarations at block scope should not be visible + doAssert declared(foo7) + doAssert declared(r1.foo6) + doAssert not declared(foo10) + doAssert not declared(foo6) + doAssert not declared(r1.Foo11) + doAssert not declared(r1.kg1b) + doAssert not declared(r1.foo12) + doAssert not compiles(r1.foo12()) + +## field access +import std/importutils +privateAccess(r1.Foo5) +var x = r1.Foo5(z1: "foo", z2: r1.kg1) +doAssert x.z1 == "foo" + +var f0: r1.Foo5 +f0.z3 = 3 +doAssert f0.z3 == 3 +var f = r1.initFoo5(z3=3) +doAssert f.z3 == 3 +doAssert r1.z3(f) == 30 + +import ./m1 as r3 +doAssert not declared(foo2) +doAssert not declared(r3.foo2) + +from ./m1 {.all.} as r4 import nil +doAssert not declared(foo2) +doAssert declared(r4.foo2) + +from ./m1 {.all.} import nil +doAssert not declared(foo2) +doAssert declared(m1.foo2) diff --git a/tests/importalls/mt3.nim b/tests/importalls/mt3.nim new file mode 100644 index 000000000..2bd7fd79d --- /dev/null +++ b/tests/importalls/mt3.nim @@ -0,0 +1,12 @@ +import ./m1 {.all.} + # D20201209T194412:here keep this as is, without `as`, so that mt8.nim test keeps + # checking that the original module symbol for `m1` isn't modified and that + # only the alias in `createModuleAlias` is affected. +doAssert declared(m1.foo1) +doAssert foo1 == 2 + + +doAssert m1.foo1 == 2 + +doAssert not compiles(mt3.foo0) # foo0 is an imported symbol +doAssert not compiles(mt3.foo1) # ditto diff --git a/tests/importalls/mt4.nim b/tests/importalls/mt4.nim new file mode 100644 index 000000000..cd7d32aad --- /dev/null +++ b/tests/importalls/mt4.nim @@ -0,0 +1,4 @@ +import ./m1 {.all.} except foo1 +doAssert foo2 == 2 +doAssert declared(foo2) +doAssert not compiles(foo1) diff --git a/tests/importalls/mt4b.nim b/tests/importalls/mt4b.nim new file mode 100644 index 000000000..4578bc54c --- /dev/null +++ b/tests/importalls/mt4b.nim @@ -0,0 +1,3 @@ +from ./m1 {.all.} as m2 import nil +doAssert not compiles(foo1) +doAssert m2.foo1 == 2 diff --git a/tests/importalls/mt5.nim b/tests/importalls/mt5.nim new file mode 100644 index 000000000..5c5785af6 --- /dev/null +++ b/tests/importalls/mt5.nim @@ -0,0 +1,9 @@ +import ./m1 {.all.} as m2 except foo1 +doAssert foo2 == 2 +doAssert not compiles(foo1) +doAssert m2.foo1 == 2 +doAssert compiles(m2.foo1) + +from system {.all.} as s import ThisIsSystem +doAssert ThisIsSystem +doAssert s.ThisIsSystem diff --git a/tests/importalls/mt6.nim b/tests/importalls/mt6.nim new file mode 100644 index 000000000..c6d8b2193 --- /dev/null +++ b/tests/importalls/mt6.nim @@ -0,0 +1,13 @@ +import ./m1 {.all.} as m2 +doAssert compiles(foo1) +doAssert compiles(m2.foo1) +doAssert declared(foo1) +doAssert declared(m2.foo0) # public: works fine + +doAssert m2.foo1 == 2 +doAssert declared(m2.foo1) +doAssert not declared(m2.nonexistant) + +# also tests the quoted `""` import +import "."/"m1" {.all.} as m1b +doAssert compiles(m1b.foo1) diff --git a/tests/importalls/mt7.nim b/tests/importalls/mt7.nim new file mode 100644 index 000000000..45a664610 --- /dev/null +++ b/tests/importalls/mt7.nim @@ -0,0 +1,14 @@ +include ./m1 +doAssert compiles(foo1) +doAssert compiles(mt7.foo1) +doAssert declared(foo1) +doAssert declared(mt7.foo1) +doAssert declared(mt7.foo0) + +var f0: Foo5 +f0.z3 = 3 +doAssert f0.z3 == 3 +var f = initFoo5(z3=3) +doAssert f.z3 == 3 +doAssert mt7.z3(f) == 30 +doAssert z3(f) == 30 diff --git a/tests/importalls/mt8.nim b/tests/importalls/mt8.nim new file mode 100644 index 000000000..f484e7b01 --- /dev/null +++ b/tests/importalls/mt8.nim @@ -0,0 +1,23 @@ +#[ +test multiple imports +]# + +{.warning[UnusedImport]: off.} +import ./m1, m2 {.all.}, ./m3 {.all.} + # make sure this keeps using `import ./m1` without as. + +# m1 is regularly imported +doAssert declared(m1.foo0) +doAssert declared(foo0) + +doAssert not declared(m1.foo1) + # if we didn't call `createModuleAlias` even for `import f1 {.all.}`, + # this would fail, see D20201209T194412. + +# m2 +doAssert declared(m2.bar2) +doAssert declared(bar2) + +# m3 +doAssert declared(m3.m3h2) +doAssert declared(m3h2) diff --git a/tests/importalls/mt9.nim b/tests/importalls/mt9.nim new file mode 100644 index 000000000..42d48ecbd --- /dev/null +++ b/tests/importalls/mt9.nim @@ -0,0 +1,12 @@ +# tests re-export of a module with import {.all.} + +import ./m4 + +doAssert m3p1 == 2 +doAssert not declared(m3h2) +doAssert m3h3 == 3 +doAssert m3h4 == 4 + +doAssert bar1 == 2 +doAssert bar2 == 2 +doAssert not declared(bar3) diff --git a/tests/importalls/tmain2.nim b/tests/importalls/tmain2.nim new file mode 100644 index 000000000..596f0f135 --- /dev/null +++ b/tests/importalls/tmain2.nim @@ -0,0 +1,7 @@ +discard """ +joinable: false # for clarity, but not necessary +""" + +{.warning[UnusedImport]: off.} +# only import `mt*.nim` here; these depend on `m*.nim` +import "."/[mt0,mt1,mt2,mt3,mt4,mt4b,mt5,mt6,mt7,mt8,mt9] From 606288974f5a424d4c5063bc6ce9c1b5cdc0a7bc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 16 Apr 2021 12:20:43 +0200 Subject: [PATCH 2427/4254] ic navigator tests (#17735) * IC navigator: first basic test --- .gitignore | 1 + compiler/ic/ic.nim | 3 ++- compiler/ic/navigator.nim | 2 +- testament/categories.nim | 19 ++++++++++++------- testament/testament.nim | 10 +++++----- tests/navigator/tnav1.nim | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 tests/navigator/tnav1.nim diff --git a/.gitignore b/.gitignore index a22a4cd03..e9e742404 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ tweeter_test.db /tests/megatest.nim /tests/ic/*_temp.nim +/tests/navigator/*_temp.nim /outputExpected.txt diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 1cd03ecfa..1f2d502ae 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -494,7 +494,8 @@ proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) = of includeFileChanged: rawMessage(config, warnFileChanged, filename.string) else: - echo "Error: ", $err, " loading file: ", filename.string + rawMessage(config, warnCannotOpenFile, filename.string & " reason: " & $err) + #echo "Error: ", $err, " loading file: ", filename.string proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef; ignoreConfig = false): RodFileError = diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index ad2b29f42..b09275220 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -79,7 +79,7 @@ proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) = file = os.extractFilename file toLocation(m, file, info.line.int, info.col.int + ColOffset) if not c.alreadyEmitted.containsOrIncl(m): - echo (if isDecl: "def" else: "usage"), c.outputSep, m + msgWriteln c.g.config, (if isDecl: "def" else: "usage") & c.outputSep & m proc list(c: var NavContext; tree: PackedTree; sym: ItemId) = for i in 0..high(tree.nodes): diff --git a/testament/categories.nim b/testament/categories.nim index 18508d70c..7b57adb8a 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -483,24 +483,27 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = # ---------------- IC tests --------------------------------------------- -proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) = +proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; + isNavigatorTest: bool) = const tooltests = ["compiler/nim.nim", "tools/nimgrep.nim"] writeOnly = " --incremental:writeonly " readOnly = " --incremental:readonly " incrementalOn = " --incremental:on -d:nimIcIntegrityChecks " + navTestConfig = " --ic:on --defusages -d:nimIcNavigatorTests --hint[Conf]:off --warnings:off " template test(x: untyped) = testSpecWithNimcache(r, makeRawTest(file, x & options, cat), nimcache) template editedTest(x: untyped) = var test = makeTest(file, x & options, cat) + if isNavigatorTest: + test.spec.action = actionCompile test.spec.targets = {getTestSpecTarget()} testSpecWithNimcache(r, test, nimcache) const tempExt = "_temp.nim" - for it in walkDirRec(testsDir / "ic"): - # for it in ["tests/ic/timports.nim"]: # debugging: to try a specific test + for it in walkDirRec(testsDir): if isTestFile(it) and not it.endsWith(tempExt): let nimcache = nimcacheDir(it, options, getTestSpecTarget()) removeDir(nimcache) @@ -510,10 +513,10 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) let file = it.replace(".nim", tempExt) writeFile(file, fragment) let oldPassed = r.passed - editedTest incrementalOn + editedTest(if isNavigatorTest: navTestConfig else: incrementalOn) if r.passed != oldPassed+1: break - when false: + if not isNavigatorTest and false: for file in tooltests: let nimcache = nimcacheDir(file, options, getTestSpecTarget()) removeDir(nimcache) @@ -528,7 +531,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string) # ---------------------------------------------------------------------------- -const AdditionalCategories = ["debugger", "examples", "lib", "ic"] +const AdditionalCategories = ["debugger", "examples", "lib", "ic", "navigator"] const MegaTestCat = "megatest" proc `&.?`(a, b: string): string = @@ -695,7 +698,9 @@ proc processCategory(r: var TResults, cat: Category, of "niminaction": testNimInAction(r, cat, options) of "ic": - icTests(r, testsDir, cat, options) + icTests(r, testsDir / cat2, cat, options, isNavigatorTest=false) + of "navigator": + icTests(r, testsDir / cat2, cat, options, isNavigatorTest=true) of "untestable": # These require special treatment e.g. because they depend on a third party # dependency; see `trunner_special` which runs some of those. diff --git a/testament/testament.nim b/testament/testament.nim index ee7f67484..b9e8f3b95 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -157,8 +157,8 @@ proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, "options", options, "file", filename.quoteShell, "filedir", filename.getFileDir(), "nim", compilerPrefix]) -proc callCompiler(cmdTemplate, filename, options, nimcache: string, - target: TTarget, extraOptions = ""): TSpec = +proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, + target: TTarget, extraOptions = ""): TSpec = let c = prepareTestArgs(cmdTemplate, filename, options, nimcache, target, extraOptions) result.cmd = quoteShellCommand(c) @@ -465,11 +465,11 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, test.startTime = epochTime() case expected.action of actionCompile: - var given = callCompiler(expected.getCmd, test.name, test.options, nimcache, target, + var given = callNimCompiler(expected.getCmd, test.name, test.options, nimcache, target, extraOptions = " --stdout --hint[Path]:off --hint[Processing]:off") compilerOutputTests(test, target, given, expected, r) of actionRun: - var given = callCompiler(expected.getCmd, test.name, test.options, + var given = callNimCompiler(expected.getCmd, test.name, test.options, nimcache, target, extraOptions) if given.err != reSuccess: r.addResult(test, target, "", "$ " & given.cmd & '\n' & given.nimout, given.err) @@ -523,7 +523,7 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, else: compilerOutputTests(test, target, given, expected, r) of actionReject: - var given = callCompiler(expected.getCmd, test.name, test.options, + var given = callNimCompiler(expected.getCmd, test.name, test.options, nimcache, target) cmpMsgs(r, expected, given, test, target) diff --git a/tests/navigator/tnav1.nim b/tests/navigator/tnav1.nim new file mode 100644 index 000000000..d7c6f63e2 --- /dev/null +++ b/tests/navigator/tnav1.nim @@ -0,0 +1,33 @@ +discard """ + cmd: "nim check $options --track:$file,12,7 $file" + nimout: '''def tnav1_temp.nim(11, 10) +usage tnav1_temp.nim(12, 8) + ''' +""" + + +import std / [times] + +proc foo(x: int) = + echo x + +foo(3) +echo "yes", 1 != 3 + +#!EDIT!# +discard """ + cmd: "nim check $options --track:$file,15,2 $file" + nimout: '''def tnav1_temp.nim(12, 6) +usage tnav1_temp.nim(15, 1) + ''' +""" + + +import std / [times] + +proc foo(x: int) = + echo x + +foo(3) +echo "yes", 1 != 3 + From 611b88763f8ec88889b14da31ff220cb47789846 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 16 Apr 2021 03:54:49 -0700 Subject: [PATCH 2428/4254] start using import {.all.} (#17736) --- lib/pure/uri.nim | 22 ---------------------- tests/stdlib/turi.nim | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 4ac04d02e..d2a9f3848 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -555,25 +555,3 @@ proc getDataUri*(data, mime: string, encoding = "utf-8"): string {.since: (1, 3) runnableExamples: static: doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" assert encoding.len > 0 and mime.len > 0 # Must *not* be URL-Safe, see RFC-2397 result = "data:" & mime & ";charset=" & encoding & ";base64," & base64.encode(data) - -when isMainModule and defined(testing): - # needed (pending https://github.com/nim-lang/Nim/pull/11865) because - # `removeDotSegments` is private, the other tests are in `turi`. - block: # removeDotSegments - # `removeDotSegments` is exported for -d:testing only - doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" - doAssert removeDotSegments("") == "" # empty test - doAssert removeDotSegments(".") == "." # trailing period - doAssert removeDotSegments("a1/a2/../a3/a4/a5/./a6/a7/././") == "a1/a3/a4/a5/a6/a7/" - doAssert removeDotSegments("https://a1/a2/../a3/a4/a5/./a6/a7/././") == "https://a1/a3/a4/a5/a6/a7/" - doAssert removeDotSegments("http://a1/a2") == "http://a1/a2" - doAssert removeDotSegments("http://www.ai.") == "http://www.ai." - when false: # xxx these cases are buggy - # this should work, refs https://webmasters.stackexchange.com/questions/73934/how-can-urls-have-a-dot-at-the-end-e-g-www-bla-de - doAssert removeDotSegments("http://www.ai./") == "http://www.ai./" # fails - echo removeDotSegments("http://www.ai./") # http://www.ai/ - echo removeDotSegments("a/b.../c") # b.c - echo removeDotSegments("a/b../c") # bc - echo removeDotSegments("a/.../c") # .c - echo removeDotSegments("a//../b") # a/b - echo removeDotSegments("a/b/c//") # a/b/c// diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index d1a30bbfc..a3b6afe2c 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -3,6 +3,7 @@ discard """ """ import std/uri +from std/uri {.all.} as uri2 import removeDotSegments from std/sequtils import toSeq template main() = @@ -14,6 +15,24 @@ template main() = doAssert decodeUrl(encodeUrl(test1, false), false) == test1 doAssert decodeUrl(encodeUrl(test1)) == test1 + block: # removeDotSegments + doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" + doAssert removeDotSegments("") == "" # empty test + doAssert removeDotSegments(".") == "." # trailing period + doAssert removeDotSegments("a1/a2/../a3/a4/a5/./a6/a7/././") == "a1/a3/a4/a5/a6/a7/" + doAssert removeDotSegments("https://a1/a2/../a3/a4/a5/./a6/a7/././") == "https://a1/a3/a4/a5/a6/a7/" + doAssert removeDotSegments("http://a1/a2") == "http://a1/a2" + doAssert removeDotSegments("http://www.ai.") == "http://www.ai." + when false: # xxx these cases are buggy + # this should work, refs https://webmasters.stackexchange.com/questions/73934/how-can-urls-have-a-dot-at-the-end-e-g-www-bla-de + doAssert removeDotSegments("http://www.ai./") == "http://www.ai./" # fails + echo removeDotSegments("http://www.ai./") # http://www.ai/ + echo removeDotSegments("a/b.../c") # b.c + echo removeDotSegments("a/b../c") # bc + echo removeDotSegments("a/.../c") # .c + echo removeDotSegments("a//../b") # a/b + echo removeDotSegments("a/b/c//") # a/b/c// + block: # parseUri block: let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" From d19e4310dc16cae2329c55dfa8feb94e0981dc0c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 16 Apr 2021 05:21:26 -0700 Subject: [PATCH 2429/4254] std/hashes: hash(ref|ptr|pointer) + other improvements (#17731) --- lib/pure/hashes.nim | 86 +++++++++++++++++++---------- testament/lib/stdtest/testutils.nim | 4 ++ tests/collections/ttables.nim | 14 +++++ tests/stdlib/thashes.nim | 22 +++++++- tests/stdlib/tstrutils.nim | 6 +- 5 files changed, 96 insertions(+), 36 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 3339adba2..2ef0e2454 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -182,7 +182,7 @@ proc hashData*(data: pointer, size: int): Hash = var h: Hash = 0 when defined(js): var p: cstring - asm """`p` = `Data`;""" + asm """`p` = `Data`""" else: var p = cast[cstring](data) var i = 0 @@ -193,32 +193,6 @@ proc hashData*(data: pointer, size: int): Hash = dec(s) result = !$h -when defined(js): - var objectID = 0 - -proc hash*(x: pointer): Hash {.inline.} = - ## Efficient hashing of pointers. - when defined(js): - asm """ - if (typeof `x` == "object") { - if ("_NimID" in `x`) - `result` = `x`["_NimID"]; - else { - `result` = ++`objectID`; - `x`["_NimID"] = `result`; - } - } - """ - else: - result = cast[Hash](cast[uint](x) shr 3) # skip the alignment - -proc hash*[T: proc](x: T): Hash {.inline.} = - ## Efficient hashing of proc vars. Closures are supported too. - when T is "closure": - result = hash(rawProc(x)) !& hash(rawEnv(x)) - else: - result = hash(pointer(x)) - proc hashIdentity*[T: Ordinal|enum](x: T): Hash {.inline, since: (1, 3).} = ## The identity hash, i.e. `hashIdentity(x) = x`. cast[Hash](ord(x)) @@ -232,6 +206,59 @@ else: ## Efficient hashing of integers. hashWangYi1(uint64(ord(x))) +when defined(js): + var objectID = 0 + proc getObjectId(x: pointer): int = + asm """ + if (typeof `x` == "object") { + if ("_NimID" in `x`) + `result` = `x`["_NimID"]; + else { + `result` = ++`objectID`; + `x`["_NimID"] = `result`; + } + } + """ + +proc hash*(x: pointer): Hash {.inline.} = + ## Efficient `hash` overload. + when defined(js): + let y = getObjectId(x) + else: + let y = cast[int](x) + hash(y) # consistent with code expecting scrambled hashes depending on `nimIntHash1`. + +proc hash*[T](x: ref[T] | ptr[T]): Hash {.inline.} = + ## Efficient `hash` overload. + runnableExamples: + var a: array[10, uint8] + assert a[0].addr.hash != a[1].addr.hash + assert cast[pointer](a[0].addr).hash == a[0].addr.hash + runnableExamples: + type A = ref object + x: int + let a = A(x: 3) + let ha = a.hash + assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. + a.x = 4 + assert ha == a.hash # the hash only depends on the address + runnableExamples: + # you can overload `hash` if you want to customize semantics + type A[T] = ref object + x, y: T + proc hash(a: A): Hash = hash(a.x) + assert A[int](x: 3, y: 4).hash == A[int](x: 3, y: 5).hash + # xxx pending bug #17733, merge as `proc hash*(pointer | ref | ptr): Hash` + # or `proc hash*[T: ref | ptr](x: T): Hash` + hash(cast[pointer](x)) + +proc hash*[T: proc](x: T): Hash {.inline.} = + ## Efficient hashing of proc vars. Closures are supported too. + when T is "closure": + result = hash((rawProc(x), rawEnv(x))) + else: + result = hash(pointer(x)) + proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. let y = x + 0.0 # for denormalization @@ -484,10 +511,9 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = h = h !& ord(c) result = !$h - proc hash*[T: tuple | object](x: T): Hash = - ## Efficient hashing of tuples and objects. - ## There must be a `hash` proc defined for each of the field types. + ## Efficient `hash` overload. + ## `hash` must be defined for each component of `x`. runnableExamples: type Obj = object x: int diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index abffff24c..35423de17 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -85,3 +85,7 @@ template accept*(a) = template reject*(a) = doAssert not compiles(a) + +template disableVm*(body) = + when nimvm: discard + else: body diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 61197e9f0..c2864b75f 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -7,7 +7,11 @@ And we get here 3 ''' joinable: false +targets: "c cpp js" """ + +# xxx wrap in a template to test in VM, see https://github.com/timotheecour/Nim/issues/534#issuecomment-769565033 + import hashes, sequtils, tables, algorithm proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted @@ -444,3 +448,13 @@ block emptyOrdered: var t2: OrderedTable[int, string] doAssert t1 == t2 +block: # Table[ref, int] + type A = ref object + x: int + var t: OrderedTable[A, int] + let a1 = A(x: 3) + let a2 = A(x: 3) + t[a1] = 10 + t[a2] = 11 + doAssert t[a1] == 10 + doAssert t[a2] == 11 diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 044259f88..66857d3ca 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -3,7 +3,7 @@ discard """ """ import std/hashes - +from stdtest/testutils import disableVm, whenVMorJs when not defined(js) and not defined(cpp): block: @@ -177,5 +177,25 @@ proc main() = doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1)) doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2)) + block: # hash(ref|ptr|pointer) + var a: array[10, uint8] + # disableVm: + whenVMorJs: + # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417 + discard + do: + assert a[0].addr.hash != a[1].addr.hash + assert cast[pointer](a[0].addr).hash == a[0].addr.hash + + block: # hash(ref) + type A = ref object + x: int + let a = A(x: 3) + disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer + let ha = a.hash + assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. + a.x = 4 + assert ha == a.hash # the hash only depends on the address + static: main() main() diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index a6248d1e3..771dddcaf 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -3,7 +3,7 @@ discard """ """ import std/strutils - +from stdtest/testutils import disableVm # xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed template rejectParse(e) = @@ -12,10 +12,6 @@ template rejectParse(e) = raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e)) except ValueError: discard -template disableVm(body) = - when nimvm: discard - else: body - template main() = block: # strip doAssert strip(" ha ") == "ha" From fdd4391534578d6a5a655eef99ef96e53ff2b4f1 Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Fri, 16 Apr 2021 13:22:51 +0100 Subject: [PATCH 2430/4254] Fix buffer-overrun bug in net (#17728) [backport:1.0] --- changelog.md | 2 ++ lib/pure/net.nim | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 6dcfab9c6..cfdcd3c62 100644 --- a/changelog.md +++ b/changelog.md @@ -40,6 +40,8 @@ ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` +- Fixed buffer overflow bugs in `net` + - Added `sections` iterator in `parsecfg`. - Make custom op in macros.quote work for all statements. diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9be9c6acb..343cdc9b1 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -690,12 +690,11 @@ when defineSsl: let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let hintString = if hint == nil: "" else: $hint let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) - if psk.len.cuint > max_psk_len: + if pskString.len.cuint > max_psk_len: return 0 if identityString.len.cuint >= max_identity_len: return 0 - - copyMem(identity, identityString.cstring, pskString.len + 1) # with the last zero byte + copyMem(identity, identityString.cstring, identityString.len + 1) # with the last zero byte copyMem(psk, pskString.cstring, pskString.len) return pskString.len.cuint @@ -716,7 +715,7 @@ when defineSsl: max_psk_len: cint): cuint {.cdecl.} = let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let pskString = (ctx.serverGetPskFunc)($identity) - if psk.len.cint > max_psk_len: + if pskString.len.cint > max_psk_len: return 0 copyMem(psk, pskString.cstring, pskString.len) From 1b65b9cc193791285f63fcf9d52f19da72fffd4f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 16 Apr 2021 05:55:51 -0700 Subject: [PATCH 2431/4254] refs #17292 fix `repr`: `(discard)` now does't render as `discard` which gave illegal code (#17455) * refs #17292 fix `repr` with (discard) * add tests * add more tests --- compiler/renderer.nim | 8 ++++++- tests/stdlib/trepr.nim | 50 ++++++++++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index b3b0adc01..4c0de9ed5 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1461,7 +1461,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, n, 1) - of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext) + of nkStmtList, nkStmtListExpr, nkStmtListType: + if n.len == 1 and n[0].kind == nkDiscardStmt: + put(g, tkParLe, "(") + gsub(g, n[0]) + put(g, tkParRi, ")") + else: + gstmts(g, n, emptyContext) of nkIfStmt: putWithSpace(g, tkIf, "if") gif(g, n) diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index f72bbb34e..86f3dee30 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -5,9 +5,10 @@ discard """ # if excessive, could remove 'cpp' from targets -from strutils import endsWith, contains +from strutils import endsWith, contains, strip from std/macros import newLit -macro deb(a): string = newLit a.repr + +macro deb(a): string = newLit a.repr.strip template main() = doAssert repr({3,5}) == "{3, 5}" @@ -67,17 +68,16 @@ template main() = else: doAssert reprOpenarray(arr) == "[1, 2, 3]" - block: # bug #17292 + block: # bug #17292 repr with `do` template foo(a, b, c, d) = discard block: let a = deb: foo(1, 2, 3, 4) - doAssert a == "\nfoo(1, 2, 3, 4)" + doAssert a == "foo(1, 2, 3, 4)" block: let a = deb: foo(1, 2, 3): 4 doAssert a == """ - foo(1, 2, 3): 4""" @@ -86,7 +86,6 @@ foo(1, 2, 3): foo(1, 2): 3 do: 4 doAssert a == """ - foo(1, 2): 3 do: @@ -98,7 +97,6 @@ do: do: 3 do: 4 doAssert a == """ - foo(1): 3 do: @@ -118,7 +116,6 @@ do: 4 doAssert a == """ - foo(1): 3 do: @@ -135,7 +132,6 @@ do: do: 3 do: 4 doAssert a == """ - foo: 1 do: @@ -145,13 +141,44 @@ do: do: 4""" + block: # bug #17292 repr with `(discard)` (`discard` would result in illegal code) + let a = deb: + let f {.inject.} = () => (discard) + doAssert a == """ +let f {.inject.} = () => + (discard )""" + + let a2 = deb: + block: + discard + discard + + block: + when true: discard + + # let a = b => discard # illegal + discard b => (discard) # legal + + block: + return + doAssert a2 == """ +block: + discard +discard +block: + when true: + discard +discard b => + (discard ) +block: + return""" + block: # bug #17292 (bug 4) let a = deb: proc `=destroy`() = discard proc `'foo`(): int = discard proc `foo bar baz`(): int = discard let a2 = """ - proc `=destroy`() = discard @@ -159,8 +186,7 @@ proc `'foo`(): int = discard proc `foo bar baz`(): int = - discard -""" + discard""" doAssert a2 == a block: # setters: `foo=` From 957478ce264d0496f9a0c33de4af77ad0846b42d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 16 Apr 2021 15:23:17 +0200 Subject: [PATCH 2432/4254] removed nimfind tool, succeeded by 'nim check --defusages' (#17737) --- koch.nim | 2 - tools/nimfind.nim | 234 --------------------------------------------- tools/nimfind.nims | 2 - 3 files changed, 238 deletions(-) delete mode 100644 tools/nimfind.nim delete mode 100644 tools/nimfind.nims diff --git a/koch.nim b/koch.nim index 44d38589b..3e41310d7 100644 --- a/koch.nim +++ b/koch.nim @@ -216,8 +216,6 @@ proc buildTools(args: string = "") = options = "-d:release " & args) when defined(windows): buildVccTool(args) bundleNimpretty(args) - nimCompileFold("Compile nimfind", "tools/nimfind.nim", - options = "-d:release " & args) nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release " & args) diff --git a/tools/nimfind.nim b/tools/nimfind.nim deleted file mode 100644 index 9c8247606..000000000 --- a/tools/nimfind.nim +++ /dev/null @@ -1,234 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2018 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Nimfind is a tool that helps to give editors IDE like capabilities. - -when not defined(nimcore): - {.error: "nimcore MUST be defined for Nim's core tooling".} -when not defined(nimfind): - {.error: "nimfind MUST be defined for Nim's nimfind tool".} - -const Usage = """ -Nimfind - Tool to find declarations or usages for Nim symbols -Usage: - nimfind [options] file.nim:line:col - -Options: - --help, -h show this help - --rebuild rebuild the index - --project:file.nim use file.nim as the entry point - -In addition, all command line options of Nim that do not affect code generation -are supported. -""" - -import strutils, os, parseopt - -import "../compiler" / [options, commands, modules, sem, - passes, passaux, msgs, ast, - idents, modulegraphs, lineinfos, cmdlinehelper, - pathutils] - -import db_sqlite - -proc createDb(db: DbConn) = - db.exec(sql""" - create table if not exists filenames( - id integer primary key, - fullpath varchar(8000) not null - ); - """) - db.exec sql"create index if not exists FilenameIx on filenames(fullpath);" - - # every sym can have potentially 2 different definitions due to forward - # declarations. - db.exec(sql""" - create table if not exists syms( - id integer primary key, - nimid integer not null, - name varchar(256) not null, - defline integer not null, - defcol integer not null, - deffile integer not null, - deflineB integer not null default 0, - defcolB integer not null default 0, - deffileB integer not null default 0, - foreign key (deffile) references filenames(id), - foreign key (deffileB) references filenames(id) - ); - """) - - db.exec(sql""" - create table if not exists usages( - id integer primary key, - nimid integer not null, - line integer not null, - col integer not null, - colB integer not null, - file integer not null, - foreign key (file) references filenames(id), - foreign key (nimid) references syms(nimid) - ); - """) - db.exec sql"create index if not exists UsagesIx on usages(file, line);" - -proc toDbFileId*(db: DbConn; conf: ConfigRef; fileIdx: FileIndex): int = - if fileIdx == FileIndex(-1): return -1 - let fullpath = toFullPath(conf, fileIdx) - let row = db.getRow(sql"select id from filenames where fullpath = ?", fullpath) - let id = row[0] - if id.len == 0: - result = int db.insertID(sql"insert into filenames(fullpath) values (?)", - fullpath) - else: - result = parseInt(id) - -type - FinderRef = ref object of RootObj - db: DbConn - -proc writeDef(graph: ModuleGraph; s: PSym; info: TLineInfo) = - let f = FinderRef(graph.backend) - f.db.exec(sql"""insert into syms(nimid, name, defline, defcol, deffile) values (?, ?, ?, ?, ?)""", - s.id, s.name.s, info.line, info.col, - toDbFileId(f.db, graph.config, info.fileIndex)) - -proc writeDefResolveForward(graph: ModuleGraph; s: PSym; info: TLineInfo) = - let f = FinderRef(graph.backend) - f.db.exec(sql"""update syms set deflineB = ?, defcolB = ?, deffileB = ? - where nimid = ?""", info.line, info.col, - toDbFileId(f.db, graph.config, info.fileIndex), s.id) - -proc writeUsage(graph: ModuleGraph; s: PSym; info: TLineInfo) = - let f = FinderRef(graph.backend) - f.db.exec(sql"""insert into usages(nimid, line, col, colB, file) values (?, ?, ?, ?, ?)""", - s.id, info.line, info.col, info.col + s.name.s.len - 1, - toDbFileId(f.db, graph.config, info.fileIndex)) - -proc performSearch(conf: ConfigRef; dbfile: AbsoluteFile) = - var db = open(connection=string dbfile, user="nim", password="", - database="nim") - let pos = conf.m.trackPos - let fid = toDbFileId(db, conf, pos.fileIndex) - let known = toFullPath(conf, pos.fileIndex) - let nimids = db.getRow(sql"""select distinct nimid from usages where line = ? and file = ? and ? between col and colB""", - pos.line, fid, pos.col) - if nimids.len > 0: - var idSet = "" - for id in nimids: - if idSet.len > 0: idSet.add ", " - idSet.add id - var outputLater = "" - for r in db.rows(sql"""select line, col, filenames.fullpath from usages - inner join filenames on filenames.id = file - where nimid in (?)""", idSet): - let line = parseInt(r[0]) - let col = parseInt(r[1]) - let file = r[2] - if file == known and line == pos.line.int: - # output the line we already know last: - outputLater.add file & ":" & $line & ":" & $(col+1) & "\n" - else: - echo file, ":", line, ":", col+1 - if outputLater.len > 0: stdout.write outputLater - close(db) - -proc setupDb(g: ModuleGraph; dbfile: AbsoluteFile) = - var f = FinderRef() - removeFile(dbfile) - f.db = open(connection=string dbfile, user="nim", password="", - database="nim") - createDb(f.db) - f.db.exec(sql"pragma journal_mode=off") - # This MUST be turned off, otherwise it's way too slow even for testing purposes: - f.db.exec(sql"pragma SYNCHRONOUS=off") - f.db.exec(sql"pragma LOCKING_MODE=exclusive") - g.backend = f - -proc mainCommand(graph: ModuleGraph) = - let conf = graph.config - let dbfile = getNimcacheDir(conf) / RelativeFile"nimfind.db" - if not fileExists(dbfile) or optForceFullMake in conf.globalOptions: - clearPasses(graph) - registerPass graph, verbosePass - registerPass graph, semPass - conf.setCmd cmdIdeTools - wantMainModule(conf) - setupDb(graph, dbfile) - - graph.onDefinition = writeUsage # writeDef - graph.onDefinitionResolveForward = writeUsage # writeDefResolveForward - graph.onUsage = writeUsage - - if not fileExists(conf.projectFull): - quit "cannot find file: " & conf.projectFull.string - add(conf.searchPaths, conf.libpath) - conf.setErrorMaxHighMaybe - try: - compileProject(graph) - finally: - close(FinderRef(graph.backend).db) - performSearch(conf, dbfile) - -proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = - var p = parseopt.initOptParser(cmd) - while true: - parseopt.next(p) - case p.kind - of cmdEnd: break - of cmdLongOption, cmdShortOption: - case p.key.normalize - of "help", "h": - stdout.writeLine(Usage) - quit() - of "project": - conf.projectName = p.val - of "rebuild": - incl conf.globalOptions, optForceFullMake - else: processSwitch(pass, p, conf) - of cmdArgument: - let info = p.key.split(':') - if info.len == 3: - conf.projectName = findProjectNimFile(conf, info[0].splitFile.dir) - if conf.projectName.len == 0: conf.projectName = info[0] - try: - conf.m.trackPos = newLineInfo(conf, AbsoluteFile info[0], - parseInt(info[1]), parseInt(info[2])-1) - except ValueError: - quit "invalid command line" - else: - quit "invalid command line" - -proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = - let self = NimProg( - suggestMode: true, - processCmdLine: processCmdLine - ) - self.initDefinesProg(conf, "nimfind") - - if paramCount() == 0: - stdout.writeLine(Usage) - return - - self.processCmdLineAndProjectPath(conf) - - # Find Nim's prefix dir. - let binaryPath = findExe("nim") - if binaryPath == "": - raise newException(IOError, - "Cannot find Nim standard library: Nim compiler not in PATH") - conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir() - if not dirExists(conf.prefixDir / RelativeDir"lib"): - conf.prefixDir = AbsoluteDir"" - - var graph = newModuleGraph(cache, conf) - if self.loadConfigsAndProcessCmdLine(cache, conf, graph): - mainCommand(graph) - -handleCmdLine(newIdentCache(), newConfigRef()) diff --git a/tools/nimfind.nims b/tools/nimfind.nims deleted file mode 100644 index 3013c360d..000000000 --- a/tools/nimfind.nims +++ /dev/null @@ -1,2 +0,0 @@ ---define:nimfind ---define:nimcore From 201ac2b9c93a8c3677b4910a1986c91741aee0e3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 16 Apr 2021 11:26:05 -0700 Subject: [PATCH 2433/4254] fix nim CI following #17455 (same postmortem as #17721) (#17740) --- tests/stdlib/trepr.nim | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 86f3dee30..356764903 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -193,10 +193,8 @@ proc `foo bar baz`(): int = let a = deb: proc `foo=`() = discard doAssert a == """ - proc `foo=`() = - discard -""" + discard""" block: # bug #14850 block: @@ -221,7 +219,6 @@ proc `foo=`() = 4) doAssert a == """ - template bar(): untyped = foo1: discard @@ -244,8 +241,7 @@ template bar(): untyped = 4 a.add(foo7 do: echo "baz" - 4) -""" + 4)""" static: main() main() From 8e474fbb57c2f7b58a840b5b30230c2267633c8e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 17 Apr 2021 01:12:12 +0200 Subject: [PATCH 2434/4254] IC: yet another embarrassing omission (#17743) * IC: yet another embarrassing omission * VM: fewer hacks that kept IC from working --- compiler/ast.nim | 2 +- compiler/ic/ic.nim | 3 ++- compiler/vmdef.nim | 3 +++ compiler/vmgen.nim | 14 ++++++-------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 4c835871f..bf0c9669a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1054,7 +1054,7 @@ const defaultSize = -1 defaultAlignment = -1 - defaultOffset = -1 + defaultOffset* = -1 proc getPIdent*(a: PNode): PIdent {.inline.} = ## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`. diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 1f2d502ae..da0af2edf 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -765,7 +765,8 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; kind: s.kind, magic: s.magic, flags: s.flags, info: translateLineInfo(c, g, si, s.info), options: s.options, - position: s.position, + position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position, + offset: if s.kind in routineKinds: defaultOffset else: s.offset, name: getIdent(c.cache, g[si].fromDisk.sh.strings[s.name]) ) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index e8b5cdda9..068ade4b0 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,6 +10,8 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. +import std / tables + import ast, idents, options, modulegraphs, lineinfos type TInstrType* = uint64 @@ -266,6 +268,7 @@ type profiler*: Profiler templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC) + procToCodePos*: Table[int, int] PStackFrame* = ref TStackFrame TStackFrame* = object diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 69d7ec4b3..951d47d2f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -27,6 +27,8 @@ # solves the opcLdConst vs opcAsgnConst issue. Of course whether we need # this copy depends on the involved types. +import std / tables + import strutils, ast, types, msgs, renderer, vmdef, intsets, magicsys, options, lowerings, lineinfos, transf @@ -2248,8 +2250,8 @@ proc optimizeJumps(c: PCtx; start: int) = else: discard proc genProc(c: PCtx; s: PSym): int = - var x = s.ast[miscPos] - if x.kind == nkEmpty or x[0].kind == nkEmpty: + let pos = c.procToCodePos.getOrDefault(s.id) + if pos == 0: #if s.name.s == "outterMacro" or s.name.s == "innerProc": # echo "GENERATING CODE FOR ", s.name.s let last = c.code.len-1 @@ -2260,11 +2262,7 @@ proc genProc(c: PCtx; s: PSym): int = c.debug.setLen(last) #c.removeLastEof result = c.code.len+1 # skip the jump instruction - if x.kind == nkEmpty: - x = newTree(nkBracket, newIntNode(nkIntLit, result), x) - else: - x[0] = newIntNode(nkIntLit, result) - s.ast[miscPos] = x + c.procToCodePos[s.id] = result # thanks to the jmp we can add top level statements easily and also nest # procs easily: let body = transformBody(c.graph, c.idgen, s, cache = not isCompileTimeProc(s)) @@ -2297,4 +2295,4 @@ proc genProc(c: PCtx; s: PSym): int = c.prc = oldPrc else: c.prc.maxSlots = s.offset - result = x[0].intVal.int + result = pos From 7e94420847d2d18347410099e97195ddebe8b85f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 17 Apr 2021 02:14:09 -0700 Subject: [PATCH 2435/4254] cString => cSourceString; tyCString => tyCstring so that error msgs show cstring, not cString (#17744) --- compiler/ast.nim | 6 +++--- compiler/ccgcalls.nim | 2 +- compiler/ccgexprs.nim | 14 +++++++------- compiler/ccgreset.nim | 2 +- compiler/ccgtypes.nim | 6 +++--- compiler/concepts.nim | 4 ++-- compiler/evalffi.nim | 8 ++++---- compiler/jsgen.nim | 20 ++++++++++---------- compiler/jstypes.nim | 2 +- compiler/liftdestructors.nim | 2 +- compiler/magicsys.nim | 2 +- compiler/nilcheck.nim | 2 +- compiler/semexprs.nim | 4 ++-- compiler/semfold.nim | 4 ++-- compiler/semmacrosanity.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/semtypes.nim | 6 +++--- compiler/sigmatch.nim | 10 +++++----- compiler/sizealignoffsetimpl.nim | 2 +- compiler/sourcemap.nim | 10 +++++----- compiler/transf.nim | 4 ++-- compiler/typeallowed.nim | 2 +- compiler/types.nim | 6 +++--- compiler/vm.nim | 2 +- compiler/vmdeps.nim | 2 +- compiler/vmgen.nim | 12 ++++++------ compiler/vmmarshal.nim | 4 ++-- lib/core/typeinfo.nim | 8 ++++---- lib/system/assign.nim | 2 +- lib/system/hti.nim | 2 +- lib/system/repr.nim | 2 +- lib/system/reprjs.nim | 2 +- 32 files changed, 79 insertions(+), 79 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index bf0c9669a..02a2ae7a4 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -379,7 +379,7 @@ type tySequence, tyProc, tyPointer, tyOpenArray, - tyString, tyCString, tyForward, + tyString, tyCstring, tyForward, tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers tyFloat, tyFloat32, tyFloat64, tyFloat128, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, @@ -1005,13 +1005,13 @@ const tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyPointer, - tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, + tyOpenArray, tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} # weird name because it contains tyFloat ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple, tySequence} - NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, + NilableTypes*: TTypeKinds = {tyPointer, tyCstring, tyRef, tyPtr, tyProc, tyError} # TODO PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2a93cb5af..616028ac6 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -178,7 +178,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, else: result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest], lengthExpr) - of tyUncheckedArray, tyCString: + of tyUncheckedArray, tyCstring: result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest], lengthExpr) of tyString, tySequence: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 3872ed360..0e54adf49 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -399,7 +399,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) - of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, + of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCstring, tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) @@ -449,7 +449,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) - of tyPointer, tyChar, tyBool, tyEnum, tyCString, + of tyPointer, tyChar, tyBool, tyEnum, tyCstring, tyInt..tyUInt64, tyRange, tyVar, tyLent: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genDeepCopy: " & $ty.kind) @@ -1016,7 +1016,7 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = of tyArray: genArrayElem(p, n, n[0], n[1], d) of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n[0], n[1], d) of tySequence, tyString: genSeqElem(p, n, n[0], n[1], d) - of tyCString: genCStringElem(p, n, n[0], n[1], d) + of tyCstring: genCStringElem(p, n, n[0], n[1], d) of tyTuple: genTupleElem(p, n, d) else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') discard getTypeDesc(p.module, n.typ) @@ -1666,7 +1666,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, e, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage) - of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: + of tyCstring, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", [ rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) @@ -1745,7 +1745,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)") else: unaryExpr(p, e, d, "$1.Field1") - of tyCString: + of tyCstring: if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") of tyString: @@ -2920,7 +2920,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = of tyBool: result = rope"NIM_FALSE" of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result = rope"0" of tyFloat..tyFloat128: result = rope"0.0" - of tyCString, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, + of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil: result = rope"NIM_NIL" of tyString, tySequence: @@ -3187,7 +3187,7 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope of tyObject: result = genConstObjConstr(p, n, isConst) - of tyString, tyCString: + of tyString, tyCstring: if optSeqDestructors in p.config.globalOptions and n.kind != nkNilLit and ty == tyString: result = genStringLiteralV2Const(p.module, n, isConst) else: diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index ef1505f57..fc7370d81 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -85,7 +85,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) of tyChar, tyBool, tyEnum, tyInt..tyUInt64: lineCg(p, cpsStmts, "$1 = 0;$n", [accessor]) - of tyCString, tyPointer, tyPtr, tyVar, tyLent: + of tyCstring, tyPointer, tyPtr, tyVar, tyLent: lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) else: discard diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 9d95e3f67..3d4619764 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -189,7 +189,7 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of tySequence: result = ctNimSeq of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct of tyString: result = ctNimStr - of tyCString: result = ctCString + of tyCstring: result = ctCString of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: @@ -292,7 +292,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = else: discard cgsym(m, "NimStringDesc") result = typeNameOrLiteral(m, typ, "NimStringDesc*") - of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING") + of tyCstring: result = typeNameOrLiteral(m, typ, "NCSTRING") of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL") of tyChar: result = typeNameOrLiteral(m, typ, "NIM_CHAR") of tyNil: result = typeNameOrLiteral(m, typ, "void*") @@ -1452,7 +1452,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = case t.kind of tyEmpty, tyVoid: result = rope"0" - of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: + of tyPointer, tyBool, tyChar, tyCstring, tyString, tyInt..tyUInt64, tyVar, tyLent: genTypeInfoAuxBase(m, t, t, result, rope"0", info) of tyStatic: if t.n != nil: result = genTypeInfoV1(m, lastSon t, info) diff --git a/compiler/concepts.nim b/compiler/concepts.nim index 54579f73f..de994f1b8 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -139,7 +139,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = if result: when logBindings: echo "A adding ", f, " ", ak m.inferred.add((f, ak)) - elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCString, tyString}: + elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCstring, tyString}: when logBindings: echo "B adding ", f, " ", lastSon ak m.inferred.add((f, lastSon ak)) result = true @@ -165,7 +165,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = result = false of tyEnum, tyObject, tyDistinct: result = sameType(f, a) - of tyEmpty, tyString, tyCString, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid: + of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid: result = a.skipTypes(ignorableForArgType).kind == f.kind of tyBool, tyChar, tyInt..tyUInt64: let ak = a.skipTypes(ignorableForArgType) diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 0d471cf98..5004011ed 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -92,7 +92,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = else: result = nil of tyFloat, tyFloat64: result = addr libffi.type_double of tyFloat32: result = addr libffi.type_float - of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped, + of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCstring, tySequence, tyString, tyUntyped, tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil: result = addr libffi.type_pointer of tyDistinct, tyAlias, tySink: @@ -205,7 +205,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) = of tyFloat32: awr(float32, v.floatVal) of tyFloat64: awr(float64, v.floatVal) - of tyPointer, tyProc, tyCString, tyString: + of tyPointer, tyProc, tyCstring, tyString: if v.kind == nkNilLit: # nothing to do since the memory is 0 initialized anyway discard @@ -386,7 +386,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = result = unpackObject(conf, x, typ, n) of tyArray: result = unpackArray(conf, x, typ, n) - of tyCString, tyString: + of tyCstring, tyString: let p = rd(cstring, x) if p.isNil: setNil() @@ -402,7 +402,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode = if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyLent, tyPointer, - tyProc, tyCString, tyString, + tyProc, tyCstring, tyString, tySequence}: result = newNodeIT(x.kind, x.info, destTyp) result.intVal = x.intVal diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ca716b1c0..350563d6b 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -210,7 +210,7 @@ proc mapType(typ: PType): TJSTypeKind = if t.n != nil: result = mapType(lastSon t) else: result = etyNone of tyProc: result = etyProc - of tyCString: result = etyString + of tyCstring: result = etyString of tyConcept, tyIterable: doAssert false proc mapType(p: PProc; typ: PType): TJSTypeKind = @@ -1047,14 +1047,14 @@ proc needsNoCopy(p: PProc; y: PNode): bool = return y.kind in nodeKindsNeedNoCopy or ((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and (skipTypes(y.typ, abstractInst).kind in - {tyRef, tyPtr, tyLent, tyVar, tyCString, tyProc, tyOwned} + IntegralTypes)) + {tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes)) proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = var a, b: TCompRes var xtyp = mapType(p, x.typ) # disable `[]=` for cstring - if x.kind == nkBracketExpr and x.len >= 2 and x[0].typ.skipTypes(abstractInst).kind == tyCString: + if x.kind == nkBracketExpr and x.len >= 2 and x[0].typ.skipTypes(abstractInst).kind == tyCstring: localError(p.config, x.info, "cstring doesn't support `[]=` operator") gen(p, x, a) @@ -1263,14 +1263,14 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = var ty = skipTypes(n[0].typ, abstractVarRange) if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.lastSon, abstractVarRange) case ty.kind - of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs: + of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs: genArrayAddr(p, n, r) of tyTuple: genFieldAddr(p, n, r) else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') r.typ = mapType(n.typ) if r.res == nil: internalError(p.config, n.info, "genArrayAccess") - if ty.kind == tyCString: + if ty.kind == tyCstring: r.res = "$1.charCodeAt($2)" % [r.address, r.res] elif r.typ == etyBaseIndex: if needsTemp(p, n[0]): @@ -1340,7 +1340,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = else: let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind case kindOfIndexedExpr - of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs: + of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs: genArrayAddr(p, n[0], r) of tyTuple: genFieldAddr(p, n[0], r) @@ -1744,7 +1744,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("null", indirect) of tySequence, tyString: result = putToSeq("[]", indirect) - of tyCString, tyProc: + of tyCstring, tyProc: result = putToSeq("null", indirect) of tyStatic: if t.n != nil: @@ -2030,7 +2030,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[1], lhs) gen(p, n[2], rhs) - if skipTypes(n[1].typ, abstractVarRange).kind == tyCString: + if skipTypes(n[1].typ, abstractVarRange).kind == tyCstring: let (b, tmp) = maybeMakeTemp(p, n[2], rhs) r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" % [b, lhs.rdLoc, tmp] @@ -2087,7 +2087,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: var x: TCompRes gen(p, n[1], x) - if skipTypes(n[1].typ, abstractInst).kind == tyCString: + if skipTypes(n[1].typ, abstractInst).kind == tyCstring: let (a, tmp) = maybeMakeTemp(p, n[1], x) r.res = "(($1) == null ? 0 : ($2).length)" % [a, tmp] else: @@ -2096,7 +2096,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mHigh: var x: TCompRes gen(p, n[1], x) - if skipTypes(n[1].typ, abstractInst).kind == tyCString: + if skipTypes(n[1].typ, abstractInst).kind == tyCstring: let (a, tmp) = maybeMakeTemp(p, n[1], x) r.res = "(($1) == null ? -1 : ($2).length - 1)" % [a, tmp] else: diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 2073c252e..81f03dc12 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -128,7 +128,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = case t.kind of tyDistinct: result = genTypeInfo(p, t[0]) - of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64: + of tyPointer, tyProc, tyBool, tyChar, tyCstring, tyString, tyInt..tyUInt64: var s = "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % [result, rope(ord(t.kind))] diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 436665827..ec0435f95 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -825,7 +825,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind of tyNone, tyEmpty, tyVoid: discard - of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, + of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCstring, tyPtr, tyUncheckedArray, tyVar, tyLent: defaultOp(c, t, body, x, y) of tyRef: diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 38d2345c8..ab234a2a8 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -68,7 +68,7 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType = of tyBool: result = sysTypeFromName("bool") of tyChar: result = sysTypeFromName("char") of tyString: result = sysTypeFromName("string") - of tyCString: result = sysTypeFromName("cstring") + of tyCstring: result = sysTypeFromName("cstring") of tyPointer: result = sysTypeFromName("pointer") of tyNil: result = newSysType(g, tyNil, g.config.target.ptrSize) else: internalError(g.config, "request for typekind: " & $kind) diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index b779830d6..f3ec893f7 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -1283,7 +1283,7 @@ proc typeNilability(typ: PType): Nilability = # echo "typeNilability ", $typ.flags, " ", $typ.kind result = if tfNotNil in typ.flags: Safe - elif typ.kind in {tyRef, tyCString, tyPtr, tyPointer}: + elif typ.kind in {tyRef, tyCstring, tyPtr, tyPointer}: # # tyVar ? tyVarargs ? tySink ? tyLent ? # TODO spec? tests? diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 13b53ef32..1582cc0fd 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -375,7 +375,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = n[1] = semExprWithType(c, n[1], {efDetermineType}) var typ = skipTypes(n[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst}) case typ.kind - of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: + of tySequence, tyString, tyCstring, tyOpenArray, tyVarargs: n.typ = getSysType(c.graph, n.info, tyInt) of tyArray: n.typ = typ[0] # indextype @@ -1508,7 +1508,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = arr = arr.base case arr.kind - of tyArray, tyOpenArray, tyVarargs, tySequence, tyString, tyCString, + of tyArray, tyOpenArray, tyVarargs, tySequence, tyString, tyCstring, tyUncheckedArray: if n.len != 2: return nil n[0] = makeDeref(n[0]) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 0d4f6a0bd..04ed73209 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -143,7 +143,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P elif a.kind in {nkStrLit..nkTripleStrLit}: if a.typ.kind == tyString: result = newIntNodeT(toInt128(a.strVal.len), n, idgen, g) - elif a.typ.kind == tyCString: + elif a.typ.kind == tyCstring: result = newIntNodeT(toInt128(nimCStrLen(a.strVal)), n, idgen, g) else: result = newIntNodeT(toInt128(a.len), n, idgen, g) @@ -578,7 +578,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode result = newIntNodeT(firstOrd(g.config, n[1].typ), n, idgen, g) of mHigh: if skipTypes(n[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin - {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: + {tySequence, tyString, tyCstring, tyOpenArray, tyVarargs}: if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64: result = newFloatNodeT(lastFloat(n[1].typ), n, g) else: diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index a8eb62067..aebee8998 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -92,7 +92,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = else: globalError(conf, n.info, "integer literal must have some int type") of nkStrLit..nkTripleStrLit: - if x.kind in {tyString, tyCString}: + if x.kind in {tyString, tyCstring}: n.typ = t else: globalError(conf, n.info, "string literal must be of some string type") diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 52998c214..e66c9596a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -696,7 +696,7 @@ proc paramType(op: PType, i: int): PType = if op != nil and i < op.len: result = op[i] proc cstringCheck(tracked: PEffects; n: PNode) = - if n[0].typ.kind == tyCString and (let a = skipConv(n[1]); + if n[0].typ.kind == tyCstring and (let a = skipConv(n[1]); a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}): message(tracked.config, n.info, warnUnsafeCode, renderTree(n)) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4763f0fd3..f7c42e638 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -95,7 +95,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = of tyTuple: if v.len == 2: strVal = v[1] # second tuple part is the string value - if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}: + if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCstring}: if not isOrdinalType(v[0].typ, allowEnumWithHoles=true): localError(c.config, v[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v[0].typ, preferDesc)) x = toInt64(getOrdValue(v[0])) # first tuple part is the ordinal @@ -104,7 +104,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = localError(c.config, strVal.info, errStringLiteralExpected) else: localError(c.config, v.info, errWrongNumberOfVariables) - of tyString, tyCString: + of tyString, tyCstring: strVal = v x = counter else: @@ -2037,7 +2037,7 @@ proc processMagicType(c: PContext, m: PSym) = if optSeqDestructors in c.config.globalOptions: incl m.typ.flags, tfHasAsgn of mCstring: - setMagicIntegral(c.config, m, tyCString, c.config.target.ptrSize) + setMagicIntegral(c.config, m, tyCstring, c.config.target.ptrSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) of mPointer: setMagicIntegral(c.config, m, tyPointer, c.config.target.ptrSize) of mNil: setMagicType(c.config, m, tyNil, c.config.target.ptrSize) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 767f34dda..2563c38e9 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -260,7 +260,7 @@ proc sumGeneric(t: PType): int = of tyGenericParam, tyUntyped, tyTyped: break of tyAlias, tySink: t = t.lastSon of tyBool, tyChar, tyEnum, tyObject, tyPointer, - tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, + tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64, tyCompositeTypeClass: return isvar else: @@ -1383,7 +1383,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # 'pointer' is NOT compatible to regionized pointers # so 'dealloc(regionPtr)' fails: if a.len == 1: result = isConvertible - of tyCString: result = isConvertible + of tyCstring: result = isConvertible else: discard of tyString: case a.kind @@ -1394,10 +1394,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isEqual of tyNil: result = isNone else: discard - of tyCString: + of tyCstring: # conversion from string to cstring is automatic: case a.kind - of tyCString: + of tyCstring: if tfNotNil in f.flags and tfNotNil notin a.flags: result = isNilConversion else: @@ -2436,7 +2436,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int n[a] = prepareOperand(c, n[a]) if skipTypes(n[a].typ, abstractVar-{tyTypeDesc}).kind==tyString: m.call.add implicitConv(nkHiddenStdConv, - getSysType(c.graph, n[a].info, tyCString), + getSysType(c.graph, n[a].info, tyCstring), copyTree(n[a]), m, c) else: m.call.add copyTree(n[a]) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index b50777c9e..44ba32579 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -242,7 +242,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = else: typ.size = conf.target.ptrSize typ.align = int16(conf.target.ptrSize) - of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent: + of tyCstring, tySequence, tyPtr, tyRef, tyVar, tyLent: let base = typ.lastSon if base == typ: # this is not the correct location to detect ``type A = ptr A`` diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim index 2ec40227b..b87de75f3 100644 --- a/compiler/sourcemap.nim +++ b/compiler/sourcemap.nim @@ -8,13 +8,13 @@ type name*: string children*: seq[Child] - C = enum cSourceNode, cString + C = enum cSourceNode, cSourceString Child* = ref object case kind*: C: of cSourceNode: node*: SourceNode - of cString: + of cSourceString: s*: string SourceMap* = ref object @@ -44,7 +44,7 @@ type proc child*(s: string): Child = - Child(kind: cString, s: s) + Child(kind: cSourceString, s: s) proc child*(node: SourceNode): Child = @@ -72,7 +72,7 @@ proc text*(sourceNode: SourceNode, depth: int): string = let empty = " " result = &"{repeat(empty, depth)}SourceNode({sourceNode.source}:{sourceNode.line}:{sourceNode.column}):\n" for child in sourceNode.children: - if child.kind == cString: + if child.kind == cSourceString: result.add(&"{repeat(empty, depth + 1)}{child.s}\n") else: result.add(child.node.text(depth + 1)) @@ -308,7 +308,7 @@ proc addMapping*(map: SourceMapGenerator, mapping: Mapping) = proc walk*(node: SourceNode, fn: proc(line: string, original: SourceNode)) = for child in node.children: - if child.kind == cString and child.s.len > 0: + if child.kind == cSourceString and child.s.len > 0: fn(child.s, node) else: child.node.walk(fn) diff --git a/compiler/transf.nim b/compiler/transf.nim index 48c737f46..fb59887b0 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -497,14 +497,14 @@ proc transformConv(c: PTransf, n: PNode): PNode = result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen) #echo n.info, " came here and produced ", typeToString(result.typ), # " from ", typeToString(n.typ), " and ", typeToString(n[1].typ) - of tyCString: + of tyCstring: if source.kind == tyString: result = newTransNode(nkStringToCString, n, 1) result[0] = transform(c, n[1]) else: result = transformSons(c, n) of tyString: - if source.kind == tyCString: + if source.kind == tyCstring: result = newTransNode(nkCStringToString, n, 1) result[0] = transform(c, n[1]) else: diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 270e7c028..2f0c039a4 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -116,7 +116,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = t of tyNil: if kind != skConst and kind != skParam: result = t - of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer: + of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCstring, tyPointer: result = nil of tyOrdinal: if kind != skParam: result = t diff --git a/compiler/types.nim b/compiler/types.nim index ce4812506..e56fcffe4 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -503,7 +503,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = typeToString(t[0]) elif prefer in {preferResolved, preferMixed}: case t.kind - of IntegralTypes + {tyFloat..tyFloat128} + {tyString, tyCString}: + of IntegralTypes + {tyFloat..tyFloat128} + {tyString, tyCstring}: result = typeToStr[t.kind] of tyGenericBody: result = typeToString(t.lastSon) @@ -762,7 +762,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = of tyOrdinal: if t.len > 0: result = firstOrd(conf, lastSon(t)) else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') - of tyUncheckedArray, tyCString: + of tyUncheckedArray, tyCstring: result = Zero else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') @@ -1129,7 +1129,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = return true case a.kind - of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, + of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCstring, tyInt..tyUInt64, tyTyped, tyUntyped, tyVoid: result = sameFlags(a, b) of tyStatic, tyFromExpr: diff --git a/compiler/vm.nim b/compiler/vm.nim index e3ba2994f..5c993d77c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -399,7 +399,7 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): dest.node.strVal = $src.floatVal of tyString: dest.node.strVal = src.node.strVal - of tyCString: + of tyCstring: if src.node.kind == nkBracket: # Array of chars var strVal = "" diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 6191f9459..b67e2e48a 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -257,7 +257,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; result.add t.n[1].copyTree of tyPointer: result = atomicType("pointer", mPointer) of tyString: result = atomicType("string", mString) - of tyCString: result = atomicType("cstring", mCstring) + of tyCstring: result = atomicType("cstring", mCstring) of tyInt: result = atomicType("int", mInt) of tyInt8: result = atomicType("int8", mInt8) of tyInt16: result = atomicType("int16", mInt16) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 951d47d2f..c60e81020 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -190,7 +190,7 @@ proc getSlotKind(t: PType): TSlotKind = case t.skipTypes(abstractRange-{tyTypeDesc}).kind of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64: slotTempInt - of tyString, tyCString: + of tyString, tyCstring: slotTempStr of tyFloat..tyFloat128: slotTempFloat @@ -1053,7 +1053,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mLengthStr: case n[1].typ.kind of tyString: genUnaryABI(c, n, dest, opcLenStr) - of tyCString: genUnaryABI(c, n, dest, opcLenCstring) + of tyCstring: genUnaryABI(c, n, dest, opcLenCstring) else: doAssert false, $n[1].typ.kind of mIncl, mExcl: unused(c, n, dest) @@ -1199,7 +1199,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = let tmp = c.genx(n[1]) case n[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind: of tyString: c.gABI(n, opcLenStr, dest, tmp, 1) - of tyCString: c.gABI(n, opcLenCstring, dest, tmp, 1) + of tyCstring: c.gABI(n, opcLenCstring, dest, tmp, 1) else: c.gABI(n, opcLenSeq, dest, tmp, 1) c.freeTemp(tmp) of mEcho: @@ -1530,7 +1530,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = let idx = c.genIndex(le[1], le[0].typ) let tmp = c.genx(ri) if le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in { - tyString, tyCString}: + tyString, tyCstring}: c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp) else: c.preventFalseAlias(le, opcWrArr, dest, idx, tmp) @@ -1775,7 +1775,7 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind - if arrayType in {tyString, tyCString}: + if arrayType in {tyString, tyCstring}: let opc = if gfNodeAddr in flags: opcLdStrIdxAddr else: opcLdStrIdx genArrAccessOpcode(c, n, dest, opc, flags) elif arrayType == tyTypeDesc: @@ -1813,7 +1813,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = result = newNodeIT(nkUIntLit, info, t) of tyFloat..tyFloat128: result = newNodeIT(nkFloatLit, info, t) - of tyCString, tyString: + of tyCstring, tyString: result = newNodeIT(nkStrLit, info, t) result.strVal = "" of tyVar, tyLent, tyPointer, tyPtr, tyUntyped, diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index ffd8e16d7..d48d2408c 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -121,7 +121,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; s.add(", ") storeAny(s, t.lastSon, a, stored, conf) s.add("]") - of tyString, tyCString: + of tyString, tyCstring: if a.kind == nkNilLit: s.add("null") else: s.add(escapeJson(a.strVal)) of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal) @@ -255,7 +255,7 @@ proc loadAny(p: var JsonParser, t: PType, if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of ref-address pair expected") else: raiseParseErr(p, "int for pointer type expected") - of tyString, tyCString: + of tyString, tyCstring: case p.kind of jsonNull: result = newNode(nkNilLit) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 08d567351..d66dc1898 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -322,12 +322,12 @@ proc base*(x: Any): Any = proc isNil*(x: Any): bool = ## `isNil` for an `x` that represents a cstring, proc or ## some pointer type. - assert x.rawType.kind in {tyCString, tyRef, tyPtr, tyPointer, tyProc} + assert x.rawType.kind in {tyCstring, tyRef, tyPtr, tyPointer, tyProc} result = isNil(cast[ppointer](x.value)[]) const pointerLike = - when defined(gcDestructors): {tyCString, tyRef, tyPtr, tyPointer, tyProc} - else: {tyString, tyCString, tyRef, tyPtr, tyPointer, tySequence, tyProc} + when defined(gcDestructors): {tyCstring, tyRef, tyPtr, tyPointer, tyProc} + else: {tyString, tyCstring, tyRef, tyPtr, tyPointer, tySequence, tyProc} proc getPointer*(x: Any): pointer = ## Retrieves the pointer value out of `x`. `x` needs to be of kind @@ -669,7 +669,7 @@ proc setString*(x: Any, y: string) = proc getCString*(x: Any): cstring = ## Retrieves the `cstring` value out of `x`. `x` needs to represent a `cstring`. - assert x.rawType.kind == tyCString + assert x.rawType.kind == tyCstring result = cast[ptr cstring](x.value)[] proc assign*(x, y: Any) = diff --git a/lib/system/assign.nim b/lib/system/assign.nim index faf16fc90..20b854107 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -167,7 +167,7 @@ when false: of tyPointer: k = "range" of tyOpenArray: k = "openarray" of tyString: k = "string" - of tyCString: k = "cstring" + of tyCstring: k = "cstring" of tyInt: k = "int" of tyInt32: k = "int32" else: k = "other" diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 3dbcd7615..9acaae88b 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -40,7 +40,7 @@ type tyPointer, tyOpenArray, tyString, - tyCString, + tyCstring, tyForward, tyInt, tyInt8, diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 7424500eb..020c2281f 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -281,7 +281,7 @@ when not defined(useNimRtl): of tyString: let sp = cast[ptr string](p) reprStrAux(result, sp[].cstring, sp[].len) - of tyCString: + of tyCstring: let cs = cast[ptr cstring](p)[] if cs.isNil: add result, "nil" else: reprStrAux(result, cs, cs.len) diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 36972024a..cdc3403f8 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -200,7 +200,7 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, var fp: int {. emit: "`fp` = `p`;\n" .} add(result, reprStr(cast[string](p))) - of tyCString: + of tyCstring: var fp: cstring {. emit: "`fp` = `p`;\n" .} if fp.isNil: From 5c5f356347b15a82491c7f23e9bf2dd30a0c80f2 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 17 Apr 2021 17:48:22 +0800 Subject: [PATCH 2436/4254] replace defer with try ... finally (#17753) --- lib/core/rlocks.nim | 10 +++++----- tests/stdlib/tuserlocks.nim | 11 +++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index 27a9c5e60..f9224adb8 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -47,9 +47,9 @@ proc release*(lock: var RLock) = template withRLock*(lock: var RLock, code: untyped): untyped = ## Acquires the given lock and then executes the code. - block: - acquire(lock) - defer: - release(lock) - {.locks: [lock].}: + acquire(lock) + {.locks: [lock].}: + try: code + finally: + release(lock) diff --git a/tests/stdlib/tuserlocks.nim b/tests/stdlib/tuserlocks.nim index f6eafa05d..9251fa9e2 100644 --- a/tests/stdlib/tuserlocks.nim +++ b/tests/stdlib/tuserlocks.nim @@ -1,8 +1,8 @@ discard """ - cmd: "nim $target --threads:on $options $file" + matrix: "--threads:on" """ -import rlocks +import std/rlocks var r: RLock r.initRLock() @@ -10,4 +10,11 @@ doAssert r.tryAcquire() doAssert r.tryAcquire() r.release() r.release() + +block: + var x = 12 + withRLock r: + inc x + doAssert x == 13 + r.deinitRLock() From 5c9c1988f6bb92e8cfdc639fc0f83e78cb5efbd2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 17 Apr 2021 02:49:54 -0700 Subject: [PATCH 2437/4254] -d:nimDebug: calls doAssert false instead of quit (#17739) --- compiler/ccgexprs.nim | 4 ++-- compiler/docgen.nim | 2 +- compiler/extccomp.nim | 2 +- compiler/ic/ic.nim | 3 +-- compiler/main.nim | 6 +++--- compiler/msgs.nim | 3 ++- compiler/options.nim | 10 ++++++++-- compiler/sigmatch.nim | 2 +- compiler/syntaxes.nim | 2 +- 9 files changed, 20 insertions(+), 14 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 0e54adf49..a42c30aae 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2387,13 +2387,13 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e[0].sym.name.s)) of mSpawn: when defined(leanCompiler): - quit "compiler built without support for the 'spawn' statement" + p.config.quitOrRaise "compiler built without support for the 'spawn' statement" else: let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.idgen, p.module.module, e, e.typ, nil, nil) expr(p, n, d) of mParallel: when defined(leanCompiler): - quit "compiler built without support for the 'parallel' statement" + p.config.quitOrRaise "compiler built without support for the 'parallel' statement" else: let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e) expr(p, n, d) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 2f7415241..4d9f09ca6 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -498,7 +498,7 @@ proc runAllExamples(d: PDoc) = "docCmd", group.docCmd, ] if os.execShellCmd(cmd) != 0: - quit "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, group[].prettyString, cmd] + d.conf.quitOrRaise "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, group[].prettyString, cmd] else: # keep generated source file `outp` to allow inspection. rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string]) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e0fd5e206..8d1432aa8 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1132,7 +1132,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = except: let e = getCurrentException() - quit "\ncaught exception:\n" & e.msg & "\nstacktrace:\n" & e.getStackTrace() & + conf.quitOrRaise "\ncaught exception:\n" & e.msg & "\nstacktrace:\n" & e.getStackTrace() & "error evaluating JSON file: " & jsonFile.string proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index da0af2edf..6f208a2a4 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -1149,8 +1149,7 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = var m: PackedModule let err = loadRodFile(rodfile, m, config, ignoreConfig=true) if err != ok: - echo "Error: could not load: ", rodfile.string, " reason: ", err - quit 1 + config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err when true: echo "exports:" diff --git a/compiler/main.nim b/compiler/main.nim index 475ba7773..6eb830164 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -229,7 +229,7 @@ proc mainCommand*(graph: ModuleGraph) = template docLikeCmd(body) = when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" + conf.quitOrRaise "compiler wasn't built with documentation generator" else: wantMainModule(conf) loadConfigs(DocConfig, cache, conf, graph.idgen) @@ -278,7 +278,7 @@ proc mainCommand*(graph: ModuleGraph) = conf.setNoteDefaults(warn, true) conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218 when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" + conf.quitOrRaise "compiler wasn't built with documentation generator" else: loadConfigs(DocConfig, cache, conf, graph.idgen) commandRst2Html(cache, conf) @@ -288,7 +288,7 @@ proc mainCommand*(graph: ModuleGraph) = warnFieldXNotSupported, warnRstStyle]: conf.setNoteDefaults(warn, true) when defined(leanCompiler): - quit "compiler wasn't built with documentation generator" + conf.quitOrRaise "compiler wasn't built with documentation generator" else: loadConfigs(DocTexConfig, cache, conf, graph.idgen) commandRst2TeX(cache, conf) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 452b1cd89..c1e1f9e39 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -398,7 +398,8 @@ proc log*(s: string) = close(f) proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} = - if defined(debug) or msg == errInternal or conf.hasHint(hintStackTrace): + if conf.isDefined("nimDebug"): quitOrRaise(conf, $msg) + elif defined(debug) or msg == errInternal or conf.hasHint(hintStackTrace): {.gcsafe.}: if stackTraceAvailable() and isNil(conf.writelnHook): writeStackTrace() diff --git a/compiler/options.nim b/compiler/options.nim index 9ba4d62e4..5475410a4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -576,6 +576,13 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osDragonfly, osMacosx} else: discard +template quitOrRaise*(conf: ConfigRef, msg = "") = + # xxx in future work, consider whether to also intercept `msgQuit` calls + if conf.isDefined("nimDebug"): + doAssert false, msg + else: + quit(msg) # quits with QuitFailure + proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in cmdDocLike + {cmdIdeTools} proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc @@ -732,8 +739,7 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, try: createDir(subdir.string) except OSError: - writeLine(stdout, "cannot create directory: " & subdir.string) - quit(1) + conf.quitOrRaise "cannot create directory: " & subdir.string result = subdir / RelativeFile f.string.splitPath.tail #echo "completeGeneratedFilePath(", f, ") = ", result diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2563c38e9..6a36c1381 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1011,7 +1011,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, when declared(deallocatedRefId): let corrupt = deallocatedRefId(cast[pointer](f)) if corrupt != 0: - quit "it's corrupt " & $corrupt + c.c.config.quitOrRaise "it's corrupt " & $corrupt if f.kind == tyUntyped: if aOrig != nil: put(c, f, aOrig) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index e745e28ba..03a9702a3 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -50,7 +50,7 @@ proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache if i+1 < line.len and line[i] == '#' and line[i+1] == '?': when defined(nimpretty): # XXX this is a bit hacky, but oh well... - quit "can't nimpretty a source code filter" + config.quitOrRaise "can't nimpretty a source code filter: " & $filename else: inc(i, 2) while i < line.len and line[i] in Whitespace: inc(i) From 8e124da75d7b3cafe27c197a027d34f1aca012e3 Mon Sep 17 00:00:00 2001 From: Tanguy Cizain Date: Sat, 17 Apr 2021 15:34:00 +0200 Subject: [PATCH 2438/4254] fix range to unsigned conversion (#17754) --- compiler/sigmatch.nim | 2 +- tests/range/trange.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6a36c1381..b2003c0a8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -409,7 +409,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = elif a.kind == tyRange and # Make sure the conversion happens between types w/ same signedness (f.kind in {tyInt..tyInt64} and a[0].kind in {tyInt..tyInt64} or - f.kind in {tyUInt8..tyUInt32} and a[0].kind in {tyUInt8..tyInt32}) and + f.kind in {tyUInt8..tyUInt32} and a[0].kind in {tyUInt8..tyUInt32}) and a.n[0].intVal >= firstOrd(nil, f) and a.n[1].intVal <= lastOrd(nil, f): # passing 'nil' to firstOrd/lastOrd here as type checking rules should # not depend on the target integer size configurations! diff --git a/tests/range/trange.nim b/tests/range/trange.nim index c864387f6..92ab5ea86 100644 --- a/tests/range/trange.nim +++ b/tests/range/trange.nim @@ -142,3 +142,15 @@ var a: array[4'u, string] for i in 0.. Date: Sat, 17 Apr 2021 16:27:10 +0100 Subject: [PATCH 2439/4254] make cuchar alias uint8 instead of char (#17738) --- changelog.md | 2 ++ lib/system.nim | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index cfdcd3c62..5efde5659 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,8 @@ ## Changes affecting backward compatibility +- `cuchar` now aliases `uint8` instead of `char` + - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. diff --git a/lib/system.nim b/lib/system.nim index 38f6d64d3..b7a4b45cf 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1452,7 +1452,7 @@ type # these work for most platforms: ## This is the same as the type `long double` in *C*. ## This C type is not supported by Nim's code generator. - cuchar* {.importc: "unsigned char", nodecl.} = char + cuchar* {.importc: "unsigned char", nodecl.} = uint8 ## This is the same as the type `unsigned char` in *C*. cushort* {.importc: "unsigned short", nodecl.} = uint16 ## This is the same as the type `unsigned short` in *C*. From 7b6ab5109fe76afefbf5744b5f9f534e86d94629 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 18 Apr 2021 07:27:03 +0200 Subject: [PATCH 2440/4254] IC exposes typedesc implementation shenanigans (#17759) * IC exposes typedesc implementation shenanigans; so I change system.default's definition to what it should have been to begin with * Update lib/system.nim Co-authored-by: Timothee Cour --- lib/system.nim | 2 +- tests/ic/tstdlib_import_changed.nim | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/ic/tstdlib_import_changed.nim diff --git a/lib/system.nim b/lib/system.nim index b7a4b45cf..532883853 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -980,7 +980,7 @@ proc `@`* [IDX, T](a: sink array[IDX, T]): seq[T] {.magic: "ArrToSeq", noSideEff ## echo @a # => @[1, 3, 5] ## echo @b # => @['f', 'o', 'o'] -proc default*(T: typedesc): T {.magic: "Default", noSideEffect.} = +proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} = ## returns the default value of the type `T`. runnableExamples: assert (int, float).default == (0, 0.0) diff --git a/tests/ic/tstdlib_import_changed.nim b/tests/ic/tstdlib_import_changed.nim new file mode 100644 index 000000000..da69a53b5 --- /dev/null +++ b/tests/ic/tstdlib_import_changed.nim @@ -0,0 +1,15 @@ +discard """ + output: '''yes''' +""" + +echo "yes" + +#!EDIT!# + +discard """ + output: '''yes2''' +""" + +import std / [monotimes] +#discard getMonoTime() +echo "yes2" From ca3fe63bab54779e6dc2df3c9a72b9c4280c0eaf Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 18 Apr 2021 21:30:30 +0800 Subject: [PATCH 2441/4254] remove jstin from important packages (#17765) Ref https://github.com/nim-lang/Nim/pull/17759 https://github.com/LemonBoy/jstin/blob/master/src/jstin.nim is already archived and cannot pass CI anymore. --- testament/important_packages.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 620ad3a00..28d7dc367 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -77,7 +77,6 @@ pkg "illwill", "nimble examples" pkg "inim" pkg "itertools", "nim doc src/itertools.nim" pkg "iterutils" -pkg "jstin" pkg "karax", "nim c -r tests/tester.nim" pkg "kdtree", "nimble test", "https://github.com/jblindsay/kdtree" pkg "loopfusion" From 42c6eec4ef7752c4f48ace2899a44840df95da9c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 18 Apr 2021 06:34:29 -0700 Subject: [PATCH 2442/4254] fix #17749 ignore SIGPIPE signals, fix nim CI #17748 (#17752) * fix #17749 SIGPIPE * fix for windows --- changelog.md | 20 ++++++++++++-------- koch.nim | 4 ++++ lib/system/excpt.nim | 16 +++++++++++++--- tests/stdlib/tosproc.nim | 23 +++++++++++++++++++++-- tests/system/tsigexitcode.nim | 11 +++++++---- 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index 5efde5659..8fab425f8 100644 --- a/changelog.md +++ b/changelog.md @@ -39,6 +39,18 @@ - In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, unless `-d:nimLegacyHomeDir` is specified (for a transition period). +- On POSIX systems, the default signal handlers used for Nim programs (it's + used for printing the stacktrace on fatal signals) will now re-raise the + signal for the OS default handlers to handle. + + This lets the OS perform its default actions, which might include core + dumping (on select signals) and notifying the parent process about the cause + of termination. + +- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` + for previous behavior. + + ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` @@ -219,14 +231,6 @@ `ValueError` when the real command line is not available. `parseopt` was previously excluded from `prelude` for JS, as it could not be imported. -- On POSIX systems, the default signal handlers used for Nim programs (it's - used for printing the stacktrace on fatal signals) will now re-raise the - signal for the OS default handlers to handle. - - This lets the OS perform its default actions, which might include core - dumping (on select signals) and notifying the parent process about the cause - of termination. - - Added `system.prepareStrMutation` for better support of low level `moveMem`, `copyMem` operations for Orc's copy-on-write string implementation. diff --git a/koch.nim b/koch.nim index 3e41310d7..49540eb6a 100644 --- a/koch.nim +++ b/koch.nim @@ -542,6 +542,10 @@ proc runCI(cmd: string) = # boot without -d:nimHasLibFFI to make sure this still works kochExecFold("Boot in release mode", "boot -d:release -d:nimStrictMode") + when false: # debugging: when you need to run only 1 test in CI, use something like this: + execFold("debugging test", "nim r tests/stdlib/tosproc.nim") + doAssert false, "debugging only" + ## build nimble early on to enable remainder to depend on it if needed kochExecFold("Build Nimble", "nimble") diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 06fa45097..da034e57e 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -602,6 +602,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and quit 1 when not defined(noSignalHandler) and not defined(useNimRtl): + type Sighandler = proc (a: cint) {.noconv, benign.} + # xxx factor with ansi_c.CSighandlerT, posix.Sighandler + proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv.} = template processSignal(s, action: untyped) {.dirty.} = if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n") @@ -652,7 +655,11 @@ when not defined(noSignalHandler) and not defined(useNimRtl): else: quit(1) + var SIG_IGN {.importc: "SIG_IGN", header: "".}: Sighandler + proc registerSignalHandler() = + # xxx `signal` is deprecated and has many caveats, we should use `sigaction` instead, e.g. + # https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal c_signal(SIGINT, signalHandler) c_signal(SIGSEGV, signalHandler) c_signal(SIGABRT, signalHandler) @@ -661,14 +668,17 @@ when not defined(noSignalHandler) and not defined(useNimRtl): when declared(SIGBUS): c_signal(SIGBUS, signalHandler) when declared(SIGPIPE): - c_signal(SIGPIPE, signalHandler) + when defined(nimLegacySigpipeHandler): + c_signal(SIGPIPE, signalHandler) + else: + c_signal(SIGPIPE, SIG_IGN) registerSignalHandler() # call it in initialization section proc setControlCHook(hook: proc () {.noconv.}) = # ugly cast, but should work on all architectures: - type SignalHandler = proc (sign: cint) {.noconv, benign.} - c_signal(SIGINT, cast[SignalHandler](hook)) + when declared(Sighandler): + c_signal(SIGINT, cast[Sighandler](hook)) when not defined(noSignalHandler) and not defined(useNimRtl): proc unsetControlCHook() = diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index 96cff1468..67731322a 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -206,8 +206,8 @@ else: # main driver var line = newStringOfCap(120) while true: if outp.readLine(line): - result[0].string.add(line.string) - result[0].string.add("\n") + result[0].add(line) + result[0].add("\n") else: result[1] = peekExitCode(p) if result[1] != -1: break @@ -279,3 +279,22 @@ else: # main driver when defined(posix): doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) + + block: # bug #17749 + let output = compileNimProg("-d:case_testfile4", "D20210417T011153") + var p = startProcess(output, dir) + let inp = p.inputStream + var count = 0 + when defined(windows): + # xxx we should make osproc.hsWriteData raise IOError on windows, consistent + # with posix; we could also (in addition) make IOError a subclass of OSError. + type SIGPIPEError = OSError + else: + type SIGPIPEError = IOError + doAssertRaises(SIGPIPEError): + for i in 0..<100000: + count.inc + inp.writeLine "ok" # was giving SIGPIPE and crashing + doAssert count >= 100 + doAssert waitForExit(p) == QuitFailure + close(p) # xxx isn't that missing in other places? diff --git a/tests/system/tsigexitcode.nim b/tests/system/tsigexitcode.nim index 6922cb8eb..249256b40 100644 --- a/tests/system/tsigexitcode.nim +++ b/tests/system/tsigexitcode.nim @@ -11,10 +11,13 @@ proc main() = discard posix.raise(signal) else: # synchronize this list with lib/system/except.nim:registerSignalHandler() - let fatalSigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, - SIGPIPE] - for s in fatalSigs: + let sigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGPIPE] + for s in sigs: let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s]) - doAssert exitCode == 128 + s, "mismatched exit code for signal " & $s + if s == SIGPIPE: + # SIGPIPE should be ignored + doAssert exitCode == 0, $(exitCode, s) + else: + doAssert exitCode == 128+s, $(exitCode, s) main() From c7b77829fe26d9053df2181d96ffc358409674a6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 18 Apr 2021 23:38:07 +0200 Subject: [PATCH 2443/4254] IC: fixes a long standing bug about DCE set computations (#17763) --- compiler/ic/cbackend.nim | 58 +++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index 2f3910b32..c7e5c7266 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -104,14 +104,35 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool let oldAsSet = toPackedSet[int32](oldData) let newAsSet = toPackedSet[int32](s) echo "set of live symbols changed ", asymFile.changeFileExt("rod"), " ", position, " ", f2.err - echo "in old but not in new ", oldAsSet.difference(newAsSet) - echo "in new but not in old ", newAsSet.difference(oldAsSet) - - if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0: - echo "command failed" + echo "in old but not in new ", oldAsSet.difference(newAsSet), " number of entries in old ", oldAsSet.len + echo "in new but not in old ", newAsSet.difference(oldAsSet), " number of entries in new ", newAsSet.len + #if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0: + # echo "command failed" result = true storeAliveSymsImpl(asymFile, s) +proc genPackedModule(g: ModuleGraph, i: int; alive: var AliveSyms) = + # case statement here to enforce exhaustive checks. + case g.packed[i].status + of undefined: + discard "nothing to do" + of loading, stored: + assert false + of storing, outdated: + storeAliveSyms(g.config, g.packed[i].module.position, alive) + generateCodeForModule(g, g.packed[i], alive) + closeRodFile(g, g.packed[i].module) + of loaded: + if g.packed[i].loadedButAliveSetChanged: + generateCodeForModule(g, g.packed[i], alive) + else: + addFileToLink(g.config, g.packed[i].module) + replayTypeInfo(g, g.packed[i], FileIndex(i)) + + if g.backend == nil: + g.backend = cgendata.newModuleList(g) + registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags) + proc generateCode*(g: ModuleGraph) = ## The single entry point, generate C(++) code for the entire ## Nim program aka `ModuleGraph`. @@ -143,24 +164,11 @@ proc generateCode*(g: ModuleGraph) = setupBackendModule(g, g.packed[i]) # Second pass: Code generation. + let mainModuleIdx = g.config.projectMainIdx2.int + # We need to generate the main module last, because only then + # all init procs have been registered: for i in 0..high(g.packed): - # case statement here to enforce exhaustive checks. - case g.packed[i].status - of undefined: - discard "nothing to do" - of loading, stored: - assert false - of storing, outdated: - generateCodeForModule(g, g.packed[i], alive) - closeRodFile(g, g.packed[i].module) - storeAliveSyms(g.config, g.packed[i].module.position, alive) - of loaded: - if g.packed[i].loadedButAliveSetChanged: - generateCodeForModule(g, g.packed[i], alive) - else: - addFileToLink(g.config, g.packed[i].module) - replayTypeInfo(g, g.packed[i], FileIndex(i)) - - if g.backend == nil: - g.backend = cgendata.newModuleList(g) - registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags) + if i != mainModuleIdx: + genPackedModule(g, i, alive) + if mainModuleIdx >= 0: + genPackedModule(g, mainModuleIdx, alive) From 6916faf83c8af609304bde9d2ea2ed62c514cbf1 Mon Sep 17 00:00:00 2001 From: Dankr4d Date: Sun, 18 Apr 2021 23:39:05 +0200 Subject: [PATCH 2444/4254] Fix #17755 (#17766) Signed-off-by: Dankr4d --- lib/wrappers/openssl.nim | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 9c33386c5..1a8893957 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -52,14 +52,23 @@ when sslVersion != "": from posix import SocketHandle elif useWinVersion: - when not defined(nimOldDlls) and defined(cpu64): + when defined(openssl10) or defined(nimOldDlls): + when defined(cpu64): + const + DLLSSLName* = "(ssleay32|ssleay64).dll" + DLLUtilName* = "(libeay32|libeay64).dll" + else: + const + DLLSSLName* = "ssleay32.dll" + DLLUtilName* = "libeay32.dll" + elif defined(cpu64): const DLLSSLName* = "(libssl-1_1-x64|ssleay64|libssl64).dll" DLLUtilName* = "(libcrypto-1_1-x64|libeay64).dll" else: const DLLSSLName* = "(libssl-1_1|ssleay32|libssl32).dll" - DLLUtilName* = "(libcrypto-1_1|libeay32).dll" + DLLUtilName* = "(libcrypto-1_1|libeay32).dll" from winlean import SocketHandle else: From d6c8efa5d444f6849102dca192a199f12c8d55eb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 18 Apr 2021 15:03:24 -0700 Subject: [PATCH 2445/4254] declaredlocs followup: handle `cannot instantiate` errors (#17745) --- compiler/semtypes.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f7c42e638..8be210067 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1463,9 +1463,9 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = matches(c, n, copyTree(n), m) if m.state != csMatch: - let err = "cannot instantiate " & typeToString(t) & "\n" & - "got: <" & describeArgs(c, n) & ">\n" & - "but expected: <" & describeArgs(c, t.n, 0) & ">" + var err = "cannot instantiate " + err.addTypeHeader(c.config, t) + err.add "\ngot: <$1>\nbut expected: <$2>" % [describeArgs(c, n), describeArgs(c, t.n, 0)] localError(c.config, n.info, errGenerated, err) return newOrPrevType(tyError, prev, c) From 0a10af5a2ce27638c8298e96866a779928122269 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 18 Apr 2021 15:15:58 -0700 Subject: [PATCH 2446/4254] privateAccess now works with ref | ptr (#17760) --- compiler/semmagic.nim | 6 +-- compiler/suggest.nim | 4 +- lib/std/importutils.nim | 2 +- testament/lib/stdtest/testutils.nim | 20 +++++++ tests/importalls/mt1.nim | 4 +- tests/stdlib/mimportutils.nim | 17 ++++++ tests/stdlib/timportutils.nim | 82 +++++++++++++++++++++++++++++ tests/stdlib/ttestutils.nim | 29 +++++++--- 8 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 tests/stdlib/mimportutils.nim create mode 100644 tests/stdlib/timportutils.nim diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index d8be85273..c6cf63767 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -578,9 +578,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, n[0].sym.magic = mSubU result = n of mPrivateAccess: - let sym = n[1].typ[0].sym - assert sym != nil - c.currentScope.allowPrivateAccess.add sym + var t = n[1].typ[0] + if t.kind in {tyRef, tyPtr}: t = t[0] + c.currentScope.allowPrivateAccess.add t.sym result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) else: result = n diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 7a2c0d964..f3add0849 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -258,7 +258,9 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = for module in c.friendModules: if fmoduleId == module.id: return true if f.kind == skField: - let symObj = f.owner + var symObj = f.owner + if symObj.typ.kind in {tyRef, tyPtr}: + symObj = symObj.typ[0].sym for scope in allScopes(c.currentScope): for sym in scope.allowPrivateAccess: if symObj.id == sym.id: return true diff --git a/lib/std/importutils.nim b/lib/std/importutils.nim index 4efe0e140..f7a3cbd03 100644 --- a/lib/std/importutils.nim +++ b/lib/std/importutils.nim @@ -17,7 +17,7 @@ when defined(nimImportutilsExample): x1: int # private proc initFoo*(): auto = Foo() -proc privateAccess*(t: typedesc) {.magic: "PrivateAccess".} = +proc privateAccess*(t: typedesc[object|ref|ptr]) {.magic: "PrivateAccess".} = ## Enables access to private fields of `t` in current scope. runnableExamples("-d:nimImportutilsExample"): # here we're importing a module containing: diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 35423de17..44048adbd 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -1,5 +1,6 @@ import std/private/miscdollars from std/os import getEnv +import std/[macros, genasts] template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = ## API to deal with flaky or failing tests. This avoids disabling entire tests @@ -89,3 +90,22 @@ template reject*(a) = template disableVm*(body) = when nimvm: discard else: body + +template typeOrVoid[T](a: T): type = + # FACTOR with asyncjs.typeOrVoid + T + +macro assertAll*(body) = + ## works in VM, unlike `check`, `require` + runnableExamples: + assertAll: + 1+1 == 2 + var a = @[1, 2] # statements work + a.len == 2 + # remove this once these support VM, pending #10129 (closed but not yet fixed) + result = newStmtList() + for a in body: + result.add genAst(a) do: + # better than: `when not compiles(typeof(a)):` + when typeOrVoid(a) is void: a + else: doAssert a diff --git a/tests/importalls/mt1.nim b/tests/importalls/mt1.nim index 87c4eff16..b7983945c 100644 --- a/tests/importalls/mt1.nim +++ b/tests/importalls/mt1.nim @@ -10,8 +10,8 @@ doAssert m.m3p1 == 2 ## field access import std/importutils privateAccess(Foo5) -# var x = Foo5(z1: "foo", z2: m.kg1) -# doAssert x.z1 == "foo" +var x = Foo5(z1: "foo", z2: m.kg1) +doAssert x.z1 == "foo" var f0: Foo5 f0.z3 = 3 diff --git a/tests/stdlib/mimportutils.nim b/tests/stdlib/mimportutils.nim new file mode 100644 index 000000000..d2b185cd3 --- /dev/null +++ b/tests/stdlib/mimportutils.nim @@ -0,0 +1,17 @@ +type + A* = object + a0*: int + ha1: float + B = object + b0*: int + hb1: float + C* = ref object + c0: int + hc1: float + D* = ptr object + d0: int + hd1: float + PA* = ref A + PtA* = ptr A + +proc initB*(): B = B() diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim new file mode 100644 index 000000000..37e2b7102 --- /dev/null +++ b/tests/stdlib/timportutils.nim @@ -0,0 +1,82 @@ +import std/importutils +import stdtest/testutils +import mimportutils + +template main = + block: # privateAccess + assertAll: + var a: A + var b = initB() # B is private + compiles(a.a0) + compiles(b.b0) + not compiles(a.ha1) + not compiles(b.hb1) + + block: + assertAll: + privateAccess A + compiles(a.ha1) + a.ha1 == 0.0 + not compiles(a.hb1) + privateAccess b.typeof + b.hb1 = 3 + type B2 = b.typeof + let b2 = B2(b0: 4, hb1: 5) + b.hb1 == 3 + b2 == B2(b0: 4, hb1: 5) + + assertAll: + not compiles(a.ha1) + not compiles(b.hb1) + + block: + assertAll: + not compiles(C(c0: 1, hc1: 2)) + privateAccess C + let c = C(c0: 1, hc1: 2) + c.hc1 == 2 + + block: + assertAll: + privateAccess PA + var pa = PA(a0: 1, ha1: 2) + pa.ha1 == 2 + pa.ha1 = 3 + pa.ha1 == 3 + + block: + assertAll: + var a = A(a0: 1) + var a2 = a.addr + not compiles(a2.ha1) + privateAccess PtA + a2.type is PtA + a2.ha1 = 2 + a2.ha1 == 2 + a.ha1 = 3 + a2.ha1 == 3 + + block: + disableVm: + assertAll: + var a = A.create() + defer: dealloc(a) + a is PtA + a.typeof is PtA + not compiles(a.ha1) + privateAccess a.typeof + a.ha1 = 2 + a.ha1 == 2 + a[].ha1 = 3 + a.ha1 == 3 + + block: + disableVm: + assertAll: + var a = A.create() + defer: dealloc(a) + privateAccess PtA + a.ha1 == 0 + +static: main() +main() diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim index 7e39c9ae3..0d789cd76 100644 --- a/tests/stdlib/ttestutils.nim +++ b/tests/stdlib/ttestutils.nim @@ -1,11 +1,24 @@ import stdtest/testutils -block: # greedyOrderedSubsetLines - doAssert greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") - doAssert not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order - doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs +block: # assertAll + assertAll: + 1+1 == 2 + var a = 3 + a == 3 - doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") - doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") - doAssert not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5") - doAssert not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix") + doAssertRaises(AssertionDefect): + assertAll: + 1+1 == 2 + var a = 3 + a == 4 + +block: # greedyOrderedSubsetLines + assertAll: + greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") + not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order + not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs + + not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") + not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") + not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5") + not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix") From 5042cb956be1cfc1dfb106d3dbc9d897e10f72d8 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Sun, 18 Apr 2021 22:40:08 -0700 Subject: [PATCH 2447/4254] [ci skip] document compiler/ic/rodfiles.nim (#17771) * [ci skip] document compiler/ic/rodfiles.nim Why? * understand how rodfile module works and a bit of the format * leave notes behind for others * rather than Araq guess what others need, he can fix what other glean * possible model for making the compiler more aproachable Bonus: * might have found a minor bug in `loadSection` * Update compiler/ic/rodfiles.nim Co-authored-by: Andreas Rumpf --- compiler/ic/rodfiles.nim | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 47362da0b..86d8ba203 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -7,8 +7,65 @@ # distribution, for details about the copyright. # +## Low level binary format used by the compiler to store and load various AST +## and related data. +## +## NB: this is incredibly low level and if you're interested in how the +## compiler works and less a storage format, you're probably looking for +## the `ic` or `packed_ast` modules to understand the logical format. + from typetraits import supportsCopyMem +## Overview +## ======== +## `RodFile` represents a Rod File (versioned binary format), and the +## associated data for common interactions such as IO and error tracking +## (`RodFileError`). The file format broken up into sections (`RodSection`) +## and preceeded by a header (see: `cookie`). The precise layout, section +## ordering and data following the section are determined by the user. See +## `ic.loadRoadFile`. +## +## A basic but "wrong" example of the lifecycle: +## --------------------------------------------- +## 1. `create` or `open` - create a new one or open an existing +## 2. `storeHeader` - header info +## 3. `storePrim` or `storeSeq` - save your stuff +## 4. `close` - and we're done +## +## Now read the bits below to understand what's missing. +## +## Issues with the Example +## ``````````````````````` +## Missing Sections: +## This is a low level API, so headers and sections need to be stored and +## loaded by the user, see `storeHeader` & `loadHeader` and `storeSection` & +## `loadSection`, respectively. +## +## No Error Handling: +## The API is centered around IO and prone to error, each operation checks or +## sets the `RodFile.err` field. A user of this API needs to handle these +## appropriately. +## +## API Notes +## ========= +## +## Valid inputs for Rod files +## -------------------------- +## ASTs, hopes, dreams, and anything as long as it and any children it may have +## support `copyMem`. This means anything that is not a pointer and that does not contain a pointer. At a glance these are: +## * string +## * objects & tuples (fields are recursed) +## * sequences AKA `seq[T]` +## +## Note on error handling style +## ---------------------------- +## A flag based approach is used where operations no-op in case of a +## preexisting error and set the flag if they encounter one. +## +## Misc +## ---- +## * 'Prim' is short for 'primitive', as in a non-sequence type + type RodSection* = enum versionSection @@ -60,6 +117,8 @@ proc setError(f: var RodFile; err: RodFileError) {.inline.} = #raise newException(IOError, "IO error") proc storePrim*(f: var RodFile; s: string) = + ## Stores a string. + ## The len is prefixed to allow for later retreival. if f.err != ok: return if s.len >= high(int32): setError f, tooBig @@ -73,6 +132,9 @@ proc storePrim*(f: var RodFile; s: string) = setError f, ioFailure proc storePrim*[T](f: var RodFile; x: T) = + ## Stores a non-sequence/string `T`. + ## If `T` doesn't support `copyMem` and is an object or tuple then the fields + ## are written -- the user from context will need to know which `T` to load. if f.err != ok: return when supportsCopyMem(T): if writeBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): @@ -90,6 +152,7 @@ proc storePrim*[T](f: var RodFile; x: T) = {.error: "unsupported type for 'storePrim'".} proc storeSeq*[T](f: var RodFile; s: seq[T]) = + ## Stores a sequence of `T`s, with the len as a prefix for later retrieval. if f.err != ok: return if s.len >= high(int32): setError f, tooBig @@ -102,6 +165,7 @@ proc storeSeq*[T](f: var RodFile; s: seq[T]) = storePrim(f, s[i]) proc loadPrim*(f: var RodFile; s: var string) = + ## Read a string, the length was stored as a prefix if f.err != ok: return var lenPrefix = int32(0) if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): @@ -113,6 +177,7 @@ proc loadPrim*(f: var RodFile; s: var string) = setError f, ioFailure proc loadPrim*[T](f: var RodFile; x: var T) = + ## Load a non-sequence/string `T`. if f.err != ok: return when supportsCopyMem(T): if readBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x): @@ -130,6 +195,7 @@ proc loadPrim*[T](f: var RodFile; x: var T) = {.error: "unsupported type for 'loadPrim'".} proc loadSeq*[T](f: var RodFile; s: var seq[T]) = + ## `T` must be compatible with `copyMem`, see `loadPrim` if f.err != ok: return var lenPrefix = int32(0) if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix): @@ -140,11 +206,13 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) = loadPrim(f, s[i]) proc storeHeader*(f: var RodFile) = + ## stores the header which is described by `cookie`. if f.err != ok: return if f.f.writeBytes(cookie, 0, cookie.len) != cookie.len: setError f, ioFailure proc loadHeader*(f: var RodFile) = + ## Loads the header which is described by `cookie`. if f.err != ok: return var thisCookie: array[cookie.len, byte] if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len: @@ -153,12 +221,14 @@ proc loadHeader*(f: var RodFile) = setError f, wrongHeader proc storeSection*(f: var RodFile; s: RodSection) = + ## update `currentSection` and writes the bytes value of s. if f.err != ok: return assert f.currentSection < s f.currentSection = s storePrim(f, s) proc loadSection*(f: var RodFile; expected: RodSection) = + ## read the bytes value of s, sets and error if the section is incorrect. if f.err != ok: return var s: RodSection loadPrim(f, s) @@ -166,11 +236,13 @@ proc loadSection*(f: var RodFile; expected: RodSection) = setError f, wrongSection proc create*(filename: string): RodFile = + ## create the file and open it for writing if not open(result.f, filename, fmWrite): setError result, cannotOpen proc close*(f: var RodFile) = close(f.f) proc open*(filename: string): RodFile = + ## open the file for reading if not open(result.f, filename, fmRead): setError result, cannotOpen From 172a5ab7f82df503c1123a3bfa2f702416733858 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 19 Apr 2021 13:41:50 +0800 Subject: [PATCH 2448/4254] [std/rlocks]add inline pragma (#17773) so that it can be used as the base of new locks module with destructors. --- lib/core/rlocks.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index f9224adb8..5f155262a 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -33,15 +33,15 @@ proc deinitRLock*(lock: var RLock) {.inline.} = ## Frees the resources associated with the lock. deinitSys(lock) -proc tryAcquire*(lock: var RLock): bool = +proc tryAcquire*(lock: var RLock): bool {.inline.} = ## Tries to acquire the given lock. Returns `true` on success. result = tryAcquireSys(lock) -proc acquire*(lock: var RLock) = +proc acquire*(lock: var RLock) {.inline.} = ## Acquires the given lock. acquireSys(lock) -proc release*(lock: var RLock) = +proc release*(lock: var RLock) {.inline.} = ## Releases the given lock. releaseSys(lock) From f8038af5ecfa20deaa0b9b1e0d8a5f5915dd9780 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 19 Apr 2021 02:42:38 -0300 Subject: [PATCH 2449/4254] Documentation only, dom (#17770) * ReSync with Devel * ReSync * https://github.com/timotheecour/Nim/issues/674 * Update lib/js/dom.nim Co-authored-by: flywind Co-authored-by: Andreas Rumpf Co-authored-by: flywind --- lib/js/dom.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index a133f1f69..303cc178f 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1496,7 +1496,9 @@ proc find*(w: Window, text: cstring, caseSensitive = false, backwards = false) proc focus*(w: Window) proc forward*(w: Window) -proc getComputedStyle*(w: Window, e: Node, pe:Node = nil): Style +proc getComputedStyle*(w: Window, e: Node, pe: Node = nil): Style + ## .. warning:: The returned Style may or may not be read-only at run-time in the browser. getComputedStyle is performance costly. + proc handleEvent*(w: Window, e: Event) proc home*(w: Window) proc moveBy*(w: Window, x, y: int) From cedbc7035d171d1535365c8acb889911b839ce99 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 19 Apr 2021 16:33:56 +0800 Subject: [PATCH 2450/4254] [std/locks]remove workaround for withLock (#17772) Ref #6113 and #6049 The workaround for generics instantiation is unnecessary. It seems to be fixed by another PR I guess. The test still works. So the changes should be harmless. https://github.com/nim-lang/Nim/blob/devel/tests/stdlib/tlocks.nim I also add some inline pragmas. --- lib/core/locks.nim | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 1540e2bcd..674817674 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -42,16 +42,16 @@ proc deinitLock*(lock: var Lock) {.inline.} = ## Frees the resources associated with the lock. deinitSys(lock) -proc tryAcquire*(lock: var Lock): bool = +proc tryAcquire*(lock: var Lock): bool {.inline.} = ## Tries to acquire the given lock. Returns `true` on success. result = tryAcquireSys(lock) -proc acquire*(lock: var Lock) = +proc acquire*(lock: var Lock) {.inline.} = ## Acquires the given lock. when not defined(js): acquireSys(lock) -proc release*(lock: var Lock) = +proc release*(lock: var Lock) {.inline.} = ## Releases the given lock. when not defined(js): releaseSys(lock) @@ -76,7 +76,6 @@ proc signal*(cond: var Cond) {.inline.} = template withLock*(a: Lock, body: untyped) = ## Acquires the given lock, executes the statements in body and ## releases the lock after the statements finish executing. - mixin acquire, release acquire(a) {.locks: [a].}: try: From dc89b212572fecd449dd469ffb2424c78941c12f Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 19 Apr 2021 16:51:13 +0800 Subject: [PATCH 2451/4254] [std/locks]close #7998(complete condition variables) (#17711) * close #7998 * workaround genode * Update lib/system/syslocks.nim --- lib/core/locks.nim | 9 +++-- lib/genode_cpp/syslocks.h | 5 +++ lib/system/syslocks.nim | 55 ++++++++++++++++++------------- lib/system/sysspawn.nim | 33 ++++++++----------- lib/system/threadlocalstorage.nim | 3 ++ 5 files changed, 60 insertions(+), 45 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 674817674..92967b9db 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -66,13 +66,18 @@ proc deinitCond*(cond: var Cond) {.inline.} = deinitSysCond(cond) proc wait*(cond: var Cond, lock: var Lock) {.inline.} = - ## waits on the condition variable `cond`. + ## Waits on the condition variable `cond`. waitSysCond(cond, lock) proc signal*(cond: var Cond) {.inline.} = - ## sends a signal to the condition variable `cond`. + ## Sends a signal to the condition variable `cond`. signalSysCond(cond) +proc broadcast*(cond: var Cond) {.inline.} = + ## Unblocks all threads currently blocked on the + ## specified condition variable `cond`. + broadcastSysCond(cond) + template withLock*(a: Lock, body: untyped) = ## Acquires the given lock, executes the statements in body and ## releases the lock after the statements finish executing. diff --git a/lib/genode_cpp/syslocks.h b/lib/genode_cpp/syslocks.h index c50180903..b5d5ae694 100644 --- a/lib/genode_cpp/syslocks.h +++ b/lib/genode_cpp/syslocks.h @@ -71,6 +71,11 @@ struct Nim::SysCond { _semaphore.up(); } + + void broadcastSysCond() + { + _semaphore.up(); + } }; #endif diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index 51dbfd3a2..ac52d9a8c 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -24,7 +24,9 @@ when defined(windows): LockSemaphore: int SpinCount: int - SysCond = Handle + RTL_CONDITION_VARIABLE {.importc: "RTL_CONDITION_VARIABLE", header: "synchapi.h".} = object + thePtr {.importc: "ptr".} : Handle + SysCond = RTL_CONDITION_VARIABLE proc initSysLock(L: var SysLock) {.importc: "InitializeCriticalSection", header: "".} @@ -48,30 +50,29 @@ when defined(windows): proc deinitSys(L: var SysLock) {.importc: "DeleteCriticalSection", header: "".} - proc createEvent(lpEventAttributes: pointer, - bManualReset, bInitialState: int32, - lpName: cstring): SysCond {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "CreateEventA".} + proc initializeConditionVariable( + conditionVariable: var SysCond + ) {.stdcall, noSideEffect, dynlib: "kernel32", importc: "InitializeConditionVariable".} - proc closeHandle(hObject: Handle) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "CloseHandle".} - proc waitForSingleObject(hHandle: Handle, dwMilliseconds: int32): int32 {. - stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.} + proc sleepConditionVariableCS( + conditionVariable: var SysCond, + PCRITICAL_SECTION: var SysLock, + dwMilliseconds: int + ): int32 {.stdcall, noSideEffect, dynlib: "kernel32", importc: "SleepConditionVariableCS".} - proc signalSysCond(hEvent: SysCond) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "SetEvent".} + + proc signalSysCond(hEvent: var SysCond) {.stdcall, noSideEffect, + dynlib: "kernel32", importc: "WakeConditionVariable".} + + proc broadcastSysCond(hEvent: var SysCond) {.stdcall, noSideEffect, + dynlib: "kernel32", importc: "WakeAllConditionVariable".} proc initSysCond(cond: var SysCond) {.inline.} = - cond = createEvent(nil, 0'i32, 0'i32, nil) + initializeConditionVariable(cond) proc deinitSysCond(cond: var SysCond) {.inline.} = - closeHandle(cond) + discard proc waitSysCond(cond: var SysCond, lock: var SysLock) = - releaseSys(lock) - discard waitForSingleObject(cond, -1'i32) - acquireSys(lock) - - proc waitSysCondWindows(cond: var SysCond) = - discard waitForSingleObject(cond, -1'i32) + discard sleepConditionVariableCS(cond, lock, -1'i32) elif defined(genode): const @@ -94,6 +95,8 @@ elif defined(genode): noSideEffect, importcpp.} proc signalSysCond(cond: var SysCond) {. noSideEffect, importcpp.} + proc broadcastSysCond(cond: var SysCond) {. + noSideEffect, importcpp.} else: type @@ -181,7 +184,7 @@ else: releaseSysAux(L) when insideRLocksModule: - let SysLockType_Reentrant{.importc: "PTHREAD_MUTEX_RECURSIVE", + let SysLockType_Reentrant {.importc: "PTHREAD_MUTEX_RECURSIVE", header: "".}: SysLockType proc initSysLockAttr(a: var SysLockAttr) {. importc: "pthread_mutexattr_init", header: "", noSideEffect.} @@ -194,10 +197,12 @@ else: proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect, importc: "pthread_cond_destroy", header: "".} - proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj) {. + proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj): cint {. importc: "pthread_cond_wait", header: "", noSideEffect.} proc signalSysCondAux(cond: var SysCondObj) {. importc: "pthread_cond_signal", header: "", noSideEffect.} + proc broadcastSysCondAux(cond: var SysCondObj) {. + importc: "pthread_cond_broadcast", header: "", noSideEffect.} when defined(ios): proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = @@ -209,9 +214,11 @@ else: c_free(cond) template waitSysCond(cond: var SysCond, lock: var SysLock) = - waitSysCondAux(cond[], lock[]) + discard waitSysCondAux(cond[], lock[]) template signalSysCond(cond: var SysCond) = signalSysCondAux(cond[]) + template broadcastSysCond(cond: var SysCond) = + broadcastSysCondAux(cond[]) else: template initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = initSysCondAux(cond, cond_attr) @@ -219,8 +226,10 @@ else: deinitSysCondAux(cond) template waitSysCond(cond: var SysCond, lock: var SysLock) = - waitSysCondAux(cond, lock) + discard waitSysCondAux(cond, lock) template signalSysCond(cond: var SysCond) = signalSysCondAux(cond) + template broadcastSysCond(cond: var SysCond) = + broadcastSysCondAux(cond) {.pop.} diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim index d1f5803f4..c9b9a68f0 100644 --- a/lib/system/sysspawn.nim +++ b/lib/system/sysspawn.nim @@ -20,34 +20,28 @@ when not declared(NimString): type CondVar = object c: SysCond - when defined(posix): - stupidLock: SysLock - counter: int + stupidLock: SysLock + counter: int proc createCondVar(): CondVar = initSysCond(result.c) - when defined(posix): - initSysLock(result.stupidLock) - #acquireSys(result.stupidLock) + initSysLock(result.stupidLock) + #acquireSys(result.stupidLock) proc destroyCondVar(c: var CondVar) {.inline.} = deinitSysCond(c.c) proc await(cv: var CondVar) = - when defined(posix): - acquireSys(cv.stupidLock) - while cv.counter <= 0: - waitSysCond(cv.c, cv.stupidLock) - dec cv.counter - releaseSys(cv.stupidLock) - else: - waitSysCondWindows(cv.c) + acquireSys(cv.stupidLock) + while cv.counter <= 0: + waitSysCond(cv.c, cv.stupidLock) + dec cv.counter + releaseSys(cv.stupidLock) proc signal(cv: var CondVar) = - when defined(posix): - acquireSys(cv.stupidLock) - inc cv.counter - releaseSys(cv.stupidLock) + acquireSys(cv.stupidLock) + inc cv.counter + releaseSys(cv.stupidLock) signalSysCond(cv.c) type @@ -57,8 +51,7 @@ type proc createFastCondVar(): FastCondVar = initSysCond(result.slow.c) - when defined(posix): - initSysLock(result.slow.stupidLock) + initSysLock(result.slow.stupidLock) #acquireSys(result.slow.stupidLock) result.event = false result.slowPath = false diff --git a/lib/system/threadlocalstorage.nim b/lib/system/threadlocalstorage.nim index cbb74c7df..30962ef77 100644 --- a/lib/system/threadlocalstorage.nim +++ b/lib/system/threadlocalstorage.nim @@ -17,6 +17,9 @@ when defined(windows): proc winResumeThread(hThread: SysThread): int32 {. stdcall, dynlib: "kernel32", importc: "ResumeThread".} + proc waitForSingleObject(hHandle: SysThread, dwMilliseconds: int32): int32 {. + stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".} + proc waitForMultipleObjects(nCount: int32, lpHandles: ptr SysThread, bWaitAll: int32, From 83fa0fc843a5757c6fa1af9ac89b85b71c0c7581 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 19 Apr 2021 17:21:35 +0800 Subject: [PATCH 2452/4254] fix #12521(type alias for openArray) (#17593) * fix nim js cmp fails at CT * fix #12521 * address comments --- compiler/ccgtypes.nim | 2 +- tests/openarray/topenarray.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 3d4619764..fa58b5651 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -453,7 +453,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, params.add(~"NIM_NOALIAS ") params.add(param.loc.r) # declare the len field for open arrays: - var arr = param.typ + var arr = param.typ.skipTypes({tyGenericInst}) if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon var j = 0 while arr.kind in {tyOpenArray, tyVarargs}: diff --git a/tests/openarray/topenarray.nim b/tests/openarray/topenarray.nim index 0b6e3afc4..aec5a4cbf 100644 --- a/tests/openarray/topenarray.nim +++ b/tests/openarray/topenarray.nim @@ -23,5 +23,31 @@ proc main = when defined(js): discard # xxx bug #15952: `a` left unchanged else: doAssert a == [1, 0, 10, 20, 5] + block: # bug #12521 + block: + type slice[T] = openArray[T] + + # Proc using that alias + proc testing(sl: slice[int]): seq[int] = + for item in sl: + result.add item + + let mySeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + doAssert testing(mySeq) == mySeq + doAssert testing(mySeq[2..^2]) == mySeq[2..^2] + + block: + type slice = openArray[int] + + # Proc using that alias + proc testing(sl: slice): seq[int] = + for item in sl: + result.add item + + let mySeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + doAssert testing(mySeq) == mySeq + doAssert testing(mySeq[2..^2]) == mySeq[2..^2] + + main() # static: main() # xxx bug #15952: Error: cannot generate code for: mSlice From 4b0b536419a500dc2e5a987ed9c2a374e0848008 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 19 Apr 2021 11:48:06 +0200 Subject: [PATCH 2453/4254] ic refactoring (#17778) * minor IC documentation update * IC: refactoring: removed the 'shared' type and fields, these were a leftover from an earlier design --- compiler/ic/dce.nim | 18 ++-- compiler/ic/design.rst | 8 +- compiler/ic/ic.nim | 175 +++++++++++++++++++++++-------------- compiler/ic/integrity.nim | 26 +++--- compiler/ic/navigator.nim | 12 +-- compiler/ic/packed_ast.nim | 56 ------------ compiler/ic/rodfiles.nim | 10 +-- 7 files changed, 146 insertions(+), 159 deletions(-) diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index 0918fc379..48ed414e2 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -27,7 +27,7 @@ type proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool = ## "Exported to C" procs are special (these are marked with '.exportc') because these ## must not be optimized away! - let symPtr = addr g[c.thisModule].fromDisk.sh.syms[symId] + let symPtr = unsafeAddr g[c.thisModule].fromDisk.syms[symId] let flags = symPtr.flags # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly; issue (#411). However, the whole purpose here @@ -39,7 +39,7 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo # XXX: This used to be a condition to: # (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or if sfCompilerProc in flags: - c.compilerProcs[g[c.thisModule].fromDisk.sh.strings[symPtr.name]] = (c.thisModule, symId) + c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId) template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty @@ -47,17 +47,17 @@ proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: i ## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will ## be analysed. if not c.alive[module].containsOrIncl(item): - var body = g[module].fromDisk.sh.syms[item].ast + var body = g[module].fromDisk.syms[item].ast if body != emptyNodeId: - let opt = g[module].fromDisk.sh.syms[item].options - if g[module].fromDisk.sh.syms[item].kind in routineKinds: + let opt = g[module].fromDisk.syms[item].options + if g[module].fromDisk.syms[item].kind in routineKinds: body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos) c.stack.add((module, opt, NodePos(body))) when false: - let nid = g[module].fromDisk.sh.syms[item].name + let nid = g[module].fromDisk.syms[item].name if nid != LitId(0): - let name = g[module].fromDisk.sh.strings[nid] + let name = g[module].fromDisk.strings[nid] if name in ["nimFrame", "callDepthLimitReached"]: echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item @@ -66,12 +66,12 @@ proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string followLater(c, g, module, item) proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind = - template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.sh.types[t.item].kind + template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.types[t.item].kind var t2 = translateId(t, g, c.thisModule, c.decoder.config) result = t2.kind while result in toSkip: - t2 = translateId(g[t2.module].fromDisk.sh.types[t2.item].types[^1], g, t2.module, c.decoder.config) + t2 = translateId(g[t2.module].fromDisk.types[t2.item].types[^1], g, t2.module, c.decoder.config) result = t2.kind proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) = diff --git a/compiler/ic/design.rst b/compiler/ic/design.rst index d8e1315b1..b096e3103 100644 --- a/compiler/ic/design.rst +++ b/compiler/ic/design.rst @@ -7,12 +7,8 @@ The frontend produces a set of `.rod` files. Every `.nim` module produces its own `.rod` file. - The IR must be a faithful representation of the AST in memory. -- The backend can do its own caching but doesn't have to. -- We know by comparing 'nim check compiler/nim' against 'nim c compiler/nim' - that 2/3 of the compiler's runtime is spent in the frontend. Hence we - implement IC for the frontend first and only later for the backend. The - backend will recompile everything until we implement its own caching - mechanisms. +- The backend can do its own caching but doesn't have to. In the + current implementation the backend also caches its results. Advantage of the "set of files" vs the previous global database: - By construction, we either read from the `.rod` file or from the diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 6f208a2a4..a23685be7 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -51,7 +51,12 @@ type emittedTypeInfo*: seq[string] backendFlags*: set[ModuleBackendFlag] - sh*: Shared + syms*: seq[PackedSym] + types*: seq[PackedType] + strings*: BiTable[string] # we could share these between modules. + numbers*: BiTable[BiggestInt] # we also store floats in here so + # that we can assure that every bit is kept + cfg: PackedConfig PackedEncoder* = object @@ -66,6 +71,50 @@ type symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId config*: ConfigRef +proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int; + result: var string) = + let pos = n.int + if result.len > 0 and result[^1] notin {' ', '\n'}: + result.add ' ' + + result.add $tree[pos].kind + case tree.nodes[pos].kind + of nkNone, nkEmpty, nkNilLit, nkType: discard + of nkIdent, nkStrLit..nkTripleStrLit: + result.add " " + result.add m.strings[LitId tree.nodes[pos].operand] + of nkSym: + result.add " " + result.add m.strings[m.syms[tree.nodes[pos].operand].name] + of directIntLit: + result.add " " + result.addInt tree.nodes[pos].operand + of externSIntLit: + result.add " " + result.addInt m.numbers[LitId tree.nodes[pos].operand] + of externUIntLit: + result.add " " + result.add $cast[uint64](m.numbers[LitId tree.nodes[pos].operand]) + of nkFloatLit..nkFloat128Lit: + result.add " " + result.add $cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand]) + else: + result.add "(\n" + for i in 1..(nesting+1)*2: result.add ' ' + for child in sonsReadonly(tree, n): + toString(tree, child, m, nesting + 1, result) + result.add "\n" + for i in 1..nesting*2: result.add ' ' + result.add ")" + #for i in 1..nesting*2: result.add ' ' + +proc toString*(tree: PackedTree; n: NodePos; m: PackedModule): string = + result = "" + toString(tree, n, m, 0, result) + +proc debug*(tree: PackedTree; m: PackedModule) = + stdout.write toString(tree, NodePos 0, m) + proc isActive*(e: PackedEncoder): bool = e.config != nil proc disable(e: var PackedEncoder) = e.config = nil @@ -134,14 +183,14 @@ proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModule): LitId = result = c.filenames.getOrDefault(x) if result == LitId(0): let p = msgs.toFullPath(c.config, x) - result = getOrIncl(m.sh.strings, p) + result = getOrIncl(m.strings, p) c.filenames[x] = result c.lastFile = x c.lastLit = result assert result != LitId(0) proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex = - result = msgs.fileInfoIdx(config, AbsoluteFile m.sh.strings[x]) + result = msgs.fileInfoIdx(config, AbsoluteFile m.strings[x]) proc includesIdentical(m: var PackedModule; config: ConfigRef): bool = for it in mitems(m.includes): @@ -151,7 +200,6 @@ proc includesIdentical(m: var PackedModule; config: ConfigRef): bool = proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) = ## setup a context for serializing to packed ast - m.sh = Shared() c.thisModule = moduleSym.itemId.module c.config = config m.moduleFlags = moduleSym.flags @@ -179,11 +227,11 @@ proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) m.imports.add toLitId(f, c, m) proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.sh.strings, s.name.s) + let nameId = getOrIncl(m.strings, s.name.s) m.hidden.add((nameId, s.itemId.item)) proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.sh.strings, s.name.s) + let nameId = getOrIncl(m.strings, s.name.s) m.exports.add((nameId, s.itemId.item)) proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) = @@ -201,12 +249,12 @@ proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) = m.methods.add s.itemId.item proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.sh.strings, s.name.s) + let nameId = getOrIncl(m.strings, s.name.s) m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item))) proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) = - let nameId = getOrIncl(m.sh.strings, s.name.s) + let nameId = getOrIncl(m.strings, s.name.s) m.compilerProcs.add((nameId, s.itemId.item)) proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) @@ -225,11 +273,11 @@ proc flush(c: var PackedEncoder; m: var PackedModule) = proc toLitId(x: string; m: var PackedModule): LitId = ## store a string as a literal - result = getOrIncl(m.sh.strings, x) + result = getOrIncl(m.strings, x) proc toLitId(x: BiggestInt; m: var PackedModule): LitId = ## store an integer as a literal - result = getOrIncl(m.sh.numbers, x) + result = getOrIncl(m.numbers, x) proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo = PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m)) @@ -299,8 +347,8 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item): - if t.uniqueId.item >= m.sh.types.len: - setLen m.sh.types, t.uniqueId.item+1 + if t.uniqueId.item >= m.types.len: + setLen m.types, t.uniqueId.item+1 var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv, size: t.size, align: t.align, nonUniqueId: t.itemId.item, @@ -315,7 +363,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI p.owner = t.owner.safeItemId(c, m) # fill the reserved slot, nothing else: - m.sh.types[t.uniqueId.item] = p + m.types[t.uniqueId.item] = p proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib = ## the plib hangs off the psym via the .annex field @@ -334,8 +382,8 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item): - if s.itemId.item >= m.sh.syms.len: - setLen m.sh.syms, s.itemId.item+1 + if s.itemId.item >= m.syms.len: + setLen m.syms, s.itemId.item+1 assert sfForward notin s.flags @@ -363,7 +411,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId p.cname = toLitId(s.cname, m) # fill the reserved slot, nothing else: - m.sh.syms[s.itemId.item] = p + m.syms[s.itemId.item] = p proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) = ## add a remote symbol reference to the tree @@ -387,7 +435,7 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa typeId: storeTypeLater(n.typ, c, m), info: info) of nkIdent: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.sh.strings, n.ident.s), + operand: int32 getOrIncl(m.strings, n.ident.s), typeId: storeTypeLater(n.typ, c, m), info: info) of nkSym: if n.sym.itemId.module == c.thisModule: @@ -405,15 +453,15 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa typeId: storeTypeLater(n.typ, c, m), info: info) of externIntLit: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.sh.numbers, n.intVal), + operand: int32 getOrIncl(m.numbers, n.intVal), typeId: storeTypeLater(n.typ, c, m), info: info) of nkStrLit..nkTripleStrLit: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.sh.strings, n.strVal), + operand: int32 getOrIncl(m.strings, n.strVal), typeId: storeTypeLater(n.typ, c, m), info: info) of nkFloatLit..nkFloat128Lit: ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, - operand: int32 getOrIncl(m.sh.numbers, cast[BiggestInt](n.floatVal)), + operand: int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)), typeId: storeTypeLater(n.typ, c, m), info: info) else: let patchPos = ir.prepare(n.kind, n.flags, @@ -499,7 +547,6 @@ proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) = proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef; ignoreConfig = false): RodFileError = - m.sh = Shared() var f = rodfiles.open(filename.string) f.loadHeader() f.loadSection configSection @@ -519,7 +566,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef f.loadSection section f.load data - loadTabSection stringsSection, m.sh.strings + loadTabSection stringsSection, m.strings loadSeqSection checkSumsSection, m.includes if not includesIdentical(m, config): @@ -527,7 +574,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef loadSeqSection depsSection, m.imports - loadTabSection numbersSection, m.sh.numbers + loadTabSection numbersSection, m.numbers loadSeqSection exportsSection, m.exports loadSeqSection hiddenSection, m.hidden @@ -545,8 +592,8 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef loadSeqSection toReplaySection, m.toReplay.nodes loadSeqSection topLevelSection, m.topLevel.nodes loadSeqSection bodiesSection, m.bodies.nodes - loadSeqSection symsSection, m.sh.syms - loadSeqSection typesSection, m.sh.types + loadSeqSection symsSection, m.syms + loadSeqSection typesSection, m.types loadSeqSection typeInstCacheSection, m.typeInstCache loadSeqSection procInstCacheSection, m.procInstCache @@ -586,13 +633,13 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac f.storeSection section f.store data - storeTabSection stringsSection, m.sh.strings + storeTabSection stringsSection, m.strings storeSeqSection checkSumsSection, m.includes storeSeqSection depsSection, m.imports - storeTabSection numbersSection, m.sh.numbers + storeTabSection numbersSection, m.numbers storeSeqSection exportsSection, m.exports storeSeqSection hiddenSection, m.hidden @@ -610,9 +657,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac storeSeqSection topLevelSection, m.topLevel.nodes storeSeqSection bodiesSection, m.bodies.nodes - storeSeqSection symsSection, m.sh.syms + storeSeqSection symsSection, m.syms - storeSeqSection typesSection, m.sh.types + storeSeqSection typesSection, m.types storeSeqSection typeInstCacheSection, m.typeInstCache storeSeqSection procInstCacheSection, m.procInstCache @@ -700,17 +747,17 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; of nkEmpty, nkNilLit, nkType: discard of nkIdent: - result.ident = getIdent(c.cache, g[thisModule].fromDisk.sh.strings[n.litId]) + result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId]) of nkSym: result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand)) of directIntLit: result.intVal = tree.nodes[n.int].operand of externIntLit: - result.intVal = g[thisModule].fromDisk.sh.numbers[n.litId] + result.intVal = g[thisModule].fromDisk.numbers[n.litId] of nkStrLit..nkTripleStrLit: - result.strVal = g[thisModule].fromDisk.sh.strings[n.litId] + result.strVal = g[thisModule].fromDisk.strings[n.litId] of nkFloatLit..nkFloat128Lit: - result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.sh.numbers[n.litId]) + result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId]) of nkModuleRef: let (n1, n2) = sons2(tree, n) assert n1.kind == nkInt32Lit @@ -767,7 +814,7 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; options: s.options, position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position, offset: if s.kind in routineKinds: defaultOffset else: s.offset, - name: getIdent(c.cache, g[si].fromDisk.sh.strings[s.name]) + name: getIdent(c.cache, g[si].fromDisk.strings[s.name]) ) template loadAstBody(p, field) = @@ -785,7 +832,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph; result = nil else: result = PLib(generated: l.generated, isOverriden: l.isOverriden, - kind: l.kind, name: rope g[si].fromDisk.sh.strings[l.name]) + kind: l.kind, name: rope g[si].fromDisk.strings[l.name]) loadAstBody(l, path) proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; @@ -798,14 +845,14 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; loadAstBody(s, ast) result.annex = loadLib(c, g, si, item, s.annex) when hasFFI: - result.cname = g[si].fromDisk.sh.strings[s.cname] + result.cname = g[si].fromDisk.strings[s.cname] if s.kind in {skLet, skVar, skField, skForVar}: result.guard = loadSym(c, g, si, s.guard) result.bitsize = s.bitsize result.alignment = s.alignment result.owner = loadSym(c, g, si, s.owner) - let externalName = g[si].fromDisk.sh.strings[s.externalName] + let externalName = g[si].fromDisk.strings[s.externalName] if externalName != "": result.loc.r = rope externalName result.loc.flags = s.locFlags @@ -818,14 +865,14 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: assert g[si].status in {loaded, storing, stored} if not g[si].symsInit: g[si].symsInit = true - setLen g[si].syms, g[si].fromDisk.sh.syms.len + setLen g[si].syms, g[si].fromDisk.syms.len if g[si].syms[s.item] == nil: - if g[si].fromDisk.sh.syms[s.item].kind != skModule: - result = symHeaderFromPacked(c, g, g[si].fromDisk.sh.syms[s.item], si, s.item) + if g[si].fromDisk.syms[s.item].kind != skModule: + result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item) # store it here early on, so that recursions work properly: g[si].syms[s.item] = result - symBodyFromPacked(c, g, g[si].fromDisk.sh.syms[s.item], si, s.item, result) + symBodyFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item, result) else: result = g[si].module assert result != nil @@ -866,13 +913,13 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t if not g[si].typesInit: g[si].typesInit = true - setLen g[si].types, g[si].fromDisk.sh.types.len + setLen g[si].types, g[si].fromDisk.types.len if g[si].types[t.item] == nil: - result = typeHeaderFromPacked(c, g, g[si].fromDisk.sh.types[t.item], si, t.item) + result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item) # store it here early on, so that recursions work properly: g[si].types[t.item] = result - typeBodyFromPacked(c, g, g[si].fromDisk.sh.types[t.item], si, t.item, result) + typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result) else: result = g[si].types[t.item] assert result.itemId.item > 0 @@ -897,7 +944,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa let e2 = when e[1] is PackedItemId: e[1] else: PackedItemId(module: LitId(0), item: e[1]) - iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(e2) + iface.mgetOrPut(cache.getIdent(m.fromDisk.strings[nameLit]), @[]).add(e2) for e in m.fromDisk.exports: m.iface.impl(e) @@ -1000,7 +1047,7 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache; lastFile: FileIndex(-1), config: config, cache: cache) - let pos = g[mId].fromDisk.sh.syms[s.itemId.item].ast + let pos = g[mId].fromDisk.syms[s.itemId.item].ast assert pos != emptyNodeId result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos) @@ -1042,15 +1089,15 @@ proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; confi proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) = var bugs = 0 - for i in 1 .. high(m.sh.syms): - if m.sh.syms[i].kind == skUnknown: + for i in 1 .. high(m.syms): + if m.syms[i].kind == skUnknown: echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId)) inc bugs assert bugs == 0 when false: var nones = 0 - for i in 1 .. high(m.sh.types): - inc nones, m.sh.types[i].kind == tyNone + for i in 1 .. high(m.types): + inc nones, m.types[i].kind == tyNone assert nones < 1 proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; @@ -1133,13 +1180,13 @@ proc interfaceSymbol*(config: ConfigRef, cache: IdentCache; result = loadSym(decoder, g, int(module), values[0]) proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator = - IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.sh.syms.len, - typeId: int32 m.fromDisk.sh.types.len) + IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.syms.len, + typeId: int32 m.fromDisk.types.len) proc searchForCompilerproc*(m: LoadedModule; name: string): int32 = # slow, linear search, but the results are cached: for it in items(m.fromDisk.compilerProcs): - if m.fromDisk.sh.strings[it[0]] == name: + if m.fromDisk.strings[it[0]] == name: return it[1] return -1 @@ -1149,31 +1196,31 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = var m: PackedModule let err = loadRodFile(rodfile, m, config, ignoreConfig=true) if err != ok: - config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err + config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err when true: echo "exports:" for ex in m.exports: - echo " ", m.sh.strings[ex[0]], " local ID: ", ex[1] - assert ex[0] == m.sh.syms[ex[1]].name + echo " ", m.strings[ex[0]], " local ID: ", ex[1] + assert ex[0] == m.syms[ex[1]].name # ex[1] int32 echo "reexports:" for ex in m.reexports: - echo " ", m.sh.strings[ex[0]] + echo " ", m.strings[ex[0]] # reexports*: seq[(LitId, PackedItemId)] echo "hidden: " & $m.hidden.len for ex in m.hidden: - echo " ", m.sh.strings[ex[0]], " local ID: ", ex[1] + echo " ", m.strings[ex[0]], " local ID: ", ex[1] echo "all symbols" - for i in 0..high(m.sh.syms): - if m.sh.syms[i].name != LitId(0): - echo " ", m.sh.strings[m.sh.syms[i].name], " local ID: ", i, " kind ", m.sh.syms[i].kind + for i in 0..high(m.syms): + if m.syms[i].name != LitId(0): + echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind else: - echo " local ID: ", i, " kind ", m.sh.syms[i].kind + echo " local ID: ", i, " kind ", m.syms[i].kind - echo "symbols: ", m.sh.syms.len, " types: ", m.sh.types.len, + echo "symbols: ", m.syms.len, " types: ", m.types.len, " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len, - " strings: ", m.sh.strings.len, " numbers: ", m.sh.numbers.len + " strings: ", m.strings.len, " numbers: ", m.numbers.len diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim index a28f2066a..428c344a3 100644 --- a/compiler/ic/integrity.nim +++ b/compiler/ic/integrity.nim @@ -42,12 +42,12 @@ proc checkType(c: var CheckedContext; typeId: PackedItemId) = if not c.checkedTypes.containsOrIncl(itemId): let oldThisModule = c.thisModule c.thisModule = itemId.module - checkTypeObj c, c.g.packed[itemId.module].fromDisk.sh.types[itemId.item] + checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item] c.thisModule = oldThisModule proc checkSym(c: var CheckedContext; s: PackedSym) = if s.name != LitId(0): - assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId s.name + assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name checkType c, s.typ if s.ast != emptyNodeId: checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast) @@ -57,14 +57,14 @@ proc checkSym(c: var CheckedContext; s: PackedSym) = proc checkLocalSym(c: var CheckedContext; item: int32) = let itemId = ItemId(module: c.thisModule, item: item) if not c.checkedSyms.containsOrIncl(itemId): - checkSym c, c.g.packed[c.thisModule].fromDisk.sh.syms[item] + checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item] proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) = let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config) if not c.checkedSyms.containsOrIncl(itemId): let oldThisModule = c.thisModule c.thisModule = itemId.module - checkSym c, c.g.packed[itemId.module].fromDisk.sh.syms[itemId.item] + checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item] c.thisModule = oldThisModule proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) = @@ -74,15 +74,15 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) = of nkEmpty, nkNilLit, nkType, nkNilRodNode: discard of nkIdent: - assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId + assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId of nkSym: checkLocalSym(c, tree.nodes[n.int].operand) of directIntLit: discard of externIntLit, nkFloatLit..nkFloat128Lit: - assert c.g.packed[c.thisModule].fromDisk.sh.numbers.hasLitId n.litId + assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId of nkStrLit..nkTripleStrLit: - assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId + assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId of nkModuleRef: let (n1, n2) = sons2(tree, n) assert n1.kind == nkInt32Lit @@ -97,25 +97,25 @@ proc checkTree(c: var CheckedContext; t: PackedTree) = proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) = for symId in symIds: - assert symId >= 0 and symId < m.sh.syms.len, $symId & " " & $m.sh.syms.len + assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len proc checkModule(c: var CheckedContext; m: PackedModule) = # We check that: # - Every symbol references existing types and symbols. # - Every tree node references existing types and symbols. - for i in 0..high(m.sh.syms): + for i in 0..high(m.syms): checkLocalSym c, int32(i) checkTree c, m.toReplay checkTree c, m.topLevel for e in m.exports: - assert e[1] >= 0 and e[1] < m.sh.syms.len - assert e[0] == m.sh.syms[e[1]].name + assert e[1] >= 0 and e[1] < m.syms.len + assert e[0] == m.syms[e[1]].name for e in m.compilerProcs: - assert e[1] >= 0 and e[1] < m.sh.syms.len - assert e[0] == m.sh.syms[e[1]].name + assert e[1] >= 0 and e[1] < m.syms.len + assert e[0] == m.syms[e[1]].name checkLocalSymIds c, m, m.converters checkLocalSymIds c, m, m.methods diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index b09275220..b1a237cf7 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -35,12 +35,12 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool = proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool = result = s.name != LitId(0) and - isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.sh.strings[s.name].len) + isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len) proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool = - let name = c.g.packed[s.module].fromDisk.sh.syms[s.item].name + let name = c.g.packed[s.module].fromDisk.syms[s.item].name result = name != LitId(0) and - isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.sh.strings[name].len) + isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len) const EmptyItemId = ItemId(module: -1'i32, item: -1'i32) @@ -51,7 +51,7 @@ proc search(c: var NavContext; tree: PackedTree): ItemId = case tree.nodes[i].kind of nkSym: let item = tree.nodes[i].operand - if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.sh.syms[item], tree.nodes[i].info): + if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree.nodes[i].info): return ItemId(module: c.thisModule, item: item) of nkModuleRef: if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file: @@ -74,7 +74,7 @@ proc isDecl(tree: PackedTree; n: NodePos): bool = proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) = var m = "" - var file = c.g.packed[c.thisModule].fromDisk.sh.strings[info.file] + var file = c.g.packed[c.thisModule].fromDisk.strings[info.file] if c.outputSep == ' ': file = os.extractFilename file toLocation(m, file, info.line.int, info.col.int + ColOffset) @@ -102,7 +102,7 @@ proc nav(g: ModuleGraph) = # translate the track position to a packed position: let unpacked = g.config.m.trackPos let mid = unpacked.fileIndex - let fileId = g.packed[int32 mid].fromDisk.sh.strings.getKeyId(toFullPath(g.config, mid)) + let fileId = g.packed[int32 mid].fromDisk.strings.getKeyId(toFullPath(g.config, mid)) if fileId == LitId(0): internalError(g.config, unpacked, "cannot find a valid file ID") diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 0649b56ce..2700c8253 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -98,17 +98,6 @@ type PackedTree* = object ## usually represents a full Nim module nodes*: seq[PackedNode] - #sh*: Shared - - Shared* = ref object # shared between different versions of 'Module'. - # (though there is always exactly one valid - # version of a module) - syms*: seq[PackedSym] - types*: seq[PackedType] - strings*: BiTable[string] # we could share these between modules. - numbers*: BiTable[BiggestInt] # we also store floats in here so - # that we can assure that every bit is kept - #config*: ConfigRef PackedInstantiation* = object key*, sym*: PackedItemId @@ -374,51 +363,6 @@ const externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit} directIntLit* = nkInt32Lit -proc toString*(tree: PackedTree; n: NodePos; sh: Shared; nesting: int; - result: var string) = - let pos = n.int - if result.len > 0 and result[^1] notin {' ', '\n'}: - result.add ' ' - - result.add $tree[pos].kind - case tree.nodes[pos].kind - of nkNone, nkEmpty, nkNilLit, nkType: discard - of nkIdent, nkStrLit..nkTripleStrLit: - result.add " " - result.add sh.strings[LitId tree.nodes[pos].operand] - of nkSym: - result.add " " - result.add sh.strings[sh.syms[tree.nodes[pos].operand].name] - of directIntLit: - result.add " " - result.addInt tree.nodes[pos].operand - of externSIntLit: - result.add " " - result.addInt sh.numbers[LitId tree.nodes[pos].operand] - of externUIntLit: - result.add " " - result.add $cast[uint64](sh.numbers[LitId tree.nodes[pos].operand]) - of nkFloatLit..nkFloat128Lit: - result.add " " - result.add $cast[BiggestFloat](sh.numbers[LitId tree.nodes[pos].operand]) - else: - result.add "(\n" - for i in 1..(nesting+1)*2: result.add ' ' - for child in sonsReadonly(tree, n): - toString(tree, child, sh, nesting + 1, result) - result.add "\n" - for i in 1..nesting*2: result.add ' ' - result.add ")" - #for i in 1..nesting*2: result.add ' ' - - -proc toString*(tree: PackedTree; n: NodePos; sh: Shared): string = - result = "" - toString(tree, n, sh, 0, result) - -proc debug*(tree: PackedTree; sh: Shared) = - stdout.write toString(tree, NodePos 0, sh) - when false: proc identIdImpl(tree: PackedTree; n: NodePos): LitId = if n.kind == nkIdent: diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 86d8ba203..a52bd18b3 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -23,8 +23,8 @@ from typetraits import supportsCopyMem ## (`RodFileError`). The file format broken up into sections (`RodSection`) ## and preceeded by a header (see: `cookie`). The precise layout, section ## ordering and data following the section are determined by the user. See -## `ic.loadRoadFile`. -## +## `ic.loadRodFile`. +## ## A basic but "wrong" example of the lifecycle: ## --------------------------------------------- ## 1. `create` or `open` - create a new one or open an existing @@ -45,10 +45,10 @@ from typetraits import supportsCopyMem ## The API is centered around IO and prone to error, each operation checks or ## sets the `RodFile.err` field. A user of this API needs to handle these ## appropriately. -## +## ## API Notes ## ========= -## +## ## Valid inputs for Rod files ## -------------------------- ## ASTs, hopes, dreams, and anything as long as it and any children it may have @@ -61,7 +61,7 @@ from typetraits import supportsCopyMem ## ---------------------------- ## A flag based approach is used where operations no-op in case of a ## preexisting error and set the flag if they encounter one. -## +## ## Misc ## ---- ## * 'Prim' is short for 'primitive', as in a non-sequence type From bae7b5b7795ae8b429e50deba61430ae43a1750f Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 19 Apr 2021 17:48:26 +0800 Subject: [PATCH 2454/4254] fix #17732(forward args... to megatest) (#17780) --- testament/categories.nim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 7b57adb8a..4c3a0b1f5 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -573,7 +573,7 @@ proc quoted(a: string): string = # todo: consider moving to system.nim result.addQuoted(a) -proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = +proc runJoinedTest(r: var TResults, cat: Category, testsDir: string, options: string) = ## returns a list of tests that have problems #[ xxx create a reusable megatest API after abstracting out testament specific code, @@ -619,7 +619,11 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) = writeFile(megatestFile, megatest) let root = getCurrentDir() - let args = ["c", "--nimCache:" & outDir, "-d:testing", "-d:nimMegatest", "--listCmd", "--path:" & root, megatestFile] + + var args = @["c", "--nimCache:" & outDir, "-d:testing", "-d:nimMegatest", "--listCmd", + "--path:" & root] + args.add options.parseCmdLine + args.add megatestFile var (cmdLine, buf, exitCode) = execCmdEx2(command = compilerPrefix, args = args, input = "") if exitCode != 0: echo "$ " & cmdLine & "\n" & buf @@ -710,7 +714,7 @@ proc processCategory(r: var TResults, cat: Category, if not handled: case cat2 of "megatest": - runJoinedTest(r, cat, testsDir) + runJoinedTest(r, cat, testsDir, options) else: var testsRun = 0 var files: seq[string] From 6de5aa1971b17b0869470d7cdc886ef230103832 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 19 Apr 2021 13:16:10 +0200 Subject: [PATCH 2455/4254] Rename `=` to `=copy` in stdlib (#17781) --- lib/deprecated/pure/sharedstrings.nim | 2 +- lib/std/channels.nim | 2 +- lib/std/isolation.nim | 2 +- lib/system.nim | 1 + lib/system/widestrs.nim | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/deprecated/pure/sharedstrings.nim b/lib/deprecated/pure/sharedstrings.nim index 29cb0fcc2..4d4ae151b 100644 --- a/lib/deprecated/pure/sharedstrings.nim +++ b/lib/deprecated/pure/sharedstrings.nim @@ -37,7 +37,7 @@ proc `=destroy`*(s: SharedString) = decRef(s.buffer) when false: - proc `=`*(dest: var SharedString; src: SharedString) = + proc `=copy`*(dest: var SharedString; src: SharedString) = incRef(src.buffer) if not dest.buffer.isNil: decRef(dest.buffer) diff --git a/lib/std/channels.nim b/lib/std/channels.nim index 49def0913..5ff141384 100644 --- a/lib/std/channels.nim +++ b/lib/std/channels.nim @@ -443,7 +443,7 @@ proc `=destroy`*[T](c: var Channel[T]) = else: atomicDec(c.d.atomicCounter) -proc `=`*[T](dest: var Channel[T], src: Channel[T]) = +proc `=copy`*[T](dest: var Channel[T], src: Channel[T]) = ## Shares `Channel` by reference counting. if src.d != nil: atomicInc(src.d.atomicCounter) diff --git a/lib/std/isolation.nim b/lib/std/isolation.nim index 8daca233b..7d6ac6092 100644 --- a/lib/std/isolation.nim +++ b/lib/std/isolation.nim @@ -18,7 +18,7 @@ type Isolated*[T] = object ## Isolated data can only be moved, not copied. value: T -proc `=`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.} +proc `=copy`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.} proc `=sink`*[T](dest: var Isolated[T]; src: Isolated[T]) {.inline.} = # delegate to value's sink operation diff --git a/lib/system.nim b/lib/system.nim index 532883853..7fd35781b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -478,6 +478,7 @@ proc `[]`*[I: Ordinal;T](a: T; i: I): T {. proc `[]=`*[I: Ordinal;T,S](a: T; i: I; x: sink S) {.noSideEffect, magic: "ArrPut".} proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} +proc `=copy`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} proc arrGet[I: Ordinal;T](a: T; i: I): T {. noSideEffect, magic: "ArrGet".} diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 16bc3f3ca..a999c9167 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -32,7 +32,7 @@ when defined(nimv2): else: dealloc(a.data) - proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.} + proc `=copy`(a: var WideCStringObj; b: WideCStringObj) {.error.} proc `=sink`(a: var WideCStringObj; b: WideCStringObj) = a.bytes = b.bytes From 438afb4db93dd9fcc6e94995a56f616a9e3d7826 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 19 Apr 2021 17:19:21 +0200 Subject: [PATCH 2456/4254] Introduce localErrorNode (#17785) --- compiler/sem.nim | 3 +-- compiler/semdata.nim | 13 +++++++++++++ compiler/semexprs.nim | 6 ++---- compiler/semmagic.nim | 12 ++++-------- compiler/semobjconstr.nim | 6 ++---- compiler/semstmts.nim | 3 +-- compiler/vm.nim | 8 ++++---- 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index ccc634b4d..4020fc4d6 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -296,8 +296,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = result = evaluated let expectedType = eOrig.typ.skipTypes({tyStatic}) if hasCycle(result): - globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further") - result = errorNode(c, eOrig) + result = localErrorNode(c, eOrig, "the resulting AST is cyclic and cannot be processed further") else: semmacrosanity.annotateType(result, expectedType, c.config) else: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 9e7258a69..354d4587d 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -501,6 +501,19 @@ proc errorNode*(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) result.typ = errorType(c) +proc localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode = + localError(c.config, info, msg, arg) + result = errorNode(c, n) + +proc localErrorNode*(c: PContext, n: PNode, info: TLineInfo, arg: string): PNode = + localErrorNode(c, n, info, errGenerated, arg) + +proc localErrorNode*(c: PContext, n: PNode, msg: TMsgKind, arg: string): PNode = + localErrorNode(c, n, n.info, msg, arg) + +proc localErrorNode*(c: PContext, n: PNode, arg: string): PNode = + localErrorNode(c, n, n.info, errGenerated, arg) + proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind dest.owner = getCurrOwner(c) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 1582cc0fd..353831736 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1044,8 +1044,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = if e != nil: result.add(newSymNode(e)) else: - localError(c.config, n.info, "system needs: echo") - result.add(errorNode(c, n)) + result.add localErrorNode(c, n, "system needs: echo") result.add(n) result = semExpr(c, result) @@ -2621,8 +2620,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # check if either everything or nothing is tyTypeDesc for i in 1.. high(TSymChoiceRule).int: - localError(c.config, n[2].info, errConstExprExpected) - return errorNode(c, n) + return localErrorNode(c, n, n[2].info, errConstExprExpected) let id = newIdentNode(getIdent(c.cache, sl.strVal), n.info) let s = qualifiedLookUp(c, id, {checkUndeclared}) @@ -253,12 +251,10 @@ proc semBindSym(c: PContext, n: PNode): PNode = proc opBindSym(c: PContext, scope: PScope, n: PNode, isMixin: int, info: PNode): PNode = if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit, nkIdent}: - localError(c.config, info.info, errStringOrIdentNodeExpected) - return errorNode(c, n) + return localErrorNode(c, n, info.info, errStringOrIdentNodeExpected) if isMixin < 0 or isMixin > high(TSymChoiceRule).int: - localError(c.config, info.info, errConstExprExpected) - return errorNode(c, n) + return localErrorNode(c, n, info.info, errConstExprExpected) let id = if n.kind == nkIdent: n else: newIdentNode(getIdent(c.cache, n.strVal), info.info) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index dea187ea7..63b4b9a75 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -379,8 +379,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = for child in n: result.add child if t == nil: - localError(c.config, n.info, errGenerated, "object constructor needs an object type") - return errorNode(c, result) + return localErrorNode(c, result, errGenerated, "object constructor needs an object type") t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned}) if t.kind == tyRef: @@ -391,8 +390,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # multiple times as long as they don't have closures. result.typ.flags.incl tfHasOwned if t.kind != tyObject: - localError(c.config, n.info, errGenerated, "object constructor needs an object type") - return errorNode(c, result) + return localErrorNode(c, result, errGenerated, "object constructor needs an object type") # Check if the object is fully initialized by recursively testing each # field (if this is a case object, initialized fields in two different diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index bedc5a7e5..a10047187 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -725,8 +725,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if n.len == 3: if n[0].kind == nkVarTuple: if n[0].len-1 != iterAfterVarLent.len: - localError(c.config, n[0].info, errWrongNumberOfVariables) - return errorNode(c, n) + return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables) for i in 0.. Date: Mon, 19 Apr 2021 17:51:00 +0200 Subject: [PATCH 2457/4254] Small privateAccess improvement (#17786) --- lib/std/importutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/importutils.nim b/lib/std/importutils.nim index f7a3cbd03..0c0f546b9 100644 --- a/lib/std/importutils.nim +++ b/lib/std/importutils.nim @@ -17,7 +17,7 @@ when defined(nimImportutilsExample): x1: int # private proc initFoo*(): auto = Foo() -proc privateAccess*(t: typedesc[object|ref|ptr]) {.magic: "PrivateAccess".} = +proc privateAccess*(t: typedesc[object|(ref object)|(ptr object)]) {.magic: "PrivateAccess".} = ## Enables access to private fields of `t` in current scope. runnableExamples("-d:nimImportutilsExample"): # here we're importing a module containing: From 3b80f0dc8ef2bc9d2a981a7c92a6355dfc72b7ef Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 19 Apr 2021 22:37:09 +0200 Subject: [PATCH 2458/4254] IC navigator: added support for include files (#17784) * ic fixed navigator crash when track wrong/missed Also fixed an issue with getNimcacheDir not observing the outDir. * closer, but not sure how to test[skip ci][ci skip] * IC navigator: added support for include files * update * make posix happy via expandFilename * update Co-authored-by: Saem Ghani --- compiler/commands.nim | 69 +++++++++++++++++++++----------- compiler/ic/ic.nim | 2 +- compiler/ic/navigator.nim | 28 +++++++++++-- compiler/msgs.nim | 3 ++ compiler/options.nim | 5 ++- testament/categories.nim | 2 +- tests/navigator/minclude.nim | 2 + tests/navigator/tincludefile.nim | 29 ++++++++++++++ tests/navigator/tnav1.nim | 4 +- 9 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 tests/navigator/minclude.nim create mode 100644 tests/navigator/tincludefile.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index e918979fb..5d6e45fb5 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -28,7 +28,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos, - pathutils, strtabs + pathutils, strtabs, pathnorm from ast import eqTypeFlags, tfGcSafe, tfNoSideEffect @@ -359,31 +359,52 @@ proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir const errInvalidNumber = "$1 is not a valid number" +proc makeAbsolute(s: string): AbsoluteFile = + if isAbsolute(s): + AbsoluteFile pathnorm.normalizePath(s) + else: + AbsoluteFile pathnorm.normalizePath(os.getCurrentDir() / s) + +proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string, + info: TLineInfo) = + ## set tracking info, common code for track, trackDirty, & ideTrack + var ln, col: int + if parseUtils.parseInt(line, ln) <= 0: + localError(conf, info, errInvalidNumber % line) + if parseUtils.parseInt(column, col) <= 0: + localError(conf, info, errInvalidNumber % column) + + let a = makeAbsolute(file) + if dirty == "": + conf.m.trackPos = newLineInfo(conf, a, ln, col) + else: + let dirtyOriginalIdx = fileInfoIdx(conf, a) + if dirtyOriginalIdx.int32 >= 0: + msgs.setDirtyFile(conf, dirtyOriginalIdx, makeAbsolute(dirty)) + conf.m.trackPos = newLineInfo(dirtyOriginalIdx, ln, col) + proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') if a.len != 4: localError(conf, info, "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected") - var line, column: int - if parseUtils.parseInt(a[2], line) <= 0: - localError(conf, info, errInvalidNumber % a[1]) - if parseUtils.parseInt(a[3], column) <= 0: - localError(conf, info, errInvalidNumber % a[2]) - - let dirtyOriginalIdx = fileInfoIdx(conf, AbsoluteFile a[1]) - if dirtyOriginalIdx.int32 >= 0: - msgs.setDirtyFile(conf, dirtyOriginalIdx, AbsoluteFile a[0]) - - conf.m.trackPos = newLineInfo(dirtyOriginalIdx, line, column) + setTrackingInfo(conf, a[0], a[1], a[2], a[3], info) proc track(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected") - var line, column: int - if parseUtils.parseInt(a[1], line) <= 0: - localError(conf, info, errInvalidNumber % a[1]) - if parseUtils.parseInt(a[2], column) <= 0: - localError(conf, info, errInvalidNumber % a[2]) - conf.m.trackPos = newLineInfo(conf, AbsoluteFile a[0], line, column) + setTrackingInfo(conf, "", a[0], a[1], a[2], info) + +proc trackIde(conf: ConfigRef; cmd: IdeCmd, arg: string, info: TLineInfo) = + ## set the tracking info related to an ide cmd, supports optional dirty file + var a = arg.split(',') + case a.len + of 4: + setTrackingInfo(conf, a[0], a[1], a[2], a[3], info) + of 3: + setTrackingInfo(conf, "", a[0], a[1], a[2], info) + else: + localError(conf, info, "[DIRTY_BUFFER,]ORIGINAL_FILE,LINE,COLUMN expected") + conf.ideCmd = cmd proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if pass in {passCmd2, passPP}: @@ -851,17 +872,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideSug of "def": - expectNoArg(conf, switch, arg, pass, info) - conf.ideCmd = ideDef + expectArg(conf, switch, arg, pass, info) + trackIde(conf, ideDef, arg, info) of "context": expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideCon of "usages": - expectNoArg(conf, switch, arg, pass, info) - conf.ideCmd = ideUse + expectArg(conf, switch, arg, pass, info) + trackIde(conf, ideUse, arg, info) of "defusages": - expectNoArg(conf, switch, arg, pass, info) - conf.ideCmd = ideDus + expectArg(conf, switch, arg, pass, info) + trackIde(conf, ideDus, arg, info) of "stdout": processOnOffSwitchG(conf, {optStdout}, arg, pass, info) of "listfullpaths": diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index a23685be7..d9a8756f1 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -29,7 +29,7 @@ type PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file definedSymbols: string moduleFlags: TSymFlags - includes: seq[(LitId, string)] # first entry is the module filename itself + includes*: seq[(LitId, string)] # first entry is the module filename itself imports: seq[LitId] # the modules this module depends on toReplay*: PackedTree # pragmas and VM specific state to replay. topLevel*: PackedTree # top level statements diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index b1a237cf7..cedf41579 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -98,11 +98,31 @@ proc list(c: var NavContext; tree: PackedTree; sym: ItemId) = usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i))) else: discard +proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int = + for i in 0..high(g.packed): + for k in 1..high(g.packed[i].fromDisk.includes): + # we start from 1 because the first "include" file is + # the module's filename. + if os.cmpPaths(g.packed[i].fromDisk.strings[g.packed[i].fromDisk.includes[k][0]], fullPath) == 0: + return i + return -1 + proc nav(g: ModuleGraph) = # translate the track position to a packed position: let unpacked = g.config.m.trackPos - let mid = unpacked.fileIndex - let fileId = g.packed[int32 mid].fromDisk.strings.getKeyId(toFullPath(g.config, mid)) + var mid = unpacked.fileIndex.int + + let fullPath = toFullPath(g.config, unpacked.fileIndex) + + if g.packed[mid].status == undefined: + # check if 'mid' is an include file of some other module: + mid = searchForIncludeFile(g, fullPath) + + if mid < 0: + localError(g.config, unpacked, "unknown file name: " & fullPath) + return + + let fileId = g.packed[mid].fromDisk.strings.getKeyId(fullPath) if fileId == LitId(0): internalError(g.config, unpacked, "cannot find a valid file ID") @@ -114,9 +134,9 @@ proc nav(g: ModuleGraph) = trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId), outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t' ) - var symId = search(c, g.packed[int32 mid].fromDisk.topLevel) + var symId = search(c, g.packed[mid].fromDisk.topLevel) if symId == EmptyItemId: - symId = search(c, g.packed[int32 mid].fromDisk.bodies) + symId = search(c, g.packed[mid].fromDisk.bodies) if symId == EmptyItemId: localError(g.config, unpacked, "no symbol at this position") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index c1e1f9e39..39b10d7df 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -582,6 +582,9 @@ template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = liMessage(conf, info, errGenerated, arg, doRaise, instLoc()) +template globalError*(conf: ConfigRef; format: string, params: openArray[string]) = + liMessage(conf, unknownLineInfo, errGenerated, format % params, doRaise, instLoc()) + template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(conf, info, msg, arg, doNothing, instLoc()) diff --git a/compiler/options.nim b/compiler/options.nim index 5475410a4..c1ac6b1e0 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -701,7 +701,10 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir = result = if not conf.nimcacheDir.isEmpty: conf.nimcacheDir elif conf.backend == backendJs: - conf.projectPath / genSubDir + if conf.outDir.isEmpty: + conf.projectPath / genSubDir + else: + conf.outDir / genSubDir else: AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name & nimcacheSuffix(conf)) diff --git a/testament/categories.nim b/testament/categories.nim index 4c3a0b1f5..d05112a25 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -490,7 +490,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; writeOnly = " --incremental:writeonly " readOnly = " --incremental:readonly " incrementalOn = " --incremental:on -d:nimIcIntegrityChecks " - navTestConfig = " --ic:on --defusages -d:nimIcNavigatorTests --hint[Conf]:off --warnings:off " + navTestConfig = " --ic:on -d:nimIcNavigatorTests --hint[Conf]:off --warnings:off " template test(x: untyped) = testSpecWithNimcache(r, makeRawTest(file, x & options, cat), nimcache) diff --git a/tests/navigator/minclude.nim b/tests/navigator/minclude.nim new file mode 100644 index 000000000..f65ebfab9 --- /dev/null +++ b/tests/navigator/minclude.nim @@ -0,0 +1,2 @@ +# An include file. +foo(3) diff --git a/tests/navigator/tincludefile.nim b/tests/navigator/tincludefile.nim new file mode 100644 index 000000000..f35ab2ec9 --- /dev/null +++ b/tests/navigator/tincludefile.nim @@ -0,0 +1,29 @@ +discard """ + cmd: "nim check $options --defusages:$file,12,7 $file" + nimout: '''def tincludefile_temp.nim(11, 10) +usage tincludefile_temp.nim(12, 8) + ''' +""" + + + + +proc foo(x: int) = + echo x + +foo(3) +echo "yes", 1 != 3 + +#!EDIT!# +discard """ + cmd: "nim check $options --defusages:$file/../minclude.nim,2,2 $file" + nimout: '''def tincludefile_temp.nim(10, 6) +usage minclude.nim(2, 1) + ''' +""" + + +proc foo(x: int) = + echo x + +include minclude diff --git a/tests/navigator/tnav1.nim b/tests/navigator/tnav1.nim index d7c6f63e2..b6bbdbf19 100644 --- a/tests/navigator/tnav1.nim +++ b/tests/navigator/tnav1.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim check $options --track:$file,12,7 $file" + cmd: "nim check $options --defusages:$file,12,7 $file" nimout: '''def tnav1_temp.nim(11, 10) usage tnav1_temp.nim(12, 8) ''' @@ -16,7 +16,7 @@ echo "yes", 1 != 3 #!EDIT!# discard """ - cmd: "nim check $options --track:$file,15,2 $file" + cmd: "nim check $options --defusages:$file,15,2 $file" nimout: '''def tnav1_temp.nim(12, 6) usage tnav1_temp.nim(15, 1) ''' From ad67bcf379dbe5b7b17d85e28620749cd8bcf5e9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Apr 2021 19:02:52 -0700 Subject: [PATCH 2459/4254] fix https://github.com/nim-lang/RFCs/issues/311 remove unary slice (#16714) --- compiler/suggest.nim | 2 +- lib/system.nim | 8 -------- testament/categories.nim | 2 +- tests/collections/ttables.nim | 2 +- tests/misc/tslices.nim | 11 ++++++----- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index f3add0849..a5b4ac87d 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -112,7 +112,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int if ident[^1] == '=' and ident[0] in linter.Letters: if sourceIdent != "=": result = 0 - elif sourceIdent.len > ident.len and sourceIdent[..ident.high] == ident: + elif sourceIdent.len > ident.len and sourceIdent[0..ident.high] == ident: result = ident.len elif sourceIdent != ident: result = 0 diff --git a/lib/system.nim b/lib/system.nim index 7fd35781b..d73ef6dbe 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -510,14 +510,6 @@ proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, mag ## echo a[2 .. 3] # @[30, 40] result = HSlice[T, U](a: a, b: b) -proc `..`*[T](b: sink T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} = - ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. - ## - ## .. code-block:: Nim - ## let a = [10, 20, 30, 40, 50] - ## echo a[.. 2] # @[10, 20, 30] - result = HSlice[int, T](a: 0, b: b) - when defined(hotCodeReloading): {.pragma: hcrInline, inline.} else: diff --git a/testament/categories.nim b/testament/categories.nim index d05112a25..d7848d51d 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -339,7 +339,7 @@ proc findMainFile(dir: string): string = var nimFiles = 0 for kind, file in os.walkDir(dir): if kind == pcFile: - if file.endsWith(cfgExt): return file[ .. ^(cfgExt.len+1)] & ".nim" + if file.endsWith(cfgExt): return file[0..^(cfgExt.len+1)] & ".nim" elif file.endsWith(".nim"): if result.len == 0: result = file inc nimFiles diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index c2864b75f..638f4241b 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -171,7 +171,7 @@ block tableconstr: # NEW: doAssert 56 in 50..100 - doAssert 56 in ..60 + doAssert 56 in 0..60 block ttables2: diff --git a/tests/misc/tslices.nim b/tests/misc/tslices.nim index d063c5ebf..987b50de1 100644 --- a/tests/misc/tslices.nim +++ b/tests/misc/tslices.nim @@ -11,10 +11,9 @@ verichtetd # Test the new slices. -import strutils - var mystr = "Abgrund" -mystr[..1] = "Zu" +# mystr[..1] = "Zu" # deprecated +mystr[0..1] = "Zu" mystr[4..4] = "5" @@ -23,7 +22,8 @@ type var myarr: array[TEnum, int] = [1, 2, 3, 4, 5, 6] myarr[e1..e3] = myarr[e4..e6] -myarr[..e3] = myarr[e4..e6] +# myarr[..e3] = myarr[e4..e6] # deprecated +myarr[0..e3] = myarr[e4..e6] for x in items(myarr): stdout.write(x) echo() @@ -46,7 +46,8 @@ echo mystr mystr[4..4] = "u" # test full replacement -mystr[.. ^2] = "egerichtet" +# mystr[.. ^2] = "egerichtet" # deprecated +mystr[0 .. ^2] = "egerichtet" echo mystr From 6852d091b33757ab34d1f0c4f9b22d10dbe48049 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Apr 2021 21:54:25 -0700 Subject: [PATCH 2460/4254] changelog: document hash changes (#17792) * changelog: document hash changes * fixup --- changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 8fab425f8..3caf5e92d 100644 --- a/changelog.md +++ b/changelog.md @@ -50,6 +50,9 @@ - On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` for previous behavior. +- `hashes.hash` now supports `object` and `ref` (can be overloaded in user code). +- `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, + `hashes.hash(closure)` has also been improved. ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` @@ -235,12 +238,9 @@ level `moveMem`, `copyMem` operations for Orc's copy-on-write string implementation. -- `hashes.hash` now supports `object`, but can be overloaded. - - Added `std/strbasics` for high performance string operations. Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. -- `hashes.hash` now supports `object`, but can be overloaded. - Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`. From fb02b569578e4538852cb92b350036548aa5da15 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Apr 2021 00:01:53 -0700 Subject: [PATCH 2461/4254] support skip ci in azure pipelines, and support it properly in github actions pipelines (#17561) * support skip ci in azure pipelines * [skip ci] example of a commit that skips CI * example of a commit that does not skip CI * fix github actions logic for ci skip handling * [skip ci] example of a commit that skips CI for all pipelines * example of a commit that does not skip CI for any pipeline --- .github/workflows/ci_docs.yml | 13 ++++++++++++- .github/workflows/ci_packages.yml | 14 +++++++++++++- azure-pipelines.yml | 22 ++++++++++++++++------ doc/contributing.rst | 7 ++++--- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 22d425b10..982efe610 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -30,8 +30,9 @@ on: jobs: build: + # see D20210329T004830 if: | - !contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') + !contains(format('{0}', github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: @@ -50,6 +51,16 @@ jobs: steps: - name: 'Checkout' uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: 'Check whether to skip CI' + shell: bash + run: | + # see D20210329T004830 + commitMsg=$(git log --no-merges -1 --pretty=format:"%s") + echo commitMsg: $commitMsg + echo $commitMsg | grep -v '\[skip ci\]' - name: 'Install build dependencies (macOS)' if: runner.os == 'macOS' diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index dd42db0c4..b7af1210c 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -3,8 +3,9 @@ on: [push, pull_request] jobs: build: + # see D20210329T004830 if: | - !contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') + !contains(format('{0}', github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: @@ -19,6 +20,17 @@ jobs: steps: - name: 'Checkout' uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: 'Check whether to skip CI' + shell: bash + run: | + # see D20210329T004830 + commitMsg=$(git log --no-merges -1 --pretty=format:"%s") + echo commitMsg: $commitMsg + echo $commitMsg | grep -v '\[skip ci\]' + - name: 'Checkout csources' uses: actions/checkout@v2 with: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9006cf6e5..55bad609e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -52,10 +52,20 @@ jobs: steps: - bash: git config --global core.autocrlf false displayName: 'Disable auto conversion to CRLF by git (Windows-only)' - condition: eq(variables['Agent.OS'], 'Windows_NT') + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - checkout: self - fetchDepth: 1 + fetchDepth: 2 # see D20210329T004830 + + - bash: | + # D20210329T004830:here refs https://github.com/microsoft/azure-pipelines-agent/issues/2944 + # `--no-merges` is needed to avoid merge commits which occur for PR's. + # $(Build.SourceVersionMessage) is not helpful + # nor is `github.event.head_commit.message` for github actions. + commitMsg=$(git log --no-merges -1 --pretty=format:"%s") + echo commitMsg: $commitMsg + echo $commitMsg | grep -v '\[skip ci\]' # fails if [skip ci] not in commit msg + displayName: 'Check whether to skip CI' - bash: git clone --depth 1 https://github.com/nim-lang/csources displayName: 'Checkout Nim csources' @@ -73,7 +83,7 @@ jobs: echo_run sudo apt-fast install --no-install-recommends -yq \ libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg displayName: 'Install dependencies (amd64 Linux)' - condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) - bash: | set -e @@ -113,11 +123,11 @@ jobs: echo_run chmod 755 bin/g++ displayName: 'Install dependencies (i386 Linux)' - condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) - bash: brew install boehmgc make sfml displayName: 'Install dependencies (OSX)' - condition: eq(variables['Agent.OS'], 'Darwin') + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - bash: | set -e @@ -130,7 +140,7 @@ jobs: echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' displayName: 'Install dependencies (Windows)' - condition: eq(variables['Agent.OS'], 'Windows_NT') + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin' displayName: 'Add build binaries to PATH' diff --git a/doc/contributing.rst b/doc/contributing.rst index 7ee3aa444..3d3da2ce0 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -508,9 +508,10 @@ Continuous Integration (CI) 1. Continuous Integration is by default run on every push in a PR; this clogs the CI pipeline and affects other PR's; if you don't need it (e.g. for WIP or - documentation only changes), add `[ci skip]` to your commit message title. - This convention is supported by `Appveyor - `_ + documentation only changes), add `[skip ci]` to your commit message title. + This convention is supported by our github actions pipelines and our azure pipeline + as well as our former other pipelines: + `Appveyor `_ and `Travis `_. 2. Consider enabling CI (azure, GitHub actions and builds.sr.ht) in your own Nim fork, and From 68e7ed9c57605bc98d3ab7625374113386e62ee7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Apr 2021 00:02:35 -0700 Subject: [PATCH 2462/4254] important_packages: `allowed_failures` batch (#17757) * important_packages: reserve batch 0 for allowed failures * custom batch name: allowed_failures --- .github/workflows/ci_packages.yml | 2 +- testament/categories.nim | 35 ++++++++++++++++++++++--------- testament/testament.nim | 2 +- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index b7af1210c..e7073ea23 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -11,7 +11,7 @@ jobs: matrix: os: [ubuntu-18.04, macos-10.15] cpu: [amd64] - batch: ["0_3", "1_3", "2_3"] # list of `index_num` + batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num` name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' runs-on: ${{ matrix.os }} env: diff --git a/testament/categories.nim b/testament/categories.nim index d7848d51d..19d9e4507 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -14,6 +14,7 @@ import important_packages import std/strformat +from std/sequtils import filterIt const specialCategories = [ @@ -399,8 +400,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = testSpec r, testObj # ----------------------------- nimble ---------------------------------------- -proc listPackages(packageFilter: string): seq[NimblePackage] = - # xxx document `packageFilter`, seems like a bad API (at least should be a regex; a substring match makes no sense) +proc listPackagesAll(): seq[NimblePackage] = var nimbleDir = getEnv("NIMBLE_DIR") if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" let packageIndex = nimbleDir / "packages_official.json" @@ -409,14 +409,29 @@ proc listPackages(packageFilter: string): seq[NimblePackage] = for a in packageList: if a["name"].str == name: return a for pkg in important_packages.packages.items: - if isCurrentBatch(testamentData0, pkg.name) and packageFilter in pkg.name: - var pkg = pkg - if pkg.url.len == 0: - let pkg2 = findPackage(pkg.name) - if pkg2 == nil: - raise newException(ValueError, "Cannot find package '$#'." % pkg.name) - pkg.url = pkg2["url"].str - result.add pkg + var pkg = pkg + if pkg.url.len == 0: + let pkg2 = findPackage(pkg.name) + if pkg2 == nil: + raise newException(ValueError, "Cannot find package '$#'." % pkg.name) + pkg.url = pkg2["url"].str + result.add pkg + +proc listPackages(packageFilter: string): seq[NimblePackage] = + let pkgs = listPackagesAll() + if packageFilter.len != 0: + # xxx document `packageFilter`, seems like a bad API, + # at least should be a regex; a substring match makes no sense. + result = pkgs.filterIt(packageFilter in it.name) + else: + let pkgs1 = pkgs.filterIt(it.allowFailure) + let pkgs2 = pkgs.filterIt(not it.allowFailure) + if testamentData0.batchArg == "allowed_failures": + result = pkgs1 + else: + for i in 0.. 0 and p.val[0] in {'0'..'9'}: let s = p.val.split("_") doAssert s.len == 2, $(p.val, s) testamentData0.testamentBatch = s[0].parseInt From 4742e6e1fdc6cebd3052875748fa10ad44c8a42e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Apr 2021 00:25:28 -0700 Subject: [PATCH 2463/4254] followup #16714: add -d:nimLegacyUnarySlice + changelog (#17794) --- changelog.md | 3 +++ lib/system.nim | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/changelog.md b/changelog.md index 3caf5e92d..0537b3d6a 100644 --- a/changelog.md +++ b/changelog.md @@ -54,6 +54,9 @@ - `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, `hashes.hash(closure)` has also been improved. +- The unary slice `..b` was removed, use `0..b` instead or use `-d:nimLegacyUnarySlice` + for a deprecation period. + ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` diff --git a/lib/system.nim b/lib/system.nim index d73ef6dbe..41749c27a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -510,6 +510,16 @@ proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, mag ## echo a[2 .. 3] # @[30, 40] result = HSlice[T, U](a: a, b: b) +when defined(nimLegacyUnarySlice): + proc `..`*[T](b: sink T): HSlice[int, T] + {.noSideEffect, inline, magic: "DotDot", deprecated: "replace `..b` with `0..b`".} = + ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. + ## + ## .. code-block:: Nim + ## let a = [10, 20, 30, 40, 50] + ## echo a[.. 2] # @[10, 20, 30] + result = HSlice[int, T](a: 0, b: b) + when defined(hotCodeReloading): {.pragma: hcrInline, inline.} else: From 54fe44135ee447c167b4a3a2d6ec5ff7855688ea Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 20 Apr 2021 15:24:20 +0200 Subject: [PATCH 2464/4254] updated the documentation (#17796) --- compiler/ic/navigator.nim | 2 +- doc/advopt.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index cedf41579..6af2c2ac0 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## Supports the "nim check --ic:on --def --track:FILE,LINE,COL" +## Supports the "nim check --ic:on --defusages:FILE,LINE,COL" ## IDE-like features. It uses the set of .rod files to accomplish ## its task. The set must cover a complete Nim project. diff --git a/doc/advopt.txt b/doc/advopt.txt index c7b63d50f..bfc381cff 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -14,8 +14,8 @@ Advanced commands: module dependency graph //dump dump all defined conditionals and search paths see also: --dump.format:json (useful with: `| jq`) - //check checks the project for syntax and semantic - (can be combined with --track and --defusages) + //check checks the project for syntax and semantics + (can be combined with --defusages) Runtime checks (see -x): --objChecks:on|off turn obj conversion checks on|off @@ -28,8 +28,8 @@ Runtime checks (see -x): --infChecks:on|off turn Inf checks on|off Advanced options: - --track:FILE,LINE,COL set the tracking position for (--defusages) - --defusages find the definition and all usages of a symbol + --defusages:FILE,LINE,COL + find the definition and all usages of a symbol -o:FILE, --out:FILE set the output filename --outdir:DIR set the path where the output file will be written --usenimcache will use `outdir=$$nimcache`, whichever it resolves From c776498170a2a08a67b1317d8965482cf266a733 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 20 Apr 2021 21:39:58 +0800 Subject: [PATCH 2465/4254] close #9691 and close #10913('spawn'ed function cannot have a 'typed' or 'untyped' parameter) (#17775) --- compiler/spawn.nim | 12 +++++++++++- tests/parallel/t10913.nim | 20 ++++++++++++++++++++ tests/parallel/t9691.nim | 9 +++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/parallel/t10913.nim create mode 100644 tests/parallel/t9691.nim diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 1635f9f83..205197eaf 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -192,6 +192,11 @@ proc createCastExpr(argsParam: PSym; objType: PType; idgen: IdGenerator): PNode result.typ = newType(tyPtr, nextTypeId idgen, objType.owner) result.typ.rawAddSon(objType) +template checkMagicProcs(g: ModuleGraph, n: PNode, formal: PNode) = + if (formal.typ.kind == tyVarargs and formal.typ[0].kind in {tyTyped, tyUntyped}) or + formal.typ.kind in {tyTyped, tyUntyped}: + localError(g.config, n.info, "'spawn'ed function cannot have a 'typed' or 'untyped' parameter") + proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; idgen: IdGenerator; owner: PSym; scratchObj: PSym, castExpr, call, @@ -205,6 +210,9 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; if i < formals.len: if formals[i].typ.kind in {tyVar, tyLent}: localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") + + checkMagicProcs(g, n[i], formals[i]) + if formals[i].typ.kind in {tyTypeDesc, tyStatic}: continue #elif containsTyRef(argType): @@ -233,6 +241,9 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; let n = n[i] if i < formals.len and formals[i].typ.kind in {tyStatic, tyTypeDesc}: continue + + checkMagicProcs(g, n, formals[i]) + let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ, abstractInst) #if containsTyRef(argType): @@ -420,4 +431,3 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp wrapperProc.newSymNode, genAddrOf(scratchObj.newSymNode, idgen), nil, spawnExpr) if spawnKind == srFlowVar: result.add fvField - diff --git a/tests/parallel/t10913.nim b/tests/parallel/t10913.nim new file mode 100644 index 000000000..d8459ecd0 --- /dev/null +++ b/tests/parallel/t10913.nim @@ -0,0 +1,20 @@ +discard """ + matrix: "--threads:on" + errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" +""" + +# bug #10913 + +import threadpool + +proc useParallel*[T](unused: T) = + # use a generic T here to show the problem. + {.push experimental: "parallel".} + parallel: + for i in 0..4: + spawn echo "echo in parallel" + sync() + + {.pop.} + +useParallel(1) diff --git a/tests/parallel/t9691.nim b/tests/parallel/t9691.nim new file mode 100644 index 000000000..bbf2b1bc7 --- /dev/null +++ b/tests/parallel/t9691.nim @@ -0,0 +1,9 @@ +discard """ + matrix: "--threads:on" + errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" +""" + +# bug #9691 + +import threadpool +spawn echo() From 0b116310bfb691755481293e8f9af11190fe0999 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 20 Apr 2021 16:30:17 +0200 Subject: [PATCH 2466/4254] unit separator (#17730) * use the ASCII Unit Separator so that error messages can be handled precisely by the tooling * updated testament --- compiler/main.nim | 4 +-- compiler/msgs.nim | 61 ++++++++++++++++++-------------- compiler/vm.nim | 10 +++--- testament/important_packages.nim | 2 +- testament/specs.nim | 2 +- testament/testament.nim | 7 ++++ tests/misc/trunner.nim | 4 +-- tests/osproc/treadlines.nim | 4 +-- 8 files changed, 55 insertions(+), 39 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 6eb830164..d66a5f329 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -335,8 +335,8 @@ proc mainCommand*(graph: ModuleGraph) = msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook}) else: msgWriteln(conf, "-- list of currently defined symbols --", - {msgStdout, msgSkipHook}) - for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook}) + {msgStdout, msgSkipHook, msgNoUnitSep}) + for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook, msgNoUnitSep}) msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook}) for it in conf.searchPaths: msgWriteln(conf, it.string) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 39b10d7df..30421fe6a 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -241,12 +241,13 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string = template toFullPathConsiderDirty*(conf: ConfigRef; info: TLineInfo): string = string toFullPathConsiderDirty(conf, info.fileIndex) -type FilenameOption* = enum - foAbs # absolute path, e.g.: /pathto/bar/foo.nim - foRelProject # relative to project path, e.g.: ../foo.nim - foMagicSauce # magic sauce, shortest of (foAbs, foRelProject) - foName # lastPathPart, e.g.: foo.nim - foStacktrace # if optExcessiveStackTrace: foAbs else: foName +type + FilenameOption* = enum + foAbs # absolute path, e.g.: /pathto/bar/foo.nim + foRelProject # relative to project path, e.g.: ../foo.nim + foMagicSauce # magic sauce, shortest of (foAbs, foRelProject) + foName # lastPathPart, e.g.: foo.nim + foStacktrace # if optExcessiveStackTrace: foAbs else: foName proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption): string = case opt @@ -295,10 +296,14 @@ proc `??`* (conf: ConfigRef; info: TLineInfo, filename: string): bool = # only for debugging purposes result = filename in toFilename(conf, info) +const + UnitSep = "\31" + type MsgFlag* = enum ## flags altering msgWriteln behavior msgStdout, ## force writing to stdout, even stderr is default msgSkipHook ## skip message hook even if it is present + msgNoUnitSep ## the message is a complete "paragraph". MsgFlags* = set[MsgFlag] proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = @@ -310,17 +315,20 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## This is used for 'nim dump' etc. where we don't have nimsuggest ## support. #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return + let sep = if msgNoUnitSep notin flags: UnitSep else: "" if not isNil(conf.writelnHook) and msgSkipHook notin flags: - conf.writelnHook(s) + conf.writelnHook(s & sep) elif optStdout in conf.globalOptions or msgStdout in flags: if eStdOut in conf.m.errorOutputs: flushDot(conf) - writeLine(stdout, s) + write stdout, s + writeLine(stdout, sep) flushFile(stdout) else: if eStdErr in conf.m.errorOutputs: flushDot(conf) - writeLine(stderr, s) + write stderr, s + writeLine(stderr, sep) # On Windows stderr is fully-buffered when piped, regardless of C std. when defined(windows): flushFile(stderr) @@ -366,7 +374,7 @@ proc msgWrite(conf: ConfigRef; s: string) = flushFile(stdOrr) conf.lastMsgWasDot.incl stdOrr.toStdOrrKind() # subsequent writes need `flushDot` -template styledMsgWriteln*(args: varargs[typed]) = +template styledMsgWriteln(args: varargs[typed]) = if not isNil(conf.writelnHook): callIgnoringStyle(callWritelnHook, nil, args) elif optStdout in conf.globalOptions: @@ -407,7 +415,7 @@ proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} = styledMsgWriteln(fgRed, """ No stack traceback available To create a stacktrace, rerun compilation with './koch temp $1 ', see $2 for details""" % - [conf.command, "intern.html#debugging-the-compiler".createDocLink]) + [conf.command, "intern.html#debugging-the-compiler".createDocLink], UnitSep) quit 1 proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = @@ -444,10 +452,11 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = conf.structuredErrorHook(conf, context.info, instantiationFrom, Severity.Hint) else: - let message = if context.detail == "": - instantiationFrom - else: - instantiationOfFrom.format(context.detail) + let message = + if context.detail == "": + instantiationFrom + else: + instantiationOfFrom.format(context.detail) styledMsgWriteln(styleBright, conf.toFileLineCol(context.info), " ", resetStyle, message) info = context.info @@ -479,11 +488,12 @@ proc sourceLine*(conf: ConfigRef; i: TLineInfo): string = result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1] -proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) = - const indent = " " - msgWriteln(conf, indent & $sourceLine(conf, info)) - if info.col >= 0: - msgWriteln(conf, indent & spaces(info.col) & '^') +proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string = + if conf.hasHint(hintSource) and info != unknownLineInfo: + const indent = " " + result = "\n" & indent & $sourceLine(conf, info) + if info.col >= 0: + result.add "\n" & indent & spaces(info.col) & '^' proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string = let title = case msg @@ -545,14 +555,13 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, if msg == hintProcessing: msgWrite(conf, ".") else: - styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg) - if conf.hasHint(hintSource) and info != unknownLineInfo: - conf.writeSurroundingSrc(info) + styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg, + resetStyle, conf.getSurroundingSrc(info), UnitSep) if hintMsgOrigin in conf.mainPackageNotes: styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, KindFormat % $hintMsgOrigin, - resetStyle) + resetStyle, UnitSep) handleError(conf, msg, eh, s) template rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = @@ -632,8 +641,8 @@ proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = result = conf.m.fileInfos[i.fileIndex.int32].quotedName template listMsg(title, r) = - msgWriteln(conf, title) - for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", $a]) + msgWriteln(conf, title, {msgNoUnitSep}) + for a in r: msgWriteln(conf, " [$1] $2" % [if a in conf.notes: "x" else: " ", $a], {msgNoUnitSep}) proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax) proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax) diff --git a/compiler/vm.nim b/compiler/vm.nim index d588067c7..7a231a482 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -37,7 +37,7 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = while x != nil: inc calls x = x.next - msgWriteln(c.config, $calls & " calls omitted\n") + msgWriteln(c.config, $calls & " calls omitted\n", {msgNoUnitSep}) return stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1) var info = c.debug[pc] @@ -59,12 +59,12 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = if x.prc != nil: for k in 1..max(1, 25-s.len): s.add(' ') s.add(x.prc.name.s) - msgWriteln(c.config, s) + msgWriteln(c.config, s, {msgNoUnitSep}) proc stackTraceImpl(c: PCtx, tos: PStackFrame, pc: int, msg: string, lineInfo: TLineInfo, infoOrigin: InstantiationInfo) {.noinline.} = # noinline to avoid code bloat - msgWriteln(c.config, "stack trace: (most recent call last)") + msgWriteln(c.config, "stack trace: (most recent call last)", {msgNoUnitSep}) stackTraceAux(c, tos, pc) let action = if c.mode == emRepl: doRaise else: doNothing # XXX test if we want 'globalError' for every mode @@ -470,7 +470,7 @@ template handleJmpBack() {.dirty.} = if allowInfiniteLoops in c.features: c.loopIterations = c.config.maxLoopIterationsVM else: - msgWriteln(c.config, "stack trace: (most recent call last)") + msgWriteln(c.config, "stack trace: (most recent call last)", {msgNoUnitSep}) stackTraceAux(c, tos, pc) globalError(c.config, c.debug[pc], errTooManyIterations % $c.config.maxLoopIterationsVM) dec(c.loopIterations) @@ -1163,7 +1163,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = stackTrace(c, tos, pc, "node is not a proc symbol") of opcEcho: let rb = instr.regB - template fn(s) = msgWriteln(c.config, s, {msgStdout}) + template fn(s) = msgWriteln(c.config, s, {msgStdout, msgNoUnitSep}) if rb == 1: fn(regs[ra].node.strVal) else: var outp = "" diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 28d7dc367..ecae42811 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -74,7 +74,7 @@ pkg "gnuplot", "nim c gnuplot.nim" pkg "hts", "nim c -o:htss src/hts.nim" pkg "httpauth" pkg "illwill", "nimble examples" -pkg "inim" +pkg "inim", allowFailure=true pkg "itertools", "nim doc src/itertools.nim" pkg "iterutils" pkg "karax", "nim c -r tests/tester.nim" diff --git a/testament/specs.nim b/testament/specs.nim index b5e6de7c2..043f14ed3 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -202,7 +202,7 @@ proc extractSpec(filename: string; spec: var TSpec): string = # look for """ only in the first section if a >= 0 and b > a and a < 40: - result = s.substr(a+3, b-1).replace("'''", tripleQuote) + result = s.substr(a+3, b-1).multiReplace({"'''": tripleQuote, "\\31": "\31"}) else: #echo "warning: file does not contain spec: " & filename result = "" diff --git a/testament/testament.nim b/testament/testament.nim index f2a8e9055..b79b86e51 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -18,6 +18,11 @@ import compiler/nodejs import lib/stdtest/testutils from lib/stdtest/specialpaths import splitTestFile +proc trimUnitSep(x: var string) = + let L = x.len + if L > 0 and x[^1] == '\31': + setLen x, L-1 + var useColors = true var backendLogging = true var simulate = false @@ -172,6 +177,7 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.nimout = "" while true: if outp.readLine(x): + trimUnitSep x result.nimout.add(x & '\n') if x =~ pegOfInterest: # `err` should contain the last error/warning message @@ -196,6 +202,7 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.msg = matches[0] elif suc.isSuccess: result.err = reSuccess + trimUnitSep result.msg proc callCCompiler(cmdTemplate, filename, options: string, target: TTarget): TSpec = diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 1895eeb97..df9ee9a48 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -235,7 +235,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines var expected = "" for a in files: let b = dir / a - expected.add &"Hint: used config file '{b}' [Conf]\n" + expected.add &"Hint: used config file '{b}' [Conf]\31\n" doAssert outp.endsWith expected, outp & "\n" & expected block: # mfoo2.customext @@ -243,7 +243,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines let cmd = fmt"{nim} e --hint:conf {filename}" let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) doAssert exitCode == 0 - var expected = &"Hint: used config file '{filename}' [Conf]\n" + var expected = &"Hint: used config file '{filename}' [Conf]\31\n" doAssert outp.endsWith "123" & "\n" & expected diff --git a/tests/osproc/treadlines.nim b/tests/osproc/treadlines.nim index 3a8303321..436dd7a10 100644 --- a/tests/osproc/treadlines.nim +++ b/tests/osproc/treadlines.nim @@ -1,6 +1,6 @@ discard """ - output: '''Error: cannot open 'a.nim' -Error: cannot open 'b.nim' + output: '''Error: cannot open 'a.nim'\31 +Error: cannot open 'b.nim'\31 ''' targets: "c" """ From eb221dcc27b7f8f11ec34046e3165508acdf8beb Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 21 Apr 2021 01:00:44 +0800 Subject: [PATCH 2467/4254] [std/deques] move data instead of copy + destroy (#17800) --- lib/pure/collections/deques.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index d2d53d993..582bb02a7 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -379,8 +379,7 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = emptyCheck(deq) dec deq.count - result = deq.data[deq.head] - destroy(deq.data[deq.head]) + result = move deq.data[deq.head] deq.head = (deq.head + 1) and deq.mask proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = @@ -398,8 +397,7 @@ proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = emptyCheck(deq) dec deq.count deq.tail = (deq.tail - 1) and deq.mask - result = deq.data[deq.tail] - destroy(deq.data[deq.tail]) + result = move deq.data[deq.tail] proc clear*[T](deq: var Deque[T]) {.inline.} = ## Resets the deque so that it is empty. From 603af22b7ca46ac566f8c7c15402028f3f976a4e Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 21 Apr 2021 11:05:16 +0800 Subject: [PATCH 2468/4254] [std/tasks]add gcsafe pragmas (#17799) * [std/tasks]add gcsafe pragmas * Update tasks.nim --- lib/std/tasks.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index aed36f985..97c4df3f7 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -59,7 +59,7 @@ when compileOption("threads"): type Task* = object ## `Task` contains the callback and its arguments. - callback: proc (args: pointer) {.nimcall.} + callback: proc (args: pointer) {.nimcall, gcsafe.} args: pointer destroy: proc (args: pointer) {.nimcall.} @@ -73,7 +73,7 @@ proc `=destroy`*(t: var Task) {.inline.} = t.destroy(t.args) c_free(t.args) -proc invoke*(task: Task) {.inline.} = +proc invoke*(task: Task) {.inline, gcsafe.} = ## Invokes the `task`. assert task.callback != nil task.callback(task.args) @@ -215,7 +215,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC result = quote do: `stmtList` - proc `funcName`(args: pointer) {.nimcall.} = + proc `funcName`(args: pointer) {.gcsafe, nimcall.} = let `objTemp` = cast[ptr `scratchObjType`](args) `functionStmtList` @@ -229,7 +229,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC let funcName = genSym(nskProc, e[0].strVal) result = quote do: - proc `funcName`(args: pointer) {.nimcall.} = + proc `funcName`(args: pointer) {.gcsafe, nimcall.} = `funcCall` Task(callback: `funcName`, args: nil) From 8de053d8708d3547edeee8c4846b355a557f1d18 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Apr 2021 22:00:45 -0700 Subject: [PATCH 2469/4254] fix `hintMsgOrigin` regression + simplify msgs code (#17805) --- compiler/msgs.nim | 5 +---- compiler/semdata.nim | 18 +++++++----------- compiler/semexprs.nim | 2 +- compiler/semmagic.nim | 8 ++++---- compiler/semobjconstr.nim | 13 ++++++------- compiler/semstmts.nim | 8 +++----- 6 files changed, 22 insertions(+), 32 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 30421fe6a..89949ef17 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -14,7 +14,7 @@ import std/private/miscdollars import strutils2 type InstantiationInfo* = typeof(instantiationInfo()) -template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) +template instLoc*(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) template toStdOrrKind(stdOrr): untyped = if stdOrr == stdout: stdOrrStdout else: stdOrrStderr @@ -600,9 +600,6 @@ template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") template localError*(conf: ConfigRef; info: TLineInfo, arg: string) = liMessage(conf, info, errGenerated, arg, doNothing, instLoc()) -template localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) = - liMessage(conf, info, errGenerated, format % params, doNothing, instLoc()) - template message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(conf, info, msg, arg, doNothing, instLoc()) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 354d4587d..95278893a 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -501,18 +501,14 @@ proc errorNode*(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) result.typ = errorType(c) -proc localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode = - localError(c.config, info, msg, arg) - result = errorNode(c, n) +template localErrorNode*(c: PContext, n: PNode, arg: string, info: TLineInfo, kind: TMsgKind = errGenerated): PNode = + liMessage(c.config, info, kind, arg, doNothing, instLoc()) + errorNode(c, n) -proc localErrorNode*(c: PContext, n: PNode, info: TLineInfo, arg: string): PNode = - localErrorNode(c, n, info, errGenerated, arg) - -proc localErrorNode*(c: PContext, n: PNode, msg: TMsgKind, arg: string): PNode = - localErrorNode(c, n, n.info, msg, arg) - -proc localErrorNode*(c: PContext, n: PNode, arg: string): PNode = - localErrorNode(c, n, n.info, errGenerated, arg) +template localErrorNode*(c: PContext, n: PNode, arg: string, kind: TMsgKind = errGenerated): PNode = + let n2 = n + liMessage(c.config, n2.info, kind, arg, doNothing, instLoc()) + errorNode(c, n2) proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 353831736..defceb291 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2620,7 +2620,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # check if either everything or nothing is tyTypeDesc for i in 1.. high(TSymChoiceRule).int: - return localErrorNode(c, n, n[2].info, errConstExprExpected) + return localErrorNode(c, n, errConstExprExpected, n[2].info) let id = newIdentNode(getIdent(c.cache, sl.strVal), n.info) let s = qualifiedLookUp(c, id, {checkUndeclared}) @@ -251,10 +251,10 @@ proc semBindSym(c: PContext, n: PNode): PNode = proc opBindSym(c: PContext, scope: PScope, n: PNode, isMixin: int, info: PNode): PNode = if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit, nkIdent}: - return localErrorNode(c, n, info.info, errStringOrIdentNodeExpected) + return localErrorNode(c, n, errStringOrIdentNodeExpected, info.info) if isMixin < 0 or isMixin > high(TSymChoiceRule).int: - return localErrorNode(c, n, info.info, errConstExprExpected) + return localErrorNode(c, n, errConstExprExpected, info.info) let id = if n.kind == nkIdent: n else: newIdentNode(getIdent(c.cache, n.strVal), info.info) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 63b4b9a75..01d5a8b28 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -210,7 +210,7 @@ proc semConstructFields(c: PContext, n: PNode, localError(c.config, constrCtx.initExpr.info, "a case selecting discriminator '$1' with value '$2' " & "appears in the object construction, but the field(s) $3 " & - "are in conflict with this value.", + "are in conflict with this value." % [discriminator.sym.name.s, discriminatorVal.renderTree, fields]) template valuesInConflictError(valsDiff) = @@ -365,11 +365,10 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = assert constrCtx.missingFields.len > 0 localError(c.config, info, "The $1 type doesn't have a default value. The following fields must " & - "be initialized: $2.", - [typeToString(t), listSymbolNames(constrCtx.missingFields)]) + "be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)]) elif objType.kind == tyDistinct: localError(c.config, info, - "The $1 distinct type doesn't have a default value.", [typeToString(t)]) + "The $1 distinct type doesn't have a default value." % typeToString(t)) else: assert false, "Must not enter here." @@ -379,7 +378,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = for child in n: result.add child if t == nil: - return localErrorNode(c, result, errGenerated, "object constructor needs an object type") + return localErrorNode(c, result, "object constructor needs an object type") t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned}) if t.kind == tyRef: @@ -390,7 +389,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # multiple times as long as they don't have closures. result.typ.flags.incl tfHasOwned if t.kind != tyObject: - return localErrorNode(c, result, errGenerated, "object constructor needs an object type") + return localErrorNode(c, result, "object constructor needs an object type") # Check if the object is fully initialized by recursively testing each # field (if this is a case object, initialized fields in two different @@ -404,7 +403,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = if constrCtx.missingFields.len > 0: hasError = true localError(c.config, result.info, - "The $1 type requires the following fields to be initialized: $2.", + "The $1 type requires the following fields to be initialized: $2." % [t.sym.name.s, listSymbolNames(constrCtx.missingFields)]) # Since we were traversing the object fields, it's possible that diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a10047187..22e4295fa 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -725,7 +725,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if n.len == 3: if n[0].kind == nkVarTuple: if n[0].len-1 != iterAfterVarLent.len: - return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables) + return localErrorNode(c, n, errWrongNumberOfVariables, n[0].info) for i in 0.. 0 and not isException(typ.lastSon): - localError(c.config, n.info, "raised object of type $1 does not inherit from Exception", - [typeToString(typ)]) + localError(c.config, n.info, "raised object of type $1 does not inherit from Exception" % typeToString(typ)) proc addGenericParamListToScope(c: PContext, n: PNode) = if n.kind != nkGenericParams: illFormedAst(n, c.config) @@ -2201,8 +2200,7 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) = if not sameType(res.typ, typ.base): localError(c.config, n.info, "cannot infer the concept parameter '%s', due to a type mismatch. " & - "attempt to equate '%s' and '%s'.", - [inferred.renderTree, $res.typ, $typ.base]) + "attempt to equate '%s' and '%s'." % [inferred.renderTree, $res.typ, $typ.base]) typ.n = res proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = From 7bce1f8578eafffacd599401e709de279528e68b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Apr 2021 22:33:56 -0700 Subject: [PATCH 2470/4254] close #13373 document `(ref Foo)(a: 1)` (#17804) --- doc/manual.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index ea444a0ac..15242cf7c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1702,7 +1702,17 @@ has the syntax `T(fieldA: valueA, fieldB: valueB, ...)` where `T` is an `object` type or a `ref object` type: .. code-block:: nim - var student = Student(name: "Anton", age: 5, id: 3) + type + Student = object + name: string + age: int + PStudent = ref Student + var a1 = Student(name: "Anton", age: 5) + var a2 = PStudent(name: "Anton", age: 5) + # this also works directly: + var a3 = (ref Student)(name: "Anton", age: 5) + # not all fields need to be mentioned, and they can be mentioned out of order: + var a4 = Student(age: 5) Note that, unlike tuples, objects require the field names along with their values. For a `ref object` type `system.new` is invoked implicitly. From a9b62de8956af50424767408bbe30631c63b331b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 21 Apr 2021 07:41:33 +0200 Subject: [PATCH 2471/4254] CIs: attempt to use csources_v1 (#16282) * CIs: attempt to use csources_v1 * also updated the BSDs * also updated azure pipelines * std modules should not itself use the 'std/' import dir... * compiler has to be careful with std/ for v1 booting --- .builds/freebsd.yml | 2 +- .builds/openbsd_0.yml | 2 +- .builds/openbsd_1.yml | 2 +- .github/workflows/ci_docs.yml | 4 +- azure-pipelines.yml | 2 +- ci/build.bat | 2 +- ci/build.sh | 2 +- ci/nsis_build.bat | 2 +- compiler/extccomp.nim | 2 +- compiler/ic/cbackend.nim | 6 +-- compiler/ic/dce.nim | 2 +- compiler/ic/ic.nim | 6 +-- compiler/ic/integrity.nim | 2 +- compiler/ic/navigator.nim | 2 +- compiler/ic/packed_ast.nim | 2 +- compiler/int128.nim | 4 +- compiler/jsgen.nim | 2 +- compiler/lookups.nim | 2 +- compiler/modulegraphs.nim | 2 +- compiler/nilcheck.nim | 2 +- compiler/nim.nim | 2 +- compiler/nimpaths.nim | 2 +- compiler/rodutils.nim | 2 +- compiler/semdata.nim | 2 +- compiler/semtypes.nim | 2 +- compiler/vmdef.nim | 2 +- compiler/vmgen.nim | 2 +- compiler/vmops.nim | 16 +++---- compiler/wordrecg.nim | 80 ++++++++++++++++----------------- lib/pure/cgi.nim | 2 +- lib/pure/collections/deques.nim | 2 +- lib/pure/collections/tables.nim | 2 +- lib/pure/complex.nim | 2 +- lib/pure/cookies.nim | 6 +-- lib/pure/distros.nim | 6 +-- lib/pure/json.nim | 7 ++- lib/pure/marshal.nim | 2 +- lib/pure/math.nim | 2 +- lib/pure/oids.nim | 2 +- lib/pure/options.nim | 2 +- lib/pure/os.nim | 8 ++-- lib/pure/random.nim | 4 +- lib/pure/rationals.nim | 2 +- lib/pure/ropes.nim | 2 +- lib/pure/stats.nim | 2 +- lib/pure/strformat.nim | 4 +- lib/pure/sugar.nim | 2 +- lib/pure/typetraits.nim | 2 +- lib/pure/unittest.nim | 8 ++-- lib/pure/uri.nim | 2 +- lib/std/enumutils.nim | 8 ++-- lib/std/jsonutils.nim | 18 ++++---- lib/std/monotimes.nim | 4 +- lib/std/private/globs.nim | 2 +- lib/std/setutils.nim | 2 +- lib/std/sha1.nim | 4 +- lib/std/sysrand.nim | 10 ++--- lib/std/wrapnils.nim | 4 +- 58 files changed, 142 insertions(+), 143 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 6898a80fd..443be798a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -15,7 +15,7 @@ environment: tasks: - setup: | cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources.git + git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources gmake -C csources -j $(sysctl -n hw.ncpu) bin/nim c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv diff --git a/.builds/openbsd_0.yml b/.builds/openbsd_0.yml index 146ad8165..c09f0f08d 100644 --- a/.builds/openbsd_0.yml +++ b/.builds/openbsd_0.yml @@ -18,7 +18,7 @@ environment: tasks: - setup: | cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources.git + git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources gmake -C csources -j $(sysctl -n hw.ncpuonline) bin/nim c koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml index ad3734008..ffe449733 100644 --- a/.builds/openbsd_1.yml +++ b/.builds/openbsd_1.yml @@ -18,7 +18,7 @@ environment: tasks: - setup: | cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources.git + git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources gmake -C csources -j $(sysctl -n hw.ncpuonline) bin/nim c koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 982efe610..c9036d1d4 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -85,7 +85,7 @@ jobs: id: csources-version shell: bash run: | - sha=$(git ls-remote https://github.com/nim-lang/csources master | cut -f 1) + sha=$(git ls-remote https://github.com/nim-lang/csources_v1 master | cut -f 1) echo "::set-output name=sha::$sha" - name: 'Get prebuilt csources from cache' @@ -99,7 +99,7 @@ jobs: if: steps.csources-cache.outputs.cache-hit != 'true' uses: actions/checkout@v2 with: - repository: nim-lang/csources + repository: nim-lang/csources_v1 path: csources - name: 'Build 1-stage compiler from csources' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 55bad609e..5c244648d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -67,7 +67,7 @@ jobs: echo $commitMsg | grep -v '\[skip ci\]' # fails if [skip ci] not in commit msg displayName: 'Check whether to skip CI' - - bash: git clone --depth 1 https://github.com/nim-lang/csources + - bash: git clone --depth 1 https://github.com/nim-lang/csources_v1 csources displayName: 'Checkout Nim csources' - task: NodeTool@0 diff --git a/ci/build.bat b/ci/build.bat index cdce8d3d2..2227168e5 100644 --- a/ci/build.bat +++ b/ci/build.bat @@ -2,7 +2,7 @@ REM Some debug info echo "Running on %CI_RUNNER_ID% (%CI_RUNNER_DESCRIPTION%) with tags %CI_RUNNER_TAGS%." gcc -v -git clone --depth 1 https://github.com/nim-lang/csources.git +git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources cd csources call build64.bat cd .. diff --git a/ci/build.sh b/ci/build.sh index 6321fffba..a89d011ed 100644 --- a/ci/build.sh +++ b/ci/build.sh @@ -1,7 +1,7 @@ sh ci/deps.sh # Build from C sources. -git clone --depth 1 https://github.com/nim-lang/csources.git +git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources cd csources sh build.sh cd .. diff --git a/ci/nsis_build.bat b/ci/nsis_build.bat index 4806810d7..12aff1b72 100644 --- a/ci/nsis_build.bat +++ b/ci/nsis_build.bat @@ -25,7 +25,7 @@ Rem Build csources koch csources -d:release || exit /b rem Grab C sources and nimsuggest -git clone --depth 1 https://github.com/nim-lang/csources.git +git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources set PATH=%CD%\bin;%PATH% diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 8d1432aa8..71a20fc47 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -14,7 +14,7 @@ import ropes, platform, condsyms, options, msgs, lineinfos, pathutils -import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json] +import os, strutils, osproc, std/sha1, streams, sequtils, times, strtabs, json type TInfoCCProp* = enum # properties of the C compiler: diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index c7e5c7266..f5811cb3b 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -18,8 +18,8 @@ ## also doing cross-module dependency tracking and DCE that we don't need ## anymore. DCE is now done as prepass over the entire packed module graph. -import std/[packedsets, algorithm, tables] - # std/intsets would give `UnusedImport`, pending https://github.com/nim-lang/Nim/issues/14246 +import std/packedsets, algorithm, tables + import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen, pathutils, extccomp, msgs] @@ -70,7 +70,7 @@ proc addFileToLink(config: ConfigRef; m: PSym) = addFileToCompile(config, cf) when defined(debugDce): - import std / [os, packedsets] + import os, std/packedsets proc storeAliveSymsImpl(asymFile: AbsoluteFile; s: seq[int32]) = var f = rodfiles.create(asymFile.string) diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index 48ed414e2..350b17d1b 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -9,7 +9,7 @@ ## Dead code elimination (=DCE) for IC. -import std / [intsets, tables] +import intsets, tables import ".." / [ast, options, lineinfos, types] import packed_ast, ic, bitabs diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index d9a8756f1..6530cb6c2 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -7,12 +7,12 @@ # distribution, for details about the copyright. # -import std / [hashes, tables, intsets, sha1] +import hashes, tables, intsets, std/sha1 import packed_ast, bitabs, rodfiles import ".." / [ast, idents, lineinfos, msgs, ropes, options, pathutils, condsyms] #import ".." / [renderer, astalgo] -from std / os import removeFile, isAbsolute +from os import removeFile, isAbsolute type PackedConfig* = object @@ -143,7 +143,7 @@ const debugConfigDiff = defined(debugConfigDiff) when debugConfigDiff: - import std / [hashes, tables, intsets, sha1, strutils, sets] + import hashes, tables, intsets, sha1, strutils, sets proc configIdentical(m: PackedModule; config: ConfigRef): bool = result = m.definedSymbols == definedSymbolsAsString(config) diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim index 428c344a3..ed367ef61 100644 --- a/compiler/ic/integrity.nim +++ b/compiler/ic/integrity.nim @@ -10,7 +10,7 @@ ## Integrity checking for a set of .rod files. ## The set must cover a complete Nim project. -import std / sets +import sets import ".." / [ast, modulegraphs] import packed_ast, bitabs, ic diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index 6af2c2ac0..a1a14885d 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -11,7 +11,7 @@ ## IDE-like features. It uses the set of .rod files to accomplish ## its task. The set must cover a complete Nim project. -import std / sets +import sets from os import nil from std/private/miscdollars import toLocation diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 2700c8253..6fadde17c 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -12,7 +12,7 @@ ## use this representation directly in all the transformations, ## it is superior. -import std / [hashes, tables, strtabs] +import hashes, tables, strtabs import bitabs import ".." / [ast, options] diff --git a/compiler/int128.nim b/compiler/int128.nim index 8d3cd7113..6ba7c1961 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -3,7 +3,7 @@ ## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This ## type is for that purpose. -from std/math import trunc +from math import trunc type Int128* = object @@ -378,7 +378,7 @@ proc `*`*(lhs, rhs: Int128): Int128 = proc `*=`*(a: var Int128, b: Int128) = a = a * b -import std/bitops +import bitops proc fastLog2*(a: Int128): int = if a.udata[3] != 0: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 350563d6b..e75ff182f 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -35,7 +35,7 @@ import cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, transf, injectdestructors, sourcemap -import std/[json, sets, math, tables, intsets, strutils] +import json, sets, math, tables, intsets, strutils from modulegraphs import ModuleGraph, PPassContext diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 7ceadfb96..c4f506a68 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -372,7 +372,7 @@ when false: of 'a'..'z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1)) else: result = x -import std/[editdistance, heapqueue] +import std/editdistance, heapqueue type SpellCandidate = object dist: int diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 9df66269b..c268308d2 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -11,7 +11,7 @@ ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -import std / [intsets, tables, hashes, md5] +import intsets, tables, hashes, md5 import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils import ic / [packed_ast, ic] diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index f3ec893f7..9c2d091f7 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -8,7 +8,7 @@ # import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes -import sequtils, strutils, std / sets +import sequtils, strutils, sets # IMPORTANT: notes not up to date, i'll update this comment again # diff --git a/compiler/nim.nim b/compiler/nim.nim index df06a83a9..f18238f60 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -24,7 +24,7 @@ import idents, lineinfos, cmdlinehelper, pathutils, modulegraphs -from std/browsers import openDefaultBrowser +from browsers import openDefaultBrowser from nodejs import findNodeJs when hasTinyCBackend: diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim index 71bb9a7d7..a93b488fd 100644 --- a/compiler/nimpaths.nim +++ b/compiler/nimpaths.nim @@ -17,7 +17,7 @@ interpolation variables: Unstable API ]## -import std/[os,strutils] +import os, strutils const docCss* = "$nimr/doc/nimdoc.css" diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 353992fca..e13b08e05 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -8,7 +8,7 @@ # ## Serialization utilities for the compiler. -import std/[strutils, math] +import strutils, math # bcc on windows doesn't have C99 functions when defined(windows) and defined(bcc): diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 95278893a..9a17efb1c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -9,7 +9,7 @@ ## This module contains the data structures for the semantic checking phase. -import std / tables +import tables import intsets, options, ast, astalgo, msgs, idents, renderer, diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 8be210067..c921703b0 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -10,7 +10,7 @@ # this module does the semantic checking of type declarations # included from sem.nim -import std/math +import math const errStringOrIdentNodeExpected = "string or ident node expected" diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 068ade4b0..0afb2ed6a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import std / tables +import tables import ast, idents, options, modulegraphs, lineinfos diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c60e81020..3a6004e8b 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -27,7 +27,7 @@ # solves the opcLdConst vs opcAsgnConst issue. Of course whether we need # this copy depends on the involved types. -import std / tables +import tables import strutils, ast, types, msgs, renderer, vmdef, diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 04356fc76..1d22750e7 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -9,24 +9,24 @@ # Unfortunately this cannot be a module yet: #import vmdeps, vm -from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, +from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma, lgamma when declared(math.copySign): - from std/math import copySign + from math import copySign when declared(math.signbit): - from std/math import signbit + from math import signbit -from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, +from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename, raiseOSError, osLastError -from std/md5 import getMD5 -from std/times import cpuTime -from std/hashes import hash -from std/osproc import nil +from md5 import getMD5 +from times import cpuTime +from hashes import hash +from osproc import nil from sighashes import symBodyDigest diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 827efcfa0..c3625c5f3 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -17,58 +17,58 @@ type TSpecialWord* = enum wInvalid = "", wAddr = "addr", wAnd = "and", wAs = "as", wAsm = "asm", - wBind = "bind", wBlock = "block", wBreak = "break", wCase = "case", wCast = "cast", - wConcept = "concept", wConst = "const", wContinue = "continue", wConverter = "converter", + wBind = "bind", wBlock = "block", wBreak = "break", wCase = "case", wCast = "cast", + wConcept = "concept", wConst = "const", wContinue = "continue", wConverter = "converter", wDefer = "defer", wDiscard = "discard", wDistinct = "distinct", wDiv = "div", wDo = "do", - wElif = "elif", wElse = "else", wEnd = "end", wEnum = "enum", wExcept = "except", - wExport = "export", wFinally = "finally", wFor = "for", wFrom = "from", wFunc = "func", - wIf = "if", wImport = "import", wIn = "in", wInclude = "include", wInterface = "interface", + wElif = "elif", wElse = "else", wEnd = "end", wEnum = "enum", wExcept = "except", + wExport = "export", wFinally = "finally", wFor = "for", wFrom = "from", wFunc = "func", + wIf = "if", wImport = "import", wIn = "in", wInclude = "include", wInterface = "interface", wIs = "is", wIsnot = "isnot", wIterator = "iterator", wLet = "let", wMacro = "macro", - wMethod = "method", wMixin = "mixin", wMod = "mod", wNil = "nil", wNot = "not", wNotin = "notin", - wObject = "object", wOf = "of", wOr = "or", wOut = "out", wProc = "proc", wPtr = "ptr", - wRaise = "raise", wRef = "ref", wReturn = "return", wShl = "shl", wShr = "shr", wStatic = "static", - wTemplate = "template", wTry = "try", wTuple = "tuple", wType = "type", wUsing = "using", + wMethod = "method", wMixin = "mixin", wMod = "mod", wNil = "nil", wNot = "not", wNotin = "notin", + wObject = "object", wOf = "of", wOr = "or", wOut = "out", wProc = "proc", wPtr = "ptr", + wRaise = "raise", wRef = "ref", wReturn = "return", wShl = "shl", wShr = "shr", wStatic = "static", + wTemplate = "template", wTry = "try", wTuple = "tuple", wType = "type", wUsing = "using", wVar = "var", wWhen = "when", wWhile = "while", wXor = "xor", wYield = "yield", wColon = ":", wColonColon = "::", wEquals = "=", wDot = ".", wDotDot = "..", wStar = "*", wMinus = "-", - wMagic = "magic", wThread = "thread", wFinal = "final", wProfiler = "profiler", + wMagic = "magic", wThread = "thread", wFinal = "final", wProfiler = "profiler", wMemTracker = "memtracker", wObjChecks = "objchecks", - wIntDefine = "intdefine", wStrDefine = "strdefine", wBoolDefine = "booldefine", + wIntDefine = "intdefine", wStrDefine = "strdefine", wBoolDefine = "booldefine", wCursor = "cursor", wNoalias = "noalias", - wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor", + wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor", wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp", - wCppNonPod = "cppNonPod", + wCppNonPod = "cppNonPod", wImportObjC = "importobjc", wImportCompilerProc = "importcompilerproc", - wImportc = "importc", wImportJs = "importjs", wExportc = "exportc", wExportCpp = "exportcpp", + wImportc = "importc", wImportJs = "importjs", wExportc = "exportc", wExportCpp = "exportcpp", wExportNims = "exportnims", wIncompleteStruct = "incompleteStruct", # deprecated wCompleteStruct = "completeStruct", wRequiresInit = "requiresInit", wAlign = "align", wNodecl = "nodecl", wPure = "pure", wSideEffect = "sideEffect", wHeader = "header", wNoSideEffect = "noSideEffect", wGcSafe = "gcsafe", wNoreturn = "noreturn", wNosinks = "nosinks", wMerge = "merge", wLib = "lib", wDynlib = "dynlib", - wCompilerProc = "compilerproc", wCore = "core", wProcVar = "procvar", - wBase = "base", wUsed = "used", wFatal = "fatal", wError = "error", wWarning = "warning", + wCompilerProc = "compilerproc", wCore = "core", wProcVar = "procvar", + wBase = "base", wUsed = "used", wFatal = "fatal", wError = "error", wWarning = "warning", wHint = "hint", wWarningAsError = "warningAsError", wHintAsError = "hintAsError", wLine = "line", wPush = "push", - wPop = "pop", wDefine = "define", wUndef = "undef", wLineDir = "lineDir", + wPop = "pop", wDefine = "define", wUndef = "undef", wLineDir = "lineDir", wStackTrace = "stackTrace", wLineTrace = "lineTrace", wLink = "link", wCompile = "compile", - wLinksys = "linksys", wDeprecated = "deprecated", wVarargs = "varargs", wCallconv = "callconv", - wDebugger = "debugger", wNimcall = "nimcall", wStdcall = "stdcall", wCdecl = "cdecl", + wLinksys = "linksys", wDeprecated = "deprecated", wVarargs = "varargs", wCallconv = "callconv", + wDebugger = "debugger", wNimcall = "nimcall", wStdcall = "stdcall", wCdecl = "cdecl", wSafecall = "safecall", wSyscall = "syscall", wInline = "inline", wNoInline = "noinline", wFastcall = "fastcall", wThiscall = "thiscall", wClosure = "closure", wNoconv = "noconv", - wOn = "on", wOff = "off", wChecks = "checks", wRangeChecks = "rangeChecks", + wOn = "on", wOff = "off", wChecks = "checks", wRangeChecks = "rangeChecks", wBoundChecks = "boundChecks", wOverflowChecks = "overflowChecks", wNilChecks = "nilChecks", - wFloatChecks = "floatChecks", wNanChecks = "nanChecks", wInfChecks = "infChecks", + wFloatChecks = "floatChecks", wNanChecks = "nanChecks", wInfChecks = "infChecks", wStyleChecks = "styleChecks", wStaticBoundchecks = "staticBoundChecks", wNonReloadable = "nonReloadable", wExecuteOnReload = "executeOnReload", - wAssertions = "assertions", wPatterns = "patterns", wTrMacros = "trmacros", + wAssertions = "assertions", wPatterns = "patterns", wTrMacros = "trmacros", wSinkInference = "sinkInference", wWarnings = "warnings", - wHints = "hints", wOptimization = "optimization", wRaises = "raises", + wHints = "hints", wOptimization = "optimization", wRaises = "raises", wWrites = "writes", wReads = "reads", wSize = "size", wEffects = "effects", wTags = "tags", wRequires = "requires", wEnsures = "ensures", wInvariant = "invariant", wAssume = "assume", wAssert = "assert", @@ -76,34 +76,34 @@ type wSafecode = "safecode", wPackage = "package", wNoForward = "noforward", wReorder = "reorder", wNoRewrite = "norewrite", wNoDestroy = "nodestroy", wPragma = "pragma", wCompileTime = "compileTime", wNoInit = "noinit", wPassc = "passc", wPassl = "passl", - wLocalPassc = "localPassC", wBorrow = "borrow", wDiscardable = "discardable", + wLocalPassc = "localPassC", wBorrow = "borrow", wDiscardable = "discardable", wFieldChecks = "fieldChecks", wSubsChar = "subschar", wAcyclic = "acyclic", wShallow = "shallow", wUnroll = "unroll", wLinearScanEnd = "linearScanEnd", wComputedGoto = "computedGoto", wInjectStmt = "injectStmt", wExperimental = "experimental", - wWrite = "write", wGensym = "gensym", wInject = "inject", wDirty = "dirty", + wWrite = "write", wGensym = "gensym", wInject = "inject", wDirty = "dirty", wInheritable = "inheritable", wThreadVar = "threadvar", wEmit = "emit", wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic", wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked", wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain", wLiftLocals = "liftlocals", - wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", - wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default", - wDelete = "delete", wDouble = "double", wDynamic_cast = "dynamic_cast", + wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", + wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default", + wDelete = "delete", wDouble = "double", wDynamic_cast = "dynamic_cast", wExplicit = "explicit", wExtern = "extern", wFalse = "false", wFloat = "float", - wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable", - wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private", - wProtected = "protected", wPublic = "public", wRegister = "register", - wReinterpret_cast = "reinterpret_cast", wRestrict = "restrict", wShort = "short", - wSigned = "signed", wSizeof = "sizeof", wStatic_cast = "static_cast", wStruct = "struct", - wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef", + wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable", + wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private", + wProtected = "protected", wPublic = "public", wRegister = "register", + wReinterpret_cast = "reinterpret_cast", wRestrict = "restrict", wShort = "short", + wSigned = "signed", wSizeof = "sizeof", wStatic_cast = "static_cast", wStruct = "struct", + wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef", wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename", - wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual", + wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual", wVoid = "void", wVolatile = "volatile", wWchar_t = "wchar_t", - wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype", + wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype", wNullptr = "nullptr", wNoexcept = "noexcept", - wThread_local = "thread_local", wStatic_assert = "static_assert", + wThread_local = "thread_local", wStatic_assert = "static_assert", wChar16_t = "char16_t", wChar32_t = "char32_t", wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr", @@ -134,14 +134,14 @@ const enumUtilsExist = compiles: when enumUtilsExist: from std/enumutils import genEnumCaseStmt from strutils import normalize - proc findStr*[T: enum](a, b: static[T], s: string, default: T): T = + proc findStr*[T: enum](a, b: static[T], s: string, default: T): T = genEnumCaseStmt(T, s, default, ord(a), ord(b), normalize) else: from strutils import cmpIgnoreStyle - proc findStr*[T: enum](a, b: static[T], s: string, default: T): T {.deprecated.} = + proc findStr*[T: enum](a, b: static[T], s: string, default: T): T {.deprecated.} = # used for compiler bootstrapping only for i in a..b: if cmpIgnoreStyle($i, s) == 0: return i - result = default \ No newline at end of file + result = default \ No newline at end of file diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index fd5089dbb..566482b21 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -29,7 +29,7 @@ ## writeLine(stdout, "your password: " & myData["password"]) ## writeLine(stdout, "") -import std/[strutils, os, strtabs, cookies, uri] +import strutils, os, strtabs, cookies, uri export uri.encodeUrl, uri.decodeUrl diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 582bb02a7..c378dff1d 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -50,7 +50,7 @@ runnableExamples: import std/private/since -import std/math +import math type Deque*[T] = object diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 9387807c0..8739b60a3 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -196,7 +196,7 @@ runnableExamples: import std/private/since -import std/[hashes, math, algorithm] +import hashes, math, algorithm type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index b9371c1e1..5492028a8 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -36,7 +36,7 @@ runnableExamples: {.push checks: off, line_dir: off, stack_trace: off, debugger: off.} # the user does not want to trace a part of the standard library! -import std/math +import math type Complex*[T: SomeFloat] = object diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 8d9cc0c95..25d701eb4 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -9,7 +9,7 @@ ## This module implements helper procs for parsing Cookies. -import std/[strtabs, times, options] +import strtabs, times, options type @@ -25,7 +25,7 @@ proc parseCookies*(s: string): StringTableRef = ## "Set-Cookie" header set by servers. runnableExamples: import std/strtabs - let cookieJar = parseCookies("a=1; foo=bar") + let cookieJar = parseCookies("a=1; foo=bar") assert cookieJar["a"] == "1" assert cookieJar["foo"] == "bar" @@ -46,7 +46,7 @@ proc parseCookies*(s: string): StringTableRef = proc setCookie*(key, value: string, domain = "", path = "", expires = "", noName = false, - secure = false, httpOnly = false, + secure = false, httpOnly = false, maxAge = none(int), sameSite = SameSite.Default): string = ## Creates a command in the format of ## `Set-Cookie: key=value; Domain=...; ...` diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 2b119b92c..c1bc44eeb 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -27,11 +27,11 @@ ## ## See `packaging `_ for hints on distributing Nim using OS packages. -from std/strutils import contains, toLowerAscii +from strutils import contains, toLowerAscii when not defined(nimscript): - from std/osproc import execProcess - from std/os import existsEnv + from osproc import execProcess + from os import existsEnv type Distribution* {.pure.} = enum ## the list of known distributions diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 7ee5be9c5..96ee61fd5 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -159,10 +159,9 @@ runnableExamples: a1, a2, a0, a3, a4: int doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" -import - std/[hashes, tables, strutils, lexbase, streams, macros, parsejson] +import hashes, tables, strutils, lexbase, streams, macros, parsejson -import std/options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 +import options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 import std/private/since export @@ -921,7 +920,7 @@ proc parseJson*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats p.close() when defined(js): - from std/math import `mod` + from math import `mod` from std/jsffi import JSObject, `[]`, to from std/private/jsutils import getProtoName, isInteger, isSafeInteger diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 936b8fe94..993e0f510 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -54,7 +54,7 @@ Please use alternative packages for serialization. It is possible to reimplement this module using generics and type traits. Please contribute a new implementation.""".} -import std/[streams, typeinfo, json, intsets, tables, unicode] +import streams, typeinfo, json, intsets, tables, unicode proc ptrToInt(x: pointer): int {.inline.} = result = cast[int](x) # don't skip alignment diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 03e5040ae..cff946581 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -58,7 +58,7 @@ import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import std/[bitops, fenv] +import bitops, fenv when defined(c) or defined(cpp): proc c_isnan(x: float): bool {.importc: "isnan", header: "".} diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index fb70047b6..da285a187 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -15,7 +15,7 @@ ## This implementation calls `initRand()` for the first call of ## `genOid`. -import std/[hashes, times, endians, random] +import hashes, times, endians, random from std/private/decode_helpers import handleHexChar type diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 63e3598f0..bd5aa389e 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -69,7 +69,7 @@ supports pattern matching on `Option`s, with the `Some()` and # xxx pending https://github.com/timotheecour/Nim/issues/376 use `runnableExamples` and `whichModule` -import std/typetraits +import typetraits when (NimMajor, NimMinor) >= (1, 1): type diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 0710b8333..50a88b43b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -44,7 +44,7 @@ include system/inclrtl import std/private/since -import std/[strutils, pathnorm] +import strutils, pathnorm const weirdTarget = defined(nimscript) or defined(js) @@ -65,9 +65,9 @@ since (1, 1): when weirdTarget: discard elif defined(windows): - import std/[winlean, times] + import winlean, times elif defined(posix): - import std/[posix, times] + import posix, times proc toTime(ts: Timespec): times.Time {.inline.} = result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) @@ -1008,7 +1008,7 @@ proc expandTilde*(path: string): string {. ## ## Windows: this is still supported despite Windows platform not having this ## convention; also, both ``~/`` and ``~\`` are handled. - ## + ## ## .. warning:: `~bob` and `~bob/` are not yet handled correctly. ## ## See also: diff --git a/lib/pure/random.nim b/lib/pure/random.nim index f91d92731..e58623baa 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -72,7 +72,7 @@ runnableExamples: ## * `list of cryptographic and hashing modules `_ ## in the standard library -import std/[algorithm, math] +import algorithm, math import std/private/since include system/inclrtl @@ -625,7 +625,7 @@ proc shuffle*[T](x: var openArray[T]) = shuffle(state, x) when not defined(nimscript) and not defined(standalone): - import std/times + import times proc initRand(): Rand = ## Initializes a new Rand state with a seed based on the current time. diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index a059651bb..800979cda 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -21,7 +21,7 @@ runnableExamples: doAssert r1 * r2 == -3 // 8 doAssert r1 / r2 == -2 // 3 -import std/[math, hashes] +import math, hashes type Rational*[T] = object ## A rational number, consisting of a numerator `num` and a denominator `den`. diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 42550af1d..1300b4479 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -17,7 +17,7 @@ ## runtime efficiency. include system/inclrtl -import std/streams +import streams {.push debugger: off.} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 6e2d5fecd..e46dff212 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -53,7 +53,7 @@ runnableExamples: doAssert statistics.kurtosis() ~= -1.0 doAssert statistics.kurtosisS() ~= -0.7000000000000008 -from std/math import FloatClass, sqrt, pow, round +from math import FloatClass, sqrt, pow, round {.push debugger: off.} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 736b4d501..52731e970 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -313,8 +313,8 @@ help with readability, since there is only so much you can cram into single letter DSLs. ]## -import std/[macros, parseutils, unicode] -import std/strutils except format +import macros, parseutils, unicode +import strutils except format proc mkDigit(v: int, typ: char): string {.inline.} = assert(v < 26) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 239ed9cf1..9abef55a2 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -11,7 +11,7 @@ ## macro system. import std/private/since -import std/macros +import macros proc checkPragma(ex, prag: var NimNode) = since (1, 3): diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 2527dc26e..3e215a0ea 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -167,7 +167,7 @@ since (1, 3, 5): typeof(block: (for ai in a: ai)) -import std/macros +import macros macro enumLen*(T: typedesc[enum]): int = ## Returns the number of items in the enum `T`. diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 3cff833e4..80a05db36 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -108,15 +108,15 @@ import std/private/since import std/exitprocs -import std/[macros, strutils, streams, times, sets, sequtils] +import macros, strutils, streams, times, sets, sequtils when declared(stdout): - import std/os + import os const useTerminal = not defined(js) when useTerminal: - import std/terminal + import terminal type TestStatus* = enum ## The status of a test when it is done. @@ -747,7 +747,7 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = of 2: discard parseInt("Hello World!") of 3: raise newException(IOError, "I can't do that Dave.") else: assert 2 + 2 == 5 - + expect IOError, OSError, ValueError, AssertionDefect: defectiveRobot() diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index d2a9f3848..cf712fa89 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -39,7 +39,7 @@ runnableExamples: doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" -import std/[strutils, parseutils, base64] +import strutils, parseutils, base64 import std/private/[since, decode_helpers] diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 16dab9d1a..6195ae07d 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -7,16 +7,16 @@ # distribution, for details about the copyright. # -import std/macros -from std/typetraits import OrdinalEnum, HoleyEnum +import macros +from typetraits import OrdinalEnum, HoleyEnum # xxx `genEnumCaseStmt` needs tests and runnableExamples -macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, +macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, userMin, userMax: static[int], normalizer: static[proc(s :string): string]): untyped = # generates a case stmt, which assigns the correct enum field given # a normalized string comparison to the `argSym` input. - # string normalization is done using passed normalizer. + # string normalization is done using passed normalizer. # NOTE: for an enum with fields Foo, Bar, ... we cannot generate # `of "Foo".nimIdentNormalize: Foo`. # This will fail, if the enum is not defined at top level (e.g. in a block). diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index a5daa9fb4..4c27bc9f2 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -13,7 +13,7 @@ runnableExamples: let j = a.toJson assert j.jsonTo(typeof(a)).toJson == j -import std/[json,strutils,tables,sets,strtabs,options] +import json, strutils, tables, sets, strtabs, options #[ Future directions: @@ -27,7 +27,7 @@ add a way to customize serialization, for e.g.: objects. ]# -import std/macros +import macros type Joptions* = object @@ -106,7 +106,7 @@ proc hasField[T](obj: T, field: string): bool = return true return false -macro accessField(obj: typed, name: static string): untyped = +macro accessField(obj: typed, name: static string): untyped = newDotExpr(obj, ident(name)) template fromJsonFields(newObj, oldObj, json, discKeys, opt) = @@ -146,7 +146,7 @@ template fromJsonFields(newObj, oldObj, json, discKeys, opt) = json.len == numMatched else: json.len == num and num == numMatched - + checkJson ok, $(json.len, num, numMatched, $T, json) proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) @@ -284,7 +284,7 @@ proc toJson*[T](a: T): JsonNode = proc fromJsonHook*[K: string|cstring, V](t: var (Table[K, V] | OrderedTable[K, V]), jsonNode: JsonNode) = ## Enables `fromJson` for `Table` and `OrderedTable` types. - ## + ## ## See also: ## * `toJsonHook proc<#toJsonHook>`_ runnableExamples: @@ -326,7 +326,7 @@ proc toJsonHook*[K: string|cstring, V](t: (Table[K, V] | OrderedTable[K, V])): J proc fromJsonHook*[A](s: var SomeSet[A], jsonNode: JsonNode) = ## Enables `fromJson` for `HashSet` and `OrderedSet` types. - ## + ## ## See also: ## * `toJsonHook proc<#toJsonHook,SomeSet[A]>`_ runnableExamples: @@ -360,7 +360,7 @@ proc toJsonHook*[A](s: SomeSet[A]): JsonNode = proc fromJsonHook*[T](self: var Option[T], jsonNode: JsonNode) = ## Enables `fromJson` for `Option` types. - ## + ## ## See also: ## * `toJsonHook proc<#toJsonHook,Option[T]>`_ runnableExamples: @@ -395,7 +395,7 @@ proc toJsonHook*[T](self: Option[T]): JsonNode = proc fromJsonHook*(a: var StringTableRef, b: JsonNode) = ## Enables `fromJson` for `StringTableRef` type. - ## + ## ## See also: ## * `toJsonHook proc<#toJsonHook,StringTableRef>`_ runnableExamples: @@ -413,7 +413,7 @@ proc fromJsonHook*(a: var StringTableRef, b: JsonNode) = proc toJsonHook*(a: StringTableRef): JsonNode = ## Enables `toJson` for `StringTableRef` type. - ## + ## ## See also: ## * `fromJsonHook proc<#fromJsonHook,StringTableRef,JsonNode>`_ runnableExamples: diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index 78736d719..8f6aa5b66 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -39,7 +39,7 @@ See also * `times module `_ ]## -import std/times +import times type MonoTime* = object ## Represents a monotonic timestamp. @@ -77,7 +77,7 @@ when defined(js): {.pop.} elif defined(posix) and not defined(osx): - import std/posix + import posix elif defined(windows): proc QueryPerformanceCounter(res: var uint64) {. diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index b98a7808b..a32f1d1b9 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -4,7 +4,7 @@ this can eventually be moved to std/os and `walkDirRec` can be implemented in te to avoid duplication ]## -import std/[os] +import os when defined(windows): from strutils import replace diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index c7fac0a54..aba5f348a 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -14,7 +14,7 @@ ## * `std/packedsets `_ ## * `std/sets `_ -import std/[typetraits, macros] +import typetraits, macros #[ type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8 diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 9c5efed1f..bda0c6de7 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -26,8 +26,8 @@ runnableExamples("-r:off"): b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") assert a == b, "files don't match" -import std/strutils -from std/endians import bigEndian32, bigEndian64 +import strutils +from endians import bigEndian32, bigEndian64 const Sha1DigestSize = 20 diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 4a2cdd10b..4c51577ac 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -10,7 +10,7 @@ ## .. warning:: This module was added in Nim 1.6. If you are using it for cryptographic purposes, ## keep in mind that so far this has not been audited by any security professionals, ## therefore may not be secure. -## +## ## `std/sysrand` generates random numbers from a secure source provided by the operating system. ## It is a cryptographically secure pseudorandom number generator ## and should be unpredictable enough for cryptographic applications, @@ -52,10 +52,10 @@ runnableExamples: when not defined(js): - import std/os + import os when defined(posix): - import std/posix + import posix const batchImplOS = defined(freebsd) or defined(openbsd) or (defined(macosx) and not defined(ios)) @@ -243,7 +243,7 @@ elif defined(macosx): """ proc getentropy(p: pointer, size: csize_t): cint {.importc: "getentropy", header: sysrandomHeader.} - # getentropy() fills a buffer with random data, which can be used as input + # getentropy() fills a buffer with random data, which can be used as input # for process-context pseudorandom generators like arc4random(3). # The maximum buffer size permitted is 256 bytes. @@ -310,7 +310,7 @@ proc urandom*(dest: var openArray[byte]): bool = proc urandom*(size: Natural): seq[byte] {.inline.} = ## Returns random bytes suitable for cryptographic use. - ## + ## ## .. warning:: The code hasn't been audited by cryptography experts and ## is provided as-is without guarantees. Use at your own risks. For production ## systems we advise you to request an external audit. diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim index 3ff48fbfe..708faf4cf 100644 --- a/lib/std/wrapnils.nim +++ b/lib/std/wrapnils.nim @@ -24,7 +24,7 @@ runnableExamples: assert (?.f2.x2.x2).x3 == nil # this terminates ?. early -from std/options import Option, isSome, get, option, unsafeGet, UnpackDefect +from options import Option, isSome, get, option, unsafeGet, UnpackDefect export options.get, options.isSome, options.isNone template fakeDot*(a: Option, b): untyped = @@ -59,7 +59,7 @@ func `[]`*[U](a: Option[U]): auto {.inline.} = if a2 != nil: result = option(a2[]) -import std/macros +import macros func replace(n: NimNode): NimNode = if n.kind == nnkDotExpr: From f1ce173283a06197cfde80e9117ba1aa0ed0dd02 Mon Sep 17 00:00:00 2001 From: Joey Date: Tue, 20 Apr 2021 23:42:04 -0600 Subject: [PATCH 2472/4254] Fix Httpclient headers from being modified accidentally (#17808) --- lib/pure/httpclient.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 14bcfd2fb..b60894103 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -962,12 +962,15 @@ proc format(client: HttpClient | AsyncHttpClient, proc override(fallback, override: HttpHeaders): HttpHeaders = # Right-biased map union for `HttpHeaders` - if override.isNil: - return fallback result = newHttpHeaders() # Copy by value result.table[] = fallback.table[] + + if override.isNil: + # Return the copy of fallback so it does not get modified + return result + for k, vs in override.table: result[k] = vs From 2951f89374e9797fa5567b5afd4effb3149c1fd5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Apr 2021 01:52:17 -0700 Subject: [PATCH 2473/4254] improve errmsg refs #17793 object ctor with generics (#17806) --- compiler/semobjconstr.nim | 5 ++++- compiler/types.nim | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 01d5a8b28..6f3cabcbf 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -11,6 +11,8 @@ # included from sem.nim +from sugar import dup + type ObjConstrContext = object typ: PType # The constructed type @@ -389,7 +391,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # multiple times as long as they don't have closures. result.typ.flags.incl tfHasOwned if t.kind != tyObject: - return localErrorNode(c, result, "object constructor needs an object type") + return localErrorNode(c, result, + "object constructor needs an object type".dup(addDeclaredLoc(c.config, t))) # Check if the object is fully initialized by recursively testing each # field (if this is a case object, initialized fields in two different diff --git a/compiler/types.nim b/compiler/types.nim index e56fcffe4..ba2cc76ce 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -130,7 +130,7 @@ proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) = if optDeclaredLocs in conf.globalOptions and sym != nil: addDeclaredLoc(result, conf, sym) -proc addDeclaredLoc(result: var string, conf: ConfigRef; typ: PType) = +proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = let typ = typ.skipTypes(abstractInst - {tyRange}) result.add " [$1" % typ.kind.toHumanStr if typ.sym != nil: From c631648cb31b11d61d249e0745181acb0fcc30cc Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 21 Apr 2021 21:07:36 +0800 Subject: [PATCH 2474/4254] close #9372 add std/tempfiles (#17361) * close #9372 add std/tempfile --- changelog.md | 3 + lib/std/tempfiles.nim | 139 ++++++++++++++++++++++++++++++++++++ tests/stdlib/ttempfiles.nim | 17 +++++ 3 files changed, 159 insertions(+) create mode 100644 lib/std/tempfiles.nim create mode 100644 tests/stdlib/ttempfiles.nim diff --git a/changelog.md b/changelog.md index 0537b3d6a..abd2f8733 100644 --- a/changelog.md +++ b/changelog.md @@ -283,9 +283,12 @@ - Added `hasClosure` to `std/typetraits`. +- Added `std/tempfiles`. + - Added `genasts.genAst` that avoids the problems inherent with `quote do` and can be used as a replacement. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim new file mode 100644 index 000000000..1e1bbd403 --- /dev/null +++ b/lib/std/tempfiles.nim @@ -0,0 +1,139 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2021 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module creates temporary files and directories. + +import os, random + + +const + maxRetry = 10000 + letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + nimTempPathLength {.intdefine.} = 8 + + +when defined(windows): + import winlean + + var O_RDWR {.importc: "_O_RDWR", header: "".}: cint + + proc c_fdopen( + filehandle: cint, + mode: cstring + ): File {.importc: "_fdopen",header: "".} + + proc open_osfhandle(osh: Handle, mode: cint): cint {. + importc: "_open_osfhandle", header: "".} + + proc close_osfandle(fd: cint): cint {. + importc: "_close", header: "".} +else: + import posix + + proc c_fdopen( + filehandle: cint, + mode: cstring + ): File {.importc: "fdopen",header: "".} + + +proc safeOpen(filename: string): File = + ## Open files exclusively. + when defined(windows): + let dwShareMode = FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE + let dwCreation = CREATE_NEW + let dwFlags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL + let handle = createFileW(newWideCString(filename), GENERIC_READ or GENERIC_WRITE, dwShareMode, + nil, dwCreation, dwFlags, Handle(0)) + + if handle == INVALID_HANDLE_VALUE: + raiseOSError(osLastError(), filename) + + let fileHandle = open_osfhandle(handle, O_RDWR) + if fileHandle == -1: + discard closeHandle(handle) + raiseOSError(osLastError(), filename) + + result = c_fdopen(fileHandle, "w+") + if result == nil: + discard close_osfandle(fileHandle) + raiseOSError(osLastError(), filename) + else: + let flags = posix.O_RDWR or posix.O_CREAT or posix.O_EXCL + + let fileHandle = posix.open(filename, flags) + if fileHandle == -1: + raiseOSError(osLastError(), filename) + + result = c_fdopen(fileHandle, "w+") + if result == nil: + discard posix.close(fileHandle) # TODO handles failure when closing file + raiseOSError(osLastError(), filename) + +template randomPathName(length: Natural): string = + var res = newString(length) + var state = initRand() + for i in 0 ..< length: + res[i] = state.sample(letters) + res + +proc createTempFile*(prefix, suffix: string, dir = ""): tuple[fd: File, path: string] = + ## `createTempFile` creates a new temporary file in the directory `dir`. + ## + ## If `dir` is the empty string, the default directory for temporary files + ## (`getTempDir `_) will be used. + ## The temporary file name begins with `prefix` and ends with `suffix`. + ## `createTempFile` returns a file handle to an open file and the path of that file. + ## + ## If failing to create a temporary file, `IOError` will be raised. + ## + ## .. note:: It is the caller's responsibility to remove the file when no longer needed. + ## + var dir = dir + if dir.len == 0: + dir = getTempDir() + + createDir(dir) + + for i in 0 ..< maxRetry: + result.path = dir / (prefix & randomPathName(nimTempPathLength) & suffix) + try: + result.fd = safeOpen(result.path) + except OSError: + continue + return + + raise newException(IOError, "Failed to create a temporary file under directory " & dir) + +proc createTempDir*(prefix, suffix: string, dir = ""): string = + ## `createTempDir` creates a new temporary directory in the directory `dir`. + ## + ## If `dir` is the empty string, the default directory for temporary files + ## (`getTempDir `_) will be used. + ## The temporary directory name begins with `prefix` and ends with `suffix`. + ## `createTempDir` returns the path of that temporary firectory. + ## + ## If failing to create a temporary directory, `IOError` will be raised. + ## + ## .. note:: It is the caller's responsibility to remove the directory when no longer needed. + ## + var dir = dir + if dir.len == 0: + dir = getTempDir() + + createDir(dir) + + for i in 0 ..< maxRetry: + result = dir / (prefix & randomPathName(nimTempPathLength) & suffix) + try: + if not existsOrCreateDir(result): + return + except OSError: + continue + + raise newException(IOError, "Failed to create a temporary directory under directory " & dir) diff --git a/tests/stdlib/ttempfiles.nim b/tests/stdlib/ttempfiles.nim new file mode 100644 index 000000000..29ef2fb2b --- /dev/null +++ b/tests/stdlib/ttempfiles.nim @@ -0,0 +1,17 @@ +import std/[os, tempfiles] + + +doAssert createTempDir("nim", "tmp") != createTempDir("nim", "tmp") + +block: + var t1 = createTempFile("nim", ".tmp") + var t2 = createTempFile("nim", ".tmp") + doAssert t1.path != t2.path + + write(t1.fd, "1234") + doAssert readAll(t2.fd) == "" + + close(t1.fd) + close(t2.fd) + removeFile(t1.path) + removeFile(t2.path) From da1c1a711780e21a372ef70f9080aebe5b9ef987 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Apr 2021 06:26:27 -0700 Subject: [PATCH 2475/4254] `--filenames:abs|canonical|legacyRelProj` for filenames in compiler msgs (replaces `--listfullpaths:on|off`) (#17746) * use canonicalImport for filename_magicSauce * --filenames:abs|canonical|magic * rename: magic => legacyRelProj --- changelog.md | 2 ++ compiler/commands.nim | 18 +++++++++++++++++- compiler/docgen.nim | 15 --------------- compiler/main.nim | 8 +++++--- compiler/msgs.nim | 24 +++++++++--------------- compiler/options.nim | 37 +++++++++++++++++++++++++++++++++---- doc/advopt.txt | 4 +++- drnim/drnim.nim | 3 ++- tests/config.nims | 2 +- 9 files changed, 72 insertions(+), 41 deletions(-) diff --git a/changelog.md b/changelog.md index abd2f8733..30fe237be 100644 --- a/changelog.md +++ b/changelog.md @@ -341,6 +341,8 @@ - Added `--spellSuggest` to show spelling suggestions on typos. +- Added `--filenames:abs|canonical|magic` which replaces --listFullPaths:on|off + - Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. diff --git a/compiler/commands.nim b/compiler/commands.nim index 5d6e45fb5..0733e500a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -141,6 +141,15 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC elif switch[i] == '[': arg = substr(switch, i) else: invalidCmdLineOption(conf, pass, switch, info) +template switchOn(arg: string): bool = + # xxx use `switchOn` wherever appropriate + case arg.normalize + of "", "on": true + of "off": false + else: + localError(conf, info, errOnOrOffExpectedButXFound % arg) + false + proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize @@ -885,8 +894,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; trackIde(conf, ideDus, arg, info) of "stdout": processOnOffSwitchG(conf, {optStdout}, arg, pass, info) + of "filenames": + case arg.normalize + of "abs": conf.filenameOption = foAbs + of "canonical": conf.filenameOption = foCanonical + of "legacyrelproj": conf.filenameOption = foLegacyRelProj + else: localError(conf, info, "expected: abs|canonical|legacyRelProj, got: $1" % arg) of "listfullpaths": - processOnOffSwitchG(conf, {optListFullPaths}, arg, pass, info) + # xxx in future work, use `warningDeprecated` + conf.filenameOption = if switchOn(arg): foAbs else: foCanonical of "spellsuggest": if arg.len == 0: conf.spellSuggestMax = spellSuggestSecretSauce elif arg == "auto": conf.spellSuggestMax = spellSuggestSecretSauce diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4d9f09ca6..977fcf8ef 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -63,21 +63,6 @@ proc prettyString(a: object): string = for k, v in fieldPairs(a): result.add k & ": " & $v & "\n" -proc canonicalImport*(conf: ConfigRef, file: AbsoluteFile): string = - ##[ - Shows the canonical module import, e.g.: - system, std/tables, fusion/pointers, system/assertions, std/private/asciitables - ]## - var ret = getRelativePathFromConfigPath(conf, file, isTitle = true) - let dir = getNimbleFile(conf, $file).parentDir.AbsoluteDir - if not dir.isEmpty: - let relPath = relativeTo(file, dir) - if not relPath.isEmpty and (ret.isEmpty or relPath.string.len < ret.string.len): - ret = relPath - if ret.isEmpty: - ret = relativeTo(file, conf.projectPath) - result = ret.string.nativeToUnixPath.changeFileExt("") - proc presentationPath*(conf: ConfigRef, file: AbsoluteFile): RelativeFile = ## returns a relative file that will be appended to outDir let file2 = $file diff --git a/compiler/main.nim b/compiler/main.nim index d66a5f329..9c9a789cb 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -362,6 +362,7 @@ proc mainCommand*(graph: ModuleGraph) = rawMessage(conf, errGenerated, "invalid command: " & conf.command) if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}: + # D20210419T170230:here let mem = when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" else: formatSize(getTotalMem()) & " totmem" @@ -370,8 +371,8 @@ proc mainCommand*(graph: ModuleGraph) = elif isDefined(conf, "release"): "Release" else: "Debug" let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) - let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName - + let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName + # xxx honor conf.filenameOption more accurately var output: string if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonscript: output = $conf.jsonBuildFile @@ -380,7 +381,8 @@ proc mainCommand*(graph: ModuleGraph) = output = "unknownOutput" else: output = $conf.absOutFile - if optListFullPaths notin conf.globalOptions: output = output.AbsoluteFile.extractFilename + if conf.filenameOption != foAbs: output = output.AbsoluteFile.extractFilename + # xxx honor filenameOption more accurately if optProfileVM in conf.globalOptions: echo conf.dump(conf.vmProfileData) rawMessage(conf, hintSuccessX, [ diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 89949ef17..b7b6a582e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -241,37 +241,30 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string = template toFullPathConsiderDirty*(conf: ConfigRef; info: TLineInfo): string = string toFullPathConsiderDirty(conf, info.fileIndex) -type - FilenameOption* = enum - foAbs # absolute path, e.g.: /pathto/bar/foo.nim - foRelProject # relative to project path, e.g.: ../foo.nim - foMagicSauce # magic sauce, shortest of (foAbs, foRelProject) - foName # lastPathPart, e.g.: foo.nim - foStacktrace # if optExcessiveStackTrace: foAbs else: foName - proc toFilenameOption*(conf: ConfigRef, fileIdx: FileIndex, opt: FilenameOption): string = case opt of foAbs: result = toFullPath(conf, fileIdx) of foRelProject: result = toProjPath(conf, fileIdx) - of foMagicSauce: + of foCanonical: + let absPath = toFullPath(conf, fileIdx) + result = canonicalImportAux(conf, absPath.AbsoluteFile) + of foName: result = toProjPath(conf, fileIdx).lastPathPart + of foLegacyRelProj: let absPath = toFullPath(conf, fileIdx) relPath = toProjPath(conf, fileIdx) - result = if (optListFullPaths in conf.globalOptions) or - (relPath.len > absPath.len) or - (relPath.count("..") > 2): + result = if (relPath.len > absPath.len) or (relPath.count("..") > 2): absPath else: relPath - of foName: result = toProjPath(conf, fileIdx).lastPathPart of foStacktrace: if optExcessiveStackTrace in conf.globalOptions: result = toFilenameOption(conf, fileIdx, foAbs) else: result = toFilenameOption(conf, fileIdx, foName) -proc toMsgFilename*(conf: ConfigRef; info: FileIndex): string = - toFilenameOption(conf, info, foMagicSauce) +proc toMsgFilename*(conf: ConfigRef; fileIdx: FileIndex): string = + toFilenameOption(conf, fileIdx, conf.filenameOption) template toMsgFilename*(conf: ConfigRef; info: TLineInfo): string = toMsgFilename(conf, info.fileIndex) @@ -558,6 +551,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg, resetStyle, conf.getSurroundingSrc(info), UnitSep) if hintMsgOrigin in conf.mainPackageNotes: + # xxx needs a bit of refactoring to honor `conf.filenameOption` styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, KindFormat % $hintMsgOrigin, diff --git a/compiler/options.nim b/compiler/options.nim index c1ac6b1e0..2aaaf5844 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -13,7 +13,7 @@ import from terminal import isatty from times import utc, fromUnix, local, getTime, format, DateTime - +from std/private/globs import nativeToUnixPath const hasTinyCBackend* = defined(tinyc) useEffectSystem* = true @@ -78,7 +78,6 @@ type # please make sure we have under 32 options optWholeProject # for 'doc': output any dependency optDocInternal # generate documentation for non-exported symbols optMixedMode # true if some module triggered C++ codegen - optListFullPaths # use full paths in toMsgFilename optDeclaredLocs # show declaration locations in messages optNoNimblePath optHotCodeReloading @@ -258,6 +257,14 @@ type stdOrrStdout stdOrrStderr + FilenameOption* = enum + foAbs # absolute path, e.g.: /pathto/bar/foo.nim + foRelProject # relative to project path, e.g.: ../foo.nim + foCanonical # canonical module name + foLegacyRelProj # legacy, shortest of (foAbs, foRelProject) + foName # lastPathPart, e.g.: foo.nim + foStacktrace # if optExcessiveStackTrace: foAbs else: foName + ConfigRef* = ref object ## every global configuration ## fields marked with '*' are subject to ## the incremental compilation mechanisms @@ -270,6 +277,7 @@ type macrosToExpand*: StringTableRef arcToExpand*: StringTableRef m*: MsgConfig + filenameOption*: FilenameOption # how to render paths in compiler messages evalTemplateCounter*: int evalMacroCounter*: int exitcode*: int8 @@ -413,8 +421,7 @@ const optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` optTrMacros, optStyleCheck, optCursorInference} - DefaultGlobalOptions* = {optThreadAnalysis, - optExcessiveStackTrace, optListFullPaths} + DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace} proc getSrcTimestamp(): DateTime = try: @@ -461,6 +468,7 @@ proc newConfigRef*(): ConfigRef = macrosToExpand: newStringTable(modeStyleInsensitive), arcToExpand: newStringTable(modeStyleInsensitive), m: initMsgConfig(), + filenameOption: foAbs, cppDefines: initHashSet[string](), headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: foreignPackageNotesDefault, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], @@ -514,6 +522,7 @@ proc newConfigRef*(): ConfigRef = proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. + # xxx FACTOR with `newConfigRef` when defined(nimDebugUtils): result = getConfigRef() else: @@ -522,6 +531,7 @@ proc newPartialConfigRef*(): ConfigRef = verbosity: 1, options: DefaultOptions, globalOptions: DefaultGlobalOptions, + filenameOption: foAbs, foreignPackageNotes: foreignPackageNotesDefault, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) @@ -885,6 +895,25 @@ proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = if dir == "": break return "" +proc canonicalImportAux*(conf: ConfigRef, file: AbsoluteFile): string = + ##[ + Shows the canonical module import, e.g.: + system, std/tables, fusion/pointers, system/assertions, std/private/asciitables + ]## + var ret = getRelativePathFromConfigPath(conf, file, isTitle = true) + let dir = getNimbleFile(conf, $file).parentDir.AbsoluteDir + if not dir.isEmpty: + let relPath = relativeTo(file, dir) + if not relPath.isEmpty and (ret.isEmpty or relPath.string.len < ret.string.len): + ret = relPath + if ret.isEmpty: + ret = relativeTo(file, conf.projectPath) + result = ret.string + +proc canonicalImport*(conf: ConfigRef, file: AbsoluteFile): string = + let ret = canonicalImportAux(conf, file) + result = ret.nativeToUnixPath.changeFileExt("") + proc canonDynlibName(s: string): string = let start = if s.startsWith("lib"): 3 else: 0 let ende = strutils.find(s, {'(', ')', '.'}) diff --git a/doc/advopt.txt b/doc/advopt.txt index bfc381cff..539cc620c 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -36,7 +36,9 @@ Advanced options: to after all options have been processed --stdout:on|off output to stdout --colors:on|off turn compiler messages coloring on|off - --listFullPaths:on|off list full paths in messages + --filenames:abs|canonical|legacyRelProj + customize how filenames are rendered in compiler messages, + defaults to `abs` (absolute) --declaredLocs:on|off show declaration locations in messages --spellSuggest|:num show at most `num >= 0` spelling suggestions on typos. if `num` is not specified (or `auto`), return diff --git a/drnim/drnim.nim b/drnim/drnim.nim index d549e1d5b..a591a8ef3 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1205,6 +1205,7 @@ proc mainCommand(graph: ModuleGraph) = registerPass graph, semPass compileProject(graph) if conf.errorCounter == 0: + # xxx deduplicate with D20210419T170230 let mem = when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" else: formatSize(getTotalMem()) & " totmem" @@ -1213,7 +1214,7 @@ proc mainCommand(graph: ModuleGraph) = elif isDefined(conf, "release"): "Release" else: "Debug" let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) - let project = if optListFullPaths in conf.globalOptions: $conf.projectFull else: $conf.projectName + let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName rawMessage(conf, hintSuccessX, [ "loc", loc, "sec", sec, diff --git a/tests/config.nims b/tests/config.nims index 41edf0005..e5d6545f4 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -6,7 +6,7 @@ switch("path", "$lib/../testament/lib") ## prevent common user config settings to interfere with testament expectations ## Indifidual tests can override this if needed to test for these options. switch("colors", "off") -switch("listFullPaths", "off") +switch("filenames", "legacyRelProj") switch("excessiveStackTrace", "off") switch("spellSuggest", "0") From 7c64e49d452607fa246b54e931c057ed172b264a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 21 Apr 2021 15:28:42 +0200 Subject: [PATCH 2476/4254] getCustomPragmaVal priority/override fixes (#17725) * Adhere left-to-right rule for custom pragma priority * Improve error message for no custom pragmas * custom pragmas on var/let sym take priority over its type ones * Workaround & bug --- lib/core/macros.nim | 78 ++++++++++++++++---------------- tests/pragmas/tcustom_pragma.nim | 10 ++++ 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index fc68781da..79c3ba28b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1536,6 +1536,14 @@ proc getPragmaNodeFromTypeSym(sym: NimNode): NimNode = if pragmaExpr.kind == nnkPragmaExpr: result = pragmaExpr[1] +proc getPragmaNodeFromType(typ: NimNode): NimNode = + case typ.kind + of nnkSym: + result = getPragmaNodeFromTypeSym(typ) + of nnkProcTy: + result = typ[1] + else: error("illegal typ kind for argument: " & $typ.kind, typ) + proc getPragmaNodeFromVarLetSym(sym: NimNode): NimNode = sym.expectKind nnkSym if sym.symKind notin {nskVar, nskLet}: error("expected var/let sym", sym) @@ -1546,73 +1554,64 @@ proc getPragmaNodeFromVarLetSym(sym: NimNode): NimNode = if pragmaExpr.kind == nnkPragmaExpr: result = pragmaExpr[1] -proc getPragmaByName(pragmaExpr: NimNode, name: string): NimNode = +proc getPragmasByName(pragmaExpr: NimNode, name: string): seq[NimNode] = if pragmaExpr.kind == nnkPragma: for it in pragmaExpr: if it.kind in nnkPragmaCallKinds: if eqIdent(it[0], name): - return it + result.add it elif it.kind == nnkSym: if eqIdent(it, name): - return it + result.add it -proc getCustomPragmaNode(sym: NimNode, name: string): NimNode = +proc getCustomPragmaNodes(sym: NimNode, name: string): seq[NimNode] = sym.expectKind nnkSym case sym.symKind of nskField: - result = getPragmaNodeFromObjFieldSym(sym).getPragmaByName(name) + result = getPragmaNodeFromObjFieldSym(sym).getPragmasByName(name) of nskProc: - result = getPragmaNodeFromProcSym(sym).getPragmaByName(name) + result = getPragmaNodeFromProcSym(sym).getPragmasByName(name) of nskType: - result = getPragmaNodeFromTypeSym(sym).getPragmaByName(name) + result = getPragmaNodeFromTypeSym(sym).getPragmasByName(name) of nskParam: # When a typedesc parameter is passed to the macro, it will be of nskParam. let typeInst = getTypeInst(sym) if typeInst.kind == nnkBracketExpr and eqIdent(typeInst[0], "typeDesc"): - result = getPragmaNodeFromTypeSym(typeInst[1]).getPragmaByName(name) + result = getPragmaNodeFromTypeSym(typeInst[1]).getPragmasByName(name) else: error("illegal sym kind for argument: " & $sym.symKind, sym) of nskVar, nskLet: - # I think it is a bad idea to fall back to the typeSym. The API - # explicity requests a var/let symbol, not a type symbol. - result = getPragmaNodeFromVarLetSym(sym).getPragmaByName(name) or - getPragmaNodeFromTypeSym(sym.getTypeInst).getPragmaByName(name) + # This checks the type of the sym too, this is consistent with how + # field expressions are handled too. If this is changed, make sure to + # change it for fields expressions too. + result = getPragmaNodeFromType(sym.getTypeInst).getPragmasByName(name) + result.add getPragmaNodeFromVarLetSym(sym).getPragmasByName(name) else: error("illegal sym kind for argument: " & $sym.symKind, sym) since (1, 5): - export getCustomPragmaNode + export getCustomPragmaNodes proc hasCustomPragma*(n: NimNode, name: string): bool = n.expectKind nnkSym - let pragmaNode = getCustomPragmaNode(n, name) - result = pragmaNode != nil + result = getCustomPragmaNodes(n, name).len > 0 -proc getCustomPragmaNodeSmart(n: NimNode, name: string): NimNode = +proc getCustomPragmaNodesSmart(n: NimNode, name: string): seq[NimNode] = case n.kind of nnkDotExpr: - result = getCustomPragmaNode(n[1], name) + result = getCustomPragmaNodes(n[1], name) of nnkCheckedFieldExpr: expectKind n[0], nnkDotExpr - result = getCustomPragmaNode(n[0][1], name) + result = getCustomPragmaNodes(n[0][1], name) of nnkSym: - result = getCustomPragmaNode(n, name) + result = getCustomPragmaNodes(n, name) of nnkTypeOfExpr: - var typeSym = n.getTypeInst - while typeSym.kind == nnkBracketExpr and typeSym[0].eqIdent "typeDesc": - typeSym = typeSym[1] - case typeSym.kind: - of nnkSym: - result = getCustomPragmaNode(typeSym, name) - of nnkProcTy: - # It is a bad idea to support this. The annotation can't be part - # of a symbol. - let pragmaExpr = typeSym[1] - result = getPragmaByName(pragmaExpr, name) - else: - typeSym.expectKind nnkSym + var typ = n.getTypeInst + while typ.kind == nnkBracketExpr and typ[0].eqIdent "typeDesc": + typ = typ[1] + result = getPragmaNodeFromType(typ).getPragmasByName(name) of nnkBracketExpr: - result = nil #false + discard else: n.expectKind({nnkDotExpr, nnkCheckedFieldExpr, nnkSym, nnkTypeOfExpr}) @@ -1633,7 +1632,7 @@ macro hasCustomPragma*(n: typed, cp: typed{nkSym}): bool = ## var o: MyObj ## assert(o.myField.hasCustomPragma(myAttr)) ## assert(myProc.hasCustomPragma(myAttr)) - result = newLit(getCustomPragmaNodeSmart(n, $cp) != nil) + result = newLit(getCustomPragmaNodesSmart(n, $cp).len > 0) iterator iterOverFormalArgs(f: NimNode): tuple[name, typ, val: NimNode] = f.expectKind nnkFormalParams @@ -1644,7 +1643,7 @@ iterator iterOverFormalArgs(f: NimNode): tuple[name, typ, val: NimNode] = for j in 0.. Date: Wed, 21 Apr 2021 16:03:30 +0200 Subject: [PATCH 2477/4254] Revert localErrorNode param order changes (#17809) * Revert localErrorNode param order changes * Remove unused globalError overload * heh --- compiler/msgs.nim | 3 --- compiler/semdata.nim | 18 ++++++++++++++---- compiler/semexprs.nim | 2 +- compiler/semmagic.nim | 8 ++++---- compiler/semstmts.nim | 2 +- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b7b6a582e..f08722cc7 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -585,9 +585,6 @@ template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = liMessage(conf, info, errGenerated, arg, doRaise, instLoc()) -template globalError*(conf: ConfigRef; format: string, params: openArray[string]) = - liMessage(conf, unknownLineInfo, errGenerated, format % params, doRaise, instLoc()) - template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(conf, info, msg, arg, doNothing, instLoc()) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 9a17efb1c..1c1a5159c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -501,13 +501,23 @@ proc errorNode*(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) result.typ = errorType(c) -template localErrorNode*(c: PContext, n: PNode, arg: string, info: TLineInfo, kind: TMsgKind = errGenerated): PNode = - liMessage(c.config, info, kind, arg, doNothing, instLoc()) +# These mimic localError +template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode = + liMessage(c.config, info, msg, arg, doNothing, instLoc()) errorNode(c, n) -template localErrorNode*(c: PContext, n: PNode, arg: string, kind: TMsgKind = errGenerated): PNode = +template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, arg: string): PNode = + liMessage(c.config, info, errGenerated, arg, doNothing, instLoc()) + errorNode(c, n) + +template localErrorNode*(c: PContext, n: PNode, msg: TMsgKind, arg: string): PNode = let n2 = n - liMessage(c.config, n2.info, kind, arg, doNothing, instLoc()) + liMessage(c.config, n2.info, msg, arg, doNothing, instLoc()) + errorNode(c, n2) + +template localErrorNode*(c: PContext, n: PNode, arg: string): PNode = + let n2 = n + liMessage(c.config, n2.info, errGenerated, arg, doNothing, instLoc()) errorNode(c, n2) proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index defceb291..353831736 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2620,7 +2620,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = # check if either everything or nothing is tyTypeDesc for i in 1.. high(TSymChoiceRule).int: - return localErrorNode(c, n, errConstExprExpected, n[2].info) + return localErrorNode(c, n, n[2].info, errConstExprExpected) let id = newIdentNode(getIdent(c.cache, sl.strVal), n.info) let s = qualifiedLookUp(c, id, {checkUndeclared}) @@ -251,10 +251,10 @@ proc semBindSym(c: PContext, n: PNode): PNode = proc opBindSym(c: PContext, scope: PScope, n: PNode, isMixin: int, info: PNode): PNode = if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit, nkIdent}: - return localErrorNode(c, n, errStringOrIdentNodeExpected, info.info) + return localErrorNode(c, n, info.info, errStringOrIdentNodeExpected) if isMixin < 0 or isMixin > high(TSymChoiceRule).int: - return localErrorNode(c, n, errConstExprExpected, info.info) + return localErrorNode(c, n, info.info, errConstExprExpected) let id = if n.kind == nkIdent: n else: newIdentNode(getIdent(c.cache, n.strVal), info.info) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 22e4295fa..d56c1c1bd 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -725,7 +725,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if n.len == 3: if n[0].kind == nkVarTuple: if n[0].len-1 != iterAfterVarLent.len: - return localErrorNode(c, n, errWrongNumberOfVariables, n[0].info) + return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables) for i in 0.. Date: Wed, 21 Apr 2021 17:57:54 +0300 Subject: [PATCH 2478/4254] add RST highlighting for command line / shells (also fixes #16858) (#17789) --- config/nimdoc.tex.cfg | 2 + doc/contributing.rst | 177 +++++++++++---------- doc/docstyle.rst | 16 +- doc/nimdoc.css | 31 +++- lib/packages/docutils/highlite.nim | 83 +++++++++- lib/packages/docutils/rst.nim | 49 +++--- lib/packages/docutils/rstast.nim | 4 +- lib/packages/docutils/rstgen.nim | 18 ++- nimdoc/testproject/expected/nimdoc.out.css | 31 +++- tests/stdlib/trstgen.nim | 20 ++- 10 files changed, 291 insertions(+), 140 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 69266f85d..471f20dc1 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -137,6 +137,8 @@ bottomline=false} \newcommand{\spanReference}[1]{#1} \newcommand{\spanOther}[1]{#1} \newcommand{\spantok}[1]{\frame{#1}} +\newcommand{\spanprogram}[1]{\textbf{\underline{#1}}} +\newcommand{\spanoption}[1]{\textbf{#1}} $content \end{document} diff --git a/doc/contributing.rst b/doc/contributing.rst index 3d3da2ce0..81fa9f8eb 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -1,9 +1,10 @@ -.. default-role:: code - ============ Contributing ============ +.. default-role:: code +.. include:: rstcommon.rst + .. contents:: @@ -19,21 +20,23 @@ Writing tests There are 4 types of tests: -1. `runnableExamples` documentation comment tests, ran by `nim doc mymod.nim` +1. `runnableExamples` documentation comment tests, ran by `nim doc mymod.nim`:cmd: These end up in documentation and ensure documentation stays in sync with code. -2. separate test files, e.g.: `tests/stdlib/tos.nim`. - In nim repo, `testament` (see below) runs all `$nim/tests/*/t*.nim` test files; +2. separate test files, e.g.: ``tests/stdlib/tos.nim``. + In nim repo, `testament`:cmd: (see below) runs all + ``$nim/tests/*/t*.nim`` test files; for nimble packages, see https://github.com/nim-lang/nimble#tests. -3. (deprecated) tests in `when isMainModule:` block, ran by `nim r mymod.nim`. - `nimble test` can run those in nimble packages when specified in a +3. (deprecated) tests in `when isMainModule:` block, ran by `nim r mymod.nim`:cmd:. + `nimble test`:cmd: can run those in nimble packages when specified in a `task "test"`. -4. (not preferred) `.. code-block:: nim` RST snippets; these should only be used in rst sources, +4. (not preferred) ``.. code-block:: nim`` RST snippets; + these should only be used in rst sources, in nim sources `runnableExamples` should now always be preferred to those for several reasons (cleaner syntax, syntax highlights, batched testing, and - `rdoccmd` allows customization). + parameter `rdoccmd` allows customization). Not all the tests follow the convention here, feel free to change the ones that don't. Always leave the code cleaner than you found it. @@ -41,8 +44,8 @@ that don't. Always leave the code cleaner than you found it. Stdlib ------ -Each stdlib module (anything under `lib/`, e.g. `lib/pure/os.nim`) should -preferably have a corresponding separate test file, e.g. `tests/stdlib/tos.nim`. +Each stdlib module (anything under ``lib/``, e.g. ``lib/pure/os.nim``) should +preferably have a corresponding separate test file, e.g. ``tests/stdlib/tos.nim``. The old convention was to add a `when isMainModule:` block in the source file, which only gets executed when the tester is building the file. @@ -71,36 +74,36 @@ Sample test: # doAssert with `not` can now be done as follows: doAssert not (1 == 2) -Always refer to a GitHub issue using the following exact syntax: `bug #1234` as shown +Always refer to a GitHub issue using the following exact syntax: ``bug #1234`` as shown above, so that it's consistent and easier to search or for tooling. Some browser extensions (e.g. https://github.com/sindresorhus/refined-github) will even turn those in clickable links when it works. Rationale for using a separate test file instead of `when isMainModule:` block: * allows custom compiler flags or testing options (see details below) -* faster CI since they can be joined in `megatest` (combined into a single test) +* faster CI since they can be joined in ``megatest`` (combined into a single test) * avoids making the parser do un-necessary work when a source file is merely imported * avoids mixing source and test code when reporting line of code statistics or code coverage Compiler -------- -The tests for the compiler use a testing tool called `testament`. They are all -located in `tests/` (e.g.: `tests/destructor/tdestructor3.nim`). +The tests for the compiler use a testing tool called `testament`:cmd:. They are all +located in ``tests/`` (e.g.: ``tests/destructor/tdestructor3.nim``). Each test has its own file. All test files are prefixed with `t`. If you want to create a file for import into another test only, use the prefix `m`. At the beginning of every test is the expected behavior of the test. Possible keys are: -- `cmd`: A compilation command template e.g. `nim $target --threads:on $options $file` +- `cmd`: A compilation command template e.g. `nim $target --threads:on $options $file`:cmd: - `output`: The expected output (stdout + stderr), most likely via `echo` - `exitcode`: Exit code of the test (via `exit(number)`) - `errormsg`: The expected compiler error message - `file`: The file the errormsg was produced at - `line`: The line the errormsg was produced at -For a full spec, see here: `testament/specs.nim` +For a full spec, see here: ``testament/specs.nim`` An example of a test: @@ -124,51 +127,51 @@ Running tests You can run the tests with -:: +.. code-block:: cmd ./koch tests which will run a good subset of tests. Some tests may fail. If you only want to see the output of failing tests, go for -:: - +```cmd ./koch tests --failing all +``` You can also run only a single category of tests. A category is a subdirectory -in the `tests` directory. There are a couple of special categories; for a -list of these, see `testament/categories.nim`, at the bottom. +in the ``tests/`` directory. There are a couple of special categories; for a +list of these, see ``testament/categories.nim``, at the bottom. -:: +.. code:: cmd - ./koch tests c lib # compiles/runs stdlib modules, including `isMainModule` tests + ./koch tests c lib # compiles / runs stdlib modules, including `isMainModule` tests ./koch tests c megatest # runs a set of tests that can be combined into 1 To run a single test: -:: +.. code:: cmd ./koch test run / # e.g.: tuples/ttuples_issues ./koch test run tests/stdlib/tos.nim # can also provide relative path For reproducible tests (to reproduce an environment more similar to the one run by Continuous Integration on travis/appveyor), you may want to disable your -local configuration (e.g. in `~/.config/nim/nim.cfg`) which may affect some +local configuration (e.g. in ``~/.config/nim/nim.cfg``) which may affect some tests; this can also be achieved by using -`export XDG_CONFIG_HOME=pathtoAlternateConfig` before running `./koch` +`export XDG_CONFIG_HOME=pathtoAlternateConfig`:cmd: before running `./koch`:cmd: commands. Comparing tests =============== -Test failures can be grepped using `Failure:`. +Test failures can be grepped using ``Failure:``. The tester can compare two test runs. First, you need to create a reference test. You'll also need to the commit id, because that's what the tester needs to know in order to compare the two. -:: +.. code:: cmd git checkout devel DEVEL_COMMIT=$(git rev-parse HEAD) @@ -176,15 +179,15 @@ the tester needs to know in order to compare the two. Then switch over to your changes and run the tester again. -:: +.. code:: cmd git checkout your-changes ./koch tests -Then you can ask the tester to create a `testresults.html` which will +Then you can ask the tester to create a ``testresults.html`` which will tell you if any new tests passed/failed. -:: +.. code:: cmd ./koch tests --print html $DEVEL_COMMIT @@ -219,14 +222,14 @@ Documentation When contributing new procs, be sure to add documentation, especially if the proc is public. Even private procs benefit from documentation and can be -viewed using `nim doc --docInternal foo.nim`. +viewed using `nim doc --docInternal foo.nim`:cmd:. Documentation begins on the line following the `proc` definition, and is prefixed by `##` on each line. Runnable code examples are also encouraged, to show typical behavior with a few test cases (typically 1 to 3 `assert` statements, depending on complexity). -These `runnableExamples` are automatically run by `nim doc mymodule.nim` -as well as `testament` and guarantee they stay in sync. +These `runnableExamples` are automatically run by `nim doc mymodule.nim`:cmd: +as well as `testament`:cmd: and guarantee they stay in sync. .. code-block:: nim proc addBar*(a: string): string = @@ -238,7 +241,7 @@ as well as `testament` and guarantee they stay in sync. See `parentDir `_ example. The RestructuredText Nim uses has a special syntax for including code snippets -embedded in documentation; these are not run by `nim doc` and therefore are +embedded in documentation; these are not run by `nim doc`:cmd: and therefore are not guaranteed to stay in sync, so `runnableExamples` is almost always preferred: .. code-block:: nim @@ -250,9 +253,9 @@ not guaranteed to stay in sync, so `runnableExamples` is almost always preferred ## echo someProc() # "something" result = "something" # single-hash comments do not produce documentation -The `.. code-block:: nim` followed by a newline and an indentation instructs the -`nim doc` command to produce syntax-highlighted example code with the -documentation (`.. code-block::` is sufficient from inside a nim module). +The ``.. code-block:: nim`` followed by a newline and an indentation instructs the +`nim doc`:cmd: command to produce syntax-highlighted example code with the +documentation (``.. code-block::`` is sufficient from inside a nim module). When forward declaration is used, the documentation should be included with the first appearance of the proc. @@ -298,10 +301,10 @@ example below) from `Nim Index`_ can be used in doc comment this way: Inline monospaced text can be input using \`single backticks\` or \`\`double backticks\`\`. The former are syntactically highlighted, the latter are not. -To avoid accidental highlighting follow this rule in `*.nim` files: +To avoid accidental highlighting follow this rule in ``*.nim`` files: * use single backticks for fragments of code in Nim and other - programming languages, including identifiers, in `*.nim` files. + programming languages, including identifiers, in ``*.nim`` files. For languages other than Nim add a role after final backtick, e.g. for C++ inline highlighting:: @@ -313,18 +316,20 @@ To avoid accidental highlighting follow this rule in `*.nim` files: `SELECT * FROM ;`:code: + Highlight shell commands by ``:cmd:`` role; for command line options use + ``:option:`` role, e.g.: \`--docInternal\`:option:. + * prefer double backticks otherwise: * for file names: \`\`os.nim\`\` * for fragments of strings **not** enclosed by `"` and `"` and not related to code, e.g. text of compiler messages - * for command line options: \`\`--docInternal\`\` * also when code ends with a standalone ``\`` (otherwise a combination of ``\`` and a final \` would get escaped) -.. Note:: `*.rst` files have `:literal:` as their default role. - So for them the rule above is only applicable if the `:nim:` role - is set up manually as the default:: +.. Note:: ``*.rst`` files have ``:literal:`` as their default role. + So for them the rule above is only applicable if the ``:nim:`` role + is set up manually as the default [*]_:: .. role:: nim(code) :language: nim @@ -333,6 +338,8 @@ To avoid accidental highlighting follow this rule in `*.nim` files: The first 2 lines are for other RST implementations, including Github one. + .. [*] this is fulfilled when ``doc/rstcommon.rst`` is included. + Best practices ============== @@ -350,7 +357,7 @@ to avoid name conflicts across packages. # if in nim sources when defined(allocStats): discard # bad, can cause conflicts when defined(nimAllocStats): discard # preferred - # if in a pacakge `cligen`: + # if in a package `cligen`: when defined(debug): discard # bad, can cause conflicts when defined(cligenDebug): discard # preferred @@ -372,7 +379,7 @@ Design with method call syntax chaining in mind # can be called as: `getLines().foo(false)` .. _avoid_quit: -Use exceptions (including assert / doAssert) instead of `quit` +Use exceptions (including `assert` / `doAssert`) instead of `quit` rationale: https://forum.nim-lang.org/t/4089 .. code-block:: nim @@ -382,7 +389,7 @@ rationale: https://forum.nim-lang.org/t/4089 .. _tests_use_doAssert: Use `doAssert` (or `unittest.check`, `unittest.require`), not `assert` in all -tests so they'll be enabled even with `--assertions:off`. +tests so they'll be enabled even with `--assertions:off`:option:. .. code-block:: nim @@ -391,10 +398,10 @@ tests so they'll be enabled even with `--assertions:off`. doAssert foo() # preferred .. _runnableExamples_use_assert: -An exception to the above rule is `runnableExamples` and `code-block` rst blocks +An exception to the above rule is `runnableExamples` and ``code-block`` rst blocks intended to be used as `runnableExamples`, which for brevity use `assert` -instead of `doAssert`. Note that `nim doc -d:danger main` won't pass `-d:danger` to the -`runnableExamples`, but `nim doc --doccmd:-d:danger main` would, and so would the +instead of `doAssert`. Note that `nim doc -d:danger main`:cmd: won't pass `-d:danger`:option: to the +`runnableExamples`, but `nim doc --doccmd:-d:danger main`:cmd: would, and so would the second example below: .. code-block:: nim @@ -437,8 +444,8 @@ https://github.com/nim-lang/Nim/pull/9335 and https://forum.nim-lang.org/t/4089 doAssert foo() == [1, 2] # preferred, except when not possible to do so. -The Git stuff -============= +The `git`:cmd: stuff +==================== General commit rules -------------------- @@ -446,12 +453,12 @@ General commit rules 1. Important, critical bugfixes that have a tiny chance of breaking somebody's code should be backported to the latest stable release branch (currently 1.4.x) and maybe also all the way back to the 1.0.x branch. - The commit message should contain the tag `[backport]` for "backport to all - stable releases" and the tag `[backport:$VERSION]` for backporting to the + The commit message should contain the tag ``[backport]`` for "backport to all + stable releases" and the tag ``[backport:$VERSION]`` for backporting to the given $VERSION. 2. If you introduce changes which affect backward compatibility, - make breaking changes, or have PR which is tagged as `[feature]`, + make breaking changes, or have PR which is tagged as ``[feature]``, the changes should be mentioned in `the changelog `_. @@ -462,29 +469,29 @@ General commit rules your editor reformatted automatically the code or whatever different reason, this should be excluded from the commit. - *Tip:* Never commit everything as is using `git commit -a`, but review - carefully your changes with `git add -p`. + *Tip:* Never commit everything as is using `git commit -a`:cmd:, but review + carefully your changes with `git add -p`:cmd:. 4. Changes should not introduce any trailing whitespace. - Always check your changes for whitespace errors using `git diff --check` - or add the following `pre-commit` hook: + Always check your changes for whitespace errors using `git diff --check`:cmd: + or add the following ``pre-commit`` hook: - .. code-block:: sh + .. code:: cmd #!/bin/sh git diff --check --cached || exit $? 5. Describe your commit and use your common sense. - Example commit message: + Example commit message:: - `Fixes #123; refs #124` + Fixes #123; refs #124 - indicates that issue `#123` is completely fixed (GitHub may automatically - close it when the PR is committed), wheres issue `#124` is referenced + indicates that issue ``#123`` is completely fixed (GitHub may automatically + close it when the PR is committed), wheres issue ``#124`` is referenced (e.g.: partially fixed) and won't close the issue when committed. 6. PR body (not just PR title) should contain references to fixed/referenced github - issues, e.g.: `fix #123` or `refs #123`. This is so that you get proper cross + issues, e.g.: ``fix #123`` or ``refs #123``. This is so that you get proper cross referencing from linked issue to the PR (github won't make those links with just PR title, and commit messages aren't always sufficient to ensure that, e.g. can't be changed after a PR is merged). @@ -492,7 +499,7 @@ General commit rules 7. Commits should be always be rebased against devel (so a fast forward merge can happen) - e.g.: use `git pull --rebase origin devel`. This is to avoid messing up + e.g.: use `git pull --rebase origin devel`:cmd:. This is to avoid messing up git history. Exceptions should be very rare: when rebase gives too many conflicts, simply squash all commits using the script shown in @@ -508,7 +515,7 @@ Continuous Integration (CI) 1. Continuous Integration is by default run on every push in a PR; this clogs the CI pipeline and affects other PR's; if you don't need it (e.g. for WIP or - documentation only changes), add `[skip ci]` to your commit message title. + documentation only changes), add ``[skip ci]`` to your commit message title. This convention is supported by our github actions pipelines and our azure pipeline as well as our former other pipelines: `Appveyor `_ @@ -531,16 +538,16 @@ Debugging CI failures, flaky tests, etc will re-trigger all CI jobs (even successful ones, which can be wasteful). Instead, follow these instructions to only restart the jobs that failed: - * Azure: if on your own fork, it's possible from inside azure console - (e.g. `dev.azure.com/username/username/_build/results?buildId=1430&view=results`) via `rerun failed jobs` on top. - If either on you own fork or in Nim repo, it's possible from inside GitHub UI - under checks tab, see https://github.com/timotheecour/Nim/issues/211#issuecomment-629751569 - * GitHub actions: under "Checks" tab, click "Re-run jobs" in the right. - * builds.sr.ht: create a sourcehut account so you can restart a PR job as illustrated. - builds.sr.ht also allows you to ssh to a CI machine which can help a lot for debugging - issues, see docs in https://man.sr.ht/builds.sr.ht/build-ssh.md and - https://drewdevault.com/2019/08/19/Introducing-shell-access-for-builds.html; see - https://man.sr.ht/tutorials/set-up-account-and-git.md to generate and upload ssh keys. + * Azure: if on your own fork, it's possible from inside azure console + (e.g. ``dev.azure.com/username/username/_build/results?buildId=1430&view=results``) via ``rerun failed jobs`` on top. + If either on you own fork or in Nim repo, it's possible from inside GitHub UI + under checks tab, see https://github.com/timotheecour/Nim/issues/211#issuecomment-629751569 + * GitHub actions: under "Checks" tab, click "Re-run jobs" in the right. + * builds.sr.ht: create a sourcehut account so you can restart a PR job as illustrated. + builds.sr.ht also allows you to ssh to a CI machine which can help a lot for debugging + issues, see docs in https://man.sr.ht/builds.sr.ht/build-ssh.md and + https://drewdevault.com/2019/08/19/Introducing-shell-access-for-builds.html; see + https://man.sr.ht/tutorials/set-up-account-and-git.md to generate and upload ssh keys. Code reviews @@ -554,15 +561,15 @@ Code reviews doesn't help much as it doesn't highlight moves. Instead, you can use something like this, see visual results `here `_: - .. code-block:: sh + .. code:: cmd git fetch origin pull/10431/head && git checkout FETCH_HEAD git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^ 3. In addition, you can view GitHub-like diffs locally to identify what was changed - within a code block using `diff-highlight` or `diff-so-fancy`, e.g.: + within a code block using `diff-highlight`:cmd: or `diff-so-fancy`:cmd:, e.g.: - .. code-block:: sh + :: # put this in ~/.gitconfig: [core] @@ -651,15 +658,15 @@ to existing modules is acceptable. For two reasons: Conventions ----------- -1. New stdlib modules should go under `Nim/lib/std/`. The rationale is to +1. New stdlib modules should go under ``Nim/lib/std/``. The rationale is to require users to import via `import std/foo` instead of `import foo`, which would cause potential conflicts with nimble packages. Note that this still applies for new modules in existing logical - directories, e.g.: use `lib/std/collections/foo.nim`, - not `lib/pure/collections/foo.nim`. + directories, e.g.: use ``lib/std/collections/foo.nim``, + not ``lib/pure/collections/foo.nim``. 2. New module names should prefer plural form whenever possible, e.g.: - `std/sums.nim` instead of `std/sum.nim`. In particular, this reduces + ``std/sums.nim`` instead of ``std/sum.nim``. In particular, this reduces chances of conflicts between module name and the symbols it defines. Furthermore, module names should use `snake_case` and not use capital letters, which cause issues when going from an OS without case diff --git a/doc/docstyle.rst b/doc/docstyle.rst index 7f3fa8cf2..df1f36dad 100644 --- a/doc/docstyle.rst +++ b/doc/docstyle.rst @@ -6,17 +6,17 @@ General Guidelines * See also `nep1`_ which should probably be merged here. * Authors should document anything that is exported; documentation for private - procs can be useful too (visible via `nim doc --docInternal foo.nim`). + procs can be useful too (visible via `nim doc --docInternal foo.nim`:cmd:). * Within documentation, a period (`.`) should follow each sentence (or sentence fragment) in a comment block. The documentation may be limited to one sentence fragment, but if multiple sentences are within the documentation, each sentence after the first should be complete and in present tense. * Documentation is parsed as a custom ReStructuredText (RST) with partial markdown support. * In nim sources, prefer single backticks to double backticks since it's simpler - and `nim doc` supports it. Likewise with rst files: `nim rst2html` will render those as monospace, and - adding `.. default-role:: code` to an rst file will also make those render as monospace when rendered directly + and `nim doc`:cmd: supports it. Likewise with ``rst`` files: `nim rst2html`:cmd: will render those as monospace, and + adding ``.. default-role:: code`` to an ``rst`` file will also make those render as monospace when rendered directly in tools such as github. -* In nim sources, for links, prefer `[link text](link.html)` to `` `link text`_ `` - since the syntax is simpler and markdown is more common (likewise, `nim rst2html` also supports it in rst files). +* (debatable) In nim sources, for links, prefer ``[link text](link.html)`` to `\`link text\`_`:code: + since the syntax is simpler and markdown is more common (likewise, `nim rst2html`:cmd: also supports it in ``rst`` files). .. code-block:: nim @@ -29,7 +29,7 @@ Module-level documentation -------------------------- Documentation of a module is placed at the top of the module itself. Each line of documentation begins with double hashes (`##`). -Sometimes `##[ multiline docs containing code ]##` is preferable, see `lib/pure/times.nim`. +Sometimes `##[ multiline docs containing code ]##` is preferable, see ``lib/pure/times.nim``. Code samples are encouraged, and should follow the general RST syntax: .. code-block:: Nim @@ -76,11 +76,11 @@ Whenever an example of usage would be helpful to the user, you should include on ## echo execCmdEx("git pull") ## drawOnScreen() runnableExamples: - # `runnableExamples` is usually preferred to `code-block`, when possible. + # `runnableExamples` is usually preferred to ``code-block``, when possible. doAssert addThree(3, 125, 6) == -122 result = x +% y +% z -The command `nim doc` will then correctly syntax highlight the Nim code within the documentation. +The command `nim doc`:cmd: will then correctly syntax highlight the Nim code within the documentation. Types ----- diff --git a/doc/nimdoc.css b/doc/nimdoc.css index ced791d16..6366d33dc 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -35,6 +35,8 @@ Modified by Boyd Greenfield and narimiran --escapeSequence: #c4891b; --number: #252dbe; --literal: #a4255b; + --program: #6060c0; + --option: #508000; --raw-data: #a4255b; } @@ -63,6 +65,8 @@ Modified by Boyd Greenfield and narimiran --escapeSequence: #bd93f9; --number: #bd93f9; --literal: #f1fa8c; + --program: #9090c0; + --option: #90b010; --raw-data: #8be9fd; } @@ -527,7 +531,6 @@ div.option-list-label { margin-left: -11.5em; margin-right: 0em; min-width: 11.5em; - font-weight: bolder; display: inline-block; vertical-align: top; } @@ -546,7 +549,7 @@ blockquote { border-left: 5px solid #bbc; } -.pre { +.pre, span.tok { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; font-weight: 500; font-size: 0.85em; @@ -557,6 +560,12 @@ blockquote { border-radius: 4px; } +span.tok { + border: 1px solid #808080; + padding-bottom: 0.1em; + margin-right: 0.2em; +} + pre { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; color: var(--text); @@ -844,9 +853,6 @@ span.classifier { span.classifier-delimiter { font-weight: bold; } -span.option { - white-space: nowrap; } - span.problematic { color: #b30000; } @@ -926,6 +932,21 @@ span.Preprocessor { span.Directive { color: #252dbe; } +span.option { + font-weight: bold; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; + color: var(--option); +} + +span.program { + font-weight: bold; + color: var(--program); + text-decoration: underline; + text-decoration-color: var(--hint); + text-decoration-thickness: 0.05em; + text-underline-offset: 0.15em; +} + span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, span.Other { color: var(--other); } diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 94cb2ebde..c0f4c9760 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -37,6 +37,18 @@ ## .. code:: Nim ## for l in ["C", "c++", "jAvA", "Nim", "c#"]: echo getSourceLanguage(l) ## +## There is also a `Cmd` pseudo-language supported, which is a simple generic +## shell/cmdline tokenizer (UNIX shell/Powershell/Windows Command): +## no escaping, no programming language constructs besides variable definition +## at the beginning of line. It supports these operators: +## +## .. code:: Cmd +## & && | || ( ) '' "" ; # for comments +## +## Instead of escaping always use quotes like here +## `nimgrep --ext:'nim|nims' file.name`:cmd: shows how to input ``|``. +## Any argument that contains ``.`` or ``/`` or ``\`` will be treated +## as a file or directory. import strutils @@ -45,7 +57,7 @@ from algorithm import binarySearch type SourceLanguage* = enum langNone, langNim, langCpp, langCsharp, langC, langJava, - langYaml, langPython + langYaml, langPython, langCmd TokenClass* = enum gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber, gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit, @@ -53,7 +65,7 @@ type gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression, gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler, gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel, - gtReference, gtOther + gtReference, gtProgram, gtOption, gtOther GeneralTokenizer* = object of RootObj kind*: TokenClass start*, length*: int @@ -64,14 +76,17 @@ type const sourceLanguageToStr*: array[SourceLanguage, string] = ["none", - "Nim", "C++", "C#", "C", "Java", "Yaml", "Python"] + "Nim", "C++", "C#", "C", "Java", "Yaml", "Python", "Cmd"] tokenClassToStr*: array[TokenClass, string] = ["Eof", "None", "Whitespace", "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", "EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment", "RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData", "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink", - "Label", "Reference", "Other"] + "Label", "Reference", + # start from lower-case if there is a corresponding RST role (see rst.nim) + "program", "option", + "Other"] # The following list comes from doc/keywords.txt, make sure it is # synchronized with this array by running the module itself as a test case. @@ -898,6 +913,65 @@ proc pythonNextToken(g: var GeneralTokenizer) = "with", "yield"] nimNextToken(g, keywords) +proc cmdNextToken(g: var GeneralTokenizer) = + var pos = g.pos + g.start = g.pos + if g.state == low(TokenClass): + g.state = gtProgram + case g.buf[pos] + of ' ', '\t'..'\r': + g.kind = gtWhitespace + while g.buf[pos] in {' ', '\t'..'\r'}: + if g.buf[pos] == '\n': + g.state = gtProgram + inc(pos) + of '\'', '"': + g.kind = gtOption + let q = g.buf[pos] + inc(pos) + while g.buf[pos] notin {q, '\0'}: + inc(pos) + if g.buf[pos] == q: inc(pos) + of '#': + g.kind = gtComment + while g.buf[pos] notin {'\n', '\0'}: + inc(pos) + of '&', '|': + g.kind = gtOperator + inc(pos) + if g.buf[pos] == g.buf[pos-1]: inc(pos) + g.state = gtProgram + of '(': + g.kind = gtOperator + g.state = gtProgram + inc(pos) + of ')': + g.kind = gtOperator + inc(pos) + of ';': + g.state = gtProgram + g.kind = gtOperator + inc(pos) + of '\0': g.kind = gtEof + else: + if g.state == gtProgram: + g.kind = gtProgram + g.state = gtOption + else: + g.kind = gtOption + while g.buf[pos] notin {' ', '\t'..'\r', '&', '|', '(', ')', '\'', '"', '\0'}: + if g.buf[pos] == ';' and g.buf[pos+1] == ' ': + # (check space because ';' can be used inside arguments in Win bat) + break + if g.kind == gtOption and g.buf[pos] in {'/', '\\', '.'}: + g.kind = gtIdentifier # for file/dir name + elif g.kind == gtProgram and g.buf[pos] == '=': + g.kind = gtIdentifier # for env variable setting at beginning of line + g.state = gtProgram + inc(pos) + g.length = pos - g.pos + g.pos = pos + proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) = g.lang = lang case lang @@ -909,6 +983,7 @@ proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) = of langJava: javaNextToken(g) of langYaml: yamlNextToken(g) of langPython: pythonNextToken(g) + of langCmd: cmdNextToken(g) when isMainModule: var keywords: seq[string] diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 7c4b92f88..cb65791ff 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -23,10 +23,10 @@ ## ## Nim can output the result to HTML [#html]_ or Latex [#latex]_. ## -## .. [#html] commands ``nim doc`` for ``*.nim`` files and -## ``nim rst2html`` for ``*.rst`` files +## .. [#html] commands `nim doc`:cmd: for ``*.nim`` files and +## `nim rst2html`:cmd: for ``*.rst`` files ## -## .. [#latex] command ``nim rst2tex`` for ``*.rst``. +## .. [#latex] command `nim rst2tex`:cmd: for ``*.rst``. ## ## If you are new to RST please consider reading the following: ## @@ -78,14 +78,21 @@ ## ## * directives: ``code-block`` [cmp:Sphinx]_, ``title``, ## ``index`` [cmp:Sphinx]_ -## * predefined roles ``:nim:`` (default), ``:c:`` (C programming language), -## ``:python:``, ``:yaml:``, ``:java:``, ``:cpp:`` (C++), ``:csharp`` (C#). -## That is every language that `highlite `_ supports. -## They turn on appropriate syntax highlighting in inline code. +## * predefined roles +## - ``:nim:`` (default), ``:c:`` (C programming language), +## ``:python:``, ``:yaml:``, ``:java:``, ``:cpp:`` (C++), ``:csharp`` (C#). +## That is every language that `highlite `_ supports. +## They turn on appropriate syntax highlighting in inline code. ## -## .. Note:: default role for Nim files is ``:nim:``, -## for ``*.rst`` it's currently ``:literal:``. +## .. Note:: default role for Nim files is ``:nim:``, +## for ``*.rst`` it's currently ``:literal:``. ## +## - generic command line highlighting roles: +## - ``:cmd:`` for commands and common shells syntax +## - ``:program:`` for executable names [cmp:Sphinx]_ +## (one can just use ``:cmd:`` on single word) +## - ``:option:`` for command line options [cmp:Sphinx]_ +## - ``:tok:``, a role for highlighting of programming language tokens ## * ***triple emphasis*** (bold and italic) using \*\*\* ## * ``:idx:`` role for \`interpreted text\` to include the link to this ## text into an index (example: `Nim index`_). @@ -95,11 +102,11 @@ ## //compile compile the project ## //doc generate documentation ## -## Here the dummy `//` will disappear, while options ``compile`` -## and ``doc`` will be left in the final document. +## Here the dummy `//` will disappear, while options `compile`:option: +## and `doc`:option: will be left in the final document. ## ## .. [cmp:Sphinx] similar but different from the directives of -## Python `Sphinx directives`_ extensions +## Python `Sphinx directives`_ and `Sphinx roles`_ extensions ## ## .. _`extra features`: ## @@ -144,7 +151,7 @@ ## ----- ## ## See `Nim DocGen Tools Guide `_ for the details about -## ``nim doc``, ``nim rst2html`` and ``nim rst2tex`` commands. +## `nim doc`:cmd:, `nim rst2html`:cmd: and `nim rst2tex`:cmd: commands. ## ## See `packages/docutils/rstgen module `_ to know how to ## generate HTML or Latex strings to embed them into your documents. @@ -156,6 +163,7 @@ ## .. _RST roles list: https://docutils.sourceforge.io/docs/ref/rst/roles.html ## .. _Nim index: https://nim-lang.org/docs/theindex.html ## .. _Sphinx directives: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html +## .. _Sphinx roles: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html import os, strutils, rstast, std/enumutils, algorithm, lists, sequtils, @@ -530,7 +538,7 @@ proc defaultRole(options: RstParseOptions): string = # mirror highlite.nim sourceLanguageToStr with substitutions c++ cpp, c# csharp const supportedLanguages = ["nim", "yaml", "python", "java", "c", - "cpp", "csharp"] + "cpp", "csharp", "cmd"] proc whichRoleAux(sym: string): RstNodeKind = let r = sym.toLowerAscii @@ -543,6 +551,7 @@ proc whichRoleAux(sym: string): RstNodeKind = of "sup", "superscript": result = rnSup # literal and code are the same in our implementation of "code": result = rnInlineLiteral + of "program", "option", "tok": result = rnCodeFragment # c++ currently can be spelled only as cpp, c# only as csharp elif r in supportedLanguages: result = rnInlineCode @@ -1113,10 +1122,10 @@ proc toInlineCode(n: PRstNode, language: string): PRstNode = lb.add newLeaf(s) result.add lb -proc toUnknownRole(n: PRstNode, roleName: string): PRstNode = +proc toOtherRole(n: PRstNode, kind: RstNodeKind, roleName: string): PRstNode = let newN = newRstNode(rnInner, n.sons) let newSons = @[newN, newLeaf(roleName)] - result = newRstNode(rnUnknownRole, newSons) + result = newRstNode(kind, newSons) proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var newKind = n.kind @@ -1144,8 +1153,8 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = # a role: let (roleName, lastIdx) = getRefname(p, p.idx+1) newKind = whichRole(p, roleName) - if newKind == rnUnknownRole: - result = n.toUnknownRole(roleName) + if newKind in {rnUnknownRole, rnCodeFragment}: + result = n.toOtherRole(newKind, roleName) elif newKind == rnInlineCode: result = n.toInlineCode(language=roleName) else: @@ -1417,8 +1426,8 @@ proc parseInline(p: var RstParser, father: PRstNode) = if k == rnInlineCode: n = n.toInlineCode(language=roleName) parseUntil(p, n, "`", false) # bug #17260 - if k == rnUnknownRole: - n = n.toUnknownRole(roleName) + if k in {rnUnknownRole, rnCodeFragment}: + n = n.toOtherRole(k, roleName) father.add(n) elif isInlineMarkupStart(p, "`"): var n = newRstNode(rnInterpretedText) diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 00f3f2b35..81e3ba6d9 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -56,7 +56,9 @@ type # * `file#id '_ rnSubstitutionDef, # a definition of a substitution # Inline markup: - rnInlineCode, + rnInlineCode, # interpreted text with code in a known language + rnCodeFragment, # inline code for highlighting with the specified + # class (which cannot be inferred from context) rnUnknownRole, # interpreted text with an unknown role rnSub, rnSup, rnIdx, rnEmphasis, # "*" diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 1b9334a77..40ed88954 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1198,7 +1198,8 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = "$1", result) of rnOptionGroup: renderAux(d, n, - "
    $1
    ", + "
    " & + "$1
    ", "\\item[$1]", result) of rnDescription: renderAux(d, n, "
    $1
    ", @@ -1319,13 +1320,22 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "|$1|", "|$1|", result) of rnDirective: renderAux(d, n, "", "", result) - of rnUnknownRole: + of rnUnknownRole, rnCodeFragment: var tmp0 = "" var tmp1 = "" renderRstToOut(d, n.sons[0], tmp0) renderRstToOut(d, n.sons[1], tmp1) - dispA(d.target, result, "$1", "\\span$2{$1}", - [tmp0, tmp1]) + var class = tmp1 + # don't allow missing role break latex compilation: + if d.target == outLatex and n.kind == rnUnknownRole: class = "Other" + if n.kind == rnCodeFragment: + dispA(d.target, result, + "" & + "$1", + "\\texttt{\\span$2{$1}}", [tmp0, class]) + else: # rnUnknownRole, not necessarily code/monospace font + dispA(d.target, result, "$1", "\\span$2{$1}", + [tmp0, class]) of rnSub: renderAux(d, n, "$1", "\\rstsub{$1}", result) of rnSup: renderAux(d, n, "$1", "\\rstsup{$1}", result) of rnEmphasis: renderAux(d, n, "$1", "\\emph{$1}", result) diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index ced791d16..6366d33dc 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -35,6 +35,8 @@ Modified by Boyd Greenfield and narimiran --escapeSequence: #c4891b; --number: #252dbe; --literal: #a4255b; + --program: #6060c0; + --option: #508000; --raw-data: #a4255b; } @@ -63,6 +65,8 @@ Modified by Boyd Greenfield and narimiran --escapeSequence: #bd93f9; --number: #bd93f9; --literal: #f1fa8c; + --program: #9090c0; + --option: #90b010; --raw-data: #8be9fd; } @@ -527,7 +531,6 @@ div.option-list-label { margin-left: -11.5em; margin-right: 0em; min-width: 11.5em; - font-weight: bolder; display: inline-block; vertical-align: top; } @@ -546,7 +549,7 @@ blockquote { border-left: 5px solid #bbc; } -.pre { +.pre, span.tok { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; font-weight: 500; font-size: 0.85em; @@ -557,6 +560,12 @@ blockquote { border-radius: 4px; } +span.tok { + border: 1px solid #808080; + padding-bottom: 0.1em; + margin-right: 0.2em; +} + pre { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; color: var(--text); @@ -844,9 +853,6 @@ span.classifier { span.classifier-delimiter { font-weight: bold; } -span.option { - white-space: nowrap; } - span.problematic { color: #b30000; } @@ -926,6 +932,21 @@ span.Preprocessor { span.Directive { color: #252dbe; } +span.option { + font-weight: bold; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; + color: var(--option); +} + +span.program { + font-weight: bold; + color: var(--program); + text-decoration: underline; + text-decoration-color: var(--hint); + text-decoration-thickness: 0.05em; + text-underline-offset: 0.15em; +} + span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, span.Other { color: var(--other); } diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 29747f4e8..0af6ba566 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -40,6 +40,10 @@ proc toHtml(input: string, proc id(str: string): string = """""" & str & "" proc op(str: string): string = """""" & str & "" proc pu(str: string): string = """""" & str & "" +proc optionListLabel(opt: string): string = + """
    """ & + opt & + "
    " suite "YAML syntax highlighting": test "Basics": @@ -1382,10 +1386,10 @@ Test1 check(output.count("") == 2) check(output.count("
    -m
    """ & + check(optionListLabel("-m") & """
    desc
    """ in output) - check("""
    -n
    """ & + check(optionListLabel("-n") & """
    very long desc
    """ in output) @@ -1400,13 +1404,13 @@ Test1 let output = input.toHtml check(output.count("-m""" & + check(optionListLabel("-m") & """
    desc
    """ in output) - check("""
    -n
    """ & + check(optionListLabel("-n") & """
    very long desc
    """ in output) - check("""
    -d
    """ & + check(optionListLabel("-d") & """
    option
    """ in output) check "

    option

    " notin output @@ -1421,13 +1425,13 @@ Test1 let output = input.toHtml check(output.count("compile""" & + check(optionListLabel("compile") & """
    compile1
    """ in output) - check("""
    doc
    """ & + check(optionListLabel("doc") & """
    doc1 cont
    """ in output) - check("""
    -d
    """ & + check(optionListLabel("-d") & """
    option
    """ in output) check "

    option

    " notin output From 4471141a1d68158f3f23c6584d1f0434807c0203 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 21 Apr 2021 23:53:31 +0800 Subject: [PATCH 2479/4254] fix #7535(Poor error message for spawn when a procedure (without calling it)) (#17774) --- compiler/semexprs.nim | 7 +++++-- tests/parallel/t7535.nim | 11 +++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 tests/parallel/t7535.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 353831736..97f88869e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2282,12 +2282,15 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mSpawn: markUsed(c, n.info, s) when defined(leanCompiler): - localError(c.config, n.info, "compiler was built without 'spawn' support") - result = n + result = localErrorNode(c, n, "compiler was built without 'spawn' support") else: result = setMs(n, s) for i in 1.. 1 and n[1].kind notin nkCallKinds: + return localErrorNode(c, n, n[1].info, "'spawn' takes a call expression; got " & $n[1]) + let typ = result[^1].typ if not typ.isEmptyType: if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar: diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim new file mode 100644 index 000000000..a6bc0dabe --- /dev/null +++ b/tests/parallel/t7535.nim @@ -0,0 +1,11 @@ +discard """ + matrix: "--threads:on" + errormsg: "'spawn' takes a call expression; got proc (x: uint32) = echo [x]" +""" + +import threadpool + +# bug #7535 +proc print_parallel_nok(r: uint32) = + for x in 0..r: + spawn (proc (x: uint32) = echo x) From fb32fff8dcf2b15a469e5cce07b10d88aa6352ee Mon Sep 17 00:00:00 2001 From: Sivchari <55221074+sivchari@users.noreply.github.com> Date: Thu, 22 Apr 2021 02:47:01 +0900 Subject: [PATCH 2480/4254] js generates spurious >>> on shr (#17767) * js generates spurious >>> on shr * Add shr arithmetic test * fix variables from const to let during testing --- compiler/jsgen.nim | 3 +-- tests/stdlib/tarithmetics.nim | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/stdlib/tarithmetics.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index e75ff182f..53ce45e96 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -683,8 +683,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) - let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size) - r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc] + r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) diff --git a/tests/stdlib/tarithmetics.nim b/tests/stdlib/tarithmetics.nim new file mode 100644 index 000000000..296ccd56e --- /dev/null +++ b/tests/stdlib/tarithmetics.nim @@ -0,0 +1,49 @@ +discard """ + targets: "c cpp js" +""" + +# TODO: in future work move existing arithmetic tests (tests/arithm/*) into this file +# FYI https://github.com/nim-lang/Nim/pull/17767 + +template main = + # put all arithmetic tests + + block tshr: + block: # Signed types + let + a1 = -3 + a2 = -2 + b1 = -4'i8 + b2 = 1'i8 + c1 = -5'i16 + c2 = 1'i16 + d1 = -7i32 + d2 = 1'i32 + e1 = -9'i64 + e2 = 1'i64 + doAssert a1 shr a2 == -1 + doAssert b1 shr b2 == -2 + doAssert c1 shr c2 == -3 + doAssert d1 shr d2 == -4 + doAssert e1 shr e2 == -5 + + block: # Unsigned types + let + a1 = 3'u + a2 = 2'u + b1 = 2'u8 + b2 = 1'u8 + c1 = 5'u16 + c2 = 1'u16 + d1 = 6'u32 + d2 = 1'u32 + e1 = 8'u64 + e2 = 1'u64 + doAssert a1 shr a2 == 0 + doAssert b1 shr b2 == 1 + doAssert c1 shr c2 == 2 + doAssert d1 shr d2 == 3 + doAssert e1 shr e2 == 4 + +static: main() +main() From 53c898de4105049c767804d0d2c520f31a86b874 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 22 Apr 2021 14:08:56 +0800 Subject: [PATCH 2481/4254] fix #17812 (repr fails to compile with ARC/ORC) (#17816) --- lib/system/repr_v2.nim | 2 +- tests/arc/t17812.nim | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/arc/t17812.nim diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index d456f4454..618cc2b40 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -84,7 +84,7 @@ proc repr*(p: pointer): string = proc repr*(p: proc): string = ## repr of a proc as its address - repr(cast[pointer](p)) + repr(cast[ptr pointer](unsafeAddr p)[]) template repr*(x: distinct): string = repr(distinctBase(typeof(x))(x)) diff --git a/tests/arc/t17812.nim b/tests/arc/t17812.nim new file mode 100644 index 000000000..bcd5f3a93 --- /dev/null +++ b/tests/arc/t17812.nim @@ -0,0 +1,29 @@ +discard """ + targets: "c js" + matrix: "--gc:refc; --gc:arc" +""" + +import std/times + +block: # bug #17812 + block: + type + Task = object + cb: proc () + + proc hello() = discard + + + let t = Task(cb: hello) + + doAssert t.repr.len > 0 + + + block: + type MyObj = object + field: DateTime + + + proc `$`(o: MyObj): string = o.repr + + doAssert ($MyObj()).len > 0 From 56859fe8516cd3e8191f9162c6409aeed8493941 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 22 Apr 2021 12:04:13 +0200 Subject: [PATCH 2482/4254] Windows: separate DLLs are not required anymore --- readme.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/readme.md b/readme.md index fa7a2d86d..9a07ae56b 100644 --- a/readme.md +++ b/readme.md @@ -84,10 +84,6 @@ Next, run the appropriate build shell script for your platform: * `build_all.sh` (Linux, Mac) * `build_all.bat` (Windows) -Windows requires a number of other dependencies that you may need to install including -PCRE and OpenSSL. Nim hosts a zip package containing known working versions of the -required DLLs [here](https://nim-lang.org/download/dlls.zip). - Finally, once you have finished the build steps (on Windows, Mac, or Linux) you should add the ``bin`` directory to your PATH. From e4a3feeb92940a9b3c4ce88fc808a0cdff2e4e9c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 22 Apr 2021 23:07:22 -0700 Subject: [PATCH 2483/4254] add `--processing:dots|filenames|off` to customize `hintProcessing` (#17817) --- changelog.md | 2 ++ compiler/ccgtypes.nim | 2 +- compiler/commands.nim | 10 ++++++++++ compiler/msgs.nim | 2 +- compiler/options.nim | 32 +++++++++++++++--------------- compiler/passaux.nim | 7 ++++--- doc/advopt.txt | 2 ++ drnim/tests/config.nims | 2 +- nimsuggest/config.nims | 2 ++ nimsuggest/tester.nim | 9 ++++++--- nimsuggest/tests/tchk1.nim | 2 +- nimsuggest/tests/tchk_compiles.nim | 2 +- nimsuggest/tests/ttempl_inst.nim | 2 +- testament/testament.nim | 2 +- tests/misc/trunner.nim | 2 +- 15 files changed, 50 insertions(+), 30 deletions(-) create mode 100644 nimsuggest/config.nims diff --git a/changelog.md b/changelog.md index 30fe237be..7b4a2438a 100644 --- a/changelog.md +++ b/changelog.md @@ -343,6 +343,8 @@ - Added `--filenames:abs|canonical|magic` which replaces --listFullPaths:on|off +- Added `--processing:dots|filenames|off` which customizes `hintProcessing` + - Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fa58b5651..767525fd5 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1018,7 +1018,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; var flags = 0 if not containsGarbageCollectedRef(typ): flags = flags or 1 if not canFormAcycle(typ): flags = flags or 2 - #else MessageOut("can contain a cycle: " & typeToString(typ)) + #else echo("can contain a cycle: " & typeToString(typ)) if flags != 0: m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)]) discard cgsym(m, "TNimType") diff --git a/compiler/commands.nim b/compiler/commands.nim index 0733e500a..278199bc0 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -900,6 +900,16 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "canonical": conf.filenameOption = foCanonical of "legacyrelproj": conf.filenameOption = foLegacyRelProj else: localError(conf, info, "expected: abs|canonical|legacyRelProj, got: $1" % arg) + of "processing": + incl(conf.notes, hintProcessing) + incl(conf.mainPackageNotes, hintProcessing) + case arg.normalize + of "dots": conf.hintProcessingDots = true + of "filenames": conf.hintProcessingDots = false + of "off": + excl(conf.notes, hintProcessing) + excl(conf.mainPackageNotes, hintProcessing) + else: localError(conf, info, "expected: dots|filenames|off, got: $1" % arg) of "listfullpaths": # xxx in future work, use `warningDeprecated` conf.filenameOption = if switchOn(arg): foAbs else: foCanonical diff --git a/compiler/msgs.nim b/compiler/msgs.nim index f08722cc7..93ca8d7cc 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -545,7 +545,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, if conf.structuredErrorHook != nil: conf.structuredErrorHook(conf, info, s & kindmsg, sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): - if msg == hintProcessing: + if msg == hintProcessing and conf.hintProcessingDots: msgWrite(conf, ".") else: styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg, diff --git a/compiler/options.nim b/compiler/options.nim index 2aaaf5844..7044e64bd 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -287,6 +287,7 @@ type implicitCmd*: bool # whether some flag triggered an implicit `command` selectedGC*: TGCMode # the selected GC (+) exc*: ExceptionSystem + hintProcessingDots*: bool # true for dots, false for filenames verbosity*: int # how verbose the compiler is numberOfProcessors*: int # number of processors lastCmdTime*: float # when caas is enabled, we measure each command @@ -458,20 +459,25 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool when defined(nimDebugUtils): import debugutils +proc initConfigRefCommon(conf: ConfigRef) = + conf.selectedGC = gcRefc + conf.verbosity = 1 + conf.hintProcessingDots = true + conf.options = DefaultOptions + conf.globalOptions = DefaultGlobalOptions + conf.filenameOption = foAbs + conf.foreignPackageNotes = foreignPackageNotesDefault + conf.notes = NotesVerbosity[1] + conf.mainPackageNotes = NotesVerbosity[1] + proc newConfigRef*(): ConfigRef = result = ConfigRef( - selectedGC: gcRefc, cCompiler: ccGcc, - verbosity: 1, - options: DefaultOptions, - globalOptions: DefaultGlobalOptions, macrosToExpand: newStringTable(modeStyleInsensitive), arcToExpand: newStringTable(modeStyleInsensitive), m: initMsgConfig(), - filenameOption: foAbs, cppDefines: initHashSet[string](), - headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: foreignPackageNotesDefault, - notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], + headerFile: "", features: {}, legacyFeatures: {}, configVars: newStringTable(modeStyleInsensitive), symbols: newStringTable(modeStyleInsensitive), packageCache: newPackageCache(), @@ -513,6 +519,7 @@ proc newConfigRef*(): ConfigRef = vmProfileData: newProfileData(), spellSuggestMax: spellSuggestSecretSauce, ) + initConfigRefCommon(result) setTargetFromSystem(result.target) # enable colors by default on terminals if terminal.isatty(stderr): @@ -522,18 +529,11 @@ proc newConfigRef*(): ConfigRef = proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. - # xxx FACTOR with `newConfigRef` when defined(nimDebugUtils): result = getConfigRef() else: - result = ConfigRef( - selectedGC: gcRefc, - verbosity: 1, - options: DefaultOptions, - globalOptions: DefaultGlobalOptions, - filenameOption: foAbs, - foreignPackageNotes: foreignPackageNotesDefault, - notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) + result = ConfigRef() + initConfigRefCommon(result) proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 715b7d676..9abc97be4 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -19,9 +19,10 @@ type config: ConfigRef proc verboseOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = - #MessageOut('compiling ' + s.name.s); - result = VerboseRef(config: graph.config, idgen: idgen) - rawMessage(graph.config, hintProcessing, s.name.s) + let conf = graph.config + result = VerboseRef(config: conf, idgen: idgen) + let path = toFilenameOption(conf, s.position.FileIndex, conf.filenameOption) + rawMessage(conf, hintProcessing, path) proc verboseProcess(context: PPassContext, n: PNode): PNode = result = n diff --git a/doc/advopt.txt b/doc/advopt.txt index 539cc620c..a783ebec5 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -39,6 +39,8 @@ Advanced options: --filenames:abs|canonical|legacyRelProj customize how filenames are rendered in compiler messages, defaults to `abs` (absolute) + --processing:dots|filenames|off + show files as they're being processed by nim compiler --declaredLocs:on|off show declaration locations in messages --spellSuggest|:num show at most `num >= 0` spelling suggestions on typos. if `num` is not specified (or `auto`), return diff --git a/drnim/tests/config.nims b/drnim/tests/config.nims index a6b0e7d88..346b0b4e6 100644 --- a/drnim/tests/config.nims +++ b/drnim/tests/config.nims @@ -3,7 +3,7 @@ switch("path", "$nim/testament/lib") # so we can `import stdtest/foo` in this di ## prevent common user config settings to interfere with testament expectations ## Indifidual tests can override this if needed to test for these options. switch("colors", "off") -switch("listFullPaths", "off") +switch("filenames", "canonical") switch("excessiveStackTrace", "off") # we only want to check the marked parts in the tests: diff --git a/nimsuggest/config.nims b/nimsuggest/config.nims new file mode 100644 index 000000000..ee19f9893 --- /dev/null +++ b/nimsuggest/config.nims @@ -0,0 +1,2 @@ +# xxx not sure why this flag isn't needed: switch("processing", "filenames") +switch("filenames", "canonical") diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 425430ede..9fcf7eacc 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -255,7 +255,6 @@ proc runEpcTest(filename: string): int = options={poStdErrToStdOut, poUsePath, poInteractive, poDaemon}) let outp = p.outputStream - let inp = p.inputStream var report = "" var socket = newSocket() try: @@ -315,8 +314,12 @@ proc runTest(filename: string): int = answer.add '\L' doReport(filename, answer, resp, report) finally: - inp.writeLine("quit") - inp.flush() + try: + inp.writeLine("quit") + inp.flush() + except: + # assume it's SIGPIPE, ie, the child already died + discard close(p) if report.len > 0: echo "==== STDIN ======================================" diff --git a/nimsuggest/tests/tchk1.nim b/nimsuggest/tests/tchk1.nim index c28b88b9b..794392c1f 100644 --- a/nimsuggest/tests/tchk1.nim +++ b/nimsuggest/tests/tchk1.nim @@ -17,7 +17,7 @@ proc main = discard """ $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tchk1 [Processing]";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tests/tchk1.nim [Processing]";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but got \'keyword template\'";;0 chk;;skUnknown;;;;Error;;$file;;14;;0;;"nestable statement requires indentation";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0 diff --git a/nimsuggest/tests/tchk_compiles.nim b/nimsuggest/tests/tchk_compiles.nim index 887a947b5..2afa06899 100644 --- a/nimsuggest/tests/tchk_compiles.nim +++ b/nimsuggest/tests/tchk_compiles.nim @@ -4,5 +4,5 @@ discard compiles(2 + "hello") discard """ $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tchk_compiles [Processing]";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tests/tchk_compiles.nim [Processing]";;0 """ diff --git a/nimsuggest/tests/ttempl_inst.nim b/nimsuggest/tests/ttempl_inst.nim index ed04a67ce..da413d99a 100644 --- a/nimsuggest/tests/ttempl_inst.nim +++ b/nimsuggest/tests/ttempl_inst.nim @@ -7,7 +7,7 @@ foo() discard """ $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;"ttempl_inst [Processing]";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tests/ttempl_inst.nim [Processing]";;0 chk;;skUnknown;;;;Hint;;$file;;4;;3;;"template/generic instantiation from here";;0 chk;;skUnknown;;;;Warning;;$file;;2;;11;;"foo [User]";;0 """ diff --git a/testament/testament.nim b/testament/testament.nim index b79b86e51..f259c7b96 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -104,7 +104,7 @@ proc isSuccess(input: string): bool = # not clear how to do the equivalent of pkg/regex's: re"FOO(.*?)BAR" in pegs # note: this doesn't handle colors, eg: `\e[1m\e[0m\e[32mHint:`; while we # could handle colors, there would be other issues such as handling other flags - # that may appear in user config (eg: `--listFullPaths`). + # that may appear in user config (eg: `--filenames`). # Passing `XDG_CONFIG_HOME= testament args...` can be used to ignore user config # stored in XDG_CONFIG_HOME, refs https://wiki.archlinux.org/index.php/XDG_Base_Directory input.startsWith("Hint: ") and input.endsWith("[SuccessX]") diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index df9ee9a48..505a06cf8 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -92,7 +92,7 @@ else: # don't run twice the same test of 5: nimcache / htmldocsDirname else: file.parentDir / htmldocsDirname - var cmd = fmt"{nim} doc --index:on --listFullPaths --hint:successX:on --nimcache:{nimcache} {options[i]} {file}" + var cmd = fmt"{nim} doc --index:on --filenames:abs --hint:successX:on --nimcache:{nimcache} {options[i]} {file}" removeDir(htmldocsDir) let (outp, exitCode) = execCmdEx(cmd) check exitCode == 0 From dbb053492a3c64236f7e8f9358b9c7f297ba241a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Apr 2021 01:05:23 -0700 Subject: [PATCH 2484/4254] followup #17561, skipping ci now implies green (#17813) * followup #17561, skip ci now implies green; [skip ci] * fixup [skip ci] * fixup test without skip ci * fixup [skip ci] * fixup2 [skip ci] * github actions now automatically supports [skip ci] --- .github/workflows/ci_docs.yml | 11 ----------- .github/workflows/ci_packages.yml | 11 ----------- azure-pipelines.yml | 33 ++++++++++++++++++++----------- ci/funs.sh | 22 +++++++++++++++++++++ 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index c9036d1d4..750613574 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -30,9 +30,6 @@ on: jobs: build: - # see D20210329T004830 - if: | - !contains(format('{0}', github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: @@ -54,14 +51,6 @@ jobs: with: fetch-depth: 2 - - name: 'Check whether to skip CI' - shell: bash - run: | - # see D20210329T004830 - commitMsg=$(git log --no-merges -1 --pretty=format:"%s") - echo commitMsg: $commitMsg - echo $commitMsg | grep -v '\[skip ci\]' - - name: 'Install build dependencies (macOS)' if: runner.os == 'macOS' run: brew install make diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index e7073ea23..7ebdc5144 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -3,9 +3,6 @@ on: [push, pull_request] jobs: build: - # see D20210329T004830 - if: | - !contains(format('{0}', github.event.pull_request.title), '[skip ci]') strategy: fail-fast: false matrix: @@ -23,14 +20,6 @@ jobs: with: fetch-depth: 2 - - name: 'Check whether to skip CI' - shell: bash - run: | - # see D20210329T004830 - commitMsg=$(git log --no-merges -1 --pretty=format:"%s") - echo commitMsg: $commitMsg - echo $commitMsg | grep -v '\[skip ci\]' - - name: 'Checkout csources' uses: actions/checkout@v2 with: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5c244648d..7e5b5c27d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,6 +7,10 @@ pr: include: - '*' +variables: +- name: skipci + value: false + jobs: - job: packages @@ -58,22 +62,22 @@ jobs: fetchDepth: 2 # see D20210329T004830 - bash: | - # D20210329T004830:here refs https://github.com/microsoft/azure-pipelines-agent/issues/2944 - # `--no-merges` is needed to avoid merge commits which occur for PR's. - # $(Build.SourceVersionMessage) is not helpful - # nor is `github.event.head_commit.message` for github actions. - commitMsg=$(git log --no-merges -1 --pretty=format:"%s") - echo commitMsg: $commitMsg - echo $commitMsg | grep -v '\[skip ci\]' # fails if [skip ci] not in commit msg + set -e + . ci/funs.sh + if nimIsCiSkip; then + echo '##vso[task.setvariable variable=skipci]true' + fi displayName: 'Check whether to skip CI' - bash: git clone --depth 1 https://github.com/nim-lang/csources_v1 csources displayName: 'Checkout Nim csources' + condition: and(succeeded(), eq(variables['skipci'], 'false')) - task: NodeTool@0 inputs: versionSpec: '12.x' displayName: 'Install node.js 12.x' + condition: and(succeeded(), eq(variables['skipci'], 'false')) - bash: | set -e @@ -83,7 +87,7 @@ jobs: echo_run sudo apt-fast install --no-install-recommends -yq \ libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg displayName: 'Install dependencies (amd64 Linux)' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) + condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) - bash: | set -e @@ -123,11 +127,11 @@ jobs: echo_run chmod 755 bin/g++ displayName: 'Install dependencies (i386 Linux)' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) + condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) - bash: brew install boehmgc make sfml displayName: 'Install dependencies (OSX)' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) + condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin')) - bash: | set -e @@ -140,9 +144,10 @@ jobs: echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' displayName: 'Install dependencies (Windows)' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Windows_NT')) - bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin' + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Add build binaries to PATH' - bash: | @@ -155,15 +160,18 @@ jobs: echo_run node -v echo_run echo '##[section]make version' echo_run make -v + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'System information' - bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)" + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Get csources version' - task: Cache@2 inputs: key: 'csources | "$(Agent.OS)" | $(CPU) | $(csources_version)' path: csources/bin + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Restore built csources' - bash: | @@ -192,13 +200,16 @@ jobs: fi echo_run cp csources/bin/nim$ext bin + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Build 1-stage compiler from csources' - bash: nim c koch + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Build koch' # set result to omit the "bash exited with error code '1'" message - bash: ./koch runCI || echo '##vso[task.complete result=Failed]' + condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'Run CI' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/ci/funs.sh b/ci/funs.sh index de56ef152..7f82e1ca3 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -1,4 +1,5 @@ # utilities used in CI pipelines to avoid duplication. +# Avoid top-level statements. echo_run () { # echo's a command before running it, which helps understanding logs @@ -6,3 +7,24 @@ echo_run () { echo "$@" "$@" } + +nimGetLastCommit() { + git log --no-merges -1 --pretty=format:"%s" +} + +nimIsCiSkip(){ + # D20210329T004830:here refs https://github.com/microsoft/azure-pipelines-agent/issues/2944 + # `--no-merges` is needed to avoid merge commits which occur for PR's. + # $(Build.SourceVersionMessage) is not helpful + # nor is `github.event.head_commit.message` for github actions. + # Note: `[skip ci]` is now handled automatically for github actions, see https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/ + commitMsg=$(nimGetLastCommit) + echo commitMsg: "$commitMsg" + if [[ $commitMsg == *"[skip ci]"* ]]; then + echo "skipci: true" + return 0 + else + echo "skipci: false" + return 1 + fi +} From dce0b3b002fcbac716bada039bed4a02eb501744 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Apr 2021 02:28:42 -0700 Subject: [PATCH 2485/4254] refactor all code that builds csources (#17815) * refactor all code that builds csources * fixup * nim_csourcesDir_v0 + nim_csourcesDir * remove deprecated, unused scripts from ci/ * reuse nimCsourcesHash in ci * simplify CI pipelines by reusing nimBuildCsourcesIfNeeded * simplify ci_docs.yml by reusing nimBuildCsourcesIfNeeded * cleanup * use csources_v1 as destination dir * fixup * remove pushCsources * address comment: remove build.sh support for now * fixup --- .builds/freebsd.yml | 6 +-- .builds/openbsd_0.yml | 8 ++-- .builds/openbsd_1.yml | 8 ++-- .github/workflows/ci.yml.disabled | 25 ++--------- .github/workflows/ci_docs.yml | 51 +++------------------ .github/workflows/ci_packages.yml | 25 ++--------- .gitignore | 3 ++ .travis.yml | 4 +- appveyor.yml.disabled | 8 ++-- azure-pipelines.yml | 50 ++++----------------- build_all.bat | 9 ++-- build_all.sh | 46 +++---------------- ci/build.bat | 14 ------ ci/build.sh | 15 ------- ci/deps.bat | 4 -- ci/deps.sh | 16 ------- ci/funs.sh | 73 ++++++++++++++++++++++++++++++- ci/nsis_build.bat | 59 ------------------------- koch.nim | 36 ++------------- lib/std/private/globs.nim | 2 +- readme.md | 5 ++- tools/ci_generate.nim | 8 ++-- 22 files changed, 136 insertions(+), 339 deletions(-) delete mode 100644 ci/build.bat delete mode 100644 ci/build.sh delete mode 100644 ci/deps.bat delete mode 100644 ci/deps.sh delete mode 100644 ci/nsis_build.bat diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 443be798a..c1fb80253 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -14,10 +14,10 @@ environment: CC: /usr/bin/clang tasks: - setup: | + set -e cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources - gmake -C csources -j $(sysctl -n hw.ncpu) - bin/nim c --skipUserCfg --skipParentCfg koch + . ci/funs.sh && nimBuildCsourcesIfNeeded + $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | cd Nim diff --git a/.builds/openbsd_0.yml b/.builds/openbsd_0.yml index c09f0f08d..e1d85d2a7 100644 --- a/.builds/openbsd_0.yml +++ b/.builds/openbsd_0.yml @@ -17,15 +17,15 @@ environment: CC: /usr/bin/clang tasks: - setup: | + set -e cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources - gmake -C csources -j $(sysctl -n hw.ncpuonline) - bin/nim c koch + . ci/funs.sh && nimBuildCsourcesIfNeeded + $nim_csources c koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | cd Nim if ! ./koch runCI; then - nim c -r tools/ci_testresults.nim + nim r tools/ci_testresults.nim exit 1 fi triggers: diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml index ffe449733..ed2ded056 100644 --- a/.builds/openbsd_1.yml +++ b/.builds/openbsd_1.yml @@ -17,15 +17,15 @@ environment: CC: /usr/bin/clang tasks: - setup: | + set -e cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources - gmake -C csources -j $(sysctl -n hw.ncpuonline) - bin/nim c koch + . ci/funs.sh && nimBuildCsourcesIfNeeded + $nim_csources c koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | cd Nim if ! ./koch runCI; then - nim c -r tools/ci_testresults.nim + nim r tools/ci_testresults.nim exit 1 fi triggers: diff --git a/.github/workflows/ci.yml.disabled b/.github/workflows/ci.yml.disabled index 183576456..62daf875a 100644 --- a/.github/workflows/ci.yml.disabled +++ b/.github/workflows/ci.yml.disabled @@ -1,3 +1,5 @@ +# out of date and unused but revivable + name: Continous Integration on: [push, pull_request] @@ -30,11 +32,6 @@ jobs: steps: - name: 'Checkout' uses: actions/checkout@v2 - - name: 'Checkout csources' - uses: actions/checkout@v2 - with: - repository: nim-lang/csources - path: csources - name: 'Install node.js 8.x' uses: actions/setup-node@v1 @@ -91,24 +88,10 @@ jobs: shell: bash run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - name: 'Build csources' + - name: 'Build csourcesAny' shell: bash - run: | - ncpu= - case '${{ runner.os }}' in - 'Linux') - ncpu=$(nproc) - ;; - 'macOS') - ncpu=$(sysctl -n hw.ncpu) - ;; - 'Windows') - ncpu=$NUMBER_OF_PROCESSORS - ;; - esac - [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 + run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' - make -C csources -j $ncpu CC=gcc ucpu='${{ matrix.cpu }}' - name: 'Build koch' shell: bash run: nim c koch diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 750613574..1459d6a31 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -70,53 +70,12 @@ jobs: shell: bash run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - name: 'Get current csources version' - id: csources-version + - name: 'Build csourcesAny' shell: bash - run: | - sha=$(git ls-remote https://github.com/nim-lang/csources_v1 master | cut -f 1) - echo "::set-output name=sha::$sha" - - - name: 'Get prebuilt csources from cache' - id: csources-cache - uses: actions/cache@v1 - with: - path: bin - key: '${{ matrix.os }}-${{ steps.csources-version.outputs.sha }}' - - - name: 'Checkout csources' - if: steps.csources-cache.outputs.cache-hit != 'true' - uses: actions/checkout@v2 - with: - repository: nim-lang/csources_v1 - path: csources - - - name: 'Build 1-stage compiler from csources' - shell: bash - run: | - ext= - [[ '${{ runner.os }}' == 'Windows' ]] && ext=.exe - if [[ ! -x bin/nim-csources$ext ]]; then - ncpu= - case '${{ runner.os }}' in - 'Linux') - ncpu=$(nproc) - ;; - 'macOS') - ncpu=$(sysctl -n hw.ncpu) - ;; - 'Windows') - ncpu=$NUMBER_OF_PROCESSORS - ;; - esac - [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 - - make -C csources -j $ncpu CC=gcc - cp bin/nim{,-csources}$ext - else - echo 'Cache hit, using prebuilt csources' - cp bin/nim{-csources,}$ext - fi + run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc + # was previously using caching via `actions/cache@v1` but this wasn't + # used in other CI pipelines and it's unclear the added complexity + # was worth the saving; can be revisited if needed. - name: 'Build koch' shell: bash diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 7ebdc5144..c6355bbcb 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -20,16 +20,11 @@ jobs: with: fetch-depth: 2 - - name: 'Checkout csources' - uses: actions/checkout@v2 - with: - repository: nim-lang/csources - path: csources - - name: 'Install node.js 12.x' uses: actions/setup-node@v1 with: node-version: '12.x' + - name: 'Install dependencies (Linux amd64)' if: runner.os == 'Linux' && matrix.cpu == 'amd64' run: | @@ -56,24 +51,10 @@ jobs: shell: bash run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - name: 'Build csources' + - name: 'Build csourcesAny' shell: bash - run: | - ncpu= - case '${{ runner.os }}' in - 'Linux') - ncpu=$(nproc) - ;; - 'macOS') - ncpu=$(sysctl -n hw.ncpu) - ;; - 'Windows') - ncpu=$NUMBER_OF_PROCESSORS - ;; - esac - [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 + run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' - make -C csources -j $ncpu CC=gcc ucpu='${{ matrix.cpu }}' - name: 'Build koch' shell: bash run: nim c koch diff --git a/.gitignore b/.gitignore index e9e742404..d22b8316a 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,10 @@ lib/**/*.html testament.db /tests/**/*.json /tests/**/*.js + /csources +/csources_v1 + /dist/ # /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it diff --git a/.travis.yml b/.travis.yml index 4c4c35334..13e5d151a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +# deprecated, out of date and unused sudo: false language: c @@ -22,9 +23,8 @@ addons: - valgrind before_script: - - git clone --depth 1 https://github.com/nim-lang/csources.git + - . ci/funs.sh && nimBuildCsourcesIfNeeded LD=$CC ucpu=$CPU - export PATH="$PWD/bin${PATH:+:$PATH}" - - make -C csources -j 2 LD=$CC ucpu=$CPU script: - echo "travis_fold:start:nim_c_koch" diff --git a/appveyor.yml.disabled b/appveyor.yml.disabled index 5468ac88a..b13c5d909 100644 --- a/appveyor.yml.disabled +++ b/appveyor.yml.disabled @@ -1,3 +1,4 @@ +# deprecated, out of date and unused version: '{build}' environment: @@ -23,10 +24,9 @@ install: - IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%" - 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul - SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%PATH% - - git clone --depth 1 https://github.com/nim-lang/csources - - cd csources - - build64.bat - - cd .. + # may need adjustments, untested, see similar examples here: + # https://chromium.googlesource.com/external/github.com/swig/swig/+/1e36f51346d95f8b9848e682c2eb986e9cb9b4f4/appveyor.yml + - bash -c ". ci/funs.sh && nimBuildCsourcesIfNeeded" build_script: - openssl version diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7e5b5c27d..8cf69f528 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -69,10 +69,6 @@ jobs: fi displayName: 'Check whether to skip CI' - - bash: git clone --depth 1 https://github.com/nim-lang/csources_v1 csources - displayName: 'Checkout Nim csources' - condition: and(succeeded(), eq(variables['skipci'], 'false')) - - task: NodeTool@0 inputs: versionSpec: '12.x' @@ -163,45 +159,17 @@ jobs: condition: and(succeeded(), eq(variables['skipci'], 'false')) displayName: 'System information' - - bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)" + - bash: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu=$(CPU) condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Get csources version' + displayName: 'Build csourcesAny' - - task: Cache@2 - inputs: - key: 'csources | "$(Agent.OS)" | $(CPU) | $(csources_version)' - path: csources/bin - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Restore built csources' - - - bash: | - set -e - . ci/funs.sh - ncpu= - ext= - case '$(Agent.OS)' in - 'Linux') - ncpu=$(nproc) - ;; - 'Darwin') - ncpu=$(sysctl -n hw.ncpu) - ;; - 'Windows_NT') - ncpu=$NUMBER_OF_PROCESSORS - ext=.exe - ;; - esac - [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 - - if [[ -x csources/bin/nim$ext ]]; then - echo_run echo "Found cached compiler, skipping build" - else - echo_run make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no - fi - - echo_run cp csources/bin/nim$ext bin - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Build 1-stage compiler from csources' + # this could be revived if performance justifies it (needs a few updates) + # - task: Cache@2 + # inputs: + # key: 'csourcesAny | "$(Agent.OS)" | $(CPU) | $(csources_version)' + # path: $(nim_csources) + # condition: and(succeeded(), eq(variables['skipci'], 'false')) + # displayName: 'Restore built csourcesAny' - bash: nim c koch condition: and(succeeded(), eq(variables['skipci'], 'false')) diff --git a/build_all.bat b/build_all.bat index 7967e2584..78a7a354a 100644 --- a/build_all.bat +++ b/build_all.bat @@ -1,10 +1,13 @@ @echo off rem build development version of the compiler; can be rerun safely -if not exist csources ( - git clone --depth 1 https://github.com/nim-lang/csources.git +rem TODO: call nimBuildCsourcesIfNeeded or auto-generate this file (from a nim script) +rem to avoid duplication. +if not exist csources_v1 ( + git clone --depth 1 https://github.com/nim-lang/csources_v1.git ) if not exist bin\nim.exe ( - cd csources + cd csources_v1 + git checkout a8a5241f9475099c823cfe1a5e0ca4022ac201ff if PROCESSOR_ARCHITECTURE == AMD64 ( SET ARCH=64 ) diff --git a/build_all.sh b/build_all.sh index c3c6e68b7..49504c8fe 100755 --- a/build_all.sh +++ b/build_all.sh @@ -1,52 +1,16 @@ #! /bin/sh # build development version of the compiler; can be rerun safely. -# arguments can be passed, e.g. `--os freebsd` +# arguments can be passed, e.g.: +# CC=gcc ucpu=amd64 uos=darwin set -u # error on undefined variables set -e # exit on first error -echo_run(){ - echo "$*" - "$@" -} +. ci/funs.sh +nimBuildCsourcesIfNeeded "$@" -[ -d csources ] || echo_run git clone -q --depth 1 https://github.com/nim-lang/csources.git - -nim_csources=bin/nim_csources - -build_nim_csources_via_script(){ - echo_run cd csources - echo_run sh build.sh "$@" -} - -build_nim_csources(){ - # avoid changing dir in case of failure - ( - if [ $# -ne 0 ]; then - # some args were passed (e.g.: `--cpu i386`), need to call build.sh - build_nim_csources_via_script "$@" - else - # no args, use multiple Make jobs (5X faster on 16 cores: 10s instead of 50s) - makeX=make - unamestr=$(uname) - if [ "$unamestr" = 'FreeBSD' ]; then - makeX=gmake - fi - nCPU=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) - which $makeX && echo_run $makeX -C csources -j $((nCPU + 2)) -l $nCPU || build_nim_csources_via_script - fi - ) - # keep $nim_csources in case needed to investigate bootstrap issues - # without having to rebuild from csources - echo_run cp bin/nim $nim_csources -} - -[ -f $nim_csources ] || echo_run build_nim_csources "$@" - -# Note: if fails, may need to `cd csources && git pull` +# Note: if fails, may need to update csourcesAny manually echo_run bin/nim c --skipUserCfg --skipParentCfg koch - echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg echo_run ./koch tools --skipUserCfg --skipParentCfg # Compile Nimble and other tools. - diff --git a/ci/build.bat b/ci/build.bat deleted file mode 100644 index 2227168e5..000000000 --- a/ci/build.bat +++ /dev/null @@ -1,14 +0,0 @@ -REM Some debug info -echo "Running on %CI_RUNNER_ID% (%CI_RUNNER_DESCRIPTION%) with tags %CI_RUNNER_TAGS%." -gcc -v - -git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources -cd csources -call build64.bat -cd .. -set PATH=%CD%\bin;%PATH% -nim -v -nim c koch -koch.exe boot -copy bin/nim bin/nimd -koch.exe boot -d:release diff --git a/ci/build.sh b/ci/build.sh deleted file mode 100644 index a89d011ed..000000000 --- a/ci/build.sh +++ /dev/null @@ -1,15 +0,0 @@ -sh ci/deps.sh - -# Build from C sources. -git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources -cd csources -sh build.sh -cd .. -# Add Nim to the PATH -export PATH=$(pwd)/bin${PATH:+:$PATH} -# Bootstrap. -nim -v -nim c koch -./koch boot -cp bin/nim bin/nimd -./koch boot -d:release diff --git a/ci/deps.bat b/ci/deps.bat deleted file mode 100644 index bda1fe14f..000000000 --- a/ci/deps.bat +++ /dev/null @@ -1,4 +0,0 @@ -nim e install_nimble.nims -nim e tests/test_nimscript.nims -nimble update -nimble install -y zip opengl sdl1 jester@#head niminst diff --git a/ci/deps.sh b/ci/deps.sh deleted file mode 100644 index f0f831a2a..000000000 --- a/ci/deps.sh +++ /dev/null @@ -1,16 +0,0 @@ -# Some debug info -echo "Running on $CI_RUNNER_ID ($CI_RUNNER_DESCRIPTION) with tags $CI_RUNNER_TAGS." - -# Packages -apt-get update -qq -apt-get install -y -qq build-essential git libcurl4-openssl-dev libsdl1.2-dev libgc-dev nodejs - -gcc -v - -export PATH=$(pwd)/bin${PATH:+:$PATH} - -# Nimble deps -nim e install_nimble.nims -nim e tests/test_nimscript.nims -nimble update -nimble install zip opengl sdl1 jester@#head niminst diff --git a/ci/funs.sh b/ci/funs.sh index 7f82e1ca3..7a6c66722 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -1,5 +1,7 @@ -# utilities used in CI pipelines to avoid duplication. +# Utilities used in CI pipelines and tooling to avoid duplication. # Avoid top-level statements. +# Prefer nim scripts whenever possible. +# functions starting with `_` are considered internal, less stable. echo_run () { # echo's a command before running it, which helps understanding logs @@ -28,3 +30,72 @@ nimIsCiSkip(){ return 1 fi } + +nimDefineVars(){ + nim_csourcesDir=csources_v1 # where we clone + nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git + nim_csourcesHash=a8a5241f9475099c823cfe1a5e0ca4022ac201ff + nim_csources=bin/nim_csources_$nim_csourcesHash +} + +_nimNumCpu(){ + # linux: $(nproc) + # FreeBSD | macOS: $(sysctl -n hw.ncpu) + # OpenBSD: $(sysctl -n hw.ncpuonline) + # windows: $NUMBER_OF_PROCESSORS ? + echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) +} + +_nimBuildCsourcesIfNeeded(){ + # if some systems cannot use make or gmake, we could add support for calling `build.sh` + # but this is slower (not parallel jobs) and would require making build.sh + # understand the arguments passed to the makefile (e.g. `CC=gcc ucpu=amd64 uos=darwin`), + # instead of `--cpu amd64 --os darwin`. + unamestr=$(uname) + # uname values: https://en.wikipedia.org/wiki/Uname + if [ "$unamestr" = 'FreeBSD' ]; then + makeX=gmake + elif [ "$unamestr" = 'OpenBSD' ]; then + makeX=gmake + else + makeX=make + fi + nCPU=$(_nimNumCpu) + echo_run which $makeX + # parallel jobs (5X faster on 16 cores: 10s instead of 50s) + echo_run $makeX -C $nim_csourcesDir -j $((nCPU + 2)) -l $nCPU "$@" + # keep $nim_csources in case needed to investigate bootstrap issues + # without having to rebuild + echo_run cp bin/nim $nim_csources +} + +nimCsourcesHash(){ + nimDefineVars + echo $nim_csourcesHash +} + +nimBuildCsourcesIfNeeded(){ + # goal: allow cachine each tagged version independently + # to avoid rebuilding, so that tools like `git bisect` + # can grab a cached past version without rebuilding. + nimDefineVars + ( + set -e + # avoid polluting caller scope with internal variable definitions. + if test -f "$nim_csources"; then + echo "$nim_csources exists." + else + if test -d "$nim_csourcesDir"; then + echo "$nim_csourcesDir exists." + else + # depth 1: adjust as needed in case useful for `git bisect` + echo_run git clone -q --depth 1 $nim_csourcesUrl "$nim_csourcesDir" + echo_run git -C "$nim_csourcesDir" checkout $nim_csourcesHash + fi + _nimBuildCsourcesIfNeeded "$@" + fi + + echo_run cp $nim_csources bin/nim + echo_run $nim_csources -v + ) +} diff --git a/ci/nsis_build.bat b/ci/nsis_build.bat deleted file mode 100644 index 12aff1b72..000000000 --- a/ci/nsis_build.bat +++ /dev/null @@ -1,59 +0,0 @@ -REM - Run the full testsuite; testament\tester all - -REM - Uncomment the list of changes in news.txt -REM - write a news ticker entry -REM - Update the version - -REM - Generate the full docs; koch web0 -REM - Generate the installers; -REM - Update the version in system.nim -REM - Test the installers -REM - Tag the release -REM - Merge devel into master -REM - Update csources - -set NIMVER=%1 - -Rem Build -docs file: -koch web0 -cd web\upload -7z a -tzip docs-%NIMVER%.zip *.html -move /y docs-%NIMVER%.zip download -cd ..\.. - -Rem Build csources -koch csources -d:release || exit /b - -rem Grab C sources and nimsuggest -git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources - -set PATH=%CD%\bin;%PATH% - -ReM Build Win32 version: - -set PATH=C:\Users\araq\projects\mingw32\bin;%PATH% -cd csources -call build.bat -cd .. -ReM Rebuilding koch is necessary because it uses its pointer size to determine -ReM which mingw link to put in the NSIS installer. -nim c --out:koch_temp koch || exit /b -koch_temp boot -d:release || exit /b -koch_temp nsis -d:release || exit /b -koch_temp zip -d:release || exit /b -dir build -move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x32.exe || exit /b -move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x32.zip || exit /b - - -ReM Build Win64 version: -set PATH=C:\Users\araq\projects\mingw64\bin;%PATH% -cd csources -call build64.bat -cd .. -nim c --out:koch_temp koch || exit /b -koch_temp boot -d:release || exit /b -koch_temp nsis -d:release || exit /b -koch_temp zip -d:release || exit /b -move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x64.exe || exit /b -move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x64.zip || exit /b diff --git a/koch.nim b/koch.nim index 49540eb6a..c78356b58 100644 --- a/koch.nim +++ b/koch.nim @@ -89,7 +89,6 @@ Commands for core developers: tests [options] run the testsuite (run a subset of tests by specifying a category, e.g. `tests cat async`) temp options creates a temporary compiler for testing - pushcsource push generated C sources to its repo Web options: --googleAnalytics:UA-... add the given google analytics code to the docs. To build the official docs, use UA-48159761-1 @@ -283,7 +282,7 @@ template doUseCpp(): bool = getEnv("NIM_COMPILE_TO_CPP", "false") == "true" proc boot(args: string) = ## bootstrapping is a process that involves 3 steps: - ## 1. use csources to produce nim1.exe. This nim1.exe is buggy but + ## 1. use csourcesAny to produce nim1.exe. This nim1.exe is buggy but ## rock solid for building a Nim compiler. It shouldn't be used for anything else. ## 2. use nim1.exe to produce nim2.exe. nim2.exe is the one you really need. ## 3. We use nim2.exe to build nim3.exe. nim3.exe is equal to nim2.exe except for timestamps. @@ -315,13 +314,8 @@ proc boot(args: string) = let ret = execCmdEx(nimStart & " --version") doAssert ret.exitCode == 0 let version = ret.output.splitLines[0] - # remove these when csources get updated - template addLib() = + if version.startsWith "Nim Compiler Version 0.20.0": extraOption.add " --lib:lib" # see https://github.com/nim-lang/Nim/pull/14291 - if version.startsWith "Nim Compiler Version 0.19.0": - extraOption.add " -d:nimBoostrapCsources0_19_0" - addLib() - elif version.startsWith "Nim Compiler Version 0.20.0": addLib() # in order to use less memory, we split the build into two steps: # --compileOnly produces a $project.json file and does not run GCC/Clang. @@ -587,29 +581,6 @@ proc runCI(cmd: string) = when defined(posix): execFold("Run nimsuggest tests", "nim c -r nimsuggest/tester") -proc pushCsources() = - if not dirExists("../csources/.git"): - quit "[Error] no csources git repository found" - csource("-d:danger") - let cwd = getCurrentDir() - try: - copyDir("build/c_code", "../csources/c_code") - copyFile("build/build.sh", "../csources/build.sh") - copyFile("build/build.bat", "../csources/build.bat") - copyFile("build/build64.bat", "../csources/build64.bat") - copyFile("build/makefile", "../csources/makefile") - - setCurrentDir("../csources") - for kind, path in walkDir("c_code"): - if kind == pcDir: - exec("git add " & path / "*.c") - exec("git commit -am \"updated csources to version " & NimVersion & "\"") - exec("git push origin master") - exec("git tag -am \"Version $1\" v$1" % NimVersion) - exec("git push origin v$1" % NimVersion) - finally: - setCurrentDir(cwd) - proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) xz(false, cmdLineRest) @@ -723,7 +694,8 @@ when isMainModule: of "tools": buildTools(op.cmdLineRest) bundleNimbleExe(latest, op.cmdLineRest) - of "pushcsource", "pushcsources": pushCsources() + of "pushcsource": + quit "use this instead: https://github.com/nim-lang/csources_v1/blob/master/push_c_code.nim" of "valgrind": valgrind(op.cmdLineRest) of "c2nim": bundleC2nim(op.cmdLineRest) of "drnim": buildDrNim(op.cmdLineRest) diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index a32f1d1b9..55f6a40bd 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -52,5 +52,5 @@ proc nativeToUnixPath*(path: string): string = when isMainModule: import sugar - for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", ".csources", "bin"]): + for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", "csources_v1", "csources", "bin"]): echo a diff --git a/readme.md b/readme.md index 9a07ae56b..37babf711 100644 --- a/readme.md +++ b/readme.md @@ -45,7 +45,7 @@ Compiling the Nim compiler is quite straightforward if you follow these steps: First, the C source of an older version of the Nim compiler is needed to bootstrap the latest version because the Nim compiler itself is written in the Nim programming language. Those C sources are available within the -[``nim-lang/csources``][csources-repo] repository. +[``nim-lang/csources_v1``][csources-v1-repo] repository. Next, to build from source you will need: @@ -217,7 +217,8 @@ Copyright © 2006-2021 Andreas Rumpf, all rights reserved. [nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ [nimble-repo]: https://github.com/nim-lang/nimble [nimsuggest-repo]: https://github.com/nim-lang/nimsuggest -[csources-repo]: https://github.com/nim-lang/csources +[csources-repo-deprecated]: https://github.com/nim-lang/csources +[csources-v1-repo]: https://github.com/nim-lang/csources_v1 [badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square [badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square [badge-nim-discord]: https://img.shields.io/discord/371759389889003530?color=blue&label=discord&logo=discord&logoColor=gold&style=flat-square diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index d13f28c33..e2580ff6b 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -33,15 +33,15 @@ environment: CC: /usr/bin/clang tasks: - setup: | + set -e cd Nim - git clone --depth 1 -q https://github.com/nim-lang/csources.git - gmake -C csources -j $(sysctl -n hw.ncpuonline) - bin/nim c koch + . ci/funs.sh && nimBuildCsourcesIfNeeded + $nim_csources c koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | cd Nim if ! ./koch runCI; then - nim c -r tools/ci_testresults.nim + nim r tools/ci_testresults.nim exit 1 fi triggers: From 511b6d2449c65cecc68eccbee1385e02758f0fd4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 23 Apr 2021 13:50:27 +0200 Subject: [PATCH 2486/4254] typos (#17824) --- compiler/ic/packed_ast.nim | 2 +- doc/destructors.rst | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 6fadde17c..17beda2c1 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -86,7 +86,7 @@ type typeInst*: PackedItemId nonUniqueId*: int32 - PackedNode* = object # 20 bytes + PackedNode* = object # 28 bytes kind*: TNodeKind flags*: TNodeFlags operand*: int32 # for kind in {nkSym, nkSymDef}: SymId diff --git a/doc/destructors.rst b/doc/destructors.rst index 01e2d2ee9..c93fcabe1 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -277,7 +277,7 @@ inference. But it has to be enabled via `--sinkInference:on`, either on the command line or via a `push` pragma. To enable it for a section of code, one can -use `{.push sinkInference: on.}`...`{.pop.}`. +use `{.push sinkInference: on.}` ... `{.pop.}`. The `.nosinks`:idx: pragma can be used to disable this inference for a single routine: @@ -661,12 +661,12 @@ There is no copy during assigning operations. y[0] = 'h' # copy The program above shows when the copy operations happen. -When mutating the variable `y`, the Nim compiler creates a fresh copy of `x`, -the variable `y` won't point to the string literal anymore. -Instead it points to the copy of `x` of which the memory can be mutated +When mutating the variable `y`, the Nim compiler creates a fresh copy of `x`, +the variable `y` won't point to the string literal anymore. +Instead it points to the copy of `x` of which the memory can be mutated and the variable `y` becomes a mutable string. -.. Note:: The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown. +.. Note:: The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown. Let's look at a silly example demonstrating this behaviour: From 3516f57e172cef22f583f43c7b16fd1f63921c6e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Apr 2021 04:51:24 -0700 Subject: [PATCH 2487/4254] manual: fix rendering of `Identifiers & Keywords` [skip ci] (#17811) --- doc/manual.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 15242cf7c..e98a0cc09 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -261,8 +261,9 @@ and underscores, with the following restrictions: * begins with a letter * does not end with an underscore `_` -* two immediate following underscores `__` are not allowed:: +* two immediate following underscores `__` are not allowed: +.. code-block:: letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff' digit ::= '0'..'9' IDENTIFIER ::= letter ( ['_'] (letter | digit) )* From 2abc936d511342265d2ef27c4b079dd49332d65a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Apr 2021 05:36:38 -0700 Subject: [PATCH 2488/4254] `typeof(voidStmt)` now works (#17807) * `typeof(voidStmt)` now works * remove typeOrVoid * add condsyms, and reference cligen https://github.com/c-blake/cligen/pull/193 * fixup * changelog [skip ci] * fixup --- changelog.md | 2 + compiler/condsyms.nim | 1 + compiler/sem.nim | 1 + compiler/semdata.nim | 3 ++ compiler/semexprs.nim | 4 +- lib/js/asyncjs.nim | 7 +--- testament/lib/stdtest/testutils.nim | 11 +++--- tests/typerel/tvoid.nim | 61 +++++++++++++++++++++++++++++ 8 files changed, 78 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 7b4a2438a..d7b568aa0 100644 --- a/changelog.md +++ b/changelog.md @@ -331,6 +331,8 @@ - Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields for an object type in the current scope. +- `typeof(voidStmt)` now works and returns `void`. + ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index bdecd7e53..6a49584c8 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -133,3 +133,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasCustomLiterals") defineSymbol("nimHasUnifiedTuple") defineSymbol("nimHasIterable") + defineSymbol("nimHasTypeofVoid") diff --git a/compiler/sem.nim b/compiler/sem.nim index 4020fc4d6..b80795354 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -525,6 +525,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext var c = newContext(graph, module) c.idgen = idgen c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil) + c.voidType = newType(tyVoid, nextTypeId(idgen), nil) if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") c.semConstExpr = semConstExpr diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 1c1a5159c..082a4813e 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -90,6 +90,9 @@ type TContext* = object of TPassContext # a context represents the module # that is currently being compiled enforceVoidContext*: PType + # for `if cond: stmt else: foo`, `foo` will be evaluated under + # enforceVoidContext != nil + voidType*: PType # for typeof(stmt) module*: PSym # the module sym belonging to the context currentScope*: PScope # current scope moduleScope*: PScope # scope for modules diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 97f88869e..2e229d861 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -83,7 +83,9 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExprCheck(c, n, flags) - if result.typ == nil or result.typ == c.enforceVoidContext: + if result.typ == nil and efInTypeof in flags: + result.typ = c.voidType + elif result.typ == nil or result.typ == c.enforceVoidContext: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index c62ac633f..861fe3fe2 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -158,10 +158,6 @@ proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importjs: "(new ## A helper for wrapping callback-based functions ## into promises and async procedures. -template typeOrVoid[T](a: T): type = - # xxx this is useful, make it public in std/typetraits in future work - T - template maybeFuture(T): untyped = # avoids `Future[Future[T]]` when T is Future: T @@ -221,7 +217,8 @@ when defined(nimExperimentalAsyncjsThen): assert witness == 3 template impl(call): untyped = - when typeOrVoid(call) is void: + # see D20210421T014713 + when typeof(block: call) is void: var ret: Future[void] else: var ret = default(maybeFuture(typeof(call))) diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 44048adbd..241ab1770 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -91,10 +91,6 @@ template disableVm*(body) = when nimvm: discard else: body -template typeOrVoid[T](a: T): type = - # FACTOR with asyncjs.typeOrVoid - T - macro assertAll*(body) = ## works in VM, unlike `check`, `require` runnableExamples: @@ -106,6 +102,9 @@ macro assertAll*(body) = result = newStmtList() for a in body: result.add genAst(a) do: - # better than: `when not compiles(typeof(a)):` - when typeOrVoid(a) is void: a + # D20210421T014713:here + # xxx pending https://github.com/nim-lang/Nim/issues/12030, + # `typeof` should introduce its own scope, so that this + # is sufficient: `typeof(a)` instead of `typeof(block: a)` + when typeof(block: a) is void: a else: doAssert a diff --git a/tests/typerel/tvoid.nim b/tests/typerel/tvoid.nim index 1e46d016e..0b7b525cc 100644 --- a/tests/typerel/tvoid.nim +++ b/tests/typerel/tvoid.nim @@ -35,3 +35,64 @@ ReturnT[void]() echo ReturnT[string]("abc") nothing() +block: # typeof(stmt) + proc fn1(): auto = + discard + proc fn2(): auto = + 1 + doAssert type(fn1()) is void + doAssert typeof(fn1()) is void + doAssert typeof(fn1()) isnot int + + doAssert type(fn2()) isnot void + doAssert typeof(fn2()) isnot void + when typeof(fn1()) is void: discard + else: doAssert false + + doAssert typeof(1+1) is int + doAssert typeof((discard)) is void + + type A1 = typeof(fn1()) + doAssert A1 is void + type A2 = type(fn1()) + doAssert A2 is void + doAssert A2 is A1 + + when false: + # xxx: MCS/UFCS doesn't work here: Error: expression 'fn1()' has no type (or is ambiguous) + type A3 = fn1().type + proc bar[T](a: T): string = $T + doAssert bar(1) == "int" + doAssert bar(fn1()) == "void" + + proc bar2[T](a: T): bool = T is void + doAssert not bar2(1) + doAssert bar2(fn1()) + + block: + proc bar3[T](a: T): T = a + let a1 = bar3(1) + doAssert compiles(block: + let a1 = bar3(fn2())) + doAssert not compiles(block: + let a2 = bar3(fn1())) + doAssert compiles(block: bar3(fn1())) + doAssert compiles(bar3(fn1())) + doAssert typeof(bar3(fn1())) is void + doAssert not compiles(sizeof(bar3(fn1()))) + + block: + var a = 1 + doAssert typeof((a = 2)) is void + doAssert typeof((a = 2; a = 3)) is void + doAssert typeof(block: + a = 2; a = 3) is void + + block: + var a = 1 + template bad1 = echo (a; a = 2) + doAssert not compiles(bad1()) + + block: + template bad2 = echo (nonexistant; discard) + doAssert not compiles(bad2()) From 80df21d9a368b0ad40f6c36b898861e75926b732 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Apr 2021 14:22:04 -0700 Subject: [PATCH 2489/4254] `--declaredlocs` now shows location for `T` instead of `static` in `proc fn(a: static T)` (#17795) --- compiler/types.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/types.nim b/compiler/types.nim index ba2cc76ce..b57e46444 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -131,7 +131,10 @@ proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) = addDeclaredLoc(result, conf, sym) proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = - let typ = typ.skipTypes(abstractInst - {tyRange}) + # xxx figure out how to resolve `tyGenericParam`, e.g. for + # proc fn[T](a: T, b: T) = discard + # fn(1.1, "a") + let typ = typ.skipTypes(abstractInst + {tyStatic} - {tyRange}) result.add " [$1" % typ.kind.toHumanStr if typ.sym != nil: result.add " declared in " & toFileLineCol(conf, typ.sym.info) From b667e288e27a09ce4f65166fc66a6b713350a9b6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Apr 2021 22:54:31 -0700 Subject: [PATCH 2490/4254] move travis, appveyor, ci.yml.disabled to `unmaintained/` (#17828) * move travis, appveyor, ci.yml.disabled to unmaintained * update some mentions of travis, appevyor * fix test --- changelog.md | 2 ++ doc/contributing.rst | 4 ++-- testament/specs.nim | 4 ++-- tests/async/tasyncdial.nim | 1 - tests/stdlib/tmemlinesBuf.nim | 8 +------- tests/stdlib/tnetdial.nim | 1 - tests/system/talloc.nim | 6 +----- tests/system/talloc2.nim | 2 +- .travis.yml => unmaintained/.travis.yml | 0 appveyor.yml.disabled => unmaintained/appveyor.yml | 0 .../workflows/ci.yml.disabled => unmaintained/ci.yml | 0 unmaintained/readme.md | 11 +++++++++++ 12 files changed, 20 insertions(+), 19 deletions(-) rename .travis.yml => unmaintained/.travis.yml (100%) rename appveyor.yml.disabled => unmaintained/appveyor.yml (100%) rename .github/workflows/ci.yml.disabled => unmaintained/ci.yml (100%) create mode 100644 unmaintained/readme.md diff --git a/changelog.md b/changelog.md index d7b568aa0..943b5d6df 100644 --- a/changelog.md +++ b/changelog.md @@ -57,6 +57,8 @@ - The unary slice `..b` was removed, use `0..b` instead or use `-d:nimLegacyUnarySlice` for a deprecation period. +- Moved `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled` to `unmaintained/`. + ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` diff --git a/doc/contributing.rst b/doc/contributing.rst index 81fa9f8eb..abc81dae6 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -155,7 +155,7 @@ To run a single test: ./koch test run tests/stdlib/tos.nim # can also provide relative path For reproducible tests (to reproduce an environment more similar to the one -run by Continuous Integration on travis/appveyor), you may want to disable your +run by Continuous Integration on github actions/azure pipelines), you may want to disable your local configuration (e.g. in ``~/.config/nim/nim.cfg``) which may affect some tests; this can also be achieved by using `export XDG_CONFIG_HOME=pathtoAlternateConfig`:cmd: before running `./koch`:cmd: @@ -517,7 +517,7 @@ Continuous Integration (CI) the CI pipeline and affects other PR's; if you don't need it (e.g. for WIP or documentation only changes), add ``[skip ci]`` to your commit message title. This convention is supported by our github actions pipelines and our azure pipeline - as well as our former other pipelines: + (using custom logic, which should complete in < 1mn) as well as our former other pipelines: `Appveyor `_ and `Travis `_. diff --git a/testament/specs.nim b/testament/specs.nim index 043f14ed3..38e4ed0db 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -328,9 +328,9 @@ proc parseSpec*(filename: string): TSpec = when defined(unix): result.err = reDisabled of "posix": when defined(posix): result.err = reDisabled - of "travis": + of "travis": # deprecated if isTravis: result.err = reDisabled - of "appveyor": + of "appveyor": # deprecated if isAppVeyor: result.err = reDisabled of "azure": if isAzure: result.err = reDisabled diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim index a755de74e..f0377dfd5 100644 --- a/tests/async/tasyncdial.nim +++ b/tests/async/tasyncdial.nim @@ -3,7 +3,6 @@ discard """ OK AF_INET OK AF_INET6 ''' - disabled: "travis" """ import diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim index ea607525d..3f0bd5182 100644 --- a/tests/stdlib/tmemlinesBuf.nim +++ b/tests/stdlib/tmemlinesBuf.nim @@ -1,8 +1,3 @@ -discard """ -output: "15" -disabled: "appveyor" -""" - import memfiles var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim") var buffer: string = "" @@ -11,5 +6,4 @@ for line in lines(inp, buffer): lineCount += 1 close(inp) - -echo lineCount +doAssert lineCount == 9, $lineCount # this file's number of lines diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim index f940bd630..3de00ff99 100644 --- a/tests/stdlib/tnetdial.nim +++ b/tests/stdlib/tnetdial.nim @@ -2,7 +2,6 @@ discard """ cmd: "nim c --threads:on $file" exitcode: 0 output: "OK" - disabled: "travis" """ import os, net, nativesockets, asyncdispatch diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim index 9b970fda0..a81fef481 100644 --- a/tests/system/talloc.nim +++ b/tests/system/talloc.nim @@ -1,8 +1,4 @@ -discard """ -disabled: "appveyor" -""" - -# appveyor is "out of memory" +# was: appveyor is "out of memory" var x: ptr int diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim index c498a3f4b..9d1687f34 100644 --- a/tests/system/talloc2.nim +++ b/tests/system/talloc2.nim @@ -5,7 +5,7 @@ joinable: false disabled: 32bit """ # no point to test this on system with smaller address space -# appveyor is "out of memory" +# was: appveyor is "out of memory" const nmax = 2*1024*1024*1024 diff --git a/.travis.yml b/unmaintained/.travis.yml similarity index 100% rename from .travis.yml rename to unmaintained/.travis.yml diff --git a/appveyor.yml.disabled b/unmaintained/appveyor.yml similarity index 100% rename from appveyor.yml.disabled rename to unmaintained/appveyor.yml diff --git a/.github/workflows/ci.yml.disabled b/unmaintained/ci.yml similarity index 100% rename from .github/workflows/ci.yml.disabled rename to unmaintained/ci.yml diff --git a/unmaintained/readme.md b/unmaintained/readme.md new file mode 100644 index 000000000..cddb15cd2 --- /dev/null +++ b/unmaintained/readme.md @@ -0,0 +1,11 @@ +Deprecated, unused and unmaintained files can be moved here when they have some value, +e.g. if someone want to revive them in their project or in this repo. If a deprecated and unused file +is redundant, it should just be removed instead. + +See also https://github.com/nim-lang/graveyard, which is maintained on a best effort basis +and has different goals. + +## table of contents +.travis.yml -> unmaintained/.travis.yml +appveyor.yml.disabled -> unmaintained/appveyor.yml +.github/workflows/ci.yml.disabled -> unmaintained/ci.yml From 6e8f0f8cfcd6d617074be9868027e39daaeba103 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 25 Apr 2021 01:33:29 +0800 Subject: [PATCH 2491/4254] add colon (#17834) --- compiler/pragmas.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/spawn.nim | 2 +- lib/pure/httpclient.nim | 2 +- lib/pure/selectors.nim | 2 +- tests/parallel/t7535.nim | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 35e75bc7b..3a2d9cede 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -824,7 +824,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) if k == wExportCpp: if c.config.backend != backendCpp: - localError(c.config, it.info, "exportcpp requires `cpp` backend, got " & $c.config.backend) + localError(c.config, it.info, "exportcpp requires `cpp` backend, got: " & $c.config.backend) else: incl(sym.flags, sfMangleCpp) incl(sym.flags, sfUsed) # avoid wrong hints diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2e229d861..cf8d4777f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2291,7 +2291,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result[i] = semExpr(c, n[i]) if n.len > 1 and n[1].kind notin nkCallKinds: - return localErrorNode(c, n, n[1].info, "'spawn' takes a call expression; got " & $n[1]) + return localErrorNode(c, n, n[1].info, "'spawn' takes a call expression; got: " & $n[1]) let typ = result[^1].typ if not typ.isEmptyType: diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 205197eaf..e57686cb4 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -334,7 +334,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp result = newNodeI(nkStmtList, n.info) if n.kind notin nkCallKinds: - localError(g.config, n.info, "'spawn' takes a call expression; got " & $n) + localError(g.config, n.info, "'spawn' takes a call expression; got: " & $n) return if optThreadAnalysis in g.config.globalOptions: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index b60894103..86708dc40 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -751,7 +751,7 @@ proc parseBody(client: HttpClient | AsyncHttpClient, headers: HttpHeaders, httpError("Got disconnected while trying to read body.") if recvLen != length: httpError("Received length doesn't match expected length. Wanted " & - $length & " got " & $recvLen) + $length & " got: " & $recvLen) else: # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index e78219aec..82550e09b 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -321,7 +321,7 @@ else: proc verifySelectParams(timeout: int) = # Timeout of -1 means: wait forever # Anything higher is the time to wait in milliseconds. - doAssert(timeout >= -1, "Cannot select with a negative value, got " & $timeout) + doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout) when defined(linux) and not defined(emscripten): include ioselects/ioselectors_epoll diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim index a6bc0dabe..052dcdc3a 100644 --- a/tests/parallel/t7535.nim +++ b/tests/parallel/t7535.nim @@ -1,6 +1,6 @@ discard """ matrix: "--threads:on" - errormsg: "'spawn' takes a call expression; got proc (x: uint32) = echo [x]" + errormsg: "'spawn' takes a call expression; got: proc (x: uint32) = echo [x]" """ import threadpool From e67593d31797cd6fa5e360c0f0a30fd02e596308 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sat, 24 Apr 2021 19:34:23 +0200 Subject: [PATCH 2492/4254] Remove unmaintained dir (#17833) --- unmaintained/.travis.yml | 52 ------------------- unmaintained/appveyor.yml | 37 -------------- unmaintained/ci.yml | 105 -------------------------------------- unmaintained/readme.md | 11 ---- 4 files changed, 205 deletions(-) delete mode 100644 unmaintained/.travis.yml delete mode 100644 unmaintained/appveyor.yml delete mode 100644 unmaintained/ci.yml delete mode 100644 unmaintained/readme.md diff --git a/unmaintained/.travis.yml b/unmaintained/.travis.yml deleted file mode 100644 index 13e5d151a..000000000 --- a/unmaintained/.travis.yml +++ /dev/null @@ -1,52 +0,0 @@ -# deprecated, out of date and unused -sudo: false -language: c - -dist: xenial - -matrix: - include: - - os: linux - env: - - NIM_COMPILE_TO_CPP=false - - CPU=amd64 - -addons: - apt: - # update the list above if more deps are introduced - packages: - - libcurl4-openssl-dev - - libsdl1.2-dev - - libgc-dev - - libsfml-dev - - libc6-dbg - - valgrind - -before_script: - - . ci/funs.sh && nimBuildCsourcesIfNeeded LD=$CC ucpu=$CPU - - export PATH="$PWD/bin${PATH:+:$PATH}" - -script: - - echo "travis_fold:start:nim_c_koch" - - nim c koch - - echo "travis_fold:end:nim_c_koch" - - echo "travis_fold:start:koch_boot" - - ./koch boot - - echo "travis_fold:end:koch_boot" - - echo "travis_fold:start:koch_doc" - - ./koch doc - - echo "travis_fold:end:koch_doc" - -before_deploy: - # Make https://nim-lang.github.io/Nim work the same as https://nim-lang.github.io/Nim/overview.html - - cp -f ./doc/html/overview.html ./doc/html/index.html - -deploy: # https://nim-lang.github.io/Nim - provider: pages - # local-dir *has* to be a relative path from the repo root. - local-dir: "doc/html" - skip-cleanup: true - github-token: "$GITHUB_OAUTH_TOKEN" - keep-history: false - on: - branch: devel diff --git a/unmaintained/appveyor.yml b/unmaintained/appveyor.yml deleted file mode 100644 index b13c5d909..000000000 --- a/unmaintained/appveyor.yml +++ /dev/null @@ -1,37 +0,0 @@ -# deprecated, out of date and unused -version: '{build}' - -environment: - DLLS_URL: https://nim-lang.org/download/dlls.zip - DLLS_ARCHIVE: dlls.zip - MINGW_DIR: mingw64 - MINGW_URL: https://nim-lang.org/download/mingw64.7z - MINGW_ARCHIVE: mingw64.7z - - matrix: - - NIM_TEST_PACKAGES: false - - NIM_TEST_PACKAGES: true - -cache: - - '%MINGW_ARCHIVE%' - - '%DLLS_ARCHIVE%' - - -install: - - ps: Install-Product node 8 # node 8 or later is required to test js async stuff - - IF not exist "%DLLS_ARCHIVE%" appveyor DownloadFile "%DLLS_URL%" -FileName "%DLLS_ARCHIVE%" - - 7z x -y "%DLLS_ARCHIVE%" -o"%CD%\BIN"> nul - - IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%" - - 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul - - SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%PATH% - # may need adjustments, untested, see similar examples here: - # https://chromium.googlesource.com/external/github.com/swig/swig/+/1e36f51346d95f8b9848e682c2eb986e9cb9b4f4/appveyor.yml - - bash -c ". ci/funs.sh && nimBuildCsourcesIfNeeded" - -build_script: - - openssl version - - openssl version -d - - bin\nim c koch - - koch runCI - -deploy: off diff --git a/unmaintained/ci.yml b/unmaintained/ci.yml deleted file mode 100644 index 62daf875a..000000000 --- a/unmaintained/ci.yml +++ /dev/null @@ -1,105 +0,0 @@ -# out of date and unused but revivable - -name: Continous Integration -on: [push, pull_request] - -jobs: - build: - strategy: - matrix: - os: [ubuntu-18.04, macos-10.15, windows-2019] - cpu: [amd64, i386] - cpp: ['false', 'true'] - pkg: ['false', 'true'] - exclude: - - os: ubuntu-18.04 - cpp: 'true' - - os: ubuntu-18.04 - pkg: 'true' - - os: macos-10.15 - cpu: i386 - - os: macos-10.15 - pkg: 'true' - - os: windows-2019 - cpu: i386 - - os: windows-2019 - cpp: 'true' - name: '${{ matrix.os }} (${{ matrix.cpu }}, cpp: ${{ matrix.cpp }}, pkg: ${{ matrix.pkg }})' - runs-on: ${{ matrix.os }} - env: - NIM_COMPILE_TO_CPP: ${{ matrix.cpp }} - NIM_TEST_PACKAGES: ${{ matrix.pkg }} - steps: - - name: 'Checkout' - uses: actions/checkout@v2 - - - name: 'Install node.js 8.x' - uses: actions/setup-node@v1 - with: - node-version: '8.x' - - name: 'Install dependencies (Linux amd64)' - if: runner.os == 'Linux' && matrix.cpu == 'amd64' - run: | - sudo apt-fast update -qq - DEBIAN_FRONTEND='noninteractive' \ - sudo apt-fast install --no-install-recommends -yq \ - libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ - valgrind libc6-dbg - - name: 'Install dependencies (Linux i386)' - if: runner.os == 'Linux' && matrix.cpu == 'i386' - run: | - sudo dpkg --add-architecture i386 - - sudo apt-fast update -qq - DEBIAN_FRONTEND='noninteractive' \ - sudo apt-fast install --no-install-recommends --allow-downgrades -yq \ - g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \ - libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 \ - libffi-dev:i386 - - cat << EOF > bin/gcc - #!/bin/bash - - exec $(which gcc) -m32 "\$@" - EOF - cat << EOF > bin/g++ - #!/bin/bash - - exec $(which g++) -m32 "\$@" - EOF - - chmod 755 bin/gcc - chmod 755 bin/g++ - - name: 'Install dependencies (macOS)' - if: runner.os == 'macOS' - run: brew install boehmgc make sfml - - name: 'Install dependencies (Windows)' - if: runner.os == 'Windows' - shell: bash - run: | - mkdir dist - curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z - curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip - 7z x dist/mingw64.7z -odist - 7z x dist/dlls.zip -obin - echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - - - name: 'Add build binaries to PATH' - shell: bash - run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - - name: 'Build csourcesAny' - shell: bash - run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' - - - name: 'Build koch' - shell: bash - run: nim c koch - - name: 'Run CI' - shell: bash - run: ./koch runCI - - - name: 'Show failed tests' - if: failure() - shell: bash - run: nim c -r tools/ci_testresults.nim diff --git a/unmaintained/readme.md b/unmaintained/readme.md deleted file mode 100644 index cddb15cd2..000000000 --- a/unmaintained/readme.md +++ /dev/null @@ -1,11 +0,0 @@ -Deprecated, unused and unmaintained files can be moved here when they have some value, -e.g. if someone want to revive them in their project or in this repo. If a deprecated and unused file -is redundant, it should just be removed instead. - -See also https://github.com/nim-lang/graveyard, which is maintained on a best effort basis -and has different goals. - -## table of contents -.travis.yml -> unmaintained/.travis.yml -appveyor.yml.disabled -> unmaintained/appveyor.yml -.github/workflows/ci.yml.disabled -> unmaintained/ci.yml From ffe4328b3513617be0d27c773d59bea441ec1c65 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 25 Apr 2021 01:25:31 -0700 Subject: [PATCH 2493/4254] `--usenimcache` (implied by `nim r main`) now caches some compile options to avoid recompiling when project was previously compiled with such options. (#17829) * `--usenimcache` (implied by `nim r main`) now caches some compile options to avoid recompiling when project was previously compiled with such options. * works * add test * changelog * use std/with --- changelog.md | 9 +++++++ compiler/extccomp.nim | 17 +++++++------ compiler/main.nim | 51 ++++++++++++++++++++++++++------------- compiler/options.nim | 15 ------------ tests/misc/mbetterrun.nim | 3 +++ tests/misc/trunner.nim | 48 +++++++++++++++++++++++++++--------- 6 files changed, 91 insertions(+), 52 deletions(-) create mode 100644 tests/misc/mbetterrun.nim diff --git a/changelog.md b/changelog.md index 943b5d6df..43ce43352 100644 --- a/changelog.md +++ b/changelog.md @@ -377,7 +377,16 @@ - `--hint:CC` now goes to stderr (like all other hints) instead of stdout. +- json build instructions are now generated in `$nimcache/outFileBasename.json` + instead of `$nimcache/projectName.json`. This allows avoiding recompiling a given project + compiled with different options if the output file differs. +- `--usenimcache` (implied by `nim r main`) now generates an output file that includes a hash of + some of the compilation options, which allows caching generated binaries: + nim r main # recompiles + nim r -d:foo main # recompiles + nim r main # uses cached binary + nim r main arg1 arg2 # ditto (runtime arguments are irrelevant) ## Tool changes diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 71a20fc47..3b415c499 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -934,9 +934,14 @@ proc callCCompiler*(conf: ConfigRef) = script.add("\n") generateScript(conf, script) - template hashNimExe(): string = $secureHashFile(os.getAppFilename()) +proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile = + # `outFile` is better than `projectName`, as it allows having different json + # files for a given source file compiled with different options; it also + # works out of the box with `hashMainCompilationParams`. + result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json") + proc writeJsonBuildInstructions*(conf: ConfigRef) = template lit(x: string) = f.write x template str(x: string) = @@ -993,8 +998,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = var buf = newStringOfCap(50) - - let jsonFile = conf.getNimcacheDir / RelativeFile(conf.projectName & ".json") + let jsonFile = conf.jsonBuildInstructionsFile conf.jsonBuildFile = jsonFile let output = conf.absOutFile @@ -1038,8 +1042,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = lit "\L}\L" close(f) -proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile): bool = - let jsonFile = toGeneratedFile(conf, projectfile, "json") +proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool = if not fileExists(jsonFile): return true if not fileExists(conf.absOutFile): return true result = false @@ -1090,11 +1093,9 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol echo "Warning: JSON processing failed: ", getCurrentExceptionMsg() result = true -proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) = - let jsonFile = toGeneratedFile(conf, projectfile, "json") +proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = try: let data = json.parseFile(jsonFile.string) - let output = data["outputFile"].getStr createDir output.parentDir let outputCurrent = $conf.absOutFile diff --git a/compiler/main.nim b/compiler/main.nim index 9c9a789cb..48fbd185c 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -19,7 +19,7 @@ import cgen, json, nversion, platform, nimconf, passaux, depends, vm, modules, - modulegraphs, tables, lineinfos, pathutils, vmprofiler + modulegraphs, tables, lineinfos, pathutils, vmprofiler, std/[sha1, with] import ic / [cbackend, integrity, navigator] from ic / ic import rodViewer @@ -80,15 +80,13 @@ when not defined(leanCompiler): proc commandCompileToC(graph: ModuleGraph) = let conf = graph.config - setOutFile(conf) extccomp.initVars(conf) semanticPasses(graph) if conf.symbolFiles == disabledSf: registerPass(graph, cgenPass) if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"): - let proj = changeFileExt(conf.projectFull, "") - if not changeDetectedViaJsonBuildInstructions(conf, proj): + if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile): # nothing changed graph.config.notes = graph.config.mainPackageNotes return @@ -117,27 +115,20 @@ proc commandCompileToC(graph: ModuleGraph) = writeDepsFile(graph) proc commandJsonScript(graph: ModuleGraph) = - let proj = changeFileExt(graph.config.projectFull, "") - extccomp.runJsonBuildInstructions(graph.config, proj) + extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile) proc commandCompileToJS(graph: ModuleGraph) = + let conf = graph.config when defined(leanCompiler): - globalError(graph.config, unknownLineInfo, "compiler wasn't built with JS code generator") + globalError(conf, unknownLineInfo, "compiler wasn't built with JS code generator") else: - let conf = graph.config conf.exc = excCpp - - if conf.outFile.isEmpty: - conf.outFile = RelativeFile(conf.projectName & ".js") - - #incl(gGlobalOptions, optSafeCode) - setTarget(graph.config.target, osJS, cpuJS) - #initDefines() - defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility + setTarget(conf.target, osJS, cpuJS) + defineSymbol(conf.symbols, "ecmascript") # For backward compatibility semanticPasses(graph) registerPass(graph, JSgenPass) compileProject(graph) - if optGenScript in graph.config.globalOptions: + if optGenScript in conf.globalOptions: writeDepsFile(graph) proc interactivePasses(graph: ModuleGraph) = @@ -186,6 +177,31 @@ proc commandView(graph: ModuleGraph) = const PrintRopeCacheStats = false +proc hashMainCompilationParams*(conf: ConfigRef): string = + ## doesn't have to be complete; worst case is a cache hit and recompilation. + var state = newSha1State() + with state: + update os.getAppFilename() # nim compiler + update conf.commandLine # excludes `arguments`, as it should + update $conf.projectFull # so that running `nim r main` from 2 directories caches differently + result = $SecureHash(state.finalize()) + +proc setOutFile*(conf: ConfigRef) = + proc libNameTmpl(conf: ConfigRef): string {.inline.} = + result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" + + if conf.outFile.isEmpty: + var base = conf.projectName + if optUseNimcache in conf.globalOptions: + base.add "_" & hashMainCompilationParams(conf) + let targetName = + if conf.backend == backendJs: base & ".js" + elif optGenDynLib in conf.globalOptions: + platform.OS[conf.target.targetOS].dllFrmt % base + elif optGenStaticLib in conf.globalOptions: libNameTmpl(conf) % base + else: base & platform.OS[conf.target.targetOS].exeExt + conf.outFile = RelativeFile targetName + proc mainCommand*(graph: ModuleGraph) = let conf = graph.config let cache = graph.cache @@ -220,6 +236,7 @@ proc mainCommand*(graph: ModuleGraph) = proc compileToBackend() = customizeForBackend(conf.backend) + setOutFile(conf) case conf.backend of backendC: commandCompileToC(graph) of backendCpp: commandCompileToC(graph) diff --git a/compiler/options.nim b/compiler/options.nim index 7044e64bd..209564d0a 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -970,18 +970,3 @@ proc floatInt64Align*(conf: ConfigRef): int16 = # to 4bytes (except with -malign-double) return 4 return 8 - -proc setOutFile*(conf: ConfigRef) = - proc libNameTmpl(conf: ConfigRef): string {.inline.} = - result = if conf.target.targetOS == osWindows: "$1.lib" else: "lib$1.a" - - if conf.outFile.isEmpty: - let base = conf.projectName - let targetName = - if optGenDynLib in conf.globalOptions: - platform.OS[conf.target.targetOS].dllFrmt % base - elif optGenStaticLib in conf.globalOptions: - libNameTmpl(conf) % base - else: - base & platform.OS[conf.target.targetOS].exeExt - conf.outFile = RelativeFile targetName diff --git a/tests/misc/mbetterrun.nim b/tests/misc/mbetterrun.nim new file mode 100644 index 000000000..d4f427af0 --- /dev/null +++ b/tests/misc/mbetterrun.nim @@ -0,0 +1,3 @@ +const mbetterrunVal {.strdefine.} = "" +static: echo "compiling: " & mbetterrunVal +echo "running: " & mbetterrunVal diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 505a06cf8..2a82ca9ee 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -29,13 +29,18 @@ const nimcache = buildDir / "nimcacheTrunner" # instead of `querySetting(nimcacheDir)`, avoids stomping on other parallel tests -proc runCmd(file, options = ""): auto = +proc runNimCmd(file, options = "", rtarg = ""): auto = let fileabs = testsDir / file.unixToNativePath doAssert fileabs.fileExists, fileabs - let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs}" + let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs} {rtarg}" result = execCmdEx(cmd) when false: echo result[0] & "\n" & result[1] # for debugging +proc runNimCmdChk(file, options = "", rtarg = ""): string = + let (ret, status) = runNimCmd(file, options, rtarg = rtarg) + doAssert status == 0, $(file, options) & "\n" & ret + ret + when defined(nimTrunnerFfi): block: # mevalffi when defined(openbsd): @@ -53,8 +58,8 @@ when defined(nimTrunnerFfi): hello world stderr hi stderr """ - let (output, exitCode) = runCmd("vm/mevalffi.nim", fmt"{opt} --experimental:compiletimeFFI") - let expected = fmt""" + let output = runNimCmdChk("vm/mevalffi.nim", fmt"{opt} --experimental:compiletimeFFI") + doAssert output == fmt""" {prefix}foo foo:100 foo:101 @@ -62,12 +67,10 @@ foo:102:103 foo:102:103:104 foo:0.03:asdf:103:105 ret=[s1:foobar s2:foobar age:25 pi:3.14] -""" - doAssert output == expected, output - doAssert exitCode == 0 +""", output else: # don't run twice the same test - import std/[strutils] + import std/strutils template check2(msg) = doAssert msg in output, output block: # tests with various options `nim doc --project --index --docroot` @@ -142,17 +145,16 @@ sub/mmain.idx""", context else: doAssert false block: # mstatic_assert - let (output, exitCode) = runCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad") + let (output, exitCode) = runNimCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad") check2 "sizeof(bool) == 2" check exitCode != 0 block: # ABI checks let file = "misc/msizeof5.nim" block: - let (output, exitCode) = runCmd(file, "-d:checkAbi") - doAssert exitCode == 0, output + discard runNimCmdChk(file, "-d:checkAbi") block: - let (output, exitCode) = runCmd(file, "-d:checkAbi -d:caseBad") + let (output, exitCode) = runNimCmd(file, "-d:checkAbi -d:caseBad") # on platforms that support _StaticAssert natively, errors will show full context, e.g.: # error: static_assert failed due to requirement 'sizeof(unsigned char) == 8' # "backend & Nim disagree on size for: BadImportcType{int64} [declared in mabi_check.nim(1, 6)]" @@ -293,3 +295,25 @@ tests/newconfig/bar/mfoo.nims""".splitLines let (outp, exitCode) = run "echo 1+2; quit(2)" check3 "3" in outp doAssert exitCode == 2 + + block: # nimBetterRun + let file = "misc/mbetterrun.nim" + const nimcache2 = buildDir / "D20210423T185116" + removeDir nimcache2 + # related to `-d:nimBetterRun` + let opt = fmt"-r --usenimcache --nimcache:{nimcache2}" + var ret = "" + for a in @["v1", "v2", "v1", "v3"]: + ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:{a}") + ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:v2", rtarg = "arg1 arg2") + # rt arguments should not cause a recompilation + doAssert ret == """ +compiling: v1 +running: v1 +compiling: v2 +running: v2 +running: v1 +compiling: v3 +running: v3 +running: v2 +""", ret From 17db15f9b1a03ac93cb6c5c0264f2b534ab8b2ab Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Sun, 25 Apr 2021 01:30:52 -0700 Subject: [PATCH 2494/4254] fix #17836 (typed macro isNil for proc params) (#17841) thanks @alaviss for the test --- compiler/ast.nim | 4 ++++ compiler/vm.nim | 4 ++-- tests/macros/t17836.nim | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/macros/t17836.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 02a2ae7a4..7090bc7ee 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1171,6 +1171,7 @@ when defined(useNodeIds): var gNodeId: int proc newNode*(kind: TNodeKind): PNode = + ## new node with unknown line info, no type, and no children result = PNode(kind: kind, info: unknownLineInfo) when defined(useNodeIds): result.id = gNodeId @@ -1180,6 +1181,7 @@ proc newNode*(kind: TNodeKind): PNode = inc gNodeId proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = + ## new node with line info, no type, and no children result = PNode(kind: kind, info: info) when defined(useNodeIds): result.id = gNodeId @@ -1189,6 +1191,7 @@ proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = inc gNodeId proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = + ## new node with line info, type, and children result = PNode(kind: kind, info: info) if children > 0: newSeq(result.sons, children) @@ -1200,6 +1203,7 @@ proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = inc gNodeId proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = + ## new node with line info, type, and no children result = newNode(kind) result.info = info result.typ = typ diff --git a/compiler/vm.nim b/compiler/vm.nim index 7a231a482..19ccea55b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1513,8 +1513,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # reference with the value `nil`, so `isNil` should be false! (node.kind == nkNilLit and nfIsRef notin node.flags) or (not node.typ.isNil and node.typ.kind == tyProc and - node.typ.callConv == ccClosure and node[0].kind == nkNilLit and - node[1].kind == nkNilLit)) + node.typ.callConv == ccClosure and node.safeLen > 0 and + node[0].kind == nkNilLit and node[1].kind == nkNilLit)) of opcNBindSym: # cannot use this simple check # if dynamicBindSym notin c.config.features: diff --git a/tests/macros/t17836.nim b/tests/macros/t17836.nim new file mode 100644 index 000000000..2453637f5 --- /dev/null +++ b/tests/macros/t17836.nim @@ -0,0 +1,15 @@ +import macros + +# Ensure that `isNil` works in the typed macro context when pass procs. + +type + O = object + fn: proc(i: int): int + +var o: O + +macro typedBug(expr: typed) = + doAssert expr[1] != nil + doAssert not expr[1].isNil + +typedBug(o.fn) \ No newline at end of file From 22e06ee95aeb32929a5b912096dfaa662165c162 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 25 Apr 2021 16:34:53 +0800 Subject: [PATCH 2495/4254] Ref #17831(synchapi.h: No such file or directory) (#17832) * Ref #17831 use windows.h * use header: "windows.h" * Update syslocks.nim * Update lib/system/syslocks.nim --- lib/system/syslocks.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index ac52d9a8c..2f0c8b0ba 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -24,9 +24,8 @@ when defined(windows): LockSemaphore: int SpinCount: int - RTL_CONDITION_VARIABLE {.importc: "RTL_CONDITION_VARIABLE", header: "synchapi.h".} = object + SysCond {.importc: "RTL_CONDITION_VARIABLE", header: "".} = object thePtr {.importc: "ptr".} : Handle - SysCond = RTL_CONDITION_VARIABLE proc initSysLock(L: var SysLock) {.importc: "InitializeCriticalSection", header: "".} From 9e6f2d7d186f760d8eb7dc26c863f23bd044b9c9 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 26 Apr 2021 01:16:20 +0800 Subject: [PATCH 2496/4254] bring back jstin after forking a new one (#17844) ref https://github.com/nim-lang/Nim/pull/17765#issuecomment-822019094 --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index ecae42811..64000dbb2 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -77,6 +77,7 @@ pkg "illwill", "nimble examples" pkg "inim", allowFailure=true pkg "itertools", "nim doc src/itertools.nim" pkg "iterutils" +pkg "jstin" pkg "karax", "nim c -r tests/tester.nim" pkg "kdtree", "nimble test", "https://github.com/jblindsay/kdtree" pkg "loopfusion" From 68e522ececdb9f79371f4b60d1fbddcf01736050 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 26 Apr 2021 15:04:52 +0800 Subject: [PATCH 2497/4254] Remove confusing (#17830) --- compiler/renderer.nim | 5 +---- lib/pure/collections/lists.nim | 14 +++++++------- lib/pure/collections/tables.nim | 14 +++++++------- lib/pure/parsecfg.nim | 10 +++++----- lib/pure/unittest.nim | 6 +++--- lib/system.nim | 4 ---- tests/destructor/tnewruntime_misc.nim | 7 ++++++- 7 files changed, 29 insertions(+), 31 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 4c0de9ed5..8bc3c3306 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1290,10 +1290,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = put(g, tkSpaces, Space) infixArgument(g, n, 2) of nkPrefix: - if n.len > 0 and n[0].kind == nkIdent and n[0].ident.s == "": - discard "XXX Remove this hack after 0.20 has been released!" - else: - gsub(g, n, 0) + gsub(g, n, 0) if n.len > 1: let opr = if n[0].kind == nkIdent: n[0].ident elif n[0].kind == nkSym: n[0].sym.name diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index c1fcb0743..c83be7aa3 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -68,7 +68,7 @@ type ## A node of a doubly linked list. ## ## It consists of a `value` field, and pointers to `next` and `prev`. - next*: (DoublyLinkedNode[T]) + next*: DoublyLinkedNode[T] prev* {.cursor.}: DoublyLinkedNode[T] value*: T DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T] @@ -77,23 +77,23 @@ type ## A node of a singly linked list. ## ## It consists of a `value` field, and a pointer to `next`. - next*: (SinglyLinkedNode[T]) + next*: SinglyLinkedNode[T] value*: T SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T] SinglyLinkedList*[T] = object ## A singly linked list. - head*: (SinglyLinkedNode[T]) + head*: SinglyLinkedNode[T] tail* {.cursor.}: SinglyLinkedNode[T] DoublyLinkedList*[T] = object ## A doubly linked list. - head*: (DoublyLinkedNode[T]) + head*: DoublyLinkedNode[T] tail* {.cursor.}: DoublyLinkedNode[T] SinglyLinkedRing*[T] = object ## A singly linked ring. - head*: (SinglyLinkedNode[T]) + head*: SinglyLinkedNode[T] tail* {.cursor.}: SinglyLinkedNode[T] DoublyLinkedRing*[T] = object @@ -148,7 +148,7 @@ proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] = discard -proc newDoublyLinkedNode*[T](value: T): (DoublyLinkedNode[T]) = +proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] = ## Creates a new doubly linked node with the given `value`. runnableExamples: let n = newDoublyLinkedNode[int](5) @@ -157,7 +157,7 @@ proc newDoublyLinkedNode*[T](value: T): (DoublyLinkedNode[T]) = new(result) result.value = value -proc newSinglyLinkedNode*[T](value: T): (SinglyLinkedNode[T]) = +proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] = ## Creates a new singly linked node with the given `value`. runnableExamples: let n = newSinglyLinkedNode[int](5) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 8739b60a3..b71bb0845 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -795,7 +795,7 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B {.deprecated: # ------------------------------------------------------------------- -proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = +proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = ## Creates a new ref hash table that is empty. ## ## See also: @@ -810,7 +810,7 @@ proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = new(result) result[] = initTable[A, B](initialSize) -proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = +proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = ## Creates a new ref hash table that contains the given `pairs`. ## ## `pairs` is a container consisting of `(key, value)` tuples. @@ -826,7 +826,7 @@ proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = new(result) result[] = toTable[A, B](pairs) -proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = +proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] result = newTable[C, B]() @@ -1790,7 +1790,7 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = # --------------------------- OrderedTableRef ------------------------------- # --------------------------------------------------------------------------- -proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableRef[A, B] = +proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableRef[A, B] = ## Creates a new ordered ref hash table that is empty. ## ## See also: @@ -1805,7 +1805,7 @@ proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableR new(result) result[] = initOrderedTable[A, B](initialSize) -proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = +proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = ## Creates a new ordered ref hash table that contains the given `pairs`. ## ## `pairs` is a container consisting of `(key, value)` tuples. @@ -2610,7 +2610,7 @@ iterator mvalues*[A](t: var CountTable[A]): var int = proc inc*[A](t: CountTableRef[A], key: A, val = 1) -proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = +proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = ## Creates a new ref count table that is empty. ## ## See also: @@ -2621,7 +2621,7 @@ proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = new(result) result[] = initCountTable[A](initialSize) -proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = +proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = ## Creates a new ref count table with every member of a container `keys` ## having a count of how many times it occurs in that container. result = newCountTable[A](keys.len) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 7f22a9857..2350cea4a 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -496,17 +496,17 @@ proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} = # ---------------- Configuration file related operations ---------------- type - Config* = OrderedTableRef[string, OrderedTableRef[string, string]] + Config* = OrderedTableRef[string, OrderedTableRef[string, string]] proc newConfig*(): Config = ## Creates a new configuration table. ## Useful when wanting to create a configuration file. - result = newOrderedTable[string, OrderedTableRef[string, string]]() + result = newOrderedTable[string, OrderedTableRef[string, string]]() -proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = +proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = ## Loads the specified configuration from stream into a new Config instance. ## `filename` parameter is only used for nicer error messages. - var dict = newOrderedTable[string, OrderedTableRef[string, string]]() + var dict = newOrderedTable[string, OrderedTableRef[string, string]]() var curSection = "" ## Current section, ## the default value of the current section is "", ## which means that the current section is a common @@ -536,7 +536,7 @@ proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config = close(p) result = dict -proc loadConfig*(filename: string): Config = +proc loadConfig*(filename: string): Config = ## Loads the specified configuration file into a new Config instance. let file = open(filename, fmRead) let fileStream = newFileStream(file) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 80a05db36..b1c01f8db 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -218,7 +218,7 @@ proc resetOutputFormatters* {.since: (1, 1).} = formatters = @[] proc newConsoleOutputFormatter*(outputLevel: OutputLevel = outputLevelDefault, - colorOutput = true): ConsoleOutputFormatter = + colorOutput = true): ConsoleOutputFormatter = ConsoleOutputFormatter( outputLevel: outputLevel, colorOutput: colorOutput @@ -246,7 +246,7 @@ proc colorOutput(): bool = deprecateEnvVarHere() result = false -proc defaultConsoleFormatter*(): ConsoleOutputFormatter = +proc defaultConsoleFormatter*(): ConsoleOutputFormatter = var colorOutput = colorOutput() var outputLevel = nimUnittestOutputLevel.parseEnum[:OutputLevel] when declared(stdout): @@ -315,7 +315,7 @@ proc xmlEscape(s: string): string = else: result.add(c) -proc newJUnitOutputFormatter*(stream: Stream): JUnitOutputFormatter = +proc newJUnitOutputFormatter*(stream: Stream): JUnitOutputFormatter = ## Creates a formatter that writes report to the specified stream in ## JUnit format. ## The ``stream`` is NOT closed automatically when the test are finished, diff --git a/lib/system.nim b/lib/system.nim index 41749c27a..9e9bacf39 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -885,8 +885,6 @@ when defined(nimOwnedEnabled) and not defined(nimscript): proc unown*[T](x: T): T {.magic: "Unown", noSideEffect.} ## Use the expression `x` ignoring its ownership attribute. - # This is only required to make 0.20 compile with the 0.19 line. - template ``*(t: untyped): untyped = owned(t) else: template unown*(x: typed): untyped = x @@ -908,8 +906,6 @@ else: new(r) return r - # This is only required to make 0.20 compile with the 0.19 line. - template ``*(t: untyped): untyped = t template disarm*(x: typed) = ## Useful for `disarming` dangling pointers explicitly for `--newruntime`. diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index 1a5b0e3b0..48ea36b7c 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -25,8 +25,13 @@ putEnv("HEAPTRASHING", "Indeed") let s1 = getAllocStats() + +proc newTableOwned[A, B](initialSize = defaultInitialSize): owned(TableRef[A, B]) = + new(result) + result[] = initTable[A, B](initialSize) + proc main = - var w = newTable[string, owned Node]() + var w = newTableOwned[string, owned Node]() w["key"] = Node(field: "value") echo w["key"][] echo getEnv("HEAPTRASHING") From 01bca8cd4fad857124794144bff09ae0326895bd Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 26 Apr 2021 20:48:25 +0800 Subject: [PATCH 2498/4254] fix gbk encodings on windows (#17843) --- lib/pure/encodings.nim | 1 + tests/stdlib/tencodings.nim | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/stdlib/tencodings.nim diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 1d8512018..bdc41c6ff 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -72,6 +72,7 @@ when defined(windows): (875, "cp875"), # IBM EBCDIC Greek Modern (932, "shift_jis"), # ANSI/OEM Japanese; Japanese (Shift-JIS) (936, "gb2312"), # ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) + (936, "gbk"), # Alias for GB2312 encoding (949, "ks_c_5601-1987"), # ANSI/OEM Korean (Unified Hangul Code) (950, "big5"), # ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) (1026, "IBM1026"), # IBM EBCDIC Turkish (Latin 5) diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim new file mode 100644 index 000000000..1da52ba59 --- /dev/null +++ b/tests/stdlib/tencodings.nim @@ -0,0 +1,25 @@ +import std/encodings + +var fromGBK = open("utf-8", "gbk") +var toGBK = open("gbk", "utf-8") + +var fromGB2312 = open("utf-8", "gb2312") +var toGB2312 = open("gb2312", "utf-8") + + +block: + let data = "\215\237\186\243\178\187\214\170\204\236\212\218\203\174\163\172\194\250\180\178\208\199\195\206\209\185\208\199\186\211" + doAssert fromGBK.convert(data) == "醉后不知天在水,满床星梦压星河" + +block: + let data = "万两黄金容易得,知心一个也难求" + doAssert toGBK.convert(data) == "\205\242\193\189\187\198\189\240\200\221\210\215\181\195\163\172\214\170\208\196\210\187\184\246\210\178\196\209\199\243" + + +block: + let data = "\215\212\208\197\200\203\201\250\182\254\176\217\196\234\163\172\187\225\181\177\203\174\187\247\200\253\199\167\192\239" + doAssert fromGB2312.convert(data) == "自信人生二百年,会当水击三千里" + +block: + let data = "谁怕?一蓑烟雨任平生" + doAssert toGB2312.convert(data) == "\203\173\197\194\163\191\210\187\203\242\209\204\211\234\200\206\198\189\201\250" From 01267292d8335b21c69e0e4d840d1fa1078cf1b8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Apr 2021 11:17:51 -0700 Subject: [PATCH 2499/4254] disable telebot, refs https://github.com/ba0f3/telebot.nim/issues/59 (#17860) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 64000dbb2..35c0cf0ce 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -139,7 +139,7 @@ pkg "stint", "nim r stint.nim" pkg "strslice" pkg "strunicode", "nim c -r src/strunicode.nim" pkg "synthesis" -pkg "telebot", "nim c -o:tbot -r src/telebot.nim" +pkg "telebot", "nim c -o:tbot -r src/telebot.nim", allowFailure = true # pending https://github.com/ba0f3/telebot.nim/issues/59 pkg "tempdir" pkg "templates" pkg "tensordsl", "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" From f52aa6bde8ba7b36d0589ee8e5d8319e5152237e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Apr 2021 11:32:41 -0700 Subject: [PATCH 2500/4254] fix typo in test name undeclared_routime.nim => undeclared_routine.nim (#17861) --- tests/errmsgs/undeclared_routime.nim | 13 ------------- tests/errmsgs/undeclared_routine.nim | 13 +++++++++++++ ...eclared_routime2.nim => undeclared_routine2.nim} | 0 ...eclared_routime3.nim => undeclared_routine3.nim} | 4 ++-- ...eclared_routime4.nim => undeclared_routine4.nim} | 2 +- ...eclared_routime5.nim => undeclared_routine5.nim} | 2 +- ...compiles.nim => undeclared_routine_compiles.nim} | 0 7 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 tests/errmsgs/undeclared_routime.nim create mode 100644 tests/errmsgs/undeclared_routine.nim rename tests/errmsgs/{undeclared_routime2.nim => undeclared_routine2.nim} (100%) rename tests/errmsgs/{undeclared_routime3.nim => undeclared_routine3.nim} (62%) rename tests/errmsgs/{undeclared_routime4.nim => undeclared_routine4.nim} (69%) rename tests/errmsgs/{undeclared_routime5.nim => undeclared_routine5.nim} (67%) rename tests/errmsgs/{undeclared_routime_compiles.nim => undeclared_routine_compiles.nim} (100%) diff --git a/tests/errmsgs/undeclared_routime.nim b/tests/errmsgs/undeclared_routime.nim deleted file mode 100644 index 7ef12cc0e..000000000 --- a/tests/errmsgs/undeclared_routime.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ -cmd: '''nim c --hints:off $file''' -errormsg: "attempting to call routine: 'myiter'" -nimout: '''undeclared_routime.nim(13, 15) Error: attempting to call routine: 'myiter' - found 'undeclared_routime.myiter(a: string)[iterator declared in undeclared_routime.nim(10, 9)]' - found 'undeclared_routime.myiter()[iterator declared in undeclared_routime.nim(11, 9)]' -''' -""" - -iterator myiter(a:string): int = discard -iterator myiter(): int = discard - -let a = myiter(1) diff --git a/tests/errmsgs/undeclared_routine.nim b/tests/errmsgs/undeclared_routine.nim new file mode 100644 index 000000000..126ade52a --- /dev/null +++ b/tests/errmsgs/undeclared_routine.nim @@ -0,0 +1,13 @@ +discard """ +cmd: '''nim c --hints:off $file''' +errormsg: "attempting to call routine: 'myiter'" +nimout: '''undeclared_routine.nim(13, 15) Error: attempting to call routine: 'myiter' + found 'undeclared_routine.myiter(a: string)[iterator declared in undeclared_routine.nim(10, 9)]' + found 'undeclared_routine.myiter()[iterator declared in undeclared_routine.nim(11, 9)]' +''' +""" + +iterator myiter(a:string): int = discard +iterator myiter(): int = discard + +let a = myiter(1) diff --git a/tests/errmsgs/undeclared_routime2.nim b/tests/errmsgs/undeclared_routine2.nim similarity index 100% rename from tests/errmsgs/undeclared_routime2.nim rename to tests/errmsgs/undeclared_routine2.nim diff --git a/tests/errmsgs/undeclared_routime3.nim b/tests/errmsgs/undeclared_routine3.nim similarity index 62% rename from tests/errmsgs/undeclared_routime3.nim rename to tests/errmsgs/undeclared_routine3.nim index 052adfc08..537871900 100644 --- a/tests/errmsgs/undeclared_routime3.nim +++ b/tests/errmsgs/undeclared_routine3.nim @@ -1,8 +1,8 @@ discard """ cmd: '''nim c --hints:off $file''' errormsg: "undeclared field: 'bar'" -nimout: '''undeclared_routime3.nim(13, 10) Error: undeclared field: 'bar' - found 'undeclared_routime3.bar()[declared in undeclared_routime3.nim(12, 9)]' of kind 'iterator' +nimout: '''undeclared_routine3.nim(13, 10) Error: undeclared field: 'bar' + found 'undeclared_routine3.bar()[declared in undeclared_routine3.nim(12, 9)]' of kind 'iterator' ''' """ diff --git a/tests/errmsgs/undeclared_routime4.nim b/tests/errmsgs/undeclared_routine4.nim similarity index 69% rename from tests/errmsgs/undeclared_routime4.nim rename to tests/errmsgs/undeclared_routine4.nim index 674caa421..9012a983f 100644 --- a/tests/errmsgs/undeclared_routime4.nim +++ b/tests/errmsgs/undeclared_routine4.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c --hints:off $file''' errormsg: "undeclared field: 'bar'" -nimout: '''undeclared_routime4.nim(10, 10) Error: undeclared field: 'bar' +nimout: '''undeclared_routine4.nim(10, 10) Error: undeclared field: 'bar' ''' """ diff --git a/tests/errmsgs/undeclared_routime5.nim b/tests/errmsgs/undeclared_routine5.nim similarity index 67% rename from tests/errmsgs/undeclared_routime5.nim rename to tests/errmsgs/undeclared_routine5.nim index 4394134ab..0387448a4 100644 --- a/tests/errmsgs/undeclared_routime5.nim +++ b/tests/errmsgs/undeclared_routine5.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c --hints:off $file''' errormsg: "undeclared identifier: 'myfun'" -nimout: '''undeclared_routime5.nim(9, 9) Error: undeclared identifier: 'myfun' +nimout: '''undeclared_routine5.nim(9, 9) Error: undeclared identifier: 'myfun' ''' """ diff --git a/tests/errmsgs/undeclared_routime_compiles.nim b/tests/errmsgs/undeclared_routine_compiles.nim similarity index 100% rename from tests/errmsgs/undeclared_routime_compiles.nim rename to tests/errmsgs/undeclared_routine_compiles.nim From 4c9fa9b75cfd6b62ab4d3a8d19fddf7f60c656fd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Apr 2021 19:14:00 -0700 Subject: [PATCH 2501/4254] fix typo in changelog refs #17746 [skip ci] (#17869) --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 43ce43352..94dbbbeb3 100644 --- a/changelog.md +++ b/changelog.md @@ -345,7 +345,7 @@ - Added `--spellSuggest` to show spelling suggestions on typos. -- Added `--filenames:abs|canonical|magic` which replaces --listFullPaths:on|off +- Added `--filenames:abs|canonical|legacyRelProj` which replaces --listFullPaths:on|off - Added `--processing:dots|filenames|off` which customizes `hintProcessing` From fdfd0f35a1c293a813f743694a5bdd199c2a8433 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 27 Apr 2021 10:31:52 +0800 Subject: [PATCH 2502/4254] correct changelog[skip CI] (#17870) --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 94dbbbeb3..81a387359 100644 --- a/changelog.md +++ b/changelog.md @@ -57,7 +57,7 @@ - The unary slice `..b` was removed, use `0..b` instead or use `-d:nimLegacyUnarySlice` for a deprecation period. -- Moved `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled` to `unmaintained/`. +- Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` From 3f58b7face3313a5fd51ab3227eabbcd53da51e2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Apr 2021 23:23:01 -0700 Subject: [PATCH 2503/4254] add -d:nimLegacyNoHashRef for a transition period which avoids defining hash(ref) (#17858) --- changelog.md | 1 + lib/pure/hashes.nim | 39 ++++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index 81a387359..e4b5c39f1 100644 --- a/changelog.md +++ b/changelog.md @@ -51,6 +51,7 @@ for previous behavior. - `hashes.hash` now supports `object` and `ref` (can be overloaded in user code). + For a transition period, use `-d:nimLegacyNoHashRef` to avoid defining `hash(ref)`. - `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, `hashes.hash(closure)` has also been improved. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 2ef0e2454..83b7a8d75 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -228,30 +228,35 @@ proc hash*(x: pointer): Hash {.inline.} = let y = cast[int](x) hash(y) # consistent with code expecting scrambled hashes depending on `nimIntHash1`. -proc hash*[T](x: ref[T] | ptr[T]): Hash {.inline.} = +proc hash*[T](x: ptr[T]): Hash {.inline.} = ## Efficient `hash` overload. runnableExamples: var a: array[10, uint8] assert a[0].addr.hash != a[1].addr.hash assert cast[pointer](a[0].addr).hash == a[0].addr.hash - runnableExamples: - type A = ref object - x: int - let a = A(x: 3) - let ha = a.hash - assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. - a.x = 4 - assert ha == a.hash # the hash only depends on the address - runnableExamples: - # you can overload `hash` if you want to customize semantics - type A[T] = ref object - x, y: T - proc hash(a: A): Hash = hash(a.x) - assert A[int](x: 3, y: 4).hash == A[int](x: 3, y: 5).hash - # xxx pending bug #17733, merge as `proc hash*(pointer | ref | ptr): Hash` - # or `proc hash*[T: ref | ptr](x: T): Hash` hash(cast[pointer](x)) +when not defined(nimLegacyNoHashRef): + proc hash*[T](x: ref[T]): Hash {.inline.} = + ## Efficient `hash` overload. + runnableExamples: + type A = ref object + x: int + let a = A(x: 3) + let ha = a.hash + assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. + a.x = 4 + assert ha == a.hash # the hash only depends on the address + runnableExamples: + # you can overload `hash` if you want to customize semantics + type A[T] = ref object + x, y: T + proc hash(a: A): Hash = hash(a.x) + assert A[int](x: 3, y: 4).hash == A[int](x: 3, y: 5).hash + # xxx pending bug #17733, merge as `proc hash*(pointer | ref | ptr): Hash` + # or `proc hash*[T: ref | ptr](x: T): Hash` + hash(cast[pointer](x)) + proc hash*[T: proc](x: T): Hash {.inline.} = ## Efficient hashing of proc vars. Closures are supported too. when T is "closure": From b1c7c994b0bcd39776fce16bdda24358f1fbb0d4 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 27 Apr 2021 16:24:59 +0800 Subject: [PATCH 2504/4254] [std/parsecfg]use runnableExamples (#17868) * [std/parsecfg]use runnableExamples * Apply suggestions from code review Co-authored-by: Timothee Cour --- lib/pure/parsecfg.nim | 191 +++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 96 deletions(-) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 2350cea4a..0ee19912c 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -19,37 +19,32 @@ ## :literal: ## ## Here is an example of how to use the configuration file parser: -## -## .. code-block:: nim -## -## import std/[os, parsecfg, strutils, streams] -## -## var f = newFileStream(paramStr(1), fmRead) -## if f != nil: -## var p: CfgParser -## open(p, f, paramStr(1)) -## while true: -## var e = next(p) -## case e.kind -## of cfgEof: break -## of cfgSectionStart: ## a `[section]` has been parsed -## echo("new section: " & e.section) -## of cfgKeyValuePair: -## echo("key-value-pair: " & e.key & ": " & e.value) -## of cfgOption: -## echo("command: " & e.key & ": " & e.value) -## of cfgError: -## echo(e.msg) -## close(p) -## else: -## echo("cannot open: " & paramStr(1)) -## -## -## Examples -## ======== -## +runnableExamples("-r:off"): + import std/[strutils, streams] + + let configFile = "example.ini" + var f = newFileStream(configFile, fmRead) + assert f != nil, "cannot open " & configFile + var p: CfgParser + open(p, f, configFile) + while true: + var e = next(p) + case e.kind + of cfgEof: break + of cfgSectionStart: ## a `[section]` has been parsed + echo "new section: " & e.section + of cfgKeyValuePair: + echo "key-value-pair: " & e.key & ": " & e.value + of cfgOption: + echo "command: " & e.key & ": " & e.value + of cfgError: + echo e.msg + close(p) + +##[ ## Configuration file example -## -------------------------- +]## + ## ## .. code-block:: nim ## @@ -58,60 +53,64 @@ ## name = "hello" ## --threads:on ## [Author] -## name = "lihf8515" -## qq = "10214028" -## email = "lihaifeng@wxm.com" -## +## name = "nim-lang" +## website = "nim-lang.org" + +##[ ## Creating a configuration file -## ----------------------------- -## .. code-block:: nim -## -## import std/parsecfg -## var dict=newConfig() -## dict.setSectionKey("","charset","utf-8") -## dict.setSectionKey("Package","name","hello") -## dict.setSectionKey("Package","--threads","on") -## dict.setSectionKey("Author","name","lihf8515") -## dict.setSectionKey("Author","qq","10214028") -## dict.setSectionKey("Author","email","lihaifeng@wxm.com") -## dict.writeConfig("config.ini") -## +]## + +runnableExamples: + var dict = newConfig() + dict.setSectionKey("","charset", "utf-8") + dict.setSectionKey("Package", "name", "hello") + dict.setSectionKey("Package", "--threads", "on") + dict.setSectionKey("Author", "name", "nim-lang") + dict.setSectionKey("Author", "website", "nim-lang.org") + assert $dict == """ +charset=utf-8 +[Package] +name=hello +--threads:on +[Author] +name=nim-lang +website=nim-lang.org +""" + +##[ ## Reading a configuration file -## ---------------------------- -## .. code-block:: nim -## -## import std/parsecfg -## var dict = loadConfig("config.ini") -## var charset = dict.getSectionValue("","charset") -## var threads = dict.getSectionValue("Package","--threads") -## var pname = dict.getSectionValue("Package","name") -## var name = dict.getSectionValue("Author","name") -## var qq = dict.getSectionValue("Author","qq") -## var email = dict.getSectionValue("Author","email") -## echo pname & "\n" & name & "\n" & qq & "\n" & email -## +]## + +runnableExamples("-r:off"): + let dict = loadConfig("config.ini") + let charset = dict.getSectionValue("","charset") + let threads = dict.getSectionValue("Package","--threads") + let pname = dict.getSectionValue("Package","name") + let name = dict.getSectionValue("Author","name") + let website = dict.getSectionValue("Author","website") + echo pname & "\n" & name & "\n" & website + +##[ ## Modifying a configuration file -## ------------------------------ -## .. code-block:: nim -## -## import std/parsecfg -## var dict = loadConfig("config.ini") -## dict.setSectionKey("Author","name","lhf") -## dict.writeConfig("config.ini") -## +]## + +runnableExamples("-r:off"): + var dict = loadConfig("config.ini") + dict.setSectionKey("Author", "name", "nim-lang") + dict.writeConfig("config.ini") + +##[ ## Deleting a section key in a configuration file -## ---------------------------------------------- -## .. code-block:: nim -## -## import std/parsecfg -## var dict = loadConfig("config.ini") -## dict.delSectionKey("Author","email") -## dict.writeConfig("config.ini") -## +]## + +runnableExamples("-r:off"): + var dict = loadConfig("config.ini") + dict.delSectionKey("Author", "website") + dict.writeConfig("config.ini") + +##[ ## Supported INI File structure -## ---------------------------- -## The examples below are supported: -## +]## # taken from https://docs.python.org/3/library/configparser.html#supported-ini-file-structure runnableExamples: @@ -150,27 +149,27 @@ runnableExamples: ) let section1 = "Simple Values" - doAssert dict.getSectionValue(section1, "key") == "value" - doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed" - doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well" - doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously" - doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values" + assert dict.getSectionValue(section1, "key") == "value" + assert dict.getSectionValue(section1, "spaces in keys") == "allowed" + assert dict.getSectionValue(section1, "spaces in values") == "allowed as well" + assert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously" + assert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values" let section2 = "All Values Are Strings" - doAssert dict.getSectionValue(section2, "values like this") == "19990429" - doAssert dict.getSectionValue(section2, "or this") == "3.14159265359" - doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no" - doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings" - doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true" + assert dict.getSectionValue(section2, "values like this") == "19990429" + assert dict.getSectionValue(section2, "or this") == "3.14159265359" + assert dict.getSectionValue(section2, "are they treated as numbers") == "no" + assert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings" + assert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true" let section3 = "Seletion A" - doAssert dict.getSectionValue(section3, + assert dict.getSectionValue(section3, "space around section name will be ignored", "not an empty value") == "" let section4 = "Sections Can Be Indented" - doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True" - doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" - doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability" + assert dict.getSectionValue(section4, "can_values_be_as_well") == "True" + assert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" + assert dict.getSectionValue(section4, "purpose") == "formatting for readability" import strutils, lexbase, streams, tables import std/private/decode_helpers @@ -564,7 +563,7 @@ proc replace(s: string): string = proc writeConfig*(dict: Config, stream: Stream) = ## Writes the contents of the table to the specified stream. ## - ## **Note:** Comment statement will be ignored. + ## .. note:: Comment statement will be ignored. for section, sectionData in dict.pairs(): if section != "": ## Not general section if not allCharsInSet(section, SymChars): ## Non system character @@ -604,7 +603,7 @@ proc writeConfig*(dict: Config, stream: Stream) = proc `$`*(dict: Config): string = ## Writes the contents of the table to string. ## - ## **Note:** Comment statement will be ignored. + ## .. note:: Comment statement will be ignored. let stream = newStringStream() defer: stream.close() dict.writeConfig(stream) @@ -613,7 +612,7 @@ proc `$`*(dict: Config): string = proc writeConfig*(dict: Config, filename: string) = ## Writes the contents of the table to the specified configuration file. ## - ## **Note:** Comment statement will be ignored. + ## .. note:: Comment statement will be ignored. let file = open(filename, fmWrite) defer: file.close() let fileStream = newFileStream(file) From 93c26041a5484373512069512471bbde943a7242 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Apr 2021 01:42:24 -0700 Subject: [PATCH 2505/4254] fix #17859; rename tests so they run in CI; merge several tests with nim check (#17862) * rename a test so it runs in CI; merge several tests with nim check * continue * continue * continue * rename tests/errmsgs/undeclared_routine_compiles.nim -> tests/errmsgs/tundeclared_routine_compiles.nim --- tests/errmsgs/tundeclared_routine.nim | 44 +++++++++++++++++++ ...s.nim => tundeclared_routine_compiles.nim} | 0 tests/errmsgs/undeclared_routine.nim | 13 ------ tests/errmsgs/undeclared_routine2.nim | 9 ---- tests/errmsgs/undeclared_routine3.nim | 13 ------ tests/errmsgs/undeclared_routine4.nim | 10 ----- tests/errmsgs/undeclared_routine5.nim | 9 ---- 7 files changed, 44 insertions(+), 54 deletions(-) create mode 100644 tests/errmsgs/tundeclared_routine.nim rename tests/errmsgs/{undeclared_routine_compiles.nim => tundeclared_routine_compiles.nim} (100%) delete mode 100644 tests/errmsgs/undeclared_routine.nim delete mode 100644 tests/errmsgs/undeclared_routine2.nim delete mode 100644 tests/errmsgs/undeclared_routine3.nim delete mode 100644 tests/errmsgs/undeclared_routine4.nim delete mode 100644 tests/errmsgs/undeclared_routine5.nim diff --git a/tests/errmsgs/tundeclared_routine.nim b/tests/errmsgs/tundeclared_routine.nim new file mode 100644 index 000000000..2f1320fff --- /dev/null +++ b/tests/errmsgs/tundeclared_routine.nim @@ -0,0 +1,44 @@ +discard """ +cmd: '''nim check --hints:off $file''' +action: reject +nimout: ''' +tundeclared_routine.nim(24, 17) Error: attempting to call routine: 'myiter' + found tundeclared_routine.myiter(a: string) [iterator declared in tundeclared_routine.nim(22, 12)] + found tundeclared_routine.myiter() [iterator declared in tundeclared_routine.nim(23, 12)] +tundeclared_routine.nim(29, 28) Error: invalid pragma: myPragma +tundeclared_routine.nim(36, 13) Error: undeclared field: 'bar3' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(33, 8)] + found tundeclared_routine.bar3() [iterator declared in tundeclared_routine.nim(35, 12)] +tundeclared_routine.nim(41, 13) Error: undeclared field: 'bar4' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(39, 8)] +tundeclared_routine.nim(44, 15) Error: attempting to call routine: 'bad5' +''' +""" + + + + + +# line 20 +block: + iterator myiter(a:string): int = discard + iterator myiter(): int = discard + let a = myiter(1) + +block: + proc myPragma():int=discard + iterator myPragma():int=discard + proc myfun(a:int): int {.myPragma.} = 1 + let a = myfun(1) + +block: + type Foo = object + var a = Foo() + iterator bar3():int=discard + let a2 = a.bar3 + +block: + type Foo = object + var a = Foo() + let a2 = a.bar4 + +block: + let a = bad5(1) diff --git a/tests/errmsgs/undeclared_routine_compiles.nim b/tests/errmsgs/tundeclared_routine_compiles.nim similarity index 100% rename from tests/errmsgs/undeclared_routine_compiles.nim rename to tests/errmsgs/tundeclared_routine_compiles.nim diff --git a/tests/errmsgs/undeclared_routine.nim b/tests/errmsgs/undeclared_routine.nim deleted file mode 100644 index 126ade52a..000000000 --- a/tests/errmsgs/undeclared_routine.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ -cmd: '''nim c --hints:off $file''' -errormsg: "attempting to call routine: 'myiter'" -nimout: '''undeclared_routine.nim(13, 15) Error: attempting to call routine: 'myiter' - found 'undeclared_routine.myiter(a: string)[iterator declared in undeclared_routine.nim(10, 9)]' - found 'undeclared_routine.myiter()[iterator declared in undeclared_routine.nim(11, 9)]' -''' -""" - -iterator myiter(a:string): int = discard -iterator myiter(): int = discard - -let a = myiter(1) diff --git a/tests/errmsgs/undeclared_routine2.nim b/tests/errmsgs/undeclared_routine2.nim deleted file mode 100644 index 3e48b48f4..000000000 --- a/tests/errmsgs/undeclared_routine2.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ -cmd: '''nim c --hints:off $file''' -errormsg: "invalid pragma: myPragma" -""" - -proc myPragma():int=discard -iterator myPragma():int=discard -proc myfun(a:int): int {.myPragma.} = 1 -let a = myfun(1) diff --git a/tests/errmsgs/undeclared_routine3.nim b/tests/errmsgs/undeclared_routine3.nim deleted file mode 100644 index 537871900..000000000 --- a/tests/errmsgs/undeclared_routine3.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ -cmd: '''nim c --hints:off $file''' -errormsg: "undeclared field: 'bar'" -nimout: '''undeclared_routine3.nim(13, 10) Error: undeclared field: 'bar' - found 'undeclared_routine3.bar()[declared in undeclared_routine3.nim(12, 9)]' of kind 'iterator' -''' -""" - - -type Foo = object -var a = Foo() -iterator bar():int=discard -let a = a.bar diff --git a/tests/errmsgs/undeclared_routine4.nim b/tests/errmsgs/undeclared_routine4.nim deleted file mode 100644 index 9012a983f..000000000 --- a/tests/errmsgs/undeclared_routine4.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ -cmd: '''nim c --hints:off $file''' -errormsg: "undeclared field: 'bar'" -nimout: '''undeclared_routine4.nim(10, 10) Error: undeclared field: 'bar' -''' -""" - -type Foo = object -var a = Foo() -let a = a.bar diff --git a/tests/errmsgs/undeclared_routine5.nim b/tests/errmsgs/undeclared_routine5.nim deleted file mode 100644 index 0387448a4..000000000 --- a/tests/errmsgs/undeclared_routine5.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ -cmd: '''nim c --hints:off $file''' -errormsg: "undeclared identifier: 'myfun'" -nimout: '''undeclared_routine5.nim(9, 9) Error: undeclared identifier: 'myfun' -''' -""" - - -let a = myfun(1) From 66022423aa21710f57f36e4f3c8c9633567cdb5e Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 27 Apr 2021 17:09:58 +0800 Subject: [PATCH 2506/4254] [std/pegs] increase test coverage (#17871) --- lib/pure/pegs.nim | 144 ------------------------------------- tests/stdlib/tpegs.nim | 158 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 154 insertions(+), 148 deletions(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 06a77af57..b5d9b1d07 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -2041,147 +2041,3 @@ proc escapePeg*(s: string): string = inQuote = true result.add(c) if inQuote: result.add('\'') - -when isMainModule: - proc pegsTest() = - assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" - assert match("(a b c)", peg"'(' @ ')'") - assert match("W_HI_Le", peg"\y 'while'") - assert(not match("W_HI_L", peg"\y 'while'")) - assert(not match("W_HI_Le", peg"\y v'while'")) - assert match("W_HI_Le", peg"y'while'") - - assert($ +digits == $peg"\d+") - assert "0158787".match(peg"\d+") - assert "ABC 0232".match(peg"\w+\s+\d+") - assert "ABC".match(peg"\d+ / \w+") - - var accum: seq[string] = @[] - for word in split("00232this02939is39an22example111", peg"\d+"): - accum.add(word) - assert(accum == @["this", "is", "an", "example"]) - - assert matchLen("key", ident) == 3 - - var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) - assert matchLen("key1= cal9", pattern) == 11 - - var ws = newNonTerminal("ws", 1, 1) - ws.rule = *whitespace - - var expr = newNonTerminal("expr", 1, 1) - expr.rule = sequence(capture(ident), *sequence( - nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) - - var c: Captures - var s = "a+b + c +d+e+f" - assert rawMatch(s, expr.rule, 0, c) == len(s) - var a = "" - for i in 0..c.ml-1: - a.add(substr(s, c.matches[i][0], c.matches[i][1])) - assert a == "abcdef" - #echo expr.rule - - #const filename = "lib/devel/peg/grammar.txt" - #var grammar = parsePeg(newFileStream(filename, fmRead), filename) - #echo "a <- [abc]*?".match(grammar) - assert find("_____abc_______", term("abc"), 2) == 5 - assert match("_______ana", peg"A <- 'ana' / . A") - assert match("abcs%%%", peg"A <- ..A / .A / '%'") - - var matches: array[0..MaxSubpatterns-1, string] - if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": - assert matches[0] == "abc" - else: - assert false - - var g2 = peg"""S <- A B / C D - A <- 'a'+ - B <- 'b'+ - C <- 'c'+ - D <- 'd'+ - """ - assert($g2 == "((A B) / (C D))") - assert match("cccccdddddd", g2) - assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey; var2<-key2key2") - assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "$1<-$2$2; $1<-$2$2") - assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") - - if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": - assert matches[0] == "a" - else: - assert false - - if match("abcdefg", peg"c {d} ef {g}", matches, 2): - assert matches[0] == "d" - assert matches[1] == "g" - else: - assert false - - accum = @[] - for x in findAll("abcdef", peg".", 3): - accum.add(x) - assert(accum == @["d", "e", "f"]) - - for x in findAll("abcdef", peg"^{.}", 3): - assert x == "d" - - if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": - assert matches[0] == "f" - assert matches[1] == "a, b" - else: - assert false - - assert match("eine übersicht und außerdem", peg"(\letter \white*)+") - # ß is not a lower cased letter?! - assert match("eine übersicht und auerdem", peg"(\lower \white*)+") - assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") - assert(not match("456678", peg"(\letter)+")) - - assert("var1 = key; var2 = key2".replacef( - peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey;var2<-key2key2") - - assert match("prefix/start", peg"^start$", 7) - - if "foo" =~ peg"{'a'}?.*": - assert matches[0].len == 0 - else: assert false - - if "foo" =~ peg"{''}.*": - assert matches[0] == "" - else: assert false - - if "foo" =~ peg"{'foo'}": - assert matches[0] == "foo" - else: assert false - - let empty_test = peg"^\d*" - let str = "XYZ" - - assert(str.find(empty_test) == 0) - assert(str.match(empty_test)) - - proc handleMatches(m: int, n: int, c: openArray[string]): string = - result = "" - - if m > 0: - result.add ", " - - result.add case n: - of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'" - of 1: toLowerAscii(c[0]) & ": ''" - else: "" - - assert("Var1=key1;var2=Key2; VAR3". - replace(peg"{\ident}('='{\ident})* ';'* \s*", - handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''") - - - doAssert "test1".match(peg"""{@}$""") - doAssert "test2".match(peg"""{(!$ .)*} $""") - pegsTest() - static: - pegsTest() diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index 99b7dc6f4..f2c93c2e5 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -1,5 +1,5 @@ discard """ - targets: "c js" + targets: "c cpp js" output: ''' PEG AST traversal output ------------------------ @@ -51,8 +51,7 @@ Event parser output ''' """ -import strutils, streams -import pegs +import std/[strutils, streams, pegs] const indent = " " @@ -125,7 +124,7 @@ block: discard of "Sum", "Product": try: - let val = matchStr.parseFloat + let val {.used.} = matchStr.parseFloat except ValueError: if valStack.len > 1 and opStack.len > 0: valStack[^2] = case opStack[^1] @@ -147,3 +146,154 @@ block: echo "-------------------" let pLen = parseArithExpr(txt) doAssert txt.len == pLen + + +import std/importutils + +block: + proc pegsTest() = + privateAccess(NonTerminal) + privateAccess(Captures) + + doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" + doAssert match("(a b c)", peg"'(' @ ')'") + doAssert match("W_HI_Le", peg"\y 'while'") + doAssert(not match("W_HI_L", peg"\y 'while'")) + doAssert(not match("W_HI_Le", peg"\y v'while'")) + doAssert match("W_HI_Le", peg"y'while'") + + doAssert($ +digits == $peg"\d+") + doAssert "0158787".match(peg"\d+") + doAssert "ABC 0232".match(peg"\w+\s+\d+") + doAssert "ABC".match(peg"\d+ / \w+") + + var accum: seq[string] = @[] + for word in split("00232this02939is39an22example111", peg"\d+"): + accum.add(word) + doAssert(accum == @["this", "is", "an", "example"]) + + doAssert matchLen("key", ident) == 3 + + var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) + doAssert matchLen("key1= cal9", pattern) == 11 + + var ws = newNonTerminal("ws", 1, 1) + ws.rule = *whitespace + + var expr = newNonTerminal("expr", 1, 1) + expr.rule = sequence(capture(ident), *sequence( + nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) + + var c: Captures + var s = "a+b + c +d+e+f" + doAssert rawMatch(s, expr.rule, 0, c) == len(s) + var a = "" + for i in 0..c.ml-1: + a.add(substr(s, c.matches[i][0], c.matches[i][1])) + doAssert a == "abcdef" + #echo expr.rule + + #const filename = "lib/devel/peg/grammar.txt" + #var grammar = parsePeg(newFileStream(filename, fmRead), filename) + #echo "a <- [abc]*?".match(grammar) + doAssert find("_____abc_______", term("abc"), 2) == 5 + doAssert match("_______ana", peg"A <- 'ana' / . A") + doAssert match("abcs%%%", peg"A <- ..A / .A / '%'") + + var matches: array[0..MaxSubpatterns-1, string] + if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": + doAssert matches[0] == "abc" + else: + doAssert false + + var g2 = peg"""S <- A B / C D + A <- 'a'+ + B <- 'b'+ + C <- 'c'+ + D <- 'd'+ + """ + doAssert($g2 == "((A B) / (C D))") + doAssert match("cccccdddddd", g2) + doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey; var2<-key2key2") + doAssert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "$1<-$2$2; $1<-$2$2") + doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") + + if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": + doAssert matches[0] == "a" + else: + doAssert false + + if match("abcdefg", peg"c {d} ef {g}", matches, 2): + doAssert matches[0] == "d" + doAssert matches[1] == "g" + else: + doAssert false + + accum = @[] + for x in findAll("abcdef", peg".", 3): + accum.add(x) + doAssert(accum == @["d", "e", "f"]) + + for x in findAll("abcdef", peg"^{.}", 3): + doAssert x == "d" + + if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": + doAssert matches[0] == "f" + doAssert matches[1] == "a, b" + else: + doAssert false + + doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+") + # ß is not a lower cased letter?! + doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+") + doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") + doAssert(not match("456678", peg"(\letter)+")) + + doAssert("var1 = key; var2 = key2".replacef( + peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey;var2<-key2key2") + + doAssert match("prefix/start", peg"^start$", 7) + + if "foo" =~ peg"{'a'}?.*": + doAssert matches[0].len == 0 + else: doAssert false + + if "foo" =~ peg"{''}.*": + doAssert matches[0] == "" + else: doAssert false + + if "foo" =~ peg"{'foo'}": + doAssert matches[0] == "foo" + else: doAssert false + + let empty_test = peg"^\d*" + let str = "XYZ" + + doAssert(str.find(empty_test) == 0) + doAssert(str.match(empty_test)) + + proc handleMatches(m: int, n: int, c: openArray[string]): string = + result = "" + + if m > 0: + result.add ", " + + result.add case n: + of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'" + of 1: toLowerAscii(c[0]) & ": ''" + else: "" + + doAssert("Var1=key1;var2=Key2; VAR3". + replace(peg"{\ident}('='{\ident})* ';'* \s*", + handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''") + + + doAssert "test1".match(peg"""{@}$""") + doAssert "test2".match(peg"""{(!$ .)*} $""") + pegsTest() + static: + pegsTest() + From a236002e54d68a672c720bd9b6d27ea0ba44edb8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Apr 2021 02:11:28 -0700 Subject: [PATCH 2507/4254] testament: add `nimoutFull: bool` spec (#17867) * testament: add `nimoutFull: bool` spec * PRTEMP * works * cleanup * add test for #12741 * PRTEMP failing test * remove unrelated changes * changelog --- changelog.md | 3 +++ testament/categories.nim | 3 +++ testament/specs.nim | 3 +++ testament/testament.nim | 18 +++++++++++------- testament/tests/shouldfail/tnimoutfull.nim | 15 +++++++++++++++ tests/config.nims | 8 ++++++-- tests/testament/tshould_not_work.nim | 2 ++ 7 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 testament/tests/shouldfail/tnimoutfull.nim diff --git a/changelog.md b/changelog.md index e4b5c39f1..75d086450 100644 --- a/changelog.md +++ b/changelog.md @@ -399,3 +399,6 @@ - `fusion` is now un-bundled from nim, `./koch fusion` will install it via nimble at a fixed hash. + +- testament: added `nimoutFull: bool` spec to compare full output of compiler + instead of a subset. diff --git a/testament/categories.nim b/testament/categories.nim index 19d9e4507..ffee5eeb3 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -576,6 +576,9 @@ proc isJoinableSpec(spec: TSpec): bool = spec.exitCode == 0 and spec.input.len == 0 and spec.nimout.len == 0 and + spec.nimoutFull == false and + # so that tests can have `nimoutFull: true` with `nimout.len == 0` with + # the meaning that they expect empty output. spec.matrix.len == 0 and spec.outputCheck != ocSubstr and spec.ccodeCheck.len == 0 and diff --git a/testament/specs.nim b/testament/specs.nim index 38e4ed0db..3774778b3 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -88,6 +88,7 @@ type targets*: set[TTarget] matrix*: seq[string] nimout*: string + nimoutFull*: bool # whether nimout is all compiler output or a subset parseErrors*: string # when the spec definition is invalid, this is not empty. unjoinable*: bool unbatchable*: bool @@ -297,6 +298,8 @@ proc parseSpec*(filename: string): TSpec = result.action = actionReject of "nimout": result.nimout = e.value + of "nimoutfull": + result.nimoutFull = parseCfgBool(e.value) of "batchable": result.unbatchable = not parseCfgBool(e.value) of "joinable": diff --git a/testament/testament.nim b/testament/testament.nim index f259c7b96..97f1f01b8 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -371,12 +371,20 @@ proc checkForInlineErrors(r: var TResults, expected, given: TSpec, test: TTest, r.addResult(test, target, "", given.msg, reSuccess) inc(r.passed) +proc nimoutCheck(expected, given: TSpec): bool = + result = true + if expected.nimoutFull: + if expected.nimout != given.nimout: + result = false + elif expected.nimout.len > 0 and not greedyOrderedSubsetLines(expected.nimout, given.nimout): + result = false + proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = if expected.inlineErrors.len > 0: checkForInlineErrors(r, expected, given, test, target) elif strip(expected.msg) notin strip(given.msg): r.addResult(test, target, expected.msg, given.msg, reMsgsDiffer) - elif expected.nimout.len > 0 and not greedyOrderedSubsetLines(expected.nimout, given.nimout): + elif not nimoutCheck(expected, given): r.addResult(test, target, expected.nimout, given.nimout, reMsgsDiffer) elif extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: @@ -424,10 +432,6 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st given.err = reCodeNotFound echo getCurrentExceptionMsg() -proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) = - if not greedyOrderedSubsetLines(expectedNimout, given.nimout): - given.err = reMsgsDiffer - proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, expected: TSpec; r: var TResults) = var expectedmsg: string = "" @@ -436,10 +440,10 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, if expected.needsCodegenCheck: codegenCheck(test, target, expected, expectedmsg, given) givenmsg = given.msg - if expected.nimout.len > 0: + if not nimoutCheck(expected, given): + given.err = reMsgsDiffer expectedmsg = expected.nimout givenmsg = given.nimout.strip - nimoutCheck(test, expectedmsg, given) else: givenmsg = "$ " & given.cmd & '\n' & given.nimout if given.err == reSuccess: inc(r.passed) diff --git a/testament/tests/shouldfail/tnimoutfull.nim b/testament/tests/shouldfail/tnimoutfull.nim new file mode 100644 index 000000000..3349ceedf --- /dev/null +++ b/testament/tests/shouldfail/tnimoutfull.nim @@ -0,0 +1,15 @@ +discard """ + targets: "c" + nimout: ''' +msg1 +msg2 +''' + action: compile + nimoutFull: true +""" + +# should fail because `msg3` is not in nimout and `nimoutFill: true` was given +static: + echo "msg1" + echo "msg2" + echo "msg3" diff --git a/tests/config.nims b/tests/config.nims index e5d6545f4..578b69e76 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -6,9 +6,13 @@ switch("path", "$lib/../testament/lib") ## prevent common user config settings to interfere with testament expectations ## Indifidual tests can override this if needed to test for these options. switch("colors", "off") -switch("filenames", "legacyRelProj") + switch("excessiveStackTrace", "off") -switch("spellSuggest", "0") + +when (NimMajor, NimMinor, NimPatch) >= (1,5,1): + # to make it easier to test against older nim versions, (best effort only) + switch("filenames", "legacyRelProj") + switch("spellSuggest", "0") # for std/unittest switch("define", "nimUnittestOutputLevel:PRINT_FAILURES") diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim index a0b4d6a36..2777bfe95 100644 --- a/tests/testament/tshould_not_work.nim +++ b/tests/testament/tshould_not_work.nim @@ -21,6 +21,8 @@ Failure: reCodegenFailure max allowed size: 1 FAIL: tests/shouldfail/tnimout.nim c Failure: reMsgsDiffer +FAIL: tests/shouldfail/tnimoutfull.nim c +Failure: reMsgsDiffer FAIL: tests/shouldfail/toutput.nim c Failure: reOutputsDiffer FAIL: tests/shouldfail/toutputsub.nim c From b03d6c9b2f9d117ed85d410313b7b39e49a16964 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 27 Apr 2021 13:03:26 +0200 Subject: [PATCH 2508/4254] Fix #17712 (#17873) --- compiler/dfa.nim | 7 ++++--- tests/arc/tarcmisc.nim | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index c7a9d4694..501d39f45 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -696,9 +696,10 @@ proc skipTrivials(c: var Con, n: PNode): PNode = proc genUse(c: var Con; orig: PNode) = let n = c.skipTrivials(orig) - if n.kind == nkSym and n.sym.kind in InterestingSyms: - c.code.add Instr(n: orig, kind: use) - elif n.kind in nkCallKinds: + if n.kind == nkSym: + if n.sym.kind in InterestingSyms: + c.code.add Instr(n: orig, kind: use) + else: gen(c, n) proc genDef(c: var Con; orig: PNode) = diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 82751f44c..a52538085 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -27,6 +27,7 @@ finalizer aaaaa hello ok +true closed destroying variable: 20 destroying variable: 10 @@ -422,3 +423,13 @@ proc test3 = static: test3() # was buggy test3() + +# bug #17712 +proc t17712 = + var ppv = new int + discard @[ppv] + var el: ref int + el = [ppv][0] + echo el != nil + +t17712() From d881a05bf6b75d9abc48b07b2a093cb96fea0b4c Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 28 Apr 2021 01:14:26 +0800 Subject: [PATCH 2509/4254] [std/encodings] fix iconv headers on OpenBSD (#17872) --- lib/pure/encodings.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index bdc41c6ff..893660d87 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -282,8 +282,10 @@ else: var errno {.importc, header: "".}: cint - when defined(freebsd) or defined(netbsd): + when defined(bsd): {.pragma: importIconv, cdecl, header: "".} + when defined(openbsd): + {.passL: "-liconv".} else: {.pragma: importIconv, cdecl, dynlib: iconvDll.} From 7637cff9cf677ad7e5952aed7670fe408eded418 Mon Sep 17 00:00:00 2001 From: Michael Krieger Date: Wed, 28 Apr 2021 20:33:08 +0200 Subject: [PATCH 2510/4254] Fix documentation of strutils.stripLineEnd (#17883) It does not return anything. --- lib/pure/strutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index bfd53a3a0..5bbd850cc 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2812,7 +2812,7 @@ func strip*(s: string, leading = true, trailing = true, result = substr(s, first, last) func stripLineEnd*(s: var string) = - ## Returns `s` stripped from one of these suffixes: + ## Strips one of these suffixes from `s` in-place: ## `\r, \n, \r\n, \f, \v` (at most once instance). ## For example, can be useful in conjunction with `osproc.execCmdEx`. ## aka: `chomp`:idx: From 601c050fcb4cc3101265018eb1cc381c6cb9dab9 Mon Sep 17 00:00:00 2001 From: c-blake Date: Thu, 29 Apr 2021 02:55:43 -0400 Subject: [PATCH 2511/4254] Implement https://forum.nim-lang.org/t/7848#50018 (#17874) * Implement https://forum.nim-lang.org/t/7848#50018 with just the same `SuccessX` hint category, build mode on a separate, final line, and no change to how the mode is spelled for -d:release/-d:danger. * Change to add a new BuildMode hint category and keep testament in sync as per comment. * Add "--hint:buildmode:off" to `defaultHintsOff`. * Remove as requested. * As requested for tests clean up. * Address code review. * Address code review. * Mirror db456423116a9b19666f551f4d38aded3964c2e2 --- compiler/lineinfos.nim | 8 +++++--- compiler/main.nim | 8 ++++---- doc/nimc.rst | 1 + drnim/drnim.nim | 8 ++++---- testament/testament.nim | 3 ++- tests/misc/trunner.nim | 2 +- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index d8f82aea0..c7057e7db 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -64,7 +64,8 @@ type warnFileChanged = "FileChanged", warnUser = "User", - hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", + hintSuccess = "Success", hintSuccessX = "SuccessX", hintBuildMode = "BuildMode", + hintCC = "CC", hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", @@ -142,7 +143,8 @@ const warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` - hintSuccessX: "${loc} lines; ${sec}s; $mem; $build build; proj: $project; out: $output", + hintSuccessX: "$loc lines; ${sec}s; $mem; proj: $project; out: $output", + hintBuildMode: "$1", hintCC: "CC: $1", hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", @@ -196,7 +198,7 @@ proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin} - result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, + result[0] = result[1] - {hintSuccessX, hintBuildMode, hintSuccess, hintConf, hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC} const diff --git a/compiler/main.nim b/compiler/main.nim index 48fbd185c..e7ee021bc 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -384,9 +384,9 @@ proc mainCommand*(graph: ModuleGraph) = when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" else: formatSize(getTotalMem()) & " totmem" let loc = $conf.linesCompiled - let build = if isDefined(conf, "danger"): "Dangerous Release" - elif isDefined(conf, "release"): "Release" - else: "Debug" + let build = if isDefined(conf, "danger"): "Dangerous Release build" + elif isDefined(conf, "release"): "Release build" + else: "***SLOW, DEBUG BUILD***; -d:release makes code run faster." let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName # xxx honor conf.filenameOption more accurately @@ -406,10 +406,10 @@ proc mainCommand*(graph: ModuleGraph) = "loc", loc, "sec", sec, "mem", mem, - "build", build, "project", project, "output", output, ]) + rawMessage(conf, hintBuildMode, build) when PrintRopeCacheStats: echo "rope cache stats: " diff --git a/doc/nimc.rst b/doc/nimc.rst index aad889591..9db95e81b 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -102,6 +102,7 @@ Source The source line that triggered a diagnostic message. StackTrace Success, SuccessX Successful compilation of a library or a binary. +BuildMode Kind of build: debug, release, danger User UserRaw XDeclaredButNotUsed Unused symbols in the code. diff --git a/drnim/drnim.nim b/drnim/drnim.nim index a591a8ef3..1eded533d 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1210,19 +1210,19 @@ proc mainCommand(graph: ModuleGraph) = when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" else: formatSize(getTotalMem()) & " totmem" let loc = $conf.linesCompiled - let build = if isDefined(conf, "danger"): "Dangerous Release" - elif isDefined(conf, "release"): "Release" - else: "Debug" + let build = if isDefined(conf, "danger"): "Dangerous Release build" + elif isDefined(conf, "release"): "Release build" + else: "***SLOW, DEBUG BUILD***; -d:release makes code run faster." let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName rawMessage(conf, hintSuccessX, [ "loc", loc, "sec", sec, "mem", mem, - "build", build, "project", project, "output", "" ]) + rawMessage(conf, hintBuildMode, build) proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) diff --git a/testament/testament.nim b/testament/testament.nim index 97f1f01b8..9caa3f6b9 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -107,7 +107,8 @@ proc isSuccess(input: string): bool = # that may appear in user config (eg: `--filenames`). # Passing `XDG_CONFIG_HOME= testament args...` can be used to ignore user config # stored in XDG_CONFIG_HOME, refs https://wiki.archlinux.org/index.php/XDG_Base_Directory - input.startsWith("Hint: ") and input.endsWith("[SuccessX]") + input.startsWith("Hint: ") and + (input.endsWith("[SuccessX]") or input.endsWith("[BuildMode]")) proc getFileDir(filename: string): string = result = filename.splitFile().dir diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 2a82ca9ee..06c828eaa 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -21,7 +21,7 @@ proc isDots(a: string): bool = a.startsWith(".") and a.strip(chars = {'.'}) == "" const - defaultHintsOff = "--hint:successx:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" + defaultHintsOff = "--hint:successx:off --hint:buildmode:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" # useful when you want to turn only some hints on, and some common ones off. # pending https://github.com/timotheecour/Nim/issues/453, simplify to: `--hints:off` nim = getCurrentCompilerExe() From 927ae26fad47289ae84de0cb23f0395ca7a79610 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Apr 2021 00:01:00 -0700 Subject: [PATCH 2512/4254] externalToLink: use quoteShell to avoid issues with spaces in paths for {.link.} pragmas (#17875) --- compiler/extccomp.nim | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 3b415c499..1cea9edeb 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -943,6 +943,7 @@ proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile = result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json") proc writeJsonBuildInstructions*(conf: ConfigRef) = + # xxx use std/json instead, will result in simpler, more maintainable code. template lit(x: string) = f.write x template str(x: string) = buf.setLen 0 @@ -964,23 +965,18 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList; llist: seq[string]) = var pastStart = false + template impl(path) = + let path2 = quoteShell(path) + objfiles.add(' ') + objfiles.add(path2) + if pastStart: lit ",\L" + str path2 + pastStart = true for it in llist: - let objfile = if noAbsolutePaths(conf): it.extractFilename - else: it - let objstr = addFileExt(objfile, CC[conf.cCompiler].objExt) - objfiles.add(' ') - objfiles.add(objstr) - if pastStart: lit ",\L" - str objstr - pastStart = true - + let objfile = if noAbsolutePaths(conf): it.extractFilename else: it + impl(addFileExt(objfile, CC[conf.cCompiler].objExt)) for it in clist: - let objstr = quoteShell(it.obj) - objfiles.add(' ') - objfiles.add(objstr) - if pastStart: lit ",\L" - str objstr - pastStart = true + impl(it.obj) lit "\L" proc depfiles(conf: ConfigRef; f: File; buf: var string) = From 016a8ccd7a8a018b28e8f424085c178d96860c6c Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 29 Apr 2021 15:51:54 +0800 Subject: [PATCH 2513/4254] [std/encodings]move to tests (#17866) --- lib/pure/encodings.nim | 72 ------------------------------------ tests/stdlib/tencodings.nim | 73 +++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 72 deletions(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 893660d87..89db0a278 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -476,75 +476,3 @@ proc convert*(s: string, destEncoding = "UTF-8", result = convert(c, s) finally: close(c) - -when not defined(testing) and isMainModule: - let - orig = "öäüß" - cp1252 = convert(orig, "CP1252", "UTF-8") - ibm850 = convert(cp1252, "ibm850", "CP1252") - current = getCurrentEncoding() - echo "Original string from source code: ", orig - echo "Forced ibm850 encoding: ", ibm850 - echo "Current encoding: ", current - echo "From ibm850 to current: ", convert(ibm850, current, "ibm850") - -when not defined(testing) and isMainModule and defined(windows): - block should_throw_on_unsupported_conversions: - let original = "some string" - - doAssertRaises(EncodingError): - discard convert(original, "utf-8", "utf-32") - - doAssertRaises(EncodingError): - discard convert(original, "utf-8", "unicodeFFFE") - - doAssertRaises(EncodingError): - discard convert(original, "utf-8", "utf-32BE") - - doAssertRaises(EncodingError): - discard convert(original, "unicodeFFFE", "utf-8") - - doAssertRaises(EncodingError): - discard convert(original, "utf-32", "utf-8") - - doAssertRaises(EncodingError): - discard convert(original, "utf-32BE", "utf-8") - - block should_convert_from_utf16_to_utf8: - let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" - let result = convert(original, "utf-8", "utf-16") - doAssert(result == "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82") - - block should_convert_from_utf16_to_win1251: - let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" - let result = convert(original, "windows-1251", "utf-16") - doAssert(result == "\xf2\xe5\xf1\xf2") - - block should_convert_from_win1251_to_koi8r: - let original = "\xf2\xe5\xf1\xf2" # win1251 test string "тест" - let result = convert(original, "koi8-r", "windows-1251") - doAssert(result == "\xd4\xc5\xd3\xd4") - - block should_convert_from_koi8r_to_win1251: - let original = "\xd4\xc5\xd3\xd4" # koi8r test string "тест" - let result = convert(original, "windows-1251", "koi8-r") - doAssert(result == "\xf2\xe5\xf1\xf2") - - block should_convert_from_utf8_to_win1251: - let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" - let result = convert(original, "windows-1251", "utf-8") - doAssert(result == "\xf2\xe5\xf1\xf2") - - block should_convert_from_utf8_to_utf16: - let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" - let result = convert(original, "utf-16", "utf-8") - doAssert(result == "\x42\x04\x35\x04\x41\x04\x42\x04") - - block should_handle_empty_string_for_any_conversion: - let original = "" - var result = convert(original, "utf-16", "utf-8") - doAssert(result == "") - result = convert(original, "utf-8", "utf-16") - doAssert(result == "") - result = convert(original, "windows-1251", "koi8-r") - doAssert(result == "") diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim index 1da52ba59..8ca55dbd9 100644 --- a/tests/stdlib/tencodings.nim +++ b/tests/stdlib/tencodings.nim @@ -23,3 +23,76 @@ block: block: let data = "谁怕?一蓑烟雨任平生" doAssert toGB2312.convert(data) == "\203\173\197\194\163\191\210\187\203\242\209\204\211\234\200\206\198\189\201\250" + + +when defined(windows): + block should_throw_on_unsupported_conversions: + let original = "some string" + + doAssertRaises(EncodingError): + discard convert(original, "utf-8", "utf-32") + + doAssertRaises(EncodingError): + discard convert(original, "utf-8", "unicodeFFFE") + + doAssertRaises(EncodingError): + discard convert(original, "utf-8", "utf-32BE") + + doAssertRaises(EncodingError): + discard convert(original, "unicodeFFFE", "utf-8") + + doAssertRaises(EncodingError): + discard convert(original, "utf-32", "utf-8") + + doAssertRaises(EncodingError): + discard convert(original, "utf-32BE", "utf-8") + + block should_convert_from_utf16_to_utf8: + let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" + let result = convert(original, "utf-8", "utf-16") + doAssert(result == "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82") + + block should_convert_from_utf16_to_win1251: + let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест" + let result = convert(original, "windows-1251", "utf-16") + doAssert(result == "\xf2\xe5\xf1\xf2") + + block should_convert_from_win1251_to_koi8r: + let original = "\xf2\xe5\xf1\xf2" # win1251 test string "тест" + let result = convert(original, "koi8-r", "windows-1251") + doAssert(result == "\xd4\xc5\xd3\xd4") + + block should_convert_from_koi8r_to_win1251: + let original = "\xd4\xc5\xd3\xd4" # koi8r test string "тест" + let result = convert(original, "windows-1251", "koi8-r") + doAssert(result == "\xf2\xe5\xf1\xf2") + + block should_convert_from_utf8_to_win1251: + let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" + let result = convert(original, "windows-1251", "utf-8") + doAssert(result == "\xf2\xe5\xf1\xf2") + + block should_convert_from_utf8_to_utf16: + let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест" + let result = convert(original, "utf-16", "utf-8") + doAssert(result == "\x42\x04\x35\x04\x41\x04\x42\x04") + + block should_handle_empty_string_for_any_conversion: + let original = "" + var result = convert(original, "utf-16", "utf-8") + doAssert(result == "") + result = convert(original, "utf-8", "utf-16") + doAssert(result == "") + result = convert(original, "windows-1251", "koi8-r") + doAssert(result == "") + + +block: + let + orig = "öäüß" + cp1252 = convert(orig, "CP1252", "UTF-8") + ibm850 = convert(cp1252, "ibm850", "CP1252") + current = getCurrentEncoding() + doAssert orig == "\195\182\195\164\195\188\195\159" + doAssert ibm850 == "\148\132\129\225" + doAssert convert(ibm850, current, "ibm850") == orig From 87229e272ecd4012b750215d35e914580cd8475c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Apr 2021 02:25:08 -0700 Subject: [PATCH 2514/4254] fix #17853 (ascii message separator broke json nim dump) (#17887) --- changelog.md | 4 ++++ compiler/main.nim | 3 ++- compiler/msgs.nim | 1 + compiler/options.nim | 2 +- tests/misc/trunner.nim | 11 +++++++++++ tests/osproc/treadlines.nim | 7 +++++-- 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 75d086450..21f3cb9b5 100644 --- a/changelog.md +++ b/changelog.md @@ -60,6 +60,10 @@ - Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. +- Nim compiler now adds ASCII unit separator `\31` before a newline for every generated + message (potentially multiline), so tooling can tell when messages start and end. + + ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` diff --git a/compiler/main.nim b/compiler/main.nim index e7ee021bc..db5dd439e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -349,7 +349,8 @@ proc mainCommand*(graph: ModuleGraph) = (key: "warnings", val: warnings), ] - msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook}) + msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook, msgNoUnitSep}) + # `msgNoUnitSep` to avoid generating invalid json, refs bug #17853 else: msgWriteln(conf, "-- list of currently defined symbols --", {msgStdout, msgSkipHook, msgNoUnitSep}) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 93ca8d7cc..3abbf9e69 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -291,6 +291,7 @@ proc `??`* (conf: ConfigRef; info: TLineInfo, filename: string): bool = const UnitSep = "\31" + # this needs care to avoid issues similar to https://github.com/nim-lang/Nim/issues/17853 type MsgFlag* = enum ## flags altering msgWriteln behavior diff --git a/compiler/options.nim b/compiler/options.nim index 209564d0a..4773ba284 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -44,7 +44,7 @@ type # please make sure we have under 32 options optImportHidden TOptions* = set[TOption] - TGlobalOption* = enum # **keep binary compatible** + TGlobalOption* = enum gloptNone, optForceFullMake, optWasNimscript, # redundant with `cmdNimscript`, could be removed optListCmd, optCompileOnly, optNoLinking, diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 06c828eaa..014373dfb 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -71,6 +71,7 @@ ret=[s1:foobar s2:foobar age:25 pi:3.14] else: # don't run twice the same test import std/strutils + import std/json template check2(msg) = doAssert msg in output, output block: # tests with various options `nim doc --project --index --docroot` @@ -317,3 +318,13 @@ compiling: v3 running: v3 running: v2 """, ret + + block: # nim dump + let cmd = fmt"{nim} dump --dump.format:json -d:D20210428T161003 --hints:off ." + let (ret, status) = execCmdEx(cmd) + doAssert status == 0 + let j = ret.parseJson + # sanity checks + doAssert "D20210428T161003" in j["defined_symbols"].to(seq[string]) + doAssert j["version"].to(string) == NimVersion + doAssert j["nimExe"].to(string) == getCurrentCompilerExe() diff --git a/tests/osproc/treadlines.nim b/tests/osproc/treadlines.nim index 436dd7a10..bcde19d7f 100644 --- a/tests/osproc/treadlines.nim +++ b/tests/osproc/treadlines.nim @@ -1,15 +1,18 @@ discard """ - output: '''Error: cannot open 'a.nim'\31 + output: ''' +Error: cannot open 'a.nim'\31 Error: cannot open 'b.nim'\31 ''' targets: "c" """ import osproc +from std/os import getCurrentCompilerExe var ps: seq[Process] # compile & run 2 progs in parallel +const nim = getCurrentCompilerExe() for prog in ["a", "b"]: - ps.add startProcess("nim", "", + ps.add startProcess(nim, "", ["r", "--hint[Conf]=off", "--hint[Processing]=off", prog], options = {poUsePath, poDaemon, poStdErrToStdOut}) From 5edddd68d04648553bc02d52cd53d3a1a14102f3 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 29 Apr 2021 19:39:36 +0800 Subject: [PATCH 2515/4254] improve cache line size (#17885) * improve cache line size - 64bit system tend to use cache line of 64 bytes - add align https://trishagee.com/2011/07/22/dissecting_the_disruptor_why_its_so_fast_part_two__magic_cache_line_padding Though I'm not sure, what do you think? @timotheecour * Update lib/pure/concurrency/threadpool.nim --- lib/pure/concurrency/threadpool.nim | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 9beb39522..f8a5f9ba8 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -52,17 +52,14 @@ proc signal(cv: var Semaphore) = release(cv.L) signal(cv.c) -const CacheLineSize = 32 # true for most archs +const CacheLineSize = 64 # true for most archs type Barrier {.compilerproc.} = object entered: int cv: Semaphore # Semaphore takes 3 words at least - when sizeof(int) < 8: - cacheAlign: array[CacheLineSize-4*sizeof(int), byte] - left: int - cacheAlign2: array[CacheLineSize-sizeof(int), byte] - interest: bool # whether the master is interested in the "all done" event + left {.align(CacheLineSize).}: int + interest {.align(CacheLineSize).} : bool # whether the master is interested in the "all done" event proc barrierEnter(b: ptr Barrier) {.compilerproc, inline.} = # due to the signaling between threads, it is ensured we are the only From e4db733d80d0b70192ac7eb4094a46269fe7cd5b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Apr 2021 04:42:56 -0700 Subject: [PATCH 2516/4254] fix #17888: remove undefined behavior for posix.open; fix tempfiles.createTempFile (#17889) * fix #17888: remove undefined behavior for posix.open; fix tempfiles.createTempFile * fix for tests/async/tasyncfile.nim * hide mode for now * add notice regarding stability --- lib/posix/posix.nim | 6 +++++- lib/pure/streams.nim | 1 + lib/std/tempfiles.nim | 13 ++++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 035b4e8fb..45fe00d5d 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -183,7 +183,11 @@ proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "", s proc creat*(a1: cstring, a2: Mode): cint {.importc, header: "", sideEffect.} proc fcntl*(a1: cint | SocketHandle, a2: cint): cint {.varargs, importc, header: "", sideEffect.} -proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "", sideEffect.} +proc openImpl(a1: cstring, a2: cint): cint {.varargs, importc: "open", header: "", sideEffect.} +proc open*(a1: cstring, a2: cint, mode: Mode | cint = 0.Mode): cint {.inline.} = + # prevents bug #17888 + openImpl(a1, a2, mode) + proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {. importc, header: "".} proc posix_fallocate*(a1: cint, a2, a3: Off): cint {. diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index eb1c9cc14..3cc5ea038 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1503,6 +1503,7 @@ when false: of fmReadWrite: flags = O_RDWR or int(O_CREAT) of fmReadWriteExisting: flags = O_RDWR of fmAppend: flags = O_WRONLY or int(O_CREAT) or O_APPEND + static: doAssert false # handle bug #17888 var handle = open(filename, flags) if handle < 0: raise newEOS("posix.open() call failed") result = newFileHandleStream(handle) diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index 1e1bbd403..2a6fe7d83 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -8,6 +8,8 @@ # ## This module creates temporary files and directories. +## +## Experimental API, subject to change. import os, random @@ -44,6 +46,8 @@ else: proc safeOpen(filename: string): File = ## Open files exclusively. + # xxx this should be clarified; it doesn't in particular prevent other processes + # from opening the file, at least currently. when defined(windows): let dwShareMode = FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE let dwCreation = CREATE_NEW @@ -64,9 +68,13 @@ proc safeOpen(filename: string): File = discard close_osfandle(fileHandle) raiseOSError(osLastError(), filename) else: + # xxx we need a `proc toMode(a: FilePermission): Mode`, possibly by + # exposing fusion/filepermissions.fromFilePermissions to stdlib; then we need + # to expose a `perm` param so users can customize this (e.g. the temp file may + # need execute permissions), and figure out how to make the API cross platform. + let mode = Mode(S_IRUSR or S_IWUSR) let flags = posix.O_RDWR or posix.O_CREAT or posix.O_EXCL - - let fileHandle = posix.open(filename, flags) + let fileHandle = posix.open(filename, flags, mode) if fileHandle == -1: raiseOSError(osLastError(), filename) @@ -93,7 +101,6 @@ proc createTempFile*(prefix, suffix: string, dir = ""): tuple[fd: File, path: st ## If failing to create a temporary file, `IOError` will be raised. ## ## .. note:: It is the caller's responsibility to remove the file when no longer needed. - ## var dir = dir if dir.len == 0: dir = getTempDir() From a424075b5eb50681b448dcf73f7559549945ad58 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Apr 2021 04:44:53 -0700 Subject: [PATCH 2517/4254] improve nimsuggest/tester, minor improvements to koch.nim (#17879) * improve nimsuggest/tester * koch improvements --- koch.nim | 21 ++++++++++----------- nimdoc/testproject/testproject.nim | 2 +- nimpretty/tester.nim | 2 +- nimsuggest/tester.nim | 22 ++++++++++++---------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/koch.nim b/koch.nim index c78356b58..12f9e1c14 100644 --- a/koch.nim +++ b/koch.nim @@ -154,7 +154,7 @@ proc bundleNimbleExe(latest: bool, args: string) = proc bundleNimsuggest(args: string) = nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim", - options = "-d:release -d:danger " & args) + options = "-d:danger " & args) proc buildVccTool(args: string) = let input = "tools/vccexe/vccexe.nim" @@ -558,28 +558,27 @@ proc runCI(cmd: string) = ## run tests execFold("Test nimscript", "nim e tests/test_nimscript.nims") when defined(windows): - # note: will be over-written below - execFold("Compile tester", "nim c -d:nimCoroutines --os:genode -d:posix --compileOnly testament/testament") + execFold("Compile tester", "nim c --usenimcache -d:nimCoroutines --os:genode -d:posix --compileOnly testament/testament") # main bottleneck here # xxx: even though this is the main bottleneck, we could speedup the rest via batching with `--batch`. # BUG: with initOptParser, `--batch:'' all` interprets `all` as the argument of --batch, pending bug #14343 - execFold("Run tester", "nim c -r -d:nimCoroutines --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimStrictMode testament/testament $# all -d:nimCoroutines" % batchParam) + execFold("Run tester", "nim c -r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimStrictMode testament/testament $# all -d:nimCoroutines" % batchParam) - block CT_FFI: + block: # nimHasLibFFI: when defined(posix): # windows can be handled in future PR's execFold("nimble install -y libffi", "nimble install -y libffi") - const nimFFI = "./bin/nim.ctffi" + const nimFFI = "bin/nim.ctffi" # no need to bootstrap with koch boot (would be slower) let backend = if doUseCpp(): "cpp" else: "c" execFold("build with -d:nimHasLibFFI", "nim $1 -d:release -d:nimHasLibFFI -o:$2 compiler/nim.nim" % [backend, nimFFI]) execFold("test with -d:nimHasLibFFI", "$1 $2 -r testament/testament --nim:$1 r tests/misc/trunner.nim -d:nimTrunnerFfi" % [nimFFI, backend]) - execFold("Run nimdoc tests", "nim c -r nimdoc/tester") - execFold("Run rst2html tests", "nim c -r nimdoc/rsttester") - execFold("Run nimpretty tests", "nim c -r nimpretty/tester.nim") + execFold("Run nimdoc tests", "nim r nimdoc/tester") + execFold("Run rst2html tests", "nim r nimdoc/rsttester") + execFold("Run nimpretty tests", "nim r nimpretty/tester.nim") when defined(posix): - execFold("Run nimsuggest tests", "nim c -r nimsuggest/tester") + execFold("Run nimsuggest tests", "nim r nimsuggest/tester") proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) @@ -605,7 +604,7 @@ proc testUnixInstall(cmdLineRest: string) = execCleanPath("./koch tools") # check the tests work: putEnv("NIM_EXE_NOT_IN_PATH", "NOT_IN_PATH") - execCleanPath("./koch tests --nim:./bin/nim cat megatest", destDir / "bin") + execCleanPath("./koch tests --nim:bin/nim cat megatest", destDir / "bin") else: echo "Version check: failure" finally: diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 6b82acb9b..c7a1cd0fc 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -341,7 +341,7 @@ when true: # issue #14473 template doit(): untyped = ## doit ## return output only - toSeq([1,2]) + toSeq(["D20210427T172228"]) # make it searcheable at least until we figure out a way to avoid echo echo doit() # using doAssert or similar to avoid echo would "hide" the original bug when true: # issue #14846 diff --git a/nimpretty/tester.nim b/nimpretty/tester.nim index d646b25ce..0a60ce693 100644 --- a/nimpretty/tester.nim +++ b/nimpretty/tester.nim @@ -3,7 +3,7 @@ import strutils, os, sequtils const - dir = "nimpretty/tests/" + dir = "nimpretty/tests" outputdir = dir / "outputdir" var diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 9fcf7eacc..f19cf5538 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -2,6 +2,8 @@ # Every test file can have a #[!]# comment that is deleted from the input # before 'nimsuggest' is invoked to ensure this token doesn't make a # crucial difference for Nim's parser. +# When debugging, to run a single test, use for e.g.: +# `nim r nimsuggest/tester.nim nimsuggest/tests/tsug_accquote.nim` import os, osproc, strutils, streams, re, sexp, net @@ -13,16 +15,16 @@ type disabled: bool const - curDir = when defined(windows): "" else: "" DummyEof = "!EOF!" - -template tpath(): untyped = getAppDir() / "tests" + tpath = "nimsuggest/tests" + # we could also use `stdtest/specialpaths` import std/compilesettings proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" - let nimsug = curDir & addFileExt("nimsuggest", ExeExt) + let nimsug = "bin" / addFileExt("nimsuggest", ExeExt) + doAssert nimsug.fileExists, nimsug const libpath = querySetting(libPath) result.filename = filename result.dest = getTempDir() / extractFilename(filename) @@ -63,7 +65,7 @@ proc parseTest(filename: string; epcMode=false): Test = elif x.startsWith(">"): # since 'markers' here are not complete yet, we do the $substitutions # afterwards - result.script.add((x.substr(1).replaceWord("$path", tpath()), "")) + result.script.add((x.substr(1).replaceWord("$path", tpath), "")) elif x.len > 0: # expected output line: let x = x % ["file", filename, "lib", libpath] @@ -104,7 +106,7 @@ proc parseCmd(c: string): seq[string] = proc edit(tmpfile: string; x: seq[string]) = if x.len != 3 and x.len != 4: quit "!edit takes two or three arguments" - let f = if x.len >= 4: tpath() / x[3] else: tmpfile + let f = if x.len >= 4: tpath / x[3] else: tmpfile try: let content = readFile(f) let newcontent = content.replace(x[1], x[2]) @@ -121,12 +123,12 @@ proc exec(x: seq[string]) = proc copy(x: seq[string]) = if x.len != 3: quit "!copy takes two arguments" - let rel = tpath() + let rel = tpath copyFile(rel / x[1], rel / x[2]) proc del(x: seq[string]) = if x.len != 2: quit "!del takes one argument" - removeFile(tpath() / x[1]) + removeFile(tpath / x[1]) proc runCmd(cmd, dest: string): bool = result = cmd[0] == '!' @@ -317,7 +319,7 @@ proc runTest(filename: string): int = try: inp.writeLine("quit") inp.flush() - except: + except IOError, OSError: # assume it's SIGPIPE, ie, the child already died discard close(p) @@ -334,7 +336,7 @@ proc main() = failures += runTest(xx) failures += runEpcTest(xx) else: - for x in walkFiles(tpath() / "t*.nim"): + for x in walkFiles(tpath / "t*.nim"): echo "Test ", x let xx = expandFilename x when not defined(windows): From 198b5e3a7a629ea58b1e2a71a3e70f35484f289b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Apr 2021 04:53:58 -0700 Subject: [PATCH 2518/4254] improve tsets.nim, twrong_setconstr.nim and avoid name clashes with compiler sets (#17876) * improve tests/sets/tsets.nim and avoid name clashes with compiler sets * avoid name clashes in twrong_setconstr.nim and merge into tsets --- tests/ccgbugs/twrong_setconstr.nim | 146 ----------------- tests/sets/tsets.nim | 247 +++++++---------------------- 2 files changed, 59 insertions(+), 334 deletions(-) delete mode 100644 tests/ccgbugs/twrong_setconstr.nim diff --git a/tests/ccgbugs/twrong_setconstr.nim b/tests/ccgbugs/twrong_setconstr.nim deleted file mode 100644 index 8be0b82b5..000000000 --- a/tests/ccgbugs/twrong_setconstr.nim +++ /dev/null @@ -1,146 +0,0 @@ -discard """ - output: "" -""" - -# bug #2880 - -type - TMsgKind* = enum - errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, - errXCompilerDoesNotSupportCpp, errStringLiteralExpected, - errIntLiteralExpected, errInvalidCharacterConstant, - errClosingTripleQuoteExpected, errClosingQuoteExpected, - errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, - errInvalidNumber, errInvalidNumberOctalCode, 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, errOnOffOrListExpectedButXFound, - 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 - 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, - hintExecuting, hintLinking, hintDependency, - hintSource, hintStackTrace, hintGCStats, - hintUser - -const - warnMin = warnCannotOpenFile - hintMax = high(TMsgKind) - -type - TNoteKind = range[warnMin..hintMax] # "notes" are warnings or hints - TNoteKinds = set[TNoteKind] - -const - NotesVerbosityConst: array[0..0, TNoteKinds] = [ - {low(TNoteKind)..high(TNoteKind)} - {hintGCStats}] - fuckyou = NotesVerbosityConst[0] - -var - gNotesFromConst: TNoteKinds = NotesVerbosityConst[0] - gNotesFromConst2: TNoteKinds = fuckyou - -if hintGCStats in gNotesFromConst: - echo "hintGCStats in gNotesFromConst A" - -if hintGCStats in gNotesFromConst2: - echo "hintGCStats in gNotesFromConst B" diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim index dbbeed543..9ccf7a0c2 100644 --- a/tests/sets/tsets.nim +++ b/tests/sets/tsets.nim @@ -1,207 +1,57 @@ -discard """ -output: ''' -Ha ein F ist in s! -false -''' -""" -# Test the handling of sets +# Test builtin sets -import - strutils +# xxx these tests are not very good, this should be revisited. + +when defined nimTestsTsetsGenerate: + # to generate enums for this test + var ret: string + for i in 0..<276: + ret.add "k" & $i & ", " + echo ret proc testSets(s: var set[char]) = s = {'A', 'B', 'C', 'E'..'G'} + {'Z'} + s # test sets if the first element is different from 0: -type - TAZ = range['a'..'z'] - TAZset = set[TAZ] +block: + type + TAZ = range['a'..'z'] + TAZset = set[TAZ] + FakeTokType = enum + k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, k124, k125, k126, k127, k128, k129, k130, k131, k132, k133, k134, k135, k136, k137, k138, k139, k140, k141, k142, k143, k144, k145, k146, k147, k148, k149, k150, k151, k152, k153, k154, k155, k156, k157, k158, k159, k160, k161, k162, k163, k164, k165, k166, k167, k168, k169, k170, k171, k172, k173, k174, k175, k176, k177, k178, k179, k180, k181, k182, k183, k184, k185, k186, k187, k188, k189, k190, k191, k192, k193, k194, k195, k196, k197, k198, k199, k200, k201, k202, k203, k204, k205, k206, k207, k208, k209, k210, k211, k212, k213, k214, k215, k216, k217, k218, k219, k220, k221, k222, k223, k224, k225, k226, k227, k228, k229, k230, k231, k232, k233, k234, k235, k236, k237, k238, k239, k240, k241, k242, k243, k244, k245, k246, k247, k248, k249 + FakeTokTypeRange = range[k2..k101] + FakeTokTypes = set[FakeTokTypeRange] - 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, - 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, - tkParDotLe, tkParDotRi, - 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: FakeTokTypes = {FakeTokTypeRange(k2)..pred(k64), k72..k74} -const - toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit), - tkStrLit..tkTripleStrLit} - -var - s: set[char] - a: TAZset -s = {'0'..'9'} -testSets(s) -if 'F' in s: write(stdout, "Ha ein F ist in s!\n") -else: write(stdout, "BUG: F ist nicht in s!\n") -a = {} #{'a'..'z'} -for x in low(TAZ) .. high(TAZ): - incl(a, x) - if x in a: discard - else: write(stdout, "BUG: something not in a!\n") - -for x in low(TTokTypeRange) .. high(TTokTypeRange): - if x in tokTypes: - discard - #writeLine(stdout, "the token '$1' is in the set" % repr(x)) - -#OUT Ha ein F ist in s! + var + s: set[char] + a: TAZset + s = {'0'..'9'} + testSets(s) + doAssert 'F' in s + a = {} #{'a'..'z'} + for x in low(TAZ) .. high(TAZ): + incl(a, x) + doAssert x in a + for x in low(FakeTokTypeRange) .. high(FakeTokTypeRange): + if x in tokTypes: + discard 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, - 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 + FakeMsgKind* = enum + k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, k124, k125, k126, k127, k128, k129, k130, k131, k132, k133, k134, k135, k136, k137, k138, k139, k140, k141, k142, k143, k144, k145, k146, k147, k148, k149, k150, k151, k152, k153, k154, k155, k156, k157, k158, k159, k160, k161, k162, k163, k164, k165, k166, k167, k168, k169, k170, k171, k172, k173, k174, k175, k176, k177, k178, k179, k180, k181, k182, k183, k184, k185, k186, k187, k188, k189, k190, k191, k192, k193, k194, k195, k196, k197, k198, k199, k200, k201, k202, k203, k204, k205, k206, k207, k208, k209, k210, k211, k212, k213, k214, k215, k216, k217, k218, k219, k220, k221, k222, k223, k224, k225, k226, k227, k228, k229, k230, k231, k232, k233, k234, k235, k236, k237, k238, k239, k240, k241, k242, k243, k244, k245, k246, k247, k248, k249, k250, k251, k252, k253, k254, k255, k256, k257, k258, k259, k260, k261, k262, k263, k264, k265, k266, k267, k268, k269, k270, k271, k272, k273, k274, k275, -const - fatalMin* = errUnknown - fatalMax* = errInternal - errMin* = errUnknown - errMax* = errUser - warnMin* = warnCannotOpenFile - warnMax* = pred(hintSuccess) - hintMin* = hintSuccess - hintMax* = high(TMsgKind) +doAssert pred(k260) == k259 type - TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints - TNoteKinds* = set[TNoteKind] + FakeMsgKind2 = range[k230..high(FakeMsgKind)] + FakeMsgKind3 = set[FakeMsgKind2] -var - gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - - {warnUninit, warnProveField, warnProveIndex, warnGcUnsafe} +var gNotes: FakeMsgKind3 = {low(FakeMsgKind2)..high(FakeMsgKind2)} - {k233, k235} - -#import compiler.msgs - -echo warnUninit in gNotes +doAssert k233 notin gNotes # 7555 doAssert {-1.int8, -2, -2}.card == 2 @@ -218,3 +68,24 @@ type Foo = enum let x = { Foo1, Foo2 } # bug #8425 + +block: + # bug #2880 + type + FakeMsgKind = enum + k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100 + + type + FakeMsgKind2 = range[k50..high(FakeMsgKind)] + FakeMsgKind2s = set[FakeMsgKind2] + + const + a1: array[0..0, FakeMsgKind2s] = [{low(FakeMsgKind2)..high(FakeMsgKind2)} - {k99}] + a2 = a1[0] + + var + s1: FakeMsgKind2s = a1[0] + s2: FakeMsgKind2s = a2 + + doAssert k99 notin s1 + doAssert k99 notin s2 From 5439cfc317cd678438bd6c154b84c2bf625504ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B6hlich=20A?= Date: Thu, 29 Apr 2021 14:11:05 +0200 Subject: [PATCH 2519/4254] Fix `insert` calling wrong function (#17856) The `insert` method is calling `tryInsertID`, which ignores the `pkName` parameter. Calling `tryInsert` instead should be correct. --- lib/impure/db_postgres.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 034a94852..cb9e5414a 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -524,7 +524,7 @@ proc insert*(db: DbConn, query: SqlQuery, pkName: string, {.tags: [WriteDbEffect], since: (1, 3).} = ## executes the query (typically "INSERT") and returns the ## generated ID - result = tryInsertID(db, query, args) + result = tryInsert(db, query, pkName, args) if result < 0: dbError(db) proc execAffectedRows*(db: DbConn, query: SqlQuery, From e61381a293ab4986427c5ce8968c6c031c83f34f Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 29 Apr 2021 18:16:14 +0300 Subject: [PATCH 2520/4254] follow-up #17692: more inline syntax highlighting (#17837) --- doc/apis.rst | 5 +- doc/backends.rst | 131 +++++++++++++------------ doc/manual.rst | 47 ++++----- doc/nimc.rst | 240 +++++++++++++++++++++++++++------------------- doc/rstcommon.rst | 45 +++++++++ 5 files changed, 287 insertions(+), 181 deletions(-) diff --git a/doc/apis.rst b/doc/apis.rst index d01e75d78..e8313749d 100644 --- a/doc/apis.rst +++ b/doc/apis.rst @@ -1,9 +1,10 @@ -.. default-role:: code - ================= API naming design ================= +.. default-role:: code +.. include:: rstcommon.rst + The API is designed to be **easy to use** and consistent. Ease of use is measured by the number of calls to achieve a concrete high-level action. diff --git a/doc/backends.rst b/doc/backends.rst index 896b0f834..377e899b0 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ================================ Nim Backend Integration ================================ @@ -7,6 +5,10 @@ :Author: Puppet Master :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst +.. no syntax highlighting here by default: + .. contents:: "Heresy grows from idleness." -- Unknown. @@ -15,8 +17,9 @@ Introduction ============ The `Nim Compiler User Guide `_ documents the typical -compiler invocation, using the `compile` or `c` command to transform a -`.nim` file into one or more `.c` files which are then compiled with the +compiler invocation, using the `compile`:option: +or `c`:option: command to transform a +``.nim`` file into one or more ``.c`` files which are then compiled with the platform's C compiler into a static binary. However, there are other commands to compile to C++, Objective-C, or JavaScript. This document tries to concentrate in a single place all the backend and interfacing options. @@ -25,7 +28,7 @@ The Nim compiler supports mainly two backend families: the C, C++ and Objective-C targets and the JavaScript target. `The C like targets <#backends-the-c-like-targets>`_ creates source files that can be compiled into a library or a final executable. `The JavaScript target -<#backends-the-javascript-target>`_ can generate a `.js` file which you +<#backends-the-javascript-target>`_ can generate a ``.js`` file which you reference from an HTML file or create a `standalone Node.js program `_. @@ -42,20 +45,22 @@ The C like targets The commands to compile to either C, C++ or Objective-C are: - //compileToC, cc compile project with C code generator - //compileToCpp, cpp compile project to C++ code - //compileToOC, objc compile project to Objective C code +//compileToC, cc compile project with C code generator +//compileToCpp, cpp compile project to C++ code +//compileToOC, objc compile project to Objective C code The most significant difference between these commands is that if you look -into the `nimcache` directory you will find `.c`, `.cpp` or `.m` +into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m`` files, other than that all of them will produce a native binary for your project. This allows you to take the generated code and place it directly into a project using any of these languages. Here are some typical command- -line invocations:: +line invocations: - $ nim c hallo.nim - $ nim cpp hallo.nim - $ nim objc hallo.nim +.. code:: cmd + + nim c hallo.nim + nim cpp hallo.nim + nim objc hallo.nim The compiler commands select the target backend, but if needed you can `specify additional switches for cross-compilation @@ -66,11 +71,11 @@ or compiler/linker commands. The JavaScript target --------------------- -Nim can also generate `JavaScript`:idx: code through the `js` command. +Nim can also generate `JavaScript`:idx: code through the `js`:option: command. Nim targets JavaScript 1.5 which is supported by any widely used browser. Since JavaScript does not have a portable means to include another module, -Nim just generates a long `.js` file. +Nim just generates a long ``.js`` file. Features or modules that the JavaScript platform does not support are not available. This includes: @@ -88,10 +93,12 @@ To compensate, the standard library has modules `catered to the JS backend and more support will come in the future (for instance, Node.js bindings to get OS info). -To compile a Nim module into a `.js` file use the `js` command; the -default is a `.js` file that is supposed to be referenced in an `.html` +To compile a Nim module into a ``.js`` file use the `js`:option: command; the +default is a ``.js`` file that is supposed to be referenced in an ``.html`` file. However, you can also run the code with `nodejs`:idx: -(``_):: +(``_): + +.. code:: cmd nim js -d:nodejs -r examples/hallo.nim @@ -150,7 +157,7 @@ interface. C invocation example ~~~~~~~~~~~~~~~~~~~~ -Create a `logic.c` file with the following content: +Create a ``logic.c`` file with the following content: .. code-block:: c int addTwoIntegers(int a, int b) @@ -158,7 +165,7 @@ Create a `logic.c` file with the following content: return a + b; } -Create a `calculator.nim` file with the following content: +Create a ``calculator.nim`` file with the following content: .. code-block:: nim @@ -168,26 +175,28 @@ Create a `calculator.nim` file with the following content: when isMainModule: echo addTwoIntegers(3, 7) -With these two files in place, you can run `nim c -r calculator.nim` and -the Nim compiler will compile the `logic.c` file in addition to -`calculator.nim` and link both into an executable, which outputs `10` when +With these two files in place, you can run `nim c -r calculator.nim`:cmd: and +the Nim compiler will compile the ``logic.c`` file in addition to +``calculator.nim`` and link both into an executable, which outputs `10` when run. Another way to link the C file statically and get the same effect would -be to remove the line with the `compile` pragma and run the following typical -Unix commands:: +be to remove the line with the `compile` pragma and run the following +typical Unix commands: - $ gcc -c logic.c - $ ar rvs mylib.a logic.o - $ nim c --passL:mylib.a -r calculator.nim +.. code:: cmd -Just like in this example we pass the path to the `mylib.a` library (and we -could as well pass `logic.o`) we could be passing switches to link any other + gcc -c logic.c + ar rvs mylib.a logic.o + nim c --passL:mylib.a -r calculator.nim + +Just like in this example we pass the path to the ``mylib.a`` library (and we +could as well pass ``logic.o``) we could be passing switches to link any other static C library. JavaScript invocation example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a `host.html` file with the following content: +Create a ``host.html`` file with the following content: .. code-block:: @@ -201,7 +210,7 @@ Create a `host.html` file with the following content: -Create a `calculator.nim` file with the following content (or reuse the one +Create a ``calculator.nim`` file with the following content (or reuse the one from the previous section): .. code-block:: nim @@ -212,7 +221,7 @@ from the previous section): echo addTwoIntegers(3, 7) Compile the Nim code to JavaScript with `nim js -o:calculator.js -calculator.nim` and open `host.html` in a browser. If the browser supports +calculator.nim`:cmd: and open ``host.html`` in a browser. If the browser supports javascript, you should see the value `10` in the browser's console. Use the `dom module `_ for specific DOM querying and modification procs or take a look at `karax `_ for how to @@ -237,7 +246,7 @@ Also, C code requires you to specify a forward declaration for functions or the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. -The Nim compiler can generate a C interface header through the `--header` +The Nim compiler can generate a C interface header through the `--header`:option: command-line switch. The generated header will contain all the exported symbols and the `NimMain` proc which you need to call before any other Nim code. @@ -246,7 +255,7 @@ Nim code. Nim invocation example from C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a `fib.nim` file with the following content: +Create a ``fib.nim`` file with the following content: .. code-block:: nim @@ -256,7 +265,7 @@ Create a `fib.nim` file with the following content: else: result = fib(a - 1) + fib(a - 2) -Create a `maths.c` file with the following content: +Create a ``maths.c`` file with the following content: .. code-block:: c @@ -273,36 +282,40 @@ Create a `maths.c` file with the following content: Now you can run the following Unix like commands to first generate C sources from the Nim code, then link them into a static binary along your main C -program:: +program: - $ nim c --noMain --noLinking --header:fib.h fib.nim - $ gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c +.. code:: cmd + + nim c --noMain --noLinking --header:fib.h fib.nim + gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c The first command runs the Nim compiler with three special options to avoid -generating a `main()` function in the generated files, avoid linking the +generating a `main()`:c: function in the generated files, avoid linking the object files into a final binary, and explicitly generate a header file for C -integration. All the generated files are placed into the `nimcache` -directory. That's why the next command compiles the `maths.c` source plus -all the `.c` files from `nimcache`. In addition to this path, you also -have to tell the C compiler where to find Nim's `nimbase.h` header file. +integration. All the generated files are placed into the ``nimcache`` +directory. That's why the next command compiles the ``maths.c`` source plus +all the ``.c`` files from ``nimcache``. In addition to this path, you also +have to tell the C compiler where to find Nim's ``nimbase.h`` header file. -Instead of depending on the generation of the individual `.c` files you can -also ask the Nim compiler to generate a statically linked library:: +Instead of depending on the generation of the individual ``.c`` files you can +also ask the Nim compiler to generate a statically linked library: - $ nim c --app:staticLib --noMain --header fib.nim - $ gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c +.. code:: cmd + + nim c --app:staticLib --noMain --header fib.nim + gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c The Nim compiler will handle linking the source files generated in the -`nimcache` directory into the `libfib.nim.a` static library, which you can +``nimcache`` directory into the ``libfib.nim.a`` static library, which you can then link into your C program. Note that these commands are generic and will vary for each system. For instance, on Linux systems you will likely need to -use `-ldl` too to link in required dlopen functionality. +use `-ldl`:option: too to link in required dlopen functionality. Nim invocation example from JavaScript ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a `mhost.html` file with the following content: +Create a ``mhost.html`` file with the following content: .. code-block:: @@ -313,7 +326,7 @@ Create a `mhost.html` file with the following content: -Create a `fib.nim` file with the following content (or reuse the one +Create a ``fib.nim`` file with the following content (or reuse the one from the previous section): .. code-block:: nim @@ -324,9 +337,9 @@ from the previous section): else: result = fib(a - 1) + fib(a - 2) -Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim` and -open `mhost.html` in a browser. If the browser supports javascript, you -should see an alert box displaying the text `Fib for 9 is 34`. As mentioned +Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim`:cmd: and +open ``mhost.html`` in a browser. If the browser supports javascript, you +should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned earlier, JavaScript doesn't require an initialization call to `NimMain` or a similar function and you can call the exported Nim proc directly. @@ -337,7 +350,7 @@ Nimcache naming logic The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default name for the directory depends on the used backend and on your OS but you can -use the `--nimcache` `compiler switch +use the `--nimcache`:option: `compiler switch `_ to change it. @@ -362,8 +375,8 @@ painless. Most C functions accepting a Nim string converted to a `cstring` will likely not need to keep this string around and by the time they return the string won't be needed anymore. However, for the rare cases where a Nim string has to be preserved and made available to the C backend -as a `cstring`, you will need to manually prevent the string data from being -freed with `GC_ref `_ and `GC_unref +as a `cstring`, you will need to manually prevent the string data +from being freed with `GC_ref `_ and `GC_unref `_. A similar thing happens with C code invoking Nim code which returns a @@ -399,7 +412,7 @@ Again, if you are wrapping a library which *mallocs* and *frees* data structures, you need to expose the appropriate *free* function to Nim so you can clean it up. And of course, once cleaned you should avoid accessing it from Nim (or C for that matter). Typically C data structures have their own -`malloc_structure` and `free_structure` specific functions, so wrapping +`malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping these for the Nim side should be enough. diff --git a/doc/manual.rst b/doc/manual.rst index e98a0cc09..50e9b5be5 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -127,9 +127,9 @@ compiler may instead choose to allow the program to die with a fatal error. echo "invalid index" The current implementation allows to switch between these different behaviors -via ``--panics:on|off``. When panics are turned on, the program dies with a +via `--panics:on|off`:option:. When panics are turned on, the program dies with a panic, if they are turned off the runtime errors are turned into -exceptions. The benefit of ``--panics:on`` is that it produces smaller binary +exceptions. The benefit of `--panics:on`:option: is that it produces smaller binary code and the compiler has more freedom to optimize the code. An `unchecked runtime error`:idx: is an error that is not guaranteed to be @@ -678,7 +678,7 @@ defined here.) These keywords are also operators: `and or not xor shl shr div mod in notin is isnot of as from`. -`.`:tok: `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they +`.`:tok:, `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they are used for other notational purposes. `*:` is as a special case treated as the two tokens `*`:tok: and `:`:tok: @@ -697,7 +697,7 @@ The following strings denote other tokens:: The `slice`:idx: operator `..`:tok: takes precedence over other tokens that -contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: +contain a dot: `{..}` are the three tokens `{`:tok:, `..`:tok:, `}`:tok: and not the two tokens `{.`:tok:, `.}`:tok:. @@ -1460,7 +1460,7 @@ The notation `x[i]` can be used to access the i-th element of `x`. Arrays are always bounds checked (statically or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -``--boundChecks:off`` command-line switch. +`--boundChecks:off`:option: command-line switch. An array constructor can have explicit indexes for readability: @@ -4093,7 +4093,7 @@ Multi-methods -------------- **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -``--multimethods:on`` when compiling. +`--multimethods:on`:option: when compiling. In a multi-method, all parameters that have an object type are used for the dispatching: @@ -4805,7 +4805,7 @@ And so is: The reason for this is that `DivByZeroDefect` inherits from `Defect` and -with ``--panics:on`` Defects become unrecoverable errors. +with `--panics:on`:option: Defects become unrecoverable errors. (Since version 1.4 of the language.) @@ -5604,7 +5604,7 @@ However, this means that the method call syntax is not available for **Note**: The Nim compiler prior to version 1 was more lenient about this -requirement. Use the ``--useVersion:0.19`` switch for a transition period. +requirement. Use the `--useVersion:0.19`:option: switch for a transition period. @@ -6960,7 +6960,7 @@ with the project: {.compile: "myfile.cpp".} **Note**: Nim computes a SHA1 checksum and only recompiles the file if it -has changed. One can use the ``-f`` command-line option to force +has changed. One can use the `-f`:option: command-line option to force the recompilation of the file. Since 1.4 the `compile` pragma is also available with this syntax: @@ -6983,7 +6983,7 @@ The `link` pragma can be used to link an additional file with the project: PassC pragma ------------ The `passc` pragma can be used to pass additional parameters to the C -compiler like one would using the command-line switch ``--passc``: +compiler like one would using the command-line switch `--passc`:option:\: .. code-block:: Nim {.passc: "-Wall -Werror".} @@ -7011,7 +7011,7 @@ the pragma resides in: PassL pragma ------------ The `passL` pragma can be used to pass additional parameters to the linker -like one would be using the command-line switch ``--passL``: +like one would be using the command-line switch `--passL`:option:\: .. code-block:: Nim {.passL: "-lSDLmain -lSDL".} @@ -7047,8 +7047,8 @@ Example: embedsC() -`nimbase.h` defines `NIM_EXTERNC` C macro that can be used for -`extern "C"`:cpp: code to work with both `nim c` and `nim cpp`, e.g.: +``nimbase.h`` defines `NIM_EXTERNC`:c: C macro that can be used for +`extern "C"`:cpp: code to work with both `nim c`:cmd: and `nim cpp`:cmd:, e.g.: .. code-block:: Nim proc foobar() {.importc:"$1".} @@ -7124,7 +7124,7 @@ pragmas this allows *sloppy* interfacing with libraries written in C++: proc run(device: IrrlichtDevice): bool {. header: irr, importcpp: "#.run(@)".} -The compiler needs to be told to generate C++ (command ``cpp``) for +The compiler needs to be told to generate C++ (command `cpp`:option:) for this to work. The conditional symbol `cpp` is defined when the compiler emits C++ code. @@ -7368,7 +7368,7 @@ allows *sloppy* interfacing with libraries written in Objective C: g.greet(12, 34) g.free() -The compiler needs to be told to generate Objective C (command ``objc``) for +The compiler needs to be told to generate Objective C (command `objc`:option:) for this to work. The conditional symbol ``objc`` is defined when the compiler emits Objective C code. @@ -7414,7 +7414,7 @@ will generate this code: The `.cppNonPod` pragma should be used for non-POD `importcpp` types so that they work properly (in particular regarding constructor and destructor) for -`.threadvar` variables. This requires ``--tlsEmulation:off``. +`.threadvar` variables. This requires `--tlsEmulation:off`:option:. .. code-block:: nim type Foo {.cppNonPod, importcpp, header: "funs.h".} = object @@ -7458,12 +7458,13 @@ pragma description :: nim c -d:FooBar=42 foobar.nim -In the above example, providing the ``-d`` flag causes the symbol +In the above example, providing the `-d`:option: flag causes the symbol `FooBar` to be overwritten at compile-time, printing out 42. If the -``-d:FooBar=42`` were to be omitted, the default value of 5 would be +`-d:FooBar=42`:option: were to be omitted, the default value of 5 would be used. To see if a value was provided, `defined(FooBar)` can be used. -The syntax ``-d:flag`` is actually just a shortcut for ``-d:flag=true``. +The syntax `-d:flag`:option: is actually just a shortcut for +`-d:flag=true`:option:. User-defined pragmas ==================== @@ -7800,7 +7801,7 @@ strings, because they are precompiled. because of order of initialization problems. **Note**: A `dynlib` import can be overridden with -the ``--dynlibOverride:name`` command-line option. The +the `--dynlibOverride:name`:option: command-line option. The `Compiler User Guide `_ contains further information. @@ -7815,14 +7816,14 @@ conjunction with the `exportc` pragma: proc exportme(): int {.cdecl, exportc, dynlib.} This is only useful if the program is compiled as a dynamic library via the -``--app:lib`` command-line option. +`--app:lib`:option: command-line option. Threads ======= -To enable thread support the ``--threads:on`` command-line switch needs to +To enable thread support the `--threads:on`:option: command-line switch needs to be used. The system_ module then contains several threading primitives. See the `threads `_ and `channels `_ modules for the low-level thread API. There are also high-level parallelism constructs @@ -7864,7 +7865,7 @@ any of its parameters contain a `ref` or `closure` type. This enforces the *no heap sharing restriction*. Routines that are imported from C are always assumed to be `gcsafe`. -To disable the GC-safety checking the ``--threadAnalysis:off`` command-line +To disable the GC-safety checking the `--threadAnalysis:off`:option: command-line switch can be used. This is a temporary workaround to ease the porting effort from old code to the new threading model. diff --git a/doc/nimc.rst b/doc/nimc.rst index 9db95e81b..47f7243cc 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -1,5 +1,3 @@ -.. default-role:: code - =================================== Nim Compiler User Guide =================================== @@ -7,8 +5,12 @@ :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: +.. + "Look at you, hacker. A pathetic creature of meat and bone, panting and sweating as you run through my corridors. How can you challenge a perfect, immortal machine?" @@ -32,6 +34,9 @@ Command-line switches --------------------- Basic command-line switches are: +.. no syntax highlighting in the below included files at the moment +.. default-role:: code + Usage: .. include:: basicopt.txt @@ -43,11 +48,12 @@ Advanced command-line switches are: .. include:: advopt.txt +.. include:: rstcommon.rst List of warnings ---------------- -Each warning can be activated individually with `--warning[NAME]:on|off` or +Each warning can be activated individually with `--warning[NAME]:on|off`:option: or in a `push` pragma. ========================== ============================================ @@ -71,7 +77,7 @@ User Some user-defined warning. List of hints ------------- -Each hint can be activated individually with `--hint[NAME]:on|off` or in a +Each hint can be activated individually with `--hint[NAME]:on|off`:option: or in a `push` pragma. ========================== ============================================ @@ -132,22 +138,22 @@ Level Description Compile-time symbols -------------------- -Through the `-d:x` or `--define:x` switch you can define compile-time +Through the `-d:x`:option: or `--define:x`:option: switch you can define compile-time symbols for conditional compilation. The defined switches can be checked in source code with the `when statement `_ and `defined proc `_. The typical use of this switch is -to enable builds in release mode (`-d:release`) where optimizations are -enabled for better performance. Another common use is the `-d:ssl` switch to +to enable builds in release mode (`-d:release`:option:) where optimizations are +enabled for better performance. Another common use is the `-d:ssl`:option: switch to activate SSL sockets. -Additionally, you may pass a value along with the symbol: `-d:x=y` +Additionally, you may pass a value along with the symbol: `-d:x=y`:option: which may be used in conjunction with the `compile-time define pragmas`_ to override symbols during build time. Compile-time symbols are completely **case insensitive** and underscores are -ignored too. `--define:FOO` and `--define:foo` are identical. +ignored too. `--define:FOO`:option: and `--define:foo`:option: are identical. Compile-time symbols starting with the `nim` prefix are reserved for the implementation and should not be used elsewhere. @@ -156,28 +162,47 @@ implementation and should not be used elsewhere. Configuration files ------------------- -**Note:** The *project file name* is the name of the `.nim` file that is +**Note:** The *project file name* is the name of the ``.nim`` file that is passed as a command-line argument to the compiler. -The `nim` executable processes configuration files in the following +The `nim`:cmd: executable processes configuration files in the following directories (in this order; later files overwrite previous settings): -1) `$nim/config/nim.cfg`, `/etc/nim/nim.cfg` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the `--skipCfg` command line option. -2) If environment variable `XDG_CONFIG_HOME` is defined, `$XDG_CONFIG_HOME/nim/nim.cfg` or `~/.config/nim/nim.cfg` (POSIX) or `%APPDATA%/nim/nim.cfg` (Windows). This file can be skipped with the `--skipUserCfg` command line option. -3) `$parentDir/nim.cfg` where `$parentDir` stands for any parent directory of the project file's path. These files can be skipped with the `--skipParentCfg` command-line option. -4) `$projectDir/nim.cfg` where `$projectDir` stands for the project file's path. This file can be skipped with the `--skipProjCfg` command-line option. -5) A project can also have a project-specific configuration file named `$project.nim.cfg` that resides in the same directory as `$project.nim`. This file can be skipped with the `--skipProjCfg` command-line option. +1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or + ``\config\nim.cfg`` (Windows). + This file can be skipped with the `--skipCfg`:option: command line option. +2) If environment variable `XDG_CONFIG_HOME` is defined, + ``$XDG_CONFIG_HOME/nim/nim.cfg`` or ``~/.config/nim/nim.cfg`` (POSIX) or + ``%APPDATA%/nim/nim.cfg`` (Windows). + This file can be skipped with the `--skipUserCfg`:option: command line + option. +3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent + directory of the project file's path. + These files can be skipped with the `--skipParentCfg`:option: + command-line option. +4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project + file's path. + This file can be skipped with the `--skipProjCfg`:option: + command-line option. +5) A project can also have a project-specific configuration file named + ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. + This file can be skipped with the `--skipProjCfg`:option: + command-line option. Command-line settings have priority over configuration file settings. The default build of a project is a `debug build`:idx:. To compile a -`release build`:idx: define the `release` symbol:: +`release build`:idx: define the `release` symbol: + +.. code:: cmd nim c -d:release myproject.nim - To compile a `dangerous release build`:idx: define the `danger` symbol:: +To compile a `dangerous release build`:idx: define the `danger` symbol: + +.. code:: cmd nim c -d:danger myproject.nim @@ -189,10 +214,10 @@ Nim has the concept of a global search path (PATH) that is queried to determine where to find imported modules or include files. If multiple files are found an ambiguity error is produced. -`nim dump` shows the contents of the PATH. +`nim dump`:cmd: shows the contents of the PATH. However before the PATH is used the current directory is checked for the -file's existence. So if PATH contains `$lib` and `$lib/bar` and the +file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the directory structure looks like this:: $lib/x.nim @@ -202,26 +227,26 @@ directory structure looks like this:: other.nim And `main` imports `x`, `foo/x` is imported. If `other` imports `x` -then both `$lib/x.nim` and `$lib/bar/x.nim` match but `$lib/x.nim` is used +then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match but ``$lib/x.nim`` is used as it is the first match. Generated C code directory -------------------------- The generated files that Nim produces all go into a subdirectory called -`nimcache`. Its full path is +``nimcache``. Its full path is -- `$XDG_CACHE_HOME/nim/$projectname(_r|_d)` or `~/.cache/nim/$projectname(_r|_d)` +- ``$XDG_CACHE_HOME/nim/$projectname(_r|_d)`` or ``~/.cache/nim/$projectname(_r|_d)`` on Posix -- `$HOME/nimcache/$projectname(_r|_d)` on Windows. +- ``$HOME\nimcache\$projectname(_r|_d)`` on Windows. The `_r` suffix is used for release builds, `_d` is for debug builds. This makes it easy to delete all generated files. -The `--nimcache` +The `--nimcache`:option: `compiler switch <#compiler-usage-commandminusline-switches>`_ can be used to -to change the `nimcache` directory. +to change the ``nimcache`` directory. However, the generated C code is not platform-independent. C code generated for Linux does not compile on Windows, for instance. The comment on top of the @@ -231,34 +256,40 @@ C file lists the OS, CPU, and CC the file has been compiled for. Compiler Selection ================== -To change the compiler from the default compiler (at the command line):: +To change the compiler from the default compiler (at the command line): + +.. code:: cmd nim c --cc:llvm_gcc --compile_only myfile.nim -This uses the configuration defined in ``config\nim.cfg`` for `lvm_gcc`. +This uses the configuration defined in ``config\nim.cfg`` for `llvm_gcc`:cmd:. If nimcache already contains compiled code from a different compiler for the same project, -add the `-f` flag to force all files to be recompiled. +add the `-f`:option: flag to force all files to be recompiled. The default compiler is defined at the top of ``config\nim.cfg``. -Changing this setting affects the compiler used by `koch` to (re)build Nim. +Changing this setting affects the compiler used by `koch`:cmd: to (re)build Nim. -To use the `CC` environment variable, use `nim c --cc:env myfile.nim`. To use the -`CXX` environment variable, use `nim cpp --cc:env myfile.nim`. `--cc:env` is available -since Nim version 1.4. +To use the `CC` environment variable, use `nim c --cc:env myfile.nim`:cmd:. +To use the `CXX` environment variable, use `nim cpp --cc:env myfile.nim`:cmd:. +`--cc:env`:option: is available since Nim version 1.4. Cross-compilation ================= -To cross compile, use for example:: +To cross compile, use for example: + +.. code:: cmd nim c --cpu:i386 --os:linux --compileOnly --genScript myproject.nim -Then move the C code and the compile script `compile_myproject.sh` to your +Then move the C code and the compile script `compile_myproject.sh`:cmd: to your Linux i386 machine and run the script. -Another way is to make Nim invoke a cross compiler toolchain:: +Another way is to make Nim invoke a cross compiler toolchain: + +.. code:: cmd nim c --cpu:arm --os:linux myproject.nim @@ -274,17 +305,22 @@ configuration file should contain something like:: Cross-compilation for Windows ============================= -To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain:: +To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain: + +.. code:: cmd nim c -d:mingw myproject.nim -Use `--cpu:i386` or `--cpu:amd64` to switch the CPU architecture. +Use `--cpu:i386`:option: or `--cpu:amd64`:option: to switch the CPU architecture. -The MinGW-w64 toolchain can be installed as follows:: +The MinGW-w64 toolchain can be installed as follows: - Ubuntu: apt install mingw-w64 - CentOS: yum install mingw32-gcc | mingw64-gcc - requires EPEL - OSX: brew install mingw-w64 +.. code:: cmd + + apt install mingw-w64 # Ubuntu + yum install mingw32-gcc + yum install mingw64-gcc # CentOS - requires EPEL + brew install mingw-w64 # OSX Cross-compilation for Android @@ -298,7 +334,7 @@ The first one is to treat Android as a simple Linux and use directly on android as if it was Linux. These programs are console-only programs that can't be distributed in the Play Store. -Use regular `nim c` inside termux to make Android terminal programs. +Use regular `nim c`:cmd: inside termux to make Android terminal programs. Normal Android apps are written in Java, to use Nim inside an Android app you need a small Java stub that calls out to a native library written in @@ -306,16 +342,16 @@ Nim using the `NDK `_. You can also use `native-activity `_ to have the Java stub be auto-generated for you. -Use `nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on` to +Use `nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on`:cmd: to generate the C source files you need to include in your Android Studio project. Add the generated C files to CMake build script in your Android project. Then do the final compile with Android Studio which uses Gradle to call CMake to compile the project. -Because Nim is part of a library it can't have its own c style `main()` -so you would need to define your own `android_main` and init the Java +Because Nim is part of a library it can't have its own C-style `main()`:c: +so you would need to define your own `android_main`:c: and init the Java environment, or use a library like SDL2 or GLFM to do it. After the Android -stuff is done, it's very important to call `NimMain()` in order to +stuff is done, it's very important to call `NimMain()`:c: in order to initialize Nim's garbage collector and to run the top level statements of your program. @@ -334,14 +370,14 @@ Normal languages for iOS development are Swift and Objective C. Both of these use LLVM and can be compiled into object files linked together with C, C++ or Objective C code produced by Nim. -Use `nim c -c --os:ios --noMain:on` to generate C files and include them in +Use `nim c -c --os:ios --noMain:on`:cmd: to generate C files and include them in your XCode project. Then you can use XCode to compile, link, package and sign everything. -Because Nim is part of a library it can't have its own c style `main()` so you +Because Nim is part of a library it can't have its own C-style `main()`:c: so you would need to define `main` that calls `autoreleasepool` and `UIApplicationMain` to do it, or use a library like SDL2 or GLFM. After -the iOS setup is done, it's very important to call `NimMain()` to +the iOS setup is done, it's very important to call `NimMain()`:c: to initialize Nim's garbage collector and to run the top-level statements of your program. @@ -358,17 +394,16 @@ so you need to clean those files manually to do a clean build. Cross-compilation for Nintendo Switch ===================================== -Simply add --os:nintendoswitch -to your usual `nim c` or `nim cpp` command and set the `passC` -and `passL` command line switches to something like: +Simply add `--os:nintendoswitch`:option: +to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option: +and `passL`:option: command line switches to something like: -.. code-block:: console +.. code-block:: cmd nim c ... --passC="-I$DEVKITPRO/libnx/include" ... --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" -or setup a nim.cfg file like so: +or setup a ``nim.cfg`` file like so:: -.. code-block:: Nim #nim.cfg --passC="-I$DEVKITPRO/libnx/include" --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" @@ -377,12 +412,14 @@ The DevkitPro setup must be the same as the default with their new installer `here for Mac/Linux `_ or `here for Windows `_. -For example, with the above-mentioned config:: +For example, with the above-mentioned config: + +.. code:: cmd nim c --os:nintendoswitch switchhomebrew.nim -This will generate a file called `switchhomebrew.elf` which can then be turned into -an nro file with the `elf2nro` tool in the DevkitPro release. Examples can be found at +This will generate a file called ``switchhomebrew.elf`` which can then be turned into +an nro file with the `elf2nro`:cmd: tool in the DevkitPro release. Examples can be found at `the nim-libnx github repo `_. There are a few things that don't work because the DevkitPro libraries don't support them. @@ -402,16 +439,20 @@ DLL generation Nim supports the generation of DLLs. However, there must be only one instance of the GC per process/address space. This instance is contained in -`nimrtl.dll`. This means that every generated Nim DLL depends -on `nimrtl.dll`. To generate the "nimrtl.dll" file, use the command:: +``nimrtl.dll``. This means that every generated Nim DLL depends +on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command: + +.. code:: cmd nim c -d:release lib/nimrtl.nim -To link against `nimrtl.dll` use the command:: +To link against ``nimrtl.dll`` use the command: + +.. code:: cmd nim c -d:useNimRtl myprog.nim -**Note**: Currently the creation of `nimrtl.dll` with thread support has +**Note**: Currently the creation of ``nimrtl.dll`` with thread support has never been tested and is unlikely to work! @@ -427,20 +468,20 @@ Define Effect ====================== ========================================================= `release` Turns on the optimizer. More aggressive optimizations are possible, e.g.: - `--passC:-ffast-math` (but see issue #10305) + `--passC:-ffast-math`:option: (but see issue #10305) `danger` Turns off all runtime checks and turns on the optimizer. -`useFork` Makes `osproc` use `fork` instead of `posix_spawn`. -`useNimRtl` Compile and link against `nimrtl.dll`. +`useFork` Makes `osproc` use `fork`:c: instead of `posix_spawn`:c:. +`useNimRtl` Compile and link against ``nimrtl.dll``. `useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's own memory manager, albeit prefixing each allocation with its size to support clearing memory on reallocation. - This only works with `gc:none`, `gc:arc` and - `--gc:orc`. + This only works with `--gc:none`:option:, + `--gc:arc`:option: and `--gc:orc`:option:. `useRealtimeGC` Enables support of Nim's GC for *soft* realtime systems. See the documentation of the `gc `_ for further information. `logGC` Enable GC logging to stdout. -`nodejs` The JS target is actually `node.js`. +`nodejs` The JS target is actually ``node.js``. `ssl` Enables OpenSSL support for the sockets module. `memProfiler` Enables memory profiling for the native GC. `uClibc` Use uClibc instead of libc. (Relevant for Unix-like OSes) @@ -448,16 +489,16 @@ Define Effect what's in the Nim file with what's in the C header. This may become enabled by default in the future. `tempDir` This symbol takes a string as its value, like - `--define:tempDir:/some/temp/path` to override the - temporary directory returned by `os.getTempDir()`. + `--define:tempDir:/some/temp/path`:option: to override + the temporary directory returned by `os.getTempDir()`. The value **should** end with a directory separator character. (Relevant for the Android platform) `useShPath` This symbol takes a string as its value, like - `--define:useShPath:/opt/sh/bin/sh` to override the - path for the `sh` binary, in cases where it is not - located in the default location `/bin/sh`. -`noSignalHandler` Disable the crash handler from `system.nim`. -`globalSymbols` Load all `{.dynlib.}` libraries with the `RTLD_GLOBAL` + `--define:useShPath:/opt/sh/bin/sh`:option: to override + the path for the `sh`:cmd: binary, in cases where it is + not located in the default location ``/bin/sh``. +`noSignalHandler` Disable the crash handler from ``system.nim``. +`globalSymbols` Load all `{.dynlib.}` libraries with the `RTLD_GLOBAL`:c: flag on Posix systems to resolve symbols in subsequently loaded libraries. ====================== ========================================================= @@ -474,20 +515,21 @@ generator and are subject to change. LineDir option -------------- -The `lineDir` option can be turned on or off. If turned on the -generated C code contains `#line` directives. This may be helpful for +The `--lineDir`:option: option can be turned on or off. If turned on the +generated C code contains `#line`:c: directives. This may be helpful for debugging with GDB. StackTrace option ----------------- -If the `stackTrace` option is turned on, the generated C contains code to +If the `--stackTrace`:option: option is turned on, the generated C contains code to ensure that proper stack traces are given if the program crashes or some uncaught exception is raised. LineTrace option ---------------- -The `lineTrace` option implies the `stackTrace` option. If turned on, +The `--lineTrace`:option: option implies the `stackTrace`:option: option. +If turned on, the generated C contains code to ensure that proper stack traces with line number information are given if the program crashes or an uncaught exception is raised. @@ -497,11 +539,13 @@ DynlibOverride ============== By default Nim's `dynlib` pragma causes the compiler to generate -`GetProcAddress` (or their Unix counterparts) -calls to bind to a DLL. With the `dynlibOverride` command line switch this -can be prevented and then via `--passL` the static library can be linked +`GetProcAddress`:cpp: (or their Unix counterparts) +calls to bind to a DLL. With the `dynlibOverride`:option: command line switch this +can be prevented and then via `--passL`:option: the static library can be linked against. For instance, to link statically against Lua this command might work -on Linux:: +on Linux: + +.. code:: cmd nim c --dynlibOverride:lua --passL:liblua.lib program.nim @@ -509,8 +553,8 @@ on Linux:: Backend language options ======================== -The typical compiler usage involves using the `compile` or `c` command to -transform a `.nim` file into one or more `.c` files which are then +The typical compiler usage involves using the `compile`:option: or `c`:option: +command to transform a ``.nim`` file into one or more ``.c`` files which are then compiled with the platform's C compiler into a static binary. However, there are other commands to compile to C++, Objective-C, or JavaScript. More details can be read in the `Nim Backend Integration document `_. @@ -520,7 +564,7 @@ Nim documentation tools ======================= Nim provides the `doc`:idx: command to generate HTML -documentation from `.nim` source files. Only exported symbols will appear in +documentation from ``.nim`` source files. Only exported symbols will appear in the output. For more details `see the docgen documentation `_. Nim idetools integration @@ -558,19 +602,21 @@ embedded microprocessors with only a few kilobytes of memory. A good start is to use the `any` operating target together with the `malloc` memory allocator and the `arc` garbage collector. For example: -`nim c --os:any --gc:arc -d:useMalloc [...] x.nim` +.. code:: cmd -- `--gc:arc` will enable the reference counting memory management instead + nim c --os:any --gc:arc -d:useMalloc [...] x.nim + +- `--gc:arc`:option: will enable the reference counting memory management instead of the default garbage collector. This enables Nim to use heap memory which is required for strings and seqs, for example. -- The `--os:any` target makes sure Nim does not depend on any specific +- The `--os:any`:option: target makes sure Nim does not depend on any specific operating system primitives. Your platform should support only some basic ANSI C library `stdlib` and `stdio` functions which should be available on almost any platform. -- The `-d:useMalloc` option configures Nim to use only the standard C memory - manage primitives `malloc()`, `free()`, `realloc()`. +- The `-d:useMalloc`:option: option configures Nim to use only the standard C memory + manage primitives `malloc()`:c:, `free()`:c:, `realloc()`:c:. If your platform does not provide these functions it should be trivial to provide an implementation for them and link these to your program. @@ -580,13 +626,13 @@ additional flags to both the Nim compiler and the C compiler and/or linker to optimize the build for size. For example, the following flags can be used when targeting a gcc compiler: -`--opt:size --passC:-flto --passL:-flto` +`--opt:size --passC:-flto --passL:-flto`:option: -The `--opt:size` flag instructs Nim to optimize code generation for small -size (with the help of the C compiler), the `flto` flags enable link-time +The `--opt:size`:option: flag instructs Nim to optimize code generation for small +size (with the help of the C compiler), the `-flto`:option: flags enable link-time optimization in the compiler and linker. -Check the `Cross-compilation` section for instructions on how to compile the +Check the `Cross-compilation`_ section for instructions on how to compile the program for your target. Nim for realtime systems @@ -603,7 +649,7 @@ The Nim programming language has no concept of Posix's signal handling mechanisms. However, the standard library offers some rudimentary support for signal handling, in particular, segmentation faults are turned into fatal errors that produce a stack trace. This can be disabled with the -`-d:noSignalHandler` switch. +`-d:noSignalHandler`:option: switch. Optimizing for Nim diff --git a/doc/rstcommon.rst b/doc/rstcommon.rst index c1503fa96..7ecc7b8cb 100644 --- a/doc/rstcommon.rst +++ b/doc/rstcommon.rst @@ -1,6 +1,51 @@ +.. + Usage of this file: + Add this in the beginning of *.rst file:: + + .. default-role:: code + .. include:: rstcommon.rst + + It's the current trick for brevity and compatibility with both Github and + rst2html.py, considering that Github cannot highlight Nim in + RST files anyway and it does not include files. + This way interpreted text is displayed with monospaced font in Github + and it's displayed an Nim code in both rst2html.py + (note ".. default-role:: Nim" above) and `nim rst2html`. + + For files that are user manual and consist of stuff like cmdline + option description, use 'code' as a **real** default role: + + .. include:: rstcommon.rst + .. default-role:: code + +.. define language roles explicitly (for compatibility with rst2html.py): .. role:: nim(code) :language: nim .. default-role:: nim +.. role:: c(code) + :language: c + +.. role:: cpp(code) + :language: cpp + +.. role:: yaml(code) + :language: yaml + +.. role:: python(code) + :language: python + +.. role:: java(code) + :language: java + +.. role:: csharp(code) + :language: csharp + +.. role:: cmd(code) + +.. role:: program(code) + +.. role:: option(code) + From 16405083485967a395b8d677833bc26040881b21 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 29 Apr 2021 18:31:15 +0300 Subject: [PATCH 2521/4254] more strict RST inline markup parsing (#17827) * more strict RST inline markup parsing * add test for unexpected bonus * introduce `roPreferMarkdown` --- compiler/docgen.nim | 7 +- lib/packages/docutils/rst.nim | 52 ++++++++--- tests/stdlib/trst.nim | 161 ++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 13 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 977fcf8ef..78fb88f9b 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -178,7 +178,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.outDir = conf.outDir.string initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), conf.configVars, filename.string, - {roSupportRawDirective, roSupportMarkdown, roNimFile}, + {roSupportRawDirective, roSupportMarkdown, + roPreferMarkdown, roNimFile}, docgenFindFile, compilerMsgHandler) if conf.configVars.hasKey("doc.googleAnalytics"): @@ -1380,7 +1381,9 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; d.isPureRst = true var rst = parseRst(readFile(filen.string), filen.string, line=LineRstInit, column=ColRstInit, - d.hasToc, {roSupportRawDirective, roSupportMarkdown}, conf) + d.hasToc, + {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown}, + conf) var modDesc = newStringOfCap(30_000) renderRstToOut(d[], rst, modDesc) d.modDesc = rope(modDesc) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index cb65791ff..6ad466716 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -11,9 +11,9 @@ ## rst ## ================================== ## -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## Nim-flavored reStructuredText -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## Nim-flavored reStructuredText and Markdown +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## ## This module implements a `reStructuredText`:idx: (RST) parser. ## A large subset is implemented with some limitations_ and @@ -177,6 +177,8 @@ type roSupportRawDirective, ## support the ``raw`` directive (don't support ## it for sandboxing) roSupportMarkdown, ## support additional features of Markdown + roPreferMarkdown, ## parse as Markdown (keeping RST as "extension" + ## to Markdown) -- implies `roSupportMarkdown` roNimFile ## set for Nim files where default interpreted ## text role should be :nim: @@ -277,6 +279,7 @@ type line*, col*, baseIndent*: int skipPounds*: bool adornmentLine*: bool + escapeNext*: bool proc getThing(L: var Lexer, tok: var Token, s: set[char]) = tok.kind = tkWord @@ -314,10 +317,18 @@ proc getPunctAdornment(L: var Lexer, tok: var Token) = tok.col = L.col var pos = L.bufpos let c = L.buf[pos] - while true: + if not L.escapeNext and (c != '\\' or L.adornmentLine): + while true: + tok.symbol.add(L.buf[pos]) + inc pos + if L.buf[pos] != c: break + elif L.escapeNext: tok.symbol.add(L.buf[pos]) inc pos - if L.buf[pos] != c: break + else: # not L.escapeNext and c == '\\' and not L.adornmentLine + tok.symbol.add '\\' + inc pos + L.escapeNext = true inc L.col, pos - L.bufpos L.bufpos = pos if tok.symbol == "\\": tok.kind = tkPunct @@ -429,7 +440,9 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TokenSeq): int = while true: inc length setLen(tokens, length) + let toEscape = L.escapeNext rawGetTok(L, tokens[length - 1]) + if toEscape: L.escapeNext = false if tokens[length - 1].kind == tkEof: break if tokens[0].kind == tkWhite: # BUGFIX @@ -981,16 +994,24 @@ proc expect(p: var RstParser, tok: string) = if currentTok(p).symbol == tok: inc p.idx else: rstMessage(p, meExpected, tok) -proc isInlineMarkupEnd(p: RstParser, markup: string): bool = +proc isInlineMarkupEnd(p: RstParser, markup: string, exact: bool): bool = # rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules - result = currentTok(p).symbol == markup + if exact: + result = currentTok(p).symbol == markup + else: + result = currentTok(p).symbol.endsWith markup + if (not result) and markup == "``": + # check that escaping may have splitted `` to 2 tokens ` and ` + result = currentTok(p).symbol == "`" and prevTok(p).symbol == "`" if not result: return # Rule 2: result = prevTok(p).kind notin {tkIndent, tkWhite} if not result: return # Rule 7: result = nextTok(p).kind in {tkIndent, tkWhite, tkEof} or - markup in ["``", "`"] and nextTok(p).kind in {tkIndent, tkWhite, tkWord, tkEof} or + (roPreferMarkdown in p.s.options and + markup in ["``", "`"] and + nextTok(p).kind in {tkIndent, tkWhite, tkWord, tkEof}) or nextTok(p).symbol[0] in {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', '?', '_'} if not result: return @@ -1130,7 +1151,8 @@ proc toOtherRole(n: PRstNode, kind: RstNodeKind, roleName: string): PRstNode = proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var newKind = n.kind var newSons = n.sons - if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"): + if isInlineMarkupEnd(p, "_", exact=true) or + isInlineMarkupEnd(p, "__", exact=true): inc p.idx if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">": var a = newRstNode(rnInner) @@ -1215,7 +1237,7 @@ proc parseWordOrRef(p: var RstParser, father: PRstNode) = inc p.idx while currentTok(p).kind in {tkWord, tkPunct}: if currentTok(p).kind == tkPunct: - if isInlineMarkupEnd(p, "_"): + if isInlineMarkupEnd(p, "_", exact=true): isRef = true break if not validRefnamePunct(currentTok(p).symbol): @@ -1253,7 +1275,15 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, while true: case currentTok(p).kind of tkPunct: - if isInlineMarkupEnd(p, postfix): + if isInlineMarkupEnd(p, postfix, exact=false): + let l = currentTok(p).symbol.len + if l > postfix.len: + # handle cases like *emphasis with stars****. (It's valid RST!) + father.add newLeaf(currentTok(p).symbol[0 ..< l - postfix.len]) + elif postfix == "``" and currentTok(p).symbol == "`" and + prevTok(p).symbol == "`": + # handle cases like ``literal\`` - delete ` already added after \ + father.sons.setLen(father.sons.len - 1) inc p.idx break else: diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 2398b92a8..fef80dfc7 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -4,6 +4,10 @@ discard """ [Suite] RST indentation [Suite] RST include directive + +[Suite] RST escaping + +[Suite] RST inline markup ''' """ @@ -267,3 +271,160 @@ And this should **NOT** be visible in `docs.html` """ doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") + +suite "RST escaping": + test "backspaces": + check("""\ this""".toAst == dedent""" + rnLeaf 'this' + """) + + check("""\\ this""".toAst == dedent""" + rnInner + rnLeaf '\' + rnLeaf ' ' + rnLeaf 'this' + """) + + check("""\\\ this""".toAst == dedent""" + rnInner + rnLeaf '\' + rnLeaf 'this' + """) + + check("""\\\\ this""".toAst == dedent""" + rnInner + rnLeaf '\' + rnLeaf '\' + rnLeaf ' ' + rnLeaf 'this' + """) + +suite "RST inline markup": + test "end-string has repeating symbols": + check("*emphasis content****".toAst == dedent""" + rnEmphasis + rnLeaf 'emphasis' + rnLeaf ' ' + rnLeaf 'content' + rnLeaf '***' + """) + + check("""*emphasis content\****""".toAst == dedent""" + rnEmphasis + rnLeaf 'emphasis' + rnLeaf ' ' + rnLeaf 'content' + rnLeaf '*' + rnLeaf '**' + """) # exact configuration of leafs with * is not really essential, + # only total number of * is essential + + check("**strong content****".toAst == dedent""" + rnStrongEmphasis + rnLeaf 'strong' + rnLeaf ' ' + rnLeaf 'content' + rnLeaf '**' + """) + + check("""**strong content*\****""".toAst == dedent""" + rnStrongEmphasis + rnLeaf 'strong' + rnLeaf ' ' + rnLeaf 'content' + rnLeaf '*' + rnLeaf '*' + rnLeaf '*' + """) + + check("``lit content`````".toAst == dedent""" + rnInlineLiteral + rnLeaf 'lit' + rnLeaf ' ' + rnLeaf 'content' + rnLeaf '```' + """) + + + test """interpreted text can be ended with \` """: + let output = (".. default-role:: literal\n" & """`\``""").toAst + check(output.endsWith """ + rnParagraph + rnInlineLiteral + rnLeaf '`'""" & "\n") + + let output2 = """`\``""".toAst + check(output2 == dedent""" + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf '`' + """) + + let output3 = """`proc \`+\``""".toAst + check(output3 == dedent""" + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf 'proc `+`' + """) + + test """inline literals can contain \ anywhere""": + check("""``\``""".toAst == dedent""" + rnInlineLiteral + rnLeaf '\' + """) + + check("""``\\``""".toAst == dedent""" + rnInlineLiteral + rnLeaf '\' + rnLeaf '\' + """) + + check("""``\```""".toAst == dedent""" + rnInlineLiteral + rnLeaf '\' + rnLeaf '`' + """) + + check("""``\\```""".toAst == dedent""" + rnInlineLiteral + rnLeaf '\' + rnLeaf '\' + rnLeaf '`' + """) + + check("""``\````""".toAst == dedent""" + rnInlineLiteral + rnLeaf '\' + rnLeaf '`' + rnLeaf '`' + """) + + test "references with _ at the end": + check(dedent""" + .. _lnk: https + + lnk_""".toAst == + dedent""" + rnHyperlink + rnInner + rnLeaf 'lnk' + rnInner + rnLeaf 'https' + """) + + test "not a hyper link": + check(dedent""" + .. _lnk: https + + lnk___""".toAst == + dedent""" + rnInner + rnLeaf 'lnk' + rnLeaf '___' + """) From 20248a68fd867ce64822698b316f1a8b6300d7ca Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 30 Apr 2021 02:00:33 -0700 Subject: [PATCH 2522/4254] gitutils: add diffStrings, diffFiles, and use it in testament to compare expected vs gotten (#17892) * gitutils: add diffStrings, diffFiles, and use it in testament to compare expected vs gotten * refactor with createTempDir * cleanup * refacotr * PRTEMP fake test spec changes to show effect of diffStrings * add runnableExamples for experimental/diff + cross-reference with gitutils * Revert "PRTEMP fake test spec changes to show effect of diffStrings" This reverts commit 57dc8d642dce6c1127c98b7cbc9edbfe747d4047. --- lib/experimental/diff.nim | 45 +++++++++++++++++---------------- lib/std/private/gitutils.nim | 40 +++++++++++++++++++++++++++++- lib/std/tempfiles.nim | 48 +++++++++++++++++++----------------- nimdoc/rsttester.nim | 3 ++- nimdoc/tester.nim | 3 ++- nimpretty/tester.nim | 5 ++-- testament/categories.nim | 4 +-- testament/testament.nim | 3 ++- 8 files changed, 99 insertions(+), 52 deletions(-) diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim index ba4e8ad64..ea0a5cfb8 100644 --- a/lib/experimental/diff.nim +++ b/lib/experimental/diff.nim @@ -10,28 +10,31 @@ ## This module implements an algorithm to compute the ## `diff`:idx: between two sequences of lines. ## -## A basic example of `diffInt` on 2 arrays of integers: -## -## .. code:: Nim -## -## import experimental/diff -## echo diffInt([0, 1, 2, 3, 4, 5, 6, 7, 8], [-1, 1, 2, 3, 4, 5, 666, 7, 42]) -## -## Another short example of `diffText` to diff strings: -## -## .. code:: Nim -## -## import experimental/diff -## # 2 samples of text for testing (from "The Call of Cthulhu" by Lovecraft) -## let txt0 = """I have looked upon all the universe has to hold of horror, -## even skies of spring and flowers of summer must ever be poison to me.""" -## let txt1 = """I have looked upon all your code has to hold of bugs, -## even skies of spring and flowers of summer must ever be poison to me.""" -## -## echo diffText(txt0, txt1) -## ## - To learn more see `Diff on Wikipedia. `_ +runnableExamples: + assert diffInt( + [0, 1, 2, 3, 4, 5, 6, 7, 8], + [-1, 1, 2, 3, 4, 5, 666, 7, 42]) == + @[Item(startA: 0, startB: 0, deletedA: 1, insertedB: 1), + Item(startA: 6, startB: 6, deletedA: 1, insertedB: 1), + Item(startA: 8, startB: 8, deletedA: 1, insertedB: 1)] + +runnableExamples: + # 2 samples of text (from "The Call of Cthulhu" by Lovecraft) + let txt0 = """ +abc +def ghi +jkl2""" + let txt1 = """ +bacx +abc +def ghi +jkl""" + assert diffText(txt0, txt1) == + @[Item(startA: 0, startB: 0, deletedA: 0, insertedB: 1), + Item(startA: 2, startB: 3, deletedA: 1, insertedB: 1)] + # code owner: Arne Döring # # This is based on C# code written by Matthias Hertel, http://www.mathertel.de @@ -309,7 +312,7 @@ proc diffText*(textA, textB: string): seq[Item] = ## `textB` B-version of the text (usually the new one) ## ## Returns a seq of Items that describe the differences. - + # See also `gitutils.diffStrings`. # prepare the input-text and convert to comparable numbers. var h = initTable[string, int]() # TextA.len + TextB.len <- probably wrong initial size # The A-Version of the data (original data) to be compared. diff --git a/lib/std/private/gitutils.nim b/lib/std/private/gitutils.nim index bf5e7cb1f..5bcd9e377 100644 --- a/lib/std/private/gitutils.nim +++ b/lib/std/private/gitutils.nim @@ -4,7 +4,7 @@ internal API for now, API subject to change # xxx move other git utilities here; candidate for stdlib. -import std/[os, osproc, strutils] +import std/[os, osproc, strutils, tempfiles] const commitHead* = "HEAD" @@ -38,3 +38,41 @@ proc isGitRepo*(dir: string): bool = # usually a series of ../), so we know that it's safe to unconditionally # remove trailing whitespaces from the result. result = status == 0 and output.strip() == "" + +proc diffFiles*(path1, path2: string): tuple[output: string, same: bool] = + ## Returns a human readable diff of files `path1`, `path2`, the exact form of + ## which is implementation defined. + # This could be customized, e.g. non-git diff with `diff -uNdr`, or with + # git diff options (e.g. --color-moved, --word-diff). + # in general, `git diff` has more options than `diff`. + var status = 0 + (result.output, status) = execCmdEx("git diff --no-index $1 $2" % [path1.quoteShell, path2.quoteShell]) + doAssert (status == 0) or (status == 1) + result.same = status == 0 + +proc diffStrings*(a, b: string): tuple[output: string, same: bool] = + ## Returns a human readable diff of `a`, `b`, the exact form of which is + ## implementation defined. + ## See also `experimental.diff`. + runnableExamples: + let a = "ok1\nok2\nok3\n" + let b = "ok1\nok2 alt\nok3\nok4\n" + let (c, same) = diffStrings(a, b) + doAssert not same + let (c2, same2) = diffStrings(a, a) + doAssert same2 + runnableExamples("-r:off"): + let a = "ok1\nok2\nok3\n" + let b = "ok1\nok2 alt\nok3\nok4\n" + echo diffStrings(a, b).output + + template tmpFileImpl(prefix, str): auto = + let path = genTempPath(prefix, "") + writeFile(path, str) + path + let patha = tmpFileImpl("diffStrings_a_", a) + let pathb = tmpFileImpl("diffStrings_b_", b) + defer: + removeFile(patha) + removeFile(pathb) + result = diffFiles(patha, pathb) diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index 2a6fe7d83..91a3ce7f3 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -90,25 +90,33 @@ template randomPathName(length: Natural): string = res[i] = state.sample(letters) res +proc getTempDirImpl(dir: string): string {.inline.} = + result = dir + if result.len == 0: + result = getTempDir() + +proc genTempPath*(prefix, suffix: string, dir = ""): string = + ## Generates a path name in `dir`. + ## + ## If `dir` is empty, (`getTempDir `_) will be used. + ## The path begins with `prefix` and ends with `suffix`. + let dir = getTempDirImpl(dir) + result = dir / (prefix & randomPathName(nimTempPathLength) & suffix) + proc createTempFile*(prefix, suffix: string, dir = ""): tuple[fd: File, path: string] = - ## `createTempFile` creates a new temporary file in the directory `dir`. + ## Creates a new temporary file in the directory `dir`. ## - ## If `dir` is the empty string, the default directory for temporary files - ## (`getTempDir `_) will be used. - ## The temporary file name begins with `prefix` and ends with `suffix`. - ## `createTempFile` returns a file handle to an open file and the path of that file. + ## This generates a path name using `genTempPath(prefix, suffix, dir)` and + ## returns a file handle to an open file and the path of that file, possibly after + ## retrying to ensure it doesn't already exist. ## ## If failing to create a temporary file, `IOError` will be raised. ## ## .. note:: It is the caller's responsibility to remove the file when no longer needed. - var dir = dir - if dir.len == 0: - dir = getTempDir() - + let dir = getTempDirImpl(dir) createDir(dir) - for i in 0 ..< maxRetry: - result.path = dir / (prefix & randomPathName(nimTempPathLength) & suffix) + result.path = genTempPath(prefix, suffix, dir) try: result.fd = safeOpen(result.path) except OSError: @@ -118,25 +126,19 @@ proc createTempFile*(prefix, suffix: string, dir = ""): tuple[fd: File, path: st raise newException(IOError, "Failed to create a temporary file under directory " & dir) proc createTempDir*(prefix, suffix: string, dir = ""): string = - ## `createTempDir` creates a new temporary directory in the directory `dir`. + ## Creates a new temporary directory in the directory `dir`. ## - ## If `dir` is the empty string, the default directory for temporary files - ## (`getTempDir `_) will be used. - ## The temporary directory name begins with `prefix` and ends with `suffix`. - ## `createTempDir` returns the path of that temporary firectory. + ## This generates a dir name using `genTempPath(prefix, suffix, dir)`, creates + ## the directory and returns it, possibly after retrying to ensure it doesn't + ## already exist. ## ## If failing to create a temporary directory, `IOError` will be raised. ## ## .. note:: It is the caller's responsibility to remove the directory when no longer needed. - ## - var dir = dir - if dir.len == 0: - dir = getTempDir() - + let dir = getTempDirImpl(dir) createDir(dir) - for i in 0 ..< maxRetry: - result = dir / (prefix & randomPathName(nimTempPathLength) & suffix) + result = genTempPath(prefix, suffix, dir) try: if not existsOrCreateDir(result): return diff --git a/nimdoc/rsttester.nim b/nimdoc/rsttester.nim index 6d41ffb86..daca3dfc7 100644 --- a/nimdoc/rsttester.nim +++ b/nimdoc/rsttester.nim @@ -1,4 +1,5 @@ import os, strutils +from std/private/gitutils import diffFiles const baseDir = "nimdoc/rst2html" @@ -19,7 +20,7 @@ proc testRst2Html(fixup = false) = exec("$1 rst2html $2" % [nimExe, sourceFile]) let producedHtml = expectedHtml.replace('\\', '/').replace("/expected/", "/source/htmldocs/") if readFile(expectedHtml) != readFile(producedHtml): - discard execShellCmd("diff -uNdr " & expectedHtml & " " & producedHtml) + echo diffFiles(expectedHtml, producedHtml).output inc failures if fixup: copyFile(producedHtml, expectedHtml) diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index 526295222..9daa0bb51 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -3,6 +3,7 @@ # to change expected results (after carefully verifying everything), use -d:fixup import strutils, os +from std/private/gitutils import diffFiles var failures = 0 @@ -40,7 +41,7 @@ proc testNimDoc(prjDir, docsDir: string; switches: NimSwitches; fixup = false) = inc failures elif readFile(expected) != readFile(produced): echo "FAILURE: files differ: ", produced - discard execShellCmd("diff -uNdr " & expected & " " & produced) + echo diffFiles(expected, produced).output inc failures if fixup: copyFile(produced, expected) diff --git a/nimpretty/tester.nim b/nimpretty/tester.nim index 0a60ce693..b1f15aee6 100644 --- a/nimpretty/tester.nim +++ b/nimpretty/tester.nim @@ -1,6 +1,7 @@ # Small program that runs the test cases import strutils, os, sequtils +from std/private/gitutils import diffFiles const dir = "nimpretty/tests" @@ -26,7 +27,7 @@ proc test(infile, ext: string) = let produced = dir / nimFile.changeFileExt(ext) if readFile(expected) != readFile(produced): echo "FAILURE: files differ: ", nimFile - discard execShellCmd("diff -uNdr " & expected & " " & produced) + echo diffFiles(expected, produced).output failures += 1 else: echo "SUCCESS: files identical: ", nimFile @@ -43,7 +44,7 @@ proc testTogether(infiles: seq[string]) = let produced = dir / "outputdir" / infile if readFile(expected) != readFile(produced): echo "FAILURE: files differ: ", nimFile - discard execShellCmd("diff -uNdr " & expected & " " & produced) + echo diffFiles(expected, produced).output failures += 1 else: echo "SUCCESS: files identical: ", nimFile diff --git a/testament/categories.nim b/testament/categories.nim index ffee5eeb3..f1dee3570 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -665,8 +665,8 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string, options: st if buf != outputExpected: writeFile(outputExceptedFile, outputExpected) - discard execShellCmd("diff -uNdr $1 $2" % [outputExceptedFile, outputGottenFile]) - echo failString & "megatest output different!" + echo diffFiles(outputGottenFile, outputExceptedFile).output + echo failString & "megatest output different, see $1 vs $2" % [outputGottenFile, outputExceptedFile] # outputGottenFile, outputExceptedFile not removed on purpose for debugging. quit 1 else: diff --git a/testament/testament.nim b/testament/testament.nim index 9caa3f6b9..0607ac41d 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -17,6 +17,7 @@ from std/sugar import dup import compiler/nodejs import lib/stdtest/testutils from lib/stdtest/specialpaths import splitTestFile +from std/private/gitutils import diffStrings proc trimUnitSep(x: var string) = let L = x.len @@ -307,7 +308,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, maybeStyledEcho styleBright, expected, "\n" maybeStyledEcho fgYellow, "Gotten:" maybeStyledEcho styleBright, given, "\n" - + echo diffStrings(expected, given).output if backendLogging and (isAppVeyor or isAzure): let (outcome, msg) = From 76f93877cdb2a2baf28eed6edda5bcc96f4ef404 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 30 Apr 2021 17:17:29 +0200 Subject: [PATCH 2523/4254] Small parser loop fix (#17904) * Fix loop on error with nim check in semiStmtList * Add test --- compiler/parser.nim | 1 + tests/parser/t15667.nim | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index fd9d06de5..9cddf8e4f 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -556,6 +556,7 @@ proc semiStmtList(p: var Parser, result: PNode) = let a = complexOrSimpleStmt(p) if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) + getTok(p) else: result.add a dec p.inSemiStmtList diff --git a/tests/parser/t15667.nim b/tests/parser/t15667.nim index d15178789..fcb862825 100644 --- a/tests/parser/t15667.nim +++ b/tests/parser/t15667.nim @@ -7,6 +7,7 @@ t15667.nim(28, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.n t15667.nim(33, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(31, 25) ? t15667.nim(42, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(38, 12) ? t15667.nim(56, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(55, 13) ? +t15667.nim(61, 48) Error: expression expected, but found ',' ''' """ @@ -16,7 +17,6 @@ t15667.nim(56, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.n - # line 20 block: proc fn1() @@ -56,3 +56,6 @@ block: runnableExamples: discard discard + +# semiStmtList loop issue +proc bar(k:static bool):SomeNumber = (when k: 3, else: 3.0) From 3192995ac97ad0648b6d1e5a5a1a42d403b37e72 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 30 Apr 2021 09:54:47 -0700 Subject: [PATCH 2524/4254] close #16646; `since` now works with bootstrap nim post csources_v1 (#17895) * revive #16627 now that csources_v1 was merged * use dedent in rst.nim, refs https://github.com/nim-lang/Nim/pull/17257#discussion_r589025683 * fix test and improve rendering of a rst warning --- compiler/semtypes.nim | 4 ++-- lib/packages/docutils/rst.nim | 5 ++--- tests/stdlib/trstgen.nim | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index c921703b0..6a59624cd 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -256,8 +256,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = else: result.n.add semConstExpr(c, range[i]) - if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[0].floatVal) == fcNan) or - (result.n[1].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[1].floatVal) == fcNan): + if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and result.n[0].floatVal.isNaN) or + (result.n[1].kind in {nkFloatLit..nkFloat64Lit} and result.n[1].floatVal.isNaN): localError(c.config, n.info, "NaN is not a valid start or end for a range") if weakLeValue(result.n[0], result.n[1]) == impNo: diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 6ad466716..223e57bc4 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -2250,11 +2250,10 @@ proc parseEnumList(p: var RstParser): PRstNode = let n = p.line + p.tok[j].line let msg = "\n" & """ not enough indentation on line $2 - (should be at column $3 if it's a continuation of enum. list), + (should be at column $3 if it's a continuation of enum. list), or no blank line after line $1 (if it should be the next paragraph), or no escaping \ at the beginning of line $1 - (if lines $1..$2 are a normal paragraph, not enum. list)""". - unindent(8) + (if lines $1..$2 are a normal paragraph, not enum. list)""".dedent let c = p.col + requiredIndent + ColRstOffset rstMessage(p, mwRstStyle, msg % [$(n-1), $n, $c], p.tok[j].line, p.tok[j].col) diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 0af6ba566..cbdb23cd6 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -849,7 +849,7 @@ Test1 let output8 = input8.toHtml(warnings = warnings8) check(warnings8[].len == 1) check("input(6, 1) Warning: RST style: \n" & - " not enough indentation on line 6" in warnings8[0]) + "not enough indentation on line 6" in warnings8[0]) doAssert output8 == "Paragraph.
      " & "
    1. stringA
    2. \n
    3. stringB
    4. \n
    \n

    C. string1 string2

    \n" From d32ab61e61a9c8875cda926fb76e12dc8e8b9a23 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 30 Apr 2021 12:40:39 -0700 Subject: [PATCH 2525/4254] fix #17905: hash(closure) was not being tested (#17906) --- lib/pure/hashes.nim | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 83b7a8d75..2dab498d7 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -257,13 +257,6 @@ when not defined(nimLegacyNoHashRef): # or `proc hash*[T: ref | ptr](x: T): Hash` hash(cast[pointer](x)) -proc hash*[T: proc](x: T): Hash {.inline.} = - ## Efficient hashing of proc vars. Closures are supported too. - when T is "closure": - result = hash((rawProc(x), rawEnv(x))) - else: - result = hash(pointer(x)) - proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. let y = x + 0.0 # for denormalization @@ -516,10 +509,10 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = h = h !& ord(c) result = !$h -proc hash*[T: tuple | object](x: T): Hash = +proc hash*[T: tuple | object | proc](x: T): Hash {.inline.} = ## Efficient `hash` overload. - ## `hash` must be defined for each component of `x`. runnableExamples: + # for `tuple|object`, `hash` must be defined for each component of `x`. type Obj = object x: int y: string @@ -530,9 +523,24 @@ proc hash*[T: tuple | object](x: T): Hash = # you can define custom hashes for objects (even if they're generic): proc hash(a: Obj2): Hash = hash((a.x)) assert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2")) - for f in fields(x): - result = result !& hash(f) - result = !$result + runnableExamples: + # proc and closure examples + proc fn1() = discard + var a = 0 + proc fn2() = a.inc + assert hash(fn1) != hash(fn2) + const fn1b = fn1 + assert hash(fn1b) == hash(fn1) + let fn2b = fn2 + assert hash(fn2b) == hash(fn2) + when T is "closure": + result = hash((rawProc(x), rawEnv(x))) + elif T is (proc): + result = hash(pointer(x)) + else: + for f in fields(x): + result = result !& hash(f) + result = !$result proc hash*[A](x: openArray[A]): Hash = ## Efficient hashing of arrays and sequences. From d0485e326ab56af367246227dedc088839678b6b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 30 Apr 2021 13:27:53 -0700 Subject: [PATCH 2526/4254] bring back std/ prefix within compiler and ensure it works in bootstrap + bsd (#17902) * [WIP] bring back std/ prefix within compiler and ensure it works in bootstrap + bsd * refs https://github.com/nim-lang/Nim/pull/16282#discussion_r616846863 * sounds very similar to https://github.com/nim-lang/Nim/pull/14291 * more: vmops * update tools/ci_generate.nim * auto-generate freebsd.yml as well, to avoid duplication with openbsd.yml * cleanup * undo temporary CI removal --- .builds/freebsd.yml | 8 ++++++- .builds/openbsd_0.yml | 7 ++++-- .builds/openbsd_1.yml | 7 ++++-- compiler/ic/dce.nim | 2 +- compiler/vmops.nim | 16 ++++++------- koch.nim | 4 +++- tools/ci_generate.nim | 54 ++++++++++++++++++++++++++++--------------- 7 files changed, 65 insertions(+), 33 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index c1fb80253..8f336771a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,3 +1,5 @@ +## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` + # see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd image: freebsd/latest packages: @@ -8,9 +10,12 @@ packages: - devel/sfml - www/node - devel/gmake + + sources: - https://github.com/nim-lang/Nim environment: + NIM_TESTAMENT_BATCH: "0_1" CC: /usr/bin/clang tasks: - setup: | @@ -20,9 +25,10 @@ tasks: $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | + set -e cd Nim if ! ./koch runCI; then - nim c -r tools/ci_testresults.nim + nim r tools/ci_testresults.nim exit 1 fi triggers: diff --git a/.builds/openbsd_0.yml b/.builds/openbsd_0.yml index e1d85d2a7..c19cd63c6 100644 --- a/.builds/openbsd_0.yml +++ b/.builds/openbsd_0.yml @@ -1,4 +1,4 @@ -## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` +## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` image: openbsd/latest packages: @@ -10,6 +10,8 @@ packages: - sfml - sdl2 - libffi + + sources: - https://github.com/nim-lang/Nim environment: @@ -20,9 +22,10 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c koch + $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | + set -e cd Nim if ! ./koch runCI; then nim r tools/ci_testresults.nim diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml index ed2ded056..06f5f2ae5 100644 --- a/.builds/openbsd_1.yml +++ b/.builds/openbsd_1.yml @@ -1,4 +1,4 @@ -## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` +## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` image: openbsd/latest packages: @@ -10,6 +10,8 @@ packages: - sfml - sdl2 - libffi + + sources: - https://github.com/nim-lang/Nim environment: @@ -20,9 +22,10 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c koch + $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | + set -e cd Nim if ! ./koch runCI; then nim r tools/ci_testresults.nim diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index 350b17d1b..0a436a5d1 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -9,7 +9,7 @@ ## Dead code elimination (=DCE) for IC. -import intsets, tables +import std/[intsets, tables] import ".." / [ast, options, lineinfos, types] import packed_ast, ic, bitabs diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 1d22750e7..04356fc76 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -9,24 +9,24 @@ # Unfortunately this cannot be a module yet: #import vmdeps, vm -from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, +from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma, lgamma when declared(math.copySign): - from math import copySign + from std/math import copySign when declared(math.signbit): - from math import signbit + from std/math import signbit -from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, +from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename, raiseOSError, osLastError -from md5 import getMD5 -from times import cpuTime -from hashes import hash -from osproc import nil +from std/md5 import getMD5 +from std/times import cpuTime +from std/hashes import hash +from std/osproc import nil from sighashes import symBodyDigest diff --git a/koch.nim b/koch.nim index 12f9e1c14..15355ec36 100644 --- a/koch.nim +++ b/koch.nim @@ -534,7 +534,9 @@ proc runCI(cmd: string) = echo "runCI: ", cmd echo hostInfo() # boot without -d:nimHasLibFFI to make sure this still works - kochExecFold("Boot in release mode", "boot -d:release -d:nimStrictMode") + # `--lib:lib` is needed for bootstrap on openbsd, for reasons described in + # https://github.com/nim-lang/Nim/pull/14291 (`getAppFilename` bugsfor older nim on openbsd). + kochExecFold("Boot in release mode", "boot -d:release -d:nimStrictMode --lib:lib") when false: # debugging: when you need to run only 1 test in CI, use something like this: execFold("debugging test", "nim r tests/stdlib/tosproc.nim") diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index e2580ff6b..6517df34a 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -1,6 +1,6 @@ ##[ avoid code duplication in CI pipelines. -For now, this is only used for openbsd, but there is a lot of other code +For now, this is only used for openbsd + freebsd, but there is a lot of other code duplication that could be removed. ## usage @@ -10,22 +10,14 @@ nim r tools/ci_generate.nim ``` ]## -import std/strformat +import std/[strformat, os] -proc genCIopenbsd(batch: int, num: int): string = +proc genCiBsd(header: string, batch: int, num: int): string = result = fmt""" -## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` +## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` + +{header} -image: openbsd/latest -packages: -- gmake -- sqlite3 -- node -- boehm-gc -- pcre -- sfml -- sdl2 -- libffi sources: - https://github.com/nim-lang/Nim environment: @@ -36,9 +28,10 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c koch + $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | + set -e cd Nim if ! ./koch runCI; then nim r tools/ci_testresults.nim @@ -51,14 +44,39 @@ triggers: """ proc main()= + let dir = ".builds" # not too large to be resource friendly, refs bug #17107 let num = 2 # if you reduce this, make sure to remove files that shouldn't be generated, # or better, do the cleanup logic here e.g.: `rm .builds/openbsd_*` + let headerFreebsd = """ +# see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd +image: freebsd/latest +packages: +- databases/sqlite3 +- devel/boehm-gc-threaded +- devel/pcre +- devel/sdl20 +- devel/sfml +- www/node +- devel/gmake +""" + + let headerOpenbsd = """ +image: openbsd/latest +packages: +- gmake +- sqlite3 +- node +- boehm-gc +- pcre +- sfml +- sdl2 +- libffi +""" for i in 0.. Date: Fri, 30 Apr 2021 22:39:25 +0200 Subject: [PATCH 2527/4254] Document the difference between toFloat/toInt and type conversion (#17894) --- lib/system.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 9e9bacf39..174630317 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1472,7 +1472,7 @@ type # these work for most platforms: PInt32* = ptr int32 ## An alias for `ptr int32`. proc toFloat*(i: int): float {.noSideEffect, inline.} = - ## Converts an integer `i` into a `float`. + ## Converts an integer `i` into a `float`. Same as `float(i)`. ## ## If the conversion fails, `ValueError` is raised. ## However, on most platforms the conversion cannot fail. @@ -1494,7 +1494,8 @@ proc toInt*(f: float): int {.noSideEffect.} = ## ## Conversion rounds `f` half away from 0, see ## `Round half away from zero - ## `_. + ## `_, + ## as opposed to a type conversion which rounds towards zero. ## ## Note that some floating point numbers (e.g. infinity or even 1e19) ## cannot be accurately converted. From abb8a73134597297b2c14567f7f8d72f6b723d24 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 1 May 2021 08:20:33 +0300 Subject: [PATCH 2528/4254] Fix nim-lang/nimforum#285 - punctuation after URL (#17908) * Fix nim-lang/nimforum#285 - punctuation after URL * keep only one leaf in a rnStandaloneHyperlink * add more complex URL --- lib/packages/docutils/rst.nim | 28 ++++++++++++-------- tests/stdlib/trst.nim | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 223e57bc4..249c310b9 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1213,23 +1213,29 @@ proc isUrl(p: RstParser, i: int): bool = p.tok[i+3].kind == tkWord and p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"] +proc parseUrl(p: var RstParser): PRstNode = + ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#standalone-hyperlinks + result = newRstNode(rnStandaloneHyperlink) + var lastIdx = p.idx + while p.tok[lastIdx].kind in {tkWord, tkPunct, tkOther}: + inc lastIdx + dec lastIdx + # standalone URL can not end with punctuation in RST + while lastIdx >= p.idx and p.tok[lastIdx].kind == tkPunct and + p.tok[lastIdx].symbol != "/": + dec lastIdx + var s = "" + for i in p.idx .. lastIdx: s.add p.tok[i].symbol + result.add s + p.idx = lastIdx + 1 + proc parseWordOrRef(p: var RstParser, father: PRstNode) = ## Parses a normal word or may be a reference or URL. if nextTok(p).kind != tkPunct: # <- main path, a normal word father.add newLeaf(p) inc p.idx elif isUrl(p, p.idx): # URL http://something - var n = newRstNode(rnStandaloneHyperlink) - while true: - case currentTok(p).kind - of tkWord, tkAdornment, tkOther: discard - of tkPunct: - if nextTok(p).kind notin {tkWord, tkAdornment, tkOther, tkPunct}: - break - else: break - n.add(newLeaf(p)) - inc p.idx - father.add(n) + father.add parseUrl(p) else: # check for reference (probably, long one like some.ref.with.dots_ ) var saveIdx = p.idx diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index fef80dfc7..905e5143a 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -428,3 +428,53 @@ suite "RST inline markup": rnLeaf 'lnk' rnLeaf '___' """) + + test "no punctuation in the end of a standalone URI is allowed": + check(dedent""" + [see (http://no.org)], end""".toAst == + dedent""" + rnInner + rnLeaf '[' + rnLeaf 'see' + rnLeaf ' ' + rnLeaf '(' + rnStandaloneHyperlink + rnLeaf 'http://no.org' + rnLeaf ')' + rnLeaf ']' + rnLeaf ',' + rnLeaf ' ' + rnLeaf 'end' + """) + + # but `/` at the end is OK + check( + dedent""" + See http://no.org/ end""".toAst == + dedent""" + rnInner + rnLeaf 'See' + rnLeaf ' ' + rnStandaloneHyperlink + rnLeaf 'http://no.org/' + rnLeaf ' ' + rnLeaf 'end' + """) + + # a more complex URL with some made-up ending '&='. + # Github Markdown would include final &= and + # so would rst2html.py in contradiction with RST spec. + check( + dedent""" + See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst == + dedent""" + rnInner + rnLeaf 'See' + rnLeaf ' ' + rnStandaloneHyperlink + rnLeaf 'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO' + rnLeaf '&' + rnLeaf '=' + rnLeaf ' ' + rnLeaf 'end' + """) From 1f1d85bb9c614d93ce38becdcc421dda00264a75 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 30 Apr 2021 22:24:41 -0700 Subject: [PATCH 2529/4254] reuse config/build_config.txt for all bootstrap scripts (posix + windows + ci); use build_all.bat in 1 CI, fix bug in build_all.bat (#17899) * reuse config/build_config.txt for all bootstrap scripts (posix + windows + ci) * ci_docs: use build_all.bat in CI (just in that pipeline) to ensure it keeps working * fixup * fix pre-existing bug in build_all.bat * fixup * cp => copy /y * auto-generate build_all.bat, build_all.sh * fixup --- .github/workflows/ci_docs.yml | 10 +++++- build_all.bat | 35 ++++++++++++------- build_all.sh | 9 ++--- ci/build_autogen.bat | 26 ++++++++++++++ ci/funs.sh | 8 ++--- config/build_config.txt | 4 +++ tools/ci_generate.nim | 65 ++++++++++++++++++++++++++++++++++- 7 files changed, 134 insertions(+), 23 deletions(-) create mode 100644 ci/build_autogen.bat create mode 100644 config/build_config.txt diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 1459d6a31..dfcff66e0 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -70,13 +70,21 @@ jobs: shell: bash run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - name: 'Build csourcesAny' + - name: 'Build csourcesAny (posix)' + # this would work on windows and other CI use this on windows, + # but we ensure here that `ci/build_autogen.bat` keeps working on windows. + if: runner.os != 'Windows' shell: bash run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc # was previously using caching via `actions/cache@v1` but this wasn't # used in other CI pipelines and it's unclear the added complexity # was worth the saving; can be revisited if needed. + - name: 'Build csourcesAny (windows)' + if: runner.os == 'Windows' + shell: cmd + run: ci/build_autogen.bat + - name: 'Build koch' shell: bash run: nim c koch diff --git a/build_all.bat b/build_all.bat index 78a7a354a..1bff761b3 100644 --- a/build_all.bat +++ b/build_all.bat @@ -1,20 +1,29 @@ @echo off -rem build development version of the compiler; can be rerun safely -rem TODO: call nimBuildCsourcesIfNeeded or auto-generate this file (from a nim script) -rem to avoid duplication. -if not exist csources_v1 ( - git clone --depth 1 https://github.com/nim-lang/csources_v1.git +rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` +rem Build development version of the compiler; can be rerun safely +rem bare bones version of ci/funs.sh adapted for windows. + +rem Read in some common shared variables (shared with other tools), +rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file +for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H +SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe +echo "building from csources: %nim_csources%" + +if not exist %nim_csourcesDir% ( + git clone -q --depth 1 %nim_csourcesUrl% %nim_csourcesDir% ) -if not exist bin\nim.exe ( - cd csources_v1 - git checkout a8a5241f9475099c823cfe1a5e0ca4022ac201ff - if PROCESSOR_ARCHITECTURE == AMD64 ( + +if not exist %nim_csources% ( + cd %nim_csourcesDir% + git checkout %nim_csourcesHash% + echo "%PROCESSOR_ARCHITECTURE%" + if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( SET ARCH=64 ) CALL build.bat cd .. + copy /y bin\nim.exe %nim_csources% ) -bin\nim.exe c --skipUserCfg --skipParentCfg koch -koch.exe boot -d:release --skipUserCfg --skipParentCfg -koch.exe tools --skipUserCfg --skipParentCfg - + bin\nim.exe c --skipUserCfg --skipParentCfg --hints:off koch + koch boot -d:release --skipUserCfg --skipParentCfg --hints:off + koch tools --skipUserCfg --skipParentCfg --hints:off diff --git a/build_all.sh b/build_all.sh index 49504c8fe..90665672f 100755 --- a/build_all.sh +++ b/build_all.sh @@ -1,4 +1,5 @@ #! /bin/sh +rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` # build development version of the compiler; can be rerun safely. # arguments can be passed, e.g.: @@ -10,7 +11,7 @@ set -e # exit on first error . ci/funs.sh nimBuildCsourcesIfNeeded "$@" -# Note: if fails, may need to update csourcesAny manually -echo_run bin/nim c --skipUserCfg --skipParentCfg koch -echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg -echo_run ./koch tools --skipUserCfg --skipParentCfg # Compile Nimble and other tools. +echo_run bin/nim c --skipUserCfg --skipParentCfg --hints:off koch +echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg --hints:off +echo_run ./koch tools --skipUserCfg --skipParentCfg --hints:off + diff --git a/ci/build_autogen.bat b/ci/build_autogen.bat new file mode 100644 index 000000000..8b1113175 --- /dev/null +++ b/ci/build_autogen.bat @@ -0,0 +1,26 @@ +@echo off +rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` +rem Build development version of the compiler; can be rerun safely +rem bare bones version of ci/funs.sh adapted for windows. + +rem Read in some common shared variables (shared with other tools), +rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file +for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H +SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe +echo "building from csources: %nim_csources%" + +if not exist %nim_csourcesDir% ( + git clone -q --depth 1 %nim_csourcesUrl% %nim_csourcesDir% +) + +if not exist %nim_csources% ( + cd %nim_csourcesDir% + git checkout %nim_csourcesHash% + echo "%PROCESSOR_ARCHITECTURE%" + if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( + SET ARCH=64 + ) + CALL build.bat + cd .. + copy /y bin\nim.exe %nim_csources% +) diff --git a/ci/funs.sh b/ci/funs.sh index 7a6c66722..5158f38d5 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -32,9 +32,7 @@ nimIsCiSkip(){ } nimDefineVars(){ - nim_csourcesDir=csources_v1 # where we clone - nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git - nim_csourcesHash=a8a5241f9475099c823cfe1a5e0ca4022ac201ff + . config/build_config.txt nim_csources=bin/nim_csources_$nim_csourcesHash } @@ -88,9 +86,11 @@ nimBuildCsourcesIfNeeded(){ if test -d "$nim_csourcesDir"; then echo "$nim_csourcesDir exists." else - # depth 1: adjust as needed in case useful for `git bisect` + # Note: using git tags would allow fetching just what's needed, unlike git hashes, e.g. + # via `git clone -q --depth 1 --branch $tag $nim_csourcesUrl`. echo_run git clone -q --depth 1 $nim_csourcesUrl "$nim_csourcesDir" echo_run git -C "$nim_csourcesDir" checkout $nim_csourcesHash + # if needed we could also add: `git reset --hard $nim_csourcesHash` fi _nimBuildCsourcesIfNeeded "$@" fi diff --git a/config/build_config.txt b/config/build_config.txt new file mode 100644 index 000000000..2484d7a52 --- /dev/null +++ b/config/build_config.txt @@ -0,0 +1,4 @@ +nim_comment="key-value pairs for windows/posix bootstrapping build scripts" +nim_csourcesDir=csources_v1 +nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git +nim_csourcesHash=a8a5241f9475099c823cfe1a5e0ca4022ac201ff diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index 6517df34a..2e6b4b3de 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -12,9 +12,10 @@ nim r tools/ci_generate.nim import std/[strformat, os] +const doNotEdit = "DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim`" proc genCiBsd(header: string, batch: int, num: int): string = result = fmt""" -## DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` +## {doNotEdit} {header} @@ -43,6 +44,64 @@ triggers: to: Andreas Rumpf """ +proc genBuildExtras(echoRun, koch, nim: string): string = + result = fmt""" +{echoRun} {nim} c --skipUserCfg --skipParentCfg --hints:off koch +{echoRun} {koch} boot -d:release --skipUserCfg --skipParentCfg --hints:off +{echoRun} {koch} tools --skipUserCfg --skipParentCfg --hints:off +""" + +proc genWindowsScript(buildAll: bool): string = + result = fmt""" +@echo off +rem {doNotEdit} +rem Build development version of the compiler; can be rerun safely +rem bare bones version of ci/funs.sh adapted for windows. + +rem Read in some common shared variables (shared with other tools), +rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file +for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H +SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe +echo "building from csources: %nim_csources%" + +if not exist %nim_csourcesDir% ( + git clone -q --depth 1 %nim_csourcesUrl% %nim_csourcesDir% +) + +if not exist %nim_csources% ( + cd %nim_csourcesDir% + git checkout %nim_csourcesHash% + echo "%PROCESSOR_ARCHITECTURE%" + if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( + SET ARCH=64 + ) + CALL build.bat + cd .. + copy /y bin\nim.exe %nim_csources% +) +""" + + if buildAll: + result.add genBuildExtras("", "koch", r"bin\nim.exe") + +proc genPosixScript(): string = + result = fmt""" +#! /bin/sh +rem {doNotEdit} + +# build development version of the compiler; can be rerun safely. +# arguments can be passed, e.g.: +# CC=gcc ucpu=amd64 uos=darwin + +set -u # error on undefined variables +set -e # exit on first error + +. ci/funs.sh +nimBuildCsourcesIfNeeded "$@" + +{genBuildExtras("echo_run", "./koch", "bin/nim")} +""" + proc main()= let dir = ".builds" # not too large to be resource friendly, refs bug #17107 @@ -74,9 +133,13 @@ packages: - sdl2 - libffi """ + for i in 0.. Date: Fri, 30 Apr 2021 22:26:52 -0700 Subject: [PATCH 2530/4254] misc fixes: remove `forceConst` (obsolete by static), add more runnableExamples to system (#17896) * misc fixes * add runnableExamples for compileOption * add runnableExamples for runnableExamples * move tconsteval => tconst * cleanup --- lib/std/compilesettings.nim | 2 +- lib/system.nim | 84 ++++++++++++++++++------------------- tests/vm/tconst.nim | 35 ++++++++++++++++ tests/vm/tconsteval.nim | 31 -------------- tests/vm/tvmops.nim | 14 +------ 5 files changed, 78 insertions(+), 88 deletions(-) create mode 100644 tests/vm/tconst.nim delete mode 100644 tests/vm/tconsteval.nim diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim index 725b68acd..273cfdb57 100644 --- a/lib/std/compilesettings.nim +++ b/lib/std/compilesettings.nim @@ -8,7 +8,7 @@ # ## This module allows querying the compiler about -## diverse configuration settings. +## diverse configuration settings. See also `compileOption`. # Note: Only add new enum values at the end to ensure binary compatibility with # other Nim compiler versions! diff --git a/lib/system.nim b/lib/system.nim index 174630317..c2c3306d4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -55,35 +55,61 @@ type include "system/basic_types" +proc runnableExamples*(rdoccmd = "", body: untyped) {.magic: "RunnableExamples".} = + ## A section you should use to mark `runnable example`:idx: code with. + ## + ## - In normal debug and release builds code within + ## a `runnableExamples` section is ignored. + ## - The documentation generator is aware of these examples and considers them + ## part of the `##` doc comment. As the last step of documentation + ## generation each runnableExample is put in its own file `$file_examples$i.nim`, + ## compiled and tested. The collected examples are + ## put into their own module to ensure the examples do not refer to + ## non-exported symbols. + runnableExamples: + proc timesTwo*(x: int): int = + ## This proc doubles a number. + runnableExamples: + # at module scope + const exported* = 123 + assert timesTwo(5) == 10 + block: # at block scope + defer: echo "done" + runnableExamples "-d:foo -b:cpp": + import std/compilesettings + assert querySetting(backend) == "cpp" + assert defined(foo) + runnableExamples "-r:off": ## this one is only compiled + import std/browsers + openDefaultBrowser "https://forum.nim-lang.org/" + 2 * x + proc compileOption*(option: string): bool {. - magic: "CompileOption", noSideEffect.} + magic: "CompileOption", noSideEffect.} = ## Can be used to determine an `on|off` compile-time option. ## ## See also: ## * `compileOption <#compileOption,string,string>`_ for enum options ## * `defined <#defined,untyped>`_ ## * `std/compilesettings module `_ - ## - ## Example: - ## - ## .. code-block:: Nim - ## when compileOption("floatchecks"): - ## echo "compiled with floating point NaN and Inf checks" + runnableExamples("--floatChecks:off"): + static: doAssert not compileOption("floatchecks") + {.push floatChecks: on.} + static: doAssert compileOption("floatchecks") + # floating point NaN and Inf checks enabled in this scope + {.pop.} proc compileOption*(option, arg: string): bool {. - magic: "CompileOptionArg", noSideEffect.} + magic: "CompileOptionArg", noSideEffect.} = ## Can be used to determine an enum compile-time option. ## ## See also: ## * `compileOption <#compileOption,string>`_ for `on|off` options ## * `defined <#defined,untyped>`_ ## * `std/compilesettings module `_ - ## - ## Example: - ## - ## .. code-block:: Nim - ## when compileOption("opt", "size") and compileOption("gc", "boehm"): - ## echo "compiled with optimization for size and uses Boehm's GC" + runnableExamples: + when compileOption("opt", "size") and compileOption("gc", "boehm"): + discard "compiled with optimization for size and uses Boehm's GC" {.push warning[GcMem]: off, warning[Uninit]: off.} {.push hints: off.} @@ -139,36 +165,6 @@ else: OrdinalImpl[T] {.magic: Ordinal.} Ordinal* = OrdinalImpl | uint | uint64 -proc runnableExamples*(rdoccmd = "", body: untyped) {.magic: "RunnableExamples".} - ## A section you should use to mark `runnable example`:idx: code with. - ## - ## - In normal debug and release builds code within - ## a `runnableExamples` section is ignored. - ## - The documentation generator is aware of these examples and considers them - ## part of the `##` doc comment. As the last step of documentation - ## generation each runnableExample is put in its own file `$file_examples$i.nim`, - ## compiled and tested. The collected examples are - ## put into their own module to ensure the examples do not refer to - ## non-exported symbols. - ## - ## Usage: - ## - ## .. code-block:: Nim - ## proc double*(x: int): int = - ## ## This proc doubles a number. - ## runnableExamples: - ## ## at module scope - ## assert double(5) == 10 - ## block: ## at block scope - ## defer: echo "done" - ## result = 2 * x - ## runnableExamples "-d:foo -b:cpp": - ## import std/compilesettings - ## doAssert querySetting(backend) == "cpp" - ## runnableExamples "-r:off": ## this one is only compiled - ## import std/browsers - ## openDefaultBrowser "https://forum.nim-lang.org/" - when defined(nimHasDeclaredMagic): proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is diff --git a/tests/vm/tconst.nim b/tests/vm/tconst.nim new file mode 100644 index 000000000..3ebbec043 --- /dev/null +++ b/tests/vm/tconst.nim @@ -0,0 +1,35 @@ +discard """ + targets: "c cpp js" +""" + +import std/strutils + +template forceConst(a: untyped): untyped = + ## Force evaluation at CT, but `static(a)` is simpler + const ret = a + ret + +proc isNimVm(): bool = + when nimvm: result = true + else: result = false + +block: + doAssert forceConst(isNimVm()) + doAssert not isNimVm() + doAssert forceConst(isNimVm()) == static(isNimVm()) + doAssert forceConst(isNimVm()) == isNimVm().static + +template main() = + # xxx merge more const related tests here + block: + const + a = """ + Version $1| + Compiled at: $2, $3 + """ % [NimVersion & spaces(44-len(NimVersion)), CompileDate, CompileTime] + let b = $a + doAssert CompileTime in b + doAssert NimVersion in b + +static: main() +main() diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim deleted file mode 100644 index 2e0fcb888..000000000 --- a/tests/vm/tconsteval.nim +++ /dev/null @@ -1,31 +0,0 @@ -discard """ -action: compile -""" - -import strutils - -const - HelpText = """ -+-----------------------------------------------------------------+ -| Maintenance program for Nim | -| Version $1| -| (c) 2012 Andreas Rumpf | -+-----------------------------------------------------------------+ -Compiled at: $2, $3 - -Usage: - koch [options] command [options for command] -Options: - --force, -f, -B, -b forces rebuild - --help, -h shows this help and quits -Possible Commands: - boot [options] bootstraps with given command line options - clean cleans Nim project; removes generated files - web generates the website - csource [options] builds the C sources for installation - zip builds the installation ZIP package - inno builds the Inno Setup installer -""" % [NimVersion & spaces(44-len(NimVersion)), - CompileDate, CompileTime] - -echo HelpText diff --git a/tests/vm/tvmops.nim b/tests/vm/tvmops.nim index c8febd982..632dcbee7 100644 --- a/tests/vm/tvmops.nim +++ b/tests/vm/tvmops.nim @@ -9,16 +9,6 @@ import os import math import strutils -template forceConst(a: untyped): untyped = - ## Force evaluation at CT, useful for example here: - ## `callFoo(forceConst(getBar1()), getBar2())` - ## instead of: - ## block: - ## const a = getBar1() - ## `callFoo(a, getBar2())` - const ret = a - ret - static: # TODO: add more tests block: #getAppFilename, gorgeEx, gorge @@ -51,6 +41,6 @@ static: block: # Check against bugs like #9176 - doAssert getCurrentCompilerExe() == forceConst(getCurrentCompilerExe()) + doAssert getCurrentCompilerExe() == getCurrentCompilerExe().static if false: #pending #9176 - doAssert gorgeEx("unexistant") == forceConst(gorgeEx("unexistant")) + doAssert gorgeEx("unexistant") == gorgeEx("unexistant").static From 9f75e8abc153bafdc5d3a34f001d20a92d36e220 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 1 May 2021 13:27:50 +0800 Subject: [PATCH 2531/4254] [std/base64] uses runnableExamples (#17882) * [std/base64] uses runnableExamples * Update lib/pure/base64.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/base64.nim | 62 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index d5c1fda7a..daba786f2 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -16,44 +16,42 @@ ## Each Base64 digit represents exactly 6 bits of data. Three 8-bit ## bytes (i.e., a total of 24 bits) can therefore be represented by ## four 6-bit Base64 digits. -## -## Basic usage -## =========== -## + +##[ +# Basic usage ## Encoding data -## ------------- -## -## .. code-block:: Nim -## import std/base64 -## let encoded = encode("Hello World") -## assert encoded == "SGVsbG8gV29ybGQ=" +]## + +runnableExamples: + let encoded = encode("Hello World") + assert encoded == "SGVsbG8gV29ybGQ=" + ## ## Apart from strings you can also encode lists of integers or characters: ## -## .. code-block:: Nim -## import std/base64 -## let encodedInts = encode([1,2,3]) -## assert encodedInts == "AQID" -## let encodedChars = encode(['h','e','y']) -## assert encodedChars == "aGV5" -## -## + +runnableExamples: + let encodedInts = encode([1,2,3]) + assert encodedInts == "AQID" + let encodedChars = encode(['h','e','y']) + assert encodedChars == "aGV5" + +##[ ## Decoding data -## ------------- -## -## .. code-block:: Nim -## import std/base64 -## let decoded = decode("SGVsbG8gV29ybGQ=") -## assert decoded == "Hello World" -## +]## + +runnableExamples: + let decoded = decode("SGVsbG8gV29ybGQ=") + assert decoded == "Hello World" + +##[ ## URL Safe Base64 -## --------------- -## -## .. code-block:: Nim -## import std/base64 -## doAssert encode("c\xf7>", safe = true) == "Y_c-" -## doAssert encode("c\xf7>", safe = false) == "Y/c+" -## +]## + +runnableExamples: + assert encode("c\xf7>", safe = true) == "Y_c-" + assert encode("c\xf7>", safe = false) == "Y/c+" + ## See also ## ======== ## From a55c7e9679e8df0ffc7eaff1e2d5626ec5a9129a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yanis=20Zafir=C3=B3pulos?= <1265028+drkameleon@users.noreply.github.com> Date: Sat, 1 May 2021 09:37:02 +0200 Subject: [PATCH 2532/4254] WIP: Added missing functions to jsre module (#17881) * added missing functions: `replace`, `replaceAll`, `split`, `match` * added `startsWith` & `endsWith` * Update lib/js/jsre.nim Co-authored-by: Juan Carlos --- lib/js/jsre.nim | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index 7d51db646..a23fccaa8 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -30,6 +30,15 @@ func newRegExp*(pattern: cstring): RegExp {.importjs: "new RegExp(@)".} func compile*(self: RegExp; pattern: cstring; flags: cstring) {.importjs: "#.compile(@)".} ## Recompiles a regular expression during execution of a script. +func replace*(pattern: cstring; self: RegExp; replacement: cstring): cstring {.importjs: "#.replace(#, #)".} + ## Returns a new string with some or all matches of a pattern replaced by given replacement + +func split*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "#.split(#)".} + ## Divides a string into an ordered list of substrings and returns the array + +func match*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "#.match(#)".} + ## Returns an array of matches of a RegExp against given string + func exec*(self: RegExp; pattern: cstring): seq[cstring] {.importjs: "#.exec(#)".} ## Executes a search for a match in its string parameter. @@ -51,6 +60,20 @@ func contains*(pattern: cstring; self: RegExp): bool = assert "xabc".contains jsregex asm "`result` = `self`.test(`pattern`);" +func startsWith*(pattern: cstring; self: RegExp): bool = + ## Tests if string starts with given RegExp + runnableExamples: + let jsregex: RegExp = newRegExp(r"abc", r"i") + assert "abcd".startsWith jsregex + pattern.contains(newRegExp(("^" & $(self.source)).cstring, self.flags)) + +func endsWith*(pattern: cstring; self: RegExp): bool = + ## Tests if string ends with given RegExp + runnableExamples: + let jsregex: RegExp = newRegExp(r"bcd", r"i") + assert "abcd".endsWith jsregex + pattern.contains(newRegExp(($(self.source) & "$").cstring, self.flags)) + runnableExamples: let jsregex: RegExp = newRegExp(r"\s+", r"i") @@ -61,3 +84,10 @@ runnableExamples: jsregex.compile(r"[0-9]", r"i") assert "0123456789abcd".contains jsregex assert $jsregex == "/[0-9]/i" + jsregex.compile(r"abc", r"i") + assert "abcd".startsWith jsregex + assert "dabc".endsWith jsregex + jsregex.compile(r"\d", r"i") + assert "do1ne".split(jsregex) == @["do".cstring, "ne".cstring] + jsregex.compile(r"[lw]", r"i") + assert "hello world".replace(jsregex,"X") == "heXlo world" From fb86271556b4ea4485195febaa02b972149ca088 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 1 May 2021 11:10:40 +0200 Subject: [PATCH 2533/4254] =?UTF-8?q?system.nim=20cleanup=20some=20exporte?= =?UTF-8?q?d=20constants=20which=20should=20never=20have=20be=E2=80=A6=20(?= =?UTF-8?q?#17909)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * system.nim cleanup some exported constants which should never have been exported --- compiler/commands.nim | 5 +---- compiler/options.nim | 2 ++ lib/pure/coro.nim | 2 ++ lib/pure/os.nim | 2 +- lib/system.nim | 22 ++-------------------- lib/system/ansi_c.nim | 2 +- lib/system/coro_detection.nim | 20 ++++++++++++++++++++ lib/system/excpt.nim | 2 +- lib/system/io.nim | 2 +- tests/cpp/tcovariancerules.nim | 2 +- 10 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 lib/system/coro_detection.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 278199bc0..32f56ad0e 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -34,9 +34,6 @@ from ast import eqTypeFlags, tfGcSafe, tfNoSideEffect # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") -bootSwitch(usedNativeStacktrace, - defined(nativeStackTrace) and nativeStackTraceSupported, - "-d:nativeStackTrace") bootSwitch(usedFFI, hasFFI, "-d:nimHasLibFFI") type @@ -101,7 +98,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger & - usedTinyC & useLinenoise & usedNativeStacktrace & + usedTinyC & useLinenoise & usedFFI & usedBoehm & usedMarkAndSweep & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) diff --git a/compiler/options.nim b/compiler/options.nim index 4773ba284..36e0e64da 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -21,6 +21,8 @@ const hasFFI* = defined(nimHasLibFFI) copyrightYear* = "2021" + nimEnableCovariance* = defined(nimEnableCovariance) + type # please make sure we have under 32 options # (improves code efficiency a lot!) TOption* = enum # **keep binary compatible** diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index e3ed6aadd..f4495a536 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -21,6 +21,8 @@ ## ## Unstable API. +import system/coro_detection + when not nimCoroutines and not defined(nimdoc): when defined(noNimCoroutines): {.error: "Coroutines can not be used with -d:noNimCoroutines".} diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 50a88b43b..287fbe125 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1910,7 +1910,7 @@ proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow}) copyFile(source, dir / source.lastPathPart, options) when not declared(ENOENT) and not defined(windows): - when NoFakeVars: + when defined(nimscript): when not defined(haiku): const ENOENT = cint(2) # 2 on most systems including Solaris else: diff --git a/lib/system.nim b/lib/system.nim index c2c3306d4..e9c036b8a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -537,7 +537,7 @@ const include "system/inclrtl" -const NoFakeVars* = defined(nimscript) ## `true` if the backend doesn't support \ +const NoFakeVars = defined(nimscript) ## `true` if the backend doesn't support \ ## "fake variables" like `var EBADF {.importc.}: cint`. const notJSnotNims = not defined(js) and not defined(nimscript) @@ -1132,7 +1132,6 @@ const const hasThreadSupport = compileOption("threads") and not defined(nimscript) hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own - nimEnableCovariance* = defined(nimEnableCovariance) # or true when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"): # tcc doesn't support TLS @@ -1920,24 +1919,7 @@ include "system/gc_interface" # we have to compute this here before turning it off in except.nim anyway ... const NimStackTrace = compileOption("stacktrace") -template coroutinesSupportedPlatform(): bool = - when defined(sparc) or defined(ELATE) or defined(boehmgc) or defined(gogc) or - defined(nogc) or defined(gcRegions) or defined(gcMarkAndSweep): - false - else: - true - -when defined(nimCoroutines): - # Explicit opt-in. - when not coroutinesSupportedPlatform(): - {.error: "Coroutines are not supported on this architecture and/or garbage collector.".} - const nimCoroutines* = true -elif defined(noNimCoroutines): - # Explicit opt-out. - const nimCoroutines* = false -else: - # Autodetect coroutine support. - const nimCoroutines* = false +import system/coro_detection {.push checks: off.} # obviously we cannot generate checking operations here :-) diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 7e156eaab..e5f26e070 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -74,7 +74,7 @@ elif defined(haiku): SIGPIPE* = cint(7) SIG_DFL* = cast[CSighandlerT](0) else: - when NoFakeVars: + when defined(nimscript): {.error: "SIGABRT not ported to your platform".} else: var diff --git a/lib/system/coro_detection.nim b/lib/system/coro_detection.nim new file mode 100644 index 000000000..f6c1b5c15 --- /dev/null +++ b/lib/system/coro_detection.nim @@ -0,0 +1,20 @@ +## Coroutine detection logic + +template coroutinesSupportedPlatform(): bool = + when defined(sparc) or defined(ELATE) or defined(boehmgc) or defined(gogc) or + defined(nogc) or defined(gcRegions) or defined(gcMarkAndSweep): + false + else: + true + +when defined(nimCoroutines): + # Explicit opt-in. + when not coroutinesSupportedPlatform(): + {.error: "Coroutines are not supported on this architecture and/or garbage collector.".} + const nimCoroutines* = true +elif defined(noNimCoroutines): + # Explicit opt-out. + const nimCoroutines* = false +else: + # Autodetect coroutine support. + const nimCoroutines* = false diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index da034e57e..8ba3a1601 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -146,7 +146,7 @@ proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = # some platforms have native support for stack traces: const - nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and + nativeStackTraceSupported = (defined(macosx) or defined(linux)) and not NimStackTrace hasSomeStackTrace = NimStackTrace or defined(nimStackTraceOverride) or (defined(nativeStackTrace) and nativeStackTraceSupported) diff --git a/lib/system/io.nim b/lib/system/io.nim index 300e7ea3f..594c78209 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -252,7 +252,7 @@ proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.} = raiseEIO("cannot write string to file") {.pop.} -when NoFakeVars: +when defined(nimscript): when defined(windows): const IOFBF = cint(0) diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim index 49fe8015b..5ac7d8bac 100644 --- a/tests/cpp/tcovariancerules.nim +++ b/tests/cpp/tcovariancerules.nim @@ -31,7 +31,7 @@ import macros macro skipElse(n: untyped): untyped = n[0] template acceptWithCovariance(x, otherwise): untyped = - when nimEnableCovariance: + when defined nimEnableCovariance: x else: reject(x) From ee6d56141c11cf9273d3671eb9dd54097361cc1b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 1 May 2021 02:12:13 -0700 Subject: [PATCH 2534/4254] fix #17911 rawProc for cpp (#17912) --- lib/pure/hashes.nim | 18 ++++++++++------ lib/system.nim | 13 ++++++++---- tests/stdlib/thashes.nim | 30 ++++++++++++++++++++++---- tests/stdlib/tsystem.nim | 46 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 tests/stdlib/tsystem.nim diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 2dab498d7..f61fbdf2b 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -524,15 +524,21 @@ proc hash*[T: tuple | object | proc](x: T): Hash {.inline.} = proc hash(a: Obj2): Hash = hash((a.x)) assert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2")) runnableExamples: - # proc and closure examples + # proc proc fn1() = discard - var a = 0 - proc fn2() = a.inc - assert hash(fn1) != hash(fn2) const fn1b = fn1 assert hash(fn1b) == hash(fn1) - let fn2b = fn2 - assert hash(fn2b) == hash(fn2) + + # closure + proc outer = + var a = 0 + proc fn2() = a.inc + assert fn2 is "closure" + let fn2b = fn2 + assert hash(fn2b) == hash(fn2) + assert hash(fn2) != hash(fn1) + outer() + when T is "closure": result = hash((rawProc(x), rawEnv(x))) elif T is (proc): diff --git a/lib/system.nim b/lib/system.nim index e9c036b8a..aecda4a70 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2414,17 +2414,22 @@ when notJSnotNims: proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw proc pointer of the closure `x`. This is - ## useful for interfacing closures with C. + ## useful for interfacing closures with C/C++, hash compuations, etc. when T is "closure": + #[ + The conversion from function pointer to `void*` is a tricky topic, but this + should work at least for c++ >= c++11, e.g. for `dlsym` support. + refs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869, + https://stackoverflow.com/questions/14125474/casts-between-pointer-to-function-and-pointer-to-object-in-c-and-c + ]# {.emit: """ - `result` = `x`.ClP_0; + `result` = (void*)`x`.ClP_0; """.} else: {.error: "Only closure function and iterator are allowed!".} proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = - ## Retrieves the raw environment pointer of the closure `x`. This is - ## useful for interfacing closures with C. + ## Retrieves the raw environment pointer of the closure `x`. See also `rawProc`. when T is "closure": {.emit: """ `result` = `x`.ClE_0; diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 66857d3ca..46576ef12 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -184,8 +184,8 @@ proc main() = # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417 discard do: - assert a[0].addr.hash != a[1].addr.hash - assert cast[pointer](a[0].addr).hash == a[0].addr.hash + doAssert a[0].addr.hash != a[1].addr.hash + doAssert cast[pointer](a[0].addr).hash == a[0].addr.hash block: # hash(ref) type A = ref object @@ -193,9 +193,31 @@ proc main() = let a = A(x: 3) disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer let ha = a.hash - assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. + doAssert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. a.x = 4 - assert ha == a.hash # the hash only depends on the address + doAssert ha == a.hash # the hash only depends on the address + + block: # hash(proc) + proc fn(a: int): auto = a*2 + doAssert fn isnot "closure" + doAssert fn is (proc) + const fn2 = fn + let fn3 = fn + whenVMorJs: discard + do: + doAssert hash(fn2) == hash(fn) + doAssert hash(fn3) == hash(fn) + + block: # hash(closure) + proc outer() = + var a = 0 + proc inner() = a.inc + doAssert inner is "closure" + let inner2 = inner + whenVMorJs: discard + do: + doAssert hash(inner2) == hash(inner) + outer() static: main() main() diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim new file mode 100644 index 000000000..f8b172b44 --- /dev/null +++ b/tests/stdlib/tsystem.nim @@ -0,0 +1,46 @@ +discard """ + targets: "c cpp js" +""" + +# TODO: in future work move existing `system` tests here, where they belong + +import stdtest/testutils + +template main = + block: # closure + proc outer() = + var a = 0 + proc inner1 = a.inc + proc inner2 = discard + doAssert inner1 is "closure" + doAssert inner2 isnot "closure" + doAssert inner1 is (proc) + doAssert inner2 is (proc) + let inner1b = inner1 + doAssert inner1b is "closure" + doAssert inner1b == inner1 + outer() + + block: # rawProc, rawProc, bug #17911 + proc outer() = + var a = 0 + var b = 0 + proc inner1() = a.inc + proc inner2() = a += 2 + proc inner3() = b.inc + let inner1b = inner1 + doAssert inner2 != inner1 + doAssert inner3 != inner1 + whenVMorJs: discard + do: + doAssert rawProc(inner1b) == rawProc(inner1) + doAssert rawProc(inner2) != rawProc(inner1) + doAssert rawProc(inner3) != rawProc(inner1) + + doAssert rawEnv(inner1b) == rawEnv(inner1) + doAssert rawEnv(inner2) == rawEnv(inner1) # because both use `a` + # doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold + outer() + +static: main() +main() From 13b57524d35a18df57bec2a7d6a2faa7ce712e9f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 1 May 2021 10:43:20 -0700 Subject: [PATCH 2535/4254] ref #17913; fix typo in tools/ci_generate.nim generating build_all.sh (#17915) --- build_all.sh | 2 +- tools/ci_generate.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build_all.sh b/build_all.sh index 90665672f..37374aa7c 100755 --- a/build_all.sh +++ b/build_all.sh @@ -1,5 +1,5 @@ #! /bin/sh -rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` +# DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` # build development version of the compiler; can be rerun safely. # arguments can be passed, e.g.: diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index 2e6b4b3de..f08cd5409 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -87,7 +87,7 @@ if not exist %nim_csources% ( proc genPosixScript(): string = result = fmt""" #! /bin/sh -rem {doNotEdit} +# {doNotEdit} # build development version of the compiler; can be rerun safely. # arguments can be passed, e.g.: From 78e2d299dffc9508430778fcff1dcaee2c8d39fd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 1 May 2021 15:26:41 -0700 Subject: [PATCH 2536/4254] typo: nonexistant => nonexistent (#17918) * typo: nonexistant => nonexistent * fix test (ordering differs because of https://github.com/nim-lang/Nim/issues/17910) --- lib/pure/osproc.nim | 2 +- lib/pure/sugar.nim | 2 +- nimdoc/testproject/expected/testproject.html | 14 +++++++------- nimdoc/testproject/expected/testproject.idx | 2 +- nimdoc/testproject/expected/theindex.html | 4 ++-- nimdoc/testproject/testproject.nim | 2 +- tests/generics/t13525.nim | 8 ++++---- tests/importalls/mt6.nim | 2 +- tests/lexer/tcustom_numeric_literals.nim | 4 ++-- tests/nimdoc/trunnableexamples.nim | 4 ++-- tests/stdlib/tos.nim | 8 ++++---- tests/stdlib/tosproc.nim | 4 ++-- tests/stdlib/trstgen.nim | 4 ++-- tests/typerel/tvoid.nim | 2 +- tests/types/titerable.nim | 10 +++++----- tests/vm/tvmops.nim | 4 ++-- 16 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 6aefb8d6c..1ac37661b 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1595,7 +1595,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## import std/[strutils, strtabs] ## stripLineEnd(result[0]) ## portable way to remove trailing newline, if any ## doAssert result == ("12", 0) - ## doAssert execCmdEx("ls --nonexistant").exitCode != 0 + ## doAssert execCmdEx("ls --nonexistent").exitCode != 0 ## when defined(posix): ## assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) ## assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 9abef55a2..7cfa932e6 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -186,7 +186,7 @@ macro dumpToString*(x: untyped): string = assert dumpToString(a + x) == "a + x: 1 + x = 11" template square(x): untyped = x * x assert dumpToString(square(x)) == "square(x): x * x = 100" - assert not compiles dumpToString(1 + nonexistant) + assert not compiles dumpToString(1 + nonexistent) import std/strutils assert "failedAssertImpl" in dumpToString(assert true) # example with a statement result = newCall(bindSym"dumpToStringImpl") diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 1ea9e172a..70c5b695a 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -210,6 +210,11 @@ window.addEventListener('DOMContentLoaded', main);
  • z11()
  • + + -
      asyncFun1
    • - -
      proc c_nonexistant(frmt: cstring): cint {.importc: "nonexistant",
      +
      +
      proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
           header: "<stdio.h>", varargs, discardable.}
      diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 1d8be99da..a8cdc3be2 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -35,7 +35,7 @@ z17 testproject.html#z17 testproject: z17() p1 testproject.html#p1 testproject: p1() addfBug14485 testproject.html#addfBug14485 testproject: addfBug14485() c_printf testproject.html#c_printf,cstring testproject: c_printf(frmt: cstring): cint -c_nonexistant testproject.html#c_nonexistant,cstring testproject: c_nonexistant(frmt: cstring): cint +c_nonexistent testproject.html#c_nonexistent,cstring testproject: c_nonexistent(frmt: cstring): cint low testproject.html#low,T testproject: low[T: Ordinal | enum | range](x: T): T low2 testproject.html#low2,T testproject: low2[T: Ordinal | enum | range](x: T): T tripleStrLitTest testproject.html#tripleStrLitTest testproject: tripleStrLitTest() diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 81370d115..e6efee986 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -142,9 +142,9 @@ window.addEventListener('DOMContentLoaded', main);
    • Shapes.Circle
    -
    c_nonexistant:
    @@ -597,7 +597,7 @@ cz1 cz2

    Example:

    -
    discard "in cz2"
    +
    discard "in cz2"
    @@ -648,7 +648,7 @@ cz8

    Example:

    -
    doAssert 1 + 1 == 2
    +
    doAssert 1 + 1 == 2
    @@ -657,7 +657,7 @@ cz8

    Example: cmd: -d:foobar

    -
    discard 1
    cz10 +
    discard 1
    cz10 @@ -666,7 +666,7 @@ cz8

    Example:

    -
    discard 1
    +
    discard 1
    @@ -675,7 +675,7 @@ cz8

    Example:

    -
    discard 1
    +
    discard 1
    @@ -700,7 +700,7 @@ cz13 cz17 rest

    Example:

    -
    discard 1
    rest +
    discard 1
    rest @@ -709,21 +709,21 @@ cz17 rest cp1

    Example:

    -
    doAssert 1 == 1 # regular comments work here
    c4 +
    doAssert 1 == 1 # regular comments work here
    c4

    Example:

    -
    # c5 regular comments before 1st token work
    -# regular comment
    -#[
    +
    # c5 regular comments before 1st token work
    +# regular comment
    +#[
     nested regular comment
    -]#
    -doAssert 2 == 2 # c8
    -## this is a non-nested doc comment
    +]#
    +doAssert 2 == 2 # c8
    +## this is a non-nested doc comment
     
    -##[
    +##[
     this is a nested doc comment
    -]##
    -discard "c9"
    -# also work after
    +]##
    +discard "c9" +# also work after
    @@ -732,9 +732,9 @@ this is a nested doc comment Some proc

    Example:

    -
    discard "foo() = " & $[1]
    -#[
    -0: let's also add some broken html to make sure this won't break in future
    +
    discard "foo() = " & $[1]
    +#[
    +0: let's also add some broken html to make sure this won't break in future
     1: </span>
     2: </span>
     3: </span
    @@ -782,7 +782,7 @@ the c printf. etc.
     
     
    low2(2) # => -9223372036854775808

    Example:

    -
    discard "in low2"
    +
    discard "in low2"
    @@ -791,41 +791,41 @@ the c printf. etc.

    Example:

    -
    ## mullitline string litterals are tricky as their indentation can span
    -## below that of the runnableExamples
    -let s1a = """
    +
    ## mullitline string litterals are tricky as their indentation can span
    +## below that of the runnableExamples
    +let s1a = """
     should appear at indent 0
       at indent 2
     at indent 0
    -"""
    -# make sure this works too
    -let s1b = """start at same line
    +"""
    +# make sure this works too
    +let s1b = """start at same line
       at indent 2
     at indent 0
    -""" # comment after
    -let s2 = """sandwich """
    -let s3 = """"""
    -when false:
    -  let s5 = """
    -        in s5 """
    +""" # comment after
    +let s2 = """sandwich """
    +let s3 = """"""
    +when false:
    +  let s5 = """
    +        in s5 """
     
    -let s3b = ["""
    +let s3b = ["""
     %!? #[...] # inside a multiline ...
    -""", "foo"]
    +""", "foo"]
     
    -## make sure handles trailing spaces
    -let s4 = """ 
    -"""
    +## make sure handles trailing spaces
    +let s4 = """ 
    +"""
     
    -let s5 = """ x
    -"""
    -let s6 = """ ""
    -"""
    -let s7 = """"""""""
    -let s8 = ["""""""""", """
    -  """ ]
    -discard
    -# should be in
    +let s5 = """ x +""" +let s6 = """ "" +""" +let s7 = """""""""" +let s8 = ["""""""""", """ + """ ] +discard +# should be in
    @@ -896,9 +896,9 @@ foo3

    Example:

    -
    # ok1
    -assert 1 == 1
    -# ok2
    +
    # ok1
    +assert 1 == 1
    +# ok2
    @@ -914,7 +914,7 @@ foo1 foo2

    Example:

    -
    discard # bar
    +
    discard # bar
    @@ -935,9 +935,9 @@ foo2

    Example:

    -
    discard 1
    cz16 after +
    discard 1
    cz16 after

    Example:

    -
    doAssert 2 == 1 + 1
    +
    doAssert 2 == 1 + 1
    @@ -979,20 +979,20 @@ This does nothing

    Example:

    -
    import std/strutils
    -## issue #8871 preserve formatting
    -## line doc comment
    -# bar
    -doAssert "'foo" == "'foo"
    -##[
    +
    import std/strutils
    +## issue #8871 preserve formatting
    +## line doc comment
    +# bar
    +doAssert "'foo" == "'foo"
    +##[
     foo
     bar
    -]##
    +]##
     
    -doAssert: not "foo".startsWith "ba"
    -block:
    -  discard 0xff # elu par cette crapule
    -# should be in
    should be still in +doAssert: not "foo".startsWith "ba" +block: + discard 0xff # elu par cette crapule +# should be in
    should be still in @@ -1012,13 +1012,13 @@ cz15

    Example:

    discard

    Example:

    -
    discard 3
    +
    discard 3

    Example:

    -
    discard 4
    ok5 ok5b +
    discard 4
    ok5 ok5b

    Example:

    -
    assert true
    +
    assert true

    Example:

    -
    discard 1
    in or out? +
    discard 1
    in or out? @@ -1027,7 +1027,7 @@ cz15

    Example:

    -
    discard 2
    +
    discard 2
    From 2ce592a209f4cd7f59c009a01e4ac4037e63a7bd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 14 May 2021 15:33:17 -0700 Subject: [PATCH 2590/4254] refs #18011 disable some newly failing tests on cpp windows; refs #17946 increase timeout for tchannels (#18012) --- lib/system.nim | 8 ++++---- tests/cpp/temitlist.nim | 4 +++- tests/cpp/tempty_generic_obj.nim | 4 +++- tests/exception/tcpp_imported_exc.nim | 4 +++- tests/stdlib/tchannels.nim | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 9317c3440..be30665dd 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1317,10 +1317,10 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = ## ## See also: ## * `delete <#delete,seq[T],Natural>`_ for preserving the order - ## - ## .. code-block:: Nim - ## var i = @[1, 2, 3, 4, 5] - ## i.del(2) # => @[1, 2, 5, 4] + runnableExamples: + var a = @[10, 11, 12, 13, 14] + a.del(2) + assert a == @[10, 11, 14, 13] let xl = x.len - 1 movingCopy(x[i], x[xl]) setLen(x, xl) diff --git a/tests/cpp/temitlist.nim b/tests/cpp/temitlist.nim index 852537518..d446176fa 100644 --- a/tests/cpp/temitlist.nim +++ b/tests/cpp/temitlist.nim @@ -1,7 +1,9 @@ discard """ targets: "cpp" - output: '''6.0 + output: ''' +6.0 0''' +disabled: "windows" # pending bug #18011 """ # bug #4730 diff --git a/tests/cpp/tempty_generic_obj.nim b/tests/cpp/tempty_generic_obj.nim index 913c1ec3c..6125190b4 100644 --- a/tests/cpp/tempty_generic_obj.nim +++ b/tests/cpp/tempty_generic_obj.nim @@ -1,7 +1,9 @@ discard """ targets: "cpp" - output: '''int + output: ''' +int float''' +disabled: "windows" # pending bug #18011 """ import typetraits diff --git a/tests/exception/tcpp_imported_exc.nim b/tests/exception/tcpp_imported_exc.nim index 8b96ca635..5195b48e7 100644 --- a/tests/exception/tcpp_imported_exc.nim +++ b/tests/exception/tcpp_imported_exc.nim @@ -1,6 +1,7 @@ discard """ targets: "cpp" -output: '''caught as std::exception +output: ''' +caught as std::exception expected finally1 finally2 @@ -12,6 +13,7 @@ finally 2 expected cpp exception caught ''' +disabled: "windows" # pending bug #18011 """ type diff --git a/tests/stdlib/tchannels.nim b/tests/stdlib/tchannels.nim index d609eec78..492faf500 100644 --- a/tests/stdlib/tchannels.nim +++ b/tests/stdlib/tchannels.nim @@ -1,5 +1,5 @@ discard """ - timeout: 20.0 # but typically < 1s (in isolation but other tests running in parallel can affect this since based on epochTime) + timeout: 60.0 # but typically < 1s (in isolation but other tests running in parallel can affect this since based on epochTime) disabled: "freebsd" matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger" """ From 4857c462d5a9dc68519ab3c6996523bdcccb883f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 15 May 2021 06:50:39 +0200 Subject: [PATCH 2591/4254] Revert "fix #14873 properly by skipping `abi` field in importc type (#17944)" (#17992) This reverts commit 98c29c01eb91a0c6ce7da09380a272eebe6bca6f. --- lib/core/locks.nim | 5 +++++ lib/system/syslocks.nim | 8 ++++++++ tests/stdlib/uselocks.nim | 18 +----------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index baec45829..92967b9db 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -28,6 +28,11 @@ type {.push stackTrace: off.} + +proc `$`*(lock: Lock): string = + # workaround bug #14873 + result = "()" + proc initLock*(lock: var Lock) {.inline.} = ## Initializes the given lock. when not defined(js): diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index 9e8da610d..2f0c8b0ba 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -102,18 +102,26 @@ else: SysLockObj {.importc: "pthread_mutex_t", pure, final, header: """#include #include """.} = object + when defined(linux) and defined(amd64): + abi: array[40 div sizeof(clong), clong] SysLockAttr {.importc: "pthread_mutexattr_t", pure, final header: """#include #include """.} = object + when defined(linux) and defined(amd64): + abi: array[4 div sizeof(cint), cint] # actually a cint SysCondObj {.importc: "pthread_cond_t", pure, final, header: """#include #include """.} = object + when defined(linux) and defined(amd64): + abi: array[48 div sizeof(clonglong), clonglong] SysCondAttr {.importc: "pthread_condattr_t", pure, final header: """#include #include """.} = object + when defined(linux) and defined(amd64): + abi: array[4 div sizeof(cint), cint] # actually a cint SysLockType = distinct cint diff --git a/tests/stdlib/uselocks.nim b/tests/stdlib/uselocks.nim index e82de8adf..e9d23f9d9 100644 --- a/tests/stdlib/uselocks.nim +++ b/tests/stdlib/uselocks.nim @@ -11,21 +11,5 @@ proc use* (m: var MyType): int = result = 3 block: - # bug #14873 var l: Lock - doAssert ($l).len > 0 - # on posix, "()", on windows, something else, but that shouldn't be part of the spec - # what matters is that `$` doesn't cause the codegen bug mentioned - -when true: # intentional - # bug https://github.com/nim-lang/Nim/issues/14873#issuecomment-784241605 - type - Test = object - path: string # Removing this makes both cases work. - lock: Lock - # A: This is not fine. - var a = Test() - proc main(): void = - # B: This is fine. - var b = Test() - main() + doAssert $l == "()" From 1568ae23c66c572891207f2c1d330d246b3144ac Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 15 May 2021 07:53:38 +0300 Subject: [PATCH 2592/4254] docgen: escape special characters in titles (#18014) --- compiler/docgen.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 23e6ba10d..e07db9188 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1217,10 +1217,11 @@ proc genOutFile(d: PDoc, groupedToc = false): string = else: # Modules get an automatic title for the HTML, but no entry in the index. title = canonicalImport(d.conf, AbsoluteFile d.filename) + title = esc(d.target, title) var subtitle = "" if d.meta[metaSubtitle] != "": dispA(d.conf, subtitle, "

    $1

    ", - "\\\\\\vspace{0.5em}\\large $1", [d.meta[metaSubtitle]]) + "\\\\\\vspace{0.5em}\\large $1", [esc(d.target, d.meta[metaSubtitle])]) var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection") let bodyname = if d.hasToc and not d.isPureRst and not d.conf.isLatexCmd: @@ -1247,7 +1248,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = "title", title, "subtitle", subtitle, "tableofcontents", toc, "moduledesc", d.modDesc, "date", getDateStr(), "time", getClockStr(), "content", content, "author", d.meta[metaAuthor], - "version", d.meta[metaVersion], "analytics", d.analytics, + "version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics, "deprecationMsg", d.modDeprecationMsg] else: code = content From 3824fd3f9a303bc885a6f1f2eb7aa28fb5460cb7 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 15 May 2021 09:12:26 +0300 Subject: [PATCH 2593/4254] RST opt.list to have priority over def.list (#17845) --- lib/packages/docutils/rst.nim | 4 ++-- tests/stdlib/trst.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 181929c09..9cbc4efb7 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1867,10 +1867,10 @@ proc whichSection(p: RstParser): RstNodeKind = elif match(p, p.idx, "(e) ") or match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList - elif isDefList(p): - result = rnDefList elif isOptionList(p): result = rnOptionList + elif isDefList(p): + result = rnDefList else: result = rnParagraph of tkWord, tkOther, tkWhite: diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 905e5143a..e6c5d9700 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -1,6 +1,8 @@ discard """ output: ''' +[Suite] RST parsing + [Suite] RST indentation [Suite] RST include directive @@ -55,6 +57,30 @@ proc toAst(input: string, except EParseError: discard +suite "RST parsing": + test "option list has priority over definition list": + check(dedent""" + --defusages + file + -o set + """.toAst == + dedent""" + rnOptionList + rnOptionListItem order=1 + rnOptionGroup + rnLeaf '--' + rnLeaf 'defusages' + rnDescription + rnInner + rnLeaf 'file' + rnOptionListItem order=2 + rnOptionGroup + rnLeaf '-' + rnLeaf 'o' + rnDescription + rnLeaf 'set' + """) + suite "RST indentation": test "nested bullet lists": let input = dedent """ From 99788ee50426946d954e7311f567414b39f7b8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20T=2E=20Jarl=C3=B8v?= Date: Sat, 15 May 2021 21:26:15 +0200 Subject: [PATCH 2594/4254] Escape `%00` / `\0` in `dbQuote` (#18015) [backport:1.4] Fix https://github.com/nim-lang/Nim/issues/17925 --- lib/impure/db_postgres.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index cb9e5414a..4edeac2fc 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -110,7 +110,9 @@ proc dbQuote*(s: string): string = ## DB quotes the string. result = "'" for c in items(s): - if c == '\'': add(result, "''") + case c + of '\'': add(result, "''") + of '\0': add(result, "\\0") else: add(result, c) add(result, '\'') From 36145236644085c636c76500a189e3afda40c13f Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 16 May 2021 00:15:53 +0200 Subject: [PATCH 2595/4254] Rework DFA traversal (#18016) * enable using dbg: without a context * Optimally joining first write/last read analysis * Add test for #18002 * potLastReads -> potentialLastReads --- compiler/injectdestructors.nim | 208 ++++++++++++++++----------------- tests/arc/tmovebug.nim | 34 ++++++ 2 files changed, 133 insertions(+), 109 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 152efd8a1..48a852d26 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -46,6 +46,13 @@ type sinkArg const toDebug {.strdefine.} = "" +when toDebug.len > 0: + var shouldDebug = false + +template dbg(body) = + when toDebug.len > 0: + if shouldDebug: + body proc hasDestructor(c: Con; t: PType): bool {.inline.} = result = ast.hasDestructor(t) @@ -54,11 +61,6 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} = if not result and c.graph.config.selectedGC in {gcArc, gcOrc}: assert(not containsGarbageCollectedRef(t)) -template dbg(body) = - when toDebug.len > 0: - if c.owner.name.s == toDebug or toDebug == "always": - body - proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info) sym.typ = typ @@ -75,106 +77,111 @@ import sets, hashes, tables proc hash(n: PNode): Hash = hash(cast[pointer](n)) -type AliasCache = Table[(PNode, PNode), AliasKind] -proc aliasesCached(cache: var AliasCache, obj, field: PNode): AliasKind = +proc aliasesCached(cache: var Table[(PNode, PNode), AliasKind], obj, field: PNode): AliasKind = let key = (obj, field) if not cache.hasKey(key): cache[key] = aliases(obj, field) cache[key] -proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, lastReads, potLastReads: var IntSet; pc: var int, until: int) = - template aliasesCached(obj, field: PNode): untyped = +type + State = ref object + lastReads: IntSet + potentialLastReads: IntSet + notLastReads: IntSet + alreadySeen: HashSet[PNode] + +proc preprocessCfg(cfg: var ControlFlowGraph) = + for i in 0.. cfg.len: + cfg[i].dest = cfg.len - i + +proc mergeStates(a: var State, b: sink State) = + # Inplace for performance: + # lastReads = a.lastReads + b.lastReads + # potentialLastReads = (a.potentialLastReads + b.potentialLastReads) - (a.notLastReads + b.notLastReads) + # notLastReads = a.notLastReads + b.notLastReads + # alreadySeen = a.alreadySeen + b.alreadySeen + # b is never nil + if a == nil: + a = b + else: + a.lastReads.incl b.lastReads + a.potentialLastReads.incl b.potentialLastReads + a.potentialLastReads.excl a.notLastReads + a.potentialLastReads.excl b.notLastReads + a.notLastReads.incl b.notLastReads + a.alreadySeen.incl b.alreadySeen + +proc computeLastReadsAndFirstWrites(cfg: ControlFlowGraph) = + var cache = initTable[(PNode, PNode), AliasKind]() + template aliasesCached(obj, field: PNode): AliasKind = aliasesCached(cache, obj, field) - while pc < until: - case cfg[pc].kind - of def: - let potLastReadsCopy = potLastReads - for r in potLastReadsCopy: - if cfg[pc].n.aliasesCached(cfg[r].n) == yes: - # the path leads to a redefinition of 's' --> sink 's'. - lastReads.incl r - potLastReads.excl r - elif cfg[r].n.aliasesCached(cfg[pc].n) != no: - # only partially writes to 's' --> can't sink 's', so this def reads 's' - # or maybe writes to 's' --> can't sink 's' - cfg[r].n.comment = '\n' & $pc - potLastReads.excl r - inc pc - of use: - let potLastReadsCopy = potLastReads - for r in potLastReadsCopy: - if cfg[pc].n.aliasesCached(cfg[r].n) != no or cfg[r].n.aliasesCached(cfg[pc].n) != no: - cfg[r].n.comment = '\n' & $pc - potLastReads.excl r + var cfg = cfg + preprocessCfg(cfg) - potLastReads.incl pc + var states = newSeq[State](cfg.len + 1) + states[0] = State() - inc pc - of goto: - pc += cfg[pc].dest - of fork: - var variantA = pc + 1 - var variantB = pc + cfg[pc].dest - var potLastReadsA, potLastReadsB = potLastReads - var lastReadsA, lastReadsB: IntSet - while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until: - if variantA < variantB: - collectLastReads(cfg, cache, lastReadsA, potLastReadsA, variantA, min(variantB, until)) - else: - collectLastReads(cfg, cache, lastReadsB, potLastReadsB, variantB, min(variantA, until)) + for pc in 0.. sink 's'. + state.lastReads.incl r + state.potentialLastReads.excl r + elif cfg[r].n.aliasesCached(cfg[pc].n) != no: + # only partially writes to 's' --> can't sink 's', so this def reads 's' + # or maybe writes to 's' --> can't sink 's' + cfg[r].n.comment = '\n' & $pc + state.potentialLastReads.excl r + state.notLastReads.incl r - # Add those last reads that were turned into last reads on both branches - lastReads.incl lastReadsA * lastReadsB - # Add those last reads that were turned into last reads on only one branch, - # but where the read operation itself also belongs to only that branch - lastReads.incl (lastReadsA + lastReadsB) - potLastReads + var alreadySeenThisNode = false + for s in state.alreadySeen: + if cfg[pc].n.aliasesCached(s) != no or s.aliasesCached(cfg[pc].n) != no: + alreadySeenThisNode = true; break + if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite + else: cfg[pc].n.flags.incl nfFirstWrite - let oldPotLastReads = potLastReads - potLastReads = initIntSet() + state.alreadySeen.incl cfg[pc].n - potLastReads.incl potLastReadsA + potLastReadsB + mergeStates(states[pc + 1], move(states[pc])) + of use: + var potentialLastReadsCopy = state.potentialLastReads + for r in potentialLastReadsCopy: + if cfg[pc].n.aliasesCached(cfg[r].n) != no or cfg[r].n.aliasesCached(cfg[pc].n) != no: + cfg[r].n.comment = '\n' & $pc + state.potentialLastReads.excl r + state.notLastReads.incl r - # Remove potential last reads that were invalidated in a branch, - # but don't remove those which were turned into last reads on that branch - potLastReads.excl ((oldPotLastReads - potLastReadsA) - lastReadsA) - potLastReads.excl ((oldPotLastReads - potLastReadsB) - lastReadsB) + state.potentialLastReads.incl pc - pc = min(variantA, variantB) + state.alreadySeen.incl cfg[pc].n -proc collectFirstWrites(cfg: ControlFlowGraph; alreadySeen: var HashSet[PNode]; pc: var int, until: int) = - while pc < until: - case cfg[pc].kind - of def: - var alreadySeenThisNode = false - for s in alreadySeen: - if cfg[pc].n.aliases(s) != no or s.aliases(cfg[pc].n) != no: - alreadySeenThisNode = true; break - if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite - else: cfg[pc].n.flags.incl nfFirstWrite + mergeStates(states[pc + 1], move(states[pc])) + of goto: + mergeStates(states[pc + cfg[pc].dest], move(states[pc])) + of fork: + var copy = State() + copy[] = states[pc][] + mergeStates(states[pc + cfg[pc].dest], copy) + mergeStates(states[pc + 1], move(states[pc])) - alreadySeen.incl cfg[pc].n - - inc pc - of use: - alreadySeen.incl cfg[pc].n - - inc pc - of goto: - pc += cfg[pc].dest - of fork: - var variantA = pc + 1 - var variantB = pc + cfg[pc].dest - var alreadySeenA, alreadySeenB = alreadySeen - while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until: - if variantA < variantB: - collectFirstWrites(cfg, alreadySeenA, variantA, min(variantB, until)) - else: - collectFirstWrites(cfg, alreadySeenB, variantB, min(variantA, until)) - - alreadySeen.incl alreadySeenA + alreadySeenB - - pc = min(variantA, variantB) + let lastReads = (states[^1].lastReads + states[^1].potentialLastReads) - states[^1].notLastReads + var lastReadTable: Table[PNode, seq[int]] + for position, node in cfg: + if node.kind == use: + lastReadTable.mgetOrPut(node.n, @[]).add position + for node, positions in lastReadTable: + block checkIfAllPosLastRead: + for p in positions: + if p notin lastReads: break checkIfAllPosLastRead + node.flags.incl nfLastRead proc isLastRead(n: PNode; c: var Con): bool = let m = dfa.skipConvDfa(n) @@ -1096,6 +1103,8 @@ proc injectDefaultCalls(n: PNode, c: var Con) = injectDefaultCalls(n[i], c) proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): PNode = + when toDebug.len > 0: + shouldDebug = toDebug == owner.name.s or toDebug == "always" if sfGeneratedOp in owner.flags or (owner.kind == skIterator and isInlineIterator(owner.typ)): return n var c = Con(owner: owner, graph: g, g: constructCfg(owner, n), idgen: idgen) @@ -1107,26 +1116,7 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: if optCursorInference in g.config.options: computeCursors(owner, n, g) - block: - var cache = initTable[(PNode, PNode), AliasKind]() - var lastReads, potLastReads: IntSet - var pc = 0 - collectLastReads(c.g, cache, lastReads, potLastReads, pc, c.g.len) - lastReads.incl potLastReads - var lastReadTable: Table[PNode, seq[int]] - for position, node in c.g: - if node.kind == use: - lastReadTable.mgetOrPut(node.n, @[]).add position - for node, positions in lastReadTable: - var allPositionsLastRead = true - for p in positions: - if p notin lastReads: allPositionsLastRead = false; break - if allPositionsLastRead: - node.flags.incl nfLastRead - - var alreadySeen: HashSet[PNode] - pc = 0 - collectFirstWrites(c.g, alreadySeen, pc, c.g.len) + computeLastReadsAndFirstWrites(c.g) var scope: Scope let body = p(n, c, scope, normal) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 3ff1c4a0c..7977d330a 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -784,3 +784,37 @@ proc main3 = main3() +# misc +proc smoltest(x: bool): bool = + while true: + if true: return x + +discard smoltest(true) + +# bug #18002 +type + TTypeAttachedOp = enum + attachedAsgn + attachedSink + attachedTrace + + PNode = ref object + discard + +proc genAddrOf(n: PNode) = + assert n != nil, "moved?!" + +proc atomicClosureOp = + let x = PNode() + + genAddrOf: + block: + x + + case attachedTrace + of attachedSink: discard + of attachedAsgn: discard + of attachedTrace: genAddrOf(x) + +atomicClosureOp() + From c218f2ba0b8e27110087ea754c11cff123806a94 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 16 May 2021 10:39:52 +0800 Subject: [PATCH 2596/4254] [std/re]fix terrible and strange interface --- lib/impure/re.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 0c96876b9..95d77033b 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -142,7 +142,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], return rawMatches[1] - rawMatches[0] proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize: int): tuple[first, last: int] = + start = 0, bufSize = 0): tuple[first, last: int] = ## returns the starting position and end position of `pattern` in `buf` ## (where `buf` has length `bufSize` and is not necessarily `'\0'` terminated), ## and the captured @@ -200,7 +200,7 @@ proc findBounds*(s: string, pattern: Regex, result = findBounds(cstring(s), pattern, matches, start, s.len) proc findBounds*(buf: cstring, pattern: Regex, - start = 0, bufSize: int): tuple[first, last: int] = + start = 0, bufSize = 0): tuple[first, last: int] = ## returns the `first` and `last` position of `pattern` in `buf`, ## where `buf` has length `bufSize` (not necessarily `'\0'` terminated). ## If it does not match, `(-1,0)` is returned. @@ -239,7 +239,7 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string], result = matchOrFind(cstring(s), pattern, matches, start.cint, s.len.cint, pcre.ANCHORED) proc matchLen*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize: int): int {.inline.} = + start = 0, bufSize = 0): int {.inline.} = ## the same as `match`, but it returns the length of the match, ## if there is no match, `-1` is returned. Note that a match length ## of zero can happen. @@ -281,7 +281,7 @@ proc match*(s: string, pattern: Regex, matches: var openArray[string], result = matchLen(cstring(s), pattern, matches, start, s.len) != -1 proc match*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize: int): bool {.inline.} = + start = 0, bufSize = 0): bool {.inline.} = ## returns `true` if `buf[start.. Date: Sun, 16 May 2021 11:10:41 +0800 Subject: [PATCH 2597/4254] Revert "[std/re]fix terrible and strange interface" (#18027) This reverts commit c218f2ba0b8e27110087ea754c11cff123806a94. --- lib/impure/re.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 95d77033b..0c96876b9 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -142,7 +142,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], return rawMatches[1] - rawMatches[0] proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize = 0): tuple[first, last: int] = + start = 0, bufSize: int): tuple[first, last: int] = ## returns the starting position and end position of `pattern` in `buf` ## (where `buf` has length `bufSize` and is not necessarily `'\0'` terminated), ## and the captured @@ -200,7 +200,7 @@ proc findBounds*(s: string, pattern: Regex, result = findBounds(cstring(s), pattern, matches, start, s.len) proc findBounds*(buf: cstring, pattern: Regex, - start = 0, bufSize = 0): tuple[first, last: int] = + start = 0, bufSize: int): tuple[first, last: int] = ## returns the `first` and `last` position of `pattern` in `buf`, ## where `buf` has length `bufSize` (not necessarily `'\0'` terminated). ## If it does not match, `(-1,0)` is returned. @@ -239,7 +239,7 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string], result = matchOrFind(cstring(s), pattern, matches, start.cint, s.len.cint, pcre.ANCHORED) proc matchLen*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize = 0): int {.inline.} = + start = 0, bufSize: int): int {.inline.} = ## the same as `match`, but it returns the length of the match, ## if there is no match, `-1` is returned. Note that a match length ## of zero can happen. @@ -281,7 +281,7 @@ proc match*(s: string, pattern: Regex, matches: var openArray[string], result = matchLen(cstring(s), pattern, matches, start, s.len) != -1 proc match*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize = 0): bool {.inline.} = + start = 0, bufSize: int): bool {.inline.} = ## returns `true` if `buf[start.. Date: Sun, 16 May 2021 10:03:22 -0700 Subject: [PATCH 2598/4254] more informative error msg for undeclared field (`A(badfield: 1)` and `a.badfield = expr`) (#17777) --- compiler/semcall.nim | 15 +++++++++-- compiler/semobjconstr.nim | 3 ++- tests/errmsgs/tundeclared_field.nim | 40 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 tests/errmsgs/tundeclared_field.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 8f29bdf32..facaa89f7 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -411,8 +411,19 @@ proc resolveOverloads(c: PContext, n, orig: PNode, if overloadsState == csEmpty and result.state == csEmpty: if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim - # xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident) - localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f)) + template impl() = + # xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident) + localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f)) + if n[0].kind == nkIdent and n[0].ident.s == ".=" and n[2].kind == nkIdent: + let sym = n[1].typ.sym + if sym == nil: + impl() + else: + let field = n[2].ident.s + let msg = errUndeclaredField % field & " for type " & getProcHeader(c.config, sym) + localError(c.config, orig[2].info, msg) + else: + impl() return elif result.state != csMatch: if nfExprCall in n.flags: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 6f3cabcbf..16e3c6cee 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -429,7 +429,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = hasError = true break # 2) No such field exists in the constructed type - localError(c.config, field.info, errUndeclaredFieldX % id.s) + let msg = errUndeclaredField % id.s & " for type " & getProcHeader(c.config, t.sym) + localError(c.config, field.info, msg) hasError = true break diff --git a/tests/errmsgs/tundeclared_field.nim b/tests/errmsgs/tundeclared_field.nim new file mode 100644 index 000000000..2b274ae58 --- /dev/null +++ b/tests/errmsgs/tundeclared_field.nim @@ -0,0 +1,40 @@ +discard """ +cmd: '''nim check --hints:off $file''' +action: reject +nimout: ''' +tundeclared_field.nim(25, 12) Error: undeclared field: 'bad' for type tundeclared_field.A [type declared in tundeclared_field.nim(22, 8)] +tundeclared_field.nim(30, 16) Error: undeclared field: 'bad' for type tundeclared_field.A [type declared in tundeclared_field.nim(28, 8)] +tundeclared_field.nim(36, 4) Error: undeclared field: 'bad' for type tundeclared_field.A [type declared in tundeclared_field.nim(33, 8)] +tundeclared_field.nim(40, 13) Error: cannot instantiate Foo [type declared in tundeclared_field.nim(39, 8)] +''' +""" + + + + + + + + + +# line 20 +block: + type A = object + a0: int + var a: A + discard a.bad + +block: + type A = object + a0: int + var a = A(bad: 0) + +block: + type A = object + a0: int + var a: A + a.bad = 0 + +block: + type Foo[T: SomeInteger] = object + var a: Foo[float] From 63fcb9e5f54fa6d3a65499abbed26a923f0dd337 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 16 May 2021 19:43:52 +0200 Subject: [PATCH 2599/4254] Disable performance hints by default (verbosity 1) (#18024) --- compiler/lineinfos.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 27d7b32e0..47cddb888 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -199,7 +199,7 @@ proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext, hintDeclaredLoc} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, - hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin} + hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance} result[0] = result[1] - {hintSuccessX, hintBuildMode, hintSuccess, hintConf, hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC} From d83b25db1ebe7025d95dbce3978219948f5c49d3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 16 May 2021 14:54:10 -0700 Subject: [PATCH 2600/4254] fix #18007: std/json now serializes nan,inf,-inf as strings instead of invalid json (#18026) * fix #18007: std/json now serializes nan,inf,-inf as raw strings instead of invalid json * fix roundtrip * fix tests * fix changelog * simplify * add runnableExamples * fix typo [skip ci] --- changelog.md | 2 + lib/pure/json.nim | 121 +++++++++++++++++++++--------------- lib/std/jsonutils.nim | 3 + tests/stdlib/tjson.nim | 23 +++++++ tests/stdlib/tjsonutils.nim | 21 ++++++- 5 files changed, 119 insertions(+), 51 deletions(-) diff --git a/changelog.md b/changelog.md index 98a7a8c44..369b11917 100644 --- a/changelog.md +++ b/changelog.md @@ -70,6 +70,8 @@ - `jsonutils` now serializes/deserializes holey enums as regular enums (via `ord`) instead of as strings. Use `-d:nimLegacyJsonutilsHoleyEnum` for a transition period. +- `json` and `jsonutils` now serialize NaN, Inf, -Inf as strings, so that + `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` which was invalid json. ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 96ee61fd5..3a9fa5898 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -333,7 +333,16 @@ proc `%`*(n: BiggestInt): JsonNode = proc `%`*(n: float): JsonNode = ## Generic constructor for JSON data. Creates a new `JFloat JsonNode`. - result = JsonNode(kind: JFloat, fnum: n) + runnableExamples: + assert $(%[NaN, Inf, -Inf, 0.0, -0.0, 1.0, 1e-2]) == """["nan","inf","-inf",0.0,-0.0,1.0,0.01]""" + assert (%NaN).kind == JString + assert (%0.0).kind == JFloat + # for those special cases, we could also have used `newJRawNumber` but then + # it would've been inconsisten with the case of `parseJson` vs `%` for representing them. + if n != n: newJString("nan") + elif n == Inf: newJString("inf") + elif n == -Inf: newJString("-inf") + else: JsonNode(kind: JFloat, fnum: n) proc `%`*(b: bool): JsonNode = ## Generic constructor for JSON data. Creates a new `JBool JsonNode`. @@ -662,6 +671,47 @@ proc escapeJson*(s: string): string = result = newStringOfCap(s.len + s.len shr 3) escapeJson(s, result) +proc toUgly*(result: var string, node: JsonNode) = + ## Converts `node` to its JSON Representation, without + ## regard for human readability. Meant to improve `$` string + ## conversion performance. + ## + ## JSON representation is stored in the passed `result` + ## + ## This provides higher efficiency than the `pretty` procedure as it + ## does **not** attempt to format the resulting JSON to make it human readable. + var comma = false + case node.kind: + of JArray: + result.add "[" + for child in node.elems: + if comma: result.add "," + else: comma = true + result.toUgly child + result.add "]" + of JObject: + result.add "{" + for key, value in pairs(node.fields): + if comma: result.add "," + else: comma = true + key.escapeJson(result) + result.add ":" + result.toUgly value + result.add "}" + of JString: + if node.isUnquoted: + result.add node.str + else: + escapeJson(node.str, result) + of JInt: + result.addInt(node.num) + of JFloat: + result.addFloat(node.fnum) + of JBool: + result.add(if node.bval: "true" else: "false") + of JNull: + result.add "null" + proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, lstArr = false, currIndent = 0) = case node.kind @@ -689,10 +739,7 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, result.add("{}") of JString: if lstArr: result.indent(currIndent) - if node.isUnquoted: - result.add node.str - else: - escapeJson(node.str, result) + toUgly(result, node) of JInt: if lstArr: result.indent(currIndent) result.addInt(node.num) @@ -743,47 +790,6 @@ proc pretty*(node: JsonNode, indent = 2): string = result = "" toPretty(result, node, indent) -proc toUgly*(result: var string, node: JsonNode) = - ## Converts `node` to its JSON Representation, without - ## regard for human readability. Meant to improve `$` string - ## conversion performance. - ## - ## JSON representation is stored in the passed `result` - ## - ## This provides higher efficiency than the `pretty` procedure as it - ## does **not** attempt to format the resulting JSON to make it human readable. - var comma = false - case node.kind: - of JArray: - result.add "[" - for child in node.elems: - if comma: result.add "," - else: comma = true - result.toUgly child - result.add "]" - of JObject: - result.add "{" - for key, value in pairs(node.fields): - if comma: result.add "," - else: comma = true - key.escapeJson(result) - result.add ":" - result.toUgly value - result.add "}" - of JString: - if node.isUnquoted: - result.add node.str - else: - node.str.escapeJson(result) - of JInt: - result.addInt(node.num) - of JFloat: - result.addFloat(node.fnum) - of JBool: - result.add(if node.bval: "true" else: "false") - of JNull: - result.add "null" - proc `$`*(node: JsonNode): string = ## Converts `node` to its JSON Representation on one line. result = newStringOfCap(node.len shl 1) @@ -1087,11 +1093,26 @@ when defined(nimFixedForwardGeneric): dst = cast[T](jsonNode.num) proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) - if jsonNode.kind == JFloat: - dst = T(jsonNode.fnum) + if jsonNode.kind == JString: + case jsonNode.str + of "nan": + let b = NaN + dst = T(b) + # dst = NaN # would fail some tests because range conversions would cause CT error + # in some cases; but this is not a hot-spot inside this branch and backend can optimize this. + of "inf": + let b = Inf + dst = T(b) + of "-inf": + let b = -Inf + dst = T(b) + else: raise newException(JsonKindError, "expected 'nan|inf|-inf', got " & jsonNode.str) else: - dst = T(jsonNode.num) + verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) + if jsonNode.kind == JFloat: + dst = T(jsonNode.fnum) + else: + dst = T(jsonNode.num) proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JString}, jsonPath) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 99f5ce9c6..1f49f60ed 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -12,6 +12,9 @@ runnableExamples: let a = (1.5'f32, (b: "b2", a: "a2"), 'x', @[Foo(t: true, z1: -3), nil], [{"name": "John"}.newStringTable]) let j = a.toJson assert j.jsonTo(typeof(a)).toJson == j + assert $[NaN, Inf, -Inf, 0.0, -0.0, 1.0, 1e-2].toJson == """["nan","inf","-inf",0.0,-0.0,1.0,0.01]""" + assert 0.0.toJson.kind == JFloat + assert Inf.toJson.kind == JString import json, strutils, tables, sets, strtabs, options diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index e538baf4f..e757e6c7e 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -8,14 +8,27 @@ Note: Macro tests are in tests/stdlib/tjsonmacro.nim ]# import std/[json,parsejson,strutils] +from std/math import isNaN when not defined(js): import std/streams proc testRoundtrip[T](t: T, expected: string) = + # checks that `T => json => T2 => json2` is such that json2 = json let j = %t doAssert $j == expected, $j doAssert %(j.to(T)) == j +proc testRoundtripVal[T](t: T, expected: string) = + # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T` + # note that this isn't always possible, e.g. for pointer-like types or nans + let j = %t + doAssert $j == expected, $j + let j2 = ($j).parseJson + doAssert $j2 == expected, $(j2, t) + let t2 = j2.to(T) + doAssert t2 == t + doAssert $(%* t2) == expected # sanity check, because -0.0 = 0.0 but their json representation differs + let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}""" # nil passthrough doAssert(testJson{"doesnt_exist"}{"anything"}.isNil) @@ -301,6 +314,16 @@ block: # bug #17383 testRoundtrip(int64.high): "9223372036854775807" testRoundtrip(uint64.high): "18446744073709551615" +block: # bug #18007 + testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]""" + # pending https://github.com/nim-lang/Nim/issues/18025 use: + # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0]) + let inf = float32(Inf) + testRoundtrip([float32(NaN), inf, -inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]""" + when not defined(js): # because of Infinity vs inf + testRoundtripVal([inf, -inf, 0.0, -0.0, 1.0]): """["inf","-inf",0.0,-0.0,1.0]""" + let a = parseJson($(%NaN)).to(float) + doAssert a.isNaN block: let a = "18446744073709551615" diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 18d0aa325..c826a79b0 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -4,15 +4,28 @@ discard """ import std/jsonutils import std/json +from std/math import isNaN proc testRoundtrip[T](t: T, expected: string) = + # checks that `T => json => T2 => json2` is such that json2 = json let j = t.toJson - doAssert $j == expected, $j + doAssert $j == expected, "\n" & $j & "\n" & expected doAssert j.jsonTo(T).toJson == j var t2: T t2.fromJson(j) doAssert t2.toJson == j +proc testRoundtripVal[T](t: T, expected: string) = + # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T` + # note that this isn't always possible, e.g. for pointer-like types. + let j = t.toJson + let j2 = $j + doAssert j2 == expected, j2 + let j3 = j2.parseJson + let t2 = j3.jsonTo(T) + doAssert t2 == t + doAssert $t2.toJson == j2 # still needed, because -0.0 = 0.0 but their json representation differs + import tables, sets, algorithm, sequtils, options, strtabs from strutils import contains @@ -91,6 +104,12 @@ template fn() = else: testRoundtrip(a): "[9223372036854775807,18446744073709551615]" + block: # bug #18007 + testRoundtrip((NaN, Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]""" + testRoundtrip((float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]""" + testRoundtripVal((Inf, -Inf, 0.0, -0.0, 1.0)): """["inf","-inf",0.0,-0.0,1.0]""" + doAssert ($NaN.toJson).parseJson.jsonTo(float).isNaN + block: # case object type Foo = object x0: float From 2096490b5974cfb11d0f5d37ff6d3a963ef43713 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 17 May 2021 00:55:14 +0300 Subject: [PATCH 2601/4254] follow-up #17930 - inline syntax highlighting (#18013) * follow-up #17930 - inline syntax highlighting * make closure->nimcall --- doc/gc.rst | 35 ++++++++++++++++++++++------------- lib/packages/docutils/rst.nim | 25 ++++++++++++++----------- tests/stdlib/trst.nim | 21 +++++++++++++++++++++ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index 4455afcbe..5de02f73d 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -1,9 +1,10 @@ -.. default-role:: code - ======================= Nim's Memory Management ======================= +.. default-role:: code +.. include:: rstcommon.rst + :Author: Andreas Rumpf :Version: |nimversion| @@ -29,24 +30,28 @@ and how the memory management strategies other than garbage collectors work. Multi-paradigm Memory Management Strategies =========================================== +.. default-role:: option + To choose the memory management strategy use the `--gc:` switch. -- `--gc:refc`. This is the default GC. It's a +--gc:refc This is the default GC. It's a deferred reference counting based garbage collector with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. -- `--gc:markAndSweep`. Simple Mark-And-Sweep based garbage collector. Heaps are thread-local. -- `--gc:boehm`. Boehm based garbage collector, it offers a shared heap. -- `--gc:go`. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. -- `--gc:arc`. Plain reference counting with +--gc:markAndSweep Simple Mark-And-Sweep based garbage collector. + Heaps are thread-local. +--gc:boehm Boehm based garbage collector, it offers a shared heap. +--gc:go Go's garbage collector, useful for interoperability with Go. + Offers a shared heap. +--gc:arc Plain reference counting with `move semantic optimizations `_, offers a shared heap. It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles cause memory leaks, beware. -- `--gc:orc`. Same as `--gc:arc` but adds a cycle collector based on "trial deletion". +--gc:orc Same as `--gc:arc` but adds a cycle collector based on "trial deletion". Unfortunately, that makes its performance profile hard to reason about so it is less useful for hard real-time systems. -- `--gc:none`. No memory management strategy nor a garbage collector. Allocated memory is +--gc:none No memory management strategy nor a garbage collector. Allocated memory is simply never freed. You should use `--gc:arc` instead. @@ -62,6 +67,9 @@ Go Shared Cycle Collector Yes `--gc:go` None Manual Manual Manual `--gc:none` ================== ======== ================= ============== =================== +.. default-role:: code +.. include:: rstcommon.rst + JavaScript's garbage collector is used for the `JavaScript and NodeJS `_ compilation targets. The `NimScript `_ target uses the memory management strategy built into @@ -82,7 +90,7 @@ Soft real-time support ---------------------- To enable real-time support, the symbol `useRealtimeGC`:idx: needs to be -defined via `--define:useRealtimeGC` (you can put this into your config +defined via `--define:useRealtimeGC`:option: (you can put this into your config file as well). With this switch the garbage collector supports the following operations: @@ -132,7 +140,7 @@ Time measurement with garbage collectors ---------------------------------------- The garbage collectors' way of measuring time uses -(see `lib/system/timers.nim` for the implementation): +(see ``lib/system/timers.nim`` for the implementation): 1) `QueryPerformanceCounter` and `QueryPerformanceFrequency` on Windows. 2) `mach_absolute_time` on Mac OS X. @@ -170,7 +178,7 @@ Other useful procs from `system `_ you can use to keep track of mem * `GC_getStatistics()` Garbage collector statistics as a human-readable string. These numbers are usually only for the running thread, not for the whole heap, -with the exception of `--gc:boehm` and `--gc:go`. +with the exception of `--gc:boehm`:option: and `--gc:go`:option:. In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`. @@ -184,7 +192,8 @@ Heap dump The heap dump feature is still in its infancy, but it already proved useful for us, so it might be useful for you. To get a heap dump, compile -with `-d:nimTypeNames` and call `dumpNumberOfInstances` at a strategic place in your program. +with `-d:nimTypeNames`:option: and call `dumpNumberOfInstances` +at a strategic place in your program. This produces a list of the used types in your program and for every type the total amount of object instances for this type as well as the total amount of bytes these instances take up. diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 9cbc4efb7..da04e9b54 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1151,6 +1151,18 @@ proc toOtherRole(n: PRstNode, kind: RstNodeKind, roleName: string): PRstNode = proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var newKind = n.kind var newSons = n.sons + + proc finalizeInterpreted(node: PRstNode, newKind: RstNodeKind, + newSons: seq[PRstNode], roleName: string): + PRstNode {.nimcall.} = + # fixes interpreted text (`x` or `y`:role:) to proper internal AST format + if newKind in {rnUnknownRole, rnCodeFragment}: + result = node.toOtherRole(newKind, roleName) + elif newKind == rnInlineCode: + result = node.toInlineCode(language=roleName) + else: + result = newRstNode(newKind, newSons) + if isInlineMarkupEnd(p, "_", exact=true) or isInlineMarkupEnd(p, "__", exact=true): inc p.idx @@ -1175,19 +1187,10 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = # a role: let (roleName, lastIdx) = getRefname(p, p.idx+1) newKind = whichRole(p, roleName) - if newKind in {rnUnknownRole, rnCodeFragment}: - result = n.toOtherRole(newKind, roleName) - elif newKind == rnInlineCode: - result = n.toInlineCode(language=roleName) - else: - result = newRstNode(newKind, newSons) + result = n.finalizeInterpreted(newKind, newSons, roleName) p.idx = lastIdx + 2 else: - if p.s.currRoleKind == rnInlineCode: - result = n.toInlineCode(language=p.s.currRole) - else: - newKind = p.s.currRoleKind - result = newRstNode(newKind, newSons) + result = n.finalizeInterpreted(p.s.currRoleKind, newSons, p.s.currRole) proc matchVerbatim(p: RstParser, start: int, expr: string): int = result = start diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index e6c5d9700..71f5a858b 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -371,6 +371,27 @@ suite "RST inline markup": rnLeaf '```' """) + test "interpreted text parsing: code fragments": + check(dedent""" + .. default-role:: option + + `--gc:refc`""".toAst == + dedent""" + rnInner + rnDefaultRole + rnDirArg + rnLeaf 'option' + [nil] + [nil] + rnParagraph + rnCodeFragment + rnInner + rnLeaf '--' + rnLeaf 'gc' + rnLeaf ':' + rnLeaf 'refc' + rnLeaf 'option' + """) test """interpreted text can be ended with \` """: let output = (".. default-role:: literal\n" & """`\``""").toAst From e904c6d87ccbb453f6f1d649b2c715bd3cebc815 Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 17 May 2021 00:04:39 -0600 Subject: [PATCH 2602/4254] Add `checked` to dom (#18033) This allows the ability to set a checkbox as checked programmatically. It's different from `setAttribute` because once an input has been clicked on by the user, `setAttribute` no longer works programmatically. --- lib/js/dom.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 303cc178f..16fc96b68 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1379,6 +1379,9 @@ proc `class=`*(n: Node; v: cstring) {.importcpp: "#.className = #", nodecl.} proc value*(n: Node): cstring {.importcpp: "#.value", nodecl.} proc `value=`*(n: Node; v: cstring) {.importcpp: "#.value = #", nodecl.} +proc checked*(n: Node): bool {.importcpp: "#.checked", nodecl.} +proc `checked=`*(n: Node; v: bool) {.importcpp: "#.checked = #", nodecl.} + proc `disabled=`*(n: Node; v: bool) {.importcpp: "#.disabled = #", nodecl.} when defined(nodejs): From 8be5344b3bb74d62cff5aa6a18f4223680612ad5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 17 May 2021 01:28:52 -0700 Subject: [PATCH 2603/4254] ./koch --nonexistant now fails (#18036) --- koch.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index 15355ec36..3d7276aee 100644 --- a/koch.nim +++ b/koch.nim @@ -634,9 +634,9 @@ proc valgrind(cmd: string) = let supp = getAppDir() / "tools" / "nimgrind.supp" exec("valgrind --suppressions=" & supp & valcmd) -proc showHelp() = +proc showHelp(success: bool) = quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)), - CompileDate, CompileTime], QuitSuccess) + CompileDate, CompileTime], if success: QuitSuccess else: QuitFailure) proc branchDone() = let thisBranch = execProcess("git symbolic-ref --short HEAD").strip() @@ -656,6 +656,7 @@ when isMainModule: case op.kind of cmdLongOption, cmdShortOption: case normalize(op.key) + of "help", "h": showHelp(success = true) of "latest": latest = true of "stable": latest = false of "nim": nimExe = op.val.absolutePath # absolute so still works with changeDir @@ -663,7 +664,7 @@ when isMainModule: localDocsOnly = true if op.val.len > 0: localDocsOut = op.val.absolutePath - else: showHelp() + else: showHelp(success = false) of cmdArgument: case normalize(op.key) of "boot": boot(op.cmdLineRest) @@ -705,6 +706,6 @@ when isMainModule: exec("nimble install -y fusion@$#" % suffix) of "ic": icTest(op.cmdLineRest) of "branchdone": branchDone() - else: showHelp() + else: showHelp(success = false) break of cmdEnd: break From fac5bae7b7d87aeec48c7252029c2852ee157ac9 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 17 May 2021 13:48:10 +0200 Subject: [PATCH 2604/4254] Fix running testament c nimble-packages without batch arg (#18023) * Fix running testament c nimble-packages without batch arg * Fix --- testament/categories.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 1253a2b8c..1f0bd6acf 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -424,11 +424,12 @@ proc listPackages(packageFilter: string): seq[NimblePackage] = # at least should be a regex; a substring match makes no sense. result = pkgs.filterIt(packageFilter in it.name) else: - let pkgs1 = pkgs.filterIt(it.allowFailure) - let pkgs2 = pkgs.filterIt(not it.allowFailure) if testamentData0.batchArg == "allowed_failures": - result = pkgs1 + result = pkgs.filterIt(it.allowFailure) + elif testamentData0.testamentNumBatch == 0: + result = pkgs else: + let pkgs2 = pkgs.filterIt(not it.allowFailure) for i in 0.. Date: Tue, 18 May 2021 09:16:07 +0300 Subject: [PATCH 2605/4254] add sink and lent annotations for xmltree and streams (#18037) --- lib/pure/streams.nim | 2 +- lib/pure/xmltree.nim | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 3cc5ea038..7dc81148f 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1252,7 +1252,7 @@ else: # after 1.3 or JS not defined var s = StringStream(s) s.data = "" - proc newStringStream*(s: string = ""): owned StringStream = + proc newStringStream*(s: sink string = ""): owned StringStream = ## Creates a new stream from the string `s`. ## ## See also: diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index af7e4d508..fdb2c3fc5 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -70,7 +70,7 @@ proc newXmlNode(kind: XmlNodeKind): XmlNode = ## Creates a new ``XmlNode``. result = XmlNode(k: kind) -proc newElement*(tag: string): XmlNode = +proc newElement*(tag: sink string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnElement`` with the given `tag`. ## ## See also: @@ -89,7 +89,7 @@ proc newElement*(tag: string): XmlNode = result.s = @[] # init attributes lazily to save memory -proc newText*(text: string): XmlNode = +proc newText*(text: sink string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnText`` with the text `text`. runnableExamples: var b = newText("my text") @@ -99,13 +99,13 @@ proc newText*(text: string): XmlNode = result = newXmlNode(xnText) result.fText = text -proc newVerbatimText*(text: string): XmlNode {.since: (1, 3).} = +proc newVerbatimText*(text: sink string): XmlNode {.since: (1, 3).} = ## Creates a new ``XmlNode`` of kind ``xnVerbatimText`` with the text `text`. ## **Since**: Version 1.3. result = newXmlNode(xnVerbatimText) result.fText = text -proc newComment*(comment: string): XmlNode = +proc newComment*(comment: sink string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnComment`` with the text `comment`. runnableExamples: var c = newComment("my comment") @@ -115,7 +115,7 @@ proc newComment*(comment: string): XmlNode = result = newXmlNode(xnComment) result.fText = comment -proc newCData*(cdata: string): XmlNode = +proc newCData*(cdata: sink string): XmlNode = ## Creates a new ``XmlNode`` of kind ``xnCData`` with the text `cdata`. runnableExamples: var d = newCData("my cdata") @@ -135,7 +135,7 @@ proc newEntity*(entity: string): XmlNode = result = newXmlNode(xnEntity) result.fText = entity -proc newXmlTree*(tag: string, children: openArray[XmlNode], +proc newXmlTree*(tag: sink string, children: openArray[XmlNode], attributes: XmlAttributes = nil): XmlNode = ## Creates a new XML tree with `tag`, `children` and `attributes`. ## @@ -151,7 +151,7 @@ proc newXmlTree*(tag: string, children: openArray[XmlNode], h.add newEntity("some entity") let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes let k = newXmlTree("treeTag", [g, h], att) - + doAssert $k == """ some text &some entity; @@ -163,7 +163,7 @@ proc newXmlTree*(tag: string, children: openArray[XmlNode], for i in 0..children.len-1: result.s[i] = children[i] result.fAttr = attributes -proc text*(n: XmlNode): string {.inline.} = +proc text*(n: XmlNode): lent string {.inline.} = ## Gets the associated text with the node `n`. ## ## `n` can be a CDATA, Text, comment, or entity node. @@ -181,7 +181,7 @@ proc text*(n: XmlNode): string {.inline.} = assert n.k in {xnText, xnComment, xnCData, xnEntity} result = n.fText -proc `text=`*(n: XmlNode, text: string){.inline.} = +proc `text=`*(n: XmlNode, text: sink string) {.inline.} = ## Sets the associated text with the node `n`. ## ## `n` can be a CDATA, Text, comment, or entity node. @@ -199,7 +199,7 @@ proc `text=`*(n: XmlNode, text: string){.inline.} = assert n.k in {xnText, xnComment, xnCData, xnEntity} n.fText = text -proc tag*(n: XmlNode): string {.inline.} = +proc tag*(n: XmlNode): lent string {.inline.} = ## Gets the tag name of `n`. ## ## `n` has to be an ``xnElement`` node. @@ -220,7 +220,7 @@ proc tag*(n: XmlNode): string {.inline.} = assert n.k == xnElement result = n.fTag -proc `tag=`*(n: XmlNode, tag: string) {.inline.} = +proc `tag=`*(n: XmlNode, tag: sink string) {.inline.} = ## Sets the tag name of `n`. ## ## `n` has to be an ``xnElement`` node. @@ -389,13 +389,13 @@ proc clear*(n: var XmlNode) = var g = newElement("myTag") g.add newText("some text") g.add newComment("this is comment") - + var h = newElement("secondTag") h.add newEntity("some entity") - + let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes var k = newXmlTree("treeTag", [g, h], att) - + doAssert $k == """ some text &some entity; @@ -447,7 +447,7 @@ proc toXmlAttributes*(keyValuePairs: varargs[tuple[key, let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes var j = newElement("myTag") j.attrs = att - + doAssert $j == """""" newStringTable(keyValuePairs) From 7f077a76fea389ce4f55e18857c499fadb3958fa Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 18 May 2021 06:10:19 -0700 Subject: [PATCH 2606/4254] jsonutils: add customization for toJson via `ToJsonOptions`; generalize symbolName; add symbolRank (#18029) * jsonutils: add customization for toJson via `ToJsonOptions` * add enumutils.symbolRank * lookup table implementation for HoleyEnum * cleanup * changelog * fixup * Update lib/std/jsonutils.nim Co-authored-by: Andreas Rumpf --- changelog.md | 5 ++- lib/std/enumutils.nim | 65 +++++++++++++++++++++++++++++++++++-- lib/std/jsonutils.nim | 43 +++++++++++++++++------- tests/stdlib/tjsonutils.nim | 13 ++++++++ 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 369b11917..97e749337 100644 --- a/changelog.md +++ b/changelog.md @@ -118,9 +118,11 @@ - `json.%`,`json.to`, `jsonutils.formJson`,`jsonutils.toJson` now work with `uint|uint64` instead of raising (as in 1.4) or giving wrong results (as in 1.2). +- `jsonutils` now handles `cstring` (including as Table key), and `set`. + - added `jsonutils.jsonTo` overload with `opt = Joptions()` param. -- `jsonutils` now handles `cstring` (including as Table key), and `set`. +- `jsonutils.toJson` now supports customization via `ToJsonOptions`. - Added an overload for the `collect` macro that inferes the container type based on the syntax of the last expression. Works with std seqs, tables and sets. @@ -138,6 +140,7 @@ - Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum. Added `items` for enums with holes. Added `symbolName` to return the enum symbol name ignoring the human readable name. + Added `symbolRank` to return the index in which an enum member is listed in an enum. - Added `typetraits.HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 6195ae07d..09cf24f51 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -86,8 +86,67 @@ iterator items*[T: HoleyEnum](E: typedesc[T]): T = assert B[float].toSeq == [B[float].b0, B[float].b1] for a in enumFullRange(E): yield a -func symbolName*[T: OrdinalEnum](a: T): string = +func span(T: typedesc[HoleyEnum]): int = + (T.high.ord - T.low.ord) + 1 + +const invalidSlot = uint8.high + +proc genLookup[T: typedesc[HoleyEnum]](_: T): auto = + const n = span(T) + var ret: array[n, uint8] + var i = 0 + assert n <= invalidSlot.int + for ai in mitems(ret): ai = invalidSlot + for ai in items(T): + ret[ai.ord - T.low.ord] = uint8(i) + inc(i) + return ret + +func symbolRankImpl[T](a: T): int {.inline.} = + const n = T.span + const thres = 255 # must be <= `invalidSlot`, but this should be tuned. + when n <= thres: + const lookup = genLookup(T) + let lookup2 {.global.} = lookup # xxx improve pending https://github.com/timotheecour/Nim/issues/553 + #[ + This could be optimized using a hash adapted to `T` (possible since it's known at CT) + to get better key distribution before indexing into the lookup table table. + ]# + {.noSideEffect.}: # because it's immutable + let ret = lookup2[ord(a) - T.low.ord] + if ret != invalidSlot: return ret.int + else: + var i = 0 + # we could also generate a case statement as optimization + for ai in items(T): + if ai == a: return i + inc(i) + raise newException(IndexDefect, $ord(a) & " invalid for " & $T) + +template symbolRank*[T: enum](a: T): int = + ## Returns the index in which `a` is listed in `T`. + ## + ## The cost for a `HoleyEnum` is implementation defined, currently optimized + ## for small enums, otherwise is `O(T.enumLen)`. + runnableExamples: + type + A = enum a0 = -3, a1 = 10, a2, a3 = (20, "f3Alt") # HoleyEnum + B = enum b0, b1, b2 # OrdinalEnum + C = enum c0 = 10, c1, c2 # OrdinalEnum + assert a2.symbolRank == 2 + assert b2.symbolRank == 2 + assert c2.symbolRank == 2 + assert c2.ord == 12 + assert a2.ord == 11 + var invalid = 7.A + doAssertRaises(IndexDefect): discard invalid.symbolRank + when T is Ordinal: ord(a) - T.low.ord.static + else: symbolRankImpl(a) + +func symbolName*[T: enum](a: T): string = ## Returns the symbol name of an enum. + ## + ## This uses `symbolRank`. runnableExamples: type B = enum b0 = (10, "kb0") @@ -97,5 +156,7 @@ func symbolName*[T: OrdinalEnum](a: T): string = assert b.symbolName == "b0" assert $b == "kb0" static: assert B.high.symbolName == "b2" + type C = enum c0 = -3, c1 = 4, c2 = 20 # HoleyEnum + assert c1.symbolName == "c1" const names = enumNames(T) - names[a.ord - T.low.ord] + names[a.symbolRank] diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 1f49f60ed..1e222e3a2 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -31,9 +31,11 @@ add a way to customize serialization, for e.g.: ]# import macros +from enumutils import symbolName +from typetraits import OrdinalEnum type - Joptions* = object + Joptions* = object # xxx rename FromJsonOptions ## Options controlling the behavior of `fromJson`. allowExtraKeys*: bool ## If `true` Nim's object to which the JSON is parsed is not required to @@ -42,6 +44,17 @@ type ## If `true` Nim's object to which JSON is parsed is allowed to have ## fields without corresponding JSON keys. # in future work: a key rename could be added + EnumMode* = enum + joptEnumOrd + joptEnumSymbol + joptEnumString + ToJsonOptions* = object + enumMode*: EnumMode + # xxx charMode + +proc initToJsonOptions*(): ToJsonOptions = + ## initializes `ToJsonOptions` with sane options. + ToJsonOptions(enumMode: joptEnumOrd) proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} @@ -261,33 +274,41 @@ proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T = ## reverse of `toJson` fromJson(result, b, opt) -proc toJson*[T](a: T): JsonNode = +proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode = ## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to ## customize serialization, see strtabs.toJsonHook for an example. when compiles(toJsonHook(a)): result = toJsonHook(a) elif T is object | tuple: when T is object or isNamedTuple(T): result = newJObject() - for k, v in a.fieldPairs: result[k] = toJson(v) + for k, v in a.fieldPairs: result[k] = toJson(v, opt) else: result = newJArray() - for v in a.fields: result.add toJson(v) + for v in a.fields: result.add toJson(v, opt) elif T is ref | ptr: if system.`==`(a, nil): result = newJNull() - else: result = toJson(a[]) + else: result = toJson(a[], opt) elif T is array | seq | set: result = newJArray() - for ai in a: result.add toJson(ai) - elif T is pointer: result = toJson(cast[int](a)) + for ai in a: result.add toJson(ai, opt) + elif T is pointer: result = toJson(cast[int](a), opt) # edge case: `a == nil` could've also led to `newJNull()`, but this results # in simpler code for `toJson` and `fromJson`. - elif T is distinct: result = toJson(a.distinctBase) + elif T is distinct: result = toJson(a.distinctBase, opt) elif T is bool: result = %(a) elif T is SomeInteger: result = %a - elif T is Ordinal: result = %(a.ord) elif T is enum: - when defined(nimLegacyJsonutilsHoleyEnum): result = %a - else: result = %(a.ord) + case opt.enumMode + of joptEnumOrd: + when T is Ordinal or not defined(nimLegacyJsonutilsHoleyEnum): %(a.ord) + else: toJson($a, opt) + of joptEnumSymbol: + when T is OrdinalEnum: + toJson(symbolName(a), opt) + else: + toJson($a, opt) + of joptEnumString: toJson($a, opt) + elif T is Ordinal: result = %(a.ord) elif T is cstring: (if a == nil: result = newJNull() else: result = % $a) else: result = %a diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index c826a79b0..a55b0ca1d 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -35,6 +35,13 @@ type Foo = ref object proc `==`(a, b: Foo): bool = a.id == b.id +type MyEnum = enum me0, me1 = "me1Alt", me2, me3, me4 + +proc `$`(a: MyEnum): string = + # putting this here pending https://github.com/nim-lang/Nim/issues/13747 + if a == me2: "me2Modif" + else: system.`$`(a) + template fn() = block: # toJson, jsonTo type Foo = distinct float @@ -83,6 +90,12 @@ template fn() = doAssert b2.ord == 1 # explains the `1` testRoundtrip(a): """[1,2,3]""" + block: # ToJsonOptions + let a = (me1, me2) + doAssert $a.toJson() == "[1,2]" + doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumSymbol)) == """["me1","me2"]""" + doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumString)) == """["me1Alt","me2Modif"]""" + block: # set type Foo = enum f1, f2, f3, f4, f5 type Goo = enum g1 = 10, g2 = 15, g3 = 17, g4 From 31143c68fc7438406df39207b30594e775b4f97e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 18 May 2021 10:48:13 -0700 Subject: [PATCH 2607/4254] disable pkg/fidget refs https://github.com/treeform/fidget/issues/155 (#18043) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 1a61d3bbf..b84155eee 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -61,7 +61,7 @@ pkg "delaunay" pkg "docopt" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" -pkg "fidget" +pkg "fidget", allowFailure = true # pending https://github.com/treeform/fidget/issues/155 pkg "fragments", "nim c -r fragments/dsl.nim" pkg "fusion" pkg "gara" From 53935b8b27643215b677cc152f563a7fb7cb84fb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 18 May 2021 21:45:37 +0200 Subject: [PATCH 2608/4254] ARC: fixes memory leaks with newSeq used in a loop [backport:1.4] (#18040) * ARC: fixes memory leaks with newSeq used in a loop [backport:1.4] * Update tests/arc/tnewseq_legacy.nim --- compiler/ccgexprs.nim | 7 ++++++- lib/system/seqs_v2.nim | 4 ++++ tests/arc/tnewseq_legacy.nim | 13 +++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/arc/tnewseq_legacy.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b5ad24cc1..7cb403a94 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2319,7 +2319,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = gcUsage(p.config, e) else: genNewFinalize(p, e) - of mNewSeq: genNewSeq(p, e) + of mNewSeq: + if optSeqDestructors in p.config.globalOptions: + e[1] = makeAddr(e[1], p.module.idgen) + genCall(p, e, d) + else: + genNewSeq(p, e) of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: let t = e[1].typ.skipTypes({tyTypeDesc}) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index b7f24ecd5..375eef340 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -124,3 +124,7 @@ proc setLen[T](s: var seq[T], newlen: Natural) = if xu.p == nil or xu.p.cap < newlen: xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T))) xu.len = newlen + +proc newSeq[T](s: var seq[T], len: Natural) = + shrink(s, 0) + setLen(s, len) diff --git a/tests/arc/tnewseq_legacy.nim b/tests/arc/tnewseq_legacy.nim new file mode 100644 index 000000000..4730d2c2b --- /dev/null +++ b/tests/arc/tnewseq_legacy.nim @@ -0,0 +1,13 @@ +discard """ + output: "(allocCount: 201, deallocCount: 201)" + cmd: "nim c --gc:orc -d:nimAllocStats $file" +""" + +proc main(prefix: string) = + var c: seq[string] + for i in 0..<100: + newSeq(c, 100) + c[i] = prefix & $i + +main("abc") +echo getAllocStats() From 558644725ddcb72ae4e0b34ad5cfb1d38e2c5385 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 19 May 2021 16:00:14 +0200 Subject: [PATCH 2609/4254] fixes #17943 (#18045) * fixes #17943 * IC: test 'nim check --ic:on' for the full Nim compiler * Update testament/testament.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- compiler/ic/ic.nim | 3 +++ testament/categories.nim | 33 +++++++++++++++++++-------------- testament/testament.nim | 4 ++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 6530cb6c2..bd3be27f0 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -507,6 +507,9 @@ proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var Pac of nkStmtList, nkStmtListExpr: for it in n: toPackedNodeIgnoreProcDefs(it, encoder, m) + of nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, + nkFromStmt, nkIncludeStmt: + discard "nothing to do" else: toPackedNode(n, m.topLevel, encoder, m) diff --git a/testament/categories.nim b/testament/categories.nim index 1f0bd6acf..28ede1ba0 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -502,7 +502,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; isNavigatorTest: bool) = const - tooltests = ["compiler/nim.nim", "tools/nimgrep.nim"] + tooltests = ["compiler/nim.nim"] writeOnly = " --incremental:writeonly " readOnly = " --incremental:readonly " incrementalOn = " --incremental:on -d:nimIcIntegrityChecks " @@ -518,6 +518,24 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; test.spec.targets = {getTestSpecTarget()} testSpecWithNimcache(r, test, nimcache) + template checkTest() = + var test = makeRawTest(file, options, cat) + test.spec.cmd = compilerPrefix & " check --hint[Conf]:off --warnings:off --ic:on $options " & file + testSpecWithNimcache(r, test, nimcache) + + if not isNavigatorTest: + for file in tooltests: + let nimcache = nimcacheDir(file, options, getTestSpecTarget()) + removeDir(nimcache) + + let oldPassed = r.passed + checkTest() + + if r.passed == oldPassed+1: + checkTest() + if r.passed == oldPassed+2: + checkTest() + const tempExt = "_temp.nim" for it in walkDirRec(testsDir): if isTestFile(it) and not it.endsWith(tempExt): @@ -532,19 +550,6 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; editedTest(if isNavigatorTest: navTestConfig else: incrementalOn) if r.passed != oldPassed+1: break - if not isNavigatorTest and false: - for file in tooltests: - let nimcache = nimcacheDir(file, options, getTestSpecTarget()) - removeDir(nimcache) - - let oldPassed = r.passed - test writeOnly - - if r.passed == oldPassed+1: - test readOnly - if r.passed == oldPassed+2: - test readOnly - # ---------------------------------------------------------------------------- const AdditionalCategories = ["debugger", "examples", "lib", "ic", "navigator"] diff --git a/testament/testament.nim b/testament/testament.nim index 076123882..a8dc0557c 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -500,7 +500,7 @@ proc equalModuloLastNewline(a, b: string): bool = proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, target: TTarget, nimcache: string, extraOptions = "") = test.startTime = epochTime() - template callNimCompilerImpl(): untyped = + template callNimCompilerImpl(): untyped = # xxx this used to also pass: `--stdout --hint:Path:off`, but was done inconsistently # with other branches callNimCompiler(expected.getCmd, test.name, test.options, nimcache, target, extraOptions) @@ -649,9 +649,9 @@ proc makeRawTest(test, options: string, cat: Category): TTest {.used.} = result.name = test result.options = options result.spec = initSpec(addFileExt(test, ".nim")) - result.startTime = epochTime() result.spec.action = actionCompile result.spec.targets = {getTestSpecTarget()} + result.startTime = epochTime() # TODO: fix these files const disabledFilesDefault = @[ From 7052503ca8d360f11fabf476f7450dc3f794a602 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 19 May 2021 19:18:16 +0200 Subject: [PATCH 2610/4254] make strformat part of the prelude (#18046) --- changelog.md | 3 +++ lib/pure/prelude.nim | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 97e749337..f9c48e0bf 100644 --- a/changelog.md +++ b/changelog.md @@ -73,6 +73,9 @@ - `json` and `jsonutils` now serialize NaN, Inf, -Inf as strings, so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` which was invalid json. +- `strformat` is now part of `include std/prelude`. + + ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` diff --git a/lib/pure/prelude.nim b/lib/pure/prelude.nim index f1728b5f7..3c98d9d57 100644 --- a/lib/pure/prelude.nim +++ b/lib/pure/prelude.nim @@ -25,4 +25,4 @@ when defined(nimdoc) and isMainModule: # xxx `nim doc -b:js -d:nodejs --doccmd:-d:nodejs lib/pure/prelude.nim` fails for some reason # specific to `nim doc`, but the code otherwise works with nodejs. -import std/[os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt] +import std/[os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt, strformat] From a1c82c39af812b54cd3dd1e472c9088457fb7dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Wed, 19 May 2021 19:19:11 +0200 Subject: [PATCH 2611/4254] asyncdispatch+stackTraceOverride: fix premature collection (#18039) [backport:1.2] Copying StackTraceEntry instances when nimStackTraceOverride is defined breaks the link between a cstring field that's supposed to point at another string field in the same object. Sometimes, the original object is garbage collected, that memory region reused for storing other strings, so when the StackTraceEntry copy tries to use its cstring pointer to construct a traceback message, it accesses unrelated strings. This only happens for async tracebacks and this patch prevents that by making sure we only use the string fields when nimStackTraceOverride is defined. Async tracebacks also beautified slightly by getting rid of an extra line that was supposed to be commented out, along with the corresponding debugging output. There's also a micro-optimisation to avoid concatenating two strings just to get their combined length. --- changelog.md | 1 + lib/pure/asyncfutures.nim | 46 ++++++++++++++++++++++---------- lib/system/exceptions.nim | 2 +- tests/async/tasync_traceback.nim | 4 +-- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index f9c48e0bf..992cd89c0 100644 --- a/changelog.md +++ b/changelog.md @@ -316,6 +316,7 @@ - Added `copyWithin` [for `seq` and `array` for JavaScript targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin). +- Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place. ## Language changes diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 0178ee4d6..af3fbb3ec 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -278,19 +278,33 @@ proc `callback=`*[T](future: Future[T], ## If future has already completed then `cb` will be called immediately. future.callback = proc () = cb(future) +template getFilenameProcname(entry: StackTraceEntry): (string, string) = + when compiles(entry.filenameStr) and compiles(entry.procnameStr): + # We can't rely on "entry.filename" and "entry.procname" still being valid + # cstring pointers, because the "string.data" buffers they pointed to might + # be already garbage collected (this entry being a non-shallow copy, + # "entry.filename" no longer points to "entry.filenameStr.data", but to the + # buffer of the original object). + (entry.filenameStr, entry.procnameStr) + else: + ($entry.filename, $entry.procname) + proc getHint(entry: StackTraceEntry): string = ## We try to provide some hints about stack trace entries that the user ## may not be familiar with, in particular calls inside the stdlib. + + let (filename, procname) = getFilenameProcname(entry) + result = "" - if entry.procname == cstring"processPendingCallbacks": - if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: + if procname == "processPendingCallbacks": + if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0: return "Executes pending callbacks" - elif entry.procname == cstring"poll": - if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: + elif procname == "poll": + if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0: return "Processes asynchronous completion events" - if entry.procname.endsWith(NimAsyncContinueSuffix): - if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0: + if procname.endsWith(NimAsyncContinueSuffix): + if cmpIgnoreStyle(filename, "asyncmacro.nim") == 0: return "Resumes an async procedure" proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string = @@ -303,16 +317,20 @@ proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string = # Find longest filename & line number combo for alignment purposes. var longestLeft = 0 for entry in entries: - if entry.procname.isNil: continue + let (filename, procname) = getFilenameProcname(entry) - let left = $entry.filename & $entry.line - if left.len > longestLeft: - longestLeft = left.len + if procname == "": continue + + let leftLen = filename.len + len($entry.line) + if leftLen > longestLeft: + longestLeft = leftLen var indent = 2 # Format the entries. for entry in entries: - if entry.procname.isNil: + let (filename, procname) = getFilenameProcname(entry) + + if procname == "": if entry.line == reraisedFromBegin: result.add(spaces(indent) & "#[\n") indent.inc(2) @@ -321,11 +339,11 @@ proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string = result.add(spaces(indent) & "]#\n") continue - let left = "$#($#)" % [$entry.filename, $entry.line] + let left = "$#($#)" % [filename, $entry.line] result.add((spaces(indent) & "$#$# $#\n") % [ left, spaces(longestLeft - left.len + 2), - $entry.procname + procname ]) let hint = getHint(entry) if hint.len > 0: @@ -349,9 +367,9 @@ proc injectStacktrace[T](future: Future[T]) = newMsg.add($entries) newMsg.add("Exception message: " & exceptionMsg & "\n") - newMsg.add("Exception type:") # # For debugging purposes + # newMsg.add("Exception type:") # for entry in getStackTraceEntries(future.error): # newMsg.add "\n" & $entry future.error.msg = newMsg diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index b5f4fc325..5dcd77bd0 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -29,7 +29,7 @@ type programCounter*: uint ## Program counter - will be used to get the rest of the info, ## when `$` is called on this type. We can't use ## "cuintptr_t" in here. - procnameStr*, filenameStr*: string ## GC-ed objects holding the cstrings in "procname" and "filename" + procnameStr*, filenameStr*: string ## GC-ed alternatives to "procname" and "filename" Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ ## Base exception class. diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim index 9f787929b..cd16b2257 100644 --- a/tests/async/tasync_traceback.nim +++ b/tests/async/tasync_traceback.nim @@ -86,7 +86,7 @@ Async traceback: asyncfutures\.nim\(\d+?\)\s+?read \]# Exception message: b failure -Exception type: + bar failure Async traceback: @@ -114,7 +114,7 @@ Async traceback: asyncfutures\.nim\(\d+?\)\s+?read \]# Exception message: bar failure -Exception type: + """ # TODO: is asyncmacro good enough location for fooIter traceback/debugging? just put the callsite info for all? From df429fa28772e077faa30dd6e3a701abf48c7669 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 20 May 2021 11:52:46 +0200 Subject: [PATCH 2612/4254] config system: special case -d:release and -d:danger [backport:1.4] (#18051) --- changelog.md | 4 ++++ compiler/commands.nim | 19 +++++++++++++++---- compiler/main.nim | 3 ++- config/nim.cfg | 2 ++ tests/newconfig/tfoo.nim | 4 ++-- tests/newconfig/tfoo.nims | 2 ++ 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 992cd89c0..4c30d67a7 100644 --- a/changelog.md +++ b/changelog.md @@ -75,6 +75,10 @@ - `strformat` is now part of `include std/prelude`. +- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. + The downside is that these defines now have custom logic that doesn't apply for + other defines. + ## Standard library additions and changes - Added support for parenthesized expressions in `strformat` diff --git a/compiler/commands.nim b/compiler/commands.nim index b9c8e9eb3..605e2930c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -482,6 +482,19 @@ proc setCommandEarly*(conf: ConfigRef, command: string) = else: conf.foreignPackageNotes = foreignPackageNotesDefault +proc specialDefine(conf: ConfigRef, key: string) = + # Keep this syncronized with the default config/nim.cfg! + if cmpIgnoreStyle(key, "nimQuirky") == 0: + conf.exc = excQuirky + elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0: + conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize} + conf.globalOptions.excl {optExcessiveStackTrace, optCDebug} + conf.options.incl optOptimizeSpeed + if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0: + conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, + optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir} + conf.globalOptions.excl {optCDebug} + proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = var @@ -548,12 +561,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectArg(conf, switch, arg, pass, info) if {':', '='} in arg: splitSwitch(conf, arg, key, val, pass, info) - if cmpIgnoreStyle(key, "nimQuirky") == 0: - conf.exc = excQuirky + specialDefine(conf, key) defineSymbol(conf.symbols, key, val) else: - if cmpIgnoreStyle(arg, "nimQuirky") == 0: - conf.exc = excQuirky + specialDefine(conf, arg) defineSymbol(conf.symbols, arg) of "undef", "u": expectArg(conf, switch, arg, pass, info) diff --git a/compiler/main.nim b/compiler/main.nim index e2b5f4b67..71e549ab8 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -417,7 +417,8 @@ proc mainCommand*(graph: ModuleGraph) = "project", project, "output", output, ]) - rawMessage(conf, hintBuildMode, build) + if conf.cmd in cmdBackends: + rawMessage(conf, hintBuildMode, build) when PrintRopeCacheStats: echo "rope cache stats: " diff --git a/config/nim.cfg b/config/nim.cfg index d3ab75825..3b964d124 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -50,6 +50,7 @@ path="$lib/pure" @end nimblepath="$home/.nimble/pkgs/" +# Syncronize with compiler/commands.specialDefine @if danger or quick: obj_checks:off field_checks:off @@ -63,6 +64,7 @@ nimblepath="$home/.nimble/pkgs/" line_dir:off @end +# Syncronize with compiler/commands.specialDefine @if release or danger: stacktrace:off excessiveStackTrace:off diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim index 6654202c5..0c6ded470 100644 --- a/tests/newconfig/tfoo.nim +++ b/tests/newconfig/tfoo.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim default --hint:cc:off --hint:cc $file" - output: '''hello world! 0.5''' + output: '''hello world! 0.5 true''' nimout: '''[NimScript] exec: gcc -v''' """ @@ -10,4 +10,4 @@ when not defined(definedefine): import math, mfriends discard gen[int]() -echo "hello world! ", ln 2.0 +echo "hello world! ", ln 2.0, " ", compileOption("opt", "speed") diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index 6f0048afb..0cb950227 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -3,6 +3,8 @@ mode = ScriptMode.Whatif exec "gcc -v" +--define:release + --forceBuild --path: "../friends" From 6a5973882bb0c4134a0e454ea4ae69dc54815f27 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 20 May 2021 10:48:46 -0300 Subject: [PATCH 2613/4254] jsgen improve spacing (#18048) * Fix inconsistent spacings in generated JS of jsgen --- compiler/jsgen.nim | 60 ++++++++++++++++++++++---------------------- compiler/jstypes.nim | 4 +-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 53ce45e96..3b183b9d6 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -322,7 +322,7 @@ proc isSimpleExpr(p: PProc; n: PNode): bool = proc getTemp(p: PProc, defineInLocals: bool = true): Rope = inc(p.unique) - result = "Tmp$1" % [rope(p.unique)] + result = "Temporary$1" % [rope(p.unique)] if defineInLocals: p.locals.add(p.indentLine("var $1;$n" % [result])) @@ -489,12 +489,12 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop if optBoundsCheck in p.options: useMagic(p, "chckIndx") if first == 0: # save a couple chars - index.res = "chckIndx($1, 0, ($2).length-1)" % [index.res, tmp1] + index.res = "chckIndx($1, 0, ($2).length - 1)" % [index.res, tmp1] else: - index.res = "chckIndx($1, $2, ($3).length+($2)-1)-($2)" % [ + index.res = "chckIndx($1, $2, ($3).length + ($2) - 1) - ($2)" % [ index.res, rope(first), tmp1] elif first != 0: - index.res = "($1)-($2)" % [index.res, rope(first)] + index.res = "($1) - ($2)" % [index.res, rope(first)] else: discard # index.res = index.res let (n1, tmp2) = maybeMakeTemp(p, n[1], index) @@ -607,12 +607,12 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = if n[1].typ.size <= 4: applyFormat("($1 << $2)", "($1 << $2)") else: - applyFormat("($1 * Math.pow(2,$2))", "($1 * Math.pow(2,$2))") + applyFormat("($1 * Math.pow(2, $2))", "($1 * Math.pow(2, $2))") of mAshrI: if n[1].typ.size <= 4: applyFormat("($1 >> $2)", "($1 >> $2)") else: - applyFormat("Math.floor($1 / Math.pow(2,$2))", "Math.floor($1 / Math.pow(2,$2))") + applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))") of mBitandI: applyFormat("($1 & $2)", "($1 & $2)") of mBitorI: applyFormat("($1 | $2)", "($1 | $2)") of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)") @@ -656,8 +656,8 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mUnaryMinusF64: applyFormat("-($1)", "-($1)") of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)") of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)") - of mIntToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")") - of mInt64ToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")") + of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") + of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") of mFloatToStr: useMagic(p, "nimFloatToString") applyFormat "cstrToNimstr(nimFloatToString($1))" @@ -704,7 +704,7 @@ proc hasFrameInfo(p: PProc): bool = ((p.prc == nil) or not (sfPure in p.prc.flags)) proc lineDir(config: ConfigRef, info: TLineInfo, line: int): Rope = - ropes.`%`("// line $2 \"$1\"$n", + ropes.`%`("/* line $2 \"$1\" */$n", [rope(toFullPath(config, info)), rope(line)]) proc genLineDir(p: PProc, n: PNode) = @@ -725,9 +725,9 @@ proc genWhileStmt(p: PProc, n: PNode) = p.blocks[^1].id = -p.unique p.blocks[^1].isLoop = true let labl = p.unique.rope - lineF(p, "L$1: while (true) {$n", [labl]) + lineF(p, "Label$1: while (true) {$n", [labl]) p.nested: gen(p, n[0], cond) - lineF(p, "if (!$1) break L$2;$n", + lineF(p, "if (!$1) break Label$2;$n", [cond.res, labl]) p.nested: genStmt(p, n[1]) lineF(p, "}$n", [labl]) @@ -750,8 +750,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = # try { # stmts; # --excHandler; - # } catch (EXC) { - # var prevJSError = lastJSError; lastJSError = EXC; + # } catch (EXCEPTION) { + # var prevJSError = lastJSError; lastJSError = EXCEPTION; # framePtr = tmpFramePtr; # --excHandler; # if (e.typ && e.typ == NTI433 || e.typ == NTI2321) { @@ -785,8 +785,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = moveInto(p, a, r) var generalCatchBranchExists = false if catchBranchesExist: - p.body.addf("--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" & - " lastJSError = EXC;$n --excHandler;$n", []) + p.body.addf("--excHandler;$n} catch (EXCEPTION) {$n var prevJSError = lastJSError;$n" & + " lastJSError = EXCEPTION;$n --excHandler;$n", []) line(p, "framePtr = $1;$n" % [tmpFramePtr]) while i < n.len and n[i].kind == nkExceptBranch: if n[i].len == 1: @@ -928,12 +928,12 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) = sym.loc.k = locOther sym.position = idx+1 let labl = p.unique - lineF(p, "L$1: do {$n", [labl.rope]) + lineF(p, "Label$1: do {$n", [labl.rope]) setLen(p.blocks, idx + 1) p.blocks[idx].id = - p.unique # negative because it isn't used yet gen(p, n[1], r) setLen(p.blocks, idx) - lineF(p, "} while(false);$n", [labl.rope]) + lineF(p, "} while (false);$n", [labl.rope]) proc genBreakStmt(p: PProc, n: PNode) = var idx: int @@ -951,7 +951,7 @@ proc genBreakStmt(p: PProc, n: PNode) = if idx < 0 or not p.blocks[idx].isLoop: internalError(p.config, n.info, "no loop to break") p.blocks[idx].id = abs(p.blocks[idx].id) # label is used - lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)]) + lineF(p, "break Label$1;$n", [rope(p.blocks[idx].id)]) proc genAsmOrEmitStmt(p: PProc, n: PNode) = genLineDir(p, n) @@ -1248,12 +1248,12 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = if optBoundsCheck in p.options: useMagic(p, "chckIndx") if first == 0: # save a couple chars - r.res = "chckIndx($1, 0, ($2).length-1)" % [b.res, tmp] + r.res = "chckIndx($1, 0, ($2).length - 1)" % [b.res, tmp] else: - r.res = "chckIndx($1, $2, ($3).length+($2)-1)-($2)" % [ + r.res = "chckIndx($1, $2, ($3).length + ($2) - 1) - ($2)" % [ b.res, rope(first), tmp] elif first != 0: - r.res = "($1)-($2)" % [b.res, rope(first)] + r.res = "($1) - ($2)" % [b.res, rope(first)] else: r.res = b.res r.kind = resExpr @@ -1876,13 +1876,13 @@ proc genNewSeq(p: PProc, n: PNode) = gen(p, n[1], x) gen(p, n[2], y) let t = skipTypes(n[1].typ, abstractVar)[0] - lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [ + lineF(p, "$1 = new Array($2); for (var i = 0 ; i < $2 ; ++i) { $1[i] = $3; }", [ x.rdLoc, y.rdLoc, createVar(p, t, false)]) proc genOrd(p: PProc, n: PNode, r: var TCompRes) = case skipTypes(n[1].typ, abstractVar + abstractRange).kind of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r) - of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)") + of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)") else: internalError(p.config, n.info, "genOrd") proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = @@ -2122,7 +2122,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = let t = skipTypes(n[1].typ, abstractVar)[0] let (a, tmp) = maybeMakeTemp(p, n[1], x) let (b, tmp2) = maybeMakeTemp(p, n[2], y) - r.res = """if ($1.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); } + r.res = """if ($1.length < $2) { for (var i = $4.length ; i < $5 ; ++i) $4.push($3); } else { $4.length = $5; }""" % [a, b, createVar(p, t, false), tmp, tmp2] r.kind = resExpr of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)") @@ -2159,7 +2159,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[1], x) gen(p, n[2], y) gen(p, n[3], z) - r.res = "($1.slice($2, $3+1))" % [x.rdLoc, y.rdLoc, z.rdLoc] + r.res = "($1.slice($2, $3 + 1))" % [x.rdLoc, y.rdLoc, z.rdLoc] r.kind = resExpr of mMove: genMove(p, n, r) @@ -2281,7 +2281,7 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) = r.res = "(!!($1))" % [r.res] r.kind = resExpr elif toInt: - r.res = "(($1)|0)" % [r.res] + r.res = "(($1) | 0)" % [r.res] else: # TODO: What types must we handle here? discard @@ -2337,7 +2337,7 @@ proc genReturnStmt(p: PProc, n: PNode) = proc frameCreate(p: PProc; procname, filename: Rope): Rope = const frameFmt = - "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" + "var F = {procname: $1, prev: framePtr, filename: $2, line: 0};$n" result = p.indentLine(frameFmt % [procname, filename]) result.add p.indentLine(ropes.`%`("framePtr = F;$n", [])) @@ -2431,10 +2431,10 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = # references will end up calling the reloaded code. var thunkName = name name = name & "IMLP" - result.add("function $#() { return $#.apply(this, arguments); }$n" % + result.add("\Lfunction $#() { return $#.apply(this, arguments); }$n" % [thunkName, name]) - def = "function $#($#) {$n$#$#$#$#$#" % + def = "\Lfunction $#($#) {$n$#$#$#$#$#" % [ name, header, optionalLine(p.globals), @@ -2482,7 +2482,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = elif fromUint: if src.size == 4 and dest.size == 4: # XXX prevent multi evaluations - r.res = "($1|0)" % [r.res] + r.res = "($1 | 0)" % [r.res] else: let trimmer = unsignedTrimmer(dest.size) let minuend = case dest.size diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 81f03dc12..5b684b60c 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -135,14 +135,14 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = prepend(p.g.typeInfo, s) of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet: var s = - "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % + "var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" % [result, rope(ord(t.kind))] prepend(p.g.typeInfo, s) p.g.typeInfo.addf("$1.base = $2;$n", [result, genTypeInfo(p, t.lastSon)]) of tyArray: var s = - "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % + "var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" % [result, rope(ord(t.kind))] prepend(p.g.typeInfo, s) p.g.typeInfo.addf("$1.base = $2;$n", From 9f7e2e30573a377770fa630f12a47bac09751282 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Fri, 21 May 2021 07:54:20 +0300 Subject: [PATCH 2614/4254] docs: make inline markup more compatible with Markdown (#18053) fixes https://github.com/timotheecour/Nim/issues/739 --- doc/regexprs.txt | 2 +- lib/impure/db_sqlite.nim | 2 +- lib/packages/docutils/rst.nim | 147 ++++++++++++++++++++++------------ lib/posix/posix_utils.nim | 2 +- tests/stdlib/trst.nim | 65 +++++++++++++-- tests/stdlib/trstgen.nim | 12 +-- 6 files changed, 168 insertions(+), 62 deletions(-) diff --git a/doc/regexprs.txt b/doc/regexprs.txt index b7370d858..9ec08b810 100644 --- a/doc/regexprs.txt +++ b/doc/regexprs.txt @@ -146,7 +146,7 @@ character meaning After ``\x``, from zero to two hexadecimal digits are read (letters can be in upper or lower case). In UTF-8 mode, any number of hexadecimal digits may appear between ``\x{`` and ``}``, but the value of the character code must be -less than 2**31 (that is, the maximum hexadecimal value is 7FFFFFFF). If +less than 2^31 (that is, the maximum hexadecimal value is 7FFFFFFF). If characters other than hexadecimal digits appear between ``\x{`` and ``}``, or if there is no terminating ``}``, this form of escape is not recognized. Instead, the initial ``\x`` will be interpreted as a basic hexadecimal escape, diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 832407960..7bd807a12 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -152,7 +152,7 @@ ## Instead, a `seq[string]` is returned for each row. ## ## The reasoning is as follows: -## 1. it's close to what many DBs offer natively (char**) +## 1. it's close to what many DBs offer natively (`char**`:c:) ## 2. it hides the number of types that the DB supports ## (int? int64? decimal up to 10 places? geo coords?) ## 3. it's convenient when all you do is to forward the data to somewhere else (echo, log, put the data into a new query) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index da04e9b54..dae692fb7 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -130,6 +130,32 @@ ## .. warning:: Using Nim-specific features can cause other RST implementations ## to fail on your document. ## +## Idiosyncrasies +## -------------- +## +## Currently we do **not** aim at 100% Markdown or RST compatibility in inline +## markup recognition rules because that would provide very little user value. +## This parser has 2 modes for inline markup: +## +## 1) Markdown-like mode which is enabled by `roPreferMarkdown` option +## (turned **on** by default). +## +## .. Note:: RST features like directives are still turned **on** +## +## 2) Compatibility mode which is RST rules. +## +## .. Note:: in both modes the parser interpretes text between single +## backticks (code) identically: +## backslash does not escape; the only exception: ``\`` folowed by ` +## does escape so that we can always input a single backtick ` in +## inline code. However that makes impossible to input code with +## ``\`` at the end in *single* backticks, one must use *double* +## backticks:: +## +## `\` -- WRONG +## ``\`` -- GOOD +## So single backticks can always be input: `\`` will turn to ` code +## ## Limitations ## ----------- ## @@ -994,8 +1020,22 @@ proc expect(p: var RstParser, tok: string) = if currentTok(p).symbol == tok: inc p.idx else: rstMessage(p, meExpected, tok) -proc isInlineMarkupEnd(p: RstParser, markup: string, exact: bool): bool = +proc inlineMarkdownEnd(p: RstParser): bool = + result = prevTok(p).kind notin {tkIndent, tkWhite} + ## (For a special case of ` we don't allow spaces surrounding it + ## unlike original Markdown because this behavior confusing/useless) + +proc inlineRstEnd(p: RstParser): bool = # rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules + # Rule 2: + result = prevTok(p).kind notin {tkIndent, tkWhite} + if not result: return + # Rule 7: + result = nextTok(p).kind in {tkIndent, tkWhite, tkEof} or + nextTok(p).symbol[0] in + {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', '?', '_'} + +proc isInlineMarkupEnd(p: RstParser, markup: string, exact: bool): bool = if exact: result = currentTok(p).symbol == markup else: @@ -1004,55 +1044,58 @@ proc isInlineMarkupEnd(p: RstParser, markup: string, exact: bool): bool = # check that escaping may have splitted `` to 2 tokens ` and ` result = currentTok(p).symbol == "`" and prevTok(p).symbol == "`" if not result: return - # Rule 2: - result = prevTok(p).kind notin {tkIndent, tkWhite} - if not result: return - # Rule 7: - result = nextTok(p).kind in {tkIndent, tkWhite, tkEof} or - (roPreferMarkdown in p.s.options and - markup in ["``", "`"] and - nextTok(p).kind in {tkIndent, tkWhite, tkWord, tkEof}) or - nextTok(p).symbol[0] in - {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', '?', '_'} - if not result: return - # Rule 4: - if p.idx > 0: - # see bug #17260; for now `\` must be written ``\``, likewise with sequences - # ending in an un-escaped `\`; `\\` is legal but not `\\\` for example; - # for this reason we can't use `["``", "`"]` here. - if markup != "``" and prevTok(p).symbol == "\\": - result = false + # surroundings check + if markup in ["_", "__"]: + result = inlineRstEnd(p) + else: + if roPreferMarkdown in p.s.options: result = inlineMarkdownEnd(p) + else: result = inlineRstEnd(p) -proc isInlineMarkupStart(p: RstParser, markup: string): bool = - # rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules - var d: char - if markup != "_`": - result = currentTok(p).symbol == markup - else: # _` is a 2 token case - result = currentTok(p).symbol == "_" and nextTok(p).symbol == "`" +proc rstRuleSurround(p: RstParser): bool = + result = true + # Rules 4 & 5: + if p.idx > 0: + var d: char + var c = prevTok(p).symbol[0] + case c + of '\'', '\"': d = c + of '(': d = ')' + of '[': d = ']' + of '{': d = '}' + of '<': d = '>' + else: d = '\0' + if d != '\0': result = nextTok(p).symbol[0] != d + +proc inlineMarkdownStart(p: RstParser): bool = + result = nextTok(p).kind notin {tkIndent, tkWhite, tkEof} if not result: return - # Rule 6: + # this rst rule is really nice, let us use it in Markdown mode too. + result = rstRuleSurround(p) + +proc inlineRstStart(p: RstParser): bool = + ## rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules + # Rule 6 result = p.idx == 0 or prevTok(p).kind in {tkIndent, tkWhite} or - (markup in ["``", "`"] and prevTok(p).kind in {tkIndent, tkWhite, tkWord}) or prevTok(p).symbol[0] in {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'} if not result: return # Rule 1: result = nextTok(p).kind notin {tkIndent, tkWhite, tkEof} if not result: return - # Rules 4 & 5: - if p.idx > 0: - if prevTok(p).symbol == "\\": - result = false - else: - var c = prevTok(p).symbol[0] - case c - of '\'', '\"': d = c - of '(': d = ')' - of '[': d = ']' - of '{': d = '}' - of '<': d = '>' - else: d = '\0' - if d != '\0': result = nextTok(p).symbol[0] != d + result = rstRuleSurround(p) + +proc isInlineMarkupStart(p: RstParser, markup: string): bool = + if markup != "_`": + result = currentTok(p).symbol == markup + else: # _` is a 2 token case + result = currentTok(p).symbol == "_" and nextTok(p).symbol == "`" + if not result: return + # surroundings check + if markup in ["_", "__", "[", "|"]: + # Note: we require space/punctuation even before [markdown link](...) + result = inlineRstStart(p) + else: + if roPreferMarkdown in p.s.options: result = inlineMarkdownStart(p) + else: result = inlineRstStart(p) proc match(p: RstParser, start: int, expr: string): bool = # regular expressions are: @@ -1263,10 +1306,7 @@ proc parseWordOrRef(p: var RstParser, father: PRstNode) = proc parseBackslash(p: var RstParser, father: PRstNode) = assert(currentTok(p).kind == tkPunct) - if currentTok(p).symbol == "\\\\": - father.add newLeaf("\\") - inc p.idx - elif currentTok(p).symbol == "\\": + if currentTok(p).symbol == "\\": # XXX: Unicode? inc p.idx if currentTok(p).kind != tkWhite: father.add(newLeaf(p)) @@ -1297,11 +1337,20 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, break else: if postfix == "`": - if prevTok(p).symbol == "\\" and currentTok(p).symbol == "`": - father.sons[^1] = newLeaf(p) # instead, we should use lookahead + if currentTok(p).symbol == "\\": + if nextTok(p).symbol == "\\": + father.add newLeaf("\\") + father.add newLeaf("\\") + inc p.idx, 2 + elif nextTok(p).symbol == "`": # escape ` + father.add newLeaf("`") + inc p.idx, 2 + else: + father.add newLeaf("\\") + inc p.idx else: father.add(newLeaf(p)) - inc p.idx + inc p.idx else: if interpretBackslash: parseBackslash(p, father) diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index aeec73a45..c2d5aab56 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -7,7 +7,7 @@ # ## A set of helpers for the POSIX module. -## Raw interfaces are in the other posix*.nim files. +## Raw interfaces are in the other ``posix*.nim`` files. # Where possible, contribute OS-independent procs in `os `_ instead. diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 71f5a858b..ec34edc91 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -23,7 +23,7 @@ import std/private/miscdollars import os proc toAst(input: string, - rstOptions: RstParseOptions = {roSupportMarkdown, roNimFile}, + rstOptions: RstParseOptions = {roPreferMarkdown, roSupportMarkdown, roNimFile}, error: ref string = nil, warnings: ref seq[string] = nil): string = ## If `error` is nil then no errors should be generated. @@ -36,10 +36,11 @@ proc toAst(input: string, toLocation(message, filename, line, col + ColRstOffset) message.add " $1: $2" % [$mc, a] if mc == mcError: - doAssert error != nil, "unexpected RST error '" & message & "'" + if error == nil: + raise newException(EParseError, "[unexpected error] " & message) error[] = message # we check only first error because subsequent ones may be meaningless - raise newException(EParseError, message) + raise newException(EParseError, "") else: doAssert warnings != nil, "unexpected RST warning '" & message & "'" warnings[].add message @@ -54,8 +55,9 @@ proc toAst(input: string, var rst = rstParse(input, filen, line=LineRstInit, column=ColRstInit, dummyHasToc, rstOptions, myFindFile, testMsgHandler) result = renderRstToStr(rst) - except EParseError: - discard + except EParseError as e: + if e.msg != "": + result = e.msg suite "RST parsing": test "option list has priority over definition list": @@ -326,6 +328,28 @@ suite "RST escaping": """) suite "RST inline markup": + test "* and ** surrounded by spaces are not inline markup": + check("a * b * c ** d ** e".toAst == dedent""" + rnInner + rnLeaf 'a' + rnLeaf ' ' + rnLeaf '*' + rnLeaf ' ' + rnLeaf 'b' + rnLeaf ' ' + rnLeaf '*' + rnLeaf ' ' + rnLeaf 'c' + rnLeaf ' ' + rnLeaf '**' + rnLeaf ' ' + rnLeaf 'd' + rnLeaf ' ' + rnLeaf '**' + rnLeaf ' ' + rnLeaf 'e' + """) + test "end-string has repeating symbols": check("*emphasis content****".toAst == dedent""" rnEmphasis @@ -420,6 +444,37 @@ suite "RST inline markup": rnLeaf 'proc `+`' """) + check("""`\\`""".toAst == + dedent""" + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf '\\' + """) + + test "Markdown-style code/backtick": + # no whitespace is required before ` + check("`try`...`except`".toAst == + dedent""" + rnInner + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf 'try' + rnLeaf '...' + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf 'except' + """) + + test """inline literals can contain \ anywhere""": check("""``\``""".toAst == dedent""" rnInlineLiteral diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 667fec780..864728686 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -10,7 +10,7 @@ import unittest, strutils, strtabs import std/private/miscdollars proc toHtml(input: string, - rstOptions: RstParseOptions = {roSupportMarkdown, roNimFile}, + rstOptions: RstParseOptions = {roPreferMarkdown, roSupportMarkdown, roNimFile}, error: ref string = nil, warnings: ref seq[string] = nil): string = ## If `error` is nil then no errors should be generated. @@ -23,18 +23,20 @@ proc toHtml(input: string, toLocation(message, filename, line, col + ColRstOffset) message.add " $1: $2" % [$mc, a] if mc == mcError: - doAssert error != nil, "unexpected RST error '" & message & "'" + if error == nil: + raise newException(EParseError, "[unexpected error] " & message) error[] = message # we check only first error because subsequent ones may be meaningless - raise newException(EParseError, message) + raise newException(EParseError, "") else: doAssert warnings != nil, "unexpected RST warning '" & message & "'" warnings[].add message try: result = rstToHtml(input, rstOptions, defaultConfig(), msgHandler=testMsgHandler) - except EParseError: - discard + except EParseError as e: + if e.msg != "": + result = e.msg # inline code tags (for parsing originated from highlite.nim) proc id(str: string): string = """""" & str & "" From e12597589f2a8cdaabe09e8b2b92ff0fbe3727ef Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 22 May 2021 08:12:30 -0300 Subject: [PATCH 2615/4254] Error message minor (#18021) * Update compiler/semtypes.nim Co-authored-by: Timothee Cour Co-authored-by: flywind Co-authored-by: Andreas Rumpf --- compiler/lineinfos.nim | 2 +- compiler/semtypes.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 47cddb888..bf81aed02 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -110,7 +110,7 @@ const warnFieldXNotSupported: "field '$1' not supported", warnRstStyle: "RST style: $1", warnCommentXIgnored: "comment '$1' ignored", - warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", + warnTypelessParam: "", # deadcode warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", warnWriteToForeignHeap: "write to foreign heap", warnUnsafeCode: "unsafe code: '$1'", diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 97e37f8b7..84556ca1a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1297,7 +1297,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, let param = strTableGet(c.signatures, arg.name) if param != nil: typ = param.typ else: - localError(c.config, a.info, "typeless parameters are obsolete") + localError(c.config, a.info, "parameter '$1' requires a type" % param.name.s) typ = errorType(c) let lifted = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info) From 1636c05d138a7a52c5b6cb3cafe6ab84f59f086b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 23 May 2021 01:02:04 -0700 Subject: [PATCH 2616/4254] close #5540 generic object with generic field evaluated too early (#18062) --- tests/misc/t5540.nim | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/misc/t5540.nim diff --git a/tests/misc/t5540.nim b/tests/misc/t5540.nim new file mode 100644 index 000000000..6a19e70e1 --- /dev/null +++ b/tests/misc/t5540.nim @@ -0,0 +1,45 @@ +# bug #5540; works in 1.2.0 +# fails in 1.0 (Error: cannot generate VM code for) +# fails in 0.18.0 (Error: type mismatch: got ) + +block: + type + Fruit = object + Yellow = object + a: int + template getColor(x: typedesc[Fruit]): typedesc = Yellow + type + Banana[T] = object + b: T + a: getColor(Fruit) + Apple[T] = object + a: T + b: getColor(T) + block: + var x: Banana[int] + doAssert x.b == 0 + doAssert x.a is Yellow + block: + var x: Apple[Fruit] + doAssert x.b is Yellow + +block: + type + Fruit = object + Yellow = object + a: int + + template getColor(x: typedesc[Fruit]): typedesc = Yellow + + type + Banana[T] = object + b: T + a: getColor(Fruit) + + Apple[T] = object + a: T + b: getColor(T) + + var x: Banana[int] + x.b = 13 + x.a.a = 17 From 61630c6aee56acf688c48c00f5a6711a59e79616 Mon Sep 17 00:00:00 2001 From: Euan Date: Sun, 23 May 2021 17:23:20 +0100 Subject: [PATCH 2617/4254] Use gmake for NetBSD as well as FreeBSD/OpenBSD (#18064) --- ci/funs.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/funs.sh b/ci/funs.sh index cad005246..0e4f0eb3b 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -55,6 +55,8 @@ _nimBuildCsourcesIfNeeded(){ makeX=gmake elif [ "$unamestr" = 'OpenBSD' ]; then makeX=gmake + elif [ "$unamestr" = 'NetBSD' ]; then + makeX=gmake else makeX=make fi From 1421a3bf265e45cea7c26dcaf3be148ea02db5f0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 23 May 2021 12:28:26 -0700 Subject: [PATCH 2618/4254] pkg/pixie: use latest (#18069) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index b84155eee..975dd63ad 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -118,7 +118,7 @@ pkg "optionsutils" pkg "ormin", "nim c -o:orminn ormin.nim" pkg "parsetoml" pkg "patty" -pkg "pixie", useHead = false +pkg "pixie" pkg "plotly", "nim c examples/all.nim" pkg "pnm" pkg "polypbren" From d217888e5679aff063668930bd00892c4f5cb2b3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 23 May 2021 14:06:14 -0700 Subject: [PATCH 2619/4254] close #18009 parseJson JInt vs JFloat; preserve -0.0 as JFloat to distinguish from 0.0 (#18067) --- lib/pure/json.nim | 2 +- tests/stdlib/tjsonutils.nim | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 3a9fa5898..d5bbb86b8 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -938,7 +938,7 @@ when defined(js): of "[object Array]": return JArray of "[object Object]": return JObject of "[object Number]": - if isInteger(x): + if isInteger(x) and 1.0 / cast[float](x) != -Inf: # preserve -0.0 as float if isSafeInteger(x): return JInt else: diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index a55b0ca1d..62486b896 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -4,7 +4,8 @@ discard """ import std/jsonutils import std/json -from std/math import isNaN +from std/math import isNaN, signbit +from stdtest/testutils import whenRuntimeJs proc testRoundtrip[T](t: T, expected: string) = # checks that `T => json => T2 => json2` is such that json2 = json @@ -123,6 +124,20 @@ template fn() = testRoundtripVal((Inf, -Inf, 0.0, -0.0, 1.0)): """["inf","-inf",0.0,-0.0,1.0]""" doAssert ($NaN.toJson).parseJson.jsonTo(float).isNaN + block: # bug #18009; unfixable unless we change parseJson (which would have overhead), + # but at least we can guarantee that the distinction between 0.0 and -0.0 is preserved. + let a = (0, 0.0, -0.0, 0.5, 1, 1.0) + testRoundtripVal(a): "[0,0.0,-0.0,0.5,1,1.0]" + let a2 = $($a.toJson).parseJson + whenRuntimeJs: + doAssert a2 == "[0,0,-0.0,0.5,1,1]" + do: + doAssert a2 == "[0,0.0,-0.0,0.5,1,1.0]" + let b = a2.parseJson.jsonTo(type(a)) + doAssert not b[1].signbit + doAssert b[2].signbit + doAssert not b[3].signbit + block: # case object type Foo = object x0: float From 478f717377c4cd60cfce112b8b21d58031b118b4 Mon Sep 17 00:00:00 2001 From: xioren <40043405+xioren@users.noreply.github.com> Date: Mon, 24 May 2021 20:56:31 -0700 Subject: [PATCH 2620/4254] Move async example to asynchronous version of proc (#18078) * improve runnableExamples in std/httpclient * Add synchronous example. * Update lib/pure/httpclient.nim Co-authored-by: Timothee Cour --- lib/pure/httpclient.nim | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 86708dc40..0dbf8a045 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -574,15 +574,11 @@ proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, ## ## `headers` specifies the HTTP Headers. runnableExamples: - import std/[asyncdispatch, httpclient, strutils] + import std/strutils - proc asyncProc(): Future[string] {.async.} = - var client = newAsyncHttpClient() - return await client.getContent("http://example.com") - - let exampleHtml = waitFor asyncProc() + let exampleHtml = newHttpClient().getContent("http://example.com") assert "Example Domain" in exampleHtml - assert not ("Pizza" in exampleHtml) + assert "Pizza" notin exampleHtml new result result.headers = headers @@ -616,6 +612,17 @@ proc newAsyncHttpClient*(userAgent = defUserAgent, maxRedirects = 5, ## connections. ## ## `headers` specifies the HTTP Headers. + runnableExamples: + import std/[asyncdispatch, strutils] + + proc asyncProc(): Future[string] {.async.} = + let client = newAsyncHttpClient() + result = await client.getContent("http://example.com") + + let exampleHtml = waitFor asyncProc() + assert "Example Domain" in exampleHtml + assert "Pizza" notin exampleHtml + new result result.headers = headers result.userAgent = userAgent From b59dc3b255d778cefdbef2c0c3ff55d43892c11c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 00:41:50 -0700 Subject: [PATCH 2621/4254] remove some custom logic in testament around flags, testExec (#18090) * remove some custom logic in testament around flags, testExec * remove testExec, custom logic around flags from testament * fixup --- testament/categories.nim | 23 ----------------------- testament/testament.nim | 16 ---------------- tests/flags/tgenscript.nim | 6 ------ tests/misc/trunner.nim | 33 ++++++++++++++++++++++++++++++--- 4 files changed, 30 insertions(+), 48 deletions(-) delete mode 100644 tests/flags/tgenscript.nim diff --git a/testament/categories.nim b/testament/categories.nim index 28ede1ba0..510e90c53 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -23,7 +23,6 @@ const "debugger", "dll", "examples", - "flags", "gc", "io", "js", @@ -48,26 +47,6 @@ proc isTestFile*(file: string): bool = let (_, name, ext) = splitFile(file) result = ext == ".nim" and name.startsWith("t") -# --------------------- flags tests ------------------------------------------- - -proc flagTests(r: var TResults, cat: Category, options: string) = - # --genscript - const filename = testsDir/"flags"/"tgenscript" - const genopts = " --genscript" - let nimcache = nimcacheDir(filename, genopts, targetC) - testSpec r, makeTest(filename, genopts, cat) - - when defined(windows): - testExec r, makeTest(filename, " cmd /c cd " & nimcache & - " && compile_tgenscript.bat", cat) - - elif defined(posix): - testExec r, makeTest(filename, " sh -c \"cd " & nimcache & - " && sh compile_tgenscript.sh\"", cat) - - # Run - testExec r, makeTest(filename, " " & nimcache / "tgenscript", cat) - # --------------------- DLL generation tests ---------------------------------- proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = @@ -705,8 +684,6 @@ proc processCategory(r: var TResults, cat: Category, jsTests(r, cat, options) of "dll": dllTests(r, cat, options) - of "flags": - flagTests(r, cat, options) of "gc": gcTests(r, cat, options) of "longgc": diff --git a/testament/testament.nim b/testament/testament.nim index a8dc0557c..2edefdb01 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -621,22 +621,6 @@ proc testC(r: var TResults, test: TTest, action: TTestAction) = if exitCode != 0: given.err = reExitcodesDiffer if given.err == reSuccess: inc(r.passed) -proc testExec(r: var TResults, test: TTest) = - # runs executable or script, just goes by exit code - if not checkDisabled(r, test): return - - inc(r.total) - let (outp, errC) = execCmdEx(test.options.strip()) - var given: TSpec - if errC == 0: - given.err = reSuccess - else: - given.err = reExitcodesDiffer - given.msg = outp - - if given.err == reSuccess: inc(r.passed) - r.addResult(test, targetC, "", given.msg, given.err) - proc makeTest(test, options: string, cat: Category): TTest = result.cat = cat result.name = test diff --git a/tests/flags/tgenscript.nim b/tests/flags/tgenscript.nim deleted file mode 100644 index d58395a40..000000000 --- a/tests/flags/tgenscript.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ - targets: "c" - action: compile -""" - -echo "--genscript" diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 1b679d92c..3297b3a24 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -33,16 +33,23 @@ const proc runNimCmd(file, options = "", rtarg = ""): auto = let fileabs = testsDir / file.unixToNativePath - doAssert fileabs.fileExists, fileabs + # doAssert fileabs.fileExists, fileabs # disabled because this allows passing `nim r --eval:code fakefile` let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs} {rtarg}" result = execCmdEx(cmd) - when false: echo result[0] & "\n" & result[1] # for debugging + when false: # for debugging + echo cmd + echo result[0] & "\n" & $result[1] proc runNimCmdChk(file, options = "", rtarg = ""): string = let (ret, status) = runNimCmd(file, options, rtarg = rtarg) doAssert status == 0, $(file, options) & "\n" & ret ret +proc genShellCmd(filename: string): string = + let filename = filename.quoteShell + when defined(windows): "cmd /c " & filename # or "cmd /c " ? + else: "sh " & filename + when defined(nimTrunnerFfi): block: # mevalffi when defined(openbsd): @@ -71,7 +78,9 @@ foo:0.03:asdf:103:105 ret=[s1:foobar s2:foobar age:25 pi:3.14] """, output -else: # don't run twice the same test +elif not defined(nimTestsTrunnerDebugging): + # don't run twice the same test with `nimTrunnerFfi` + # use `-d:nimTestsTrunnerDebugging` for debugging convenience when you want to just run 1 test import std/strutils import std/json template check2(msg) = doAssert msg in output, output @@ -330,3 +339,21 @@ running: v2 doAssert "D20210428T161003" in j["defined_symbols"].to(seq[string]) doAssert j["version"].to(string) == NimVersion doAssert j["nimExe"].to(string) == getCurrentCompilerExe() + + block: # genscript + const nimcache2 = buildDir / "D20210524T212851" + removeDir(nimcache2) + let input = "tgenscript_fakefile" # no need for a real file, --eval is good enough + let output = runNimCmdChk(input, fmt"""--genscript --nimcache:{nimcache2.quoteShell} --eval:"echo(12345)" """) + doAssert output.len == 0, output + let ext = when defined(windows): ".bat" else: ".sh" + let filename = fmt"compile_{input}{ext}" # synchronize with `generateScript` + doAssert fileExists(nimcache2/filename), nimcache2/filename + let (outp, status) = execCmdEx(genShellCmd(filename), options = {poStdErrToStdOut}, workingDir = nimcache2) + doAssert status == 0, outp + let (outp2, status2) = execCmdEx(nimcache2 / input, options = {poStdErrToStdOut}) + doAssert outp2 == "12345\n", outp2 + doAssert status2 == 0 + +else: + discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled From c495628255330a559e3398663cc8872cca18b04d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 00:43:30 -0700 Subject: [PATCH 2622/4254] refactor common code in CI pipelines (#18035) * refactor CI with nimInternalInstallDepsWindows * refactor CI with nimInternalBuildKochAndRunCI * fixup --- .builds/freebsd.yml | 6 +----- .builds/openbsd_0.yml | 6 +----- .builds/openbsd_1.yml | 6 +----- .github/workflows/ci_docs.yml | 8 +++----- .github/workflows/ci_packages.yml | 22 ++++++---------------- azure-pipelines.yml | 16 ++++------------ ci/funs.sh | 17 +++++++++++++++++ tools/ci_generate.nim | 6 +----- 8 files changed, 34 insertions(+), 53 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 8f336771a..15d09dda0 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -22,15 +22,11 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | set -e cd Nim - if ! ./koch runCI; then - nim r tools/ci_testresults.nim - exit 1 - fi + . ci/funs.sh && nimInternalBuildKochAndRunCI triggers: - action: email condition: failure diff --git a/.builds/openbsd_0.yml b/.builds/openbsd_0.yml index c19cd63c6..c3b2fd43e 100644 --- a/.builds/openbsd_0.yml +++ b/.builds/openbsd_0.yml @@ -22,15 +22,11 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | set -e cd Nim - if ! ./koch runCI; then - nim r tools/ci_testresults.nim - exit 1 - fi + . ci/funs.sh && nimInternalBuildKochAndRunCI triggers: - action: email condition: failure diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml index 06f5f2ae5..e98ec4640 100644 --- a/.builds/openbsd_1.yml +++ b/.builds/openbsd_1.yml @@ -22,15 +22,11 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | set -e cd Nim - if ! ./koch runCI; then - nim r tools/ci_testresults.nim - exit 1 - fi + . ci/funs.sh && nimInternalBuildKochAndRunCI triggers: - action: email condition: failure diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 364c05051..ddef94fbe 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -59,11 +59,9 @@ jobs: if: runner.os == 'Windows' shell: bash run: | - mkdir dist - curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z - curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip - 7z x dist/mingw64.7z -odist - 7z x dist/dlls.zip -obin + set -e + . ci/funs.sh + nimInternalInstallDepsWindows echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - name: 'Add build binaries to PATH' diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index d033aba10..aeb29e147 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -40,12 +40,10 @@ jobs: if: runner.os == 'Windows' shell: bash run: | - mkdir dist - curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z - curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip - 7z x dist/mingw64.7z -odist - 7z x dist/dlls.zip -obin - echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" + set -e + . ci/funs.sh + nimInternalInstallDepsWindows + echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - name: 'Add build binaries to PATH' shell: bash @@ -59,14 +57,6 @@ jobs: shell: bash run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' - - name: 'Build koch' + - name: 'koch, Run CI' shell: bash - run: nim c koch - - name: 'Run CI' - shell: bash - run: ./koch runCI - - - name: 'Show failed tests' - if: failure() - shell: bash - run: nim c -r tools/ci_testresults.nim + run: . ci/funs.sh && nimInternalBuildKochAndRunCI diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 112fb0a62..f0c3b2d0a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -133,11 +133,7 @@ jobs: - bash: | set -e . ci/funs.sh - echo_run mkdir dist - echo_run curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z - echo_run curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip - echo_run 7z x dist/mingw64.7z -odist - echo_run 7z x dist/dlls.zip -obin + nimInternalInstallDepsWindows echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' displayName: 'Install dependencies (Windows)' @@ -163,13 +159,9 @@ jobs: # condition: and(succeeded(), eq(variables['skipci'], 'false')) # displayName: 'Restore built csourcesAny' - - bash: nim c koch + - bash: . ci/funs.sh && nimInternalBuildKochAndRunCI + # would could also show on failure: echo '##vso[task.complete result=Failed]' condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Build koch' - - # set result to omit the "bash exited with error code '1'" message - - bash: ./koch runCI || echo '##vso[task.complete result=Failed]' - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Run CI' + displayName: 'koch, Run CI' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/ci/funs.sh b/ci/funs.sh index 0e4f0eb3b..9772535be 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -31,6 +31,23 @@ nimIsCiSkip(){ fi } +nimInternalInstallDepsWindows(){ + echo_run mkdir dist + echo_run curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z + echo_run curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip + echo_run 7z x dist/mingw64.7z -odist + echo_run 7z x dist/dlls.zip -obin +} + +nimInternalBuildKochAndRunCI(){ + echo_run nim c koch + if ! echo_run ./koch runCI; then + echo_run echo "runCI failed" + echo_run nim r -tools/ci_testresults.nim + return 1 + fi +} + nimDefineVars(){ . config/build_config.txt nim_csources=bin/nim_csources_$nim_csourcesHash diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index f08cd5409..52b84f0d8 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -29,15 +29,11 @@ tasks: set -e cd Nim . ci/funs.sh && nimBuildCsourcesIfNeeded - $nim_csources c --skipUserCfg --skipParentCfg koch echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv - test: | set -e cd Nim - if ! ./koch runCI; then - nim r tools/ci_testresults.nim - exit 1 - fi + . ci/funs.sh && nimInternalBuildKochAndRunCI triggers: - action: email condition: failure From 8df55d0ad735277683631bb8e5966ee75545de2b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 00:44:00 -0700 Subject: [PATCH 2623/4254] close #3482 no more cgen error with typed templates (#18094) --- tests/misc/t3482.nim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/misc/t3482.nim diff --git a/tests/misc/t3482.nim b/tests/misc/t3482.nim new file mode 100644 index 000000000..33b3b8f40 --- /dev/null +++ b/tests/misc/t3482.nim @@ -0,0 +1,15 @@ +discard """ + action: reject + nimout: "t3482.nim(13, 8) Error: undeclared identifier: 'output'" +""" +# bug #3482 (correct behavior since 1.4.0, cgen error in 1.2.0) +template foo*(body: typed) = + if true: + body + +proc test = + foo: + var output = "" + echo output.len + +test() From 0b2bbcaa23f91b06bc06dd2cf35d4d26a6d24aa8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 00:46:53 -0700 Subject: [PATCH 2624/4254] fix #18077 testament now parses `cmd` properly (#18086) --- testament/categories.nim | 3 ++- testament/testament.nim | 53 ++++++++++++++++++++++++++++------------ tests/misc/t18077.nim | 21 ++++++++++++++++ 3 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 tests/misc/t18077.nim diff --git a/testament/categories.nim b/testament/categories.nim index 510e90c53..8cf90666c 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -87,8 +87,9 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = var hcri = makeTest("tests/dll/nimhcr_integration.nim", options & " --forceBuild --hotCodeReloading:on" & rpath, cat) let nimcache = nimcacheDir(hcri.name, hcri.options, getTestSpecTarget()) - hcri.args = prepareTestArgs(hcri.spec.getCmd, hcri.name, + let cmd = prepareTestCmd(hcri.spec.getCmd, hcri.name, hcri.options, nimcache, getTestSpecTarget()) + hcri.testArgs = cmd.parseCmdLine testSpec r, hcri proc dllTests(r: var TResults, cat: Category, options: string) = diff --git a/testament/testament.nim b/testament/testament.nim index 2edefdb01..1eb925122 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -85,7 +85,7 @@ type name: string cat: Category options: string - args: seq[string] + testArgs: seq[string] spec: TSpec startTime: float debugInfo: string @@ -154,24 +154,23 @@ proc nimcacheDir(filename, options: string, target: TTarget): string = let hashInput = options & $target result = "nimcache" / (filename & '_' & hashInput.getMD5) -proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, - target: TTarget, extraOptions = ""): seq[string] = +proc prepareTestCmd(cmdTemplate, filename, options, nimcache: string, + target: TTarget, extraOptions = ""): string = var options = target.defaultOptions & ' ' & options - # improve pending https://github.com/nim-lang/Nim/issues/14343 - if nimcache.len > 0: options.add ' ' & ("--nimCache:" & nimcache).quoteShell + if nimcache.len > 0: options.add(" --nimCache:$#" % nimcache.quoteShell) options.add ' ' & extraOptions - result = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], + # we avoid using `parseCmdLine` which is buggy, refs bug #14343 + result = cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell, - "filedir", filename.getFileDir(), "nim", compilerPrefix]) + "filedir", filename.getFileDir(), "nim", compilerPrefix] proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, target: TTarget, extraOptions = ""): TSpec = - let c = prepareTestArgs(cmdTemplate, filename, options, nimcache, target, + result.cmd = prepareTestCmd(cmdTemplate, filename, options, nimcache, target, extraOptions) - result.cmd = quoteShellCommand(c) - verboseCmd(c.quoteShellCommand) - var p = startProcess(command = c[0], args = c[1 .. ^1], - options = {poStdErrToStdOut, poUsePath}) + verboseCmd(result.cmd) + var p = startProcess(command = result.cmd, + options = {poStdErrToStdOut, poUsePath, poEvalCommand}) let outp = p.outputStream var foundSuccessMsg = false var foundErrorMsg = false @@ -224,9 +223,33 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, proc callCCompiler(cmdTemplate, filename, options: string, target: TTarget): TSpec = - let c = prepareTestArgs(cmdTemplate, filename, options, nimcache = "", target) + let cmd = prepareTestCmd(cmdTemplate, filename, options, nimcache = "", target) + doAssert false + #[ + this code hasn't been run in a while, and should be removed which simplifies code + there are better ways to do this anyways (e.g. running c code from a nim file) + + the only place where this is called is: + `testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat), actionRun` + which isn't run unless you call: + XDG_CONFIG_HOME= nim r --lib:lib --stacktrace:on testament/testament.nim r longgc + + and this fails since at least nim 1.0 with: + testament/testament.nim(851) testament + testament/testament.nim(822) main + testament/categories.nim(713) processCategory + testament/categories.nim(189) longGCTests + testament/testament.nim(644) makeTest + testament/specs.nim(251) parseSpec + testament/specs.nim(184) extractSpec + lib/system/io.nim(861) readFile + Error: unhandled exception: cannot open: tests/realtimeGC/cmain.nim [IOError] + + Also, `c[5 .. ^1]` is too magical. + ]# + let c = cmd.parseCmdLine var p = startProcess(command = "gcc", args = c[5 .. ^1], - options = {poStdErrToStdOut, poUsePath}) + options = {poStdErrToStdOut, poUsePath, poEvalCommand}) let outp = p.outputStream var x = newStringOfCap(120) result.nimout = "" @@ -525,7 +548,7 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, reExeNotFound) else: var exeCmd: string - var args = test.args + var args = test.testArgs if isJsTarget: exeCmd = nodejs # see D20210217T215950 diff --git a/tests/misc/t18077.nim b/tests/misc/t18077.nim new file mode 100644 index 000000000..6cd05d575 --- /dev/null +++ b/tests/misc/t18077.nim @@ -0,0 +1,21 @@ +discard """ + cmd: '''nim doc -d:nimTestsT18077b:4 --doccmd:"-d:nimTestsT18077 -d:nimTestsT18077b:3 --hints:off" $file''' + action: compile +""" + +# bug #18077 + +const nimTestsT18077b {.intdefine.} = 1 + +static: + when defined(nimdoc): + doAssert nimTestsT18077b == 4 + doAssert not defined(nimTestsT18077) + else: + doAssert defined(nimTestsT18077) + doAssert nimTestsT18077b == 3 + +runnableExamples: + const nimTestsT18077b {.intdefine.} = 2 + doAssert nimTestsT18077b == 3 + doAssert defined(nimTestsT18077) From 3b1aabdcffafbbf37ad02f013f754f67dfe2461c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 00:51:48 -0700 Subject: [PATCH 2625/4254] change `--hint[X] => --hint:X` in nim repo (avoids shell quoting issues) (#18085) --- compiler/nim.cfg | 4 ++-- compiler/nimfix/nimfix.nim.cfg | 2 +- config/nim.cfg | 4 ++-- doc/advopt.txt | 10 +++++----- doc/filters.rst | 2 +- doc/nimc.rst | 8 ++++---- drnim/nim.cfg | 2 +- nimsuggest/nimsuggest.nim.cfg | 2 +- testament/categories.nim | 4 ++-- tests/effects/toutparam.nim | 2 +- tests/osproc/treadlines.nim | 2 +- tests/pragmas/t8741.nim | 2 +- tests/range/tcompiletime_range_checks.nim | 2 +- tests/tools/tunused_imports.nim | 2 +- tools/nimweb.nim | 2 +- 15 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 40e93d523..9ecd00b0b 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -1,6 +1,6 @@ # Special configuration file for the Nim project -hint[XDeclaredButNotUsed]:off +hint:XDeclaredButNotUsed:off define:booting define:nimcore @@ -22,5 +22,5 @@ define:useStdoutAsStdmsg #gc:markAndSweep @if nimHasWarningObservableStores: - warning[ObservableStores]: off + warning:ObservableStores: off @end diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg index 0d9dbfa4b..27ebf10b9 100644 --- a/compiler/nimfix/nimfix.nim.cfg +++ b/compiler/nimfix/nimfix.nim.cfg @@ -1,7 +1,7 @@ # Special configuration file for the Nim project # gc:markAndSweep -hint[XDeclaredButNotUsed]:off +hint:XDeclaredButNotUsed:off path:"$projectPath/.." path:"$lib/packages/docutils" diff --git a/config/nim.cfg b/config/nim.cfg index 3b964d124..c0a844e03 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -13,8 +13,8 @@ cc = gcc # additional options always passed to the compiler: --parallel_build: "0" # 0 to auto-detect number of processors -hint[LineTooLong]=off -#hint[XDeclaredButNotUsed]=off +hint:LineTooLong:off +#hint:XDeclaredButNotUsed:off # Examples of how to setup a cross-compiler: diff --git a/doc/advopt.txt b/doc/advopt.txt index e50fb243b..ea3370880 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -47,12 +47,12 @@ Advanced options: an implementation defined set of suggestions. -w:on|off|list, --warnings:on|off|list turn all warnings on|off or list all available - --warning[X]:on|off turn specific warning X on|off + --warning:X:on|off turn specific warning X on|off. + `warning:X` means `warning:X:on`, as with similar flags. --hints:on|off|list turn all hints on|off or list all available - --hint[X]:on|off turn specific hint X on|off - --warningAsError[X]:on|off - turn specific warning X into an error on|off - --hintAsError[X]:on|off turn specific hint X into an error on|off + --hint:X:on|off turn specific hint X on|off. + --warningAsError:X:on|off turn specific warning X into an error on|off + --hintAsError:X:on|off turn specific hint X into an error on|off --styleCheck:off|hint|error produce hints or errors for Nim identifiers that do not adhere to Nim's official style guide diff --git a/doc/filters.rst b/doc/filters.rst index c6d436194..e237744cb 100644 --- a/doc/filters.rst +++ b/doc/filters.rst @@ -25,7 +25,7 @@ just like an ordinary procedure call with named or positional arguments. The available parameters depend on the invoked filter. Before version 0.12.0 of the language `#!` was used instead of `#?`. -**Hint:** With `--hint[codeBegin]:on`:option: or `--verbosity:2`:option: +**Hint:** With `--hint:codeBegin:on`:option: or `--verbosity:2`:option: (or higher) while compiling or `nim check`:cmd:, Nim lists the processed code after each filter application. diff --git a/doc/nimc.rst b/doc/nimc.rst index 47f7243cc..e467a33af 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -53,8 +53,8 @@ Advanced command-line switches are: List of warnings ---------------- -Each warning can be activated individually with `--warning[NAME]:on|off`:option: or -in a `push` pragma. +Each warning can be activated individually with `--warning:NAME:on|off`:option: or +in a `push` pragma with `{.warning[NAME]:on|off.}`. ========================== ============================================ Name Description @@ -77,8 +77,8 @@ User Some user-defined warning. List of hints ------------- -Each hint can be activated individually with `--hint[NAME]:on|off`:option: or in a -`push` pragma. +Each hint can be activated individually with `--hint:NAME:on|off`:option: or in a +`push` pragma with `{.hint[NAME]:on|off.}`. ========================== ============================================ Name Description diff --git a/drnim/nim.cfg b/drnim/nim.cfg index 58c1725d9..57dca974c 100644 --- a/drnim/nim.cfg +++ b/drnim/nim.cfg @@ -1,6 +1,6 @@ # Special configuration file for the Nim project -hint[XDeclaredButNotUsed]:off +hint:XDeclaredButNotUsed:off define:booting define:nimcore diff --git a/nimsuggest/nimsuggest.nim.cfg b/nimsuggest/nimsuggest.nim.cfg index 394449740..6e5ee8c71 100644 --- a/nimsuggest/nimsuggest.nim.cfg +++ b/nimsuggest/nimsuggest.nim.cfg @@ -2,7 +2,7 @@ gc:markAndSweep -hint[XDeclaredButNotUsed]:off +hint:XDeclaredButNotUsed:off path:"$lib/packages/docutils" diff --git a/testament/categories.nim b/testament/categories.nim index 8cf90666c..0a3595ff4 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -486,7 +486,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; writeOnly = " --incremental:writeonly " readOnly = " --incremental:readonly " incrementalOn = " --incremental:on -d:nimIcIntegrityChecks " - navTestConfig = " --ic:on -d:nimIcNavigatorTests --hint[Conf]:off --warnings:off " + navTestConfig = " --ic:on -d:nimIcNavigatorTests --hint:Conf:off --warnings:off " template test(x: untyped) = testSpecWithNimcache(r, makeRawTest(file, x & options, cat), nimcache) @@ -500,7 +500,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; template checkTest() = var test = makeRawTest(file, options, cat) - test.spec.cmd = compilerPrefix & " check --hint[Conf]:off --warnings:off --ic:on $options " & file + test.spec.cmd = compilerPrefix & " check --hint:Conf:off --warnings:off --ic:on $options " & file testSpecWithNimcache(r, test, nimcache) if not isNavigatorTest: diff --git a/tests/effects/toutparam.nim b/tests/effects/toutparam.nim index 00572aa6b..1126aa77e 100644 --- a/tests/effects/toutparam.nim +++ b/tests/effects/toutparam.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --warningAsError[Uninit]:on --skipCfg --skipParentCfg $file''' + cmd: '''nim c --warningAsError:Uninit:on --skipCfg --skipParentCfg $file''' errormsg: "use explicit initialization of 'x' for clarity [Uninit]" line: 24 disabled: "true" diff --git a/tests/osproc/treadlines.nim b/tests/osproc/treadlines.nim index bcde19d7f..200a7c299 100644 --- a/tests/osproc/treadlines.nim +++ b/tests/osproc/treadlines.nim @@ -13,7 +13,7 @@ var ps: seq[Process] # compile & run 2 progs in parallel const nim = getCurrentCompilerExe() for prog in ["a", "b"]: ps.add startProcess(nim, "", - ["r", "--hint[Conf]=off", "--hint[Processing]=off", prog], + ["r", "--hint:Conf:off", "--hint:Processing:off", prog], options = {poUsePath, poDaemon, poStdErrToStdOut}) for p in ps: diff --git a/tests/pragmas/t8741.nim b/tests/pragmas/t8741.nim index 61a449c01..221c732b0 100644 --- a/tests/pragmas/t8741.nim +++ b/tests/pragmas/t8741.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim check --hint[processing]:off $file" + cmd: "nim check --hint:processing:off $file" errormsg: "3 is not two" nimout: '''t8741.nim(13, 9) Error: cannot attach a custom pragma to 'a' t8741.nim(29, 15) template/generic instantiation of `onlyTwo` from here diff --git a/tests/range/tcompiletime_range_checks.nim b/tests/range/tcompiletime_range_checks.nim index 37095e0b7..29e2c48a8 100644 --- a/tests/range/tcompiletime_range_checks.nim +++ b/tests/range/tcompiletime_range_checks.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim check --hint[Processing]:off --hint[Conf]:off $file" + cmd: "nim check --hint:Processing:off --hint:Conf:off $file" errormsg: "18446744073709551615 can't be converted to int8" nimout: '''tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32 tcompiletime_range_checks.nim(37, 23) Error: -1 can't be converted to uint64 diff --git a/tests/tools/tunused_imports.nim b/tests/tools/tunused_imports.nim index bce906634..31d6cf7d7 100644 --- a/tests/tools/tunused_imports.nim +++ b/tests/tools/tunused_imports.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --hint[Processing]:off $file''' + cmd: '''nim c --hint:Processing:off $file''' nimout: ''' tunused_imports.nim(11, 10) Warning: BEGIN [User] tunused_imports.nim(36, 10) Warning: END [User] diff --git a/tools/nimweb.nim b/tools/nimweb.nim index f71b5f3be..ccc80dfcf 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -53,7 +53,7 @@ proc initConfigData(c: var TConfigData) = c.webdoc = @[] c.pdf = @[] c.infile = "" - c.nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot " + c.nimArgs = "--hint:Conf:off --hint:Path:off --hint:Processing:off -d:boot " c.gitURL = "https://github.com/nim-lang/Nim" c.docHTMLOutput = "doc/html" c.webUploadOutput = "web/upload" From 1e0165186bb8539cfd8aca1a7af8d01dc278bd46 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 11:49:01 -0700 Subject: [PATCH 2626/4254] testament: remove deadcode related to realtimeGC, testC, callCCompiler (#18087) --- testament/categories.nim | 22 +++--------- testament/testament.nim | 63 --------------------------------- tests/readme.md | 3 +- tests/realtimeGC/cmain.c | 69 ------------------------------------- tests/realtimeGC/readme.txt | 10 ------ tests/realtimeGC/tmain.nim | 10 +++++- 6 files changed, 15 insertions(+), 162 deletions(-) delete mode 100644 tests/realtimeGC/cmain.c delete mode 100644 tests/realtimeGC/readme.txt diff --git a/testament/categories.nim b/testament/categories.nim index 0a3595ff4..7f05797ff 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -28,7 +28,6 @@ const "js", "ic", "lib", - "longgc", "manyloc", "nimble-packages", "niminaction", @@ -39,7 +38,6 @@ const "coroutines", "osproc", "shouldfail", - "dir with space", "destructor" ] @@ -156,19 +154,6 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "cyclecollector" testWithoutBoehm "trace_globals" -proc longGCTests(r: var TResults, cat: Category, options: string) = - when defined(windows): - let cOptions = "-ldl -DWIN" - else: - let cOptions = "-ldl" - - var c = initResults() - # According to ioTests, this should compile the file - testSpec c, makeTest("tests/realtimeGC/shared", options, cat) - # ^- why is this not appended to r? Should this be discarded? - testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat), actionRun - testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat) - # ------------------------- threading tests ----------------------------------- proc threadTests(r: var TResults, cat: Category, options: string) = @@ -186,6 +171,11 @@ proc ioTests(r: var TResults, cat: Category, options: string) = # dummy compile result: var c = initResults() testSpec c, makeTest("tests/system/helpers/readall_echo", options, cat) + # ^- why is this not appended to r? Should this be discarded? + # EDIT: this should be replaced by something like in D20210524T180826, + # likewise in similar instances where `testSpec c` is used, or more generally + # when a test depends on another test, as it makes tests non-independent, + # creating complications for batching and megatest logic. testSpec r, makeTest("tests/system/tio", options, cat) # ------------------------- async tests --------------------------------------- @@ -687,8 +677,6 @@ proc processCategory(r: var TResults, cat: Category, dllTests(r, cat, options) of "gc": gcTests(r, cat, options) - of "longgc": - longGCTests(r, cat, options) of "debugger": debuggerTests(r, cat, options) of "manyloc": diff --git a/testament/testament.nim b/testament/testament.nim index 1eb925122..789c987c0 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -221,53 +221,6 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.msg = matches[0] trimUnitSep result.msg -proc callCCompiler(cmdTemplate, filename, options: string, - target: TTarget): TSpec = - let cmd = prepareTestCmd(cmdTemplate, filename, options, nimcache = "", target) - doAssert false - #[ - this code hasn't been run in a while, and should be removed which simplifies code - there are better ways to do this anyways (e.g. running c code from a nim file) - - the only place where this is called is: - `testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat), actionRun` - which isn't run unless you call: - XDG_CONFIG_HOME= nim r --lib:lib --stacktrace:on testament/testament.nim r longgc - - and this fails since at least nim 1.0 with: - testament/testament.nim(851) testament - testament/testament.nim(822) main - testament/categories.nim(713) processCategory - testament/categories.nim(189) longGCTests - testament/testament.nim(644) makeTest - testament/specs.nim(251) parseSpec - testament/specs.nim(184) extractSpec - lib/system/io.nim(861) readFile - Error: unhandled exception: cannot open: tests/realtimeGC/cmain.nim [IOError] - - Also, `c[5 .. ^1]` is too magical. - ]# - let c = cmd.parseCmdLine - var p = startProcess(command = "gcc", args = c[5 .. ^1], - options = {poStdErrToStdOut, poUsePath, poEvalCommand}) - let outp = p.outputStream - var x = newStringOfCap(120) - result.nimout = "" - result.msg = "" - result.file = "" - result.output = "" - result.line = -1 - while true: - if outp.readLine(x): - result.nimout.add(x & '\n') - elif not running(p): - break - close(p) - if p.peekExitCode == 0: - result.err = reSuccess - else: - result.err = reNimcCrash - proc initResults: TResults = result.total = 0 result.passed = 0 @@ -628,22 +581,6 @@ proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) {.used var testClone = test testSpecHelper(r, testClone, test.spec, target, nimcache) -proc testC(r: var TResults, test: TTest, action: TTestAction) = - # runs C code. Doesn't support any specs, just goes by exit code. - if not checkDisabled(r, test): return - - let tname = test.name.addFileExt(".c") - inc(r.total) - maybeStyledEcho "Processing ", fgCyan, extractFilename(tname) - var given = callCCompiler(getCmd(TSpec()), test.name & ".c", test.options, targetC) - if given.err != reSuccess: - r.addResult(test, targetC, "", given.msg, given.err) - elif action == actionRun: - let exeFile = changeFileExt(test.name, ExeExt) - var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath}) - if exitCode != 0: given.err = reExitcodesDiffer - if given.err == reSuccess: inc(r.passed) - proc makeTest(test, options: string, cat: Category): TTest = result.cat = cat result.name = test diff --git a/tests/readme.md b/tests/readme.md index 69be92051..dca7ec152 100644 --- a/tests/readme.md +++ b/tests/readme.md @@ -55,5 +55,4 @@ testing, which is slower). The folder ``dll`` contains simple DLL tests. The folder ``realtimeGC`` contains a test for validating that the realtime GC -can run properly without linking against the nimrtl.dll/so. It includes a C -client and platform specific build files for manual compilation. +can run properly without linking against the nimrtl.dll/so. diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c deleted file mode 100644 index 4bc5bd026..000000000 --- a/tests/realtimeGC/cmain.c +++ /dev/null @@ -1,69 +0,0 @@ -/* xxx consider removing, this seems redundant with tmain.nim */ - -#ifdef WIN -#include -#else -#include -#include /* for sleep(3) */ -#endif -#include -#include -#include -#include -#include - -#define RUNTIME (15*60) - - -typedef void (*pFunc)(void); - -int main(int argc, char* argv[]) -{ - int i; - void* hndl; - pFunc status; - pFunc count; - pFunc checkOccupiedMem; - -#ifdef WIN - hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll"); - status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status"); - count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count"); - checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem"); -#else /* OSX || NIX xxx: OSX assumes dylib*/ - hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY); - status = (pFunc) dlsym(hndl, (char const*)"status"); - count = (pFunc) dlsym(hndl, (char const*)"count"); - checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem"); -#endif - - assert(hndl); - assert(status); - assert(count); - assert(checkOccupiedMem); - - time_t startTime = time((time_t*)0); - time_t runTime = (time_t)(RUNTIME); - time_t accumTime = 0; - while (accumTime < runTime) { - for (i = 0; i < 10; i++) - count(); - /* printf("1. sleeping...\n"); */ - sleep(1); - for (i = 0; i < 10; i++) - status(); - /* printf("2. sleeping...\n"); */ - sleep(1); - checkOccupiedMem(); - accumTime = time((time_t*)0) - startTime; - /* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */ - } - printf("Cleaning up the shared object pointer...\n"); -#ifdef WIN - FreeLibrary((HMODULE)hndl); -#else /* OSX || NIX */ - dlclose(hndl); -#endif - printf("Done\n"); - return 0; -} diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt deleted file mode 100644 index c5837ee14..000000000 --- a/tests/realtimeGC/readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -Test the realtime GC without linking nimrtl.dll/so. - -To build by hand and run the test for 35 minutes: - $ nim r --threads:on -d:runtimeSecs:2100 tests/realtimeGC/nmain.nim - -``` -xxx do we still need tests/realtimeGC/cmain.c? -if so, tests/realtimeGC/cmain.c needs to updated and factorized with nmain.nim to avoid duplication (even if it's a C file) -``` - $ gcc -o tests/realtimeGC/cmain tests/realtimeGC/cmain.c -ldl \ No newline at end of file diff --git a/tests/realtimeGC/tmain.nim b/tests/realtimeGC/tmain.nim index f1515a549..ca0177e3d 100644 --- a/tests/realtimeGC/tmain.nim +++ b/tests/realtimeGC/tmain.nim @@ -9,6 +9,13 @@ these dont' seem needed --debuginfo nor these from the previous main.nim.cfg: --app:console ]# +#[ +Test the realtime GC without linking nimrtl.dll/so. + +To build by hand and run the test for 35 minutes: +`nim r --threads:on -d:runtimeSecs:2100 tests/realtimeGC/tmain.nim` +]# + import times, os, strformat, strutils from stdtest/specialpaths import buildDir # import threadpool @@ -16,9 +23,10 @@ from stdtest/specialpaths import buildDir const runtimeSecs {.intdefine.} = 5 const file = "shared.nim" -const dllname = buildDir / (DynlibFormat % file) +const dllname = buildDir / (DynlibFormat % "shared_D20210524T180506") static: + # D20210524T180826:here we compile the dependency on the fly let nim = getCurrentCompilerExe() let (output, exitCode) = gorgeEx(fmt"{nim} c -o:{dllname} --debuginfo --app:lib --threads:on -d:release -d:useRealtimeGC {file}") doAssert exitCode == 0, output From d62a298a2834b9a35aac4d922a810a772cd3bc1d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 27 May 2021 09:04:10 -0700 Subject: [PATCH 2627/4254] fix typo in ci/funs.sh (#18115) --- ci/funs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/funs.sh b/ci/funs.sh index 9772535be..4a8887658 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -43,7 +43,7 @@ nimInternalBuildKochAndRunCI(){ echo_run nim c koch if ! echo_run ./koch runCI; then echo_run echo "runCI failed" - echo_run nim r -tools/ci_testresults.nim + echo_run nim r tools/ci_testresults.nim return 1 fi } From 9eae6b4fe312035daadd8dcb0ca488a3e5897c11 Mon Sep 17 00:00:00 2001 From: vabresto <77133146+vabresto@users.noreply.github.com> Date: Fri, 28 May 2021 18:17:37 -0400 Subject: [PATCH 2628/4254] fix #17456 flaky test tasynchttpserver_transferencoding (#18052) --- .../tasynchttpserver_transferencoding.nim | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim index bfa0e2f69..fd79ce3a0 100644 --- a/tests/stdlib/tasynchttpserver_transferencoding.nim +++ b/tests/stdlib/tasynchttpserver_transferencoding.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger; --threads:on" +""" + import httpclient, asynchttpserver, asyncdispatch, asyncfutures import net @@ -10,33 +14,38 @@ Transfer-Encoding:chunked """ -template genTest(input, expected) = - var sanity = false - proc handler(request: Request) {.async.} = - doAssert(request.body == expected) - doAssert(request.headers.hasKey("Transfer-Encoding")) - doAssert(not request.headers.hasKey("Content-Length")) - sanity = true - await request.respond(Http200, "Good") +template genTest(input, expected: string) = + proc handler(request: Request, future: Future[bool]) {.async, gcsafe.} = + doAssert(request.body == expected) + doAssert(request.headers.hasKey("Transfer-Encoding")) + doAssert(not request.headers.hasKey("Content-Length")) + future.complete(true) + await request.respond(Http200, "Good") - proc runSleepLoop(server: AsyncHttpServer) {.async.} = + proc sendData(data: string, port: Port) {.async.} = + var socket = newSocket() + defer: socket.close() + + socket.connect("127.0.0.1", port) + socket.send(data) + + proc runTest(): Future[bool] {.async.} = + var handlerFuture = newFuture[bool]("runTest") + let data = postBegin & input + let server = newAsyncHttpServer() server.listen(Port(0)) - proc wrapper() = - waitFor server.acceptRequest(handler) - asyncdispatch.callSoon wrapper - let server = newAsyncHttpServer() - waitFor runSleepLoop(server) - let data = postBegin & input - var socket = newSocket() - socket.connect("127.0.0.1", server.getPort) - socket.send(data) - waitFor sleepAsync(10) - socket.close() - server.close() + proc wrapper(request: Request): Future[void] {.gcsafe, closure.} = + handler(request, handlerFuture) + + asyncCheck sendData(data, server.getPort) + asyncCheck server.acceptRequest(wrapper) + doAssert await handlerFuture + + server.close() + return true - # Verify we ran the handler and its asserts - doAssert(sanity) + doAssert waitFor runTest() block: const expected = "hello=world" From c792154b030c1bfec9ed0020ddaf985d5f034ca3 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Sat, 29 May 2021 15:39:46 -0400 Subject: [PATCH 2629/4254] Minor doc fixes; follow up to 17258 and 17259 (#18123) Co-authored-by: quantimnot --- doc/manual.rst | 6 +++--- doc/manual_experimental_strictnotnil.rst | 2 +- doc/tut1.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 2b85f5c34..6a0dec120 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -363,7 +363,7 @@ contain the following `escape sequences`:idx:\ : ``\\`` `backslash`:idx: ``\"`` `quotation mark`:idx: ``\'`` `apostrophe`:idx: - ``\\`` '0'..'9'+ `character with decimal value d`:idx:; + ``\`` '0'..'9'+ `character with decimal value d`:idx:; all decimal digits directly following are used for the character ``\a`` `alert`:idx: @@ -473,7 +473,7 @@ literals: ``\\`` `backslash`:idx: ``\"`` `quotation mark`:idx: ``\'`` `apostrophe`:idx: - ``\\`` '0'..'9'+ `character with decimal value d`:idx:; + ``\`` '0'..'9'+ `character with decimal value d`:idx:; all decimal digits directly following are used for the character ``\a`` `alert`:idx: @@ -7825,7 +7825,7 @@ Threads To enable thread support the `--threads:on`:option: command-line switch needs to be used. The system_ module then contains several threading primitives. -See the `threads `_ and `channels `_ modules +See the `threads `_ and `channels `_ modules for the low-level thread API. There are also high-level parallelism constructs available. See `spawn `_ for further details. diff --git a/doc/manual_experimental_strictnotnil.rst b/doc/manual_experimental_strictnotnil.rst index c7c045683..cb3bfeca9 100644 --- a/doc/manual_experimental_strictnotnil.rst +++ b/doc/manual_experimental_strictnotnil.rst @@ -143,7 +143,7 @@ Merging usually merges maps and alias sets: nilabilities are merged like this: else: MaybeNil -Special handling is for `.isNil` and ` == nil`, also for `not`, `and` and `or`. +Special handling is for `.isNil` and `== nil`, also for `not`, `and` and `or`. `not` reverses the nilability, `and` is similar to "forking" : the right expression is checked in the layer resulting from the left one and `or` is similar to "merging": the right and left expression should be both checked in the original layer. diff --git a/doc/tut1.rst b/doc/tut1.rst index 2f19ae173..210ea324e 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -114,7 +114,7 @@ String and character literals ----------------------------- String literals are enclosed in double-quotes; character literals in single -quotes. Special characters are escaped with ``\\``: ``\n`` means newline, ``\t`` +quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t`` means tabulator, etc. There are also *raw* string literals: .. code-block:: Nim From cfe19247e856950f7facaf7adbc50bca8dec3990 Mon Sep 17 00:00:00 2001 From: vabresto <77133146+vabresto@users.noreply.github.com> Date: Sat, 29 May 2021 15:44:39 -0400 Subject: [PATCH 2630/4254] Disable tasynchttpserver_transferencoding on FreeBSD (#18122) --- tests/stdlib/tasynchttpserver_transferencoding.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim index fd79ce3a0..cdd30d04b 100644 --- a/tests/stdlib/tasynchttpserver_transferencoding.nim +++ b/tests/stdlib/tasynchttpserver_transferencoding.nim @@ -1,5 +1,6 @@ discard """ matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger; --threads:on" + disabled: "freebsd" """ import httpclient, asynchttpserver, asyncdispatch, asyncfutures From 4a7f2c386cde91b784106905f6e70d3954d8fae9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 30 May 2021 13:37:21 -0700 Subject: [PATCH 2631/4254] close #16569: deprecated `reversed(a, start, last)` overload, use toOpenArray instead (#18047) * close #16569: deprecated reversed overload, use toOpenArray instead * [skip ci] change wording in changelog per review * fixup --- changelog.md | 2 ++ lib/pure/algorithm.nim | 39 ++++++++++----------------------------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/changelog.md b/changelog.md index 4c30d67a7..809728b16 100644 --- a/changelog.md +++ b/changelog.md @@ -75,6 +75,8 @@ - `strformat` is now part of `include std/prelude`. +- Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` in `std/algorithm`. + - The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. The downside is that these defines now have custom logic that doesn't apply for other defines. diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index f4b3f46be..c96f599e8 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -131,40 +131,21 @@ proc reverse*[T](a: var openArray[T]) = # the max is needed, since a.high is -1 if a is empty reverse(a, 0, max(0, a.high)) -proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = - ## Returns the reverse of the slice `a[first..last]`. - ## - ## If an invalid range is passed, it raises `IndexDefect`. +proc reversed*[T](a: openArray[T]): seq[T] {.inline.} = + ## Returns the elements of `a` in reverse order. ## ## **See also:** - ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice ## * `reverse proc<#reverse,openArray[T]>`_ runnableExamples: - let - a = [1, 2, 3, 4, 5, 6] - b = a.reversed(1, 3) - assert b == @[4, 3, 2] - assert last >= first - 1 - var i = last - first - var x = first.int - result = newSeq[T](i + 1) - while i >= 0: - result[i] = a[x] - dec(i) - inc(x) + assert [10, 11, 12].reversed == @[12, 11, 10] + assert seq[string].default.reversed == @[] + let n = a.len + result.setLen(n) + for i in 0..`_ reverse a slice - ## * `reverse proc<#reverse,openArray[T]>`_ - runnableExamples: - let - a = [1, 2, 3, 4, 5, 6] - b = reversed(a) - assert b == @[6, 5, 4, 3, 2, 1] - reversed(a, 0, a.high) +proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] + {.inline, deprecated: "use: `reversed(toOpenArray(a, first, last))`".} = + reversed(toOpenArray(a, first, last)) proc binarySearch*[T, K](a: openArray[T], key: K, cmp: proc (x: T, y: K): int {.closure.}): int = From a6bd6c7ed803dcef41b49343b5cd60607b984ca8 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sun, 30 May 2021 23:38:33 +0300 Subject: [PATCH 2632/4254] Fixes #17849 (#18055) [backport:1.2] * Fixes #17849 * Update compiler/closureiters.nim Co-authored-by: Andreas Rumpf --- compiler/closureiters.nim | 6 ++++++ tests/iter/tyieldintry.nim | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index e474e5ba2..adc5a4873 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -606,6 +606,12 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind) result.add(n) result.add(ctx.newEnvVarAccess(tmp)) + elif n[0].kind == nkStmtListExpr: + result = newNodeI(nkStmtList, n.info) + let (st, ex) = exprToStmtList(n[0]) + result.add(st) + n[0] = ex + result.add(n) of nkCallKinds, nkChckRange, nkChckRangeF, nkChckRange64: var ns = false diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 35df55c24..3d5260800 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -483,5 +483,19 @@ block: # nnkChckRange test(it, 1, 2, 3) -echo "ok" +block: #17849 - yield in case subject + template yieldInCase: int = + yield 2 + 3 + iterator it(): int {.closure.} = + yield 1 + case yieldInCase() + of 1: checkpoint(11) + of 3: checkpoint(13) + else: checkpoint(14) + yield 5 + + test(it, 1, 2, 13, 5) + +echo "ok" From 4274e6e4d700ef72275344afed44d0b658729761 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 30 May 2021 13:39:17 -0700 Subject: [PATCH 2633/4254] upgrade ubuntu 16.04 (not supported starting dec 2021) => 18.04; revive Linux_i386 (#18107) --- .gitlab-ci.yml | 4 +++- azure-pipelines.yml | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ad9e565a6..31908d223 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,6 @@ -image: ubuntu:16.04 +# xxx unused, out of date + +image: ubuntu:18.04 stages: - pre-build diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f0c3b2d0a..a70a86fae 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,14 +19,14 @@ jobs: strategy: matrix: Linux_amd64: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-18.04' CPU: amd64 - # pending bug #17325 (broken again) - # Linux_i386: - # # bug #17325: fails on 'ubuntu-16.04' because it now errors with: - # # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed - # vmImage: 'ubuntu-18.04' - # CPU: i386 + # regularly breaks, refs bug #17325 + Linux_i386: + # on 'ubuntu-16.04' (not supported anymore anyways) it errored with: + # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed + vmImage: 'ubuntu-18.04' + CPU: i386 OSX_amd64: vmImage: 'macOS-10.15' CPU: amd64 From e2ab08603db6499063b3ff0f16776b4ed20c36f0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 30 May 2021 13:40:42 -0700 Subject: [PATCH 2634/4254] fix warnings/hints in nimdoc/tester.nim (#18083) * fix warnings/hints in nimdoc/tester.nim * improve err msg for nimdoc/tester.nim and change flag from fixup to nimTestsNimdocFixup * address comment: put back quit instead of doAssert --- nimdoc/tester.nim | 12 +++++++----- nimdoc/testproject/expected/testproject.html | 8 ++++---- nimdoc/testproject/testproject.nim | 9 +++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index 9daa0bb51..1e438b97b 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -1,10 +1,12 @@ # Small program that runs the test cases for 'nim doc'. # To run this, cd to the git repo root, and run "nim r nimdoc/tester.nim". -# to change expected results (after carefully verifying everything), use -d:fixup +# to change expected results (after carefully verifying everything), use -d:nimTestsNimdocFixup import strutils, os from std/private/gitutils import diffFiles +const fixup = defined(nimTestsNimdocFixup) + var failures = 0 @@ -62,7 +64,7 @@ let "$1/$2.nim" % [test1Dir, test1PrjName]], buildIndex: @["--out:$1/$2/theindex.html" % [test1Dir, test1DocsDir], "$1/$2" % [test1Dir, test1DocsDir]]) -testNimDoc(test1Dir, test1DocsDir, test1Switches, defined(fixup)) +testNimDoc(test1Dir, test1DocsDir, test1Switches, fixup) # Test "nim doc --out:.. --index:on .." let @@ -75,7 +77,7 @@ let "$1/$2.nim" % [test2Dir, test2PrjName]], buildIndex: @["--out:$1/$2/theindex.html" % [test2Dir, test2DocsDir], "$1/$2" % [test2Dir, test2DocsDir]]) -testNimDoc(test2Dir, test2DocsDir, test2Switches, defined(fixup)) +testNimDoc(test2Dir, test2DocsDir, test2Switches, fixup) -# Check for failures -if failures > 0: quit($failures & " failures occurred.") +if failures > 0: + quit "$# failures occurred; see note in tester.nim regarding -d:nimTestsNimdocFixup" % $failures diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index f23f6bb42..d2fe38021 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -790,7 +790,7 @@ the c printf. etc.
    -

    Example:

    +

    Example: cmd: --hint:XDeclaredButNotUsed:off

    ## mullitline string litterals are tricky as their indentation can span
     ## below that of the runnableExamples
     let s1a = """
    @@ -865,21 +865,21 @@ There is no block quote after blank lines at the beginning.
     

    Methods

    -
    method method1(self: Moo) {....raises: [], tags: [].}
    +
    method method1(self: Moo) {.base, ...raises: [], tags: [].}
    foo1
    -
    method method2(self: Moo): int {....raises: [], tags: [].}
    +
    method method2(self: Moo): int {.base, ...raises: [], tags: [].}
    foo2
    -
    method method3(self: Moo): int {....raises: [], tags: [].}
    +
    method method3(self: Moo): int {.base, ...raises: [], tags: [].}
    foo3 diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index d435efa66..b88b41098 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -131,6 +131,7 @@ when true: # BUG: this currently this won't be run since not exported # but probably should doAssert false + if false: bazNonExported() # silence XDeclaredButNotUsed proc z17*() = # BUG: a comment before 1st doc comment currently doesn't prevent @@ -212,7 +213,7 @@ when true: # tests RST inside comments when true: # multiline string litterals proc tripleStrLitTest*() = - runnableExamples: + runnableExamples("--hint:XDeclaredButNotUsed:off"): ## mullitline string litterals are tricky as their indentation can span ## below that of the runnableExamples let s1a = """ @@ -252,12 +253,12 @@ at indent 0 when true: # methods; issue #14691 type Moo = object - method method1*(self: Moo) = + method method1*(self: Moo) {.base.} = ## foo1 - method method2*(self: Moo): int = + method method2*(self: Moo): int {.base.} = ## foo2 result = 1 - method method3*(self: Moo): int = + method method3*(self: Moo): int {.base.} = ## foo3 1 From 50e98e6efaca05b60b33db0c878f04951a43b3b8 Mon Sep 17 00:00:00 2001 From: Miran Date: Sun, 30 May 2021 23:55:51 +0200 Subject: [PATCH 2635/4254] hashes for refs should be an opt-in feature (#18098) --- changelog.md | 17 +++++++++++++---- lib/pure/hashes.nim | 2 +- tests/collections/ttables.nim | 1 + tests/stdlib/thashes.nim | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 809728b16..279ba38dd 100644 --- a/changelog.md +++ b/changelog.md @@ -50,8 +50,9 @@ - On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` for previous behavior. -- `hashes.hash` now supports `object` and `ref` (can be overloaded in user code). - For a transition period, use `-d:nimLegacyNoHashRef` to avoid defining `hash(ref)`. +- `hashes.hash` can now support `object` and `ref` (can be overloaded in user code), + if `-d:nimEnableHashRef` is used. + - `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, `hashes.hash(closure)` has also been improved. @@ -82,7 +83,9 @@ other defines. + ## Standard library additions and changes + - Added support for parenthesized expressions in `strformat` - Fixed buffer overflow bugs in `net` @@ -99,7 +102,6 @@ the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you now also need to ship `cacert.pem` with your `.exe` file. - - Make `{.requiresInit.}` pragma to work for `distinct` types. - Added a macros `enumLen` for returning the number of items in an enum to the @@ -324,6 +326,8 @@ - Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place. + + ## Language changes - `nimscript` now handles `except Exception as e`. @@ -368,6 +372,8 @@ - `typeof(voidStmt)` now works and returns `void`. + + ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. @@ -394,7 +400,8 @@ - TLS: OSX now uses native TLS (`--tlsEmulation:off`), TLS now works with importcpp non-POD types, such types must use `.cppNonPod` and `--tlsEmulation:off`should be used. -- Now array literals(JS backend) uses JS typed arrays when the corresponding js typed array exists, for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. +- Now array literals(JS backend) uses JS typed arrays when the corresponding js typed array exists, + for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. - docgen: rst files can now use single backticks instead of double backticks and correctly render in both rst2html (as before) as well as common tools rendering rst directly (e.g. github), by @@ -426,6 +433,8 @@ the official Nim style guide. To be enabled, this has to be combined either with `--styleCheck:error` or `--styleCheck:hint`. + + ## Tool changes - The rst parser now supports markdown table syntax. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index f61fbdf2b..46b4fc948 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -236,7 +236,7 @@ proc hash*[T](x: ptr[T]): Hash {.inline.} = assert cast[pointer](a[0].addr).hash == a[0].addr.hash hash(cast[pointer](x)) -when not defined(nimLegacyNoHashRef): +when defined(nimEnableHashRef): proc hash*[T](x: ref[T]): Hash {.inline.} = ## Efficient `hash` overload. runnableExamples: diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 638f4241b..751509062 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -8,6 +8,7 @@ And we get here ''' joinable: false targets: "c cpp js" +matrix: "-d:nimEnableHashRef" """ # xxx wrap in a template to test in VM, see https://github.com/timotheecour/Nim/issues/534#issuecomment-769565033 diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 46576ef12..1e9b02d0c 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,5 +1,6 @@ discard """ targets: "c cpp js" + matrix: "-d:nimEnableHashRef" """ import std/hashes From 98ea61f09b4bfdc13c911b1ff3fb404dfc0d1338 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 30 May 2021 14:57:25 -0700 Subject: [PATCH 2636/4254] dont silence hints in system.nim (#18034) --- lib/system.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index be30665dd..942d29fe8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -112,7 +112,7 @@ proc compileOption*(option, arg: string): bool {. discard "compiled with optimization for size and uses Boehm's GC" {.push warning[GcMem]: off, warning[Uninit]: off.} -{.push hints: off.} +# {.push hints: off.} proc `or`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} ## Constructs an `or` meta class. @@ -2471,7 +2471,7 @@ proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} = quit(errorcode) {.pop.} # checks: off -{.pop.} # hints: off +# {.pop.} # hints: off proc `/`*(x, y: int): float {.inline, noSideEffect.} = ## Division of integers that results in a float. From 18b477431138d944b90e7a6e6e0412496634b518 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 31 May 2021 01:51:20 -0700 Subject: [PATCH 2637/4254] document macros.unpackVarargs (#18106) * deprecate macros.unpackVarargs * un-deprecate unpackVarargs and add docs+runnableExamples * update examples + tests with varargs[typed] --- lib/core/macros.nim | 15 ++++++++++ tests/destructor/tatomicptrs.nim | 1 + tests/stdlib/tmacros.nim | 50 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 79c3ba28b..89f90a23b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1682,6 +1682,21 @@ macro getCustomPragmaVal*(n: typed, cp: typed): untyped = error(n.repr & " doesn't have a pragma named " & cp.repr, n) macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped = + ## Calls `callee` with `args` unpacked as individual arguments. + ## This is useful in 2 cases: + ## * when forwarding `varargs[T]` for some typed `T` + ## * when forwarding `varargs[untyped]` when `args` can potentially be empty, + ## due to a compiler limitation + runnableExamples: + template call1(fun: typed; args: varargs[untyped]): untyped = + unpackVarargs(fun, args) + # when varargsLen(args) > 0: fun(args) else: fun() # this would also work + template call2(fun: typed; args: varargs[typed]): untyped = + unpackVarargs(fun, args) + proc fn1(a = 0, b = 1) = discard (a, b) + call1(fn1, 10, 11) + call1(fn1) # `args` is empty in this case + if false: call2(echo, 10, 11) # would print 1011 result = newCall(callee) for i in 0 ..< args.len: result.add args[i] diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim index 7313afbf5..36f0cab8a 100644 --- a/tests/destructor/tatomicptrs.nim +++ b/tests/destructor/tatomicptrs.nim @@ -72,6 +72,7 @@ template `.=`*[T](s: SharedPtr[T]; field, value: untyped) = from macros import unpackVarargs template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped = + # xxx this isn't used, the test should be improved unpackVarargs(s.x.field, args) diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index effe1032f..52ea1e898 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -10,3 +10,53 @@ block: # hasArgOfName block: # bug #17454 proc f(v: NimNode): string {.raises: [].} = $v + +block: # unpackVarargs + block: + proc bar1(a: varargs[int]): string = + for ai in a: result.add " " & $ai + proc bar2(a: varargs[int]) = + let s1 = bar1(a) + let s2 = unpackVarargs(bar1, a) # `unpackVarargs` makes no difference here + doAssert s1 == s2 + bar2(1, 2, 3) + bar2(1) + bar2() + + block: + template call1(fun: typed; args: varargs[untyped]): untyped = + unpackVarargs(fun, args) + template call2(fun: typed; args: varargs[untyped]): untyped = + # fun(args) # works except for last case with empty `args`, pending bug #9996 + when varargsLen(args) > 0: fun(args) + else: fun() + + proc fn1(a = 0, b = 1) = discard (a, b) + + call1(fn1) + call1(fn1, 10) + call1(fn1, 10, 11) + + call2(fn1) + call2(fn1, 10) + call2(fn1, 10, 11) + + block: + template call1(fun: typed; args: varargs[typed]): untyped = + unpackVarargs(fun, args) + template call2(fun: typed; args: varargs[typed]): untyped = + # xxx this would give a confusing error message: + # required type for a: varargs[typed] [varargs] but expression '[10]' is of type: varargs[typed] [varargs] + when varargsLen(args) > 0: fun(args) + else: fun() + macro toString(a: varargs[typed, `$`]): string = + var msg = genSym(nskVar, "msg") + result = newStmtList() + result.add quote do: + var `msg` = "" + for ai in a: + result.add quote do: `msg`.add $`ai` + result.add quote do: `msg` + doAssert call1(toString) == "" + doAssert call1(toString, 10) == "10" + doAssert call1(toString, 10, 11) == "1011" From 064fe18de61c2aae5c215077ba1dd0352affa271 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Mon, 31 May 2021 09:20:15 +0000 Subject: [PATCH 2638/4254] improve fast returns of find and rfind (#18127) --- lib/pure/strutils.nim | 4 +++- tests/stdlib/tstrutils.nim | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 5bbd850cc..3fb67ead1 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1890,7 +1890,7 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, ## See also: ## * `rfind func<#rfind,string,string,Natural>`_ ## * `replace func<#replace,string,string,string>`_ - if sub.len > s.len: return -1 + if sub.len > s.len - start: return -1 if sub.len == 1: return find(s, sub[0], start, last) template useSkipTable {.dirty.} = @@ -1967,6 +1967,8 @@ func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, ## * `find func<#find,string,string,Natural,int>`_ if sub.len == 0: return -1 + if sub.len > s.len - start: + return -1 let last = if last == -1: s.high else: last result = 0 for i in countdown(last - sub.len + 1, start): diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 771dddcaf..637661ba3 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -243,6 +243,34 @@ template main() = doAssert "/1/2/3".rfind('/', last=1) == 0 doAssert "/1/2/3".rfind('0') == -1 + block: + const haystack: string = "ABCABABABABCAB" + doAssert haystack.len == 14 + doAssert haystack.rfind("ABC") == 9 + doAssert haystack.rfind("ABC", last=13) == 9 + doAssert haystack.rfind("ABC", last=12) == 9 + doAssert haystack.rfind("ABC", last=11) == 9 + doAssert haystack.rfind("ABC", last=10) == 0 + + doAssert haystack.rfind("ABC", start=0) == 9 + doAssert haystack.rfind("ABC", start=1) == 9 + doAssert haystack.rfind("ABC", start=2) == 9 + doAssert haystack.rfind("ABC", start=9) == 9 + doAssert haystack.rfind("ABC", start=10) == -1 + doAssert haystack.rfind("ABC", start=11) == -1 + doAssert haystack.rfind("ABC", start=12) == -1 + + doAssert haystack.rfind("ABC", start=0, last=13) == 9 + doAssert haystack.rfind("ABC", start=0, last=12) == 9 + doAssert haystack.rfind("ABC", start=0, last=11) == 9 + doAssert haystack.rfind("ABC", start=0, last=10) == 0 + doAssert haystack.rfind("ABC", start=1, last=10) == -1 + + doAssert "".rfind("/") == -1 + doAssert "/".rfind("/") == 0 + doAssert "/".rfind("//") == -1 + doAssert "///".rfind("//", start=3) == -1 + block: # trimZeros var x = "1200" x.trimZeros() From b7ad29e692ffd9d12fdf4d42cd8ef2a63b9340d1 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 31 May 2021 04:27:44 -0700 Subject: [PATCH 2639/4254] fix #18113 (#18124) --- compiler/semtempl.nim | 8 ++++++-- tests/proc/t17157.nim | 1 + tests/template/t18113.nim | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/template/t18113.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 40502daf4..181cc01db 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -610,8 +610,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = s.owner.name.s == "vm" and s.name.s == "stackTrace": incl(s.flags, sfCallsite) - s.ast = n - styleCheckDef(c.config, s) onDef(n[namePos].info, s) # check parameter list: @@ -664,6 +662,12 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = semIdeForTemplateOrGeneric(c, n[bodyPos], ctx.cursorInBody) closeScope(c) popOwner(c) + + # set the symbol AST after pragmas, at least. This stops pragma that have + # been pushed (implicit) to be explicitly added to the template definition + # and misapplied to the body. see #18113 + s.ast = n + if sfCustomPragma in s.flags: if n[bodyPos].kind != nkEmpty: localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s) diff --git a/tests/proc/t17157.nim b/tests/proc/t17157.nim index 020e93fce..2927eeee8 100644 --- a/tests/proc/t17157.nim +++ b/tests/proc/t17157.nim @@ -1,5 +1,6 @@ discard """ errormsg: "'untyped' is only allowed in templates and macros or magic procs" + disabled: true """ template something(op: proc (v: untyped): void): void = diff --git a/tests/template/t18113.nim b/tests/template/t18113.nim new file mode 100644 index 000000000..a84b3fd0e --- /dev/null +++ b/tests/template/t18113.nim @@ -0,0 +1,14 @@ +# ensure template pragma handling doesn't eagerly attempt to add an implicit +# 'pushed' pragma to the evaluation of any intermediate AST prior to +# substitution. + +# bug #18113 + +import sequtils + +{.push raises: [Defect].} + +var a = toSeq([1, 2, 3, 5, 10]).filterIt(it > 5) + +doAssert a.len == 1 +doAssert a[0] == 10 From a36efb59b5a74db6c5bbe6c0997c0221d0f55491 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 31 May 2021 04:39:19 -0700 Subject: [PATCH 2640/4254] fix #16256: nimout: should give error (vacuously true); improve a few tests (#18089) * fix #16256: nimout: should give error (vacuously true); improve some tests * renamed: tests/stdlib/t9710.nim -> tests/misc/t9710.nim * improve tests * fix non-DRY tests * improve $nim_prs_D/tests/stdlib/t9091.nim * renamed: tests/stdlib/t9091.nim -> tests/misc/t9091.nim * fixup * address comment: doAssert => result.parseErrors --- testament/specs.nim | 5 ++ tests/{stdlib => misc}/t9091.nim | 15 +++--- tests/misc/t9710.nim | 6 +++ tests/stdlib/t9710.nim | 11 ---- tests/stdlib/tgetprotobyname.nim | 10 ---- tests/stdlib/tnativesockets.nim | 46 ++++++++--------- tests/stdlib/tvarints.nim | 86 +++++++++++++------------------- 7 files changed, 73 insertions(+), 106 deletions(-) rename tests/{stdlib => misc}/t9091.nim (70%) create mode 100644 tests/misc/t9710.nim delete mode 100644 tests/stdlib/t9710.nim diff --git a/testament/specs.nim b/testament/specs.nim index a3271aeaa..6fd0ab22d 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -253,6 +253,7 @@ proc parseSpec*(filename: string): TSpec = var p: CfgParser open(p, ss, filename, 1) var flags: HashSet[string] + var nimoutFound = false while true: var e = next(p) case e.kind @@ -309,6 +310,7 @@ proc parseSpec*(filename: string): TSpec = result.action = actionReject of "nimout": result.nimout = e.value + nimoutFound = true of "nimoutfull": result.nimoutFull = parseCfgBool(e.value) of "batchable": @@ -401,6 +403,9 @@ proc parseSpec*(filename: string): TSpec = if skips.anyIt(it in result.file): result.err = reDisabled + if nimoutFound and result.nimout.len == 0 and not result.nimoutFull: + result.parseErrors.addLine "empty `nimout` is vacuously true, use `nimoutFull:true` if intentional" + result.inCurrentBatch = isCurrentBatch(testamentData0, filename) or result.unbatchable if not result.inCurrentBatch: result.err = reDisabled diff --git a/tests/stdlib/t9091.nim b/tests/misc/t9091.nim similarity index 70% rename from tests/stdlib/t9091.nim rename to tests/misc/t9091.nim index 8419479a7..6e7a98ca5 100644 --- a/tests/stdlib/t9091.nim +++ b/tests/misc/t9091.nim @@ -1,10 +1,5 @@ -discard """ - targets: "c" - output: "test AObj" - action: "compile" - exitcode: 0 - timeout: 60.0 -""" +# bug #9091 + import streams block: @@ -18,6 +13,8 @@ block: let mi = new Mine str.write(mi) + str.setPosition 0 + doAssert str.readAll == "sure" block: type @@ -27,10 +24,10 @@ block: proc foo(a: int): string = "" proc test(args: varargs[string, foo]) = - echo "varargs" + doAssert false proc test(a: AObj) = - echo "test AObj" + discard let x = AObj() test(x) diff --git a/tests/misc/t9710.nim b/tests/misc/t9710.nim new file mode 100644 index 000000000..c65cb7bf4 --- /dev/null +++ b/tests/misc/t9710.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--debugger:native" +""" +# bug #9710 +for i in 1 || 200: + discard i diff --git a/tests/stdlib/t9710.nim b/tests/stdlib/t9710.nim deleted file mode 100644 index f3ed860df..000000000 --- a/tests/stdlib/t9710.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - cmd: "nim c -r --debugger:native --panics:on $options $file" - targets: "c" - nimout: "" - action: "run" - exitcode: 0 - timeout: 60.0 -""" - -for i in 1 || 200: - discard i diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim index b4df05102..0b60d059f 100644 --- a/tests/stdlib/tgetprotobyname.nim +++ b/tests/stdlib/tgetprotobyname.nim @@ -1,15 +1,5 @@ -discard """ - cmd: "nim c -r --styleCheck:hint --panics:on $options $file" - targets: "c" - nimout: "" - action: "run" - exitcode: 0 - timeout: 60.0 -""" - import nativesockets - when not defined(netbsd): # Ref: https://github.com/nim-lang/Nim/issues/15452 - NetBSD doesn't define an `ip` protocol doAssert getProtoByName("ip") == 0 diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim index b0cfd09cf..6a1a00881 100644 --- a/tests/stdlib/tnativesockets.nim +++ b/tests/stdlib/tnativesockets.nim @@ -1,29 +1,25 @@ -discard """ - cmd: "nim c -r --styleCheck:hint --panics:on $options $file" - targets: "c" - nimout: "" - action: "run" - exitcode: 0 - timeout: 60.0 -""" - -import nativesockets +import std/nativesockets +import stdtest/testutils +block: + let hostname = getHostname() + doAssert hostname.len > 0 when defined(windows): - doAssert toInt(IPPROTO_IP) == 0.cint - doAssert toInt(IPPROTO_ICMP) == 1.cint - doAssert toInt(IPPROTO_TCP) == 6.cint - doAssert toInt(IPPROTO_UDP) == 17.cint - doAssert toInt(IPPROTO_IPV6) == 41.cint - doAssert toInt(IPPROTO_ICMPV6) == 58.cint - doAssert toInt(IPPROTO_RAW) == 20.cint + assertAll: + toInt(IPPROTO_IP) == 0 + toInt(IPPROTO_ICMP) == 1 + toInt(IPPROTO_TCP) == 6 + toInt(IPPROTO_UDP) == 17 + toInt(IPPROTO_IPV6) == 41 + toInt(IPPROTO_ICMPV6) == 58 + toInt(IPPROTO_RAW) == 20 - # no changes to enum value - doAssert ord(IPPROTO_TCP) == 6 - doAssert ord(IPPROTO_UDP) == 17 - doAssert ord(IPPROTO_IP) == 18 - doAssert ord(IPPROTO_IPV6) == 19 - doAssert ord(IPPROTO_RAW) == 20 - doAssert ord(IPPROTO_ICMP) == 21 - doAssert ord(IPPROTO_ICMPV6) == 22 + # no changes to enum value + ord(IPPROTO_TCP) == 6 + ord(IPPROTO_UDP) == 17 + ord(IPPROTO_IP) == 18 + ord(IPPROTO_IPV6) == 19 + ord(IPPROTO_RAW) == 20 + ord(IPPROTO_ICMP) == 21 + ord(IPPROTO_ICMPV6) == 22 diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim index dcdb756ce..772121f9f 100644 --- a/tests/stdlib/tvarints.nim +++ b/tests/stdlib/tvarints.nim @@ -1,15 +1,6 @@ -discard """ - cmd: "nim c -r --styleCheck:hint --panics:on $options $file" - matrix: "-d:danger; -d:release" - targets: "c cpp" - nimout: "" - action: "run" - exitcode: 0 - timeout: 60.0 -""" - import std/varints +# xxx doesn't work with js: tvarints.nim(18, 14) `wrLen == rdLen` [AssertionDefect] block: var dest: array[50, byte] @@ -39,46 +30,39 @@ block: block: var hugeIntArray: array[50, byte] var readedInt: uint64 - doAssert writeVu64(hugeIntArray, 0.uint64) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == 0.uint64 - doAssert writeVu64(hugeIntArray, uint64.high) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == uint64.high - doAssert writeVu64(hugeIntArray, uint64(int64.high)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == uint64(int64.high) - doAssert writeVu64(hugeIntArray, uint64(int32.high)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == uint64(int32.high) - doAssert writeVu64(hugeIntArray, uint64(int16.high)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == uint64(int16.high) - doAssert writeVu64(hugeIntArray, uint64(int8.high)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == uint64(int8.high) - doAssert writeVu64(hugeIntArray, cast[uint64](0.0)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](0.0) - doAssert writeVu64(hugeIntArray, cast[uint64](-0.0)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](-0.0) - doAssert writeVu64(hugeIntArray, cast[uint64](0.1)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](0.1) - doAssert writeVu64(hugeIntArray, cast[uint64](0.9555555555555555555555501)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](0.9555555555555555555555501) - doAssert writeVu64(hugeIntArray, cast[uint64](+Inf)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](+Inf) - doAssert writeVu64(hugeIntArray, cast[uint64](NegInf)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](NegInf) - doAssert writeVu64(hugeIntArray, cast[uint64](Nan)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](Nan) - doAssert writeVu64(hugeIntArray, cast[uint64](3.1415926535897932384626433)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](3.1415926535897932384626433) - doAssert writeVu64(hugeIntArray, cast[uint64](2.71828182845904523536028747)) == readVu64(hugeIntArray, readedInt) - doAssert readedInt == cast[uint64](2.71828182845904523536028747) + + template chk(a) = + let b = cast[uint64](a) + doAssert writeVu64(hugeIntArray, b) == readVu64(hugeIntArray, readedInt) + doAssert readedInt == b + + chk 0 + chk uint64.high + chk int64.high + chk int32.high + chk int16.high + chk int16.high + chk int8.high + chk 0.0 + chk -0.0 + chk 0.1 + chk Inf + chk NegInf + chk Nan + chk 3.1415926535897932384626433 block: - doAssert encodeZigzag(decodeZigzag(0.uint64)) == 0.uint64 - doAssert encodeZigzag(decodeZigzag(uint64(uint32.high))) == uint64(uint32.high) - doAssert encodeZigzag(decodeZigzag(uint64(int32.high))) == uint64(int32.high) - doAssert encodeZigzag(decodeZigzag(uint64(int16.high))) == uint64(int16.high) - doAssert encodeZigzag(decodeZigzag(uint64(int8.high))) == uint64(int8.high) - doAssert encodeZigzag(decodeZigzag(cast[uint64](0.0))) == cast[uint64](0.0) - doAssert encodeZigzag(decodeZigzag(cast[uint64](0.1))) == cast[uint64](0.1) - doAssert encodeZigzag(decodeZigzag(cast[uint64](0.9555555555555555555555501))) == cast[uint64](0.9555555555555555555555501) - doAssert encodeZigzag(decodeZigzag(cast[uint64](+Inf))) == cast[uint64](+Inf) - doAssert encodeZigzag(decodeZigzag(cast[uint64](3.1415926535897932384626433))) == cast[uint64](3.1415926535897932384626433) - doAssert encodeZigzag(decodeZigzag(cast[uint64](2.71828182845904523536028747))) == cast[uint64](2.71828182845904523536028747) + template chk(a) = + let b = cast[uint64](a) + doAssert encodeZigzag(decodeZigzag(b)) == b + chk 0 + chk uint32.high + chk int32.high + chk int16.high + chk int8.high + chk 0.0 + chk 0.1 + chk 0.9555555555555555555555501 + chk Inf + chk 3.1415926535897932384626433 + chk 2.71828182845904523536028747 From 60cbdbf37ac66624f78edd5b3d575c80c6603679 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 31 May 2021 13:14:50 -0700 Subject: [PATCH 2641/4254] close #18092 document elif in case statements (#18105) * close #18092 [skip ci] document elif in case statements * fixup * clarify spec; mention special rule for string in case statements * address comments --- doc/manual.rst | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 6a0dec120..ff34b62ca 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2981,11 +2981,13 @@ Example: .. code-block:: nim - case readline(stdin) + let line = readline(stdin) + case line of "delete-everything", "restart-computer": echo "permission denied" of "go-for-a-walk": echo "please yourself" - else: echo "unknown command" + elif line.len == 0: echo "empty" # optional, must come after `of` branches + else: echo "unknown command" # ditto # indentation of the branches is also allowed; and so is an optional colon # after the selecting expression: @@ -2996,19 +2998,23 @@ Example: else: echo "unknown command" -The `case` statement is similar to the if statement, but it represents +The `case` statement is similar to the `if` statement, but it represents a multi-branch selection. The expression after the keyword `case` is evaluated and if its value is in a *slicelist* the corresponding statements (after the `of` keyword) are executed. If the value is not in any -given *slicelist* the `else` part is executed. If there is no `else` -part and not all possible values that `expr` can hold occur in a -*slicelist*, a static error occurs. This holds only for expressions of -ordinal types. "All possible values" of `expr` are determined by `expr`'s -type. To suppress the static error an `else` part with an -empty `discard` statement should be used. +given *slicelist*, trailing `elif` and `else` parts are executed using same +semantics as for `if` statement, and `elif` is handled just like `else: if`. +If there are no `else` or `elif` parts and not +all possible values that `expr` can hold occur in a *slicelist*, a static error occurs. +This holds only for expressions of ordinal types. +"All possible values" of `expr` are determined by `expr`'s type. +To suppress the static error an `else: discard` should be used. For non-ordinal types, it is not possible to list every possible value and so these always require an `else` part. +An exception to this rule is for the `string` type, which currently doesn't +require a trailing `else` or `elif` branch; it's unspecified whether this will +keep working in future versions. Because case statements are checked for exhaustiveness during semantic analysis, the value in every `of` branch must be a constant expression. @@ -3054,15 +3060,15 @@ won't work: var foo = Foo(x: @[]) foo.get_x().add("asd") -This can be fixed by explicitly using `return`: +This can be fixed by explicitly using `result` or `return`: .. code-block:: nim proc get_x(x: Foo): var seq[string] = case true of true: - return x.x + result = x.x else: - return x.x + result = x.x When statement From 9559350e34a62614d1f7de0945095a4c4f4f5ece Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 31 May 2021 13:16:33 -0700 Subject: [PATCH 2642/4254] add `os.getCacheDir` (#18126) * add `os.getCacheDir` * fixup * address comments --- changelog.md | 3 ++- lib/pure/os.nim | 44 ++++++++++++++++++++++++++++++++++++++------ tests/stdlib/tos.nim | 3 +++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 279ba38dd..d404b1965 100644 --- a/changelog.md +++ b/changelog.md @@ -175,10 +175,11 @@ - `--gc:orc` is now 10% faster than previously for common workloads. If you have trouble with its changed behavior, compile with `-d:nimOldOrc`. - - `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, determining preferred I/O block size for this file object. +- Added `os.getCacheDir()` to return platform specific cache directory. + - Added a simpler to use `io.readChars` overload. - Added `**` to jsffi. diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 287fbe125..c48d0d84f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -922,9 +922,7 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## See also: ## * `getHomeDir proc <#getHomeDir>`_ ## * `getTempDir proc <#getTempDir>`_ - ## * `expandTilde proc <#expandTilde,string>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getCacheDir proc <#getCacheDir>`_ runnableExamples: from std/strutils import endsWith # See `getHomeDir` for behavior regarding trailing DirSep. @@ -935,6 +933,42 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", result = getEnv("XDG_CONFIG_HOME", getEnv("HOME") / ".config") result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) +proc getCacheDir*(): string = + ## Returns the cache directory of the current user for applications. + ## + ## This makes use of the following environment variables: + ## + ## * On Windows: `getEnv("LOCALAPPDATA")` + ## + ## * On macOS: `getEnv("XDG_CACHE_HOME", getEnv("HOME") / "Library/Caches")` + ## + ## * On other platforms: `getEnv("XDG_CACHE_HOME", getEnv("HOME") / ".cache")` + ## + ## **See also:** + ## * `getHomeDir proc <#getHomeDir>`_ + ## * `getTempDir proc <#getTempDir>`_ + ## * `getConfigDir proc <#getConfigDir>`_ + # follows https://crates.io/crates/platform-dirs + when defined(windows): + result = getEnv("LOCALAPPDATA") + elif defined(osx): + result = getEnv("XDG_CACHE_HOME", getEnv("HOME") / "Library/Caches") + else: + result = getEnv("XDG_CACHE_HOME", getEnv("HOME") / ".cache") + result.normalizePathEnd(false) + +proc getCacheDir*(app: string): string = + ## Returns the cache directory for an application `app`. + ## + ## * On windows, this uses: `getCacheDir() / app / "cache"` + ## + ## * On other platforms, this uses: `getCacheDir() / app` + when defined(windows): + getCacheDir() / app / "cache" + else: + getCacheDir() / app + + when defined(windows): type DWORD = uint32 @@ -972,9 +1006,7 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", ## See also: ## * `getHomeDir proc <#getHomeDir>`_ ## * `getConfigDir proc <#getConfigDir>`_ - ## * `expandTilde proc <#expandTilde,string>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getCacheDir proc <#getCacheDir>`_ runnableExamples: from std/strutils import endsWith # See `getHomeDir` for behavior regarding trailing DirSep. diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 1fcee5a2e..b9769d05c 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -556,6 +556,9 @@ block getTempDir: else: doAssert getTempDir() == "/tmp" +block: # getCacheDir + doAssert getCacheDir().dirExists + block osenv: block delEnv: const dummyEnvVar = "DUMMY_ENV_VAR" # This env var wouldn't be likely to exist to begin with From 369a7d12467831295c12f5f51aa8c69ec3b3596a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 31 May 2021 13:17:52 -0700 Subject: [PATCH 2643/4254] jsonutils.toJson now serializes JsonNode as is by default (#18097) * jsonutils.toJson now serializes JsonNode as is (without deep copy nor treating it as a regular ref object) * JsonNodeMode --- changelog.md | 4 +++- lib/std/jsonutils.nim | 20 ++++++++++++++++---- tests/stdlib/tjsonutils.nim | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index d404b1965..9806a6011 100644 --- a/changelog.md +++ b/changelog.md @@ -69,7 +69,9 @@ previous behavior for a transition time, see PR #17467. - `jsonutils` now serializes/deserializes holey enums as regular enums (via `ord`) instead of as strings. - Use `-d:nimLegacyJsonutilsHoleyEnum` for a transition period. + Use `-d:nimLegacyJsonutilsHoleyEnum` for a transition period. `toJson` now serializes `JsonNode` + as is via reference (without a deep copy) instead of treating `JsonNode` as a regular ref object, + this can be customized via `jsonNodeMode`. - `json` and `jsonutils` now serialize NaN, Inf, -Inf as strings, so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` which was invalid json. diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 1e222e3a2..e33ae4401 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -48,13 +48,18 @@ type joptEnumOrd joptEnumSymbol joptEnumString + JsonNodeMode* = enum ## controls `toJson` for JsonNode types + joptJsonNodeAsRef ## returns the ref as is + joptJsonNodeAsCopy ## returns a deep copy of the JsonNode + joptJsonNodeAsObject ## treats JsonNode as a regular ref object ToJsonOptions* = object enumMode*: EnumMode - # xxx charMode + jsonNodeMode*: JsonNodeMode + # xxx charMode, etc proc initToJsonOptions*(): ToJsonOptions = ## initializes `ToJsonOptions` with sane options. - ToJsonOptions(enumMode: joptEnumOrd) + ToJsonOptions(enumMode: joptEnumOrd, jsonNodeMode: joptJsonNodeAsRef) proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} @@ -286,8 +291,15 @@ proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode = result = newJArray() for v in a.fields: result.add toJson(v, opt) elif T is ref | ptr: - if system.`==`(a, nil): result = newJNull() - else: result = toJson(a[], opt) + template impl = + if system.`==`(a, nil): result = newJNull() + else: result = toJson(a[], opt) + when T is JsonNode: + case opt.jsonNodeMode + of joptJsonNodeAsRef: result = a + of joptJsonNodeAsCopy: result = copy(a) + of joptJsonNodeAsObject: impl() + else: impl() elif T is array | seq | set: result = newJArray() for ai in a: result.add toJson(ai, opt) diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 62486b896..88c05facf 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -91,6 +91,28 @@ template fn() = doAssert b2.ord == 1 # explains the `1` testRoundtrip(a): """[1,2,3]""" + block: # JsonNode + let a = ((1, 2.5, "abc").toJson, (3, 4.5, "foo")) + testRoundtripVal(a): """[[1,2.5,"abc"],[3,4.5,"foo"]]""" + + block: + template toInt(a): untyped = cast[int](a) + + let a = 3.toJson + let b = (a, a) + + let c1 = b.toJson + doAssert c1[0].toInt == a.toInt + doAssert c1[1].toInt == a.toInt + + let c2 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsCopy)) + doAssert c2[0].toInt != a.toInt + doAssert c2[1].toInt != c2[0].toInt + doAssert c2[1] == c2[0] + + let c3 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsObject)) + doAssert $c3 == """[{"isUnquoted":false,"kind":2,"num":3},{"isUnquoted":false,"kind":2,"num":3}]""" + block: # ToJsonOptions let a = (me1, me2) doAssert $a.toJson() == "[1,2]" From 06d50bfd4cac6611c5fc775c8130cad87e4dcee1 Mon Sep 17 00:00:00 2001 From: Dylan Modesitt Date: Mon, 31 May 2021 16:51:32 -0400 Subject: [PATCH 2644/4254] Fixes #5034 illformed AST from getImpl with proc returning value (#17976) * Fixes 5034 * address comments --- compiler/semstmts.nim | 25 +++++++++++++++++++++---- tests/macros/tmacrogetimpl.nim | 31 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 tests/macros/tmacrogetimpl.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b4630294b..085146f7f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1439,16 +1439,33 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = else: localError(c.config, n.info, errNoSymbolToBorrowFromFound) +proc swapResult(n: PNode, sRes: PSym, dNode: PNode) = + ## Swap nodes that are (skResult) symbols to d(estination)Node. + for i in 0.. resultPos and n[resultPos] != nil: - if n[resultPos].sym.kind != skResult or n[resultPos].sym.owner != getCurrOwner(c): + if n[resultPos].sym.kind != skResult: localError(c.config, n.info, "incorrect result proc symbol") + if n[resultPos].sym.owner != getCurrOwner(c): + # re-write result with new ownership, and re-write the proc accordingly + let sResSym = n[resultPos].sym + genResSym(s) + n[resultPos] = newSymNode(s) + swapResult(n, sResSym, n[resultPos]) c.p.resultSym = n[resultPos].sym else: - var s = newSym(skResult, getIdent(c.cache, "result"), nextSymId c.idgen, getCurrOwner(c), n.info) - s.typ = t - incl(s.flags, sfUsed) + genResSym(s) c.p.resultSym = s n.add newSymNode(c.p.resultSym) addParamOrResult(c, c.p.resultSym, owner) diff --git a/tests/macros/tmacrogetimpl.nim b/tests/macros/tmacrogetimpl.nim new file mode 100644 index 000000000..1d996ff29 --- /dev/null +++ b/tests/macros/tmacrogetimpl.nim @@ -0,0 +1,31 @@ +import macros + +# bug #5034 + +macro copyImpl(srsProc: typed, toSym: untyped) = + result = copyNimTree(getImplTransformed(srsProc)) + result[0] = ident $toSym.toStrLit() + +proc foo1(x: float, one: bool = true): float = + if one: + return 1'f + result = x + +proc bar1(what: string): string = + ## be a little more adversarial with `skResult` + proc buzz: string = + result = "lightyear" + if what == "buzz": + result = "buzz " & buzz() + else: + result = what + return result + +copyImpl(foo1, foo2) +doAssert foo1(1'f) == 1.0 +doAssert foo2(10.0, false) == 10.0 +doAssert foo2(10.0) == 1.0 + +copyImpl(bar1, bar2) +doAssert bar1("buzz") == "buzz lightyear" +doAssert bar1("macros") == "macros" From c0e8199acc9f49caa36bae34d103600d112b66f3 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 1 Jun 2021 05:28:22 +0800 Subject: [PATCH 2645/4254] [std/re] fix findBounds and find procs (#18028) * [std/re] make interface consistent * tiny * revert --- lib/impure/re.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 0c96876b9..40860cc88 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -171,7 +171,7 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[tuple[first, last: int]], - start = 0, bufSize = 0): tuple[first, last: int] = + start = 0, bufSize: int): tuple[first, last: int] = ## returns the starting position and end position of `pattern` in `buf` ## (where `buf` has length `bufSize` and is not necessarily `'\0'` terminated), ## and the captured substrings in the array `matches`. @@ -290,7 +290,7 @@ proc match*(buf: cstring, pattern: Regex, matches: var openArray[string], result = matchLen(buf, pattern, matches, start, bufSize) != -1 proc find*(buf: cstring, pattern: Regex, matches: var openArray[string], - start = 0, bufSize = 0): int = + start = 0, bufSize: int): int = ## returns the starting position of `pattern` in `buf` and the captured ## substrings in the array `matches`. If it does not match, nothing ## is written into `matches` and `-1` is returned. From c2e3dc0ed16a854981769b426e9e327663447df7 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 2 Jun 2021 00:16:25 +0800 Subject: [PATCH 2646/4254] close #18129 Add setCurrentException for JS backend (#18145) * [std/re] make interface consistent * tiny * revert * close #18129 add setCurrentException * changelog entry --- changelog.md | 2 +- lib/system/jssys.nim | 3 +++ tests/exception/tsetexceptions.nim | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/exception/tsetexceptions.nim diff --git a/changelog.md b/changelog.md index 9806a6011..900b23ad8 100644 --- a/changelog.md +++ b/changelog.md @@ -329,7 +329,7 @@ - Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place. - +- Added setCurrentException for JS backend. ## Language changes diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index ef06437e5..371cb7962 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -69,6 +69,9 @@ proc getCurrentExceptionMsg*(): string = return $msg return "" +proc setCurrentException*(exc: ref Exception) = + lastJSError = cast[PJSError](exc) + proc auxWriteStackTrace(f: PCallFrame): string = type TempFrame = tuple[procname: cstring, line: int, filename: cstring] diff --git a/tests/exception/tsetexceptions.nim b/tests/exception/tsetexceptions.nim new file mode 100644 index 000000000..557fc1898 --- /dev/null +++ b/tests/exception/tsetexceptions.nim @@ -0,0 +1,8 @@ +discard """ + targets: "c cpp js" +""" + +let ex = newException(CatchableError, "test") +setCurrentException(ex) +doAssert getCurrentException().msg == ex.msg +doAssert getCurrentExceptionMsg() == ex.msg From ba3ec7b04954a9a60adb6e1a64405f7644f799ee Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 1 Jun 2021 21:47:23 +0300 Subject: [PATCH 2647/4254] docs: Latex generation improvements (#18141) * docs: improve Latex generation * make it work on Windows + fix ] escaping * minor fixes with escapes and style --- compiler/docgen.nim | 2 +- config/nimdoc.tex.cfg | 202 ++++++++++++++++++++++--------- lib/packages/docutils/rstast.nim | 18 ++- lib/packages/docutils/rstgen.nim | 140 +++++++++++---------- tests/stdlib/trstgen.nim | 4 +- tools/kochdocs.nim | 14 +-- 6 files changed, 252 insertions(+), 128 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e07db9188..18c568ba0 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -549,7 +549,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var string, var msg = "Example:" if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd dispA(d.conf, dest, "\n

    $1

    \n", - "\n\\textbf{$1}\n", [msg]) + "\n\n\\textbf{$1}\n", [msg]) inc d.listingCounter let id = $d.listingCounter dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index b19b25678..75382ce26 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -8,7 +8,8 @@ split.item.toc = "20" # after this number of characters doc.section = """ -\rsthA{$sectionTitle}\label{$sectionID} +\rsthA[$sectionTitle]{$sectionTitle}\label{$sectionID} + $content """ @@ -17,12 +18,16 @@ doc.section.toc = "" doc.item = """ +\vspace{1em} \phantomsection\addcontentsline{toc}{subsection}{$uniqueName} -\begin{rstpre} +\begin{rstdocitem} $header -\end{rstpre} +\end{rstdocitem} + +\begin{addmargin}[0.05\linewidth]{0pt} $desc +\end{addmargin} """ doc.item.toc = "" @@ -42,46 +47,118 @@ $content # $1 - number of listing in document, $2 - language (e.g. langNim), $3 - anchor doc.listing_start = "\\begin{rstpre}\n" -doc.listing_end = "\n\\end{rstpre}\n" +doc.listing_end = "\n\\end{rstpre}\n\n" doc.file = """ % This file was generated by Nim. % Generated: $date $time UTC -\documentclass[a4paper]{article} -\usepackage[left=2cm,right=3cm,top=3cm,bottom=3cm]{geometry} -\usepackage[utf8]{inputenc} -\usepackage[T1]{fontenc} +% +% Compile it by: xelatex (up to 3 times to get labels generated) +% ------- +% +\documentclass[a4paper,11pt]{article} +\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry} + +% for 2-sided printing with larger inner "binding" margin +%\usepackage[a4paper,xetex,twoside,left=4cm,right=2cm,top=1.5cm,bottom=2cm]{geometry} +% for e-readers with 1.77:1 aspect ratio (e.g. 1920x1080) +%\usepackage[xetex,paperheight=27.6cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} +% for e-readers with 1.45:1 aspect ratio (e.g. 1200x825) +%\usepackage[xetex,paperheight=22.5cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} +% for e-readers with 1.33:1 aspect ratio (e.g. 1872x1404) +%\usepackage[xetex,paperheight=20.7cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} + +\usepackage{fontspec} +% logic to select default font with some fall-back fonts. +\IfFontExistsTF{Times New Roman}{% + \setmainfont{Times New Roman} % the default font + \typeout{========================================= nim: using Times New Roman} +}{ + \IfFontExistsTF{FreeSerif}{% + \setmainfont{FreeSerif} % fallback #1 - official GNU font, resembles Times + \typeout{========================================= nim: using FreeSerif} + }{ + \IfFontExistsTF{DejaVuSerif}{% + \setmainfont{DejaVuSerif} % fallback #2 - very widespread free font + \typeout{========================================= nim: using DejaVuSerif} + }{ + \typeout{!!!!!!!!!!!!!!!!!!! Fonts not found !!!!!!!!!!!!!!!!!!!!!!!} + } + } +} + +% default monospace font for code: +\usepackage{GoMono} +\usepackage{relsize} +% make this monospace font 2 steps smaller to hold 80-character line +\newcommand{\rstverbblockfont}{\smaller[2]} +\newcommand{\rstverbinlinefont}{\smaller} + +\usepackage{parskip} % paragraphs delimited by vertical space, no indent \usepackage{graphicx} -\usepackage{lmodern} -\usepackage{fancyvrb, courier} -\usepackage{tabularx} -\usepackage{hyperref} -\usepackage{enumitem} % for option list, enumList, and rstfootnote + +\usepackage{dingbat} % for \carriagereturn, etc +\usepackage{fvextra} % for code blocks (works better than original fancyvrb) +\fvset{ + breaklines, + breakafter={=}:|\_\{\}[](){,}.;+-*/'", + breaksymbolleft=\color{red}{\ensuremath{\hookrightarrow}}, + breaksymbolright=\color{red}{\small\carriagereturn} +} +\fvinlineset{% + breaklines, + breakafter={=}:|\_\{\}[](){,}.;+-*/'", + % that does not work at all when we underline inline code by ulem :-( + commandchars=\\\{\} +} + +\usepackage{scrextend} % for the `addmargin` environment \usepackage{xcolor} -\usepackage[tikz]{mdframed} -\usetikzlibrary{shadows} -\mdfsetup{% -linewidth=3, -topline=false, -rightline=false, -bottomline=false} +\usepackage[urlbordercolor=blue,linkbordercolor=cyan, + pdfborderstyle={/S/U/W 1}]{hyperref} +\usepackage{enumitem} % for option list, enumList, and rstfootnote -\begin{document} -\title{$title $version $subtitle} -\author{$author} +\usepackage[most]{tcolorbox} % boxes around admonitions, code blocks, doc.item -\tolerance 1414 -\hbadness 1414 -\emergencystretch 1.5em -\hfuzz 0.3pt -\widowpenalty=10000 -\vfuzz \hfuzz -\raggedbottom +\newtcolorbox{rstadmonition}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + before upper=\indent, parbox=false, #1} + +\definecolor{rstframecolor}{rgb}{0.85, 0.8, 0.6} + +\newtcolorbox{rstprebox}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + borderline ={0.1em}{0pt}{rstframecolor}, + before upper=\indent, parbox=false, #1} + +\newenvironment{rstpre}{% +\VerbatimEnvironment\begingroup\begin{rstprebox}% +\begin{Verbatim}[fontsize=\rstverbblockfont , commandchars=\\\{\}]}% +{\end{Verbatim}\end{rstprebox}\endgroup} + +\newtcolorbox{rstdocitembox}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + borderline ={1pt}{0pt}{cyan}, + before upper=\indent, parbox=false, #1} + +% Inline code formatting: grey underline, +% use \Verb from fvextras e.g. to display -- correctly as double - +\usepackage[normalem]{ulem} +\newcommand\rstuline{\bgroup\markoverwith{\textcolor{rstframecolor}{\rule[-0.8ex]{2pt}{1.0pt}}}\ULon} + +\newcommand{\rstcode}[1]{% +{\rstverbinlinefont\Verb{\rstuline{#1}}}% +} + +\newcommand{\rstcodeitem}[1]{\Verb{#1}} + +\newenvironment{rstdocitem}{% +\VerbatimEnvironment\begingroup\begin{rstdocitembox}% +\begin{Verbatim}[fontsize=\rstverbblockfont , commandchars=\\\{\}]}% +{\end{Verbatim}\end{rstdocitembox}\endgroup} -\maketitle -\newenvironment{rstpre}{\VerbatimEnvironment\begingroup\begin{Verbatim}[fontsize=\footnotesize , commandchars=\\\{\}]}{\end{Verbatim}\endgroup} \newenvironment{rstfootnote}{\begin{description}[labelindent=1em,leftmargin=1em,labelwidth=2.6em]}{\end{description}} \ifdim\linewidth<30em \def\rstoptleftmargin{0.4\linewidth} @@ -93,37 +170,41 @@ bottomline=false} \newenvironment{rstoptlist}{% \begin{description}[font=\sffamily\bfseries,style=nextline,leftmargin=\rstoptleftmargin,labelwidth=\rstoptlabelwidth]}{\end{description}} -% to pack tabularx into a new environment, special syntax is needed :-( -\newenvironment{rsttab}[1]{\tabularx{\linewidth}{#1}}{\endtabularx} +\usepackage{tabulary} % tables with adjustable cell width and no overflow +% make tabulary prevent overflows (https://tex.stackexchange.com/a/195088) +\tymin=60pt +\tymax=\maxdimen +% to pack tabulary into a new environment, special syntax is needed :-( +\newenvironment{rsttab}[1]{\tabulary{\linewidth}{#1}}{\endtabulary} \newcommand{\rstsub}[1]{\raisebox{-0.5ex}{\scriptsize{#1}}} \newcommand{\rstsup}[1]{\raisebox{0.5ex}{\scriptsize{#1}}} -\newcommand{\rsthA}[1]{\section{#1}} -\newcommand{\rsthB}[1]{\subsection{#1}} -\newcommand{\rsthC}[1]{\subsubsection{#1}} -\newcommand{\rsthD}[1]{\paragraph{#1}} -\newcommand{\rsthE}[1]{\paragraph{#1}} +\newcommand{\rsthA}[2][]{\section[#1]{#2}} +\newcommand{\rsthB}[2][]{\subsection[#1]{#2}} +\newcommand{\rsthC}[2][]{\subsubsection[#1]{#2}} +\newcommand{\rsthD}[2][]{\paragraph[#1]{#2}} +\newcommand{\rsthE}[2][]{\paragraph[#1]{#2}} -\newcommand{\rstovA}[1]{\section*{#1}} -\newcommand{\rstovB}[1]{\subsection*{#1}} -\newcommand{\rstovC}[1]{\subsubsection*{#1}} -\newcommand{\rstovD}[1]{\paragraph*{#1}} -\newcommand{\rstovE}[1]{\paragraph*{#1}} +\newcommand{\rstovA}[2][]{\section*[#1]{#2}} +\newcommand{\rstovB}[2][]{\subsection*[#1]{#2}} +\newcommand{\rstovC}[2][]{\subsubsection*[#1]{#2}} +\newcommand{\rstovD}[2][]{\paragraph*[#1]{#2}} +\newcommand{\rstovE}[2][]{\paragraph*[#1]{#2}} % Syntax highlighting: -\newcommand{\spanDecNumber}[1]{#1} -\newcommand{\spanBinNumber}[1]{#1} -\newcommand{\spanHexNumber}[1]{#1} -\newcommand{\spanOctNumber}[1]{#1} -\newcommand{\spanFloatNumber}[1]{#1} +\newcommand{\spanDecNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanBinNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanHexNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanOctNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanFloatNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} \newcommand{\spanIdentifier}[1]{#1} \newcommand{\spanKeyword}[1]{\textbf{#1}} -\newcommand{\spanStringLit}[1]{#1} -\newcommand{\spanLongStringLit}[1]{#1} +\newcommand{\spanStringLit}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanLongStringLit}[1]{\textbf{\textcolor{darkgray}{#1}}} \newcommand{\spanCharLit}[1]{#1} \newcommand{\spanEscapeSequence}[1]{#1} -\newcommand{\spanOperator}[1]{#1} +\newcommand{\spanOperator}[1]{\textbf{#1}} \newcommand{\spanPunctuation}[1]{#1} \newcommand{\spanComment}[1]{\emph{#1}} \newcommand{\spanLongComment}[1]{\emph{#1}} @@ -132,7 +213,7 @@ bottomline=false} \newcommand{\spanTagEnd}[1]{#1} \newcommand{\spanKey}[1]{#1} \newcommand{\spanValue}[1]{#1} -\newcommand{\spanRawData}[1]{#1} +\newcommand{\spanRawData}[1]{\textbf{\textcolor{darkgray}{#1}}} \newcommand{\spanAssembler}[1]{#1} \newcommand{\spanPreprocessor}[1]{#1} \newcommand{\spanDirective}[1]{#1} @@ -142,11 +223,20 @@ bottomline=false} \newcommand{\spanLabel}[1]{#1} \newcommand{\spanReference}[1]{#1} \newcommand{\spanOther}[1]{#1} -\newcommand{\spantok}[1]{\frame{#1}} +\newcommand{\spantok}[1]{\fbox{#1}} \newcommand{\spanPrompt}[1]{\textcolor{red}{\textbf{#1}}} -\newcommand{\spanProgramOutput}[1]{\textcolor{gray}{\textbf{#1}}} +\newcommand{\spanProgramOutput}[1]{\textcolor{darkgray}{\textbf{#1}}} \newcommand{\spanprogram}[1]{\textbf{\underline{#1}}} -\newcommand{\spanoption}[1]{\textbf{#1}} +\newcommand{\spanoption}[1]{\textbf{\textcolor{darkgray}{#1}}} + +\begin{document} +\title{$title $version $subtitle} +\author{$author} + +% Never allow text overflow to margin: +\setlength\emergencystretch{\hsize}\hbadness=10000 + +\maketitle $content \end{document} diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 81e3ba6d9..2489ce40c 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -349,8 +349,24 @@ proc renderRstToJson*(node: PRstNode): string = ## } renderRstToJsonNode(node).pretty +proc renderRstToText*(node: PRstNode): string = + ## minimal text representation of markup node + const code = {rnCodeFragment, rnInterpretedText, rnInlineLiteral, rnInlineCode} + if node == nil: + return "" + case node.kind + of rnLeaf, rnSmiley: + result.add node.text + else: + if node.kind in code: result.add "`" + for i in 0 ..< node.sons.len: + if node.kind in {rnInlineCode, rnCodeBlock} and i == 0: + continue # omit language specifier + result.add renderRstToText(node.sons[i]) + if node.kind in code: result.add "`" + proc renderRstToStr*(node: PRstNode, indent=0): string = - ## Writes the parsed RST `node` into a compact string + ## Writes the parsed RST `node` into an AST tree with compact string ## representation in the format (one line per every sub-node): ## ``indent - kind - [text|level|order|adType] - anchor (if non-zero)`` ## (suitable for debugging of RST parsing). diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 5ab6f28ee..e3f889283 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -60,6 +60,10 @@ type MetaEnum* = enum metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion + EscapeMode = enum # in Latex text inside options [] and URLs is + # escaped slightly differently than in normal text + emText, emOption, emUrl # emText is currently used for code also + RstGenerator* = object of RootObj target*: OutputTarget config*: StringTableRef @@ -84,6 +88,7 @@ type id*: int ## A counter useful for generating IDs. onTestSnippet*: proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) + escMode*: EscapeMode PDoc = var RstGenerator ## Alias to type less. @@ -161,6 +166,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, g.findFile = findFile g.currentSection = "" g.id = 0 + g.escMode = emText let fileParts = filename.splitFile if fileParts.ext == ".nim": g.currentSection = "Module " & fileParts.name @@ -189,28 +195,34 @@ proc addHtmlChar(dest: var string, c: char) = of '\"': add(dest, """) else: add(dest, c) -proc addRtfChar(dest: var string, c: char) = +proc addTexChar(dest: var string, c: char, escMode: EscapeMode) = + ## Escapes 10 special Latex characters and sometimes ` and [, ]. + ## TODO: @ is always a normal symbol (besides the header), am I wrong? + ## All escapes that need to work in text and code blocks (`emText` mode) + ## should start from \ (to be compatible with fancyvrb/fvextra). case c - of '{': add(dest, "\\{") - of '}': add(dest, "\\}") - of '\\': add(dest, "\\\\") - else: add(dest, c) - -proc addTexChar(dest: var string, c: char) = - # Escapes 10 special Latex characters. Note that [, ], and ` are not - # considered as such. TODO: neither is @, am I wrong? - case c - of '_', '{', '}', '$', '&', '#', '%': add(dest, "\\" & c) + of '_', '$', '&', '#', '%': add(dest, "\\" & c) # \~ and \^ have a special meaning unless they are followed by {} of '~', '^': add(dest, "\\" & c & "{}") + # Latex loves to substitute ` to opening quote, even in texttt mode! + of '`': add(dest, "\\textasciigrave{}") # add {} to avoid gobbling up space by \textbackslash of '\\': add(dest, "\\textbackslash{}") + # Using { and } in URL in Latex: https://tex.stackexchange.com/a/469175 + of '{': + add(dest, if escMode == emUrl: "\\%7B" else: "\\{") + of '}': + add(dest, if escMode == emUrl: "\\%7D" else: "\\}") + of ']': + # escape ] inside an optional argument in e.g. \section[static[T]]{.. + add(dest, if escMode == emOption: "\\text{]}" else: "]") else: add(dest, c) -proc escChar*(target: OutputTarget, dest: var string, c: char) {.inline.} = +proc escChar*(target: OutputTarget, dest: var string, + c: char, escMode: EscapeMode) {.inline.} = case target of outHtml: addHtmlChar(dest, c) - of outLatex: addTexChar(dest, c) + of outLatex: addTexChar(dest, c, escMode) proc addSplitter(target: OutputTarget; dest: var string) {.inline.} = case target @@ -229,7 +241,7 @@ proc nextSplitPoint*(s: string, start: int): int = inc(result) dec(result) # last valid index -proc esc*(target: OutputTarget, s: string, splitAfter = -1): string = +proc esc*(target: OutputTarget, s: string, splitAfter = -1, escMode = emText): string = ## Escapes the HTML. result = "" if splitAfter >= 0: @@ -240,11 +252,11 @@ proc esc*(target: OutputTarget, s: string, splitAfter = -1): string = #if (splitter != " ") or (partLen + k - j + 1 > splitAfter): partLen = 0 addSplitter(target, result) - for i in countup(j, k): escChar(target, result, s[i]) + for i in countup(j, k): escChar(target, result, s[i], escMode) inc(partLen, k - j + 1) j = k + 1 else: - for i in countup(0, len(s) - 1): escChar(target, result, s[i]) + for i in countup(0, len(s) - 1): escChar(target, result, s[i], escMode) proc disp(target: OutputTarget, xml, tex: string): string = @@ -760,6 +772,8 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = sectionPrefix = rstnodeToRefname(n2) & "-" break var refname = sectionPrefix & rstnodeToRefname(n) + var tocName = esc(d.target, renderRstToText(n), escMode = emOption) + # for Latex: simple text without commands that may break TOC/hyperref if d.hasToc: var length = len(d.tocPart) setLen(d.tocPart, length + 1) @@ -768,13 +782,14 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = d.tocPart[length].header = tmp dispA(d.target, result, "\n$3", "\\rsth$4{$3}$2\n", - [$n.level, refname.idS, tmp, $chr(n.level - 1 + ord('A')), refname]) + "$2 href=\"#$5\">$3", "\\rsth$4[$6]{$3}$2\n", + [$n.level, refname.idS, tmp, + $chr(n.level - 1 + ord('A')), refname, tocName]) else: dispA(d.target, result, "\n$3", - "\\rsth$4{$3}$2\n", [ + "\\rsth$4[$5]{$3}$2\n", [ $n.level, refname.idS, tmp, - $chr(n.level - 1 + ord('A'))]) + $chr(n.level - 1 + ord('A')), tocName]) # Generate index entry using spaces to indicate TOC level for the output HTML. assert n.level >= 0 @@ -802,9 +817,10 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) = var tmp = "" for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp) d.currentSection = tmp + var tocName = esc(d.target, renderRstToText(n), escMode=emOption) dispA(d.target, result, "
    $3
    ", - "\\rstov$4{$3}$2\n", [$n.level, - rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A'))]) + "\\rstov$4[$5]{$3}$2\n", [$n.level, + rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName]) proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) = @@ -870,7 +886,7 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = htmlOut = "" # support for `:target:` links for images: - var target = esc(d.target, getFieldValue(n, "target").strip()) + var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl) if target.len > 0: # `htmlOut` needs to be of the following format for link to work for images: # @@ -1031,16 +1047,16 @@ proc renderCode(d: PDoc, n: PRstNode, result: var string) = blockEnd = "
    " of outLatex: if n.kind == rnCodeBlock: - blockStart = "\n\n\\begin{rstpre}" & n.anchor.idS & "\n" - blockEnd = "\n\\end{rstpre}\n" + blockStart = "\n\n" & n.anchor.idS & "\\begin{rstpre}\n" + blockEnd = "\n\\end{rstpre}\n\n" else: # rnInlineCode - blockStart = "\\texttt{" + blockStart = "\\rstcode{" blockEnd = "}" dispA(d.target, result, blockStart, blockStart, []) if params.lang == langNone: if len(params.langStr) > 0: d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr) - for letter in m.text: escChar(d.target, result, letter) + for letter in m.text: escChar(d.target, result, letter, emText) else: renderCodeLang(result, params.lang, m.text, d.target) dispA(d.target, result, blockEnd, blockEnd) @@ -1055,9 +1071,8 @@ proc renderContainer(d: PDoc, n: PRstNode, result: var string) = dispA(d.target, result, "
    $2
    ", "$2", [arg, tmp]) proc texColumns(n: PRstNode): string = - result = "" let nColumns = if n.sons.len > 0: len(n.sons[0]) else: 1 - for i in countup(1, nColumns): add(result, "|X") + result = "L".repeat(nColumns) proc renderField(d: PDoc, n: PRstNode, result: var string) = var b = false @@ -1144,19 +1159,38 @@ proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, htmlHead & "" & txt & ":\n" & "$1\n", - "\n\n\\begin{mdframed}[linecolor=" & texColor & "]$2\n" & + "\n\n\\begin{rstadmonition}[borderline west={0.2em}{0pt}{" & + texColor & "}]$2\n" & "{" & texSz & "\\color{" & texColor & "}{\\textbf{" & txt & ":}}} " & - "$1\n\\end{mdframed}\n", + "$1\n\\end{rstadmonition}\n", result) +proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external: bool) = + var linkStr = "" + block: + let mode = d.escMode + d.escMode = emUrl + renderRstToOut(d, link, linkStr) + d.escMode = mode + var textStr = "" + renderRstToOut(d, text, textStr) + if external: + dispA(d.target, result, + "$1", + "\\href{$2}{$1}", [textStr, linkStr]) + else: + dispA(d.target, result, + "$1", + "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [textStr, linkStr]) + proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = if n == nil: return case n.kind of rnInner: renderAux(d, n, result) of rnHeadline, rnMarkdownHeadline: renderHeadline(d, n, result) of rnOverline: renderOverline(d, n, result) - of rnTransition: renderAux(d, n, "\n", "\\hrule$2\n", result) - of rnParagraph: renderAux(d, n, "$1

    \n", "$2\n$1\n\n", result) + of rnTransition: renderAux(d, n, "\n", "\n\n\\vspace{0.6em}\\hrule$2\n", result) + of rnParagraph: renderAux(d, n, "$1

    \n", "\n\n$2\n$1\n\n", result) of rnBulletList: renderAux(d, n, "$1\n", "\\begin{itemize}\n$2\n$1\\end{itemize}\n", result) @@ -1202,7 +1236,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "
    " & "$1
    ", - "\\item[$1]", result) + "\\item[\\rstcodeitem{\\spanoption{$1}}]", result) of rnDescription: renderAux(d, n, "
    $1
    ", " $1\n", result) @@ -1210,7 +1244,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = doAssert false, "renderRstToOut" of rnLiteralBlock: renderAux(d, n, "$1
    \n", - "\\begin{rstpre}\n$2\n$1\n\\end{rstpre}\n", result) + "\n\n\\begin{rstpre}\n$2\n$1\n\\end{rstpre}\n\n", result) of rnQuotedLiteralBlock: doAssert false, "renderRstToOut" of rnLineBlock: @@ -1237,8 +1271,8 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnTable, rnGridTable, rnMarkdownTable: renderAux(d, n, "$1", - "\\begin{table}\n$2\n\\begin{rsttab}{" & - texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result) + "\n$2\n\\begin{rsttab}{" & + texColumns(n) & "}\n\\hline\n$1\\end{rsttab}", result) of rnTableRow: if len(n) >= 1: if d.target == outLatex: @@ -1275,21 +1309,13 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = "\\item[\\textsuperscript{[$3]}]$2 $1\n", [body, n.anchor.idS, mark, n.anchor]) of rnRef: - var tmp = "" - renderAux(d, n, tmp) - dispA(d.target, result, - "$1", - "$1\\ref{$2}", [tmp, rstnodeToRefname(n)]) + renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=false) of rnStandaloneHyperlink: - renderAux(d, n, - "$1", - "\\href{$1}{$1}", result) + renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=true) of rnInternalRef: - var tmp = "" - renderAux(d, n.sons[0], tmp) - dispA(d.target, result, - "$1", - "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [tmp, n.sons[1].text]) + renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false) + of rnHyperlink: + renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=true) of rnFootnoteRef: var tmp = "[" renderAux(d, n.sons[0], tmp) @@ -1299,14 +1325,6 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = "$1", "\\textsuperscript{\\hyperlink{$2}{\\textbf{$1}}}", [tmp, n.sons[1].text]) - of rnHyperlink: - var tmp0 = "" - var tmp1 = "" - renderRstToOut(d, n.sons[0], tmp0) - renderRstToOut(d, n.sons[1], tmp1) - dispA(d.target, result, - "$1", - "\\href{$2}{$1}", [tmp0, tmp1]) of rnDirArg, rnRaw: renderAux(d, n, result) of rnRawHtml: if d.target != outLatex and not lastSon(n).isNil: @@ -1334,7 +1352,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = dispA(d.target, result, "" & "$1", - "\\texttt{\\span$2{$1}}", [tmp0, class]) + "\\rstcode{\\span$2{$1}}", [tmp0, class]) else: # rnUnknownRole, not necessarily code/monospace font dispA(d.target, result, "$1", "\\span$2{$1}", [tmp0, class]) @@ -1351,7 +1369,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnInlineLiteral, rnInterpretedText: renderAux(d, n, "$1", - "\\texttt{$1}", result) + "\\rstcode{$1}", result) of rnInlineTarget: var tmp = "" renderAux(d, n, tmp) @@ -1360,7 +1378,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = "\\label{$2}\\hypertarget{$2}{$1}", [tmp, rstnodeToRefname(n)]) of rnSmiley: renderSmiley(d, n, result) - of rnLeaf: result.add(esc(d.target, n.text)) + of rnLeaf: result.add(esc(d.target, n.text, escMode=d.escMode)) of rnContents: d.hasToc = true of rnDefaultRole: discard of rnTitle: diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 864728686..34b172935 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -259,7 +259,7 @@ A2 A3 A4 A5 ==== === """ let output1 = rstToLatex(input1, {}) - doAssert "{|X|X|}" in output1 # 2 columns + doAssert "{LL}" in output1 # 2 columns doAssert count(output1, "\\\\") == 4 # 4 rows for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]: doAssert cell in output1 @@ -274,7 +274,7 @@ A0 A1 X Ax Y ==== === = """ let output2 = rstToLatex(input2, {}) - doAssert "{|X|X|X|}" in output2 # 3 columns + doAssert "{LLL}" in output2 # 3 columns doAssert count(output2, "\\\\") == 2 # 2 rows for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]: doAssert cell in output2 diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 621dc643f..f25564fad 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -284,22 +284,22 @@ proc buildDoc(nimArgs, destPath: string) = proc nim2pdf(src: string, dst: string, nimArgs: string) = # xxx expose as a `nim` command or in some other reusable way. - let outDir = "build" / "pdflatextmp" # xxx factor pending https://github.com/timotheecour/Nim/issues/616 + let outDir = "build" / "xelatextmp" # xxx factor pending https://github.com/timotheecour/Nim/issues/616 # note: this will generate temporary files in gitignored `outDir`: aux toc log out tex exec("$# rst2tex $# --outdir:$# $#" % [findNim().quoteShell(), nimArgs, outDir.quoteShell, src.quoteShell]) let texFile = outDir / src.lastPathPart.changeFileExt("tex") - for i in 0..<2: # call LaTeX twice to get cross references right: - let pdflatexLog = outDir / "pdflatex.log" + for i in 0..<3: # call LaTeX three times to get cross references right: + let xelatexLog = outDir / "xelatex.log" # `>` should work on windows, if not, we can use `execCmdEx` - let cmd = "pdflatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, pdflatexLog.quoteShell] - exec(cmd) # on error, user can inspect `pdflatexLog` + let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell] + exec(cmd) # on error, user can inspect `xelatexLog` moveFile(texFile.changeFileExt("pdf"), dst) proc buildPdfDoc*(nimArgs, destPath: string) = var pdfList: seq[string] createDir(destPath) - if os.execShellCmd("pdflatex -version") != 0: - doAssert false, "pdflatex not found" # or, raise an exception + if os.execShellCmd("xelatex -version") != 0: + doAssert false, "xelatex not found" # or, raise an exception else: for src in items(rstPdfList): let dst = destPath / src.lastPathPart.changeFileExt("pdf") From 63db2b19bf0787db89ce89c8861e976d44e33cbd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 Jun 2021 22:29:53 +0200 Subject: [PATCH 2648/4254] use dragonbox algorithm; alternative to #18008 (#18139) * use dragonbox algorithm; alternative to #18008 * removed unsafe code --- changelog.md | 4 + compiler/condsyms.nim | 2 + lib/system/dragonbox.nim | 1347 ++++++++++++++++++++++++++++++++++++ lib/system/formatfloat.nim | 97 +-- tests/float/tfloat6.nim | 8 +- 5 files changed, 1408 insertions(+), 50 deletions(-) create mode 100644 lib/system/dragonbox.nim diff --git a/changelog.md b/changelog.md index 900b23ad8..a23aedbdf 100644 --- a/changelog.md +++ b/changelog.md @@ -76,6 +76,10 @@ - `json` and `jsonutils` now serialize NaN, Inf, -Inf as strings, so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` which was invalid json. +- `system.addFloat` now uses the "Dragonbox" algorithm, which ensures correct roundtrips of floating point + numbers, that the minimum length representation of a floating point number is used and correct rounding. + Use `-d:nimLegacyAddFloat` for a transition period. + - `strformat` is now part of `include std/prelude`. - Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` in `std/algorithm`. diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 6a49584c8..ff0c603cb 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -134,3 +134,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasUnifiedTuple") defineSymbol("nimHasIterable") defineSymbol("nimHasTypeofVoid") + + defineSymbol("nimHasDragonBox") diff --git a/lib/system/dragonbox.nim b/lib/system/dragonbox.nim new file mode 100644 index 000000000..db608c630 --- /dev/null +++ b/lib/system/dragonbox.nim @@ -0,0 +1,1347 @@ +## Copyright 2020 Junekey Jeon +## Copyright 2020 Alexander Bolz +## +## Distributed under the Boost Software License, Version 1.0. +## (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) + +## char* output_end = Dtoa(buffer, value); +## +## Converts the given double-precision number into decimal form and stores the result in the given +## buffer. +## +## The buffer must be large enough, i.e. >= DtoaMinBufferLength. +## The output format is similar to printf("%g"). +## The output is _not_ null-terminted. +## +## The output is optimal, i.e. the output string +## 1. rounds back to the input number when read in (using round-to-nearest-even) +## 2. is as short as possible, +## 3. is as close to the input number as possible. +## +## Note: +## This function may temporarily write up to DtoaMinBufferLength characters into the buffer. + +const + dtoaMinBufferLength*: cint = 64 + +## -------------------------------------------------------------------------------------------------- +## This file contains an implementation of Junekey Jeon's Dragonbox algorithm. +## +## It is a simplified version of the reference implementation found here: +## https://github.com/jk-jeon/dragonbox +## +## The reference implementation also works with single-precision floating-point numbers and +## has options to configure the rounding mode. +## -------------------------------------------------------------------------------------------------- + +template dragonbox_Assert*(x: untyped): untyped = + assert(x) + +## ================================================================================================== +## +## ================================================================================================== + +type + ValueType* = float + BitsType* = uint64 + +type + Double* = object + bits*: BitsType + +const ## = p (includes the hidden bit) + significandSize*: int32 = 53 + +const ## static constexpr int32_t MaxExponent = 1024 - 1 - (SignificandSize - 1); + ## static constexpr int32_t MinExponent = std::numeric_limits::min_exponent - 1 - (SignificandSize - 1); + exponentBias*: int32 = 1024 - 1 + (significandSize - 1) + +const + maxIeeeExponent*: BitsType = BitsType(2 * 1024 - 1) + +const ## = 2^(p-1) + hiddenBit*: BitsType = BitsType(1) shl (significandSize - 1) + +const ## = 2^(p-1) - 1 + significandMask*: BitsType = hiddenBit - 1 + +const + exponentMask*: BitsType = maxIeeeExponent shl (significandSize - 1) + +const + signMask*: BitsType = not (not BitsType(0) shr 1) + +proc constructDouble*(bits: BitsType): Double {.constructor.} = + result.bits = bits + +proc constructDouble*(value: ValueType): Double {.constructor.} = + result.bits = cast[typeof(result.bits)](value) + +proc physicalSignificand*(this: Double): BitsType {.noSideEffect.} = + return this.bits and significandMask + +proc physicalExponent*(this: Double): BitsType {.noSideEffect.} = + return (this.bits and exponentMask) shr (significandSize - 1) + +proc isFinite*(this: Double): bool {.noSideEffect.} = + return (this.bits and exponentMask) != exponentMask + +proc isInf*(this: Double): bool {.noSideEffect.} = + return (this.bits and exponentMask) == exponentMask and + (this.bits and significandMask) == 0 + +proc isNaN*(this: Double): bool {.noSideEffect.} = + return (this.bits and exponentMask) == exponentMask and + (this.bits and significandMask) != 0 + +proc isZero*(this: Double): bool {.noSideEffect.} = + return (this.bits and not signMask) == 0 + +proc signBit*(this: Double): int {.noSideEffect.} = + return ord((this.bits and signMask) != 0) + +## namespace +## ================================================================================================== +## +## ================================================================================================== +## Returns floor(x / 2^n). +## +## Technically, right-shift of negative integers is implementation defined... +## Should easily be optimized into SAR (or equivalent) instruction. + +proc floorDivPow2*(x: int32; n: int32): int32 {.inline.} = + return x shr n + +proc floorLog2Pow10*(e: int32): int32 {.inline.} = + dragonbox_Assert(e >= -1233) + dragonbox_Assert(e <= 1233) + return floorDivPow2(e * 1741647, 19) + +proc floorLog10Pow2*(e: int32): int32 {.inline.} = + dragonbox_Assert(e >= -1500) + dragonbox_Assert(e <= 1500) + return floorDivPow2(e * 1262611, 22) + +proc floorLog10ThreeQuartersPow2*(e: int32): int32 {.inline.} = + dragonbox_Assert(e >= -1500) + dragonbox_Assert(e <= 1500) + return floorDivPow2(e * 1262611 - 524031, 22) + +## ================================================================================================== +## +## ================================================================================================== + +type + uint64x2* {.bycopy.} = object + hi*: uint64 + lo*: uint64 + + +proc computePow10*(k: int32): uint64x2 {.inline.} = + const + kMin: int32 = -292 + const + kMax: int32 = 326 + const + pow10: array[kMax - kMin + 1, uint64x2] = [ + uint64x2(hi: 0xFF77B1FCBEBCDC4F'u, lo: 0x25E8E89C13BB0F7B'u), + uint64x2(hi: 0x9FAACF3DF73609B1'u, lo: 0x77B191618C54E9AD'u), + uint64x2(hi: 0xC795830D75038C1D'u, lo: 0xD59DF5B9EF6A2418'u), + uint64x2(hi: 0xF97AE3D0D2446F25'u, lo: 0x4B0573286B44AD1E'u), + uint64x2(hi: 0x9BECCE62836AC577'u, lo: 0x4EE367F9430AEC33'u), + uint64x2(hi: 0xC2E801FB244576D5'u, lo: 0x229C41F793CDA740'u), + uint64x2(hi: 0xF3A20279ED56D48A'u, lo: 0x6B43527578C11110'u), + uint64x2(hi: 0x9845418C345644D6'u, lo: 0x830A13896B78AAAA'u), + uint64x2(hi: 0xBE5691EF416BD60C'u, lo: 0x23CC986BC656D554'u), + uint64x2(hi: 0xEDEC366B11C6CB8F'u, lo: 0x2CBFBE86B7EC8AA9'u), + uint64x2(hi: 0x94B3A202EB1C3F39'u, lo: 0x7BF7D71432F3D6AA'u), + uint64x2(hi: 0xB9E08A83A5E34F07'u, lo: 0xDAF5CCD93FB0CC54'u), + uint64x2(hi: 0xE858AD248F5C22C9'u, lo: 0xD1B3400F8F9CFF69'u), + uint64x2(hi: 0x91376C36D99995BE'u, lo: 0x23100809B9C21FA2'u), + uint64x2(hi: 0xB58547448FFFFB2D'u, lo: 0xABD40A0C2832A78B'u), + uint64x2(hi: 0xE2E69915B3FFF9F9'u, lo: 0x16C90C8F323F516D'u), + uint64x2(hi: 0x8DD01FAD907FFC3B'u, lo: 0xAE3DA7D97F6792E4'u), + uint64x2(hi: 0xB1442798F49FFB4A'u, lo: 0x99CD11CFDF41779D'u), + uint64x2(hi: 0xDD95317F31C7FA1D'u, lo: 0x40405643D711D584'u), + uint64x2(hi: 0x8A7D3EEF7F1CFC52'u, lo: 0x482835EA666B2573'u), + uint64x2(hi: 0xAD1C8EAB5EE43B66'u, lo: 0xDA3243650005EED0'u), + uint64x2(hi: 0xD863B256369D4A40'u, lo: 0x90BED43E40076A83'u), + uint64x2(hi: 0x873E4F75E2224E68'u, lo: 0x5A7744A6E804A292'u), + uint64x2(hi: 0xA90DE3535AAAE202'u, lo: 0x711515D0A205CB37'u), + uint64x2(hi: 0xD3515C2831559A83'u, lo: 0x0D5A5B44CA873E04'u), + uint64x2(hi: 0x8412D9991ED58091'u, lo: 0xE858790AFE9486C3'u), + uint64x2(hi: 0xA5178FFF668AE0B6'u, lo: 0x626E974DBE39A873'u), + uint64x2(hi: 0xCE5D73FF402D98E3'u, lo: 0xFB0A3D212DC81290'u), + uint64x2(hi: 0x80FA687F881C7F8E'u, lo: 0x7CE66634BC9D0B9A'u), + uint64x2(hi: 0xA139029F6A239F72'u, lo: 0x1C1FFFC1EBC44E81'u), + uint64x2(hi: 0xC987434744AC874E'u, lo: 0xA327FFB266B56221'u), + uint64x2(hi: 0xFBE9141915D7A922'u, lo: 0x4BF1FF9F0062BAA9'u), + uint64x2(hi: 0x9D71AC8FADA6C9B5'u, lo: 0x6F773FC3603DB4AA'u), + uint64x2(hi: 0xC4CE17B399107C22'u, lo: 0xCB550FB4384D21D4'u), + uint64x2(hi: 0xF6019DA07F549B2B'u, lo: 0x7E2A53A146606A49'u), + uint64x2(hi: 0x99C102844F94E0FB'u, lo: 0x2EDA7444CBFC426E'u), + uint64x2(hi: 0xC0314325637A1939'u, lo: 0xFA911155FEFB5309'u), + uint64x2(hi: 0xF03D93EEBC589F88'u, lo: 0x793555AB7EBA27CB'u), + uint64x2(hi: 0x96267C7535B763B5'u, lo: 0x4BC1558B2F3458DF'u), + uint64x2(hi: 0xBBB01B9283253CA2'u, lo: 0x9EB1AAEDFB016F17'u), + uint64x2(hi: 0xEA9C227723EE8BCB'u, lo: 0x465E15A979C1CADD'u), + uint64x2(hi: 0x92A1958A7675175F'u, lo: 0x0BFACD89EC191ECA'u), + uint64x2(hi: 0xB749FAED14125D36'u, lo: 0xCEF980EC671F667C'u), + uint64x2(hi: 0xE51C79A85916F484'u, lo: 0x82B7E12780E7401B'u), + uint64x2(hi: 0x8F31CC0937AE58D2'u, lo: 0xD1B2ECB8B0908811'u), + uint64x2(hi: 0xB2FE3F0B8599EF07'u, lo: 0x861FA7E6DCB4AA16'u), + uint64x2(hi: 0xDFBDCECE67006AC9'u, lo: 0x67A791E093E1D49B'u), + uint64x2(hi: 0x8BD6A141006042BD'u, lo: 0xE0C8BB2C5C6D24E1'u), + uint64x2(hi: 0xAECC49914078536D'u, lo: 0x58FAE9F773886E19'u), + uint64x2(hi: 0xDA7F5BF590966848'u, lo: 0xAF39A475506A899F'u), + uint64x2(hi: 0x888F99797A5E012D'u, lo: 0x6D8406C952429604'u), + uint64x2(hi: 0xAAB37FD7D8F58178'u, lo: 0xC8E5087BA6D33B84'u), + uint64x2(hi: 0xD5605FCDCF32E1D6'u, lo: 0xFB1E4A9A90880A65'u), + uint64x2(hi: 0x855C3BE0A17FCD26'u, lo: 0x5CF2EEA09A550680'u), + uint64x2(hi: 0xA6B34AD8C9DFC06F'u, lo: 0xF42FAA48C0EA481F'u), + uint64x2(hi: 0xD0601D8EFC57B08B'u, lo: 0xF13B94DAF124DA27'u), + uint64x2(hi: 0x823C12795DB6CE57'u, lo: 0x76C53D08D6B70859'u), + uint64x2(hi: 0xA2CB1717B52481ED'u, lo: 0x54768C4B0C64CA6F'u), + uint64x2(hi: 0xCB7DDCDDA26DA268'u, lo: 0xA9942F5DCF7DFD0A'u), + uint64x2(hi: 0xFE5D54150B090B02'u, lo: 0xD3F93B35435D7C4D'u), + uint64x2(hi: 0x9EFA548D26E5A6E1'u, lo: 0xC47BC5014A1A6DB0'u), + uint64x2(hi: 0xC6B8E9B0709F109A'u, lo: 0x359AB6419CA1091C'u), + uint64x2(hi: 0xF867241C8CC6D4C0'u, lo: 0xC30163D203C94B63'u), + uint64x2(hi: 0x9B407691D7FC44F8'u, lo: 0x79E0DE63425DCF1E'u), + uint64x2(hi: 0xC21094364DFB5636'u, lo: 0x985915FC12F542E5'u), + uint64x2(hi: 0xF294B943E17A2BC4'u, lo: 0x3E6F5B7B17B2939E'u), + uint64x2(hi: 0x979CF3CA6CEC5B5A'u, lo: 0xA705992CEECF9C43'u), + uint64x2(hi: 0xBD8430BD08277231'u, lo: 0x50C6FF782A838354'u), + uint64x2(hi: 0xECE53CEC4A314EBD'u, lo: 0xA4F8BF5635246429'u), + uint64x2(hi: 0x940F4613AE5ED136'u, lo: 0x871B7795E136BE9A'u), + uint64x2(hi: 0xB913179899F68584'u, lo: 0x28E2557B59846E40'u), + uint64x2(hi: 0xE757DD7EC07426E5'u, lo: 0x331AEADA2FE589D0'u), + uint64x2(hi: 0x9096EA6F3848984F'u, lo: 0x3FF0D2C85DEF7622'u), + uint64x2(hi: 0xB4BCA50B065ABE63'u, lo: 0x0FED077A756B53AA'u), + uint64x2(hi: 0xE1EBCE4DC7F16DFB'u, lo: 0xD3E8495912C62895'u), + uint64x2(hi: 0x8D3360F09CF6E4BD'u, lo: 0x64712DD7ABBBD95D'u), + uint64x2(hi: 0xB080392CC4349DEC'u, lo: 0xBD8D794D96AACFB4'u), + uint64x2(hi: 0xDCA04777F541C567'u, lo: 0xECF0D7A0FC5583A1'u), + uint64x2(hi: 0x89E42CAAF9491B60'u, lo: 0xF41686C49DB57245'u), + uint64x2(hi: 0xAC5D37D5B79B6239'u, lo: 0x311C2875C522CED6'u), + uint64x2(hi: 0xD77485CB25823AC7'u, lo: 0x7D633293366B828C'u), + uint64x2(hi: 0x86A8D39EF77164BC'u, lo: 0xAE5DFF9C02033198'u), + uint64x2(hi: 0xA8530886B54DBDEB'u, lo: 0xD9F57F830283FDFD'u), + uint64x2(hi: 0xD267CAA862A12D66'u, lo: 0xD072DF63C324FD7C'u), + uint64x2(hi: 0x8380DEA93DA4BC60'u, lo: 0x4247CB9E59F71E6E'u), + uint64x2(hi: 0xA46116538D0DEB78'u, lo: 0x52D9BE85F074E609'u), + uint64x2(hi: 0xCD795BE870516656'u, lo: 0x67902E276C921F8C'u), + uint64x2(hi: 0x806BD9714632DFF6'u, lo: 0x00BA1CD8A3DB53B7'u), + uint64x2(hi: 0xA086CFCD97BF97F3'u, lo: 0x80E8A40ECCD228A5'u), + uint64x2(hi: 0xC8A883C0FDAF7DF0'u, lo: 0x6122CD128006B2CE'u), + uint64x2(hi: 0xFAD2A4B13D1B5D6C'u, lo: 0x796B805720085F82'u), + uint64x2(hi: 0x9CC3A6EEC6311A63'u, lo: 0xCBE3303674053BB1'u), + uint64x2(hi: 0xC3F490AA77BD60FC'u, lo: 0xBEDBFC4411068A9D'u), + uint64x2(hi: 0xF4F1B4D515ACB93B'u, lo: 0xEE92FB5515482D45'u), + uint64x2(hi: 0x991711052D8BF3C5'u, lo: 0x751BDD152D4D1C4B'u), + uint64x2(hi: 0xBF5CD54678EEF0B6'u, lo: 0xD262D45A78A0635E'u), + uint64x2(hi: 0xEF340A98172AACE4'u, lo: 0x86FB897116C87C35'u), + uint64x2(hi: 0x9580869F0E7AAC0E'u, lo: 0xD45D35E6AE3D4DA1'u), + uint64x2(hi: 0xBAE0A846D2195712'u, lo: 0x8974836059CCA10A'u), + uint64x2(hi: 0xE998D258869FACD7'u, lo: 0x2BD1A438703FC94C'u), + uint64x2(hi: 0x91FF83775423CC06'u, lo: 0x7B6306A34627DDD0'u), + uint64x2(hi: 0xB67F6455292CBF08'u, lo: 0x1A3BC84C17B1D543'u), + uint64x2(hi: 0xE41F3D6A7377EECA'u, lo: 0x20CABA5F1D9E4A94'u), + uint64x2(hi: 0x8E938662882AF53E'u, lo: 0x547EB47B7282EE9D'u), + uint64x2(hi: 0xB23867FB2A35B28D'u, lo: 0xE99E619A4F23AA44'u), + uint64x2(hi: 0xDEC681F9F4C31F31'u, lo: 0x6405FA00E2EC94D5'u), + uint64x2(hi: 0x8B3C113C38F9F37E'u, lo: 0xDE83BC408DD3DD05'u), + uint64x2(hi: 0xAE0B158B4738705E'u, lo: 0x9624AB50B148D446'u), + uint64x2(hi: 0xD98DDAEE19068C76'u, lo: 0x3BADD624DD9B0958'u), + uint64x2(hi: 0x87F8A8D4CFA417C9'u, lo: 0xE54CA5D70A80E5D7'u), + uint64x2(hi: 0xA9F6D30A038D1DBC'u, lo: 0x5E9FCF4CCD211F4D'u), + uint64x2(hi: 0xD47487CC8470652B'u, lo: 0x7647C32000696720'u), + uint64x2(hi: 0x84C8D4DFD2C63F3B'u, lo: 0x29ECD9F40041E074'u), + uint64x2(hi: 0xA5FB0A17C777CF09'u, lo: 0xF468107100525891'u), + uint64x2(hi: 0xCF79CC9DB955C2CC'u, lo: 0x7182148D4066EEB5'u), + uint64x2(hi: 0x81AC1FE293D599BF'u, lo: 0xC6F14CD848405531'u), + uint64x2(hi: 0xA21727DB38CB002F'u, lo: 0xB8ADA00E5A506A7D'u), + uint64x2(hi: 0xCA9CF1D206FDC03B'u, lo: 0xA6D90811F0E4851D'u), + uint64x2(hi: 0xFD442E4688BD304A'u, lo: 0x908F4A166D1DA664'u), + uint64x2(hi: 0x9E4A9CEC15763E2E'u, lo: 0x9A598E4E043287FF'u), + uint64x2(hi: 0xC5DD44271AD3CDBA'u, lo: 0x40EFF1E1853F29FE'u), + uint64x2(hi: 0xF7549530E188C128'u, lo: 0xD12BEE59E68EF47D'u), + uint64x2(hi: 0x9A94DD3E8CF578B9'u, lo: 0x82BB74F8301958CF'u), + uint64x2(hi: 0xC13A148E3032D6E7'u, lo: 0xE36A52363C1FAF02'u), + uint64x2(hi: 0xF18899B1BC3F8CA1'u, lo: 0xDC44E6C3CB279AC2'u), + uint64x2(hi: 0x96F5600F15A7B7E5'u, lo: 0x29AB103A5EF8C0BA'u), + uint64x2(hi: 0xBCB2B812DB11A5DE'u, lo: 0x7415D448F6B6F0E8'u), + uint64x2(hi: 0xEBDF661791D60F56'u, lo: 0x111B495B3464AD22'u), + uint64x2(hi: 0x936B9FCEBB25C995'u, lo: 0xCAB10DD900BEEC35'u), + uint64x2(hi: 0xB84687C269EF3BFB'u, lo: 0x3D5D514F40EEA743'u), + uint64x2(hi: 0xE65829B3046B0AFA'u, lo: 0x0CB4A5A3112A5113'u), + uint64x2(hi: 0x8FF71A0FE2C2E6DC'u, lo: 0x47F0E785EABA72AC'u), + uint64x2(hi: 0xB3F4E093DB73A093'u, lo: 0x59ED216765690F57'u), + uint64x2(hi: 0xE0F218B8D25088B8'u, lo: 0x306869C13EC3532D'u), + uint64x2(hi: 0x8C974F7383725573'u, lo: 0x1E414218C73A13FC'u), + uint64x2(hi: 0xAFBD2350644EEACF'u, lo: 0xE5D1929EF90898FB'u), + uint64x2(hi: 0xDBAC6C247D62A583'u, lo: 0xDF45F746B74ABF3A'u), + uint64x2(hi: 0x894BC396CE5DA772'u, lo: 0x6B8BBA8C328EB784'u), + uint64x2(hi: 0xAB9EB47C81F5114F'u, lo: 0x066EA92F3F326565'u), + uint64x2(hi: 0xD686619BA27255A2'u, lo: 0xC80A537B0EFEFEBE'u), + uint64x2(hi: 0x8613FD0145877585'u, lo: 0xBD06742CE95F5F37'u), + uint64x2(hi: 0xA798FC4196E952E7'u, lo: 0x2C48113823B73705'u), + uint64x2(hi: 0xD17F3B51FCA3A7A0'u, lo: 0xF75A15862CA504C6'u), + uint64x2(hi: 0x82EF85133DE648C4'u, lo: 0x9A984D73DBE722FC'u), + uint64x2(hi: 0xA3AB66580D5FDAF5'u, lo: 0xC13E60D0D2E0EBBB'u), + uint64x2(hi: 0xCC963FEE10B7D1B3'u, lo: 0x318DF905079926A9'u), + uint64x2(hi: 0xFFBBCFE994E5C61F'u, lo: 0xFDF17746497F7053'u), + uint64x2(hi: 0x9FD561F1FD0F9BD3'u, lo: 0xFEB6EA8BEDEFA634'u), + uint64x2(hi: 0xC7CABA6E7C5382C8'u, lo: 0xFE64A52EE96B8FC1'u), + uint64x2(hi: 0xF9BD690A1B68637B'u, lo: 0x3DFDCE7AA3C673B1'u), + uint64x2(hi: 0x9C1661A651213E2D'u, lo: 0x06BEA10CA65C084F'u), + uint64x2(hi: 0xC31BFA0FE5698DB8'u, lo: 0x486E494FCFF30A63'u), + uint64x2(hi: 0xF3E2F893DEC3F126'u, lo: 0x5A89DBA3C3EFCCFB'u), + uint64x2(hi: 0x986DDB5C6B3A76B7'u, lo: 0xF89629465A75E01D'u), + uint64x2(hi: 0xBE89523386091465'u, lo: 0xF6BBB397F1135824'u), + uint64x2(hi: 0xEE2BA6C0678B597F'u, lo: 0x746AA07DED582E2D'u), + uint64x2(hi: 0x94DB483840B717EF'u, lo: 0xA8C2A44EB4571CDD'u), + uint64x2(hi: 0xBA121A4650E4DDEB'u, lo: 0x92F34D62616CE414'u), + uint64x2(hi: 0xE896A0D7E51E1566'u, lo: 0x77B020BAF9C81D18'u), + uint64x2(hi: 0x915E2486EF32CD60'u, lo: 0x0ACE1474DC1D122F'u), + uint64x2(hi: 0xB5B5ADA8AAFF80B8'u, lo: 0x0D819992132456BB'u), + uint64x2(hi: 0xE3231912D5BF60E6'u, lo: 0x10E1FFF697ED6C6A'u), + uint64x2(hi: 0x8DF5EFABC5979C8F'u, lo: 0xCA8D3FFA1EF463C2'u), + uint64x2(hi: 0xB1736B96B6FD83B3'u, lo: 0xBD308FF8A6B17CB3'u), + uint64x2(hi: 0xDDD0467C64BCE4A0'u, lo: 0xAC7CB3F6D05DDBDF'u), + uint64x2(hi: 0x8AA22C0DBEF60EE4'u, lo: 0x6BCDF07A423AA96C'u), + uint64x2(hi: 0xAD4AB7112EB3929D'u, lo: 0x86C16C98D2C953C7'u), + uint64x2(hi: 0xD89D64D57A607744'u, lo: 0xE871C7BF077BA8B8'u), + uint64x2(hi: 0x87625F056C7C4A8B'u, lo: 0x11471CD764AD4973'u), + uint64x2(hi: 0xA93AF6C6C79B5D2D'u, lo: 0xD598E40D3DD89BD0'u), + uint64x2(hi: 0xD389B47879823479'u, lo: 0x4AFF1D108D4EC2C4'u), + uint64x2(hi: 0x843610CB4BF160CB'u, lo: 0xCEDF722A585139BB'u), + uint64x2(hi: 0xA54394FE1EEDB8FE'u, lo: 0xC2974EB4EE658829'u), + uint64x2(hi: 0xCE947A3DA6A9273E'u, lo: 0x733D226229FEEA33'u), + uint64x2(hi: 0x811CCC668829B887'u, lo: 0x0806357D5A3F5260'u), + uint64x2(hi: 0xA163FF802A3426A8'u, lo: 0xCA07C2DCB0CF26F8'u), + uint64x2(hi: 0xC9BCFF6034C13052'u, lo: 0xFC89B393DD02F0B6'u), + uint64x2(hi: 0xFC2C3F3841F17C67'u, lo: 0xBBAC2078D443ACE3'u), + uint64x2(hi: 0x9D9BA7832936EDC0'u, lo: 0xD54B944B84AA4C0E'u), + uint64x2(hi: 0xC5029163F384A931'u, lo: 0x0A9E795E65D4DF12'u), + uint64x2(hi: 0xF64335BCF065D37D'u, lo: 0x4D4617B5FF4A16D6'u), + uint64x2(hi: 0x99EA0196163FA42E'u, lo: 0x504BCED1BF8E4E46'u), + uint64x2(hi: 0xC06481FB9BCF8D39'u, lo: 0xE45EC2862F71E1D7'u), + uint64x2(hi: 0xF07DA27A82C37088'u, lo: 0x5D767327BB4E5A4D'u), + uint64x2(hi: 0x964E858C91BA2655'u, lo: 0x3A6A07F8D510F870'u), + uint64x2(hi: 0xBBE226EFB628AFEA'u, lo: 0x890489F70A55368C'u), + uint64x2(hi: 0xEADAB0ABA3B2DBE5'u, lo: 0x2B45AC74CCEA842F'u), + uint64x2(hi: 0x92C8AE6B464FC96F'u, lo: 0x3B0B8BC90012929E'u), + uint64x2(hi: 0xB77ADA0617E3BBCB'u, lo: 0x09CE6EBB40173745'u), + uint64x2(hi: 0xE55990879DDCAABD'u, lo: 0xCC420A6A101D0516'u), + uint64x2(hi: 0x8F57FA54C2A9EAB6'u, lo: 0x9FA946824A12232E'u), + uint64x2(hi: 0xB32DF8E9F3546564'u, lo: 0x47939822DC96ABFA'u), + uint64x2(hi: 0xDFF9772470297EBD'u, lo: 0x59787E2B93BC56F8'u), + uint64x2(hi: 0x8BFBEA76C619EF36'u, lo: 0x57EB4EDB3C55B65B'u), + uint64x2(hi: 0xAEFAE51477A06B03'u, lo: 0xEDE622920B6B23F2'u), + uint64x2(hi: 0xDAB99E59958885C4'u, lo: 0xE95FAB368E45ECEE'u), + uint64x2(hi: 0x88B402F7FD75539B'u, lo: 0x11DBCB0218EBB415'u), + uint64x2(hi: 0xAAE103B5FCD2A881'u, lo: 0xD652BDC29F26A11A'u), + uint64x2(hi: 0xD59944A37C0752A2'u, lo: 0x4BE76D3346F04960'u), + uint64x2(hi: 0x857FCAE62D8493A5'u, lo: 0x6F70A4400C562DDC'u), + uint64x2(hi: 0xA6DFBD9FB8E5B88E'u, lo: 0xCB4CCD500F6BB953'u), + uint64x2(hi: 0xD097AD07A71F26B2'u, lo: 0x7E2000A41346A7A8'u), + uint64x2(hi: 0x825ECC24C873782F'u, lo: 0x8ED400668C0C28C9'u), + uint64x2(hi: 0xA2F67F2DFA90563B'u, lo: 0x728900802F0F32FB'u), + uint64x2(hi: 0xCBB41EF979346BCA'u, lo: 0x4F2B40A03AD2FFBA'u), + uint64x2(hi: 0xFEA126B7D78186BC'u, lo: 0xE2F610C84987BFA9'u), + uint64x2(hi: 0x9F24B832E6B0F436'u, lo: 0x0DD9CA7D2DF4D7CA'u), + uint64x2(hi: 0xC6EDE63FA05D3143'u, lo: 0x91503D1C79720DBC'u), + uint64x2(hi: 0xF8A95FCF88747D94'u, lo: 0x75A44C6397CE912B'u), + uint64x2(hi: 0x9B69DBE1B548CE7C'u, lo: 0xC986AFBE3EE11ABB'u), + uint64x2(hi: 0xC24452DA229B021B'u, lo: 0xFBE85BADCE996169'u), + uint64x2(hi: 0xF2D56790AB41C2A2'u, lo: 0xFAE27299423FB9C4'u), + uint64x2(hi: 0x97C560BA6B0919A5'u, lo: 0xDCCD879FC967D41B'u), + uint64x2(hi: 0xBDB6B8E905CB600F'u, lo: 0x5400E987BBC1C921'u), + uint64x2(hi: 0xED246723473E3813'u, lo: 0x290123E9AAB23B69'u), + uint64x2(hi: 0x9436C0760C86E30B'u, lo: 0xF9A0B6720AAF6522'u), + uint64x2(hi: 0xB94470938FA89BCE'u, lo: 0xF808E40E8D5B3E6A'u), + uint64x2(hi: 0xE7958CB87392C2C2'u, lo: 0xB60B1D1230B20E05'u), + uint64x2(hi: 0x90BD77F3483BB9B9'u, lo: 0xB1C6F22B5E6F48C3'u), + uint64x2(hi: 0xB4ECD5F01A4AA828'u, lo: 0x1E38AEB6360B1AF4'u), + uint64x2(hi: 0xE2280B6C20DD5232'u, lo: 0x25C6DA63C38DE1B1'u), + uint64x2(hi: 0x8D590723948A535F'u, lo: 0x579C487E5A38AD0F'u), + uint64x2(hi: 0xB0AF48EC79ACE837'u, lo: 0x2D835A9DF0C6D852'u), + uint64x2(hi: 0xDCDB1B2798182244'u, lo: 0xF8E431456CF88E66'u), + uint64x2(hi: 0x8A08F0F8BF0F156B'u, lo: 0x1B8E9ECB641B5900'u), + uint64x2(hi: 0xAC8B2D36EED2DAC5'u, lo: 0xE272467E3D222F40'u), + uint64x2(hi: 0xD7ADF884AA879177'u, lo: 0x5B0ED81DCC6ABB10'u), + uint64x2(hi: 0x86CCBB52EA94BAEA'u, lo: 0x98E947129FC2B4EA'u), + uint64x2(hi: 0xA87FEA27A539E9A5'u, lo: 0x3F2398D747B36225'u), + uint64x2(hi: 0xD29FE4B18E88640E'u, lo: 0x8EEC7F0D19A03AAE'u), + uint64x2(hi: 0x83A3EEEEF9153E89'u, lo: 0x1953CF68300424AD'u), + uint64x2(hi: 0xA48CEAAAB75A8E2B'u, lo: 0x5FA8C3423C052DD8'u), + uint64x2(hi: 0xCDB02555653131B6'u, lo: 0x3792F412CB06794E'u), + uint64x2(hi: 0x808E17555F3EBF11'u, lo: 0xE2BBD88BBEE40BD1'u), + uint64x2(hi: 0xA0B19D2AB70E6ED6'u, lo: 0x5B6ACEAEAE9D0EC5'u), + uint64x2(hi: 0xC8DE047564D20A8B'u, lo: 0xF245825A5A445276'u), + uint64x2(hi: 0xFB158592BE068D2E'u, lo: 0xEED6E2F0F0D56713'u), + uint64x2(hi: 0x9CED737BB6C4183D'u, lo: 0x55464DD69685606C'u), + uint64x2(hi: 0xC428D05AA4751E4C'u, lo: 0xAA97E14C3C26B887'u), + uint64x2(hi: 0xF53304714D9265DF'u, lo: 0xD53DD99F4B3066A9'u), + uint64x2(hi: 0x993FE2C6D07B7FAB'u, lo: 0xE546A8038EFE402A'u), + uint64x2(hi: 0xBF8FDB78849A5F96'u, lo: 0xDE98520472BDD034'u), + uint64x2(hi: 0xEF73D256A5C0F77C'u, lo: 0x963E66858F6D4441'u), + uint64x2(hi: 0x95A8637627989AAD'u, lo: 0xDDE7001379A44AA9'u), + uint64x2(hi: 0xBB127C53B17EC159'u, lo: 0x5560C018580D5D53'u), + uint64x2(hi: 0xE9D71B689DDE71AF'u, lo: 0xAAB8F01E6E10B4A7'u), + uint64x2(hi: 0x9226712162AB070D'u, lo: 0xCAB3961304CA70E9'u), + uint64x2(hi: 0xB6B00D69BB55C8D1'u, lo: 0x3D607B97C5FD0D23'u), + uint64x2(hi: 0xE45C10C42A2B3B05'u, lo: 0x8CB89A7DB77C506B'u), + uint64x2(hi: 0x8EB98A7A9A5B04E3'u, lo: 0x77F3608E92ADB243'u), + uint64x2(hi: 0xB267ED1940F1C61C'u, lo: 0x55F038B237591ED4'u), + uint64x2(hi: 0xDF01E85F912E37A3'u, lo: 0x6B6C46DEC52F6689'u), + uint64x2(hi: 0x8B61313BBABCE2C6'u, lo: 0x2323AC4B3B3DA016'u), + uint64x2(hi: 0xAE397D8AA96C1B77'u, lo: 0xABEC975E0A0D081B'u), + uint64x2(hi: 0xD9C7DCED53C72255'u, lo: 0x96E7BD358C904A22'u), + uint64x2(hi: 0x881CEA14545C7575'u, lo: 0x7E50D64177DA2E55'u), + uint64x2(hi: 0xAA242499697392D2'u, lo: 0xDDE50BD1D5D0B9EA'u), + uint64x2(hi: 0xD4AD2DBFC3D07787'u, lo: 0x955E4EC64B44E865'u), + uint64x2(hi: 0x84EC3C97DA624AB4'u, lo: 0xBD5AF13BEF0B113F'u), + uint64x2(hi: 0xA6274BBDD0FADD61'u, lo: 0xECB1AD8AEACDD58F'u), + uint64x2(hi: 0xCFB11EAD453994BA'u, lo: 0x67DE18EDA5814AF3'u), + uint64x2(hi: 0x81CEB32C4B43FCF4'u, lo: 0x80EACF948770CED8'u), + uint64x2(hi: 0xA2425FF75E14FC31'u, lo: 0xA1258379A94D028E'u), + uint64x2(hi: 0xCAD2F7F5359A3B3E'u, lo: 0x096EE45813A04331'u), + uint64x2(hi: 0xFD87B5F28300CA0D'u, lo: 0x8BCA9D6E188853FD'u), + uint64x2(hi: 0x9E74D1B791E07E48'u, lo: 0x775EA264CF55347E'u), + uint64x2(hi: 0xC612062576589DDA'u, lo: 0x95364AFE032A819E'u), + uint64x2(hi: 0xF79687AED3EEC551'u, lo: 0x3A83DDBD83F52205'u), + uint64x2(hi: 0x9ABE14CD44753B52'u, lo: 0xC4926A9672793543'u), + uint64x2(hi: 0xC16D9A0095928A27'u, lo: 0x75B7053C0F178294'u), + uint64x2(hi: 0xF1C90080BAF72CB1'u, lo: 0x5324C68B12DD6339'u), + uint64x2(hi: 0x971DA05074DA7BEE'u, lo: 0xD3F6FC16EBCA5E04'u), + uint64x2(hi: 0xBCE5086492111AEA'u, lo: 0x88F4BB1CA6BCF585'u), + uint64x2(hi: 0xEC1E4A7DB69561A5'u, lo: 0x2B31E9E3D06C32E6'u), + uint64x2(hi: 0x9392EE8E921D5D07'u, lo: 0x3AFF322E62439FD0'u), + uint64x2(hi: 0xB877AA3236A4B449'u, lo: 0x09BEFEB9FAD487C3'u), + uint64x2(hi: 0xE69594BEC44DE15B'u, lo: 0x4C2EBE687989A9B4'u), + uint64x2(hi: 0x901D7CF73AB0ACD9'u, lo: 0x0F9D37014BF60A11'u), + uint64x2(hi: 0xB424DC35095CD80F'u, lo: 0x538484C19EF38C95'u), + uint64x2(hi: 0xE12E13424BB40E13'u, lo: 0x2865A5F206B06FBA'u), + uint64x2(hi: 0x8CBCCC096F5088CB'u, lo: 0xF93F87B7442E45D4'u), + uint64x2(hi: 0xAFEBFF0BCB24AAFE'u, lo: 0xF78F69A51539D749'u), + uint64x2(hi: 0xDBE6FECEBDEDD5BE'u, lo: 0xB573440E5A884D1C'u), + uint64x2(hi: 0x89705F4136B4A597'u, lo: 0x31680A88F8953031'u), + uint64x2(hi: 0xABCC77118461CEFC'u, lo: 0xFDC20D2B36BA7C3E'u), + uint64x2(hi: 0xD6BF94D5E57A42BC'u, lo: 0x3D32907604691B4D'u), + uint64x2(hi: 0x8637BD05AF6C69B5'u, lo: 0xA63F9A49C2C1B110'u), + uint64x2(hi: 0xA7C5AC471B478423'u, lo: 0x0FCF80DC33721D54'u), + uint64x2(hi: 0xD1B71758E219652B'u, lo: 0xD3C36113404EA4A9'u), + uint64x2(hi: 0x83126E978D4FDF3B'u, lo: 0x645A1CAC083126EA'u), + uint64x2(hi: 0xA3D70A3D70A3D70A'u, lo: 0x3D70A3D70A3D70A4'u), + uint64x2(hi: 0xCCCCCCCCCCCCCCCC'u, lo: 0xCCCCCCCCCCCCCCCD'u), + uint64x2(hi: 0x8000000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xA000000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xC800000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xFA00000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x9C40000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xC350000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xF424000000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x9896800000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xBEBC200000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xEE6B280000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x9502F90000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xBA43B74000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xE8D4A51000000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x9184E72A00000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xB5E620F480000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xE35FA931A0000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x8E1BC9BF04000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xB1A2BC2EC5000000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xDE0B6B3A76400000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x8AC7230489E80000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xAD78EBC5AC620000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xD8D726B7177A8000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x878678326EAC9000'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xA968163F0A57B400'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xD3C21BCECCEDA100'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x84595161401484A0'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xA56FA5B99019A5C8'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0xCECB8F27F4200F3A'u, lo: 0x0000000000000000'u), + uint64x2(hi: 0x813F3978F8940984'u, lo: 0x4000000000000000'u), + uint64x2(hi: 0xA18F07D736B90BE5'u, lo: 0x5000000000000000'u), + uint64x2(hi: 0xC9F2C9CD04674EDE'u, lo: 0xA400000000000000'u), + uint64x2(hi: 0xFC6F7C4045812296'u, lo: 0x4D00000000000000'u), + uint64x2(hi: 0x9DC5ADA82B70B59D'u, lo: 0xF020000000000000'u), + uint64x2(hi: 0xC5371912364CE305'u, lo: 0x6C28000000000000'u), + uint64x2(hi: 0xF684DF56C3E01BC6'u, lo: 0xC732000000000000'u), + uint64x2(hi: 0x9A130B963A6C115C'u, lo: 0x3C7F400000000000'u), + uint64x2(hi: 0xC097CE7BC90715B3'u, lo: 0x4B9F100000000000'u), + uint64x2(hi: 0xF0BDC21ABB48DB20'u, lo: 0x1E86D40000000000'u), + uint64x2(hi: 0x96769950B50D88F4'u, lo: 0x1314448000000000'u), + uint64x2(hi: 0xBC143FA4E250EB31'u, lo: 0x17D955A000000000'u), + uint64x2(hi: 0xEB194F8E1AE525FD'u, lo: 0x5DCFAB0800000000'u), + uint64x2(hi: 0x92EFD1B8D0CF37BE'u, lo: 0x5AA1CAE500000000'u), + uint64x2(hi: 0xB7ABC627050305AD'u, lo: 0xF14A3D9E40000000'u), + uint64x2(hi: 0xE596B7B0C643C719'u, lo: 0x6D9CCD05D0000000'u), + uint64x2(hi: 0x8F7E32CE7BEA5C6F'u, lo: 0xE4820023A2000000'u), + uint64x2(hi: 0xB35DBF821AE4F38B'u, lo: 0xDDA2802C8A800000'u), + uint64x2(hi: 0xE0352F62A19E306E'u, lo: 0xD50B2037AD200000'u), + uint64x2(hi: 0x8C213D9DA502DE45'u, lo: 0x4526F422CC340000'u), + uint64x2(hi: 0xAF298D050E4395D6'u, lo: 0x9670B12B7F410000'u), + uint64x2(hi: 0xDAF3F04651D47B4C'u, lo: 0x3C0CDD765F114000'u), + uint64x2(hi: 0x88D8762BF324CD0F'u, lo: 0xA5880A69FB6AC800'u), + uint64x2(hi: 0xAB0E93B6EFEE0053'u, lo: 0x8EEA0D047A457A00'u), + uint64x2(hi: 0xD5D238A4ABE98068'u, lo: 0x72A4904598D6D880'u), + uint64x2(hi: 0x85A36366EB71F041'u, lo: 0x47A6DA2B7F864750'u), + uint64x2(hi: 0xA70C3C40A64E6C51'u, lo: 0x999090B65F67D924'u), + uint64x2(hi: 0xD0CF4B50CFE20765'u, lo: 0xFFF4B4E3F741CF6D'u), + uint64x2(hi: 0x82818F1281ED449F'u, lo: 0xBFF8F10E7A8921A4'u), + uint64x2(hi: 0xA321F2D7226895C7'u, lo: 0xAFF72D52192B6A0D'u), + uint64x2(hi: 0xCBEA6F8CEB02BB39'u, lo: 0x9BF4F8A69F764490'u), + uint64x2(hi: 0xFEE50B7025C36A08'u, lo: 0x02F236D04753D5B4'u), + uint64x2(hi: 0x9F4F2726179A2245'u, lo: 0x01D762422C946590'u), + uint64x2(hi: 0xC722F0EF9D80AAD6'u, lo: 0x424D3AD2B7B97EF5'u), + uint64x2(hi: 0xF8EBAD2B84E0D58B'u, lo: 0xD2E0898765A7DEB2'u), + uint64x2(hi: 0x9B934C3B330C8577'u, lo: 0x63CC55F49F88EB2F'u), + uint64x2(hi: 0xC2781F49FFCFA6D5'u, lo: 0x3CBF6B71C76B25FB'u), + uint64x2(hi: 0xF316271C7FC3908A'u, lo: 0x8BEF464E3945EF7A'u), + uint64x2(hi: 0x97EDD871CFDA3A56'u, lo: 0x97758BF0E3CBB5AC'u), + uint64x2(hi: 0xBDE94E8E43D0C8EC'u, lo: 0x3D52EEED1CBEA317'u), + uint64x2(hi: 0xED63A231D4C4FB27'u, lo: 0x4CA7AAA863EE4BDD'u), + uint64x2(hi: 0x945E455F24FB1CF8'u, lo: 0x8FE8CAA93E74EF6A'u), + uint64x2(hi: 0xB975D6B6EE39E436'u, lo: 0xB3E2FD538E122B44'u), + uint64x2(hi: 0xE7D34C64A9C85D44'u, lo: 0x60DBBCA87196B616'u), + uint64x2(hi: 0x90E40FBEEA1D3A4A'u, lo: 0xBC8955E946FE31CD'u), + uint64x2(hi: 0xB51D13AEA4A488DD'u, lo: 0x6BABAB6398BDBE41'u), + uint64x2(hi: 0xE264589A4DCDAB14'u, lo: 0xC696963C7EED2DD1'u), + uint64x2(hi: 0x8D7EB76070A08AEC'u, lo: 0xFC1E1DE5CF543CA2'u), + uint64x2(hi: 0xB0DE65388CC8ADA8'u, lo: 0x3B25A55F43294BCB'u), + uint64x2(hi: 0xDD15FE86AFFAD912'u, lo: 0x49EF0EB713F39EBE'u), + uint64x2(hi: 0x8A2DBF142DFCC7AB'u, lo: 0x6E3569326C784337'u), + uint64x2(hi: 0xACB92ED9397BF996'u, lo: 0x49C2C37F07965404'u), + uint64x2(hi: 0xD7E77A8F87DAF7FB'u, lo: 0xDC33745EC97BE906'u), + uint64x2(hi: 0x86F0AC99B4E8DAFD'u, lo: 0x69A028BB3DED71A3'u), + uint64x2(hi: 0xA8ACD7C0222311BC'u, lo: 0xC40832EA0D68CE0C'u), + uint64x2(hi: 0xD2D80DB02AABD62B'u, lo: 0xF50A3FA490C30190'u), + uint64x2(hi: 0x83C7088E1AAB65DB'u, lo: 0x792667C6DA79E0FA'u), + uint64x2(hi: 0xA4B8CAB1A1563F52'u, lo: 0x577001B891185938'u), + uint64x2(hi: 0xCDE6FD5E09ABCF26'u, lo: 0xED4C0226B55E6F86'u), + uint64x2(hi: 0x80B05E5AC60B6178'u, lo: 0x544F8158315B05B4'u), + uint64x2(hi: 0xA0DC75F1778E39D6'u, lo: 0x696361AE3DB1C721'u), + uint64x2(hi: 0xC913936DD571C84C'u, lo: 0x03BC3A19CD1E38E9'u), + uint64x2(hi: 0xFB5878494ACE3A5F'u, lo: 0x04AB48A04065C723'u), + uint64x2(hi: 0x9D174B2DCEC0E47B'u, lo: 0x62EB0D64283F9C76'u), + uint64x2(hi: 0xC45D1DF942711D9A'u, lo: 0x3BA5D0BD324F8394'u), + uint64x2(hi: 0xF5746577930D6500'u, lo: 0xCA8F44EC7EE36479'u), + uint64x2(hi: 0x9968BF6ABBE85F20'u, lo: 0x7E998B13CF4E1ECB'u), + uint64x2(hi: 0xBFC2EF456AE276E8'u, lo: 0x9E3FEDD8C321A67E'u), + uint64x2(hi: 0xEFB3AB16C59B14A2'u, lo: 0xC5CFE94EF3EA101E'u), + uint64x2(hi: 0x95D04AEE3B80ECE5'u, lo: 0xBBA1F1D158724A12'u), + uint64x2(hi: 0xBB445DA9CA61281F'u, lo: 0x2A8A6E45AE8EDC97'u), + uint64x2(hi: 0xEA1575143CF97226'u, lo: 0xF52D09D71A3293BD'u), + uint64x2(hi: 0x924D692CA61BE758'u, lo: 0x593C2626705F9C56'u), + uint64x2(hi: 0xB6E0C377CFA2E12E'u, lo: 0x6F8B2FB00C77836C'u), + uint64x2(hi: 0xE498F455C38B997A'u, lo: 0x0B6DFB9C0F956447'u), + uint64x2(hi: 0x8EDF98B59A373FEC'u, lo: 0x4724BD4189BD5EAC'u), + uint64x2(hi: 0xB2977EE300C50FE7'u, lo: 0x58EDEC91EC2CB657'u), + uint64x2(hi: 0xDF3D5E9BC0F653E1'u, lo: 0x2F2967B66737E3ED'u), + uint64x2(hi: 0x8B865B215899F46C'u, lo: 0xBD79E0D20082EE74'u), + uint64x2(hi: 0xAE67F1E9AEC07187'u, lo: 0xECD8590680A3AA11'u), + uint64x2(hi: 0xDA01EE641A708DE9'u, lo: 0xE80E6F4820CC9495'u), + uint64x2(hi: 0x884134FE908658B2'u, lo: 0x3109058D147FDCDD'u), + uint64x2(hi: 0xAA51823E34A7EEDE'u, lo: 0xBD4B46F0599FD415'u), + uint64x2(hi: 0xD4E5E2CDC1D1EA96'u, lo: 0x6C9E18AC7007C91A'u), + uint64x2(hi: 0x850FADC09923329E'u, lo: 0x03E2CF6BC604DDB0'u), + uint64x2(hi: 0xA6539930BF6BFF45'u, lo: 0x84DB8346B786151C'u), + uint64x2(hi: 0xCFE87F7CEF46FF16'u, lo: 0xE612641865679A63'u), + uint64x2(hi: 0x81F14FAE158C5F6E'u, lo: 0x4FCB7E8F3F60C07E'u), + uint64x2(hi: 0xA26DA3999AEF7749'u, lo: 0xE3BE5E330F38F09D'u), + uint64x2(hi: 0xCB090C8001AB551C'u, lo: 0x5CADF5BFD3072CC5'u), + uint64x2(hi: 0xFDCB4FA002162A63'u, lo: 0x73D9732FC7C8F7F6'u), + uint64x2(hi: 0x9E9F11C4014DDA7E'u, lo: 0x2867E7FDDCDD9AFA'u), + uint64x2(hi: 0xC646D63501A1511D'u, lo: 0xB281E1FD541501B8'u), + uint64x2(hi: 0xF7D88BC24209A565'u, lo: 0x1F225A7CA91A4226'u), + uint64x2(hi: 0x9AE757596946075F'u, lo: 0x3375788DE9B06958'u), + uint64x2(hi: 0xC1A12D2FC3978937'u, lo: 0x0052D6B1641C83AE'u), + uint64x2(hi: 0xF209787BB47D6B84'u, lo: 0xC0678C5DBD23A49A'u), + uint64x2(hi: 0x9745EB4D50CE6332'u, lo: 0xF840B7BA963646E0'u), + uint64x2(hi: 0xBD176620A501FBFF'u, lo: 0xB650E5A93BC3D898'u), + uint64x2(hi: 0xEC5D3FA8CE427AFF'u, lo: 0xA3E51F138AB4CEBE'u), + uint64x2(hi: 0x93BA47C980E98CDF'u, lo: 0xC66F336C36B10137'u), + uint64x2(hi: 0xB8A8D9BBE123F017'u, lo: 0xB80B0047445D4184'u), + uint64x2(hi: 0xE6D3102AD96CEC1D'u, lo: 0xA60DC059157491E5'u), + uint64x2(hi: 0x9043EA1AC7E41392'u, lo: 0x87C89837AD68DB2F'u), + uint64x2(hi: 0xB454E4A179DD1877'u, lo: 0x29BABE4598C311FB'u), + uint64x2(hi: 0xE16A1DC9D8545E94'u, lo: 0xF4296DD6FEF3D67A'u), + uint64x2(hi: 0x8CE2529E2734BB1D'u, lo: 0x1899E4A65F58660C'u), + uint64x2(hi: 0xB01AE745B101E9E4'u, lo: 0x5EC05DCFF72E7F8F'u), + uint64x2(hi: 0xDC21A1171D42645D'u, lo: 0x76707543F4FA1F73'u), + uint64x2(hi: 0x899504AE72497EBA'u, lo: 0x6A06494A791C53A8'u), + uint64x2(hi: 0xABFA45DA0EDBDE69'u, lo: 0x0487DB9D17636892'u), + uint64x2(hi: 0xD6F8D7509292D603'u, lo: 0x45A9D2845D3C42B6'u), + uint64x2(hi: 0x865B86925B9BC5C2'u, lo: 0x0B8A2392BA45A9B2'u), + uint64x2(hi: 0xA7F26836F282B732'u, lo: 0x8E6CAC7768D7141E'u), + uint64x2(hi: 0xD1EF0244AF2364FF'u, lo: 0x3207D795430CD926'u), + uint64x2(hi: 0x8335616AED761F1F'u, lo: 0x7F44E6BD49E807B8'u), + uint64x2(hi: 0xA402B9C5A8D3A6E7'u, lo: 0x5F16206C9C6209A6'u), + uint64x2(hi: 0xCD036837130890A1'u, lo: 0x36DBA887C37A8C0F'u), + uint64x2(hi: 0x802221226BE55A64'u, lo: 0xC2494954DA2C9789'u), + uint64x2(hi: 0xA02AA96B06DEB0FD'u, lo: 0xF2DB9BAA10B7BD6C'u), + uint64x2(hi: 0xC83553C5C8965D3D'u, lo: 0x6F92829494E5ACC7'u), + uint64x2(hi: 0xFA42A8B73ABBF48C'u, lo: 0xCB772339BA1F17F9'u), + uint64x2(hi: 0x9C69A97284B578D7'u, lo: 0xFF2A760414536EFB'u), + uint64x2(hi: 0xC38413CF25E2D70D'u, lo: 0xFEF5138519684ABA'u), + uint64x2(hi: 0xF46518C2EF5B8CD1'u, lo: 0x7EB258665FC25D69'u), + uint64x2(hi: 0x98BF2F79D5993802'u, lo: 0xEF2F773FFBD97A61'u), + uint64x2(hi: 0xBEEEFB584AFF8603'u, lo: 0xAAFB550FFACFD8FA'u), + uint64x2(hi: 0xEEAABA2E5DBF6784'u, lo: 0x95BA2A53F983CF38'u), + uint64x2(hi: 0x952AB45CFA97A0B2'u, lo: 0xDD945A747BF26183'u), + uint64x2(hi: 0xBA756174393D88DF'u, lo: 0x94F971119AEEF9E4'u), + uint64x2(hi: 0xE912B9D1478CEB17'u, lo: 0x7A37CD5601AAB85D'u), + uint64x2(hi: 0x91ABB422CCB812EE'u, lo: 0xAC62E055C10AB33A'u), + uint64x2(hi: 0xB616A12B7FE617AA'u, lo: 0x577B986B314D6009'u), + uint64x2(hi: 0xE39C49765FDF9D94'u, lo: 0xED5A7E85FDA0B80B'u), + uint64x2(hi: 0x8E41ADE9FBEBC27D'u, lo: 0x14588F13BE847307'u), + uint64x2(hi: 0xB1D219647AE6B31C'u, lo: 0x596EB2D8AE258FC8'u), + uint64x2(hi: 0xDE469FBD99A05FE3'u, lo: 0x6FCA5F8ED9AEF3BB'u), + uint64x2(hi: 0x8AEC23D680043BEE'u, lo: 0x25DE7BB9480D5854'u), + uint64x2(hi: 0xADA72CCC20054AE9'u, lo: 0xAF561AA79A10AE6A'u), + uint64x2(hi: 0xD910F7FF28069DA4'u, lo: 0x1B2BA1518094DA04'u), + uint64x2(hi: 0x87AA9AFF79042286'u, lo: 0x90FB44D2F05D0842'u), + uint64x2(hi: 0xA99541BF57452B28'u, lo: 0x353A1607AC744A53'u), + uint64x2(hi: 0xD3FA922F2D1675F2'u, lo: 0x42889B8997915CE8'u), + uint64x2(hi: 0x847C9B5D7C2E09B7'u, lo: 0x69956135FEBADA11'u), + uint64x2(hi: 0xA59BC234DB398C25'u, lo: 0x43FAB9837E699095'u), + uint64x2(hi: 0xCF02B2C21207EF2E'u, lo: 0x94F967E45E03F4BB'u), + uint64x2(hi: 0x8161AFB94B44F57D'u, lo: 0x1D1BE0EEBAC278F5'u), + uint64x2(hi: 0xA1BA1BA79E1632DC'u, lo: 0x6462D92A69731732'u), + uint64x2(hi: 0xCA28A291859BBF93'u, lo: 0x7D7B8F7503CFDCFE'u), + uint64x2(hi: 0xFCB2CB35E702AF78'u, lo: 0x5CDA735244C3D43E'u), + uint64x2(hi: 0x9DEFBF01B061ADAB'u, lo: 0x3A0888136AFA64A7'u), + uint64x2(hi: 0xC56BAEC21C7A1916'u, lo: 0x088AAA1845B8FDD0'u), + uint64x2(hi: 0xF6C69A72A3989F5B'u, lo: 0x8AAD549E57273D45'u), + uint64x2(hi: 0x9A3C2087A63F6399'u, lo: 0x36AC54E2F678864B'u), + uint64x2(hi: 0xC0CB28A98FCF3C7F'u, lo: 0x84576A1BB416A7DD'u), + uint64x2(hi: 0xF0FDF2D3F3C30B9F'u, lo: 0x656D44A2A11C51D5'u), + uint64x2(hi: 0x969EB7C47859E743'u, lo: 0x9F644AE5A4B1B325'u), + uint64x2(hi: 0xBC4665B596706114'u, lo: 0x873D5D9F0DDE1FEE'u), + uint64x2(hi: 0xEB57FF22FC0C7959'u, lo: 0xA90CB506D155A7EA'u), + uint64x2(hi: 0x9316FF75DD87CBD8'u, lo: 0x09A7F12442D588F2'u), + uint64x2(hi: 0xB7DCBF5354E9BECE'u, lo: 0x0C11ED6D538AEB2F'u), + uint64x2(hi: 0xE5D3EF282A242E81'u, lo: 0x8F1668C8A86DA5FA'u), + uint64x2(hi: 0x8FA475791A569D10'u, lo: 0xF96E017D694487BC'u), + uint64x2(hi: 0xB38D92D760EC4455'u, lo: 0x37C981DCC395A9AC'u), + uint64x2(hi: 0xE070F78D3927556A'u, lo: 0x85BBE253F47B1417'u), + uint64x2(hi: 0x8C469AB843B89562'u, lo: 0x93956D7478CCEC8E'u), + uint64x2(hi: 0xAF58416654A6BABB'u, lo: 0x387AC8D1970027B2'u), + uint64x2(hi: 0xDB2E51BFE9D0696A'u, lo: 0x06997B05FCC0319E'u), + uint64x2(hi: 0x88FCF317F22241E2'u, lo: 0x441FECE3BDF81F03'u), + uint64x2(hi: 0xAB3C2FDDEEAAD25A'u, lo: 0xD527E81CAD7626C3'u), + uint64x2(hi: 0xD60B3BD56A5586F1'u, lo: 0x8A71E223D8D3B074'u), + uint64x2(hi: 0x85C7056562757456'u, lo: 0xF6872D5667844E49'u), + uint64x2(hi: 0xA738C6BEBB12D16C'u, lo: 0xB428F8AC016561DB'u), + uint64x2(hi: 0xD106F86E69D785C7'u, lo: 0xE13336D701BEBA52'u), + uint64x2(hi: 0x82A45B450226B39C'u, lo: 0xECC0024661173473'u), + uint64x2(hi: 0xA34D721642B06084'u, lo: 0x27F002D7F95D0190'u), + uint64x2(hi: 0xCC20CE9BD35C78A5'u, lo: 0x31EC038DF7B441F4'u), + uint64x2(hi: 0xFF290242C83396CE'u, lo: 0x7E67047175A15271'u), + uint64x2(hi: 0x9F79A169BD203E41'u, lo: 0x0F0062C6E984D386'u), + uint64x2(hi: 0xC75809C42C684DD1'u, lo: 0x52C07B78A3E60868'u), + uint64x2(hi: 0xF92E0C3537826145'u, lo: 0xA7709A56CCDF8A82'u), + uint64x2(hi: 0x9BBCC7A142B17CCB'u, lo: 0x88A66076400BB691'u), + uint64x2(hi: 0xC2ABF989935DDBFE'u, lo: 0x6ACFF893D00EA435'u), + uint64x2(hi: 0xF356F7EBF83552FE'u, lo: 0x0583F6B8C4124D43'u), + uint64x2(hi: 0x98165AF37B2153DE'u, lo: 0xC3727A337A8B704A'u), + uint64x2(hi: 0xBE1BF1B059E9A8D6'u, lo: 0x744F18C0592E4C5C'u), + uint64x2(hi: 0xEDA2EE1C7064130C'u, lo: 0x1162DEF06F79DF73'u), + uint64x2(hi: 0x9485D4D1C63E8BE7'u, lo: 0x8ADDCB5645AC2BA8'u), + uint64x2(hi: 0xB9A74A0637CE2EE1'u, lo: 0x6D953E2BD7173692'u), + uint64x2(hi: 0xE8111C87C5C1BA99'u, lo: 0xC8FA8DB6CCDD0437'u), + uint64x2(hi: 0x910AB1D4DB9914A0'u, lo: 0x1D9C9892400A22A2'u), + uint64x2(hi: 0xB54D5E4A127F59C8'u, lo: 0x2503BEB6D00CAB4B'u), + uint64x2(hi: 0xE2A0B5DC971F303A'u, lo: 0x2E44AE64840FD61D'u), + uint64x2(hi: 0x8DA471A9DE737E24'u, lo: 0x5CEAECFED289E5D2'u), + uint64x2(hi: 0xB10D8E1456105DAD'u, lo: 0x7425A83E872C5F47'u), + uint64x2(hi: 0xDD50F1996B947518'u, lo: 0xD12F124E28F77719'u), + uint64x2(hi: 0x8A5296FFE33CC92F'u, lo: 0x82BD6B70D99AAA6F'u), + uint64x2(hi: 0xACE73CBFDC0BFB7B'u, lo: 0x636CC64D1001550B'u), + uint64x2(hi: 0xD8210BEFD30EFA5A'u, lo: 0x3C47F7E05401AA4E'u), + uint64x2(hi: 0x8714A775E3E95C78'u, lo: 0x65ACFAEC34810A71'u), + uint64x2(hi: 0xA8D9D1535CE3B396'u, lo: 0x7F1839A741A14D0D'u), + uint64x2(hi: 0xD31045A8341CA07C'u, lo: 0x1EDE48111209A050'u), + uint64x2(hi: 0x83EA2B892091E44D'u, lo: 0x934AED0AAB460432'u), + uint64x2(hi: 0xA4E4B66B68B65D60'u, lo: 0xF81DA84D5617853F'u), + uint64x2(hi: 0xCE1DE40642E3F4B9'u, lo: 0x36251260AB9D668E'u), + uint64x2(hi: 0x80D2AE83E9CE78F3'u, lo: 0xC1D72B7C6B426019'u), + uint64x2(hi: 0xA1075A24E4421730'u, lo: 0xB24CF65B8612F81F'u), + uint64x2(hi: 0xC94930AE1D529CFC'u, lo: 0xDEE033F26797B627'u), + uint64x2(hi: 0xFB9B7CD9A4A7443C'u, lo: 0x169840EF017DA3B1'u), + uint64x2(hi: 0x9D412E0806E88AA5'u, lo: 0x8E1F289560EE864E'u), + uint64x2(hi: 0xC491798A08A2AD4E'u, lo: 0xF1A6F2BAB92A27E2'u), + uint64x2(hi: 0xF5B5D7EC8ACB58A2'u, lo: 0xAE10AF696774B1DB'u), + uint64x2(hi: 0x9991A6F3D6BF1765'u, lo: 0xACCA6DA1E0A8EF29'u), + uint64x2(hi: 0xBFF610B0CC6EDD3F'u, lo: 0x17FD090A58D32AF3'u), + uint64x2(hi: 0xEFF394DCFF8A948E'u, lo: 0xDDFC4B4CEF07F5B0'u), + uint64x2(hi: 0x95F83D0A1FB69CD9'u, lo: 0x4ABDAF101564F98E'u), + uint64x2(hi: 0xBB764C4CA7A4440F'u, lo: 0x9D6D1AD41ABE37F1'u), + uint64x2(hi: 0xEA53DF5FD18D5513'u, lo: 0x84C86189216DC5ED'u), + uint64x2(hi: 0x92746B9BE2F8552C'u, lo: 0x32FD3CF5B4E49BB4'u), + uint64x2(hi: 0xB7118682DBB66A77'u, lo: 0x3FBC8C33221DC2A1'u), + uint64x2(hi: 0xE4D5E82392A40515'u, lo: 0x0FABAF3FEAA5334A'u), + uint64x2(hi: 0x8F05B1163BA6832D'u, lo: 0x29CB4D87F2A7400E'u), + uint64x2(hi: 0xB2C71D5BCA9023F8'u, lo: 0x743E20E9EF511012'u), + uint64x2(hi: 0xDF78E4B2BD342CF6'u, lo: 0x914DA9246B255416'u), + uint64x2(hi: 0x8BAB8EEFB6409C1A'u, lo: 0x1AD089B6C2F7548E'u), + uint64x2(hi: 0xAE9672ABA3D0C320'u, lo: 0xA184AC2473B529B1'u), + uint64x2(hi: 0xDA3C0F568CC4F3E8'u, lo: 0xC9E5D72D90A2741E'u), + uint64x2(hi: 0x8865899617FB1871'u, lo: 0x7E2FA67C7A658892'u), + uint64x2(hi: 0xAA7EEBFB9DF9DE8D'u, lo: 0xDDBB901B98FEEAB7'u), + uint64x2(hi: 0xD51EA6FA85785631'u, lo: 0x552A74227F3EA565'u), + uint64x2(hi: 0x8533285C936B35DE'u, lo: 0xD53A88958F87275F'u), + uint64x2(hi: 0xA67FF273B8460356'u, lo: 0x8A892ABAF368F137'u), + uint64x2(hi: 0xD01FEF10A657842C'u, lo: 0x2D2B7569B0432D85'u), + uint64x2(hi: 0x8213F56A67F6B29B'u, lo: 0x9C3B29620E29FC73'u), + uint64x2(hi: 0xA298F2C501F45F42'u, lo: 0x8349F3BA91B47B8F'u), + uint64x2(hi: 0xCB3F2F7642717713'u, lo: 0x241C70A936219A73'u), + uint64x2(hi: 0xFE0EFB53D30DD4D7'u, lo: 0xED238CD383AA0110'u), + uint64x2(hi: 0x9EC95D1463E8A506'u, lo: 0xF4363804324A40AA'u), + uint64x2(hi: 0xC67BB4597CE2CE48'u, lo: 0xB143C6053EDCD0D5'u), + uint64x2(hi: 0xF81AA16FDC1B81DA'u, lo: 0xDD94B7868E94050A'u), + uint64x2(hi: 0x9B10A4E5E9913128'u, lo: 0xCA7CF2B4191C8326'u), + uint64x2(hi: 0xC1D4CE1F63F57D72'u, lo: 0xFD1C2F611F63A3F0'u), + uint64x2(hi: 0xF24A01A73CF2DCCF'u, lo: 0xBC633B39673C8CEC'u), + uint64x2(hi: 0x976E41088617CA01'u, lo: 0xD5BE0503E085D813'u), + uint64x2(hi: 0xBD49D14AA79DBC82'u, lo: 0x4B2D8644D8A74E18'u), + uint64x2(hi: 0xEC9C459D51852BA2'u, lo: 0xDDF8E7D60ED1219E'u), + uint64x2(hi: 0x93E1AB8252F33B45'u, lo: 0xCABB90E5C942B503'u), + uint64x2(hi: 0xB8DA1662E7B00A17'u, lo: 0x3D6A751F3B936243'u), + uint64x2(hi: 0xE7109BFBA19C0C9D'u, lo: 0x0CC512670A783AD4'u), + uint64x2(hi: 0x906A617D450187E2'u, lo: 0x27FB2B80668B24C5'u), + uint64x2(hi: 0xB484F9DC9641E9DA'u, lo: 0xB1F9F660802DEDF6'u), + uint64x2(hi: 0xE1A63853BBD26451'u, lo: 0x5E7873F8A0396973'u), + uint64x2(hi: 0x8D07E33455637EB2'u, lo: 0xDB0B487B6423E1E8'u), + uint64x2(hi: 0xB049DC016ABC5E5F'u, lo: 0x91CE1A9A3D2CDA62'u), + uint64x2(hi: 0xDC5C5301C56B75F7'u, lo: 0x7641A140CC7810FB'u), + uint64x2(hi: 0x89B9B3E11B6329BA'u, lo: 0xA9E904C87FCB0A9D'u), + uint64x2(hi: 0xAC2820D9623BF429'u, lo: 0x546345FA9FBDCD44'u), + uint64x2(hi: 0xD732290FBACAF133'u, lo: 0xA97C177947AD4095'u), + uint64x2(hi: 0x867F59A9D4BED6C0'u, lo: 0x49ED8EABCCCC485D'u), + uint64x2(hi: 0xA81F301449EE8C70'u, lo: 0x5C68F256BFFF5A74'u), + uint64x2(hi: 0xD226FC195C6A2F8C'u, lo: 0x73832EEC6FFF3111'u), + uint64x2(hi: 0x83585D8FD9C25DB7'u, lo: 0xC831FD53C5FF7EAB'u), + uint64x2(hi: 0xA42E74F3D032F525'u, lo: 0xBA3E7CA8B77F5E55'u), + uint64x2(hi: 0xCD3A1230C43FB26F'u, lo: 0x28CE1BD2E55F35EB'u), + uint64x2(hi: 0x80444B5E7AA7CF85'u, lo: 0x7980D163CF5B81B3'u), + uint64x2(hi: 0xA0555E361951C366'u, lo: 0xD7E105BCC332621F'u), + uint64x2(hi: 0xC86AB5C39FA63440'u, lo: 0x8DD9472BF3FEFAA7'u), + uint64x2(hi: 0xFA856334878FC150'u, lo: 0xB14F98F6F0FEB951'u), + uint64x2(hi: 0x9C935E00D4B9D8D2'u, lo: 0x6ED1BF9A569F33D3'u), + uint64x2(hi: 0xC3B8358109E84F07'u, lo: 0x0A862F80EC4700C8'u), + uint64x2(hi: 0xF4A642E14C6262C8'u, lo: 0xCD27BB612758C0FA'u), + uint64x2(hi: 0x98E7E9CCCFBD7DBD'u, lo: 0x8038D51CB897789C'u), + uint64x2(hi: 0xBF21E44003ACDD2C'u, lo: 0xE0470A63E6BD56C3'u), + uint64x2(hi: 0xEEEA5D5004981478'u, lo: 0x1858CCFCE06CAC74'u), + uint64x2(hi: 0x95527A5202DF0CCB'u, lo: 0x0F37801E0C43EBC8'u), + uint64x2(hi: 0xBAA718E68396CFFD'u, lo: 0xD30560258F54E6BA'u), + uint64x2(hi: 0xE950DF20247C83FD'u, lo: 0x47C6B82EF32A2069'u), + uint64x2(hi: 0x91D28B7416CDD27E'u, lo: 0x4CDC331D57FA5441'u), + uint64x2(hi: 0xB6472E511C81471D'u, lo: 0xE0133FE4ADF8E952'u), + uint64x2(hi: 0xE3D8F9E563A198E5'u, lo: 0x58180FDDD97723A6'u), + uint64x2(hi: 0x8E679C2F5E44FF8F'u, lo: 0x570F09EAA7EA7648'u), + uint64x2(hi: 0xB201833B35D63F73'u, lo: 0x2CD2CC6551E513DA'u), + uint64x2(hi: 0xDE81E40A034BCF4F'u, lo: 0xF8077F7EA65E58D1'u), + uint64x2(hi: 0x8B112E86420F6191'u, lo: 0xFB04AFAF27FAF782'u), + uint64x2(hi: 0xADD57A27D29339F6'u, lo: 0x79C5DB9AF1F9B563'u), + uint64x2(hi: 0xD94AD8B1C7380874'u, lo: 0x18375281AE7822BC'u), + uint64x2(hi: 0x87CEC76F1C830548'u, lo: 0x8F2293910D0B15B5'u), + uint64x2(hi: 0xA9C2794AE3A3C69A'u, lo: 0xB2EB3875504DDB22'u), + uint64x2(hi: 0xD433179D9C8CB841'u, lo: 0x5FA60692A46151EB'u), + uint64x2(hi: 0x849FEEC281D7F328'u, lo: 0xDBC7C41BA6BCD333'u), + uint64x2(hi: 0xA5C7EA73224DEFF3'u, lo: 0x12B9B522906C0800'u), + uint64x2(hi: 0xCF39E50FEAE16BEF'u, lo: 0xD768226B34870A00'u), + uint64x2(hi: 0x81842F29F2CCE375'u, lo: 0xE6A1158300D46640'u), + uint64x2(hi: 0xA1E53AF46F801C53'u, lo: 0x60495AE3C1097FD0'u), + uint64x2(hi: 0xCA5E89B18B602368'u, lo: 0x385BB19CB14BDFC4'u), + uint64x2(hi: 0xFCF62C1DEE382C42'u, lo: 0x46729E03DD9ED7B5'u), + uint64x2(hi: 0x9E19DB92B4E31BA9'u, lo: 0x6C07A2C26A8346D1'u), + uint64x2(hi: 0xC5A05277621BE293'u, lo: 0xC7098B7305241885'u), + uint64x2(hi: 0xF70867153AA2DB38'u, lo: 0xB8CBEE4FC66D1EA7'u)] + dragonbox_Assert(k >= kMin) + dragonbox_Assert(k <= kMax) + return pow10[k - kMin] + +## Returns whether value is divisible by 2^e2 + +proc multipleOfPow2*(value: uint64; e2: int32): bool {.inline.} = + dragonbox_Assert(e2 >= 0) + return e2 < 64 and (value and ((uint64(1) shl e2) - 1)) == 0 + +## Returns whether value is divisible by 5^e5 + +proc multipleOfPow5*(value: uint64; e5: int32): bool {.inline.} = + type + MulCmp {.bycopy.} = object + mul: uint64 + cmp: uint64 + + const + mod5 = [MulCmp(mul: 0x0000000000000001'u, cmp: 0xFFFFFFFFFFFFFFFF'u), + MulCmp(mul: 0xCCCCCCCCCCCCCCCD'u, cmp: 0x3333333333333333'u), + MulCmp(mul: 0x8F5C28F5C28F5C29'u, cmp: 0x0A3D70A3D70A3D70'u), + MulCmp(mul: 0x1CAC083126E978D5'u, cmp: 0x020C49BA5E353F7C'u), + MulCmp(mul: 0xD288CE703AFB7E91'u, cmp: 0x0068DB8BAC710CB2'u), + MulCmp(mul: 0x5D4E8FB00BCBE61D'u, cmp: 0x0014F8B588E368F0'u), + MulCmp(mul: 0x790FB65668C26139'u, cmp: 0x000431BDE82D7B63'u), + MulCmp(mul: 0xE5032477AE8D46A5'u, cmp: 0x0000D6BF94D5E57A'u), + MulCmp(mul: 0xC767074B22E90E21'u, cmp: 0x00002AF31DC46118'u), + MulCmp(mul: 0x8E47CE423A2E9C6D'u, cmp: 0x0000089705F4136B'u), + MulCmp(mul: 0x4FA7F60D3ED61F49'u, cmp: 0x000001B7CDFD9D7B'u), + MulCmp(mul: 0x0FEE64690C913975'u, cmp: 0x00000057F5FF85E5'u), + MulCmp(mul: 0x3662E0E1CF503EB1'u, cmp: 0x000000119799812D'u), + MulCmp(mul: 0xA47A2CF9F6433FBD'u, cmp: 0x0000000384B84D09'u), + MulCmp(mul: 0x54186F653140A659'u, cmp: 0x00000000B424DC35'u), + MulCmp(mul: 0x7738164770402145'u, cmp: 0x0000000024075F3D'u), + MulCmp(mul: 0xE4A4D1417CD9A041'u, cmp: 0x000000000734ACA5'u), + MulCmp(mul: 0xC75429D9E5C5200D'u, cmp: 0x000000000170EF54'u), + MulCmp(mul: 0xC1773B91FAC10669'u, cmp: 0x000000000049C977'u), + MulCmp(mul: 0x26B172506559CE15'u, cmp: 0x00000000000EC1E4'u), + MulCmp(mul: 0xD489E3A9ADDEC2D1'u, cmp: 0x000000000002F394'u), + MulCmp(mul: 0x90E860BB892C8D5D'u, cmp: 0x000000000000971D'u), + MulCmp(mul: 0x502E79BF1B6F4F79'u, cmp: 0x0000000000001E39'u), + MulCmp(mul: 0xDCD618596BE30FE5'u, cmp: 0x000000000000060B'u), + MulCmp(mul: 0x2C2AD1AB7BFA3661'u, cmp: 0x0000000000000135'u)] + dragonbox_Assert(e5 >= 0) + dragonbox_Assert(e5 <= 24) + let m5: MulCmp = mod5[e5] + return value * m5.mul <= m5.cmp + +type + FloatingDecimal64* {.bycopy.} = object + significand*: uint64 + exponent*: int32 + + +proc toDecimal64AsymmetricInterval*(e2: int32): FloatingDecimal64 {.inline.} = + ## NB: + ## accept_lower_endpoint = true + ## accept_upper_endpoint = true + const + P: int32 = significandSize + ## Compute k and beta + let minusK: int32 = floorLog10ThreeQuartersPow2(e2) + let betaMinus1: int32 = e2 + floorLog2Pow10(-minusK) + ## Compute xi and zi + let pow10: uint64x2 = computePow10(-minusK) + let lowerEndpoint: uint64 = (pow10.hi - (pow10.hi shr (P + 1))) shr + (64 - P - betaMinus1) + let upperEndpoint: uint64 = (pow10.hi + (pow10.hi shr (P + 0))) shr + (64 - P - betaMinus1) + ## If we don't accept the left endpoint (but we do!) or + ## if the left endpoint is not an integer, increase it + let lowerEndpointIsInteger: bool = (2 <= e2 and e2 <= 3) + let xi: uint64 = lowerEndpoint + uint64(not lowerEndpointIsInteger) + let zi: uint64 = upperEndpoint + ## Try bigger divisor + var q: uint64 = zi div 10 + if q * 10 >= xi: + return FloatingDecimal64(significand: q, exponent: minusK + 1) + q = ((pow10.hi shr (64 - (P + 1) - betaMinus1)) + 1) div 2 + ## When tie occurs, choose one of them according to the rule + if e2 == -77: + dec(q, ord(q mod 2 != 0)) + ## Round to even. + else: + inc(q, ord(q < xi)) + return FloatingDecimal64(significand: q, exponent: minusK) + +proc computeDelta*(pow10: uint64x2; betaMinus1: int32): uint32 {.inline.} = + dragonbox_Assert(betaMinus1 >= 0) + dragonbox_Assert(betaMinus1 <= 63) + return cast[uint32](pow10.hi shr (64 - 1 - betaMinus1)) + +when defined(sizeof_Int128): + proc mul128*(x: uint64; y: uint64): uint64x2 {.inline.} = + ## 1 mulx + type + uint128T = uint128 + let p: uint128T = uint128T(x) * y + let hi: uint64 = cast[uint64](p shr 64) + let lo: uint64 = cast[uint64](p) + return (hi, lo) + +elif defined(vcc) and defined(cpu64): + proc mul128*(x: uint64; y: uint64): uint64x2 {.inline.} = + var hi: uint64 = 0 + var lo: uint64 = umul128(x, y, addr(hi)) + return (hi, lo) + +else: + proc lo32*(x: uint64): uint32 {.inline.} = + return cast[uint32](x) + + proc hi32*(x: uint64): uint32 {.inline.} = + return cast[uint32](x shr 32) + + proc mul128*(a: uint64; b: uint64): uint64x2 {.inline.} = + let b00: uint64 = uint64(lo32(a)) * lo32(b) + let b01: uint64 = uint64(lo32(a)) * hi32(b) + let b10: uint64 = uint64(hi32(a)) * lo32(b) + let b11: uint64 = uint64(hi32(a)) * hi32(b) + let mid1: uint64 = b10 + hi32(b00) + let mid2: uint64 = b01 + lo32(mid1) + let hi: uint64 = b11 + hi32(mid1) + hi32(mid2) + let lo: uint64 = lo32(b00) or uint64(lo32(mid2)) shl 32 + return uint64x2(hi: hi, lo: lo) + +## Returns (x * y) / 2^128 + +proc mulShift*(x: uint64; y: uint64x2): uint64 {.inline.} = + ## 2 mulx + var p1: uint64x2 = mul128(x, y.hi) + var p0: uint64x2 = mul128(x, y.lo) + p1.lo += p0.hi + inc(p1.hi, ord(p1.lo < p0.hi)) + return p1.hi + +proc mulParity*(twoF: uint64; pow10: uint64x2; betaMinus1: int32): bool {.inline.} = + ## 1 mulx, 1 mul + dragonbox_Assert(betaMinus1 >= 1) + dragonbox_Assert(betaMinus1 <= 63) + let p01: uint64 = twoF * pow10.hi + let p10: uint64 = mul128(twoF, pow10.lo).hi + let mid: uint64 = p01 + p10 + return (mid and (uint64(1) shl (64 - betaMinus1))) != 0 + +proc isIntegralEndpoint*(twoF: uint64; e2: int32; minusK: int32): bool {.inline.} = + if e2 < -2: + return false + if e2 <= 9: + return true + if e2 <= 86: + return multipleOfPow5(twoF, minusK) + return false + +proc isIntegralMidpoint*(twoF: uint64; e2: int32; minusK: int32): bool {.inline.} = + if e2 < -4: + return multipleOfPow2(twoF, minusK - e2 + 1) + if e2 <= 9: + return true + if e2 <= 86: + return multipleOfPow5(twoF, minusK) + return false + +proc toDecimal64*(ieeeSignificand: uint64; ieeeExponent: uint64): FloatingDecimal64 {. + inline.} = + const + kappa: int32 = 2 + const + bigDivisor: uint32 = 1000 + ## 10^(kappa + 1) + const + smallDivisor: uint32 = 100 + ## 10^(kappa) + ## + ## Step 1: + ## integer promotion & Schubfach multiplier calculation. + ## + var m2: uint64 + var e2: int32 + if ieeeExponent != 0: + m2 = hiddenBit or ieeeSignificand + e2 = cast[int32](ieeeExponent) - exponentBias + if 0 <= -e2 and -e2 < significandSize and multipleOfPow2(m2, -e2): + ## Small integer. + return FloatingDecimal64(significand: m2 shr -e2, exponent: 0) + if ieeeSignificand == 0 and ieeeExponent > 1: + ## Shorter interval case; proceed like Schubfach. + return toDecimal64AsymmetricInterval(e2) + else: + ## Subnormal case; interval is always regular. + m2 = ieeeSignificand + e2 = 1 - exponentBias + let isEven: bool = (m2 mod 2 == 0) + let acceptLower: bool = isEven + let acceptUpper: bool = isEven + ## Compute k and beta. + let minusK: int32 = floorLog10Pow2(e2) - kappa + let betaMinus1: int32 = e2 + floorLog2Pow10(-minusK) + dragonbox_Assert(betaMinus1 >= 6) + dragonbox_Assert(betaMinus1 <= 9) + let pow10: uint64x2 = computePow10(-minusK) + ## Compute delta + ## 10^kappa <= delta < 10^(kappa + 1) + ## 100 <= delta < 1000 + let delta: uint32 = computeDelta(pow10, betaMinus1) + dragonbox_Assert(delta >= smallDivisor) + dragonbox_Assert(delta < bigDivisor) + let twoFl: uint64 = 2 * m2 - 1 + let twoFc: uint64 = 2 * m2 + let twoFr: uint64 = 2 * m2 + 1 + ## (54 bits) + ## Compute zi + ## (54 + 9 = 63 bits) + let zi: uint64 = mulShift(twoFr shl betaMinus1, pow10) + ## 2 mulx + ## + ## Step 2: + ## Try larger divisor. + ## + var q: uint64 = zi div bigDivisor + ## uint64_t q = Mul128(zi, 0x83126E978D4FDF3Cu).hi >> 9; // 1 mulx + var r: uint32 = cast[uint32](zi) - bigDivisor * cast[uint32](q) + ## r = zi % BigDivisor + ## 0 <= r < 1000 + if r < delta: ## likely ~50% ?! + ## (r > deltai) + ## Exclude the right endpoint if necessary + if r != 0 or acceptUpper or not isIntegralEndpoint(twoFr, e2, minusK): + return FloatingDecimal64(significand: q, exponent: minusK + kappa + 1) + dragonbox_Assert(q != 0) + dec(q) + r = bigDivisor + elif r == delta: ## unlikely + ## Compare fractional parts. + ## Check conditions in the order different from the paper + ## to take advantage of short-circuiting + if (acceptLower and isIntegralEndpoint(twoFl, e2, minusK)) or + mulParity(twoFl, pow10, betaMinus1): + return FloatingDecimal64(significand: q, exponent: minusK + kappa + 1) + else: + discard + ## + ## Step 3: + ## Find the significand with the smaller divisor + ## + q = q * 10 + ## 1 hmul + ## 0 <= r <= 1000 + let dist: uint32 = r - (delta div 2) + (smallDivisor div 2) + let distQ: uint32 = dist div 100 + ## 1 mul + ## const uint32_t dist_r = dist % 100; + q += distQ + ## if /*likely*/ (dist_r == 0) + if dist == distQ * 100: + ## const bool approx_y_parity = ((dist ^ (SmallDivisor / 2)) & 1) != 0; + let approxYParity: bool = (dist and 1) != 0 + ## Check z^(f) >= epsilon^(f) + ## We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + ## where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f) + ## Since there are only 2 possibilities, we only need to care about the + ## parity. Also, zi and r should have the same parity since the divisor + ## is an even number + if mulParity(twoFc, pow10, betaMinus1) != approxYParity: + dec(q) + elif q mod 2 != 0 and isIntegralMidpoint(twoFc, e2, minusK): + dec(q) + return FloatingDecimal64(significand: q, exponent: minusK + kappa) + +## ================================================================================================== +## ToChars +## ================================================================================================== + +proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = + const + digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', + '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', + '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', + '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', + '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', + '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', + '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', + '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', + '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', + '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', + '9', '6', '9', '7', '9', '8', '9', '9'] + dragonbox_Assert(digits <= 99) + buf[pos] = digits100[2 * digits] + buf[pos+1] = digits100[2 * digits + 1] + #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) + +proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = + const + trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0] + dragonbox_Assert(digits <= 99) + return trailingZeros100[digits] + +when false: + template `+!`(x: cstring; offset: int): cstring = cast[cstring](cast[uint](x) + uint(offset)) + + template dec(x: cstring; offset=1) = x = cast[cstring](cast[uint](x) - uint(offset)) + template inc(x: cstring; offset=1) = x = cast[cstring](cast[uint](x) + uint(offset)) + + proc memset(x: cstring; ch: char; L: int) {.importc, nodecl.} + proc memmove(a, b: cstring; L: int) {.importc, nodecl.} + +proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int32 {.inline.} = + dragonbox_Assert(digits >= 1) + dragonbox_Assert(digits <= 99999999'u32) + let q: uint32 = digits div 10000 + let r: uint32 = digits mod 10000 + let qH: uint32 = q div 100 + let qL: uint32 = q mod 100 + utoa2Digits(buf, pos, qH) + utoa2Digits(buf, pos + 2, qL) + if r == 0: + return trailingZeros2Digits(if qL == 0: qH else: qL) + (if qL == 0: 6 else: 4) + else: + let rH: uint32 = r div 100 + let rL: uint32 = r mod 100 + utoa2Digits(buf, pos + 4, rH) + utoa2Digits(buf, pos + 6, rL) + return trailingZeros2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0) + +proc printDecimalDigitsBackwards*(buf: var openArray[char]; pos: int; output64: uint64): int32 {.inline.} = + var pos = pos + var output64 = output64 + var tz: int32 = 0 + ## number of trailing zeros removed. + var nd: int32 = 0 + ## number of decimal digits processed. + ## At most 17 digits remaining + if output64 >= 100000000'u64: + let q: uint64 = output64 div 100000000'u64 + let r: uint32 = cast[uint32](output64 mod 100000000'u64) + output64 = q + dec(pos, 8) + if r != 0: + tz = utoa8DigitsSkipTrailingZeros(buf, pos, r) + dragonbox_Assert(tz >= 0) + dragonbox_Assert(tz <= 7) + else: + tz = 8 + nd = 8 + dragonbox_Assert(output64 <= high(uint32)) + var output = cast[uint32](output64) + if output >= 10000: + let q: uint32 = output div 10000 + let r: uint32 = output mod 10000 + output = q + dec(pos, 4) + if r != 0: + let rH: uint32 = r div 100 + let rL: uint32 = r mod 100 + utoa2Digits(buf, pos, rH) + utoa2Digits(buf, pos + 2, rL) + if tz == nd: + inc(tz, trailingZeros2Digits(if rL == 0: rH else: rL) + + (if rL == 0: 2 else: 0)) + else: + if tz == nd: + inc(tz, 4) + else: + for i in 0..3: buf[pos+i] = '0' + ## (actually not required...) + inc(nd, 4) + if output >= 100: + let q: uint32 = output div 100 + let r: uint32 = output mod 100 + output = q + dec(pos, 2) + utoa2Digits(buf, pos, r) + if tz == nd: + inc(tz, trailingZeros2Digits(r)) + inc(nd, 2) + if output >= 100: + let q2: uint32 = output div 100 + let r2: uint32 = output mod 100 + output = q2 + dec(pos, 2) + utoa2Digits(buf, pos, r2) + if tz == nd: + inc(tz, trailingZeros2Digits(r2)) + inc(nd, 2) + dragonbox_Assert(output >= 1) + dragonbox_Assert(output <= 99) + if output >= 10: + let q: uint32 = output + dec(pos, 2) + utoa2Digits(buf, pos, q) + if tz == nd: + inc(tz, trailingZeros2Digits(q)) + else: + let q: uint32 = output + dragonbox_Assert(q >= 1) + dragonbox_Assert(q <= 9) + dec(pos) + buf[pos] = chr(ord('0') + q) + return tz + +proc decimalLength*(v: uint64): int32 {.inline.} = + dragonbox_Assert(v >= 1) + dragonbox_Assert(v <= 99999999999999999'u64) + if cast[uint32](v shr 32) != 0: + if v >= 10000000000000000'u64: + return 17 + if v >= 1000000000000000'u64: + return 16 + if v >= 100000000000000'u64: + return 15 + if v >= 10000000000000'u64: + return 14 + if v >= 1000000000000'u64: + return 13 + if v >= 100000000000'u64: + return 12 + if v >= 10000000000'u64: + return 11 + return 10 + let v32: uint32 = cast[uint32](v) + if v32 >= 1000000000'u: + return 10 + if v32 >= 100000000'u: + return 9 + if v32 >= 10000000'u: + return 8 + if v32 >= 1000000'u: + return 7 + if v32 >= 100000'u: + return 6 + if v32 >= 10000'u: + return 5 + if v32 >= 1000'u: + return 4 + if v32 >= 100'u: + return 3 + if v32 >= 10'u: + return 2 + return 1 + +proc formatDigits*(buffer: var openArray[char]; pos: int; digits: uint64; decimalExponent: int32; + forceTrailingDotZero = false): int {.inline.} = + const + minFixedDecimalPoint: int32 = -6 + const + maxFixedDecimalPoint: int32 = 17 + var pos = pos + assert(minFixedDecimalPoint <= -1, "internal error") + assert(maxFixedDecimalPoint >= 17, "internal error") + dragonbox_Assert(digits >= 1) + dragonbox_Assert(digits <= 99999999999999999'u64) + dragonbox_Assert(decimalExponent >= -999) + dragonbox_Assert(decimalExponent <= 999) + var numDigits: int32 = decimalLength(digits) + let decimalPoint: int32 = numDigits + decimalExponent + let useFixed: bool = minFixedDecimalPoint <= decimalPoint and + decimalPoint <= maxFixedDecimalPoint + ## Prepare the buffer. + for i in 0..<32: buffer[pos+i] = '0' + assert(minFixedDecimalPoint >= -30, "internal error") + assert(maxFixedDecimalPoint <= 32, "internal error") + var decimalDigitsPosition: int32 + if useFixed: + if decimalPoint <= 0: + ## 0.[000]digits + decimalDigitsPosition = 2 - decimalPoint + else: + ## dig.its + ## digits[000] + decimalDigitsPosition = 0 + else: + ## dE+123 or d.igitsE+123 + decimalDigitsPosition = 1 + var digitsEnd = pos + int(decimalDigitsPosition + numDigits) + let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits) + dec(digitsEnd, tz) + dec(numDigits, tz) + ## decimal_exponent += tz; // => decimal_point unchanged. + if useFixed: + if decimalPoint <= 0: + ## 0.[000]digits + buffer[pos+1] = '.' + pos = digitsEnd + elif decimalPoint < numDigits: + ## dig.its + when true: #defined(vcc) and not defined(clang): + ## VC does not inline the memmove call below. (Even if compiled with /arch:AVX2.) + ## However, memcpy will be inlined. + var tmp: array[16, char] + for i in 0..<16: tmp[i] = buffer[i+pos+decimalPoint] + for i in 0..<16: buffer[i+pos+decimalPoint+1] = tmp[i] + else: + memmove(buffer +! (decimalPoint + 1), buffer +! decimalPoint, 16) + buffer[pos+decimalPoint] = '.' + pos = digitsEnd + 1 + else: + ## digits[000] + inc(pos, decimalPoint) + if forceTrailingDotZero: + buffer[pos] = '.' + buffer[pos+1] = '0' + inc(pos, 2) + else: + ## Copy the first digit one place to the left. + buffer[pos] = buffer[pos+1] + if numDigits == 1: + ## dE+123 + inc(pos) + else: + ## d.igitsE+123 + buffer[pos+1] = '.' + pos = digitsEnd + let scientificExponent: int32 = decimalPoint - 1 + ## SF_ASSERT(scientific_exponent != 0); + buffer[pos] = 'e' + buffer[pos+1] = if scientificExponent < 0: '-' else: '+' + inc(pos, 2) + let k: uint32 = cast[uint32](if scientificExponent < 0: -scientificExponent else: scientificExponent) + if k < 10: + buffer[pos] = chr(ord('0') + k) + inc(pos) + elif k < 100: + utoa2Digits(buffer, pos, k) + inc(pos, 2) + else: + let q: uint32 = k div 100 + let r: uint32 = k mod 100 + buffer[pos] = chr(ord('0') + q) + inc(pos) + utoa2Digits(buffer, pos, r) + inc(pos, 2) + return pos + +proc toChars*(buffer: var openArray[char]; v: float; forceTrailingDotZero = false): int {. + inline.} = + var pos = 0 + let significand: uint64 = physicalSignificand(constructDouble(v)) + let exponent: uint64 = physicalExponent(constructDouble(v)) + if exponent != maxIeeeExponent: + ## Finite + buffer[pos] = '-' + inc(pos, signBit(constructDouble(v))) + if exponent != 0 or significand != 0: + ## != 0 + let dec = toDecimal64(significand, exponent) + return formatDigits(buffer, pos, dec.significand, dec.exponent, + forceTrailingDotZero) + else: + buffer[pos] = '0' + buffer[pos+1] = '.' + buffer[pos+2] = '0' + buffer[pos+3] = ' ' + inc(pos, if forceTrailingDotZero: 3 else: 1) + return pos + if significand == 0: + buffer[pos] = '-' + inc(pos, signBit(constructDouble(v))) + buffer[pos] = 'i' + buffer[pos+1] = 'n' + buffer[pos+2] = 'f' + buffer[pos+3] = ' ' + return pos + 3 + else: + buffer[pos] = 'n' + buffer[pos+1] = 'a' + buffer[pos+2] = 'n' + buffer[pos+3] = ' ' + return pos + 3 + +when false: + proc toString*(value: float): string = + var buffer: array[dtoaMinBufferLength, char] + let last = toChars(addr buffer, value) + let L = cast[int](last) - cast[int](addr(buffer)) + result = newString(L) + copyMem(addr result[0], addr buffer[0], L) + diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim index cb46c8c36..41bc56adc 100644 --- a/lib/system/formatfloat.nim +++ b/lib/system/formatfloat.nim @@ -7,53 +7,58 @@ # distribution, for details about the copyright. # -proc c_sprintf(buf, frmt: cstring): cint {.header: "", - importc: "sprintf", varargs, noSideEffect.} +when not defined(nimLegacyAddFloat) and not defined(nimscript) and + not defined(js) and defined(nimHasDragonBox): + import dragonbox -proc writeToBuffer(buf: var array[65, char]; value: cstring) = - var i = 0 - while value[i] != '\0': - buf[i] = value[i] - inc i + proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + result = toChars(buf, value, forceTrailingDotZero=true) + buf[result] = '\0' -proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats in the Nim - ## programming language. The specific format for floating point - ## numbers is not specified in the Nim programming language and - ## might change slightly in the future, but at least wherever you - ## format a float, it should be consistent. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - ## - ## * `buf` - A buffer to write into. The buffer does not need to be - ## initialized and it will be overridden. - ## - var n: int = c_sprintf(addr buf, "%.16g", value) - var hasDot = false - for i in 0..n-1: - if buf[i] == ',': - buf[i] = '.' - hasDot = true - elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: - hasDot = true - if not hasDot: - buf[n] = '.' - buf[n+1] = '0' - buf[n+2] = '\0' - result = n + 2 - else: - result = n - # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' - # of '-1.#IND' are produced. - # We want to get rid of these here: - if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: - writeToBuffer(buf, "nan") - result = 3 - elif buf[n-1] == 'F': - if buf[0] == '-': - writeToBuffer(buf, "-inf") - result = 4 +else: + proc c_sprintf(buf, frmt: cstring): cint {.header: "", + importc: "sprintf", varargs, noSideEffect.} + + proc writeToBuffer(buf: var array[65, char]; value: cstring) = + var i = 0 + while value[i] != '\0': + buf[i] = value[i] + inc i + + proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + var n: int = c_sprintf(addr buf, "%.16g", value) + var hasDot = false + for i in 0..n-1: + if buf[i] == ',': + buf[i] = '.' + hasDot = true + elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: + hasDot = true + if not hasDot: + buf[n] = '.' + buf[n+1] = '0' + buf[n+2] = '\0' + result = n + 2 else: - writeToBuffer(buf, "inf") + result = n + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' + # of '-1.#IND' are produced. + # We want to get rid of these here: + if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: + writeToBuffer(buf, "nan") result = 3 + elif buf[n-1] == 'F': + if buf[0] == '-': + writeToBuffer(buf, "-inf") + result = 4 + else: + writeToBuffer(buf, "inf") + result = 3 diff --git a/tests/float/tfloat6.nim b/tests/float/tfloat6.nim index c4cd6e932..c0e6e419f 100644 --- a/tests/float/tfloat6.nim +++ b/tests/float/tfloat6.nim @@ -1,10 +1,10 @@ discard """ output: ''' -1e-06 : 1e-06 -1e-06 : 1e-06 +0.000001 : 0.000001 +0.000001 : 0.000001 0.001 : 0.001 -1e-06 : 1e-06 -1e-06 : 1e-06 +0.000001 : 0.000001 +0.000001 : 0.000001 10.000001 : 10.000001 100.000001 : 100.000001 ''' From f10eef29b5d77ad45b00b0d4eb7e87f930c2a0a4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 2 Jun 2021 13:13:23 +0200 Subject: [PATCH 2649/4254] fixes #18059 (#18140) * fixes #18059 --- compiler/semexprs.nim | 28 ++++++++++++++++++++++++++-- compiler/semstmts.nim | 20 +++++++++++++++++++- tests/metatype/tcps.nim | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 tests/metatype/tcps.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8c4f25e12..c839d04d9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -54,7 +54,8 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n, flags + {efOperand}) if result.typ != nil: # XXX tyGenericInst here? - if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: + if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}): + #and tfUnresolved in result.typ.flags: localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: @@ -2649,6 +2650,23 @@ proc shouldBeBracketExpr(n: PNode): bool = n[0] = be return true +proc asBracketExpr(c: PContext; n: PNode): PNode = + proc isGeneric(c: PContext; n: PNode): bool = + if n.kind in {nkIdent, nkAccQuoted}: + let s = qualifiedLookUp(c, n, {}) + result = s != nil and isGenericRoutineStrict(s) + + assert n.kind in nkCallKinds + if n.len > 1 and isGeneric(c, n[1]): + let b = n[0] + if b.kind in nkSymChoices: + for i in 0.. Date: Wed, 2 Jun 2021 13:14:10 +0200 Subject: [PATCH 2650/4254] refactoring: removed empty withBracketExpr template (#18152) --- compiler/semgnrc.nim | 6 ++---- compiler/semtempl.nim | 14 ++++---------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index ebd361db6..4f3c50dae 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -303,8 +303,7 @@ proc semGenericStmt(c: PContext, n: PNode, result = newNodeI(nkCall, n.info) result.add newIdentNode(getIdent(c.cache, "[]"), n.info) for i in 0.. Date: Wed, 2 Jun 2021 09:02:14 -0700 Subject: [PATCH 2652/4254] fix #16993, #18054, #17835 runnableExamples now works with templates and nested templates (#18082) --- compiler/evaltempl.nim | 12 ++-- lib/system/assertions.nim | 47 ++++++--------- .../expected/subdir/subdir_b/utils.html | 4 +- nimdoc/testproject/expected/testproject.html | 11 ++-- nimdoc/testproject/subdir/subdir_b/utils.nim | 10 +++- tests/js/tstdlib_various.nim | 2 +- tests/nimdoc/trunnableexamples.nim | 57 ++++++++++++++++++- tests/nimdoc/trunnableexamples2.nim | 11 ++++ 8 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 tests/nimdoc/trunnableexamples2.nim diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index a85314ac2..8a6bf9287 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -83,10 +83,14 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = not c.isDeclarative: c.isDeclarative = true isDeclarative = true - var res = copyNode(c, templ, actual) - for i in 0..`_. + runnableExamples: assert 1 == 1 + runnableExamples("--assertions:off"): + assert 1 == 2 # no code generated, no failure here + runnableExamples("-d:danger"): assert 1 == 2 # ditto assertImpl(cond, msg, astToStr(cond), compileOption("assertions")) template doAssert*(cond: untyped, msg = "") = ## Similar to `assert <#assert.t,untyped,string>`_ but is always turned on regardless of `--assertions`. + runnableExamples: + doAssert 1 == 1 # generates code even when built with `-d:danger` or `--assertions:off` assertImpl(cond, msg, astToStr(cond), true) template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = ## Sets an assertion failure handler that will intercept any assert ## statements following `onFailedAssert` in the current scope. + runnableExamples: + type MyError = object of CatchableError + lineinfo: tuple[filename: string, line: int, column: int] + # block-wide policy to change the failed assert exception type in order to + # include a lineinfo + onFailedAssert(msg): + raise (ref MyError)(msg: msg, lineinfo: instantiationInfo(-2)) + doAssertRaises(MyError): doAssert false template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = let msg = msgIMPL code template doAssertRaises*(exception: typedesc, code: untyped) = ## Raises `AssertionDefect` if specified `code` does not raise `exception`. + runnableExamples: + doAssertRaises(ValueError): raise newException(ValueError, "Hello World") + doAssertRaises(CatchableError): raise newException(ValueError, "Hello World") + doAssertRaises(AssertionDefect): doAssert false var wrong = false const begin = "expected raising '" & astToStr(exception) & "', instead" const msgEnd = " by: " & astToStr(code) diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 794066cae..826cad02a 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -206,9 +206,9 @@ constructor.
    template fromUtilsGen(): untyped
    -this should be shown in utils.html +should be shown in utils.html only

    Example:

    -
    assert 3*2 == 6
    ditto +
    discard "should be in utils.html only, not in module that calls fromUtilsGen"
    ditto
    diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index d2fe38021..513dd507b 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -431,10 +431,7 @@ window.addEventListener('DOMContentLoaded', main); discard "in top2"
    top2 after

    Example:

    import testproject
    -discard "in top3"
    top3 after -

    Example:

    -
    import testproject
    -assert 3*2 == 6

    +discard "in top3"
    top3 after

    Imports

    @@ -574,7 +571,8 @@ My someFunc. Stuff in fromUtilsGen is called

    Example:

    -
    discard 1
    +
    discard """should be shown as examples for fromUtils3
    +       in module calling fromUtilsGen"""
    @@ -957,6 +955,9 @@ cz18
    ok3 +

    Example:

    +
    discard """should be shown as examples for fromUtils2
    +       in module calling fromUtilsGen"""
    diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index 128e8e481..4e3aa1f10 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -50,9 +50,9 @@ template bEnum*(): untyped = discard template fromUtilsGen*(): untyped = - ## this should be shown in utils.html + ## should be shown in utils.html only runnableExamples: - assert 3*2 == 6 + discard "should be in utils.html only, not in module that calls fromUtilsGen" ## ditto iterator fromUtils1*(): int = @@ -64,7 +64,11 @@ template fromUtilsGen*(): untyped = template fromUtils2*() = ## ok3 + runnableExamples: + discard """should be shown as examples for fromUtils2 + in module calling fromUtilsGen""" proc fromUtils3*() = ## came form utils but should be shown where `fromUtilsGen` is called - runnableExamples: discard 1 + runnableExamples: discard """should be shown as examples for fromUtils3 + in module calling fromUtilsGen""" diff --git a/tests/js/tstdlib_various.nim b/tests/js/tstdlib_various.nim index a1bb63d46..4b5ce1de8 100644 --- a/tests/js/tstdlib_various.nim +++ b/tests/js/tstdlib_various.nim @@ -153,7 +153,7 @@ block tsplit2: var errored = false try: discard "hello".split("") - except AssertionError: + except AssertionDefect: errored = true doAssert errored diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim index bc5ea0e5e..ac7a0e26f 100644 --- a/tests/nimdoc/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -1,6 +1,7 @@ discard """ -cmd: "nim doc --doccmd:-d:testFooExternal --hints:off $file" +cmd: "nim doc --doccmd:--hints:off --hints:off $file" action: "compile" +nimoutFull: true nimout: ''' foo1 foo2 @@ -8,12 +9,23 @@ foo3 foo5 foo6 foo7 +in examplesInTemplate1 +doc in outer +doc in inner1 +doc in inner2 foo8 foo9 ''' joinable: false """ +#[ +pending bug #18077, use instead: +cmd: "nim doc --doccmd:'-d:testFooExternal --hints:off' --hints:off $file" +and merge trunnableexamples2 back here +]# +{.define(testFooExternal).} + proc fun*() = runnableExamples: block: # `defer` only allowed inside a block @@ -109,6 +121,47 @@ when true: # runnableExamples with rdoccmd # passing seq (to run with multiple compilation options) runnableExamples(@["-b:cpp", "-b:js"]): discard +when true: # bug #16993 + template examplesInTemplate1*(cond: untyped) = + ## in examplesInTemplate1 + runnableExamples: + echo "in examplesInTemplate1" + discard + examplesInTemplate1 true + examplesInTemplate1 true + examplesInTemplate1 true + +when true: # bug #18054 + template outer*(body: untyped) = + ## outer template doc string. + runnableExamples: + echo "doc in outer" + ## + template inner1*() = + ## inner1 template doc string. + runnableExamples: + echo "doc in inner1" + ## + + template inner2*() = + ## inner2 template doc string. + runnableExamples: + echo "doc in inner2" + body + outer: + inner1() + inner2() + +when true: # bug #17835 + template anyItFake*(s, pred: untyped): bool = + ## Foo + runnableExamples: discard + true + + proc anyItFakeMain*(n: seq[int]): bool = + result = anyItFake(n, it == 0) + # this was giving: Error: runnableExamples must appear before the first non-comment statement + runnableExamples: block: # bug #17279 when int.sizeof == 8: @@ -118,7 +171,7 @@ runnableExamples: # bug #13491 block: proc fun(): int = doAssert false - doAssertRaises(AssertionError, (discard fun())) + doAssertRaises(AssertionDefect, (discard fun())) block: template foo(body) = discard diff --git a/tests/nimdoc/trunnableexamples2.nim b/tests/nimdoc/trunnableexamples2.nim new file mode 100644 index 000000000..5a437744e --- /dev/null +++ b/tests/nimdoc/trunnableexamples2.nim @@ -0,0 +1,11 @@ +discard """ +cmd: "nim doc --doccmd:-d:testFooExternal --hints:off $file" +action: "compile" +joinable: false +""" + +# pending bug #18077, merge back inside trunnableexamples.nim +when true: # runnableExamples with rdoccmd + runnableExamples "-d:testFoo -d:testBar": + doAssert defined(testFoo) and defined(testBar) + doAssert defined(testFooExternal) From f27f3f65df0bab567cc416cd1332a502833bd12f Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 3 Jun 2021 10:59:06 +0800 Subject: [PATCH 2653/4254] [std/hashcommon]improve docs a bit (#18153) * reduce duplicated deprecated messages --- lib/pure/collections/hashcommon.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index 030446176..a169418ce 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -34,10 +34,10 @@ proc slotsNeeded(count: Natural): int {.inline.} = result = nextPowerOfTwo(count * 3 div 2 + 4) proc rightSize*(count: Natural): int {.inline, deprecated: "Deprecated since 1.4.0".} = - ## **Deprecated since Nim v1.4.0**, it is not needed anymore - ## because picking the correct size is done internally. + ## It is not needed anymore because + ## picking the correct size is done internally. ## - ## Return the value of `initialSize` to support `count` items. + ## Returns the value of `initialSize` to support `count` items. ## ## If more items are expected to be added, simply add that ## expected extra amount to the parameter before calling this. From bbce3d2da919bef2900e4061b9b8a99cb84fdf57 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 3 Jun 2021 12:09:04 +0800 Subject: [PATCH 2654/4254] [std/tables] remove unnecessary `do: ` (#18160) --- lib/pure/collections/tables.nim | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index b71bb0845..d617e06e4 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -594,17 +594,17 @@ template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) = let u = User(name: "Hello", uid: 99) t[1] = u - t.withValue(1, value) do: + t.withValue(1, value): # block is executed only if `key` in `t` value.name = "Nim" value.uid = 1314 - t.withValue(2, value) do: + t.withValue(2, value): value.name = "No" value.uid = 521 - doAssert t[1].name == "Nim" - doAssert t[1].uid == 1314 + assert t[1].name == "Nim" + assert t[1].uid == 1314 mixin rawGet var hc: Hash @@ -629,16 +629,22 @@ template withValue*[A, B](t: var Table[A, B], key: A, let u = User(name: "Hello", uid: 99) t[1] = u - t.withValue(1, value) do: + t.withValue(1, value): # block is executed only if `key` in `t` value.name = "Nim" value.uid = 1314 - # do: - # # block is executed when `key` not in `t` - # raise newException(KeyError, "Key not found") - doAssert t[1].name == "Nim" - doAssert t[1].uid == 1314 + t.withValue(521, value): + doAssert false + do: + # block is executed when `key` not in `t` + t[1314] = User(name: "exist", uid: 521) + + assert t[1].name == "Nim" + assert t[1].uid == 1314 + assert t[1314].name == "exist" + assert t[1314].uid == 521 + mixin rawGet var hc: Hash var index = rawGet(t, key, hc) From 06960bb9cb6bb548c8f72882169ae65e14f29e89 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 3 Jun 2021 13:35:24 +0800 Subject: [PATCH 2655/4254] Ref #17697 improve withValue docs (#18154) * Ref #17697 improve withValue docs * address comments --- lib/pure/collections/sharedtables.nim | 81 +++++++++++++++++---------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 4ac3befb6..2788ec785 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -60,17 +60,27 @@ template withLock(t, x: untyped) = template withValue*[A, B](t: var SharedTable[A, B], key: A, value, body: untyped) = - ## retrieves the value at `t[key]`. + ## Retrieves the value at `t[key]`. ## `value` can be modified in the scope of the `withValue` call. - ## - ## .. code-block:: nim - ## - ## sharedTable.withValue(key, value) do: - ## # block is executed only if `key` in `t` - ## # value is threadsafe in block - ## value.name = "username" - ## value.uid = 1000 - ## + runnableExamples: + var table: SharedTable[string, string] + init(table) + + table["a"] = "x" + table["b"] = "y" + table["c"] = "z" + + table.withValue("a", value): + assert value[] == "x" + + table.withValue("b", value): + value[] = "modified" + + table.withValue("b", value): + assert value[] == "modified" + + table.withValue("nonexistent", value): + assert false # not called acquire(t.lock) try: var hc: Hash @@ -84,20 +94,29 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, template withValue*[A, B](t: var SharedTable[A, B], key: A, value, body1, body2: untyped) = - ## retrieves the value at `t[key]`. + ## Retrieves the value at `t[key]`. ## `value` can be modified in the scope of the `withValue` call. - ## - ## .. code-block:: nim - ## - ## sharedTable.withValue(key, value) do: - ## # block is executed only if `key` in `t` - ## # value is threadsafe in block - ## value.name = "username" - ## value.uid = 1000 - ## do: - ## # block is executed when `key` not in `t` - ## raise newException(KeyError, "Key not found") - ## + runnableExamples: + var table: SharedTable[string, string] + init(table) + + table["a"] = "x" + table["b"] = "y" + table["c"] = "z" + + + table.withValue("a", value): + value[] = "m" + + table.withValue("d", value): + discard value + doAssert false + do: # if "d" notin table + table["d"] = "n" + + assert table.mget("a") == "m" + assert table.mget("d") == "n" + acquire(t.lock) try: var hc: Hash @@ -112,7 +131,7 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, release(t.lock) proc mget*[A, B](t: var SharedTable[A, B], key: A): var B = - ## retrieves the value at `t[key]`. The value can be modified. + ## Retrieves the value at `t[key]`. The value can be modified. ## If `key` is not in `t`, the `KeyError` exception is raised. withLock t: var hc: Hash @@ -126,7 +145,7 @@ proc mget*[A, B](t: var SharedTable[A, B], key: A): var B = raise newException(KeyError, "key not found") proc mgetOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): var B = - ## retrieves value at `t[key]` or puts `val` if not present, either way + ## Retrieves value at `t[key]` or puts `val` if not present, either way ## returning a value which can be modified. **Note**: This is inherently ## unsafe in the context of multi-threading since it returns a pointer ## to `B`. @@ -134,7 +153,7 @@ proc mgetOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): var B = mgetOrPutImpl(enlarge) proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool = - ## returns true if `key` is in the table, otherwise inserts `value`. + ## Returns true if `key` is in the table, otherwise inserts `value`. withLock t: hasKeyOrPutImpl(enlarge) @@ -191,28 +210,28 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A, st_maybeRehashPutImpl(enlarge) proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) = - ## puts a (key, value)-pair into `t`. + ## Puts a (key, value)-pair into `t`. withLock t: putImpl(enlarge) proc add*[A, B](t: var SharedTable[A, B], key: A, val: B) = - ## puts a new (key, value)-pair into `t` even if `t[key]` already exists. + ## Puts a new (key, value)-pair into `t` even if `t[key]` already exists. ## This can introduce duplicate keys into the table! withLock t: addImpl(enlarge) proc del*[A, B](t: var SharedTable[A, B], key: A) = - ## deletes `key` from hash table `t`. + ## Deletes `key` from hash table `t`. withLock t: delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash) proc len*[A, B](t: var SharedTable[A, B]): int = - ## number of elements in `t` + ## Number of elements in `t`. withLock t: result = t.counter proc init*[A, B](t: var SharedTable[A, B], initialSize = 32) = - ## creates a new hash table that is empty. + ## Creates a new hash table that is empty. ## ## This proc must be called before any other usage of `t`. let initialSize = slotsNeeded(initialSize) From daaa40973c65c46f8d38dc6033f56fffcd7d8d3f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 3 Jun 2021 12:09:40 +0200 Subject: [PATCH 2656/4254] added float32 schubfach algorithm; wip (#18155) * added float32 schubfach algorithm; wip * fixes #18418 --- compiler/ccgexprs.nim | 6 +- lib/system/dollars.nim | 4 + lib/system/schubfach.nim | 451 +++++++++++++++++++++++++++++++++++++++ lib/system/strmantle.nim | 13 ++ tests/float/tfloat6.nim | 5 + 5 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 lib/system/schubfach.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7cb403a94..7ed80145b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2300,7 +2300,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)") of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") - of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)") + of mFloatToStr: + if e[1].typ.skipTypes(abstractInst).kind == tyFloat32: + genDollar(p, e, d, "#nimFloat32ToStr($1)") + else: + genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e[1], d) of mIsolate: genCall(p, e, d) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index ce4e8e0ca..5a7a77e56 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -58,6 +58,10 @@ proc `$`*(x: float): string {.magic: "FloatToStr", noSideEffect.} ## The stringify operator for a float argument. Returns `x` ## converted to a decimal string. +proc `$`*(x: float32): string {.magic: "FloatToStr", noSideEffect.} + ## The stringify operator for a float32 argument. Returns `x` + ## converted to a decimal string. + proc `$`*(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## The stringify operator for a boolean argument. Returns `x` ## converted to the string "false" or "true". diff --git a/lib/system/schubfach.nim b/lib/system/schubfach.nim new file mode 100644 index 000000000..c344b7425 --- /dev/null +++ b/lib/system/schubfach.nim @@ -0,0 +1,451 @@ +## Copyright 2020 Alexander Bolz +## +## Distributed under the Boost Software License, Version 1.0. +## (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) + +## -------------------------------------------------------------------------------------------------- +## This file contains an implementation of the Schubfach algorithm as described in +## +## [1] Raffaello Giulietti, "The Schubfach way to render doubles", +## https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN +## -------------------------------------------------------------------------------------------------- + +template sf_Assert(x: untyped): untyped = + assert(x) + +## ================================================================================================== +## +## ================================================================================================== + +type + ValueType = float32 + BitsType = uint32 + Single {.bycopy.} = object + bits: BitsType + +const + significandSize: int32 = 24 + MaxExponent = 128 + exponentBias: int32 = MaxExponent - 1 + (significandSize - 1) + maxIeeeExponent: BitsType = BitsType(2 * MaxExponent - 1) + hiddenBit: BitsType = BitsType(1) shl (significandSize - 1) + significandMask: BitsType = hiddenBit - 1 + exponentMask: BitsType = maxIeeeExponent shl (significandSize - 1) + signMask: BitsType = not (not BitsType(0) shr 1) + +proc constructSingle(bits: BitsType): Single {.constructor.} = + result.bits = bits + +proc constructSingle(value: ValueType): Single {.constructor.} = + result.bits = cast[typeof(result.bits)](value) + +proc physicalSignificand(this: Single): BitsType {.noSideEffect.} = + return this.bits and significandMask + +proc physicalExponent(this: Single): BitsType {.noSideEffect.} = + return (this.bits and exponentMask) shr (significandSize - 1) + +proc isFinite(this: Single): bool {.noSideEffect.} = + return (this.bits and exponentMask) != exponentMask + +proc isInf(this: Single): bool {.noSideEffect.} = + return (this.bits and exponentMask) == exponentMask and + (this.bits and significandMask) == 0 + +proc isNaN(this: Single): bool {.noSideEffect.} = + return (this.bits and exponentMask) == exponentMask and + (this.bits and significandMask) != 0 + +proc isZero(this: Single): bool {.noSideEffect.} = + return (this.bits and not signMask) == 0 + +proc signBit(this: Single): int {.noSideEffect.} = + return int((this.bits and signMask) != 0) + +## ================================================================================================== +## Returns floor(x / 2^n). +## +## Technically, right-shift of negative integers is implementation defined... +## Should easily be optimized into SAR (or equivalent) instruction. + +proc floorDivPow2(x: int32; n: int32): int32 {.inline.} = + return x shr n + +## Returns floor(log_10(2^e)) +## static inline int32_t FloorLog10Pow2(int32_t e) +## { +## SF_ASSERT(e >= -1500); +## SF_ASSERT(e <= 1500); +## return FloorDivPow2(e * 1262611, 22); +## } +## Returns floor(log_10(3/4 2^e)) +## static inline int32_t FloorLog10ThreeQuartersPow2(int32_t e) +## { +## SF_ASSERT(e >= -1500); +## SF_ASSERT(e <= 1500); +## return FloorDivPow2(e * 1262611 - 524031, 22); +## } +## Returns floor(log_2(10^e)) + +proc floorLog2Pow10(e: int32): int32 {.inline.} = + sf_Assert(e >= -1233) + sf_Assert(e <= 1233) + return floorDivPow2(e * 1741647, 19) + +proc computePow10Single(k: int32): uint64 {.inline.} = + ## There are unique beta and r such that 10^k = beta 2^r and + ## 2^63 <= beta < 2^64, namely r = floor(log_2 10^k) - 63 and + ## beta = 2^-r 10^k. + ## Let g = ceil(beta), so (g-1) 2^r < 10^k <= g 2^r, with the latter + ## value being a pretty good overestimate for 10^k. + ## NB: Since for all the required exponents k, we have g < 2^64, + ## all constants can be stored in 128-bit integers. + const + kMin: int32 = -31 + kMax: int32 = 45 + g: array[kMax - kMin + 1, uint64] = [0x81CEB32C4B43FCF5'u64, 0xA2425FF75E14FC32'u64, + 0xCAD2F7F5359A3B3F'u64, 0xFD87B5F28300CA0E'u64, 0x9E74D1B791E07E49'u64, + 0xC612062576589DDB'u64, 0xF79687AED3EEC552'u64, 0x9ABE14CD44753B53'u64, + 0xC16D9A0095928A28'u64, 0xF1C90080BAF72CB2'u64, 0x971DA05074DA7BEF'u64, + 0xBCE5086492111AEB'u64, 0xEC1E4A7DB69561A6'u64, 0x9392EE8E921D5D08'u64, + 0xB877AA3236A4B44A'u64, 0xE69594BEC44DE15C'u64, 0x901D7CF73AB0ACDA'u64, + 0xB424DC35095CD810'u64, 0xE12E13424BB40E14'u64, 0x8CBCCC096F5088CC'u64, + 0xAFEBFF0BCB24AAFF'u64, 0xDBE6FECEBDEDD5BF'u64, 0x89705F4136B4A598'u64, + 0xABCC77118461CEFD'u64, 0xD6BF94D5E57A42BD'u64, 0x8637BD05AF6C69B6'u64, + 0xA7C5AC471B478424'u64, 0xD1B71758E219652C'u64, 0x83126E978D4FDF3C'u64, + 0xA3D70A3D70A3D70B'u64, 0xCCCCCCCCCCCCCCCD'u64, 0x8000000000000000'u64, + 0xA000000000000000'u64, 0xC800000000000000'u64, 0xFA00000000000000'u64, + 0x9C40000000000000'u64, 0xC350000000000000'u64, 0xF424000000000000'u64, + 0x9896800000000000'u64, 0xBEBC200000000000'u64, 0xEE6B280000000000'u64, + 0x9502F90000000000'u64, 0xBA43B74000000000'u64, 0xE8D4A51000000000'u64, + 0x9184E72A00000000'u64, 0xB5E620F480000000'u64, 0xE35FA931A0000000'u64, + 0x8E1BC9BF04000000'u64, 0xB1A2BC2EC5000000'u64, 0xDE0B6B3A76400000'u64, + 0x8AC7230489E80000'u64, 0xAD78EBC5AC620000'u64, 0xD8D726B7177A8000'u64, + 0x878678326EAC9000'u64, 0xA968163F0A57B400'u64, 0xD3C21BCECCEDA100'u64, + 0x84595161401484A0'u64, 0xA56FA5B99019A5C8'u64, 0xCECB8F27F4200F3A'u64, + 0x813F3978F8940985'u64, 0xA18F07D736B90BE6'u64, 0xC9F2C9CD04674EDF'u64, + 0xFC6F7C4045812297'u64, 0x9DC5ADA82B70B59E'u64, 0xC5371912364CE306'u64, + 0xF684DF56C3E01BC7'u64, 0x9A130B963A6C115D'u64, 0xC097CE7BC90715B4'u64, + 0xF0BDC21ABB48DB21'u64, 0x96769950B50D88F5'u64, 0xBC143FA4E250EB32'u64, + 0xEB194F8E1AE525FE'u64, 0x92EFD1B8D0CF37BF'u64, 0xB7ABC627050305AE'u64, + 0xE596B7B0C643C71A'u64, 0x8F7E32CE7BEA5C70'u64, 0xB35DBF821AE4F38C'u64] + sf_Assert(k >= kMin) + sf_Assert(k <= kMax) + return g[k - kMin] + +proc lo32(x: uint64): uint32 {.inline.} = + return cast[uint32](x) + +proc hi32(x: uint64): uint32 {.inline.} = + return cast[uint32](x shr 32) + +when defined(sizeof_Int128): + proc roundToOdd(g: uint64; cp: uint32): uint32 {.inline.} = + let p: uint128 = uint128(g) * cp + let y1: uint32 = lo32(cast[uint64](p shr 64)) + let y0: uint32 = hi32(cast[uint64](p)) + return y1 or uint32(y0 > 1) + +elif defined(vcc) and defined(cpu64): + proc roundToOdd(g: uint64; cpHi: uint32): uint32 {.inline.} = + var p1: uint64 = 0 + var p0: uint64 = umul128(g, cpHi, addr(p1)) + let y1: uint32 = lo32(p1) + let y0: uint32 = hi32(p0) + return y1 or uint32(y0 > 1) + +else: + proc roundToOdd(g: uint64; cp: uint32): uint32 {.inline.} = + let b01: uint64 = uint64(lo32(g)) * cp + let b11: uint64 = uint64(hi32(g)) * cp + let hi: uint64 = b11 + hi32(b01) + let y1: uint32 = hi32(hi) + let y0: uint32 = lo32(hi) + return y1 or uint32(y0 > 1) + +## Returns whether value is divisible by 2^e2 + +proc multipleOfPow2(value: uint32; e2: int32): bool {.inline.} = + sf_Assert(e2 >= 0) + sf_Assert(e2 <= 31) + return (value and ((uint32(1) shl e2) - 1)) == 0 + +type + FloatingDecimal32 {.bycopy.} = object + digits: uint32 ## num_digits <= 9 + exponent: int32 + +proc toDecimal32(ieeeSignificand: uint32; ieeeExponent: uint32): FloatingDecimal32 {. + inline.} = + var c: uint32 + var q: int32 + if ieeeExponent != 0: + c = hiddenBit or ieeeSignificand + q = cast[int32](ieeeExponent) - exponentBias + if 0 <= -q and -q < significandSize and multipleOfPow2(c, -q): + return FloatingDecimal32(digits: c shr -q, exponent: 0'i32) + else: + c = ieeeSignificand + q = 1 - exponentBias + let isEven: bool = (c mod 2 == 0) + let lowerBoundaryIsCloser: bool = (ieeeSignificand == 0 and ieeeExponent > 1) + ## const int32_t qb = q - 2; + let cbl: uint32 = 4 * c - 2 + uint32(lowerBoundaryIsCloser) + let cb: uint32 = 4 * c + let cbr: uint32 = 4 * c + 2 + ## (q * 1262611 ) >> 22 == floor(log_10( 2^q)) + ## (q * 1262611 - 524031) >> 22 == floor(log_10(3/4 2^q)) + sf_Assert(q >= -1500) + sf_Assert(q <= 1500) + let k: int32 = floorDivPow2(q * 1262611 - (if lowerBoundaryIsCloser: 524031 else: 0), 22) + let h: int32 = q + floorLog2Pow10(-k) + 1 + sf_Assert(h >= 1) + sf_Assert(h <= 4) + let pow10: uint64 = computePow10Single(-k) + let vbl: uint32 = roundToOdd(pow10, cbl shl h) + let vb: uint32 = roundToOdd(pow10, cb shl h) + let vbr: uint32 = roundToOdd(pow10, cbr shl h) + let lower: uint32 = vbl + uint32(not isEven) + let upper: uint32 = vbr - uint32(not isEven) + ## See Figure 4 in [1]. + ## And the modifications in Figure 6. + let s: uint32 = vb div 4 + ## NB: 4 * s == vb & ~3 == vb & -4 + if s >= 10: + let sp: uint32 = s div 10 + ## = vb / 40 + let upInside: bool = lower <= 40 * sp + let wpInside: bool = 40 * sp + 40 <= upper + ## if (up_inside || wp_inside) // NB: At most one of u' and w' is in R_v. + if upInside != wpInside: + return FloatingDecimal32(digits: sp + uint32(wpInside), exponent: k + 1) + let uInside: bool = lower <= 4 * s + let wInside: bool = 4 * s + 4 <= upper + if uInside != wInside: + return FloatingDecimal32(digits: s + uint32(wInside), exponent: k) + let mid: uint32 = 4 * s + 2 + ## = 2(s + t) + let roundUp: bool = vb > mid or (vb == mid and (s and 1) != 0) + return FloatingDecimal32(digits: s + uint32(roundUp), exponent: k) + +## ================================================================================================== +## ToChars +## ================================================================================================== + +proc utoa2Digits(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = + const + digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', + '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', + '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', + '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', + '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', + '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', + '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', + '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', + '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', + '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', + '9', '6', '9', '7', '9', '8', '9', '9'] + sf_Assert(digits <= 99) + buf[pos] = digits100[2 * digits] + buf[pos+1] = digits100[2 * digits + 1] + +proc trailingZeros2Digits(digits: uint32): int32 {.inline.} = + const + trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0] + sf_Assert(digits <= 99) + return trailingZeros100[digits] + +proc printDecimalDigitsBackwards(buf: var openArray[char]; pos: int; output: uint32): int32 {.inline.} = + var output = output + var pos = pos + var tz: int32 = 0 + ## number of trailing zeros removed. + var nd: int32 = 0 + ## number of decimal digits processed. + ## At most 9 digits remaining + if output >= 10000: + let q: uint32 = output div 10000 + let r: uint32 = output mod 10000 + output = q + dec(pos, 4) + if r != 0: + let rH: uint32 = r div 100 + let rL: uint32 = r mod 100 + utoa2Digits(buf, pos, rH) + utoa2Digits(buf, pos + 2, rL) + tz = trailingZeros2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0) + else: + tz = 4 + nd = 4 + if output >= 100: + let q: uint32 = output div 100 + let r: uint32 = output mod 100 + output = q + dec(pos, 2) + utoa2Digits(buf, pos, r) + if tz == nd: + inc(tz, trailingZeros2Digits(r)) + inc(nd, 2) + if output >= 100: + let q2: uint32 = output div 100 + let r2: uint32 = output mod 100 + output = q2 + dec(pos, 2) + utoa2Digits(buf, pos, r2) + if tz == nd: + inc(tz, trailingZeros2Digits(r2)) + inc(nd, 2) + sf_Assert(output >= 1) + sf_Assert(output <= 99) + if output >= 10: + let q: uint32 = output + dec(pos, 2) + utoa2Digits(buf, pos, q) + if tz == nd: + inc(tz, trailingZeros2Digits(q)) + else: + let q: uint32 = output + sf_Assert(q >= 1) + sf_Assert(q <= 9) + dec(pos) + buf[pos] = chr(uint32('0') + q) + return tz + +proc decimalLength(v: uint32): int32 {.inline.} = + sf_Assert(v >= 1) + sf_Assert(v <= 999999999'u) + if v >= 100000000'u: + return 9 + if v >= 10000000'u: + return 8 + if v >= 1000000'u: + return 7 + if v >= 100000'u: + return 6 + if v >= 10000'u: + return 5 + if v >= 1000'u: + return 4 + if v >= 100'u: + return 3 + if v >= 10'u: + return 2 + return 1 + +proc formatDigits(buffer: var openArray[char]; pos: int; digits: uint32; decimalExponent: int32; + forceTrailingDotZero: bool = false): int {.inline.} = + const + minFixedDecimalPoint: int32 = -4 + maxFixedDecimalPoint: int32 = 9 + var pos = pos + assert(minFixedDecimalPoint <= -1, "internal error") + assert(maxFixedDecimalPoint >= 1, "internal error") + sf_Assert(digits >= 1) + sf_Assert(digits <= 999999999'u) + sf_Assert(decimalExponent >= -99) + sf_Assert(decimalExponent <= 99) + var numDigits: int32 = decimalLength(digits) + let decimalPoint: int32 = numDigits + decimalExponent + let useFixed: bool = minFixedDecimalPoint <= decimalPoint and + decimalPoint <= maxFixedDecimalPoint + ## Prepare the buffer. + ## Avoid calling memset/memcpy with variable arguments below... + for i in 0..<32: buffer[pos+i] = '0' + assert(minFixedDecimalPoint >= -30, "internal error") + assert(maxFixedDecimalPoint <= 32, "internal error") + var decimalDigitsPosition: int32 + if useFixed: + if decimalPoint <= 0: + ## 0.[000]digits + decimalDigitsPosition = 2 - decimalPoint + else: + ## dig.its + ## digits[000] + decimalDigitsPosition = 0 + else: + ## dE+123 or d.igitsE+123 + decimalDigitsPosition = 1 + var digitsEnd = pos + decimalDigitsPosition + numDigits + let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits) + dec(digitsEnd, tz) + dec(numDigits, tz) + ## decimal_exponent += tz; // => decimal_point unchanged. + if useFixed: + if decimalPoint <= 0: + ## 0.[000]digits + buffer[pos+1] = '.' + pos = digitsEnd + elif decimalPoint < numDigits: + ## dig.its + for i in 0..<8: + buffer[i + decimalPoint + 1] = buffer[i + decimalPoint] + buffer[pos+decimalPoint] = '.' + pos = digitsEnd + 1 + else: + ## digits[000] + inc(pos, decimalPoint) + if forceTrailingDotZero: + buffer[pos] = '.' + buffer[pos+1] = '0' + inc(pos, 2) + else: + buffer[pos] = buffer[pos+1] + if numDigits == 1: + ## dE+123 + inc(pos) + else: + ## d.igitsE+123 + buffer[pos+1] = '.' + pos = digitsEnd + let scientificExponent: int32 = decimalPoint - 1 + ## SF_ASSERT(scientific_exponent != 0); + buffer[pos] = 'e' + buffer[pos+1] = if scientificExponent < 0: '-' else: '+' + inc(pos, 2) + let k: uint32 = cast[uint32](if scientificExponent < 0: -scientificExponent else: scientificExponent) + if k < 10: + buffer[pos] = chr(uint32('0') + k) + inc pos + else: + utoa2Digits(buffer, pos, k) + inc(pos, 2) + return pos + +proc float32ToChars*(buffer: var openArray[char]; v: float32; forceTrailingDotZero = false): int {. + inline.} = + let significand: uint32 = physicalSignificand(constructSingle(v)) + let exponent: uint32 = physicalExponent(constructSingle(v)) + var pos = 0 + if exponent != maxIeeeExponent: + ## Finite + buffer[pos] = '-' + inc(pos, signBit(constructSingle(v))) + if exponent != 0 or significand != 0: + ## != 0 + let dec: auto = toDecimal32(significand, exponent) + return formatDigits(buffer, pos, dec.digits, dec.exponent, forceTrailingDotZero) + else: + buffer[pos] = '0' + buffer[pos+1] = '.' + buffer[pos+2] = '0' + buffer[pos+3] = ' ' + inc(pos, if forceTrailingDotZero: 3 else: 1) + return pos + if significand == 0: + buffer[pos] = '-' + inc(pos, signBit(constructSingle(v))) + buffer[pos] = 'i' + buffer[pos+1] = 'n' + buffer[pos+2] = 'f' + buffer[pos+3] = ' ' + return pos + 3 + else: + buffer[pos] = 'n' + buffer[pos+1] = 'a' + buffer[pos+2] = 'n' + buffer[pos+3] = ' ' + return pos + 3 diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 42ea9d226..1a32a4afe 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -164,6 +164,19 @@ proc nimFloatToStr(f: float): string {.compilerproc.} = result = newStringOfCap(8) result.addFloat f +when not defined(nimLegacyAddFloat) and not defined(nimscript) and + not defined(js) and defined(nimHasDragonBox): + import schubfach + +proc nimFloat32ToStr(f: float32): string {.compilerproc.} = + when declared(float32ToChars): + result = newString(65) + let L = float32ToChars(result, f, forceTrailingDotZero=true) + setLen(result, L) + else: + result = newStringOfCap(8) + result.addFloat f + proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. importc: "strtod", header: "", noSideEffect.} diff --git a/tests/float/tfloat6.nim b/tests/float/tfloat6.nim index c0e6e419f..fa8fc9da8 100644 --- a/tests/float/tfloat6.nim +++ b/tests/float/tfloat6.nim @@ -21,3 +21,8 @@ echo "0.00000_1".parseFloat(), " : ", 1E-6 echo "1_0.00_0001".parseFloat(), " : ", 10.000001 echo "1__00.00_0001".parseFloat(), " : ", 1_00.000001 + +# bug #18148 + +var a = 1.1'f32 +doAssert $a == "1.1", $a # fails From 282d61bafa4f1b06e1328cf8e517f556fb86d592 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 3 Jun 2021 14:00:53 +0200 Subject: [PATCH 2657/4254] added lib/deps.txt --- lib/deps.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 lib/deps.txt diff --git a/lib/deps.txt b/lib/deps.txt new file mode 100644 index 000000000..2a44b5fe2 --- /dev/null +++ b/lib/deps.txt @@ -0,0 +1,14 @@ +# Dragonbox.nim and Schubfach.nim + +"Dragonbox" is Nim's "float64 to string" algorithm. +"Schubfach" is Nim's "float32 to string" algorithm. These are based on + +https://github.com/abolz/Drachennest/blob/master/src/dragonbox.cc +https://github.com/abolz/Drachennest/blob/master/src/schubfach_32.cc + +commit e6714a39ad331b4489d0b6aaf3968635bff4eb5e + +The `.cc` files were translated by c2nim via `--cpp --keepBodies --nep1` +and then modified to remove the unsafe code. + +We used c2nim as of commit f0469c909d9e2e28d59687e394bf5ac862f561b6. From 9df631a379998f554748697da7fe95ce4463cb83 Mon Sep 17 00:00:00 2001 From: n5m <72841454+n5m@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:25:52 +0000 Subject: [PATCH 2658/4254] reuse algorithm.fill while building SkipTable (#18138) * reuse algorithm.fill while building SkipTable * Update lib/pure/strutils.nim Co-authored-by: Timothee Cour Co-authored-by: Timothee Cour --- lib/pure/strutils.nim | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 3fb67ead1..8e0a6158b 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -72,7 +72,7 @@ runnableExamples: import parseutils from math import pow, floor, log10 -from algorithm import reverse +from algorithm import fill, reverse import std/enumutils from unicode import toLower, toUpper @@ -1779,17 +1779,7 @@ func initSkipTable*(a: var SkipTable, sub: string) {.rtl, extern: "nsuInitSkipTable".} = ## Preprocess table `a` for `sub`. let m = len(sub) - var i = 0 - while i <= 0xff-7: - a[chr(i + 0)] = m - a[chr(i + 1)] = m - a[chr(i + 2)] = m - a[chr(i + 3)] = m - a[chr(i + 4)] = m - a[chr(i + 5)] = m - a[chr(i + 6)] = m - a[chr(i + 7)] = m - i += 8 + fill(a, m) for i in 0 ..< m - 1: a[sub[i]] = m - 1 - i From 3e57c2f7800dbedd0df735a0236f09410f6db11a Mon Sep 17 00:00:00 2001 From: Artem Klevtsov Date: Thu, 3 Jun 2021 19:41:57 +0700 Subject: [PATCH 2659/4254] Improve db_postgres iterators (#18144) * Fix pqSetSingleRowMode case. Add links to the docs * Add missing PGContextVisibility enum * Remove unused PGContextVisibility enum * Improve db_postgres iterators * Fix instantRows with DbColumns. Cosmetics. * Reduce copy&paste in db_postgres * Move pqclear inside loop --- lib/impure/db_postgres.nim | 179 ++++++++++++++++++++++++------------- 1 file changed, 117 insertions(+), 62 deletions(-) diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 4edeac2fc..36e035d3d 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -96,7 +96,6 @@ type ## converted to nil. InstantRow* = object ## a handle that can be res: PPGresult ## used to get a row's - line: int ## column text on demand SqlPrepared* = distinct string ## a identifier for the prepared queries proc dbError*(db: DbConn) {.noreturn.} = @@ -184,6 +183,22 @@ proc setupQuery(db: DbConn, stmtName: SqlPrepared, deallocCStringArray(arr) if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db) +proc setupSingeRowQuery(db: DbConn, query: SqlQuery, + args: varargs[string]) = + if pqsendquery(db, dbFormat(query, args)) != 1: + dbError(db) + if pqSetSingleRowMode(db) != 1: + dbError(db) + +proc setupSingeRowQuery(db: DbConn, stmtName: SqlPrepared, + args: varargs[string]) = + var arr = allocCStringArray(args) + if pqsendqueryprepared(db, stmtName.string, int32(args.len), arr, nil, nil, 0) != 1: + dbError(db) + if pqSetSingleRowMode(db) != 1: + dbError(db) + deallocCStringArray(arr) + proc prepare*(db: DbConn; stmtName: string, query: SqlQuery; nParams: int): SqlPrepared = ## Creates a new `SqlPrepared` statement. Parameter substitution is done @@ -203,49 +218,70 @@ proc setRow(res: PPGresult, r: var Row, line, cols: int32) = else: add(r[col], x) +template fetchRows(db: DbConn): untyped = + var res: PPGresult = nil + while true: + res = pqgetresult(db) + if res == nil: + break + let status = pqresultStatus(res) + if status == PGRES_TUPLES_OK: + discard + elif status != PGRES_SINGLE_TUPLE: + dbError(db) + else: + let L = pqNfields(res) + var result = newRow(L) + setRow(res, result, 0, L) + yield result + pqclear(res) + iterator fastRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = ## executes the query and iterates over the result dataset. This is very ## fast, but potentially dangerous: If the for-loop-body executes another ## query, the results can be undefined. For Postgres it is safe though. - var res = setupQuery(db, query, args) - var L = pqnfields(res) - var result = newRow(L) - for i in 0'i32..pqntuples(res)-1: - setRow(res, result, i, L) - yield result - pqclear(res) + setupSingeRowQuery(db, query, args) + fetchRows(db) iterator fastRows*(db: DbConn, stmtName: SqlPrepared, args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - ## executes the prepared query and iterates over the result dataset. - var res = setupQuery(db, stmtName, args) - var L = pqNfields(res) - var result = newRow(L) - for i in 0'i32..pqNtuples(res)-1: - setRow(res, result, i, L) - yield result - pqClear(res) + ## executes the query and iterates over the result dataset. This is very + ## fast, but potentially dangerous: If the for-loop-body executes another + ## query, the results can be undefined. For Postgres it is safe though. + setupSingeRowQuery(db, stmtName, args) + fetchRows(db) + +template fetchinstantRows(db: DbConn): untyped = + var res: PPGresult = nil + while true: + res = pqgetresult(db) + if res == nil: + break + let status = pqresultStatus(res) + if status == PGRES_TUPLES_OK: + discard + elif status != PGRES_SINGLE_TUPLE: + dbError(db) + else: + yield InstantRow(res: res) + pqclear(res) iterator instantRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): InstantRow {.tags: [ReadDbEffect].} = ## same as fastRows but returns a handle that can be used to get column text ## on demand using []. Returned handle is valid only within iterator body. - var res = setupQuery(db, query, args) - for i in 0'i32..pqNtuples(res)-1: - yield InstantRow(res: res, line: i) - pqClear(res) + setupSingeRowQuery(db, query, args) + fetchinstantRows(db) iterator instantRows*(db: DbConn, stmtName: SqlPrepared, args: varargs[string, `$`]): InstantRow {.tags: [ReadDbEffect].} = ## same as fastRows but returns a handle that can be used to get column text ## on demand using []. Returned handle is valid only within iterator body. - var res = setupQuery(db, stmtName, args) - for i in 0'i32..pqNtuples(res)-1: - yield InstantRow(res: res, line: i) - pqClear(res) + setupSingeRowQuery(db, stmtName, args) + fetchinstantRows(db) proc getColumnType(res: PPGresult, col: int) : DbType = ## returns DbType for given column in the row @@ -382,7 +418,7 @@ proc getColumnType(res: PPGresult, col: int) : DbType = of 705: return DbType(kind: DbTypeKind.dbUnknown, name: "unknown") else: return DbType(kind: DbTypeKind.dbUnknown, name: $oid) ## Query the system table pg_type to determine exactly which type is referenced. -proc setColumnInfo(columns: var DbColumns; res: PPGresult; L: int32) = +proc setColumnInfo(columns: var DbColumns; res: PPGresult, L: int32) = setLen(columns, L) for i in 0'i32.. 0: setRow(res, result, 0, L) pqclear(res) +proc getRow*(db: DbConn, query: SqlQuery, + args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = + ## retrieves a single row. If the query doesn't return any rows, this proc + ## will return a Row with empty strings for each column. + let res = setupQuery(db, query, args) + getRow(res) + proc getRow*(db: DbConn, stmtName: SqlPrepared, args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = - var res = setupQuery(db, stmtName, args) - var L = pqNfields(res) - result = newRow(L) - if pqntuples(res) > 0: - setRow(res, result, 0, L) - pqClear(res) + let res = setupQuery(db, stmtName, args) + getRow(res) + +proc getAllRows(res: PPGresult): seq[Row] = + let N = pqntuples(res) + let L = pqnfields(res) + result = newSeqOfCap[Row](N) + var row = newRow(L) + for i in 0'i32..N-1: + setRow(res, row, i, L) + result.add(row) + pqclear(res) proc getAllRows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): seq[Row] {. tags: [ReadDbEffect].} = ## executes the query and returns the whole result dataset. - result = @[] - for r in fastRows(db, query, args): - result.add(r) + let res = setupQuery(db, query, args) + getAllRows(res) proc getAllRows*(db: DbConn, stmtName: SqlPrepared, args: varargs[string, `$`]): seq[Row] {.tags: [ReadDbEffect].} = ## executes the prepared query and returns the whole result dataset. - result = @[] - for r in fastRows(db, stmtName, args): - result.add(r) + let res = setupQuery(db, stmtName, args) + getAllRows(res) iterator rows*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = @@ -459,18 +515,21 @@ iterator rows*(db: DbConn, stmtName: SqlPrepared, ## same as `fastRows`, but slower and safe. for r in items(getAllRows(db, stmtName, args)): yield r +proc getValue(res: PPGresult): string = + if pqntuples(res) > 0: + var x = pqgetvalue(res, 0, 0) + result = if isNil(x): "" else: $x + else: + result = "" + proc getValue*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): string {. tags: [ReadDbEffect].} = ## executes the query and returns the first column of the first row of the ## result dataset. Returns "" if the dataset contains no rows or the database ## value is NULL. - var res = setupQuery(db, query, args) - if pqntuples(res) > 0: - var x = pqgetvalue(res, 0, 0) - result = if isNil(x): "" else: $x - else: - result = "" + let res = setupQuery(db, query, args) + getValue(res) proc getValue*(db: DbConn, stmtName: SqlPrepared, args: varargs[string, `$`]): string {. @@ -478,12 +537,8 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared, ## executes the query and returns the first column of the first row of the ## result dataset. Returns "" if the dataset contains no rows or the database ## value is NULL. - var res = setupQuery(db, stmtName, args) - if pqntuples(res) > 0: - var x = pqgetvalue(res, 0, 0) - result = if isNil(x): "" else: $x - else: - result = "" + let res = setupQuery(db, stmtName, args) + getValue(res) proc tryInsertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {. From 7ef364a402d3d827f10c893280f8dc7b9ef056f5 Mon Sep 17 00:00:00 2001 From: narimiran Date: Thu, 3 Jun 2021 15:20:42 +0200 Subject: [PATCH 2660/4254] add missing import to asynchttpserver's example --- lib/pure/asynchttpserver.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index fd0cad5ca..8cea7f162 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -18,7 +18,7 @@ runnableExamples("-r:off"): # This example will create an HTTP server on an automatically chosen port. # It will respond to all requests with a `200 OK` response code and "Hello World" # as the response body. - import std/asyncdispatch + import std/asyncdispatch, asynchttpserver proc main {.async.} = var server = newAsyncHttpServer() proc cb(req: Request) {.async.} = From 0aa8b793a5f5ef58afe5e8aa96b7646a8afde765 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 3 Jun 2021 16:27:34 +0200 Subject: [PATCH 2661/4254] clarify what a 'monotonic' timestamp is (#18163) --- lib/std/monotimes.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index 8f6aa5b66..3bb4fa141 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -10,7 +10,7 @@ ##[ The `std/monotimes` module implements monotonic timestamps. A monotonic timestamp represents the time that has passed since some system defined -point in time. The monotonic timestamps are guaranteed to always increase, +point in time. The monotonic timestamps are guaranteed not to decrease, meaning that that the following is guaranteed to work: ]## @@ -18,9 +18,8 @@ runnableExamples: import std/os let a = getMonoTime() - sleep(10) let b = getMonoTime() - assert a < b + assert a <= b ##[ This is not guaranteed for the `times.Time` type! This means that the From d31cbfd167c0bf2fcf2b1e6d401a20a16acaaebb Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 3 Jun 2021 22:44:11 +0800 Subject: [PATCH 2662/4254] Revert "add missing import to asynchttpserver's example" (#18164) This reverts commit 7ef364a402d3d827f10c893280f8dc7b9ef056f5. --- lib/pure/asynchttpserver.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 8cea7f162..fd0cad5ca 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -18,7 +18,7 @@ runnableExamples("-r:off"): # This example will create an HTTP server on an automatically chosen port. # It will respond to all requests with a `200 OK` response code and "Hello World" # as the response body. - import std/asyncdispatch, asynchttpserver + import std/asyncdispatch proc main {.async.} = var server = newAsyncHttpServer() proc cb(req: Request) {.async.} = From 06232b7f2e230a46beea982f172087e9da51814a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 3 Jun 2021 17:12:45 +0200 Subject: [PATCH 2663/4254] fixes #18058 (#18162) --- compiler/commands.nim | 2 ++ compiler/msgs.nim | 12 ++++-------- compiler/options.nim | 1 + doc/advopt.txt | 2 ++ tests/misc/trunner.nim | 4 ++-- tests/osproc/treadlines.nim | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 605e2930c..994b224f1 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -919,6 +919,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; excl(conf.notes, hintProcessing) excl(conf.mainPackageNotes, hintProcessing) else: localError(conf, info, "expected: dots|filenames|off, got: $1" % arg) + of "unitsep": + conf.unitSep = if switchOn(arg): "\31" else: "" of "listfullpaths": # xxx in future work, use `warningDeprecated` conf.filenameOption = if switchOn(arg): foAbs else: foCanonical diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6a8c45db5..053b5c928 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -289,10 +289,6 @@ proc `??`* (conf: ConfigRef; info: TLineInfo, filename: string): bool = # only for debugging purposes result = filename in toFilename(conf, info) -const - UnitSep = "\31" - # this needs care to avoid issues similar to https://github.com/nim-lang/Nim/issues/17853 - type MsgFlag* = enum ## flags altering msgWriteln behavior msgStdout, ## force writing to stdout, even stderr is default @@ -309,7 +305,7 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## This is used for 'nim dump' etc. where we don't have nimsuggest ## support. #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - let sep = if msgNoUnitSep notin flags: UnitSep else: "" + let sep = if msgNoUnitSep notin flags: conf.unitSep else: "" if not isNil(conf.writelnHook) and msgSkipHook notin flags: conf.writelnHook(s & sep) elif optStdout in conf.globalOptions or msgStdout in flags: @@ -409,7 +405,7 @@ proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} = styledMsgWriteln(fgRed, """ No stack traceback available To create a stacktrace, rerun compilation with './koch temp $1 ', see $2 for details""" % - [conf.command, "intern.html#debugging-the-compiler".createDocLink], UnitSep) + [conf.command, "intern.html#debugging-the-compiler".createDocLink], conf.unitSep) quit 1 proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = @@ -550,13 +546,13 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, msgWrite(conf, ".") else: styledMsgWriteln(styleBright, loc, resetStyle, color, title, resetStyle, s, KindColor, kindmsg, - resetStyle, conf.getSurroundingSrc(info), UnitSep) + resetStyle, conf.getSurroundingSrc(info), conf.unitSep) if hintMsgOrigin in conf.mainPackageNotes: # xxx needs a bit of refactoring to honor `conf.filenameOption` styledMsgWriteln(styleBright, toFileLineCol(info2), resetStyle, " compiler msg initiated here", KindColor, KindFormat % $hintMsgOrigin, - resetStyle, UnitSep) + resetStyle, conf.unitSep) handleError(conf, msg, eh, s) template rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = diff --git a/compiler/options.nim b/compiler/options.nim index 9cbb747c9..e6c667d92 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -283,6 +283,7 @@ type arcToExpand*: StringTableRef m*: MsgConfig filenameOption*: FilenameOption # how to render paths in compiler messages + unitSep*: string evalTemplateCounter*: int evalMacroCounter*: int exitcode*: int8 diff --git a/doc/advopt.txt b/doc/advopt.txt index ea3370880..e627d4768 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -41,6 +41,8 @@ Advanced options: defaults to `abs` (absolute) --processing:dots|filenames|off show files as they're being processed by nim compiler + --unitsep:on|off use the ASCII unit separator (31) between error + messages, useful for IDE-like tooling --declaredLocs:on|off show declaration locations in messages --spellSuggest|:num show at most `num >= 0` spelling suggestions on typos. if `num` is not specified (or `auto`), return diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 3297b3a24..b6b302836 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -249,7 +249,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines var expected = "" for a in files: let b = dir / a - expected.add &"Hint: used config file '{b}' [Conf]\31\n" + expected.add &"Hint: used config file '{b}' [Conf]\n" doAssert outp.endsWith expected, outp & "\n" & expected block: # mfoo2.customext @@ -257,7 +257,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines let cmd = fmt"{nim} e --hint:conf {filename}" let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) doAssert exitCode == 0 - var expected = &"Hint: used config file '{filename}' [Conf]\31\n" + var expected = &"Hint: used config file '{filename}' [Conf]\n" doAssert outp.endsWith "123" & "\n" & expected diff --git a/tests/osproc/treadlines.nim b/tests/osproc/treadlines.nim index 200a7c299..bb6a7f129 100644 --- a/tests/osproc/treadlines.nim +++ b/tests/osproc/treadlines.nim @@ -1,7 +1,7 @@ discard """ output: ''' -Error: cannot open 'a.nim'\31 -Error: cannot open 'b.nim'\31 +Error: cannot open 'a.nim' +Error: cannot open 'b.nim' ''' targets: "c" """ From 28f2abe1a20a7f7f758b42c233deb7daa78406b1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 3 Jun 2021 20:55:41 +0200 Subject: [PATCH 2664/4254] fixes #18112 (#18165) --- compiler/docgen.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 18c568ba0..dc2a63f48 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -20,7 +20,7 @@ import from uri import encodeUrl from std/private/globs import nativeToUnixPath - +from nodejs import findNodeJs const exportSection = skField @@ -430,7 +430,9 @@ proc runAllExamples(d: PDoc) = "rdoccmd", group.rdoccmd, "docCmd", group.docCmd, ] - if os.execShellCmd(cmd) != 0: + if d.conf.backend == backendJs and findNodeJs() == "": + discard "ignore JS runnableExample" + elif os.execShellCmd(cmd) != 0: d.conf.quitOrRaise "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, group[].prettyString, cmd] else: # keep generated source file `outp` to allow inspection. From d91d78f8aed2b1b59effa3b98765aaf675d7e4c3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 3 Jun 2021 13:25:36 -0700 Subject: [PATCH 2665/4254] changelog for --unitsep (#18167) --- changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index a23aedbdf..06251abfc 100644 --- a/changelog.md +++ b/changelog.md @@ -61,9 +61,6 @@ - Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. -- Nim compiler now adds ASCII unit separator `\31` before a newline for every generated - message (potentially multiline), so tooling can tell when messages start and end. - - `random.initRand(seed)` now produces non-skewed values for the 1st call to `rand()` after initialization with a small (< 30000) seed. Use `-d:nimLegacyRandomInitRand` to restore previous behavior for a transition time, see PR #17467. @@ -395,6 +392,9 @@ - Added `--processing:dots|filenames|off` which customizes `hintProcessing` +- Added `--unitsep:on|off` to control whether to add ASCII unit separator `\31` before a newline + for every generated message (potentially multiline), so tooling can tell when messages start and end. + - Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. From 654a20166eabb614cbf0379c67115981f0532079 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 3 Jun 2021 13:29:45 -0700 Subject: [PATCH 2666/4254] simplify extccomp.nim json logic via jsonutils; fix #18084 (#18100) * simplify extccomp.nim json logic via jsonutils * fix #18084 * simplify further * workaround for bootstrap that can be removed after updating csources_v1 >= 1.2 --- compiler/extccomp.nim | 256 +++++++++++++----------------------------- compiler/nimconf.nim | 11 +- compiler/options.nim | 4 +- lib/std/jsonutils.nim | 18 ++- 4 files changed, 99 insertions(+), 190 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 1cea9edeb..ea2b09866 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -14,7 +14,7 @@ import ropes, platform, condsyms, options, msgs, lineinfos, pathutils -import os, strutils, osproc, std/sha1, streams, sequtils, times, strtabs, json +import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar] type TInfoCCProp* = enum # properties of the C compiler: @@ -942,195 +942,91 @@ proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile = # works out of the box with `hashMainCompilationParams`. result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json") +const cacheVersion = "D20210525T193831" # update when `BuildCache` spec changes +type BuildCache = object + cacheVersion: string + outputFile: string + compile: seq[(string, string)] + link: seq[string] + linkcmd: string + extraCmds: seq[string] + configFiles: seq[string] # the hash shouldn't be needed + stdinInput: bool + projectIsCmd: bool + cmdInput: string + currentDir: string + cmdline: string + depfiles: seq[(string, string)] + nimexe: string + proc writeJsonBuildInstructions*(conf: ConfigRef) = - # xxx use std/json instead, will result in simpler, more maintainable code. - template lit(x: string) = f.write x - template str(x: string) = - buf.setLen 0 - escapeJson(x, buf) - f.write buf - - proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) = - var comma = false - for i, it in clist: - if CfileFlag.Cached in it.flags: continue - let compileCmd = getCompileCFileCmd(conf, it) - if comma: lit ",\L" else: comma = true - lit "[" - str it.cname.string - lit ", " - str compileCmd - lit "]" - - proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList; - llist: seq[string]) = - var pastStart = false - template impl(path) = - let path2 = quoteShell(path) - objfiles.add(' ') - objfiles.add(path2) - if pastStart: lit ",\L" - str path2 - pastStart = true - for it in llist: - let objfile = if noAbsolutePaths(conf): it.extractFilename else: it - impl(addFileExt(objfile, CC[conf.cCompiler].objExt)) - for it in clist: - impl(it.obj) - lit "\L" - - proc depfiles(conf: ConfigRef; f: File; buf: var string) = - var i = 0 - for it in conf.m.fileInfos: + var linkFiles = collect(for it in conf.externalToLink: + var it = it + if conf.noAbsolutePaths: it = it.extractFilename + it.addFileExt(CC[conf.cCompiler].objExt)) + for it in conf.toCompile: linkFiles.add it.obj.string + var bcache = BuildCache( + cacheVersion: cacheVersion, + outputFile: conf.absOutFile.string, + compile: collect(for i, it in conf.toCompile: + if CfileFlag.Cached notin it.flags: (it.cname.string, getCompileCFileCmd(conf, it))), + link: linkFiles, + linkcmd: getLinkCmd(conf, conf.absOutFile, linkFiles.quoteShellCommand), + extraCmds: getExtraCmds(conf, conf.absOutFile), + stdinInput: conf.projectIsStdin, + projectIsCmd: conf.projectIsCmd, + cmdInput: conf.cmdInput, + configFiles: conf.configFiles.mapIt(it.string), + currentDir: getCurrentDir()) + if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): + bcache.cmdline = conf.commandLine + bcache.depfiles = collect(for it in conf.m.fileInfos: let path = it.fullPath.string if isAbsolute(path): # TODO: else? - if i > 0: lit "],\L" - lit "[" - str path - lit ", " - str $secureHashFile(path) - inc i - lit "]\L" - - - var buf = newStringOfCap(50) - let jsonFile = conf.jsonBuildInstructionsFile - conf.jsonBuildFile = jsonFile - let output = conf.absOutFile - - var f: File - if open(f, jsonFile.string, fmWrite): - lit "{\L" - lit "\"outputFile\": " - str $output - - lit ",\L\"compile\":[\L" - cfiles(conf, f, buf, conf.toCompile, false) - lit "],\L\"link\":[\L" - var objfiles = "" - # XXX add every file here that is to link - linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink) - - lit "],\L\"linkcmd\": " - str getLinkCmd(conf, output, objfiles) - - lit ",\L\"extraCmds\": " - lit $(%* getExtraCmds(conf, conf.absOutFile)) - - lit ",\L\"stdinInput\": " - lit $(%* conf.projectIsStdin) - lit ",\L\"projectIsCmd\": " - lit $(%* conf.projectIsCmd) - lit ",\L\"cmdInput\": " - lit $(%* conf.cmdInput) - lit ",\L\"currentDir\": " - lit $(%* getCurrentDir()) - - if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): - lit ",\L\"cmdline\": " - str conf.commandLine - lit ",\L\"depfiles\":[\L" - depfiles(conf, f, buf) - lit "],\L\"nimexe\": \L" - str hashNimExe() - lit "\L" - - lit "\L}\L" - close(f) + (path, $secureHashFile(path))) + bcache.nimexe = hashNimExe() + conf.jsonBuildFile = conf.jsonBuildInstructionsFile + conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty) proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool = - if not fileExists(jsonFile): return true - if not fileExists(conf.absOutFile): return true - result = false - try: - let data = json.parseFile(jsonFile.string) - for key in "depfiles cmdline stdinInput currentDir".split: - if not data.hasKey(key): return true - if getCurrentDir() != data["currentDir"].getStr: - # fixes bug #16271 - # Note that simply comparing `expandFilename(projectFile)` would - # not be sufficient in case other flags depend implicitly on `getCurrentDir`, - # and would require much more care. Simply re-compiling is safer for now. - # A better strategy for future work would be to cache (with an LRU cache) - # the N most recent unique build instructions, as done with `rdmd`, - # which is both robust and avoids recompilation when switching back and forth - # between projects, see https://github.com/timotheecour/Nim/issues/199 - return true - let oldCmdLine = data["cmdline"].getStr - if conf.commandLine != oldCmdLine: - return true - if hashNimExe() != data["nimexe"].getStr: - return true - let stdinInput = data["stdinInput"].getBool - let projectIsCmd = data["projectIsCmd"].getBool - if conf.projectIsStdin or stdinInput: - # could optimize by returning false if stdin input was the same, - # but I'm not sure how to get full stding input - return true - - if conf.projectIsCmd or projectIsCmd: - if not (conf.projectIsCmd and projectIsCmd): return true - if not data.hasKey("cmdInput"): return true - let cmdInput = data["cmdInput"].getStr - if cmdInput != conf.cmdInput: return true - - let depfilesPairs = data["depfiles"] - doAssert depfilesPairs.kind == JArray - for p in depfilesPairs: - doAssert p.kind == JArray - # >= 2 for forwards compatibility with potential later .json files: - doAssert p.len >= 2 - let depFilename = p[0].getStr - let oldHashValue = p[1].getStr - let newHashValue = $secureHashFile(depFilename) - if oldHashValue != newHashValue: - return true + if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true + var bcache: BuildCache + try: bcache.fromJson(jsonFile.string.parseFile) except IOError, OSError, ValueError: - echo "Warning: JSON processing failed: ", getCurrentExceptionMsg() - result = true + stderr.write "Warning: JSON processing failed for $#: $#\n" % [jsonFile.string, getCurrentExceptionMsg()] + return true + if bcache.currentDir != getCurrentDir() or # fixes bug #16271 + bcache.configFiles != conf.configFiles.mapIt(it.string) or + bcache.cacheVersion != cacheVersion or bcache.outputFile != conf.absOutFile.string or + bcache.cmdline != conf.commandLine or bcache.nimexe != hashNimExe() or + bcache.projectIsCmd != conf.projectIsCmd or conf.cmdInput != bcache.cmdInput: return true + if bcache.stdinInput or conf.projectIsStdin: return true + # xxx optimize by returning false if stdin input was the same + for (file, hash) in bcache.depfiles: + if $secureHashFile(file) != hash: return true proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = - try: - let data = json.parseFile(jsonFile.string) - let output = data["outputFile"].getStr - createDir output.parentDir - let outputCurrent = $conf.absOutFile - if output != outputCurrent: - # previously, any specified output file would be silently ignored; - # simply copying won't work in some cases, for example with `extraCmds`, - # so we just make it an error, user should use same command for jsonscript - # as was used with --compileOnly. - globalError(conf, gCmdLineInfo, "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " % [outputCurrent, output, jsonFile.string]) - - let toCompile = data["compile"] - doAssert toCompile.kind == JArray - var cmds: TStringSeq - var prettyCmds: TStringSeq - let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) - for c in toCompile: - doAssert c.kind == JArray - doAssert c.len >= 2 - - cmds.add(c[1].getStr) - prettyCmds.add displayProgressCC(conf, c[0].getStr, c[1].getStr) - - execCmdsInParallel(conf, cmds, prettyCb) - - let linkCmd = data["linkcmd"] - doAssert linkCmd.kind == JString - execLinkCmd(conf, linkCmd.getStr) - if data.hasKey("extraCmds"): - let extraCmds = data["extraCmds"] - doAssert extraCmds.kind == JArray - for cmd in extraCmds: - doAssert cmd.kind == JString, $cmd.kind - let cmd2 = cmd.getStr - execExternalProgram(conf, cmd2, hintExecuting) - + var bcache: BuildCache + try: bcache.fromJson(jsonFile.string.parseFile) except: let e = getCurrentException() - conf.quitOrRaise "\ncaught exception:\n" & e.msg & "\nstacktrace:\n" & e.getStackTrace() & - "error evaluating JSON file: " & jsonFile.string + conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" % + [e.msg, e.getStackTrace(), jsonFile.string] + let output = bcache.outputFile + createDir output.parentDir + let outputCurrent = $conf.absOutFile + if output != outputCurrent or bcache.cacheVersion != cacheVersion: + globalError(conf, gCmdLineInfo, + "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " % + [outputCurrent, output, jsonFile.string]) + var cmds, prettyCmds: TStringSeq + let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) + for (name, cmd) in bcache.compile: + cmds.add cmd + prettyCmds.add displayProgressCC(conf, name, cmd) + execCmdsInParallel(conf, cmds, prettyCb) + execLinkCmd(conf, bcache.linkcmd) + for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting) proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = for it in list: diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index b63e5a0ad..94c93a283 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -240,13 +240,10 @@ proc getSystemConfigPath*(conf: ConfigRef; filename: RelativeFile): AbsoluteFile proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: IdGenerator) = setDefaultLibpath(conf) - - var configFiles = newSeq[AbsoluteFile]() - template readConfigFile(path) = let configPath = path if readConfigFile(configPath, cache, conf): - configFiles.add(configPath) + conf.configFiles.add(configPath) template runNimScriptIfExists(path: AbsoluteFile, isMain = false) = let p = path # eval once @@ -256,7 +253,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput) if s == nil and fileExists(p): s = llStreamOpen(p, fmRead) if s != nil: - configFiles.add(p) + conf.configFiles.add(p) runNimScript(cache, p, idgen, freshDefines = false, conf, s) if optSkipSystemConfigFile notin conf.globalOptions: @@ -295,12 +292,12 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: let scriptFile = conf.projectFull.changeFileExt("nims") let scriptIsProj = scriptFile == conf.projectFull template showHintConf = - for filename in configFiles: + for filename in conf.configFiles: # delayed to here so that `hintConf` is honored rawMessage(conf, hintConf, filename.string) if conf.cmd == cmdNimscript: showHintConf() - configFiles.setLen 0 + conf.configFiles.setLen 0 if conf.cmd != cmdIdeTools: if conf.cmd == cmdNimscript: runNimScriptIfExists(conf.projectFull, isMain = true) diff --git a/compiler/options.nim b/compiler/options.nim index e6c667d92..afe8b0fc7 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -308,7 +308,7 @@ type ## should be run ideCmd*: IdeCmd oldNewlines*: bool - cCompiler*: TSystemCC + cCompiler*: TSystemCC # the used compiler modifiedyNotes*: TNoteKinds # notes that have been set/unset from either cmdline/configs cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline foreignPackageNotes*: TNoteKinds @@ -353,7 +353,7 @@ type docRoot*: string ## see nim --fullhelp for --docRoot docCmd*: string ## see nim --fullhelp for --docCmd - # the used compiler + configFiles*: seq[AbsoluteFile] # config files (cfg,nims) cIncludes*: seq[AbsoluteDir] # directories to search for included files cLibs*: seq[AbsoluteDir] # directories to search for lib files cLinkedLibs*: seq[string] # libraries to link diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index e33ae4401..60d78fea5 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -34,6 +34,23 @@ import macros from enumutils import symbolName from typetraits import OrdinalEnum +when not defined(nimFixedForwardGeneric): + # xxx remove pending csources_v1 update >= 1.2.0 + proc to[T](node: JsonNode, t: typedesc[T]): T = + when T is string: node.getStr + elif T is bool: node.getBool + else: static: doAssert false, $T # support as needed (only needed during bootstrap) + proc isNamedTuple(T: typedesc): bool = # old implementation + when T isnot tuple: result = false + else: + var t: T + for name, _ in t.fieldPairs: + when name == "Field0": return compiles(t.Field0) + else: return true + return false +else: + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} + type Joptions* = object # xxx rename FromJsonOptions ## Options controlling the behavior of `fromJson`. @@ -61,7 +78,6 @@ proc initToJsonOptions*(): ToJsonOptions = ## initializes `ToJsonOptions` with sane options. ToJsonOptions(enumMode: joptEnumOrd, jsonNodeMode: joptJsonNodeAsRef) -proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} template distinctBase[T](a: T): untyped = distinctBase(typeof(a))(a) From 7e21218a07f919d56cd0974c657aefb11574da26 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Fri, 4 Jun 2021 17:16:51 +0300 Subject: [PATCH 2667/4254] follow-up #18013 - inline syntax highlighting (#18166) --- doc/destructors.rst | 2 +- doc/docgen.rst | 2 +- doc/drnim.rst | 4 +- doc/estp.rst | 2 +- doc/hcr.rst | 31 +++++++++------ doc/intern.rst | 2 +- doc/koch.rst | 27 +++++++------ doc/lib.rst | 12 +++--- doc/manual.rst | 48 ++++++++++++------------ doc/manual_experimental.rst | 20 +++++----- doc/manual_experimental_strictnotnil.rst | 26 ++++++++----- doc/nep1.rst | 11 +++--- doc/nimgrep.rst | 31 ++++++++------- doc/niminst.rst | 24 ++++++------ doc/nims.rst | 45 +++++++++++----------- doc/nimsuggest.rst | 37 +++++++++--------- doc/packaging.rst | 2 +- doc/regexprs.txt | 4 +- doc/testament.rst | 2 +- doc/tools.rst | 15 ++++---- 20 files changed, 183 insertions(+), 164 deletions(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index 3cd4cd925..c99606b95 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -5,8 +5,8 @@ Nim Destructors and Move Semantics :Authors: Andreas Rumpf :Version: |nimversion| +.. default-role:: code .. include:: rstcommon.rst -.. default-role:: nim .. contents:: diff --git a/doc/docgen.rst b/doc/docgen.rst index 86352a989..e9ff7f1e3 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -5,8 +5,8 @@ :Author: Erik O'Leary :Version: |nimversion| +.. default-role:: code .. include:: rstcommon.rst -.. default-role:: Nim .. contents:: diff --git a/doc/drnim.rst b/doc/drnim.rst index 08de7cd6d..070cd1787 100644 --- a/doc/drnim.rst +++ b/doc/drnim.rst @@ -5,8 +5,8 @@ :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code .. include:: rstcommon.rst -.. default-role:: Nim .. contents:: @@ -43,7 +43,7 @@ your code. Installation ============ -Run `koch drnim`:option:, the executable will afterwards be +Run `koch drnim`:cmd:, the executable will afterwards be in ``$nim/bin/drnim``. diff --git a/doc/estp.rst b/doc/estp.rst index 43128bef7..550194d2d 100644 --- a/doc/estp.rst +++ b/doc/estp.rst @@ -2,8 +2,8 @@ Embedded Stack Trace Profiler (ESTP) User Guide =================================================== +.. default-role:: code .. include:: rstcommon.rst -.. default-role:: Nim :Author: Andreas Rumpf :Version: |nimversion| diff --git a/doc/hcr.rst b/doc/hcr.rst index 574c4f39d..dd25e39b3 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -1,9 +1,10 @@ -.. default-role:: code - =================================== Hot code reloading =================================== +.. default-role:: code +.. include:: rstcommon.rst + The `hotCodeReloading`:idx: option enables special compilation mode where changes in the code can be applied automatically to a running program. The code reloading happens at the granularity of an individual module. @@ -22,7 +23,7 @@ during development resides. In this example, we use SDL2 to create a window and we reload the logic code when `F9` is pressed. The important lines are marked with `#***`. -To install SDL2 you can use `nimble install sdl2`. +To install SDL2 you can use `nimble install sdl2`:cmd:. .. code-block:: nim @@ -98,34 +99,40 @@ To install SDL2 you can use `nimble install sdl2`. main() -Compile this example via:: +Compile this example via: +```cmd nim c --hotcodereloading:on mymain.nim +``` Now start the program and KEEP it running! -:: - +.. code:: cmd # Unix: mymain & # or Windows (click on the .exe) mymain.exe # edit -For example, change the line:: +For example, change the line: +```nim discard renderer.setDrawColor(255, 128, 128, 0) +``` -into:: +into: +```nim discard renderer.setDrawColor(255, 255, 128, 0) +``` (This will change the color of the rectangle.) Then recompile the project, but do not restart or quit the mymain.exe program! -:: +```cmd nim c --hotcodereloading:on mymain.nim +``` Now give the `mymain` SDL window the focus, press F9, and watch the updated version of the program. @@ -188,15 +195,15 @@ Native code targets =================== Native projects using the hot code reloading option will be implicitly -compiled with the `-d:useNimRtl` option and they will depend on both +compiled with the `-d:useNimRtl`:option: option and they will depend on both the `nimrtl` library and the `nimhcr` library which implements the hot code reloading run-time. Both libraries can be found in the `lib` folder of Nim and can be compiled into dynamic libraries to satisfy runtime demands of the example code above. An example of compiling -`nimhcr.nim` and `nimrtl.nim` when the source dir of Nim is installed +``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed with choosenim follows. -:: +.. code:: console # Unix/MacOS # Make sure you are in the directory containing your .nim files diff --git a/doc/intern.rst b/doc/intern.rst index 2f83e0d06..ab74c4a3a 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -6,8 +6,8 @@ :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code .. include:: rstcommon.rst -.. default-role:: Nim .. contents:: "Abstraction is layering ignorance on top of reality." -- Richard Gabriel diff --git a/doc/koch.rst b/doc/koch.rst index 1eb02d785..b8d85dff4 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -1,11 +1,11 @@ -.. default-role:: code - =============================== Nim maintenance script =============================== :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: .. raw:: html @@ -19,7 +19,7 @@ Introduction The `koch`:idx: program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. -The word *koch* means *cook* in German. `koch` is used mainly to build the +The word *koch* means *cook* in German. `koch`:cmd: is used mainly to build the Nim compiler, but it can also be used for other tasks. This document describes the supported commands and their options. @@ -33,12 +33,11 @@ boot command The `boot`:idx: command bootstraps the compiler, and it accepts different options: --d:release - By default a debug version is created, passing this option will +-d:release By default a debug version is created, passing this option will force a release build, which is much faster and should be preferred unless you are debugging the compiler. --d:nimUseLinenoise - Use the linenoise library for interactive mode (not needed on Windows). +-d:nimUseLinenoise Use the linenoise library for interactive mode + (not needed on Windows). After compilation is finished you will hopefully end up with the nim compiler in the `bin` directory. You can add Nim's `bin` directory to @@ -56,16 +55,16 @@ temp command ------------ The temp command builds the Nim compiler but with a different final name -(`nim_temp`), so it doesn't overwrite your normal compiler. You can use +(`nim_temp`:cmd:), so it doesn't overwrite your normal compiler. You can use this command to test different options, the same you would issue for the `boot command <#commands-boot-command>`_. test command ------------ -The `test`:idx: command can also be invoked with the alias `tests`. This -command will compile and run `testament/tester.nim`, which is the main -driver of Nim's test suite. You can pass options to the `test` command, +The `test`:idx: command can also be invoked with the alias `tests`:option:. This +command will compile and run ``testament/tester.nim``, which is the main +driver of Nim's test suite. You can pass options to the `test`:option: command, they will be forwarded to the tester. See its source code for available options. @@ -74,13 +73,13 @@ web command The `web`:idx: command converts the documentation in the `doc` directory from rst to HTML. It also repeats the same operation but places the result in -the `web/upload` which can be used to update the website at +the ``web/upload`` which can be used to update the website at https://nim-lang.org. By default, the documentation will be built in parallel using the number of available CPU cores. If any documentation build sub-commands fail, they will be rerun in serial fashion so that meaningful error output can be gathered for -inspection. The `--parallelBuild:n` switch or configuration option can be +inspection. The `--parallelBuild:n`:option: switch or configuration option can be used to force a specific number of parallel jobs or run everything serially from the start (`n == 1`). @@ -89,4 +88,4 @@ pdf command The `pdf`:idx: command builds PDF versions of Nim documentation: Manual, Tutorial and a few other documents. To run it one needs to -`install Latex/pdflatex `_ first. +`install Latex/xelatex `_ first. diff --git a/doc/lib.rst b/doc/lib.rst index f09fe16b2..988fbf6f0 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ==================== Nim Standard Library ==================== @@ -7,11 +5,13 @@ Nim Standard Library :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: Nim's library is divided into *pure libraries*, *impure libraries*, and *wrappers*. -Pure libraries do not depend on any external `*.dll` or `lib*.so` binary +Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary while impure libraries do. A wrapper is an impure library that is a very low-level interface to a C library. @@ -39,11 +39,11 @@ Automatic imports * `threads `_ Basic Nim thread support. **Note:** This is part of the system module. Do not - import it explicitly. Enabled with `--threads:on`. + import it explicitly. Enabled with `--threads:on`:option:. * `channels `_ Nim message passing support for threads. **Note:** This is part of the - system module. Do not import it explicitly. Enabled with `--threads:on`. + system module. Do not import it explicitly. Enabled with `--threads:on`:option:. Core @@ -366,7 +366,7 @@ Parsers * `parsecfg `_ The `parsecfg` module implements a high-performance configuration file - parser. The configuration file's syntax is similar to the Windows `.ini` + parser. The configuration file's syntax is similar to the Windows ``.ini`` format, but much more powerful, as it is not a line based parser. String literals, raw string literals, and triple quote string literals are supported as in the Nim programming language. diff --git a/doc/manual.rst b/doc/manual.rst index ff34b62ca..867db245b 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -572,7 +572,8 @@ In the following examples, `-1` is a single token: "abc";-1 -In the following examples, `-1` is parsed as two separate tokens (as `- 1`): +In the following examples, `-1` is parsed as two separate tokens +(as `-`:tok: `1`:tok:): .. code-block:: nim @@ -2509,7 +2510,7 @@ of the argument. range. 3. Generic match: `f` is a generic type and `a` matches, for instance `a` is `int` and `f` is a generic (constrained) parameter - type (like in `[T]` or `[T: int|char]`. + type (like in `[T]` or `[T: int|char]`). 4. Subrange or subtype match: `a` is a `range[T]` and `T` matches `f` exactly. Or: `a` is a subtype of `f`. 5. Integral conversion match: `a` is convertible to `f` and `f` and `a` @@ -3840,7 +3841,7 @@ Type bound operators currently include: (some of which are still implementation defined and not yet documented). For more details on some of those procs, see -`lifetimeminustracking-hooks `_. +`Lifetime-tracking hooks `_. Nonoverloadable builtins ------------------------ @@ -5283,7 +5284,7 @@ instantiations cross multiple different modules: In module B has an `init` proc from module C in its scope that is not taken into account when `genericB` is instantiated which leads to the -instantiation of `genericA`. The solution is to `forward`:idx these +instantiation of `genericA`. The solution is to `forward`:idx: these symbols by a `bind` statement inside `genericB`. @@ -7305,19 +7306,19 @@ Produces: supplied pattern to denote the concrete type parameters of the generic type. See the usage of the apostrophe operator in proc patterns for more details. -.. code-block:: nim + .. code-block:: nim - type - VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object + type + VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object - var x: VectorIterator[cint] + var x: VectorIterator[cint] -Produces: + Produces: -.. code-block:: C + .. code-block:: C - std::vector::iterator x; + std::vector::iterator x; ImportJs pragma @@ -7444,7 +7445,7 @@ compile-time define pragmas --------------------------- The pragmas listed here can be used to optionally accept values from -the -d/--define option at compile time. +the `-d/--define`:option: option at compile time. The implementation currently provides the following possible options (various others may be added later). @@ -7461,7 +7462,7 @@ pragma description const FooBar {.intdefine.}: int = 5 echo FooBar -:: +.. code:: cmd nim c -d:FooBar=42 foobar.nim In the above example, providing the `-d`:option: flag causes the symbol @@ -7480,7 +7481,8 @@ pragma pragma ------------- The `pragma` pragma can be used to declare user-defined pragmas. This is -useful because Nim's templates and macros do not affect pragmas. User-defined pragmas are in a different module-wide scope than all other symbols. +useful because Nim's templates and macros do not affect pragmas. +User-defined pragmas are in a different module-wide scope than all other symbols. They cannot be imported from a module. Example: @@ -7553,18 +7555,18 @@ More examples with custom pragmas: - Better serialization/deserialization control: -.. code-block:: nim - type MyObj = object - a {.dontSerialize.}: int - b {.defaultDeserialize: 5.}: int - c {.serializationKey: "_c".}: string + .. code-block:: nim + type MyObj = object + a {.dontSerialize.}: int + b {.defaultDeserialize: 5.}: int + c {.serializationKey: "_c".}: string - Adopting type for gui inspector in a game engine: -.. code-block:: nim - type MyComponent = object - position {.editable, animatable.}: Vector3 - alpha {.editRange: [0.0..1.0], animatable.}: float32 + .. code-block:: nim + type MyComponent = object + position {.editable, animatable.}: Vector3 + alpha {.editRange: [0.0..1.0], animatable.}: float32 Macro pragmas diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 51037b509..2c1043ecb 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ========================= Nim Experimental Features ========================= @@ -7,6 +5,8 @@ Nim Experimental Features :Authors: Andreas Rumpf :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: @@ -15,7 +15,7 @@ About this document This document describes features of Nim that are to be considered experimental. Some of these are not covered by the `.experimental` pragma or -`--experimental` switch because they are already behind a special syntax and +`--experimental`:option: switch because they are already behind a special syntax and one may want to use Nim libraries using these features without using them oneself. @@ -1109,7 +1109,7 @@ The `parameter constraint`:idx: expression can use the operators `|` (or), Predicate Meaning =================== ===================================================== `atom` The matching node has no children. -`lit` The matching node is a literal like "abc", 12. +`lit` The matching node is a literal like `"abc"`, `12`. `sym` The matching node must be a symbol (a bound identifier). `ident` The matching node must be an identifier (an unbound @@ -1185,7 +1185,7 @@ constant folding, so the following does not work: The reason is that the compiler already transformed the 1 into "1" for the `echo` statement. However, a term rewriting macro should not change the -semantics anyway. In fact they can be deactivated with the `--patterns:off` +semantics anyway. In fact they can be deactivated with the `--patterns:off`:option: command line option or temporarily with the `patterns` pragma. @@ -1779,7 +1779,7 @@ Noalias annotation ================== Since version 1.4 of the Nim compiler, there is a `.noalias` annotation for variables -and parameters. It is mapped directly to C/C++'s `restrict` keyword and means that +and parameters. It is mapped directly to C/C++'s `restrict`:c: keyword and means that the underlying pointer is pointing to a unique location in memory, no other aliases to this location exist. It is *unchecked* that this alias restriction is followed, if the restriction is violated, the backend optimizer is free to miscompile the code. @@ -1832,8 +1832,8 @@ the `view types section <#view-types-algorithm>`_. View types ========== -**Note**: `--experimental:views` is more effective -with `--experimental:strictFuncs`. +**Note**: `--experimental:views`:option: is more effective +with `--experimental:strictFuncs`:option:. A view type is a type that is or contains one of the following types: @@ -1981,8 +1981,8 @@ The scope of the view does not matter: The analysis requires as much precision about mutations as is reasonably obtainable, so it is more effective with the experimental `strict funcs <#strict-funcs>`_ -feature. In other words `--experimental:views` works better -with `--experimental:strictFuncs`. +feature. In other words `--experimental:views`:option: works better +with `--experimental:strictFuncs`:option:. The analysis is currently control flow insensitive: diff --git a/doc/manual_experimental_strictnotnil.rst b/doc/manual_experimental_strictnotnil.rst index cb3bfeca9..b14e5f9f3 100644 --- a/doc/manual_experimental_strictnotnil.rst +++ b/doc/manual_experimental_strictnotnil.rst @@ -1,8 +1,9 @@ -.. default-role:: code - Strict not nil checking ========================= +.. default-role:: code +.. include:: rstcommon.rst + **Note:** This feature is experimental, you need to enable it with .. code-block:: nim @@ -10,7 +11,7 @@ Strict not nil checking or -.. code-block:: bash +.. code-block:: cmd nim c --experimental:strictNotNil In the second case it would check builtin and imported modules as well. @@ -60,14 +61,16 @@ You can annotate a type where nil isn't a valid value with `not nil`. If a type can include `nil` as a valid value, dereferencing values of the type -is checked by the compiler: if a value which might be nil is derefenced, this produces a warning by default, you can turn this into an error using the compiler options `--warningAsError:strictNotNil` +is checked by the compiler: if a value which might be nil is derefenced, this +produces a warning by default, you can turn this into an error using +the compiler options `--warningAsError:strictNotNil`:option:. If a type is nilable, you should dereference its values only after a `isNil` or equivalent check. local turn on/off --------------------- -You can still turn off nil checking on function/module level by using a `{.strictNotNil: off}.` pragma. +You can still turn off nil checking on function/module level by using a `{.strictNotNil: off.}` pragma. Note: test that/TODO for code/manual. nilability state @@ -75,11 +78,14 @@ nilability state Currently a nilable value can be `Safe`, `MaybeNil` or `Nil` : we use internally `Parent` and `Unreachable` but this is an implementation detail(a parent layer has the actual nilability). -`Safe` means it shouldn't be nil at that point: e.g. after assignment to a non-nil value or `not a.isNil` check -`MaybeNil` means it might be nil, but it might not be nil: e.g. an argument, a call argument or a value after an `if` and `else`. -`Nil` means it should be nil at that point; e.g. after an assignment to `nil` or a `.isNil` check. - -`Unreachable` means it shouldn't be possible to access this in this branch: so we do generate a warning as well. +- `Safe` means it shouldn't be nil at that point: e.g. after assignment to + a non-nil value or `not a.isNil` check +- `MaybeNil` means it might be nil, but it might not be nil: e.g. an argument, + a call argument or a value after an `if` and `else`. +- `Nil` means it should be nil at that point; e.g. after an assignment to + `nil` or a `.isNil` check. +- `Unreachable` means it shouldn't be possible to access this in this branch: + so we do generate a warning as well. We show an error for each dereference (`[]`, `.field`, `[index]` `()` etc) which is of a tracked expression which is in `MaybeNil` or `Nil` state. diff --git a/doc/nep1.rst b/doc/nep1.rst index 8687725bb..fc69bab69 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -1,11 +1,12 @@ -.. default-role:: code - ========================================================== Nim Enhancement Proposal #1 - Standard Library Style Guide ========================================================== + :Author: Clay Sweetser, Dominik Picheta :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: @@ -139,7 +140,7 @@ Naming Conventions - rotate and rotated - When the 'returns transformed copy' version already exists like `strutils.replace` - an in-place version should get an `-In` suffix (`replaceIn` for this example). + an in-place version should get an ``-In`` suffix (`replaceIn` for this example). - Use `subjectVerb`, not `verbSubject`, e.g.: `fileExists`, not `existsFile`. @@ -225,8 +226,8 @@ indentation indent Coding Conventions ------------------ -- The 'return' statement should ideally be used when its control-flow properties - are required. Use a procedure's implicit 'result' variable whenever possible. +- The `return` statement should ideally be used when its control-flow properties + are required. Use a procedure's implicit `result` variable whenever possible. This improves readability. .. code-block:: nim diff --git a/doc/nimgrep.rst b/doc/nimgrep.rst index 52fc4d62a..6088a4c45 100644 --- a/doc/nimgrep.rst +++ b/doc/nimgrep.rst @@ -1,14 +1,11 @@ -.. default-role:: code - ========================= nimgrep User's manual ========================= -.. default-role:: literal - :Author: Andreas Rumpf :Version: 1.6.0 +.. default-role:: option .. contents:: Nimgrep is a command line tool for search and replace tasks. It can search for @@ -23,11 +20,12 @@ Apart from that it is a generic text manipulation tool. Installation ============ -Compile nimgrep with the command:: +Compile nimgrep with the command: +.. code:: cmd nim c -d:release tools/nimgrep.nim -And copy the executable somewhere in your `$PATH`. +And copy the executable somewhere in your ``$PATH``. Command line switches @@ -40,31 +38,32 @@ Examples All examples below use default PCRE Regex patterns: -+ To search recursively in Nim files using style-insensitive identifiers:: ++ To search recursively in Nim files using style-insensitive identifiers: - --recursive --ext:'nim|nims' --ignoreStyle + .. code:: cmd + nimgrep --recursive --ext:'nim|nims' --ignoreStyle # short: -r --ext:'nim|nims' -y .. Note:: we used `'` quotes to avoid special treatment of `|` symbol for shells like Bash + To exclude version control directories (Git, Mercurial=hg, Subversion=svn) - from the search:: + from the search: - --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$' + .. code:: cmd + nimgrep --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$' # short: --ed:'^\.git$' --ed:'^\.hg$' --ed:'^\.svn$' + To search only in paths containing the `tests` sub-directory recursively:: - --recursive --includeDir:'(^|/)tests($|/)' + .. code:: cmd + nimgrep --recursive --includeDir:'(^|/)tests($|/)' # short: -r --id:'(^|/)tests($|/)' - .. Attention:: note the subtle difference between `--excludeDir` and - `--includeDir`: the former is applied to relative directory entries + .. Attention:: note the subtle difference between `--excludeDir`:option: and + `--includeDir`:option:\: the former is applied to relative directory entries and the latter is applied to the whole paths + Nimgrep can search multi-line, e.g. to find files containing `import` - and then `strutils` use:: - - 'import(.|\n)*?strutils' + and then `strutils` use pattern `'import(.|\n)*?strutils'`:option:. diff --git a/doc/niminst.rst b/doc/niminst.rst index 3ccb47cc8..8fff1f0e8 100644 --- a/doc/niminst.rst +++ b/doc/niminst.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ========================= niminst User's manual ========================= @@ -7,6 +5,8 @@ :Author: Andreas Rumpf :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: Introduction @@ -34,7 +34,7 @@ configuration file. Here's an example of how the syntax looks like: The value of a key-value pair can reference user-defined variables via the `$variable` notation: They can be defined in the command line with the -`--var:name=value` switch. This is useful to not hard-coding the +`--var:name=value`:option: switch. This is useful to not hard-coding the program's version number into the configuration file, for instance. It follows a description of each possible section and how it affects the @@ -91,10 +91,10 @@ Documentation section The `documentation` section supports the `files` key. Listed files will be installed into the OS's native documentation directory -(which might be `$appdir/doc`). +(which might be ``$appdir/doc``). There is a `start` key which determines whether the Windows installer -generates a link to e.g. the `index.html` of your documentation. +generates a link to e.g. the ``index.html`` of your documentation. Other section @@ -125,9 +125,9 @@ Other possible options are: ==================== ======================================================= Key description ==================== ======================================================= -`BinPath` paths to add to the Windows `%PATH%` environment +`BinPath` paths to add to the Windows `%PATH%` environment variable. Example: ``BinPath: r"bin;dist\mingw\bin"`` -`InnoSetup` boolean flag whether an Inno Setup installer should be +`InnoSetup` boolean flag whether an Inno Setup installer should be generated for Windows. Example: `InnoSetup: "Yes"` ==================== ======================================================= @@ -137,7 +137,7 @@ UnixBin section The `UnixBin` section currently only supports the `files` key. Listed files will be installed into the OS's native bin directory -(e.g. `/usr/local/bin`). The exact location depends on the +(e.g. ``/usr/local/bin``). The exact location depends on the installation path the user specifies when running the `install.sh` script. @@ -165,9 +165,9 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -`path` Path to Inno Setup. +`path` Path to Inno Setup. Example: ``path = r"c:\inno setup 5\iscc.exe"`` -`flags` Flags to pass to Inno Setup. +`flags` Flags to pass to Inno Setup. Example: `flags = "/Q"` ==================== ======================================================= @@ -180,8 +180,8 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -`path` Path to the C compiler. -`flags` Flags to pass to the C Compiler. +`path` Path to the C compiler. +`flags` Flags to pass to the C Compiler. Example: `flags = "-w"` ==================== ======================================================= diff --git a/doc/nims.rst b/doc/nims.rst index f81637d73..5ae1d7baa 100644 --- a/doc/nims.rst +++ b/doc/nims.rst @@ -1,32 +1,33 @@ -.. default-role:: code - ================================ NimScript ================================ +.. default-role:: code +.. include:: rstcommon.rst + Strictly speaking, `NimScript` is the subset of Nim that can be evaluated by Nim's builtin virtual machine (VM). This VM is used for Nim's compiletime function evaluation features. -The `nim` executable processes the `.nims` configuration files in +The `nim`:cmd: executable processes the ``.nims`` configuration files in the following directories (in this order; later files overwrite previous settings): 1) If environment variable `XDG_CONFIG_HOME` is defined, - `$XDG_CONFIG_HOME/nim/config.nims` or - `~/.config/nim/config.nims` (POSIX) or - `%APPDATA%/nim/config.nims` (Windows). This file can be skipped - with the `--skipUserCfg` command line option. -2) `$parentDir/config.nims` where `$parentDir` stands for any + ``$XDG_CONFIG_HOME/nim/config.nims`` or + ``~/.config/nim/config.nims`` (POSIX) or + ``%APPDATA%/nim/config.nims`` (Windows). This file can be skipped + with the `--skipUserCfg`:option: command line option. +2) ``$parentDir/config.nims`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be - skipped with the `--skipParentCfg` command line option. -3) `$projectDir/config.nims` where `$projectDir` stands for the - project's path. This file can be skipped with the `--skipProjCfg` + skipped with the `--skipParentCfg`:option: command line option. +3) ``$projectDir/config.nims`` where ``$projectDir`` stands for the + project's path. This file can be skipped with the `--skipProjCfg`:option: command line option. 4) A project can also have a project specific configuration file named - `$project.nims` that resides in the same directory as - `$project.nim`. This file can be skipped with the same - `--skipProjCfg` command line option. + ``$project.nims`` that resides in the same directory as + ``$project.nim``. This file can be skipped with the same + `--skipProjCfg`:option: command line option. For available procs and implementation details see `nimscript `_. @@ -111,8 +112,8 @@ See also: NimScript as a configuration file ================================= -A command-line switch `--FOO` is written as `switch("FOO")` in -NimScript. Similarly, command-line `--FOO:VAL` translates to +A command-line switch `--FOO`:option: is written as `switch("FOO")` in +NimScript. Similarly, command-line `--FOO:VAL`:option: translates to `switch("FOO", "VAL")`. Here are few examples of using the `switch` proc: @@ -125,7 +126,7 @@ Here are few examples of using the `switch` proc: # command-line: --forceBuild switch("forceBuild") -NimScripts also support `--` templates for convenience, which look +NimScripts also support `--`:option: templates for convenience, which look like command-line switches written as-is in the NimScript file. So the above example can be rewritten as: @@ -136,7 +137,7 @@ above example can be rewritten as: **Note**: In general, the *define* switches can also be set in NimScripts using `switch` or `--`, as shown in above -examples. Only the `release` define (`-d:release`) cannot be set +examples. Only the `release` define (`-d:release`:option:) cannot be set in NimScripts. @@ -145,7 +146,7 @@ NimScript as a build tool The `task` template that the `system` module defines allows a NimScript file to be used as a build tool. The following example defines a -task `build` that is an alias for the `c` command: +task `build` that is an alias for the `c`:option: command: .. code-block:: nim task build, "builds an example": @@ -159,7 +160,7 @@ Task Description ========= =================================================== `help` List all the available NimScript tasks along with their docstrings. `build` Build the project with the required - backend (`c`, `cpp` or `js`). + backend (`c`:option:, `cpp`:option: or `js`:option:). `tests` Runs the tests belonging to the project. `bench` Runs benchmarks belonging to the project. ========= =================================================== @@ -180,7 +181,7 @@ Standalone NimScript ==================== NimScript can also be used directly as a portable replacement for Bash and -Batch files. Use `nim myscript.nims` to run `myscript.nims`. For example, +Batch files. Use `nim myscript.nims`:cmd: to run ``myscript.nims``. For example, installation of Nimble could be accomplished with this simple script: .. code-block:: nim @@ -199,7 +200,7 @@ installation of Nimble could be accomplished with this simple script: mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe On Unix, you can also use the shebang `#!/usr/bin/env nim`, as long as your filename -ends with `.nims`: +ends with ``.nims``: .. code-block:: nim diff --git a/doc/nimsuggest.rst b/doc/nimsuggest.rst index 509f72e8a..82693da0e 100644 --- a/doc/nimsuggest.rst +++ b/doc/nimsuggest.rst @@ -1,5 +1,3 @@ -.. default-role:: code - ================================ Nim IDE Integration Guide ================================ @@ -7,14 +5,16 @@ :Author: Unknown :Version: |nimversion| +.. default-role:: code +.. include:: rstcommon.rst .. contents:: Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the -`nimsuggest` tool, any IDE -can query a `.nim` source file and obtain useful information like +`nimsuggest`:cmd: tool, any IDE +can query a ``.nim`` source file and obtain useful information like definition of symbols or suggestions for completion. This document will guide you through the available options. If you @@ -27,29 +27,30 @@ already available. Installation ============ -Nimsuggest is part of Nim's core. Build it via:: +Nimsuggest is part of Nim's core. Build it via: +.. code:: cmd koch nimsuggest Nimsuggest invocation ===================== -Run it via `nimsuggest --stdin --debug myproject.nim`. Nimsuggest is a +Run it via `nimsuggest --stdin --debug myproject.nim`:cmd:. Nimsuggest is a server that takes queries that are related to `myproject`. There is some -support so that you can throw random `.nim` files which are not part +support so that you can throw random ``.nim`` files which are not part of `myproject` at Nimsuggest too, but usually the query refer to modules/files that are part of `myproject`. -`--stdin` means that Nimsuggest reads the query from `stdin`. This is great +`--stdin`:option: means that Nimsuggest reads the query from `stdin`. This is great for testing things out and playing with it but for an editor communication via sockets is more reasonable so that is the default. It listens to port 6000 by default. -Nimsuggest is basically a frontend for the nim compiler so `--path` flags and +Nimsuggest is basically a frontend for the nim compiler so `--path`:option: flags and `config files `_ can be used to specify additional dependencies like -`nimsuggest --stdin --debug --path:"dependencies" myproject.nim`. +`nimsuggest --stdin --debug --path:"dependencies" myproject.nim`:cmd:. Specifying the location of the query @@ -60,25 +61,25 @@ cryptic 3 letter "command" `def` or `con` or `sug` or `use` followed by a location. A query location consists of: -`file.nim` +``file.nim`` This is the name of the module or include file the query refers to. -`dirtyfile.nim` +``dirtyfile.nim`` This is optional. The `file` parameter is enough for static analysis, but IDEs tend to have *unsaved buffers* where the user may still be in the middle of typing a line. In such situations the IDE can save the current contents to a temporary file and then use the - `dirtyfile.nim` option to tell Nimsuggest that `foobar.nim` should - be taken from `temporary/foobar.nim`. + ``dirtyfile.nim`` option to tell Nimsuggest that ``foobar.nim`` should + be taken from ``temporary/foobar.nim``. -`line` +``line`` An integer with the line you are going to query. For the compiler lines start at **1**. -`col` +``col`` An integer with the column you are going to query. For the compiler columns start at **0**. @@ -149,9 +150,9 @@ tab characters (``\t``). The values of each column are: 1. Three characters indicating the type of returned answer (e.g. `def` for definition, `sug` for suggestion, etc). 2. Type of the symbol. This can be `skProc`, `skLet`, and just - about any of the enums defined in the module `compiler/ast.nim`. + about any of the enums defined in the module ``compiler/ast.nim``. 3. Fully qualified path of the symbol. If you are querying a symbol - defined in the `proj.nim` file, this would have the form + defined in the ``proj.nim`` file, this would have the form `proj.symbolName`. 4. Type/signature. For variables and enums this will contain the type of the symbol, for procs, methods and templates this will diff --git a/doc/packaging.rst b/doc/packaging.rst index ecde73f61..ecb17e482 100644 --- a/doc/packaging.rst +++ b/doc/packaging.rst @@ -45,7 +45,7 @@ The Debian package ships bash and ksh completion and manpages that can be reused Hints on the build process: -:: +.. code:: cmd # build from C sources and then using koch ./build.sh --os $os_type --cpu $cpu_arch diff --git a/doc/regexprs.txt b/doc/regexprs.txt index 9ec08b810..f5544cc28 100644 --- a/doc/regexprs.txt +++ b/doc/regexprs.txt @@ -47,9 +47,11 @@ full documentation of Perl's regular expressions. Because the backslash ``\`` is a meta character both in the Nim programming language and in regular expressions, it is strongly recommended that one uses the *raw* strings of Nim, so that -backslashes are interpreted by the regular expression engine:: +backslashes are interpreted by the regular expression engine: +```nim r"\S" # matches any character that is not whitespace +``` A regular expression is a pattern that is matched against a subject string from left to right. Most characters stand for themselves in a pattern, and diff --git a/doc/testament.rst b/doc/testament.rst index ed1bd63a1..5590cc6d7 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -2,8 +2,8 @@ Testament =========== +.. default-role:: code .. include:: rstcommon.rst -.. default-role:: nim .. contents:: Testament is an advanced automatic unittests runner for Nim tests, is used for the development of Nim itself, diff --git a/doc/tools.rst b/doc/tools.rst index e0044e1ca..0de4ac914 100644 --- a/doc/tools.rst +++ b/doc/tools.rst @@ -1,9 +1,10 @@ -.. default-role:: code - ======================== Tools available with Nim ======================== +.. default-role:: code +.. include:: rstcommon.rst + The standard distribution ships with the following tools: - | `Hot code reloading `_ @@ -11,11 +12,11 @@ The standard distribution ships with the following tools: document explaining how it works. - | `Documentation generator `_ - | The builtin document generator `nim doc` generates HTML documentation - from `.nim` source files. + | The builtin document generator `nim doc`:cmd: generates HTML documentation + from ``.nim`` source files. - | `Nimsuggest for IDE support `_ - | Through the `nimsuggest` tool, any IDE can query a `.nim` source file + | Through the `nimsuggest`:cmd: tool, any IDE can query a ``.nim`` source file and obtain useful information like the definition of symbols or suggestions for completion. @@ -29,11 +30,11 @@ The standard distribution ships with the following tools: | Nim search and replace utility. - | nimpretty - | `nimpretty` is a Nim source code beautifier, + | `nimpretty`:cmd: is a Nim source code beautifier, to format code according to the official style guide. - | `testament `_ - | `testament` is an advanced automatic *unittests runner* for Nim tests, + | `testament`:cmd: is an advanced automatic *unittests runner* for Nim tests, is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, JS, etc), `simulated Dry-Runs `_, From 5423915e5ade14fb98c2aba28f269311506960e5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 4 Jun 2021 16:20:47 +0200 Subject: [PATCH 2668/4254] real bugfix for #17170 (#18171) * real bugfix for #17170 * better fix --- compiler/closureiters.nim | 10 ++++++---- compiler/injectdestructors.nim | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index adc5a4873..a8da7485e 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -414,8 +414,11 @@ proc exprToStmtList(n: PNode): tuple[s, res: PNode] = proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode = - result = newTree(nkFastAsgn, ctx.newEnvVarAccess(s), v) - result.info = v.info + if isEmptyType(v.typ): + result = v + else: + result = newTree(nkFastAsgn, ctx.newEnvVarAccess(s), v) + result.info = v.info proc addExprAssgn(ctx: Ctx, output, input: PNode, sym: PSym) = if input.kind == nkStmtListExpr: @@ -427,8 +430,7 @@ proc addExprAssgn(ctx: Ctx, output, input: PNode, sym: PSym) = proc convertExprBodyToAsgn(ctx: Ctx, exprBody: PNode, res: PSym): PNode = result = newNodeI(nkStmtList, exprBody.info) - if exprBody.typ != nil: - ctx.addExprAssgn(result, exprBody, res) + ctx.addExprAssgn(result, exprBody, res) proc newNotCall(g: ModuleGraph; e: PNode): PNode = result = newTree(nkCall, newSymNode(g.getSysMagic(e.info, "not", mNot), e.info), e) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 48a852d26..8ef08adeb 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -364,6 +364,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) = proc genCopyNoCheck(c: var Con; dest, ri: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) result = c.genOp(t, attachedAsgn, dest, ri) + assert ri.typ != nil proc genCopy(c: var Con; dest, ri: PNode): PNode = let t = dest.typ @@ -371,6 +372,7 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode = # try to improve the error message here: c.checkForErrorPragma(t, ri, "=copy") result = c.genCopyNoCheck(dest, ri) + assert ri.typ != nil proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = # discriminator is ordinal value that doesn't need sink destroy From a77360da5bad40d22e942cdd5cb9614c3548bf34 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 5 Jun 2021 03:41:13 +0800 Subject: [PATCH 2669/4254] workaround bug in sharedtables.withValue to unblock frozen CI on OSX (#18172) --- lib/pure/collections/sharedtables.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 2788ec785..a85674df9 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -108,10 +108,14 @@ template withValue*[A, B](t: var SharedTable[A, B], key: A, table.withValue("a", value): value[] = "m" + var flag = false table.withValue("d", value): discard value doAssert false do: # if "d" notin table + flag = true + + if flag: table["d"] = "n" assert table.mget("a") == "m" From cc7ec5a6a42c2aead2c411228f023cbeff4220de Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 4 Jun 2021 15:32:46 -0700 Subject: [PATCH 2670/4254] fix #7295: use move(result) inside template to avoid copy with --gc:refc (#18168) --- lib/pure/collections/sequtils.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e937b8394..6facfcc32 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1014,27 +1014,27 @@ template applyIt*(varSeq, op: untyped) = template newSeqWith*(len: int, init: untyped): untyped = - ## Creates a new sequence of length `len`, calling `init` to initialize - ## each value of the sequence. - ## - ## Useful for creating "2D" sequences - sequences containing other sequences - ## or to populate fields of the created sequence. + ## Creates a new `seq` of length `len`, calling `init` to initialize + ## each value of the seq. ## + ## Useful for creating "2D" seqs - seqs containing other seqs + ## or to populate fields of the created seq. runnableExamples: - ## Creates a sequence containing 5 bool sequences, each of length of 3. + ## Creates a seq containing 5 bool seqs, each of length of 3. var seq2D = newSeqWith(5, newSeq[bool](3)) assert seq2D.len == 5 assert seq2D[0].len == 3 assert seq2D[4][2] == false - ## Creates a sequence of 20 random numbers from 1 to 10 - import random - var seqRand = newSeqWith(20, rand(10)) + ## Creates a seq with random numbers + import std/random + var seqRand = newSeqWith(20, rand(1.0)) + assert seqRand[0] != seqRand[1] var result = newSeq[typeof(init)](len) for i in 0 ..< len: result[i] = init - result + move(result) # refs bug #7295 func mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool; filter = nnkLiterals): NimNode = From a2b60812568b5b90af9bb15c50873a726dd49b94 Mon Sep 17 00:00:00 2001 From: Euan Date: Fri, 4 Jun 2021 23:46:57 +0100 Subject: [PATCH 2671/4254] Ref #18177 - lbgc.so.5.0 on OpenBSD 6.9 (#18180) --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 942d29fe8..cae0ec3e2 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1146,7 +1146,7 @@ when defined(boehmgc): elif defined(macosx): const boehmLib = "libgc.dylib" elif defined(openbsd): - const boehmLib = "libgc.so.4.0" + const boehmLib = "libgc.so.(4|5).0" elif defined(freebsd): const boehmLib = "libgc-threaded.so.1" else: From 3cc547f2dfc3d2a981ccde38adb1f3deeb9715c2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 4 Jun 2021 21:58:26 -0700 Subject: [PATCH 2672/4254] macros.treeRepr + friends: collapse SymChoice (#18072) * macros.treeRepr + friends: collapse SymChoice * make repr+friends work with invalid symchoice nodes * address comment --- changelog.md | 3 + lib/core/macros.nim | 63 +++++++++++++------- tests/macros/tdumpast.nim | 122 +++++++++++++++++++++++++++++++------- tests/stdlib/tmacros.nim | 6 ++ 4 files changed, 151 insertions(+), 43 deletions(-) diff --git a/changelog.md b/changelog.md index 06251abfc..1050e4916 100644 --- a/changelog.md +++ b/changelog.md @@ -81,6 +81,9 @@ - Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` in `std/algorithm`. +- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes in a collapsed way, + use `-d:nimLegacyMacrosCollapseSymChoice` to get previous behavior. + - The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. The downside is that these defines now have custom logic that doesn't apply for other defines. diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 89f90a23b..37f855d94 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -856,6 +856,29 @@ proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode = for i in countdown(pack.len - 1, 0): result = newCall(op, pack[i], result) +proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. + +proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. `a` can be an identifier or a + ## symbol. `a` may be wrapped in an export marker + ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), + ## these nodes will be unwrapped. + +proc eqIdent*(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. `b` can be an identifier or a + ## symbol. `b` may be wrapped in an export marker + ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), + ## these nodes will be unwrapped. + +proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. `a` and `b` can be an + ## identifier or a symbol. Both may be wrapped in an export marker + ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), + ## these nodes will be unwrapped. + +const collapseSymChoice = not defined(nimLegacyMacrosCollapseSymChoice) + proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indented = false) {.benign.} = if level > 0: if indented: @@ -883,8 +906,21 @@ proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indent res.add(" " & $n.strVal.newLit.repr) of nnkNone: assert false + elif n.kind in {nnkOpenSymChoice, nnkClosedSymChoice} and collapseSymChoice: + res.add(" " & $n.len) + if n.len > 0: + var allSameSymName = true + for i in 0.. 0: + res.add(" " & n[0].strVal.newLit.repr) else: res.add(".newTree(") for j in 0..`_. return node.copyNimTree() -proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. - -proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. `a` can be an identifier or a - ## symbol. `a` may be wrapped in an export marker - ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), - ## these nodes will be unwrapped. - -proc eqIdent*(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. `b` can be an identifier or a - ## symbol. `b` may be wrapped in an export marker - ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), - ## these nodes will be unwrapped. - -proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. `a` and `b` can be an - ## identifier or a symbol. Both may be wrapped in an export marker - ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), - ## these nodes will be unwrapped. - proc expectIdent*(n: NimNode, name: string) {.since: (1,1).} = ## Check that `eqIdent(n,name)` holds true. If this is not the ## case, compilation aborts with an error message. This is useful diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim index b6bcbe8f0..484b3c2f3 100644 --- a/tests/macros/tdumpast.nim +++ b/tests/macros/tdumpast.nim @@ -2,34 +2,69 @@ import macros -template plus(a, b: untyped): untyped {.dirty} = - a + b +block: + template plus(a, b: untyped): untyped {.dirty} = + a + b -macro call(e: untyped): untyped = - result = newCall("foo", newStrLitNode("bar")) + macro call(e: untyped): untyped = + result = newCall("foo", newStrLitNode("bar")) -macro dumpAST(n: untyped): untyped = - # dump AST as a side-effect and return the inner node - let n = callsite() - echo n.lispRepr - echo n.treeRepr + macro dumpAST(n: untyped): string = + var msg = "" + msg.add "lispRepr:\n" & n.lispRepr & "\n" + msg.add "treeRepr:\n" & n.treeRepr & "\n" - var plusAst = getAst(plus(1, 2)) - echo plusAst.lispRepr + var plusAst = getAst(plus(1, 2)) + msg.add "lispRepr:\n" & n.lispRepr & "\n" - var callAst = getAst(call(4)) - echo callAst.lispRepr + var callAst = getAst(call(4)) + msg.add "callAst.lispRepr:\n" & callAst.lispRepr & "\n" - var e = parseExpr("foo(bar + baz)") - echo e.lispRepr + var e = parseExpr("foo(bar + baz)") + msg.add "e.lispRepr:\n" & e.lispRepr & "\n" + result = msg.newLit - result = n[1] + let a = dumpAST: + proc add(x, y: int): int = + return x + y + const foo = 3 -dumpAST: - proc add(x, y: int): int = - return x + y - - proc sub(x, y: int): int = return x - y + doAssert a == """ +lispRepr: +(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3)))) +treeRepr: +StmtList + ProcDef + Ident "add" + Empty + Empty + FormalParams + Ident "int" + IdentDefs + Ident "x" + Ident "y" + Ident "int" + Empty + Empty + Empty + StmtList + ReturnStmt + Infix + Ident "+" + Ident "x" + Ident "y" + ConstSection + ConstDef + Ident "foo" + Empty + IntLit 3 +lispRepr: +(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3)))) +callAst.lispRepr: +(Call (Ident "foo") (StrLit "bar")) +e.lispRepr: +(Call (Ident "foo") (Infix (Ident "+") (Ident "bar") (Ident "baz"))) +""" macro fun() = let n = quote do: @@ -79,3 +114,48 @@ block: # repr doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)" doAssert repr2((1)) == "(1)" doAssert repr2((1+2)) == "(1 + 2)" + +block: # treeRepr + macro treeRepr2(a: untyped): string = newLit a.treeRepr + macro treeRepr3(a: typed): string = newLit a.treeRepr + + doAssert treeRepr2(1+1 == 2) == """ +Infix + Ident "==" + Infix + Ident "+" + IntLit 1 + IntLit 1 + IntLit 2""" + + proc baz() = discard + proc baz(a: int) = discard + proc baz(a: float) = discard + + doAssert treeRepr3(baz()) == """ +Call + Sym "baz"""" + + let a = treeRepr3(block: + proc bar(a: auto) = baz()) + doAssert a == """ +BlockStmt + Empty + ProcDef + Sym "bar" + Empty + GenericParams + Sym "a:type" + FormalParams + Empty + IdentDefs + Sym "a" + Sym "auto" + Empty + Empty + Bracket + Empty + Empty + StmtList + Call + OpenSymChoice 3 "baz"""" diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index 52ea1e898..18cfdc75c 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -1,3 +1,9 @@ +#[ +xxx macros tests need to be reorganized to makes sure each API is tested once +See also: + tests/macros/tdumpast.nim for treeRepr + friends +]# + import std/macros block: # hasArgOfName From 295429f42595ce5c707456e657e4de6b2734df42 Mon Sep 17 00:00:00 2001 From: Rainbow Asteroids Date: Sat, 5 Jun 2021 03:07:26 -0400 Subject: [PATCH 2673/4254] add `dom.scrollIntoView` with options; refs #18093 (#18181) --- changelog.md | 2 ++ lib/js/dom.nim | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/changelog.md b/changelog.md index 1050e4916..7619ee6a3 100644 --- a/changelog.md +++ b/changelog.md @@ -335,6 +335,8 @@ - Added setCurrentException for JS backend. +- Added `dom.scrollIntoView` proc with options + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 16fc96b68..2b2332020 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1317,6 +1317,11 @@ type ready*: FontFaceSetReady onloadingdone*: proc(event: Event) + ScrollIntoViewOptions* = object + behavior*: cstring + `block`*: cstring + inline*: cstring + since (1, 3): type DomParser* = ref object @@ -1538,6 +1543,7 @@ proc removeAttribute*(n: Node, attr: cstring) proc removeAttributeNode*(n, attr: Node) proc replaceData*(n: Node, start, len: int, text: cstring) proc scrollIntoView*(n: Node) +proc scrollIntoView*(n: Node, options: ScrollIntoViewOptions) proc setAttribute*(n: Node, name, value: cstring) proc setAttributeNode*(n: Node, attr: Node) proc querySelector*(n: Node, selectors: cstring): Element From 9c0666e0bbb7af69e2d87e7e81302ed3d3f06412 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 5 Jun 2021 10:12:37 +0300 Subject: [PATCH 2674/4254] rst: remove `roSkipPounds` option (#18175) --- lib/packages/docutils/rst.nim | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index dae692fb7..336caa2df 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -201,8 +201,6 @@ from highlite import SourceLanguage, getSourceLanguage type RstParseOption* = enum ## options for the RST parser - roSkipPounds, ## skip ``#`` at line beginning (documentation - ## embedded in Nim comments) roSupportSmilies, ## make the RST parser support smilies like ``:)`` roSupportRawDirective, ## support the ``raw`` directive (don't support ## it for sandboxing) @@ -307,7 +305,6 @@ type buf*: cstring bufpos*: int line*, col*, baseIndent*: int - skipPounds*: bool adornmentLine*: bool escapeNext*: bool @@ -380,9 +377,6 @@ proc getIndentAux(L: var Lexer, start: int): int = else: inc pos elif L.buf[pos] == '\n': inc pos - if L.skipPounds: - if L.buf[pos] == '#': inc pos - if L.buf[pos] == '#': inc pos while true: case L.buf[pos] of ' ', '\v', '\f': @@ -447,26 +441,13 @@ proc rawGetTok(L: var Lexer, tok: var Token) = inc L.col tok.col = max(tok.col - L.baseIndent, 0) -proc getTokens(buffer: string, skipPounds: bool, tokens: var TokenSeq): int = +proc getTokens(buffer: string, tokens: var TokenSeq): int = var L: Lexer var length = tokens.len L.buf = cstring(buffer) L.line = 0 # skip UTF-8 BOM if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF': inc L.bufpos, 3 - L.skipPounds = skipPounds - if skipPounds: - if L.buf[L.bufpos] == '#': - inc L.bufpos - inc result - if L.buf[L.bufpos] == '#': - inc L.bufpos - inc result - L.baseIndent = 0 - while L.buf[L.bufpos] == ' ': - inc L.bufpos - inc L.baseIndent - inc result while true: inc length setLen(tokens, length) @@ -2123,7 +2104,7 @@ proc parseSimpleTable(p: var RstParser): PRstNode = q.col = cols[j] q.line = line - 1 q.filename = p.filename - q.col += getTokens(row[j], false, q.tok) + q.col += getTokens(row[j], q.tok) b = newRstNode(rnTableDataCell) b.add(parseDoc(q)) a.add(b) @@ -2176,7 +2157,7 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = q.col = p.col q.line = currentTok(p).line - 1 q.filename = p.filename - q.col += getTokens(getColContents(p, row[j]), false, q.tok) + q.col += getTokens(getColContents(p, row[j]), q.tok) b.add(parseDoc(q)) a.add(b) result.add(a) @@ -2584,7 +2565,6 @@ proc dirInclude(p: var RstParser): PRstNode = q.filename = path q.col += getTokens( inputString[startPosition..endPosition].strip(), - false, q.tok) # workaround a GCC bug; more like the interior pointer bug? #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0: @@ -2948,7 +2928,7 @@ proc rstParse*(text, filename: string, initParser(p, newSharedState(options, findFile, msgHandler)) p.filename = filename p.line = line - p.col = column + getTokens(text, roSkipPounds in options, p.tok) + p.col = column + getTokens(text, p.tok) let unresolved = parseDoc(p) countTitles(p, unresolved) orderFootnotes(p) From 9c6259e55717acbc954140ef2bb0ca363971c8c7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 5 Jun 2021 00:45:37 -0700 Subject: [PATCH 2675/4254] up to 20x faster jsonutils deserialization (#18183) * up to 20x faster jsonutils deserialization * noinline --- lib/std/jsonutils.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 60d78fea5..c141985d3 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -128,14 +128,14 @@ macro initCaseObject(T: typedesc, fun: untyped): untyped = `fun`(`key2`, typedesc[`typ`]) result.add newTree(nnkExprColonExpr, key, val) -proc checkJsonImpl(cond: bool, condStr: string, msg = "") = - if not cond: - # just pick 1 exception type for simplicity; other choices would be: - # JsonError, JsonParser, JsonKindError - raise newException(ValueError, msg) +proc raiseJsonException(condStr: string, msg: string) {.noinline.} = + # just pick 1 exception type for simplicity; other choices would be: + # JsonError, JsonParser, JsonKindError + raise newException(ValueError, condStr & " failed: " & msg) template checkJson(cond: untyped, msg = "") = - checkJsonImpl(cond, astToStr(cond), msg) + if not cond: + raiseJsonException(astToStr(cond), msg) proc hasField[T](obj: T, field: string): bool = for k, _ in fieldPairs(obj): From b9843b156dfc16f1f99cbee8fc8e55b7abd6c21b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 5 Jun 2021 00:47:28 -0700 Subject: [PATCH 2676/4254] fix #18178, set a CI timeout for github action pipelines instead of the 6 hour default (#18179) --- .github/workflows/ci_docs.yml | 1 + .github/workflows/ci_packages.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index ddef94fbe..6ae228d2d 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -44,6 +44,7 @@ jobs: name: ${{ matrix.target }} runs-on: ${{ matrix.os }} + timeout-minutes: 60 # refs bug #18178 steps: - name: 'Checkout' diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index aeb29e147..529e6e8b6 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -11,6 +11,7 @@ jobs: batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num` name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' runs-on: ${{ matrix.os }} + timeout-minutes: 60 # refs bug #18178 env: NIM_TEST_PACKAGES: "1" NIM_TESTAMENT_BATCH: ${{ matrix.batch }} From 9106ab7db19e22782c544c6362741dff4142820e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 6 Jun 2021 00:53:22 -0700 Subject: [PATCH 2677/4254] make changeDetectedViaJsonBuildInstructions warning less verbose when json file invalid (eg due to spec change) (#18197) --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index ea2b09866..831acae68 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -993,7 +993,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute var bcache: BuildCache try: bcache.fromJson(jsonFile.string.parseFile) except IOError, OSError, ValueError: - stderr.write "Warning: JSON processing failed for $#: $#\n" % [jsonFile.string, getCurrentExceptionMsg()] + stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string return true if bcache.currentDir != getCurrentDir() or # fixes bug #16271 bcache.configFiles != conf.configFiles.mapIt(it.string) or From e7816a3e77ab0f821d66667dfc448f1898199f59 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 6 Jun 2021 10:55:20 +0300 Subject: [PATCH 2678/4254] update docgen documentation (#18192) * update docgen documentation * --fullhelp * Update doc/docgen.rst Co-authored-by: Timothee Cour * [skip ci] fix typos Co-authored-by: Timothee Cour --- changelog.md | 7 +++ doc/advopt.txt | 3 +- doc/docgen.rst | 123 ++++++++++++++++++++++++++++++------------------- 3 files changed, 84 insertions(+), 49 deletions(-) diff --git a/changelog.md b/changelog.md index 7619ee6a3..f141ea95a 100644 --- a/changelog.md +++ b/changelog.md @@ -449,6 +449,13 @@ ## Tool changes +- Latex doc generation is revised: output `.tex` files should be compiled + by `xelatex` (not by `pdflatex` as before). Now default Latex settings + provide support for Unicode and do better job for avoiding margin overflows. + +- Implemented `doc2tex` compiler command which converts documentation in + `.nim` files to Latex. + - The rst parser now supports markdown table syntax. Known limitations: - cell alignment is not supported, i.e. alignment annotations in a delimiter diff --git a/doc/advopt.txt b/doc/advopt.txt index e627d4768..e5b4c9568 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -6,7 +6,8 @@ Advanced commands: //e run a Nimscript file //rst2html convert a reStructuredText file to HTML use `--docCmd:skip` to skip compiling snippets - //rst2tex convert a reStructuredText file to TeX + //rst2tex convert a reStructuredText file to LaTeX + //doc2tex extract the documentation to a LaTeX file //jsondoc extract the documentation to a json file //ctags create a tags file //buildIndex build an index for the whole documentation diff --git a/doc/docgen.rst b/doc/docgen.rst index e9ff7f1e3..2074ee06f 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -14,12 +14,22 @@ Introduction ============ This document describes the `documentation generation tools`:idx: built into -the `Nim compiler `_, which can generate HTML and JSON output -from input .nim files and projects, as well as HTML and LaTeX from input RST +the `Nim compiler `_, which can generate HTML, Latex and JSON output +from input ``.nim`` files and projects, as well as HTML and LaTeX from input RST (reStructuredText) files. The output documentation will include the module dependencies (`import`), any top-level documentation comments (`##`), and exported symbols (`*`), including procedures, types, and variables. +=================== ====================== ============ ============== +command runs on... input format output format +=================== ====================== ============ ============== +`nim doc`:cmd: documentation comments ``.nim`` ``.html`` HTML +`nim doc2tex`:cmd: ″ ″ ``.tex`` LaTeX +`nim jsondoc`:cmd: ″ ″ ``.json`` JSON +`nim rst2html`:cmd: standalone rst files ``.rst`` ``.html`` HTML +`nim rst2tex`:cmd: ″ ″ ``.tex`` LaTeX +=================== ====================== ============ ============== + Quick start ----------- @@ -53,7 +63,8 @@ Any comments which are preceded by a double-hash (`##`), are interpreted as documentation. Comments are parsed as RST (see `reference `_), providing Nim module authors the ability to easily generate richly formatted -documentation with only their well-documented code. +documentation with only their well-documented code! +Basic Markdown syntax is also supported inside the doc comments. Example: @@ -99,32 +110,22 @@ won't influence RST formatting. ## ## Paragraph. -Nim file input ------------------ - -The following examples will generate documentation for the below contrived -*Nim* module, aptly named 'sample.nim' - -sample.nim: - -.. code-block:: nim - ## This module is a sample. - - import std/strutils - - proc helloWorld*(times: int) = - ## Takes an integer and outputs - ## as many "hello world!"s - - for i in 0 .. times-1: - echo "hello world!" - - helloWorld(5) - Document Types ============== +Example of Nim file input +------------------------- + +The following examples will generate documentation for this sample +*Nim* module, aptly named ``doc/docgen_sample.nim``: + +.. code:: nim + :file: docgen_sample.nim + +All the below commands save their output to ``htmldocs`` directory relative to +the directory of file; +hence the output for this sample will be in ``doc/htmldocs``. HTML ---- @@ -138,7 +139,7 @@ The `doc`:option: command: .. code:: cmd - nim doc sample + nim doc docgen_sample.nim Partial Output:: ... @@ -149,6 +150,27 @@ The full output can be seen here: `docgen_sample.html `_. It runs after semantic checking and includes pragmas attached implicitly by the compiler. +LaTeX +----- + +LaTeX files are intended to be converted to PDF, especially for offline +reading or making hard copies. (LaTeX output is oftentimes better than +HTML -> PDF conversion). + +The `doc2tex`:option: command: + +.. code:: cmd + + nim doc2tex docgen_sample.nim + cd htmldocs + xelatex docgen_sample.tex + xelatex docgen_sample.tex + # It is usually necessary to run `xelatex` 2 times (or even 3 times for + # large documents) to get all labels generated. + # That depends on this warning in the end of `xelatex` output: + # LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. + +The output is ``docgen_sample.pdf``. JSON ---- @@ -163,7 +185,7 @@ The `jsondoc`:option: command: .. code:: cmd - nim jsondoc sample + nim jsondoc docgen_sample.nim Output:: { @@ -189,7 +211,7 @@ The `jsondoc0`:option: command: .. code:: cmd - nim jsondoc0 sample + nim jsondoc0 docgen_sample.nim Output:: [ @@ -204,7 +226,7 @@ Output:: } ] -Note that the `jsondoc`:option: command outputs it's JSON without pretty-printing it, +Note that the `jsondoc`:option: command outputs its JSON without pretty-printing it, while `jsondoc0`:option: outputs pretty-printed JSON. Related Options @@ -217,9 +239,10 @@ Project switch nim doc --project filename.nim -This will recursively generate documentation of all nim modules imported +This will recursively generate documentation of all Nim modules imported into the input module that belong to the Nimble package that ``filename.nim`` -belongs to. +belongs to. The index files and the corresponding ``theindex.html`` will +also be generated. Index switch @@ -252,12 +275,13 @@ documented item in your source code pointing to the implementation of that item on a GitHub repository. You can click the link to see the implementation of the item. -The `git.commit`:option: switch overrides the hardcoded `devel` branch in config/nimdoc.cfg. +The `git.commit`:option: switch overrides the hardcoded `devel` branch in +``config/nimdoc.cfg``. This is useful to link to a different branch e.g. `--git.commit:master`:option:, or to a tag e.g. `--git.commit:1.2.3`:option: or a commit. Source URLs are generated as ``href="${url}/tree/${commit}/${path}#L${line}"`` -by default and this compatible with GitHub but not with GitLab. +by default and thus compatible with GitHub but not with GitLab. Similarly, `git.devel`:option: switch overrides the hardcoded `devel` branch for the `Edit` link which is also useful if you have a different working @@ -282,9 +306,10 @@ Other Input Formats The *Nim compiler* also has support for RST (reStructuredText) files with the `rst2html`:option: and `rst2tex`:option: commands. Documents like this one are -initially written in a dialect of RST which adds support for nim source code +initially written in a dialect of RST which adds support for Nim source code highlighting with the ``.. code-block:: nim`` prefix. ``code-block`` also -supports highlighting of C++ and some other c-like languages. +supports highlighting of a few other languages supported by the +`packages/docutils/highlite module `_. Usage: @@ -333,16 +358,16 @@ if they don't have any parameters. If there are parameters, they are represented by their types and will be comma-separated. To the plain symbol a suffix may be added depending on the type of the callable: -------------- -------------- -Callable type Suffix -------------- -------------- -proc *empty string* -macro ``.m`` -method ``.e`` -iterator ``.i`` -template ``.t`` -converter ``.c`` -------------- -------------- +============== ============== +Callable type Suffix +============== ============== +`proc`, `func` *empty string* +`macro` ``.m`` +`method` ``.e`` +`iterator` ``.i`` +`template` ``.t`` +`converter` ``.c`` +============== ============== The relationship of type to suffix is made by the proc `complexName` in the ``compiler/docgen.nim`` file. Here are some examples of complex names for @@ -422,10 +447,12 @@ final index, and TOC entries found in ``.nim`` files are discarded. Additional resources ==================== -`Nim Compiler User Guide `_ +* `Nim Compiler User Guide `_ -`RST Quick Reference -`_ +* Documentation for `rst module `_ -- Nim RST/Markdown parser. + +* `RST Quick Reference + `_ The output for HTML and LaTeX comes from the ``config/nimdoc.cfg`` and ``config/nimdoc.tex.cfg`` configuration files. You can add and modify these From e7aa41ff3f6820d8ada3fd650d523c7f7d584fda Mon Sep 17 00:00:00 2001 From: slangmgh <37659406+slangmgh@users.noreply.github.com> Date: Mon, 7 Jun 2021 17:42:32 +0800 Subject: [PATCH 2679/4254] fix 18186 with adding importc _umul128 (#18200) --- lib/system/dragonbox.nim | 3 ++- lib/system/schubfach.nim | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/system/dragonbox.nim b/lib/system/dragonbox.nim index db608c630..eec8749da 100644 --- a/lib/system/dragonbox.nim +++ b/lib/system/dragonbox.nim @@ -867,10 +867,11 @@ when defined(sizeof_Int128): return (hi, lo) elif defined(vcc) and defined(cpu64): + proc umul128(x, y: uint64, z: ptr uint64): uint64 {.importc: "_umul128", header: "".} proc mul128*(x: uint64; y: uint64): uint64x2 {.inline.} = var hi: uint64 = 0 var lo: uint64 = umul128(x, y, addr(hi)) - return (hi, lo) + return uint64x2(hi: hi, lo: lo) else: proc lo32*(x: uint64): uint32 {.inline.} = diff --git a/lib/system/schubfach.nim b/lib/system/schubfach.nim index c344b7425..94d3d3c25 100644 --- a/lib/system/schubfach.nim +++ b/lib/system/schubfach.nim @@ -147,6 +147,7 @@ when defined(sizeof_Int128): return y1 or uint32(y0 > 1) elif defined(vcc) and defined(cpu64): + proc umul128(x, y: uint64, z: ptr uint64): uint64 {.importc: "_umul128", header: "".} proc roundToOdd(g: uint64; cpHi: uint32): uint32 {.inline.} = var p1: uint64 = 0 var p0: uint64 = umul128(g, cpHi, addr(p1)) From 2ec52faae5ba5c233f977a8a4b997734c4ad83e7 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Mon, 7 Jun 2021 10:44:43 +0100 Subject: [PATCH 2680/4254] koch: print help if no command is given (#18199) --- koch.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 3d7276aee..665b5e042 100644 --- a/koch.nim +++ b/koch.nim @@ -708,4 +708,5 @@ when isMainModule: of "branchdone": branchDone() else: showHelp(success = false) break - of cmdEnd: break + of cmdEnd: + showHelp(success = false) From 429b1286325e7b6cf86ed4e29cea3e11a8c0e2df Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 7 Jun 2021 19:57:42 +0800 Subject: [PATCH 2681/4254] change mimedb stroe stringtable to orderedtable (#18065) * change mimedb stroe stringtable to orderedtable * Update lib/pure/mimetypes.nim Co-authored-by: Andreas Rumpf --- lib/pure/mimetypes.nim | 7 ++++--- tests/stdlib/tmimetypes.nim | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index c10739fec..6ae63a0ae 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -26,12 +26,12 @@ runnableExamples: doAssert m.getMimetype("fakext") == "text/fakelang" doAssert m.getMimetype("FaKeXT") == "text/fakelang" -import strtabs +import tables from strutils import startsWith, toLowerAscii, strip type MimeDB* = object - mimes: StringTableRef + mimes: OrderedTableRef[string, string] const mimes* = { "123": "application/vnd.lotus-1-2-3", @@ -1903,7 +1903,8 @@ const mimes* = { func newMimetypes*(): MimeDB = ## Creates a new Mimetypes database. The database will contain the most ## common mimetypes. - result.mimes = mimes.newStringTable() + {.cast(noSideEffect).}: + result.mimes = mimes.newOrderedTable() func getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string = ## Gets mimetype which corresponds to `ext`. Returns `default` if `ext` diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim index cd41e614b..93c20d4a3 100644 --- a/tests/stdlib/tmimetypes.nim +++ b/tests/stdlib/tmimetypes.nim @@ -6,6 +6,7 @@ import std/mimetypes template main() = var m = newMimetypes() doAssert m.getMimetype("mp4") == "video/mp4" + doAssert m.getExt("application/json") == "json" # see also `runnableExamples`. # xxx we should have a way to avoid duplicating code between runnableExamples and tests From 5bad022d58e21f0da455fbd7d421cd26a2b5c812 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 7 Jun 2021 21:32:37 +0800 Subject: [PATCH 2682/4254] alternative to #18185 (#18206) --- lib/core/rlocks.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index 5f155262a..a1ee0a6ec 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -11,7 +11,10 @@ when not compileOption("threads") and not defined(nimdoc): - {.error: "Rlocks requires --threads:on option.".} + when false: + # make rlocks modlue consistent with locks module, + # so they can replace each other seamlessly. + {.error: "Rlocks requires --threads:on option.".} const insideRLocksModule = true include "system/syslocks" From 21f3b8539a2e440f7cb69502721b6c56070e122f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 7 Jun 2021 17:22:35 +0200 Subject: [PATCH 2683/4254] fixes #18088 (#18209) --- lib/pure/nativesockets.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 605f62321..124afce56 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -438,7 +438,7 @@ proc getHostname*(): string {.tags: [ReadIOEffect].} = ## Returns the local hostname (not the FQDN) # https://tools.ietf.org/html/rfc1035#section-2.3.1 # https://tools.ietf.org/html/rfc2181#section-11 - const size = 64 + const size = 256 result = newString(size) when useWinVersion: let success = winlean.gethostname(result, size) From 51ab7ccec1ffa21cef67f1a75dea889653751cfc Mon Sep 17 00:00:00 2001 From: drtheuns Date: Mon, 7 Jun 2021 18:40:09 +0200 Subject: [PATCH 2684/4254] Fix JS error on index page and detect dark mode (#18191) * Fix JS error on index page and detect dark mode The theindex.html page doesn't have a dark mode switch so the main function will error because `toggleSwitch` is not defined. Checks have been added to prevent this from happening. Also add automatic detection of system settings for dark-mode. This could also be done with pure css, but then the dark mode variable declarations would have to be duplicated to work with the switch so I went with this approach. * Fix nimdoc tests * Fix rst2html tests --- config/nimdoc.cfg | 13 +++++++++---- nimdoc/rst2html/expected/rst_examples.html | 13 +++++++++---- nimdoc/test_out_index_dot_html/expected/index.html | 13 +++++++++---- .../test_out_index_dot_html/expected/theindex.html | 13 +++++++++---- .../testproject/expected/subdir/subdir_b/utils.html | 13 +++++++++---- nimdoc/testproject/expected/testproject.html | 13 +++++++++---- nimdoc/testproject/expected/theindex.html | 13 +++++++++---- 7 files changed, 63 insertions(+), 28 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index ed1b346a2..cdf49197d 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -252,7 +252,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -263,13 +262,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 5c434193e..68b796be7 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -34,7 +34,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -45,13 +44,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index bac39fd33..fac758c9b 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -34,7 +34,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -45,13 +44,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index aa9ca2645..34ddf8f6a 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -34,7 +34,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -45,13 +44,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 826cad02a..6aa71e8c2 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -34,7 +34,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -45,13 +44,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 513dd507b..65d9f83f5 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -34,7 +34,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -45,13 +44,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index e6efee986..55f7f33c9 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -34,7 +34,6 @@ function main() { } } - const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); function switchTheme(e) { if (e.target.checked) { document.documentElement.setAttribute('data-theme', 'dark'); @@ -45,13 +44,19 @@ function main() { } } - toggleSwitch.addEventListener('change', switchTheme, false); + const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]'); + if (toggleSwitch !== null) { + toggleSwitch.addEventListener('change', switchTheme, false); + } - const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null; + var currentTheme = localStorage.getItem('theme'); + if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = 'dark'; + } if (currentTheme) { document.documentElement.setAttribute('data-theme', currentTheme); - if (currentTheme === 'dark') { + if (currentTheme === 'dark' && toggleSwitch !== null) { toggleSwitch.checked = true; } } From 47acc80f4e05053d2653c7218434bc7fad880741 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 9 Jun 2021 17:33:19 +0200 Subject: [PATCH 2685/4254] make strict funcs analysis smarter (#18219) * make strict funcs analysis smarter: varParam[i] = v is different from varParam[i][] = v * added a test case * Update compiler/varpartitions.nim Co-authored-by: Clyybber --- compiler/varpartitions.nim | 87 +++++++++++++++---------- tests/effects/tfuncs_cannot_mutate2.nim | 27 ++++++++ tests/effects/tstrict_funcs.nim | 17 +++++ 3 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 tests/effects/tfuncs_cannot_mutate2.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 810ce8586..9cf1e38ad 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -175,12 +175,18 @@ proc root(v: var Partitions; start: int): int = v.s[it].con = Connection(kind: dependsOn, parent: result) it = next -proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) = +proc potentialMutation(v: var Partitions; s: PSym; level: int; info: TLineInfo) = let id = variableId(v, s) if id >= 0: let r = root(v, id) - let flags = if s.kind == skParam and isConstParam(s): - {isMutated, isMutatedDirectly} + let flags = if s.kind == skParam: + if isConstParam(s): + {isMutated, isMutatedDirectly} + elif s.typ.kind == tyVar and level <= 1: + # varParam[i] = v is different from varParam[i][] = v + {} + else: + {isMutated} else: {isMutated} @@ -339,36 +345,44 @@ proc pathExpr(node: PNode; owner: PSym): PNode = if result == nil and borrowFromConstExpr(n): result = n -proc allRoots(n: PNode; result: var seq[PSym]; followDotExpr = true) = +const + RootEscapes = 1000 # in 'p(r)' we don't know what p does to our poor root. + # so we assume a high level of indirections + +proc allRoots(n: PNode; result: var seq[(PSym, int)]; level: int) = case n.kind of nkSym: if n.sym.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}: - result.add(n.sym) + result.add((n.sym, level)) - of nkDotExpr, nkDerefExpr, nkBracketExpr, nkHiddenDeref, - nkCheckedFieldExpr, nkAddr, nkHiddenAddr: - if followDotExpr: - allRoots(n[0], result, followDotExpr) + of nkDerefExpr, nkHiddenDeref: + allRoots(n[0], result, level+1) + of nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, nkAddr, nkHiddenAddr: + allRoots(n[0], result, level) of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkCast, nkObjUpConv, nkObjDownConv: if n.len > 0: - allRoots(n.lastSon, result, followDotExpr) + allRoots(n.lastSon, result, level) of nkCaseStmt, nkObjConstr: for i in 1.. 1: - allRoots(n[1], result, followDotExpr) + # XXX We really need the unwritten RFC here and distinguish between + # proc `[]`(x: var Container): var T # resizes the container + # and + # proc `[]`(x: Container): var T # only allows for slot mutation + allRoots(n[1], result, RootEscapes) else: let m = getMagic(n) case m @@ -387,12 +401,12 @@ proc allRoots(n: PNode; result: var seq[PSym]; followDotExpr = true) = let paramType = typ.n[i].typ if not paramType.isCompileTimeOnly and not typ.sons[0].isEmptyType and canAlias(paramType, typ.sons[0]): - allRoots(it, result, followDotExpr) + allRoots(it, result, RootEscapes) else: - allRoots(it, result, followDotExpr) + allRoots(it, result, RootEscapes) of mSlice: - allRoots(n[1], result, followDotExpr) + allRoots(n[1], result, level+1) else: discard "harmless operation" else: @@ -466,10 +480,10 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = dest.flags.incl ownsData elif n.typ.kind in {tyLent, tyVar}: # we know the result is derived from the first argument: - var roots: seq[PSym] - allRoots(n[1], roots) + var roots: seq[(PSym, int)] + allRoots(n[1], roots, RootEscapes) for r in roots: - connect(c, dest.sym, r, n[1].info) + connect(c, dest.sym, r[0], n[1].info) else: let magic = if n[0].kind == nkSym: n[0].sym.magic else: mNone @@ -582,19 +596,19 @@ proc deps(c: var Partitions; dest, src: PNode) = if borrowChecking in c.goals: borrowingAsgn(c, dest, src) - var targets, sources: seq[PSym] - allRoots(dest, targets) - allRoots(src, sources) + var targets, sources: seq[(PSym, int)] + allRoots(dest, targets, 0) + allRoots(src, sources, 0) let destIsComplex = containsPointer(dest.typ) for t in targets: if dest.kind != nkSym and c.inNoSideEffectSection == 0: - potentialMutation(c, t, dest.info) + potentialMutation(c, t[0], t[1], dest.info) if destIsComplex: for s in sources: - connect(c, t, s, dest.info) + connect(c, t[0], s[0], dest.info) if cursorInference in c.goals and src.kind != nkEmpty: let d = pathExpr(dest, c.owner) @@ -602,7 +616,8 @@ proc deps(c: var Partitions; dest, src: PNode) = let vid = variableId(c, d.sym) if vid >= 0: destMightOwn(c, c.s[vid], src) - for s in sources: + for source in sources: + let s = source[0] if s == d.sym: discard "assignments like: it = it.next are fine" elif {sfGlobal, sfThread} * s.flags != {} or hasDisabledAsgn(c.g, s.typ): @@ -638,9 +653,9 @@ proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) = if constParameters in c.goals and tfNoSideEffect in callee.flags: discard "we know there are no hidden mutations through an immutable parameter" elif c.inNoSideEffectSection == 0 and containsPointer(n.typ): - var roots: seq[PSym] - allRoots(n, roots) - for r in roots: potentialMutation(c, r, n.info) + var roots: seq[(PSym, int)] + allRoots(n, roots, RootEscapes) + for r in roots: potentialMutation(c, r[0], r[1], n.info) proc traverse(c: var Partitions; n: PNode) = inc c.abstractTime @@ -682,12 +697,12 @@ proc traverse(c: var Partitions; n: PNode) = if i < L: let paramType = parameters[i].skipTypes({tyGenericInst, tyAlias}) if not paramType.isCompileTimeOnly and paramType.kind in {tyVar, tySink, tyOwned}: - var roots: seq[PSym] - allRoots(it, roots) + var roots: seq[(PSym, int)] + allRoots(it, roots, RootEscapes) if paramType.kind == tyVar: if c.inNoSideEffectSection == 0: - for r in roots: potentialMutation(c, r, it.info) - for r in roots: noCursor(c, r) + for r in roots: potentialMutation(c, r[0], r[1], it.info) + for r in roots: noCursor(c, r[0]) if borrowChecking in c.goals: # a call like 'result.add toOpenArray()' can also be a borrow @@ -703,10 +718,10 @@ proc traverse(c: var Partitions; n: PNode) = when false: # XXX investigate if this is required, it doesn't look # like it is! - var roots: seq[PSym] - allRoots(n[0], roots) + var roots: seq[(PSym, int)] + allRoots(n[0], roots, RootEscapes) for r in roots: - potentialMutation(c, r, it.info) + potentialMutation(c, r[0], r[1], it.info) of nkTupleConstr, nkBracket: for child in n: traverse(c, child) diff --git a/tests/effects/tfuncs_cannot_mutate2.nim b/tests/effects/tfuncs_cannot_mutate2.nim new file mode 100644 index 000000000..d5082e57b --- /dev/null +++ b/tests/effects/tfuncs_cannot_mutate2.nim @@ -0,0 +1,27 @@ +discard """ + errormsg: "'copy' can have side effects" + nimout: '''an object reachable from 'y' is potentially mutated +tfuncs_cannot_mutate2.nim(15, 7) the mutation is here +tfuncs_cannot_mutate2.nim(13, 10) is the statement that connected the mutation to the parameter +''' +""" + +{.experimental: "strictFuncs".} + +func copy[T](x: var openArray[T]; y: openArray[T]) = + for i in 0..high(x): + x[i] = y[i] + + x[0].a = nil + +type + R = ref object + a, b: R + data: string + +proc main = + var a, b: array[3, R] + b = [R(data: "a"), R(data: "b"), R(data: "c")] + copy a, b + +main() diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index 044bc7ee1..9d20f5d7e 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -27,3 +27,20 @@ block: var x = @[0, 1] let z = x &&& 2 + + +func copy[T](x: var openArray[T]; y: openArray[T]) = + for i in 0..high(x): + x[i] = y[i] + +type + R = ref object + a, b: R + data: string + +proc main = + var a, b: array[3, R] + b = [R(data: "a"), R(data: "b"), R(data: "c")] + copy a, b + +main() From 19918ceb2b099440cd3e43b6d7fff313de6a84a2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 9 Jun 2021 14:46:00 -0700 Subject: [PATCH 2686/4254] update .github/ISSUE_TEMPLATE/bug_report.md, mention PRs, contributing, devel branch (#18224) --- .github/ISSUE_TEMPLATE/bug_report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 9571896d8..807e50d35 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,6 +7,8 @@ assignees: '' --- +(Consider writing a PR targetting devel branch after filing this, see [contributing.html](https://nim-lang.github.io/Nim/contributing.html)). + Function `echo` outputs the wrong string. ### Example From 79ded694d7f913755dc7261c7468f04fe421e0b3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 9 Jun 2021 22:00:34 -0700 Subject: [PATCH 2687/4254] avoid re-exporting options from std/wrapnils (#18222) --- lib/std/wrapnils.nim | 2 +- tests/stdlib/twrapnils.nim | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim index 708faf4cf..ed0a79d79 100644 --- a/lib/std/wrapnils.nim +++ b/lib/std/wrapnils.nim @@ -25,7 +25,6 @@ runnableExamples: assert (?.f2.x2.x2).x3 == nil # this terminates ?. early from options import Option, isSome, get, option, unsafeGet, UnpackDefect -export options.get, options.isSome, options.isNone template fakeDot*(a: Option, b): untyped = ## See top-level example. @@ -90,6 +89,7 @@ macro `?.`*(a: untyped): auto = macro `??.`*(a: untyped): Option = ## Same as `?.` but returns an `Option`. runnableExamples: + import std/options type Foo = ref object x1: ref int x2: int diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index af0978762..956204355 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -1,4 +1,5 @@ import std/wrapnils +from std/options import get, isSome proc checkNotZero(x: float): float = doAssert x != 0 From 0a4858dc59b1464d4057822d60e888fa4403223e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 Jun 2021 09:25:51 +0200 Subject: [PATCH 2688/4254] fixes #18220 (#18227) --- lib/pure/hashes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 46b4fc948..1c49b0317 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -509,7 +509,7 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = h = h !& ord(c) result = !$h -proc hash*[T: tuple | object | proc](x: T): Hash {.inline.} = +proc hash*[T: tuple | object | proc](x: T): Hash = ## Efficient `hash` overload. runnableExamples: # for `tuple|object`, `hash` must be defined for each component of `x`. From 8a9b20579e4afde6ccd515b9840ab2c68d0fe9e6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 10 Jun 2021 01:27:12 -0700 Subject: [PATCH 2689/4254] update changelog for wrapnils (#18228) --- changelog.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/changelog.md b/changelog.md index f141ea95a..cc6f826ee 100644 --- a/changelog.md +++ b/changelog.md @@ -285,9 +285,6 @@ - Added `std/strbasics` for high performance string operations. Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. - -- Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`. - - `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` and `$none(int)` to `"none(int)"` instead of `"None[int]"`. From 7bf0404dd86ff094ebd3d5b4a39bc4c52b442593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B6hlich=20A?= Date: Thu, 10 Jun 2021 14:28:00 +0200 Subject: [PATCH 2690/4254] #18216 make moveDir work across partitions on windows (#18223) * return false if AccessDeniedError in tryMoveFSObject - fixes #18216 * add moveDir & moveFile tests * rename `isMoveDir` parameter to `isDir` --- lib/pure/os.nim | 44 ++++++++++++++++++++++++------------------- tests/stdlib/tos.nim | 45 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index c48d0d84f..4dd5c8d8b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2009,28 +2009,32 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n if not tryRemoveFile(file): raiseOSError(osLastError(), file) -proc tryMoveFSObject(source, dest: string): bool {.noWeirdTarget.} = - ## Moves a file or directory from `source` to `dest`. +proc tryMoveFSObject(source, dest: string, isDir: bool): bool {.noWeirdTarget.} = + ## Moves a file (or directory if `isDir` is true) from `source` to `dest`. ## - ## Returns false in case of `EXDEV` error. + ## Returns false in case of `EXDEV` error or `AccessDeniedError` on windows (if `isDir` is true). ## In case of other errors `OSError` is raised. ## Returns true in case of success. when defined(windows): when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) - if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32 else: - if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) == 0'i32: raiseOSError(osLastError(), $(source, dest)) + result = moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32 else: - if c_rename(source, dest) != 0'i32: - let err = osLastError() - if err == EXDEV.OSErrorCode: - return false + result = c_rename(source, dest) == 0'i32 + + if not result: + let err = osLastError() + let isAccessDeniedError = + when defined(windows): + const AccessDeniedError = OSErrorCode(5) + isDir and err == AccessDeniedError else: - # see whether `strerror(errno)` is redundant with what raiseOSError already shows - raiseOSError(err, $(source, dest, strerror(errno))) - return true + err == EXDEV.OSErrorCode + if not isAccessDeniedError: + raiseOSError(err, $(source, dest)) proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect], noWeirdTarget.} = @@ -2051,8 +2055,10 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", ## * `removeFile proc <#removeFile,string>`_ ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ - if not tryMoveFSObject(source, dest): - when not defined(windows): + if not tryMoveFSObject(source, dest, isDir = false): + when defined(windows): + doAssert false + else: # Fallback to copy & del copyFile(source, dest, {cfSymlinkAsIs}) try: @@ -2060,6 +2066,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", except: discard tryRemoveFile(dest) raise + proc exitStatusLikeShell*(status: cint): cint = ## Converts exit code from `c_system` into a shell exit code. @@ -2614,11 +2621,10 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWei ## * `removeDir proc <#removeDir,string>`_ ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ ## * `createDir proc <#createDir,string>`_ - if not tryMoveFSObject(source, dest): - when not defined(windows): - # Fallback to copy & del - copyDir(source, dest) - removeDir(source) + if not tryMoveFSObject(source, dest, isDir = true): + # Fallback to copy & del + copyDir(source, dest) + removeDir(source) proc createHardlink*(src, dest: string) {.noWeirdTarget.} = ## Create a hard link at `dest` which points to the item specified diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index b9769d05c..a4f030dde 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -261,6 +261,51 @@ block fileOperations: removeDir(dname) +block: # moveFile + let tempDir = getTempDir() / "D20210609T151608" + createDir(tempDir) + defer: removeDir(tempDir) + + writeFile(tempDir / "a.txt", "") + moveFile(tempDir / "a.txt", tempDir / "b.txt") + doAssert not fileExists(tempDir / "a.txt") + doAssert fileExists(tempDir / "b.txt") + removeFile(tempDir / "b.txt") + + createDir(tempDir / "moveFile_test") + writeFile(tempDir / "moveFile_test/a.txt", "") + moveFile(tempDir / "moveFile_test/a.txt", tempDir / "moveFile_test/b.txt") + doAssert not fileExists(tempDir / "moveFile_test/a.txt") + doAssert fileExists(tempDir / "moveFile_test/b.txt") + removeDir(tempDir / "moveFile_test") + + createDir(tempDir / "moveFile_test") + writeFile(tempDir / "a.txt", "") + moveFile(tempDir / "a.txt", tempDir / "moveFile_test/b.txt") + doAssert not fileExists(tempDir / "a.txt") + doAssert fileExists(tempDir / "moveFile_test/b.txt") + removeDir(tempDir / "moveFile_test") + +block: # moveDir + let tempDir = getTempDir() / "D20210609T161443" + createDir(tempDir) + defer: removeDir(tempDir) + + createDir(tempDir / "moveDir_test") + moveDir(tempDir / "moveDir_test/", tempDir / "moveDir_test_dest") + doAssert not dirExists(tempDir / "moveDir_test") + doAssert dirExists(tempDir / "moveDir_test_dest") + removeDir(tempDir / "moveDir_test_dest") + + createDir(tempDir / "moveDir_test") + writeFile(tempDir / "moveDir_test/a.txt", "") + moveDir(tempDir / "moveDir_test", tempDir / "moveDir_test_dest") + doAssert not dirExists(tempDir / "moveDir_test") + doAssert not fileExists(tempDir / "moveDir_test/a.txt") + doAssert dirExists(tempDir / "moveDir_test_dest") + doAssert fileExists(tempDir / "moveDir_test_dest/a.txt") + removeDir(tempDir / "moveDir_test_dest") + import times block modificationTime: # Test get/set modification times From 3481ff6172a2e11c990cc67a7fd74a2f0a2445d2 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Thu, 10 Jun 2021 08:29:03 -0400 Subject: [PATCH 2691/4254] Update nims.rst to reflect that -d:release is now allowed in config.nims (#18221) `-d:release` and `-d:danger` started working in `config.nims` after https://github.com/nim-lang/Nim/commit/df429fa28772e077faa30dd6e3a701abf48c7669 . --- doc/nims.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/nims.rst b/doc/nims.rst index 5ae1d7baa..4141c3bdc 100644 --- a/doc/nims.rst +++ b/doc/nims.rst @@ -121,8 +121,8 @@ Here are few examples of using the `switch` proc: .. code-block:: nim # command-line: --opt:size switch("opt", "size") - # command-line: --define:foo or -d:foo - switch("define", "foo") + # command-line: --define:release or -d:release + switch("define", "release") # command-line: --forceBuild switch("forceBuild") @@ -132,13 +132,13 @@ above example can be rewritten as: .. code-block:: nim --opt:size - --define:foo + --define:release --forceBuild **Note**: In general, the *define* switches can also be set in -NimScripts using `switch` or `--`, as shown in above -examples. Only the `release` define (`-d:release`:option:) cannot be set -in NimScripts. +NimScripts using `switch` or `--`, as shown in above examples. Few +`define` switches such as `-d:strip`:option:, `-d:lto`:option: and +`-d:lto_incremental`:option: cannot be set in NimScripts. NimScript as a build tool From 2ea7287217ffe3ad6c3790ff1233845de2aedcf4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 Jun 2021 16:49:17 +0200 Subject: [PATCH 2692/4254] view types: spec changes (#18226) * view types: spec changes * Update doc/manual_experimental.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/manual_experimental.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- compiler/varpartitions.nim | 5 +++-- doc/manual_experimental.rst | 31 ++++++++++++++----------------- tests/views/tdont_mutate.nim | 9 ++++----- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 9cf1e38ad..04c7c629d 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -572,7 +572,7 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) = borrowFrom(c, dest.sym, src) elif dest.kind in {nkHiddenDeref, nkDerefExpr, nkBracketExpr}: case directViewType(dest[0].typ) - of mutableView: + of mutableView, immutableView: # we do not borrow, but we use the view to mutate the borrowed # location: let viewOrigin = pathExpr(dest, c.owner) @@ -580,12 +580,13 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) = let vid = variableId(c, viewOrigin.sym) if vid >= 0: c.s[vid].flags.incl viewDoesMutate - of immutableView: + #[of immutableView: if dest.kind == nkBracketExpr and dest[0].kind == nkHiddenDeref and mutableParameter(dest[0][0]): discard "remains a mutable location anyhow" else: localError(c.g.config, dest.info, "attempt to mutate a borrowed location from an immutable view") + ]# of noView: discard "nothing to do" proc containsPointer(t: PType): bool = diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 2c1043ecb..3157708da 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -475,8 +475,8 @@ Not nil annotation **Note:** This is an experimental feature. It can be enabled with `{.experimental: "notnil"}`. -All types for which `nil` is a valid value can be annotated with the `not -nil` annotation to exclude `nil` as a valid value: +All types for which `nil` is a valid value can be annotated with the +`not nil` annotation to exclude `nil` as a valid value: .. code-block:: nim {.experimental: "notnil"} @@ -1837,8 +1837,7 @@ with `--experimental:strictFuncs`:option:. A view type is a type that is or contains one of the following types: -- `var T` (mutable view into `T`) -- `lent T` (immutable view into `T`) +- `lent T` (view into `T`) - `openArray[T]` (pair of (pointer to array of `T`, size)) For example: @@ -1846,10 +1845,9 @@ For example: .. code-block:: nim type - View1 = var int - View2 = openArray[byte] - View3 = lent string - View4 = Table[openArray[char], int] + View1 = openArray[byte] + View2 = lent string + View3 = Table[openArray[char], int] Exceptions to this rule are types constructed via `ptr` or `proc`. @@ -1860,11 +1858,11 @@ For example, the following types are **not** view types: type NotView1 = proc (x: openArray[int]) NotView2 = ptr openArray[char] - NotView3 = ptr array[4, var int] + NotView3 = ptr array[4, lent int] -A *mutable* view type is a type that is or contains a `var T` type. -An *immutable* view type is a view type that is not a mutable view type. +The mutability aspect of a view type is not part of the type but part +of the locations it's derived from. More on this later. A *view* is a symbol (a let, var, const, etc.) that has a view type. @@ -1948,11 +1946,14 @@ details about how this is done for `var T`. A mutable view can borrow from a mutable location, an immutable view can borrow from both a mutable or an immutable location. +If a view borrows from a mutable location, the view can be used to update the +location. Otherwise it cannot be used for mutations. + The *duration* of a borrow is the span of commands beginning from the assignment to the view and ending with the last usage of the view. For the duration of the borrow operation, no mutations to the borrowed locations -may be performed except via the potentially mutable view that borrowed from the +may be performed except via the view that borrowed from the location. The borrowed location is said to be *sealed* during the borrow. .. code-block:: nim @@ -2064,11 +2065,7 @@ and `b` the location that is borrowed from. - The lifetime of `v` must not exceed `b`'s lifetime. Note: The lifetime of a parameter is the complete proc body. -- If `v` is a mutable view and `v` is used to actually mutate the - borrowed location, then `b` has to be a mutable location. - Note: If it is not actually used for mutation, borrowing a mutable view from an - immutable location is allowed! This allows for many important idioms and will be - justified in an upcoming RFC. +- If `v` is used for a mutation, `b` must be a mutable location too. - During `v`'s lifetime, `G(b)` can only be modified by `v` (and only if `v` is a mutable view). - If `v` is `result` then `b` has to be a location derived from the first diff --git a/tests/views/tdont_mutate.nim b/tests/views/tdont_mutate.nim index d243c7c7a..43acaaf71 100644 --- a/tests/views/tdont_mutate.nim +++ b/tests/views/tdont_mutate.nim @@ -9,8 +9,9 @@ import tables const Whitespace = {' ', '\t', '\n', '\r'} -proc split*(s: string, seps: set[char] = Whitespace, - maxsplit: int = -1): Table[int, openArray[char]] = +proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): Table[int, openArray[char]] #[tt.Error + 'result' borrows from the immutable location 's' and attempts to mutate it + ]# = var last = 0 var splits = maxsplit result = initTable[int, openArray[char]]() @@ -22,9 +23,7 @@ proc split*(s: string, seps: set[char] = Whitespace, if splits == 0: last = len(s) result[first] = toOpenArray(s, first, last-1) - result[first][0] = 'c' #[tt.Error - attempt to mutate a borrowed location from an immutable view - ]# + result[first][0] = 'c' if splits == 0: break dec(splits) From f65f760dee2d4e19be826c256be50d34f8873d48 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 Jun 2021 18:19:20 +0200 Subject: [PATCH 2693/4254] fixes #15884 (#18230) * fixes #15884 * micro optimization --- compiler/renderer.nim | 2 ++ compiler/sem.nim | 9 +++++++++ compiler/semexprs.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/varpartitions.nim | 6 +++++- 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 8bc3c3306..ac3f47948 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1238,6 +1238,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = putWithSpace(g, tkBind, "bind") gsub(g, n, 0) of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString: + if renderIds in g.flags: + putWithSpace(g, tkAddr, $n.kind) gsub(g, n, 0) of nkLambda: putWithSpace(g, tkProc, "proc") diff --git a/compiler/sem.nim b/compiler/sem.nim index 72b8dfe10..879f6efc9 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -100,6 +100,15 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: result = fitNodePostMatch(c, formal, result) +proc fitNodeForLocalVar(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = + let a = fitNode(c, formal, arg, info) + if formal.kind in {tyVar, tyLent}: + #classifyViewType(formal) != noView: + result = newNodeIT(nkHiddenAddr, a.info, formal) + result.add a + else: + result = a + proc inferWithMetatype(c: PContext, formal: PType, arg: PNode, coerceDistincts = false): PNode diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c839d04d9..ba8b93ae6 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1643,7 +1643,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le[0] - if (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView) and x.kind == nkSym and x.sym.kind == skResult: + if x.kind == nkSym and x.sym.kind == skResult and (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView): n[0] = x # 'result[]' --> 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a2401b376..8f87ce83c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -526,7 +526,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: # BUGFIX: ``fitNode`` is needed here! # check type compatibility between def.typ and typ - def = fitNode(c, typ, def, def.info) + def = fitNodeForLocalVar(c, typ, def, def.info) #changeType(def.skipConv, typ, check=true) else: typ = def.typ.skipTypes({tyStatic, tySink}).skipIntLit(c.idgen) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 04c7c629d..697dd2b1d 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -519,13 +519,17 @@ const proc isConstSym(s: PSym): bool = result = s.kind in {skConst, skLet} or isConstParam(s) +proc toString(n: PNode): string = + if n.kind == nkEmpty: result = "" + else: result = $n + proc borrowFrom(c: var Partitions; dest: PSym; src: PNode) = const url = "see https://nim-lang.github.io/Nim/manual_experimental.html#view-types-algorithm-path-expressions for details" let s = pathExpr(src, c.owner) if s == nil: - localError(c.g.config, src.info, "cannot borrow from " & $src & ", it is not a path expression; " & url) + localError(c.g.config, src.info, "cannot borrow from " & src.toString & ", it is not a path expression; " & url) elif s.kind == nkSym: if dest.kind == skResult: if s.sym.kind != skParam or s.sym.position != 0: From 6b97889f44d06f6649b6547a4ffdb18b94d6e578 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 11 Jun 2021 00:26:58 +0800 Subject: [PATCH 2694/4254] fix #9437(fix `re.replace` wrong behaviour) (#17546) * fix nim js cmp fails at CT * fix --- lib/impure/re.nim | 20 ++++++++++++++++++-- tests/stdlib/tre.nim | 9 ++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 40860cc88..78ea7b002 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -199,6 +199,18 @@ proc findBounds*(s: string, pattern: Regex, ## `(-1,0)` is returned. result = findBounds(cstring(s), pattern, matches, start, s.len) +proc findBoundsImpl(buf: cstring, pattern: Regex, + start = 0, bufSize = 0, flags = 0): tuple[first, last: int] = + var rtarray = initRtArray[cint](3) + let rawMatches = rtarray.getRawData + let res = pcre.exec(pattern.h, pattern.e, buf, bufSize.cint, start.cint, flags.int32, + cast[ptr cint](rawMatches), 3) + + if res < 0'i32: + result = (-1, 0) + else: + result = (int(rawMatches[0]), int(rawMatches[1]-1)) + proc findBounds*(buf: cstring, pattern: Regex, start = 0, bufSize: int): tuple[first, last: int] = ## returns the `first` and `last` position of `pattern` in `buf`, @@ -433,12 +445,16 @@ proc replace*(s: string, sub: Regex, by = ""): string = doAssert "var1=key; var2=key2".replace(re"(\w+)=(\w+)", "?") == "?; ?" result = "" var prev = 0 + var flags = int32(0) while prev < s.len: - var match = findBounds(s, sub, prev) + var match = findBoundsImpl(s.cstring, sub, prev, s.len, flags) + flags = 0 if match.first < 0: break add(result, substr(s, prev, match.first-1)) add(result, by) - if match.last + 1 == prev: break + if match.first > match.last: + # 0-len match + flags = pcre.NOTEMPTY_ATSTART prev = match.last + 1 add(result, substr(s, prev)) diff --git a/tests/stdlib/tre.nim b/tests/stdlib/tre.nim index ea1b5af32..2857c6c9e 100644 --- a/tests/stdlib/tre.nim +++ b/tests/stdlib/tre.nim @@ -99,10 +99,13 @@ proc testAll() = accum.add($x) doAssert(accum == @["a","b","c"]) - block: - # bug #9306 + block: # bug #9306 doAssert replace("bar", re"^", "foo") == "foobar" - doAssert replace("foo", re"", "-") == "-foo" doAssert replace("foo", re"$", "bar") == "foobar" + + block: # bug #9437 + doAssert replace("foo", re"", "-") == "-f-o-o-" + doAssert replace("ooo", re"o", "-") == "---" + testAll() From c64d9176190b3b691391f1645873dd4ca5b09933 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 10 Jun 2021 23:36:06 -0700 Subject: [PATCH 2695/4254] handle tyUserTypeClassInst in addDeclaredLoc (#18236) --- compiler/astmsgs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim index 5be8dc38f..924f0ddea 100644 --- a/compiler/astmsgs.nim +++ b/compiler/astmsgs.nim @@ -13,7 +13,7 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = # xxx figure out how to resolve `tyGenericParam`, e.g. for # proc fn[T](a: T, b: T) = discard # fn(1.1, "a") - let typ = typ.skipTypes(abstractInst + {tyStatic} - {tyRange}) + let typ = typ.skipTypes(abstractInst + {tyStatic, tyUserTypeClassInst} - {tyRange}) result.add " [$1" % typ.kind.toHumanStr if typ.sym != nil: result.add " declared in " & toFileLineCol(conf, typ.sym.info) From 57609902c4438da2bcc156296128591a9906e922 Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 11 Jun 2021 10:07:23 +0200 Subject: [PATCH 2696/4254] use more meaningful name than "workaround14447" (#18237) --- compiler/lambdalifting.nim | 2 +- lib/system/iterators.nim | 2 +- testament/important_packages.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6f43649a1..c555cedfe 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -292,7 +292,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = if illegalCapture(s): localError(g.config, n.info, ("'$1' is of type <$2> which cannot be captured as it would violate memory" & - " safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") % + " safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases") % [s.name.s, typeToString(s.typ), g.config$s.info]) elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags): localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 0f79970b8..f23f7aa11 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -1,4 +1,4 @@ -when defined(nimHasLentIterators) and not defined(nimWorkaround14447): +when defined(nimHasLentIterators) and not defined(nimNoLentIterators): template lent2(T): untyped = lent T else: template lent2(T): untyped = T diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 975dd63ad..3d3c340eb 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -156,5 +156,5 @@ pkg "winim", allowFailure = true pkg "with" pkg "ws" pkg "yaml", "nim build" -pkg "zero_functional", "nim c -r -d:nimWorkaround14447 test.nim" +pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim" pkg "zippy" From 2ca6169ba10dca704712b59339a24208e30e79ac Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 11 Jun 2021 11:09:00 +0200 Subject: [PATCH 2697/4254] added a test case ensuring exception inference continues to work --- tests/exception/texception_inference.nim | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/exception/texception_inference.nim diff --git a/tests/exception/texception_inference.nim b/tests/exception/texception_inference.nim new file mode 100644 index 000000000..7dd01cca1 --- /dev/null +++ b/tests/exception/texception_inference.nim @@ -0,0 +1,32 @@ +discard """ + output: '''good''' + cmd: "nim c --gc:orc -d:release $file" +""" + +type + Raising[T, E] = object + +proc foo[T, Errors](x: proc (x: Raising[T, Errors])) {.raises: Errors.} = + discard + +proc callback(x: Raising[int, ValueError]) = + echo "callback" + +proc xy() {.raises: [ValueError].} = + foo callback + +proc x[E]() {.raises: [E, IOError].} = + raise newException(E, "text here") + +try: + x[ValueError]() +except ValueError: + echo "good" + +proc callback2(x: Raising[int, IOError]) = + discard + +proc foo2[T, OtherErrors](x: proc(x: Raising[T, OtherErrors])) {.raises: [ValueError, OtherErrors].} = + discard + +foo2 callback2 From 897e50d5fe274850d4772612a90b325e33cca8a2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 12 Jun 2021 12:35:12 -0700 Subject: [PATCH 2698/4254] getType now works with tyInferred (arising from concepts); refs #18220 (#18241) * getType now works with tyInferred (concepts); refs #18220 * avoid cast * add more docs --- compiler/vmdeps.nim | 2 +- tests/macros/tgettype.nim | 100 +++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index b67e2e48a..1afda14b0 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -289,7 +289,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyNot: result = mapTypeToBracket("not", mNot, t, info) of tyIterable: result = mapTypeToBracket("iterable", mIterableType, t, info) of tyAnything: result = atomicType("anything", mNone) - of tyInferred: assert false + of tyInferred: result = mapTypeToAstX(cache, t.lastSon, info, idgen, inst, allowRecursion) of tyStatic, tyFromExpr: if inst: if t.n != nil: result = t.n.copyTree diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim index bd70a1c30..d91efe1fe 100644 --- a/tests/macros/tgettype.nim +++ b/tests/macros/tgettype.nim @@ -1,29 +1,85 @@ -discard """ -output: ''' -(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password"))) -(BracketExpr (Sym "typeDesc") (Sym "User")) -''' -""" -import macros +import std/macros +import stdtest/testutils -type - Model = object of RootObj - User = object of Model - name : string - password : string +# getType -macro testUser: string = - result = newLit(User.getType.lispRepr) +block: + type + Model = object of RootObj + User = object of Model + name : string + password : string -macro testGeneric(T: typedesc[Model]): string= - result = newLit(T.getType.lispRepr) + macro testUser: string = + result = newLit(User.getType.lispRepr) -echo testUser -echo User.testGeneric + macro testGeneric(T: typedesc[Model]): string= + result = newLit(T.getType.lispRepr) -macro assertVoid(e: typed): untyped = - assert(getTypeInst(e).typeKind == ntyVoid) + doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))""" + doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))""" -proc voidProc() = discard + macro assertVoid(e: typed): untyped = + assert(getTypeInst(e).typeKind == ntyVoid) -assertVoid voidProc() + proc voidProc() = discard + + assertVoid voidProc() + +block: + # refs #18220; not an actual solution (yet) but at least shows what's currently + # possible + + type Callable1[R, T, U] = concept fn + fn(default(T)) is R + fn is U + + # note that typetraits.arity doesn't work + macro arity(a: typed): int = + # number of params + # this is not production code! + let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false`` + newLit a2.len - 1 + + type Callable2[R, T, U] = concept fn + fn(default(T)) is R + fn is U + arity(U) == 2 + + proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R = + let fn = U(fn) + # `cast[U](fn)` would also work; + # this is currently needed otherwise, sigmatch errors with: + # Error: attempting to call routine: 'fn' + # found 'fn' [param declared in tgettype.nim(53, 28)] + # this can be fixed in future work + fn(a) + + proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R = + let fn = U(fn) + fn(a) + + proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1") + proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2") + proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3") + proc fn4(a: int): string {.inline.} = $(a, "fn4") + proc fn5(a: int): string = $(a, "fn5") + + assertAll: + # Callable1 + 1.map1(fn1) == """(1, 'x', "fn1")""" + 1.map1(fn2) == """(1, "zoo", "fn2")""" + 1.map1(fn3) == """(1, "zoo", "fn3")""" + # fn3's optional param is not honored, because fn3 and fn2 yield same + # generic instantiation; this is a caveat with this approach + # There are several possible ways to improve things in future work. + 1.map1(fn4) == """(1, "fn4")""" + 1.map1(fn5) == """(1, "fn5")""" + + # Callable2; prevents passing procs with optional params to avoid above + # mentioned caveat, but more restrictive + not compiles(1.map2(fn1)) + not compiles(1.map2(fn2)) + not compiles(1.map2(fn3)) + 1.map2(fn4) == """(1, "fn4")""" + 1.map2(fn5) == """(1, "fn5")""" From c871e22da2ad8f9caf82fdba43fccb7230d726e1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 12 Jun 2021 22:32:47 -0700 Subject: [PATCH 2699/4254] fix #7717 roundtrip float to string; fix `parseFloat` for js (#18248) * refs #7717 roundtrip float to string * make parseFloat more correct * improve float tests * improve float tests * cleanup --- lib/system/jssys.nim | 99 +++++++++++++++++++---------------------- tests/float/tfloat6.nim | 28 ------------ tests/float/tfloats.nim | 84 ++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 81 deletions(-) delete mode 100644 tests/float/tfloat6.nim create mode 100644 tests/float/tfloats.nim diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 371cb7962..7cb5652c5 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -716,19 +716,23 @@ proc tenToThePowerOf(b: int): BiggestFloat = const IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} -# XXX use JS's native way here -proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {. - compilerproc.} = - var - esign = 1.0 - sign = 1.0 - i = start - exponent: int - flags: int - number = 0.0 + +proc parseFloatNative(a: string): float = + let a2 = a.cstring + asm """ + `result` = Number(`a2`); + """ + +#[ +xxx how come code like this doesn't give IndexDefect ? +let z = s[10000] == 'a' +]# +proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int {.compilerproc.} = + var sign: bool + var i = start if s[i] == '+': inc(i) elif s[i] == '-': - sign = -1.0 + sign = true inc(i) if s[i] == 'N' or s[i] == 'n': if s[i+1] == 'A' or s[i+1] == 'a': @@ -741,51 +745,40 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int { if s[i+1] == 'N' or s[i+1] == 'n': if s[i+2] == 'F' or s[i+2] == 'f': if s[i+3] notin IdentChars: - number = Inf*sign + number = if sign: -Inf else: Inf return i+3 - start return 0 - while s[i] in {'0'..'9'}: - # Read integer part - flags = flags or 1 - number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) - inc(i) - while s[i] == '_': inc(i) - # Decimal? - if s[i] == '.': - var hd = 1.0 - inc(i) - while s[i] in {'0'..'9'}: - # Read fractional part - flags = flags or 2 - number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) - hd = hd * 10.0 - inc(i) - while s[i] == '_': inc(i) - number = number / hd # this complicated way preserves precision - # Again, read integer and fractional part - if flags == 0: return 0 - # Exponent? - if s[i] in {'e', 'E'}: - inc(i) - if s[i] == '+': - inc(i) - elif s[i] == '-': - esign = -1.0 - inc(i) - if s[i] notin {'0'..'9'}: - return 0 - while s[i] in {'0'..'9'}: - exponent = exponent * 10 + ord(s[i]) - ord('0') - inc(i) - while s[i] == '_': inc(i) - # Calculate Exponent - let hd = tenToThePowerOf(exponent) - if esign > 0.0: number = number * hd - else: number = number / hd - # evaluate sign - number = number * sign - result = i - start + var buf: string + # we could also use an `array[char, N]` buffer to avoid reallocs, or + # use a 2-pass algorithm that first computes the length. + if sign: buf.add '-' + template addInc = + buf.add s[i] + inc(i) + template eatUnderscores = + while s[i] == '_': inc(i) + while s[i] in {'0'..'9'}: # Read integer part + buf.add s[i] + inc(i) + eatUnderscores() + if s[i] == '.': # Decimal? + addInc() + while s[i] in {'0'..'9'}: # Read fractional part + addInc() + eatUnderscores() + # Again, read integer and fractional part + if buf.len == ord(sign): return 0 + if s[i] in {'e', 'E'}: # Exponent? + addInc() + if s[i] == '+': inc(i) + elif s[i] == '-': addInc() + if s[i] notin {'0'..'9'}: return 0 + while s[i] in {'0'..'9'}: + addInc() + eatUnderscores() + number = parseFloatNative(buf) + result = i - start # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce # 'Math.trunc' for Nim's ``div`` and ``mod`` operators: diff --git a/tests/float/tfloat6.nim b/tests/float/tfloat6.nim deleted file mode 100644 index fa8fc9da8..000000000 --- a/tests/float/tfloat6.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - output: ''' -0.000001 : 0.000001 -0.000001 : 0.000001 -0.001 : 0.001 -0.000001 : 0.000001 -0.000001 : 0.000001 -10.000001 : 10.000001 -100.000001 : 100.000001 -''' - disabled: "windows" -""" - -import strutils - -echo "0.00_0001".parseFloat(), " : ", 1E-6 -echo "0.00__00_01".parseFloat(), " : ", 1E-6 -echo "0.0_01".parseFloat(), " : ", 0.001 -echo "0.00_000_1".parseFloat(), " : ", 1E-6 -echo "0.00000_1".parseFloat(), " : ", 1E-6 - -echo "1_0.00_0001".parseFloat(), " : ", 10.000001 -echo "1__00.00_0001".parseFloat(), " : ", 1_00.000001 - -# bug #18148 - -var a = 1.1'f32 -doAssert $a == "1.1", $a # fails diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim new file mode 100644 index 000000000..406ddb6d9 --- /dev/null +++ b/tests/float/tfloats.nim @@ -0,0 +1,84 @@ +discard """ + targets: "c cpp js" +""" +# disabled: "windows" + +#[ +xxx merge all or most float tests into this file +]# + +import std/[fenv, math, strutils] + +proc equalsOrNaNs(a, b: float): bool = + if isNaN(a): isNaN(b) + elif a == 0: + b == 0 and signbit(a) == signbit(b) + else: + a == b + +template reject(a) = + doAssertRaises(ValueError): discard parseFloat(a) + +template main = + block: + proc test(a: string, b: float) = + let a2 = a.parseFloat + doAssert equalsOrNaNs(a2, b), $(a, a2, b) + test "0.00_0001", 1E-6 + test "0.00__00_01", 1E-6 + test "0.0_01", 0.001 + test "0.00_000_1", 1E-6 + test "0.00000_1", 1E-6 + test "1_0.00_0001", 10.000001 + test "1__00.00_0001", 1_00.000001 + test "inf", Inf + test "-inf", -Inf + test "-Inf", -Inf + test "-INF", -Inf + test "NaN", NaN + test "-nan", NaN + test ".1", 0.1 + test "-.1", -0.1 + test "-0", -0.0 + when false: # pending bug #18246 + test "-0", -0.0 + test ".1e-1", 0.1e-1 + test "0_1_2_3.0_1_2_3E+0_1_2", 123.0123e12 + test "0_1_2.e-0", 12e0 + test "0_1_2e-0", 12e0 + test "-0e0", -0.0 + test "-0e-0", -0.0 + + reject "a" + reject "" + reject "e1" + reject "infa" + reject "infe1" + reject "_" + reject "1e" + + when false: # gray area; these numbers should probably be invalid + reject "1_" + reject "1_.0" + reject "1.0_" + + block: # bug #18148 + var a = 1.1'f32 + doAssert $a == "1.1", $a # was failing + + block: # bug #7717 + proc test(f: float) = + let f2 = $f + let f3 = parseFloat(f2) + doAssert equalsOrNaNs(f, f3), $(f, f2, f3) + + test 1.0 + epsilon(float64) + test 1000000.0000000123 + test log2(100000.0) + test maximumPositiveValue(float32) + test maximumPositiveValue(float64) + test minimumPositiveValue(float32) + test minimumPositiveValue(float64) + +static: main() +main() From a266c549212d1d6e09dbfa01344edbca8b2f6222 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 13 Jun 2021 16:50:04 +0100 Subject: [PATCH 2700/4254] Improve httpClient docs on SSL cert verification (#15201) * Improve httpClient docs on SSL cert verification Cert verification is enabled by default after CVE-2021-29495 * Update httpclient.nim Co-authored-by: Dominik Picheta --- lib/pure/httpclient.nim | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 0dbf8a045..2f9f1913f 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -115,7 +115,7 @@ ## ## SSL/TLS support ## =============== -## This requires the OpenSSL library, fortunately it's widely used and installed +## This requires the OpenSSL library. Fortunately it's widely used and installed ## on many operating systems. httpclient will use SSL automatically if you give ## any of the functions a url with the `https` schema, for example: ## `https://github.com/`. @@ -123,12 +123,25 @@ ## You will also have to compile with `ssl` defined like so: ## `nim c -d:ssl ...`. ## -## Certificate validation is NOT performed by default. -## This will change in the future. +## Certificate validation is performed by default. ## ## A set of directories and files from the `ssl_certs `_ ## module are scanned to locate CA certificates. ## +## Example of setting SSL verification parameters in a new client: +## +## .. code-block:: Nim +## import httpclient +## var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer)) +## +## There are three options for verify mode: +## +## * ``CVerifyNone``: certificates are not verified; +## * ``CVerifyPeer``: certificates are verified; +## * ``CVerifyPeerUseEnvVars``: certificates are verified and the optional +## environment variables SSL_CERT_FILE and SSL_CERT_DIR are also used to +## locate certificates +## ## See `newContext `_ to tweak or disable certificate validation. ## ## Timeouts From 065243dc5988fbfcbed8236e19a588b98d63b199 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 13 Jun 2021 23:21:18 -0700 Subject: [PATCH 2701/4254] followup #17777: declaredloc field error msgs now work with generics (#18259) * followup #17777: declaredloc field error msgs now work with generics * fix tests * cleanup --- compiler/astmsgs.nim | 5 ++++ compiler/semcall.nim | 5 ++-- tests/errmsgs/tundeclared_field.nim | 40 ++++++++++++++++++----------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim index 924f0ddea..90bdce7cf 100644 --- a/compiler/astmsgs.nim +++ b/compiler/astmsgs.nim @@ -2,6 +2,11 @@ import std/strutils import options, ast, msgs +proc typSym*(t: PType): PSym = + result = t.sym + if result == nil and t.kind == tyGenericInst: # this might need to be refined + result = t[0].sym + proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) = result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)] diff --git a/compiler/semcall.nim b/compiler/semcall.nim index facaa89f7..b56a1dbac 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -326,7 +326,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string = let ident = considerQuotedIdent(c, f, n).s if {nfDotField, nfExplicitCall} * n.flags == {nfDotField}: - let sym = n[1].typ.sym + let sym = n[1].typ.typSym var typeHint = "" if sym == nil: # Perhaps we're in a `compiles(foo.bar)` expression, or @@ -337,7 +337,8 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string = discard else: typeHint = " for type " & getProcHeader(c.config, sym) - result = errUndeclaredField % ident & typeHint & " " & result + let suffix = if result.len > 0: " " & result else: "" + result = errUndeclaredField % ident & typeHint & suffix else: if result.len == 0: result = errUndeclaredRoutine % ident else: result = errBadRoutine % [ident, result] diff --git a/tests/errmsgs/tundeclared_field.nim b/tests/errmsgs/tundeclared_field.nim index 2b274ae58..5668050e0 100644 --- a/tests/errmsgs/tundeclared_field.nim +++ b/tests/errmsgs/tundeclared_field.nim @@ -2,38 +2,48 @@ discard """ cmd: '''nim check --hints:off $file''' action: reject nimout: ''' -tundeclared_field.nim(25, 12) Error: undeclared field: 'bad' for type tundeclared_field.A [type declared in tundeclared_field.nim(22, 8)] -tundeclared_field.nim(30, 16) Error: undeclared field: 'bad' for type tundeclared_field.A [type declared in tundeclared_field.nim(28, 8)] -tundeclared_field.nim(36, 4) Error: undeclared field: 'bad' for type tundeclared_field.A [type declared in tundeclared_field.nim(33, 8)] -tundeclared_field.nim(40, 13) Error: cannot instantiate Foo [type declared in tundeclared_field.nim(39, 8)] +tundeclared_field.nim(25, 12) Error: undeclared field: 'bad1' for type tundeclared_field.A [type declared in tundeclared_field.nim(22, 8)] +tundeclared_field.nim(30, 17) Error: undeclared field: 'bad2' for type tundeclared_field.A [type declared in tundeclared_field.nim(28, 8)] +tundeclared_field.nim(36, 4) Error: undeclared field: 'bad3' for type tundeclared_field.A [type declared in tundeclared_field.nim(33, 8)] +tundeclared_field.nim(42, 12) Error: undeclared field: 'bad4' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] +tundeclared_field.nim(43, 4) Error: undeclared field: 'bad5' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] +tundeclared_field.nim(44, 23) Error: undeclared field: 'bad6' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] +tundeclared_field.nim(46, 19) Error: undeclared field: 'bad7' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)] +tundeclared_field.nim(50, 13) Error: cannot instantiate Foo [type declared in tundeclared_field.nim(49, 8)] ''' """ - - - - - - - - +#[ +xxx in future work, generic instantiations (e.g. `B[int]`) should be shown with their instantiation instead of `tundeclared_field.B`, +maybe using TPreferedDesc.preferResolved or preferMixed +]# # line 20 block: type A = object a0: int var a: A - discard a.bad + discard a.bad1 block: type A = object a0: int - var a = A(bad: 0) + var a = A(bad2: 0) block: type A = object a0: int var a: A - a.bad = 0 + a.bad3 = 0 + +block: + type B[T] = object + b0: int + var b: B[int] + discard b.bad4 + b.bad5 = 0 + var b2 = B[int](bad6: 0) + type Bi = B[int] + var b3 = Bi(bad7: 0) block: type Foo[T: SomeInteger] = object From e1e8af535ec195e5749dffa728add95770e5cbd7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 13 Jun 2021 23:51:40 -0700 Subject: [PATCH 2702/4254] merge BuildMode into SuccessX, remove code duplication w drnim, add useful info to successx, add gc to compilesettings (#18252) * merge BuildMode into SuccessX, add more info * refactor duplicated with drnim * fixup * address comment --- compiler/lineinfos.nim | 7 +++--- compiler/main.nim | 40 ++++++---------------------------- compiler/msgs.nim | 43 +++++++++++++++++++++++++++++++++---- compiler/options.nim | 13 +++++++++-- compiler/vmops.nim | 1 + doc/nimc.rst | 1 - drnim/drnim.nim | 19 +--------------- lib/std/compilesettings.nim | 1 + testament/testament.nim | 3 +-- tests/misc/trunner.nim | 2 +- 10 files changed, 64 insertions(+), 66 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index bf81aed02..da0a8d623 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -65,7 +65,7 @@ type warnFileChanged = "FileChanged", warnUser = "User", - hintSuccess = "Success", hintSuccessX = "SuccessX", hintBuildMode = "BuildMode", + hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", @@ -145,8 +145,7 @@ const warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` - hintSuccessX: "$loc lines; ${sec}s; $mem; proj: $project; out: $output", - hintBuildMode: "$1", + hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output", hintCC: "CC: $1", hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", @@ -200,7 +199,7 @@ proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance} - result[0] = result[1] - {hintSuccessX, hintBuildMode, hintSuccess, hintConf, + result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC} const diff --git a/compiler/main.nim b/compiler/main.nim index 71e549ab8..7824e8cb2 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -13,13 +13,14 @@ when not defined(nimcore): {.error: "nimcore MUST be defined for Nim's core tooling".} import - llstream, strutils, os, ast, lexer, syntaxes, options, msgs, - condsyms, times, + std/[strutils, os, times, tables, sha1, with, json], + llstream, ast, lexer, syntaxes, options, msgs, + condsyms, sem, idents, passes, extccomp, - cgen, json, nversion, + cgen, nversion, platform, nimconf, passaux, depends, vm, modules, - modulegraphs, tables, lineinfos, pathutils, vmprofiler, std/[sha1, with] + modulegraphs, lineinfos, pathutils, vmprofiler import ic / [cbackend, integrity, navigator] from ic / ic import rodViewer @@ -387,38 +388,9 @@ proc mainCommand*(graph: ModuleGraph) = rawMessage(conf, errGenerated, "invalid command: " & conf.command) if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}: - # D20210419T170230:here - let mem = - when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" - else: formatSize(getTotalMem()) & " totmem" - let loc = $conf.linesCompiled - let build = if isDefined(conf, "danger"): "Dangerous Release build" - elif isDefined(conf, "release"): "Release build" - else: "***SLOW, DEBUG BUILD***; -d:release makes code run faster." - let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) - let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName - # xxx honor conf.filenameOption more accurately - var output: string - if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonscript: - output = $conf.jsonBuildFile - elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonscript} + cmdDocLike + cmdBackends: - # for some cmd we expect a valid absOutFile - output = "unknownOutput" - else: - output = $conf.absOutFile - if conf.filenameOption != foAbs: output = output.AbsoluteFile.extractFilename - # xxx honor filenameOption more accurately if optProfileVM in conf.globalOptions: echo conf.dump(conf.vmProfileData) - rawMessage(conf, hintSuccessX, [ - "loc", loc, - "sec", sec, - "mem", mem, - "project", project, - "output", output, - ]) - if conf.cmd in cmdBackends: - rawMessage(conf, hintBuildMode, build) + genSuccessX(conf) when PrintRopeCacheStats: echo "rope cache stats: " diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 053b5c928..6b005be3d 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -8,10 +8,9 @@ # import - options, strutils, os, tables, ropes, terminal, macros, - lineinfos, pathutils -import std/private/miscdollars -import strutils2 + std/[strutils, os, tables, terminal, macros, times], + std/private/miscdollars, + options, ropes, lineinfos, pathutils, strutils2 type InstantiationInfo* = typeof(instantiationInfo()) template instLoc*(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) @@ -656,3 +655,39 @@ proc uniqueModuleName*(conf: ConfigRef; fid: FileIndex): string = # We mangle upper letters and digits too so that there cannot # be clashes with our special meanings of 'Z' and 'O' result.addInt ord(c) + +proc genSuccessX*(conf: ConfigRef) = + let mem = + when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" + else: formatSize(getTotalMem()) & " totmem" + let loc = $conf.linesCompiled + var build = "" + if conf.cmd in cmdBackends: + build.add "gc: $#; " % $conf.selectedGC + if optThreads in conf.globalOptions: build.add "threads: on; " + build.add "opt: " + if optOptimizeSpeed in conf.options: build.add "speed" + elif optOptimizeSize in conf.options: build.add "size" + else: build.add "none (DEBUG BUILD, `-d:release` generates faster code)" + # pending https://github.com/timotheecour/Nim/issues/752, point to optimization.html + let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) + let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName + # xxx honor conf.filenameOption more accurately + var output: string + if optCompileOnly in conf.globalOptions and conf.cmd != cmdJsonscript: + output = $conf.jsonBuildFile + elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonscript} + cmdDocLike + cmdBackends: + # for some cmd we expect a valid absOutFile + output = "unknownOutput" + else: + output = $conf.absOutFile + if conf.filenameOption != foAbs: output = output.AbsoluteFile.extractFilename + # xxx honor filenameOption more accurately + rawMessage(conf, hintSuccessX, [ + "build", build, + "loc", loc, + "sec", sec, + "mem", mem, + "project", project, + "output", output, + ]) diff --git a/compiler/options.nim b/compiler/options.nim index afe8b0fc7..1851770d9 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -167,8 +167,17 @@ const type TStringSeq* = seq[string] TGCMode* = enum # the selected GC - gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc, - gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo + gcUnselected = "unselected" + gcNone = "none" + gcBoehm = "boehm" + gcRegions = "regions" + gcArc = "arc" + gcOrc = "orc" + gcMarkAndSweep = "markAndSweep" + gcHooks = "hooks" + gcRefc = "refc" + gcV2 = "v2" + gcGo = "go" # gcRefc and the GCs that follow it use a write barrier, # as far as usesWriteBarrier() is concerned diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 04356fc76..85729fd59 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -136,6 +136,7 @@ when defined(nimHasInvariant): of ccompilerPath: result = conf.cCompilerPath of backend: result = $conf.backend of libPath: result = conf.libpath.string + of gc: result = $conf.selectedGC proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = diff --git a/doc/nimc.rst b/doc/nimc.rst index e467a33af..2b9f33cb5 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -108,7 +108,6 @@ Source The source line that triggered a diagnostic message. StackTrace Success, SuccessX Successful compilation of a library or a binary. -BuildMode Kind of build: debug, release, danger User UserRaw XDeclaredButNotUsed Unused symbols in the code. diff --git a/drnim/drnim.nim b/drnim/drnim.nim index 1eded533d..eb0d89aa2 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1205,24 +1205,7 @@ proc mainCommand(graph: ModuleGraph) = registerPass graph, semPass compileProject(graph) if conf.errorCounter == 0: - # xxx deduplicate with D20210419T170230 - let mem = - when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem" - else: formatSize(getTotalMem()) & " totmem" - let loc = $conf.linesCompiled - let build = if isDefined(conf, "danger"): "Dangerous Release build" - elif isDefined(conf, "release"): "Release build" - else: "***SLOW, DEBUG BUILD***; -d:release makes code run faster." - let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) - let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName - rawMessage(conf, hintSuccessX, [ - "loc", loc, - "sec", sec, - "mem", mem, - "project", project, - "output", "" - ]) - rawMessage(conf, hintBuildMode, build) + genSuccessX(graph.config) proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim index 273cfdb57..e1ffc954a 100644 --- a/lib/std/compilesettings.nim +++ b/lib/std/compilesettings.nim @@ -32,6 +32,7 @@ type backend ## the backend (eg: c|cpp|objc|js); both `nim doc --backend:js` ## and `nim js` would imply backend=js libPath ## the absolute path to the stdlib library, i.e. nim's `--lib`, since 1.5.1 + gc ## gc selected MultipleValueSetting* {.pure.} = enum ## \ ## settings resulting in a seq of string values diff --git a/testament/testament.nim b/testament/testament.nim index 789c987c0..ab6620c84 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -108,8 +108,7 @@ proc isSuccess(input: string): bool = # that may appear in user config (eg: `--filenames`). # Passing `XDG_CONFIG_HOME= testament args...` can be used to ignore user config # stored in XDG_CONFIG_HOME, refs https://wiki.archlinux.org/index.php/XDG_Base_Directory - input.startsWith("Hint: ") and - (input.endsWith("[SuccessX]") or input.endsWith("[BuildMode]")) + input.startsWith("Hint: ") and input.endsWith("[SuccessX]") proc getFileDir(filename: string): string = result = filename.splitFile().dir diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index b6b302836..f2ea1d040 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -23,7 +23,7 @@ proc isDots(a: string): bool = a.startsWith(".") and a.strip(chars = {'.'}) == "" const - defaultHintsOff = "--hint:successx:off --hint:buildmode:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" + defaultHintsOff = "--hint:successx:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" # useful when you want to turn only some hints on, and some common ones off. # pending https://github.com/timotheecour/Nim/issues/453, simplify to: `--hints:off` nim = getCurrentCompilerExe() From 488acd9d077e8179d35d665ac0591c456bfa93aa Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 14 Jun 2021 00:21:33 -0700 Subject: [PATCH 2703/4254] fixes #18235 - proc annotation type macro sym leak (#18249) * fixes #18235 - proc annotation type macro sym leak - also fixed a typo - proc annotations guard symbol exports with shadow scopes - symbol handling is shadow scope aware * test for exporting an existing unexported sym this one is for my homie alaviss. * Special handling not needed in semProcAnnotation * Testcasing * [skip ci] clean-up and add some more comments * [skip ci] rm trailing whitespace Co-authored-by: Clyybber --- compiler/lookups.nim | 27 +++++++++++++++++++++----- compiler/semstmts.nim | 8 ++++---- tests/macros/m18235.nim | 42 +++++++++++++++++++++++++++++++++++++++++ tests/macros/t18235.nim | 18 ++++++++++++++++++ 4 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 tests/macros/m18235.nim create mode 100644 tests/macros/t18235.nim diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 64476d816..a21e35ddc 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -314,6 +314,7 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) = from ic / ic import addHidden proc addInterfaceDeclAux*(c: PContext, sym: PSym, forceExport = false) = + ## adds symbol to the module for either private or public access. if sfExported in sym.flags or forceExport: # add to interface: if c.module != nil: exportSym(c, sym) @@ -324,10 +325,15 @@ proc addInterfaceDeclAux*(c: PContext, sym: PSym, forceExport = false) = addHidden(c.encoder, c.packedRepr, sym) proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) = + ## adds a symbol on the scope and the interface if appropriate addDeclAt(c, scope, sym) - addInterfaceDeclAux(c, sym) + if not scope.isShadowScope: + # adding into a non-shadow scope, we need to handle exports, etc + addInterfaceDeclAux(c, sym) proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) = + ## adds an symbol to the given scope, will check for and raise errors if it's + ## a redefinition as opposed to an overload. if fn.kind notin OverloadableSyms: internalError(c.config, fn.info, "addOverloadableSymAt") return @@ -338,24 +344,35 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) = scope.addSym(fn) proc addInterfaceDecl*(c: PContext, sym: PSym) = - # it adds the symbol to the interface if appropriate + ## adds a decl and the interface if appropriate addDecl(c, sym) - addInterfaceDeclAux(c, sym) + if not c.currentScope.isShadowScope: + addInterfaceDeclAux(c, sym) proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) = - # it adds the symbol to the interface if appropriate + ## adds an overloadable symbol on the scope and the interface if appropriate addOverloadableSymAt(c, scope, sym) - addInterfaceDeclAux(c, sym) + if not scope.isShadowScope: + addInterfaceDeclAux(c, sym) proc openShadowScope*(c: PContext) = + ## opens a shadow scope, just like any other scope except the depth is the + ## same as the parent -- see `isShadowScope`. c.currentScope = PScope(parent: c.currentScope, symbols: newStrTable(), depthLevel: c.scopeDepth) proc closeShadowScope*(c: PContext) = + ## closes the shadow scope, but doesn't merge any of the symbols c.closeScope proc mergeShadowScope*(c: PContext) = + ## close the existing scope and merge in all defined symbols, this will also + ## trigger any export related code if this is into a non-shadow scope. + ## + ## Merges: + ## shadow -> shadow: add symbols to the parent but check for redefinitions etc + ## shadow -> non-shadow: the above, but also handle exports and all that let shadowScope = c.currentScope c.rawCloseScope for sym in shadowScope.symbols: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8f87ce83c..d6ad7ab54 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1844,7 +1844,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # before compiling the proc params & body, set as current the scope # where the proc was declared - let delcarationScope = c.currentScope + let declarationScope = c.currentScope pushOwner(c, s) openScope(c) @@ -1889,7 +1889,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, var (proto, comesFromShadowScope) = if isAnon: (nil, false) - else: searchForProc(c, delcarationScope, s) + else: searchForProc(c, declarationScope, s) if proto == nil and sfForward in s.flags: ## In cases such as a macro generating a proc with a gensymmed name we ## know `searchForProc` will not find it and sfForward will be set. In @@ -1916,9 +1916,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not hasProto and sfGenSym notin s.flags: #and not isAnon: if s.kind in OverloadableSyms: - addInterfaceOverloadableSymAt(c, delcarationScope, s) + addInterfaceOverloadableSymAt(c, declarationScope, s) else: - addInterfaceDeclAt(c, delcarationScope, s) + addInterfaceDeclAt(c, declarationScope, s) pragmaCallable(c, s, n, validPragmas) if not hasProto: diff --git a/tests/macros/m18235.nim b/tests/macros/m18235.nim new file mode 100644 index 000000000..6bb4547e0 --- /dev/null +++ b/tests/macros/m18235.nim @@ -0,0 +1,42 @@ +import macros + +# Necessary code to update the AST on a symbol across module boundaries when +# processed by a type macro. Used by a test of a corresponding name of this +# file. + +macro eexport(n: typed): untyped = + result = copyNimTree(n) + # turn exported nnkSym -> nnkPostfix(*, nnkIdent), forcing re-sem + result[0] = nnkPostfix.newTree(ident"*").add: + n.name.strVal.ident + +macro unexport(n: typed): untyped = + result = copyNimTree(n) + # turn nnkSym -> nnkIdent, forcing re-sem and dropping any exported-ness + # that might be present + result[0] = n.name.strVal.ident + +proc foo*() {.unexport.} = discard +proc bar() {.eexport.} = discard + +proc foooof*() {.unexport, eexport, unexport.} = discard +proc barrab() {.eexport, unexport, eexport.} = discard + +macro eexportMulti(n: typed): untyped = + # use the call version of `eexport` macro for one or more decls + result = copyNimTree(n) + for i in 0.. Date: Mon, 14 Jun 2021 08:30:04 +0100 Subject: [PATCH 2704/4254] Enable parallel build in build.sh (#18195) Add help --- tools/niminst/buildsh.nimf | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index e13221781..e7afd402e 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -21,10 +21,23 @@ do optosname=$2 shift 2 ;; + --parallel) + parallel=$2 + shift 2 + ;; --extraBuildArgs) extraBuildArgs=" $2" shift 2 ;; + -h | --help) + echo "Options:" + echo " --os " + echo " --cpu " + echo " --osname Additional OS specification (used for Android)" + echo " --extraBuildArgs Additional arguments passed to the compiler" + echo " --parallel Multiprocess build. Requires GNU parallel" + exit 0 + ;; --) # End of all options shift break; @@ -39,7 +52,15 @@ do esac done +parallel="${parallel:-0}" CC="${CC:-gcc}" +if [ "$parallel" -gt 1 ]; then + if ! command -v sem > /dev/null; then + echo "Error: GNU parallel is required to use --parallel" + exit 1 + fi + CC="sem -j $parallel --id $$ ${CC}" +fi COMP_FLAGS="${CPPFLAGS:-} ${CFLAGS:-} ?{c.ccompiler.flags}$extraBuildArgs" LINK_FLAGS="${LDFLAGS:-} ?{c.linker.flags}" PS4="" @@ -222,6 +243,9 @@ case $myos in $CC $COMP_FLAGS -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")} # add(linkCmd, " \\\n" & changeFileExt(f, "o")) # end for + if [ "$parallel" -gt 0 ]; then + sem --wait --id $$ + fi $CC -o ?{"$binDir/" & toLowerAscii(c.name)} ?linkCmd $LINK_FLAGS ;; # end for From 0adb47aa15e242983c8251d85367c0fe45fc5f12 Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 14 Jun 2021 11:26:12 -0500 Subject: [PATCH 2705/4254] system/excpt: check if the exception is not nil before pop (#18247) In CPS we would consume an exception in the except branch by stashing it into a local then remove the exception from Nim environment so as not to leak it to other code that would be running before the continuation continues However since popCurrentException() assumes that the exception always exist, removing the exception from an except branch will cause a SIGSEGV to happen. This commit fixes that. --- lib/system/excpt.nim | 5 +++-- tests/exception/tsetexceptions.nim | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 5b7d4d49f..72225cf96 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -135,8 +135,9 @@ proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} = #showErrorMessage2 "A" proc popCurrentException {.compilerRtl, inl.} = - currException = currException.up - #showErrorMessage2 "B" + if currException != nil: + currException = currException.up + #showErrorMessage2 "B" proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = discard "only for bootstrapping compatbility" diff --git a/tests/exception/tsetexceptions.nim b/tests/exception/tsetexceptions.nim index 557fc1898..386a6ae4c 100644 --- a/tests/exception/tsetexceptions.nim +++ b/tests/exception/tsetexceptions.nim @@ -6,3 +6,10 @@ let ex = newException(CatchableError, "test") setCurrentException(ex) doAssert getCurrentException().msg == ex.msg doAssert getCurrentExceptionMsg() == ex.msg +setCurrentException(nil) + +try: + raise newException(CatchableError, "test2") +except: + setCurrentException(nil) +doAssert getCurrentException() == nil From 8c42f5be0274d8d16910401d7d5a45aa35a63afd Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 14 Jun 2021 19:19:58 +0200 Subject: [PATCH 2706/4254] Small scope refactoring (#18263) * Small scope refactoring * Add test for #10251 * Add inline where appropriate --- compiler/astalgo.nim | 3 ++- compiler/lookups.nim | 36 +++++++++++++++++------------------- compiler/semtypes.nim | 6 ++---- tests/errmsgs/t10251.nim | 12 ++++++++++++ 4 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 tests/errmsgs/t10251.nim diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 300089d81..5af8caad8 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -777,9 +777,10 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym; replaceSlot = h h = nextTry(h, high(t.data)) if replaceSlot >= 0: + result = t.data[replaceSlot] # found it if not onConflictKeepOld: t.data[replaceSlot] = n # overwrite it with newer definition! - return t.data[replaceSlot] # found it + return result elif mustRehash(t.data.len, t.counter): strTableEnlarge(t) strTableRawInsert(t.data, n) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index a21e35ddc..9dac106e4 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -293,29 +293,28 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; "redefinition of '$1'; previous declaration here: $2" % [s, c.config $ conflictsWith]) -proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) = - let conflict = c.currentScope.addUniqueSym(sym) +proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = + let conflict = scope.addUniqueSym(sym) if conflict != nil: wrongRedefinition(c, info, sym.name.s, conflict.info) -proc addDecl*(c: PContext, sym: PSym) = - let conflict = strTableInclReportConflict(c.currentScope.symbols, sym, true) - if conflict != nil: - wrongRedefinition(c, sym.info, sym.name.s, conflict.info) +proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) {.inline.} = + addDeclAt(c, scope, sym, sym.info) + +proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) {.inline.} = + addDeclAt(c, c.currentScope, sym, info) + +proc addDecl*(c: PContext, sym: PSym) {.inline.} = + addDeclAt(c, c.currentScope, sym) proc addPrelimDecl*(c: PContext, sym: PSym) = discard c.currentScope.addUniqueSym(sym) -proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) = - let conflict = scope.addUniqueSym(sym) - if conflict != nil: - wrongRedefinition(c, sym.info, sym.name.s, conflict.info) - from ic / ic import addHidden -proc addInterfaceDeclAux*(c: PContext, sym: PSym, forceExport = false) = +proc addInterfaceDeclAux(c: PContext, sym: PSym) = ## adds symbol to the module for either private or public access. - if sfExported in sym.flags or forceExport: + if sfExported in sym.flags: # add to interface: if c.module != nil: exportSym(c, sym) else: internalError(c.config, sym.info, "addInterfaceDeclAux") @@ -331,6 +330,10 @@ proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) = # adding into a non-shadow scope, we need to handle exports, etc addInterfaceDeclAux(c, sym) +proc addInterfaceDecl*(c: PContext, sym: PSym) {.inline.} = + ## adds a decl and the interface if appropriate + addInterfaceDeclAt(c, c.currentScope, sym) + proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) = ## adds an symbol to the given scope, will check for and raise errors if it's ## a redefinition as opposed to an overload. @@ -343,16 +346,11 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) = else: scope.addSym(fn) -proc addInterfaceDecl*(c: PContext, sym: PSym) = - ## adds a decl and the interface if appropriate - addDecl(c, sym) - if not c.currentScope.isShadowScope: - addInterfaceDeclAux(c, sym) - proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) = ## adds an overloadable symbol on the scope and the interface if appropriate addOverloadableSymAt(c, scope, sym) if not scope.isShadowScope: + # adding into a non-shadow scope, we need to handle exports, etc addInterfaceDeclAux(c, sym) proc openShadowScope*(c: PContext) = diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 84556ca1a..38307a9ac 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -138,15 +138,13 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: - incl(e.flags, {sfUsed, sfExported}) - if result.sym != nil and not isPure: - addInterfaceDeclAux(c, e, forceExport = sfExported in result.sym.flags) + e.flags.incl {sfUsed, sfExported} result.n.add symNode styleCheckDef(c.config, e) onDef(e.info, e) if sfGenSym notin e.flags: - if not isPure: addDecl(c, e) + if not isPure: addInterfaceDecl(c, e) else: declarePureEnumField(c, e) if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil): wrongRedefinition(c, e.info, e.name.s, conflict.info) diff --git a/tests/errmsgs/t10251.nim b/tests/errmsgs/t10251.nim new file mode 100644 index 000000000..5ad373ba3 --- /dev/null +++ b/tests/errmsgs/t10251.nim @@ -0,0 +1,12 @@ +discard """ +errormsg: "redefinition of 'foo'; previous declaration here: t10251.nim(9, 9)" +line: 11 +column: 9 +""" + +type + Enum1 = enum + foo, bar, baz + Enum2 = enum + foo, bar, baz + From e80d7ff0f2716fd1f892a936a78986531b107fb6 Mon Sep 17 00:00:00 2001 From: Mark Pointing Date: Tue, 15 Jun 2021 03:29:23 +1000 Subject: [PATCH 2707/4254] httpclient.nim Fixes #14794 and an issue where content-header is not set on postContent (#18208) * Fixed missing newline after bound marker in mulipart post (#14794) and a problem where calling postContent with multipart data does not set content-length header. * Update lib/pure/httpclient.nim * Added comment outlining the reason for changes to httpclient.nim and added tests to ensure that multipart post has a newline at the end of the body, and that the content-length header is present. * Fixed typo in comments. * Removed redundant blank lines in thttpclient_standalone.nim. Co-authored-by: Mark Pointing Co-authored-by: Andreas Rumpf --- lib/pure/httpclient.nim | 8 ++++-- tests/stdlib/thttpclient_standalone.nim | 33 ++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 2f9f1913f..33da6ef6c 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -975,7 +975,7 @@ proc format(client: HttpClient | AsyncHttpClient, if entry.isFile: length += entry.fileSize + httpNewLine.len - result.add "--" & bound & "--" + result.add "--" & bound & "--" & httpNewLine for s in result: length += s.len client.headers["Content-Length"] = $length @@ -1010,12 +1010,16 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: Uri, await newConnection(client, url) - let newHeaders = client.headers.override(headers) + var newHeaders: HttpHeaders var data: seq[string] if multipart != nil and multipart.content.len > 0: + # `format` modifies `client.headers`, see + # https://github.com/nim-lang/Nim/pull/18208#discussion_r647036979 data = await client.format(multipart) + newHeaders = client.headers.override(headers) else: + newHeaders = client.headers.override(headers) # Only change headers if they have not been specified already if not newHeaders.hasKey("Content-Length"): if body.len != 0: diff --git a/tests/stdlib/thttpclient_standalone.nim b/tests/stdlib/thttpclient_standalone.nim index 44a88e91e..5fa1ea41a 100644 --- a/tests/stdlib/thttpclient_standalone.nim +++ b/tests/stdlib/thttpclient_standalone.nim @@ -2,7 +2,7 @@ discard """ cmd: "nim c --threads:on $file" """ -import asynchttpserver, httpclient, asyncdispatch +import asynchttpserver, httpclient, asyncdispatch, strutils block: # bug #16436 proc startServer() {.async.} = @@ -21,3 +21,34 @@ block: # bug #16436 asyncCheck startServer() doAssertRaises(ProtocolError): waitFor runClient() + +block: # bug #14794 (And test for presence of content-length header when using postContent) + proc startServer() {.async.} = + var killServer = false + proc cb(req: Request) {.async.} = + doAssert(req.body.endsWith(httpNewLine), "Multipart body does not end with a newline.") + # this next line is probably not required because asynchttpserver does not call + # the callback when there is no content-length header. It instead errors with + # Error: unhandled exception: 411 Length Required + # Added for good measure in case the server becomes more permissive. + doAssert(req.headers.hasKey("content-length"), "Content-Length header is not present.") + killServer = true + asyncCheck req.respond(Http200, "OK") + + var server = newAsyncHttpServer() + server.listen(Port(5556)) + while not killServer: + if server.shouldAcceptRequest(): + await server.acceptRequest(cb) + else: + poll() + + proc runClient() {.async.} = + let c = newAsyncHttpClient() + var data = newMultipartData() + data.add("file.txt", "This is intended to be an example text file.\r\nThis would be the second line.\r\n") + let r = await c.postContent("http://127.0.0.1:5556", multipart = data) + c.close() + + asyncCheck startServer() + waitFor runClient() From 8ef6073543b14bd48665ae075df66c2c36f564dd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 14 Jun 2021 23:56:10 -0700 Subject: [PATCH 2708/4254] add test case for pure enum redefinition error within enum (fixed in recent PR) (#18266) * add test case for pure enum redefinition error within enum (fixed in recent PR) * remove code duplication * Revert "remove code duplication" (would require bootstrap >= 1.4) This reverts commit 3f793874c231f847ef015e37a5fd6851f85d9675. * fixup --- compiler/astalgo.nim | 8 ++++---- compiler/lookups.nim | 2 ++ tests/errmsgs/t10251.nim | 21 ++++++++++++++------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 5af8caad8..3c97665f0 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -759,9 +759,9 @@ proc strTableAdd*(t: var TStrTable, n: PSym) = proc strTableInclReportConflict*(t: var TStrTable, n: PSym; onConflictKeepOld = false): PSym = - # returns true if n is already in the string table: - # It is essential that `n` is written nevertheless! - # This way the newest redefinition is picked by the semantic analyses! + # if `t` has a conflicting symbol (same identifier as `n`), return it + # otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true` + # and a conflict was found. assert n.name != nil var h: Hash = n.name.h and high(t.data) var replaceSlot = -1 @@ -780,7 +780,7 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym; result = t.data[replaceSlot] # found it if not onConflictKeepOld: t.data[replaceSlot] = n # overwrite it with newer definition! - return result + return result # but return the old one elif mustRehash(t.data.len, t.counter): strTableEnlarge(t) strTableRawInsert(t.data, n) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 9dac106e4..f72b58ac6 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -293,6 +293,8 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; "redefinition of '$1'; previous declaration here: $2" % [s, c.config $ conflictsWith]) +# xxx pending bootstrap >= 1.4, replace all those overloads with a single one: +# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} = proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = let conflict = scope.addUniqueSym(sym) if conflict != nil: diff --git a/tests/errmsgs/t10251.nim b/tests/errmsgs/t10251.nim index 5ad373ba3..0c7fe0b3d 100644 --- a/tests/errmsgs/t10251.nim +++ b/tests/errmsgs/t10251.nim @@ -1,12 +1,19 @@ discard """ -errormsg: "redefinition of 'foo'; previous declaration here: t10251.nim(9, 9)" -line: 11 -column: 9 + action:reject + cmd: "nim check $options $file" + nimout: ''' +t10251.nim(15, 5) Error: redefinition of 'foo'; previous declaration here: t10251.nim(13, 5) +t10251.nim(19, 23) Error: redefinition of 'goo1'; previous declaration here: t10251.nim(19, 11) +''' """ +# line 10 type - Enum1 = enum - foo, bar, baz - Enum2 = enum - foo, bar, baz + Enum1 = enum + foo, bar, baz + Enum2 = enum + foo, bar, baz +type + Enum3 {.pure.} = enum # fixed (by accident?) in https://github.com/nim-lang/Nim/pull/18263 + goo0, goo1, goo2, goo1 From d3b27eb63e18fbe36a7579a3322db316115a3d81 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 15 Jun 2021 14:56:49 -0700 Subject: [PATCH 2709/4254] link stable and devel docs in nim docs (#18272) [backport:1.2] --- config/nimdoc.cfg | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index cdf49197d..15f887023 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -127,21 +127,12 @@ doc.body_toc_group = """
    From c5cf21c0c4f314e4128658d35000339d67e4824b Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 16 Jun 2021 02:45:05 +0200 Subject: [PATCH 2710/4254] Don't report unused hints for consumed AST (#18270) * Fix #18203 * Add testcase * Fix testcase * Fix test --- compiler/lookups.nim | 4 +++- tests/macros/t18203.nim | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/macros/t18203.nim diff --git a/compiler/lookups.nim b/compiler/lookups.nim index f72b58ac6..4f413f472 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -364,7 +364,9 @@ proc openShadowScope*(c: PContext) = proc closeShadowScope*(c: PContext) = ## closes the shadow scope, but doesn't merge any of the symbols - c.closeScope + ## Does not check for unused symbols or missing forward decls since a macro + ## or template consumes this AST + rawCloseScope(c) proc mergeShadowScope*(c: PContext) = ## close the existing scope and merge in all defined symbols, this will also diff --git a/tests/macros/t18203.nim b/tests/macros/t18203.nim new file mode 100644 index 000000000..aae0a2690 --- /dev/null +++ b/tests/macros/t18203.nim @@ -0,0 +1,15 @@ +discard """ + matrix: "--hint:SuccessX:off --hint:Link:off --hint:Conf:off --hint:CC:off --hint:XDeclaredButNotUsed:on" + nimout: ''' +''' +nimoutFull: true +action: compile +""" + +# bug #18203 +import std/macros + +macro foo(x: typed) = newProc ident"bar" +proc bar() {.foo.} = raise +bar() + From c51680e7012bff32156623fad0996d62f7918222 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 16 Jun 2021 17:31:20 +0800 Subject: [PATCH 2711/4254] fixes #17696 (#18276) --- lib/pure/collections/sharedlist.nim | 7 ++-- tests/stdlib/tsharedlist.nim | 53 +++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index c72477675..79f2391f6 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -35,8 +35,10 @@ template withLock(t, x: untyped) = release(t.lock) proc iterAndMutate*[A](x: var SharedList[A]; action: proc(x: A): bool) = - ## iterates over the list. If 'action' returns true, the + ## Iterates over the list. If 'action' returns true, the ## current item is removed from the list. + ## + ## .. warning:: It may not preserve the element order after some modifications. withLock(x): var n = x.head while n != nil: @@ -47,8 +49,9 @@ proc iterAndMutate*[A](x: var SharedList[A]; action: proc(x: A): bool) = if action(n.d[i]): acquire(x.lock) let t = x.tail + dec t.dataLen # TODO considering t.dataLen == 0, + # probably the module should be refactored using doubly linked lists n.d[i] = t.d[t.dataLen] - dec t.dataLen else: acquire(x.lock) inc i diff --git a/tests/stdlib/tsharedlist.nim b/tests/stdlib/tsharedlist.nim index a795be0f3..693f1018e 100644 --- a/tests/stdlib/tsharedlist.nim +++ b/tests/stdlib/tsharedlist.nim @@ -1,17 +1,48 @@ -import sharedlist +discard """ + matrix: "--threads:on" +""" -var - list: SharedList[int] - count: int +import std/sharedlist -init(list) +block: + var + list: SharedList[int] + count: int -for i in 1 .. 250: - list.add i + init(list) -for i in list: - inc count + for i in 1 .. 250: + list.add i -doAssert count == 250 + for i in list: + inc count -deinitSharedList(list) + doAssert count == 250 + + deinitSharedList(list) + + +block: # bug #17696 + var keysList = SharedList[string]() + init(keysList) + + keysList.add("a") + keysList.add("b") + keysList.add("c") + keysList.add("d") + keysList.add("e") + keysList.add("f") + + + # Remove element "b" and "d" from the list. + keysList.iterAndMutate(proc (key: string): bool = + if key == "b" or key == "d": # remove only "b" and "d" + return true + return false + ) + + var results: seq[string] + for key in keysList.items: + results.add key + + doAssert results == @["a", "f", "c", "e"] From 13b94c0297806911cf317ff6169dba8595a0333d Mon Sep 17 00:00:00 2001 From: Clyybber Date: Wed, 16 Jun 2021 16:40:22 +0200 Subject: [PATCH 2712/4254] Fix doubly typed forward declarations (#18279) * Add testcase * Fix testcase * Fix doubly typed forward decls * Better fix --- compiler/semstmts.nim | 7 ++++++- tests/macros/tmacros_issues.nim | 22 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d6ad7ab54..f29dc24ef 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1890,11 +1890,16 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, var (proto, comesFromShadowScope) = if isAnon: (nil, false) else: searchForProc(c, declarationScope, s) - if proto == nil and sfForward in s.flags: + if proto == nil and sfForward in s.flags and n[bodyPos].kind != nkEmpty: ## In cases such as a macro generating a proc with a gensymmed name we ## know `searchForProc` will not find it and sfForward will be set. In ## such scenarios the sym is shared between forward declaration and we ## can treat the `s` as the proto. + ## To differentiate between that happening and a macro just returning a + ## forward declaration that has been typed before we check if the body + ## is not empty. This has the sideeffect of allowing multiple forward + ## declarations if they share the same sym. + ## See the "doubly-typed forward decls" case in tmacros_issues.nim proto = s let hasProto = proto != nil diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim index a964f46ba..a81c51658 100644 --- a/tests/macros/tmacros_issues.nim +++ b/tests/macros/tmacros_issues.nim @@ -484,6 +484,26 @@ func expMin: float {.aadMin.} = 1 echo expMin() +# doubly-typed forward decls +macro noop(x: typed) = x +noop: + proc cally() = discard + +cally() + +noop: + proc barry() + +proc barry() = discard + +# some more: +proc barry2() {.noop.} +proc barry2() = discard + +proc barry3() {.noop.} +proc barry3() {.noop.} = discard + + # issue #15389 block double_sem_for_procs: @@ -498,4 +518,4 @@ block double_sem_for_procs: return x1 + 1.0 result = 10.0 - discard exp(5.0) \ No newline at end of file + discard exp(5.0) From 3c854e8c24b394900dc65df680b7679f09cee97c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 16 Jun 2021 23:04:12 -0700 Subject: [PATCH 2713/4254] followup #16400; use use -d:nimCompilerStackraceHints in more places (#18282) --- compiler/vmgen.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c6fd75259..bb203e0ab 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -35,6 +35,9 @@ import from modulegraphs import getBody +when defined(nimCompilerStackraceHints): + import std/stackframes + const debugEchoCode* = defined(nimVMDebug) @@ -2000,6 +2003,8 @@ proc procIsCallback(c: PCtx; s: PSym): bool = dec i proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = + when defined(nimCompilerStackraceHints): + setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags case n.kind of nkSym: let s = n.sym From 49e945ed082bacd5cd5ecff305ec47ff3a00f1c5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 16 Jun 2021 23:07:40 -0700 Subject: [PATCH 2714/4254] increase backoffDuration to avoid timeouts (#18281) --- testament/categories.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/categories.nim b/testament/categories.nim index 7f05797ff..bf7855b2c 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -429,7 +429,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = let buildPath = packagesDir / pkg.name template tryCommand(cmd: string, workingDir2 = buildPath, reFailed = reInstallFailed, maxRetries = 1): string = var outp: string - let ok = retryCall(maxRetry = maxRetries, backoffDuration = 1.0): + let ok = retryCall(maxRetry = maxRetries, backoffDuration = 10.0): var status: int (outp, status) = execCmdEx(cmd, workingDir = workingDir2) status == QuitSuccess From 969cb97c0a9f045a2fb31866fc804cdf1b2698dd Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 17 Jun 2021 09:19:52 +0300 Subject: [PATCH 2715/4254] PCRE, nimgrep: add limit for buffer size (#18280) --- lib/impure/re.nim | 13 ++++++++++--- tools/nimgrep.nim | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 78ea7b002..504d8f22e 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -141,6 +141,10 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], else: matches[i-1] = "" return rawMatches[1] - rawMatches[0] +const MaxReBufSize* = high(cint) + ## Maximum PCRE (API 1) buffer start/size equal to `high(cint)`, which even + ## for 64-bit systems can be either 2`31`:sup:-1 or 2`63`:sup:-1. + proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], start = 0, bufSize: int): tuple[first, last: int] = ## returns the starting position and end position of `pattern` in `buf` @@ -167,7 +171,8 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], ## and the captured substrings in the array `matches`. ## If it does not match, nothing ## is written into `matches` and `(-1,0)` is returned. - result = findBounds(cstring(s), pattern, matches, start, s.len) + result = findBounds(cstring(s), pattern, matches, + min(start, MaxReBufSize), min(s.len, MaxReBufSize)) proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[tuple[first, last: int]], @@ -197,7 +202,8 @@ proc findBounds*(s: string, pattern: Regex, ## and the captured substrings in the array `matches`. ## If it does not match, nothing is written into `matches` and ## `(-1,0)` is returned. - result = findBounds(cstring(s), pattern, matches, start, s.len) + result = findBounds(cstring(s), pattern, matches, + min(start, MaxReBufSize), min(s.len, MaxReBufSize)) proc findBoundsImpl(buf: cstring, pattern: Regex, start = 0, bufSize = 0, flags = 0): tuple[first, last: int] = @@ -232,7 +238,8 @@ proc findBounds*(s: string, pattern: Regex, ## Note: there is a speed improvement if the matches do not need to be captured. runnableExamples: assert findBounds("01234abc89", re"abc") == (5,7) - result = findBounds(cstring(s), pattern, start, s.len) + result = findBounds(cstring(s), pattern, + min(start, MaxReBufSize), min(s.len, MaxReBufSize)) proc matchOrFind(buf: cstring, pattern: Regex, start, bufSize: int, flags: cint): cint = var diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index a368c40ef..a589cfb14 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -649,7 +649,7 @@ template updateCounters(output: Output) = proc printInfo(filename:string, output: Output) = case output.kind of openError: - printError("can not open path " & filename & " " & output.msg) + printError("cannot open path '" & filename & "': " & output.msg) of rejected: if optVerbose in options: echo "(rejected: ", output.reason, ")" @@ -719,6 +719,9 @@ iterator searchFile(pattern: Pattern; buffer: string): Output = pre: pre, match: move(curMi)) i = t.last+1 + when typeof(pattern) is Regex: + if buffer.len > MaxReBufSize: + yield Output(kind: openError, msg: "PCRE size limit is " & $MaxReBufSize) func detectBin(buffer: string): bool = for i in 0 ..< min(1024, buffer.len): From fd8b79707c1b936ed1ba42892f5e06f846e2816b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 17 Jun 2021 08:20:10 +0200 Subject: [PATCH 2716/4254] Revert "system/excpt: check if the exception is not nil before pop (#18247)" (#18265) This reverts commit 0adb47aa15e242983c8251d85367c0fe45fc5f12. --- lib/system/excpt.nim | 5 ++--- tests/exception/tsetexceptions.nim | 7 ------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 72225cf96..5b7d4d49f 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -135,9 +135,8 @@ proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} = #showErrorMessage2 "A" proc popCurrentException {.compilerRtl, inl.} = - if currException != nil: - currException = currException.up - #showErrorMessage2 "B" + currException = currException.up + #showErrorMessage2 "B" proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = discard "only for bootstrapping compatbility" diff --git a/tests/exception/tsetexceptions.nim b/tests/exception/tsetexceptions.nim index 386a6ae4c..557fc1898 100644 --- a/tests/exception/tsetexceptions.nim +++ b/tests/exception/tsetexceptions.nim @@ -6,10 +6,3 @@ let ex = newException(CatchableError, "test") setCurrentException(ex) doAssert getCurrentException().msg == ex.msg doAssert getCurrentExceptionMsg() == ex.msg -setCurrentException(nil) - -try: - raise newException(CatchableError, "test2") -except: - setCurrentException(nil) -doAssert getCurrentException() == nil From 99411674a6da72f608bfa870f51b3a296cd85eee Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 16 Jun 2021 23:20:33 -0700 Subject: [PATCH 2717/4254] tests/exception/tsetexceptions.nim not joinable (#18264) --- tests/exception/tsetexceptions.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/exception/tsetexceptions.nim b/tests/exception/tsetexceptions.nim index 557fc1898..0e353f43e 100644 --- a/tests/exception/tsetexceptions.nim +++ b/tests/exception/tsetexceptions.nim @@ -1,7 +1,10 @@ discard """ targets: "c cpp js" + joinable: false """ +# refs https://github.com/nim-lang/Nim/pull/18247#issuecomment-860877161 + let ex = newException(CatchableError, "test") setCurrentException(ex) doAssert getCurrentException().msg == ex.msg From c83ac16671170e513fa1ca40419892ccc618ec85 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 17 Jun 2021 00:17:46 -0700 Subject: [PATCH 2718/4254] Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints`. (#18283) --- changelog.md | 1 + compiler/ccgexprs.nim | 4 ++-- compiler/semexprs.nim | 4 ++-- compiler/vmgen.nim | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index cc6f826ee..26048eedd 100644 --- a/changelog.md +++ b/changelog.md @@ -88,6 +88,7 @@ The downside is that these defines now have custom logic that doesn't apply for other defines. +- Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints`. ## Standard library additions and changes diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7ed80145b..c07ddf1db 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -9,7 +9,7 @@ # included from cgen.nim -when defined(nimCompilerStackraceHints): +when defined(nimCompilerStacktraceHints): import std/stackframes proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, @@ -2694,7 +2694,7 @@ proc genConstStmt(p: BProc, n: PNode) = genConstDefinition(m, p, sym) proc expr(p: BProc, n: PNode, d: var TLoc) = - when defined(nimCompilerStackraceHints): + when defined(nimCompilerStacktraceHints): setFrameMsg p.config$n.info & " " & $n.kind p.currLineInfo = n.info diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ba8b93ae6..53a5f149e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,7 +10,7 @@ # this module does the semantic checking for expressions # included from sem.nim -when defined(nimCompilerStackraceHints): +when defined(nimCompilerStacktraceHints): import std/stackframes const @@ -2714,7 +2714,7 @@ proc getNilType(c: PContext): PType = c.nilTypeCache = result proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = - when defined(nimCompilerStackraceHints): + when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind result = n if c.config.cmd == cmdIdeTools: suggestExpr(c, n) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bb203e0ab..14f9e0b30 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -35,7 +35,7 @@ import from modulegraphs import getBody -when defined(nimCompilerStackraceHints): +when defined(nimCompilerStacktraceHints): import std/stackframes const @@ -2003,7 +2003,7 @@ proc procIsCallback(c: PCtx; s: PSym): bool = dec i proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = - when defined(nimCompilerStackraceHints): + when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags case n.kind of nkSym: From 5a3456d220d0c2a4022969b98ab33baaf1fd4d00 Mon Sep 17 00:00:00 2001 From: Adrian Veith Date: Thu, 17 Jun 2021 11:23:38 +0200 Subject: [PATCH 2719/4254] fix for #18284 int32 should be int (#18285) the var exp was typed as int32 - it should be int since frep expects an int --- lib/pure/math.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index cff946581..410660d4a 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -997,7 +997,7 @@ when not defined(js): # taken from Go-lang Math.Log2 const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 template log2Impl[T](x: T): T = - var exp: int32 + var exp: int var frac = frexp(x, exp) # Make sure exact powers of two give an exact answer. # Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1. From ef121f3b99c4d020d3df7cb369f5060c76c73d57 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 17 Jun 2021 16:19:16 -0700 Subject: [PATCH 2720/4254] followup #17876: remove annoying enum name clashes in tests/enum/tenum.nim (#18291) --- tests/enum/tenum.nim | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index 97fd4c68c..37383890c 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -128,22 +128,21 @@ block tnamedfields: doAssert $x == "abc", $x -block toptions: +block tfakeOptions: type - # please make sure we have under 32 options (improves code efficiency!) - TOption = enum - optNone, optForceFullMake, optBoehmGC, optRefcGC, optRangeCheck, - optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir, - optWarns, optHints, optListCmd, optCompileOnly, - optSafeCode, # only allow safe code - optStyleCheck, optOptimizeSpeed, optOptimizeSize, optGenDynLib, - optGenGuiApp, optStackTrace + TFakeOption = enum + fakeNone, fakeForceFullMake, fakeBoehmGC, fakeRefcGC, fakeRangeCheck, + fakeBoundsCheck, fakeOverflowCheck, fakeNilCheck, fakeAssert, fakeLineDir, + fakeWarns, fakeHints, fakeListCmd, fakeCompileOnly, + fakeSafeCode, # only allow safe code + fakeStyleCheck, fakeOptimizeSpeed, fakeOptimizeSize, fakeGenDynLib, + fakeGenGuiApp, fakeStackTrace - TOptionset = set[TOption] + TFakeOptionset = set[TFakeOption] var - gOptions: TOptionset = {optRefcGC, optRangeCheck, optBoundsCheck, - optOverflowCheck, optAssert, optWarns, optHints, optLineDir, optStackTrace} + gFakeOptions: TFakeOptionset = {fakeRefcGC, fakeRangeCheck, fakeBoundsCheck, + fakeOverflowCheck, fakeAssert, fakeWarns, fakeHints, fakeLineDir, fakeStackTrace} compilerArgs: int gExitcode: int8 From fc76565574b86566e4a642b9aac541e025cf5de3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 17 Jun 2021 16:38:15 -0700 Subject: [PATCH 2721/4254] disable pkg manu (#18292) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 3d3c340eb..efee361da 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -82,7 +82,7 @@ pkg "karax", "nim c -r tests/tester.nim" pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree" pkg "loopfusion" pkg "macroutils" -pkg "manu" +pkg "manu", allowFailure=true # pending https://github.com/planetis-m/manu/issues/5 pkg "markdown" pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" From a250481dcde2167d568cc1b61624658419c18e69 Mon Sep 17 00:00:00 2001 From: j-james <35242550+j-james@users.noreply.github.com> Date: Fri, 18 Jun 2021 03:10:45 -0700 Subject: [PATCH 2722/4254] Make the existence of high(type) clearer, especially near subranges (#18286) * Make the existence of high(type) clearer, especially around subranges * Use a better example and dry up the wording --- doc/manual.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 867db245b..46a40a690 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -989,10 +989,12 @@ Ordinal types have the following characteristics: - Ordinal types are countable and ordered. This property allows the operation of functions such as `inc`, `ord`, and `dec` on ordinal types to be defined. -- Ordinal values have the smallest possible value. Trying to count further - down than the smallest value produces a panic or a static error. -- Ordinal values have the largest possible value. Trying to count further - than the largest value produces a panic or a static error. +- Ordinal types have a smallest possible value, accessible with `low(type)`. + Trying to count further down than the smallest value produces a panic or + a static error. +- Ordinal types have a largest possible value, accessible with `high(type)`. + Trying to count further up than the largest value produces a panic or + a static error. Integers, bool, characters, and enumeration types (and subranges of these types) belong to ordinal types. @@ -1095,6 +1097,7 @@ lowest and highest value of the type. For example: type Subrange = range[0..5] PositiveFloat = range[0.0..Inf] + Positive* = range[1..high(int)] # as defined in `system` `Subrange` is a subrange of an integer which can only hold the values 0 From 87cd9b24a3df66dcde96bbdec2bd7620015ddeba Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 18 Jun 2021 06:52:08 -0700 Subject: [PATCH 2723/4254] add more APIs to compiler/debugutils; re-export it (#18243) --- compiler/debugutils.nim | 37 +++++++++++++++++++++++++++++++++ compiler/options.nim | 3 +++ compiler/semexprs.nim | 7 +++++++ tests/compiler/tdebugutils.nim | 38 ++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 tests/compiler/tdebugutils.nim diff --git a/compiler/debugutils.nim b/compiler/debugutils.nim index 235c100b3..d109d2121 100644 --- a/compiler/debugutils.nim +++ b/compiler/debugutils.nim @@ -4,7 +4,26 @@ Utilities to help with debugging nim compiler. Experimental API, subject to change. ]## +#[ +## example +useful debugging flags: +--stacktrace -d:debug -d:nimDebugUtils + nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim + +## future work +* expose and improve astalgo.debug, replacing it by std/prettyprints, + refs https://github.com/nim-lang/RFCs/issues/385 +]# + import options +import std/wrapnils +export wrapnils + # allows using things like: `?.n.sym.typ.len` + +import std/stackframes +export stackframes + # allows using things like: `setFrameMsg c.config$n.info & " " & $n.kind` + # which doesn't log, but augments stacktrace with side channel information var conf0: ConfigRef @@ -17,3 +36,21 @@ proc onNewConfigRef*(conf: ConfigRef) {.inline.} = proc getConfigRef*(): ConfigRef = ## nil, if -d:nimDebugUtils wasn't specified result = conf0 + +proc isCompilerDebug*(): bool = + ##[ + Provides a simple way for user code to enable/disable logging in the compiler + in a granular way. This can then be used in the compiler as follows: + ```nim + if isCompilerDebug(): + echo ?.n.sym.typ.len + ``` + ]## + runnableExamples: + proc main = + echo 2 + {.define(nimCompilerDebug).} + echo 3.5 # code section in which `isCompilerDebug` will be true + {.undef(nimCompilerDebug).} + echo 'x' + conf0.isDefined("nimCompilerDebug") diff --git a/compiler/options.nim b/compiler/options.nim index 1851770d9..05d8ee5b7 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -472,7 +472,10 @@ const foreignPackageNotesDefault* = { proc isDefined*(conf: ConfigRef; symbol: string): bool when defined(nimDebugUtils): + # this allows inserting debugging utilties in all modules that import `options` + # with a single switch, which is useful when debugging compiler. import debugutils + export debugutils proc initConfigRefCommon(conf: ConfigRef) = conf.selectedGC = gcRefc diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 53a5f149e..c885f4963 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2716,6 +2716,13 @@ proc getNilType(c: PContext): PType = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind + when false: # see `tdebugutils` + if isCompilerDebug(): + echo (">", c.config$n.info, n, flags, n.kind) + defer: + if isCompilerDebug(): + echo ("<", c.config$n.info, n, ?.result.typ) + result = n if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if nfSem in n.flags: return diff --git a/tests/compiler/tdebugutils.nim b/tests/compiler/tdebugutils.nim new file mode 100644 index 000000000..50b15cb78 --- /dev/null +++ b/tests/compiler/tdebugutils.nim @@ -0,0 +1,38 @@ +discard """ + joinable: false + disabled: true +""" + +#[ +This test illustrates some features of `debugutils` to debug the compiler. + +## example +this shows how to enable compiler logging just for a section of user code, +without generating tons of unrelated log messages for code you're not interested +in debugging. + +```sh +# enable some debugging code, e.g. the `when false:` block in `semExpr` +nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim +bin/nim_temp c tests/compiler/tdebugutils.nim +``` + +(use --filenames:abs for abs files) + +## result +("<", "tdebugutils.nim(16, 3)", {.define(nimCompilerDebug).}, nil) +(">", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, {}, nkLetSection) +(">", "tdebugutils.nim(17, 15)", 2.5 * 3, {efAllowDestructor, efWantValue}, nkInfix) +(">", "tdebugutils.nim(17, 11)", 2.5, {efAllowStmt, efDetermineType, efOperand}, nkFloatLit) +("<", "tdebugutils.nim(17, 11)", 2.5, float64) +(">", "tdebugutils.nim(17, 17)", 3, {efAllowStmt, efDetermineType, efOperand}, nkIntLit) +("<", "tdebugutils.nim(17, 17)", 3, int literal(3)) +("<", "tdebugutils.nim(17, 15)", 2.5 * 3, float) +("<", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, nil) +(">", "tdebugutils.nim(18, 3)", {.undef(nimCompilerDebug).}, {}, nkPragma) +]# + +proc main = + {.define(nimCompilerDebug).} + let a = 2.5 * 3 + {.undef(nimCompilerDebug).} From 5600a622297a9b06b2f47039e0397cded1bd425c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 18 Jun 2021 08:57:51 -0700 Subject: [PATCH 2724/4254] strformat.fmt now supports non-literal const strings (#18274) Co-authored-by: Andreas Rumpf --- changelog.md | 4 ++- lib/core/macros.nim | 3 +- lib/pure/strformat.nim | 63 +++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index 26048eedd..4fd1ef355 100644 --- a/changelog.md +++ b/changelog.md @@ -93,7 +93,9 @@ ## Standard library additions and changes -- Added support for parenthesized expressions in `strformat` +- `strformat`: + added support for parenthesized expressions. + added support for const string's instead of just string literals - Fixed buffer overflow bugs in `net` diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 37f855d94..c09fae6b3 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -476,8 +476,9 @@ proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {. ## needs to occur in a declaration context. proc callsite*(): NimNode {.magic: "NCallSite", benign, deprecated: - "Deprecated since v0.18.1; use varargs[untyped] in the macro prototype instead".} + "Deprecated since v0.18.1; use `varargs[untyped]` in the macro prototype instead".} ## Returns the AST of the invocation expression that invoked this macro. + # see https://github.com/nim-lang/RFCs/issues/387 as candidate replacement. proc toStrLit*(n: NimNode): NimNode = ## Converts the AST `n` to the concrete Nim code and wraps that diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 52731e970..872141383 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -573,15 +573,12 @@ template formatValue(result: var string; value: char; specifier: string) = template formatValue(result: var string; value: cstring; specifier: string) = result.add value -proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = - if pattern.kind notin {nnkStrLit..nnkTripleStrLit}: - error "string formatting (fmt(), &) only works with string literals", pattern +proc strformatImpl(f: string; openChar, closeChar: char): NimNode = if openChar == ':' or closeChar == ':': error "openChar and closeChar must not be ':'" - let f = pattern.strVal var i = 0 let res = genSym(nskVar, "fmtRes") - result = newNimNode(nnkStmtListExpr, lineInfoFrom = pattern) + result = newNimNode(nnkStmtListExpr) # XXX: https://github.com/nim-lang/Nim/issues/8405 # When compiling with -d:useNimRtl, certain procs such as `count` from the strutils # module are not accessible at compile-time: @@ -633,12 +630,8 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = var x: NimNode try: x = parseExpr(subexpr) - except ValueError: - when declared(getCurrentExceptionMsg): - let msg = getCurrentExceptionMsg() - error("could not parse `" & subexpr & "`.\n" & msg, pattern) - else: - error("could not parse `" & subexpr & "`.\n", pattern) + except ValueError as e: + error("could not parse `$#` in `$#`.\n$#" % [subexpr, f, e.msg]) let formatSym = bindSym("formatValue", brOpen) var options = "" if f[i] == ':': @@ -667,19 +660,39 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = when defined(debugFmtDsl): echo repr result -macro `&`*(pattern: string): untyped = strformatImpl(pattern, '{', '}') - ## For a specification of the `&` macro, see the module level documentation. - -macro fmt*(pattern: string): untyped = strformatImpl(pattern, '{', '}') - ## An alias for `& <#&.m,string>`_. - -macro fmt*(pattern: string; openChar, closeChar: char): untyped = - ## The same as `fmt <#fmt.m,string>`_, but uses `openChar` instead of `'{'` - ## and `closeChar` instead of `'}'`. +macro fmt*(pattern: static string; openChar: static char, closeChar: static char): string = + ## Interpolates `pattern` using symbols in scope. runnableExamples: - let testInt = 123 - assert "".fmt('<', '>') == "123" - assert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" - assert """ ""{"123+123"}"" """.fmt('"', '"') == " \"{246}\" " + let x = 7 + assert "var is {x * 2}".fmt == "var is 14" + assert "var is {{x}}".fmt == "var is {x}" # escape via doubling + const s = "foo: {x}" + assert s.fmt == "foo: 7" # also works with const strings - strformatImpl(pattern, openChar.intVal.char, closeChar.intVal.char) + assert fmt"\n" == r"\n" # raw string literal + assert "\n".fmt == "\n" # regular literal (likewise with `fmt("\n")` or `fmt "\n"`) + runnableExamples: + # custom `openChar`, `closeChar` + let x = 7 + assert "".fmt('<', '>') == "7" + assert "<<>>".fmt('<', '>') == "<7>" + assert "`x`".fmt('`', '`') == "7" + strformatImpl(pattern, openChar, closeChar) + +template fmt*(pattern: static string): untyped = + ## Alias for `fmt(pattern, '{', '}')`. + fmt(pattern, '{', '}') + +macro `&`*(pattern: string{lit}): string = + ## `&pattern` is the same as `pattern.fmt`. + ## For a specification of the `&` macro, see the module level documentation. + # pending bug #18275, bug #18278, use `pattern: static string` + # consider deprecating this, it's redundant with `fmt` and `fmt` is strictly + # more flexible, readable (no confusion with the binary `&`), self-documenting, + # not to mention #18275, bug #18278. + runnableExamples: + let x = 7 + assert &"{x}\n" == "7\n" # regular string literal + assert &"{x}\n" == "7\n".fmt # `fmt` can be used instead + assert &"{x}\n" != fmt"7\n" # see `fmt` docs, this would use a raw string literal + strformatImpl(pattern.strVal, '{', '}') From 5d15bd7b618cda06e3ae88883914467f89d38112 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 18 Jun 2021 10:23:27 -0700 Subject: [PATCH 2725/4254] refs #18278: do not gag fatal msgs (#18290) --- compiler/lineinfos.nim | 13 ++++++++----- compiler/modules.nim | 3 +-- compiler/msgs.nim | 15 +++++++++++---- compiler/pragmas.nim | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index da0a8d623..052dae272 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -27,7 +27,10 @@ proc createDocLink*(urlSuffix: string): string = type TMsgKind* = enum - errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, + # fatal errors + errUnknown, errFatal, errInternal, + # non-fatal errors + errIllFormedAstX, errCannotOpenFile, errXExpected, errGridTableNotImplemented, errMarkdownIllformedTable, @@ -38,7 +41,7 @@ type errProveInit, # deadcode errGenerated, errUser, - + # warnings warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit", warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated", @@ -64,7 +67,7 @@ type warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", warnUser = "User", - + # hints hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", @@ -83,6 +86,7 @@ type const MsgKindToStr*: array[TMsgKind, string] = [ errUnknown: "unknown error", + errFatal: "fatal error: $1", errInternal: "internal error: $1", errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open '$1'", @@ -180,8 +184,7 @@ const ] const - fatalMin* = errUnknown - fatalMax* = errInternal + fatalMsgs* = {errUnknown..errInternal} errMin* = errUnknown errMax* = errUser warnMin* = warnCannotOpenFile diff --git a/compiler/modules.nim b/compiler/modules.nim index 27b93e8df..dcfcfd508 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -153,8 +153,7 @@ proc compileSystemModule*(graph: ModuleGraph) = proc wantMainModule*(conf: ConfigRef) = if conf.projectFull.isEmpty: - fatal(conf, newLineInfo(conf, AbsoluteFile(commandLineDesc), 1, 1), errGenerated, - "command expects a filename") + fatal(conf, gCmdLineInfo, "command expects a filename") conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt)) proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6b005be3d..8b4365ec4 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -408,7 +408,7 @@ To create a stacktrace, rerun compilation with './koch temp $1 ', see $2 f quit 1 proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = - if msg >= fatalMin and msg <= fatalMax: + if msg in fatalMsgs: if conf.cmd == cmdIdeTools: log(s) quit(conf, msg) if msg >= errMin and msg <= errMax or @@ -498,6 +498,12 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, color: ForegroundColor ignoreMsg = false sev: Severity + let errorOutputsOld = conf.m.errorOutputs + if msg in fatalMsgs: + # don't gag, refs bug #7080, bug #18278; this can happen with `{.fatal.}` + # or inside a `tryConstExpr`. + conf.m.errorOutputs = {eStdOut, eStdErr} + let kind = if msg in warnMin..hintMax and msg != hintUserRaw: $msg else: "" # xxx not sure why hintUserRaw is special case msg of errMin..errMax: @@ -553,6 +559,9 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, KindFormat % $hintMsgOrigin, resetStyle, conf.unitSep) handleError(conf, msg, eh, s) + if msg in fatalMsgs: + # most likely would have died here but just in case, we restore state + conf.m.errorOutputs = errorOutputsOld template rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = let arg = msgKindToString(msg) % args @@ -561,9 +570,7 @@ template rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = template rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = liMessage(conf, unknownLineInfo, msg, arg, eh = doAbort, instLoc()) -template fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = - # this fixes bug #7080 so that it is at least obvious 'fatal' was executed. - conf.m.errorOutputs = {eStdOut, eStdErr} +template fatal*(conf: ConfigRef; info: TLineInfo, arg = "", msg = errFatal) = liMessage(conf, info, msg, arg, doAbort, instLoc()) template globalAssert*(conf: ConfigRef; cond: untyped, info: TLineInfo = unknownLineInfo, arg = "") = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 3a2d9cede..695e595c3 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1047,7 +1047,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, let s = expectStrLit(c, it) recordPragma(c, it, "error", s) localError(c.config, it.info, errUser, s) - of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it)) + of wFatal: fatal(c.config, it.info, expectStrLit(c, it)) of wDefine: processDefine(c, it) of wUndef: processUndef(c, it) of wCompile: processCompile(c, it) From 7714ab468a665e772c6d37d39038974cbcea75dc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 19 Jun 2021 11:24:46 -0700 Subject: [PATCH 2726/4254] make privateAccess work with generic types and generic instantiations; fix a SIGSEGV (#18260) Co-authored-by: Andreas Rumpf --- compiler/ast.nim | 20 +++++++++++++ compiler/semmagic.nim | 10 ++++--- lib/std/importutils.nim | 32 +++++++++++++------- tests/stdlib/mimportutils.nim | 15 ++++++++++ tests/stdlib/timportutils.nim | 56 +++++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 15 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 96adb8c1f..8bb8de1d6 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1887,6 +1887,26 @@ proc toObject*(typ: PType): PType = if t.kind == tyRef: t.lastSon else: typ +proc toObjectFromRefPtrGeneric*(typ: PType): PType = + #[ + See also `toObject`. + Finds the underlying `object`, even in cases like these: + type + B[T] = object f0: int + A1[T] = ref B[T] + A2[T] = ref object f1: int + A3 = ref object f2: int + A4 = object f3: int + ]# + result = typ + while true: + case result.kind + of tyGenericBody: result = result.lastSon + of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0] + # automatic dereferencing is deep, refs #18298. + else: break + assert result.sym != nil + proc isImportedException*(t: PType; conf: ConfigRef): bool = assert t != nil diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e4e007678..d3f26e630 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -457,6 +457,11 @@ proc semOld(c: PContext; n: PNode): PNode = localError(c.config, n[1].info, n[1].sym.name.s & " does not belong to " & getCurrOwner(c).name.s) result = n +proc semPrivateAccess(c: PContext, n: PNode): PNode = + let t = n[1].typ[0].toObjectFromRefPtrGeneric + c.currentScope.allowPrivateAccess.add t.sym + result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) + proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = ## This is the preferred code point to implement magics. @@ -574,9 +579,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, n[0].sym.magic = mSubU result = n of mPrivateAccess: - var t = n[1].typ[0] - if t.kind in {tyRef, tyPtr}: t = t[0] - c.currentScope.allowPrivateAccess.add t.sym - result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) + result = semPrivateAccess(c, n) else: result = n diff --git a/lib/std/importutils.nim b/lib/std/importutils.nim index 0c0f546b9..d2da76ea8 100644 --- a/lib/std/importutils.nim +++ b/lib/std/importutils.nim @@ -13,22 +13,32 @@ Possible future APIs: ]# when defined(nimImportutilsExample): - type Foo = object - x1: int # private + type + Foo = object + f0: int # private + Goo*[T] = object + g0: int # private proc initFoo*(): auto = Foo() -proc privateAccess*(t: typedesc[object|(ref object)|(ptr object)]) {.magic: "PrivateAccess".} = +proc privateAccess*(t: typedesc) {.magic: "PrivateAccess".} = ## Enables access to private fields of `t` in current scope. runnableExamples("-d:nimImportutilsExample"): # here we're importing a module containing: - # type Foo = object - # x1: int # private + # type + # Foo = object + # f0: int # private + # Goo*[T] = object + # g0: int # private # proc initFoo*(): auto = Foo() - var a = initFoo() + var f = initFoo() block: - assert not compiles(a.x1) - privateAccess(a.type) - a.x1 = 1 # accessible in this scope + assert not compiles(f.f0) + privateAccess(f.type) + f.f0 = 1 # accessible in this scope block: - assert a.x1 == 1 # still in scope - assert not compiles(a.x1) + assert f.f0 == 1 # still in scope + assert not compiles(f.f0) + + # this also works with generics + privateAccess(Goo) + assert Goo[float](g0: 1).g0 == 1 diff --git a/tests/stdlib/mimportutils.nim b/tests/stdlib/mimportutils.nim index d2b185cd3..e89d58d27 100644 --- a/tests/stdlib/mimportutils.nim +++ b/tests/stdlib/mimportutils.nim @@ -13,5 +13,20 @@ type hd1: float PA* = ref A PtA* = ptr A + E*[T] = object + he1: int + FSub[T1, T2] = object + h3: T1 + h4: T2 + F*[T1, T2] = ref FSub[T1, T2] + G*[T] = ref E[T] + H3*[T] = object + h5: T + H2*[T] = H3[T] + H1*[T] = ref H2[T] + H*[T] = H1[T] + +type BAalias* = typeof(B.default) + # typeof is not a transparent abstraction, creates a `tyAlias` proc initB*(): B = B() diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim index 37e2b7102..be912e702 100644 --- a/tests/stdlib/timportutils.nim +++ b/tests/stdlib/timportutils.nim @@ -36,6 +36,55 @@ template main = let c = C(c0: 1, hc1: 2) c.hc1 == 2 + block: + assertAll: + not compiles(E[int](he1: 1)) + privateAccess E[int] + var e = E[int](he1: 1) + e.he1 == 1 + e.he1 = 2 + e.he1 == 2 + e.he1 += 3 + e.he1 == 5 + # xxx caveat: this currently compiles but in future, we may want + # to make `privateAccess E[int]` only affect a specific instantiation; + # note that `privateAccess E` does work to cover all instantiations. + var e2 = E[float](he1: 1) + + block: + assertAll: + not compiles(E[int](he1: 1)) + privateAccess E + var e = E[int](he1: 1) + e.he1 == 1 + + block: + assertAll: + not compiles(F[int, int](h3: 1)) + privateAccess F[int, int] + var e = F[int, int](h3: 1) + e.h3 == 1 + + block: + assertAll: + not compiles(F[int, int](h3: 1)) + privateAccess F[int, int].default[].typeof + var e = F[int, int](h3: 1) + e.h3 == 1 + + block: + assertAll: + var a = G[int]() + var b = a.addr + privateAccess b.type + discard b.he1 + discard b[][].he1 + + block: + assertAll: + privateAccess H[int] + var a = H[int](h5: 2) + block: assertAll: privateAccess PA @@ -44,6 +93,13 @@ template main = pa.ha1 = 3 pa.ha1 == 3 + block: + assertAll: + var b = BAalias() + not compiles(b.hb1) + privateAccess BAalias + discard b.hb1 + block: assertAll: var a = A(a0: 1) From ad5063aed101f0102fb867f0b4e518ede7fa188b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 19 Jun 2021 14:41:43 -0700 Subject: [PATCH 2727/4254] testutils.assertAll: show correct location on assert failure (#18299) --- testament/lib/stdtest/testutils.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 6d8620dc7..a5476b8d7 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -107,10 +107,12 @@ macro assertAll*(body) = # remove this once these support VM, pending #10129 (closed but not yet fixed) result = newStmtList() for a in body: - result.add genAst(a) do: + result.add genAst(a, a2 = a.repr, info = lineInfo(a)) do: # D20210421T014713:here # xxx pending https://github.com/nim-lang/Nim/issues/12030, # `typeof` should introduce its own scope, so that this # is sufficient: `typeof(a)` instead of `typeof(block: a)` when typeof(block: a) is void: a - else: doAssert a + else: + if not a: + raise newException(AssertionDefect, info & " " & a2) From 128d21be1cdf28d6aac6a63910fabf02f186e548 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 20 Jun 2021 00:49:18 -0700 Subject: [PATCH 2728/4254] add `typetraits.pointerBase` to return `T` in `ref T|ptr T` (#18293) * add typetraits.deref to return T in ref T|ptr T * deref => refBase * refBase=>pointerBase * [skip ci] address comment --- changelog.md | 15 ++++++--------- lib/pure/typetraits.nim | 10 ++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 4fd1ef355..80e38f420 100644 --- a/changelog.md +++ b/changelog.md @@ -113,8 +113,12 @@ - Make `{.requiresInit.}` pragma to work for `distinct` types. -- Added a macros `enumLen` for returning the number of items in an enum to the - `typetraits.nim` module. +- `typetraits`: + `distinctBase` now is identity instead of error for non distinct types. + Added `enumLen` to return the number of elements in an enum. + Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. + Added `hasClosure`. + Added `pointerBase` to return `T` for `ref T | ptr T`. - `prelude` now works with the JavaScript target. Added `sequtils` import to `prelude`. @@ -162,8 +166,6 @@ Added `symbolName` to return the enum symbol name ignoring the human readable name. Added `symbolRank` to return the index in which an enum member is listed in an enum. -- Added `typetraits.HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. - - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). @@ -293,7 +295,6 @@ - Added `algorithm.merge`. - - Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target. - Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) wrapper for JavaScript target. @@ -322,8 +323,6 @@ - Added `hasDataBuffered` to `asyncnet`. -- Added `hasClosure` to `std/typetraits`. - - Added `std/tempfiles`. - Added `genasts.genAst` that avoids the problems inherent with `quote do` and can @@ -345,8 +344,6 @@ - nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. -- `typetraits.distinctBase` now is identity instead of error for non distinct types. - - `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`; use `-d:nimLegacyCopyFile` for OSX < 10.5. diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 3e215a0ea..e63585f63 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -100,6 +100,16 @@ proc isNamedTuple*(T: typedesc): bool {.magic: "TypeTrait".} = doAssert not isNamedTuple((string, int)) doAssert isNamedTuple(tuple[name: string, age: int]) +template pointerBase*[T](_: typedesc[ptr T | ref T]): typedesc = + ## Returns `T` for `ref T | ptr T`. + runnableExamples: + assert (ref int).pointerBase is int + type A = ptr seq[float] + assert A.pointerBase is seq[float] + assert (ref A).pointerBase is A # not seq[float] + assert (var s = "abc"; s[0].addr).typeof.pointerBase is char + T + proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} = ## Returns the base type for distinct types, or the type itself otherwise. ## From 590d457631290beacf97d945c5d3a625cc671645 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 20 Jun 2021 10:50:03 +0300 Subject: [PATCH 2729/4254] docgen: move to shared RST state (fix #16990) (#18256) * docgen: move to shared RST state (fix #16990) * Update lib/packages/docutils/rst.nim Co-authored-by: Andreas Rumpf * Update lib/packages/docutils/rst.nim Co-authored-by: Andreas Rumpf * Update lib/packages/docutils/rst.nim Co-authored-by: Andreas Rumpf * Update compiler/docgen.nim Co-authored-by: Timothee Cour * Update compiler/docgen.nim Co-authored-by: Timothee Cour * Update compiler/docgen.nim Co-authored-by: Timothee Cour * Update lib/packages/docutils/rst.nim Co-authored-by: Timothee Cour * rename `cmdDoc2` to `cmdDoc` * fix (P)RstSharedState convention * new style of initialization * misc suggestions * 1 more rename * fix a regression Co-authored-by: Andreas Rumpf Co-authored-by: Timothee Cour --- compiler/commands.nim | 2 +- compiler/docgen.nim | 241 ++++++++++++------ compiler/docgen2.nim | 1 + compiler/main.nim | 2 +- compiler/options.nim | 6 +- lib/packages/docutils/rst.nim | 215 +++++++++------- .../expected/subdir/subdir_b/utils.idx | 10 +- tests/stdlib/trstgen.nim | 7 +- 8 files changed, 292 insertions(+), 192 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 994b224f1..8f8df71a7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -443,7 +443,7 @@ proc parseCommand*(command: string): Command = of "check": cmdCheck of "e": cmdNimscript of "doc0": cmdDoc0 - of "doc2", "doc": cmdDoc2 + of "doc2", "doc": cmdDoc of "doc2tex": cmdDoc2tex of "rst2html": cmdRst2html of "rst2tex": cmdRst2tex diff --git a/compiler/docgen.nim b/compiler/docgen.nim index dc2a63f48..2c99adba3 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -28,6 +28,24 @@ const DocColOffset = "## ".len # assuming that a space was added after ## type + ItemFragment = object ## A fragment from each item will be eventually + ## constructed by converting `rst` fields to strings. + case isRst: bool + of true: + rst: PRstNode + of false: ## contains ready markup e.g. from runnableExamples + str: string + ItemPre = seq[ItemFragment] ## A pre-processed item. + Item = object ## Any item in documentation, e.g. symbol + ## entry. Configuration variable ``doc.item`` + ## is used for its HTML rendering. + descRst: ItemPre ## Description of the item (may contain + ## runnableExamples). + substitutions: seq[string] ## Variable names in `doc.item`... + ModSection = object ## Section like Procs, Types, etc. + secItems: seq[Item] ## Pre-processed items. + finalMarkup: string ## The items, after RST pass 2 and rendering. + ModSections = array[TSymKind, ModSection] TSections = array[TSymKind, string] ExampleGroup = ref object ## a group of runnableExamples with same rdoccmd @@ -35,17 +53,25 @@ type docCmd: string ## from user config, e.g. --doccmd:-d:foo code: string ## contains imports; each import contains `body` index: int ## group index + JsonItem = object # pre-processed item: `rst` should be finalized + json: JsonNode + rst: PRstNode + rstField: string TDocumentor = object of rstgen.RstGenerator - modDesc: string # module description + modDescPre: ItemPre # module description, not finalized + modDescFinal: string # module description, after RST pass 2 and rendering module: PSym modDeprecationMsg: string - toc, toc2, section: TSections + section: ModSections # entries of ``.nim`` file (for `proc`s, etc) + toc, toc2: TSections # toc2 - grouped TOC tocTable: array[TSymKind, Table[string, string]] indexValFilename: string analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. - jArray: JsonNode + jEntriesPre: seq[JsonItem] # pre-processed RST + JSON content + jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering types: TStrTable + sharedState: PRstSharedState isPureRst: bool conf*: ConfigRef cache*: IdentCache @@ -58,6 +84,9 @@ type PDoc* = ref TDocumentor ## Alias to type less. +proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst) +proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str) + proc prettyString(a: object): string = # xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906 for k, v in fieldPairs(a): @@ -151,12 +180,12 @@ template declareClosures = if not fileExists(result): result = "" proc parseRst(text, filename: string, - line, column: int, hasToc: var bool, + line, column: int, rstOptions: RstParseOptions; - conf: ConfigRef): PRstNode = + conf: ConfigRef, sharedState: PRstSharedState): PRstNode = declareClosures() - result = rstParse(text, filename, line, column, hasToc, rstOptions, - docgenFindFile, compilerMsgHandler) + result = rstParsePass1(text, filename, line, column, rstOptions, + sharedState) proc getOutFile2(conf: ConfigRef; filename: RelativeFile, ext: string, guessTarget: bool): AbsoluteFile = @@ -179,10 +208,13 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.conf = conf result.cache = cache result.outDir = conf.outDir.string + const options = {roSupportRawDirective, roSupportMarkdown, + roPreferMarkdown, roNimFile} + result.sharedState = newRstSharedState( + options, filename.string, + docgenFindFile, compilerMsgHandler) initRstGenerator(result[], (if conf.isLatexCmd: outLatex else: outHtml), - conf.configVars, filename.string, - {roSupportRawDirective, roSupportMarkdown, - roPreferMarkdown, roNimFile}, + conf.configVars, filename.string, options, docgenFindFile, compilerMsgHandler) if conf.configVars.hasKey("doc.googleAnalytics"): @@ -203,7 +235,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.seenSymbols = newStringTable(modeCaseInsensitive) result.id = 100 - result.jArray = newJArray() + result.jEntriesFinal = newJArray() initStrTable result.types result.onTestSnippet = proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) = @@ -261,37 +293,31 @@ proc getVarIdx(varnames: openArray[string], id: string): int = return i result = -1 -proc genComment(d: PDoc, n: PNode): string = - result = "" +proc genComment(d: PDoc, n: PNode): PRstNode = if n.comment.len > 0: - let comment = n.comment - when false: - # RFC: to preseve newlines in comments, this would work: - comment = comment.replace("\n", "\n\n") - renderRstToOut(d[], - parseRst(comment, toFullPath(d.conf, n.info), - toLinenumber(n.info), - toColumn(n.info) + DocColOffset, - (var dummy: bool; dummy), d.options, d.conf), - result) + result = parseRst(n.comment, toFullPath(d.conf, n.info), + toLinenumber(n.info), + toColumn(n.info) + DocColOffset, + d.options, d.conf, + d.sharedState) -proc genRecCommentAux(d: PDoc, n: PNode): string = - if n == nil: return "" +proc genRecCommentAux(d: PDoc, n: PNode): PRstNode = + if n == nil: return nil result = genComment(d, n) - if result == "": + if result == nil: if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkHiddenStdConv}: # notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}: for i in 0.. 0: msg.add " cmd: " & rdoccmd - dispA(d.conf, dest, "\n

    $1

    \n", + var s: string + dispA(d.conf, s, "\n

    $1

    \n", "\n\n\\textbf{$1}\n", [msg]) + dest.add s inc d.listingCounter let id = $d.listingCounter dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) @@ -597,7 +625,7 @@ proc getRoutineBody(n: PNode): PNode = doAssert result.len == 2 result = result[1] -proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var string) = +proc getAllRunnableExamples(d: PDoc, n: PNode, dest: var ItemPre) = var n = n var state = rsStart template fn(n2, topLevel) = @@ -706,7 +734,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string = ## types will be added with a preceding dash. Return types won't be added. ## ## If you modify the output of this proc, please update the anchor generation - ## section of ``doc/docgen.txt``. + ## section of ``doc/docgen.rst``. result = baseName case k of skProc, skFunc: discard @@ -804,7 +832,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = var result = "" var literal, plainName = "" var kind = tkEof - var comm = "" + var comm: ItemPre if n.kind in routineDefs: getAllRunnableExamples(d, n, comm) else: @@ -840,9 +868,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int) - d.section[k].add(getConfigVar(d.conf, "doc.item") % - ["name", name, "uniqueName", uniqueName, - "header", result, "desc", comm, "itemID", $d.id, + d.section[k].secItems.add Item(descRst: comm, substitutions: @[ + "name", name, "uniqueName", uniqueName, + "header", result, "itemID", $d.id, "header_plain", plainNameEsc, "itemSym", cleanPlainSymbol, "itemSymOrID", symbolOrId, "itemSymEnc", plainSymbolEnc, "itemSymOrIDEnc", symbolOrIdEnc, "seeSrc", seeSrc, @@ -886,25 +914,26 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = if k == skType and nameNode.kind == nkSym: d.types.strTableAdd nameNode.sym -proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = +proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem = if not isVisible(d, nameNode): return var name = getName(d, nameNode) comm = genRecComment(d, n) r: TSrcGen initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) - result = %{ "name": %name, "type": %($k), "line": %n.info.line.int, - "col": %n.info.col} - if comm.len > 0: - result["description"] = %comm + result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int, + "col": %n.info.col} + if comm != nil: + result.rst = comm + result.rstField = "description" if r.buf.len > 0: - result["code"] = %r.buf + result.json["code"] = %r.buf if k in routineKinds: - result["signature"] = newJObject() + result.json["signature"] = newJObject() if n[paramsPos][0].kind != nkEmpty: - result["signature"]["return"] = %($n[paramsPos][0]) + result.json["signature"]["return"] = %($n[paramsPos][0]) if n[paramsPos].len > 1: - result["signature"]["arguments"] = newJArray() + result.json["signature"]["arguments"] = newJArray() for paramIdx in 1 ..< n[paramsPos].len: for identIdx in 0 ..< n[paramsPos][paramIdx].len - 2: let @@ -912,22 +941,22 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = paramType = $n[paramsPos][paramIdx][^2] if n[paramsPos][paramIdx][^1].kind != nkEmpty: let paramDefault = $n[paramsPos][paramIdx][^1] - result["signature"]["arguments"].add %{"name": %paramName, "type": %paramType, "default": %paramDefault} + result.json["signature"]["arguments"].add %{"name": %paramName, "type": %paramType, "default": %paramDefault} else: - result["signature"]["arguments"].add %{"name": %paramName, "type": %paramType} + result.json["signature"]["arguments"].add %{"name": %paramName, "type": %paramType} if n[pragmasPos].kind != nkEmpty: - result["signature"]["pragmas"] = newJArray() + result.json["signature"]["pragmas"] = newJArray() for pragma in n[pragmasPos]: - result["signature"]["pragmas"].add %($pragma) + result.json["signature"]["pragmas"].add %($pragma) if n[genericParamsPos].kind != nkEmpty: - result["signature"]["genericParams"] = newJArray() + result.json["signature"]["genericParams"] = newJArray() for genericParam in n[genericParamsPos]: var param = %{"name": %($genericParam)} if genericParam.sym.typ.sons.len > 0: param["types"] = newJArray() for kind in genericParam.sym.typ.sons: param["types"].add %($kind) - result["signature"]["genericParams"].add param + result.json["signature"]["genericParams"].add param proc checkForFalse(n: PNode): bool = result = n.kind == nkIdent and cmpIgnoreStyle(n.ident.s, "false") == 0 @@ -946,8 +975,8 @@ proc traceDeps(d: PDoc, it: PNode) = traceDeps(d, a) elif it.kind == nkSym and belongsToPackage(d.conf, it.sym): let external = externalDep(d, it.sym) - if d.section[k] != "": d.section[k].add(", ") - dispA(d.conf, d.section[k], + if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") + dispA(d.conf, d.section[k].finalMarkup, "$1", "$1", [esc(d.target, external.prettyLink), changeFileExt(external, "html")]) @@ -956,8 +985,8 @@ proc exportSym(d: PDoc; s: PSym) = const k = exportSection if s.kind == skModule and belongsToPackage(d.conf, s): let external = externalDep(d, s) - if d.section[k] != "": d.section[k].add(", ") - dispA(d.conf, d.section[k], + if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") + dispA(d.conf, d.section[k].finalMarkup, "$1", "$1", [esc(d.target, external.prettyLink), changeFileExt(external, "html")]) @@ -968,9 +997,9 @@ proc exportSym(d: PDoc; s: PSym) = complexSymbol = complexName(s.kind, s.ast, s.name.s) symbolOrId = d.newUniquePlainSymbol(complexSymbol) external = externalDep(d, module) - if d.section[k] != "": d.section[k].add(", ") + if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") # XXX proper anchor generation here - dispA(d.conf, d.section[k], + dispA(d.conf, d.section[k].finalMarkup, "$1", "$1", [esc(d.target, s.name.s), changeFileExt(external, "html"), @@ -1034,13 +1063,16 @@ proc documentRaises*(cache: IdentCache; n: PNode) = if p5 != nil: n[pragmasPos].add p5 proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = + ## Goes through nim nodes recursively and collects doc comments. + ## Main function for `doc`:option: command, + ## which is implemented in ``docgen2.nim``. template genItemAux(skind) = genItem(d, n, n[namePos], skind, docFlags) case n.kind of nkPragma: let pragmaNode = findPragma(n, wDeprecated) d.modDeprecationMsg.add(genDeprecationMsg(d, pragmaNode)) - of nkCommentStmt: d.modDesc.add(genComment(d, n)) + of nkCommentStmt: d.modDescPre.add(genComment(d, n)) of nkProcDef, nkFuncDef: when useEffectSystem: documentRaises(d.cache, n) genItemAux(skProc) @@ -1079,21 +1111,63 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept" of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0]) of nkCallKinds: - var comm = "" + var comm: ItemPre getAllRunnableExamples(d, n, comm) - if comm != "": d.modDesc.add(comm) + if comm.len != 0: d.modDescPre.add(comm) else: discard -proc add(d: PDoc; j: JsonNode) = - if j != nil: d.jArray.add j +proc finishGenerateDoc*(d: var PDoc) = + ## Perform 2nd RST pass for resolution of links/footnotes/headings... + # Main title/subtitle are allowed only in the first RST fragment of document + var firstRst = PRstNode(nil) + for fragment in d.modDescPre: + if fragment.isRst: + firstRst = fragment.rst + break + preparePass2(d.sharedState, firstRst) + + # Finalize fragments of ``.nim`` or ``.rst`` file + proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) = + for f in fragments: + case f.isRst: + of true: + var resolved = resolveSubs(d.sharedState, f.rst) + renderRstToOut(d[], resolved, result) + of false: result &= f.str + for k in TSymKind: + for item in d.section[k].secItems: + var itemDesc: string + renderItemPre(d, item.descRst, itemDesc) + d.section[k].finalMarkup.add( + getConfigVar(d.conf, "doc.item") % ( + item.substitutions & @["desc", itemDesc])) + itemDesc = "" + d.section[k].secItems.setLen 0 + renderItemPre(d, d.modDescPre, d.modDescFinal) + d.modDescPre.setLen 0 + d.hasToc = d.hasToc or d.sharedState.hasToc + + # Finalize fragments of ``.json`` file + for i, entry in d.jEntriesPre: + if entry.rst != nil: + let resolved = resolveSubs(d.sharedState, entry.rst) + var str: string + renderRstToOut(d[], resolved, str) + entry.json[entry.rstField] = %str + d.jEntriesFinal.add entry.json + d.jEntriesPre[i].rst = nil + +proc add(d: PDoc; j: JsonItem) = + if j.json != nil or j.rst != nil: d.jEntriesPre.add j proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = case n.kind of nkCommentStmt: if includeComments: - d.add %*{"comment": genComment(d, n)} + d.add JsonItem(rst: genComment(d, n), rstField: "comment", + json: %Table[string, string]()) else: - d.modDesc.add(genComment(d, n)) + d.modDescPre.add(genComment(d, n)) of nkProcDef, nkFuncDef: when useEffectSystem: documentRaises(d.cache, n) d.add genJsonItem(d, n, n[namePos], skProc) @@ -1173,11 +1247,11 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs", "Methods", "Iterators", "Converters", "Macros", "Templates", "Exports" ] - if d.section[kind] == "": return + if d.section[kind].finalMarkup == "": return var title = sectionNames[kind] - d.section[kind] = getConfigVar(d.conf, "doc.section") % [ + d.section[kind].finalMarkup = getConfigVar(d.conf, "doc.section") % [ "sectionid", $ord(kind), "sectionTitle", title, - "sectionTitleID", $(ord(kind) + 50), "content", d.section[kind]] + "sectionTitleID", $(ord(kind) + 50), "content", d.section[kind].finalMarkup] var tocSource = d.toc if groupedToc: @@ -1209,7 +1283,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = if toc != "" or d.target == outLatex: # for Latex $doc.toc will automatically generate TOC if `d.hasToc` is set toc = getConfigVar(d.conf, "doc.toc") % ["content", toc] - for i in TSymKind: code.add(d.section[i]) + for i in TSymKind: code.add(d.section[i].finalMarkup) # Extract the title. Non API modules generate an entry in the index table. if d.meta[metaTitle].len != 0: @@ -1234,7 +1308,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = let seeSrc = genSeeSrc(d, d.filename, 1) content = getConfigVar(d.conf, bodyname) % [ "title", title, "subtitle", subtitle, - "tableofcontents", toc, "moduledesc", d.modDesc, "date", getDateStr(), + "tableofcontents", toc, "moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(), "content", code, "deprecationMsg", d.modDeprecationMsg, "theindexhref", relLink(d.conf.outDir, d.destFile.AbsoluteFile, @@ -1248,7 +1322,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = "dochackjs", relLink(d.conf.outDir, d.destFile.AbsoluteFile, docHackJsFname.RelativeFile), "title", title, "subtitle", subtitle, "tableofcontents", toc, - "moduledesc", d.modDesc, "date", getDateStr(), "time", getClockStr(), + "moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(), "content", content, "author", d.meta[metaAuthor], "version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics, "deprecationMsg", d.modDeprecationMsg] @@ -1297,12 +1371,12 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) = proc writeOutputJson*(d: PDoc, useWarning = false) = runAllExamples(d) var modDesc: string - for desc in d.modDesc: + for desc in d.modDescFinal: modDesc &= desc let content = %*{"orig": d.filename, "nimble": getPackageName(d.conf, d.filename), "moduleDescription": modDesc, - "entries": d.jArray} + "entries": d.jEntriesFinal} if optStdout in d.conf.globalOptions: write(stdout, $content) else: @@ -1324,12 +1398,14 @@ proc handleDocOutputOptions*(conf: ConfigRef) = conf.outDir = AbsoluteDir(conf.outDir / conf.outFile) proc commandDoc*(cache: IdentCache, conf: ConfigRef) = + ## implementation of deprecated ``doc0`` command (without semantic checking) handleDocOutputOptions conf var ast = parseFile(conf.projectMainIdx, cache, conf) if ast == nil: return var d = newDocumentor(conf.projectFull, cache, conf) d.hasToc = true generateDoc(d, ast, ast) + finishGenerateDoc(d) writeOutput(d) generateIndex(d) @@ -1339,14 +1415,13 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; var d = newDocumentor(filen, cache, conf, outExt) d.isPureRst = true - var rst = parseRst(readFile(filen.string), filen.string, + let rst = parseRst(readFile(filen.string), filen.string, line=LineRstInit, column=ColRstInit, - d.hasToc, - {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown}, - conf) - var modDesc = newStringOfCap(30_000) - renderRstToOut(d[], rst, modDesc) - d.modDesc = modDesc + {roSupportRawDirective, roSupportMarkdown, + roPreferMarkdown}, conf, + d.sharedState) + d.modDescPre = @[ItemFragment(isRst: true, rst: rst)] + finishGenerateDoc(d) writeOutput(d) generateIndex(d) @@ -1357,6 +1432,7 @@ proc commandRst2TeX*(cache: IdentCache, conf: ConfigRef) = commandRstAux(cache, conf, conf.projectFull, TexExt) proc commandJson*(cache: IdentCache, conf: ConfigRef) = + ## implementation of a deprecated jsondoc0 command var ast = parseFile(conf.projectMainIdx, cache, conf) if ast == nil: return var d = newDocumentor(conf.projectFull, cache, conf) @@ -1366,7 +1442,8 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) = warnUser, "the ':test:' attribute is not supported by this backend") d.hasToc = true generateJson(d, ast) - let json = d.jArray + finishGenerateDoc(d) + let json = d.jEntriesFinal let content = pretty(json) if optStdout in d.conf.globalOptions: diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index d077ddc67..bfdb4568c 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -31,6 +31,7 @@ template closeImpl(body: untyped) {.dirty.} = let useWarning = sfMainModule notin g.module.flags let groupedToc = true if shouldProcess(g): + finishGenerateDoc(g.doc) body try: generateIndex(g.doc) diff --git a/compiler/main.nim b/compiler/main.nim index 7824e8cb2..1c8034c6c 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -282,7 +282,7 @@ proc mainCommand*(graph: ModuleGraph) = else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") of cmdDoc0: docLikeCmd commandDoc(cache, conf) - of cmdDoc2: + of cmdDoc: docLikeCmd(): conf.setNoteDefaults(warnLockLevel, false) # issue #13218 conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 diff --git a/compiler/options.nim b/compiler/options.nim index 05d8ee5b7..ffb0f4501 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -143,8 +143,8 @@ type cmdIdeTools # ide tools (e.g. nimsuggest) cmdNimscript # evaluate nimscript cmdDoc0 - cmdDoc2 - cmdDoc2tex + cmdDoc # convert .nim doc comments to HTML + cmdDoc2tex # convert .nim doc comments to LaTeX cmdRst2html # convert a reStructuredText file to HTML cmdRst2tex # convert a reStructuredText file to TeX cmdJsondoc0 @@ -161,7 +161,7 @@ type const cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCrun} - cmdDocLike* = {cmdDoc0, cmdDoc2, cmdDoc2tex, cmdJsondoc0, cmdJsondoc, + cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc, cmdCtags, cmdBuildindex} type diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 336caa2df..031a86d98 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -441,7 +441,7 @@ proc rawGetTok(L: var Lexer, tok: var Token) = inc L.col tok.col = max(tok.col - L.baseIndent, 0) -proc getTokens(buffer: string, tokens: var TokenSeq): int = +proc getTokens(buffer: string, tokens: var TokenSeq) = var L: Lexer var length = tokens.len L.buf = cstring(buffer) @@ -489,7 +489,7 @@ type autoSymIdx: int # order of occurence: fnAutoSymbol label: string # valid for fnAutoNumberLabel - SharedState = object + RstSharedState = object options: RstParseOptions # parsing options hLevels: LevelMap # hierarchy of heading styles hTitleCnt: int # =0 if no title, =1 if only main title, @@ -498,8 +498,8 @@ type currRole: string # current interpreted text role currRoleKind: RstNodeKind # ... and its node kind subs: seq[Substitution] # substitutions - refs: seq[Substitution] # references - anchors: seq[AnchorSubst] # internal target substitutions + refs*: seq[Substitution] # references + anchors*: seq[AnchorSubst] # internal target substitutions lineFootnoteNum: seq[int] # footnote line, auto numbers .. [#] lineFootnoteNumRef: seq[int] # footnote line, their reference [#]_ lineFootnoteSym: seq[int] # footnote line, auto symbols .. [*] @@ -508,19 +508,19 @@ type # number, order of occurrence msgHandler: MsgHandler # How to handle errors. findFile: FindFileHandler # How to find files. + filename: string + hasToc*: bool - PSharedState = ref SharedState + PRstSharedState* = ref RstSharedState RstParser = object of RootObj idx*: int tok*: TokenSeq - s*: PSharedState + s*: PRstSharedState indentStack*: seq[int] - filename*: string line*, col*: int ## initial line/column of whole text or ## documenation fragment that will be added ## in case of error/warning reporting to ## (relative) line/column of the token. - hasToc*: bool curAnchor*: string # variable to track latest anchor in s.anchors EParseError* = object of ValueError @@ -578,35 +578,42 @@ proc whichRoleAux(sym: string): RstNodeKind = else: # unknown role result = rnUnknownRole -proc newSharedState(options: RstParseOptions, - findFile: FindFileHandler, - msgHandler: MsgHandler): PSharedState = - new(result) - result.currRole = defaultRole(options) - result.currRoleKind = whichRoleAux(result.currRole) - result.subs = @[] - result.refs = @[] - result.options = options - result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler - result.findFile = if not isNil(findFile): findFile else: defaultFindFile +proc newRstSharedState*(options: RstParseOptions, + filename: string, + findFile: FindFileHandler, + msgHandler: MsgHandler): PRstSharedState = + let r = defaultRole(options) + result = PRstSharedState( + currRole: r, + currRoleKind: whichRoleAux(r), + options: options, + msgHandler: if not isNil(msgHandler): msgHandler else: defaultMsgHandler, + filename: filename, + findFile: if not isNil(findFile): findFile else: defaultFindFile + ) proc curLine(p: RstParser): int = p.line + currentTok(p).line proc findRelativeFile(p: RstParser; filename: string): string = - result = p.filename.splitFile.dir / filename + result = p.s.filename.splitFile.dir / filename if not fileExists(result): result = p.s.findFile(filename) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = - p.s.msgHandler(p.filename, curLine(p), + p.s.msgHandler(p.s.filename, curLine(p), p.col + currentTok(p).col, msgKind, arg) +proc rstMessage(s: PRstSharedState, msgKind: MsgKind, arg: string) = + ## Print warnings for footnotes/substitutions. + ## TODO: their line/column info is not known, to fix it. + s.msgHandler(s.filename, LineRstInit, ColRstInit, msgKind, arg) + proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) = - p.s.msgHandler(p.filename, p.line + line, + p.s.msgHandler(p.s.filename, p.line + line, p.col + col, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind) = - p.s.msgHandler(p.filename, curLine(p), + p.s.msgHandler(p.s.filename, curLine(p), p.col + currentTok(p).col, msgKind, currentTok(p).symbol) @@ -680,12 +687,10 @@ proc popInd(p: var RstParser) = # whether it should continue its processing or not, and decided not to, # then this B.E. handler should step back (e.g. do `dec p.idx`). -proc initParser(p: var RstParser, sharedState: PSharedState) = +proc initParser(p: var RstParser, sharedState: PRstSharedState) = p.indentStack = @[0] p.tok = @[] p.idx = 0 - p.filename = "" - p.hasToc = false p.col = ColRstInit p.line = LineRstInit p.s = sharedState @@ -754,14 +759,14 @@ proc rstnodeToRefname(n: PRstNode): string = var b = false rstnodeToRefnameAux(n, result, b) -proc findSub(p: var RstParser, n: PRstNode): int = +proc findSub(s: PRstSharedState, n: PRstNode): int = var key = addNodes(n) # the spec says: if no exact match, try one without case distinction: - for i in countup(0, high(p.s.subs)): - if key == p.s.subs[i].key: + for i in countup(0, high(s.subs)): + if key == s.subs[i].key: return i - for i in countup(0, high(p.s.subs)): - if cmpIgnoreStyle(key, p.s.subs[i].key) == 0: + for i in countup(0, high(s.subs)): + if cmpIgnoreStyle(key, s.subs[i].key) == 0: return i result = -1 @@ -783,10 +788,10 @@ proc setRef(p: var RstParser, key: string, value: PRstNode) = return p.s.refs.add(Substitution(key: key, value: value)) -proc findRef(p: var RstParser, key: string): PRstNode = - for i in countup(0, high(p.s.refs)): - if key == p.s.refs[i].key: - return p.s.refs[i].value +proc findRef(s: PRstSharedState, key: string): PRstNode = + for i in countup(0, high(s.refs)): + if key == s.refs[i].key: + return s.refs[i].value proc addAnchor(p: var RstParser, refn: string, reset: bool) = ## add anchor `refn` to anchor aliases and update last anchor ``curAnchor`` @@ -800,8 +805,8 @@ proc addAnchor(p: var RstParser, refn: string, reset: bool) = else: p.curAnchor = refn -proc findMainAnchor(p: RstParser, refn: string): string = - for subst in p.s.anchors: +proc findMainAnchor(s: PRstSharedState, refn: string): string = + for subst in s.anchors: if subst.mainAnchor == refn: # no need to rename result = subst.mainAnchor break @@ -838,28 +843,28 @@ proc addFootnoteSymAuto(p: var RstParser) = p.s.lineFootnoteSym.add curLine(p) p.s.footnotes.add((fnAutoSymbol, -1, -1, p.s.lineFootnoteSym.len, "")) -proc orderFootnotes(p: var RstParser) = +proc orderFootnotes(s: PRstSharedState) = ## numerate auto-numbered footnotes taking into account that all ## manually numbered ones always have preference. - ## Save the result back to p.s.footnotes. + ## Save the result back to `s.footnotes`. # Report an error if found any mismatch in number of automatic footnotes proc listFootnotes(lines: seq[int]): string = result.add $lines.len & " (lines " & join(lines, ", ") & ")" - if p.s.lineFootnoteNum.len != p.s.lineFootnoteNumRef.len: - rstMessage(p, meFootnoteMismatch, - "$1 != $2" % [listFootnotes(p.s.lineFootnoteNum), - listFootnotes(p.s.lineFootnoteNumRef)] & + if s.lineFootnoteNum.len != s.lineFootnoteNumRef.len: + rstMessage(s, meFootnoteMismatch, + "$1 != $2" % [listFootnotes(s.lineFootnoteNum), + listFootnotes(s.lineFootnoteNumRef)] & " for auto-numbered footnotes") - if p.s.lineFootnoteSym.len != p.s.lineFootnoteSymRef.len: - rstMessage(p, meFootnoteMismatch, - "$1 != $2" % [listFootnotes(p.s.lineFootnoteSym), - listFootnotes(p.s.lineFootnoteSymRef)] & + if s.lineFootnoteSym.len != s.lineFootnoteSymRef.len: + rstMessage(s, meFootnoteMismatch, + "$1 != $2" % [listFootnotes(s.lineFootnoteSym), + listFootnotes(s.lineFootnoteSymRef)] & " for auto-symbol footnotes") var result: seq[FootnoteSubst] var manuallyN, autoN, autoSymbol: seq[FootnoteSubst] - for fs in p.s.footnotes: + for fs in s.footnotes: if fs.kind == fnManualNumber: manuallyN.add fs elif fs.kind in {fnAutoNumber, fnAutoNumberLabel}: autoN.add fs else: autoSymbol.add fs @@ -906,26 +911,26 @@ proc orderFootnotes(p: var RstParser) = let label = footnoteAutoSymbols[symbolNum].repeat(nSymbols) result.add((fs.kind, -1, -1, fs.autoSymIdx, label)) - p.s.footnotes = result + s.footnotes = result -proc getFootnoteNum(p: var RstParser, label: string): int = +proc getFootnoteNum(s: PRstSharedState, label: string): int = ## get number from label. Must be called after `orderFootnotes`. result = -1 - for fnote in p.s.footnotes: + for fnote in s.footnotes: if fnote.label == label: return fnote.number -proc getFootnoteNum(p: var RstParser, order: int): int = +proc getFootnoteNum(s: PRstSharedState, order: int): int = ## get number from occurrence. Must be called after `orderFootnotes`. result = -1 - for fnote in p.s.footnotes: + for fnote in s.footnotes: if fnote.autoNumIdx == order: return fnote.number -proc getAutoSymbol(p: var RstParser, order: int): string = +proc getAutoSymbol(s: PRstSharedState, order: int): string = ## get symbol from occurrence of auto-symbol footnote. result = "???" - for fnote in p.s.footnotes: + for fnote in s.footnotes: if fnote.autoSymIdx == order: return fnote.label @@ -1765,17 +1770,18 @@ proc getLevel(p: var RstParser, c: char, hasOverline: bool): int = line: curLine(p), hasPeers: false) result = p.s.hLevels.len - 1 -proc countTitles(p: var RstParser, n: PRstNode) = - ## Fill `p.s.hTitleCnt` +proc countTitles(s: PRstSharedState, n: PRstNode) = + ## Fill `s.hTitleCnt` + if n == nil: return for node in n.sons: if node != nil: if node.kind notin {rnOverline, rnSubstitutionDef, rnDefaultRole}: break if node.kind == rnOverline: - if p.s.hLevels[p.s.hTitleCnt].hasPeers: + if s.hLevels[s.hTitleCnt].hasPeers: break - inc p.s.hTitleCnt - if p.s.hTitleCnt >= 2: + inc s.hTitleCnt + if s.hTitleCnt >= 2: break proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool = @@ -2103,8 +2109,7 @@ proc parseSimpleTable(p: var RstParser): PRstNode = initParser(q, p.s) q.col = cols[j] q.line = line - 1 - q.filename = p.filename - q.col += getTokens(row[j], q.tok) + getTokens(row[j], q.tok) b = newRstNode(rnTableDataCell) b.add(parseDoc(q)) a.add(b) @@ -2156,8 +2161,7 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = initParser(q, p.s) q.col = p.col q.line = currentTok(p).line - 1 - q.filename = p.filename - q.col += getTokens(getColContents(p, row[j]), q.tok) + getTokens(getColContents(p, row[j]), q.tok) b.add(parseDoc(q)) a.add(b) result.add(a) @@ -2562,8 +2566,8 @@ proc dirInclude(p: var RstParser): PRstNode = var q: RstParser initParser(q, p.s) - q.filename = path - q.col += getTokens( + q.s.filename = path + getTokens( inputString[startPosition..endPosition].strip(), q.tok) # workaround a GCC bug; more like the interior pointer bug? @@ -2806,7 +2810,27 @@ proc parseDotDot(p: var RstParser): PRstNode = else: result = parseComment(p) -proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = +proc rstParsePass1*(fragment, filename: string, + line, column: int, + options: RstParseOptions, + sharedState: PRstSharedState): PRstNode = + ## Parses an RST `fragment`. + ## The result should be further processed by + ## `preparePass2` and `resolveSubs` (which is pass 2). + var p: RstParser + initParser(p, sharedState) + p.line = line + p.col = column + getTokens(fragment, p.tok) + result = parseDoc(p) + +proc preparePass2*(s: PRstSharedState, mainNode: PRstNode) = + ## Records titles in node `mainNode` and orders footnotes. + countTitles(s, mainNode) + orderFootnotes(s) + +proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = + ## Makes pass 2 of RST parsing. ## Resolves substitutions and anchor aliases, groups footnotes. ## Takes input node `n` and returns the same node with recursive ## substitutions in `n.sons` to `result`. @@ -2814,32 +2838,32 @@ proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = if n == nil: return case n.kind of rnSubstitutionReferences: - var x = findSub(p, n) + var x = findSub(s, n) if x >= 0: - result = p.s.subs[x].value + result = s.subs[x].value else: var key = addNodes(n) var e = getEnv(key) if e != "": result = newLeaf(e) - else: rstMessage(p, mwUnknownSubstitution, key) + else: rstMessage(s, mwUnknownSubstitution, key) of rnHeadline, rnOverline: # fix up section levels depending on presence of a title and subtitle - if p.s.hTitleCnt == 2: + if s.hTitleCnt == 2: if n.level == 1: # it's the subtitle n.level = 0 elif n.level >= 2: # normal sections n.level -= 1 - elif p.s.hTitleCnt == 0: + elif s.hTitleCnt == 0: n.level += 1 of rnRef: let refn = rstnodeToRefname(n) - var y = findRef(p, refn) + var y = findRef(s, refn) if y != nil: result = newRstNode(rnHyperlink) let text = newRstNode(rnInner, n.sons) result.sons = @[text, y] else: - let s = findMainAnchor(p, refn) + let s = findMainAnchor(s, refn) if s != "": result = newRstNode(rnInternalRef) let text = newRstNode(rnInner, n.sons) @@ -2853,16 +2877,16 @@ proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = of fnAutoNumberLabel, fnAutoNumber: if fnType == fnAutoNumberLabel: let labelR = rstnodeToRefname(n.sons[0]) - num = getFootnoteNum(p, labelR) + num = getFootnoteNum(s, labelR) else: - num = getFootnoteNum(p, n.order) + num = getFootnoteNum(s, n.order) var nn = newRstNode(rnInner) nn.add newLeaf($num) result.sons[0] = nn of fnAutoSymbol: - let sym = getAutoSymbol(p, n.order) + let sym = getAutoSymbol(s, n.order) n.sons[0].sons[0].text = sym - n.sons[1] = resolveSubs(p, n.sons[1]) + n.sons[1] = resolveSubs(s, n.sons[1]) of rnFootnoteRef: var (fnType, num) = getFootnoteType(n.sons[0]) template addLabel(number: int | string) = @@ -2877,31 +2901,31 @@ proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = addLabel num refn.add $num of fnAutoNumber: - addLabel getFootnoteNum(p, n.order) + addLabel getFootnoteNum(s, n.order) refn.add $n.order of fnAutoNumberLabel: - addLabel getFootnoteNum(p, rstnodeToRefname(n)) + addLabel getFootnoteNum(s, rstnodeToRefname(n)) refn.add rstnodeToRefname(n) of fnAutoSymbol: - addLabel getAutoSymbol(p, n.order) + addLabel getAutoSymbol(s, n.order) refn.add $n.order of fnCitation: result.add n.sons[0] refn.add rstnodeToRefname(n) - let s = findMainAnchor(p, refn) - if s != "": - result.add newLeaf(s) # add link + let anch = findMainAnchor(s, refn) + if anch != "": + result.add newLeaf(anch) # add link else: - rstMessage(p, mwUnknownSubstitution, refn) + rstMessage(s, mwUnknownSubstitution, refn) result.add newLeaf(refn) # add link of rnLeaf: discard of rnContents: - p.hasToc = true + s.hasToc = true else: var regroup = false for i in 0 ..< n.len: - n.sons[i] = resolveSubs(p, n.sons[i]) + n.sons[i] = resolveSubs(s, n.sons[i]) if n.sons[i] != nil and n.sons[i].kind == rnFootnote: regroup = true if regroup: # group footnotes together into rnFootnoteGroup @@ -2924,13 +2948,10 @@ proc rstParse*(text, filename: string, options: RstParseOptions, findFile: FindFileHandler = nil, msgHandler: MsgHandler = nil): PRstNode = - var p: RstParser - initParser(p, newSharedState(options, findFile, msgHandler)) - p.filename = filename - p.line = line - p.col = column + getTokens(text, p.tok) - let unresolved = parseDoc(p) - countTitles(p, unresolved) - orderFootnotes(p) - result = resolveSubs(p, unresolved) - hasToc = p.hasToc + ## Parses the whole `text`. The result is ready for `rstgen.renderRstToOut`. + var sharedState = newRstSharedState(options, filename, findFile, msgHandler) + let unresolved = rstParsePass1(text, filename, line, column, + options, sharedState) + preparePass2(sharedState, unresolved) + result = resolveSubs(sharedState, unresolved) + hasToc = sharedState.hasToc diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx index b49a777c8..6dc3953af 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx @@ -1,8 +1,3 @@ -This is now a header subdir/subdir_b/utils.html#this-is-now-a-header This is now a header -Next header subdir/subdir_b/utils.html#this-is-now-a-header-next-header Next header -And so on subdir/subdir_b/utils.html#next-header-and-so-on And so on -More headers subdir/subdir_b/utils.html#more-headers More headers -Up to level 6 subdir/subdir_b/utils.html#more-headers-up-to-level-6 Up to level 6 enumValueA subdir/subdir_b/utils.html#enumValueA SomeType.enumValueA enumValueB subdir/subdir_b/utils.html#enumValueB SomeType.enumValueB enumValueC subdir/subdir_b/utils.html#enumValueC SomeType.enumValueC @@ -11,3 +6,8 @@ someType subdir/subdir_b/utils.html#someType_2 utils: someType(): SomeType aEnum subdir/subdir_b/utils.html#aEnum.t utils: aEnum(): untyped bEnum subdir/subdir_b/utils.html#bEnum.t utils: bEnum(): untyped fromUtilsGen subdir/subdir_b/utils.html#fromUtilsGen.t utils: fromUtilsGen(): untyped +This is now a header subdir/subdir_b/utils.html#this-is-now-a-header This is now a header +Next header subdir/subdir_b/utils.html#this-is-now-a-header-next-header Next header +And so on subdir/subdir_b/utils.html#next-header-and-so-on And so on +More headers subdir/subdir_b/utils.html#more-headers More headers +Up to level 6 subdir/subdir_b/utils.html#more-headers-up-to-level-6 Up to level 6 diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 34b172935..300229648 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -997,7 +997,7 @@ Test1 """ var error5 = new string let output5 = input5.toHtml(error=error5) - check(error5[] == "input(6, 1) Error: mismatch in number of footnotes " & + check(error5[] == "input(1, 1) Error: mismatch in number of footnotes " & "and their refs: 1 (lines 2) != 0 (lines ) for auto-numbered " & "footnotes") @@ -1011,7 +1011,7 @@ Test1 """ var error6 = new string let output6 = input6.toHtml(error=error6) - check(error6[] == "input(6, 1) Error: mismatch in number of footnotes " & + check(error6[] == "input(1, 1) Error: mismatch in number of footnotes " & "and their refs: 1 (lines 3) != 2 (lines 2, 6) for auto-symbol " & "footnotes") @@ -1034,7 +1034,8 @@ Test1 """ var warnings8 = new seq[string] let output8 = input8.toHtml(warnings=warnings8) - check(warnings8[] == @["input(4, 1) Warning: unknown substitution " & + # TODO: the line 1 is arbitrary because reference lines are not preserved + check(warnings8[] == @["input(1, 1) Warning: unknown substitution " & "\'citation-som\'"]) # check that footnote group does not break parsing of other directives: From 6030e139b5c630b5508dbe12d7b58c56264212b1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 20 Jun 2021 00:51:07 -0700 Subject: [PATCH 2730/4254] move {.injectStmt.} to experimental; add a test (#18300) * move {.injectStmt.} to experimental; add a test * undocument and deprecat `.injectStmt` but keep its implementation until we have a replacement --- compiler/pragmas.nim | 5 ++-- doc/manual.rst | 11 -------- doc/manual_experimental.rst | 1 + lib/pure/asyncdispatch.nim | 2 -- lib/system/gc_ms.nim | 1 + tests/pragmas/tinjectstmt.nim | 48 +++++++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 tests/pragmas/tinjectstmt.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 695e595c3..8ae931d84 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1183,6 +1183,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if sym == nil: invalidPragma(c, it) else: magicsys.registerNimScriptSymbol(c.graph, sym) of wInjectStmt: + warningDeprecated(c.config, it.info, "'.injectStmt' pragma is deprecated") if it.kind notin nkPragmaCallKinds or it.len != 2: localError(c.config, it.info, "expression expected") else: @@ -1194,10 +1195,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: c.selfName = considerQuotedIdent(c, it[1]) - message(c.config, n.info, warnDeprecated, "the '.this' pragma is deprecated") + message(c.config, n.info, warnDeprecated, "'.this' pragma is deprecated") elif it.kind == nkIdent or it.len == 1: c.selfName = getIdent(c.cache, "self") - message(c.config, n.info, warnDeprecated, "the '.this' pragma is deprecated") + message(c.config, n.info, warnDeprecated, "'.this' pragma is deprecated") else: localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments") of wNoRewrite: diff --git a/doc/manual.rst b/doc/manual.rst index 46a40a690..e8eec9a57 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7432,17 +7432,6 @@ work properly (in particular regarding constructor and destructor) for proc main()= var a {.threadvar.}: Foo -InjectStmt pragma ------------------ - -The `injectStmt` pragma can be used to inject a statement before every -other statement in the current module. It is only supposed to be used for -debugging: - -.. code-block:: nim - {.injectStmt: gcInvariants().} - - # ... complex code here that produces crashes ... compile-time define pragmas --------------------------- diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 3157708da..d10ef8d1b 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -380,6 +380,7 @@ pass multiple blocks to a macro: # code to undo it + Special Operators ================= diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 3866ebd24..b88d5ede8 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -176,8 +176,6 @@ export Port, SocketFlag export asyncfutures except callSoon export asyncstreams -#{.injectStmt: newGcInvariant().} - # TODO: Check if yielded future is nil and throw a more meaningful exception type diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index c20e93699..9e306c497 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -429,6 +429,7 @@ proc sweep(gch: var GcHeap) = else: freeCyclicCell(gch, c) when false: + # meant to be used with the now-deprected `.injectStmt`: {.injectStmt: newGcInvariant().} proc newGcInvariant*() = for x in allObjects(gch.region): if isCell(x): diff --git a/tests/pragmas/tinjectstmt.nim b/tests/pragmas/tinjectstmt.nim new file mode 100644 index 000000000..bca041e46 --- /dev/null +++ b/tests/pragmas/tinjectstmt.nim @@ -0,0 +1,48 @@ +discard """ + joinable: false + output:''' +onInject: 1 +onInject: 2 +ok0 +ok1 +onInject: 3 +onInject: 4 +0 +onInject: 5 +onInject: 6 +1 +onInject: 7 +onInject: 8 +2 +ok2 +onInject: 9 +''' +""" + +# test {.injectStmt.} + +#[ +{.injectStmt.} pragma can be used to inject a statement before every +other statement in the current module. It's now undocumented and may be removed +in the future and replaced with something more general and without its limitations. +e.g. (e.g. doesn't work in VM or js backends). +]# + +from system/ansi_c import c_printf + +var count = 0 +proc onInject*() = + count.inc + # echo count # xxx would fail, probably infinite recursion + c_printf("onInject: %d\n", cast[int](count)) + +{.injectStmt: onInject().} +echo "ok0" +proc main()= + echo "ok1" + for a in 0..<3: + echo a + echo "ok2" + +static: main() # xxx injectStmt not honred in VM +main() From e45b858f0402bbae428bdfa86f72613b69c2671a Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 20 Jun 2021 15:57:59 +0800 Subject: [PATCH 2731/4254] [std/terminal] improve docs a bit (#18296) * Revert "add missing import to asynchttpserver's example" This reverts commit 7ef364a402d3d827f10c893280f8dc7b9ef056f5. * alternative to #18185 * add std/mutexes * cvlose #17696 * Revert "add std/mutexes" This reverts commit 69abc8b64954206da6ffe5fc40a1142b39777762. * tiny * test * improve terminal docs * follow advice --- lib/pure/terminal.nim | 115 +++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 70 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index cada72196..283652bb3 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -16,6 +16,34 @@ ## Similarly, if you hide the cursor, make sure to unhide it with ## `showCursor` before quitting. +##[ +## Playing with colorful and styled text +]## + +## Procs like `styledWriteLine`, `styledEcho` etc. have a temporary effect on +## text parameters. Style parameters only affect the text parameter right after them. +## After being called, these procs will reset the default style of the terminal. +## While `setBackGroundColor`, `setForeGroundColor` etc. have a lasting +## influence on the terminal, you can use `resetAttributes` to +## reset the default style of the terminal. +runnableExamples("-r:off"): + stdout.styledWriteLine({styleBright, styleBlink, styleUnderscore}, "styled text ") + stdout.styledWriteLine(fgRed, "red text ") + stdout.styledWriteLine(fgWhite, bgRed, "white text in red background") + stdout.styledWriteLine(" ordinary text without style ") + + stdout.setBackGroundColor(bgCyan, true) + stdout.setForeGroundColor(fgBlue) + stdout.write("blue text in cyan background") + stdout.resetAttributes() + + # You can specify multiple text parameters. Style parameters + # only affect the text parameter right after them. + styledEcho styleBright, fgGreen, "[PASS]", resetStyle, fgGreen, " Yay!" + + stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text") + + import macros import strformat from strutils import toLowerAscii, `%` @@ -418,6 +446,9 @@ else: proc eraseLine*(f: File) = ## Erases the entire current line. + runnableExamples("-r:off"): + write(stdout, "never mind") + stdout.eraseLine() # nothing will be printed on the screen when defined(windows): let h = conHandle(f) var scrbuf: CONSOLE_SCREEN_BUFFER_INFO @@ -480,7 +511,7 @@ proc resetAttributes*(f: File) = gBG = 0 type - Style* = enum ## different styles for text output + Style* = enum ## Different styles for text output. styleBright = 1, ## bright text styleDim, ## dim text styleItalic, ## italic (or reverse on terminals not supporting) @@ -534,7 +565,7 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = stdout.write(ansiStyleCode(gBG)) type - ForegroundColor* = enum ## terminal's foreground colors + ForegroundColor* = enum ## Terminal's foreground colors. fgBlack = 30, ## black fgRed, ## red fgGreen, ## green @@ -546,7 +577,7 @@ type fg8Bit, ## 256-color (not supported, see `enableTrueColors` instead.) fgDefault ## default terminal foreground color - BackgroundColor* = enum ## terminal's background colors + BackgroundColor* = enum ## Terminal's background colors. bgBlack = 40, ## black bgRed, ## red bgGreen, ## green @@ -701,14 +732,10 @@ macro styledWrite*(f: File, m: varargs[typed]): untyped = ## When some argument is `Style`, `set[Style]`, `ForegroundColor`, ## `BackgroundColor` or `TerminalCmd` then it is not sent directly to ## `f`, but instead corresponding terminal style proc is called. - ## - ## Example: - ## - ## .. code-block:: nim - ## - ## stdout.styledWrite(fgRed, "red text ") - ## stdout.styledWrite(fgGreen, "green text") - ## + runnableExamples("-r:off"): + stdout.styledWrite(fgRed, "red text ") + stdout.styledWrite(fgGreen, "green text") + var reset = false result = newNimNode(nnkStmtList) @@ -731,14 +758,10 @@ macro styledWrite*(f: File, m: varargs[typed]): untyped = template styledWriteLine*(f: File, args: varargs[untyped]) = ## Calls `styledWrite` and appends a newline at the end. - ## - ## Example: - ## - ## .. code-block:: nim - ## - ## proc error(msg: string) = - ## styledWriteLine(stderr, fgRed, "Error: ", resetStyle, msg) - ## + runnableExamples: + proc error(msg: string) = + styledWriteLine(stderr, fgRed, "Error: ", resetStyle, msg) + styledWrite(f, args) write(f, "\n") @@ -747,7 +770,7 @@ template styledEcho*(args: varargs[untyped]) = stdout.styledWriteLine(args) proc getch*(): char = - ## Read a single character from the terminal, blocking until it is entered. + ## Reads a single character from the terminal, blocking until it is entered. ## The character is not printed to the terminal. when defined(windows): let fd = getStdHandle(STD_INPUT_HANDLE) @@ -852,7 +875,7 @@ when defined(windows): import os proc enableTrueColors*() = - ## Enable true color. + ## Enables true color. var term = getTerminal() when defined(windows): var @@ -885,7 +908,7 @@ proc enableTrueColors*() = term.trueColorIsEnabled = term.trueColorIsSupported proc disableTrueColors*() = - ## Disable true color. + ## Disables true color. var term = getTerminal() when defined(windows): if term.trueColorIsSupported: @@ -902,51 +925,3 @@ proc newTerminal(): owned(PTerminal) = new result when defined(windows): initTerminal(result) - -when not defined(testing) and isMainModule: - assert ansiStyleCode(styleBright) == "\e[1m" - assert ansiStyleCode(styleStrikethrough) == "\e[9m" - # exitprocs.addExitProc(resetAttributes) - write(stdout, "never mind") - stdout.eraseLine() - stdout.styledWriteLine({styleBright, styleBlink, styleUnderscore}, "styled text ") - stdout.styledWriteLine("italic text ", {styleItalic}) - stdout.setBackGroundColor(bgCyan, true) - stdout.setForeGroundColor(fgBlue) - stdout.write("blue text in cyan background") - stdout.resetAttributes() - echo "" - stdout.writeLine("ordinary text") - echo "more ordinary text" - styledEcho styleBright, fgGreen, "[PASS]", resetStyle, fgGreen, " Yay!" - echo "ordinary text again" - styledEcho styleBright, fgRed, "[FAIL]", resetStyle, fgRed, " Nay :(" - echo "ordinary text again" - setForeGroundColor(fgGreen) - echo "green text" - echo "more green text" - setForeGroundColor(fgBlue) - echo "blue text" - resetAttributes() - echo "ordinary text" - - stdout.styledWriteLine(fgRed, "red text ") - stdout.styledWriteLine(fgWhite, bgRed, "white text in red background") - stdout.styledWriteLine(" ordinary text ") - stdout.styledWriteLine(fgGreen, "green text") - - writeStyled("underscored text", {styleUnderscore}) - stdout.styledWrite(fgRed, " red text ") - writeStyled("bright text ", {styleBright}) - echo "ordinary text" - - stdout.styledWrite(fgRed, "red text ") - stdout.styledWrite(fgWhite, bgRed, "white text in red background") - stdout.styledWrite(" ordinary text ") - stdout.styledWrite(fgGreen, "green text") - echo "" - echo "ordinary text" - stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text") - stdout.styledWriteLine(bgYellow, "text in yellow bg", styleBright, - " bold text in yellow bg", bgDefault, " bold text") - echo "ordinary text" From eb0b323f452f5f06d74a4f747c50ae5115e44eae Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sun, 20 Jun 2021 15:51:13 +0300 Subject: [PATCH 2732/4254] Revert "disable pkg manu (#18292)" (#18307) This reverts commit fc76565574b86566e4a642b9aac541e025cf5de3. --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index efee361da..3d3c340eb 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -82,7 +82,7 @@ pkg "karax", "nim c -r tests/tester.nim" pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree" pkg "loopfusion" pkg "macroutils" -pkg "manu", allowFailure=true # pending https://github.com/planetis-m/manu/issues/5 +pkg "manu" pkg "markdown" pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" From 92cb765714325703d1a8e1b0409bfcd1b17af103 Mon Sep 17 00:00:00 2001 From: Heiko Nickerl Date: Sun, 20 Jun 2021 17:56:33 +0200 Subject: [PATCH 2733/4254] Raise IndexDefect when deleting element at out of bounds index (#17821) Co-authored-by: Timothee Cour Co-authored-by: Heiko Nickerl Co-authored-by: Heiko Nickerl --- changelog.md | 3 ++ lib/system.nim | 58 ++++++++++++++++++++--------------- tests/gc/gcleak3.nim | 8 ++--- tests/stdlib/tsystem.nim | 32 ++++++++++++++++++- tests/system/tsystem_misc.nim | 5 --- 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/changelog.md b/changelog.md index 80e38f420..5af195e59 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,9 @@ - `math.round` now is rounded "away from zero" in JS backend which is consistent with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. +- Instead of deleting the element at the last index, + `system.delete()` now raises `IndexDefect` when given index is out of bounds. + - Changed the behavior of `uri.decodeQuery` when there are unencoded `=` characters in the decoded values. Prior versions would raise an error. This is no longer the case to comply with the HTML spec and other languages diff --git a/lib/system.nim b/lib/system.nim index cae0ec3e2..a4608997a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1325,30 +1325,6 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = movingCopy(x[i], x[xl]) setLen(x, xl) -proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = - ## Deletes the item at index `i` by moving all `x[i+1..]` items by one position. - ## - ## This is an `O(n)` operation. - ## - ## See also: - ## * `del <#del,seq[T],Natural>`_ for O(1) operation - ## - ## .. code-block:: Nim - ## var i = @[1, 2, 3, 4, 5] - ## i.delete(2) # => @[1, 2, 4, 5] - template defaultImpl = - let xl = x.len - for j in i.int..xl-2: movingCopy(x[j], x[j+1]) - setLen(x, xl-1) - - when nimvm: - defaultImpl() - else: - when defined(js): - {.emit: "`x`.splice(`i`, 1);".} - else: - defaultImpl() - proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} = ## Inserts `item` into `x` at position `i`. ## @@ -2154,6 +2130,40 @@ const import system/dollars export dollars +proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = + ## Deletes the item at index `i` by moving all `x[i+1..^1]` items by one position. + ## + ## This is an `O(n)` operation. + ## + ## See also: + ## * `del <#del,seq[T],Natural>`_ for O(1) operation + ## + runnableExamples: + var s = @[1, 2, 3, 4, 5] + s.delete(2) + doAssert s == @[1, 2, 4, 5] + + doAssertRaises(IndexDefect): + s.delete(4) + + if i > high(x): + # xxx this should call `raiseIndexError2(i, high(x))` after some refactoring + raise (ref IndexDefect)(msg: "index out of bounds: '" & $i & "' < '" & $x.len & "' failed") + + template defaultImpl = + let xl = x.len + for j in i.int..xl-2: movingCopy(x[j], x[j+1]) + setLen(x, xl-1) + + when nimvm: + defaultImpl() + else: + when defined(js): + {.emit: "`x`.splice(`i`, 1);".} + else: + defaultImpl() + + const NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch ## is the version of Nim as a string. diff --git a/tests/gc/gcleak3.nim b/tests/gc/gcleak3.nim index 588e238e9..5e146d69f 100644 --- a/tests/gc/gcleak3.nim +++ b/tests/gc/gcleak3.nim @@ -17,14 +17,10 @@ for i in 0..1024: s.add(obj) proc limit*[t](a: var seq[t]) = - var loop = s.len() - 512 - for i in 0..loop: - #echo i - #GC_fullCollect() + while s.len > 0: if getOccupiedMem() > 3000_000: quit("still a leak!") - s.delete(i) + s.delete(0) s.limit() - echo "no leak: ", getOccupiedMem() diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim index f8b172b44..b48034043 100644 --- a/tests/stdlib/tsystem.nim +++ b/tests/stdlib/tsystem.nim @@ -2,9 +2,10 @@ discard """ targets: "c cpp js" """ +import stdtest/testutils + # TODO: in future work move existing `system` tests here, where they belong -import stdtest/testutils template main = block: # closure @@ -42,5 +43,34 @@ template main = # doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold outer() + block: # system.delete + block: + var s = @[1] + s.delete(0) + doAssert s == @[] + + block: + var s = @["foo", "bar"] + s.delete(1) + doAssert s == @["foo"] + + block: + var s: seq[string] + doAssertRaises(IndexDefect): + s.delete(0) + + block: + doAssert not compiles(@["foo"].delete(-1)) + + block: # bug #6710 + var s = @["foo"] + s.delete(0) + doAssert s == @[] + + block: # bug #16544: deleting out of bounds index should raise + var s = @["foo"] + doAssertRaises(IndexDefect): + s.delete(1) + static: main() main() diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index cb879d3b3..13b8c18a9 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -59,11 +59,6 @@ doAssert high(float) > low(float) doAssert high(float32) > low(float32) doAssert high(float64) > low(float64) -# bug #6710 -var s = @[1] -s.delete(0) - - proc foo(a: openArray[int]) = for x in a: echo x From 7d5e6b0169fb83c7682bfad5d675c21db785c324 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 20 Jun 2021 10:52:22 -0700 Subject: [PATCH 2734/4254] support `--hint:all:off --hint:x` (ditto with `--warnings` + friends) (#17852) * select all hints via `--hint:all:on|off`, etc * simplify code with setutils * address comment --- changelog.md | 4 +++ compiler/commands.nim | 59 +++++++++++++++++++++--------------------- compiler/condsyms.nim | 2 +- doc/advopt.txt | 15 ++++++----- tests/misc/trunner.nim | 9 +++---- 5 files changed, 45 insertions(+), 44 deletions(-) diff --git a/changelog.md b/changelog.md index 5af195e59..570aff542 100644 --- a/changelog.md +++ b/changelog.md @@ -429,6 +429,10 @@ - `--hint:CC` now goes to stderr (like all other hints) instead of stdout. +- `--hint:all:on|off` is now supported to select or deselect all hints; it + differs from `--hints:on|off` which acts as a (reversible) gate. + Likewise with `--warning:all:on|off`. + - json build instructions are now generated in `$nimcache/outFileBasename.json` instead of `$nimcache/projectName.json`. This allows avoiding recompiling a given project compiled with different options if the output file differs. diff --git a/compiler/commands.nim b/compiler/commands.nim index 8f8df71a7..4c1db8ead 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -25,10 +25,10 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") bootSwitch(usedGoGC, defined(gogc), "--gc:go") bootSwitch(usedNoGC, defined(nogc), "--gc:none") +import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs] import - os, msgs, options, nversion, condsyms, strutils, extccomp, platform, - wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos, - pathutils, strtabs, pathnorm + msgs, options, nversion, condsyms, extccomp, platform, + wordrecg, nimblecmd, lineinfos, pathutils, pathnorm from ast import eqTypeFlags, tfGcSafe, tfNoSideEffect @@ -182,7 +182,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, info: TLineInfo; orig: string; conf: ConfigRef) = var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off var i = 0 - var n = hintMin + var notes: set[TMsgKind] var isBracket = false if i < arg.len and arg[i] == '[': isBracket = true @@ -197,37 +197,36 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, if i == arg.len: discard elif i < arg.len and (arg[i] in {':', '='}): inc(i) else: invalidCmdLineOption(conf, pass, orig, info) - # unfortunately, hintUser and warningUser clash - if state in {wHint, wHintAsError}: - let x = findStr(hintMin, hintMax, id, errUnknown) - if x != errUnknown: n = TNoteKind(x) - else: localError(conf, info, "unknown hint: " & id) - else: - let x = findStr(warnMin, warnMax, id, errUnknown) - if x != errUnknown: n = TNoteKind(x) - else: localError(conf, info, "unknown warning: " & id) + let isSomeHint = state in {wHint, wHintAsError} + template findNote(noteMin, noteMax, name) = + # unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit + let x = findStr(noteMin, noteMax, id, errUnknown) + if x != errUnknown: notes = {TNoteKind(x)} + else: localError(conf, info, "unknown $#: $#" % [name, id]) + case id.normalize + of "all": # other note groups would be easy to support via additional cases + notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax} + elif isSomeHint: findNote(hintMin, hintMax, "hint") + else: findNote(warnMin, warnMax, "warning") var val = substr(arg, i).normalize if val == "": val = "on" if val notin ["on", "off"]: + # xxx in future work we should also allow users to have control over `foreignPackageNotes` + # so that they can enable `hints|warnings|warningAsErrors` for all the code they depend on. localError(conf, info, errOnOrOffExpectedButXFound % arg) - elif n notin conf.cmdlineNotes or pass == passCmd1: - if pass == passCmd1: incl(conf.cmdlineNotes, n) - incl(conf.modifiedyNotes, n) - case val - of "on": - if state in {wWarningAsError, wHintAsError}: - incl(conf.warningAsErrors, n) # xxx rename warningAsErrors to noteAsErrors - else: - incl(conf.notes, n) - incl(conf.mainPackageNotes, n) - of "off": - if state in {wWarningAsError, wHintAsError}: - excl(conf.warningAsErrors, n) - else: - excl(conf.notes, n) - excl(conf.mainPackageNotes, n) - excl(conf.foreignPackageNotes, n) + else: + let isOn = val == "on" + for n in notes: + if n notin conf.cmdlineNotes or pass == passCmd1: + if pass == passCmd1: incl(conf.cmdlineNotes, n) + incl(conf.modifiedyNotes, n) + if state in {wWarningAsError, wHintAsError}: + conf.warningAsErrors[n] = isOn # xxx rename warningAsErrors to noteAsErrors + else: + conf.notes[n] = isOn + conf.mainPackageNotes[n] = isOn + if not isOn: excl(conf.foreignPackageNotes, n) proc processCompile(conf: ConfigRef; filename: string) = var found = findFile(conf, filename) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ff0c603cb..b3f8465f0 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -134,5 +134,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasUnifiedTuple") defineSymbol("nimHasIterable") defineSymbol("nimHasTypeofVoid") - defineSymbol("nimHasDragonBox") + defineSymbol("nimHasHintAll") diff --git a/doc/advopt.txt b/doc/advopt.txt index e5b4c9568..b56649a86 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -48,14 +48,15 @@ Advanced options: --spellSuggest|:num show at most `num >= 0` spelling suggestions on typos. if `num` is not specified (or `auto`), return an implementation defined set of suggestions. - -w:on|off|list, --warnings:on|off|list - turn all warnings on|off or list all available - --warning:X:on|off turn specific warning X on|off. - `warning:X` means `warning:X:on`, as with similar flags. - --hints:on|off|list turn all hints on|off or list all available - --hint:X:on|off turn specific hint X on|off. - --warningAsError:X:on|off turn specific warning X into an error on|off + --hints:on|off|list. `on|off` enables or disables hints. + `list` reports which hints are selected. + --hint:X:on|off turn specific hint X on|off. `hint:X` means `hint:X:on`, + as with similar flags. `all` can be used for "all hints". --hintAsError:X:on|off turn specific hint X into an error on|off + -w:on|off|list, --warnings:on|off|list + same as `--hints` but for warnings. + --warning:X:on|off ditto + --warningAsError:X:on|off ditto --styleCheck:off|hint|error produce hints or errors for Nim identifiers that do not adhere to Nim's official style guide diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index f2ea1d040..77ae10f3d 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -23,9 +23,6 @@ proc isDots(a: string): bool = a.startsWith(".") and a.strip(chars = {'.'}) == "" const - defaultHintsOff = "--hint:successx:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" - # useful when you want to turn only some hints on, and some common ones off. - # pending https://github.com/timotheecour/Nim/issues/453, simplify to: `--hints:off` nim = getCurrentCompilerExe() mode = querySetting(backend) nimcache = buildDir / "nimcacheTrunner" @@ -236,7 +233,7 @@ sub/mmain.idx""", context check execCmdEx(cmd) == ("witness\n", 0) block: # config.nims, nim.cfg, hintConf, bug #16557 - let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf tests/newconfig/bar/mfoo.nim" + let cmd = fmt"{nim} r --hint:all:off --hint:conf tests/newconfig/bar/mfoo.nim" let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) doAssert exitCode == 0 let dir = getCurrentDir() @@ -268,7 +265,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines check fmt"""{nim} r -b:js {opt} --eval:"echo defined(js)"""".execCmdEx == ("true\n", 0) block: # `hintProcessing` dots should not interfere with `static: echo` + friends - let cmd = fmt"""{nim} r {defaultHintsOff} --hint:processing -f --eval:"static: echo 1+1"""" + let cmd = fmt"""{nim} r --hint:all:off --hint:processing -f --eval:"static: echo 1+1"""" let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) template check3(cond) = doAssert cond, $(outp,) doAssert exitCode == 0 @@ -282,7 +279,7 @@ tests/newconfig/bar/mfoo.nims""".splitLines check3 "2" in outp block: # nim secret - let opt = fmt"{defaultHintsOff} --hint:processing" + let opt = "--hint:all:off --hint:processing" template check3(cond) = doAssert cond, $(outp,) for extra in ["", "--stdout"]: let cmd = fmt"""{nim} secret {opt} {extra}""" From 1b3c0f142dd5abc3b3509feb194f54e6acf046c0 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 20 Jun 2021 21:00:42 +0300 Subject: [PATCH 2735/4254] validate rst field for :number-lines:, :status: (#18304) --- compiler/docgen.nim | 1 + compiler/lineinfos.nim | 2 ++ lib/packages/docutils/rst.nim | 1 + lib/packages/docutils/rstgen.nim | 30 ++++++++++++++++++++++-------- tests/stdlib/trstgen.nim | 12 ++++++++++++ 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 2c99adba3..08311eade 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -164,6 +164,7 @@ template declareClosures = of meNewSectionExpected: k = errNewSectionExpected of meGeneralParseError: k = errGeneralParseError of meInvalidDirective: k = errInvalidDirectiveX + of meInvalidRstField: k = errInvalidRstField of meFootnoteMismatch: k = errFootnoteMismatch of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel of mwUnknownSubstitution: k = warnUnknownSubstitutionX diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 052dae272..abe6bce7c 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -37,6 +37,7 @@ type errGeneralParseError, errNewSectionExpected, errInvalidDirectiveX, + errInvalidRstField, errFootnoteMismatch, errProveInit, # deadcode errGenerated, @@ -96,6 +97,7 @@ const errGeneralParseError: "general parse error", errNewSectionExpected: "new section expected $1", errInvalidDirectiveX: "invalid directive: '$1'", + errInvalidRstField: "invalid field: $1", errFootnoteMismatch: "number of footnotes and their references don't match: $1", errProveInit: "Cannot prove that '$1' is initialized.", # deadcode errGenerated: "$1", diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 031a86d98..64910aa19 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -225,6 +225,7 @@ type meNewSectionExpected = "new section expected $1", meGeneralParseError = "general parse error", meInvalidDirective = "invalid directive: '$1'", + meInvalidRstField = "invalid field: $1", meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1", mwRedefinitionOfLabel = "redefinition of label '$1'", mwUnknownSubstitution = "unknown substitution '$1'", diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index e3f889283..829177263 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -907,6 +907,25 @@ proc renderSmiley(d: PDoc, n: PRstNode, result: var string) = "\\includegraphics{$1}", [d.config.getOrDefault"doc.smiley_format" % n.text]) +proc getField1Int(d: PDoc, n: PRstNode, fieldName: string): int = + # TODO: proper column/line info + template err(msg: string) = + d.msgHandler(d.filename, 1, 0, meInvalidRstField, msg) + let value = n.getFieldValue + var number: int + let nChars = parseInt(value, number) + if nChars == 0: + if value.len == 0: + err("field $1 requires an argument" % [fieldName]) + else: + err("field $1 requires an integer, but '$2' was given" % + [fieldName, value]) + elif nChars < value.len: + err("extra arguments were given to $1: '$2'" % + [fieldName, value[nChars..^1]]) + else: + result = number + proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = ## Parses useful fields which can appear before a code block. ## @@ -916,9 +935,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = of "number-lines": params.numberLines = true # See if the field has a parameter specifying a different line than 1. - var number: int - if parseInt(n.getFieldValue, number) > 0: - params.startLine = number + params.startLine = getField1Int(d, n, "number-lines") of "file", "filename": # The ``file`` option is a Nim extension to the official spec, it acts # like it would for other directives like ``raw`` or ``cvs-table``. This @@ -936,9 +953,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = # consider whether `$docCmd` should be appended here too params.testCmd = unescape(params.testCmd) of "status", "exitcode": - var status: int - if parseInt(n.getFieldValue, status) > 0: - params.status = status + params.status = getField1Int(d, n, n.getArgument) of "default-language": params.langStr = n.getFieldValue.strip params.lang = params.langStr.getSourceLanguage @@ -954,7 +969,6 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = if n.isNil: return assert n.kind in {rnCodeBlock, rnInlineCode} - assert(not n.sons[2].isNil) # Parse the field list for rendering parameters if there are any. if not n.sons[1].isNil: @@ -1028,8 +1042,8 @@ proc renderCode(d: PDoc, n: PRstNode, result: var string) = ## option to differentiate between a plain code block and Nim's code block ## extension. assert n.kind in {rnCodeBlock, rnInlineCode} - if n.sons[2] == nil: return var params = d.parseCodeBlockParams(n) + if n.sons[2] == nil: return var m = n.sons[2].sons[0] assert m.kind == rnLeaf diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 300229648..d5d902e1d 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1136,6 +1136,18 @@ Test1 check "
    55\n
    " in output check "x" in output + test "Nim code-block indentation": + let input = dedent """ + .. code-block:: nim + :number-lines: 55 + let a = 1 + """ + var error = new string + let output = input.toHtml(error=error) + check(error[] == "input(1, 1) Error: invalid field: " & + "extra arguments were given to number-lines: ' let a = 1'") + check "" == output + test "RST admonitions": # check that all admonitions are implemented let input0 = dedent """ From 40ec8184ad51ccdaa6042132dc9b37b6f242c362 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 20 Jun 2021 13:49:14 -0700 Subject: [PATCH 2736/4254] followup #17852, disallow all:on for now (#18311) --- compiler/commands.nim | 2 ++ doc/advopt.txt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 4c1db8ead..1c3de29ba 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -217,6 +217,8 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, localError(conf, info, errOnOrOffExpectedButXFound % arg) else: let isOn = val == "on" + if isOn and id.normalize == "all": + localError(conf, info, "only 'all:off' is supported") for n in notes: if n notin conf.cmdlineNotes or pass == passCmd1: if pass == passCmd1: incl(conf.cmdlineNotes, n) diff --git a/doc/advopt.txt b/doc/advopt.txt index b56649a86..063d018d1 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -51,7 +51,8 @@ Advanced options: --hints:on|off|list. `on|off` enables or disables hints. `list` reports which hints are selected. --hint:X:on|off turn specific hint X on|off. `hint:X` means `hint:X:on`, - as with similar flags. `all` can be used for "all hints". + as with similar flags. `all` is the set of all hints + (only `all:off` is supported). --hintAsError:X:on|off turn specific hint X into an error on|off -w:on|off|list, --warnings:on|off|list same as `--hints` but for warnings. From abd21ef213b7368253050a18e5c4907d22992c8c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 21 Jun 2021 00:45:26 -0700 Subject: [PATCH 2737/4254] close #17403; improve docs for tuple (#18312) --- doc/manual.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index e8eec9a57..f80b03369 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1616,7 +1616,7 @@ heterogeneous storage types with few abstractions. The `()` syntax can be used to construct tuples. The order of the fields in the constructor must match the order of the tuple's definition. Different tuple-types are *equivalent* if they specify the same fields of the same type in the same -order. The *names* of the fields also have to be identical. +order. The *names* of the fields also have to be the same. The assignment operator for tuples copies each component. The default assignment operator for objects copies each component. Overloading @@ -1627,15 +1627,16 @@ of the assignment operator is described `here type Person = tuple[name: string, age: int] # type representing a person: - # a person consists of a name - # and an age - var - person: Person + # it consists of a name and an age. + var person: Person person = (name: "Peter", age: 30) - echo person.name + assert person.name == "Peter" # the same, but less readable: person = ("Peter", 30) - echo person[0] + assert person[0] == "Peter" + assert Person is (string, int) + assert (string, int) is Person + assert Person isnot tuple[other: string, age: int] # `other` is a different identifier A tuple with one unnamed field can be constructed with the parentheses and a trailing comma: From ad70a65e0e3eda39a3ca074af9feadb68f10598f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 21 Jun 2021 00:46:31 -0700 Subject: [PATCH 2738/4254] fix #18310 system.== in vm for NimNode (#18313) * fix #18310 == in vm * fixup * fixup --- compiler/vm.nim | 11 ++++++----- tests/vm/tvmmisc.nim | 11 +++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index b540ac071..837a1c366 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -10,14 +10,15 @@ ## This file implements the new evaluation engine for Nim code. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast except getstr import - strutils, msgs, vmdef, vmgen, nimsets, types, passes, - parser, vmdeps, idents, trees, renderer, options, transf, parseutils, - vmmarshal, gorgeimpl, lineinfos, tables, btrees, macrocacheimpl, + std/[strutils, tables, parseutils], + msgs, vmdef, vmgen, nimsets, types, passes, + parser, vmdeps, idents, trees, renderer, options, transf, + vmmarshal, gorgeimpl, lineinfos, btrees, macrocacheimpl, modulegraphs, sighashes, int128, vmprofiler +import ast except getstr from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate from magicsys import getSysType @@ -1026,7 +1027,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let nc = regs[rc].node if nb.kind != nc.kind: discard elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional - elif (nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ.kind == tyProc) and sameConstant(nb, nc): + elif nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ != nil and nb.typ.kind == tyProc and sameConstant(nb, nc): ret = true # this also takes care of procvar's, represented as nkTupleConstr, e.g. (nil, nil) elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index f0d2c2dbf..a4f6391cc 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -256,6 +256,17 @@ block: doAssert f == @[] +block: # bug #18310 + macro t() : untyped = + let + x = nnkTupleConstr.newTree(newLit(1)) + y = nnkTupleConstr.newTree(newLit(2)) + doAssert not (x == y) # not using != intentionally + doAssert not(cast[int](x) == cast[int](y)) + doAssert not(system.`==`(x, y)) + doAssert system.`==`(x, x) + t() + block: # bug #10815 type Opcode = enum From 2deb7011f5388559a70617c398360639102724c4 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 21 Jun 2021 18:50:47 +0800 Subject: [PATCH 2739/4254] fixes #17768 [backport:1.4] (#18317) * fixes #17768 [backport:1.4] * tiny --- lib/pure/unicode.nim | 10 ++++------ tests/stdlib/tunicode.nim | 9 ++++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 903f01fb4..dda631633 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -333,7 +333,7 @@ proc runeReverseOffset*(s: string, rev: Positive): (int, int) = ## from the end (starting with 1) and the total ## number of runes in the string. ## - ## Returns a negative value for offset if there are to few runes in + ## Returns a negative value for offset if there are too few runes in ## the string to satisfy the request. ## ## **Beware:** This can lead to unoptimized code and slow execution! @@ -346,16 +346,14 @@ proc runeReverseOffset*(s: string, rev: Positive): (int, int) = a = rev.int o = 0 x = 0 + let times = 2*rev.int-s.runeLen # transformed from rev.int - a < s.runeLen - rev.int while o < s.len: let r = runeLenAt(s, o) o += r - if a < 0: + if a > times: x += r dec a - - if a > 0: - return (-a, rev.int-a) - return (x, -a+rev.int) + result = if a > 0: (-a, rev.int-a) else: (x, -a+rev.int) proc runeAtPos*(s: string, pos: int): Rune = ## Returns the rune at position ``pos``. diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim index a346106f9..33405cf38 100644 --- a/tests/stdlib/tunicode.nim +++ b/tests/stdlib/tunicode.nim @@ -1,4 +1,4 @@ -import unicode +import std/unicode proc asRune(s: static[string]): Rune = @@ -213,3 +213,10 @@ block differentSizes: doAssert swapCase("ⱥbCd") == "ȺBcD" doAssert swapCase("XyꟆaB") == "xYᶎAb" doAssert swapCase("aᵹcᲈd") == "AꝽCꙊD" + +block: # bug #17768 + let s1 = "abcdef" + let s2 = "abcdéf" + + doAssert s1.runeSubstr(0, -1) == "abcde" + doAssert s2.runeSubstr(0, -1) == "abcdé" From d398c558a44ad346c2cfadf266a8cf808585de6d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 21 Jun 2021 03:51:00 -0700 Subject: [PATCH 2740/4254] close #13196 now that we have dragonbox (#18316) --- tests/stdlib/tjson.nim | 11 +++++++++++ tests/stdlib/tjsonutils.nim | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index e757e6c7e..289ef9d05 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -11,6 +11,8 @@ import std/[json,parsejson,strutils] from std/math import isNaN when not defined(js): import std/streams +import stdtest/testutils +from std/fenv import epsilon proc testRoundtrip[T](t: T, expected: string) = # checks that `T => json => T2 => json2` is such that json2 = json @@ -325,6 +327,15 @@ block: # bug #18007 let a = parseJson($(%NaN)).to(float) doAssert a.isNaN + whenRuntimeJs: discard # refs bug #18009 + do: + testRoundtripVal(0.0): "0.0" + testRoundtripVal(-0.0): "-0.0" + +block: # bug #15397, bug #13196 + testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" + testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" + block: let a = "18446744073709551615" let b = a.parseJson diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 88c05facf..31ec4316f 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -5,6 +5,7 @@ discard """ import std/jsonutils import std/json from std/math import isNaN, signbit +from std/fenv import epsilon from stdtest/testutils import whenRuntimeJs proc testRoundtrip[T](t: T, expected: string) = @@ -160,6 +161,16 @@ template fn() = doAssert b[2].signbit doAssert not b[3].signbit + block: # bug #15397, bug #13196 + let a = 0.1 + let x = 0.12345678901234567890123456789 + let b = (a + 0.2, 0.3, x) + testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]" + + testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" + testRoundtripVal(epsilon(float64)): "2.220446049250313e-16" + testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" + block: # case object type Foo = object x0: float From 16461a88101a398fd7349eb56392b27cdb285c17 Mon Sep 17 00:00:00 2001 From: xioren <40043405+xioren@users.noreply.github.com> Date: Mon, 21 Jun 2021 18:53:35 -0700 Subject: [PATCH 2741/4254] add multi type exception catching to manual (#18258) (#18323) --- doc/manual.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index f80b03369..a99c4b5af 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4462,10 +4462,8 @@ Example: echo "sum: " & $(parseInt(a) + parseInt(b)) except OverflowDefect: echo "overflow!" - except ValueError: - echo "could not convert string to integer" - except IOError: - echo "IO error!" + except ValueError, IOError: + echo "catch multiple exceptions!" except: echo "Unknown exception!" finally: From 9d3a813fb96950631c69858e8e26b6503abd02fe Mon Sep 17 00:00:00 2001 From: xioren <40043405+xioren@users.noreply.github.com> Date: Mon, 21 Jun 2021 18:56:16 -0700 Subject: [PATCH 2742/4254] convert code-blocks to runnableExamples in io (#18315) Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/system/io.nim | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 594c78209..62a9d1e18 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -912,14 +912,14 @@ iterator lines*(filename: string): string {.tags: [ReadIOEffect].} = ## If the file does not exist `IOError` is raised. The trailing newline ## character(s) are removed from the iterated lines. Example: ## - ## .. code-block:: nim - ## import std/strutils - ## - ## proc transformLetters(filename: string) = - ## var buffer = "" - ## for line in filename.lines: - ## buffer.add(line.replace("a", "0") & '\n') - ## writeFile(filename, buffer) + runnableExamples: + import std/strutils + + proc transformLetters(filename: string) = + var buffer = "" + for line in filename.lines: + buffer.add(line.replace("a", "0") & '\n') + writeFile(filename, buffer) var f = open(filename, bufSize=8000) try: var res = newStringOfCap(80) @@ -931,14 +931,13 @@ iterator lines*(f: File): string {.tags: [ReadIOEffect].} = ## Iterate over any line in the file `f`. ## ## The trailing newline character(s) are removed from the iterated lines. - ## Example: ## - ## .. code-block:: nim - ## proc countZeros(filename: File): tuple[lines, zeros: int] = - ## for line in filename.lines: - ## for letter in line: - ## if letter == '0': - ## result.zeros += 1 - ## result.lines += 1 + runnableExamples: + proc countZeros(filename: File): tuple[lines, zeros: int] = + for line in filename.lines: + for letter in line: + if letter == '0': + result.zeros += 1 + result.lines += 1 var res = newStringOfCap(80) while f.readLine(res): yield res From d8488e41e85c84a6b5fe687940b7fee10314d1f1 Mon Sep 17 00:00:00 2001 From: mantielero Date: Tue, 22 Jun 2021 06:19:11 +0200 Subject: [PATCH 2743/4254] readAsText supports both Blob and File (fixes #18187) (#18189) --- lib/js/dom.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 2b2332020..ca325fdd2 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1767,5 +1767,5 @@ since (1, 3): ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString proc readAsDataURL*(f: FileReader, b: Blob) {.importcpp: "#.readAsDataURL(#)".} ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL - proc readAsText*(f: FileReader, b: Blob, encoding = cstring"UTF-8") {.importcpp: "#.readAsText(#, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText + proc readAsText*(f: FileReader, b: Blob|File, encoding = cstring"UTF-8") {.importcpp: "#.readAsText(#, #)".} + ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText \ No newline at end of file From 037715285c088af46c94939f36abef63c95406e8 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 22 Jun 2021 18:44:56 +0800 Subject: [PATCH 2744/4254] fix #18327 (#18328) --- compiler/semtypes.nim | 2 +- tests/errmsgs/t18327.nim | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/errmsgs/t18327.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 38307a9ac..484997e3a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1295,7 +1295,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, let param = strTableGet(c.signatures, arg.name) if param != nil: typ = param.typ else: - localError(c.config, a.info, "parameter '$1' requires a type" % param.name.s) + localError(c.config, a.info, "parameter '$1' requires a type" % arg.name.s) typ = errorType(c) let lifted = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info) diff --git a/tests/errmsgs/t18327.nim b/tests/errmsgs/t18327.nim new file mode 100644 index 000000000..686a1bd0c --- /dev/null +++ b/tests/errmsgs/t18327.nim @@ -0,0 +1,5 @@ +discard """ + errormsg: "parameter 'n' requires a type" +""" + +proc fn3(n) = discard \ No newline at end of file From 9a81e91fa5d01cd6d60a408d0888dce4a9f49898 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 22 Jun 2021 23:02:32 +0800 Subject: [PATCH 2745/4254] merge similar procs regarding digits (#18318) --- lib/std/private/digitsutils.nim | 88 +++++++++++++++++++++++++++++++++ lib/system/dollars.nim | 23 ++++----- lib/system/dragonbox.nim | 32 ++---------- lib/system/schubfach.nim | 30 ++--------- lib/system/strmantle.nim | 65 +----------------------- 5 files changed, 105 insertions(+), 133 deletions(-) create mode 100644 lib/std/private/digitsutils.nim diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim new file mode 100644 index 000000000..cc985c7bd --- /dev/null +++ b/lib/std/private/digitsutils.nim @@ -0,0 +1,88 @@ +const + trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0] + + digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', + '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', + '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', + '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', + '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', + '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', + '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', + '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', + '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', + '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', + '9', '6', '9', '7', '9', '8', '9', '9'] + +# Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c +# Generates: +# .. code-block:: nim +# var res = "" +# for i in 0 .. 99: +# if i < 10: +# res.add "0" & $i +# else: +# res.add $i +# doAssert res == digits100 + +proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = + assert(digits <= 99) + buf[pos] = digits100[2 * digits] + buf[pos+1] = digits100[2 * digits + 1] + #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) + +proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = + assert(digits <= 99) + return trailingZeros100[digits] + +func digits10*(num: uint64): int {.noinline.} = + if num < 10'u64: + result = 1 + elif num < 100'u64: + result = 2 + elif num < 1_000'u64: + result = 3 + elif num < 10_000'u64: + result = 4 + elif num < 100_000'u64: + result = 5 + elif num < 1_000_000'u64: + result = 6 + elif num < 10_000_000'u64: + result = 7 + elif num < 100_000_000'u64: + result = 8 + elif num < 1_000_000_000'u64: + result = 9 + elif num < 10_000_000_000'u64: + result = 10 + elif num < 100_000_000_000'u64: + result = 11 + elif num < 1_000_000_000_000'u64: + result = 12 + else: + result = 12 + digits10(num div 1_000_000_000_000'u64) + +template numToString*(result: var string, origin: uint64, length: int) = + var num = origin + var next = length - 1 + const nbatch = 100 + + while num >= nbatch: + let originNum = num + num = num div nbatch + let index = (originNum - num * nbatch) shl 1 + result[next] = digits100[index + 1] + result[next - 1] = digits100[index] + dec(next, 2) + + # process last 1-2 digits + if num < 10: + result[next] = chr(ord('0') + num) + else: + let index = num * 2 + result[next] = digits100[index + 1] + result[next - 1] = digits100[index] diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 5a7a77e56..75390b0e1 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -1,3 +1,6 @@ +import std/private/digitsutils + + proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` ## converted to a decimal string. `$` is Nim's general way of @@ -6,22 +9,14 @@ proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} template dollarImpl(x: uint | uint64, result: var string) = type destTyp = typeof(x) if x == 0: - result = "0" - else: - result = newString(60) - var i = 0 - var n = x - while n != 0: - let nn = n div destTyp(10) - result[i] = char(n - destTyp(10) * nn + ord('0')) - inc i - n = nn - result.setLen i + return "0" + elif x == 1: + return "1" - let half = i div 2 - # Reverse - for t in 0 .. half-1: swap(result[t], result[i-t-1]) + let length = digits10(x) + setLen(result, length) + numToString(result, x, length) when defined(js): import std/private/since diff --git a/lib/system/dragonbox.nim b/lib/system/dragonbox.nim index eec8749da..336c982c1 100644 --- a/lib/system/dragonbox.nim +++ b/lib/system/dragonbox.nim @@ -21,6 +21,10 @@ ## Note: ## This function may temporarily write up to DtoaMinBufferLength characters into the buffer. + +import std/private/digitsutils + + const dtoaMinBufferLength*: cint = 64 @@ -1038,34 +1042,6 @@ proc toDecimal64*(ieeeSignificand: uint64; ieeeExponent: uint64): FloatingDecima ## ToChars ## ================================================================================================== -proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = - const - digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', - '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', - '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', - '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', - '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', - '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', - '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', - '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', - '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', - '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', - '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', - '9', '6', '9', '7', '9', '8', '9', '9'] - dragonbox_Assert(digits <= 99) - buf[pos] = digits100[2 * digits] - buf[pos+1] = digits100[2 * digits + 1] - #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) - -proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = - const - trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0] - dragonbox_Assert(digits <= 99) - return trailingZeros100[digits] - when false: template `+!`(x: cstring; offset: int): cstring = cast[cstring](cast[uint](x) + uint(offset)) diff --git a/lib/system/schubfach.nim b/lib/system/schubfach.nim index 94d3d3c25..5f974a79e 100644 --- a/lib/system/schubfach.nim +++ b/lib/system/schubfach.nim @@ -10,6 +10,9 @@ ## https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN ## -------------------------------------------------------------------------------------------------- +import std/private/digitsutils + + template sf_Assert(x: untyped): untyped = assert(x) @@ -233,33 +236,6 @@ proc toDecimal32(ieeeSignificand: uint32; ieeeExponent: uint32): FloatingDecimal ## ToChars ## ================================================================================================== -proc utoa2Digits(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = - const - digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', - '0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', - '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', - '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', - '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', - '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', - '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', - '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', - '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', - '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', - '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', - '9', '6', '9', '7', '9', '8', '9', '9'] - sf_Assert(digits <= 99) - buf[pos] = digits100[2 * digits] - buf[pos+1] = digits100[2 * digits + 1] - -proc trailingZeros2Digits(digits: uint32): int32 {.inline.} = - const - trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0] - sf_Assert(digits <= 99) - return trailingZeros100[digits] - proc printDecimalDigitsBackwards(buf: var openArray[char]; pos: int; output: uint32): int32 {.inline.} = var output = output var pos = pos diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 1a32a4afe..b60bc4b80 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -9,72 +9,9 @@ # Compilerprocs for strings that do not depend on the string implementation. -const digitsTable = "0001020304050607080910111213141516171819" & - "2021222324252627282930313233343536373839" & - "4041424344454647484950515253545556575859" & - "6061626364656667686970717273747576777879" & - "8081828384858687888990919293949596979899" - # Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c - # Generates: - # .. code-block:: nim - # var res = "" - # for i in 0 .. 99: - # if i < 10: - # res.add "0" & $i - # else: - # res.add $i - # doAssert res == digitsTable +import std/private/digitsutils -func digits10(num: uint64): int {.noinline.} = - if num < 10'u64: - result = 1 - elif num < 100'u64: - result = 2 - elif num < 1_000'u64: - result = 3 - elif num < 10_000'u64: - result = 4 - elif num < 100_000'u64: - result = 5 - elif num < 1_000_000'u64: - result = 6 - elif num < 10_000_000'u64: - result = 7 - elif num < 100_000_000'u64: - result = 8 - elif num < 1_000_000_000'u64: - result = 9 - elif num < 10_000_000_000'u64: - result = 10 - elif num < 100_000_000_000'u64: - result = 11 - elif num < 1_000_000_000_000'u64: - result = 12 - else: - result = 12 + digits10(num div 1_000_000_000_000'u64) - -template numToString(result: var string, origin: uint64, length: int) = - var num = origin - var next = length - 1 - const nbatch = 100 - - while num >= nbatch: - let originNum = num - num = num div nbatch - let index = (originNum - num * nbatch) shl 1 - result[next] = digitsTable[index + 1] - result[next - 1] = digitsTable[index] - dec(next, 2) - - # process last 1-2 digits - if num < 10: - result[next] = chr(ord('0') + num) - else: - let index = num * 2 - result[next] = digitsTable[index + 1] - result[next - 1] = digitsTable[index] - proc cmpStrings(a, b: string): int {.inline, compilerproc.} = let alen = a.len let blen = b.len From 5badeea17055c85ea8177baeee62c8d1d06ac13e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 22 Jun 2021 21:42:39 -0700 Subject: [PATCH 2746/4254] followup #18318: simplify `dollarImpl` and add a test (#18330) --- lib/system/dollars.nim | 7 ------- tests/stdlib/tdigitsutils.nim | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 tests/stdlib/tdigitsutils.nim diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 75390b0e1..3d824a965 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -7,15 +7,8 @@ proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} ## spelling `toString`:idx:. template dollarImpl(x: uint | uint64, result: var string) = - type destTyp = typeof(x) - if x == 0: - return "0" - elif x == 1: - return "1" - let length = digits10(x) setLen(result, length) - numToString(result, x, length) when defined(js): diff --git a/tests/stdlib/tdigitsutils.nim b/tests/stdlib/tdigitsutils.nim new file mode 100644 index 000000000..7cf63411f --- /dev/null +++ b/tests/stdlib/tdigitsutils.nim @@ -0,0 +1,23 @@ +import std/private/digitsutils + +template main = + block: # digits10 + doAssert digits10(0'u64) == 1 + # checks correctness on all powers of 10 + [0,-1,1] + var x = 1'u64 + var num = 1 + while true: + # echo (x, num) + doAssert digits10(x) == num + doAssert digits10(x+1) == num + if x > 1: + doAssert digits10(x-1) == num - 1 + num += 1 + let xOld = x + x *= 10 + if x < xOld: + # wrap-around + break + +static: main() +main() From 9c43f05099aaddae236df8b86da0cee342a785b8 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Wed, 23 Jun 2021 08:50:05 +0300 Subject: [PATCH 2747/4254] Markdown: allow to end URL with balanced parenthesis (#18321) * Markdown: allow to end URL with balanced parenthesis * Update lib/packages/docutils/rst.nim Co-authored-by: Timothee Cour * apply suggestion * remove unnecessary if Co-authored-by: Timothee Cour --- lib/packages/docutils/rst.nim | 36 ++++++++++++++++++++++++++++-- tests/stdlib/trst.nim | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 64910aa19..7833e6e9a 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1246,15 +1246,43 @@ proc isUrl(p: RstParser, i: int): bool = p.tok[i+3].kind == tkWord and p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"] +proc checkParen(token: Token, parensStack: var seq[char]): bool {.inline.} = + ## Returns `true` iff `token` is a closing parenthesis for some + ## previous opening parenthesis saved in `parensStack`. + ## This is according Markdown balanced parentheses rule + ## (https://spec.commonmark.org/0.29/#link-destination) + ## to allow links like + ## https://en.wikipedia.org/wiki/APL_(programming_language), + ## we use it for RST also. + result = false + if token.kind == tkPunct: + let c = token.symbol[0] + if c in {'(', '[', '{'}: # push + parensStack.add c + elif c in {')', ']', '}'}: # try pop + # a case like ([) inside a link is allowed and [ is also `pop`ed: + for i in countdown(parensStack.len - 1, 0): + if (parensStack[i] == '(' and c == ')' or + parensStack[i] == '[' and c == ']' or + parensStack[i] == '{' and c == '}'): + parensStack.setLen i + result = true + break + proc parseUrl(p: var RstParser): PRstNode = ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#standalone-hyperlinks result = newRstNode(rnStandaloneHyperlink) var lastIdx = p.idx + var closedParenIdx = p.idx - 1 # for balanced parens rule + var parensStack: seq[char] while p.tok[lastIdx].kind in {tkWord, tkPunct, tkOther}: + let isClosing = checkParen(p.tok[lastIdx], parensStack) + if isClosing: + closedParenIdx = lastIdx inc lastIdx dec lastIdx # standalone URL can not end with punctuation in RST - while lastIdx >= p.idx and p.tok[lastIdx].kind == tkPunct and + while lastIdx > closedParenIdx and p.tok[lastIdx].kind == tkPunct and p.tok[lastIdx].symbol != "/": dec lastIdx var s = "" @@ -1393,11 +1421,15 @@ proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = var desc, link = "" var i = p.idx + var parensStack: seq[char] template parse(endToken, dest) = + parensStack.setLen 0 inc i # skip begin token while true: if p.tok[i].kind in {tkEof, tkIndent}: return false - if p.tok[i].symbol == endToken: break + let isClosing = checkParen(p.tok[i], parensStack) + if p.tok[i].symbol == endToken and not isClosing: + break dest.add p.tok[i].symbol inc i inc i # skip end token diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index ec34edc91..c69450cd9 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -580,3 +580,44 @@ suite "RST inline markup": rnLeaf ' ' rnLeaf 'end' """) + + test "URL with balanced parentheses (Markdown rule)": + # 2 balanced parens, 1 unbalanced: + check(dedent""" + https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst == + dedent""" + rnInner + rnStandaloneHyperlink + rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))' + rnLeaf ')' + """) + + # the same for Markdown-style link: + check(dedent""" + [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst == + dedent""" + rnInner + rnHyperlink + rnLeaf 'foo [bar]' + rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))' + rnLeaf ')' + """) + + # unbalanced (here behavior is more RST-like actually): + check(dedent""" + https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst == + dedent""" + rnInner + rnStandaloneHyperlink + rnLeaf 'https://en.wikipedia.org/wiki/APL_(programming_language' + rnLeaf '(' + """) + + # unbalanced [, but still acceptable: + check(dedent""" + [my {link example](http://example.com/bracket_(symbol_[))""".toAst == + dedent""" + rnHyperlink + rnLeaf 'my {link example' + rnLeaf 'http://example.com/bracket_(symbol_[)' + """) From 0eee7f572796d3626db1d94d3eb344b399780db1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 23 Jun 2021 14:39:10 +0200 Subject: [PATCH 2748/4254] OS.nim: style changes (#18331) --- lib/pure/os.nim | 58 ++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 4dd5c8d8b..213da2aed 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -320,17 +320,17 @@ else: template `!=?`(a, b: char): bool = toLowerAscii(a) != toLowerAscii(b) when doslikeFileSystem: - proc isAbsFromCurrentDrive(path: string): bool {.noSideEffect, raises: []} = + proc isAbsFromCurrentDrive(path: string): bool {.noSideEffect, raises: [].} = ## An absolute path from the root of the current drive (e.g. "\foo") path.len > 0 and (path[0] == AltSep or (path[0] == DirSep and (path.len == 1 or path[1] notin {DirSep, AltSep, ':'}))) - proc isUNCPrefix(path: string): bool {.noSideEffect, raises: []} = + proc isUNCPrefix(path: string): bool {.noSideEffect, raises: [].} = path[0] == DirSep and path[1] == DirSep - proc sameRoot(path1, path2: string): bool {.noSideEffect, raises: []} = + proc sameRoot(path1, path2: string): bool {.noSideEffect, raises: [].} = ## Return true if path1 and path2 have a same root. ## ## Detail of windows path formats: @@ -935,7 +935,7 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", proc getCacheDir*(): string = ## Returns the cache directory of the current user for applications. - ## + ## ## This makes use of the following environment variables: ## ## * On Windows: `getEnv("LOCALAPPDATA")` @@ -1038,7 +1038,7 @@ proc expandTilde*(path: string): string {. ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing ## ``~`` with `getHomeDir() <#getHomeDir>`_ (otherwise returns ``path`` unmodified). ## - ## Windows: this is still supported despite Windows platform not having this + ## Windows: this is still supported despite the Windows platform not having this ## convention; also, both ``~/`` and ``~\`` are handled. ## ## .. warning:: `~bob` and `~bob/` are not yet handled correctly. @@ -1101,18 +1101,14 @@ proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1" proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote ``s``, so it can be safely passed to POSIX shell. - ## Based on Python's `pipes.quote`. const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@', '0'..'9', 'A'..'Z', 'a'..'z'} if s.len == 0: - return "''" - - let safe = s.allCharsInSet(safeUnixChars) - - if safe: - return s + result = "''" + elif s.allCharsInSet(safeUnixChars): + result = s else: - return "'" & s.replace("'", "'\"'\"'") & "'" + result = "'" & s.replace("'", "'\"'\"'") & "'" when defined(windows) or defined(posix) or defined(nintendoswitch): proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = @@ -1122,9 +1118,9 @@ when defined(windows) or defined(posix) or defined(nintendoswitch): ## <#quoteShellWindows,string>`_. Otherwise, calls `quoteShellPosix proc ## <#quoteShellPosix,string>`_. when defined(windows): - return quoteShellWindows(s) + result = quoteShellWindows(s) else: - return quoteShellPosix(s) + result = quoteShellPosix(s) proc quoteShellCommand*(args: openArray[string]): string = ## Concatenates and quotes shell arguments `args`. @@ -1217,7 +1213,7 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect] result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32 else: var res: Stat - return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode) + result = stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode) proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], @@ -1239,7 +1235,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32 else: var res: Stat - return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) + result = lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) when not defined(windows): @@ -1752,17 +1748,18 @@ proc isAdmin*: bool {.noWeirdTarget.} = addr administratorsGroup)): raiseOSError(osLastError(), "could not get SID for Administrators group") - defer: + try: + var b: WINBOOL + if not isSuccess(checkTokenMembership(0, administratorsGroup, addr b)): + raiseOSError(osLastError(), "could not check access token membership") + + result = isSuccess(b) + finally: if freeSid(administratorsGroup) != nil: raiseOSError(osLastError(), "failed to free SID for Administrators group") - var b: WINBOOL - if not isSuccess(checkTokenMembership(0, administratorsGroup, addr b)): - raiseOSError(osLastError(), "could not check access token membership") - - return isSuccess(b) else: - return geteuid() == 0 + result = geteuid() == 0 proc createSymlink*(src, dest: string) {.noWeirdTarget.} = ## Create a symbolic link at `dest` which points to the item specified @@ -1828,10 +1825,11 @@ when hasCCopyfile: COPYFILE_XATTR {.nodecl.}: copyfile_flags_t {.pop.} -type CopyFlag* = enum ## Copy options. - cfSymlinkAsIs, ## Copy symlinks as symlinks - cfSymlinkFollow, ## Copy the files symlinks point to - cfSymlinkIgnore ## Ignore symlinks +type + CopyFlag* = enum ## Copy options. + cfSymlinkAsIs, ## Copy symlinks as symlinks + cfSymlinkFollow, ## Copy the files symlinks point to + cfSymlinkIgnore ## Ignore symlinks const copyFlagSymlink = {cfSymlinkAsIs, cfSymlinkFollow, cfSymlinkIgnore} @@ -2027,7 +2025,7 @@ proc tryMoveFSObject(source, dest: string, isDir: bool): bool {.noWeirdTarget.} if not result: let err = osLastError() - let isAccessDeniedError = + let isAccessDeniedError = when defined(windows): const AccessDeniedError = OSErrorCode(5) isDir and err == AccessDeniedError @@ -2066,7 +2064,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", except: discard tryRemoveFile(dest) raise - + proc exitStatusLikeShell*(status: cint): cint = ## Converts exit code from `c_system` into a shell exit code. From 63456c6d7f84f29da38703fb3e59acf00acec1b8 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Wed, 23 Jun 2021 18:56:20 +0300 Subject: [PATCH 2749/4254] Add some tests (#18333) --- tests/destructor/tv2_cast.nim | 72 ++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index ef0b3a936..5502cb38d 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -1,10 +1,78 @@ discard """ - cmd: '''nim c --gc:arc $file''' output: '''@[1] @[116, 101, 115, 116] @[1953719668, 875770417]''' + cmd: '''nim c --gc:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file''' + nimout: '''--expandArc: main + +var + data + :tmpD +`=copy`(data, cast[string](encode(cast[seq[byte]]( + :tmpD = newString(100) + :tmpD)))) +`=destroy`(:tmpD) +`=destroy`(data) +-- end of expandArc ------------------------ +--expandArc: main1 + +var + s + data +s = newString(100) +`=copy`(data, cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1)))) +`=destroy`(data) +`=destroy`(s) +-- end of expandArc ------------------------ +--expandArc: main2 + +var + s + data +s = newSeq(100) +`=copy`(data, cast[string](encode(s))) +`=destroy`(data) +`=destroy_1`(s) +-- end of expandArc ------------------------ +--expandArc: main3 + +var + data + :tmpD +`=copy`(data, cast[string](encode do: + :tmpD = newSeq(100) + :tmpD)) +`=destroy`(:tmpD) +`=destroy_1`(data) +-- end of expandArc ------------------------''' """ +func encode*(src: openArray[byte]): seq[byte] = + result = newSeq[byte](src.len) + +template compress*(src: string): string = + cast[string](encode(cast[seq[byte]](src))) + +proc main = + let data = compress(newString(100)) +main() + +proc main1 = + var + s = newString(100) + let data = cast[string](encode(s.toOpenArrayByte(0, s.len-1))) +main1() + +proc main2 = + var + s = newSeq[byte](100) + let data = cast[string](encode(s)) +main2() + +proc main3 = + let data = cast[string](encode(newSeq[byte](100))) +main3() + # bug #11018 discard cast[seq[uint8]](@[1]) discard cast[seq[uint8]]("test") @@ -20,4 +88,4 @@ echo a #issue 11204 var ac {.compileTime.} = @["a", "b"] -const bc = ac.len \ No newline at end of file +const bc = ac.len From 496bd790e1b641a7c025bde2c6a1c6dca433ed5d Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 24 Jun 2021 03:33:19 +0800 Subject: [PATCH 2750/4254] [std/times]getTime now uses high resolution API on windows (#17901) --- lib/pure/times.nim | 5 +++-- lib/windows/winlean.nim | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index a92eccc8c..7bb393aa0 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -880,6 +880,7 @@ since((1, 1)): export fromUnixFloat export toUnixFloat + proc fromWinTime*(win: int64): Time = ## Convert a Windows file time (100-nanosecond intervals since ## `1601-01-01T00:00:00Z`) to a `Time`. @@ -912,7 +913,7 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} = result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) elif defined(windows): var f {.noinit.}: FILETIME - getSystemTimeAsFileTime(f) + getSystemTimePreciseAsFileTime(f) result = fromWinTime(rdFileTime(f)) proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = @@ -2595,7 +2596,7 @@ proc epochTime*(): float {.tags: [TimeEffect].} = toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 elif defined(windows): var f {.noinit.}: winlean.FILETIME - getSystemTimeAsFileTime(f) + getSystemTimePreciseAsFileTime(f) var i64 = rdFileTime(f) - epochDiff var secs = i64 div rateDiff var subsecs = i64 mod rateDiff diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index d2d7d26cc..a71dd97d8 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -928,6 +928,9 @@ proc getProcessTimes*(hProcess: Handle; lpCreationTime, lpExitTime, lpKernelTime, lpUserTime: var FILETIME): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetProcessTimes".} +proc getSystemTimePreciseAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {. + importc: "GetSystemTimePreciseAsFileTime", dynlib: "kernel32", stdcall, sideEffect.} + type inet_ntop_proc = proc(family: cint, paddr: pointer, pStringBuffer: cstring, stringBufSize: int32): cstring {.gcsafe, stdcall, tags: [].} From 0f91b67f5c15328330f74a8769aed9961940aab2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 23 Jun 2021 23:31:17 +0200 Subject: [PATCH 2751/4254] fixes #18326 (#18335) * fixes #18326 * make tests green again --- compiler/isolation_check.nim | 4 ++-- tests/isolate/tisolate.nim | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 43db5d59b..777e7f6ce 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -64,7 +64,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool = else: result = false -proc isValueOnlyType(t: PType): bool = +proc isValueOnlyType(t: PType): bool = # t doesn't contain pointers and references proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent} result = not types.searchTypeFor(t, wrap) @@ -88,7 +88,7 @@ proc checkIsolate*(n: PNode): bool = # XXX: as long as we don't update the analysis while examining arguments # we can do an early check of the return type, otherwise this is a # bug and needs to be moved below - if n[0].typ.flags * {tfGcSafe, tfNoSideEffect} == {}: + if tfNoSideEffect notin n[0].typ.flags: return false for i in 1.. Date: Wed, 23 Jun 2021 23:31:55 -0700 Subject: [PATCH 2752/4254] fix #18332: XDeclaredButNotUsed hints now in deterministic order (#18336) --- compiler/lookups.nim | 10 ++++++---- tests/errmsgs/treportunused.nim | 24 +++++++++++++----------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 4f413f472..ee79673d0 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -8,11 +8,10 @@ # # This module implements lookup helpers. - +import std/[algorithm, strutils] import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, nimfix/prettybase, lineinfos, strutils, - modulegraphs, astmsgs + renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -268,6 +267,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = var it: TTabIter var s = initTabIter(it, scope.symbols) var missingImpls = 0 + var unusedSyms: seq[tuple[sym: PSym, key: string]] while s != nil: if sfForward in s.flags and s.kind notin {skType, skModule}: # too many 'implementation of X' errors are annoying @@ -282,8 +282,10 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = # maybe they can be made skGenericParam as well. if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and s.typ.kind != tyGenericParam: - message(c.config, s.info, hintXDeclaredButNotUsed, s.name.s) + unusedSyms.add (s, toFileLineCol(c.config, s.info)) s = nextIter(it, scope.symbols) + for (s, _) in sortedByIt(unusedSyms, it.key): + message(c.config, s.info, hintXDeclaredButNotUsed, s.name.s) proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; conflictsWith: TLineInfo) = diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index b339e06bf..3e945013e 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -1,16 +1,18 @@ discard """ + matrix: "--hint:all:off --hint:XDeclaredButNotUsed" + nimoutFull: true nimout: ''' -treportunused.nim(19, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(26, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(22, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(25, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(24, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(23, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(20, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(29, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(27, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(21, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(28, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(21, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(22, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(23, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(24, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(25, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(26, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(27, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(28, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(29, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(30, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(31, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] ''' action: compile """ From 55c1953f636ff2d2e2b9e9599194fa6c3fb49050 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 24 Jun 2021 00:58:11 -0700 Subject: [PATCH 2753/4254] fix #18334: handle path with spaces on windows during bootstrap (#18337) --- compiler/nim.nim | 27 +++++++++++++++------------ koch.nim | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/nim.nim b/compiler/nim.nim index f18238f60..91b1bc2db 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -7,21 +7,24 @@ # distribution, for details about the copyright. # -when defined(gcc) and defined(windows): - when defined(x86): - {.link: "../icons/nim.res".} - else: - {.link: "../icons/nim_icon.o".} +import std/[os, strutils, parseopt] +when defined(windows) and not defined(nimKochBootstrap): + # remove workaround pending bootstrap >= 1.5.1 + # refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536 + # alternative would be to prepend `currentSourcePath.parentDir.quoteShell` + when defined(gcc): + when defined(x86): + {.link: "../icons/nim.res".} + else: + {.link: "../icons/nim_icon.o".} -when defined(amd64) and defined(windows) and defined(vcc): - {.link: "../icons/nim-amd64-windows-vcc.res".} -when defined(i386) and defined(windows) and defined(vcc): - {.link: "../icons/nim-i386-windows-vcc.res".} + when defined(amd64) and defined(vcc): + {.link: "../icons/nim-amd64-windows-vcc.res".} + when defined(i386) and defined(vcc): + {.link: "../icons/nim-i386-windows-vcc.res".} import - commands, options, msgs, - extccomp, strutils, os, main, parseopt, - idents, lineinfos, cmdlinehelper, + commands, options, msgs, extccomp, main, idents, lineinfos, cmdlinehelper, pathutils, modulegraphs from browsers import openDefaultBrowser diff --git a/koch.nim b/koch.nim index 665b5e042..51be53cc7 100644 --- a/koch.nim +++ b/koch.nim @@ -308,7 +308,7 @@ proc boot(args: string) = var nimi = i.thVersion if i == 0: nimi = nimStart - extraOption.add " --skipUserCfg --skipParentCfg" + extraOption.add " --skipUserCfg --skipParentCfg -d:nimKochBootstrap" # The configs are skipped for bootstrap # (1st iteration) to prevent newer flags from breaking bootstrap phase. let ret = execCmdEx(nimStart & " --version") From 0c8d3ae9852721147ddf878e204c14e949ed676a Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 24 Jun 2021 11:28:28 +0300 Subject: [PATCH 2754/4254] rst: allow comment to continue on second line (#18338) --- lib/packages/docutils/rst.nim | 28 ++++++--------- tests/stdlib/trst.nim | 66 +++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 7833e6e9a..8ffbbd4d3 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1615,24 +1615,16 @@ proc getDirective(p: var RstParser): string = "too many colons for a directive (should be ::)", p.tok[afterIdx].line, p.tok[afterIdx].col) -proc parseComment(p: var RstParser): PRstNode = - case currentTok(p).kind - of tkIndent, tkEof: - if currentTok(p).kind != tkEof and nextTok(p).kind == tkIndent: - inc p.idx # empty comment - else: - var indent = currentTok(p).ival - while true: - case currentTok(p).kind - of tkEof: - break - of tkIndent: - if currentTok(p).ival < indent: break - else: - discard - inc p.idx +proc parseComment(p: var RstParser, col: int): PRstNode = + if currentTok(p).kind != tkEof and nextTok(p).kind == tkIndent: + inc p.idx # empty comment else: - while currentTok(p).kind notin {tkIndent, tkEof}: inc p.idx + while currentTok(p).kind != tkEof: + if currentTok(p).kind == tkIndent and currentTok(p).ival > col or + currentTok(p).kind != tkIndent and currentTok(p).col > col: + inc p.idx + else: + break result = nil proc parseLine(p: var RstParser, father: PRstNode) = @@ -2841,7 +2833,7 @@ proc parseDotDot(p: var RstParser): PRstNode = (n = parseFootnote(p); n != nil): result = n else: - result = parseComment(p) + result = parseComment(p, col) proc rstParsePass1*(fragment, filename: string, line, column: int, diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index c69450cd9..d53092d3b 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -83,6 +83,72 @@ suite "RST parsing": rnLeaf 'set' """) + test "RST comment": + check(dedent""" + .. comment1 + comment2 + someParagraph""".toAst == + dedent""" + rnLeaf 'someParagraph' + """) + + check(dedent""" + .. + comment1 + comment2 + someParagraph""".toAst == + dedent""" + rnLeaf 'someParagraph' + """) + + test "check that additional line right after .. ends comment": + check(dedent""" + .. + + notAcomment1 + notAcomment2 + someParagraph""".toAst == + dedent""" + rnInner + rnBlockQuote + rnInner + rnLeaf 'notAcomment1' + rnLeaf ' ' + rnLeaf 'notAcomment2' + rnParagraph + rnLeaf 'someParagraph' + """) + + test "but blank lines after 2nd non-empty line don't end the comment": + check(dedent""" + .. + comment1 + + + comment2 + someParagraph""".toAst == + dedent""" + rnLeaf 'someParagraph' + """) + + test "using .. as separator b/w directives and block quotes": + check(dedent""" + .. note:: someNote + + .. + + someBlockQuote""".toAst == + dedent""" + rnInner + rnAdmonition adType=note + [nil] + [nil] + rnLeaf 'someNote' + rnBlockQuote + rnInner + rnLeaf 'someBlockQuote' + """) + suite "RST indentation": test "nested bullet lists": let input = dedent """ From 565e07a9936657fa356777eec5f0f52b2d5d7e02 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 24 Jun 2021 02:55:31 -0700 Subject: [PATCH 2755/4254] enable VM tracing in user code via `{.define(nimVmTrace).}` (#18244) * enable VM tracing in user code via `{.define(nimVmTrace).}` * add vmutils.vmTrace * add vmTrace --- changelog.md | 2 ++ compiler/options.nim | 1 + compiler/vm.nim | 7 +++++-- compiler/vmops.nim | 3 +++ lib/std/vmutils.nim | 11 +++++++++++ tests/stdlib/tvmutils.nim | 31 +++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 lib/std/vmutils.nim create mode 100644 tests/stdlib/tvmutils.nim diff --git a/changelog.md b/changelog.md index 570aff542..6672f7538 100644 --- a/changelog.md +++ b/changelog.md @@ -387,6 +387,8 @@ - Added `--declaredlocs` to show symbol declaration location in messages. +- You can now enable/disable VM tracing in user code via `vmutils.vmTrace`. + - Deprecated `TaintedString` and `--taintmode`. - Deprecated `--nilseqs` which is now a noop. diff --git a/compiler/options.nim b/compiler/options.nim index ffb0f4501..135ecf1de 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -330,6 +330,7 @@ type warnCounter*: int errorMax*: int maxLoopIterationsVM*: int ## VM: max iterations of all loops + isVmTrace*: bool configVars*: StringTableRef symbols*: StringTableRef ## We need to use a StringTableRef here as defined ## symbols are always guaranteed to be style diff --git a/compiler/vm.nim b/compiler/vm.nim index 837a1c366..9541af701 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -548,9 +548,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = "pc", $pc, "opcode", alignLeft($c.code[pc].opcode, 15), "ra", regDescr("ra", ra), "rb", regDescr("rb", instr.regB), "rc", regDescr("rc", instr.regC)] - + if c.config.isVmTrace: + # unlike nimVMDebug, this doesn't require re-compiling nim and is controlled by user code + let info = c.debug[pc] + # other useful variables: c.loopIterations + echo "$# [$#] $#" % [c.config$info, $instr.opcode, c.config.sourceLine(info)] c.profiler.enter(c, tos) - case instr.opcode of opcEof: return regs[ra] of opcRet: diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 85729fd59..67a196b8f 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -249,6 +249,9 @@ proc registerAdditionalOps*(c: PCtx) = "isExported() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info) setResult(a, sfExported in n.sym.flags) + registerCallback c, "stdlib.vmutils.vmTrace", proc (a: VmArgs) = + c.config.isVmTrace = getBool(a, 0) + proc hashVmImpl(a: VmArgs) = var res = hashes.hash(a.getString(0), a.getInt(1).int, a.getInt(2).int) if c.config.backend == backendJs: diff --git a/lib/std/vmutils.nim b/lib/std/vmutils.nim new file mode 100644 index 000000000..e16912a3c --- /dev/null +++ b/lib/std/vmutils.nim @@ -0,0 +1,11 @@ +##[ +Experimental API, subject to change. +]## + +proc vmTrace*(on: bool) {.compileTime.} = + runnableExamples: + static: vmTrace(true) + proc fn = + var a = 1 + vmTrace(false) + static: fn() diff --git a/tests/stdlib/tvmutils.nim b/tests/stdlib/tvmutils.nim new file mode 100644 index 000000000..f43557ad8 --- /dev/null +++ b/tests/stdlib/tvmutils.nim @@ -0,0 +1,31 @@ +discard """ + joinable: false + nimout: ''' +0 +1 +2 +tvmutils.nim(28, 13) [opcLdImmInt] if i == 4: +tvmutils.nim(28, 10) [opcEqInt] if i == 4: +tvmutils.nim(28, 10) [opcFJmp] if i == 4: +tvmutils.nim(28, 13) [opcLdImmInt] if i == 4: +tvmutils.nim(28, 10) [opcEqInt] if i == 4: +tvmutils.nim(28, 10) [opcFJmp] if i == 4: +tvmutils.nim(29, 7) [opcLdConst] vmTrace(false) +tvmutils.nim(29, 15) [opcLdImmInt] vmTrace(false) +tvmutils.nim(29, 14) [opcIndCall] vmTrace(false) +5 +6 +''' +""" +# line 20 (only showing a subset of nimout to avoid making the test rigid) +import std/vmutils + +proc main() = + for i in 0..<7: + echo i + if i == 2: + vmTrace(true) + if i == 4: + vmTrace(false) + +static: main() From 16038d44f6b246c5f39d1a8609a8c45f2cd005a4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 24 Jun 2021 18:37:04 +0200 Subject: [PATCH 2756/4254] fixes #18320 (#18343) * TSymFlag has 47 flags already * fixes #18320 --- compiler/ast.nim | 2 +- compiler/varpartitions.nim | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 8bb8de1d6..56043692f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -229,7 +229,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 46 flags! + TSymFlag* = enum # 47 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 697dd2b1d..213c3b80e 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -51,6 +51,7 @@ type SubgraphFlag = enum isMutated, # graph might be mutated isMutatedDirectly, # graph is mutated directly by a non-var parameter. + isMutatedByVarParam, # graph is mutated by a var parameter. connectsConstParam # graph is connected to a non-var parameter. VarFlag = enum @@ -184,7 +185,7 @@ proc potentialMutation(v: var Partitions; s: PSym; level: int; info: TLineInfo) {isMutated, isMutatedDirectly} elif s.typ.kind == tyVar and level <= 1: # varParam[i] = v is different from varParam[i][] = v - {} + {isMutatedByVarParam} else: {isMutated} else: @@ -878,7 +879,7 @@ proc computeGraphPartitions*(s: PSym; n: PNode; g: ModuleGraph; goals: set[Goal] proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = #echo "range ", v.aliveStart, " .. ", v.aliveEnd, " ", v.sym - if isMutated in g.flags: + if {isMutated, isMutatedByVarParam} * g.flags != {}: for m in g.mutations: #echo "mutation ", m if m in v.aliveStart..v.aliveEnd: @@ -941,4 +942,5 @@ proc computeCursors*(s: PSym; n: PNode; g: ModuleGraph) = discard "cannot cursor into a graph that is mutated" else: v.sym.flags.incl sfCursor - #echo "this is now a cursor ", v.sym, " ", par.s[rid].flags, " ", g.config $ v.sym.info + when false: + echo "this is now a cursor ", v.sym, " ", par.s[rid].flags, " ", g.config $ v.sym.info From f128f7971f6eda5dc9b21af3dbaeccc5dc71da5a Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Thu, 24 Jun 2021 13:19:50 -0400 Subject: [PATCH 2757/4254] float parsing: Add test for a fixed issue (#18232) Fixes https://github.com/nim-lang/Nim/issues/14407 . This issue was fixed by https://github.com/nim-lang/Nim/pull/18139. --- tests/errmsgs/treportunused.nim | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index 3e945013e..65e00163b 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -2,17 +2,19 @@ discard """ matrix: "--hint:all:off --hint:XDeclaredButNotUsed" nimoutFull: true nimout: ''' -treportunused.nim(21, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(22, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(23, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(24, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(25, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(26, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(27, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(28, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(29, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(30, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(31, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(23, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(24, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(25, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(26, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(27, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(28, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(29, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(30, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(31, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(32, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(33, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(37, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(38, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] ''' action: compile """ @@ -29,3 +31,8 @@ let s8 = 0 var s9: int type s10 = object type s11 = type(1.2) + +# https://github.com/nim-lang/Nim/issues/14407 +let + `v0.99` = "0.99" + `v0.99.99` = "0.99.99" From 6be8a66833ee25ad183fa3e4a667e3c0948413d8 Mon Sep 17 00:00:00 2001 From: Smooth Operator Date: Thu, 24 Jun 2021 13:48:57 -0400 Subject: [PATCH 2758/4254] couple tiny typo fixes (#18344) --- lib/pure/times.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 7bb393aa0..fb48a199c 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -359,7 +359,7 @@ type Timezone* = ref object ## \ ## Timezone interface for supporting `DateTime <#DateTime>`_\s of arbitrary ## timezones. The `times` module only supplies implementations for the - ## systems local time and UTC. + ## system's local time and UTC. zonedTimeFromTimeImpl: proc (x: Time): ZonedTime {.tags: [], raises: [], benign.} zonedTimeFromAdjTimeImpl: proc (x: Time): ZonedTime @@ -1145,7 +1145,7 @@ proc name*(zone: Timezone): string = ## If the timezone doesn't exist in the tz database, or if the timezone ## name is unknown, then any string that describes the timezone ## unambiguously might be used. For example, the string "LOCAL" is used - ## for the systems local timezone. + ## for the system's local timezone. ## ## See also: https://en.wikipedia.org/wiki/Tz_database zone.name From 0d194cdbf90953f28450c4bf1db744d2c1332996 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 25 Jun 2021 06:22:52 +0200 Subject: [PATCH 2759/4254] fixes #18287 (#18346) --- compiler/varpartitions.nim | 48 ++++++++++++++++----------------- tests/arc/topt_no_cursor.nim | 51 +++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 213c3b80e..8f422face 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -416,7 +416,6 @@ proc allRoots(n: PNode; result: var seq[(PSym, int)]; level: int) = proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = ## Analyse if 'n' is an expression that owns the data, if so mark 'dest' ## with 'ownsData'. - if n.typ == nil: return case n.kind of nkEmpty, nkCharLit..nkNilLit: # primitive literals including the empty are harmless: @@ -475,30 +474,31 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = destMightOwn(c, dest, n[0]) of nkCallKinds: - if hasDestructor(n.typ): - # calls do construct, what we construct must be destroyed, - # so dest cannot be a cursor: - dest.flags.incl ownsData - elif n.typ.kind in {tyLent, tyVar}: - # we know the result is derived from the first argument: - var roots: seq[(PSym, int)] - allRoots(n[1], roots, RootEscapes) - for r in roots: - connect(c, dest.sym, r[0], n[1].info) + if n.typ != nil: + if hasDestructor(n.typ): + # calls do construct, what we construct must be destroyed, + # so dest cannot be a cursor: + dest.flags.incl ownsData + elif n.typ.kind in {tyLent, tyVar}: + # we know the result is derived from the first argument: + var roots: seq[(PSym, int)] + allRoots(n[1], roots, RootEscapes) + for r in roots: + connect(c, dest.sym, r[0], n[1].info) - else: - let magic = if n[0].kind == nkSym: n[0].sym.magic else: mNone - # this list is subtle, we try to answer the question if after 'dest = f(src)' - # there is a connection betwen 'src' and 'dest' so that mutations to 'src' - # also reflect 'dest': - if magic in {mNone, mMove, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mArrToSeq}: - for i in 1.. Date: Fri, 25 Jun 2021 14:12:23 +0200 Subject: [PATCH 2760/4254] fixes #18240 (#18354) * ORC: track escaping parameters properly * fixes #18240 --- compiler/sempass2.nim | 37 +++++++++++++++++++++++++------------ tests/arc/torcmisc.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e66c9596a..e124baf26 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -77,6 +77,7 @@ type config: ConfigRef graph: ModuleGraph c: PContext + escapingParams: IntSet PEffects = var TEffects proc `<`(a, b: TLockLevel): bool {.borrow.} @@ -900,6 +901,25 @@ proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) = localError(tracked.config, pragma.info, "invalid pragma block: " & $pragma) +proc trackInnerProc(tracked: PEffects, n: PNode) = + case n.kind + of nkSym: + let s = n.sym + if s.kind == skParam and s.owner == tracked.owner: + tracked.escapingParams.incl s.id + of nkNone..pred(nkSym), succ(nkSym)..nkNilLit: + discard + of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo: + if n[0].kind == nkSym and n[0].sym.ast != nil: + trackInnerProc(tracked, getBody(tracked.graph, n[0].sym)) + of nkTypeSection, nkMacroDef, nkTemplateDef, nkError, + nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, + nkTypeOfExpr, nkMixinStmt, nkBindStmt: + discard + else: + for ch in n: trackInnerProc(tracked, ch) + proc track(tracked: PEffects, n: PNode) = case n.kind of nkSym: @@ -1095,8 +1115,10 @@ proc track(tracked: PEffects, n: PNode) = track(tracked, n.lastSon) unapplyBlockContext(tracked, bc) - of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, - nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef: + of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo: + if n[0].kind == nkSym and n[0].sym.ast != nil: + trackInnerProc(tracked, getBody(tracked.graph, n[0].sym)) + of nkTypeSection, nkMacroDef, nkTemplateDef: discard of nkCast: if n.len == 2: @@ -1259,15 +1281,6 @@ proc hasRealBody(s: PSym): bool = ## which is not a real implementation, refs #14314 result = {sfForward, sfImportc} * s.flags == {} -proc maybeWrappedInClosure(tracked: PEffects; t: PType): bool {.inline.} = - ## The spec does say when to produce destructors. However, the spec - ## was written in mind with the idea that "lambda lifting" already - ## happened. Not true in our implementation, so we need to workaround - ## here: - result = tracked.isInnerProc and - sfSystemModule notin tracked.c.module.flags and - tfCheckedForDestructor notin t.flags and containsGarbageCollectedRef(t) - proc trackProc*(c: PContext; s: PSym, body: PNode) = let g = c.graph var effects = s.typ.n[0] @@ -1287,7 +1300,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let typ = param.typ if isSinkTypeForParam(typ) or (t.config.selectedGC in {gcArc, gcOrc} and - (isClosure(typ.skipTypes(abstractInst)) or maybeWrappedInClosure(t, typ))): + (isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)): createTypeBoundOps(t, typ, param.info) when false: if typ.kind == tyOut and param.id notin t.init: diff --git a/tests/arc/torcmisc.nim b/tests/arc/torcmisc.nim index 20dd18fb3..e41ad7c77 100644 --- a/tests/arc/torcmisc.nim +++ b/tests/arc/torcmisc.nim @@ -32,3 +32,35 @@ when true: waitFor hello(Flags()) echo "success" +# bug #18240 +import tables + +type + TopicHandler* = proc(topic: string, + data: seq[byte]): Future[void] {.gcsafe, raises: [Defect].} + + PeerID* = object + data*: seq[byte] + + PeerInfo* = ref object of RootObj + peerId*: PeerID + + Connection* = ref object of RootObj + peerInfo*: PeerInfo + + PubSubPeer* = ref object of RootObj + codec*: string + + PubSub* = ref object of RootObj + topics*: Table[string, seq[TopicHandler]] + peers*: Table[PeerID, PubSubPeer] + +proc getOrCreatePeer*(myParam: PubSub, peerId: PeerID, protos: seq[string]): PubSubPeer = + myParam.peers.withValue(peerId, peer): + return peer[] + +method handleConn*(myParam: PubSub, + conn: Connection, + proto: string) {.base, async.} = + myParam.peers.withValue(conn.peerInfo.peerId, peer): + let peerB = peer[] From 8535b26a754b2daea46627019e3145d7c12d826e Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 25 Jun 2021 07:47:10 -0700 Subject: [PATCH 2761/4254] docs now show nimExperimentalX APIs (#18345) * docs now show nimExperimentalX APIs * fix for windows --- lib/std/jsfetch.nim | 2 +- lib/wrappers/linenoise/linenoise.nim | 12 ++++++------ tests/config.nims | 3 +++ tools/kochdocs.nim | 3 ++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/std/jsfetch.nim b/lib/std/jsfetch.nim index 36bc772d5..1e7bb4d29 100644 --- a/lib/std/jsfetch.nim +++ b/lib/std/jsfetch.nim @@ -3,7 +3,7 @@ when not defined(js): {.fatal: "Module jsfetch is designed to be used with the JavaScript backend.".} -when defined(nimExperimentalJsfetch) or defined(nimdoc): +when defined(nimExperimentalJsfetch): import std/[asyncjs, jsheaders, jsformdata] from std/httpcore import HttpMethod from std/jsffi import JsObject diff --git a/lib/wrappers/linenoise/linenoise.nim b/lib/wrappers/linenoise/linenoise.nim index 5b1fa7190..186b3b252 100644 --- a/lib/wrappers/linenoise/linenoise.nim +++ b/lib/wrappers/linenoise/linenoise.nim @@ -32,17 +32,17 @@ proc printKeyCodes*() {.importc: "linenoisePrintKeyCodes".} proc free*(s: cstring) {.importc: "free", header: "".} -when defined nimExperimentalLinenoiseExtra: +when defined(nimExperimentalLinenoiseExtra) and not defined(windows): # C interface - type linenoiseStatus = enum + type LinenoiseStatus = enum linenoiseStatus_ctrl_unknown linenoiseStatus_ctrl_C linenoiseStatus_ctrl_D - type linenoiseData* = object - status: linenoiseStatus + type LinenoiseData* = object + status: LinenoiseStatus - proc linenoiseExtra(prompt: cstring, data: ptr linenoiseData): cstring {.importc.} + proc linenoiseExtra(prompt: cstring, data: ptr LinenoiseData): cstring {.importc.} # stable nim interface type Status* = enum @@ -65,7 +65,7 @@ when defined nimExperimentalLinenoiseExtra: if ret.line.len > 0: echo ret.line if ret.status == lnCtrlD: break echo "exiting" - var data: linenoiseData + var data: LinenoiseData let buf = linenoiseExtra(prompt, data.addr) result.line = $buf free(buf) diff --git a/tests/config.nims b/tests/config.nims index 578b69e76..539de5e8d 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -30,4 +30,7 @@ hint("Processing", off) # switch("hint", "ConvFromXtoItselfNotNeeded") # experimental API's are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 +# sync with `kochdocs.docDefines` or refactor. switch("define", "nimExperimentalAsyncjsThen") +switch("define", "nimExperimentalJsfetch") +switch("define", "nimExperimentalLinenoiseExtra") diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index f25564fad..469059348 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -8,7 +8,8 @@ const gaCode* = " --doc.googleAnalytics:UA-48159761-1" # errormax: subsequent errors are probably consequences of 1st one; a simple # bug could cause unlimited number of errors otherwise, hard to debug in CI. - nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off --hint:XDeclaredButNotUsed:off --warning:UnusedImport:off -d:boot --putenv:nimversion=$#" % system.NimVersion + docDefines = "-d:nimExperimentalAsyncjsThen -d:nimExperimentalJsfetch -d:nimExperimentalLinenoiseExtra" + nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off --hint:XDeclaredButNotUsed:off --warning:UnusedImport:off -d:boot --putenv:nimversion=$# $#" % [system.NimVersion, docDefines] gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" webUploadOutput = "web/upload" From f6bea08eac7938e460ca9088693f0cf3f274e75b Mon Sep 17 00:00:00 2001 From: tomc1998 Date: Fri, 25 Jun 2021 21:06:24 +0100 Subject: [PATCH 2762/4254] Add sink annotation to option some() (#18358) --- lib/pure/options.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index bd5aa389e..850bfa555 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -92,7 +92,7 @@ type UnpackDefect* = object of Defect UnpackError* {.deprecated: "See corresponding Defect".} = UnpackDefect -proc option*[T](val: T): Option[T] {.inline.} = +proc option*[T](val: sink T): Option[T] {.inline.} = ## Can be used to convert a pointer type (`ptr`, `pointer`, `ref` or `proc`) to an option type. ## It converts `nil` to `none(T)`. When `T` is no pointer type, this is equivalent to `some(val)`. ## @@ -112,7 +112,7 @@ proc option*[T](val: T): Option[T] {.inline.} = when T isnot SomePointer: result.has = true -proc some*[T](val: T): Option[T] {.inline.} = +proc some*[T](val: sink T): Option[T] {.inline.} = ## Returns an `Option` that has the value `val`. ## ## **See also:** From 39fbf3c84bd83613407e22b3de215d9a221b9422 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 26 Jun 2021 03:39:52 +0200 Subject: [PATCH 2763/4254] ensure 'koch boot --gc:orc' stays green (#18353) * ensure 'koch boot --gc:orc' stays green * disable for C++ code generator for now --- koch.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/koch.nim b/koch.nim index 51be53cc7..6a0b7a0d3 100644 --- a/koch.nim +++ b/koch.nim @@ -582,6 +582,11 @@ proc runCI(cmd: string) = when defined(posix): execFold("Run nimsuggest tests", "nim r nimsuggest/tester") + when not defined(bsd): + if not doUseCpp: + # the BSDs are overwhelmed already, so only run this test on the other machines: + kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib") + proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) xz(false, cmdLineRest) From b8f761b7e2cb3f28abd6486d28ea19228887cdf5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 26 Jun 2021 06:21:46 -0700 Subject: [PATCH 2764/4254] even lighter version of #17938: fix most issues with UnusedImport, XDeclaredButNotUsed, etc; fix #17511, #17510, #14246 (without realModule) (#18362) * {.used: symbol} * add tests * fix tests with --import * --import works without giving spurious unused warnings * new warning warnDuplicateModuleImport for `import foo; import foo` * fix test, add resolveModuleAlias, use proper line info for module aliases * fix spurious warnings * fix deprecation msg for deprecated modules even with `import foo as bar` * disable a test for i386 pending sorting XDeclaredButNotUsed errors * UnusedImport now works with re-exported symbols * fix typo [skip ci] * ic support * add genPNode to allow writing PNode-based compiler code similarly to `genAst` * fix DuplicateModuleImport warning * adjust test * fixup * fixup * fixup * fix after rebase * fix for IC * keep the proc inline, move the const out * [skip ci] fix changelog * experiment: remove calls to resolveModuleAlias * followup * fixup * fix tests/modules/tselfimport.nim * workaround tests/deprecated/tmodule1.nim * fix properly * simplify --- compiler/importer.nim | 34 +++++++++-------- compiler/lineinfos.nim | 2 + compiler/lookups.nim | 18 +++++---- compiler/passaux.nim | 2 +- lib/system/schubfach.nim | 59 +++++++++++++++--------------- testament/categories.nim | 1 + tests/deprecated/tmodule1.nim | 22 ++++++++--- tests/modules/tselfimport.nim | 2 +- tests/pragmas/mused2a.nim | 23 ++++++++++++ tests/pragmas/mused2b.nim | 3 ++ tests/pragmas/mused2c.nim | 1 + tests/pragmas/tused2.nim | 46 +++++++++++++++++++++++ tests/statictypes/tstatictypes.nim | 2 +- 13 files changed, 155 insertions(+), 60 deletions(-) create mode 100644 tests/pragmas/mused2a.nim create mode 100644 tests/pragmas/mused2b.nim create mode 100644 tests/pragmas/mused2c.nim create mode 100644 tests/pragmas/tused2.nim diff --git a/compiler/importer.nim b/compiler/importer.nim index 692cdb604..7a5c4de4a 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -13,6 +13,7 @@ import intsets, ast, astalgo, msgs, options, idents, lookups, semdata, modulepaths, sigmatch, lineinfos, sets, modulegraphs, wordrecg +from strutils import `%` proc readExceptSet*(c: PContext, n: PNode): IntSet = assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} @@ -224,19 +225,20 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym = result = realModule - c.unusedImports.add((realModule, n.info)) template createModuleAliasImpl(ident): untyped = - createModuleAlias(realModule, nextSymId c.idgen, ident, realModule.info, c.config.options) + createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options) if n.kind != nkImportAs: discard elif n.len != 2 or n[1].kind != nkIdent: localError(c.config, n.info, "module alias must be an identifier") elif n[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... result = createModuleAliasImpl(n[1].ident) + if result == realModule: + # avoids modifying `realModule`, see D20201209T194412 for `import {.all.}` + result = createModuleAliasImpl(realModule.name) if importHidden: - if result == realModule: # avoids modifying `realModule`, see D20201209T194412. - result = createModuleAliasImpl(realModule.name) result.options.incl optImportHidden + c.unusedImports.add((result, n.info)) proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] = var ret: typeof(result) @@ -274,23 +276,22 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = toFullPath(c.config, c.graph.importStack[i+1]) c.recursiveDep = err + var realModule: PSym discard pushOptionEntry(c) - result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f), transf.importHidden) + realModule = c.graph.importModuleCallback(c.graph, c.module, f) + result = importModuleAs(c, n, realModule, transf.importHidden) popOptionEntry(c) #echo "set back to ", L c.graph.importStack.setLen(L) # we cannot perform this check reliably because of - # test: modules/import_in_config) - when true: - if result.info.fileIndex == c.module.info.fileIndex and - result.info.fileIndex == n.info.fileIndex: - localError(c.config, n.info, "A module cannot import itself") - if sfDeprecated in result.flags: - if result.constraint != nil: - message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s & " is deprecated") - else: - message(c.config, n.info, warnDeprecated, result.name.s & " is deprecated") + # test: modules/import_in_config) # xxx is that still true? + if realModule == c.module: + localError(c.config, n.info, "module '$1' cannot import itself" % realModule.name.s) + if sfDeprecated in realModule.flags: + var prefix = "" + if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; " + message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated") suggestSym(c.graph, n.info, result, c.graph.usageSym, false) importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) @@ -303,6 +304,9 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = addDecl(c, m, it.info) # add symbol to symbol table of module importAllSymbols(c, m) #importForwarded(c, m.ast, emptySet, m) + for s in allSyms(c.graph, m): # fixes bug #17510, for re-exported symbols + if s.owner != m: + c.exportIndirections.incl((m.id, s.id)) proc evalImport*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index abe6bce7c..11fa45480 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -67,6 +67,7 @@ type warnResultUsed = "ResultUsed", warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", + warnDuplicateModuleImport = "DuplicateModuleImport", warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -148,6 +149,7 @@ const warnResultUsed: "used 'result' variable", warnCannotOpen: "cannot open: $1", warnFileChanged: "file changed: $1", + warnDuplicateModuleImport: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` diff --git a/compiler/lookups.nim b/compiler/lookups.nim index ee79673d0..0e057a79a 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -58,8 +58,8 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent = template addSym*(scope: PScope, s: PSym) = strTableAdd(scope.symbols, s) -proc addUniqueSym*(scope: PScope, s: PSym): PSym = - result = strTableInclReportConflict(scope.symbols, s) +proc addUniqueSym*(scope: PScope, s: PSym, onConflictKeepOld: bool): PSym = + result = strTableInclReportConflict(scope.symbols, s, onConflictKeepOld) proc openScope*(c: PContext): PScope {.discardable.} = result = PScope(parent: c.currentScope, @@ -288,19 +288,23 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = message(c.config, s.info, hintXDeclaredButNotUsed, s.name.s) proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; - conflictsWith: TLineInfo) = + conflictsWith: TLineInfo, note = errGenerated) = ## Emit a redefinition error if in non-interactive mode if c.config.cmd != cmdInteractive: - localError(c.config, info, + localError(c.config, info, note, "redefinition of '$1'; previous declaration here: $2" % [s, c.config $ conflictsWith]) # xxx pending bootstrap >= 1.4, replace all those overloads with a single one: # proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} = proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = - let conflict = scope.addUniqueSym(sym) + let conflict = scope.addUniqueSym(sym, onConflictKeepOld = true) if conflict != nil: - wrongRedefinition(c, info, sym.name.s, conflict.info) + var note = errGenerated + if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner: + # import foo; import foo + note = warnDuplicateModuleImport + wrongRedefinition(c, info, sym.name.s, conflict.info, note) proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) {.inline.} = addDeclAt(c, scope, sym, sym.info) @@ -312,7 +316,7 @@ proc addDecl*(c: PContext, sym: PSym) {.inline.} = addDeclAt(c, c.currentScope, sym) proc addPrelimDecl*(c: PContext, sym: PSym) = - discard c.currentScope.addUniqueSym(sym) + discard c.currentScope.addUniqueSym(sym, onConflictKeepOld = false) from ic / ic import addHidden diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 9abc97be4..87cb3a730 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -10,7 +10,7 @@ ## implements some little helper passes import - ast, passes, idents, msgs, options, lineinfos + ast, passes, msgs, options, lineinfos from modulegraphs import ModuleGraph, PPassContext diff --git a/lib/system/schubfach.nim b/lib/system/schubfach.nim index 5f974a79e..d072cde99 100644 --- a/lib/system/schubfach.nim +++ b/lib/system/schubfach.nim @@ -95,6 +95,36 @@ proc floorLog2Pow10(e: int32): int32 {.inline.} = sf_Assert(e <= 1233) return floorDivPow2(e * 1741647, 19) +const + kMin: int32 = -31 + kMax: int32 = 45 + g: array[kMax - kMin + 1, uint64] = [0x81CEB32C4B43FCF5'u64, 0xA2425FF75E14FC32'u64, + 0xCAD2F7F5359A3B3F'u64, 0xFD87B5F28300CA0E'u64, 0x9E74D1B791E07E49'u64, + 0xC612062576589DDB'u64, 0xF79687AED3EEC552'u64, 0x9ABE14CD44753B53'u64, + 0xC16D9A0095928A28'u64, 0xF1C90080BAF72CB2'u64, 0x971DA05074DA7BEF'u64, + 0xBCE5086492111AEB'u64, 0xEC1E4A7DB69561A6'u64, 0x9392EE8E921D5D08'u64, + 0xB877AA3236A4B44A'u64, 0xE69594BEC44DE15C'u64, 0x901D7CF73AB0ACDA'u64, + 0xB424DC35095CD810'u64, 0xE12E13424BB40E14'u64, 0x8CBCCC096F5088CC'u64, + 0xAFEBFF0BCB24AAFF'u64, 0xDBE6FECEBDEDD5BF'u64, 0x89705F4136B4A598'u64, + 0xABCC77118461CEFD'u64, 0xD6BF94D5E57A42BD'u64, 0x8637BD05AF6C69B6'u64, + 0xA7C5AC471B478424'u64, 0xD1B71758E219652C'u64, 0x83126E978D4FDF3C'u64, + 0xA3D70A3D70A3D70B'u64, 0xCCCCCCCCCCCCCCCD'u64, 0x8000000000000000'u64, + 0xA000000000000000'u64, 0xC800000000000000'u64, 0xFA00000000000000'u64, + 0x9C40000000000000'u64, 0xC350000000000000'u64, 0xF424000000000000'u64, + 0x9896800000000000'u64, 0xBEBC200000000000'u64, 0xEE6B280000000000'u64, + 0x9502F90000000000'u64, 0xBA43B74000000000'u64, 0xE8D4A51000000000'u64, + 0x9184E72A00000000'u64, 0xB5E620F480000000'u64, 0xE35FA931A0000000'u64, + 0x8E1BC9BF04000000'u64, 0xB1A2BC2EC5000000'u64, 0xDE0B6B3A76400000'u64, + 0x8AC7230489E80000'u64, 0xAD78EBC5AC620000'u64, 0xD8D726B7177A8000'u64, + 0x878678326EAC9000'u64, 0xA968163F0A57B400'u64, 0xD3C21BCECCEDA100'u64, + 0x84595161401484A0'u64, 0xA56FA5B99019A5C8'u64, 0xCECB8F27F4200F3A'u64, + 0x813F3978F8940985'u64, 0xA18F07D736B90BE6'u64, 0xC9F2C9CD04674EDF'u64, + 0xFC6F7C4045812297'u64, 0x9DC5ADA82B70B59E'u64, 0xC5371912364CE306'u64, + 0xF684DF56C3E01BC7'u64, 0x9A130B963A6C115D'u64, 0xC097CE7BC90715B4'u64, + 0xF0BDC21ABB48DB21'u64, 0x96769950B50D88F5'u64, 0xBC143FA4E250EB32'u64, + 0xEB194F8E1AE525FE'u64, 0x92EFD1B8D0CF37BF'u64, 0xB7ABC627050305AE'u64, + 0xE596B7B0C643C71A'u64, 0x8F7E32CE7BEA5C70'u64, 0xB35DBF821AE4F38C'u64] + proc computePow10Single(k: int32): uint64 {.inline.} = ## There are unique beta and r such that 10^k = beta 2^r and ## 2^63 <= beta < 2^64, namely r = floor(log_2 10^k) - 63 and @@ -103,35 +133,6 @@ proc computePow10Single(k: int32): uint64 {.inline.} = ## value being a pretty good overestimate for 10^k. ## NB: Since for all the required exponents k, we have g < 2^64, ## all constants can be stored in 128-bit integers. - const - kMin: int32 = -31 - kMax: int32 = 45 - g: array[kMax - kMin + 1, uint64] = [0x81CEB32C4B43FCF5'u64, 0xA2425FF75E14FC32'u64, - 0xCAD2F7F5359A3B3F'u64, 0xFD87B5F28300CA0E'u64, 0x9E74D1B791E07E49'u64, - 0xC612062576589DDB'u64, 0xF79687AED3EEC552'u64, 0x9ABE14CD44753B53'u64, - 0xC16D9A0095928A28'u64, 0xF1C90080BAF72CB2'u64, 0x971DA05074DA7BEF'u64, - 0xBCE5086492111AEB'u64, 0xEC1E4A7DB69561A6'u64, 0x9392EE8E921D5D08'u64, - 0xB877AA3236A4B44A'u64, 0xE69594BEC44DE15C'u64, 0x901D7CF73AB0ACDA'u64, - 0xB424DC35095CD810'u64, 0xE12E13424BB40E14'u64, 0x8CBCCC096F5088CC'u64, - 0xAFEBFF0BCB24AAFF'u64, 0xDBE6FECEBDEDD5BF'u64, 0x89705F4136B4A598'u64, - 0xABCC77118461CEFD'u64, 0xD6BF94D5E57A42BD'u64, 0x8637BD05AF6C69B6'u64, - 0xA7C5AC471B478424'u64, 0xD1B71758E219652C'u64, 0x83126E978D4FDF3C'u64, - 0xA3D70A3D70A3D70B'u64, 0xCCCCCCCCCCCCCCCD'u64, 0x8000000000000000'u64, - 0xA000000000000000'u64, 0xC800000000000000'u64, 0xFA00000000000000'u64, - 0x9C40000000000000'u64, 0xC350000000000000'u64, 0xF424000000000000'u64, - 0x9896800000000000'u64, 0xBEBC200000000000'u64, 0xEE6B280000000000'u64, - 0x9502F90000000000'u64, 0xBA43B74000000000'u64, 0xE8D4A51000000000'u64, - 0x9184E72A00000000'u64, 0xB5E620F480000000'u64, 0xE35FA931A0000000'u64, - 0x8E1BC9BF04000000'u64, 0xB1A2BC2EC5000000'u64, 0xDE0B6B3A76400000'u64, - 0x8AC7230489E80000'u64, 0xAD78EBC5AC620000'u64, 0xD8D726B7177A8000'u64, - 0x878678326EAC9000'u64, 0xA968163F0A57B400'u64, 0xD3C21BCECCEDA100'u64, - 0x84595161401484A0'u64, 0xA56FA5B99019A5C8'u64, 0xCECB8F27F4200F3A'u64, - 0x813F3978F8940985'u64, 0xA18F07D736B90BE6'u64, 0xC9F2C9CD04674EDF'u64, - 0xFC6F7C4045812297'u64, 0x9DC5ADA82B70B59E'u64, 0xC5371912364CE306'u64, - 0xF684DF56C3E01BC7'u64, 0x9A130B963A6C115D'u64, 0xC097CE7BC90715B4'u64, - 0xF0BDC21ABB48DB21'u64, 0x96769950B50D88F5'u64, 0xBC143FA4E250EB32'u64, - 0xEB194F8E1AE525FE'u64, 0x92EFD1B8D0CF37BF'u64, 0xB7ABC627050305AE'u64, - 0xE596B7B0C643C71A'u64, 0x8F7E32CE7BEA5C70'u64, 0xB35DBF821AE4F38C'u64] sf_Assert(k >= kMin) sf_Assert(k <= kMax) return g[k - kMin] diff --git a/testament/categories.nim b/testament/categories.nim index bf7855b2c..b5e8a5454 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -508,6 +508,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string; const tempExt = "_temp.nim" for it in walkDirRec(testsDir): + # for it in ["tests/ic/timports.nim"]: # debugging: to try a specific test if isTestFile(it) and not it.endsWith(tempExt): let nimcache = nimcacheDir(it, options, getTestSpecTarget()) removeDir(nimcache) diff --git a/tests/deprecated/tmodule1.nim b/tests/deprecated/tmodule1.nim index 954836889..f26e4ce3f 100644 --- a/tests/deprecated/tmodule1.nim +++ b/tests/deprecated/tmodule1.nim @@ -1,13 +1,23 @@ discard """ - nimout: '''tmodule1.nim(11, 8) Warning: goodbye; importme is deprecated [Deprecated] -tmodule1.nim(14, 10) Warning: Ty is deprecated [Deprecated] -tmodule1.nim(17, 10) Warning: hello; Ty1 is deprecated [Deprecated] -tmodule1.nim(20, 8) Warning: aVar is deprecated [Deprecated] -tmodule1.nim(22, 3) Warning: aProc is deprecated [Deprecated] -tmodule1.nim(23, 3) Warning: hello; aProc1 is deprecated [Deprecated] + matrix: "--hint:all:off" + nimoutFull: true + nimout: ''' +tmodule1.nim(21, 8) Warning: goodbye; importme is deprecated [Deprecated] +tmodule1.nim(24, 10) Warning: Ty is deprecated [Deprecated] +tmodule1.nim(27, 10) Warning: hello; Ty1 is deprecated [Deprecated] +tmodule1.nim(30, 8) Warning: aVar is deprecated [Deprecated] +tmodule1.nim(32, 3) Warning: aProc is deprecated [Deprecated] +tmodule1.nim(33, 3) Warning: hello; aProc1 is deprecated [Deprecated] ''' """ + + + + + + +# line 20 import importme block: diff --git a/tests/modules/tselfimport.nim b/tests/modules/tselfimport.nim index 7e50bef7c..ba5d9b4cf 100644 --- a/tests/modules/tselfimport.nim +++ b/tests/modules/tselfimport.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "A module cannot import itself" + errormsg: "module 'tselfimport' cannot import itself" file: "tselfimport.nim" line: 7 """ diff --git a/tests/pragmas/mused2a.nim b/tests/pragmas/mused2a.nim new file mode 100644 index 000000000..d9b2bb9bf --- /dev/null +++ b/tests/pragmas/mused2a.nim @@ -0,0 +1,23 @@ +import std/strutils + +from std/os import fileExists + +import std/typetraits as typetraits2 +from std/setutils import complement + + + + + +proc fn1() = discard +proc fn2*() = discard + + +let fn4 = 0 +let fn5* = 0 + + +const fn7 = 0 +const fn8* = 0 + +type T1 = object diff --git a/tests/pragmas/mused2b.nim b/tests/pragmas/mused2b.nim new file mode 100644 index 000000000..39c92b964 --- /dev/null +++ b/tests/pragmas/mused2b.nim @@ -0,0 +1,3 @@ +import mused2c +export mused2c + diff --git a/tests/pragmas/mused2c.nim b/tests/pragmas/mused2c.nim new file mode 100644 index 000000000..a374e634e --- /dev/null +++ b/tests/pragmas/mused2c.nim @@ -0,0 +1 @@ +proc baz*() = discard \ No newline at end of file diff --git a/tests/pragmas/tused2.nim b/tests/pragmas/tused2.nim new file mode 100644 index 000000000..f80c198d8 --- /dev/null +++ b/tests/pragmas/tused2.nim @@ -0,0 +1,46 @@ +discard """ + matrix: "--hint:all:off --hint:XDeclaredButNotUsed --path:." + joinable: false + nimoutFull: true + nimout: ''' +mused2a.nim(12, 6) Hint: 'fn1' is declared but not used [XDeclaredButNotUsed] +mused2a.nim(16, 5) Hint: 'fn4' is declared but not used [XDeclaredButNotUsed] +mused2a.nim(20, 7) Hint: 'fn7' is declared but not used [XDeclaredButNotUsed] +mused2a.nim(23, 6) Hint: 'T1' is declared but not used [XDeclaredButNotUsed] +mused2a.nim(1, 11) Warning: imported and not used: 'strutils' [UnusedImport] +mused2a.nim(3, 9) Warning: imported and not used: 'os' [UnusedImport] +mused2a.nim(5, 23) Warning: imported and not used: 'typetraits2' [UnusedImport] +mused2a.nim(6, 9) Warning: imported and not used: 'setutils' [UnusedImport] +tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport] +tused2.nim(45, 11) Warning: imported and not used: 'strutils' [UnusedImport] +''' +""" + + + + + + + + + + + + + + + + + + + + + + +# line 40 + +import mused2a +import mused2b + +import std/strutils +baz() diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 16cb55c28..5df3f35fd 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -271,7 +271,7 @@ block: fails(foo) -import macros, tables +import tables var foo{.compileTime.} = [ "Foo", From 1b9b8060075efab82912dc33ba64e671d102b999 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 26 Jun 2021 19:10:46 +0300 Subject: [PATCH 2765/4254] rst: fix bug 20 from #17340 (#18360) and a leftover bug: priority of option list inside definition list --- lib/packages/docutils/rst.nim | 4 ++- tests/stdlib/trst.nim | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 8ffbbd4d3..419cf50e7 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -2245,7 +2245,7 @@ proc parseOptionList(p: var RstParser): PRstNode = popInd(p) else: parseLine(p, b) - if currentTok(p).kind == tkIndent: inc p.idx + while currentTok(p).kind == tkIndent: inc p.idx c.add(a) c.add(b) c.order = order; inc order @@ -2262,6 +2262,8 @@ proc parseDefinitionList(p: var RstParser): PRstNode = var col = currentTok(p).col result = newRstNodeA(p, rnDefList) while true: + if isOptionList(p): + break # option list has priority over def.list j = p.idx var a = newRstNode(rnDefName) parseLine(p, a) diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index d53092d3b..fb9552479 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -83,6 +83,53 @@ suite "RST parsing": rnLeaf 'set' """) + test "items of 1 option list can be separated by blank lines": + check(dedent""" + -a desc1 + + -b desc2 + """.toAst == + dedent""" + rnOptionList + rnOptionListItem order=1 + rnOptionGroup + rnLeaf '-' + rnLeaf 'a' + rnDescription + rnLeaf 'desc1' + rnOptionListItem order=2 + rnOptionGroup + rnLeaf '-' + rnLeaf 'b' + rnDescription + rnLeaf 'desc2' + """) + + test "option list has priority over definition list": + check(dedent""" + defName + defBody + + -b desc2 + """.toAst == + dedent""" + rnInner + rnDefList + rnDefItem + rnDefName + rnLeaf 'defName' + rnDefBody + rnInner + rnLeaf 'defBody' + rnOptionList + rnOptionListItem order=1 + rnOptionGroup + rnLeaf '-' + rnLeaf 'b' + rnDescription + rnLeaf 'desc2' + """) + test "RST comment": check(dedent""" .. comment1 From 0b7361e938134305d6893ee2876b5fc8f9ba419b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 27 Jun 2021 11:39:16 -0700 Subject: [PATCH 2766/4254] followup #18362: make `UnusedImport` work robustly (#18366) * warnDuplicateModuleImport => hintDuplicateModuleImport * improve DuplicateModuleImport msg, add test --- compiler/cgen.nim | 2 - compiler/dfa.nim | 2 +- compiler/docgen.nim | 2 +- compiler/importer.nim | 16 +++++-- compiler/injectdestructors.nim | 6 +-- compiler/jsgen.nim | 2 - compiler/lineinfos.nim | 6 +-- compiler/lookups.nim | 12 ++++-- compiler/semdata.nim | 3 +- compiler/suggest.nim | 5 ++- tests/misc/trunner.nim | 26 +++++++++++- tests/pragmas/mused3.nim | 76 ++++++++++++++++++++++++++++++++++ tests/pragmas/mused3a.nim | 41 ++++++++++++++++++ tests/pragmas/mused3b.nim | 12 ++++++ 14 files changed, 186 insertions(+), 25 deletions(-) create mode 100644 tests/pragmas/mused3.nim create mode 100644 tests/pragmas/mused3a.nim create mode 100644 tests/pragmas/mused3b.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5d6de2a03..3b004d399 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -24,8 +24,6 @@ import strutils except `%` # collides with ropes.`%` from ic / ic import ModuleBackendFlag from modulegraphs import ModuleGraph, PPassContext -from lineinfos import - warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile import dynlib when not declared(dynlib.libCandidates): diff --git a/compiler/dfa.nim b/compiler/dfa.nim index ea60dbc59..402945042 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -29,7 +29,7 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, types, intsets, lineinfos, renderer +import ast, intsets, lineinfos, renderer import std/private/asciitables type diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 08311eade..e6bb7cef8 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -16,7 +16,7 @@ import packages/docutils/rst, packages/docutils/rstgen, json, xmltree, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, trees, tables, nimpaths, renderverbatim, osproc + pathutils, tables, nimpaths, renderverbatim, osproc from uri import encodeUrl from std/private/globs import nativeToUnixPath diff --git a/compiler/importer.nim b/compiler/importer.nim index 7a5c4de4a..af392f849 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -12,7 +12,7 @@ import intsets, ast, astalgo, msgs, options, idents, lookups, semdata, modulepaths, sigmatch, lineinfos, sets, - modulegraphs, wordrecg + modulegraphs, wordrecg, tables from strutils import `%` proc readExceptSet*(c: PContext, n: PNode): IntSet = @@ -239,6 +239,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool) if importHidden: result.options.incl optImportHidden c.unusedImports.add((result, n.info)) + c.importModuleMap[result.id] = realModule.id proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] = var ret: typeof(result) @@ -296,6 +297,13 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) +proc afterImport(c: PContext, m: PSym) = + # fixes bug #17510, for re-exported symbols + let realModuleId = c.importModuleMap[m.id] + for s in allSyms(c.graph, m): + if s.owner.id != realModuleId: + c.exportIndirections.incl((m.id, s.id)) + proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = var it = it let m = myImportModule(c, it, importStmtResult) @@ -304,9 +312,7 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = addDecl(c, m, it.info) # add symbol to symbol table of module importAllSymbols(c, m) #importForwarded(c, m.ast, emptySet, m) - for s in allSyms(c.graph, m): # fixes bug #17510, for re-exported symbols - if s.owner != m: - c.exportIndirections.incl((m.id, s.id)) + afterImport(c, m) proc evalImport*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) @@ -345,6 +351,7 @@ proc evalFrom*(c: PContext, n: PNode): PNode = if n[i].kind != nkNilLit: importSymbol(c, n[i], m, im.imported) c.addImport im + afterImport(c, m) proc evalImportExcept*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) @@ -355,3 +362,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode = addDecl(c, m, n.info) # add symbol to symbol table of module importAllSymbolsExcept(c, m, readExceptSet(c, n)) #importForwarded(c, m.ast, exceptSet, m) + afterImport(c, m) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 8ef08adeb..6447557c5 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -15,7 +15,7 @@ import intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents, - strutils, options, dfa, lowerings, tables, modulegraphs, msgs, + strutils, options, dfa, lowerings, tables, modulegraphs, lineinfos, parampatterns, sighashes, liftdestructors, optimizer, varpartitions @@ -73,7 +73,7 @@ proc nestedScope(parent: var Scope): Scope = proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode -import sets, hashes, tables +import sets, hashes proc hash(n: PNode): Hash = hash(cast[pointer](n)) @@ -245,8 +245,6 @@ template isUnpackedTuple(n: PNode): bool = ## hence unpacked tuples themselves don't need to be destroyed (n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple) -from strutils import parseInt - proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">" if (opname == "=" or opname == "=copy") and ri != nil: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 3b183b9d6..393ac83c2 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -37,8 +37,6 @@ import import json, sets, math, tables, intsets, strutils -from modulegraphs import ModuleGraph, PPassContext - type TJSGen = object of PPassContext module: PSym diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 11fa45480..131fe480b 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -67,12 +67,12 @@ type warnResultUsed = "ResultUsed", warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", - warnDuplicateModuleImport = "DuplicateModuleImport", warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", - hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", + hintLineTooLong = "LineTooLong", + hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintCodeBegin = "CodeBegin", @@ -149,7 +149,6 @@ const warnResultUsed: "used 'result' variable", warnCannotOpen: "cannot open: $1", warnFileChanged: "file changed: $1", - warnDuplicateModuleImport: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` @@ -157,6 +156,7 @@ const hintCC: "CC: $1", hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", + hintDuplicateModuleImport: "$1", hintXCannotRaiseY: "$1", hintConvToBaseNotNeeded: "conversion to base object is not needed", hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 0e057a79a..9b878dd4b 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -300,11 +300,15 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = let conflict = scope.addUniqueSym(sym, onConflictKeepOld = true) if conflict != nil: - var note = errGenerated if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner: - # import foo; import foo - note = warnDuplicateModuleImport - wrongRedefinition(c, info, sym.name.s, conflict.info, note) + # e.g.: import foo; import foo + # xxx we could refine this by issuing a different hint for the case + # where a duplicate import happens inside an include. + localError(c.config, info, hintDuplicateModuleImport, + "duplicate import of '$1'; previous import here: $2" % + [sym.name.s, c.config $ conflict.info]) + else: + wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated) proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) {.inline.} = addDeclAt(c, scope, sym, sym.info) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index f763a00e4..bd863505c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -156,7 +156,8 @@ type features*: set[Feature] inTypeContext*, inConceptDecl*: int unusedImports*: seq[(PSym, TLineInfo)] - exportIndirections*: HashSet[(int, int)] + exportIndirections*: HashSet[(int, int)] # (module.id, symbol.id) + importModuleMap*: Table[int, int] # (module.id, module.id) lastTLineInfo*: TLineInfo template config*(c: PContext): ConfigRef = c.graph.config diff --git a/compiler/suggest.nim b/compiler/suggest.nim index a5b4ac87d..eaa30040a 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -32,7 +32,7 @@ # included from sigmatch.nim -import algorithm, sets, prefixmatches, lineinfos, parseutils, linter +import algorithm, sets, prefixmatches, lineinfos, parseutils, linter, tables from wordrecg import wDeprecated, wError, wAddr, wYield when defined(nimsuggest): @@ -572,7 +572,8 @@ proc markOwnerModuleAsUsed(c: PContext; s: PSym) = var i = 0 while i <= high(c.unusedImports): let candidate = c.unusedImports[i][0] - if candidate == module or c.exportIndirections.contains((candidate.id, s.id)): + if candidate == module or c.importModuleMap.getOrDefault(candidate.id, int.low) == module.id or + c.exportIndirections.contains((candidate.id, s.id)): # mark it as used: c.unusedImports.del(i) else: diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 77ae10f3d..8426e9aee 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -31,7 +31,7 @@ const proc runNimCmd(file, options = "", rtarg = ""): auto = let fileabs = testsDir / file.unixToNativePath # doAssert fileabs.fileExists, fileabs # disabled because this allows passing `nim r --eval:code fakefile` - let cmd = fmt"{nim} {mode} {options} --hints:off {fileabs} {rtarg}" + let cmd = fmt"{nim} {mode} --hint:all:off {options} {fileabs} {rtarg}" result = execCmdEx(cmd) when false: # for debugging echo cmd @@ -352,5 +352,29 @@ running: v2 doAssert outp2 == "12345\n", outp2 doAssert status2 == 0 + block: # UnusedImport + proc fn(opt: string, expected: string) = + let output = runNimCmdChk("pragmas/mused3.nim", fmt"--warning:all:off --warning:UnusedImport --hint:DuplicateModuleImport {opt}") + doAssert output == expected, opt & "\noutput:\n" & output & "expected:\n" & expected + fn("-d:case1"): """ +mused3.nim(13, 8) Warning: imported and not used: 'mused3b' [UnusedImport] +""" + fn("-d:case2"): "" + fn("-d:case3"): "" + fn("-d:case4"): "" + fn("-d:case5"): "" + fn("-d:case6"): "" + fn("-d:case7"): "" + fn("-d:case8"): "" + fn("-d:case9"): "" + fn("-d:case10"): "" + when false: + fn("-d:case11"): """ + Warning: imported and not used: 'm2' [UnusedImport] + """ + fn("-d:case12"): """ +mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport] +""" + else: discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled diff --git a/tests/pragmas/mused3.nim b/tests/pragmas/mused3.nim new file mode 100644 index 000000000..0beec1d44 --- /dev/null +++ b/tests/pragmas/mused3.nim @@ -0,0 +1,76 @@ +#[ +ran from trunner +]# + + + + + + +# line 10 +when defined case1: + from mused3a import nil + from mused3b import nil + mused3a.fn1() + +when defined case2: + from mused3a as m1 import nil + m1.fn1() + +when defined case3: + from mused3a import fn1 + fn1() + +when defined case4: + from mused3a as m1 import fn1 + m1.fn1() + +when defined case5: + import mused3a as m1 + fn1() + +when defined case6: + import mused3a except nonexistent + fn1() + +when defined case7: + import mused3a + mused3a.fn1() + +when defined case8: + # re-export test + import mused3a except nonexistent + gn1() + +when defined case9: + # re-export test + import mused3a + gn1() + +when defined case10: + #[ + edge case which happens a lot in compiler code: + don't report UnusedImport for mused3b here even though it works without `import mused3b`, + because `a.b0.f0` is accessible from both mused3a and mused3b (fields are given implicit access) + ]# + import mused3a + import mused3b + var a: Bar + discard a.b0.f0 + +when false: + when defined case11: + #[ + xxx minor bug: this should give: + Warning: imported and not used: 'm2' [UnusedImport] + but doesn't, because currently implementation in `markOwnerModuleAsUsed` + only looks at `fn1`, not fully qualified call `m1.fn1() + ]# + from mused3a as m1 import nil + from mused3a as m2 import nil + m1.fn1() + +when defined case12: + import mused3a + import mused3a + fn1() diff --git a/tests/pragmas/mused3a.nim b/tests/pragmas/mused3a.nim new file mode 100644 index 000000000..c33d1ecb3 --- /dev/null +++ b/tests/pragmas/mused3a.nim @@ -0,0 +1,41 @@ +when defined case1: + proc fn1*() = discard + +when defined case2: + proc fn1*() = discard + +when defined case3: + proc fn1*() = discard + proc fn2*() = discard + +when defined case4: + proc fn1*() = discard + proc fn2*() = discard + +when defined case5: + proc fn1*() = discard + +when defined case6: + proc fn1*() = discard + +when defined case7: + proc fn1*() = discard + +when defined case8: + import mused3b + export mused3b + +when defined case9: + import mused3b + export mused3b + +when defined case10: + import mused3b + type Bar* = object + b0*: Foo + +when defined case11: + proc fn1*() = discard + +when defined case12: + proc fn1*() = discard diff --git a/tests/pragmas/mused3b.nim b/tests/pragmas/mused3b.nim new file mode 100644 index 000000000..de288bb08 --- /dev/null +++ b/tests/pragmas/mused3b.nim @@ -0,0 +1,12 @@ +when defined case1: + proc gn1*()=discard + +when defined case8: + proc gn1*()=discard + +when defined case9: + proc gn1*()=discard + +when defined case10: + type Foo* = object + f0*: int From 0804b4b37d5fcc43d975f56a4c2c88dd58a0b882 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 27 Jun 2021 19:51:28 +0100 Subject: [PATCH 2767/4254] Switch packaging.rst to use makefile Minor cleanup --- doc/packaging.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/packaging.rst b/doc/packaging.rst index ecb17e482..fcdc4ae04 100644 --- a/doc/packaging.rst +++ b/doc/packaging.rst @@ -48,14 +48,15 @@ Hints on the build process: .. code:: cmd # build from C sources and then using koch - ./build.sh --os $os_type --cpu $cpu_arch - ./bin/nim c koch + make -j # supports parallel build + # alternatively: ./build.sh --os $os_type --cpu $cpu_arch + ./bin/nim c -d:release koch ./koch boot -d:release # optionally generate docs into doc/html ./koch docs - ./koch tools -d:release + ./koch tools # extract files to be really installed ./install.sh From 908b2cc2e44bededdcb943778f44b908a4f3c1df Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 27 Jun 2021 21:12:12 +0100 Subject: [PATCH 2768/4254] Switch IRC links to Libera Chat (#18370) --- readme.md | 4 ++-- tools/website.nimf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 37babf711..7c6e28be3 100644 --- a/readme.md +++ b/readme.md @@ -16,7 +16,7 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( [![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter] * The [forum][nim-forum] - the best place to ask questions and to discuss Nim. -* [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time. +* [#nim IRC Channel (Libera Chat)][nim-irc] - a place to discuss Nim in real-time. Also where most development decisions get made. * [Discord][nim-discord] - an additional place to discuss Nim in real-time. Most channels there are bridged to IRC. @@ -206,7 +206,7 @@ Copyright © 2006-2021 Andreas Rumpf, all rights reserved. [nim-forum]: https://forum.nim-lang.org [nim-issues]: https://github.com/nim-lang/Nim/issues [nim-issues-easy]: https://github.com/nim-lang/Nim/labels/Easy -[nim-irc]: https://webchat.freenode.net/?channels=nim +[nim-irc]: https://web.libera.chat/#nim [nim-twitter]: https://twitter.com/nim_lang [nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim-lang [nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim-lang?sort=newest&pageSize=15 diff --git a/tools/website.nimf b/tools/website.nimf index bde84b32f..cea30f74f 100644 --- a/tools/website.nimf +++ b/tools/website.nimf @@ -188,7 +188,7 @@ runForever()
    From e720bbdd76303e2cc0a3a169e870859470a1da84 Mon Sep 17 00:00:00 2001 From: gemath <33119724+gemath@users.noreply.github.com> Date: Mon, 28 Jun 2021 12:33:20 +0200 Subject: [PATCH 2769/4254] Peg captures get stack-like behavior (#18369) * Implements reverse capture indexing. * Now works for modified backrefs too. * Changed reverse indexing syntax prefix for back-references to '$^'. --- doc/pegdocs.txt | 10 +++-- lib/pure/pegs.nim | 90 +++++++++++++++++++++++++++--------------- tests/stdlib/tpegs.nim | 28 +++++++++++++ 3 files changed, 94 insertions(+), 34 deletions(-) diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt index 4c557aed8..0363d4874 100644 --- a/doc/pegdocs.txt +++ b/doc/pegdocs.txt @@ -27,7 +27,10 @@ notation meaning ``{E}`` Capture: Apply expression `E` and store the substring that matched `E` into a *capture* that can be accessed after the matching process. -``$i`` Back reference to the ``i``th capture. ``i`` counts from 1. +``{}`` Empty capture: Delete the last capture. No character + is consumed. +``$i`` Back reference to the ``i``th capture. ``i`` counts forwards + from 1 or backwards (last capture to first) from ^1. ``$`` Anchor: Matches at the end of the input. No character is consumed. Same as ``!.``. ``^`` Anchor: Matches at the start of the input. No character @@ -149,14 +152,15 @@ The PEG parser implements this grammar (written in PEG syntax):: rule <- identifier \s* "<-" expr ig identNoArrow <- identifier !(\s* "<-") prefixOpr <- ig '&' / ig '!' / ig '@' / ig '{@}' / ig '@@' - literal <- ig identifier? '$' [0-9]+ / '$' / '^' / + literal <- ig identifier? '$' '^'? [0-9]+ / '$' / '^' / ig identNoArrow / ig charset / ig stringlit / ig builtin / ig '.' / ig '_' / - (ig "(" expr ig ")") + (ig "(" expr ig ")") / + (ig "{" expr? ig "}") postfixOpr <- ig '?' / ig '*' / ig '+' primary <- prefixOpr* (literal postfixOpr*) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index b5d9b1d07..b6b05cdc1 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -83,7 +83,7 @@ type of pkChar, pkGreedyRepChar: ch: char of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] of pkNonTerminal: nt: NonTerminal - of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] + of pkBackRef..pkBackRefIgnoreStyle: index: range[-MaxSubpatterns..MaxSubpatterns-1] else: sons: seq[Peg] NonTerminal* = ref NonTerminalObj @@ -106,7 +106,7 @@ proc nt*(p: Peg): NonTerminal = p.nt ## Returns the *NonTerminal* object of a given *Peg* variant object ## where present. -proc index*(p: Peg): range[0..MaxSubpatterns] = p.index +proc index*(p: Peg): range[-MaxSubpatterns..MaxSubpatterns-1] = p.index ## Returns the back-reference index of a captured sub-pattern in the ## *Captures* object for a given *Peg* variant object where present. @@ -304,34 +304,37 @@ proc endAnchor*: Peg {.inline.} = ## constructs the PEG ``$`` which matches the end of the input. result = !any() -proc capture*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsCapture".} = +proc capture*(a: Peg = Peg(kind: pkEmpty)): Peg {.noSideEffect, rtl, extern: "npegsCapture".} = ## constructs a capture with the PEG `a` result = Peg(kind: pkCapture, sons: @[a]) -proc backref*(index: range[1..MaxSubpatterns]): Peg {. +proc backref*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. noSideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. - result = Peg(kind: pkBackRef, index: index-1) + ## from 1. `reverse` specifies wether indexing starts from the end of the + ## capture list. + result = Peg(kind: pkBackRef, index: (if reverse: -index else: index - 1)) -proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {. +proc backrefIgnoreCase*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. noSideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. Ignores case for matching. - result = Peg(kind: pkBackRefIgnoreCase, index: index-1) + ## from 1. `reverse` specifies wether indexing starts from the end of the + ## capture list. Ignores case for matching. + result = Peg(kind: pkBackRefIgnoreCase, index: (if reverse: -index else: index - 1)) -proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {. +proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. noSideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. Ignores style for matching. - result = Peg(kind: pkBackRefIgnoreStyle, index: index-1) + ## from 1. `reverse` specifies wether indexing starts from the end of the + ## capture list. Ignores style for matching. + result = Peg(kind: pkBackRefIgnoreStyle, index: (if reverse: -index else: index - 1)) proc spaceCost(n: Peg): int = case n.kind of pkEmpty: discard of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, - pkAny..pkWhitespace, pkGreedyAny: + pkAny..pkWhitespace, pkGreedyAny, pkBackRef..pkBackRefIgnoreStyle: result = 1 of pkNonTerminal: # we cannot inline a rule with a non-terminal @@ -561,8 +564,10 @@ template matchOrParse(mopProc: untyped) = # Parse handler code must run in an *of* clause of its own for each # *PegKind*, so we encapsulate the identical clause body for # *pkBackRef..pkBackRefIgnoreStyle* here. - if p.index >= c.ml: return -1 - var (a, b) = c.matches[p.index] + var index = p.index + if index < 0: index.inc(c.ml) + if index < 0 or index >= c.ml: return -1 + var (a, b) = c.matches[index] var n: Peg case p.kind of pkBackRef: @@ -822,15 +827,19 @@ template matchOrParse(mopProc: untyped) = leave(pkNotPredicate, s, p, start, result) of pkCapture: enter(pkCapture, s, p, start) - var idx = c.ml # reserve a slot for the subpattern - inc(c.ml) - result = mopProc(s, p.sons[0], start, c) - if result >= 0: - if idx < MaxSubpatterns: - c.matches[idx] = (start, start+result-1) - #else: silently ignore the capture + if p.sons.len == 0 or p.sons[0].kind == pkEmpty: + # empty capture removes last match + dec(c.ml) + c.matches[c.ml] = (0, 0) + result = 0 # match of length 0 else: - c.ml = idx + var idx = c.ml # reserve a slot for the subpattern + result = mopProc(s, p.sons[0], start, c) + if result >= 0: + inc(c.ml) + if idx < MaxSubpatterns: + c.matches[idx] = (start, start+result-1) + #else: silently ignore the capture leave(pkCapture, s, p, start, result) of pkBackRef: enter(pkBackRef, s, p, start) @@ -1395,6 +1404,7 @@ type tkCurlyLe, ## '{' tkCurlyRi, ## '}' tkCurlyAt, ## '{@}' + tkEmptyCurl, ## '{}' tkArrow, ## '<-' tkBar, ## '/' tkStar, ## '*' @@ -1427,7 +1437,7 @@ type const tokKindToStr: array[TokKind, string] = [ "invalid", "[EOF]", ".", "_", "identifier", "string literal", - "character set", "(", ")", "{", "}", "{@}", + "character set", "(", ")", "{", "}", "{@}", "{}", "<-", "/", "*", "+", "&", "!", "?", "@", "built-in", "escaped", "$", "$", "^" ] @@ -1564,13 +1574,21 @@ proc getString(c: var PegLexer, tok: var Token) = proc getDollar(c: var PegLexer, tok: var Token) = var pos = c.bufpos + 1 + var neg = false + if pos < c.buf.len and c.buf[pos] == '^': + neg = true + inc(pos) if pos < c.buf.len and c.buf[pos] in {'0'..'9'}: tok.kind = tkBackref tok.index = 0 while pos < c.buf.len and c.buf[pos] in {'0'..'9'}: tok.index = tok.index * 10 + ord(c.buf[pos]) - ord('0') inc(pos) + if neg: + tok.index = -tok.index else: + if neg: + dec(pos) tok.kind = tkDollar c.bufpos = pos @@ -1670,6 +1688,10 @@ proc getTok(c: var PegLexer, tok: var Token) = tok.kind = tkCurlyAt inc(c.bufpos, 2) add(tok.literal, "{@}") + elif c.buf[c.bufpos] == '}' and c.bufpos < c.buf.len: + tok.kind = tkEmptyCurl + inc(c.bufpos) + add(tok.literal, "{}") else: tok.kind = tkCurlyLe add(tok.literal, '{') @@ -1705,7 +1727,7 @@ proc getTok(c: var PegLexer, tok: var Token) = return if c.buf[c.bufpos] in {'\'', '"'} or c.buf[c.bufpos] == '$' and c.bufpos+1 < c.buf.len and - c.buf[c.bufpos+1] in {'0'..'9'}: + c.buf[c.bufpos+1] in {'^', '0'..'9'}: case tok.literal of "i": tok.modifier = modIgnoreCase of "y": tok.modifier = modIgnoreStyle @@ -1819,10 +1841,13 @@ proc modifiedTerm(s: string, m: Modifier): Peg = of modIgnoreStyle: result = termIgnoreStyle(s) proc modifiedBackref(s: int, m: Modifier): Peg = + var + reverse = s < 0 + index = if reverse: -s else: s case m - of modNone, modVerbatim: result = backref(s) - of modIgnoreCase: result = backrefIgnoreCase(s) - of modIgnoreStyle: result = backrefIgnoreStyle(s) + of modNone, modVerbatim: result = backref(index, reverse) + of modIgnoreCase: result = backrefIgnoreCase(index, reverse) + of modIgnoreStyle: result = backrefIgnoreStyle(index, reverse) proc builtin(p: var PegParser): Peg = # do not use "y", "skip" or "i" as these would be ambiguous @@ -1896,6 +1921,9 @@ proc primary(p: var PegParser): Peg = result = capture(parseExpr(p)).token(p) eat(p, tkCurlyRi) inc(p.captures) + of tkEmptyCurl: + result = capture() + getTok(p) of tkAny: result = any().token(p) getTok(p) @@ -1915,11 +1943,11 @@ proc primary(p: var PegParser): Peg = result = startAnchor() getTok(p) of tkBackref: + if abs(p.tok.index) > p.captures or p.tok.index == 0: + pegError(p, "invalid back reference index: " & $p.tok.index) var m = p.tok.modifier if m == modNone: m = p.modifier result = modifiedBackref(p.tok.index, m).token(p) - if p.tok.index < 0 or p.tok.index > p.captures: - pegError(p, "invalid back reference index: " & $p.tok.index) getTok(p) else: pegError(p, "expression expected, but found: " & p.tok.literal) @@ -1943,7 +1971,7 @@ proc seqExpr(p: var PegParser): Peg = case p.tok.kind of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe, tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, - tkHat, tkCurlyAt: + tkHat, tkCurlyAt, tkEmptyCurl: result = sequence(result, primary(p)) of tkIdentifier: if not arrowIsNextTok(p): diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index f2c93c2e5..1261d55b8 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -293,6 +293,34 @@ block: doAssert "test1".match(peg"""{@}$""") doAssert "test2".match(peg"""{(!$ .)*} $""") + + doAssert "abbb".match(peg"{a} {b} $2 $^1") + doAssert "abBA".match(peg"{a} {b} i$2 i$^2") + + doAssert "abba".match(peg"{a} {b} $^1 {} $^1") + + block: + let grammar = peg""" +program <- {''} stmt* $ +stmt <- call / block +call <- 'call()' EOL +EOL <- \n / $ +block <- 'block:' \n indBody +indBody <- {$^1 ' '+} stmt ($^1 stmt)* {} +""" + let program = """ +call() +block: + block: + call() + call() + call() +call() +""" + var c: Captures + doAssert program.len == program.rawMatch(grammar, 0, c) + doAssert c.ml == 1 + pegsTest() static: pegsTest() From 6e74fecb4275272e5224e2a0ba45df5ca2c40b82 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 28 Jun 2021 15:00:14 +0200 Subject: [PATCH 2770/4254] Simplify addInt, remove digits10 (#18356) * Simplify addInt, remove digits10 Co-authored-by: Charles Blake * Fix bootstrapping * Add noInit to tmp array * noInit -> noinit Co-authored-by: Charles Blake --- lib/std/private/digitsutils.nim | 58 +++++++++++++-------------------- lib/system/dollars.nim | 4 +-- lib/system/strmantle.nim | 10 ++---- tests/stdlib/tdigitsutils.nim | 23 ------------- 4 files changed, 27 insertions(+), 68 deletions(-) delete mode 100644 tests/stdlib/tdigitsutils.nim diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index cc985c7bd..7aefc36bc 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -38,51 +38,39 @@ proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = assert(digits <= 99) return trailingZeros100[digits] -func digits10*(num: uint64): int {.noinline.} = - if num < 10'u64: - result = 1 - elif num < 100'u64: - result = 2 - elif num < 1_000'u64: - result = 3 - elif num < 10_000'u64: - result = 4 - elif num < 100_000'u64: - result = 5 - elif num < 1_000_000'u64: - result = 6 - elif num < 10_000_000'u64: - result = 7 - elif num < 100_000_000'u64: - result = 8 - elif num < 1_000_000_000'u64: - result = 9 - elif num < 10_000_000_000'u64: - result = 10 - elif num < 100_000_000_000'u64: - result = 11 - elif num < 1_000_000_000_000'u64: - result = 12 - else: - result = 12 + digits10(num div 1_000_000_000_000'u64) - -template numToString*(result: var string, origin: uint64, length: int) = +func addIntImpl*(result: var string, origin: uint64) = + var tmp {.noinit.}: array[24, char] var num = origin - var next = length - 1 + var next = tmp.len - 1 const nbatch = 100 while num >= nbatch: let originNum = num num = num div nbatch let index = (originNum - num * nbatch) shl 1 - result[next] = digits100[index + 1] - result[next - 1] = digits100[index] + tmp[next] = digits100[index + 1] + tmp[next - 1] = digits100[index] dec(next, 2) # process last 1-2 digits if num < 10: - result[next] = chr(ord('0') + num) + tmp[next] = chr(ord('0') + num) else: let index = num * 2 - result[next] = digits100[index + 1] - result[next - 1] = digits100[index] + tmp[next] = digits100[index + 1] + tmp[next - 1] = digits100[index] + dec next + let n = result.len + let length = tmp.len - next + result.setLen n + length + when nimvm: + for i in 0.. 1: - doAssert digits10(x-1) == num - 1 - num += 1 - let xOld = x - x *= 10 - if x < xOld: - # wrap-around - break - -static: main() -main() From 0be17f5d9c6b66a8f8dda83c9a3c77c61be3844d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 28 Jun 2021 17:08:45 +0200 Subject: [PATCH 2771/4254] fixes #18319 (#18375) --- compiler/jsgen.nim | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 393ac83c2..a9339c7fd 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -29,7 +29,7 @@ implements the required case distinction. import - ast, trees, magicsys, options, + ast, astalgo, trees, magicsys, options, nversion, msgs, idents, types, ropes, passes, ccgutils, wordrecg, renderer, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, @@ -2234,6 +2234,16 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) = r.res.addf("Field$#: $#", [i.rope, a.res]) r.res.add("}") +proc lookupFieldAgain(ty: PType; field: PSym): PSym = + var ty = ty + while ty != nil: + ty = ty.skipTypes(skipPtrs) + assert(ty.kind in {tyTuple, tyObject}) + result = lookupInRecord(ty.n, field.name) + if result != nil: break + ty = ty[0] + if result == nil: result = field + proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes r.kind = resExpr @@ -2247,7 +2257,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = gen(p, val, a) var f = it[0].sym if f.loc.r == nil: f.loc.r = mangleName(p.module, f) - fieldIDs.incl(f.id) + fieldIDs.incl(lookupFieldAgain(n.typ, f).id) let typ = val.typ.skipTypes(abstractInst) if a.typ == etyBaseIndex: From cb9496693a718cdb9ad8b764f82f524efe943bd2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 28 Jun 2021 08:15:20 -0700 Subject: [PATCH 2772/4254] `./koch tools` now builds bin/nim_dbg, a debug version of nim (#18289) --- koch.nim | 10 ++++++++-- tools/kochdocs.nim | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index 6a0b7a0d3..d3957069b 100644 --- a/koch.nim +++ b/koch.nim @@ -215,8 +215,14 @@ proc buildTools(args: string = "") = options = "-d:release " & args) when defined(windows): buildVccTool(args) bundleNimpretty(args) - nimCompileFold("Compile testament", "testament/testament.nim", - options = "-d:release " & args) + nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release" & args) + + # pre-packages a debug version of nim which can help in many cases investigate issuses + # withouth having to rebuild compiler. + # `-d:nimDebugUtils` only makes sense when temporarily editing/debugging compiler + # `-d:debug` should be changed to a flag that doesn't require re-compiling nim + # `--opt:speed` is a sensible default even for a debug build, it doesn't affect nim stacktraces + nimCompileFold("Compile nim_dbg", "compiler/nim.nim", options = "--opt:speed --stacktrace -d:debug --stacktraceMsgs -d:nimCompilerStacktraceHints" & args, outputName = "nim_dbg") proc nsis(latest: bool; args: string) = bundleNimbleExe(latest, args) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 469059348..8e8085f73 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -98,8 +98,9 @@ proc nimCompile*(input: string, outputDir = "bin", mode = "c", options = "") = let cmd = findNim().quoteShell() & " " & mode & " -o:" & output & " " & options & " " & input exec cmd -proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options = "") = - let output = outputDir / input.splitFile.name.exe +proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options = "", outputName = "") = + let outputName2 = if outputName.len == 0: input.splitFile.name.exe else: outputName.exe + let output = outputDir / outputName2 let cmd = findNim().quoteShell() & " " & mode & " -o:" & output & " " & options & " " & input execFold(desc, cmd) From 72d6a9c885504a1752ee0639aa110d4bf42d95c8 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 28 Jun 2021 17:41:37 +0200 Subject: [PATCH 2773/4254] Fix #16426 (#18377) --- compiler/parser.nim | 13 ++++++++----- tests/parser/tstmtlists.nim | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 9cddf8e4f..b6c01e9c6 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -537,13 +537,16 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode = proc complexOrSimpleStmt(p: var Parser): PNode proc simpleExpr(p: var Parser, mode = pmNormal): PNode -proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode +proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode proc semiStmtList(p: var Parser, result: PNode) = inc p.inSemiStmtList withInd(p): # Be lenient with the first stmt/expr - let a = if p.tok.tokType == tkIf: parseIfExpr(p, nkIfStmt) else: complexOrSimpleStmt(p) + let a = case p.tok.tokType + of tkIf: parseIfOrWhenExpr(p, nkIfStmt) + of tkWhen: parseIfOrWhenExpr(p, nkWhenStmt) + else: complexOrSimpleStmt(p) result.add a while p.tok.tokType != tkEof: @@ -1203,13 +1206,13 @@ proc parseExpr(p: var Parser): PNode = result = parseBlock(p) of tkIf: nimprettyDontTouch: - result = parseIfExpr(p, nkIfExpr) + result = parseIfOrWhenExpr(p, nkIfExpr) of tkFor: nimprettyDontTouch: result = parseFor(p) of tkWhen: nimprettyDontTouch: - result = parseIfExpr(p, nkWhenExpr) + result = parseIfOrWhenExpr(p, nkWhenExpr) of tkCase: # Currently we think nimpretty is good enough with case expressions, # so it is allowed to touch them: @@ -1559,7 +1562,7 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode = branch.add(parseStmt(p)) result.add(branch) -proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode = +proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode = #| condExpr = expr colcom expr optInd #| ('elif' expr colcom expr optInd)* #| 'else' colcom expr diff --git a/tests/parser/tstmtlists.nim b/tests/parser/tstmtlists.nim index b6c7e4a94..fa47ba364 100644 --- a/tests/parser/tstmtlists.nim +++ b/tests/parser/tstmtlists.nim @@ -50,6 +50,8 @@ hello 9 hello 10 +lucky +lucky ''' """ @@ -163,3 +165,16 @@ template dim: int = else: int.high) +# lenient indentation: + +echo (if 0 == 1: + "0 == 1" +else: + "lucky") + +# bug #16426 +echo (when 0 == 1: + "0 == 1" +else: + "lucky") + From dd2cbe3164e476dafda4b59d6ed518d79f69f195 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 28 Jun 2021 19:25:30 +0200 Subject: [PATCH 2774/4254] Cleanup lookups.nim again.. (#18379) --- compiler/lookups.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 9b878dd4b..44a30eefa 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -58,8 +58,8 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent = template addSym*(scope: PScope, s: PSym) = strTableAdd(scope.symbols, s) -proc addUniqueSym*(scope: PScope, s: PSym, onConflictKeepOld: bool): PSym = - result = strTableInclReportConflict(scope.symbols, s, onConflictKeepOld) +proc addUniqueSym*(scope: PScope, s: PSym): PSym = + result = strTableInclReportConflict(scope.symbols, s) proc openScope*(c: PContext): PScope {.discardable.} = result = PScope(parent: c.currentScope, @@ -298,7 +298,7 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; # xxx pending bootstrap >= 1.4, replace all those overloads with a single one: # proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} = proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = - let conflict = scope.addUniqueSym(sym, onConflictKeepOld = true) + let conflict = scope.addUniqueSym(sym) if conflict != nil: if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner: # e.g.: import foo; import foo @@ -320,7 +320,7 @@ proc addDecl*(c: PContext, sym: PSym) {.inline.} = addDeclAt(c, c.currentScope, sym) proc addPrelimDecl*(c: PContext, sym: PSym) = - discard c.currentScope.addUniqueSym(sym, onConflictKeepOld = false) + discard c.currentScope.addUniqueSym(sym) from ic / ic import addHidden From 808db3b2845dab9822bc82ae80073a68396db999 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 28 Jun 2021 22:01:06 +0200 Subject: [PATCH 2775/4254] Fix unused warning for $ on empty object (#18381) --- lib/system/dollars.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index c23ea347d..baae8f090 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -113,7 +113,7 @@ proc `$`*[T: tuple|object](x: T): string = ## $() == "()" result = "(" const isNamed = T is object or isNamedTuple(T) - var count = 0 + var count {.used.} = 0 for name, value in fieldPairs(x): if count > 0: result.add(", ") when isNamed: From 6387e289631c22b8fa81e8e478c97cc500b90e26 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 28 Jun 2021 13:09:14 -0700 Subject: [PATCH 2776/4254] simplify rdstdin (#18382) --- lib/impure/rdstdin.nim | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index c580b89d1..32048b131 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -52,16 +52,6 @@ elif defined(genode): else: import linenoise - proc readLineFromStdin*(prompt: string): string {. - tags: [ReadIOEffect, WriteIOEffect].} = - var buffer = linenoise.readLine(prompt) - if isNil(buffer): - raise newException(IOError, "Linenoise returned nil") - result = $buffer - if result.len > 0: - historyAdd(buffer) - linenoise.free(buffer) - proc readLineFromStdin*(prompt: string, line: var string): bool {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = linenoise.readLine(prompt) @@ -73,3 +63,7 @@ else: historyAdd(buffer) linenoise.free(buffer) result = true + + proc readLineFromStdin*(prompt: string): string {.inline.} = + if not readLineFromStdin(prompt, result): + raise newException(IOError, "Linenoise returned nil") From 97fc95012d2725b625c492b6b72336a89c501076 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 29 Jun 2021 15:34:39 +0200 Subject: [PATCH 2777/4254] fixes #16270 (#18388) --- compiler/ast.nim | 3 ++- compiler/semexprs.nim | 1 + compiler/sigmatch.nim | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 56043692f..2a2a84e76 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -499,7 +499,7 @@ type nfFirstWrite# this node is a first write TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: ~40) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43) tfVarargs, # procedure has C styled varargs # tyArray type represeting a varargs list tfNoSideEffect, # procedure type does not allow side effects @@ -566,6 +566,7 @@ type # (for importc types); type is fully specified, allowing to compute # sizeof, alignof, offsetof at CT tfExplicitCallConv + tfIsConstructor TTypeFlags* = set[TTypeFlag] diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c885f4963..acf408db0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2412,6 +2412,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = proc semSetConstr(c: PContext, n: PNode): PNode = result = newNodeI(nkCurly, n.info) result.typ = newTypeS(tySet, c) + result.typ.flags.incl tfIsConstructor if n.len == 0: rawAddSon(result.typ, newTypeS(tyEmpty, c)) else: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index b2003c0a8..071685057 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1341,8 +1341,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isSubtype else: result = typeRel(c, f[0], a[0], flags) - if result <= isConvertible: - result = isNone # BUGFIX! + if result < isGeneric: + if result <= isConvertible: + result = isNone + elif tfIsConstructor notin a.flags: + # set constructors are a bit special... + result = isNone + of tyPtr, tyRef: skipOwned(a) if a.kind == f.kind: From 36d24846b6685a44ff2185a823cdcb0f3bc236d3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 29 Jun 2021 18:08:50 -0700 Subject: [PATCH 2778/4254] typo: enmRange => enumElementsAsSet (#18394) --- lib/std/setutils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index aba5f348a..84cc93623 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -36,7 +36,7 @@ template toSet*(iter: untyped): untyped = incl(result, x) result -macro enmRange(enm: typed): untyped = result = newNimNode(nnkCurly).add(enm.getType[1][1..^1]) +macro enumElementsAsSet(enm: typed): untyped = result = newNimNode(nnkCurly).add(enm.getType[1][1..^1]) # func fullSet*(T: typedesc): set[T] {.inline.} = # xxx would give: Error: ordinal type expected func fullSet*[T](U: typedesc[T]): set[T] {.inline.} = @@ -49,7 +49,7 @@ func fullSet*[T](U: typedesc[T]): set[T] {.inline.} = when T is Ordinal: {T.low..T.high} else: # Hole filled enum - enmRange(T) + enumElementsAsSet(T) func complement*[T](s: set[T]): set[T] {.inline.} = ## Returns the set complement of `a`. From afe5eb569b36ed310f6f93a33ae52274a6dce02e Mon Sep 17 00:00:00 2001 From: Elliot Waite Date: Tue, 29 Jun 2021 19:21:30 -0700 Subject: [PATCH 2779/4254] Add commas to docs for clarity (#18398) --- doc/tut2.rst | 2 +- lib/pure/asyncdispatch.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/tut2.rst b/doc/tut2.rst index 2624b2690..725f68dd5 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -79,7 +79,7 @@ to introduce new object roots apart from `system.RootObj`. (This is used in the GTK wrapper for instance.) Ref objects should be used whenever inheritance is used. It isn't strictly -necessary, but with non-ref objects assignments such as `let person: Person = +necessary, but with non-ref objects, assignments such as `let person: Person = Student(id: 123)` will truncate subclass fields. **Note**: Composition (*has-a* relation) is often preferable to inheritance diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index b88d5ede8..17fd5f824 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -61,8 +61,8 @@ ## callback on this future which will be called once the future completes. ## All the callback does is write the data stored in the future to `stdout`. ## The `read` function is used for this and it checks whether the future -## completes with an error for you (if it did it will simply raise the -## error), if there is no error however it returns the value of the future. +## completes with an error for you (if it did, it will simply raise the +## error), if there is no error, however, it returns the value of the future. ## ## Asynchronous procedures ## ======================= From 0483a5ffaf3284b6bfc51e2e08bbc1d5a57cd939 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 29 Jun 2021 22:16:31 -0700 Subject: [PATCH 2780/4254] improvements to hint:processing: show import stack, distinguish nims, show includes etc (#18372) * improvements to hint:processing * fix tests; do not show hintProcessing for nimscript unless given -d:nimHintProcessingNims * fix trunner and avoid need for -d:nimHintProcessingNims * fix some tests --- compiler/lineinfos.nim | 5 +++-- compiler/modulegraphs.nim | 12 ++++++++++++ compiler/modules.nim | 11 ++++++----- compiler/passaux.nim | 13 ++++--------- compiler/semstmts.nim | 1 + nimsuggest/tests/tchk1.nim | 2 +- nimsuggest/tests/tchk_compiles.nim | 2 +- nimsuggest/tests/ttempl_inst.nim | 2 +- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 131fe480b..801c20d25 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -75,7 +75,7 @@ type hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", - hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintCodeBegin = "CodeBegin", + hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintProcessingStmt = "ProcessingStmt", hintCodeBegin = "CodeBegin", hintCodeEnd = "CodeEnd", hintConf = "Conf", hintPath = "Path", hintConditionAlwaysTrue = "CondTrue", hintConditionAlwaysFalse = "CondFalse", hintName = "Name", hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency", @@ -163,6 +163,7 @@ const hintExprAlwaysX: "expression evaluates always to '$1'", hintQuitCalled: "quit() called", hintProcessing: "$1", + hintProcessingStmt: "$1", hintCodeBegin: "generated code listing:", hintCodeEnd: "end of listing", hintConf: "used config file '$1'", @@ -202,7 +203,7 @@ type proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed} - result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext, hintDeclaredLoc} + result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance} diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 0d8d4f867..90b130e92 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -582,3 +582,15 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex; proc configComplete*(g: ModuleGraph) = rememberStartupConfig(g.startupPackedConfig, g.config) + +from std/strutils import repeat, `%` + +proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym, ) = + let conf = graph.config + let isNimscript = conf.isDefined("nimscript") + if (not isNimscript) or hintProcessing in conf.cmdlineNotes: + let path = toFilenameOption(conf, fileIdx, conf.filenameOption) + let indent = ">".repeat(graph.importStack.len) + let fromModule2 = if fromModule != nil: $fromModule.name.s else: "(toplevel)" + let mode = if isNimscript: "(nims) " else: "" + rawMessage(conf, hintProcessing, "$#$# $#: $#: $#" % [mode, indent, fromModule2, moduleStatus, path]) diff --git a/compiler/modules.nim b/compiler/modules.nim index dcfcfd508..6fba606b2 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -84,12 +84,13 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = partialInitModule(result, graph, fileIdx, filename) graph.registerModule(result) -proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym = +proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym = var flags = flags if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule result = graph.getModule(fileIdx) - template processModuleAux = + template processModuleAux(moduleStatus) = + onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule) var s: PLLStream if sfMainModule in flags: if graph.config.projectIsStdin: s = stdin.llStreamOpen @@ -103,7 +104,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P result = newModule(graph, fileIdx) result.flags.incl flags registerModule(graph, result) - processModuleAux() + processModuleAux("import") else: if sfSystemModule in flags: graph.systemModule = result @@ -117,13 +118,13 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P # reset module fields: initStrTables(graph, result) result.ast = nil - processModuleAux() + processModuleAux("import(dirty)") graph.markClientsDirty(fileIdx) proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = # this is called by the semantic checking phase assert graph.config != nil - result = compileModule(graph, fileIdx, {}) + result = compileModule(graph, fileIdx, {}, s) graph.addDep(s, fileIdx) # keep track of import relationships if graph.config.hcrOn: diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 87cb3a730..68b783248 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -19,18 +19,13 @@ type config: ConfigRef proc verboseOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = - let conf = graph.config - result = VerboseRef(config: conf, idgen: idgen) - let path = toFilenameOption(conf, s.position.FileIndex, conf.filenameOption) - rawMessage(conf, hintProcessing, path) + # xxx consider either removing this or keeping for documentation for how to add a pass + result = VerboseRef(config: graph.config, idgen: idgen) proc verboseProcess(context: PPassContext, n: PNode): PNode = + # called from `process` in `processTopLevelStmt`. result = n let v = VerboseRef(context) - if v.config.verbosity == 3: - # system.nim deactivates all hints, for verbosity:3 we want the processing - # messages nonetheless, so we activate them again (but honor cmdlineNotes) - v.config.setNote(hintProcessing) - message(v.config, n.info, hintProcessing, $v.idgen[]) + message(v.config, n.info, hintProcessingStmt, $v.idgen[]) const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f29dc24ef..2907d5172 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2158,6 +2158,7 @@ proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) = var f = checkModuleName(c.config, it) if f != InvalidFileIdx: addIncludeFileDep(c, f) + onProcessing(c.graph, f, "include", c.module) if containsOrIncl(c.includedFiles, f.int): localError(c.config, n.info, errRecursiveDependencyX % toMsgFilename(c.config, f)) else: diff --git a/nimsuggest/tests/tchk1.nim b/nimsuggest/tests/tchk1.nim index 794392c1f..f8e2989c5 100644 --- a/nimsuggest/tests/tchk1.nim +++ b/nimsuggest/tests/tchk1.nim @@ -17,7 +17,7 @@ proc main = discard """ $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tests/tchk1.nim [Processing]";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tchk1.nim [Processing]";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but got \'keyword template\'";;0 chk;;skUnknown;;;;Error;;$file;;14;;0;;"nestable statement requires indentation";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0 diff --git a/nimsuggest/tests/tchk_compiles.nim b/nimsuggest/tests/tchk_compiles.nim index 2afa06899..c8a3daac4 100644 --- a/nimsuggest/tests/tchk_compiles.nim +++ b/nimsuggest/tests/tchk_compiles.nim @@ -4,5 +4,5 @@ discard compiles(2 + "hello") discard """ $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tests/tchk_compiles.nim [Processing]";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tchk_compiles.nim [Processing]";;0 """ diff --git a/nimsuggest/tests/ttempl_inst.nim b/nimsuggest/tests/ttempl_inst.nim index da413d99a..5f5b10fe9 100644 --- a/nimsuggest/tests/ttempl_inst.nim +++ b/nimsuggest/tests/ttempl_inst.nim @@ -7,7 +7,7 @@ foo() discard """ $nimsuggest --tester $file >chk $1 -chk;;skUnknown;;;;Hint;;???;;0;;-1;;"tests/ttempl_inst.nim [Processing]";;0 +chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/ttempl_inst.nim [Processing]";;0 chk;;skUnknown;;;;Hint;;$file;;4;;3;;"template/generic instantiation from here";;0 chk;;skUnknown;;;;Warning;;$file;;2;;11;;"foo [User]";;0 """ From 16f0b556643a8a9cc73781de6d71d0041a194640 Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 30 Jun 2021 13:28:41 +0800 Subject: [PATCH 2781/4254] remove isKeywordIgnoreCase from highlite, not used , can't even compile with -d:useNimRtl (#18399) --- lib/packages/docutils/highlite.nim | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 014303837..d36b2c877 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -188,9 +188,6 @@ const proc isKeyword(x: openArray[string], y: string): int = binarySearch(x, y) -proc isKeywordIgnoreCase(x: openArray[string], y: string): int = - binarySearch(x, y, cmpIgnoreCase) - proc nimNextToken(g: var GeneralTokenizer, keywords: openArray[string] = @[]) = const hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'} From eaa1c3a37754725f91f54f23080980b82c2f2356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Wed, 30 Jun 2021 07:29:10 +0200 Subject: [PATCH 2782/4254] genDepend: fix for module names that are reserved DOT keywords (#18392) (like "node" and "edge") --- compiler/depends.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/depends.nim b/compiler/depends.nim index 7225b6b47..30fc961c5 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -25,7 +25,7 @@ type dotGraph: Rope proc addDependencyAux(b: Backend; importing, imported: string) = - b.dotGraph.addf("$1 -> \"$2\";$n", [rope(importing), rope(imported)]) + b.dotGraph.addf("\"$1\" -> \"$2\";$n", [rope(importing), rope(imported)]) # s1 -> s2_4[label="[0-9]"]; proc addDotDependency(c: PPassContext, n: PNode): PNode = From 19263f27756e56026fe8d1ac05966b84010ae8d1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 30 Jun 2021 12:36:24 +0200 Subject: [PATCH 2783/4254] fixes #18400 (#18402) --- lib/system/schubfach.nim | 2 +- tests/float/tfloat4.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/system/schubfach.nim b/lib/system/schubfach.nim index d072cde99..06813f632 100644 --- a/lib/system/schubfach.nim +++ b/lib/system/schubfach.nim @@ -359,7 +359,7 @@ proc formatDigits(buffer: var openArray[char]; pos: int; digits: uint32; decimal pos = digitsEnd elif decimalPoint < numDigits: ## dig.its - for i in 0..<8: + for i in countdown(7, 0): buffer[i + decimalPoint + 1] = buffer[i + decimalPoint] buffer[pos+decimalPoint] = '.' pos = digitsEnd + 1 diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim index 6a87cbe66..5bedca371 100644 --- a/tests/float/tfloat4.nim +++ b/tests/float/tfloat4.nim @@ -54,4 +54,10 @@ doAssert 9999999999999999.0 == "9999999999999999.0".parseFloat doAssert 0.999999999999999 == ".999999999999999".parseFloat doAssert 0.9999999999999999 == ".9999999999999999".parseFloat +# bug #18400 +var s = [-13.888888'f32] +assert $s[0] == "-13.888888" +var x = 1.23456789012345'f32 +assert $x == "1.2345679" + echo("passed all tests.") From 28a4814019ea5d985d323def3766fe7f44f2e3e1 Mon Sep 17 00:00:00 2001 From: Endeg Date: Wed, 30 Jun 2021 23:19:22 +0600 Subject: [PATCH 2784/4254] Missing spaces when compiling testament and nim_dbg. (#18403) --- koch.nim | 4 ++-- lib/pure/times.nim | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index d3957069b..4ba0d0eb5 100644 --- a/koch.nim +++ b/koch.nim @@ -215,14 +215,14 @@ proc buildTools(args: string = "") = options = "-d:release " & args) when defined(windows): buildVccTool(args) bundleNimpretty(args) - nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release" & args) + nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release " & args) # pre-packages a debug version of nim which can help in many cases investigate issuses # withouth having to rebuild compiler. # `-d:nimDebugUtils` only makes sense when temporarily editing/debugging compiler # `-d:debug` should be changed to a flag that doesn't require re-compiling nim # `--opt:speed` is a sensible default even for a debug build, it doesn't affect nim stacktraces - nimCompileFold("Compile nim_dbg", "compiler/nim.nim", options = "--opt:speed --stacktrace -d:debug --stacktraceMsgs -d:nimCompilerStacktraceHints" & args, outputName = "nim_dbg") + nimCompileFold("Compile nim_dbg", "compiler/nim.nim", options = "--opt:speed --stacktrace -d:debug --stacktraceMsgs -d:nimCompilerStacktraceHints " & args, outputName = "nim_dbg") proc nsis(latest: bool; args: string) = bundleNimbleExe(latest, args) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index fb48a199c..fcdd4ec8d 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -913,7 +913,7 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} = result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) elif defined(windows): var f {.noinit.}: FILETIME - getSystemTimePreciseAsFileTime(f) + getSystemTimeAsFileTime(f) result = fromWinTime(rdFileTime(f)) proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = @@ -2596,7 +2596,7 @@ proc epochTime*(): float {.tags: [TimeEffect].} = toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 elif defined(windows): var f {.noinit.}: winlean.FILETIME - getSystemTimePreciseAsFileTime(f) + getSystemTimeAsFileTime(f) var i64 = rdFileTime(f) - epochDiff var secs = i64 div rateDiff var subsecs = i64 mod rateDiff From 17911a116d8677228480d74ceb2b9593b992253e Mon Sep 17 00:00:00 2001 From: Mark Pointing Date: Thu, 1 Jul 2021 03:22:38 +1000 Subject: [PATCH 2785/4254] Removed hard coded ports from thttpclient_standalone.nim. (#18374) Co-authored-by: Dominik Picheta Co-authored-by: Mark Pointing Co-authored-by: Andreas Rumpf Co-authored-by: Timothee Cour --- tests/stdlib/thttpclient_standalone.nim | 49 +++++++++++++------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/tests/stdlib/thttpclient_standalone.nim b/tests/stdlib/thttpclient_standalone.nim index 5fa1ea41a..362b1cb86 100644 --- a/tests/stdlib/thttpclient_standalone.nim +++ b/tests/stdlib/thttpclient_standalone.nim @@ -2,29 +2,37 @@ discard """ cmd: "nim c --threads:on $file" """ -import asynchttpserver, httpclient, asyncdispatch, strutils +import asynchttpserver, httpclient, asyncdispatch, strutils, net block: # bug #16436 - proc startServer() {.async.} = + proc startServer(): AsyncHttpServer = + result = newAsyncHttpServer() + result.listen(Port(0)) + + proc processRequest(server: AsyncHttpServer) {.async.} = proc cb(req: Request) {.async.} = let headers = { "Content-length": "15"} # Provide invalid content-length await req.respond(Http200, "Hello World", headers.newHttpHeaders()) - var server = newAsyncHttpServer() - await server.serve(Port(5555), cb) + await server.acceptRequest(cb) - proc runClient() {.async.} = + proc runClient(port: Port) {.async.} = let c = newAsyncHttpClient(headers = {"Connection": "close"}.newHttpHeaders) - let r = await c.getContent("http://127.0.0.1:5555") + discard await c.getContent("http://127.0.0.1:" & $port) doAssert false, "should fail earlier" - asyncCheck startServer() + let server = startServer() + asyncCheck processRequest(server) + let port = server.getPort() doAssertRaises(ProtocolError): - waitFor runClient() + waitFor runClient(port) block: # bug #14794 (And test for presence of content-length header when using postContent) - proc startServer() {.async.} = - var killServer = false + proc startServer(): AsyncHttpServer = + result = newAsyncHttpServer() + result.listen(Port(0)) + + proc runServer(server: AsyncHttpServer) {.async.} = proc cb(req: Request) {.async.} = doAssert(req.body.endsWith(httpNewLine), "Multipart body does not end with a newline.") # this next line is probably not required because asynchttpserver does not call @@ -32,23 +40,18 @@ block: # bug #14794 (And test for presence of content-length header when using p # Error: unhandled exception: 411 Length Required # Added for good measure in case the server becomes more permissive. doAssert(req.headers.hasKey("content-length"), "Content-Length header is not present.") - killServer = true asyncCheck req.respond(Http200, "OK") - var server = newAsyncHttpServer() - server.listen(Port(5556)) - while not killServer: - if server.shouldAcceptRequest(): - await server.acceptRequest(cb) - else: - poll() + await server.acceptRequest(cb) - proc runClient() {.async.} = + proc runClient(port: Port) {.async.} = let c = newAsyncHttpClient() - var data = newMultipartData() + let data = newMultipartData() data.add("file.txt", "This is intended to be an example text file.\r\nThis would be the second line.\r\n") - let r = await c.postContent("http://127.0.0.1:5556", multipart = data) + discard await c.postContent("http://127.0.0.1:" & $port, multipart = data) c.close() - asyncCheck startServer() - waitFor runClient() + let server = startServer() + let port = server.getPort() + asyncCheck runServer(server) + waitFor runClient(port) From 41c29cb3a1674a8b85844888e831b79050d91293 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 1 Jul 2021 06:51:08 +0200 Subject: [PATCH 2786/4254] fixes #18130 (#18407) --- compiler/injectdestructors.nim | 2 +- tests/destructor/tv2_cast.nim | 87 +++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 6447557c5..6e4eaa817 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1057,7 +1057,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod result = c.genCopy(dest, ri) result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) - of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: + of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast: result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 5502cb38d..917cf0eb3 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -1,48 +1,81 @@ discard """ output: '''@[1] @[116, 101, 115, 116] -@[1953719668, 875770417]''' +@[1953719668, 875770417] +destroying O1''' cmd: '''nim c --gc:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file''' nimout: '''--expandArc: main var data :tmpD -`=copy`(data, cast[string](encode(cast[seq[byte]]( - :tmpD = newString(100) - :tmpD)))) -`=destroy`(:tmpD) -`=destroy`(data) + :tmpD_1 + :tmpD_2 +data = + wasMoved(:tmpD) + `=copy`(:tmpD, cast[string]( + :tmpD_2 = encode(cast[seq[byte]]( + :tmpD_1 = newString(100) + :tmpD_1)) + :tmpD_2)) + :tmpD +`=destroy`(:tmpD_2) +`=destroy_1`(:tmpD_1) +`=destroy_1`(data) -- end of expandArc ------------------------ --expandArc: main1 var s data + :tmpD + :tmpD_1 s = newString(100) -`=copy`(data, cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1)))) -`=destroy`(data) -`=destroy`(s) +data = + wasMoved(:tmpD) + `=copy`(:tmpD, cast[string]( + :tmpD_1 = encode(toOpenArrayByte(s, 0, len(s) - 1)) + :tmpD_1)) + :tmpD +`=destroy`(:tmpD_1) +`=destroy_1`(data) +`=destroy_1`(s) -- end of expandArc ------------------------ --expandArc: main2 var s data + :tmpD + :tmpD_1 s = newSeq(100) -`=copy`(data, cast[string](encode(s))) -`=destroy`(data) -`=destroy_1`(s) +data = + wasMoved(:tmpD) + `=copy`(:tmpD, cast[string]( + :tmpD_1 = encode(s) + :tmpD_1)) + :tmpD +`=destroy`(:tmpD_1) +`=destroy_1`(data) +`=destroy`(s) -- end of expandArc ------------------------ --expandArc: main3 var data :tmpD -`=copy`(data, cast[string](encode do: - :tmpD = newSeq(100) - :tmpD)) -`=destroy`(:tmpD) + :tmpD_1 + :tmpD_2 +data = + wasMoved(:tmpD) + `=copy`(:tmpD, cast[string]( + :tmpD_2 = encode do: + :tmpD_1 = newSeq(100) + :tmpD_1 + :tmpD_2)) + :tmpD +`=destroy`(:tmpD_2) +`=destroy`(:tmpD_1) `=destroy_1`(data) -- end of expandArc ------------------------''' """ @@ -89,3 +122,25 @@ echo a #issue 11204 var ac {.compileTime.} = @["a", "b"] const bc = ac.len + + +type + O = object of RootRef + i: int + + O1 = object of O + O2 = object of O + +proc `=destroy`(o: var O) = + echo "destroying O" + +proc `=destroy`(o: var O1) = + echo "destroying O1" + +proc `=destroy`(o: var O2) = + echo "destroying O2" + +proc test = + let o3 = cast[ref O2]((ref O1)()) + +test() From 779b4e307bdeb018bb2884920144a8c0d1f3b377 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 1 Jul 2021 02:14:01 -0700 Subject: [PATCH 2787/4254] don't use `{.rtl.}` for generics, otherwise `-d:useNimRtl` gives `ambiguous identifier` nimrtl error (#18406) --- lib/pure/strutils.nim | 2 +- lib/system/inclrtl.nim | 13 +++++++------ tests/dll/client.nim | 8 +++++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 8e0a6158b..9e0837942 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1760,7 +1760,7 @@ func join*(a: openArray[string], sep: string = ""): string {.rtl, else: result = "" -func join*[T: not string](a: openArray[T], sep: string = ""): string {.rtl.} = +func join*[T: not string](a: openArray[T], sep: string = ""): string = ## Converts all elements in the container `a` to strings using `$`, ## and concatenates them with `sep`. runnableExamples: diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 0bc51d693..ca41f39c6 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -30,12 +30,13 @@ when defined(createNimRtl): {.pragma: inl.} {.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.} elif defined(useNimRtl): - when defined(windows): - const nimrtl* = "nimrtl.dll" - elif defined(macosx): - const nimrtl* = "libnimrtl.dylib" - else: - const nimrtl* = "libnimrtl.so" + #[ + `{.rtl.}` should only be used for non-generic procs. + ]# + const nimrtl* = + when defined(windows): "nimrtl.dll" + elif defined(macosx): "libnimrtl.dylib" + else: "libnimrtl.so" {.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl, gcsafe.} {.pragma: inl.} {.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.} diff --git a/tests/dll/client.nim b/tests/dll/client.nim index 150af3a17..62697569f 100644 --- a/tests/dll/client.nim +++ b/tests/dll/client.nim @@ -1,5 +1,4 @@ discard """ - output: "Done" cmd: "nim $target --debuginfo --hints:on --define:useNimRtl $options $file" """ @@ -37,5 +36,8 @@ proc eval(n: PNode): int = for i in 0..100_000: discard eval(buildTree(2)) -echo "Done" - +# bug https://forum.nim-lang.org/t/8176; Error: ambiguous identifier: 'nimrtl' +import std/strutils +doAssert join(@[1, 2]) == "12" +doAssert join(@[1.5, 2.5]) == "1.52.5" +doAssert join(@["a", "bc"]) == "abc" From 3ceaf5c1309ac8d4d68e6f39c13b021bcc1b15f4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 1 Jul 2021 17:35:04 +0200 Subject: [PATCH 2788/4254] fixes #18030 (#18415) --- compiler/seminst.nim | 2 +- tests/arc/tarcmisc.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 68ab2a310..e1fad236c 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -146,8 +146,8 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) = freshGenSyms(c, b, result, orig, symMap) b = semProcBody(c, b) result.ast[bodyPos] = hloBody(c, b) - trackProc(c, result, result.ast[bodyPos]) excl(result.flags, sfForward) + trackProc(c, result, result.ast[bodyPos]) dec c.inGenericInst proc fixupInstantiatedSymbols(c: PContext, s: PSym) = diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index a52538085..5d5d8e914 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -28,6 +28,8 @@ aaaaa hello ok true +copying +123 closed destroying variable: 20 destroying variable: 10 @@ -433,3 +435,31 @@ proc t17712 = echo el != nil t17712() + +# bug #18030 + +type + Foo = object + n: int + +proc `=copy`(dst: var Foo, src: Foo) = + echo "copying" + dst.n = src.n + +proc `=sink`(dst: var Foo, src: Foo) = + echo "sinking" + dst.n = src.n + +var a: Foo + +proc putValue[T](n: T) + +proc useForward = + putValue(123) + +proc putValue[T](n: T) = + var b = Foo(n:n) + a = b + echo b.n + +useForward() From 60eac79f7f0478565a24ff423aa52ab53527d153 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 2 Jul 2021 20:38:01 +0800 Subject: [PATCH 2789/4254] [minor]remove unnecessary stringify (#18419) --- compiler/lexer.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 59b983060..c7a9aa47f 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -536,9 +536,9 @@ proc getNumber(L: var Lexer, result: var Token) = try: len = parseBiggestUInt(result.literal, iNumber) except ValueError: - raise newException(OverflowDefect, "number out of range: " & $result.literal) + raise newException(OverflowDefect, "number out of range: " & result.literal) if len != result.literal.len: - raise newException(ValueError, "invalid integer: " & $result.literal) + raise newException(ValueError, "invalid integer: " & result.literal) result.iNumber = cast[int64](iNumber) else: var iNumber: int64 @@ -546,9 +546,9 @@ proc getNumber(L: var Lexer, result: var Token) = try: len = parseBiggestInt(result.literal, iNumber) except ValueError: - raise newException(OverflowDefect, "number out of range: " & $result.literal) + raise newException(OverflowDefect, "number out of range: " & result.literal) if len != result.literal.len: - raise newException(ValueError, "invalid integer: " & $result.literal) + raise newException(ValueError, "invalid integer: " & result.literal) result.iNumber = iNumber # Explicit bounds checks. From d1d2498c7b933b6364af450df5088aaa89b4cf4b Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:20:59 +0300 Subject: [PATCH 2790/4254] Add lent annotation to avoid extra copies in sample (#18404) * Add lent annotation to avoid extra copies in sample * Remove lent * Update random.nim --- lib/pure/random.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 6a5f35bde..07db0365c 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -410,7 +410,7 @@ proc sample*[T](r: var Rand; a: openArray[T]): T = result = a[r.rand(a.low..a.high)] -proc sample*[T](a: openArray[T]): T = +proc sample*[T](a: openArray[T]): lent T = ## Returns a random element from `a`. ## ## If `randomize <#randomize>`_ has not been called, the order of outcomes From ffa638ed5023834a7a5040a54c6cfde550d68054 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 5 Jul 2021 05:26:40 -0700 Subject: [PATCH 2791/4254] std/net: show addr+port on address already in use error; code-block => runnableExamples (#18428) * std/net: show addr+port on address already in use error; code-block => runnableExamples * var=>let --- lib/pure/net.nim | 80 ++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ff179fb2c..ec3e4e74d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -44,46 +44,44 @@ ## After you create a socket with the `newSocket` procedure, you can easily ## connect it to a server running at a known hostname (or IP address) and port. ## To do so over TCP, use the example below. -## -## .. code-block:: Nim -## var socket = newSocket() -## socket.connect("google.com", Port(80)) -## -## For SSL, use the following example (and make sure to compile with `-d:ssl`): -## -## .. code-block:: Nim -## var socket = newSocket() -## var ctx = newContext() -## wrapSocket(ctx, socket) -## socket.connect("google.com", Port(443)) -## + +runnableExamples("-r:off"): + let socket = newSocket() + socket.connect("google.com", Port(80)) + +## For SSL, use the following example: + +runnableExamples("-r:off -d:ssl"): + let socket = newSocket() + let ctx = newContext() + wrapSocket(ctx, socket) + socket.connect("google.com", Port(443)) + ## UDP is a connectionless protocol, so UDP sockets don't have to explicitly ## call the `connect `_ procedure. They can ## simply start sending data immediately. -## -## .. code-block:: Nim -## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) -## socket.sendTo("192.168.0.1", Port(27960), "status\n") -## + +runnableExamples("-r:off"): + let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + socket.sendTo("192.168.0.1", Port(27960), "status\n") + ## Creating a server ## ----------------- ## ## After you create a socket with the `newSocket` procedure, you can create a ## TCP server by calling the `bindAddr` and `listen` procedures. -## -## .. code-block:: Nim -## var socket = newSocket() -## socket.bindAddr(Port(1234)) -## socket.listen() -## -## You can then begin accepting connections using the `accept` procedure. -## -## .. code-block:: Nim -## var client: Socket -## var address = "" -## while true: -## socket.acceptAddr(client, address) -## echo("Client connected from: ", address) + +runnableExamples("-r:off"): + let socket = newSocket() + socket.bindAddr(Port(1234)) + socket.listen() + + # You can then begin accepting connections using the `accept` procedure. + var client: Socket + var address = "" + while true: + socket.acceptAddr(client, address) + echo "Client connected from: ", address import std/private/since @@ -960,7 +958,7 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: freeaddrinfo(aiList) - raiseOSError(osLastError()) + raiseOSError(osLastError(), "address: $# port: $#" % [address, $port]) freeaddrinfo(aiList) proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, @@ -1233,12 +1231,10 @@ proc getPeerAddr*(socket: Socket): (string, Port) = proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.tags: [WriteIOEffect].} = ## Sets option `opt` to a boolean value specified by `value`. - ## - ## .. code-block:: Nim - ## var socket = newSocket() - ## socket.setSockOpt(OptReusePort, true) - ## socket.setSockOpt(OptNoDelay, true, level=IPPROTO_TCP.toInt) - ## + runnableExamples("-r:off"): + let socket = newSocket() + socket.setSockOpt(OptReusePort, true) + socket.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint) var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) @@ -2025,10 +2021,8 @@ proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress = ## ## Supports IPv4 and v6. ## Raises OSError if external networking is not set up. - ## - ## .. code-block:: Nim - ## echo $getPrimaryIPAddr() # "192.168.1.2" - + runnableExamples("-r:off"): + echo getPrimaryIPAddr() # "192.168.1.2" let socket = if dest.family == IpAddressFamily.IPv4: newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) From 1bed7773146d6acf704b0ae5cfe62455f7a127a1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 5 Jul 2021 18:04:07 +0200 Subject: [PATCH 2792/4254] fixes #18411 (#18432) [backport:1.4] --- lib/system/excpt.nim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 5b7d4d49f..9f65db2fe 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -446,9 +446,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = pushCurrentException(e) {.emit: "throw `e`;".} elif defined(nimQuirky) or gotoBasedExceptions: - # XXX This check should likely also be done in the setjmp case below. - if e != currException: - pushCurrentException(e) + pushCurrentException(e) when gotoBasedExceptions: inc nimInErrorMode else: From 927a832dde9403492d4a2838780bf59bd1a48177 Mon Sep 17 00:00:00 2001 From: pyautogui <79544976+pyautogui@users.noreply.github.com> Date: Mon, 5 Jul 2021 10:12:58 -0700 Subject: [PATCH 2793/4254] deprecate std/mersenne (#18395) Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Timothee Cour Co-authored-by: Andreas Rumpf --- changelog.md | 2 ++ lib/pure/mersenne.nim | 12 ++++-------- tests/stdlib/tmersenne.nim | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index 6672f7538..a4c5b4e62 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,8 @@ ## Changes affecting backward compatibility +- Deprecated `std/mersenne` + - `cuchar` now aliases `uint8` instead of `char` - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index 6778e2d62..6ec0d66b4 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -2,24 +2,20 @@ # # Nim's Runtime Library # (c) Copyright 2015 Nim Contributors -# # See the file "copying.txt", included in this # distribution, for details about the copyright. -# - ## The [Mersenne Twister](https://en.wikipedia.org/wiki/Mersenne_Twister) ## random number generator. -## -## **Note:** The procs in this module work at compile-time. +## .. note:: The procs in this module work at compile-time. + +{.deprecated: "use `std/random` instead.".} runnableExamples: var rand = newMersenneTwister(uint32.high) ## must be "var" doAssert rand.getNum() != rand.getNum() ## pseudorandom number - ## See also ## ======== ## * `random module`_ for Nim's standard random number generator - type MersenneTwister* = object ## The Mersenne Twister. @@ -35,6 +31,7 @@ proc newMersenneTwister*(seed: uint32): MersenneTwister = (result.mt[i-1] shr 30'u32)) + i) proc generateNumbers(m: var MersenneTwister) = + for i in 0..623: var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32) @@ -48,7 +45,6 @@ proc getNum*(m: var MersenneTwister): uint32 = generateNumbers(m) result = m.mt[m.index] m.index = (m.index + 1) mod m.mt.len - result = result xor (result shr 11'u32) result = result xor ((result shl 7'u32) and 0x9d2c5680'u32) result = result xor ((result shl 15'u32) and 0xefc60000'u32) diff --git a/tests/stdlib/tmersenne.nim b/tests/stdlib/tmersenne.nim index 2707aa2f2..54eb7b216 100644 --- a/tests/stdlib/tmersenne.nim +++ b/tests/stdlib/tmersenne.nim @@ -7,5 +7,6 @@ template main() = doAssert mt.getNum == 1071751096'u32 doAssert mt.getNum == 3805347140'u32 + static: main() main() From 36654fd577f46c49191c5e6f7e499ea31193018c Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Mon, 5 Jul 2021 21:55:46 +0300 Subject: [PATCH 2794/4254] Cleanup interval and timeout procs (#18431) clear/setTimeout procs were using ref ref Timeout. Added more interval overloads. Corrections. --- lib/js/dom.nim | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index ca325fdd2..3f0b9f630 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1301,7 +1301,7 @@ type width*: int TimeOut* {.importc.} = ref object of RootObj - Interval* {.importc.} = object of RootObj + Interval* {.importc.} = ref object of RootObj AddEventListenerOptions* = object capture*: bool @@ -1481,6 +1481,8 @@ else: proc setTimeout*(action: proc(); ms: int): TimeOut {.importc, nodecl.} proc clearTimeout*(t: TimeOut) {.importc, nodecl.} +proc setInterval*(action: proc(); ms: int): Interval {.importc, nodecl.} +proc clearInterval*(i: Interval) {.importc, nodecl.} {.push importcpp.} @@ -1494,8 +1496,8 @@ proc removeEventListener*(et: EventTarget; ev: cstring; cb: proc(ev: Event)) proc alert*(w: Window, msg: cstring) proc back*(w: Window) proc blur*(w: Window) -proc clearInterval*(w: Window, interval: ref Interval) -proc clearTimeout*(w: Window, timeout: ref TimeOut) +proc clearInterval*(w: Window, interval: Interval) +proc clearTimeout*(w: Window, timeout: TimeOut) proc close*(w: Window) proc confirm*(w: Window, msg: cstring): bool proc disableExternalCapture*(w: Window) @@ -1520,10 +1522,10 @@ proc resizeTo*(w: Window, x, y: int) proc routeEvent*(w: Window, event: Event) proc scrollBy*(w: Window, x, y: int) proc scrollTo*(w: Window, x, y: int) -proc setInterval*(w: Window, code: cstring, pause: int): ref Interval -proc setInterval*(w: Window, function: proc (), pause: int): ref Interval -proc setTimeout*(w: Window, code: cstring, pause: int): ref TimeOut -proc setTimeout*(w: Window, function: proc (), pause: int): ref Interval +proc setInterval*(w: Window, code: cstring, pause: int): Interval +proc setInterval*(w: Window, function: proc (), pause: int): Interval +proc setTimeout*(w: Window, code: cstring, pause: int): TimeOut +proc setTimeout*(w: Window, function: proc (), pause: int): Interval proc stop*(w: Window) proc requestAnimationFrame*(w: Window, function: proc (time: float)): int proc cancelAnimationFrame*(w: Window, id: int) @@ -1768,4 +1770,4 @@ since (1, 3): proc readAsDataURL*(f: FileReader, b: Blob) {.importcpp: "#.readAsDataURL(#)".} ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL proc readAsText*(f: FileReader, b: Blob|File, encoding = cstring"UTF-8") {.importcpp: "#.readAsText(#, #)".} - ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText \ No newline at end of file + ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText From c522f7f33ca08e6a441ebbb08ea9d2d79a3c500c Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Tue, 6 Jul 2021 08:21:50 +0300 Subject: [PATCH 2795/4254] Add entry (#18434) --- changelog.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index a4c5b4e62..028743bab 100644 --- a/changelog.md +++ b/changelog.md @@ -86,8 +86,8 @@ - Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` in `std/algorithm`. -- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes in a collapsed way, - use `-d:nimLegacyMacrosCollapseSymChoice` to get previous behavior. +- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes in a collapsed way, + use `-d:nimLegacyMacrosCollapseSymChoice` to get previous behavior. - The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. The downside is that these defines now have custom logic that doesn't apply for @@ -95,6 +95,8 @@ - Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints`. +- In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. Definitions of `setTimeout`, + `clearTimeout`, `setInterval`, `clearInterval` were updated. ## Standard library additions and changes @@ -341,6 +343,8 @@ - Added `dom.scrollIntoView` proc with options +- Added `dom.setInterval`, `dom.clearInterval` overloads. + ## Language changes - `nimscript` now handles `except Exception as e`. From 252eea8cae33e486b179398e193aea9459954338 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 5 Jul 2021 23:28:38 -0600 Subject: [PATCH 2796/4254] Make procedure mismatch more informative with pragma/call convention mismatches (#18384) * Added more concise calling convention/pragma mismatch messages * Now only adds callConvMsg/lock message when sensible * Fixed message formatting * Added tests, and fixed some bugs * Tests joined, and always indenting * More tests and more bug fixes * Fixed first test in tprocmismatch * Using var param for writting mismatches * Better logic for handling proc type rel and conv/pragma mismatch * Refactored getProcConvMismatch * Fixed callConv message formatting * Fixed test for proper message * Cleanup to address issues * getProcConvMismatch now returns tuple, and reformatted code --- compiler/semcall.nim | 8 ++- compiler/sigmatch.nim | 33 +----------- compiler/types.nim | 87 ++++++++++++++++++++++++++++++++ tests/errmsgs/tproc_mismatch.nim | 74 +++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 32 deletions(-) create mode 100644 tests/errmsgs/tproc_mismatch.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index b56a1dbac..cec656fc2 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -247,7 +247,13 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add typeToString(got) candidates.addDeclaredLocMaybe(c.config, got) doAssert wanted != nil - if got != nil: effectProblem(wanted, got, candidates, c) + if got != nil: + if got.kind == tyProc and wanted.kind == tyProc: + # These are proc mismatches so, + # add the extra explict detail of the mismatch + candidates.addPragmaAndCallConvMismatch(wanted, got, c.config) + effectProblem(wanted, got, candidates, c) + of kUnknown: discard "do not break 'nim check'" candidates.add "\n" if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 071685057..73ab5e9a3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -86,21 +86,6 @@ type TTypeRelFlags* = set[TTypeRelFlag] - TTypeRelation* = enum # order is important! - isNone, isConvertible, - isIntConv, - isSubtype, - isSubrange, # subrange of the wanted type; no type conversion - # but apart from that counts as ``isSubtype`` - isBothMetaConvertible # generic proc parameter was matched against - # generic type, e.g., map(mySeq, x=>x+1), - # maybe recoverable by rerun if the parameter is - # the proc's return value - isInferred, # generic proc was matched against a concrete type - isInferredConvertible, # same as above, but requiring proc CC conversion - isGeneric, - isFromIntLit, # conversion *from* int literal; proven safe - isEqual const isNilConversion = isConvertible # maybe 'isIntConv' fits better? @@ -640,23 +625,9 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = return isNone elif a[0] != nil: return isNone + + result = getProcConvMismatch(c.c.config, f, a, result)[1] - if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags: - return isNone - elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and - optThreadAnalysis in c.c.config.globalOptions: - # noSideEffect implies ``tfThread``! - return isNone - elif f.flags * {tfIterator} != a.flags * {tfIterator}: - return isNone - elif f.callConv != a.callConv: - # valid to pass a 'nimcall' thingie to 'closure': - if f.callConv == ccClosure and a.callConv == ccNimCall: - result = if result == isInferred: isInferredConvertible - elif result == isBothMetaConvertible: isBothMetaConvertible - else: isConvertible - else: - return isNone when useEffectSystem: if compatibleEffects(f, a) != efCompat: return isNone when defined(drnim): diff --git a/compiler/types.nim b/compiler/types.nim index bc970a6d2..bdf08ffe9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -26,6 +26,29 @@ type # most useful, shows: symbol + resolved symbols if it differs, e.g.: # tuple[a: MyInt{int}, b: float] + TTypeRelation* = enum # order is important! + isNone, isConvertible, + isIntConv, + isSubtype, + isSubrange, # subrange of the wanted type; no type conversion + # but apart from that counts as ``isSubtype`` + isBothMetaConvertible # generic proc parameter was matched against + # generic type, e.g., map(mySeq, x=>x+1), + # maybe recoverable by rerun if the parameter is + # the proc's return value + isInferred, # generic proc was matched against a concrete type + isInferredConvertible, # same as above, but requiring proc CC conversion + isGeneric, + isFromIntLit, # conversion *from* int literal; proven safe + isEqual + + ProcConvMismatch* = enum + pcmNoSideEffect + pcmNotGcSafe + pcmLockDifference + pcmNotIterator + pcmDifferentCallConv + proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string template `$`*(typ: PType): string = typeToString(typ) @@ -1471,6 +1494,68 @@ proc skipHiddenSubConv*(n: PNode; g: ModuleGraph; idgen: IdGenerator): PNode = else: result = n +proc getProcConvMismatch*(c: ConfigRef, f, a: PType, rel = isNone): (set[ProcConvMismatch], TTypeRelation) = + ## Returns a set of the reason of mismatch, and the relation for conversion. + result[1] = rel + if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags: + # Formal is pure, but actual is not + result[0].incl pcmNoSideEffect + result[1] = isNone + + if tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and + optThreadAnalysis in c.globalOptions: + # noSideEffect implies ``tfThread``! + result[0].incl pcmNotGcSafe + result[1] = isNone + + if f.flags * {tfIterator} != a.flags * {tfIterator}: + # One of them is an iterator so not convertible + result[0].incl pcmNotIterator + result[1] = isNone + + if f.callConv != a.callConv: + # valid to pass a 'nimcall' thingie to 'closure': + if f.callConv == ccClosure and a.callConv == ccNimCall: + case result[1] + of isInferred: result[1] = isInferredConvertible + of isBothMetaConvertible: result[1] = isBothMetaConvertible + elif result[1] != isNone: result[1] = isConvertible + else: + result[1] = isNone + result[0].incl pcmDifferentCallConv + + if f.lockLevel.ord != UnspecifiedLockLevel.ord and + a.lockLevel.ord != UnspecifiedLockLevel.ord: + # proctypeRel has more logic to catch this difference, + # so dont need to do `rel = isNone` + # but it's a pragma mismatch reason which is why it's here + result[0].incl pcmLockDifference + +proc addPragmaAndCallConvMismatch*(message: var string, formal, actual: PType, conf: ConfigRef) = + assert formal.kind == tyProc and actual.kind == tyProc + let (convMismatch, _) = getProcConvMismatch(conf, formal, actual) + var + gotPragmas = "" + expectedPragmas = "" + for reason in convMismatch: + case reason + of pcmDifferentCallConv: + message.add "\n Calling convention mismatch: got '{.$1.}', but expected '{.$2.}'." % [$actual.callConv, $formal.callConv] + of pcmNoSideEffect: + expectedPragmas.add "noSideEffect, " + of pcmNotGcSafe: + expectedPragmas.add "gcsafe, " + of pcmLockDifference: + gotPragmas.add("locks: " & $actual.lockLevel & ", ") + expectedPragmas.add("locks: " & $formal.lockLevel & ", ") + of pcmNotIterator: discard + + if expectedPragmas.len > 0: + gotPragmas.setLen(max(0, gotPragmas.len - 2)) # Remove ", " + expectedPragmas.setLen(max(0, expectedPragmas.len - 2)) # Remove ", " + message.add "\n Pragma mismatch: got '{.$1.}', but expected '{.$2.}'." % [gotPragmas, expectedPragmas] + + proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType, n: PNode) = if formal.kind != tyError and actual.kind != tyError: let actualStr = typeToString(actual) @@ -1491,6 +1576,7 @@ proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType, n: P if verbose: msg.addDeclaredLoc(conf, formal) if formal.kind == tyProc and actual.kind == tyProc: + msg.addPragmaAndCallConvMismatch(formal, actual, conf) case compatibleEffects(formal, actual) of efCompat: discard of efRaisesDiffer: @@ -1503,6 +1589,7 @@ proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType, n: P msg.add "\n.tag effect is 'any tag allowed'" of efLockLevelsDiffer: msg.add "\nlock levels differ" + if formal.kind == tyEnum and actual.kind == tyEnum: msg.add "\nmaybe use `-d:nimLegacyConvEnumEnum` for a transition period" localError(conf, info, msg) diff --git a/tests/errmsgs/tproc_mismatch.nim b/tests/errmsgs/tproc_mismatch.nim new file mode 100644 index 000000000..400c3d441 --- /dev/null +++ b/tests/errmsgs/tproc_mismatch.nim @@ -0,0 +1,74 @@ +discard """ + action: reject + cmd: '''nim check --hints:off $options $file''' + nimoutFull: true + nimout: ''' +tproc_mismatch.nim(35, 52) Error: type mismatch: got but expected 'proc (a: int, c: float){.closure, noSideEffect.}' + Calling convention mismatch: got '{.cdecl.}', but expected '{.closure.}'. +tproc_mismatch.nim(39, 6) Error: type mismatch: got +but expected one of: +proc bar(a: proc ()) + first type mismatch at position: 1 + required type for a: proc (){.closure.} + but expression 'fn1' is of type: proc (){.inline, noSideEffect, gcsafe, locks: 0.} + Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'. + +expression: bar(fn1) +tproc_mismatch.nim(43, 8) Error: type mismatch: got but expected 'proc (){.closure.}' + Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'. +tproc_mismatch.nim(48, 8) Error: type mismatch: got but expected 'proc (){.closure, noSideEffect.}' + Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'. +tproc_mismatch.nim(52, 8) Error: type mismatch: got but expected 'proc (a: float){.closure.}' +tproc_mismatch.nim(61, 9) Error: type mismatch: got but expected 'proc (a: int){.closure, gcsafe.}' + Pragma mismatch: got '{..}', but expected '{.gcsafe.}'. +tproc_mismatch.nim(69, 9) Error: type mismatch: got but expected 'proc (a: int): int{.cdecl.}' + Calling convention mismatch: got '{.nimcall.}', but expected '{.cdecl.}'. +tproc_mismatch.nim(70, 9) Error: type mismatch: got but expected 'proc (a: int): int{.nimcall.}' + Calling convention mismatch: got '{.cdecl.}', but expected '{.nimcall.}'. +tproc_mismatch.nim(74, 9) Error: type mismatch: got but expected 'proc (a: int){.closure, locks: 1.}' + Pragma mismatch: got '{.locks: 3.}', but expected '{.locks: 1.}'. +lock levels differ +''' +""" +block: # CallConv mismatch + func a(a: int, c: float) {.cdecl.} = discard + var b: proc(a: int, c: float) {.noSideEffect.} = a +block: # Parameter CallConv mismatch + proc fn1() {.inline.} = discard + proc bar(a: proc()) = discard + bar(fn1) +block: # CallConv mismatch + proc fn1() {.inline.} = discard + var fn: proc() + fn = fn1 +block: # Pragma mismatch + var a = "" + proc fn1() = a.add "b" + var fn: proc() {.noSideEffect.} + fn = fn1 +block: # Fail match not do to Pragma or CallConv + proc fn1(a: int) = discard + var fn: proc(a: float) + fn = fn1 +block: # Infered noSideEffect assign + type Foo = ref object + x0: int + var g0 = Foo(x0: 1) + proc fn1(a: int) = g0.x0 = a + var fn2: proc(a: int) + var fn3: proc(a: int) {.gcsafe.} + fn2 = fn1 + fn3 = fn1 +block: # Indrection through pragmas + {.pragma: inl1, inline.} + {.pragma: inl2, inline.} + {.pragma: p1, nimcall.} + {.pragma: p2, cdecl.} + var fn1: proc(a: int): int {.inl1, p1.} + var fn2: proc(a: int): int {.inl2, p2.} + fn2 = fn1 + fn1 = fn2 +block: # Lock levels differ + var fn1: proc(a: int){.locks: 3.} + var fn2: proc(a: int){.locks: 1.} + fn2 = fn1 From b88496ac67bea92c40cf1d0f3dc55b0fa91550a4 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 6 Jul 2021 21:09:56 +0300 Subject: [PATCH 2797/4254] fix compilation on Debian 7 (no git -C) (#18427) * fix compilation on Debian 7 (no git -C) * address review * allow specify branch for testing unmerged csources * temporarily change csources checkout parameters for testing * Update tools/deps.nim Co-authored-by: Timothee Cour * fix failure * Update config/build_config.txt * set proper git branch/hash Co-authored-by: Timothee Cour Co-authored-by: Andreas Rumpf --- build_all.bat | 2 +- ci/build_autogen.bat | 2 +- ci/funs.sh | 8 ++++++-- config/build_config.txt | 3 ++- tools/ci_generate.nim | 2 +- tools/deps.nim | 9 +++++++-- tools/niminst/makefile.nimf | 3 ++- 7 files changed, 20 insertions(+), 9 deletions(-) diff --git a/build_all.bat b/build_all.bat index 1bff761b3..c8ba05e19 100644 --- a/build_all.bat +++ b/build_all.bat @@ -10,7 +10,7 @@ SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe echo "building from csources: %nim_csources%" if not exist %nim_csourcesDir% ( - git clone -q --depth 1 %nim_csourcesUrl% %nim_csourcesDir% + git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% ) if not exist %nim_csources% ( diff --git a/ci/build_autogen.bat b/ci/build_autogen.bat index 8b1113175..0b6ca566e 100644 --- a/ci/build_autogen.bat +++ b/ci/build_autogen.bat @@ -10,7 +10,7 @@ SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe echo "building from csources: %nim_csources%" if not exist %nim_csourcesDir% ( - git clone -q --depth 1 %nim_csourcesUrl% %nim_csourcesDir% + git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% ) if not exist %nim_csources% ( diff --git a/ci/funs.sh b/ci/funs.sh index 4a8887658..e25922c8c 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -120,8 +120,12 @@ nimBuildCsourcesIfNeeded(){ else # Note: using git tags would allow fetching just what's needed, unlike git hashes, e.g. # via `git clone -q --depth 1 --branch $tag $nim_csourcesUrl`. - echo_run git clone -q --depth 1 $nim_csourcesUrl "$nim_csourcesDir" - echo_run git -C "$nim_csourcesDir" checkout $nim_csourcesHash + echo_run git clone -q --depth 1 -b $nim_csourcesBranch \ + $nim_csourcesUrl "$nim_csourcesDir" + # old `git` versions don't support -C option, using `cd` explicitly: + echo_run cd "$nim_csourcesDir" + echo_run git checkout $nim_csourcesHash + echo_run cd "$OLDPWD" # if needed we could also add: `git reset --hard $nim_csourcesHash` fi _nimBuildCsourcesIfNeeded "$@" diff --git a/config/build_config.txt b/config/build_config.txt index 2484d7a52..75dbb1da3 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -1,4 +1,5 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" nim_csourcesDir=csources_v1 nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git -nim_csourcesHash=a8a5241f9475099c823cfe1a5e0ca4022ac201ff +nim_csourcesBranch=master +nim_csourcesHash=9a7f751d23c49c75a0b6f63a234c575dc0df7231 diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index 52b84f0d8..ecf0023d3 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -61,7 +61,7 @@ SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe echo "building from csources: %nim_csources%" if not exist %nim_csourcesDir% ( - git clone -q --depth 1 %nim_csourcesUrl% %nim_csourcesDir% + git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% ) if not exist %nim_csources% ( diff --git a/tools/deps.nim b/tools/deps.nim index 8ed95b59a..95b2916a1 100644 --- a/tools/deps.nim +++ b/tools/deps.nim @@ -28,8 +28,13 @@ proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, # from failing execRetry fmt"git clone -q {url} {destDir2}" if isGitRepo(destDir): - execRetry fmt"git -C {destDir2} fetch -q" - exec fmt"git -C {destDir2} checkout -q {commit}" + let oldDir = getCurrentDir() + setCurrentDir(destDir2) + try: + execRetry "git fetch -q" + exec fmt"git checkout -q {commit}" + finally: + setCurrentDir(oldDir) elif allowBundled: discard "this dependency was bundled with Nim, don't do anything" else: diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index aff0c5da0..8c40cf50f 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -25,7 +25,8 @@ endif ifeq ($(uos),linux) myos = linux - LDFLAGS += -ldl -lm + # add -lrt to avoid "undefined reference to `clock_gettime'" with glibc<2.17 + LDFLAGS += -ldl -lm -lrt endif ifeq ($(uos),dragonfly) myos = freebsd From b72ecaf639ca7b2edf5a762cfea3a11f7cc5da9a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 6 Jul 2021 21:00:59 -0700 Subject: [PATCH 2798/4254] fix shebangs #! /xxx => #!/xxx (#18444) --- build_all.sh | 2 +- lib/pure/unidecode/gen.py | 2 +- tools/ci_generate.nim | 2 +- tools/niminst/buildsh.nimf | 2 +- tools/niminst/deinstall.nimf | 2 +- tools/niminst/install.nimf | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build_all.sh b/build_all.sh index 37374aa7c..fb3d15d45 100755 --- a/build_all.sh +++ b/build_all.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh # DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` # build development version of the compiler; can be rerun safely. diff --git a/lib/pure/unidecode/gen.py b/lib/pure/unidecode/gen.py index 0b180a381..2fb69f7b2 100644 --- a/lib/pure/unidecode/gen.py +++ b/lib/pure/unidecode/gen.py @@ -1,4 +1,4 @@ -#! usr/bin/env python3 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Generates the unidecode.dat module diff --git a/tools/ci_generate.nim b/tools/ci_generate.nim index ecf0023d3..a8a80e026 100644 --- a/tools/ci_generate.nim +++ b/tools/ci_generate.nim @@ -82,7 +82,7 @@ if not exist %nim_csources% ( proc genPosixScript(): string = result = fmt""" -#! /bin/sh +#!/bin/sh # {doNotEdit} # build development version of the compiler; can be rerun safely. diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index e7afd402e..f74413c09 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -1,6 +1,6 @@ #? stdtmpl(subsChar='?') | standard #proc generateBuildShellScript(c: ConfigData): string = -# result = "#! /bin/sh\n# Generated from niminst\n" & +# result = "#!/bin/sh\n# Generated from niminst\n" & # "# Template is in tools/niminst/buildsh.nimf\n" & # "# To regenerate run ``niminst csource`` or ``koch csource``\n" diff --git a/tools/niminst/deinstall.nimf b/tools/niminst/deinstall.nimf index 8b4477369..0dcfda75e 100644 --- a/tools/niminst/deinstall.nimf +++ b/tools/niminst/deinstall.nimf @@ -1,6 +1,6 @@ #? stdtmpl(subsChar='?') | standard #proc generateDeinstallScript(c: ConfigData): string = -# result = "#! /bin/sh\n# Generated by niminst\n" +# result = "#!/bin/sh\n# Generated by niminst\n" # var proj = c.name.toLowerAscii if [ $# -eq 1 ] ; then diff --git a/tools/niminst/install.nimf b/tools/niminst/install.nimf index a78914ecd..c2fc96e94 100644 --- a/tools/niminst/install.nimf +++ b/tools/niminst/install.nimf @@ -1,6 +1,6 @@ #? stdtmpl(subsChar = '?') | standard #proc generateInstallScript(c: ConfigData): string = -# result = "#! /bin/sh\n# Generated by niminst\n" +# result = "#!/bin/sh\n# Generated by niminst\n" # var proj = c.name.toLowerAscii set -e From d1447fe25d40e35d4746d570701d23333ff480a0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 6 Jul 2021 21:04:36 -0700 Subject: [PATCH 2799/4254] major improvements to `std/wrapnils`: optimal codegen, case objects, lvalue semantics (#18435) * wrapnils now generates optimal code; also handles case objects * changelog * unsafeAddr => addr --- changelog.md | 4 + lib/std/wrapnils.nim | 185 +++++++++++++++++++-------- tests/stdlib/twrapnils.nim | 249 ++++++++++++++++++++++++++++--------- 3 files changed, 329 insertions(+), 109 deletions(-) diff --git a/changelog.md b/changelog.md index 028743bab..1deb97161 100644 --- a/changelog.md +++ b/changelog.md @@ -279,6 +279,10 @@ issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages) for modules importing `std/wrapnils`. Added `??.` macro which returns an `Option`. + `std/wrapnils` can now be used to protect against `FieldDefect` errors in + case objects, generates optimal code (no overhead compared to manual + if-else branches), and preserves lvalue semantics which allows modifying + an expression. - Added `math.frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead. diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim index ed0a79d79..facba85fa 100644 --- a/lib/std/wrapnils.nim +++ b/lib/std/wrapnils.nim @@ -1,9 +1,20 @@ -## This module allows chains of field-access and indexing where the LHS can be nil. -## This simplifies code by reducing need for if-else branches around intermediate values -## that may be nil. +## This module allows evaluating expressions safely against the following conditions: +## * nil dereferences +## * field accesses with incorrect discriminant in case objects +## +## `default(T)` is returned in those cases when evaluating an expression of type `T`. +## This simplifies code by reducing need for if-else branches. ## ## Note: experimental module, unstable API. +#[ +TODO: +consider handling indexing operations, eg: +doAssert ?.default(seq[int])[3] == default(int) +]# + +import macros + runnableExamples: type Foo = ref object x1: string @@ -24,8 +35,124 @@ runnableExamples: assert (?.f2.x2.x2).x3 == nil # this terminates ?. early +runnableExamples: + # ?. also allows case object + type B = object + b0: int + case cond: bool + of false: discard + of true: + b1: float + + var b = B(cond: false, b0: 3) + doAssertRaises(FieldDefect): discard b.b1 # wrong discriminant + doAssert ?.b.b1 == 0.0 # safe + b = B(cond: true, b1: 4.5) + doAssert ?.b.b1 == 4.5 + + # lvalue semantics are preserved: + if (let p = ?.b.b1.addr; p != nil): p[] = 4.7 + doAssert b.b1 == 4.7 + +proc finalize(n: NimNode, lhs: NimNode, level: int): NimNode = + if level == 0: + result = quote: `lhs` = `n` + else: + result = quote: (let `lhs` = `n`) + +proc process(n: NimNode, lhs: NimNode, level: int): NimNode = + var n = n.copyNimTree + var it = n + let addr2 = bindSym"addr" + var old: tuple[n: NimNode, index: int] + while true: + if it.len == 0: + result = finalize(n, lhs, level) + break + elif it.kind == nnkCheckedFieldExpr: + let dot = it[0] + let obj = dot[0] + let objRef = quote do: `addr2`(`obj`) + # avoids a copy and preserves lvalue semantics, see tests + let check = it[1] + let okSet = check[1] + let kind1 = check[2] + let tmp = genSym(nskLet, "tmpCase") + let body = process(objRef, tmp, level + 1) + let tmp3 = nnkDerefExpr.newTree(tmp) + it[0][0] = tmp3 + let dot2 = nnkDotExpr.newTree(@[tmp, dot[1]]) + if old.n != nil: old.n[old.index] = dot2 + else: n = dot2 + let assgn = finalize(n, lhs, level) + result = quote do: + `body` + if `tmp3`.`kind1` notin `okSet`: break + `assgn` + break + elif it.kind in {nnkHiddenDeref, nnkDerefExpr}: + let tmp = genSym(nskLet, "tmp") + let body = process(it[0], tmp, level + 1) + it[0] = tmp + let assgn = finalize(n, lhs, level) + result = quote do: + `body` + if `tmp` == nil: break + `assgn` + break + elif it.kind == nnkCall: # consider extending to `nnkCallKinds` + # `copyNimTree` needed to avoid `typ = nil` issues + old = (it, 1) + it = it[1].copyNimTree + else: + old = (it, 0) + it = it[0] + +macro `?.`*(a: typed): auto = + ## Transforms `a` into an expression that can be safely evaluated even in + ## presence of intermediate nil pointers/references, in which case a default + ## value is produced. + let lhs = genSym(nskVar, "lhs") + let body = process(a, lhs, 0) + result = quote do: + var `lhs`: type(`a`) + block: + `body` + `lhs` + +# the code below is not needed for `?.` from options import Option, isSome, get, option, unsafeGet, UnpackDefect +macro `??.`*(a: typed): Option = + ## Same as `?.` but returns an `Option`. + runnableExamples: + import std/options + type Foo = ref object + x1: ref int + x2: int + # `?.` can't distinguish between a valid vs invalid default value, but `??.` can: + var f1 = Foo(x1: int.new, x2: 2) + doAssert (??.f1.x1[]).get == 0 # not enough to tell when the chain was valid. + doAssert (??.f1.x1[]).isSome # a nil didn't occur in the chain + doAssert (??.f1.x2).get == 2 + + var f2: Foo + doAssert not (??.f2.x1[]).isSome # f2 was nil + + doAssertRaises(UnpackDefect): discard (??.f2.x1[]).get + doAssert ?.f2.x1[] == 0 # in contrast, this returns default(int) + + let lhs = genSym(nskVar, "lhs") + let lhs2 = genSym(nskVar, "lhs") + let body = process(a, lhs2, 0) + result = quote do: + var `lhs`: Option[type(`a`)] + block: + var `lhs2`: type(`a`) + `body` + `lhs` = option(`lhs2`) + `lhs` + template fakeDot*(a: Option, b): untyped = ## See top-level example. let a1 = a # to avoid double evaluations @@ -58,51 +185,7 @@ func `[]`*[U](a: Option[U]): auto {.inline.} = if a2 != nil: result = option(a2[]) -import macros - -func replace(n: NimNode): NimNode = - if n.kind == nnkDotExpr: - result = newCall(bindSym"fakeDot", replace(n[0]), n[1]) - elif n.kind == nnkPar: - doAssert n.len == 1 - result = newCall(bindSym"option", n[0]) - elif n.kind in {nnkCall, nnkObjConstr}: - result = newCall(bindSym"option", n) - elif n.len == 0: - result = newCall(bindSym"option", n) - else: - n[0] = replace(n[0]) - result = n - -proc safeGet[T](a: Option[T]): T {.inline.} = - get(a, default(T)) - -macro `?.`*(a: untyped): auto = - ## Transforms `a` into an expression that can be safely evaluated even in - ## presence of intermediate nil pointers/references, in which case a default - ## value is produced. - result = replace(a) - result = quote do: - # `result`.val # TODO: expose a way to do this directly in std/options, e.g.: `getAsIs` - safeGet(`result`) - -macro `??.`*(a: untyped): Option = - ## Same as `?.` but returns an `Option`. - runnableExamples: - import std/options - type Foo = ref object - x1: ref int - x2: int - # `?.` can't distinguish between a valid vs invalid default value, but `??.` can: - var f1 = Foo(x1: int.new, x2: 2) - doAssert (??.f1.x1[]).get == 0 # not enough to tell when the chain was valid. - doAssert (??.f1.x1[]).isSome # a nil didn't occur in the chain - doAssert (??.f1.x2).get == 2 - - var f2: Foo - doAssert not (??.f2.x1[]).isSome # f2 was nil - from std/options import UnpackDefect - doAssertRaises(UnpackDefect): discard (??.f2.x1[]).get - doAssert ?.f2.x1[] == 0 # in contrast, this returns default(int) - - result = replace(a) +when false: + # xxx: expose a way to do this directly in std/options, e.g.: `getAsIs` + proc safeGet[T](a: Option[T]): T {.inline.} = + get(a, default(T)) diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index 956204355..1a66f4cd9 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -7,80 +7,213 @@ proc checkNotZero(x: float): float = proc main() = var witness = 0 - type Bar = object - b1: int - b2: ptr string + block: + type Bar = object + b1: int + b2: ptr string - type Foo = ref object - x1: float - x2: Foo - x3: string - x4: Bar - x5: seq[int] - x6: ptr Bar - x7: array[2, string] - x8: seq[int] - x9: ref Bar + type Foo = ref object + x1: float + x2: Foo + x3: string + x4: Bar + x5: seq[int] + x6: ptr Bar + x7: array[2, string] + x8: seq[int] + x9: ref Bar - type Gook = ref object - foo: Foo + type Gook = ref object + foo: Foo - proc fun(a: Bar): auto = a.b2 + proc fun(a: Bar): auto = a.b2 - var a: Foo + var a: Foo - var x6: ptr Bar - when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568 - else: - x6 = create(Bar) - x6.b1 = 42 - var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6) - var a3 = Foo(x1: 1.2, x3: "abc") - a3.x2 = a3 + var x6: ptr Bar + when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568 + else: + x6 = create(Bar) + x6.b1 = 42 + var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6) + var a3 = Foo(x1: 1.2, x3: "abc") + a3.x2 = a3 - var gook = Gook(foo: a) + var gook = Gook(foo: a) - proc initFoo(x1: float): auto = - witness.inc - result = Foo(x1: x1) + proc initFoo(x1: float): auto = + witness.inc + result = Foo(x1: x1) - doAssert ?.a.x2.x2.x1 == 0.0 - doAssert ?.a3.x2.x2.x1 == 1.2 - doAssert ?.a3.x2.x2.x3[1] == 'b' + doAssert ?.a.x2.x2.x1 == 0.0 + doAssert ?.a3.x2.x2.x1 == 1.2 + doAssert ?.a3.x2.x2.x3[1] == 'b' - doAssert ?.a3.x2.x2.x5.len == 0 - doAssert a3.x2.x2.x3.len == 3 + doAssert ?.a3.x2.x2.x5.len == 0 + doAssert a3.x2.x2.x3.len == 3 - doAssert ?.a.x2.x2.x3[1] == default(char) - # here we only apply wrapnil around gook.foo, not gook (and assume gook is not nil) - doAssert ?.(gook.foo).x2.x2.x1 == 0.0 + doAssert ?.a.x2.x2.x3[1] == default(char) + # here we only apply wrapnil around gook.foo, not gook (and assume gook is not nil) + doAssert ?.(gook.foo).x2.x2.x1 == 0.0 - when nimvm: discard - else: - doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar + when nimvm: discard + else: + doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar - doAssert ?.a2.x1.checkNotZero == 1.0 - doAssert a == nil - # shows that checkNotZero won't be called if a nil is found earlier in chain - doAssert ?.a.x1.checkNotZero == 0.0 + doAssert ?.a2.x1.checkNotZero == 1.0 + doAssert a == nil + # shows that checkNotZero won't be called if a nil is found earlier in chain + doAssert ?.a.x1.checkNotZero == 0.0 - when nimvm: discard - else: - # checks that a chain without nil but with an empty seq still raises - doAssertRaises(IndexDefect): discard ?.a2.x8[3] + when nimvm: discard + else: + # checks that a chain without nil but with an empty seq still raises + doAssertRaises(IndexDefect): discard ?.a2.x8[3] - # make sure no double evaluation bug - doAssert witness == 0 - doAssert ?.initFoo(1.3).x1 == 1.3 - doAssert witness == 1 + # make sure no double evaluation bug + doAssert witness == 0 + doAssert ?.initFoo(1.3).x1 == 1.3 + doAssert witness == 1 - # here, it's used twice, to deref `ref Bar` and then `ptr string` - doAssert ?.a.x9[].fun[] == "" + # here, it's used twice, to deref `ref Bar` and then `ptr string` + doAssert ?.a.x9[].fun[] == "" - block: # `??.` - doAssert (??.a3.x2.x2.x3.len).get == 3 - doAssert (??.a2.x4).isSome - doAssert not (??.a.x4).isSome + block: # `??.` + doAssert (??.a3.x2.x2.x3.len).get == 3 + doAssert (??.a2.x4).isSome + doAssert not (??.a.x4).isSome + + block: + type + A = object + b: B + B = object + c: C + C = object + d: D + D = ref object + e: E + e2: array[2, E] + e3: seq[E] + d3: D + i4: int + E = object + f: int + d2: D + proc identity[T](a: T): T = a + proc identity2[T](a: T, ignore: int): T = a + var a: A + doAssert ?.a.b.c.d.e.f == 0 + doAssert ?.a.b.c.d.e.d2.d3[].d3.e.d2.e.f == 0 + doAssert ?.a.b.c.d.d3[].e.f == 0 + doAssert ?.a.b.c.d.e2[0].d2.e3[0].f == 0 + doAssert ?.a == A.default + doAssert ?.a.b.c.d.e == E.default + doAssert ?.a.b.c.d.e.d2 == nil + + doAssert ?.a.identity.b.c.identity2(12).d.d3.e.f == 0 + doAssert ?.a.b.c.d.d3.e2[0].f == 0 + a.b.c.d = D() + a.b.c.d.d3 = a.b.c.d + a.b.c.d.e2[0].f = 5 + doAssert ?.a.b.c.d.d3.e2[0].f == 5 + + var d: D = nil + doAssert ?.d.identity.i4 == 0 + doAssert ?.d.i4.identity == 0 + + block: # case objects + type + Kind = enum k0, k1, k2 + V = object + case kind: Kind + of k0: + x0: int + of k1: + x1: int + of k2: + x2: int + A = object + v0: V + + block: + var a = V(kind: k0, x0: 3) + doAssert ?.a.x0 == 3 + doAssert ?.a.x1 == 0 + a = V(kind: k1, x1: 5) + doAssert ?.a.x0 == 0 + doAssert ?.a.x1 == 5 + + block: + var a = A(v0: V(kind: k0, x0: 10)) + doAssert ?.a.v0.x0 == 10 + doAssert ?.a.v0.x1 == 0 + a.v0 = V(kind: k2, x2: 8) + doAssert ?.a.v0.x0 == 0 + doAssert ?.a.v0.x1 == 0 + doAssert ?.a.v0.x2 == 8 + + block: # `nnkCall` + type + A = object + a0: int + d: D + D = ref object + i4: int + + proc identity[T](a: T): T = a + var d: D = nil + doAssert ?.d.i4.identity == 0 + doAssert ?.identity(?.d.i4) == 0 + doAssert ?.identity(d.i4) == 0 + doAssert ?.identity(d) == nil + doAssert ?.identity(d[]) == default(typeof(d[])) + doAssert ?.identity(d[]).i4 == 0 + var a: A + doAssert ?.identity(a) == default(A) + doAssert ?.identity(a.a0) == 0 + doAssert ?.identity(a.d) == nil + doAssert ?.identity(a.d.i4) == 0 + + block: # lvalue semantic propagation + type + A = ref object + a0: A + a1: seq[A] + a2: int + + B = object + b0: int + case cond: bool + of false: discard + of true: + b1: float + + block: + var a: A + doAssert ?.a.a0.a1[0].a2.addr == nil + a = A(a2: 3) + doAssert ?.a.a0.a1[0].a2.addr == nil + a.a0 = a + a.a1 = @[a] + let p = ?.a.a0.a1[0].a2.addr + doAssert p != nil + p[] = 5 + doAssert a.a2 == 5 + + block: + var b = B(cond: false, b0: 3) + let p = ?.b.b1.addr + doAssert p == nil + b = B(cond: true, b1: 4.5) + let p2 = ?.b.b1.addr + doAssert p2 != nil + p2[] = 4.6 + doAssert b.b1 == 4.6 + # useful pattern, impossible with Options + if (let p3 = ?.b.b1.addr; p3 != nil): + p3[] = 4.7 + doAssert b.b1 == 4.7 main() static: main() From 3eb3e6b9a38aed1f26014bd5dece216b0c625b1a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 7 Jul 2021 09:39:01 +0200 Subject: [PATCH 2800/4254] ORC: use =destroy instead of =dispose (#18440) * ORC refactoring in preparation for further changes (=dispose must die) * ORC: embrace =destroy, avoid =dispose * ORC: no need for =dispose * closes #18421 --- compiler/ast.nim | 3 +- compiler/ccgtypes.nim | 5 +- compiler/liftdestructors.nim | 49 ++--------- compiler/semstmts.nim | 2 - doc/manual.rst | 2 +- lib/system.nim | 1 - lib/system/cellseqs_v2.nim | 26 +++--- lib/system/cyclebreaker.nim | 3 +- lib/system/orc.nim | 40 +++++---- tests/arc/thamming_orc.nim | 155 +++++++++++++++++++++++++++++++++++ 10 files changed, 205 insertions(+), 81 deletions(-) create mode 100644 tests/arc/thamming_orc.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 2a2a84e76..26050426a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -911,7 +911,6 @@ type attachedAsgn, attachedSink, attachedTrace, - attachedDispose, attachedDeepCopy TType* {.acyclic.} = object of TIdObj # \ @@ -1408,7 +1407,7 @@ const MaxLockLevel* = 1000'i16 UnknownLockLevel* = TLockLevel(1001'i16) AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=destroy", "=copy", "=sink", "=trace", "=dispose", "=deepcopy"] + "=destroy", "=copy", "=sink", "=trace", "=deepcopy"] proc `$`*(x: TLockLevel): string = if x.ord == UnspecifiedLockLevel.ord: result = "" diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6e5ffeaa4..67e701804 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1328,14 +1328,13 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) let destroyImpl = genHook(m, t, info, attachedDestructor) let traceImpl = genHook(m, t, info, attachedTrace) - let disposeImpl = genHook(m, t, info, attachedDispose) var flags = 0 if not canFormAcycle(t): flags = flags or 1 - addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6; $1.flags = $7;", [ + addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.flags = $6;", [ name, destroyImpl, getTypeDesc(m, t), typeName, - traceImpl, disposeImpl, rope(flags)]) + traceImpl, rope(flags)]) if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 43f87e179..1824557e6 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -421,11 +421,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = result = considerAsgnOrSink(c, t, body, x, y, op) if op != nil: setAttachedOp(c.g, c.idgen.module, t, c.kind, op) - of attachedDispose: - var op = getAttachedOp(c.g, t, c.kind) - result = considerAsgnOrSink(c, t, body, x, nil, op) - if op != nil: - setAttachedOp(c.g, c.idgen.module, t, c.kind, op) of attachedDeepCopy: let op = getAttachedOp(c.g, t, attachedDeepCopy) if op != nil: @@ -516,9 +511,6 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if canFormAcycle(t.elemType): # follow all elements: forallElements(c, t, body, x, y) - of attachedDispose: - forallElements(c, t, body, x, y) - body.add genBuiltin(c, mDestroy, "destroy", x) proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = createTypeBoundOps(c.g, c.c, t, body.info, c.idgen) @@ -556,11 +548,6 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if op == nil: return # protect from recursion body.add newHookCall(c, op, x, y) - of attachedDispose: - let op = getAttachedOp(c.g, t, c.kind) - if op == nil: - return # protect from recursion - body.add newHookCall(c, op, x, nil) proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -572,7 +559,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) body.add moveCall - of attachedDestructor, attachedDispose: + of attachedDestructor: body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" @@ -667,16 +654,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # If the ref is polymorphic we have to account for this body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y) #echo "can follow ", elemType, " static ", isFinal(elemType) - of attachedDispose: - # this is crucial! dispose is like =destroy but we don't follow refs - # as that is dealt within the cycle collector. - if not isCyclic: - body.add genIf(c, cond, actions) - when false: - let cond = copyTree(x) - cond.typ = getSysType(c.g, x.info, tyBool) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) - body.add genIf(c, cond, actions) proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ## Closures are really like refs except they always use a virtual destructor @@ -725,14 +702,6 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y) - of attachedDispose: - # this is crucial! dispose is like =destroy but we don't follow refs - # as that is dealt within the cycle collector. - when false: - let cond = copyTree(xenv) - cond.typ = getSysType(c.g, xenv.info, tyBool) - actions.add callCodegenProc(c.g, "nimRawDispose", c.info, xenv) - body.add genIf(c, cond, actions) proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -756,7 +725,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = else: body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace, attachedDispose: discard + of attachedTrace: discard proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) @@ -781,7 +750,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDestructor: body.add genIf(c, x, actions) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace, attachedDispose: discard + of attachedTrace: discard proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind == attachedDeepCopy: @@ -815,7 +784,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = else: body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace, attachedDispose: discard + of attachedTrace: discard proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) @@ -830,7 +799,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDestructor: body.add genIf(c, xx, actions) of attachedDeepCopy: assert(false, "cannot happen") - of attachedTrace, attachedDispose: discard + of attachedTrace: discard proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind @@ -946,7 +915,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp result.typ = newProcType(info, nextTypeId(idgen), owner) result.typ.addParam dest - if kind notin {attachedDestructor, attachedDispose}: + if kind != attachedDestructor: result.typ.addParam src if kind == attachedAsgn and g.config.selectedGC == gcOrc and @@ -980,7 +949,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; let dest = result.typ.n[1].sym let d = newDeref(newSymNode(dest)) - let src = if kind in {attachedDestructor, attachedDispose}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) + let src = if kind == attachedDestructor: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) else: newSymNode(result.typ.n[2].sym) # register this operation already: @@ -1098,13 +1067,13 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf # we do not generate '=trace' nor '=dispose' procs if we # have the cycle detection disabled, saves code size. - let lastAttached = if g.config.selectedGC == gcOrc: attachedDispose + let lastAttached = if g.config.selectedGC == gcOrc: attachedTrace else: attachedSink # bug #15122: We need to produce all prototypes before entering the # mind boggling recursion. Hacks like these imply we should rewrite # this module. - var generics: array[attachedDestructor..attachedDispose, bool] + var generics: array[attachedDestructor..attachedTrace, bool] for k in attachedDestructor..lastAttached: generics[k] = getAttachedOp(g, canon, k) != nil if not generics[k]: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2907d5172..c3402aee3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1753,8 +1753,6 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = "signature for '" & s.name.s & "' must be proc[T: object](x: var T; y: T)") of "=trace": bindTypeHook(c, s, n, attachedTrace) - of "=dispose": - bindTypeHook(c, s, n, attachedDispose) else: if sfOverriden in s.flags: localError(c.config, n.info, errGenerated, diff --git a/doc/manual.rst b/doc/manual.rst index a99c4b5af..9ddf02009 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3841,7 +3841,7 @@ the operator is in scope (including if it is private). doAssert witness == 3 Type bound operators currently include: -`=destroy`, `=copy`, `=sink`, `=trace`, `=dispose`, `=deepcopy` +`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy` (some of which are still implementation defined and not yet documented). For more details on some of those procs, see diff --git a/lib/system.nim b/lib/system.nim index a4608997a..090ab309e 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1779,7 +1779,6 @@ when not defined(js) and defined(nimV2): align: int name: cstring traceImpl: pointer - disposeImpl: pointer typeInfoV1: pointer # for backwards compat, usually nil flags: int PNimTypeV2 = ptr TNimTypeV2 diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim index 59cf67dcd..27be48d78 100644 --- a/lib/system/cellseqs_v2.nim +++ b/lib/system/cellseqs_v2.nim @@ -10,20 +10,20 @@ # Cell seqs for cyclebreaker and cyclicrefs_v2. type - CellTuple = (PT, PNimTypeV2) - CellArray = ptr UncheckedArray[CellTuple] - CellSeq = object + CellTuple[T] = (T, PNimTypeV2) + CellArray[T] = ptr UncheckedArray[CellTuple[T]] + CellSeq[T] = object len, cap: int - d: CellArray + d: CellArray[T] -proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} = +proc add[T](s: var CellSeq[T], c: T; t: PNimTypeV2) {.inline.} = if s.len >= s.cap: s.cap = s.cap * 3 div 2 when compileOption("threads"): - var d = cast[CellArray](allocShared(uint(s.cap * sizeof(CellTuple)))) + var d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T])))) else: - var d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) - copyMem(d, s.d, s.len * sizeof(CellTuple)) + var d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T]))) + copyMem(d, s.d, s.len * sizeof(CellTuple[T])) when compileOption("threads"): deallocShared(s.d) else: @@ -33,15 +33,15 @@ proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} = s.d[s.len] = (c, t) inc(s.len) -proc init(s: var CellSeq, cap: int = 1024) = +proc init[T](s: var CellSeq[T], cap: int = 1024) = s.len = 0 s.cap = cap when compileOption("threads"): - s.d = cast[CellArray](allocShared(uint(s.cap * sizeof(CellTuple)))) + s.d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T])))) else: - s.d = cast[CellArray](alloc(s.cap * sizeof(CellTuple))) + s.d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T]))) -proc deinit(s: var CellSeq) = +proc deinit[T](s: var CellSeq[T]) = if s.d != nil: when compileOption("threads"): deallocShared(s.d) @@ -51,6 +51,6 @@ proc deinit(s: var CellSeq) = s.len = 0 s.cap = 0 -proc pop(s: var CellSeq): (PT, PNimTypeV2) = +proc pop[T](s: var CellSeq[T]): (T, PNimTypeV2) = result = s.d[s.len-1] dec s.len diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim index a3159f95c..6ec0f01f7 100644 --- a/lib/system/cyclebreaker.nim +++ b/lib/system/cyclebreaker.nim @@ -53,7 +53,6 @@ depth-first traversal suffices. ]# -type PT = ptr pointer include cellseqs_v2 const @@ -78,7 +77,7 @@ proc nimMarkCyclic(p: pointer) {.compilerRtl, inl.} = discard type GcEnv = object - traceStack: CellSeq + traceStack: CellSeq[ptr pointer] proc trace(p: pointer; desc: PNimTypeV2; j: var GcEnv) {.inline.} = when false: diff --git a/lib/system/orc.nim b/lib/system/orc.nim index df81afcf1..6273e1a21 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -14,7 +14,6 @@ # R.D. Lins / Information Processing Letters 109 (2008) 71–78 # -type PT = Cell include cellseqs_v2 const @@ -68,10 +67,10 @@ const type GcEnv = object - traceStack: CellSeq + traceStack: CellSeq[ptr pointer] when useJumpStack: - jumpStack: CellSeq # Lins' jump stack in order to speed up traversals - toFree: CellSeq + jumpStack: CellSeq[ptr pointer] # Lins' jump stack in order to speed up traversals + toFree: CellSeq[Cell] freed, touched, edges, rcSum: int keepThreshold: bool @@ -92,13 +91,13 @@ proc free(s: Cell; desc: PNimTypeV2) {.inline.} = when logOrc: writeCell("free", s, desc) - if desc.disposeImpl != nil: - cast[DisposeProc](desc.disposeImpl)(p) + if desc.destructor != nil: + cast[DestructorProc](desc.destructor)(p) when false: cstderr.rawWrite desc.name cstderr.rawWrite " " - if desc.disposeImpl == nil: + if desc.destructor == nil: cstderr.rawWrite "lacks dispose" if desc.traceImpl != nil: cstderr.rawWrite ", but has trace\n" @@ -125,16 +124,16 @@ proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inli orcAssert strstr(desc.name, "TType") == nil, "following a TType but it's acyclic!" var j = cast[ptr GcEnv](env) - j.traceStack.add(head p[], desc) + j.traceStack.add(p, desc) proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inline.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) - j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[]) + j.traceStack.add(p, cast[ptr PNimTypeV2](p[])[]) var - roots {.threadvar.}: CellSeq + roots {.threadvar.}: CellSeq[Cell] proc unregisterCycle(s: Cell) = # swap with the last element. O(1) @@ -162,7 +161,8 @@ proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) = trace(s, desc, j) when logOrc: writeCell("root still alive", s, desc) while j.traceStack.len > until: - let (t, desc) = j.traceStack.pop() + let (entry, desc) = j.traceStack.pop() + let t = head entry[] inc t.rc, rcIncrement if t.color != colBlack: t.setColor colBlack @@ -187,7 +187,8 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty") trace(s, desc, j) while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() + let (entry, desc) = j.traceStack.pop() + let t = head entry[] dec t.rc, rcIncrement inc j.edges when useJumpStack: @@ -195,7 +196,7 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) = t.rc = t.rc or jumpStackFlag when traceCollector: cprintf("[Now in jumpstack] %p %ld color %ld in jumpstack %ld\n", t, t.rc shr rcShift, t.color, t.rc and jumpStackFlag) - j.jumpStack.add(t, desc) + j.jumpStack.add(entry, desc) if t.color != colGray: t.setColor colGray inc j.touched @@ -225,7 +226,8 @@ proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = # that are still alive; we also need to mark what they # refer to as alive: while j.jumpStack.len > 0: - let (t, desc) = j.jumpStack.pop + let (entry, desc) = j.jumpStack.pop + let t = head entry[] # not in jump stack anymore! t.rc = t.rc and not jumpStackFlag if t.color == colGray and (t.rc shr rcShift) >= 0: @@ -239,7 +241,8 @@ proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = s.setColor(colWhite) trace(s, desc, j) while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() + let (entry, desc) = j.traceStack.pop() + let t = head entry[] if t.color == colGray: if (t.rc shr rcShift) >= 0: scanBlack(t, desc, j) @@ -249,7 +252,8 @@ proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) = # that are still alive; we also need to mark what they # refer to as alive: while j.jumpStack.len > 0: - let (t, desc) = j.jumpStack.pop + let (entry, desc) = j.jumpStack.pop + let t = head entry[] # not in jump stack anymore! t.rc = t.rc and not jumpStackFlag if t.color == colGray and (t.rc shr rcShift) >= 0: @@ -285,7 +289,9 @@ proc collectColor(s: Cell; desc: PNimTypeV2; col: int; j: var GcEnv) = j.toFree.add(s, desc) trace(s, desc, j) while j.traceStack.len > 0: - let (t, desc) = j.traceStack.pop() + let (entry, desc) = j.traceStack.pop() + let t = head entry[] + entry[] = nil # ensure that the destructor does touch moribund objects! if t.color == col and t.rootIdx == 0: j.toFree.add(t, desc) t.setColor(colBlack) diff --git a/tests/arc/thamming_orc.nim b/tests/arc/thamming_orc.nim new file mode 100644 index 000000000..463f7117e --- /dev/null +++ b/tests/arc/thamming_orc.nim @@ -0,0 +1,155 @@ +discard """ + output: '''(allocCount: 1114, deallocCount: 1112) +created 439 destroyed 402''' + cmd: "nim c --gc:orc -d:nimAllocStats $file" +""" + +# bug #18421 + +# test Nim Hamming Number Lazy List algo with reference counts and not... +# compile with "-d:release -d:danger" and test with various +# memory managment GC's, allocators, threading, etc. +# it should be guaranteed to work with zero memory leaks with `--gc:orc`... + +# compile with `-d:trace20` to trace creation and destruction of first 20 values. + +from math import log2 + +# implement our own basic BigInt so the bigints library isn't necessary... +type + BigInt = object + digits: seq[uint32] +let zeroBigInt = BigInt(digits: @[ 0'u32 ]) +let oneBigInt = BigInt(digits: @[ 1'u32 ]) + +proc shladd(bi: var BigInt; n: int; a: BigInt) = + # assume that both `bi` and `a` are sized correctly with + # msuint32 for both not containing a zero + let alen = a.digits.len + let mx = max(bi.digits.len, a.digits.len) + for i in bi.digits.len ..< mx: bi.digits.add 0'u32 + var cry = 0'u64 + for i in 0 ..< alen: + cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64 + bi.digits[i] = cry.uint32; cry = cry shr 32 + for i in alen ..< mx: + cry += bi.digits[i].uint64 shl n + bi.digits[i] = cry.uint32; cry = cry shr 32 + if cry > 0'u64: + bi.digits.add cry.uint32 + +proc `$`(x: BigInt): string = + if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32): + return "0" + result = ""; var n = x; var msd = n.digits.high + while msd >= 0: + if n.digits[msd] == 0'u32: msd.dec; continue + var brw = 0.uint64 + for i in countdown(msd, 0): + let dvdnd = n.digits[i].uint64 + (brw shl 32) + let q = dvdnd div 10'u64; brw = dvdnd - q * 10'u64 + n.digits[i] = q.uint32 + result &= $brw + for i in 0 .. result.high shr 1: # reverse result string in place + let tmp = result[^(i + 1)] + result[^(i + 1)] = result[i] + result[i] = tmp + +type TriVal = (uint32, uint32, uint32) +type LogRep = (float64, TriVal) +type LogRepf = proc(x: LogRep): LogRep +const one: LogRep = (0.0'f64, (0'u32, 0'u32, 0'u32)) +proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0] + +proc convertTriVal2BigInt(tpl: TriVal): BigInt = + result = oneBigInt + let (x2, x3, x5) = tpl + for _ in 1 .. x2: result.shladd 1, zeroBigInt + for _ in 1 .. x3: result.shladd 1, result + for _ in 1 .. x5: result.shladd 2, result + +const lb2 = 1.0'f64 +const lb3 = 3.0'f64.log2 +const lb5 = 5.0'f64.log2 + +proc mul2(me: LogRep): LogRep = + let (lr, tpl) = me; let (x2, x3, x5) = tpl + (lr + lb2, (x2 + 1, x3, x5)) + +proc mul3(me: LogRep): LogRep = + let (lr, tpl) = me; let (x2, x3, x5) = tpl + (lr + lb3, (x2, x3 + 1, x5)) + +proc mul5(me: LogRep): LogRep = + let (lr, tpl) = me; let (x2, x3, x5) = tpl + (lr + lb5, (x2, x3, x5 + 1)) + +type + LazyListObj = object + hd: LogRep + tlf: proc(): LazyList {.closure.} + tl: LazyList + LazyList = ref LazyListObj + +var destroyed = 0 + +proc `=destroy`(ll: var LazyListObj) = + if ll.tlf == nil and ll.tl == nil: return + destroyed += 1 + + when defined(trace20): + echo "destroying: ", (destroyed, ll.hd[1].convertTriVal2BigInt) + if ll.tlf != nil: ll.tlf.`=destroy` + if ll.tl != nil: ll.tl.`=destroy` + #wasMoved(ll) + +proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk + if ll.tlf != nil: ll.tl = ll.tlf(); ll.tlf = nil + ll.tl + +var created = 0 +iterator hammings(until: int): TriVal = + proc merge(x, y: LazyList): LazyList = + let xh = x.hd; let yh = y.hd; created += 1 + when defined(trace20): + echo "merge create: ", (created - 1, (if xh < yh: xh else: yh)[1].convertTriVal2BigInt) + if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y) + else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest) + proc smult(mltf: LogRepf; s: LazyList): LazyList = + proc smults(ss: LazyList): LazyList = + when defined(trace20): + echo "mult create: ", (created, ss.hd.mltf[1].convertTriVal2BigInt) + created += 1; LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults) + s.smults + proc unnsm(s: LazyList, mltf: LogRepf): LazyList = + var r: LazyList = nil + when defined(trace20): + echo "first create: ", (created, one[1].convertTriVal2BigInt) + let frst = LazyList(hd: one, tlf: proc(): LazyList = r); created += 1 + r = if s == nil: smult(mltf, frst) else: s.merge smult(mltf, frst) + r + yield one[1] + var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2 + for _ in 2 .. until: + yield hmpll.hd[1]; hmpll = hmpll.rest # almost forever + +proc main = + var s = "" + for h in hammings(20): s &= $h.convertTrival2BigInt & " " + doAssert s == "1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 ", + "Algorithmic error finding first 20 Hamming numbers!!!" + + when not defined(trace20): + var lsth: TriVal; created = 0; destroyed = 0 + for h in hammings(200): lsth = h + doAssert $lsth.convertTriVal2BigInt == "16200", + "Algorithmic error finding 200th Hamming number!!!" + +let mem = getOccupiedMem() +main() +GC_FullCollect() +let mb = getOccupiedMem() - mem +#doAssert mb == 0, "Found memory leak of " & $mb & " bytes!!!" + +echo getAllocStats() +echo "created ", created, " destroyed ", destroyed From ffce6de84c94348dd5a615c9855a14ed64807449 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 7 Jul 2021 00:43:16 -0700 Subject: [PATCH 2801/4254] improve rendering of newOSError.additionalInfo (#18443) * improve rendering of newOSError.additionalInfo * fixup --- lib/pure/includes/oserr.nim | 5 +++-- lib/pure/net.nim | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index b0740cbe6..e42771d52 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -80,8 +80,9 @@ proc newOSError*( e.msg = osErrorMsg(errorCode) if additionalInfo.len > 0: if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n' - e.msg.add "Additional info: " - e.msg.addQuoted additionalInfo + e.msg.add "Additional info: " + e.msg.add additionalInfo + # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs. if e.msg == "": e.msg = "unknown OS error" return e diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ec3e4e74d..9c3827751 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -958,7 +958,9 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: freeaddrinfo(aiList) - raiseOSError(osLastError(), "address: $# port: $#" % [address, $port]) + var address2: string + address2.addQuoted address + raiseOSError(osLastError(), "address: $# port: $#" % [address2, $port]) freeaddrinfo(aiList) proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, From 2d758795f05d8edf567011eeb49f0cdd38b6dc13 Mon Sep 17 00:00:00 2001 From: Aditya Siram Date: Wed, 7 Jul 2021 21:21:30 -0500 Subject: [PATCH 2802/4254] Rename test variable due to unfortunate connotations (#18453) --- tests/stdlib/twrapnils.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index 1a66f4cd9..a0549c1bc 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -23,7 +23,7 @@ proc main() = x8: seq[int] x9: ref Bar - type Gook = ref object + type Goo = ref object foo: Foo proc fun(a: Bar): auto = a.b2 @@ -39,7 +39,7 @@ proc main() = var a3 = Foo(x1: 1.2, x3: "abc") a3.x2 = a3 - var gook = Gook(foo: a) + var goo = Goo(foo: a) proc initFoo(x1: float): auto = witness.inc @@ -53,8 +53,8 @@ proc main() = doAssert a3.x2.x2.x3.len == 3 doAssert ?.a.x2.x2.x3[1] == default(char) - # here we only apply wrapnil around gook.foo, not gook (and assume gook is not nil) - doAssert ?.(gook.foo).x2.x2.x1 == 0.0 + # here we only apply wrapnil around goo.foo, not goo (and assume goo is not nil) + doAssert ?.(goo.foo).x2.x2.x1 == 0.0 when nimvm: discard else: From 5a42f4a53e22051493232652cda7fb3d32c16da8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 8 Jul 2021 03:26:57 -0700 Subject: [PATCH 2803/4254] followup #18252: show special flags -d:danger, -d:release when given (#18451) --- compiler/msgs.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 8b4365ec4..242b06587 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -677,6 +677,10 @@ proc genSuccessX*(conf: ConfigRef) = elif optOptimizeSize in conf.options: build.add "size" else: build.add "none (DEBUG BUILD, `-d:release` generates faster code)" # pending https://github.com/timotheecour/Nim/issues/752, point to optimization.html + var flags = "" + if isDefined(conf, "danger"): flags.add " -d:danger" + elif isDefined(conf, "release"): flags.add " -d:release" + if flags.len > 0: build.add "; options:" & flags let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName # xxx honor conf.filenameOption more accurately From 836b061ae30bb471dc7deef41bb454e1d047bab7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 8 Jul 2021 03:28:06 -0700 Subject: [PATCH 2804/4254] improve `--declaredLocs` to help disambiguate types (generics, aliases etc) (#18389) * improve --declaredlocs to help disambiguate types (generics, aliases etc) * avoid a cyclic deps * fix test after rebase --- changelog.md | 2 +- compiler/astmsgs.nim | 2 +- compiler/semcall.nim | 12 ++--- compiler/semexprs.nim | 2 +- compiler/types.nim | 8 +++ tests/errmsgs/tdeclaredlocs.nim | 92 ++++++++++++++++++++++++++++++++ tests/errmsgs/tproc_mismatch.nim | 2 +- tests/errmsgs/tsigmatch.nim | 6 +-- 8 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 tests/errmsgs/tdeclaredlocs.nim diff --git a/changelog.md b/changelog.md index 1deb97161..f4c31fbc9 100644 --- a/changelog.md +++ b/changelog.md @@ -395,7 +395,7 @@ ## Compiler changes -- Added `--declaredlocs` to show symbol declaration location in messages. +- Added `--declaredLocs` to show symbol declaration location in messages. - You can now enable/disable VM tracing in user code via `vmutils.vmTrace`. diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim index 90bdce7cf..d9105b761 100644 --- a/compiler/astmsgs.nim +++ b/compiler/astmsgs.nim @@ -18,7 +18,7 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = # xxx figure out how to resolve `tyGenericParam`, e.g. for # proc fn[T](a: T, b: T) = discard # fn(1.1, "a") - let typ = typ.skipTypes(abstractInst + {tyStatic, tyUserTypeClassInst} - {tyRange}) + let typ = typ.skipTypes(abstractInst + {tyStatic, tySequence, tyArray, tySet, tyUserTypeClassInst, tyVar, tyRef, tyPtr} - {tyRange}) result.add " [$1" % typ.kind.toHumanStr if typ.sym != nil: result.add " declared in " & toFileLineCol(conf, typ.sym.info) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index cec656fc2..d8dba3e6c 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -231,11 +231,10 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): of kMissingParam: candidates.add("\n missing parameter: " & nameParam) of kTypeMismatch, kVarNeeded: doAssert nArg != nil - var wanted = err.firstMismatch.formal.typ + let wanted = err.firstMismatch.formal.typ doAssert err.firstMismatch.formal != nil candidates.add("\n required type for " & nameParam & ": ") - candidates.add typeToString(wanted) - candidates.addDeclaredLocMaybe(c.config, wanted) + candidates.addTypeDeclVerboseMaybe(c.config, wanted) candidates.add "\n but expression '" if err.firstMismatch.kind == kVarNeeded: candidates.add renderNotLValue(nArg) @@ -243,9 +242,8 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): else: candidates.add renderTree(nArg) candidates.add "' is of type: " - var got = nArg.typ - candidates.add typeToString(got) - candidates.addDeclaredLocMaybe(c.config, got) + let got = nArg.typ + candidates.addTypeDeclVerboseMaybe(c.config, got) doAssert wanted != nil if got != nil: if got.kind == tyProc and wanted.kind == tyProc: @@ -274,7 +272,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): const errTypeMismatch = "type mismatch: got <" - errButExpected = "but expected one of: " + errButExpected = "but expected one of:" errUndeclaredField = "undeclared field: '$1'" errUndeclaredRoutine = "attempting to call undeclared routine: '$1'" errBadRoutine = "attempting to call routine: '$1'$2" diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index acf408db0..f46d44bf0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -988,7 +988,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = break if not hasErrorType: let typ = n[0].typ - msg.add(">\nbut expected one of: \n" & + msg.add(">\nbut expected one of:\n" & typeToString(typ)) # prefer notin preferToResolveSymbols # t.sym != nil diff --git a/compiler/types.nim b/compiler/types.nim index bdf08ffe9..49ebb1dae 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -50,6 +50,14 @@ type pcmDifferentCallConv proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string + +proc addTypeDeclVerboseMaybe*(result: var string, conf: ConfigRef; typ: PType) = + if optDeclaredLocs in conf.globalOptions: + result.add typeToString(typ, preferMixed) + result.addDeclaredLoc(conf, typ) + else: + result.add typeToString(typ) + template `$`*(typ: PType): string = typeToString(typ) proc base*(t: PType): PType = diff --git a/tests/errmsgs/tdeclaredlocs.nim b/tests/errmsgs/tdeclaredlocs.nim new file mode 100644 index 000000000..926ebf217 --- /dev/null +++ b/tests/errmsgs/tdeclaredlocs.nim @@ -0,0 +1,92 @@ +discard """ + action: reject + matrix: "--declaredLocs --hints:off" + nimoutFull: true + nimout: ''' +tdeclaredlocs.nim(92, 3) Error: type mismatch: got +but expected one of: +proc fn(a: Bam) [proc declared in tdeclaredlocs.nim(86, 6)] + first type mismatch at position: 1 + required type for a: Bam [object declared in tdeclaredlocs.nim(78, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: Goo[MyInt2]) [proc declared in tdeclaredlocs.nim(89, 6)] + first type mismatch at position: 1 + required type for a: Goo[MyInt2{char}] [object declared in tdeclaredlocs.nim(79, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: Goo[cint]) [proc declared in tdeclaredlocs.nim(88, 6)] + first type mismatch at position: 1 + required type for a: Goo[cint{int32}] [object declared in tdeclaredlocs.nim(79, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: array[3, Bar]) [proc declared in tdeclaredlocs.nim(82, 6)] + first type mismatch at position: 1 + required type for a: array[0..2, Bar] [object declared in tdeclaredlocs.nim(74, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: seq[Bar]) [proc declared in tdeclaredlocs.nim(81, 6)] + first type mismatch at position: 1 + required type for a: seq[Bar] [object declared in tdeclaredlocs.nim(74, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: seq[MyInt1]) [proc declared in tdeclaredlocs.nim(80, 6)] + first type mismatch at position: 1 + required type for a: seq[MyInt1{int}] [int declared in tdeclaredlocs.nim(72, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: set[Baz]) [proc declared in tdeclaredlocs.nim(84, 6)] + first type mismatch at position: 1 + required type for a: set[Baz{enum}] [enum declared in tdeclaredlocs.nim(75, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: set[MyInt2]) [proc declared in tdeclaredlocs.nim(83, 6)] + first type mismatch at position: 1 + required type for a: set[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: var SetBaz) [proc declared in tdeclaredlocs.nim(85, 6)] + first type mismatch at position: 1 + required type for a: var SetBaz [enum declared in tdeclaredlocs.nim(75, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] +proc fn(a: var ref ptr Bam) [proc declared in tdeclaredlocs.nim(87, 6)] + first type mismatch at position: 1 + required type for a: var ref ptr Bam [object declared in tdeclaredlocs.nim(78, 3)] + but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)] + +expression: fn(a) +''' +""" + +#[ +see also: tests/errmsgs/tsigmatch.nim +]# + + + + + + + + + + + + + + +# line 70 +type + MyInt1 = int + MyInt2 = char + Bar = object + Baz = enum k0, k1 + Baz2 = Baz + SetBaz = set[Baz2] + Bam = ref object + Goo[T] = object +proc fn(a: seq[MyInt1]) = discard +proc fn(a: seq[Bar]) = discard +proc fn(a: array[3, Bar]) = discard +proc fn(a: set[MyInt2]) = discard +proc fn(a: set[Baz]) = discard +proc fn(a: var SetBaz) = discard +proc fn(a: Bam) = discard +proc fn(a: var ref ptr Bam) = discard +proc fn(a: Goo[cint]) = discard +proc fn(a: Goo[MyInt2]) = discard + +var a: seq[MyInt2] +fn(a) diff --git a/tests/errmsgs/tproc_mismatch.nim b/tests/errmsgs/tproc_mismatch.nim index 400c3d441..4ddc7635e 100644 --- a/tests/errmsgs/tproc_mismatch.nim +++ b/tests/errmsgs/tproc_mismatch.nim @@ -6,7 +6,7 @@ discard """ tproc_mismatch.nim(35, 52) Error: type mismatch: got but expected 'proc (a: int, c: float){.closure, noSideEffect.}' Calling convention mismatch: got '{.cdecl.}', but expected '{.closure.}'. tproc_mismatch.nim(39, 6) Error: type mismatch: got -but expected one of: +but expected one of: proc bar(a: proc ()) first type mismatch at position: 1 required type for a: proc (){.closure.} diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim index 4f40be2d4..023b7d518 100644 --- a/tests/errmsgs/tsigmatch.nim +++ b/tests/errmsgs/tsigmatch.nim @@ -89,9 +89,9 @@ expression: fun1(default(Mystring), "asdf") - - - +#[ +see also: tests/errmsgs/tdeclaredlocs.nim +]# From 0d74f60742ecff2ac96d97e9ad421aa1b2e8fc85 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 8 Jul 2021 16:09:56 +0200 Subject: [PATCH 2805/4254] Revert "Make 'echo' raise IOErrors when appropriate (#16367)" (#18460) This reverts commit 23d23ecb081be6702d74024be8f96d92d9f88a59. --- changelog.md | 3 --- lib/system/io.nim | 24 ++++++++---------------- tests/exception/t16366.nim | 11 ----------- 3 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 tests/exception/t16366.nim diff --git a/changelog.md b/changelog.md index f4c31fbc9..849640e06 100644 --- a/changelog.md +++ b/changelog.md @@ -24,9 +24,6 @@ - Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous behavior. -- `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior - silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. - - `math.round` now is rounded "away from zero" in JS backend which is consistent with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. diff --git a/lib/system/io.nim b/lib/system/io.nim index 62a9d1e18..591ea3e92 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -227,9 +227,6 @@ when defined(windows): # But we cannot call printf directly as the string might contain \0. # So we have to loop over all the sections separated by potential \0s. var i = c_fprintf(f, "%s", s) - if i < 0: - if doRaise: raiseEIO("cannot write string to file") - return while i < s.len: if s[i] == '\0': let w = c_fputc('\0', f) @@ -787,13 +784,6 @@ when declared(stdout): not defined(nintendoswitch) and not defined(freertos) and hostOS != "any" - const echoDoRaise = not defined(nimLegacyEchoNoRaise) and not defined(guiapp) # see PR #16366 - - template checkErrMaybe(succeeded: bool): untyped = - if not succeeded: - when echoDoRaise: - checkErr(stdout) - proc echoBinSafe(args: openArray[string]) {.compilerproc.} = when defined(androidNDK): var s = "" @@ -806,18 +796,20 @@ when declared(stdout): proc flockfile(f: File) {.importc, nodecl.} proc funlockfile(f: File) {.importc, nodecl.} flockfile(stdout) - defer: funlockfile(stdout) when defined(windows) and compileOption("threads"): acquireSys echoLock - defer: releaseSys echoLock for s in args: when defined(windows): - writeWindows(stdout, s, doRaise = echoDoRaise) + writeWindows(stdout, s) else: - checkErrMaybe(c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout) == s.len) + discard c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout) const linefeed = "\n" - checkErrMaybe(c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) == linefeed.len) - checkErrMaybe(c_fflush(stdout) == 0) + discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) + discard c_fflush(stdout) + when stdOutLock: + funlockfile(stdout) + when defined(windows) and compileOption("threads"): + releaseSys echoLock when defined(windows) and not defined(nimscript) and not defined(js): diff --git a/tests/exception/t16366.nim b/tests/exception/t16366.nim deleted file mode 100644 index 4bcad79ed..000000000 --- a/tests/exception/t16366.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ - action: run - exitcode: 0 - targets: "c cpp" - disabled: openbsd -""" - -echo "foo1" -close stdout -doAssertRaises(IOError): - echo "foo" From 0e44d137f97a8206af1f2747391615e2f237f000 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Fri, 9 Jul 2021 03:24:57 +0300 Subject: [PATCH 2806/4254] rm redundant blank lines before literal blocks (#18465) --- lib/packages/docutils/rst.nim | 2 +- lib/packages/docutils/rstgen.nim | 2 +- nimdoc/rst2html/expected/rst_examples.html | 15 +++++---------- tests/stdlib/trst.nim | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 419cf50e7..9abdf3fc3 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1762,7 +1762,7 @@ proc parseLiteralBlock(p: var RstParser): PRstNode = var n = newLeaf("") if currentTok(p).kind == tkIndent: var indent = currentTok(p).ival - inc p.idx + while currentTok(p).kind == tkIndent: inc p.idx # skip blank lines while true: case currentTok(p).kind of tkEof: diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 829177263..b9c8f688b 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1258,7 +1258,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = doAssert false, "renderRstToOut" of rnLiteralBlock: renderAux(d, n, "$1
    \n", - "\n\n\\begin{rstpre}\n$2\n$1\n\\end{rstpre}\n\n", result) + "\n\n$2\\begin{rstpre}\n$1\n\\end{rstpre}\n\n", result) of rnQuotedLiteralBlock: doAssert false, "renderRstToOut" of rnLineBlock: diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 68b796be7..1df91ff1f 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -133,8 +133,7 @@ window.addEventListener('DOMContentLoaded', main);

    Note: Assignments, moves, and destruction are specified in the destructors document.

    The language constructs are explained using an extended BNF, in which (a)* means 0 or more a's, a+ means 1 or more a's, and (a)? means an optional a. Parentheses may be used to group elements.

    & is the lookahead operator; &a means that an a is expected but not consumed. It will be consumed in the following rule.

    -

    Non-terminals start with a lowercase letter, abstract terminal symbols are in UPPERCASE. Verbatim terminal symbols (including keywords) are quoted with '. An example:

    -ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
    +

    Non-terminals start with a lowercase letter, abstract terminal symbols are in UPPERCASE. Verbatim terminal symbols (including keywords) are quoted with '. An example:

    ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?

    In a typical Nim program, most of the code is compiled into the executable. However, some of the code may be executed at compile-time. This can include constant expressions, macro definitions, and Nim procedures used by macro definitions. Most of the Nim language is supported at compile-time, but there are some restrictions -- see Restrictions on Compile-Time Execution for details. We use the term runtime to cover both compile-time execution and code execution in the executable.

    var a: array[0..1, char]
    @@ -146,8 +145,7 @@ ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?

    Encoding

    All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other encodings are not supported. Any of the standard platform line termination sequences can be used - the Unix form using ASCII LF (linefeed), the Windows form using the ASCII sequence CR LF (return followed by linefeed), or the old Macintosh form using the ASCII CR (return) character. All of these forms can be used equally, regardless of the platform.

    Indentation

    Nim's standard grammar describes an indentation sensitive language. This means that all the control structures are recognized by indentation. Indentation consists only of spaces; tabulators are not allowed.

    -

    With this notation we can now easily define the core of the grammar: A block of statements (simplified example):

    -ifStmt = 'if' expr ':' stmt
    +

    With this notation we can now easily define the core of the grammar: A block of statements (simplified example):

    ifStmt = 'if' expr ':' stmt
              (IND{=} 'elif' expr ':' stmt)*
              (IND{=} 'else' ':' stmt)?
     
    @@ -174,18 +172,15 @@ stmt = IND{>} stmt ^+ IND{=} DED  # list of statements
     \x HHcharacter with hex value HH; exactly two hex digits are allowed
     \u HHHHunicode codepoint with hex value HHHH; exactly four hex digits are allowed
     \u {H+}unicode codepoint; all hex digits enclosed in {} are used for the codepoint
    -
    """"long string within quotes""""

    Produces:

    -"long string within quotes"
    +
    """"long string within quotes""""

    Produces:

    "long string within quotes"

    -

    Operators

    Nim allows user defined operators. An operator is any combination of the following characters:

    -=     +     -     *     /     <     >
    +

    Operators

    Nim allows user defined operators. An operator is any combination of the following characters:

    =     +     -     *     /     <     >
     @     $     ~     &     %     |
     !     ?     ^     .     :     \

    (The grammar uses the terminal OPR to refer to operator symbols as defined here.)

    -

    The following strings denote other tokens:

    -`   (    )     {    }     [    ]    ,  ;   [.    .]  {.   .}  (.  .)  [:
    +

    The following strings denote other tokens:

    `   (    )     {    }     [    ]    ,  ;   [.    .]  {.   .}  (.  .)  [:

    Otherwise, precedence is determined by the first character.

    diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index fb9552479..fe99d6cfa 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -196,6 +196,22 @@ suite "RST parsing": rnLeaf 'someBlockQuote' """) + test "no redundant blank lines in literal blocks": + check(dedent""" + Check:: + + + code + + """.toAst == + dedent""" + rnInner + rnLeaf 'Check' + rnLeaf ':' + rnLiteralBlock + rnLeaf 'code' + """) + suite "RST indentation": test "nested bullet lists": let input = dedent """ From 86f5a56fcdbdbd4748c979e6f517d8dfc64857f7 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Fri, 9 Jul 2021 03:26:49 +0300 Subject: [PATCH 2807/4254] Fix a bug with starting of asynchronous processes (#18464) The asynchronous process completion handler callback should be called only once. This is achieved by passing `WT_EXECUTEONLYONCE` flag to the `registerWaitForSingleObject` Windows API procedure. Related to cheatfate/asynctools#35 --- lib/pure/asyncdispatch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 17fd5f824..d98ca77df 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1022,7 +1022,7 @@ when defined(windows) or defined(nimdoc): raiseOSError(osLastError()) var pcd = cast[PostCallbackDataPtr](allocShared0(sizeof(PostCallbackData))) - var flags = WT_EXECUTEINWAITTHREAD.DWORD + var flags = WT_EXECUTEINWAITTHREAD.DWORD or WT_EXECUTEONLYONCE.DWORD proc proccb(fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = closeWaitable(hProcess) From 6869157cd17229dbadb8b1b43c218d5fb28e8eb2 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 9 Jul 2021 13:44:38 +0800 Subject: [PATCH 2808/4254] [docs] improve std/encodings (#18458) * [docs] improve std/encodings * tiny * shrink * Apply suggestions from code review Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Apply suggestions from code review * Update lib/pure/encodings.nim Co-authored-by: Varriount Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Varriount --- lib/pure/encodings.nim | 53 ++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 89db0a278..dcdc474ae 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -7,15 +7,42 @@ # distribution, for details about the copyright. # -## Converts between different character encodings. On UNIX, this uses +## Routines for converting between different character encodings. On UNIX, this uses ## the `iconv`:idx: library, on Windows the Windows API. +## +## The following example shows how to change character encodings. +runnableExamples: + let + orig = "öäüß" + # convert `orig` from "UTF-8" to "CP1252" + cp1252 = convert(orig, "CP1252", "UTF-8") + # convert `cp1252` from "CP1252" to "ibm850" + ibm850 = convert(cp1252, "ibm850", "CP1252") + current = getCurrentEncoding() + assert orig == "\195\182\195\164\195\188\195\159" + assert ibm850 == "\148\132\129\225" + assert convert(ibm850, current, "ibm850") == orig + +## The example below uses a reuseable `EncodingConverter` object which is +## created by `open` with `destEncoding` and `srcEncoding` specified. You can use +## `convert` on this object multiple times. +runnableExamples: + var fromGB2312 = open("utf-8", "gb2312") + let first = "\203\173\197\194\163\191\210\187" & + "\203\242\209\204\211\234\200\206\198\189\201\250" + assert fromGB2312.convert(first) == "谁怕?一蓑烟雨任平生" + + let second = "\211\208\176\215\205\183\200\231" & + "\208\194\163\172\199\227\184\199\200\231\185\202" + assert fromGB2312.convert(second) == "有白头如新,倾盖如故" + import os when not defined(windows): type ConverterObj = object - EncodingConverter* = ptr ConverterObj ## can convert between two character sets + EncodingConverter* = ptr ConverterObj ## Can convert between two character sets. else: type @@ -24,8 +51,8 @@ else: dest, src: CodePage type - EncodingError* = object of ValueError ## exception that is raised - ## for encoding errors + EncodingError* = object of ValueError ## Exception that is raised + ## for encoding errors. when defined(windows): import parseutils, strutils @@ -298,7 +325,7 @@ else: importc: "iconv", importIconv.} proc getCurrentEncoding*(uiApp = false): string = - ## retrieves the current encoding. On Unix, always "UTF-8" is returned. + ## Retrieves the current encoding. On Unix, "UTF-8" is always returned. ## The `uiApp` parameter is Windows specific. If true, the UI's code-page ## is returned, if false, the Console's code-page is returned. when defined(windows): @@ -307,7 +334,7 @@ proc getCurrentEncoding*(uiApp = false): string = result = "UTF-8" proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter = - ## opens a converter that can convert from `srcEncoding` to `destEncoding`. + ## Opens a converter that can convert from `srcEncoding` to `destEncoding`. ## Raises `IOError` if it cannot fulfill the request. when not defined(windows): result = iconvOpen(destEncoding, srcEncoding) @@ -326,7 +353,7 @@ proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter = "cannot find encoding " & srcEncoding) proc close*(c: EncodingConverter) = - ## frees the resources the converter `c` holds. + ## Frees the resources the converter `c` holds. when not defined(windows): iconvClose(c) @@ -421,12 +448,13 @@ when defined(windows): else: convertFromWideString(codePageTo, wideString) proc convert*(c: EncodingConverter, s: string): string = - ## converts `s` to `destEncoding` that was given to the converter `c`. It - ## assumed that `s` is in `srcEncoding`. - ## utf-16BE, utf-32 conversions not supported on windows result = convertWin(c.src, c.dest, s) else: proc convert*(c: EncodingConverter, s: string): string = + ## Converts `s` to `destEncoding` that was given to the converter `c`. It + ## assumes that `s` is in `srcEncoding`. + ## + ## .. warning:: UTF-16BE and UTF-32 conversions are not supported on Windows. result = newString(s.len) var inLen = csize_t len(s) var outLen = csize_t len(result) @@ -467,10 +495,11 @@ else: proc convert*(s: string, destEncoding = "UTF-8", srcEncoding = "CP1252"): string = - ## converts `s` to `destEncoding`. It assumed that `s` is in `srcEncoding`. + ## Converts `s` to `destEncoding`. It assumed that `s` is in `srcEncoding`. ## This opens a converter, uses it and closes it again and is thus more ## convenient but also likely less efficient than re-using a converter. - ## utf-16BE, utf-32 conversions not supported on windows + ## + ## .. warning:: UTF-16BE and UTF-32 conversions are not supported on Windows. var c = open(destEncoding, srcEncoding) try: result = convert(c, s) From ae7e7756fea146126ffc5200b2e66bfe2dab4cd4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 9 Jul 2021 02:41:28 -0700 Subject: [PATCH 2809/4254] runnableExamples now show originating location in stacktraces on failure (#18457) * runnableExamples now show originating location in stacktraces on failure * PRTEMP * fix indentation inside multiline strings --- compiler/docgen.nim | 25 +++++++++++++++++++------ compiler/renderverbatim.nim | 11 ++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e6bb7cef8..1ae00e22e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -468,6 +468,10 @@ proc runAllExamples(d: PDoc) = proc quoted(a: string): string = result.addQuoted(a) +proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): auto = + # xxx expose in compiler/lineinfos.nim + (conf.toMsgFilename(info), info.line.int, info.col.int + ColOffset) + proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, code: string] = ## returns `rdoccmd` and source code for this runnableExamples var rdoccmd = "" @@ -481,6 +485,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c let useRenderModule = false let loc = d.conf.toFileLineCol(n.info) let code = extractRunnableExamplesSource(d.conf, n) + let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2) if d.conf.errorCounter > 0: return (rdoccmd, code) @@ -489,7 +494,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c let outputDir = d.exampleOutputDir createDir(outputDir) inc d.exampleCounter - let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" & ("_examples$1.nim" % $d.exampleCounter))) + let outp = outputDir / RelativeFile("$#_examples_$#.nim" % [d.filename.extractFilename.changeFileExt"", $d.exampleCounter]) if useRenderModule: var docComment = newTree(nkCommentStmt) @@ -507,13 +512,21 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c renderModule(runnableExamples, outp.string, conf = d.conf) else: - let code2 = """ + var code2 = code + if code.len > 0 and "codeReordering" notin code: + # hacky but simplest solution, until we devise a way to make `{.line.}` + # work without introducing a scope + code2 = """ +{.line: $#.}: +$# +""" % [$toInstantiationInfo(d.conf, n.info), codeIndent] + code2 = """ #[ -$1 +$# ]# -import $2 -$3 -""" % [comment, d.filename.quoted, code] +import $# +$# +""" % [comment, d.filename.quoted, code2] writeFile(outp.string, code2) if rdoccmd notin d.exampleGroups: diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index a20c8873d..fc74f2322 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -83,7 +83,7 @@ proc startOfLineInsideTriple(ldata: LineData, line: int): bool = if index >= ldata.lines.len: false else: ldata.lines[index] -proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = +proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode, indent = 0): string = ## TLineInfo.offsetA,offsetB would be cleaner but it's only enabled for nimpretty, ## we'd need to check performance impact to enable it for nimdoc. var first = n.lastSon.info @@ -102,7 +102,7 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = let last = n.lastNodeRec.info var info = first - var indent = info.col + var indent2 = info.col let numLines = numLines(conf, info.fileIndex).uint16 var lastNonemptyPos = 0 @@ -118,14 +118,15 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string = info.line = line let src = sourceLine(conf, info) let special = startOfLineInsideTriple(ldata, line.int) - if line > last.line and not special and not isInIndentationBlock(src, indent): + if line > last.line and not special and not isInIndentationBlock(src, indent2): break if line > first.line: result.add "\n" if special: result.add src lastNonemptyPos = result.len - elif src.len > indent: - result.add src[indent..^1] + elif src.len > indent2: + for i in 0.. Date: Fri, 9 Jul 2021 15:15:49 +0200 Subject: [PATCH 2810/4254] ORC: support for custom =trace procs (#18459) * ORC: support custom =trace procs (WIP) * Update tests/arc/tcustomtrace.nim Co-authored-by: Clyybber * =trace is now documented and seems to work * make test green Co-authored-by: Clyybber --- changelog.md | 2 + compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 1 + compiler/condsyms.nim | 1 + compiler/jsgen.nim | 2 +- compiler/liftdestructors.nim | 16 ++- compiler/semmagic.nim | 6 + compiler/semstmts.nim | 13 +- compiler/vmgen.nim | 2 +- doc/destructors.rst | 37 ++++++ doc/manual.rst | 5 +- lib/system.nim | 5 + tests/arc/tcustomtrace.nim | 240 +++++++++++++++++++++++++++++++++++ 13 files changed, 321 insertions(+), 11 deletions(-) create mode 100644 tests/arc/tcustomtrace.nim diff --git a/changelog.md b/changelog.md index 849640e06..bc64e9579 100644 --- a/changelog.md +++ b/changelog.md @@ -388,6 +388,8 @@ - `typeof(voidStmt)` now works and returns `void`. +- The `gc:orc` algorithm was refined so that custom container types can participate in the + cycle collection process. ## Compiler changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 26050426a..f96e464af 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -667,7 +667,7 @@ type mIsPartOf, mAstToStr, mParallel, mSwap, mIsNil, mArrToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, - mMove, mWasMoved, mDestroy, + mMove, mWasMoved, mDestroy, mTrace, mDefault, mUnown, mIsolate, mAccessEnv, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c07ddf1db..09326ceeb 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2422,6 +2422,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mDestroy: genDestroy(p, e) of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0") of mSlice: genSlice(p, e, d) + of mTrace: discard "no code to generate" else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index b3f8465f0..33cd1818b 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -136,3 +136,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasTypeofVoid") defineSymbol("nimHasDragonBox") defineSymbol("nimHasHintAll") + defineSymbol("nimHasTrace") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index a9339c7fd..82fba02a6 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2079,7 +2079,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[1], x) useMagic(p, "nimCopy") r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)] - of mDestroy: discard "ignore calls to the default destructor" + of mDestroy, mTrace: discard "ignore calls to the default destructor" of mOrd: genOrd(p, n, r) of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: var x: TCompRes diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 1824557e6..b2b70edee 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -416,11 +416,23 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = body.add destructorCall(c, op, x) result = true #result = addDestructorCall(c, t, body, x) - of attachedAsgn, attachedSink, attachedTrace: + of attachedAsgn, attachedSink: var op = getAttachedOp(c.g, t, c.kind) result = considerAsgnOrSink(c, t, body, x, y, op) if op != nil: setAttachedOp(c.g, c.idgen.module, t, c.kind, op) + of attachedTrace: + var op = getAttachedOp(c.g, t, c.kind) + if op != nil and sfOverriden in op.flags: + if op.ast.isGenericRoutine: + # patch generic =trace: + op = instantiateGeneric(c, op, t, t.typeInst) + setAttachedOp(c.g, c.idgen.module, t, c.kind, op) + + result = considerAsgnOrSink(c, t, body, x, y, op) + if op != nil: + setAttachedOp(c.g, c.idgen.module, t, c.kind, op) + of attachedDeepCopy: let op = getAttachedOp(c.g, t, attachedDeepCopy) if op != nil: @@ -1065,7 +1077,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf # 4. We have a custom destructor. # 5. We have a (custom) generic destructor. - # we do not generate '=trace' nor '=dispose' procs if we + # we do not generate '=trace' procs if we # have the cycle detection disabled, saves code size. let lastAttached = if g.config.selectedGC == gcOrc: attachedTrace else: attachedSink diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index d3f26e630..04f4c4729 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -551,6 +551,12 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, let op = getAttachedOp(c.graph, t, attachedDestructor) if op != nil: result[0] = newSymNode(op) + of mTrace: + result = n + let t = n[1].typ.skipTypes(abstractVar) + let op = getAttachedOp(c.graph, t, attachedTrace) + if op != nil: + result[0] = newSymNode(op) of mUnown: result = semUnown(c, n) of mExists, mForall: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c3402aee3..fd2f8a1d9 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1649,6 +1649,8 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = var noError = false let cond = if op == attachedDestructor: t.len == 2 and t[0] == nil and t[1].kind == tyVar + elif op == attachedTrace: + t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer else: t.len >= 2 and t[0] == nil @@ -1673,8 +1675,12 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = localError(c.config, n.info, errGenerated, "type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")") if not noError and sfSystemModule notin s.owner.flags: - localError(c.config, n.info, errGenerated, - "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") + if op == attachedTrace: + localError(c.config, n.info, errGenerated, + "signature for '=trace' must be proc[T: object](x: var T; env: pointer)") + else: + localError(c.config, n.info, errGenerated, + "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") incl(s.flags, sfUsed) incl(s.flags, sfOverriden) @@ -1752,7 +1758,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = localError(c.config, n.info, errGenerated, "signature for '" & s.name.s & "' must be proc[T: object](x: var T; y: T)") of "=trace": - bindTypeHook(c, s, n, attachedTrace) + if s.magic != mTrace: + bindTypeHook(c, s, n, attachedTrace) else: if sfOverriden in s.flags: localError(c.config, n.info, errGenerated, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 14f9e0b30..e5e4a854e 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1362,7 +1362,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = globalError(c.config, n.info, sizeOfLikeMsg("offsetof")) of mRunnableExamples: discard "just ignore any call to runnableExamples" - of mDestroy: discard "ignore calls to the default destructor" + of mDestroy, mTrace: discard "ignore calls to the default destructor" of mMove: let arg = n[1] let a = c.genx(arg) diff --git a/doc/destructors.rst b/doc/destructors.rst index c99606b95..a94ccb9e7 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -42,6 +42,12 @@ written as: for i in 0..`_. diff --git a/lib/system.nim b/lib/system.nim index 090ab309e..8aa9bd718 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -488,6 +488,11 @@ proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} = ## Generic `sink`:idx: implementation that can be overridden. shallowCopy(x, y) +when defined(nimHasTrace): + proc `=trace`*[T](x: var T; env: pointer) {.inline, magic: "Trace".} = + ## Generic `trace`:idx: implementation that can be overridden. + discard + type HSlice*[T, U] = object ## "Heterogeneous" slice type. a*: T ## The lower bound (inclusive). diff --git a/tests/arc/tcustomtrace.nim b/tests/arc/tcustomtrace.nim new file mode 100644 index 000000000..3977194d9 --- /dev/null +++ b/tests/arc/tcustomtrace.nim @@ -0,0 +1,240 @@ +discard """ + outputsub: '''1 +2 +3 +4 +5 +6 +89 +90 +90 +0 0 1 +0 1 2 +0 2 3 +1 0 4 +1 1 5 +1 2 6 +1 3 7 +after 6 6 +MEM 0''' +joinable: false + cmd: "nim c --gc:orc -d:useMalloc $file" + valgrind: "true" +""" + +import typetraits + +type + myseq*[T] = object + len, cap: int + data: ptr UncheckedArray[T] + +# XXX make code memory safe for overflows in '*' +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var myseq[T]) = + if x.data != nil: + when not supportsCopyMem(T): + for i in 0..= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + +template add*[T](x: var myseq[T]; y: T) = + reserveSlot(x)[] = y + +proc shrink*[T](x: var myseq[T]; newLen: int) = + assert newLen <= x.len + assert newLen >= 0 + when not supportsCopyMem(T): + for i in countdown(x.len - 1, newLen - 1): + `=destroy`(x.data[i]) + x.len = newLen + +proc grow*[T](x: var myseq[T]; newLen: int; value: T) = + if newLen <= x.len: return + assert newLen >= 0 + let oldCap = x.cap + if oldCap == 0: x.cap = newLen + else: x.cap = max(newLen, (oldCap * 3) shr 1) + if x.data == nil: inc allocCount + x.data = cast[type(x.data)](realloc0(x.data, oldCap * sizeof(T), x.cap * sizeof(T))) + for i in x.len.. Date: Sat, 10 Jul 2021 09:41:07 +0300 Subject: [PATCH 2811/4254] sync with the same template from locks module (#18414) --- lib/core/rlocks.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index a1ee0a6ec..0444b9a83 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -48,7 +48,7 @@ proc release*(lock: var RLock) {.inline.} = ## Releases the given lock. releaseSys(lock) -template withRLock*(lock: var RLock, code: untyped): untyped = +template withRLock*(lock: RLock, code: untyped) = ## Acquires the given lock and then executes the code. acquire(lock) {.locks: [lock].}: From 3645f5fc7ae885e22cb52b9f865edf062cfb8e59 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 10 Jul 2021 15:55:01 +0800 Subject: [PATCH 2812/4254] more important packages (#18472) --- testament/important_packages.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 3d3c340eb..afceffb2e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -37,6 +37,7 @@ pkg "alea", allowFailure = true pkg "argparse" pkg "arraymancer", "nim c tests/tests_cpu.nim", allowFailure = true pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim", allowFailure = true +pkg "asyncthreadpool" pkg "awk" pkg "bigints", url = "https://github.com/Araq/nim-bigints" pkg "binaryheap", "nim c -r binaryheap.nim" @@ -56,6 +57,7 @@ pkg "combparser", "nimble test --gc:orc" pkg "compactdict" pkg "comprehension", "nimble test", "https://github.com/alehander42/comprehension" pkg "criterion", allowFailure = true # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) +pkg "datamancer" pkg "dashing", "nim c tests/functional.nim" pkg "delaunay" pkg "docopt" @@ -81,6 +83,7 @@ pkg "jstin" pkg "karax", "nim c -r tests/tester.nim" pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree" pkg "loopfusion" +pkg "lockfreequeues" pkg "macroutils" pkg "manu" pkg "markdown" @@ -89,6 +92,7 @@ pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" pkg "neo", "nim c -d:blas=openblas tests/all.nim" pkg "nesm", "nimble tests", allowFailure = true # notice plural 'tests' +pkg "netty" pkg "nico", allowFailure = true pkg "nicy", "nim c -r src/nicy.nim" pkg "nigui", "nim c -o:niguii -r src/nigui.nim" @@ -134,10 +138,12 @@ pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", "nim c -r src/sdl.nim" pkg "sdl2_nim", "nim c -r sdl2/sdl.nim" pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" +pkg "sim" pkg "snip", "nimble test", "https://github.com/genotrance/snip" pkg "stint", "nim r stint.nim" pkg "strslice" pkg "strunicode", "nim c -r src/strunicode.nim" +pkg "supersnappy" pkg "synthesis" pkg "telebot", "nim c -o:tbot -r src/telebot.nim", allowFailure = true # pending https://github.com/ba0f3/telebot.nim/issues/59 pkg "tempdir" From 980a9ed5239ef03e73946ffcc84671a6eaa35616 Mon Sep 17 00:00:00 2001 From: sivchari Date: Sun, 11 Jul 2021 15:19:20 +0900 Subject: [PATCH 2813/4254] fix comment (#18473) --- lib/impure/re.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 504d8f22e..d6922f4f1 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -41,12 +41,12 @@ const type RegexFlag* = enum ## options for regular expressions - reIgnoreCase = 0, ## do caseless matching - reMultiLine = 1, ## `^` and `$` match newlines within data - reDotAll = 2, ## `.` matches anything including NL - reExtended = 3, ## ignore whitespace and `#` comments - reStudy = 4 ## study the expression (may be omitted if the - ## expression will be used only once) + reIgnoreCase = 0, ## do caseless matching + reMultiLine = 1, ## `^` and `$` match newlines within data + reDotAll = 2, ## `.` matches anything including NL + reExtended = 3, ## ignore whitespace and `#` comments + reStudy = 4 ## study the expression (may be omitted if the + ## expression will be used only once) RegexDesc = object h: ptr Pcre From 9ffc70851b586dbdc579d8c6af30a6a3604d7313 Mon Sep 17 00:00:00 2001 From: GordonBGood Date: Mon, 12 Jul 2021 16:55:40 +0700 Subject: [PATCH 2814/4254] thamming_orc test created/destroyed counts match (#18471) The thamming_orc.nim code now counts all created objects being tested, not just the ones following the "first 20" test, and the position of the `destroyed += 1` counter has been adjusted so it counts all the calls that are as a result of `=trace` tracing and not just the original destruction calls. --- tests/arc/thamming_orc.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/arc/thamming_orc.nim b/tests/arc/thamming_orc.nim index 463f7117e..777efb38e 100644 --- a/tests/arc/thamming_orc.nim +++ b/tests/arc/thamming_orc.nim @@ -1,6 +1,6 @@ discard """ output: '''(allocCount: 1114, deallocCount: 1112) -created 439 destroyed 402''' +created 491 destroyed 491''' cmd: "nim c --gc:orc -d:nimAllocStats $file" """ @@ -94,8 +94,8 @@ type var destroyed = 0 proc `=destroy`(ll: var LazyListObj) = - if ll.tlf == nil and ll.tl == nil: return destroyed += 1 + if ll.tlf == nil and ll.tl == nil: return when defined(trace20): echo "destroying: ", (destroyed, ll.hd[1].convertTriVal2BigInt) @@ -140,7 +140,7 @@ proc main = "Algorithmic error finding first 20 Hamming numbers!!!" when not defined(trace20): - var lsth: TriVal; created = 0; destroyed = 0 + var lsth: TriVal for h in hammings(200): lsth = h doAssert $lsth.convertTriVal2BigInt == "16200", "Algorithmic error finding 200th Hamming number!!!" @@ -149,7 +149,7 @@ let mem = getOccupiedMem() main() GC_FullCollect() let mb = getOccupiedMem() - mem -#doAssert mb == 0, "Found memory leak of " & $mb & " bytes!!!" +doAssert mb == 0, "Found memory leak of " & $mb & " bytes!!!" echo getAllocStats() echo "created ", created, " destroyed ", destroyed From 195300a938c7c8dd4ec7db3ca7cc76dddeab953e Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 12 Jul 2021 20:26:46 +0800 Subject: [PATCH 2815/4254] [source code filter]fix Nightlies bug (#18475) * workaround Nightlies bug * Update tools/niminst/makefile.nimf --- tools/niminst/makefile.nimf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index 8c40cf50f..d14960ac5 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -25,7 +25,7 @@ endif ifeq ($(uos),linux) myos = linux - # add -lrt to avoid "undefined reference to `clock_gettime'" with glibc<2.17 + ## add -lrt to avoid "undefined reference to `clock_gettime'" with glibc<2.17 LDFLAGS += -ldl -lm -lrt endif ifeq ($(uos),dragonfly) From 1b128ac04533421547298ecca0d9b8e7de477280 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 13 Jul 2021 06:18:07 +0800 Subject: [PATCH 2816/4254] close #17986 add testcase (#18477) --- tests/stdlib/tjsonutils.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 31ec4316f..b0c444cbf 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -311,6 +311,18 @@ template fn() = doAssert guide == AboutLifeUniverseAndEverythingElse( question: "6*9=?", answer: 42) + block refObject: #bug 17986 + type A = ref object + case is_a: bool + of true: + a: int + else: + b: int + + var a = A() + fromJson(a, """{"is_a": true, "a":1, "extra_key": 1}""".parse_json, Joptions(allowExtraKeys: true)) + doAssert $a[] == "(is_a: true, a: 1)" + block testAllowMissingKeys: var guide = AboutLifeUniverseAndEverythingElse( question: "6*9=?", answer: 54) From 15fdcd0c4d4d5b44a08766120d88b085eb358ae1 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 13 Jul 2021 15:22:33 +0800 Subject: [PATCH 2817/4254] workaround #18481 (#18482) --- lib/pure/encodings.nim | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index dcdc474ae..36e891dd3 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -12,29 +12,31 @@ ## ## The following example shows how to change character encodings. runnableExamples: - let - orig = "öäüß" - # convert `orig` from "UTF-8" to "CP1252" - cp1252 = convert(orig, "CP1252", "UTF-8") - # convert `cp1252` from "CP1252" to "ibm850" - ibm850 = convert(cp1252, "ibm850", "CP1252") - current = getCurrentEncoding() - assert orig == "\195\182\195\164\195\188\195\159" - assert ibm850 == "\148\132\129\225" - assert convert(ibm850, current, "ibm850") == orig + when defined(windows): + let + orig = "öäüß" + # convert `orig` from "UTF-8" to "CP1252" + cp1252 = convert(orig, "CP1252", "UTF-8") + # convert `cp1252` from "CP1252" to "ibm850" + ibm850 = convert(cp1252, "ibm850", "CP1252") + current = getCurrentEncoding() + assert orig == "\195\182\195\164\195\188\195\159" + assert ibm850 == "\148\132\129\225" + assert convert(ibm850, current, "ibm850") == orig ## The example below uses a reuseable `EncodingConverter` object which is ## created by `open` with `destEncoding` and `srcEncoding` specified. You can use ## `convert` on this object multiple times. runnableExamples: - var fromGB2312 = open("utf-8", "gb2312") - let first = "\203\173\197\194\163\191\210\187" & - "\203\242\209\204\211\234\200\206\198\189\201\250" - assert fromGB2312.convert(first) == "谁怕?一蓑烟雨任平生" + when defined(windows): + var fromGB2312 = open("utf-8", "gb2312") + let first = "\203\173\197\194\163\191\210\187" & + "\203\242\209\204\211\234\200\206\198\189\201\250" + assert fromGB2312.convert(first) == "谁怕?一蓑烟雨任平生" - let second = "\211\208\176\215\205\183\200\231" & - "\208\194\163\172\199\227\184\199\200\231\185\202" - assert fromGB2312.convert(second) == "有白头如新,倾盖如故" + let second = "\211\208\176\215\205\183\200\231" & + "\208\194\163\172\199\227\184\199\200\231\185\202" + assert fromGB2312.convert(second) == "有白头如新,倾盖如故" import os From b3aca78e228feb93d5dcd6f00cdd81e4178c24cc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 13 Jul 2021 12:44:29 +0200 Subject: [PATCH 2818/4254] closes #18433 (#18484) * beneficial refactoring; use system.Endianness * closes #18433 --- compiler/options.nim | 4 ++-- compiler/platform.nim | 6 ++---- tests/arc/tfuncobj.nim | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 tests/arc/tfuncobj.nim diff --git a/compiler/options.nim b/compiler/options.nim index 135ecf1de..45ca14e76 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -592,8 +592,8 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = result = conf.target.targetOS == osNintendoSwitch of "freertos", "lwip": result = conf.target.targetOS == osFreeRTOS - of "littleendian": result = CPU[conf.target.targetCPU].endian == platform.littleEndian - of "bigendian": result = CPU[conf.target.targetCPU].endian == platform.bigEndian + of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian + of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian of "cpu8": result = CPU[conf.target.targetCPU].bit == 8 of "cpu16": result = CPU[conf.target.targetCPU].bit == 16 of "cpu32": result = CPU[conf.target.targetCPU].bit == 32 diff --git a/compiler/platform.nim b/compiler/platform.nim index 413a91304..7bc77d809 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -196,13 +196,11 @@ type cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32 type - TEndian* = enum - littleEndian, bigEndian - TInfoCPU* = tuple[name: string, intSize: int, endian: TEndian, + TInfoCPU* = tuple[name: string, intSize: int, endian: Endianness, floatSize, bit: int] const - EndianToStr*: array[TEndian, string] = ["littleEndian", "bigEndian"] + EndianToStr*: array[Endianness, string] = ["littleEndian", "bigEndian"] CPU*: array[succ(low(TSystemCPU))..high(TSystemCPU), TInfoCPU] = [ (name: "i386", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "m68k", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), diff --git a/tests/arc/tfuncobj.nim b/tests/arc/tfuncobj.nim new file mode 100644 index 000000000..50cd9425e --- /dev/null +++ b/tests/arc/tfuncobj.nim @@ -0,0 +1,38 @@ +discard """ + outputsub: '''f1 +f2 +f3''' + cmd: "nim c --gc:orc $file" + valgrind: true +""" + +type + FuncObj = object + fn: proc (env: pointer) {.cdecl.} + env: pointer + +proc `=destroy`(x: var FuncObj) = + GC_unref(cast[RootRef](x.env)) + +proc `=copy`(x: var FuncObj, y: FuncObj) {.error.} + +# bug #18433 + +proc main = + var fs: seq[FuncObj] + + proc wrap(p: proc()) = + proc closeOver() = p() + let env = rawEnv closeOver + GC_ref(cast[RootRef](env)) + fs.add(FuncObj(fn: cast[proc(env: pointer){.cdecl.}](rawProc closeOver), env: env)) + + wrap(proc() {.closure.} = echo "f1") + wrap(proc() {.closure.} = echo "f2") + wrap(proc() {.closure.} = echo "f3") + + for a in fs: + a.fn(a.env) + +main() + From 12da32a891b08f34acbb676001f0c211ecfe1af8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 13 Jul 2021 14:17:59 +0200 Subject: [PATCH 2819/4254] fixes #17893 (#18485) * fixes #17893 --- compiler/liftdestructors.nim | 7 +--- tests/arc/tshared_ptr_crash.nim | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 tests/arc/tshared_ptr_crash.nim diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index b2b70edee..cc7e36cdb 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -416,12 +416,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = body.add destructorCall(c, op, x) result = true #result = addDestructorCall(c, t, body, x) - of attachedAsgn, attachedSink: - var op = getAttachedOp(c.g, t, c.kind) - result = considerAsgnOrSink(c, t, body, x, y, op) - if op != nil: - setAttachedOp(c.g, c.idgen.module, t, c.kind, op) - of attachedTrace: + of attachedAsgn, attachedSink, attachedTrace: var op = getAttachedOp(c.g, t, c.kind) if op != nil and sfOverriden in op.flags: if op.ast.isGenericRoutine: diff --git a/tests/arc/tshared_ptr_crash.nim b/tests/arc/tshared_ptr_crash.nim new file mode 100644 index 000000000..1794834db --- /dev/null +++ b/tests/arc/tshared_ptr_crash.nim @@ -0,0 +1,67 @@ +discard """ + cmd: "nim c --threads:on --gc:arc $file" + action: compile +""" + +# bug #17893 + +type + SharedPtr*[T] = object + val: ptr tuple[value: T, atomicCounter: int] + +proc `=destroy`*[T](p: var SharedPtr[T]) = + mixin `=destroy` + if p.val != nil: + if atomicLoadN(addr p.val[].atomicCounter, AtomicConsume) == 0: + `=destroy`(p.val[]) + deallocShared(p.val) + else: + discard atomicDec(p.val[].atomicCounter) + +proc `=copy`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) = + if src.val != nil: + discard atomicInc(src.val[].atomicCounter) + if dest.val != nil: + `=destroy`(dest) + dest.val = src.val + +proc newSharedPtr*[T](val: sink T): SharedPtr[T] {.nodestroy.} = + result.val = cast[typeof(result.val)](allocShared(sizeof(result.val[]))) + result.val.atomicCounter = 0 + result.val.value = val + +proc isNil*[T](p: SharedPtr[T]): bool {.inline.} = + p.val == nil + +proc `[]`*[T](p: SharedPtr[T]): var T {.inline.} = + when compileOption("boundChecks"): + doAssert(p.val != nil, "deferencing nil shared pointer") + result = p.val.value + +type + Sender*[T] = object + queue: SharedPtr[seq[T]] + +proc newSender*[T](queue: sink SharedPtr[seq[T]]): Sender[T] = + result = Sender[T](queue: queue) + +proc send*[T](self: Sender[T]; t: sink T) = + self.queue[].add t + +proc newChannel*(): Sender[int] = + let queue = newSharedPtr(newSeq[int]()) + result = newSender(queue) + + +var + p: Thread[Sender[int]] + +proc threadFn(tx: Sender[int]) = + send tx, 0 + +proc multiThreadedChannel = + let tx = newChannel() + createThread(p, threadFn, tx) + joinThread(p) + +multiThreadedChannel() From a6ff6e7871d757821ba2b84cb8f175f48721bb9a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Jul 2021 10:52:09 -0700 Subject: [PATCH 2820/4254] fix https://github.com/dom96/choosenim/issues/256 WSL CRLF (#18452) * fix https://github.com/dom96/choosenim/issues/256 WSL CRLF * fixup --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitattributes b/.gitattributes index 674da7939..2c9ff103c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,6 @@ # duplicated, which is easily identifiable and fixable. /changelog.md merge=union +# bug https://github.com/dom96/choosenim/issues/256 for WSL CRLF +*.sh text eol=lf +/config/build_config.txt text eol=lf From 8c6dd2b9a9157c0e0bd822d8a80d1014fc87ecd7 Mon Sep 17 00:00:00 2001 From: GordonBGood Date: Thu, 15 Jul 2021 19:35:53 +0700 Subject: [PATCH 2821/4254] Improve description of how =trace is used (#18491) * [skip ci] thamming_orc test created/destroyed counts match The thamming_orc.nim code now counts all created objects being tested, not just the ones following the "first 20" test, and the position of the `destroyed += 1` counter has been adjusted so it counts all the calls that are as a result of `=trace` tracing and not just the original destruction calls. * Improve description of how `=trace` is used The following nuances weren't previously fully explained: 1. That `=trace` is only used by `--gc:orc`. 2. That `=trace` is almost certainly used along with `=destroy` when manual resource allocation has been used, but it is only required if there is a possibility of cyclic references in the wrapped types (ie. generic types). 3. That, currently, a forward definition is required for the second of the pair to avoid an auto compiler generation conflict. The pattern of the use of `=trace` has also been made more extensive, showing how both a custom `=destroy` and `=trace` are used for manual allocation of resources when there is any possibility of a cyclic reference in the resource-wrapped values. * Update doc/destructors.rst Co-authored-by: Andreas Rumpf --- doc/destructors.rst | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index a94ccb9e7..a3fd7514e 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -222,16 +222,33 @@ The prototype of this hook for a type `T` needs to be: `env` is used by ORC to keep track of its internal state, it should be passed around to calls of the built-in `=trace` operation. -The general pattern in `=trace` looks like: +Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates manually allocated resources is also used, and then only when there is a chance of cyclic references from items within the manually allocated resources when it is desired that `--gc:orc` be able to break and collect these cyclic referenced resources. Currently however, there is a mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically create a version of the other which will then conflict with the creation of the second of the pair. The work around for this problem is to forward declare the second of the "hooks" to prevent the automatic creation. + +The general pattern in using `=destroy` with `=trace` looks like: .. code-block:: nim - proc `=trace`(dest: var T; env: pointer) = - for child in childrenThatCanContainPointers(dest): - `=trace`(child, env) + type + Test[T] = object + size: Natural + arr: ptr UncheckedArray[T] # raw pointer field + + proc makeTest[T](size: Natural): Test[T] = # custom allocation... + Test[T](size: size, arr: cast[ptr UncheckedArray[T]](alloc0(sizeof(T) * size))) -**Note**: The `=trace` hooks is currently more experimental and less refined + proc `=destroy`[T](dest: var Test[T]) = + if dest.arr != nil: + for i in 0 ..< dest.size: dest.arr[i].`=destroy` + dest.arr.dealloc + + proc `=trace`[T](dest: var Test[T]; env: pointer) = + if dest.arr != nil: # trace the `T`'s which may be cyclic + for i in 0 ..< dest.size: dest.arr[i].`=trace` env + + # following may be other custom "hooks" as required... + +**Note**: The `=trace` hooks (which are only used by `--gc:orc`) are currently more experimental and less refined than the other hooks. From af3d2d8ad90c31161c34f0d4f82cd0ac4a9b3d00 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 15 Jul 2021 17:58:47 +0200 Subject: [PATCH 2822/4254] added `nimAllocPagesViaMalloc` switch (#18490) * added switch * alloc.nim needs page aligned memory blocks --- changelog.md | 3 +++ doc/nimc.rst | 14 +++++++++++++- lib/system/alloc.nim | 3 ++- lib/system/osalloc.nim | 31 +++++++++++++++++++++++++++---- tests/arc/tarcmisc.nim | 2 +- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index bc64e9579..d44f28b94 100644 --- a/changelog.md +++ b/changelog.md @@ -391,6 +391,9 @@ - The `gc:orc` algorithm was refined so that custom container types can participate in the cycle collection process. +- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. + This is only supported for `--gc:orc` or `--gc:arc`. + ## Compiler changes diff --git a/doc/nimc.rst b/doc/nimc.rst index 2b9f33cb5..070956860 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -176,7 +176,7 @@ directories (in this order; later files overwrite previous settings): ``%APPDATA%/nim/nim.cfg`` (Windows). This file can be skipped with the `--skipUserCfg`:option: command line option. -3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent +3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the `--skipParentCfg`:option: command-line option. @@ -634,6 +634,18 @@ optimization in the compiler and linker. Check the `Cross-compilation`_ section for instructions on how to compile the program for your target. + +nimAllocPagesViaMalloc +---------------------- + +Nim's default allocator is based on TLSF, this algorithm was designed for embedded +devices. This allocator gets blocks/pages of memory via a currently undocumented +`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap` +is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc` +define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently +only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6) + + Nim for realtime systems ======================== diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index c598b8250..479458950 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -749,8 +749,9 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = inc(a.allocCounter) sysAssert(allocInv(a), "rawAlloc: begin") sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") - sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small") var size = roundup(requestedSize, MemAlign) + sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small") + sysAssert(size >= requestedSize, "insufficient allocated size!") #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size) if size <= SmallChunkSize-smallChunkOverhead(): diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 32d3b166d..2830adb48 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -28,7 +28,30 @@ const doNotUnmap = not (defined(amd64) or defined(i386)) or defined(windows) or defined(nimAllocNoUnmap) -when defined(emscripten) and not defined(StandaloneHeapSize): +when defined(nimAllocPagesViaMalloc): + when not defined(gcArc) and not defined(gcOrc): + {.error: "-d:nimAllocPagesViaMalloc is only supported with --gc:arc or --gc:orc".} + + proc osTryAllocPages(size: int): pointer {.inline.} = + let base = c_malloc(csize_t size + PageSize - 1 + sizeof(uint32)) + if base == nil: raiseOutOfMem() + # memory layout: padding + offset (4 bytes) + user_data + # in order to deallocate: read offset at user_data - 4 bytes, + # then deallocate user_data - offset + let offset = PageSize - (cast[int](base) and (PageSize - 1)) + cast[ptr uint32](base +! (offset - sizeof(uint32)))[] = uint32(offset) + result = base +! offset + + proc osAllocPages(size: int): pointer {.inline.} = + result = osTryAllocPages(size) + if result == nil: raiseOutOfMem() + + proc osDeallocPages(p: pointer, size: int) {.inline.} = + # read offset at p - 4 bytes, then deallocate (p - offset) pointer + let offset = cast[ptr uint32](p -! sizeof(uint32))[] + c_free(p -! offset) + +elif defined(emscripten) and not defined(StandaloneHeapSize): const PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written @@ -197,11 +220,11 @@ elif defined(posix) and not defined(StandaloneHeapSize): PROT_WRITE = 2 # page can be written when defined(netbsd) or defined(openbsd): - # OpenBSD security for setjmp/longjmp coroutines - var MAP_STACK {.importc: "MAP_STACK", header: "".}: cint + # OpenBSD security for setjmp/longjmp coroutines + var MAP_STACK {.importc: "MAP_STACK", header: "".}: cint else: const MAP_STACK = 0 # avoid sideeffects - + when defined(macosx) or defined(freebsd): const MAP_ANONYMOUS = 0x1000 const MAP_PRIVATE = 0x02 # Changes are private diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 5d5d8e914..7daea62c8 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -34,7 +34,7 @@ closed destroying variable: 20 destroying variable: 10 ''' - cmd: "nim c --gc:arc --deepcopy:on $file" + cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file" """ proc takeSink(x: sink string): bool = true From a9701f6531288ab3ba2c2a7ff0124802ae78122c Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Thu, 15 Jul 2021 14:43:57 -0400 Subject: [PATCH 2823/4254] Extended side effect error messages (#18418) * Extended side effect error messages * Applied feedback: - refactored `markSideEffect` - refactored string interpolations - single message - skip diagnostics in `system.compiles` context Other: - started a test of diagnostic messages [ci skip] Tests aren't updated yet because messaging isn't nailed down. * - Added hints of where for side effect call locations. - Tried to clarify the reasons. * fix tests * Applied PR review feedback: - moved collection of side effects from TSym to TContext - used pragma shorthand form `.sideEffect` and `.noSideEffect` in messages - added leading '>' to structured messages for readability - changed `sempass2.markSideEffect` to a proc - replaced `system.echo` in the test to make the test compatible with Windows * Applied NEP1 formatting suggestion Co-authored-by: quantimnot --- compiler/semdata.nim | 1 + compiler/sempass2.nim | 74 ++++++++++++++++++++------ tests/effects/tdiagnostic_messages.nim | 37 +++++++++++++ 3 files changed, 95 insertions(+), 17 deletions(-) create mode 100644 tests/effects/tdiagnostic_messages.nim diff --git a/compiler/semdata.nim b/compiler/semdata.nim index bd863505c..12bb22ff9 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -159,6 +159,7 @@ type exportIndirections*: HashSet[(int, int)] # (module.id, symbol.id) importModuleMap*: Table[int, int] # (module.id, module.id) lastTLineInfo*: TLineInfo + sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index template config*(c: PContext): ConfigRef = c.graph.config diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e124baf26..1e1672cad 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling + modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables when defined(useDfa): import dfa @@ -223,13 +223,21 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, nextSymId a.c.idgen, a.owner, reason.info, {}) -when true: - template markSideEffect(a: PEffects; reason: typed) = - if not a.inEnforcedNoSideEffects: a.hasSideEffect = true -else: - template markSideEffect(a: PEffects; reason: typed) = - if not a.inEnforcedNoSideEffects: a.hasSideEffect = true - markGcUnsafe(a, reason) +proc markSideEffect(a: PEffects; reason: PNode | PSym; useLoc: TLineInfo) = + if not a.inEnforcedNoSideEffects: + a.hasSideEffect = true + if a.owner.kind in routineKinds: + var sym: PSym + when reason is PNode: + if reason.kind == nkSym: + sym = reason.sym + else: + let kind = if reason.kind == nkHiddenDeref: skParam else: skUnknown + sym = newSym(kind, a.owner.name, nextSymId a.c.idgen, a.owner, reason.info, {}) + else: + sym = reason + a.c.sideEffects.mgetOrPut(a.owner.id, @[]).add (useLoc, sym) + when false: markGcUnsafe(a, reason) proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) = let u = s.gcUnsafetyReason @@ -259,6 +267,31 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) = var cycleCheck = initIntSet() listGcUnsafety(s, onlyWarning, cycleCheck, conf) +proc listSideEffects(result: var string; s: PSym; cycleCheck: var IntSet; + conf: ConfigRef; context: PContext; indentLevel: int) = + template addHint(msg; lineInfo; sym; level = indentLevel) = + result.addf("$# $# Hint: '$#' $#\n", repeat(">", level), conf $ lineInfo, sym, msg) + if context.sideEffects.hasKey(s.id): + for (useLineInfo, u) in context.sideEffects[s.id]: + if u != nil and not cycleCheck.containsOrIncl(u.id): + case u.kind + of skLet, skVar: + addHint("accesses global state '$#'" % u.name.s, useLineInfo, s.name.s) + addHint("accessed by '$#'" % s.name.s, u.info, u.name.s, indentLevel + 1) + of routineKinds: + addHint("calls `.sideEffect` '$#'" % u.name.s, useLineInfo, s.name.s) + addHint("called by '$#'" % s.name.s, u.info, u.name.s, indentLevel + 1) + listSideEffects(result, u, cycleCheck, conf, context, indentLevel + 2) + of skParam, skForVar: + addHint("calls routine via hidden pointer indirection", useLineInfo, s.name.s) + else: + addHint("calls routine via pointer indirection", useLineInfo, s.name.s) + +proc listSideEffects(result: var string; s: PSym; conf: ConfigRef; context: PContext) = + var cycleCheck = initIntSet() + result.addf("'$#' can have side effects\n", s.name.s) + listSideEffects(result, s, cycleCheck, conf, context, 1) + proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) = if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and s.magic != mNimvm: @@ -267,9 +300,7 @@ proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) = (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n) markGcUnsafe(a, s) - markSideEffect(a, s) - else: - markSideEffect(a, s) + markSideEffect(a, s, n.info) if s.owner != a.owner and s.kind in {skVar, skLet, skForVar, skResult, skParam} and {sfGlobal, sfThread} * s.flags == {}: a.isInnerProc = true @@ -502,7 +533,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, s) if tfNoSideEffect notin s.typ.flags: - markSideEffect(tracked, s) + markSideEffect(tracked, s, n.info) mergeLockLevels(tracked, n, s.getLockLevel) proc procVarCheck(n: PNode; conf: ConfigRef) = @@ -584,7 +615,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner): - markSideEffect(tracked, a) + markSideEffect(tracked, a, n.info) else: mergeRaises(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) @@ -592,7 +623,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags: - markSideEffect(tracked, a) + markSideEffect(tracked, a, n.info) if paramType != nil and paramType.kind in {tyVar}: invalidateFacts(tracked.guards, n) if n.kind == nkSym and isLocalVar(tracked, n.sym): @@ -749,7 +780,7 @@ proc trackCall(tracked: PEffects; n: PNode) = if tfNoSideEffect notin op.flags and not importedFromC(a): # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): - markSideEffect(tracked, a) + markSideEffect(tracked, a, n.info) # p's effects are ours too: var a = n[0] @@ -771,7 +802,7 @@ proc trackCall(tracked: PEffects; n: PNode) = if a.sym == tracked.owner: tracked.isRecursive = true # even for recursive calls we need to check the lock levels (!): mergeLockLevels(tracked, n, a.sym.getLockLevel) - if sfSideEffect in a.sym.flags: markSideEffect(tracked, a) + if sfSideEffect in a.sym.flags: markSideEffect(tracked, a, n.info) else: mergeLockLevels(tracked, n, op.lockLevel) var effectList = op.n[0] @@ -1336,6 +1367,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = effects[ensuresEffects] = ensuresSpec var mutationInfo = MutationInfo() + var hasMutationSideEffect = false if {strictFuncs, views} * c.features != {}: var goals: set[Goal] = {} if strictFuncs in c.features: goals.incl constParameters @@ -1343,6 +1375,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = var partitions = computeGraphPartitions(s, body, g, goals) if not t.hasSideEffect and t.hasDangerousAssign: t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) + hasMutationSideEffect = t.hasSideEffect if views in c.features: checkBorrowedLocations(partitions, body, g.config) @@ -1357,7 +1390,14 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = when false: listGcUnsafety(s, onlyWarning=false, g.config) else: - localError(g.config, s.info, ("'$1' can have side effects" % s.name.s) & (g.config $ mutationInfo)) + if hasMutationSideEffect: + localError(g.config, s.info, "'$1' can have side effects$2" % [s.name.s, g.config $ mutationInfo]) + elif c.compilesContextId == 0: # don't render extended diagnostic messages in `system.compiles` context + var msg = "" + listSideEffects(msg, s, g.config, t.c) + message(g.config, s.info, errGenerated, msg) + else: + localError(g.config, s.info, "") # simple error for `system.compiles` context if not t.gcUnsafe: s.typ.flags.incl tfGcSafe if not t.hasSideEffect and sfSideEffect notin s.flags: diff --git a/tests/effects/tdiagnostic_messages.nim b/tests/effects/tdiagnostic_messages.nim new file mode 100644 index 000000000..2ce4895a3 --- /dev/null +++ b/tests/effects/tdiagnostic_messages.nim @@ -0,0 +1,37 @@ +discard """ + nimoutFull: true + action: "reject" + cmd: "nim r --hint:Conf:off $file" + nimout: ''' +tdiagnostic_messages.nim(36, 6) Error: 'a' can have side effects +> tdiagnostic_messages.nim(37, 30) Hint: 'a' calls `.sideEffect` 'callWithSideEffects' +>> tdiagnostic_messages.nim(29, 6) Hint: 'callWithSideEffects' called by 'a' +>>> tdiagnostic_messages.nim(31, 34) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaVarParam' +>>>> tdiagnostic_messages.nim(25, 6) Hint: 'indirectCallViaVarParam' called by 'callWithSideEffects' +>>>>> tdiagnostic_messages.nim(26, 7) Hint: 'indirectCallViaVarParam' calls routine via hidden pointer indirection +>>> tdiagnostic_messages.nim(32, 33) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaPointer' +>>>> tdiagnostic_messages.nim(27, 6) Hint: 'indirectCallViaPointer' called by 'callWithSideEffects' +>>>>> tdiagnostic_messages.nim(28, 32) Hint: 'indirectCallViaPointer' calls routine via pointer indirection +>>> tdiagnostic_messages.nim(33, 10) Hint: 'callWithSideEffects' calls `.sideEffect` 'myEcho' +>>>> tdiagnostic_messages.nim(24, 6) Hint: 'myEcho' called by 'callWithSideEffects' +>>> tdiagnostic_messages.nim(34, 3) Hint: 'callWithSideEffects' accesses global state 'globalVar' +>>>> tdiagnostic_messages.nim(23, 5) Hint: 'globalVar' accessed by 'callWithSideEffects' + +''' +""" + +var globalVar = 0 +proc myEcho(a: string) {.sideEffect.} = discard +proc indirectCallViaVarParam(call: var proc(): int {.nimcall.}): int = + call() +proc indirectCallViaPointer(call: pointer): int = + cast[ptr proc(): int](call)[]() +proc callWithSideEffects(): int = + var p = proc (): int {.nimcall.} = 0 + discard indirectCallViaVarParam(p) + discard indirectCallViaPointer(addr p) + myEcho "" + globalVar + +func a: int = + discard callWithSideEffects() From 1d6863a7899fd87fd9eb017ae370ef37db18ad32 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Jul 2021 11:54:07 -0700 Subject: [PATCH 2824/4254] deprecate `sequtils.delete` and add an overload with saner semantics consistent with `system.delete` (#18487) * deprecate sequtils.delete and add an overload with saner semantics * AssertionDefect => IndexDefect * improve tsequtils * add tests; use splice in js for optimization --- changelog.md | 3 + lib/pure/collections/sequtils.nim | 45 +++++++++- tests/stdlib/tsequtils.nim | 144 ++++++++++++++++++++---------- 3 files changed, 144 insertions(+), 48 deletions(-) diff --git a/changelog.md b/changelog.md index d44f28b94..d07ddddb4 100644 --- a/changelog.md +++ b/changelog.md @@ -346,6 +346,9 @@ - Added `dom.setInterval`, `dom.clearInterval` overloads. +- Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect + if the slice is out of bounds. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 6facfcc32..5b41ea00d 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -509,12 +509,51 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) inc(pos) setLen(s, pos) -func delete*[T](s: var seq[T]; first, last: Natural) = +func delete*[T](s: var seq[T]; slice: Slice[int]) = + ## Deletes the items `s[slice]`, raising `IndexDefect` if the slice contains + ## elements out of range. + ## + ## This operation moves all elements after `s[slice]` in linear time. + runnableExamples: + var a = @[10, 11, 12, 13, 14] + doAssertRaises(IndexDefect): a.delete(4..5) + assert a == @[10, 11, 12, 13, 14] + a.delete(4..4) + assert a == @[10, 11, 12, 13] + a.delete(1..2) + assert a == @[10, 13] + a.delete(1..<1) # empty slice + assert a == @[10, 13] + when compileOption("boundChecks"): + if not (slice.a < s.len and slice.a >= 0 and slice.b < s.len): + raise newException(IndexDefect, $(slice: slice, len: s.len)) + if slice.b >= slice.a: + template defaultImpl = + var i = slice.a + var j = slice.b + 1 + var newLen = s.len - j + i + while i < newLen: + when defined(gcDestructors): + s[i] = move(s[j]) + else: + s[i].shallowCopy(s[j]) + inc(i) + inc(j) + setLen(s, newLen) + when nimvm: defaultImpl() + else: + when defined(js): + let n = slice.b - slice.a + 1 + let first = slice.a + {.emit: "`s`.splice(`first`, `n`);".} + else: + defaultImpl() + +func delete*[T](s: var seq[T]; first, last: Natural) {.deprecated: "use `delete(s, first..last)`".} = ## Deletes the items of a sequence `s` at positions `first..last` ## (including both ends of the range). ## This modifies `s` itself, it does not return a copy. - ## - runnableExamples: + runnableExamples("--warning:deprecated:off"): let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] dest.delete(3, 8) diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index 385e6e651..6c9c92873 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -1,3 +1,9 @@ +discard """ + targets: "c js" +""" + +# xxx move all tests under `main` + import std/sequtils import strutils from algorithm import sorted @@ -190,17 +196,6 @@ block: # keepIf test keepIf(floats, proc(x: float): bool = x > 10) doAssert floats == @[13.0, 12.5, 10.1] -block: # delete tests - let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] - var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] - dest.delete(3, 8) - doAssert outcome == dest, """\ - Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] - is [1,1,1,1,1,1,1,1]""" - var x = @[1, 2, 3] - x.delete(100, 100) - doAssert x == @[1, 2, 3] - block: # insert tests var dest = @[1, 1, 1, 1, 1, 1, 1, 1] let @@ -298,43 +293,45 @@ block: # toSeq test doAssert myIter.toSeq == @[1, 2] doAssert toSeq(myIter) == @[1, 2] - block: - iterator myIter(): int {.closure.} = - yield 1 - yield 2 + when not defined(js): + # pending #4695 + block: + iterator myIter(): int {.closure.} = + yield 1 + yield 2 - doAssert myIter.toSeq == @[1, 2] - doAssert toSeq(myIter) == @[1, 2] - - block: - proc myIter(): auto = - iterator ret(): int {.closure.} = - yield 1 - yield 2 - result = ret - - doAssert myIter().toSeq == @[1, 2] - doAssert toSeq(myIter()) == @[1, 2] - - block: - proc myIter(n: int): auto = - var counter = 0 - iterator ret(): int {.closure.} = - while counter < n: - yield counter - counter.inc - result = ret + doAssert myIter.toSeq == @[1, 2] + doAssert toSeq(myIter) == @[1, 2] block: - let myIter3 = myIter(3) - doAssert myIter3.toSeq == @[0, 1, 2] + proc myIter(): auto = + iterator ret(): int {.closure.} = + yield 1 + yield 2 + result = ret + + doAssert myIter().toSeq == @[1, 2] + doAssert toSeq(myIter()) == @[1, 2] + block: - let myIter3 = myIter(3) - doAssert toSeq(myIter3) == @[0, 1, 2] - block: - # makes sure this does not hang forever - doAssert myIter(3).toSeq == @[0, 1, 2] - doAssert toSeq(myIter(3)) == @[0, 1, 2] + proc myIter(n: int): auto = + var counter = 0 + iterator ret(): int {.closure.} = + while counter < n: + yield counter + counter.inc + result = ret + + block: + let myIter3 = myIter(3) + doAssert myIter3.toSeq == @[0, 1, 2] + block: + let myIter3 = myIter(3) + doAssert toSeq(myIter3) == @[0, 1, 2] + block: + # makes sure this does not hang forever + doAssert myIter(3).toSeq == @[0, 1, 2] + doAssert toSeq(myIter(3)) == @[0, 1, 2] block: # tests https://github.com/nim-lang/Nim/issues/7187 @@ -452,4 +449,61 @@ block: for i in 0.. Date: Thu, 15 Jul 2021 23:13:01 +0300 Subject: [PATCH 2825/4254] Add changes required by Nimble lock file support (#12104) Implemented support for Nimble local cache with package directories with a checksum of the package at the end of their names. Now the compiler supports package paths in the form: * /path_to_nimble_cache_dir/pkgs/package_name-1.2.3- FEBADEAEA2345E777F0F6F8433F7F0A52EDD5D1B * /path_to_nimble_cache_dir/pkgs/package_name-#head- 042D4BE2B90ED0672E717D71850ABDB0A2D19CD2 * /path_to_nimble_cache_dir/pkgs/package_name-#branch-name- DBC1F902CB79946E990E38AF51F0BAD36ACFABD9 Related to nim-lang/nimble#127 --- compiler/modulepaths.nim | 2 +- compiler/nimblecmd.nim | 78 +++++++++++++++++++----------- lib/std/sha1.nim | 4 ++ tests/compiler/tnimblecmd.nim | 91 +++++++++++++++++++++++++++-------- tests/stdlib/tsha1.nim | 10 ++++ 5 files changed, 135 insertions(+), 50 deletions(-) diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 8511b1592..a16b669c4 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -21,7 +21,7 @@ when false: for k, p in os.walkDir(dir, relative=true): if k == pcDir and p.len > pkg.len+1 and p[pkg.len] == '-' and p.startsWith(pkg): - let (_, a) = getPathVersion(p) + let (_, a, _) = getPathVersionChecksum(p) if bestv.len == 0 or bestv < a: bestv = a best = dir / p diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 28398289c..9cd2941ba 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -9,8 +9,8 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. -import parseutils, strutils, strtabs, os, options, msgs, sequtils, - lineinfos, pathutils +import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils, + std/sha1, tables proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) = if not conf.searchPaths.contains(path): @@ -18,6 +18,7 @@ proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) = type Version* = distinct string + PackageInfo = Table[string, tuple[version, checksum: string]] proc `$`*(ver: Version): string {.borrow.} @@ -62,43 +63,64 @@ proc `<`*(ver: Version, ver2: Version): bool = else: return false -proc getPathVersion*(p: string): tuple[name, version: string] = - ## Splits path ``p`` in the format ``/home/user/.nimble/pkgs/package-0.1`` - ## into ``(/home/user/.nimble/pkgs/package, 0.1)`` - result.name = "" - result.version = "" +proc getPathVersionChecksum*(p: string): tuple[name, version, checksum: string] = + ## Splits path ``p`` in the format + ## ``/home/user/.nimble/pkgs/package-0.1-febadeaea2345e777f0f6f8433f7f0a52edd5d1b`` into + ## ``("/home/user/.nimble/pkgs/package", "0.1", "febadeaea2345e777f0f6f8433f7f0a52edd5d1b")`` - const specialSeparator = "-#" - let last = p.rfind(p.lastPathPart) # the index where the last path part begins - var sepIdx = p.find(specialSeparator, start = last) - if sepIdx == -1: - sepIdx = p.rfind('-', start = last) + const checksumSeparator = '-' + const versionSeparator = '-' + const specialVersionSepartator = "-#" + const separatorNotFound = -1 - if sepIdx == -1: - result.name = p - return + var checksumSeparatorIndex = p.rfind(checksumSeparator) + if checksumSeparatorIndex != separatorNotFound: + result.checksum = p.substr(checksumSeparatorIndex + 1) + if not result.checksum.isValidSha1Hash(): + result.checksum = "" + checksumSeparatorIndex = p.len() + else: + checksumSeparatorIndex = p.len() - for i in sepIdx.. Date: Fri, 16 Jul 2021 07:42:35 +0200 Subject: [PATCH 2826/4254] added Atlas helper tool (#18497) * added Atlas helper tool * further improvements --- koch.nim | 8 +- tools/atlas/atlas.md | 77 +++++++ tools/atlas/atlas.nim | 390 +++++++++++++++++++++++++++++++++ tools/atlas/osutils.nim | 59 +++++ tools/atlas/packagesjson.nim | 117 ++++++++++ tools/atlas/parse_requires.nim | 101 +++++++++ 6 files changed, 751 insertions(+), 1 deletion(-) create mode 100644 tools/atlas/atlas.md create mode 100644 tools/atlas/atlas.nim create mode 100644 tools/atlas/osutils.nim create mode 100644 tools/atlas/packagesjson.nim create mode 100644 tools/atlas/parse_requires.nim diff --git a/koch.nim b/koch.nim index 4ba0d0eb5..da7576e65 100644 --- a/koch.nim +++ b/koch.nim @@ -222,7 +222,13 @@ proc buildTools(args: string = "") = # `-d:nimDebugUtils` only makes sense when temporarily editing/debugging compiler # `-d:debug` should be changed to a flag that doesn't require re-compiling nim # `--opt:speed` is a sensible default even for a debug build, it doesn't affect nim stacktraces - nimCompileFold("Compile nim_dbg", "compiler/nim.nim", options = "--opt:speed --stacktrace -d:debug --stacktraceMsgs -d:nimCompilerStacktraceHints " & args, outputName = "nim_dbg") + nimCompileFold("Compile nim_dbg", "compiler/nim.nim", options = + "--opt:speed --stacktrace -d:debug --stacktraceMsgs -d:nimCompilerStacktraceHints " & args, + outputName = "nim_dbg") + + nimCompileFold("Compile atlas", "tools/atlas/atlas.nim", options = "-d:release " & args, + outputName = "atlas") + proc nsis(latest: bool; args: string) = bundleNimbleExe(latest, args) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md new file mode 100644 index 000000000..a36817dc5 --- /dev/null +++ b/tools/atlas/atlas.md @@ -0,0 +1,77 @@ +# Atlas Package Cloner + +Atlas is a simple package cloner tool that automates some of the +workflows and needs for Nim's stdlib evolution. + +Atlas is compatible with Nimble in the sense that it supports the Nimble +file format. + + +## How it works + +Atlas uses git commits internally; version requirements are translated +to git commits via `git show-ref --tags`. + +Atlas uses URLs internally; Nimble package names are translated to URLs +via Nimble's `packages.json` file. + +Atlas does not call the Nim compiler for a build, instead it creates/patches +a `nim.cfg` file for the compiler. For example: + +``` +############# begin Atlas config section ########## +--noNimblePath +--path:"../nimx" +--path:"../sdl2/src" +--path:"../opengl/src" +############# end Atlas config section ########## +``` + +The version selection is deterministic, it picks up the *minimum* required +version. Thanks to this design, lock files are not required. + + +## Dependencies + +Dependencies are neither installed globally, nor locally into the current +project. Instead a "workspace" is used. The workspace is the nearest parent +directory of the current directory that does not contain a `.git` subdirectory. +Dependencies are managed as **siblings**, not as children. Dependencies are +kept as git repositories. + +Thanks to this setup, it's easy to develop multiple projects at the same time. + +A project plus its dependencies are stored in a workspace: + + $workspace / main project + $workspace / dependency A + $workspace / dependency B + + +No attempts are being made at keeping directory hygiene inside the +workspace, you're supposed to create appropriate `$workspace` directories +at your own leisure. + + +## Commands + +Atlas supports the following commands: + + +### Clone + +Clones a URL and all of its dependencies (recursively) into the workspace. +Creates or patches a `nim.cfg` file with the required `--path` entries. + + +### Clone + +The `` is translated into an URL via `packages.json` and +then `clone ` is performed. + + +### Search + +Search the package index `packages.json` for a package that the given terms +in its description (or name or list of tags). + diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim new file mode 100644 index 000000000..bc1cc6ae3 --- /dev/null +++ b/tools/atlas/atlas.nim @@ -0,0 +1,390 @@ +# +# Atlas Package Cloner +# (c) Copyright 2021 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Simple tool to automate frequent workflows: Can "clone" +## a Nimble dependency and its dependencies recursively. + +import std/[parseopt, strutils, os, osproc, sequtils, unicode, tables, sets] +import parse_requires, osutils, packagesjson + +const + Version = "0.1" + Usage = "atlas - Nim Package Manager Version " & Version & """ + + (c) 2021 Andreas Rumpf +Usage: + atlas [options] [command] [arguments] +Command: + clone url|pkgname clone a package and all of its dependencies + search keyw keywB... search for package that contains the given keywords + +Options: + --keepCommits do not perform any `git checkouts` + --version show the version + --help show this help +""" + +proc writeHelp() = + stdout.write(Usage) + stdout.flushFile() + quit(0) + +proc writeVersion() = + stdout.write(Version & "\n") + stdout.flushFile() + quit(0) + +type + PackageName = distinct string + DepRelation = enum + normal, strictlyLess, strictlyGreater + + Dependency = object + name: PackageName + url, commit: string + rel: DepRelation # "requires x < 1.0" is silly, but Nimble allows it so we have too. + AtlasContext = object + projectDir, workspace: string + hasPackageList: bool + keepCommits: bool + p: Table[string, string] # name -> url mapping + processed: HashSet[string] # the key is (url / commit) + errors: int + +const + InvalidCommit = "" + +proc toDepRelation(s: string): DepRelation = + case s + of "<": strictlyLess + of ">": strictlyGreater + else: normal + +proc isCleanGit(dir: string): string = + result = "" + let (outp, status) = osproc.execCmdEx("git diff") + if outp.len != 0: + result = "'git diff' not empty" + elif status != 0: + result = "'git diff' returned non-zero" + +proc message(c: var AtlasContext; category: string; p: PackageName; args: varargs[string]) = + var msg = category & "(" & p.string & ")" + for a in args: + msg.add ' ' + msg.add a + stdout.writeLine msg + inc c.errors + +proc warn(c: var AtlasContext; p: PackageName; args: varargs[string]) = + message(c, "[Warning] ", p, args) + +proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = + message(c, "[Error] ", p, args) + +proc sameVersionAs(tag, ver: string): bool = + const VersionChars = {'0'..'9', '.'} + + proc safeCharAt(s: string; i: int): char {.inline.} = + if i >= 0 and i < s.len: s[i] else: '\0' + + let idx = find(tag, ver) + if idx >= 0: + # we found the version as a substring inside the `tag`. But we + # need to watch out the the boundaries are not part of a + # larger/different version number: + result = safeCharAt(tag, idx-1) notin VersionChars and + safeCharAt(tag, idx+ver.len) notin VersionChars + +proc versionToCommit(d: Dependency): string = + let (outp, status) = osproc.execCmdEx("git show-ref --tags") + if status == 0: + var useNextOne = false + for line in splitLines(outp): + let commitsAndTags = strutils.splitWhitespace(line) + if commitsAndTags.len == 2: + case d.rel + of normal: + if commitsAndTags[1].sameVersionAs(d.commit): + return commitsAndTags[0] + of strictlyLess: + if d.commit == InvalidCommit or not commitsAndTags[1].sameVersionAs(d.commit): + return commitsAndTags[0] + of strictlyGreater: + if commitsAndTags[1].sameVersionAs(d.commit): + useNextOne = true + elif useNextOne: + return commitsAndTags[0] + + return "" + +proc checkoutGitCommit(c: var AtlasContext; p: PackageName; commit: string) = + let (outp, status) = osproc.execCmdEx("git checkout " & quoteShell(commit)) + if status != 0: + error(c, p, "could not checkout commit", commit) + +proc gitPull(c: var AtlasContext; p: PackageName) = + let (_, status) = osproc.execCmdEx("git pull") + if status != 0: + error(c, p, "could not 'git pull'") + +proc updatePackages(c: var AtlasContext) = + if dirExists(c.workspace / PackagesDir): + withDir(c.workspace / PackagesDir): + gitPull(c, PackageName PackagesDir) + else: + withDir c.workspace: + let err = cloneUrl("https://github.com/nim-lang/packages", PackagesDir, false) + if err != "": + error c, PackageName(PackagesDir), err + +proc fillPackageLookupTable(c: var AtlasContext) = + if not c.hasPackageList: + c.hasPackageList = true + updatePackages(c) + let plist = getPackages(c.workspace) + for entry in plist: + c.p[unicode.toLower entry.name] = entry.url + +proc toUrl(c: var AtlasContext; p: string): string = + if p.isUrl: + result = p + else: + fillPackageLookupTable(c) + result = c.p.getOrDefault(unicode.toLower p) + if result.len == 0: + inc c.errors + +proc toName(p: string): PackageName = + if p.isUrl: + result = PackageName splitFile(p).name + else: + result = PackageName p + +proc needsCommitLookup(commit: string): bool {.inline} = + '.' in commit or commit == InvalidCommit + +proc checkoutCommit(c: var AtlasContext; w: Dependency) = + let dir = c.workspace / w.name.string + withDir dir: + if w.commit.len == 0 or cmpIgnoreCase(w.commit, "#head") == 0: + gitPull(c, w.name) + else: + let err = isCleanGit(dir) + if err != "": + warn c, w.name, err + else: + let requiredCommit = if needsCommitLookup(w.commit): versionToCommit(w) else: w.commit + let (cc, status) = osproc.execCmdEx("git log -n 1 --format=%H") + let currentCommit = strutils.strip(cc) + if requiredCommit == "" or status != 0: + if requiredCommit == "" and w.commit == InvalidCommit: + warn c, w.name, "package has no tagged releases" + else: + warn c, w.name, "cannot find specified version/commit", w.commit + else: + if currentCommit != requiredCommit: + # checkout the later commit: + # git merge-base --is-ancestor + let (mergeBase, status) = osproc.execCmdEx("git merge-base " & + currentCommit.quoteShell & " " & requiredCommit.quoteShell) + if status == 0 and (mergeBase == currentCommit or mergeBase == requiredCommit): + # conflict resolution: pick the later commit: + if mergeBase == currentCommit: + checkoutGitCommit(c, w.name, requiredCommit) + else: + checkoutGitCommit(c, w.name, requiredCommit) + when false: + warn c, w.name, "do not know which commit is more recent:", + currentCommit, "(current) or", w.commit, " =", requiredCommit, "(required)" + +proc findNimbleFile(c: AtlasContext; dep: Dependency): string = + result = c.workspace / dep.name.string / (dep.name.string & ".nimble") + if not fileExists(result): + result = "" + for x in walkFiles(c.workspace / dep.name.string / "*.nimble"): + if result.len == 0: + result = x + else: + # ambiguous .nimble file + return "" + +proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency]; + tokens: seq[string]) = + let oldErrors = c.errors + let url = toUrl(c, tokens[0]) + if oldErrors != c.errors: + warn c, toName(tokens[0]), "cannot resolve package name" + elif not c.processed.containsOrIncl(url / tokens[2]): + work.add Dependency(name: toName(tokens[0]), url: url, commit: tokens[2], + rel: toDepRelation(tokens[1])) + +proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; + dep: Dependency; result: var seq[string]; + isMainProject: bool) = + let nimbleFile = findNimbleFile(c, dep) + if nimbleFile != "": + let nimbleInfo = extractRequiresInfo(nimbleFile) + for r in nimbleInfo.requires: + var tokens: seq[string] = @[] + for token in tokenizeRequires(r): + tokens.add token + if tokens.len == 1: + # nimx uses dependencies like 'requires "sdl2"'. + # Via this hack we map them to the first tagged release. + # (See the `isStrictlySmallerThan` logic.) + tokens.add "<" + tokens.add InvalidCommit + elif tokens.len == 2 and tokens[1].startsWith("#"): + # Dependencies can also look like 'requires "sdl2#head" + var commit = tokens[1] + tokens[1] = "==" + tokens.add commit + + if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0: + c.addUniqueDep work, tokens + + result.add dep.name.string / nimbleInfo.srcDir + else: + result.add dep.name.string + +proc clone(c: var AtlasContext; start: string): seq[string] = + # non-recursive clone. + let oldErrors = c.errors + var work = @[Dependency(name: toName(start), url: toUrl(c, start), commit: "")] + + if oldErrors != c.errors: + error c, toName(start), "cannot resolve package name" + return + + c.projectDir = work[0].name.string + result = @[] + var i = 0 + while i < work.len: + let w = work[i] + let oldErrors = c.errors + if not dirExists(c.workspace / w.name.string): + withDir c.workspace: + let err = cloneUrl(w.url, w.name.string, false) + if err != "": + error c, w.name, err + if oldErrors == c.errors: + if not c.keepCommits: checkoutCommit(c, w) + # even if the checkout fails, we can make use of the somewhat + # outdated .nimble file to clone more of the most likely still relevant + # dependencies: + collectNewDeps(c, work, w, result, i == 0) + inc i + +const + configPatternBegin = "############# begin Atlas config section ##########\n" + configPatternEnd = "############# end Atlas config section ##########\n" + +proc patchNimCfg(c: AtlasContext; deps: seq[string]) = + var paths = "--noNimblePath\n" + for d in deps: + paths.add "--path:\"../" & d.replace("\\", "/") & "\"\n" + + let cfg = c.projectDir / "nim.cfg" + var cfgContent = configPatternBegin & paths & configPatternEnd + if not fileExists(cfg): + writeFile(cfg, cfgContent) + else: + let content = readFile(cfg) + let start = content.find(configPatternBegin) + if start >= 0: + cfgContent = content.substr(0, start-1) & cfgContent + let theEnd = content.find(configPatternEnd, start) + if theEnd >= 0: + cfgContent.add content.substr(theEnd+len(configPatternEnd)) + else: + cfgContent = content & "\n" & cfgContent + if cfgContent != content: + # do not touch the file if nothing changed + # (preserves the file date information): + writeFile(cfg, cfgContent) + +proc error*(msg: string) = + when defined(debug): + writeStackTrace() + quit "[Error] " & msg + +proc main = + var action = "" + var args: seq[string] = @[] + template singleArg() = + if args.len != 1: + error action & " command takes a single package name" + + template noArgs() = + if args.len != 0: + error action & " command takes no arguments" + + var c = AtlasContext( + projectDir: getCurrentDir(), + workspace: getCurrentDir()) + + for kind, key, val in getopt(): + case kind + of cmdArgument: + if action.len == 0: + action = key.normalize + else: + args.add key + of cmdLongOption, cmdShortOption: + case normalize(key) + of "help", "h": writeHelp() + of "version", "v": writeVersion() + of "keepcommits": c.keepCommits = true + else: writeHelp() + of cmdEnd: assert false, "cannot happen" + + while c.workspace.len > 0 and dirExists(c.workspace / ".git"): + c.workspace = c.workspace.parentDir() + + case action + of "": + error "No action." + of "clone": + singleArg() + let deps = clone(c, args[0]) + patchNimCfg c, deps + if c.errors > 0: + error "There were problems." + of "refresh": + noArgs() + updatePackages(c) + of "search", "list": + updatePackages(c) + search getPackages(c.workspace), args + else: + error "Invalid action: " & action + +when isMainModule: + main() + +when false: + # some testing code for the `patchNimCfg` logic: + var c = AtlasContext( + projectDir: getCurrentDir(), + workspace: getCurrentDir().parentDir) + + patchNimCfg(c, @[PackageName"abc", PackageName"xyz"]) + +when false: + assert sameVersionAs("v0.2.0", "0.2.0") + assert sameVersionAs("v1", "1") + + assert sameVersionAs("1.90", "1.90") + + assert sameVersionAs("v1.2.3-zuzu", "1.2.3") + assert sameVersionAs("foo-1.2.3.4", "1.2.3.4") + + assert not sameVersionAs("foo-1.2.3.4", "1.2.3") + assert not sameVersionAs("foo", "1.2.3") + assert not sameVersionAs("", "1.2.3") diff --git a/tools/atlas/osutils.nim b/tools/atlas/osutils.nim new file mode 100644 index 000000000..31392b113 --- /dev/null +++ b/tools/atlas/osutils.nim @@ -0,0 +1,59 @@ +## OS utilities like 'withDir'. +## (c) 2021 Andreas Rumpf + +import os, strutils, osproc + +template withDir*(dir, body) = + let oldDir = getCurrentDir() + try: + setCurrentDir(dir) + body + finally: + setCurrentDir(oldDir) + +proc isUrl*(x: string): bool = + x.startsWith("git://") or x.startsWith("https://") or x.startsWith("http://") + +proc cloneUrl*(url, dest: string; cloneUsingHttps: bool): string = + ## Returns an error message on error or else "". + result = "" + var modUrl = + if url.startsWith("git://") and cloneUsingHttps: + "https://" & url[6 .. ^1] + else: url + + # github + https + trailing url slash causes a + # checkout/ls-remote to fail with Repository not found + var isGithub = false + if modUrl.contains("github.com") and modUrl.endswith("/"): + modUrl = modUrl[0 .. ^2] + isGithub = true + + let (_, exitCode) = execCmdEx("git ls-remote --quiet --tags " & modUrl) + var xcode = exitCode + if isGithub and exitCode != QuitSuccess: + # retry multiple times to avoid annoying github timeouts: + for i in 0..4: + os.sleep(4000) + xcode = execCmdEx("git ls-remote --quiet --tags " & modUrl)[1] + if xcode == QuitSuccess: break + + if xcode == QuitSuccess: + # retry multiple times to avoid annoying github timeouts: + let cmd = "git clone " & modUrl & " " & dest + for i in 0..4: + if execShellCmd(cmd) == 0: return "" + os.sleep(4000) + result = "exernal program failed: " & cmd + elif not isGithub: + let (_, exitCode) = execCmdEx("hg identify " & modUrl) + if exitCode == QuitSuccess: + let cmd = "hg clone " & modUrl & " " & dest + for i in 0..4: + if execShellCmd(cmd) == 0: return "" + os.sleep(4000) + result = "exernal program failed: " & cmd + else: + result = "Unable to identify url: " & modUrl + else: + result = "Unable to identify url: " & modUrl diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim new file mode 100644 index 000000000..e1e23ee29 --- /dev/null +++ b/tools/atlas/packagesjson.nim @@ -0,0 +1,117 @@ + +import std / [json, os, sets, strutils] +import osutils + +type + Package* = ref object + # Required fields in a package. + name*: string + url*: string # Download location. + license*: string + downloadMethod*: string + description*: string + tags*: seq[string] # \ + # From here on, optional fields set to the empty string if not available. + version*: string + dvcsTag*: string + web*: string # Info url for humans. + +proc optionalField(obj: JsonNode, name: string, default = ""): string = + if hasKey(obj, name) and obj[name].kind == JString: + result = obj[name].str + else: + result = default + +proc requiredField(obj: JsonNode, name: string): string = + result = optionalField(obj, name, "") + +proc fromJson*(obj: JSonNode): Package = + result = Package() + result.name = obj.requiredField("name") + if result.name.len == 0: return nil + result.version = obj.optionalField("version") + result.url = obj.requiredField("url") + if result.url.len == 0: return nil + result.downloadMethod = obj.requiredField("method") + if result.downloadMethod.len == 0: return nil + result.dvcsTag = obj.optionalField("dvcs-tag") + result.license = obj.optionalField("license") + result.tags = @[] + for t in obj["tags"]: + result.tags.add(t.str) + result.description = obj.requiredField("description") + result.web = obj.optionalField("web") + +const PackagesDir* = "packages" + +proc getPackages*(workspaceDir: string): seq[Package] = + result = @[] + var uniqueNames = initHashSet[string]() + var jsonFiles = 0 + for kind, path in walkDir(workspaceDir / PackagesDir): + if kind == pcFile and path.endsWith(".json"): + inc jsonFiles + let packages = json.parseFile(path) + for p in packages: + let pkg = p.fromJson() + if pkg != nil and not uniqueNames.containsOrIncl(pkg.name): + result.add(pkg) + +proc `$`*(pkg: Package): string = + result = pkg.name & ":\n" + result &= " url: " & pkg.url & " (" & pkg.downloadMethod & ")\n" + result &= " tags: " & pkg.tags.join(", ") & "\n" + result &= " description: " & pkg.description & "\n" + result &= " license: " & pkg.license & "\n" + if pkg.web.len > 0: + result &= " website: " & pkg.web & "\n" + +proc search*(pkgList: seq[Package]; terms: seq[string]) = + var found = false + template onFound = + echo pkg + echo("") + found = true + break forPackage + + for pkg in pkgList: + if terms.len > 0: + block forPackage: + for term in terms: + let word = term.toLower + # Search by name. + if word in pkg.name.toLower: + onFound() + # Search by tag. + for tag in pkg.tags: + if word in tag.toLower: + onFound() + else: + echo(pkg) + echo(" ") + + if not found and terms.len > 0: + echo("No package found.") + +type PkgCandidates* = array[3, seq[Package]] + +proc determineCandidates*(pkgList: seq[Package]; + terms: seq[string]): PkgCandidates = + result[0] = @[] + result[1] = @[] + result[2] = @[] + for pkg in pkgList: + block termLoop: + for term in terms: + let word = term.toLower + if word == pkg.name.toLower: + result[0].add pkg + break termLoop + elif word in pkg.name.toLower: + result[1].add pkg + break termLoop + else: + for tag in pkg.tags: + if word in tag.toLower: + result[2].add pkg + break termLoop diff --git a/tools/atlas/parse_requires.nim b/tools/atlas/parse_requires.nim new file mode 100644 index 000000000..7e26a1656 --- /dev/null +++ b/tools/atlas/parse_requires.nim @@ -0,0 +1,101 @@ +## Utility API for Nim package managers. +## (c) 2021 Andreas Rumpf + +import std / strutils +import ".." / compiler / [ast, idents, msgs, syntaxes, options, pathutils] + +type + NimbleFileInfo* = object + requires*: seq[string] + srcDir*: string + tasks*: seq[(string, string)] + +proc extract(n: PNode; conf: ConfigRef; result: var NimbleFileInfo) = + case n.kind + of nkStmtList, nkStmtListExpr: + for child in n: + extract(child, conf, result) + of nkCallKinds: + if n[0].kind == nkIdent: + case n[0].ident.s + of "requires": + for i in 1.. 0: ch = ch.lastSon + if ch.kind in {nkStrLit..nkTripleStrLit}: + result.requires.add ch.strVal + else: + localError(conf, ch.info, "'requires' takes string literals") + of "task": + if n.len >= 3 and n[1].kind == nkIdent and n[2].kind in {nkStrLit..nkTripleStrLit}: + result.tasks.add((n[1].ident.s, n[2].strVal)) + else: discard + of nkAsgn, nkFastAsgn: + if n[0].kind == nkIdent and cmpIgnoreCase(n[0].ident.s, "srcDir") == 0: + if n[1].kind in {nkStrLit..nkTripleStrLit}: + result.srcDir = n[1].strVal + else: + localError(conf, n[1].info, "assignments to 'srcDir' must be string literals") + else: + discard + +proc extractRequiresInfo*(nimbleFile: string): NimbleFileInfo = + ## Extract the `requires` information from a Nimble file. This does **not** + ## evaluate the Nimble file. Errors are produced on stderr/stdout and are + ## formatted as the Nim compiler does it. The parser uses the Nim compiler + ## as an API. The result can be empty, this is not an error, only parsing + ## errors are reported. + var conf = newConfigRef() + conf.foreignPackageNotes = {} + conf.notes = {} + conf.mainPackageNotes = {} + + let fileIdx = fileInfoIdx(conf, AbsoluteFile nimbleFile) + var parser: Parser + if setupParser(parser, fileIdx, newIdentCache(), conf): + extract(parseAll(parser), conf, result) + closeParser(parser) + +const Operators* = {'<', '>', '=', '&', '@', '!', '^'} + +proc token(s: string; idx: int; lit: var string): int = + var i = idx + if i >= s.len: return i + while s[i] in Whitespace: inc(i) + case s[i] + of Letters, '#': + lit.add s[i] + inc i + while i < s.len and s[i] notin (Whitespace + {'@', '#'}): + lit.add s[i] + inc i + of '0'..'9': + while i < s.len and s[i] in {'0'..'9', '.'}: + lit.add s[i] + inc i + of '"': + inc i + while i < s.len and s[i] != '"': + lit.add s[i] + inc i + inc i + of Operators: + while i < s.len and s[i] in Operators: + lit.add s[i] + inc i + else: + lit.add s[i] + inc i + result = i + +iterator tokenizeRequires*(s: string): string = + var start = 0 + var tok = "" + while start < s.len: + tok.setLen 0 + start = token(s, start, tok) + yield tok + +when isMainModule: + for x in tokenizeRequires("jester@#head >= 1.5 & <= 1.8"): + echo x From 96a7f9b31c84f14906b201d5e3b17c93d3878af6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 16 Jul 2021 15:50:02 +0200 Subject: [PATCH 2827/4254] deprecate cuchar, don't redefine it (#18505) --- changelog.md | 3 ++- lib/posix/posix_linux_amd64.nim | 2 +- lib/posix/posix_nintendoswitch.nim | 12 ++++----- lib/pure/bitops.nim | 42 +++++++++++++++--------------- lib/pure/net.nim | 6 ++--- lib/pure/terminal.nim | 2 +- lib/std/sysrand.nim | 2 +- lib/system.nim | 4 +-- lib/windows/winlean.nim | 4 +-- lib/wrappers/openssl.nim | 24 ++++++++--------- tests/stdlib/topenssl.nim | 8 +++--- 11 files changed, 55 insertions(+), 54 deletions(-) diff --git a/changelog.md b/changelog.md index d07ddddb4..568ff0bba 100644 --- a/changelog.md +++ b/changelog.md @@ -6,7 +6,8 @@ - Deprecated `std/mersenne` -- `cuchar` now aliases `uint8` instead of `char` +- `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`. + Please use `char` or `uint8` instead. - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 7f6a589f0..5c0b4d6cf 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -47,7 +47,7 @@ type d_ino*: Ino d_off*: Off d_reclen*: cushort - d_type*: int8 # cuchar really! + d_type*: int8 # uint8 really! d_name*: array[256, cchar] Tflock* {.importc: "struct flock", final, pure, diff --git a/lib/posix/posix_nintendoswitch.nim b/lib/posix/posix_nintendoswitch.nim index 44e431437..4cef80bb7 100644 --- a/lib/posix/posix_nintendoswitch.nim +++ b/lib/posix/posix_nintendoswitch.nim @@ -33,7 +33,7 @@ type Dirent* {.importc: "struct dirent", header: "", final, pure.} = object ## dirent_t struct d_ino*: Ino - d_type*: int8 # cuchar really! + d_type*: int8 # uint8 really! d_name*: array[256, cchar] Tflock* {.importc: "struct flock", final, pure, @@ -347,20 +347,20 @@ type SockAddr* {.importc: "struct sockaddr", header: "", pure, final.} = object ## struct sockaddr - sa_len: cuchar + sa_len: uint8 sa_family*: TSa_Family ## Address family. sa_data*: array[14, char] ## Socket address (variable-length data). Sockaddr_storage* {.importc: "struct sockaddr_storage", header: "", pure, final.} = object ## struct sockaddr_storage - ss_len: cuchar + ss_len: uint8 ss_family*: TSa_Family ## Address family. - ss_padding1: array[64 - sizeof(cuchar) - sizeof(cshort), char] + ss_padding1: array[64 - sizeof(uint8) - sizeof(cshort), char] ss_align: clonglong ss_padding2: array[ - 128 - sizeof(cuchar) - sizeof(cshort) - - (64 - sizeof(cuchar) - sizeof(cshort)) - 64, char] + 128 - sizeof(uint8) - sizeof(cshort) - + (64 - sizeof(uint8) - sizeof(cshort)) - 64, char] Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "".} = object ## struct if_nameindex diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index b5b08985e..6d3865e5d 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -450,15 +450,15 @@ when useGCC_builtins: elif useVCC_builtins: # Search the mask data from most significant bit (MSB) to least significant bit (LSB) for a set bit (1). - func bitScanReverse(index: ptr culong, mask: culong): cuchar {. + func bitScanReverse(index: ptr culong, mask: culong): uint8 {. importc: "_BitScanReverse", header: "".} - func bitScanReverse64(index: ptr culong, mask: uint64): cuchar {. + func bitScanReverse64(index: ptr culong, mask: uint64): uint8 {. importc: "_BitScanReverse64", header: "".} # Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1). - func bitScanForward(index: ptr culong, mask: culong): cuchar {. + func bitScanForward(index: ptr culong, mask: culong): uint8 {. importc: "_BitScanForward", header: "".} - func bitScanForward64(index: ptr culong, mask: uint64): cuchar {. + func bitScanForward64(index: ptr culong, mask: uint64): uint8 {. importc: "_BitScanForward64", header: "".} template vcc_scan_impl(fnc: untyped; v: untyped): int = @@ -468,15 +468,15 @@ elif useVCC_builtins: elif useICC_builtins: # Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined. - func bitScanForward(p: ptr uint32, b: uint32): cuchar {. + func bitScanForward(p: ptr uint32, b: uint32): uint8 {. importc: "_BitScanForward", header: "".} - func bitScanForward64(p: ptr uint32, b: uint64): cuchar {. + func bitScanForward64(p: ptr uint32, b: uint64): uint8 {. importc: "_BitScanForward64", header: "".} # Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined. - func bitScanReverse(p: ptr uint32, b: uint32): cuchar {. + func bitScanReverse(p: ptr uint32, b: uint32): uint8 {. importc: "_BitScanReverse", header: "".} - func bitScanReverse64(p: ptr uint32, b: uint64): cuchar {. + func bitScanReverse64(p: ptr uint32, b: uint64): uint8 {. importc: "_BitScanReverse64", header: "".} template icc_scan_impl(fnc: untyped; v: untyped): int = @@ -664,7 +664,7 @@ when useBuiltinsRotate: when defined(gcc): # GCC was tested until version 4.8.1 and intrinsics were present. Not tested # in previous versions. - func builtin_rotl8(value: cuchar, shift: cint): cuchar + func builtin_rotl8(value: uint8, shift: cint): uint8 {.importc: "__rolb", header: "".} func builtin_rotl16(value: cushort, shift: cint): cushort {.importc: "__rolw", header: "".} @@ -674,7 +674,7 @@ when useBuiltinsRotate: func builtin_rotl64(value: culonglong, shift: cint): culonglong {.importc: "__rolq", header: "".} - func builtin_rotr8(value: cuchar, shift: cint): cuchar + func builtin_rotr8(value: uint8, shift: cint): uint8 {.importc: "__rorb", header: "".} func builtin_rotr16(value: cushort, shift: cint): cushort {.importc: "__rorw", header: "".} @@ -690,7 +690,7 @@ when useBuiltinsRotate: # https://releases.llvm.org/8.0.0/tools/clang/docs/ReleaseNotes.html#non-comprehensive-list-of-changes-in-this-release # https://releases.llvm.org/8.0.0/tools/clang/docs/LanguageExtensions.html#builtin-rotateleft # source for correct declarations: https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/Builtins.def - func builtin_rotl8(value: cuchar, shift: cuchar): cuchar + func builtin_rotl8(value: uint8, shift: uint8): uint8 {.importc: "__builtin_rotateleft8", nodecl.} func builtin_rotl16(value: cushort, shift: cushort): cushort {.importc: "__builtin_rotateleft16", nodecl.} @@ -700,7 +700,7 @@ when useBuiltinsRotate: func builtin_rotl64(value: culonglong, shift: culonglong): culonglong {.importc: "__builtin_rotateleft64", nodecl.} - func builtin_rotr8(value: cuchar, shift: cuchar): cuchar + func builtin_rotr8(value: uint8, shift: uint8): uint8 {.importc: "__builtin_rotateright8", nodecl.} func builtin_rotr16(value: cushort, shift: cushort): cushort {.importc: "__builtin_rotateright16", nodecl.} @@ -716,9 +716,9 @@ when useBuiltinsRotate: # https://docs.microsoft.com/en-us/cpp/intrinsics/rotl8-rotl16?view=msvc-160 # https://docs.microsoft.com/en-us/cpp/intrinsics/rotr8-rotr16?view=msvc-160 # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rotl-rotl64-rotr-rotr64?view=msvc-160 - func builtin_rotl8(value: cuchar, shift: cuchar): cuchar + func builtin_rotl8(value: uint8, shift: uint8): uint8 {.importc: "_rotl8", header: "".} - func builtin_rotl16(value: cushort, shift: cuchar): cushort + func builtin_rotl16(value: cushort, shift: uint8): cushort {.importc: "_rotl16", header: "".} func builtin_rotl32(value: cuint, shift: cint): cuint {.importc: "_rotl", header: "".} @@ -726,9 +726,9 @@ when useBuiltinsRotate: func builtin_rotl64(value: culonglong, shift: cint): culonglong {.importc: "_rotl64", header: "".} - func builtin_rotr8(value: cuchar, shift: cuchar): cuchar + func builtin_rotr8(value: uint8, shift: uint8): uint8 {.importc: "_rotr8", header: "".} - func builtin_rotr16(value: cushort, shift: cuchar): cushort + func builtin_rotr16(value: cushort, shift: uint8): cushort {.importc: "_rotr16", header: "".} func builtin_rotr32(value: cuint, shift: cint): cuint {.importc: "_rotr", header: "".} @@ -738,7 +738,7 @@ when useBuiltinsRotate: elif defined(icl): # Tested on Intel(R) C++ Intel(R) 64 Compiler Classic Version 2021.1.2 Build # 20201208_000000 x64 and x86. Not tested in previous versions. - func builtin_rotl8(value: cuchar, shift: cint): cuchar + func builtin_rotl8(value: uint8, shift: cint): uint8 {.importc: "__rolb", header: "".} func builtin_rotl16(value: cushort, shift: cint): cushort {.importc: "__rolw", header: "".} @@ -748,7 +748,7 @@ when useBuiltinsRotate: func builtin_rotl64(value: culonglong, shift: cint): culonglong {.importc: "__rolq", header: "".} - func builtin_rotr8(value: cuchar, shift: cint): cuchar + func builtin_rotr8(value: uint8, shift: cint): uint8 {.importc: "__rorb", header: "".} func builtin_rotr16(value: cushort, shift: cint): cushort {.importc: "__rorw", header: "".} @@ -777,7 +777,7 @@ func shiftTypeTo(size: static int, shift: int): auto {.inline.} = when (defined(vcc) and (size in [4, 8])) or defined(gcc) or defined(icl): cint(shift) elif (defined(vcc) and (size in [1, 2])) or (defined(clang) and size == 1): - cuchar(shift) + uint8(shift) elif defined(clang): when size == 2: cushort(shift) @@ -802,7 +802,7 @@ func rotateLeftBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * when useBuiltinsRotate: const size = sizeof(T) when size == 1: - builtin_rotl8(value.cuchar, shiftTypeTo(size, shift)).T + builtin_rotl8(value.uint8, shiftTypeTo(size, shift)).T elif size == 2: builtin_rotl16(value.cushort, shiftTypeTo(size, shift)).T elif size == 4: @@ -830,7 +830,7 @@ func rotateRightBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * when useBuiltinsRotate: const size = sizeof(T) when size == 1: - builtin_rotr8(value.cuchar, shiftTypeTo(size, shift)).T + builtin_rotr8(value.uint8, shiftTypeTo(size, shift)).T elif size == 2: builtin_rotr16(value.cushort, shiftTypeTo(size, shift)).T elif size == 4: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9c3827751..934dd034e 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -503,7 +503,7 @@ when defineSsl: ## Retrieve the ssl pointer of `socket`. ## Useful for interfacing with `openssl`. self.sslHandle - + proc raiseSSLError*(s = "") = ## Raises a new SSL error. if s != "": @@ -688,7 +688,7 @@ when defineSsl: return ctx.getExtraInternal().clientGetPskFunc proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; - max_identity_len: cuint; psk: ptr cuchar; + max_identity_len: cuint; psk: ptr uint8; max_psk_len: cuint): cuint {.cdecl.} = let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let hintString = if hint == nil: "" else: $hint @@ -714,7 +714,7 @@ when defineSsl: proc serverGetPskFunc*(ctx: SslContext): SslServerGetPskFunc = return ctx.getExtraInternal().serverGetPskFunc - proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; + proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr uint8; max_psk_len: cint): cuint {.cdecl.} = let ctx = SslContext(context: ssl.SSL_get_SSL_CTX) let pskString = (ctx.serverGetPskFunc)($identity) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 283652bb3..ce5660557 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -761,7 +761,7 @@ template styledWriteLine*(f: File, args: varargs[untyped]) = runnableExamples: proc error(msg: string) = styledWriteLine(stderr, fgRed, "Error: ", resetStyle, msg) - + styledWrite(f, args) write(f, "\n") diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 4c51577ac..75983e3c6 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -132,7 +132,7 @@ elif defined(windows): type PVOID = pointer BCRYPT_ALG_HANDLE = PVOID - PUCHAR = ptr cuchar + PUCHAR = ptr uint8 NTSTATUS = clong ULONG = culong diff --git a/lib/system.nim b/lib/system.nim index 8aa9bd718..57d620e57 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1427,8 +1427,8 @@ type # these work for most platforms: ## This is the same as the type `long double` in *C*. ## This C type is not supported by Nim's code generator. - cuchar* {.importc: "unsigned char", nodecl.} = uint8 - ## This is the same as the type `unsigned char` in *C*. + cuchar* {.importc: "unsigned char", nodecl, deprecated: "use `char` or `uint8` instead".} = char + ## Deprecated: Use `uint8` instead. cushort* {.importc: "unsigned short", nodecl.} = uint16 ## This is the same as the type `unsigned short` in *C*. cuint* {.importc: "unsigned int", nodecl.} = uint32 diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index a71dd97d8..d901af244 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -42,7 +42,7 @@ type PULONG_PTR* = ptr uint HDC* = Handle HGLRC* = Handle - BYTE* = cuchar + BYTE* = uint8 SECURITY_ATTRIBUTES* {.final, pure.} = object nLength*: int32 @@ -717,7 +717,7 @@ const FILE_WRITE_DATA* = 0x00000002 # file & pipe # Error Constants -const +const ERROR_FILE_NOT_FOUND* = 2 ## https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- ERROR_PATH_NOT_FOUND* = 3 ERROR_ACCESS_DENIED* = 5 diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 1a8893957..c756fa938 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -520,16 +520,16 @@ proc OPENSSL_sk_num*(stack: PSTACK): int {.cdecl, dynlib: DLLSSLName, importc.} proc OPENSSL_sk_value*(stack: PSTACK, index: int): pointer {.cdecl, dynlib: DLLSSLName, importc.} -proc d2i_X509*(px: ptr PX509, i: ptr ptr cuchar, len: cint): PX509 {.cdecl, +proc d2i_X509*(px: ptr PX509, i: ptr ptr uint8, len: cint): PX509 {.cdecl, dynlib: DLLUtilName, importc.} -proc i2d_X509*(cert: PX509; o: ptr ptr cuchar): cint {.cdecl, +proc i2d_X509*(cert: PX509; o: ptr ptr uint8): cint {.cdecl, dynlib: DLLUtilName, importc.} proc d2i_X509*(b: string): PX509 = ## decode DER/BER bytestring into X.509 certificate struct var bb = b.cstring - let i = cast[ptr ptr cuchar](addr bb) + let i = cast[ptr ptr uint8](addr bb) let ret = d2i_X509(addr result, i, b.len.cint) if ret.isNil: raise newException(Exception, "X.509 certificate decoding failed") @@ -539,7 +539,7 @@ proc i2d_X509*(cert: PX509): string = let encoded_length = i2d_X509(cert, nil) result = newString(encoded_length) var q = result.cstring - let o = cast[ptr ptr cuchar](addr q) + let o = cast[ptr ptr uint8](addr q) let length = i2d_X509(cert, o) if length.int <= 0: raise newException(Exception, "X.509 certificate encoding failed") @@ -599,11 +599,11 @@ proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int = type PskClientCallback* = proc (ssl: SslPtr; - hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; + hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr uint8; max_psk_len: cuint): cuint {.cdecl.} PskServerCallback* = proc (ssl: SslPtr; - identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} + identity: cstring; psk: ptr uint8; max_psk_len: cint): cuint {.cdecl.} proc SSL_CTX_set_psk_client_callback*(ctx: SslCtx; callback: PskClientCallback) {.cdecl, dynlib: DLLSSLName, importc.} ## Set callback called when OpenSSL needs PSK (for client). @@ -672,13 +672,13 @@ proc PEM_read_bio_RSAPublicKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: po dynlib: DLLUtilName, importc.} proc PEM_read_bio_RSAPrivateKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, dynlib: DLLUtilName, importc.} -proc RSA_private_encrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, +proc RSA_private_encrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, dynlib: DLLUtilName, importc.} -proc RSA_public_encrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, +proc RSA_public_encrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, dynlib: DLLUtilName, importc.} -proc RSA_private_decrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, +proc RSA_private_decrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, dynlib: DLLUtilName, importc.} -proc RSA_public_decrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, +proc RSA_public_decrypt*(flen: cint, fr: ptr uint8, to: ptr uint8, rsa: PRSA, padding: PaddingType): cint {.cdecl, dynlib: DLLUtilName, importc.} proc RSA_free*(rsa: PRSA) {.cdecl, dynlib: DLLUtilName, importc.} proc RSA_size*(rsa: PRSA): cint {.cdecl, dynlib: DLLUtilName, importc.} @@ -744,8 +744,8 @@ type proc md5_Init*(c: var MD5_CTX): cint{.importc: "MD5_Init".} proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize_t): cint{.importc: "MD5_Update".} proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.importc: "MD5_Final".} -proc md5*(d: ptr cuchar; n: csize_t; md: ptr cuchar): ptr cuchar{.importc: "MD5".} -proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".} +proc md5*(d: ptr uint8; n: csize_t; md: ptr uint8): ptr uint8{.importc: "MD5".} +proc md5_Transform*(c: var MD5_CTX; b: ptr uint8){.importc: "MD5_Transform".} {.pop.} from strutils import toHex, toLowerAscii diff --git a/tests/stdlib/topenssl.nim b/tests/stdlib/topenssl.nim index 75e1ba868..4c38b4216 100644 --- a/tests/stdlib/topenssl.nim +++ b/tests/stdlib/topenssl.nim @@ -12,8 +12,8 @@ proc rsaPublicEncrypt(fr: string): string = doAssert rsa != nil doAssert BIO_free(bio) >= 0 result = newString(RSA_size(rsa)) - let frdata = cast[ptr cuchar](fr.cstring) - var todata = cast[ptr cuchar](result.cstring) + let frdata = cast[ptr uint8](fr.cstring) + var todata = cast[ptr uint8](result.cstring) doAssert RSA_public_encrypt(fr.len.cint, frdata, todata, rsa, RSA_PKCS1_PADDING) != -1 RSA_free(rsa) @@ -26,8 +26,8 @@ proc rasPrivateDecrypt(fr: string): string = doAssert BIO_free(bio) >= 0 let rsaLen = RSA_size(rsa) result = newString(rsaLen) - let frdata = cast[ptr cuchar](fr.cstring) - var todata = cast[ptr cuchar](result.cstring) + let frdata = cast[ptr uint8](fr.cstring) + var todata = cast[ptr uint8](result.cstring) let lenOrig = RSA_private_decrypt(rsaLen, frdata, todata, rsa, RSA_PKCS1_PADDING) doAssert lenOrig >= 0 and lenOrig < result.len doAssert result[lenOrig] == '\0' From 25efb5386293540b0542833625d3fb6e22f3cfbc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 16 Jul 2021 18:29:49 +0200 Subject: [PATCH 2828/4254] make dragonbox opt-in via -d:nimFpRoundtrips (#18504) * make dragonbox opt-in via -d:nimFpRoundtrips * make tests green again * make tests green again --- changelog.md | 12 ++++++------ lib/system/formatfloat.nim | 2 +- lib/system/strmantle.nim | 2 +- tests/errmsgs/treportunused.nim | 14 ++++++++------ tests/float/nim.cfg | 1 + tests/float/tfloats.nim | 4 ++++ tests/stdlib/tjson.nim | 6 +++--- tests/stdlib/tjsonutils.nim | 21 +++++++++++---------- 8 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 tests/float/nim.cfg diff --git a/changelog.md b/changelog.md index 568ff0bba..289202587 100644 --- a/changelog.md +++ b/changelog.md @@ -76,9 +76,6 @@ - `json` and `jsonutils` now serialize NaN, Inf, -Inf as strings, so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` which was invalid json. -- `system.addFloat` now uses the "Dragonbox" algorithm, which ensures correct roundtrips of floating point - numbers, that the minimum length representation of a floating point number is used and correct rounding. - Use `-d:nimLegacyAddFloat` for a transition period. - `strformat` is now part of `include std/prelude`. @@ -102,6 +99,12 @@ added support for parenthesized expressions. added support for const string's instead of just string literals + +- `system.addFloat` and `system.$` now can produce string representations of floating point numbers + that are minimal in size and that "roundtrip" (via the "Dragonbox" algorithm). This currently has + to be enabled via `-d:nimFpRoundtrips`. It is expected that this behavior becomes the new default + in upcoming versions. + - Fixed buffer overflow bugs in `net` - Exported `sslHandle` from `net` and `asyncnet`. @@ -116,8 +119,6 @@ the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you now also need to ship `cacert.pem` with your `.exe` file. -- Make `{.requiresInit.}` pragma to work for `distinct` types. - - `typetraits`: `distinctBase` now is identity instead of error for non distinct types. Added `enumLen` to return the number of elements in an enum. @@ -468,7 +469,6 @@ with `--styleCheck:error` or `--styleCheck:hint`. - ## Tool changes - Latex doc generation is revised: output `.tex` files should be compiled diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim index 41bc56adc..772f0a848 100644 --- a/lib/system/formatfloat.nim +++ b/lib/system/formatfloat.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -when not defined(nimLegacyAddFloat) and not defined(nimscript) and +when defined(nimFpRoundtrips) and not defined(nimscript) and not defined(js) and defined(nimHasDragonBox): import dragonbox diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 63e341763..041272175 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -97,7 +97,7 @@ proc nimFloatToStr(f: float): string {.compilerproc.} = result = newStringOfCap(8) result.addFloat f -when not defined(nimLegacyAddFloat) and not defined(nimscript) and +when defined(nimFpRoundtrips) and not defined(nimscript) and not defined(js) and defined(nimHasDragonBox): import schubfach diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index 65e00163b..f9b7c3d11 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -13,12 +13,12 @@ treportunused.nim(30, 5) Hint: 's8' is declared but not used [XDeclaredButNotUse treportunused.nim(31, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] treportunused.nim(32, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] treportunused.nim(33, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(37, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(38, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] ''' action: compile """ +#treportunused.nim(37, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] +#treportunused.nim(38, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] # bug #9764 iterator s1(a:string): int = discard iterator s2(): int = discard @@ -32,7 +32,9 @@ var s9: int type s10 = object type s11 = type(1.2) -# https://github.com/nim-lang/Nim/issues/14407 -let - `v0.99` = "0.99" - `v0.99.99` = "0.99.99" +when false: + # enabled again when Nim bootstraps with -d:nimFpRoundtrips + # https://github.com/nim-lang/Nim/issues/14407 + let + `v0.99` = "0.99" + `v0.99.99` = "0.99.99" diff --git a/tests/float/nim.cfg b/tests/float/nim.cfg new file mode 100644 index 000000000..d27bbf43b --- /dev/null +++ b/tests/float/nim.cfg @@ -0,0 +1 @@ +-d:nimFpRoundtrips diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim index 406ddb6d9..30d9c50d6 100644 --- a/tests/float/tfloats.nim +++ b/tests/float/tfloats.nim @@ -66,6 +66,8 @@ template main = var a = 1.1'f32 doAssert $a == "1.1", $a # was failing +proc runtimeOnlyTests = + # enable for 'static' once -d:nimFpRoundtrips became the default block: # bug #7717 proc test(f: float) = let f2 = $f @@ -82,3 +84,5 @@ template main = static: main() main() + +runtimeOnlyTests() diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index 289ef9d05..000f72038 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -303,7 +303,7 @@ let jsonNode = %*mynode doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}""" doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])""" -block: # bug #17383 +when defined(nimFpRoundtrips): # bug #17383 testRoundtrip(int32.high): "2147483647" testRoundtrip(uint32.high): "4294967295" when int.sizeof == 4: @@ -316,7 +316,7 @@ block: # bug #17383 testRoundtrip(int64.high): "9223372036854775807" testRoundtrip(uint64.high): "18446744073709551615" -block: # bug #18007 +when defined(nimFpRoundtrips): # bug #18007 testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]""" # pending https://github.com/nim-lang/Nim/issues/18025 use: # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0]) @@ -332,7 +332,7 @@ block: # bug #18007 testRoundtripVal(0.0): "0.0" testRoundtripVal(-0.0): "-0.0" -block: # bug #15397, bug #13196 +when defined(nimFpRoundtrips): # bug #15397, bug #13196 testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index b0c444cbf..3e9c422e0 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -44,7 +44,7 @@ proc `$`(a: MyEnum): string = if a == me2: "me2Modif" else: system.`$`(a) -template fn() = +template fn() = block: # toJson, jsonTo type Foo = distinct float testRoundtrip('x', """120""") @@ -161,15 +161,16 @@ template fn() = doAssert b[2].signbit doAssert not b[3].signbit - block: # bug #15397, bug #13196 - let a = 0.1 - let x = 0.12345678901234567890123456789 - let b = (a + 0.2, 0.3, x) - testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]" + when defined(nimFpRoundtrips): + block: # bug #15397, bug #13196 + let a = 0.1 + let x = 0.12345678901234567890123456789 + let b = (a + 0.2, 0.3, x) + testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]" - testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" - testRoundtripVal(epsilon(float64)): "2.220446049250313e-16" - testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" + testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" + testRoundtripVal(epsilon(float64)): "2.220446049250313e-16" + testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" block: # case object type Foo = object @@ -433,7 +434,7 @@ template fn() = """{"b": true, "bt": false, "btf": "test"}""" testRoundtrip(Variant(b: true, bt: true, btt: 'c')): """{"b": true, "bt": true, "btt": "c"}""" - + # TODO: Add additional tests with missing and extra JSON keys, both when # allowed and forbidden analogous to the tests for the not nested # variant objects. From 923a1c6ea7d9f45b6389680717692690218228fb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 16 Jul 2021 22:54:47 -0700 Subject: [PATCH 2829/4254] fix nativeToUnixPath (#18501) --- lib/std/private/globs.nim | 11 ++++++++--- tests/stdlib/tglobs.nim | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/stdlib/tglobs.nim diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index 55f6a40bd..b3726c9c3 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -45,10 +45,15 @@ iterator walkDirRecFilter*(dir: string, follow: proc(entry: PathEntry): bool = n proc nativeToUnixPath*(path: string): string = # pending https://github.com/nim-lang/Nim/pull/13265 - doAssert not path.isAbsolute # not implemented here; absolute files need more care for the drive + result = path + when defined(windows): + if path.len >= 2 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':': + result[0] = '/' + result[1] = path[0] + if path.len > 2 and path[2] != '\\': + doAssert false, "paths like `C:foo` are currently unsupported, path: " & path when DirSep == '\\': - result = replace(path, '\\', '/') - else: result = path + result = replace(result, '\\', '/') when isMainModule: import sugar diff --git a/tests/stdlib/tglobs.nim b/tests/stdlib/tglobs.nim new file mode 100644 index 000000000..739a127f8 --- /dev/null +++ b/tests/stdlib/tglobs.nim @@ -0,0 +1,20 @@ +import std/private/globs + +template main = + when defined(windows): + doAssert nativeToUnixPath("C:") == "/C" + doAssert nativeToUnixPath(r"D:\") == "/D/" + doAssert nativeToUnixPath(r"E:\a") == "/E/a" + doAssert nativeToUnixPath(r"E:\a1\") == "/E/a1/" + doAssert nativeToUnixPath(r"E:\a1\bc") == "/E/a1/bc" + doAssert nativeToUnixPath(r"\a1\bc") == "/a1/bc" + doAssert nativeToUnixPath(r"a1\bc") == "a1/bc" + doAssert nativeToUnixPath("a1") == "a1" + doAssert nativeToUnixPath("") == "" + doAssert nativeToUnixPath(".") == "." + doAssert nativeToUnixPath("..") == ".." + doAssert nativeToUnixPath(r"..\") == "../" + doAssert nativeToUnixPath(r"..\..\.\") == "../.././" + +static: main() +main() From ac5435ecd0a08d1a0bdd9d6d6cd89577634ecb0f Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sun, 18 Jul 2021 10:49:03 +0200 Subject: [PATCH 2830/4254] Make error message for empty new-styled concept more descriptive (#18506) * Allow empty new-styled concept Slightly improve error messages * Make empty new-styled concepts an error --- compiler/concepts.nim | 15 +++++++-------- compiler/parser.nim | 2 ++ tests/concepts/tspec.nim | 5 ++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/concepts.nim b/compiler/concepts.nim index de994f1b8..885b69c60 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -11,8 +11,7 @@ ## for details. Note this is a first implementation and only the "Concept matching" ## section has been implemented. -import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, - types, intsets +import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets from magicsys import addSonSkipIntLit @@ -23,7 +22,7 @@ const ## -------------------------------------- proc declareSelf(c: PContext; info: TLineInfo) = - ## adds the magical 'Self' symbols to the current scope. + ## Adds the magical 'Self' symbols to the current scope. let ow = getCurrOwner(c) let s = newSym(skType, getIdent(c.cache, "Self"), nextSymId(c.idgen), ow, info) s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow) @@ -32,7 +31,7 @@ proc declareSelf(c: PContext; info: TLineInfo) = addDecl(c, s, info) proc isSelf*(t: PType): bool {.inline.} = - ## is this the magical 'Self' type? + ## Is this the magical 'Self' type? t.kind == tyTypeDesc and tfPacked in t.flags proc makeTypeDesc*(c: PContext, typ: PType): PType = @@ -45,8 +44,8 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = proc semConceptDecl(c: PContext; n: PNode): PNode = ## Recursive helper for semantic checking for the concept declaration. - ## Currently we only support lists of statements containing 'proc' - ## declarations and the like. + ## Currently we only support (possibly empty) lists of statements + ## containing 'proc' declarations and the like. case n.kind of nkStmtList, nkStmtListExpr: result = shallowCopy(n) @@ -60,7 +59,7 @@ proc semConceptDecl(c: PContext; n: PNode): PNode = result[i] = n[i] result[^1] = semConceptDecl(c, n[^1]) else: - localError(c.config, n.info, "unexpected construct in the new-styled concept " & renderTree(n)) + localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n)) result = n proc semConceptDeclaration*(c: PContext; n: PNode): PNode = @@ -97,7 +96,7 @@ proc existingBinding(m: MatchCon; key: PType): PType = proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = - ## the heart of the concept matching process. 'f' is the formal parameter of some + ## The heart of the concept matching process. 'f' is the formal parameter of some ## routine inside the concept that we're looking for. 'a' is the formal parameter ## of a routine that might match. const diff --git a/compiler/parser.nim b/compiler/parser.nim index b6c01e9c6..d00a17e9f 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -2058,6 +2058,8 @@ proc parseTypeClass(p: var Parser): PNode = skipComment(p, result) # an initial IND{>} HAS to follow: if not realInd(p): + if result.isNewStyleConcept: + parMessage(p, "routine expected, but found '$1' (empty new-styled concepts are not allowed)", p.tok) result.add(p.emptyNode) else: result.add(parseStmt(p)) diff --git a/tests/concepts/tspec.nim b/tests/concepts/tspec.nim index 1bca3c11b..52f13a40a 100644 --- a/tests/concepts/tspec.nim +++ b/tests/concepts/tspec.nim @@ -7,8 +7,7 @@ discard """ 2 3 yes int -string int -true''' +string int''' joinable: false """ @@ -102,5 +101,5 @@ type Monoid = concept proc z(x: typedesc[int]): int = 0 -echo(int is Monoid) +doAssert int is Monoid From 8091545f95143d520c64b14f88bb5ce2818c893c Mon Sep 17 00:00:00 2001 From: Miran Date: Sun, 18 Jul 2021 11:04:19 +0200 Subject: [PATCH 2831/4254] Revert #17398 and #17402 (#18480) * Revert "followup #17398: `getTempDir`, `getConfigDir` now do not have trailing DirSep (#17402)" This reverts commit 2356d0603f70cad90f76fa57999054bf5c0a9157. * Revert "fix #17393 getHomeDir and expandTilde should not include trailing `/` (#17398)" This reverts commit bebf2ce24a43bef4cde5c90c4010631a1e4a7927. * fix test --- changelog.md | 3 --- lib/pure/os.nim | 40 ++++++++++++++----------------------- tests/stdlib/tos.nim | 6 +++--- tests/stdlib/ttempfiles.nim | 2 +- 4 files changed, 19 insertions(+), 32 deletions(-) diff --git a/changelog.md b/changelog.md index 289202587..16f2192dc 100644 --- a/changelog.md +++ b/changelog.md @@ -39,9 +39,6 @@ underlying code is also updated the same way. - Custom pragma values have now an API for use in macros. -- In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, - unless `-d:nimLegacyHomeDir` is specified (for a transition period). - - On POSIX systems, the default signal handlers used for Nim programs (it's used for printing the stacktrace on fatal signals) will now re-raise the signal for the OS default handlers to handle. diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 213da2aed..dadc380e6 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -901,14 +901,9 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", ## * `setCurrentDir proc <#setCurrentDir,string>`_ runnableExamples: assert getHomeDir() == expandTilde("~") - # `getHomeDir()` doesn't end in `DirSep` even if `$HOME` (on posix) or - # `$USERPROFILE` (on windows) does, unless `-d:nimLegacyHomeDir` is specified. - from std/strutils import endsWith - assert not getHomeDir().endsWith DirSep - when defined(windows): result = getEnv("USERPROFILE") - else: result = getEnv("HOME") - result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) + when defined(windows): return getEnv("USERPROFILE") & "\\" + else: return getEnv("HOME") & "/" proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = @@ -917,21 +912,23 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## On non-Windows OSs, this proc conforms to the XDG Base Directory ## spec. Thus, this proc returns the value of the `XDG_CONFIG_HOME` environment ## variable if it is set, otherwise it returns the default configuration - ## directory ("~/.config"). + ## directory ("~/.config/"). + ## + ## An OS-dependent trailing slash is always present at the end of the + ## returned string: `\\` on Windows and `/` on all other OSs. ## ## See also: ## * `getHomeDir proc <#getHomeDir>`_ ## * `getTempDir proc <#getTempDir>`_ - ## * `getCacheDir proc <#getCacheDir>`_ - runnableExamples: - from std/strutils import endsWith - # See `getHomeDir` for behavior regarding trailing DirSep. - assert not getConfigDir().endsWith DirSep + ## * `expandTilde proc <#expandTilde,string>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ when defined(windows): result = getEnv("APPDATA") else: result = getEnv("XDG_CONFIG_HOME", getEnv("HOME") / ".config") - result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) + result.normalizePathEnd(trailingSep = true) + proc getCacheDir*(): string = ## Returns the cache directory of the current user for applications. @@ -1006,11 +1003,9 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", ## See also: ## * `getHomeDir proc <#getHomeDir>`_ ## * `getConfigDir proc <#getConfigDir>`_ - ## * `getCacheDir proc <#getCacheDir>`_ - runnableExamples: - from std/strutils import endsWith - # See `getHomeDir` for behavior regarding trailing DirSep. - assert not getTempDir().endsWith(DirSep) + ## * `expandTilde proc <#expandTilde,string>`_ + ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `setCurrentDir proc <#setCurrentDir,string>`_ const tempDirDefault = "/tmp" when defined(tempDir): const tempDir {.strdefine.}: string = tempDirDefault @@ -1031,7 +1026,7 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", getTempDirImpl(result) if result.len == 0: result = tempDirDefault - result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) + normalizePathEnd(result, trailingSep=true) proc expandTilde*(path: string): string {. tags: [ReadEnvEffect, ReadIOEffect].} = @@ -1041,8 +1036,6 @@ proc expandTilde*(path: string): string {. ## Windows: this is still supported despite the Windows platform not having this ## convention; also, both ``~/`` and ``~\`` are handled. ## - ## .. warning:: `~bob` and `~bob/` are not yet handled correctly. - ## ## See also: ## * `getHomeDir proc <#getHomeDir>`_ ## * `getConfigDir proc <#getConfigDir>`_ @@ -1053,9 +1046,6 @@ proc expandTilde*(path: string): string {. assert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg" assert expandTilde("~/foo/bar") == getHomeDir() / "foo/bar" assert expandTilde("/foo/bar") == "/foo/bar" - assert expandTilde("~") == getHomeDir() - from std/strutils import endsWith - assert not expandTilde("~").endsWith(DirSep) if len(path) == 0 or path[0] != '~': result = path diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index a4f030dde..912558461 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -594,12 +594,12 @@ block getTempDir: if existsEnv("TMPDIR"): let origTmpDir = getEnv("TMPDIR") putEnv("TMPDIR", "/mytmp") - doAssert getTempDir() == "/mytmp" + doAssert getTempDir() == "/mytmp/" delEnv("TMPDIR") - doAssert getTempDir() == "/tmp" + doAssert getTempDir() == "/tmp/" putEnv("TMPDIR", origTmpDir) else: - doAssert getTempDir() == "/tmp" + doAssert getTempDir() == "/tmp/" block: # getCacheDir doAssert getCacheDir().dirExists diff --git a/tests/stdlib/ttempfiles.nim b/tests/stdlib/ttempfiles.nim index d740e1850..297410686 100644 --- a/tests/stdlib/ttempfiles.nim +++ b/tests/stdlib/ttempfiles.nim @@ -40,7 +40,7 @@ block: # createTempDir doAssert dirExists(dir1) doAssert dir1.lastPathPart.contains(re"^D20210502T100442(\w+).tmp$") - doAssert dir1.parentDir == getTempDir() + doAssert dir1.parentDir == getTempDir().normalizePathEnd() block: let dir3 = createTempDir(prefix, "_mytmp", ".") From 3723140044b99fde3f47df4f2e6a3ed4abdaba89 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 18 Jul 2021 02:05:35 -0700 Subject: [PATCH 2832/4254] add NIM_STATIC_ASSERT(CHAR_BIT == 8, "") to fail-fast where assumption is violated (#18512) --- lib/nimbase.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/nimbase.h b/lib/nimbase.h index cbd35605b..e480c55fd 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -325,6 +325,9 @@ typedef unsigned char NIM_BOOL; // best effort #endif NIM_STATIC_ASSERT(sizeof(NIM_BOOL) == 1, ""); // check whether really needed +NIM_STATIC_ASSERT(CHAR_BIT == 8, ""); + // fail fast for (rare) environments where this doesn't hold, as some implicit + // assumptions would need revisiting (e.g. `uint8` or https://github.com/nim-lang/Nim/pull/18505) #define NIM_TRUE true #define NIM_FALSE false From adba5eb45e0ae0d370aea4d653a4f00a4c075695 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 18 Jul 2021 02:10:08 -0700 Subject: [PATCH 2833/4254] deprecate strutils.delete and add an overload with saner semantics consistent with sequtils.delete; follows #18487 (#18510) --- changelog.md | 2 +- lib/pure/strutils.nim | 36 +++++++++++++++++++++++++++++++----- tests/stdlib/tstrutils.nim | 26 +++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 16f2192dc..6dddd8a01 100644 --- a/changelog.md +++ b/changelog.md @@ -346,7 +346,7 @@ - Added `dom.setInterval`, `dom.clearInterval` overloads. - Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect - if the slice is out of bounds. + if the slice is out of bounds, likewise with `strutils.delete`. ## Language changes diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 9e0837942..ac078df4e 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1476,12 +1476,39 @@ func dedent*(s: string, count: Natural = indentation(s)): string {.rtl, doAssert x == "Hello\n There\n" unindent(s, count, " ") -func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete".} = - ## Deletes in `s` (must be declared as `var`) the characters at positions - ## `first .. last` (both ends included). +func delete*(s: var string, slice: Slice[int]) = + ## Deletes the items `s[slice]`, raising `IndexDefect` if the slice contains + ## elements out of range. ## - ## This modifies `s` itself, it does not return a copy. + ## This operation moves all elements after `s[slice]` in linear time, and + ## is the string analog to `sequtils.delete`. runnableExamples: + var a = "abcde" + doAssertRaises(IndexDefect): a.delete(4..5) + assert a == "abcde" + a.delete(4..4) + assert a == "abcd" + a.delete(1..2) + assert a == "ad" + a.delete(1..<1) # empty slice + assert a == "ad" + when compileOption("boundChecks"): + if not (slice.a < s.len and slice.a >= 0 and slice.b < s.len): + raise newException(IndexDefect, $(slice: slice, len: s.len)) + if slice.b >= slice.a: + var i = slice.a + var j = slice.b + 1 + var newLen = s.len - j + i + # if j < s.len: moveMem(addr s[i], addr s[j], s.len - j) # pending benchmark + while i < newLen: + s[i] = s[j] + inc(i) + inc(j) + setLen(s, newLen) + +func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete", deprecated: "use `delete(s, first..last)`".} = + ## Deletes in `s` the characters at positions `first .. last` (both ends included). + runnableExamples("--warning:deprecated:off"): var a = "abracadabra" a.delete(4, 5) @@ -1502,7 +1529,6 @@ func delete*(s: var string, first, last: int) {.rtl, extern: "nsuDelete".} = inc(j) setLen(s, newLen) - func startsWith*(s: string, prefix: char): bool {.inline.} = ## Returns true if `s` starts with character `prefix`. ## diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 68ee5812b..234991bdb 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -198,7 +198,30 @@ template main() = s.removePrefix("") doAssert s == "\r\n\r\nhello" - block: # delete + block: # delete(slice) + var s = "0123456789ABCDEFGH" + delete(s, 4 .. 5) + doAssert s == "01236789ABCDEFGH" + delete(s, s.len-1 .. s.len-1) + doAssert s == "01236789ABCDEFG" + delete(s, 0..0) + doAssert s == "1236789ABCDEFG" + s = "" + doAssertRaises(IndexDefect): delete(s, 0..0) + doAssert s == "" + s = "abc" + doAssertRaises(IndexDefect): delete(s, -1 .. -2) + doAssertRaises(IndexDefect): delete(s, 2..3) + doAssertRaises(IndexDefect): delete(s, 3..2) + delete(s, 2..2) + doAssert s == "ab" + delete(s, 1..0) + doAssert s == "ab" + delete(s, 0..0) + doAssert s == "b" + + block: # delete(first, last) + {.push warning[deprecated]:off.} var s = "0123456789ABCDEFGH" delete(s, 4, 5) doAssert s == "01236789ABCDEFGH" @@ -206,6 +229,7 @@ template main() = doAssert s == "01236789ABCDEFG" delete(s, 0, 0) doAssert s == "1236789ABCDEFG" + {.pop.} block: # find doAssert "0123456789ABCDEFGH".find('A') == 10 From 99c4b69097638aca8377ea3746e52cc19c24ced8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 18 Jul 2021 15:16:26 +0200 Subject: [PATCH 2834/4254] fixed system.delete (#18507) --- changelog.md | 13 ++++++++++++- lib/system.nim | 17 ++++++++++------- tests/stdlib/tsystem.nim | 8 ++++---- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 6dddd8a01..097beac2c 100644 --- a/changelog.md +++ b/changelog.md @@ -4,7 +4,18 @@ ## Changes affecting backward compatibility -- Deprecated `std/mersenne` +- Deprecated `std/mersenne`. + +- `system.delete` had a most surprising behavior when the index passed to it was out of + bounds (it would delete the last entry then). Compile with `-d:nimStrictDelete` so + that an index error is produced instead. But be aware that your code might depend on + this quirky behavior so a review process is required on your part before you can + use `-d:nimStrictDelete`. To make this review easier, use the `-d:nimAuditDelete` + switch, it pretends that `system.delete` is deprecated so that it is easier to see + where it was used in your code. + + `-d:nimStrictDelete` will become the default in upcoming versions. + - `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`. Please use `char` or `uint8` instead. diff --git a/lib/system.nim b/lib/system.nim index 57d620e57..2790187f4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2134,7 +2134,12 @@ const import system/dollars export dollars -proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = +when defined(nimAuditDelete): + {.pragma: auditDelete, deprecated: "review this call for out of bounds behavior".} +else: + {.pragma: auditDelete.} + +proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, auditDelete.} = ## Deletes the item at index `i` by moving all `x[i+1..^1]` items by one position. ## ## This is an `O(n)` operation. @@ -2147,12 +2152,10 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = s.delete(2) doAssert s == @[1, 2, 4, 5] - doAssertRaises(IndexDefect): - s.delete(4) - - if i > high(x): - # xxx this should call `raiseIndexError2(i, high(x))` after some refactoring - raise (ref IndexDefect)(msg: "index out of bounds: '" & $i & "' < '" & $x.len & "' failed") + when defined(nimStrictDelete): + if i > high(x): + # xxx this should call `raiseIndexError2(i, high(x))` after some refactoring + raise (ref IndexDefect)(msg: "index out of bounds: '" & $i & "' < '" & $x.len & "' failed") template defaultImpl = let xl = x.len diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim index b48034043..00be16275 100644 --- a/tests/stdlib/tsystem.nim +++ b/tests/stdlib/tsystem.nim @@ -53,8 +53,8 @@ template main = var s = @["foo", "bar"] s.delete(1) doAssert s == @["foo"] - - block: + + when false: var s: seq[string] doAssertRaises(IndexDefect): s.delete(0) @@ -66,8 +66,8 @@ template main = var s = @["foo"] s.delete(0) doAssert s == @[] - - block: # bug #16544: deleting out of bounds index should raise + + when false: # bug #16544: deleting out of bounds index should raise var s = @["foo"] doAssertRaises(IndexDefect): s.delete(1) From 220b55c5d7c40aa93df7879ebc6c9f71147c3eda Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Sun, 18 Jul 2021 16:29:49 +0300 Subject: [PATCH 2835/4254] attempt to support short commit hashes (#18514) * attempt to support short commit hashes Not sure if that's the correct way and what happens when the short hash matches "head" * need to remove # * Output needs to be stripped of newlines --- tools/atlas/atlas.nim | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index bc1cc6ae3..371a1c13f 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -123,8 +123,12 @@ proc versionToCommit(d: Dependency): string = return "" +proc shortToCommit(short: string): string = + let (cc, status) = osproc.execCmdEx("git rev-parse " & quoteShell(short)) + result = if status == 0: strutils.strip(cc) else: "" + proc checkoutGitCommit(c: var AtlasContext; p: PackageName; commit: string) = - let (outp, status) = osproc.execCmdEx("git checkout " & quoteShell(commit)) + let (_, status) = osproc.execCmdEx("git checkout " & quoteShell(commit)) if status != 0: error(c, p, "could not checkout commit", commit) @@ -169,17 +173,23 @@ proc toName(p: string): PackageName = proc needsCommitLookup(commit: string): bool {.inline} = '.' in commit or commit == InvalidCommit +proc isShortCommitHash(commit: string): bool {.inline.} = + commit.len >= 4 and commit.len < 40 + proc checkoutCommit(c: var AtlasContext; w: Dependency) = let dir = c.workspace / w.name.string withDir dir: - if w.commit.len == 0 or cmpIgnoreCase(w.commit, "#head") == 0: + if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: gitPull(c, w.name) else: let err = isCleanGit(dir) if err != "": warn c, w.name, err else: - let requiredCommit = if needsCommitLookup(w.commit): versionToCommit(w) else: w.commit + let requiredCommit = + if needsCommitLookup(w.commit): versionToCommit(w) + elif isShortCommitHash(w.commit): shortToCommit(w.commit) + else: w.commit let (cc, status) = osproc.execCmdEx("git log -n 1 --format=%H") let currentCommit = strutils.strip(cc) if requiredCommit == "" or status != 0: @@ -191,8 +201,9 @@ proc checkoutCommit(c: var AtlasContext; w: Dependency) = if currentCommit != requiredCommit: # checkout the later commit: # git merge-base --is-ancestor - let (mergeBase, status) = osproc.execCmdEx("git merge-base " & + let (cc, status) = osproc.execCmdEx("git merge-base " & currentCommit.quoteShell & " " & requiredCommit.quoteShell) + let mergeBase = strutils.strip(cc) if status == 0 and (mergeBase == currentCommit or mergeBase == requiredCommit): # conflict resolution: pick the later commit: if mergeBase == currentCommit: @@ -242,7 +253,7 @@ proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; tokens.add InvalidCommit elif tokens.len == 2 and tokens[1].startsWith("#"): # Dependencies can also look like 'requires "sdl2#head" - var commit = tokens[1] + var commit = tokens[1][1 .. ^1] tokens[1] = "==" tokens.add commit From 488e9c2991cd6f4ae946dd719271ea284a051891 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Jul 2021 03:42:45 -0700 Subject: [PATCH 2836/4254] nim doc now correctly renders deprecated pragmas for routines and types (#18515) --- compiler/ast.nim | 31 ++++++++++++++++++++ compiler/docgen.nim | 15 ++-------- compiler/renderer.nim | 4 +-- nimdoc/testproject/expected/testproject.html | 18 ++++++++++-- nimdoc/testproject/expected/testproject.idx | 1 + nimdoc/testproject/expected/theindex.html | 4 +++ nimdoc/testproject/testproject.nim | 3 ++ 7 files changed, 59 insertions(+), 17 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index f96e464af..f1f73dcee 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1168,6 +1168,37 @@ template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int] template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x +proc getDeclPragma*(n: PNode): PNode = + ## return the `nkPragma` node for declaration `n`, or `nil` if no pragma was found. + ## Currently only supports routineDefs + {nkTypeDef}. + case n.kind + of routineDefs: + if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos] + of nkTypeDef: + #[ + type F3*{.deprecated: "x3".} = int + + TypeSection + TypeDef + PragmaExpr + Postfix + Ident "*" + Ident "F3" + Pragma + ExprColonExpr + Ident "deprecated" + StrLit "x3" + Empty + Ident "int" + ]# + if n[0].kind == nkPragmaExpr: + result = n[0][1] + else: + # support as needed for `nkIdentDefs` etc. + result = nil + if result != nil: + assert result.kind == nkPragma, $(result.kind, n.kind) + when defined(useNodeIds): const nodeIdToDebug* = -1 # 2322968 var gNodeId: int diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 1ae00e22e..9c75c0a6f 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -764,14 +764,6 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string = result.add(defaultParamSeparator) result.add(params) -proc isCallable(n: PNode): bool = - ## Returns true if `n` contains a callable node. - case n.kind - of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, - nkConverterDef, nkFuncDef: result = true - else: - result = false - proc docstringSummary(rstText: string): string = ## Returns just the first line or a brief chunk of text from a rst string. ## @@ -862,9 +854,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = break plainName.add(literal) - var pragmaNode: PNode = nil - if n.isCallable and n[pragmasPos].kind != nkEmpty: - pragmaNode = findPragma(n[pragmasPos], wDeprecated) + var pragmaNode = getDeclPragma(n) + if pragmaNode != nil: pragmaNode = findPragma(pragmaNode, wDeprecated) inc(d.id) let @@ -920,7 +911,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = # because it doesn't include object fields or documentation comments. So we # use the plain one for callable elements, and the complex for the rest. var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": " - if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip)) + if n.kind in routineDefs: linkTitle.add(xmltree.escape(plainName.strip)) else: linkTitle.add(xmltree.escape(complexSymbol.strip)) setIndexTerm(d[], external, symbolOrId, name, linkTitle, diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ac3f47948..3346e629c 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -593,8 +593,8 @@ proc isHideable(config: ConfigRef, n: PNode): bool = # xxx compare `ident` directly with `getIdent(cache, wRaises)`, but # this requires a `cache`. case n.kind - of nkExprColonExpr: result = n[0].kind == nkIdent and n[0].ident.s in ["raises", "tags", "extern"] - of nkIdent: result = n.ident.s in ["gcsafe"] + of nkExprColonExpr: result = n[0].kind == nkIdent and n[0].ident.s in ["raises", "tags", "extern", "deprecated"] + of nkIdent: result = n.ident.s in ["gcsafe", "deprecated"] else: result = false proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 65d9f83f5..7e5a685d2 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -107,7 +107,9 @@ window.addEventListener('DOMContentLoaded', main);
  • Types
      -
    • FooBuzz
    • +
    • A
    • Types

      + +
      FooBuzz {....deprecated: "FooBuzz msg".} = int
      +
      +
      + Deprecated: FooBuzz msg +
      + + + +
      A {.inject.} = enum
         aA
      @@ -544,7 +556,7 @@ This should be visible. -
      proc baz[T](a, b: T): T {.deprecated.}
      +
      proc baz[T](a, b: T): T {....deprecated.}
      Deprecated @@ -554,7 +566,7 @@ This is deprecated without message.
      -
      proc buzz[T](a, b: T): T {.deprecated: "since v0.20".}
      +
      proc buzz[T](a, b: T): T {....deprecated: "since v0.20".}
      Deprecated: since v0.20 diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index a8cdc3be2..4d0e63c0c 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -6,6 +6,7 @@ C_D testproject.html#C_D testproject: C_D bar testproject.html#bar,T,T testproject: bar[T](a, b: T): T baz testproject.html#baz,T,T testproject: baz[T](a, b: T): T buzz testproject.html#buzz,T,T testproject: buzz[T](a, b: T): T +FooBuzz testproject.html#FooBuzz testproject: FooBuzz aVariable testproject.html#aVariable testproject: aVariable A testproject.html#A testproject: A B testproject.html#B testproject: B diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 55f7f33c9..cfaf6856d 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -179,6 +179,10 @@ window.addEventListener('DOMContentLoaded', main);
    • testproject: foo(a, b: SomeType)
    +
    FooBuzz:
    fromUtils1:
    • testproject: fromUtils1(): int
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index b88b41098..57960c69f 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -39,6 +39,9 @@ proc buzz*[T](a, b: T): T {.deprecated: "since v0.20".} = ## This is deprecated with a message. result = a + b +type + FooBuzz* {.deprecated: "FooBuzz msg".} = int + import std/macros var aVariable*: array[1, int] From bdfee32dc8e81dd6c727d711a7b1c1fad1728383 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 19 Jul 2021 18:43:31 +0800 Subject: [PATCH 2837/4254] close #18489 (#18524) --- tests/stdlib/tstrtabs2.nim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/stdlib/tstrtabs2.nim diff --git a/tests/stdlib/tstrtabs2.nim b/tests/stdlib/tstrtabs2.nim new file mode 100644 index 000000000..cb534f198 --- /dev/null +++ b/tests/stdlib/tstrtabs2.nim @@ -0,0 +1,15 @@ +discard """ + targets: "c cpp js" +""" + +import std/strtabs + +macro m = + var t = {"name": "John"}.newStringTable + doAssert t["name"] == "John" + +block: + var t = {"name": "John"}.newStringTable + doAssert t["name"] == "John" + +m() From 1e7a10001a8f823dddabf10b59e0ef9893716787 Mon Sep 17 00:00:00 2001 From: ynfle <23086821+ynfle@users.noreply.github.com> Date: Mon, 19 Jul 2021 13:44:06 +0300 Subject: [PATCH 2838/4254] Docs(manual): add clarification for default params (#18522) * Docs(manual): add clarification for default params * Docs(manual): fix wording to refer to call time * Docs(manual): Clarify default parameter wording Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- doc/manual.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 34781141e..f0bd85638 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3543,7 +3543,8 @@ separation of types and subsequent identifiers more distinct. proc foo(a; b: int; c, d: bool): int A parameter may be declared with a default value which is used if the caller -does not provide a value for the argument. +does not provide a value for the argument. The value will be reevaluated +every time the function is called. .. code-block:: nim # b is optional with 47 as its default value From 73ce40aaf71196faa08072216bd826a94b5d40b1 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 19 Jul 2021 12:45:13 +0200 Subject: [PATCH 2839/4254] Revert #17321 (#18521) Use better names in example --- lib/pure/collections/lists.nim | 270 ++++++++++++++++----------------- 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index c83be7aa3..af53bb68b 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -19,15 +19,15 @@ ## ## ## Lists runnableExamples: - var l = initDoublyLinkedList[int]() + var list = initDoublyLinkedList[int]() let a = newDoublyLinkedNode[int](3) b = newDoublyLinkedNode[int](7) c = newDoublyLinkedNode[int](9) - l.add(a) - l.add(b) - l.prepend(c) + list.add(a) + list.add(b) + list.prepend(c) assert a.next == b assert a.prev == c @@ -38,15 +38,15 @@ runnableExamples: ## ## Rings runnableExamples: - var l = initSinglyLinkedRing[int]() + var ring = initSinglyLinkedRing[int]() let a = newSinglyLinkedNode[int](3) b = newSinglyLinkedNode[int](7) c = newSinglyLinkedNode[int](9) - l.add(a) - l.add(b) - l.prepend(c) + ring.add(a) + ring.add(b) + ring.prepend(c) assert c.next == a assert a.next == b @@ -189,21 +189,21 @@ func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: ( result.add(elem) template itemsListImpl() {.dirty.} = - var it = list.head + var it = L.head while it != nil: yield it.value it = it.next template itemsRingImpl() {.dirty.} = - var it = ring.head + var it = L.head if it != nil: while true: yield it.value it = it.next - if it == ring.head: break + if it == L.head: break -iterator items*[T](list: SomeLinkedList[T]): T = - ## Yields every value of `list`. +iterator items*[T](L: SomeLinkedList[T]): T = + ## Yields every value of `L`. ## ## **See also:** ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_ @@ -218,8 +218,8 @@ iterator items*[T](list: SomeLinkedList[T]): T = itemsListImpl() -iterator items*[T](ring: SomeLinkedRing[T]): T = - ## Yields every value of `ring`. +iterator items*[T](L: SomeLinkedRing[T]): T = + ## Yields every value of `L`. ## ## **See also:** ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_ @@ -234,8 +234,8 @@ iterator items*[T](ring: SomeLinkedRing[T]): T = itemsRingImpl() -iterator mitems*[T](list: var SomeLinkedList[T]): var T = - ## Yields every value of `list` so that you can modify it. +iterator mitems*[T](L: var SomeLinkedList[T]): var T = + ## Yields every value of `L` so that you can modify it. ## ## **See also:** ## * `items iterator <#items.i,SomeLinkedList[T]>`_ @@ -251,8 +251,8 @@ iterator mitems*[T](list: var SomeLinkedList[T]): var T = itemsListImpl() -iterator mitems*[T](ring: var SomeLinkedRing[T]): var T = - ## Yields every value of `ring` so that you can modify it. +iterator mitems*[T](L: var SomeLinkedRing[T]): var T = + ## Yields every value of `L` so that you can modify it. ## ## **See also:** ## * `items iterator <#items.i,SomeLinkedRing[T]>`_ @@ -268,7 +268,7 @@ iterator mitems*[T](ring: var SomeLinkedRing[T]): var T = itemsRingImpl() -iterator nodes*[T](list: SomeLinkedList[T]): SomeLinkedNode[T] = +iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] = ## Iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. ## @@ -287,13 +287,13 @@ iterator nodes*[T](list: SomeLinkedList[T]): SomeLinkedNode[T] = x.value = 5 * x.value - 1 assert $a == "[49, 99, 199, 249]" - var it = list.head + var it = L.head while it != nil: let nxt = it.next yield it it = nxt -iterator nodes*[T](ring: SomeLinkedRing[T]): SomeLinkedNode[T] = +iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = ## Iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. ## @@ -312,27 +312,27 @@ iterator nodes*[T](ring: SomeLinkedRing[T]): SomeLinkedNode[T] = x.value = 5 * x.value - 1 assert $a == "[49, 99, 199, 249]" - var it = ring.head + var it = L.head if it != nil: while true: let nxt = it.next yield it it = nxt - if it == ring.head: break + if it == L.head: break -proc `$`*[T](l: SomeLinkedCollection[T]): string = +proc `$`*[T](L: SomeLinkedCollection[T]): string = ## Turns a list into its string representation for logging and printing. runnableExamples: let a = [1, 2, 3, 4].toSinglyLinkedList assert $a == "[1, 2, 3, 4]" result = "[" - for x in nodes(l): + for x in nodes(L): if result.len > 1: result.add(", ") result.addQuoted(x.value) result.add("]") -proc find*[T](l: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = +proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = ## Searches in the list for a value. Returns `nil` if the value does not ## exist. ## @@ -343,10 +343,10 @@ proc find*[T](l: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = assert a.find(9).value == 9 assert a.find(1) == nil - for x in nodes(l): + for x in nodes(L): if x.value == value: return x -proc contains*[T](l: SomeLinkedCollection[T], value: T): bool {.inline.} = +proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = ## Searches in the list for a value. Returns `false` if the value does not ## exist, `true` otherwise. This allows the usage of the `in` and `notin` ## operators. @@ -360,7 +360,7 @@ proc contains*[T](l: SomeLinkedCollection[T], value: T): bool {.inline.} = assert(not a.contains(1)) assert 2 notin a - result = find(l, value) != nil + result = find(L, value) != nil proc prepend*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = ## Prepends a shallow copy of `b` to the beginning of `a`. @@ -411,8 +411,8 @@ proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = (b, a) = (a, b) else: swap a, b -proc add*[T](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = - ## Appends (adds to the end) a node `n` to `list`. Efficiency: O(1). +proc add*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = + ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value @@ -426,14 +426,14 @@ proc add*[T](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = assert a.contains(9) n.next = nil - if list.tail != nil: - assert(list.tail.next == nil) - list.tail.next = n - list.tail = n - if list.head == nil: list.head = n + if L.tail != nil: + assert(L.tail.next == nil) + L.tail.next = n + L.tail = n + if L.head == nil: L.head = n -proc add*[T](list: var SinglyLinkedList[T], value: T) {.inline.} = - ## Appends (adds to the end) a value to `list`. Efficiency: O(1). +proc add*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = + ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value @@ -446,11 +446,11 @@ proc add*[T](list: var SinglyLinkedList[T], value: T) {.inline.} = a.add(8) assert a.contains(9) - add(list, newSinglyLinkedNode(value)) + add(L, newSinglyLinkedNode(value)) -proc prepend*[T](list: var SinglyLinkedList[T], +proc prepend*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = - ## Prepends (adds to the beginning) a node to `list`. Efficiency: O(1). + ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ @@ -463,12 +463,12 @@ proc prepend*[T](list: var SinglyLinkedList[T], a.prepend(n) assert a.contains(9) - n.next = list.head - list.head = n - if list.tail == nil: list.tail = n + n.next = L.head + L.head = n + if L.tail == nil: L.tail = n -proc prepend*[T](list: var SinglyLinkedList[T], value: T) {.inline.} = - ## Prepends (adds to the beginning) a node to `list`. Efficiency: O(1). +proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = + ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ @@ -482,7 +482,7 @@ proc prepend*[T](list: var SinglyLinkedList[T], value: T) {.inline.} = a.prepend(8) assert a.contains(9) - prepend(list, newSinglyLinkedNode(value)) + prepend(L, newSinglyLinkedNode(value)) func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = ## Creates a shallow copy of `a`. @@ -540,8 +540,8 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = b.head = nil b.tail = nil -proc add*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = - ## Appends (adds to the end) a node `n` to `list`. Efficiency: O(1). +proc add*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = + ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedList[T],T>`_ for appending a value @@ -557,15 +557,15 @@ proc add*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = assert a.contains(9) n.next = nil - n.prev = list.tail - if list.tail != nil: - assert(list.tail.next == nil) - list.tail.next = n - list.tail = n - if list.head == nil: list.head = n + n.prev = L.tail + if L.tail != nil: + assert(L.tail.next == nil) + L.tail.next = n + L.tail = n + if L.head == nil: L.head = n -proc add*[T](list: var DoublyLinkedList[T], value: T) = - ## Appends (adds to the end) a value to `list`. Efficiency: O(1). +proc add*[T](L: var DoublyLinkedList[T], value: T) = + ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ @@ -581,10 +581,10 @@ proc add*[T](list: var DoublyLinkedList[T], value: T) = a.add(8) assert a.contains(9) - add(list, newDoublyLinkedNode(value)) + add(L, newDoublyLinkedNode(value)) -proc prepend*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = - ## Prepends (adds to the beginning) a node `n` to `list`. Efficiency: O(1). +proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = + ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ @@ -600,15 +600,15 @@ proc prepend*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = assert a.contains(9) n.prev = nil - n.next = list.head - if list.head != nil: - assert(list.head.prev == nil) - list.head.prev = n - list.head = n - if list.tail == nil: list.tail = n + n.next = L.head + if L.head != nil: + assert(L.head.prev == nil) + L.head.prev = n + L.head = n + if L.tail == nil: L.tail = n -proc prepend*[T](list: var DoublyLinkedList[T], value: T) = - ## Prepends (adds to the beginning) a value to `list`. Efficiency: O(1). +proc prepend*[T](L: var DoublyLinkedList[T], value: T) = + ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ @@ -624,7 +624,7 @@ proc prepend*[T](list: var DoublyLinkedList[T], value: T) = a.prepend(8) assert a.contains(9) - prepend(list, newDoublyLinkedNode(value)) + prepend(L, newDoublyLinkedNode(value)) func copy*[T](a: DoublyLinkedList[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = ## Creates a shallow copy of `a`. @@ -705,9 +705,9 @@ proc add*[T: SomeLinkedList](a: var T, b: T) {.since: (1, 5, 1).} = var tmp = b.copy a.addMoved(tmp) -proc remove*[T](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.discardable.} = - ## Removes a node `n` from `list`. - ## Returns `true` if `n` was found in `list`. +proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.discardable.} = + ## Removes a node `n` from `L`. + ## Returns `true` if `n` was found in `L`. ## Efficiency: O(n); the list is traversed until `n` is found. ## Attempting to remove an element not contained in the list is a no-op. ## When the list is cyclic, the cycle is preserved after removal. @@ -728,12 +728,12 @@ proc remove*[T](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.d ai assert s == [2, 2, 2, 2] - if n == list.head: - list.head = n.next - if list.tail.next == n: - list.tail.next = list.head # restore cycle + if n == L.head: + L.head = n.next + if L.tail.next == n: + L.tail.next = L.head # restore cycle else: - var prev = list.head + var prev = L.head while prev.next != n and prev.next != nil: prev = prev.next if prev.next == nil: @@ -741,9 +741,9 @@ proc remove*[T](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.d prev.next = n.next true -proc remove*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = - ## Removes a node `n` from `list`. Efficiency: O(1). - ## This function assumes, for the sake of efficiency, that `n` is contained in `list`, +proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = + ## Removes a node `n` from `L`. Efficiency: O(1). + ## This function assumes, for the sake of efficiency, that `n` is contained in `L`, ## otherwise the effects are undefined. ## When the list is cyclic, the cycle is preserved after removal. runnableExamples: @@ -763,15 +763,15 @@ proc remove*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ai assert s == [2, 2, 2, 2] - if n == list.tail: list.tail = n.prev - if n == list.head: list.head = n.next + if n == L.tail: L.tail = n.prev + if n == L.head: L.head = n.next if n.next != nil: n.next.prev = n.prev if n.prev != nil: n.prev.next = n.next -proc add*[T](ring: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = - ## Appends (adds to the end) a node `n` to `ring`. Efficiency: O(1). +proc add*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = + ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value @@ -784,17 +784,17 @@ proc add*[T](ring: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = a.add(n) assert a.contains(9) - if ring.head != nil: - n.next = ring.head - assert(ring.tail != nil) - ring.tail.next = n + if L.head != nil: + n.next = L.head + assert(L.tail != nil) + L.tail.next = n else: n.next = n - ring.head = n - ring.tail = n + L.head = n + L.tail = n -proc add*[T](ring: var SinglyLinkedRing[T], value: T) = - ## Appends (adds to the end) a value to `ring`. Efficiency: O(1). +proc add*[T](L: var SinglyLinkedRing[T], value: T) = + ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ @@ -808,10 +808,10 @@ proc add*[T](ring: var SinglyLinkedRing[T], value: T) = a.add(8) assert a.contains(9) - add(ring, newSinglyLinkedNode(value)) + add(L, newSinglyLinkedNode(value)) -proc prepend*[T](ring: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = - ## Prepends (adds to the beginning) a node `n` to `ring`. Efficiency: O(1). +proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = + ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ @@ -824,17 +824,17 @@ proc prepend*[T](ring: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = a.prepend(n) assert a.contains(9) - if ring.head != nil: - n.next = ring.head - assert(ring.tail != nil) - ring.tail.next = n + if L.head != nil: + n.next = L.head + assert(L.tail != nil) + L.tail.next = n else: n.next = n - ring.tail = n - ring.head = n + L.tail = n + L.head = n -proc prepend*[T](ring: var SinglyLinkedRing[T], value: T) = - ## Prepends (adds to the beginning) a value to `ring`. Efficiency: O(1). +proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = + ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ @@ -848,12 +848,12 @@ proc prepend*[T](ring: var SinglyLinkedRing[T], value: T) = a.prepend(8) assert a.contains(9) - prepend(ring, newSinglyLinkedNode(value)) + prepend(L, newSinglyLinkedNode(value)) -proc add*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = - ## Appends (adds to the end) a node `n` to `ring`. Efficiency: O(1). +proc add*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = + ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedRing[T],T>`_ for appending a value @@ -868,18 +868,18 @@ proc add*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = a.add(n) assert a.contains(9) - if ring.head != nil: - n.next = ring.head - n.prev = ring.head.prev - ring.head.prev.next = n - ring.head.prev = n + if L.head != nil: + n.next = L.head + n.prev = L.head.prev + L.head.prev.next = n + L.head.prev = n else: n.prev = n n.next = n - ring.head = n + L.head = n -proc add*[T](ring: var DoublyLinkedRing[T], value: T) = - ## Appends (adds to the end) a value to `ring`. Efficiency: O(1). +proc add*[T](L: var DoublyLinkedRing[T], value: T) = + ## Appends (adds to the end) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ @@ -895,10 +895,10 @@ proc add*[T](ring: var DoublyLinkedRing[T], value: T) = a.add(8) assert a.contains(9) - add(ring, newDoublyLinkedNode(value)) + add(L, newDoublyLinkedNode(value)) -proc prepend*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = - ## Prepends (adds to the beginning) a node `n` to `ring`. Efficiency: O(1). +proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = + ## Prepends (adds to the beginning) a node `n` to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ @@ -913,18 +913,18 @@ proc prepend*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = a.prepend(n) assert a.contains(9) - if ring.head != nil: - n.next = ring.head - n.prev = ring.head.prev - ring.head.prev.next = n - ring.head.prev = n + if L.head != nil: + n.next = L.head + n.prev = L.head.prev + L.head.prev.next = n + L.head.prev = n else: n.prev = n n.next = n - ring.head = n + L.head = n -proc prepend*[T](ring: var DoublyLinkedRing[T], value: T) = - ## Prepends (adds to the beginning) a value to `ring`. Efficiency: O(1). +proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = + ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). ## ## **See also:** ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ @@ -940,11 +940,11 @@ proc prepend*[T](ring: var DoublyLinkedRing[T], value: T) = a.prepend(8) assert a.contains(9) - prepend(ring, newDoublyLinkedNode(value)) + prepend(L, newDoublyLinkedNode(value)) -proc remove*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = - ## Removes `n` from `ring`. Efficiency: O(1). - ## This function assumes, for the sake of efficiency, that `n` is contained in `ring`, +proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = + ## Removes `n` from `L`. Efficiency: O(1). + ## This function assumes, for the sake of efficiency, that `n` is contained in `L`, ## otherwise the effects are undefined. runnableExamples: var a = initDoublyLinkedRing[int]() @@ -956,13 +956,13 @@ proc remove*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = n.next.prev = n.prev n.prev.next = n.next - if n == ring.head: - let p = ring.head.prev - if p == ring.head: + if n == L.head: + let p = L.head.prev + if p == L.head: # only one element left: - ring.head = nil + L.head = nil else: - ring.head = p + L.head = p proc append*[T](a: var (SinglyLinkedList[T] | SinglyLinkedRing[T]), b: SinglyLinkedList[T] | SinglyLinkedNode[T] | T) = From db6e7fffba021c223fc67e1c0853e5839cd256d2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 19 Jul 2021 20:07:47 -0700 Subject: [PATCH 2840/4254] minor clenup in vmops (#18529) --- compiler/vmops.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 67a196b8f..283306ecc 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -150,6 +150,9 @@ when defined(nimHasInvariant): of cincludes: copySeq(conf.cIncludes) of clibs: copySeq(conf.cLibs) +proc stackTrace2(c: PCtx, msg: string, n: PNode) = + stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info) + proc registerAdditionalOps*(c: PCtx) = proc gorgeExWrapper(a: VmArgs) = let ret = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), @@ -238,15 +241,13 @@ proc registerAdditionalOps*(c: PCtx) = registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) = let n = getNode(a, 0) if n.kind != nkSym: - stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, - "symBodyHash() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info) + stackTrace2(c, "symBodyHash() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n) setResult(a, $symBodyDigest(c.graph, n.sym)) registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) = let n = getNode(a, 0) if n.kind != nkSym: - stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, - "isExported() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info) + stackTrace2(c, "isExported() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n) setResult(a, sfExported in n.sym.flags) registerCallback c, "stdlib.vmutils.vmTrace", proc (a: VmArgs) = From 44c5afe448ecd9a7009982c16ec85fc8cabe3124 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 20 Jul 2021 11:14:04 +0800 Subject: [PATCH 2841/4254] [std/os]document `checkDir` and use `runnableExamples` (#18517) Co-authored-by: Timothee Cour --- lib/pure/os.nim | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index dadc380e6..6289c64f0 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -10,27 +10,14 @@ ## This module contains basic operating system facilities like ## retrieving environment variables, reading command line arguments, ## working with directories, running shell commands, etc. -## -## .. code-block:: -## import std/os -## -## let myFile = "/path/to/my/file.nim" -## -## let pathSplit = splitPath(myFile) -## assert pathSplit.head == "/path/to/my" -## assert pathSplit.tail == "file.nim" -## -## assert parentDir(myFile) == "/path/to/my" -## -## let fileSplit = splitFile(myFile) -## assert fileSplit.dir == "/path/to/my" -## assert fileSplit.name == "file" -## assert fileSplit.ext == ".nim" -## -## assert myFile.changeFileExt("c") == "/path/to/my/file.c" -## -## +runnableExamples("-r:off"): + let myFile = "/path/to/my/file.nim" + assert splitPath(myFile) == (head: "/path/to/my", tail: "file.nim") + assert parentDir(myFile) == "/path/to/my" + assert splitFile(myFile) == (dir: "/path/to/my", name: "file", ext: ".nim") + assert myFile.changeFileExt("c") == "/path/to/my/file.c" + ## **See also:** ## * `osproc module `_ for process communication beyond ## `execShellCmd proc <#execShellCmd,string>`_ @@ -2286,6 +2273,10 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): ## ## Walking is not recursive. If ``relative`` is true (default: false) ## the resulting path is shortened to be relative to ``dir``. + ## + ## If `checkDir` is true, `OSError` is raised when `dir` + ## doesn't exist. + ## ## Example: This directory structure:: ## dirA / dirB / fileB1.txt ## / dirC @@ -2385,6 +2376,9 @@ iterator walkDirRec*(dir: string, ## If ``relative`` is true (default: false) the resulting path is ## shortened to be relative to ``dir``, otherwise the full path is returned. ## + ## If `checkDir` is true, `OSError` is raised when `dir` + ## doesn't exist. + ## ## .. warning:: Modifying the directory structure while the iterator ## is traversing may result in undefined behavior! ## @@ -2448,7 +2442,7 @@ proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ ## in `dir` (recursively). ## ## If this fails, `OSError` is raised. This does not fail if the directory never - ## existed in the first place, unless `checkDir` = true + ## existed in the first place, unless `checkDir` = true. ## ## See also: ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ From 8c7ee96457769a8c8aa1d4bab306b53acf306c8e Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 20 Jul 2021 09:32:22 +0300 Subject: [PATCH 2842/4254] rst: add missing line/column info for some warnings (#18383) * rst: add missing line/column info for some warnings * add workaround * use TLineInfo/FileIndex for storing file names * fix blank lines in include file (rm harmful strip) * don't use ref TLineInfo * return `hasToc` as output parameter for uniformity * Update compiler/docgen.nim Co-authored-by: Timothee Cour * Update compiler/docgen.nim Co-authored-by: Timothee Cour * Update lib/packages/docutils/rst.nim Co-authored-by: Timothee Cour * address review - stylistic things * Update compiler/docgen.nim Co-authored-by: Timothee Cour * unify RST warnings/errors names * doAssert + minor name change * fix a bug caught by doAssert * apply strbasics.strip to final HTML/Latex * rm redundant filename * fix test after rebase * delete `order` from rnFootnoteRef, also display errors/warnings properly when footnote references are from different files * Update compiler/lineinfos.nim Co-authored-by: Timothee Cour * Update lib/packages/docutils/rstast.nim Co-authored-by: Timothee Cour * Update lib/packages/docutils/rstast.nim Co-authored-by: Timothee Cour * Update lib/packages/docutils/rstast.nim Co-authored-by: Timothee Cour * revert because of error: Error: cannot prove that it's safe to initialize 'info' with the runtime value for the discriminator 'kind' * Update lib/packages/docutils/rstgen.nim Co-authored-by: Timothee Cour * apply suggestion * Update lib/packages/docutils/rst.nim Co-authored-by: Timothee Cour * add Table for string->file name mapping * do not import compiler/lineinfos * fix ambiguous calls Co-authored-by: Timothee Cour Co-authored-by: narimiran --- compiler/docgen.nim | 54 ++++----- compiler/lineinfos.nim | 49 +++++---- compiler/main.nim | 11 +- lib/packages/docutils/rst.nim | 181 ++++++++++++++++++++----------- lib/packages/docutils/rstast.nim | 20 +++- lib/packages/docutils/rstgen.nim | 40 +++---- tests/stdlib/trst.nim | 58 +++++++++- tests/stdlib/trstgen.nim | 122 ++++++++++++--------- 8 files changed, 342 insertions(+), 193 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 9c75c0a6f..f9e72850a 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -12,11 +12,12 @@ import ast, strutils, strtabs, options, msgs, os, idents, - wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, + wordrecg, syntaxes, renderer, lexer, packages/docutils/rst, packages/docutils/rstgen, json, xmltree, trees, types, typesrenderer, astalgo, lineinfos, intsets, pathutils, tables, nimpaths, renderverbatim, osproc +import packages/docutils/rstast except FileIndex, TLineInfo from uri import encodeUrl from std/private/globs import nativeToUnixPath @@ -159,17 +160,18 @@ template declareClosures = case msgKind of meCannotOpenFile: k = errCannotOpenFile of meExpected: k = errXExpected - of meGridTableNotImplemented: k = errGridTableNotImplemented - of meMarkdownIllformedTable: k = errMarkdownIllformedTable - of meNewSectionExpected: k = errNewSectionExpected - of meGeneralParseError: k = errGeneralParseError - of meInvalidDirective: k = errInvalidDirectiveX - of meInvalidRstField: k = errInvalidRstField - of meFootnoteMismatch: k = errFootnoteMismatch - of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel - of mwUnknownSubstitution: k = warnUnknownSubstitutionX - of mwUnsupportedLanguage: k = warnLanguageXNotSupported - of mwUnsupportedField: k = warnFieldXNotSupported + of meGridTableNotImplemented: k = errRstGridTableNotImplemented + of meMarkdownIllformedTable: k = errRstMarkdownIllformedTable + of meNewSectionExpected: k = errRstNewSectionExpected + of meGeneralParseError: k = errRstGeneralParseError + of meInvalidDirective: k = errRstInvalidDirectiveX + of meInvalidField: k = errRstInvalidField + of meFootnoteMismatch: k = errRstFootnoteMismatch + of mwRedefinitionOfLabel: k = warnRstRedefinitionOfLabel + of mwUnknownSubstitution: k = warnRstUnknownSubstitutionX + of mwBrokenLink: k = warnRstBrokenLink + of mwUnsupportedLanguage: k = warnRstLanguageXNotSupported + of mwUnsupportedField: k = warnRstFieldXNotSupported of mwRstStyle: k = warnRstStyle {.gcsafe.}: globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg) @@ -182,11 +184,9 @@ template declareClosures = proc parseRst(text, filename: string, line, column: int, - rstOptions: RstParseOptions; conf: ConfigRef, sharedState: PRstSharedState): PRstNode = declareClosures() - result = rstParsePass1(text, filename, line, column, rstOptions, - sharedState) + result = rstParsePass1(text, line, column, sharedState) proc getOutFile2(conf: ConfigRef; filename: RelativeFile, ext: string, guessTarget: bool): AbsoluteFile = @@ -202,20 +202,22 @@ proc getOutFile2(conf: ConfigRef; filename: RelativeFile, proc isLatexCmd(conf: ConfigRef): bool = conf.cmd in {cmdRst2tex, cmdDoc2tex} proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, - outExt: string = HtmlExt, module: PSym = nil): PDoc = + outExt: string = HtmlExt, module: PSym = nil, + isPureRst = false): PDoc = declareClosures() new(result) result.module = module result.conf = conf result.cache = cache result.outDir = conf.outDir.string - const options = {roSupportRawDirective, roSupportMarkdown, - roPreferMarkdown, roNimFile} + result.isPureRst = isPureRst + var options= {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown} + if not isPureRst: options.incl roNimFile result.sharedState = newRstSharedState( options, filename.string, docgenFindFile, compilerMsgHandler) initRstGenerator(result[], (if conf.isLatexCmd: outLatex else: outHtml), - conf.configVars, filename.string, options, + conf.configVars, filename.string, docgenFindFile, compilerMsgHandler) if conf.configVars.hasKey("doc.googleAnalytics"): @@ -299,8 +301,7 @@ proc genComment(d: PDoc, n: PNode): PRstNode = result = parseRst(n.comment, toFullPath(d.conf, n.info), toLinenumber(n.info), toColumn(n.info) + DocColOffset, - d.options, d.conf, - d.sharedState) + d.conf, d.sharedState) proc genRecCommentAux(d: PDoc, n: PNode): PRstNode = if n == nil: return nil @@ -1123,6 +1124,9 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = proc finishGenerateDoc*(d: var PDoc) = ## Perform 2nd RST pass for resolution of links/footnotes/headings... + # copy file map `filenames` to ``rstgen.nim`` for its warnings + d.filenames = d.sharedState.filenames + # Main title/subtitle are allowed only in the first RST fragment of document var firstRst = PRstNode(nil) for fragment in d.modDescPre: @@ -1417,14 +1421,10 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) = proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename: AbsoluteFile, outExt: string) = var filen = addFileExt(filename, "txt") - var d = newDocumentor(filen, cache, conf, outExt) - - d.isPureRst = true + var d = newDocumentor(filen, cache, conf, outExt, isPureRst = true) let rst = parseRst(readFile(filen.string), filen.string, line=LineRstInit, column=ColRstInit, - {roSupportRawDirective, roSupportMarkdown, - roPreferMarkdown}, conf, - d.sharedState) + conf, d.sharedState) d.modDescPre = @[ItemFragment(isRst: true, rst: rst)] finishGenerateDoc(d) writeOutput(d) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 801c20d25..8ab52a452 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -32,13 +32,13 @@ type # non-fatal errors errIllFormedAstX, errCannotOpenFile, errXExpected, - errGridTableNotImplemented, - errMarkdownIllformedTable, - errGeneralParseError, - errNewSectionExpected, - errInvalidDirectiveX, - errInvalidRstField, - errFootnoteMismatch, + errRstGridTableNotImplemented, + errRstMarkdownIllformedTable, + errRstNewSectionExpected, + errRstGeneralParseError, + errRstInvalidDirectiveX, + errRstInvalidField, + errRstFootnoteMismatch, errProveInit, # deadcode errGenerated, errUser, @@ -47,10 +47,13 @@ type warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit", warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated", warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", - warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX", - warnLanguageXNotSupported = "LanguageXNotSupported", - warnFieldXNotSupported = "FieldXNotSupported", - warnRstStyle = "warnRstStyle", warnCommentXIgnored = "CommentXIgnored", + warnRstRedefinitionOfLabel = "RedefinitionOfLabel", + warnRstUnknownSubstitutionX = "UnknownSubstitutionX", + warnRstBrokenLink = "BrokenLink", + warnRstLanguageXNotSupported = "LanguageXNotSupported", + warnRstFieldXNotSupported = "FieldXNotSupported", + warnRstStyle = "warnRstStyle", + warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam", warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap", warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport", @@ -93,13 +96,13 @@ const errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open '$1'", errXExpected: "'$1' expected", - errGridTableNotImplemented: "grid table is not implemented", - errMarkdownIllformedTable: "illformed delimiter row of a markdown table", - errGeneralParseError: "general parse error", - errNewSectionExpected: "new section expected $1", - errInvalidDirectiveX: "invalid directive: '$1'", - errInvalidRstField: "invalid field: $1", - errFootnoteMismatch: "number of footnotes and their references don't match: $1", + errRstGridTableNotImplemented: "grid table is not implemented", + errRstMarkdownIllformedTable: "illformed delimiter row of a markdown table", + errRstNewSectionExpected: "new section expected $1", + errRstGeneralParseError: "general parse error", + errRstInvalidDirectiveX: "invalid directive: '$1'", + errRstInvalidField: "invalid field: $1", + errRstFootnoteMismatch: "number of footnotes and their references don't match: $1", errProveInit: "Cannot prove that '$1' is initialized.", # deadcode errGenerated: "$1", errUser: "$1", @@ -111,10 +114,11 @@ const warnConfigDeprecated: "config file '$1' is deprecated", warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", warnUnknownMagic: "unknown magic '$1' might crash the compiler", - warnRedefinitionOfLabel: "redefinition of label '$1'", - warnUnknownSubstitutionX: "unknown substitution '$1'", - warnLanguageXNotSupported: "language '$1' not supported", - warnFieldXNotSupported: "field '$1' not supported", + warnRstRedefinitionOfLabel: "redefinition of label '$1'", + warnRstUnknownSubstitutionX: "unknown substitution '$1'", + warnRstBrokenLink: "broken link '$1'", + warnRstLanguageXNotSupported: "language '$1' not supported", + warnRstFieldXNotSupported: "field '$1' not supported", warnRstStyle: "RST style: $1", warnCommentXIgnored: "comment '$1' ignored", warnTypelessParam: "", # deadcode @@ -196,6 +200,7 @@ const warnMax* = pred(hintSuccess) hintMin* = hintSuccess hintMax* = high(TMsgKind) + rstWarnings* = {warnRstRedefinitionOfLabel..warnRstStyle} type TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints diff --git a/compiler/main.nim b/compiler/main.nim index 1c8034c6c..e4ec4d729 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -285,7 +285,7 @@ proc mainCommand*(graph: ModuleGraph) = of cmdDoc: docLikeCmd(): conf.setNoteDefaults(warnLockLevel, false) # issue #13218 - conf.setNoteDefaults(warnRedefinitionOfLabel, false) # issue #13218 + conf.setNoteDefaults(warnRstRedefinitionOfLabel, false) # issue #13218 # because currently generates lots of false positives due to conflation # of labels links in doc comments, e.g. for random.rand: # ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer @@ -295,19 +295,16 @@ proc mainCommand*(graph: ModuleGraph) = commandBuildIndex(conf, $conf.outDir) of cmdRst2html: # XXX: why are warnings disabled by default for rst2html and rst2tex? - for warn in [warnUnknownSubstitutionX, warnLanguageXNotSupported, - warnFieldXNotSupported, warnRstStyle]: + for warn in rstWarnings: conf.setNoteDefaults(warn, true) - conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218 + conf.setNoteDefaults(warnRstRedefinitionOfLabel, false) # similar to issue #13218 when defined(leanCompiler): conf.quitOrRaise "compiler wasn't built with documentation generator" else: loadConfigs(DocConfig, cache, conf, graph.idgen) commandRst2Html(cache, conf) of cmdRst2tex, cmdDoc2tex: - for warn in [warnRedefinitionOfLabel, warnUnknownSubstitutionX, - warnLanguageXNotSupported, - warnFieldXNotSupported, warnRstStyle]: + for warn in rstWarnings: conf.setNoteDefaults(warn, true) when defined(leanCompiler): conf.quitOrRaise "compiler wasn't built with documentation generator" diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 9abdf3fc3..abea026dd 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -196,7 +196,7 @@ import os, strutils, rstast, std/enumutils, algorithm, lists, sequtils, - std/private/miscdollars + std/private/miscdollars, tables from highlite import SourceLanguage, getSourceLanguage type @@ -217,6 +217,7 @@ type mcWarning = "Warning", mcError = "Error" + # keep the order in sync with compiler/docgen.nim and compiler/lineinfos.nim: MsgKind* = enum ## the possible messages meCannotOpenFile = "cannot open '$1'", meExpected = "'$1' expected", @@ -225,10 +226,11 @@ type meNewSectionExpected = "new section expected $1", meGeneralParseError = "general parse error", meInvalidDirective = "invalid directive: '$1'", - meInvalidRstField = "invalid field: $1", + meInvalidField = "invalid field: $1", meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1", mwRedefinitionOfLabel = "redefinition of label '$1'", mwUnknownSubstitution = "unknown substitution '$1'", + mwBrokenLink = "broken link '$1'", mwUnsupportedLanguage = "language '$1' not supported", mwUnsupportedField = "field '$1' not supported", mwRstStyle = "RST style: $1" @@ -489,7 +491,9 @@ type autoNumIdx: int # order of occurence: fnAutoNumber, fnAutoNumberLabel autoSymIdx: int # order of occurence: fnAutoSymbol label: string # valid for fnAutoNumberLabel - + RstFileTable* = object + filenameToIdx*: Table[string, FileIndex] + idxToFilename*: seq[string] RstSharedState = object options: RstParseOptions # parsing options hLevels: LevelMap # hierarchy of heading styles @@ -501,15 +505,19 @@ type subs: seq[Substitution] # substitutions refs*: seq[Substitution] # references anchors*: seq[AnchorSubst] # internal target substitutions - lineFootnoteNum: seq[int] # footnote line, auto numbers .. [#] - lineFootnoteNumRef: seq[int] # footnote line, their reference [#]_ - lineFootnoteSym: seq[int] # footnote line, auto symbols .. [*] - lineFootnoteSymRef: seq[int] # footnote line, their reference [*]_ + lineFootnoteNum: seq[TLineInfo] # footnote line, auto numbers .. [#] + lineFootnoteNumRef: seq[TLineInfo] # footnote line, their reference [#]_ + currFootnoteNumRef: int # ... their counter for `resolveSubs` + lineFootnoteSym: seq[TLineInfo] # footnote line, auto symbols .. [*] + lineFootnoteSymRef: seq[TLineInfo] # footnote line, their reference [*]_ + currFootnoteSymRef: int # ... their counter for `resolveSubs` footnotes: seq[FootnoteSubst] # correspondence b/w footnote label, # number, order of occurrence msgHandler: MsgHandler # How to handle errors. findFile: FindFileHandler # How to find files. - filename: string + filenames*: RstFileTable # map file name <-> FileIndex (for storing + # file names for warnings after 1st stage) + currFileIdx: FileIndex # current index in `filesnames` hasToc*: bool PRstSharedState* = ref RstSharedState @@ -579,6 +587,25 @@ proc whichRoleAux(sym: string): RstNodeKind = else: # unknown role result = rnUnknownRole +proc len(filenames: RstFileTable): int = filenames.idxToFilename.len + +proc setCurrFilename(s: PRstSharedState, file1: string) = + let nextIdx = s.filenames.len.FileIndex + let v = getOrDefault(s.filenames.filenameToIdx, file1, default = nextIdx) + if v == nextIdx: + s.filenames.filenameToIdx[file1] = v + s.filenames.idxToFilename.add file1 + s.currFileIdx = v + +proc getFilename(filenames: RstFileTable, fid: FileIndex): string = + doAssert(0 <= fid.int and fid.int < filenames.len, + "incorrect FileIndex $1 (range 0..$2)" % [ + $fid.int, $(filenames.len - 1)]) + result = filenames.idxToFilename[fid.int] + +proc currFilename(s: PRstSharedState): string = + getFilename(s.filenames, s.currFileIdx) + proc newRstSharedState*(options: RstParseOptions, filename: string, findFile: FindFileHandler, @@ -589,32 +616,37 @@ proc newRstSharedState*(options: RstParseOptions, currRoleKind: whichRoleAux(r), options: options, msgHandler: if not isNil(msgHandler): msgHandler else: defaultMsgHandler, - filename: filename, findFile: if not isNil(findFile): findFile else: defaultFindFile ) + setCurrFilename(result, filename) proc curLine(p: RstParser): int = p.line + currentTok(p).line proc findRelativeFile(p: RstParser; filename: string): string = - result = p.s.filename.splitFile.dir / filename + result = p.s.currFilename.splitFile.dir / filename if not fileExists(result): result = p.s.findFile(filename) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = - p.s.msgHandler(p.s.filename, curLine(p), + p.s.msgHandler(p.s.currFilename, curLine(p), p.col + currentTok(p).col, msgKind, arg) proc rstMessage(s: PRstSharedState, msgKind: MsgKind, arg: string) = - ## Print warnings for footnotes/substitutions. - ## TODO: their line/column info is not known, to fix it. - s.msgHandler(s.filename, LineRstInit, ColRstInit, msgKind, arg) + s.msgHandler(s.currFilename, LineRstInit, ColRstInit, msgKind, arg) + +proc rstMessage*(filenames: RstFileTable, f: MsgHandler, + info: TLineInfo, msgKind: MsgKind, arg: string) = + ## Print warnings using `info`, i.e. in 2nd-pass warnings for + ## footnotes/substitutions/references or from ``rstgen.nim``. + let file = getFilename(filenames, info.fileIndex) + f(file, info.line.int, info.col.int, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) = - p.s.msgHandler(p.s.filename, p.line + line, + p.s.msgHandler(p.s.currFilename, p.line + line, p.col + col, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind) = - p.s.msgHandler(p.s.filename, curLine(p), + p.s.msgHandler(p.s.currFilename, curLine(p), p.col + currentTok(p).col, msgKind, currentTok(p).symbol) @@ -827,11 +859,18 @@ proc addFootnoteNumManual(p: var RstParser, num: int) = return p.s.footnotes.add((fnManualNumber, num, -1, -1, $num)) +proc lineInfo(p: RstParser, iTok: int): TLineInfo = + result.col = int16(p.col + p.tok[iTok].col) + result.line = uint16(p.line + p.tok[iTok].line) + result.fileIndex = p.s.currFileIdx + +proc lineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx) + proc addFootnoteNumAuto(p: var RstParser, label: string) = ## add auto-numbered footnote. ## Empty label [#] means it'll be resolved by the occurrence. if label == "": # simple auto-numbered [#] - p.s.lineFootnoteNum.add curLine(p) + p.s.lineFootnoteNum.add lineInfo(p) p.s.footnotes.add((fnAutoNumber, -1, p.s.lineFootnoteNum.len, -1, label)) else: # auto-numbered with label [#label] for fnote in p.s.footnotes: @@ -841,7 +880,7 @@ proc addFootnoteNumAuto(p: var RstParser, label: string) = p.s.footnotes.add((fnAutoNumberLabel, -1, -1, -1, label)) proc addFootnoteSymAuto(p: var RstParser) = - p.s.lineFootnoteSym.add curLine(p) + p.s.lineFootnoteSym.add lineInfo(p) p.s.footnotes.add((fnAutoSymbol, -1, -1, p.s.lineFootnoteSym.len, "")) proc orderFootnotes(s: PRstSharedState) = @@ -850,7 +889,15 @@ proc orderFootnotes(s: PRstSharedState) = ## Save the result back to `s.footnotes`. # Report an error if found any mismatch in number of automatic footnotes - proc listFootnotes(lines: seq[int]): string = + proc listFootnotes(locations: seq[TLineInfo]): string = + var lines: seq[string] + for info in locations: + if s.filenames.len > 1: + let file = getFilename(s.filenames, info.fileIndex) + lines.add file & ":" + else: # no need to add file name here if there is only 1 + lines.add "" + lines[^1].add $info.line result.add $lines.len & " (lines " & join(lines, ", ") & ")" if s.lineFootnoteNum.len != s.lineFootnoteNumRef.len: rstMessage(s, meFootnoteMismatch, @@ -1157,7 +1204,7 @@ proc whichRole(p: RstParser, sym: string): RstNodeKind = proc toInlineCode(n: PRstNode, language: string): PRstNode = ## Creates rnInlineCode and attaches `n` contents as code (in 3rd son). - result = newRstNode(rnInlineCode) + result = newRstNode(rnInlineCode, info=n.info) let args = newRstNode(rnDirArg) var lang = language if language == "cpp": lang = "c++" @@ -1179,6 +1226,7 @@ proc toOtherRole(n: PRstNode, kind: RstNodeKind, roleName: string): PRstNode = result = newRstNode(kind, newSons) proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = + ## Finalizes node `n` that was tentatively determined as interpreted text. var newKind = n.kind var newSons = n.sons @@ -1207,12 +1255,10 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = newKind = rnHyperlink newSons = @[a, b] setRef(p, rstnodeToRefname(a), b) - elif n.kind == rnInterpretedText: + result = newRstNode(newKind, newSons) + else: # some link that will be resolved in `resolveSubs` newKind = rnRef - else: - newKind = rnRef - newSons = @[n] - result = newRstNode(newKind, newSons) + result = newRstNode(newKind, sons=newSons, info=n.info) elif match(p, p.idx, ":w:"): # a role: let (roleName, lastIdx) = getRefname(p, p.idx+1) @@ -1300,20 +1346,19 @@ proc parseWordOrRef(p: var RstParser, father: PRstNode) = else: # check for reference (probably, long one like some.ref.with.dots_ ) var saveIdx = p.idx - var isRef = false + var reference: PRstNode = nil inc p.idx while currentTok(p).kind in {tkWord, tkPunct}: if currentTok(p).kind == tkPunct: if isInlineMarkupEnd(p, "_", exact=true): - isRef = true + reference = newRstNode(rnRef, info=lineInfo(p, saveIdx)) break if not validRefnamePunct(currentTok(p).symbol): break inc p.idx - if isRef: - let r = newRstNode(rnRef) - for i in saveIdx..p.idx-1: r.add newLeaf(p.tok[i].symbol) - father.add r + if reference != nil: + for i in saveIdx..p.idx-1: reference.add newLeaf(p.tok[i].symbol) + father.add reference inc p.idx # skip final _ else: # 1 normal word father.add newLeaf(p.tok[saveIdx].symbol) @@ -1387,6 +1432,8 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, else: rstMessage(p, meExpected, postfix, line, col) proc parseMarkdownCodeblock(p: var RstParser): PRstNode = + result = newRstNodeA(p, rnCodeBlock) + result.info = lineInfo(p) var args = newRstNode(rnDirArg) if currentTok(p).kind == tkWord: args.add(newLeaf(p)) @@ -1411,7 +1458,6 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = inc p.idx var lb = newRstNode(rnLiteralBlock) lb.add(n) - result = newRstNodeA(p, rnCodeBlock) result.add(args) result.add(PRstNode(nil)) result.add(lb) @@ -1495,6 +1541,7 @@ proc parseFootnoteName(p: var RstParser, reference: bool): PRstNode = proc parseInline(p: var RstParser, father: PRstNode) = var n: PRstNode # to be used in `if` condition + let saveIdx = p.idx case currentTok(p).kind of tkPunct: if isInlineMarkupStart(p, "***"): @@ -1537,12 +1584,12 @@ proc parseInline(p: var RstParser, father: PRstNode) = n = n.toOtherRole(k, roleName) father.add(n) elif isInlineMarkupStart(p, "`"): - var n = newRstNode(rnInterpretedText) + var n = newRstNode(rnInterpretedText, info=lineInfo(p, p.idx+1)) parseUntil(p, n, "`", false) # bug #17260 n = parsePostfix(p, n) father.add(n) elif isInlineMarkupStart(p, "|"): - var n = newRstNode(rnSubstitutionReferences) + var n = newRstNode(rnSubstitutionReferences, info=lineInfo(p, p.idx+1)) parseUntil(p, n, "|", false) father.add(n) elif roSupportMarkdown in p.s.options and @@ -1552,15 +1599,14 @@ proc parseInline(p: var RstParser, father: PRstNode) = elif isInlineMarkupStart(p, "[") and nextTok(p).symbol != "[" and (n = parseFootnoteName(p, reference=true); n != nil): var nn = newRstNode(rnFootnoteRef) + nn.info = lineInfo(p, saveIdx+1) nn.add n let (fnType, _) = getFootnoteType(n) case fnType of fnAutoSymbol: - p.s.lineFootnoteSymRef.add curLine(p) - nn.order = p.s.lineFootnoteSymRef.len + p.s.lineFootnoteSymRef.add lineInfo(p) of fnAutoNumber: - p.s.lineFootnoteNumRef.add curLine(p) - nn.order = p.s.lineFootnoteNumRef.len + p.s.lineFootnoteNumRef.add lineInfo(p) else: discard father.add(nn) else: @@ -1693,7 +1739,7 @@ proc parseField(p: var RstParser): PRstNode = ## Returns a parsed rnField node. ## ## rnField nodes have two children nodes, a rnFieldName and a rnFieldBody. - result = newRstNode(rnField) + result = newRstNode(rnField, info=lineInfo(p)) var col = currentTok(p).col var fieldname = newRstNode(rnFieldName) parseUntil(p, fieldname, ":", false) @@ -2469,6 +2515,7 @@ proc parseDirective(p: var RstParser, k: RstNodeKind, flags: DirFlags): PRstNode ## Both rnDirArg and rnFieldList children nodes might be nil, so you need to ## check them before accessing. result = newRstNodeA(p, k) + if k == rnCodeBlock: result.info = lineInfo(p) var args: PRstNode = nil var options: PRstNode = nil if hasArg in flags: @@ -2593,14 +2640,16 @@ proc dirInclude(p: var RstParser): PRstNode = var q: RstParser initParser(q, p.s) - q.s.filename = path + let saveFileIdx = p.s.currFileIdx + setCurrFilename(p.s, path) getTokens( - inputString[startPosition..endPosition].strip(), + inputString[startPosition..endPosition], q.tok) # workaround a GCC bug; more like the interior pointer bug? #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0: # InternalError("Too many binary zeros in include file") result = parseDoc(q) + p.s.currFileIdx = saveFileIdx proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = ## Parses a code block. @@ -2634,7 +2683,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList) assert result.sons[1].kind == rnFieldList # Hook the extra field and specify the Nim language as value. - var extraNode = newRstNode(rnField) + var extraNode = newRstNode(rnField, info=lineInfo(p)) extraNode.add(newRstNode(rnFieldName)) extraNode.add(newRstNode(rnFieldBody)) extraNode.sons[0].add newLeaf("default-language") @@ -2837,9 +2886,8 @@ proc parseDotDot(p: var RstParser): PRstNode = else: result = parseComment(p, col) -proc rstParsePass1*(fragment, filename: string, +proc rstParsePass1*(fragment: string, line, column: int, - options: RstParseOptions, sharedState: PRstSharedState): PRstNode = ## Parses an RST `fragment`. ## The result should be further processed by @@ -2872,7 +2920,8 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = var key = addNodes(n) var e = getEnv(key) if e != "": result = newLeaf(e) - else: rstMessage(s, mwUnknownSubstitution, key) + else: rstMessage(s.filenames, s.msgHandler, n.info, + mwUnknownSubstitution, key) of rnHeadline, rnOverline: # fix up section levels depending on presence of a title and subtitle if s.hTitleCnt == 2: @@ -2890,12 +2939,14 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = let text = newRstNode(rnInner, n.sons) result.sons = @[text, y] else: - let s = findMainAnchor(s, refn) - if s != "": + let anchor = findMainAnchor(s, refn) + if anchor != "": result = newRstNode(rnInternalRef) let text = newRstNode(rnInner, n.sons) - result.sons = @[text, # visible text of reference - newLeaf(s)] # link itself + result.sons = @[text, # visible text of reference + newLeaf(anchor)] # link itself + else: + rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, refn) of rnFootnote: var (fnType, num) = getFootnoteType(n.sons[0]) case fnType @@ -2922,20 +2973,22 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = result.add(nn) var refn = fnType.prefix # create new rnFootnoteRef, add final label, and finalize target refn: - result = newRstNode(rnFootnoteRef) + result = newRstNode(rnFootnoteRef, info = n.info) case fnType of fnManualNumber: addLabel num refn.add $num of fnAutoNumber: - addLabel getFootnoteNum(s, n.order) - refn.add $n.order + inc s.currFootnoteNumRef + addLabel getFootnoteNum(s, s.currFootnoteNumRef) + refn.add $s.currFootnoteNumRef of fnAutoNumberLabel: addLabel getFootnoteNum(s, rstnodeToRefname(n)) refn.add rstnodeToRefname(n) of fnAutoSymbol: - addLabel getAutoSymbol(s, n.order) - refn.add $n.order + inc s.currFootnoteSymRef + addLabel getAutoSymbol(s, s.currFootnoteSymRef) + refn.add $s.currFootnoteSymRef of fnCitation: result.add n.sons[0] refn.add rstnodeToRefname(n) @@ -2943,7 +2996,7 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = if anch != "": result.add newLeaf(anch) # add link else: - rstMessage(s, mwUnknownSubstitution, refn) + rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, refn) result.add newLeaf(refn) # add link of rnLeaf: discard @@ -2971,14 +3024,18 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = result.sons = newSons proc rstParse*(text, filename: string, - line, column: int, hasToc: var bool, + line, column: int, options: RstParseOptions, findFile: FindFileHandler = nil, - msgHandler: MsgHandler = nil): PRstNode = - ## Parses the whole `text`. The result is ready for `rstgen.renderRstToOut`. + msgHandler: MsgHandler = nil): + tuple[node: PRstNode, filenames: RstFileTable, hasToc: bool] = + ## Parses the whole `text`. The result is ready for `rstgen.renderRstToOut`, + ## note that 2nd tuple element should be fed to `initRstGenerator` + ## argument `filenames` (it is being filled here at least with `filename` + ## and possibly with other files from RST ``.. include::`` statement). var sharedState = newRstSharedState(options, filename, findFile, msgHandler) - let unresolved = rstParsePass1(text, filename, line, column, - options, sharedState) + let unresolved = rstParsePass1(text, line, column, sharedState) preparePass2(sharedState, unresolved) - result = resolveSubs(sharedState, unresolved) - hasToc = sharedState.hasToc + result.node = resolveSubs(sharedState, unresolved) + result.filenames = sharedState.filenames + result.hasToc = sharedState.hasToc diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 2489ce40c..fa0620f44 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -74,6 +74,11 @@ type rnLeaf # a leaf; the node's text field contains the # leaf val + FileIndex* = distinct int32 + TLineInfo* = object + line*: uint16 + col*: int16 + fileIndex*: FileIndex PRstNode* = ref RstNode ## an RST node RstNodeSeq* = seq[PRstNode] @@ -92,21 +97,32 @@ type level*: int ## level of headings starting from 1 (main ## chapter) to larger ones (minor sub-sections) ## level=0 means it's document title or subtitle - of rnFootnote, rnCitation, rnFootnoteRef, rnOptionListItem: + of rnFootnote, rnCitation, rnOptionListItem: order*: int ## footnote order (for auto-symbol footnotes and ## auto-numbered ones without a label) + of rnRef, rnSubstitutionReferences, + rnInterpretedText, rnField, rnInlineCode, rnCodeBlock, rnFootnoteRef: + info*: TLineInfo ## To have line/column info for warnings at + ## nodes that are post-processed after parsing else: discard anchor*: string ## anchor, internal link target ## (aka HTML id tag, aka Latex label/hypertarget) sons*: RstNodeSeq ## the node's sons +proc `==`*(a, b: FileIndex): bool {.borrow.} + proc len*(n: PRstNode): int = result = len(n.sons) proc newRstNode*(kind: RstNodeKind, sons: seq[PRstNode] = @[], anchor = ""): PRstNode = + result = PRstNode(kind: kind, sons: sons, anchor: anchor) + +proc newRstNode*(kind: RstNodeKind, info: TLineInfo, + sons: seq[PRstNode] = @[]): PRstNode = result = PRstNode(kind: kind, sons: sons) + result.info = info proc newRstNode*(kind: RstNodeKind, s: string): PRstNode {.deprecated.} = assert kind in {rnLeaf, rnSmiley} @@ -388,7 +404,7 @@ proc renderRstToStr*(node: PRstNode, indent=0): string = result.add " adType=" & node.adType of rnHeadline, rnOverline, rnMarkdownHeadline: result.add " level=" & $node.level - of rnFootnote, rnCitation, rnFootnoteRef, rnOptionListItem: + of rnFootnote, rnCitation, rnOptionListItem: result.add (if node.order == 0: "" else: " order=" & $node.order) else: discard diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index b9c8f688b..10a229479 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -40,7 +40,7 @@ ## can be done by simply searching for [footnoteName]. import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, - algorithm, parseutils + algorithm, parseutils, std/strbasics import ../../std/private/since @@ -72,11 +72,11 @@ type tocPart*: seq[TocEntry] hasToc*: bool theIndex: string # Contents of the index file to be dumped at the end. - options*: RstParseOptions findFile*: FindFileHandler msgHandler*: MsgHandler outDir*: string ## output directory, initialized by docgen.nim destFile*: string ## output (HTML) file, initialized by docgen.nim + filenames*: RstFileTable filename*: string ## source Nim or Rst file meta*: array[MetaEnum, string] currentSection: string ## \ @@ -112,9 +112,9 @@ proc init(p: var CodeBlockParams) = proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, config: StringTableRef, filename: string, - options: RstParseOptions, findFile: FindFileHandler = nil, - msgHandler: MsgHandler = nil) = + msgHandler: MsgHandler = nil, + filenames = default(RstFileTable)) = ## Initializes a ``RstGenerator``. ## ## You need to call this before using a ``RstGenerator`` with any other @@ -160,9 +160,9 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, g.target = target g.tocPart = @[] g.filename = filename + g.filenames = filenames g.splitAfter = 20 g.theIndex = "" - g.options = options g.findFile = findFile g.currentSection = "" g.id = 0 @@ -908,9 +908,8 @@ proc renderSmiley(d: PDoc, n: PRstNode, result: var string) = [d.config.getOrDefault"doc.smiley_format" % n.text]) proc getField1Int(d: PDoc, n: PRstNode, fieldName: string): int = - # TODO: proper column/line info template err(msg: string) = - d.msgHandler(d.filename, 1, 0, meInvalidRstField, msg) + rstMessage(d.filenames, d.msgHandler, n.info, meInvalidField, msg) let value = n.getFieldValue var number: int let nChars = parseInt(value, number) @@ -958,7 +957,8 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = params.langStr = n.getFieldValue.strip params.lang = params.langStr.getSourceLanguage else: - d.msgHandler(d.filename, 1, 0, mwUnsupportedField, n.getArgument) + rstMessage(d.filenames, d.msgHandler, n.info, mwUnsupportedField, + n.getArgument) proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = ## Iterates over all code block fields and returns processed params. @@ -1069,7 +1069,8 @@ proc renderCode(d: PDoc, n: PRstNode, result: var string) = dispA(d.target, result, blockStart, blockStart, []) if params.lang == langNone: if len(params.langStr) > 0: - d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr) + rstMessage(d.filenames, d.msgHandler, n.info, mwUnsupportedLanguage, + params.langStr) for letter in m.text: escChar(d.target, result, letter, emText) else: renderCodeLang(result, params.lang, m.text, d.target) @@ -1564,23 +1565,24 @@ proc rstToHtml*(s: string, options: RstParseOptions, result = "" const filen = "input" + let (rst, filenames, _) = rstParse(s, filen, + line=LineRstInit, column=ColRstInit, + options, myFindFile, msgHandler) var d: RstGenerator - initRstGenerator(d, outHtml, config, filen, options, myFindFile, msgHandler) - var dummyHasToc = false - var rst = rstParse(s, filen, line=LineRstInit, column=ColRstInit, - dummyHasToc, options, myFindFile, msgHandler) + initRstGenerator(d, outHtml, config, filen, myFindFile, msgHandler, filenames) result = "" renderRstToOut(d, rst, result) + strbasics.strip(result) proc rstToLatex*(rstSource: string; options: RstParseOptions): string {.inline, since: (1, 3).} = ## Convenience proc for `renderRstToOut` and `initRstGenerator`. runnableExamples: doAssert rstToLatex("*Hello* **world**", {}) == """\emph{Hello} \textbf{world}""" if rstSource.len == 0: return - var option: bool + let (rst, filenames, _) = rstParse(rstSource, "", + line=LineRstInit, column=ColRstInit, + options) var rstGenera: RstGenerator - rstGenera.initRstGenerator(outLatex, defaultConfig(), "input", options) - rstGenera.renderRstToOut( - rstParse(rstSource, "", line=LineRstInit, column=ColRstInit, - option, options), - result) + rstGenera.initRstGenerator(outLatex, defaultConfig(), "input", filenames=filenames) + rstGenera.renderRstToOut(rst, result) + strbasics.strip(result) diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index fe99d6cfa..fc3ccbf4e 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -5,6 +5,8 @@ discard """ [Suite] RST indentation +[Suite] Warnings + [Suite] RST include directive [Suite] RST escaping @@ -51,9 +53,8 @@ proc toAst(input: string, # we don't find any files in online mode: result = "" - var dummyHasToc = false - var rst = rstParse(input, filen, line=LineRstInit, column=ColRstInit, - dummyHasToc, rstOptions, myFindFile, testMsgHandler) + var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit, + rstOptions, myFindFile, testMsgHandler) result = renderRstToStr(rst) except EParseError as e: if e.msg != "": @@ -356,6 +357,53 @@ suite "RST indentation": # "template..." should be parsed as a definition list attached to ":test:": check inputWrong.toAst != ast +suite "Warnings": + test "warnings for broken footnotes/links/substitutions": + let input = dedent""" + firstParagraph + + footnoteRef [som]_ + + link `a broken Link`_ + + substitution |undefined subst| + + link short.link_ + + lastParagraph + """ + var warnings = new seq[string] + let output = input.toAst(warnings=warnings) + check(warnings[] == @[ + "input(3, 14) Warning: broken link 'citation-som'", + "input(5, 7) Warning: broken link 'a-broken-link'", + "input(7, 15) Warning: unknown substitution 'undefined subst'", + "input(9, 6) Warning: broken link 'shortdotlink'" + ]) + + test "With include directive and blank lines at the beginning": + "other.rst".writeFile(dedent""" + + + firstParagraph + + here brokenLink_""") + let input = ".. include:: other.rst" + var warnings = new seq[string] + let output = input.toAst(warnings=warnings) + check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenlink'"] + check(output == dedent""" + rnInner + rnParagraph + rnLeaf 'firstParagraph' + rnParagraph + rnLeaf 'here' + rnLeaf ' ' + rnRef + rnLeaf 'brokenLink' + """) + removeFile("other.rst") + suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") @@ -374,7 +422,7 @@ OtherStart .. include:: other.rst :start-after: OtherStart """ - doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) + check "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include everything before": @@ -406,7 +454,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) + check "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index d5d902e1d..867677404 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -237,8 +237,7 @@ not in table"""
  • -
    Precedence levelOperatorsFirst characterTerminal symbol
    D1 """ & id"code" & " " & op"\|" & """D2
    E1 | text
    F2 without pipe

    not in table

    -""") +

    not in table

    """) let input2 = """ | A1 header | A2 | | --- | --- |""" @@ -420,9 +419,10 @@ Some chapter "the following intermediate section level(s) are missing on " & "lines 12..15: underline -----)") + test "RST sections overline": # the same as input9good but with overline headings # first overline heading has a special meaning: document title - let input10 = dedent """ + let input = dedent """ ====== Title0 ====== @@ -454,22 +454,23 @@ Some chapter ~~~~~ """ - var option: bool var rstGenera: RstGenerator - var output10: string - rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", {}) - rstGenera.renderRstToOut(rstParse(input10, "", 1, 1, option, {}), output10) + var output: string + let (rst, files, _) = rstParse(input, "", 1, 1, {}) + rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames = files) + rstGenera.renderRstToOut(rst, output) doAssert rstGenera.meta[metaTitle] == "Title0" doAssert rstGenera.meta[metaSubTitle] == "SubTitle0" - doAssert "

    Level1

    " in output10 - doAssert "

    Level2

    " in output10 - doAssert "

    Level3

    " in output10 - doAssert "

    L1

    " in output10 - doAssert "

    Another2

    " in output10 - doAssert "

    More3

    " in output10 + doAssert "

    Level1

    " in output + doAssert "

    Level2

    " in output + doAssert "

    Level3

    " in output + doAssert "

    L1

    " in output + doAssert "

    Another2

    " in output + doAssert "

    More3

    " in output + test "RST sections overline 2": # check that a paragraph prevents interpreting overlines as document titles - let input11 = dedent """ + let input = dedent """ Paragraph ====== @@ -480,18 +481,19 @@ Some chapter SubTitle0 +++++++++ """ - var option11: bool - var rstGenera11: RstGenerator - var output11: string - rstGenera11.initRstGenerator(outHtml, defaultConfig(), "input", {}) - rstGenera11.renderRstToOut(rstParse(input11, "", 1, 1, option11, {}), output11) - doAssert rstGenera11.meta[metaTitle] == "" - doAssert rstGenera11.meta[metaSubTitle] == "" - doAssert "

    Title0

    " in output11 - doAssert "

    SubTitle0

    " in output11 + var rstGenera: RstGenerator + var output: string + let (rst, files, _) = rstParse(input, "", 1, 1, {}) + rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) + rstGenera.renderRstToOut(rst, output) + doAssert rstGenera.meta[metaTitle] == "" + doAssert rstGenera.meta[metaSubTitle] == "" + doAssert "

    Title0

    " in output + doAssert "

    SubTitle0

    " in output + test "RST+Markdown sections": # check that RST and Markdown headings don't interfere - let input12 = dedent """ + let input = dedent """ ====== Title0 ====== @@ -509,14 +511,14 @@ Some chapter MySection2a ----------- """ - var option12: bool - var rstGenera12: RstGenerator - var output12: string - rstGenera12.initRstGenerator(outHtml, defaultConfig(), "input", {}) - rstGenera12.renderRstToOut(rstParse(input12, "", 1, 1, option12, {roSupportMarkdown}), output12) - doAssert rstGenera12.meta[metaTitle] == "Title0" - doAssert rstGenera12.meta[metaSubTitle] == "" - doAssert output12 == + var rstGenera: RstGenerator + var output: string + let (rst, files, _) = rstParse(input, "", 1, 1, {roSupportMarkdown}) + rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) + rstGenera.renderRstToOut(rst, output) + doAssert rstGenera.meta[metaTitle] == "Title0" + doAssert rstGenera.meta[metaSubTitle] == "" + doAssert output == "\n

    MySection1a

    " & # RST "\n

    MySection1b

    " & # Markdown "\n

    MySection1c

    " & # RST @@ -628,7 +630,7 @@ let x = 1 let p2 = """

    Par2 value2.

    """ let p3 = """

    Par3 """ & id"value3" & ".

    " let p4 = """

    Par4 value4.

    """ - let expected = p1 & p2 & "\n" & p3 & "\n" & p4 & "\n" + let expected = p1 & p2 & "\n" & p3 & "\n" & p4 check(input.toHtml == expected) test "role directive": @@ -653,8 +655,8 @@ Check that comment disappears: let output1 = input1.toHtml doAssert output1 == "Check that comment disappears:" - test "RST line blocks": - let input1 = """ + test "RST line blocks + headings": + let input = """ ===== Test1 ===== @@ -665,19 +667,20 @@ Test1 | other line """ - var option: bool var rstGenera: RstGenerator - var output1: string - rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", {}) - rstGenera.renderRstToOut(rstParse(input1, "", 1, 1, option, {}), output1) + var output: string + let (rst, files, _) = rstParse(input, "", 1, 1, {}) + rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) + rstGenera.renderRstToOut(rst, output) doAssert rstGenera.meta[metaTitle] == "Test1" # check that title was not overwritten to '|' - doAssert output1 == "



    line block
    other line

    " - let output1l = rstToLatex(input1, {}) + doAssert output == "



    line block
    other line

    " + let output1l = rstToLatex(input, {}) doAssert "line block\n\n" in output1l doAssert "other line\n\n" in output1l doAssert output1l.count("\\vspace") == 2 + 2 # +2 surrounding paddings + test "RST line blocks": let input2 = dedent""" Paragraph1 @@ -686,7 +689,7 @@ Test1 Paragraph2""" let output2 = input2.toHtml - doAssert "Paragraph1


    Paragraph2

    \n" == output2 + doAssert "Paragraph1


    Paragraph2

    " == output2 let input3 = dedent""" | xxx @@ -853,7 +856,7 @@ Test1 check("input(6, 1) Warning: RST style: \n" & "not enough indentation on line 6" in warnings8[0]) doAssert output8 == "Paragraph.
      " & - "
    1. stringA
    2. \n
    3. stringB
    4. \n
    \n

    C. string1 string2

    \n" + "
  • stringA
  • \n
  • stringB
  • \n\n

    C. string1 string2

    " test "Markdown enumerated lists": let input1 = dedent """ @@ -926,7 +929,7 @@ Test1 Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_. """ let output2 = input2.toHtml - doAssert output2 == "Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_. " + doAssert output2 == "Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_." # check that auto-symbol footnotes work: let input3 = dedent """ @@ -1034,9 +1037,7 @@ Test1 """ var warnings8 = new seq[string] let output8 = input8.toHtml(warnings=warnings8) - # TODO: the line 1 is arbitrary because reference lines are not preserved - check(warnings8[] == @["input(1, 1) Warning: unknown substitution " & - "\'citation-som\'"]) + check(warnings8[] == @["input(3, 7) Warning: broken link 'citation-som'"]) # check that footnote group does not break parsing of other directives: let input9 = dedent """ @@ -1144,10 +1145,33 @@ Test1 """ var error = new string let output = input.toHtml(error=error) - check(error[] == "input(1, 1) Error: invalid field: " & + check(error[] == "input(2, 3) Error: invalid field: " & "extra arguments were given to number-lines: ' let a = 1'") check "" == output + test "code-block warning": + let input = dedent """ + .. code:: Nim + :unsupportedField: anything + + .. code:: unsupportedLang + + anything + + ```anotherLang + someCode + ``` + """ + let warnings = new seq[string] + let output = input.toHtml(warnings=warnings) + check(warnings[] == @[ + "input(2, 4) Warning: field 'unsupportedField' not supported", + "input(4, 11) Warning: language 'unsupportedLang' not supported", + "input(8, 4) Warning: language 'anotherLang' not supported" + ]) + check(output == "
    anything
    " & + "

    \nsomeCode\n

    ") + test "RST admonitions": # check that all admonitions are implemented let input0 = dedent """ @@ -1477,7 +1501,7 @@ Test1 check "(3, 15) Warning: " in warnings[1] check "language 'py:class' not supported" in warnings[1] check("""

    See function spam.

    """ & "\n" & - """

    See also egg.

    """ & "\n" == + """

    See also egg.

    """ == output) test "(not) Roles: check escaping 1": From e38388eb4e92b0e7c7db204fe36d7969967cd609 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 20 Jul 2021 08:35:53 +0200 Subject: [PATCH 2843/4254] use .} instead of } for code highlighters --- lib/system/threads.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 7fbfe54ab..2b5eb07fd 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -41,7 +41,7 @@ ## for i in 0..high(thr): ## createThread(thr[i], threadFunc, (i*10, i*10+5)) ## joinThreads(thr) -## +## ## deinitLock(L) when not declared(ThisIsSystem): @@ -395,7 +395,7 @@ elif defined(netbsd): elif defined(freebsd): proc syscall(arg: cint, arg0: ptr cint): cint {.varargs, importc: "syscall", header: "".} - var SYS_thr_self {.importc:"SYS_thr_self", header:""}: cint + var SYS_thr_self {.importc:"SYS_thr_self", header:"".}: cint proc getThreadId*(): int = ## Gets the ID of the currently running thread. From 5e011e8e42b2e4e322e9b40d4075da6d4a9103e5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 20 Jul 2021 10:37:36 +0200 Subject: [PATCH 2844/4254] updated the changelog (#18539) --- changelog.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/changelog.md b/changelog.md index 097beac2c..a633c1fb3 100644 --- a/changelog.md +++ b/changelog.md @@ -39,9 +39,6 @@ - `math.round` now is rounded "away from zero" in JS backend which is consistent with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. -- Instead of deleting the element at the last index, - `system.delete()` now raises `IndexDefect` when given index is out of bounds. - - Changed the behavior of `uri.decodeQuery` when there are unencoded `=` characters in the decoded values. Prior versions would raise an error. This is no longer the case to comply with the HTML spec and other languages From 6286b5599c7d9fc03f3a6809f5c17fbefc23427e Mon Sep 17 00:00:00 2001 From: Paul Roberts Date: Tue, 20 Jul 2021 11:50:43 +0100 Subject: [PATCH 2845/4254] termux ssl (#18520) --- lib/pure/net.nim | 2 +- lib/pure/ssl_certs.nim | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 934dd034e..c2e4810de 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -647,7 +647,7 @@ when defineSsl: if verifyMode != CVerifyNone: # Use the caDir and caFile parameters if set if caDir != "" or caFile != "": - if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != VerifySuccess: + if newCTX.SSL_CTX_load_verify_locations(if caFile == "": nil else: caFile.cstring, if caDir == "": nil else: caDir.cstring) != VerifySuccess: raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).") else: diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index 2d2644ebe..c7ce04ffa 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -34,6 +34,7 @@ elif defined(linux): # Fedora/RHEL "/etc/pki/tls/certs", # Android + "/data/data/com.termux/files/usr/etc/tls/cert.pem", "/system/etc/security/cacerts", ] elif defined(bsd): From dbf8d0b8946419311ac710b1adc995ad206b52c1 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 20 Jul 2021 20:12:15 +0800 Subject: [PATCH 2846/4254] use more `.}` (#18542) --- changelogs/changelog_0_19_0.md | 2 +- doc/manual_experimental.rst | 4 ++-- lib/posix/posix_linux_amd64.nim | 2 +- lib/system.nim | 8 ++++---- lib/windows/winlean.nim | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/changelogs/changelog_0_19_0.md b/changelogs/changelog_0_19_0.md index 18d3ca2b3..45cefe933 100644 --- a/changelogs/changelog_0_19_0.md +++ b/changelogs/changelog_0_19_0.md @@ -15,7 +15,7 @@ at runtime. Use ``ref object`` with inheritance rather than ``object`` with inheritance to prevent this issue. - The ``not nil`` type annotation now has to be enabled explicitly - via ``{.experimental: "notnil"}`` as we are still not pleased with how this + via ``{.experimental: "notnil".}`` as we are still not pleased with how this feature works with Nim's containers. - The parser now warns about inconsistent spacing around binary operators as these can easily be confused with unary operators. This warning will likely diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index d10ef8d1b..22db184a8 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -474,13 +474,13 @@ Not nil annotation ================== **Note:** This is an experimental feature. It can be enabled with -`{.experimental: "notnil"}`. +`{.experimental: "notnil".}`. All types for which `nil` is a valid value can be annotated with the `not nil` annotation to exclude `nil` as a valid value: .. code-block:: nim - {.experimental: "notnil"} + {.experimental: "notnil".} type PObject = ref TObj not nil diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 5c0b4d6cf..2309e19a9 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -334,7 +334,7 @@ type si_status*: cint ## Exit value or signal. si_band*: int ## Band event for SIGPOLL. si_value*: SigVal ## Signal value. - pad {.importc: "_pad"}: array[128 - 56, uint8] + pad {.importc: "_pad".}: array[128 - 56, uint8] Nl_item* {.importc: "nl_item", header: "".} = cint Nl_catd* {.importc: "nl_catd", header: "".} = pointer diff --git a/lib/system.nim b/lib/system.nim index 2790187f4..e878f9f2f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -536,7 +536,7 @@ include "system/arithmetics" include "system/comparisons" const - appType* {.magic: "AppType"}: string = "" + appType* {.magic: "AppType".}: string = "" ## A string that describes the application type. Possible values: ## `"console"`, `"gui"`, `"lib"`. @@ -1101,15 +1101,15 @@ const ## True only when accessed in the main module. This works thanks to ## compiler magic. It is useful to embed testing code in a module. - CompileDate* {.magic: "CompileDate"}: string = "0000-00-00" + CompileDate* {.magic: "CompileDate".}: string = "0000-00-00" ## The date (in UTC) of compilation as a string of the form ## `YYYY-MM-DD`. This works thanks to compiler magic. - CompileTime* {.magic: "CompileTime"}: string = "00:00:00" + CompileTime* {.magic: "CompileTime".}: string = "00:00:00" ## The time (in UTC) of compilation as a string of the form ## `HH:MM:SS`. This works thanks to compiler magic. - cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian + cpuEndian* {.magic: "CpuEndian".}: Endianness = littleEndian ## The endianness of the target CPU. This is a valuable piece of ## information for low-level code only. This works thanks to compiler ## magic. diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index d901af244..b8f3886d7 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -1143,7 +1143,7 @@ proc setFileTime*(hFile: Handle, lpCreationTime: LPFILETIME, type # https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority SID_IDENTIFIER_AUTHORITY* {.importc, header: "".} = object - value* {.importc: "Value"}: array[6, BYTE] + value* {.importc: "Value".}: array[6, BYTE] # https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid SID* {.importc, header: "".} = object Revision: BYTE From a8b3e7c05919511db62f1aabd706c46316b4f7b6 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 20 Jul 2021 21:32:55 +0800 Subject: [PATCH 2847/4254] follow up #18517 (#18537) * follow up #18517 * Update lib/pure/os.nim Co-authored-by: Timothee Cour * Update lib/pure/os.nim Co-authored-by: Timothee Cour --- lib/pure/os.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 6289c64f0..73e3fcb31 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -11,10 +11,11 @@ ## retrieving environment variables, reading command line arguments, ## working with directories, running shell commands, etc. -runnableExamples("-r:off"): +runnableExamples: let myFile = "/path/to/my/file.nim" assert splitPath(myFile) == (head: "/path/to/my", tail: "file.nim") - assert parentDir(myFile) == "/path/to/my" + when defined(posix): + assert parentDir(myFile) == "/path/to/my" assert splitFile(myFile) == (dir: "/path/to/my", name: "file", ext: ".nim") assert myFile.changeFileExt("c") == "/path/to/my/file.c" From cf0cf32d276002e850a87667fff62c4df12999d6 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 20 Jul 2021 13:13:52 -0700 Subject: [PATCH 2848/4254] make -d:nimFpRoundtrips work consistently in vm vs rt, fix #18400, etc (#18531) * compiler/vmhooks: add getVar to allow vmops with var params * addFloat vmops with var param * cgen now renders float32 literals in c backend using roundtrip float to string --- compiler/ast.nim | 4 +- compiler/ccgexprs.nim | 12 +-- compiler/jsgen.nim | 7 +- compiler/nim.cfg | 1 + compiler/rodutils.nim | 10 +- compiler/semfold.nim | 1 - compiler/vmgen.nim | 3 +- compiler/vmhooks.nim | 32 +++--- compiler/vmops.nim | 11 +++ lib/system.nim | 3 - lib/system/dollars.nim | 13 +-- lib/system/formatfloat.nim | 166 ++++++++++++++++++++++---------- lib/system/jssys.nim | 18 +--- lib/system/repr_v2.nim | 6 +- lib/system/strmantle.nim | 41 -------- tests/config.nims | 2 + tests/errmsgs/treportunused.nim | 14 ++- tests/float/nim.cfg | 1 - tests/float/tfloats.nim | 117 ++++++++++++++++++---- tests/stdlib/tjson.nim | 6 +- tests/stdlib/tjsonutils.nim | 17 ++-- 21 files changed, 286 insertions(+), 199 deletions(-) delete mode 100644 tests/float/nim.cfg diff --git a/compiler/ast.nim b/compiler/ast.nim index f1f73dcee..8b836e088 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -652,7 +652,7 @@ type mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mImplies, mIff, mExists, mForall, mOld, @@ -720,7 +720,7 @@ const mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 09326ceeb..79c73b602 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -94,9 +94,12 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = else: result = makeCString(n.strVal) of nkFloatLit, nkFloat64Lit: - result = rope(n.floatVal.toStrMaxPrecision) + if ty.kind == tyFloat32: + result = rope(n.floatVal.float32.toStrMaxPrecision) + else: + result = rope(n.floatVal.toStrMaxPrecision) of nkFloat32Lit: - result = rope(n.floatVal.toStrMaxPrecision("f")) + result = rope(n.floatVal.float32.toStrMaxPrecision) else: internalError(p.config, n.info, "genLiteral(" & $n.kind & ')') result = nil @@ -2300,11 +2303,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)") of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") - of mFloatToStr: - if e[1].typ.skipTypes(abstractInst).kind == tyFloat32: - genDollar(p, e, d, "#nimFloat32ToStr($1)") - else: - genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e[1], d) of mIsolate: genCall(p, e, d) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 82fba02a6..4b89b0cde 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -434,7 +434,6 @@ const # magic checked op; magic unchecked op; mBoolToStr: ["nimBoolToStr", "nimBoolToStr"], mIntToStr: ["cstrToNimstr", "cstrToNimstr"], mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"], - mFloatToStr: ["cstrToNimstr", "cstrToNimstr"], mCStrToStr: ["cstrToNimstr", "cstrToNimstr"], mStrToStr: ["", ""]] @@ -656,9 +655,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)") of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") - of mFloatToStr: - useMagic(p, "nimFloatToString") - applyFormat "cstrToNimstr(nimFloatToString($1))" of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)") of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1") else: @@ -682,8 +678,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = gen(p, n[1], x) gen(p, n[2], y) r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] - of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, - mCStrToStr, mStrToStr, mEnumToStr: + of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) of mEqRef: if mapType(n[1].typ) != etyBaseIndex: diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 9ecd00b0b..f10d847ac 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -4,6 +4,7 @@ hint:XDeclaredButNotUsed:off define:booting define:nimcore +define:nimFpRoundtrips #import:"$projectpath/testability" diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index e13b08e05..a4f7a5146 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -39,7 +39,10 @@ when not declared(signbit): proc signbit*(x: SomeFloat): bool {.inline.} = result = c_signbit(x) != 0 -proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = +import system/formatfloat + +proc toStrMaxPrecision*(f: BiggestFloat | float32): string = + const literalPostfix = when f is float32: "f" else: "" case classify(f) of fcNan: if signbit(f): @@ -55,9 +58,8 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = of fcNegInf: result = "-INF" else: - result = newString(81) - let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring) - setLen(result, n) + result.addFloatRoundtrip(f) + result.add literalPostfix proc encodeStr*(s: string, result: var string) = for i in 0..", discardable.} - proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - result = toChars(buf, value, forceTrailingDotZero=true) - buf[result] = '\0' +proc addCstringN(result: var string, buf: cstring; buflen: int) = + # no nimvm support needed, so it doesn't need to be fast here either + let oldLen = result.len + let newLen = oldLen + buflen + result.setLen newLen + c_memcpy(result[oldLen].addr, buf, buflen.csize_t) -else: - proc c_sprintf(buf, frmt: cstring): cint {.header: "", - importc: "sprintf", varargs, noSideEffect.} +import dragonbox, schubfach - proc writeToBuffer(buf: var array[65, char]; value: cstring) = - var i = 0 - while value[i] != '\0': - buf[i] = value[i] - inc i +proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + result = toChars(buf, value, forceTrailingDotZero=true) + buf[result] = '\0' - proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat): int = - ## This is the implementation to format floats. - ## - ## returns the amount of bytes written to `buf` not counting the - ## terminating '\0' character. - var n: int = c_sprintf(addr buf, "%.16g", value) - var hasDot = false - for i in 0..n-1: - if buf[i] == ',': - buf[i] = '.' - hasDot = true - elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: - hasDot = true - if not hasDot: - buf[n] = '.' - buf[n+1] = '0' - buf[n+2] = '\0' - result = n + 2 +proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int = + result = float32ToChars(buf, value, forceTrailingDotZero=true) + buf[result] = '\0' + +proc c_sprintf(buf, frmt: cstring): cint {.header: "", + importc: "sprintf", varargs, noSideEffect.} + +proc writeToBuffer(buf: var array[65, char]; value: cstring) = + var i = 0 + while value[i] != '\0': + buf[i] = value[i] + inc i + +proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int = + ## This is the implementation to format floats. + ## + ## returns the amount of bytes written to `buf` not counting the + ## terminating '\0' character. + var n: int = c_sprintf(addr buf, "%.16g", value) + var hasDot = false + for i in 0..n-1: + if buf[i] == ',': + buf[i] = '.' + hasDot = true + elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: + hasDot = true + if not hasDot: + buf[n] = '.' + buf[n+1] = '0' + buf[n+2] = '\0' + result = n + 2 + else: + result = n + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' + # of '-1.#IND' are produced. + # We want to get rid of these here: + if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: + writeToBuffer(buf, "nan") + result = 3 + elif buf[n-1] == 'F': + if buf[0] == '-': + writeToBuffer(buf, "-inf") + result = 4 else: - result = n - # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)' - # of '-1.#IND' are produced. - # We want to get rid of these here: - if buf[n-1] in {'n', 'N', 'D', 'd', ')'}: - writeToBuffer(buf, "nan") + writeToBuffer(buf, "inf") result = 3 - elif buf[n-1] == 'F': - if buf[0] == '-': - writeToBuffer(buf, "-inf") - result = 4 - else: - writeToBuffer(buf, "inf") - result = 3 + +proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} = + when defined(nimFpRoundtrips): + writeFloatToBufferRoundtrip(buf, value) + else: + writeFloatToBufferSprintf(buf, value) + +proc addFloatRoundtrip*(result: var string; x: float | float32) = + when nimvm: + doAssert false + else: + var buffer {.noinit.}: array[65, char] + let n = writeFloatToBufferRoundtrip(buffer, x) + result.addCstringN(cstring(buffer[0].addr), n) + +proc addFloatSprintf*(result: var string; x: float) = + when nimvm: + doAssert false + else: + var buffer {.noinit.}: array[65, char] + let n = writeFloatToBufferSprintf(buffer, x) + result.addCstringN(cstring(buffer[0].addr), n) + +proc nimFloatToString(a: float): cstring = + ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 + # print `-0.0` properly + asm """ + function nimOnlyDigitsOrMinus(n) { + return n.toString().match(/^-?\d+$/); + } + if (Number.isSafeInteger(`a`)) + `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" + else { + `result` = `a`+"" + if(nimOnlyDigitsOrMinus(`result`)){ + `result` = `a`+".0" + } + } + """ + +proc addFloat*(result: var string; x: float | float32) {.inline.} = + ## Converts float to its string representation and appends it to `result`. + runnableExamples: + var + s = "foo:" + b = 45.67 + s.addFloat(45.67) + assert s == "foo:45.67" + template impl = + when defined(nimFpRoundtrips): + addFloatRoundtrip(result, x) + else: + addFloatSprintf(result, x) + when defined(js): + when nimvm: impl() + else: + result.add nimFloatToString(x) + else: impl() diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 7cb5652c5..b42dc3a20 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -496,23 +496,6 @@ proc negInt(a: int): int {.compilerproc.} = proc negInt64(a: int64): int64 {.compilerproc.} = result = a*(-1) -proc nimFloatToString(a: float): cstring {.compilerproc.} = - ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 - # print `-0.0` properly - asm """ - function nimOnlyDigitsOrMinus(n) { - return n.toString().match(/^-?\d+$/); - } - if (Number.isSafeInteger(`a`)) - `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" - else { - `result` = `a`+"" - if(nimOnlyDigitsOrMinus(`result`)){ - `result` = `a`+".0" - } - } - """ - proc absInt(a: int): int {.compilerproc.} = result = if a < 0: a*(-1) else: a @@ -703,6 +686,7 @@ proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = {.pop.} proc tenToThePowerOf(b: int): BiggestFloat = + # xxx deadcode var b = b var a = 10.0 result = 1.0 diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 618cc2b40..8471ea148 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -19,9 +19,9 @@ proc repr*(x: uint64): string {.noSideEffect.} = ## converted to a decimal string. $x #Calls `$` from system/strmantle.nim -proc repr*(x: float): string {.magic: "FloatToStr", noSideEffect.} - ## repr for a float argument. Returns `x` - ## converted to a decimal string. +proc repr*(x: float): string = + ## Same as $x + $x proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## repr for a boolean argument. Returns `x` diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 041272175..81ac5c751 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -69,47 +69,6 @@ proc nimIntToStr(x: int): string {.compilerRtl.} = result = newStringOfCap(sizeof(x)*4) result.addInt x -proc addCstringN(result: var string, buf: cstring; buflen: int) = - # no nimvm support needed, so it doesn't need to be fast here either - let oldLen = result.len - let newLen = oldLen + buflen - result.setLen newLen - copyMem(result[oldLen].addr, buf, buflen) - -import formatfloat - -proc addFloat*(result: var string; x: float) = - ## Converts float to its string representation and appends it to `result`. - ## - ## .. code-block:: Nim - ## var - ## a = "123" - ## b = 45.67 - ## a.addFloat(b) # a <- "12345.67" - when nimvm: - result.add $x - else: - var buffer {.noinit.}: array[65, char] - let n = writeFloatToBuffer(buffer, x) - result.addCstringN(cstring(buffer[0].addr), n) - -proc nimFloatToStr(f: float): string {.compilerproc.} = - result = newStringOfCap(8) - result.addFloat f - -when defined(nimFpRoundtrips) and not defined(nimscript) and - not defined(js) and defined(nimHasDragonBox): - import schubfach - -proc nimFloat32ToStr(f: float32): string {.compilerproc.} = - when declared(float32ToChars): - result = newString(65) - let L = float32ToChars(result, f, forceTrailingDotZero=true) - setLen(result, L) - else: - result = newStringOfCap(8) - result.addFloat f - proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. importc: "strtod", header: "", noSideEffect.} diff --git a/tests/config.nims b/tests/config.nims index 539de5e8d..12b303318 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -34,3 +34,5 @@ hint("Processing", off) switch("define", "nimExperimentalAsyncjsThen") switch("define", "nimExperimentalJsfetch") switch("define", "nimExperimentalLinenoiseExtra") + +switch("define", "nimFpRoundtrips") diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index f9b7c3d11..3105b35ea 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -13,12 +13,12 @@ treportunused.nim(30, 5) Hint: 's8' is declared but not used [XDeclaredButNotUse treportunused.nim(31, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] treportunused.nim(32, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] treportunused.nim(33, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(37, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(38, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] ''' action: compile """ -#treportunused.nim(37, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] -#treportunused.nim(38, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] # bug #9764 iterator s1(a:string): int = discard iterator s2(): int = discard @@ -32,9 +32,7 @@ var s9: int type s10 = object type s11 = type(1.2) -when false: - # enabled again when Nim bootstraps with -d:nimFpRoundtrips - # https://github.com/nim-lang/Nim/issues/14407 - let - `v0.99` = "0.99" - `v0.99.99` = "0.99.99" +# bug #14407 (requires `compiler/nim.cfg` containing define:nimFpRoundtrips) +let + `v0.99` = "0.99" + `v0.99.99` = "0.99.99" diff --git a/tests/float/nim.cfg b/tests/float/nim.cfg deleted file mode 100644 index d27bbf43b..000000000 --- a/tests/float/nim.cfg +++ /dev/null @@ -1 +0,0 @@ --d:nimFpRoundtrips diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim index 30d9c50d6..63987bb8d 100644 --- a/tests/float/tfloats.nim +++ b/tests/float/tfloats.nim @@ -1,13 +1,14 @@ discard """ + matrix: "-d:nimFpRoundtrips; -u:nimFpRoundtrips" targets: "c cpp js" """ -# disabled: "windows" #[ xxx merge all or most float tests into this file ]# import std/[fenv, math, strutils] +import stdtest/testutils proc equalsOrNaNs(a, b: float): bool = if isNaN(a): isNaN(b) @@ -62,27 +63,103 @@ template main = reject "1_.0" reject "1.0_" - block: # bug #18148 - var a = 1.1'f32 - doAssert $a == "1.1", $a # was failing + block: # bugs mentioned in https://github.com/nim-lang/Nim/pull/18504#issuecomment-881635317 + block: # example 1 + let a = 0.1+0.2 + doAssert a != 0.3 + when defined(nimFpRoundtrips): + doAssert $a == "0.30000000000000004" + else: + whenRuntimeJs: discard + do: doAssert $a == "0.3" + block: # example 2 + const a = 0.1+0.2 + when defined(nimFpRoundtrips): + doAssert $($a, a) == """("0.30000000000000004", 0.30000000000000004)""" + else: + whenRuntimeJs: discard + do: doAssert $($a, a) == """("0.3", 0.3)""" + block: # example 3 + const a1 = 0.1+0.2 + let a2 = a1 + doAssert a1 != 0.3 + when defined(nimFpRoundtrips): + doAssert $[$a1, $a2] == """["0.30000000000000004", "0.30000000000000004"]""" + else: + whenRuntimeJs: discard + do: doAssert $[$a1, $a2] == """["0.3", "0.3"]""" -proc runtimeOnlyTests = - # enable for 'static' once -d:nimFpRoundtrips became the default - block: # bug #7717 - proc test(f: float) = - let f2 = $f - let f3 = parseFloat(f2) - doAssert equalsOrNaNs(f, f3), $(f, f2, f3) + when defined(nimFpRoundtrips): + block: # bug #18148 + var a = 1.1'f32 + doAssert $a == "1.1", $a # was failing - test 1.0 + epsilon(float64) - test 1000000.0000000123 - test log2(100000.0) - test maximumPositiveValue(float32) - test maximumPositiveValue(float64) - test minimumPositiveValue(float32) - test minimumPositiveValue(float64) + block: # bug #18400 + block: + let a1 = 0.1'f32 + let a2 = 0.2'f32 + let a3 = a1 + a2 + var s = "" + s.addFloat(a3) + whenVMorJs: discard # xxx refs #12884 + do: + doAssert a3 == 0.3'f32 + doAssert $a3 == "0.3" + + block: + let a1 = 0.1 + let a2 = 0.2 + let a3 = a1 + a2 + var s = "" + s.addFloat(a3) + doAssert a3 != 0.3 + doAssert $a3 == "0.30000000000000004" + + block: + var s = [-13.888888'f32] + whenRuntimeJs: discard + do: + doAssert $s == "[-13.888888]" + doAssert $s[0] == "-13.888888" + + block: # bug #7717 + proc test(f: float) = + let f2 = $f + let f3 = parseFloat(f2) + doAssert equalsOrNaNs(f, f3), $(f, f2, f3) + test 1.0 + epsilon(float64) + test 1000000.0000000123 + test log2(100000.0) + test maximumPositiveValue(float32) + test maximumPositiveValue(float64) + test minimumPositiveValue(float32) + test minimumPositiveValue(float64) + + block: # bug #12884 + block: # example 1 + const x0: float32 = 1.32 + let x1 = 1.32 + let x2 = 1.32'f32 + var x3: float32 = 1.32 + doAssert $(x0, x1, x2, x3) == "(1.32, 1.32, 1.32, 1.32)" + block: # example https://github.com/nim-lang/Nim/issues/12884#issuecomment-564967962 + let x = float(1.32'f32) + when nimvm: discard # xxx prints 1.3 + else: + when not defined(js): + doAssert $x == "1.3200000524520874" + doAssert $1.32 == "1.32" + doAssert $1.32'f32 == "1.32" + let x2 = 1.32'f32 + doAssert $x2 == "1.32" + block: + var x = 1.23456789012345'f32 + when nimvm: + discard # xxx, refs #12884 + else: + when not defined(js): + doAssert x == 1.2345679'f32 + doAssert $x == "1.2345679" static: main() main() - -runtimeOnlyTests() diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index 000f72038..289ef9d05 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -303,7 +303,7 @@ let jsonNode = %*mynode doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}""" doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])""" -when defined(nimFpRoundtrips): # bug #17383 +block: # bug #17383 testRoundtrip(int32.high): "2147483647" testRoundtrip(uint32.high): "4294967295" when int.sizeof == 4: @@ -316,7 +316,7 @@ when defined(nimFpRoundtrips): # bug #17383 testRoundtrip(int64.high): "9223372036854775807" testRoundtrip(uint64.high): "18446744073709551615" -when defined(nimFpRoundtrips): # bug #18007 +block: # bug #18007 testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]""" # pending https://github.com/nim-lang/Nim/issues/18025 use: # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0]) @@ -332,7 +332,7 @@ when defined(nimFpRoundtrips): # bug #18007 testRoundtripVal(0.0): "0.0" testRoundtripVal(-0.0): "-0.0" -when defined(nimFpRoundtrips): # bug #15397, bug #13196 +block: # bug #15397, bug #13196 testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 3e9c422e0..205160471 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -161,16 +161,15 @@ template fn() = doAssert b[2].signbit doAssert not b[3].signbit - when defined(nimFpRoundtrips): - block: # bug #15397, bug #13196 - let a = 0.1 - let x = 0.12345678901234567890123456789 - let b = (a + 0.2, 0.3, x) - testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]" + block: # bug #15397, bug #13196 + let a = 0.1 + let x = 0.12345678901234567890123456789 + let b = (a + 0.2, 0.3, x) + testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]" - testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" - testRoundtripVal(epsilon(float64)): "2.220446049250313e-16" - testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" + testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568" + testRoundtripVal(epsilon(float64)): "2.220446049250313e-16" + testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002" block: # case object type Foo = object From f8519657c43f458db9c915cec62c59022041eb05 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 20 Jul 2021 22:15:06 +0200 Subject: [PATCH 2849/4254] fixes #18469 (#18544) * fixes #18469 * Update compiler/injectdestructors.nim --- compiler/injectdestructors.nim | 25 ++++++++++++--- compiler/jsgen.nim | 10 ------ compiler/types.nim | 10 ++++++ tests/arc/tcursor_field_obj_constr.nim | 44 ++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 tests/arc/tcursor_field_obj_constr.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 6e4eaa817..cf09b3ff5 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -774,7 +774,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = passCopyToSink(n, c, s) else: case n.kind - of nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkCurly: + of nkBracket, nkTupleConstr, nkClosure, nkCurly: # Let C(x) be the construction, 'x' the vector of arguments. # C(x) either owns 'x' or it doesn't. # If C(x) owns its data, we must consume C(x). @@ -785,13 +785,11 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = # don't destroy it" # but if C(x) is a ref it MUST own its data since we must destroy it # so then we have no choice but to use 'sinkArg'. - let isRefConstr = n.kind == nkObjConstr and n.typ.skipTypes(abstractInst).kind == tyRef - let m = if isRefConstr: sinkArg - elif mode == normal: normal + let m = if mode == normal: normal else: sinkArg result = copyTree(n) - for i in ord(n.kind in {nkObjConstr, nkClosure}).. Date: Wed, 21 Jul 2021 08:51:03 +0200 Subject: [PATCH 2850/4254] =?UTF-8?q?undo=20RFC=20#294,=20it=20breaks=20co?= =?UTF-8?q?de=20for=20no=20good=20reason,=20the=20compiler=20can=20wa?= =?UTF-8?q?=E2=80=A6=20(#18546)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * undo RFC #294, it breaks code for no good reason, the compiler can warn about the construct instead * Update changelog.md Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * enable test case Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 9 ++++----- compiler/lineinfos.nim | 2 ++ compiler/semexprs.nim | 4 +--- compiler/types.nim | 2 -- tests/misc/tconv.nim | 8 +++----- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/changelog.md b/changelog.md index a633c1fb3..1a904d043 100644 --- a/changelog.md +++ b/changelog.md @@ -23,15 +23,14 @@ - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. -- An enum now can't be converted to another enum directly, you must use `ord` (or `cast`, but - compiler won't help if you misuse it). +- A type conversion from one enum type to another now produces an `[EnumConv]` warning. + You should use `ord` (or `cast`, but the compiler won't help, if you misuse it) instead. ``` type A = enum a1, a2 type B = enum b1, b2 - doAssert not compiles(a1.B) - doAssert compiles(a1.ord.B) + echo a1.B # produces a warning + echo a1.ord.B # produces no warning ``` - for a transition period, use `-d:nimLegacyConvEnumEnum`. - Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous behavior. diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 8ab52a452..a3243d5fc 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -70,6 +70,7 @@ type warnResultUsed = "ResultUsed", warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", + warnSuspiciousEnumConv = "EnumConv", warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -153,6 +154,7 @@ const warnResultUsed: "used 'result' variable", warnCannotOpen: "cannot open: $1", warnFileChanged: "file changed: $1", + warnSuspiciousEnumConv: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f46d44bf0..c25a4067f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -168,9 +168,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = elif (targetBaseTyp.kind in IntegralTypes) and (srcBaseTyp.kind in IntegralTypes): if targetTyp.kind == tyEnum and srcBaseTyp.kind == tyEnum: - if c.config.isDefined("nimLegacyConvEnumEnum"): - message(c.config, src.info, warnUser, "enum to enum conversion is now deprecated") - else: result = convNotLegal + message(c.config, src.info, warnSuspiciousEnumConv, "suspicious code: enum to enum conversion") # `elif` would be incorrect here if targetTyp.kind == tyBool: discard "convOk" diff --git a/compiler/types.nim b/compiler/types.nim index 0a50af56e..798f872c2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1598,8 +1598,6 @@ proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType, n: P of efLockLevelsDiffer: msg.add "\nlock levels differ" - if formal.kind == tyEnum and actual.kind == tyEnum: - msg.add "\nmaybe use `-d:nimLegacyConvEnumEnum` for a transition period" localError(conf, info, msg) proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index c93fc57f8..94677b1bf 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -1,7 +1,5 @@ discard """ - nimout:''' -tconv.nim(81, 15) Warning: enum to enum conversion is now deprecated [User] -''' + matrix: "--warningAsError:EnumConv" """ template reject(x) = @@ -77,12 +75,12 @@ block: # https://github.com/nim-lang/RFCs/issues/294 reject: k2.Goo reject: k2.string - {.define(nimLegacyConvEnumEnum).} + {.push warningAsError[EnumConv]:off.} discard Goo(k2) accept: Goo(k2) accept: k2.Goo reject: k2.string - {.undef(nimLegacyConvEnumEnum).} + {.pop.} reject: Goo(k2) reject: k2.Goo From b6f9f7a33eb550a75350c2bce8423269734bb185 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 21 Jul 2021 09:09:43 +0200 Subject: [PATCH 2851/4254] atlas: minor changes --- tools/atlas/atlas.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 371a1c13f..b10ec0358 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -14,7 +14,7 @@ import parse_requires, osutils, packagesjson const Version = "0.1" - Usage = "atlas - Nim Package Manager Version " & Version & """ + Usage = "atlas - Nim Package Cloner Version " & Version & """ (c) 2021 Andreas Rumpf Usage: @@ -170,7 +170,7 @@ proc toName(p: string): PackageName = else: result = PackageName p -proc needsCommitLookup(commit: string): bool {.inline} = +proc needsCommitLookup(commit: string): bool {.inline.} = '.' in commit or commit == InvalidCommit proc isShortCommitHash(commit: string): bool {.inline.} = From 9c2442af94fc3db8486ee16e82ea27752e9ae4f5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 21 Jul 2021 09:46:18 +0200 Subject: [PATCH 2852/4254] unary slices get a deprecation period (#18549) --- changelog.md | 3 +-- lib/system.nim | 17 ++++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 1a904d043..ece88f710 100644 --- a/changelog.md +++ b/changelog.md @@ -63,8 +63,7 @@ - `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, `hashes.hash(closure)` has also been improved. -- The unary slice `..b` was removed, use `0..b` instead or use `-d:nimLegacyUnarySlice` - for a deprecation period. +- The unary slice `..b` was deprecated, use `0..b` instead. - Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. diff --git a/lib/system.nim b/lib/system.nim index 1da1444d2..e6a2439df 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -511,15 +511,14 @@ proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, mag ## echo a[2 .. 3] # @[30, 40] result = HSlice[T, U](a: a, b: b) -when defined(nimLegacyUnarySlice): - proc `..`*[T](b: sink T): HSlice[int, T] - {.noSideEffect, inline, magic: "DotDot", deprecated: "replace `..b` with `0..b`".} = - ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. - ## - ## .. code-block:: Nim - ## let a = [10, 20, 30, 40, 50] - ## echo a[.. 2] # @[10, 20, 30] - result = HSlice[int, T](a: 0, b: b) +proc `..`*[T](b: sink T): HSlice[int, T] + {.noSideEffect, inline, magic: "DotDot", deprecated: "replace `..b` with `0..b`".} = + ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. + ## + ## .. code-block:: Nim + ## let a = [10, 20, 30, 40, 50] + ## echo a[.. 2] # @[10, 20, 30] + result = HSlice[int, T](a: 0, b: b) when defined(hotCodeReloading): {.pragma: hcrInline, inline.} From f048dad7c3af7d70fbb852a59cb5bdda332e96d7 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 21 Jul 2021 15:47:06 +0800 Subject: [PATCH 2853/4254] add testcase for #6499 #12229 #7172 (#18547) --- tests/magics/tmagics.nim | 8 ++++++++ tests/threads/t7172.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/threads/t7172.nim diff --git a/tests/magics/tmagics.nim b/tests/magics/tmagics.nim index fa138320c..70926a0d7 100644 --- a/tests/magics/tmagics.nim +++ b/tests/magics/tmagics.nim @@ -55,3 +55,11 @@ block t9442: GC_unref(v2) GC_ref(v3) GC_unref(v3) + +block: # bug #6499 + let x = (chr, 0) + doAssert x[1] == 0 + +block: # bug #12229 + proc foo(T: typedesc) = discard + foo(ref) diff --git a/tests/threads/t7172.nim b/tests/threads/t7172.nim new file mode 100644 index 000000000..983765dba --- /dev/null +++ b/tests/threads/t7172.nim @@ -0,0 +1,32 @@ +discard """ + output: ''' +In doStuff() +In initProcess() +initProcess() done +TEST +Crashes before getting here! +''' + joinable: false +""" + +import std/os + +proc whatever() {.thread, nimcall.} = + echo("TEST") + +proc initProcess(): void = + echo("In initProcess()") + var thread: Thread[void] + createThread(thread, whatever) + echo("initProcess() done") + joinThread(thread) + +proc doStuff(): void = + echo("In doStuff()") + # ... + initProcess() + sleep(500) + # ... + echo("Crashes before getting here!") + +doStuff() From f86a530214d56f39664d6aaca3ddddf3b2fdba0c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 21 Jul 2021 10:22:30 +0200 Subject: [PATCH 2854/4254] breaking changes policies (#18541) * document some std library evolution policies In wanting to improve the standard library, it's helpful to have a set of principles and guidelines to lean back on, that show how to introduce such improvements while at the same time considering existing users of the language. A key idea behind documentation of this sort is that it should highlight a path forwards in making changes rather than trying to prevent them, and although the current snippet does include some language for what one shouldn't do, it also shows a few options for what one can do. This is a riff on https://github.com/nim-lang/Nim/pull/18468 mainly based on what helps enable to the use of Nim productively in environments and teams where the priority and focus is not always on the tool (Nim in this case) but rather on the codebase itself, and its use by end users. We use similar guidance documentation to help coordinate the code of the teams using Nim in https://status-im.github.io/nim-style-guide/ where it is applied not as law, but rather as recommendations for the default approach that should be considered first. * document the new policies * typo * Update doc/contributing.rst Co-authored-by: Timothee Cour * Update doc/contributing.rst * Update doc/contributing.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/contributing.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/contributing.rst * Update doc/contributing.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * clarify some things * Update doc/contributing.rst Co-authored-by: Dominik Picheta Co-authored-by: Jacek Sieka Co-authored-by: Timothee Cour Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Dominik Picheta --- doc/contributing.rst | 114 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/doc/contributing.rst b/doc/contributing.rst index 5a31d85bd..07fa01714 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -671,3 +671,117 @@ Conventions Furthermore, module names should use `snake_case` and not use capital letters, which cause issues when going from an OS without case sensitivity to an OS with it. + + +Breaking Changes +================ + +Introducing breaking changes, no matter how well intentioned, +creates long-term problems for the community, in particular those looking to promote +reusable Nim code in libraries: In the Nim distribution, critical security and bugfixes, +language changes and community improvements are bundled in a single distribution - it is +difficult to make partial upgrades with only benign changes. When one library depends on +a legacy behavior, it can no longer be used together with another library that does not, +breaking all downstream applications - the standard library is unique in that it sits at +the root of **all** dependency trees. + +There is a big difference between compile-time breaking changes and run-time breaking +changes. + + +Run-time breaking changes +------------------------- + +Run-time breaking changes are to be avoided at almost all costs: Nim is used for +mission critical applications which depend on behaviours that +are not covered by the test suite. As such, it's important that changes to the +*stable* parts of the standard library are made avoiding changing the existing +behaviors, even when the test suite continues to pass. + +Examples of run-time breaking changes: + +- Raising exceptions of a new type, compared to what's currently being raised. + +- Adding unconstrained or poorly constrained generic procs or macros + ("hash now works for all `ref T`"): This may cause code to behave differently + depending only on which modules are imported - common examples include `==` and `hash`. + +- Changing behavior of existing functions like: + + * "Nim's path handling procs like `getXDir` now consistently lack the trailing slash" + * "Nim's strformat implementation is now more consistent with Python" + +Instead write new code that explicitly announces the feature you think we announced but +didn't. For example, `strformat` does not say "it's compatible with Python", it +says "inspired by Python's f-strings". This new code can be submitted to the stdlib +and the old code can be deprecated or it can be published as a Nimble package. + +Sometimes, a run-time breaking change is most desirable: For example, a string +representation of a floating point number that "roundtrips" is much better than +a string represenation that doesn't. These run-time breaking changes must start in the +state "opt-in" via a new `-d:nimPreviewX` or command line flag and then should become +the new default later, in follow-up versions. This way users can track +regressions more easily. ("git bisect" is not an acceptable alternative, that's for +Nim compiler developers, not for Nim users.) + +Above all else, additive approaches that don't change existing behaviors +should be preferred. + + +Compile-time breaking changes +----------------------------- + +Compile-time breaking changes are usually easier to handle, but for large code bases +it can also be much work and it can hinder the adoption of a new Nim release. +Additive approaches are to be preferred here as well. + +Examples of compile-time breaking changes include (but are not limited to): + +* Renaming functions and modules, or moving things. Instead of a direct rename, + deprecate the old name and introduce a new one. +* Renaming the parameter names: Thanks to Nim's "named parameter" calling syntax + like `f(x = 0, y = 1)` this is a breaking change. Instead live with the existing + parameter names. +* Adding an enum value to an existing enum. Nim's exhaustive case statements stop + compiling after such a change. Instead consider to introduce new `bool` + fields/parameters. This can be impractical though, so we use good judgement + and our list of "important packages" to see if it doesn't break too much code + out there in practice. +* Adding a new proc to an existing stdlib module. However, for aesthetic reasons + this is often preferred over introducing a new module with just a single proc + inside. We use good judgement and our list of "important packages" to see if + it doesn't break too much code out there in practice. The new procs need to + be annotated with a `.since` annotation. + + +Compiler/language spec bugfixes +------------------------------- + +This can even be applied to compiler "bugfixes": If the compiler should have been +"pickier" in its handling of `typedesc`, instead of "fixing typedesc handling bugs", +consider the following solution: + +- Spec out how `typedesc` should really work and also spec out the cases where it + should not be allowed! +- Deprecate `typedesc` and name the new metatype something new like `typeArg`. +- Implement the spec. + + +Non-breaking changes +-------------------- + +Examples of changes that are considered non-breaking (or acceptable breaking changes) include: + +* Creating a new module. +* Adding an overload to an already overloaded proc. +* Adding new default parameters to an existing proc. It is assumed that you do not + use Nim's stdlib procs's addresses (that you don't use them as first class entities). +* Changing the calling convention from `nimcall` to `inline` + (but first RFC https://github.com/nim-lang/RFCs/issues/396 needs to be implemented). +* Changing the behavior from "crashing" into some other, well documented result (including + raising a Defect, but not raising an exception that does not inherit from Defect). +* Adding new fields to an existing object. + +Nim's introspection facilities imply that strictly speaking almost every addition can +break somebody's code. It is impractical to care about these cases, a change that only +affects introspection is not considered to be a breaking change. From 6f34829ee5a060300859002fd41f0181c0adf754 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 21 Jul 2021 19:46:17 +0800 Subject: [PATCH 2855/4254] clean unused imports on runnableExamples (#18551) --- lib/std/monotimes.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index 3bb4fa141..bd078d7c0 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -15,8 +15,6 @@ meaning that that the following is guaranteed to work: ]## runnableExamples: - import std/os - let a = getMonoTime() let b = getMonoTime() assert a <= b From 880353c0ad9300f2543c1b16548b4f2ab6784183 Mon Sep 17 00:00:00 2001 From: IterableTrucks <42210451+IterableTrucks@users.noreply.github.com> Date: Wed, 21 Jul 2021 20:13:50 +0800 Subject: [PATCH 2856/4254] complement notes of two doc strings of tables module (#18527) * complement notes of two doc strings warning the deprecated procedure's side effect * Update lib/pure/collections/tables.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update lib/pure/collections/tables.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: BillyZee Co-authored-by: Andreas Rumpf Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/collections/tables.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index d617e06e4..b845f57cc 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -496,6 +496,8 @@ template tabCellHash(i) = t.data[i].hcode proc del*[A, B](t: var Table[A, B], key: A) = ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. ## + ## .. warning:: If duplicate keys were added, this may need to be called multiple times. + ## ## See also: ## * `pop proc<#pop,Table[A,B],A,B>`_ ## * `clear proc<#clear,Table[A,B]>`_ to empty the whole table @@ -514,6 +516,8 @@ proc pop*[A, B](t: var Table[A, B], key: A, val: var B): bool = ## mapping of the key. Otherwise, returns `false`, and the `val` is ## unchanged. ## + ## .. warning:: If duplicate keys were added, this may need to be called multiple times. + ## ## See also: ## * `del proc<#del,Table[A,B],A>`_ ## * `clear proc<#clear,Table[A,B]>`_ to empty the whole table From 58080525a1dcad23de6ad0cf9ca6988f103de350 Mon Sep 17 00:00:00 2001 From: itsumura-h <39766805+itsumura-h@users.noreply.github.com> Date: Wed, 21 Jul 2021 22:03:48 +0900 Subject: [PATCH 2857/4254] add [1..2] for JArray (#18525) * add [1..2] for JArray * fix BackwardsIndex to int * fix for BackwardsIndex * fix for assert node kind check * fix variable name * Update lib/pure/json.nim * fix for when x.a is BackwardsIndex Co-authored-by: itsumura-h Co-authored-by: Dominik Picheta --- lib/pure/json.nim | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index d5bbb86b8..85c3393b2 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -531,6 +531,24 @@ proc `[]`*(node: JsonNode, index: BackwardsIndex): JsonNode {.inline, since: (1, `[]`(node, node.len - int(index)) +proc `[]`*[U, V](a: JsonNode, x: HSlice[U, V]): JsonNode = + ## Slice operation for JArray. + ## + ## Returns the inclusive range `[a[x.a], a[x.b]]`: + runnableExamples: + import json + let arr = %[0,1,2,3,4,5] + doAssert arr[2..4] == %[2,3,4] + doAssert arr[2..^2] == %[2,3,4] + doAssert arr[^4..^2] == %[2,3,4] + + assert(a.kind == JArray) + result = newJArray() + let xa = (when x.a is BackwardsIndex: a.len - int(x.a) else: int(x.a)) + let L = (when x.b is BackwardsIndex: a.len - int(x.b) else: int(x.b)) - xa + 1 + for i in 0.. Date: Wed, 21 Jul 2021 16:55:50 +0200 Subject: [PATCH 2858/4254] fixes #18550 (#18553) * fixes #18550 * update the manual to reflect reality --- changelog.md | 4 ++++ compiler/lineinfos.nim | 2 ++ compiler/sempass2.nim | 16 ++++++++++++++++ compiler/sighashes.nim | 4 +++- compiler/types.nim | 15 +++++++++++++++ doc/manual.rst | 7 +++---- lib/system/io.nim | 8 ++++---- lib/system/widestrs.nim | 2 +- tests/misc/tconv.nim | 10 +++++++++- 9 files changed, 57 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index ece88f710..f2a9ca914 100644 --- a/changelog.md +++ b/changelog.md @@ -32,6 +32,10 @@ echo a1.ord.B # produces no warning ``` +- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning. + This warning will become an error in future versions! Use an explicit conversion + like `cstring(x)` in order to silence the warning. + - Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous behavior. diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index a3243d5fc..3f31ceb97 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -71,6 +71,7 @@ type warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", warnSuspiciousEnumConv = "EnumConv", + warnCstringConv = "CStringConv", warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -155,6 +156,7 @@ const warnCannotOpen: "cannot open: $1", warnFileChanged: "file changed: $1", warnSuspiciousEnumConv: "$1", + warnCstringConv: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 1e1672cad..ce21c3ed2 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -951,6 +951,15 @@ proc trackInnerProc(tracked: PEffects, n: PNode) = else: for ch in n: trackInnerProc(tracked, ch) +proc allowCStringConv(n: PNode): bool = + case n.kind + of nkStrLit..nkTripleStrLit: result = true + of nkSym: result = n.sym.kind in {skConst, skParam} + of nkAddr: result = isCharArrayPtr(n.typ, true) + of nkCallKinds: + result = isCharArrayPtr(n.typ, n[0].kind == nkSym and n[0].sym.magic == mAddr) + else: result = isCharArrayPtr(n.typ, false) + proc track(tracked: PEffects, n: PNode) = case n.kind of nkSym: @@ -1157,6 +1166,13 @@ proc track(tracked: PEffects, n: PNode) = if tracked.owner.kind != skMacro: createTypeBoundOps(tracked, n.typ, n.info) of nkHiddenStdConv, nkHiddenSubConv, nkConv: + if n.kind in {nkHiddenStdConv, nkHiddenSubConv} and + n.typ.skipTypes(abstractInst).kind == tyCstring and + not allowCStringConv(n[1]): + message(tracked.config, n.info, warnCstringConv, + "implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" % + [$n[1]]) + if n.len == 2: track(tracked, n[1]) if tracked.owner.kind != skMacro: diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index f6df422e6..0ff97017f 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -14,7 +14,9 @@ from hashes import Hash import types proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) -proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1) +proc `&=`(c: var MD5Context, ch: char) = + # XXX suspicious code here; relies on ch being zero terminated? + md5Update(c, unsafeAddr ch, 1) proc `&=`(c: var MD5Context, r: Rope) = for l in leaves(r): md5Update(c, l, l.len) proc `&=`(c: var MD5Context, i: BiggestInt) = diff --git a/compiler/types.nim b/compiler/types.nim index 798f872c2..f0bd99a17 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1664,3 +1664,18 @@ proc lookupFieldAgain*(ty: PType; field: PSym): PSym = if result != nil: break ty = ty[0] if result == nil: result = field + +proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool = + let t = t.skipTypes(abstractInst) + if t.kind == tyPtr: + let pointsTo = t[0].skipTypes(abstractInst) + case pointsTo.kind + of tyUncheckedArray: + result = pointsTo[0].kind == tyChar + of tyArray: + result = pointsTo[1].kind == tyChar and firstOrd(nil, pointsTo[0]) == 0 and + skipTypes(pointsTo[0], {tyRange}).kind in {tyInt..tyInt64} + of tyChar: + result = allowPointerToChar + else: + discard diff --git a/doc/manual.rst b/doc/manual.rst index f0bd85638..9f614c2cd 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1380,10 +1380,9 @@ variadic proc, it is implicitly converted to `cstring` too: Even though the conversion is implicit, it is not *safe*: The garbage collector does not consider a `cstring` to be a root and may collect the underlying -memory. However, in practice, this almost never happens as the GC considers -stack roots conservatively. One can use the builtin procs `GC_ref` and -`GC_unref` to keep the string data alive for the rare cases where it does -not work. +memory. For this reason, the implicit conversion will be removed in future +releases of the Nim compiler. Certain idioms like conversion of a `const` string +to `cstring` are safe and will remain to be allowed. A `$` proc is defined for cstrings that returns a string. Thus to get a nim string from a cstring: diff --git a/lib/system/io.nim b/lib/system/io.nim index 591ea3e92..d8b2ac741 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -630,8 +630,8 @@ const "" else: "" - FormatOpen: array[FileMode, string] = [ - "rb" & NoInheritFlag, "wb" & NoInheritFlag, "w+b" & NoInheritFlag, + FormatOpen: array[FileMode, cstring] = [ + cstring("rb" & NoInheritFlag), "wb" & NoInheritFlag, "w+b" & NoInheritFlag, "r+b" & NoInheritFlag, "ab" & NoInheritFlag ] #"rt", "wt", "w+t", "r+t", "at" @@ -678,7 +678,7 @@ proc open*(f: var File, filename: string, ## This throws no exception if the file could not be opened. ## ## The file handle associated with the resulting `File` is not inheritable. - var p = fopen(filename, FormatOpen[mode]) + var p = fopen(filename.cstring, FormatOpen[mode]) if p != nil: var f2 = cast[File](p) when defined(posix) and not defined(nimscript): @@ -711,7 +711,7 @@ proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. ## Default mode is readonly. Returns true if the file could be reopened. ## ## The file handle associated with `f` won't be inheritable. - if freopen(filename, FormatOpen[mode], f) != nil: + if freopen(filename.cstring, FormatOpen[mode], f) != nil: when not defined(nimInheritHandles) and declared(setInheritable) and NoInheritFlag.len == 0: if not setInheritable(getOsFileHandle(f), false): diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index a999c9167..8b08959b5 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -171,7 +171,7 @@ proc newWideCString*(s: cstring): WideCStringObj = result = newWideCString(s, s.len) proc newWideCString*(s: string): WideCStringObj = - result = newWideCString(s, s.len) + result = newWideCString(cstring s, s.len) proc `$`*(w: WideCString, estimate: int, replacement: int = 0xFFFD): string = result = newStringOfCap(estimate + estimate shr 2) diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index 94677b1bf..1cb4b4fbf 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--warningAsError:EnumConv" + matrix: "--warningAsError:EnumConv --warningAsError:CStringConv" """ template reject(x) = @@ -84,3 +84,11 @@ block: # https://github.com/nim-lang/RFCs/issues/294 reject: Goo(k2) reject: k2.Goo + +reject: + # bug #18550 + proc f(c: char): cstring = + var x = newString(109*1024*1024) + x[0] = c + x + From d5b5827bc2a3724290d3257b0f2fa70004c37c97 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Jul 2021 23:00:29 -0700 Subject: [PATCH 2859/4254] fix setCommand so it behaves like regular nim invocation (#18555) --- compiler/cmdlinehelper.nim | 9 +-------- compiler/options.nim | 10 ++++++++++ compiler/scriptconfig.nim | 11 +---------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index c6a0f200a..007dc2319 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -44,14 +44,7 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) = elif self.supportsStdinFile and conf.projectName == "-": handleStdinInput(conf) elif conf.projectName != "": - try: - conf.projectFull = canonicalizePath(conf, AbsoluteFile conf.projectName) - except OSError: - conf.projectFull = AbsoluteFile conf.projectName - let p = splitFile(conf.projectFull) - let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir - conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir) - conf.projectName = p.name + setFromProjectName(conf, conf.projectName) else: conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir()) diff --git a/compiler/options.nim b/compiler/options.nim index 45ca14e76..f02f02256 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -695,6 +695,16 @@ proc setDefaultLibpath*(conf: ConfigRef) = proc canonicalizePath*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile = result = AbsoluteFile path.string.expandFilename +proc setFromProjectName*(conf: ConfigRef; projectName: string) = + try: + conf.projectFull = canonicalizePath(conf, AbsoluteFile projectName) + except OSError: + conf.projectFull = AbsoluteFile projectName + let p = splitFile(conf.projectFull) + let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir + conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir) + conf.projectName = p.name + proc removeTrailingDirSep*(path: string): string = if (path.len > 0) and (path[^1] == DirSep): result = substr(path, 0, path.len - 2) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index ef1ceb12b..89510f6b2 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -151,18 +151,9 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1)) cbconf setCommand: conf.setCommandEarly(a.getString 0) - # xxx move remaining logic to commands.nim or other let arg = a.getString 1 incl(conf.globalOptions, optWasNimscript) - if arg.len > 0: - conf.projectName = arg - let path = - if conf.projectName.isAbsolute: AbsoluteFile(conf.projectName) - else: conf.projectPath / RelativeFile(conf.projectName) - try: - conf.projectFull = canonicalizePath(conf, path) - except OSError: - conf.projectFull = path + if arg.len > 0: setFromProjectName(conf, arg) cbconf getCommand: setResult(a, conf.command) cbconf switch: From 58e27ebd4a16ca9f2ba24826d7162384d5321101 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 22 Jul 2021 09:37:41 +0200 Subject: [PATCH 2860/4254] fixes #12815 (#18554) --- changelog.md | 3 +++ compiler/ast.nim | 2 +- compiler/lineinfos.nim | 4 +++- compiler/sempass2.nim | 5 ++++- doc/nimc.rst | 6 ++++++ tests/misc/tconv.nim | 13 +++++++++++++ 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index f2a9ca914..8e8b0a908 100644 --- a/changelog.md +++ b/changelog.md @@ -36,6 +36,9 @@ This warning will become an error in future versions! Use an explicit conversion like `cstring(x)` in order to silence the warning. +- There is a new warning for *any* type conversion to enum that can be enabled via + `.warning[AnyEnumConv]:on` or `--warning:AnyEnumConv:on`. + - Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous behavior. diff --git a/compiler/ast.nim b/compiler/ast.nim index 8b836e088..0eeaa8133 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1064,7 +1064,7 @@ proc getPIdent*(a: PNode): PIdent {.inline.} = # which may simplify code. case a.kind of nkSym: a.sym.name - of nkIdent: a.ident + of nkIdent: a.ident else: nil proc getnimblePkg*(a: PSym): PSym = diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 3f31ceb97..8cb834156 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -71,6 +71,7 @@ type warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", warnSuspiciousEnumConv = "EnumConv", + warnAnyEnumConv = "AnyEnumConv", warnCstringConv = "CStringConv", warnUser = "User", # hints @@ -156,6 +157,7 @@ const warnCannotOpen: "cannot open: $1", warnFileChanged: "file changed: $1", warnSuspiciousEnumConv: "$1", + warnAnyEnumConv: "$1", warnCstringConv: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", @@ -211,7 +213,7 @@ type TNoteKinds* = set[TNoteKind] proc computeNotesVerbosity(): array[0..3, TNoteKinds] = - result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed} + result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv} result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index ce21c3ed2..87ed81098 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1171,7 +1171,10 @@ proc track(tracked: PEffects, n: PNode) = not allowCStringConv(n[1]): message(tracked.config, n.info, warnCstringConv, "implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" % - [$n[1]]) + $n[1]) + + if n.typ.skipTypes(abstractInst).kind == tyEnum: + message(tracked.config, n.info, warnAnyEnumConv, "enum conversion: $1" % $n[1]) if n.len == 2: track(tracked, n[1]) diff --git a/doc/nimc.rst b/doc/nimc.rst index 070956860..3c451706b 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -70,6 +70,12 @@ SmallLshouldNotBeUsed The letter 'l' should not be used as an identifier. EachIdentIsTuple The code contains a confusing `var` declaration. +CStringConv Warn about dangerous implicit conversions + to `cstring`. +EnumConv Warn about conversions from enum to enum. +AnyEnumConv Warn about any conversions to an enum type. +ResultUsed Warn about the usage of the + built-in `result` variable. User Some user-defined warning. ========================== ============================================ diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index 1cb4b4fbf..ff6875021 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -92,3 +92,16 @@ reject: x[0] = c x +{.push warning[AnyEnumConv]:on, warningAsError[AnyEnumConv]:on.} + +reject: + # bug #12815 + type + Foo = enum + one = 1 + three = 3 + + var va = 2 + var vb = va.Foo + +{.pop.} From 0c4582c66524d58a3c72827d9546a5c5f1c40286 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 22 Jul 2021 11:59:21 +0200 Subject: [PATCH 2861/4254] mitigates #12815 (#18557) * mitigates #12815 * Update doc/nimc.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- compiler/lineinfos.nim | 2 ++ compiler/sempass2.nim | 8 ++++++-- doc/nimc.rst | 2 ++ tests/misc/tconv.nim | 19 ++++++++++++++++--- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 8cb834156..c64d7b9dd 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -72,6 +72,7 @@ type warnFileChanged = "FileChanged", warnSuspiciousEnumConv = "EnumConv", warnAnyEnumConv = "AnyEnumConv", + warnHoleEnumConv = "HoleEnumConv", warnCstringConv = "CStringConv", warnUser = "User", # hints @@ -158,6 +159,7 @@ const warnFileChanged: "file changed: $1", warnSuspiciousEnumConv: "$1", warnAnyEnumConv: "$1", + warnHoleEnumConv: "$1", warnCstringConv: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 87ed81098..e2f85dd38 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1173,8 +1173,12 @@ proc track(tracked: PEffects, n: PNode) = "implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" % $n[1]) - if n.typ.skipTypes(abstractInst).kind == tyEnum: - message(tracked.config, n.info, warnAnyEnumConv, "enum conversion: $1" % $n[1]) + let t = n.typ.skipTypes(abstractInst) + if t.kind == tyEnum: + if tfEnumHasHoles in t.flags: + message(tracked.config, n.info, warnHoleEnumConv, "conversion to enum with holes is unsafe: $1" % $n) + else: + message(tracked.config, n.info, warnAnyEnumConv, "enum conversion: $1" % $n) if n.len == 2: track(tracked, n[1]) diff --git a/doc/nimc.rst b/doc/nimc.rst index 3c451706b..ed9077912 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -74,6 +74,8 @@ CStringConv Warn about dangerous implicit conversions to `cstring`. EnumConv Warn about conversions from enum to enum. AnyEnumConv Warn about any conversions to an enum type. +HoleEnumConv Warn about conversion to an enum with + holes. These conversions are unsafe. ResultUsed Warn about the usage of the built-in `result` variable. User Some user-defined warning. diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index ff6875021..5e8eac729 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -95,13 +95,26 @@ reject: {.push warning[AnyEnumConv]:on, warningAsError[AnyEnumConv]:on.} reject: - # bug #12815 type Foo = enum - one = 1 - three = 3 + one + three var va = 2 var vb = va.Foo {.pop.} + +{.push warningAsError[HoleEnumConv]:on.} + +reject: + # bug #12815 + type + Hole = enum + one = 1 + three = 3 + + var va = 2 + var vb = va.Hole + +{.pop.} From 5386ae75ba91ee2fe280f1fe807676a7c9af4b13 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Fri, 23 Jul 2021 00:46:13 -0600 Subject: [PATCH 2862/4254] Fixed template const tuple unpacking (#18562) --- compiler/semtempl.nim | 40 ++++++++++++++++++---------------------- tests/vm/tconst.nim | 10 ++++++++++ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 92cc0be8c..a2b0f99ba 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -209,7 +209,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = let pragmaNode = n[1] for i in 0.. Date: Fri, 23 Jul 2021 08:04:29 +0000 Subject: [PATCH 2863/4254] Replace calls to `putenv` with `setenv` (#18530) * Replace calls to C `putenv` with C `setenv` to remove possible memory leaks * Add test of correct behaviour on invalid input * Fix style in tests/stdlib/tos.nim Co-authored-by: Timothee Cour * Update tests/stdlib/tos.nim Co-authored-by: Timothee Cour * Update tests/stdlib/tos.nim Co-authored-by: Timothee Cour * Add comment with bug number to tests/stdlib/tos.nim Co-authored-by: Timothee Cour * Fix possible msvc arch issues Co-authored-by: Timothee Cour --- lib/pure/includes/osenv.nim | 11 ++++++++--- tests/stdlib/tos.nim | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index d0c92d566..db291c5fd 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -45,8 +45,10 @@ else: proc c_getenv(env: cstring): cstring {. importc: "getenv", header: "".} - proc c_putenv(env: cstring): cint {. - importc: "putenv", header: "".} + when defined(vcc): + proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + else: + proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} proc c_unsetenv(env: cstring): cint {. importc: "unsetenv", header: "".} @@ -220,8 +222,11 @@ else: if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) else: if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) + elif defined(vcc): + if c_putenv_s(key, val) != 0'i32: + raiseOSError(osLastError()) else: - if c_putenv(environment[indx]) != 0'i32: + if c_setenv(key, val, 1'i32) != 0'i32: raiseOSError(osLastError()) proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 912558461..8a12b9b90 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -614,6 +614,9 @@ block osenv: doAssert existsEnv(dummyEnvVar) == false delEnv(dummyEnvVar) # deleting an already deleted env var doAssert existsEnv(dummyEnvVar) == false + block: # putEnv, bug #18502 + doAssertRaises(OSError): putEnv("DUMMY_ENV_VAR_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE") + doAssertRaises(OSError): putEnv("", "NEW_DUMMY_VALUE") block: doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", "") == "" doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", " ") == " " From 76f74fae88fba72f58e43ad5c8fd20a7c4d8b439 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 23 Jul 2021 04:41:16 -0700 Subject: [PATCH 2864/4254] std/random: fix overflow bugs; fixes #16360; fixes #16296; fixes #17670 (#18456) --- lib/pure/random.nim | 32 ++++++++++++++------ tests/stdlib/trandom.nim | 63 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 07db0365c..a292386af 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -204,6 +204,19 @@ proc skipRandomNumbers*(s: var Rand) = s.a0 = s0 s.a1 = s1 +proc rand[T: uint | uint64](r: var Rand; max: T): T = + # xxx export in future work + if max == 0: return + else: + let max = uint64(max) + when T.high.uint64 == uint64.high: + if max == uint64.high: return T(next(r)) + while true: + let x = next(r) + # avoid `mod` bias + if x <= randMax - (randMax mod max): + return T(x mod (max + 1)) + proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. ## @@ -213,15 +226,13 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_ ## that accepts a slice ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type - runnableExamples("-r:off"): + runnableExamples: var r = initRand(123) - assert r.rand(100) == 96 # implementation defined - - if max == 0: return - while true: - let x = next(r) - if x <= randMax - (randMax mod Ui(max)): - return int(x mod (uint64(max) + 1u64)) + if false: + assert r.rand(100) == 96 # implementation defined + # bootstrap: can't use `runnableExamples("-r:off")` + cast[int](rand(r, uint64(max))) + # xxx toUnsigned pending https://github.com/nim-lang/Nim/pull/18445 proc rand*(max: int): int {.benign.} = ## Returns a random integer in the range `0..max`. @@ -306,7 +317,10 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = when T is SomeFloat: result = rand(r, x.b - x.a) + x.a else: # Integers and Enum types - result = T(rand(r, int(x.b) - int(x.a)) + int(x.a)) + when defined(js): + result = cast[T](rand(r, cast[uint](x.b) - cast[uint](x.a)) + cast[uint](x.a)) + else: + result = cast[T](rand(r, cast[uint64](x.b) - cast[uint64](x.a)) + cast[uint64](x.a)) proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = ## For a slice `a..b`, returns a value in the range `a..b`. diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index e47ddad66..39ccca85b 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -3,7 +3,9 @@ discard """ targets: "c js" """ -import std/[random, math, os, stats, sets, tables] +import std/[random, math, stats, sets, tables] +when not defined(js): + import std/os randomize(233) @@ -187,3 +189,62 @@ block: # bug #17467 doAssert x > 1e-4, $(x, i) # This used to fail for each i in 0..<26844, i.e. the 1st produced value # was predictable and < 1e-4, skewing distributions. + +const withUint = false # pending exporting `proc rand[T: uint | uint64](r: var Rand; max: T): T =` + +block: # bug #16360 + var r = initRand() + template test(a) = + let a2 = a + block: + let a3 = r.rand(a2) + doAssert a3 <= a2 + doAssert a3.type is a2.type + block: + let a3 = rand(a2) + doAssert a3 <= a2 + doAssert a3.type is a2.type + when withUint: + test cast[uint](int.high) + test cast[uint](int.high) + 1 + when not defined(js): + # pending bug #16411 + test uint64.high + test uint64.high - 1 + test uint.high - 2 + test uint.high - 1 + test uint.high + test int.high + test int.high - 1 + test int.high - 2 + test 0 + when withUint: + test 0'u + test 0'u64 + +block: # bug #16296 + var r = initRand() + template test(x) = + let a2 = x + let a3 = r.rand(a2) + doAssert a3 <= a2.b + doAssert a3 >= a2.a + doAssert a3.type is a2.a.type + test(-2 .. int.high-1) + test(int.low .. int.high) + test(int.low+1 .. int.high) + test(int.low .. int.high-1) + test(int.low .. 0) + test(int.low .. -1) + test(int.low .. 1) + test(int64.low .. 1'i64) + when not defined(js): + # pending bug #16411 + test(10'u64 .. uint64.high) + +block: # bug #17670 + when not defined(js): + # pending bug #16411 + type UInt48 = range[0'u64..2'u64^48-1] + let x = rand(UInt48) + doAssert x is UInt48 From faabcfa6432cd15ecfee44a061ebf7738b16ad6c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 23 Jul 2021 16:15:40 +0200 Subject: [PATCH 2865/4254] fixes #18558 (#18563) * fixes #18558 * better fix --- compiler/ccgcalls.nim | 44 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 616028ac6..510b8d9ec 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -317,36 +317,46 @@ proc skipTrivialIndirections(n: PNode): PNode = result = n while true: case result.kind - of {nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv}: + of nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv: result = result[0] - of {nkHiddenStdConv, nkHiddenSubConv}: + of nkHiddenStdConv, nkHiddenSubConv: result = result[1] else: break -proc getPotentialWrites(n: PNode, mutate = false): seq[PNode] = +proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) = case n.kind: of nkLiterals, nkIdent: discard of nkSym: if mutate: result.add n of nkAsgn, nkFastAsgn: - result.add getPotentialWrites(n[0], true) - result.add getPotentialWrites(n[1], mutate) + getPotentialWrites(n[0], true, result) + getPotentialWrites(n[1], mutate, result) of nkAddr, nkHiddenAddr: - result.add getPotentialWrites(n[0], true) - of nkCallKinds: #TODO: Find out why in f += 1, f is a nkSym and not a nkHiddenAddr - for s in n.sons: - result.add getPotentialWrites(s, true) + getPotentialWrites(n[0], true, result) + of nkCallKinds: + case n.getMagic: + of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem, + mAddr, mNew, mNewFinalize, mWasMoved, mDestroy, mReset: + getPotentialWrites(n[1], true, result) + for i in 2.. Date: Fri, 23 Jul 2021 14:57:47 -0700 Subject: [PATCH 2866/4254] rename nimFpRoundtrips => nimPreviewFloatRoundtrip (#18566) --- changelog.md | 4 ++-- compiler/nim.cfg | 2 +- lib/system/formatfloat.nim | 4 ++-- tests/config.nims | 2 +- tests/errmsgs/treportunused.nim | 2 +- tests/float/tfloats.nim | 10 +++++----- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 8e8b0a908..d33e24b65 100644 --- a/changelog.md +++ b/changelog.md @@ -112,8 +112,8 @@ - `system.addFloat` and `system.$` now can produce string representations of floating point numbers that are minimal in size and that "roundtrip" (via the "Dragonbox" algorithm). This currently has - to be enabled via `-d:nimFpRoundtrips`. It is expected that this behavior becomes the new default - in upcoming versions. + to be enabled via `-d:nimPreviewFloatRoundtrip`. It is expected that this behavior becomes the new default + in upcoming versions, as with other `nimPreviewX` define flags. - Fixed buffer overflow bugs in `net` diff --git a/compiler/nim.cfg b/compiler/nim.cfg index f10d847ac..ec51bd463 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -4,7 +4,7 @@ hint:XDeclaredButNotUsed:off define:booting define:nimcore -define:nimFpRoundtrips +define:nimPreviewFloatRoundtrip #import:"$projectpath/testability" diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim index cb46c6ea7..3bcd3257b 100644 --- a/lib/system/formatfloat.nim +++ b/lib/system/formatfloat.nim @@ -74,7 +74,7 @@ proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): result = 3 proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} = - when defined(nimFpRoundtrips): + when defined(nimPreviewFloatRoundtrip): writeFloatToBufferRoundtrip(buf, value) else: writeFloatToBufferSprintf(buf, value) @@ -121,7 +121,7 @@ proc addFloat*(result: var string; x: float | float32) {.inline.} = s.addFloat(45.67) assert s == "foo:45.67" template impl = - when defined(nimFpRoundtrips): + when defined(nimPreviewFloatRoundtrip): addFloatRoundtrip(result, x) else: addFloatSprintf(result, x) diff --git a/tests/config.nims b/tests/config.nims index 12b303318..f876cb612 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -35,4 +35,4 @@ switch("define", "nimExperimentalAsyncjsThen") switch("define", "nimExperimentalJsfetch") switch("define", "nimExperimentalLinenoiseExtra") -switch("define", "nimFpRoundtrips") +switch("define", "nimPreviewFloatRoundtrip") diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index 3105b35ea..f5ee79afa 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -32,7 +32,7 @@ var s9: int type s10 = object type s11 = type(1.2) -# bug #14407 (requires `compiler/nim.cfg` containing define:nimFpRoundtrips) +# bug #14407 (requires `compiler/nim.cfg` containing define:nimPreviewFloatRoundtrip) let `v0.99` = "0.99" `v0.99.99` = "0.99.99" diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim index 63987bb8d..480396e81 100644 --- a/tests/float/tfloats.nim +++ b/tests/float/tfloats.nim @@ -1,5 +1,5 @@ discard """ - matrix: "-d:nimFpRoundtrips; -u:nimFpRoundtrips" + matrix: "-d:nimPreviewFloatRoundtrip; -u:nimPreviewFloatRoundtrip" targets: "c cpp js" """ @@ -67,14 +67,14 @@ template main = block: # example 1 let a = 0.1+0.2 doAssert a != 0.3 - when defined(nimFpRoundtrips): + when defined(nimPreviewFloatRoundtrip): doAssert $a == "0.30000000000000004" else: whenRuntimeJs: discard do: doAssert $a == "0.3" block: # example 2 const a = 0.1+0.2 - when defined(nimFpRoundtrips): + when defined(nimPreviewFloatRoundtrip): doAssert $($a, a) == """("0.30000000000000004", 0.30000000000000004)""" else: whenRuntimeJs: discard @@ -83,13 +83,13 @@ template main = const a1 = 0.1+0.2 let a2 = a1 doAssert a1 != 0.3 - when defined(nimFpRoundtrips): + when defined(nimPreviewFloatRoundtrip): doAssert $[$a1, $a2] == """["0.30000000000000004", "0.30000000000000004"]""" else: whenRuntimeJs: discard do: doAssert $[$a1, $a2] == """["0.3", "0.3"]""" - when defined(nimFpRoundtrips): + when defined(nimPreviewFloatRoundtrip): block: # bug #18148 var a = 1.1'f32 doAssert $a == "1.1", $a # was failing From f4ff276a90091f2b88c191aac5a201dcb3ec9795 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 24 Jul 2021 00:30:02 +0200 Subject: [PATCH 2867/4254] refactoring: removed dead code (#18567) --- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 19 +++++++------------ compiler/semobjconstr.nim | 5 ++--- compiler/semstmts.nim | 2 +- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 12bb22ff9..0a6d09a56 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -65,7 +65,7 @@ type # you may be in position to supply a better error message # to the user. efWantStmt, efAllowStmt, efDetermineType, efExplain, - efAllowDestructor, efWantValue, efOperand, efNoSemCheck, + efWantValue, efOperand, efNoSemCheck, efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check, efNoUndeclared # Use this if undeclared identifiers should not raise an error during diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c25a4067f..42c6b465e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -623,10 +623,10 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = localError(c.config, x.info, "invalid order in array constructor") x = x[1] - let xx = semExprWithType(c, x, flags*{efAllowDestructor}) + let xx = semExprWithType(c, x, {}) result.add xx typ = commonType(c, typ, xx.typ) - #n[i] = semExprWithType(c, x, flags*{efAllowDestructor}) + #n[i] = semExprWithType(c, x, {}) #result.add fitNode(c, typ, n[i]) inc(lastIndex) addSonSkipIntLit(result.typ, typ, c.idgen) @@ -1758,13 +1758,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = localError(c.config, a.info, errXCannotBeAssignedTo % renderTree(a, {renderNoComments})) else: - let - lhs = n[0] - lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult - var - rhs = semExprWithType(c, n[1], - if lhsIsResult: {efAllowDestructor} else: {}) - if lhsIsResult: + let lhs = n[0] + let rhs = semExprWithType(c, n[1], {}) + if lhs.kind == nkSym and lhs.sym.kind == skResult: n.typ = c.enforceVoidContext if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ): var rhsTyp = rhs.typ @@ -2512,8 +2508,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = let id = considerQuotedIdent(c, n[i][0]) if containsOrIncl(ids, id.id): localError(c.config, n[i].info, errFieldInitTwice % id.s) - n[i][1] = semExprWithType(c, n[i][1], - flags*{efAllowDestructor}) + n[i][1] = semExprWithType(c, n[i][1], {}) if n[i][1].typ.kind == tyTypeDesc: localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.") @@ -2533,7 +2528,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result.transitionSonsKind(nkTupleConstr) var typ = newTypeS(tyTuple, c) # leave typ.n nil! for i in 0.. Date: Sun, 25 Jul 2021 09:06:04 -0700 Subject: [PATCH 2868/4254] fixes #18385 (#18571) needs a more permanent fix by better incorporating IC, but fixes nimsuggest highlighting for now. --- compiler/vmgen.nim | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index be86550ae..4957a3339 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2254,8 +2254,16 @@ proc optimizeJumps(c: PCtx; start: int) = else: discard proc genProc(c: PCtx; s: PSym): int = - let pos = c.procToCodePos.getOrDefault(s.id) - if pos == 0: + let + pos = c.procToCodePos.getOrDefault(s.id) + wasNotGenProcBefore = pos == 0 + noRegistersAllocated = s.offset == -1 + if wasNotGenProcBefore or noRegistersAllocated: + # xxx: the noRegisterAllocated check is required in order to avoid issues + # where nimsuggest can crash due as a macro with pos will be loaded + # but it doesn't have offsets for register allocations see: + # https://github.com/nim-lang/Nim/issues/18385 + # Improvements and further use of IC should remove the need for this. #if s.name.s == "outterMacro" or s.name.s == "innerProc": # echo "GENERATING CODE FOR ", s.name.s let last = c.code.len-1 From e08ec0c6745e54de4e174970e513acef3b0d8f5e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 25 Jul 2021 13:07:43 -0300 Subject: [PATCH 2869/4254] Documentation only, Sugar arrow and semicolons (#18574) * Document that sugar arrow do not support semicolon as argument separator --- lib/pure/sugar.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 7cfa932e6..f82e1706f 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -54,6 +54,8 @@ proc createProcType(p, b: NimNode): NimNode = macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. It also supports pragmas. + ## + ## .. warning:: Semicolons can not be used to separate procedure arguments. runnableExamples: proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) @@ -133,6 +135,8 @@ macro `=>`*(p, b: untyped): untyped = macro `->`*(p, b: untyped): untyped = ## Syntax sugar for procedure types. It also supports pragmas. + ## + ## .. warning:: Semicolons can not be used to separate procedure arguments. runnableExamples: proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) # is the same as: From 5f7db652577523bdbb4e9b9157b4fb3bed25e01c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 25 Jul 2021 12:55:33 -0700 Subject: [PATCH 2870/4254] followup #18453 (#18582) --- tests/stdlib/tos.nim | 4 ++-- tests/vm/tvmmisc.nim | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 8a12b9b90..d598a05b2 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -558,9 +558,9 @@ block ospaths: doAssert joinPath("foo","abc") == unixToNativePath"foo/abc" doAssert joinPath("","abc") == unixToNativePath"abc" - doAssert joinPath("gook/.","abc") == unixToNativePath"gook/abc" + doAssert joinPath("zook/.","abc") == unixToNativePath"zook/abc" - # controversial: inconsistent with `joinPath("gook/.","abc")` + # controversial: inconsistent with `joinPath("zook/.","abc")` # on linux, `./foo` and `foo` are treated a bit differently for executables # but not `./foo/bar` and `foo/bar` doAssert joinPath(".", "/lib") == unixToNativePath"./lib" diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index a4f6391cc..f6fbde0f9 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -376,7 +376,7 @@ block: # VM wrong register free causes errors in unrelated code in let prc = if not isClosure: bb.sym else: bb[0].sym ]# proc bar2(head: string): string = "asdf" - proc gook(u1: int) = discard + proc zook(u1: int) = discard type PathEntry = object kind: int @@ -385,20 +385,20 @@ block: # VM wrong register free causes errors in unrelated code iterator globOpt(): int = var u1: int - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) - gook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) var entry = PathEntry() entry.path = bar2("") From 10da888c075acb901b57ba51e4400df6cdf3efd6 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 26 Jul 2021 00:01:19 +0300 Subject: [PATCH 2871/4254] docgen: sort symbols (fix #17910) (#18560) * docgen: sort symbols (fix #17910) * add workaround + change naming * switch to a dedicated sort comparator * fix numbers with unequal string lengths * dedicated `sortName` instead of `plainNameEsc`: * more compact names for non-overloaded symbols * more predictable Ascii sort (e.g. `<` instead of `<`) --- compiler/docgen.nim | 98 ++- .../expected/subdir/subdir_b/utils.html | 10 +- nimdoc/testproject/expected/testproject.html | 686 +++++++++--------- 3 files changed, 432 insertions(+), 362 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f9e72850a..492668543 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -11,7 +11,7 @@ # by knowing how the anchors are going to be named. import - ast, strutils, strtabs, options, msgs, os, idents, + ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents, wordrecg, syntaxes, renderer, lexer, packages/docutils/rst, packages/docutils/rstgen, json, xmltree, trees, types, @@ -43,11 +43,15 @@ type descRst: ItemPre ## Description of the item (may contain ## runnableExamples). substitutions: seq[string] ## Variable names in `doc.item`... + sortName: string ## The string used for sorting in output ModSection = object ## Section like Procs, Types, etc. secItems: seq[Item] ## Pre-processed items. finalMarkup: string ## The items, after RST pass 2 and rendering. ModSections = array[TSymKind, ModSection] - TSections = array[TSymKind, string] + TocItem = object ## HTML TOC item + content: string + sortName: string + TocSectionsFinal = array[TSymKind, string] ExampleGroup = ref object ## a group of runnableExamples with same rdoccmd rdoccmd: string ## from 1st arg in `runnableExamples(rdoccmd): body` @@ -64,8 +68,13 @@ type module: PSym modDeprecationMsg: string section: ModSections # entries of ``.nim`` file (for `proc`s, etc) - toc, toc2: TSections # toc2 - grouped TOC - tocTable: array[TSymKind, Table[string, string]] + tocSimple: array[TSymKind, seq[TocItem]] + # TOC entries for non-overloadable symbols (e.g. types, constants)... + tocTable: array[TSymKind, Table[string, seq[TocItem]]] + # ...otherwise (e.g. procs) + toc2: TocSectionsFinal # TOC `content`, which is probably wrapped + # in `doc.section.toc2` + toc: TocSectionsFinal # final TOC (wrapped in `doc.section.toc`) indexValFilename: string analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. @@ -88,6 +97,51 @@ type proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst) proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str) +proc cmpDecimalsIgnoreCase(a, b: string): int = + ## For sorting with correct handling of cases like 'uint8' and 'uint16'. + ## Also handles leading zeros well (however note that leading zeros are + ## significant when lengths of numbers mismatch, e.g. 'bar08' > 'bar8' !). + runnableExamples: + doAssert cmpDecimalsIgnoreCase("uint8", "uint16") < 0 + doAssert cmpDecimalsIgnoreCase("val00032", "val16suffix") > 0 + doAssert cmpDecimalsIgnoreCase("val16suffix", "val16") > 0 + doAssert cmpDecimalsIgnoreCase("val_08_32", "val_08_8") > 0 + doAssert cmpDecimalsIgnoreCase("val_07_32", "val_08_8") < 0 + doAssert cmpDecimalsIgnoreCase("ab8", "ab08") < 0 + doAssert cmpDecimalsIgnoreCase("ab8de", "ab08c") < 0 # sanity check + let aLen = a.len + let bLen = b.len + var + iA = 0 + iB = 0 + while iA < aLen and iB < bLen: + if isDigit(a[iA]) and isDigit(b[iB]): + var + limitA = iA # index after the last (least significant) digit + limitB = iB + while limitA < aLen and isDigit(a[limitA]): inc limitA + while limitB < bLen and isDigit(b[limitB]): inc limitB + var pos = max(limitA-iA, limitB-iA) + while pos > 0: + if limitA-pos < iA: # digit in `a` is 0 effectively + result = ord('0') - ord(b[limitB-pos]) + elif limitB-pos < iB: # digit in `b` is 0 effectively + result = ord(a[limitA-pos]) - ord('0') + else: + result = ord(a[limitA-pos]) - ord(b[limitB-pos]) + if result != 0: return + dec pos + result = (limitA - iA) - (limitB - iB) # consider 'bar08' > 'bar8' + if result != 0: return + iA = limitA + iB = limitB + else: + result = ord(toLowerAscii(a[iA])) - ord(toLowerAscii(b[iB])) + if result != 0: return + inc iA + inc iB + result = (aLen - iA) - (bLen - iB) + proc prettyString(a: object): string = # xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906 for k, v in fieldPairs(a): @@ -862,6 +916,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = let plainNameEsc = esc(d.target, plainName.strip) uniqueName = if k in routineKinds: plainNameEsc else: name + sortName = if k in routineKinds: plainName.strip else: name cleanPlainSymbol = renderPlainSymbolName(nameNode) complexSymbol = complexName(k, n, cleanPlainSymbol) plainSymbolEnc = encodeUrl(cleanPlainSymbol) @@ -874,7 +929,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int) - d.section[k].secItems.add Item(descRst: comm, substitutions: @[ + d.section[k].secItems.add Item( + descRst: comm, + sortName: sortName, + substitutions: @[ "name", name, "uniqueName", uniqueName, "header", result, "itemID", $d.id, "header_plain", plainNameEsc, "itemSym", cleanPlainSymbol, @@ -898,12 +956,15 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = setIndexTerm(d[], external, symbolOrId, plain, nameNode.sym.name.s & '.' & plain, xmltree.escape(getPlainDocstring(e).docstringSummary)) - d.toc[k].add(getConfigVar(d.conf, "doc.item.toc") % [ + d.tocSimple[k].add TocItem( + sortName: sortName, + content: getConfigVar(d.conf, "doc.item.toc") % [ "name", name, "header_plain", plainNameEsc, "itemSymOrIDEnc", symbolOrIdEnc]) - d.tocTable[k].mgetOrPut(cleanPlainSymbol, "").add( - getConfigVar(d.conf, "doc.item.tocTable") % [ + d.tocTable[k].mgetOrPut(cleanPlainSymbol, newSeq[TocItem]()).add TocItem( + sortName: sortName, + content: getConfigVar(d.conf, "doc.item.tocTable") % [ "name", name, "header_plain", plainNameEsc, "itemSymOrID", symbolOrId.replace(",", ","), "itemSymOrIDEnc", symbolOrIdEnc]) @@ -1143,8 +1204,9 @@ proc finishGenerateDoc*(d: var PDoc) = var resolved = resolveSubs(d.sharedState, f.rst) renderRstToOut(d[], resolved, result) of false: result &= f.str + proc cmp(x, y: Item): int = cmpDecimalsIgnoreCase(x.sortName, y.sortName) for k in TSymKind: - for item in d.section[k].secItems: + for item in d.section[k].secItems.sorted(cmp): var itemDesc: string renderItemPre(d, item.descRst, itemDesc) d.section[k].finalMarkup.add( @@ -1262,18 +1324,26 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = "sectionid", $ord(kind), "sectionTitle", title, "sectionTitleID", $(ord(kind) + 50), "content", d.section[kind].finalMarkup] - var tocSource = d.toc + proc cmp(x, y: TocItem): int = cmpDecimalsIgnoreCase(x.sortName, y.sortName) if groupedToc: - for p in d.tocTable[kind].keys: + let overloadableNames = toSeq(keys(d.tocTable[kind])) + for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase): + var overloadChoices = d.tocTable[kind][plainName] + overloadChoices.sort(cmp) + var content: string + for item in overloadChoices: + content.add item.content d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [ "sectionid", $ord(kind), "sectionTitle", title, "sectionTitleID", $(ord(kind) + 50), - "content", d.tocTable[kind][p], "plainName", p] - tocSource = d.toc2 + "content", content, "plainName", plainName] + else: + for item in d.tocSimple[kind].sorted(cmp): + d.toc2[kind].add item.content d.toc[kind] = getConfigVar(d.conf, "doc.section.toc") % [ "sectionid", $ord(kind), "sectionTitle", title, - "sectionTitleID", $(ord(kind) + 50), "content", tocSource[kind]] + "sectionTitleID", $(ord(kind) + 50), "content", d.toc2[kind]] proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): string = $relativeTo(outDir / linkto, destFile.splitFile().dir, '/') diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 6aa71e8c2..939495ad1 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -130,16 +130,16 @@ window.addEventListener('DOMContentLoaded', main);
  • aEnum(): untyped
  • - - + diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 7e5a685d2..0f6289bbc 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -107,9 +107,7 @@ window.addEventListener('DOMContentLoaded', main);
  • Types
      -
    • FooBuzz
    • -
    • A
    • Foo
    • +
    • FooBuzz
    • Vars
    • @@ -153,35 +153,57 @@ window.addEventListener('DOMContentLoaded', main);
    • Procs
        -
          z10 -
        • z10()
        • + -
            tripleStrLitTest -
          • tripleStrLitTest()
          • + -
              z17 -
            • z17()
            • + + - + + + + - - - - - - - - - - - - - - -
                z4 -
              • z4()
              • +
                  someFunc @@ -285,29 +235,79 @@ window.addEventListener('DOMContentLoaded', main); title="someFunc()">someFunc()
                -
                  z8 -
                • z8(): int
                • + + + + -
                    asyncFun2 -
                  • asyncFun2(): owned(Future[void])
                  • + -
                      asyncFun1 -
                    • asyncFun1(): Future[int]
                    • + + + + + + + + @@ -316,7 +316,12 @@ window.addEventListener('DOMContentLoaded', main);
                    • Methods @@ -379,10 +379,25 @@ window.addEventListener('DOMContentLoaded', main);
                    • Templates
                        - @@ -447,16 +447,6 @@ window.addEventListener('DOMContentLoaded', main);

                        Types

                        - -
                        FooBuzz {....deprecated: "FooBuzz msg".} = int
                        -
                        -
                        - Deprecated: FooBuzz msg -
                        - - - -
                        A {.inject.} = enum
                           aA
                        @@ -480,6 +470,16 @@ The enum B. + + +
                        FooBuzz {....deprecated: "FooBuzz msg".} = int
                        +
                        +
                        + Deprecated: FooBuzz msg +
                        + + +
                        Shapes = enum
                        @@ -496,19 +496,19 @@ Some shapes.
                         

                        Vars

                        - -
                        someVariable: bool
                        -
                        - -This should be visible. - -
                        aVariable: array[1, int]
                        +
                        + +
                        someVariable: bool
                        +
                        + +This should be visible. +
                        @@ -548,12 +548,69 @@ This should be visible.

                        Procs

                        + +
                        proc addfBug14485() {....raises: [], tags: [].}
                        +
                        + +Some proc +

                        Example:

                        +
                        discard "foo() = " & $[1]
                        +#[
                        +0: let's also add some broken html to make sure this won't break in future
                        +1: </span>
                        +2: </span>
                        +3: </span
                        +4: </script>
                        +5: </script
                        +6: </script
                        +7: end of broken html
                        +]#
                        + +
                        + +
                        proc anything() {....raises: [], tags: [].}
                        +
                        + +There is no block quote after blank lines at the beginning. + +
                        + +
                        proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
                        +                                tags: [RootEffect].}
                        +
                        + +ok1 + +
                        + +
                        proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
                        +
                        + + + +
                        + +
                        proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
                        +
                        + + +

                        Example:

                        +
                        discard
                        ok1 + +
                        proc bar[T](a, b: T): T
                        +
                        + +
                        proc baz() {....raises: [], tags: [].}
                        +
                        + + +
                        proc baz[T](a, b: T): T {....deprecated.}
                        @@ -575,11 +632,20 @@ This is deprecated without message. This is deprecated with a message. - -
                        func someFunc() {....raises: [], tags: [].}
                        + +
                        proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
                        +    header: "<stdio.h>", varargs, discardable.}
                        -My someFunc. Stuff in quotes here. Some link + + +
                        + +
                        proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
                        +                                     varargs, discardable.}
                        +
                        + +the c printf. etc.
                        @@ -598,6 +664,103 @@ came form utils but should be shown where + +
                        proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
                        +
                        + +

                        Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                        +

                        See also:

                        + +
                        low2(2) # => -9223372036854775808
                        +

                        Example:

                        +
                        discard "in low2"
                        + +
                        + +
                        proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
                        +
                        + +

                        Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                        +

                        See also:

                        + +
                        low(2) # => -9223372036854775808
                        + +
                        + +
                        proc p1() {....raises: [], tags: [].}
                        +
                        + +cp1 +

                        Example:

                        +
                        doAssert 1 == 1 # regular comments work here
                        c4 +

                        Example:

                        +
                        # c5 regular comments before 1st token work
                        +# regular comment
                        +#[
                        +nested regular comment
                        +]#
                        +doAssert 2 == 2 # c8
                        +## this is a non-nested doc comment
                        +
                        +##[
                        +this is a nested doc comment
                        +]##
                        +discard "c9"
                        +# also work after
                        + +
                        + +
                        func someFunc() {....raises: [], tags: [].}
                        +
                        + +My someFunc. Stuff in quotes here. Some link + +
                        + +
                        proc tripleStrLitTest() {....raises: [], tags: [].}
                        +
                        + + +

                        Example: cmd: --hint:XDeclaredButNotUsed:off

                        +
                        ## mullitline string litterals are tricky as their indentation can span
                        +## below that of the runnableExamples
                        +let s1a = """
                        +should appear at indent 0
                        +  at indent 2
                        +at indent 0
                        +"""
                        +# make sure this works too
                        +let s1b = """start at same line
                        +  at indent 2
                        +at indent 0
                        +""" # comment after
                        +let s2 = """sandwich """
                        +let s3 = """"""
                        +when false:
                        +  let s5 = """
                        +        in s5 """
                        +
                        +let s3b = ["""
                        +%!? #[...] # inside a multiline ...
                        +""", "foo"]
                        +
                        +## make sure handles trailing spaces
                        +let s4 = """ 
                        +"""
                        +
                        +let s5 = """ x
                        +"""
                        +let s6 = """ ""
                        +"""
                        +let s7 = """"""""""
                        +let s8 = ["""""""""", """
                        +  """ ]
                        +discard
                        +# should be in
                        +
                        proc z1(): Foo {....raises: [], tags: [].}
                        @@ -701,13 +864,6 @@ cz13

                        Example:

                        discard
                        - - -
                        proc baz() {....raises: [], tags: [].}
                        -
                        - - -
                        proc z17() {....raises: [], tags: [].}
                        @@ -717,162 +873,6 @@ cz17 rest

                        Example:

                        discard 1
                        rest - - -
                        proc p1() {....raises: [], tags: [].}
                        -
                        - -cp1 -

                        Example:

                        -
                        doAssert 1 == 1 # regular comments work here
                        c4 -

                        Example:

                        -
                        # c5 regular comments before 1st token work
                        -# regular comment
                        -#[
                        -nested regular comment
                        -]#
                        -doAssert 2 == 2 # c8
                        -## this is a non-nested doc comment
                        -
                        -##[
                        -this is a nested doc comment
                        -]##
                        -discard "c9"
                        -# also work after
                        - -
                        - -
                        proc addfBug14485() {....raises: [], tags: [].}
                        -
                        - -Some proc -

                        Example:

                        -
                        discard "foo() = " & $[1]
                        -#[
                        -0: let's also add some broken html to make sure this won't break in future
                        -1: </span>
                        -2: </span>
                        -3: </span
                        -4: </script>
                        -5: </script
                        -6: </script
                        -7: end of broken html
                        -]#
                        - -
                        - -
                        proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
                        -                                     varargs, discardable.}
                        -
                        - -the c printf. etc. - -
                        - -
                        proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
                        -    header: "<stdio.h>", varargs, discardable.}
                        -
                        - - - -
                        - -
                        proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
                        -
                        - -

                        Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                        -

                        See also:

                        - -
                        low(2) # => -9223372036854775808
                        - -
                        - -
                        proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
                        -
                        - -

                        Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

                        -

                        See also:

                        - -
                        low2(2) # => -9223372036854775808
                        -

                        Example:

                        -
                        discard "in low2"
                        - -
                        - -
                        proc tripleStrLitTest() {....raises: [], tags: [].}
                        -
                        - - -

                        Example: cmd: --hint:XDeclaredButNotUsed:off

                        -
                        ## mullitline string litterals are tricky as their indentation can span
                        -## below that of the runnableExamples
                        -let s1a = """
                        -should appear at indent 0
                        -  at indent 2
                        -at indent 0
                        -"""
                        -# make sure this works too
                        -let s1b = """start at same line
                        -  at indent 2
                        -at indent 0
                        -""" # comment after
                        -let s2 = """sandwich """
                        -let s3 = """"""
                        -when false:
                        -  let s5 = """
                        -        in s5 """
                        -
                        -let s3b = ["""
                        -%!? #[...] # inside a multiline ...
                        -""", "foo"]
                        -
                        -## make sure handles trailing spaces
                        -let s4 = """ 
                        -"""
                        -
                        -let s5 = """ x
                        -"""
                        -let s6 = """ ""
                        -"""
                        -let s7 = """"""""""
                        -let s8 = ["""""""""", """
                        -  """ ]
                        -discard
                        -# should be in
                        - -
                        - -
                        proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
                        -                                tags: [RootEffect].}
                        -
                        - -ok1 - -
                        - -
                        proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
                        -
                        - - - -
                        - -
                        proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
                        -
                        - - -

                        Example:

                        -
                        discard
                        ok1 - -
                        - -
                        proc anything() {....raises: [], tags: [].}
                        -
                        - -There is no block quote after blank lines at the beginning. -
                        @@ -967,6 +967,13 @@ cz18

                        Templates

                        + +
                        template foo(a, b: SomeType)
                        +
                        + +This does nothing + +
                        template fromUtils2()
                        @@ -976,20 +983,6 @@ ok3
                        discard """should be shown as examples for fromUtils2
                                in module calling fromUtilsGen"""
                        -
                        - -
                        template z6t(): int
                        -
                        - -cz6t - -
                        - -
                        template foo(a, b: SomeType)
                        -
                        - -This does nothing -
                        template myfn()
                        @@ -1012,6 +1005,22 @@ bar discard 0xff # elu par cette crapule # should be in
                        should be still in + + +
                        template testNimDocTrailingExample()
                        +
                        + + +

                        Example:

                        +
                        discard 2
                        + +
                        + +
                        template z6t(): int
                        +
                        + +cz6t +
                        template z14()
                        @@ -1038,15 +1047,6 @@ cz15

                        Example:

                        discard 1
                        in or out? - - -
                        template testNimDocTrailingExample()
                        -
                        - - -

                        Example:

                        -
                        discard 2
                        -
                        From ff280c012731b1978005a743eec96cd885331475 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 26 Jul 2021 09:57:19 +0200 Subject: [PATCH 2872/4254] added missing .inline for toCChar --- compiler/msgs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 242b06587..20a55daee 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -27,7 +27,7 @@ proc flushDot*(conf: ConfigRef) = conf.lastMsgWasDot.excl stdOrrKind write(stdOrr, "\n") -proc toCChar*(c: char; result: var string) = +proc toCChar*(c: char; result: var string) {.inline.} = case c of '\0'..'\x1F', '\x7F'..'\xFF': result.add '\\' From 158d7c7a7a8977f5937311b98bc381399f31db8d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 26 Jul 2021 14:15:55 +0200 Subject: [PATCH 2873/4254] fixes #18558 again (#18586) --- compiler/ccgcalls.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 510b8d9ec..749a7a3b6 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -333,6 +333,8 @@ proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) = getPotentialWrites(n[1], mutate, result) of nkAddr, nkHiddenAddr: getPotentialWrites(n[0], true, result) + of nkBracketExpr, nkDotExpr, nkCheckedFieldExpr: + getPotentialWrites(n[0], mutate, result) of nkCallKinds: case n.getMagic: of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem, From d4c3a09286d1cbb534ed5dbd21d99a18670b3427 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Mon, 26 Jul 2021 16:22:42 +0300 Subject: [PATCH 2874/4254] optimize for the non-throwing case (#18587) --- lib/pure/collections/tables.nim | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index b845f57cc..403345755 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -227,6 +227,12 @@ template dataLen(t): untyped = len(t.data) include tableimpl +proc raiseKeyError[T](key: T) {.noinline, noreturn.} = + when compiles($key): + raise newException(KeyError, "key not found: " & $key) + else: + raise newException(KeyError, "key not found") + template get(t, key): untyped = ## retrieves the value at `t[key]`. The value can be modified. ## If `key` is not in `t`, the `KeyError` exception is raised. @@ -235,10 +241,7 @@ template get(t, key): untyped = var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val else: - when compiles($key): - raise newException(KeyError, "key not found: " & $key) - else: - raise newException(KeyError, "key not found") + raiseKeyError(key) proc enlarge[A, B](t: var Table[A, B]) = var n: KeyValuePairSeq[A, B] From 664dbb6bfbe06ff0ddc4339c0fe80c49d0838ca4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 26 Jul 2021 18:00:03 +0200 Subject: [PATCH 2875/4254] atlas tool: testing via mocking (#18588) * atlas: refactoring * Atlas: do some basic testing via mocking --- koch.nim | 2 + tools/atlas/atlas.nim | 187 +++++++++++++++++------ tools/atlas/osutils.nim | 8 - tools/atlas/testdata.nim | 63 ++++++++ tools/atlas/tests/balls.nimble | 32 ++++ tools/atlas/tests/grok.nimble | 5 + tools/atlas/tests/nim-bytes2human.nimble | 7 + tools/atlas/tests/nim.cfg | 11 ++ tools/atlas/tests/npeg.nimble | 48 ++++++ tools/atlas/tests/packages/packages.json | 36 +++++ tools/atlas/tests/sync.nimble | 10 ++ tools/atlas/tests/testes.nimble | 23 +++ tools/atlas/tests/ups.nimble | 13 ++ 13 files changed, 387 insertions(+), 58 deletions(-) create mode 100644 tools/atlas/testdata.nim create mode 100644 tools/atlas/tests/balls.nimble create mode 100644 tools/atlas/tests/grok.nimble create mode 100644 tools/atlas/tests/nim-bytes2human.nimble create mode 100644 tools/atlas/tests/nim.cfg create mode 100644 tools/atlas/tests/npeg.nimble create mode 100644 tools/atlas/tests/packages/packages.json create mode 100644 tools/atlas/tests/sync.nimble create mode 100644 tools/atlas/tests/testes.nimble create mode 100644 tools/atlas/tests/ups.nimble diff --git a/koch.nim b/koch.nim index da7576e65..4296e4529 100644 --- a/koch.nim +++ b/koch.nim @@ -594,6 +594,8 @@ proc runCI(cmd: string) = when defined(posix): execFold("Run nimsuggest tests", "nim r nimsuggest/tester") + execFold("Run atlas tests", "nim c -r -d:atlasTests tools/atlas/atlas.nim clone https://github.com/disruptek/balls") + when not defined(bsd): if not doUseCpp: # the BSDs are overwhelmed already, so only run this test on the other machines: diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index b10ec0358..d0990c1f7 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -39,6 +39,10 @@ proc writeVersion() = stdout.flushFile() quit(0) +const + MockupRun = defined(atlasTests) + TestsDir = "tools/atlas/tests" + type PackageName = distinct string DepRelation = enum @@ -55,9 +59,79 @@ type p: Table[string, string] # name -> url mapping processed: HashSet[string] # the key is (url / commit) errors: int + when MockupRun: + currentDir: string + step: int + mockupSuccess: bool const InvalidCommit = "" + ProduceTest = false + +type + Command = enum + GitDiff = "git diff", + GitTags = "git show-ref --tags", + GitRevParse = "git rev-parse", + GitCheckout = "git checkout", + GitPull = "git pull", + GitCurrentCommit = "git log -n 1 --format=%H" + GitMergeBase = "git merge-base" + +include testdata + +proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, int) = + when MockupRun: + assert TestLog[c.step].cmd == cmd + case cmd + of GitDiff, GitTags, GitRevParse, GitPull, GitCurrentCommit: + result = (TestLog[c.step].output, TestLog[c.step].exitCode) + of GitCheckout: + assert args[0] == TestLog[c.step].output + of GitMergeBase: + let tmp = TestLog[c.step].output.splitLines() + assert tmp.len == 4, $tmp.len + assert tmp[0] == args[0] + assert tmp[1] == args[1] + assert tmp[3] == "" + result[0] = tmp[2] + result[1] = TestLog[c.step].exitCode + inc c.step + else: + var cmdLine = $cmd + for i in 0.. ", result + +proc cloneUrl(c: var AtlasContext; url, dest: string; cloneUsingHttps: bool): string = + when MockupRun: + result = "" + else: + result = osutils.cloneUrl(url, dest, cloneUsingHttps) + when ProduceTest: + echo "cloned ", url, " into ", dest + +template withDir*(c: var AtlasContext; dir: string; body: untyped) = + when MockupRun: + c.currentDir = dir + body + else: + let oldDir = getCurrentDir() + try: + when ProduceTest: + echo "Current directory is now ", dir + setCurrentDir(dir) + body + finally: + setCurrentDir(oldDir) + +proc extractRequiresInfo(c: var AtlasContext; nimbleFile: string): NimbleFileInfo = + result = extractRequiresInfo(nimbleFile) + when ProduceTest: + echo "nimble ", nimbleFile, " info ", result proc toDepRelation(s: string): DepRelation = case s @@ -65,9 +139,9 @@ proc toDepRelation(s: string): DepRelation = of ">": strictlyGreater else: normal -proc isCleanGit(dir: string): string = +proc isCleanGit(c: var AtlasContext; dir: string): string = result = "" - let (outp, status) = osproc.execCmdEx("git diff") + let (outp, status) = exec(c, GitDiff, []) if outp.len != 0: result = "'git diff' not empty" elif status != 0: @@ -101,8 +175,8 @@ proc sameVersionAs(tag, ver: string): bool = result = safeCharAt(tag, idx-1) notin VersionChars and safeCharAt(tag, idx+ver.len) notin VersionChars -proc versionToCommit(d: Dependency): string = - let (outp, status) = osproc.execCmdEx("git show-ref --tags") +proc versionToCommit(c: var AtlasContext; d: Dependency): string = + let (outp, status) = exec(c, GitTags, []) if status == 0: var useNextOne = false for line in splitLines(outp): @@ -123,35 +197,36 @@ proc versionToCommit(d: Dependency): string = return "" -proc shortToCommit(short: string): string = - let (cc, status) = osproc.execCmdEx("git rev-parse " & quoteShell(short)) +proc shortToCommit(c: var AtlasContext; short: string): string = + let (cc, status) = exec(c, GitRevParse, [short]) result = if status == 0: strutils.strip(cc) else: "" proc checkoutGitCommit(c: var AtlasContext; p: PackageName; commit: string) = - let (_, status) = osproc.execCmdEx("git checkout " & quoteShell(commit)) + let (_, status) = exec(c, GitCheckout, [commit]) if status != 0: error(c, p, "could not checkout commit", commit) proc gitPull(c: var AtlasContext; p: PackageName) = - let (_, status) = osproc.execCmdEx("git pull") + let (_, status) = exec(c, GitPull, []) if status != 0: error(c, p, "could not 'git pull'") proc updatePackages(c: var AtlasContext) = if dirExists(c.workspace / PackagesDir): - withDir(c.workspace / PackagesDir): + withDir(c, c.workspace / PackagesDir): gitPull(c, PackageName PackagesDir) else: - withDir c.workspace: - let err = cloneUrl("https://github.com/nim-lang/packages", PackagesDir, false) + withDir c, c.workspace: + let err = cloneUrl(c, "https://github.com/nim-lang/packages", PackagesDir, false) if err != "": error c, PackageName(PackagesDir), err proc fillPackageLookupTable(c: var AtlasContext) = if not c.hasPackageList: c.hasPackageList = true - updatePackages(c) - let plist = getPackages(c.workspace) + when not MockupRun: + updatePackages(c) + let plist = getPackages(when MockupRun: TestsDir else: c.workspace) for entry in plist: c.p[unicode.toLower entry.name] = entry.url @@ -178,19 +253,19 @@ proc isShortCommitHash(commit: string): bool {.inline.} = proc checkoutCommit(c: var AtlasContext; w: Dependency) = let dir = c.workspace / w.name.string - withDir dir: + withDir c, dir: if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: gitPull(c, w.name) else: - let err = isCleanGit(dir) + let err = isCleanGit(c, dir) if err != "": warn c, w.name, err else: let requiredCommit = - if needsCommitLookup(w.commit): versionToCommit(w) - elif isShortCommitHash(w.commit): shortToCommit(w.commit) + if needsCommitLookup(w.commit): versionToCommit(c, w) + elif isShortCommitHash(w.commit): shortToCommit(c, w.commit) else: w.commit - let (cc, status) = osproc.execCmdEx("git log -n 1 --format=%H") + let (cc, status) = exec(c, GitCurrentCommit, []) let currentCommit = strutils.strip(cc) if requiredCommit == "" or status != 0: if requiredCommit == "" and w.commit == InvalidCommit: @@ -201,8 +276,7 @@ proc checkoutCommit(c: var AtlasContext; w: Dependency) = if currentCommit != requiredCommit: # checkout the later commit: # git merge-base --is-ancestor - let (cc, status) = osproc.execCmdEx("git merge-base " & - currentCommit.quoteShell & " " & requiredCommit.quoteShell) + let (cc, status) = exec(c, GitMergeBase, [currentCommit, requiredCommit]) let mergeBase = strutils.strip(cc) if status == 0 and (mergeBase == currentCommit or mergeBase == requiredCommit): # conflict resolution: pick the later commit: @@ -215,15 +289,19 @@ proc checkoutCommit(c: var AtlasContext; w: Dependency) = currentCommit, "(current) or", w.commit, " =", requiredCommit, "(required)" proc findNimbleFile(c: AtlasContext; dep: Dependency): string = - result = c.workspace / dep.name.string / (dep.name.string & ".nimble") - if not fileExists(result): - result = "" - for x in walkFiles(c.workspace / dep.name.string / "*.nimble"): - if result.len == 0: - result = x - else: - # ambiguous .nimble file - return "" + when MockupRun: + result = TestsDir / dep.name.string & ".nimble" + doAssert fileExists(result), "file does not exist " & result + else: + result = c.workspace / dep.name.string / (dep.name.string & ".nimble") + if not fileExists(result): + result = "" + for x in walkFiles(c.workspace / dep.name.string / "*.nimble"): + if result.len == 0: + result = x + else: + # ambiguous .nimble file + return "" proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency]; tokens: seq[string]) = @@ -240,7 +318,7 @@ proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; isMainProject: bool) = let nimbleFile = findNimbleFile(c, dep) if nimbleFile != "": - let nimbleInfo = extractRequiresInfo(nimbleFile) + let nimbleInfo = extractRequiresInfo(c, nimbleFile) for r in nimbleInfo.requires: var tokens: seq[string] = @[] for token in tokenizeRequires(r): @@ -280,8 +358,8 @@ proc clone(c: var AtlasContext; start: string): seq[string] = let w = work[i] let oldErrors = c.errors if not dirExists(c.workspace / w.name.string): - withDir c.workspace: - let err = cloneUrl(w.url, w.name.string, false) + withDir c, c.workspace: + let err = cloneUrl(c, w.url, w.name.string, false) if err != "": error c, w.name, err if oldErrors == c.errors: @@ -296,29 +374,34 @@ const configPatternBegin = "############# begin Atlas config section ##########\n" configPatternEnd = "############# end Atlas config section ##########\n" -proc patchNimCfg(c: AtlasContext; deps: seq[string]) = +proc patchNimCfg(c: var AtlasContext; deps: seq[string]) = var paths = "--noNimblePath\n" for d in deps: paths.add "--path:\"../" & d.replace("\\", "/") & "\"\n" - let cfg = c.projectDir / "nim.cfg" var cfgContent = configPatternBegin & paths & configPatternEnd - if not fileExists(cfg): - writeFile(cfg, cfgContent) + + when MockupRun: + assert readFile(TestsDir / "nim.cfg") == cfgContent + c.mockupSuccess = true else: - let content = readFile(cfg) - let start = content.find(configPatternBegin) - if start >= 0: - cfgContent = content.substr(0, start-1) & cfgContent - let theEnd = content.find(configPatternEnd, start) - if theEnd >= 0: - cfgContent.add content.substr(theEnd+len(configPatternEnd)) - else: - cfgContent = content & "\n" & cfgContent - if cfgContent != content: - # do not touch the file if nothing changed - # (preserves the file date information): + let cfg = c.projectDir / "nim.cfg" + if not fileExists(cfg): writeFile(cfg, cfgContent) + else: + let content = readFile(cfg) + let start = content.find(configPatternBegin) + if start >= 0: + cfgContent = content.substr(0, start-1) & cfgContent + let theEnd = content.find(configPatternEnd, start) + if theEnd >= 0: + cfgContent.add content.substr(theEnd+len(configPatternEnd)) + else: + cfgContent = content & "\n" & cfgContent + if cfgContent != content: + # do not touch the file if nothing changed + # (preserves the file date information): + writeFile(cfg, cfgContent) proc error*(msg: string) = when defined(debug): @@ -365,8 +448,12 @@ proc main = singleArg() let deps = clone(c, args[0]) patchNimCfg c, deps - if c.errors > 0: - error "There were problems." + when MockupRun: + if not c.mockupSuccess: + error "There were problems." + else: + if c.errors > 0: + error "There were problems." of "refresh": noArgs() updatePackages(c) diff --git a/tools/atlas/osutils.nim b/tools/atlas/osutils.nim index 31392b113..1bb414c03 100644 --- a/tools/atlas/osutils.nim +++ b/tools/atlas/osutils.nim @@ -3,14 +3,6 @@ import os, strutils, osproc -template withDir*(dir, body) = - let oldDir = getCurrentDir() - try: - setCurrentDir(dir) - body - finally: - setCurrentDir(oldDir) - proc isUrl*(x: string): bool = x.startsWith("git://") or x.startsWith("https://") or x.startsWith("http://") diff --git a/tools/atlas/testdata.nim b/tools/atlas/testdata.nim new file mode 100644 index 000000000..f960e3d08 --- /dev/null +++ b/tools/atlas/testdata.nim @@ -0,0 +1,63 @@ + +type + PerDirData = object + dirname: string + cmd: Command + exitCode: int + output: string + +template toData(a, b, c, d): untyped = + PerDirData(dirname: a, cmd: b, exitCode: c, output: d) + +const + TestLog = [ + toData("balls", GitPull, 0, "Already up to date.\n"), + toData("grok", GitDiff, 0, ""), + toData("grok", GitTags, 0, "2ca193c31fa2377c1e991a080d60ca3215ff6cf0 refs/tags/0.0.1\n48007554b21ba2f65c726ae2fdda88d621865b4a refs/tags/0.0.2\n7092a0286421c7818cd335cca9ebc72d03d866c2 refs/tags/0.0.3\n62707b8ac684efac35d301dbde57dc750880268e refs/tags/0.0.4\n876f2504e0c2f785ffd2cf65a78e2aea474fa8aa refs/tags/0.0.5\nb7eb1f2501aa2382cb3a38353664a13af62a9888 refs/tags/0.0.6\nf5d818bfd6038884b3d8b531c58484ded20a58a4 refs/tags/0.1.0\n961eaddea49c3144d130d105195583d3f11fb6c6 refs/tags/0.2.0\n15ab8ed8d4f896232a976a9008548bd53af72a66 refs/tags/0.2.1\n426a7d7d4603f77ced658e73ad7f3f582413f6cd refs/tags/0.3.0\n83cf7a39b2fe897786fb0fe01a7a5933c3add286 refs/tags/0.3.1\n8d2e3c900edbc95fa0c036fd76f8e4f814aef2c1 refs/tags/0.3.2\n48b43372f49a3bb4dc0969d82a0fca183fb94662 refs/tags/0.3.3\n9ca947a3009ea6ba17814b20eb953272064eb2e6 refs/tags/0.4.0\n1b5643d04fba6d996a16d1ffc13d034a40003f8f refs/tags/0.5.0\n486b0eb580b1c465453d264ac758cc490c19c33e refs/tags/0.5.1\naedb0d9497390e20b9d2541cef2bb05a5cda7a71 refs/tags/0.5.2\n"), + toData("grok", GitCurrentCommit, 0, "349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n"), + toData("grok", GitMergeBase, 0, "349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n1b5643d04fba6d996a16d1ffc13d034a40003f8f\n349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n"), + toData("grok", GitCheckout, 0, "1b5643d04fba6d996a16d1ffc13d034a40003f8f"), # watch out! + + toData("ups", GitDiff, 0, ""), + toData("ups", GitTags, 0, "4008f9339cd22b30e180bc87a6cca7270fd28ac1 refs/tags/0.0.2\n19bc490c22b4f5b0628c31cdedead1375b279356 refs/tags/0.0.3\nff34602aaea824cb46d6588cd5fe1178132e9702 refs/tags/0.0.4\n09de599138f20b745133b6e4fe563e204415a7e8 refs/tags/0.0.5\n85fee3b74798311108a105635df31f892150f5d0 refs/tags/0.0.6\nfd303913b22b121dc42f332109e9c44950b9acd4 refs/tags/0.0.7\n"), + toData("ups", GitCurrentCommit, 0, "74c31af8030112dac758440aa51ef175992f71f3\n"), + toData("ups", GitMergeBase, 0, "74c31af8030112dac758440aa51ef175992f71f3\n4008f9339cd22b30e180bc87a6cca7270fd28ac1\n74c31af8030112dac758440aa51ef175992f71f3\n"), + toData("ups", GitCheckout, 0, "4008f9339cd22b30e180bc87a6cca7270fd28ac1"), + + toData("sync", GitDiff, 0, ""), + toData("sync", GitTags, 0, "c9811af2d03dc78a920d33592d0a3daae3d9e68f refs/tags/v0.1.0\nc99d3a73344c4c02335190b489e7ea8aaa4e9584 refs/tags/v0.2.0\n6186a38c97c0f26e1a0c8016979227d26c41717b refs/tags/v0.3.0\n5506e4e09b849bd59f930fcccee3096abb089b1d refs/tags/v0.4.0\n1e4ef046ed0447aec7ca4ab3b2e2a5347ac41448 refs/tags/v0.5.0\na95f7b0b22c77b98ed63c1c4f435d550de8dbb05 refs/tags/v0.6.0\n214b868ace4ebc9140ee56734147fbd16b238c71 refs/tags/v0.7.0\n786698bf9f597834f36cd530d32faee31545a1d7 refs/tags/v0.9.0\n810bd2d75e9f6e182534ae2488670b51a9f13fc3 refs/tags/v1.0.0\na133d37991e3d4e9553c5261eabcb07d471968f7 refs/tags/v1.1.0\n0872a7cd70ea43a26deb94b8ab12cc5b89a1c212 refs/tags/v1.2.0\n19ac734438b6c04fe89711728a97fcde591324eb refs/tags/v1.3.0\nde5c7337ebc22422190e8aeca37d05651735f440 refs/tags/v1.4.0\n"), + toData("sync", GitCurrentCommit, 0, "de5c7337ebc22422190e8aeca37d05651735f440\n"), + toData("sync", GitMergeBase, 0, "de5c7337ebc22422190e8aeca37d05651735f440\n810bd2d75e9f6e182534ae2488670b51a9f13fc3\n810bd2d75e9f6e182534ae2488670b51a9f13fc3\n"), + + toData("npeg", GitDiff, 0, ""), + toData("npeg", GitTags, 0, "8df2f0c9391995fd086b8aab00e8ab7aded1e8f0 refs/tags/0.1.0\n4c959a72db5283b55eeef491076eefb5e02316f1 refs/tags/0.10.0\n802f47c0f7f4318a4f0858ba5a6a6ed2333bde71 refs/tags/0.11.0\n82c8d92837108dce225358ace2c416bf9a3f30ce refs/tags/0.12.0\n87d2f2c4f6ef7da350d45beb5a336611bde7f518 refs/tags/0.13.0\n39964f0d220bfaade47a568bf03c1cf28aa2bc37 refs/tags/0.14.0\nbe9f03f92304cbeab70572944a8563db9b23b2fb refs/tags/0.14.1\na933fb9832566fc95273e417597bfb4faf564ca6 refs/tags/0.15.0\n6aad2e438c52ff0636c7bfb64338e444ac3e83ba refs/tags/0.16.0\nf4ddffb5848c42c6151743dd9c7eddcaaabc56cc refs/tags/0.17.0\n30b446b39442cdbc53a97018ab8a54149aa7c3b7 refs/tags/0.17.1\n1a9d36aa3b34a6169d4530463f1c17a3fe1e075e refs/tags/0.18.0\ndd34f903a9a63b876cb2db19b7a4ce0bcc252134 refs/tags/0.19.0\nd93d49c81fc8722d7929ac463b435c0f2e10c53b refs/tags/0.2.0\neeae7746c9b1118bcf27744ab2aee26969051256 refs/tags/0.20.0\n8c3471a548129f3bf62df15cd0fd8cca1787d852 refs/tags/0.21.0\nc0e873a17bc713c80e74fec3c30cb62dcd5d194a refs/tags/0.21.1\nbae84c47a1bb259b209b6f6be1582327b784539d refs/tags/0.21.2\nbfcb4bcae76a917c3c88736ca773e4cb67dbb2d8 refs/tags/0.21.3\n0eabb7c462d30932049f0b7e6a030c1562cf9fee refs/tags/0.22.0\n2e75367095f54d4351005078bad98041a55b14c1 refs/tags/0.22.1\n814ea235dd398108d7b18f966694c3d951575701 refs/tags/0.22.2\na812064587d983c129737f8500bf74990e6b8dab refs/tags/0.23.0\nbd969ad3745db0d66022564cac76cf9424651104 refs/tags/0.23.1\na037c646a47623b92718efadc2bb74d03664b360 refs/tags/0.23.2\n078475ccceeaca0fac947492acdd24514da8d863 refs/tags/0.24.0\ne7bd87dc992512fd5825a557a56907647e03c979 refs/tags/0.24.1\n45ea601e1c7f64fb857bc99df984b86673621d2c refs/tags/0.3.0\n1ea9868a3fee3aa487ab7ec9129208a4dd483d0d refs/tags/0.4.0\n39afdb5733d3245386d29d08c5ff61c89268f499 refs/tags/0.5.0\n458c7b5910fcb157af3fc51bc3b3e663fdb3ed4a refs/tags/0.6.0\n06c38bd8563d822455bc237c2a98c153d938ed1b refs/tags/0.7.0\nf446b6056eef6d8dc9d8b47a79aca93d17dc8230 refs/tags/0.8.0\nbb25a195133f9f7af06386d0809793923cc5e8ab refs/tags/0.9.0\n"), + toData("npeg", GitCurrentCommit, 0, "5d80f93aa720898936668b3bc47d0fff101ec414\n"), + toData("npeg", GitMergeBase, 0, "5d80f93aa720898936668b3bc47d0fff101ec414\na037c646a47623b92718efadc2bb74d03664b360\na037c646a47623b92718efadc2bb74d03664b360\n"), + + toData("testes", GitDiff, 0, ""), + toData("testes", GitTags, 0, "3ce9b2968b5f644755a0ced1baa3eece88c2f12e refs/tags/0.1.0\nf73af8318b54737678fab8b54bdcd8a451015e0d refs/tags/0.1.1\nd21d84d37b161a123a43318bae353108755916de refs/tags/0.1.2\n5c36b6095353ed03b08ac939d00aff2d73f79a35 refs/tags/0.1.3\na1220d11237ee8f135f772ff9731c11b2d91ba31 refs/tags/0.1.4\n574f741b90d04a7ce8c9b990e6077708d7ad076e refs/tags/0.1.5\nced0a9e58234b680def6931578e09165a32e6291 refs/tags/0.1.6\nbb248952e8742a6011eb1a45a9d2059aeb0341d7 refs/tags/0.1.7\nabb7d7c552da0a8e0ddc586c15ccf7e74b0d068b refs/tags/0.10.0\n6e42a768a90d6442196b344bcdcb6f834b76e7b7 refs/tags/0.2.0\n9d136c3a0851ca2c021f5fb4f7b63f0a0ef77232 refs/tags/0.2.1\ndcb282b2da863fd2939e1969cec7a99788feb456 refs/tags/0.2.2\nf708a632afaa40a322a1a61c1c13722edac8e8c5 refs/tags/0.3.0\n3213f59e3f9ba052452c59f01d1418360d856af6 refs/tags/0.3.1\nf7bb1743dffd327958dfcebae4cfb6f61cc1cb8c refs/tags/0.3.2\n6b64569ebecad6bc60cc8697713701e7659204f4 refs/tags/0.3.3\nb51c25a4367bd17f419f78cb5a27f319e9d820f5 refs/tags/0.3.4\nb265612710cbd5ddb1b173c94ece8ec5c7ceccac refs/tags/0.3.5\ne404bcfe42e92d7509717a2dfa115cacb4964c5d refs/tags/0.3.6\n5e4d0d5b7e7f314dde701c546c4365c59782d3dc refs/tags/0.3.7\ne13f91c9c913d2b81c59adeaad687efa2b35293a refs/tags/0.3.8\n17599625f09af0ae4b525e63ab726a3002540702 refs/tags/0.3.9\n13e907f70571dd146d8dc29ddec4599b40ba4e85 refs/tags/0.4.0\n155a74cf676495df1e0674dd07b5e4a0291a9a4a refs/tags/0.4.1\nf37abccdc148cb02ca637a6f0bc8821491cce358 refs/tags/0.4.2\n0250d29ebdd02f28f9020445adb5a4e51fd1902c refs/tags/0.5.0\n2fb87db6d9f34109a70205876030c53f815739b7 refs/tags/0.5.1\n629d17ba8d6a1a4eca8145eb089ed5bca4473dfc refs/tags/0.6.0\ne926130f5f1b7903f68be49cc1563225bd9d948d refs/tags/0.7.0\n7365303897e6185796c274425c079916047e3f14 refs/tags/0.7.1\na735c4adabeba637409f41c4325dd8fc5fb91e2d refs/tags/0.7.10\nfe023fd27404889c5122f902456cbba14b767405 refs/tags/0.7.11\n4430e72972c77a5e9c1555d59bba11d840682691 refs/tags/0.7.12\nf0e53eb490a9558c7f594d2e095b70665e36ca88 refs/tags/0.7.13\nf6520e25e7c329c2957cda447f149fc6a930db0d refs/tags/0.7.2\nd509762f7191757c240d3c79c9ecda53f8c0cfe3 refs/tags/0.7.3\nc02e7a783d1c42fd1f91bca7142f7c3733950c05 refs/tags/0.7.4\n8c8a9e496e9b86ba7602709438980ca31e6989d9 refs/tags/0.7.5\n29839c18b4ac83c0111a178322b57ebb8a8d402c refs/tags/0.7.6\n3b62973cf74fafd8ea906644d89ac34d29a8a6cf refs/tags/0.7.7\ne67ff99dc43c391e89a37f97a9d298c3428bbde2 refs/tags/0.7.8\n4b72ecda0d40ed8e5ab8ad4095a0691d30ec6cd0 refs/tags/0.7.9\n2512b8cc3d7f001d277e89978da2049a5feee5c4 refs/tags/0.8.0\n86c47029690bd2731d204245f3f54462227bba0d refs/tags/0.9.0\n9a7f94f78588e9b5ba7ca077e1f7eae0607c6cf6 refs/tags/0.9.1\n08c915dc016d16c1dfa9a77d0b045ec29c9f2074 refs/tags/0.9.2\n3fb658b1ce1e1efa37d6f9f14322bdac8def02a5 refs/tags/0.9.3\n738fda0add962379ffe6aa6ca5f01a6943a98a2e refs/tags/0.9.4\n48d821add361f7ad768ecb35a0b19c38f90c919e refs/tags/0.9.5\nff9ae890f597dac301b2ac6e6805eb9ac5afd49a refs/tags/0.9.6\n483c78f06e60b0ec5e79fc3476df075ee7286890 refs/tags/0.9.7\n416eec87a5ae39a1a6035552e9e9a47d76b13026 refs/tags/1.0.0\na935cfe9445cc5218fbdd7e0afb35aa1587fff61 refs/tags/1.0.1\n4b83863a9181f054bb695b11b5d663406dfd85d2 refs/tags/1.0.2\n295145fddaa4fe29c1e71a5044d968a84f9dbf69 refs/tags/1.1.0\n8f74ea4e5718436c47305b4488842e6458a13dac refs/tags/1.1.1\n4135bb291e53d615a976e997c44fb2bd9e1ad343 refs/tags/1.1.10\n8c09dbcd16612f5989065db02ea2e7a752dd2656 refs/tags/1.1.11\naedfebdb6c016431d84b0c07cf181b957a900640 refs/tags/1.1.12\n2c2e958366ef6998115740bdf110588d730e5738 refs/tags/1.1.2\nbecc77258321e6ec40d89efdddf37bafd0d07fc3 refs/tags/1.1.3\ne070d7c9853bf94c35b81cf0c0a8980c2449bb22 refs/tags/1.1.4\n12c986cbbf65e8571a486e9230808bf887e5f04f refs/tags/1.1.5\n63df8986f5b56913b02d26954fa033eeaf43714c refs/tags/1.1.6\n38e02c9c6bd728b043036fe0d1894d774cab3108 refs/tags/1.1.7\n3c3879fff16450d28ade79a6b08982bf5cefc061 refs/tags/1.1.8\ne32b811b3b2e70a1d189d7a663bc2583e9c18f96 refs/tags/1.1.9\n0c1b4277c08197ce7e7e0aa2bad91d909fcd96ac refs/tags/2.0.0\n"), + toData("testes", GitCurrentCommit, 0, "d9db2ad09aa38fc26625341e1b666602959e144f\n"), + toData("testes", GitMergeBase, 0, "d9db2ad09aa38fc26625341e1b666602959e144f\n416eec87a5ae39a1a6035552e9e9a47d76b13026\nd9db2ad09aa38fc26625341e1b666602959e144f\n"), + toData("testes", GitCheckout, 0, "416eec87a5ae39a1a6035552e9e9a47d76b13026"), + + toData("grok", GitDiff, 0, ""), + toData("grok", GitTags, 0, "2ca193c31fa2377c1e991a080d60ca3215ff6cf0 refs/tags/0.0.1\n48007554b21ba2f65c726ae2fdda88d621865b4a refs/tags/0.0.2\n7092a0286421c7818cd335cca9ebc72d03d866c2 refs/tags/0.0.3\n62707b8ac684efac35d301dbde57dc750880268e refs/tags/0.0.4\n876f2504e0c2f785ffd2cf65a78e2aea474fa8aa refs/tags/0.0.5\nb7eb1f2501aa2382cb3a38353664a13af62a9888 refs/tags/0.0.6\nf5d818bfd6038884b3d8b531c58484ded20a58a4 refs/tags/0.1.0\n961eaddea49c3144d130d105195583d3f11fb6c6 refs/tags/0.2.0\n15ab8ed8d4f896232a976a9008548bd53af72a66 refs/tags/0.2.1\n426a7d7d4603f77ced658e73ad7f3f582413f6cd refs/tags/0.3.0\n83cf7a39b2fe897786fb0fe01a7a5933c3add286 refs/tags/0.3.1\n8d2e3c900edbc95fa0c036fd76f8e4f814aef2c1 refs/tags/0.3.2\n48b43372f49a3bb4dc0969d82a0fca183fb94662 refs/tags/0.3.3\n9ca947a3009ea6ba17814b20eb953272064eb2e6 refs/tags/0.4.0\n1b5643d04fba6d996a16d1ffc13d034a40003f8f refs/tags/0.5.0\n486b0eb580b1c465453d264ac758cc490c19c33e refs/tags/0.5.1\naedb0d9497390e20b9d2541cef2bb05a5cda7a71 refs/tags/0.5.2\n"), + toData("grok", GitCurrentCommit, 0, "4e6526a91a23eaec778184e16ce9a34d25d48bdc\n"), + toData("grok", GitMergeBase, 0, "4e6526a91a23eaec778184e16ce9a34d25d48bdc\n62707b8ac684efac35d301dbde57dc750880268e\n349c15fd1e03f1fcdd81a1edefba3fa6116ab911\n"), + toData("grok", GitCheckout, 0, "62707b8ac684efac35d301dbde57dc750880268e"), + + toData("nim-bytes2human", GitDiff, 0, ""), + toData("nim-bytes2human", GitTags, 0, ""), + toData("nim-bytes2human", GitCurrentcommit, 0, "ec2c1a758cabdd4751a06c8ebf2b923f19e32731\n") + ] + +#[ +Current directory is now E:\atlastest\nim-bytes2human +cmd git diff args [] --> ("", 0) +cmd git show-ref --tags args [] --> ("", 1) +cmd git log -n 1 --format=%H args [] --> (, 0) +[Warning] (nim-bytes2human) package has no tagged releases +nimble E:\atlastest\nim-bytes2human\bytes2human.nimble info (requires: @["nim >= 1.0.0"], srcDir: "src", tasks: @[]) +[Error] There were problems. +Error: execution of an external program failed: 'E:\nim\tools\atlas\atlas.exe clone https://github.com/disruptek/balls' +]# diff --git a/tools/atlas/tests/balls.nimble b/tools/atlas/tests/balls.nimble new file mode 100644 index 000000000..62ab4750b --- /dev/null +++ b/tools/atlas/tests/balls.nimble @@ -0,0 +1,32 @@ +version = "3.4.1" +author = "disruptek" +description = "a unittest framework with balls 🔴🟡🟢" +license = "MIT" + +# requires newTreeFrom +requires "https://github.com/disruptek/grok >= 0.5.0 & < 1.0.0" +requires "https://github.com/disruptek/ups < 1.0.0" +requires "https://github.com/planetis-m/sync >= 1.0.0 & < 2.0.0" +#requires "https://github.com/c-blake/cligen < 2.0.0" + +bin = @["balls"] # build the binary for basic test running +installExt = @["nim"] # we need to install balls.nim also +skipDirs = @["tests"] # so stupid... who doesn't want tests? +#installFiles = @["balls.nim"] # https://github.com/nim-lang/Nim/issues/16661 + +task test, "run tests for ci": + when defined(windows): + exec "balls.cmd" + else: + exec "balls" + +task demo, "produce a demo": + exec "nim c --define:release balls.nim" + when (NimMajor, NimMinor) != (1, 0): + echo "due to nim bug #16307, use nim-1.0" + quit 1 + exec """demo docs/demo.svg "nim c --out=\$1 examples/fails.nim"""" + exec """demo docs/clean.svg "nim c --define:danger -f --out=\$1 tests/test.nim"""" + exec "nim c --define:release --define:ballsDry balls.nim" + exec """demo docs/runner.svg "balls"""" + diff --git a/tools/atlas/tests/grok.nimble b/tools/atlas/tests/grok.nimble new file mode 100644 index 000000000..1b6d77c08 --- /dev/null +++ b/tools/atlas/tests/grok.nimble @@ -0,0 +1,5 @@ +version = "0.0.4" +author = "disruptek" +description = "don't read too much into it" +license = "MIT" +requires "nim >= 1.0.0" diff --git a/tools/atlas/tests/nim-bytes2human.nimble b/tools/atlas/tests/nim-bytes2human.nimble new file mode 100644 index 000000000..9f3ae2479 --- /dev/null +++ b/tools/atlas/tests/nim-bytes2human.nimble @@ -0,0 +1,7 @@ +version = "0.2.2" +author = "Juan Carlos" +description = "Convert bytes to kilobytes, megabytes, gigabytes, etc." +license = "MIT" +srcDir = "src" + +requires "nim >= 1.0.0" # https://github.com/juancarlospaco/nim-bytes2human/issues/2#issue-714338524 diff --git a/tools/atlas/tests/nim.cfg b/tools/atlas/tests/nim.cfg new file mode 100644 index 000000000..5f568569b --- /dev/null +++ b/tools/atlas/tests/nim.cfg @@ -0,0 +1,11 @@ +############# begin Atlas config section ########## +--noNimblePath +--path:"../balls" +--path:"../grok" +--path:"../ups" +--path:"../sync" +--path:"../npeg/src" +--path:"../testes" +--path:"../grok" +--path:"../nim-bytes2human/src" +############# end Atlas config section ########## diff --git a/tools/atlas/tests/npeg.nimble b/tools/atlas/tests/npeg.nimble new file mode 100644 index 000000000..e71fc5aa5 --- /dev/null +++ b/tools/atlas/tests/npeg.nimble @@ -0,0 +1,48 @@ +# Package + +version = "0.24.1" +author = "Ico Doornekamp" +description = "a PEG library" +license = "MIT" +srcDir = "src" +installExt = @["nim"] + +# Dependencies + +requires "nim >= 0.19.0" + +# Test + +task test, "Runs the test suite": + exec "nimble testc && nimble testcpp && nimble testarc && nimble testjs" + +task testc, "C tests": + exec "nim c -r tests/tests.nim" + +task testcpp, "CPP tests": + exec "nim cpp -r tests/tests.nim" + +task testjs, "JS tests": + exec "nim js -r tests/tests.nim" + +task testdanger, "Runs the test suite in danger mode": + exec "nim c -d:danger -r tests/tests.nim" + +task testwin, "Mingw tests": + exec "nim c -d:mingw tests/tests.nim && wine tests/tests.exe" + +task test32, "32 bit tests": + exec "nim c --cpu:i386 --passC:-m32 --passL:-m32 tests/tests.nim && tests/tests" + +task testall, "Test all": + exec "nimble test && nimble testcpp && nimble testdanger && nimble testjs && nimble testwin" + +when (NimMajor, NimMinor) >= (1, 1): + task testarc, "--gc:arc tests": + exec "nim c --gc:arc -r tests/tests.nim" +else: + task testarc, "--gc:arc tests": + exec "true" + +task perf, "Test performance": + exec "nim cpp -r -d:danger tests/performance.nim" diff --git a/tools/atlas/tests/packages/packages.json b/tools/atlas/tests/packages/packages.json new file mode 100644 index 000000000..d054a201b --- /dev/null +++ b/tools/atlas/tests/packages/packages.json @@ -0,0 +1,36 @@ +[ + { + "name": "bytes2human", + "url": "https://github.com/juancarlospaco/nim-bytes2human", + "method": "git", + "tags": [ + "bytes", + "human", + "minimalism", + "size" + ], + "description": "Convert bytes to kilobytes, megabytes, gigabytes, etc.", + "license": "LGPLv3", + "web": "https://github.com/juancarlospaco/nim-bytes2human" + }, + { + "name": "npeg", + "url": "https://github.com/zevv/npeg", + "method": "git", + "tags": [ + "PEG", + "parser", + "parsing", + "regexp", + "regular", + "grammar", + "lexer", + "lexing", + "pattern", + "matching" + ], + "description": "PEG (Parsing Expression Grammars) string matching library for Nim", + "license": "MIT", + "web": "https://github.com/zevv/npeg" + } +] diff --git a/tools/atlas/tests/sync.nimble b/tools/atlas/tests/sync.nimble new file mode 100644 index 000000000..a07ae8925 --- /dev/null +++ b/tools/atlas/tests/sync.nimble @@ -0,0 +1,10 @@ +# Package + +version = "1.4.0" +author = "Antonis Geralis" +description = "Useful synchronization primitives." +license = "MIT" + +# Deps + +requires "nim >= 1.0.0" diff --git a/tools/atlas/tests/testes.nimble b/tools/atlas/tests/testes.nimble new file mode 100644 index 000000000..60fe1d508 --- /dev/null +++ b/tools/atlas/tests/testes.nimble @@ -0,0 +1,23 @@ +version = "1.0.0" +author = "disruptek" +description = "a cure for salty testes" +license = "MIT" + +#requires "cligen >= 0.9.41 & <= 0.9.45" +#requires "bump >= 1.8.18 & < 2.0.0" +requires "https://github.com/disruptek/grok >= 0.0.4 & < 1.0.0" +requires "https://github.com/juancarlospaco/nim-bytes2human" + +bin = @["testes"] # build the binary for basic test running +installExt = @["nim"] # we need to install testes.nim also +skipDirs = @["tests"] # so stupid... who doesn't want tests? + +task test, "run tests for ci": + exec "nim c --run testes.nim" + +task demo, "produce a demo": + when (NimMajor, NimMinor) != (1, 0): + echo "due to nim bug #16307, use nim-1.0" + quit 1 + exec """demo docs/demo.svg "nim c --out=\$1 examples/balls.nim"""" + exec """demo docs/clean.svg "nim c --define:danger --out=\$1 tests/testicles.nim"""" diff --git a/tools/atlas/tests/ups.nimble b/tools/atlas/tests/ups.nimble new file mode 100644 index 000000000..d91abbe60 --- /dev/null +++ b/tools/atlas/tests/ups.nimble @@ -0,0 +1,13 @@ +version = "0.0.2" +author = "disruptek" +description = "a package handler" +license = "MIT" + +requires "npeg >= 0.23.2 & < 1.0.0" +requires "https://github.com/disruptek/testes >= 1.0.0 & < 2.0.0" + +task test, "run tests": + when defined(windows): + exec "testes.cmd" + else: + exec findExe"testes" From 4eca84cff7a16aa227b1b412d84dcecacc47dad5 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 27 Jul 2021 01:13:47 +0200 Subject: [PATCH 2876/4254] don't use plus instead of space (#18589) --- compiler/docgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 492668543..3bc01bbe6 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -919,9 +919,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = sortName = if k in routineKinds: plainName.strip else: name cleanPlainSymbol = renderPlainSymbolName(nameNode) complexSymbol = complexName(k, n, cleanPlainSymbol) - plainSymbolEnc = encodeUrl(cleanPlainSymbol) + plainSymbolEnc = encodeUrl(cleanPlainSymbol, usePlus = false) symbolOrId = d.newUniquePlainSymbol(complexSymbol) - symbolOrIdEnc = encodeUrl(symbolOrId) + symbolOrIdEnc = encodeUrl(symbolOrId, usePlus = false) deprecationMsg = genDeprecationMsg(d, pragmaNode) nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, From 22776c410a916b29c05b798523c94c834c7371ad Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 27 Jul 2021 01:15:21 +0200 Subject: [PATCH 2877/4254] Update documentation for dynlib (#17356) * Update documentation for dynlib * Apply suggestions * Improve error handling in example --- lib/pure/dynlib.nim | 78 ++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index 3c1466322..48fd91b8f 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -17,75 +17,64 @@ ## Loading a simple C function ## --------------------------- ## -## The following example demonstrates loading a function called 'greet' +## The following example demonstrates loading a function called `greet` ## from a library that is determined at runtime based upon a language choice. -## If the library fails to load or the function 'greet' is not found, +## If the library fails to load or the function `greet` is not found, ## it quits with a failure error code. ## -## .. code-block:: Nim -## -## import std/dynlib -## -## type -## greetFunction = proc(): cstring {.gcsafe, stdcall.} -## -## let lang = stdin.readLine() -## -## let lib = case lang -## of "french": -## loadLib("french.dll") -## else: -## loadLib("english.dll") -## -## if lib == nil: -## echo "Error loading library" -## quit(QuitFailure) -## -## let greet = cast[greetFunction](lib.symAddr("greet")) -## -## if greet == nil: -## echo "Error loading 'greet' function from library" -## quit(QuitFailure) -## -## let greeting = greet() -## -## echo greeting -## -## unloadLib(lib) -## +runnableExamples: + type + GreetFunction = proc (): cstring {.gcsafe, stdcall.} -import strutils + proc loadGreet(lang: string) = + let lib = + case lang + of "french": + loadLib("french.dll") + else: + loadLib("english.dll") + assert lib != nil, "Error loading library" + + let greet = cast[GreetFunction](lib.symAddr("greet")) + assert greet != nil, "Error loading 'greet' function from library" + + echo greet() + + unloadLib(lib) + + +import std/strutils type - LibHandle* = pointer ## a handle to a dynamically loaded library + LibHandle* = pointer ## A handle to a dynamically loaded library. proc loadLib*(path: string, globalSymbols = false): LibHandle {.gcsafe.} - ## loads a library from `path`. Returns nil if the library could not + ## Loads a library from `path`. Returns nil if the library could not ## be loaded. proc loadLib*(): LibHandle {.gcsafe.} - ## gets the handle from the current executable. Returns nil if the + ## Gets the handle from the current executable. Returns nil if the ## library could not be loaded. proc unloadLib*(lib: LibHandle) {.gcsafe.} - ## unloads the library `lib` + ## Unloads the library `lib`. proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = - ## raises an `EInvalidLibrary` exception. + ## Raises a `LibraryError` exception. raise newException(LibraryError, "could not find symbol: " & $name) proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.} - ## retrieves the address of a procedure/variable from `lib`. Returns nil + ## Retrieves the address of a procedure/variable from `lib`. Returns nil ## if the symbol could not be found. proc checkedSymAddr*(lib: LibHandle, name: cstring): pointer = - ## retrieves the address of a procedure/variable from `lib`. Raises - ## `EInvalidLibrary` if the symbol could not be found. + ## Retrieves the address of a procedure/variable from `lib`. Raises + ## `LibraryError` if the symbol could not be found. result = symAddr(lib, name) if result == nil: raiseInvalidLibrary(name) proc libCandidates*(s: string, dest: var seq[string]) = - ## given a library name pattern `s` write possible library names to `dest`. + ## Given a library name pattern `s`, write possible library names to `dest`. var le = strutils.find(s, '(') var ri = strutils.find(s, ')', le+1) if le >= 0 and ri > le: @@ -97,8 +86,9 @@ proc libCandidates*(s: string, dest: var seq[string]) = add(dest, s) proc loadLibPattern*(pattern: string, globalSymbols = false): LibHandle = - ## loads a library with name matching `pattern`, similar to what `dynlib` + ## Loads a library with name matching `pattern`, similar to what the `dynlib` ## pragma does. Returns nil if the library could not be loaded. + ## ## .. warning:: this proc uses the GC and so cannot be used to load the GC. var candidates = newSeq[string]() libCandidates(pattern, candidates) From 9cb5ab0108c62bfda30b4f9b52b2957fdd364544 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 27 Jul 2021 13:21:39 +0800 Subject: [PATCH 2878/4254] fix #18578 (#18580) * fix #18578 * add tests * tiny * apply changes * typo * add removeStaticFile --- compiler/extccomp.nim | 15 +++++++++------ tests/compiles/mstaticlib.nim | 1 + tests/compiles/tstaticlib.nim | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 tests/compiles/mstaticlib.nim create mode 100644 tests/compiles/tstaticlib.nim diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 831acae68..a091060ff 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -665,9 +665,10 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = addExternalFileToCompile(conf, c) proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, - objfiles: string, isDllBuild: bool): string = + objfiles: string, isDllBuild: bool, removeStaticFile: bool): string = if optGenStaticLib in conf.globalOptions: - removeFile output # fixes: bug #16947 + if removeStaticFile: + removeFile output # fixes: bug #16947 result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output), "objfiles", objfiles] else: @@ -750,8 +751,9 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, if optCDebug in conf.globalOptions and conf.cCompiler == ccVcc: result.add " /Zi /FS /Od" -template getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string): string = - getLinkCmd(conf, output, objfiles, optGenDynLib in conf.globalOptions) +template getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string, + removeStaticFile = false): string = + getLinkCmd(conf, output, objfiles, optGenDynLib in conf.globalOptions, removeStaticFile) template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped) = try: @@ -891,7 +893,7 @@ proc callCCompiler*(conf: ConfigRef) = let objFile = conf.getObjFilePath(x) let buildDll = idx != mainFileIdx let linkTarget = conf.hcrLinkTargetName(objFile, not buildDll) - cmds.add(getLinkCmd(conf, linkTarget, objfiles & " " & quoteShell(objFile), buildDll)) + cmds.add(getLinkCmd(conf, linkTarget, objfiles & " " & quoteShell(objFile), buildDll, removeStaticFile = true)) # try to remove all .pdb files for the current binary so they don't accumulate endlessly in the nimcache # for more info check the comment inside of getLinkCmd() where the /PDB: MSVC flag is used if isVSCompatible(conf): @@ -914,7 +916,8 @@ proc callCCompiler*(conf: ConfigRef) = objfiles.add(quoteShell(objFile)) let mainOutput = if optGenScript notin conf.globalOptions: conf.prepareToWriteOutput else: AbsoluteFile(conf.projectName) - linkCmd = getLinkCmd(conf, mainOutput, objfiles) + + linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true) extraCmds = getExtraCmds(conf, mainOutput) if optCompileOnly notin conf.globalOptions: const MaxCmdLen = when defined(windows): 8_000 else: 32_000 diff --git a/tests/compiles/mstaticlib.nim b/tests/compiles/mstaticlib.nim new file mode 100644 index 000000000..6ed593691 --- /dev/null +++ b/tests/compiles/mstaticlib.nim @@ -0,0 +1 @@ +echo 1234 \ No newline at end of file diff --git a/tests/compiles/tstaticlib.nim b/tests/compiles/tstaticlib.nim new file mode 100644 index 000000000..a18b59204 --- /dev/null +++ b/tests/compiles/tstaticlib.nim @@ -0,0 +1,22 @@ +import std/[os, osproc, strformat] + + +const dir = "tests/compiles" +const fileName = dir / "mstaticlib.nim" +const nim = getCurrentCompilerExe() + +block: # bug #18578 + const libName = dir / "tstaticlib1.a" + let (_, status) = execCmdEx(fmt"{nim} c -o:{libName} --app:staticlib {fileName}") + doAssert status == 0 + doAssert fileExists(libName) + removeFile(libName) + +block: # bug #16947 + const libName = dir / "tstaticlib2.a" + writeFile(libName, "echo 124") + doAssert fileExists(libName) + let (_, status) = execCmdEx(fmt"{nim} c -o:{libName} --app:staticlib {fileName}") + doAssert status == 0 + doAssert fileExists(libName) + removeFile(libName) From fa0209609d3bedd3466f162aa350d261907851ce Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 27 Jul 2021 09:36:19 +0200 Subject: [PATCH 2879/4254] fixes #18565 (#18593) * fixes #18565 --- compiler/semstmts.nim | 22 +++++++++++----------- compiler/sigmatch.nim | 4 +++- tests/arc/tkeys_lent.nim | 17 +++++++++++++++++ tests/stdlib/tgetfileinfo.nim | 1 + tests/stdlib/tos.nim | 1 + 5 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 tests/arc/tkeys_lent.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index bfce91849..75323a95e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2260,20 +2260,20 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # nkNilLit, nkEmpty}: # dec last for i in 0.. Date: Tue, 27 Jul 2021 01:36:59 -0600 Subject: [PATCH 2880/4254] Fixed const tuples in inferred generics (#18598) --- compiler/semgnrc.nim | 33 ++++++++++++------------ tests/tuples/tinferred_generic_const.nim | 14 ++++++++++ 2 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 tests/tuples/tinferred_generic_const.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 4f3c50dae..3df1e0c3f 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -391,16 +391,24 @@ proc semGenericStmt(c: PContext, n: PNode, a[^1] = semGenericStmtScope(c, a[^1], flags, ctx) closeScope(c) - of nkVarSection, nkLetSection: + of nkVarSection, nkLetSection, nkConstSection: + let varKind = + case n.kind + of nkVarSection: skVar + of nkLetSection: skLet + else: skConst for i in 0.. Date: Tue, 27 Jul 2021 00:37:11 -0700 Subject: [PATCH 2881/4254] add comment to astalgo.debug (#18594) --- compiler/astalgo.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 3c97665f0..94fa9da93 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -585,6 +585,9 @@ proc value(this: var DebugPrinter; value: PNode) = this.openCurly this.key "kind" this.value value.kind + if value.comment.len > 0: + this.key "comment" + this.value value.comment when defined(useNodeIds): this.key "id" this.value value.id From 37f5f0d7d08d6057b20d3e319b38dfe82ce1ba65 Mon Sep 17 00:00:00 2001 From: GordonBGood Date: Tue, 27 Jul 2021 14:38:30 +0700 Subject: [PATCH 2882/4254] Clarify use of import via pseudo dir... (#18569) --- doc/manual.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/manual.rst b/doc/manual.rst index 9f614c2cd..1b65ae9ee 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6190,6 +6190,7 @@ There are two pseudo directories: its semantics are: *Use the search path to look for module name but ignore the standard library locations*. In other words, it is the opposite of `std`. +It is recommended and preferred but not currently enforced that all stdlib module imports include the std/ "pseudo directory" as part of the import name. From import statement --------------------- From 493721c16c06b5681dc270679bdcbb41011614b2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Jul 2021 00:56:16 -0700 Subject: [PATCH 2883/4254] delEnv now works at CT (#18568) --- compiler/vmops.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index bc331bbcd..6ee915bd5 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -20,7 +20,7 @@ when declared(math.copySign): when declared(math.signbit): from std/math import signbit -from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, +from std/os import getEnv, existsEnv, delEnv, putEnv, dirExists, fileExists, walkDir, getAppFilename, raiseOSError, osLastError from std/md5 import getMD5 @@ -215,6 +215,7 @@ proc registerAdditionalOps*(c: PCtx) = wrap2s(getEnv, osop) wrap1s(existsEnv, osop) wrap2svoid(putEnv, osop) + wrap1svoid(delEnv, osop) wrap1s(dirExists, osop) wrap1s(fileExists, osop) wrapDangerous(writeFile, ioop) From c86f9590fb5ba6512ba33994fa0711341eb8524b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 27 Jul 2021 12:48:27 +0200 Subject: [PATCH 2884/4254] fixes #18570 (#18599) --- compiler/injectdestructors.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index cf09b3ff5..985f27878 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -799,7 +799,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[i] = p(n[i], c, s, m) of nkObjConstr: # see also the remark about `nkTupleConstr`. - let isRefConstr = n.typ.skipTypes(abstractInst).kind == tyRef + let t = n.typ.skipTypes(abstractInst) + let isRefConstr = t.kind == tyRef let m = if isRefConstr: sinkArg elif mode == normal: normal else: sinkArg @@ -807,7 +808,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = copyTree(n) for i in 1.. Date: Tue, 27 Jul 2021 14:32:56 +0200 Subject: [PATCH 2885/4254] fixes #18579 (#18600) --- lib/system/arc.nim | 6 ++---- tests/arc/tunref_cycle.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 tests/arc/tunref_cycle.nim diff --git a/lib/system/arc.nim b/lib/system/arc.nim index ed5e9f5ca..d66f4b997 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -207,10 +207,8 @@ proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = proc GC_unref*[T](x: ref T) = ## New runtime only supports this operation for 'ref T'. - if nimDecRefIsLast(cast[pointer](x)): - # XXX this does NOT work for virtual destructors! - `=destroy`(x[]) - nimRawDispose(cast[pointer](x), T.alignOf) + var y {.cursor.} = x + `=destroy`(y) proc GC_ref*[T](x: ref T) = ## New runtime only supports this operation for 'ref T'. diff --git a/tests/arc/tunref_cycle.nim b/tests/arc/tunref_cycle.nim new file mode 100644 index 000000000..82551b7f7 --- /dev/null +++ b/tests/arc/tunref_cycle.nim @@ -0,0 +1,26 @@ +discard """ + outputsub: '''inside closure +hello world''' + cmd: "nim c --gc:orc -d:useMalloc $file" + valgrind: true +""" + +# bug #18579 + +var fp: proc (env: pointer) {.cdecl.} +var env: pointer + +proc store(f: proc (){.closure.}) = + proc closeOver() = + echo "inside closure" + f() + (fp,env) = (cast[proc(env: pointer){.cdecl.}](rawProc closeOver), rawEnv closeOver) + GC_ref(cast[RootRef](env)) + +proc run() = + fp(env) + GC_unref(cast[RootRef](env)) + +store(proc() = echo "hello world") +run() +GC_fullCollect() From 4920b06973e69c525405ff3147dc8a823a4c3c58 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 27 Jul 2021 19:04:55 +0200 Subject: [PATCH 2886/4254] fixes #18543 (#18601) * fixes #18543 * make tests green again --- changelog.md | 1 - lib/core/macros.nim | 264 +++++++++++-------------------- testament/important_packages.nim | 1 + tests/pragmas/tcustom_pragma.nim | 25 +-- 4 files changed, 107 insertions(+), 184 deletions(-) diff --git a/changelog.md b/changelog.md index d33e24b65..89e013cff 100644 --- a/changelog.md +++ b/changelog.md @@ -51,7 +51,6 @@ implementations. Old behavior can be obtained with `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same underlying code is also updated the same way. -- Custom pragma values have now an API for use in macros. - On POSIX systems, the default signal handlers used for Nim programs (it's used for printing the stacktrace on fatal signals) will now re-raise the diff --git a/lib/core/macros.nim b/lib/core/macros.nim index c09fae6b3..d3eaf6298 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1068,11 +1068,11 @@ proc newEmptyNode*(): NimNode {.noSideEffect.} = ## Create a new empty node. result = newNimNode(nnkEmpty) -proc newStmtList*(stmts: varargs[NimNode]): NimNode= +proc newStmtList*(stmts: varargs[NimNode]): NimNode = ## Create a new statement list. result = newNimNode(nnkStmtList).add(stmts) -proc newPar*(exprs: varargs[NimNode]): NimNode= +proc newPar*(exprs: varargs[NimNode]): NimNode = ## Create a new parentheses-enclosed expression. newNimNode(nnkPar).add(exprs) @@ -1494,148 +1494,80 @@ macro expandMacros*(body: typed): untyped = echo body.toStrLit result = body -proc findPragmaNodeInRecList(arg, fieldSym: NimNode): NimNode = - case arg.kind - of nnkRecList, nnkRecCase: - for it in arg.children: - result = findPragmaNodeInRecList(it, fieldSym) - if result != nil: return - of nnkOfBranch: - return findPragmaNodeInRecList(arg[1], fieldSym) - of nnkElse: - return findPragmaNodeInRecList(arg[0], fieldSym) - of nnkIdentDefs: - for i in 0.. 0: - impl.expectKind nnkTypeDef - let pragmaExpr = impl[0] - if pragmaExpr.kind == nnkPragmaExpr: - result = pragmaExpr[1] - -proc getPragmaNodeFromType(typ: NimNode): NimNode = - case typ.kind - of nnkSym: - result = getPragmaNodeFromTypeSym(typ) - of nnkProcTy: - result = typ[1] - else: error("illegal typ kind for argument: " & $typ.kind, typ) - -proc getPragmaNodeFromVarLetSym(sym: NimNode): NimNode = - sym.expectKind nnkSym - if sym.symKind notin {nskVar, nskLet}: error("expected var/let sym", sym) - let impl = sym.getImpl - impl.expectKind nnkIdentDefs - impl.expectLen 3 - let pragmaExpr = impl[0] - if pragmaExpr.kind == nnkPragmaExpr: - result = pragmaExpr[1] - -proc getPragmasByName(pragmaExpr: NimNode, name: string): seq[NimNode] = - if pragmaExpr.kind == nnkPragma: - for it in pragmaExpr: - if it.kind in nnkPragmaCallKinds: - if eqIdent(it[0], name): - result.add it - elif it.kind == nnkSym: - if eqIdent(it, name): - result.add it - -proc getCustomPragmaNodes(sym: NimNode, name: string): seq[NimNode] = - sym.expectKind nnkSym - case sym.symKind - of nskField: - result = getPragmaNodeFromObjFieldSym(sym).getPragmasByName(name) - of nskProc: - result = getPragmaNodeFromProcSym(sym).getPragmasByName(name) - of nskType: - result = getPragmaNodeFromTypeSym(sym).getPragmasByName(name) - of nskParam: - # When a typedesc parameter is passed to the macro, it will be of nskParam. - let typeInst = getTypeInst(sym) - if typeInst.kind == nnkBracketExpr and eqIdent(typeInst[0], "typeDesc"): - result = getPragmaNodeFromTypeSym(typeInst[1]).getPragmasByName(name) + if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy: + return typ[1][1] + elif typ.typeKind == ntyTypeDesc: + let impl = typ[1].getImpl() + if impl[0].kind == nnkPragmaExpr: + return impl[0][1] else: - error("illegal sym kind for argument: " & $sym.symKind, sym) - of nskVar, nskLet: - # This checks the type of the sym too, this is consistent with how - # field expressions are handled too. If this is changed, make sure to - # change it for fields expressions too. - result = getPragmaNodeFromType(sym.getTypeInst).getPragmasByName(name) - result.add getPragmaNodeFromVarLetSym(sym).getPragmasByName(name) - else: - error("illegal sym kind for argument: " & $sym.symKind, sym) + return impl[0] # handle types which don't have macro at all -since (1, 5): - export getCustomPragmaNodes + if n.kind == nnkSym: # either an variable or a proc + let impl = n.getImpl() + if impl.kind in RoutineNodes: + return impl.pragma + elif impl.kind == nnkIdentDefs and impl[0].kind == nnkPragmaExpr: + return impl[0][1] + else: + let timpl = typ.getImpl() + if timpl.len>0 and timpl[0].len>1: + return timpl[0][1] + else: + return timpl -proc hasCustomPragma*(n: NimNode, name: string): bool = - n.expectKind nnkSym - result = getCustomPragmaNodes(n, name).len > 0 + if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}: + let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1]) + let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0]) + var typDef = getImpl(if typInst.kind == nnkVarTy: typInst[0] else: typInst) + while typDef != nil: + typDef.expectKind(nnkTypeDef) + let typ = typDef[2] + typ.expectKind({nnkRefTy, nnkPtrTy, nnkObjectTy}) + let isRef = typ.kind in {nnkRefTy, nnkPtrTy} + if isRef and typ[0].kind in {nnkSym, nnkBracketExpr}: # defines ref type for another object(e.g. X = ref X) + typDef = getImpl(typ[0]) + else: # object definition, maybe an object directly defined as a ref type + let + obj = (if isRef: typ[0] else: typ) + var identDefsStack = newSeq[NimNode](obj[2].len) + for i in 0.. 0: + var identDefs = identDefsStack.pop() + if identDefs.kind == nnkRecCase: + identDefsStack.add(identDefs[0]) + for i in 1.. 0) + let pragmaNode = customPragmaNode(n) + for p in pragmaNode: + if (p.kind == nnkSym and p == cp) or + (p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp): + return newLit(true) + return newLit(false) -iterator iterOverFormalArgs(f: NimNode): tuple[name, typ, val: NimNode] = - f.expectKind nnkFormalParams - for i in 1.. 0 and p[0].kind == nnkSym and p[0] == cp: + if p.len == 2: + result = p[1] + else: + let def = p[0].getImpl[3] + result = newTree(nnkPar) + for i in 1 ..< def.len: + let key = def[i][0] + let val = p[i] + result.add newTree(nnkExprColonExpr, key, val) + break + if result.kind == nnkEmpty: + error(n.repr & " doesn't have a pragma named " & cp.repr()) # returning an empty node results in most cases in a cryptic error, macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped = ## Calls `callee` with `args` unpacked as individual arguments. diff --git a/testament/important_packages.nim b/testament/important_packages.nim index afceffb2e..ab29dcd0d 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -114,6 +114,7 @@ pkg "nimsvg" pkg "nimterop", "nimble minitest" pkg "nimwc", "nim c nimwc.nim" pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true +pkg "nimYAML", "nim c -r test/tserialization.nim" pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" pkg "norm", "nim c -r tests/sqlite/trows.nim" pkg "npeg", "nimble testarc" diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 3ef5bdcb6..b197a7c55 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -384,7 +384,7 @@ block: discard Hello(a: 1.0, b: 12) # issue #11511 -block: +when false: template myAttr {.pragma.} type TObj = object @@ -395,23 +395,24 @@ block: let recList = objTy[2] let sym = recList[0] assert sym.kind == nnkSym and sym.eqIdent("a") - let hasAttr = sym.hasCustomPragma("myAttr") + let hasAttr = sym.hasCustomPragma(myAttr) newLit(hasAttr) doAssert hasMyAttr(TObj) -# misc -{.pragma: haha.} -{.pragma: hoho.} -template hehe(key, val: string, haha) {.pragma.} +when false: + # misc + {.pragma: haha.} + {.pragma: hoho.} + template hehe(key, val: string, haha) {.pragma.} -type A {.haha, hoho, haha, hehe("hi", "hu", "he").} = int + type A {.haha, hoho, haha, hehe("hi", "hu", "he").} = int -assert A.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") + assert A.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") -template hehe(key, val: int) {.pragma.} + template hehe(key, val: int) {.pragma.} -var bb {.haha, hoho, hehe(1, 2), haha, hehe("hi", "hu", "he").} = 3 + var bb {.haha, hoho, hehe(1, 2), haha, hehe("hi", "hu", "he").} = 3 -# left-to-right priority/override order for getCustomPragmaVal -assert bb.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") + # left-to-right priority/override order for getCustomPragmaVal + assert bb.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") From 8d2f6bba3a491bc93677da9590397346e63c2bb2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Jul 2021 10:50:59 -0700 Subject: [PATCH 2887/4254] support same-line doc comments in routines (#18595) * support same-line comments in routines * remove assert as per review comment --- compiler/parser.nim | 7 ++ .../expected/subdir/subdir_b/utils.html | 110 +++++++++++++++++- .../expected/subdir/subdir_b/utils.idx | 9 ++ nimdoc/testproject/expected/theindex.html | 36 ++++++ nimdoc/testproject/subdir/subdir_b/utils.nim | 17 +++ tests/stdlib/trepr.nim | 27 +++++ 6 files changed, 205 insertions(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index d00a17e9f..b089614b2 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1795,6 +1795,13 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode = else: result.add(p.emptyNode) indAndComment(p, result, maybeMissEquals) + let body = result[^1] + if body.kind == nkStmtList and body.len > 0 and body[0].comment.len > 0 and body[0].kind != nkCommentStmt: + if result.comment.len == 0: + # proc fn*(a: int): int = a ## foo + # => moves comment `foo` to `fn` + swap(result.comment, body[0].comment) + else: discard # xxx either `assert false` or issue a warning (otherwise we'll never know of this edge case) proc newCommentStmt(p: var Parser): PNode = #| commentStmt = COMMENT diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 939495ad1..533cb5b9d 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -115,7 +115,52 @@ window.addEventListener('DOMContentLoaded', main);
                      • Procs
                          -
                            someType + + + + + + + + + +
                              someType
                            • someType(): SomeType
                            • @@ -181,6 +226,69 @@ window.addEventListener('DOMContentLoaded', main);

                              Procs

                              + +
                              proc fn2() {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              proc fn3(): auto {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              proc fn4(): auto {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              proc fn5() {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              proc fn6() {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              proc fn7() {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              proc fn8(): auto {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              func fn9(a: int): int {....raises: [], tags: [].}
                              +
                              + +comment + +
                              + +
                              func fn10(a: int): int {....raises: [], tags: [].}
                              +
                              + +comment + +
                              proc someType(): SomeType {....raises: [], tags: [].}
                              diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx index 6dc3953af..a87393f09 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx @@ -3,6 +3,15 @@ enumValueB subdir/subdir_b/utils.html#enumValueB SomeType.enumValueB enumValueC subdir/subdir_b/utils.html#enumValueC SomeType.enumValueC SomeType subdir/subdir_b/utils.html#SomeType utils: SomeType someType subdir/subdir_b/utils.html#someType_2 utils: someType(): SomeType +fn2 subdir/subdir_b/utils.html#fn2 utils: fn2() +fn3 subdir/subdir_b/utils.html#fn3 utils: fn3(): auto +fn4 subdir/subdir_b/utils.html#fn4 utils: fn4(): auto +fn5 subdir/subdir_b/utils.html#fn5 utils: fn5() +fn6 subdir/subdir_b/utils.html#fn6 utils: fn6() +fn7 subdir/subdir_b/utils.html#fn7 utils: fn7() +fn8 subdir/subdir_b/utils.html#fn8 utils: fn8(): auto +fn9 subdir/subdir_b/utils.html#fn9,int utils: fn9(a: int): int +fn10 subdir/subdir_b/utils.html#fn10,int utils: fn10(a: int): int aEnum subdir/subdir_b/utils.html#aEnum.t utils: aEnum(): untyped bEnum subdir/subdir_b/utils.html#bEnum.t utils: bEnum(): untyped fromUtilsGen subdir/subdir_b/utils.html#fromUtilsGen.t utils: fromUtilsGen(): untyped diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index cfaf6856d..f72f6c37e 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -171,6 +171,42 @@ window.addEventListener('DOMContentLoaded', main);
                            • SomeType.enumValueC
                            +
                            fn10:
                            +
                            fn2:
                            +
                            fn3:
                            +
                            fn4:
                            +
                            fn5:
                            +
                            fn6:
                            +
                            fn7:
                            +
                            fn8:
                            +
                            fn9:
                            Foo:
                            • testproject: Foo
                            • diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index 4e3aa1f10..37c91dd3c 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -31,6 +31,23 @@ proc someType*(): SomeType = ## constructor. SomeType(2) + +proc fn2*() = discard ## comment +proc fn3*(): auto = 1 ## comment +proc fn4*(): auto = 2 * 3 + 4 ## comment +proc fn5*() ## comment +proc fn5*() = discard +proc fn6*() = + ## comment +proc fn7*() = + ## comment + discard +proc fn8*(): auto = + ## comment + 1+1 +func fn9*(a: int): int = 42 ## comment +func fn10*(a: int): int = a ## comment + # bug #9235 template aEnum*(): untyped = diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 356764903..83ae7b119 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -9,6 +9,7 @@ from strutils import endsWith, contains, strip from std/macros import newLit macro deb(a): string = newLit a.repr.strip +macro debTyped(a: typed): string = newLit a.repr.strip template main() = doAssert repr({3,5}) == "{3, 5}" @@ -243,5 +244,31 @@ template bar(): untyped = echo "baz" 4)""" + block: # one liner doc comments + let a1 = deb: + func fn1(): int = 1 ## comment + func fn2(): int = 1 + ## comment + let a2 = debTyped: + func fn1(): int = 1 ## comment + func fn2(): int = 1 + ## comment + doAssert a1 == """ +func fn1(): int = + ## comment + 1 + +func fn2(): int = + ## comment + 1""" + doAssert a2 == """ +func fn1(): int = + ## comment + result = 1 + +func fn2(): int = + ## comment + result = 1""" + static: main() main() From 4c1202972abdfe99232e5d15a6169c7b2e0f5d75 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Jul 2021 21:38:19 -0700 Subject: [PATCH 2888/4254] fix #17072: add times.dateTime with ISO 8601 order (#18590) * fix #17072: add times.dateTime with ISO 8601 order * address comments --- changelog.md | 6 +++++- lib/pure/times.nim | 29 ++++++++++++++++++----------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 89e013cff..be94f92c4 100644 --- a/changelog.md +++ b/changelog.md @@ -331,9 +331,12 @@ - Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). -- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time +- `std/times`: + Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time zone offsets without colons, e.g. `UTC+7 -> +0700`. + Added `dateTime` and deprecated `initDateTime`. + - Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. - Added dollar `$` and `len` for `jsre.RegExp`. @@ -357,6 +360,7 @@ - Added `dom.setInterval`, `dom.clearInterval` overloads. + - Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect if the slice is out of bounds, likewise with `strutils.delete`. diff --git a/lib/pure/times.nim b/lib/pure/times.nim index fcdd4ec8d..b2a22250d 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1333,14 +1333,13 @@ proc now*(): DateTime {.tags: [TimeEffect], benign.} = ## `cpuTime` instead, depending on the use case. getTime().local -proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, - hour: HourRange, minute: MinuteRange, second: SecondRange, - nanosecond: NanosecondRange, - zone: Timezone = local()): DateTime = +proc dateTime*(year: int, month: Month, monthday: MonthdayRange, + hour: HourRange = 0, minute: MinuteRange = 0, second: SecondRange = 0, + nanosecond: NanosecondRange = 0, + zone: Timezone = local()): DateTime = ## Create a new `DateTime <#DateTime>`_ in the specified timezone. runnableExamples: - let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc()) - doAssert $dt1 == "2017-03-30T00:00:00Z" + assert $dateTime(2017, mMar, 30, zone = utc()) == "2017-03-30T00:00:00Z" assertValidDate monthday, month, year let dt = DateTime( @@ -1356,12 +1355,20 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, hour: HourRange, minute: MinuteRange, second: SecondRange, - zone: Timezone = local()): DateTime = + nanosecond: NanosecondRange, + zone: Timezone = local()): DateTime {.deprecated: "use `dateTime`".} = ## Create a new `DateTime <#DateTime>`_ in the specified timezone. - runnableExamples: - let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) - doAssert $dt1 == "2017-03-30T00:00:00Z" - initDateTime(monthday, month, year, hour, minute, second, 0, zone) + runnableExamples("--warning:deprecated:off"): + assert $initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc()) == "2017-03-30T00:00:00Z" + dateTime(year, month, monthday, hour, minute, second, nanosecond, zone) + +proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, + hour: HourRange, minute: MinuteRange, second: SecondRange, + zone: Timezone = local()): DateTime {.deprecated: "use `dateTime`".} = + ## Create a new `DateTime <#DateTime>`_ in the specified timezone. + runnableExamples("--warning:deprecated:off"): + assert $initDateTime(30, mMar, 2017, 00, 00, 00, utc()) == "2017-03-30T00:00:00Z" + dateTime(year, month, monthday, hour, minute, second, 0, zone) proc `+`*(dt: DateTime, dur: Duration): DateTime = runnableExamples: From a273ea70e8817e3509014a1b3dcd16a360ed400b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 28 Jul 2021 12:46:28 +0200 Subject: [PATCH 2889/4254] implements overloadable enum values; WIP (#18470) * implements overloadable enum values * simpler code --- compiler/ast.nim | 2 +- compiler/lookups.nim | 7 +++-- compiler/options.nim | 3 +- compiler/sem.nim | 8 +++++ compiler/semexprs.nim | 36 +++++++++++++++++++++- compiler/semstmts.nim | 16 +++++++++- compiler/semtypes.nim | 12 ++++++-- compiler/sigmatch.nim | 2 +- tests/enum/toverloadable_enums.nim | 48 ++++++++++++++++++++++++++++++ tests/errmsgs/t10251.nim | 2 +- 10 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 tests/enum/toverloadable_enums.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 0eeaa8133..5b54dd8ef 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -993,7 +993,7 @@ type const OverloadableSyms* = {skProc, skFunc, skMethod, skIterator, - skConverter, skModule, skTemplate, skMacro} + skConverter, skModule, skTemplate, skMacro, skEnumField} GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, tyGenericParam} diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 44a30eefa..331eef525 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -177,13 +177,16 @@ iterator allSyms*(c: PContext): (PSym, int, bool) = proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym = var marked = initIntSet() + var symSet = OverloadableSyms + if overloadableEnums notin c.features: + symSet.excl skEnumField result = nil for im in c.imports.mitems: for s in symbols(im, marked, name, c.graph): if result == nil: result = s else: - if s.kind notin OverloadableSyms or result.kind notin OverloadableSyms: + if s.kind notin symSet or result.kind notin symSet: ambiguous = true proc searchInScopes*(c: PContext, s: PIdent; ambiguous: var bool): PSym = @@ -384,7 +387,7 @@ proc mergeShadowScope*(c: PContext) = ## ## Merges: ## shadow -> shadow: add symbols to the parent but check for redefinitions etc - ## shadow -> non-shadow: the above, but also handle exports and all that + ## shadow -> non-shadow: the above, but also handle exports and all that let shadowScope = c.currentScope c.rawCloseScope for sym in shadowScope.symbols: diff --git a/compiler/options.nim b/compiler/options.nim index f02f02256..e37dea1b6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -203,7 +203,8 @@ type vmopsDanger, strictFuncs, views, - strictNotNil + strictNotNil, + overloadableEnums LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/sem.nim b/compiler/sem.nim index 879f6efc9..804325e56 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -90,6 +90,12 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = # error correction: result = copyTree(arg) result.typ = formal + elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum: + # Pick the right 'sym' from the sym choice by looking at 'formal' type: + for ch in arg: + if sameType(ch.typ, formal): + return getConstExpr(c.module, ch, c.idgen, c.graph) + typeMismatch(c.config, info, formal, arg.typ, arg) else: result = indexTypesMatch(c, formal, arg.typ, arg) if result == nil: @@ -356,6 +362,8 @@ proc semConstExpr(c: PContext, n: PNode): PNode = if e == nil: localError(c.config, n.info, errConstExprExpected) return n + if e.kind in nkSymChoices and e[0].typ.skipTypes(abstractInst).kind == tyEnum: + return e result = getConstExpr(c.module, e, c.idgen, c.graph) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 42c6b465e..f2fe54fad 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2707,6 +2707,34 @@ proc getNilType(c: PContext): PType = result.align = c.config.target.ptrSize.int16 c.nilTypeCache = result +proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode = + var o: TOverloadIter + var i = 0 + var a = initOverloadIter(o, c, n) + while a != nil: + if a.kind in OverloadableSyms-{skModule}: + inc(i) + if i > 1: break + a = nextOverloadIter(o, c, n) + let info = getCallLineInfo(n) + if i <= 1: + if sfGenSym notin s.flags: + result = newSymNode(s, info) + markUsed(c, info, s) + onUse(info, s) + else: + result = n + else: + result = newNodeIT(nkClosedSymChoice, info, newTypeS(tyNone, c)) + a = initOverloadIter(o, c, n) + while a != nil: + if a.kind in OverloadableSyms-{skModule}: + incl(a.flags, sfUsed) + markOwnerModuleAsUsed(c, a) + result.add newSymNode(a, info) + onUse(info, a) + a = nextOverloadIter(o, c, n) + proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind @@ -2730,7 +2758,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields} var s = qualifiedLookUp(c, n, checks) if c.matchedConcept == nil: semCaptureSym(s, c.p.owner) - if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}: + case s.kind + of skProc, skFunc, skMethod, skConverter, skIterator: #performProcvarCheck(c, n, s) result = symChoice(c, n, s, scClosed) if result.kind == nkSym: @@ -2740,6 +2769,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # "procs literals" are 'owned' if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) + of skEnumField: + if overloadableEnums in c.features: + result = enumFieldSymChoice(c, n, s) + else: + result = semSym(c, n, s, flags) else: result = semSym(c, n, s, flags) of nkSym: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 75323a95e..cc09291c5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -490,6 +490,18 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = ret.add result result = semExprNoType(c, ret) +proc errorSymChoiceUseQualifier(c: PContext; n: PNode) = + assert n.kind in nkSymChoices + var err = "ambiguous identifier: '" & $n[0] & "'" + var i = 0 + for child in n: + let candidate = child.sym + if i == 0: err.add " -- use one of the following:\n" + else: err.add "\n" + err.add " " & candidate.owner.name.s & "." & candidate.name.s + inc i + localError(c.config, n.info, errGenerated, err) + proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if n.len == 1: result = semLowerLetVarCustomPragma(c, n[0], n) @@ -514,7 +526,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if a[^1].kind != nkEmpty: def = semExprWithType(c, a[^1], {}) - if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}: + if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum: + errorSymChoiceUseQualifier(c, def) + elif def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}: typFlags.incl taIsTemplateOrMacro elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: typFlags.incl taProcContextIsNotMacro diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 484997e3a..db895cab6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -144,8 +144,13 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = styleCheckDef(c.config, e) onDef(e.info, e) if sfGenSym notin e.flags: - if not isPure: addInterfaceDecl(c, e) - else: declarePureEnumField(c, e) + if not isPure: + if overloadableEnums in c.features: + addInterfaceOverloadableSymAt(c, c.currentScope, e) + else: + addInterfaceDecl(c, e) + else: + declarePureEnumField(c, e) if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil): wrongRedefinition(c, e.info, e.name.s, conflict.info) inc(counter) @@ -240,7 +245,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = if not hasUnknownTypes: if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): - localError(c.config, n.info, "type mismatch") + typeMismatch(c.config, n.info, rangeT[0], rangeT[1], n) + elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin {tyFloat..tyFloat128} or rangeT[0].kind == tyBool: localError(c.config, n.info, "ordinal or float type expected") diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6bc641bd6..674dd7e2e 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2197,7 +2197,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, var best = -1 for i in 0.. nkSym + +proc x(p: int) = discard +proc x(p: string) = discard + +proc takeCallback(param: proc(p: int)) = discard + +takeCallback x + +echo ord v diff --git a/tests/errmsgs/t10251.nim b/tests/errmsgs/t10251.nim index 0c7fe0b3d..19adf02eb 100644 --- a/tests/errmsgs/t10251.nim +++ b/tests/errmsgs/t10251.nim @@ -2,7 +2,6 @@ discard """ action:reject cmd: "nim check $options $file" nimout: ''' -t10251.nim(15, 5) Error: redefinition of 'foo'; previous declaration here: t10251.nim(13, 5) t10251.nim(19, 23) Error: redefinition of 'goo1'; previous declaration here: t10251.nim(19, 11) ''' """ @@ -14,6 +13,7 @@ type Enum2 = enum foo, bar, baz + type Enum3 {.pure.} = enum # fixed (by accident?) in https://github.com/nim-lang/Nim/pull/18263 goo0, goo1, goo2, goo1 From e616675c419552a85bdf0b47f47586852be8b5be Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 28 Jul 2021 14:31:13 +0200 Subject: [PATCH 2890/4254] various small documentation improvements (#18602) --- lib/pure/asyncdispatch.nim | 34 ++++++++++----------- lib/pure/collections/deques.nim | 13 ++++---- lib/pure/collections/intsets.nim | 2 +- lib/pure/collections/sharedlist.nim | 2 +- lib/pure/collections/tables.nim | 20 ++++++++----- lib/pure/net.nim | 8 ++--- lib/pure/strformat.nim | 46 ++++++++++++++--------------- lib/pure/strscans.nim | 2 +- lib/std/enumutils.nim | 31 +++++++++++++++---- lib/std/packedsets.nim | 8 ++--- lib/system/threads.nim | 2 +- lib/system_overview.rst | 42 +++++++++++++------------- tests/stdlib/trst.nim | 10 +++---- 13 files changed, 123 insertions(+), 97 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index d98ca77df..955e66f6b 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -42,12 +42,12 @@ ## ## Code to read some data from a socket may look something like this: ## -## .. code-block:: Nim -## var future = socket.recv(100) -## future.addCallback( -## proc () = -## echo(future.read) -## ) +## .. code-block:: Nim +## var future = socket.recv(100) +## future.addCallback( +## proc () = +## echo(future.read) +## ) ## ## All asynchronous functions returning a `Future` will not block. They ## will not however return immediately. An asynchronous function will have @@ -104,20 +104,20 @@ ## The most reliable way to handle exceptions is to use `yield` on a future ## then check the future's `failed` property. For example: ## -## .. code-block:: Nim -## var future = sock.recv(100) -## yield future -## if future.failed: -## # Handle exception +## .. code-block:: Nim +## var future = sock.recv(100) +## yield future +## if future.failed: +## # Handle exception ## ## The `async` procedures also offer limited support for the try statement. ## -## .. code-block:: Nim -## try: -## let data = await sock.recv(100) -## echo("Received ", data) -## except: -## # Handle exception +## .. code-block:: Nim +## try: +## let data = await sock.recv(100) +## echo("Received ", data) +## except: +## # Handle exception ## ## Unfortunately the semantics of the try statement may not always be correct, ## and occasionally the compilation may fail altogether. diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index fe9ceca1e..ecdf199d2 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -10,8 +10,9 @@ ## An implementation of a `deque`:idx: (double-ended queue). ## The underlying implementation uses a `seq`. ## -## Note that none of the procs that get an individual value from the deque should be used -## on an empty deque. +## .. note:: None of the procs that get an individual value from the deque should be used +## on an empty deque. +## ## If compiled with the `boundChecks` option, those procs will raise an `IndexDefect` ## on such access. This should not be relied upon, as `-d:danger` or `--checks:off` will ## disable those checks and then the procs may return garbage or crash the program. @@ -198,7 +199,7 @@ iterator items*[T](deq: Deque[T]): lent T = ## Yields every element of `deq`. ## ## **See also:** - ## * `mitems iterator <#mitems,Deque[T]>`_ + ## * `mitems iterator <#mitems.i,Deque[T]>`_ runnableExamples: from std/sequtils import toSeq @@ -214,7 +215,7 @@ iterator mitems*[T](deq: var Deque[T]): var T = ## Yields every element of `deq`, which can be modified. ## ## **See also:** - ## * `items iterator <#items,Deque[T]>`_ + ## * `items iterator <#items.i,Deque[T]>`_ runnableExamples: var a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" @@ -274,7 +275,7 @@ proc addFirst*[T](deq: var Deque[T], item: sink T) = ## Adds an `item` to the beginning of `deq`. ## ## **See also:** - ## * `addLast proc <#addLast,Deque[T],T>`_ + ## * `addLast proc <#addLast,Deque[T],sinkT>`_ runnableExamples: var a = initDeque[int]() for i in 1 .. 5: @@ -290,7 +291,7 @@ proc addLast*[T](deq: var Deque[T], item: sink T) = ## Adds an `item` to the end of `deq`. ## ## **See also:** - ## * `addFirst proc <#addFirst,Deque[T],T>`_ + ## * `addFirst proc <#addFirst,Deque[T],sinkT>`_ runnableExamples: var a = initDeque[int]() for i in 1 .. 5: diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 05e5addcc..765a23e97 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -8,7 +8,7 @@ # ## Specialization of the generic `packedsets module `_ -## for ordinal sparse sets. +## (see its documentation for more examples) for ordinal sparse sets. import std/private/since import std/packedsets diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index 79f2391f6..73e147e05 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -35,7 +35,7 @@ template withLock(t, x: untyped) = release(t.lock) proc iterAndMutate*[A](x: var SharedList[A]; action: proc(x: A): bool) = - ## Iterates over the list. If 'action' returns true, the + ## Iterates over the list. If `action` returns true, the ## current item is removed from the list. ## ## .. warning:: It may not preserve the element order after some modifications. diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 403345755..2695f3693 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -136,6 +136,8 @@ runnableExamples: ## a more complex object as a key you will be greeted by a strange compiler ## error: ## +## .. code:: +## ## Error: type mismatch: got (Person) ## but expected one of: ## hashes.hash(x: openArray[A]): Hash @@ -324,7 +326,7 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new + ## * `[]= proc<#[]=,Table[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,Table[A,B],A>`_ for checking if a key is in ## the table @@ -345,7 +347,7 @@ proc `[]`*[A, B](t: var Table[A, B], key: A): var B = ## a default value (e.g. zero for int) if the key doesn't exist ## * `getOrDefault proc<#getOrDefault,Table[A,B],A,B>`_ to return ## a custom value if the key doesn't exist - ## * `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new + ## * `[]= proc<#[]=,Table[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table ## * `hasKey proc<#hasKey,Table[A,B],A>`_ for checking if a key is in ## the table @@ -488,7 +490,7 @@ proc add*[A, B](t: var Table[A, B], key: A, val: sink B) {.deprecated: ## ## **This can introduce duplicate keys into the table!** ## - ## Use `[]= proc<#[]=,Table[A,B],A,B>`_ for inserting a new + ## Use `[]= proc<#[]=,Table[A,B],A,sinkB>`_ for inserting a new ## (key, value) pair in the table without introducing duplicates. addImpl(enlarge) @@ -499,7 +501,8 @@ template tabCellHash(i) = t.data[i].hcode proc del*[A, B](t: var Table[A, B], key: A) = ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. ## - ## .. warning:: If duplicate keys were added, this may need to be called multiple times. + ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), + ## this may need to be called multiple times. ## ## See also: ## * `pop proc<#pop,Table[A,B],A,B>`_ @@ -519,7 +522,8 @@ proc pop*[A, B](t: var Table[A, B], key: A, val: var B): bool = ## mapping of the key. Otherwise, returns `false`, and the `val` is ## unchanged. ## - ## .. warning:: If duplicate keys were added, this may need to be called multiple times. + ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), + ## this may need to be called multiple times. ## ## See also: ## * `del proc<#del,Table[A,B],A>`_ @@ -1028,7 +1032,8 @@ proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated: proc del*[A, B](t: TableRef[A, B], key: A) = ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. ## - ## **If duplicate keys were added, this may need to be called multiple times.** + ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), + ## this may need to be called multiple times. ## ## See also: ## * `pop proc<#pop,TableRef[A,B],A,B>`_ @@ -1048,7 +1053,8 @@ proc pop*[A, B](t: TableRef[A, B], key: A, val: var B): bool = ## mapping of the key. Otherwise, returns `false`, and the `val` is ## unchanged. ## - ## **If duplicate keys were added, this may need to be called multiple times.** + ## .. warning:: If duplicate keys were added (via the now deprecated `add` proc), + ## this may need to be called multiple times. ## ## See also: ## * `del proc<#del,TableRef[A,B],A>`_ diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c2e4810de..c0f9e1465 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -585,10 +585,10 @@ when defineSsl: ## ## CA certificates will be loaded, in the following order, from: ## - ## - caFile, caDir, parameters, if set - ## - if `verifyMode` is set to `CVerifyPeerUseEnvVars`, - ## the SSL_CERT_FILE and SSL_CERT_DIR environment variables are used - ## - a set of files and directories from the `ssl_certs `_ file. + ## - caFile, caDir, parameters, if set + ## - if `verifyMode` is set to `CVerifyPeerUseEnvVars`, + ## the SSL_CERT_FILE and SSL_CERT_DIR environment variables are used + ## - a set of files and directories from the `ssl_certs `_ file. ## ## The last two parameters specify the certificate file path and the key file ## path, a server socket will most likely not work without these. diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 872141383..746f01ace 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -142,12 +142,12 @@ An expression like `&"{key} is {value:arg} {{z}}"` is transformed into: temp Parts of the string that are enclosed in the curly braces are interpreted -as Nim code, to escape a `{` or `}`, double it. +as Nim code. To escape a `{` or `}`, double it. -Within a curly expression,however, '{','}', must be escaped with a backslash. +Within a curly expression, however, `{`, `}`, must be escaped with a backslash. -To enable evaluating Nim expressions within curlies, inside parentheses -colons do not need to be escaped. +To enable evaluating Nim expressions within curlies, colons inside parentheses +do not need to be escaped. ]## runnableExamples: @@ -177,28 +177,28 @@ The general form of a standard format specifier is:: The square brackets `[]` indicate an optional element. -The optional 'align' flag can be one of the following: +The optional `align` flag can be one of the following: -'<' +`<` Forces the field to be left-aligned within the available space. (This is the default for strings.) -'>' +`>` Forces the field to be right-aligned within the available space. (This is the default for numbers.) -'^' +`^` Forces the field to be centered within the available space. Note that unless a minimum field width is defined, the field width will always be the same size as the data to fill it, so that the alignment option has no meaning in this case. -The optional 'fill' character defines the character to be used to pad +The optional `fill` character defines the character to be used to pad the field to the minimum width. The fill character, if present, must be followed by an alignment flag. -The 'sign' option is only valid for numeric types, and can be one of the following: +The `sign` option is only valid for numeric types, and can be one of the following: ================= ==================================================== Sign Meaning @@ -211,22 +211,22 @@ The 'sign' option is only valid for numeric types, and can be one of the followi positive numbers. ================= ==================================================== -If the '#' character is present, integers use the 'alternate form' for formatting. +If the `#` character is present, integers use the 'alternate form' for formatting. This means that binary, octal and hexadecimal output will be prefixed -with '0b', '0o' and '0x', respectively. +with `0b`, `0o` and `0x`, respectively. -'width' is a decimal integer defining the minimum field width. If not specified, +`width` is a decimal integer defining the minimum field width. If not specified, then the field width will be determined by the content. -If the width field is preceded by a zero ('0') character, this enables +If the width field is preceded by a zero (`0`) character, this enables zero-padding. -The 'precision' is a decimal number indicating how many digits should be displayed +The `precision` is a decimal number indicating how many digits should be displayed after the decimal point in a floating point conversion. For non-numeric types the field indicates the maximum field size - in other words, how many characters will be used from the field content. The precision is ignored for integer conversions. -Finally, the 'type' determines how the data should be presented. +Finally, the `type` determines how the data should be presented. The available integer presentation types are: @@ -240,7 +240,7 @@ The available integer presentation types are: lower-case letters for the digits above 9. `X` Hex format. Outputs the number in base 16, using uppercase letters for the digits above 9. -(None) The same as 'd'. +(None) The same as `d`. ================= ==================================================== The available floating point presentation types are: @@ -249,21 +249,21 @@ The available floating point presentation types are: Type Result ================= ==================================================== `e` Exponent notation. Prints the number in scientific - notation using the letter 'e' to indicate the + notation using the letter `e` to indicate the exponent. -`E` Exponent notation. Same as 'e' except it converts +`E` Exponent notation. Same as `e` except it converts the number to uppercase. `f` Fixed point. Displays the number as a fixed-point number. -`F` Fixed point. Same as 'f' except it converts the +`F` Fixed point. Same as `f` except it converts the number to uppercase. `g` General format. This prints the number as a fixed-point number, unless the number is too - large, in which case it switches to 'e' + large, in which case it switches to `e` exponent notation. -`G` General format. Same as 'g' except it switches to 'E' +`G` General format. Same as `g` except it switches to `E` if the number gets to large. -(None) Similar to 'g', except that it prints at least one +(None) Similar to `g`, except that it prints at least one digit after the decimal point. ================= ==================================================== diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 73b53e3d6..291af7408 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -52,7 +52,7 @@ substrings starting with ``$``. These constructions are available: ================= ======================================================== Even though ``$*`` and ``$+`` look similar to the regular expressions ``.*`` -and ``.+`` they work quite differently, there is no non-deterministic +and ``.+``, they work quite differently. There is no non-deterministic state machine involved and the matches are non-greedy. ``[$*]`` matches ``[xyz]`` via ``parseutils.parseUntil``. diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 09cf24f51..6269950c7 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -79,8 +79,14 @@ macro enumNames(a: typed): untyped = iterator items*[T: HoleyEnum](E: typedesc[T]): T = ## Iterates over an enum with holes. runnableExamples: - type A = enum a0 = 2, a1 = 4, a2 - type B[T] = enum b0 = 2, b1 = 4 + type + A = enum + a0 = 2 + a1 = 4 + a2 + B[T] = enum + b0 = 2 + b1 = 4 from std/sequtils import toSeq assert A.toSeq == [a0, a1, a2] assert B[float].toSeq == [B[float].b0, B[float].b1] @@ -130,9 +136,19 @@ template symbolRank*[T: enum](a: T): int = ## for small enums, otherwise is `O(T.enumLen)`. runnableExamples: type - A = enum a0 = -3, a1 = 10, a2, a3 = (20, "f3Alt") # HoleyEnum - B = enum b0, b1, b2 # OrdinalEnum - C = enum c0 = 10, c1, c2 # OrdinalEnum + A = enum # HoleyEnum + a0 = -3 + a1 = 10 + a2 + a3 = (20, "f3Alt") + B = enum # OrdinalEnum + b0 + b1 + b2 + C = enum # OrdinalEnum + c0 = 10 + c1 + c2 assert a2.symbolRank == 2 assert b2.symbolRank == 2 assert c2.symbolRank == 2 @@ -156,7 +172,10 @@ func symbolName*[T: enum](a: T): string = assert b.symbolName == "b0" assert $b == "kb0" static: assert B.high.symbolName == "b2" - type C = enum c0 = -3, c1 = 4, c2 = 20 # HoleyEnum + type C = enum # HoleyEnum + c0 = -3 + c1 = 4 + c2 = 20 assert c1.symbolName == "c1" const names = enumNames(T) names[a.symbolRank] diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index e209d2aae..b2ee917eb 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -12,10 +12,10 @@ ## ## Supports any Ordinal type. ## -## **Note**: Currently the assignment operator `=` for `PackedSet[A]` -## performs some rather meaningless shallow copy. Since Nim currently does -## not allow the assignment operator to be overloaded, use the `assign proc -## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy. +## .. note:: Currently the assignment operator `=` for `PackedSet[A]` +## performs some rather meaningless shallow copy. Since Nim currently does +## not allow the assignment operator to be overloaded, use the `assign proc +## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy. ## ## See also ## ======== diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 2b5eb07fd..a9006b0c5 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -11,7 +11,7 @@ ## ## **Note**: This is part of the system module. Do not import it directly. ## To activate thread support you need to compile -## with the `--threads:on` command line switch. +## with the `--threads:on`:option: command line switch. ## ## Nim's memory model for threads is quite different from other common ## programming languages (C, Pascal): Each thread has its own diff --git a/lib/system_overview.rst b/lib/system_overview.rst index d6cbe1a35..df22697e0 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -48,27 +48,27 @@ Proc Usage Seqs ---- -============================================== ========================================== -Proc Usage -============================================== ========================================== -`newSeq<#newSeq>`_ Create a new sequence of a given length -`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length - and a given capacity -`setLen<#setLen,seq[T],Natural>`_ Set the length of a sequence -`len<#len,seq[T]>`_ Return the length of a sequence -`@<#@,openArray[T]>`_ Turn an array into a sequence -`add<#add,seq[T],sinkT>`_ Add an item to the sequence -`insert<#insert,seq[T],sinkT>`_ Insert an item at a specific position -`delete<#delete,seq[T],Natural>`_ Delete an item while preserving the - order of elements (`O(n)` operation) -`del<#del,seq[T],Natural>`_ `O(1)` removal, doesn't preserve the order -`pop<#pop,seq[T]>`_ Remove and return last item of a sequence -`x & y<#&,seq[T],seq[T]>`_ Concatenate two sequences -`x[a .. b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (both ends included) -`x[a .. ^b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence but `b` is a - reversed index (both ends included) -`x[a ..\< b]<#[],openArray[T],HSlice[U,V]>`_ Slice of a sequence (excluded upper bound) -============================================== ========================================== +============================================================= ========================================== +Proc Usage +============================================================= ========================================== +`newSeq<#newSeq>`_ Create a new sequence of a given length +`newSeqOfCap<#newSeqOfCap,Natural>`_ Create a new sequence with zero length + and a given capacity +`setLen<#setLen,seq[T],Natural>`_ Set the length of a sequence +`len<#len,seq[T]>`_ Return the length of a sequence +`@<#@,openArray[T]>`_ Turn an array into a sequence +`add<#add,seq[T],sinkT>`_ Add an item to the sequence +`insert<#insert,seq[T],sinkT>`_ Insert an item at a specific position +`delete<#delete,seq[T],Natural>`_ Delete an item while preserving the + order of elements (`O(n)` operation) +`del<#del,seq[T],Natural>`_ `O(1)` removal, doesn't preserve the order +`pop<#pop,seq[T]>`_ Remove and return last item of a sequence +`x & y<#&,seq[T],seq[T]>`_ Concatenate two sequences +`x[a .. b]<#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_ Slice of a sequence (both ends included) +`x[a .. ^b]<#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_ Slice of a sequence but `b` is a + reversed index (both ends included) +`x[a ..< b]<#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_ Slice of a sequence (excluded upper bound) +============================================================= ========================================== **See also:** * `sequtils module `_ for operations on container diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index fc3ccbf4e..bc11f219c 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -182,9 +182,9 @@ suite "RST parsing": test "using .. as separator b/w directives and block quotes": check(dedent""" .. note:: someNote - + .. - + someBlockQuote""".toAst == dedent""" rnInner @@ -300,14 +300,14 @@ suite "RST indentation": let input1 = dedent""" .. code-block:: nim :test: "nim c $1" - + template additive(typ: typedesc) = discard """ let input2 = dedent""" .. code-block:: nim :test: "nim c $1" - + template additive(typ: typedesc) = discard """ @@ -320,7 +320,7 @@ suite "RST indentation": let inputWrong = dedent""" .. code-block:: nim :test: "nim c $1" - + template additive(typ: typedesc) = discard """ From 7d3c3e00efe777dcbda15f2125fa77aa7d17cad4 Mon Sep 17 00:00:00 2001 From: Vindaar Date: Thu, 29 Jul 2021 07:47:34 +0200 Subject: [PATCH 2891/4254] Allow `nnkAccQuoted` in `genEnumCaseStmt` (#18606) * [enumutils] provide node kind for `Invalid node type` error * [enumutils] add support for nnkAccQuoted in `genEnumCaseStmt` For reasons unknown to me, when running `nim doc` on a file that uses `parseEnum` with an enum that contains accented quotes errors at CT with the `Invalid node for type` error. Further errors are raised, probably because the enum parsing fails? --- lib/std/enumutils.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 6269950c7..81e602ad5 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -36,6 +36,10 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, case f.kind of nnkEmpty: continue # skip first node of `enumTy` of nnkSym, nnkIdent: fStr = f.strVal + of nnkAccQuoted: + fStr = "" + for ch in f: + fStr.add ch.strVal of nnkEnumFieldDef: case f[1].kind of nnkStrLit: fStr = f[1].strVal @@ -46,7 +50,7 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, fStr = f[0].strVal fNum = f[1].intVal else: error("Invalid tuple syntax!", f[1]) - else: error("Invalid node for enum type!", f) + else: error("Invalid node for enum type `" & $f.kind & "`!", f) # add field if string not already added if fNum >= userMin and fNum <= userMax: fStr = normalizer(fStr) From 1bba641fed99bce61de2470c8bf73cd34480d907 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 29 Jul 2021 10:50:17 +0200 Subject: [PATCH 2892/4254] Update `lib.rst` (#18605) * Update lib.rst * Remove "Unstable" category Add `strbasics` * Update doc/lib.rst * Update doc/lib.rst Co-authored-by: Andreas Rumpf --- doc/lib.rst | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/doc/lib.rst b/doc/lib.rst index 988fbf6f0..54728d681 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -41,7 +41,7 @@ Automatic imports Basic Nim thread support. **Note:** This is part of the system module. Do not import it explicitly. Enabled with `--threads:on`:option:. -* `channels `_ +* `channels_builtin `_ Nim message passing support for threads. **Note:** This is part of the system module. Do not import it explicitly. Enabled with `--threads:on`:option:. @@ -49,6 +49,9 @@ Automatic imports Core ---- +* `atomics `_ + Types and operations for atomic operations and lockless algorithms. + * `bitops `_ Provides a series of low-level methods for bit manipulation. @@ -66,7 +69,7 @@ Core * `macrocache `_ Provides an API for macros to collect compile-time information across modules. - + * `macros `_ Contains the AST API and documentation of Nim for writing macros. @@ -113,7 +116,7 @@ Collections The underlying implementation uses a `seq`. * `heapqueue `_ - Implementation of a heap data structure that can be used as a priority queue. + Implementation of a binary heap data structure that can be used as a priority queue. * `intsets `_ Efficient implementation of a set of ints as a sparse bit set. @@ -129,7 +132,7 @@ Collections Efficient implementation of a set of ordinals as a sparse bit set. * `sets `_ - Nim hash and bit set support. + Nim hash set support. * `sharedlist `_ Nim shared linked list support. Contains a shared singly-linked list. @@ -167,11 +170,14 @@ String handling * `ropes `_ This module contains support for a *rope* data type. Ropes can represent very long strings efficiently; - especially concatenation is done in O(1) instead of O(n). + in particular, concatenation is done in O(1) instead of O(n). + +* `strbasics `_ + This module provides some high performance string operations. * `strformat `_ Macro based standard string interpolation/formatting. Inspired by - Python's `f`-strings. + Python's f-strings. * `strmisc `_ This module contains uncommon string handling operations that do not @@ -266,9 +272,6 @@ Math libraries * `math `_ Mathematical operations like cosine, square root. -* `mersenne `_ - Mersenne twister random number generator. - * `random `_ Fast and tiny random number generator. @@ -433,7 +436,7 @@ Hashing ------- * `base64 `_ - This module implements a base64 encoder and decoder. + This module implements a Base64 encoder and decoder. * `hashes `_ This module implements efficient computations of hash values for diverse @@ -446,7 +449,7 @@ Hashing An OID is a global ID that consists of a timestamp, a unique counter, and a random value. This combination should suffice to produce a globally distributed unique ID. This implementation was extracted - from the Mongodb interface and it thus binary compatible with a Mongo OID. + from the MongoDB interface and it thus binary compatible with a MongoDB OID. * `sha1 `_ This module implements a sha1 encoder and decoder. @@ -487,9 +490,8 @@ Miscellaneous This module implements the `with` macro for easy function chaining. - -Modules for JS backend ----------------------- +Modules for the JS backend +-------------------------- * `asyncjs `_ Types and macros for writing asynchronous procedures in JavaScript. @@ -497,6 +499,9 @@ Modules for JS backend * `dom `_ Declaration of the Document Object Model for the JS backend. +* `jsbigints `_ + Arbitrary precision integers. + * `jsconsole `_ Wrapper for the `console` object. @@ -519,7 +524,6 @@ Regular expressions expressions. The current implementation uses PCRE. - Database support ---------------- @@ -583,7 +587,7 @@ Database support * `mysql `_ Contains a wrapper for the mySQL API. * `sqlite3 `_ - Contains a wrapper for SQLite 3 API. + Contains a wrapper for the SQLite 3 API. * `odbcsql `_ interface to the ODBC driver. @@ -593,11 +597,3 @@ Network Programming and Internet Protocols * `openssl `_ Wrapper for OpenSSL. - - - -Unstable -======== - -* `atomics `_ - Types and operations for atomic operations and lockless algorithms. From bbe05c15326c7a62d15c0fe47d1c6e1be3ab11a8 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 29 Jul 2021 14:30:19 +0300 Subject: [PATCH 2893/4254] docgen: draw frame around active anchors (#18607) --- config/nimdoc.cfg | 3 +- doc/nimdoc.css | 6 + .../expected/index.html | 3 +- nimdoc/testproject/expected/nimdoc.out.css | 6 + .../expected/subdir/subdir_b/utils.html | 42 +++-- nimdoc/testproject/expected/testproject.html | 177 ++++++++++++------ 6 files changed, 162 insertions(+), 75 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 15f887023..162b2b4a3 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -46,13 +46,14 @@ doc.section.toc2 = """ # * $seeSrc: generated HTML from doc.item.seesrc (if some switches are used). doc.item = """ - +
                              $header
                              $deprecationMsg $desc $seeSrc
                              +
                              """ # Chunk of HTML emitted for each entry in the HTML table of contents. diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 5c2bf2093..4abea9ce0 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -234,6 +234,12 @@ select:focus { } /* Docgen styles */ + +:target { + border: 2px solid #B5651D; + border-style: dotted; +} + /* Links */ a { color: var(--anchor); diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index fac758c9b..3499b5326 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -121,13 +121,14 @@ window.addEventListener('DOMContentLoaded', main);

                              Procs

                              - +
                              proc foo() {....raises: [], tags: [].}
                              I do foo
                              +
                              diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 5c2bf2093..4abea9ce0 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -234,6 +234,12 @@ select:focus { } /* Docgen styles */ + +:target { + border: 2px solid #B5651D; + border-style: dotted; +} + /* Links */ a { color: var(--anchor); diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 533cb5b9d..47901ce0d 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -213,7 +213,7 @@ window.addEventListener('DOMContentLoaded', main);

                              Types

                              - +
                              SomeType = enum
                                 enumValueA, enumValueB, enumValueC
                              @@ -221,101 +221,114 @@ window.addEventListener('DOMContentLoaded', main);
                              +

                              Procs

                              - +
                              proc fn2() {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc fn3(): auto {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc fn4(): auto {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc fn5() {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc fn6() {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc fn7() {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc fn8(): auto {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              func fn9(a: int): int {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              func fn10(a: int): int {....raises: [], tags: [].}
                              comment
                              - +
                              +
                              proc someType(): SomeType {....raises: [], tags: [].}
                              constructor.
                              +

                              Templates

                              - +
                              template aEnum(): untyped
                              - +
                              +
                              template bEnum(): untyped
                              - +
                              +
                              template fromUtilsGen(): untyped
                              @@ -324,6 +337,7 @@ should be shown in utils.html only
                              discard "should be in utils.html only, not in module that calls fromUtilsGen"
                              ditto
                              +
                              diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 0f6289bbc..d98b1b00f 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -447,7 +447,7 @@ window.addEventListener('DOMContentLoaded', main);

                              Types

                              - +
                              A {.inject.} = enum
                                 aA
                              @@ -455,7 +455,8 @@ window.addEventListener('DOMContentLoaded', main); The enum A.
                              - +
                              +
                              B {.inject.} = enum
                                 bB
                              @@ -463,7 +464,8 @@ The enum A. The enum B.
                              - +
                              +
                              Foo = enum
                                 enumValueA2
                              @@ -471,7 +473,8 @@ The enum B.
                              - +
                              +
                              FooBuzz {....deprecated: "FooBuzz msg".} = int
                              @@ -481,7 +484,8 @@ The enum B.
                              - +
                              +
                              Shapes = enum
                                 Circle,                   ## A circle
                                 Triangle,                 ## A three-sided shape
                              @@ -491,64 +495,71 @@ The enum B.
                               Some shapes.
                               
                               
                            +

                            Vars

                            - +
                            aVariable: array[1, int]
                            - +
                            +
                            someVariable: bool
                            This should be visible.
                            +

                            Consts

                            - +
                            C_A = 0x7FF0000000000000'f64
                            - +
                            +
                            C_B = 0o377'i8
                            - +
                            +
                            C_C = 0o277'i8
                            - +
                            +
                            C_D = 0o177777'i16
                            +

                            Procs

                            - +
                            proc addfBug14485() {....raises: [], tags: [].}
                            @@ -567,14 +578,16 @@ Some proc ]#
  • - + +
    proc anything() {....raises: [], tags: [].}
    There is no block quote after blank lines at the beginning.
    - +
    +
    proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
                                     tags: [RootEffect].}
    @@ -582,14 +595,16 @@ There is no block quote after blank lines at the beginning. ok1
    - +
    +
    proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    - +
    +
    proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    @@ -598,21 +613,24 @@ ok1
    discard
    ok1
    - +
    +
    proc bar[T](a, b: T): T
    - +
    +
    proc baz() {....raises: [], tags: [].}
    - +
    +
    proc baz[T](a, b: T): T {....deprecated.}
    @@ -622,7 +640,8 @@ ok1 This is deprecated without message.
    - +
    +
    proc buzz[T](a, b: T): T {....deprecated: "since v0.20".}
    @@ -632,7 +651,8 @@ This is deprecated without message. This is deprecated with a message.
    - +
    +
    proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
         header: "<stdio.h>", varargs, discardable.}
    @@ -640,7 +660,8 @@ This is deprecated with a message.
    - +
    +
    proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
                                          varargs, discardable.}
    @@ -648,7 +669,8 @@ This is deprecated with a message. the c printf. etc.
    - +
    +
    proc fromUtils3() {....raises: [], tags: [].}
    @@ -658,14 +680,16 @@ came form utils but should be shown where
    - + +
    proc isValid[T](x: T): bool
    - +
    +
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
    @@ -678,7 +702,8 @@ came form utils but should be shown where discard "in low2"
    - + +
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
    @@ -689,7 +714,8 @@ came form utils but should be shown where low(2) # => -9223372036854775808
    - + +
    proc p1() {....raises: [], tags: [].}
    @@ -712,14 +738,16 @@ this is a nested doc comment # also work after
    - + +
    func someFunc() {....raises: [], tags: [].}
    My someFunc. Stuff in quotes here. Some link
    - +
    +
    proc tripleStrLitTest() {....raises: [], tags: [].}
    @@ -762,14 +790,16 @@ at indent 0 # should be in
    - + +
    proc z1(): Foo {....raises: [], tags: [].}
    cz1
    - +
    +
    proc z2() {....raises: [], tags: [].}
    @@ -778,49 +808,56 @@ cz2
    discard "in cz2"
    - +
    +
    proc z3() {....raises: [], tags: [].}
    cz3
    - +
    +
    proc z4() {....raises: [], tags: [].}
    cz4
    - +
    +
    proc z5(): int {....raises: [], tags: [].}
    cz5
    - +
    +
    proc z6(): int {....raises: [], tags: [].}
    cz6
    - +
    +
    proc z7(): int {....raises: [], tags: [].}
    cz7
    - +
    +
    proc z8(): int {....raises: [], tags: [].}
    cz8
    - +
    +
    proc z9() {....raises: [], tags: [].}
    @@ -829,7 +866,8 @@ cz8
    doAssert 1 + 1 == 2
    - +
    +
    proc z10() {....raises: [], tags: [].}
    @@ -838,7 +876,8 @@ cz8
    discard 1
    cz10
    - +
    +
    proc z11() {....raises: [], tags: [].}
    @@ -847,7 +886,8 @@ cz8
    discard 1
    - +
    +
    proc z12(): int {....raises: [], tags: [].}
    @@ -856,7 +896,8 @@ cz8
    discard 1
    - +
    +
    proc z13() {....raises: [], tags: [].}
    @@ -865,7 +906,8 @@ cz13
    discard
    - +
    +
    proc z17() {....raises: [], tags: [].}
    @@ -874,38 +916,42 @@ cz17 rest
    discard 1
    rest
    +

    Methods

    - +
    method method1(self: Moo) {.base, ...raises: [], tags: [].}
    foo1
    - +
    +
    method method2(self: Moo): int {.base, ...raises: [], tags: [].}
    foo2
    - +
    +
    method method3(self: Moo): int {.base, ...raises: [], tags: [].}
    foo3
    +

    Iterators

    - +
    iterator fromUtils1(): int {....raises: [], tags: [].}
    @@ -916,14 +962,16 @@ foo3 # ok2
    - + +
    iterator iter1(n: int): int {....raises: [], tags: [].}
    foo1
    - +
    +
    iterator iter2(n: int): int {....raises: [], tags: [].}
    @@ -932,19 +980,21 @@ foo2
    discard # bar
    +

    Macros

    - +
    macro bar(): untyped
    - +
    +
    macro z16()
    @@ -955,26 +1005,29 @@ foo2
    doAssert 2 == 1 + 1
    - +
    +
    macro z18(): int
    cz18
    +

    Templates

    - +
    template foo(a, b: SomeType)
    This does nothing
    - +
    +
    template fromUtils2()
    @@ -984,7 +1037,8 @@ ok3 in module calling fromUtilsGen"""
    - + +
    template myfn()
    @@ -1006,7 +1060,8 @@ bar # should be in
    should be still in - + +
    template testNimDocTrailingExample()
    @@ -1015,14 +1070,16 @@ bar
    discard 2
    - +
    +
    template z6t(): int
    cz6t
    - +
    +
    template z14()
    @@ -1031,7 +1088,8 @@ cz14
    discard
    - +
    +
    template z15()
    @@ -1048,6 +1106,7 @@ cz15
    discard 1
    in or out?
    +
    From 6b3c77e7f4421267c551b1cd84717a19c65be2c5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Jul 2021 14:05:26 -0700 Subject: [PATCH 2894/4254] Remove tracking of environment from osenv.nim v2 (#18575) * Remove unnecessary environment tracking * try to fix windows * fix delEnv * make putEnv work on windows even with empty values; improve tests: add tests, add js, vm testing * [skip ci] fix changelog Co-authored-by: Caden Haustein --- changelog.md | 3 + lib/pure/includes/osenv.nim | 237 +++++++++----------------- lib/std/private/win_setenv.nim | 92 ++++++++++ tests/destructor/tnewruntime_misc.nim | 2 +- tests/stdlib/tos.nim | 34 +--- tests/stdlib/tosenv.nim | 58 +++++++ 6 files changed, 240 insertions(+), 186 deletions(-) create mode 100644 lib/std/private/win_setenv.nim create mode 100644 tests/stdlib/tosenv.nim diff --git a/changelog.md b/changelog.md index be94f92c4..a19697c8c 100644 --- a/changelog.md +++ b/changelog.md @@ -97,11 +97,14 @@ The downside is that these defines now have custom logic that doesn't apply for other defines. +- `std/os`: `putEnv` now raises if the 1st argument contains a `=` + - Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints`. - In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. + ## Standard library additions and changes - `strformat`: diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index db291c5fd..6aaafbfda 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -40,112 +40,15 @@ when defined(nodejs): # {.error: "requires -d:nodejs".} else: - when defined(windows): - from parseutils import skipIgnoreCase proc c_getenv(env: cstring): cstring {. importc: "getenv", header: "".} - when defined(vcc): + when defined(windows): proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + from std/private/win_setenv import setEnvImpl else: proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} - proc c_unsetenv(env: cstring): cint {. - importc: "unsetenv", header: "".} - - # Environment handling cannot be put into RTL, because the `envPairs` - # iterator depends on `environment`. - - var - envComputed {.threadvar.}: bool - environment {.threadvar.}: seq[string] - - when defined(nimV2): - proc unpairedEnvAllocs*(): int = - result = environment.len - if result > 0: inc result - - when defined(windows) and not defined(nimscript): - # because we support Windows GUI applications, things get really - # messy here... - when useWinUnicode: - when defined(cpp): - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. - importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "".} - else: - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. - importc: "wcschr", header: "".} - else: - proc strEnd(cstr: cstring, c = 0'i32): cstring {. - importc: "strchr", header: "".} - - proc getEnvVarsC() = - if not envComputed: - environment = @[] - when useWinUnicode: - var - env = getEnvironmentStringsW() - e = env - if e == nil: return # an error occurred - while true: - var eend = strEnd(e) - add(environment, $e) - e = cast[WideCString](cast[ByteAddress](eend)+2) - if eend[1].int == 0: break - discard freeEnvironmentStringsW(env) - else: - var - env = getEnvironmentStringsA() - e = env - if e == nil: return # an error occurred - while true: - var eend = strEnd(e) - add(environment, $e) - e = cast[cstring](cast[ByteAddress](eend)+1) - if eend[1] == '\0': break - discard freeEnvironmentStringsA(env) - envComputed = true - - else: - const - useNSGetEnviron = (defined(macosx) and not defined(ios) and not defined(emscripten)) or defined(nimscript) - - when useNSGetEnviron: - # From the manual: - # Shared libraries and bundles don't have direct access to environ, - # which is only available to the loader ld(1) when a complete program - # is being linked. - # The environment routines can still be used, but if direct access to - # environ is needed, the _NSGetEnviron() routine, defined in - # , can be used to retrieve the address of environ - # at runtime. - proc NSGetEnviron(): ptr cstringArray {. - importc: "_NSGetEnviron", header: "".} - elif defined(haiku): - var gEnv {.importc: "environ", header: "".}: cstringArray - else: - var gEnv {.importc: "environ".}: cstringArray - - proc getEnvVarsC() = - # retrieves the variables of char** env of C's main proc - if not envComputed: - environment = @[] - when useNSGetEnviron: - var gEnv = NSGetEnviron()[] - var i = 0 - while gEnv[i] != nil: - add environment, $gEnv[i] - inc(i) - envComputed = true - - proc findEnvVar(key: string): int = - getEnvVarsC() - var temp = key & '=' - for i in 0..high(environment): - when defined(windows): - if skipIgnoreCase(environment[i], temp) == len(temp): return i - else: - if startsWith(environment[i], temp): return i - return -1 + proc c_unsetenv(env: cstring): cint {.importc: "unsetenv", header: "".} proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = ## Returns the value of the `environment variable`:idx: named `key`. @@ -163,16 +66,9 @@ else: assert getEnv("unknownEnv") == "" assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" - when nimvm: - discard "built into the compiler" - else: - var i = findEnvVar(key) - if i >= 0: - return substr(environment[i], find(environment[i], '=')+1) - else: - var env = c_getenv(key) - if env == nil: return default - result = $env + let env = c_getenv(key) + if env == nil: return default + result = $env proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = ## Checks whether the environment variable named `key` exists. @@ -186,11 +82,7 @@ else: runnableExamples: assert not existsEnv("unknownEnv") - when nimvm: - discard "built into the compiler" - else: - if c_getenv(key) != nil: return true - else: return findEnvVar(key) >= 0 + return c_getenv(key) != nil proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = ## Sets the value of the `environment variable`:idx: named `key` to `val`. @@ -201,33 +93,14 @@ else: ## * `existsEnv proc <#existsEnv,string>`_ ## * `delEnv proc <#delEnv,string>`_ ## * `envPairs iterator <#envPairs.i>`_ - - # Note: by storing the string in the environment sequence, - # we guarantee that we don't free the memory before the program - # ends (this is needed for POSIX compliance). It is also needed so that - # the process itself may access its modified environment variables! - when nimvm: - discard "built into the compiler" + when defined(windows): + if key.len == 0 or '=' in key: + raise newException(OSError, "invalid key, got: " & $(key, val)) + if setEnvImpl(key, val, 1'i32) != 0'i32: + raiseOSError(osLastError(), $(key, val)) else: - var indx = findEnvVar(key) - if indx >= 0: - environment[indx] = key & '=' & val - else: - add environment, (key & '=' & val) - indx = high(environment) - when defined(windows) and not defined(nimscript): - when useWinUnicode: - var k = newWideCString(key) - var v = newWideCString(val) - if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) - else: - if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) - elif defined(vcc): - if c_putenv_s(key, val) != 0'i32: - raiseOSError(osLastError()) - else: - if c_setenv(key, val, 1'i32) != 0'i32: - raiseOSError(osLastError()) + if c_setenv(key, val, 1'i32) != 0'i32: + raiseOSError(osLastError(), $(key, val)) proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = ## Deletes the `environment variable`:idx: named `key`. @@ -238,21 +111,45 @@ else: ## * `existsEnv proc <#existsEnv,string>`_ ## * `putEnv proc <#putEnv,string,string>`_ ## * `envPairs iterator <#envPairs.i>`_ - when nimvm: - discard "built into the compiler" + template bail = raiseOSError(osLastError(), key) + when defined(windows): + #[ + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160 + > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string + note that nil is not legal + ]# + if key.len == 0 or '=' in key: + raise newException(OSError, "invalid key, got: " & key) + if c_putenv_s(key, "") != 0'i32: bail else: - var indx = findEnvVar(key) - if indx < 0: return # Do nothing if the env var is not already set - when defined(windows) and not defined(nimscript): - when useWinUnicode: - var k = newWideCString(key) - if setEnvironmentVariableW(k, nil) == 0'i32: raiseOSError(osLastError()) - else: - if setEnvironmentVariableA(key, nil) == 0'i32: raiseOSError(osLastError()) + if c_unsetenv(key) != 0'i32: bail + + when defined(windows): + when useWinUnicode: + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", + header: "".} else: - if c_unsetenv(key) != 0'i32: - raiseOSError(osLastError()) - environment.delete(indx) + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importc: "wcschr", + header: "".} + else: + proc strEnd(cstr: cstring, c = 0'i32): cstring {.importc: "strchr", + header: "".} + elif defined(macosx) and not defined(ios) and not defined(emscripten): + # From the manual: + # Shared libraries and bundles don't have direct access to environ, + # which is only available to the loader ld(1) when a complete program + # is being linked. + # The environment routines can still be used, but if direct access to + # environ is needed, the _NSGetEnviron() routine, defined in + # , can be used to retrieve the address of environ + # at runtime. + proc NSGetEnviron(): ptr cstringArray {.importc: "_NSGetEnviron", + header: "".} + elif defined(haiku): + var gEnv {.importc: "environ", header: "".}: cstringArray + else: + var gEnv {.importc: "environ".}: cstringArray iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = ## Iterate over all `environments variables`:idx:. @@ -265,8 +162,30 @@ else: ## * `existsEnv proc <#existsEnv,string>`_ ## * `putEnv proc <#putEnv,string,string>`_ ## * `delEnv proc <#delEnv,string>`_ - getEnvVarsC() - for i in 0..high(environment): - var p = find(environment[i], '=') - yield (substr(environment[i], 0, p-1), - substr(environment[i], p+1)) + when defined(windows): + block: + template impl(get_fun, typ, size, zero, free_fun) = + let env = get_fun() + var e = env + if e == nil: break + while true: + let eend = strEnd(e) + let kv = $e + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) + e = cast[typ](cast[ByteAddress](eend)+size) + if typeof(zero)(eend[1]) == zero: break + discard free_fun(env) + when useWinUnicode: + impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW) + else: + impl(getEnvironmentStringsA, cstring, 1, '\0', freeEnvironmentStringsA) + else: + var i = 0 + when defined(macosx) and not defined(ios) and not defined(emscripten): + var gEnv = NSGetEnviron()[] + while gEnv[i] != nil: + let kv = $gEnv[i] + inc(i) + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim new file mode 100644 index 000000000..067e656a3 --- /dev/null +++ b/lib/std/private/win_setenv.nim @@ -0,0 +1,92 @@ +#[ +Copyright (c) Facebook, Inc. and its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Adapted `setenv` from https://github.com/facebook/folly/blob/master/folly/portability/Stdlib.cpp +translated from C to nim. +]# + +#[ +Introduced in https://github.com/facebook/folly/commit/5d8ca09a3f96afefb44e35808f03651a096ab9c7 + +TODO: +check errno_t vs cint +]# + +when not defined(windows): discard +else: + proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {. + stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA", sideEffect.} + # same as winlean.setEnvironmentVariableA + + proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} + proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv", header: "".} + + var errno {.importc, header: "".}: cint + type wchar_t {.importc: "wchar_t".} = int16 + var gWenviron {.importc:"_wenviron".}: ptr ptr wchar_t + # xxx `ptr UncheckedArray[WideCString]` did not work + + proc mbstowcs_s(pReturnValue: ptr csize_t, wcstr: WideCString, sizeInWords: csize_t, mbstr: cstring, count: csize_t): cint {.importc: "mbstowcs_s", header: "".} + # xxx cint vs errno_t? + + proc setEnvImpl*(name: cstring, value: cstring, overwrite: cint): cint = + const EINVAL = cint(22) + const MAX_ENV = 32767 + # xxx get it from: `var MAX_ENV {.importc: "_MAX_ENV", header:"".}: cint` + if overwrite == 0 and c_getenv(name) != nil: return 0 + if value[0] != '\0': + let e = c_putenv_s(name, value) + if e != 0: + errno = e + return -1 + return 0 + #[ + We are trying to set the value to an empty string, but `_putenv_s` deletes + entries if the value is an empty string, and just calling + SetEnvironmentVariableA doesn't update `_environ`, + so we have to do these terrible things. + ]# + if c_putenv_s(name, " ") != 0: + errno = EINVAL + return -1 + # Here lies the documentation we blatently ignore to make this work. + var s = c_getenv(name) + s[0] = '\0' + #[ + This would result in a double null termination, which normally signifies the + end of the environment variable list, so we stick a completely empty + environment variable into the list instead. + ]# + s[1] = '=' + #[ + If gWenviron is null, the wide environment has not been initialized + yet, and we don't need to try to update it. We have to do this otherwise + we'd be forcing the initialization and maintenance of the wide environment + even though it's never actually used in most programs. + ]# + if gWenviron != nil: + # var buf: array[MAX_ENV + 1, WideCString] + var buf: array[MAX_ENV + 1, Utf16Char] + let buf2 = cast[WideCString](buf[0].addr) + var len: csize_t + if mbstowcs_s(len.addr, buf2, buf.len.csize_t, name, MAX_ENV) != 0: + errno = EINVAL + return -1 + c_wgetenv(buf2)[0] = '\0'.Utf16Char + c_wgetenv(buf2)[1] = '='.Utf16Char + + # And now, we have to update the outer environment to have a proper empty value. + if setEnvironmentVariableA(name, value) == 0: + errno = EINVAL + return -1 + return 0 diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index 48ea36b7c..ac061f2f7 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -7,7 +7,7 @@ axc ... destroying GenericObj[T] GenericObj[system.int] test -(allocCount: 13, deallocCount: 11) +(allocCount: 12, deallocCount: 10) 3''' """ diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index fedf2b3e3..dcb2d44f4 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -331,7 +331,7 @@ block walkDirRec: doAssert p.startsWith("walkdir_test") var s: seq[string] - for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative=true): + for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative = true): s.add(p) doAssert s.len == 2 @@ -553,19 +553,19 @@ block ospaths: doAssert joinPath("/", "") == unixToNativePath"/" doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case... doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c" - doAssert joinPath("foo/","") == unixToNativePath"foo/" - doAssert joinPath("foo/","abc") == unixToNativePath"foo/abc" - doAssert joinPath("foo//./","abc/.//") == unixToNativePath"foo/abc/" - doAssert joinPath("foo","abc") == unixToNativePath"foo/abc" - doAssert joinPath("","abc") == unixToNativePath"abc" + doAssert joinPath("foo/", "") == unixToNativePath"foo/" + doAssert joinPath("foo/", "abc") == unixToNativePath"foo/abc" + doAssert joinPath("foo//./", "abc/.//") == unixToNativePath"foo/abc/" + doAssert joinPath("foo", "abc") == unixToNativePath"foo/abc" + doAssert joinPath("", "abc") == unixToNativePath"abc" - doAssert joinPath("zook/.","abc") == unixToNativePath"zook/abc" + doAssert joinPath("zook/.", "abc") == unixToNativePath"zook/abc" # controversial: inconsistent with `joinPath("zook/.","abc")` # on linux, `./foo` and `foo` are treated a bit differently for executables # but not `./foo/bar` and `foo/bar` doAssert joinPath(".", "/lib") == unixToNativePath"./lib" - doAssert joinPath(".","abc") == unixToNativePath"./abc" + doAssert joinPath(".", "abc") == unixToNativePath"./abc" # cases related to issue #13455 doAssert joinPath("foo", "", "") == "foo" @@ -605,24 +605,6 @@ block getTempDir: block: # getCacheDir doAssert getCacheDir().dirExists -block osenv: - block delEnv: - const dummyEnvVar = "DUMMY_ENV_VAR" # This env var wouldn't be likely to exist to begin with - doAssert existsEnv(dummyEnvVar) == false - putEnv(dummyEnvVar, "1") - doAssert existsEnv(dummyEnvVar) == true - delEnv(dummyEnvVar) - doAssert existsEnv(dummyEnvVar) == false - delEnv(dummyEnvVar) # deleting an already deleted env var - doAssert existsEnv(dummyEnvVar) == false - block: # putEnv, bug #18502 - doAssertRaises(OSError): putEnv("DUMMY_ENV_VAR_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE") - doAssertRaises(OSError): putEnv("", "NEW_DUMMY_VALUE") - block: - doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", "") == "" - doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", " ") == " " - doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", "Arrakis") == "Arrakis" - block isRelativeTo: doAssert isRelativeTo("/foo", "/") doAssert isRelativeTo("/foo/bar", "/foo") diff --git a/tests/stdlib/tosenv.nim b/tests/stdlib/tosenv.nim new file mode 100644 index 000000000..df5759d0c --- /dev/null +++ b/tests/stdlib/tosenv.nim @@ -0,0 +1,58 @@ +discard """ + matrix: "--threads" + joinable: false + targets: "c js cpp" +""" + +import std/os +from std/sequtils import toSeq +import stdtest/testutils + +template main = + block: # delEnv, existsEnv, getEnv, envPairs + for val in ["val", ""]: # ensures empty val works too + const key = "NIM_TESTS_TOSENV_KEY" + doAssert not existsEnv(key) + putEnv(key, val) + doAssert existsEnv(key) + doAssert getEnv(key) == val + when nimvm: discard + else: + doAssert (key, val) in toSeq(envPairs()) + delEnv(key) + when nimvm: discard + else: + doAssert (key, val) notin toSeq(envPairs()) + doAssert not existsEnv(key) + delEnv(key) # deleting an already deleted env var + doAssert not existsEnv(key) + + block: + doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == "" + doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " " + doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval" + + whenVMorJs: discard # xxx improve + do: + doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE")) + doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE")) + doAssert not existsEnv("") + doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE") + doAssert not existsEnv("NIM_TESTS_TOSENV_PUT") + +static: main() +main() + +when not defined(js): + block: # bug #18533 + proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} + var thr: Thread[void] + proc threadFunc {.thread.} = putEnv("foo", "fooVal2") + + putEnv("foo", "fooVal1") + doAssert getEnv("foo") == "fooVal1" + createThread(thr, threadFunc) + joinThreads(thr) + doAssert getEnv("foo") == $c_getenv("foo") + + doAssertRaises(OSError): delEnv("foo=bar") From afc0259b125f5be032bf4c13721669c5452f9143 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 29 Jul 2021 19:28:33 -0700 Subject: [PATCH 2895/4254] fix #18385 followup, by building nimsuggest with -d:release during testing (#18581) --- koch.nim | 5 +++++ nimsuggest/tester.nim | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index 4296e4529..8dd897028 100644 --- a/koch.nim +++ b/koch.nim @@ -592,6 +592,11 @@ proc runCI(cmd: string) = execFold("Run rst2html tests", "nim r nimdoc/rsttester") execFold("Run nimpretty tests", "nim r nimpretty/tester.nim") when defined(posix): + # refs #18385, build with -d:release instead of -d:danger for testing + # We could also skip building nimsuggest in buildTools, or build it with -d:release + # in bundleNimsuggest depending on some environment variable when we are in CI. One advantage + # of rebuilding is this won't affect bin/nimsuggest when running runCI locally + execFold("build nimsuggest_testing", "nim c -o:bin/nimsuggest_testing -d:release nimsuggest/nimsuggest") execFold("Run nimsuggest tests", "nim r nimsuggest/tester") execFold("Run atlas tests", "nim c -r -d:atlasTests tools/atlas/atlas.nim clone https://github.com/disruptek/balls") diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index b62aa8783..1db33706a 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -6,6 +6,7 @@ # `nim r nimsuggest/tester.nim nimsuggest/tests/tsug_accquote.nim` import os, osproc, strutils, streams, re, sexp, net +from sequtils import toSeq type Test = object @@ -23,7 +24,7 @@ import std/compilesettings proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" - let nimsug = "bin" / addFileExt("nimsuggest", ExeExt) + let nimsug = "bin" / addFileExt("nimsuggest_testing", ExeExt) doAssert nimsug.fileExists, nimsug const libpath = querySetting(libPath) result.filename = filename @@ -272,6 +273,7 @@ proc runEpcTest(filename: string): int = let a = outp.readAll().strip() let port = parseInt(a) socket.connect("localhost", Port(port)) + for req, resp in items(s.script): if not runCmd(req, s.dest): socket.sendEpcStr(req) @@ -279,8 +281,12 @@ proc runEpcTest(filename: string): int = if not req.startsWith("mod "): let answer = sexpToAnswer(sx) doReport(filename, answer, resp, report) - finally: + socket.sendEpcStr "return arg" + # bugfix: this was in `finally` block, causing the original error to be + # potentially masked by another one in case `socket.sendEpcStr` raises + # (e.g. if socket couldn't connect in the 1st place) + finally: close(p) if report.len > 0: echo "==== EPC ========================================" @@ -336,8 +342,9 @@ proc main() = failures += runTest(xx) failures += runEpcTest(xx) else: - for x in walkFiles(tpath / "t*.nim"): - echo "Test ", x + let files = toSeq(walkFiles(tpath / "t*.nim")) + for i, x in files: + echo "$#/$# test: $#" % [$i, $files.len, x] when defined(i386): if x == "nimsuggest/tests/tmacro_highlight.nim": echo "skipping" # workaround bug #17945 From 9a26f5059be48b19d821c17fe1066c05d167bc7d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 30 Jul 2021 00:30:22 -0700 Subject: [PATCH 2896/4254] refs #16613: check opcWrDeref for nil (#18613) --- compiler/vm.nim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 9541af701..73a228b6c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -812,11 +812,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # vmgen generates opcWrDeref, which means that we must dereference # twice. # TODO: This should likely be handled differently in vmgen. - if (nfIsRef notin regs[ra].nodeAddr[].flags and - nfIsRef notin n.flags): - regs[ra].nodeAddr[][] = n[] - else: - regs[ra].nodeAddr[] = n + let nAddr = regs[ra].nodeAddr + if nAddr[] == nil: stackTrace(c, tos, pc, "opcWrDeref internal error") # refs bug #16613 + if (nfIsRef notin nAddr[].flags and nfIsRef notin n.flags): nAddr[][] = n[] + else: nAddr[] = n of rkRegisterAddr: regs[ra].regAddr[] = regs[rc] of rkNode: # xxx: also check for nkRefTy as in opcLdDeref? From c6fadb179975f79ad9914f09ce10f7fa6cbf0735 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 30 Jul 2021 15:32:00 +0800 Subject: [PATCH 2897/4254] [minor] reduce `substr` (#18611) * minor * correct * unify the type of addrLen * Update lib/packages/docutils/rstgen.nim --- lib/packages/docutils/rstgen.nim | 2 +- lib/pure/nativesockets.nim | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 10a229479..3734392c3 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -675,7 +675,7 @@ proc readIndexDir(dir: string): var x = fileEntries[0].link let i = find(x, '#') if i > 0: - x = x.substr(0, i-1) + x.setLen(i) if i != 0: # don't add entries starting with '#' result.modules.add(x.changeFileExt("")) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 124afce56..13c08dd92 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -14,6 +14,7 @@ import os, options import std/private/since +import std/strbasics when hostOS == "solaris": @@ -468,7 +469,7 @@ proc getAddrString*(sockAddr: ptr SockAddr): string = if sockAddr.sa_family.cint == nativeAfInet: result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) elif sockAddr.sa_family.cint == nativeAfInet6: - let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN + let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int else: 46 # it's actually 46 in both cases result = newString(addrLen) let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr @@ -477,7 +478,7 @@ proc getAddrString*(sockAddr: ptr SockAddr): string = result.len.int32) == nil: raiseOSError(osLastError()) if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0: - result = result.substr("::ffff:".len) + result.setSlice("::ffff:".len.. Date: Fri, 30 Jul 2021 12:05:14 +0200 Subject: [PATCH 2898/4254] fixes #18371 (#18617) --- compiler/vmops.nim | 7 +++++-- lib/std/effecttraits.nim | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 6ee915bd5..a1a4996b2 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -303,12 +303,15 @@ proc registerAdditionalOps*(c: PCtx) = proc getEffectList(c: PCtx; a: VmArgs; effectIndex: int) = let fn = getNode(a, 0) + var list = newNodeI(nkBracket, fn.info) if fn.typ != nil and fn.typ.n != nil and fn.typ.n[0].len >= effectListLen and fn.typ.n[0][effectIndex] != nil: - var list = newNodeI(nkBracket, fn.info) for e in fn.typ.n[0][effectIndex]: list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info, c.idgen) - setResult(a, list) + else: + list.add newIdentNode(getIdent(c.cache, "UncomputedEffects"), fn.info) + + setResult(a, list) registerCallback c, "stdlib.effecttraits.getRaisesListImpl", proc (a: VmArgs) = getEffectList(c, a, exceptionEffects) diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim index 358280db0..635ec82d0 100644 --- a/lib/std/effecttraits.nim +++ b/lib/std/effecttraits.nim @@ -11,7 +11,7 @@ ## for Nim's macro system. ## **Since**: Version 1.4. ## -## One can test for the existance of this standard module +## One can test for the existence of this standard module ## via `defined(nimHasEffectTraitsModule)`. import macros From ecfc47b332a67bb373d433f01277bc924b75f77f Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Fri, 30 Jul 2021 17:36:16 +0300 Subject: [PATCH 2899/4254] Modify atlas test for short commit hashes (#18619) * test commit hashes support * Update testdata.nim * remove extra newlines --- tools/atlas/packagesjson.nim | 2 -- tools/atlas/testdata.nim | 2 +- tools/atlas/tests/balls.nimble | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim index e1e23ee29..ed83ce85c 100644 --- a/tools/atlas/packagesjson.nim +++ b/tools/atlas/packagesjson.nim @@ -70,7 +70,6 @@ proc search*(pkgList: seq[Package]; terms: seq[string]) = var found = false template onFound = echo pkg - echo("") found = true break forPackage @@ -88,7 +87,6 @@ proc search*(pkgList: seq[Package]; terms: seq[string]) = onFound() else: echo(pkg) - echo(" ") if not found and terms.len > 0: echo("No package found.") diff --git a/tools/atlas/testdata.nim b/tools/atlas/testdata.nim index f960e3d08..aefaeacd2 100644 --- a/tools/atlas/testdata.nim +++ b/tools/atlas/testdata.nim @@ -25,7 +25,7 @@ const toData("ups", GitCheckout, 0, "4008f9339cd22b30e180bc87a6cca7270fd28ac1"), toData("sync", GitDiff, 0, ""), - toData("sync", GitTags, 0, "c9811af2d03dc78a920d33592d0a3daae3d9e68f refs/tags/v0.1.0\nc99d3a73344c4c02335190b489e7ea8aaa4e9584 refs/tags/v0.2.0\n6186a38c97c0f26e1a0c8016979227d26c41717b refs/tags/v0.3.0\n5506e4e09b849bd59f930fcccee3096abb089b1d refs/tags/v0.4.0\n1e4ef046ed0447aec7ca4ab3b2e2a5347ac41448 refs/tags/v0.5.0\na95f7b0b22c77b98ed63c1c4f435d550de8dbb05 refs/tags/v0.6.0\n214b868ace4ebc9140ee56734147fbd16b238c71 refs/tags/v0.7.0\n786698bf9f597834f36cd530d32faee31545a1d7 refs/tags/v0.9.0\n810bd2d75e9f6e182534ae2488670b51a9f13fc3 refs/tags/v1.0.0\na133d37991e3d4e9553c5261eabcb07d471968f7 refs/tags/v1.1.0\n0872a7cd70ea43a26deb94b8ab12cc5b89a1c212 refs/tags/v1.2.0\n19ac734438b6c04fe89711728a97fcde591324eb refs/tags/v1.3.0\nde5c7337ebc22422190e8aeca37d05651735f440 refs/tags/v1.4.0\n"), + toData("sync", GitRevParse, 0, "810bd2d75e9f6e182534ae2488670b51a9f13fc3\n"), toData("sync", GitCurrentCommit, 0, "de5c7337ebc22422190e8aeca37d05651735f440\n"), toData("sync", GitMergeBase, 0, "de5c7337ebc22422190e8aeca37d05651735f440\n810bd2d75e9f6e182534ae2488670b51a9f13fc3\n810bd2d75e9f6e182534ae2488670b51a9f13fc3\n"), diff --git a/tools/atlas/tests/balls.nimble b/tools/atlas/tests/balls.nimble index 62ab4750b..143e757e9 100644 --- a/tools/atlas/tests/balls.nimble +++ b/tools/atlas/tests/balls.nimble @@ -6,7 +6,7 @@ license = "MIT" # requires newTreeFrom requires "https://github.com/disruptek/grok >= 0.5.0 & < 1.0.0" requires "https://github.com/disruptek/ups < 1.0.0" -requires "https://github.com/planetis-m/sync >= 1.0.0 & < 2.0.0" +requires "https://github.com/planetis-m/sync#810bd2d" #requires "https://github.com/c-blake/cligen < 2.0.0" bin = @["balls"] # build the binary for basic test running From 52e276c82daf2b8a33f4e4304eac3074bb37b70d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 31 Jul 2021 23:54:08 -0700 Subject: [PATCH 2900/4254] exportC => exportc (#18625) --- tests/template/template_pragmas.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/template/template_pragmas.nim b/tests/template/template_pragmas.nim index d6c99080d..da532b010 100644 --- a/tests/template/template_pragmas.nim +++ b/tests/template/template_pragmas.nim @@ -3,7 +3,7 @@ proc output_x:string {.compileTime.} = "x" template t = const x = output_x() let - bar {.exportC:"bar" & x.} = 100 + bar {.exportc:"bar" & x.} = 100 static: doAssert(compiles (t())) From 916d0c21af6153338a8064ff953b579ff87c6ba6 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 1 Aug 2021 17:19:43 +0800 Subject: [PATCH 2901/4254] fix #18620 (#18624) * fix #18620 * add testcase --- lib/system/excpt.nim | 5 +---- tests/exception/t18620.nim | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 tests/exception/t18620.nim diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 9f65db2fe..4814b77b4 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -524,10 +524,7 @@ proc getStackTrace(e: ref Exception): string = proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = ## Returns the attached stack trace to the exception `e` as ## a `seq`. This is not yet available for the JS backend. - when not defined(nimSeqsV2): - shallowCopy(result, e.trace) - else: - result = move(e.trace) + shallowCopy(result, e.trace) proc getStackTraceEntries*(): seq[StackTraceEntry] = ## Returns the stack trace entries for the current stack trace. diff --git a/tests/exception/t18620.nim b/tests/exception/t18620.nim new file mode 100644 index 000000000..ee23f8bac --- /dev/null +++ b/tests/exception/t18620.nim @@ -0,0 +1,17 @@ +discard """ + matrix: "--gc:arc; --gc:refc" +""" + +proc hello() = + raise newException(ValueError, "You are wrong") + +var flag = false + +try: + hello() +except ValueError as e: + flag = true + doAssert len(getStackTraceEntries(e)) > 0 + doAssert len(getStackTraceEntries(e)) > 0 + +doAssert flag From 2bc07554ccd64d7405d0f386f17f7b1faa95bd6f Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 1 Aug 2021 19:52:24 +0800 Subject: [PATCH 2902/4254] make proc names consistent (#18626) * rename `endswith` to `endsWith` * rename --- compiler/semtypes.nim | 10 +++++----- tests/arc/tasyncawait.nim | 2 +- tests/async/tasyncawait.nim | 2 +- tests/async/tasyncnetudp.nim | 2 +- tests/async/tasyncssl.nim | 2 +- tests/async/tnewasyncudp.nim | 2 +- tests/async/twinasyncrw.nim | 2 +- tools/atlas/osutils.nim | 2 +- tools/trimcc.nim | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index db895cab6..cb7f847a9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1700,14 +1700,14 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType = result.rawAddSon(base) result.flags.incl tfHasStatic -proc semTypeof(c: PContext; n: PNode; prev: PType): PType = +proc semTypeOf(c: PContext; n: PNode; prev: PType): PType = openScope(c) let t = semExprWithType(c, n, {efInTypeof}) closeScope(c) fixupTypeOf(c, prev, t) result = t.typ -proc semTypeof2(c: PContext; n: PNode; prev: PType): PType = +proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType = openScope(c) var m = BiggestInt 1 # typeOfIter if n.len == 3: @@ -1731,7 +1731,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkTypeOfExpr: # for ``typeof(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1, c.config) - result = semTypeof(c, n[0], prev) + result = semTypeOf(c, n[0], prev) if result.kind == tyTypeDesc: result.flags.incl tfExplicit of nkPar: if n.len == 1: result = semTypeNode(c, n[0], prev) @@ -1833,9 +1833,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semAnyRef(c, n, tyRef, prev) elif op.id == ord(wType): checkSonsLen(n, 2, c.config) - result = semTypeof(c, n[1], prev) + result = semTypeOf(c, n[1], prev) elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeOf: - result = semTypeof2(c, n, prev) + result = semTypeOf2(c, n, prev) elif op.s == "owned" and optOwnedRefs notin c.config.globalOptions and n.len == 2: result = semTypeExpr(c, n[1], prev) else: diff --git a/tests/arc/tasyncawait.nim b/tests/arc/tasyncawait.nim index 75d9bc9b5..91a7453cd 100644 --- a/tests/arc/tasyncawait.nim +++ b/tests/arc/tasyncawait.nim @@ -40,7 +40,7 @@ proc readMessages(client: AsyncFD) {.async.} = clientCount.inc break else: - if line.startswith("Message "): + if line.startsWith("Message "): msgCount.inc else: doAssert false diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index f658a15ed..e86542b2d 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -34,7 +34,7 @@ proc readMessages(client: AsyncFD) {.async.} = clientCount.inc break else: - if line.startswith("Message "): + if line.startsWith("Message "): msgCount.inc else: doAssert false diff --git a/tests/async/tasyncnetudp.nim b/tests/async/tasyncnetudp.nim index ef6dfc5e1..dade96fb2 100644 --- a/tests/async/tasyncnetudp.nim +++ b/tests/async/tasyncnetudp.nim @@ -59,7 +59,7 @@ proc readMessages(server: AsyncSocket) {.async.} = while i < maxResponses: let (data, fromIp, fromPort) = await recvFrom(server, 16384) - if data.startswith("Message ") and fromIp == "127.0.0.1": + if data.startsWith("Message ") and fromIp == "127.0.0.1": await sendTo(server, fromIp, fromPort, data) inc(msgCount) diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index a582818eb..222aaa3a1 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -36,7 +36,7 @@ when defined(ssl): inc(clientCount) break else: - if line.startswith("Message "): + if line.startsWith("Message "): inc(msgCount) else: doAssert false diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim index 76462c21d..ba1e4134e 100644 --- a/tests/async/tnewasyncudp.nim +++ b/tests/async/tnewasyncudp.nim @@ -81,7 +81,7 @@ proc readMessages(server: AsyncFD) {.async.} = addr(slen)) size = 0 var grammString = $cstring(addr buffer) - if grammString.startswith("Message ") and + if grammString.startsWith("Message ") and saddr.sin_addr.s_addr == nativesockets.ntohl(INADDR_LOOPBACK.uint32): await sendTo(server, addr grammString[0], len(grammString), cast[ptr SockAddr](addr saddr), slen) diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim index 69b092607..ad27ca38f 100644 --- a/tests/async/twinasyncrw.nim +++ b/tests/async/twinasyncrw.nim @@ -220,7 +220,7 @@ when defined(windows): clientCount.inc break else: - if line.startswith("Message "): + if line.startsWith("Message "): msgCount.inc else: doAssert false diff --git a/tools/atlas/osutils.nim b/tools/atlas/osutils.nim index 1bb414c03..6134830b5 100644 --- a/tools/atlas/osutils.nim +++ b/tools/atlas/osutils.nim @@ -17,7 +17,7 @@ proc cloneUrl*(url, dest: string; cloneUsingHttps: bool): string = # github + https + trailing url slash causes a # checkout/ls-remote to fail with Repository not found var isGithub = false - if modUrl.contains("github.com") and modUrl.endswith("/"): + if modUrl.contains("github.com") and modUrl.endsWith("/"): modUrl = modUrl[0 .. ^2] isGithub = true diff --git a/tools/trimcc.nim b/tools/trimcc.nim index 959eaf310..41795e1aa 100644 --- a/tools/trimcc.nim +++ b/tools/trimcc.nim @@ -31,7 +31,7 @@ proc processIncludes(dir: string, whitelist: StringTableRef) = if ('.' notin name and "include" in path) or ("c++" in path): let n = whitelist.getOrDefault(name) if n != "processed": whitelist[name] = "found" - if name.endswith(".h"): + if name.endsWith(".h"): let n = whitelist.getOrDefault(name) if n == "found": includes(path, name, whitelist) of pcDir: processIncludes(path, whitelist) From 499d4690fbbb59b6baf1698b1ed1574dde6ea7c5 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Mon, 2 Aug 2021 00:38:15 -0700 Subject: [PATCH 2903/4254] Add Artix to distro list (#18629) --- lib/pure/distros.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index c1bc44eeb..7a9910c1e 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -52,6 +52,7 @@ type CentOS Deepin ArchLinux + Artix Antergos PCLinuxOS Mageia @@ -133,7 +134,7 @@ type const - LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, Distribution.ArchLinux} + LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, Distribution.ArchLinux, Distribution.Artix} # we cache the result of the 'cmdRelease' # execution for faster platform detections. @@ -180,6 +181,8 @@ proc detectOsImpl(d: Distribution): bool = result = "rhel" in osReleaseID() of Distribution.ArchLinux: result = "arch" in osReleaseID() + of Distribution.Artix: + result = "artix" in osReleaseID() of Distribution.NixOS: # Check if this is a Nix build or NixOS environment result = existsEnv("NIX_BUILD_TOP") or existsEnv("__NIXOS_SET_ENVIRONMENT_DONE") @@ -249,7 +252,7 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = result = ("pkg_add " & p, true) elif detectOs(PCLinuxOS): result = ("rpm -ivh " & p, true) - elif detectOs(ArchLinux) or detectOs(Manjaro): + elif detectOs(ArchLinux) or detectOs(Manjaro) or detectOs(Artix): result = ("pacman -S " & p, true) else: result = (" install " & p, true) From c0abdaa2b4587526f235ef41186e84c4f87813e1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 2 Aug 2021 22:22:47 -0700 Subject: [PATCH 2904/4254] improve runnableExamples and docs for std/nre (#18634) * improve runnableExamples and docs for std/nre * avoid too long lines in example --- lib/impure/nre.nim | 117 +++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 7b2d7d3ee..01ef77427 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -23,12 +23,12 @@ when defined(js): ## **Note**: If you love `sequtils.toSeq` we have bad news for you. This ## library doesn't work with it due to documented compiler limitations. As ## a workaround, use this: -## -## .. code-block:: nim -## -## import std/nre except toSeq -## -## +runnableExamples: + # either `import std/nre except toSeq` or fully qualify `sequtils.toSeq`: + import std/sequtils + iterator iota(n: int): int = + for i in 0..\w)").get.captures["letter"] == "a"` - ## - `"abc".match(re"(\w)\w").get.captures[-1] == "ab"` + ## `nil` is returned. See examples for `match`. ## ## `captureBounds[]: HSlice[int, int]` ## gets the bounds of the given capture according to the same rules as ## the above. If the capture is not filled, then `None` is returned. - ## The bounds are both inclusive. - ## - ## - `"abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0` - ## - `0 in "abc".match(re"(\w)").get.captureBounds == true` - ## - `"abc".match(re"").get.captureBounds[-1] == 0 .. -1` - ## - `"abc".match(re"abc").get.captureBounds[-1] == 0 .. 2` + ## The bounds are both inclusive. See examples for `match`. ## ## `match: string` ## the full text of the match. @@ -198,7 +184,6 @@ type pattern*: Regex ## The regex doing the matching. ## Not nil. str*: string ## The string that was matched against. - ## Not nil. pcreMatchBounds: seq[HSlice[cint, cint]] ## First item is the bounds of the match ## Other items are the captures ## `a` is inclusive start, `b` is exclusive end @@ -226,18 +211,6 @@ type ## for whatever reason. The message contains the error ## code. -runnableExamples: - # This MUST be kept in sync with the examples in RegexMatch - doAssert "abc".match(re"(\w)").get.captures[0] == "a" - doAssert "abc".match(re"(?\w)").get.captures["letter"] == "a" - doAssert "abc".match(re"(\w)\w").get.captures[-1] == "ab" - - doAssert "abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0 - doAssert 0 in "abc".match(re"(\w)").get.captureBounds == true - doAssert "abc".match(re"").get.captureBounds[-1] == 0 .. -1 - doAssert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2 - - proc destroyRegex(pattern: Regex) = pcre.free_substring(cast[cstring](pattern.pcreObj)) if pattern.pcreExtra != nil: @@ -540,18 +513,27 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] = ## Like `find(...)<#find,string,Regex,int>`_, but anchored to the start of the ## string. - ## runnableExamples: - doAssert "foo".match(re"f").isSome - doAssert "foo".match(re"o").isNone + assert "foo".match(re"f").isSome + assert "foo".match(re"o").isNone + assert "abc".match(re"(\w)").get.captures[0] == "a" + assert "abc".match(re"(?\w)").get.captures["letter"] == "a" + assert "abc".match(re"(\w)\w").get.captures[-1] == "ab" + + assert "abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0 + assert 0 in "abc".match(re"(\w)").get.captureBounds + assert "abc".match(re"").get.captureBounds[-1] == 0 .. -1 + assert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2 return str.matchImpl(pattern, start, endpos, pcre.ANCHORED) iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): RegexMatch = ## Works the same as `find(...)<#find,string,Regex,int>`_, but finds every - ## non-overlapping match. `"2222".find(re"22")` is `"22", "22"`, not - ## `"22", "22", "22"`. - ## + ## non-overlapping match: + runnableExamples: + import std/sugar + assert collect(for a in "2222".findIter(re"22"): a.match) == @["22", "22"] + # not @["22", "22", "22"] ## Arguments are the same as `find(...)<#find,string,Regex,int>`_ ## ## Variants: @@ -619,11 +601,10 @@ proc contains*(str: string, pattern: Regex, start = 0, endpos = int.high): bool ## Determine if the string contains the given pattern between the end and ## start positions: ## This function is equivalent to `isSome(str.find(pattern, start, endpos))`. - ## runnableExamples: - doAssert "abc".contains(re"bc") - doAssert not "abc".contains(re"cd") - doAssert not "abc".contains(re"a", start = 1) + assert "abc".contains(re"bc") + assert not "abc".contains(re"cd") + assert not "abc".contains(re"a", start = 1) return isSome(str.find(pattern, start, endpos)) @@ -635,16 +616,16 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] ## runnableExamples: # - If the match is zero-width, then the string is still split: - doAssert "123".split(re"") == @["1", "2", "3"] + assert "123".split(re"") == @["1", "2", "3"] # - If the pattern has a capture in it, it is added after the string # split: - doAssert "12".split(re"(\d)") == @["", "1", "", "2", ""] + assert "12".split(re"(\d)") == @["", "1", "", "2", ""] # - If `maxsplit != -1`, then the string will only be split # `maxsplit - 1` times. This means that there will be `maxsplit` # strings in the output seq. - doAssert "1.2.3".split(re"\.", maxsplit = 2) == @["1", "2.3"] + assert "1.2.3".split(re"\.", maxsplit = 2) == @["1", "2.3"] result = @[] var lastIdx = start @@ -747,9 +728,9 @@ proc escapeRe*(str: string): string {.gcsafe.} = ## ## Escaped char: `\ + * ? [ ^ ] $ ( ) { } = ! < > | : -` runnableExamples: - doAssert escapeRe("fly+wind") == "fly\\+wind" - doAssert escapeRe("!") == "\\!" - doAssert escapeRe("nim*") == "nim\\*" + assert escapeRe("fly+wind") == "fly\\+wind" + assert escapeRe("!") == "\\!" + assert escapeRe("nim*") == "nim\\*" #([\\+*?[^\]$(){}=!<>|:-]) const SpecialCharMatcher = {'\\', '+', '*', '?', '[', '^', ']', '$', '(', From 6563a685c1076cb5342f65d192b8f2a983220dba Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 3 Aug 2021 13:16:33 -0300 Subject: [PATCH 2905/4254] Documentation only, add 1 example (#18633) --- doc/manual_experimental.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 22db184a8..3272a4d0d 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1157,6 +1157,24 @@ the ordinary AST predicates: a = b inc a, c +Another example: + +.. code-block:: nim + proc somefunc(s: string) = assert s == "variable" + proc somefunc(s: string{nkStrLit}) = assert s == "literal" + proc somefunc(s: string{nkRStrLit}) = assert s == r"raw" + proc somefunc(s: string{nkTripleStrLit}) = assert s == """triple""" + proc somefunc(s: static[string]) = assert s == "constant" + + # Use parameter constraints to provide overloads based on both the input parameter type and form. + var variable = "variable" + somefunc(variable) + const constant = "constant" + somefunc(constant) + somefunc("literal") + somefunc(r"raw") + somefunc("""triple""") + Pattern operators ----------------- From 2cddf7fc96a01bcd0f6029f38de005314333daca Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 8 Aug 2021 14:26:34 -0300 Subject: [PATCH 2906/4254] Documentation only, add 1 example (#18621) * ReSync with Devel * ReSync * Documentation only, add 1 example to For loop macro * Flip it * Update doc/manual.rst Co-authored-by: Andreas Rumpf Co-authored-by: Andreas Rumpf --- doc/manual.rst | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 1b65ae9ee..41ed49715 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5830,6 +5830,27 @@ For loop macro A macro that takes as its only input parameter an expression of the special type `system.ForLoopStmt` can rewrite the entirety of a `for` loop: +.. code-block:: nim + :test: "nim c $1" + + import std/macros + + macro example(loop: ForLoopStmt) = + result = newTree(nnkForStmt) # Create a new For loop. + result.add loop[^3] # This is "item". + result.add loop[^2][^1] # This is "[1, 2, 3]". + result.add newCall(bindSym"echo", loop[0]) + + for item in example([1, 2, 3]): discard + +Expands to: + +.. code-block:: nim + for item in items([1, 2, 3]): + echo item + +Another example: + .. code-block:: nim :test: "nim c $1" @@ -5866,7 +5887,6 @@ type `system.ForLoopStmt` can rewrite the entirety of a `for` loop: echo a, " ", b - Special Types ============= From 9269a72f6f6f19e4bcffce82ad47c68755e7a696 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 9 Aug 2021 01:27:43 +0800 Subject: [PATCH 2907/4254] [nre]fix #17129 (#18632) * fix #17129 * correct * give reference implementaion links * add comment * typo * I'm conservative * change --- lib/impure/nre.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 01ef77427..f346d84cb 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -539,7 +539,7 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R ## Variants: ## ## - `proc findAll(...)` returns a `seq[string]` - # see pcredemo for explanation + # see pcredemo for explanation => https://www.pcre.org/original/doc/html/pcredemo.html let matchesCrLf = pattern.matchesCrLf() let unicode = uint32(getinfo[culong](pattern, pcre.INFO_OPTIONS) and pcre.UTF8) > 0u32 @@ -560,7 +560,7 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R # either the end of the input or the string # cannot be split here - we also need to bail # if we've never matched and we've already tried to... - if offset >= strlen or neverMatched: + if flags == 0 or offset >= strlen or neverMatched: # All matches found break if matchesCrLf and offset < (str.len - 1) and @@ -576,7 +576,6 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R else: neverMatched = false offset = match.get.matchBounds.b + 1 - yield match.get proc find*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] = From 24445d31b394a120a8571c0d9dc4ab07b7672cd7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 8 Aug 2021 10:28:49 -0700 Subject: [PATCH 2908/4254] improve several tests in testament (#18635) * silence error output from template_various.nim * any => auto in tests * avoid showing failed for parseSpec since this is expected behavior in 2 cases: tincludefile.nim, tnav1.nim * enforce InheritFromException * fixup --- testament/categories.nim | 2 +- tests/config.nims | 1 + tests/generics/mdotlookup.nim | 4 +- tests/iter/tyieldintry.nim | 60 +++++++++++++--------------- tests/overload/toverload_various.nim | 2 +- tests/template/template_various.nim | 6 ++- tests/template/tparams_gensymed.nim | 2 +- 7 files changed, 38 insertions(+), 39 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index b5e8a5454..6375105ee 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -588,7 +588,7 @@ proc runJoinedTest(r: var TResults, cat: Category, testsDir: string, options: st except ValueError: # e.g. for `tests/navigator/tincludefile.nim` which have multiple # specs; this will be handled elsewhere - echo "parseSpec failed for: '$1', assuming this will be handled outside of megatest" % file + echo "parseSpec raised ValueError for: '$1', assuming this will be handled outside of megatest" % file continue if isJoinableSpec(spec): specs.add spec diff --git a/tests/config.nims b/tests/config.nims index f876cb612..d7f6ae7f9 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -28,6 +28,7 @@ hint("Processing", off) # switch("define", "nimTestsEnableFlaky") # switch("hint", "ConvFromXtoItselfNotNeeded") +# switch("warningAsError", "InheritFromException") # would require fixing a few tests # experimental API's are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 # sync with `kochdocs.docDefines` or refactor. diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 470fa0a51..3112c133f 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -1,9 +1,9 @@ -proc baz(o: any): int = 5 # if bar is exported, it works +proc baz(o: auto): int = 5 # if bar is exported, it works type MyObj = object x: int -proc foo*(b: any) = +proc foo*(b: auto) = var o: MyObj echo b.baz, " ", o.x.baz, " ", b.baz() diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 3d5260800..9862fe1de 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -1,17 +1,15 @@ discard """ -targets: "c" -output: "ok" + targets: "c cpp" """ -var closureIterResult = newSeq[int]() -# XXX Investigate why this fails now for 'nim cpp' +var closureIterResult = newSeq[int]() proc checkpoint(arg: int) = closureIterResult.add(arg) type - TestException = object of Exception - AnotherException = object of Exception + TestError = object of CatchableError + AnotherError = object of CatchableError proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) = closureIterResult.setLen(0) @@ -21,7 +19,7 @@ proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedRe try: for i in it(): closureIterResult.add(i) - except TestException: + except TestError: exceptionCaught = true if closureIterResult != @expectedResults or exceptionCaught != exceptionExpected: @@ -39,8 +37,8 @@ proc test(it: iterator(): int, expectedResults: varargs[int]) = proc testExc(it: iterator(): int, expectedResults: varargs[int]) = testClosureIterAux(it, true, expectedResults) -proc raiseException() = - raise newException(TestException, "Test exception!") +proc raiseTestError() = + raise newException(TestError, "Test exception!") block: iterator it(): int {.closure.} = @@ -58,8 +56,8 @@ block: yield 0 try: checkpoint(1) - raiseException() - except TestException: + raiseTestError() + except TestError: checkpoint(2) yield 3 checkpoint(4) @@ -89,7 +87,7 @@ block: yield 0 try: yield 1 - raiseException() + raiseTestError() yield 2 finally: checkpoint(3) @@ -103,8 +101,8 @@ block: iterator it(): int {.closure.} = try: try: - raiseException() - except AnotherException: + raiseTestError() + except AnotherError: yield 123 finally: checkpoint(3) @@ -117,8 +115,8 @@ block: iterator it(): int {.closure.} = try: yield 1 - raiseException() - except AnotherException: + raiseTestError() + except AnotherError: checkpoint(123) finally: checkpoint(2) @@ -134,12 +132,12 @@ block: yield 1 try: yield 2 - raiseException() - except AnotherException: + raiseTestError() + except AnotherError: yield 123 finally: yield 3 - except AnotherException: + except AnotherError: yield 124 finally: yield 4 @@ -170,10 +168,10 @@ block: try: try: yield 0 - raiseException() + raiseTestError() finally: checkpoint(1) - except TestException: + except TestError: yield 2 return finally: @@ -188,10 +186,10 @@ block: try: try: yield 0 - raiseException() + raiseTestError() finally: return # Return in finally should stop exception propagation - except AnotherException: + except AnotherError: yield 2 return finally: @@ -228,9 +226,9 @@ block: var foo = 123 let i = try: yield 0 - raiseException() + raiseTestError() 1 - except TestException as e: + except TestError as e: assert(e.msg == "Test exception!") case foo of 1: @@ -262,9 +260,9 @@ block: template tryexcept: int = try: yield 1 - raiseException() + raiseTestError() 123 - except TestException: + except TestError: yield 2 checkpoint(3) 4 @@ -323,11 +321,11 @@ block: for i in 0 .. 1: try: yield 1 - raiseException() - except TestException as e: + raiseTestError() + except TestError as e: doAssert(e.msg == "Test exception!") yield 2 - except AnotherException: + except AnotherError: yield 123 except: yield 1234 @@ -497,5 +495,3 @@ block: #17849 - yield in case subject yield 5 test(it, 1, 2, 13, 5) - -echo "ok" diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index f913ce3ee..55a8d17e6 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -395,7 +395,7 @@ block: template bar2[F,T](x: FooUn[F,T]): int = 1 template bar2[F,T1,T2](x: FooBi[F,T1,T2]): int = 2 - proc test(x: any, n: int) = + proc test(x: auto, n: int) = doAssert(foo1(x) == n) doAssert(foo2(x) == n) doAssert(bar1(x) == n) diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim index 75226ea2d..e7a2be748 100644 --- a/tests/template/template_various.nim +++ b/tests/template/template_various.nim @@ -94,7 +94,7 @@ block generic_templates: var i3: int = t1[int]("xx") - +from strutils import contains block tgetast_typeliar: proc error(s: string) = quit s @@ -111,7 +111,9 @@ block tgetast_typeliar: var message : NimNode = newLit(condition.repr) # echo message result = getAst assertOrReturn2(condition, message) - echo result.repr + # echo result.repr + let s = result.repr + doAssert """error("Assertion failed:""" in s proc point(size: int16): tuple[x, y: int16] = # returns random point in square area with given `size` diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index 1444667f4..b68d7e253 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -72,7 +72,7 @@ proc concreteProc(x: int) = forStatic i, 0..3: echo i -proc genericProc(x: any) = +proc genericProc(x: auto) = forStatic i, 0..3: echo i From eb19db6595846c92e5eb999d96605fe4bb0934f7 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Sun, 8 Aug 2021 10:30:51 -0700 Subject: [PATCH 2909/4254] Nim pretty and add void (#18652) * pretty and add void * distro fixup * Update lib/pure/distros.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * tab to space * requested change to be cleaner Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/distros.nim | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 7a9910c1e..ddf0fd30c 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -109,7 +109,7 @@ type Clonezilla SteamOS Absolute - NixOS ## NixOS or a Nix build environment + NixOS ## NixOS or a Nix build environment AUSTRUMI Arya Porteus @@ -124,6 +124,7 @@ type ExTiX Rockstor GoboLinux + Void BSD FreeBSD @@ -134,7 +135,9 @@ type const - LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, Distribution.ArchLinux, Distribution.Artix} + LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, + Distribution.ArchLinux, Distribution.Artix, Distribution.Antergos, + Distribution.BlackArch, Distribution.ArchBang} # we cache the result of the 'cmdRelease' # execution for faster platform detections. @@ -153,7 +156,8 @@ template hostnamectl(): untyped = cmdRelease("hostnamectl", hostnamectlRes) proc detectOsWithAllCmd(d: Distribution): bool = let dd = toLowerAscii($d) result = dd in toLowerAscii(osReleaseID()) or dd in toLowerAscii(release()) or - dd in toLowerAscii(uname()) or ("operating system: " & dd) in toLowerAscii(hostnamectl()) + dd in toLowerAscii(uname()) or ("operating system: " & dd) in + toLowerAscii(hostnamectl()) proc detectOsImpl(d: Distribution): bool = case d @@ -173,9 +177,9 @@ proc detectOsImpl(d: Distribution): bool = case d of Distribution.Gentoo: result = ("-" & $d & " ") in uname() - of Distribution.Elementary, Distribution.Ubuntu, Distribution.Debian, Distribution.Fedora, - Distribution.OpenMandriva, Distribution.CentOS, Distribution.Alpine, - Distribution.Mageia, Distribution.Zorin: + of Distribution.Elementary, Distribution.Ubuntu, Distribution.Debian, + Distribution.Fedora, Distribution.OpenMandriva, Distribution.CentOS, + Distribution.Alpine, Distribution.Mageia, Distribution.Zorin, Distribution.Void: result = toLowerAscii($d) in osReleaseID() of Distribution.RedHat: result = "rhel" in osReleaseID() @@ -254,6 +258,8 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = result = ("rpm -ivh " & p, true) elif detectOs(ArchLinux) or detectOs(Manjaro) or detectOs(Artix): result = ("pacman -S " & p, true) + elif detectOs(Void): + result = ("xbps-install " & p, true) else: result = (" install " & p, true) elif defined(haiku): From 0d3af5454b66dfe4a8a7017030708a890207c658 Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Sun, 8 Aug 2021 20:11:07 +0200 Subject: [PATCH 2910/4254] Only allow IPv4 literals in strict form (#18656) * Only allow IPv4 literals in strict form The strict form as defined in RFC 6943, section 3.1.1 only allows the dotted form ddd.ddd.ddd.ddd of IPv4 literals, where ddd is a one to three digit decimal number between 0 and 255. Until now octal numbers (with a leading zero) were interpreted as decimal numbers which has security implications, see CVE-2021-29922 and CVE-2021-29923. * Update lib/pure/net.nim Co-authored-by: Dominik Picheta --- lib/pure/net.nim | 25 +++++++++-- tests/stdlib/tnet.nim | 35 +++++++++++++++ tests/stdlib/tparseipv6.nim | 90 ++++++++++++++++++++----------------- 3 files changed, 106 insertions(+), 44 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c0f9e1465..09cdc8afb 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -281,14 +281,20 @@ proc parseIPv4Address(addressStr: string): IpAddress = byteCount = 0 currentByte: uint16 = 0 separatorValid = false + leadingZero = false result = IpAddress(family: IpAddressFamily.IPv4) for i in 0 .. high(addressStr): if addressStr[i] in strutils.Digits: # Character is a number + if leadingZero: + raise newException(ValueError, + "Invalid IP address. Octal numbers are not allowed") currentByte = currentByte * 10 + cast[uint16](ord(addressStr[i]) - ord('0')) - if currentByte > 255'u16: + if currentByte == 0'u16: + leadingZero = true + elif currentByte > 255'u16: raise newException(ValueError, "Invalid IP Address. Value is out of range") separatorValid = true @@ -300,6 +306,7 @@ proc parseIPv4Address(addressStr: string): IpAddress = currentByte = 0 byteCount.inc separatorValid = false + leadingZero = false else: raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") @@ -388,10 +395,16 @@ proc parseIPv6Address(addressStr: string): IpAddress = result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) groupCount.inc() else: # Must parse IPv4 address + var leadingZero = false for i, c in addressStr[v4StartPos..high(addressStr)]: if c in strutils.Digits: # Character is a number + if leadingZero: + raise newException(ValueError, + "Invalid IP address. Octal numbers not allowed") currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) - if currentShort > 255'u32: + if currentShort == 0'u32: + leadingZero = true + elif currentShort > 255'u32: raise newException(ValueError, "Invalid IP Address. Value is out of range") separatorValid = true @@ -402,6 +415,7 @@ proc parseIPv6Address(addressStr: string): IpAddress = currentShort = 0 byteCount.inc() separatorValid = false + leadingZero = false else: # Invalid character raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") @@ -431,7 +445,12 @@ proc parseIPv6Address(addressStr: string): IpAddress = proc parseIpAddress*(addressStr: string): IpAddress = ## Parses an IP address - ## Raises ValueError on error + ## + ## Raises ValueError on error. + ## + ## For IPv4 addresses, only the strict form as + ## defined in RFC 6943 is considered valid, see + ## https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1. if addressStr.len == 0: raise newException(ValueError, "IP Address string is empty") if addressStr.contains(':'): diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index b19d31f6c..671e0f7bc 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -50,6 +50,41 @@ block: # parseIpAddress tests expect(ValueError): discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") + block: # ipv4-compatible ipv6 address (embedded ipv4 address) + check parseIpAddress("::ffff:10.0.0.23") == parseIpAddress("::ffff:0a00:0017") + + block: # octal number in ipv4 address + expect(ValueError): + discard parseIpAddress("010.8.8.8") + expect(ValueError): + discard parseIpAddress("8.010.8.8") + + block: # hexadecimal number in ipv4 address + expect(ValueError): + discard parseIpAddress("0xc0.168.0.1") + expect(ValueError): + discard parseIpAddress("192.0xa8.0.1") + + block: # less than 4 numbers in ipv4 address + expect(ValueError): + discard parseIpAddress("127.0.1") + + block: # octal number in embedded ipv4 address + expect(ValueError): + discard parseIpAddress("::ffff:010.8.8.8") + expect(ValueError): + discard parseIpAddress("::ffff:8.010.8.8") + + block: # hexadecimal number in embedded ipv4 address + expect(ValueError): + discard parseIpAddress("::ffff:0xc0.168.0.1") + expect(ValueError): + discard parseIpAddress("::ffff:192.0xa8.0.1") + + block: # less than 4 numbers in embedded ipv4 address + expect(ValueError): + discard parseIpAddress("::ffff:127.0.1") + block: # "IpAddress/Sockaddr conversion" proc test(ipaddrstr: string) = var ipaddr_1 = parseIpAddress(ipaddrstr) diff --git a/tests/stdlib/tparseipv6.nim b/tests/stdlib/tparseipv6.nim index 3e1c23e58..dd9abc511 100644 --- a/tests/stdlib/tparseipv6.nim +++ b/tests/stdlib/tparseipv6.nim @@ -8,23 +8,23 @@ const positives = [ "::f:8:a8f:218.17.235.229", "::b:228.19.241.2", - "::8:c:a:f:8.35.8.096", - "::3:e:a:bc:04.19.2.9", + "::8:c:a:f:8.35.8.96", + "::3:e:a:bc:4.19.2.9", "::2:212.242.248.19", "::df:a5f:3.250.208.9", "::8:c:5:e63:250.208.249.0", "::b:f:181.12.9.98", - "::a:f8:77.08.243.232", - "::a:b:85:e4d9:252.9.229.056", + "::a:f8:77.8.243.232", + "::a:b:85:e4d9:252.9.229.56", "941:c:8a:c:e::917", "e8:7a:e:ad:88a:8:203.235.225.46", - "139c:9e::f8:254.08.21.249", + "139c:9e::f8:254.8.21.249", "b38:f0:e::f9:89.6.12.18", "ef::8", "5::ab", "a::8:255.247.96.253", "b:c0::c:254.248.95.254", - "::8c:2:99.251.024.3", + "::8c:2:99.251.24.3", "98::c:247.240.249.57", "9::9", "628::f1ed:f", @@ -106,68 +106,68 @@ const "::315", "::a:a", "::aed3:a", - "f0eb:0:e8:b:c:a:254.098.233.17", + "f0eb:0:e8:b:c:a:254.98.233.17", "bfa:7fc:c66d:15:e9a:ded:254.119.9.9", - "d:ffa8:9:a:879:3:202.39.08.245", + "d:ffa8:9:a:879:3:202.39.8.245", "8e:2:8:fa8a:f1d1:1aa8:252.254.245.81", - "5:d4:a:e9:8:8:06.38.98.253", - "9c5:4:a5c:f:a6:8c9d:05.250.8.2", + "5:d4:a:e9:8:8:6.38.98.253", + "9c5:4:a5c:f:a6:8c9d:5.250.8.2", "d19a:2:f808:be:f:c:98.86.197.249", - "8:26ac:8:8:cb:f:242.00.254.85", + "8:26ac:8:8:cb:f:242.0.254.85", "38:e:1:0b88:f:0:8.89.248.92", - "e7:ff96:a:f:f:b:253.91.052.195", + "e7:ff96:a:f:f:b:253.91.52.195", "d:8:2:5:894:5:254.0.240.199", "2:98:9:8aa:9c8f:fa:252.98.248.17", - "e9:d4f:890:ccbe:5:8:088.200.228.216", + "e9:d4f:890:ccbe:5:8:88.200.228.216", "3:3:9:5:6a:df5:255.251.8.12", - "0280:3:8:8:4:9:255.000.251.249", + "0280:3:8:8:4:9:255.0.251.249", "8:af7:db:aa:0:9:238.248.250.255", - "ff:ee:9a:9252:a:289:059.083.18.255", + "ff:ee:9a:9252:a:289:59.83.18.255", "9f6:5:fc9:b:a89:a:142.1.250.254", "e:981a:da:bf94:9:f8:254.242.18.95", "3c:1:4:f2:89:f:8.91.255.14", - "e::9a2:c:9.050.80.8", + "e::9a2:c:9.50.80.8", "9::4a:07:fb:211.241.254.228", "9be::2:e:215.189.48.188", - "f::f:d:069.148.99.168", + "f::f:d:69.148.99.168", "f::a:97.18.240.47", "c::a98e:1:251.253.252.254", "668::82:214.87.208.9", "9c0::cf0:ecb:253.208.238.255", - "a::0:f1:210.240.238.049", - "8::a:1:251.238.34.09", + "a::0:f1:210.240.238.49", + "8::a:1:251.238.34.9", "81:dfe::b8:8.255.249.248", - "d3::7:b:9:83.189.08.244", - "8::9:8:8:00.7.11.252", + "d3::7:b:9:83.189.8.244", + "8::9:8:8:0.7.11.252", "2:8::c:a8:250.221.9.249", "2::f:99.8.249.247", "c:22f5::5:2c:243.15.79.89", "e:8e::da:251.243.255.2", "f15f:9::a:255.70.247.218", - "f:b::9f38:31.220.94.022", - "9::9a48:03.98.249.119", + "f:b::9f38:31.220.94.22", + "9::9a48:3.98.249.119", "d:d:9b87::2d:a:249.253.38.8", "d86d:99b::a9b:5:242.236.8.244", "eb:3::f:9cf:1.253.1.228", "b::ba2:255.247.114.64", - "2f:ec:bcb::9:219.254.250.094", + "2f:ec:bcb::9:219.254.250.94", "da8a:f6::a:e0:19.251.241.251", - "5e:c1::a:021.250.8.254", + "5e:c1::a:21.250.8.254", "c:9::8c9b:248.219.212.252", "2:a::8d4a:216.255.198.223", - "1f::66:255.30.08.150", + "1f::66:255.30.8.150", "bc2b:8f::2ff9:6.245.99.230", "a:8::a8:9.251.246.255", - "f:7:7::98:06.14.1.208", + "f:7:7::98:6.14.1.208", "e:2::9:218.249.255.254", "79:f::6:250.255.98.246", - "47:9:fb9f::9:038.136.17.251", + "47:9:fb9f::9:38.136.17.251", "ed::a:247.9.23.239", "6f::f1:88.254.119.9", "a::d:218.199.236.0", - "fc88::9:203.196.04.95", - "::8.048.255.85", - "::253.07.255.36", + "fc88::9:203.196.4.95", + "::8.48.255.85", + "::253.7.255.36", "9:d::253.7.178.229", "::250.84.158.253", "::8.55.204.248", @@ -175,31 +175,39 @@ const "df9:88ca::248.255.108.17", "8e9b::250.206.0.82", "::209.8.254.209", - "::247.088.8.8", + "::247.88.8.8", "::cb:f:ba41:250.208.19.249", "::fe:0e8:243.240.229.5", "::c:223.251.5.226", - "::8:08.03.8.250", + "::8:8.3.8.250", "::f:8.88.11.255", - "::fda:48:aa:05.189.07.2", - "::8:c3f:f:240.06.212.255", + "::fda:48:aa:5.189.7.2", + "::8:c3f:f:240.6.212.255", "::f:0aa:244.123.99.16", - "::c9b5:c:034.8.090.196", + "::c9b5:c:34.8.90.196", "::98:c9:254.14.241.81" ] negatives = ["foo.bar", "::::::::::::", "yet another failure", - "de:6:c:ab5:6a::9:252.06.06.249", - "f9:5f7:fa38:9:b::b6:09.255.248.252", + "de:6:c:ab5:6a::9:252.6.6.249", + "f9:5f7:fa38:9:b::b6:9.255.248.252", "97:c:5b:81:8a::f5dd:144.252.250.9", - "9:8:cd:8:a9::f:247.255.09.255", + "9:8:cd:8:a9::f:247.255.9.255", "18:1:8c:2:3::9:8.254.252.139", - "e:c298:3:e:a::bb12:254.246.05.250", + "e:c298:3:e:a::bb12:254.246.5.250", "e:e:c:8e:fd::8:253.8.49.231", "9:97f:f:e929:8a::c9:0.8.252.10", - "0df:b24:7:89:c::2b:16.249.240.092", + "0df:b24:7:89:c::2b:16.249.240.92", "b:8f5f:485:c:9a::84c:178.7.249.34", + "::3:e:a:bc:091.19.2.9", + "::a:f8:77.08.243.232", + "::8c:2:99.251.029.3", + "::8:c:a:f:8.35.8.096", + "d:ffa8:9:a:879:3:0202.39.8.245", + "139c:9e::f8:254.07.21.249", + "f0eb:0:e8:b:c:a:254.233.043.17", + "::a:b:85:e4d9:252.9.229.056", ] proc ok(pos: openarray[string]) = From a7e622267e1049a454f4f522c0dbce5eb4017495 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 9 Aug 2021 02:44:14 +0800 Subject: [PATCH 2911/4254] use lent (#18638) --- lib/system/excpt.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 4814b77b4..3e520570f 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -521,10 +521,10 @@ proc getStackTrace(e: ref Exception): string = else: result = "" -proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = +proc getStackTraceEntries*(e: ref Exception): lent seq[StackTraceEntry] = ## Returns the attached stack trace to the exception `e` as ## a `seq`. This is not yet available for the JS backend. - shallowCopy(result, e.trace) + e.trace proc getStackTraceEntries*(): seq[StackTraceEntry] = ## Returns the stack trace entries for the current stack trace. From 988c02b7cbef634523b87af04097d06ed453dd61 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 8 Aug 2021 19:24:45 -0700 Subject: [PATCH 2912/4254] renamed: lib/std/private/vmutils.nim -> lib/std/private/bitops_utils.nim to avoid confusion with unrelated std/vmutils (#18660) --- lib/pure/bitops.nim | 4 +--- lib/std/private/{vmutils.nim => bitops_utils.nim} | 0 lib/system/countbits_impl.nim | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) rename lib/std/private/{vmutils.nim => bitops_utils.nim} (100%) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 6d3865e5d..1b3838621 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -27,9 +27,7 @@ import macros import std/private/since -from std/private/vmutils import forwardImpl, toUnsigned - - +from std/private/bitops_utils import forwardImpl, toUnsigned func bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI".} ## Computes the `bitwise complement` of the integer `x`. diff --git a/lib/std/private/vmutils.nim b/lib/std/private/bitops_utils.nim similarity index 100% rename from lib/std/private/vmutils.nim rename to lib/std/private/bitops_utils.nim diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim index 184f97bd4..020423e01 100644 --- a/lib/system/countbits_impl.nim +++ b/lib/system/countbits_impl.nim @@ -9,7 +9,7 @@ ## Contains the used algorithms for counting bits. -from std/private/vmutils import forwardImpl, toUnsigned +from std/private/bitops_utils import forwardImpl, toUnsigned const useBuiltins* = not defined(noIntrinsicsBitOpts) From 8ce782d463b0bca091be5a34db190dc441c23ce4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 8 Aug 2021 23:51:39 -0700 Subject: [PATCH 2913/4254] Add optional recursive arg to distinctBase (v2) (#18659) * Add optional recursive arg to distinctBase * Add docs and examples Co-authored-by: ALANVF --- compiler/semmagic.nim | 5 +++-- lib/pure/typetraits.nim | 17 ++++++++++++----- lib/std/jsonutils.nim | 4 ++-- lib/system/repr_v2.nim | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 04f4c4729..87f7da815 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -190,9 +190,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) result = newIntNodeT(toInt128(operand.len), traitCall, c.idgen, c.graph) of "distinctBase": var arg = operand.skipTypes({tyGenericInst}) + let rec = semConstExpr(c, traitCall[2]).intVal != 0 while arg.kind == tyDistinct: - arg = arg.base - arg = arg.skipTypes(skippedTypes + {tyGenericInst}) + arg = arg.base.skipTypes(skippedTypes + {tyGenericInst}) + if not rec: break result = getTypeDescNode(c, arg, operand.owner, traitCall.info) else: localError(c.config, traitCall.info, "unknown trait: " & s) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index e63585f63..8dc1b8cf2 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -110,25 +110,32 @@ template pointerBase*[T](_: typedesc[ptr T | ref T]): typedesc = assert (var s = "abc"; s[0].addr).typeof.pointerBase is char T -proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} = +proc distinctBase*(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} = ## Returns the base type for distinct types, or the type itself otherwise. + ## If `recursive` is false, only the immediate distinct base will be returned. ## ## **See also:** - ## * `distinctBase template <#distinctBase.t,T>`_ + ## * `distinctBase template <#distinctBase.t,T,static[bool]>`_ runnableExamples: type MyInt = distinct int + type MyOtherInt = distinct MyInt doAssert distinctBase(MyInt) is int + doAssert distinctBase(MyOtherInt) is int + doAssert distinctBase(MyOtherInt, false) is MyInt doAssert distinctBase(int) is int since (1, 1): - template distinctBase*[T](a: T): untyped = - ## Overload of `distinctBase <#distinctBase,typedesc>`_ for values. + template distinctBase*[T](a: T, recursive: static bool = true): untyped = + ## Overload of `distinctBase <#distinctBase,typedesc,static[bool]>`_ for values. runnableExamples: type MyInt = distinct int + type MyOtherInt = distinct MyInt doAssert 12.MyInt.distinctBase == 12 + doAssert 12.MyOtherInt.distinctBase == 12 + doAssert 12.MyOtherInt.distinctBase(false) is MyInt doAssert 12.distinctBase == 12 when T is distinct: - distinctBase(typeof(a))(a) + distinctBase(typeof(a), recursive)(a) else: # avoids hint ConvFromXtoItselfNotNeeded a diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index c141985d3..727a75288 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -78,8 +78,8 @@ proc initToJsonOptions*(): ToJsonOptions = ## initializes `ToJsonOptions` with sane options. ToJsonOptions(enumMode: joptEnumOrd, jsonNodeMode: joptJsonNodeAsRef) -proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} -template distinctBase[T](a: T): untyped = distinctBase(typeof(a))(a) +proc distinctBase(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} +template distinctBase[T](a: T, recursive: static bool = true): untyped = distinctBase(typeof(a), recursive)(a) macro getDiscriminants(a: typedesc): seq[string] = ## return the discriminant keys diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 8471ea148..f99f09799 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -1,7 +1,7 @@ proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} ## imported from typetraits -proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} +proc distinctBase(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} ## imported from typetraits proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.} From 31fc0f97187cef472cf113629a90c7aa126d3693 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Tue, 10 Aug 2021 16:26:42 -0700 Subject: [PATCH 2914/4254] Remove unused imports, and deprecated function usage (#18663) * clean up imports and slice to remove delete * revert buggy code * Replace "delete" with setlen to remove depreciation warning --- compiler/docgen.nim | 4 ++-- compiler/jsgen.nim | 2 +- tools/atlas/atlas.nim | 2 +- tools/atlas/packagesjson.nim | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 3bc01bbe6..d39a20aae 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -835,7 +835,7 @@ proc docstringSummary(rstText: string): string = result = rstText.substr(2).strip var pos = result.find('\L') if pos > 0: - result.delete(pos, result.len - 1) + result.setLen(pos - 1) result.add("…") if pos < maxDocstringChars: return @@ -843,7 +843,7 @@ proc docstringSummary(rstText: string): string = pos = result.find({'.', ',', ':'}) let last = result.len - 1 if pos > 0 and pos < last: - result.delete(pos, last) + result.setLen(pos - 1) result.add("…") proc genDeprecationMsg(d: PDoc, n: PNode): string = diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 85947535e..49a57b4a6 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -29,7 +29,7 @@ implements the required case distinction. import - ast, astalgo, trees, magicsys, options, + ast, trees, magicsys, options, nversion, msgs, idents, types, ropes, passes, ccgutils, wordrecg, renderer, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index d0990c1f7..761ca5db8 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -9,7 +9,7 @@ ## Simple tool to automate frequent workflows: Can "clone" ## a Nimble dependency and its dependencies recursively. -import std/[parseopt, strutils, os, osproc, sequtils, unicode, tables, sets] +import std/[parseopt, strutils, os, osproc, unicode, tables, sets] import parse_requires, osutils, packagesjson const diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim index ed83ce85c..0b8599769 100644 --- a/tools/atlas/packagesjson.nim +++ b/tools/atlas/packagesjson.nim @@ -1,6 +1,5 @@ import std / [json, os, sets, strutils] -import osutils type Package* = ref object From d0dd923acf8c2ddfa5e0ea7574c8d5200416e9f5 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Wed, 11 Aug 2021 08:54:49 +0200 Subject: [PATCH 2915/4254] Switch maintanance (#18668) * Fix and improve Nintendo Switch support * Document the necessity for nimAllocPagesViaMalloc * update changelog * Use --gc:orc in examples --- changelog.md | 3 + doc/nimc.rst | 21 ++--- lib/nintendoswitch/switch_memory.nim | 36 --------- lib/pure/os.nim | 9 +-- lib/system/osalloc.nim | 111 --------------------------- 5 files changed, 15 insertions(+), 165 deletions(-) delete mode 100644 lib/nintendoswitch/switch_memory.nim diff --git a/changelog.md b/changelog.md index a19697c8c..0e3c54d77 100644 --- a/changelog.md +++ b/changelog.md @@ -104,6 +104,8 @@ - In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. +- The allocator for Nintendo Switch, which was nonfunctional because + of breaking changes in libnx, was removed, in favour of the new `-d:nimAllocPagesViaMalloc` option. ## Standard library additions and changes @@ -363,6 +365,7 @@ - Added `dom.setInterval`, `dom.clearInterval` overloads. +- Allow reading parameters when compiling for Nintendo Switch. - Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect if the slice is out of bounds, likewise with `strutils.delete`. diff --git a/doc/nimc.rst b/doc/nimc.rst index ed9077912..ad5ecaa76 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -406,16 +406,18 @@ to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option: and `passL`:option: command line switches to something like: .. code-block:: cmd - nim c ... --passC="-I$DEVKITPRO/libnx/include" ... + nim c ... --d:nimAllocPagesViaMalloc --gc:orc --passC="-I$DEVKITPRO/libnx/include" ... --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" or setup a ``nim.cfg`` file like so:: #nim.cfg + --gc:orc + --d:nimAllocPagesViaMalloc --passC="-I$DEVKITPRO/libnx/include" --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" -The DevkitPro setup must be the same as the default with their new installer +The devkitPro setup must be the same as the default with their new installer `here for Mac/Linux `_ or `here for Windows `_. @@ -426,20 +428,19 @@ For example, with the above-mentioned config: nim c --os:nintendoswitch switchhomebrew.nim This will generate a file called ``switchhomebrew.elf`` which can then be turned into -an nro file with the `elf2nro`:cmd: tool in the DevkitPro release. Examples can be found at +an nro file with the `elf2nro`:cmd: tool in the devkitPro release. Examples can be found at `the nim-libnx github repo `_. -There are a few things that don't work because the DevkitPro libraries don't support them. +There are a few things that don't work because the devkitPro libraries don't support them. They are: 1. Waiting for a subprocess to finish. A subprocess can be started, but right now it can't be waited on, which sort of makes subprocesses a bit hard to use -2. Dynamic calls. DevkitPro libraries have no dlopen/dlclose functions. -3. Command line parameters. It doesn't make sense to have these for a console - anyways, so no big deal here. -4. mqueue. Sadly there are no mqueue headers. -5. ucontext. No headers for these either. No coroutines for now :( -6. nl_types. No headers for this. +2. Dynamic calls. Switch OS (Horizon) doesn't support dynamic libraries, so dlopen/dlclose are not available. +3. mqueue. Sadly there are no mqueue headers. +4. ucontext. No headers for these either. No coroutines for now :( +5. nl_types. No headers for this. +6. As mmap is not supported, the nimAllocPagesViaMalloc option has to be used. DLL generation ============== diff --git a/lib/nintendoswitch/switch_memory.nim b/lib/nintendoswitch/switch_memory.nim deleted file mode 100644 index f34bd363a..000000000 --- a/lib/nintendoswitch/switch_memory.nim +++ /dev/null @@ -1,36 +0,0 @@ -## All of these library headers and source can be found in the github repo -## https://github.com/switchbrew/libnx. - -const virtMemHeader = "" -const svcHeader = "" -const mallocHeader = "" - -## Aligns a block of memory with request `size` to `bytes` size. For -## example, a request of memalign(0x1000, 0x1001) == 0x2000 bytes allocated -proc memalign*(bytes: csize, size: csize): pointer {.importc: "memalign", - header: mallocHeader.} - -# Should be required, but not needed now because of how -# svcUnmapMemory frees all memory -#proc free*(address: pointer) {.importc: "free", -# header: mallocHeader.} - -## Maps a memaligned block of memory from `src_addr` to `dst_addr`. The -## Nintendo Switch requires this call in order to make use of memory, otherwise -## an invalid memory access occurs. -proc svcMapMemory*(dst_addr: pointer; src_addr: pointer; size: uint64): uint32 {. - importc: "svcMapMemory", header: svcHeader.} - -## Unmaps (frees) all memory from both `dst_addr` and `src_addr`. **Must** be called -## whenever svcMapMemory is used. The Switch will expect all memory to be allocated -## before gfxExit() calls () -proc svcUnmapMemory*(dst_addr: pointer; src_addr: pointer; size: uint64): uint32 {. - importc: "svcUnmapMemory", header: svcHeader.} - -proc virtmemReserveMap*(size: csize): pointer {.importc: "virtmemReserveMap", - header: virtMemHeader.} - -# Should be required, but not needed now because of how -# svcUnmapMemory frees all memory -#proc virtmemFreeMap*(address: pointer; size: csize) {.importc: "virtmemFreeMap", -# header: virtMemHeader.} diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 73e3fcb31..fd618e93c 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2910,13 +2910,6 @@ elif defined(nodejs): result = $argv[i] else: raise newException(IndexDefect, formatErrorIndexBound(i - 1, argv.len - 2)) -elif defined(nintendoswitch): - proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = - raise newException(OSError, "paramStr is not implemented on Nintendo Switch") - - proc paramCount*(): int {.tags: [ReadIOEffect].} = - raise newException(OSError, "paramCount is not implemented on Nintendo Switch") - elif defined(windows): # Since we support GUI applications with Nim, we sometimes generate # a WinMain entry proc. But a WinMain proc has no access to the parsed @@ -3190,7 +3183,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW result = getApplAux("/proc/self/exe") elif defined(solaris): result = getApplAux("/proc/" & $getpid() & "/path/a.out") - elif defined(genode) or defined(nintendoswitch): + elif defined(genode): raiseOSError(OSErrorCode(-1), "POSIX command line not supported") elif defined(freebsd) or defined(dragonfly) or defined(netbsd): result = getApplFreebsd() diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 2830adb48..39bf65d6c 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -103,117 +103,6 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): elif defined(genode) and not defined(StandaloneHeapSize): include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages -elif defined(nintendoswitch) and not defined(StandaloneHeapSize): - - import nintendoswitch/switch_memory - - type - PSwitchBlock = ptr NSwitchBlock - ## This will hold the heap pointer data in a separate - ## block of memory that is PageSize bytes above - ## the requested memory. It's the only good way - ## to pass around data with heap allocations - NSwitchBlock {.pure, inheritable.} = object - realSize: int - heap: pointer # pointer to main heap alloc - heapMirror: pointer # pointer to virtmem mapped heap - - proc alignSize(size: int): int {.inline.} = - ## Align a size integer to be in multiples of PageSize - ## The nintendo switch will not allocate memory that is not - ## aligned to 0x1000 bytes and will just crash. - (size + (PageSize - 1)) and not (PageSize - 1) - - proc deallocate(heapMirror: pointer, heap: pointer, size: int) = - # Unmap the allocated memory - discard svcUnmapMemory(heapMirror, heap, size.uint64) - # These should be called (theoretically), but referencing them crashes the switch. - # The above call seems to free all heap memory, so these are not needed. - # virtmemFreeMap(nswitchBlock.heapMirror, nswitchBlock.realSize.csize) - # free(nswitchBlock.heap) - - proc freeMem(p: pointer) = - # Retrieve the switch block data from the pointer we set before - # The data is located just sizeof(NSwitchBlock) bytes below - # the top of the pointer to the heap - let - nswitchDescrPos = cast[ByteAddress](p) -% sizeof(NSwitchBlock) - nswitchBlock = cast[PSwitchBlock](nswitchDescrPos) - - deallocate( - nswitchBlock.heapMirror, nswitchBlock.heap, nswitchBlock.realSize - ) - - proc storeHeapData(address, heapMirror, heap: pointer, size: int) {.inline.} = - ## Store data in the heap for deallocation purposes later - - # the position of our heap pointer data. Since we allocated PageSize extra - # bytes, we should have a buffer on top of the requested size of at least - # PageSize bytes, which is much larger than sizeof(NSwitchBlock). So we - # decrement the address by sizeof(NSwitchBlock) and use that address - # to store our pointer data - let nswitchBlockPos = cast[ByteAddress](address) -% sizeof(NSwitchBlock) - - # We need to store this in a pointer obj (PSwitchBlock) so that the data sticks - # at the address we've chosen. If NSwitchBlock is used here, the data will - # be all 0 when we try to retrieve it later. - var nswitchBlock = cast[PSwitchBlock](nswitchBlockPos) - nswitchBlock.realSize = size - nswitchBlock.heap = heap - nswitchBlock.heapMirror = heapMirror - - proc getOriginalHeapPosition(address: pointer, difference: int): pointer {.inline.} = - ## This function sets the heap back to the originally requested - ## size - let - pos = cast[int](address) - newPos = cast[ByteAddress](pos) +% difference - - return cast[pointer](newPos) - - template allocPages(size: int, outOfMemoryStmt: untyped): untyped = - # This is to ensure we get a block of memory the requested - # size, as well as space to store our structure - let realSize = alignSize(size + sizeof(NSwitchBlock)) - - let heap = memalign(PageSize, realSize) - - if heap.isNil: - outOfMemoryStmt - - let heapMirror = virtmemReserveMap(realSize.csize) - result = heapMirror - - let rc = svcMapMemory(heapMirror, heap, realSize.uint64) - # Any return code not equal 0 means an error in libnx - if rc.uint32 != 0: - deallocate(heapMirror, heap, realSize) - outOfMemoryStmt - - # set result to be the original size requirement - result = getOriginalHeapPosition(result, realSize - size) - - storeHeapData(result, heapMirror, heap, realSize) - - proc osAllocPages(size: int): pointer {.inline.} = - allocPages(size): - raiseOutOfMem() - - proc osTryAllocPages(size: int): pointer = - allocPages(size): - return nil - - proc osDeallocPages(p: pointer, size: int) = - # Note that in order for the Switch not to crash, a call to - # deallocHeap(runFinalizers = true, allowGcAfterwards = false) - # must be run before gfxExit(). The Switch requires all memory - # to be deallocated before the graphics application has exited. - # - # gfxExit() can be found in in the github - # repo https://github.com/switchbrew/libnx - when reallyOsDealloc: - freeMem(p) - elif defined(posix) and not defined(StandaloneHeapSize): const PROT_READ = 1 # page can be read From 854006575498704c42b5ac465fdc74c3efdb5b97 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 11 Aug 2021 02:42:01 -0700 Subject: [PATCH 2916/4254] --cc:env now works correctly to assign linker executable, allowing to cross-compile/run for windows on osx via wine (#18672) * --cc:env now works correctly to assign linker executable, allowing using wine on osx * fixup --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index a091060ff..e7e1bcd51 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -252,7 +252,7 @@ compiler envcc: buildGui: "", buildDll: " -shared ", buildLib: "", # XXX: not supported yet - linkerExe: "cc", + linkerExe: "", linkTmpl: "-o $exefile $buildgui $builddll $objfiles $options", includeCmd: " -I", linkDirCmd: "", # XXX: not supported yet From 6c1bd4bb1cb7a6af38b5929fe02b069b03e39db4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 11 Aug 2021 03:17:17 -0700 Subject: [PATCH 2917/4254] fix: `var a{.foo.} = expr` inside templates (refs #15920) (except when `foo` is overloaded) (#13869) * fix: `var a{.foo.} = expr` inside templates * add test * improve tdecls test * improve tests * add failing test * PRTEMP * fixup --- compiler/semstmts.nim | 35 ++++++++++++---------- compiler/semtempl.nim | 15 ++++++++-- tests/pragmas/tpragmas_misc.nim | 52 +++++++++++++++++++++++++++++++++ tests/stdlib/tdecls.nim | 23 ++++++++++++++- tests/stdlib/tsince.nim | 2 +- 5 files changed, 107 insertions(+), 20 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index cc09291c5..14dc89781 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -453,23 +453,29 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = return nil let nodePragma = b[1][0] # see: `singlePragma` - if nodePragma.kind notin {nkIdent, nkAccQuoted}: - return nil - let ident = considerQuotedIdent(c, nodePragma) - var userPragma = strTableGet(c.userPragmas, ident) - if userPragma != nil: return nil - - let w = nodePragma.whichPragma - if n.kind == nkVarSection and w in varPragmas or - n.kind == nkLetSection and w in letPragmas or - n.kind == nkConstSection and w in constPragmas: - return nil var amb = false - let sym = searchInScopes(c, ident, amb) - # XXX what if amb is true? - if sym == nil or sfCustomPragma in sym.flags: return nil + var sym: PSym = nil + case nodePragma.kind + of nkIdent, nkAccQuoted: + let ident = considerQuotedIdent(c, nodePragma) + var userPragma = strTableGet(c.userPragmas, ident) + if userPragma != nil: return nil + let w = nodePragma.whichPragma + if n.kind == nkVarSection and w in varPragmas or + n.kind == nkLetSection and w in letPragmas or + n.kind == nkConstSection and w in constPragmas: + return nil + sym = searchInScopes(c, ident, amb) + # XXX what if amb is true? + # CHECKME: should that test also apply to `nkSym` case? + if sym == nil or sfCustomPragma in sym.flags: return nil + of nkSym: + sym = nodePragma.sym + else: + return nil # skip if not in scope; skip `template myAttr() {.pragma.}` + let lhs = b[0] let clash = strTableGet(c.currentScope.symbols, lhs.ident) if clash != nil: @@ -477,7 +483,6 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = wrongRedefinition(c, lhs.info, lhs.ident.s, clash.info) result = newTree(nkCall) - doAssert nodePragma.kind in {nkIdent, nkAccQuoted}, $nodePragma.kind result.add nodePragma result.add lhs if a[1].kind != nkEmpty: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index a2b0f99ba..2636784af 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -208,9 +208,18 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma): let pragmaNode = n[1] for i in 0..= version: + body + when false: # bug + template fun3(): int {.since3: (1, 3).} = 12 + + block: # ditto, w + # case with overload + template since2(version: (int, int), body: untyped) {.dirty.} = + when (NimMajor, NimMinor) >= version: + body + template since2(version: (int, int, int), body: untyped) {.dirty.} = + when (NimMajor, NimMinor, NimPatch) >= version: + body + when false: # bug + template fun3(): int {.since2: (1, 3).} = 12 + +when true: # D20210801T100514:here + from macros import genSym + block: + template fn() = + var ret {.gensym.}: int # must special case template pragmas so it doesn't get confused + discard ret + fn() + static: discard genSym() diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim index 3567639e0..53e070bee 100644 --- a/tests/stdlib/tdecls.nim +++ b/tests/stdlib/tdecls.nim @@ -1,6 +1,10 @@ +discard """ + targets: "c cpp js" +""" + import std/decls -block: +template fun() = var s = @[10,11,12] var a {.byaddr.} = s[0] a+=100 @@ -34,6 +38,13 @@ block: doAssert compiles(block: var b2 {.byaddr.}: int = s[2]) +proc fun2() = fun() +fun() +fun2() +static: fun2() +when false: # pending bug #13887 + static: fun() + ## We can define custom pragmas in user code template byUnsafeAddr(lhs, typ, expr) = when typ is type(nil): @@ -68,3 +79,13 @@ block: # nkAccQuoted let a {.`cast`.} = s[0] doAssert a == "foo" doAssert a[0].unsafeAddr == s[0][0].unsafeAddr + +block: # bug #15920 + template foo(lhs, typ, expr) = + let lhs = expr + proc fun1()= + let a {.foo.} = 1 + template fun2()= + let a {.foo.} = 1 + fun1() # ok + fun2() # BUG diff --git a/tests/stdlib/tsince.nim b/tests/stdlib/tsince.nim index 14dd09c15..d0320ff12 100644 --- a/tests/stdlib/tsince.nim +++ b/tests/stdlib/tsince.nim @@ -27,6 +27,6 @@ since (99, 3): doAssert false when false: - # pending https://github.com/timotheecour/Nim/issues/129 + # pending bug #15920 # Error: cannot attach a custom pragma to 'fun3' template fun3(): int {.since: (1, 3).} = 12 From bc14b7735929f764b09446073375174236fab161 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 11 Aug 2021 17:19:23 +0200 Subject: [PATCH 2918/4254] fixes #18665 DFA generator bug (#18676) --- compiler/dfa.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 402945042..65c483e9c 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -769,6 +769,12 @@ proc gen(c: var Con; n: PNode) = of nkCharLit..nkNilLit: discard of nkAsgn, nkFastAsgn: gen(c, n[1]) + + if n[0].kind in PathKinds0: + let a = c.skipTrivials(n[0]) + if a.kind in nkCallKinds: + gen(c, a) + # watch out: 'obj[i].f2 = value' sets 'f2' but # "uses" 'i'. But we are only talking about builtin array indexing so # it doesn't matter and 'x = 34' is NOT a usage of 'x'. From c94933acb7a8fe08e1ef479d02bd20732ea1ea23 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 11 Aug 2021 13:30:51 -0700 Subject: [PATCH 2919/4254] fix #18674 --nimcache now works better with --os:windows (#18675) --- compiler/commands.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/commands.nim b/compiler/commands.nim index 1c3de29ba..82e908152 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -537,6 +537,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.lazyPaths.keepItIf(it != path) of "nimcache": expectArg(conf, switch, arg, pass, info) + var arg = arg + # refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set + # in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")` + if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/') conf.nimcacheDir = processPath(conf, arg, info, notRelativeToProj=true) of "out", "o": expectArg(conf, switch, arg, pass, info) From 018465a2345b2d11f7d1d711010d97e636af98d0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 12 Aug 2021 08:25:11 +0200 Subject: [PATCH 2920/4254] fixes #18643 [backport:1.0] (#18678) --- compiler/ccgexprs.nim | 2 +- tests/array/tarray.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 79c73b602..acf83f966 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -920,7 +920,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = if optBoundsCheck in p.options and ty.kind != tyUncheckedArray: if not isConstExpr(y): # semantic pass has already checked for const index expressions - if firstOrd(p.config, ty) == 0: + if firstOrd(p.config, ty) == 0 and lastOrd(p.config, ty) >= 0: if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)): linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)){ #raiseIndexError2($1, $2); $3}$n", [rdCharLoc(b), intLiteral(lastOrd(p.config, ty)), raiseInstr(p)]) diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index 2765ad06d..d10011ef2 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -594,3 +594,14 @@ block t17705: a = int(a) var b = array[0, int].high b = int(b) + +block t18643: + # https://github.com/nim-lang/Nim/issues/18643 + let a: array[0, int] = [] + var caught = false + let b = 9999999 + try: + echo a[b] + except IndexDefect: + caught = true + doAssert caught, "IndexDefect not caught!" From 5c1304a4181596e764b05679cd8a0044ab3398dd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 12 Aug 2021 07:50:08 -0700 Subject: [PATCH 2921/4254] fix #18670 quoteShellCommand, quoteShell, quoteShellWindows on windows (#18671) --- lib/pure/os.nim | 11 ++++++----- tests/stdlib/tos.nim | 13 ++++++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index fd618e93c..cfdacdb3c 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1045,15 +1045,12 @@ proc expandTilde*(path: string): string {. # TODO: handle `~bob` and `~bob/` which means home of bob result = path -# TODO: consider whether quoteShellPosix, quoteShellWindows, quoteShell, quoteShellCommand -# belong in `strutils` instead; they are not specific to paths proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote `s`, so it can be safely passed to Windows API. ## ## Based on Python's `subprocess.list2cmdline`. ## See `this link `_ ## for more details. - let needQuote = {' ', '\t'} in s or s.len == 0 result = "" var backslashBuff = "" @@ -1064,8 +1061,8 @@ proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1" if c == '\\': backslashBuff.add(c) elif c == '\"': - result.add(backslashBuff) - result.add(backslashBuff) + for i in 0.. 0: + result.add(backslashBuff) if needQuote: + result.add(backslashBuff) result.add("\"") + proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote ``s``, so it can be safely passed to POSIX shell. const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@', diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index dcb2d44f4..b7816fd41 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -622,7 +622,18 @@ block: # quoteShellWindows doAssert quoteShellWindows("aaa\"") == "aaa\\\"" doAssert quoteShellWindows("") == "\"\"" -block: # quoteShellWindows +block: # quoteShellCommand + when defined(windows): + doAssert quoteShellCommand(["a b c", "d", "e"]) == """"a b c" d e""" + doAssert quoteShellCommand(["""ab"c""", r"\", "d"]) == """ab\"c \ d""" + doAssert quoteShellCommand(["""ab"c""", """ \""", "d"]) == """ab\"c " \\" d""" + doAssert quoteShellCommand(["""a\\\b""", """de fg""", "h"]) == """a\\\b "de fg" h""" + doAssert quoteShellCommand(["""a\"b""", "c", "d"]) == """a\\\"b c d""" + doAssert quoteShellCommand(["""a\\b c""", "d", "e"]) == """"a\\b c" d e""" + doAssert quoteShellCommand(["""a\\b\ c""", "d", "e"]) == """"a\\b\ c" d e""" + doAssert quoteShellCommand(["ab", ""]) == """ab """"" + +block: # quoteShellPosix doAssert quoteShellPosix("aaa") == "aaa" doAssert quoteShellPosix("aaa a") == "'aaa a'" doAssert quoteShellPosix("") == "''" From f559319a682fb2abbf2945fd3390585a54f044d5 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 13 Aug 2021 00:21:01 +0800 Subject: [PATCH 2922/4254] fix a sqlite bug (#18669) --- lib/impure/db_sqlite.nim | 15 ++++----------- lib/std/private/dbutils.nim | 15 +++++++++++++++ tests/stdlib/tsqlitebindatas.nim | 28 ++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 lib/std/private/dbutils.nim diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 7bd807a12..b600576df 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -171,7 +171,7 @@ import sqlite3, macros import db_common export db_common -import std/private/since +import std/private/[since, dbutils] type DbConn* = PSqlite3 ## Encapsulates a database connection. @@ -211,14 +211,7 @@ proc dbQuote*(s: string): string = add(result, '\'') proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = - result = "" - var a = 0 - for c in items(string(formatstr)): - if c == '?': - add(result, dbQuote(args[a])) - inc(a) - else: - add(result, c) + dbFormatImpl(formatstr, dbQuote, args) proc prepare*(db: DbConn; q: string): SqlPrepared {.since: (1, 3).} = ## Creates a new `SqlPrepared` statement. @@ -642,7 +635,7 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared): string proc tryInsertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 - {.tags: [WriteDbEffect], raises: [].} = + {.tags: [WriteDbEffect], raises: [DbError].} = ## Executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. ## @@ -699,7 +692,7 @@ proc insertID*(db: DbConn, query: SqlQuery, proc tryInsert*(db: DbConn, query: SqlQuery, pkName: string, args: varargs[string, `$`]): int64 - {.tags: [WriteDbEffect], raises: [], since: (1, 3).} = + {.tags: [WriteDbEffect], raises: [DbError], since: (1, 3).} = ## same as tryInsertID tryInsertID(db, query, args) diff --git a/lib/std/private/dbutils.nim b/lib/std/private/dbutils.nim new file mode 100644 index 000000000..0ae3b3702 --- /dev/null +++ b/lib/std/private/dbutils.nim @@ -0,0 +1,15 @@ +import db_common + + +template dbFormatImpl*(formatstr: SqlQuery, dbQuote: proc (s: string): string, args: varargs[string]): string = + var res = "" + var a = 0 + for c in items(string(formatstr)): + if c == '?': + if a == args.len: + dbError("""The number of "?" given exceeds the number of parameters present in the query.""") + add(res, dbQuote(args[a])) + inc(a) + else: + add(res, c) + res diff --git a/tests/stdlib/tsqlitebindatas.nim b/tests/stdlib/tsqlitebindatas.nim index 643f1e2e6..754c80ae1 100644 --- a/tests/stdlib/tsqlitebindatas.nim +++ b/tests/stdlib/tsqlitebindatas.nim @@ -48,3 +48,31 @@ block tsqlitebindatas: ## db_sqlite binary data db.close() doAssert tryRemoveFile(dbName) + + +block: + block: + const dbName = buildDir / "db.sqlite3" + var db = db_sqlite.open(dbName, "", "", "") + var witness = false + try: + db.exec(sql("CREATE TABLE table1 (url TEXT, other_field INT);")) + db.exec(sql("REPLACE INTO table (url, another_field) VALUES (?, '123');")) + except DbError as e: + witness = true + doAssert e.msg == "The number of \"?\" given exceeds the number of parameters present in the query." + finally: + db.close() + removeFile(dbName) + + doAssert witness + + block: + const dbName = buildDir / "db.sqlite3" + var db = db_sqlite.open(dbName, "", "", "") + try: + db.exec(sql("CREATE TABLE table1 (url TEXT, other_field INT);")) + db.exec(sql("INSERT INTO table1 (url, other_field) VALUES (?, ?);"), "http://domain.com/test?param=1", 123) + finally: + db.close() + removeFile(dbName) From 883c04d444e943ba8e3d071a4dfcaca68ab300f9 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 13 Aug 2021 08:57:12 +0800 Subject: [PATCH 2923/4254] don't use space after proc names (#18681) --- lib/pure/strutils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index ac078df4e..3179c73d2 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2726,7 +2726,7 @@ func addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.rtl, add s, formatstr[i] inc(i) -func `%` *(formatstr: string, a: openArray[string]): string {.rtl, +func `%`*(formatstr: string, a: openArray[string]): string {.rtl, extern: "nsuFormatOpenArray".} = ## Interpolates a format string with the values from `a`. ## @@ -2774,7 +2774,7 @@ func `%` *(formatstr: string, a: openArray[string]): string {.rtl, result = newStringOfCap(formatstr.len + a.len shl 4) addf(result, formatstr, a) -func `%` *(formatstr, a: string): string {.rtl, +func `%`*(formatstr, a: string): string {.rtl, extern: "nsuFormatSingleElem".} = ## This is the same as `formatstr % [a]` (see ## `% func<#%25,string,openArray[string]>`_). From 3a1109a53be172a92c63ebc5bdb69c45e78e9ca6 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Thu, 12 Aug 2021 23:57:29 -0700 Subject: [PATCH 2924/4254] initial fix for compiling Nim on Zephyr RTOS (issue #18684) (#18685) * initial fix for compiling Nim on Zephyr RTOS (issue #18684) Co-authored-by: Jaremy J. Creechley --- lib/nimbase.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/nimbase.h b/lib/nimbase.h index e480c55fd..a83bd3006 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -75,7 +75,8 @@ __AVR__ #endif /* ------------------------------------------------------------------------- */ -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__ZEPHYR__) +/* Zephyr does some magic in it's headers that override the GCC stdlib. This breaks that. */ # define _GNU_SOURCE 1 #endif From b24812df5f952427c1266e48c40b7956bdf3d999 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 13 Aug 2021 00:35:48 -0700 Subject: [PATCH 2925/4254] properly fix #10053 ; `FieldDefect` msg now shows discriminant value + lineinfo, in all backends (c,vm,js) (#11955) * fix #10053 FieldError for vm * fixup * FieldError now also shows runtime value of discriminant * fix field error reporting in vm * also report culprit line info in err msg * fix errors for newruntime 2 * fix for js * fixup * PRTEMP4 * works * works * works perfect * refactor * std/private/repr_impl * suppport --gc:arc * cleanup * refactor * simplify * simplify * simplify * fixup * move out compiler.vmgen.genCustom * fixup * fixup * add tests * revert compiler/debugutils.nim * simplify reprDiscriminant * fixup * lib/std/private/repr_impl.nim -> lib/system/repr_impl.nim * try to fix D20210812T165220 * honor --declaredlocs * control toFileLineCol via --declaredlocs --- compiler/astmsgs.nim | 11 ++++++++++ compiler/ccgexprs.nim | 41 +++++++++++++++++++++++++----------- compiler/ccgtypes.nim | 6 ++++++ compiler/cgen.nim | 2 +- compiler/jsgen.nim | 11 +++++----- compiler/pragmas.nim | 2 +- compiler/renderer.nim | 12 ----------- compiler/vm.nim | 5 ++++- compiler/vmgen.nim | 14 ++++++------ lib/system/chcks.nim | 10 +++++++++ lib/system/indexerrors.nim | 4 ++++ lib/system/jssys.nim | 4 ++-- lib/system/repr.nim | 2 ++ lib/system/repr_impl.nim | 15 +++++++++++++ lib/system/repr_v2.nim | 7 ++++++ lib/system/reprjs.nim | 2 ++ tests/misc/mfield_defect.nim | 30 ++++++++++++++++++++++++++ tests/misc/trunner.nim | 16 +++++++++++--- 18 files changed, 151 insertions(+), 43 deletions(-) create mode 100644 lib/system/repr_impl.nim create mode 100644 tests/misc/mfield_defect.nim diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim index d9105b761..a9027126a 100644 --- a/compiler/astmsgs.nim +++ b/compiler/astmsgs.nim @@ -26,3 +26,14 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) = if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ) + +template quoteExpr*(a: string): untyped = + ## can be used for quoting expressions in error msgs. + "'" & a & "'" + +proc genFieldDefect*(conf: ConfigRef, field: string, disc: PSym): string = + let obj = disc.owner.name.s # `types.typeToString` might be better, eg for generics + result = "field '$#' is not accessible for type '$#'" % [field, obj] + if optDeclaredLocs in conf.globalOptions: + result.add " [discriminant declared in $#]" % toFileLineCol(conf, disc.info) + result.add " using '$# = " % disc.name.s diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index acf83f966..7eb4a7a1d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -18,6 +18,8 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, # -------------------------- constant expressions ------------------------ +proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType): Rope + proc int64Literal(i: BiggestInt): Rope = if i > low(int64): result = "IL64($1)" % [rope(i)] @@ -873,16 +875,34 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = v.r.add(".") v.r.add(disc.sym.loc.r) genInExprAux(p, it, u, v, test) - let msg = genFieldDefect(field, disc.sym) + var msg = "" + if optDeclaredLocs in p.config.globalOptions: + # xxx this should be controlled by a separate flag, and + # used for other similar defects so that location information is shown + # even without the expensive `--stacktrace`; binary size could be optimized + # by encoding the file names separately from `file(line:col)`, essentially + # passing around `TLineInfo` + the set of files in the project. + msg.add toFileLineCol(p.config, e.info) & " " + msg.add genFieldDefect(p.config, field.name.s, disc.sym) let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg)) - if op.magic == mNot: - linefmt(p, cpsStmts, - "if ($1){ #raiseFieldError($2); $3}$n", - [rdLoc(test), strLit, raiseInstr(p)]) + + ## discriminant check + template fun(code) = linefmt(p, cpsStmts, code, [rdLoc(test)]) + if op.magic == mNot: fun("if ($1) ") else: fun("if (!($1)) ") + + ## call raiseFieldError2 on failure + let discIndex = rdSetElemLoc(p.config, v, u.t) + if optTinyRtti in p.config.globalOptions: + # not sure how to use `genEnumToStr` here + const code = "{ #raiseFieldError2($1, (NI)$3); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex]) else: - linefmt(p, cpsStmts, - "if (!($1)){ #raiseFieldError($2); $3}$n", - [rdLoc(test), strLit, raiseInstr(p)]) + # complication needed for signed types + let first = p.config.firstOrd(disc.sym.typ) + let firstLit = int64Literal(cast[int](first)) + let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info) + const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$3) + (NI)$4, $5)); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex, firstLit, discName]) proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = assert e[0].kind == nkDotExpr @@ -1565,10 +1585,7 @@ proc genNewFinalize(p: BProc, e: PNode) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], f) initLoc(b, locExpr, a.lode, OnHeap) - if optTinyRtti in p.config.globalOptions: - ti = genTypeInfoV2(p.module, refType, e.info) - else: - ti = genTypeInfoV1(p.module, refType, e.info) + ti = genTypeInfo(p.config, p.module, refType, e.info) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 67e701804..d05c4cd8b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1514,3 +1514,9 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = proc genTypeSection(m: BModule, n: PNode) = discard + +proc genTypeInfo*(config: ConfigRef, m: BModule, t: PType; info: TLineInfo): Rope = + if optTinyRtti in config.globalOptions: + result = genTypeInfoV2(m, t, info) + else: + result = genTypeInfoV1(m, t, info) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3b004d399..f55da7f65 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -15,7 +15,7 @@ import ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, rodutils, renderer, cgendata, aliases, lowerings, tables, sets, ndi, lineinfos, pathutils, transf, - injectdestructors + injectdestructors, astmsgs when not defined(leanCompiler): import spawn, semparallel diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 49a57b4a6..3aa5c474e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -33,7 +33,7 @@ import nversion, msgs, idents, types, ropes, passes, ccgutils, wordrecg, renderer, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - transf, injectdestructors, sourcemap + transf, injectdestructors, sourcemap, astmsgs import json, sets, math, tables, intsets, strutils @@ -1208,12 +1208,13 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) = let tmp = p.getTemp() lineF(p, "var $1 = $2;$n", tmp, obj.res) - useMagic(p, "raiseFieldError") + useMagic(p, "raiseFieldError2") useMagic(p, "makeNimstrLit") - let msg = genFieldDefect(field, disc) - lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n", + useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen + let msg = genFieldDefect(p.config, field.name.s, disc) + lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n", setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===", - makeJSString(msg)) + makeJSString(msg), genTypeInfo(p, disc.typ)) if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex: r.typ = etyBaseIndex diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 8ae931d84..6637a8673 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -699,7 +699,7 @@ proc typeBorrow(c: PContext; sym: PSym, n: PNode) = incl(sym.typ.flags, tfBorrowDot) proc markCompilerProc(c: PContext; s: PSym) = - # minor hack ahead: FlowVar is the only generic .compilerProc type which + # minor hack ahead: FlowVar is the only generic .compilerproc type which # should not have an external name set: if s.kind != skType or s.name.s != "FlowVar": makeExternExport(c, s, "$1", s.info) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 3346e629c..393f35289 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1758,15 +1758,3 @@ proc getTokSym*(r: TSrcGen): PSym = result = r.tokens[r.idx-1].sym else: result = nil - -proc quoteExpr*(a: string): string {.inline.} = - ## can be used for quoting expressions in error msgs. - "'" & a & "'" - -proc genFieldDefect*(field: PSym, disc: PSym): string = - ## this needs to be in a module accessible by jsgen, ccgexprs, and vm to - ## provide this error msg FieldDefect; msgs would be better but it does not - ## import ast - result = field.name.s.quoteExpr & " is not accessible using discriminant " & - disc.name.s.quoteExpr & " of type " & - disc.owner.name.s.quoteExpr diff --git a/compiler/vm.nim b/compiler/vm.nim index 73a228b6c..9fa25efbe 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1472,7 +1472,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: return TFullReg(kind: rkNone) of opcInvalidField: - stackTrace(c, tos, pc, errFieldXNotFound & regs[ra].node.strVal) + let msg = regs[ra].node.strVal + let disc = regs[instr.regB].regToNode + let msg2 = formatFieldDefect(msg, $disc) + stackTrace(c, tos, pc, msg2) of opcSetLenStr: decodeB(rkNode) #createStrKeepNode regs[ra] diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 4957a3339..725afdd3f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -31,7 +31,7 @@ import tables import strutils, ast, types, msgs, renderer, vmdef, - intsets, magicsys, options, lowerings, lineinfos, transf + intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs from modulegraphs import getBody @@ -1742,12 +1742,14 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs) c.freeTemp(rs) let strType = getSysType(c.graph, n.info, tyString) - var fieldNameRegister: TDest = c.getTemp(strType) - let strLit = newStrNode($accessExpr[1], accessExpr[1].info) + var msgReg: TDest = c.getTemp(strType) + let fieldName = $accessExpr[1] + let msg = genFieldDefect(c.config, fieldName, disc.sym) + let strLit = newStrNode(msg, accessExpr[1].info) strLit.typ = strType - c.genLit(strLit, fieldNameRegister) - c.gABC(n, opcInvalidField, fieldNameRegister) - c.freeTemp(fieldNameRegister) + c.genLit(strLit, msgReg) + c.gABC(n, opcInvalidField, msgReg, discVal) + c.freeTemp(msgReg) c.patch(lab1) proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 255d97cb2..8c7c95795 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -26,8 +26,18 @@ proc raiseIndexError() {.compilerproc, noinline.} = sysFatal(IndexDefect, "index out of bounds") proc raiseFieldError(f: string) {.compilerproc, noinline.} = + ## remove after bootstrap > 1.5.1 sysFatal(FieldDefect, f) +when defined(gcdestructors): + proc raiseFieldError2(f: string, discVal: int) {.compilerproc, noinline.} = + ## raised when field is inaccessible given runtime value of discriminant + sysFatal(FieldError, f & $discVal & "'") +else: + proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noinline.} = + ## raised when field is inaccessible given runtime value of discriminant + sysFatal(FieldError, formatFieldDefect(f, discVal)) + proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} = when defined(standalone): sysFatal(RangeDefect, "value out of range") diff --git a/lib/system/indexerrors.nim b/lib/system/indexerrors.nim index 1b91789bd..6a8cb8a0a 100644 --- a/lib/system/indexerrors.nim +++ b/lib/system/indexerrors.nim @@ -1,4 +1,5 @@ # imported by other modules, unlike helpers.nim which is included +# xxx this is now included instead of imported, we should import instead template formatErrorIndexBound*[T](i, a, b: T): string = when defined(standalone): @@ -9,3 +10,6 @@ template formatErrorIndexBound*[T](i, a, b: T): string = template formatErrorIndexBound*[T](i, n: T): string = formatErrorIndexBound(i, 0, n) + +template formatFieldDefect*(f, discVal): string = + f & discVal & "'" diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index b42dc3a20..63e7b3d9d 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -171,8 +171,8 @@ proc raiseRangeError() {.compilerproc, noreturn.} = proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} = raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b))) -proc raiseFieldError(f: string) {.compilerproc, noreturn.} = - raise newException(FieldDefect, f) +proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} = + raise newException(FieldDefect, formatFieldDefect(f, discVal)) proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = asm """ diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 020c2281f..e049d18fa 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -72,6 +72,8 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = result = $e & " (invalid data!)" +include system/repr_impl + type PByteArray = ptr UncheckedArray[byte] # array[0xffff, byte] diff --git a/lib/system/repr_impl.nim b/lib/system/repr_impl.nim new file mode 100644 index 000000000..b9ec1890f --- /dev/null +++ b/lib/system/repr_impl.nim @@ -0,0 +1,15 @@ +#[ +other APIs common to system/repr and system/reprjs could be refactored here, eg: +* reprChar +* reprBool +* reprStr + +Another possibility in future work would be to have a single include file instead +of system/repr and system/reprjs, and use `when defined(js)` inside it. +]# + +proc reprDiscriminant*(e: int, typ: PNimType): string {.compilerRtl.} = + case typ.kind + of tyEnum: reprEnum(e, typ) + of tyBool: $(e != 0) + else: $e diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index f99f09799..ba94b881d 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -1,3 +1,5 @@ +include system/inclrtl + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} ## imported from typetraits @@ -66,6 +68,11 @@ proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.} ## If a `repr` operator for a concrete enumeration is provided, this is ## used instead. (In other words: *Overwriting* is possible.) +proc reprDiscriminant*(e: int): string {.compilerproc.} = + # repr and reprjs can use `PNimType` to symbolize `e`; making this work here + # would require a way to pass the set of enum stringified values to cgen. + $e + proc repr*(p: pointer): string = ## repr of pointer as its hexadecimal value if p == nil: diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index cdc3403f8..28935a4ef 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -30,6 +30,8 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = else: result = $e & " (invalid data!)" +include system/repr_impl + proc reprChar(x: char): string {.compilerRtl.} = result = "\'" case x diff --git a/tests/misc/mfield_defect.nim b/tests/misc/mfield_defect.nim new file mode 100644 index 000000000..53bfba40e --- /dev/null +++ b/tests/misc/mfield_defect.nim @@ -0,0 +1,30 @@ +#[ +ran from trunner +]# + + + + + + +# line 10 +type Kind = enum k0, k1, k2, k3, k4 + +type Foo = object + case kind: Kind + of k0: f0: int + of k1: f1: int + of k2: f2: int + of k3: f3: int + of k4: f4: int + +proc main()= + var foo = Foo(kind: k3, f3: 3) + let s1 = foo.f3 + doAssert s1 == 3 + let s2 = foo.f2 + +when defined case1: + static: main() +when defined case2: + main() diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 8426e9aee..f874d38d9 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -37,9 +37,9 @@ proc runNimCmd(file, options = "", rtarg = ""): auto = echo cmd echo result[0] & "\n" & $result[1] -proc runNimCmdChk(file, options = "", rtarg = ""): string = - let (ret, status) = runNimCmd(file, options, rtarg = rtarg) - doAssert status == 0, $(file, options) & "\n" & ret +proc runNimCmdChk(file, options = "", rtarg = "", status = 0): string = + let (ret, status2) = runNimCmd(file, options, rtarg = rtarg) + doAssert status2 == status, $(file, options, status, status2) & "\n" & ret ret proc genShellCmd(filename: string): string = @@ -376,5 +376,15 @@ mused3.nim(13, 8) Warning: imported and not used: 'mused3b' [UnusedImport] mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport] """ + block: # FieldDefect + proc fn(opt: string, expected: string) = + let output = runNimCmdChk("misc/mfield_defect.nim", fmt"-r --warning:all:off --declaredlocs {opt}", status = 1) + doAssert expected in output, opt & "\noutput:\n" & output & "expected:\n" & expected + fn("-d:case1"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case2 --gc:refc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case1 -b:js"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case2 -b:js"): """field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + # 3 instead of k3, because of lack of RTTI + fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = 3'""" else: discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled From 4463a3c3d75daabfef52a139221f729e8af9e81e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 13 Aug 2021 12:34:28 +0200 Subject: [PATCH 2926/4254] manual: minor improvements (#18687) --- doc/manual.rst | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 41ed49715..9c7c219e9 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -31,7 +31,7 @@ the `destructors `_ document. This document describes the lexis, the syntax, and the semantics of the Nim language. To learn how to compile Nim programs and generate documentation see -`Compiler User Guide `_ and `DocGen Tools Guide `_. +the `Compiler User Guide `_ and the `DocGen Tools Guide `_. The language constructs are explained using an extended BNF, in which `(a)*` means 0 or more `a`'s, `a+` means 1 or more `a`'s, and `(a)?` means an @@ -583,12 +583,11 @@ In the following examples, `-1` is parsed as two separate tokens "abc"-1 -There exists a literal for each numerical type that is -defined. The suffix starting with an apostrophe ('\'') is called a +The suffix starting with an apostrophe ('\'') is called a `type suffix`:idx:. Literals without a type suffix are of an integer type unless the literal contains a dot or `E|e` in which case it is of type `float`. This integer type is `int` if the literal is in the range -`low(i32)..high(i32)`, otherwise it is `int64`. +`low(int32)..high(int32)`, otherwise it is `int64`. For notational convenience, the apostrophe of a type suffix is optional if it is not ambiguous (only hexadecimal floating-point literals with a type suffix can be ambiguous). @@ -619,10 +618,9 @@ notation: `0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64` is approximately 1.72826e35 according to the IEEE floating-point standard. -Literals are bounds checked so that they fit the datatype. Non-base-10 -literals are used mainly for flags and bit pattern representations, therefore -bounds checking is done on bit width, not value range. If the literal fits in -the bit width of the datatype, it is accepted. +Literals must match the datatype, for example, `333'i8` is an invalid literal. +Non-base-10 literals are used mainly for flags and bit pattern representations, +therefore the checking is done on bit width and not on value range. Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1 instead of causing an overflow error. @@ -1980,8 +1978,7 @@ details like this when mixing garbage-collected data with unmanaged memory. Procedural type --------------- A procedural type is internally a pointer to a procedure. `nil` is -an allowed value for variables of a procedural type. Nim uses procedural -types to achieve `functional`:idx: programming techniques. +an allowed value for a variable of a procedural type. Examples: @@ -2494,8 +2491,8 @@ An expression `b` can be assigned to an expression `a` iff `a` is an `l-value` and `isImplicitlyConvertible(b.typ, a.typ)` holds. -Overloading resolution -====================== +Overload resolution +=================== In a call `p(args)` the routine `p` that matches best is selected. If multiple routines match equally well, the ambiguity is reported during From 52cc0a82cad856fa58ebbb16a9e7ad8c7012e8cf Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 14 Aug 2021 02:13:30 -0700 Subject: [PATCH 2927/4254] fix #18692 AsyncHttpServer was hanging because client.close was not called (#18693) --- lib/pure/asynchttpserver.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index fd0cad5ca..f23c3d3f9 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -362,7 +362,9 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string let retry = await processRequest( server, request, client, address, lineFut, callback ) - if not retry: break + if not retry: + client.close() + break const nimMaxDescriptorsFallback* {.intdefine.} = 16_000 ## fallback value for \ From b3e077863aa6985eebab0c37785ba127b3192c80 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 14 Aug 2021 21:51:41 -0300 Subject: [PATCH 2928/4254] Documentation only, Terminal (#18696) Add simple progress bar example to terminal module --- lib/pure/terminal.nim | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index ce5660557..25b1a4cdd 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -15,6 +15,21 @@ ## code `exitprocs.addExitProc(resetAttributes)` to restore the defaults. ## Similarly, if you hide the cursor, make sure to unhide it with ## `showCursor` before quitting. +## +## Progress bar +## ============ +## +## Basic progress bar example: +runnableExamples("-r:off"): + import std/[os, strutils] + + for i in 0..100: + stdout.styledWriteLine(fgRed, "0% ", fgWhite, '#'.repeat i, if i > 50: fgGreen else: fgYellow, "\t", $i , "%") + sleep 42 + cursorUp 1 + eraseLine() + + stdout.resetAttributes() ##[ ## Playing with colorful and styled text @@ -43,7 +58,6 @@ runnableExamples("-r:off"): stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text") - import macros import strformat from strutils import toLowerAscii, `%` From 1acba63cb725a0eee8f8b02f585057e030ce6295 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 16 Aug 2021 00:32:12 -0700 Subject: [PATCH 2929/4254] cross compilation targetting windows now supports `nim r`: `nim r -d:mingw main` (#18682) * cross compilation targetting windows now supports `nim r`: `nim r -d:mingw main` * quoteShell * address comment: remove `conf.getConfigVar("nimrun.exe")` --- changelog.md | 3 +++ compiler/nim.nim | 20 +++++++++++++++----- doc/nimc.rst | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 0e3c54d77..40c6c9ace 100644 --- a/changelog.md +++ b/changelog.md @@ -482,6 +482,9 @@ nim r main # uses cached binary nim r main arg1 arg2 # ditto (runtime arguments are irrelevant) +- `nim r` now supports cross compilation from unix to windows when specifying `-d:mingw` by using wine, + e.g.: `nim r --eval:'import os; echo "a" / "b"'` prints `a\b` + - The style checking of the compiler now supports a `--styleCheck:usages` switch. This switch enforces that every symbol is written as it was declared, not enforcing the official Nim style guide. To be enabled, this has to be combined either diff --git a/compiler/nim.nim b/compiler/nim.nim index 91b1bc2db..b8256d576 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -70,6 +70,13 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}: rawMessage(config, errGenerated, errArgsNeedRunOption) +proc getNimRunExe(conf: ConfigRef): string = + # xxx consider defining `conf.getConfigVar("nimrun.exe")` to allow users to + # customize the binary to run the command with, e.g. for custom `nodejs` or `wine`. + if conf.isDefined("mingw"): + if conf.isDefined("i386"): result = "wine" + elif conf.isDefined("amd64"): result = "wine64" + proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let self = NimProg( supportsStdinFile: true, @@ -95,18 +102,21 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let output = conf.absOutFile case conf.cmd of cmdBackends, cmdTcc: - var cmdPrefix = "" + let nimRunExe = getNimRunExe(conf) + var cmdPrefix: string + if nimRunExe.len > 0: cmdPrefix.add nimRunExe.quoteShell case conf.backend of backendC, backendCpp, backendObjc: discard of backendJs: # D20210217T215950:here this flag is needed for node < v15.0.0, otherwise # tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode - cmdPrefix = findNodeJs() & " --unhandled-rejections=strict " + if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell + cmdPrefix.add " --unhandled-rejections=strict" else: doAssert false, $conf.backend - # No space before command otherwise on windows you'd get a cryptic: - # `The parameter is incorrect` + if cmdPrefix.len > 0: cmdPrefix.add " " + # without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic: + # `The parameter is incorrect` execExternalProgram(conf, cmdPrefix & output.quoteShell & ' ' & conf.arguments) - # execExternalProgram(conf, cmdPrefix & ' ' & output.quoteShell & ' ' & conf.arguments) of cmdDocLike, cmdRst2html, cmdRst2tex: # bugfix(cmdRst2tex was missing) if conf.arguments.len > 0: # reserved for future use diff --git a/doc/nimc.rst b/doc/nimc.rst index ad5ecaa76..98b754729 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -317,6 +317,8 @@ To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain: .. code:: cmd nim c -d:mingw myproject.nim + # `nim r` also works, running the binary via `wine` or `wine64`: + nim r -d:mingw --eval:'import os; echo "a" / "b"' Use `--cpu:i386`:option: or `--cpu:amd64`:option: to switch the CPU architecture. From 901c5ded527bb06c52bfc1fd38c9a5fadee0f49a Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 16 Aug 2021 21:14:35 +0800 Subject: [PATCH 2930/4254] fix #18702(fix `parseutils.parseFloat`) (#18703) [backport:1.0] * fix #18702 * Apply suggestions from code review --- lib/system/strmantle.nim | 9 +++++---- tests/stdlib/tparseutils.nim | 13 +++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 81ac5c751..f55168c01 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -211,15 +211,16 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, var ti = 0 let maxlen = t.high - "e+000".len # reserve enough space for exponent - result = i - start + let endPos = i + result = endPos - start i = start # re-parse without error checking, any error should be handled by the code above. - if i < s.len and s[i] == '.': i.inc - while i < s.len and s[i] in {'0'..'9','+','-'}: + if i < endPos and s[i] == '.': i.inc + while i < endPos and s[i] in {'0'..'9','+','-'}: if ti < maxlen: t[ti] = s[i]; inc(ti) inc(i) - while i < s.len and s[i] in {'.', '_'}: # skip underscore and decimal point + while i < endPos and s[i] in {'.', '_'}: # skip underscore and decimal point inc(i) # insert exponent diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim index 3bc54dff1..db7a0ac8d 100644 --- a/tests/stdlib/tparseutils.nim +++ b/tests/stdlib/tparseutils.nim @@ -1,5 +1,5 @@ -import parseutils -import sequtils +import std/[parseutils, sequtils, sugar] + let input = "$test{} $this is ${an{ example}} " let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"), @@ -41,3 +41,12 @@ doAssert value == 1_000_000 var i64Value: int64 discard parseBiggestInt("9223372036854775807", i64Value) doAssert i64Value == 9223372036854775807 + +block: + var f: float + let res = collect: + for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]: + (parseFloat(x, f, 0), $f) + doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"), + (17, "9.123456789012344"), (17, "8.123456789012344"), + (16, "9.12345678901234"), (17, "9.123456789012344")] From 5fd150b7f792754b0431f2cc2e9830fb23ce15f6 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 18 Aug 2021 14:25:25 +0200 Subject: [PATCH 2931/4254] asynchttpserver: ipv6 support (#18706) Fix #18705 --- lib/pure/asynchttpserver.nim | 13 +++++++------ tests/errmsgs/tgcsafety.nim | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index f23c3d3f9..d7daacd03 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -41,7 +41,7 @@ runnableExamples("-r:off"): import asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore -from nativesockets import getLocalAddr, AF_INET +from nativesockets import getLocalAddr, Domain, AF_INET, AF_INET6 import std/private/since export httpcore except parseHeader @@ -82,7 +82,7 @@ proc getPort*(self: AsyncHttpServer): Port {.since: (1, 5, 1).} = server.listen(Port(0)) assert server.getPort.uint16 > 0 server.close() - result = getLocalAddr(self.socket.getFd, AF_INET)[1] + result = getLocalAddr(self.socket)[1] proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = @@ -372,13 +372,13 @@ const ## This can be set on the command line during compilation ## via `-d:nimMaxDescriptorsFallback=N` -proc listen*(server: AsyncHttpServer; port: Port; address = "") = +proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET) = ## Listen to the given port and address. when declared(maxDescriptors): server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback else: server.maxFDs = nimMaxDescriptorsFallback - server.socket = newAsyncSocket() + server.socket = newAsyncSocket(domain) if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) if server.reusePort: @@ -404,7 +404,8 @@ proc acceptRequest*(server: AsyncHttpServer, proc serve*(server: AsyncHttpServer, port: Port, callback: proc (request: Request): Future[void] {.closure, gcsafe.}, address = ""; - assumedDescriptorsPerRequest = -1) {.async.} = + assumedDescriptorsPerRequest = -1; + domain = AF_INET) {.async.} = ## Starts the process of listening for incoming HTTP connections on the ## specified address and port. ## @@ -417,7 +418,7 @@ proc serve*(server: AsyncHttpServer, port: Port, ## ## You should prefer to call `acceptRequest` instead with a custom server ## loop so that you're in control over the error handling and logging. - listen server, port, address + listen server, port, address, domain while true: if shouldAcceptRequest(server, assumedDescriptorsPerRequest): var (address, client) = await server.socket.acceptAddr() diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 6021d19e1..701adeebf 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -6,7 +6,7 @@ tgcsafety.nim(31, 18) Error: type mismatch: got Date: Wed, 18 Aug 2021 21:53:52 +0800 Subject: [PATCH 2932/4254] [wip]better hint message for JS (#18704) * better hint message for JS * both --- compiler/msgs.nim | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 20a55daee..56531eb68 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -669,17 +669,28 @@ proc genSuccessX*(conf: ConfigRef) = else: formatSize(getTotalMem()) & " totmem" let loc = $conf.linesCompiled var build = "" + var flags = "" + const debugModeHints = "none (DEBUG BUILD, `-d:release` generates faster code)" if conf.cmd in cmdBackends: - build.add "gc: $#; " % $conf.selectedGC - if optThreads in conf.globalOptions: build.add "threads: on; " - build.add "opt: " - if optOptimizeSpeed in conf.options: build.add "speed" - elif optOptimizeSize in conf.options: build.add "size" - else: build.add "none (DEBUG BUILD, `-d:release` generates faster code)" - # pending https://github.com/timotheecour/Nim/issues/752, point to optimization.html - var flags = "" - if isDefined(conf, "danger"): flags.add " -d:danger" - elif isDefined(conf, "release"): flags.add " -d:release" + if conf.backend != backendJs: + build.add "gc: $#; " % $conf.selectedGC + if optThreads in conf.globalOptions: build.add "threads: on; " + build.add "opt: " + if optOptimizeSpeed in conf.options: build.add "speed" + elif optOptimizeSize in conf.options: build.add "size" + else: build.add debugModeHints + # pending https://github.com/timotheecour/Nim/issues/752, point to optimization.html + if isDefined(conf, "danger"): flags.add " -d:danger" + elif isDefined(conf, "release"): flags.add " -d:release" + else: + build.add "opt: " + if isDefined(conf, "danger"): + build.add "speed" + flags.add " -d:danger" + elif isDefined(conf, "release"): + build.add "speed" + flags.add " -d:release" + else: build.add debugModeHints if flags.len > 0: build.add "; options:" & flags let sec = formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3) let project = if conf.filenameOption == foAbs: $conf.projectFull else: $conf.projectName From 7b58dc2de0f606b757a558dfdda9d930ae63f41a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Aug 2021 10:33:11 -0700 Subject: [PATCH 2933/4254] allow building 1.4.0 from devel (#18708) * allow building 1.4.0 from devel * changelog --- changelog.md | 3 +++ compiler/ast.nim | 8 ++++++-- compiler/ccgexprs.nim | 21 +++++++++++++++++---- compiler/jsgen.nim | 1 + compiler/semfold.nim | 1 + compiler/vmgen.nim | 2 +- 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 40c6c9ace..77a77f2f5 100644 --- a/changelog.md +++ b/changelog.md @@ -485,6 +485,9 @@ - `nim r` now supports cross compilation from unix to windows when specifying `-d:mingw` by using wine, e.g.: `nim r --eval:'import os; echo "a" / "b"'` prints `a\b` +- `nim` can compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off -d:nimVersion140 compiler/nim`. + `-d:nimVersion140` is not needed for bootstrapping, only for building 1.4.0 from devel. + - The style checking of the compiler now supports a `--styleCheck:usages` switch. This switch enforces that every symbol is written as it was declared, not enforcing the official Nim style guide. To be enabled, this has to be combined either diff --git a/compiler/ast.nim b/compiler/ast.nim index 5b54dd8ef..08fbc70e1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -652,7 +652,9 @@ type mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, + mFloatToStr, # for -d:nimVersion140 + mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mImplies, mIff, mExists, mForall, mOld, @@ -720,7 +722,9 @@ const mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, + mFloatToStr, + mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7eb4a7a1d..374876367 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -894,15 +894,23 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = let discIndex = rdSetElemLoc(p.config, v, u.t) if optTinyRtti in p.config.globalOptions: # not sure how to use `genEnumToStr` here - const code = "{ #raiseFieldError2($1, (NI)$3); $2} $n" - linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex]) + if p.config.isDefined("nimVersion140"): + const code = "{ #raiseFieldError($1); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p)]) + else: + const code = "{ #raiseFieldError2($1, (NI)$3); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex]) else: # complication needed for signed types let first = p.config.firstOrd(disc.sym.typ) let firstLit = int64Literal(cast[int](first)) let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info) - const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$3) + (NI)$4, $5)); $2} $n" - linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex, firstLit, discName]) + if p.config.isDefined("nimVersion140"): + const code = "{ #raiseFieldError($1); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p)]) + else: + const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$3) + (NI)$4, $5)); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex, firstLit, discName]) proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = assert e[0].kind == nkDotExpr @@ -2320,6 +2328,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)") of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") + of mFloatToStr: + if e[1].typ.skipTypes(abstractInst).kind == tyFloat32: + genDollar(p, e, d, "#nimFloat32ToStr($1)") + else: + genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e[1], d) of mIsolate: genCall(p, e, d) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 3aa5c474e..931e56475 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -434,6 +434,7 @@ const # magic checked op; magic unchecked op; mBoolToStr: ["nimBoolToStr", "nimBoolToStr"], mIntToStr: ["cstrToNimstr", "cstrToNimstr"], mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"], + mFloatToStr: ["cstrToNimstr", "cstrToNimstr"], mCStrToStr: ["cstrToNimstr", "cstrToNimstr"], mStrToStr: ["", ""]] diff --git a/compiler/semfold.nim b/compiler/semfold.nim index e5f0643bc..04ed73209 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -290,6 +290,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P of mBoolToStr: if getOrdValue(a) == 0: result = newStrNodeT("false", n, g) else: result = newStrNodeT("true", n, g) + of mFloatToStr: result = newStrNodeT($getFloat(a), n, g) of mCStrToStr, mCharToStr: if a.kind == nkBracket: var s = "" diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 725afdd3f..f2758ff37 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1127,7 +1127,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8): c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) - of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr: + of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: genConv(c, n, n[1], dest) of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr) of mLeStr: genBinaryABC(c, n, dest, opcLeStr) From 394f4ac7bb92fe5aaf902495c6b43b3451667602 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 19 Aug 2021 02:33:52 -0700 Subject: [PATCH 2934/4254] improvements to `addInt` and `$` for integer types (#18592) * improvements to $(SomeInteger) and addInt * remove mIntToStr, mInt64ToStr * improvements * fix tests/pragmas/tinjectstmt.nim; the diff is harmless, cgen code is identical with -d:danger or debug mode * rm tests/system/tstrmantle.nim * revert compiler/jsgen.nim for -d:nimVersion140 --- compiler/ast.nim | 8 +-- lib/std/private/digitsutils.nim | 72 +++++++++++++++----- lib/std/private/miscdollars.nim | 9 ++- lib/system.nim | 9 ++- lib/system/assertions.nim | 5 +- lib/system/dollars.nim | 56 ++++++---------- lib/system/repr_v2.nim | 17 +++-- lib/system/strmantle.nim | 30 --------- nimsuggest/tests/tqualified_highlight.nim | 2 +- tests/pragmas/tinjectstmt.nim | 13 ++-- tests/system/tdollars.nim | 81 +++++++++++++++-------- tests/system/tstrmantle.nim | 46 ------------- 12 files changed, 162 insertions(+), 186 deletions(-) delete mode 100644 tests/system/tstrmantle.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 08fbc70e1..0bdcc0e97 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -652,8 +652,8 @@ type mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, - mFloatToStr, # for -d:nimVersion140 + mCharToStr, mBoolToStr, + mIntToStr, mInt64ToStr, mFloatToStr, # for -d:nimVersion140 mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, @@ -722,8 +722,8 @@ const mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, - mFloatToStr, + mCharToStr, mBoolToStr, + mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index 7aefc36bc..268a3ba7d 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -29,18 +29,34 @@ const # doAssert res == digits100 proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = - assert(digits <= 99) buf[pos] = digits100[2 * digits] buf[pos+1] = digits100[2 * digits + 1] #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = - assert(digits <= 99) return trailingZeros100[digits] -func addIntImpl*(result: var string, origin: uint64) = +when defined(js): + proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".} + +func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} = + let old = result.len + result.setLen old + n + template impl = + for i in 0.. 0: result.add "(" - # simplify this after moving moving `include strmantle` above import assertions` - when declared(addInt): result.addInt line - else: result.add $line + addInt(result, line) if col > 0: result.add ", " - when declared(addInt): result.addInt col - else: result.add $col + addInt(result, col) result.add ")" diff --git a/lib/system.nim b/lib/system.nim index e6a2439df..740c4419f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2463,14 +2463,13 @@ when notJSnotNims: else: {.error: "Only closure iterator is allowed!".} +from std/private/digitsutils import addInt +export addInt + when defined(js): include "system/jssys" include "system/reprjs" -when defined(js) or defined(nimscript): - proc addInt*(result: var string; x: int64) = - result.add $x - proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} = ## A shorthand for `echo(errormsg); quit(errorcode)`. when defined(nimscript) or defined(js) or (hostOS == "standalone"): @@ -2918,7 +2917,7 @@ proc addQuoted*[T](s: var string, x: T) = s.addEscapedChar(x) s.add("'") # prevent temporary string allocation - elif T is SomeSignedInt: + elif T is SomeInteger: s.addInt(x) elif T is SomeFloat: s.addFloat(x) diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index cd789845b..6f64a55b7 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -12,7 +12,6 @@ import std/private/miscdollars type InstantiationInfo = tuple[filename: string, line: int, column: int] -proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.} proc `$`(info: InstantiationInfo): string = # The +1 is needed here # instead of overriding `$` (and changing its meaning), consider explicit name. @@ -108,7 +107,9 @@ template doAssertRaises*(exception: typedesc, code: untyped) = wrong = true except exception: discard - except Exception as e: raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd) + except Exception as e: + mixin `$` # alternatively, we could define $cstring in this module + raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd) except: raisedForeign() if wrong: raiseAssert(begin & " nothing was raised" & msgEnd) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 8634db382..46085d2aa 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -1,45 +1,31 @@ +## `$` is Nim's general way of spelling `toString`:idx:. +runnableExamples: + assert $0.1 == "0.1" + assert $(-2*3) == "-6" + import std/private/digitsutils import system/formatfloat export addFloat -proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} - ## The stringify operator for an integer argument. Returns `x` - ## converted to a decimal string. `$` is Nim's general way of - ## spelling `toString`:idx:. +proc `$`*(x: int): string {.raises: [].} = + ## Outplace version of `addInt`. + result.addInt(x) -template dollarImpl(x: uint | uint64, result: var string) = - addIntImpl(result, x) +proc `$`*(x: int64): string {.raises: [].} = + ## Outplace version of `addInt`. + result.addInt(x) -when defined(js): - import std/private/since - since (1, 3): - proc `$`*(x: uint): string = - ## Caveat: currently implemented as $(cast[int](x)), tied to current - ## semantics of js' Number type. - # for c, see strmantle.`$` - when nimvm: - dollarImpl(x, result) - else: - result = $(int(x)) +proc `$`*(x: uint64): string {.raises: [].} = + ## Outplace version of `addInt`. + addInt(result, x) - proc `$`*(x: uint64): string = - ## Compatibility note: - ## the results may change in future releases if/when js target implements - ## 64bit ints. - # pending https://github.com/nim-lang/RFCs/issues/187 - when nimvm: - dollarImpl(x, result) - else: - result = $(cast[int](x)) -else: - proc `$`*(x: uint64): string {.noSideEffect, raises: [].} = - ## The stringify operator for an unsigned integer argument. Returns `x` - ## converted to a decimal string. - dollarImpl(x, result) - -proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} - ## The stringify operator for an integer argument. Returns `x` - ## converted to a decimal string. +# same as old `ctfeWhitelist` behavior, whether or not this is a good idea. +template gen(T) = + # xxx simplify this by supporting this in compiler: int{lit} | uint64{lit} | int64{lit} + func `$`*(x: T{lit}): string {.compileTime.} = result.addInt(x) +gen(int) +gen(uint64) +gen(int64) func `$`*(x: float | float32): string = ## Outplace version of `addFloat`. diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index ba94b881d..6ab5f3c3f 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -8,18 +8,17 @@ proc distinctBase(T: typedesc, recursive: static bool = true): typedesc {.magic: proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.} -proc repr*(x: int): string {.magic: "IntToStr", noSideEffect.} - ## repr for an integer argument. Returns `x` - ## converted to a decimal string. +proc repr*(x: int): string = + ## Same as $x + $x -proc repr*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} - ## repr for an integer argument. Returns `x` - ## converted to a decimal string. +proc repr*(x: int64): string = + ## Same as $x + $x proc repr*(x: uint64): string {.noSideEffect.} = - ## repr for an unsigned integer argument. Returns `x` - ## converted to a decimal string. - $x #Calls `$` from system/strmantle.nim + ## Same as $x + $x proc repr*(x: float): string = ## Same as $x diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index f55168c01..9cf4f9e55 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -43,32 +43,6 @@ proc hashString(s: string): int {.compilerproc.} = h = h + h shl 15 result = cast[int](h) -proc addInt*(result: var string; x: int64) = - ## Converts integer to its string representation and appends it to `result`. - ## - ## .. code-block:: Nim - ## var - ## a = "123" - ## b = 45 - ## a.addInt(b) # a <- "12345" - var num: uint64 - - if x < 0: - if x == low(int64): - num = uint64(x) - else: - num = uint64(-x) - let base = result.len - setLen(result, base + 1) - result[base] = '-' - else: - num = uint64(x) - addIntImpl(result, num) - -proc nimIntToStr(x: int): string {.compilerRtl.} = - result = newStringOfCap(sizeof(x)*4) - result.addInt x - proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. importc: "strtod", header: "", noSideEffect.} @@ -240,10 +214,6 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, when defined(nimHasInvariant): {.pop.} # staticBoundChecks -proc nimInt64ToStr(x: int64): string {.compilerRtl.} = - result = newStringOfCap(sizeof(x)*4) - result.addInt x - proc nimBoolToStr(x: bool): string {.compilerRtl.} = return if x: "true" else: "false" diff --git a/nimsuggest/tests/tqualified_highlight.nim b/nimsuggest/tests/tqualified_highlight.nim index 3b521ecc1..b83669e72 100644 --- a/nimsuggest/tests/tqualified_highlight.nim +++ b/nimsuggest/tests/tqualified_highlight.nim @@ -10,5 +10,5 @@ highlight;;skProc;;1;;7;;4 highlight;;skTemplate;;2;;7;;4 highlight;;skTemplate;;2;;7;;4 highlight;;skTemplate;;2;;7;;4 -highlight;;skProc;;3;;8;;1 +highlight;;skFunc;;3;;8;;1 """ diff --git a/tests/pragmas/tinjectstmt.nim b/tests/pragmas/tinjectstmt.nim index bca041e46..c6256bda6 100644 --- a/tests/pragmas/tinjectstmt.nim +++ b/tests/pragmas/tinjectstmt.nim @@ -7,15 +7,18 @@ ok0 ok1 onInject: 3 onInject: 4 -0 onInject: 5 +0 onInject: 6 -1 onInject: 7 onInject: 8 +1 +onInject: 9 +onInject: 10 +onInject: 11 2 ok2 -onInject: 9 +onInject: 12 ''' """ @@ -25,7 +28,7 @@ onInject: 9 {.injectStmt.} pragma can be used to inject a statement before every other statement in the current module. It's now undocumented and may be removed in the future and replaced with something more general and without its limitations. -e.g. (e.g. doesn't work in VM or js backends). +(e.g. doesn't work in VM or js backends). ]# from system/ansi_c import c_printf @@ -44,5 +47,5 @@ proc main()= echo a echo "ok2" -static: main() # xxx injectStmt not honred in VM +static: main() # xxx injectStmt not honored in VM main() diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 34801d9ee..17d195e76 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -102,40 +102,41 @@ block: # #14350, #16674, #16686 for JS doAssert nil2 == cstring("") block: - block: - let x = -1'i8 - let y = uint32(x) - - doAssert $y == "4294967295" - - block: - let x = -1'i16 - let y = uint32(x) - - doAssert $y == "4294967295" - - block: - let x = -1'i32 - let y = uint32(x) - - doAssert $y == "4294967295" + when defined(js): # bug #18591 + let a1 = -1'i8 + let a2 = uint8(a1) + # if `uint8(a1)` changes meaning to `cast[uint8](a1)` in future, update this test; + # until then, this is the correct semantics. + let a3 = $a2 + doAssert a2 < 3 + doAssert a3 == "-1" + proc intToStr(a: uint8): cstring {.importjs: "(# + \"\")".} + doAssert $intToStr(a2) == "-1" + else: + block: + let x = -1'i8 + let y = uint32(x) + doAssert $y == "4294967295" + block: + let x = -1'i16 + let y = uint32(x) + doAssert $y == "4294967295" + block: + let x = -1'i32 + let y = uint32(x) + doAssert $y == "4294967295" + block: + proc foo1(arg: int): string = + let x = uint32(arg) + $x + doAssert $foo1(-1) == "4294967295" block: let x = 4294967295'u32 doAssert $x == "4294967295" - block: doAssert $(4294967295'u32) == "4294967295" - - block: - proc foo1(arg: int): string = - let x = uint32(arg) - $x - - doAssert $foo1(-1) == "4294967295" - - proc main()= block: let a = -0.0 @@ -159,6 +160,32 @@ proc main()= doAssert $uint32.high == "4294967295" + block: # addInt + var res = newStringOfCap(24) + template test2(a, b) = + res.setLen(0) + res.addInt a + doAssert res == b + + for i in 0 .. 9: + res.addInt int64(i) + doAssert res == "0123456789" + + res.setLen(0) + for i in -9 .. 0: + res.addInt int64(i) + doAssert res == "-9-8-7-6-5-4-3-2-10" + + when not defined(js): + test2 high(int64), "9223372036854775807" + test2 low(int64), "-9223372036854775808" + + test2 high(int32), "2147483647" + test2 low(int32), "-2147483648" + test2 high(int16), "32767" + test2 low(int16), "-32768" + test2 high(int8), "127" + test2 low(int8), "-128" static: main() main() diff --git a/tests/system/tstrmantle.nim b/tests/system/tstrmantle.nim deleted file mode 100644 index 1f195adde..000000000 --- a/tests/system/tstrmantle.nim +++ /dev/null @@ -1,46 +0,0 @@ -var res = newStringOfCap(24) - -for i in 0 .. 9: - res.addInt int64(i) - -doAssert res == "0123456789" - -res.setLen(0) - -for i in -9 .. 0: - res.addInt int64(i) - -doAssert res == "-9-8-7-6-5-4-3-2-10" - -res.setLen(0) -res.addInt high(int64) -doAssert res == "9223372036854775807" - -res.setLen(0) -res.addInt low(int64) -doAssert res == "-9223372036854775808" - -res.setLen(0) -res.addInt high(int32) -doAssert res == "2147483647" - -res.setLen(0) -res.addInt low(int32) -doAssert res == "-2147483648" - -res.setLen(0) -res.addInt high(int16) -doAssert res == "32767" - -res.setLen(0) -res.addInt low(int16) -doAssert res == "-32768" - - -res.setLen(0) -res.addInt high(int8) -doAssert res == "127" - -res.setLen(0) -res.addInt low(int8) -doAssert res == "-128" From 373bbd9bb4cbcb06fbfd80ab0e968127dc098873 Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Thu, 19 Aug 2021 18:35:40 +0900 Subject: [PATCH 2935/4254] Add ceilDiv to math (#18596) * Use assert in runnableExamples and improve boundary check * Add more tests for ceilDiv * Fix comment in ceilDiv * Calling ceilDiv with int type T such like sizeof(T) > 8 is error --- changelog.md | 2 ++ lib/pure/math.nim | 52 ++++++++++++++++++++++++++++++++++++++++++ tests/stdlib/tmath.nim | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/changelog.md b/changelog.md index 77a77f2f5..447401cd0 100644 --- a/changelog.md +++ b/changelog.md @@ -148,6 +148,8 @@ - Added `clamp` in `math` which allows using a `Slice` to clamp to a value. +- Added `ceilDiv` in `math` for round up integer division. + - The JSON module can now handle integer literals and floating point literals of arbitrary length and precision. Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 410660d4a..66f1a2e2c 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -941,6 +941,58 @@ func euclMod*[T: SomeNumber](x, y: T): T {.since: (1, 5, 1).} = if result < 0: result += abs(y) +func ceilDiv*[T: SomeInteger](x, y: T): T {.inline, since: (1, 5, 1).} = + ## Ceil division is conceptually defined as `ceil(x / y)`. + ## + ## Assumes `x >= 0` and `y > 0` (and `x + y - 1 <= high(T)` if T is SomeUnsignedInt). + ## + ## This is different from the `system.div `_ + ## operator, which works like `trunc(x / y)`. + ## That is, `div` rounds towards `0` and `ceilDiv` rounds up. + ## + ## This function has the above input limitation, because that allows the + ## compiler to generate faster code and it is rarely used with + ## negative values or unsigned integers close to `high(T)/2`. + ## If you need a `ceilDiv` that works with any input, see: + ## https://github.com/demotomohiro/divmath. + ## + ## **See also:** + ## * `system.div proc `_ for integer division + ## * `floorDiv func <#floorDiv,T,T>`_ for integer division which rounds down. + runnableExamples: + assert ceilDiv(12, 3) == 4 + assert ceilDiv(13, 3) == 5 + + when sizeof(T) == 8: + type UT = uint64 + elif sizeof(T) == 4: + type UT = uint32 + elif sizeof(T) == 2: + type UT = uint16 + elif sizeof(T) == 1: + type UT = uint8 + else: + {.fatal: "Unsupported int type".} + + assert x >= 0 and y > 0 + when T is SomeUnsignedInt: + assert x + y - 1 >= x + + # If the divisor is const, the backend C/C++ compiler generates code without a `div` + # instruction, as it is slow on most CPUs. + # If the divisor is a power of 2 and a const unsigned integer type, the + # compiler generates faster code. + # If the divisor is const and a signed integer, generated code becomes slower + # than the code with unsigned integers, because division with signed integers + # need to works for both positive and negative value without `idiv`/`sdiv`. + # That is why this code convert parameters to unsigned. + # This post contains a comparison of the performance of signed/unsigned integers: + # https://github.com/nim-lang/Nim/pull/18596#issuecomment-894420984. + # If signed integer arguments were not converted to unsigned integers, + # `ceilDiv` wouldn't work for any positive signed integer value, because + # `x + (y - 1)` can overflow. + ((x.UT + (y.UT - 1.UT)) div y.UT).T + func frexp*[T: float32|float64](x: T): tuple[frac: T, exp: int] {.inline.} = ## Splits `x` into a normalized fraction `frac` and an integral power of 2 `exp`, ## such that `abs(frac) in 0.5..<1` and `x == frac * 2 ^ exp`, except for special diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 2cf544ddb..9bc5b994f 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -106,6 +106,46 @@ template main() = doAssert euclDiv(-9, -3) == 3 doAssert euclMod(-9, -3) == 0 + block: # ceilDiv + doAssert ceilDiv(8, 3) == 3 + doAssert ceilDiv(8, 4) == 2 + doAssert ceilDiv(8, 5) == 2 + doAssert ceilDiv(11, 3) == 4 + doAssert ceilDiv(12, 3) == 4 + doAssert ceilDiv(13, 3) == 5 + doAssert ceilDiv(41, 7) == 6 + doAssert ceilDiv(0, 1) == 0 + doAssert ceilDiv(1, 1) == 1 + doAssert ceilDiv(1, 2) == 1 + doAssert ceilDiv(2, 1) == 2 + doAssert ceilDiv(2, 2) == 1 + doAssert ceilDiv(0, high(int)) == 0 + doAssert ceilDiv(1, high(int)) == 1 + doAssert ceilDiv(0, high(int) - 1) == 0 + doAssert ceilDiv(1, high(int) - 1) == 1 + doAssert ceilDiv(high(int) div 2, high(int) div 2 + 1) == 1 + doAssert ceilDiv(high(int) div 2, high(int) div 2 + 2) == 1 + doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2) == 2 + doAssert ceilDiv(high(int) div 2 + 2, high(int) div 2) == 2 + doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2 + 1) == 1 + doAssert ceilDiv(high(int), 1) == high(int) + doAssert ceilDiv(high(int) - 1, 1) == high(int) - 1 + doAssert ceilDiv(high(int) - 1, 2) == high(int) div 2 + doAssert ceilDiv(high(int) - 1, high(int)) == 1 + doAssert ceilDiv(high(int) - 1, high(int) - 1) == 1 + doAssert ceilDiv(high(int) - 1, high(int) - 2) == 2 + doAssert ceilDiv(high(int), high(int)) == 1 + doAssert ceilDiv(high(int), high(int) - 1) == 2 + doAssert ceilDiv(255'u8, 1'u8) == 255'u8 + doAssert ceilDiv(254'u8, 2'u8) == 127'u8 + when not defined(danger): + doAssertRaises(AssertionDefect): discard ceilDiv(41, 0) + doAssertRaises(AssertionDefect): discard ceilDiv(41, -1) + doAssertRaises(AssertionDefect): discard ceilDiv(-1, 1) + doAssertRaises(AssertionDefect): discard ceilDiv(-1, -1) + doAssertRaises(AssertionDefect): discard ceilDiv(254'u8, 3'u8) + doAssertRaises(AssertionDefect): discard ceilDiv(255'u8, 2'u8) + block: # splitDecimal() tests doAssert splitDecimal(54.674).intpart == 54.0 doAssert splitDecimal(54.674).floatpart ==~ 0.674 From 8fa0decf6b4917e5559b9fd84a18825849dc11df Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 19 Aug 2021 21:54:45 +0800 Subject: [PATCH 2936/4254] fix a typo (#18715) --- compiler/semcall.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index d8dba3e6c..2478420f7 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -280,7 +280,7 @@ const proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = # Gives a detailed error message; this is separated from semOverloadedCall, - # as semOverlodedCall is already pretty slow (and we need this information + # as semOverloadedCall is already pretty slow (and we need this information # only in case of an error). if c.config.m.errorOutputs == {}: # fail fast: From 13b97291835046eb1368ff4cd240cdcc7d0a2899 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 20 Aug 2021 01:56:52 +0800 Subject: [PATCH 2937/4254] fix #18627(Program segfaults with ARC when using openArray[string]) (#18713) * fix #18627 * add testcase * rename * another * remove tyVarargs --- compiler/ast.nim | 2 +- tests/arc/topenarray.nim | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/arc/topenarray.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 0bdcc0e97..e7507c9c6 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1595,7 +1595,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = if mask != {} and propagateHasAsgn: let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) if o2.kind in {tyTuple, tyObject, tyArray, - tySequence, tySet, tyDistinct, tyOpenArray, tyVarargs}: + tySequence, tySet, tyDistinct}: o2.flags.incl mask owner.flags.incl mask diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim new file mode 100644 index 000000000..03ec7adf2 --- /dev/null +++ b/tests/arc/topenarray.nim @@ -0,0 +1,24 @@ +discard """ + input: "hi" + output: ''' +hi +Nim +''' + matrix: "--gc:arc -d:useMalloc; --gc:arc" +""" +block: # bug 18627 + proc setPosition(params: openArray[string]) = + for i in params.toOpenArray(0, params.len - 1): + echo i + + proc uciLoop() = + let params = @[readLine(stdin)] + setPosition(params) + + uciLoop() + + proc uciLoop2() = + let params = @["Nim"] + for i in params.toOpenArray(0, params.len - 1): + echo i + uciLoop2() From f2910077ac41a614154f3851f5bffc02b06124a2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 20 Aug 2021 01:13:03 -0700 Subject: [PATCH 2938/4254] sigmatch: support optional params with last block arg(s) (#18631) * sigmatch: support optional params with last block arg * add tests * works with multiple block args * cleanup * address comment --- compiler/sigmatch.nim | 14 +++++++- tests/misc/trfc405.nim | 81 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/misc/trfc405.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 674dd7e2e..465a9a51d 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2305,6 +2305,17 @@ proc incrIndexType(t: PType) = template isVarargsUntyped(x): untyped = x.kind == tyVarargs and x[0].kind == tyUntyped +proc findFirstArgBlock(m: var TCandidate, n: PNode): int = + # see https://github.com/nim-lang/RFCs/issues/405 + result = int.high + for a2 in countdown(n.len-1, 0): + # checking `nfBlockArg in n[a2].flags` wouldn't work inside templates + if n[a2].kind != nkStmtList: break + let formalLast = m.callee.n[m.callee.n.len - (n.len - a2)] + if formalLast.kind == nkSym and formalLast.sym.ast == nil: + result = a2 + else: break + proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var IntSet) = template noMatch() = @@ -2345,7 +2356,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int formalLen = m.callee.n.len formal = if formalLen > 1: m.callee.n[1].sym else: nil # current routine parameter container: PNode = nil # constructed container - + let firstArgBlock = findFirstArgBlock(m, n) while a < n.len: c.openShadowScope @@ -2441,6 +2452,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int if m.callee.n[f].kind != nkSym: internalError(c.config, n[a].info, "matches") noMatch() + if a >= firstArgBlock: f = max(f, m.callee.n.len - (n.len - a)) formal = m.callee.n[f].sym m.firstMismatch.kind = kTypeMismatch if containsOrIncl(marker, formal.position) and container.isNil: diff --git a/tests/misc/trfc405.nim b/tests/misc/trfc405.nim new file mode 100644 index 000000000..adc39b1df --- /dev/null +++ b/tests/misc/trfc405.nim @@ -0,0 +1,81 @@ +# https://github.com/nim-lang/RFCs/issues/405 + +template main = + template fn1(a = 1, b = 2, body): auto = (a, b, astToStr(body)) + let a1 = fn1(10, 20): + foo + doAssert a1 == (10, 20, "\nfoo") + + template fn2(a = 1, b = 2, body): auto = (a, b, astToStr(body)) + let a2 = fn2(a = 10): foo + doAssert a2 == (10, 2, "\nfoo") + let a2b = fn2(b = 20): foo + doAssert a2b == (1, 20, "\nfoo") + + template fn3(x: int, a = 1, b = 2, body): auto = (a, b, astToStr(body)) + let a3 = fn3(3, 10, 20): foo + doAssert a3 == (10, 20, "\nfoo") + let a3b = fn3(3, a = 10): foo + doAssert a3b == (10, 2, "\nfoo") + + template fn4(x: int, y: int, body): auto = (x, y, astToStr(body)) + let a4 = fn4(1, 2): foo + doAssert a4 == (1, 2, "\nfoo") + + template fn5(x = 1, y = 2, body: untyped = 3): auto = (x, y, astToStr(body)) + doAssert compiles(fn5(1, 2, foo)) + doAssert not compiles(fn5(1, foo)) + + block: + # with an overload + var witness = 0 + template fn6() = discard + template fn6(procname: string, body: untyped): untyped = witness.inc + fn6("abc"): discard + assert witness == 1 + + block: + # with overloads + var witness = 0 + template fn6() = discard + template fn6(a: int) = discard + template fn6(procname: string, body: untyped): untyped = witness.inc + fn6("abc"): discard + assert witness == 1 + + template fn6(b = 1.5, body: untyped): untyped = witness.inc + fn6(1.3): discard + assert witness == 2 + + block: + var witness = 0 + template fn6(a: int) = discard + template fn6(a: string) = discard + template fn6(ignore: string, b = 1.5, body: untyped): untyped = witness.inc + fn6(""): + foobar1 + foobar2 + doAssert witness == 1 + fn6(""): discard + doAssert witness == 2 + + block: # multi block args + template fn8(a = 1, b = 2, body1: untyped, body2: untyped): auto = (a, b, astToStr(body1), astToStr(body2)) + let a1 = fn8(): + foobar1 + foobar2 + do: + foobar3 + foobar4 + doAssert a1 == (1, 2, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4") + + let a2 = fn8(b = 20): + foobar1 + foobar2 + do: + foobar3 + foobar4 + doAssert a2 == (1, 20, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4") + +static: main() +main() From e52221e2967d7511f26dc020cae5fe62dcae5696 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 21 Aug 2021 02:00:04 +0800 Subject: [PATCH 2939/4254] [docs]fix an item missing (#18717) --- doc/astspec.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/astspec.txt b/doc/astspec.txt index 92212bf8c..6d44f7f7e 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -364,6 +364,7 @@ AST: nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)), nnkExprColonExpr(nnkIdent("b"), nnkIntLit(2)), nnkExprColonExpr(nnkIdent("c"), nnkIntLit(3))) + nnkTupleConstr() Since the one tuple would be syntactically identical to parentheses with an expression in them, the parser expects a trailing comma for From f0c6593412c117c7f8e19421016303416d6b8bd3 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 21 Aug 2021 14:21:06 +0800 Subject: [PATCH 2940/4254] add testcase for overloadable_enums (#18722) * add testcase for overloadable_enums * link --- tests/enum/toverloadable_enums.nim | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/enum/toverloadable_enums.nim b/tests/enum/toverloadable_enums.nim index 6f3aac3e2..2152d7fff 100644 --- a/tests/enum/toverloadable_enums.nim +++ b/tests/enum/toverloadable_enums.nim @@ -46,3 +46,32 @@ proc takeCallback(param: proc(p: int)) = discard takeCallback x echo ord v + +block: # https://github.com/nim-lang/RFCs/issues/8 + type + Enum1 = enum + A, B, C + Enum2 = enum + A, Z + + proc f(e: Enum1): int = ord(e) + proc g(e: Enum2): int = ord(e) + + proc h(e: Enum1): int = ord(e) + proc h(e: Enum2): int = ord(e) + + let fA = f(A) # Type of A is well defined + let gA = g(A) # Same as above + + let hA1 = h(Enum1.A) # A requires disambiguation + let hA2 = h(Enum2.A) # Similarly + let hA3 = h(B) + let hA4 = h(B) + let x = ord(Enum1.A) # Also + doAssert fA == 0 + doAssert gA == 0 + doAssert hA1 == 0 + doAssert hA2 == 0 + doAssert x == 0 + doAssert hA3 == 1 + doAssert hA4 == 1 From 5b26f2bd81d6fc7d48befbfb4fa3317f713af787 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 21 Aug 2021 14:22:00 +0800 Subject: [PATCH 2941/4254] fix deprecated example (#18721) --- doc/astspec.txt | 16 ++++++++++++---- tests/astspec/tastspec.nim | 22 +++++++++++++++------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/doc/astspec.txt b/doc/astspec.txt index 6d44f7f7e..6d3fa1f8c 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1082,7 +1082,7 @@ its entirety to see some of the complexities. Concrete syntax: .. code-block:: nim - type Obj[T] = object {.inheritable.} + type Obj[T] {.inheritable.} = object name: string case isFat: bool of true: @@ -1094,10 +1094,18 @@ AST: .. code-block:: nim # ... + nnkPragmaExpr( + nnkIdent("Obj"), + nnkPragma(nnkIdent("inheritable")) + ), + nnkGenericParams( + nnkIdentDefs( + nnkIdent("T"), + nnkEmpty(), + nnkEmpty()) + ), nnkObjectTy( - nnkPragma( - nnkIdent("inheritable") - ), + nnkEmpty(), nnkEmpty(), nnkRecList( # list of object parameters nnkIdentDefs( diff --git a/tests/astspec/tastspec.nim b/tests/astspec/tastspec.nim index 33a245b1b..c99d8ec79 100644 --- a/tests/astspec/tastspec.nim +++ b/tests/astspec/tastspec.nim @@ -871,11 +871,20 @@ static: scope: macro testRecCase(ast: untyped): untyped = - ast.peelOff({nnkStmtList, nnkTypeSection})[2].matchAst: - of nnkObjectTy( - nnkPragma( - ident"inheritable" + ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst: + of nnkTypeDef( + nnkPragmaExpr( + ident"Obj", + nnkPragma(ident"inheritable") ), + nnkGenericParams( + nnkIdentDefs( + ident"T", + nnkEmpty(), + nnkEmpty()) + ), + nnkObjectTy( + nnkEmpty(), nnkEmpty(), nnkRecList( # list of object parameters nnkIdentDefs( @@ -914,6 +923,7 @@ static: ident"T" ), nnkEmpty() + ) ) ) ) @@ -922,10 +932,8 @@ static: ): echo "ok" - - testRecCase: - type Obj[T] = object {.inheritable.} + type Obj[T] {.inheritable.} = object name: string case isFat: bool of true: From 061a9183f7b49289b05cf134893d703760f467a7 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 22 Aug 2021 12:21:53 +0800 Subject: [PATCH 2942/4254] replace wrt with proper word (#18724) * what does wrt mean? * clarify --- compiler/ast.nim | 2 +- compiler/docgen.nim | 2 +- compiler/sighashes.nim | 2 +- lib/core/macros.nim | 6 ++++-- tests/iter/titer3.nim | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index e7507c9c6..446c00f49 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -860,7 +860,7 @@ type case kind*: TSymKind of routineKinds: #procInstCache*: seq[PInstantiation] - gcUnsafetyReason*: PSym # for better error messages wrt gcsafe + gcUnsafetyReason*: PSym # for better error messages regarding gcsafe transformedBody*: PNode # cached body after transf pass of skLet, skVar, skField, skForVar: guard*: PSym diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d39a20aae..706b54bcd 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -172,7 +172,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile): RelativeFile = if result.isEmpty: bail() elif conf.docRoot.len > 0: # we're (currently) requiring `isAbsolute` to avoid confusion when passing - # a relative path (would it be relative wrt $PWD or to projectfile) + # a relative path (would it be relative with regard to $PWD or to projectfile) conf.globalAssert conf.docRoot.isAbsolute, arg=conf.docRoot conf.globalAssert conf.docRoot.dirExists, arg=conf.docRoot # needed because `canonicalizePath` called on `file` diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 0ff97017f..8534f4c0c 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -390,7 +390,7 @@ proc idOrSig*(s: PSym, currentModule: string, sigCollisions: var CountTable[SigHash]): Rope = if s.kind in routineKinds and s.typ != nil: # signatures for exported routines are reliable enough to - # produce a unique name and this means produced C++ is more stable wrt + # produce a unique name and this means produced C++ is more stable regarding # Nim changes: let sig = hashProc(s) result = rope($sig) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index d3eaf6298..645f5067a 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -442,9 +442,11 @@ proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.} ## Create a new ident node from a string. type - BindSymRule* = enum ## specifies how `bindSym` behaves + BindSymRule* = enum ## Specifies how `bindSym` behaves. The difference + ## between open and closed symbols can be found in + ## ``_ brClosed, ## only the symbols in current scope are bound - brOpen, ## open wrt overloaded symbols, but may be a single + brOpen, ## open for overloaded symbols, but may be a single ## symbol if not ambiguous (the rules match that of ## binding in generics) brForceOpen ## same as brOpen, but it will always be open even diff --git a/tests/iter/titer3.nim b/tests/iter/titer3.nim index 9dcfd7be5..defd56c98 100644 --- a/tests/iter/titer3.nim +++ b/tests/iter/titer3.nim @@ -26,7 +26,7 @@ var x = [[1, 2, 3], [4, 5, 6]] for y in iter1(x[0]): write(stdout, $y) writeLine(stdout, "") -# ensure closure and inline iterators have the same behaviour wrt +# ensure closure and inline iterators have the same behaviour regarding # parameter passing iterator clo(a: int): int {.closure.} = From cc08d5c2c641e9390e9e05012defc9616f5d6ba8 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 22 Aug 2021 13:40:20 +0800 Subject: [PATCH 2943/4254] fix #17898(randomPathName called twice in a row can return the same string on windows) (#18729) * close #17898 * no need to consider js --- lib/std/tempfiles.nim | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index c97db67b6..f1cfd5885 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -17,7 +17,7 @@ See also: * `mkstemp` (posix), refs https://man7.org/linux/man-pages/man3/mkstemp.3.html ]# -import os, random +import os, random, std/monotimes const @@ -96,11 +96,25 @@ proc safeOpen(filename: string): File = discard posix.close(fileHandle) # TODO handles failure when closing file raiseOSError(osLastError(), filename) + +type + NimTempPathState = object + state: Rand + isInit: bool + +var nimTempPathState {.threadvar.}: NimTempPathState + template randomPathName(length: Natural): string = var res = newString(length) - var state = initRand() + if not nimTempPathState.isInit: + var time = getMonoTime().ticks + when compileOption("threads"): + time = time xor int64(getThreadId()) + nimTempPathState.isInit = true + nimTempPathState.state = initRand(time) + for i in 0 ..< length: - res[i] = state.sample(letters) + res[i] = nimTempPathState.state.sample(letters) res proc getTempDirImpl(dir: string): string {.inline.} = From e65dc36ddd6bbb1a87a607ee8c8491732730fa95 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 22 Aug 2021 16:32:55 -0300 Subject: [PATCH 2944/4254] Implement RFC-391 (#18585) --- lib/std/jsfetch.nim | 177 ++++++++++++++++++++++---------------------- tests/config.nims | 1 - tools/kochdocs.nim | 2 +- 3 files changed, 89 insertions(+), 91 deletions(-) diff --git a/lib/std/jsfetch.nim b/lib/std/jsfetch.nim index 1e7bb4d29..a25fe7ca8 100644 --- a/lib/std/jsfetch.nim +++ b/lib/std/jsfetch.nim @@ -1,121 +1,120 @@ ## - Fetch for the JavaScript target: https://developer.mozilla.org/docs/Web/API/Fetch_API -## .. Note:: jsfetch is Experimental. jsfetch module requires `-d:nimExperimentalJsfetch` +## .. Note:: jsfetch is Experimental. when not defined(js): {.fatal: "Module jsfetch is designed to be used with the JavaScript backend.".} -when defined(nimExperimentalJsfetch): - import std/[asyncjs, jsheaders, jsformdata] - from std/httpcore import HttpMethod - from std/jsffi import JsObject +import std/[asyncjs, jsheaders, jsformdata] +from std/httpcore import HttpMethod +from std/jsffi import JsObject - type - FetchOptions* = ref object of JsRoot ## Options for Fetch API. - keepalive*: bool - metod* {.importjs: "method".}: cstring - body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*, referrerPolicy*: cstring +type + FetchOptions* = ref object of JsRoot ## Options for Fetch API. + keepalive*: bool + metod* {.importjs: "method".}: cstring + body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*, referrerPolicy*: cstring - FetchModes* = enum ## Mode options. - fmCors = "cors" - fmNoCors = "no-cors" - fmSameOrigin = "same-origin" + FetchModes* = enum ## Mode options. + fmCors = "cors" + fmNoCors = "no-cors" + fmSameOrigin = "same-origin" - FetchCredentials* = enum ## Credential options. See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials - fcInclude = "include" - fcSameOrigin = "same-origin" - fcOmit = "omit" + FetchCredentials* = enum ## Credential options. See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials + fcInclude = "include" + fcSameOrigin = "same-origin" + fcOmit = "omit" - FetchCaches* = enum ## https://developer.mozilla.org/docs/Web/API/Request/cache - fchDefault = "default" - fchNoStore = "no-store" - fchReload = "reload" - fchNoCache = "no-cache" - fchForceCache = "force-cache" + FetchCaches* = enum ## https://developer.mozilla.org/docs/Web/API/Request/cache + fchDefault = "default" + fchNoStore = "no-store" + fchReload = "reload" + fchNoCache = "no-cache" + fchForceCache = "force-cache" - FetchRedirects* = enum ## Redirects options. - frFollow = "follow" - frError = "error" - frManual = "manual" + FetchRedirects* = enum ## Redirects options. + frFollow = "follow" + frError = "error" + frManual = "manual" - FetchReferrerPolicies* = enum ## Referrer Policy options. - frpNoReferrer = "no-referrer" - frpNoReferrerWhenDowngrade = "no-referrer-when-downgrade" - frpOrigin = "origin" - frpOriginWhenCrossOrigin = "origin-when-cross-origin" - frpUnsafeUrl = "unsafe-url" + FetchReferrerPolicies* = enum ## Referrer Policy options. + frpNoReferrer = "no-referrer" + frpNoReferrerWhenDowngrade = "no-referrer-when-downgrade" + frpOrigin = "origin" + frpOriginWhenCrossOrigin = "origin-when-cross-origin" + frpUnsafeUrl = "unsafe-url" - Body* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Body - bodyUsed*: bool + Body* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Body + bodyUsed*: bool - Response* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Response - bodyUsed*, ok*, redirected*: bool - typ* {.importjs: "type".}: cstring - url*, statusText*: cstring - status*: cint - headers*: Headers - body*: Body + Response* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Response + bodyUsed*, ok*, redirected*: bool + typ* {.importjs: "type".}: cstring + url*, statusText*: cstring + status*: cint + headers*: Headers + body*: Body - Request* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Request - bodyUsed*, ok*, redirected*: bool - typ* {.importjs: "type".}: cstring - url*, statusText*: cstring - status*: cint - headers*: Headers - body*: Body + Request* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Request + bodyUsed*, ok*, redirected*: bool + typ* {.importjs: "type".}: cstring + url*, statusText*: cstring + status*: cint + headers*: Headers + body*: Body - func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response(#))".} - ## Constructor for `Response`. This does *not* call `fetch()`. Same as `new Response()`. +func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response(#))".} + ## Constructor for `Response`. This does *not* call `fetch()`. Same as `new Response()`. - func newRequest*(url: cstring): Request {.importjs: "(new Request(#))".} - ## Constructor for `Request`. This does *not* call `fetch()`. Same as `new Request()`. +func newRequest*(url: cstring): Request {.importjs: "(new Request(#))".} + ## Constructor for `Request`. This does *not* call `fetch()`. Same as `new Request()`. - func clone*(self: Response | Request): Response {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Response/clone +func clone*(self: Response | Request): Response {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Response/clone - proc text*(self: Response): Future[cstring] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Body/text +proc text*(self: Response): Future[cstring] {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Body/text - proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Body/json +proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Body/json - proc formData*(self: Body): Future[FormData] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Body/formData +proc formData*(self: Body): Future[FormData] {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Body/formData - proc unsafeNewFetchOptions*(metod, body, mode, credentials, cache, referrerPolicy: cstring; - keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring): FetchOptions {.importjs: - "{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #}".} - ## .. warning:: Unsafe `newfetchOptions`. +proc unsafeNewFetchOptions*(metod, body, mode, credentials, cache, referrerPolicy: cstring; + keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring): FetchOptions {.importjs: + "{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #}".} + ## .. warning:: Unsafe `newfetchOptions`. - func newfetchOptions*(metod: HttpMethod; body: cstring; - mode: FetchModes; credentials: FetchCredentials; cache: FetchCaches; referrerPolicy: FetchReferrerPolicies; - keepalive: bool; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring): FetchOptions = - ## Constructor for `FetchOptions`. - result = FetchOptions( - body: body, mode: $mode, credentials: $credentials, cache: $cache, referrerPolicy: $referrerPolicy, - keepalive: keepalive, redirect: $redirect, referrer: referrer, integrity: integrity, - metod: (case metod - of HttpHead: "HEAD".cstring - of HttpGet: "GET".cstring - of HttpPost: "POST".cstring - of HttpPut: "PUT".cstring - of HttpDelete: "DELETE".cstring - of HttpPatch: "PATCH".cstring - else: "GET".cstring - ) +func newfetchOptions*(metod: HttpMethod; body: cstring; + mode: FetchModes; credentials: FetchCredentials; cache: FetchCaches; referrerPolicy: FetchReferrerPolicies; + keepalive: bool; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring): FetchOptions = + ## Constructor for `FetchOptions`. + result = FetchOptions( + body: body, mode: $mode, credentials: $credentials, cache: $cache, referrerPolicy: $referrerPolicy, + keepalive: keepalive, redirect: $redirect, referrer: referrer, integrity: integrity, + metod: (case metod + of HttpHead: "HEAD".cstring + of HttpGet: "GET".cstring + of HttpPost: "POST".cstring + of HttpPut: "PUT".cstring + of HttpDelete: "DELETE".cstring + of HttpPatch: "PATCH".cstring + else: "GET".cstring ) + ) - proc fetch*(url: cstring | Request): Future[Response] {.importjs: "$1(#)".} - ## `fetch()` API, simple `GET` only, returns a `Future[Response]`. +proc fetch*(url: cstring | Request): Future[Response] {.importjs: "$1(#)".} + ## `fetch()` API, simple `GET` only, returns a `Future[Response]`. - proc fetch*(url: cstring | Request; options: FetchOptions): Future[Response] {.importjs: "$1(#, #)".} - ## `fetch()` API that takes a `FetchOptions`, returns a `Future[Response]`. +proc fetch*(url: cstring | Request; options: FetchOptions): Future[Response] {.importjs: "$1(#, #)".} + ## `fetch()` API that takes a `FetchOptions`, returns a `Future[Response]`. - func toCstring*(self: Request | Response | Body | FetchOptions): cstring {.importjs: "JSON.stringify(#)".} +func toCstring*(self: Request | Response | Body | FetchOptions): cstring {.importjs: "JSON.stringify(#)".} - func `$`*(self: Request | Response | Body | FetchOptions): string = $toCstring(self) +func `$`*(self: Request | Response | Body | FetchOptions): string = $toCstring(self) -runnableExamples("-d:nimExperimentalJsfetch -r:off"): +runnableExamples("-r:off"): import std/[asyncjs, jsconsole, jsheaders, jsformdata] from std/httpcore import HttpMethod from std/jsffi import JsObject diff --git a/tests/config.nims b/tests/config.nims index d7f6ae7f9..0327f0b76 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -33,7 +33,6 @@ hint("Processing", off) # experimental API's are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 # sync with `kochdocs.docDefines` or refactor. switch("define", "nimExperimentalAsyncjsThen") -switch("define", "nimExperimentalJsfetch") switch("define", "nimExperimentalLinenoiseExtra") switch("define", "nimPreviewFloatRoundtrip") diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 8e8085f73..fe3335c0f 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -8,7 +8,7 @@ const gaCode* = " --doc.googleAnalytics:UA-48159761-1" # errormax: subsequent errors are probably consequences of 1st one; a simple # bug could cause unlimited number of errors otherwise, hard to debug in CI. - docDefines = "-d:nimExperimentalAsyncjsThen -d:nimExperimentalJsfetch -d:nimExperimentalLinenoiseExtra" + docDefines = "-d:nimExperimentalAsyncjsThen -d:nimExperimentalLinenoiseExtra" nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off --hint:XDeclaredButNotUsed:off --warning:UnusedImport:off -d:boot --putenv:nimversion=$# $#" % [system.NimVersion, docDefines] gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" From 2d84f6e7c836bf18c0ecbe07fb413166861196ac Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 23 Aug 2021 00:13:39 +0200 Subject: [PATCH 2945/4254] Fix #18718 (#18731) Update tests --- lib/pure/stats.nim | 13 +++--- tests/stdlib/tstats.nim | 93 ++++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 47 deletions(-) diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index e46dff212..58014e503 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -42,7 +42,7 @@ runnableExamples: template `~=`(a, b: float): bool = almostEqual(a, b) - var statistics: RunningStat ## Must be var + var statistics: RunningStat # must be var statistics.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) doAssert statistics.n == 8 doAssert statistics.mean() ~= 2.0 @@ -76,7 +76,7 @@ type proc clear*(s: var RunningStat) = ## Resets `s`. s.n = 0 - s.min = toBiggestFloat(int.high) + s.min = 0.0 s.max = 0.0 s.sum = 0.0 s.mom1 = 0.0 @@ -86,11 +86,14 @@ proc clear*(s: var RunningStat) = proc push*(s: var RunningStat, x: float) = ## Pushes a value `x` for processing. - if s.n == 0: s.min = x + if s.n == 0: + s.min = x + s.max = x + else: + if s.min > x: s.min = x + if s.max < x: s.max = x inc(s.n) # See Knuth TAOCP vol 2, 3rd edition, page 232 - if s.min > x: s.min = x - if s.max < x: s.max = x s.sum += x let n = toFloat(s.n) let delta = x - s.mom1 diff --git a/tests/stdlib/tstats.nim b/tests/stdlib/tstats.nim index 37240c884..92a2ed8b8 100644 --- a/tests/stdlib/tstats.nim +++ b/tests/stdlib/tstats.nim @@ -1,46 +1,55 @@ -include stats +import std/stats -proc clean(x: float): float = - result = round(1.0e8*x).float * 1.0e-8 +proc `~=`(x, y: float): bool = + abs(x - y) < 10e-8 -var rs: RunningStat -rs.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) -doAssert(rs.n == 8) -doAssert(clean(rs.mean) == 2.0) -doAssert(clean(rs.variance()) == 1.5) -doAssert(clean(rs.varianceS()) == 1.71428571) -doAssert(clean(rs.skewness()) == 0.81649658) -doAssert(clean(rs.skewnessS()) == 1.01835015) -doAssert(clean(rs.kurtosis()) == -1.0) -doAssert(clean(rs.kurtosisS()) == -0.7000000000000001) +template main() = + var rs: RunningStat + rs.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0]) + doAssert(rs.n == 8) + doAssert rs.mean ~= 2.0 + doAssert rs.variance() ~= 1.5 + doAssert rs.varianceS() ~= 1.71428571 + doAssert rs.skewness() ~= 0.81649658 + doAssert rs.skewnessS() ~= 1.01835015 + doAssert rs.kurtosis() ~= -1.0 + doAssert rs.kurtosisS() ~= -0.7000000000000001 -var rs1, rs2: RunningStat -rs1.push(@[1.0, 2.0, 1.0, 4.0]) -rs2.push(@[1.0, 4.0, 1.0, 2.0]) -let rs3 = rs1 + rs2 -doAssert(clean(rs3.mom2) == clean(rs.mom2)) -doAssert(clean(rs3.mom3) == clean(rs.mom3)) -doAssert(clean(rs3.mom4) == clean(rs.mom4)) -rs1 += rs2 -doAssert(clean(rs1.mom2) == clean(rs.mom2)) -doAssert(clean(rs1.mom3) == clean(rs.mom3)) -doAssert(clean(rs1.mom4) == clean(rs.mom4)) -rs1.clear() -rs1.push(@[1.0, 2.2, 1.4, 4.9]) -doAssert(rs1.sum == 9.5) -doAssert(rs1.mean() == 2.375) + var rs1, rs2: RunningStat + rs1.push(@[1.0, 2.0, 1.0, 4.0]) + rs2.push(@[1.0, 4.0, 1.0, 2.0]) + let rs3 = rs1 + rs2 + doAssert rs3.variance ~= rs.variance + doAssert rs3.skewness ~= rs.skewness + doAssert rs3.kurtosis ~= rs.kurtosis + rs1 += rs2 + doAssert rs1.variance ~= rs.variance + doAssert rs1.skewness ~= rs.skewness + doAssert rs1.kurtosis ~= rs.kurtosis + rs1.clear() + rs1.push(@[1.0, 2.2, 1.4, 4.9]) + doAssert(rs1.sum == 9.5) + doAssert(rs1.mean() == 2.375) -when not defined(cpu32): - # XXX For some reason on 32bit CPUs these results differ - var rr: RunningRegress - rr.push(@[0.0, 1.0, 2.8, 3.0, 4.0], @[0.0, 1.0, 2.3, 3.0, 4.0]) - doAssert(rr.slope() == 0.9695585996955861) - doAssert(rr.intercept() == -0.03424657534246611) - doAssert(rr.correlation() == 0.9905100362239381) - var rr1, rr2: RunningRegress - rr1.push(@[0.0, 1.0], @[0.0, 1.0]) - rr2.push(@[2.8, 3.0, 4.0], @[2.3, 3.0, 4.0]) - let rr3 = rr1 + rr2 - doAssert(rr3.correlation() == rr.correlation()) - doAssert(clean(rr3.slope()) == clean(rr.slope())) - doAssert(clean(rr3.intercept()) == clean(rr.intercept())) \ No newline at end of file + when not defined(cpu32): + # XXX For some reason on 32bit CPUs these results differ + var rr: RunningRegress + rr.push(@[0.0, 1.0, 2.8, 3.0, 4.0], @[0.0, 1.0, 2.3, 3.0, 4.0]) + doAssert(rr.slope() == 0.9695585996955861) + doAssert(rr.intercept() == -0.03424657534246611) + doAssert(rr.correlation() == 0.9905100362239381) + var rr1, rr2: RunningRegress + rr1.push(@[0.0, 1.0], @[0.0, 1.0]) + rr2.push(@[2.8, 3.0, 4.0], @[2.3, 3.0, 4.0]) + let rr3 = rr1 + rr2 + doAssert(rr3.correlation() == rr.correlation()) + doAssert rr3.slope() ~= rr.slope() + doAssert rr3.intercept() ~= rr.intercept() + + block: # bug #18718 + var rs: RunningStat + rs.push(-1.0) + doAssert rs.max == -1.0 + +static: main() +main() From 8a8267e2bc36ac8070fa2842fecd9cfe53e0a9ef Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 23 Aug 2021 21:05:22 +0800 Subject: [PATCH 2946/4254] fix a typo (#18736) --- compiler/sighashes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 8534f4c0c..01a0fa784 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -166,7 +166,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = if t.n.len > 0: let oldFlags = symWithFlags.flags # Hack to prevent endless recursion - # xxx intead, use a hash table to indicate we've already visited a type, which + # xxx instead, use a hash table to indicate we've already visited a type, which # would also be more efficient. symWithFlags.flags.excl {sfAnon, sfGenSym} hashTree(c, t.n, flags + {CoHashTypeInsideNode}) From 9674ff4361468137afdbedb86196b7082aaa6efd Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 24 Aug 2021 02:13:10 +0800 Subject: [PATCH 2947/4254] make deprecated message better (#18737) --- lib/pure/mersenne.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index 6ec0d66b4..37c5085b1 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -8,7 +8,7 @@ ## random number generator. ## .. note:: The procs in this module work at compile-time. -{.deprecated: "use `std/random` instead.".} +{.deprecated: "use `std/random` instead".} runnableExamples: var rand = newMersenneTwister(uint32.high) ## must be "var" From 24178bf8aa37c179caab9e16682940e8340f2bfc Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 24 Aug 2021 17:15:26 +0200 Subject: [PATCH 2948/4254] get rid of the warnings during bootstrapping (#18741) * fix bootstrapping hints and warnings * revert removals in ccgtypes --- compiler/nimlexbase.nim | 4 ++-- compiler/semfold.nim | 2 +- compiler/sighashes.nim | 2 +- compiler/suggest.nim | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index 99d07d093..b8cb9f78a 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -104,7 +104,7 @@ proc fillBuffer(L: var TBaseLexer) = oldBufLen = L.bufLen L.bufLen = L.bufLen * 2 L.bufStorage.setLen(L.bufLen) - L.buf = L.bufStorage + L.buf = L.bufStorage.cstring assert(L.bufLen - oldBufLen == oldBufLen) charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]), oldBufLen) @@ -147,7 +147,7 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) = L.bufpos = 0 L.offsetBase = 0 L.bufStorage = newString(bufLen) - L.buf = L.bufStorage + L.buf = L.bufStorage.cstring L.bufLen = bufLen L.sentinel = bufLen - 1 L.lineStart = 0 diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 04ed73209..1f8efc4de 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -144,7 +144,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P if a.typ.kind == tyString: result = newIntNodeT(toInt128(a.strVal.len), n, idgen, g) elif a.typ.kind == tyCstring: - result = newIntNodeT(toInt128(nimCStrLen(a.strVal)), n, idgen, g) + result = newIntNodeT(toInt128(nimCStrLen(a.strVal.cstring)), n, idgen, g) else: result = newIntNodeT(toInt128(a.len), n, idgen, g) of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 01a0fa784..d02728627 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -18,7 +18,7 @@ proc `&=`(c: var MD5Context, ch: char) = # XXX suspicious code here; relies on ch being zero terminated? md5Update(c, unsafeAddr ch, 1) proc `&=`(c: var MD5Context, r: Rope) = - for l in leaves(r): md5Update(c, l, l.len) + for l in leaves(r): md5Update(c, l.cstring, l.len) proc `&=`(c: var MD5Context, i: BiggestInt) = md5Update(c, cast[cstring](unsafeAddr i), sizeof(i)) proc `&=`(c: var MD5Context, f: BiggestFloat) = diff --git a/compiler/suggest.nim b/compiler/suggest.nim index eaa30040a..84c94d793 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -32,7 +32,7 @@ # included from sigmatch.nim -import algorithm, sets, prefixmatches, lineinfos, parseutils, linter, tables +import algorithm, sets, prefixmatches, parseutils, tables from wordrecg import wDeprecated, wError, wAddr, wYield when defined(nimsuggest): From 3d1bba04ab1092630983695734d6984ddff4688c Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 24 Aug 2021 23:16:12 +0800 Subject: [PATCH 2949/4254] [minor]use `addInt` and `addFloat` (#18733) * unify int and uint * back * minor --- compiler/ic/ic.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index bd3be27f0..7387d165b 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -94,10 +94,10 @@ proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int; result.addInt m.numbers[LitId tree.nodes[pos].operand] of externUIntLit: result.add " " - result.add $cast[uint64](m.numbers[LitId tree.nodes[pos].operand]) + result.addInt cast[uint64](m.numbers[LitId tree.nodes[pos].operand]) of nkFloatLit..nkFloat128Lit: result.add " " - result.add $cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand]) + result.addFloat cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand]) else: result.add "(\n" for i in 1..(nesting+1)*2: result.add ' ' From 3aa16c1de00c723d48e48fe3fdf07a276d1b4b6a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 24 Aug 2021 21:50:40 -0700 Subject: [PATCH 2950/4254] fix RFC #341: dot-like operators are now parsed with same precedence as `.` (#18711) * fix RFC #341: dot-like operators are now parsed with same precedence as `.` * fixup * [skip ci] address comment in changelog * address comment * update grammmar * add manual entry * fixup * -d:nimPreviewDotLikeOps * address comment to unblock PR: move nimPreviewDotLikeOps out of config/config.nims --- changelog.md | 4 ++++ compiler/lineinfos.nim | 2 ++ compiler/parser.nim | 34 +++++++++++++++++++++++++++++----- doc/grammar.txt | 2 ++ doc/manual.rst | 9 +++++++++ tests/config.nims | 1 + tests/misc/trfc_341.nim | 27 +++++++++++++++++++++++++++ 7 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 tests/misc/trfc_341.nim diff --git a/changelog.md b/changelog.md index 447401cd0..3ba008cf3 100644 --- a/changelog.md +++ b/changelog.md @@ -104,6 +104,10 @@ - In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. +- With `-d:nimPreviewDotLikeOps` (default in devel), dot-like operators (operators starting with `.`, but not with `..`) + now have the same precedence as `.`, so that `a.?b.c` is now parsed as `(a.?b).c` instead of `a.?(b.c)`. + A warning is generated when a dot-like operator is used without `-d:nimPreviewDotLikeOps`. + - The allocator for Nintendo Switch, which was nonfunctional because of breaking changes in libnx, was removed, in favour of the new `-d:nimAllocPagesViaMalloc` option. diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index c64d7b9dd..fd7ce0c04 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -46,6 +46,7 @@ type warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit", warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated", + warnDotLikeOps = "DotLikeOps", warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", warnRstRedefinitionOfLabel = "RedefinitionOfLabel", warnRstUnknownSubstitutionX = "UnknownSubstitutionX", @@ -116,6 +117,7 @@ const warnXmightNotBeenInit: "'$1' might not have been initialized", warnDeprecated: "$1", warnConfigDeprecated: "config file '$1' is deprecated", + warnDotLikeOps: "$1", warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", warnUnknownMagic: "unknown magic '$1' might crash the compiler", warnRstRedefinitionOfLabel: "redefinition of label '$1'", diff --git a/compiler/parser.nim b/compiler/parser.nim index b089614b2..30180e545 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -466,6 +466,17 @@ proc dotExpr(p: var Parser, a: PNode): PNode = exprColonEqExprListAux(p, tkParRi, y) result = y +proc dotLikeExpr(p: var Parser, a: PNode): PNode = + #| dotLikeExpr = expr DOTLIKEOP optInd symbol + var info = p.parLineInfo + result = newNodeI(nkInfix, info) + optInd(p, result) + var opNode = newIdentNodeP(p.tok.ident, p) + getTok(p) + result.add(opNode) + result.add(a) + result.add(parseSymbol(p, smAfterDot)) + proc qualifiedIdent(p: var Parser): PNode = #| qualifiedIdent = symbol ('.' optInd symbol)? result = parseSymbol(p) @@ -788,10 +799,15 @@ proc commandExpr(p: var Parser; r: PNode; mode: PrimaryMode): PNode = p.hasProgress = false result.add commandParam(p, isFirstParam, mode) +proc isDotLike(tok: Token): bool = + result = tok.tokType == tkOpr and tok.ident.s.len > 1 and + tok.ident.s[0] == '.' and tok.ident.s[1] != '.' + proc primarySuffix(p: var Parser, r: PNode, baseIndent: int, mode: PrimaryMode): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' #| | '.' optInd symbol generalizedLit? + #| | DOTLIKEOP optInd symbol generalizedLit? #| | '[' optInd exprColonEqExprList optPar ']' #| | '{' optInd exprColonEqExprList optPar '}' #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax @@ -840,11 +856,19 @@ proc primarySuffix(p: var Parser, r: PNode, # `foo ref` or `foo ptr`. Unfortunately, these two are also # used as infix operators for the memory regions feature and # the current parsing rules don't play well here. - if p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): - # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet - # solution, but pragmas.nim can't handle that - result = commandExpr(p, result, mode) - break + let isDotLike2 = p.tok.isDotLike + if isDotLike2 and p.lex.config.isDefined("nimPreviewDotLikeOps"): + # synchronize with `tkDot` branch + result = dotLikeExpr(p, result) + result = parseGStrLit(p, result) + else: + if isDotLike2: + parMessage(p, warnDotLikeOps, "dot-like operators will be parsed differently with `-d:nimPreviewDotLikeOps`") + if p.inPragma == 0 and (isUnary(p.tok) or p.tok.tokType notin {tkOpr, tkDotDot}): + # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet + # solution, but pragmas.nim can't handle that + result = commandExpr(p, result, mode) + break else: break diff --git a/doc/grammar.txt b/doc/grammar.txt index d4f4a0515..f58621b97 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -29,6 +29,7 @@ exprList = expr ^+ comma exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? dotExpr = expr '.' optInd (symbol | '[:' exprList ']') explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? +dotLikeExpr = expr DOTLIKEOP optInd symbol qualifiedIdent = symbol ('.' optInd symbol)? setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' castExpr = 'cast' ('[' optInd typeDesc optPar ']' '(' optInd expr optPar ')') / @@ -56,6 +57,7 @@ tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' primarySuffix = '(' (exprColonEqExpr comma?)* ')' | '.' optInd symbol generalizedLit? + | DOTLIKEOP optInd symbol generalizedLit? | '[' optInd exprColonEqExprList optPar ']' | '{' optInd exprColonEqExprList optPar '}' | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax diff --git a/doc/manual.rst b/doc/manual.rst index 9c7c219e9..72d50a901 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -748,6 +748,7 @@ has the second-lowest precedence. Otherwise, precedence is determined by the first character. + ================ ======================================================= ================== =============== Precedence level Operators First character Terminal symbol ================ ======================================================= ================== =============== @@ -783,6 +784,14 @@ of a call or whether it is parsed as a tuple constructor: .. code-block:: nim echo (1, 2) # pass the tuple (1, 2) to echo +Dot-like operators +------------------ + +Terminal symbol in the grammar: `DOTLIKEOP`. + +Dot-like operators are operators starting with `.`, but not with `..`, for e.g. `.?`; +they have the same precedence as `.`, so that `a.?b.c` is parsed as `(a.?b).c` instead of `a.?(b.c)`. + Grammar ------- diff --git a/tests/config.nims b/tests/config.nims index 0327f0b76..86787db1d 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -36,3 +36,4 @@ switch("define", "nimExperimentalAsyncjsThen") switch("define", "nimExperimentalLinenoiseExtra") switch("define", "nimPreviewFloatRoundtrip") +switch("define", "nimPreviewDotLikeOps") diff --git a/tests/misc/trfc_341.nim b/tests/misc/trfc_341.nim new file mode 100644 index 000000000..37cf675c6 --- /dev/null +++ b/tests/misc/trfc_341.nim @@ -0,0 +1,27 @@ +# test for https://github.com/nim-lang/RFCs/issues/341 +import std/json +import std/jsonutils +import std/macros + +macro fn1(a: untyped): string = newLit a.lispRepr + +doAssert fn1(a.?b.c) == """(DotExpr (Infix (Ident ".?") (Ident "a") (Ident "b")) (Ident "c"))""" + +template `.?`(a: JsonNode, b: untyped{ident}): JsonNode = + a[astToStr(b)] + +proc identity[T](a: T): T = a +proc timesTwo[T](a: T): T = a * 2 + +template main = + let a = (a1: 1, a2: "abc", a3: (a4: 2.5)) + let j = a.toJson + doAssert j.?a1.getInt == 1 + doAssert j.?a3.?a4.getFloat == 2.5 + doAssert j.?a3.?a4.getFloat.timesTwo == 5.0 + doAssert j.?a3.identity.?a4.getFloat.timesTwo == 5.0 + doAssert j.identity.?a3.identity.?a4.identity.getFloat.timesTwo == 5.0 + doAssert j.identity.?a3.?a4.identity.getFloat.timesTwo == 5.0 + +static: main() +main() From c70e4040bd69e1ee32b6c676dbfc763c7cf4df37 Mon Sep 17 00:00:00 2001 From: Dankr4d Date: Wed, 25 Aug 2021 19:27:00 +0200 Subject: [PATCH 2951/4254] fixes #14511 [backport:1.4] (#18732) * fixes #14511 [backport:1.4] Signed-off-by: Dankr4d * Replaced fix with code from alaviss, for better readability, with small changes. Signed-off-by: Dankr4d * - Specified output in test. Signed-off-by: Dankr4d * Replaced case in nnkRecCase with a simpler version, which just adds the last son. Signed-off-by: Dankr4d * Update tests/macros/t14511.nim * Update tests/macros/t14511.nim Co-authored-by: Andreas Rumpf --- lib/core/macros.nim | 21 ++++++++-------- tests/macros/t14511.nim | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 tests/macros/t14511.nim diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 645f5067a..806ea7e31 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1541,18 +1541,17 @@ proc customPragmaNode(n: NimNode): NimNode = for i in 0.. 0: var identDefs = identDefsStack.pop() - if identDefs.kind == nnkRecCase: - identDefsStack.add(identDefs[0]) - for i in 1.. Date: Wed, 25 Aug 2021 22:04:18 -0700 Subject: [PATCH 2952/4254] followup #18711 grammar_nanny now reports unused non-terminals (#18746) * followup #18711 cleanup unused grammar rules * make tools/grammar_nanny.nim report unused terminals * revert removal of some grammar comments --- tools/grammar_nanny.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim index 397041559..5120ef976 100644 --- a/tools/grammar_nanny.nim +++ b/tools/grammar_nanny.nim @@ -4,7 +4,7 @@ import std / [strutils, sets] import ".." / compiler / [ - llstream, ast, lexer, options, msgs, idents, + llstream, lexer, options, msgs, idents, lineinfos, pathutils] proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = @@ -35,6 +35,10 @@ proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = usedSyms.incl word else: rawGetTok(L, tok) + for u in declaredSyms: + if u notin usedSyms: + echo "Unused non-terminal: ", u + for u in usedSyms: if u notin declaredSyms: echo "Undeclared non-terminal: ", u From 041edaa1df96fc7963f01bf5048f2bee86b6b363 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 26 Aug 2021 18:07:54 -0300 Subject: [PATCH 2953/4254] Implement RFC-413 (#18749) * Implement RFC 413 * Implement RFC 413 * Implement RFC 413 * Implement RFC 413 * https://github.com/nim-lang/Nim/pull/18749#discussion_r696320995 * Update lib/js/dom_extensions.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update lib/js/dom_extensions.nim * https://github.com/nim-lang/Nim/pull/18749#discussion_r696913310 Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Andreas Rumpf --- changelog.md | 3 +++ lib/js/dom.nim | 3 +++ lib/js/dom_extensions.nim | 6 ++---- tests/effects/tstrict_funcs_imports_js.nim | 1 - 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 3ba008cf3..65ae61833 100644 --- a/changelog.md +++ b/changelog.md @@ -371,6 +371,9 @@ - Added `dom.setInterval`, `dom.clearInterval` overloads. +- Merged `dom_extensions` module into `dom` module, + it was a module with a single line, see https://github.com/nim-lang/RFCs/issues/413 + - Allow reading parameters when compiling for Nintendo Switch. - Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 3f0b9f630..aca79faca 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1771,3 +1771,6 @@ since (1, 3): ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL proc readAsText*(f: FileReader, b: Blob|File, encoding = cstring"UTF-8") {.importcpp: "#.readAsText(#, #)".} ## https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText + +since (1, 5): + proc elementsFromPoint*(n: DocumentOrShadowRoot; x, y: float): seq[Element] {.importcpp.} diff --git a/lib/js/dom_extensions.nim b/lib/js/dom_extensions.nim index a1ceff5b4..c15a03195 100644 --- a/lib/js/dom_extensions.nim +++ b/lib/js/dom_extensions.nim @@ -1,5 +1,3 @@ import std/dom - -{.push importcpp.} -proc elementsFromPoint*(n: DocumentOrShadowRoot; x, y: float): seq[Element] -{.pop.} +export elementsFromPoint +{.deprecated: "use `std/dom` instead".} diff --git a/tests/effects/tstrict_funcs_imports_js.nim b/tests/effects/tstrict_funcs_imports_js.nim index b7fcd343a..667887ff0 100644 --- a/tests/effects/tstrict_funcs_imports_js.nim +++ b/tests/effects/tstrict_funcs_imports_js.nim @@ -7,7 +7,6 @@ discard """ import asyncjs, dom, - dom_extensions, jsconsole, jsffi, jsre From 5eba3725707df0f62dcf9c380eaa518635b0f0c0 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 27 Aug 2021 17:50:06 +0800 Subject: [PATCH 2954/4254] [minor] break loops if it is ambiguous (#18745) * [minor] break loops if it is ambiguous * Update compiler/lookups.nim Co-authored-by: Timothee Cour Co-authored-by: Timothee Cour --- compiler/lookups.nim | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 331eef525..4c072eed8 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -181,13 +181,14 @@ proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PS if overloadableEnums notin c.features: symSet.excl skEnumField result = nil - for im in c.imports.mitems: - for s in symbols(im, marked, name, c.graph): - if result == nil: - result = s - else: - if s.kind notin symSet or result.kind notin symSet: + block outer: + for im in c.imports.mitems: + for s in symbols(im, marked, name, c.graph): + if result == nil: + result = s + elif s.kind notin symSet or result.kind notin symSet: ambiguous = true + break outer proc searchInScopes*(c: PContext, s: PIdent; ambiguous: var bool): PSym = for scope in allScopes(c.currentScope): From 719718df2f98f2bd9aa4286ff8aeac3f02e4d46c Mon Sep 17 00:00:00 2001 From: Miran Date: Sat, 28 Aug 2021 08:27:56 +0200 Subject: [PATCH 2955/4254] more minor bootstrapping cleanups (#18759) --- compiler/ccgtypes.nim | 3 --- compiler/cgen.nim | 1 - compiler/vmops.nim | 1 - 3 files changed, 5 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index d05c4cd8b..492e1f181 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -12,7 +12,6 @@ # ------------------------- Name Mangling -------------------------------- import sighashes, modulegraphs -from lowerings import createObj proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope @@ -256,8 +255,6 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) = m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope]) # see `testCodegenABICheck` for example error message it generates -from ccgutils import ccgIntroducedPtr -export ccgIntroducedPtr proc fillResult(conf: ConfigRef; param: PNode) = fillLoc(param.sym.loc, locParam, param, ~"Result", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f55da7f65..a06a87172 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -23,7 +23,6 @@ when not defined(leanCompiler): import strutils except `%` # collides with ropes.`%` from ic / ic import ModuleBackendFlag -from modulegraphs import ModuleGraph, PPassContext import dynlib when not declared(dynlib.libCandidates): diff --git a/compiler/vmops.nim b/compiler/vmops.nim index a1a4996b2..08225b065 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -29,7 +29,6 @@ from std/hashes import hash from std/osproc import nil from system/formatfloat import addFloatRoundtrip, addFloatSprintf -from sighashes import symBodyDigest # There are some useful procs in vmconv. import vmconv From 014edde36a2f61b0a232ceb4800681a2ce261759 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 28 Aug 2021 16:34:27 -0700 Subject: [PATCH 2956/4254] followup #18759: make compiler build cleanly with 0 warnings/hints (#18764) --- compiler/semtypes.nim | 2 -- compiler/vmops.nim | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index cb7f847a9..9f7a17a53 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -10,8 +10,6 @@ # this module does the semantic checking of type declarations # included from sem.nim -import math - const errStringOrIdentNodeExpected = "string or ident node expected" errStringLiteralExpected = "string literal expected" diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 08225b065..e287dd41d 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -15,10 +15,12 @@ from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, lgamma when declared(math.copySign): - from std/math import copySign + # pending bug #18762, avoid renaming math + from std/math as math2 import copySign when declared(math.signbit): - from std/math import signbit + # ditto + from std/math as math3 import signbit from std/os import getEnv, existsEnv, delEnv, putEnv, dirExists, fileExists, walkDir, getAppFilename, raiseOSError, osLastError From c07d8da7b9d491500096dbd4c224f5762cbf89ac Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 29 Aug 2021 15:18:54 +0800 Subject: [PATCH 2957/4254] add missing docs (#18758) --- lib/nimrtl.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim index 301ffb43b..93349b287 100644 --- a/lib/nimrtl.nim +++ b/lib/nimrtl.nim @@ -26,6 +26,7 @@ batchable: false ## * unicode ## * pegs ## * ropes +## * cstrutils ## when system.appType != "lib": From 0ddd9519c0007b705d70b5a75b634831396dd904 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sun, 29 Aug 2021 10:42:52 +0200 Subject: [PATCH 2958/4254] Remove `Covariance` section from the experimental manual (#18688) * Remove `Covariance` section * Add blank lines after `.. code-block::` * Fix CI? --- doc/manual_experimental.rst | 164 ++++++++++++++---------------------- 1 file changed, 63 insertions(+), 101 deletions(-) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 3272a4d0d..458512292 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -70,6 +70,7 @@ type `void` are treated as non-existent, `void` as a return type means that the procedure does not return a value: .. code-block:: nim + proc nothing(x, y: void): void = echo "ha" @@ -78,6 +79,7 @@ the procedure does not return a value: The `void` type is particularly useful for generic code: .. code-block:: nim + proc callProc[T](p: proc (x: T), x: T) = when T is void: p() @@ -93,6 +95,7 @@ The `void` type is particularly useful for generic code: However, a `void` type cannot be inferred in generic code: .. code-block:: nim + callProc(emptyProc) # Error: type mismatch: got (proc ()) # but expected one of: @@ -102,106 +105,6 @@ The `void` type is only valid for parameters and return types; other symbols cannot have the type `void`. - -Covariance -========== - -Covariance in Nim can be introduced only through pointer-like types such -as `ptr` and `ref`. Sequence, Array and OpenArray types, instantiated -with pointer-like types will be considered covariant if and only if they -are also immutable. The introduction of a `var` modifier or additional -`ptr` or `ref` indirections would result in invariant treatment of -these types. - -`proc` types are currently always invariant, but future versions of Nim -may relax this rule. - -User-defined generic types may also be covariant with respect to some of -their parameters. By default, all generic params are considered invariant, -but you may choose the apply the prefix modifier `in` to a parameter to -make it contravariant or `out` to make it covariant: - -.. code-block:: nim - type - AnnotatedPtr[out T] = - metadata: MyTypeInfo - p: ref T - - RingBuffer[out T] = - startPos: int - data: seq[T] - - Action {.importcpp: "std::function".} [in T] = object - -When the designated generic parameter is used to instantiate a pointer-like -type as in the case of `AnnotatedPtr` above, the resulting generic type will -also have pointer-like covariance: - -.. code-block:: nim - type - GuiWidget = object of RootObj - Button = object of GuiWidget - ComboBox = object of GuiWidget - - var - widgetPtr: AnnotatedPtr[GuiWidget] - buttonPtr: AnnotatedPtr[Button] - - ... - - proc drawWidget[T](x: AnnotatedPtr[GuiWidget]) = ... - - # you can call procs expecting base types by supplying a derived type - drawWidget(buttonPtr) - - # and you can convert more-specific pointer types to more general ones - widgetPtr = buttonPtr - -Just like with regular pointers, covariance will be enabled only for immutable -values: - -.. code-block:: nim - proc makeComboBox[T](x: var AnnotatedPtr[GuiWidget]) = - x.p = new(ComboBox) - - makeComboBox(buttonPtr) # Error, AnnotatedPtr[Button] cannot be modified - # to point to a ComboBox - -On the other hand, in the `RingBuffer` example above, the designated generic -param is used to instantiate the non-pointer `seq` type, which means that -the resulting generic type will have covariance that mimics an array or -sequence (i.e. it will be covariant only when instantiated with `ptr` and -`ref` types): - -.. code-block:: nim - - type - Base = object of RootObj - Derived = object of Base - - proc consumeBaseValues(b: RingBuffer[Base]) = ... - - var derivedValues: RingBuffer[Derived] - - consumeBaseValues(derivedValues) # Error, Base and Derived values may differ - # in size - - proc consumeBasePointers(b: RingBuffer[ptr Base]) = ... - - var derivedPointers: RingBuffer[ptr Derived] - - consumeBaseValues(derivedPointers) # This is legal - -Please note that Nim will treat the user-defined pointer-like types as -proper alternatives to the built-in pointer types. That is, types such -as `seq[AnnotatedPtr[T]]` or `RingBuffer[AnnotatedPtr[T]]` will also be -considered covariant and you can create new pointer-like types by instantiating -other user-defined pointer-like types. - -The contravariant parameters introduced with the `in` modifier are currently -useful only when interfacing with imported types having such semantics. - - Automatic dereferencing ======================= @@ -209,6 +112,7 @@ Automatic dereferencing is performed for the first argument of a routine call. This feature has to be enabled via `{.experimental: "implicitDeref".}`: .. code-block:: nim + {.experimental: "implicitDeref".} proc depth(x: NodeObj): int = ... @@ -219,6 +123,7 @@ This feature has to be enabled via `{.experimental: "implicitDeref".}`: echo n.depth # no need to write n[].depth either + Code reordering =============== @@ -281,6 +186,7 @@ statement) can have their entire initialization statement reordered. Be wary of what code is executed at the top level: .. code-block:: nim + {.experimental: "codeReordering".} proc a() = @@ -300,6 +206,7 @@ what code is executed at the top level: code is the same as it would be with code reordering disabled. .. code-block:: nim + {.experimental: "codeReordering".} proc x() = @@ -313,6 +220,7 @@ It is important to note that reordering *only* works for symbols at top level scope. Therefore, the following will *fail to compile:* .. code-block:: nim + {.experimental: "codeReordering".} proc a() = @@ -331,6 +239,7 @@ has different names. This does not need an `experimental` switch, but is an unstable feature. .. code-block:: Nim + proc foo(x: int) = echo "Using x: ", x proc foo(y: int) = @@ -349,6 +258,7 @@ As a special more convenient notation, proc expressions involved in procedure calls can use the `do` keyword: .. code-block:: nim + sort(cities) do (x,y: string) -> int: cmp(x.len, y.len) @@ -371,6 +281,7 @@ parentheses is just a block of code. The `do` notation can be used to pass multiple blocks to a macro: .. code-block:: nim + macro performWithUndo(task, undo: untyped) = ... performWithUndo do: @@ -380,7 +291,6 @@ pass multiple blocks to a macro: # code to undo it - Special Operators ================= @@ -404,6 +314,7 @@ the expression, where the unknown field or proc name is passed to an `untyped` parameter: .. code-block:: nim + a.b # becomes `.`(a, b) a.b(c, d) # becomes `.`(a, b, c, d) @@ -411,6 +322,7 @@ The matched dot operators can be symbols of any callable kind (procs, templates and macros), depending on the desired effect: .. code-block:: nim + template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)] var js = parseJson("{ x: 1, y: 2}") @@ -435,6 +347,7 @@ operator `.=` This operator will be matched against assignments to missing fields. .. code-block:: nim + a.b = c # becomes `.=`(a, b, c) Call operator @@ -445,6 +358,7 @@ for existing routines. The experimental `callOperator` switch must be enabled to use this operator. .. code-block:: nim + {.experimental: "callOperator".} template `()`(a: int, b: float): untyped = $(a, b) @@ -480,6 +394,7 @@ All types for which `nil` is a valid value can be annotated with the `not nil` annotation to exclude `nil` as a valid value: .. code-block:: nim + {.experimental: "notnil".} type @@ -502,6 +417,7 @@ here. .. include:: manual_experimental_strictnotnil.rst + Concepts ======== @@ -511,6 +427,7 @@ arbitrary set of requirements that the matched type must satisfy. Concepts are written in the following form: .. code-block:: nim + type Comparable = concept x, y (x < y) is bool @@ -536,6 +453,7 @@ instance. You can also apply the `type` modifier to create a named instance of the type itself: .. code-block:: nim + type MyConcept = concept x, var v, ref r, ptr p, static s, type T ... @@ -545,6 +463,7 @@ and parameters are expected. This provides a more convenient way to check for the presence of callable symbols with specific signatures: .. code-block:: nim + type OutputStream = concept var s s.write(string) @@ -555,6 +474,7 @@ type, following the `concept` keyword is also considered to have the explicit modifier and will be matched only as a type. .. code-block:: nim + type # Let's imagine a user-defined casting framework with operators # such as `val.to(string)` and `val.to(JSonValue)`. We can test @@ -592,6 +512,7 @@ concept and, as a result, a wrong overload is selected, you can apply the `explain` pragma to either the concept body or a particular call-site. .. code-block:: nim + type MyConcept {.explain.} = concept ... @@ -607,6 +528,7 @@ Generic concepts and type binding rules The concept types can be parametric just like the regular generic types: .. code-block:: nim + ### matrixalgo.nim import std/typetraits @@ -680,6 +602,7 @@ Unbound static params will be inferred from expressions involving the `==` operator and also when types dependent on them are being matched: .. code-block:: nim + type MatrixReducer[M, N: static int; T] = concept x x.reduce(SquareMatrix[N, T]) is array[M, int] @@ -694,6 +617,7 @@ matched without permanently inferring it. This may be useful when you need to match several procs accepting the same wide class of types: .. code-block:: nim + type Enumerable[T] = concept e for v in e: @@ -716,6 +640,7 @@ types used in multiple signatures, without actually requiring any concrete types, thus allowing you to encode implementation-defined types: .. code-block:: nim + type MyConcept = concept x type T1 = auto @@ -776,6 +701,7 @@ accessible through the dot operator in procs where the concept was successfully matched to a concrete type: .. code-block:: nim + type DateTime = concept t1, t2, type T const Min = T.MinDate @@ -810,6 +736,7 @@ one. As an alternative way of defining concept refinements, you can use the object inheritance syntax involving the `of` keyword: .. code-block:: nim + type Graph = concept g, type G of EquallyComparable, Copyable type @@ -853,6 +780,7 @@ object inheritance syntax involving the `of` keyword: the concept body: .. code-block:: nim + type Stringable = concept x $x is string @@ -904,6 +832,7 @@ object inheritance syntax involving the `of` keyword: types to the corresponding VTable type. .. code-block:: nim + type IntEnumerable = vtref Enumerable[int] @@ -970,6 +899,7 @@ language may weaken this restriction.) The signature has to be: .. code-block:: nim + proc `=deepCopy`(x: T): T This mechanism will be used by most data structures that support shared memory @@ -1037,6 +967,7 @@ phase of the compiler: This means they provide an easy way to enhance the compilation pipeline with user defined optimizations: .. code-block:: nim + template optMul{`*`(a, 2)}(a: int): int = a+a let x = 3 @@ -1059,6 +990,7 @@ Unfortunately optimizations are hard to get right and even the tiny example is **wrong**: .. code-block:: nim + template optMul{`*`(a, 2)}(a: int): int = a+a proc f(): int = @@ -1071,6 +1003,7 @@ We cannot duplicate 'a' if it denotes an expression that has a side effect! Fortunately Nim supports side effect analysis: .. code-block:: nim + template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a proc f(): int = @@ -1088,11 +1021,13 @@ cannot really do that however as the following code only swaps arguments blindly: .. code-block:: nim + template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a What optimizers really need to do is a *canonicalization*: .. code-block:: nim + template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a The `int{lit}` parameter pattern matches against an expression of @@ -1152,6 +1087,7 @@ but also to every other bound parameter; syntactically they need to occur after the ordinary AST predicates: .. code-block:: nim + template ex{a = b + c}(a: int{noalias}, b, c: int) = # this transformation is only valid if 'b' and 'c' do not alias 'a': a = b @@ -1160,6 +1096,7 @@ the ordinary AST predicates: Another example: .. code-block:: nim + proc somefunc(s: string) = assert s == "variable" proc somefunc(s: string{nkStrLit}) = assert s == "literal" proc somefunc(s: string{nkRStrLit}) = assert s == r"raw" @@ -1189,6 +1126,7 @@ The `|` operator The `|` operator if used as infix operator creates an ordered choice: .. code-block:: nim + template t{0|1}(): untyped = 3 let a = 1 # outputs 3: @@ -1198,6 +1136,7 @@ The matching is performed after the compiler performed some optimizations like constant folding, so the following does not work: .. code-block:: nim + template t{0|1}(): untyped = 3 # outputs 1: echo 1 @@ -1215,6 +1154,7 @@ A pattern expression can be bound to a pattern parameter via the `expr{param}` notation: .. code-block:: nim + template t{(0|1|2){x}}(x: untyped): untyped = x+1 let a = 1 # outputs 2: @@ -1227,6 +1167,7 @@ The `~` operator The `~` operator is the **not** operator in patterns: .. code-block:: nim + template t{x = (~x){y} and (~x){z}}(x, y, z: bool) = x = y if x: x = z @@ -1246,6 +1187,7 @@ The `*` operator can *flatten* a nested binary expression like `a & b & c` to `&(a, b, c)`: .. code-block:: nim + var calls = 0 @@ -1270,6 +1212,7 @@ which is flattened into a call expression; thus the invocation of `optConc` produces: .. code-block:: nim + `&&`("my", space & "awe", "some ", "concat") @@ -1280,6 +1223,7 @@ The `**` is much like the `*` operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation: .. code-block:: nim + import std/macros type @@ -1324,6 +1268,7 @@ parameter is of the type `varargs` it is treated specially and it can match 0 or more arguments in the AST to be matched against: .. code-block:: nim + template optWrite{ write(f, x) ((write|writeLine){w})(f, y) @@ -1339,6 +1284,7 @@ The following example shows how some simple partial evaluation can be implemented with term rewriting: .. code-block:: nim + proc p(x, y: int; cond: bool): int = result = if cond: x + y else: x - y @@ -1352,6 +1298,7 @@ Example: Hoisting The following example shows how some form of hoisting can be implemented: .. code-block:: nim + import std/pegs template optPeg{peg(pattern)}(pattern: string{lit}): Peg = @@ -1375,6 +1322,7 @@ Parameter constraints can also be used for ordinary routine parameters; these constraints affect ordinary overloading resolution then: .. code-block:: nim + proc optLit(a: string{lit|`const`}) = echo "string literal" proc optLit(a: string) = @@ -1426,6 +1374,7 @@ Spawn statement `spawn`:idx: can be used to pass a task to the thread pool: .. code-block:: nim + import std/threadpool proc processLine(line: string) = @@ -1458,6 +1407,7 @@ with the `^` operator is **blocking**. However, one can use `blockUntilAny` to wait on multiple flow variables at the same time: .. code-block:: nim + import std/threadpool, ... # wait until 2 out of 3 servers received the update: @@ -1552,6 +1502,7 @@ Protecting global variables Object fields and global variables can be annotated via a `guard` pragma: .. code-block:: nim + var glock: TLock var gdata {.guard: glock.}: int @@ -1559,6 +1510,7 @@ The compiler then ensures that every access of `gdata` is within a `locks` section: .. code-block:: nim + proc invalid = # invalid: unguarded access: echo gdata @@ -1577,6 +1529,7 @@ semantics and should not be used directly! It should only be used in templates that also implement some form of locking at runtime: .. code-block:: nim + template lock(a: TLock; body: untyped) = pthread_mutex_lock(a) {.locks: [a].}: @@ -1590,6 +1543,7 @@ The guard does not need to be of any particular type. It is flexible enough to model low level lockfree mechanisms: .. code-block:: nim + var dummyLock {.compileTime.}: int var atomicCounter {.guard: dummyLock.}: int @@ -1617,6 +1571,7 @@ Since objects can reside on the heap or on the stack this greatly enhances the expressivity of the language: .. code-block:: nim + type ProtectedCounter = object v {.guard: L.}: int @@ -1631,6 +1586,7 @@ The access to field `x.v` is allowed since its guard `x.L` is active. After template expansion, this amounts to: .. code-block:: nim + proc incCounters(counters: var openArray[ProtectedCounter]) = for i in 0..counters.high: pthread_mutex_lock(counters[i].L) @@ -1651,6 +1607,7 @@ Two paths are considered equivalent if they are syntactically the same. This means the following compiles (for now) even though it really should not: .. code-block:: nim + {.locks: [a[i].L].}: inc i access a[i].v @@ -1671,6 +1628,7 @@ of the same level can only be acquired *at the same time* within a single `locks` section: .. code-block:: nim + var a, b: TLock[2] var x: TLock[1] # invalid locking order: TLock[1] cannot be acquired before TLock[2]: @@ -1697,6 +1655,7 @@ the runtime check is required to ensure a global ordering for two locks `a` and `b` of the same lock level: .. code-block:: nim + template multilock(a, b: ptr TLock; body: untyped) = if cast[ByteAddress](a) < cast[ByteAddress](b): pthread_mutex_lock(a) @@ -1717,6 +1676,7 @@ level. This then means that the routine may acquire locks of up to this level. This is essential so that procs can be called within a `locks` section: .. code-block:: nim + proc p() {.locks: 3.} = discard var a: TLock[4] @@ -1739,6 +1699,7 @@ cannot be inferred statically, leading to compiler warnings. By using having unknown lock level as well: .. code-block:: nim + type SomeBase* = ref object of RootObj type SomeDerived* = ref object of SomeBase memberProc*: proc () @@ -1761,6 +1722,7 @@ e.g. when rewriting term to same term plus extra content. e.g. with given example `echo("ab")` will be rewritten just once: .. code-block:: nim + template pwnEcho{echo(x)}(x: untyped) = {.noRewrite.}: echo("pwned!") From fa7c1aa8647aa97a4a204751db727c3cbeded749 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 29 Aug 2021 06:54:07 -0700 Subject: [PATCH 2959/4254] move PNode.comment to a side channel, reducing memory usage during compilation by a factor 1.25x (#18760) * move PNode.comment so a side channel, reducing memory usage * fix a bug * fixup * use sfHasComment to speedup comment lookups * fix for IC * Update compiler/parser.nim Co-authored-by: Andreas Rumpf --- compiler/ast.nim | 77 +++++++++++++++++++++++++++++++------------ compiler/commands.nim | 3 +- compiler/parser.nim | 14 +++++--- 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 446c00f49..5893a5671 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,7 @@ # abstract syntax tree + symbol table import - lineinfos, hashes, options, ropes, idents, int128 + lineinfos, hashes, options, ropes, idents, int128, tables from strutils import toLowerAscii export int128 @@ -497,6 +497,7 @@ type nfExecuteOnReload # A top-level statement that will be executed during reloads nfLastRead # this node is a last read nfFirstWrite# this node is a first write + nfHasComment # node has a comment TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43) @@ -774,7 +775,6 @@ type ident*: PIdent else: sons*: TNodeSeq - comment*: string TStrTable* = object # a table[PIdent] of PSym counter*: int @@ -991,6 +991,38 @@ type TImplication* = enum impUnknown, impNo, impYes +template nodeId(n: PNode): int = cast[int](n) + +type Gconfig = object + # we put comments in a side channel to avoid increasing `sizeof(TNode)`, which + # reduces memory usage given that `PNode` is the most allocated type by far. + comments: Table[int, string] # nodeId => comment + useIc*: bool + +var gconfig {.threadvar.}: Gconfig + +proc setUseIc*(useIc: bool) = gconfig.useIc = useIc + +proc comment*(n: PNode): string = + if nfHasComment in n.flags and not gconfig.useIc: + # IC doesn't track comments, see `packed_ast`, so this could fail + result = gconfig.comments[n.nodeId] + +proc `comment=`*(n: PNode, a: string) = + let id = n.nodeId + if a.len > 0: + # if needed, we could periodically cleanup gconfig.comments when its size increases, + # to ensure only live nodes (and with nfHasComment) have an entry in gconfig.comments; + # for compiling compiler, the waste is very small: + # num calls to newNodeImpl: 14984160 (num of PNode allocations) + # size of gconfig.comments: 33585 + # num of nodes with comments that were deleted and hence wasted: 3081 + n.flags.incl nfHasComment + gconfig.comments[id] = a + elif nfHasComment in n.flags: + n.flags.excl nfHasComment + gconfig.comments.del(id) + # 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. @@ -1207,9 +1239,17 @@ when defined(useNodeIds): const nodeIdToDebug* = -1 # 2322968 var gNodeId: int -proc newNode*(kind: TNodeKind): PNode = - ## new node with unknown line info, no type, and no children - result = PNode(kind: kind, info: unknownLineInfo) +template newNodeImpl(info2) = + result = PNode(kind: kind, info: info2) + when false: + # this would add overhead, so we skip it; it results in a small amount of leaked entries + # for old PNode that gets re-allocated at the same address as a PNode that + # has `nfHasComment` set (and an entry in that table). Only `nfHasComment` + # should be used to test whether a PNode has a comment; gconfig.comments + # can contain extra entries for deleted PNode's with comments. + gconfig.comments.del(cast[int](result)) + +template setIdMaybe() = when defined(useNodeIds): result.id = gNodeId if result.id == nodeIdToDebug: @@ -1217,27 +1257,22 @@ proc newNode*(kind: TNodeKind): PNode = writeStackTrace() inc gNodeId +proc newNode*(kind: TNodeKind): PNode = + ## new node with unknown line info, no type, and no children + newNodeImpl(unknownLineInfo) + setIdMaybe() + proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = ## new node with line info, no type, and no children - result = PNode(kind: kind, info: info) - when defined(useNodeIds): - result.id = gNodeId - if result.id == nodeIdToDebug: - echo "KIND ", result.kind - writeStackTrace() - inc gNodeId + newNodeImpl(info) + setIdMaybe() proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = ## new node with line info, type, and children - result = PNode(kind: kind, info: info) + newNodeImpl(info) if children > 0: newSeq(result.sons, children) - when defined(useNodeIds): - result.id = gNodeId - if result.id == nodeIdToDebug: - echo "KIND ", result.kind - writeStackTrace() - inc gNodeId + setIdMaybe() proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = ## new node with line info, type, and no children @@ -1644,8 +1679,8 @@ proc copyNode*(src: PNode): PNode = template transitionNodeKindCommon(k: TNodeKind) = let obj {.inject.} = n[] - n[] = TNode(kind: k, typ: obj.typ, info: obj.info, flags: obj.flags, - comment: obj.comment) + n[] = TNode(kind: k, typ: obj.typ, info: obj.info, flags: obj.flags) + # n.comment = obj.comment # shouldn't be needed, the address doesnt' change when defined(useNodeIds): n.id = obj.id diff --git a/compiler/commands.nim b/compiler/commands.nim index 82e908152..079717862 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -8,7 +8,7 @@ # # This module handles the parsing of command line arguments. - +from ast import setUseIc # We do this here before the 'import' statement so 'defined' does not get # confused with 'TGCMode.gcMarkAndSweep' etc. @@ -862,6 +862,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "v2": conf.symbolFiles = v2Sf of "stress": conf.symbolFiles = stressTest else: localError(conf, info, "invalid option for --incremental: " & arg) + setUseIc(conf.symbolFiles != disabledSf) of "skipcfg": processOnOffSwitchG(conf, {optSkipSystemConfigFile}, arg, pass, info) of "skipprojcfg": diff --git a/compiler/parser.nim b/compiler/parser.nim index 30180e545..225493902 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -170,13 +170,15 @@ proc validInd(p: var Parser): bool {.inline.} = proc rawSkipComment(p: var Parser, node: PNode) = if p.tok.tokType == tkComment: if node != nil: + var rhs = node.comment when defined(nimpretty): if p.tok.commentOffsetB > p.tok.commentOffsetA: - node.comment.add fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) + rhs.add fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) else: - node.comment.add p.tok.literal + rhs.add p.tok.literal else: - node.comment.add p.tok.literal + rhs.add p.tok.literal + node.comment = move rhs else: parMessage(p, errInternal, "skipComment") getTok(p) @@ -1824,8 +1826,10 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode = if result.comment.len == 0: # proc fn*(a: int): int = a ## foo # => moves comment `foo` to `fn` - swap(result.comment, body[0].comment) - else: discard # xxx either `assert false` or issue a warning (otherwise we'll never know of this edge case) + result.comment = body[0].comment + body[0].comment = "" + else: + assert false, p.lex.config$body.info # avoids hard to track bugs, fail early. proc newCommentStmt(p: var Parser): PNode = #| commentStmt = COMMENT From f02de25ca1b660b0b6e1ae2d4981106744814fe3 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 31 Aug 2021 08:14:05 +0200 Subject: [PATCH 2960/4254] Fix #15150 (#18730) --- lib/pure/asyncfile.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index c51b338e3..222a89b97 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -202,10 +202,11 @@ proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] = proc read*(f: AsyncFile, size: int): Future[string] = ## Read `size` bytes from the specified file asynchronously starting at - ## the current position of the file pointer. + ## the current position of the file pointer. `size` should be greater than zero. ## ## If the file pointer is past the end of the file then an empty string is ## returned. + assert size > 0 var retFuture = newFuture[string]("asyncfile.read") when defined(windows) or defined(nimdoc): From 8f4bdb3596bb7650f2688b8243dc3164abfc21c9 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 31 Aug 2021 19:32:37 +0800 Subject: [PATCH 2961/4254] [minor]break loops after a candidate is added to seqs (#18770) * [minor]break loops when added * Update compiler/lookups.nim Co-authored-by: Clyybber Co-authored-by: Clyybber --- compiler/lookups.nim | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 4c072eed8..fc30408e5 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -211,14 +211,16 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} = proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] = result = @[] - for scope in allScopes(c.currentScope): - var ti: TIdentIter - var candidate = initIdentIter(ti, scope.symbols, s) - while candidate != nil: - if candidate.kind in filter: - if result.len == 0: + block outer: + for scope in allScopes(c.currentScope): + var ti: TIdentIter + var candidate = initIdentIter(ti, scope.symbols, s) + while candidate != nil: + if candidate.kind in filter: result.add candidate - candidate = nextIdentIter(ti, scope.symbols) + # Break here, because further symbols encountered would be shadowed + break outer + candidate = nextIdentIter(ti, scope.symbols) if result.len == 0: var marked = initIntSet() From 3469f3a39320cf35d02d11b78c7db0be79e992f8 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 31 Aug 2021 20:05:45 +0800 Subject: [PATCH 2962/4254] add Apple Silicon to supporting platforms (#18772) * add Apple Silicon to supporting platforms * Update readme.md Co-authored-by: flywind Co-authored-by: Andreas Rumpf --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7c6e28be3..b28c25ec1 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ architecture combinations: * Windows (Windows XP or greater) - x86 and x86_64 * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l - * Mac OS X (10.04 or greater) - x86, x86_64 and ppc64 + * Mac OS X (10.04 or greater) - x86, x86_64, ppc64 and Apple Silicon (based on the ARM64 architecture) More platforms are supported, however, they are not tested regularly and they may not be as stable as the above-listed platforms. From 72fa5833adac590e3c78e2b774cd33f28827594b Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 2 Sep 2021 13:41:14 +0800 Subject: [PATCH 2963/4254] fix #9778 (pairs iterator calling a helper proc with tuple return type will cut the iterator yield into half) (#18767) * test someSymFromImportTable * Update compiler/lookups.nim * test nkTupleConstr * use isConstExpr * add tests * add comments and todo * use todo --- compiler/transf.nim | 55 +++++++-- tests/stdlib/tyield.nim | 256 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+), 11 deletions(-) create mode 100644 tests/stdlib/tyield.nim diff --git a/compiler/transf.nim b/compiler/transf.nim index fb59887b0..80794b581 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -364,7 +364,7 @@ proc transformYield(c: PTransf, n: PNode): PNode = if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons if c.transCon.forStmt.len != 3: e = skipConv(e) - if e.kind in {nkPar, nkTupleConstr}: + if e.kind == nkTupleConstr: for i in 0.. 0: - var changeNode = result[0] - changeNode.info = c.transCon.forStmt.info - for i, child in changeNode: - child.info = changeNode.info + for idx in 0 ..< result.len: + var changeNode = result[idx] + changeNode.info = c.transCon.forStmt.info + for i, child in changeNode: + child.info = changeNode.info proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = transformSons(c, n) diff --git a/tests/stdlib/tyield.nim b/tests/stdlib/tyield.nim new file mode 100644 index 000000000..85be97365 --- /dev/null +++ b/tests/stdlib/tyield.nim @@ -0,0 +1,256 @@ +discard """ + targets: "c cpp js" +""" + +import std/[sugar, algorithm] + +block: + var x = @[(6.0, 6, '6'), + (5.0, 5, '5'), + (4.0, 4, '4'), + (3.0, 3, '3'), + (2.0, 2, '2'), + (1.0, 1, '1')] + + let y = x.reversed + + block: + let res = collect: + for (f, i, c) in x: + (f, i, c) + + doAssert res == x + + iterator popAscending[T](q: var seq[T]): T = + while q.len > 0: yield q.pop + + block: + var res = collect: + for f, i, c in popAscending(x): + (f, i, c) + + doAssert res == y + + let z = reversed(res) + let res2 = collect: + for (f, i, c) in popAscending(res): + (f, i, c) + + doAssert res2 == z + + +block: + var visits = 0 + block: + proc bar(): (int, int) = + inc visits + (visits, visits) + + iterator foo(): (int, int) = + yield bar() + + for a, b in foo(): + doAssert a == b + + doAssert visits == 1 + + block: + proc iterAux(a: seq[int], i: var int): (int, string) = + result = (a[i], $a[i]) + inc i + + iterator pairs(a: seq[int]): (int, string) = + var i = 0 + while i < a.len: + yield iterAux(a, i) + + var x = newSeq[int](10) + for i in 0 ..< x.len: + x[i] = i + + let res = collect: + for k, v in x: + (k, v) + + let expected = collect: + for i in 0 ..< x.len: + (i, $i) + + doAssert res == expected + + block: + proc bar(): (int, int, int) = + inc visits + (visits, visits, visits) + + iterator foo(): (int, int, int) = + yield bar() + + for a, b, c in foo(): + doAssert a == b + + doAssert visits == 2 + + + block: + + proc bar(): int = + inc visits + visits + + proc car(): int = + inc visits + visits + + iterator foo(): (int, int) = + yield (bar(), car()) + yield (bar(), car()) + + for a, b in foo(): + doAssert b == a + 1 + + doAssert visits == 6 + + + block: + proc bar(): (int, int) = + inc visits + (visits, visits) + + proc t2(): int = 99 + + iterator foo(): (int, int) = + yield (12, t2()) + yield bar() + + let res = collect: + for (a, b) in foo(): + (a, b) + + doAssert res == @[(12, 99), (7, 7)] + doAssert visits == 7 + + block: + proc bar(): (int, int) = + inc visits + (visits, visits) + + proc t2(): int = 99 + + iterator foo(): (int, int) = + yield ((12, t2())) + yield (bar()) + + let res = collect: + for (a, b) in foo(): + (a, b) + + doAssert res == @[(12, 99), (8, 8)] + doAssert visits == 8 + + block: + proc bar(): (int, int) = + inc visits + (visits, visits) + + proc t1(): int = 99 + proc t2(): int = 99 + + iterator foo(): (int, int) = + yield (t1(), t2()) + yield bar() + + let res = collect: + for a, b in foo(): + (a, b) + + doAssert res == @[(99, 99), (9, 9)] + doAssert visits == 9 + + + block: + proc bar(): ((int, int), string) = + inc visits + ((visits, visits), $visits) + + proc t2(): int = 99 + + iterator foo(): ((int, int), string) = + yield ((1, 2), $t2()) + yield bar() + + let res = collect: + for a, b in foo(): + (a, b) + + doAssert res == @[((1, 2), "99"), ((10, 10), "10")] + doAssert visits == 10 + + + block: + proc bar(): (int, int) = + inc visits + (visits, visits) + + iterator foo(): (int, int) = + yield (for i in 0 ..< 10: discard bar(); bar()) + yield (bar()) + + let res = collect: + for (a, b) in foo(): + (a, b) + + doAssert res == @[(21, 21), (22, 22)] + + block: + proc bar(): (int, int) = + inc visits + (visits, visits) + + proc t2(): int = 99 + + iterator foo(): (int, int) = + yield if true: bar() else: (t2(), t2()) + yield (bar()) + + let res = collect: + for a, b in foo(): + (a, b) + + doAssert res == @[(23, 23), (24, 24)] + + +block: + iterator foo(): (int, int, int) = + var time = 777 + yield (1, time, 3) + + let res = collect: + for a, b, c in foo(): + (a, b, c) + + doAssert res == @[(1, 777, 3)] + +block: + iterator foo(): (int, int, int) = + var time = 777 + yield (1, time, 3) + + let res = collect: + for t in foo(): + (t[0], t[1], t[2]) + + doAssert res == @[(1, 777, 3)] + + +block: + proc bar(): (int, int, int) = + (1, 2, 3) + iterator foo(): (int, int, int) = + yield bar() + + let res = collect: + for a, b, c in foo(): + (a, b, c) + + doAssert res == @[(1, 2, 3)] From e0ef859130f429df1891e31a85955daa753346b4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 2 Sep 2021 12:10:14 +0200 Subject: [PATCH 2964/4254] strict effects (#18777) * fixes #17369 * megatest is green for --cpu:arm64 * docgen output includes more tags/raises * implemented 'effectsOf' * algorithm.nim: uses new effectsOf annotation * closes #18376 * closes #17475 * closes #13905 * allow effectsOf: [a, b] * added a test case * parameters that are not ours cannot be declared as .effectsOf * documentation * manual: added the 'sort' example * bootstrap with the new better options --- changelog.md | 17 ++ compiler/ast.nim | 6 +- compiler/ccgcalls.nim | 4 +- compiler/commands.nim | 3 +- compiler/condsyms.nim | 1 + compiler/docgen.nim | 7 +- compiler/lineinfos.nim | 2 + compiler/nim.cfg | 5 + compiler/options.nim | 3 +- compiler/pragmas.nim | 30 ++- compiler/sem.nim | 7 +- compiler/semcall.nim | 2 + compiler/semdata.nim | 4 +- compiler/sempass2.nim | 116 +++++--- compiler/semstmts.nim | 9 +- compiler/types.nim | 17 +- compiler/wordrecg.nim | 2 +- doc/manual.rst | 252 ++++++++++-------- lib/pure/algorithm.nim | 23 +- lib/pure/times.nim | 2 +- lib/std/private/globs.nim | 7 +- lib/system/io.nim | 2 +- lib/system/nimscript.nim | 6 +- .../expected/index.html | 2 +- nimdoc/testproject/expected/testproject.html | 10 +- tests/effects/teffects1.nim | 3 +- tests/effects/teffects2.nim | 3 +- tests/effects/teffects7.nim | 4 +- tests/effects/teffects8.nim | 3 +- tests/effects/tstrict_effects.nim | 27 ++ tests/effects/tstrict_effects2.nim | 28 ++ tests/effects/tstrict_effects3.nim | 17 ++ tests/effects/tstrict_effects_sort.nim | 27 ++ tests/pragmas/tuserpragma2.nim | 3 +- tests/stdlib/tstdlib_various.nim | 31 +-- 35 files changed, 482 insertions(+), 203 deletions(-) create mode 100644 tests/effects/tstrict_effects.nim create mode 100644 tests/effects/tstrict_effects2.nim create mode 100644 tests/effects/tstrict_effects3.nim create mode 100644 tests/effects/tstrict_effects_sort.nim diff --git a/changelog.md b/changelog.md index 65ae61833..10824cfc6 100644 --- a/changelog.md +++ b/changelog.md @@ -427,6 +427,23 @@ - On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. This is only supported for `--gc:orc` or `--gc:arc`. +- The effect system was refined and there is a new `.effectsOf` annotation that does + explicitly what was previously done implicitly. See the manual for details. + To write code that is portable with older Nim versions, use this idiom: + +```nim + +when defined(nimHasEffectsOf): + {.experimental: "strictEffects".} +else: + {.pragma: effectsOf.} + +proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.} + +``` + + To enable the new effect system, use --experimental:strictEffects. + ## Compiler changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 5893a5671..50d048edd 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -229,7 +229,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 47 flags! + TSymFlag* = enum # 48 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -299,6 +299,7 @@ type sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' sfSingleUsedTemp # For temporaries that we know will only be used once sfNoalias # 'noalias' annotation, means C's 'restrict' + sfEffectsDelayed # an 'effectsDelayed' parameter TSymFlags* = set[TSymFlag] @@ -568,6 +569,7 @@ type # sizeof, alignof, offsetof at CT tfExplicitCallConv tfIsConstructor + tfEffectSystemWorkaround TTypeFlags* = set[TTypeFlag] @@ -1781,7 +1783,7 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool = proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool = case n.kind - of nkEmpty..nkNilLit: result = n.kind == kind + of nkEmpty..nkNilLit, nkFormalParams: result = n.kind == kind else: for i in 0.. pragma: arg result.transitionSonsKind(n.kind) +proc processEffectsOf(c: PContext, n: PNode; owner: PSym) = + proc processParam(c: PContext; n: PNode) = + let r = c.semExpr(c, n) + if r.kind == nkSym and r.sym.kind == skParam: + if r.sym.owner == owner: + incl r.sym.flags, sfEffectsDelayed + else: + localError(c.config, n.info, errGenerated, "parameter cannot be declared as .effectsOf") + else: + localError(c.config, n.info, errGenerated, "parameter name expected") + + if n.kind notin nkPragmaCallKinds or n.len != 2: + localError(c.config, n.info, errGenerated, "parameter name expected") + else: + let it = n[1] + if it.kind in {nkCurly, nkBracket}: + for x in items(it): processParam(c, x) + else: + processParam(c, it) + proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, validPragmas: TSpecialWords, comesFromPush, isStatement: bool): bool = @@ -895,6 +915,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wNoalias: noVal(c, it) incl(sym.flags, sfNoalias) + of wEffectsOf: + processEffectsOf(c, it, sym) of wThreadVar: noVal(c, it) incl(sym.flags, {sfThread, sfGlobal}) diff --git a/compiler/sem.nim b/compiler/sem.nim index 804325e56..24709cf21 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -400,9 +400,10 @@ when not defined(nimHasSinkInference): include hlo, seminst, semcall proc resetSemFlag(n: PNode) = - excl n.flags, nfSem - for i in 0.. 0: rr = rr.lastSon - localError(g.config, r.info, errGenerated, renderTree(rr) & " " & msg & typeToString(r.typ)) + message(g.config, r.info, if emitWarnings: warnEffect else: errGenerated, + renderTree(rr) & " " & msg & typeToString(r.typ)) popInfoContext(g.config) # hint about unnecessarily listed exception types: if hints: @@ -1258,11 +1293,11 @@ proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) = let p = disp.ast[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): - checkRaisesSpec(g, raisesSpec, actual[exceptionEffects], + checkRaisesSpec(g, false, raisesSpec, actual[exceptionEffects], "can raise an unlisted exception: ", hints=off, subtypeRelation) let tagsSpec = effectSpec(p, wTags) if not isNil(tagsSpec): - checkRaisesSpec(g, tagsSpec, actual[tagEffects], + checkRaisesSpec(g, false, tagsSpec, actual[tagEffects], "can have an unlisted effect: ", hints=off, subtypeRelation) if sfThread in disp.flags and notGcSafe(branch.typ): localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" % @@ -1283,7 +1318,7 @@ proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) = "base method has lock level $1, but dispatcher has $2" % [$branch.typ.lockLevel, $disp.typ.lockLevel]) -proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) = +proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode; s: PSym = nil) = var effects = t.n[0] if t.kind != tyProc or effects.kind != nkEffectList: return if n.kind != nkEmpty: @@ -1292,9 +1327,14 @@ proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) = let raisesSpec = effectSpec(n, wRaises) if not isNil(raisesSpec): effects[exceptionEffects] = raisesSpec + elif s != nil and (s.magic != mNone or {sfImportc, sfExportc} * s.flags == {sfImportc}): + effects[exceptionEffects] = newNodeI(nkArgList, effects.info) + let tagsSpec = effectSpec(n, wTags) if not isNil(tagsSpec): effects[tagEffects] = tagsSpec + elif s != nil and (s.magic != mNone or {sfImportc, sfExportc} * s.flags == {sfImportc}): + effects[tagEffects] = newNodeI(nkArgList, effects.info) let requiresSpec = propSpec(n, wRequires) if not isNil(requiresSpec): @@ -1304,15 +1344,21 @@ proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) = effects[ensuresEffects] = ensuresSpec effects[pragmasEffects] = n + if s != nil and s.magic != mNone: + if s.magic != mEcho: + t.flags.incl tfNoSideEffect -proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) = +proc rawInitEffects(g: ModuleGraph; effects: PNode) = newSeq(effects.sons, effectListLen) - effects[exceptionEffects] = newNodeI(nkArgList, s.info) - effects[tagEffects] = newNodeI(nkArgList, s.info) + effects[exceptionEffects] = newNodeI(nkArgList, effects.info) + effects[tagEffects] = newNodeI(nkArgList, effects.info) effects[requiresEffects] = g.emptyNode effects[ensuresEffects] = g.emptyNode effects[pragmasEffects] = g.emptyNode +proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) = + rawInitEffects(g, effects) + t.exc = effects[exceptionEffects] t.tags = effects[tagEffects] t.owner = s @@ -1341,10 +1387,14 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = if effects.kind != nkEffectList: return # effects already computed? if not s.hasRealBody: return - if effects.len == effectListLen: return + let emitWarnings = tfEffectSystemWorkaround in s.typ.flags + if effects.len == effectListLen and not emitWarnings: return + + var inferredEffects = newNodeI(nkEffectList, s.info) var t: TEffects - initEffects(g, effects, s, t, c) + initEffects(g, inferredEffects, s, t, c) + rawInitEffects g, effects track(t, body) if s.kind != skMacro: @@ -1369,17 +1419,21 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let p = s.ast[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): - checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ", + checkRaisesSpec(g, emitWarnings, raisesSpec, t.exc, "can raise an unlisted exception: ", hints=on, subtypeRelation, hintsArg=s.ast[0]) # after the check, use the formal spec: effects[exceptionEffects] = raisesSpec + else: + effects[exceptionEffects] = t.exc let tagsSpec = effectSpec(p, wTags) if not isNil(tagsSpec): - checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ", + checkRaisesSpec(g, emitWarnings, tagsSpec, t.tags, "can have an unlisted effect: ", hints=off, subtypeRelation) # after the check, use the formal spec: effects[tagEffects] = tagsSpec + else: + effects[tagEffects] = t.tags let requiresSpec = propSpec(p, wRequires) if not isNil(requiresSpec): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 14dc89781..df0e2778b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1953,6 +1953,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not hasProto: implicitPragmas(c, s, n.info, validPragmas) + if n[pragmasPos].kind != nkEmpty: + setEffectsForProcType(c.graph, s.typ, n[pragmasPos], s) + s.typ.flags.incl tfEffectSystemWorkaround + # To ease macro generation that produce forwarded .async procs we now # allow a bit redundancy in the pragma declarations. The rule is # a prototype's pragma list must be a superset of the current pragma @@ -2211,8 +2215,9 @@ proc evalInclude(c: PContext, n: PNode): PNode = incMod(c, n, it, result) proc setLine(n: PNode, info: TLineInfo) = - for i in 0..`_ pretends to be free of side effects +so that it can be used for debugging routines marked as `noSideEffect`. + +`func` is syntactic sugar for a proc with no side effects: + +.. code-block:: nim + func `+` (x, y: int): int + + +To override the compiler's side effect analysis a `{.noSideEffect.}` +`cast` pragma block can be used: + +.. code-block:: nim + + func f() = + {.cast(noSideEffect).}: + echo "test" + +**Side effects are usually inferred. The inference for side effects is +analogous to the inference for exception tracking.** + + +GC safety effect +---------------- + +We call a proc `p` `GC safe`:idx: when it doesn't access any global variable +that contains GC'ed memory (`string`, `seq`, `ref` or a closure) either +directly or indirectly through a call to a GC unsafe proc. + +**The GC safety property is usually inferred. The inference for GC safety is +analogous to the inference for exception tracking.** + +The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe, +otherwise this property is inferred by the compiler. Note that `noSideEffect` +implies `gcsafe`. + +Routines that are imported from C are always assumed to be `gcsafe`. + +To override the compiler's gcsafety analysis a `{.cast(gcsafe).}` pragma block can +be used: + +.. code-block:: nim + + var + someGlobal: string = "some string here" + perThread {.threadvar.}: string + + proc setPerThread() = + {.cast(gcsafe).}: + deepCopy(perThread, someGlobal) + + +See also: + +- `Shared heap memory management `_. + + Effects pragma -------------- @@ -6366,55 +6486,6 @@ This pragma can also take in an optional warning string to relay to developers. proc thing(x: bool) {.deprecated: "use thong instead".} -noSideEffect pragma -------------------- - -The `noSideEffect` pragma is used to mark a proc/iterator that can have only -side effects through parameters. This means that the proc/iterator only changes locations that are -reachable from its parameters and the return value only depends on the -parameters. If none of its parameters have the type `var`, `ref`, `ptr`, `cstring`, or `proc`, -then no locations are modified. - -It is a static error to mark a proc/iterator to have no side effect if the compiler cannot verify this. - -As a special semantic rule, the built-in `debugEcho -`_ pretends to be free of side effects -so that it can be used for debugging routines marked as `noSideEffect`. - -`func` is syntactic sugar for a proc with no side effects: - -.. code-block:: nim - func `+` (x, y: int): int - - -To override the compiler's side effect analysis a `{.noSideEffect.}` -`cast` pragma block can be used: - -.. code-block:: nim - - func f() = - {.cast(noSideEffect).}: - echo "test" - -When a `noSideEffect` proc has proc params `bar`, whether it can be used inside a `noSideEffect` context -depends on what the compiler knows about `bar`: - -.. code-block:: nim - :test: "nim c $1" - - func foo(bar: proc(): int): int = bar() - var count = 0 - proc fn1(): int = 1 - proc fn2(): int = (count.inc; count) - func fun1() = discard foo(fn1) # ok because fn1 is inferred as `func` - # func fun2() = discard foo(fn2) # would give: Error: 'fun2' can have side effects - - # with callbacks, the compiler is conservative, ie that bar will have side effects - var foo2: type(foo) = foo - func main() = - discard foo(fn1) # ok - # discard foo2(fn1) # now this errors - compileTime pragma ------------------ @@ -7861,6 +7932,10 @@ collected) heap, and sharing of memory is restricted to global variables. This helps to prevent race conditions. GC efficiency is improved quite a lot, because the GC never has to stop other threads and see what they reference. +The only way to create a thread is via `spawn` or +`createThread`. The invoked proc must not use `var` parameters nor must +any of its parameters contain a `ref` or `closure` type. This enforces +the *no heap sharing restriction*. Thread pragma ------------- @@ -7875,43 +7950,6 @@ A thread proc is passed to `createThread` or `spawn` and invoked indirectly; so the `thread` pragma implies `procvar`. -GC safety ---------- - -We call a proc `p` `GC safe`:idx: when it doesn't access any global variable -that contains GC'ed memory (`string`, `seq`, `ref` or a closure) either -directly or indirectly through a call to a GC unsafe proc. - -The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe, -otherwise this property is inferred by the compiler. Note that `noSideEffect` -implies `gcsafe`. The only way to create a thread is via `spawn` or -`createThread`. The invoked proc must not use `var` parameters nor must -any of its parameters contain a `ref` or `closure` type. This enforces -the *no heap sharing restriction*. - -Routines that are imported from C are always assumed to be `gcsafe`. -To disable the GC-safety checking the `--threadAnalysis:off`:option: command-line -switch can be used. This is a temporary workaround to ease the porting effort -from old code to the new threading model. - -To override the compiler's gcsafety analysis a `{.cast(gcsafe).}` pragma block can -be used: - -.. code-block:: nim - - var - someGlobal: string = "some string here" - perThread {.threadvar.}: string - - proc setPerThread() = - {.cast(gcsafe).}: - deepCopy(perThread, someGlobal) - - -See also: - -- `Shared heap memory management `_. - Threadvar pragma ---------------- diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index c96f599e8..1ddcc9843 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -147,8 +147,13 @@ proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] {.inline, deprecated: "use: `reversed(toOpenArray(a, first, last))`".} = reversed(toOpenArray(a, first, last)) +when defined(nimHasEffectsOf): + {.experimental: "strictEffects".} +else: + {.pragma: effectsOf.} + proc binarySearch*[T, K](a: openArray[T], key: K, - cmp: proc (x: T, y: K): int {.closure.}): int = + cmp: proc (x: T, y: K): int {.closure.}): int {.effectsOf: cmp.} = ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found. ## Assumes that `a` is sorted according to `cmp`. ## @@ -210,7 +215,7 @@ const onlySafeCode = true proc lowerBound*[T, K](a: openArray[T], key: K, - cmp: proc(x: T, k: K): int {.closure.}): int = + cmp: proc(x: T, k: K): int {.closure.}): int {.effectsOf: cmp.} = ## Returns the index of the first element in `a` that is not less than ## (i.e. greater or equal to) `key`, or last if no such element is found. ## In other words if you have a sorted sequence and you call @@ -260,7 +265,7 @@ proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T]) ## * `upperBound proc<#upperBound,openArray[T],T>`_ proc upperBound*[T, K](a: openArray[T], key: K, - cmp: proc(x: T, k: K): int {.closure.}): int = + cmp: proc(x: T, k: K): int {.closure.}): int {.effectsOf: cmp.} = ## Returns the index of the first element in `a` that is greater than ## `key`, or last if no such element is found. ## In other words if you have a sorted sequence and you call @@ -318,7 +323,7 @@ template `<-`(a, b) = copyMem(addr(a), addr(b), sizeof(T)) proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int, - cmp: proc (x, y: T): int {.closure.}, order: SortOrder) = + cmp: proc (x, y: T): int {.closure.}, order: SortOrder) {.effectsOf: cmp.} = # Optimization: If max(left) <= min(right) there is nothing to do! # 1 2 3 4 ## 5 6 7 8 # -> O(n) for sorted arrays. @@ -358,7 +363,7 @@ proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int, func sort*[T](a: var openArray[T], cmp: proc (x, y: T): int {.closure.}, - order = SortOrder.Ascending) = + order = SortOrder.Ascending) {.effectsOf: cmp.} = ## Default Nim sort (an implementation of merge sort). The sorting ## is guaranteed to be stable (that is, equal elements stay in the same order) ## and the worst case is guaranteed to be O(n log n). @@ -420,7 +425,7 @@ proc sort*[T](a: var openArray[T], order = SortOrder.Ascending) = sort[T](a, ## * `sortedByIt template<#sortedByIt.t,untyped,untyped>`_ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): seq[T] = + order = SortOrder.Ascending): seq[T] {.effectsOf: cmp.} = ## Returns `a` sorted by `cmp` in the specified `order`. ## ## **See also:** @@ -497,7 +502,7 @@ template sortedByIt*(seq1, op: untyped): untyped = func isSorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): bool = + order = SortOrder.Ascending): bool {.effectsOf: cmp.} = ## Checks to see whether `a` is already sorted in `order` ## using `cmp` for the comparison. The parameters are identical ## to `sort`. Requires O(n) time. @@ -545,7 +550,7 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = proc merge*[T]( result: var seq[T], x, y: openArray[T], cmp: proc(x, y: T): int {.closure.} -) {.since: (1, 5, 1).} = +) {.since: (1, 5, 1), effectsOf: cmp.} = ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted. ## If you do not wish to provide your own `cmp`, ## you may use `system.cmp` or instead call the overloaded @@ -638,7 +643,7 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = ## Produces the Cartesian product of the array. ## Every element of the result is a combination of one element from each seq in `x`, ## with the ith element coming from `x[i]`. - ## + ## ## .. warning:: complexity may explode. runnableExamples: assert product(@[@[1], @[2]]) == @[@[1, 2]] diff --git a/lib/pure/times.nim b/lib/pure/times.nim index b2a22250d..b41bb28b5 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1333,7 +1333,7 @@ proc now*(): DateTime {.tags: [TimeEffect], benign.} = ## `cpuTime` instead, depending on the use case. getTime().local -proc dateTime*(year: int, month: Month, monthday: MonthdayRange, +proc dateTime*(year: int, month: Month, monthday: MonthdayRange, hour: HourRange = 0, minute: MinuteRange = 0, second: SecondRange = 0, nanosecond: NanosecondRange = 0, zone: Timezone = local()): DateTime = diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index b3726c9c3..190316f93 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -8,13 +8,18 @@ import os when defined(windows): from strutils import replace +when defined(nimHasEffectsOf): + {.experimental: "strictEffects".} +else: + {.pragma: effectsOf.} + type PathEntry* = object kind*: PathComponent path*: string iterator walkDirRecFilter*(dir: string, follow: proc(entry: PathEntry): bool = nil, - relative = false, checkDir = true): PathEntry {.tags: [ReadDirEffect].} = + relative = false, checkDir = true): PathEntry {.tags: [ReadDirEffect], effectsOf: follow.} = ## Improved `os.walkDirRec`. #[ note: a yieldFilter isn't needed because caller can filter at call site, without diff --git a/lib/system/io.nim b/lib/system/io.nim index d8b2ac741..59f070f73 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -78,7 +78,7 @@ proc c_fputs(c: cstring, f: File): cint {. proc c_fgets(c: cstring, n: cint, f: File): cstring {. importc: "fgets", header: "", tags: [ReadIOEffect].} proc c_fgetc(stream: File): cint {. - importc: "fgetc", header: "", tags: [ReadIOEffect].} + importc: "fgetc", header: "", tags: [].} proc c_ungetc(c: cint, f: File): cint {. importc: "ungetc", header: "", tags: [].} proc c_putc(c: cint, stream: File): cint {. diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 9ece10e3e..b4554d778 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -261,7 +261,7 @@ proc cpDir*(`from`, to: string) {.raises: [OSError].} = checkOsError() proc exec*(command: string) {. - raises: [OSError], tags: [ExecIOEffect].} = + raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} = ## Executes an external process. If the external process terminates with ## a non-zero exit code, an OSError exception is raised. ## @@ -274,7 +274,7 @@ proc exec*(command: string) {. checkOsError() proc exec*(command: string, input: string, cache = "") {. - raises: [OSError], tags: [ExecIOEffect].} = + raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} = ## Executes an external process. If the external process terminates with ## a non-zero exit code, an OSError exception is raised. log "exec: " & command: @@ -284,7 +284,7 @@ proc exec*(command: string, input: string, cache = "") {. echo output proc selfExec*(command: string) {. - raises: [OSError], tags: [ExecIOEffect].} = + raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} = ## Executes an external command with the current nim/nimble executable. ## `Command` must not contain the "nim " part. let c = selfExe() & " " & command diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 3499b5326..458a0394f 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -122,7 +122,7 @@ window.addEventListener('DOMContentLoaded', main);

    Procs

    -
    proc foo() {....raises: [], tags: [].}
    +
    proc foo() {....raises: [], tags: [WriteIOEffect].}
    I do foo diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index d98b1b00f..dbacb57a7 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -654,7 +654,7 @@ This is deprecated with a message.
    proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
    -    header: "<stdio.h>", varargs, discardable.}
    + header: "<stdio.h>", varargs, discardable, ...raises: [], tags: [].}
    @@ -663,7 +663,7 @@ This is deprecated with a message.
    proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
    -                                     varargs, discardable.}
    + varargs, discardable, ...raises: [], tags: [].}
    the c printf. etc. @@ -690,7 +690,8 @@ came form utils but should be shown where
    -
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
    +
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    +    ...raises: [], tags: [].}

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    @@ -704,7 +705,8 @@ came form utils but should be shown where
    -
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect.}
    +
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    +    ...raises: [], tags: [].}

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 66d6a3518..82efefe77 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -6,7 +6,7 @@ teffects1.nim(22, 29) Hint: 'lier' cannot raise 'IO2Error' [XCannotRaiseY] teffects1.nim(38, 21) Error: type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' .raise effects differ''' """ - +{.push warningAsError[Effect]: on.} type TObj {.pure, inheritable.} = object TObjB = object of TObj @@ -41,3 +41,4 @@ type mismatch: got but ]# {.pop.} +{.pop.} diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim index e4b50aba5..ec3c0a887 100644 --- a/tests/effects/teffects2.nim +++ b/tests/effects/teffects2.nim @@ -2,7 +2,7 @@ discard """ errormsg: "can raise an unlisted exception: ref IOError" line: 19 """ - +{.push warningAsError[Effect]: on.} type TObj = object {.pure, inheritable.} TObjB = object of TObj @@ -17,3 +17,4 @@ proc lier(): int {.raises: [IOError].} = proc forw: int = raise newException(IOError, "arg") +{.pop.} diff --git a/tests/effects/teffects7.nim b/tests/effects/teffects7.nim index 73865b18d..9b7fbf5f0 100644 --- a/tests/effects/teffects7.nim +++ b/tests/effects/teffects7.nim @@ -2,7 +2,7 @@ discard """ errormsg: "can raise an unlisted exception: ref ValueError" line: 10 """ - +{.push warningAsError[Effect]: on.} proc foo() {.raises: [].} = try: discard @@ -12,3 +12,5 @@ proc foo() {.raises: [].} = discard foo() + +{.pop.} diff --git a/tests/effects/teffects8.nim b/tests/effects/teffects8.nim index fb3c088d6..359b3a1df 100644 --- a/tests/effects/teffects8.nim +++ b/tests/effects/teffects8.nim @@ -2,7 +2,7 @@ discard """ errormsg: "can raise an unlisted exception: Exception" line: 10 """ - +{.push warningAsError[Effect]: on.} proc foo() {.raises: [].} = try: discard @@ -10,3 +10,4 @@ proc foo() {.raises: [].} = raise foo() +{.pop.} diff --git a/tests/effects/tstrict_effects.nim b/tests/effects/tstrict_effects.nim new file mode 100644 index 000000000..eee8fb71a --- /dev/null +++ b/tests/effects/tstrict_effects.nim @@ -0,0 +1,27 @@ +discard """ + errormsg: "s1 can raise an unlisted exception: CatchableError" + line: 27 +""" + +{.push warningAsError[Effect]: on.} +{.experimental: "strictEffects".} + +# bug #18376 + +{.push raises: [Defect].} +type Call = proc (x: int): int {.gcsafe, raises: [Defect, CatchableError].} + +type Bar* = object + foo*: Call + +proc passOn*(x: Call) = discard + +proc barCal(b: var Bar, s: string, s1: Call) = + #compiler complains that his line can throw CatchableError + passOn s1 + + +proc passOnB*(x: Call) {.effectsOf: x.} = discard + +proc barCal2(b: var Bar, s: string, s1: Call) = + passOnB s1 diff --git a/tests/effects/tstrict_effects2.nim b/tests/effects/tstrict_effects2.nim new file mode 100644 index 000000000..acc0a0540 --- /dev/null +++ b/tests/effects/tstrict_effects2.nim @@ -0,0 +1,28 @@ +discard """ + errormsg: "can raise an unlisted exception: Exception" + line: 23 +""" + +{.push warningAsError[Effect]: on.} +{.experimental: "strictEffects".} + +# bug #13905 + +proc atoi(v: cstring): cint {.importc: "atoi", cdecl, raises: [].} + +type Conv = proc(v: cstring): cint {.cdecl, raises: [].} + +var x: Conv = atoi + +# bug #17475 + +type + Callback = proc() + +proc f(callback: Callback) {.raises: [].} = + callback() + +proc main = + f(proc () = raise newException(IOError, "IO")) + +main() diff --git a/tests/effects/tstrict_effects3.nim b/tests/effects/tstrict_effects3.nim new file mode 100644 index 000000000..1ab15cc80 --- /dev/null +++ b/tests/effects/tstrict_effects3.nim @@ -0,0 +1,17 @@ +discard """ + action: compile +""" + +{.push warningAsError[Effect]: on.} + +{.experimental: "strictEffects".} + +proc fn(a: int, p1, p2: proc()) {.effectsOf: p1.} = + if a == 7: + p1() + if a<0: + raise newException(ValueError, $a) + +proc main() {.raises: [ValueError].} = + fn(1, proc()=discard, proc() = raise newException(IOError, "foo")) +main() diff --git a/tests/effects/tstrict_effects_sort.nim b/tests/effects/tstrict_effects_sort.nim new file mode 100644 index 000000000..8928ed0d3 --- /dev/null +++ b/tests/effects/tstrict_effects_sort.nim @@ -0,0 +1,27 @@ +discard """ + errormsg: "cmpE can raise an unlisted exception: Exception" + line: 27 +""" + +{.push warningAsError[Effect]: on.} + +{.experimental: "strictEffects".} + +import algorithm + +type + MyInt = distinct int + +var toSort = @[MyInt 1, MyInt 2, MyInt 3] + +proc cmpN(a, b: MyInt): int = + cmp(a.int, b.int) + +proc harmless {.raises: [].} = + toSort.sort cmpN + +proc cmpE(a, b: MyInt): int {.raises: [Exception].} = + cmp(a.int, b.int) + +proc harmfull {.raises: [].} = + toSort.sort cmpE diff --git a/tests/pragmas/tuserpragma2.nim b/tests/pragmas/tuserpragma2.nim index ce16c4649..c3f31cd5e 100644 --- a/tests/pragmas/tuserpragma2.nim +++ b/tests/pragmas/tuserpragma2.nim @@ -3,9 +3,10 @@ discard """ file: "tuserpragma2.nim" line: 11 """ - +{.push warningAsError[Effect]: on.} # bug #7216 {.pragma: my_pragma, raises: [].} proc test1 {.my_pragma.} = raise newException(Exception, "msg") +{.pop.} diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim index b153fd2ba..bc90d6ef4 100644 --- a/tests/stdlib/tstdlib_various.nim +++ b/tests/stdlib/tstdlib_various.nim @@ -20,12 +20,6 @@ Hi Andreas! How do you feel, Rumpf? @[0, 2, 1] @[0, 1, 2] 055this should be the casehugh@["(", "+", " 1", " 2", ")"] -caught a crash! -caught a crash! -caught a crash! -caught a crash! -caught a crash! -caught a crash! [5] [4, 5] [3, 4, 5] @@ -161,18 +155,21 @@ block tropes: block tsegfaults: - proc main = - try: - var x: ptr int - echo x[] + when not defined(arm64): + var crashes = 0 + proc main = try: - raise newException(ValueError, "not a crash") - except ValueError: - discard - except NilAccessDefect: - echo "caught a crash!" - for i in 0..5: - main() + var x: ptr int + echo x[] + try: + raise newException(ValueError, "not a crash") + except ValueError: + discard + except NilAccessDefect: + inc crashes + for i in 0..5: + main() + assert crashes == 6 From 7c8ea490a2be36d171d362c43212195ea8ce489f Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Thu, 2 Sep 2021 21:12:14 +0900 Subject: [PATCH 2965/4254] Fix initrand to avoid random number sequences overlapping (#18744) * Fix initrand to avoid random number sequences overlapping * Minor fix * Fix compile error on js backend * Disable new test for js backend * Minor fix * tempfiles module uses random.initRand() * Remove unused module import from lib/std/tempfiles.nim * Initialize baseState in initRand() * Run tests/stdlib/trandom.nim from tests/test_nimscript.nims * baseState is initialized only with sysrand.urandom and quit if failed * Add comments --- lib/pure/random.nim | 74 +++++++++++++++++++++++++++++++++------ lib/std/tempfiles.nim | 7 ++-- tests/stdlib/trandom.nim | 32 ++++++++++++++--- tests/test_nimscript.nims | 2 ++ 4 files changed, 95 insertions(+), 20 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index a292386af..b8aeb86e0 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -108,10 +108,19 @@ when defined(js): a0: 0x69B4C98Cu32, a1: 0xFED1DD30u32) # global for backwards compatibility else: - # racy for multi-threading but good enough for now: - var state = Rand( + const DefaultRandSeed = Rand( a0: 0x69B4C98CB8530805u64, - a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility + a1: 0xFED1DD3004688D67CAu64) + + # racy for multi-threading but good enough for now: + var state = DefaultRandSeed # global for backwards compatibility + +func isValid(r: Rand): bool {.inline.} = + ## Check whether state of `r` is valid. + ## + ## In `xoroshiro128+`, if all bits of `a0` and `a1` are zero, + ## they are always zero after calling `next(r: var Rand)`. + not (r.a0 == 0 and r.a1 == 0) since (1, 5): template randState*(): untyped = @@ -617,15 +626,28 @@ proc shuffle*[T](x: var openArray[T]) = shuffle(state, x) -when not defined(nimscript) and not defined(standalone): - import times +when not defined(standalone): + when defined(js): + import std/times + else: + when defined(nimscript): + import std/hashes + else: + import std/[hashes, os, sysrand, monotimes] + + when compileOption("threads"): + import locks + var baseSeedLock: Lock + baseSeedLock.initLock + + var baseState: Rand proc initRand(): Rand = - ## Initializes a new Rand state with a seed based on the current time. + ## Initializes a new Rand state. ## ## The resulting state is independent of the default RNG's state. ## - ## **Note:** Does not work for NimScript or the compile-time VM. + ## **Note:** Does not work for the compile-time VM. ## ## See also: ## * `initRand proc<#initRand,int64>`_ that accepts a seed for a new Rand state @@ -635,20 +657,50 @@ when not defined(nimscript) and not defined(standalone): let time = int64(times.epochTime() * 1000) and 0x7fff_ffff result = initRand(time) else: - let now = times.getTime() - result = initRand(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond) + proc getRandomState(): Rand = + when defined(nimscript): + result = Rand( + a0: CompileTime.hash.Ui, + a1: CompileDate.hash.Ui) + if not result.isValid: + result = DefaultRandSeed + else: + var urand: array[sizeof(Rand), byte] + + for i in 0 .. 7: + if sysrand.urandom(urand): + copyMem(result.addr, urand[0].addr, sizeof(Rand)) + if result.isValid: + break + + if not result.isValid: + # Don't try to get alternative random values from other source like time or process/thread id, + # because such code would be never tested and is a liability for security. + quit("Failed to initializes baseState in random module as sysrand.urandom doesn't work.") + + when compileOption("threads"): + baseSeedLock.withLock: + if not baseState.isValid: + baseState = getRandomState() + result = baseState + baseState.skipRandomNumbers + else: + if not baseState.isValid: + baseState = getRandomState() + result = baseState + baseState.skipRandomNumbers since (1, 5, 1): export initRand proc randomize*() {.benign.} = ## Initializes the default random number generator with a seed based on - ## the current time. + ## random number source. ## ## This proc only needs to be called once, and it should be called before ## the first usage of procs from this module that use the default RNG. ## - ## **Note:** Does not work for NimScript or the compile-time VM. + ## **Note:** Does not work for the compile-time VM. ## ## **See also:** ## * `randomize proc<#randomize,int64>`_ that accepts a seed diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index f1cfd5885..26786d463 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -17,7 +17,7 @@ See also: * `mkstemp` (posix), refs https://man7.org/linux/man-pages/man3/mkstemp.3.html ]# -import os, random, std/monotimes +import os, random const @@ -107,11 +107,8 @@ var nimTempPathState {.threadvar.}: NimTempPathState template randomPathName(length: Natural): string = var res = newString(length) if not nimTempPathState.isInit: - var time = getMonoTime().ticks - when compileOption("threads"): - time = time xor int64(getThreadId()) nimTempPathState.isInit = true - nimTempPathState.state = initRand(time) + nimTempPathState.state = initRand() for i in 0 ..< length: res[i] = nimTempPathState.state.sample(letters) diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index 39ccca85b..61e858f86 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -23,9 +23,10 @@ proc main() = doAssert a in [[0,1], [1,0]] doAssert rand(0) == 0 - doAssert sample("a") == 'a' + when not defined(nimscript): + doAssert sample("a") == 'a' - when compileOption("rangeChecks"): + when compileOption("rangeChecks") and not defined(nimscript): doAssertRaises(RangeDefect): discard rand(-1) @@ -92,7 +93,7 @@ block: # random int block: # again gives new numbers var rand1 = rand(1000000) - when not defined(js): + when not (defined(js) or defined(nimscript)): os.sleep(200) var rand2 = rand(1000000) @@ -122,7 +123,7 @@ block: # random float block: # again gives new numbers var rand1: float = rand(1000000.0) - when not defined(js): + when not (defined(js) or defined(nimscript)): os.sleep(200) var rand2: float = rand(1000000.0) @@ -248,3 +249,26 @@ block: # bug #17670 type UInt48 = range[0'u64..2'u64^48-1] let x = rand(UInt48) doAssert x is UInt48 + +block: # bug #17898 + # Checks whether `initRand()` generates unique states. + # size should be 2^64, but we don't have time and space. + + # Disable this test for js until js gets proper skipRandomNumbers. + when not defined(js): + const size = 1000 + var + rands: array[size, Rand] + randSet: HashSet[Rand] + for i in 0.. Date: Thu, 2 Sep 2021 14:35:25 +0200 Subject: [PATCH 2966/4254] sequtils now support strict effect tracking (#18782) --- lib/pure/collections/sequtils.nim | 23 ++++++++++++++--------- tests/stdlib/tsequtils.nim | 5 +++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 5b41ea00d..12b961371 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -84,6 +84,11 @@ import std/private/since import macros +when defined(nimHasEffectsOf): + {.experimental: "strictEffects".} +else: + {.pragma: effectsOf.} + macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped = ## Injects `expAlias` in caller scope, to avoid bugs involving multiple @@ -356,7 +361,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = first = last proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): - seq[S]{.inline.} = + seq[S] {.inline, effectsOf: op.} = ## Returns a new sequence with the results of the `op` proc applied to every ## item in the container `s`. ## @@ -382,7 +387,7 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): result[i] = op(s[i]) proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) - {.inline.} = + {.inline, effectsOf: op.} = ## Applies `op` to every item in `s`, modifying it directly. ## ## Note that the container `s` must be declared as a `var`, @@ -401,7 +406,7 @@ proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) for i in 0 ..< s.len: op(s[i]) proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) - {.inline.} = + {.inline, effectsOf: op.} = ## Applies `op` to every item in `s` modifying it directly. ## ## Note that the container `s` must be declared as a `var` @@ -420,7 +425,7 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) for i in 0 ..< s.len: s[i] = op(s[i]) -proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3).} = +proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1, 3), effectsOf: op.} = ## Same as `apply` but for a proc that does not return anything ## and does not mutate `s` directly. runnableExamples: @@ -429,7 +434,7 @@ proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1 assert message == "01234" for i in 0 ..< s.len: op(s[i]) -iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = +iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T {.effectsOf: pred.} = ## Iterates through a container `s` and yields every item that fulfills the ## predicate `pred` (a function that returns a `bool`). ## @@ -453,7 +458,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = yield s[i] proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] - {.inline.} = + {.inline, effectsOf: pred.} = ## Returns a new sequence with all the items of `s` that fulfill the ## predicate `pred` (a function that returns a `bool`). ## @@ -480,7 +485,7 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] result.add(s[i]) proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) - {.inline.} = + {.inline, effectsOf: pred.} = ## Keeps the items in the passed sequence `s` if they fulfill the ## predicate `pred` (a function that returns a `bool`). ## @@ -685,7 +690,7 @@ since (1, 1): if pred: result += 1 result -proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = +proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool {.effectsOf: pred.} = ## Iterates through a container and checks if every item fulfills the ## predicate. ## @@ -727,7 +732,7 @@ template allIt*(s, pred: untyped): bool = break result -proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = +proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool {.effectsOf: pred.} = ## Iterates through a container and checks if at least one item ## fulfills the predicate. ## diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index 6c9c92873..338473407 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -8,6 +8,9 @@ import std/sequtils import strutils from algorithm import sorted +{.experimental: "strictEffects".} +{.push warningAsError[Effect]: on.} + # helper for testing double substitution side effects which are handled # by `evalOnceAs` var counter = 0 @@ -507,3 +510,5 @@ template main = static: main() main() + +{.pop.} From a7cae2bda24871c55348173816a43144b9e668a5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 2 Sep 2021 17:15:11 +0200 Subject: [PATCH 2967/4254] fixes #16325 [backport:1.4] (#18784) --- compiler/sigmatch.nim | 3 +-- .../tproc_types_dont_like_subtypes.nim | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/overload/tproc_types_dont_like_subtypes.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 465a9a51d..9cf18277f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -595,8 +595,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = # if f is metatype. result = typeRel(c, f, a) - # v--- is this correct? - if result <= isIntConv or inconsistentVarTypes(f, a): + if result <= isSubrange or inconsistentVarTypes(f, a): result = isNone #if result == isEqual: diff --git a/tests/overload/tproc_types_dont_like_subtypes.nim b/tests/overload/tproc_types_dont_like_subtypes.nim new file mode 100644 index 000000000..d322f41be --- /dev/null +++ b/tests/overload/tproc_types_dont_like_subtypes.nim @@ -0,0 +1,20 @@ +discard """ + errormsg: "got " + line: 20 +""" + +type + A = ref object of RootObj + B = ref object of A + + P = proc (a: A) + +# bug #16325 + +proc doThings(a: A, p: P) = + p(a) + +var x = proc (b: B) {.closure.} = + echo "B" + +doThings(B(), x) From f46569bafdfdd3290baf132f025d61a0e550dd58 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 2 Sep 2021 17:16:03 +0200 Subject: [PATCH 2968/4254] fixes #18494 (#18783) --- lib/system/alloc.nim | 46 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 479458950..6d83a2c17 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -1053,22 +1053,48 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = inc(result, it.size) it = it.next - proc getFreeMem(): int = - result = allocator.freeMem - #sysAssert(result == countFreeMem()) + when hasThreadSupport: + var sharedHeap: MemRegion + var heapLock: SysLock + initSysLock(heapLock) - proc getTotalMem(): int = return allocator.currMem - proc getOccupiedMem(): int = return allocator.occ #getTotalMem() - getFreeMem() - proc getMaxMem*(): int = return getMaxMem(allocator) + proc getFreeMem(): int = + #sysAssert(result == countFreeMem()) + when hasThreadSupport and defined(gcDestructors): + acquireSys(heapLock) + result = sharedHeap.freeMem + releaseSys(heapLock) + else: + result = allocator.freeMem + + proc getTotalMem(): int = + when hasThreadSupport and defined(gcDestructors): + acquireSys(heapLock) + result = sharedHeap.currMem + releaseSys(heapLock) + else: + result = allocator.currMem + + proc getOccupiedMem(): int = + when hasThreadSupport and defined(gcDestructors): + acquireSys(heapLock) + result = sharedHeap.occ + releaseSys(heapLock) + else: + result = allocator.occ #getTotalMem() - getFreeMem() + + proc getMaxMem*(): int = + when hasThreadSupport and defined(gcDestructors): + acquireSys(heapLock) + result = getMaxMem(sharedHeap) + releaseSys(heapLock) + else: + result = getMaxMem(allocator) when defined(nimTypeNames): proc getMemCounters*(): (int, int) = getMemCounters(allocator) # -------------------- shared heap region ---------------------------------- - when hasThreadSupport: - var sharedHeap: MemRegion - var heapLock: SysLock - initSysLock(heapLock) proc allocSharedImpl(size: Natural): pointer = when hasThreadSupport: From 64165f03fc96d6e8293f1b065a2e1e45f9fc1bf8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 2 Sep 2021 22:15:08 -0700 Subject: [PATCH 2969/4254] testament --megatest:off now makes tests non-joinable so that they all run (#18787) --- testament/categories.nim | 2 +- testament/testament.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 6375105ee..6702d24a2 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -541,7 +541,7 @@ proc processSingleTest(r: var TResults, cat: Category, options, test: string, ta proc isJoinableSpec(spec: TSpec): bool = # xxx simplify implementation using a whitelist of fields that are allowed to be # set to non-default values (use `fieldPairs`), to avoid issues like bug #16576. - result = not spec.sortoutput and + result = useMegatest and not spec.sortoutput and spec.action == actionRun and not fileExists(spec.file.changeFileExt("cfg")) and not fileExists(spec.file.changeFileExt("nims")) and diff --git a/testament/testament.nim b/testament/testament.nim index ab6620c84..105f00156 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -28,6 +28,7 @@ var useColors = true var backendLogging = true var simulate = false var optVerbose = false +var useMegatest = true proc verboseCmd(cmd: string) = if optVerbose: @@ -645,7 +646,6 @@ proc main() = var targetsStr = "" var isMainProcess = true var skipFrom = "" - var useMegatest = true var p = initOptParser() p.next() From 0887dcc398a38c91e99a043acbb095afc7200460 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 3 Sep 2021 09:03:26 +0200 Subject: [PATCH 2970/4254] fixes #18786 (#18788) --- compiler/sempass2.nim | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b584bb232..cae2f926c 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -296,12 +296,11 @@ proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) = if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and s.magic != mNimvm: if s.guard != nil: guardGlobal(a, n, s.guard) - if strictEffects notin a.c.features: - if {sfGlobal, sfThread} * s.flags == {sfGlobal} and - (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): - #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n) - markGcUnsafe(a, s) - markSideEffect(a, s, n.info) + if {sfGlobal, sfThread} * s.flags == {sfGlobal} and + (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): + #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n) + markGcUnsafe(a, s) + markSideEffect(a, s, n.info) if s.owner != a.owner and s.kind in {skVar, skLet, skForVar, skResult, skParam} and {sfGlobal, sfThread} * s.flags == {}: a.isInnerProc = true From 0635697a89b3aef2a188a0bddb46965bae7ee70f Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Fri, 3 Sep 2021 14:20:57 +0200 Subject: [PATCH 2971/4254] Document `-d:async_backend` flag (#18700) * Document `-d:asyncBackend` flag Since libraries may want to support multiple async backends, it's useful to standardize the way this is done, so as to simplify usage of any async backend within the ecosystem. A similar text is being added to chronos here: https://github.com/status-im/nim-chronos/pull/216 See also https://github.com/status-im/nim-chronos/issues/207 * typos, add none * Update lib/pure/asyncdispatch.nim * Update lib/pure/asyncdispatch.nim Co-authored-by: Andreas Rumpf --- lib/pure/asyncdispatch.nim | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 955e66f6b..d87e2360f 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -165,6 +165,34 @@ ## ================ ## ## * The effect system (`raises: []`) does not work with async procedures. +## +## +## Multiple async backend support +## ============================== +## +## Thanks to its powerful macro support, Nim allows ``async``/``await`` to be +## implemented in libraries with only minimal support from the language - as +## such, multiple ``async`` libraries exist, including ``asyncdispatch`` and +## ``chronos``, and more may come to be developed in the future. +## +## Libraries built on top of async/await may wish to support multiple async +## backends - the best way to do so is to create separate modules for each backend +## that may be imported side-by-side. +## +## An alternative way is to select backend using a global compile flag - this +## method makes it difficult to compose applications that use both backends as may +## happen with transitive dependencies, but may be appropriate in some cases - +## libraries choosing this path should call the flag `asyncBackend`, allowing +## applications to choose the backend with `-d:asyncBackend=`. +## +## Known `async` backends include: +## +## * `none` - ``-d:asyncBackend=none`` - disable ``async`` support completely +## * `asyncdispatch -``-d:asyncBackend=asyncdispatch`` +## * `chronos ` - ``-d:asyncBackend=chronos`` +## +## ``none`` can be used when a library supports both a synchronous and +## asynchronous API, to disable the latter. import os, tables, strutils, times, heapqueue, options, asyncstreams import options, math, std/monotimes From 06ff0e96249884f4ac6c49dadc96147be1c31097 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 3 Sep 2021 15:18:55 +0200 Subject: [PATCH 2972/4254] fixes #18769 (#18790) --- compiler/semgnrc.nim | 8 +++++++- tests/enum/toverloadable_enums.nim | 11 ++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 3df1e0c3f..e249d88e8 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -107,6 +107,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, else: result = n onUse(n.info, s) + of skEnumField: + if overloadableEnums in c.features: + result = symChoice(c, n, s, scOpen) + else: + result = newSymNode(s, n.info) + onUse(n.info, s) else: result = newSymNode(s, n.info) onUse(n.info, s) @@ -407,7 +413,7 @@ proc semGenericStmt(c: PContext, n: PNode, a[^1] = semGenericStmt(c, a[^1], flags, ctx) for j in 0.. Date: Fri, 3 Sep 2021 22:41:00 +0800 Subject: [PATCH 2973/4254] remove unnecessary if statement (#18792) --- compiler/transf.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 80794b581..3250f2ec4 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -434,12 +434,12 @@ proc transformYield(c: PTransf, n: PNode): PNode = else: # we need to introduce new local variables: result.add(introduceNewLocalVars(c, c.transCon.forLoopBody)) - if result.len > 0: - for idx in 0 ..< result.len: - var changeNode = result[idx] - changeNode.info = c.transCon.forStmt.info - for i, child in changeNode: - child.info = changeNode.info + + for idx in 0 ..< result.len: + var changeNode = result[idx] + changeNode.info = c.transCon.forStmt.info + for i, child in changeNode: + child.info = changeNode.info proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = transformSons(c, n) From c2b20516d33520b1d339b447ece32ade8625fefc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 3 Sep 2021 17:31:16 +0200 Subject: [PATCH 2974/4254] implemented Unicode operators (#18789) * implemented Unicode operators; refs https://github.com/nim-lang/RFCs/issues/388 * bugfix * better test * arguably more elegant implementation * Update changelog.md Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 7 +++ compiler/lexer.nim | 80 +++++++++++++++++++++++++++--- compiler/options.nim | 3 +- doc/manual.rst | 19 +++++++ tests/lexer/nim.cfg | 1 + tests/lexer/tunicode_operators.nim | 14 ++++++ 6 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 tests/lexer/nim.cfg create mode 100644 tests/lexer/tunicode_operators.nim diff --git a/changelog.md b/changelog.md index 10824cfc6..bc4898c9d 100644 --- a/changelog.md +++ b/changelog.md @@ -445,6 +445,13 @@ proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.} To enable the new effect system, use --experimental:strictEffects. +- Nim now supports a small subset of Unicode operators as operator symbols. + The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔". + To enable this feature, use `--experimental:unicodeOperators`. Note that due + to parser limitations you **cannot** enable this feature via a + pragma `{.experimental: "unicodeOperators".}` reliably. + + ## Compiler changes - Added `--declaredLocs` to show symbol declaration location in messages. diff --git a/compiler/lexer.nim b/compiler/lexer.nim index c7a9aa47f..ddf98661a 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -882,15 +882,66 @@ proc endOperator(L: var Lexer, tok: var Token, pos: int, else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon)) L.bufpos = pos +const + UnicodeOperatorStartChars = {'\226', '\194', '\195'} + # the allowed unicode characters ("∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔") + # all start with one of these. + +type + UnicodeOprPred = enum + Mul, Add + +proc unicodeOprLen(buf: cstring; pos: int): (int8, UnicodeOprPred) = + template m(len): untyped = (int8(len), Mul) + template a(len): untyped = (int8(len), Add) + result = 0.m + case buf[pos] + of '\226': + if buf[pos+1] == '\136': + if buf[pos+2] == '\152': result = 3.m # ∘ + elif buf[pos+2] == '\153': result = 3.m # ∙ + elif buf[pos+2] == '\167': result = 3.m # ∧ + elif buf[pos+2] == '\168': result = 3.a # ∨ + elif buf[pos+2] == '\169': result = 3.m # ∩ + elif buf[pos+2] == '\170': result = 3.a # ∪ + elif buf[pos+1] == '\138': + if buf[pos+2] == '\147': result = 3.m # ⊓ + elif buf[pos+2] == '\148': result = 3.a # ⊔ + elif buf[pos+2] == '\149': result = 3.a # ⊕ + elif buf[pos+2] == '\150': result = 3.a # ⊖ + elif buf[pos+2] == '\151': result = 3.m # ⊗ + elif buf[pos+2] == '\152': result = 3.m # ⊘ + elif buf[pos+2] == '\153': result = 3.m # ⊙ + elif buf[pos+2] == '\155': result = 3.m # ⊛ + elif buf[pos+2] == '\158': result = 3.a # ⊞ + elif buf[pos+2] == '\159': result = 3.a # ⊟ + elif buf[pos+2] == '\160': result = 3.m # ⊠ + elif buf[pos+2] == '\161': result = 3.m # ⊡ + elif buf[pos+1] == '\152' and buf[pos+2] == '\133': result = 3.m # ★ + of '\194': + if buf[pos+1] == '\177': result = 2.a # ± + of '\195': + if buf[pos+1] == '\151': result = 2.m # × + else: + discard + proc getOperator(L: var Lexer, tok: var Token) = var pos = L.bufpos tokenBegin(tok, pos) var h: Hash = 0 while true: var c = L.buf[pos] - if c notin OpChars: break - h = h !& ord(c) - inc(pos) + if c in OpChars: + h = h !& ord(c) + inc(pos) + elif c in UnicodeOperatorStartChars and unicodeOperators in L.config.features: + let oprLen = unicodeOprLen(L.buf, pos)[0] + if oprLen == 0: break + for i in 0..', '!': result = 5 of '.': considerAsgn(6) of '?': result = 2 + of UnicodeOperatorStartChars: + if tok.ident.s[^1] == '=': + result = 1 + else: + let (len, pred) = unicodeOprLen(cstring(tok.ident.s), 0) + if len != 0: + result = if pred == Mul: MulPred else: PlusPred + else: + result = 2 else: considerAsgn(2) of tkDiv, tkMod, tkShl, tkShr: result = 9 of tkDotDot: result = 6 @@ -1167,10 +1230,15 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = var c = L.buf[L.bufpos] tok.line = L.lineNumber tok.col = getColNumber(L, L.bufpos) - if c in SymStartChars - {'r', 'R'}: + if c in SymStartChars - {'r', 'R'} - UnicodeOperatorStartChars: getSymbol(L, tok) else: case c + of UnicodeOperatorStartChars: + if unicodeOperators in L.config.features and unicodeOprLen(L.buf, L.bufpos)[0] != 0: + getOperator(L, tok) + else: + getSymbol(L, tok) of '#': scanComment(L, tok) of '*': diff --git a/compiler/options.nim b/compiler/options.nim index 89a16a49c..ea302aed6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -205,7 +205,8 @@ type views, strictNotNil, overloadableEnums, - strictEffects + strictEffects, + unicodeOperators LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/doc/manual.rst b/doc/manual.rst index 02c688968..997253f16 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -700,6 +700,25 @@ contain a dot: `{..}` are the three tokens `{`:tok:, `..`:tok:, `}`:tok: and not the two tokens `{.`:tok:, `.}`:tok:. +Unicode Operators +----------------- + +Under the `--experimental:unicodeOperators` switch these Unicode operators are +also parsed as operators:: + + ∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ # same priority as * (multiplication) + ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔ # same priority as + (addition) + + +If enabled, Unicode operators can be combined with non-Unicode operator +symbols. The usual precedence extensions then apply, for example, `⊠=` is an +assignment like operator just like `*=` is. + +No Unicode normalization step is performed. + +**Note**: Due to parser limitations one **cannot** enable this feature via a +pragma `{.experimental: "unicodeOperators".}` reliably. + Syntax ====== diff --git a/tests/lexer/nim.cfg b/tests/lexer/nim.cfg new file mode 100644 index 000000000..f7a301a10 --- /dev/null +++ b/tests/lexer/nim.cfg @@ -0,0 +1 @@ +--experimental:unicodeOperators diff --git a/tests/lexer/tunicode_operators.nim b/tests/lexer/tunicode_operators.nim new file mode 100644 index 000000000..74fcbb763 --- /dev/null +++ b/tests/lexer/tunicode_operators.nim @@ -0,0 +1,14 @@ +#{.experimental: "unicodeOperators".} + +proc `⊙`(x, y: int): int = x * y +proc `⊙=`(x: var int, y: int) = x *= y + +proc `⊞++`(x, y: int): int = x + y + +var x = 45 +x ⊙= 9 ⊞++ 4 ⊙ 3 + +var y = 45 +y *= 9 + 4 * 3 + +assert x == y From cddf8ec6f684e5636a114e0e286bc6609e01f228 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 3 Sep 2021 21:52:24 +0200 Subject: [PATCH 2975/4254] implements https://github.com/nim-lang/RFCs/issues/407 (#18793) --- compiler/semdata.nim | 1 + compiler/semexprs.nim | 16 ++++++++++++---- compiler/semobjconstr.nim | 31 ++++++++++++++++-------------- compiler/sempass2.nim | 2 ++ compiler/semstmts.nim | 14 ++++++++++++++ compiler/sigmatch.nim | 14 ++++++++++++-- compiler/wordrecg.nim | 1 + doc/manual.rst | 35 ++++++++++++++++++++++++++++++++++ tests/objvariant/treassign.nim | 9 +++++++++ 9 files changed, 103 insertions(+), 20 deletions(-) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 31affb24f..422d1223a 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -160,6 +160,7 @@ type importModuleMap*: Table[int, int] # (module.id, module.id) lastTLineInfo*: TLineInfo sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index + inUncheckedAssignSection*: int template config*(c: PContext): ConfigRef = c.graph.config diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f2fe54fad..3edeae324 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -691,8 +691,12 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = else: result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) result.add n - if isAssignable(c, n) notin {arLValue, arLocalLValue}: - localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n)) + let aa = isAssignable(c, n) + if aa notin {arLValue, arLocalLValue}: + if aa == arDiscriminant and c.inUncheckedAssignSection > 0: + discard "allow access within a cast(unsafeAssign) section" + else: + localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n)) proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n @@ -738,9 +742,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = if i < t.len and t[i] != nil and skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}: let it = n[i] - if isAssignable(c, it) notin {arLValue, arLocalLValue}: + let aa = isAssignable(c, it) + if aa notin {arLValue, arLocalLValue}: if it.kind != nkHiddenAddr: - localError(c.config, it.info, errVarForOutParamNeededX % $it) + if aa == arDiscriminant and c.inUncheckedAssignSection > 0: + discard "allow access within a cast(unsafeAssign) section" + else: + localError(c.config, it.info, errVarForOutParamNeededX % $it) # bug #5113: disallow newSeq(result) where result is a 'var T': if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: var arg = n[1] #.skipAddr diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 1c97d32c8..1563e5c16 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -200,20 +200,22 @@ proc semConstructFields(c: PContext, n: PNode, if selectedBranch != -1: template badDiscriminatorError = - let fields = fieldsPresentInBranch(selectedBranch) - localError(c.config, constrCtx.initExpr.info, - ("cannot prove that it's safe to initialize $1 with " & - "the runtime value for the discriminator '$2' ") % - [fields, discriminator.sym.name.s]) + if c.inUncheckedAssignSection == 0: + let fields = fieldsPresentInBranch(selectedBranch) + localError(c.config, constrCtx.initExpr.info, + ("cannot prove that it's safe to initialize $1 with " & + "the runtime value for the discriminator '$2' ") % + [fields, discriminator.sym.name.s]) mergeInitStatus(result, initNone) template wrongBranchError(i) = - let fields = fieldsPresentInBranch(i) - localError(c.config, constrCtx.initExpr.info, - "a case selecting discriminator '$1' with value '$2' " & - "appears in the object construction, but the field(s) $3 " & - "are in conflict with this value." % - [discriminator.sym.name.s, discriminatorVal.renderTree, fields]) + if c.inUncheckedAssignSection == 0: + let fields = fieldsPresentInBranch(i) + localError(c.config, constrCtx.initExpr.info, + ("a case selecting discriminator '$1' with value '$2' " & + "appears in the object construction, but the field(s) $3 " & + "are in conflict with this value.") % + [discriminator.sym.name.s, discriminatorVal.renderTree, fields]) template valuesInConflictError(valsDiff) = localError(c.config, discriminatorVal.info, ("possible values " & @@ -251,9 +253,10 @@ proc semConstructFields(c: PContext, n: PNode, badDiscriminatorError() elif discriminatorVal.sym.kind notin {skLet, skParam} or discriminatorVal.sym.typ.kind in {tyVar}: - localError(c.config, discriminatorVal.info, - "runtime discriminator must be immutable if branch fields are " & - "initialized, a 'let' binding is required.") + if c.inUncheckedAssignSection == 0: + localError(c.config, discriminatorVal.info, + "runtime discriminator must be immutable if branch fields are " & + "initialized, a 'let' binding is required.") elif ctorCase[ctorIdx].kind == nkElifBranch: localError(c.config, discriminatorVal.info, "branch initialization " & "with a runtime discriminator is not supported inside of an " & diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index cae2f926c..2df6327b8 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -961,6 +961,8 @@ proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) = else: bc.exc = newNodeI(nkArgList, pragma.info) bc.exc.add n + of wUncheckedAssign: + discard "handled in sempass1" else: localError(tracked.config, pragma.info, "invalid pragma block: " & $pragma) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index df0e2778b..2c5f3ba54 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2223,7 +2223,21 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = checkSonsLen(n, 2, c.config) let pragmaList = n[0] pragma(c, nil, pragmaList, exprPragmas, isStatement = true) + + var inUncheckedAssignSection = 0 + for p in pragmaList: + if whichPragma(p) == wCast: + case whichPragma(p[1]) + of wGcSafe, wNoSideEffect, wTags, wRaises: + discard "handled in sempass2" + of wUncheckedAssign: + inUncheckedAssignSection = 1 + else: + localError(c.config, p.info, "invalid pragma block: " & $p) + + inc c.inUncheckedAssignSection, inUncheckedAssignSection n[1] = semExpr(c, n[1]) + dec c.inUncheckedAssignSection, inUncheckedAssignSection result = n result.typ = n[1].typ for i in 0.. 0 + else: + result = false + proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, arg: PNode): PNode = result = nil @@ -1895,7 +1905,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, let constraint = c.converters[i].typ.n[1].sym.constraint if not constraint.isNil and not matchNodeKinds(constraint, arg): continue - if src.kind in {tyVar, tyLent} and not arg.isLValue: + if src.kind in {tyVar, tyLent} and not isLValue(c, arg): continue let destIsGeneric = containsGenericType(dest) @@ -2338,7 +2348,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int if argConverter.typ.kind notin {tyVar}: m.firstMismatch.kind = kVarNeeded noMatch() - elif not n.isLValue: + elif not isLValue(c, n): m.firstMismatch.kind = kVarNeeded noMatch() diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 6ff68be75..4ba807518 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -36,6 +36,7 @@ type wMemTracker = "memtracker", wObjChecks = "objchecks", wIntDefine = "intdefine", wStrDefine = "strdefine", wBoolDefine = "booldefine", wCursor = "cursor", wNoalias = "noalias", wEffectsOf = "effectsOf", + wUncheckedAssign = "uncheckedAssign", wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor", wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp", diff --git a/doc/manual.rst b/doc/manual.rst index 997253f16..714f98bdc 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1854,6 +1854,41 @@ A small example: let unknownKindBounded = range[nkAdd..nkSub](unknownKind) z = Node(kind: unknownKindBounded, leftOp: Node(), rightOp: Node()) + +cast uncheckedAssign +-------------------- + +Some restrictions for case objects can be disabled via a `{.cast(unsafeAssign).}` section: + +.. code-block:: nim + :test: "nim c $1" + + type + TokenKind* = enum + strLit, intLit + Token = object + case kind*: TokenKind + of strLit: + s*: string + of intLit: + i*: int64 + + proc passToVar(x: var TokenKind) = discard + + var t = Token(kind: strLit, s: "abc") + + {.cast(uncheckedAssign).}: + # inside the 'cast' section it is allowed to pass 't.kind' to a 'var T' parameter: + passToVar(t.kind) + + # inside the 'cast' section it is allowed to set field 's' even though the + # constructed 'kind' field has an unknown value: + t = Token(kind: t.kind, s: "abc") + + # inside the 'cast' section it is allowed to assign to the 't.kind' field directly: + t.kind = intLit + + Set type -------- diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim index 2938b30a3..9549cb29c 100644 --- a/tests/objvariant/treassign.nim +++ b/tests/objvariant/treassign.nim @@ -25,3 +25,12 @@ t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34)) t.curr = TokenObject(kind: Token.foo, foo: "foo") echo "SUCCESS" + +proc passToVar(x: var Token) = discard + +{.cast(uncheckedAssign).}: + passToVar(t.curr.kind) + + t.curr = TokenObject(kind: t.curr.kind, foo: "abc") + + t.curr.kind = Token.foo From ac7acd827cd05ea916c53513e68d13be0d63a604 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Sep 2021 08:18:00 +0200 Subject: [PATCH 2976/4254] =?UTF-8?q?we=20need=20something=20better=20than?= =?UTF-8?q?=20warningAsError=20for=20effect=20handling=20viol=E2=80=A6=20(?= =?UTF-8?q?#18796)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * we need something better than warningAsError for effect handling violations --- compiler/sempass2.nim | 4 ++-- lib/system.nim | 3 +-- nimdoc/test_out_index_dot_html/expected/index.html | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 2df6327b8..6a0e8772a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1420,7 +1420,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let p = s.ast[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): - checkRaisesSpec(g, emitWarnings, raisesSpec, t.exc, "can raise an unlisted exception: ", + checkRaisesSpec(g, false, raisesSpec, t.exc, "can raise an unlisted exception: ", hints=on, subtypeRelation, hintsArg=s.ast[0]) # after the check, use the formal spec: effects[exceptionEffects] = raisesSpec @@ -1429,7 +1429,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let tagsSpec = effectSpec(p, wTags) if not isNil(tagsSpec): - checkRaisesSpec(g, emitWarnings, tagsSpec, t.tags, "can have an unlisted effect: ", + checkRaisesSpec(g, false, tagsSpec, t.tags, "can have an unlisted effect: ", hints=off, subtypeRelation) # after the check, use the formal spec: effects[tagEffects] = tagsSpec diff --git a/lib/system.nim b/lib/system.nim index 740c4419f..c93af0854 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2004,8 +2004,7 @@ elif hasAlloc: inc(i) {.pop.} -proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", tags: [WriteIOEffect], - benign, sideEffect.} +proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", benign, sideEffect.} ## Writes and flushes the parameters to the standard output. ## ## Special built-in that takes a variable number of arguments. Each argument diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 458a0394f..3499b5326 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -122,7 +122,7 @@ window.addEventListener('DOMContentLoaded', main);

    Procs

    -
    proc foo() {....raises: [], tags: [WriteIOEffect].}
    +
    proc foo() {....raises: [], tags: [].}
    I do foo From 686096a912107e620142e78ef98a380bb8a4764f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Sep 2021 12:52:24 +0200 Subject: [PATCH 2977/4254] documented overloadable enums and changelog improvements (#18797) --- changelog.md | 51 ++++++++++++++++++++++++++++---------------------- doc/manual.rst | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/changelog.md b/changelog.md index bc4898c9d..d553864b6 100644 --- a/changelog.md +++ b/changelog.md @@ -114,16 +114,18 @@ ## Standard library additions and changes - `strformat`: - added support for parenthesized expressions. - added support for const string's instead of just string literals + - added support for parenthesized expressions. + - added support for const string's instead of just string literals +- `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`; + use `-d:nimLegacyCopyFile` for OSX < 10.5. - `system.addFloat` and `system.$` now can produce string representations of floating point numbers that are minimal in size and that "roundtrip" (via the "Dragonbox" algorithm). This currently has to be enabled via `-d:nimPreviewFloatRoundtrip`. It is expected that this behavior becomes the new default in upcoming versions, as with other `nimPreviewX` define flags. -- Fixed buffer overflow bugs in `net` +- Fixed buffer overflow bugs in `net`. - Exported `sslHandle` from `net` and `asyncnet`. @@ -187,10 +189,11 @@ - Added `std/sysrand` module to get random numbers from a secure source provided by the operating system. -- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum. - Added `items` for enums with holes. - Added `symbolName` to return the enum symbol name ignoring the human readable name. - Added `symbolRank` to return the index in which an enum member is listed in an enum. +- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates + case statement to parse string to enum. +- Added `items` for enums with holes. +- Added `symbolName` to return the enum symbol name ignoring the human readable name. +- Added `symbolRank` to return the index in which an enum member is listed in an enum. - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). @@ -381,15 +384,10 @@ ## Language changes -- `nimscript` now handles `except Exception as e`. - - The `cstring` doesn't support `[]=` operator in JS backend. - nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. -- `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`; - use `-d:nimLegacyCopyFile` for OSX < 10.5. - - The required name of case statement macros for the experimental `caseStmtMacros` feature has changed from `match` to `` `case` ``. @@ -403,18 +401,11 @@ - Tuple expressions are now parsed consistently as `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. -- `nim e` now accepts arbitrary file extensions for the nimscript file, - although `.nims` is still the preferred extension in general. - - Added `iterable[T]` type class to match called iterators, which enables writing: `template fn(a: iterable)` instead of `template fn(a: untyped)` - A new import syntax `import foo {.all.}` now allows to import all symbols (public or private) - from `foo`. It works in combination with all pre-existing import features. - This reduces or eliminates the need for workarounds such as using `include` (which has known issues) - when you need a private symbol for testing or making some internal APIs public just because - another internal module needs those. - It also helps mitigate the lack of cyclic imports in some cases. + from `foo`. This can be useful for testing purposes. - Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields for an object type in the current scope. @@ -422,7 +413,7 @@ - `typeof(voidStmt)` now works and returns `void`. - The `gc:orc` algorithm was refined so that custom container types can participate in the - cycle collection process. + cycle collection process. See the documentation of `=trace` for more details. - On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. This is only supported for `--gc:orc` or `--gc:arc`. @@ -449,7 +440,18 @@ proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.} The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔". To enable this feature, use `--experimental:unicodeOperators`. Note that due to parser limitations you **cannot** enable this feature via a - pragma `{.experimental: "unicodeOperators".}` reliably. + pragma `{.experimental: "unicodeOperators".}` reliably, you need to enable + it via the command line or in a configuration file. + +- There is a new `cast` section `{.cast(uncheckedAssign).}: body` that disables some + compiler checks regarding `case objects`. This allows serialization libraries + to avoid ugly, non-portable solutions. See https://github.com/nim-lang/RFCs/issues/407 + for more details. + +- Enum values can now be overloaded. This needs to be enabled + via `{.experimental: "overloadableEnums".}`. We hope that this feature allows for the + development of more fluent (less ugly) APIs. See https://github.com/nim-lang/RFCs/issues/373 + for more details. ## Compiler changes @@ -529,6 +531,11 @@ proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.} ## Tool changes +- `nimscript` now handles `except Exception as e`. + +- `nim e` now accepts arbitrary file extensions for the nimscript file, + although `.nims` is still the preferred extension in general. + - Latex doc generation is revised: output `.tex` files should be compiled by `xelatex` (not by `pdflatex` as before). Now default Latex settings provide support for Unicode and do better job for avoiding margin overflows. diff --git a/doc/manual.rst b/doc/manual.rst index 714f98bdc..e9c730c7b 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1323,6 +1323,47 @@ as `MyEnum.value`: To implement bit fields with enums see `Bit fields <#set-type-bit-fields>`_ +Overloadable enum field names +----------------------------- + +To be enabled via `{.experimental: "overloadableEnums".}`. + +Enum field names are overloadable much like routines. When an overloaded +enum field is used, it produces a closed sym choice construct, here +written as `(E|E)`. +During overload resolution the right `E` is picked, if possible. +For (array/object...) constructors the right `E` is picked, comparable to +how `[byte(1), 2, 3]` works, one needs to use `[T.E, E2, E3]`. Ambiguous +enum fields produce a static error: + +.. code-block:: nim + :test: "nim c $1" + + {.experimental: "overloadableEnums".} + + type + E1 = enum + value1, + value2 + E2 = enum + value1, + value2 = 4 + + const + Lookuptable = [ + E1.value1: "1", + value2: "2" + ] + + proc p(e: E1) = + # disambiguation in 'case' statements: + case e + of value1: echo "A" + of value2: echo "B" + + p value2 + + String type ----------- All string literals are of the type `string`. A string in Nim is very From 3c2edd142b527c34163cbd7ea9ad94518f46e9ae Mon Sep 17 00:00:00 2001 From: Sven Keller Date: Sat, 4 Sep 2021 12:53:02 +0200 Subject: [PATCH 2978/4254] fix for js strict mode (#18799) * Assignments, which would accidentally create global variables, instead throw an error in strict mode * Assignment to a getter-only property Co-authored-by: Sven Keller --- compiler/jsgen.nim | 2 +- lib/system/jssys.nim | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 931e56475..f009c83f2 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1769,7 +1769,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = inc p.extraIndent elif useGlobalPragmas: lineF(p, "if (globalThis.$1 === undefined) {$n", varName) - varCode = $varName + varCode = "globalThis." & $varName inc p.extraIndent else: varCode = "var $2" diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 63e7b3d9d..cd4f378be 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -593,12 +593,9 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = `result` = null; } else { - if (`dest` === null || `dest` === undefined) { + if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { `dest` = new Array(`src`.length); } - else { - `dest`.length = `src`.length; - } `result` = `dest`; for (var i = 0; i < `src`.length; ++i) { `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base); From b3ad68edea72f04275c9b1e330cafb77254d945c Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 4 Sep 2021 21:57:02 +0800 Subject: [PATCH 2979/4254] remove channels (#18801) * remove channels * test --- changelog.md | 2 - doc/manual.rst | 2 +- lib/std/channels.nim | 498 ----------------------------- tests/stdlib/tchannels.nim | 33 -- tests/stdlib/tchannels_pthread.nim | 322 ------------------- tests/stdlib/tchannels_simple.nim | 67 ---- 6 files changed, 1 insertion(+), 923 deletions(-) delete mode 100644 lib/std/channels.nim delete mode 100644 tests/stdlib/tchannels.nim delete mode 100644 tests/stdlib/tchannels_pthread.nim delete mode 100644 tests/stdlib/tchannels_simple.nim diff --git a/changelog.md b/changelog.md index d553864b6..3658fb105 100644 --- a/changelog.md +++ b/changelog.md @@ -341,8 +341,6 @@ - Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). -- Added `std/channels`. - - Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). - `std/times`: diff --git a/doc/manual.rst b/doc/manual.rst index e9c730c7b..7976ffe0f 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -8016,7 +8016,7 @@ Threads To enable thread support the `--threads:on`:option: command-line switch needs to be used. The system_ module then contains several threading primitives. -See the `threads `_ and `channels `_ modules +See the `channels `_ modules for the low-level thread API. There are also high-level parallelism constructs available. See `spawn `_ for further details. diff --git a/lib/std/channels.nim b/lib/std/channels.nim deleted file mode 100644 index 5ff141384..000000000 --- a/lib/std/channels.nim +++ /dev/null @@ -1,498 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2021 Andreas Prell, Mamy André-Ratsimbazafy & Nim Contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - - -# Based on https://github.com/mratsim/weave/blob/5696d94e6358711e840f8c0b7c684fcc5cbd4472/unused/channels/channels_legacy.nim -# Those are translations of @aprell (Andreas Prell) original channels from C to Nim -# (https://github.com/aprell/tasking-2.0/blob/master/src/channel_shm/channel.c) -# And in turn they are an implementation of Michael & Scott lock-based queues -# (note the paper has 2 channels: lock-free and lock-based) with additional caching: -# Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms -# Maged M. Michael, Michael L. Scott, 1996 -# https://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf - -## This module only works with `--gc:arc` or `--gc:orc`. -## -## .. warning:: This module is experimental and its interface may change. -## -## The following is a simple example of two different ways to use channels: -## blocking and non-blocking. -## - -runnableExamples("--threads:on --gc:orc"): - import std/os - - # In this example a channel is declared at module scope. - # Channels are generic, and they include support for passing objects between - # threads. - # Note that isolated data passed through channels is moved around. - var chan = newChannel[string]() - - # This proc will be run in another thread using the threads module. - proc firstWorker() = - chan.send("Hello World!") - - # This is another proc to run in a background thread. This proc takes a while - # to send the message since it sleeps for 2 seconds (or 2000 milliseconds). - proc secondWorker() = - sleep(2000) - chan.send("Another message") - - # Launch the worker. - var worker1: Thread[void] - createThread(worker1, firstWorker) - - # Block until the message arrives, then print it out. - let dest = chan.recv() - assert dest == "Hello World!" - - # Wait for the thread to exit before moving on to the next example. - worker1.joinThread() - - # Launch the other worker. - var worker2: Thread[void] - createThread(worker2, secondWorker) - # This time, use a non-blocking approach with tryRecv. - # Since the main thread is not blocked, it could be used to perform other - # useful work while it waits for data to arrive on the channel. - var messages: seq[string] - while true: - var msg = "" - if chan.tryRecv(msg): - messages.add msg # "Another message" - break - - messages.add "Pretend I'm doing useful work..." - # For this example, sleep in order not to flood stdout with the above - # message. - sleep(400) - - # Wait for the second thread to exit before cleaning up the channel. - worker2.joinThread() - - # Clean up the channel. - assert chan.close() - - assert messages[^1] == "Another message" - assert messages.len >= 2 - - -when not defined(gcArc) and not defined(gcOrc) and not defined(nimdoc): - {.error: "This channel implementation requires --gc:arc or --gc:orc".} - -import std/[locks, atomics, isolation] -import system/ansi_c - -# Channel (Shared memory channels) -# ---------------------------------------------------------------------------------- - -const - cacheLineSize {.intdefine.} = 64 # TODO: some Samsung phone have 128 cache-line - nimChannelCacheSize* {.intdefine.} = 100 - -type - ChannelRaw = ptr ChannelObj - ChannelObj = object - headLock, tailLock: Lock - notFullCond, notEmptyCond: Cond - closed: Atomic[bool] - size: int - itemsize: int # up to itemsize bytes can be exchanged over this channel - head {.align: cacheLineSize.} : int # Items are taken from head and new items are inserted at tail - tail: int - buffer: ptr UncheckedArray[byte] - atomicCounter: Atomic[int] - - ChannelCache = ptr ChannelCacheObj - ChannelCacheObj = object - next: ChannelCache - chanSize: int - chanN: int - numCached: int - cache: array[nimChannelCacheSize, ChannelRaw] - -# ---------------------------------------------------------------------------------- - -proc numItems(chan: ChannelRaw): int {.inline.} = - result = chan.tail - chan.head - if result < 0: - inc(result, 2 * chan.size) - - assert result <= chan.size - -template isFull(chan: ChannelRaw): bool = - abs(chan.tail - chan.head) == chan.size - -template isEmpty(chan: ChannelRaw): bool = - chan.head == chan.tail - -# Unbuffered / synchronous channels -# ---------------------------------------------------------------------------------- - -template numItemsUnbuf(chan: ChannelRaw): int = - chan.head - -template isFullUnbuf(chan: ChannelRaw): bool = - chan.head == 1 - -template isEmptyUnbuf(chan: ChannelRaw): bool = - chan.head == 0 - -# ChannelRaw kinds -# ---------------------------------------------------------------------------------- - -func isUnbuffered(chan: ChannelRaw): bool = - chan.size - 1 == 0 - -# ChannelRaw status and properties -# ---------------------------------------------------------------------------------- - -proc isClosed(chan: ChannelRaw): bool {.inline.} = load(chan.closed, moRelaxed) - -proc peek(chan: ChannelRaw): int {.inline.} = - (if chan.isUnbuffered: numItemsUnbuf(chan) else: numItems(chan)) - -# Per-thread channel cache -# ---------------------------------------------------------------------------------- - -var channelCache {.threadvar.}: ChannelCache -var channelCacheLen {.threadvar.}: int - -proc allocChannelCache(size, n: int): bool = - ## Allocate a free list for storing channels of a given type - var p = channelCache - - # Avoid multiple free lists for the exact same type of channel - while not p.isNil: - if size == p.chanSize and n == p.chanN: - return false - p = p.next - - p = cast[ptr ChannelCacheObj](c_malloc(csize_t sizeof(ChannelCacheObj))) - if p.isNil: - raise newException(OutOfMemDefect, "Could not allocate memory") - - p.chanSize = size - p.chanN = n - p.numCached = 0 - - p.next = channelCache - channelCache = p - inc channelCacheLen - result = true - -proc freeChannelCache*() = - ## Frees the entire channel cache, including all channels - var p = channelCache - var q: ChannelCache - - while not p.isNil: - q = p.next - for i in 0 ..< p.numCached: - let chan = p.cache[i] - if not chan.buffer.isNil: - c_free(chan.buffer) - deinitLock(chan.headLock) - deinitLock(chan.tailLock) - deinitCond(chan.notFullCond) - deinitCond(chan.notEmptyCond) - c_free(chan) - c_free(p) - dec channelCacheLen - p = q - - assert(channelCacheLen == 0) - channelCache = nil - -# Channels memory ops -# ---------------------------------------------------------------------------------- - -proc allocChannel(size, n: int): ChannelRaw = - when nimChannelCacheSize > 0: - var p = channelCache - - while not p.isNil: - if size == p.chanSize and n == p.chanN: - # Check if free list contains channel - if p.numCached > 0: - dec p.numCached - result = p.cache[p.numCached] - assert(result.isEmpty) - return - else: - # All the other lists in cache won't match - break - p = p.next - - result = cast[ChannelRaw](c_malloc(csize_t sizeof(ChannelObj))) - if result.isNil: - raise newException(OutOfMemDefect, "Could not allocate memory") - - # To buffer n items, we allocate for n - result.buffer = cast[ptr UncheckedArray[byte]](c_malloc(csize_t n*size)) - if result.buffer.isNil: - raise newException(OutOfMemDefect, "Could not allocate memory") - - initLock(result.headLock) - initLock(result.tailLock) - initCond(result.notFullCond) - initCond(result.notEmptyCond) - - result.closed.store(false, moRelaxed) # We don't need atomic here, how to? - result.size = n - result.itemsize = size - result.head = 0 - result.tail = 0 - result.atomicCounter.store(0, moRelaxed) - - when nimChannelCacheSize > 0: - # Allocate a cache as well if one of the proper size doesn't exist - discard allocChannelCache(size, n) - -proc freeChannel(chan: ChannelRaw) = - if chan.isNil: - return - - when nimChannelCacheSize > 0: - var p = channelCache - while not p.isNil: - if chan.itemsize == p.chanSize and - chan.size == p.chanN: - if p.numCached < nimChannelCacheSize: - # If space left in cache, cache it - p.cache[p.numCached] = chan - inc p.numCached - return - else: - # All the other lists in cache won't match - break - p = p.next - - if not chan.buffer.isNil: - c_free(chan.buffer) - - deinitLock(chan.headLock) - deinitLock(chan.tailLock) - deinitCond(chan.notFullCond) - deinitCond(chan.notEmptyCond) - - c_free(chan) - -# MPMC Channels (Multi-Producer Multi-Consumer) -# ---------------------------------------------------------------------------------- - -proc sendUnbufferedMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBlocking: bool): bool = - if nonBlocking and chan.isFullUnbuf: - return false - - acquire(chan.headLock) - - if nonBlocking and chan.isFullUnbuf: - # Another thread was faster - release(chan.headLock) - return false - - while chan.isFullUnbuf: - wait(chan.notFullcond, chan.headLock) - - assert chan.isEmptyUnbuf - assert size <= chan.itemsize - copyMem(chan.buffer, data, size) - - chan.head = 1 - - signal(chan.notEmptyCond) - release(chan.headLock) - result = true - -proc sendMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBlocking: bool): bool = - assert not chan.isNil - assert not data.isNil - - if isUnbuffered(chan): - return sendUnbufferedMpmc(chan, data, size, nonBlocking) - - if nonBlocking and chan.isFull: - return false - - acquire(chan.tailLock) - - if nonBlocking and chan.isFull: - # Another thread was faster - release(chan.tailLock) - return false - - while chan.isFull: - wait(chan.notFullcond, chan.tailLock) - - assert not chan.isFull - assert size <= chan.itemsize - - let writeIdx = if chan.tail < chan.size: chan.tail - else: chan.tail - chan.size - - copyMem(chan.buffer[writeIdx * chan.itemsize].addr, data, size) - - inc chan.tail - if chan.tail == 2 * chan.size: - chan.tail = 0 - - signal(chan.notEmptyCond) - release(chan.tailLock) - result = true - -proc recvUnbufferedMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bool = - if nonBlocking and chan.isEmptyUnbuf: - return false - - acquire(chan.headLock) - - if nonBlocking and chan.isEmptyUnbuf: - # Another thread was faster - release(chan.headLock) - return false - - while chan.isEmptyUnbuf: - wait(chan.notEmptyCond, chan.headLock) - - assert chan.isFullUnbuf - assert size <= chan.itemsize - - copyMem(data, chan.buffer, size) - - chan.head = 0 - - signal(chan.notFullCond) - release(chan.headLock) - result = true - -proc recvMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bool = - assert not chan.isNil - assert not data.isNil - - if isUnbuffered(chan): - return recvUnbufferedMpmc(chan, data, size, nonBlocking) - - if nonBlocking and chan.isEmpty: - return false - - acquire(chan.headLock) - - if nonBlocking and chan.isEmpty: - # Another thread took the last data - release(chan.headLock) - return false - - while chan.isEmpty: - wait(chan.notEmptyCond, chan.headLock) - - assert not chan.isEmpty - assert size <= chan.itemsize - - let readIdx = if chan.head < chan.size: chan.head - else: chan.head - chan.size - - copyMem(data, chan.buffer[readIdx * chan.itemsize].addr, size) - - inc chan.head - if chan.head == 2 * chan.size: - chan.head = 0 - - signal(chan.notFullCond) - release(chan.headLock) - result = true - -proc channelCloseMpmc(chan: ChannelRaw): bool = - # Unsynchronized - - if chan.isClosed: - # ChannelRaw already closed - return false - - store(chan.closed, true, moRelaxed) - result = true - -proc channelOpenMpmc(chan: ChannelRaw): bool = - # Unsynchronized - - if not chan.isClosed: - # ChannelRaw already open - return false - - store(chan.closed, false, moRelaxed) - result = true - -# Public API -# ---------------------------------------------------------------------------------- - -type - Channel*[T] = object ## Typed channels - d: ChannelRaw - -proc `=destroy`*[T](c: var Channel[T]) = - if c.d != nil: - if load(c.d.atomicCounter, moAcquire) == 0: - if c.d.buffer != nil: - freeChannel(c.d) - else: - atomicDec(c.d.atomicCounter) - -proc `=copy`*[T](dest: var Channel[T], src: Channel[T]) = - ## Shares `Channel` by reference counting. - if src.d != nil: - atomicInc(src.d.atomicCounter) - - if dest.d != nil: - `=destroy`(dest) - dest.d = src.d - -func trySend*[T](c: Channel[T], src: var Isolated[T]): bool {.inline.} = - ## Sends item to the channel(non blocking). - var data = src.extract - result = sendMpmc(c.d, data.addr, sizeof(T), true) - if result: - wasMoved(data) - -template trySend*[T](c: Channel[T], src: T): bool = - ## Helper templates for `trySend`. - trySend(c, isolate(src)) - -func tryRecv*[T](c: Channel[T], dst: var T): bool {.inline.} = - ## Receives item from the channel(non blocking). - recvMpmc(c.d, dst.addr, sizeof(T), true) - -func send*[T](c: Channel[T], src: sink Isolated[T]) {.inline.} = - ## Sends item to the channel(blocking). - var data = src.extract - discard sendMpmc(c.d, data.addr, sizeof(T), false) - wasMoved(data) - -template send*[T](c: Channel[T]; src: T) = - ## Helper templates for `send`. - send(c, isolate(src)) - -func recv*[T](c: Channel[T]): T {.inline.} = - ## Receives item from the channel(blocking). - discard recvMpmc(c.d, result.addr, sizeof(result), false) - -func open*[T](c: Channel[T]): bool {.inline.} = - result = c.d.channelOpenMpmc() - -func close*[T](c: Channel[T]): bool {.inline.} = - result = c.d.channelCloseMpmc() - -func peek*[T](c: Channel[T]): int {.inline.} = peek(c.d) - -proc newChannel*[T](elements = 30): Channel[T] = - ## Returns a new `Channel`. `elements` should be positive. - ## `elements` is used to specify whether a channel is buffered or not. - ## If `elements` = 1, the channel is unbuffered. If `elements` > 1, the - ## channel is buffered. - assert elements >= 1, "Elements must be positive!" - result = Channel[T](d: allocChannel(sizeof(T), elements)) diff --git a/tests/stdlib/tchannels.nim b/tests/stdlib/tchannels.nim deleted file mode 100644 index 492faf500..000000000 --- a/tests/stdlib/tchannels.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - timeout: 60.0 # but typically < 1s (in isolation but other tests running in parallel can affect this since based on epochTime) - disabled: "freebsd" - matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger" -""" - -when true: - # bug #17380: this was either blocking (without -d:danger) or crashing with SIGSEGV (with -d:danger) - import std/[channels, isolation] - const - N1 = 10 - N2 = 100 - var - sender: array[N1, Thread[void]] - receiver: array[5, Thread[void]] - - var chan = newChannel[seq[string]](N1 * N2) # large enough to not block - proc sendHandler() = - chan.send(isolate(@["Hello, Nim"])) - proc recvHandler() = - template fn = - let x = chan.recv() - fn() - - template benchmark() = - for t in mitems(sender): - t.createThread(sendHandler) - joinThreads(sender) - for t in mitems(receiver): - t.createThread(recvHandler) - joinThreads(receiver) - for i in 0.. 0 - -when defined(blockingTest): - const nonBlocking = false -else: - const nonBlocking = true - -type - Pthread {.importc: "pthread_t", header: "".} = distinct culong - PthreadAttr* {.byref, importc: "pthread_attr_t", header: "".} = object - Errno* = distinct cint - -proc pthread_create[T]( - thread: var Pthread, - attr: ptr PthreadAttr, # In Nim this is a var and how Nim sets a custom stack - fn: proc (x: ptr T): pointer {.thread, noconv.}, - arg: ptr T - ): Errno {.header: "".} - -proc pthread_join( - thread: Pthread, - thread_exit_status: ptr pointer - ): Errno {.header: "".} - -template channel_send_loop(chan: ChannelRaw, - data: sink pointer, - size: int, - body: untyped): untyped = - while not sendMpmc(chan, data, size, nonBlocking): - body - -template channel_receive_loop(chan: ChannelRaw, - data: pointer, - size: int, - body: untyped): untyped = - while not recvMpmc(chan, data, size, nonBlocking): - body - - -# Without threads:on or release, -# worker threads will crash on popFrame - -import std/unittest - -type ThreadArgs = object - ID: int - chan: ChannelRaw - -template Worker(id: int, body: untyped): untyped {.dirty.} = - if args.ID == id: - body - - -const Sender = 1 -const Receiver = 0 - -proc runSuite( - name: string, - fn: proc(args: ptr ThreadArgs): pointer {.noconv, gcsafe.} - ) = - var chan: ChannelRaw - - for i in Unbuffered .. Buffered: - if i == Unbuffered: - chan = allocChannel(size = 32, n = 1) - check: - peek(chan) == 0 - capacity(chan) == 1 - isBuffered(chan) == false - isUnbuffered(chan) == true - - else: - chan = allocChannel(size = int.sizeof.int, n = 7) - check: - peek(chan) == 0 - capacity(chan) == 7 - isBuffered(chan) == true - isUnbuffered(chan) == false - - var threads: array[2, Pthread] - var args = [ - ThreadArgs(ID: 0, chan: chan), - ThreadArgs(ID: 1, chan: chan) - ] - - discard pthread_create(threads[0], nil, fn, args[0].addr) - discard pthread_create(threads[1], nil, fn, args[1].addr) - - discard pthread_join(threads[0], nil) - discard pthread_join(threads[1], nil) - - freeChannel(chan) - -# ---------------------------------------------------------------------------------- - -proc thread_func(args: ptr ThreadArgs): pointer {.noconv.} = - - # Worker RECEIVER: - # --------- - # <- chan - # <- chan - # <- chan - # - # Worker SENDER: - # --------- - # chan <- 42 - # chan <- 53 - # chan <- 64 - # - - Worker(Receiver): - var val: int - for j in 0 ..< 3: - channel_receive_loop(args.chan, val.addr, val.sizeof.int): - # Busy loop, normally it should yield - discard - check: val == 42 + j*11 - - Worker(Sender): - var val: int - check: peek(args.chan) == 0 - for j in 0 ..< 3: - val = 42 + j*11 - channel_send_loop(args.chan, val.addr, val.sizeof.int): - # Busy loop, normally it should yield - discard - - return nil - -runSuite("[ChannelRaw] 2 threads can send data", thread_func) - -# ---------------------------------------------------------------------------------- - -iterator pairs(chan: ChannelRaw, T: typedesc): (int, T) = - var i = 0 - var x: T - while not isClosed(chan) or peek(chan) > 0: - let r = recvMpmc(chan, x.addr, x.sizeof.int, true) - # printf("x: %d, r: %d\n", x, r) - if r: - yield (i, x) - inc i - -proc thread_func_2(args: ptr ThreadArgs): pointer {.noconv.} = - # Worker RECEIVER: - # --------- - # <- chan until closed and empty - # - # Worker SENDER: - # --------- - # chan <- 42, 53, 64, ... - - const N = 100 - - Worker(Receiver): - for j, val in pairs(args.chan, int): - # TODO: Need special handling that doesn't allocate - # in thread with no GC - # when check fails - # - check: val == 42 + j*11 - - Worker(Sender): - var val: int - check: peek(args.chan) == 0 - for j in 0 ..< N: - val = 42 + j*11 - channel_send_loop(args.chan, val.addr, int.sizeof.int): - discard - discard channelCloseMpmc(args.chan) - - return nil - -runSuite("[ChannelRaw] channel_close, freeChannel, channelCache", thread_func_2) - -# ---------------------------------------------------------------------------------- - -proc isCached(chan: ChannelRaw): bool = - assert not chan.isNil - - var p = channelCache - while not p.isNil: - if chan.itemsize == p.chanSize and - chan.size == p.chanN: - for i in 0 ..< p.numCached: - if chan == p.cache[i]: - return true - # No more channel in cache can match - return false - p = p.next - return false - -block: # [ChannelRaw] ChannelRaw caching implementation - - # Start from clean cache slate - freeChannelCache() - - block: # Explicit caches allocation - check: - allocChannelCache(int sizeof(char), 4) - allocChannelCache(int sizeof(int), 8) - allocChannelCache(int sizeof(ptr float64), 16) - - # Don't create existing channel cache - not allocChannelCache(int sizeof(char), 4) - not allocChannelCache(int sizeof(int), 8) - not allocChannelCache(int sizeof(ptr float64), 16) - - check: - channelCacheLen == 3 - - # --------------------------------- - var chan, stash: array[10, ChannelRaw] - - block: # Implicit caches allocation - - chan[0] = allocChannel(sizeof(char), 4) - chan[1] = allocChannel(sizeof(int32), 8) - chan[2] = allocChannel(sizeof(ptr float64), 16) - - chan[3] = allocChannel(sizeof(char), 5) - chan[4] = allocChannel(sizeof(int64), 8) - chan[5] = allocChannel(sizeof(ptr float32), 24) - - # We have caches ready to store specific channel kinds - check: channelCacheLen == 6 # Cumulated with previous test - # But they are not in cache while in use - check: - not chan[0].isCached - not chan[1].isCached - not chan[2].isCached - not chan[3].isCached - not chan[4].isCached - not chan[5].isCached - - block: # Freed channels are returned to cache - stash[0..5] = chan.toOpenArray(0, 5) - for i in 0 .. 5: - # Free the channels - freeChannel(chan[i]) - - check: - stash[0].isCached - stash[1].isCached - stash[2].isCached - stash[3].isCached - stash[4].isCached - stash[5].isCached - - block: # Cached channels are being reused - - chan[6] = allocChannel(sizeof(char), 4) - chan[7] = allocChannel(sizeof(int32), 8) - chan[8] = allocChannel(sizeof(ptr float32), 16) - chan[9] = allocChannel(sizeof(ptr float64), 16) - - # All (itemsize, queue size, implementation) were already allocated - check: channelCacheLen == 6 - - # We reused old channels from cache - check: - chan[6] == stash[0] - chan[7] == stash[1] - chan[8] == stash[2] - # chan[9] - required a fresh alloc - - block: # Clearing the cache - - stash[6..9] = chan.toOpenArray(6, 9) - - for i in 6 .. 9: - freeChannel(chan[i]) - - check: - stash[6].isCached - stash[7].isCached - stash[8].isCached - stash[9].isCached - - freeChannelCache() - - # Check that nothing is cached anymore - for i in 0 .. 9: - check: not stash[i].isCached - # And length is reset to 0 - check: channelCacheLen == 0 - - # Cache can grow again - chan[0] = allocChannel(sizeof((int, float, int32, uint)), 1) - chan[1] = allocChannel(sizeof(int32), 0) - chan[2] = allocChannel(sizeof(int32), 0) - - check: channelCacheLen == 2 - - # Interleave cache clear and channel free - freeChannelCache() - check: channelCacheLen == 0 - - freeChannel(chan[0]) - freeChannel(chan[1]) - freeChannel(chan[2]) diff --git a/tests/stdlib/tchannels_simple.nim b/tests/stdlib/tchannels_simple.nim deleted file mode 100644 index 56e5fb8f1..000000000 --- a/tests/stdlib/tchannels_simple.nim +++ /dev/null @@ -1,67 +0,0 @@ -discard """ - matrix: "--threads:on --gc:orc; --threads:on --gc:arc" - disabled: "freebsd" -""" - -import std/channels -import std/os - -var chan = newChannel[string]() - -# This proc will be run in another thread using the threads module. -proc firstWorker() = - chan.send("Hello World!") - -# This is another proc to run in a background thread. This proc takes a while -# to send the message since it sleeps for 2 seconds (or 2000 milliseconds). -proc secondWorker() = - sleep(2000) - chan.send("Another message") - - -# Launch the worker. -var worker1: Thread[void] -createThread(worker1, firstWorker) - -# Block until the message arrives, then print it out. -let dest = chan.recv() -doAssert dest == "Hello World!" - -# Wait for the thread to exit before moving on to the next example. -worker1.joinThread() - -# Launch the other worker. -var worker2: Thread[void] -createThread(worker2, secondWorker) -# This time, use a non-blocking approach with tryRecv. -# Since the main thread is not blocked, it could be used to perform other -# useful work while it waits for data to arrive on the channel. - -var messages: seq[string] -var msg = "" -while true: - let tried = chan.tryRecv(msg) - if tried: - messages.add move(msg) - break - - messages.add "Pretend I'm doing useful work..." - # For this example, sleep in order not to flood stdout with the above - # message. - sleep(400) - -# Wait for the second thread to exit before cleaning up the channel. -worker2.joinThread() - -# Clean up the channel. -doAssert chan.close() -doAssert messages[^1] == "Another message" -doAssert messages.len >= 2 - - -block: - let chan0 = newChannel[int]() - let chan1 = chan0 - block: - let chan3 = chan0 - let chan4 = chan0 From e8dad482a309b1c33056aba22550d691845414d7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Sep 2021 15:57:16 +0200 Subject: [PATCH 2980/4254] fixes #16246 (#18800) --- compiler/seminst.nim | 3 ++- compiler/semtypinst.nim | 2 +- compiler/types.nim | 8 ++++++++ tests/arc/tarcmisc.nim | 11 +++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index e1fad236c..456e40a94 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -91,7 +91,8 @@ proc sameInstantiation(a, b: TInstantiation): bool = for i in 0..a.concreteTypes.high: if not compareTypes(a.concreteTypes[i], b.concreteTypes[i], flags = {ExactTypeDescValues, - ExactGcSafety}): return + ExactGcSafety, + PickyCAliases}): return result = true proc genericCacheGet(g: ModuleGraph; genericSym: PSym, entry: TInstantiation; diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 18febb52e..9f9eb9489 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -51,7 +51,7 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType = for j in 1..high(key.sons): # XXX sameType is not really correct for nested generics? if not compareTypes(inst[j], key[j], - flags = {ExactGenericParams}): + flags = {ExactGenericParams, PickyCAliases}): break matchType return inst diff --git a/compiler/types.nim b/compiler/types.nim index 61f563514..cf6579317 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -896,6 +896,7 @@ type ExactConstraints ExactGcSafety AllowCommonBase + PickyCAliases # be picky about the distinction between 'cint' and 'int32' TTypeCmpFlags* = set[TTypeCmpFlag] @@ -1144,6 +1145,13 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCstring, tyInt..tyUInt64, tyTyped, tyUntyped, tyVoid: result = sameFlags(a, b) + if result and PickyCAliases in c.flags: + # additional requirement for the caching of generics for importc'ed types: + # the symbols must be identical too: + let symFlagsA = if a.sym != nil: a.sym.flags else: {} + let symFlagsB = if b.sym != nil: b.sym.flags else: {} + if (symFlagsA+symFlagsB) * {sfImportc, sfExportc} != {}: + result = symFlagsA == symFlagsB of tyStatic, tyFromExpr: result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b) if result and a.len == b.len and a.len == 1: diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 7daea62c8..951ae25f3 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -463,3 +463,14 @@ proc putValue[T](n: T) = echo b.n useForward() + + +# bug #16246 + +proc testWeirdTypeAliases() = + var values = newSeq[cuint](8) + # var values: seq[cuint] does not produce codegen error + var drawCb = proc(): seq[uint32] = + result = newSeq[uint32](10) + +testWeirdTypeAliases() From 5c85e480a6a13ac12c69f7e5500322eb5474be11 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Sep 2021 17:49:27 +0200 Subject: [PATCH 2981/4254] unicode operator bugfixes (#18802) --- compiler/lexer.nim | 106 ++++++++++++++++------------- tests/lexer/tunicode_operators.nim | 4 +- 2 files changed, 63 insertions(+), 47 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index ddf98661a..ede16fdf1 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -838,50 +838,6 @@ proc getCharacter(L: var Lexer; tok: var Token) = lexMessage(L, errGenerated, "missing closing ' for character literal") tokenEndIgnore(tok, L.bufpos) -proc getSymbol(L: var Lexer, tok: var Token) = - var h: Hash = 0 - var pos = L.bufpos - tokenBegin(tok, pos) - var suspicious = false - while true: - var c = L.buf[pos] - case c - of 'a'..'z', '0'..'9', '\x80'..'\xFF': - h = h !& ord(c) - inc(pos) - of 'A'..'Z': - c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() - h = h !& ord(c) - inc(pos) - suspicious = true - of '_': - if L.buf[pos+1] notin SymChars: - lexMessage(L, errGenerated, "invalid token: trailing underscore") - break - inc(pos) - suspicious = true - else: break - tokenEnd(tok, pos-1) - h = !$h - tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) - if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or - (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): - tok.tokType = tkSymbol - else: - tok.tokType = TokType(tok.ident.id + ord(tkSymbol)) - if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}: - lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s) - L.bufpos = pos - - -proc endOperator(L: var Lexer, tok: var Token, pos: int, - hash: Hash) {.inline.} = - var h = !$hash - tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) - if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr - else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon)) - L.bufpos = pos - const UnicodeOperatorStartChars = {'\226', '\194', '\195'} # the allowed unicode characters ("∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔") @@ -925,6 +881,56 @@ proc unicodeOprLen(buf: cstring; pos: int): (int8, UnicodeOprPred) = else: discard +proc getSymbol(L: var Lexer, tok: var Token) = + var h: Hash = 0 + var pos = L.bufpos + tokenBegin(tok, pos) + var suspicious = false + while true: + var c = L.buf[pos] + case c + of 'a'..'z', '0'..'9': + h = h !& ord(c) + inc(pos) + of 'A'..'Z': + c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() + h = h !& ord(c) + inc(pos) + suspicious = true + of '_': + if L.buf[pos+1] notin SymChars: + lexMessage(L, errGenerated, "invalid token: trailing underscore") + break + inc(pos) + suspicious = true + of '\x80'..'\xFF': + if c in UnicodeOperatorStartChars and unicodeOperators in L.config.features and unicodeOprLen(L.buf, pos)[0] != 0: + break + else: + h = h !& ord(c) + inc(pos) + else: break + tokenEnd(tok, pos-1) + h = !$h + tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) + if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or + (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): + tok.tokType = tkSymbol + else: + tok.tokType = TokType(tok.ident.id + ord(tkSymbol)) + if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}: + lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s) + L.bufpos = pos + + +proc endOperator(L: var Lexer, tok: var Token, pos: int, + hash: Hash) {.inline.} = + var h = !$hash + tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) + if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr + else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon)) + L.bufpos = pos + proc getOperator(L: var Lexer, tok: var Token) = var pos = L.bufpos tokenBegin(tok, pos) @@ -1346,7 +1352,11 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = getNumber(L, tok) let c = L.buf[L.bufpos] if c in SymChars+{'_'}: - lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") + if c in UnicodeOperatorStartChars and unicodeOperators in L.config.features and + unicodeOprLen(L.buf, L.bufpos)[0] != 0: + discard + else: + lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") of '-': if L.buf[L.bufpos+1] in {'0'..'9'} and (L.bufpos-1 == 0 or L.buf[L.bufpos-1] in UnaryMinusWhitelist): @@ -1357,7 +1367,11 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = getNumber(L, tok) let c = L.buf[L.bufpos] if c in SymChars+{'_'}: - lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") + if c in UnicodeOperatorStartChars and unicodeOperators in L.config.features and + unicodeOprLen(L.buf, L.bufpos)[0] != 0: + discard + else: + lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") else: getOperator(L, tok) else: diff --git a/tests/lexer/tunicode_operators.nim b/tests/lexer/tunicode_operators.nim index 74fcbb763..6ad40beab 100644 --- a/tests/lexer/tunicode_operators.nim +++ b/tests/lexer/tunicode_operators.nim @@ -5,8 +5,10 @@ proc `⊙=`(x: var int, y: int) = x *= y proc `⊞++`(x, y: int): int = x + y +const a = 9 + var x = 45 -x ⊙= 9 ⊞++ 4 ⊙ 3 +x ⊙= a⊞++4⊙3 var y = 45 y *= 9 + 4 * 3 From 2e2d9288465709d84a5d91abbb035583c23efe45 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Sep 2021 19:52:57 +0200 Subject: [PATCH 2982/4254] formal grammar updates [backport:1.2] (#18803) --- compiler/parser.nim | 50 +++++++++++++++++++---------------------- doc/grammar.txt | 37 +++++++++++++----------------- tools/grammar_nanny.nim | 1 + 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 225493902..7d3c913da 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -275,12 +275,6 @@ proc isRightAssociative(tok: Token): bool {.inline.} = result = tok.tokType == tkOpr and tok.ident.s[0] == '^' # or (tok.ident.s.len > 1 and tok.ident.s[^1] == '>') -proc isOperator(tok: Token): bool = - ## Determines if the given token is an operator type token. - tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, - tkOr, tkXor} - proc isUnary(tok: Token): bool = ## Check if the given token is a unary operator tok.tokType in {tkOpr, tkDotDot} and @@ -323,6 +317,14 @@ proc checkBinary(p: Parser) {.inline.} = #| mulExpr = dollarExpr (OP9 optInd dollarExpr)* #| dollarExpr = primary (OP10 optInd primary)* +proc isOperator(tok: Token): bool = + #| operatorB = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | + #| 'div' | 'mod' | 'shl' | 'shr' | 'in' | 'notin' | + #| 'is' | 'isnot' | 'not' | 'of' | 'as' | 'from' | '..' | 'and' | 'or' | 'xor' + tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, + tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, + tkOr, tkXor} + proc colcom(p: var Parser, n: PNode) = eat(p, tkColon) skipComment(p, n) @@ -447,8 +449,6 @@ proc exprColonEqExprList(p: var Parser, kind: TNodeKind, exprColonEqExprListAux(p, endTok, result) proc dotExpr(p: var Parser, a: PNode): PNode = - #| dotExpr = expr '.' optInd (symbol | '[:' exprList ']') - #| explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? var info = p.parLineInfo getTok(p) result = newNodeI(nkDotExpr, info) @@ -469,7 +469,6 @@ proc dotExpr(p: var Parser, a: PNode): PNode = result = y proc dotLikeExpr(p: var Parser, a: PNode): PNode = - #| dotLikeExpr = expr DOTLIKEOP optInd symbol var info = p.parLineInfo result = newNodeI(nkInfix, info) optInd(p, result) @@ -661,7 +660,7 @@ proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode = #| | NIL #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT #| identOrLiteral = generalizedLit | symbol | literal - #| | par | arrayConstr | setOrTableConstr + #| | par | arrayConstr | setOrTableConstr | tupleConstr #| | castExpr #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' @@ -808,7 +807,7 @@ proc isDotLike(tok: Token): bool = proc primarySuffix(p: var Parser, r: PNode, baseIndent: int, mode: PrimaryMode): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' - #| | '.' optInd symbol generalizedLit? + #| | '.' optInd symbol ('[:' exprList ']' ( '(' exprColonEqExpr ')' )?)? generalizedLit? #| | DOTLIKEOP optInd symbol generalizedLit? #| | '[' optInd exprColonEqExprList optPar ']' #| | '{' optInd exprColonEqExprList optPar '}' @@ -1013,11 +1012,9 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode = result.add(newNodeP(nkEmpty, p)) proc parseTuple(p: var Parser, indentAllowed = false): PNode = - #| inlTupleDecl = 'tuple' - #| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' - #| extTupleDecl = 'tuple' + #| tupleDecl = 'tuple' + #| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' | #| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? - #| tupleClass = 'tuple' result = newNodeP(nkTupleTy, p) getTok(p) if p.tok.tokType == tkBracketLe: @@ -1123,7 +1120,7 @@ proc parseDoBlock(p: var Parser; info: TLineInfo): PNode = genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode) proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode = - #| procExpr = 'proc' paramListColon pragma? ('=' COMMENT? stmt)? + #| routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)? # either a proc type or a anonymous proc let info = parLineInfo(p) getTok(p) @@ -1165,7 +1162,6 @@ proc parseSymbolList(p: var Parser, result: PNode) = proc parseTypeDescKAux(p: var Parser, kind: TNodeKind, mode: PrimaryMode): PNode = - #| distinct = 'distinct' optInd typeDesc result = newNodeP(kind, p) getTok(p) if p.tok.indent != -1 and p.tok.indent <= p.currInd: return @@ -1254,12 +1250,14 @@ proc parseObject(p: var Parser): PNode proc parseTypeClass(p: var Parser): PNode proc primary(p: var Parser, mode: PrimaryMode): PNode = - #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple' - #| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' - #| primary = typeKeyw optInd typeDesc + #| primary = operatorB primary primarySuffix* | + #| tupleDecl | routineExpr | enumDecl + #| objectDecl | conceptDecl | ('bind' primary) + #| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary #| / prefixOperator* identOrLiteral primarySuffix* - #| / 'bind' primary if isOperator(p.tok): + # Note 'sigil like' operators are currently not reflected in the grammar + # and should be removed for Nim 2.0, I don't think anybody uses them. let isSigil = isSigilLike(p.tok) result = newNodeP(nkPrefix, p) var a = newIdentNodeP(p.tok.ident, p) @@ -1342,7 +1340,6 @@ proc parseTypeDesc(p: var Parser): PNode = proc parseTypeDefAux(p: var Parser): PNode = #| typeDefAux = simpleExpr ('not' expr)? - #| | 'concept' typeClass result = simpleExpr(p, pmTypeDef) result = binaryNot(p, result) @@ -1695,7 +1692,6 @@ proc parseTry(p: var Parser; isExpr: bool): PNode = if b == nil: parMessage(p, "expected 'except'") proc parseExceptBlock(p: var Parser, kind: TNodeKind): PNode = - #| exceptBlock = 'except' colcom stmt result = newNodeP(kind, p) getTok(p) colcom(p, result) @@ -1867,7 +1863,7 @@ proc parseSection(p: var Parser, kind: TNodeKind, parMessage(p, errIdentifierExpected, p.tok) proc parseEnum(p: var Parser): PNode = - #| enum = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+ + #| enumDecl = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+ result = newNodeP(nkEnumTy, p) getTok(p) result.add(p.emptyNode) @@ -2015,7 +2011,7 @@ proc parseObjectPart(p: var Parser): PNode = result = p.emptyNode proc parseObject(p: var Parser): PNode = - #| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart + #| objectDecl = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart result = newNodeP(nkObjectTy, p) getTok(p) if p.tok.tokType == tkCurlyDotLe and p.validInd: @@ -2057,8 +2053,8 @@ proc parseTypeClassParam(p: var Parser): PNode = result = p.parseSymbol proc parseTypeClass(p: var Parser): PNode = - #| typeClassParam = ('var' | 'out')? symbol - #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? + #| conceptParam = ('var' | 'out')? symbol + #| conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? #| &IND{>} stmt result = newNodeP(nkTypeClassTy, p) getTok(p) diff --git a/doc/grammar.txt b/doc/grammar.txt index f58621b97..8f86dd98c 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -22,14 +22,14 @@ ampExpr = plusExpr (OP7 optInd plusExpr)* plusExpr = mulExpr (OP8 optInd mulExpr)* mulExpr = dollarExpr (OP9 optInd dollarExpr)* dollarExpr = primary (OP10 optInd primary)* +operatorB = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | + 'div' | 'mod' | 'shl' | 'shr' | 'in' | 'notin' | + 'is' | 'isnot' | 'not' | 'of' | 'as' | 'from' | '..' | 'and' | 'or' | 'xor' symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' | IDENT | KEYW exprColonEqExpr = expr (':'|'=' expr)? exprList = expr ^+ comma exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? -dotExpr = expr '.' optInd (symbol | '[:' exprList ']') -explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? -dotLikeExpr = expr DOTLIKEOP optInd symbol qualifiedIdent = symbol ('.' optInd symbol)? setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' castExpr = 'cast' ('[' optInd typeDesc optPar ']' '(' optInd expr optPar ')') / @@ -51,12 +51,12 @@ literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT | NIL generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT identOrLiteral = generalizedLit | symbol | literal - | par | arrayConstr | setOrTableConstr + | par | arrayConstr | setOrTableConstr | tupleConstr | castExpr tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' primarySuffix = '(' (exprColonEqExpr comma?)* ')' - | '.' optInd symbol generalizedLit? + | '.' optInd symbol ('[:' exprList ']' ( '(' exprColonEqExpr ')' )?)? generalizedLit? | DOTLIKEOP optInd symbol generalizedLit? | '[' optInd exprColonEqExprList optPar ']' | '{' optInd exprColonEqExprList optPar '}' @@ -70,17 +70,14 @@ declColonEquals = identWithPragma (comma identWithPragma)* comma? (':' optInd typeDesc)? ('=' optInd expr)? identColonEquals = IDENT (comma IDENT)* comma? (':' optInd typeDesc)? ('=' optInd expr)?) -inlTupleDecl = 'tuple' - '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' -extTupleDecl = 'tuple' +tupleDecl = 'tuple' + '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' | COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? -tupleClass = 'tuple' paramList = '(' declColonEquals ^* (comma/semicolon) ')' paramListArrow = paramList? ('->' optInd typeDesc)? paramListColon = paramList? (':' optInd typeDesc)? doBlock = 'do' paramListArrow pragma? colcom stmt -procExpr = 'proc' paramListColon pragma? ('=' COMMENT? stmt)? -distinct = 'distinct' optInd typeDesc +routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)? forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt forExpr = forStmt expr = (blockExpr @@ -90,14 +87,13 @@ expr = (blockExpr | forExpr | tryExpr) / simpleExpr -typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple' - | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' -primary = typeKeyw optInd typeDesc +primary = operatorB primary primarySuffix* | + tupleDecl | routineExpr | enumDecl + objectDecl | conceptDecl | ('bind' primary) + ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary / prefixOperator* identOrLiteral primarySuffix* - / 'bind' primary typeDesc = simpleExpr ('not' expr)? typeDefAux = simpleExpr ('not' expr)? - | 'concept' typeClass postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt @@ -147,7 +143,6 @@ tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') (optInd 'except' exprList colcom stmt)* (optInd 'finally' colcom stmt)? -exceptBlock = 'except' colcom stmt blockStmt = 'block' symbol? colcom stmt blockExpr = 'block' symbol? colcom stmt staticStmt = 'static' colcom stmt @@ -162,7 +157,7 @@ routine = optInd identVis pattern? genericParamList? paramListColon pragma? ('=' COMMENT? stmt)? indAndComment commentStmt = COMMENT section(RULE) = COMMENT? RULE / (IND{>} (RULE / COMMENT)^+IND{=} DED) -enum = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+ +enumDecl = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+ objectWhen = 'when' expr colcom objectPart COMMENT? ('elif' expr colcom objectPart COMMENT?)* ('else' colcom objectPart COMMENT?)? @@ -175,9 +170,9 @@ objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT? | IND{=} objectBranches) objectPart = IND{>} objectPart^+IND{=} DED / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals -object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart -typeClassParam = ('var' | 'out')? symbol -typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? +objectDecl = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart +conceptParam = ('var' | 'out')? symbol +conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? &IND{>} stmt typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux indAndComment? / identVisDot genericParamList? pragma '=' optInd typeDefAux diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim index 5120ef976..502412c3c 100644 --- a/tools/grammar_nanny.nim +++ b/tools/grammar_nanny.nim @@ -13,6 +13,7 @@ proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = var stream = llStreamOpen(data) var declaredSyms = initHashSet[string]() var usedSyms = initHashSet[string]() + usedSyms.incl "module" # 'module' is the start rule. if stream != nil: declaredSyms.incl "section" # special case for 'section(RULE)' in the grammar var From 4320b158dd2e5d7420cc813a1e9e2aecc946de7d Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 5 Sep 2021 16:50:54 +0800 Subject: [PATCH 2983/4254] add weave to important packages (#17665) * add weave to important packages * Update testament/important_packages.nim --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index ab29dcd0d..a91246562 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -158,6 +158,7 @@ pkg "tiny_sqlite" pkg "unicodedb", "nim c -d:release -r tests/tests.nim" pkg "unicodeplus", "nim c -d:release -r tests/tests.nim" pkg "unpack" +pkg "weave", "nimble test_gc_arc", allowFailure = true pkg "websocket", "nim c websocket.nim" pkg "winim", allowFailure = true pkg "with" From f373c17ad926b669bb3b5819ae1dff4bde1da88a Mon Sep 17 00:00:00 2001 From: Miran Date: Mon, 6 Sep 2021 09:40:31 +0200 Subject: [PATCH 2984/4254] use new Nimble, with lockfiles (#18810) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 8dd897028..e42ea53de 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master + NimbleStableCommit = "795704833ddfd0cdaefb45c60551d3ea205279ef" # master # examples of possible values: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" HeadHash = "#head" From 7ae52d779184cd8a16b760e384777a75ed54464b Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 6 Sep 2021 01:43:26 -0600 Subject: [PATCH 2985/4254] Fix recursive generic typed defs (#18809) --- compiler/semtypinst.nim | 2 +- tests/generics/trecursivegenerics.nim | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/generics/trecursivegenerics.nim diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 9f9eb9489..01b21498b 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -378,7 +378,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = cl.typeMap = newTypeMapLayer(cl) for i in 1.. Date: Mon, 6 Sep 2021 13:12:14 +0200 Subject: [PATCH 2986/4254] fixes #14165, fixes #18739, fix the second example of #6269 (#18812) --- compiler/transf.nim | 11 ++++++---- tests/iter/titer.nim | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 3250f2ec4..5846e6e3b 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -738,7 +738,7 @@ proc transformFor(c: PTransf, n: PNode): PNode = pushInfoContext(c.graph.config, n.info) inc(c.inlining) stmtList.add(transform(c, body)) - #findWrongOwners(c, stmtList.pnode) + #findWrongOwners(c, stmtList.PNode) dec(c.inlining) popInfoContext(c.graph.config) popTransCon(c) @@ -1019,10 +1019,11 @@ proc transform(c: PTransf, n: PNode): PNode = of nkAsgn: result = transformAsgn(c, n) of nkIdentDefs, nkConstDef: - result = n + result = newTransNode(n) result[0] = transform(c, n[0]) # Skip the second son since it only contains an unsemanticized copy of the # variable type used by docgen + result[1] = n[1] result[2] = transform(c, n[2]) # XXX comment handling really sucks: if importantComments(c.graph.config): @@ -1033,8 +1034,10 @@ proc transform(c: PTransf, n: PNode): PNode = # (bug #2604). We need to patch this environment here too: let a = n[1] if a.kind == nkSym: - n[1] = transformSymAux(c, a) - return n + result = copyTree(n) + result[1] = transformSymAux(c, a) + else: + result = n of nkExceptBranch: result = transformExceptBranch(c, n) of nkCheckedFieldExpr: diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim index 8e1c13e82..3a2450ae3 100644 --- a/tests/iter/titer.nim +++ b/tests/iter/titer.nim @@ -62,3 +62,53 @@ type Rule[T] = (int, T) var t: seq[Rule[int]] for (c, t) in t: discard + + + +import std/sugar + +# bug #14165 +iterator log_nodups_hamming(): int {.inline.} = + let lb3 = 1 + let lb4 = 123 + proc mul3(): int = lb3 + lb4 + yield mul3() + +for h in log_nodups_hamming(): + break +for h in log_nodups_hamming(): + break +for h in log_nodups_hamming(): + break + +# bug #18536 +iterator envPairs*(): int = + var foo: seq[int] + proc fun() = + foo = @[] + fun() + yield 3 + +proc main() = + for a in envPairs(): + discard + for a in envPairs(): + discard +static: main() +main() + +# bug #6269 +iterator makeFn(outer_val: int): proc(a: int): int = + for i in 0..1: + yield proc(a:int): int = + return a + i.int + +let v1 = 42 + +let res = collect: + for fn1 in makeFn(v1): + let v2 = fn1(v1) + for fn2 in makeFn(v2): + fn2(v2) + +doAssert res == @[42, 43, 43, 44] From cc5422ae5070a2cdd69dbd5b78663305623a0fbc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Sep 2021 13:19:11 +0200 Subject: [PATCH 2987/4254] Atlas: added 'extract' command, as promised (#18813) --- tools/atlas/atlas.nim | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 761ca5db8..370138029 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -9,7 +9,7 @@ ## Simple tool to automate frequent workflows: Can "clone" ## a Nimble dependency and its dependencies recursively. -import std/[parseopt, strutils, os, osproc, unicode, tables, sets] +import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonutils] import parse_requires, osutils, packagesjson const @@ -22,6 +22,8 @@ Usage: Command: clone url|pkgname clone a package and all of its dependencies search keyw keywB... search for package that contains the given keywords + extract file.nimble extract the requirements and custom commands from + the given Nimble file Options: --keepCommits do not perform any `git checkouts` @@ -460,6 +462,12 @@ proc main = of "search", "list": updatePackages(c) search getPackages(c.workspace), args + of "extract": + singleArg() + if fileExists(args[0]): + echo toJson(extractRequiresInfo(args[0])) + else: + error "File does not exist: " & args[0] else: error "Invalid action: " & action From 90bfd342504fd1a6a9e4c8f232bf7c35eab92f82 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 6 Sep 2021 07:30:49 -0600 Subject: [PATCH 2988/4254] '[]' can now be used for iterators (#18814) --- compiler/semexprs.nim | 2 +- tests/iter/tarrayiter.nim | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/iter/tarrayiter.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3edeae324..c0a2a346a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1596,7 +1596,7 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semSubscript(c, n, flags) if result == nil: # overloaded [] operator: - result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]"))) + result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags) proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = var id = considerQuotedIdent(c, a[1], a) diff --git a/tests/iter/tarrayiter.nim b/tests/iter/tarrayiter.nim new file mode 100644 index 000000000..eb7ba591a --- /dev/null +++ b/tests/iter/tarrayiter.nim @@ -0,0 +1,14 @@ +block: + iterator `[]`(a: int, r: int): int = + for q in 0 .. r: + yield a + + for val in 10[2]: discard + + type Custom = distinct string + + iterator `[]`(a: Custom, r: int): char = + for q in 0 .. r: + yield a.string[q] + + for val in Custom("test")[2]: discard \ No newline at end of file From 34a53e804943ceaf3900feb6e89194aa03236c0a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Sep 2021 17:43:03 +0200 Subject: [PATCH 2989/4254] fixes #12642 (#18811) * fixes #12642 * update important packages; refs #18804 * fixes #18805; refs #18806 * fixes a regression * Update testament/categories.nim Co-authored-by: flywind * progress * progress Co-authored-by: flywind --- compiler/ccgcalls.nim | 1 + compiler/sem.nim | 6 ++++++ compiler/transf.nim | 5 +++-- testament/categories.nim | 6 ++++-- testament/important_packages.nim | 5 ++--- tests/effects/teffects6.nim | 20 ++++++++++++++++++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 828e666a8..f6cc6da74 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -369,6 +369,7 @@ proc genParams(p: BProc, ri: PNode, typ: PType): Rope = if ri[i].skipTrivialIndirections.kind == nkSym: needTmp[i - 1] = potentialAlias(ri[i], potentialWrites) else: + #if not ri[i].typ.isCompileTimeOnly: var potentialReads: seq[PNode] getPotentialReads(ri[i], potentialReads) for n in potentialReads: diff --git a/compiler/sem.nim b/compiler/sem.nim index 24709cf21..ad0ba1f7c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -174,6 +174,12 @@ proc commonType*(c: PContext; x, y: PType): PType = result = b #.skipIntLit elif a.kind in IntegralTypes and a.n != nil: result = a #.skipIntLit + elif a.kind == tyProc and b.kind == tyProc: + if a.callConv == ccClosure and b.callConv != ccClosure: + result = x + elif compatibleEffects(a, b) != efCompat or + (b.flags * {tfNoSideEffect, tfGcSafe}) < (a.flags * {tfNoSideEffect, tfGcSafe}): + result = y else: var k = tyNone if a.kind in {tyRef, tyPtr}: diff --git a/compiler/transf.nim b/compiler/transf.nim index 5846e6e3b..89fa89701 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1023,8 +1023,9 @@ proc transform(c: PTransf, n: PNode): PNode = result[0] = transform(c, n[0]) # Skip the second son since it only contains an unsemanticized copy of the # variable type used by docgen - result[1] = n[1] - result[2] = transform(c, n[2]) + let last = n.len-1 + for i in 1.. Date: Mon, 6 Sep 2021 12:11:21 -0600 Subject: [PATCH 2990/4254] Fixes implicit and explicit generics in procedures (#18808) * Fixes implicit and explicit generics * moved block logic into 'maybeInstantiateGeneric' * Added more tests * Update compiler/semexprs.nim Co-authored-by: Andreas Rumpf --- compiler/semexprs.nim | 28 +++++++++++--- tests/generics/timplicit_and_explicit.nim | 45 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 tests/generics/timplicit_and_explicit.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c0a2a346a..0f6f71cc2 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1493,6 +1493,28 @@ proc semDeref(c: PContext, n: PNode): PNode = else: result = nil #GlobalError(n[0].info, errCircumNeedsPointer) +proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym): PNode = + ## Instantiates generic if not lacking implicit generics, + ## otherwise returns n. + let + neededGenParams = s.ast[genericParamsPos].len + heldGenParams = n.len - 1 + var implicitParams = 0 + for x in s.ast[genericParamsPos]: + if tfImplicitTypeParam in x.typ.flags: + inc implicitParams + if heldGenParams != neededGenParams and implicitParams + heldGenParams == neededGenParams: + # This is an implicit + explicit generic procedure without all args passed, + # kicking back the sem'd symbol fixes #17212 + # Uncertain the hackiness of this solution. + result = n + else: + result = explicitGenericInstantiation(c, n, s) + if result == n: + n[0] = copyTree(result) + else: + n[0] = result + proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if not a built-in subscript operator; also called for the ## checking of assignments @@ -1568,11 +1590,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = of skProc, skFunc, skMethod, skConverter, skIterator: # type parameters: partial generic specialization n[0] = semSymGenericInstantiation(c, n[0], s) - result = explicitGenericInstantiation(c, n, s) - if result == n: - n[0] = copyTree(result) - else: - n[0] = result + result = maybeInstantiateGeneric(c, n, s) of skMacro, skTemplate: if efInCall in flags: # We are processing macroOrTmpl[] in macroOrTmpl[](...) call. diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim new file mode 100644 index 000000000..ba24b79e9 --- /dev/null +++ b/tests/generics/timplicit_and_explicit.nim @@ -0,0 +1,45 @@ + +block: # basic test + proc doStuff[T](a: SomeInteger): T = discard + proc doStuff[T;Y](a: SomeInteger, b: Y): Y = discard + assert typeof(doStuff[int](100)) is int + assert typeof(doStuff[int](100, 1.0)) is float + assert typeof(doStuff[int](100, "Hello")) is string + + proc t[T](x: T; z: int | float): seq[T] = result.add(x & $z) + + assert t[string]("Hallo", 2.0) == @["Hallo" & $2.0] + + proc t2[T](z: int | float): seq[T] = result.add($z) + + assert t2[string](2.0) == @[$2.0] + +block: # template test + template someThing[T;Y](a: SomeFloat, b: SomeOrdinal): (T, Y) = (a, b) + assert typeof(someThing[float64, int](1.0, 100)) is (float64, int) + +block: # static test + proc t[T](s: static bool) = discard + proc t2[T](s: static string) = discard + t[string](true) + t2[int]("hello") + t2[string]("world") + t2[float]("test222222") + +block: #11152 + proc f[T](X: typedesc) = discard + f[int](string) + +block: #15622 + proc test1[T](a: T, b: static[string] = "") = discard + test1[int64](123) + proc test2[T](a: T, b: static[string] = "") = discard + test2[int64, static[string]](123) + +block: #4688 + proc convertTo[T](v: int or float): T = (T)(v) + discard convertTo[float](1) + +block: #4164 + proc printStr[T](s: static[string]): T = discard + discard printStr[int]("hello static") \ No newline at end of file From ee2eb5cae2585c5cd0a476814bd5879c130e5d30 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Tue, 7 Sep 2021 09:11:08 -0600 Subject: [PATCH 2991/4254] Fix subranges of distinct types (#18816) [backport] --- compiler/typeallowed.nim | 2 +- tests/distinct/tdistinct.nim | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 2f0c039a4..d00aa538f 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -124,7 +124,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, lastSon(t), kind, c, flags) of tyRange: if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin - {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t + {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64, tyRange}: result = t of tyOpenArray: # you cannot nest openArrays/sinks/etc. if (kind != skParam or taIsOpenArray in flags) and views notin c.features: diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index 876975a7c..fd60b4ac0 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -167,6 +167,20 @@ template main() = s.Foo.add('c') doAssert s.string == "c" # was failing test() + block: #18061 + type + A = distinct (0..100) + B = A(0) .. A(10) + proc test(b: B) = discard + let + a = A(10) + b = B(a) + test(b) + + proc test(a: A) = discard + discard cast[B](A(1)) + var c: B + static: main() main() From c56008450a86daf454fa0e2e0722711831cd78ae Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 8 Sep 2021 17:47:14 +0800 Subject: [PATCH 2992/4254] fix CI failure(upstream changes) (#18820) * fix upstream changes * Update tests/js/tunittest_error2.nim Co-authored-by: flywind Co-authored-by: Andreas Rumpf --- tests/js/tunittest_error2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/js/tunittest_error2.nim b/tests/js/tunittest_error2.nim index 273e39d9d..9c5af7529 100644 --- a/tests/js/tunittest_error2.nim +++ b/tests/js/tunittest_error2.nim @@ -1,7 +1,7 @@ discard """ exitcode: 1 outputsub: ''' -Unhandled exception: Cannot read property 'charCodeAt' of null [] +[] [FAILED] Bad test ''' matrix: "-d:nodejs" From 23e10ea85ea35c1a5963bfd12fb69efe6358076a Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 9 Sep 2021 14:46:55 +0800 Subject: [PATCH 2993/4254] active some packages (#18825) --- testament/important_packages.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 025121990..657ddb2d1 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -63,7 +63,7 @@ pkg "delaunay" pkg "docopt" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" -pkg "fidget", allowFailure = true # pending https://github.com/treeform/fidget/issues/155 +pkg "fidget" pkg "fragments", "nim c -r fragments/dsl.nim" pkg "fusion" pkg "gara" @@ -76,7 +76,7 @@ pkg "gnuplot", "nim c gnuplot.nim" pkg "hts", "nim c -o:htss src/hts.nim" pkg "httpauth" pkg "illwill", "nimble examples" -pkg "inim", allowFailure=true +pkg "inim" pkg "itertools", "nim doc src/itertools.nim" pkg "iterutils" pkg "jstin" @@ -100,7 +100,7 @@ pkg "nimcrypto", "nim r --path:. tests/testall.nim" # `--path:.` workaround need pkg "NimData", "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", "nim c src/nimes.nim" pkg "nimfp", "nim c -o:nfp -r src/fp.nim" -pkg "nimgame2", "nim c -d:nimLegacyConvEnumEnum nimgame2/nimgame.nim", allowFailure = true +pkg "nimgame2", "nim c -d:nimLegacyConvEnumEnum nimgame2/nimgame.nim" # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" pkg "nimlsp" @@ -145,7 +145,7 @@ pkg "strslice" pkg "strunicode", "nim c -r src/strunicode.nim" pkg "supersnappy" pkg "synthesis" -pkg "telebot", "nim c -o:tbot -r src/telebot.nim", allowFailure = true # pending https://github.com/ba0f3/telebot.nim/issues/59 +pkg "telebot", "nim c -o:tbot -r src/telebot.nim" pkg "tempdir" pkg "templates" pkg "tensordsl", "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" From a896f9f19eec221b8651849297bdbc8be72b00af Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Thu, 9 Sep 2021 12:57:21 +0100 Subject: [PATCH 2994/4254] Clarify unknown processor error (#18829) --- tools/niminst/makefile.nimf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index d14960ac5..a0e9a40f7 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -164,7 +164,7 @@ ifeq ($(ucpu),riscv64) mycpu = riscv64 endif ifndef mycpu - $(error unknown processor: $(ucpu)) + $(error unknown CPU architecture: $(ucpu) See makefile.nimf) endif # for osA in 1..c.oses.len: From 0ef830577b6f6ee2314ecdfe56a631ffd4f8e4c7 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 10 Sep 2021 05:20:32 -0300 Subject: [PATCH 2995/4254] distros.foreignDeps made public (#18830) * Deprecate distros.echoForeignDeps * Deprecate distros.echoForeignDeps * https://github.com/nim-lang/Nim/pull/18830#discussion_r705364162 * https://github.com/nim-lang/Nim/pull/18830#discussion_r705364162 --- changelog.md | 1 + lib/pure/distros.nim | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 3658fb105..9e449dcaa 100644 --- a/changelog.md +++ b/changelog.md @@ -380,6 +380,7 @@ - Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect if the slice is out of bounds, likewise with `strutils.delete`. + ## Language changes - The `cstring` doesn't support `[]=` operator in JS backend. diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index ddf0fd30c..797698d61 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -27,11 +27,11 @@ ## ## See `packaging `_ for hints on distributing Nim using OS packages. -from strutils import contains, toLowerAscii +from std/strutils import contains, toLowerAscii when not defined(nimscript): - from osproc import execProcess - from os import existsEnv + from std/osproc import execProcess + from std/os import existsEnv type Distribution* {.pure.} = enum ## the list of known distributions @@ -211,7 +211,7 @@ template detectOs*(d: untyped): bool = detectOsImpl(Distribution.d) when not defined(nimble): - var foreignDeps: seq[string] = @[] + var foreignDeps*: seq[string] = @[] ## Registered foreign deps. proc foreignCmd*(cmd: string; requiresSudo = false) = ## Registers a foreign command to the internal list of commands From 6c2f041368e36bb7a6b217c7ac0c5de94c7b4a7a Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 11 Sep 2021 09:25:48 +0800 Subject: [PATCH 2996/4254] fix code-block which causes missing docs --- lib/system/channels_builtin.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/channels_builtin.nim b/lib/system/channels_builtin.nim index c7a445766..30267e375 100644 --- a/lib/system/channels_builtin.nim +++ b/lib/system/channels_builtin.nim @@ -26,7 +26,7 @@ ## The following is a simple example of two different ways to use channels: ## blocking and non-blocking. ## -## .. code-block :: Nim +## .. code-block:: Nim ## # Be sure to compile with --threads:on. ## # The channels and threads modules are part of system and should not be ## # imported. @@ -112,7 +112,7 @@ ## using e.g. `system.allocShared0` and pass these pointers through thread ## arguments: ## -## .. code-block :: Nim +## .. code-block:: Nim ## proc worker(channel: ptr Channel[string]) = ## let greeting = channel[].recv() ## echo greeting From 1f68f71ec24d3ec6b8e83411a6f1604277f9d493 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 11 Sep 2021 17:33:52 +0800 Subject: [PATCH 2997/4254] [minor] fix docs (#18834) --- lib/pure/collections/sets.nim | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 3f91d9030..7b1c58ac8 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -603,12 +603,10 @@ proc isValid*[A](s: HashSet[A]): bool {.deprecated: ## Returns `true` if the set has been initialized (with `initHashSet proc ## <#initHashSet>`_ or `init proc <#init,HashSet[A]>`_). ## - ## **Examples:** - ## - ## .. code-block :: - ## proc savePreferences(options: HashSet[string]) = - ## assert options.isValid, "Pass an initialized set!" - ## # Do stuff here, may crash in release builds! + runnableExamples: + proc savePreferences(options: HashSet[string]) = + assert options.isValid, "Pass an initialized set!" + # Do stuff here, may crash in release builds! result = s.data.len > 0 From 66e53bdd7b465edd9045314d4d6a60ef6e0b5e32 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sat, 11 Sep 2021 05:05:53 -0600 Subject: [PATCH 2998/4254] Fixed type inference for 'set` and 'tuple' (#18827) * improved built in typeclass inference * Smarter logic to fit node * Forgot the untyped check --- compiler/sem.nim | 3 ++- tests/metatype/typeclassinference.nim | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index ad0ba1f7c..bdecbe602 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -77,7 +77,8 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode = let x = arg.skipConv - if x.kind in {nkPar, nkTupleConstr, nkCurly} and formal.kind != tyUntyped: + if (x.kind == nkCurly and formal.kind == tySet and formal.base.kind != tyGenericParam) or + (x.kind in {nkPar, nkTupleConstr}) and formal.kind notin {tyUntyped, tyBuiltInTypeClass}: changeType(c, x, formal, check=true) result = arg result = skipHiddenSubConv(result, c.graph, c.idgen) diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim index c845e04f7..b3f197718 100644 --- a/tests/metatype/typeclassinference.nim +++ b/tests/metatype/typeclassinference.nim @@ -19,3 +19,25 @@ var ptr1: ptr = addr(str1) var str2: string = "hello, world!" var ptr2: ptr = str2 +block: # built in typeclass inference + proc tupleA(): tuple = return (1, 2) + proc tupleB(): tuple = (1f, 2f) + assert typeof(tupleA()) is (int, int) + assert typeof(tupleB()) is (float32, float32) + + proc a(val: int or float): tuple = + when typeof(val) is int: + (10, 10) + else: + (30f, 30f) + + assert typeof(a(10)) is (int, int) + assert typeof(a(10.0)) is (float32, float32) + + proc b(val: int or float): set = + when typeof(val) is int: + {10u8, 3} + else: + {'a', 'b'} + assert typeof(b(10)) is set[uint8] + assert typeof(b(10.0)) is set[char] \ No newline at end of file From 5d1608c9764416e74b36f6a772f16a66d58ddc28 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sat, 11 Sep 2021 14:20:22 -0600 Subject: [PATCH 2999/4254] Generic pointer procs now error if no types supplied (#18832) * more precise logic for pointer procs * added test for generic pointer procs * Fixed generic getting bracket expr if erroring --- compiler/semexprs.nim | 2 +- compiler/semstmts.nim | 2 +- tests/generics/tpointerprocs.nim | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/generics/tpointerprocs.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0f6f71cc2..41381b057 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1511,7 +1511,7 @@ proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym): PNode = else: result = explicitGenericInstantiation(c, n, s) if result == n: - n[0] = copyTree(result) + n[0] = copyTree(result[0]) else: n[0] = result diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2c5f3ba54..364444c98 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -553,7 +553,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = typ = typ.lastSon if hasEmpty(typ): localError(c.config, def.info, errCannotInferTypeOfTheLiteral % typ.kind.toHumanStr) - elif typ.kind == tyProc and hasUnresolvedParams(def, {}): + elif typ.kind == tyProc and def.kind == nkSym and isGenericRoutine(def.sym.ast): # tfUnresolved in typ.flags: localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree) when false: diff --git a/tests/generics/tpointerprocs.nim b/tests/generics/tpointerprocs.nim new file mode 100644 index 000000000..2bcaf15b3 --- /dev/null +++ b/tests/generics/tpointerprocs.nim @@ -0,0 +1,28 @@ +discard """ +cmd: "nim check $options --hints:off $file" +action: "reject" +nimout:''' +tpointerprocs.nim(15, 11) Error: 'foo' doesn't have a concrete type, due to unspecified generic parameters. +tpointerprocs.nim(27, 11) Error: cannot instantiate: 'foo[int]'; got 1 typeof(s) but expected 2 +tpointerprocs.nim(27, 14) Error: expression 'foo[int]' has no type (or is ambiguous) +tpointerprocs.nim(28, 11) Error: expression 'bar' has no type (or is ambiguous) +''' +""" + +block: + proc foo(x: int | float): float = result = 1.0 + let + bar = foo + baz = bar + +block: + proc foo(x: int | float): float = result = 1.0 + let + bar = foo[int] + baz = bar + +block: + proc foo(x: int | float, y: int or string): float = result = 1.0 + let + bar = foo[int] + baz = bar \ No newline at end of file From 3f3e0fa303a2729d0d6a9ffe54936c1c830e2d7e Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 13 Sep 2021 01:35:19 -0600 Subject: [PATCH 3000/4254] Fixed #18838 (#18841) [backport] --- compiler/semtypinst.nim | 6 ++++- tests/generics/trecursivegenerics.nim | 36 ++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 01b21498b..cb1ead027 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -344,7 +344,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = x = lookupTypeVar(cl, x) if x != nil: if header == t: header = instCopyType(cl, t) - header[i] = x + header[i] = + if x.kind == tyGenericInst: + t[i] + else: + x propagateToOwner(header, x) else: propagateToOwner(header, x) diff --git a/tests/generics/trecursivegenerics.nim b/tests/generics/trecursivegenerics.nim index 56c074e3f..e4c0e720f 100644 --- a/tests/generics/trecursivegenerics.nim +++ b/tests/generics/trecursivegenerics.nim @@ -1,6 +1,7 @@ block: # Replicates #18728 type FlipFlop[A, B] = ref object + val: A next: FlipFlop[B, A] Trinary[A, B, C] = ref object @@ -9,4 +10,37 @@ block: # Replicates #18728 assert typeof(FlipFlop[int, string]().next) is FlipFlop[string, int] assert typeof(FlipFlop[string, int]().next) is FlipFlop[int, string] assert typeof(Trinary[int, float, string]().next) is Trinary[float, string, int] - assert typeof(Trinary[int, float, string]().next.next) is Trinary[string, int, float] \ No newline at end of file + assert typeof(Trinary[int, float, string]().next.next) is Trinary[string, int, float] + var a = FlipFlop[int, string](val: 100, next: FlipFlop[string, int](val: "Hello")) + assert a.val == 100 + assert a.next.val == "Hello" + +block: # 18838 + type + DoublyLinkedNodeObj[T] = object + value: T + + DoublyLinkedNode[T] = ref DoublyLinkedNodeObj[T] + + Item[T] = ref object + link: DoublyLinkedNode[Item[T]] + + Box = object + + proc newDoublyLinkedNode[T](value: T): DoublyLinkedNode[T] = + new(result) + result.value = value + + let link = newDoublyLinkedNode(Item[Box]()) + +import lists +block: + type + Box = object + Item[T] = ref object + link:DoublyLinkedNode[ Item[T] ] + + ItemSimple = ref object + link:DoublyLinkedNode[ ItemSimple ] + + let link = newDoublyLinkedNode( Item[Box]() ) \ No newline at end of file From 179fad934d52641c5e064efce4bdd98578cc5e9e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Sep 2021 11:05:09 +0200 Subject: [PATCH 3001/4254] doc improvements (#18843) * cleaned up destructors documentation [backport] * Spec updates [backport:1.0] --- doc/destructors.rst | 53 +++++--------------- doc/manual.rst | 118 ++++++++------------------------------------ 2 files changed, 33 insertions(+), 138 deletions(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index a3fd7514e..28d8fa5f9 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -222,7 +222,14 @@ The prototype of this hook for a type `T` needs to be: `env` is used by ORC to keep track of its internal state, it should be passed around to calls of the built-in `=trace` operation. -Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates manually allocated resources is also used, and then only when there is a chance of cyclic references from items within the manually allocated resources when it is desired that `--gc:orc` be able to break and collect these cyclic referenced resources. Currently however, there is a mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically create a version of the other which will then conflict with the creation of the second of the pair. The work around for this problem is to forward declare the second of the "hooks" to prevent the automatic creation. +Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates +manually allocated resources is also used, and then only when there is a chance of cyclic +references from items within the manually allocated resources when it is desired that `--gc:orc` +be able to break and collect these cyclic referenced resources. Currently however, there is a +mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically +create a version of the other which will then conflict with the creation of the second of the +pair. The work around for this problem is to forward declare the second of the "hooks" to +prevent the automatic creation. The general pattern in using `=destroy` with `=trace` looks like: @@ -696,43 +703,22 @@ should eventually be replaced by a better solution. Copy on write ============= -String literals are implemented as [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write). +String literals are implemented as "copy on write". When assigning a string literal to a variable, a copy of the literal won't be created. Instead the variable simply points to the literal. The literal is shared between different variables which are pointing to it. The copy operation is deferred until the first write. -.. code-block:: nim - var x = "abc" # no copy - var y = x # no copy - -The string literal "abc" is stored in static memory and not allocated on the heap. -The variable `x` points to the literal and the variable `y` points to the literal too. -There is no copy during assigning operations. +For example: .. code-block:: nim var x = "abc" # no copy var y = x # no copy y[0] = 'h' # copy -The program above shows when the copy operations happen. -When mutating the variable `y`, the Nim compiler creates a fresh copy of `x`, -the variable `y` won't point to the string literal anymore. -Instead it points to the copy of `x` of which the memory can be mutated -and the variable `y` becomes a mutable string. -.. Note:: The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown. - -Let's look at a silly example demonstrating this behaviour: - -.. code-block:: nim - var x = "abc" - var y = x - - moveMem(addr y[0], addr x[0], 3) - -The program fails because we need to prepare a fresh copy for the variable `y`. -`prepareMutation` should be called before the address operation. +The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown. +`prepareMutation` needs to be called before the "address of" operation. For example: .. code-block:: nim var x = "abc" @@ -741,18 +727,3 @@ The program fails because we need to prepare a fresh copy for the variable `y`. prepareMutation(y) moveMem(addr y[0], addr x[0], 3) assert y == "abc" - -Now `prepareMutation` solves the problem. -It manually creates a fresh copy and makes the variable `y` mutable. - -.. code-block:: nim - var x = "abc" - var y = x - - prepareMutation(y) - moveMem(addr y[0], addr x[0], 3) - moveMem(addr y[0], addr x[0], 3) - moveMem(addr y[0], addr x[0], 3) - assert y == "abc" - -No matter how many times `moveMem` is called, the program compiles and runs. diff --git a/doc/manual.rst b/doc/manual.rst index 7976ffe0f..af163bceb 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2400,121 +2400,38 @@ describe the type checking done by the compiler. Type equality ------------- + Nim uses structural type equivalence for most types. Only for objects, -enumerations and distinct types name equivalence is used. The following -algorithm, *in pseudo-code*, determines type equality: - -.. code-block:: nim - proc typeEqualsAux(a, b: PType, - s: var HashSet[(PType, PType)]): bool = - if (a,b) in s: return true - incl(s, (a,b)) - if a.kind == b.kind: - case a.kind - of int, intXX, float, floatXX, char, string, cstring, pointer, - bool, nil, void: - # leaf type: kinds identical; nothing more to check - result = true - of ref, ptr, var, set, seq, openarray: - result = typeEqualsAux(a.baseType, b.baseType, s) - of range: - result = typeEqualsAux(a.baseType, b.baseType, s) and - (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB) - of array: - result = typeEqualsAux(a.baseType, b.baseType, s) and - typeEqualsAux(a.indexType, b.indexType, s) - of tuple: - if a.tupleLen == b.tupleLen: - for i in 0..a.tupleLen-1: - if not typeEqualsAux(a[i], b[i], s): return false - result = true - of object, enum, distinct: - result = a == b - of proc: - result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and - typeEqualsAux(a.resultType, b.resultType, s) and - a.callingConvention == b.callingConvention - - proc typeEquals(a, b: PType): bool = - var s: HashSet[(PType, PType)] = {} - result = typeEqualsAux(a, b, s) - -Since types are graphs which can have cycles, the above algorithm needs an -auxiliary set `s` to detect this case. - - -Type equality modulo type distinction -------------------------------------- - -The following algorithm (in pseudo-code) determines whether two types -are equal with no respect to `distinct` types. For brevity the cycle check -with an auxiliary set `s` is omitted: - -.. code-block:: nim - proc typeEqualsOrDistinct(a, b: PType): bool = - if a.kind == b.kind: - case a.kind - of int, intXX, float, floatXX, char, string, cstring, pointer, - bool, nil, void: - # leaf type: kinds identical; nothing more to check - result = true - of ref, ptr, var, set, seq, openarray: - result = typeEqualsOrDistinct(a.baseType, b.baseType) - of range: - result = typeEqualsOrDistinct(a.baseType, b.baseType) and - (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB) - of array: - result = typeEqualsOrDistinct(a.baseType, b.baseType) and - typeEqualsOrDistinct(a.indexType, b.indexType) - of tuple: - if a.tupleLen == b.tupleLen: - for i in 0..a.tupleLen-1: - if not typeEqualsOrDistinct(a[i], b[i]): return false - result = true - of distinct: - result = typeEqualsOrDistinct(a.baseType, b.baseType) - of object, enum: - result = a == b - of proc: - result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and - typeEqualsOrDistinct(a.resultType, b.resultType) and - a.callingConvention == b.callingConvention - elif a.kind == distinct: - result = typeEqualsOrDistinct(a.baseType, b) - elif b.kind == distinct: - result = typeEqualsOrDistinct(a, b.baseType) +enumerations and distinct types and for generic types name equivalence is used. Subtype relation ---------------- -If object `a` inherits from `b`, `a` is a subtype of `b`. This subtype -relation is extended to the types `var`, `ref`, `ptr`: -.. code-block:: nim - proc isSubtype(a, b: PType): bool = - if a.kind == b.kind: - case a.kind - of object: - var aa = a.baseType - while aa != nil and aa != b: aa = aa.baseType - result = aa == b - of var, ref, ptr: - result = isSubtype(a.baseType, b.baseType) +If object `a` inherits from `b`, `a` is a subtype of `b`. -.. XXX nil is a special value! +This subtype relation is extended to the types `var`, `ref`, `ptr`. +If `A` is a subtype of `B` and `A` and `B` are `object` types then: +- `var A` is a subtype of `var B` +- `ref A` is a subtype of `ref B` +- `ptr A` is a subtype of `ptr B`. +**Note**: In later versions of the language the subtype relation might +be changed to *require* the pointer indirection in order to prevent +"object slicing". Convertible relation -------------------- + A type `a` is **implicitly** convertible to type `b` iff the following algorithm returns true: .. code-block:: nim proc isImplicitlyConvertible(a, b: PType): bool = - if isSubtype(a, b) or isCovariant(a, b): + if isSubtype(a, b): return true if isIntLiteral(a): return b in {int8, int16, int32, int64, int, uint, uint8, uint16, @@ -2540,7 +2457,12 @@ algorithm returns true: result = b == pointer of string: result = b == cstring + of proc: + result = typeEquals(a, b) or compatibleParametersAndEffects(a, b) +We used the predicate `typeEquals(a, b)` for the "type equality" property +and the predicate `isSubtype(a, b)` for the "subtype relation". +`compatibleParametersAndEffects(a, b)` is currently not specified. Implicit conversions are also performed for Nim's `range` type constructor. @@ -2563,7 +2485,9 @@ algorithm returns true: proc isExplicitlyConvertible(a, b: PType): bool = result = false if isImplicitlyConvertible(a, b): return true - if typeEqualsOrDistinct(a, b): return true + if typeEquals(a, b): return true + if a == distinct and typeEquals(a.baseType, b): return true + if b == distinct and typeEquals(b.baseType, a): return true if isIntegralType(a) and isIntegralType(b): return true if isSubtype(a, b) or isSubtype(b, a): return true From ef390e6a68db74a61137d7690dd2b10ec3dee050 Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Mon, 13 Sep 2021 18:47:33 +0200 Subject: [PATCH 3002/4254] add changelog entry for #18656 (#18839) [backport] --- changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.md b/changelog.md index 9e449dcaa..ab037c328 100644 --- a/changelog.md +++ b/changelog.md @@ -111,6 +111,11 @@ - The allocator for Nintendo Switch, which was nonfunctional because of breaking changes in libnx, was removed, in favour of the new `-d:nimAllocPagesViaMalloc` option. +- `net.parseIpAddress` now only allows IPv4 addresses in strict form as defined + in [RFC 6943](https://www.rfc-editor.org/rfc/rfc6943#section-3.1.1). + Specifically, octal numbers in IPv4 addresses are no longer accepted (before + they were parsed as decimal numbers). + ## Standard library additions and changes - `strformat`: From 172253cb551a475d7d32093e562521990e71a1ed Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Tue, 14 Sep 2021 11:34:52 -0600 Subject: [PATCH 3003/4254] Dotborrow now works with generic distincts (#18848) --- compiler/semexprs.nim | 4 ++-- compiler/semstmts.nim | 3 ++- tests/borrow/tborrow.nim | 20 ++++++++++++++++++++ tests/borrow/tinvalidborrow.nim | 17 +++++++++++++---- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 41381b057..ebdfe02f0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1280,7 +1280,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if p != nil and p.selfSym != nil: var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) - while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct}) + while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst}) var check: PNode = nil if ty.kind == tyObject: while true: @@ -1412,7 +1412,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass: ty = ty.lastSon ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink}) - while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct}) + while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst}) var check: PNode = nil if ty.kind == tyObject: while true: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 364444c98..c2f05ccce 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1296,7 +1296,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = incl a[2].flags, nfSem # bug #10548 if sfExportc in s.flags and s.typ.kind == tyAlias: localError(c.config, name.info, "{.exportc.} not allowed for type aliases") - if tfBorrowDot in s.typ.flags and s.typ.kind != tyDistinct: + + if tfBorrowDot in s.typ.flags and s.typ.skipTypes({tyGenericBody}).kind != tyDistinct: excl s.typ.flags, tfBorrowDot localError(c.config, name.info, "only a 'distinct' type can borrow `.`") let aa = a[2] diff --git a/tests/borrow/tborrow.nim b/tests/borrow/tborrow.nim index 9c403021e..2fc788fa0 100644 --- a/tests/borrow/tborrow.nim +++ b/tests/borrow/tborrow.nim @@ -33,3 +33,23 @@ let b = Radians(1.0) a -= b echo a.float64 + +block: #14449 + type + Foo[T] = object + foo: T + + Bar[T] {.borrow:`.`.} = distinct Foo[T] + SomeThing {.borrow:`.`.} = distinct Foo[float] + OtherThing {.borrow:`.`.} = distinct SomeThing + + var + a: Bar[int] + b: SomeThing + c: OtherThing + a.foo = 300 + b.foo = 400 + c.foo = 42 + assert a.foo == 300 + assert b.foo == 400d + assert c.foo == 42d \ No newline at end of file diff --git a/tests/borrow/tinvalidborrow.nim b/tests/borrow/tinvalidborrow.nim index 89aa4e2e8..08148608d 100644 --- a/tests/borrow/tinvalidborrow.nim +++ b/tests/borrow/tinvalidborrow.nim @@ -1,16 +1,25 @@ discard """ - errormsg: "no symbol to borrow from found" - line: 11 + cmd: "nim check --hints:off --warnings:off $file" + action: "reject" + nimout:''' +tinvalidborrow.nim(18, 3) Error: only a 'distinct' type can borrow `.` +tinvalidborrow.nim(19, 3) Error: only a 'distinct' type can borrow `.` +tinvalidborrow.nim(20, 1) Error: no symbol to borrow from found +''' """ # bug #516 type TAtom = culong - + Test {.borrow:`.`.} = distinct int + Foo[T] = object + a: int + Bar[T] {.borrow:`.`.} = Foo[T] + OtherFoo {.borrow:`.`.} = Foo[int] proc `==`*(a, b: TAtom): bool {.borrow.} var d, e: TAtom -echo( $(d == e) ) +discard( $(d == e) ) From bf1700bab17da3c8776914ac5bdfff016eb70442 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 15 Sep 2021 01:39:55 +0800 Subject: [PATCH 3004/4254] add testcase for #7308 (#18849) --- tests/arc/tarcmisc.nim | 11 ---------- tests/ccgbugs/tctypes.nim | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 tests/ccgbugs/tctypes.nim diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 951ae25f3..7daea62c8 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -463,14 +463,3 @@ proc putValue[T](n: T) = echo b.n useForward() - - -# bug #16246 - -proc testWeirdTypeAliases() = - var values = newSeq[cuint](8) - # var values: seq[cuint] does not produce codegen error - var drawCb = proc(): seq[uint32] = - result = newSeq[uint32](10) - -testWeirdTypeAliases() diff --git a/tests/ccgbugs/tctypes.nim b/tests/ccgbugs/tctypes.nim new file mode 100644 index 000000000..be6009115 --- /dev/null +++ b/tests/ccgbugs/tctypes.nim @@ -0,0 +1,43 @@ +discard """ + targets: "c cpp" + matrix: "--gc:refc; --gc:arc" +""" + +# bug #7308 +proc foo(x: seq[int32]) = + var y = newSeq[cint](1) + +proc bar = + var t = newSeq[int32](1) + foo(t) + +bar() + + +# bug #16246 + +proc testWeirdTypeAliases() = + var values = newSeq[cuint](8) + # var values: seq[cuint] does not produce codegen error + var drawCb = proc(): seq[uint32] = + result = newSeq[uint32](10) + +testWeirdTypeAliases() + +block: # bug #11797 + block: + type cdouble2 = cdouble + type Foo1 = seq[cdouble] + type Foo2 = seq[cdouble2] + static: doAssert Foo1 is Foo2 + var a1: Foo1 + var a2: Foo2 + doAssert a1 == @[] + doAssert a2 == @[] + + block: + proc foo[T: int|cint](fun: proc(): T) = discard + proc foo1(): cint = 1 + proc foo3(): int32 = 2 + foo(proc(): cint = foo1()) + foo(proc(): int32 = foo3()) From cebf7cdc1ede7385e8d774b83c52d17e7021899b Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 15 Sep 2021 01:40:42 +0800 Subject: [PATCH 3005/4254] fix #10128 (#18852) --- compiler/ccgexprs.nim | 6 +++--- tests/ccgbugs/t10128.nim | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 tests/ccgbugs/t10128.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 374876367..7a3d769aa 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1006,14 +1006,14 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = # emit range check: if optBoundsCheck in p.options: linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", - [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! + [rdCharLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) else: if optBoundsCheck in p.options: linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.Field1)){ #raiseIndexError2($1,$2.Field1-1); $3}$n", - [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! + [rdCharLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, ropecg(p.module, "$1.Field0[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) @@ -1028,7 +1028,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if optBoundsCheck in p.options: linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)$2){ #raiseIndexError2($1,$2-1); $3}$n", - [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) + [rdCharLoc(b), lenExpr(p, a), raiseInstr(p)]) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = ropecg(p.module, "(*$1)", [a.r]) diff --git a/tests/ccgbugs/t10128.nim b/tests/ccgbugs/t10128.nim new file mode 100644 index 000000000..48970916f --- /dev/null +++ b/tests/ccgbugs/t10128.nim @@ -0,0 +1,18 @@ +# bug #10128 +let data = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +var seq2 = newSeq[char](data.len) +for i in 0.. Date: Thu, 16 Sep 2021 00:48:58 -0600 Subject: [PATCH 3006/4254] Fixed borrowing dot from aliases (#18854) --- compiler/semexprs.nim | 4 ++-- tests/borrow/tborrow.nim | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ebdfe02f0..5a1426f2b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1280,7 +1280,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if p != nil and p.selfSym != nil: var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) - while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst}) + while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias}) var check: PNode = nil if ty.kind == tyObject: while true: @@ -1412,7 +1412,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass: ty = ty.lastSon ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink}) - while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst}) + while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias}) var check: PNode = nil if ty.kind == tyObject: while true: diff --git a/tests/borrow/tborrow.nim b/tests/borrow/tborrow.nim index 2fc788fa0..35652e2e0 100644 --- a/tests/borrow/tborrow.nim +++ b/tests/borrow/tborrow.nim @@ -52,4 +52,40 @@ block: #14449 c.foo = 42 assert a.foo == 300 assert b.foo == 400d - assert c.foo == 42d \ No newline at end of file + assert c.foo == 42d + +block: # Borrow from muliple aliasses #16666 + type + AImpl = object + i: int + + A = AImpl + + B {.borrow: `.`.} = distinct A + C = B + D {.borrow: `.`.} = distinct C + E {.borrow: `.`.} = distinct D + + let + b = default(B) + d = default(D) + e = default(E) + + assert b.i == 0 + assert d.i == 0 + assert e.i == 0 + +block: # Borrow from generic alias + type + AImpl[T] = object + i: T + B[T] = AImpl[T] + C {.borrow: `.`.} = distinct B[int] + D = B[float] + E {.borrow: `.`.} = distinct D + + let + c = default(C) + e = default(E) + assert c.i == int(0) + assert e.i == 0d \ No newline at end of file From 6cd219c3a38c5f1a0712b0b5d07a3ea4ab02ff74 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 17 Sep 2021 04:51:26 +0000 Subject: [PATCH 3007/4254] semtypinst: don't wrap type nodes from expressions in static[T] (#18860) --- compiler/semtypinst.nim | 2 +- tests/generics/t18859.nim | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/generics/t18859.nim diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index cb1ead027..2ca355e7d 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -548,7 +548,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = n.typ.skipTypes({tyTypeDesc}) # result = n.typ.base else: - if n.typ.kind != tyStatic: + if n.typ.kind != tyStatic and n.kind != nkType: # XXX: In the future, semConstExpr should # return tyStatic values to let anyone make # use of this knowledge. The patching here diff --git a/tests/generics/t18859.nim b/tests/generics/t18859.nim new file mode 100644 index 000000000..ca6c3d10b --- /dev/null +++ b/tests/generics/t18859.nim @@ -0,0 +1,17 @@ +import macros + +macro symFromDesc(T: typedesc): untyped = + let typ = getType(T) + typ[1] + +template produceType(T: typedesc): untyped = + type + XT = object + x: symFromDesc(T) + + XT + +type + X[T] = produceType(T) + +var x: X[int] From ca51bb8fd97e36e001afc7e9ad150dc77e9ca83b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Sep 2021 18:31:55 +0200 Subject: [PATCH 3008/4254] documented overload disambiguation [backport] (#18865) * documented overload disambiguation [backport] * Update doc/manual.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * documented overload disambiguation [backport] * documented overload disambiguation [backport] Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- doc/manual.rst | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index af163bceb..09826441c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2708,6 +2708,24 @@ a parameter typed as `untyped` (for unresolved expressions) or the type class assert toSeq2(items(@[1,2])) == @[1, 2] # but items(@[1,2]) is +Overload disambiguation +======================= + +For routine calls "overload resolution" is performed. There is a weaker form of +overload resolution called *overload disambiguation* that is performed when an +overloaded symbol is used in a context where there is additional type information +available. Let `p` be an overloaded symbol. These contexts are: + +- In a function call `q(..., p, ...)` when the corresponding formal parameter + of `q` is a `proc` type. If `q` itself is overloaded then the cartesian product + of every interpretation of `q` and `p` must be considered. +- In an object constructor `Obj(..., field: p, ...)` when `field` is a `proc` + type. Analogous rules exist for array/set/tuple constructors. +- In a declaration like `x: T = p` when `T` is a `proc` type. + +As usual, ambiguous matches produce a compile-time error. + + Statements and expressions ========================== @@ -4414,7 +4432,7 @@ would. For example: if n > 0: yield n for e in toItr(recCountDown(n - 1)): - yield e + yield e for i in toItr(recCountDown(6)): # Emits: 6 5 4 3 2 1 echo i From 3241df2a13662e0158ec9d0b0c07996b22fb0939 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Sep 2021 23:35:50 +0200 Subject: [PATCH 3009/4254] fixes #18858 [backport] (#18868) * fixes #18858 [backport] * ensure async tests work with --experimental:strictEffects [backport] * ensure async tests work with --experimental:strictEffects [backport] --- lib/pure/asyncfutures.nim | 2 +- lib/pure/osproc.nim | 6 +++++- lib/pure/unicode.nim | 5 ++++- tests/async/nim.cfg | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/async/nim.cfg diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index af3fbb3ec..6906d03fd 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -93,7 +93,7 @@ proc setCallSoonProc*(p: (proc(cbproc: proc ()) {.gcsafe.})) = ## Change current implementation of `callSoon`. This is normally called when dispatcher from `asyncdispatcher` is initialized. callSoonProc = p -proc callSoon*(cbproc: proc ()) = +proc callSoon*(cbproc: proc () {.gcsafe.}) = ## Call `cbproc` "soon". ## ## If async dispatcher is running, `cbproc` will be executed during next dispatcher tick. diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 1ac37661b..6a0ac9a8b 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -330,12 +330,16 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} = ## It is implemented just calling `cpuinfo.countProcessors`. result = cpuinfo.countProcessors() +when not defined(nimHasEffectsOf): + {.pragma: effectsOf.} + proc execProcesses*(cmds: openArray[string], options = {poStdErrToStdOut, poParentStreams}, n = countProcessors(), beforeRunEvent: proc(idx: int) = nil, afterRunEvent: proc(idx: int, p: Process) = nil): int {.rtl, extern: "nosp$1", - tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect].} = + tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect], + effectsOf: [beforeRunEvent, afterRunEvent].} = ## Executes the commands `cmds` in parallel. ## Creates `n` processes that execute in parallel. ## diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index dda631633..660be7814 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -705,8 +705,11 @@ proc capitalize*(s: string): string {.noSideEffect, fastRuneAt(s, i, rune, doInc = true) result = $toUpper(rune) & substr(s, i) +when not defined(nimHasEffectsOf): + {.pragma: effectsOf.} + proc translate*(s: string, replacements: proc(key: string): string): string {. - rtl, extern: "nuc$1".} = + rtl, extern: "nuc$1", effectsOf: replacements.} = ## Translates words in a string using the ``replacements`` proc to substitute ## words inside ``s`` with their replacements. ## diff --git a/tests/async/nim.cfg b/tests/async/nim.cfg new file mode 100644 index 000000000..be50f572c --- /dev/null +++ b/tests/async/nim.cfg @@ -0,0 +1 @@ +--experimental:strictEffects From c56ba3f06a3d77ff5eabb3b48ecd6a752e5a3ea8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Sep 2021 09:09:53 +0200 Subject: [PATCH 3010/4254] fixes #18847 [backport] (#18870) --- compiler/parser.nim | 5 +++-- tests/parser/tdoc_comments.nim | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 7d3c913da..5e9a7424a 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1824,8 +1824,9 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode = # => moves comment `foo` to `fn` result.comment = body[0].comment body[0].comment = "" - else: - assert false, p.lex.config$body.info # avoids hard to track bugs, fail early. + #else: + # assert false, p.lex.config$body.info # avoids hard to track bugs, fail early. + # Yeah, that worked so well. There IS a bug in this logic, now what? proc newCommentStmt(p: var Parser): PNode = #| commentStmt = COMMENT diff --git a/tests/parser/tdoc_comments.nim b/tests/parser/tdoc_comments.nim index fa1374b45..3c86e69ea 100644 --- a/tests/parser/tdoc_comments.nim +++ b/tests/parser/tdoc_comments.nim @@ -69,3 +69,7 @@ type MyEnum3* = enum value5 ## only document the enum value + +# bug #18847 +proc close*() = ## asdfasdfsdfa + discard ## adsfasdfads From ee9795f76f1125e0addbf8cf5471cf188ad7f57a Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 20 Sep 2021 15:50:20 +0800 Subject: [PATCH 3011/4254] fix #18844 (#18851) --- lib/pure/concurrency/atomics.nim | 8 ++++---- tests/stdlib/concurrency/tatomics.nim | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index bdf1e8cc2..b252789fb 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -288,10 +288,10 @@ else: type # Atomic* {.importcpp: "_Atomic('0)".} [T] = object - AtomicInt8 {.importc: "_Atomic NI8", size: 1.} = object - AtomicInt16 {.importc: "_Atomic NI16", size: 2.} = object - AtomicInt32 {.importc: "_Atomic NI32", size: 4.} = object - AtomicInt64 {.importc: "_Atomic NI64", size: 8.} = object + AtomicInt8 {.importc: "_Atomic NI8".} = int8 + AtomicInt16 {.importc: "_Atomic NI16".} = int16 + AtomicInt32 {.importc: "_Atomic NI32".} = int32 + AtomicInt64 {.importc: "_Atomic NI64".} = int64 template atomicType*(T: typedesc[Trivial]): untyped = # Maps the size of a trivial type to it's internal atomic type diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim index 260d00990..beae0ed6d 100644 --- a/tests/stdlib/concurrency/tatomics.nim +++ b/tests/stdlib/concurrency/tatomics.nim @@ -1,6 +1,6 @@ # test atomic operations -import atomics, bitops +import std/[atomics, bitops] type Object = object @@ -607,3 +607,23 @@ block clear: doAssert not location.testAndSet location.clear(moRelease) doAssert not location.testAndSet + +block: # bug #18844 + when not defined(cpp): # cpp pending pr #18836 + type + Deprivation = object of RootObj + memes: Atomic[int] + Zoomer = object + dopamine: Deprivation + + block: + var x = Deprivation() + var y = Zoomer() + doAssert x.memes.load == 0 + doAssert y.dopamine.memes.load == 0 + + block: + var x: Deprivation + var y: Zoomer + doAssert x.memes.load == 0 + doAssert y.dopamine.memes.load == 0 From 14ced06bb1ef7f23fc6391d16763f1421a3edc80 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Sep 2021 11:37:54 +0200 Subject: [PATCH 3012/4254] fixes #18863 [backport] (#18871) --- compiler/semstmts.nim | 2 +- compiler/semtempl.nim | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c2f05ccce..81d6eeda2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1905,7 +1905,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime) if n[patternPos].kind != nkEmpty: - n[patternPos] = semPattern(c, n[patternPos]) + n[patternPos] = semPattern(c, n[patternPos], s) if s.kind == skIterator: s.typ.flags.incl(tfIterator) elif s.kind == skFunc: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 2636784af..eda4ca6cc 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -334,7 +334,7 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start = 0) = illFormedAst(a, c.c.config) -proc semPattern(c: PContext, n: PNode): PNode +proc semPattern(c: PContext, n: PNode; s: PSym): PNode proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode = result = n @@ -645,7 +645,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = if allUntyped: incl(s.flags, sfAllUntyped) if n[patternPos].kind != nkEmpty: - n[patternPos] = semPattern(c, n[patternPos]) + n[patternPos] = semPattern(c, n[patternPos], s) var ctx: TemplCtx ctx.toBind = initIntSet() @@ -798,7 +798,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = for i in 0.. Date: Mon, 20 Sep 2021 13:24:44 +0200 Subject: [PATCH 3013/4254] [backport] Revert "use new Nimble, with lockfiles (#18810)" (#18872) This reverts commit f373c17ad926b669bb3b5819ae1dff4bde1da88a. For more details, see: - https://github.com/nim-lang/nimble/issues/940 - https://github.com/nim-lang/Nim/issues/18840 - https://forum.nim-lang.org/t/8404 --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index e42ea53de..8dd897028 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "795704833ddfd0cdaefb45c60551d3ea205279ef" # master + NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master # examples of possible values: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" HeadHash = "#head" From 928ea6bb4c0cc791f1b81e55dbebd14d5c6a7315 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Sep 2021 13:32:33 +0200 Subject: [PATCH 3014/4254] atlas: added --cfgHere switch [backport] (#18873) --- tools/atlas/atlas.nim | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 370138029..e604c3167 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -27,6 +27,8 @@ Command: Options: --keepCommits do not perform any `git checkouts` + --cfgHere also create/maintain a nim.cfg in the current + working directory --version show the version --help show this help """ @@ -58,6 +60,7 @@ type projectDir, workspace: string hasPackageList: bool keepCommits: bool + cfgHere: bool p: Table[string, string] # name -> url mapping processed: HashSet[string] # the key is (url / commit) errors: int @@ -353,7 +356,7 @@ proc clone(c: var AtlasContext; start: string): seq[string] = error c, toName(start), "cannot resolve package name" return - c.projectDir = work[0].name.string + c.projectDir = c.workspace / work[0].name.string result = @[] var i = 0 while i < work.len: @@ -376,10 +379,16 @@ const configPatternBegin = "############# begin Atlas config section ##########\n" configPatternEnd = "############# end Atlas config section ##########\n" -proc patchNimCfg(c: var AtlasContext; deps: seq[string]) = +proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgHere: bool) = var paths = "--noNimblePath\n" - for d in deps: - paths.add "--path:\"../" & d.replace("\\", "/") & "\"\n" + if cfgHere: + let cwd = getCurrentDir() + for d in deps: + let x = relativePath(c.workspace / d, cwd, '/') + paths.add "--path:\"" & x & "\"\n" + else: + for d in deps: + paths.add "--path:\"../" & d.replace("\\", "/") & "\"\n" var cfgContent = configPatternBegin & paths & configPatternEnd @@ -387,7 +396,8 @@ proc patchNimCfg(c: var AtlasContext; deps: seq[string]) = assert readFile(TestsDir / "nim.cfg") == cfgContent c.mockupSuccess = true else: - let cfg = c.projectDir / "nim.cfg" + let cfg = if cfgHere: getCurrentDir() / "nim.cfg" + else: c.projectDir / "nim.cfg" if not fileExists(cfg): writeFile(cfg, cfgContent) else: @@ -437,6 +447,7 @@ proc main = of "help", "h": writeHelp() of "version", "v": writeVersion() of "keepcommits": c.keepCommits = true + of "cfghere": c.cfgHere = true else: writeHelp() of cmdEnd: assert false, "cannot happen" @@ -449,7 +460,9 @@ proc main = of "clone": singleArg() let deps = clone(c, args[0]) - patchNimCfg c, deps + patchNimCfg c, deps, false + if c.cfgHere: + patchNimCfg c, deps, true when MockupRun: if not c.mockupSuccess: error "There were problems." From 0ad601d3c1657216d27be839173861594e3e2421 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 22 Sep 2021 09:43:06 +0200 Subject: [PATCH 3015/4254] fixes #18856 [backport] (#18879) --- compiler/semexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5a1426f2b..ee2626922 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1661,7 +1661,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments})) else: localError(c.config, n.info, errExprHasNoAddress) - result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ)) + result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ)) result.add(n) proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = From 6163bdd279a2c33d4290223cc7f466c8070b8ce4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 22 Sep 2021 15:07:36 +0200 Subject: [PATCH 3016/4254] closes #16132 [backport] (#18880) * closes #16132 [backport] * fixes #16132 [backport] --- compiler/semexprs.nim | 13 ++++++++----- tests/views/tviews1.nim | 14 +++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ee2626922..9134c1301 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1667,11 +1667,14 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le[0] - if x.kind == nkSym and x.sym.kind == skResult and (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView): - n[0] = x # 'result[]' --> 'result' - n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) - x.typ.flags.incl tfVarIsPtr - #echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info + if x.kind == nkSym: + if x.sym.kind == skResult and (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView): + n[0] = x # 'result[]' --> 'result' + n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) + x.typ.flags.incl tfVarIsPtr + #echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info + elif sfGlobal in x.sym.flags: + x.typ.flags.incl tfVarIsPtr proc borrowCheck(c: PContext, n, le, ri: PNode) = const diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index 51f17b9d6..49d79c5b5 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -5,7 +5,8 @@ discard """ 3 2 3 -3''' +3 +15''' targets: "c cpp" """ @@ -26,3 +27,14 @@ proc main(s: seq[int]) = take x main(@[11, 22, 33]) + +var x: int + +proc foo(x: var int): var int = + once: x = 42 + return x + +var y: var int = foo(x) +y = 15 +echo foo(x) +# bug #16132 From 7d2a4c0880223c2c80a5c30227c26fa497898f39 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 23 Sep 2021 11:00:36 +0200 Subject: [PATCH 3017/4254] update csources hash (#18885) --- config/build_config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/build_config.txt b/config/build_config.txt index 75dbb1da3..aee15e695 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -2,4 +2,4 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" nim_csourcesDir=csources_v1 nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git nim_csourcesBranch=master -nim_csourcesHash=9a7f751d23c49c75a0b6f63a234c575dc0df7231 +nim_csourcesHash=5e9be0383f842c9c22ae86e41946a896c43e95d0 From 90a2b5afd8368777e5da9ab97c28130ba683e1d3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 23 Sep 2021 16:47:24 +0200 Subject: [PATCH 3018/4254] correct effect tracking for .borrowed procs [backport] (#18882) * correct effect tracking for .borrowed procs [backport] * progress * fix error message in a test * correctly fix it Co-authored-by: narimiran --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 4 ++-- compiler/jsgen.nim | 2 +- compiler/sempass2.nim | 13 +++++++++---- compiler/semstmts.nim | 5 ++++- compiler/vmgen.nim | 2 +- lib/system.nim | 2 +- tests/effects/tgcsafe3.nim | 2 +- 8 files changed, 20 insertions(+), 12 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 50d048edd..0a3b1b72d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -673,7 +673,7 @@ type mSwap, mIsNil, mArrToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, mTrace, - mDefault, mUnown, mIsolate, mAccessEnv, mReset, + mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, mIterableType, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7a3d769aa..ac4a26bd6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2335,7 +2335,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e[1], d) - of mIsolate: genCall(p, e, d) + of mIsolate, mFinished: genCall(p, e, d) of mEnumToStr: if optTinyRtti in p.config.globalOptions: genEnumToStr(p, e, d) @@ -2929,7 +2929,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if n[genericParamsPos].kind == nkEmpty: var prc = n[namePos].sym if useAliveDataFromDce in p.module.flags: - if p.module.alive.contains(prc.itemId.item) and prc.magic in {mNone, mIsolate}: + if p.module.alive.contains(prc.itemId.item) and prc.magic in {mNone, mIsolate, mFinished}: genProc(p.module, prc) elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index f009c83f2..ff4d2839e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -657,7 +657,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")") of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)") - of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1") + of mStrToStr, mUnown, mIsolate, mFinished: applyFormat("$1", "$1") else: assert false, $op diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 6a0e8772a..9a27d14fa 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -245,9 +245,14 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: Co let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated case u.kind of skLet, skVar: - message(conf, s.info, msgKind, - ("'$#' is not GC-safe as it accesses '$#'" & - " which is a global using GC'ed memory") % [s.name.s, u.name.s]) + if u.typ.skipTypes(abstractInst).kind == tyProc: + message(conf, s.info, msgKind, + "'$#' is not GC-safe as it calls '$#'" % + [s.name.s, u.name.s]) + else: + message(conf, s.info, msgKind, + ("'$#' is not GC-safe as it accesses '$#'" & + " which is a global using GC'ed memory") % [s.name.s, u.name.s]) of routineKinds: # recursive call *always* produces only a warning so the full error # message is printed: @@ -850,7 +855,7 @@ proc trackCall(tracked: PEffects; n: PNode) = mergeRaises(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) gcsafeAndSideeffectCheck() - if a.kind != nkSym or a.sym.magic != mNBindSym: + if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished}: for i in 1.. 0: + s.typ.n[0] = b.typ.n[0] + s.typ.flags = b.typ.flags else: localError(c.config, n.info, errNoSymbolToBorrowFromFound) @@ -1954,7 +1957,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not hasProto: implicitPragmas(c, s, n.info, validPragmas) - if n[pragmasPos].kind != nkEmpty: + if n[pragmasPos].kind != nkEmpty and sfBorrow notin s.flags: setEffectsForProcType(c.graph, s.typ, n[pragmasPos], s) s.typ.flags.incl tfEffectSystemWorkaround diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index f2758ff37..bb095d3ee 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1029,7 +1029,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.genAsgnPatch(n[1], d) c.freeTemp(d) of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest) - of mIsolate: + of mIsolate, mFinished: genCall(c, n, dest) of mNew, mNewFinalize: unused(c, n, dest) diff --git a/lib/system.nim b/lib/system.nim index c93af0854..a5356cb54 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2453,7 +2453,7 @@ when notJSnotNims: else: {.error: "Only closure function and iterator are allowed!".} - proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = + proc finished*[T: proc](x: T): bool {.noSideEffect, inline, magic: "Finished".} = ## It can be used to determine if a first class iterator has finished. when T is "iterator": {.emit: """ diff --git a/tests/effects/tgcsafe3.nim b/tests/effects/tgcsafe3.nim index 5137efe4c..36ea5112c 100644 --- a/tests/effects/tgcsafe3.nim +++ b/tests/effects/tgcsafe3.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'myproc' is not GC-safe as it accesses 'global_proc' which is a global using GC'ed memory" + errormsg: "'myproc' is not GC-safe as it calls 'global_proc'" line: 12 cmd: "nim $target --hints:on --threads:on $options $file" """ From 561b01004cfeb572f82327cd8a3de55d076cb5ff Mon Sep 17 00:00:00 2001 From: Miran Date: Fri, 24 Sep 2021 11:24:55 +0200 Subject: [PATCH 3019/4254] [backport] change some examples in tut1.rst (#18884) * [backport] change some examples in tut1.rst * Update doc/tut1.rst * Update doc/tut1.rst Co-authored-by: Andreas Rumpf --- doc/tut1.rst | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 210ea324e..f492f12b0 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1643,9 +1643,25 @@ variables! For example: echo badname echo badext +Tuple unpacking is also supported in for-loops: + +.. code-block:: nim + :test: "nim c $1" + let a = [(10, 'a'), (20, 'b'), (30, 'c')] + + for (x, c) in a: + echo x + # This will output: 10; 20; 30 + + # Accessing the index is also possible: + for i, (x, c) in a: + echo i, c + # This will output: 0a; 1b; 2c + Fields of tuples are always public, they don't need to be explicity marked to be exported, unlike for example fields in an object type. + Reference and pointer types --------------------------- @@ -1675,13 +1691,18 @@ operators perform implicit dereferencing operations for reference types: Node = ref object le, ri: Node data: int - var - n: Node - new(n) - n.data = 9 + + var n = Node(data: 9) + echo n.data # no need to write n[].data; in fact n[].data is highly discouraged! -To allocate a new traced object, the built-in procedure `new` must be used. +To allocate a new traced object, the built-in procedure `new` can be used: + +.. code-block:: nim + + var n: Node + new(n) + To deal with untraced memory, the procedures `alloc`, `dealloc` and `realloc` can be used. The `system `_ module's documentation contains further details. @@ -1701,15 +1722,17 @@ Example: .. code-block:: nim :test: "nim c $1" - proc echoItem(x: int) = echo x + proc greet(name: string): string = + "Hello, " & name & "!" - proc forEach(action: proc (x: int)) = - const - data = [2, 3, 5, 7, 11] - for d in items(data): - action(d) + proc bye(name: string): string = + "Goodbye, " & name & "." - forEach(echoItem) + proc communicate(greeting: proc (x: string): string, name: string) = + echo greeting(name) + + communicate(greet, "John") + communicate(bye, "Mary") A subtle issue with procedural types is that the calling convention of the procedure influences the type compatibility: procedural types are only compatible From 5d315ebcc2d4f46b4a74c6ab10146466c894b9de Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 24 Sep 2021 13:24:41 +0200 Subject: [PATCH 3020/4254] ported Nim to proprietary CrossOS [backport] (#18889) --- ci/funs.sh | 2 ++ compiler/installer.ini | 1 + compiler/options.nim | 6 ++++-- compiler/platform.nim | 6 +++++- lib/pure/os.nim | 2 +- tools/niminst/buildsh.nimf | 5 +++++ 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ci/funs.sh b/ci/funs.sh index e25922c8c..1638931c6 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -74,6 +74,8 @@ _nimBuildCsourcesIfNeeded(){ makeX=gmake elif [ "$unamestr" = 'NetBSD' ]; then makeX=gmake + elif [ "$unamestr" = 'CROSSOS' ]; then + makeX=gmake else makeX=make fi diff --git a/compiler/installer.ini b/compiler/installer.ini index 3f1630a92..9e31b4e3f 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -13,6 +13,7 @@ Platforms: """ netbsd: i386;amd64 openbsd: i386;amd64;arm;arm64 dragonfly: i386;amd64 + crossos: amd64 haiku: i386;amd64 android: i386;arm;arm64 nintendoswitch: arm64 diff --git a/compiler/options.nim b/compiler/options.nim index ea302aed6..eafcd816d 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -577,11 +577,13 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osQnx, osAtari, osAix, osHaiku, osVxWorks, osSolaris, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos, - osAndroid, osNintendoSwitch, osFreeRTOS} + osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos} of "linux": result = conf.target.targetOS in {osLinux, osAndroid} of "bsd": - result = conf.target.targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly} + result = conf.target.targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos} + of "freebsd": + result = conf.target.targetOS in {osFreebsd, osCrossos} of "emulatedthreadvars": result = platform.OS[conf.target.targetOS].props.contains(ospLacksThreadVars) of "msdos": result = conf.target.targetOS == osDos diff --git a/compiler/platform.nim b/compiler/platform.nim index 7bc77d809..1bc00b629 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -20,7 +20,7 @@ type TSystemOS* = enum # Also add OS in initialization section and alias # conditionals to condsyms (end of module). osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, - osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx, + osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx, osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny @@ -105,6 +105,10 @@ const scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {ospNeedsPIC, ospPosix}), + (name: "CROSSOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + props: {ospNeedsPIC, ospPosix}), (name: "AIX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", diff --git a/lib/pure/os.nim b/lib/pure/os.nim index cfdacdb3c..dd1f9f0b6 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -3007,7 +3007,7 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly) or defined(netb proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t, newp: pointer, newplen: csize_t): cint {.importc: "sysctl",header: """#include - #include """} + #include """.} const CTL_KERN = 1 KERN_PROC = 14 diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index f74413c09..7b30cd86c 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -109,6 +109,11 @@ case $uos in CC="clang" LINK_FLAGS="$LINK_FLAGS -lm" ;; + *crossos* ) + myos="crossos" + CC="clang" + LINK_FLAGS="$LINK_FLAGS -lm" + ;; *openbsd* ) myos="openbsd" CC="clang" From f7d642f2f3925feb5addc315eb59caf326cad470 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 24 Sep 2021 14:59:48 +0200 Subject: [PATCH 3021/4254] [backport] arc: improve compile time of (nested) loops (#18890) --- compiler/dfa.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 65c483e9c..0539f6699 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -308,6 +308,11 @@ when true: # We unroll every loop 3 times. We emulate 0, 1, 2 iterations # through the loop. We need to prove this is correct for our # purposes. But Herb Sutter claims it is. (Proof by authority.) + # + # EDIT: Actually, we only need to unroll 2 times + # because Nim doesn't have a way of breaking/goto-ing into + # a loop iteration. Unrolling 2 times is much better for compile + # times of nested loops than 3 times, so we do that here. #[ while cond: body @@ -347,12 +352,12 @@ when true: # 'while true' is an idiom in Nim and so we produce # better code for it: withBlock(nil): - for i in 0..2: + for i in 0..1: c.gen(n[1]) else: withBlock(nil): - var endings: array[3, TPosition] - for i in 0..2: + var endings: array[2, TPosition] + for i in 0..1: c.gen(n[0]) endings[i] = c.forkI(n) c.gen(n[1]) From 7e5eab571e6e8e57928b40f535802aec04e04633 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 24 Sep 2021 16:27:34 +0200 Subject: [PATCH 3022/4254] closes #18690; make view types stricter [backport] (#18891) * closes #18690 * don't allow capturing of view types [backport] --- compiler/lambdalifting.nim | 6 ++---- tests/views/tviews1.nim | 13 ++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c555cedfe..a622f6de6 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -12,7 +12,7 @@ import intsets, strutils, options, ast, astalgo, msgs, idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos, - transf, liftdestructors + transf, liftdestructors, typeallowed discard """ The basic approach is that captured vars need to be put on the heap and @@ -191,9 +191,7 @@ proc interestingVar(s: PSym): bool {.inline.} = s.typ.kind notin {tyStatic, tyTypeDesc} proc illegalCapture(s: PSym): bool {.inline.} = - result = skipTypes(s.typ, abstractInst).kind in - {tyVar, tyOpenArray, tyVarargs, tyLent} or - s.kind == skResult + result = classifyViewType(s.typ) != noView or s.kind == skResult proc isInnerProc(s: PSym): bool = if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone: diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index 49d79c5b5..3dbf664fc 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -6,7 +6,8 @@ discard """ 2 3 3 -15''' +15 +(oa: [1, 3, 4])''' targets: "c cpp" """ @@ -38,3 +39,13 @@ var y: var int = foo(x) y = 15 echo foo(x) # bug #16132 + +# bug #18690 + +type + F = object + oa: openarray[int] + +let s1 = @[1,3,4,5,6] +var test = F(oa: toOpenArray(s1, 0, 2)) +echo test From 4adada0d8016016104d6259a1167a7f8b37f1611 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 24 Sep 2021 22:34:12 +0800 Subject: [PATCH 3023/4254] fix a typo (rename `temporal` to `temporary` (#18892) [backport] --- lib/pure/strutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 3179c73d2..873949ca6 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2039,7 +2039,7 @@ func countLines*(s: string): int {.rtl, extern: "nsuCountLines".} = ## Returns the number of lines in the string `s`. ## ## This is the same as `len(splitLines(s))`, but much more efficient - ## because it doesn't modify the string creating temporal objects. Every + ## because it doesn't modify the string creating temporary objects. Every ## `character literal `_ ## newline combination (CR, LF, CR-LF) is supported. ## From 8bdb98539570fdf3c41ee5509d5b90913ac1803e Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 25 Sep 2021 19:22:00 +0800 Subject: [PATCH 3024/4254] fix wrong name (rnimsyn => renderer; pnimsyn => parser; scanner => lexer) (#18895) * fix wrong module name * rephrase more word --- compiler/filter_tmpl.nim | 2 +- compiler/lexer.nim | 4 ++-- compiler/nimconf.nim | 2 +- compiler/renderer.nim | 4 ++-- doc/manual.rst | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 6165ff2f3..84ed99164 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -22,7 +22,7 @@ type info: TLineInfo indent, emitPar: int x: string # the current input line - outp: PLLStream # the output will be parsed by pnimsyn + outp: PLLStream # the output will be parsed by parser subsChar, nimDirective: char emit, conc, toStr: string curly, bracket, par: int diff --git a/compiler/lexer.nim b/compiler/lexer.nim index ede16fdf1..506b0e924 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -7,12 +7,12 @@ # distribution, for details about the copyright. # -# This scanner is handwritten for efficiency. I used an elegant buffering +# This lexer is handwritten for efficiency. I used an elegant buffering # scheme which I have not seen anywhere else: # We guarantee that a whole line is in the buffer. Thus only when scanning # the \n or \r character we have to check whether we need to read in the next # chunk. (\n or \r already need special handling for incrementing the line -# counter; choosing both \n and \r allows the scanner to properly read Unix, +# counter; choosing both \n and \r allows the lexer to properly read Unix, # DOS or Macintosh text files, even when it is not the native format. import diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 94c93a283..1cf22e20a 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -14,7 +14,7 @@ import options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig # ---------------- configuration file parser ----------------------------- -# we use Nim's scanner here to save space and work +# we use Nim's lexer here to save space and work proc ppGetTok(L: var Lexer, tok: var Token) = # simple filter diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 393f35289..22a2d4cbd 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -410,7 +410,7 @@ proc atom(g: TSrcGen; n: PNode): string = if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s else: result = "[type node]" else: - internalError(g.config, "rnimsyn.atom " & $n.kind) + internalError(g.config, "renderer.atom " & $n.kind) result = "" proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int = @@ -1699,7 +1699,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = gsub(g, n[0], c) else: #nkNone, nkExplicitTypeListCall: - internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')') + internalError(g.config, n.info, "renderer.gsub(" & $n.kind & ')') proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = if n == nil: return "" diff --git a/doc/manual.rst b/doc/manual.rst index 09826441c..dfcf0ba54 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -216,7 +216,7 @@ comment: .. code-block:: nim i = 0 # This is a single comment over multiple lines. - # The scanner merges these two pieces. + # The lexer merges these two pieces. # The comment continues here. From e3b19cbe52e0578de315d259fbb066bfe991a60f Mon Sep 17 00:00:00 2001 From: Aditya Siram Date: Sat, 25 Sep 2021 07:17:41 -0500 Subject: [PATCH 3025/4254] fixes #18878 (#18883) --- lib/core/typeinfo.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index d66dc1898..18d2091b9 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -216,7 +216,8 @@ proc extendSeq*(x: Any) = when defined(gcDestructors): var s = cast[ptr NimSeqV2Reimpl](x.value) let elem = x.rawType.base - s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAdd(s.len, s.p, 1, elem.size, elem.align)) + if s.p == nil or s.p.cap < s.len+1: + s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAdd(s.len, s.p, 1, elem.size, elem.align)) inc s.len else: var y = cast[ptr PGenSeq](x.value)[] From 57eb763c65c2d517e2b6ca7b2ca2d3bb5ab6c3d5 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 27 Sep 2021 19:13:02 +0800 Subject: [PATCH 3026/4254] activate winim (#18907) `winim` is dependent on windows API. --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 657ddb2d1..0c47104ac 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -159,7 +159,7 @@ pkg "unicodeplus", "nim c -d:release -r tests/tests.nim" pkg "unpack" pkg "weave", "nimble test_gc_arc", allowFailure = true pkg "websocket", "nim c websocket.nim" -pkg "winim", allowFailure = true +pkg "winim", "nim c winim.nim" pkg "with" pkg "ws", allowFailure = true pkg "yaml", "nim c -r test/tserialization.nim" From 5325a366e79b6e34fcd2b2dfe675897212f8ca2d Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Mon, 27 Sep 2021 16:35:14 +0100 Subject: [PATCH 3027/4254] Add armv8l support (Closes: #18898) (#18901) [backport] --- tools/niminst/buildsh.nimf | 2 +- tools/niminst/makefile.nimf | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 7b30cd86c..9850abd89 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -213,7 +213,7 @@ case $ucpu in mycpu="alpha" ;; *aarch64*|*arm64* ) mycpu="arm64" ;; - *arm*|*armv6l*|*armv71* ) + *arm*|*armv6l*|*armv7l*|*armv8l* ) mycpu="arm" ;; *riscv64|riscv* ) mycpu="riscv64" ;; diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index a0e9a40f7..69e87b837 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -157,6 +157,9 @@ endif ifeq ($(ucpu),armv7hl) mycpu = arm endif +ifeq ($(ucpu),armv8l) + mycpu = arm +endif ifeq ($(ucpu),aarch64) mycpu = arm64 endif From cdf9ac675b4348a7b5239186637c54920bb92619 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 27 Sep 2021 19:25:00 +0200 Subject: [PATCH 3028/4254] this ensures libp2p continues to compile [backport] (#18908) --- compiler/cgen.nim | 11 ++++++++--- compiler/guards.nim | 10 ++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a06a87172..43410dc60 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -855,10 +855,15 @@ proc closureSetup(p: BProc, prc: PSym) = [rdLoc(env.loc), getTypeDesc(p.module, env.typ)]) proc containsResult(n: PNode): bool = - if n.kind == nkSym and n.sym.kind == skResult: - result = true + result = false + case n.kind + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams: + discard + of nkSym: + if n.sym.kind == skResult: + result = true else: - for i in 0.. Date: Mon, 27 Sep 2021 22:23:31 +0200 Subject: [PATCH 3029/4254] fixes 'lent T' inside object constructor [backport] (#18911) * fixes 'lent T' inside object constructor [backport] * progress --- compiler/sem.nim | 3 ++- compiler/semobjconstr.nim | 2 +- compiler/semstmts.nim | 2 +- tests/views/tviews1.nim | 17 +++++++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index bdecbe602..70c57864c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -107,12 +107,13 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: result = fitNodePostMatch(c, formal, result) -proc fitNodeForLocalVar(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = +proc fitNodeConsiderViewType(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = let a = fitNode(c, formal, arg, info) if formal.kind in {tyVar, tyLent}: #classifyViewType(formal) != noView: result = newNodeIT(nkHiddenAddr, a.info, formal) result.add a + formal.flags.incl tfVarIsPtr else: result = a diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 1563e5c16..001956ede 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -79,7 +79,7 @@ proc semConstrField(c: PContext, flags: TExprFlags, var initValue = semExprFlagDispatched(c, assignment[1], flags) if initValue != nil: - initValue = fitNode(c, field.typ, initValue, assignment.info) + initValue = fitNodeConsiderViewType(c, field.typ, initValue, assignment.info) assignment[0] = newSymNode(field) assignment[1] = initValue assignment.flags.incl nfSem diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 3b699f6c8..4607e857a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -545,7 +545,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: # BUGFIX: ``fitNode`` is needed here! # check type compatibility between def.typ and typ - def = fitNodeForLocalVar(c, typ, def, def.info) + def = fitNodeConsiderViewType(c, typ, def, def.info) #changeType(def.skipConv, typ, check=true) else: typ = def.typ.skipTypes({tyStatic, tySink}).skipIntLit(c.idgen) diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index 3dbf664fc..ced487ce8 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -49,3 +49,20 @@ type let s1 = @[1,3,4,5,6] var test = F(oa: toOpenArray(s1, 0, 2)) echo test + +type + Foo = object + x: string + y: seq[int] + data: array[10000, byte] + + View[T] = object + x: lent T + +proc mainB = + let f = Foo(y: @[1, 2, 3]) + let foo = View[Foo](x: f) + assert foo.x.x == "" + assert foo.x.y == @[1, 2, 3] + +mainB() From 5eb357f5a2db81d7027eaf5430cda74370e45a67 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 28 Sep 2021 12:45:25 +0800 Subject: [PATCH 3030/4254] change comment (#18913) --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index a5356cb54..358aae938 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -160,7 +160,7 @@ when defined(nimHashOrdinalFixed): ## as well as their subtypes. See also ## `SomeOrdinal`. else: - # bootstrap <= 0.20.0 + # bootstrap < 1.2.0 type OrdinalImpl[T] {.magic: Ordinal.} Ordinal* = OrdinalImpl | uint | uint64 From 56bd5cbb877b69f5c4a49470845621267a316f91 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 28 Sep 2021 15:05:22 +0800 Subject: [PATCH 3031/4254] fix a typo (canonilization => canonicalization) (#18914) --- compiler/patterns.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 1ef903161..4b39de3ba 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -36,7 +36,7 @@ proc putLazy(c: PPatternContext, sym: PSym, n: PNode) = proc matches(c: PPatternContext, p, n: PNode): bool proc canonKind(n: PNode): TNodeKind = - ## nodekind canonilization for pattern matching + ## nodekind canonicalization for pattern matching result = n.kind case result of nkCallKinds: result = nkCall From 08cf4cb1e58fad35be3846e98a308500ac2cfdb0 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 28 Sep 2021 17:35:04 +0800 Subject: [PATCH 3032/4254] test ord (#18909) --- compiler/semmagic.nim | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 87f7da815..874098294 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -216,10 +216,6 @@ proc semOrd(c: PContext, n: PNode): PNode = let parType = n[1].typ if isOrdinalType(parType, allowEnumWithHoles=true): discard - elif parType.kind == tySet: - let a = toInt64(firstOrd(c.config, parType)) - let b = toInt64(lastOrd(c.config, parType)) - result.typ = makeRangeType(c, a, b, n.info) else: localError(c.config, n.info, errOrdinalTypeExpected) result.typ = errorType(c) From f061971a9be5222f0f158f605220f3bda42f7488 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 29 Sep 2021 00:32:39 -0700 Subject: [PATCH 3033/4254] envPairs works in vm, nims (#18615) * envPairs works in vm, nims * fixup --- compiler/vmops.nim | 14 +- lib/pure/includes/osenv.nim | 349 ++++++++++++++-------------- lib/pure/os.nim | 3 +- testament/lib/stdtest/testutils.nim | 7 +- tests/js/tos.nim | 28 +-- tests/stdlib/tosenv.nim | 18 +- tests/test_nimscript.nims | 4 + 7 files changed, 213 insertions(+), 210 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index e287dd41d..b9801234d 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -13,7 +13,7 @@ from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma, lgamma - +from std/sequtils import toSeq when declared(math.copySign): # pending bug #18762, avoid renaming math from std/math as math2 import copySign @@ -22,8 +22,8 @@ when declared(math.signbit): # ditto from std/math as math3 import signbit -from std/os import getEnv, existsEnv, delEnv, putEnv, dirExists, fileExists, walkDir, - getAppFilename, raiseOSError, osLastError +from std/os import getEnv, existsEnv, delEnv, putEnv, envPairs, + dirExists, fileExists, walkDir, getAppFilename, raiseOSError, osLastError from std/md5 import getMD5 from std/times import cpuTime @@ -156,6 +156,12 @@ proc stackTrace2(c: PCtx, msg: string, n: PNode) = stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info) proc registerAdditionalOps*(c: PCtx) = + + template wrapIterator(fqname: string, iter: untyped) = + registerCallback c, fqname, proc(a: VmArgs) = + setResult(a, toLit(toSeq(iter))) + + proc gorgeExWrapper(a: VmArgs) = let ret = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), a.currentLineInfo, c.config) @@ -341,3 +347,5 @@ proc registerAdditionalOps*(c: PCtx) = let p = a.getVar(0) let x = a.getFloat(1) addFloatSprintf(p.strVal, x) + + wrapIterator("stdlib.os.envPairsImplSeq"): envPairs() diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index 6aaafbfda..00a82327c 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -3,189 +3,200 @@ when not declared(os) and not declared(ospaths): {.error: "This is an include file for os.nim!".} -when defined(nodejs): - proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = - var ret = default.cstring - let key2 = key.cstring - {.emit: "const value = process.env[`key2`];".} - {.emit: "if (value !== undefined) { `ret` = value };".} - result = $ret +when not defined(nimscript): + when defined(nodejs): + proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = + var ret = default.cstring + let key2 = key.cstring + {.emit: "const value = process.env[`key2`];".} + {.emit: "if (value !== undefined) { `ret` = value };".} + result = $ret - proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = - var key2 = key.cstring - var ret: bool - {.emit: "`ret` = `key2` in process.env;".} - result = ret + proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + var key2 = key.cstring + var ret: bool + {.emit: "`ret` = `key2` in process.env;".} + result = ret - proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = - var key2 = key.cstring - var val2 = val.cstring - {.emit: "process.env[`key2`] = `val2`;".} + proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + var key2 = key.cstring + var val2 = val.cstring + {.emit: "process.env[`key2`] = `val2`;".} - proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = - var key2 = key.cstring - {.emit: "delete process.env[`key2`];".} + proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + var key2 = key.cstring + {.emit: "delete process.env[`key2`];".} - iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = - var num: int - var keys: RootObj - {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".} - for i in 0..".} - when defined(windows): - proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} - from std/private/win_setenv import setEnvImpl else: - proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} - proc c_unsetenv(env: cstring): cint {.importc: "unsetenv", header: "".} - proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = - ## Returns the value of the `environment variable`:idx: named `key`. - ## - ## If the variable does not exist, `""` is returned. To distinguish - ## whether a variable exists or it's value is just `""`, call - ## `existsEnv(key) proc <#existsEnv,string>`_. - ## - ## See also: - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - runnableExamples: - assert getEnv("unknownEnv") == "" - assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" - - let env = c_getenv(key) - if env == nil: return default - result = $env - - proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = - ## Checks whether the environment variable named `key` exists. - ## Returns true if it exists, false otherwise. - ## - ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - runnableExamples: - assert not existsEnv("unknownEnv") - - return c_getenv(key) != nil - - proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = - ## Sets the value of the `environment variable`:idx: named `key` to `val`. - ## If an error occurs, `OSError` is raised. - ## - ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ + proc c_getenv(env: cstring): cstring {. + importc: "getenv", header: "".} when defined(windows): - if key.len == 0 or '=' in key: - raise newException(OSError, "invalid key, got: " & $(key, val)) - if setEnvImpl(key, val, 1'i32) != 0'i32: - raiseOSError(osLastError(), $(key, val)) + proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + from std/private/win_setenv import setEnvImpl else: - if c_setenv(key, val, 1'i32) != 0'i32: - raiseOSError(osLastError(), $(key, val)) + proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} + proc c_unsetenv(env: cstring): cint {.importc: "unsetenv", header: "".} - proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = - ## Deletes the `environment variable`:idx: named `key`. - ## If an error occurs, `OSError` is raised. - ## - ## See also:ven - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ - template bail = raiseOSError(osLastError(), key) - when defined(windows): - #[ - # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160 - > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string - note that nil is not legal - ]# - if key.len == 0 or '=' in key: - raise newException(OSError, "invalid key, got: " & key) - if c_putenv_s(key, "") != 0'i32: bail - else: - if c_unsetenv(key) != 0'i32: bail + proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = + ## Returns the value of the `environment variable`:idx: named `key`. + ## + ## If the variable does not exist, `""` is returned. To distinguish + ## whether a variable exists or it's value is just `""`, call + ## `existsEnv(key) proc <#existsEnv,string>`_. + ## + ## See also: + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + runnableExamples: + assert getEnv("unknownEnv") == "" + assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" - when defined(windows): - when useWinUnicode: - when defined(cpp): - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", - header: "".} + let env = c_getenv(key) + if env == nil: return default + result = $env + + proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + ## Checks whether the environment variable named `key` exists. + ## Returns true if it exists, false otherwise. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + runnableExamples: + assert not existsEnv("unknownEnv") + + return c_getenv(key) != nil + + proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + ## Sets the value of the `environment variable`:idx: named `key` to `val`. + ## If an error occurs, `OSError` is raised. + ## + ## See also: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + when defined(windows): + if key.len == 0 or '=' in key: + raise newException(OSError, "invalid key, got: " & $(key, val)) + if setEnvImpl(key, val, 1'i32) != 0'i32: + raiseOSError(osLastError(), $(key, val)) else: - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importc: "wcschr", - header: "".} - else: - proc strEnd(cstr: cstring, c = 0'i32): cstring {.importc: "strchr", - header: "".} - elif defined(macosx) and not defined(ios) and not defined(emscripten): - # From the manual: - # Shared libraries and bundles don't have direct access to environ, - # which is only available to the loader ld(1) when a complete program - # is being linked. - # The environment routines can still be used, but if direct access to - # environ is needed, the _NSGetEnviron() routine, defined in - # , can be used to retrieve the address of environ - # at runtime. - proc NSGetEnviron(): ptr cstringArray {.importc: "_NSGetEnviron", - header: "".} - elif defined(haiku): - var gEnv {.importc: "environ", header: "".}: cstringArray - else: - var gEnv {.importc: "environ".}: cstringArray + if c_setenv(key, val, 1'i32) != 0'i32: + raiseOSError(osLastError(), $(key, val)) + + proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + ## Deletes the `environment variable`:idx: named `key`. + ## If an error occurs, `OSError` is raised. + ## + ## See also:ven + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `envPairs iterator <#envPairs.i>`_ + template bail = raiseOSError(osLastError(), key) + when defined(windows): + #[ + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160 + > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string + note that nil is not legal + ]# + if key.len == 0 or '=' in key: + raise newException(OSError, "invalid key, got: " & key) + if c_putenv_s(key, "") != 0'i32: bail + else: + if c_unsetenv(key) != 0'i32: bail - iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = - ## Iterate over all `environments variables`:idx:. - ## - ## In the first component of the tuple is the name of the current variable stored, - ## in the second its value. - ## - ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ when defined(windows): - block: - template impl(get_fun, typ, size, zero, free_fun) = - let env = get_fun() - var e = env - if e == nil: break - while true: - let eend = strEnd(e) - let kv = $e - let p = find(kv, '=') - yield (substr(kv, 0, p-1), substr(kv, p+1)) - e = cast[typ](cast[ByteAddress](eend)+size) - if typeof(zero)(eend[1]) == zero: break - discard free_fun(env) - when useWinUnicode: - impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW) + when useWinUnicode: + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", + header: "".} else: - impl(getEnvironmentStringsA, cstring, 1, '\0', freeEnvironmentStringsA) + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importc: "wcschr", + header: "".} + else: + proc strEnd(cstr: cstring, c = 0'i32): cstring {.importc: "strchr", + header: "".} + elif defined(macosx) and not defined(ios) and not defined(emscripten): + # From the manual: + # Shared libraries and bundles don't have direct access to environ, + # which is only available to the loader ld(1) when a complete program + # is being linked. + # The environment routines can still be used, but if direct access to + # environ is needed, the _NSGetEnviron() routine, defined in + # , can be used to retrieve the address of environ + # at runtime. + proc NSGetEnviron(): ptr cstringArray {.importc: "_NSGetEnviron", + header: "".} + elif defined(haiku): + var gEnv {.importc: "environ", header: "".}: cstringArray else: - var i = 0 - when defined(macosx) and not defined(ios) and not defined(emscripten): - var gEnv = NSGetEnviron()[] - while gEnv[i] != nil: - let kv = $gEnv[i] - inc(i) - let p = find(kv, '=') - yield (substr(kv, 0, p-1), substr(kv, p+1)) + var gEnv {.importc: "environ".}: cstringArray + + iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = + when defined(windows): + block: + template impl(get_fun, typ, size, zero, free_fun) = + let env = get_fun() + var e = env + if e == nil: break + while true: + let eend = strEnd(e) + let kv = $e + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) + e = cast[typ](cast[ByteAddress](eend)+size) + if typeof(zero)(eend[1]) == zero: break + discard free_fun(env) + when useWinUnicode: + impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW) + else: + impl(getEnvironmentStringsA, cstring, 1, '\0', freeEnvironmentStringsA) + else: + var i = 0 + when defined(macosx) and not defined(ios) and not defined(emscripten): + var gEnv = NSGetEnviron()[] + while gEnv[i] != nil: + let kv = $gEnv[i] + inc(i) + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) + +proc envPairsImplSeq(): seq[tuple[key, value: string]] = discard # vmops + +iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = + ## Iterate over all `environments variables`:idx:. + ## + ## In the first component of the tuple is the name of the current variable stored, + ## in the second its value. + ## + ## Works in native backends, nodejs and vm, like the following APIs: + ## * `getEnv proc <#getEnv,string,string>`_ + ## * `existsEnv proc <#existsEnv,string>`_ + ## * `putEnv proc <#putEnv,string,string>`_ + ## * `delEnv proc <#delEnv,string>`_ + when nimvm: + for ai in envPairsImplSeq(): yield ai + else: + when defined(nimscript): discard + else: + for ai in envPairsImpl(): yield ai diff --git a/lib/pure/os.nim b/lib/pure/os.nim index dd1f9f0b6..e3b8e9f1c 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -871,8 +871,7 @@ proc unixToNativePath*(path: string, drive=""): string {. inc(i) include "includes/oserr" -when not defined(nimscript): - include "includes/osenv" +include "includes/osenv" proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index a5476b8d7..12e6a56ab 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -1,5 +1,8 @@ import std/private/miscdollars -from std/os import getEnv +when defined(nimscript): + import std/os # xxx investigate why needed +else: + from std/os import getEnv import std/[macros, genasts] template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = @@ -26,7 +29,7 @@ template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = msg2.add $expr & " " & msg echo msg2 -when not defined(js): +when not defined(js) and not defined(nimscript): import std/strutils proc greedyOrderedSubsetLines*(lhs, rhs: string, allowPrefixMatch = false): bool = diff --git a/tests/js/tos.nim b/tests/js/tos.nim index 07eb3aaa3..bfe3cd9b4 100644 --- a/tests/js/tos.nim +++ b/tests/js/tos.nim @@ -1,3 +1,5 @@ +# xxx consider merging this in tests/stdlib/tos.nim for increased coverage (with selecting disabling) + static: doAssert defined(nodejs) import os @@ -19,29 +21,3 @@ block: if not isWindows: doAssert cwd.isAbsolute doAssert relativePath(getCurrentDir() / "foo", "bar") == "../foo" - -import std/sequtils - -template main = - putEnv("foo", "bar") - doAssert getEnv("foo") == "bar" - doAssert existsEnv("foo") - - putEnv("foo", "") - doAssert existsEnv("foo") - putEnv("foo", "bar2") - doAssert getEnv("foo") == "bar2" - - when nimvm: - discard - else: - # need support in vmops: envPairs, delEnv - let s = toSeq(envPairs()) - doAssert ("foo", "bar2") in s - doAssert ("foo", "bar") notin s - - delEnv("foo") - doAssert not existsEnv("foo") - -static: main() -main() diff --git a/tests/stdlib/tosenv.nim b/tests/stdlib/tosenv.nim index df5759d0c..0a50031a1 100644 --- a/tests/stdlib/tosenv.nim +++ b/tests/stdlib/tosenv.nim @@ -13,16 +13,18 @@ template main = for val in ["val", ""]: # ensures empty val works too const key = "NIM_TESTS_TOSENV_KEY" doAssert not existsEnv(key) - putEnv(key, val) + + putEnv(key, "tempval") + doAssert existsEnv(key) + doAssert getEnv(key) == "tempval" + + putEnv(key, val) # change a key that already exists doAssert existsEnv(key) doAssert getEnv(key) == val - when nimvm: discard - else: - doAssert (key, val) in toSeq(envPairs()) + + doAssert (key, val) in toSeq(envPairs()) delEnv(key) - when nimvm: discard - else: - doAssert (key, val) notin toSeq(envPairs()) + doAssert (key, val) notin toSeq(envPairs()) doAssert not existsEnv(key) delEnv(key) # deleting an already deleted env var doAssert not existsEnv(key) @@ -43,7 +45,7 @@ template main = static: main() main() -when not defined(js): +when not defined(js) and not defined(nimscript): block: # bug #18533 proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} var thr: Thread[void] diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 90b6181aa..ecb409677 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -71,7 +71,11 @@ import std/[ decls, compilesettings, with, wrapnils ] +# non-std imports +import stdtest/testutils +# tests (increase coverage via code reuse) import stdlib/trandom +import stdlib/tosenv echo "Nimscript imports are successful." From b74b914e4f36199797b77e98bd2d771b4056a0d6 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 29 Sep 2021 11:14:47 +0200 Subject: [PATCH 3034/4254] [backport] use old style hints in .cfg files (#18917) refs #18085 --- compiler/nim.cfg | 4 ++-- compiler/nimfix/nimfix.nim.cfg | 2 +- config/nim.cfg | 4 ++-- drnim/nim.cfg | 2 +- nimsuggest/nimsuggest.nim.cfg | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index d6ac6a937..4a0287cb5 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -1,6 +1,6 @@ # Special configuration file for the Nim project -hint:XDeclaredButNotUsed:off +hint[XDeclaredButNotUsed]:off define:booting define:nimcore @@ -23,7 +23,7 @@ define:useStdoutAsStdmsg #gc:markAndSweep @if nimHasWarningObservableStores: - warning:ObservableStores: off + warning[ObservableStores]: off @end @if nimHasEffectsOf: diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg index 27ebf10b9..0d9dbfa4b 100644 --- a/compiler/nimfix/nimfix.nim.cfg +++ b/compiler/nimfix/nimfix.nim.cfg @@ -1,7 +1,7 @@ # Special configuration file for the Nim project # gc:markAndSweep -hint:XDeclaredButNotUsed:off +hint[XDeclaredButNotUsed]:off path:"$projectPath/.." path:"$lib/packages/docutils" diff --git a/config/nim.cfg b/config/nim.cfg index c0a844e03..3b964d124 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -13,8 +13,8 @@ cc = gcc # additional options always passed to the compiler: --parallel_build: "0" # 0 to auto-detect number of processors -hint:LineTooLong:off -#hint:XDeclaredButNotUsed:off +hint[LineTooLong]=off +#hint[XDeclaredButNotUsed]=off # Examples of how to setup a cross-compiler: diff --git a/drnim/nim.cfg b/drnim/nim.cfg index 57dca974c..58c1725d9 100644 --- a/drnim/nim.cfg +++ b/drnim/nim.cfg @@ -1,6 +1,6 @@ # Special configuration file for the Nim project -hint:XDeclaredButNotUsed:off +hint[XDeclaredButNotUsed]:off define:booting define:nimcore diff --git a/nimsuggest/nimsuggest.nim.cfg b/nimsuggest/nimsuggest.nim.cfg index 6e5ee8c71..394449740 100644 --- a/nimsuggest/nimsuggest.nim.cfg +++ b/nimsuggest/nimsuggest.nim.cfg @@ -2,7 +2,7 @@ gc:markAndSweep -hint:XDeclaredButNotUsed:off +hint[XDeclaredButNotUsed]:off path:"$lib/packages/docutils" From f35e9a5752bb4cd4e30105cd27b6bc56cbf22329 Mon Sep 17 00:00:00 2001 From: Jonas Schubert Erlandsson Date: Wed, 29 Sep 2021 19:14:31 +0300 Subject: [PATCH 3035/4254] Adds source to single tags list (#18920) --- lib/pure/htmlparser.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index c572146a7..21dff69ff 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -215,7 +215,7 @@ const tagMenu, tagNoframes} SingleTags* = {tagArea, tagBase, tagBasefont, tagBr, tagCol, tagFrame, tagHr, tagImg, tagIsindex, - tagLink, tagMeta, tagParam, tagWbr} + tagLink, tagMeta, tagParam, tagWbr, tagSource} proc allLower(s: string): bool = for c in s: From 6bb32da4aecbe80a9cc0cce90322c0e741ee8b85 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 30 Sep 2021 13:46:30 +0800 Subject: [PATCH 3036/4254] [std/tasks] more gcsafe stuffs [backport] (#18926) --- lib/std/tasks.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index 97c4df3f7..e2ea5377f 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -61,12 +61,12 @@ type Task* = object ## `Task` contains the callback and its arguments. callback: proc (args: pointer) {.nimcall, gcsafe.} args: pointer - destroy: proc (args: pointer) {.nimcall.} + destroy: proc (args: pointer) {.nimcall, gcsafe.} proc `=copy`*(x: var Task, y: Task) {.error.} -proc `=destroy`*(t: var Task) {.inline.} = +proc `=destroy`*(t: var Task) {.inline, gcsafe.} = ## Frees the resources allocated for a `Task`. if t.args != nil: if t.destroy != nil: @@ -219,7 +219,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC let `objTemp` = cast[ptr `scratchObjType`](args) `functionStmtList` - proc `destroyName`(args: pointer) {.nimcall.} = + proc `destroyName`(args: pointer) {.gcsafe, nimcall.} = let `objTemp2` = cast[ptr `scratchObjType`](args) `tempNode` From c3dd53bb2cf492029ae256f64f64d2577621b995 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Sep 2021 11:35:42 +0200 Subject: [PATCH 3037/4254] typos [backport] (#18929) --- doc/destructors.rst | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index 28d8fa5f9..195dc8f97 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -145,7 +145,7 @@ not free the resources afterward by setting the object to its default value default value is written as `wasMoved(x)`. When not provided the compiler is using a combination of `=destroy` and `copyMem` instead. This is efficient hence users rarely need to implement their own `=sink` operator, it is enough to -provide `=destroy` and `=copy`, compiler will take care of the rest. +provide `=destroy` and `=copy`, the compiler will take care of the rest. The prototype of this hook for a type `T` needs to be: @@ -169,7 +169,7 @@ How self-assignments are handled is explained later in this document. `=copy` hook ---------------- +------------ The ordinary assignment in Nim conceptually copies the values. The `=copy` hook is called for assignments that couldn't be transformed into `=sink` @@ -206,11 +206,11 @@ by the compiler. Notice that there is no `=` before the `{.error.}` pragma. `=trace` hook ---------------- +------------- A custom **container** type can support Nim's cycle collector `--gc:orc` via the `=trace` hook. If the container does not implement `=trace`, cyclic data -structure which are constructed with the help of the container might leak +structures which are constructed with the help of the container might leak memory or resources, but memory safety is not compromised. The prototype of this hook for a type `T` needs to be: @@ -225,10 +225,10 @@ to calls of the built-in `=trace` operation. Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates manually allocated resources is also used, and then only when there is a chance of cyclic references from items within the manually allocated resources when it is desired that `--gc:orc` -be able to break and collect these cyclic referenced resources. Currently however, there is a +is able to break and collect these cyclic referenced resources. Currently however, there is a mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically create a version of the other which will then conflict with the creation of the second of the -pair. The work around for this problem is to forward declare the second of the "hooks" to +pair. The workaround for this problem is to forward declare the second of the "hooks" to prevent the automatic creation. The general pattern in using `=destroy` with `=trace` looks like: @@ -250,8 +250,9 @@ The general pattern in using `=destroy` with `=trace` looks like: dest.arr.dealloc proc `=trace`[T](dest: var Test[T]; env: pointer) = - if dest.arr != nil: # trace the `T`'s which may be cyclic - for i in 0 ..< dest.size: dest.arr[i].`=trace` env + if dest.arr != nil: + # trace the `T`'s which may be cyclic + for i in 0 ..< dest.size: `=trace`(dest.arr[i], env) # following may be other custom "hooks" as required... @@ -265,7 +266,7 @@ Move semantics A "move" can be regarded as an optimized copy operation. If the source of the copy operation is not used afterward, the copy can be replaced by a move. This document uses the notation `lastReadOf(x)` to describe that `x` is not -used afterwards. This property is computed by a static control flow analysis +used afterward. This property is computed by a static control flow analysis but can also be enforced by using `system.move` explicitly. @@ -601,7 +602,7 @@ a form of copy elision. To see how and when we can do that, think about this question: In `dest = src` when do we really have to *materialize* the full copy? - Only if `dest` or `src` are mutated -afterwards. If `dest` is a local variable that is simple to analyze. And if `src` is a +afterward. If `dest` is a local variable that is simple to analyze. And if `src` is a location derived from a formal parameter, we also know it is not mutated! In other words, we do a compile-time copy-on-write analysis. From c38ab3e257fbb08622f9ec6f0068a0fd3a5d82d7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Sep 2021 12:09:42 +0200 Subject: [PATCH 3038/4254] fixes #18921 [backport] (#18930) --- compiler/commands.nim | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 9b7e35791..a8caad916 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -482,18 +482,20 @@ proc setCommandEarly*(conf: ConfigRef, command: string) = else: conf.foreignPackageNotes = foreignPackageNotesDefault -proc specialDefine(conf: ConfigRef, key: string) = +proc specialDefine(conf: ConfigRef, key: string; pass: TCmdLinePass) = # Keep this syncronized with the default config/nim.cfg! if cmpIgnoreStyle(key, "nimQuirky") == 0: conf.exc = excQuirky elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0: - conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize} - conf.globalOptions.excl {optExcessiveStackTrace, optCDebug} - conf.options.incl optOptimizeSpeed + if pass in {passCmd1, passPP}: + conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize} + conf.globalOptions.excl {optExcessiveStackTrace, optCDebug} + conf.options.incl optOptimizeSpeed if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0: - conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, - optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir} - conf.globalOptions.excl {optCDebug} + if pass in {passCmd1, passPP}: + conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, + optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir} + conf.globalOptions.excl {optCDebug} proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = @@ -565,10 +567,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectArg(conf, switch, arg, pass, info) if {':', '='} in arg: splitSwitch(conf, arg, key, val, pass, info) - specialDefine(conf, key) + specialDefine(conf, key, pass) defineSymbol(conf.symbols, key, val) else: - specialDefine(conf, arg) + specialDefine(conf, arg, pass) defineSymbol(conf.symbols, arg) of "undef", "u": expectArg(conf, switch, arg, pass, info) From f915b3aa86929d87e162b6ddd7589e6337a30397 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Thu, 30 Sep 2021 08:55:43 -0600 Subject: [PATCH 3039/4254] Alternative to #18928 (#18931) * fixed #18841 * Added test --- compiler/semtypinst.nim | 12 +++---- tests/generics/trecursivegenerics.nim | 52 ++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 2ca355e7d..0bb53e04d 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -344,11 +344,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = x = lookupTypeVar(cl, x) if x != nil: if header == t: header = instCopyType(cl, t) - header[i] = - if x.kind == tyGenericInst: - t[i] - else: - x + header[i] = x propagateToOwner(header, x) else: propagateToOwner(header, x) @@ -382,7 +378,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = cl.typeMap = newTypeMapLayer(cl) for i in 1.. Date: Thu, 30 Sep 2021 22:57:06 +0800 Subject: [PATCH 3040/4254] alternative to #18918 (#18927) * fix #16558 * add testcase --- compiler/semexprs.nim | 2 ++ tests/arc/t16558.nim | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/arc/t16558.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9134c1301..342b8b05f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -217,6 +217,8 @@ proc isCastable(c: PContext; dst, src: PType): bool = let s = skipTypes(src, abstractInst) if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal: return false + elif d.kind in IntegralTypes and s.kind in {tyString, tySequence}: + return false var dstSize, srcSize: BiggestInt dstSize = computeSize(conf, dst) diff --git a/tests/arc/t16558.nim b/tests/arc/t16558.nim new file mode 100644 index 000000000..7b6eb4669 --- /dev/null +++ b/tests/arc/t16558.nim @@ -0,0 +1,9 @@ +discard """ + matrix: "--gc:arc" + errormsg: "expression cannot be cast to int" +""" + +block: # bug #16558 + var value = "hi there" + var keepInt: int + keepInt = cast[int](value) From 4b764f4c7cff02b1f698d90d4605ae8fa85c3ee6 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 1 Oct 2021 16:19:02 +0800 Subject: [PATCH 3041/4254] close #17319; add testcase (#18934) --- tests/arc/tarcmisc.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 7daea62c8..d259e1197 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -463,3 +463,22 @@ proc putValue[T](n: T) = echo b.n useForward() + + +# bug #17319 +type + BrokenObject = ref object + brokenType: seq[int] + +proc use(obj: BrokenObject) = + discard + +method testMethod(self: BrokenObject) {.base.} = + iterator testMethodIter() {.closure.} = + use(self) + + var nameIterVar = testMethodIter + nameIterVar() + +let mikasa = BrokenObject() +mikasa.testMethod() From 2aeac26f088c5170f7f0c4d8e73d099a32e8895a Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 1 Oct 2021 19:57:06 +0800 Subject: [PATCH 3042/4254] correct licence header (#18935) * rename licence * spaces --- lib/pure/lexbase.nim | 2 +- lib/std/compilesettings.nim | 2 +- lib/std/setutils.nim | 2 +- lib/std/sha1.nim | 2 +- lib/std/strbasics.nim | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index 166d8286b..bbc0a38ae 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -1,6 +1,6 @@ # # -# The Nim Compiler +# Nim's Runtime Library # (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim index e1ffc954a..5bb0bd673 100644 --- a/lib/std/compilesettings.nim +++ b/lib/std/compilesettings.nim @@ -1,6 +1,6 @@ # # -# The Nim Compiler +# Nim's Runtime Library # (c) Copyright 2020 Nim Contributors # # See the file "copying.txt", included in this diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index 84cc93623..4664d6dcc 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -1,6 +1,6 @@ # # -# The Nim Compiler +# Nim's Runtime Library # (c) Copyright 2020 Nim Contributors # # See the file "copying.txt", included in this diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 3cc8a0249..120a81702 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -1,6 +1,6 @@ # # -# The Nim Compiler +# Nim's Runtime Library # (c) Copyright 2015 Nim Contributors # # See the file "copying.txt", included in this diff --git a/lib/std/strbasics.nim b/lib/std/strbasics.nim index 9232204ab..0d4c96f44 100644 --- a/lib/std/strbasics.nim +++ b/lib/std/strbasics.nim @@ -1,6 +1,6 @@ # # -# The Nim Compiler +# Nim's Runtime Library # (c) Copyright 2021 Nim Contributors # # See the file "copying.txt", included in this From 7577ea9e4ce4d9966edc1f1cc27bde1b2ec9f369 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 2 Oct 2021 02:14:10 +0800 Subject: [PATCH 3043/4254] [std/tempfiles] docs improvement (#18936) * unify comments * more --- lib/std/tempfiles.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index 26786d463..ce84c2a37 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -122,23 +122,24 @@ proc getTempDirImpl(dir: string): string {.inline.} = proc genTempPath*(prefix, suffix: string, dir = ""): string = ## Generates a path name in `dir`. ## - ## If `dir` is empty, (`getTempDir `_) will be used. ## The path begins with `prefix` and ends with `suffix`. + ## + ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir `_). let dir = getTempDirImpl(dir) result = dir / (prefix & randomPathName(nimTempPathLength) & suffix) proc createTempFile*(prefix, suffix: string, dir = ""): tuple[cfile: File, path: string] = ## Creates a new temporary file in the directory `dir`. - ## + ## ## This generates a path name using `genTempPath(prefix, suffix, dir)` and ## returns a file handle to an open file and the path of that file, possibly after ## retrying to ensure it doesn't already exist. - ## + ## ## If failing to create a temporary file, `OSError` will be raised. ## ## .. note:: It is the caller's responsibility to close `result.cfile` and ## remove `result.file` when no longer needed. - ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir()`). + ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir `_). runnableExamples: import std/os doAssertRaises(OSError): discard createTempFile("", "", "nonexistent") @@ -170,7 +171,7 @@ proc createTempDir*(prefix, suffix: string, dir = ""): string = ## If failing to create a temporary directory, `OSError` will be raised. ## ## .. note:: It is the caller's responsibility to remove the directory when no longer needed. - ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir()`). + ## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir `_). runnableExamples: import std/os doAssertRaises(OSError): discard createTempDir("", "", "nonexistent") From 5c4692fad4c807a010d58d553e92360128699197 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 2 Oct 2021 02:26:29 +0800 Subject: [PATCH 3044/4254] rename nimLegacyJsonutilsHoleyEnum [backport] (#18938) * enable nimPreviewJsonutilsHoleyEnum [backport] * docuement nimPreviewJsonutilsHoleyEnum --- changelog.md | 3 +-- lib/std/jsonutils.nim | 6 +++++- tests/config.nims | 4 +++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index ab037c328..38ace19ed 100644 --- a/changelog.md +++ b/changelog.md @@ -77,8 +77,7 @@ initialization with a small (< 30000) seed. Use `-d:nimLegacyRandomInitRand` to restore previous behavior for a transition time, see PR #17467. -- `jsonutils` now serializes/deserializes holey enums as regular enums (via `ord`) instead of as strings. - Use `-d:nimLegacyJsonutilsHoleyEnum` for a transition period. `toJson` now serializes `JsonNode` +- With `-d:nimPreviewJsonutilsHoleyEnum`, `jsonutils` now can serialize/deserialize holey enums as regular enums (via `ord`) instead of as strings. It is expected that this behavior becomes the new default in upcoming versions. `toJson` now serializes `JsonNode` as is via reference (without a deep copy) instead of treating `JsonNode` as a regular ref object, this can be customized via `jsonNodeMode`. diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 727a75288..19384b5d1 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -298,6 +298,10 @@ proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T = proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode = ## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to ## customize serialization, see strtabs.toJsonHook for an example. + ## + ## .. note:: With `-d:nimPreviewJsonutilsHoleyEnum`, `toJson` now can + ## serialize/deserialize holey enums as regular enums (via `ord`) instead of as strings. + ## It is expected that this behavior becomes the new default in upcoming versions. when compiles(toJsonHook(a)): result = toJsonHook(a) elif T is object | tuple: when T is object or isNamedTuple(T): @@ -328,7 +332,7 @@ proc toJson*[T](a: T, opt = initToJsonOptions()): JsonNode = elif T is enum: case opt.enumMode of joptEnumOrd: - when T is Ordinal or not defined(nimLegacyJsonutilsHoleyEnum): %(a.ord) + when T is Ordinal or defined(nimPreviewJsonutilsHoleyEnum): %(a.ord) else: toJson($a, opt) of joptEnumSymbol: when T is OrdinalEnum: diff --git a/tests/config.nims b/tests/config.nims index 86787db1d..ed2a1b7e9 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -30,10 +30,12 @@ hint("Processing", off) # switch("hint", "ConvFromXtoItselfNotNeeded") # switch("warningAsError", "InheritFromException") # would require fixing a few tests -# experimental API's are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 +# experimental APIs are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 # sync with `kochdocs.docDefines` or refactor. switch("define", "nimExperimentalAsyncjsThen") switch("define", "nimExperimentalLinenoiseExtra") +# preview APIs are expected to be the new default in upcoming versions switch("define", "nimPreviewFloatRoundtrip") switch("define", "nimPreviewDotLikeOps") +switch("define", "nimPreviewJsonutilsHoleyEnum") From e9268b52d9a34e7e851105d569bccced4b7261fd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 3 Oct 2021 07:21:08 +0200 Subject: [PATCH 3045/4254] with this patch :idx: can be used for the index generation for LaTeX (#18946) --- config/nimdoc.tex.cfg | 6 ++++-- lib/packages/docutils/rstgen.nim | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 75382ce26..4aff9b379 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -3,7 +3,7 @@ # (c) 2012 Andreas Rumpf # Feel free to edit the templates as you need. -split.item.toc = "20" +split.item.toc = "20" # too long entries in the table of contents wrap around # after this number of characters @@ -97,12 +97,14 @@ doc.file = """ \usepackage{parskip} % paragraphs delimited by vertical space, no indent \usepackage{graphicx} +\newcommand{\nimindexterm}[2]{#2\label{#1}} + \usepackage{dingbat} % for \carriagereturn, etc \usepackage{fvextra} % for code blocks (works better than original fancyvrb) \fvset{ breaklines, breakafter={=}:|\_\{\}[](){,}.;+-*/'", - breaksymbolleft=\color{red}{\ensuremath{\hookrightarrow}}, + breaksymbolleft=\color{red}{\ensuremath{\hookrightarrow}}, breaksymbolright=\color{red}{\small\carriagereturn} } \fvinlineset{% diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 3734392c3..7d7eb4fb8 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -406,7 +406,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = var term = "" renderAux(d, n, term) setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection) - dispA(d.target, result, "$2", "$2\\label{$1}", + dispA(d.target, result, "$2", "\\nimindexterm{$2}{$1}", [id, term]) type From 45c4332c81521224a4db90fe9bf46efc0f93aaf7 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 3 Oct 2021 13:22:53 +0800 Subject: [PATCH 3046/4254] document -d:nimStrictDelete [backport] (#18939) --- lib/system.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index 358aae938..caa036f37 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2142,6 +2142,10 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, auditDelete.} = ## ## This is an `O(n)` operation. ## + ## .. note:: With `-d:nimStrictDelete`, an index error is produced when the index passed + ## to it was out of bounds. `-d:nimStrictDelete` will become the default + ## in upcoming versions. + ## ## See also: ## * `del <#del,seq[T],Natural>`_ for O(1) operation ## From 6b0db5be1f21cec1b75822c021ccee79035a6f74 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 3 Oct 2021 06:25:15 +0100 Subject: [PATCH 3047/4254] Fixes build_all.sh failing on Nimble builds (#18945) When running `build_all.sh` I was getting: ``` bin/nim c -o:bin/nimsuggest -d:danger --skipUserCfg --skipParentCfg --hints:off nimsuggest/nimsuggest.nim bin/nim c -o:bin/nimgrep -d:release --skipUserCfg --skipParentCfg --hints:off tools/nimgrep.nim bin/nim c -o:bin/nimpretty -d:release --skipUserCfg --skipParentCfg --hints:off nimpretty/nimpretty.nim bin/nim c -o:bin/testament -d:release --skipUserCfg --skipParentCfg --hints:off testament/testament.nim bin/nim c -o:bin/nim_dbg --opt:speed --stacktrace -d:debug --stacktraceMsgs -d:nimCompilerStacktraceHints --skipUserCfg --skipParentCfg --hints:off compiler/nim.nim bin/nim c -o:bin/atlas -d:release --skipUserCfg --skipParentCfg --hints:off tools/atlas/atlas.nim /home/dom/.choosenim/toolchains/nim-#devel/koch.nim(722) koch /home/dom/.choosenim/toolchains/nim-#devel/koch.nim(149) bundleNimbleExe /home/dom/.choosenim/toolchains/nim-#devel/tools/deps.nim(32) cloneDependency /home/dom/.choosenim/toolchains/nim-#devel/lib/pure/os.nim(1438) setCurrentDir /home/dom/.choosenim/toolchains/nim-#devel/lib/pure/includes/oserr.nim(95) raiseOSError Error: unhandled exception: No such file or directory Additional info: '/home/dom/.choosenim/toolchains/nim-#devel/dist/nimble' [OSError] ``` With this patch it builds. --- tools/deps.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/deps.nim b/tools/deps.nim index 95b2916a1..59872070d 100644 --- a/tools/deps.nim +++ b/tools/deps.nim @@ -22,14 +22,14 @@ proc cloneDependency*(destDirBase: string, url: string, commit = commitHead, let name = p.splitFile.name var destDir = destDirBase if appendRepoName: destDir = destDir / name - let destDir2 = destDir.quoteShell + let quotedDestDir = destDir.quoteShell if not dirExists(destDir): # note: old code used `destDir / .git` but that wouldn't prevent git clone # from failing - execRetry fmt"git clone -q {url} {destDir2}" + execRetry fmt"git clone -q {url} {quotedDestDir}" if isGitRepo(destDir): let oldDir = getCurrentDir() - setCurrentDir(destDir2) + setCurrentDir(destDir) try: execRetry "git fetch -q" exec fmt"git checkout -q {commit}" From 97c24dd54892a1f256707bc73230fe5443be36ce Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 4 Oct 2021 15:19:20 +0800 Subject: [PATCH 3048/4254] correct changelog [backport] (#18940) --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 38ace19ed..f8dc9087c 100644 --- a/changelog.md +++ b/changelog.md @@ -103,7 +103,7 @@ - In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. -- With `-d:nimPreviewDotLikeOps` (default in devel), dot-like operators (operators starting with `.`, but not with `..`) +- With `-d:nimPreviewDotLikeOps`, dot-like operators (operators starting with `.`, but not with `..`) now have the same precedence as `.`, so that `a.?b.c` is now parsed as `(a.?b).c` instead of `a.?(b.c)`. A warning is generated when a dot-like operator is used without `-d:nimPreviewDotLikeOps`. From 500d5f0f38dc59895908f25f2c43c2a4c61d7874 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Oct 2021 12:34:29 +0200 Subject: [PATCH 3049/4254] typo [backport] (#18948) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index dfcf0ba54..4b212fe19 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1201,7 +1201,7 @@ The only operations that are affected by the `floatChecks` pragma are the `+`, `-`, `*`, `/` operators for floating-point types. An implementation should always use the maximum precision available to evaluate -floating pointer values during semantic analysis; this means expressions like +floating-point values during semantic analysis; this means expressions like `0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64` that are evaluating during constant folding are true. From f017eadc97b041e678196cb2b72c3c66767e7ab0 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Mon, 4 Oct 2021 15:27:13 -0400 Subject: [PATCH 3050/4254] Add support for `strictEffects` to `std/pegs` (#18949) * Add support for `strictEffects` to `std/pegs` * Fixed support of older Nim versions Co-authored-by: quantimnot --- lib/pure/pegs.nim | 5 ++++- tests/stdlib/tpegs.nim | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index b6b05cdc1..11270e34c 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1285,9 +1285,12 @@ proc parallelReplace*(s: string, subs: varargs[ # copy the rest: add(result, substr(s, i)) +when not defined(nimHasEffectsOf): + {.pragma: effectsOf.} + proc replace*(s: string, sub: Peg, cb: proc( match: int, cnt: int, caps: openArray[string]): string): string {. - rtl, extern: "npegs$1cb".} = + rtl, extern: "npegs$1cb", effectsOf: cb.} = ## Replaces `sub` in `s` by the resulting strings from the callback. ## The callback proc receives the index of the current match (starting with 0), ## the count of captures and an open array with the captures of each match. Examples: diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index 1261d55b8..c3d8942cf 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -51,6 +51,9 @@ Event parser output ''' """ +when defined(nimHasEffectsOf): + {.experimental: "strictEffects".} + import std/[strutils, streams, pegs] const From e7bac9177335c75b4eeed18ec5f8a0b0489c0561 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 5 Oct 2021 03:28:13 +0800 Subject: [PATCH 3051/4254] rename nimEnableHashRef [backport] (#18941) * rename nimEnableHashRef [backport] * Apply suggestions from code review Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 3 ++- lib/pure/hashes.nim | 18 +++++++++++++----- tests/collections/ttables.nim | 1 - tests/config.nims | 1 + tests/stdlib/thashes.nim | 1 - 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/changelog.md b/changelog.md index f8dc9087c..1925878bf 100644 --- a/changelog.md +++ b/changelog.md @@ -64,7 +64,8 @@ for previous behavior. - `hashes.hash` can now support `object` and `ref` (can be overloaded in user code), - if `-d:nimEnableHashRef` is used. + if `-d:nimPreviewHashRef` is used. It is expected that this behavior + becomes the new default in upcoming versions. - `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, `hashes.hash(closure)` has also been improved. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 1c49b0317..d9f534670 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -51,8 +51,12 @@ runnableExamples: h = h !& hash(x.bar) result = !$h -## **Note:** If the type has a `==` operator, the following must hold: -## If two values compare equal, their hashes must also be equal. +## .. important:: Use `-d:nimPreviewHashRef` to +## enable hashing `ref`s. It is expected that this behavior +## becomes the new default in upcoming versions. +## +## .. note:: If the type has a `==` operator, the following must hold: +## If two values compare equal, their hashes must also be equal. ## ## See also ## ======== @@ -236,10 +240,14 @@ proc hash*[T](x: ptr[T]): Hash {.inline.} = assert cast[pointer](a[0].addr).hash == a[0].addr.hash hash(cast[pointer](x)) -when defined(nimEnableHashRef): +when defined(nimPreviewHashRef) or defined(nimdoc): proc hash*[T](x: ref[T]): Hash {.inline.} = ## Efficient `hash` overload. - runnableExamples: + ## + ## .. important:: Use `-d:nimPreviewHashRef` to + ## enable hashing `ref`s. It is expected that this behavior + ## becomes the new default in upcoming versions. + runnableExamples("-d:nimPreviewHashRef"): type A = ref object x: int let a = A(x: 3) @@ -247,7 +255,7 @@ when defined(nimEnableHashRef): assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`. a.x = 4 assert ha == a.hash # the hash only depends on the address - runnableExamples: + runnableExamples("-d:nimPreviewHashRef"): # you can overload `hash` if you want to customize semantics type A[T] = ref object x, y: T diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 751509062..638f4241b 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -8,7 +8,6 @@ And we get here ''' joinable: false targets: "c cpp js" -matrix: "-d:nimEnableHashRef" """ # xxx wrap in a template to test in VM, see https://github.com/timotheecour/Nim/issues/534#issuecomment-769565033 diff --git a/tests/config.nims b/tests/config.nims index ed2a1b7e9..894c4bea0 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -39,3 +39,4 @@ switch("define", "nimExperimentalLinenoiseExtra") switch("define", "nimPreviewFloatRoundtrip") switch("define", "nimPreviewDotLikeOps") switch("define", "nimPreviewJsonutilsHoleyEnum") +switch("define", "nimPreviewHashRef") diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 1e9b02d0c..46576ef12 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,6 +1,5 @@ discard """ targets: "c cpp js" - matrix: "-d:nimEnableHashRef" """ import std/hashes From f1f1e85ec673b9ea2ea5d3a97aa27993be153602 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 5 Oct 2021 12:29:59 +0200 Subject: [PATCH 3052/4254] fixes #18954 (#18955) --- lib/pure/sugar.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index f82e1706f..d7beef8d9 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -121,9 +121,9 @@ macro `=>`*(p, b: untyped): untyped = else: error("Incorrect procedure parameter.", c) params.add(identDefs) - of nnkIdent: + of nnkIdent, nnkOpenSymChoice, nnkClosedSymChoice, nnkSym: var identDefs = newNimNode(nnkIdentDefs) - identDefs.add(p) + identDefs.add(ident $p) identDefs.add(ident"auto") identDefs.add(newEmptyNode()) params.add(identDefs) From 9fc2918314a75fd1923af049966e4c4e9d8cf710 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Wed, 6 Oct 2021 03:41:42 -0400 Subject: [PATCH 3053/4254] Document how to compile a reproducible build (#18953) * Make compiler build more reproducible Removed the compile time from the version output. Added Git commit's author's datetime in UTC timezone. Fixes #18508 See https://reproducible-builds.org/docs/timestamps/ See https://reproducible-builds.org/docs/source-date-epoch/ * Revert "Make compiler build more reproducible" This reverts commit 2f9359ae89622c2d95ef243d13251a310e94a199. Documented how to use compile reproducible builds with the `SOURCE_DATE_EPOCH` environment variable. * Corrected `readme.md` formatting Co-authored-by: quantimnot --- doc/intern.rst | 11 +++++++++++ doc/packaging.rst | 4 ++++ readme.md | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/intern.rst b/doc/intern.rst index ab74c4a3a..fe0d333fd 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -68,6 +68,17 @@ More information about its options can be found in the `koch `_ documentation. +Reproducible builds +------------------- + +Set the compilation timestamp with the `SOURCE_DATE_EPOCH` environment variable. + +.. code:: cmd + + export SOURCE_DATE_EPOCH=$(git log -n 1 --format=%at) + koch boot # or `./build_all.sh` + + Developing the compiler ======================= diff --git a/doc/packaging.rst b/doc/packaging.rst index fcdc4ae04..7976dfe92 100644 --- a/doc/packaging.rst +++ b/doc/packaging.rst @@ -6,6 +6,9 @@ This page provide hints on distributing Nim using OS packages. See `distros `_ for tools to detect Linux distribution at runtime. +See `here `_ for how to +compile reproducible builds. + Supported architectures ----------------------- @@ -71,3 +74,4 @@ What to install: - Optionally: manpages, documentation, shell completion - When installing documentation, .idx files are not required - The "compiler" directory contains compiler sources and should not be part of the compiler binary package + diff --git a/readme.md b/readme.md index b28c25ec1..7f333d5d4 100644 --- a/readme.md +++ b/readme.md @@ -71,7 +71,6 @@ the installation instructions on the website to do so: https://nim-lang.org/inst For package maintainers: see [packaging guidelines](https://nim-lang.github.io/Nim/packaging.html). - First, get Nim from github: ``` @@ -89,6 +88,8 @@ should add the ``bin`` directory to your PATH. See also [rebuilding the compiler](doc/intern.rst#rebuilding-the-compiler). +See also [reproducible builds](doc/intern.rst#reproducible-builds). + ## Koch ``koch`` is the build tool used to build various parts of Nim and to generate From cb30dc51701f0d4bc5dedc2615de68e4c1e5ba71 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 6 Oct 2021 15:42:35 +0800 Subject: [PATCH 3054/4254] enable tests for #2710 (#18961) --- tests/metatype/ttypedesc3.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim index b691d3488..98a59f613 100644 --- a/tests/metatype/ttypedesc3.nim +++ b/tests/metatype/ttypedesc3.nim @@ -3,6 +3,7 @@ output: ''' proc Base proc Child method Base +method Child yield Base yield Child 12 @@ -24,8 +25,7 @@ Base.pr Child.pr Base.me -when false: - Child.me #<- bug #2710 +Child.me #<- bug #2710 for s in Base.it: echo s for s in Child.it: echo s #<- bug #2662 From b2873f0f63f7741ee995363a6bb225a228d03d18 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 6 Oct 2021 18:47:46 +0800 Subject: [PATCH 3055/4254] [tools] use the right parameter [backport:1.0] (#18957) --- tools/finish.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/finish.nim b/tools/finish.nim index 4b5131045..69838829c 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -41,7 +41,7 @@ proc downloadMingw(): DownloadResult = let curl = findExe"curl" var cmd: string if curl.len > 0: - cmd = quoteShell(curl) & " --out " & "dist" / mingw & " " & url + cmd = quoteShell(curl) & " --output " & "dist" / mingw & " " & url elif fileExists"bin/nimgrab.exe": cmd = r"bin\nimgrab.exe " & url & " dist" / mingw if cmd.len > 0: From f03872d99ec2d25de829415a75162f9d8297bb19 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Wed, 6 Oct 2021 14:53:01 +0300 Subject: [PATCH 3056/4254] rst: minor fixes (#18960) --- lib/packages/docutils/rst.nim | 1 + lib/packages/docutils/rstast.nim | 4 ++-- lib/packages/docutils/rstgen.nim | 2 +- tests/stdlib/trst.nim | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index abea026dd..29234f28b 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -172,6 +172,7 @@ ## ``header``, ``footer``, ``meta``, ``class`` ## - no ``role`` directives and no custom interpreted text roles ## - some standard roles are not supported (check `RST roles list`_) +## - no generic admonition support ## * inline markup ## - no simple-inline-markup ## - no embedded aliases diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index fa0620f44..e1ed7c099 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -381,7 +381,7 @@ proc renderRstToText*(node: PRstNode): string = result.add renderRstToText(node.sons[i]) if node.kind in code: result.add "`" -proc renderRstToStr*(node: PRstNode, indent=0): string = +proc treeRepr*(node: PRstNode, indent=0): string = ## Writes the parsed RST `node` into an AST tree with compact string ## representation in the format (one line per every sub-node): ## ``indent - kind - [text|level|order|adType] - anchor (if non-zero)`` @@ -411,4 +411,4 @@ proc renderRstToStr*(node: PRstNode, indent=0): string = result.add (if node.anchor == "": "" else: " anchor='" & node.anchor & "'") result.add "\n" for son in node.sons: - result.add renderRstToStr(son, indent=indent+2) + result.add treeRepr(son, indent=indent+2) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 7d7eb4fb8..8eac37307 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1164,7 +1164,7 @@ proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) = case n.adType of "hint", "note", "tip": htmlCls = "admonition-info"; texSz = "\\normalsize"; texColor = "green" - of "attention", "admonition", "important", "warning": + of "attention", "admonition", "important", "warning", "caution": htmlCls = "admonition-warning"; texSz = "\\large"; texColor = "orange" of "danger", "error": htmlCls = "admonition-error"; texSz = "\\Large"; texColor = "red" diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index bc11f219c..e9f67324c 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -55,7 +55,7 @@ proc toAst(input: string, var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit, rstOptions, myFindFile, testMsgHandler) - result = renderRstToStr(rst) + result = treeRepr(rst) except EParseError as e: if e.msg != "": result = e.msg From eede2bfb5de30f7f411d9437e19f253f8dac629b Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 7 Oct 2021 10:48:09 +0200 Subject: [PATCH 3057/4254] update csources hash (#18969) --- config/build_config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/build_config.txt b/config/build_config.txt index aee15e695..15f44bb57 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -2,4 +2,4 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" nim_csourcesDir=csources_v1 nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git nim_csourcesBranch=master -nim_csourcesHash=5e9be0383f842c9c22ae86e41946a896c43e95d0 +nim_csourcesHash=561b417c65791cd8356b5f73620914ceff845d10 From 8eef55715725a9dba2ff0afbdbb564383f3a29a6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 7 Oct 2021 12:01:06 +0200 Subject: [PATCH 3058/4254] fixes a 'mixin' statement handling regression [backport:1.2] (#18968) --- compiler/semtempl.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index eda4ca6cc..c10917bcb 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -110,9 +110,14 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode = proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode = result = copyNode(n) + var count = 0 for i in 0.. Date: Thu, 7 Oct 2021 18:01:27 +0800 Subject: [PATCH 3059/4254] typo [backport] (#18967) --- lib/pure/strscans.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 291af7408..99442075a 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -35,7 +35,7 @@ substrings starting with ``$``. These constructions are available: ``$o`` Matches an octal integer. This uses ``parseutils.parseOct``. ``$i`` Matches a decimal integer. This uses ``parseutils.parseInt``. ``$h`` Matches a hex integer. This uses ``parseutils.parseHex``. -``$f`` Matches a floating pointer number. Uses ``parseFloat``. +``$f`` Matches a floating-point number. Uses ``parseFloat``. ``$w`` Matches an ASCII identifier: ``[A-Za-z_][A-Za-z_0-9]*``. ``$c`` Matches a single ASCII character. ``$s`` Skips optional whitespace. From 19774a72e7fcc7c5b7649bb956b149362c05ea15 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Thu, 7 Oct 2021 06:16:58 -0400 Subject: [PATCH 3060/4254] Fixed `strictFuncs` support for `std/pegs` (#18951) * Fixed `strictFuncs` support for `std/pegs` Enabled `std/pegs` in the `strictFuncs` import test. Fixes #18057 Fixes #16892 See #18111 * Rebased from `devel` * Conditionally compile `std/pegs` in `koch` This is for supporting `csources` bootstrap. Co-authored-by: quantimnot --- lib/pure/pegs.nim | 280 ++++++++++++------------ tests/effects/tstrict_funcs_imports.nim | 2 +- tools/kochdocs.nim | 11 +- 3 files changed, 151 insertions(+), 142 deletions(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 11270e34c..bac8b1a0e 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -87,26 +87,26 @@ type else: sons: seq[Peg] NonTerminal* = ref NonTerminalObj -proc kind*(p: Peg): PegKind = p.kind +func kind*(p: Peg): PegKind = p.kind ## Returns the *PegKind* of a given *Peg* object. -proc term*(p: Peg): string = p.term +func term*(p: Peg): string = p.term ## Returns the *string* representation of a given *Peg* variant object ## where present. -proc ch*(p: Peg): char = p.ch +func ch*(p: Peg): char = p.ch ## Returns the *char* representation of a given *Peg* variant object ## where present. -proc charChoice*(p: Peg): ref set[char] = p.charChoice +func charChoice*(p: Peg): ref set[char] = p.charChoice ## Returns the *charChoice* field of a given *Peg* variant object ## where present. -proc nt*(p: Peg): NonTerminal = p.nt +func nt*(p: Peg): NonTerminal = p.nt ## Returns the *NonTerminal* object of a given *Peg* variant object ## where present. -proc index*(p: Peg): range[-MaxSubpatterns..MaxSubpatterns-1] = p.index +func index*(p: Peg): range[-MaxSubpatterns..MaxSubpatterns-1] = p.index ## Returns the back-reference index of a captured sub-pattern in the ## *Captures* object for a given *Peg* variant object where present. @@ -120,59 +120,59 @@ iterator pairs*(p: Peg): (int, Peg) {.inline.} = for i in 0 ..< p.sons.len: yield (i, p.sons[i]) -proc name*(nt: NonTerminal): string = nt.name +func name*(nt: NonTerminal): string = nt.name ## Gets the name of the symbol represented by the parent *Peg* object variant ## of a given *NonTerminal*. -proc line*(nt: NonTerminal): int = nt.line +func line*(nt: NonTerminal): int = nt.line ## Gets the line number of the definition of the parent *Peg* object variant ## of a given *NonTerminal*. -proc col*(nt: NonTerminal): int = nt.col +func col*(nt: NonTerminal): int = nt.col ## Gets the column number of the definition of the parent *Peg* object variant ## of a given *NonTerminal*. -proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags +func flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags ## Gets the *NonTerminalFlag*-typed flags field of the parent *Peg* variant ## object of a given *NonTerminal*. -proc rule*(nt: NonTerminal): Peg = nt.rule +func rule*(nt: NonTerminal): Peg = nt.rule ## Gets the *Peg* object representing the rule definition of the parent *Peg* ## object variant of a given *NonTerminal*. -proc term*(t: string): Peg {.noSideEffect, rtl, extern: "npegs$1Str".} = +func term*(t: string): Peg {.rtl, extern: "npegs$1Str".} = ## constructs a PEG from a terminal string if t.len != 1: result = Peg(kind: pkTerminal, term: t) else: result = Peg(kind: pkChar, ch: t[0]) -proc termIgnoreCase*(t: string): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func termIgnoreCase*(t: string): Peg {. + rtl, extern: "npegs$1".} = ## constructs a PEG from a terminal string; ignore case for matching result = Peg(kind: pkTerminalIgnoreCase, term: t) -proc termIgnoreStyle*(t: string): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func termIgnoreStyle*(t: string): Peg {. + rtl, extern: "npegs$1".} = ## constructs a PEG from a terminal string; ignore style for matching result = Peg(kind: pkTerminalIgnoreStyle, term: t) -proc term*(t: char): Peg {.noSideEffect, rtl, extern: "npegs$1Char".} = +func term*(t: char): Peg {.rtl, extern: "npegs$1Char".} = ## constructs a PEG from a terminal char assert t != '\0' result = Peg(kind: pkChar, ch: t) -proc charSet*(s: set[char]): Peg {.noSideEffect, rtl, extern: "npegs$1".} = +func charSet*(s: set[char]): Peg {.rtl, extern: "npegs$1".} = ## constructs a PEG from a character set `s` assert '\0' notin s result = Peg(kind: pkCharChoice) new(result.charChoice) result.charChoice[] = s -proc len(a: Peg): int {.inline.} = return a.sons.len -proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s) +func len(a: Peg): int {.inline.} = return a.sons.len +func add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s) -proc addChoice(dest: var Peg, elem: Peg) = +func addChoice(dest: var Peg, elem: Peg) = var L = dest.len-1 if L >= 0 and dest.sons[L].kind == pkCharChoice: # caution! Do not introduce false aliasing here! @@ -195,12 +195,12 @@ template multipleOp(k: PegKind, localOpt: untyped) = if result.len == 1: result = result.sons[0] -proc `/`*(a: varargs[Peg]): Peg {. - noSideEffect, rtl, extern: "npegsOrderedChoice".} = +func `/`*(a: varargs[Peg]): Peg {. + rtl, extern: "npegsOrderedChoice".} = ## constructs an ordered choice with the PEGs in `a` multipleOp(pkOrderedChoice, addChoice) -proc addSequence(dest: var Peg, elem: Peg) = +func addSequence(dest: var Peg, elem: Peg) = var L = dest.len-1 if L >= 0 and dest.sons[L].kind == pkTerminal: # caution! Do not introduce false aliasing here! @@ -212,12 +212,12 @@ proc addSequence(dest: var Peg, elem: Peg) = else: add(dest, elem) else: add(dest, elem) -proc sequence*(a: varargs[Peg]): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func sequence*(a: varargs[Peg]): Peg {. + rtl, extern: "npegs$1".} = ## constructs a sequence with all the PEGs from `a` multipleOp(pkSequence, addSequence) -proc `?`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsOptional".} = +func `?`*(a: Peg): Peg {.rtl, extern: "npegsOptional".} = ## constructs an optional for the PEG `a` if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar, pkGreedyRepSet}: @@ -227,7 +227,7 @@ proc `?`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsOptional".} = else: result = Peg(kind: pkOption, sons: @[a]) -proc `*`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsGreedyRep".} = +func `*`*(a: Peg): Peg {.rtl, extern: "npegsGreedyRep".} = ## constructs a "greedy repetition" for the PEG `a` case a.kind of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption: @@ -242,94 +242,94 @@ proc `*`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsGreedyRep".} = else: result = Peg(kind: pkGreedyRep, sons: @[a]) -proc `!*`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsSearch".} = +func `!*`*(a: Peg): Peg {.rtl, extern: "npegsSearch".} = ## constructs a "search" for the PEG `a` result = Peg(kind: pkSearch, sons: @[a]) -proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl, +func `!*\`*(a: Peg): Peg {.rtl, extern: "npgegsCapturedSearch".} = ## constructs a "captured search" for the PEG `a` result = Peg(kind: pkCapturedSearch, sons: @[a]) -proc `+`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsGreedyPosRep".} = +func `+`*(a: Peg): Peg {.rtl, extern: "npegsGreedyPosRep".} = ## constructs a "greedy positive repetition" with the PEG `a` return sequence(a, *a) -proc `&`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsAndPredicate".} = +func `&`*(a: Peg): Peg {.rtl, extern: "npegsAndPredicate".} = ## constructs an "and predicate" with the PEG `a` result = Peg(kind: pkAndPredicate, sons: @[a]) -proc `!`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npegsNotPredicate".} = +func `!`*(a: Peg): Peg {.rtl, extern: "npegsNotPredicate".} = ## constructs a "not predicate" with the PEG `a` result = Peg(kind: pkNotPredicate, sons: @[a]) -proc any*: Peg {.inline.} = +func any*: Peg {.inline.} = ## constructs the PEG `any character`:idx: (``.``) result = Peg(kind: pkAny) -proc anyRune*: Peg {.inline.} = +func anyRune*: Peg {.inline.} = ## constructs the PEG `any rune`:idx: (``_``) result = Peg(kind: pkAnyRune) -proc newLine*: Peg {.inline.} = +func newLine*: Peg {.inline.} = ## constructs the PEG `newline`:idx: (``\n``) result = Peg(kind: pkNewLine) -proc unicodeLetter*: Peg {.inline.} = +func unicodeLetter*: Peg {.inline.} = ## constructs the PEG ``\letter`` which matches any Unicode letter. result = Peg(kind: pkLetter) -proc unicodeLower*: Peg {.inline.} = +func unicodeLower*: Peg {.inline.} = ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. result = Peg(kind: pkLower) -proc unicodeUpper*: Peg {.inline.} = +func unicodeUpper*: Peg {.inline.} = ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter. result = Peg(kind: pkUpper) -proc unicodeTitle*: Peg {.inline.} = +func unicodeTitle*: Peg {.inline.} = ## constructs the PEG ``\title`` which matches any Unicode title letter. result = Peg(kind: pkTitle) -proc unicodeWhitespace*: Peg {.inline.} = +func unicodeWhitespace*: Peg {.inline.} = ## constructs the PEG ``\white`` which matches any Unicode ## whitespace character. result = Peg(kind: pkWhitespace) -proc startAnchor*: Peg {.inline.} = +func startAnchor*: Peg {.inline.} = ## constructs the PEG ``^`` which matches the start of the input. result = Peg(kind: pkStartAnchor) -proc endAnchor*: Peg {.inline.} = +func endAnchor*: Peg {.inline.} = ## constructs the PEG ``$`` which matches the end of the input. result = !any() -proc capture*(a: Peg = Peg(kind: pkEmpty)): Peg {.noSideEffect, rtl, extern: "npegsCapture".} = +func capture*(a: Peg = Peg(kind: pkEmpty)): Peg {.rtl, extern: "npegsCapture".} = ## constructs a capture with the PEG `a` result = Peg(kind: pkCapture, sons: @[a]) -proc backref*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func backref*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. + rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting ## from 1. `reverse` specifies wether indexing starts from the end of the ## capture list. result = Peg(kind: pkBackRef, index: (if reverse: -index else: index - 1)) -proc backrefIgnoreCase*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func backrefIgnoreCase*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. + rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting ## from 1. `reverse` specifies wether indexing starts from the end of the ## capture list. Ignores case for matching. result = Peg(kind: pkBackRefIgnoreCase, index: (if reverse: -index else: index - 1)) -proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func backrefIgnoreStyle*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. + rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting ## from 1. `reverse` specifies wether indexing starts from the end of the ## capture list. Ignores style for matching. result = Peg(kind: pkBackRefIgnoreStyle, index: (if reverse: -index else: index - 1)) -proc spaceCost(n: Peg): int = +func spaceCost(n: Peg): int = case n.kind of pkEmpty: discard of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, @@ -344,8 +344,8 @@ proc spaceCost(n: Peg): int = inc(result, spaceCost(n.sons[i])) if result >= InlineThreshold: break -proc nonterminal*(n: NonTerminal): Peg {. - noSideEffect, rtl, extern: "npegs$1".} = +func nonterminal*(n: NonTerminal): Peg {. + rtl, extern: "npegs$1".} = ## constructs a PEG that consists of the nonterminal symbol assert n != nil if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold: @@ -354,8 +354,8 @@ proc nonterminal*(n: NonTerminal): Peg {. else: result = Peg(kind: pkNonTerminal, nt: n) -proc newNonTerminal*(name: string, line, column: int): NonTerminal {. - noSideEffect, rtl, extern: "npegs$1".} = +func newNonTerminal*(name: string, line, column: int): NonTerminal {. + rtl, extern: "npegs$1".} = ## constructs a nonterminal symbol result = NonTerminal(name: name, line: line, col: column) @@ -390,7 +390,7 @@ template natural*: Peg = # ------------------------- debugging ----------------------------------------- -proc esc(c: char, reserved = {'\0'..'\255'}): string = +func esc(c: char, reserved = {'\0'..'\255'}): string = case c of '\b': result = "\\b" of '\t': result = "\\t" @@ -406,14 +406,14 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string = elif c in reserved: result = '\\' & c else: result = $c -proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" +func singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" -proc singleQuoteEsc(str: string): string = +func singleQuoteEsc(str: string): string = result = "'" for c in items(str): add result, esc(c, {'\''}) add result, '\'' -proc charSetEscAux(cc: set[char]): string = +func charSetEscAux(cc: set[char]): string = const reserved = {'^', '-', ']'} result = "" var c1 = 0 @@ -430,13 +430,13 @@ proc charSetEscAux(cc: set[char]): string = c1 = c2 inc(c1) -proc charSetEsc(cc: set[char]): string = +func charSetEsc(cc: set[char]): string = if card(cc) >= 128+64: result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']' else: result = '[' & charSetEscAux(cc) & ']' -proc toStrAux(r: Peg, res: var string) = +func toStrAux(r: Peg, res: var string) = case r.kind of pkEmpty: add(res, "()") of pkAny: add(res, '.') @@ -522,7 +522,7 @@ proc toStrAux(r: Peg, res: var string) = of pkStartAnchor: add(res, '^') -proc `$` *(r: Peg): string {.noSideEffect, rtl, extern: "npegsToString".} = +func `$` *(r: Peg): string {.rtl, extern: "npegsToString".} = ## converts a PEG to its string representation result = "" toStrAux(r, result) @@ -535,7 +535,7 @@ type ml: int origStart: int -proc bounds*(c: Captures, +func bounds*(c: Captures, i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = ## returns the bounds ``[first..last]`` of the `i`'th capture. result = c.matches[i] @@ -548,11 +548,11 @@ when not useUnicode: inc(i) template runeLenAt(s, i): untyped = 1 - proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z', 'A'..'Z'} - proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} - proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'} - proc isTitle(a: char): bool {.inline.} = return false - proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} + func isAlpha(a: char): bool {.inline.} = return a in {'a'..'z', 'A'..'Z'} + func isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} + func isLower(a: char): bool {.inline.} = return a in {'a'..'z'} + func isTitle(a: char): bool {.inline.} = return false + func isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} template matchOrParse(mopProc: untyped) = # Used to make the main matcher proc *rawMatch* as well as event parser @@ -860,8 +860,8 @@ template matchOrParse(mopProc: untyped) = leave(pkStartAnchor, s, p, start, result) of pkRule, pkList: assert false -proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int - {.noSideEffect, rtl, extern: "npegs$1".} = +func rawMatch*(s: string, p: Peg, start: int, c: var Captures): int + {.rtl, extern: "npegs$1".} = ## low-level matching proc that implements the PEG interpreter. Use this ## for maximum efficiency (every other PEG operation ends up calling this ## proc). @@ -873,7 +873,11 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int template leave(pk, s, p, start, length) = discard matchOrParse(matchIt) - result = matchIt(s, p, start, c) + {.cast(noSideEffect).}: + # This cast is allowed because the `matchOrParse` template is used for + # both matching and parsing, but side effects are only possible when it's + # used by `eventParser`. + result = matchIt(s, p, start, c) macro mkHandlerTplts(handlers: untyped): untyped = # Transforms the handler spec in *handlers* into handler templates. @@ -900,7 +904,7 @@ macro mkHandlerTplts(handlers: untyped): untyped = # StmtList # # ... - proc mkEnter(hdName, body: NimNode): NimNode = + func mkEnter(hdName, body: NimNode): NimNode = template helper(hdName, body) {.dirty.} = template hdName(s, p, start) = let s {.inject.} = s @@ -1069,8 +1073,8 @@ template fillMatches(s, caps, c) = else: caps[k] = "" -proc matchLen*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): int {.noSideEffect, rtl, extern: "npegs$1Capture".} = +func matchLen*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): int {.rtl, extern: "npegs$1Capture".} = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains @@ -1080,8 +1084,8 @@ proc matchLen*(s: string, pattern: Peg, matches: var openArray[string], result = rawMatch(s, pattern, start, c) if result >= 0: fillMatches(s, matches, c) -proc matchLen*(s: string, pattern: Peg, - start = 0): int {.noSideEffect, rtl, extern: "npegs$1".} = +func matchLen*(s: string, pattern: Peg, + start = 0): int {.rtl, extern: "npegs$1".} = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains @@ -1090,22 +1094,22 @@ proc matchLen*(s: string, pattern: Peg, c.origStart = start result = rawMatch(s, pattern, start, c) -proc match*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): bool {.noSideEffect, rtl, extern: "npegs$1Capture".} = +func match*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): bool {.rtl, extern: "npegs$1Capture".} = ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and ## the captured substrings in the array ``matches``. If it does not ## match, nothing is written into ``matches`` and ``false`` is ## returned. result = matchLen(s, pattern, matches, start) != -1 -proc match*(s: string, pattern: Peg, - start = 0): bool {.noSideEffect, rtl, extern: "npegs$1".} = +func match*(s: string, pattern: Peg, + start = 0): bool {.rtl, extern: "npegs$1".} = ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``. result = matchLen(s, pattern, start) != -1 -proc find*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): int {.noSideEffect, rtl, extern: "npegs$1Capture".} = +func find*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): int {.rtl, extern: "npegs$1Capture".} = ## returns the starting position of ``pattern`` in ``s`` and the captured ## substrings in the array ``matches``. If it does not match, nothing ## is written into ``matches`` and -1 is returned. @@ -1119,9 +1123,9 @@ proc find*(s: string, pattern: Peg, matches: var openArray[string], return -1 # could also use the pattern here: (!P .)* P -proc findBounds*(s: string, pattern: Peg, matches: var openArray[string], +func findBounds*(s: string, pattern: Peg, matches: var openArray[string], start = 0): tuple[first, last: int] {. - noSideEffect, rtl, extern: "npegs$1Capture".} = + rtl, extern: "npegs$1Capture".} = ## returns the starting position and end position of ``pattern`` in ``s`` ## and the captured ## substrings in the array ``matches``. If it does not match, nothing @@ -1136,8 +1140,8 @@ proc findBounds*(s: string, pattern: Peg, matches: var openArray[string], return (i, i+L-1) return (-1, 0) -proc find*(s: string, pattern: Peg, - start = 0): int {.noSideEffect, rtl, extern: "npegs$1".} = +func find*(s: string, pattern: Peg, + start = 0): int {.rtl, extern: "npegs$1".} = ## returns the starting position of ``pattern`` in ``s``. If it does not ## match, -1 is returned. var c: Captures @@ -1160,8 +1164,8 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string = yield substr(s, i, i+L-1) inc(i, L) -proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {. - noSideEffect, rtl, extern: "npegs$1".} = +func findAll*(s: string, pattern: Peg, start = 0): seq[string] {. + rtl, extern: "npegs$1".} = ## returns all matching *substrings* of `s` that match `pattern`. ## If it does not match, @[] is returned. result = @[] @@ -1192,31 +1196,31 @@ template `=~`*(s: string, pattern: Peg): bool = # ------------------------- more string handling ------------------------------ -proc contains*(s: string, pattern: Peg, start = 0): bool {. - noSideEffect, rtl, extern: "npegs$1".} = +func contains*(s: string, pattern: Peg, start = 0): bool {. + rtl, extern: "npegs$1".} = ## same as ``find(s, pattern, start) >= 0`` return find(s, pattern, start) >= 0 -proc contains*(s: string, pattern: Peg, matches: var openArray[string], - start = 0): bool {.noSideEffect, rtl, extern: "npegs$1Capture".} = +func contains*(s: string, pattern: Peg, matches: var openArray[string], + start = 0): bool {.rtl, extern: "npegs$1Capture".} = ## same as ``find(s, pattern, matches, start) >= 0`` return find(s, pattern, matches, start) >= 0 -proc startsWith*(s: string, prefix: Peg, start = 0): bool {. - noSideEffect, rtl, extern: "npegs$1".} = +func startsWith*(s: string, prefix: Peg, start = 0): bool {. + rtl, extern: "npegs$1".} = ## returns true if `s` starts with the pattern `prefix` result = matchLen(s, prefix, start) >= 0 -proc endsWith*(s: string, suffix: Peg, start = 0): bool {. - noSideEffect, rtl, extern: "npegs$1".} = +func endsWith*(s: string, suffix: Peg, start = 0): bool {. + rtl, extern: "npegs$1".} = ## returns true if `s` ends with the pattern `suffix` var c: Captures c.origStart = start for i in start .. s.len-1: if rawMatch(s, suffix, i, c) == s.len - i: return true -proc replacef*(s: string, sub: Peg, by: string): string {. - noSideEffect, rtl, extern: "npegs$1".} = +func replacef*(s: string, sub: Peg, by: string): string {. + rtl, extern: "npegs$1".} = ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## @@ -1244,8 +1248,8 @@ proc replacef*(s: string, sub: Peg, by: string): string {. inc(i, x) add(result, substr(s, i)) -proc replace*(s: string, sub: Peg, by = ""): string {. - noSideEffect, rtl, extern: "npegs$1".} = +func replace*(s: string, sub: Peg, by = ""): string {. + rtl, extern: "npegs$1".} = ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed ## in `by`. result = "" @@ -1261,9 +1265,9 @@ proc replace*(s: string, sub: Peg, by = ""): string {. inc(i, x) add(result, substr(s, i)) -proc parallelReplace*(s: string, subs: varargs[ +func parallelReplace*(s: string, subs: varargs[ tuple[pattern: Peg, repl: string]]): string {. - noSideEffect, rtl, extern: "npegs$1".} = + rtl, extern: "npegs$1".} = ## Returns a modified copy of `s` with the substitutions in `subs` ## applied in parallel. result = "" @@ -1288,7 +1292,7 @@ proc parallelReplace*(s: string, subs: varargs[ when not defined(nimHasEffectsOf): {.pragma: effectsOf.} -proc replace*(s: string, sub: Peg, cb: proc( +func replace*(s: string, sub: Peg, cb: proc( match: int, cnt: int, caps: openArray[string]): string): string {. rtl, extern: "npegs$1cb", effectsOf: cb.} = ## Replaces `sub` in `s` by the resulting strings from the callback. @@ -1297,7 +1301,7 @@ proc replace*(s: string, sub: Peg, cb: proc( ## ## .. code-block:: nim ## - ## proc handleMatches*(m: int, n: int, c: openArray[string]): string = + ## func handleMatches*(m: int, n: int, c: openArray[string]): string = ## result = "" ## if m > 0: ## result.add ", " @@ -1380,8 +1384,8 @@ iterator split*(s: string, sep: Peg): string = if first < last: yield substr(s, first, last-1) -proc split*(s: string, sep: Peg): seq[string] {. - noSideEffect, rtl, extern: "npegs$1".} = +func split*(s: string, sep: Peg): seq[string] {. + rtl, extern: "npegs$1".} = ## Splits the string `s` into substrings. result = @[] for it in split(s, sep): result.add it @@ -1445,20 +1449,20 @@ const "@", "built-in", "escaped", "$", "$", "^" ] -proc handleCR(L: var PegLexer, pos: int): int = +func handleCR(L: var PegLexer, pos: int): int = assert(L.buf[pos] == '\c') inc(L.lineNumber) result = pos+1 if result < L.buf.len and L.buf[result] == '\L': inc(result) L.lineStart = result -proc handleLF(L: var PegLexer, pos: int): int = +func handleLF(L: var PegLexer, pos: int): int = assert(L.buf[pos] == '\L') inc(L.lineNumber) result = pos+1 L.lineStart = result -proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = +func init(L: var PegLexer, input, filename: string, line = 1, col = 0) = L.buf = input L.bufpos = 0 L.lineNumber = line @@ -1466,18 +1470,18 @@ proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = L.lineStart = 0 L.filename = filename -proc getColumn(L: PegLexer): int {.inline.} = +func getColumn(L: PegLexer): int {.inline.} = result = abs(L.bufpos - L.lineStart) + L.colOffset -proc getLine(L: PegLexer): int {.inline.} = +func getLine(L: PegLexer): int {.inline.} = result = L.lineNumber -proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = +func errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = var line = if line < 0: getLine(L) else: line var col = if col < 0: getColumn(L) else: col result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] -proc getEscapedChar(c: var PegLexer, tok: var Token) = +func getEscapedChar(c: var PegLexer, tok: var Token) = inc(c.bufpos) if c.bufpos >= len(c.buf): tok.kind = tkInvalid @@ -1537,7 +1541,7 @@ proc getEscapedChar(c: var PegLexer, tok: var Token) = add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -proc skip(c: var PegLexer) = +func skip(c: var PegLexer) = var pos = c.bufpos while pos < c.buf.len: case c.buf[pos] @@ -1554,7 +1558,7 @@ proc skip(c: var PegLexer) = break # EndOfFile also leaves the loop c.bufpos = pos -proc getString(c: var PegLexer, tok: var Token) = +func getString(c: var PegLexer, tok: var Token) = tok.kind = tkStringLit var pos = c.bufpos + 1 var quote = c.buf[pos-1] @@ -1575,7 +1579,7 @@ proc getString(c: var PegLexer, tok: var Token) = inc(pos) c.bufpos = pos -proc getDollar(c: var PegLexer, tok: var Token) = +func getDollar(c: var PegLexer, tok: var Token) = var pos = c.bufpos + 1 var neg = false if pos < c.buf.len and c.buf[pos] == '^': @@ -1595,7 +1599,7 @@ proc getDollar(c: var PegLexer, tok: var Token) = tok.kind = tkDollar c.bufpos = pos -proc getCharSet(c: var PegLexer, tok: var Token) = +func getCharSet(c: var PegLexer, tok: var Token) = tok.kind = tkCharSet tok.charset = {} var pos = c.bufpos + 1 @@ -1652,7 +1656,7 @@ proc getCharSet(c: var PegLexer, tok: var Token) = c.bufpos = pos if caret: tok.charset = {'\1'..'\xFF'} - tok.charset -proc getSymbol(c: var PegLexer, tok: var Token) = +func getSymbol(c: var PegLexer, tok: var Token) = var pos = c.bufpos while pos < c.buf.len: add(tok.literal, c.buf[pos]) @@ -1661,7 +1665,7 @@ proc getSymbol(c: var PegLexer, tok: var Token) = c.bufpos = pos tok.kind = tkIdentifier -proc getBuiltin(c: var PegLexer, tok: var Token) = +func getBuiltin(c: var PegLexer, tok: var Token) = if c.bufpos+1 < c.buf.len and c.buf[c.bufpos+1] in strutils.Letters: inc(c.bufpos) getSymbol(c, tok) @@ -1670,7 +1674,7 @@ proc getBuiltin(c: var PegLexer, tok: var Token) = tok.kind = tkEscaped getEscapedChar(c, tok) # may set tok.kind to tkInvalid -proc getTok(c: var PegLexer, tok: var Token) = +func getTok(c: var PegLexer, tok: var Token) = tok.kind = tkInvalid tok.modifier = modNone setLen(tok.literal, 0) @@ -1792,7 +1796,7 @@ proc getTok(c: var PegLexer, tok: var Token) = add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -proc arrowIsNextTok(c: PegLexer): bool = +func arrowIsNextTok(c: PegLexer): bool = # the only look ahead we need var pos = c.bufpos while pos < c.buf.len and c.buf[pos] in {'\t', ' '}: inc(pos) @@ -1813,23 +1817,23 @@ type identIsVerbatim: bool skip: Peg -proc pegError(p: PegParser, msg: string, line = -1, col = -1) = +func pegError(p: PegParser, msg: string, line = -1, col = -1) = var e: ref EInvalidPeg new(e) e.msg = errorStr(p, msg, line, col) raise e -proc getTok(p: var PegParser) = +func getTok(p: var PegParser) = getTok(p, p.tok) if p.tok.kind == tkInvalid: pegError(p, "'" & p.tok.literal & "' is invalid token") -proc eat(p: var PegParser, kind: TokKind) = +func eat(p: var PegParser, kind: TokKind) = if p.tok.kind == kind: getTok(p) else: pegError(p, tokKindToStr[kind] & " expected") -proc parseExpr(p: var PegParser): Peg {.gcsafe.} +func parseExpr(p: var PegParser): Peg {.gcsafe.} -proc getNonTerminal(p: var PegParser, name: string): NonTerminal = +func getNonTerminal(p: var PegParser, name: string): NonTerminal = for i in 0..high(p.nonterms): result = p.nonterms[i] if cmpIgnoreStyle(result.name, name) == 0: return @@ -1837,13 +1841,13 @@ proc getNonTerminal(p: var PegParser, name: string): NonTerminal = result = newNonTerminal(name, getLine(p), getColumn(p)) add(p.nonterms, result) -proc modifiedTerm(s: string, m: Modifier): Peg = +func modifiedTerm(s: string, m: Modifier): Peg = case m of modNone, modVerbatim: result = term(s) of modIgnoreCase: result = termIgnoreCase(s) of modIgnoreStyle: result = termIgnoreStyle(s) -proc modifiedBackref(s: int, m: Modifier): Peg = +func modifiedBackref(s: int, m: Modifier): Peg = var reverse = s < 0 index = if reverse: -s else: s @@ -1852,7 +1856,7 @@ proc modifiedBackref(s: int, m: Modifier): Peg = of modIgnoreCase: result = backrefIgnoreCase(index, reverse) of modIgnoreStyle: result = backrefIgnoreStyle(index, reverse) -proc builtin(p: var PegParser): Peg = +func builtin(p: var PegParser): Peg = # do not use "y", "skip" or "i" as these would be ambiguous case p.tok.literal of "n": result = newLine() @@ -1872,11 +1876,11 @@ proc builtin(p: var PegParser): Peg = of "white": result = unicodeWhitespace() else: pegError(p, "unknown built-in: " & p.tok.literal) -proc token(terminal: Peg, p: PegParser): Peg = +func token(terminal: Peg, p: PegParser): Peg = if p.skip.kind == pkEmpty: result = terminal else: result = sequence(p.skip, terminal) -proc primary(p: var PegParser): Peg = +func primary(p: var PegParser): Peg = case p.tok.kind of tkAmp: getTok(p) @@ -1968,7 +1972,7 @@ proc primary(p: var PegParser): Peg = getTok(p) else: break -proc seqExpr(p: var PegParser): Peg = +func seqExpr(p: var PegParser): Peg = result = primary(p) while true: case p.tok.kind @@ -1982,13 +1986,13 @@ proc seqExpr(p: var PegParser): Peg = else: break else: break -proc parseExpr(p: var PegParser): Peg = +func parseExpr(p: var PegParser): Peg = result = seqExpr(p) while p.tok.kind == tkBar: getTok(p) result = result / seqExpr(p) -proc parseRule(p: var PegParser): NonTerminal = +func parseRule(p: var PegParser): NonTerminal = if p.tok.kind == tkIdentifier and arrowIsNextTok(p): result = getNonTerminal(p, p.tok.literal) if ntDeclared in result.flags: @@ -2002,7 +2006,7 @@ proc parseRule(p: var PegParser): NonTerminal = else: pegError(p, "rule expected, but found: " & p.tok.literal) -proc rawParse(p: var PegParser): Peg = +func rawParse(p: var PegParser): Peg = ## parses a rule or a PEG expression while p.tok.kind == tkBuiltin: case p.tok.literal @@ -2032,7 +2036,7 @@ proc rawParse(p: var PegParser): Peg = elif ntUsed notin nt.flags and i > 0: pegError(p, "unused rule: " & nt.name, nt.line, nt.col) -proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = +func parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are ## used for error messages, but they only provide start offsets. `parsePeg` ## keeps track of line and column numbers within `pattern`. @@ -2047,14 +2051,14 @@ proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = getTok(p) result = rawParse(p) -proc peg*(pattern: string): Peg = +func peg*(pattern: string): Peg = ## constructs a Peg object from the `pattern`. The short name has been ## chosen to encourage its use as a raw string modifier:: ## ## peg"{\ident} \s* '=' \s* {.*}" result = parsePeg(pattern, "pattern") -proc escapePeg*(s: string): string = +func escapePeg*(s: string): string = ## escapes `s` so that it is matched verbatim when used as a peg. result = "" var inQuote = false diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim index 4e9b9fe66..264771a1a 100644 --- a/tests/effects/tstrict_funcs_imports.nim +++ b/tests/effects/tstrict_funcs_imports.nim @@ -84,7 +84,7 @@ import parseutils, parsexml, pathnorm, - # pegs, + pegs, posix_utils, prelude, punycode, diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index fe3335c0f..0c5c8f4a3 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,6 +1,9 @@ ## Part of 'koch' responsible for the documentation generation. -import os, strutils, osproc, sets, pathnorm, pegs, sequtils +import os, strutils, osproc, sets, pathnorm, sequtils +# XXX: Remove this feature check once the csources supports it. +when defined(nimHasCastPragmaBlocks): + import std/pegs from std/private/globs import nativeToUnixPath, walkDirRecFilter, PathEntry import "../compiler/nimpaths" @@ -338,7 +341,9 @@ proc buildDocs*(args: string, localOnly = false, localOutDir = "") = if not localOnly: buildDocsDir(args, webUploadOutput / NimVersion) - let gaFilter = peg"@( y'--doc.googleAnalytics:' @(\s / $) )" - args = args.replace(gaFilter) + # XXX: Remove this feature check once the csources supports it. + when defined(nimHasCastPragmaBlocks): + let gaFilter = peg"@( y'--doc.googleAnalytics:' @(\s / $) )" + args = args.replace(gaFilter) buildDocsDir(args, localOutDir) From 6f15af41a7ea7aeb09b9c9b9c1d7ca3b505107c9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 7 Oct 2021 15:07:24 +0200 Subject: [PATCH 3061/4254] fixes a regression caused by overloadable enums even though they're opt-in (#18970) --- compiler/semtempl.nim | 10 +++++++--- tests/enum/mregression.nim | 4 ++++ tests/enum/tregression.nim | 13 +++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 tests/enum/mregression.nim create mode 100644 tests/enum/tregression.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index c10917bcb..49ce55a64 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -250,7 +250,7 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode = of skUnknown: # Introduced in this pass! Leave it as an identifier. result = n - of OverloadableSyms: + of OverloadableSyms-{skEnumField}: result = symChoice(c, n, s, scOpen, isField) of skGenericParam: if isField and sfGenSym in s.flags: result = n @@ -261,8 +261,12 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode = if isField and sfGenSym in s.flags: result = n else: result = newSymNodeTypeDesc(s, c.idgen, n.info) else: - if isField and sfGenSym in s.flags: result = n - else: result = newSymNode(s, n.info) + if s.kind == skEnumField and overloadableEnums in c.features: + result = symChoice(c, n, s, scOpen, isField) + elif isField and sfGenSym in s.flags: + result = n + else: + result = newSymNode(s, n.info) # Issue #12832 when defined(nimsuggest): suggestSym(c.graph, n.info, s, c.graph.usageSym, false) diff --git a/tests/enum/mregression.nim b/tests/enum/mregression.nim new file mode 100644 index 000000000..9c3e3cf8b --- /dev/null +++ b/tests/enum/mregression.nim @@ -0,0 +1,4 @@ + +type + OtherEnum* = enum + Success, Failed, More diff --git a/tests/enum/tregression.nim b/tests/enum/tregression.nim new file mode 100644 index 000000000..597f0c80a --- /dev/null +++ b/tests/enum/tregression.nim @@ -0,0 +1,13 @@ +discard """ + action: "compile" +""" +import options, mregression + +type + MyEnum = enum + Success + +template t = + echo some(Success) + +t() From 08107c2192e6aebb386df2711f2935731ee599fd Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 8 Oct 2021 00:54:21 +0800 Subject: [PATCH 3062/4254] [minor] give more friendly description (#18973) --- nimdoc/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index 1e438b97b..32dce0709 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -80,4 +80,4 @@ let testNimDoc(test2Dir, test2DocsDir, test2Switches, fixup) if failures > 0: - quit "$# failures occurred; see note in tester.nim regarding -d:nimTestsNimdocFixup" % $failures + quit "$# failures occurred; see note in nimdoc/tester.nim regarding -d:nimTestsNimdocFixup" % $failures From 787def271b1cabc6f898caa42f892125de9fa908 Mon Sep 17 00:00:00 2001 From: antonl05 <88133270+antonl05@users.noreply.github.com> Date: Sat, 9 Oct 2021 14:17:07 +0530 Subject: [PATCH 3063/4254] add OpenIndiana to list (#18972) * add OpenIndiana support * point sunos to solaris --- tools/niminst/buildsh.nimf | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 9850abd89..5f68a6a17 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -139,6 +139,11 @@ case $uos in myos="solaris" LINK_FLAGS="$LINK_FLAGS -ldl -lm -lsocket -lnsl" ;; + *SunOS* ) + myos="solaris" + LINK_FLAGS="$LINK_FLAGS -ldl -lm -lsocket -lnsl" + isOpenIndiana="yes" + ;; *haiku* ) myos="haiku" LINK_FLAGS="$LINK_FLAGS -lroot -lnetwork" @@ -159,7 +164,12 @@ esac case $ucpu in *i386* | *i486* | *i586* | *i686* | *bepc* | *i86pc* ) - mycpu="i386" ;; + if [ isOpenIndiana -eq "yes" ] ; then + mycpu="amd64" + else + mycpu="i386" + fi + ;; *amd*64* | *x86-64* | *x86_64* ) mycpu="amd64" ;; *sparc*|*sun* ) From 83128f217f63045974a48e61b65386abbfc97352 Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 11 Oct 2021 14:38:59 +0200 Subject: [PATCH 3064/4254] disable testing of `fidget`, to make CIs green --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 0c47104ac..e037cc609 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -63,7 +63,7 @@ pkg "delaunay" pkg "docopt" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" -pkg "fidget" +pkg "fidget", allowFailure = true pkg "fragments", "nim c -r fragments/dsl.nim" pkg "fusion" pkg "gara" From 0ae2d1ea88fdc7b6910ddbc960c7db086be383e4 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 12 Oct 2021 06:41:30 -0700 Subject: [PATCH 3065/4254] Improve error message when NodeJS is not installed and 'nim js -r' is run (#18978) --- compiler/nodejs.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/nodejs.nim b/compiler/nodejs.nim index 781035bb7..283643e8d 100644 --- a/compiler/nodejs.nim +++ b/compiler/nodejs.nim @@ -3,5 +3,8 @@ import os proc findNodeJs*(): string {.inline.} = ## Find NodeJS executable and return it as a string. result = findExe("nodejs") - if result == "": + if result.len == 0: result = findExe("node") + if result.len == 0: + echo "Please install NodeJS first, see https://nodejs.org/en/download" + raise newException(IOError, "NodeJS not found in PATH: " & result) From 2aa97a228aa3a34b48f1af9901f29379fb131a31 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 13 Oct 2021 10:09:45 +0100 Subject: [PATCH 3066/4254] Removes deprecated {.injectStmt.}. Fixes #18666 (#18984) --- compiler/ccgcalls.nim | 1 - compiler/ccgstmts.nim | 5 ---- compiler/cgen.nim | 3 --- compiler/cgendata.nim | 1 - compiler/pragmas.nim | 8 +----- compiler/wordrecg.nim | 2 +- lib/system/gc_ms.nim | 10 ------- tests/pragmas/tinjectstmt.nim | 51 ----------------------------------- 8 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 tests/pragmas/tinjectstmt.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index f6cc6da74..12f366a53 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -801,6 +801,5 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = genNamedParamCall(p, ri, d) else: genPrefixCall(p, le, ri, d) - postStmtActions(p) proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 6cbff6ee9..559849f0d 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1509,11 +1509,6 @@ proc genPragma(p: BProc, n: PNode) = for it in n.sons: case whichPragma(it) of wEmit: genEmit(p, it) - of wInjectStmt: - var p = newProc(nil, p.module) - p.options.excl {optLineTrace, optStackTrace} - genStmts(p, it[1]) - p.module.injectStmt = p.s(cpsStmts) else: discard diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 43410dc60..412a428da 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -271,9 +271,6 @@ proc genLineDir(p: BProc, t: PNode) = linefmt(p, cpsStmts, "nimln_($1, $2);$n", [line, quotedFilename(p.config, t.info)]) -proc postStmtActions(p: BProc) {.inline.} = - p.s(cpsStmts).add(p.module.injectStmt) - proc accessThreadLocalVar(p: BProc, s: PSym) proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} proc genProc(m: BModule, prc: PSym) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 3678adacf..88b8d4090 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -170,7 +170,6 @@ type labels*: Natural # for generating unique module-scope names extensionLoaders*: array['0'..'9', Rope] # special procs for the # OpenGL wrapper - injectStmt*: Rope sigConflicts*: CountTable[SigHash] g*: BModuleList ndi*: NdiFile diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index e9f52c71f..a6e6131d7 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -55,7 +55,7 @@ const wDeprecated, wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto, - wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert} + wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert} lambdaPragmas* = {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader, wThread, wAsmNoStackFrame, @@ -1204,12 +1204,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wExportNims: if sym == nil: invalidPragma(c, it) else: magicsys.registerNimScriptSymbol(c.graph, sym) - of wInjectStmt: - warningDeprecated(c.config, it.info, "'.injectStmt' pragma is deprecated") - if it.kind notin nkPragmaCallKinds or it.len != 2: - localError(c.config, it.info, "expression expected") - else: - it[1] = c.semExpr(c, it[1]) of wExperimental: if not isTopLevel(c): localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement or in a 'push' environment") diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 4ba807518..ce06effab 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -80,7 +80,7 @@ type wLocalPassc = "localPassC", wBorrow = "borrow", wDiscardable = "discardable", wFieldChecks = "fieldChecks", wSubsChar = "subschar", wAcyclic = "acyclic", wShallow = "shallow", wUnroll = "unroll", wLinearScanEnd = "linearScanEnd", - wComputedGoto = "computedGoto", wInjectStmt = "injectStmt", wExperimental = "experimental", + wComputedGoto = "computedGoto", wExperimental = "experimental", wWrite = "write", wGensym = "gensym", wInject = "inject", wDirty = "dirty", wInheritable = "inheritable", wThreadVar = "threadvar", wEmit = "emit", wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic", diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 9e306c497..0675b9f2e 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -428,16 +428,6 @@ proc sweep(gch: var GcHeap) = if c.refcount == rcBlack: c.refcount = rcWhite else: freeCyclicCell(gch, c) -when false: - # meant to be used with the now-deprected `.injectStmt`: {.injectStmt: newGcInvariant().} - proc newGcInvariant*() = - for x in allObjects(gch.region): - if isCell(x): - var c = cast[PCell](x) - if c.typ == nil: - writeStackTrace() - quit 1 - proc markGlobals(gch: var GcHeap) = if gch.gcThreadId == 0: when defined(nimTracing): diff --git a/tests/pragmas/tinjectstmt.nim b/tests/pragmas/tinjectstmt.nim deleted file mode 100644 index c6256bda6..000000000 --- a/tests/pragmas/tinjectstmt.nim +++ /dev/null @@ -1,51 +0,0 @@ -discard """ - joinable: false - output:''' -onInject: 1 -onInject: 2 -ok0 -ok1 -onInject: 3 -onInject: 4 -onInject: 5 -0 -onInject: 6 -onInject: 7 -onInject: 8 -1 -onInject: 9 -onInject: 10 -onInject: 11 -2 -ok2 -onInject: 12 -''' -""" - -# test {.injectStmt.} - -#[ -{.injectStmt.} pragma can be used to inject a statement before every -other statement in the current module. It's now undocumented and may be removed -in the future and replaced with something more general and without its limitations. -(e.g. doesn't work in VM or js backends). -]# - -from system/ansi_c import c_printf - -var count = 0 -proc onInject*() = - count.inc - # echo count # xxx would fail, probably infinite recursion - c_printf("onInject: %d\n", cast[int](count)) - -{.injectStmt: onInject().} -echo "ok0" -proc main()= - echo "ok1" - for a in 0..<3: - echo a - echo "ok2" - -static: main() # xxx injectStmt not honored in VM -main() From e645be4d0c6c53cd9483d4fde24c4ddc7bd1bf96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E4=BA=A6=E6=81=A9?= Date: Wed, 13 Oct 2021 17:35:47 +0800 Subject: [PATCH 3067/4254] add ghci like type annotation buildEchoStmt (1049) (#18875) * add ghci like type annotation buildEchoStmt (1049) * Update compiler/semexprs.nim * Update compiler/semexprs.nim Co-authored-by: flywind Co-authored-by: Andreas Rumpf Co-authored-by: flywind --- compiler/semexprs.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 342b8b05f..c11cecfa9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1057,6 +1057,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = else: result.add localErrorNode(c, n, "system needs: echo") result.add(n) + result.add(newStrNode(nkStrLit, ": " & n.typ.typeToString)) result = semExpr(c, result) proc semExprNoType(c: PContext, n: PNode): PNode = From 2ac3ba713b61e4e6b70c98da59dc05925f8b5e6b Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 13 Oct 2021 20:57:25 +0800 Subject: [PATCH 3068/4254] fix #18985 (#18988) --- compiler/semtypes.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9f7a17a53..d03fa88a8 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2076,7 +2076,10 @@ proc processMagicType(c: PContext, m: PSym) = setMagicType(c.config, m, tySequence, szUncomputedSize) if optSeqDestructors in c.config.globalOptions: incl m.typ.flags, tfHasAsgn - assert c.graph.sysTypes[tySequence] == nil + if defined(nimsuggest) or c.config.cmd == cmdCheck: # bug #18985 + discard + else: + assert c.graph.sysTypes[tySequence] == nil c.graph.sysTypes[tySequence] = m.typ of mOrdinal: setMagicIntegral(c.config, m, tyOrdinal, szUncomputedSize) From e2b19bb2deba0932cf324c0127ffa7f2cbed8b5d Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 13 Oct 2021 20:58:31 +0800 Subject: [PATCH 3069/4254] remove deprecated stuffs from std/times (#18937) --- lib/pure/times.nim | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index b41bb28b5..113f73d2a 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -488,7 +488,7 @@ proc fromEpochDay(epochday: int64): proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): YeardayRange {.tags: [], raises: [], benign.} = ## Returns the day of the year. - ## Equivalent with `initDateTime(monthday, month, year, 0, 0, 0).yearday`. + ## Equivalent with `dateTime(year, month, monthday, 0, 0, 0, 0).yearday`. runnableExamples: doAssert getDayOfYear(1, mJan, 2000) == 0 doAssert getDayOfYear(10, mJan, 2000) == 9 @@ -508,7 +508,7 @@ proc getDayOfYear*(monthday: MonthdayRange, month: Month, year: int): proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay {.tags: [], raises: [], benign.} = ## Returns the day of the week enum from day, month and year. - ## Equivalent with `initDateTime(monthday, month, year, 0, 0, 0).weekday`. + ## Equivalent with `dateTime(year, month, monthday, 0, 0, 0, 0).weekday`. runnableExamples: doAssert getDayOfWeek(13, mJun, 1990) == dWed doAssert $getDayOfWeek(13, mJun, 1990) == "Wednesday" @@ -1060,13 +1060,13 @@ proc isLeapDay*(dt: DateTime): bool {.since: (1, 1).} = ## Returns whether `t` is a leap day, i.e. Feb 29 in a leap year. This matters ## as it affects time offset calculations. runnableExamples: - let dt = initDateTime(29, mFeb, 2020, 00, 00, 00, utc()) + let dt = dateTime(2020, mFeb, 29, 00, 00, 00, 00, utc()) doAssert dt.isLeapDay doAssert dt+1.years-1.years != dt - let dt2 = initDateTime(28, mFeb, 2020, 00, 00, 00, utc()) + let dt2 = dateTime(2020, mFeb, 28, 00, 00, 00, 00, utc()) doAssert not dt2.isLeapDay doAssert dt2+1.years-1.years == dt2 - doAssertRaises(Exception): discard initDateTime(29, mFeb, 2021, 00, 00, 00, utc()) + doAssertRaises(Exception): discard dateTime(2021, mFeb, 29, 00, 00, 00, 00, utc()) assertDateTimeInitialized dt dt.year.isLeapYear and dt.month == mFeb and dt.monthday == 29 @@ -1372,7 +1372,7 @@ proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, proc `+`*(dt: DateTime, dur: Duration): DateTime = runnableExamples: - let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) let dur = initDuration(hours = 5) doAssert $(dt + dur) == "2017-03-30T05:00:00Z" @@ -1380,7 +1380,7 @@ proc `+`*(dt: DateTime, dur: Duration): DateTime = proc `-`*(dt: DateTime, dur: Duration): DateTime = runnableExamples: - let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) let dur = initDuration(days = 5) doAssert $(dt - dur) == "2017-03-25T00:00:00Z" @@ -1389,8 +1389,8 @@ proc `-`*(dt: DateTime, dur: Duration): DateTime = proc `-`*(dt1, dt2: DateTime): Duration = ## Compute the duration between `dt1` and `dt2`. runnableExamples: - let dt1 = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) - let dt2 = initDateTime(25, mMar, 2017, 00, 00, 00, utc()) + let dt1 = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) + let dt2 = dateTime(2017, mMar, 25, 00, 00, 00, 00, utc()) doAssert dt1 - dt2 == initDuration(days = 5) @@ -1998,10 +1998,10 @@ proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, if p.utcOffset.isNone: # No timezone parsed - assume timezone is `zone` - result = initDateTime(monthday, month, year, hour, minute, second, nanosecond, zone) + result = dateTime(year, month, monthday, hour, minute, second, nanosecond, zone) else: # Otherwise convert to `zone` - result = (initDateTime(monthday, month, year, hour, minute, second, nanosecond, utc()).toTime + + result = (dateTime(year, month, monthday, hour, minute, second, nanosecond, utc()).toTime + initDuration(seconds = p.utcOffset.get())).inZone(zone) proc format*(dt: DateTime, f: TimeFormat, @@ -2009,7 +2009,7 @@ proc format*(dt: DateTime, f: TimeFormat, ## Format `dt` using the format specified by `f`. runnableExamples: let f = initTimeFormat("yyyy-MM-dd") - let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) + let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) doAssert "2000-01-01" == dt.format(f) assertDateTimeInitialized dt result = "" @@ -2034,7 +2034,7 @@ proc format*(dt: DateTime, f: string, loc: DateTimeLocale = DefaultLocale): stri ## See `Parsing and formatting dates`_ for documentation of the ## `format` argument. runnableExamples: - let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) + let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) doAssert "2000-01-01" == format(dt, "yyyy-MM-dd") let dtFormat = initTimeFormat(f) result = dt.format(dtFormat, loc) @@ -2057,7 +2057,7 @@ proc format*(time: Time, f: string, zone: Timezone = local()): string ## See `Parsing and formatting dates`_ for documentation of the ## `f` argument. runnableExamples: - var dt = initDateTime(01, mJan, 1970, 00, 00, 00, utc()) + var dt = dateTime(1970, mJan, 01, 00, 00, 00, 00, utc()) var tm = dt.toTime() doAssert format(tm, "yyyy-MM-dd'T'HH:mm:ss", utc()) == "1970-01-01T00:00:00" time.inZone(zone).format(f) @@ -2083,7 +2083,7 @@ proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), ## Month and day names from the passed in `loc` are used. runnableExamples: let f = initTimeFormat("yyyy-MM-dd") - let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) + let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) doAssert dt == "2000-01-01".parse(f, utc()) var inpIdx = 0 # Input index var patIdx = 0 # Pattern index @@ -2125,7 +2125,7 @@ proc parse*(input, f: string, tz: Timezone = local(), ## See `Parsing and formatting dates`_ for documentation of the ## `f` argument. runnableExamples: - let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) + let dt = dateTime(2000, mJan, 01, 00, 00, 00, 00, utc()) doAssert dt == parse("2000-01-01", "yyyy-MM-dd", utc()) let dtFormat = initTimeFormat(f) result = input.parse(dtFormat, tz, loc = loc) @@ -2159,7 +2159,7 @@ proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} = ## Converts a `DateTime` object to a string representation. ## It uses the format `yyyy-MM-dd'T'HH:mm:sszzz`. runnableExamples: - let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) + let dt = dateTime(2000, mJan, 01, 12, 00, 00, 00, utc()) doAssert $dt == "2000-01-01T12:00:00Z" doAssert $default(DateTime) == "Uninitialized DateTime" if not dt.isInitialized: @@ -2171,7 +2171,7 @@ proc `$`*(time: Time): string {.tags: [], raises: [], benign.} = ## Converts a `Time` value to a string representation. It will use the local ## time zone and use the format `yyyy-MM-dd'T'HH:mm:sszzz`. runnableExamples: - let dt = initDateTime(01, mJan, 1970, 00, 00, 00, local()) + let dt = dateTime(1970, mJan, 01, 00, 00, 00, 00, local()) let tm = dt.toTime() doAssert $tm == "1970-01-01T00:00:00" & format(dt, "zzz") $time.local @@ -2193,7 +2193,7 @@ proc initTimeInterval*(nanoseconds, microseconds, milliseconds, ## `seconds`, `minutes`, `hours`, `days`, `months`, and `years`. runnableExamples: let day = initTimeInterval(hours = 24) - let dt = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) + let dt = dateTime(2000, mJan, 01, 12, 00, 00, 00, utc()) doAssert $(dt + day) == "2000-01-02T12:00:00Z" doAssert initTimeInterval(hours = 24) != initTimeInterval(days = 1) result.nanoseconds = nanoseconds @@ -2279,8 +2279,8 @@ proc between*(startDt, endDt: DateTime): TimeInterval = ## - If `startDt.timezone != endDt.timezone`, then the result will be ## equivalent to `between(startDt.utc, endDt.utc)`. runnableExamples: - var a = initDateTime(25, mMar, 2015, 12, 0, 0, utc()) - var b = initDateTime(1, mApr, 2017, 15, 0, 15, utc()) + var a = dateTime(2015, mMar, 25, 12, 0, 0, 00, utc()) + var b = dateTime(2017, mApr, 1, 15, 0, 15, 00, utc()) var ti = initTimeInterval(years = 2, weeks = 1, hours = 3, seconds = 15) doAssert between(a, b) == ti doAssert between(a, b) == -between(b, a) @@ -2360,8 +2360,8 @@ proc between*(startDt, endDt: DateTime): TimeInterval = startDate = endDate # Handle hours, minutes, seconds, milliseconds, microseconds and nanoseconds - let newStartDt = initDateTime(startDate.monthday, startDate.month.Month, - startDate.year, startDt.hour, startDt.minute, startDt.second, + let newStartDt = dateTime(startDate.year, startDate.month.Month, + startDate.monthday, startDt.hour, startDt.minute, startDt.second, startDt.nanosecond, startDt.timezone) let dur = endDt - newStartDt let parts = toParts(dur) @@ -2512,7 +2512,7 @@ proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = ## So adding one month to `31 October` will result in `31 November`, which ## will overflow and result in `1 December`. runnableExamples: - let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) doAssert $(dt + 1.months) == "2017-04-30T00:00:00Z" # This is correct and happens due to monthday overflow. doAssert $(dt - 1.months) == "2017-03-02T00:00:00Z" @@ -2535,7 +2535,7 @@ proc `-`*(dt: DateTime, interval: TimeInterval): DateTime = ## then the `months` component and so on. The returned `DateTime` will ## have the same timezone as the input. runnableExamples: - let dt = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) + let dt = dateTime(2017, mMar, 30, 00, 00, 00, 00, utc()) doAssert $(dt - 5.days) == "2017-03-25T00:00:00Z" dt + (-interval) From f93bfc0a329f193c8b83062e10140c2fb55a7873 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 13 Oct 2021 20:31:04 +0200 Subject: [PATCH 3070/4254] [backport] add v1.6 changelog (#18932) --- changelog.md | 538 +------------------- changelogs/changelog_1_6_0.md | 927 ++++++++++++++++++++++++++++++++++ 2 files changed, 928 insertions(+), 537 deletions(-) create mode 100644 changelogs/changelog_1_6_0.md diff --git a/changelog.md b/changelog.md index 1925878bf..ab63bd8b5 100644 --- a/changelog.md +++ b/changelog.md @@ -1,560 +1,24 @@ -# v1.6.x - yyyy-mm-dd +# v1.8.x - yyyy-mm-dd ## Changes affecting backward compatibility -- Deprecated `std/mersenne`. -- `system.delete` had a most surprising behavior when the index passed to it was out of - bounds (it would delete the last entry then). Compile with `-d:nimStrictDelete` so - that an index error is produced instead. But be aware that your code might depend on - this quirky behavior so a review process is required on your part before you can - use `-d:nimStrictDelete`. To make this review easier, use the `-d:nimAuditDelete` - switch, it pretends that `system.delete` is deprecated so that it is easier to see - where it was used in your code. - - `-d:nimStrictDelete` will become the default in upcoming versions. - - -- `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`. - Please use `char` or `uint8` instead. - -- `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, - see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. - -- A type conversion from one enum type to another now produces an `[EnumConv]` warning. - You should use `ord` (or `cast`, but the compiler won't help, if you misuse it) instead. - ``` - type A = enum a1, a2 - type B = enum b1, b2 - echo a1.B # produces a warning - echo a1.ord.B # produces no warning - ``` - -- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning. - This warning will become an error in future versions! Use an explicit conversion - like `cstring(x)` in order to silence the warning. - -- There is a new warning for *any* type conversion to enum that can be enabled via - `.warning[AnyEnumConv]:on` or `--warning:AnyEnumConv:on`. - -- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous - behavior. - -- `math.round` now is rounded "away from zero" in JS backend which is consistent - with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. - -- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` - characters in the decoded values. Prior versions would raise an error. This is - no longer the case to comply with the HTML spec and other languages - implementations. Old behavior can be obtained with - `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same - underlying code is also updated the same way. - -- On POSIX systems, the default signal handlers used for Nim programs (it's - used for printing the stacktrace on fatal signals) will now re-raise the - signal for the OS default handlers to handle. - - This lets the OS perform its default actions, which might include core - dumping (on select signals) and notifying the parent process about the cause - of termination. - -- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` - for previous behavior. - -- `hashes.hash` can now support `object` and `ref` (can be overloaded in user code), - if `-d:nimPreviewHashRef` is used. It is expected that this behavior - becomes the new default in upcoming versions. - -- `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`, - `hashes.hash(closure)` has also been improved. - -- The unary slice `..b` was deprecated, use `0..b` instead. - -- Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. - -- `random.initRand(seed)` now produces non-skewed values for the 1st call to `rand()` after - initialization with a small (< 30000) seed. Use `-d:nimLegacyRandomInitRand` to restore - previous behavior for a transition time, see PR #17467. - -- With `-d:nimPreviewJsonutilsHoleyEnum`, `jsonutils` now can serialize/deserialize holey enums as regular enums (via `ord`) instead of as strings. It is expected that this behavior becomes the new default in upcoming versions. `toJson` now serializes `JsonNode` - as is via reference (without a deep copy) instead of treating `JsonNode` as a regular ref object, - this can be customized via `jsonNodeMode`. - -- `json` and `jsonutils` now serialize NaN, Inf, -Inf as strings, so that - `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` which was invalid json. - - -- `strformat` is now part of `include std/prelude`. - -- Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` in `std/algorithm`. - -- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes in a collapsed way, - use `-d:nimLegacyMacrosCollapseSymChoice` to get previous behavior. - -- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. - The downside is that these defines now have custom logic that doesn't apply for - other defines. - -- `std/os`: `putEnv` now raises if the 1st argument contains a `=` - -- Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints`. - -- In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. Definitions of `setTimeout`, - `clearTimeout`, `setInterval`, `clearInterval` were updated. - -- With `-d:nimPreviewDotLikeOps`, dot-like operators (operators starting with `.`, but not with `..`) - now have the same precedence as `.`, so that `a.?b.c` is now parsed as `(a.?b).c` instead of `a.?(b.c)`. - A warning is generated when a dot-like operator is used without `-d:nimPreviewDotLikeOps`. - -- The allocator for Nintendo Switch, which was nonfunctional because - of breaking changes in libnx, was removed, in favour of the new `-d:nimAllocPagesViaMalloc` option. - -- `net.parseIpAddress` now only allows IPv4 addresses in strict form as defined - in [RFC 6943](https://www.rfc-editor.org/rfc/rfc6943#section-3.1.1). - Specifically, octal numbers in IPv4 addresses are no longer accepted (before - they were parsed as decimal numbers). ## Standard library additions and changes -- `strformat`: - - added support for parenthesized expressions. - - added support for const string's instead of just string literals - -- `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`; - use `-d:nimLegacyCopyFile` for OSX < 10.5. - -- `system.addFloat` and `system.$` now can produce string representations of floating point numbers - that are minimal in size and that "roundtrip" (via the "Dragonbox" algorithm). This currently has - to be enabled via `-d:nimPreviewFloatRoundtrip`. It is expected that this behavior becomes the new default - in upcoming versions, as with other `nimPreviewX` define flags. - -- Fixed buffer overflow bugs in `net`. - -- Exported `sslHandle` from `net` and `asyncnet`. - -- Added `sections` iterator in `parsecfg`. - -- Make custom op in macros.quote work for all statements. - -- On Windows the SSL library now checks for valid certificates. - It uses the `cacert.pem` file for this purpose which was extracted - from `https://curl.se/ca/cacert.pem`. Besides - the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you - now also need to ship `cacert.pem` with your `.exe` file. - -- `typetraits`: - `distinctBase` now is identity instead of error for non distinct types. - Added `enumLen` to return the number of elements in an enum. - Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. - Added `hasClosure`. - Added `pointerBase` to return `T` for `ref T | ptr T`. - -- `prelude` now works with the JavaScript target. - Added `sequtils` import to `prelude`. - `prelude` can now be used via `include std/prelude`, but `include prelude` still works. - -- Added `almostEqual` in `math` for comparing two float values using a machine epsilon. - -- Added `clamp` in `math` which allows using a `Slice` to clamp to a value. - -- Added `ceilDiv` in `math` for round up integer division. - -- The JSON module can now handle integer literals and floating point literals of - arbitrary length and precision. - Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are - kept as string literals and one can use external BigNum libraries to handle these. - The `parseFloat` family of functions also has now optional `rawIntegers` and - `rawFloats` parameters that can be used to enforce that all integer or float - literals remain in the "raw" string form so that client code can easily treat - small and large numbers uniformly. - -- Added `BackwardsIndex` overload for `JsonNode`. - -- `json.%`,`json.to`, `jsonutils.formJson`,`jsonutils.toJson` now work with `uint|uint64` - instead of raising (as in 1.4) or giving wrong results (as in 1.2). - -- `jsonutils` now handles `cstring` (including as Table key), and `set`. - -- added `jsonutils.jsonTo` overload with `opt = Joptions()` param. - -- `jsonutils.toJson` now supports customization via `ToJsonOptions`. - -- Added an overload for the `collect` macro that inferes the container type based - on the syntax of the last expression. Works with std seqs, tables and sets. - -- Added `randState` template that exposes the default random number generator. - Useful for library authors. - -- Added `random.initRand()` overload with no argument which uses the current time as a seed. - -- `random.initRand(seed)` now allows `seed == 0`. - -- Added `std/sysrand` module to get random numbers from a secure source - provided by the operating system. - -- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates - case statement to parse string to enum. -- Added `items` for enums with holes. -- Added `symbolName` to return the enum symbol name ignoring the human readable name. -- Added `symbolRank` to return the index in which an enum member is listed in an enum. - -- Removed deprecated `iup` module from stdlib, it has already moved to - [nimble](https://github.com/nim-lang/iup). - -- various functions in `httpclient` now accept `url` of type `Uri`. Moreover `request` function's - `httpMethod` argument of type `string` was deprecated in favor of `HttpMethod` enum type. - -- `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. - -- Added `cmpMem` to `system`. - -- `doAssertRaises` now correctly handles foreign exceptions. - -- Added `asyncdispatch.activeDescriptors` that returns the number of currently - active async event handles/file descriptors. - -- Added `getPort` to `asynchttpserver`. - -- `--gc:orc` is now 10% faster than previously for common workloads. If - you have trouble with its changed behavior, compile with `-d:nimOldOrc`. - -- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, - determining preferred I/O block size for this file object. - -- Added `os.getCacheDir()` to return platform specific cache directory. - -- Added a simpler to use `io.readChars` overload. - -- Added `**` to jsffi. - -- `writeStackTrace` is available in JS backend now. - -- Added `decodeQuery` to `std/uri`. - -- `strscans.scanf` now supports parsing single characters. - -- `strscans.scanTuple` added which uses `strscans.scanf` internally, - returning a tuple which can be unpacked for easier usage of `scanf`. - -- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`, - if the iterable yields a built-in settable type. - -- Added `setutils.fullSet` which returns a full built-in `set` for a valid type. - -- Added `setutils.complement` which returns the complement of a built-in `set`. - -- Added `setutils.[]=`. - -- Added `math.isNaN`. - -- Added `jsbigints` module, arbitrary precision integers for JavaScript target. - -- Added `math.copySign`. - -- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList` - and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements - shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes - its argument, `addMoved`, is also supplied. - -- Added `euclDiv` and `euclMod` to `math`. - -- Added `httpcore.is1xx` and missing HTTP codes. - -- Added `jsconsole.jsAssert` for JavaScript target. - -- Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs. - https://www.freedesktop.org/software/systemd/man/os-release.html - -- Added `socketstream` module that wraps sockets in the stream interface - -- Added `sugar.dumpToString` which improves on `sugar.dump`. - -- Added `math.signbit`. - -- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) - -- In `lists`: renamed `append` to `add` and retained `append` as an alias; - added `prepend` and `prependMoved` analogously to `add` and `addMoved`; - added `remove` for `SinglyLinkedList`s. - -- Deprecated `any`. See https://github.com/nim-lang/RFCs/issues/281 - -- Added optional `options` argument to `copyFile`, `copyFileToDir`, and - `copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are - followed (copy files symlinks point to); on Windows, `options` argument is - ignored and symlinks are skipped. - -- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as - symlinks (instead of skipping them as it was before); on Windows symlinks are - skipped. - -- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks - (instead of skipping them sometimes as it was before). - -- Added optional `followSymlinks` argument to `setFilePermissions`. - -- Added `os.isAdmin` to tell whether the caller's process is a member of the - Administrators local group (on Windows) or a root (on POSIX). - -- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C). - -- Added `compilesettings.SingleValueSetting.libPath`. - -- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding - issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages) - for modules importing `std/wrapnils`. - Added `??.` macro which returns an `Option`. - `std/wrapnils` can now be used to protect against `FieldDefect` errors in - case objects, generates optimal code (no overhead compared to manual - if-else branches), and preserves lvalue semantics which allows modifying - an expression. - -- Added `math.frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead. - -- `parseopt.initOptParser` has been made available and `parseopt` has been - added back to `prelude` for all backends. Previously `initOptParser` was - unavailable if the `os` module did not have `paramCount` or `paramStr`, - but the use of these in `initOptParser` were conditionally to the runtime - arguments passed to it, so `initOptParser` has been changed to raise - `ValueError` when the real command line is not available. `parseopt` was - previously excluded from `prelude` for JS, as it could not be imported. - -- Added `system.prepareStrMutation` for better support of low - level `moveMem`, `copyMem` operations for Orc's copy-on-write string - implementation. - -- Added `std/strbasics` for high performance string operations. - Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. - -- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` - and `$none(int)` to `"none(int)"` instead of `"None[int]"`. - -- Added `algorithm.merge`. - -- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target. - -- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) wrapper for JavaScript target. - -- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) wrapper for JavaScript target. - -- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible - with most other languages. - -- Removed support for named procs in `sugar.=>`. - -- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). - -- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). - -- `std/times`: - Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time - zone offsets without colons, e.g. `UTC+7 -> +0700`. - - Added `dateTime` and deprecated `initDateTime`. - -- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. - -- Added dollar `$` and `len` for `jsre.RegExp`. - -- Added `std/tasks`. - -- Added `hasDataBuffered` to `asyncnet`. - -- Added `std/tempfiles`. - -- Added `genasts.genAst` that avoids the problems inherent with `quote do` and can - be used as a replacement. - -- Added `copyWithin` [for `seq` and `array` for JavaScript targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin). - -- Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place. - -- Added setCurrentException for JS backend. - -- Added `dom.scrollIntoView` proc with options - -- Added `dom.setInterval`, `dom.clearInterval` overloads. - -- Merged `dom_extensions` module into `dom` module, - it was a module with a single line, see https://github.com/nim-lang/RFCs/issues/413 - -- Allow reading parameters when compiling for Nintendo Switch. - -- Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises a defect - if the slice is out of bounds, likewise with `strutils.delete`. ## Language changes -- The `cstring` doesn't support `[]=` operator in JS backend. - -- nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. - -- The required name of case statement macros for the experimental - `caseStmtMacros` feature has changed from `match` to `` `case` ``. - -- `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages. - -- The unary minus in `-1` is now part of the integer literal, it is now parsed as a single token. - This implies that edge cases like `-128'i8` finally work correctly. - -- Custom numeric literals (e.g. `-128'bignum`) are now supported. - -- Tuple expressions are now parsed consistently as - `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. - -- Added `iterable[T]` type class to match called iterators, which enables writing: - `template fn(a: iterable)` instead of `template fn(a: untyped)` - -- A new import syntax `import foo {.all.}` now allows to import all symbols (public or private) - from `foo`. This can be useful for testing purposes. - -- Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields - for an object type in the current scope. - -- `typeof(voidStmt)` now works and returns `void`. - -- The `gc:orc` algorithm was refined so that custom container types can participate in the - cycle collection process. See the documentation of `=trace` for more details. - -- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. - This is only supported for `--gc:orc` or `--gc:arc`. - -- The effect system was refined and there is a new `.effectsOf` annotation that does - explicitly what was previously done implicitly. See the manual for details. - To write code that is portable with older Nim versions, use this idiom: - -```nim - -when defined(nimHasEffectsOf): - {.experimental: "strictEffects".} -else: - {.pragma: effectsOf.} - -proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.} - -``` - - To enable the new effect system, use --experimental:strictEffects. - - -- Nim now supports a small subset of Unicode operators as operator symbols. - The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔". - To enable this feature, use `--experimental:unicodeOperators`. Note that due - to parser limitations you **cannot** enable this feature via a - pragma `{.experimental: "unicodeOperators".}` reliably, you need to enable - it via the command line or in a configuration file. - -- There is a new `cast` section `{.cast(uncheckedAssign).}: body` that disables some - compiler checks regarding `case objects`. This allows serialization libraries - to avoid ugly, non-portable solutions. See https://github.com/nim-lang/RFCs/issues/407 - for more details. - -- Enum values can now be overloaded. This needs to be enabled - via `{.experimental: "overloadableEnums".}`. We hope that this feature allows for the - development of more fluent (less ugly) APIs. See https://github.com/nim-lang/RFCs/issues/373 - for more details. ## Compiler changes -- Added `--declaredLocs` to show symbol declaration location in messages. - -- You can now enable/disable VM tracing in user code via `vmutils.vmTrace`. - -- Deprecated `TaintedString` and `--taintmode`. - -- Deprecated `--nilseqs` which is now a noop. - -- Added `--spellSuggest` to show spelling suggestions on typos. - -- Added `--filenames:abs|canonical|legacyRelProj` which replaces --listFullPaths:on|off - -- Added `--processing:dots|filenames|off` which customizes `hintProcessing` - -- Added `--unitsep:on|off` to control whether to add ASCII unit separator `\31` before a newline - for every generated message (potentially multiline), so tooling can tell when messages start and end. - -- Source+Edit links now appear on top of every docgen'd page when - `nim doc --git.url:url ...` is given. - -- Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`. - -- VM now supports `addr(mystring[ind])` (index + index assignment) - -- Added `--hintAsError` with similar semantics as `--warningAsError`. - -- TLS: OSX now uses native TLS (`--tlsEmulation:off`), TLS now works with importcpp non-POD types, - such types must use `.cppNonPod` and `--tlsEmulation:off`should be used. - -- Now array literals(JS backend) uses JS typed arrays when the corresponding js typed array exists, - for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. - -- docgen: rst files can now use single backticks instead of double backticks and correctly render - in both rst2html (as before) as well as common tools rendering rst directly (e.g. github), by - adding: `default-role:: code` directive inside the rst file, which is now handled by rst2html. - -- Added `-d:nimStrictMode` in CI in several places to ensure code doesn't have certain hints/warnings - -- Added `then`, `catch` to `asyncjs`, for now hidden behind `-d:nimExperimentalAsyncjsThen`. - -- `--newruntime` and `--refchecks` are deprecated. - -- Added `unsafeIsolate` and `extract` to `std/isolation`. - -- `--hint:CC` now goes to stderr (like all other hints) instead of stdout. - -- `--hint:all:on|off` is now supported to select or deselect all hints; it - differs from `--hints:on|off` which acts as a (reversible) gate. - Likewise with `--warning:all:on|off`. - -- json build instructions are now generated in `$nimcache/outFileBasename.json` - instead of `$nimcache/projectName.json`. This allows avoiding recompiling a given project - compiled with different options if the output file differs. - -- `--usenimcache` (implied by `nim r main`) now generates an output file that includes a hash of - some of the compilation options, which allows caching generated binaries: - nim r main # recompiles - nim r -d:foo main # recompiles - nim r main # uses cached binary - nim r main arg1 arg2 # ditto (runtime arguments are irrelevant) - -- `nim r` now supports cross compilation from unix to windows when specifying `-d:mingw` by using wine, - e.g.: `nim r --eval:'import os; echo "a" / "b"'` prints `a\b` - -- `nim` can compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off -d:nimVersion140 compiler/nim`. - `-d:nimVersion140` is not needed for bootstrapping, only for building 1.4.0 from devel. - -- The style checking of the compiler now supports a `--styleCheck:usages` switch. This switch - enforces that every symbol is written as it was declared, not enforcing - the official Nim style guide. To be enabled, this has to be combined either - with `--styleCheck:error` or `--styleCheck:hint`. ## Tool changes -- `nimscript` now handles `except Exception as e`. -- `nim e` now accepts arbitrary file extensions for the nimscript file, - although `.nims` is still the preferred extension in general. -- Latex doc generation is revised: output `.tex` files should be compiled - by `xelatex` (not by `pdflatex` as before). Now default Latex settings - provide support for Unicode and do better job for avoiding margin overflows. - -- Implemented `doc2tex` compiler command which converts documentation in - `.nim` files to Latex. - -- The rst parser now supports markdown table syntax. - Known limitations: - - cell alignment is not supported, i.e. alignment annotations in a delimiter - row (`:---`, `:--:`, `---:`) are ignored, - - every table row must start with `|`, e.g. `| cell 1 | cell 2 |`. - -- `fusion` is now un-bundled from nim, `./koch fusion` will - install it via nimble at a fixed hash. - -- testament: added `nimoutFull: bool` spec to compare full output of compiler - instead of a subset. diff --git a/changelogs/changelog_1_6_0.md b/changelogs/changelog_1_6_0.md new file mode 100644 index 000000000..1ce6c2093 --- /dev/null +++ b/changelogs/changelog_1_6_0.md @@ -0,0 +1,927 @@ +# v1.6.0 - 2021-10-14 + + + +# Major new features + +With so many new features, pinpointing the most salient ones is a subjective exercise, +but here are a select few: + + +## `iterable[T]` + +The `iterable[T]` type class was added to match called iterators, +which solves a number of long-standing issues related to iterators. +Example: + +```nim +iterator iota(n: int): int = + for i in 0.. response.json()) + .then((json: JsObject) => console.log(json)) + .catch((err: Error) => console.log("Request Failed", err)) +discard fn() +``` + + +## New `std/tasks` module + +Provides basic primitives for creating parallel programs. +Example: +```nim +import std/tasks +var num = 0 +proc hello(a: int) = num+=a + +let b = toTask hello(13) # arguments must be isolated, see `std/isolation` +b.invoke() +assert num == 13 +b.invoke() # can be called again +assert num == 26 +``` + + +## New module: `std/genasts` + +Provides an API `genAst` that avoids the problems inherent with `quote do` and can +be used as a replacement. +Example showing how this could be used for writing a simplified version of `unittest.check`: +```nim +import std/[genasts, macros, strutils] +macro check2(cond: bool): untyped = + assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind + result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]): + # each local symbol we access must be explicitly captured + if not cond: + doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] +let a = 3 +check2 a*2 == a+3 +if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4' +``` + +See PR [#17426](https://github.com/nim-lang/Nim/pull/17426) for details. + + +## New module: `std/setutils` + +- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`, + if the iterable yields a built-in settable type. +- Added `setutils.fullSet` which returns a full built-in `set` for a valid type. +- Added `setutils.complement` which returns the complement of a built-in `set`. +- Added `setutils.[]=`. + + +## New module: `std/enumutils` + +- Added `genEnumCaseStmt` macro that generates + case statement to parse string to enum. +- Added `items` for enums with holes. +- Added `symbolName` to return the `enum` symbol name ignoring the human-readable name. +- Added `symbolRank` to return the index in which an `enum` member is listed in an enum. + + +## `system` + +- Added `system.prepareMutation` for better support of low + level `moveMem`, `copyMem` operations for `gc:orc`'s copy-on-write string + implementation. +- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible + with most other languages. +- Added `cmpMem` to `system`. +- `doAssertRaises` now correctly handles foreign exceptions. +- `addInt` now supports unsigned integers. + +Compatibility notes: +- `system.delete` had surprising behavior when the index passed to it was out of + bounds (it would delete the last entry then). Compile with `-d:nimStrictDelete` so + that an index error is produced instead. Be aware however that your code might depend on + this quirky behavior so a review process is required on your part before you can + use `-d:nimStrictDelete`. To make this review easier, use the `-d:nimAuditDelete` + switch, which pretends that `system.delete` is deprecated so that it is easier + to see where it was used in your code. + `-d:nimStrictDelete` will become the default in upcoming versions. +- `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`. + Please use `char` or `uint8` instead. +- `repr` now doesn't insert trailing newlines; the previous behavior was very inconsistent, + see [#16034](https://github.com/nim-lang/Nim/pull/16034). + Use `-d:nimLegacyReprWithNewline` for the previous behavior. + `repr` now also renders ASTs correctly for user defined literals, setters, `do`, etc. +- Deprecated `any`. See RFC [#281](https://github.com/nim-lang/RFCs/issues/281). +- The unary slice `..b` was deprecated, use `0..b` instead. + + +## `std/math` + +- Added `almostEqual` for comparing two float values using a machine epsilon. +- Added `clamp` which allows using a `Slice` to clamp to a value. +- Added `ceilDiv` for integer division that rounds up. +- Added `isNaN`. +- Added `copySign`. +- Added `euclDiv` and `euclMod`. +- Added `signbit`. +- Added `frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead. + +Compatibility notes: +- `math.round` now rounds "away from zero" in the JS backend, which is consistent + with other backends. See [#9125](https://github.com/nim-lang/Nim/pull/9125). + Use `-d:nimLegacyJsRound` for the previous behavior. + + +## Random number generators: `std/random`, `std/sysrand`, `std/oids` + +- Added `std/sysrand` module (see details above). +- Added `randState` template that exposes the default random number generator. + Useful for library authors. +- Added `initRand()` overload with no argument which uses the current time as a seed. +- `initRand(seed)` now allows `seed == 0`. +- Fixed overflow bugs. +- Fix `initRand` to avoid random number sequences overlapping, refs + [#18744](https://github.com/nim-lang/Nim/pull/18744). +- `std/oids` now uses `std/random`. + +Compatibility notes: +- Deprecated `std/mersenne`. +- `random.initRand(seed)` now produces non-skewed values for the first call to + `rand()` after initialization with a small (< 30000) seed. + Use `-d:nimLegacyRandomInitRand` to restore previous behavior for a transition + time, see PR [#17467](https://github.com/nim-lang/Nim/pull/17467). + + +## `std/json`, `std/jsonutils` + +- With `-d:nimPreviewJsonutilsHoleyEnum`, `jsonutils` now can serialize/deserialize + holey enums as regular enums (via `ord`) instead of as strings. + It is expected that this behavior becomes the new default in upcoming versions. + `toJson` now serializes `JsonNode` as is via reference (without a deep copy) + instead of treating `JsonNode` as a regular ref object, + this can be customized via `jsonNodeMode`. +- `std/json` and `std/jsonutils` now serialize `NaN`, `Inf`, `-Inf` as strings, + so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` + which was invalid JSON. +- `std/json` can now handle integer literals and floating point literals of + arbitrary length and precision. + Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are + kept as string literals and one can use external BigNum libraries to handle these. + The `parseFloat` family of functions also has now optional `rawIntegers` and + `rawFloats` parameters that can be used to enforce that all integer or float + literals remain in the "raw" string form so that client code can easily treat + small and large numbers uniformly. +- Added `BackwardsIndex` overload for `JsonNode`. +- `json.%`,`json.to`, `jsonutils.fromJson`,`jsonutils.toJson` now work with `uint|uint64` + instead of raising (as in 1.4) or giving wrong results (as in 1.2). +- `std/jsonutils` now handles `cstring` (including as Table key), and `set`. +- Added `jsonutils.jsonTo` overload with `opt = Joptions()` param. +- `jsonutils.toJson` now supports customization via `ToJsonOptions`. +- `std/json`, `std/jsonutils` now support round-trip serialization when + `-d:nimPreviewFloatRoundtrip` is used. + + +## `std/typetraits`, `std/compilesettings` + +- `distinctBase` now is identity instead of error for non distinct types. +- `distinctBase` now allows controlling whether to be recursive or not. +- Added `enumLen` to return the number of elements in an enum. +- Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. +- Added `hasClosure`. +- Added `pointerBase` to return `T` for `ref T | ptr T`. +- Added `compilesettings.SingleValueSetting.libPath`. + + +## networking: `std/net`, `std/asyncnet`, `std/htmlgen`, `std/httpclient`, `std/asyncdispatch`, `std/asynchttpserver`, `std/httpcore` + +- Fixed buffer overflow bugs in `std/net`. +- Exported `sslHandle` from `std/net` and `std/asyncnet`. +- Added `hasDataBuffered` to `std/asyncnet`. +- Various functions in `std/httpclient` now accept `url` of type `Uri`. + Moreover, the `request` function's `httpMethod` argument of type `string` was + deprecated in favor of `HttpMethod` `enum` type; see + [#15919](https://github.com/nim-lang/Nim/pull/15919). +- Added `asyncdispatch.activeDescriptors` that returns the number of currently + active async event handles/file descriptors. +- Added `getPort` to `std/asynchttpserver` to resolve OS-assigned `Port(0)`; + this is usually recommended instead of hardcoding ports which can lead to + "Address already in use" errors. +- Fixed premature garbage collection in `std/asyncdispatch`, when a stacktrace + override is in place. +- Added `httpcore.is1xx` and missing HTTP codes. +- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). + +Compatibility notes: +- On Windows, the SSL library now checks for valid certificates. + For this purpose it uses the `cacert.pem` file, which was extracted + from `https://curl.se/ca/cacert.pem`. Besides + the OpenSSL DLLs (e.g. `libssl-1_1-x64.dll`, `libcrypto-1_1-x64.dll`) you + now also need to ship `cacert.pem` with your `.exe` file. + + +## `std/hashes` + +- `hashes.hash` can now support `object` and `ref` (can be overloaded in user code), + if `-d:nimPreviewHashRef` is used. It is expected that this behavior + becomes the new default in upcoming versions. +- `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`. + `hashes.hash(closure)` has also been improved. + + +## OS: `std/os`, `std/io`, `std/socketstream`, `std/linenoise`, `std/tempfiles` + +- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, + determining preferred I/O block size for this file object. +- Added `os.getCacheDir()` to return platform specific cache directory. +- Improved `os.getTempDir()`, see PR [#16914](https://github.com/nim-lang/Nim/pull/16914). +- Added `os.isAdmin` to tell whether the caller's process is a member of the + Administrators local group (on Windows) or a root (on POSIX). +- Added optional `options` argument to `copyFile`, `copyFileToDir`, and + `copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are + followed (copy files symlinks point to); on Windows, `options` argument is + ignored and symlinks are skipped. +- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as + symlinks (instead of skipping them as it was before); on Windows symlinks are + skipped. +- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks + (instead of skipping them sometimes as it was before). +- Added optional `followSymlinks` argument to `setFilePermissions`. +- Added a simpler to use `io.readChars` overload. +- Added `socketstream` module that wraps sockets in the stream interface. +- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C). + + +## Environment variable handling + +- Empty environment variable values are now supported across OS's and backends. +- Environment variable APIs now work in multithreaded scenarios, by delegating to + direct OS calls instead of trying to keep track of the environment. +- `putEnv`, `delEnv` now work at compile time. +- NodeJS backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. + +Compatibility notes: +- `std/os`: `putEnv` now raises if the first argument contains a `=`. + + +## POSIX + +- On POSIX systems, the default signal handlers used for Nim programs (it's + used for printing the stacktrace on fatal signals) will now re-raise the + signal for the OS default handlers to handle. + This lets the OS perform its default actions, which might include core + dumping (on select signals) and notifying the parent process about the cause + of termination. +- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` + for previous behavior. +- Added `posix_utils.osReleaseFile` to get system identification from `os-release` + file on Linux and the BSDs. + ([link](https://www.freedesktop.org/software/systemd/man/os-release.html)) +- Removed undefined behavior for `posix.open`. + + +## `std/prelude` + +- `std/strformat` is now part of `include std/prelude`. +- Added `std/sequtils` import to `std/prelude`. +- `std/prelude` now works with the JS target. +- `std/prelude` can now be used via `include std/prelude`, but `include prelude` still works. + + +## String manipulation: `std/strformat`, `std/strbasics` + +- Added support for parenthesized expressions. +- Added support for const strings instead of just string literals. +- Added `std/strbasics` for high-performance string operations. +- Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. + + +## `std/wrapnils` + +- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding + issues like bug [#13063](https://github.com/nim-lang/Nim/issues/13063) + (which affected error messages) for modules importing `std/wrapnils`. +- Added `??.` macro which returns an `Option`. +- `std/wrapnils` can now be used to protect against `FieldDefect` errors in + case objects, generates optimal code (no overhead compared to manual + if-else branches), and preserves lvalue semantics which allows modifying + an expression. + + +## Containers: `std/algorithm`, `std/lists`, `std/sequtils`, `std/options`, `std/packedsets` + +- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` + iterators (it never worked reliably). +- Added `algorithm.merge`. +- In `std/lists`: renamed `append` to `add` and retained `append` as an alias; + added `prepend` and `prependMoved` analogously to `add` and `addMoved`; + added `remove` for `SinglyLinkedList`s. +- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList` + and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements + shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes + its argument, `addMoved`, is also supplied. + See PRs [#16362](https://github.com/nim-lang/Nim/pull/16362), + [#16536](https://github.com/nim-lang/Nim/pull/16536). +- New module: `std/packedsets`. + Generalizes `std/intsets`, see PR [#15564](https://github.com/nim-lang/Nim/pull/15564). + +Compatibility notes: +- Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises + a defect if the slice is out of bounds, likewise with `strutils.delete`. +- Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` + in `std/algorithm`. +- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` + and `$none(int)` to `"none(int)"` instead of `"None[int]"`. + + +## `std/times` + +- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time + zone offsets without colons, e.g. `UTC+7 -> +0700`. +- Added `dateTime` and deprecated `initDateTime`. + + +## `std/macros` and AST + +- New module `std/genasts`, see description above. +- The required name of case statement macros for the experimental + `caseStmtMacros` feature has changed from `match` to `` `case` ``. +- Tuple expressions are now parsed consistently as + `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. +- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes + in a collapsed way. + Use `-d:nimLegacyMacrosCollapseSymChoice` to get the previous behavior. +- Made custom op in `macros.quote` work for all statements. + + +## `std/sugar` + +- Added `sugar.dumpToString` which improves on `sugar.dump`. +- Added an overload for the `collect` macro that infers the container type based + on the syntax of the last expression. Works with std seqs, tables and sets. + +Compatibility notes: +- Removed support for named procs in `sugar.=>`. + + +## Parsing: `std/parsecfg`, `std/strscans`, `std/uri` + +- Added `sections` iterator in `parsecfg`. +- `strscans.scanf` now supports parsing single characters. +- Added `strscans.scanTuple` which uses `strscans.scanf` internally, + returning a tuple which can be unpacked for easier usage of `scanf`. +- Added `decodeQuery` to `std/uri`. +- `parseopt.initOptParser` has been made available and `parseopt` has been + added back to `std/prelude` for all backends. Previously `initOptParser` was + unavailable if the `std/os` module did not have `paramCount` or `paramStr`, + but the use of these in `initOptParser` were conditionally to the runtime + arguments passed to it, so `initOptParser` has been changed to raise + `ValueError` when the real command line is not available. `parseopt` was + previously excluded from `std/prelude` for JS, as it could not be imported. + +Compatibility notes: +- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` + characters in the decoded values. Prior versions would raise an error. This is + no longer the case to comply with the HTML spec and other languages' + implementations. Old behavior can be obtained with + `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same + underlying code is also updated the same way. + + +## JS stdlib changes + +- Added `std/jsbigints` module, which provides arbitrary precision integers for the JS target. +- Added `setCurrentException` for the JS backend. +- `writeStackTrace` is available in the JS backend now. +- Added `then`, `catch` to `std/asyncjs` for promise pipelining, for now hidden + behind `-d:nimExperimentalAsyncjsThen`. +- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) + wrapper for the JS target. +- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) + wrapper for the JS target. +- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) + wrapper for the JS target. +- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). +- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. +- Added dollar `$` and `len` for `jsre.RegExp`. +- Added `jsconsole.jsAssert` for the JS target. +- Added `**` to `std/jsffi`. +- Added `copyWithin` [for `seq` and `array` for JS targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin). +- In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. + Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. +- Added `dom.scrollIntoView` proc with options. +- Added `dom.setInterval`, `dom.clearInterval` overloads. +- Merged `std/dom_extensions` into the `std/dom` module, + as it was a module with a single line, see RFC [#413](https://github.com/nim-lang/RFCs/issues/413). +- `$` now gives more correct results on the JS backend. + + +## JS compiler changes + +- `cstring` doesn't support the `[]=` operator anymore in the JS backend. +- Array literals now use JS typed arrays when the corresponding JS typed array exists, + for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. + + +## VM and nimscript backend + +- VM now supports `addr(mystring[ind])` (index + index assignment). +- `nimscript` now handles `except Exception as e`. +- `nil` dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. +- `static[T]` now works better, refs [#17590](https://github.com/nim-lang/Nim/pull/17590), + [#15853](https://github.com/nim-lang/Nim/pull/15853). +- `distinct T` conversions now work in VM. +- `items(cstring)` now works in VM. +- Fix `addr`, `len`, `high` in VM ([#16002](https://github.com/nim-lang/Nim/pull/16002), + [#16610](https://github.com/nim-lang/Nim/pull/16610)). +- `std/cstrutils` now works in VM. + + +## OS/platform-specific notes + +- Support for Apple silicon/M1. +- Support for 32-bit RISC-V, refs [#16231](https://github.com/nim-lang/Nim/pull/16231). +- Support for armv8l, refs [#18901](https://github.com/nim-lang/Nim/pull/18901). +- Support for CROSSOS, refs [#18889](https://github.com/nim-lang/Nim/pull/18889). +- The allocator for Nintendo Switch, which was nonfunctional because + of breaking changes in libnx, was removed, in favor of the new `-d:nimAllocPagesViaMalloc` option. +- Allow reading parameters when compiling for Nintendo Switch. +- `--nimcache` now correctly works in a cross-compilation setting. +- Cross compilation targeting Windows was improved. +- This now works from macOS/Linux: `nim r -d:mingw main` + + + +## Performance / memory optimizations + +- The comment field in PNode AST was moved to a side channel, reducing overall + memory usage during compilation by a factor 1.25x +- `std/jsonutils` deserialization is now up to 20x faster. +- `os.copyFile` is now 2.5x faster on macOS, by using `copyfile` from `copyfile.h`; + use `-d:nimLegacyCopyFile` for macOS < 10.5. +- Float to string conversion is now 10x faster thanks to the Dragonbox algorithm, + with `-d:nimPreviewFloatRoundtrip`. +- `newSeqWith` is 3x faster. +- CI now supports batching (making Windows CI 2.3X faster). +- Sets now uses the optimized `countSetBits` proc, see PR + [#17334](https://github.com/nim-lang/Nim/pull/17334). + + +## Debugging + +- You can now enable/disable VM tracing in user code via `vmutils.vmTrace`. +- `koch tools` now builds `bin/nim_dbg` which allows easy access to a debug version + of Nim without recompiling. +- Added new module `compiler/debugutils` to help with debugging Nim compiler. +- Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints` and + used it in more contexts; this flag which works in tandem with `--stackTraceMsgs` + to show user code context in compiler stacktraces. + + +## Type system + +- `typeof(voidStmt)` now works and returns `void`. +- `enum` values can now be overloaded. This needs to be enabled + via `{.experimental: "overloadableEnums".}`. We hope that this feature allows + for the development of more fluent (less ugly) APIs. + See RFC [#373](https://github.com/nim-lang/RFCs/issues/373) for more details. +- A type conversion from one `enum` type to another now produces an `[EnumConv]` warning. + You should use `ord` (or `cast`, but the compiler won't help, if you misuse it) instead. + ```nim + type A = enum a1, a2 + type B = enum b1, b2 + echo a1.B # produces a warning + echo a1.ord.B # produces no warning + ``` +- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning. + This warning will become an error in future versions! Use an explicit conversion + like `cstring(x)` in order to silence the warning. +- There is a new warning for *any* type conversion to `enum` that can be enabled via + `.warning[AnyEnumConv]:on` or `--warning:AnyEnumConv:on`. +- Reusing a type name in a different scope now works, refs [#17710](https://github.com/nim-lang/Nim/pull/17710). +- Fixed implicit and explicit generics in procedures, refs [#18808](https://github.com/nim-lang/Nim/pull/18808). + + +## New-style concepts + +Example: +```nim +type + Comparable = concept # no T, an atom + proc cmp(a, b: Self): int +``` +The new design does not rely on `system.compiles` and may compile faster. +See PR [#15251](https://github.com/nim-lang/Nim/pull/15251) +and RFC [#168](https://github.com/nim-lang/RFCs/issues/168) for details. + + +## Lexical / syntactic + +- Nim now supports a small subset of Unicode operators as operator symbols. + The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔". + To enable this feature, use `--experimental:unicodeOperators`. Note that due + to parser limitations you **cannot** enable this feature via a + pragma `{.experimental: "unicodeOperators".}` reliably, you need to enable + it via the command line or in a configuration file. +- `var a {.foo.} = expr` now works inside templates (except when `foo` is overloaded). + + +## Compiler messages, error messages, hints, warnings + +- Significant improvement to error messages involving effect mismatches, + see PRs [#18384](https://github.com/nim-lang/Nim/pull/18384), + [#18418](https://github.com/nim-lang/Nim/pull/18418). +- Added `--declaredLocs` to show symbol declaration location in error messages. +- Added `--spellSuggest` to show spelling suggestions on typos. +- Added `--processing:dots|filenames|off` which customizes `hintProcessing`; + `--processing:filenames` shows which include/import modules are being compiled as an import stack. +- `FieldDefect` messages now shows discriminant value + lineinfo, in all backends (C, JS, VM) +- Added `--hintAsError` with similar semantics as `--warningAsError`. +- Added `--unitsep:on|off` to control whether to add ASCII unit separator `\31` + before a newline for every generated message (potentially multiline), + so tooling can tell when messages start and end. +- Added `--filenames:abs|canonical|legacyRelProj` which replaces `--listFullPaths:on|off` +- `--hint:all:on|off` is now supported to select or deselect all hints; it + differs from `--hints:on|off` which acts as a (reversible) gate. + Likewise with `--warning:all:on|off`. +- The style checking of the compiler now supports a `--styleCheck:usages` switch. + This switch enforces that every symbol is written as it was declared, not enforcing + the official Nim style guide. To be enabled, this has to be combined either + with `--styleCheck:error` or `--styleCheck:hint`. +- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for + previous behavior. +- `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages. +- `runnableExamples` now show originating location in stacktraces on failure. +- `SuccessX` message now shows more useful information. +- New `DuplicateModuleImport` warning; improved `UnusedImport` and + `XDeclaredButNotUsed` accuracy. + +Compatibility notes: +- `--hint:CC` now prints to stderr (like all other hints) instead of stdout. + + +## Building and running Nim programs, configuration system + +- JSON build instructions are now generated in `$nimcache/outFileBasename.json` + instead of `$nimcache/projectName.json`. This allows avoiding recompiling a + given project compiled with different options if the output file differs. +- `--usenimcache` (implied by `nim r main`) now generates an output file that includes + a hash of some of the compilation options, which allows caching generated binaries: + ```bash + nim r main # recompiles + nim r -d:foo main # recompiles + nim r main # uses cached binary + nim r main arg1 arg2 # likewise (runtime arguments are irrelevant) + ``` +- `nim r` now supports cross compilation from unix to windows when specifying + `-d:mingw` by using Wine, e.g.: + `nim r --eval:'import os; echo "a" / "b"'` prints `a\b`. +- `nim` can compile version 1.4.0 as follows: + `nim c --lib:lib --stylecheck:off -d:nimVersion140 compiler/nim`. + `-d:nimVersion140` is not needed for bootstrapping, only for building 1.4.0 from devel. +- `nim e` now accepts arbitrary file extensions for the nimscript file, + although `.nims` is still the preferred extension in general. +- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. + The downside is that these defines now have custom logic that doesn't apply for + other defines. + + +## Multithreading + +- TLS: macOS now uses native TLS (`--tlsEmulation:off`). TLS now works with + `importcpp` non-POD types; such types must use `.cppNonPod` and + `--tlsEmulation:off`should be used. +- Added `unsafeIsolate` and `extract` to `std/isolation`. +- Added `std/tasks`, see description above. + + +## Memory management + +- `--gc:arc` now bootstraps (PR [#17342](https://github.com/nim-lang/Nim/pull/17342)). +- Lots of improvements to `gc:arc`, `gc:orc`, see PR + [#15697](https://github.com/nim-lang/Nim/pull/15697), + [#16849](https://github.com/nim-lang/Nim/pull/16849), + [#17993](https://github.com/nim-lang/Nim/pull/17993). +- `--gc:orc` is now 10% faster than previously for common workloads. + If you have trouble with its changed behavior, compile with `-d:nimOldOrc`. +- The `--gc:orc` algorithm was refined so that custom container types can participate in the + cycle collection process. See the documentation of `=trace` for more details. +- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. + This is only supported for `--gc:orc` or `--gc:arc`. + +Compatibility notes: +- `--newruntime` and `--refchecks` are deprecated, + use `--gc:arc`, `--gc:orc`, or `--gc:none` as appropriate instead. + + +## Docgen + +- docgen: RST files can now use single backticks instead of double backticks and + correctly render in both `nim rst2html` (as before) as well as common tools rendering + RST directly (e.g. GitHub). + This is done by adding the `default-role:: code` directive inside the RST file + (which is now handled by `nim rst2html`). +- Source+Edit links now appear on top of every docgen'd page when + `nim doc --git.url:url ...` is given. +- Latex doc generation is revised: output `.tex` files should be compiled + by `xelatex` (not by `pdflatex` as before). Now default Latex settings + provide support for Unicode and better avoid margin overflows. + The minimum required version is TeXLive 2018 (or an equivalent MikTeX version). +- The RST parser now supports footnotes, citations, admonitions, and short style + references with symbols. +- The RST parser now supports Markdown table syntax. + Known limitations: + - cell alignment is not supported, i.e. alignment annotations in a delimiter + row (`:---`, `:--:`, `---:`) are ignored + - every table row must start with `|`, e.g. `| cell 1 | cell 2 |`. +- Implemented `doc2tex` compiler command which converts documentation in + `.nim` files to Latex. +- docgen now supports syntax highlighting for inline code. +- docgen now supports same-line doc comments: + ```nim + func fn*(a: int): int = 42 ## Doc comment + ``` +- docgen now renders `deprecated` and other pragmas. +- `runnableExamples` now works with templates and nested templates. +- `runnableExamples: "-r:off"` now works for examples that should compile but not run. +- `runnableExamples` now renders code verbatim, and produces correct code in all cases. +- docgen now shows correct, canonical import paths in docs. +- docgen now shows all routines in sidebar, and the proc signature is now shown in sidebar. + + +## Effects and checks + +- Significant improvement to error messages involving effect mismatches +- There is a new `cast` section `{.cast(uncheckedAssign).}: body` that disables some + compiler checks regarding `case objects`. This allows serialization libraries + to avoid ugly, non-portable solutions. See RFC + [#407](https://github.com/nim-lang/RFCs/issues/407) for more details. + + +## Tools + +- Major improvements to `nimgrep`, see PR [#15612 +](https://github.com/nim-lang/Nim/pull/15612). +- `fusion` is now un-bundled from Nim, `./koch fusion` will + install it via Nimble at a fixed hash. +- `testament`: added `nimoutFull: bool` spec to compare full output of compiler + instead of a subset; many bugfixes to testament. + + +## Misc/cleanups + +- Deprecated `TaintedString` and `--taintmode`. +- Deprecated `--nilseqs` which is now a noop. +- Added `-d:nimStrictMode` in CI in several places to ensure code doesn't have + certain hints/warnings. +- Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. +- `[skip ci]` now works in azure and CI pipelines, see detail in PR + [#17561](https://github.com/nim-lang/Nim/pull/17561). From c4c9876785a17f9b43bb1e0748eff67a71a7487f Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 14 Oct 2021 15:23:01 +0800 Subject: [PATCH 3071/4254] fix a potential bug (#18900) --- lib/std/private/digitsutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index 268a3ba7d..9be2ab3ef 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -95,7 +95,7 @@ proc addInt*(result: var string; x: int64) = var num: uint64 if x < 0: if x == low(int64): - num = uint64(x) + num = cast[uint64](x) else: num = uint64(-x) let base = result.len From 3493783d0f3f90b2a90c87b93c92360168272f34 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 14 Oct 2021 15:23:36 +0800 Subject: [PATCH 3072/4254] test whether it is unnecessary (#18893) --- compiler/semtypinst.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 0bb53e04d..5d300fc58 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -35,7 +35,7 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = proc searchInstTypes*(g: ModuleGraph; key: PType): PType = let genericTyp = key[0] if not (genericTyp.kind == tyGenericBody and - key[0] == genericTyp and genericTyp.sym != nil): return + genericTyp.sym != nil): return for inst in typeInstCacheItems(g, genericTyp.sym): if inst.id == key.id: return inst From 8a4eeba218b22d4258f95a279771851082a2e197 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 14 Oct 2021 09:56:58 +0200 Subject: [PATCH 3073/4254] try to fix broken ssl test (#18991) --- tests/untestable/thttpclient_ssl_remotenetwork.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim index f56fe274b..d8137e516 100644 --- a/tests/untestable/thttpclient_ssl_remotenetwork.nim +++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim @@ -48,7 +48,7 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win ("https://sha256.badssl.com/", good, "sha256"), ("https://sha384.badssl.com/", good, "sha384"), ("https://sha512.badssl.com/", good, "sha512"), - ("https://1000-sans.badssl.com/", good, "1000-sans"), + ("https://1000-sans.badssl.com/", bad, "1000-sans"), ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), ("https://ecc256.badssl.com/", good, "ecc256"), ("https://ecc384.badssl.com/", good, "ecc384"), From 73330711a3d753d25b073fb1dc24cb16e559724d Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 14 Oct 2021 23:55:05 +0800 Subject: [PATCH 3074/4254] make choosenim work on windows [backport] (#18993) --- bin/nim-gdb.bash | 1 - compiler/installer.ini | 1 - 2 files changed, 2 deletions(-) delete mode 120000 bin/nim-gdb.bash diff --git a/bin/nim-gdb.bash b/bin/nim-gdb.bash deleted file mode 120000 index f6eba4b0c..000000000 --- a/bin/nim-gdb.bash +++ /dev/null @@ -1 +0,0 @@ -nim-gdb \ No newline at end of file diff --git a/compiler/installer.ini b/compiler/installer.ini index 9e31b4e3f..41eee09f1 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -120,7 +120,6 @@ Files: "bin/nim" InstallScript: "yes" UninstallScript: "yes" Files: "bin/nim-gdb" -Files: "bin/nim-gdb.bash" [InnoSetup] From f4525efcf3b915be8e17c9730e9e0ffd0afe3a0f Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Fri, 15 Oct 2021 09:10:27 +0200 Subject: [PATCH 3075/4254] changelog_1_6_0: mention breaking change in effect tracking (#18995) --- changelogs/changelog_1_6_0.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/changelogs/changelog_1_6_0.md b/changelogs/changelog_1_6_0.md index 1ce6c2093..4a1047d20 100644 --- a/changelogs/changelog_1_6_0.md +++ b/changelogs/changelog_1_6_0.md @@ -905,6 +905,36 @@ Compatibility notes: to avoid ugly, non-portable solutions. See RFC [#407](https://github.com/nim-lang/RFCs/issues/407) for more details. +Compatibility notes: +- Fixed effect tracking for borrowed procs (see [#18882](https://github.com/nim-lang/Nim/pull/18882)). + One consequence is that, under some circumstances, Nim could previously permit a procedure with side effects to be written with `func` - you may need to change some occurrences of `func` to `proc`. + To illustrate, Nim versions before 1.6.0 compile the below without error + ```nim + proc print(s: string) = + echo s + + type + MyString = distinct string + + proc print(s: MyString) {.borrow.} + + func foo(s: MyString) = + print(s) + ``` + but Nim 1.6.0 produces the error + ``` + Error: 'foo' can have side effects + ``` + similar to how we expect that + ```nim + func print(s: string) = + echo s + ``` + produces + ``` + Error: 'print' can have side effects + ``` + ## Tools From 3b1a601fe1ad6ac27a21b5f28442474d47c60a2f Mon Sep 17 00:00:00 2001 From: ee7 <45465154+ee7@users.noreply.github.com> Date: Sat, 16 Oct 2021 11:25:05 +0200 Subject: [PATCH 3076/4254] sequtils: fix errors from `strictFuncs` use (#18998) Nim 1.4.x compiled the below code without error when using `--experimental:strictFuncs` import std/sequtils type Foo = ref object let foo1 = Foo() let foo2 = Foo() let foos = @[foo1, foo2] let fooTuples = @[(foo1, 1), (foo2, 2)] discard repeat(foo1, 3) discard zip(foos, foos) discard unzip(fooTuples) However, since 2020-12-09, devel Nim produced errors like /tmp/bar.nim(11, 15) template/generic instantiation of `repeat` from here /foo/nim/pure/collections/sequtils.nim(172, 6) Error: 'repeat' can have side effects an object reachable from 'x' is potentially mutated /foo/nim/pure/collections/sequtils.nim(183, 15) the mutation is here /foo/nim/pure/collections/sequtils.nim(183, 15) is the statement that connected the mutation to the parameter This commit reverts some `proc` to `func` changes so that code that: - calls `repeat`, `zip`, or `unzip` - and instantiates them with types containing `ref` can once again be compiled with `strictFuncs`. Otherwise, a user might be forced to drop or alter their `strictFuncs` use when upgrading from Nim 1.4.x, or when writing new code that uses these procedures (at least for now, with the current `strictFuncs` implementation). This commit also adds tests to assert that the remaining funcs in this module can be compiled with `strictFuncs` when used with types containing `ref`. The original batch of `proc` to `func` changes in `sequtils.nim` was in commit 6f57ebae349f, which was partially reverted in 38eb021f8158. See also: https://github.com/nim-lang/Nim/issues/16305 --- lib/pure/collections/sequtils.nim | 6 +++--- tests/stdlib/tsequtils.nim | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 12b961371..64a7be7a9 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -169,7 +169,7 @@ func cycle*[T](s: openArray[T], n: Natural): seq[T] = result[o] = e inc o -func repeat*[T](x: T, n: Natural): seq[T] = +proc repeat*[T](x: T, n: Natural): seq[T] = ## Returns a new sequence with the item `x` repeated `n` times. ## `n` must be a non-negative number (zero or more). ## @@ -246,7 +246,7 @@ func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = template zipImpl(s1, s2, retType: untyped): untyped = - func zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = + proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = ## Returns a new sequence with a combination of the two input containers. ## ## The input containers can be of different types. @@ -289,7 +289,7 @@ when (NimMajor, NimMinor) <= (1, 0): else: zipImpl(s1, s2, seq[(S, T)]) -func unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = +proc unzip*[S, T](s: openArray[(S, T)]): (seq[S], seq[T]) {.since: (1, 1).} = ## Returns a tuple of two sequences split out from a sequence of 2-field tuples. runnableExamples: let diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index 338473407..179f619f0 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -10,6 +10,7 @@ from algorithm import sorted {.experimental: "strictEffects".} {.push warningAsError[Effect]: on.} +{.experimental: "strictFuncs".} # helper for testing double substitution side effects which are handled # by `evalOnceAs` @@ -456,6 +457,31 @@ block: # xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6 +block: # strictFuncs tests with ref object + type Foo = ref object + + let foo1 = Foo() + let foo2 = Foo() + let foos = @[foo1, foo2] + + # Procedures that are `func` + discard concat(foos, foos) + discard count(foos, foo1) + discard cycle(foos, 3) + discard deduplicate(foos) + discard minIndex(foos) + discard maxIndex(foos) + discard distribute(foos, 2) + var mutableFoos = foos + mutableFoos.delete(0..1) + mutableFoos.insert(foos) + + # Some procedures that are `proc`, but were reverted from `func` + discard repeat(foo1, 3) + discard zip(foos, foos) + let fooTuples = @[(foo1, 1), (foo2, 2)] + discard unzip(fooTuples) + template main = # xxx move all tests here block: # delete tests From 162b07d72cbe79bad1ddf99413ba508f07a831b1 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sun, 17 Oct 2021 06:38:07 +0300 Subject: [PATCH 3077/4254] fix parsesql.treeRepr when nil is in input (#18974) * fix parsesql.treeRepr when nil is in input * return newNode(nkNone) as default value, not nil --- lib/pure/parsesql.nim | 6 +++--- tests/stdlib/tparsesql.nim | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index eb5d7c2cc..9d74d08d0 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -982,7 +982,7 @@ proc parseInsert(p: var SqlParser): SqlNode = parseParIdentList(p, n) result.add n else: - result.add(nil) + result.add(newNode(nkNone)) if isKeyw(p, "default"): getTok(p) eat(p, "values") @@ -1017,7 +1017,7 @@ proc parseUpdate(p: var SqlParser): SqlNode = if isKeyw(p, "where"): result.add(parseWhere(p)) else: - result.add(nil) + result.add(newNode(nkNone)) proc parseDelete(p: var SqlParser): SqlNode = getTok(p) @@ -1029,7 +1029,7 @@ proc parseDelete(p: var SqlParser): SqlNode = if isKeyw(p, "where"): result.add(parseWhere(p)) else: - result.add(nil) + result.add(newNode(nkNone)) proc parseSelect(p: var SqlParser): SqlNode = getTok(p) diff --git a/tests/stdlib/tparsesql.nim b/tests/stdlib/tparsesql.nim index ba9e601a1..b440dc90f 100644 --- a/tests/stdlib/tparsesql.nim +++ b/tests/stdlib/tparsesql.nim @@ -3,6 +3,17 @@ discard """ """ import parsesql +doAssert treeRepr(parseSql("INSERT INTO STATS VALUES (10, 5.5); ") +) == """ + +nkStmtList + nkInsert + nkIdent STATS + nkNone + nkValueList + nkIntegerLit 10 + nkNumericLit 5.5""" + doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;" doAssert $parseSQL(""" SELECT @@ -183,8 +194,31 @@ SET ContactName = 'Alfred Schmidt', City= 'Frankfurt' WHERE CustomerID = 1; """) == "update Customers set ContactName = 'Alfred Schmidt' , City = 'Frankfurt' where CustomerID = 1;" +doAssert treeRepr(parseSql("""UPDATE Customers + SET ContactName = 'Alice', City= 'Frankfurt';""") +) == """ + +nkStmtList + nkUpdate + nkIdent Customers + nkAsgn + nkIdent ContactName + nkStringLit Alice + nkAsgn + nkIdent City + nkStringLit Frankfurt + nkNone""" + doAssert $parseSQL("DELETE FROM table_name;") == "delete from table_name;" +doAssert treeRepr(parseSQL("DELETE FROM table_name;") +) == """ + +nkStmtList + nkDelete + nkIdent table_name + nkNone""" + doAssert $parseSQL("DELETE * FROM table_name;") == "delete from table_name;" doAssert $parseSQL(""" From f77dea01fd980734a3ed4acb812575827540aff9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 16 Oct 2021 23:37:52 -0700 Subject: [PATCH 3078/4254] define `nimVersion` automatically and avoid needing -d:nimVersion140 (#18726) * define `nimVersion` and avoid needing -d:nimVersion140 * fix changelog --- changelog.md | 3 ++- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 4 ++-- compiler/options.nim | 18 ++++++++++++++++++ config/config.nims | 2 ++ 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index ab63bd8b5..fbda70582 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,6 @@ # v1.8.x - yyyy-mm-dd - ## Changes affecting backward compatibility @@ -16,6 +15,8 @@ ## Compiler changes +- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, + without requiring `-d:nimVersion140` which is now a noop. ## Tool changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 0a3b1b72d..abd2ff01e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -656,7 +656,7 @@ type mUnaryPlusI, mBitnotI, mUnaryPlusF64, mUnaryMinusF64, mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, # for -d:nimVersion140 + mIntToStr, mInt64ToStr, mFloatToStr, # for compiling nimStdlibVersion < 1.5.1 (not bootstrapping) mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ac4a26bd6..fc09fefc3 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -894,7 +894,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = let discIndex = rdSetElemLoc(p.config, v, u.t) if optTinyRtti in p.config.globalOptions: # not sure how to use `genEnumToStr` here - if p.config.isDefined("nimVersion140"): + if p.config.getStdlibVersion < (1,5,1): const code = "{ #raiseFieldError($1); $2} $n" linefmt(p, cpsStmts, code, [strLit, raiseInstr(p)]) else: @@ -905,7 +905,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = let first = p.config.firstOrd(disc.sym.typ) let firstLit = int64Literal(cast[int](first)) let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info) - if p.config.isDefined("nimVersion140"): + if p.config.getStdlibVersion < (1,5,1): const code = "{ #raiseFieldError($1); $2} $n" linefmt(p, cpsStmts, code, [strLit, raiseInstr(p)]) else: diff --git a/compiler/options.nim b/compiler/options.nim index eafcd816d..d3f868316 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -165,6 +165,7 @@ const cmdCtags, cmdBuildindex} type + NimVer* = tuple[major: int, minor: int, patch: int] TStringSeq* = seq[string] TGCMode* = enum # the selected GC gcUnselected = "unselected" @@ -346,6 +347,7 @@ type outDir*: AbsoluteDir jsonBuildFile*: AbsoluteFile prefixDir*, libpath*, nimcacheDir*: AbsoluteDir + nimStdlibVersion*: NimVer dllOverrides, moduleOverrides*, cfileSpecificOptions*: StringTableRef projectName*: string # holds a name like 'nim' projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/ @@ -389,6 +391,16 @@ type cppCustomNamespace*: string vmProfileData*: ProfileData +proc parseNimVersion*(a: string): NimVer = + # could be moved somewhere reusable + if a.len > 0: + let b = a.split(".") + assert b.len == 3, a + template fn(i) = result[i] = b[i].parseInt # could be optimized if needed + fn(0) + fn(1) + fn(2) + proc assignIfDefault*[T](result: var T, val: T, def = default(T)) = ## if `result` was already assigned to a value (that wasn't `def`), this is a noop. if result == def: result = val @@ -560,6 +572,12 @@ proc newPartialConfigRef*(): ConfigRef = proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define +proc getStdlibVersion*(conf: ConfigRef): NimVer = + if conf.nimStdlibVersion == (0,0,0): + let s = conf.symbols.getOrDefault("nimVersion", "") + conf.nimStdlibVersion = s.parseNimVersion + result = conf.nimStdlibVersion + proc isDefined*(conf: ConfigRef; symbol: string): bool = if conf.symbols.hasKey(symbol): result = true diff --git a/config/config.nims b/config/config.nims index 2ae86012c..893d6960f 100644 --- a/config/config.nims +++ b/config/config.nims @@ -14,3 +14,5 @@ when defined(nimStrictMode): # switch("hint", "ConvFromXtoItselfNotNeeded") switch("hintAsError", "ConvFromXtoItselfNotNeeded") # future work: XDeclaredButNotUsed + +switch("define", "nimVersion:" & NimVersion) From f0af4a36b932af3932b611c1f728ebfbfe3a2749 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sun, 17 Oct 2021 08:24:43 -0600 Subject: [PATCH 3079/4254] Added setGlobalValue to VM api (#19007) --- compiler/nimeval.nim | 4 ++++ compiler/vm.nim | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 577c7b586..82e2f0812 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -57,6 +57,10 @@ proc callRoutine*(i: Interpreter; routine: PSym; args: openArray[PNode]): PNode proc getGlobalValue*(i: Interpreter; letOrVar: PSym): PNode = result = vm.getGlobalValue(PCtx i.graph.vm, letOrVar) +proc setGlobalValue*(i: Interpreter; letOrVar: PSym, val: PNode) = + ## Sets a global value to a given PNode, does not do any type checking. + vm.setGlobalValue(PCtx i.graph.vm, letOrVar, val) + proc implementRoutine*(i: Interpreter; pkg, module, name: string; impl: proc (a: VmArgs) {.closure, gcsafe.}) = assert i != nil diff --git a/compiler/vm.nim b/compiler/vm.nim index 9fa25efbe..1b443aff1 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2162,6 +2162,11 @@ proc getGlobalValue*(c: PCtx; s: PSym): PNode = internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags result = c.globals[s.position-1] +proc setGlobalValue*(c: PCtx; s: PSym, val: PNode) = + ## Does not do type checking so ensure the `val` matches the `s.typ` + internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags + c.globals[s.position-1] = val + include vmops proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) = From c239db4817586f769327a6d27c244682111f903a Mon Sep 17 00:00:00 2001 From: narimiran Date: Tue, 19 Oct 2021 17:01:56 +0200 Subject: [PATCH 3080/4254] bump NimVersion to 1.7.1 --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index caa036f37..012aefe6a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2121,7 +2121,7 @@ const ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard # see also std/private/since - NimMinor* {.intdefine.}: int = 5 + NimMinor* {.intdefine.}: int = 7 ## is the minor number of Nim's version. ## Odd for devel, even for releases. From 62701cd3b92677c2014cf70b1cf5a5ba6e0468bf Mon Sep 17 00:00:00 2001 From: John Novak Date: Thu, 21 Oct 2021 01:06:00 +1000 Subject: [PATCH 3081/4254] Fix isInvalidFilename & always operate on the full passed in string (#19004) * Fix isInvalidFilename segfault & deprecate the method * Update lib/pure/os.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update lib/pure/os.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/os.nim | 91 +++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e3b8e9f1c..5320aa87e 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -39,8 +39,8 @@ const weirdTarget = defined(nimscript) or defined(js) since (1, 1): const invalidFilenameChars* = {'/', '\\', ':', '*', '?', '"', '<', '>', '|', '^', '\0'} ## \ - ## Characters that may produce invalid filenames across Linux, Windows, Mac, etc. - ## You can check if your filename contains these char and strip them for safety. + ## Characters that may produce invalid filenames across Linux, Windows and Mac. + ## You can check if your filename contains any of these chars and strip them for safety. ## Mac bans ``':'``, Linux bans ``'/'``, Windows bans all others. invalidFilenames* = [ "CON", "PRN", "AUX", "NUL", @@ -297,7 +297,7 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raise result = path[0] == '$' elif defined(posix) or defined(js): # `or defined(js)` wouldn't be needed pending https://github.com/nim-lang/Nim/issues/13469 - # This works around the problem for posix, but windows is still broken with nim js -d:nodejs + # This works around the problem for posix, but Windows is still broken with nim js -d:nodejs result = path[0] == '/' else: doAssert false # if ever hits here, adapt as needed @@ -321,7 +321,7 @@ when doslikeFileSystem: proc sameRoot(path1, path2: string): bool {.noSideEffect, raises: [].} = ## Return true if path1 and path2 have a same root. ## - ## Detail of windows path formats: + ## Detail of Windows path formats: ## https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats assert(isAbsolute(path1)) @@ -370,7 +370,7 @@ proc relativePath*(path, base: string, sep = DirSep): string {. ## this can be useful to ensure the relative path only contains `'/'` ## so that it can be used for URL constructions. ## - ## On windows, if a root of `path` and a root of `base` are different, + ## On Windows, if a root of `path` and a root of `base` are different, ## returns `path` as is because it is impossible to make a relative path. ## That means an absolute path can be returned. ## @@ -558,27 +558,25 @@ iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string = ## See also: ## * `parentDir proc <#parentDir,string>`_ ## - ## **Examples:** - ## - ## .. code-block:: - ## let g = "a/b/c" - ## - ## for p in g.parentDirs: - ## echo p - ## # a/b/c - ## # a/b - ## # a - ## - ## for p in g.parentDirs(fromRoot=true): - ## echo p - ## # a/ - ## # a/b/ - ## # a/b/c - ## - ## for p in g.parentDirs(inclusive=false): - ## echo p - ## # a/b - ## # a + runnableExamples: + let g = "a/b/c" + + for p in g.parentDirs: + echo p + # a/b/c + # a/b + # a + + for p in g.parentDirs(fromRoot=true): + echo p + # a/ + # a/b/ + # a/b/c + + for p in g.parentDirs(inclusive=false): + echo p + # a/b + # a if not fromRoot: var current = path @@ -944,8 +942,7 @@ proc getCacheDir*(): string = proc getCacheDir*(app: string): string = ## Returns the cache directory for an application `app`. ## - ## * On windows, this uses: `getCacheDir() / app / "cache"` - ## + ## * On Windows, this uses: `getCacheDir() / app / "cache"` ## * On other platforms, this uses: `getCacheDir() / app` when defined(windows): getCacheDir() / app / "cache" @@ -1988,7 +1985,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n proc tryMoveFSObject(source, dest: string, isDir: bool): bool {.noWeirdTarget.} = ## Moves a file (or directory if `isDir` is true) from `source` to `dest`. ## - ## Returns false in case of `EXDEV` error or `AccessDeniedError` on windows (if `isDir` is true). + ## Returns false in case of `EXDEV` error or `AccessDeniedError` on Windows (if `isDir` is true). ## In case of other errors `OSError` is raised. ## Returns true in case of success. when defined(windows): @@ -2144,7 +2141,7 @@ iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noWeirdT ## * `walkDirRec iterator <#walkDirRec.i,string>`_ runnableExamples: import std/sequtils - let paths = toSeq(walkPattern("lib/pure/*")) # works on windows too + let paths = toSeq(walkPattern("lib/pure/*")) # works on Windows too assert "lib/pure/concurrency".unixToNativePath in paths assert "lib/pure/os.nim".unixToNativePath in paths walkCommon(pattern, defaultWalkFilter) @@ -2163,7 +2160,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTar ## * `walkDirRec iterator <#walkDirRec.i,string>`_ runnableExamples: import std/sequtils - assert "lib/pure/os.nim".unixToNativePath in toSeq(walkFiles("lib/pure/*.nim")) # works on windows too + assert "lib/pure/os.nim".unixToNativePath in toSeq(walkFiles("lib/pure/*.nim")) # works on Windows too walkCommon(pattern, isFile) iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarget.} = @@ -2180,7 +2177,7 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarg ## * `walkDirRec iterator <#walkDirRec.i,string>`_ runnableExamples: import std/sequtils - let paths = toSeq(walkDirs("lib/pure/*")) # works on windows too + let paths = toSeq(walkDirs("lib/pure/*")) # works on Windows too assert "lib/pure/concurrency".unixToNativePath in paths walkCommon(pattern, isDir) @@ -2278,7 +2275,9 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): ## If `checkDir` is true, `OSError` is raised when `dir` ## doesn't exist. ## - ## Example: This directory structure:: + ## **Example:** + ## + ## This directory structure:: ## dirA / dirB / fileB1.txt ## / dirC ## / fileA1.txt @@ -2291,7 +2290,6 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): # this also works at compile time assert collect(for k in walkDir("dirA"): k.path).join(" ") == "dirA/dirB dirA/dirC dirA/fileA2.txt dirA/fileA1.txt" - ## ## See also: ## * `walkPattern iterator <#walkPattern.i,string>`_ ## * `walkFiles iterator <#walkFiles.i,string>`_ @@ -3271,7 +3269,7 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime)) formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime)) formalInfo.creationTime = fromWinTime(rdFileTime(rawInfo.ftCreationTime)) - formalInfo.blockSize = 8192 # xxx use windows API instead of hardcoding + formalInfo.blockSize = 8192 # xxx use Windows API instead of hardcoding # Retrieve basic permissions if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32: @@ -3494,27 +3492,30 @@ proc setLastModificationTime*(file: string, t: times.Time) {.noWeirdTarget.} = discard h.closeHandle if res == 0'i32: raiseOSError(osLastError(), file) -func isValidFilename*(filename: string, maxLen = 259.Positive): bool {.since: (1, 1).} = +func isValidFilename*(filename: string, maxLen = 259.Positive): bool {.since: (1, 1), deprecated: "Deprecated since v1.5.1".} = ## Returns true if ``filename`` is valid for crossplatform use. ## ## This is useful if you want to copy or save files across Windows, Linux, Mac, etc. ## You can pass full paths as argument too, but func only checks filenames. - ## It uses ``invalidFilenameChars``, ``invalidFilenames`` and ``maxLen`` to verify the specified ``filename``. ## - ## .. code-block:: nim - ## assert not isValidFilename(" foo") ## Leading white space - ## assert not isValidFilename("foo ") ## Trailing white space - ## assert not isValidFilename("foo.") ## Ends with Dot - ## assert not isValidFilename("con.txt") ## "CON" is invalid (Windows) - ## assert not isValidFilename("OwO:UwU") ## ":" is invalid (Mac) - ## assert not isValidFilename("aux.bat") ## "AUX" is invalid (Windows) + ## It uses `invalidFilenameChars`, `invalidFilenames` and `maxLen` to verify the specified `filename`. ## + runnableExamples: + assert not isValidFilename(" foo") # Leading white space + assert not isValidFilename("foo ") # Trailing white space + assert not isValidFilename("foo.") # Ends with dot + assert not isValidFilename("con.txt") # "CON" is invalid (Windows) + assert not isValidFilename("OwO:UwU") # ":" is invalid (Mac) + assert not isValidFilename("aux.bat") # "AUX" is invalid (Windows) + assert not isValidFilename("") # Empty string + assert not isValidFilename("foo/") # Filename is empty + # https://docs.microsoft.com/en-us/dotnet/api/system.io.pathtoolongexception # https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx result = true let f = filename.splitFile() - if unlikely(f.name.len + f.ext.len > maxLen or + if unlikely(f.name.len + f.ext.len > maxLen or f.name.len == 0 or f.name[0] == ' ' or f.name[^1] == ' ' or f.name[^1] == '.' or find(f.name, invalidFilenameChars) != -1): return false for invalid in invalidFilenames: From 1a45da9150c6cf5da324e754f49dc4cf957f1180 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 21 Oct 2021 16:53:15 +0200 Subject: [PATCH 3082/4254] use two underscores for easy demangling [backport:1.6] (#19028) --- compiler/ccgtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 492e1f181..23e1a5867 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -39,7 +39,7 @@ proc mangleName(m: BModule; s: PSym): Rope = result = s.loc.r if result == nil: result = s.name.s.mangle.rope - result.add "_" + result.add "__" result.add m.g.graph.ifaces[s.itemId.module].uniqueName result.add "_" result.add rope s.itemId.item From 5e2b9341f343c3f80f92cfd160a0186f23521a42 Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Thu, 21 Oct 2021 18:01:48 +0300 Subject: [PATCH 3083/4254] Add Elbrus 2000 architecture (#19024) * Add Elbrus 2000 architecture * Add e2k to niminst * Update compiler/installer.ini Co-authored-by: Andreas Rumpf --- compiler/platform.nim | 6 ++++-- lib/system/platforms.nim | 4 +++- tools/nim.zsh-completion | 1 + tools/niminst/buildsh.nimf | 2 ++ tools/niminst/makefile.nimf | 3 +++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/platform.nim b/compiler/platform.nim index 1bc00b629..18d43f006 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -197,7 +197,8 @@ type cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430, - cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32 + cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32, + cpuE2k type TInfoCPU* = tuple[name: string, intSize: int, endian: Endianness, @@ -232,7 +233,8 @@ const (name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), - (name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)] + (name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), + (name: "e2k", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)] type Target* = object diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim index bd6541b6a..5bca8cb1c 100644 --- a/lib/system/platforms.nim +++ b/lib/system/platforms.nim @@ -35,7 +35,8 @@ type msp430, ## TI MSP430 microcontroller riscv32, ## RISC-V 32-bit processor riscv64, ## RISC-V 64-bit processor - wasm32 ## WASM, 32-bit + wasm32, ## WASM, 32-bit + e2k ## MCST Elbrus 2000 OsPlatform* {.pure.} = enum ## the OS this program will run on. none, dos, windows, os2, linux, morphos, skyos, solaris, @@ -93,5 +94,6 @@ const elif defined(riscv32): CpuPlatform.riscv32 elif defined(riscv64): CpuPlatform.riscv64 elif defined(wasm32): CpuPlatform.wasm32 + elif defined(e2k): CpuPlatform.e2k else: CpuPlatform.none ## the CPU this program will run on. diff --git a/tools/nim.zsh-completion b/tools/nim.zsh-completion index f7aeb72c6..07a221e9c 100644 --- a/tools/nim.zsh-completion +++ b/tools/nim.zsh-completion @@ -74,6 +74,7 @@ _nim() { '*--cpu=arm64[compile for ARM64 architecture]' \ '*--cpu=avr[compile for AVR architecture]' \ '*--cpu=esp[compile for ESP architecture]' \ + '*--cpu=e2k[compile for Elbrus 2000 architecture]' \ '*--cpu=hppa[compile for HPPA architecture]' \ '*--cpu=i386[compile for i386 architecture]' \ '*--cpu=ia64[compile for ia64 architecture]' \ diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 5f68a6a17..b81ac731f 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -227,6 +227,8 @@ case $ucpu in mycpu="arm" ;; *riscv64|riscv* ) mycpu="riscv64" ;; + *e2k* ) + mycpu="e2k" ;; *) echo 2>&1 "Error: unknown processor: $ucpu" exit 1 diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index 69e87b837..c4f2f0e79 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -166,6 +166,9 @@ endif ifeq ($(ucpu),riscv64) mycpu = riscv64 endif +ifeq ($(ucpu),e2k) + mycpu = e2k +endif ifndef mycpu $(error unknown CPU architecture: $(ucpu) See makefile.nimf) endif From d6345874236e03d21f4f6acbad34546ce27052b7 Mon Sep 17 00:00:00 2001 From: Abishek PY <43115551+vj-abishek@users.noreply.github.com> Date: Fri, 22 Oct 2021 15:40:32 +0530 Subject: [PATCH 3084/4254] feat: copy to clipboard (#18963) * feat: copy to clipboard * fix: CI failure related issue * fix: CI failure issue * fix: copy to clipboard button bug * feat: copy pragmadots value to clipboard --- doc/nimdoc.css | 32 ++++++++++++- nimdoc/testproject/expected/nimdoc.out.css | 32 ++++++++++++- tools/dochack/dochack.nim | 56 ++++++++++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 4abea9ce0..3353f1cda 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -38,6 +38,10 @@ Modified by Boyd Greenfield and narimiran --program: #6060c0; --option: #508000; --raw-data: #a4255b; + + --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: black' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); + --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: black' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); + --clipboard-image: var(--clipboard-image-normal) } [data-theme="dark"] { @@ -68,6 +72,10 @@ Modified by Boyd Greenfield and narimiran --program: #9090c0; --option: #90b010; --raw-data: #8be9fd; + + --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); + --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); + --clipboard-image: var(--clipboard-image-normal); } .theme-switch-wrapper { @@ -572,6 +580,10 @@ span.tok { margin-right: 0.2em; } +.copyToClipBoard { + position: relative; +} + pre { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; color: var(--text); @@ -590,7 +602,25 @@ pre { border: 1px solid var(--border); -webkit-border-radius: 6px; -moz-border-radius: 6px; - border-radius: 6px; } + border-radius: 6px; +} + +.copyToClipBoardBtn { + visibility: hidden; + position: absolute; + width: 24px; + border-radius: 4px; + background-image: var(--clipboard-image); + right: 5px; + top: 13px; + background-color: var(--secondary-background); + padding: 11px; + border: 0; +} + +.copyToClipBoard:hover .copyToClipBoardBtn { + visibility: visible; +} .pre-scrollable { max-height: 340px; diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 4abea9ce0..3353f1cda 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -38,6 +38,10 @@ Modified by Boyd Greenfield and narimiran --program: #6060c0; --option: #508000; --raw-data: #a4255b; + + --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: black' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); + --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: black' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); + --clipboard-image: var(--clipboard-image-normal) } [data-theme="dark"] { @@ -68,6 +72,10 @@ Modified by Boyd Greenfield and narimiran --program: #9090c0; --option: #90b010; --raw-data: #8be9fd; + + --clipboard-image-normal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E %3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2' /%3E %3C/svg%3E"); + --clipboard-image-selected: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' style='color: lightgray' viewBox='0 0 20 20' fill='currentColor'%3E %3Cpath d='M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z' /%3E %3Cpath d='M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z' /%3E %3C/svg%3E"); + --clipboard-image: var(--clipboard-image-normal); } .theme-switch-wrapper { @@ -572,6 +580,10 @@ span.tok { margin-right: 0.2em; } +.copyToClipBoard { + position: relative; +} + pre { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; color: var(--text); @@ -590,7 +602,25 @@ pre { border: 1px solid var(--border); -webkit-border-radius: 6px; -moz-border-radius: 6px; - border-radius: 6px; } + border-radius: 6px; +} + +.copyToClipBoardBtn { + visibility: hidden; + position: absolute; + width: 24px; + border-radius: 4px; + background-image: var(--clipboard-image); + right: 5px; + top: 13px; + background-color: var(--secondary-background); + padding: 11px; + border: 0; +} + +.copyToClipBoard:hover .copyToClipBoardBtn { + visibility: visible; +} .pre-scrollable { max-height: 340px; diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 4a491cf88..83e81f1c0 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -341,3 +341,59 @@ proc search*() {.exportc.} = if timer != nil: clearTimeout(timer) timer = setTimeout(wrapper, 400) + +proc copyToClipboard*() {.exportc.} = + {.emit: """ + + function updatePreTags() { + + const allPreTags = document.querySelectorAll("pre") + + allPreTags.forEach((e) => { + + const div = document.createElement("div") + div.classList.add("copyToClipBoard") + + const preTag = document.createElement("pre") + preTag.innerHTML = e.innerHTML + + const button = document.createElement("button") + button.value = e.textContent.replace('...', '') + button.classList.add("copyToClipBoardBtn") + + div.appendChild(preTag) + div.appendChild(button) + + e.outerHTML = div.outerHTML + + }) + } + + + function copyTextToClipboard(e) { + const clipBoardContent = e.target.value + navigator.clipboard.writeText(clipBoardContent).then(function() { + e.target.style.setProperty("--clipboard-image", "var(--clipboard-image-selected)") + }, function(err) { + console.error("Could not copy text: ", err); + }); + } + + window.addEventListener("click", (e) => { + if (e.target.classList.contains("copyToClipBoardBtn")) { + copyTextToClipboard(e) + } + }) + + window.addEventListener("mouseover", (e) => { + if (e.target.nodeName === "PRE") { + e.target.nextElementSibling.style.setProperty("--clipboard-image", "var(--clipboard-image-normal)") + } + }) + + window.addEventListener("DOMContentLoaded", updatePreTags) + + """ + .} + +copyToClipboard() \ No newline at end of file From 4d8108046b71b6e40d88cde7496e687e68116877 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 22 Oct 2021 18:15:08 +0800 Subject: [PATCH 3085/4254] remove exception (#18906) --- compiler/semfold.nim | 8 +------- tests/system/tdollars.nim | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 1f8efc4de..5ae91d306 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -292,13 +292,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P else: result = newStrNodeT("true", n, g) of mFloatToStr: result = newStrNodeT($getFloat(a), n, g) of mCStrToStr, mCharToStr: - if a.kind == nkBracket: - var s = "" - for b in a.sons: - s.add b.getStrOrChar - result = newStrNodeT(s, n, g) - else: - result = newStrNodeT(getStrOrChar(a), n, g) + result = newStrNodeT(getStrOrChar(a), n, g) of mStrToStr: result = newStrNodeT(getStrOrChar(a), n, g) of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g) of mArrToSeq: diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 17d195e76..93fa5cb9e 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -187,5 +187,12 @@ proc main()= test2 high(int8), "127" test2 low(int8), "-128" + block: + const + a: array[3, char] = ['N', 'i', 'm'] + aStr = $(a) + + doAssert aStr == """['N', 'i', 'm']""" + static: main() main() From 490c4226a55e8abd7cb504d4e24fcb714bff23f1 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 22 Oct 2021 17:32:02 +0200 Subject: [PATCH 3086/4254] allow converting static vars to `openArray` (#19035) When assigning constant output to a seq, and then passing that static seq to other functions that take `openArray`, the compiler may end up producing errors, as it does not know how to convert `static[seq[T]]` to `openArray[T]`. By ignoring the `static` wrapper on the type for the purpose of determining data memory location and length, this gets resolved cleanly. Unfortunately, it is relatively tricky to come up with a minimal example, as there are followup problems from the failing conversion, e.g., this may lead to `internal error: inconsistent environment type`, instead of the relevant `openArrayLoc` error message. --- compiler/ccgcalls.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 12f366a53..fe0516f9a 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -214,7 +214,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: var a: TLoc initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a) - case skipTypes(a.t, abstractVar).kind + case skipTypes(a.t, abstractVar+{tyStatic}).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(n): if a.t.kind in {tyVar, tyLent}: From 6621e1a3ead7166fa116bfbb8f0d2acb4e318d81 Mon Sep 17 00:00:00 2001 From: BarrOff <58253563+BarrOff@users.noreply.github.com> Date: Fri, 22 Oct 2021 23:42:54 +0000 Subject: [PATCH 3087/4254] use the correct header for TIOCGWINSZ on Solaris (#19037) --- lib/posix/termios.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index b03ce74f3..f755c720d 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -237,8 +237,11 @@ proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", header: "".} # Get process group ID for session leader for controlling terminal FD. -# Window size ioctl. Should work on on any Unix that xterm has been ported to. -var TIOCGWINSZ*{.importc, header: "".}: culong +# Window size ioctl. Solaris based systems have an uncommen place for this. +when defined(solaris) or defined(sunos): + var TIOCGWINSZ*{.importc, header: "".}: culong +else: + var TIOCGWINSZ*{.importc, header: "".}: culong when defined(nimHasStyleChecks): {.push styleChecks: off.} From 41d99185918923063bd6ae34898c8ac18a941169 Mon Sep 17 00:00:00 2001 From: BarrOff <58253563+BarrOff@users.noreply.github.com> Date: Sun, 24 Oct 2021 05:24:31 +0000 Subject: [PATCH 3088/4254] use `gmake` in the buildscript on Solaris systems (#19036) --- ci/funs.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/funs.sh b/ci/funs.sh index 1638931c6..8e7f8faf7 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -76,6 +76,8 @@ _nimBuildCsourcesIfNeeded(){ makeX=gmake elif [ "$unamestr" = 'CROSSOS' ]; then makeX=gmake + elif [ "$unamestr" = 'SunOS' ]; then + makeX=gmake else makeX=make fi From 141b76e36519219915ada9086d1c9b1d0b465659 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Sun, 24 Oct 2021 09:51:57 +0000 Subject: [PATCH 3089/4254] Add Zephyr Support (#19003) * Porting Nim to run on Zephyr. Includes changes to `std/net`. Squashed commit of the following: tweaking more memory / malloc things revert back bitmasks tweaking nim to use kernel heap as C malloc doesn't work fixing socket polling on zephyr cleanup getting maximum sockets for process or for rtos'es reorganizing and fixing net for async / system merge netlite changes back into nativesockets merge netlite changes back into nativesockets reverting native sockets back tweaking nim / zephyr network adding option to run 'net-lite' from linux bridging zephyr's max connections fixing net errors fixing compilation with getAddrString fixing compilation with getAddrString experimenting with a nativesockets_lite ... getAddrString experimenting with a nativesockets_lite ... getAddrString experimenting with a nativesockets_lite ... getLocalAddr experimenting with a nativesockets_lite ... getLocalAddr experimenting with a nativesockets_lite ... add note regarding incorrect FreeRTOS Sockadd_in fields changing to NIM_STATIC_ASSERT cleaning up the static_assert error messages cleaning up the static_assert error messages setting up static assert ftw! testing compile time asserts reworking Sockaddr objects to more closely match various platforms reworking Sockaddr objects to more closely match various platforms reworking Sockaddr objects to more closely match various platforms finding missing items (issue #18684) fixup posix constants (issue #18684) adding plumbing for zephyr os (issue #18684) adding plumbing for zephyr os (issue #18684) * fixing constant capitalizations * remove extra debug prints and fix TSa_Family/cint issue * remove extra debug prints and fix TSa_Family/cint issue * Porting Nim to run on Zephyr. Includes changes to `std/net`. Squashed commit of the following: tweaking more memory / malloc things revert back bitmasks tweaking nim to use kernel heap as C malloc doesn't work fixing socket polling on zephyr cleanup getting maximum sockets for process or for rtos'es reorganizing and fixing net for async / system merge netlite changes back into nativesockets merge netlite changes back into nativesockets reverting native sockets back tweaking nim / zephyr network adding option to run 'net-lite' from linux bridging zephyr's max connections fixing net errors fixing compilation with getAddrString fixing compilation with getAddrString experimenting with a nativesockets_lite ... getAddrString experimenting with a nativesockets_lite ... getAddrString experimenting with a nativesockets_lite ... getLocalAddr experimenting with a nativesockets_lite ... getLocalAddr experimenting with a nativesockets_lite ... add note regarding incorrect FreeRTOS Sockadd_in fields changing to NIM_STATIC_ASSERT cleaning up the static_assert error messages cleaning up the static_assert error messages setting up static assert ftw! testing compile time asserts reworking Sockaddr objects to more closely match various platforms reworking Sockaddr objects to more closely match various platforms reworking Sockaddr objects to more closely match various platforms finding missing items (issue #18684) fixup posix constants (issue #18684) adding plumbing for zephyr os (issue #18684) adding plumbing for zephyr os (issue #18684) * fixing constant capitalizations * remove extra debug prints and fix TSa_Family/cint issue * remove extra debug prints and fix TSa_Family/cint issue * fixing PR issues * Porting Nim to run on Zephyr. Includes changes to `std/net`. Squashed commit of the following: tweaking more memory / malloc things revert back bitmasks tweaking nim to use kernel heap as C malloc doesn't work fixing socket polling on zephyr cleanup getting maximum sockets for process or for rtos'es reorganizing and fixing net for async / system merge netlite changes back into nativesockets merge netlite changes back into nativesockets reverting native sockets back tweaking nim / zephyr network adding option to run 'net-lite' from linux bridging zephyr's max connections fixing net errors fixing compilation with getAddrString fixing compilation with getAddrString experimenting with a nativesockets_lite ... getAddrString experimenting with a nativesockets_lite ... getAddrString experimenting with a nativesockets_lite ... getLocalAddr experimenting with a nativesockets_lite ... getLocalAddr experimenting with a nativesockets_lite ... add note regarding incorrect FreeRTOS Sockadd_in fields changing to NIM_STATIC_ASSERT cleaning up the static_assert error messages cleaning up the static_assert error messages setting up static assert ftw! testing compile time asserts reworking Sockaddr objects to more closely match various platforms reworking Sockaddr objects to more closely match various platforms reworking Sockaddr objects to more closely match various platforms finding missing items (issue #18684) fixup posix constants (issue #18684) adding plumbing for zephyr os (issue #18684) adding plumbing for zephyr os (issue #18684) * fixing constant capitalizations * remove extra debug prints and fix TSa_Family/cint issue * remove extra debug prints and fix TSa_Family/cint issue * Remerge * fixing constant capitalizations * remove extra debug prints and fix TSa_Family/cint issue * remove extra debug prints and fix TSa_Family/cint issue * fixing PR issues * fix maxDescriptors on zephyr/freertos * move maxDescriptors to selector.nim -- fixes compile issue * change realloc impl on zephyr to match ansi c behavior * change realloc impl on zephyr to match ansi c behavior * force compileOnly mode for tlwip Co-authored-by: Jaremy J. Creechley Co-authored-by: Jaremy Creechley --- compiler/options.nim | 4 +- compiler/platform.nim | 6 +- lib/posix/posix.nim | 6 +- lib/posix/posix_freertos_consts.nim | 2 + lib/posix/posix_other.nim | 94 ++-- lib/posix/posix_other_consts.nim | 12 +- lib/pure/asyncdispatch.nim | 7 +- lib/pure/asyncnet.nim | 14 +- lib/pure/ioselects/ioselectors_epoll.nim | 5 +- lib/pure/ioselects/ioselectors_poll.nim | 5 +- lib/pure/ioselects/ioselectors_select.nim | 2 +- lib/pure/nativesockets.nim | 615 ++++++++++++---------- lib/pure/net.nim | 17 +- lib/pure/selectors.nim | 19 + lib/system/ansi_c.nim | 31 +- lib/system/bitmasks.nim | 1 + lib/system/dyncalls.nim | 2 +- lib/system/io.nim | 9 +- lib/system/mm/malloc.nim | 15 +- tests/stdlib/tlwip.nim | 2 +- 20 files changed, 522 insertions(+), 346 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index d3f868316..2feaa2d43 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -595,7 +595,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osQnx, osAtari, osAix, osHaiku, osVxWorks, osSolaris, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos, - osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos} + osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr} of "linux": result = conf.target.targetOS in {osLinux, osAndroid} of "bsd": @@ -615,6 +615,8 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = result = conf.target.targetOS == osNintendoSwitch of "freertos", "lwip": result = conf.target.targetOS == osFreeRTOS + of "zephyr": + result = conf.target.targetOS == osZephyr of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian of "cpu8": result = CPU[conf.target.targetCPU].bit == 8 diff --git a/compiler/platform.nim b/compiler/platform.nim index 18d43f006..eb1398677 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -22,7 +22,7 @@ type osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx, osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks - osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny + osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, osAny type TInfoOSProp* = enum @@ -185,6 +185,10 @@ const objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {ospPosix}), + (name: "Zephyr", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + props: {ospPosix}), (name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 45fe00d5d..c2504f994 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -151,8 +151,10 @@ proc htons*(a1: uint16): uint16 {.importc, header: "".} proc ntohl*(a1: uint32): uint32 {.importc, header: "".} proc ntohs*(a1: uint16): uint16 {.importc, header: "".} -proc inet_addr*(a1: cstring): InAddrT {.importc, header: "".} -proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "".} +when not defined(zephyr): + proc inet_addr*(a1: cstring): InAddrT {.importc, header: "".} + proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "".} + proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {. importc:"(char *)$1", header: "".} proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {. diff --git a/lib/posix/posix_freertos_consts.nim b/lib/posix/posix_freertos_consts.nim index efe87aacf..ca500534a 100644 --- a/lib/posix/posix_freertos_consts.nim +++ b/lib/posix/posix_freertos_consts.nim @@ -363,6 +363,8 @@ var SEM_FAILED* {.importc: "SEM_FAILED", header: "".}: pointer # # var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "".}: cint +var FD_MAX* {.importc: "CONFIG_LWIP_MAX_SOCKETS", header: "".}: cint + # var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 6584bfab2..688867b98 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -10,7 +10,7 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(freertos): +when defined(freertos) or defined(zephyr): const hasSpawnH = false # should exist for every Posix system nowadays hasAioH = false @@ -391,9 +391,29 @@ when hasSpawnH: header: "", final, pure.} = object when defined(linux): + const Sockaddr_max_length* = 255 # from sys/un.h const Sockaddr_un_path_length* = 108 +elif defined(zephyr): + when defined(net_ipv6): + const Sockaddr_max_length* = 24 + elif defined(net_raw): + const Sockaddr_max_length* = 20 + else: + const Sockaddr_max_length* = 8 + const Sockaddr_un_path_length* = Sockaddr_max_length + # Zephyr is heavily customizable so it's easy to get to a state + # where Nim & Zephyr IPv6 settings are out of sync, causing painful runtime failures. + {.emit: ["NIM_STATIC_ASSERT(NET_SOCKADDR_MAX_SIZE == ", + Sockaddr_max_length, + ",\"NET_SOCKADDR_MAX_SIZE and Sockaddr_max_length size mismatch!", + " Check that Nim and Zephyr IPv4/IPv6 settings match.", + " Try adding -d:net_ipv6 to enable IPv6 for Nim on Zephyr.\" );"].} +elif defined(freertos) or defined(lwip): + const Sockaddr_max_length* = 14 + const Sockaddr_un_path_length* = 108 else: + const Sockaddr_max_length* = 255 # according to http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html # this is >=92 const Sockaddr_un_path_length* = 92 @@ -408,48 +428,50 @@ when defined(lwip): pure, final.} = object ## struct sockaddr sa_len*: uint8 ## Address family. sa_family*: TSa_Family ## Address family. - sa_data*: array[0..255, char] ## Socket address (variable-length data). + sa_data*: array[0..Sockaddr_max_length-sizeof(uint8)-sizeof(TSa_Family), char] ## Socket address (variable-length data). + + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + s2_len*: uint8 ## Address family. + ss_family*: TSa_Family ## Address family. + s2_data1*: array[2, char] ## Address family. + s2_data2*: array[3, uint32] ## Address family. + when defined(lwip6) or defined(net_ipv6): + s2_data3*: array[3, uint32] ## Address family. +elif defined(zephyr): + type + SockAddr* {.importc: "struct sockaddr", header: "", + pure, final.} = object ## struct sockaddr + sa_family*: TSa_Family ## Address family. + data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). + + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + ss_family*: TSa_Family ## Address family. + data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). + {.emit: ["NIM_STATIC_ASSERT(sizeof(struct sockaddr) == ", sizeof(Sockaddr), ",\"struct size mismatch\" );"].} + {.emit: ["NIM_STATIC_ASSERT(sizeof(struct sockaddr_storage) == ", sizeof(Sockaddr_storage), ",\"struct size mismatch\" );"].} else: type SockAddr* {.importc: "struct sockaddr", header: "", pure, final.} = object ## struct sockaddr sa_family*: TSa_Family ## Address family. - sa_data*: array[0..255, char] ## Socket address (variable-length data). + sa_data*: array[0..Sockaddr_max_length-sizeof(TSa_Family), char] ## Socket address (variable-length data). + + Sockaddr_storage* {.importc: "struct sockaddr_storage", + header: "", + pure, final.} = object ## struct sockaddr_storage + ss_family*: TSa_Family ## Address family. type Sockaddr_un* {.importc: "struct sockaddr_un", header: "", pure, final.} = object ## struct sockaddr_un sun_family*: TSa_Family ## Address family. - sun_path*: array[0..Sockaddr_un_path_length-1, char] ## Socket path + sun_path*: array[0..Sockaddr_un_path_length-sizeof(TSa_Family), char] ## Socket path -when defined(lwip): - when not defined(lwip6): - type - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - s2_len*: uint8 ## Address family. - ss_family*: TSa_Family ## Address family. - s2_data1*: array[2, char] ## Address family. - s2_data2*: array[3, uint32] ## Address family. - else: - type - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - s2_len*: uint8 ## Address family. - ss_family*: TSa_Family ## Address family. - s2_data1*: array[2, char] ## Address family. - s2_data2*: array[3, uint32] ## Address family. - s2_data3*: array[3, uint32] ## Address family. -else: - type - Sockaddr_storage* {.importc: "struct sockaddr_storage", - header: "", - pure, final.} = object ## struct sockaddr_storage - ss_family*: TSa_Family ## Address family. - type Tif_nameindex* {.importc: "struct if_nameindex", final, pure, header: "".} = object ## struct if_nameindex @@ -494,6 +516,7 @@ type header: "".} = object ## struct in_addr s_addr*: InAddrScalar + # TODO: Fixme for FreeRTOS/LwIP, these are incorrect Sockaddr_in* {.importc: "struct sockaddr_in", pure, final, header: "".} = object ## struct sockaddr_in sin_family*: TSa_Family ## AF_INET. @@ -577,7 +600,12 @@ when not defined(lwip): events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = cint + when defined(zephyr): + type + Tnfds* = distinct cint + else: + type + Tnfds* {.importc: "nfds_t", header: "".} = cint var errno* {.importc, header: "".}: cint ## error variable @@ -625,7 +653,7 @@ elif defined(solaris): # Solaris doesn't have MSG_NOSIGNAL const MSG_NOSIGNAL* = 0'i32 -elif defined(freertos) or defined(lwip): +elif defined(zephyr) or defined(freertos) or defined(lwip): # LwIP/FreeRTOS doesn't have MSG_NOSIGNAL const MSG_NOSIGNAL* = 0x20'i32 diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index f43407b40..59ac6f9ed 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -462,6 +462,9 @@ var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "".}: cin # var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint +when defined(zephyr): + # Zephyr specific hardcoded value + var FD_MAX* {.importc: "CONFIG_POSIX_MAX_FDS ", header: "".}: cint # var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint @@ -487,10 +490,15 @@ var SO_SNDTIMEO* {.importc: "SO_SNDTIMEO", header: "".}: cint var SO_TYPE* {.importc: "SO_TYPE", header: "".}: cint var SOCK_DGRAM* {.importc: "SOCK_DGRAM", header: "".}: cint var SOCK_RAW* {.importc: "SOCK_RAW", header: "".}: cint -var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "".}: cint +when defined(zephyr): + const SOCK_SEQPACKET* = cint(5) + var SOMAXCONN* {.importc: "CONFIG_NET_SOCKETS_POLL_MAX", header: "".}: cint +else: + var SOCK_SEQPACKET* {.importc: "SOCK_SEQPACKET", header: "".}: cint + var SOMAXCONN* {.importc: "SOMAXCONN", header: "".}: cint + var SOCK_STREAM* {.importc: "SOCK_STREAM", header: "".}: cint var SOL_SOCKET* {.importc: "SOL_SOCKET", header: "".}: cint -var SOMAXCONN* {.importc: "SOMAXCONN", header: "".}: cint var MSG_PEEK* {.importc: "MSG_PEEK", header: "".}: cint var MSG_TRUNC* {.importc: "MSG_TRUNC", header: "".}: cint var MSG_WAITALL* {.importc: "MSG_WAITALL", header: "".}: cint diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index d87e2360f..e15fb0851 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1973,15 +1973,18 @@ proc activeDescriptors*(): int {.inline.} = when defined(posix): import posix -when defined(linux) or defined(windows) or defined(macosx) or defined(bsd): +when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or + defined(zephyr) or defined(freertos): proc maxDescriptors*(): int {.raises: OSError.} = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is ## supported on the following OSes: Windows, Linux, OSX, BSD. when defined(windows): result = 16_700_000 + elif defined(zephyr) or defined(freertos): + result = FD_MAX else: var fdLim: RLimit if getrlimit(RLIMIT_NOFILE, fdLim) < 0: raiseOSError(osLastError()) - result = int(fdLim.rlim_cur) - 1 + result = int(fdLim.rlim_cur) - 1 \ No newline at end of file diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 5523fa10e..abb4dd075 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -103,6 +103,7 @@ export SOBool # TODO: Remove duplication introduced by PR #4683. const defineSsl = defined(ssl) or defined(nimdoc) +const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) when defineSsl: import openssl @@ -178,11 +179,12 @@ proc getLocalAddr*(socket: AsyncSocket): (string, Port) = ## This is high-level interface for `getsockname`:idx:. getLocalAddr(socket.fd, socket.domain) -proc getPeerAddr*(socket: AsyncSocket): (string, Port) = - ## Get the socket's peer address and port number. - ## - ## This is high-level interface for `getpeername`:idx:. - getPeerAddr(socket.fd, socket.domain) +when not useNimNetLite: + proc getPeerAddr*(socket: AsyncSocket): (string, Port) = + ## Get the socket's peer address and port number. + ## + ## This is high-level interface for `getpeername`:idx:. + getPeerAddr(socket.fd, socket.domain) proc newAsyncSocket*(domain, sockType, protocol: cint, buffered = true, @@ -655,7 +657,7 @@ proc hasDataBuffered*(s: AsyncSocket): bool {.since: (1, 5).} = # xxx dedup with std/net s.isBuffered and s.bufLen > 0 and s.currPos != s.bufLen -when defined(posix): +when defined(posix) and not useNimNetLite: proc connectUnix*(socket: AsyncSocket, path: string): owned(Future[void]) = ## Binds Unix socket to `path`. diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index b62b4c2db..05d9d19a8 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -73,10 +73,7 @@ type proc newSelector*[T](): Selector[T] = # Retrieve the maximum fd count (for current OS) via getrlimit() - var a = RLimit() - if getrlimit(posix.RLIMIT_NOFILE, a) != 0: - raiseOSError(osLastError()) - var maxFD = int(a.rlim_max) + var maxFD = maxDescriptors() doAssert(maxFD > 0) # Start with a reasonable size, checkFd() will grow this on demand const numFD = 1024 diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 6b10e19ae..0d8fef78a 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -53,10 +53,7 @@ else: body proc newSelector*[T](): Selector[T] = - var a = RLimit() - if getrlimit(posix.RLIMIT_NOFILE, a) != 0: - raiseIOSelectorsError(osLastError()) - var maxFD = int(a.rlim_max) + var maxFD = maxDescriptors() when hasThreadSupport: result = cast[Selector[T]](allocShared0(sizeof(SelectorImpl[T]))) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 6f216ac85..88cbaf28c 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -313,7 +313,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, verifySelectParams(timeout) if timeout != -1: - when defined(genode) or defined(freertos): + when defined(genode) or defined(freertos) or defined(zephyr): tv.tv_sec = Time(timeout div 1_000) else: tv.tv_sec = timeout.int32 div 1_000 diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 13c08dd92..4037d7181 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -21,6 +21,7 @@ when hostOS == "solaris": {.passl: "-lsocket -lnsl".} const useWinVersion = defined(windows) or defined(nimdoc) +const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) when useWinVersion: import winlean @@ -35,9 +36,12 @@ else: export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, Sockaddr_in6, Sockaddr_storage, - inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto, + recv, `==`, connect, send, accept, recvfrom, sendto, freeAddrInfo +when not useNimNetLite: + export inet_ntoa + export SO_ERROR, SOL_SOCKET, @@ -332,125 +336,6 @@ template htons*(x: uint16): untyped = ## order, this is a no-op; otherwise, it performs a 2-byte swap operation. nativesockets.ntohs(x) -proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = - ## Searches the database from the beginning and finds the first entry for - ## which the service name specified by `name` matches the s_name member - ## and the protocol name specified by `proto` matches the s_proto member. - ## - ## On posix this will search through the `/etc/services` file. - when useWinVersion: - var s = winlean.getservbyname(name, proto) - else: - var s = posix.getservbyname(name, proto) - if s == nil: raiseOSError(osLastError(), "Service not found.") - result.name = $s.s_name - result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = Port(s.s_port) - result.proto = $s.s_proto - -proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = - ## Searches the database from the beginning and finds the first entry for - ## which the port specified by `port` matches the s_port member and the - ## protocol name specified by `proto` matches the s_proto member. - ## - ## On posix this will search through the `/etc/services` file. - when useWinVersion: - var s = winlean.getservbyport(ze(int16(port)).cint, proto) - else: - var s = posix.getservbyport(ze(int16(port)).cint, proto) - if s == nil: raiseOSError(osLastError(), "Service not found.") - result.name = $s.s_name - result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = Port(s.s_port) - result.proto = $s.s_proto - -proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = - ## This function will lookup the hostname of an IP Address. - var myaddr: InAddr - myaddr.s_addr = inet_addr(ip) - - when useWinVersion: - var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, - cint(AF_INET)) - if s == nil: raiseOSError(osLastError()) - else: - var s = - when defined(android4): - posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint, - cint(posix.AF_INET)) - else: - posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen, - cint(posix.AF_INET)) - if s == nil: - raiseOSError(osLastError(), $hstrerror(h_errno)) - - result.name = $s.h_name - result.aliases = cstringArrayToSeq(s.h_aliases) - when useWinVersion: - result.addrtype = Domain(s.h_addrtype) - else: - if s.h_addrtype == posix.AF_INET: - result.addrtype = AF_INET - elif s.h_addrtype == posix.AF_INET6: - result.addrtype = AF_INET6 - else: - raiseOSError(osLastError(), "unknown h_addrtype") - if result.addrtype == AF_INET: - result.addrList = @[] - var i = 0 - while not isNil(s.h_addr_list[i]): - var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i]) - result.addrList.add($inet_ntoa(inaddrPtr[])) - inc(i) - else: - result.addrList = cstringArrayToSeq(s.h_addr_list) - result.length = int(s.h_length) - -proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = - ## This function will lookup the IP address of a hostname. - when useWinVersion: - var s = winlean.gethostbyname(name) - else: - var s = posix.gethostbyname(name) - if s == nil: raiseOSError(osLastError()) - result.name = $s.h_name - result.aliases = cstringArrayToSeq(s.h_aliases) - when useWinVersion: - result.addrtype = Domain(s.h_addrtype) - else: - if s.h_addrtype == posix.AF_INET: - result.addrtype = AF_INET - elif s.h_addrtype == posix.AF_INET6: - result.addrtype = AF_INET6 - else: - raiseOSError(osLastError(), "unknown h_addrtype") - if result.addrtype == AF_INET: - result.addrList = @[] - var i = 0 - while not isNil(s.h_addr_list[i]): - var inaddrPtr = cast[ptr InAddr](s.h_addr_list[i]) - result.addrList.add($inet_ntoa(inaddrPtr[])) - inc(i) - else: - result.addrList = cstringArrayToSeq(s.h_addr_list) - result.length = int(s.h_length) - -proc getHostname*(): string {.tags: [ReadIOEffect].} = - ## Returns the local hostname (not the FQDN) - # https://tools.ietf.org/html/rfc1035#section-2.3.1 - # https://tools.ietf.org/html/rfc2181#section-11 - const size = 256 - result = newString(size) - when useWinVersion: - let success = winlean.gethostname(result, size) - else: - # Posix - let success = posix.gethostname(result, size) - if success != 0.cint: - raiseOSError(osLastError()) - let x = len(cstring(result)) - result.setLen(x) - proc getSockDomain*(socket: SocketHandle): Domain = ## Returns the socket's domain (AF_INET or AF_INET6). var name: Sockaddr_in6 @@ -464,162 +349,354 @@ proc getSockDomain*(socket: SocketHandle): Domain = else: raise newException(IOError, "Unknown socket family in getSockDomain") -proc getAddrString*(sockAddr: ptr SockAddr): string = - ## Returns the string representation of address within sockAddr - if sockAddr.sa_family.cint == nativeAfInet: - result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr) - elif sockAddr.sa_family.cint == nativeAfInet6: - let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int - else: 46 # it's actually 46 in both cases - result = newString(addrLen) - let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr - when not useWinVersion: - if posix.inet_ntop(posix.AF_INET6, addr6, addr result[0], - result.len.int32) == nil: - raiseOSError(osLastError()) - if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0: - result.setSlice("::ffff:".len..= Sockaddr_un_path_length: + raise newException(ValueError, "socket path too long") + copyMem(addr result.sun_path, path.cstring, path.len + 1) + + proc getSockName*(socket: SocketHandle): Port = + ## Returns the socket's associated port number. + var name: Sockaddr_in + when useWinVersion: + name.sin_family = uint16(ord(AF_INET)) + else: + name.sin_family = TSa_Family(posix.AF_INET) + #name.sin_port = htons(cint16(port)) + #name.sin_addr.s_addr = htonl(INADDR_ANY) + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = Port(nativesockets.ntohs(name.sin_port)) + + proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## Returns the socket's local address and port number. + ## + ## Similar to POSIX's `getsockname`:idx:. + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = uint16(ord(AF_INET)) + else: + name.sin_family = TSa_Family(posix.AF_INET) + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: raiseOSError(osLastError()) - else: - raise newException(IOError, "Unknown socket family in getAddrString") - setLen(strAddress, len(cstring(strAddress))) + result = ($inet_ntoa(name.sin_addr), + Port(nativesockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = uint16(ord(AF_INET6)) + else: + name.sin6_family = TSa_Family(posix.AF_INET6) + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + result[0] = newString(64) + if inet_ntop(name.sin6_family.cint, + addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: + raiseOSError(osLastError()) + setLen(result[0], result[0].cstring.len) + result[1] = Port(nativesockets.ntohs(name.sin6_port)) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") -when defined(posix) and not defined(nimdoc): - proc makeUnixAddr*(path: string): Sockaddr_un = - result.sun_family = AF_UNIX.TSa_Family - if path.len >= Sockaddr_un_path_length: - raise newException(ValueError, "socket path too long") - copyMem(addr result.sun_path, path.cstring, path.len + 1) + proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## Returns the socket's peer address and port number. + ## + ## Similar to POSIX's `getpeername`:idx: + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = uint16(ord(AF_INET)) + else: + name.sin_family = TSa_Family(posix.AF_INET) + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = ($inet_ntoa(name.sin_addr), + Port(nativesockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = uint16(ord(AF_INET6)) + else: + name.sin6_family = TSa_Family(posix.AF_INET6) + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + result[0] = newString(64) + if inet_ntop(name.sin6_family.cint, + addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: + raiseOSError(osLastError()) + setLen(result[0], result[0].cstring.len) + result[1] = Port(nativesockets.ntohs(name.sin6_port)) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + +when useNimNetLite: -proc getSockName*(socket: SocketHandle): Port = - ## Returns the socket's associated port number. - var name: Sockaddr_in when useWinVersion: - name.sin_family = uint16(ord(AF_INET)) - else: - name.sin_family = TSa_Family(posix.AF_INET) - #name.sin_port = htons(cint16(port)) - #name.sin_addr.s_addr = htonl(INADDR_ANY) - var namelen = sizeof(name).SockLen - if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - result = Port(nativesockets.ntohs(name.sin_port)) + const + INET_ADDRSTRLEN = 16 + INET6_ADDRSTRLEN = 46 # it's actually 46 in both cases -proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## Returns the socket's local address and port number. - ## - ## Similar to POSIX's `getsockname`:idx:. - case domain - of AF_INET: - var name: Sockaddr_in - when useWinVersion: - name.sin_family = uint16(ord(AF_INET)) - else: - name.sin_family = TSa_Family(posix.AF_INET) - var namelen = sizeof(name).SockLen - if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - result = ($inet_ntoa(name.sin_addr), - Port(nativesockets.ntohs(name.sin_port))) - of AF_INET6: - var name: Sockaddr_in6 - when useWinVersion: - name.sin6_family = uint16(ord(AF_INET6)) - else: - name.sin6_family = TSa_Family(posix.AF_INET6) - var namelen = sizeof(name).SockLen - if getsockname(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - # Cannot use INET6_ADDRSTRLEN here, because it's a C define. - result[0] = newString(64) - if inet_ntop(name.sin6_family.cint, - addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: - raiseOSError(osLastError()) - setLen(result[0], result[0].cstring.len) - result[1] = Port(nativesockets.ntohs(name.sin6_port)) - else: - raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + proc sockAddrToStr(sa: ptr Sockaddr): string {.noinit.} = + let af_family = sa.sa_family + var nl, v4Slice: cint + var si_addr: ptr InAddr -proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = - ## Returns the socket's peer address and port number. - ## - ## Similar to POSIX's `getpeername`:idx: - case domain - of AF_INET: - var name: Sockaddr_in - when useWinVersion: - name.sin_family = uint16(ord(AF_INET)) + if af_family == AF_INET.TSa_Family: + nl = INET_ADDRSTRLEN + si_addr = cast[ptr Sockaddr_in](sa).sin_addr.addr() + elif af_family == AF_INET6.TSa_Family: + nl = INET6_ADDRSTRLEN + let si6_addr = cast[ptr Sockaddr_in6](sa).sin6_addr.addr() + si_addr = cast[ptr InAddr](si6_addr) # let's us reuse logic below + when defined(posix) and not defined(nimdoc) and not defined(zephyr): + if posix.IN6_IS_ADDR_V4MAPPED(si6_addr) != 0: + v4Slice = "::ffff:".len() else: - name.sin_family = TSa_Family(posix.AF_INET) - var namelen = sizeof(name).SockLen - if getpeername(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: - raiseOSError(osLastError()) - result = ($inet_ntoa(name.sin_addr), - Port(nativesockets.ntohs(name.sin_port))) - of AF_INET6: - var name: Sockaddr_in6 - when useWinVersion: - name.sin6_family = uint16(ord(AF_INET6)) + when defined(posix) and not defined(nimdoc): + if af_family.cint == nativeAfUnix: + return "unix" + return "" + + result = newString(nl) + let namePtr = result.cstring() + if namePtr == inet_ntop(af_family.cint, si_addr, namePtr, nl): + result.setLen(len(namePtr)) + if v4Slice > 0: result.setSlice(v4Slice.int ..< nl.int) else: - name.sin6_family = TSa_Family(posix.AF_INET6) - var namelen = sizeof(name).SockLen - if getpeername(socket, cast[ptr SockAddr](addr(name)), - addr(namelen)) == -1'i32: + return "" + + proc sockAddrToStr(sa: var Sockaddr_in | var Sockaddr_in6): string = + result = sockAddrToStr(cast[ptr SockAddr](unsafeAddr(sa))) + + proc getAddrString*(sockAddr: ptr SockAddr): string = + result = sockAddrToStr(sockAddr) + if result.len() == 0: raiseOSError(osLastError()) - # Cannot use INET6_ADDRSTRLEN here, because it's a C define. - result[0] = newString(64) - if inet_ntop(name.sin6_family.cint, - addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: - raiseOSError(osLastError()) - setLen(result[0], result[0].cstring.len) - result[1] = Port(nativesockets.ntohs(name.sin6_port)) - else: - raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + + proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) {.noinit.} = + strAddress = getAddrString(sockAddr) + + proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## Returns the socket's local address and port number. + ## + ## Similar to POSIX's `getsockname`:idx:. + template sockGetNameOrRaiseError(socket: untyped, name: untyped) = + var namelen = sizeof(socket).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + + case domain + of AF_INET: + var name = Sockaddr_in(sin_family: TSa_Family(posix.AF_INET)) + sockGetNameOrRaiseError(socket, name) + result = (sockAddrToStr(name), + Port(nativesockets.ntohs(name.sin_port))) + of AF_INET6: + var name = Sockaddr_in6(sin6_family: TSa_Family(posix.AF_INET6)) + sockGetNameOrRaiseError(socket, name) + result = (sockAddrToStr(name), + Port(nativesockets.ntohs(name.sin6_port))) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. tags: [ReadIOEffect].} = @@ -733,14 +810,14 @@ proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (Socke ## child processes. ## ## Returns (osInvalidSocket, "") if an error occurred. - var sockAddress: Sockaddr_in + var sockAddress: Sockaddr var addrLen = sizeof(sockAddress).SockLen var sock = when (defined(linux) or defined(bsd)) and not defined(nimdoc): - accept4(fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen), + accept4(fd, addr(sockAddress), addr(addrLen), if inheritable: 0 else: SOCK_CLOEXEC) else: - accept(fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) + accept(fd, addr(sockAddress), addr(addrLen)) when declared(setInheritable) and not (defined(linux) or defined(bsd)): if not setInheritable(sock, inheritable): close sock @@ -748,7 +825,11 @@ proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (Socke if sock == osInvalidSocket: return (osInvalidSocket, "") else: - return (sock, $inet_ntoa(sockAddress.sin_addr)) + when useNimNetLite: + var name = sockAddrToStr(addr sockAddress) + return (sock, name) + else: + return (sock, $inet_ntoa(cast[Sockaddr_in](sockAddress).sin_addr)) when defined(windows): var wsa: WSAData diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 09cdc8afb..7b0ff78e7 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -85,12 +85,14 @@ runnableExamples("-r:off"): import std/private/since -import nativesockets, os, strutils, times, sets, options, std/monotimes +import nativesockets +import os, strutils, times, sets, options, std/monotimes import ssl_config export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol const useWinVersion = defined(windows) or defined(nimdoc) +const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) const defineSsl = defined(ssl) or defined(nimdoc) when useWinVersion: @@ -1243,11 +1245,12 @@ proc getLocalAddr*(socket: Socket): (string, Port) = ## This is high-level interface for `getsockname`:idx:. getLocalAddr(socket.fd, socket.domain) -proc getPeerAddr*(socket: Socket): (string, Port) = - ## Get the socket's peer address and port number. - ## - ## This is high-level interface for `getpeername`:idx:. - getPeerAddr(socket.fd, socket.domain) +when not useNimNetLite: + proc getPeerAddr*(socket: Socket): (string, Port) = + ## Get the socket's peer address and port number. + ## + ## This is high-level interface for `getpeername`:idx:. + getPeerAddr(socket.fd, socket.domain) proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.tags: [WriteIOEffect].} = @@ -1259,7 +1262,7 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) -when defined(posix) or defined(nimdoc): +when defined(nimdoc) or (defined(posix) and not useNimNetLite): proc connectUnix*(socket: Socket, path: string) = ## Connects to Unix socket on `path`. ## This only works on Unix-style systems: Mac OS X, BSD and Linux diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 82550e09b..ec441f6da 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -323,6 +323,23 @@ else: # Anything higher is the time to wait in milliseconds. doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout) + when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or + defined(zephyr) or defined(freertos): + template maxDescriptors*(): int = + ## Returns the maximum number of active file descriptors for the current + ## process. This involves a system call. For now `maxDescriptors` is + ## supported on the following OSes: Windows, Linux, OSX, BSD. + when defined(windows): + 16_700_000 + elif defined(zephyr) or defined(freertos): + FD_MAX + else: + var fdLim: RLimit + var res = int(getrlimit(RLIMIT_NOFILE, fdLim)) + if res >= 0: + res = int(fdLim.rlim_cur) - 1 + res + when defined(linux) and not defined(emscripten): include ioselects/ioselectors_epoll elif bsdPlatform: @@ -337,5 +354,7 @@ else: include ioselects/ioselectors_select elif defined(freertos) or defined(lwip): include ioselects/ioselectors_select + elif defined(zephyr): + include ioselects/ioselectors_poll else: include ioselects/ioselectors_poll diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index e5f26e070..259d36633 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -142,14 +142,29 @@ proc c_sprintf*(buf, frmt: cstring): cint {. importc: "sprintf", header: "", varargs, noSideEffect.} # we use it only in a way that cannot lead to security issues -proc c_malloc*(size: csize_t): pointer {. - importc: "malloc", header: "".} -proc c_calloc*(nmemb, size: csize_t): pointer {. - importc: "calloc", header: "".} -proc c_free*(p: pointer) {. - importc: "free", header: "".} -proc c_realloc*(p: pointer, newsize: csize_t): pointer {. - importc: "realloc", header: "".} +when defined(zephyr) and not defined(zephyrUseLibcMalloc): + proc c_malloc*(size: csize_t): pointer {. + importc: "k_malloc", header: "".} + proc c_calloc*(nmemb, size: csize_t): pointer {. + importc: "k_calloc", header: "".} + proc c_free*(p: pointer) {. + importc: "k_free", header: "".} + proc c_realloc*(p: pointer, newsize: csize_t): pointer = + # Zephyr's kernel malloc doesn't support realloc + result = c_malloc(newSize) + # match the ansi c behavior + if not result.isNil(): + copyMem(result, p, newSize) + c_free(p) +else: + proc c_malloc*(size: csize_t): pointer {. + importc: "malloc", header: "".} + proc c_calloc*(nmemb, size: csize_t): pointer {. + importc: "calloc", header: "".} + proc c_free*(p: pointer) {. + importc: "free", header: "".} + proc c_realloc*(p: pointer, newsize: csize_t): pointer {. + importc: "realloc", header: "".} proc c_fwrite*(buf: pointer, size, n: csize_t, f: CFilePtr): cint {. importc: "fwrite", header: "".} diff --git a/lib/system/bitmasks.nim b/lib/system/bitmasks.nim index d7c55a4d9..caf86568a 100644 --- a/lib/system/bitmasks.nim +++ b/lib/system/bitmasks.nim @@ -15,6 +15,7 @@ const PageSize = 1 shl PageShift PageMask = PageSize-1 + MemAlign = # also minimal allocatable memory block when defined(useMalloc): when defined(amd64): 16 diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index c14fcf31e..36c2c5fe1 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -176,7 +176,7 @@ elif defined(genode): proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = raiseAssert("nimGetProcAddr not implemented") -elif defined(nintendoswitch) or defined(freertos): +elif defined(nintendoswitch) or defined(freertos) or defined(zephyr): proc nimUnloadLibrary(lib: LibHandle) = cstderr.rawWrite("nimUnLoadLibrary not implemented") cstderr.rawWrite("\n") diff --git a/lib/system/io.nim b/lib/system/io.nim index 59f070f73..6f4accc2a 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -347,7 +347,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w ## availability with `declared() `. when SupportIoctlInheritCtl: result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1 - elif defined(freertos): + elif defined(freertos) or defined(zephyr): result = true elif defined(posix): var flags = c_fcntl(f, F_GETFD) @@ -780,8 +780,11 @@ when declared(stdout): var echoLock: SysLock initSysLock echoLock - const stdOutLock = not defined(windows) and not defined(android) and - not defined(nintendoswitch) and not defined(freertos) and + const stdOutLock = not defined(windows) and + not defined(android) and + not defined(nintendoswitch) and + not defined(freertos) and + not defined(zephyr) and hostOS != "any" proc echoBinSafe(args: openArray[string]) {.compilerproc.} = diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 2ba5c0fec..d41dce705 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -2,13 +2,22 @@ {.push stackTrace: off.} proc allocImpl(size: Natural): pointer = - c_malloc(size.csize_t) + result = c_malloc(size.csize_t) + when defined(zephyr): + if result == nil: + raiseOutOfMem() proc alloc0Impl(size: Natural): pointer = - c_calloc(size.csize_t, 1) + result = c_calloc(size.csize_t, 1) + when defined(zephyr): + if result == nil: + raiseOutOfMem() proc reallocImpl(p: pointer, newSize: Natural): pointer = - c_realloc(p, newSize.csize_t) + result = c_realloc(p, newSize.csize_t) + when defined(zephyr): + if result == nil: + raiseOutOfMem() proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = result = realloc(p, newSize.csize_t) diff --git a/tests/stdlib/tlwip.nim b/tests/stdlib/tlwip.nim index 7f7822236..fc53be592 100644 --- a/tests/stdlib/tlwip.nim +++ b/tests/stdlib/tlwip.nim @@ -1,6 +1,6 @@ discard """ targets: "c" - cmd: "nim $target --os:freertos --gc:arc $options $file" + cmd: "nim $target --compileOnly --os:freertos --gc:arc $options $file" disabled: "bsd" disabled: "windows" action: compile From 582468da1cc266d0dd922ec5c620713bbc45d02a Mon Sep 17 00:00:00 2001 From: Tail Wag Games Date: Mon, 25 Oct 2021 03:13:30 -0500 Subject: [PATCH 3090/4254] deinitializing locks at program exit (#19043) * deinitializing locks at program exit * deinitLock shouldn't be called for js backend I guess... * I suppose this is the best way to detect the ewruntime option * I guess I need these guards here too... * fixing merge conflict --- lib/std/exitprocs.nim | 3 +++ lib/system/io.nim | 56 ++++++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index c6537f7f8..c76583a8c 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -44,6 +44,9 @@ proc callClosures() {.noconv.} = of kClosure: fun.fun1() of kNoconv: fun.fun2() + when not defined(js) and not defined(nimOwnedEnabled): + deinitLock(gFunsLock) + template fun() = if gFuns.len == 0: addAtExit(callClosures) diff --git a/lib/system/io.nim b/lib/system/io.nim index 6f4accc2a..e7369392a 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -20,19 +20,19 @@ type incompleteStruct.} = object File* = ptr CFile ## The type representing a file handle. - FileMode* = enum ## The file mode when opening a file. - fmRead, ## Open the file for read access only. - fmWrite, ## Open the file for write access only. - ## If the file does not exist, it will be - ## created. Existing files will be cleared! - fmReadWrite, ## Open the file for read and write access. - ## If the file does not exist, it will be - ## created. Existing files will be cleared! - fmReadWriteExisting, ## Open the file for read and write access. - ## If the file does not exist, it will not be - ## created. The existing file will not be cleared. - fmAppend ## Open the file for writing only; append data - ## at the end. + FileMode* = enum ## The file mode when opening a file. + fmRead, ## Open the file for read access only. + fmWrite, ## Open the file for write access only. + ## If the file does not exist, it will be + ## created. Existing files will be cleared! + fmReadWrite, ## Open the file for read and write access. + ## If the file does not exist, it will be + ## created. Existing files will be cleared! + fmReadWriteExisting, ## Open the file for read and write access. + ## If the file does not exist, it will not be + ## created. The existing file will not be cleared. + fmAppend ## Open the file for writing only; append data + ## at the end. FileHandle* = cint ## type that represents an OS file handle; this is ## useful for low-level file access @@ -40,7 +40,8 @@ type # text file handling: when not defined(nimscript) and not defined(js): # duplicated between io and ansi_c - const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined(dragonfly)) and not defined(emscripten) + const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined( + dragonfly)) and not defined(emscripten) const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr" const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout" const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin" @@ -158,7 +159,7 @@ proc checkErr(f: File) = # shouldn't happen quit(1) -{.push stackTrace:off, profiler:off.} +{.push stackTrace: off, profiler: off.} proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. tags: [ReadIOEffect], benign.} = ## reads `len` bytes into the buffer pointed to by `buffer`. Returns @@ -167,7 +168,8 @@ proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. result = cast[int](c_fread(buffer, 1, cast[csize_t](len), f)) if result != len: checkErr(f) -proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {. +proc readBytes*(f: File, a: var openArray[int8|uint8], start, + len: Natural): int {. tags: [ReadIOEffect], benign.} = ## reads `len` bytes into the buffer `a` starting at `a[start]`. Returns ## the actual number of bytes that have been read which may be less than @@ -418,8 +420,8 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], numberOfCharsRead -= 2 # handle Ctrl+Z as EOF for i in 0..", final, pure.} = object ## struct stat filler_1: array[24, char] - st_mode: Mode ## Mode of file + st_mode: Mode ## Mode of file filler_2: array[144 - 24 - 4, char] proc modeIsDir(m: Mode): bool = @@ -660,7 +662,7 @@ when defined(posix) and not defined(nimscript): Stat {.importc: "struct stat", header: "", final, pure.} = object ## struct stat - st_mode: Mode ## Mode of file + st_mode: Mode ## Mode of file proc modeIsDir(m: Mode): bool {.importc: "S_ISDIR", header: "".} ## Test for a directory. @@ -727,7 +729,8 @@ proc open*(f: var File, filehandle: FileHandle, ## ## The passed file handle will no longer be inheritable. when not defined(nimInheritHandles) and declared(setInheritable): - let oshandle = when defined(windows): FileHandle getOsfhandle(filehandle) else: filehandle + let oshandle = when defined(windows): FileHandle getOsfhandle( + filehandle) else: filehandle if not setInheritable(oshandle, false): return false f = c_fdopen(filehandle, FormatOpen[mode]) @@ -780,6 +783,10 @@ when declared(stdout): var echoLock: SysLock initSysLock echoLock + when not defined(js) and not defined(nimOwnedEnabled): + import std/exitprocs + addExitProc(proc() {.noconv.} = deinitSys echoLock) + const stdOutLock = not defined(windows) and not defined(android) and not defined(nintendoswitch) and @@ -898,7 +905,8 @@ proc readLines*(filename: string, n: Natural): seq[string] = else: sysFatal(IOError, "cannot open: " & filename) -template readLines*(filename: string): seq[string] {.deprecated: "use readLines with two arguments".} = +template readLines*(filename: string): seq[ + string] {.deprecated: "use readLines with two arguments".} = readLines(filename, 1) iterator lines*(filename: string): string {.tags: [ReadIOEffect].} = @@ -915,7 +923,7 @@ iterator lines*(filename: string): string {.tags: [ReadIOEffect].} = for line in filename.lines: buffer.add(line.replace("a", "0") & '\n') writeFile(filename, buffer) - var f = open(filename, bufSize=8000) + var f = open(filename, bufSize = 8000) try: var res = newStringOfCap(80) while f.readLine(res): yield res From 3ecb369ca1a12754486429bda4ab0bc60f9b86d7 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Tue, 26 Oct 2021 02:33:26 -0400 Subject: [PATCH 3091/4254] Document file changes that may be needed for add a new platform (#19055) Co-authored-by: quantimnot --- doc/intern.rst | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/doc/intern.rst b/doc/intern.rst index fe0d333fd..e8fb4ac86 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -207,6 +207,42 @@ implementation uses C's `setjmp`:c: function to store all registers on the hardware stack. It may be necessary that the new platform needs to replace this generic code by some assembler code. +Files that may need changed for your platform include: + +* `compiler/platform.nim` + Add os/cpu properties. +* `lib/system.nim` + Add os/cpu to the documentation for `system.hostOS` and `system.hostCPU`. +* `compiler/options.nim` + Add special os/cpu property checks in `isDefined`. +* `compiler/installer.ini` + Add os/cpu to `Project.Platforms` field. +* `lib/system/platforms.nim` + Add os/cpu. +* `lib/pure/include/osseps.nim` + Add os specializations. +* `lib/pure/distros.nim` + Add os, package handler. +* `tools/niminst/makefile.nimf` + Add os/cpu compiler/linker flags. +* `tools/niminst/buildsh.nimf` + Add os/cpu compiler/linker flags. + +If the `--os` or `--cpu` options aren't passed to the compiler, then Nim will +determine the current host os, cpu and endianess from `system.cpuEndian`, +`system.hostOS` and `system.hostCPU`. Those values are derived from +`compiler/platform.nim`. + +In order for the new platform to be bootstrapped from the `csources`, it must: + +* have `compiler/platform.nim` updated +* have `compiler/installer.ini` updated +* have `tools/niminst/buildsh.nimf` updated +* have `tools/niminst/makefile.nimf` updated +* be backported to the Nim version used by the `csources` +* the new `csources` must be pushed +* the new `csources` revision must be updated in `config/build_config.txt` + Runtime type information ======================== From 83a2515af7aeb9a1c12015321243399a0d1f4c95 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Tue, 26 Oct 2021 03:27:11 -0600 Subject: [PATCH 3092/4254] Fixed generic distinct conversions for 'var' (#18837) * SameTypeAux now properly traverses generic distincts * Smarter traversal of distincts * Removed redundant check * Fixed nkConv for jsgen * Added test for non distinct nkConv * using skiptypes for distinct now * Fixed genaddr for nkconv --- compiler/jsgen.nim | 140 +++++++++++++---------- compiler/types.nim | 8 +- tests/converter/texplicit_conversion.nim | 6 + tests/distinct/tdistinct.nim | 17 +++ 4 files changed, 104 insertions(+), 67 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ff4d2839e..7e8c25173 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1288,75 +1288,89 @@ template isIndirect(x: PSym): bool = v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator, skConst, skTemp, skLet}) -proc genAddr(p: PProc, n: PNode, r: var TCompRes) = - case n[0].kind - of nkSym: - let s = n[0].sym - if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") - case s.kind - of skParam: - r.res = s.loc.r - r.address = nil - r.typ = etyNone - of skVar, skLet, skResult: - r.kind = resExpr - let jsType = mapType(p, n.typ) - if jsType == etyObject: - # make addr() a no-op: - r.typ = etyNone - if isIndirect(s): - r.res = s.loc.r & "[0]" - else: - r.res = s.loc.r - r.address = nil - elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex: - # for ease of code generation, we do not distinguish between - # sfAddrTaken and sfGlobal. - r.typ = etyBaseIndex - r.address = s.loc.r - r.res = rope("0") +proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = + let s = n.sym + if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") + case s.kind + of skParam: + r.res = s.loc.r + r.address = nil + r.typ = etyNone + of skVar, skLet, skResult: + r.kind = resExpr + let jsType = mapType(p): + if typ.isNil: + n.typ else: - # 'var openArray' for instance produces an 'addr' but this is harmless: - gen(p, n[0], r) - #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n)) - else: internalError(p.config, n.info, $("genAddr: 2", s.kind)) - of nkCheckedFieldExpr: - genCheckedFieldOp(p, n[0], n.typ, r) - of nkDotExpr: - if mapType(p, n.typ) == etyBaseIndex: - genFieldAddr(p, n[0], r) + typ + if jsType == etyObject: + # make addr() a no-op: + r.typ = etyNone + if isIndirect(s): + r.res = s.loc.r & "[0]" + else: + r.res = s.loc.r + r.address = nil + elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex: + # for ease of code generation, we do not distinguish between + # sfAddrTaken and sfGlobal. + r.typ = etyBaseIndex + r.address = s.loc.r + r.res = rope("0") else: - genFieldAccess(p, n[0], r) - of nkBracketExpr: - var ty = skipTypes(n[0].typ, abstractVarRange) - if ty.kind in MappedToObject: - gen(p, n[0], r) - else: - let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind - case kindOfIndexedExpr - of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs: - genArrayAddr(p, n[0], r) - of tyTuple: - genFieldAddr(p, n[0], r) - else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') - of nkObjDownConv: - gen(p, n[0], r) - of nkHiddenDeref: - gen(p, n[0], r) - of nkHiddenAddr: - gen(p, n[0], r) - of nkStmtListExpr: - if n.len == 1: gen(p, n[0], r) - else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr") - of nkCallKinds: - if n[0].typ.kind == tyOpenArray: # 'var openArray' for instance produces an 'addr' but this is harmless: - # namely toOpenArray(a, 1, 3) + gen(p, n, r) + #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n)) + else: internalError(p.config, n.info, $("genAddr: 2", s.kind)) + +proc genAddr(p: PProc, n: PNode, r: var TCompRes) = + if n.kind == nkSym: + genSymAddr(p, n, nil, r) + else: + case n[0].kind + of nkSym: + genSymAddr(p, n[0], n.typ, r) + of nkCheckedFieldExpr: + genCheckedFieldOp(p, n[0], n.typ, r) + of nkDotExpr: + if mapType(p, n.typ) == etyBaseIndex: + genFieldAddr(p, n[0], r) + else: + genFieldAccess(p, n[0], r) + of nkBracketExpr: + var ty = skipTypes(n[0].typ, abstractVarRange) + if ty.kind in MappedToObject: + gen(p, n[0], r) + else: + let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind + case kindOfIndexedExpr + of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs: + genArrayAddr(p, n[0], r) + of tyTuple: + genFieldAddr(p, n[0], r) + of tyGenericBody: + genAddr(p, n[^1], r) + else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') + of nkObjDownConv: gen(p, n[0], r) + of nkHiddenDeref: + gen(p, n[0], r) + of nkHiddenAddr: + gen(p, n[0], r) + of nkConv: + genAddr(p, n[0], r) + of nkStmtListExpr: + if n.len == 1: gen(p, n[0], r) + else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr") + of nkCallKinds: + if n[0].typ.kind == tyOpenArray: + # 'var openArray' for instance produces an 'addr' but this is harmless: + # namely toOpenArray(a, 1, 3) + gen(p, n[0], r) + else: + internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) - else: - internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) proc attachProc(p: PProc; content: Rope; s: PSym) = p.g.code.add(content) diff --git a/compiler/types.nim b/compiler/types.nim index cf6579317..2c7b91d9f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1121,15 +1121,15 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = case c.cmp of dcEq: return false of dcEqIgnoreDistinct: - while a.kind == tyDistinct: a = a[0] - while b.kind == tyDistinct: b = b[0] + a = a.skipTypes({tyDistinct, tyGenericInst}) + b = b.skipTypes({tyDistinct, tyGenericInst}) if a.kind != b.kind: return false of dcEqOrDistinctOf: - while a.kind == tyDistinct: a = a[0] + a = a.skipTypes({tyDistinct, tyGenericInst}) if a.kind != b.kind: return false # this is required by tunique_type but makes no sense really: - if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags: + if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags: let lhs = x.skipGenericAlias rhs = y.skipGenericAlias diff --git a/tests/converter/texplicit_conversion.nim b/tests/converter/texplicit_conversion.nim index 6b2e96faf..e36d78ad5 100644 --- a/tests/converter/texplicit_conversion.nim +++ b/tests/converter/texplicit_conversion.nim @@ -11,3 +11,9 @@ converter toInt(s: string): int = let x = (int)"234" echo x + +block: # Test for nkconv + proc foo(o: var int) = + assert o == 0 + var a = 0 + foo(int(a)) \ No newline at end of file diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index fd60b4ac0..dd8237854 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -8,6 +8,7 @@ false false false Foo +foo ''' """ @@ -140,6 +141,22 @@ block tRequiresInit: let s = "test" doAssert s == "test" +block: #17322 + type + A[T] = distinct string + + proc foo(a: var A) = + a.string.add "foo" + + type + B = distinct A[int] + + var b: B + foo(A[int](b)) + echo A[int](b).string + b.string.add "bar" + assert b.string == "foobar" + type Foo = distinct string template main() = From 8d5a27518929bd4c54f4beb7e40a5fc382d3dd05 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Tue, 26 Oct 2021 03:29:07 -0600 Subject: [PATCH 3093/4254] Fixed distinct composite type class proc borrowing (#18904) * Fixed composite type class proc borrowing * Moved borrow search into transf * added borrow check to symbol flag --- compiler/semcall.nim | 13 +++++++++++-- compiler/seminst.nim | 6 +++++- compiler/transf.nim | 8 ++++++++ tests/borrow/typeclassborrow.nim | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 tests/borrow/typeclassborrow.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index a3064788e..36658d472 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -703,7 +703,16 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = call.add(newIdentNode(fn.name, fn.info)) for i in 1.. Date: Tue, 26 Oct 2021 13:32:52 -0500 Subject: [PATCH 3094/4254] Fix #19052; [backport:1.6.0] (#19053) * Fix #19052; [backport:1.6.0] Adds a compile flag to avoid a getrandom syscall, fixing #19052. This is neccesary when the getrandom syscall is missing, as noted in #19052, particularly in kernel versions < 3.17 when getrandom was introduced. Specifically relevant is this is missing from kernel 3.10, which is the supported kernel throughout RHEL 7 and CentOS 7, which is widely used at many organizations. Without this, versions of nim that include sysrand (i.e. versions >= 1.6.0) will not compile without modification, however with this change a compile flag may be used to fall back using /dev/urandom as done with any unknown Posix OS (preferred here as a fallback since it already supplies a cryptographically secure PRNG and existing code deals with entropy pool init, etc). The change is placed behind a compile flag, as discussed in github ticket #19052 (summed up here): * First, I can't seem to catch that a importc such as SYS_getrandom is declared without using it (the declared proc returns true, but compiler throws an undeclared identifier flag when referencing it). * Second, it seemed preferable to be behaviorally explicit vs implicit when considering this is intended to be a cryptographically secure PRNG. * Third, if I intend to compile on a kernel >= 3.17 while running the binary on at least one system < 3.17, I'll want to be able to target this without relying on a compile time determination if the getrandom syscall is available. * Documenting compile flag for -d:nimNoGetRandom and adding changelog entry Related to #19052 and comments in PR #19053. Also created a new changelog file since none currently exists. Co-authored-by: Timothy Alexander --- changelogs/changelog.md | 31 +++++++++++++++++++++++++++++++ lib/std/sysrand.nim | 7 ++++++- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 changelogs/changelog.md diff --git a/changelogs/changelog.md b/changelogs/changelog.md new file mode 100644 index 000000000..475f568ec --- /dev/null +++ b/changelogs/changelog.md @@ -0,0 +1,31 @@ +# v1.xx.x - yyyy-mm-dd + +## Changes affecting backward compatibility + +## Standard library additions and changes + +### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall + +This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17. + +On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall. + +When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be: +```sh +$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details +$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8 +$ sh build.sh # per unix install instructions +$ bin/nim c koch # per unix install instructions +$ ./koch boot -d:release # per unix install instructions +$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall +``` + +This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular). + +## Language changes + + +## Compiler changes + + +## Tool changes diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 75983e3c6..b35f24a72 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -38,6 +38,11 @@ ## .. _randomFillSync: https://nodejs.org/api/crypto.html#crypto_crypto_randomfillsync_buffer_offset_size ## .. _/dev/urandom: https://en.wikipedia.org/wiki//dev/random ## +## On a Linux target, a call to the `getrandom` syscall can be avoided (e.g. +## for targets running kernel version < 3.17) by passing a compile flag of +## `-d:nimNoGetRandom`. If this flag is passed, sysrand will use `/dev/urandom` +## as with any other POSIX compliant OS. +## runnableExamples: doAssert urandom(0).len == 0 @@ -159,7 +164,7 @@ elif defined(windows): result = randomBytes(addr dest[0], size) -elif defined(linux): +elif defined(linux) and not defined(nimNoGetRandom): # TODO using let, pending bootstrap >= 1.4.0 var SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong const syscallHeader = """#include From f50bcf82c3e45921961ee4145bac88701fec62b0 Mon Sep 17 00:00:00 2001 From: Netsu <52031254+WeebNetsu@users.noreply.github.com> Date: Tue, 26 Oct 2021 21:42:22 +0200 Subject: [PATCH 3095/4254] Minor update to terminal docs (#19056) * Update terminal.nim - Added some extra docs to cursorUp/Down/Forward/Backward - I was able to use hideCursor and showCursor without adding stdout, removed the parameter - Added docs to terminalHeight()* and terminalWidth()* * Update lib/pure/terminal.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update lib/pure/terminal.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Added back f: file to cursor movement * Removed unnecessary comments Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/terminal.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 25b1a4cdd..c9aafc037 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -170,6 +170,7 @@ when defined(windows): return 0 proc terminalWidth*(): int = + ## Returns the terminal width in columns. var w: int = 0 w = terminalWidthIoctl([getStdHandle(STD_INPUT_HANDLE), getStdHandle(STD_OUTPUT_HANDLE), @@ -178,6 +179,7 @@ when defined(windows): return 80 proc terminalHeight*(): int = + ## Returns the terminal height in rows. var h: int = 0 h = terminalHeightIoctl([getStdHandle(STD_INPUT_HANDLE), getStdHandle(STD_OUTPUT_HANDLE), @@ -389,6 +391,9 @@ when defined(windows): proc cursorUp*(f: File, count = 1) = ## Moves the cursor up by `count` rows. + runnableExamples("-r:off"): + stdout.cursorUp(2) + write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -399,6 +404,9 @@ proc cursorUp*(f: File, count = 1) = proc cursorDown*(f: File, count = 1) = ## Moves the cursor down by `count` rows. + runnableExamples("-r:off"): + stdout.cursorDown(2) + write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -409,6 +417,9 @@ proc cursorDown*(f: File, count = 1) = proc cursorForward*(f: File, count = 1) = ## Moves the cursor forward by `count` columns. + runnableExamples("-r:off"): + stdout.cursorForward(2) + write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) @@ -419,6 +430,9 @@ proc cursorForward*(f: File, count = 1) = proc cursorBackward*(f: File, count = 1) = ## Moves the cursor backward by `count` columns. + runnableExamples("-r:off"): + stdout.cursorBackward(2) + write(stdout, "Hello World!") # anything written at that location will be erased/replaced with this when defined(windows): let h = conHandle(f) var p = getCursorPos(h) From ee65767d44cca79ce2677564151be69a60f6a94d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derek=20=E5=91=86?= <116649+derekdai@users.noreply.github.com> Date: Wed, 27 Oct 2021 17:45:05 +0800 Subject: [PATCH 3096/4254] fix a tiny formating issue in doc/destructors.rst (#19058) --- doc/destructors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index 195dc8f97..b4575b2e2 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -653,7 +653,7 @@ The ability to override a hook leads to a phase ordering problem: discard -The solution is to define `proc `=destroy`[T](f: var Foo[T])` before +The solution is to define ````proc `=destroy`[T](f: var Foo[T])```` before it is used. The compiler generates implicit hooks for all types in *strategic places* so that an explicitly provided hook that comes too "late" can be detected reliably. These *strategic places* From cd2b093d07303aa7bfcb4a007281f56de3755110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derek=20=E5=91=86?= <116649+derekdai@users.noreply.github.com> Date: Thu, 28 Oct 2021 15:35:57 +0800 Subject: [PATCH 3097/4254] fix a tiny code snippet formatting issue in `doc/constructors.rst`, again (#19065) --- doc/destructors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index b4575b2e2..6e4509666 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -653,7 +653,7 @@ The ability to override a hook leads to a phase ordering problem: discard -The solution is to define ````proc `=destroy`[T](f: var Foo[T])```` before +The solution is to define ``proc `=destroy`[T](f: var Foo[T])`` before it is used. The compiler generates implicit hooks for all types in *strategic places* so that an explicitly provided hook that comes too "late" can be detected reliably. These *strategic places* From c80e2c173686bd12904e5487752dc0ce20cb8bcb Mon Sep 17 00:00:00 2001 From: ynfle <23086821+ynfle@users.noreply.github.com> Date: Thu, 28 Oct 2021 11:02:18 +0300 Subject: [PATCH 3098/4254] Docs: change clipboard cursor type to `pointer` (#19064) --- tools/dochack/dochack.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 83e81f1c0..3a663808d 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -360,6 +360,7 @@ proc copyToClipboard*() {.exportc.} = const button = document.createElement("button") button.value = e.textContent.replace('...', '') button.classList.add("copyToClipBoardBtn") + button.style = "cursor: pointer" div.appendChild(preTag) div.appendChild(button) @@ -396,4 +397,4 @@ proc copyToClipboard*() {.exportc.} = """ .} -copyToClipboard() \ No newline at end of file +copyToClipboard() From 7ba2659f733b97db63b7552415ad048e34d4a11a Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 28 Oct 2021 20:20:52 +0300 Subject: [PATCH 3099/4254] docgen: implement doc link resolution in current module (#18642) --- compiler/docgen.nim | 154 ++++++++- compiler/lineinfos.nim | 2 + compiler/typesrenderer.nim | 66 +++- config/nimdoc.cfg | 11 + config/nimdoc.tex.cfg | 10 +- doc/docgen.rst | 170 ++++++++++ doc/nimdoc.css | 4 + lib/packages/docutils/dochelpers.nim | 267 +++++++++++++++ lib/packages/docutils/rst.nim | 319 ++++++++++++++---- lib/packages/docutils/rstast.nim | 3 + lib/packages/docutils/rstgen.nim | 27 +- lib/pure/strutils.nim | 5 + .../expected/index.html | 4 + nimdoc/testproject/expected/nimdoc.out.css | 4 + .../expected/subdir/subdir_b/utils.html | 297 +++++++++++++++- .../expected/subdir/subdir_b/utils.idx | 14 + nimdoc/testproject/expected/testproject.html | 210 +++++++++++- nimdoc/testproject/expected/theindex.html | 52 ++- nimdoc/testproject/subdir/subdir_b/utils.nim | 65 ++++ .../subdir/subdir_b/utils_helpers.nim | 1 + .../subdir/subdir_b/utils_overview.rst | 8 + tests/stdlib/tdochelpers.nim | 155 +++++++++ tests/stdlib/trst.nim | 109 +++++- tests/stdlib/trstgen.nim | 19 +- 24 files changed, 1833 insertions(+), 143 deletions(-) create mode 100644 lib/packages/docutils/dochelpers.nim create mode 100644 nimdoc/testproject/subdir/subdir_b/utils_helpers.nim create mode 100644 nimdoc/testproject/subdir/subdir_b/utils_overview.rst create mode 100644 tests/stdlib/tdochelpers.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 1acfc7489..2639840d1 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -13,7 +13,7 @@ import ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents, wordrecg, syntaxes, renderer, lexer, - packages/docutils/rst, packages/docutils/rstgen, + packages/docutils/[rst, rstgen, dochelpers], json, xmltree, trees, types, typesrenderer, astalgo, lineinfos, intsets, pathutils, tables, nimpaths, renderverbatim, osproc @@ -44,8 +44,14 @@ type ## runnableExamples). substitutions: seq[string] ## Variable names in `doc.item`... sortName: string ## The string used for sorting in output + info: rstast.TLineInfo ## place where symbol was defined (for messages) + anchor: string ## e.g. HTML anchor + name: string ## short name of the symbol, not unique + ## (includes backticks ` if present) + detailedName: string ## longer name like `proc search(x: int): int` ModSection = object ## Section like Procs, Types, etc. - secItems: seq[Item] ## Pre-processed items. + secItems: Table[string, seq[Item]] + ## Map basic name -> pre-processed items. finalMarkup: string ## The items, after RST pass 2 and rendering. ModSections = array[TSymKind, ModSection] TocItem = object ## HTML TOC item @@ -91,12 +97,22 @@ type thisDir*: AbsoluteDir exampleGroups: OrderedTable[string, ExampleGroup] wroteSupportFiles*: bool + nimToRstFid: Table[lineinfos.FileIndex, rstast.FileIndex] + ## map Nim FileIndex -> RST one, it's needed because we keep them separate PDoc* = ref TDocumentor ## Alias to type less. proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst) proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str) +proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex = + let invalid = rstast.FileIndex(-1) + result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid) + if result == invalid: + let fname = toFullPath(d.conf, info) + result = addFilename(d.sharedState, fname) + d.nimToRstFid[info.fileIndex] = result + proc cmpDecimalsIgnoreCase(a, b: string): int = ## For sorting with correct handling of cases like 'uint8' and 'uint16'. ## Also handles leading zeros well (however note that leading zeros are @@ -223,6 +239,7 @@ template declareClosures = of meFootnoteMismatch: k = errRstFootnoteMismatch of mwRedefinitionOfLabel: k = warnRstRedefinitionOfLabel of mwUnknownSubstitution: k = warnRstUnknownSubstitutionX + of mwAmbiguousLink: k = warnRstAmbiguousLink of mwBrokenLink: k = warnRstBrokenLink of mwUnsupportedLanguage: k = warnRstLanguageXNotSupported of mwUnsupportedField: k = warnRstFieldXNotSupported @@ -236,7 +253,7 @@ template declareClosures = result = getCurrentDir() / s if not fileExists(result): result = "" -proc parseRst(text, filename: string, +proc parseRst(text: string, line, column: int, conf: ConfigRef, sharedState: PRstSharedState): PRstNode = declareClosures() @@ -352,7 +369,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int = proc genComment(d: PDoc, n: PNode): PRstNode = if n.comment.len > 0: - result = parseRst(n.comment, toFullPath(d.conf, n.info), + d.sharedState.currFileIdx = addRstFileIndex(d, n.info) + result = parseRst(n.comment, toLinenumber(n.info), toColumn(n.info) + DocColOffset, d.conf, d.sharedState) @@ -885,6 +903,57 @@ proc genSeeSrc(d: PDoc, path: string, line: int): string = "path", path.string, "line", $line, "url", gitUrl, "commit", commit, "devel", develBranch]]) +proc symbolPriority(k: TSymKind): int = + result = case k + of skMacro: -3 + of skTemplate: -2 + of skIterator: -1 + else: 0 # including skProc which have higher priority + # documentation itself has even higher priority 1 + +proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol = + ## Converts symbol info (names/types/parameters) in `n` into format + ## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``. + result.name = baseName.nimIdentNormalize + result.symKind = k.toHumanStr + if k in routineKinds: + var + paramTypes: seq[string] + renderParamTypes(paramTypes, n[paramsPos], toNormalize=true) + let paramNames = renderParamNames(n[paramsPos], toNormalize=true) + # In some rare cases (system.typeof) parameter type is not set for default: + doAssert paramTypes.len <= paramNames.len + for i in 0 ..< paramNames.len: + if i < paramTypes.len: + result.parameters.add (paramNames[i], paramTypes[i]) + else: + result.parameters.add (paramNames[i], "") + result.parametersProvided = true + + result.outType = renderOutType(n[paramsPos], toNormalize=true) + + if k in {skProc, skFunc, skType, skIterator}: + # Obtain `result.generics` + # Use `n[miscPos]` since n[genericParamsPos] does not contain constraints + var genNode: PNode = nil + if k == skType: + genNode = n[1] # FIXME: what is index 1? + else: + if n[miscPos].kind != nkEmpty: + genNode = n[miscPos][1] # FIXME: what is index 1? + if genNode != nil: + var literal = "" + var r: TSrcGen + initTokRender(r, genNode, {renderNoBody, renderNoComments, + renderNoPragmas, renderNoProcDefs}) + var kind = tkEof + while true: + getNextTok(r, kind, literal) + if kind == tkEof: + break + if kind != tkSpaces: + result.generics.add(literal.nimIdentNormalize) + proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = if (docFlags != kForceExport) and not isVisible(d, nameNode): return let @@ -915,6 +984,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = inc(d.id) let plainNameEsc = esc(d.target, plainName.strip) + detailedName = k.toHumanStr & " " & ( + if k in routineKinds: plainName else: name) uniqueName = if k in routineKinds: plainNameEsc else: name sortName = if k in routineKinds: plainName.strip else: name cleanPlainSymbol = renderPlainSymbolName(nameNode) @@ -923,20 +994,32 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = symbolOrId = d.newUniquePlainSymbol(complexSymbol) symbolOrIdEnc = encodeUrl(symbolOrId, usePlus = false) deprecationMsg = genDeprecationMsg(d, pragmaNode) + rstLangSymbol = toLangSymbol(k, n, cleanPlainSymbol) + + # we generate anchors automatically for subsequent use in doc comments + let lineinfo = rstast.TLineInfo( + line: nameNode.info.line, col: nameNode.info.col, + fileIndex: addRstFileIndex(d, nameNode.info)) + addAnchorNim(d.sharedState, refn = symbolOrId, tooltip = detailedName, + rstLangSymbol, priority = symbolPriority(k), info = lineinfo) nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, renderDocComments, renderSyms}, symbolOrIdEnc) let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int) - d.section[k].secItems.add Item( + d.section[k].secItems.mgetOrPut(cleanPlainSymbol, newSeq[Item]()).add Item( descRst: comm, sortName: sortName, + info: lineinfo, + anchor: symbolOrId, + detailedName: detailedName, + name: name, substitutions: @[ - "name", name, "uniqueName", uniqueName, + "uniqueName", uniqueName, "header", result, "itemID", $d.id, "header_plain", plainNameEsc, "itemSym", cleanPlainSymbol, - "itemSymOrID", symbolOrId, "itemSymEnc", plainSymbolEnc, + "itemSymEnc", plainSymbolEnc, "itemSymOrIDEnc", symbolOrIdEnc, "seeSrc", seeSrc, "deprecationMsg", deprecationMsg]) @@ -1184,6 +1267,11 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = if comm.len != 0: d.modDescPre.add(comm) else: discard +proc overloadGroupName(s: string, k: TSymKind): string = + ## Turns a name like `f` into anchor `f-procs-all` + #s & " " & k.toHumanStr & "s all" + s & "-" & k.toHumanStr & "s-all" + proc finishGenerateDoc*(d: var PDoc) = ## Perform 2nd RST pass for resolution of links/footnotes/headings... # copy file map `filenames` to ``rstgen.nim`` for its warnings @@ -1197,6 +1285,21 @@ proc finishGenerateDoc*(d: var PDoc) = break preparePass2(d.sharedState, firstRst) + # add anchors to overload groups before RST resolution + for k in TSymKind: + if k in routineKinds: + for plainName, overloadChoices in d.section[k].secItems: + if overloadChoices.len > 1: + let refn = overloadGroupName(plainName, k) + let tooltip = "$1 ($2 overloads)" % [ + k.toHumanStr & " " & plainName, $overloadChoices.len] + addAnchorNim(d.sharedState, refn, tooltip, + LangSymbol(symKind: k.toHumanStr, name: plainName, + isGroup: true), + priority = symbolPriority(k), + # select index `0` just to have any meaningful warning: + info = overloadChoices[0].info) + # Finalize fragments of ``.nim`` or ``.rst`` file proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) = for f in fragments: @@ -1207,14 +1310,33 @@ proc finishGenerateDoc*(d: var PDoc) = of false: result &= f.str proc cmp(x, y: Item): int = cmpDecimalsIgnoreCase(x.sortName, y.sortName) for k in TSymKind: - for item in d.section[k].secItems.sorted(cmp): - var itemDesc: string - renderItemPre(d, item.descRst, itemDesc) - d.section[k].finalMarkup.add( - getConfigVar(d.conf, "doc.item") % ( - item.substitutions & @["desc", itemDesc])) - itemDesc = "" - d.section[k].secItems.setLen 0 + # add symbols to section for each `k`, while optionally wrapping + # overloadable items with the same basic name by ``doc.item2`` + let overloadableNames = toSeq(keys(d.section[k].secItems)) + for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase): + var overloadChoices = d.section[k].secItems[plainName] + overloadChoices.sort(cmp) + var nameContent = "" + for item in overloadChoices: + var itemDesc: string + renderItemPre(d, item.descRst, itemDesc) + nameContent.add( + getConfigVar(d.conf, "doc.item") % ( + item.substitutions & @[ + "desc", itemDesc, + "name", item.name, + "itemSymOrID", item.anchor])) + if k in routineKinds: + let plainNameEsc1 = esc(d.target, plainName.strip) + let plainNameEsc2 = esc(d.target, plainName.strip, escMode=emUrl) + d.section[k].finalMarkup.add( + getConfigVar(d.conf, "doc.item2") % ( + @["header_plain", plainNameEsc1, + "overloadGroupName", overloadGroupName(plainNameEsc2, k), + "content", nameContent])) + else: + d.section[k].finalMarkup.add(nameContent) + d.section[k].secItems.clear renderItemPre(d, d.modDescPre, d.modDescFinal) d.modDescPre.setLen 0 d.hasToc = d.hasToc or d.sharedState.hasToc @@ -1493,7 +1615,7 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename: AbsoluteFile, outExt: string) = var filen = addFileExt(filename, "txt") var d = newDocumentor(filen, cache, conf, outExt, isPureRst = true) - let rst = parseRst(readFile(filen.string), filen.string, + let rst = parseRst(readFile(filen.string), line=LineRstInit, column=ColRstInit, conf, d.sharedState) d.modDescPre = @[ItemFragment(isRst: true, rst: rst)] diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 8bd5a0890..e13387be6 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -50,6 +50,7 @@ type warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", warnRstRedefinitionOfLabel = "RedefinitionOfLabel", warnRstUnknownSubstitutionX = "UnknownSubstitutionX", + warnRstAmbiguousLink = "AmbiguousLink", warnRstBrokenLink = "BrokenLink", warnRstLanguageXNotSupported = "LanguageXNotSupported", warnRstFieldXNotSupported = "FieldXNotSupported", @@ -123,6 +124,7 @@ const warnUnknownMagic: "unknown magic '$1' might crash the compiler", warnRstRedefinitionOfLabel: "redefinition of label '$1'", warnRstUnknownSubstitutionX: "unknown substitution '$1'", + warnRstAmbiguousLink: "ambiguous doc link $1", warnRstBrokenLink: "broken link '$1'", warnRstLanguageXNotSupported: "language '$1' not supported", warnRstFieldXNotSupported: "field '$1' not supported", diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 0da05d70d..c81ff283e 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -11,6 +11,12 @@ import renderer, strutils, ast, types const defaultParamSeparator* = "," +template mayNormalize(s: string): string = + if toNormalize: + s.nimIdentNormalize + else: + s + proc renderPlainSymbolName*(n: PNode): string = ## Returns the first non '*' nkIdent node from the tree. ## @@ -30,24 +36,26 @@ proc renderPlainSymbolName*(n: PNode): string = result = "" #internalError(n.info, "renderPlainSymbolName() with " & $n.kind) -proc renderType(n: PNode): string = +proc renderType(n: PNode, toNormalize: bool): string = ## Returns a string with the node type or the empty string. + ## This proc should be kept in sync with `toLangSymbols` from + ## ``lib/packages/docutils/dochelpers.nim``. case n.kind: - of nkIdent: result = n.ident.s - of nkSym: result = typeToString(n.sym.typ) + of nkIdent: result = mayNormalize(n.ident.s) + of nkSym: result = mayNormalize(typeToString(n.sym.typ)) of nkVarTy: if n.len == 1: - result = renderType(n[0]) + result = renderType(n[0], toNormalize) else: result = "var" of nkRefTy: if n.len == 1: - result = "ref." & renderType(n[0]) + result = "ref." & renderType(n[0], toNormalize) else: result = "ref" of nkPtrTy: if n.len == 1: - result = "ptr." & renderType(n[0]) + result = "ptr." & renderType(n[0], toNormalize) else: result = "ptr" of nkProcTy: @@ -57,36 +65,53 @@ proc renderType(n: PNode): string = assert params.kind == nkFormalParams assert params.len > 0 result = "proc(" - for i in 1..= 3 let typePos = n.len - 2 - let typeStr = renderType(n[typePos]) + let typeStr = renderType(n[typePos], toNormalize) result = typeStr for i in 1..= 2 - result = renderType(n[0]) & '[' - for i in 1.. 1: result.add ", " - result.add(renderType(n[i])) + result.add(renderType(n[i], toNormalize)) else: result = "" -proc renderParamTypes(found: var seq[string], n: PNode) = +proc renderParamNames*(n: PNode, toNormalize=false): seq[string] = + ## Returns parameter names of routine `n`. + doAssert n.kind == nkFormalParams + case n.kind + of nkFormalParams: + for i in 1.. 0 - var typeStr = renderType(n[typePos]) + var typeStr = renderType(n[typePos], toNormalize) if typeStr.len < 1 and n[typePos+1].kind != nkEmpty: # Try with the last node, maybe its a default value. let typ = n[typePos+1].typ @@ -111,7 +136,8 @@ proc renderParamTypes(found: var seq[string], n: PNode) = found.add($n) #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind) -proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string = +proc renderParamTypes*(n: PNode, sep = defaultParamSeparator, + toNormalize=false): string = ## Returns the types contained in `n` joined by `sep`. ## ## This proc expects to be passed as `n` the parameters of any callable. The @@ -120,6 +146,10 @@ proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string = ## other characters may appear too, like ``[]`` or ``|``. result = "" var found: seq[string] = @[] - renderParamTypes(found, n) + renderParamTypes(found, n, toNormalize) if found.len > 0: result = found.join(sep) + +proc renderOutType*(n: PNode, toNormalize=false): string = + assert n.kind == nkFormalParams + result = renderType(n[0], toNormalize) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 162b2b4a3..c1074f344 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -56,6 +56,17 @@ $seeSrc
    """ +# A wrapper of a few overloaded `doc.item`s with the same basic name +# * $header_plain - see above +# * $overloadGroupName - the anchor for this whole group +# * $content - string containing `doc.item`s themselves +doc.item2 = """ + +
    +$content +
    +""" + # Chunk of HTML emitted for each entry in the HTML table of contents. # See doc.item for available substitution variables. diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 4aff9b379..d7ab652eb 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -19,7 +19,8 @@ doc.section.toc = "" doc.item = """ \vspace{1em} -\phantomsection\addcontentsline{toc}{subsection}{$uniqueName} +\phantomsection\addcontentsline{toc}{subsubsection}{$uniqueName} +\label{$itemSymOrID}\hypertarget{$itemSymOrID}{} \begin{rstdocitem} $header @@ -30,6 +31,13 @@ $desc \end{addmargin} """ +doc.item2 = """ +\phantomsection\addcontentsline{toc}{subsection}{$header_plain} +\label{$overloadGroupName}\hypertarget{$overloadGroupName}{} + +$content +""" + doc.item.toc = "" doc.toc = r"\tableofcontents \newpage" diff --git a/doc/docgen.rst b/doc/docgen.rst index 2074ee06f..51e7102eb 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -229,6 +229,176 @@ Output:: Note that the `jsondoc`:option: command outputs its JSON without pretty-printing it, while `jsondoc0`:option: outputs pretty-printed JSON. + +Referencing Nim symbols: simple documentation links +=================================================== + +You can reference Nim identifiers from Nim documentation comments, currently +only inside their ``.nim`` file (or inside a ``.rst`` file included from +a ``.nim``). The point is that such links will be resolved automatically +by `nim doc`:cmd: (or `nim jsondoc`:cmd: or `nim doc2tex`:cmd:). +This pertains to any exported symbol like `proc`, `const`, `iterator`, etc. +Syntax for referencing is basically a normal RST one: addition of +underscore `_` to a *link text*. +Link text is either one word or a group of words enclosed by backticks `\`` +(for a one word case backticks are usually omitted). +Link text will be displayed *as is* while *link target* will be set to +the anchor [*]_ of Nim symbol that corresponds to link text. + +.. [*] anchors' format is described in `HTML anchor generation`_ section below. + +If you have a constant: + +.. code:: Nim + + const pi* = 3.14 + +then it should be referenced in one of the 2 forms: + +A. non-qualified (no symbol kind specification):: + pi_ +B. qualified (with symbol kind specification):: + `const pi`_ + +For routine kinds there are more options. Consider this definition: + +.. code:: Nim + + proc foo*(a: int, b: float): string + +Generally following syntax is allowed for referencing `foo`: + +* short (without parameters): + + A. non-qualified:: + + foo_ + + B. qualified:: + + `proc foo`_ + +* longer variants (with parameters): + + A. non-qualified: + + 1) specifying parameters names:: + + `foo(a, b)`_ + + 2) specifying parameters types:: + + `foo(int, float)`_ + + 3) specifying both names and types:: + + `foo(a: int, b: float)`_ + + 4) output parameter can also be specified if you wish:: + + `foo(a: int, b: float): string`_ + + B. qualified: all 4 options above are valid. + Particularly you can use the full format:: + + `proc foo(a: int, b: float): string`_ + +.. Tip:: Avoid cluttering your text with extraneous information by using + one of shorter forms:: + + binarySearch_ + `binarySearch(a, key, cmp)`_ + + Brevity is better for reading! If you use a short form and have an + ambiguity problem (see below) then just add some additional info. + +Symbol kind like `proc` can also be specified in the postfix form:: + + `foo proc`_ + `walkDir(d: string) iterator`_ + +.. Warning:: An ambiguity in resolving documentation links may arise because of: + + 1. clash with other RST anchors + * manually setup anchors + * automatically set up, e.g. section names + 2. collision with other Nim symbols: + + * routines with different parameters can exist e.g. for + `proc` and `template`. In this case they are split between their + corresponding sections in output file. Qualified references are + useful in this case -- just disambiguate by referring to these + sections explicitly:: + + See `foo proc`_ and `foo template`_. + + * because in Nim `proc` and `iterator` belong to different namespaces, + so there can be a collision even if parameters are the same. + Use `\`proc foo\`_`:literal: or `\`iterator foo\`_`:literal: then. + + Any ambiguity is always reported with Nim compiler warnings and an anchor + with higher priority is selected. Manual anchors have highest + priority, then go automatic RST anchors; then Nim-generated anchors + (while procs have higher priority than other Nim symbol kinds). + +Generic parameters can also be used. All in all, this long form will be +recognized fine:: + + `proc binarySearch*[T; K](a: openArray[T], key: K, cmp: proc(T, K)): int`_ + +**Limitations**: + +1. The parameters of a nested routine type can be specified only with types + (without parameter names, see form A.2 above). + E.g. for this signature: + + .. code:: Nim + + proc binarySearch*[T, K](a: openArray[T]; key: K; + cmp: proc (x: T; y: K): int {.closure.}): int + ~~ ~~ ~~~~~ + + you cannot use names underlined by `~~` so it must be referenced with + ``cmp: proc(T, K)``. Hence these forms are valid:: + + `binarySearch(a: openArray[T], key: K, cmp: proc(T, K))`_ + `binarySearch(openArray[T], K, proc(T, K))`_ + `binarySearch(a, key, cmp)`_ +2. Default values in routine parameters are not recognized, one needs to + specify the type and/or name instead. E.g. for referencing `proc f(x = 7)` + use one of the mentioned forms:: + + `f(int)`_ or `f(x)`_ or `f(x: int)`_. +3. Generic parameters must be given the same way as in the + definition of referenced symbol. + + * their names should be the same + * parameters list should be given the same way, e.g. without substitutions + between commas (,) and semicolons (;). + +.. Note:: A bit special case is operators + (as their signature is also defined with `\``): + + .. code:: Nim + + func `$`(x: MyType): string + func `[]`*[T](x: openArray[T]): T + + A short form works without additional backticks:: + + `$`_ + `[]`_ + + However for fully-qualified reference copy-pasting backticks (`) into other + backticks will not work in our RST parser (because we use Markdown-like + inline markup rules). You need either to delete backticks or keep + them and escape with backslash \\:: + + no backticks: `func $`_ + escaped: `func \`$\``_ + no backticks: `func [][T](x: openArray[T]): T`_ + escaped: `func \`[]\`[T](x: openArray[T]): T`_ + Related Options =============== diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 3353f1cda..7c819ea30 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -263,6 +263,10 @@ a.reference-toplevel { font-weight: bold; } +a.nimdoc { + word-spacing: 0.3em; +} + a.toc-backref { text-decoration: none; color: var(--text); } diff --git a/lib/packages/docutils/dochelpers.nim b/lib/packages/docutils/dochelpers.nim new file mode 100644 index 000000000..c488c4d99 --- /dev/null +++ b/lib/packages/docutils/dochelpers.nim @@ -0,0 +1,267 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2021 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Integration helpers between ``docgen.nim`` and ``rst.nim``. +## +## Function `toLangSymbol(linkText)`_ produces a signature `docLink` of +## `type LangSymbol`_ in ``rst.nim``, while `match(generated, docLink)`_ +## matches it with `generated`, produced from `PNode` by ``docgen.rst``. + +import rstast + +type + LangSymbol* = object ## symbol signature in Nim + symKind*: string ## "proc", "const", etc + name*: string ## plain symbol name without any parameters + generics*: string ## generic parameters (without brackets) + isGroup*: bool ## is LangSymbol a group with overloads? + # the following fields are valid iff `isGroup` == false + # (always false when parsed by `toLangSymbol` because link like foo_ + # can point to just a single symbol foo, e.g. proc). + parametersProvided*: bool ## to disambiguate `proc f`_ and `proc f()`_ + parameters*: seq[tuple[name: string, `type`: string]] + ## name-type seq, e.g. for proc + outType*: string ## result type, e.g. for proc + +func nimIdentBackticksNormalize*(s: string): string = + ## Normalizes the string `s` as a Nim identifier. + ## + ## Unlike `nimIdentNormalize` removes spaces and backticks. + ## + ## .. Warning:: No checking (e.g. that identifiers cannot start from + ## digits or '_', or that number of backticks is even) is performed. + runnableExamples: + doAssert nimIdentBackticksNormalize("Foo_bar") == "Foobar" + doAssert nimIdentBackticksNormalize("FoO BAr") == "Foobar" + doAssert nimIdentBackticksNormalize("`Foo BAR`") == "Foobar" + doAssert nimIdentBackticksNormalize("` Foo BAR `") == "Foobar" + # not a valid identifier: + doAssert nimIdentBackticksNormalize("`_x_y`") == "_xy" + result = newString(s.len) + var firstChar = true + var j = 0 + for i in 0..len(s) - 1: + if s[i] in {'A'..'Z'}: + if not firstChar: # to lowercase + result[j] = chr(ord(s[i]) + (ord('a') - ord('A'))) + else: + result[j] = s[i] + firstChar = false + inc j + elif s[i] notin {'_', ' ', '`'}: + result[j] = s[i] + inc j + firstChar = false + elif s[i] == '_' and firstChar: + result[j] = '_' + inc j + firstChar = false + else: discard # just omit '`' or ' ' + if j != s.len: setLen(result, j) + +proc toLangSymbol*(linkText: PRstNode): LangSymbol = + ## Parses `linkText` into a more structured form using a state machine. + ## + ## This proc is designed to allow link syntax with operators even + ## without escaped backticks inside:: + ## + ## `proc *`_ + ## `proc []`_ + ## + ## This proc should be kept in sync with the `renderTypes` proc from + ## ``compiler/typesrenderer.nim``. + assert linkText.kind in {rnRef, rnInner} + + const NimDefs = ["proc", "func", "macro", "method", "iterator", + "template", "converter", "const", "type", "var"] + type + State = enum + inBeginning + afterSymKind + beforeSymbolName # auxiliary state to catch situations like `proc []`_ after space + atSymbolName + afterSymbolName + genericsPar + parameterName + parameterType + outType + var state = inBeginning + var curIdent = "" + template flushIdent() = + if curIdent != "": + case state + of inBeginning: doAssert false, "incorrect state inBeginning" + of afterSymKind: result.symKind = curIdent + of beforeSymbolName: doAssert false, "incorrect state beforeSymbolName" + of atSymbolName: result.name = curIdent.nimIdentBackticksNormalize + of afterSymbolName: doAssert false, "incorrect state afterSymbolName" + of genericsPar: result.generics = curIdent + of parameterName: result.parameters.add (curIdent, "") + of parameterType: + for a in countdown(result.parameters.len - 1, 0): + if result.parameters[a].`type` == "": + result.parameters[a].`type` = curIdent + of outType: result.outType = curIdent + curIdent = "" + var parens = 0 + let L = linkText.sons.len + template s(i: int): string = linkText.sons[i].text + var i = 0 + template nextState = + case s(i) + of " ": + if state == afterSymKind: + flushIdent + state = beforeSymbolName + of "`": + curIdent.add "`" + inc i + while i < L: # add contents between ` ` as a whole + curIdent.add s(i) + if s(i) == "`": + break + inc i + curIdent = curIdent.nimIdentBackticksNormalize + if state in {inBeginning, afterSymKind, beforeSymbolName}: + state = atSymbolName + flushIdent + state = afterSymbolName + of "[": + if state notin {inBeginning, afterSymKind, beforeSymbolName}: + inc parens + if state in {inBeginning, afterSymKind, beforeSymbolName}: + state = atSymbolName + curIdent.add s(i) + elif state in {atSymbolName, afterSymbolName} and parens == 1: + flushIdent + state = genericsPar + curIdent.add s(i) + else: curIdent.add s(i) + of "]": + if state notin {inBeginning, afterSymKind, beforeSymbolName, atSymbolName}: + dec parens + if state == genericsPar and parens == 0: + curIdent.add s(i) + flushIdent + else: curIdent.add s(i) + of "(": + inc parens + if state in {inBeginning, afterSymKind, beforeSymbolName}: + result.parametersProvided = true + state = atSymbolName + flushIdent + state = parameterName + elif state in {atSymbolName, afterSymbolName, genericsPar} and parens == 1: + result.parametersProvided = true + flushIdent + state = parameterName + else: curIdent.add s(i) + of ")": + dec parens + if state in {parameterName, parameterType} and parens == 0: + flushIdent + state = outType + else: curIdent.add s(i) + of "{": # remove pragmas + while i < L: + if s(i) == "}": + break + inc i + of ",", ";": + if state in {parameterName, parameterType} and parens == 1: + flushIdent + state = parameterName + else: curIdent.add s(i) + of "*": # skip export symbol + if state == atSymbolName: + flushIdent + state = afterSymbolName + elif state == afterSymbolName: + discard + else: curIdent.add "*" + of ":": + if state == outType: discard + elif state == parameterName: + flushIdent + state = parameterType + else: curIdent.add ":" + else: + let isPostfixSymKind = i > 0 and i == L - 1 and + result.symKind == "" and s(i) in NimDefs + if isPostfixSymKind: # for links like `foo proc`_ + result.symKind = s(i) + else: + case state + of inBeginning: + if s(i) in NimDefs: + state = afterSymKind + else: + state = atSymbolName + curIdent.add s(i) + of afterSymKind, beforeSymbolName: + state = atSymbolName + curIdent.add s(i) + of parameterType: + case s(i) + of "ref": curIdent.add "ref." + of "ptr": curIdent.add "ptr." + of "var": discard + else: curIdent.add s(i).nimIdentBackticksNormalize + of atSymbolName: + curIdent.add s(i) + else: + curIdent.add s(i).nimIdentBackticksNormalize + while i < L: + nextState + inc i + if state == afterSymKind: # treat `type`_ as link to symbol `type` + state = atSymbolName + flushIdent + result.isGroup = false + +proc match*(generated: LangSymbol, docLink: LangSymbol): bool = + ## Returns true if `generated` can be a target for `docLink`. + ## If `generated` is an overload group then only `symKind` and `name` + ## are compared for success. + result = true + if docLink.symKind != "": + if generated.symKind == "proc": + result = docLink.symKind in ["proc", "func"] + else: + result = generated.symKind == docLink.symKind + if not result: return + result = generated.name == docLink.name + if not result: return + if generated.isGroup: + # if `()` were added then it's not a reference to the whole group: + return not docLink.parametersProvided + if docLink.generics != "": + result = generated.generics == docLink.generics + if not result: return + if docLink.outType != "": + result = generated.outType == docLink.outType + if not result: return + if docLink.parametersProvided: + result = generated.parameters.len == docLink.parameters.len + if not result: return + var onlyType = false + for i in 0 ..< generated.parameters.len: + let g = generated.parameters[i] + let d = docLink.parameters[i] + if i == 0: + if g.`type` == d.name: + onlyType = true # only types, not names, are provided in `docLink` + if onlyType: + result = g.`type` == d.name: + else: + if d.`type` != "": + result = g.`type` == d.`type` + if not result: return + result = g.name == d.name + if not result: return diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 29234f28b..2e908f4e5 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -114,7 +114,7 @@ ## .. _`extra features`: ## ## Optional additional features, turned on by ``options: RstParseOption`` in -## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_: +## `proc rstParse`_: ## ## * emoji / smiley symbols ## * Markdown tables @@ -196,7 +196,7 @@ ## .. _Sphinx roles: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html import - os, strutils, rstast, std/enumutils, algorithm, lists, sequtils, + os, strutils, rstast, dochelpers, std/enumutils, algorithm, lists, sequtils, std/private/miscdollars, tables from highlite import SourceLanguage, getSourceLanguage @@ -231,6 +231,7 @@ type meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1", mwRedefinitionOfLabel = "redefinition of label '$1'", mwUnknownSubstitution = "unknown substitution '$1'", + mwAmbiguousLink = "ambiguous doc link $1", mwBrokenLink = "broken link '$1'", mwUnsupportedLanguage = "language '$1' not supported", mwUnsupportedField = "field '$1' not supported", @@ -473,12 +474,42 @@ type hasPeers: bool # has headings on the same level of hierarchy? LevelMap = seq[LevelInfo] # Saves for each possible title adornment # style its level in the current document. + SubstitutionKind = enum + rstSubstitution = "substitution", + hyperlinkAlias = "hyperlink alias", + implicitHyperlinkAlias = "implicitly-generated hyperlink alias" Substitution = object + kind*: SubstitutionKind key*: string value*: PRstNode - AnchorSubst = tuple - mainAnchor: string - aliases: seq[string] + info*: TLineInfo # place where the substitution was defined + AnchorRule = enum + arInternalRst, ## For automatically generated RST anchors (from + ## headings, footnotes, inline internal targets): + ## case-insensitive, 1-space-significant (by RST spec) + arNim ## For anchors generated by ``docgen.rst``: Nim-style case + ## sensitivity, etc. (see `proc normalizeNimName`_ for details) + arHyperlink, ## For links with manually set anchors in + ## form `text `_ + RstAnchorKind = enum + manualDirectiveAnchor = "manual directive anchor", + manualInlineAnchor = "manual inline anchor", + footnoteAnchor = "footnote anchor", + headlineAnchor = "implicitly-generated headline anchor" + AnchorSubst = object + mainAnchor: ref string # A reference name that will be inserted directly + # into HTML/Latex. It's declared as `ref` because + # it can be shared between aliases. + info: TLineInfo # where the anchor was defined + priority: int + case kind: range[arInternalRst .. arNim] + of arInternalRst: + anchorType: RstAnchorKind + of arNim: + tooltip: string # displayed tooltip for Nim-generated anchors + langSym: LangSymbol + AnchorSubstTable = Table[string, seq[AnchorSubst]] + # use `seq` to account for duplicate anchors FootnoteType = enum fnManualNumber, # manually numbered footnote like [3] fnAutoNumber, # auto-numbered footnote [#] @@ -505,7 +536,8 @@ type currRoleKind: RstNodeKind # ... and its node kind subs: seq[Substitution] # substitutions refs*: seq[Substitution] # references - anchors*: seq[AnchorSubst] # internal target substitutions + anchors*: AnchorSubstTable + # internal target substitutions lineFootnoteNum: seq[TLineInfo] # footnote line, auto numbers .. [#] lineFootnoteNumRef: seq[TLineInfo] # footnote line, their reference [#]_ currFootnoteNumRef: int # ... their counter for `resolveSubs` @@ -518,7 +550,7 @@ type findFile: FindFileHandler # How to find files. filenames*: RstFileTable # map file name <-> FileIndex (for storing # file names for warnings after 1st stage) - currFileIdx: FileIndex # current index in `filesnames` + currFileIdx*: FileIndex # current index in `filenames` hasToc*: bool PRstSharedState* = ref RstSharedState @@ -532,6 +564,7 @@ type ## in case of error/warning reporting to ## (relative) line/column of the token. curAnchor*: string # variable to track latest anchor in s.anchors + curAnchorName*: string # corresponding name in human-readable format EParseError* = object of ValueError @@ -590,13 +623,16 @@ proc whichRoleAux(sym: string): RstNodeKind = proc len(filenames: RstFileTable): int = filenames.idxToFilename.len -proc setCurrFilename(s: PRstSharedState, file1: string) = +proc addFilename*(s: PRstSharedState, file1: string): FileIndex = + ## Returns index of filename, adding it if it has not been used before let nextIdx = s.filenames.len.FileIndex - let v = getOrDefault(s.filenames.filenameToIdx, file1, default = nextIdx) - if v == nextIdx: - s.filenames.filenameToIdx[file1] = v + result = getOrDefault(s.filenames.filenameToIdx, file1, default = nextIdx) + if result == nextIdx: + s.filenames.filenameToIdx[file1] = result s.filenames.idxToFilename.add file1 - s.currFileIdx = v + +proc setCurrFilename*(s: PRstSharedState, file1: string) = + s.currFileIdx = addFilename(s, file1) proc getFilename(filenames: RstFileTable, fid: FileIndex): string = doAssert(0 <= fid.int and fid.int < filenames.len, @@ -730,6 +766,8 @@ proc initParser(p: var RstParser, sharedState: PRstSharedState) = p.s = sharedState proc addNodesAux(n: PRstNode, result: var string) = + if n == nil: + return if n.kind == rnLeaf: result.add(n.text) else: @@ -738,6 +776,11 @@ proc addNodesAux(n: PRstNode, result: var string) = proc addNodes(n: PRstNode): string = n.addNodesAux(result) +proc linkName(n: PRstNode): string = + ## Returns a normalized reference name, see: + ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names + n.addNodes.toLowerAscii + proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) = template special(s) = if b: @@ -804,15 +847,26 @@ proc findSub(s: PRstSharedState, n: PRstNode): int = return i result = -1 +proc lineInfo(p: RstParser, iTok: int): TLineInfo = + result.col = int16(p.col + p.tok[iTok].col) + result.line = uint16(p.line + p.tok[iTok].line) + result.fileIndex = p.s.currFileIdx + +proc lineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx) +# TODO: we need this simplification because we don't preserve exact starting +# token of currently parsed element: +proc prevLineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx-1) + proc setSub(p: var RstParser, key: string, value: PRstNode) = var length = p.s.subs.len for i in 0 ..< length: if key == p.s.subs[i].key: p.s.subs[i].value = value return - p.s.subs.add(Substitution(key: key, value: value)) + p.s.subs.add(Substitution(key: key, value: value, info: prevLineInfo(p))) -proc setRef(p: var RstParser, key: string, value: PRstNode) = +proc setRef(p: var RstParser, key: string, value: PRstNode, + refType: SubstitutionKind) = var length = p.s.refs.len for i in 0 ..< length: if key == p.s.refs[i].key: @@ -820,37 +874,111 @@ proc setRef(p: var RstParser, key: string, value: PRstNode) = rstMessage(p, mwRedefinitionOfLabel, key) p.s.refs[i].value = value return - p.s.refs.add(Substitution(key: key, value: value)) + p.s.refs.add(Substitution(kind: refType, key: key, value: value, + info: prevLineInfo(p))) -proc findRef(s: PRstSharedState, key: string): PRstNode = +proc findRef(s: PRstSharedState, key: string): seq[Substitution] = for i in countup(0, high(s.refs)): if key == s.refs[i].key: - return s.refs[i].value + result.add s.refs[i] -proc addAnchor(p: var RstParser, refn: string, reset: bool) = - ## add anchor `refn` to anchor aliases and update last anchor ``curAnchor`` - if p.curAnchor == "": - p.s.anchors.add (refn, @[refn]) +# Ambiguity in links: we don't follow procedure of removing implicit targets +# defined in https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#implicit-hyperlink-targets +# Instead we just give explicit links a higher priority than to implicit ones +# and report ambiguities as warnings. Hopefully it is easy to remove +# ambiguities manually. Nim auto-generated links from ``docgen.nim`` +# have lowest priority: 1 (for procs) and below for other symbol types. + +proc refPriority(k: SubstitutionKind): int = + case k + of rstSubstitution: result = 8 + of hyperlinkAlias: result = 7 + of implicitHyperlinkAlias: result = 2 + +proc internalRefPriority(k: RstAnchorKind): int = + case k + of manualDirectiveAnchor: result = 6 + of manualInlineAnchor: result = 5 + of footnoteAnchor: result = 4 + of headlineAnchor: result = 3 + +proc addAnchorRst(p: var RstParser, name: string, refn: string, reset: bool, + anchorType: RstAnchorKind) = + ## Adds anchor `refn` with an alias `name` and + ## updates the corresponding `curAnchor` / `curAnchorName`. + let prio = internalRefPriority(anchorType) + if p.curAnchorName == "": + var anchRef = new string + anchRef[] = refn + p.s.anchors.mgetOrPut(name, newSeq[AnchorSubst]()).add( + AnchorSubst(kind: arInternalRst, mainAnchor: anchRef, priority: prio, + info: prevLineInfo(p), anchorType: anchorType)) else: - p.s.anchors[^1].mainAnchor = refn - p.s.anchors[^1].aliases.add refn + # override previous mainAnchor by `ref` in all aliases + var anchRef = p.s.anchors[p.curAnchorName][0].mainAnchor + anchRef[] = refn + p.s.anchors.mgetOrPut(name, newSeq[AnchorSubst]()).add( + AnchorSubst(kind: arInternalRst, mainAnchor: anchRef, priority: prio, + info: prevLineInfo(p), anchorType: anchorType)) if reset: p.curAnchor = "" + p.curAnchorName = "" else: p.curAnchor = refn + p.curAnchorName = name -proc findMainAnchor(s: PRstSharedState, refn: string): string = - for subst in s.anchors: - if subst.mainAnchor == refn: # no need to rename - result = subst.mainAnchor - break - var toLeave = false - for anchor in subst.aliases: - if anchor == refn: # this anchor will be named as mainAnchor - result = subst.mainAnchor - toLeave = true - if toLeave: - break +proc addAnchorNim*(s: var PRstSharedState, refn: string, tooltip: string, + langSym: LangSymbol, priority: int, + info: TLineInfo) = + ## Adds an anchor `refn` (`mainAnchor`), which follows + ## the rule `arNim` (i.e. a symbol in ``*.nim`` file) + var anchRef = new string + anchRef[] = refn + s.anchors.mgetOrPut(langSym.name, newSeq[AnchorSubst]()).add( + AnchorSubst(kind: arNim, mainAnchor: anchRef, langSym: langSym, + tooltip: tooltip, priority: priority, + info: info)) + +proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode, + info: TLineInfo): + seq[AnchorSubst] = + let langSym = toLangSymbol(signature) + let substitutions = s.anchors.getOrDefault(langSym.name, + newSeq[AnchorSubst]()) + if substitutions.len == 0: + return + # map symKind (like "proc") -> found symbols/groups: + var found: Table[string, seq[AnchorSubst]] + for s in substitutions: + if s.kind == arNim: + if match(s.langSym, langSym): + found.mgetOrPut(s.langSym.symKind, newSeq[AnchorSubst]()).add s + for symKind, sList in found: + if sList.len == 1: + result.add sList[0] + else: # > 1, there are overloads, potential ambiguity in this `symKind` + if langSym.parametersProvided: + # there are non-group signatures, select only them + for s in sList: + if not s.langSym.isGroup: + result.add s + else: # when there are many overloads a link like foo_ points to all + # of them, so selecting the group + var foundGroup = true + for s in sList: + if s.langSym.isGroup: + result.add s + foundGroup = true + break + doAssert foundGroup, "docgen has not generated the group" + +proc findMainAnchorRst(s: PRstSharedState, linkText: string, info: TLineInfo): + seq[AnchorSubst] = + let name = linkText.toLowerAscii + let substitutions = s.anchors.getOrDefault(name, newSeq[AnchorSubst]()) + for s in substitutions: + if s.kind == arInternalRst: + result.add s proc addFootnoteNumManual(p: var RstParser, num: int) = ## add manually-numbered footnote @@ -860,13 +988,6 @@ proc addFootnoteNumManual(p: var RstParser, num: int) = return p.s.footnotes.add((fnManualNumber, num, -1, -1, $num)) -proc lineInfo(p: RstParser, iTok: int): TLineInfo = - result.col = int16(p.col + p.tok[iTok].col) - result.line = uint16(p.line + p.tok[iTok].line) - result.fileIndex = p.s.currFileIdx - -proc lineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx) - proc addFootnoteNumAuto(p: var RstParser, label: string) = ## add auto-numbered footnote. ## Empty label [#] means it'll be resolved by the occurrence. @@ -989,6 +1110,7 @@ proc newRstNodeA(p: var RstParser, kind: RstNodeKind): PRstNode = if p.curAnchor != "": result.anchor = p.curAnchor p.curAnchor = "" + p.curAnchorName = "" template newLeaf(s: string): PRstNode = newRstLeaf(s) @@ -1255,7 +1377,7 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = else: newKind = rnHyperlink newSons = @[a, b] - setRef(p, rstnodeToRefname(a), b) + setRef(p, rstnodeToRefname(a), b, implicitHyperlinkAlias) result = newRstNode(newKind, newSons) else: # some link that will be resolved in `resolveSubs` newKind = rnRef @@ -1562,7 +1684,8 @@ proc parseInline(p: var RstParser, father: PRstNode) = inc p.idx parseUntil(p, n, "`", false) let refn = rstnodeToRefname(n) - p.s.anchors.add (refn, @[refn]) + addAnchorRst(p, name = linkName(n), refn = refn, reset = true, + anchorType=manualInlineAnchor) father.add(n) elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": inc p.idx @@ -2084,7 +2207,8 @@ proc parseHeadline(p: var RstParser): PRstNode = result.level = getLevel(p, c, hasOverline=false) checkHeadingHierarchy(p, result.level) p.s.hCurLevel = result.level - addAnchor(p, rstnodeToRefname(result), reset=true) + addAnchorRst(p, linkName(result), rstnodeToRefname(result), reset=true, + anchorType=headlineAnchor) proc parseOverline(p: var RstParser): PRstNode = var c = currentTok(p).symbol[0] @@ -2106,7 +2230,8 @@ proc parseOverline(p: var RstParser): PRstNode = if currentTok(p).kind == tkAdornment: inc p.idx if currentTok(p).kind == tkIndent: inc p.idx - addAnchor(p, rstnodeToRefname(result), reset=true) + addAnchorRst(p, linkName(result), rstnodeToRefname(result), reset=true, + anchorType=headlineAnchor) type IntSeq = seq[int] @@ -2837,7 +2962,7 @@ proc parseFootnote(p: var RstParser): PRstNode = anchor.add $p.s.lineFootnoteSym.len of fnCitation: anchor.add rstnodeToRefname(label) - addAnchor(p, anchor, reset=true) + addAnchorRst(p, anchor, anchor, reset=true, anchorType=footnoteAnchor) result.anchor = anchor if currentTok(p).kind == tkWhite: inc p.idx discard parseBlockContent(p, result, parseSectionWrapper) @@ -2858,13 +2983,23 @@ proc parseDotDot(p: var RstParser): PRstNode = elif match(p, p.idx, " _"): # hyperlink target: inc p.idx, 2 - var a = getReferenceName(p, ":") + var ending = ":" + if currentTok(p).symbol == "`": + inc p.idx + ending = "`" + var a = getReferenceName(p, ending) + if ending == "`": + if currentTok(p).symbol == ":": + inc p.idx + else: + rstMessage(p, meExpected, ":") if currentTok(p).kind == tkWhite: inc p.idx var b = untilEol(p) if len(b) == 0: # set internal anchor - addAnchor(p, rstnodeToRefname(a), reset=false) + addAnchorRst(p, linkName(a), rstnodeToRefname(a), reset=false, + anchorType=manualDirectiveAnchor) else: # external hyperlink - setRef(p, rstnodeToRefname(a), b) + setRef(p, rstnodeToRefname(a), b, refType=hyperlinkAlias) elif match(p, p.idx, " |"): # substitution definitions: inc p.idx, 2 @@ -2892,7 +3027,7 @@ proc rstParsePass1*(fragment: string, sharedState: PRstSharedState): PRstNode = ## Parses an RST `fragment`. ## The result should be further processed by - ## `preparePass2` and `resolveSubs` (which is pass 2). + ## preparePass2_ and resolveSubs_ (which is pass 2). var p: RstParser initParser(p, sharedState) p.line = line @@ -2905,6 +3040,65 @@ proc preparePass2*(s: PRstSharedState, mainNode: PRstNode) = countTitles(s, mainNode) orderFootnotes(s) +proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode = + # Associate this link alias with its target and change node kind to + # rnHyperlink or rnInternalRef appropriately. + type LinkDef = object + ar: AnchorRule + priority: int + tooltip: string + target: PRstNode + info: TLineInfo + proc cmp(x, y: LinkDef): int = + result = cmp(x.priority, y.priority) + if result == 0: + result = cmp(x.target, y.target) + var foundLinks: seq[LinkDef] + let text = newRstNode(rnInner, n.sons) + let refn = rstnodeToRefname(n) + var hyperlinks = findRef(s, refn) + for y in hyperlinks: + foundLinks.add LinkDef(ar: arHyperlink, priority: refPriority(y.kind), + target: y.value, info: y.info, + tooltip: "(" & $y.kind & ")") + let substRst = findMainAnchorRst(s, text.addNodes, n.info) + for subst in substRst: + foundLinks.add LinkDef(ar: arInternalRst, priority: subst.priority, + target: newLeaf(subst.mainAnchor[]), + info: subst.info, + tooltip: "(" & $subst.anchorType & ")") + if roNimFile in s.options: + let substNim = findMainAnchorNim(s, signature=text, n.info) + for subst in substNim: + foundLinks.add LinkDef(ar: arNim, priority: subst.priority, + target: newLeaf(subst.mainAnchor[]), + info: subst.info, tooltip: subst.tooltip) + foundLinks.sort(cmp = cmp, order = Descending) + let linkText = addNodes(n) + if foundLinks.len >= 1: + let kind = if foundLinks[0].ar == arHyperlink: rnHyperlink + elif foundLinks[0].ar == arNim: rnNimdocRef + else: rnInternalRef + result = newRstNode(kind) + result.sons = @[text, foundLinks[0].target] + if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip + if foundLinks.len > 1: # report ambiguous link + var targets = newSeq[string]() + for l in foundLinks: + var t = " " + if s.filenames.len > 1: + t.add getFilename(s.filenames, l.info.fileIndex) + let n = l.info.line + let c = l.info.col + ColRstOffset + t.add "($1, $2): $3" % [$n, $c, l.tooltip] + targets.add t + rstMessage(s.filenames, s.msgHandler, n.info, mwAmbiguousLink, + "`$1`\n clash:\n$2" % [ + linkText, targets.join("\n")]) + else: # nothing found + result = n + rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, linkText) + proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = ## Makes pass 2 of RST parsing. ## Resolves substitutions and anchor aliases, groups footnotes. @@ -2933,21 +3127,7 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = elif s.hTitleCnt == 0: n.level += 1 of rnRef: - let refn = rstnodeToRefname(n) - var y = findRef(s, refn) - if y != nil: - result = newRstNode(rnHyperlink) - let text = newRstNode(rnInner, n.sons) - result.sons = @[text, y] - else: - let anchor = findMainAnchor(s, refn) - if anchor != "": - result = newRstNode(rnInternalRef) - let text = newRstNode(rnInner, n.sons) - result.sons = @[text, # visible text of reference - newLeaf(anchor)] # link itself - else: - rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, refn) + result = resolveLink(s, n) of rnFootnote: var (fnType, num) = getFootnoteType(n.sons[0]) case fnType @@ -2993,9 +3173,10 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = of fnCitation: result.add n.sons[0] refn.add rstnodeToRefname(n) - let anch = findMainAnchor(s, refn) - if anch != "": - result.add newLeaf(anch) # add link + # TODO: correctly report ambiguities + let anchorInfo = findMainAnchorRst(s, refn, n.info) + if anchorInfo.len != 0: + result.add newLeaf(anchorInfo[0].mainAnchor[]) # add link else: rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, refn) result.add newLeaf(refn) # add link diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index e1ed7c099..bc7b9a650 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -43,6 +43,7 @@ type rnFootnoteGroup, # footnote group - exists for a purely stylistic # reason: to display a few footnotes as 1 block rnStandaloneHyperlink, rnHyperlink, rnRef, rnInternalRef, rnFootnoteRef, + rnNimdocRef, # reference to automatically generated Nim symbol rnDirective, # a general directive rnDirArg, # a directive argument (for some directives). # here are directives that are not rnDirective: @@ -104,6 +105,8 @@ type rnInterpretedText, rnField, rnInlineCode, rnCodeBlock, rnFootnoteRef: info*: TLineInfo ## To have line/column info for warnings at ## nodes that are post-processed after parsing + of rnNimdocRef: + tooltip*: string else: discard anchor*: string ## anchor, internal link target diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 8eac37307..a556aa2e3 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -60,8 +60,8 @@ type MetaEnum* = enum metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion - EscapeMode = enum # in Latex text inside options [] and URLs is - # escaped slightly differently than in normal text + EscapeMode* = enum # in Latex text inside options [] and URLs is + # escaped slightly differently than in normal text emText, emOption, emUrl # emText is currently used for code also RstGenerator* = object of RootObj @@ -201,7 +201,9 @@ proc addTexChar(dest: var string, c: char, escMode: EscapeMode) = ## All escapes that need to work in text and code blocks (`emText` mode) ## should start from \ (to be compatible with fancyvrb/fvextra). case c - of '_', '$', '&', '#', '%': add(dest, "\\" & c) + of '_', '&', '#', '%': add(dest, "\\" & c) + # commands \label and \pageref don't accept \$ by some reason but OK with $: + of '$': (if escMode == emUrl: add(dest, c) else: add(dest, "\\" & c)) # \~ and \^ have a special meaning unless they are followed by {} of '~', '^': add(dest, "\\" & c & "{}") # Latex loves to substitute ` to opening quote, even in texttt mode! @@ -1180,7 +1182,8 @@ proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) = "$1\n\\end{rstadmonition}\n", result) -proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external: bool) = +proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, + external: bool, nimdoc = false, tooltip="") = var linkStr = "" block: let mode = d.escMode @@ -1189,14 +1192,19 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external d.escMode = mode var textStr = "" renderRstToOut(d, text, textStr) + let nimDocStr = if nimdoc: " nimdoc" else: "" + var tooltipStr = "" + if tooltip != "": + tooltipStr = """ title="$1"""" % [ esc(d.target, tooltip) ] if external: dispA(d.target, result, - "$1", - "\\href{$2}{$1}", [textStr, linkStr]) + "$1", + "\\href{$2}{$1}", [textStr, linkStr, nimDocStr, tooltipStr]) else: dispA(d.target, result, - "$1", - "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [textStr, linkStr]) + "$1", + "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", + [textStr, linkStr, nimDocStr, tooltipStr]) proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = if n == nil: return @@ -1329,6 +1337,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=true) of rnInternalRef: renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false) + of rnNimdocRef: + renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false, + nimdoc=true, tooltip=n.tooltip) of rnHyperlink: renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=true) of rnFootnoteRef: diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 873949ca6..2234a8625 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -273,6 +273,11 @@ func nimIdentNormalize*(s: string): string = ## ## That means to convert to lower case and remove any '_' on all characters ## except first one. + ## + ## .. Warning:: Backticks (`) are not handled: they remain *as is* and + ## spaces are preserved. See `nimIdentBackticksNormalize + ## `_ for + ## an alternative approach. runnableExamples: doAssert nimIdentNormalize("Foo_bar") == "Foobar" result = newString(s.len) diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 3499b5326..69dd2eb2e 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -121,6 +121,8 @@ window.addEventListener('DOMContentLoaded', main);

    Procs

    + +
    proc foo() {....raises: [], tags: [].}
    @@ -130,6 +132,8 @@ I do foo
    +
    +
    diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 3353f1cda..7c819ea30 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -263,6 +263,10 @@ a.reference-toplevel { font-weight: bold; } +a.nimdoc { + word-spacing: 0.3em; +} + a.toc-backref { text-decoration: none; color: var(--text); } diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 47901ce0d..c64039941 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -106,7 +106,10 @@ window.addEventListener('DOMContentLoaded', main);
  • Types
      -
    • G
    • +
    • SomeType
    • @@ -115,9 +118,54 @@ window.addEventListener('DOMContentLoaded', main);
    • Procs
        -
          fn2 + + + + + + + +
            fn3 @@ -159,6 +207,11 @@ window.addEventListener('DOMContentLoaded', main);
          • fn10(a: int): int
          • +
          +
            someType
          • +
          • + Iterators + +
          • Templates
              @@ -197,7 +261,13 @@ window.addEventListener('DOMContentLoaded', main);
              -

              +

              This is a description of the utils module.

              +

              Links work:

              + +

              This is now a header

              Next header

              And so on

              @@ -209,10 +279,31 @@ window.addEventListener('DOMContentLoaded', main);
              1. Other case value
              2. Second case.
              -

              +

              Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

              +

              Ref generics like this: binarySearch or binarySearch(openArray[T], K, proc (T, K)) or proc binarySearch(openArray[T], K, proc (T, K)) or in different style: proc binarysearch(openarray[T], K, proc(T, K)). Can be combined with export symbols and type parameters: binarysearch*[T, K](openArray[T], K, proc (T, K)). With spaces binary search.

              +

              Note that proc can be used in postfix form: binarySearch proc.

              +

              Ref. type like G and type G and G[T] and type G*[T].

              +Ref. [] is the same as proc `[]`(G[T]) because there are no overloads. The full form: proc `[]`*[T](x: G[T]): TRef. []= aka `[]=`(G[T], int, T).Ref. $ aka proc $ or proc `$`.Ref. $(a: ref SomeType).Ref. foo_bar aka iterator foo_bar_.Ref. fn[T; U,V: SomeFloat]().Ref. 'big or func `'big` or `'big`(string).

              Types

              +
              +
              G[T] = object
              +  val: T
              +
              +
              + + + +
              +
              SomeType = enum
                 enumValueA, enumValueB, enumValueC
              @@ -227,6 +318,109 @@ window.addEventListener('DOMContentLoaded', main);

              Procs

              + +
              +
              +
              proc `$`[T](a: G[T]): string
              +
              + + + +
              +
              +
              +
              proc `$`[T](a: ref SomeType): string
              +
              + + + +
              +
              + +
              + +
              +
              +
              func `'big`(a: string): SomeType {....raises: [], tags: [].}
              +
              + + + +
              +
              + +
              + +
              +
              +
              proc `[]`[T](x: G[T]): T
              +
              + + + +
              +
              + +
              + +
              +
              +
              proc `[]=`[T](a: var G[T]; index: int; value: T)
              +
              + + + +
              +
              + +
              + +
              +
              +
              proc binarySearch[T, K](a: openArray[T]; key: K;
              +                        cmp: proc (x: T; y: K): int {.closure.}): int
              +
              + + + +
              +
              + +
              + +
              +
              +
              proc f(x: G[int]) {....raises: [], tags: [].}
              +
              + +There is also variant f(G[string]) + +
              +
              +
              +
              proc f(x: G[string]) {....raises: [], tags: [].}
              +
              + +See also f(G[int]). + +
              +
              + +
              + +
              +
              +
              proc fn[T; U, V: SomeFloat]()
              +
              + + + +
              +
              + +
              + +
              proc fn2() {....raises: [], tags: [].}
              @@ -235,6 +429,26 @@ comment
              +
              +
              proc fn2(x: int) {....raises: [], tags: [].}
              +
              + +fn2 comment + +
              +
              +
              +
              proc fn2(x: int; y: float) {....raises: [], tags: [].}
              +
              + + + +
              +
              + +
              + +
              proc fn3(): auto {....raises: [], tags: [].}
              @@ -243,6 +457,10 @@ comment
              + +
              + +
              proc fn4(): auto {....raises: [], tags: [].}
              @@ -251,6 +469,10 @@ comment
              + +
              + +
              proc fn5() {....raises: [], tags: [].}
              @@ -259,6 +481,10 @@ comment
              + +
              + +
              proc fn6() {....raises: [], tags: [].}
              @@ -267,6 +493,10 @@ comment
              + +
              + +
              proc fn7() {....raises: [], tags: [].}
              @@ -275,6 +505,10 @@ comment
              + +
              + +
              proc fn8(): auto {....raises: [], tags: [].}
              @@ -283,6 +517,10 @@ comment
              + +
              + +
              func fn9(a: int): int {....raises: [], tags: [].}
              @@ -291,6 +529,10 @@ comment
              + +
              + +
              func fn10(a: int): int {....raises: [], tags: [].}
              @@ -299,6 +541,22 @@ comment
              + +
              + +
              +
              +
              proc funWithGenerics[T, U: SomeFloat](a: T; b: U)
              +
              + + + +
              +
              + +
              + +
              proc someType(): SomeType {....raises: [], tags: [].}
              @@ -308,10 +566,31 @@ constructor.
              +
              + +
              +
              +

              Iterators

              +
              + +
              +
              +
              iterator fooBar(a: seq[SomeType]): int {....raises: [], tags: [].}
              +
              + + + +
              +
              + +
              +

              Templates

              + +
              template aEnum(): untyped
              @@ -320,6 +599,10 @@ constructor.
              + +
              + +
              template bEnum(): untyped
              @@ -328,6 +611,10 @@ constructor.
              + +
              + +
              template fromUtilsGen(): untyped
              @@ -339,6 +626,8 @@ should be shown in utils.html only
              +
              +
              diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx index a87393f09..441bd8675 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx @@ -1,9 +1,14 @@ +funWithGenerics subdir/subdir_b/utils.html#funWithGenerics,T,U utils: funWithGenerics[T, U: SomeFloat](a: T; b: U) enumValueA subdir/subdir_b/utils.html#enumValueA SomeType.enumValueA enumValueB subdir/subdir_b/utils.html#enumValueB SomeType.enumValueB enumValueC subdir/subdir_b/utils.html#enumValueC SomeType.enumValueC SomeType subdir/subdir_b/utils.html#SomeType utils: SomeType +G subdir/subdir_b/utils.html#G utils: G someType subdir/subdir_b/utils.html#someType_2 utils: someType(): SomeType fn2 subdir/subdir_b/utils.html#fn2 utils: fn2() +fn2 subdir/subdir_b/utils.html#fn2,int utils: fn2(x: int) +fn2 subdir/subdir_b/utils.html#fn2,int,float utils: fn2(x: int; y: float) +binarySearch subdir/subdir_b/utils.html#binarySearch,openArray[T],K,proc(T,K) utils: binarySearch[T, K](a: openArray[T]; key: K;\n cmp: proc (x: T; y: K): int {.closure.}): int fn3 subdir/subdir_b/utils.html#fn3 utils: fn3(): auto fn4 subdir/subdir_b/utils.html#fn4 utils: fn4(): auto fn5 subdir/subdir_b/utils.html#fn5 utils: fn5() @@ -15,6 +20,15 @@ fn10 subdir/subdir_b/utils.html#fn10,int utils: fn10(a: int): int aEnum subdir/subdir_b/utils.html#aEnum.t utils: aEnum(): untyped bEnum subdir/subdir_b/utils.html#bEnum.t utils: bEnum(): untyped fromUtilsGen subdir/subdir_b/utils.html#fromUtilsGen.t utils: fromUtilsGen(): untyped +f subdir/subdir_b/utils.html#f,G[int] utils: f(x: G[int]) +f subdir/subdir_b/utils.html#f,G[string] utils: f(x: G[string]) +`[]` subdir/subdir_b/utils.html#[],G[T] utils: `[]`[T](x: G[T]): T +`[]=` subdir/subdir_b/utils.html#[]=,G[T],int,T utils: `[]=`[T](a: var G[T]; index: int; value: T) +`$` subdir/subdir_b/utils.html#$,G[T] utils: `$`[T](a: G[T]): string +`$` subdir/subdir_b/utils.html#$,ref.SomeType utils: `$`[T](a: ref SomeType): string +fooBar subdir/subdir_b/utils.html#fooBar.i,seq[SomeType] utils: fooBar(a: seq[SomeType]): int +fn subdir/subdir_b/utils.html#fn utils: fn[T; U, V: SomeFloat]() +`'big` subdir/subdir_b/utils.html#'big,string utils: `'big`(a: string): SomeType This is now a header subdir/subdir_b/utils.html#this-is-now-a-header This is now a header Next header subdir/subdir_b/utils.html#this-is-now-a-header-next-header Next header And so on subdir/subdir_b/utils.html#next-header-and-so-on And so on diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index dbacb57a7..e45492dac 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -559,6 +559,8 @@ This should be visible.

              Procs

              + +
              proc addfBug14485() {....raises: [], tags: [].}
              @@ -579,6 +581,10 @@ Some proc
              + +
              + +
              proc anything() {....raises: [], tags: [].}
              @@ -587,6 +593,10 @@ There is no block quote after blank lines at the beginning.
              + +
              + +
              proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
                                               tags: [RootEffect].}
              @@ -596,6 +606,10 @@ ok1
  • + + + +
    proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    @@ -604,6 +618,10 @@ ok1
    + +
    + +
    proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    @@ -614,6 +632,10 @@ ok1
    + +
    + +
    proc bar[T](a, b: T): T
    @@ -622,6 +644,10 @@ ok1
    + +
    + +
    proc baz() {....raises: [], tags: [].}
    @@ -641,6 +667,10 @@ This is deprecated without message.
    + +
    + +
    proc buzz[T](a, b: T): T {....deprecated: "since v0.20".}
    @@ -652,6 +682,10 @@ This is deprecated with a message.
    + +
    + +
    proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
         header: "<stdio.h>", varargs, discardable, ...raises: [], tags: [].}
    @@ -661,6 +695,10 @@ This is deprecated with a message.
    + +
    + +
    proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
                                          varargs, discardable, ...raises: [], tags: [].}
    @@ -670,6 +708,10 @@ the c printf. etc.
    + +
    + +
    proc fromUtils3() {....raises: [], tags: [].}
    @@ -681,6 +723,10 @@ came form utils but should be shown where
    + +
    + +
    proc isValid[T](x: T): bool
    @@ -689,6 +735,27 @@ came form utils but should be shown where
    + +
    + +
    +
    +
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    +    ...raises: [], tags: [].}
    +
    + +

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    +

    See also:

    + +
    low(2) # => -9223372036854775808
    + +
    +
    + +
    + +
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
         ...raises: [], tags: [].}
    @@ -704,19 +771,10 @@ came form utils but should be shown where
    -
    -
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    -    ...raises: [], tags: [].}
    -
    -

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    -

    See also:

    - -
    low(2) # => -9223372036854775808
    - -
    + +
    proc p1() {....raises: [], tags: [].}
    @@ -741,6 +799,10 @@ this is a nested doc comment
    + +
    + +
    func someFunc() {....raises: [], tags: [].}
    @@ -749,6 +811,10 @@ My someFunc. Stuff in
    + +
    + +
    proc tripleStrLitTest() {....raises: [], tags: [].}
    @@ -793,6 +859,10 @@ at indent 0
    + +
    + +
    proc z1(): Foo {....raises: [], tags: [].}
    @@ -801,6 +871,10 @@ cz1
    + +
    + +
    proc z2() {....raises: [], tags: [].}
    @@ -811,6 +885,10 @@ cz2
    + +
    + +
    proc z3() {....raises: [], tags: [].}
    @@ -819,6 +897,10 @@ cz3
    + +
    + +
    proc z4() {....raises: [], tags: [].}
    @@ -827,6 +909,10 @@ cz4
    + +
    + +
    proc z5(): int {....raises: [], tags: [].}
    @@ -835,6 +921,10 @@ cz5
    + +
    + +
    proc z6(): int {....raises: [], tags: [].}
    @@ -843,6 +933,10 @@ cz6
    + +
    + +
    proc z7(): int {....raises: [], tags: [].}
    @@ -851,6 +945,10 @@ cz7
    + +
    + +
    proc z8(): int {....raises: [], tags: [].}
    @@ -859,6 +957,10 @@ cz8
    + +
    + +
    proc z9() {....raises: [], tags: [].}
    @@ -869,6 +971,10 @@ cz8
    + +
    + +
    proc z10() {....raises: [], tags: [].}
    @@ -879,6 +985,10 @@ cz8
    + +
    + +
    proc z11() {....raises: [], tags: [].}
    @@ -889,6 +999,10 @@ cz8
    + +
    + +
    proc z12(): int {....raises: [], tags: [].}
    @@ -899,6 +1013,10 @@ cz8
    + +
    + +
    proc z13() {....raises: [], tags: [].}
    @@ -909,6 +1027,10 @@ cz13
    + +
    + +
    proc z17() {....raises: [], tags: [].}
    @@ -920,10 +1042,14 @@ cz17 rest
    +
    +

    Methods

    + +
    method method1(self: Moo) {.base, ...raises: [], tags: [].}
    @@ -932,6 +1058,10 @@ foo1
    + +
    + +
    method method2(self: Moo): int {.base, ...raises: [], tags: [].}
    @@ -940,6 +1070,10 @@ foo2
    + +
    + +
    method method3(self: Moo): int {.base, ...raises: [], tags: [].}
    @@ -949,10 +1083,14 @@ foo3
    +
    +

    Iterators

    + +
    iterator fromUtils1(): int {....raises: [], tags: [].}
    @@ -965,6 +1103,10 @@ foo3
    + +
    + +
    iterator iter1(n: int): int {....raises: [], tags: [].}
    @@ -973,6 +1115,10 @@ foo1
    + +
    + +
    iterator iter2(n: int): int {....raises: [], tags: [].}
    @@ -984,10 +1130,14 @@ foo2
    +
    +

    Macros

    + +
    macro bar(): untyped
    @@ -996,6 +1146,10 @@ foo2
    + +
    + +
    macro z16()
    @@ -1008,6 +1162,10 @@ foo2
    + +
    + +
    macro z18(): int
    @@ -1017,10 +1175,14 @@ cz18
    +
    +

    Templates

    + +
    template foo(a, b: SomeType)
    @@ -1029,6 +1191,10 @@ This does nothing
    + +
    + +
    template fromUtils2()
    @@ -1040,6 +1206,10 @@ ok3
    + +
    + +
    template myfn()
    @@ -1063,6 +1233,10 @@ bar
    + +
    + +
    template testNimDocTrailingExample()
    @@ -1073,6 +1247,10 @@ bar
    + +
    + +
    template z6t(): int
    @@ -1081,6 +1259,10 @@ cz6t
    + +
    + +
    template z14()
    @@ -1091,6 +1273,10 @@ cz14
    + +
    + +
    template z15()
    @@ -1110,6 +1296,8 @@ cz15
    +
    +
    diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index f72f6c37e..da76334d4 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -71,7 +71,25 @@ window.addEventListener('DOMContentLoaded', main);

    Index

    Modules: subdir/subdir_b/utils, testproject.

    API symbols

    -
    A:
    +
    binarySearch:
    buzz:
    +
    f:
    +
    fn:
    fn10:
    • utils: fn10(a: int): int
    • @@ -178,6 +212,10 @@ window.addEventListener('DOMContentLoaded', main);
      fn2:
      fn3:
      +
      fooBar:
      FooBuzz:
      +
      funWithGenerics:
      +
      G:
      isValid:
      • testproject: isValid[T](x: T): bool
      • diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index 37c91dd3c..5d881e620 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -1,5 +1,7 @@ ##[ +.. include:: ./utils_overview.rst + # This is now a header ## Next header @@ -19,13 +21,32 @@ More text. 1. Other case value 2. Second case. +Ref group fn2_ or specific function like `fn2()`_ +or `fn2( int )`_ or `fn2(int, +float)`_. + +Ref generics like this: binarySearch_ or `binarySearch(openArray[T], K, +proc (T, K))`_ or `proc binarySearch(openArray[T], K, proc (T, K))`_ or +in different style: `proc binarysearch(openarray[T], K, proc(T, K))`_. +Can be combined with export symbols and type parameters: +`binarysearch*[T, K](openArray[T], K, proc (T, K))`_. +With spaces `binary search`_. + +Note that `proc` can be used in postfix form: `binarySearch proc`_. + +Ref. type like G_ and `type G`_ and `G[T]`_ and `type G*[T]`_. + ]## +include ./utils_helpers + type SomeType* = enum enumValueA, enumValueB, enumValueC + G*[T] = object + val: T proc someType*(): SomeType = ## constructor. @@ -33,6 +54,14 @@ proc someType*(): SomeType = proc fn2*() = discard ## comment +proc fn2*(x: int) = + ## fn2 comment + discard +proc fn2*(x: int, y: float) = + discard +proc binarySearch*[T, K](a: openArray[T]; key: K; + cmp: proc (x: T; y: K): int {.closure.}): int = + discard proc fn3*(): auto = 1 ## comment proc fn4*(): auto = 2 * 3 + 4 ## comment proc fn5*() ## comment @@ -89,3 +118,39 @@ template fromUtilsGen*(): untyped = ## came form utils but should be shown where `fromUtilsGen` is called runnableExamples: discard """should be shown as examples for fromUtils3 in module calling fromUtilsGen""" + +proc f*(x: G[int]) = + ## There is also variant `f(G[string])`_ + discard +proc f*(x: G[string]) = + ## See also `f(G[int])`_. + discard + +## Ref. `[]`_ is the same as `proc \`[]\`(G[T])`_ because there are no +## overloads. The full form: `proc \`[]\`*[T](x: G[T]): T`_ + +proc `[]`*[T](x: G[T]): T = x.val + +## Ref. `[]=`_ aka `\`[]=\`(G[T], int, T)`_. + +proc `[]=`*[T](a: var G[T], index: int, value: T) = discard + +## Ref. `$`_ aka `proc $`_ or `proc \`$\``_. + +proc `$`*[T](a: G[T]): string = "" + +## Ref. `$(a: ref SomeType)`_. + +proc `$`*[T](a: ref SomeType): string = "" + +## Ref. foo_bar_ aka `iterator foo_bar_`_. + +iterator fooBar*(a: seq[SomeType]): int = discard + +## Ref. `fn[T; U,V: SomeFloat]()`_. + +proc fn*[T; U, V: SomeFloat]() = discard + +## Ref. `'big`_ or `func \`'big\``_ or `\`'big\`(string)`_. + +func `'big`*(a: string): SomeType = discard diff --git a/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim new file mode 100644 index 000000000..2c45ffb83 --- /dev/null +++ b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim @@ -0,0 +1 @@ +proc funWithGenerics*[T, U: SomeFloat](a: T, b: U) = discard diff --git a/nimdoc/testproject/subdir/subdir_b/utils_overview.rst b/nimdoc/testproject/subdir/subdir_b/utils_overview.rst new file mode 100644 index 000000000..58ce930bf --- /dev/null +++ b/nimdoc/testproject/subdir/subdir_b/utils_overview.rst @@ -0,0 +1,8 @@ +This is a description of the utils module. + +Links work: + +* other module: `iterators `_ (not in this dir, just an example) +* internal: `fn2(x)`_ +* internal included from another module: `funWithGenerics*[T, U: + SomeFloat](a: T, b: U)`_. diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim new file mode 100644 index 000000000..5bcdf32d5 --- /dev/null +++ b/tests/stdlib/tdochelpers.nim @@ -0,0 +1,155 @@ +discard """ + output: ''' + +[Suite] Integration with Nim +''' +""" + +# tests for dochelpers.nim module + +import ../../lib/packages/docutils/[rstast, rst, dochelpers] +import unittest + +proc rstParseTest(text: string): PRstNode = + proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind, + arg: string) = + doAssert msgkind == mwBrokenLink + let r = rstParse(text, "-input-", LineRstInit, ColRstInit, + {roPreferMarkdown, roSupportMarkdown, roNimFile}, + msgHandler=testMsgHandler) + result = r.node + +suite "Integration with Nim": + test "simple symbol parsing (shortest form)": + let input1 = "g_".rstParseTest + check input1.toLangSymbol == LangSymbol(symKind: "", name: "g") + + test "simple symbol parsing (group of words)": + let input1 = "`Y`_".rstParseTest + check input1.toLangSymbol == LangSymbol(symKind: "", name: "Y") + + # this means not a statement 'type', it's a backticked identifier `type`: + let input2 = "`type`_".rstParseTest + check input2.toLangSymbol == LangSymbol(symKind: "", name: "type") + + let input3 = "`[]`_".rstParseTest + check input3.toLangSymbol == LangSymbol(symKind: "", name: "[]") + + let input4 = "`X Y Z`_".rstParseTest + check input4.toLangSymbol == LangSymbol(symKind: "", name: "Xyz") + + test "simple proc parsing": + let input1 = "proc f".rstParseTest + check input1.toLangSymbol == LangSymbol(symKind: "proc", name: "f") + + test "another backticked name": + let input1 = """`template \`type\``_""".rstParseTest + check input1.toLangSymbol == LangSymbol(symKind: "template", name: "type") + + test "simple proc parsing with parameters": + let input1 = "`proc f*()`_".rstParseTest + let input2 = "`proc f()`_".rstParseTest + let expected = LangSymbol(symKind: "proc", name: "f", + parametersProvided: true) + check input1.toLangSymbol == expected + check input2.toLangSymbol == expected + + test "symbol parsing with 1 parameter": + let input = "`f(G[int])`_".rstParseTest + let expected = LangSymbol(symKind: "", name: "f", + parameters: @[("G[int]", "")], + parametersProvided: true) + check input.toLangSymbol == expected + + test "more proc parsing": + let input1 = "`proc f[T](x:G[T]):M[T]`_".rstParseTest + let input2 = "`proc f[ T ] ( x: G [T] ): M[T]`_".rstParseTest + let input3 = "`proc f*[T](x: G[T]): M[T]`_".rstParseTest + let expected = LangSymbol(symKind: "proc", + name: "f", + generics: "[T]", + parameters: @[("x", "G[T]")], + parametersProvided: true, + outType: "M[T]") + check(input1.toLangSymbol == expected) + check(input2.toLangSymbol == expected) + check(input3.toLangSymbol == expected) + + test "advanced proc parsing with Nim identifier normalization": + let input = """`proc binarySearch*[T, K](a: openArray[T]; key: K; + cmp: proc (x: T; y: K): int)`_""".rstParseTest + let expected = LangSymbol(symKind: "proc", + name: "binarysearch", + generics: "[T,K]", + parameters: @[ + ("a", "openarray[T]"), + ("key", "K"), + ("cmp", "proc(x:T;y:K):int")], + parametersProvided: true, + outType: "") + check(input.toLangSymbol == expected) + + test "the same without proc": + let input = """`binarySearch*[T, K](a: openArray[T]; key: K; + cmp: proc (x: T; y: K): int {.closure.})`_""".rstParseTest + let expected = LangSymbol(symKind: "", + name: "binarysearch", + generics: "[T,K]", + parameters: @[ + ("a", "openarray[T]"), + ("key", "K"), + ("cmp", "proc(x:T;y:K):int")], + parametersProvided: true, + outType: "") + check(input.toLangSymbol == expected) + + test "operator $ with and without backticks": + let input1 = """`func \`$\`*[T](a: \`open Array\`[T]): string`_""". + rstParseTest + let input2 = """`func $*[T](a: \`open Array\`[T]): string`_""". + rstParseTest + let expected = LangSymbol(symKind: "func", + name: "$", + generics: "[T]", + parameters: @[("a", "openarray[T]")], + parametersProvided: true, + outType: "string") + check(input1.toLangSymbol == expected) + check(input2.toLangSymbol == expected) + + test "operator [] with and without backticks": + let input1 = """`func \`[]\`[T](a: \`open Array\`[T], idx: int): T`_""". + rstParseTest + let input2 = """`func [][T](a: \`open Array\`[T], idx: int): T`_""". + rstParseTest + let expected = LangSymbol(symKind: "func", + name: "[]", + generics: "[T]", + parameters: @[("a", "openarray[T]"), + ("idx", "int")], + parametersProvided: true, + outType: "T") + check(input1.toLangSymbol == expected) + check(input2.toLangSymbol == expected) + + test "postfix symbol specifier #1": + let input = """`walkDir iterator`_""". + rstParseTest + let expected = LangSymbol(symKind: "iterator", + name: "walkdir") + check(input.toLangSymbol == expected) + + test "postfix symbol specifier #2": + let input1 = """`\`[]\`[T](a: \`open Array\`[T], idx: int): T func`_""". + rstParseTest + let input2 = """`[][T](a: \`open Array\`[T], idx: int): T func`_""". + rstParseTest + let expected = LangSymbol(symKind: "func", + name: "[]", + generics: "[T]", + parameters: @[("a", "openarray[T]"), + ("idx", "int")], + parametersProvided: true, + outType: "T") + check(input1.toLangSymbol == expected) + check(input2.toLangSymbol == expected) diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index e9f67324c..e4609a671 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -17,9 +17,7 @@ discard """ # tests for rst module -import ../../lib/packages/docutils/rstgen -import ../../lib/packages/docutils/rst -import ../../lib/packages/docutils/rstast +import ../../lib/packages/docutils/[rstgen, rst, rstast] import unittest, strutils import std/private/miscdollars import os @@ -61,6 +59,52 @@ proc toAst(input: string, result = e.msg suite "RST parsing": + test "References are whitespace-neutral and case-insensitive": + # refname is 'lexical-analysis', the same for all the 3 variants: + check(dedent""" + Lexical Analysis + ================ + + Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_. + """.toAst == + dedent""" + rnInner + rnHeadline level=1 + rnLeaf 'Lexical' + rnLeaf ' ' + rnLeaf 'Analysis' + rnParagraph + rnLeaf 'Ref' + rnLeaf '.' + rnLeaf ' ' + rnInternalRef + rnInner + rnLeaf 'Lexical' + rnLeaf ' ' + rnLeaf 'Analysis' + rnLeaf 'lexical-analysis' + rnLeaf ' ' + rnLeaf 'or' + rnLeaf ' ' + rnInternalRef + rnInner + rnLeaf 'Lexical' + rnLeaf ' ' + rnLeaf 'analysis' + rnLeaf 'lexical-analysis' + rnLeaf ' ' + rnLeaf 'or' + rnLeaf ' ' + rnInternalRef + rnInner + rnLeaf 'lexical' + rnLeaf ' ' + rnLeaf 'analysis' + rnLeaf 'lexical-analysis' + rnLeaf '.' + rnLeaf ' ' + """) + test "option list has priority over definition list": check(dedent""" --defusages @@ -376,9 +420,9 @@ suite "Warnings": let output = input.toAst(warnings=warnings) check(warnings[] == @[ "input(3, 14) Warning: broken link 'citation-som'", - "input(5, 7) Warning: broken link 'a-broken-link'", + "input(5, 7) Warning: broken link 'a broken Link'", "input(7, 15) Warning: unknown substitution 'undefined subst'", - "input(9, 6) Warning: broken link 'shortdotlink'" + "input(9, 6) Warning: broken link 'short.link'" ]) test "With include directive and blank lines at the beginning": @@ -391,7 +435,7 @@ suite "Warnings": let input = ".. include:: other.rst" var warnings = new seq[string] let output = input.toAst(warnings=warnings) - check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenlink'"] + check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"] check(output == dedent""" rnInner rnParagraph @@ -404,6 +448,59 @@ suite "Warnings": """) removeFile("other.rst") + test "warnings for ambiguous links (references + anchors)": + # Reference like `x`_ generates a link alias x that may clash with others + let input = dedent""" + Manual reference: `foo <#foo,string,string>`_ + + .. _foo: + + Paragraph. + + Ref foo_ + """ + var warnings = new seq[string] + let output = input.toAst(warnings=warnings) + check(warnings[] == @[ + dedent """ + input(7, 5) Warning: ambiguous doc link `foo` + clash: + (3, 8): (manual directive anchor) + (1, 45): (implicitly-generated hyperlink alias)""" + ]) + # reference should be resolved to the manually set anchor: + check(output == + dedent""" + rnInner + rnParagraph + rnLeaf 'Manual' + rnLeaf ' ' + rnLeaf 'reference' + rnLeaf ':' + rnLeaf ' ' + rnHyperlink + rnInner + rnLeaf 'foo' + rnInner + rnLeaf '#' + rnLeaf 'foo' + rnLeaf ',' + rnLeaf 'string' + rnLeaf ',' + rnLeaf 'string' + rnParagraph anchor='foo' + rnLeaf 'Paragraph' + rnLeaf '.' + rnParagraph + rnLeaf 'Ref' + rnLeaf ' ' + rnInternalRef + rnInner + rnLeaf 'foo' + rnLeaf 'foo' + rnLeaf ' ' + """) + suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 867677404..45cf1a68e 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1054,8 +1054,9 @@ Test1 Paragraph2 ref `internal anchor`_. """ let output9 = input9.toHtml - #doAssert "id=\"internal-anchor\"" in output9 - #doAssert "internal anchor" notin output9 + # _`internal anchor` got erased: + check "href=\"#internal-anchor\"" notin output9 + check "href=\"#citation-another\"" in output9 doAssert output9.count("
        " & "
        ") == 1 doAssert output9.count("
        ") == 3 @@ -1330,12 +1331,12 @@ Test1 """ let output1 = input1.toHtml # "target101" should be erased and changed to "section-xyz": - doAssert "href=\"#target101\"" notin output1 - doAssert "id=\"target101\"" notin output1 - doAssert "href=\"#target102\"" notin output1 - doAssert "id=\"target102\"" notin output1 - doAssert "id=\"section-xyz\"" in output1 - doAssert "href=\"#section-xyz\"" in output1 + check "href=\"#target101\"" notin output1 + check "id=\"target101\"" notin output1 + check "href=\"#target102\"" notin output1 + check "id=\"target102\"" notin output1 + check "id=\"section-xyz\"" in output1 + check "href=\"#section-xyz\"" in output1 let input2 = dedent """ .. _target300: @@ -1405,7 +1406,7 @@ Test1 let output1 = input1.toHtml doAssert "id=\"secdot1\"" in output1 doAssert "id=\"Z2minusothercolonsecplusc-2\"" in output1 - doAssert "id=\"linkdot1-2021\"" in output1 + check "id=\"linkdot1-2021\"" in output1 let ref1 = "sec.1" let ref2 = "2-other:sec+c_2" let ref3 = "link.1_2021" From ee703c5db4ceb8d0228b4429c53d85d5f1ff91ea Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Fri, 29 Oct 2021 10:39:41 +0100 Subject: [PATCH 3100/4254] Fix nimIdentNormalize, fixes #19067 (#19068) * Make nimIdentNormalize return "" when passed ""; fixes #19067 Fixes #19067 * Add tests for nimIdentNormalize --- lib/pure/strutils.nim | 5 +++-- tests/stdlib/tstrutils.nim | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 2234a8625..e4a4a5ec1 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -281,8 +281,9 @@ func nimIdentNormalize*(s: string): string = runnableExamples: doAssert nimIdentNormalize("Foo_bar") == "Foobar" result = newString(s.len) - if s.len > 0: - result[0] = s[0] + if s.len == 0: + return + result[0] = s[0] var j = 1 for i in 1..len(s) - 1: if s[i] in {'A'..'Z'}: diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 234991bdb..8000b6b07 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -841,5 +841,12 @@ bar doAssert s.endsWith('a') == false doAssert s.endsWith('\0') == false + block: # nimIdentNormalize + doAssert nimIdentNormalize("") == "" + doAssert nimIdentNormalize("foo") == "foo" + doAssert nimIdentNormalize("foo_bar") == "foobar" + doAssert nimIdentNormalize("Foo_bar") == "Foobar" + doAssert nimIdentNormalize("_Foo_bar") == "_foobar" + static: main() main() From cfdac6666f5772479724e082fb08c2db694d8d40 Mon Sep 17 00:00:00 2001 From: Tail Wag Games Date: Fri, 29 Oct 2021 06:42:44 -0500 Subject: [PATCH 3101/4254] Freeing critical sections via atexit in system/alloc and system/io (#19062) * adding new system module sysexitprocs and including system exit procedures when registering exit handlers defined in userland * fixing failing tests and adding initialization guard to handle cases where the module's global init logic isn't invoked first as is the case with some gc implementaions * js backend shouldn't try to invoke actual system exit procs * fixing formatting in sysexitprocs.nim * 256 was too much - my max number of plugins in my engine is 64 and I require two hooks per runtime it looks like with tls emulation turned off, so for my purposes 128 should be sufficient * so atExit should be enough here, can get rid of all the extra cruft I had added on top since I didn't realize atExit already provided a stack * done being cute - since newruntime prevents correct cpp codegen for object variants apparently and breaks tests if I try to use std/exitprocs, ddSysExitProc is just going into both modules. Since system doesn't include system/io, polluting system with it doesn't make sense either... at least it is only importc'd when it is required in either module and we don't have to have any weird when defined(nimOwnedEnabled) with a comment explaining why --- lib/std/exitprocs.nim | 3 --- lib/system/alloc.nim | 3 +++ lib/system/io.nim | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index c76583a8c..c6537f7f8 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -44,9 +44,6 @@ proc callClosures() {.noconv.} = of kClosure: fun.fun1() of kNoconv: fun.fun2() - when not defined(js) and not defined(nimOwnedEnabled): - deinitLock(gFunsLock) - template fun() = if gFuns.len == 0: addAtExit(callClosures) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 6d83a2c17..2c6ab4462 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -1054,9 +1054,12 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = it = it.next when hasThreadSupport: + proc addSysExitProc(quitProc: proc() {.noconv.}) {.importc: "atexit", header: "".} + var sharedHeap: MemRegion var heapLock: SysLock initSysLock(heapLock) + addSysExitProc(proc() {.noconv.} = deinitSys(heapLock)) proc getFreeMem(): int = #sysAssert(result == countFreeMem()) diff --git a/lib/system/io.nim b/lib/system/io.nim index e7369392a..2ad43acdb 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -777,15 +777,15 @@ proc setStdIoUnbuffered*() {.tags: [], benign.} = when declared(stdout): when defined(windows) and compileOption("threads"): + proc addSysExitProc(quitProc: proc() {.noconv.}) {.importc: "atexit", header: "".} + const insideRLocksModule = false include "system/syslocks" + var echoLock: SysLock initSysLock echoLock - - when not defined(js) and not defined(nimOwnedEnabled): - import std/exitprocs - addExitProc(proc() {.noconv.} = deinitSys echoLock) + addSysExitProc(proc() {.noconv.} = deinitSys(echoLock)) const stdOutLock = not defined(windows) and not defined(android) and From f755e452d2a2c7656f07793b7f01dc654a7c5253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derek=20=E5=91=86?= <116649+derekdai@users.noreply.github.com> Date: Sat, 30 Oct 2021 01:55:48 +0800 Subject: [PATCH 3102/4254] fix #18971 (#19070) [backport:1.6] since the example code return value from global variable, instead of first argument, the `n.len` is 1 which causes compiler crashes. --- compiler/varpartitions.nim | 2 +- tests/arc/t18971.nim | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/arc/t18971.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 8f422face..709d00fa0 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -479,7 +479,7 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = # calls do construct, what we construct must be destroyed, # so dest cannot be a cursor: dest.flags.incl ownsData - elif n.typ.kind in {tyLent, tyVar}: + elif n.typ.kind in {tyLent, tyVar} and n.len > 1: # we know the result is derived from the first argument: var roots: seq[(PSym, int)] allRoots(n[1], roots, RootEscapes) diff --git a/tests/arc/t18971.nim b/tests/arc/t18971.nim new file mode 100644 index 000000000..9b587d956 --- /dev/null +++ b/tests/arc/t18971.nim @@ -0,0 +1,10 @@ +discard """ + cmd: "nim c --gc:arc $file" +""" + +type MyObj = ref object + +var o = MyObj() +proc x: var MyObj = o + +var o2 = x() From 2bda4a30a6b12dd0840dc347e454e54fe26721e7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 30 Oct 2021 10:14:23 +0200 Subject: [PATCH 3103/4254] fixes #19000 (#19032) * fixes #19000 * progress --- lib/system/memalloc.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index f8ebc8c5f..49766e69d 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -116,6 +116,9 @@ when hasAlloc and not defined(js): ## ## See also: ## * `create <#create,typedesc>`_ + static: + when sizeof(T) <= 0: + {.fatal: "createU does not support types T where sizeof(T) == 0".} cast[ptr T](alloc(T.sizeof * size)) template alloc0*(size: Natural): pointer = @@ -141,6 +144,9 @@ when hasAlloc and not defined(js): ## ## The allocated memory belongs to its allocating thread! ## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap. + static: + when sizeof(T) <= 0: + {.fatal: "create does not support types T where sizeof(T) == 0".} cast[ptr T](alloc0(sizeof(T) * size)) template realloc*(p: pointer, newSize: Natural): pointer = From 2f730afe9e7eb981258aea257deba0240f488dd1 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 31 Oct 2021 13:22:00 +0800 Subject: [PATCH 3104/4254] fix #18410 (Errors initializing an object of RootObj with the C++ backend) [backport] (#18836) * fix #18410 * one line comment * typo * typo * cover cpp --- compiler/cgen.nim | 3 ++- tests/arc/tconst_to_sink.nim | 3 ++- tests/cpp/torc.nim | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/cpp/torc.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 412a428da..b669483cc 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -363,7 +363,8 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, else: linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) of frEmbedded: - if optTinyRtti in p.config.globalOptions: + # inheritance in C++ does not allow struct initialization: bug #18410 + if not p.module.compileToCpp and optTinyRtti in p.config.globalOptions: var tmp: TLoc if mode == constructRefObj: let objType = t.skipTypes(abstractInst+{tyRef}) diff --git a/tests/arc/tconst_to_sink.nim b/tests/arc/tconst_to_sink.nim index ddcc46e67..25f659341 100644 --- a/tests/arc/tconst_to_sink.nim +++ b/tests/arc/tconst_to_sink.nim @@ -1,6 +1,7 @@ discard """ output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]''' - cmd: "nim c --gc:arc $file" + matrix: "--gc:arc" + targets: "c cpp" """ # bug #13240 diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim new file mode 100644 index 000000000..7fc474f94 --- /dev/null +++ b/tests/cpp/torc.nim @@ -0,0 +1,15 @@ +discard """ + targets: "cpp" + matrix: "--gc:orc" +""" + +import std/options + +# bug #18410 +type + O = object of RootObj + val: pointer + +proc p(): Option[O] = none(O) + +doAssert $p() == "none(O)" \ No newline at end of file From 4c510d5577a0ced6a31b8417fed74acdd604b9a3 Mon Sep 17 00:00:00 2001 From: haxscramper Date: Tue, 2 Nov 2021 10:54:04 +0300 Subject: [PATCH 3105/4254] [FIX] Do not break formatted string line (#19085) [backport] Otherwise, compiler produces broken error message - `$1` is not interpolated `Error: The $1 type doesn't have a default value. The following fields must be initialized: importGraph.` --- compiler/semobjconstr.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 001956ede..30ab76957 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -368,8 +368,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = let initResult = semConstructTypeAux(c, constrCtx, {}) assert constrCtx.missingFields.len > 0 localError(c.config, info, - "The $1 type doesn't have a default value. The following fields must " & - "be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)]) + "The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)]) elif objType.kind == tyDistinct: localError(c.config, info, "The $1 distinct type doesn't have a default value." % typeToString(t)) From 24a75842998709b29ef50ef4cc10d30304efe3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derek=20=E5=91=86?= <116649+derekdai@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:55:50 +0800 Subject: [PATCH 3106/4254] update numbers of lifetime-tracking hooks in doc/destructors.rst (#19088) --- doc/destructors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index 6e4509666..d6f240dee 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -101,7 +101,7 @@ The memory management for Nim's standard `string` and `seq` types as well as other standard collections is performed via so-called "Lifetime-tracking hooks", which are particular `type bound operators `_. -There are 3 different hooks for each (generic or concrete) object type `T` (`T` can also be a +There are 4 different hooks for each (generic or concrete) object type `T` (`T` can also be a `distinct` type) that are called implicitly by the compiler. (Note: The word "hook" here does not imply any kind of dynamic binding From cc984217a98438de5a36447ea6574eb2c5da4ae4 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Tue, 2 Nov 2021 02:02:53 -0600 Subject: [PATCH 3107/4254] Fix VM's sametype impl to work for generics/typedescs (#19073) * Fix vm's sametype implementation to properly handle generics and typedescs * actually fixed sametype + have test * added comments and removed unsafe code --- compiler/types.nim | 5 ++++ compiler/vm.nim | 3 ++- tests/stdlib/tmacros.nim | 58 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/compiler/types.nim b/compiler/types.nim index 2c7b91d9f..7cf02c240 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1128,6 +1128,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = a = a.skipTypes({tyDistinct, tyGenericInst}) if a.kind != b.kind: return false + #[ + The following code should not run in the case either side is an generic alias, + but it's not presently possible to distinguish the genericinsts from aliases of + objects ie `type A[T] = SomeObject` + ]# # this is required by tunique_type but makes no sense really: if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags: let diff --git a/compiler/vm.nim b/compiler/vm.nim index 1b443aff1..b64545081 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1044,7 +1044,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = strictSymEquality=true)) of opcSameNodeType: decodeBC(rkInt) - regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil regs[rc].node.typ) + regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil(regs[rc].node.typ, {ExactTypeDescValues, ExactGenericParams})) + # The types should exactly match which is why we pass `{ExactTypeDescValues..ExactGcSafety}`. of opcXor: decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal) diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index 18cfdc75c..64a474743 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -66,3 +66,61 @@ block: # unpackVarargs doAssert call1(toString) == "" doAssert call1(toString, 10) == "10" doAssert call1(toString, 10, 11) == "1011" + +block: # SameType + type + A = int + B = distinct int + C = object + Generic[T, Y] = object + macro isSameType(a, b: typed): untyped = + newLit(sameType(a, b)) + + static: + assert Generic[int, int].isSameType(Generic[int, int]) + assert Generic[A, string].isSameType(Generic[int, string]) + assert not Generic[A, string].isSameType(Generic[B, string]) + assert not Generic[int, string].isSameType(Generic[int, int]) + assert isSameType(int, A) + assert isSameType(10, 20) + assert isSameType("Hello", "world") + assert not isSameType("Hello", cstring"world") + assert not isSameType(int, B) + assert not isSameType(int, Generic[int, int]) + assert not isSameType(C, string) + assert not isSameType(C, int) + + + #[ + # compiler sameType fails for the following, read more in `types.nim`'s `sameTypeAux`. + type + D[T] = C + G[T] = T + static: + assert isSameType(D[int], C) + assert isSameType(D[int], D[float]) + assert isSameType(G[float](1.0), float(1.0)) + assert isSameType(float(1.0), G[float](1.0)) + ]# + + type Tensor[T] = object + data: T + + macro testTensorInt(x: typed): untyped = + let + tensorIntType = getTypeInst(Tensor[int])[1] + xTyp = x.getTypeInst + + newLit(xTyp.sameType(tensorIntType)) + + var + x: Tensor[int] + x1 = Tensor[float]() + x2 = Tensor[A]() + x3 = Tensor[B]() + + static: + assert testTensorInt(x) + assert not testTensorInt(x1) + assert testTensorInt(x2) + assert not testTensorInt(x3) From 2e0db988e7efd05b07f5165cf1357efea9391eb3 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Tue, 2 Nov 2021 04:06:46 -0400 Subject: [PATCH 3108/4254] tests: Fix warnings in tstrscans (#19082) --- tests/stdlib/tstrscans.nim | 60 +++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index d443c5dda..24a3c02f7 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -15,7 +15,7 @@ block ParsePasswd: else: break - const etc_passwd = """root:x:0:0:root:/root:/bin/bash + const etcPasswd = """root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh @@ -23,7 +23,7 @@ nobody:x:65534:65534:nobody:/nonexistent:/bin/sh messagebus:x:103:107::/var/run/dbus:/bin/false """ - const parsed_etc_passwd = @[ + const parsedEtcPasswd = @[ "root:x:0:0:root:/root:/bin/bash", "daemon:x:1:1:daemon:/usr/sbin:/bin/sh", "bin:x:2:2:bin:/bin:/bin/sh", @@ -31,7 +31,7 @@ messagebus:x:103:107::/var/run/dbus:/bin/false "nobody:x:65534:65534:nobody:/nonexistent:/bin/sh", "messagebus:x:103:107::/var/run/dbus:/bin/false", ] - doAssert etc_passwd.parsePasswd == parsed_etc_passwd + doAssert etcPasswd.parsePasswd == parsedEtcPasswd block LastNot: var idx : int @@ -139,27 +139,27 @@ block: break var key, val: string - var intval: int - var floatval: float - doAssert scanf("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f", key, val, intval, floatVal) + var intVal: int + var floatVal: float + doAssert scanf("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f", key, val, intVal, floatVal) doAssert key == "abc" doAssert val == "xyz" - doAssert intval == 89 + doAssert intVal == 89 doAssert floatVal == 33.25 - var binval: int - var octval: int - var hexval: int - doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) - doAssert binval == 0b0101 - doAssert octval == 0o1234 - doAssert hexval == 0xabcd + var binVal: int + var octVal: int + var hexVal: int + doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal) + doAssert binVal == 0b0101 + doAssert octVal == 0o1234 + doAssert hexVal == 0xabcd - let xx = scanf("$abc", "$$$i", intval) + let xx = scanf("$abc", "$$$i", intVal) doAssert xx == false - let xx2 = scanf("$1234", "$$$i", intval) + let xx2 = scanf("$1234", "$$$i", intVal) doAssert xx2 let yy = scanf(";.--Breakpoint00 [output]", @@ -246,24 +246,32 @@ block: result = 0 while start+result < input.len and input[start+result] in seps: inc result + type + ScanRetType = tuple + success: bool + lo: int + hi: int + ch: char + word: string + var res = 0 for line in input.splitLines: - let (success, lo, hi, c ,w) = scanTuple(line, "$i-$i $c: $w") - if success: + let ret: ScanRetType = scanTuple(line, "$i-$i $c: $w") + if ret.success: inc res doAssert res == 4 - let (_, key, val, intval, floatVal) = scanTuple("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f") + let (_, key, val, intVal, floatVal) = scanTuple("abc:: xyz 89 33.25", "$w$s::$s$w$s$i $f") doAssert key == "abc" doAssert val == "xyz" - doAssert intval == 89 + doAssert intVal == 89 doAssert floatVal == 33.25 - let (_, binVal, octVal, hexVal) = scanTuple("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) - doAssert binval == 0b0101 - doAssert octval == 0o1234 - doAssert hexval == 0xabcd + let (_, binVal, octVal, hexVal) = scanTuple("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal) + doAssert binVal == 0b0101 + doAssert octVal == 0o1234 + doAssert hexVal == 0xabcd var (xx,_) = scanTuple("$abc", "$$$i") doAssert xx == false @@ -272,9 +280,9 @@ block: let (xx2, _) = block: scanTuple("$1234", "$$$i") doAssert xx2 - var (yy, intval2, key2) = scanTuple(";.--Breakpoint00 [output]", + var (yy, intVal2, key2) = scanTuple(";.--Breakpoint00 [output]", "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.", int) doAssert yy doAssert key2 == "output" - doAssert intVal2 == 13 \ No newline at end of file + doAssert intVal2 == 13 From e01e543fce8eab147d4e7eb5b89bba80c25e9cb3 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 2 Nov 2021 16:10:25 +0800 Subject: [PATCH 3109/4254] bootstrapping Nim compiler with `cpp --gc:orc` (#19087) --- koch.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/koch.nim b/koch.nim index 8dd897028..06515aad7 100644 --- a/koch.nim +++ b/koch.nim @@ -602,9 +602,8 @@ proc runCI(cmd: string) = execFold("Run atlas tests", "nim c -r -d:atlasTests tools/atlas/atlas.nim clone https://github.com/disruptek/balls") when not defined(bsd): - if not doUseCpp: - # the BSDs are overwhelmed already, so only run this test on the other machines: - kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib") + # the BSDs are overwhelmed already, so only run this test on the other machines: + kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib") proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) From 12d2901e89d394cb1eb1242acc0107a2d20e3b3d Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Tue, 2 Nov 2021 04:12:54 -0400 Subject: [PATCH 3110/4254] libs/impore/re: Add note about the requirement of `matches` to be pre-allocated (#19081) Add few runnableExamples for `findBounds` for clarity. Fixes https://github.com/nim-lang/Nim/issues/18775 --- lib/impure/re.nim | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index d6922f4f1..8e5efbb28 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -152,6 +152,9 @@ proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], ## and the captured ## substrings in the array `matches`. If it does not match, nothing ## is written into `matches` and `(-1,0)` is returned. + ## + ## Note: The memory for `matches` needs to be allocated before this function is + ## called, otherwise it will just remain empty. var rtarray = initRtArray[cint]((matches.len+1)*3) rawMatches = rtarray.getRawData @@ -171,6 +174,14 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], ## and the captured substrings in the array `matches`. ## If it does not match, nothing ## is written into `matches` and `(-1,0)` is returned. + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. + runnableExamples: + var matches = newSeq[string](1) + let (first, last) = findBounds("Hello World", re"(W\w+)", matches) + doAssert first == 6 + doAssert last == 10 + doAssert matches[0] == "World" result = findBounds(cstring(s), pattern, matches, min(start, MaxReBufSize), min(s.len, MaxReBufSize)) @@ -182,6 +193,8 @@ proc findBounds*(buf: cstring, pattern: Regex, ## and the captured substrings in the array `matches`. ## If it does not match, nothing is written into `matches` and ## `(-1,0)` is returned. + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. var rtarray = initRtArray[cint]((matches.len+1)*3) rawMatches = rtarray.getRawData @@ -202,6 +215,14 @@ proc findBounds*(s: string, pattern: Regex, ## and the captured substrings in the array `matches`. ## If it does not match, nothing is written into `matches` and ## `(-1,0)` is returned. + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. + runnableExamples: + var matches = newSeq[tuple[first, last: int]](1) + let (first, last) = findBounds("Hello World", re"(\w+)", matches) + doAssert first == 0 + doAssert last == 4 + doAssert matches[0] == (0, 4) result = findBounds(cstring(s), pattern, matches, min(start, MaxReBufSize), min(s.len, MaxReBufSize)) @@ -255,6 +276,8 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string], ## the same as `match`, but it returns the length of the match, ## if there is no match, `-1` is returned. Note that a match length ## of zero can happen. + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. result = matchOrFind(cstring(s), pattern, matches, start.cint, s.len.cint, pcre.ANCHORED) proc matchLen*(buf: cstring, pattern: Regex, matches: var openArray[string], @@ -262,6 +285,8 @@ proc matchLen*(buf: cstring, pattern: Regex, matches: var openArray[string], ## the same as `match`, but it returns the length of the match, ## if there is no match, `-1` is returned. Note that a match length ## of zero can happen. + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. return matchOrFind(buf, pattern, matches, start.cint, bufSize.cint, pcre.ANCHORED) proc matchLen*(s: string, pattern: Regex, start = 0): int {.inline.} = @@ -292,6 +317,7 @@ proc match*(s: string, pattern: Regex, matches: var openArray[string], ## match, nothing is written into `matches` and `false` is ## returned. ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. runnableExamples: import std/sequtils var matches: array[2, string] @@ -306,6 +332,8 @@ proc match*(buf: cstring, pattern: Regex, matches: var openArray[string], ## match, nothing is written into `matches` and `false` is ## returned. ## `buf` has length `bufSize` (not necessarily `'\0'` terminated). + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. result = matchLen(buf, pattern, matches, start, bufSize) != -1 proc find*(buf: cstring, pattern: Regex, matches: var openArray[string], @@ -314,6 +342,8 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string], ## substrings in the array `matches`. If it does not match, nothing ## is written into `matches` and `-1` is returned. ## `buf` has length `bufSize` (not necessarily `'\0'` terminated). + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. var rtarray = initRtArray[cint]((matches.len+1)*3) rawMatches = rtarray.getRawData @@ -332,6 +362,8 @@ proc find*(s: string, pattern: Regex, matches: var openArray[string], ## returns the starting position of `pattern` in `s` and the captured ## substrings in the array `matches`. If it does not match, nothing ## is written into `matches` and `-1` is returned. + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. result = find(cstring(s), pattern, matches, start, s.len) proc find*(buf: cstring, pattern: Regex, start = 0, bufSize: int): int = @@ -433,6 +465,8 @@ proc contains*(s: string, pattern: Regex, start = 0): bool {.inline.} = proc contains*(s: string, pattern: Regex, matches: var openArray[string], start = 0): bool {.inline.} = ## same as `find(s, pattern, matches, start) >= 0` + ## + ## .. note:: The memory for `matches` needs to be allocated before this function is called, otherwise it will just remain empty. return find(s, pattern, matches, start) >= 0 proc startsWith*(s: string, prefix: Regex): bool {.inline.} = From efaaa38eefa38d842ef9225b6ac3f60c4c842209 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Tue, 2 Nov 2021 05:34:11 -0400 Subject: [PATCH 3111/4254] docstyle.rst: Do not export it to HTML as a standalone doc (#19083) .. This doc is included in contributing.rst. Fixes https://github.com/nim-lang/Nim/issues/14593. --- tools/kochdocs.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 0c5c8f4a3..42e648fb4 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -111,7 +111,10 @@ proc getRst2html(): seq[string] = for a in walkDirRecFilter("doc"): let path = a.path if a.kind == pcFile and path.splitFile.ext == ".rst" and path.lastPathPart notin - ["docs.rst", "nimfix.rst"]: + ["docs.rst", "nimfix.rst", + "docstyle.rst" # docstyle.rst shouldn't be converted to html separately; + # it's included in contributing.rst. + ]: # maybe we should still show nimfix, could help reviving it # `docs` is redundant with `overview`, might as well remove that file? result.add path From a55b90827ed87b61972147e8120c9afa949d17f9 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 2 Nov 2021 23:22:11 +0800 Subject: [PATCH 3112/4254] remove the mention of travis from readme (#19093) --- readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 7f333d5d4..af07c2a7b 100644 --- a/readme.md +++ b/readme.md @@ -149,7 +149,7 @@ read [this guide][pull-request-instructions]. Ideally, you should make sure that all tests pass before submitting a pull request. However, if you are short on time, you can just run the tests specific to your -changes by only running the corresponding categories of tests. Travis CI verifies +changes by only running the corresponding categories of tests. CI verifies that all tests pass before allowing the pull request to be accepted, so only running specific tests should be harmless. Integration tests should go in ``tests/untestable``. @@ -220,7 +220,6 @@ Copyright © 2006-2021 Andreas Rumpf, all rights reserved. [nimsuggest-repo]: https://github.com/nim-lang/nimsuggest [csources-repo-deprecated]: https://github.com/nim-lang/csources [csources-v1-repo]: https://github.com/nim-lang/csources_v1 -[badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square [badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square [badge-nim-discord]: https://img.shields.io/discord/371759389889003530?color=blue&label=discord&logo=discord&logoColor=gold&style=flat-square [badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square From 9d51197aa4eb404c3cce8c5989146dea8d3de024 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 2 Nov 2021 16:30:59 +0100 Subject: [PATCH 3113/4254] fixes #19078 [backport] (#19090) --- compiler/condsyms.nim | 2 ++ compiler/pragmas.nim | 4 +++- compiler/wordrecg.nim | 2 +- lib/std/private/digitsutils.nim | 9 ++++++--- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index df355bc26..5a7e78d5f 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -138,3 +138,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasHintAll") defineSymbol("nimHasTrace") defineSymbol("nimHasEffectsOf") + + defineSymbol("nimHasEnforceNoRaises") diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index a6e6131d7..702a9e082 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -31,7 +31,7 @@ const wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wDelegator, wGcSafe, wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy, - wRequires, wEnsures} + wRequires, wEnsures, wEnforceNoRaises} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty, @@ -1237,6 +1237,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, pragmaProposition(c, it) of wEnsures: pragmaEnsures(c, it) + of wEnforceNoRaises: + sym.flags.incl sfNeverRaises else: invalidPragma(c, it) elif comesFromPush and whichKeyword(ident) != wInvalid: discard "ignore the .push pragma; it doesn't apply" diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index ce06effab..22f6cc71d 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -86,7 +86,7 @@ type wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic", wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked", wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain", - wLiftLocals = "liftlocals", + wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises", wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default", diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index 9be2ab3ef..588bcaec0 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -78,14 +78,17 @@ func addIntImpl(result: var string, x: uint64) {.inline.} = dec next addChars(result, tmp, next, tmp.len - next) -func addInt*(result: var string, x: uint64) = +when not defined(nimHasEnforceNoRaises): + {.pragma: enforceNoRaises.} + +func addInt*(result: var string, x: uint64) {.enforceNoRaises.} = when nimvm: addIntImpl(result, x) else: when not defined(js): addIntImpl(result, x) else: addChars(result, numToString(x)) -proc addInt*(result: var string; x: int64) = +proc addInt*(result: var string; x: int64) {.enforceNoRaises.} = ## Converts integer to its string representation and appends it to `result`. runnableExamples: var s = "foo" @@ -110,5 +113,5 @@ proc addInt*(result: var string; x: int64) = addChars(result, numToString(x)) else: impl() -proc addInt*(result: var string; x: int) {.inline.} = +proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} = addInt(result, int64(x)) From b155864967ba08861c39403003095d4822b03b4e Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 2 Nov 2021 23:31:30 +0800 Subject: [PATCH 3114/4254] build testament in package CI (#19092) * build testament in package CI * Update testament/important_packages.nim --- koch.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 06515aad7..f87828cdc 100644 --- a/koch.nim +++ b/koch.nim @@ -559,7 +559,8 @@ proc runCI(cmd: string) = let batchParam = "--batch:$1" % "NIM_TESTAMENT_BATCH".getEnv("_") if getEnv("NIM_TEST_PACKAGES", "0") == "1": - execFold("Test selected Nimble packages", "nim r testament/testament $# pcat nimble-packages" % batchParam) + nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release") + execFold("Test selected Nimble packages", "testament $# pcat nimble-packages" % batchParam) else: buildTools() From 539bced70df035ddbdbf4c3d9c7fd6074f0b1073 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Wed, 3 Nov 2021 01:46:34 -0400 Subject: [PATCH 3115/4254] Add test for issue 15435 (#19079) * Add test for issue 15435 Closes https://github.com/nim-lang/Nim/issues/15435. * Specify bug # in comment Addresses https://github.com/nim-lang/Nim/pull/19079#discussion_r740279547 --- tests/sets/t15435.nim | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/sets/t15435.nim diff --git a/tests/sets/t15435.nim b/tests/sets/t15435.nim new file mode 100644 index 000000000..5ead7e641 --- /dev/null +++ b/tests/sets/t15435.nim @@ -0,0 +1,29 @@ +# bug #15435 +discard """ +errormsg: "type mismatch: got " +nimout: '''t15435.nim(28, 13) Error: type mismatch: got +but expected one of: +proc `<`[T](x, y: set[T]): bool + first type mismatch at position: 2 + required type for y: set[T] + but expression 'x' is of type: set[range 1..5(uint8)] +20 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them + +expression: {1'u8, 5} < x''' +""" + + + + + + +## line 20 +var + x: set[range[1u8..5u8]] + +x.incl(1) +x.incl(3) +x.incl(5) + +if {1u8, 5} < x: + echo "successful" From 5fed1c05ce7ea9cbeb2b70bb8583e836c981abd4 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Wed, 3 Nov 2021 01:48:30 -0400 Subject: [PATCH 3116/4254] manual: Document the use of `static` as a proc call (#19084) * manual: Document the use of `static` as a proc call Also adds tests. Fixes https://github.com/nim-lang/Nim/issues/16987 . * Update doc/manual.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Use the "bug #NNNN" comment syntax for consistency Ref: https://nim-lang.github.io/Nim/contributing.html#writing-tests-stdlib > Always refer to a GitHub issue using the following exact syntax: bug for tooling. * manual: Undocument usage of foo.static foo.static and foo.static() are not expected to work. Ref: https://github.com/nim-lang/Nim/pull/19084/files#r741203578 Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- doc/manual.rst | 14 ++++++++++++++ tests/system/tstatic_callable.nim | 12 ++++++++++++ tests/system/tstatic_callable_error.nim | 14 ++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 tests/system/tstatic_callable.nim create mode 100644 tests/system/tstatic_callable_error.nim diff --git a/doc/manual.rst b/doc/manual.rst index 4b212fe19..1371dba17 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2975,6 +2975,20 @@ Even some code that has side effects is permitted in a static block: static: echo "echo at compile time" +`static` can also be used like a routine. + +.. code-block:: nim + + proc getNum(a: int): int = a + + # Below calls "echo getNum(123)" at compile time. + static: + echo getNum(123) + + # Below call evaluates the "getNum(123)" at compile time, but its + # result gets used at run time. + echo static(getNum(123)) + There are limitations on what Nim code can be executed at compile time; see `Restrictions on Compile-Time Execution <#restrictions-on-compileminustime-execution>`_ for details. diff --git a/tests/system/tstatic_callable.nim b/tests/system/tstatic_callable.nim new file mode 100644 index 000000000..92d1fca8d --- /dev/null +++ b/tests/system/tstatic_callable.nim @@ -0,0 +1,12 @@ +# bug #16987 + +proc getNum(a: int): int = a + +# Below calls "doAssert getNum(123) == 123" at compile time. +static: + doAssert getNum(123) == 123 + +# Below calls evaluate the "getNum(123)" at compile time, but the +# results of those calls get used at run time. +doAssert (static getNum(123)) == 123 +doAssert (static(getNum(123))) == 123 diff --git a/tests/system/tstatic_callable_error.nim b/tests/system/tstatic_callable_error.nim new file mode 100644 index 000000000..c6f1e3d07 --- /dev/null +++ b/tests/system/tstatic_callable_error.nim @@ -0,0 +1,14 @@ +# bug #16987 + +discard """ +errormsg: "cannot evaluate at compile time: inp" +nimout: ''' +tstatic_callable_error.nim(14, 21) Error: cannot evaluate at compile time: inp''' +""" + + +# line 10 +proc getNum(a: int): int = a + +let inp = 123 +echo (static getNum(inp)) From dbbafd320ce1edb0e51167c8e9f6ba3d865672c3 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Wed, 3 Nov 2021 03:08:50 -0400 Subject: [PATCH 3117/4254] manual: Document that comma propagates the default values of parameters (#19080) * manual: Document that comma propagates the default values of parameters Fixes https://github.com/nim-lang/Nim/issues/15949. * Use the "bug #NNNN" comment syntax for consistency Ref: https://nim-lang.github.io/Nim/contributing.html#writing-tests-stdlib > Always refer to a GitHub issue using the following exact syntax: bug for tooling. --- doc/manual.rst | 10 +++++++++- tests/proc/t15949.nim | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/proc/t15949.nim diff --git a/doc/manual.rst b/doc/manual.rst index 1371dba17..001402036 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3603,9 +3603,17 @@ does not provide a value for the argument. The value will be reevaluated every time the function is called. .. code-block:: nim - # b is optional with 47 as its default value + # b is optional with 47 as its default value. proc foo(a: int, b: int = 47): int +Just as the comma propagates the types from right to left until the +first parameter or until a semicolon is hit, it also propagates the +default value starting from the parameter declared with it. + +.. code-block:: nim + # Both a and b are optional with 47 as their default values. + proc foo(a, b: int = 47): int + Parameters can be declared mutable and so allow the proc to modify those arguments, by using the type modifier `var`. diff --git a/tests/proc/t15949.nim b/tests/proc/t15949.nim new file mode 100644 index 000000000..bc3fddc84 --- /dev/null +++ b/tests/proc/t15949.nim @@ -0,0 +1,20 @@ +# bug #15949 + +discard """ +errormsg: "parameter 'a' requires a type" +nimout: ''' +t15949.nim(20, 14) Error: parameter 'a' requires a type''' +""" + + +# line 10 +proc procGood(a, b = 1): (int, int) = (a, b) + +doAssert procGood() == (1, 1) +doAssert procGood(b = 3) == (1, 3) +doAssert procGood(a = 2) == (2, 1) +doAssert procGood(a = 5, b = 6) == (5, 6) + +# The type (and default value propagation breaks in the below example +# as semicolon is used instead of comma. +proc procBad(a; b = 1): (int, int) = (a, b) From f7cfc46ae17b81d9ccdc84573da00561f24ea99f Mon Sep 17 00:00:00 2001 From: David Krause Date: Wed, 3 Nov 2021 09:14:59 +0100 Subject: [PATCH 3118/4254] Added support for sending "ehlo" and receiving multiline "ehlo" response. (#19077) * Added support for sending "ehlo" and receiving multiline "ehlo" response. Signed-off-by: David Krause * fix typo Signed-off-by: David Krause * send "EHLO" first, if not supported, send "HELO" to smtp server. Signed-off-by: David Krause * fix english Signed-off-by: David Krause * add changelog entry for smtp `ehlo` Signed-off-by: David Krause * recvEhlo must not be exported Signed-off-by: David Krause --- changelog.md | 2 ++ lib/pure/smtp.nim | 33 ++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index fbda70582..1636d125f 100644 --- a/changelog.md +++ b/changelog.md @@ -7,7 +7,9 @@ ## Standard library additions and changes +## `std/smtp` +- Sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. ## Language changes diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 5ba048608..f5196ce1e 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -100,7 +100,6 @@ proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[string] {.multisync.} = ## `SMTP extensions`_. ## ## See `checkReply(reply)<#checkReply,AsyncSmtp,string>`_. - result = await smtp.sock.recvLine() if smtp.debug: echo("S:" & result) @@ -171,8 +170,7 @@ proc `$`*(msg: Message): string = result.add("\c\L") result.add(msg.msgBody) -proc newSmtp*(useSsl = false, debug = false, - sslContext: SslContext = nil): Smtp = +proc newSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): Smtp = ## Creates a new `Smtp` instance. new result result.debug = debug @@ -186,12 +184,10 @@ proc newSmtp*(useSsl = false, debug = false, else: {.error: "SMTP module compiled without SSL support".} -proc newAsyncSmtp*(useSsl = false, debug = false, - sslContext: SslContext = nil): AsyncSmtp = +proc newAsyncSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): AsyncSmtp = ## Creates a new `AsyncSmtp` instance. new result result.debug = debug - result.sock = newAsyncSocket() if useSsl: when compiledWithSsl: @@ -220,7 +216,6 @@ proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = ## would need to call when using this module. One exception to ## this is if you are implementing any ## `SMTP extensions`_. - var line = await smtp.debugRecv() if not line.startsWith(reply): await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line) @@ -230,6 +225,22 @@ proc helo*(smtp: Smtp | AsyncSmtp) {.multisync.} = await smtp.debugSend("HELO " & smtp.address & "\c\L") await smtp.checkReply("250") +proc recvEhlo(smtp: Smtp | AsyncSmtp): Future[bool] {.multisync.} = + ## Skips "250-" lines, read until "250 " found. + ## Return `true` if server supports `EHLO`, false otherwise. + while true: + var line = await smtp.sock.recvLine() + if smtp.debug: + echo("S:" & line) + if line.startsWith("250-"): continue + elif line.startsWith("250 "): return true # last line + else: return false + +proc ehlo*(smtp: Smtp | AsyncSmtp): Future[bool] {.multisync.} = + ## Sends EHLO request. + await smtp.debugSend("EHLO " & smtp.address & "\c\L") + return await smtp.recvEhlo() + proc connect*(smtp: Smtp | AsyncSmtp, address: string, port: Port) {.multisync.} = ## Establishes a connection with a SMTP server. @@ -237,7 +248,9 @@ proc connect*(smtp: Smtp | AsyncSmtp, smtp.address = address await smtp.sock.connect(address, port) await smtp.checkReply("220") - await smtp.helo() + let speaksEsmtp = await smtp.ehlo() + if not speaksEsmtp: + await smtp.helo() proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SslContext = nil) {.multisync.} = ## Put the SMTP connection in TLS (Transport Layer Security) mode. @@ -249,7 +262,9 @@ proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SslContext = nil) {.multisync getSSLContext().wrapConnectedSocket(smtp.sock, handshakeAsClient) else: sslContext.wrapConnectedSocket(smtp.sock, handshakeAsClient) - await smtp.helo() + let speaksEsmtp = await smtp.ehlo() + if not speaksEsmtp: + await smtp.helo() else: {.error: "SMTP module compiled without SSL support".} From b2edc3468cf0857b337bff09cb68649d49803ccf Mon Sep 17 00:00:00 2001 From: Constantine Molchanov Date: Wed, 3 Nov 2021 11:16:24 +0300 Subject: [PATCH 3119/4254] Use testament to check Norm test pass (#19018) * Use testament to check Norm test pass This is what I actually use to test Norm, so it's better to use it. This should not currently pass. This is expected because this is exactly the problem I want to highlight with this PR. My tests do indeed not pass at the moment. * Remove clearNimblePath from testament command. Co-authored-by: flywind --- testament/important_packages.nim | 2 +- testament/specs.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index e037cc609..fc5c808ab 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -115,7 +115,7 @@ pkg "nimterop", "nimble minitest" pkg "nimwc", "nim c nimwc.nim" pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" -pkg "norm", "nim c -r tests/sqlite/trows.nim" +pkg "norm", "testament r tests/sqlite/trows.nim" pkg "npeg", "nimble testarc" pkg "numericalnim", "nim c -r tests/test_integrate.nim" pkg "optionsutils" diff --git a/testament/specs.nim b/testament/specs.nim index 6fd0ab22d..c7e332262 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -103,7 +103,7 @@ type proc getCmd*(s: TSpec): string = if s.cmd.len == 0: - result = compilerPrefix & " $target --hints:on -d:testing --clearNimblePath --nimblePath:build/deps/pkgs $options $file" + result = compilerPrefix & " $target --hints:on -d:testing --nimblePath:build/deps/pkgs $options $file" else: result = s.cmd From f2f15e972645496f901fcfde197048de368453d6 Mon Sep 17 00:00:00 2001 From: Don-Duong Quach Date: Wed, 3 Nov 2021 08:47:31 -0700 Subject: [PATCH 3120/4254] fix for #19020, credit to @ElegantBeef (#19021) --- lib/core/macros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 806ea7e31..6dbb92875 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1611,7 +1611,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = let pragmaNode = customPragmaNode(n) for p in pragmaNode: if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp: - if p.len == 2: + if p.len == 2 or (p.len == 3 and p[1].kind == nnkSym and p[1].symKind == nskType): result = p[1] else: let def = p[0].getImpl[3] From fce89cb60a3428c61da3c7e6c2d3e6cdcb14bb3b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 7 Nov 2021 16:38:02 +0100 Subject: [PATCH 3121/4254] fixes another effect inference bug [backport:1.6] (#19100) * fixes another effect inference bug [backport:1.6] --- compiler/sempass2.nim | 3 ++ lib/pure/asyncdispatch.nim | 4 +- lib/pure/json.nim | 10 +++-- lib/system/excpt.nim | 13 ++++--- lib/system/seqs_v2.nim | 2 +- tests/effects/tnestedprocs.nim | 63 +++++++++++++++++++++++++++++++ tests/pragmas/tcompile_pragma.nim | 1 + 7 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 tests/effects/tnestedprocs.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 9a27d14fa..5624d7adb 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -851,6 +851,9 @@ proc trackCall(tracked: PEffects; n: PNode) = elif isIndirectCall(tracked, a): assumeTheWorst(tracked, n, op) gcsafeAndSideeffectCheck() + else: + if strictEffects in tracked.c.features and a.kind == nkSym and a.sym.kind in routineKinds: + propagateEffects(tracked, n, a.sym) else: mergeRaises(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index e15fb0851..c924d0a3d 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -733,7 +733,7 @@ when defined(windows) or defined(nimdoc): proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}, inheritable = defined(nimInheritHandles)): - owned(Future[tuple[address: string, client: AsyncFD]]) = + owned(Future[tuple[address: string, client: AsyncFD]]) {.gcsafe.} = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection and the remote address of the client. ## The future will complete when the connection is successfully accepted. @@ -800,7 +800,7 @@ when defined(windows) or defined(nimdoc): var ol = newCustom() ol.data = CompletionData(fd: socket, cb: - proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = + proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) {.gcsafe.} = if not retFuture.finished: if errcode == OSErrorCode(-1): completeAccept() diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 85c3393b2..c831bf85d 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -437,7 +437,7 @@ macro `%*`*(x: untyped): untyped = ## `%` for every element. result = toJsonImpl(x) -proc `==`*(a, b: JsonNode): bool = +proc `==`*(a, b: JsonNode): bool {.noSideEffect.} = ## Check two nodes for equality if a.isNil: if b.isNil: return true @@ -464,12 +464,16 @@ proc `==`*(a, b: JsonNode): bool = if a.fields.len != b.fields.len: return false for key, val in a.fields: if not b.fields.hasKey(key): return false - if b.fields[key] != val: return false + when defined(nimHasEffectsOf): + {.noSideEffect.}: + if b.fields[key] != val: return false + else: + if b.fields[key] != val: return false result = true proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.} -proc hash*(n: JsonNode): Hash = +proc hash*(n: JsonNode): Hash {.noSideEffect.} = ## Compute the hash for a JSON node case n.kind of JArray: diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 3e520570f..a71328c14 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -354,7 +354,7 @@ var onUnhandledException*: (proc (errorMsg: string) {. ## The default is to write a stacktrace to `stderr` and then call `quit(1)`. ## Unstable API. -proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = +proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} = when hasSomeStackTrace: var buf = newStringOfCap(2000) if e.trace.len == 0: @@ -362,7 +362,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = else: var trace = $e.trace add(buf, trace) - `=destroy`(trace) + {.gcsafe.}: + `=destroy`(trace) add(buf, "Error: unhandled exception: ") add(buf, e.msg) add(buf, " [") @@ -373,7 +374,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = onUnhandledException(buf) else: showErrorMessage2(buf) - `=destroy`(buf) + {.gcsafe.}: + `=destroy`(buf) else: # ugly, but avoids heap allocations :-) template xadd(buf, s, slen) = @@ -387,7 +389,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = if e.trace.len != 0: var trace = $e.trace add(buf, trace) - `=destroy`(trace) + {.gcsafe.}: + `=destroy`(trace) add(buf, "Error: unhandled exception: ") add(buf, e.msg) add(buf, " [") @@ -398,7 +401,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = else: showErrorMessage(buf.addr, L) -proc reportUnhandledError(e: ref Exception) {.nodestroy.} = +proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} = if unhandledExceptionHook != nil: unhandledExceptionHook(e) when hostOS != "any": diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 375eef340..0ac51109e 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin q.cap = newCap result = q -proc shrink*[T](x: var seq[T]; newLen: Natural) = +proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [].} = when nimvm: setLen(x, newLen) else: diff --git a/tests/effects/tnestedprocs.nim b/tests/effects/tnestedprocs.nim new file mode 100644 index 000000000..125896d44 --- /dev/null +++ b/tests/effects/tnestedprocs.nim @@ -0,0 +1,63 @@ +discard """ + cmd: "nim check --hints:off $file" + nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects +> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2' +>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner' + +tnestedprocs.nim(45, 8) Error: 'inner' can have side effects +> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6' +>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner' + +tnestedprocs.nim(58, 41) Error: type mismatch: got but expected 'proc (){.closure, noSideEffect.}' + Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'. +''' + errormsg: "type mismatch: got but expected 'proc (){.closure, noSideEffect.}'" +""" +{.experimental: "strictEffects".} +proc outer {.noSideEffect.} = + proc inner(p: int) = + if p == 0: + outer() + + inner(4) + +outer() + +proc outer2 = + proc inner(p: int) {.noSideEffect.} = + if p == 0: + outer2() + + inner(4) + +outer2() + +proc outer3(p: int) {.noSideEffect.} = + proc inner(p: int) {.noSideEffect.} = + if p == 0: + p.outer3() + + inner(4) + +outer3(5) + +proc outer6 = + proc inner(p: int) {.noSideEffect.} = + if p == 0: + outer6() + + inner(4) + echo "bad" + +outer6() + + +proc outer4 = + proc inner(p: int) {.noSideEffect.} = + if p == 0: + let x: proc () {.noSideEffect.} = outer4 + x() + + inner(4) + +outer4() diff --git a/tests/pragmas/tcompile_pragma.nim b/tests/pragmas/tcompile_pragma.nim index 4e09a7501..5b99352dd 100644 --- a/tests/pragmas/tcompile_pragma.nim +++ b/tests/pragmas/tcompile_pragma.nim @@ -1,5 +1,6 @@ discard """ output: '''34''' + joinable: false """ {.compile("cfunction.c", "-DNUMBER_HERE=34").} From b423ab138f41c24db3b168fd30f1ecce7850a170 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 8 Nov 2021 07:21:15 +0000 Subject: [PATCH 3122/4254] Remove invalid statements about try in async docs. (#19108) --- lib/pure/asyncdispatch.nim | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index c924d0a3d..20ad60427 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -101,16 +101,9 @@ ## Handling Exceptions ## ------------------- ## -## The most reliable way to handle exceptions is to use `yield` on a future -## then check the future's `failed` property. For example: +## You can handle exceptions in the same way as in ordinary Nim code; +## by using the try statement: ## -## .. code-block:: Nim -## var future = sock.recv(100) -## yield future -## if future.failed: -## # Handle exception -## -## The `async` procedures also offer limited support for the try statement. ## ## .. code-block:: Nim ## try: @@ -119,9 +112,16 @@ ## except: ## # Handle exception ## -## Unfortunately the semantics of the try statement may not always be correct, -## and occasionally the compilation may fail altogether. -## As such it is better to use the former style when possible. +## +## +## An alternative approach to handling exceptions is to use `yield` on a future +## then check the future's `failed` property. For example: +## +## .. code-block:: Nim +## var future = sock.recv(100) +## yield future +## if future.failed: +## # Handle exception ## ## ## Discarding futures @@ -1987,4 +1987,4 @@ when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or var fdLim: RLimit if getrlimit(RLIMIT_NOFILE, fdLim) < 0: raiseOSError(osLastError()) - result = int(fdLim.rlim_cur) - 1 \ No newline at end of file + result = int(fdLim.rlim_cur) - 1 From b21eb1ed36aa068cc9b0a304742e4c81b5112304 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 8 Nov 2021 15:10:01 +0300 Subject: [PATCH 3123/4254] change os.nim doc links to new style (#19102) --- compiler/docgen.nim | 7 + doc/docgen.rst | 7 + lib/packages/docutils/dochelpers.nim | 19 +- lib/pure/includes/osenv.nim | 42 +- lib/pure/includes/oserr.nim | 21 +- lib/pure/includes/osseps.nim | 6 +- lib/pure/os.nim | 558 +++++++++++++-------------- tests/stdlib/tdochelpers.nim | 6 + 8 files changed, 345 insertions(+), 321 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 2639840d1..7ba952083 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -954,6 +954,13 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol = if kind != tkSpaces: result.generics.add(literal.nimIdentNormalize) + if k == skType: + case n[2].kind + of nkEnumTy: result.symTypeKind = "enum" + of nkObjectTy: result.symTypeKind = "object" + of nkTupleTy: result.symTypeKind = "tuple" + else: discard + proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) = if (docFlags != kForceExport) and not isVisible(d, nameNode): return let diff --git a/doc/docgen.rst b/doc/docgen.rst index 51e7102eb..48166b2c5 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -399,6 +399,13 @@ recognized fine:: no backticks: `func [][T](x: openArray[T]): T`_ escaped: `func \`[]\`[T](x: openArray[T]): T`_ +.. Note:: Types that defined as `enum`, or `object`, or `tuple` can also be + referenced with those names directly (instead of `type`):: + + type CopyFlag = enum + ... + ## Ref. `CopyFlag enum`_ + Related Options =============== diff --git a/lib/packages/docutils/dochelpers.nim b/lib/packages/docutils/dochelpers.nim index c488c4d99..8f97a7119 100644 --- a/lib/packages/docutils/dochelpers.nim +++ b/lib/packages/docutils/dochelpers.nim @@ -17,7 +17,9 @@ import rstast type LangSymbol* = object ## symbol signature in Nim - symKind*: string ## "proc", "const", etc + symKind*: string ## "proc", "const", "type", etc + symTypeKind*: string ## ""|enum|object|tuple - + ## valid only when `symKind == "type"` name*: string ## plain symbol name without any parameters generics*: string ## generic parameters (without brackets) isGroup*: bool ## is LangSymbol a group with overloads? @@ -79,7 +81,14 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol = assert linkText.kind in {rnRef, rnInner} const NimDefs = ["proc", "func", "macro", "method", "iterator", - "template", "converter", "const", "type", "var"] + "template", "converter", "const", "type", "var", + "enum", "object", "tuple"] + template resolveSymKind(x: string) = + if x in ["enum", "object", "tuple"]: + result.symKind = "type" + result.symTypeKind = x + else: + result.symKind = x type State = enum inBeginning @@ -97,7 +106,7 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol = if curIdent != "": case state of inBeginning: doAssert false, "incorrect state inBeginning" - of afterSymKind: result.symKind = curIdent + of afterSymKind: resolveSymKind curIdent of beforeSymbolName: doAssert false, "incorrect state beforeSymbolName" of atSymbolName: result.name = curIdent.nimIdentBackticksNormalize of afterSymbolName: doAssert false, "incorrect state afterSymbolName" @@ -195,7 +204,7 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol = let isPostfixSymKind = i > 0 and i == L - 1 and result.symKind == "" and s(i) in NimDefs if isPostfixSymKind: # for links like `foo proc`_ - result.symKind = s(i) + resolveSymKind s(i) else: case state of inBeginning: @@ -235,6 +244,8 @@ proc match*(generated: LangSymbol, docLink: LangSymbol): bool = result = docLink.symKind in ["proc", "func"] else: result = generated.symKind == docLink.symKind + if result and docLink.symKind == "type" and docLink.symTypeKind != "": + result = generated.symTypeKind == docLink.symTypeKind if not result: return result = generated.name == docLink.name if not result: return diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index 00a82327c..1a01ab9bc 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -56,13 +56,13 @@ when not defined(nimscript): ## ## If the variable does not exist, `""` is returned. To distinguish ## whether a variable exists or it's value is just `""`, call - ## `existsEnv(key) proc <#existsEnv,string>`_. + ## `existsEnv(key) proc`_. ## ## See also: - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ + ## * `existsEnv proc`_ + ## * `putEnv proc`_ + ## * `delEnv proc`_ + ## * `envPairs iterator`_ runnableExamples: assert getEnv("unknownEnv") == "" assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" @@ -76,10 +76,10 @@ when not defined(nimscript): ## Returns true if it exists, false otherwise. ## ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ + ## * `getEnv proc`_ + ## * `putEnv proc`_ + ## * `delEnv proc`_ + ## * `envPairs iterator`_ runnableExamples: assert not existsEnv("unknownEnv") @@ -90,10 +90,10 @@ when not defined(nimscript): ## If an error occurs, `OSError` is raised. ## ## See also: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `delEnv proc <#delEnv,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ + ## * `getEnv proc`_ + ## * `existsEnv proc`_ + ## * `delEnv proc`_ + ## * `envPairs iterator`_ when defined(windows): if key.len == 0 or '=' in key: raise newException(OSError, "invalid key, got: " & $(key, val)) @@ -108,10 +108,10 @@ when not defined(nimscript): ## If an error occurs, `OSError` is raised. ## ## See also:ven - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `envPairs iterator <#envPairs.i>`_ + ## * `getEnv proc`_ + ## * `existsEnv proc`_ + ## * `putEnv proc`_ + ## * `envPairs iterator`_ template bail = raiseOSError(osLastError(), key) when defined(windows): #[ @@ -190,10 +190,10 @@ iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = ## in the second its value. ## ## Works in native backends, nodejs and vm, like the following APIs: - ## * `getEnv proc <#getEnv,string,string>`_ - ## * `existsEnv proc <#existsEnv,string>`_ - ## * `putEnv proc <#putEnv,string,string>`_ - ## * `delEnv proc <#delEnv,string>`_ + ## * `getEnv proc`_ + ## * `existsEnv proc`_ + ## * `putEnv proc`_ + ## * `delEnv proc`_ when nimvm: for ai in envPairsImplSeq(): yield ai else: diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index e42771d52..01403fa70 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -18,7 +18,7 @@ proc `$`*(err: OSErrorCode): string {.borrow.} proc osErrorMsg*(errorCode: OSErrorCode): string = ## Converts an OS error code into a human readable string. ## - ## The error code can be retrieved using the `osLastError proc <#osLastError>`_. + ## The error code can be retrieved using the `osLastError proc`_. ## ## If conversion fails, or `errorCode` is `0` then `""` will be ## returned. @@ -28,8 +28,8 @@ proc osErrorMsg*(errorCode: OSErrorCode): string = ## message. ## ## See also: - ## * `raiseOSError proc <#raiseOSError,OSErrorCode,string>`_ - ## * `osLastError proc <#osLastError>`_ + ## * `raiseOSError proc`_ + ## * `osLastError proc`_ runnableExamples: when defined(linux): assert osErrorMsg(OSErrorCode(0)) == "" @@ -63,18 +63,17 @@ proc newOSError*( ## Creates a new `OSError exception `_. ## ## The `errorCode` will determine the - ## message, `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ will be used + ## message, `osErrorMsg proc`_ will be used ## to get this message. ## - ## The error code can be retrieved using the `osLastError proc - ## <#osLastError>`_. + ## The error code can be retrieved using the `osLastError proc`_. ## ## If the error code is `0` or an error message could not be retrieved, ## the message `unknown OS error` will be used. ## ## See also: - ## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ - ## * `osLastError proc <#osLastError>`_ + ## * `osErrorMsg proc`_ + ## * `osLastError proc`_ var e: owned(ref OSError); new(e) e.errorCode = errorCode.int32 e.msg = osErrorMsg(errorCode) @@ -90,7 +89,7 @@ proc newOSError*( proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} = ## Raises an `OSError exception `_. ## - ## Read the description of the `newOSError proc <#newOSError,OSErrorCode,string>`_ to learn + ## Read the description of the `newOSError proc`_ to learn ## how the exception object is created. raise newOSError(errorCode, additionalInfo) @@ -109,8 +108,8 @@ proc osLastError*(): OSErrorCode {.sideEffect.} = ## immediately after an OS call fails. On POSIX systems this is not a problem. ## ## See also: - ## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ - ## * `raiseOSError proc <#raiseOSError,OSErrorCode,string>`_ + ## * `osErrorMsg proc`_ + ## * `raiseOSError proc`_ when defined(nimscript): discard elif defined(windows): diff --git a/lib/pure/includes/osseps.nim b/lib/pure/includes/osseps.nim index 10c85047b..1ea587e3c 100644 --- a/lib/pure/includes/osseps.nim +++ b/lib/pure/includes/osseps.nim @@ -37,9 +37,9 @@ const when doslikeFileSystem: '/' else: DirSep ## An alternative character used by the operating system to separate - ## pathname components, or the same as `DirSep <#DirSep>`_ if only one separator + ## pathname components, or the same as DirSep_ if only one separator ## character exists. This is set to `'/'` on Windows systems - ## where `DirSep <#DirSep>`_ is a backslash (`'\\'`). + ## where DirSep_ is a backslash (`'\\'`). PathSep* = when defined(macos) or defined(RISCOS): ',' @@ -55,7 +55,7 @@ const defined(PalmOS) or defined(MorphOS): false else: true ## True if the file system is case sensitive, false otherwise. Used by - ## `cmpPaths proc <#cmpPaths,string,string>`_ to compare filenames properly. + ## `cmpPaths proc`_ to compare filenames properly. ExeExt* = when doslikeFileSystem: "exe" diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 5320aa87e..513e09b48 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -21,9 +21,9 @@ runnableExamples: ## **See also:** ## * `osproc module `_ for process communication beyond -## `execShellCmd proc <#execShellCmd,string>`_ +## `execShellCmd proc`_ ## * `parseopt module `_ for command-line parser beyond -## `parseCmdLine proc <#parseCmdLine,string>`_ +## `parseCmdLine proc`_ ## * `uri module `_ ## * `distros module `_ ## * `dynlib module `_ @@ -152,9 +152,9 @@ proc joinPath*(head, tail: string): string {. ## head has one). ## ## See also: - ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ - ## * `/ proc <#/,string,string>`_ - ## * `splitPath proc <#splitPath,string>`_ + ## * `joinPath(parts: varargs[string]) proc`_ + ## * `/ proc`_ + ## * `splitPath proc`_ ## * `uri.combine proc `_ ## * `uri./ proc `_ runnableExamples: @@ -189,17 +189,17 @@ proc joinPath*(head, tail: string): string {. proc joinPath*(parts: varargs[string]): string {.noSideEffect, rtl, extern: "nos$1OpenArray".} = - ## The same as `joinPath(head, tail) proc <#joinPath,string,string>`_, + ## The same as `joinPath(head, tail) proc`_, ## but works with any number of directory parts. ## ## You need to pass at least one element or the proc ## will assert in debug builds and crash on release builds. ## ## See also: - ## * `joinPath(head, tail) proc <#joinPath,string,string>`_ - ## * `/ proc <#/,string,string>`_ - ## * `/../ proc <#/../,string,string>`_ - ## * `splitPath proc <#splitPath,string>`_ + ## * `joinPath(head, tail) proc`_ + ## * `/ proc`_ + ## * `/../ proc`_ + ## * `splitPath proc`_ runnableExamples: when defined(posix): assert joinPath("a") == "a" @@ -214,13 +214,13 @@ proc joinPath*(parts: varargs[string]): string {.noSideEffect, joinPathImpl(result, state, parts[i]) proc `/`*(head, tail: string): string {.noSideEffect, inline.} = - ## The same as `joinPath(head, tail) proc <#joinPath,string,string>`_. + ## The same as `joinPath(head, tail) proc`_. ## ## See also: - ## * `/../ proc <#/../,string,string>`_ - ## * `joinPath(head, tail) proc <#joinPath,string,string>`_ - ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ - ## * `splitPath proc <#splitPath,string>`_ + ## * `/../ proc`_ + ## * `joinPath(head, tail) proc`_ + ## * `joinPath(parts: varargs[string]) proc`_ + ## * `splitPath proc`_ ## * `uri.combine proc `_ ## * `uri./ proc `_ runnableExamples: @@ -239,11 +239,11 @@ proc splitPath*(path: string): tuple[head, tail: string] {. ## ``head / tail == path`` (except for edge cases like "/usr"). ## ## See also: - ## * `joinPath(head, tail) proc <#joinPath,string,string>`_ - ## * `joinPath(varargs) proc <#joinPath,varargs[string]>`_ - ## * `/ proc <#/,string,string>`_ - ## * `/../ proc <#/../,string,string>`_ - ## * `relativePath proc <#relativePath,string,string>`_ + ## * `joinPath(head, tail) proc`_ + ## * `joinPath(parts: varargs[string]) proc`_ + ## * `/ proc`_ + ## * `/../ proc`_ + ## * `relativePath proc`_ runnableExamples: assert splitPath("usr/local/bin") == ("usr/local", "bin") assert splitPath("usr/local/bin/") == ("usr/local/bin", "") @@ -366,7 +366,7 @@ proc relativePath*(path, base: string, sep = DirSep): string {. rtl, extern: "nos$1".} = ## Converts `path` to a path relative to `base`. ## - ## The `sep` (default: `DirSep <#DirSep>`_) is used for the path normalizations, + ## The `sep` (default: DirSep_) is used for the path normalizations, ## this can be useful to ensure the relative path only contains `'/'` ## so that it can be used for URL constructions. ## @@ -375,9 +375,9 @@ proc relativePath*(path, base: string, sep = DirSep): string {. ## That means an absolute path can be returned. ## ## See also: - ## * `splitPath proc <#splitPath,string>`_ - ## * `parentDir proc <#parentDir,string>`_ - ## * `tailDir proc <#tailDir,string>`_ + ## * `splitPath proc`_ + ## * `parentDir proc`_ + ## * `tailDir proc`_ runnableExamples: assert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim" assert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim" @@ -476,14 +476,13 @@ proc parentDir*(path: string): string {. ## ## This is similar to ``splitPath(path).head`` when ``path`` doesn't end ## in a dir separator, but also takes care of path normalizations. - ## The remainder can be obtained with `lastPathPart(path) proc - ## <#lastPathPart,string>`_. + ## The remainder can be obtained with `lastPathPart(path) proc`_. ## ## See also: - ## * `relativePath proc <#relativePath,string,string>`_ - ## * `splitPath proc <#splitPath,string>`_ - ## * `tailDir proc <#tailDir,string>`_ - ## * `parentDirs iterator <#parentDirs.i,string>`_ + ## * `relativePath proc`_ + ## * `splitPath proc`_ + ## * `tailDir proc`_ + ## * `parentDirs iterator`_ runnableExamples: assert parentDir("") == "" when defined(posix): @@ -511,9 +510,9 @@ proc tailDir*(path: string): string {. ## Returns the tail part of `path`. ## ## See also: - ## * `relativePath proc <#relativePath,string,string>`_ - ## * `splitPath proc <#splitPath,string>`_ - ## * `parentDir proc <#parentDir,string>`_ + ## * `relativePath proc`_ + ## * `splitPath proc`_ + ## * `parentDir proc`_ runnableExamples: assert tailDir("/bin") == "bin" assert tailDir("bin") == "" @@ -556,7 +555,7 @@ iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string = ## only the directories appearing in the relative path. ## ## See also: - ## * `parentDir proc <#parentDir,string>`_ + ## * `parentDir proc`_ ## runnableExamples: let g = "a/b/c" @@ -599,8 +598,8 @@ proc `/../`*(head, tail: string): string {.noSideEffect.} = ## directory. Then ``head / tail`` is performed instead. ## ## See also: - ## * `/ proc <#/,string,string>`_ - ## * `parentDir proc <#parentDir,string>`_ + ## * `/ proc`_ + ## * `parentDir proc`_ runnableExamples: when defined(posix): assert "a/b/c" /../ "d/e" == "a/b/d/e" @@ -621,11 +620,11 @@ proc searchExtPos*(path: string): int = ## of extension. Returns -1 otherwise. ## ## See also: - ## * `splitFile proc <#splitFile,string>`_ - ## * `extractFilename proc <#extractFilename,string>`_ - ## * `lastPathPart proc <#lastPathPart,string>`_ - ## * `changeFileExt proc <#changeFileExt,string,string>`_ - ## * `addFileExt proc <#addFileExt,string,string>`_ + ## * `splitFile proc`_ + ## * `extractFilename proc`_ + ## * `lastPathPart proc`_ + ## * `changeFileExt proc`_ + ## * `addFileExt proc`_ runnableExamples: assert searchExtPos("a/b/c") == -1 assert searchExtPos("c.nim") == 1 @@ -645,7 +644,7 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {. noSideEffect, rtl, extern: "nos$1".} = ## Splits a filename into `(dir, name, extension)` tuple. ## - ## `dir` does not end in `DirSep <#DirSep>`_ unless it's `/`. + ## `dir` does not end in DirSep_ unless it's `/`. ## `extension` includes the leading dot. ## ## If `path` has no extension, `ext` is the empty string. @@ -653,11 +652,11 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {. ## If `path` has no filename component, `name` and `ext` are empty strings. ## ## See also: - ## * `searchExtPos proc <#searchExtPos,string>`_ - ## * `extractFilename proc <#extractFilename,string>`_ - ## * `lastPathPart proc <#lastPathPart,string>`_ - ## * `changeFileExt proc <#changeFileExt,string,string>`_ - ## * `addFileExt proc <#addFileExt,string,string>`_ + ## * `searchExtPos proc`_ + ## * `extractFilename proc`_ + ## * `lastPathPart proc`_ + ## * `changeFileExt proc`_ + ## * `addFileExt proc`_ runnableExamples: var (dir, name, ext) = splitFile("usr/local/nimc.html") assert dir == "usr/local" @@ -698,15 +697,14 @@ proc extractFilename*(path: string): string {. noSideEffect, rtl, extern: "nos$1".} = ## Extracts the filename of a given `path`. ## - ## This is the same as ``name & ext`` from `splitFile(path) proc - ## <#splitFile,string>`_. + ## This is the same as ``name & ext`` from `splitFile(path) proc`_. ## ## See also: - ## * `searchExtPos proc <#searchExtPos,string>`_ - ## * `splitFile proc <#splitFile,string>`_ - ## * `lastPathPart proc <#lastPathPart,string>`_ - ## * `changeFileExt proc <#changeFileExt,string,string>`_ - ## * `addFileExt proc <#addFileExt,string,string>`_ + ## * `searchExtPos proc`_ + ## * `splitFile proc`_ + ## * `lastPathPart proc`_ + ## * `changeFileExt proc`_ + ## * `addFileExt proc`_ runnableExamples: assert extractFilename("foo/bar/") == "" assert extractFilename("foo/bar") == "bar" @@ -719,15 +717,15 @@ proc extractFilename*(path: string): string {. proc lastPathPart*(path: string): string {. noSideEffect, rtl, extern: "nos$1".} = - ## Like `extractFilename proc <#extractFilename,string>`_, but ignores + ## Like `extractFilename proc`_, but ignores ## trailing dir separator; aka: `baseName`:idx: in some other languages. ## ## See also: - ## * `searchExtPos proc <#searchExtPos,string>`_ - ## * `splitFile proc <#splitFile,string>`_ - ## * `extractFilename proc <#extractFilename,string>`_ - ## * `changeFileExt proc <#changeFileExt,string,string>`_ - ## * `addFileExt proc <#addFileExt,string,string>`_ + ## * `searchExtPos proc`_ + ## * `splitFile proc`_ + ## * `extractFilename proc`_ + ## * `changeFileExt proc`_ + ## * `addFileExt proc`_ runnableExamples: assert lastPathPart("foo/bar/") == "bar" assert lastPathPart("foo/bar") == "bar" @@ -747,11 +745,11 @@ proc changeFileExt*(filename, ext: string): string {. ## of none such beast.) ## ## See also: - ## * `searchExtPos proc <#searchExtPos,string>`_ - ## * `splitFile proc <#splitFile,string>`_ - ## * `extractFilename proc <#extractFilename,string>`_ - ## * `lastPathPart proc <#lastPathPart,string>`_ - ## * `addFileExt proc <#addFileExt,string,string>`_ + ## * `searchExtPos proc`_ + ## * `splitFile proc`_ + ## * `extractFilename proc`_ + ## * `lastPathPart proc`_ + ## * `addFileExt proc`_ runnableExamples: assert changeFileExt("foo.bar", "baz") == "foo.baz" assert changeFileExt("foo.bar", "") == "foo" @@ -771,11 +769,11 @@ proc addFileExt*(filename, ext: string): string {. ## (Although I know of none such beast.) ## ## See also: - ## * `searchExtPos proc <#searchExtPos,string>`_ - ## * `splitFile proc <#splitFile,string>`_ - ## * `extractFilename proc <#extractFilename,string>`_ - ## * `lastPathPart proc <#lastPathPart,string>`_ - ## * `changeFileExt proc <#changeFileExt,string,string>`_ + ## * `searchExtPos proc`_ + ## * `splitFile proc`_ + ## * `extractFilename proc`_ + ## * `lastPathPart proc`_ + ## * `changeFileExt proc`_ runnableExamples: assert addFileExt("foo.bar", "baz") == "foo.bar" assert addFileExt("foo.bar", "") == "foo.bar" @@ -875,15 +873,15 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the home directory of the current user. ## - ## This proc is wrapped by the `expandTilde proc <#expandTilde,string>`_ + ## This proc is wrapped by the `expandTilde proc`_ ## for the convenience of processing paths coming from user configuration files. ## ## See also: - ## * `getConfigDir proc <#getConfigDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `expandTilde proc <#expandTilde,string>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getConfigDir proc`_ + ## * `getTempDir proc`_ + ## * `expandTilde proc`_ + ## * `getCurrentDir proc`_ + ## * `setCurrentDir proc`_ runnableExamples: assert getHomeDir() == expandTilde("~") @@ -903,11 +901,11 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## returned string: `\\` on Windows and `/` on all other OSs. ## ## See also: - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `expandTilde proc <#expandTilde,string>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getHomeDir proc`_ + ## * `getTempDir proc`_ + ## * `expandTilde proc`_ + ## * `getCurrentDir proc`_ + ## * `setCurrentDir proc`_ when defined(windows): result = getEnv("APPDATA") else: @@ -927,9 +925,9 @@ proc getCacheDir*(): string = ## * On other platforms: `getEnv("XDG_CACHE_HOME", getEnv("HOME") / ".cache")` ## ## **See also:** - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `getConfigDir proc <#getConfigDir>`_ + ## * `getHomeDir proc`_ + ## * `getTempDir proc`_ + ## * `getConfigDir proc`_ # follows https://crates.io/crates/platform-dirs when defined(windows): result = getEnv("LOCALAPPDATA") @@ -985,11 +983,11 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", ## **Note:** This proc does not check whether the returned path exists. ## ## See also: - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getConfigDir proc <#getConfigDir>`_ - ## * `expandTilde proc <#expandTilde,string>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getHomeDir proc`_ + ## * `getConfigDir proc`_ + ## * `expandTilde proc`_ + ## * `getCurrentDir proc`_ + ## * `setCurrentDir proc`_ const tempDirDefault = "/tmp" when defined(tempDir): const tempDir {.strdefine.}: string = tempDirDefault @@ -1015,17 +1013,17 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", proc expandTilde*(path: string): string {. tags: [ReadEnvEffect, ReadIOEffect].} = ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing - ## ``~`` with `getHomeDir() <#getHomeDir>`_ (otherwise returns ``path`` unmodified). + ## ``~`` with `getHomeDir()`_ (otherwise returns ``path`` unmodified). ## ## Windows: this is still supported despite the Windows platform not having this ## convention; also, both ``~/`` and ``~\`` are handled. ## ## See also: - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getConfigDir proc <#getConfigDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getHomeDir proc`_ + ## * `getConfigDir proc`_ + ## * `getTempDir proc`_ + ## * `getCurrentDir proc`_ + ## * `setCurrentDir proc`_ runnableExamples: assert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg" assert expandTilde("~/foo/bar") == getHomeDir() / "foo/bar" @@ -1089,9 +1087,8 @@ when defined(windows) or defined(posix) or defined(nintendoswitch): proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = ## Quote ``s``, so it can be safely passed to shell. ## - ## When on Windows, it calls `quoteShellWindows proc - ## <#quoteShellWindows,string>`_. Otherwise, calls `quoteShellPosix proc - ## <#quoteShellPosix,string>`_. + ## When on Windows, it calls `quoteShellWindows proc`_. + ## Otherwise, calls `quoteShellPosix proc`_. when defined(windows): result = quoteShellWindows(s) else: @@ -1158,8 +1155,8 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", ## Directories, device files, named pipes and sockets return false. ## ## See also: - ## * `dirExists proc <#dirExists,string>`_ - ## * `symlinkExists proc <#symlinkExists,string>`_ + ## * `dirExists proc`_ + ## * `symlinkExists proc`_ when defined(windows): when useWinUnicode: wrapUnary(a, getFileAttributesW, filename) @@ -1177,8 +1174,8 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect] ## is returned. Follows symlinks. ## ## See also: - ## * `fileExists proc <#fileExists,string>`_ - ## * `symlinkExists proc <#symlinkExists,string>`_ + ## * `fileExists proc`_ + ## * `symlinkExists proc`_ when defined(windows): when useWinUnicode: wrapUnary(a, getFileAttributesW, dir) @@ -1197,8 +1194,8 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", ## regardless of whether the link points to a directory or file. ## ## See also: - ## * `fileExists proc <#fileExists,string>`_ - ## * `dirExists proc <#dirExists,string>`_ + ## * `fileExists proc`_ + ## * `dirExists proc`_ when defined(windows): when useWinUnicode: wrapUnary(a, getFileAttributesW, link) @@ -1228,7 +1225,7 @@ proc findExe*(exe: string, followSymlinks: bool = true; ## in directories listed in the ``PATH`` environment variable. ## ## Returns `""` if the `exe` cannot be found. `exe` - ## is added the `ExeExts <#ExeExts>`_ file extensions if it has none. + ## is added the `ExeExts`_ file extensions if it has none. ## ## If the system supports symlinks it also resolves them until it ## meets the actual file. This behavior can be disabled if desired @@ -1283,9 +1280,9 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", ## Returns the `file`'s last modification time. ## ## See also: - ## * `getLastAccessTime proc <#getLastAccessTime,string>`_ - ## * `getCreationTime proc <#getCreationTime,string>`_ - ## * `fileNewer proc <#fileNewer,string,string>`_ + ## * `getLastAccessTime proc`_ + ## * `getCreationTime proc`_ + ## * `fileNewer proc`_ when defined(posix): var res: Stat if stat(file, res) < 0'i32: raiseOSError(osLastError(), file) @@ -1301,9 +1298,9 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeir ## Returns the `file`'s last read or write access time. ## ## See also: - ## * `getLastModificationTime proc <#getLastModificationTime,string>`_ - ## * `getCreationTime proc <#getCreationTime,string>`_ - ## * `fileNewer proc <#fileNewer,string,string>`_ + ## * `getLastModificationTime proc`_ + ## * `getCreationTime proc`_ + ## * `fileNewer proc`_ when defined(posix): var res: Stat if stat(file, res) < 0'i32: raiseOSError(osLastError(), file) @@ -1323,9 +1320,9 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdT ## `here `_ for details. ## ## See also: - ## * `getLastModificationTime proc <#getLastModificationTime,string>`_ - ## * `getLastAccessTime proc <#getLastAccessTime,string>`_ - ## * `fileNewer proc <#fileNewer,string,string>`_ + ## * `getLastModificationTime proc`_ + ## * `getLastAccessTime proc`_ + ## * `fileNewer proc`_ when defined(posix): var res: Stat if stat(file, res) < 0'i32: raiseOSError(osLastError(), file) @@ -1342,9 +1339,9 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noWeirdTarget.} = ## modification time is later than `b`'s. ## ## See also: - ## * `getLastModificationTime proc <#getLastModificationTime,string>`_ - ## * `getLastAccessTime proc <#getLastAccessTime,string>`_ - ## * `getCreationTime proc <#getCreationTime,string>`_ + ## * `getLastModificationTime proc`_ + ## * `getLastAccessTime proc`_ + ## * `getCreationTime proc`_ when defined(posix): # If we don't have access to nanosecond resolution, use '>=' when not StatHasNanoseconds: @@ -1362,10 +1359,10 @@ when not defined(nimscript): ## So the path returned by this proc is determined at run time. ## ## See also: - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getConfigDir proc <#getConfigDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `setCurrentDir proc <#setCurrentDir,string>`_ + ## * `getHomeDir proc`_ + ## * `getConfigDir proc`_ + ## * `getTempDir proc`_ + ## * `setCurrentDir proc`_ ## * `currentSourcePath template `_ ## * `getProjectPath proc `_ when defined(nodejs): @@ -1421,10 +1418,10 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} = ## is raised if `newDir` cannot been set. ## ## See also: - ## * `getHomeDir proc <#getHomeDir>`_ - ## * `getConfigDir proc <#getConfigDir>`_ - ## * `getTempDir proc <#getTempDir>`_ - ## * `getCurrentDir proc <#getCurrentDir>`_ + ## * `getHomeDir proc`_ + ## * `getConfigDir proc`_ + ## * `getTempDir proc`_ + ## * `getCurrentDir proc`_ when defined(windows): when useWinUnicode: if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: @@ -1441,8 +1438,8 @@ proc absolutePath*(path: string, root = getCurrentDir()): string = ## If `path` is absolute, return it, ignoring `root`. ## ## See also: - ## * `normalizedPath proc <#normalizedPath,string>`_ - ## * `normalizePath proc <#normalizePath,string>`_ + ## * `normalizedPath proc`_ + ## * `normalizePath proc`_ runnableExamples: assert absolutePath("a") == getCurrentDir() / "a" @@ -1479,9 +1476,9 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## Triple dot is not handled. ## ## See also: - ## * `absolutePath proc <#absolutePath,string>`_ - ## * `normalizedPath proc <#normalizedPath,string>`_ for outplace version - ## * `normalizeExe proc <#normalizeExe,string>`_ + ## * `absolutePath proc`_ + ## * `normalizedPath proc`_ for outplace version + ## * `normalizeExe proc`_ runnableExamples: when defined(posix): var a = "a///b//..//c///d" @@ -1522,8 +1519,8 @@ proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} = ## Returns a normalized path for the current OS. ## ## See also: - ## * `absolutePath proc <#absolutePath,string>`_ - ## * `normalizePath proc <#normalizePath,string>`_ for the in-place version + ## * `absolutePath proc`_ + ## * `normalizePath proc`_ for the in-place version runnableExamples: when defined(posix): assert normalizedPath("a///b//..//c///d") == "a/c/d" @@ -1561,7 +1558,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", ## sym-linked paths to the same file or directory. ## ## See also: - ## * `sameFileContent proc <#sameFileContent,string,string>`_ + ## * `sameFileContent proc`_ when defined(windows): var success = true var f1 = openHandle(path1) @@ -1598,9 +1595,9 @@ type FilePermission* = enum ## File access permission, modelled after UNIX. ## ## See also: - ## * `getFilePermissions <#getFilePermissions,string>`_ - ## * `setFilePermissions <#setFilePermissions,string,set[FilePermission]>`_ - ## * `FileInfo object <#FileInfo>`_ + ## * `getFilePermissions`_ + ## * `setFilePermissions`_ + ## * `FileInfo object`_ fpUserExec, ## execute access for the file owner fpUserWrite, ## write access for the file owner fpUserRead, ## read access for the file owner @@ -1620,8 +1617,8 @@ proc getFilePermissions*(filename: string): set[FilePermission] {. ## permission is available in any case. ## ## See also: - ## * `setFilePermissions proc <#setFilePermissions,string,set[FilePermission]>`_ - ## * `FilePermission enum <#FilePermission>`_ + ## * `setFilePermissions proc`_ + ## * `FilePermission enum`_ when defined(posix): var a: Stat if stat(filename, a) < 0'i32: raiseOSError(osLastError(), filename) @@ -1666,8 +1663,8 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission], ## ``fpUserWrite`` permission. ## ## See also: - ## * `getFilePermissions <#getFilePermissions,string>`_ - ## * `FilePermission enum <#FilePermission>`_ + ## * `getFilePermissions proc`_ + ## * `FilePermission enum`_ when defined(posix): var p = 0.Mode if fpUserRead in permissions: p = p or S_IRUSR.Mode @@ -1744,8 +1741,8 @@ proc createSymlink*(src, dest: string) {.noWeirdTarget.} = ## of symlinks to root users (administrators) or users with developper mode enabled. ## ## See also: - ## * `createHardlink proc <#createHardlink,string,string>`_ - ## * `expandSymlink proc <#expandSymlink,string>`_ + ## * `createHardlink proc`_ + ## * `expandSymlink proc`_ when defined(windows): const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2 @@ -1769,7 +1766,7 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} = ## On Windows this is a noop, `symlinkPath` is simply returned. ## ## See also: - ## * `createSymlink proc <#createSymlink,string,string>`_ + ## * `createSymlink proc`_ when defined(windows): result = symlinkPath else: @@ -1823,11 +1820,11 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl, ## copy the source file's attributes into dest. ## ## On other platforms you need - ## to use `getFilePermissions <#getFilePermissions,string>`_ and - ## `setFilePermissions <#setFilePermissions,string,set[FilePermission]>`_ + ## to use `getFilePermissions`_ and + ## `setFilePermissions`_ ## procs ## to copy them by hand (or use the convenience `copyFileWithPermissions - ## proc <#copyFileWithPermissions,string,string>`_), + ## proc`_), ## otherwise `dest` will inherit the default permissions of a newly ## created file for the user. ## @@ -1838,12 +1835,12 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl, ## `-d:nimLegacyCopyFile` is used. ## ## See also: - ## * `CopyFlag enum <#CopyFlag>`_ - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ - ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ - ## * `removeFile proc <#removeFile,string>`_ - ## * `moveFile proc <#moveFile,string,string>`_ + ## * `CopyFlag enum`_ + ## * `copyDir proc`_ + ## * `copyFileWithPermissions proc`_ + ## * `tryRemoveFile proc`_ + ## * `removeFile proc`_ + ## * `moveFile proc`_ doAssert card(copyFlagSymlink * options) == 1, "There should be exactly " & "one cfSymlink* in options" @@ -1908,8 +1905,8 @@ proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow}) ## ignored on Windows: symlinks are skipped. ## ## See also: - ## * `CopyFlag enum <#CopyFlag>`_ - ## * `copyFile proc <#copyDir,string,string>`_ + ## * `CopyFlag enum`_ + ## * `copyFile proc`_ if dir.len == 0: # treating "" as "." is error prone raise newException(ValueError, "dest is empty") copyFile(source, dir / source.lastPathPart, options) @@ -1942,10 +1939,10 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE ## On Windows, ignores the read-only attribute. ## ## See also: - ## * `copyFile proc <#copyFile,string,string>`_ - ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ - ## * `removeFile proc <#removeFile,string>`_ - ## * `moveFile proc <#moveFile,string,string>`_ + ## * `copyFile proc`_ + ## * `copyFileWithPermissions proc`_ + ## * `removeFile proc`_ + ## * `moveFile proc`_ result = true when defined(windows): when useWinUnicode: @@ -1974,11 +1971,11 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n ## On Windows, ignores the read-only attribute. ## ## See also: - ## * `removeDir proc <#removeDir,string>`_ - ## * `copyFile proc <#copyFile,string,string>`_ - ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ - ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ - ## * `moveFile proc <#moveFile,string,string>`_ + ## * `removeDir proc`_ + ## * `copyFile proc`_ + ## * `copyFileWithPermissions proc`_ + ## * `tryRemoveFile proc`_ + ## * `moveFile proc`_ if not tryRemoveFile(file): raiseOSError(osLastError(), file) @@ -2022,11 +2019,11 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", ## Can be used to `rename files`:idx:. ## ## See also: - ## * `moveDir proc <#moveDir,string,string>`_ - ## * `copyFile proc <#copyFile,string,string>`_ - ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ - ## * `removeFile proc <#removeFile,string>`_ - ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ + ## * `moveDir proc`_ + ## * `copyFile proc`_ + ## * `copyFileWithPermissions proc`_ + ## * `removeFile proc`_ + ## * `tryRemoveFile proc`_ if not tryMoveFSObject(source, dest, isDir = false): when defined(windows): @@ -2135,10 +2132,10 @@ iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noWeirdT ## notation is supported. ## ## See also: - ## * `walkFiles iterator <#walkFiles.i,string>`_ - ## * `walkDirs iterator <#walkDirs.i,string>`_ - ## * `walkDir iterator <#walkDir.i,string>`_ - ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + ## * `walkFiles iterator`_ + ## * `walkDirs iterator`_ + ## * `walkDir iterator`_ + ## * `walkDirRec iterator`_ runnableExamples: import std/sequtils let paths = toSeq(walkPattern("lib/pure/*")) # works on Windows too @@ -2154,10 +2151,10 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTar ## notation is supported. ## ## See also: - ## * `walkPattern iterator <#walkPattern.i,string>`_ - ## * `walkDirs iterator <#walkDirs.i,string>`_ - ## * `walkDir iterator <#walkDir.i,string>`_ - ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + ## * `walkPattern iterator`_ + ## * `walkDirs iterator`_ + ## * `walkDir iterator`_ + ## * `walkDirRec iterator`_ runnableExamples: import std/sequtils assert "lib/pure/os.nim".unixToNativePath in toSeq(walkFiles("lib/pure/*.nim")) # works on Windows too @@ -2171,10 +2168,10 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarg ## notation is supported. ## ## See also: - ## * `walkPattern iterator <#walkPattern.i,string>`_ - ## * `walkFiles iterator <#walkFiles.i,string>`_ - ## * `walkDir iterator <#walkDir.i,string>`_ - ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + ## * `walkPattern iterator`_ + ## * `walkFiles iterator`_ + ## * `walkDir iterator`_ + ## * `walkDirRec iterator`_ runnableExamples: import std/sequtils let paths = toSeq(walkDirs("lib/pure/*")) # works on Windows too @@ -2235,15 +2232,15 @@ type PathComponent* = enum ## Enumeration specifying a path component. ## ## See also: - ## * `walkDirRec iterator <#walkDirRec.i,string>`_ - ## * `FileInfo object <#FileInfo>`_ + ## * `walkDirRec iterator`_ + ## * `FileInfo object`_ pcFile, ## path refers to a file pcLinkToFile, ## path refers to a symbolic link to a file pcDir, ## path refers to a directory pcLinkToDir ## path refers to a symbolic link to a directory proc getCurrentCompilerExe*(): string {.compileTime.} = discard - ## This is `getAppFilename() <#getAppFilename>`_ at compile time. + ## This is `getAppFilename()`_ at compile time. ## ## Can be used to retrieve the currently executing ## Nim compiler from a Nim or nimscript program, or the nimble binary @@ -2291,10 +2288,10 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): assert collect(for k in walkDir("dirA"): k.path).join(" ") == "dirA/dirB dirA/dirC dirA/fileA2.txt dirA/fileA1.txt" ## See also: - ## * `walkPattern iterator <#walkPattern.i,string>`_ - ## * `walkFiles iterator <#walkFiles.i,string>`_ - ## * `walkDirs iterator <#walkDirs.i,string>`_ - ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + ## * `walkPattern iterator`_ + ## * `walkFiles iterator`_ + ## * `walkDirs iterator`_ + ## * `walkDirRec iterator`_ when nimvm: for k, v in items(staticWalkDir(dir, relative)): @@ -2401,10 +2398,10 @@ iterator walkDirRec*(dir: string, ## ## ## See also: - ## * `walkPattern iterator <#walkPattern.i,string>`_ - ## * `walkFiles iterator <#walkFiles.i,string>`_ - ## * `walkDirs iterator <#walkDirs.i,string>`_ - ## * `walkDir iterator <#walkDir.i,string>`_ + ## * `walkPattern iterator`_ + ## * `walkFiles iterator`_ + ## * `walkDirs iterator`_ + ## * `walkDir iterator`_ var stack = @[""] var checkDir = checkDir @@ -2444,13 +2441,13 @@ proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ ## existed in the first place, unless `checkDir` = true. ## ## See also: - ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ - ## * `removeFile proc <#removeFile,string>`_ - ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ - ## * `createDir proc <#createDir,string>`_ - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ - ## * `moveDir proc <#moveDir,string,string>`_ + ## * `tryRemoveFile proc`_ + ## * `removeFile proc`_ + ## * `existsOrCreateDir proc`_ + ## * `createDir proc`_ + ## * `copyDir proc`_ + ## * `copyDirWithPermissions proc`_ + ## * `moveDir proc`_ for kind, path in walkDir(dir, checkDir = checkDir): case kind of pcFile, pcLinkToFile, pcLinkToDir: removeFile(path) @@ -2512,11 +2509,11 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", ## Returns `true` if the directory already exists, and `false` otherwise. ## ## See also: - ## * `removeDir proc <#removeDir,string>`_ - ## * `createDir proc <#createDir,string>`_ - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ - ## * `moveDir proc <#moveDir,string,string>`_ + ## * `removeDir proc`_ + ## * `createDir proc`_ + ## * `copyDir proc`_ + ## * `copyDirWithPermissions proc`_ + ## * `moveDir proc`_ result = not rawCreateDir(dir) if result: # path already exists - need to check that it is indeed a directory @@ -2534,11 +2531,11 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", ## most usages this does not indicate an error. ## ## See also: - ## * `removeDir proc <#removeDir,string>`_ - ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ - ## * `moveDir proc <#moveDir,string,string>`_ + ## * `removeDir proc`_ + ## * `existsOrCreateDir proc`_ + ## * `copyDir proc`_ + ## * `copyDirWithPermissions proc`_ + ## * `moveDir proc`_ var omitNext = false when doslikeFileSystem: omitNext = isAbsolute(dir) @@ -2568,17 +2565,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", ## ## On other platforms created files and directories will inherit the ## default permissions of a newly created file/directory for the user. - ## Use `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## Use `copyDirWithPermissions proc`_ ## to preserve attributes recursively on these platforms. ## ## See also: - ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ - ## * `copyFile proc <#copyFile,string,string>`_ - ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ - ## * `removeDir proc <#removeDir,string>`_ - ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ - ## * `createDir proc <#createDir,string>`_ - ## * `moveDir proc <#moveDir,string,string>`_ + ## * `copyDirWithPermissions proc`_ + ## * `copyFile proc`_ + ## * `copyFileWithPermissions proc`_ + ## * `removeDir proc`_ + ## * `existsOrCreateDir proc`_ + ## * `createDir proc`_ + ## * `moveDir proc`_ createDir(dest) for kind, path in walkDir(source): var noSource = splitPath(path).tail @@ -2596,12 +2593,12 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWei ## If this fails, `OSError` is raised. ## ## See also: - ## * `moveFile proc <#moveFile,string,string>`_ - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ - ## * `removeDir proc <#removeDir,string>`_ - ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ - ## * `createDir proc <#createDir,string>`_ + ## * `moveFile proc`_ + ## * `copyDir proc`_ + ## * `copyDirWithPermissions proc`_ + ## * `removeDir proc`_ + ## * `existsOrCreateDir proc`_ + ## * `createDir proc`_ if not tryMoveFSObject(source, dest, isDir = true): # Fallback to copy & del copyDir(source, dest) @@ -2615,7 +2612,7 @@ proc createHardlink*(src, dest: string) {.noWeirdTarget.} = ## root users (administrators). ## ## See also: - ## * `createSymlink proc <#createSymlink,string,string>`_ + ## * `createSymlink proc`_ when defined(windows): when useWinUnicode: var wSrc = newWideCString(src) @@ -2638,13 +2635,12 @@ proc copyFileWithPermissions*(source, dest: string, ## if `source` is a symlink, copies the file symlink points to. `options` is ## ignored on Windows: symlinks are skipped. ## - ## This is a wrapper proc around `copyFile <#copyFile,string,string>`_, - ## `getFilePermissions <#getFilePermissions,string>`_ and - ## `setFilePermissions<#setFilePermissions,string,set[FilePermission]>`_ + ## This is a wrapper proc around `copyFile`_, + ## `getFilePermissions`_ and `setFilePermissions`_ ## procs on non-Windows platforms. ## - ## On Windows this proc is just a wrapper for `copyFile proc - ## <#copyFile,string,string>`_ since that proc already copies attributes. + ## On Windows this proc is just a wrapper for `copyFile proc`_ since + ## that proc already copies attributes. ## ## On non-Windows systems permissions are copied after the file itself has ## been copied, which won't happen atomically and could lead to a race @@ -2653,13 +2649,13 @@ proc copyFileWithPermissions*(source, dest: string, ## `OSError`. ## ## See also: - ## * `CopyFlag enum <#CopyFlag>`_ - ## * `copyFile proc <#copyFile,string,string>`_ - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ - ## * `removeFile proc <#removeFile,string>`_ - ## * `moveFile proc <#moveFile,string,string>`_ - ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ + ## * `CopyFlag enum`_ + ## * `copyFile proc`_ + ## * `copyDir proc`_ + ## * `tryRemoveFile proc`_ + ## * `removeFile proc`_ + ## * `moveFile proc`_ + ## * `copyDirWithPermissions proc`_ copyFile(source, dest, options) when not defined(windows): try: @@ -2678,13 +2674,12 @@ proc copyDirWithPermissions*(source, dest: string, ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks ## are skipped. ## - ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir - ## <#copyDir,string,string>`_ and `copyFileWithPermissions - ## <#copyFileWithPermissions,string,string>`_ procs + ## If this fails, `OSError` is raised. This is a wrapper proc around + ## `copyDir`_ and `copyFileWithPermissions`_ procs ## on non-Windows platforms. ## - ## On Windows this proc is just a wrapper for `copyDir proc - ## <#copyDir,string,string>`_ since that proc already copies attributes. + ## On Windows this proc is just a wrapper for `copyDir proc`_ since + ## that proc already copies attributes. ## ## On non-Windows systems permissions are copied after the file or directory ## itself has been copied, which won't happen atomically and could lead to a @@ -2693,13 +2688,13 @@ proc copyDirWithPermissions*(source, dest: string, ## `OSError`. ## ## See also: - ## * `copyDir proc <#copyDir,string,string>`_ - ## * `copyFile proc <#copyFile,string,string>`_ - ## * `copyFileWithPermissions proc <#copyFileWithPermissions,string,string>`_ - ## * `removeDir proc <#removeDir,string>`_ - ## * `moveDir proc <#moveDir,string,string>`_ - ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ - ## * `createDir proc <#createDir,string>`_ + ## * `copyDir proc`_ + ## * `copyFile proc`_ + ## * `copyFileWithPermissions proc`_ + ## * `removeDir proc`_ + ## * `moveDir proc`_ + ## * `existsOrCreateDir proc`_ + ## * `createDir proc`_ createDir(dest) when not defined(windows): try: @@ -2769,9 +2764,9 @@ proc parseCmdLine*(c: string): seq[string] {. ## ## See also: ## * `parseopt module `_ - ## * `paramCount proc <#paramCount>`_ - ## * `paramStr proc <#paramStr,int>`_ - ## * `commandLineParams proc <#commandLineParams>`_ + ## * `paramCount proc`_ + ## * `paramStr proc`_ + ## * `commandLineParams proc`_ result = @[] var i = 0 @@ -2838,9 +2833,8 @@ when defined(nimdoc): ## ## Unlike `argc`:idx: in C, if your binary was called without parameters this ## will return zero. - ## You can query each individual parameter with `paramStr proc <#paramStr,int>`_ - ## or retrieve all of them in one go with `commandLineParams proc - ## <#commandLineParams>`_. + ## You can query each individual parameter with `paramStr proc`_ + ## or retrieve all of them in one go with `commandLineParams proc`_. ## ## **Availability**: When generating a dynamic library (see `--app:lib`) on ## Posix this proc is not defined. @@ -2848,9 +2842,9 @@ when defined(nimdoc): ## ## See also: ## * `parseopt module `_ - ## * `parseCmdLine proc <#parseCmdLine,string>`_ - ## * `paramStr proc <#paramStr,int>`_ - ## * `commandLineParams proc <#commandLineParams>`_ + ## * `parseCmdLine proc`_ + ## * `paramStr proc`_ + ## * `commandLineParams proc`_ ## ## **Examples:** ## @@ -2865,13 +2859,13 @@ when defined(nimdoc): ## ## `i` should be in the range `1..paramCount()`, the `IndexDefect` ## exception will be raised for invalid values. Instead of iterating - ## over `paramCount() <#paramCount>`_ with this proc you can - ## call the convenience `commandLineParams() <#commandLineParams>`_. + ## over `paramCount()`_ with this proc you can + ## call the convenience `commandLineParams()`_. ## ## Similarly to `argv`:idx: in C, ## it is possible to call `paramStr(0)` but this will return OS specific ## contents (usually the name of the invoked executable). You should avoid - ## this and call `getAppFilename() <#getAppFilename>`_ instead. + ## this and call `getAppFilename()`_ instead. ## ## **Availability**: When generating a dynamic library (see `--app:lib`) on ## Posix this proc is not defined. @@ -2879,10 +2873,10 @@ when defined(nimdoc): ## ## See also: ## * `parseopt module `_ - ## * `parseCmdLine proc <#parseCmdLine,string>`_ - ## * `paramCount proc <#paramCount>`_ - ## * `commandLineParams proc <#commandLineParams>`_ - ## * `getAppFilename proc <#getAppFilename>`_ + ## * `parseCmdLine proc`_ + ## * `paramCount proc`_ + ## * `commandLineParams proc`_ + ## * `getAppFilename proc`_ ## ## **Examples:** ## @@ -2971,7 +2965,7 @@ when declared(paramCount) or defined(nimdoc): ## Convenience proc which returns the command line parameters. ## ## This returns **only** the parameters. If you want to get the application - ## executable filename, call `getAppFilename() <#getAppFilename>`_. + ## executable filename, call `getAppFilename()`_. ## ## **Availability**: On Posix there is no portable way to get the command ## line from a DLL and thus the proc isn't defined in this environment. You @@ -2980,10 +2974,10 @@ when declared(paramCount) or defined(nimdoc): ## ## See also: ## * `parseopt module `_ - ## * `parseCmdLine proc <#parseCmdLine,string>`_ - ## * `paramCount proc <#paramCount>`_ - ## * `paramStr proc <#paramStr,int>`_ - ## * `getAppFilename proc <#getAppFilename>`_ + ## * `parseCmdLine proc`_ + ## * `paramCount proc`_ + ## * `paramStr proc`_ + ## * `getAppFilename proc`_ ## ## **Examples:** ## @@ -3133,8 +3127,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW ## This proc will resolve symlinks. ## ## See also: - ## * `getAppDir proc <#getAppDir>`_ - ## * `getCurrentCompilerExe proc <#getCurrentCompilerExe>`_ + ## * `getAppDir proc`_ + ## * `getCurrentCompilerExe proc`_ # Linux: /proc//exe # Solaris: @@ -3198,7 +3192,7 @@ proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdT ## Returns the directory of the application's executable. ## ## See also: - ## * `getAppFilename proc <#getAppFilename>`_ + ## * `getAppFilename proc`_ result = splitFile(getAppFilename()).dir proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTarget.} = @@ -3242,9 +3236,9 @@ type ## Contains information associated with a file object. ## ## See also: - ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ - ## * `getFileInfo(file) proc <#getFileInfo,File>`_ - ## * `getFileInfo(path) proc <#getFileInfo,string>`_ + ## * `getFileInfo(handle) proc`_ + ## * `getFileInfo(file) proc`_ + ## * `getFileInfo(path, followSymlink) proc`_ id*: tuple[device: DeviceId, file: FileId] ## Device and file id. kind*: PathComponent ## Kind of file object - directory, symlink, etc. size*: BiggestInt ## Size of file. @@ -3334,8 +3328,8 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} = ## is invalid, `OSError` is raised. ## ## See also: - ## * `getFileInfo(file) proc <#getFileInfo,File>`_ - ## * `getFileInfo(path) proc <#getFileInfo,string>`_ + ## * `getFileInfo(file) proc`_ + ## * `getFileInfo(path, followSymlink) proc`_ # Done: ID, Kind, Size, Permissions, Link Count when defined(windows): @@ -3356,8 +3350,8 @@ proc getFileInfo*(file: File): FileInfo {.noWeirdTarget.} = ## Retrieves file information for the file object. ## ## See also: - ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ - ## * `getFileInfo(path) proc <#getFileInfo,string>`_ + ## * `getFileInfo(handle) proc`_ + ## * `getFileInfo(path, followSymlink) proc`_ if file.isNil: raise newException(IOError, "File is nil") result = getFileInfo(file.getFileHandle()) @@ -3366,7 +3360,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget. ## Retrieves file information for the file object pointed to by `path`. ## ## Due to intrinsic differences between operating systems, the information - ## contained by the returned `FileInfo object <#FileInfo>`_ will be slightly + ## contained by the returned `FileInfo object`_ will be slightly ## different across platforms, and in some cases, incomplete or inaccurate. ## ## When `followSymlink` is true (default), symlinks are followed and the @@ -3378,8 +3372,8 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget. ## file information, `OSError` is raised. ## ## See also: - ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ - ## * `getFileInfo(file) proc <#getFileInfo,File>`_ + ## * `getFileInfo(handle) proc`_ + ## * `getFileInfo(file) proc`_ when defined(windows): var handle = openHandle(path, followSymlink) @@ -3406,7 +3400,7 @@ proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", ## binary content. ## ## See also: - ## * `sameFile proc <#sameFile,string,string>`_ + ## * `sameFile proc`_ var a, b: File if not open(a, path1): return false diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim index 5bcdf32d5..9d440a1d6 100644 --- a/tests/stdlib/tdochelpers.nim +++ b/tests/stdlib/tdochelpers.nim @@ -153,3 +153,9 @@ suite "Integration with Nim": outType: "T") check(input1.toLangSymbol == expected) check(input2.toLangSymbol == expected) + + test "type of type": + check ("`CopyFlag enum`_".rstParseTest.toLangSymbol == + LangSymbol(symKind: "type", + symTypeKind: "enum", + name: "Copyflag")) From 83a9c3ba31d180cd5e31026d8b7603bf7adea18c Mon Sep 17 00:00:00 2001 From: Zoom Date: Mon, 8 Nov 2021 18:47:20 +0000 Subject: [PATCH 3124/4254] Update readme.md: matrix links (#19109) Added links to the main #nim-lang room on Matrix and to the Nim matrix space. Added Matrix badge. --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index af07c2a7b..7d45556db 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( [![Join the IRC chat][badge-nim-irc]][nim-irc] [![Join the Discord server][badge-nim-discord]][nim-discord] [![Join the Gitter chat][badge-nim-gitter]][nim-gitter] +[![Join the Matrix room](https://img.shields.io/matrix/nim-lang:matrix.org?color=blue&style=flat&logo=matrix)](https://matrix.to/#/#nim-lang:matrix.org) [![Get help][badge-nim-forum-gethelp]][nim-forum] [![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest] [![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter] @@ -22,6 +23,7 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( channels there are bridged to IRC. * [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There is a bridge between Gitter and the IRC channel. +* [Matrix][nim-matrix] - the main room to discuss Nim in real-time. [Matrix space][nim-matrix-space] contains a list of rooms, most of them are bridged to IRC. * [Telegram][nim-telegram] - an additional place to discuss Nim in real-time. There is the official Telegram channel. Not bridged to IRC. * [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related @@ -213,6 +215,8 @@ Copyright © 2006-2021 Andreas Rumpf, all rights reserved. [nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim-lang?sort=newest&pageSize=15 [nim-discord]: https://discord.gg/nim [nim-gitter]: https://gitter.im/nim-lang/Nim +[nim-matrix]: https://matrix.to/#/#nim-lang:matrix.org +[nim-matrix-space]: https://matrix.to/#/#nim:envs.net [nim-telegram]: https://t.me/nim_lang [nim-bountysource]: https://www.bountysource.com/teams/nim [nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ From b7c66ce860cfbadfa8ed60784fc387a0818e2e5d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 9 Nov 2021 12:43:16 +0100 Subject: [PATCH 3125/4254] fixes #19013 [backport:1.6] (#19111) * fixes #19013 [backport:1.6] * added test case --- compiler/ast.nim | 8 ++++++++ compiler/isolation_check.nim | 17 ++++++++++++++++- compiler/varpartitions.nim | 7 ------- tests/isolate/tisolate2.nim | 22 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 tests/isolate/tisolate2.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index abd2ff01e..9086860b9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -2101,3 +2101,11 @@ proc skipAddr*(n: PNode): PNode {.inline.} = proc isNewStyleConcept*(n: PNode): bool {.inline.} = assert n.kind == nkTypeClassTy result = n[0].kind == nkEmpty + +const + nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit, + nkTypeSection, nkProcDef, nkConverterDef, + nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, + nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, + nkTypeOfExpr, nkMixinStmt, nkBindStmt} diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 777e7f6ce..a8c5a3651 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -77,6 +77,17 @@ proc canAlias*(arg, ret: PType): bool = var marker = initIntSet() result = canAlias(arg, ret, marker) +proc containsVariable(n: PNode): bool = + case n.kind + of nodesToIgnoreSet: + result = false + of nkSym: + result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp} + else: + for ch in n: + if containsVariable(ch): return true + result = false + proc checkIsolate*(n: PNode): bool = if types.containsTyRef(n.typ): # XXX Maybe require that 'n.typ' is acyclic. This is not much @@ -96,7 +107,11 @@ proc checkIsolate*(n: PNode): bool = else: let argType = n[i].typ if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType): - if argType.canAlias(n.typ): + if argType.canAlias(n.typ) or containsVariable(n[i]): + # bug #19013: Alias information is not enough, we need to check for potential + # "overlaps". I claim the problem can only happen by reading again from a location + # that materialized which is only possible if a variable that contains a `ref` + # is involved. return false result = true of nkIfStmt, nkIfExpr: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 709d00fa0..721de900e 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -647,13 +647,6 @@ proc deps(c: var Partitions; dest, src: PNode) = when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo c.s[vid].flags.incl preventCursor -const - nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit, - nkTypeSection, nkProcDef, nkConverterDef, - nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, - nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, - nkTypeOfExpr, nkMixinStmt, nkBindStmt} proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) = if constParameters in c.goals and tfNoSideEffect in callee.flags: diff --git a/tests/isolate/tisolate2.nim b/tests/isolate/tisolate2.nim new file mode 100644 index 000000000..9bf92d82e --- /dev/null +++ b/tests/isolate/tisolate2.nim @@ -0,0 +1,22 @@ +discard """ + errormsg: "expression cannot be isolated: a_to_b(a)" + line: 22 +""" + +# bug #19013 +import std/isolation + +type Z = ref object + i: int + +type A = object + z: Z + +type B = object + z: Z + +func a_to_b(a: A): B = + result = B(z: a.z) + +let a = A(z: Z(i: 3)) +let b = isolate(a_to_b(a)) From 6ff61766daec10d4cf78488b38bbe05d034e3a1c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 9 Nov 2021 18:59:59 +0100 Subject: [PATCH 3126/4254] fixes #19011 [backport:1.6] (#19114) --- compiler/parser.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 5e9a7424a..aedf62d54 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1877,7 +1877,7 @@ proc parseEnum(p: var Parser): PNode = var symPragma = a var pragma: PNode - if p.tok.tokType == tkCurlyDotLe: + if (p.tok.indent < 0 or p.tok.indent >= p.currInd) and p.tok.tokType == tkCurlyDotLe: pragma = optPragmas(p) symPragma = newNodeP(nkPragmaExpr, p) symPragma.add(a) From b0f4a9b845e4d483547f1a3818e3caf53cd90964 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 9 Nov 2021 19:00:33 +0100 Subject: [PATCH 3127/4254] Add deprecation pragmas in lib/deprecated/pure (#19113) --- lib/deprecated/pure/LockFreeHash.nim | 6 ++++-- lib/deprecated/pure/events.nim | 2 ++ lib/deprecated/pure/ospaths.nim | 5 +++-- lib/deprecated/pure/securehash.nim | 5 ++--- lib/deprecated/pure/sharedstrings.nim | 2 ++ 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/deprecated/pure/LockFreeHash.nim b/lib/deprecated/pure/LockFreeHash.nim index 97e1ef6ad..69e12226f 100644 --- a/lib/deprecated/pure/LockFreeHash.nim +++ b/lib/deprecated/pure/LockFreeHash.nim @@ -1,10 +1,12 @@ #nim c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim -import math, hashes - #------------------------------------------------------------------------------ ## Memory Utility Functions +{.deprecated.} + +import math, hashes + proc newHeap*[T](): ptr T = result = cast[ptr T](alloc0(sizeof(T))) diff --git a/lib/deprecated/pure/events.nim b/lib/deprecated/pure/events.nim index 218cb45d5..85fc349c2 100644 --- a/lib/deprecated/pure/events.nim +++ b/lib/deprecated/pure/events.nim @@ -36,6 +36,8 @@ ## myobj.SomeEvent.addHandler(handleevent) ## ee.emit(myobj.SomeEvent, genericargs) +{.deprecated.} + type EventArgs* = object of RootObj ## Base object for event arguments that are passed to callback functions. EventHandler* = tuple[name: string, handlers: seq[proc(e: EventArgs) {.closure.}]] ## An eventhandler for an event. diff --git a/lib/deprecated/pure/ospaths.nim b/lib/deprecated/pure/ospaths.nim index 6c7fe4fb3..e253a3e5a 100644 --- a/lib/deprecated/pure/ospaths.nim +++ b/lib/deprecated/pure/ospaths.nim @@ -7,8 +7,9 @@ # distribution, for details about the copyright. # -## This module is deprecated, `import os` instead. -{.deprecated: "import os.nim instead".} +## This module is deprecated, `import std/os` instead. + +{.deprecated: "use `std/os` instead".} import os export ReadEnvEffect, WriteEnvEffect, ReadDirEffect, WriteDirEffect, OSErrorCode, diff --git a/lib/deprecated/pure/securehash.nim b/lib/deprecated/pure/securehash.nim index 2f4530d88..ea7930f81 100644 --- a/lib/deprecated/pure/securehash.nim +++ b/lib/deprecated/pure/securehash.nim @@ -1,6 +1,5 @@ - - ## This module is a deprecated alias for the `sha1` module. -{.deprecated.} + +{.deprecated: "use `std/sha1` instead".} include "../std/sha1" diff --git a/lib/deprecated/pure/sharedstrings.nim b/lib/deprecated/pure/sharedstrings.nim index 4d4ae151b..99963e1f2 100644 --- a/lib/deprecated/pure/sharedstrings.nim +++ b/lib/deprecated/pure/sharedstrings.nim @@ -9,6 +9,8 @@ ## Shared string support for Nim. +{.deprecated.} + type UncheckedCharArray = UncheckedArray[char] From 46fb85542518c8594c24d168b025cc8a64b8fb3d Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 9 Nov 2021 19:00:43 +0100 Subject: [PATCH 3128/4254] Deprecate `std/sharedlist` and `std/sharedtables` (#19112) --- changelogs/changelog.md | 2 ++ changelogs/changelog_1_4_0.md | 2 +- doc/lib.rst | 6 ------ lib/pure/collections/lists.nim | 1 - lib/pure/collections/sharedlist.nim | 2 ++ lib/pure/collections/sharedtables.nim | 2 ++ lib/pure/collections/tables.nim | 1 - 7 files changed, 7 insertions(+), 9 deletions(-) diff --git a/changelogs/changelog.md b/changelogs/changelog.md index 475f568ec..d793c4313 100644 --- a/changelogs/changelog.md +++ b/changelogs/changelog.md @@ -4,6 +4,8 @@ ## Standard library additions and changes +- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433). + ### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17. diff --git a/changelogs/changelog_1_4_0.md b/changelogs/changelog_1_4_0.md index 091048ad1..77f66ffde 100644 --- a/changelogs/changelog_1_4_0.md +++ b/changelogs/changelog_1_4_0.md @@ -282,7 +282,7 @@ - Removed the deprecated `asyncdispatch.newAsyncNativeSocket`. - Removed the deprecated `dom.releaseEvents` and `dom.captureEvents`. -- Removed `sharedlists.initSharedList`, was deprecated and produces undefined behaviour. +- Removed `sharedlist.initSharedList`, was deprecated and produces undefined behaviour. - There is a new experimental feature called "strictFuncs" which makes the definition of `.noSideEffect` stricter. [See here](manual_experimental.html#stricts-funcs) diff --git a/doc/lib.rst b/doc/lib.rst index 54728d681..881d857d3 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -134,12 +134,6 @@ Collections * `sets `_ Nim hash set support. -* `sharedlist `_ - Nim shared linked list support. Contains a shared singly-linked list. - -* `sharedtables `_ - Nim shared hash table support. Contains shared tables. - * `tables `_ Nim hash table support. Contains tables, ordered tables, and count tables. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index af53bb68b..8b255fb60 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -56,7 +56,6 @@ runnableExamples: ## # See also ## * `deques module `_ for double-ended queues -## * `sharedlist module `_ for shared singly-linked lists import std/private/since diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index 73e147e05..e61883220 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -11,6 +11,8 @@ ## ## Unstable API. +{.deprecated.} + {.push stackTrace: off.} import diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index a85674df9..816ab49ab 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -14,6 +14,8 @@ ## ## Unstable API. +{.deprecated.} + import hashes, math, locks diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 2695f3693..00f71ef1d 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -191,7 +191,6 @@ runnableExamples: ## ## * `json module`_ for table-like structure which allows ## heterogeneous members -## * `sharedtables module`_ for shared hash table support ## * `strtabs module`_ for efficient hash tables ## mapping from strings to strings ## * `hashes module`_ for helper functions for hashing From 997ccc588955dab5cdbfd4c0fc067d91ccc1a7c8 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 9 Nov 2021 21:01:47 +0300 Subject: [PATCH 3129/4254] fix nimindexterm in rst2tex/doc2tex [backport] (#19106) * fix nimindexterm (rst2tex/doc2tex) [backport] * Add support for indexing in rst --- config/nimdoc.tex.cfg | 12 +++++++++++- lib/packages/docutils/rstgen.nim | 2 +- tools/kochdocs.nim | 6 ++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index d7ab652eb..457f452dd 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -63,6 +63,11 @@ doc.file = """ % % Compile it by: xelatex (up to 3 times to get labels generated) % ------- +% For example: +% xelatex file.tex +% xelatex file.tex +% makeindex file +% xelatex file.tex % \documentclass[a4paper,11pt]{article} \usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry} @@ -105,7 +110,9 @@ doc.file = """ \usepackage{parskip} % paragraphs delimited by vertical space, no indent \usepackage{graphicx} -\newcommand{\nimindexterm}[2]{#2\label{#1}} +\usepackage{makeidx} +\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}} +\makeindex \usepackage{dingbat} % for \carriagereturn, etc \usepackage{fvextra} % for code blocks (works better than original fancyvrb) @@ -249,5 +256,8 @@ doc.file = """ \maketitle $content + +\printindex + \end{document} """ diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index a556aa2e3..4cbd05379 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -408,7 +408,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = var term = "" renderAux(d, n, term) setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection) - dispA(d.target, result, "$2", "\\nimindexterm{$2}{$1}", + dispA(d.target, result, "$2", "\\nimindexterm{$1}{$2}", [id, term]) type diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 42e648fb4..70ee5ad07 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -301,6 +301,12 @@ proc nim2pdf(src: string, dst: string, nimArgs: string) = # `>` should work on windows, if not, we can use `execCmdEx` let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell] exec(cmd) # on error, user can inspect `xelatexLog` + if i == 1: # build .ind file + var texFileBase = texFile + texFileBase.removeSuffix(".tex") + let cmd = "makeindex $# > $#" % [ + texFileBase.quoteShell, xelatexLog.quoteShell] + exec(cmd) moveFile(texFile.changeFileExt("pdf"), dst) proc buildPdfDoc*(nimArgs, destPath: string) = From 15157d06c3e0bba0c372a094917a13b916e15b54 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 9 Nov 2021 22:48:04 +0100 Subject: [PATCH 3130/4254] fixes #14470 [backport:1.2] (#19115) --- compiler/ccgtypes.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 23e1a5867..e7e099659 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -220,7 +220,8 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. - if rettype == nil: result = true + if rettype == nil or getSize(conf, rettype) > conf.target.floatSize*3: + result = true else: case mapType(conf, rettype, skResult) of ctArray: From a78ee8ae8453aabde04fa0103e02378efe870827 Mon Sep 17 00:00:00 2001 From: treeform Date: Tue, 9 Nov 2021 23:52:34 -0800 Subject: [PATCH 3131/4254] Call {.cursor.} a pragma. (#19116) * Call {.cursor.} a pragma. Its hard to find .curser annotation while googling because all other things like it are called pragmas. See https://nim-lang.org/docs/manual.html#pragmas Also the . in front of the name makes it hard to find and search for. Can we just call it cursor pragma? * Small fix for comment. --- doc/destructors.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/destructors.rst b/doc/destructors.rst index d6f240dee..83a50230b 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -555,14 +555,14 @@ for expressions of type `lent T` or of type `var T`. echo t[0] # accessor does not copy the element! -The .cursor annotation -====================== +The cursor pragma +================= Under the `--gc:arc|orc`:option: modes Nim's `ref` type is implemented via the same runtime "hooks" and thus via reference counting. This means that cyclic structures cannot be freed immediately (`--gc:orc`:option: ships with a cycle collector). -With the `.cursor` annotation one can break up cycles declaratively: +With the `cursor` pragma one can break up cycles declaratively: .. code-block:: nim @@ -575,7 +575,7 @@ But please notice that this is not C++'s weak_ptr, it means the right field is n involved in the reference counting, it is a raw pointer without runtime checks. Automatic reference counting also has the disadvantage that it introduces overhead -when iterating over linked structures. The `.cursor` annotation can also be used +when iterating over linked structures. The `cursor` pragma can also be used to avoid this overhead: .. code-block:: nim @@ -586,10 +586,10 @@ to avoid this overhead: it = it.next -In fact, `.cursor` more generally prevents object construction/destruction pairs +In fact, `cursor` more generally prevents object construction/destruction pairs and so can also be useful in other contexts. The alternative solution would be to use raw pointers (`ptr`) instead which is more cumbersome and also more dangerous -for Nim's evolution: Later on, the compiler can try to prove `.cursor` annotations +for Nim's evolution: Later on, the compiler can try to prove `cursor` pragmas to be safe, but for `ptr` the compiler has to remain silent about possible problems. @@ -597,7 +597,7 @@ problems. Cursor inference / copy elision =============================== -The current implementation also performs `.cursor` inference. Cursor inference is +The current implementation also performs `cursor` inference. Cursor inference is a form of copy elision. To see how and when we can do that, think about this question: In `dest = src` when @@ -612,7 +612,7 @@ indirections: .. code-block:: nim proc main(tab: Table[string, string]) = - let v = tab["key"] # inferred as .cursor because 'tab' is not mutated. + let v = tab["key"] # inferred as cursor because 'tab' is not mutated. # no copy into 'v', no destruction of 'v'. use(v) useItAgain(v) From 77b696c2c92b5f478526290c5e184a4c41060f7b Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Wed, 10 Nov 2021 23:48:22 -0600 Subject: [PATCH 3132/4254] Remove tlsEmulation enabled from Windows + GCC config (#19119) [backport:1.6] This flag has a very significant performance impact on programs compiled with --threads:on. It is also apparently not needed anymore for standard circumstances. Can we remove the config? See https://github.com/nim-lang/Nim/issues/18146#issuecomment-876802676 for discussion and perf impact. [backport:1.6] --- config/nim.cfg | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index 3b964d124..86c6e2141 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -154,9 +154,6 @@ nimblepath="$home/.nimble/pkgs/" # Configuration for the GNU C/C++ compiler: @if windows: #gcc.path = r"$nim\dist\mingw\bin" - @if gcc or tcc: - tlsEmulation:on - @end @end gcc.maxerrorsimpl = "-fmax-errors=3" From 036d894e6a13cf9792c3250e34252a225c73e468 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Thu, 11 Nov 2021 07:41:21 +0000 Subject: [PATCH 3133/4254] Add security tip for setCookie (#19117) * Add security tip for setCookie * Update lib/pure/cookies.nim Co-authored-by: Dominik Picheta * Update lib/pure/cookies.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Andreas Rumpf Co-authored-by: Dominik Picheta Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/cookies.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 25d701eb4..132f64637 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -50,6 +50,9 @@ proc setCookie*(key, value: string, domain = "", path = "", maxAge = none(int), sameSite = SameSite.Default): string = ## Creates a command in the format of ## `Set-Cookie: key=value; Domain=...; ...` + ## + + ## .. tip: Cookies can be vulnerable. Consider setting `secure=true`, `httpOnly=true` and `sameSite=Strict`. result = "" if not noName: result.add("Set-Cookie: ") result.add key & "=" & value From 7313b70a6af3fec6f367dd72bdd4f7651bf60d21 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 11 Nov 2021 15:53:27 +0800 Subject: [PATCH 3134/4254] correct cookie docs (#19122) --- lib/pure/cookies.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 132f64637..7bf34f75b 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -51,8 +51,7 @@ proc setCookie*(key, value: string, domain = "", path = "", ## Creates a command in the format of ## `Set-Cookie: key=value; Domain=...; ...` ## - - ## .. tip: Cookies can be vulnerable. Consider setting `secure=true`, `httpOnly=true` and `sameSite=Strict`. + ## .. tip:: Cookies can be vulnerable. Consider setting `secure=true`, `httpOnly=true` and `sameSite=Strict`. result = "" if not noName: result.add("Set-Cookie: ") result.add key & "=" & value From cde83d90aa888ccc83bd78e6b6fb54d0ab0b2c26 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 11 Nov 2021 19:07:08 +0100 Subject: [PATCH 3135/4254] refactoring: orc can use getThreadId() (#19123) * refactoring: orc can use getThreadId() * progress --- lib/system/orc.nim | 7 +- lib/system/threadids.nim | 103 ++++++++++++++++++++++++++++++ lib/system/threadlocalstorage.nim | 3 - lib/system/threads.nim | 93 +-------------------------- 4 files changed, 110 insertions(+), 96 deletions(-) create mode 100644 lib/system/threadids.nim diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 6273e1a21..f9f5cd81f 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -79,10 +79,12 @@ proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = var p = s +! sizeof(RefHeader) cast[TraceProc](desc.traceImpl)(p, addr(j)) +include threadids + when logOrc: proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) = - cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld\n", - msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color) + cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld; thread: %ld\n", + msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color, getThreadId()) proc free(s: Cell; desc: PNimTypeV2) {.inline.} = when traceCollector: @@ -419,6 +421,7 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) = proc GC_runOrc* = ## Forces a cycle collection pass. collectCycles() + orcAssert roots.len == 0, "roots not empty!" proc GC_enableOrc*() = ## Enables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` diff --git a/lib/system/threadids.nim b/lib/system/threadids.nim new file mode 100644 index 000000000..3a6eadcbb --- /dev/null +++ b/lib/system/threadids.nim @@ -0,0 +1,103 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# we need to cache current threadId to not perform syscall all the time +var threadId {.threadvar.}: int + +when defined(windows): + proc getCurrentThreadId(): int32 {. + stdcall, dynlib: "kernel32", importc: "GetCurrentThreadId".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(getCurrentThreadId()) + result = threadId + +elif defined(linux): + proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "".} + when defined(amd64): + const NR_gettid = clong(186) + else: + var NR_gettid {.importc: "__NR_gettid", header: "".}: clong + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(syscall(NR_gettid)) + result = threadId + +elif defined(dragonfly): + proc lwp_gettid(): int32 {.importc, header: "unistd.h".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(lwp_gettid()) + result = threadId + +elif defined(openbsd): + proc getthrid(): int32 {.importc: "getthrid", header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(getthrid()) + result = threadId + +elif defined(netbsd): + proc lwp_self(): int32 {.importc: "_lwp_self", header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(lwp_self()) + result = threadId + +elif defined(freebsd): + proc syscall(arg: cint, arg0: ptr cint): cint {.varargs, importc: "syscall", header: "".} + var SYS_thr_self {.importc:"SYS_thr_self", header:"".}: cint + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + var tid = 0.cint + if threadId == 0: + discard syscall(SYS_thr_self, addr tid) + threadId = tid + result = threadId + +elif defined(macosx): + proc syscall(arg: cint): cint {.varargs, importc: "syscall", header: "".} + var SYS_thread_selfid {.importc:"SYS_thread_selfid", header:"".}: cint + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(syscall(SYS_thread_selfid)) + result = threadId + +elif defined(solaris): + type thread_t {.importc: "thread_t", header: "".} = distinct int + proc thr_self(): thread_t {.importc, header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(thr_self()) + result = threadId + +elif defined(haiku): + type thr_id {.importc: "thread_id", header: "".} = distinct int32 + proc find_thread(name: cstring): thr_id {.importc, header: "".} + + proc getThreadId*(): int = + ## Gets the ID of the currently running thread. + if threadId == 0: + threadId = int(find_thread(nil)) + result = threadId diff --git a/lib/system/threadlocalstorage.nim b/lib/system/threadlocalstorage.nim index 30962ef77..e772f270c 100644 --- a/lib/system/threadlocalstorage.nim +++ b/lib/system/threadlocalstorage.nim @@ -29,9 +29,6 @@ when defined(windows): proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {. stdcall, dynlib: "kernel32", importc: "TerminateThread".} - proc getCurrentThreadId(): int32 {. - stdcall, dynlib: "kernel32", importc: "GetCurrentThreadId".} - type ThreadVarSlot = distinct int32 diff --git a/lib/system/threads.nim b/lib/system/threads.nim index a9006b0c5..a8a413bcb 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -343,94 +343,5 @@ else: proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) = createThread[void](t, tp) -# we need to cache current threadId to not perform syscall all the time -var threadId {.threadvar.}: int - -when defined(windows): - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(getCurrentThreadId()) - result = threadId - -elif defined(linux): - proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "".} - when defined(amd64): - const NR_gettid = clong(186) - else: - var NR_gettid {.importc: "__NR_gettid", header: "".}: clong - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(syscall(NR_gettid)) - result = threadId - -elif defined(dragonfly): - proc lwp_gettid(): int32 {.importc, header: "unistd.h".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(lwp_gettid()) - result = threadId - -elif defined(openbsd): - proc getthrid(): int32 {.importc: "getthrid", header: "".} - - proc getThreadId*(): int = - ## get the ID of the currently running thread. - if threadId == 0: - threadId = int(getthrid()) - result = threadId - -elif defined(netbsd): - proc lwp_self(): int32 {.importc: "_lwp_self", header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(lwp_self()) - result = threadId - -elif defined(freebsd): - proc syscall(arg: cint, arg0: ptr cint): cint {.varargs, importc: "syscall", header: "".} - var SYS_thr_self {.importc:"SYS_thr_self", header:"".}: cint - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - var tid = 0.cint - if threadId == 0: - discard syscall(SYS_thr_self, addr tid) - threadId = tid - result = threadId - -elif defined(macosx): - proc syscall(arg: cint): cint {.varargs, importc: "syscall", header: "".} - var SYS_thread_selfid {.importc:"SYS_thread_selfid", header:"".}: cint - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(syscall(SYS_thread_selfid)) - result = threadId - -elif defined(solaris): - type thread_t {.importc: "thread_t", header: "".} = distinct int - proc thr_self(): thread_t {.importc, header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(thr_self()) - result = threadId - -elif defined(haiku): - type thr_id {.importc: "thread_id", header: "".} = distinct int32 - proc find_thread(name: cstring): thr_id {.importc, header: "".} - - proc getThreadId*(): int = - ## Gets the ID of the currently running thread. - if threadId == 0: - threadId = int(find_thread(nil)) - result = threadId +when not defined(gcOrc): + include threadids From 528ef6c218d90653f0f814c3dd256caa2cc389dc Mon Sep 17 00:00:00 2001 From: orthoplex <39635932+orthoplex@users.noreply.github.com> Date: Thu, 11 Nov 2021 20:01:51 +0100 Subject: [PATCH 3136/4254] fixed colorNames sorting mistake (#19125) [backport] --- lib/pure/colors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 4a3f47e92..2193f69a6 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -353,8 +353,8 @@ const ("lightcoral", colLightCoral), ("lightcyan", colLightCyan), ("lightgoldenrodyellow", colLightGoldenRodYellow), - ("lightgrey", colLightGrey), ("lightgreen", colLightGreen), + ("lightgrey", colLightGrey), ("lightpink", colLightPink), ("lightsalmon", colLightSalmon), ("lightseagreen", colLightSeaGreen), From 3aaa12dbe5796cc55c6161e4d30a70a7f75cb3b5 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 12 Nov 2021 14:59:48 +0800 Subject: [PATCH 3137/4254] update manual (#19130) [backport] --- doc/manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 001402036..328035b6d 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6721,11 +6721,11 @@ statement, as seen in stack backtraces: if not cond: # change run-time line information of the 'raise' statement: {.line: instantiationInfo().}: - raise newException(EAssertionFailed, msg) + raise newException(AssertionDefect, msg) If the `line` pragma is used with a parameter, the parameter needs be a `tuple[filename: string, line: int]`. If it is used without a parameter, -`system.InstantiationInfo()` is used. +`system.instantiationInfo()` is used. linearScanEnd pragma From f8b71f7075b68aefc3955388ad5ec3178aee7658 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 12 Nov 2021 18:00:19 +1100 Subject: [PATCH 3138/4254] Fix type mismatch with future logging (#19131) --- lib/pure/asyncfutures.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 6906d03fd..4782f0a73 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -225,7 +225,7 @@ proc complete*[T](future: FutureVar[T], val: T) = fut.finished = true fut.value = val fut.callbacks.call() - when isFutureLoggingEnabled: logFutureFinish(future) + when isFutureLoggingEnabled: logFutureFinish(fut) proc fail*[T](future: Future[T], error: ref Exception) = ## Completes `future` with `error`. From c6fc3b2eae5aac68480a787b7fa3b81e3748bc2f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 12 Nov 2021 11:19:24 +0100 Subject: [PATCH 3139/4254] fixes #19051 [backport:1.6] (#19133) --- compiler/sizealignoffsetimpl.nim | 19 +++++++++++++++++-- tests/ccgbugs/t5296.nim | 9 ++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 44ba32579..c5cd3ba64 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -196,6 +196,11 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo accum.offset = szUnknownSize proc computeSizeAlign(conf: ConfigRef; typ: PType) = + template setSize(typ, s) = + typ.size = s + typ.align = s + typ.paddingAtEnd = 0 + ## computes and sets ``size`` and ``align`` members of ``typ`` assert typ != nil let hasSize = typ.size != szUncomputedSize @@ -258,14 +263,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = of tyArray: computeSizeAlign(conf, typ[1]) - let elemSize = typ[1].size + let elemSize = typ[1].size let len = lengthOrd(conf, typ[0]) if elemSize < 0: typ.size = elemSize typ.align = int16(elemSize) elif len < 0: typ.size = szUnknownSize - typ.align = szUnknownSize + typ.align = szUnknownSize else: typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize) typ.align = typ[1].align @@ -445,6 +450,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.size = szUnknownSize typ.align = szUnknownSize typ.paddingAtEnd = szUnknownSize + of tyInt, tyUInt: + setSize typ, conf.target.intSize.int16 + of tyBool, tyChar, tyUInt8, tyInt8: + setSize typ, 1 + of tyInt16, tyUInt16: + setSize typ, 2 + of tyInt32, tyUInt32: + setSize typ, 4 + of tyInt64, tyUInt64: + setSize typ, 8 else: typ.size = szUnknownSize typ.align = szUnknownSize diff --git a/tests/ccgbugs/t5296.nim b/tests/ccgbugs/t5296.nim index 990b4bee2..8fbed35c4 100644 --- a/tests/ccgbugs/t5296.nim +++ b/tests/ccgbugs/t5296.nim @@ -1,6 +1,7 @@ discard """ cmd: "nim c -d:release $file" -output: 1 +output: '''1 +-1''' """ proc bug() : void = @@ -12,3 +13,9 @@ proc bug() : void = echo x bug() + +# bug #19051 +type GInt[T] = int + +var a = 1 +echo -a From 0a1049881eaa08cb7d10194d9b446d8a9ca52122 Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Fri, 12 Nov 2021 22:51:43 -0500 Subject: [PATCH 3140/4254] Merge file size fields correctly on Windows (#19141) * Merge file size fields correctly on Windows Merge file size fields correctly on Windows - Merge the two 32-bit file size fields from `BY_HANDLE_FILE_INFORMATION` correctly in `rawToFormalFileInfo`. - Fixes #19135 * Update os.nim --- lib/pure/os.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 513e09b48..9b08fe2e1 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -3255,7 +3255,11 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = ## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows, ## or a 'Stat' structure on posix when defined(windows): - template merge(a, b): untyped = a or (b shl 32) + template merge(a, b): untyped = + int64( + (uint64(cast[uint32](a))) or + (uint64(cast[uint32](b)) shl 32) + ) formalInfo.id.device = rawInfo.dwVolumeSerialNumber formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh) formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh) From ade85ee91fee849f4b036ed8e42e31b978144522 Mon Sep 17 00:00:00 2001 From: Christoph Krybus Date: Sat, 13 Nov 2021 04:51:58 +0100 Subject: [PATCH 3141/4254] Fix punycode.decode function (#19136) * Refactor: rename proc to func * Fix punycode.decode function This function could only properly decode punycodes containing a single encoded unicode character. As soon as there was more than one punycode character group to decode it produced invalid output - the number of characters was correct, but their position was not. * Update tpunycode.nim Co-authored-by: Clay Sweetser --- lib/pure/punycode.nim | 31 +++--- tests/stdlib/tpunycode.nim | 202 ++++++++++++++++++++++++++++++++++++- 2 files changed, 217 insertions(+), 16 deletions(-) diff --git a/lib/pure/punycode.nim b/lib/pure/punycode.nim index dfeeea35e..49e46496e 100644 --- a/lib/pure/punycode.nim +++ b/lib/pure/punycode.nim @@ -28,7 +28,7 @@ const type PunyError* = object of ValueError -proc decodeDigit(x: char): int {.raises: [PunyError].} = +func decodeDigit(x: char): int {.raises: [PunyError].} = if '0' <= x and x <= '9': result = ord(x) - (ord('0') - 26) elif 'A' <= x and x <= 'Z': @@ -38,7 +38,7 @@ proc decodeDigit(x: char): int {.raises: [PunyError].} = else: raise newException(PunyError, "Bad input") -proc encodeDigit(digit: int): Rune {.raises: [PunyError].} = +func encodeDigit(digit: int): Rune {.raises: [PunyError].} = if 0 <= digit and digit < 26: result = Rune(digit + ord('a')) elif 26 <= digit and digit < 36: @@ -46,10 +46,10 @@ proc encodeDigit(digit: int): Rune {.raises: [PunyError].} = else: raise newException(PunyError, "internal error in punycode encoding") -proc isBasic(c: char): bool = ord(c) < 0x80 -proc isBasic(r: Rune): bool = int(r) < 0x80 +func isBasic(c: char): bool = ord(c) < 0x80 +func isBasic(r: Rune): bool = int(r) < 0x80 -proc adapt(delta, numPoints: int, first: bool): int = +func adapt(delta, numPoints: int, first: bool): int = var d = if first: delta div Damp else: delta div 2 d += d div numPoints var k = 0 @@ -58,7 +58,7 @@ proc adapt(delta, numPoints: int, first: bool): int = k += Base result = k + (Base - TMin + 1) * d div (d + Skew) -proc encode*(prefix, s: string): string {.raises: [PunyError].} = +func encode*(prefix, s: string): string {.raises: [PunyError].} = ## Encode a string that may contain Unicode. ## Prepend `prefix` to the result result = prefix @@ -114,18 +114,18 @@ proc encode*(prefix, s: string): string {.raises: [PunyError].} = inc d inc n -proc encode*(s: string): string {.raises: [PunyError].} = +func encode*(s: string): string {.raises: [PunyError].} = ## Encode a string that may contain Unicode. Prefix is empty. result = encode("", s) -proc decode*(encoded: string): string {.raises: [PunyError].} = +func decode*(encoded: string): string {.raises: [PunyError].} = ## Decode a Punycode-encoded string var n = InitialN i = 0 bias = InitialBias var d = rfind(encoded, Delimiter) - result = "" + var output: seq[Rune] if d > 0: # found Delimiter @@ -133,7 +133,7 @@ proc decode*(encoded: string): string {.raises: [PunyError].} = var c = encoded[j] # char if not c.isBasic: raise newException(PunyError, "Encoded contains a non-basic char") - result.add(c) # add the character + output.add(Rune(c)) # add the character inc d else: d = 0 # set to first index @@ -161,16 +161,17 @@ proc decode*(encoded: string): string {.raises: [PunyError].} = break w *= Base - t k += Base - bias = adapt(i - oldi, runeLen(result) + 1, oldi == 0) + bias = adapt(i - oldi, len(output) + 1, oldi == 0) - if i div (runeLen(result) + 1) > high(int32) - n: + if i div (len(output) + 1) > high(int32) - n: raise newException(PunyError, "Value too large") - n += i div (runeLen(result) + 1) - i = i mod (runeLen(result) + 1) - insert(result, $Rune(n), i) + n += i div (len(output) + 1) + i = i mod (len(output) + 1) + insert(output, Rune(n), i) inc i + result = $output runnableExamples: static: diff --git a/tests/stdlib/tpunycode.nim b/tests/stdlib/tpunycode.nim index 596c5ef63..bb2b4beb4 100644 --- a/tests/stdlib/tpunycode.nim +++ b/tests/stdlib/tpunycode.nim @@ -1,5 +1,205 @@ -import punycode +import punycode, std/unicode doAssert(decode(encode("", "bücher")) == "bücher") doAssert(decode(encode("münchen")) == "münchen") doAssert encode("xn--", "münchen") == "xn--mnchen-3ya" + +# source: https://datatracker.ietf.org/doc/html/rfc3492.html#section-7 +let punycode_testcases = [ + # (A) Arabic (Egyptian): + ( + input: + "\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" & + "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F", + output: + "egbpdaj6bu4bxfgehfvwxn" + ), + + # (B) Chinese (simplified): + ( + input: + "\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587", + output: + "ihqwcrb4cv8a8dqg056pqjye" + ), + + # (C) Chinese (traditional): + ( + input: + "\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587", + output: + "ihqwctvzc91f659drss3x8bo0yb" + ), + + # (D) Czech: Proprostnemluvesky + ( + input: + "\u0050\u0072\u006F\u010D\u0070\u0072\u006F\u0073\u0074" & + "\u011B\u006E\u0065\u006D\u006C\u0075\u0076\u00ED\u010D" & + "\u0065\u0073\u006B\u0079", + output: + "Proprostnemluvesky-uyb24dma41a" + ), + + # (E) Hebrew: + ( + input: + "\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8" & + "\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2" & + "\u05D1\u05E8\u05D9\u05EA", + output: + "4dbcagdahymbxekheh6e0a7fei0b" + ), + + # (F) Hindi (Devanagari): + ( + input: + "\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D" & + "\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939" & + "\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947" & + "\u0939\u0948\u0902", + output: + "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd" + ), + + # (G) Japanese (kanji and hiragana): + ( + input: + "\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092" & + "\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B", + output: + "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa" + ), + + # (H) Korean (Hangul syllables): + ( + input: + "\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774" & + "\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74" & + "\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C", + output: + "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c" + ), + + # (I) Russian (Cyrillic): + ( + input: + "\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E" & + "\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440" & + "\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A" & + "\u0438", + output: + "b1abfaaepdrnnbgefbaDotcwatmq2g4l" + ), + + # (J) Spanish: PorqunopuedensimplementehablarenEspaol + ( + input: + "\u0050\u006F\u0072\u0071\u0075\u00E9\u006E\u006F\u0070" & + "\u0075\u0065\u0064\u0065\u006E\u0073\u0069\u006D\u0070" & + "\u006C\u0065\u006D\u0065\u006E\u0074\u0065\u0068\u0061" & + "\u0062\u006C\u0061\u0072\u0065\u006E\u0045\u0073\u0070" & + "\u0061\u00F1\u006F\u006C", + output: + "PorqunopuedensimplementehablarenEspaol-fmd56a" + ), + + # (K) Vietnamese: + # Tisaohkhngthch\ + # nitingVit + ( + input: + "\u0054\u1EA1\u0069\u0073\u0061\u006F\u0068\u1ECD\u006B" & + "\u0068\u00F4\u006E\u0067\u0074\u0068\u1EC3\u0063\u0068" & + "\u1EC9\u006E\u00F3\u0069\u0074\u0069\u1EBF\u006E\u0067" & + "\u0056\u0069\u1EC7\u0074", + output: + "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g" + ), + + # (L) 3B + ( + input: + "\u0033\u5E74\u0042\u7D44\u91D1\u516B\u5148\u751F", + output: + "3B-ww4c5e180e575a65lsy2b" + ), + + # (M) -with-SUPER-MONKEYS + ( + input: + "\u5B89\u5BA4\u5948\u7F8E\u6075\u002D\u0077\u0069\u0074" & + "\u0068\u002D\u0053\u0055\u0050\u0045\u0052\u002D\u004D" & + "\u004F\u004E\u004B\u0045\u0059\u0053", + output: + "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n" + ), + + # (N) Hello-Another-Way- + ( + input: + "\u0048\u0065\u006C\u006C\u006F\u002D\u0041\u006E\u006F" & + "\u0074\u0068\u0065\u0072\u002D\u0057\u0061\u0079\u002D" & + "\u305D\u308C\u305E\u308C\u306E\u5834\u6240", + output: + "Hello-Another-Way--fc4qua05auwb3674vfr0b" + ), + + # (O) 2 + ( + input: + "\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B\u0032", + output: + "2-u9tlzr9756bt3uc0v" + ), + + # (P) MajiKoi5 + ( + input: + "\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" & + "\u308B\u0035\u79D2\u524D", + output: + "MajiKoi5-783gue6qz075azm5e" + ), + + # (Q) de + ( + input: + "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", + output: + "de-jg4avhby1noc0d" + ), + + # (R) + ( + input: + "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067", + output: + "d9juau41awczczp" + ), + + # (S) -> $1.00 <- + ( + input: + "\u002D\u003E\u0020\u0024\u0031\u002E\u0030\u0030\u0020" & + "\u003C\u002D", + output: + "-> $1.00 <--" + ) +] + +block encodeTests: + for (uni, puny) in punycode_testcases: + # Need to convert both strings to lower case, since + # some of the extended encodings use upper case, but our + # code produces only lower case. Converting just puny to + # lower is also insufficient, since some of the input characters + # are upper case. + doAssert encode(uni).toLower() == puny.toLower() + +block decodeTests: + for (uni, puny) in punycode_testcases: + doAssert decode(puny) == uni + +block decodeInvalidTest: + doAssertRaises(PunyError): discard decode("xn--w&") From 270a5a372ddcb8fa97eacdf926dd90bfe189298f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 13 Nov 2021 19:09:15 -0500 Subject: [PATCH 3142/4254] Fix undeclared 'SYS_getrandom' on emscripten (#19144) --- lib/std/sysrand.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index b35f24a72..6b354e5a3 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -164,7 +164,7 @@ elif defined(windows): result = randomBytes(addr dest[0], size) -elif defined(linux) and not defined(nimNoGetRandom): +elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten): # TODO using let, pending bootstrap >= 1.4.0 var SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong const syscallHeader = """#include From bec490016548e73f01317736ff8863f9ce6aab31 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 14 Nov 2021 19:46:21 +0800 Subject: [PATCH 3143/4254] wrong spaces (3 => 2) (#19145) --- lib/system/threads.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index a8a413bcb..0e5198035 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -190,7 +190,7 @@ when defined(windows): threadProcWrapperBody(closure) # implicitly return 0 elif defined(genode): - proc threadProcWrapper[TArg](closure: pointer) {.noconv.} = + proc threadProcWrapper[TArg](closure: pointer) {.noconv.} = threadProcWrapperBody(closure) else: proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} = From 6976d18519d102c9cc857a84a4b10b009c1e1a38 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Sun, 14 Nov 2021 03:49:30 -0800 Subject: [PATCH 3144/4254] Implement zephyr urandom and monotime (#19142) * implement urandom for Zephyr * add monotime on zephyr Co-authored-by: Jaremy Creechley --- lib/std/monotimes.nim | 7 +++++++ lib/std/sysrand.nim | 12 +++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index bd078d7c0..5c67a5d4c 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -76,6 +76,10 @@ when defined(js): elif defined(posix) and not defined(osx): import posix +when defined(zephyr): + proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "".} + proc k_ticks_to_ns_floor64(ticks: int64): int64 {.importc: "k_ticks_to_ns_floor64", header: "".} + elif defined(windows): proc QueryPerformanceCounter(res: var uint64) {. importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".} @@ -98,6 +102,9 @@ proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} = mach_timebase_info(machAbsoluteTimeFreq) result = MonoTime(ticks: ticks * machAbsoluteTimeFreq.numer div machAbsoluteTimeFreq.denom) + elif defined(zephyr): + let ticks = k_ticks_to_ns_floor64(k_uptime_ticks()) + result = MonoTime(ticks: ticks) elif defined(posix): var ts: Timespec discard clock_gettime(CLOCK_MONOTONIC, ts) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 6b354e5a3..1b7b2c024 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -63,7 +63,7 @@ when defined(posix): import posix const - batchImplOS = defined(freebsd) or defined(openbsd) or (defined(macosx) and not defined(ios)) + batchImplOS = defined(freebsd) or defined(openbsd) or defined(zephyr) or (defined(macosx) and not defined(ios)) batchSize {.used.} = 256 when batchImplOS: @@ -207,6 +207,16 @@ elif defined(openbsd): proc getRandomImpl(p: pointer, size: int): int {.inline.} = result = getentropy(p, cint(size)).int +elif defined(zephyr): + proc sys_csrand_get(dst: pointer, length: csize_t): cint {.importc: "sys_csrand_get", header: "".} + # Fill the destination buffer with cryptographically secure + # random data values + # + + proc getRandomImpl(p: pointer, size: int): int {.inline.} = + # 0 if success, -EIO if entropy reseed error + result = sys_csrand_get(p, csize_t(size)).int + elif defined(freebsd): type cssize_t {.importc: "ssize_t", header: "".} = int From 309ec7167e6ea17112901533539be0a1884c8b65 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 16 Nov 2021 15:49:04 +0100 Subject: [PATCH 3145/4254] fixes .raises inference for newSeq builtin under --gc:orc [backport] (#19158) --- lib/system/seqs_v2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 0ac51109e..0c487b31d 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin q.cap = newCap result = q -proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [].} = +proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} = when nimvm: setLen(x, newLen) else: From 92d6fb86c66ceda154972314ba695cea4aac9301 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Tue, 16 Nov 2021 11:30:07 -0800 Subject: [PATCH 3146/4254] Enable customizing PageShift to set PageSize for embedded targets (#19129) * Enable customizing PageSize (via PageShift). This enables adjusting PageSize for embedded targets without abusing cpu16. * copy nimPageXYZ settings for mmpaptest * add docs for Nim manual * add docs for Nim manual * docs tweaks Co-authored-by: Jaremy Creechley --- doc/nimc.rst | 24 ++++++++++++++++++++++++ lib/system/bitmasks.nim | 10 +++++++--- tests/mmaptest.nim | 7 +++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/doc/nimc.rst b/doc/nimc.rst index 98b754729..d35dad6c2 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -656,6 +656,30 @@ is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc` define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6) +nimPage256 / nimPage512 / nimPage1k +=================================== + +Adjust the page size for Nim's GC allocator. This enables using +`nimAllocPagesViaMalloc` on devices with less RAM. The default +page size requires too much RAM to work. + +Recommended settings: + +- < 32 kB of RAM use `nimPage256` + +- < 512 kB of RAM use `nimPage512` + +- < 2 MB of RAM use `nimPage1k` + +Initial testing hasn't shown much difference between 512B or 1kB page sizes +in terms of performance or latency. Using `nimPages256` will limit the +total amount of allocatable RAM. + +nimMemAlignTiny +=============== + +Sets `MemAlign` to `4` bytes which reduces the memory alignment +to better match some embedded devices. Nim for realtime systems ======================== diff --git a/lib/system/bitmasks.nim b/lib/system/bitmasks.nim index caf86568a..9cb57bc45 100644 --- a/lib/system/bitmasks.nim +++ b/lib/system/bitmasks.nim @@ -10,14 +10,18 @@ # Page size of the system; in most cases 4096 bytes. For exotic OS or # CPU this needs to be changed: const - PageShift = when defined(cpu16): 8 else: 12 # \ - # my tests showed no improvements for using larger page sizes. + PageShift = when defined(nimPage256) or defined(cpu16): 8 + elif defined(nimPage512): 9 + elif defined(nimPage1k): 10 + else: 12 # \ # my tests showed no improvements for using larger page sizes. + PageSize = 1 shl PageShift PageMask = PageSize-1 MemAlign = # also minimal allocatable memory block - when defined(useMalloc): + when defined(nimMemAlignTiny): 4 + elif defined(useMalloc): when defined(amd64): 16 else: 8 else: 16 diff --git a/tests/mmaptest.nim b/tests/mmaptest.nim index 7a93cdd45..33010606f 100644 --- a/tests/mmaptest.nim +++ b/tests/mmaptest.nim @@ -19,8 +19,11 @@ proc `+!!`(p: pointer, size: int): pointer {.inline.} = result = cast[pointer](cast[int](p) + size) const - PageShift = when defined(cpu16): 8 else: 12 # \ - # my tests showed no improvements for using larger page sizes. + PageShift = when defined(nimPage256) or defined(cpu16): 8 + elif defined(nimPage512): 9 + elif defined(nimPage1k): 10 + else: 12 # \ # my tests showed no improvements for using larger page sizes. + PageSize = 1 shl PageShift var p = osAllocPages(3 * PageSize) From fe46c8b5f13f854e4109183d2199b922f939548c Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 17 Nov 2021 17:15:54 +0800 Subject: [PATCH 3147/4254] fix marshal bugs in VM (#19161) [backport:1.6] --- compiler/vmmarshal.nim | 4 ++-- tests/ccgbugs/t8967.nim | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index d48d2408c..d28f0325b 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -92,7 +92,8 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; if a[i].kind == nkRange: var x = copyNode(a[i][0]) storeAny(s, t.lastSon, x, stored, conf) - while x.intVal+1 <= a[i][1].intVal: + inc x.intVal + while x.intVal <= a[i][1].intVal: s.add(", ") storeAny(s, t.lastSon, x, stored, conf) inc x.intVal @@ -231,7 +232,6 @@ proc loadAny(p: var JsonParser, t: PType, result = newNode(nkCurly) while p.kind != jsonArrayEnd and p.kind != jsonEof: result.add loadAny(p, t.lastSon, tab, cache, conf, idgen) - next(p) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") of tyPtr, tyRef: diff --git a/tests/ccgbugs/t8967.nim b/tests/ccgbugs/t8967.nim index e342b7eae..0301a2e4f 100644 --- a/tests/ccgbugs/t8967.nim +++ b/tests/ccgbugs/t8967.nim @@ -4,7 +4,11 @@ discard """ import marshal -let orig: set[char] = {'A'..'Z'} -let m = $$orig -let old = to[set[char]](m) -doAssert orig - old == {} +template main() = + let orig: set[char] = {'A'..'Z'} + let m = $$orig + let old = to[set[char]](m) + doAssert orig - old == {} + +static: main() +main() From a8611c665f26adbf7f6dd2438359b4c5d930bf86 Mon Sep 17 00:00:00 2001 From: OxFred <88140942+OxFred@users.noreply.github.com> Date: Wed, 17 Nov 2021 13:16:12 +0100 Subject: [PATCH 3148/4254] Update dependency (#19151) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index fc5c808ab..e11799e73 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -55,7 +55,7 @@ pkg "chronos", "nim c -r -d:release tests/testall", allowFailure = true # pendin pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" pkg "compactdict" -pkg "comprehension", "nimble test", "https://github.com/alehander42/comprehension" +pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension" pkg "criterion", allowFailure = true # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) pkg "datamancer" pkg "dashing", "nim c tests/functional.nim" From eb5358dcdb1b650db658def14cc8c60b4bb7c203 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Fri, 19 Nov 2021 02:19:01 -0500 Subject: [PATCH 3149/4254] Testament now checks OS, CPU, endianess, bitsizes 8-64 in discard statements (#19137) * Testament checks host/cpu in compiler/platform for discard spec statement * Remove duplicated value checks, add comments, add all cpu bit sizes and endianesses Co-authored-by: quantimnot --- testament/specs.nim | 70 ++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/testament/specs.nim b/testament/specs.nim index c7e332262..42400f22d 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -9,6 +9,7 @@ import sequtils, parseutils, strutils, os, streams, parsecfg, tables, hashes, sets +import compiler/platform type TestamentData* = ref object # better to group globals under 1 object; could group the other ones here too @@ -329,42 +330,71 @@ proc parseSpec*(filename: string): TSpec = # Valgrind only supports OSX <= 17.x result.useValgrind = disabled of "disabled": - case e.value.normalize + let value = e.value.normalize + case value of "y", "yes", "true", "1", "on": result.err = reDisabled of "n", "no", "false", "0", "off": discard - of "win", "windows": + # These values are defined in `compiler/options.isDefined` + of "win": when defined(windows): result.err = reDisabled of "linux": when defined(linux): result.err = reDisabled of "bsd": when defined(bsd): result.err = reDisabled - of "osx", "macosx": # xxx remove `macosx` alias? + of "osx": when defined(osx): result.err = reDisabled - of "unix": - when defined(unix): result.err = reDisabled - of "posix": + of "unix", "posix": when defined(posix): result.err = reDisabled + of "freebsd": + when defined(freebsd): result.err = reDisabled + of "littleendian": + when defined(littleendian): result.err = reDisabled + of "bigendian": + when defined(bigendian): result.err = reDisabled + of "cpu8", "8bit": + when defined(cpu8): result.err = reDisabled + of "cpu16", "16bit": + when defined(cpu16): result.err = reDisabled + of "cpu32", "32bit": + when defined(cpu32): result.err = reDisabled + of "cpu64", "64bit": + when defined(cpu64): result.err = reDisabled + # These values are for CI environments of "travis": # deprecated if isTravis: result.err = reDisabled of "appveyor": # deprecated if isAppVeyor: result.err = reDisabled of "azure": if isAzure: result.err = reDisabled - of "32bit": - if sizeof(int) == 4: - result.err = reDisabled - of "freebsd": - when defined(freebsd): result.err = reDisabled - of "arm64": - when defined(arm64): result.err = reDisabled - of "i386": - when defined(i386): result.err = reDisabled - of "openbsd": - when defined(openbsd): result.err = reDisabled - of "netbsd": - when defined(netbsd): result.err = reDisabled else: - result.parseErrors.addLine "cannot interpret as a bool: ", e.value + # Check whether the value exists as an OS or CPU that is + # defined in `compiler/platform`. + block checkHost: + for os in platform.OS: + # Check if the value exists as OS. + if value == os.name.normalize: + # The value exists; is it the same as the current host? + if value == hostOS.normalize: + # The value exists and is the same as the current host, + # so disable the test. + result.err = reDisabled + # The value was defined, so there is no need to check further + # values or raise an error. + break checkHost + for cpu in platform.CPU: + # Check if the value exists as CPU. + if value == cpu.name.normalize: + # The value exists; is it the same as the current host? + if value == hostCPU.normalize: + # The value exists and is the same as the current host, + # so disable the test. + result.err = reDisabled + # The value was defined, so there is no need to check further + # values or raise an error. + break checkHost + # The value doesn't exist as an OS, CPU, or any previous value + # defined in this case statement, so raise an error. + result.parseErrors.addLine "cannot interpret as a bool: ", e.value of "cmd": if e.value.startsWith("nim "): result.cmd = compilerPrefix & e.value[3..^1] From 1b143f5e79c940ba7f70e0512f36b5c61a6bc24d Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Mon, 22 Nov 2021 12:41:35 +0300 Subject: [PATCH 3150/4254] Accept nnkTypeSection from typedef macro pragmas (#19168) --- changelog.md | 29 ++++++++++++++ compiler/semstmts.nim | 18 ++++++--- doc/manual.rst | 1 + tests/pragmas/ttypedef_macro.nim | 66 ++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 tests/pragmas/ttypedef_macro.nim diff --git a/changelog.md b/changelog.md index 1636d125f..8e70513e0 100644 --- a/changelog.md +++ b/changelog.md @@ -13,7 +13,36 @@ ## Language changes +- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, + allowing multiple type definitions to be injected in place of the original type definition. + ```nim + import macros + + macro multiply(amount: static int, s: untyped): untyped = + let name = $s[0].basename + result = newNimNode(nnkTypeSection) + for i in 1 .. amount: + result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) + + type + Foo = object + Bar {.multiply: 3.} = object + x, y, z: int + Baz = object + + # becomes + + type + Foo = object + Bar1 = object + x, y, z: int + Bar2 = object + x, y, z: int + Bar3 = object + x, y, z: int + Baz = object + ``` ## Compiler changes diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4607e857a..36d76608e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1112,7 +1112,12 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = if name.kind == nkPragmaExpr: let rewritten = applyTypeSectionPragmas(c, name[1], typeDef) if rewritten != nil: - typeSection[i] = rewritten + case rewritten.kind + of nkTypeDef: + typeSection[i] = rewritten + of nkTypeSection: + typeSection.sons[i .. i] = rewritten.sons + else: illFormedAst(rewritten, c.config) typeDefLeftSidePass(c, typeSection, i) return pragma(c, s, name[1], typePragmas) @@ -1143,16 +1148,19 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = proc typeSectionLeftSidePass(c: PContext, n: PNode) = # process the symbols on the left side for the whole type section, before # we even look at the type definitions on the right - for i in 0.. Date: Tue, 23 Nov 2021 00:13:03 -0800 Subject: [PATCH 3151/4254] Implement threads on Zephyr (#19156) * pthreads setup for zephyr - enable tweak stack size - update lib/system/threads.nim - Fix int/uint in casting pointer. * add documentation and tweak flag names * add documentation and tweak flag names * fix configuration flag names * fix configuration flag names * cleanup Co-authored-by: Jaremy Creechley --- doc/nimc.rst | 9 ++++++++ lib/system/threadlocalstorage.nim | 2 ++ lib/system/threads.nim | 34 +++++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/doc/nimc.rst b/doc/nimc.rst index d35dad6c2..6be4c204e 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -681,6 +681,15 @@ nimMemAlignTiny Sets `MemAlign` to `4` bytes which reduces the memory alignment to better match some embedded devices. +Thread stack size +================= + +Nim's thread API provides a simple wrapper around more advanced +RTOS task features. Customizing the stack size and stack guard size can +be done by setting `-d:nimThreadStackSize=16384` or `-d:nimThreadStackGuard=32`. + +Currently only Zephyr and FreeRTOS support these configurations. + Nim for realtime systems ======================== diff --git a/lib/system/threadlocalstorage.nim b/lib/system/threadlocalstorage.nim index e772f270c..cea9abb42 100644 --- a/lib/system/threadlocalstorage.nim +++ b/lib/system/threadlocalstorage.nim @@ -153,6 +153,8 @@ else: proc pthread_attr_init(a1: var Pthread_attr): cint {. importc, header: pthreadh.} + proc pthread_attr_setstack*(a1: ptr Pthread_attr, a2: pointer, a3: int): cint {. + importc, header: pthreadh.} proc pthread_attr_setstacksize(a1: var Pthread_attr, a2: int): cint {. importc, header: pthreadh.} proc pthread_attr_destroy(a1: var Pthread_attr): cint {. diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 0e5198035..ac727be0a 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -47,14 +47,23 @@ when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} -const - StackGuardSize = 4096 - ThreadStackMask = - when defined(genode): - 1024*64*sizeof(int)-1 - else: - 1024*256*sizeof(int)-1 - ThreadStackSize = ThreadStackMask+1 - StackGuardSize +when defined(zephyr) or defined(freertos): + const + nimThreadStackSize {.intdefine.} = 8192 + nimThreadStackGuard {.intdefine.} = 128 + + StackGuardSize = nimThreadStackGuard + ThreadStackSize = nimThreadStackSize - nimThreadStackGuard +else: + const + StackGuardSize = 4096 + ThreadStackMask = + when defined(genode): + 1024*64*sizeof(int)-1 + else: + 1024*256*sizeof(int)-1 + + ThreadStackSize = ThreadStackMask+1 - StackGuardSize #const globalsSlot = ThreadVarSlot(0) #sysAssert checkSlot.int == globalsSlot.int @@ -321,7 +330,14 @@ else: when hasSharedHeap: t.core.stackSize = ThreadStackSize var a {.noinit.}: Pthread_attr doAssert pthread_attr_init(a) == 0 - let setstacksizeResult = pthread_attr_setstacksize(a, ThreadStackSize) + when defined(zephyr): + var + rawstk = allocShared0(ThreadStackSize + StackGuardSize) + stk = cast[pointer](cast[uint](rawstk) + StackGuardSize) + let setstacksizeResult = pthread_attr_setstack(addr a, stk, ThreadStackSize) + else: + let setstacksizeResult = pthread_attr_setstacksize(a, ThreadStackSize) + when not defined(ios): # This fails on iOS doAssert(setstacksizeResult == 0) From 040d23e799e94aa3e0c6b254f1dc708b2eada96b Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 23 Nov 2021 15:02:03 +0300 Subject: [PATCH 3152/4254] implement RST & Markdown quote blocks (#19147) * implement RST & Markdown quote blocks * compile with nim 1.0 * Fix indentation --- config/nimdoc.tex.cfg | 10 +- doc/nimdoc.css | 5 + lib/packages/docutils/rst.nim | 210 +++++++++++- lib/packages/docutils/rstast.nim | 9 +- lib/packages/docutils/rstgen.nim | 29 +- nimdoc/testproject/expected/nimdoc.out.css | 5 + tests/stdlib/trst.nim | 361 +++++++++++++++++++++ 7 files changed, 617 insertions(+), 12 deletions(-) diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 457f452dd..3912d1279 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -139,9 +139,17 @@ doc.file = """ \usepackage[most]{tcolorbox} % boxes around admonitions, code blocks, doc.item \newtcolorbox{rstadmonition}[1][]{blanker, breakable, - left=3mm, right=3mm, top=1mm, bottom=1mm, + left=3mm, right=0mm, top=1mm, bottom=1mm, before upper=\indent, parbox=false, #1} +\newtcolorbox{rstquote}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + parbox=false, + borderline west={0.3em}{0pt}{lightgray}, + borderline north={0.05em}{0pt}{lightgray}, + borderline east={0.05em}{0pt}{lightgray}, + borderline south={0.05em}{0pt}{lightgray}} + \definecolor{rstframecolor}{rgb}{0.85, 0.8, 0.6} \newtcolorbox{rstprebox}[1][]{blanker, breakable, diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 7c819ea30..0014cf196 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -567,6 +567,11 @@ blockquote { border-left: 5px solid #bbc; } +blockquote.markdown-quote { + font-size: 0.9rem; /* use rem to avoid recursion */ + font-style: normal; +} + .pre, span.tok { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; font-weight: 500; diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 2e908f4e5..4c28894fb 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -53,6 +53,8 @@ ## + field lists ## + option lists ## + indented literal blocks +## + quoted literal blocks +## + line blocks ## + simple tables ## + directives (see official documentation in `RST directives list`_): ## - ``image``, ``figure`` for including images and videos @@ -121,6 +123,7 @@ ## * Markdown code blocks ## * Markdown links ## * Markdown headlines +## * Markdown block quotes ## * using ``1`` as auto-enumerator in enumerated lists like RST ``#`` ## (auto-enumerator ``1`` can not be used with ``#`` in the same list) ## @@ -145,7 +148,7 @@ ## 2) Compatibility mode which is RST rules. ## ## .. Note:: in both modes the parser interpretes text between single -## backticks (code) identically: +## backticks (code) identically: ## backslash does not escape; the only exception: ``\`` folowed by ` ## does escape so that we can always input a single backtick ` in ## inline code. However that makes impossible to input code with @@ -156,13 +159,35 @@ ## ``\`` -- GOOD ## So single backticks can always be input: `\`` will turn to ` code ## +## .. Attention:: +## We don't support some obviously poor design choices of Markdown (or RST). +## +## - no support for the rule of 2 spaces causing a line break in Markdown +## (use RST "line blocks" syntax for making line breaks) +## +## - interpretation of Markdown block quotes is also slightly different, +## e.g. case +## +## :: +## +## >>> foo +## > bar +## >>baz +## +## is a single 3rd-level quote `foo bar baz` in original Markdown, while +## in Nim we naturally see it as 3rd-level quote `foo` + 1st level `bar` + +## 2nd level `baz`: +## +## >>> foo +## > bar +## >>baz +## ## Limitations ## ----------- ## ## * no Unicode support in character width calculations ## * body elements ## - no roman numerals in enumerated lists -## - no quoted literal blocks ## - no doctest blocks ## - no grid tables ## - some directives are missing (check official `RST directives list`_): @@ -472,6 +497,10 @@ type line: int # the last line of this style occurrence # (for error message) hasPeers: bool # has headings on the same level of hierarchy? + LiteralBlockKind = enum # RST-style literal blocks after `::` + lbNone, + lbIndentedLiteralBlock, + lbQuotedLiteralBlock LevelMap = seq[LevelInfo] # Saves for each possible title adornment # style its level in the current document. SubstitutionKind = enum @@ -1953,6 +1982,44 @@ proc parseLiteralBlock(p: var RstParser): PRstNode = inc p.idx result.add(n) +proc parseQuotedLiteralBlock(p: var RstParser): PRstNode = + result = newRstNodeA(p, rnLiteralBlock) + var n = newLeaf("") + if currentTok(p).kind == tkIndent: + var indent = currInd(p) + while currentTok(p).kind == tkIndent: inc p.idx # skip blank lines + var quoteSym = currentTok(p).symbol[0] + while true: + case currentTok(p).kind + of tkEof: + break + of tkIndent: + if currentTok(p).ival < indent: + break + elif currentTok(p).ival == indent: + if nextTok(p).kind == tkPunct and nextTok(p).symbol[0] == quoteSym: + n.text.add("\n") + inc p.idx + elif nextTok(p).kind == tkIndent: + break + else: + rstMessage(p, mwRstStyle, "no newline after quoted literal block") + break + else: + rstMessage(p, mwRstStyle, + "unexpected indentation in quoted literal block") + break + else: + n.text.add(currentTok(p).symbol) + inc p.idx + result.add(n) + +proc parseRstLiteralBlock(p: var RstParser, kind: LiteralBlockKind): PRstNode = + if kind == lbIndentedLiteralBlock: + result = parseLiteralBlock(p) + else: + result = parseQuotedLiteralBlock(p) + proc getLevel(p: var RstParser, c: char, hasOverline: bool): int = ## Returns (preliminary) heading level corresponding to `c` and ## `hasOverline`. If level does not exist, add it first. @@ -2023,6 +2090,33 @@ proc isLineBlock(p: RstParser): bool = p.tok[j].col > currentTok(p).col or p.tok[j].symbol == "\n" +proc isMarkdownBlockQuote(p: RstParser): bool = + result = currentTok(p).symbol[0] == '>' + +proc whichRstLiteralBlock(p: RstParser): LiteralBlockKind = + ## Checks that the following tokens are either Indented Literal Block or + ## Quoted Literal Block (which is not quite the same as Markdown quote block). + ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#quoted-literal-blocks + if currentTok(p).symbol == "::" and nextTok(p).kind == tkIndent: + if currInd(p) > nextTok(p).ival: + result = lbNone + if currInd(p) < nextTok(p).ival: + result = lbIndentedLiteralBlock + elif currInd(p) == nextTok(p).ival: + var i = p.idx + 1 + while p.tok[i].kind == tkIndent: inc i + const validQuotingCharacters = { + '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', + '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', + '_', '`', '{', '|', '}', '~'} + if p.tok[i].kind in {tkPunct, tkAdornment} and + p.tok[i].symbol[0] in validQuotingCharacters: + result = lbQuotedLiteralBlock + else: + result = lbNone + else: + result = lbNone + proc predNL(p: RstParser): bool = result = true if p.idx > 0: @@ -2078,6 +2172,8 @@ proc whichSection(p: RstParser): RstNodeKind = elif match(p, p.idx + 1, " a"): result = rnTable elif currentTok(p).symbol == "|" and isLineBlock(p): result = rnLineBlock + elif roSupportMarkdown in p.s.options and isMarkdownBlockQuote(p): + result = rnMarkdownBlockQuote elif match(p, p.idx + 1, "i") and isAdornmentHeadline(p, p.idx): result = rnOverline else: @@ -2090,6 +2186,8 @@ proc whichSection(p: RstParser): RstNodeKind = result = rnMarkdownTable elif currentTok(p).symbol == "|" and isLineBlock(p): result = rnLineBlock + elif roSupportMarkdown in p.s.options and isMarkdownBlockQuote(p): + result = rnMarkdownBlockQuote elif match(p, tokenAfterNewline(p), "aI") and isAdornmentHeadline(p, tokenAfterNewline(p)): result = rnHeadline @@ -2143,6 +2241,102 @@ proc parseLineBlock(p: var RstParser): PRstNode = else: break +proc parseDoc(p: var RstParser): PRstNode {.gcsafe.} + +proc getQuoteSymbol(p: RstParser, idx: int): tuple[sym: string, depth: int, tokens: int] = + result = ("", 0, 0) + var i = idx + result.sym &= p.tok[i].symbol + result.depth += p.tok[i].symbol.len + inc result.tokens + inc i + while p.tok[i].kind == tkWhite and i+1 < p.tok.len and + p.tok[i+1].kind == tkPunct and p.tok[i+1].symbol[0] == '>': + result.sym &= p.tok[i].symbol + result.sym &= p.tok[i+1].symbol + result.depth += p.tok[i+1].symbol.len + inc result.tokens, 2 + inc i, 2 + +proc parseMarkdownQuoteSegment(p: var RstParser, curSym: string, col: int): + PRstNode = + ## We define *segment* as a group of lines that starts with exactly the + ## same quote symbol. If the following lines don't contain any `>` (*lazy* + ## continuation) they considered as continuation of the current segment. + var q: RstParser # to delete `>` at a start of line and then parse normally + initParser(q, p.s) + q.col = p.col + q.line = p.line + var minCol = int.high # minimum colum num in the segment + while true: # move tokens of segment from `p` to `q` skipping `curSym` + case currentTok(p).kind + of tkEof: + break + of tkIndent: + if nextTok(p).kind in {tkIndent, tkEof}: + break + else: + if nextTok(p).symbol[0] == '>': + var (quoteSym, _, quoteTokens) = getQuoteSymbol(p, p.idx + 1) + if quoteSym == curSym: # the segment continues + var iTok = tokenAfterNewline(p, p.idx+1) + if p.tok[iTok].kind notin {tkEof, tkIndent} and + p.tok[iTok].symbol[0] != '>': + rstMessage(p, mwRstStyle, + "two or more quoted lines are followed by unquoted line " & + $(curLine(p) + 1)) + break + q.tok.add currentTok(p) + var ival = currentTok(p).ival + quoteSym.len + inc p.idx, (1 + quoteTokens) # skip newline and > > > + if currentTok(p).kind == tkWhite: + ival += currentTok(p).symbol.len + inc p.idx + # fix up previous `tkIndent`s to ival (as if >>> were not there) + var j = q.tok.len - 1 + while j >= 0 and q.tok[j].kind == tkIndent: + q.tok[j].ival = ival + dec j + else: # next segment started + break + elif currentTok(p).ival < col: + break + else: # the segment continues, a case like: + # > beginning + # continuation + q.tok.add currentTok(p) + inc p.idx + else: + if currentTok(p).col < minCol: minCol = currentTok(p).col + q.tok.add currentTok(p) + inc p.idx + q.indentStack = @[minCol] + # if initial indentation `minCol` is > 0 then final newlines + # should be omitted so that parseDoc could advance to the end of tokens: + var j = q.tok.len - 1 + while q.tok[j].kind == tkIndent: dec j + q.tok.setLen (j+1) + q.tok.add Token(kind: tkEof, line: currentTok(p).line) + result = parseDoc(q) + +proc parseMarkdownBlockQuote(p: var RstParser): PRstNode = + var (curSym, quotationDepth, quoteTokens) = getQuoteSymbol(p, p.idx) + let col = currentTok(p).col + result = newRstNodeA(p, rnMarkdownBlockQuote) + inc p.idx, quoteTokens # skip first > + while true: + var item = newRstNode(rnMarkdownBlockQuoteItem) + item.quotationDepth = quotationDepth + if currentTok(p).kind == tkWhite: inc p.idx + item.add parseMarkdownQuoteSegment(p, curSym, col) + result.add(item) + if currentTok(p).kind == tkIndent and currentTok(p).ival == col and + nextTok(p).kind != tkEof and nextTok(p).symbol[0] == '>': + (curSym, quotationDepth, quoteTokens) = getQuoteSymbol(p, p.idx + 1) + inc p.idx, (1 + quoteTokens) # skip newline and > > > + else: + break + proc parseParagraph(p: var RstParser, result: PRstNode) = while true: case currentTok(p).kind @@ -2158,16 +2352,17 @@ proc parseParagraph(p: var RstParser, result: PRstNode) = result.add newLeaf(" ") of rnLineBlock: result.addIfNotNil(parseLineBlock(p)) + of rnMarkdownBlockQuote: + result.addIfNotNil(parseMarkdownBlockQuote(p)) else: break else: break of tkPunct: - if currentTok(p).symbol == "::" and - nextTok(p).kind == tkIndent and - currInd(p) < nextTok(p).ival: + if (let literalBlockKind = whichRstLiteralBlock(p); + literalBlockKind != lbNone): result.add newLeaf(":") inc p.idx # skip '::' - result.add(parseLiteralBlock(p)) + result.add(parseRstLiteralBlock(p, literalBlockKind)) break else: parseInline(p, result) @@ -2257,8 +2452,6 @@ proc getColumns(p: var RstParser, cols: var IntSeq) = # last column has no limit: cols[L - 1] = 32000 -proc parseDoc(p: var RstParser): PRstNode {.gcsafe.} - proc parseSimpleTable(p: var RstParser): PRstNode = var cols: IntSeq @@ -2585,6 +2778,7 @@ proc parseSection(p: var RstParser, result: PRstNode) = a = parseLiteralBlock(p) of rnBulletList: a = parseBulletList(p) of rnLineBlock: a = parseLineBlock(p) + of rnMarkdownBlockQuote: a = parseMarkdownBlockQuote(p) of rnDirective: a = parseDotDot(p) of rnEnumList: a = parseEnumList(p) of rnLeaf: rstMessage(p, meNewSectionExpected, "(syntax error)") diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index bc7b9a650..1d5da5e1c 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -32,7 +32,10 @@ type rnFieldName, # consisting of a field name ... rnFieldBody, # ... and a field body rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, - rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock, + rnOptionArgument, rnDescription, rnLiteralBlock, + rnMarkdownBlockQuote, # a quote starting from punctuation like >>> + rnMarkdownBlockQuoteItem, # a quotation block, quote lines starting with + # the same number of chars rnLineBlock, # the | thingie rnLineBlockItem, # a son of rnLineBlock - one line inside it. # When `RstNode` lineIndent="\n" the line's empty @@ -101,6 +104,8 @@ type of rnFootnote, rnCitation, rnOptionListItem: order*: int ## footnote order (for auto-symbol footnotes and ## auto-numbered ones without a label) + of rnMarkdownBlockQuoteItem: + quotationDepth*: int ## number of characters in line prefix of rnRef, rnSubstitutionReferences, rnInterpretedText, rnField, rnInlineCode, rnCodeBlock, rnFootnoteRef: info*: TLineInfo ## To have line/column info for warnings at @@ -409,6 +414,8 @@ proc treeRepr*(node: PRstNode, indent=0): string = result.add " level=" & $node.level of rnFootnote, rnCitation, rnOptionListItem: result.add (if node.order == 0: "" else: " order=" & $node.order) + of rnMarkdownBlockQuoteItem: + result.add " quotationDepth=" & $node.quotationDepth else: discard result.add (if node.anchor == "": "" else: " anchor='" & node.anchor & "'") diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 4cbd05379..dc6ca25c1 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -89,6 +89,7 @@ type onTestSnippet*: proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) escMode*: EscapeMode + curQuotationDepth: int PDoc = var RstGenerator ## Alias to type less. @@ -167,6 +168,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, g.currentSection = "" g.id = 0 g.escMode = emText + g.curQuotationDepth = 0 let fileParts = filename.splitFile if fileParts.ext == ".nim": g.currentSection = "Module " & fileParts.name @@ -1268,8 +1270,31 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnLiteralBlock: renderAux(d, n, "$1
    \n", "\n\n$2\\begin{rstpre}\n$1\n\\end{rstpre}\n\n", result) - of rnQuotedLiteralBlock: - doAssert false, "renderRstToOut" + of rnMarkdownBlockQuote: + d.curQuotationDepth = 1 + var tmp = "" + renderAux(d, n, "$1", "$1", tmp) + let itemEnding = + if d.target == outHtml: "" else: "\\end{rstquote}" + tmp.add itemEnding.repeat(d.curQuotationDepth - 1) + dispA(d.target, result, + "$1\n", + "\n\\begin{rstquote}\n$2\n$1\\end{rstquote}\n", [tmp, n.anchor.idS]) + of rnMarkdownBlockQuoteItem: + let addQuotationDepth = n.quotationDepth - d.curQuotationDepth + var itemPrefix: string # start or ending (quotation grey bar on the left) + if addQuotationDepth >= 0: + let s = + if d.target == outHtml: "
    " + else: "\\begin{rstquote}" + itemPrefix = s.repeat(addQuotationDepth) + else: + let s = + if d.target == outHtml: "
    " + else: "\\end{rstquote}" + itemPrefix = s.repeat(-addQuotationDepth) + renderAux(d, n, itemPrefix & "

    $1

    ", itemPrefix & "\n$1", result) + d.curQuotationDepth = n.quotationDepth of rnLineBlock: if n.sons.len == 1 and n.sons[0].lineIndent == "\n": # whole line block is one empty line, no need to add extra spacing diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 7c819ea30..0014cf196 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -567,6 +567,11 @@ blockquote { border-left: 5px solid #bbc; } +blockquote.markdown-quote { + font-size: 0.9rem; /* use rem to avoid recursion */ + font-style: normal; +} + .pre, span.tok { font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; font-weight: 500; diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index e4609a671..0a9eb8038 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -105,6 +105,367 @@ suite "RST parsing": rnLeaf ' ' """) + test "RST quoted literal blocks": + let expected = + dedent""" + rnInner + rnLeaf 'Paragraph' + rnLeaf ':' + rnLiteralBlock + rnLeaf '>x' + """ + + check(dedent""" + Paragraph:: + + >x""".toAst == expected) + + check(dedent""" + Paragraph:: + + >x""".toAst == expected) + + test "RST quoted literal blocks, :: at a separate line": + let expected = + dedent""" + rnInner + rnInner + rnLeaf 'Paragraph' + rnLiteralBlock + rnLeaf '>x + >>y' + """ + + check(dedent""" + Paragraph + + :: + + >x + >>y""".toAst == expected) + + check(dedent""" + Paragraph + + :: + + >x + >>y""".toAst == expected) + + test "Markdown quoted blocks": + check(dedent""" + Paragraph. + >x""".toAst == + dedent""" + rnInner + rnLeaf 'Paragraph' + rnLeaf '.' + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnLeaf 'x' + """) + + # bug #17987 + check(dedent""" + foo https://github.com/nim-lang/Nim/issues/8258 + + > bar""".toAst == + dedent""" + rnInner + rnInner + rnLeaf 'foo' + rnLeaf ' ' + rnStandaloneHyperlink + rnLeaf 'https://github.com/nim-lang/Nim/issues/8258' + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnLeaf 'bar' + """) + + let expected = dedent""" + rnInner + rnLeaf 'Paragraph' + rnLeaf '.' + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnInner + rnLeaf 'x1' + rnLeaf ' ' + rnLeaf 'x2' + rnMarkdownBlockQuoteItem quotationDepth=2 + rnInner + rnLeaf 'y1' + rnLeaf ' ' + rnLeaf 'y2' + rnMarkdownBlockQuoteItem quotationDepth=1 + rnLeaf 'z' + """ + + check(dedent""" + Paragraph. + >x1 x2 + >>y1 y2 + >z""".toAst == expected) + + check(dedent""" + Paragraph. + > x1 x2 + >> y1 y2 + > z""".toAst == expected) + + check(dedent""" + >x + >y + >z""".toAst == + dedent""" + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnInner + rnLeaf 'x' + rnLeaf ' ' + rnLeaf 'y' + rnLeaf ' ' + rnLeaf 'z' + """) + + check(dedent""" + > z + > > >y + """.toAst == + dedent""" + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnLeaf 'z' + rnMarkdownBlockQuoteItem quotationDepth=3 + rnLeaf 'y' + """) + + test "Markdown quoted blocks: lazy": + let expected = dedent""" + rnInner + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=2 + rnInner + rnLeaf 'x' + rnLeaf ' ' + rnLeaf 'continuation1' + rnLeaf ' ' + rnLeaf 'continuation2' + rnParagraph + rnLeaf 'newParagraph' + """ + check(dedent""" + >>x + continuation1 + continuation2 + + newParagraph""".toAst == expected) + + check(dedent""" + >> x + continuation1 + continuation2 + + newParagraph""".toAst == expected) + + # however mixing more than 1 non-lazy line and lazy one(s) splits quote + # in our parser, which appeared the easiest way to handle such cases: + var warnings = new seq[string] + check(dedent""" + >> x + >> continuation1 + continuation2 + + newParagraph""".toAst(warnings=warnings) == + dedent""" + rnInner + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=2 + rnLeaf 'x' + rnMarkdownBlockQuoteItem quotationDepth=2 + rnInner + rnLeaf 'continuation1' + rnLeaf ' ' + rnLeaf 'continuation2' + rnParagraph + rnLeaf 'newParagraph' + """) + check(warnings[] == @[ + "input(2, 1) Warning: RST style: two or more quoted lines " & + "are followed by unquoted line 3"]) + + test "Markdown quoted blocks: not lazy": + # here is where we deviate from CommonMark specification: 'bar' below is + # not considered as continuation of 2-level '>> foo' quote. + check(dedent""" + >>> foo + > bar + >> baz + """.toAst() == + dedent""" + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=3 + rnLeaf 'foo' + rnMarkdownBlockQuoteItem quotationDepth=1 + rnLeaf 'bar' + rnMarkdownBlockQuoteItem quotationDepth=2 + rnLeaf 'baz' + """) + + + test "Markdown quoted blocks: inline markup works": + check(dedent""" + > hi **bold** text + """.toAst == dedent""" + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnInner + rnLeaf 'hi' + rnLeaf ' ' + rnStrongEmphasis + rnLeaf 'bold' + rnLeaf ' ' + rnLeaf 'text' + """) + + test "Markdown quoted blocks: blank line separator": + let expected = dedent""" + rnInner + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnInner + rnLeaf 'x' + rnLeaf ' ' + rnLeaf 'y' + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnInner + rnLeaf 'z' + rnLeaf ' ' + rnLeaf 't' + """ + check(dedent""" + >x + >y + + > z + > t""".toAst == expected) + + check(dedent""" + >x + y + + > z + t""".toAst == expected) + + test "Markdown quoted blocks: nested body blocks/elements work #1": + let expected = dedent""" + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnBulletList + rnBulletItem + rnInner + rnLeaf 'x' + rnBulletItem + rnInner + rnLeaf 'y' + """ + + check(dedent""" + > - x + - y + """.toAst == expected) + + # TODO: if bug #17340 point 28 is resolved then this may work: + # check(dedent""" + # > - x + # - y + # """.toAst == expected) + + check(dedent""" + > - x + > - y + """.toAst == expected) + + check(dedent""" + > + > - x + > + > - y + > + """.toAst == expected) + + test "Markdown quoted blocks: nested body blocks/elements work #2": + let expected = dedent""" + rnAdmonition adType=note + [nil] + [nil] + rnDefList + rnDefItem + rnDefName + rnLeaf 'deflist' + rnLeaf ':' + rnDefBody + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=2 + rnInner + rnLeaf 'quote' + rnLeaf ' ' + rnLeaf 'continuation' + """ + + check(dedent""" + .. Note:: deflist: + >> quote + continuation + """.toAst == expected) + + check(dedent""" + .. Note:: + deflist: + >> quote + continuation + """.toAst == expected) + + check(dedent""" + .. Note:: + deflist: + >> quote + >> continuation + """.toAst == expected) + + # spaces are not significant between `>`: + check(dedent""" + .. Note:: + deflist: + > > quote + > > continuation + """.toAst == expected) + + test "Markdown quoted blocks: de-indent handled well": + check(dedent""" + > + > - x + > - y + > + > Paragraph. + """.toAst == dedent""" + rnMarkdownBlockQuote + rnMarkdownBlockQuoteItem quotationDepth=1 + rnInner + rnBlockQuote + rnBulletList + rnBulletItem + rnInner + rnLeaf 'x' + rnBulletItem + rnInner + rnLeaf 'y' + rnParagraph + rnLeaf 'Paragraph' + rnLeaf '.' + """) + test "option list has priority over definition list": check(dedent""" --defusages From 5933aece9b5f7320e8feb2ef610b59d347c74d27 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Tue, 23 Nov 2021 18:30:17 +0300 Subject: [PATCH 3153/4254] `caseStmtMacros` no longer experimental, experimental manual refactor (#19173) * `caseStmtMacros` no longer experimental, experimental manual refactor * Update doc/manual.rst * apply review suggestions * apply review Co-authored-by: Andreas Rumpf --- changelog.md | 2 + compiler/options.nim | 2 +- compiler/semstmts.nim | 8 +- doc/manual.rst | 409 ++++++++--- doc/manual_experimental.rst | 1180 +++++++++++++------------------ lib/core/macros.nim | 7 +- tests/macros/tcasestmtmacro.nim | 2 - 7 files changed, 814 insertions(+), 796 deletions(-) diff --git a/changelog.md b/changelog.md index 8e70513e0..b645bc5c7 100644 --- a/changelog.md +++ b/changelog.md @@ -43,6 +43,8 @@ x, y, z: int Baz = object ``` +- [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental, + meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. ## Compiler changes diff --git a/compiler/options.nim b/compiler/options.nim index 2feaa2d43..d8e5057f9 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -195,7 +195,7 @@ type notnil, dynamicBindSym, forLoopMacros, # not experimental anymore; remains here for backwards compatibility - caseStmtMacros, + caseStmtMacros, # ditto codeReordering, compiletimeFFI, ## This requires building nim with `-d:nimHasLibFFI` diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 36d76608e..f302dd4c3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -987,10 +987,10 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode = else: popCaseContext(c) closeScope(c) - if caseStmtMacros in c.features: - result = handleCaseStmtMacro(c, n, flags) - if result != nil: - return result + #if caseStmtMacros in c.features: + result = handleCaseStmtMacro(c, n, flags) + if result != nil: + return result localError(c.config, n[0].info, errSelectorMustBeOfCertainTypes) return for i in 1..`_. +See also `custom numeric literals <#custom-numeric-literals>`_. -Numeric Literals +Numeric literals ---------------- Numeric literals have the form:: @@ -625,7 +625,7 @@ Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1 instead of causing an overflow error. -Custom Numeric Literals +Custom numeric literals ~~~~~~~~~~~~~~~~~~~~~~~ If the suffix is not predefined, then the suffix is assumed to be a call @@ -700,26 +700,6 @@ contain a dot: `{..}` are the three tokens `{`:tok:, `..`:tok:, `}`:tok: and not the two tokens `{.`:tok:, `.}`:tok:. -Unicode Operators ------------------ - -Under the `--experimental:unicodeOperators` switch these Unicode operators are -also parsed as operators:: - - ∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ # same priority as * (multiplication) - ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔ # same priority as + (addition) - - -If enabled, Unicode operators can be combined with non-Unicode operator -symbols. The usual precedence extensions then apply, for example, `⊠=` is an -assignment like operator just like `*=` is. - -No Unicode normalization step is performed. - -**Note**: Due to parser limitations one **cannot** enable this feature via a -pragma `{.experimental: "unicodeOperators".}` reliably. - - Syntax ====== @@ -1323,46 +1303,6 @@ as `MyEnum.value`: To implement bit fields with enums see `Bit fields <#set-type-bit-fields>`_ -Overloadable enum field names ------------------------------ - -To be enabled via `{.experimental: "overloadableEnums".}`. - -Enum field names are overloadable much like routines. When an overloaded -enum field is used, it produces a closed sym choice construct, here -written as `(E|E)`. -During overload resolution the right `E` is picked, if possible. -For (array/object...) constructors the right `E` is picked, comparable to -how `[byte(1), 2, 3]` works, one needs to use `[T.E, E2, E3]`. Ambiguous -enum fields produce a static error: - -.. code-block:: nim - :test: "nim c $1" - - {.experimental: "overloadableEnums".} - - type - E1 = enum - value1, - value2 - E2 = enum - value1, - value2 = 4 - - const - Lookuptable = [ - E1.value1: "1", - value2: "2" - ] - - proc p(e: E1) = - # disambiguation in 'case' statements: - case e - of value1: echo "A" - of value2: echo "B" - - p value2 - String type ----------- @@ -1684,11 +1624,6 @@ must match the order of the tuple's definition. Different tuple-types are *equivalent* if they specify the same fields of the same type in the same order. The *names* of the fields also have to be the same. -The assignment operator for tuples copies each component. -The default assignment operator for objects copies each component. Overloading -of the assignment operator is described `here -`_. - .. code-block:: nim type @@ -1765,6 +1700,10 @@ introduce new object roots apart from `system.RootObj`. Student = ref object of Person # Error: inheritance only works with non-final objects id: int +The assignment operator for tuples and objects copies each component. +The methods to override this copying behavior are described `here +`_. + Object construction ------------------- @@ -2685,6 +2624,7 @@ Varargs matching See `Varargs <#types-varargs>`_. + iterable -------- @@ -2725,6 +2665,24 @@ available. Let `p` be an overloaded symbol. These contexts are: As usual, ambiguous matches produce a compile-time error. +Named argument overloading +-------------------------- + +Routines with the same type signature can be called individually if +a parameter has different names between them. + +.. code-block:: Nim + proc foo(x: int) = + echo "Using x: ", x + proc foo(y: int) = + echo "Using y: ", y + + foo(x = 2) # Using x: 2 + foo(y = 2) # Using y: 2 + +Not supplying the parameter name in such cases results in an +ambiguity error. + Statements and expressions ========================== @@ -3200,7 +3158,7 @@ Return statement Example: .. code-block:: nim - return 40+2 + return 40 + 2 The `return` statement ends the execution of the current procedure. It is only allowed in procedures. If there is an `expr`, this is syntactic @@ -3836,8 +3794,8 @@ behavior inside loop bodies. See `closureScope `_ and `capture `_ for details on how to change this behavior. -Anonymous Procs ---------------- +Anonymous procedures +-------------------- Unnamed procedures can be used as lambda expressions to pass into other procedures: @@ -3845,8 +3803,8 @@ procedures: .. code-block:: nim var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"] - cities.sort(proc (x,y: string): int = - cmp(x.len, y.len)) + cities.sort(proc (x, y: string): int = + cmp(x.len, y.len)) Procs as expressions can appear both as nested procs and inside top-level @@ -3854,6 +3812,42 @@ executable code. The `sugar `_ module contains the `=>` macro which enables a more succinct syntax for anonymous procedures resembling lambdas as they are in languages like JavaScript, C#, etc. +Do notation +----------- + +As a special convenience notation that keeps most elements of a +regular proc expression, the `do` keyword can be used to pass +anonymous procedures to routines: + +.. code-block:: nim + var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"] + + sort(cities) do (x, y: string) -> int: + cmp(x.len, y.len) + + # Less parentheses using the method plus command syntax: + cities = cities.map do (x: string) -> string: + "City of " & x + +`do` is written after the parentheses enclosing the regular proc params. +The proc expression represented by the `do` block is appended to the routine +call as the last argument. In calls using the command syntax, the `do` block +will bind to the immediately preceding expression rather than the command call. + +`do` with a parameter list corresponds to an anonymous `proc`, however +`do` without parameters is treated as a normal statement list. This allows +macros to receive both indented statement lists as an argument in inline +calls, as well as a direct mirror of Nim's routine syntax. + +.. code-block:: nim + # Passing a statement list to an inline macro: + macroResults.add quote do: + if not `ex`: + echo `info`, ": Check failed: ", `expString` + + # Processing a routine definition in a macro: + rpc(router, "add") do (a, b: int) -> int: + result = a + b Func ---- @@ -5133,7 +5127,7 @@ code: deletedKeys: seq[bool] -Type Classes +Type classes ------------ A type class is a special pseudo-type that can be used to match against @@ -5863,7 +5857,15 @@ twice: While macros enable advanced compile-time code transformations, they cannot change Nim's syntax. -Debug Example +**Style note:** For code readability, it is best to use the least powerful +programming construct that remains expressive. So the "check list" is: + +(1) Use an ordinary proc/iterator, if possible. +(2) Else: Use a generic proc/iterator, if possible. +(3) Else: Use a template, if possible. +(4) Else: Use a macro. + +Debug example ------------- The following example implements a powerful `debug` command that accepts a @@ -5921,7 +5923,7 @@ constructor expression. This is why `debug` iterates over all of `args`'s children. -BindSym +bindSym ------- The above `debug` macro relies on the fact that `write`, `writeLine` and @@ -5970,43 +5972,38 @@ However, the symbols `write`, `writeLine` and `stdout` are already bound and are not looked up again. As the example shows, `bindSym` does work with overloaded symbols implicitly. -Case-Of Macro -------------- +Note that the symbol names passed to `bindSym` have to be constant. The +experimental feature `dynamicBindSym` (`experimental manual +`_) +allows this value to be computed dynamically. -In Nim, it is possible to have a macro with the syntax of a *case-of* -expression just with the difference that all *of-branches* are passed to -and processed by the macro implementation. It is then up the macro -implementation to transform the *of-branches* into a valid Nim -statement. The following example should show how this feature could be -used for a lexical analyzer. +Post-statement blocks +--------------------- + +Macros can receive `of`, `elif`, `else`, `except`, `finally` and `do` +blocks (including their different forms such as `do` with routine parameters) +as arguments if called in statement form. .. code-block:: nim - import std/macros + macro performWithUndo(task, undo: untyped) = ... - macro case_token(args: varargs[untyped]): untyped = - echo args.treeRepr - # creates a lexical analyzer from regular expressions - # ... (implementation is an exercise for the reader ;-) - discard - - case_token: # this colon tells the parser it is a macro statement - of r"[A-Za-z_]+[A-Za-z_0-9]*": - return tkIdentifier - of r"0-9+": - return tkInteger - of r"[\+\-\*\?]+": - return tkOperator + performWithUndo do: + # multiple-line block of code + # to perform the task + do: + # code to undo it + + let num = 12 + # a single colon may be used if there is no initial block + match (num mod 3, num mod 5): + of (0, 0): + echo "FizzBuzz" + of (0, _): + echo "Fizz" + of (_, 0): + echo "Buzz" else: - return tkUnknown - - -**Style note**: For code readability, it is best to use the least powerful -programming construct that still suffices. So the "check list" is: - -(1) Use an ordinary proc/iterator, if possible. -(2) Else: Use a generic proc/iterator, if possible. -(3) Else: Use a template, if possible. -(4) Else: Use a macro. + echo num For loop macro @@ -6072,6 +6069,48 @@ Another example: echo a, " ", b +Case statement macros +--------------------- + +Macros named `` `case` `` can provide implementations of `case` statements +for certain types. The following is an example of such an implementation +for tuples, leveraging the existing equality operator for tuples +(as provided in `system.==`): + +.. code-block:: nim + :test: "nim c $1" + import std/macros + + macro `case`(n: tuple): untyped = + result = newTree(nnkIfStmt) + let selector = n[0] + for i in 1 ..< n.len: + let it = n[i] + case it.kind + of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr: + result.add it + of nnkOfBranch: + for j in 0..it.len-2: + let cond = newCall("==", selector, it[j]) + result.add newTree(nnkElifBranch, cond, it[^1]) + else: + error "custom 'case' for tuple cannot handle this node", it + + case ("foo", 78) + of ("foo", 78): echo "yes" + of ("bar", 88): echo "no" + else: discard + +`case` macros are subject to overload resolution. The type of the +`case` statement's selector expression is matched against the type +of the first argument of the `case` macro. Then the complete `case` +statement is passed in place of the argument and the macro is evaluated. + +In other words, the macro needs to transform the full `case` statement +but only the statement's selector expression is used to determine which +macro to call. + + Special Types ============= @@ -6959,7 +6998,8 @@ experimental pragma The `experimental` pragma enables experimental language features. Depending on the concrete feature, this means that the feature is either considered too unstable for an otherwise stable release or that the future of the feature -is uncertain (it may be removed at any time). +is uncertain (it may be removed at any time). See the +`experimental manual `_ for more details. Example: @@ -7060,6 +7100,21 @@ alignment requirement of the type are ignored. This pragma has no effect on the JS backend. +Noalias pragma +============== + +Since version 1.4 of the Nim compiler, there is a `.noalias` annotation for variables +and parameters. It is mapped directly to C/C++'s `restrict`:c: keyword and means that +the underlying pointer is pointing to a unique location in memory, no other aliases to +this location exist. It is *unchecked* that this alias restriction is followed. If the +restriction is violated, the backend optimizer is free to miscompile the code. +This is an **unsafe** language feature. + +Ideally in later versions of the language, the restriction will be enforced at +compile time. (This is also why the name `noalias` was choosen instead of a more +verbose name like `unsafeAssumeNoAlias`.) + + Volatile pragma --------------- The `volatile` pragma is for variables only. It declares the variable as @@ -7641,7 +7696,7 @@ Example: {.pragma: rtl, importc, dynlib: "client.dll", cdecl.} proc p*(a, b: int): int {.rtl.} = - result = a+b + result = a + b In the example, a new pragma named `rtl` is introduced that either imports a symbol from a dynamic library or exports the symbol for dynamic library @@ -8032,3 +8087,137 @@ Threads and exceptions The interaction between threads and exceptions is simple: A *handled* exception in one thread cannot affect any other thread. However, an *unhandled* exception in one thread terminates the whole *process*. + + +Guards and locks +================ + +Nim provides common low level concurrency mechanisms like locks, atomic +intrinsics or condition variables. + +Nim significantly improves on the safety of these features via additional +pragmas: + +1) A `guard`:idx: annotation is introduced to prevent data races. +2) Every access of a guarded memory location needs to happen in an + appropriate `locks`:idx: statement. + + +Guards and locks sections +------------------------- + +Protecting global variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Object fields and global variables can be annotated via a `guard` pragma: + +.. code-block:: nim + + var glock: TLock + var gdata {.guard: glock.}: int + +The compiler then ensures that every access of `gdata` is within a `locks` +section: + +.. code-block:: nim + + proc invalid = + # invalid: unguarded access: + echo gdata + + proc valid = + # valid access: + {.locks: [glock].}: + echo gdata + +Top level accesses to `gdata` are always allowed so that it can be initialized +conveniently. It is *assumed* (but not enforced) that every top level statement +is executed before any concurrent action happens. + +The `locks` section deliberately looks ugly because it has no runtime +semantics and should not be used directly! It should only be used in templates +that also implement some form of locking at runtime: + +.. code-block:: nim + + template lock(a: TLock; body: untyped) = + pthread_mutex_lock(a) + {.locks: [a].}: + try: + body + finally: + pthread_mutex_unlock(a) + + +The guard does not need to be of any particular type. It is flexible enough to +model low level lockfree mechanisms: + +.. code-block:: nim + + var dummyLock {.compileTime.}: int + var atomicCounter {.guard: dummyLock.}: int + + template atomicRead(x): untyped = + {.locks: [dummyLock].}: + memoryReadBarrier() + x + + echo atomicRead(atomicCounter) + + +The `locks` pragma takes a list of lock expressions `locks: [a, b, ...]` +in order to support *multi lock* statements. Why these are essential is +explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. + + +Protecting general locations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `guard` annotation can also be used to protect fields within an object. +The guard then needs to be another field within the same object or a +global variable. + +Since objects can reside on the heap or on the stack, this greatly enhances +the expressivity of the language: + +.. code-block:: nim + + type + ProtectedCounter = object + v {.guard: L.}: int + L: TLock + + proc incCounters(counters: var openArray[ProtectedCounter]) = + for i in 0..counters.high: + lock counters[i].L: + inc counters[i].v + +The access to field `x.v` is allowed since its guard `x.L` is active. +After template expansion, this amounts to: + +.. code-block:: nim + + proc incCounters(counters: var openArray[ProtectedCounter]) = + for i in 0..counters.high: + pthread_mutex_lock(counters[i].L) + {.locks: [counters[i].L].}: + try: + inc counters[i].v + finally: + pthread_mutex_unlock(counters[i].L) + +There is an analysis that checks that `counters[i].L` is the lock that +corresponds to the protected location `counters[i].v`. This analysis is called +`path analysis`:idx: because it deals with paths to locations +like `obj.field[i].fieldB[j]`. + +The path analysis is **currently unsound**, but that doesn't make it useless. +Two paths are considered equivalent if they are syntactically the same. + +This means the following compiles (for now) even though it really should not: + +.. code-block:: nim + + {.locks: [a[i].L].}: + inc i + access a[i].v diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 458512292..4ed8439df 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -19,47 +19,8 @@ Some of these are not covered by the `.experimental` pragma or one may want to use Nim libraries using these features without using them oneself. -**Note**: Unless otherwise indicated, these features are not to be removed, -but refined and overhauled. - - -Package level objects -===================== - -Every Nim module resides in a (nimble) package. An object type can be attached -to the package it resides in. If that is done, the type can be referenced from -other modules as an `incomplete`:idx: object type. This feature allows to -break up recursive type dependencies across module boundaries. Incomplete -object types are always passed `byref` and can only be used in pointer like -contexts (`var/ref/ptr IncompleteObject`) in general since the compiler does -not yet know the size of the object. To complete an incomplete object -the `package` pragma has to be used. `package` implies `byref`. - -As long as a type `T` is incomplete, neither `sizeof(T)` nor runtime -type information for `T` is available. - - -Example: - -.. code-block:: nim - - # module A (in an arbitrary package) - type - Pack.SomeObject = object ## declare as incomplete object of package 'Pack' - Triple = object - a, b, c: ref SomeObject ## pointers to incomplete objects are allowed - - ## Incomplete objects can be used as parameters: - proc myproc(x: SomeObject) = discard - - -.. code-block:: nim - - # module B (in package "Pack") - type - SomeObject* {.package.} = object ## Use 'package' to complete the object - s, t: string - x, y: int +.. note:: Unless otherwise indicated, these features are not to be removed, + but refined and overhauled. Void type @@ -105,23 +66,106 @@ The `void` type is only valid for parameters and return types; other symbols cannot have the type `void`. -Automatic dereferencing -======================= +Unicode Operators +================= -Automatic dereferencing is performed for the first argument of a routine call. -This feature has to be enabled via `{.experimental: "implicitDeref".}`: +Under the `--experimental:unicodeOperators`:option: switch, +these Unicode operators are also parsed as operators:: + + ∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ # same priority as * (multiplication) + ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔ # same priority as + (addition) + + +If enabled, Unicode operators can be combined with non-Unicode operator +symbols. The usual precedence extensions then apply, for example, `⊠=` is an +assignment like operator just like `*=` is. + +No Unicode normalization step is performed. + +.. note:: Due to parser limitations one **cannot** enable this feature via a + pragma `{.experimental: "unicodeOperators".}` reliably. + + +Overloadable enum value names +============================= + +Enabled via `{.experimental: "overloadableEnums".}`. + +Enum value names are overloadable, much like routines. If both of the enums +`T` and `U` have a member named `foo`, then the identifier `foo` corresponds +to a choice between `T.foo` and `U.foo`. During overload resolution, +the correct type of `foo` is decided from the context. If the type of `foo` is +ambiguous, a static error will be produced. + +.. code-block:: nim + :test: "nim c $1" + + {.experimental: "overloadableEnums".} + + type + E1 = enum + value1, + value2 + E2 = enum + value1, + value2 = 4 + + const + Lookuptable = [ + E1.value1: "1", + # no need to qualify value2, known to be E1.value2 + value2: "2" + ] + + proc p(e: E1) = + # disambiguation in 'case' statements: + case e + of value1: echo "A" + of value2: echo "B" + + p value2 + + +Package level objects +===================== + +Every Nim module resides in a (nimble) package. An object type can be attached +to the package it resides in. If that is done, the type can be referenced from +other modules as an `incomplete`:idx: object type. This feature allows to +break up recursive type dependencies across module boundaries. Incomplete +object types are always passed `byref` and can only be used in pointer like +contexts (`var/ref/ptr IncompleteObject`) in general, since the compiler does +not yet know the size of the object. To complete an incomplete object, +the `package` pragma has to be used. `package` implies `byref`. + +As long as a type `T` is incomplete, no runtime type information for `T` is +available. + + +Example: .. code-block:: nim - {.experimental: "implicitDeref".} + # module A (in an arbitrary package) + type + Pack.SomeObject = object # declare as incomplete object of package 'Pack' + Triple = object + a, b, c: ref SomeObject # pointers to incomplete objects are allowed - proc depth(x: NodeObj): int = ... + # Incomplete objects can be used as parameters: + proc myproc(x: SomeObject) = discard - var - n: Node - new(n) - echo n.depth - # no need to write n[].depth either + +.. code-block:: nim + + # module B (in package "Pack") + type + SomeObject* {.package.} = object # Use 'package' to complete the object + s, t: string + x, y: int + +This feature will likely be superseded in the future by support for +recursive module dependencies. Code reordering @@ -230,65 +274,30 @@ scope. Therefore, the following will *fail to compile:* a() - -Named argument overloading -========================== - -Routines with the same type signature can be called differently if a parameter -has different names. This does not need an `experimental` switch, but is an -unstable feature. - -.. code-block:: Nim - - proc foo(x: int) = - echo "Using x: ", x - proc foo(y: int) = - echo "Using y: ", y - - foo(x = 2) - # Using x: 2 - foo(y = 2) - # Using y: 2 +This feature will likely be replaced with a better solution to remove +the need for forward declarations. -Do notation -=========== +Automatic dereferencing +======================= -As a special more convenient notation, proc expressions involved in procedure -calls can use the `do` keyword: +Automatic dereferencing is performed for the first argument of a routine call. +This feature has to be enabled via `{.experimental: "implicitDeref".}`: .. code-block:: nim - sort(cities) do (x,y: string) -> int: - cmp(x.len, y.len) + {.experimental: "implicitDeref".} - # Less parenthesis using the method plus command syntax: - cities = cities.map do (x:string) -> string: - "City of " & x + type + NodeObj = object + # ... + Node = ref NodeObj - # In macros, the do notation is often used for quasi-quoting - macroResults.add quote do: - if not `ex`: - echo `info`, ": Check failed: ", `expString` + proc depth(x: NodeObj): int = ... -`do` is written after the parentheses enclosing the regular proc params. -The proc expression represented by the do block is appended to them. -In calls using the command syntax, the do block will bind to the immediately -preceding expression, transforming it in a call. - -`do` with parentheses is an anonymous `proc`; however a `do` without -parentheses is just a block of code. The `do` notation can be used to -pass multiple blocks to a macro: - -.. code-block:: nim - - macro performWithUndo(task, undo: untyped) = ... - - performWithUndo do: - # multiple-line block of code - # to perform the task - do: - # code to undo it + let n = Node() + echo n.depth + # no need to write n[].depth Special Operators @@ -297,8 +306,8 @@ Special Operators dot operators ------------- -**Note**: Dot operators are still experimental and so need to be enabled -via `{.experimental: "dotOperators".}`. +.. note:: Dot operators are still experimental and so need to be enabled + via `{.experimental: "dotOperators".}`. Nim offers a special family of dot operators that can be used to intercept and rewrite proc call and field access attempts, referring @@ -418,6 +427,314 @@ here. .. include:: manual_experimental_strictnotnil.rst +Aliasing restrictions in parameter passing +========================================== + +.. note:: The aliasing restrictions are currently not enforced by the + implementation and need to be fleshed out further. + +"Aliasing" here means that the underlying storage locations overlap in memory +at runtime. An "output parameter" is a parameter of type `var T`, +an input parameter is any parameter that is not of type `var`. + +1. Two output parameters should never be aliased. +2. An input and an output parameter should not be aliased. +3. An output parameter should never be aliased with a global or thread local + variable referenced by the called proc. +4. An input parameter should not be aliased with a global or thread local + variable updated by the called proc. + +One problem with rules 3 and 4 is that they affect specific global or thread +local variables, but Nim's effect tracking only tracks "uses no global variable" +via `.noSideEffect`. The rules 3 and 4 can also be approximated by a different rule: + +5. A global or thread local variable (or a location derived from such a location) + can only passed to a parameter of a `.noSideEffect` proc. + + +Strict funcs +============ + +Since version 1.4, a stricter definition of "side effect" is available. +In addition to the existing rule that a side effect is calling a function +with side effects, the following rule is also enforced: + +Any mutation to an object does count as a side effect if that object is reachable +via a parameter that is not declared as a `var` parameter. + +For example: + +.. code-block:: nim + + {.experimental: "strictFuncs".} + + type + Node = ref object + le, ri: Node + data: string + + func len(n: Node): int = + # valid: len does not have side effects + var it = n + while it != nil: + inc result + it = it.ri + + func mut(n: Node) = + let m = n # is the statement that connected the mutation to the parameter + m.data = "yeah" # the mutation is here + # Error: 'mut' can have side effects + # an object reachable from 'n' is potentially mutated + + +The algorithm behind this analysis is described in +the `view types section <#view-types-algorithm>`_. + + +View types +========== + +.. tip:: `--experimental:views`:option: is more effective + with `--experimental:strictFuncs`:option:. + +A view type is a type that is or contains one of the following types: + +- `lent T` (view into `T`) +- `openArray[T]` (pair of (pointer to array of `T`, size)) + +For example: + +.. code-block:: nim + + type + View1 = openArray[byte] + View2 = lent string + View3 = Table[openArray[char], int] + + +Exceptions to this rule are types constructed via `ptr` or `proc`. +For example, the following types are **not** view types: + +.. code-block:: nim + + type + NotView1 = proc (x: openArray[int]) + NotView2 = ptr openArray[char] + NotView3 = ptr array[4, lent int] + + +The mutability aspect of a view type is not part of the type but part +of the locations it's derived from. More on this later. + +A *view* is a symbol (a let, var, const, etc.) that has a view type. + +Since version 1.4, Nim allows view types to be used as local variables. +This feature needs to be enabled via `{.experimental: "views".}`. + +A local variable of a view type *borrows* from the locations and +it is statically enforced that the view does not outlive the location +it was borrowed from. + +For example: + +.. code-block:: nim + + {.experimental: "views".} + + proc take(a: openArray[int]) = + echo a.len + + proc main(s: seq[int]) = + var x: openArray[int] = s # 'x' is a view into 's' + # it is checked that 'x' does not outlive 's' and + # that 's' is not mutated. + for i in 0 .. high(x): + echo x[i] + take(x) + + take(x.toOpenArray(0, 1)) # slicing remains possible + let y = x # create a view from a view + take y + # it is checked that 'y' does not outlive 'x' and + # that 'x' is not mutated as long as 'y' lives. + + + main(@[11, 22, 33]) + + +A local variable of a view type can borrow from a location +derived from a parameter, another local variable, a global `const` or `let` +symbol or a thread-local `var` or `let`. + +Let `p` the proc that is analysed for the correctness of the borrow operation. + +Let `source` be one of: + +- A formal parameter of `p`. Note that this does not cover parameters of + inner procs. +- The `result` symbol of `p`. +- A local `var` or `let` or `const` of `p`. Note that this does + not cover locals of inner procs. +- A thread-local `var` or `let`. +- A global `let` or `const`. +- A constant array/seq/object/tuple constructor. + + +Path expressions +---------------- + +A location derived from `source` is then defined as a path expression that +has `source` as the owner. A path expression `e` is defined recursively: + +- `source` itself is a path expression. +- Container access like `e[i]` is a path expression. +- Tuple access `e[0]` is a path expression. +- Object field access `e.field` is a path expression. +- `system.toOpenArray(e, ...)` is a path expression. +- Pointer dereference `e[]` is a path expression. +- An address `addr e`, `unsafeAddr e` is a path expression. +- A type conversion `T(e)` is a path expression. +- A cast expression `cast[T](e)` is a path expression. +- `f(e, ...)` is a path expression if `f`'s return type is a view type. + Because the view can only have been borrowed from `e`, we then know + that the owner of `f(e, ...)` is `e`. + + +If a view type is used as a return type, the location must borrow from a location +that is derived from the first parameter that is passed to the proc. +See `the manual `_ +for details about how this is done for `var T`. + +A mutable view can borrow from a mutable location, an immutable view can borrow +from both a mutable or an immutable location. + +If a view borrows from a mutable location, the view can be used to update the +location. Otherwise it cannot be used for mutations. + +The *duration* of a borrow is the span of commands beginning from the assignment +to the view and ending with the last usage of the view. + +For the duration of the borrow operation, no mutations to the borrowed locations +may be performed except via the view that borrowed from the +location. The borrowed location is said to be *sealed* during the borrow. + +.. code-block:: nim + + {.experimental: "views".} + + type + Obj = object + field: string + + proc dangerous(s: var seq[Obj]) = + let v: lent Obj = s[0] # seal 's' + s.setLen 0 # prevented at compile-time because 's' is sealed. + echo v.field + + +The scope of the view does not matter: + +.. code-block:: nim + + proc valid(s: var seq[Obj]) = + let v: lent Obj = s[0] # begin of borrow + echo v.field # end of borrow + s.setLen 0 # valid because 'v' isn't used afterwards + + +The analysis requires as much precision about mutations as is reasonably obtainable, +so it is more effective with the experimental `strict funcs <#strict-funcs>`_ +feature. In other words `--experimental:views`:option: works better +with `--experimental:strictFuncs`:option:. + +The analysis is currently control flow insensitive: + +.. code-block:: nim + + proc invalid(s: var seq[Obj]) = + let v: lent Obj = s[0] + if false: + s.setLen 0 + echo v.field + +In this example, the compiler assumes that `s.setLen 0` invalidates the +borrow operation of `v` even though a human being can easily see that it +will never do that at runtime. + + +Start of a borrow +----------------- + +A borrow starts with one of the following: + +- The assignment of a non-view-type to a view-type. +- The assignment of a location that is derived from a local parameter + to a view-type. + + +End of a borrow +--------------- + +A borrow operation ends with the last usage of the view variable. + + +Reborrows +--------- + +A view `v` can borrow from multiple different locations. However, the borrow +is always the full span of `v`'s lifetime and every location that is borrowed +from is sealed during `v`'s lifetime. + + +Algorithm +--------- + +The following section is an outline of the algorithm that the current implementation +uses. The algorithm performs two traversals over the AST of the procedure or global +section of code that uses a view variable. No fixpoint iterations are performed, the +complexity of the analysis is O(N) where N is the number of nodes of the AST. + +The first pass over the AST computes the lifetime of each local variable based on +a notion of an "abstract time", in the implementation it's a simple integer that is +incremented for every visited node. + +In the second pass, information about the underlying object "graphs" is computed. +Let `v` be a parameter or a local variable. Let `G(v)` be the graph +that `v` belongs to. A graph is defined by the set of variables that belong +to the graph. Initially for all `v`: `G(v) = {v}`. Every variable can only +be part of a single graph. + +Assignments like `a = b` "connect" two variables, both variables end up in the +same graph `{a, b} = G(a) = G(b)`. Unfortunately, the pattern to look for is +much more complex than that and can involve multiple assignment targets +and sources:: + + f(x, y) = g(a, b) + +connects `x` and `y` to `a` and `b`: `G(x) = G(y) = G(a) = G(b) = {x, y, a, b}`. +A type based alias analysis rules out some of these combinations, for example +a `string` value cannot possibly be connected to a `seq[int]`. + +A pattern like `v[] = value` or `v.field = value` marks `G(v)` as mutated. +After the second pass a set of disjoint graphs was computed. + +For strict functions it is then enforced that there is no graph that is both mutated +and has an element that is an immutable parameter (that is a parameter that is not +of type `var T`). + +For borrow checking, a different set of checks is performed. Let `v` be the view +and `b` the location that is borrowed from. + +- The lifetime of `v` must not exceed `b`'s lifetime. Note: The lifetime of + a parameter is the complete proc body. +- If `v` is used for a mutation, `b` must be a mutable location too. +- During `v`'s lifetime, `G(b)` can only be modified by `v` (and only if + `v` is a mutable view). +- If `v` is `result` then `b` has to be a location derived from the first + formal parameter or from a constant location. +- A view cannot be used for a read or a write access before it was assigned to. + + Concepts ======== @@ -441,10 +758,10 @@ Concepts are written in the following form: for value in s: value is T -The concept is a match if: +The concept matches if: -a) all of the expressions within the body can be compiled for the tested type -b) all statically evaluable boolean expressions in the body must be true +a) all expressions within the body can be compiled for the tested type +b) all statically evaluable boolean expressions in the body are true The identifiers following the `concept` keyword represent instances of the currently matched type. You can apply any of the standard type modifiers such @@ -874,15 +1191,17 @@ There are 4 operations that are bound to a type: 3. Destruction 4. Deep copying for communication between threads -These operations can be *overridden* instead of *overloaded*. This means the -implementation is automatically lifted to structured types. For instance if type -`T` has an overridden assignment operator `=` this operator is also used -for assignments of the type `seq[T]`. Since these operations are bound to a -type they have to be bound to a nominal type for reasons of simplicity of -implementation: This means an overridden `deepCopy` for `ref T` is really -bound to `T` and not to `ref T`. This also means that one cannot override -`deepCopy` for both `ptr T` and `ref T` at the same time; instead a -helper distinct or object type has to be used for one pointer type. +These operations can be *overridden* instead of *overloaded*. This means that +the implementation is automatically lifted to structured types. For instance, +if the type `T` has an overridden assignment operator `=`, this operator is +also used for assignments of the type `seq[T]`. + +Since these operations are bound to a type, they have to be bound to a +nominal type for reasons of simplicity of implementation; this means an +overridden `deepCopy` for `ref T` is really bound to `T` and not to `ref T`. +This also means that one cannot override `deepCopy` for both `ptr T` and +`ref T` at the same time, instead a distinct or object helper type has to be +used for one pointer type. Assignments, moves and destruction are specified in the `destructors `_ document. @@ -902,60 +1221,29 @@ The signature has to be: proc `=deepCopy`(x: T): T -This mechanism will be used by most data structures that support shared memory -like channels to implement thread safe automatic memory management. +This mechanism will be used by most data structures that support shared memory, +like channels, to implement thread safe automatic memory management. The builtin `deepCopy` can even clone closures and their environments. See the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details. -Case statement macros -===================== +Dynamic arguments for bindSym +============================= -Macros named `case` can rewrite `case` statements for certain types in order to -implement `pattern matching`:idx:. The following example implements a -simplistic form of pattern matching for tuples, leveraging the existing -equality operator for tuples (as provided in `system.==`): +This experimental feature allows the symbol name argument of `macros.bindSym` +to be computed dynamically. .. code-block:: nim - :test: "nim c $1" + {.experimental: "dynamicBindSym".} - {.experimental: "caseStmtMacros".} + import macros - import std/macros + macro callOp(opName, arg1, arg2): untyped = + result = newCall(bindSym($opName), arg1, arg2) - macro `case`(n: tuple): untyped = - result = newTree(nnkIfStmt) - let selector = n[0] - for i in 1 ..< n.len: - let it = n[i] - case it.kind - of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr: - result.add it - of nnkOfBranch: - for j in 0..it.len-2: - let cond = newCall("==", selector, it[j]) - result.add newTree(nnkElifBranch, cond, it[^1]) - else: - error "custom 'case' for tuple cannot handle this node", it - - case ("foo", 78) - of ("foo", 78): echo "yes" - of ("bar", 88): echo "no" - else: discard - - -Currently case statement macros must be enabled explicitly -via `{.experimental: "caseStmtMacros".}`. - -`case` macros are subject to overload resolution. The type of the -`case` statement's selector expression is matched against the type -of the first argument of the `case` macro. Then the complete `case` -statement is passed in place of the argument and the macro is evaluated. - -In other words, the macro needs to transform the full `case` statement -but only the statement's selector expression is used to determine which -macro to call. + echo callOp("+", 1, 2) + echo callOp("-", 5, 4) Term rewriting macros @@ -968,30 +1256,30 @@ compilation pipeline with user defined optimizations: .. code-block:: nim - template optMul{`*`(a, 2)}(a: int): int = a+a + template optMul{`*`(a, 2)}(a: int): int = a + a let x = 3 echo x * 2 The compiler now rewrites `x * 2` as `x + x`. The code inside the -curlies is the pattern to match against. The operators `*`, `**`, +curly brackets is the pattern to match against. The operators `*`, `**`, `|`, `~` have a special meaning in patterns if they are written in infix notation, so to match verbatim against `*` the ordinary function call syntax needs to be used. -Term rewriting macro are applied recursively, up to a limit. This means that +Term rewriting macros are applied recursively, up to a limit. This means that if the result of a term rewriting macro is eligible for another rewriting, the compiler will try to perform it, and so on, until no more optimizations are applicable. To avoid putting the compiler into an infinite loop, there is a hard limit on how many times a single term rewriting macro can be applied. Once this limit has been passed, the term rewriting macro will be ignored. -Unfortunately optimizations are hard to get right and even the tiny example +Unfortunately optimizations are hard to get right and even this tiny example is **wrong**: .. code-block:: nim - template optMul{`*`(a, 2)}(a: int): int = a+a + template optMul{`*`(a, 2)}(a: int): int = a + a proc f(): int = echo "side effect!" @@ -1004,7 +1292,7 @@ Fortunately Nim supports side effect analysis: .. code-block:: nim - template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a + template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a + a proc f(): int = echo "side effect!" @@ -1022,13 +1310,13 @@ blindly: .. code-block:: nim - template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a + template mulIsCommutative{`*`(a, b)}(a, b: int): int = b * a What optimizers really need to do is a *canonicalization*: .. code-block:: nim - template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a + template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b * a The `int{lit}` parameter pattern matches against an expression of type `int`, but only if it's a literal. @@ -1143,7 +1431,7 @@ constant folding, so the following does not work: The reason is that the compiler already transformed the 1 into "1" for the `echo` statement. However, a term rewriting macro should not change the -semantics anyway. In fact they can be deactivated with the `--patterns:off`:option: +semantics anyway. In fact, they can be deactivated with the `--patterns:off`:option: command line option or temporarily with the `patterns` pragma. @@ -1155,7 +1443,7 @@ notation: .. code-block:: nim - template t{(0|1|2){x}}(x: untyped): untyped = x+1 + template t{(0|1|2){x}}(x: untyped): untyped = x + 1 let a = 1 # outputs 2: echo a @@ -1164,7 +1452,7 @@ notation: The `~` operator ~~~~~~~~~~~~~~~~~~ -The `~` operator is the **not** operator in patterns: +The `~` operator is the 'not' operator in patterns: .. code-block:: nim @@ -1257,14 +1545,14 @@ an `nnkArgList` node containing:: Sym "x" Sym "-" -(Which is the reverse polish notation of `x + y * z - x`.) +(This is the reverse polish notation of `x + y * z - x`.) Parameters ---------- Parameters in a pattern are type checked in the matching process. If a -parameter is of the type `varargs` it is treated specially and it can match +parameter is of the type `varargs`, it is treated specially and can match 0 or more arguments in the AST to be matched against: .. code-block:: nim @@ -1276,6 +1564,27 @@ parameter is of the type `varargs` it is treated specially and it can match w(f, x, y) +noRewrite pragma +---------------- + +Term rewriting macros and templates are currently greedy and +they will rewrite as long as there is a match. +There was no way to ensure some rewrite happens only once, +e.g. when rewriting term to same term plus extra content. + +`noRewrite` pragma can actually prevent further rewriting on marked code, +e.g. with given example `echo("ab")` will be rewritten just once: + +.. code-block:: nim + + template pwnEcho{echo(x)}(x: untyped) = + {.noRewrite.}: echo("pwned!") + + echo "ab" + +`noRewrite` pragma can be useful to control term-rewriting macros recursion. + + Example: Partial evaluation --------------------------- @@ -1319,7 +1628,7 @@ AST based overloading ===================== Parameter constraints can also be used for ordinary routine parameters; these -constraints affect ordinary overloading resolution then: +constraints then affect ordinary overloading resolution: .. code-block:: nim @@ -1356,22 +1665,25 @@ module to work. Somewhat confusingly, `spawn` is also used in the `parallel` statement with slightly different semantics. `spawn` always takes a call expression of -the form `f(a, ...)`. Let `T` be `f`'s return type. If `T` is `void` -then `spawn`'s return type is also `void` otherwise it is `FlowVar[T]`. +the form `f(a, ...)`. Let `T` be `f`'s return type. If `T` is `void`, +then `spawn`'s return type is also `void`, otherwise it is `FlowVar[T]`. -Within a `parallel` section sometimes the `FlowVar[T]` is eliminated +Within a `parallel` section, the `FlowVar[T]` is sometimes eliminated to `T`. This happens when `T` does not contain any GC'ed memory. The compiler can ensure the location in `location = spawn f(...)` is not read prematurely within a `parallel` section and so there is no need for the overhead of an indirection via `FlowVar[T]` to ensure correctness. -**Note**: Currently exceptions are not propagated between `spawn`'ed tasks! +.. note:: Currently exceptions are not propagated between `spawn`'ed tasks! + +This feature is likely to be removed in the future as external packages +can have better solutions. Spawn statement --------------- -`spawn`:idx: can be used to pass a task to the thread pool: +The `spawn`:idx: statement can be used to pass a task to the thread pool: .. code-block:: nim @@ -1393,10 +1705,10 @@ that `spawn` takes is restricted: * `f`'s parameters may not be of type `var`. This means one has to use raw `ptr`'s for data passing reminding the programmer to be careful. -* `ref` parameters are deeply copied which is a subtle semantic change and - can cause performance problems but ensures memory safety. This deep copy - is performed via `system.deepCopy` and so can be overridden. -* For *safe* data exchange between `f` and the caller a global `TChannel` +* `ref` parameters are deeply copied, which is a subtle semantic change and + can cause performance problems, but ensures memory safety. This deep copy + is performed via `system.deepCopy`, so it can be overridden. +* For *safe* data exchange between `f` and the caller, a global `Channel` needs to be used. However, since spawn can return a result, often no further communication is required. @@ -1420,10 +1732,10 @@ wait on multiple flow variables at the same time: responses.del(index) discard blockUntilAny(responses) -Data flow variables ensure that no data races -are possible. Due to technical limitations not every type `T` is possible in -a data flow variable: `T` has to be of the type `ref`, `string`, `seq` -or of a type that doesn't contain a type that is garbage collected. This +Data flow variables ensure that no data races are possible. Due to +technical limitations, not every type `T` can be used in +a data flow variable: `T` has to be a `ref`, `string`, `seq` +or of a type that doesn't contain any GC'd type. This restriction is not hard to work-around in practice. @@ -1436,14 +1748,14 @@ Example: .. code-block:: nim :test: "nim c --threads:on $1" - # Compute PI in an inefficient way + # Compute pi in an inefficient way import std/[strutils, math, threadpool] {.experimental: "parallel".} proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) proc pi(n: int): float = - var ch = newSeq[float](n+1) + var ch = newSeq[float](n + 1) parallel: for k in 0..ch.high: ch[k] = spawn term(float(k)) @@ -1454,16 +1766,16 @@ Example: The parallel statement is the preferred mechanism to introduce parallelism in a -Nim program. A subset of the Nim language is valid within a `parallel` +Nim program. Only a subset of the Nim language is valid within a `parallel` section. This subset is checked during semantic analysis to be free of data races. A sophisticated `disjoint checker`:idx: ensures that no data races are -possible even though shared memory is extensively supported! +possible, even though shared memory is extensively supported! The subset is in fact the full language with the following restrictions / changes: * `spawn` within a `parallel` section has special semantics. -* Every location of the form `a[i]` and `a[i..j]` and `dest` where +* Every location of the form `a[i]`, `a[i..j]` and `dest` where `dest` is part of the pattern `dest = spawn f(...)` has to be provably disjoint. This is called the *disjoint check*. * Every other complex location `loc` that is used in a spawned @@ -1477,152 +1789,16 @@ restrictions / changes: yet performed for ordinary slices outside of a `parallel` section. -Guards and locks -================ - -Apart from `spawn` and `parallel` Nim also provides all the common low level -concurrency mechanisms like locks, atomic intrinsics or condition variables. - -Nim significantly improves on the safety of these features via additional -pragmas: - -1) A `guard`:idx: annotation is introduced to prevent data races. -2) Every access of a guarded memory location needs to happen in an - appropriate `locks`:idx: statement. -3) Locks and routines can be annotated with `lock levels`:idx: to allow - potential deadlocks to be detected during semantic analysis. - - -Guards and the locks section ----------------------------- - -Protecting global variables -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Object fields and global variables can be annotated via a `guard` pragma: - -.. code-block:: nim - - var glock: TLock - var gdata {.guard: glock.}: int - -The compiler then ensures that every access of `gdata` is within a `locks` -section: - -.. code-block:: nim - - proc invalid = - # invalid: unguarded access: - echo gdata - - proc valid = - # valid access: - {.locks: [glock].}: - echo gdata - -Top level accesses to `gdata` are always allowed so that it can be initialized -conveniently. It is *assumed* (but not enforced) that every top level statement -is executed before any concurrent action happens. - -The `locks` section deliberately looks ugly because it has no runtime -semantics and should not be used directly! It should only be used in templates -that also implement some form of locking at runtime: - -.. code-block:: nim - - template lock(a: TLock; body: untyped) = - pthread_mutex_lock(a) - {.locks: [a].}: - try: - body - finally: - pthread_mutex_unlock(a) - - -The guard does not need to be of any particular type. It is flexible enough to -model low level lockfree mechanisms: - -.. code-block:: nim - - var dummyLock {.compileTime.}: int - var atomicCounter {.guard: dummyLock.}: int - - template atomicRead(x): untyped = - {.locks: [dummyLock].}: - memoryReadBarrier() - x - - echo atomicRead(atomicCounter) - - -The `locks` pragma takes a list of lock expressions `locks: [a, b, ...]` -in order to support *multi lock* statements. Why these are essential is -explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. - - -Protecting general locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The `guard` annotation can also be used to protect fields within an object. -The guard then needs to be another field within the same object or a -global variable. - -Since objects can reside on the heap or on the stack this greatly enhances the -expressivity of the language: - -.. code-block:: nim - - type - ProtectedCounter = object - v {.guard: L.}: int - L: TLock - - proc incCounters(counters: var openArray[ProtectedCounter]) = - for i in 0..counters.high: - lock counters[i].L: - inc counters[i].v - -The access to field `x.v` is allowed since its guard `x.L` is active. -After template expansion, this amounts to: - -.. code-block:: nim - - proc incCounters(counters: var openArray[ProtectedCounter]) = - for i in 0..counters.high: - pthread_mutex_lock(counters[i].L) - {.locks: [counters[i].L].}: - try: - inc counters[i].v - finally: - pthread_mutex_unlock(counters[i].L) - -There is an analysis that checks that `counters[i].L` is the lock that -corresponds to the protected location `counters[i].v`. This analysis is called -`path analysis`:idx: because it deals with paths to locations -like `obj.field[i].fieldB[j]`. - -The path analysis is **currently unsound**, but that doesn't make it useless. -Two paths are considered equivalent if they are syntactically the same. - -This means the following compiles (for now) even though it really should not: - -.. code-block:: nim - - {.locks: [a[i].L].}: - inc i - access a[i].v - - Lock levels ------------ +=========== Lock levels are used to enforce a global locking order in order to detect potential deadlocks during semantic analysis. A lock level is an constant integer in the range 0..1_000. Lock level 0 means that no lock is acquired at all. -If a section of code holds a lock of level `M` than it can also acquire any +If a section of code holds a lock of level `M`, it can also acquire any lock of level `N < M`. Another lock of level `M` cannot be acquired. Locks of the same level can only be acquired *at the same time* within a single `locks` section: @@ -1685,7 +1861,7 @@ This is essential so that procs can be called within a `locks` section: p() -As usual `locks` is an inferred effect and there is a subtype +As usual, `locks` is an inferred effect and there is a subtype relation: `proc () {.locks: N.}` is a subtype of `proc () {.locks: M.}` iff (M <= N). @@ -1709,346 +1885,4 @@ having unknown lock level as well: if g.memberProc != nil: g.memberProc() - -noRewrite pragma ----------------- - -Term rewriting macros and templates are currently greedy and -they will rewrite as long as there is a match. -There was no way to ensure some rewrite happens only once, -e.g. when rewriting term to same term plus extra content. - -`noRewrite` pragma can actually prevent further rewriting on marked code, -e.g. with given example `echo("ab")` will be rewritten just once: - -.. code-block:: nim - - template pwnEcho{echo(x)}(x: untyped) = - {.noRewrite.}: echo("pwned!") - - echo "ab" - -`noRewrite` pragma can be useful to control term-rewriting macros recursion. - - -Aliasing restrictions in parameter passing -========================================== - -**Note**: The aliasing restrictions are currently not enforced by the -implementation and need to be fleshed out further. - -"Aliasing" here means that the underlying storage locations overlap in memory -at runtime. An "output parameter" is a parameter of type `var T`, -an input parameter is any parameter that is not of type `var`. - -1. Two output parameters should never be aliased. -2. An input and an output parameter should not be aliased. -3. An output parameter should never be aliased with a global or thread local - variable referenced by the called proc. -4. An input parameter should not be aliased with a global or thread local - variable updated by the called proc. - -One problem with rules 3 and 4 is that they affect specific global or thread -local variables, but Nim's effect tracking only tracks "uses no global variable" -via `.noSideEffect`. The rules 3 and 4 can also be approximated by a different rule: - -5. A global or thread local variable (or a location derived from such a location) - can only passed to a parameter of a `.noSideEffect` proc. - - -Noalias annotation -================== - -Since version 1.4 of the Nim compiler, there is a `.noalias` annotation for variables -and parameters. It is mapped directly to C/C++'s `restrict`:c: keyword and means that -the underlying pointer is pointing to a unique location in memory, no other aliases to -this location exist. It is *unchecked* that this alias restriction is followed, if the -restriction is violated, the backend optimizer is free to miscompile the code. -This is an **unsafe** language feature. - -Ideally in later versions of the language, the restriction will be enforced at -compile time. (Which is also why the name `noalias` was choosen instead of a more -verbose name like `unsafeAssumeNoAlias`.) - - -Strict funcs -============ - -Since version 1.4 a stricter definition of "side effect" is available. In addition -to the existing rule that a side effect is calling a function with side effects -the following rule is also enforced: - -Any mutation to an object does count as a side effect if that object is reachable -via a parameter that is not declared as a `var` parameter. - -For example: - -.. code-block:: nim - - {.experimental: "strictFuncs".} - - type - Node = ref object - le, ri: Node - data: string - - func len(n: Node): int = - # valid: len does not have side effects - var it = n - while it != nil: - inc result - it = it.ri - - func mut(n: Node) = - let m = n # is the statement that connected the mutation to the parameter - m.data = "yeah" # the mutation is here - # Error: 'mut' can have side effects - # an object reachable from 'n' is potentially mutated - - -The algorithm behind this analysis is described in -the `view types section <#view-types-algorithm>`_. - - -View types -========== - -**Note**: `--experimental:views`:option: is more effective -with `--experimental:strictFuncs`:option:. - -A view type is a type that is or contains one of the following types: - -- `lent T` (view into `T`) -- `openArray[T]` (pair of (pointer to array of `T`, size)) - -For example: - -.. code-block:: nim - - type - View1 = openArray[byte] - View2 = lent string - View3 = Table[openArray[char], int] - - -Exceptions to this rule are types constructed via `ptr` or `proc`. -For example, the following types are **not** view types: - -.. code-block:: nim - - type - NotView1 = proc (x: openArray[int]) - NotView2 = ptr openArray[char] - NotView3 = ptr array[4, lent int] - - -The mutability aspect of a view type is not part of the type but part -of the locations it's derived from. More on this later. - -A *view* is a symbol (a let, var, const, etc.) that has a view type. - -Since version 1.4 Nim allows view types to be used as local variables. -This feature needs to be enabled via `{.experimental: "views".}`. - -A local variable of a view type *borrows* from the locations and -it is statically enforced that the view does not outlive the location -it was borrowed from. - -For example: - -.. code-block:: nim - - {.experimental: "views".} - - proc take(a: openArray[int]) = - echo a.len - - proc main(s: seq[int]) = - var x: openArray[int] = s # 'x' is a view into 's' - # it is checked that 'x' does not outlive 's' and - # that 's' is not mutated. - for i in 0 .. high(x): - echo x[i] - take(x) - - take(x.toOpenArray(0, 1)) # slicing remains possible - let y = x # create a view from a view - take y - # it is checked that 'y' does not outlive 'x' and - # that 'x' is not mutated as long as 'y' lives. - - - main(@[11, 22, 33]) - - -A local variable of a view type can borrow from a location -derived from a parameter, another local variable, a global `const` or `let` -symbol or a thread-local `var` or `let`. - -Let `p` the proc that is analysed for the correctness of the borrow operation. - -Let `source` be one of: - -- A formal parameter of `p`. Note that this does not cover parameters of - inner procs. -- The `result` symbol of `p`. -- A local `var` or `let` or `const` of `p`. Note that this does - not cover locals of inner procs. -- A thread-local `var` or `let`. -- A global `let` or `const`. -- A constant array/seq/object/tuple constructor. - - -Path expressions ----------------- - -A location derived from `source` is then defined as a path expression that -has `source` as the owner. A path expression `e` is defined recursively: - -- `source` itself is a path expression. -- Container access like `e[i]` is a path expression. -- Tuple access `e[0]` is a path expression. -- Object field access `e.field` is a path expression. -- `system.toOpenArray(e, ...)` is a path expression. -- Pointer dereference `e[]` is a path expression. -- An address `addr e`, `unsafeAddr e` is a path expression. -- A type conversion `T(e)` is a path expression. -- A cast expression `cast[T](e)` is a path expression. -- `f(e, ...)` is a path expression if `f`'s return type is a view type. - Because the view can only have been borrowed from `e`, we then know - that owner of `f(e, ...)` is `e`. - - -If a view type is used as a return type, the location must borrow from a location -that is derived from the first parameter that is passed to the proc. -See https://nim-lang.org/docs/manual.html#procedures-var-return-type for -details about how this is done for `var T`. - -A mutable view can borrow from a mutable location, an immutable view can borrow -from both a mutable or an immutable location. - -If a view borrows from a mutable location, the view can be used to update the -location. Otherwise it cannot be used for mutations. - -The *duration* of a borrow is the span of commands beginning from the assignment -to the view and ending with the last usage of the view. - -For the duration of the borrow operation, no mutations to the borrowed locations -may be performed except via the view that borrowed from the -location. The borrowed location is said to be *sealed* during the borrow. - -.. code-block:: nim - - {.experimental: "views".} - - type - Obj = object - field: string - - proc dangerous(s: var seq[Obj]) = - let v: lent Obj = s[0] # seal 's' - s.setLen 0 # prevented at compile-time because 's' is sealed. - echo v.field - - -The scope of the view does not matter: - -.. code-block:: nim - - proc valid(s: var seq[Obj]) = - let v: lent Obj = s[0] # begin of borrow - echo v.field # end of borrow - s.setLen 0 # valid because 'v' isn't used afterwards - - -The analysis requires as much precision about mutations as is reasonably obtainable, -so it is more effective with the experimental `strict funcs <#strict-funcs>`_ -feature. In other words `--experimental:views`:option: works better -with `--experimental:strictFuncs`:option:. - -The analysis is currently control flow insensitive: - -.. code-block:: nim - - proc invalid(s: var seq[Obj]) = - let v: lent Obj = s[0] - if false: - s.setLen 0 - echo v.field - -In this example, the compiler assumes that `s.setLen 0` invalidates the -borrow operation of `v` even though a human being can easily see that it -will never do that at runtime. - - -Start of a borrow ------------------ - -A borrow starts with one of the following: - -- The assignment of a non-view-type to a view-type. -- The assignment of a location that is derived from a local parameter - to a view-type. - - -End of a borrow ---------------- - -A borrow operation ends with the last usage of the view variable. - - -Reborrows ---------- - -A view `v` can borrow from multiple different locations. However, the borrow -is always the full span of `v`'s lifetime and every location that is borrowed -from is sealed during `v`'s lifetime. - - -Algorithm ---------- - -The following section is an outline of the algorithm that the current implementation -uses. The algorithm performs two traversals over the AST of the procedure or global -section of code that uses a view variable. No fixpoint iterations are performed, the -complexity of the analysis is O(N) where N is the number of nodes of the AST. - -The first pass over the AST computes the lifetime of each local variable based on -a notion of an "abstract time", in the implementation it's a simple integer that is -incremented for every visited node. - -In the second pass information about the underlying object "graphs" is computed. -Let `v` be a parameter or a local variable. Let `G(v)` be the graph -that `v` belongs to. A graph is defined by the set of variables that belong -to the graph. Initially for all `v`: `G(v) = {v}`. Every variable can only -be part of a single graph. - -Assignments like `a = b` "connect" two variables, both variables end up in the -same graph `{a, b} = G(a) = G(b)`. Unfortunately, the pattern to look for is -much more complex than that and can involve multiple assignment targets -and sources:: - - f(x, y) = g(a, b) - -connects `x` and `y` to `a` and `b`: `G(x) = G(y) = G(a) = G(b) = {x, y, a, b}`. -A type based alias analysis rules out some of these combinations, for example -a `string` value cannot possibly be connected to a `seq[int]`. - -A pattern like `v[] = value` or `v.field = value` marks `G(v)` as mutated. -After the second pass a set of disjoint graphs was computed. - -For strict functions it is then enforced that there is no graph that is both mutated -and has an element that is an immutable parameter (that is a parameter that is not -of type `var T`). - -For borrow checking a different set of checks is performed. Let `v` be the view -and `b` the location that is borrowed from. - -- The lifetime of `v` must not exceed `b`'s lifetime. Note: The lifetime of - a parameter is the complete proc body. -- If `v` is used for a mutation, `b` must be a mutable location too. -- During `v`'s lifetime, `G(b)` can only be modified by `v` (and only if - `v` is a mutable view). -- If `v` is `result` then `b` has to be a location derived from the first - formal parameter or from a constant location. -- A view cannot be used for a read or a write access before it was assigned to. +This feature may be removed in the future due to its practical difficulties. diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 6dbb92875..c7d56c0ed 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -465,12 +465,7 @@ proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {. ## If `rule == brForceOpen` always an `nnkOpenSymChoice` tree is ## returned even if the symbol is not ambiguous. ## - ## Experimental feature: - ## use {.experimental: "dynamicBindSym".} to activate it. - ## If called from template / regular code, `ident` and `rule` must be - ## constant expression / literal value. - ## If called from macros / compile time procs / static blocks, - ## `ident` and `rule` can be VM computed value. + ## See the `manual `_ for more details. proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {. magic: "NGenSym", noSideEffect.} diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim index 26519f637..32019a92a 100644 --- a/tests/macros/tcasestmtmacro.nim +++ b/tests/macros/tcasestmtmacro.nim @@ -4,8 +4,6 @@ yes ''' """ -{.experimental: "caseStmtMacros".} - import macros macro `case`(n: tuple): untyped = From 2859069dbe1c943494cb6be299b200afa748cf52 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 24 Nov 2021 09:08:07 +0300 Subject: [PATCH 3154/4254] fix #12274 (#19180) --- compiler/parser.nim | 2 +- tests/parser/t12274.nim | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/parser/t12274.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index aedf62d54..0ef6d1f54 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1146,7 +1146,7 @@ proc isExprStart(p: Parser): bool = of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor, tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCustomLit, tkVar, tkRef, tkPtr, - tkTuple, tkObject, tkWhen, tkCase, tkOut: + tkTuple, tkObject, tkWhen, tkCase, tkOut, tkTry, tkBlock: result = true else: result = false diff --git a/tests/parser/t12274.nim b/tests/parser/t12274.nim new file mode 100644 index 000000000..40c85f158 --- /dev/null +++ b/tests/parser/t12274.nim @@ -0,0 +1,9 @@ +var s: seq[int] +s.add block: + let i = 1 + i +s.add try: + 2 +except: + 3 +doAssert s == @[1, 2] From ff39f6e26062651a56d6ac4c24fe5a799c177c50 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 24 Nov 2021 10:20:15 +0300 Subject: [PATCH 3155/4254] make JS trunc polyfill opt-in, closes #16144 (#19183) --- changelog.md | 8 +++++++- lib/system/jssys.nim | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index b645bc5c7..f7f92ad3c 100644 --- a/changelog.md +++ b/changelog.md @@ -3,7 +3,13 @@ ## Changes affecting backward compatibility - +- The `Math.trunc` polyfill for targeting Internet Explorer was + previously emitted for every JavaScript output file except if + the symbol `nodejs` was defined via `-d:nodejs`. Now, it is only + emitted if the symbol `nimJsMathTruncPolyfill` is defined. If you are + targeting Internet Explorer, you may choose to enable this option + or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). Nim uses + `Math.trunc` for the division and modulo operators for integers. ## Standard library additions and changes diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index cd4f378be..250bd069d 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -763,7 +763,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce # 'Math.trunc' for Nim's ``div`` and ``mod`` operators: -const jsMathTrunc = """ +when defined(nimJsMathTruncPolyfill): + {.emit: """ if (!Math.trunc) { Math.trunc = function(v) { v = +v; @@ -771,5 +772,4 @@ if (!Math.trunc) { return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0); }; } -""" -when not defined(nodejs): {.emit: jsMathTrunc .} +""".} From c7c6b13a325958c6b55cbec2eb812eb06074101b Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 24 Nov 2021 14:22:40 +0300 Subject: [PATCH 3156/4254] parseExpr/parseStmt accept filename, fixes #13540 (#19182) --- changelog.md | 3 +++ compiler/vm.nim | 9 ++++----- compiler/vmgen.nim | 4 ++-- lib/core/macros.nim | 14 ++++++++------ tests/macros/mparsefile.nim | 4 ++++ tests/macros/tparsefile.nim | 11 +++++++++++ 6 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 tests/macros/mparsefile.nim create mode 100644 tests/macros/tparsefile.nim diff --git a/changelog.md b/changelog.md index f7f92ad3c..63c3eff40 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,9 @@ ## Standard library additions and changes +- `macros.parseExpr` and `macros.parseStmt` now accept an optional + filename argument for more informative errors. + ## `std/smtp` - Sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. diff --git a/compiler/vm.nim b/compiler/vm.nim index b64545081..d58a49f9e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1748,11 +1748,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = elif instr.opcode == opcNHint: message(c.config, info, hintUser, a.strVal) of opcParseExprToAst: - decodeB(rkNode) - # c.debug[pc].line.int - countLines(regs[rb].strVal) ? + decodeBC(rkNode) var error: string let ast = parseString(regs[rb].node.strVal, c.cache, c.config, - toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, + regs[rc].node.strVal, 0, proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) @@ -1764,10 +1763,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: regs[ra].node = ast[0] of opcParseStmtToAst: - decodeB(rkNode) + decodeBC(rkNode) var error: string let ast = parseString(regs[rb].node.strVal, c.cache, c.config, - toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, + regs[rc].node.strVal, 0, proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bb095d3ee..9a823dff4 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1225,9 +1225,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = unused(c, n, dest) genBinaryStmtVar(c, n, opcAddSeqElem) of mParseExprToAst: - genUnaryABC(c, n, dest, opcParseExprToAst) + genBinaryABC(c, n, dest, opcParseExprToAst) of mParseStmtToAst: - genUnaryABC(c, n, dest, opcParseStmtToAst) + genBinaryABC(c, n, dest, opcParseStmtToAst) of mTypeTrait: let tmp = c.genx(n[1]) if dest < 0: dest = c.getTemp(n.typ) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index c7d56c0ed..444783b5a 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -511,27 +511,29 @@ proc lineInfo*(arg: NimNode): string = ## Return line info in the form `filepath(line, column)`. $arg.lineInfoObj -proc internalParseExpr(s: string): NimNode {. +proc internalParseExpr(s, filename: string): NimNode {. magic: "ParseExprToAst", noSideEffect.} -proc internalParseStmt(s: string): NimNode {. +proc internalParseStmt(s, filename: string): NimNode {. magic: "ParseStmtToAst", noSideEffect.} proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.} ## Some builtins set an error flag. This is then turned into a proper ## exception. **Note**: Ordinary application code should not call this. -proc parseExpr*(s: string): NimNode {.noSideEffect.} = +proc parseExpr*(s: string; filename: string = ""): NimNode {.noSideEffect.} = ## Compiles the passed string to its AST representation. ## Expects a single expression. Raises `ValueError` for parsing errors. - result = internalParseExpr(s) + ## A filename can be given for more informative errors. + result = internalParseExpr(s, filename) let x = internalErrorFlag() if x.len > 0: raise newException(ValueError, x) -proc parseStmt*(s: string): NimNode {.noSideEffect.} = +proc parseStmt*(s: string; filename: string = ""): NimNode {.noSideEffect.} = ## Compiles the passed string to its AST representation. ## Expects one or more statements. Raises `ValueError` for parsing errors. - result = internalParseStmt(s) + ## A filename can be given for more informative errors. + result = internalParseStmt(s, filename) let x = internalErrorFlag() if x.len > 0: raise newException(ValueError, x) diff --git a/tests/macros/mparsefile.nim b/tests/macros/mparsefile.nim new file mode 100644 index 000000000..8ac99d568 --- /dev/null +++ b/tests/macros/mparsefile.nim @@ -0,0 +1,4 @@ +let a = 1 +let b = 2 +let c = +let d = 4 diff --git a/tests/macros/tparsefile.nim b/tests/macros/tparsefile.nim new file mode 100644 index 000000000..a41223f80 --- /dev/null +++ b/tests/macros/tparsefile.nim @@ -0,0 +1,11 @@ +import macros + +static: + let fn = "mparsefile.nim" + var raised = false + try: + discard parseStmt(staticRead(fn), filename = fn) + except ValueError as e: + raised = true + doAssert e.msg == "mparsefile.nim(4, 1) Error: invalid indentation" + doAssert raised From a0073d2d4c18f030eccef98a130f7f1f2ad9d67a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 24 Nov 2021 15:49:32 +0100 Subject: [PATCH 3157/4254] renamed 'gc' switch to 'mm'; [backport:1.6] (#19187) * renamed 'gc' switch to 'mm'; [backport:1.6] * better docs --- changelog.md | 5 +- compiler/commands.nim | 4 +- doc/advopt.txt | 7 +-- doc/backends.rst | 38 +------------- doc/destructors.rst | 12 ++--- doc/docs.rst | 4 +- doc/mm.rst | 95 ++++++++++++++++++++++++++++++++++ doc/nimc.rst | 22 ++++---- doc/{gc.rst => refc.rst} | 109 +++++++++++---------------------------- koch.nim | 2 +- tools/kochdocs.nim | 2 +- 11 files changed, 157 insertions(+), 143 deletions(-) create mode 100644 doc/mm.rst rename doc/{gc.rst => refc.rst} (62%) diff --git a/changelog.md b/changelog.md index 63c3eff40..258cf73e4 100644 --- a/changelog.md +++ b/changelog.md @@ -53,7 +53,7 @@ Baz = object ``` - [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental, - meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. + meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. ## Compiler changes @@ -63,5 +63,6 @@ ## Tool changes - +- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the + reality better. (Nim moved away from all techniques based on "tracing".) diff --git a/compiler/commands.nim b/compiler/commands.nim index a8caad916..d5c5f24e4 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -248,7 +248,7 @@ template deprecatedAlias(oldName, newName: string) = proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool = case switch.normalize - of "gc": + of "gc", "mm": case arg.normalize of "boehm": result = conf.selectedGC == gcBoehm of "refc": result = conf.selectedGC == gcRefc @@ -596,7 +596,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info) of "project": processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) - of "gc": + of "gc", "mm": if conf.backend == backendJs: return # for: bug #16033 expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: diff --git a/doc/advopt.txt b/doc/advopt.txt index 063d018d1..79e784fde 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -122,8 +122,9 @@ Advanced options: --skipUserCfg:on|off do not read the user's configuration file --skipParentCfg:on|off do not read the parent dirs' configuration files --skipProjCfg:on|off do not read the project's configuration file - --gc:refc|arc|orc|markAndSweep|boehm|go|none|regions - select the GC to use; default is 'refc' + --mm:orc|arc|refc|markAndSweep|boehm|go|none|regions + select which memory management to use; default is 'refc' + recommended is 'orc' --exceptions:setjmp|cpp|goto|quirky select the exception handling implementation --index:on|off turn index file generation on|off @@ -163,4 +164,4 @@ Advanced options: --profileVM:on|off turn compile time VM profiler on|off --sinkInference:on|off turn sink parameter inference on|off (default: on) --panics:on|off turn panics into process terminations (default: off) - --deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc`` + --deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc`` diff --git a/doc/backends.rst b/doc/backends.rst index 377e899b0..d55503d10 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -105,7 +105,7 @@ file. However, you can also run the code with `nodejs`:idx: If you experience errors saying that `globalThis` is not defined, be sure to run a recent version of Node.js (at least 12.0). - + Interfacing =========== @@ -387,14 +387,8 @@ A similar thing happens with C code invoking Nim code which returns a proc gimme(): cstring {.exportc.} = result = "Hey there C code! " & $rand(100) -Since Nim's garbage collector is not aware of the C code, once the +Since Nim's reference counting mechanism is not aware of the C code, once the `gimme` proc has finished it can reclaim the memory of the `cstring`. -However, from a practical standpoint, the C code invoking the `gimme` -function directly will be able to use it since Nim's garbage collector has -not had a chance to run *yet*. This gives you enough time to make a copy for -the C side of the program, as calling any further Nim procs *might* trigger -garbage collection making the previously returned string garbage. Or maybe you -are `yourself triggering the collection `_. Custom data types @@ -414,31 +408,3 @@ you can clean it up. And of course, once cleaned you should avoid accessing it from Nim (or C for that matter). Typically C data structures have their own `malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping these for the Nim side should be enough. - - -Thread coordination -------------------- - -When the `NimMain()` function is called Nim initializes the garbage -collector to the current thread, which is usually the main thread of your -application. If your C code later spawns a different thread and calls Nim -code, the garbage collector will fail to work properly and you will crash. - -As long as you don't use the threadvar emulation Nim uses native thread -variables, of which you get a fresh version whenever you create a thread. You -can then attach a GC to this thread via - -.. code-block:: nim - - system.setupForeignThreadGc() - -It is **not** safe to disable the garbage collector and enable it after the -call from your background thread even if the code you are calling is short -lived. - -Before the thread exits, you should tear down the thread's GC to prevent memory -leaks by calling - -.. code-block:: nim - - system.tearDownForeignThreadGc() diff --git a/doc/destructors.rst b/doc/destructors.rst index 83a50230b..c98e94536 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -43,7 +43,7 @@ written as: dealloc(x.data) proc `=trace`[T](x: var myseq[T]; env: pointer) = - # `=trace` allows the cycle collector `--gc:orc` + # `=trace` allows the cycle collector `--mm:orc` # to understand how to trace the object graph. if x.data != nil: for i in 0..`_ | Description of some tools that come with the standard distribution. -- | `GC `_ - | Additional documentation about Nim's multi-paradigm memory management strategies +- | `Memory management `_ + | Additional documentation about Nim's memory management strategies | and how to operate them in a realtime setting. - | `Source code filters `_ diff --git a/doc/mm.rst b/doc/mm.rst new file mode 100644 index 000000000..b6941a901 --- /dev/null +++ b/doc/mm.rst @@ -0,0 +1,95 @@ +======================= +Nim's Memory Management +======================= + +.. default-role:: code +.. include:: rstcommon.rst + +:Author: Andreas Rumpf +:Version: |nimversion| + +.. + + + "The road to hell is paved with good intentions." + + +Multi-paradigm Memory Management Strategies +=========================================== + +.. default-role:: option + +Nim offers multiple different memory management strategies. +To choose the memory management strategy use the `--mm:` switch. + +**The recommended switch for newly written Nim code is `--mm:orc`.** + + +ARC/ORC +------- + +`--mm:orc` is a memory management mode primarily based on reference counting. Cycles +in the object graph are handled by a "cycle collector" which is based on "trial deletion". +Since algorithms based on "tracing" are not used, the runtime behavior is oblivious to +the involved heap sizes. + +The reference counting operations (= "RC ops") do not use atomic instructions and do not have to -- +instead entire subgraphs are *moved* between threads. The Nim compiler also aggressively +optimizes away RC ops and exploits `move semantics `_. + +Nim performs a fair share of optimizations for ARC/ORC; you can inspect what it did +to your time critical function via `--expandArc:functionName`. + +`--mm:arc` uses the same mechanism as `--mm:orc`, but it leaves out the cycle collector. +Both ARC and ORC offer deterministic performance for `hard realtime`:idx: systems, but +ARC can be easier to reason about for people coming from Ada/C++/C -- roughly speaking +the memory for a variable is freed when it goes "out of scope". + +We generally advise you to use the `acyclic` annotation in order to optimize away the +cycle collector's overhead +but `--mm:orc` also produces more machine code than `--mm:arc`, so if you're on a target +where code size matters and you know that your code does not produce cycles, you can +use `--mm:arc`. Notice that the default `async`:idx: implementation produces cycles +and leaks memory with `--mm:arc`, in other words, for `async` you need to use `--mm:orc`. + + + +Other MM modes +-------------- + +.. note:: The default `refc` GC is incremental, thread-local and not "stop-the-world". + +--mm:refc This is the default memory management strategy. It's a + deferred reference counting based garbage collector + with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. + `This document `_ contains further information. +--mm:markAndSweep Simple Mark-And-Sweep based garbage collector. + Heaps are thread-local. +--mm:boehm Boehm based garbage collector, it offers a shared heap. +--mm:go Go's garbage collector, useful for interoperability with Go. + Offers a shared heap. + +--mm:none No memory management strategy nor a garbage collector. Allocated memory is + simply never freed. You should use `--mm:arc` instead. + +Here is a comparison of the different memory management modes: + +================== ======== ================= ============== =================== +Memory Management Heap Reference Cycles Stop-The-World Command line switch +================== ======== ================= ============== =================== +ORC Shared Cycle Collector No `--mm:orc` +ARC Shared Leak No `--mm:arc` +RefC Local Cycle Collector No `--mm:refc` +Mark & Sweep Local Cycle Collector No `--mm:markAndSweep` +Boehm Shared Cycle Collector Yes `--mm:boehm` +Go Shared Cycle Collector Yes `--mm:go` +None Manual Manual Manual `--mm:none` +================== ======== ================= ============== =================== + +.. default-role:: code +.. include:: rstcommon.rst + +JavaScript's garbage collector is used for the `JavaScript and NodeJS +`_ compilation targets. +The `NimScript `_ target uses the memory management strategy built into +the Nim compiler. diff --git a/doc/nimc.rst b/doc/nimc.rst index 6be4c204e..eb066e748 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -408,13 +408,13 @@ to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option: and `passL`:option: command line switches to something like: .. code-block:: cmd - nim c ... --d:nimAllocPagesViaMalloc --gc:orc --passC="-I$DEVKITPRO/libnx/include" ... + nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ... --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" or setup a ``nim.cfg`` file like so:: #nim.cfg - --gc:orc + --mm:orc --d:nimAllocPagesViaMalloc --passC="-I$DEVKITPRO/libnx/include" --passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx" @@ -485,10 +485,10 @@ Define Effect `useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's own memory manager, albeit prefixing each allocation with its size to support clearing memory on reallocation. - This only works with `--gc:none`:option:, - `--gc:arc`:option: and `--gc:orc`:option:. + This only works with `--mm:none`:option:, + `--mm:arc`:option: and `--mm:orc`:option:. `useRealtimeGC` Enables support of Nim's GC for *soft* realtime - systems. See the documentation of the `gc `_ + systems. See the documentation of the `mm `_ for further information. `logGC` Enable GC logging to stdout. `nodejs` The JS target is actually ``node.js``. @@ -614,9 +614,9 @@ A good start is to use the `any` operating target together with the .. code:: cmd - nim c --os:any --gc:arc -d:useMalloc [...] x.nim + nim c --os:any --mm:arc -d:useMalloc [...] x.nim -- `--gc:arc`:option: will enable the reference counting memory management instead +- `--mm:arc`:option: will enable the reference counting memory management instead of the default garbage collector. This enables Nim to use heap memory which is required for strings and seqs, for example. @@ -654,7 +654,7 @@ devices. This allocator gets blocks/pages of memory via a currently undocumented `osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap` is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc` define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently -only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6) +only supported with `--mm:arc` or `--mm:orc`. (Since version 1.6) nimPage256 / nimPage512 / nimPage1k =================================== @@ -681,19 +681,19 @@ nimMemAlignTiny Sets `MemAlign` to `4` bytes which reduces the memory alignment to better match some embedded devices. -Thread stack size +Thread stack size ================= Nim's thread API provides a simple wrapper around more advanced RTOS task features. Customizing the stack size and stack guard size can be done by setting `-d:nimThreadStackSize=16384` or `-d:nimThreadStackGuard=32`. -Currently only Zephyr and FreeRTOS support these configurations. +Currently only Zephyr and FreeRTOS support these configurations. Nim for realtime systems ======================== -See the documentation of Nim's soft realtime `GC `_ for further +See the `--mm:arc` or `--mm:orc` memory management settings in `MM `_ for further information. diff --git a/doc/gc.rst b/doc/refc.rst similarity index 62% rename from doc/gc.rst rename to doc/refc.rst index 5de02f73d..766097f23 100644 --- a/doc/gc.rst +++ b/doc/refc.rst @@ -1,81 +1,3 @@ -======================= -Nim's Memory Management -======================= - -.. default-role:: code -.. include:: rstcommon.rst - -:Author: Andreas Rumpf -:Version: |nimversion| - -.. - - - "The road to hell is paved with good intentions." - - -Introduction -============ - -A memory-management algorithm optimal for every use-case cannot exist. -Nim provides multiple paradigms for needs ranging from large multi-threaded -applications, to games, hard-realtime systems and small microcontrollers. - -This document describes how the management strategies work; -How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, -and how the memory management strategies other than garbage collectors work. - -.. note:: the default GC is incremental, thread-local and not "stop-the-world" - -Multi-paradigm Memory Management Strategies -=========================================== - -.. default-role:: option - -To choose the memory management strategy use the `--gc:` switch. - ---gc:refc This is the default GC. It's a - deferred reference counting based garbage collector - with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. ---gc:markAndSweep Simple Mark-And-Sweep based garbage collector. - Heaps are thread-local. ---gc:boehm Boehm based garbage collector, it offers a shared heap. ---gc:go Go's garbage collector, useful for interoperability with Go. - Offers a shared heap. ---gc:arc Plain reference counting with - `move semantic optimizations `_, offers a shared heap. - It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles - cause memory leaks, beware. - ---gc:orc Same as `--gc:arc` but adds a cycle collector based on "trial deletion". - Unfortunately, that makes its performance profile hard to reason about so it is less - useful for hard real-time systems. - ---gc:none No memory management strategy nor a garbage collector. Allocated memory is - simply never freed. You should use `--gc:arc` instead. - - -================== ======== ================= ============== =================== -Memory Management Heap Reference Cycles Stop-The-World Command line switch -================== ======== ================= ============== =================== -RefC Local Cycle Collector No `--gc:refc` -Mark & Sweep Local Cycle Collector No `--gc:markAndSweep` -ARC Shared Leak No `--gc:arc` -ORC Shared Cycle Collector No `--gc:orc` -Boehm Shared Cycle Collector Yes `--gc:boehm` -Go Shared Cycle Collector Yes `--gc:go` -None Manual Manual Manual `--gc:none` -================== ======== ================= ============== =================== - -.. default-role:: code -.. include:: rstcommon.rst - -JavaScript's garbage collector is used for the `JavaScript and NodeJS -`_ compilation targets. -The `NimScript `_ target uses the memory management strategy built into -the Nim compiler. - - Tweaking the refc GC ==================== @@ -164,6 +86,35 @@ that up to 100 objects are traversed and freed before it checks again. Thus highly specialized environments or for older hardware. +Thread coordination +------------------- + +When the `NimMain()` function is called Nim initializes the garbage +collector to the current thread, which is usually the main thread of your +application. If your C code later spawns a different thread and calls Nim +code, the garbage collector will fail to work properly and you will crash. + +As long as you don't use the threadvar emulation Nim uses native thread +variables, of which you get a fresh version whenever you create a thread. You +can then attach a GC to this thread via + +.. code-block:: nim + + system.setupForeignThreadGc() + +It is **not** safe to disable the garbage collector and enable it after the +call from your background thread even if the code you are calling is short +lived. + +Before the thread exits, you should tear down the thread's GC to prevent memory +leaks by calling + +.. code-block:: nim + + system.tearDownForeignThreadGc() + + + Keeping track of memory ======================= @@ -178,7 +129,7 @@ Other useful procs from `system `_ you can use to keep track of mem * `GC_getStatistics()` Garbage collector statistics as a human-readable string. These numbers are usually only for the running thread, not for the whole heap, -with the exception of `--gc:boehm`:option: and `--gc:go`:option:. +with the exception of `--mm:boehm`:option: and `--mm:go`:option:. In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`. diff --git a/koch.nim b/koch.nim index f87828cdc..295b1584b 100644 --- a/koch.nim +++ b/koch.nim @@ -604,7 +604,7 @@ proc runCI(cmd: string) = when not defined(bsd): # the BSDs are overwhelmed already, so only run this test on the other machines: - kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib") + kochExecFold("Boot Nim ORC", "boot -d:release --mm:orc --lib:lib") proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 70ee5ad07..4fbea8c77 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -129,7 +129,7 @@ tut2.rst tut3.rst nimc.rst niminst.rst -gc.rst +mm.rst """.splitWhitespace().mapIt("doc" / it) doc0 = """ From a59ad2006291eafcd6790f3011b5cd355b219a5b Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Wed, 24 Nov 2021 18:16:20 +0300 Subject: [PATCH 3158/4254] fix inline syntax highlighting in system.nim (#19184) --- lib/system_overview.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/system_overview.rst b/lib/system_overview.rst index df22697e0..0e4ffaf17 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -1,4 +1,5 @@ .. default-role:: code +.. include:: ../doc/rstcommon.rst The System module imports several separate modules, and their documentation is in separate files: From f91867aa31f3ae2c4f28d24547d62603daaa6d0c Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Wed, 24 Nov 2021 18:34:42 +0300 Subject: [PATCH 3159/4254] accept object type node from macros (#19179) --- compiler/semexprs.nim | 2 +- tests/macros/ttypenodes.nim | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/macros/ttypenodes.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c11cecfa9..0df332689 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2856,7 +2856,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkBind: message(c.config, n.info, warnDeprecated, "bind is deprecated") result = semExpr(c, n[0], flags) - of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy: + of nkTypeOfExpr..nkTupleClassTy, nkStaticTy, nkRefTy..nkEnumTy: if c.matchedConcept != nil and n.len == 1: let modifier = n.modifierTypeKindOfNode if modifier != tyNone: diff --git a/tests/macros/ttypenodes.nim b/tests/macros/ttypenodes.nim new file mode 100644 index 000000000..233ea9780 --- /dev/null +++ b/tests/macros/ttypenodes.nim @@ -0,0 +1,16 @@ +import macros + +macro makeEnum(): untyped = + newTree(nnkEnumTy, newEmptyNode(), ident"a", ident"b", ident"c") + +macro makeObject(): untyped = + newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), newTree(nnkRecList, + newTree(nnkIdentDefs, ident"x", ident"y", ident"int", newEmptyNode()))) + +type + Foo = makeEnum() + Bar = makeObject() + +doAssert {a, b, c} is set[Foo] +let bar = Bar(x: 3, y: 4) +doAssert (bar.x, bar.y) == (3, 4) From 0d0c249074d6a1041de16108dc247396efef5513 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Wed, 24 Nov 2021 08:37:14 -0800 Subject: [PATCH 3160/4254] swap port to correct port order (#19177) Co-authored-by: Jaremy Creechley --- lib/pure/net.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 7b0ff78e7..06024e46d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -478,14 +478,14 @@ proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl = sizeof(Sockaddr_in).SockLen let s = cast[ptr Sockaddr_in](addr sa) s.sin_family = typeof(s.sin_family)(toInt(AF_INET)) - s.sin_port = port + s.sin_port = htons(port) copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr)) of IpAddressFamily.IPv6: sl = sizeof(Sockaddr_in6).SockLen let s = cast[ptr Sockaddr_in6](addr sa) s.sin6_family = typeof(s.sin6_family)(toInt(AF_INET6)) - s.sin6_port = port + s.sin6_port = htons(port) copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) From 373c909300c9ecef159666ac196e360fbd7a3ebc Mon Sep 17 00:00:00 2001 From: Iced Quinn <70673392+IcedQuinn@users.noreply.github.com> Date: Sat, 4 Dec 2021 00:42:03 -0600 Subject: [PATCH 3161/4254] feat: TLS-ALPN wrappers for OpenSSL (#19202) Co-authored-by: Iced Quinn --- lib/wrappers/openssl.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index c756fa938..00ec160cb 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -847,3 +847,17 @@ when not defined(nimDisableCertificateValidation) and not defined(windows): let cert = d2i_X509(certbytes) let encoded = cert.i2d_X509() assert encoded == certbytes + +# Application Layer Protocol Negociation extension (TLS-ALPN, RFC7301) +# Available in at least OpenSSL 1.1.1 and later, not sure if earlier +# --Iced Quinn + +proc SSL_CTX_set_alpn_protos*(ctx: SslCtx; protos: cstring; protos_len: cuint): cint {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_set_alpn_protos*(ssl: SslPtr; protos: cstring; protos_len: cuint): cint {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_set_alpn_select_cb*(ctx: SslCtx; cb: proc(ssl: SslPtr; out_proto: ptr cstring; outlen: cstring; in_proto: cstring; inlen: cuint; arg: pointer): cint {.cdecl.}; arg: pointer): cint {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_get0_alpn_selected*(ssl: SslPtr; data: ptr cstring; len: ptr cuint) {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_set_next_protos_advertised_cb*(ctx: SslCtx; cb: proc(ssl: SslPtr; out_proto: ptr cstring; outlen: ptr cuint; arg: pointer): cint {.cdecl.}; arg: pointer) {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_set_next_proto_select_cb*(ctx: SslCtx; cb: proc(s: SslPtr; out_proto: cstring; outlen: cstring; in_proto: cstring; inlen: cuint; arg: pointer): cint {.cdecl.}; arg: pointer) {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_select_next_proto*(out_proto: ptr cstring; outlen: cstring; server: cstring; server_len: cuint; client: cstring; client_len: cuint): cint {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_get0_next_proto_negotiated*(s: SslPtr; data: ptr cstring; len: ptr cuint) {.cdecl, dynlib: DLLSSLName, importc.} + From 23c117a950a3ce0e3c85d4f89409075329648230 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Dec 2021 07:42:34 +0100 Subject: [PATCH 3162/4254] misc bugfixes [backport:1.2] (#19203) --- compiler/semobjconstr.nim | 6 +++--- doc/backends.rst | 23 +++++++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 30ab76957..6d11d321e 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -366,9 +366,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = if objType.kind == tyObject: var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info)) let initResult = semConstructTypeAux(c, constrCtx, {}) - assert constrCtx.missingFields.len > 0 - localError(c.config, info, - "The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)]) + if constrCtx.missingFields.len > 0: + localError(c.config, info, + "The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)]) elif objType.kind == tyDistinct: localError(c.config, info, "The $1 distinct type doesn't have a default value." % typeToString(t)) diff --git a/doc/backends.rst b/doc/backends.rst index d55503d10..3a3359fca 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -52,7 +52,7 @@ The commands to compile to either C, C++ or Objective-C are: The most significant difference between these commands is that if you look into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m`` files, other than that all of them will produce a native binary for your -project. This allows you to take the generated code and place it directly +project. This allows you to take the generated code and place it directly into a project using any of these languages. Here are some typical command- line invocations: @@ -123,7 +123,7 @@ Nim code can interface with the backend through the `Foreign function interface `_ mainly through the `importc pragma `_. The `importc` pragma is the *generic* way of making backend symbols available -in Nim and is available in all the target backends (JavaScript too). The C++ +in Nim and is available in all the target backends (JavaScript too). The C++ or Objective-C backends have their respective `ImportCpp `_ and `ImportObjC `_ @@ -246,11 +246,6 @@ Also, C code requires you to specify a forward declaration for functions or the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. -The Nim compiler can generate a C interface header through the `--header`:option: -command-line switch. The generated header will contain all the exported -symbols and the `NimMain` proc which you need to call before any other -Nim code. - Nim invocation example from C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -269,9 +264,10 @@ Create a ``maths.c`` file with the following content: .. code-block:: c - #include "fib.h" #include + extern int fib(int a); + int main(void) { NimMain(); @@ -286,13 +282,12 @@ program: .. code:: cmd - nim c --noMain --noLinking --header:fib.h fib.nim + nim c --noMain --noLinking fib.nim gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c The first command runs the Nim compiler with three special options to avoid -generating a `main()`:c: function in the generated files, avoid linking the -object files into a final binary, and explicitly generate a header file for C -integration. All the generated files are placed into the ``nimcache`` +generating a `main()`:c: function in the generated files and to avoid linking the +object files into a final binary. All the generated files are placed into the ``nimcache`` directory. That's why the next command compiles the ``maths.c`` source plus all the ``.c`` files from ``nimcache``. In addition to this path, you also have to tell the C compiler where to find Nim's ``nimbase.h`` header file. @@ -302,12 +297,12 @@ also ask the Nim compiler to generate a statically linked library: .. code:: cmd - nim c --app:staticLib --noMain --header fib.nim + nim c --app:staticLib --noMain fib.nim gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c The Nim compiler will handle linking the source files generated in the ``nimcache`` directory into the ``libfib.nim.a`` static library, which you can -then link into your C program. Note that these commands are generic and will +then link into your C program. Note that these commands are generic and will vary for each system. For instance, on Linux systems you will likely need to use `-ldl`:option: too to link in required dlopen functionality. From d584dd5b99f4c1e32477db2dfb791d52b0139df1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Dec 2021 07:42:58 +0100 Subject: [PATCH 3163/4254] fixes #19015 [backport:1.6] (#19204) --- changelog.md | 3 +++ compiler/options.nim | 3 ++- compiler/sigmatch.nim | 3 ++- tests/misc/trfc405.nim | 3 +++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 258cf73e4..a8f1920e9 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,9 @@ or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). Nim uses `Math.trunc` for the division and modulo operators for integers. +- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via + `experimental:flexibleOptionalParams`. + ## Standard library additions and changes - `macros.parseExpr` and `macros.parseStmt` now accept an optional diff --git a/compiler/options.nim b/compiler/options.nim index d8e5057f9..383b6fa2a 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -207,7 +207,8 @@ type strictNotNil, overloadableEnums, strictEffects, - unicodeOperators + unicodeOperators, + flexibleOptionalParams LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6bc6eefe0..93be92676 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2461,7 +2461,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int if m.callee.n[f].kind != nkSym: internalError(c.config, n[a].info, "matches") noMatch() - if a >= firstArgBlock: f = max(f, m.callee.n.len - (n.len - a)) + if flexibleOptionalParams in c.features and a >= firstArgBlock: + f = max(f, m.callee.n.len - (n.len - a)) formal = m.callee.n[f].sym m.firstMismatch.kind = kTypeMismatch if containsOrIncl(marker, formal.position) and container.isNil: diff --git a/tests/misc/trfc405.nim b/tests/misc/trfc405.nim index adc39b1df..8c967eb77 100644 --- a/tests/misc/trfc405.nim +++ b/tests/misc/trfc405.nim @@ -1,3 +1,6 @@ + +{.experimental: "flexibleOptionalParams".} + # https://github.com/nim-lang/RFCs/issues/405 template main = From f90620fb325d5b5b924774ce84384cb4098ed18e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Dec 2021 07:43:20 +0100 Subject: [PATCH 3164/4254] fixes #19198 [backport:1.6] (#19209) * fixes #19198 [backport:1.6] * added a test case --- compiler/vm.nim | 6 ++++-- compiler/vmgen.nim | 28 ++++++++++++++++------------ tests/vm/tvmmisc.nim | 23 +++++++++++++++++++++-- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index d58a49f9e..3343eb781 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -434,8 +434,10 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): of tyFloat..tyFloat64: dest.intVal = int(src.floatVal) else: - let srcDist = (sizeof(src.intVal) - styp.size) * 8 - let destDist = (sizeof(dest.intVal) - desttyp.size) * 8 + let srcSize = getSize(c.config, styp) + let destSize = getSize(c.config, desttyp) + let srcDist = (sizeof(src.intVal) - srcSize) * 8 + let destDist = (sizeof(dest.intVal) - destSize) * 8 var value = cast[BiggestUInt](src.intVal) value = (value shl srcDist) shr srcDist value = (value shl destDist) shr destDist diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 9a823dff4..c0c4bac19 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -749,18 +749,20 @@ proc genNarrow(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for # other unsigned types: - if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8): - c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) - elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8): - c.gABC(n, opcNarrowS, dest, TRegister(t.size*8)) + let size = getSize(c.config, t) + if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8): + c.gABC(n, opcNarrowU, dest, TRegister(size*8)) + elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8): + c.gABC(n, opcNarrowS, dest, TRegister(size*8)) proc genNarrowU(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for # other unsigned types: + let size = getSize(c.config, t) if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or - (t.kind in {tyUInt, tyInt} and t.size < 8): - c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) + (t.kind in {tyUInt, tyInt} and size < 8): + c.gABC(n, opcNarrowU, dest, TRegister(size*8)) proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = genBinaryABC(c, n, dest, opc) @@ -1088,10 +1090,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = genBinaryABC(c, n, dest, opcShlInt) # genNarrowU modified let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) - if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8): - c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) - elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8): - c.gABC(n, opcSignExtend, dest, TRegister(t.size*8)) + let size = getSize(c.config, t) + if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8): + c.gABC(n, opcNarrowU, dest, TRegister(size*8)) + elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8): + c.gABC(n, opcSignExtend, dest, TRegister(size*8)) of mAshrI: genBinaryABC(c, n, dest, opcAshrInt) of mBitandI: genBinaryABC(c, n, dest, opcBitandInt) of mBitorI: genBinaryABC(c, n, dest, opcBitorInt) @@ -1125,8 +1128,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = genUnaryABC(c, n, dest, opcBitnotInt) #genNarrowU modified, do not narrow signed types let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) - if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8): - c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) + let size = getSize(c.config, t) + if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8): + c.gABC(n, opcNarrowU, dest, TRegister(size*8)) of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: genConv(c, n, n[1], dest) of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index f6fbde0f9..dfe086d10 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -290,10 +290,10 @@ block: # bug #10815 const a = P() doAssert $a == "" - + when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734 block: - type CharSet {.union.} = object + type CharSet {.union.} = object cs: set[char] vs: array[4, uint64] const a = Charset(cs: {'a'..'z'}) @@ -553,3 +553,22 @@ block: # bug #8015 doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)" doAssert viaProc.table[1].handler() == 100 doAssert viaProc.table[2].handler() == 200 + + +# bug #19198 + +block: + type + Foo[n: static int] = int + +block: + static: + let x = int 1 + echo x.type # Foo + +block: + static: + let x = int 1 + let y = x + 1 + # Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect] + echo y From 1cbdc1573af5db8bf555b0b6454424188c9f345c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Dec 2021 07:44:26 +0100 Subject: [PATCH 3165/4254] fixes #19159 [backport:1.6] (#19210) --- compiler/sempass2.nim | 7 ++++--- tests/effects/tstrict_effects3.nim | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 5624d7adb..d6cc4180b 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -852,13 +852,14 @@ proc trackCall(tracked: PEffects; n: PNode) = assumeTheWorst(tracked, n, op) gcsafeAndSideeffectCheck() else: - if strictEffects in tracked.c.features and a.kind == nkSym and a.sym.kind in routineKinds: + if strictEffects in tracked.c.features and a.kind == nkSym and + a.sym.kind in routineKinds: propagateEffects(tracked, n, a.sym) else: mergeRaises(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) gcsafeAndSideeffectCheck() - if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished}: + if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}: for i in 1.. Date: Sat, 4 Dec 2021 07:54:11 +0100 Subject: [PATCH 3166/4254] Improve documentation around func and method (#19207) * Improve documentation around func and method * Update doc/tut1.rst Co-authored-by: Danil Yarantsev * Update doc/tut1.rst Co-authored-by: Danil Yarantsev * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update doc/tut1.rst Co-authored-by: Zoom * Update doc/tut1.rst Co-authored-by: Zoom * Update doc/tut1.rst Co-authored-by: Zoom * Update doc/tut1.rst Co-authored-by: Zoom * Rewrite of Zooms suggestion * Update doc/tut1.rst Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Danil Yarantsev Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Zoom --- doc/tut1.rst | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index f492f12b0..2856625b7 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -595,8 +595,10 @@ Procedures To define new commands like `echo `_ and `readLine `_ in the examples, the concept of a -*procedure* is needed. (Some languages call them *methods* or *functions*.) -In Nim new procedures are defined with the `proc` keyword: +*procedure* is needed. You might be used to them being called *methods* or +*functions* in other languages, but Nim +`differentiates these concepts `_. In +Nim, new procedures are defined with the `proc` keyword: .. code-block:: nim :test: "nim c $1" @@ -874,6 +876,31 @@ The example also shows that a proc's body can consist of a single expression whose value is then returned implicitly. +Funcs and methods +----------------- + +As mentioned in the introduction, Nim differentiates between procedures, +functions, and methods, defined by the `proc`, `func`, and `method` keywords +respectively. In some ways, Nim is a bit more pedantic in its definitions than +other languages. + +Functions are closer to the concept of a pure mathematical +function, which might be familiar to you if you've ever done functional +programming. Essentially they are procedures with additional limitations set on +them: they can't access global state (except `const`) and can't produce +side-effects. The `func` keyword is basically an alias for `proc` tagged +with `{.noSideEffects.}`. Functions can still change their mutable arguments +however, which are those marked as `var`, along with any `ref` objects. + +Unlike procedures, methods are dynamically dispatched. This sounds a bit +complicated, but it is a concept closely related to inheritance and object oriented +programming. If you overload a procedure (two procedures with the same name but +of different types or with different sets of arguments are said to be overloaded), the procedure to use is determined +at compile-time. Methods, on the other hand, depend on objects that inherit from +the `RootObj`. This is something that is covered in much greater depth in +the `second part of the tutorial`_. + + Iterators ========= From 1ef945668d458163cb7116a8c936ff92b63d679d Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 5 Dec 2021 08:44:22 +0300 Subject: [PATCH 3167/4254] treat do with pragmas but no parens as proc (#19191) fixes #19188 --- compiler/parser.nim | 12 +++++++++--- doc/manual.rst | 8 ++++---- tests/parser/tdo.nim | 19 +++++++++++++++++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 0ef6d1f54..9ff847ef6 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1110,11 +1110,14 @@ proc optPragmas(p: var Parser): PNode = proc parseDoBlock(p: var Parser; info: TLineInfo): PNode = #| doBlock = 'do' paramListArrow pragma? colcom stmt - let params = parseParamList(p, retColon=false) + var params = parseParamList(p, retColon=false) let pragmas = optPragmas(p) colcom(p, result) result = parseStmt(p) - if params.kind != nkEmpty: + if params.kind != nkEmpty or pragmas.kind != nkEmpty: + if params.kind == nkEmpty: + params = newNodeP(nkFormalParams, p) + params.add(p.emptyNode) # return type result = newProcNode(nkDo, info, body = result, params = params, name = p.emptyNode, pattern = p.emptyNode, genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode) @@ -1381,7 +1384,10 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = if stmtList[0].kind == nkStmtList: stmtList = stmtList[0] stmtList.flags.incl nfBlockArg - if openingParams.kind != nkEmpty: + if openingParams.kind != nkEmpty or openingPragmas.kind != nkEmpty: + if openingParams.kind == nkEmpty: + openingParams = newNodeP(nkFormalParams, p) + openingParams.add(p.emptyNode) # return type result.add newProcNode(nkDo, stmtList.info, body = stmtList, params = openingParams, name = p.emptyNode, pattern = p.emptyNode, diff --git a/doc/manual.rst b/doc/manual.rst index 4fcc516ec..6705e673e 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3834,10 +3834,10 @@ The proc expression represented by the `do` block is appended to the routine call as the last argument. In calls using the command syntax, the `do` block will bind to the immediately preceding expression rather than the command call. -`do` with a parameter list corresponds to an anonymous `proc`, however -`do` without parameters is treated as a normal statement list. This allows -macros to receive both indented statement lists as an argument in inline -calls, as well as a direct mirror of Nim's routine syntax. +`do` with a parameter list or pragma list corresponds to an anonymous `proc`, +however `do` without parameters or pragmas is treated as a normal statement +list. This allows macros to receive both indented statement lists as an +argument in inline calls, as well as a direct mirror of Nim's routine syntax. .. code-block:: nim # Passing a statement list to an inline macro: diff --git a/tests/parser/tdo.nim b/tests/parser/tdo.nim index 7bd1f7411..382d03398 100644 --- a/tests/parser/tdo.nim +++ b/tests/parser/tdo.nim @@ -1,8 +1,12 @@ discard """ - output: '''true + output: ''' true true -true inner B''' +true +true inner B +running with pragma +ran with pragma +''' """ template withValue(a, b, c, d, e: untyped) = @@ -77,3 +81,14 @@ proc main2 = echo "true inner B" main2() + +proc withPragma(foo: int, bar: proc() {.raises: [].}) = + echo "running with pragma" + bar() + +withPragma(3) do {.raises: [].}: + echo "ran with pragma" + +doAssert not (compiles do: + withPragma(3) do {.raises: [].}: + raise newException(Exception)) From e5475768ba5b540489fb47bdb6fdd338d75175e1 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 5 Dec 2021 14:17:52 +0800 Subject: [PATCH 3168/4254] feature_request should be labelled automatically (#19215) --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index b9f7caad5..6a9afe071 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Do you want to suggest a new feature? Use this template. title: '' -labels: '' +labels: ["Feature"] assignees: '' --- From faacd63bf69561fe915f3651e6b917bb2c0e5bc2 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 6 Dec 2021 17:04:54 +0800 Subject: [PATCH 3169/4254] the title of PR should contain a brief description (#19211) In addition to an issue number, the title of a PR should contain a brief description; then users can follow the progress more easily from the title. --- doc/contributing.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/contributing.rst b/doc/contributing.rst index 07fa01714..d3b2770f3 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -10,6 +10,9 @@ Contributing Contributing happens via "Pull requests" (PR) on github. Every PR needs to be reviewed before it can be merged and the Continuous Integration should be green. +The title of a PR should contain a brief description. If it fixes an issue, +in addition to the number of the issue, the title should also contain a description +of the issue. The PR has to be approved by two core developers or by Araq. From 7e3da693f5bd8879d91ccadc469a3ec80d77a34f Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 7 Dec 2021 01:58:01 +0800 Subject: [PATCH 3170/4254] [format minor] remove unnecessary spaces (#19216) --- lib/system/atomics.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index f69cb753d..75731764b 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -73,7 +73,7 @@ when someGcc and hasThreadSupport: proc atomicCompareExchangeN*[T: AtomType](p, expected: ptr T, desired: T, weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {. - importc: "__atomic_compare_exchange_n ", nodecl.} + importc: "__atomic_compare_exchange_n", nodecl.} ## This proc implements an atomic compare and exchange operation. This compares the ## contents at p with the contents at expected and if equal, writes desired at p. ## If they are not equal, the current contents at p is written into expected. @@ -100,13 +100,13 @@ when someGcc and hasThreadSupport: proc atomicSubFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. importc: "__atomic_sub_fetch", nodecl.} proc atomicOrFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. - importc: "__atomic_or_fetch ", nodecl.} + importc: "__atomic_or_fetch", nodecl.} proc atomicAndFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. importc: "__atomic_and_fetch", nodecl.} proc atomicXorFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. importc: "__atomic_xor_fetch", nodecl.} proc atomicNandFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. - importc: "__atomic_nand_fetch ", nodecl.} + importc: "__atomic_nand_fetch", nodecl.} ## Perform the operation return the old value, all memory models are valid proc atomicFetchAdd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {. @@ -177,8 +177,8 @@ elif someVcc and hasThreadSupport: proc `==`(x1, x2: AtomMemModel): bool {.borrow.} - proc readBarrier() {.importc: "_ReadBarrier", header: "".} - proc writeBarrier() {.importc: "_WriteBarrier", header: "".} + proc readBarrier() {.importc: "_ReadBarrier", header: "".} + proc writeBarrier() {.importc: "_WriteBarrier", header: "".} proc fence*() {.importc: "_ReadWriteBarrier", header: "".} template barrier(mem: AtomMemModel) = From 0213c7313b2edf8e8ec9d81764685744e874ef84 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 6 Dec 2021 20:38:23 +0100 Subject: [PATCH 3171/4254] allow `HSlice` bounded by constants of distinct types (#19219) [backport:1.2] When creating heterogenous slices of distinct types, the compiler does not initialize the internal type's `size` before accessing it. This then leads to this crash message: ``` compiler/int128.nim(594, 11) `false` masking only implemented for 1, 2, 4 and 8 bytes [AssertionError] ``` This patch initializes the `size` properly, fixing the problem. --- compiler/semfold.nim | 16 ++++++++-------- tests/slice/tdistinct.nim | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 tests/slice/tdistinct.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 5ae91d306..d0473b5ce 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -133,7 +133,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g) of mBitnotI: if n.typ.isUnsigned: - result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, idgen, g) + result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(getSize(g.config, n.typ))), n, idgen, g) else: result = newIntNodeT(bitnot(getInt(a)), n, idgen, g) of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g) @@ -248,23 +248,23 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g) of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g) of mAddU: - let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size)) + let val = maskBytes(getInt(a) + getInt(b), int(getSize(g.config, n.typ))) result = newIntNodeT(val, n, idgen, g) of mSubU: - let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size)) + let val = maskBytes(getInt(a) - getInt(b), int(getSize(g.config, n.typ))) result = newIntNodeT(val, n, idgen, g) # echo "subU: ", val, " n: ", n, " result: ", val of mMulU: - let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size)) + let val = maskBytes(getInt(a) * getInt(b), int(getSize(g.config, n.typ))) result = newIntNodeT(val, n, idgen, g) of mModU: - let argA = maskBytes(getInt(a), int(a.typ.size)) - let argB = maskBytes(getInt(b), int(a.typ.size)) + let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ))) + let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ))) if argB != Zero: result = newIntNodeT(argA mod argB, n, idgen, g) of mDivU: - let argA = maskBytes(getInt(a), int(a.typ.size)) - let argB = maskBytes(getInt(b), int(a.typ.size)) + let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ))) + let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ))) if argB != Zero: result = newIntNodeT(argA div argB, n, idgen, g) of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g) diff --git a/tests/slice/tdistinct.nim b/tests/slice/tdistinct.nim new file mode 100644 index 000000000..d99b529a7 --- /dev/null +++ b/tests/slice/tdistinct.nim @@ -0,0 +1,2 @@ +type Foo = distinct uint64 +const slice = 0 ..< 42.Foo From ebd88725f9d899440408cc635b79041942bc4fd0 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 7 Dec 2021 05:41:42 +0800 Subject: [PATCH 3172/4254] remove `sysspawn` which is dead code (#19218) --- lib/system/sysspawn.nim | 187 ---------------------------------------- 1 file changed, 187 deletions(-) delete mode 100644 lib/system/sysspawn.nim diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim deleted file mode 100644 index c9b9a68f0..000000000 --- a/lib/system/sysspawn.nim +++ /dev/null @@ -1,187 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Implements Nim's 'spawn'. - -when not declared(NimString): - {.error: "You must not import this module explicitly".} - -{.push stackTrace:off.} - -# We declare our own condition variables here to get rid of the dummy lock -# on Windows: - -type - CondVar = object - c: SysCond - stupidLock: SysLock - counter: int - -proc createCondVar(): CondVar = - initSysCond(result.c) - initSysLock(result.stupidLock) - #acquireSys(result.stupidLock) - -proc destroyCondVar(c: var CondVar) {.inline.} = - deinitSysCond(c.c) - -proc await(cv: var CondVar) = - acquireSys(cv.stupidLock) - while cv.counter <= 0: - waitSysCond(cv.c, cv.stupidLock) - dec cv.counter - releaseSys(cv.stupidLock) - -proc signal(cv: var CondVar) = - acquireSys(cv.stupidLock) - inc cv.counter - releaseSys(cv.stupidLock) - signalSysCond(cv.c) - -type - FastCondVar = object - event, slowPath: bool - slow: CondVar - -proc createFastCondVar(): FastCondVar = - initSysCond(result.slow.c) - initSysLock(result.slow.stupidLock) - #acquireSys(result.slow.stupidLock) - result.event = false - result.slowPath = false - -proc await(cv: var FastCondVar) = - #for i in 0 .. 50: - # if cas(addr cv.event, true, false): - # # this is a HIT: Triggers > 95% in my tests. - # return - # cpuRelax() - #cv.slowPath = true - # XXX For some reason this crashes some test programs - await(cv.slow) - cv.event = false - -proc signal(cv: var FastCondVar) = - cv.event = true - #if cas(addr cv.slowPath, true, false): - signal(cv.slow) - -type - Barrier* {.compilerproc.} = object - counter: int - cv: CondVar - -proc barrierEnter*(b: ptr Barrier) {.compilerproc.} = - atomicInc b.counter - -proc barrierLeave*(b: ptr Barrier) {.compilerproc.} = - atomicDec b.counter - if b.counter <= 0: signal(b.cv) - -proc openBarrier*(b: ptr Barrier) {.compilerproc.} = - b.counter = 0 - b.cv = createCondVar() - -proc closeBarrier*(b: ptr Barrier) {.compilerproc.} = - await(b.cv) - destroyCondVar(b.cv) - -{.pop.} - -# ---------------------------------------------------------------------------- - -type - WorkerProc = proc (thread, args: pointer) {.nimcall, gcsafe.} - Worker = object - taskArrived: CondVar - taskStarted: FastCondVar #\ - # task data: - f: WorkerProc - data: pointer - ready: bool # put it here for correct alignment! - -proc nimArgsPassingDone(p: pointer) {.compilerproc.} = - let w = cast[ptr Worker](p) - signal(w.taskStarted) - -var gSomeReady = createFastCondVar() - -proc slave(w: ptr Worker) {.thread.} = - while true: - w.ready = true # If we instead signal "workerReady" we need the scheduler - # to notice this. The scheduler could then optimize the - # layout of the worker threads (e.g. keep the list sorted) - # so that no search for a "ready" thread is necessary. - # This might be implemented later, but is more tricky than - # it looks because 'spawn' itself can run concurrently. - signal(gSomeReady) - await(w.taskArrived) - assert(not w.ready) - # shield against spurious wakeups: - if w.data != nil: - w.f(w, w.data) - w.data = nil - -const NumThreads = 4 - -var - workers: array[NumThreads, Thread[ptr Worker]] - workersData: array[NumThreads, Worker] - -proc setup() = - for i in 0 ..< NumThreads: - workersData[i].taskArrived = createCondVar() - workersData[i].taskStarted = createFastCondVar() - createThread(workers[i], slave, addr(workersData[i])) - -proc preferSpawn*(): bool = - ## Use this proc to determine quickly if a 'spawn' or a direct call is - ## preferable. If it returns 'true' a 'spawn' may make sense. In general - ## it is not necessary to call this directly; use 'spawnX' instead. - result = gSomeReady.event - -proc spawn*(call: typed) {.magic: "Spawn".} - ## always spawns a new task, so that the 'call' is never executed on - ## the calling thread. 'call' has to be proc call 'p(...)' where 'p' - ## is gcsafe and has 'void' as the return type. - -template spawnX*(call: typed) = - ## spawns a new task if a CPU core is ready, otherwise executes the - ## call in the calling thread. Usually it is advised to - ## use 'spawn' in order to not block the producer for an unknown - ## amount of time. 'call' has to be proc call 'p(...)' where 'p' - ## is gcsafe and has 'void' as the return type. - if preferSpawn(): spawn call - else: call - -proc nimSpawn(fn: WorkerProc; data: pointer) {.compilerproc.} = - # implementation of 'spawn' that is used by the code generator. - while true: - for i in 0.. high(workers): - let w = addr(workersData[i]) - if cas(addr w.ready, true, false): - w.data = data - w.f = fn - signal(w.taskArrived) - await(w.taskStarted) - return - await(gSomeReady) - -proc sync*() = - ## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate - ## waiting, you have to use an explicit barrier. - while true: - var allReady = true - for i in 0 .. high(workers): - if not allReady: break - allReady = allReady and workersData[i].ready - if allReady: break - await(gSomeReady) - -setup() From 93c8427fca0bdc0f32c8f7c011c661808ea1e6dc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 7 Dec 2021 17:59:43 +0100 Subject: [PATCH 3173/4254] re-enable chronos testing once again [backport:1.2] (#19222) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index e11799e73..7e15e7c65 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -51,7 +51,7 @@ pkg "cascade" pkg "cello" pkg "chroma" pkg "chronicles", "nim c -o:chr -r chronicles.nim" -pkg "chronos", "nim c -r -d:release tests/testall", allowFailure = true # pending https://github.com/nim-lang/Nim/issues/17130 +pkg "chronos", "nim c -r -d:release tests/testall" pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" pkg "compactdict" From cd592ed85ba3bf440d7b24a4bc5b117d1a5f8725 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Tue, 7 Dec 2021 18:01:22 +0100 Subject: [PATCH 3174/4254] fix #19193 (#19195) [backport:1.2] --- compiler/cgen.nim | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b669483cc..c862d4d30 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -443,8 +443,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): - linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), - getTypeDesc(p.module, typ, mapTypeChooser(loc))]) + if containsGarbageCollectedRef(loc.t): + var nilLoc: TLoc + initLoc(nilLoc, locTemp, loc.lode, OnStack) + nilLoc.r = rope("NIM_NIL") + genRefAssign(p, loc, nilLoc) + else: + linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), + getTypeDesc(p.module, typ, mapTypeChooser(loc))]) else: if not isTemp or containsGarbageCollectedRef(loc.t): # don't use nimZeroMem for temporary values for performance if we can From 7806ec525eec83d250141a32cfa197949ea1a42b Mon Sep 17 00:00:00 2001 From: rockcavera Date: Wed, 8 Dec 2021 02:48:34 -0300 Subject: [PATCH 3175/4254] Making TCC work again on Windows --cpu:amd64 - fix #16326 (#19221) * fix #16326 * removing comments --- lib/system/io.nim | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 2ad43acdb..661d1a9ba 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -109,8 +109,22 @@ when defined(windows): else: proc c_fseek(f: File, offset: int64, whence: cint): cint {. importc: "_fseeki64", header: "", tags: [].} - proc c_ftell(f: File): int64 {. - importc: "_ftelli64", header: "", tags: [].} + when defined(tcc): + proc c_fsetpos(f: File, pos: var int64): int32 {. + importc: "fsetpos", header: "", tags: [].} + proc c_fgetpos(f: File, pos: var int64): int32 {. + importc: "fgetpos", header: "", tags: [].} + proc c_telli64(f: cint): int64 {. + importc: "_telli64", header: "", tags: [].} + proc c_ftell(f: File): int64 = + # Taken from https://pt.osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.4-trunk/mingwrt/mingwex/stdio/ftelli64.c + result = -1'i64 + var pos: int64 + if c_fgetpos(f, pos) == 0 and c_fsetpos(f, pos) == 0: + result = c_telli64(c_fileno(f)) + else: + proc c_ftell(f: File): int64 {. + importc: "_ftelli64", header: "", tags: [].} else: proc c_fseek(f: File, offset: int64, whence: cint): cint {. importc: "fseeko", header: "", tags: [].} From 099285494124dedd7d83a848e213f895f54f9e81 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 8 Dec 2021 15:40:35 +0800 Subject: [PATCH 3176/4254] Atomic inc/dec should use ATOMIC_SEQ_CST (#19212) --- lib/system/atomics.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index 75731764b..8d29c287d 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -217,7 +217,7 @@ else: proc atomicInc*(memLoc: var int, x: int = 1): int = when someGcc and hasThreadSupport: - result = atomicAddFetch(memLoc.addr, x, ATOMIC_RELAXED) + result = atomicAddFetch(memLoc.addr, x, ATOMIC_SEQ_CST) elif someVcc and hasThreadSupport: result = addAndFetch(memLoc.addr, x) inc(result, x) @@ -228,9 +228,9 @@ proc atomicInc*(memLoc: var int, x: int = 1): int = proc atomicDec*(memLoc: var int, x: int = 1): int = when someGcc and hasThreadSupport: when declared(atomicSubFetch): - result = atomicSubFetch(memLoc.addr, x, ATOMIC_RELAXED) + result = atomicSubFetch(memLoc.addr, x, ATOMIC_SEQ_CST) else: - result = atomicAddFetch(memLoc.addr, -x, ATOMIC_RELAXED) + result = atomicAddFetch(memLoc.addr, -x, ATOMIC_SEQ_CST) elif someVcc and hasThreadSupport: result = addAndFetch(memLoc.addr, -x) dec(result, x) From 502ac4ed5e539146d31920d50020ae35668f4755 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 9 Dec 2021 13:56:51 +0100 Subject: [PATCH 3177/4254] fixes a converter handling regression that caused private converters to leak into client modules; fixes #19213; [backport:1.6] (#19229) --- compiler/importer.nim | 6 ++++-- tests/converter/mdontleak.nim | 3 +++ tests/converter/tdontleak.nim | 10 ++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/converter/mdontleak.nim create mode 100644 tests/converter/tdontleak.nim diff --git a/compiler/importer.nim b/compiler/importer.nim index af392f849..acca2c644 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -185,11 +185,13 @@ template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} = for it in mitems c.graph.ifaces[fromMod.position].converters: if filter: loadPackedSym(c.graph, it) - addConverter(c, it) + if sfExported in it.sym.flags: + addConverter(c, it) for it in mitems c.graph.ifaces[fromMod.position].patterns: if filter: loadPackedSym(c.graph, it) - addPattern(c, it) + if sfExported in it.sym.flags: + addPattern(c, it) for it in mitems c.graph.ifaces[fromMod.position].pureEnums: if filter: loadPackedSym(c.graph, it) diff --git a/tests/converter/mdontleak.nim b/tests/converter/mdontleak.nim new file mode 100644 index 000000000..e55c3f87c --- /dev/null +++ b/tests/converter/mdontleak.nim @@ -0,0 +1,3 @@ + +converter toBool(x: uint32): bool = x != 0 +# Note: This convertes is not exported! diff --git a/tests/converter/tdontleak.nim b/tests/converter/tdontleak.nim new file mode 100644 index 000000000..4965fa90a --- /dev/null +++ b/tests/converter/tdontleak.nim @@ -0,0 +1,10 @@ +discard """ + output: '''5''' +joinable: false +""" + +import mdontleak +# bug #19213 + +let a = 5'u32 +echo a From 742e9d65ad6b56387dc6bf9a2be1b95c510fd0c4 Mon Sep 17 00:00:00 2001 From: wenghongquan <93646063+wenghongquan@users.noreply.github.com> Date: Thu, 9 Dec 2021 21:00:33 +0800 Subject: [PATCH 3178/4254] Add support for LoongArch (#19223) * Add support for LoongArch * Update compiler/installer.ini Co-authored-by: Andreas Rumpf --- compiler/platform.nim | 5 +++-- lib/system.nim | 2 +- lib/system/platforms.nim | 4 +++- tools/nim.zsh-completion | 1 + tools/niminst/buildsh.nimf | 2 ++ tools/niminst/makefile.nimf | 3 +++ 6 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/platform.nim b/compiler/platform.nim index eb1398677..4e6054d5c 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -202,7 +202,7 @@ type cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430, cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32, - cpuE2k + cpuE2k, cpuLoongArch64 type TInfoCPU* = tuple[name: string, intSize: int, endian: Endianness, @@ -238,7 +238,8 @@ const (name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), (name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), (name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), - (name: "e2k", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)] + (name: "e2k", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), + (name: "loongarch64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)] type Target* = object diff --git a/lib/system.nim b/lib/system.nim index 012aefe6a..c424cbc1b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1126,7 +1126,7 @@ const ## Possible values: ## `"i386"`, `"alpha"`, `"powerpc"`, `"powerpc64"`, `"powerpc64el"`, ## `"sparc"`, `"amd64"`, `"mips"`, `"mipsel"`, `"arm"`, `"arm64"`, - ## `"mips64"`, `"mips64el"`, `"riscv32"`, `"riscv64"`. + ## `"mips64"`, `"mips64el"`, `"riscv32"`, `"riscv64"`, '"loongarch64"'. seqShallowFlag = low(int) strlitFlag = 1 shl (sizeof(int)*8 - 2) # later versions of the codegen \ diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim index 5bca8cb1c..b4c9f1f06 100644 --- a/lib/system/platforms.nim +++ b/lib/system/platforms.nim @@ -36,7 +36,8 @@ type riscv32, ## RISC-V 32-bit processor riscv64, ## RISC-V 64-bit processor wasm32, ## WASM, 32-bit - e2k ## MCST Elbrus 2000 + e2k, ## MCST Elbrus 2000 + loongarch64 ## LoongArch 64-bit processor OsPlatform* {.pure.} = enum ## the OS this program will run on. none, dos, windows, os2, linux, morphos, skyos, solaris, @@ -95,5 +96,6 @@ const elif defined(riscv64): CpuPlatform.riscv64 elif defined(wasm32): CpuPlatform.wasm32 elif defined(e2k): CpuPlatform.e2k + elif defined(loongarch64): CpuPlatform.loongarch64 else: CpuPlatform.none ## the CPU this program will run on. diff --git a/tools/nim.zsh-completion b/tools/nim.zsh-completion index 07a221e9c..45477d860 100644 --- a/tools/nim.zsh-completion +++ b/tools/nim.zsh-completion @@ -95,6 +95,7 @@ _nim() { '*--cpu=sparc64[compile for SPARC64 architecture]' \ '*--cpu=vm[compile for Nim VM]' \ '*--cpu=wasm32[compile to WASM 32]' \ + '*--cpu=loongarch64[compile for LoongArch64 architecture]' \ '*--gc=refc[use reference counting garbage collection]' \ '*--gc=arc[use ARC garbage collection]' \ '*--gc=orc[use ORC garbage collection]' \ diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index b81ac731f..464c70abf 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -229,6 +229,8 @@ case $ucpu in mycpu="riscv64" ;; *e2k* ) mycpu="e2k" ;; + *loongarch64* ) + mycpu="loongarch64" ;; *) echo 2>&1 "Error: unknown processor: $ucpu" exit 1 diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index c4f2f0e79..a1f3fa977 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -169,6 +169,9 @@ endif ifeq ($(ucpu),e2k) mycpu = e2k endif +ifeq ($(ucpu),loongarch64) + mycpu = loongarch64 +endif ifndef mycpu $(error unknown CPU architecture: $(ucpu) See makefile.nimf) endif From 99f8793502e65cd43f6e301557d428758948c3ca Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 9 Dec 2021 22:37:59 +0800 Subject: [PATCH 3179/4254] remove `std/sharedstrings` (#19228) * remove std/sharedstrings it has been broken since 0.18.0 * rephrase the changelog entry --- changelog.md | 2 + lib/deprecated/pure/sharedstrings.nim | 154 -------------------------- testament/testament.nim | 1 - 3 files changed, 2 insertions(+), 155 deletions(-) delete mode 100644 lib/deprecated/pure/sharedstrings.nim diff --git a/changelog.md b/changelog.md index a8f1920e9..ebad54fe4 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,8 @@ - Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via `experimental:flexibleOptionalParams`. +- `std/sharedstrings` module is removed. + ## Standard library additions and changes - `macros.parseExpr` and `macros.parseStmt` now accept an optional diff --git a/lib/deprecated/pure/sharedstrings.nim b/lib/deprecated/pure/sharedstrings.nim deleted file mode 100644 index 99963e1f2..000000000 --- a/lib/deprecated/pure/sharedstrings.nim +++ /dev/null @@ -1,154 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Shared string support for Nim. - -{.deprecated.} - -type - UncheckedCharArray = UncheckedArray[char] - -type - Buffer = ptr object - refcount: int - capacity, realLen: int - data: UncheckedCharArray - - SharedString* = object ## A string that can be shared. Slicing is O(1). - buffer: Buffer - first, len: int - -proc decRef(b: Buffer) {.inline.} = - if atomicDec(b.refcount) <= 0: - deallocShared(b) - -proc incRef(b: Buffer) {.inline.} = - atomicInc(b.refcount) - -{.experimental.} - -proc `=destroy`*(s: SharedString) = - #echo "destroyed" - if not s.buffer.isNil: - decRef(s.buffer) - -when false: - proc `=copy`*(dest: var SharedString; src: SharedString) = - incRef(src.buffer) - if not dest.buffer.isNil: - decRef(dest.buffer) - dest.buffer = src.buffer - dest.first = src.first - dest.len = src.len - -proc len*(s: SharedString): int = s.len - -proc `[]`*(s: SharedString; i: Natural): char = - if i < s.len: result = s.buffer.data[i+s.first] - else: raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1)) - -proc `[]=`*(s: var SharedString; i: Natural; value: char) = - if i < s.len: s.buffer.data[i+s.first] = value - else: raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1)) - -proc `[]`*(s: SharedString; ab: HSlice[int, int]): SharedString = - #incRef(src.buffer) - if ab.a < s.len: - result.buffer = s.buffer - result.first = ab.a - result.len = min(s.len, ab.b - ab.a + 1) - # else: produce empty string ;-) - -proc newBuffer(cap, len: int): Buffer = - assert cap >= len - result = cast[Buffer](allocShared0(sizeof(int)*3 + cap)) - result.refcount = 0 - result.capacity = cap - result.realLen = len - -proc newSharedString*(len: Natural): SharedString = - if len != 0: - # optimization: Don't have an underlying buffer when 'len == 0' - result.buffer = newBuffer(len, len) - result.first = 0 - result.len = len - -proc newSharedString*(s: string): SharedString = - let len = s.len - if len != 0: - # optimization: Don't have an underlying buffer when 'len == 0' - result.buffer = newBuffer(len, len) - copyMem(addr result.buffer.data[0], cstring(s), s.len) - result.first = 0 - result.len = len - -when declared(atomicLoadN): - template load(x): untyped = atomicLoadN(addr x, ATOMIC_SEQ_CST) -else: - # XXX Fixme - template load(x): untyped = x - -proc add*(s: var SharedString; t: cstring; len: Natural) = - if len == 0: return - let newLen = s.len + len - if s.buffer.isNil: - s.buffer = newBuffer(len, len) - copyMem(addr s.buffer.data[0], t, len) - s.len = len - elif newLen >= s.buffer.capacity or s.first != 0 or - s.len != s.buffer.realLen or load(s.buffer.refcount) > 1: - let oldBuf = s.buffer - s.buffer = newBuffer(max(s.buffer.capacity * 3 div 2, newLen), newLen) - copyMem(addr s.buffer.data[0], addr oldBuf.data[s.first], s.len) - copyMem(addr s.buffer.data[s.len], t, len) - decRef(oldBuf) - else: - copyMem(addr s.buffer.data[s.len], t, len) - s.buffer.realLen += len - s.len += len - -proc add*(s: var SharedString; t: string) = - s.add(t.cstring, t.len) - -proc rawData*(s: var SharedString): pointer = - if s.buffer.isNil: result = nil - else: result = addr s.buffer.data[s.first] - -proc add*(s: var SharedString; t: SharedString) = - if t.buffer.isNil: return - s.add(cast[cstring](addr s.buffer.data[s.first]), t.len) - -proc `$`*(s: SharedString): string = - result = newString(s.len) - if s.len > 0: - copyMem(addr result[0], addr s.buffer.data[s.first], s.len) - -proc `==`*(s: SharedString; t: string): bool = - if s.buffer.isNil: result = t.len == 0 - else: result = t.len == s.len and equalMem(addr s.buffer.data[s.first], - cstring(t), t.len) - -proc `==`*(s, t: SharedString): bool = - if s.buffer.isNil: result = t.len == 0 - else: result = t.len == s.len and equalMem(addr s.buffer.data[s.first], - addr t.buffer.data[t.first], t.len) - -iterator items*(s: SharedString): char = - let buf = s.buffer.data - let x = s.first - if buf != nil: - for i in 0.. Date: Fri, 10 Dec 2021 01:49:31 +0800 Subject: [PATCH 3180/4254] add comments to spawn and pinnedSpawn (#19230) `spawn` uses `nimSpawn3` internally and `pinnedSpawn` uses `nimSpawn4` internally. I comment it in order to help contributors get the gist of its functionality. --- lib/pure/concurrency/threadpool.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index f8a5f9ba8..9334b4833 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -448,19 +448,21 @@ proc preferSpawn*(): bool = ## <#spawnX.t>`_ instead. result = gSomeReady.counter > 0 -proc spawn*(call: sink typed) {.magic: "Spawn".} +proc spawn*(call: sink typed) {.magic: "Spawn".} = ## Always spawns a new task, so that the `call` is never executed on ## the calling thread. ## ## `call` has to be a proc call `p(...)` where `p` is gcsafe and has a ## return type that is either `void` or compatible with `FlowVar[T]`. + discard "It uses `nimSpawn3` internally" -proc pinnedSpawn*(id: ThreadId; call: sink typed) {.magic: "Spawn".} +proc pinnedSpawn*(id: ThreadId; call: sink typed) {.magic: "Spawn".} = ## Always spawns a new task on the worker thread with `id`, so that ## the `call` is **always** executed on the thread. ## ## `call` has to be a proc call `p(...)` where `p` is gcsafe and has a ## return type that is either `void` or compatible with `FlowVar[T]`. + discard "It uses `nimSpawn4` internally" template spawnX*(call) = ## Spawns a new task if a CPU core is ready, otherwise executes the From 32d4bf352585a4fc4a6fa1bd24b270af087b0372 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 9 Dec 2021 22:23:16 +0100 Subject: [PATCH 3181/4254] fixes an old ARC bug: the produced copy/sink operations don't copy the hidden type field for objects with enabled inheritance; fixes #19205 [backport:1.6] (#19232) --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 8 ++++++++ compiler/ccgtypes.nim | 2 +- compiler/liftdestructors.nim | 10 ++++++++++ compiler/types.nim | 3 +++ tests/arc/tarcmisc.nim | 15 +++++++++++++++ 6 files changed, 38 insertions(+), 2 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 9086860b9..4286f940f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -673,7 +673,7 @@ type mSwap, mIsNil, mArrToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, mTrace, - mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mReset, + mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, mIterableType, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index fc09fefc3..1f1035115 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1741,6 +1741,13 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) = # use the dynamic type stored at offset 0: putIntoDest(p, d, e, rdMType(p, a, nilCheck)) +proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) = + var a: TLoc + initLocExpr(p, e[1], a) + var nilCheck = Rope(nil) + # use the dynamic type stored at offset 0: + putIntoDest(p, d, e, rdMType(p, a, nilCheck)) + template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = var a: TLoc initLocExpr(p, n[1], a) @@ -2449,6 +2456,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mMove: genMove(p, e, d) of mDestroy: genDestroy(p, e) of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0") + of mAccessTypeField: genAccessTypeField(p, e, d) of mSlice: genSlice(p, e, d) of mTrace: discard "no code to generate" else: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e7e099659..740ce5f19 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -583,7 +583,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, if typ.kind == tyObject: if typ[0] == nil: - if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags: + if lacksMTypeField(typ): appcg(m, result, " {$n", []) else: if optTinyRtti in m.config.globalOptions: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index cc7e36cdb..51b4ddfb0 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -941,6 +941,12 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp incl result.flags, sfFromGeneric incl result.flags, sfGeneratedOp +proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) = + let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x) + let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y) + xx.typ = getSysType(c.g, c.info, tyPointer) + yy.typ = xx.typ + body.add newAsgnStmt(xx, yy) proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo; idgen: IdGenerator): PSym = @@ -980,6 +986,10 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; fillStrOp(a, typ, result.ast[bodyPos], d, src) else: fillBody(a, typ, result.ast[bodyPos], d, src) + if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ): + # bug #19205: Do not forget to also copy the hidden type field: + genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src) + if not a.canRaise: incl result.flags, sfNeverRaises completePartialOp(g, idgen.module, typ, kind, result) diff --git a/compiler/types.nim b/compiler/types.nim index 7cf02c240..007a61356 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1705,3 +1705,6 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool = result = allowPointerToChar else: discard + +proc lacksMTypeField*(typ: PType): bool {.inline.} = + (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index d259e1197..45d1514cd 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -30,6 +30,7 @@ ok true copying 123 +42 closed destroying variable: 20 destroying variable: 10 @@ -482,3 +483,17 @@ method testMethod(self: BrokenObject) {.base.} = let mikasa = BrokenObject() mikasa.testMethod() + +# bug #19205 +type + InputSectionBase* = object of RootObj + relocations*: seq[int] # traced reference. string has a similar SIGSEGV. + InputSection* = object of InputSectionBase + +proc fooz(sec: var InputSectionBase) = + if sec of InputSection: # this line SIGSEGV. + echo 42 + +var sec = create(InputSection) +sec[] = InputSection(relocations: newSeq[int]()) +fooz sec[] From 69aabdab800077e9aaa08344494c83138a02f57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Fri, 10 Dec 2021 06:31:29 +0100 Subject: [PATCH 3182/4254] nimRawSetjmp: support Windows (#19197) * nimRawSetjmp: support Windows Using `_setjmp()` directly is required to avoid some rare (but very annoying) exception-related stack corruption leading to segfaults on Windows, with Mingw-w64 and SEH. More details: https://github.com/status-im/nimbus-eth2/issues/3121 Also add "nimBuiltinSetjmp" - mostly for benchmarking. * fix for Apple's Clang++ --- compiler/ccgstmts.nim | 13 +++- doc/nimc.rst | 14 ++++ lib/system/ansi_c.nim | 46 +++++++++-- tests/exception/texceptions.nim | 6 +- tests/exception/texceptions2.nim | 130 +++++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 tests/exception/texceptions2.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 559849f0d..7fecc1475 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1356,8 +1356,19 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) elif isDefined(p.config, "nimSigSetjmp"): linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint]) + elif isDefined(p.config, "nimBuiltinSetjmp"): + linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint]) elif isDefined(p.config, "nimRawSetjmp"): - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) + if isDefined(p.config, "mswindows"): + # The Windows `_setjmp()` takes two arguments, with the second being an + # undocumented buffer used by the SEH mechanism for stack unwinding. + # Mingw-w64 has been trying to get it right for years, but it's still + # prone to stack corruption during unwinding, so we disable that by setting + # it to NULL. + # More details: https://github.com/status-im/nimbus-eth2/issues/3121 + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint]) + else: + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) else: linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint]) diff --git a/doc/nimc.rst b/doc/nimc.rst index eb066e748..0ab1501ff 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -165,6 +165,20 @@ ignored too. `--define:FOO`:option: and `--define:foo`:option: are identical. Compile-time symbols starting with the `nim` prefix are reserved for the implementation and should not be used elsewhere. +========================== ============================================ +Name Description +========================== ============================================ +nimStdSetjmp Use the standard `setjmp()/longjmp()` library + functions for setjmp-based exceptions. This is + the default on most platforms. +nimSigSetjmp Use `sigsetjmp()/siglongjmp()` for setjmp-based exceptions. +nimRawSetjmp Use `_setjmp()/_longjmp()` on POSIX and `_setjmp()/longjmp()` + on Windows, for setjmp-based exceptions. It's the default on + BSDs and BSD-like platforms, where it's significantly faster + than the standard functions. +nimBuiltinSetjmp Use `__builtin_setjmp()/__builtin_longjmp()` for setjmp-based + exceptions. This will not work if an exception is being thrown + and caught inside the same procedure. Useful for benchmarking. Configuration files ------------------- diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 259d36633..23fb9fdef 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -31,7 +31,10 @@ proc c_abort*() {. importc: "abort", header: "", noSideEffect, noreturn.} -when defined(linux) and defined(amd64): +when defined(nimBuiltinSetjmp): + type + C_JmpBuf* = array[5, pointer] +elif defined(linux) and defined(amd64): type C_JmpBuf* {.importc: "jmp_buf", header: "", bycopy.} = object abi: array[200 div sizeof(clong), clong] @@ -92,18 +95,47 @@ when defined(macosx): elif defined(haiku): const SIGBUS* = cint(30) -when defined(nimSigSetjmp) and not defined(nimStdSetjmp): +# "nimRawSetjmp" is defined by default for certain platforms, so we need the +# "nimStdSetjmp" escape hatch with it. +when defined(nimSigSetjmp): proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "siglongjmp".} - template c_setjmp*(jmpb: C_JmpBuf): cint = + proc c_setjmp*(jmpb: C_JmpBuf): cint = proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {. header: "", importc: "sigsetjmp".} c_sigsetjmp(jmpb, 0) +elif defined(nimBuiltinSetjmp): + proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) = + # Apple's Clang++ has trouble converting array names to pointers, so we need + # to be very explicit here. + proc c_builtin_longjmp(jmpb: ptr pointer, retval: cint) {. + importc: "__builtin_longjmp", nodecl.} + # The second parameter needs to be 1 and sometimes the C/C++ compiler checks it. + c_builtin_longjmp(unsafeAddr jmpb[0], 1) + proc c_setjmp*(jmpb: C_JmpBuf): cint = + proc c_builtin_setjmp(jmpb: ptr pointer): cint {. + importc: "__builtin_setjmp", nodecl.} + c_builtin_setjmp(unsafeAddr jmpb[0]) elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): - proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. - header: "", importc: "_longjmp".} - proc c_setjmp*(jmpb: C_JmpBuf): cint {. - header: "", importc: "_setjmp".} + when defined(windows): + # No `_longjmp()` on Windows. + proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "longjmp".} + # The Windows `_setjmp()` takes two arguments, with the second being an + # undocumented buffer used by the SEH mechanism for stack unwinding. + # Mingw-w64 has been trying to get it right for years, but it's still + # prone to stack corruption during unwinding, so we disable that by setting + # it to NULL. + # More details: https://github.com/status-im/nimbus-eth2/issues/3121 + proc c_setjmp*(jmpb: C_JmpBuf): cint = + proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {. + header: "", importc: "_setjmp".} + c_setjmp_win(jmpb, nil) + else: + proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "_longjmp".} + proc c_setjmp*(jmpb: C_JmpBuf): cint {. + header: "", importc: "_setjmp".} else: proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "longjmp".} diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim index adee5d1d5..62d24c934 100644 --- a/tests/exception/texceptions.nim +++ b/tests/exception/texceptions.nim @@ -1,4 +1,6 @@ discard """ + disabled: "windows" # no sigsetjmp() there + matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp" output: ''' BEFORE @@ -17,7 +19,7 @@ FINALLY echo "" -proc no_expcetion = +proc no_exception = try: echo "BEFORE" @@ -28,7 +30,7 @@ proc no_expcetion = finally: echo "FINALLY" -try: no_expcetion() +try: no_exception() except: echo "RECOVER" echo "" diff --git a/tests/exception/texceptions2.nim b/tests/exception/texceptions2.nim new file mode 100644 index 000000000..97fd856a0 --- /dev/null +++ b/tests/exception/texceptions2.nim @@ -0,0 +1,130 @@ +discard """ + disabled: "posix" # already covered by texceptions.nim + matrix: "-d:nimStdSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp" + output: ''' + +BEFORE +FINALLY + +BEFORE +EXCEPT +FINALLY +RECOVER + +BEFORE +EXCEPT: IOError: hi +FINALLY +''' +""" + +echo "" + +proc no_exception = + try: + echo "BEFORE" + + except: + echo "EXCEPT" + raise + + finally: + echo "FINALLY" + +try: no_exception() +except: echo "RECOVER" + +echo "" + +proc reraise_in_except = + try: + echo "BEFORE" + raise newException(IOError, "") + + except IOError: + echo "EXCEPT" + raise + + finally: + echo "FINALLY" + +try: reraise_in_except() +except: echo "RECOVER" + +echo "" + +proc return_in_except = + try: + echo "BEFORE" + raise newException(IOError, "hi") + + except: + echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg() + return + + finally: + echo "FINALLY" + +try: return_in_except() +except: echo "RECOVER" + +block: #10417 + proc moo() {.noreturn.} = discard + + let bar = + try: + 1 + except: + moo() + + doAssert(bar == 1) + +# Make sure the VM handles the exceptions correctly +block: + proc fun1(): seq[int] = + try: + try: + raise newException(ValueError, "xx") + except: + doAssert("xx" == getCurrentExceptionMsg()) + raise newException(KeyError, "yy") + except: + doAssert("yy" == getCurrentExceptionMsg()) + result.add(1212) + try: + try: + raise newException(AssertionDefect, "a") + finally: + result.add(42) + except AssertionDefect: + result.add(99) + finally: + result.add(10) + result.add(4) + result.add(0) + try: + result.add(1) + except KeyError: + result.add(-1) + except ValueError: + result.add(-1) + except IndexDefect: + result.add(2) + except: + result.add(3) + + try: + try: + result.add(1) + return + except: + result.add(-1) + finally: + result.add(2) + except KeyError: + doAssert(false) + finally: + result.add(3) + + let x1 = fun1() + const x2 = fun1() + doAssert(x1 == x2) From d39147219a41f54b45b585a103bfb04cce71c52c Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Thu, 9 Dec 2021 22:38:39 -0800 Subject: [PATCH 3183/4254] Revert "swap port to correct port order (#19177)" (#19234) This reverts commit 0d0c249074d6a1041de16108dc247396efef5513. --- lib/pure/net.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 06024e46d..7b0ff78e7 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -478,14 +478,14 @@ proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl = sizeof(Sockaddr_in).SockLen let s = cast[ptr Sockaddr_in](addr sa) s.sin_family = typeof(s.sin_family)(toInt(AF_INET)) - s.sin_port = htons(port) + s.sin_port = port copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr)) of IpAddressFamily.IPv6: sl = sizeof(Sockaddr_in6).SockLen let s = cast[ptr Sockaddr_in6](addr sa) s.sin6_family = typeof(s.sin6_family)(toInt(AF_INET6)) - s.sin6_port = htons(port) + s.sin6_port = port copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) From c98954233981cb30807bd8be8b805663d44964d1 Mon Sep 17 00:00:00 2001 From: MichalMarsalek Date: Fri, 10 Dec 2021 07:39:12 +0100 Subject: [PATCH 3184/4254] move toDeque to after addLast (#19233) [backport:1.0] Changes the order of procs definitions in order to avoid calling an undefined proc. --- lib/pure/collections/deques.nim | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index ecdf199d2..c4eb5331e 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -87,20 +87,6 @@ proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] = ## * `toDeque proc <#toDeque,openArray[T]>`_ result.initImpl(initialSize) -proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} = - ## Creates a new deque that contains the elements of `x` (in the same order). - ## - ## **See also:** - ## * `initDeque proc <#initDeque,int>`_ - runnableExamples: - let a = toDeque([7, 8, 9]) - assert len(a) == 3 - assert $a == "[7, 8, 9]" - - result.initImpl(x.len) - for item in items(x): - result.addLast(item) - proc len*[T](deq: Deque[T]): int {.inline.} = ## Returns the number of elements of `deq`. result = deq.count @@ -303,6 +289,20 @@ proc addLast*[T](deq: var Deque[T], item: sink T) = deq.data[deq.tail] = item deq.tail = (deq.tail + 1) and deq.mask +proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} = + ## Creates a new deque that contains the elements of `x` (in the same order). + ## + ## **See also:** + ## * `initDeque proc <#initDeque,int>`_ + runnableExamples: + let a = toDeque([7, 8, 9]) + assert len(a) == 3 + assert $a == "[7, 8, 9]" + + result.initImpl(x.len) + for item in items(x): + result.addLast(item) + proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} = ## Returns the first element of `deq`, but does not remove it from the deque. ## From 9338aa24977e84a33b9a7802eaff0777fcf4d9c3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Dec 2021 09:24:20 +0100 Subject: [PATCH 3185/4254] fixes a possible 'javascript:' protocol exploit [backport:1.0] (#19134) * fixes a possible 'javascript:' protocol exploit [backport:1.0] * add tests * Update tests/stdlib/trstgen.nim * add the same logic for hyperlinks * move the logic into a proc Co-authored-by: narimiran --- lib/packages/docutils/rstgen.nim | 15 +++++++++++++- tests/stdlib/trstgen.nim | 35 ++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index dc6ca25c1..9018087f7 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -40,7 +40,7 @@ ## can be done by simply searching for [footnoteName]. import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, - algorithm, parseutils, std/strbasics + algorithm, parseutils, std/strbasics, strscans import ../../std/private/since @@ -827,6 +827,16 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) = rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName]) +proc safeProtocol(linkStr: var string) = + var protocol = "" + if scanf(linkStr, "$w:", protocol): + # if it has a protocol at all, ensure that it's not 'javascript:' or worse: + if cmpIgnoreCase(protocol, "http") == 0 or cmpIgnoreCase(protocol, "https") == 0 or + cmpIgnoreCase(protocol, "ftp") == 0: + discard "it's fine" + else: + linkStr = "" + proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) = dispA(d.target, result, "
  • $2
  • \n", @@ -891,6 +901,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = # support for `:target:` links for images: var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl) + safeProtocol(target) + if target.len > 0: # `htmlOut` needs to be of the following format for link to work for images: # @@ -1192,6 +1204,7 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, d.escMode = emUrl renderRstToOut(d, link, linkStr) d.escMode = mode + safeProtocol(linkStr) var textStr = "" renderRstToOut(d, text, textStr) let nimDocStr = if nimdoc: " nimdoc" else: "" diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 45cf1a68e..2be65b35b 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -398,7 +398,7 @@ Some chapter Level2 ------ - + Level3 ~~~~~~ @@ -407,7 +407,7 @@ Some chapter More ~~~~ - + Another ------- @@ -683,7 +683,7 @@ Test1 test "RST line blocks": let input2 = dedent""" Paragraph1 - + | Paragraph2""" @@ -704,7 +704,7 @@ Test1 # check that '| ' with a few spaces is still parsed as new line let input4 = dedent""" | xxx - | + | | zzz""" let output4 = input4.toHtml @@ -1549,3 +1549,30 @@ suite "RST/Code highlight": check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) == strip(expected) + + +suite "invalid targets": + test "invalid image target": + let input1 = dedent """.. image:: /images/myimage.jpg + :target: https://bar.com + :alt: Alt text for the image""" + let output1 = input1.toHtml + check output1 == """Alt text for the image""" + + let input2 = dedent """.. image:: /images/myimage.jpg + :target: javascript://bar.com + :alt: Alt text for the image""" + let output2 = input2.toHtml + check output2 == """Alt text for the image""" + + let input3 = dedent """.. image:: /images/myimage.jpg + :target: bar.com + :alt: Alt text for the image""" + let output3 = input3.toHtml + check output3 == """Alt text for the image""" + + test "invalid links": + check("(([Nim](https://nim-lang.org/)))".toHtml == + """((Nim))""") + check("(([Nim](javascript://nim-lang.org/)))".toHtml == + """((Nim))""") From 7ff43d07b2b983271d666b1c654b1426cbbbf236 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Dec 2021 14:28:59 +0100 Subject: [PATCH 3186/4254] added --nimMainPrefix switch; fixes #15955; refs #16945 [backport:1.6] (#19235) --- changelog.md | 2 ++ compiler/cgen.nim | 37 ++++++++++++++++++++----------------- compiler/commands.nim | 1 + compiler/options.nim | 1 + doc/advopt.txt | 2 ++ doc/backends.rst | 3 +++ doc/nimc.rst | 7 +++++++ 7 files changed, 36 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index ebad54fe4..df8051a16 100644 --- a/changelog.md +++ b/changelog.md @@ -71,3 +71,5 @@ - The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the reality better. (Nim moved away from all techniques based on "tracing".) +- There is a new switch `--nimMainPrefix:prefix` to influence the `NimMain` that the + compiler produces. This is particularly useful for generating static libraries. diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c862d4d30..032c22ec0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -154,6 +154,11 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = inc(i) result.add newCall(formatValue, resVar, args[num]) inc(num) + of '^': + flushStrLit() + inc(i) + result.add newCall(formatValue, resVar, args[^1]) + inc(num) of '0'..'9': var j = 0 while true: @@ -1366,7 +1371,7 @@ proc genMainProc(m: BModule) = "}$N$N" MainProcs = - "\tNimMain();$N" + "\t$^NimMain();$N" MainProcsWithResult = MainProcs & ("\treturn $1nim_program_result;$N") @@ -1376,7 +1381,7 @@ proc genMainProc(m: BModule) = "}$N$N" NimMainProc = - "N_CDECL(void, NimMain)(void) {$N" & + "N_CDECL(void, $5NimMain)(void) {$N" & "\tvoid (*volatile inner)(void);$N" & "$4" & "\tinner = NimMainInner;$N" & @@ -1456,28 +1461,27 @@ proc genMainProc(m: BModule) = if optGenGuiApp in m.config.globalOptions: const nimMain = WinNimMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) else: const nimMain = WinNimDllMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) elif m.config.target.targetOS == osGenode: const nimMain = GenodeNimMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) elif optGenDynLib in m.config.globalOptions: const nimMain = PosixNimDllMain appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) elif m.config.target.targetOS == osStandalone: const nimMain = NimMainBody appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) else: const nimMain = NimMainBody appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode]) - + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) if optNoMain notin m.config.globalOptions: if m.config.cppCustomNamespace.len > 0: @@ -1487,23 +1491,22 @@ proc genMainProc(m: BModule) = m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: if optGenGuiApp in m.config.globalOptions: const otherMain = WinCMain - appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""]) + appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) else: const otherMain = WinCDllMain - appcg(m, m.s[cfsProcs], otherMain, []) + appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) elif m.config.target.targetOS == osGenode: const otherMain = ComponentConstruct - appcg(m, m.s[cfsProcs], otherMain, []) + appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) elif optGenDynLib in m.config.globalOptions: const otherMain = PosixCDllMain - appcg(m, m.s[cfsProcs], otherMain, []) + appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) elif m.config.target.targetOS == osStandalone: const otherMain = StandaloneCMain - appcg(m, m.s[cfsProcs], otherMain, []) + appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) else: const otherMain = PosixCMain - appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""]) - + appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) if m.config.cppCustomNamespace.len > 0: m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace) @@ -1885,7 +1888,7 @@ proc writeHeader(m: BModule) = if optGenDynLib in m.config.globalOptions: result.add("N_LIB_IMPORT ") - result.addf("N_CDECL(void, NimMain)(void);$n", []) + result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix]) if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim() result.addf("#endif /* $1 */$n", [guard]) if not writeRope(result, m.filename): diff --git a/compiler/commands.nim b/compiler/commands.nim index d5c5f24e4..c4df46bc2 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -1052,6 +1052,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) handleStdinInput(conf) of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch) + of "nimmainprefix": conf.nimMainPrefix = arg else: if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) diff --git a/compiler/options.nim b/compiler/options.nim index 383b6fa2a..9e957332f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -390,6 +390,7 @@ type structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string + nimMainPrefix*: string vmProfileData*: ProfileData proc parseNimVersion*(a: string): NimVer = diff --git a/doc/advopt.txt b/doc/advopt.txt index 79e784fde..e27c75ada 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -135,6 +135,8 @@ Advanced options: --cppCompileToNamespace:namespace use the provided namespace for the generated C++ code, if no namespace is provided "Nim" will be used + --nimMainPrefix:prefix use `{prefix}NimMain` instead of `NimMain` in the produced + C/C++ code --expandMacro:MACRO dump every generated AST from MACRO --expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations before the final backend phase (mostly ARC/ORC specific) diff --git a/doc/backends.rst b/doc/backends.rst index 3a3359fca..65dd8a6f2 100644 --- a/doc/backends.rst +++ b/doc/backends.rst @@ -246,6 +246,9 @@ Also, C code requires you to specify a forward declaration for functions or the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. +The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch. +Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`. + Nim invocation example from C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/nimc.rst b/doc/nimc.rst index 0ab1501ff..6b4f3c9a1 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -385,6 +385,10 @@ of your program. NimMain() # initialize garbage collector memory, types and stack +The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch. +Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`. + + Cross-compilation for iOS ========================= @@ -413,6 +417,9 @@ of your program. Note: XCode's "make clean" gets confused about the generated nim.c files, so you need to clean those files manually to do a clean build. +The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch. +Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`. + Cross-compilation for Nintendo Switch ===================================== From 908fc2a22e7336670173bcd06ab30f440ca6d321 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Dec 2021 17:13:48 +0100 Subject: [PATCH 3187/4254] let Nim support Nimble 0.14 with lock-file support [backport:1.6] (#19236) --- changelog.md | 4 ++++ config/nim.cfg | 2 ++ 2 files changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index df8051a16..6f47ef8a4 100644 --- a/changelog.md +++ b/changelog.md @@ -71,5 +71,9 @@ - The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the reality better. (Nim moved away from all techniques based on "tracing".) +- Nim now supports Nimble version 0.14 which added support for lock-files. This is done by + a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg` + replace `pkgs` by `pkgs2`. + - There is a new switch `--nimMainPrefix:prefix` to influence the `NimMain` that the compiler produces. This is particularly useful for generating static libraries. diff --git a/config/nim.cfg b/config/nim.cfg index 86c6e2141..59d7f48d2 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -44,10 +44,12 @@ path="$lib/core" path="$lib/pure" @if not windows: + nimblepath="/opt/nimble/pkgs2/" nimblepath="/opt/nimble/pkgs/" @else: # TODO: @end +nimblepath="$home/.nimble/pkgs2/" nimblepath="$home/.nimble/pkgs/" # Syncronize with compiler/commands.specialDefine From 1a92edeb894a10a13f60905a79304bd26e1c144e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Sat, 11 Dec 2021 05:15:44 +0100 Subject: [PATCH 3188/4254] nimc.rst: fix table markup (#19239) --- doc/nimc.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/nimc.rst b/doc/nimc.rst index 6b4f3c9a1..aa6650491 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -179,6 +179,8 @@ nimRawSetjmp Use `_setjmp()/_longjmp()` on POSIX and `_setjm nimBuiltinSetjmp Use `__builtin_setjmp()/__builtin_longjmp()` for setjmp-based exceptions. This will not work if an exception is being thrown and caught inside the same procedure. Useful for benchmarking. +========================== ============================================ + Configuration files ------------------- From a3ef5df680e55d9bf68027fcb0ec6358b4279d09 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 11 Dec 2021 08:24:23 +0000 Subject: [PATCH 3189/4254] Update uri.nim (#19148) [backport:1.0] --- lib/pure/uri.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index a828298c2..5de333b8f 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -216,6 +216,8 @@ func parseAuthority(authority: string, result: var Uri) = result.isIpv6 = true of ']': inIPv6 = false + of '\0': + break else: if inPort: result.port.add(authority[i]) From 4b5cecd902cc4126ff9d6cda9edb78a13a421239 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Sun, 12 Dec 2021 13:39:56 -0800 Subject: [PATCH 3190/4254] Various std net improvements (#19132) * Variant of that works with raw IpAddresses. - Add doc tests for new net proc's. - Aadd recvFrom impl - Add recvFrom impl -- tweak handling data var - Update lib/pure/net.nim Co-authored-by: Dominik Picheta - cleaning up sendTo args - remove extra connect test - cleaning up sendTo args - fix inet_ntop test - fix test failing - byte len * fix test failing - byte len * debugging odd windows build failure * debugging odd windows build failure * more experiments to figure out the windows failure * try manual assigment on InAddr Co-authored-by: Jaremy Creechley --- lib/posix/posix.nim | 4 +- lib/pure/net.nim | 61 +++++++++++++++++++++++----- tests/stdlib/tnet_ll.nim | 88 ++++++++++++++++++++-------------------- 3 files changed, 97 insertions(+), 56 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index c2504f994..57dd6e2c7 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -155,9 +155,9 @@ when not defined(zephyr): proc inet_addr*(a1: cstring): InAddrT {.importc, header: "".} proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "".} -proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {. +proc inet_ntop*(a1: cint, a2: pointer | ptr InAddr | ptr In6Addr, a3: cstring, a4: int32): cstring {. importc:"(char *)$1", header: "".} -proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {. +proc inet_pton*(a1: cint, a2: cstring, a3: pointer | ptr InAddr | ptr In6Addr): cint {. importc, header: "".} var diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 7b0ff78e7..2d1bb0b33 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -65,6 +65,11 @@ runnableExamples("-r:off"): let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) socket.sendTo("192.168.0.1", Port(27960), "status\n") +runnableExamples("-r:off"): + let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + let ip = parseIpAddress("192.168.0.1") + doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8 + ## Creating a server ## ----------------- ## @@ -1607,11 +1612,12 @@ proc recvLine*(socket: Socket, timeout = -1, result = "" readLine(socket, result, timeout, flags, maxLength) -proc recvFrom*(socket: Socket, data: var string, length: int, - address: var string, port: var Port, flags = 0'i32): int {. +proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int, + address: var T, port: var Port, flags = 0'i32): int {. tags: [ReadIOEffect].} = ## Receives data from `socket`. This function should normally be used with - ## connection-less sockets (UDP sockets). + ## connection-less sockets (UDP sockets). The source address of the data + ## packet is stored in the `address` argument as either a string or an IpAddress. ## ## If an error occurs an OSError exception will be raised. Otherwise the return ## value will be the length of data received. @@ -1620,31 +1626,37 @@ proc recvFrom*(socket: Socket, data: var string, length: int, ## so when `socket` is buffered the non-buffered implementation will be ## used. Therefore if `socket` contains something in its buffer this ## function will make no effort to return it. - template adaptRecvFromToDomain(domain: Domain) = + template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) = var addrLen = sizeof(sockAddress).SockLen result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if result != -1: data.setLen(result) - address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) - when domain == AF_INET6: - port = ntohs(sockAddress.sin6_port).Port + + when typeof(address) is string: + address = getAddrString(cast[ptr SockAddr](addr(sockAddress))) + when domain == AF_INET6: + port = ntohs(sockAddress.sin6_port).Port + else: + port = ntohs(sockAddress.sin_port).Port else: - port = ntohs(sockAddress.sin_port).Port + data.setLen(result) + sockAddress.fromSockAddr(addrLen, address, port) else: raiseOSError(osLastError()) assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") # TODO: Buffered sockets data.setLen(length) + case socket.domain of AF_INET6: var sockAddress: Sockaddr_in6 - adaptRecvFromToDomain(AF_INET6) + adaptRecvFromToDomain(sockAddress, AF_INET6) of AF_INET: var sockAddress: Sockaddr_in - adaptRecvFromToDomain(AF_INET) + adaptRecvFromToDomain(sockAddress, AF_INET) else: raise newException(ValueError, "Unknown socket address family") @@ -1707,7 +1719,8 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, tags: [WriteIOEffect].} = ## This proc sends `data` to the specified `address`, ## which may be an IP address or a hostname, if a hostname is specified - ## this function will try each IP of that hostname. + ## this function will try each IP of that hostname. This function + ## should normally be used with connection-less sockets (UDP sockets). ## ## If an error occurs an OSError exception will be raised. ## @@ -1741,12 +1754,38 @@ proc sendTo*(socket: Socket, address: string, port: Port, ## This proc sends `data` to the specified `address`, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. + ## + ## Generally for use with connection-less (UDP) sockets. ## ## If an error occurs an OSError exception will be raised. ## ## This is the high-level version of the above `sendTo` function. socket.sendTo(address, port, cstring(data), data.len, socket.domain) +proc sendTo*(socket: Socket, address: IpAddress, port: Port, + data: string, flags = 0'i32): int {. + discardable, tags: [WriteIOEffect].} = + ## This proc sends `data` to the specified `IpAddress` and returns + ## the number of bytes written. + ## + ## Generally for use with connection-less (UDP) sockets. + ## + ## If an error occurs an OSError exception will be raised. + ## + ## This is the high-level version of the above `sendTo` function. + assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket") + assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") + + var sa: Sockaddr_storage + var sl: Socklen + toSockAddr(address, port, sa, sl) + result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint, + cast[ptr SockAddr](addr sa), sl) + + if result == -1'i32: + let osError = osLastError() + raiseOSError(osError) + proc isSsl*(socket: Socket): bool = ## Determines whether `socket` is a SSL socket. diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index affa21947..248dbb79b 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -1,43 +1,45 @@ -discard """ - action: run - output: ''' - -[Suite] inet_ntop tests -''' -""" - -when defined(windows): - import winlean -elif defined(posix): - import posix -else: - {.error: "Unsupported OS".} - -import unittest, strutils - -suite "inet_ntop tests": - - setup: - when defined(windows): - var wsa: WSAData - discard wsaStartup(0x101'i16, wsa.addr) - - test "IP V4": - var ip4 = 0x10111213 - var buff: array[0..255, char] - let r = inet_ntop(AF_INET, ip4.addr, buff[0].addr, buff.sizeof.int32) - let res = if r == nil: "" else: $r - check: res == "19.18.17.16" - - - test "IP V6": - when defined(windows): - let ipv6Support = (getVersion() and 0xff) > 0x5 - else: - let ipv6Support = true - - var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001] - var buff: array[0..255, char] - let r = inet_ntop(AF_INET6, ip6[0].addr, buff[0].addr, buff.sizeof.int32) - let res = if r == nil: "" else: $r - check: not ipv6Support or res == "10:110:20:120:30:130:40:140" +discard """ + action: run + output: ''' + +[Suite] inet_ntop tests +''' +""" + +when defined(windows): + import winlean +elif defined(posix): + import posix +else: + {.error: "Unsupported OS".} + +import unittest, strutils + +suite "inet_ntop tests": + + setup: + when defined(windows): + var wsa: WSAData + discard wsaStartup(0x101'i16, wsa.addr) + + test "IP V4": + # regular + var ip4 = InAddr() + ip4.s_addr = 0x10111213'u32 + + var buff: array[0..255, char] + let r = inet_ntop(AF_INET, cast[pointer](ip4.s_addr.addr), buff[0].addr, buff.len.int32) + let res = if r == nil: "" else: $r + check: res == "19.18.17.16" + + test "IP V6": + when defined(windows): + let ipv6Support = (getVersion() and 0xff) > 0x5 + else: + let ipv6Support = true + + var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001] + var buff: array[0..255, char] + let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), buff[0].addr, buff.len.int32) + let res = if r == nil: "" else: $r + check: not ipv6Support or res == "10:110:20:120:30:130:40:140" From 0ff4b2ba7ee74ed2758b0eb5992e4ccab7433952 Mon Sep 17 00:00:00 2001 From: Carlo Capocasa Date: Mon, 13 Dec 2021 07:29:22 +0100 Subject: [PATCH 3191/4254] fix bug #14468 zero-width split (#19248) --- lib/impure/re.nim | 11 +++++++---- tests/stdlib/tre.nim | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 8e5efbb28..4eacf0091 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -556,19 +556,22 @@ iterator split*(s: string, sep: Regex; maxsplit = -1): string = @["", "this", "is", "an", "example", ""] var last = 0 var splits = maxsplit - var x: int + var x = -1 + if len(s) == 0: + last = 1 + if matchLen(s, sep, 0) == 0: + x = 0 while last <= len(s): var first = last var sepLen = 1 + if x == 0: + inc(last) while last < len(s): x = matchLen(s, sep, last) if x >= 0: sepLen = x break inc(last) - if x == 0: - if last >= len(s): break - inc last if splits == 0: last = len(s) yield substr(s, first, last-1) if splits == 0: break diff --git a/tests/stdlib/tre.nim b/tests/stdlib/tre.nim index 2857c6c9e..9f27f7db2 100644 --- a/tests/stdlib/tre.nim +++ b/tests/stdlib/tre.nim @@ -108,4 +108,10 @@ proc testAll() = doAssert replace("foo", re"", "-") == "-f-o-o-" doAssert replace("ooo", re"o", "-") == "---" + block: # bug #14468 + accum = @[] + for word in split("this is an example", re"\b"): + accum.add(word) + doAssert(accum == @["this", " ", "is", " ", "an", " ", "example"]) + testAll() From 78b86b79425f37683ce522dbdd567f52ea26aa35 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Tue, 14 Dec 2021 16:54:01 +0800 Subject: [PATCH 3192/4254] basicopt.txt: Unify the format (#19251) --- doc/basicopt.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/basicopt.txt b/doc/basicopt.txt index a2db1c92e..390fc6fd2 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -27,11 +27,11 @@ Options: -a, --assertions:on|off turn assertions on|off --opt:none|speed|size optimize not at all or for speed|size Note: use -d:release for a release build! - --debugger:native Use native debugger (gdb) + --debugger:native use native debugger (gdb) --app:console|gui|lib|staticlib generate a console app|GUI app|DLL|static library -r, --run run the compiled program with given arguments - --eval:cmd evaluates nim code directly; e.g.: `nim --eval:"echo 1"` + --eval:cmd evaluate nim code directly; e.g.: `nim --eval:"echo 1"` defaults to `e` (nimscript) but customizable: `nim r --eval:'for a in stdin.lines: echo a'` --fullhelp show all command line switches From c55930f2e644fe04526eb4878e7e106229812fe4 Mon Sep 17 00:00:00 2001 From: Nick Wilburn Date: Tue, 14 Dec 2021 06:22:10 -0600 Subject: [PATCH 3193/4254] fix: fixes bug in CVerifyPeerUseEnvVars (#19247) Previously CVerifyPeerUseEnvVars was not being passed into scanSslCertificates, which meant that we weren't scanning additional certificate locations given via the SSL_CERT_FILE and SSL_CERT_DIR environment variables --- lib/pure/net.nim | 3 ++- tests/stdlib/thttpclient_ssl.nim | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 2d1bb0b33..ced6b2fb2 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -680,7 +680,8 @@ when defineSsl: # Scan for certs in known locations. For CVerifyPeerUseEnvVars also scan # the SSL_CERT_FILE and SSL_CERT_DIR env vars var found = false - for fn in scanSSLCertificates(): + let useEnvVars = (if verifyMode == CVerifyPeerUseEnvVars: true else: false) + for fn in scanSSLCertificates(useEnvVars = useEnvVars): if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess: found = true break diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index 1c531eae9..3acdacfe3 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -129,3 +129,19 @@ when not defined(windows): msg.contains("certificate verify failed")): echo "CVerifyPeer exception: " & msg check(false) + + test "HttpClient with CVerifyPeerUseEnvVars": + const port = 12346.Port + let t = spawn runServer(port) + sleep(100) + + putEnv("SSL_CERT_FILE", getCurrentDir() / certFile) + var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeerUseEnvVars)) + try: + log "client: connect" + discard client.getContent("https://127.0.0.1:12346") + except: + let msg = getCurrentExceptionMsg() + log "client: exception: " & msg + log "getContent should not have raised an exception" + fail() From 3e31f55aed4cd9fdcc289687fd0e31edfc0af805 Mon Sep 17 00:00:00 2001 From: PMunch Date: Tue, 14 Dec 2021 14:28:42 +0100 Subject: [PATCH 3194/4254] Fix #19253 (#19254) This fixes 19253 by marking the bodyStream as completed when no content was sent. --- lib/pure/httpclient.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 33da6ef6c..67ba8cf2b 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -869,6 +869,9 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, client.parseBodyFut.addCallback do(): if client.parseBodyFut.failed: client.bodyStream.fail(client.parseBodyFut.error) + else: + when client is AsyncHttpClient: + result.bodyStream.complete() proc newConnection(client: HttpClient | AsyncHttpClient, url: Uri) {.multisync.} = From c17baaefbcff5c207a4e95242fa0790e64ca6c8c Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 14 Dec 2021 18:16:49 +0100 Subject: [PATCH 3195/4254] [backport:1.0] json: limit recursion depth (#19252) * json: limit recursion depth * do not run this check for JS backend --- lib/pure/json.nim | 12 +++++++++--- tests/stdlib/tjson.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index c831bf85d..922cd4e2f 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -202,6 +202,8 @@ type of JArray: elems*: seq[JsonNode] +const DepthLimit = 1000 + proc newJString*(s: string): JsonNode = ## Creates a new `JString JsonNode`. result = JsonNode(kind: JString, str: s) @@ -849,7 +851,7 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] = for key, val in mpairs(node.fields): yield (key, val) -proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode = +proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool, depth = 0): JsonNode = ## Parses JSON from a JSON Parser `p`. case p.tok of tkString: @@ -885,6 +887,8 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode = result = newJNull() discard getTok(p) of tkCurlyLe: + if depth > DepthLimit: + raiseParseErr(p, "}") result = newJObject() discard getTok(p) while p.tok != tkCurlyRi: @@ -893,16 +897,18 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode = var key = p.a discard getTok(p) eat(p, tkColon) - var val = parseJson(p, rawIntegers, rawFloats) + var val = parseJson(p, rawIntegers, rawFloats, depth+1) result[key] = val if p.tok != tkComma: break discard getTok(p) eat(p, tkCurlyRi) of tkBracketLe: + if depth > DepthLimit: + raiseParseErr(p, "]") result = newJArray() discard getTok(p) while p.tok != tkBracketRi: - result.add(parseJson(p, rawIntegers, rawFloats)) + result.add(parseJson(p, rawIntegers, rawFloats, depth+1)) if p.tok != tkComma: break discard getTok(p) eat(p, tkBracketRi) diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index 289ef9d05..336558ff3 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -345,3 +345,35 @@ block: doAssert c == "18446744073709552000" else: doAssert c == "18446744073709551615" + +block: + let a = """ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +""" + + when not defined(js): + try: + discard parseJson(a) + except JsonParsingError: + doAssert getCurrentExceptionMsg().contains("] expected") From 5d2bab7558b54813b212a26fbcdb51556ff37b05 Mon Sep 17 00:00:00 2001 From: Sven Keller Date: Thu, 16 Dec 2021 08:58:32 +0100 Subject: [PATCH 3196/4254] suggestion to respect typedarray type (#19257) * suggestion to respect typedarray * Update jssys.nim Co-authored-by: Sven Keller --- lib/system/jssys.nim | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 250bd069d..6608a2927 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -587,7 +587,33 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = else: asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;" nimCopyAux(result, src, ti.node) - of tySequence, tyArrayConstr, tyOpenArray, tyArray: + of tyArrayConstr, tyArray: + # In order to prevent a type change (TypedArray -> Array) and to have better copying performance, + # arrays constructors are considered separately + asm """ + if(ArrayBuffer.isView(`src`)) { + if(`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { + `dest` = new `src`.constructor(`src`); + } else { + `dest`.set(`src`, 0); + } + `result` = `dest`; + } else { + if (`src` === null) { + `result` = null; + } + else { + if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { + `dest` = new Array(`src`.length); + } + `result` = `dest`; + for (var i = 0; i < `src`.length; ++i) { + `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base); + } + } + } + """ + of tySequence, tyOpenArray: asm """ if (`src` === null) { `result` = null; From 609388e33fb9a19d65b5dee8711d411916981802 Mon Sep 17 00:00:00 2001 From: snxx Date: Fri, 17 Dec 2021 13:58:05 +0600 Subject: [PATCH 3197/4254] Add icon for Nim (#19258) * Add Nim's file icon * Add installer icon * Add uninstaller icon --- tools/niminst/nim-file.ico | Bin 0 -> 3311 bytes tools/niminst/setup.ico | Bin 0 -> 2551 bytes tools/niminst/uninstall.ico | Bin 0 -> 2226 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/niminst/nim-file.ico create mode 100644 tools/niminst/setup.ico create mode 100644 tools/niminst/uninstall.ico diff --git a/tools/niminst/nim-file.ico b/tools/niminst/nim-file.ico new file mode 100644 index 0000000000000000000000000000000000000000..0685fedcb0b7851d874bbe9606912b243e712e68 GIT binary patch literal 3311 zcmcImc{r47AAV=dVJZ$K8ctcWv{wMn{(~UoFwoaF+h5(Ea8~eT?Oosm0PHyi+L~7b#)y-_?!!MI9h;na7f`h} zXFk}JSzA3vZA#{%w7YC|(+9um$fjy{M#buOB%}P^+uxT{Ug&jKK!`AQP*HcO$LWs*MNm@IPit%3;KnR(&oYeK@_I zSh=1>ik^&tLGXN2Er&&)q$j97f^z{}5D_GRg#9^fTj56fJ=Xm$V4MOJJ9{EJ>l952 z3tBRglp{ME8tL1hKslps`^bHLZTz1k2+%9Hp3wP`Cp~{e)7m9?C|N9^OCBDc6J5vR zK~BV!x;7|ibOHheL~Lik=$3ZSIX+Sp3E-_n6B2^j&k8D|_pz+%sB7xRaUlSCte5;j z6b8t8fy)0D!_|d4L{*21>MqF}(D>%hm$L#?%^gICwrKDocpZ#ReTSeO4d z2(g9#g@!CF9Nhml>R?p}OwEY+3=gnB9^@FAL{HCTDH-guS>Iyjm@}Sx)+(8$g<98X zsN`)Mr%a@A`%xW^LWBTVPK|1r;iLMVw~0?HPZsuPNW*MN<=nEcz8*546B#wA5;%k> z+QJ~RRXYv$8Xa4@$V*gR9$xF@zA^iEi@JbkhxM(HC$|ffhLiTLoxiS*ySo^bdGUB8 z0FkAh#O$RNX?Ao_C@bc5O?6X&Yi+LV;#CjVM=AUZj`XXRp2npLv+3uak&WjW2$ZRhOjr|2RixqFRg_i$slK! zTJ$cZR&xg#t&QY;VPP`qr_lWTuI^Cw@|hzU4a$hE(zT!M-9lUd){UgI6n^A47O!aV zv}5J*0K4L7O@yXbq;da(0(;lDK=VZ@GD8H4UL-~i5l%YWkJ~VwPbj~ilK@@~H1WzN zJlbhc7V)Jzq%^5I4-6!m)&+@qBdhZ-V6fAMl%5|xdw9VT65;XXb8b4Y7NaPX`_r`f z)y@dwOwTc2Fztfr6r77?`rBl`35>l*pd2feYU%XO8|RZ)P^0zt&);pyWc{yL~qxG~pw& z!lmze=F8WV)SRyDdbRS|jiLOHqzEBk!HjO4Yp9gxuWj3*?xqJDli0H*eiJlYAJdX+Arakc=^FnZu-H z!Bbmm{;kgrsU+a-OqUPbq;ag z4%{0@t)?`u1m-qA06$z*jCYbw2lGO$$=<7A8ODd65UBu>kk8^F7Fz=30`jVEUQDGV z*1k$^Fff!lGe9?gy|cguMFMc7^M^hCA*?($_UEwb)lAZI*WxF{k7e++TAtL!uyL92(JM*mdVd<5i3=-OyiP$htOvEZHTx*xEkz9(Uz_$E?7#*bdqVpU_6w0riY?K$P8bD>cD z`?Thj?Kcw=m%Uo^*(%Qbz5@gNUCk4%`k9*z{6T%fdzQZi^)ap_TAAEoq|0*w6VETQ zt^Vk|VlLc>$(eaz60c^?L*io-0uVxJuXpb)8z z`YVQmHv-JCqGCO{BYrq;W3yuX{j;A$3pNoouX70yqh~6HVBMbCR`$B&tuwtfsEV8P z%i<2a@1-aNK`;?&N@vjW0+0FLD25L?hkRc4;5Wb1`(>5$7hwRriwF8#Ny+PGAKOh0 z`J7F?2XBIP9+|7E9@cqtcH`?ET0n+5-7i<#yk_#F*)y=YYsrC3O9Hm`u>WTx@XuZY zh8O`IcDL58x& zNTR4C`wRl7#+CN2(EO_Zn{uXOOjrS>UGa;2KcUA zbwo=3gM8mkXn@_}a0t{^*KKMl=bi}*3y8(DXyj(Plig?Bb#k)yXXxotG0E` z@e{Lc8=7tGzkV6DPUk~&rYnNoC;UGe_%DdNS!bQS&N+MU@B7X=>l^?8aoT}_09jy$ z9{`SX{6uR@xZq*Q!yH!-VQPHsVD+H$9pVhmA*Egbz+Z|m{>?6Y?AxS^|C6m>+Gx`k z_0L^%wWw{2@4XsdYJSV+h@$!*q5PLrJra+JXdltOo#4-ZvpNRiMiM}Z2e!XG=db85 zprWoIkF+aS6_@z4+_23BHr>&jViv%~&Mfx-U?3XIdApF>y2kux{u6 zSvars>y=p}Qb5EzQzKZWYO88(U9U7Cs&*jm{|ih4a`EybSKIM*nc9`xr*4YpQv3uP zfJeuRCL`eA8ZIDeK&nPZL4S$(f0X5mUPuBm)O;~q@oFREs4royN9=ulaXM~Ml5Q`e zt7S}93p5?qNE;V+!Q-W!K}gwGZ+WTYKJfyDoe`7fXPoVif9VW65=NN6kkKlv!!2)N31nU4}y_GNYOB_%GCZ&*2UsyEwBp+wCmJ^VKN-NH_vh2Ppb2-y_Mj_%SY<#i z$fkB7v*QJMNIvAo)|Q}+EgI=K{!kS!>PCzRlTMw8M@ONT#aqL7dPQvI-Pe4kFFXKH z60wn&qOF-%i-1bc|^kzKuITh7&e=u#AiWro#r0*K&aGN5yIcy69>CAFla|R%G9wZFP za05)uxW~}l=F!}Fj+$8kQZ;-WVH8^d>lDcO9iAAu)HeLbX?*i=n*iXOWC&+?WypY( z?Ug$956=A{O5!B`Bb!htFB8iF{GUJ{m2u$`v$gZ}V8betHr{)(z+Fkss-SqNWYxzs z;A@q@&e_<^>M%tZm{aC}D{12Xp)}W=qd5x@i5__J#S->xJsP3aqNa*9AXo#3HNaV< z=>U3K?1?A%Y#aPED2UG*fGnXvY2+;+p; zh*4GX)^C`tuUK}G&TfP?KyT-(NVM&V^n!KvfNWtKj{8e9b4oq^$VYD_Cqbjbj$A+Q z+M=hEiJx8&^KrK0l+7dN9UVU)ndMYyMx}{V5}8@`Ay=2BYevo)PHr}nN3bdibG@nB+nz|wb)16u*-POZ7(FTadnF4) z>z0a$W9rKN76hBHDc-887OgOB>+P|WvMmU0+YpASay``K8GTuA|3f1LLR%hJFQ5(3 zvwy$gXa3SBnNnlf9#6|%m{_yBsq%2hA`yo}g=J9f{Cp$#G8;2G$LVQertoM;lOqdZFtxuG6saLOIfUh2&s2Ce>o@^QfIPZ^7(p zcWjM!Zc0QT`%8{M;!U=e(iU}AI3}MX?)BgeQxoIwdQ=!~HI+uSNLE>_-Qy^V8jzXq zVn#P87;G=H*Oj(AHnrPdFhXH_@KLTjTzQ0sI3XH?(u-V=<<#!GI1OkxbL!DHGU__H zFfxgq#k9wbU;Tnd(#@M*7n~VFaYV=uexsG>jdhjA-digE&1#=#vpRSo{hd|DE8ThH zwe-r4vFmR~Z{)6hR0TwzxC~9IvFPUh(G42Md%BP6(6nJLk_6(XgH7SIx+1Owfi$)qzOSAs|(PiH0fs|pft*#7L5$qg2-7&~z z9b;wHswd*-Fy}r;S0MSXB-Jq(&%R((mMDR{bNb@}l+1l^EGTbrwS0}=(72u4L2+!* zfeI28Y|zSyOHc3yoMY~bM{a$>xeU3e`5Gy<+(m0CM&D|#oDU+OISmF**`P~xB@GaL z2DU`}pqaSPx5yWXa}Z{9$=4iqmTLb#WEfC3>i2&eF7jqR=$Ph%1|ERC{Hl49R^yiX zV?6Grll(IZ8SjAl6%Z|Q8Ip&_GGXTK9chw31L*=ko1K-~ znCY=szQ`<@$xzs@F3|nm9y8am!U8`Ebm){dkbViXRTSEW?rrl-khJCUkz7GndY`Y= zBx4*LJZG27%zH{#8yz;7mk}CL{lu&tZXjXNCm9i06pqR6 zD<1+sVj3jlv~45Dg#ne!sJ$tQ45aP^{}qDffB!;a;;2zT$`kD)?{GUo^-!<$LY=;d wL%Sh-oNRoYf7Z{m|A-R+ow1$5#O@i^ICKpvQHMNZ-`BJO;KT7(uw57M@WEOFY8<42S`WP!n3 z*&ln-C)|k!FC}Y#KifKdj$t>U#GEDGf9I~09&~lbuYtW$Sl39)~C^FGZ5o^>%}TKsq`5l1Z+@3QpwM zzcKhjCg_VdDjf44z%%7Vp6Sbb!!G^~)b~)J9k@x)Uj14-y2iLI2HY-L_#+ihD_#e` zDU=3TRy1(X1V2}t>eC)v;*wdpu(B5tw;(w(23LyXjw<|TIBiYaciKN823k1$&|jQ0 z+|A)phY1a>hAaqSnQCL^R+u$zB=nbe^*bdt-=!L&jM4s_aHLggzvMH>uUVYt>^_;! zpEXh2{blpW;)26Ps9$=8RdaacgD7rT2_<*Qjdx^AQsApzRnf zE?BR&I@8%T>nqQEsW2FDU@=&wsKC=%L?=`*lrmb<;PKf*Uoq38Qio+eoCL*vHzRa5yP*?X8Ei zZDUn~KFlj-XVi4@OQq#_Uy;X(4_IF`gWW`sJbB9hd-FThzWm5;2fOAZxn&t+!YbW` zw;$+3Z``oM&D|;w6}DDb#|S7~%W2f0t`SfJ^|+Jj=hTF+*aLjvz9kp(X_+Lm%&EznGb?ZqQX zgG_}0)G6N6*xPUbUwkLGSTl9qsGAm@+07QWLlPkGE<{A;chhV_Qn#|_0n7hx3DJky zbX1AIQ?~4e{aetJHcrzjUXO~};5K=65$B(KpZVL=&ly7f;b=e1=K!pdY5kYd>iw*3 z?I25M1)AVObU;R;d{qwT=cYxC%-wAHE)tcOsm54b_?eTJ0gq2HhRFpN?iO*4HRVf{ zP6VxYQ*=Nfm7Plo(}Q+38zO4>H4hWQoo3AIt|K&eZs^{-*x9RU<9pm^OL9AkgfmMx)dyX}&^I0)G$(X5h5Iz-|U>pHG2_ccrHayazRp}&W@I+s}5FOzk{PC9X z+{DTGkv!7+om&N_2b8cvPt56<%dOA3rwud?i2)sI_%(eKw%r|U<)Heul!K2 z<}6EpDjs_{&qFAE1zdQS6OH6R=;4QwALS&7fxwloR}vOpVjVX9JC3))oMzX`9(P%S z9#QG3On-eZb?TOtx_5Jvu>JpqkkCSs%JnVTHfg=x) z`I$;Li9hYO c(!hC-V4HpC^wmC3csCFYjFlt0+R`unUtQjos{jB1 literal 0 HcmV?d00001 From 5ddaf3e1fbff4c0519088612f9ec3b10d62d2316 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Fri, 17 Dec 2021 05:01:33 -0300 Subject: [PATCH 3198/4254] fix #19244 - solves the problem of the InAddr object constructor in Windows. (#19259) * Update winlean.nim * Update tnet_ll.nim --- lib/windows/winlean.nim | 2 +- tests/stdlib/tnet_ll.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index b8f3886d7..6e626e4ba 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -478,7 +478,7 @@ type PSockAddr = ptr SockAddr - InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object + InAddr* {.importc: "IN_ADDR", header: "winsock2.h", union.} = object s_addr*: uint32 # IP address Sockaddr_in* {.importc: "SOCKADDR_IN", diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index 248dbb79b..2d340cea8 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -26,6 +26,7 @@ suite "inet_ntop tests": # regular var ip4 = InAddr() ip4.s_addr = 0x10111213'u32 + check: ip4.s_addr == 0x10111213'u32 var buff: array[0..255, char] let r = inet_ntop(AF_INET, cast[pointer](ip4.s_addr.addr), buff[0].addr, buff.len.int32) @@ -43,3 +44,8 @@ suite "inet_ntop tests": let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), buff[0].addr, buff.len.int32) let res = if r == nil: "" else: $r check: not ipv6Support or res == "10:110:20:120:30:130:40:140" + + test "InAddr": + # issue 19244 + var ip4 = InAddr(s_addr: 0x10111213'u32) + check: ip4.s_addr == 0x10111213'u32 From 3d9b6cfebce898dede2f63d0288050a106a7f5e4 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 17 Dec 2021 18:16:59 +0800 Subject: [PATCH 3199/4254] [formatter] async.nim uses two spaces (#19264) according to https://nim-lang.org/docs/nep1.html#introduction-spacing-and-whitespace-conventions, two spaces should be preferred in stdlib. --- lib/pure/async.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/async.nim b/lib/pure/async.nim index 97b29f81d..482ab32c6 100644 --- a/lib/pure/async.nim +++ b/lib/pure/async.nim @@ -1,6 +1,6 @@ when defined(js): - import asyncjs - export asyncjs + import asyncjs + export asyncjs else: - import asyncmacro, asyncfutures - export asyncmacro, asyncfutures + import asyncmacro, asyncfutures + export asyncmacro, asyncfutures From 610516e02756dd1447fc807077bacf86eb75acdd Mon Sep 17 00:00:00 2001 From: Don-Duong Quach Date: Fri, 17 Dec 2021 11:58:31 -0800 Subject: [PATCH 3200/4254] Fixed typo in manual.rst unsafeAssign->uncheckedAssign. Fixes part 1 of #19266 (#19267) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index 6705e673e..d9f5d4ea6 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1838,7 +1838,7 @@ A small example: cast uncheckedAssign -------------------- -Some restrictions for case objects can be disabled via a `{.cast(unsafeAssign).}` section: +Some restrictions for case objects can be disabled via a `{.cast(uncheckedAssign).}` section: .. code-block:: nim :test: "nim c $1" From b812431f831748c9013a12074cc6a7a838b580cd Mon Sep 17 00:00:00 2001 From: xioren <40043405+xioren@users.noreply.github.com> Date: Sun, 19 Dec 2021 05:01:17 -0800 Subject: [PATCH 3201/4254] use uppercase "type" for Proxy-Authorization header (#19273) Some servers will reject authorization requests with a lowercase "basic" type. Changing to "Basic" seems to solve these issues. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 67ba8cf2b..7686d15bd 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -523,7 +523,7 @@ proc generateHeaders(requestUrl: Uri, httpMethod: HttpMethod, headers: HttpHeade # Proxy auth header. if not proxy.isNil and proxy.auth != "": let auth = base64.encode(proxy.auth) - add(result, "Proxy-Authorization: basic " & auth & httpNewLine) + add(result, "Proxy-Authorization: Basic " & auth & httpNewLine) for key, val in headers: add(result, key & ": " & val & httpNewLine) From ea475a4e98bc1cfc861f870baf6f2cc4c979ac7a Mon Sep 17 00:00:00 2001 From: MichalMarsalek Date: Mon, 20 Dec 2021 10:40:32 +0100 Subject: [PATCH 3202/4254] Update colors.nim (#19274) * Update colors.nim Added `lightgray` alias to `lightgrey` and `...grey`aliases for the rest of the gray colors. Added color `rebeccapurple`. Fixed the incorrect values for the `PaleVioletRed` and `MediumPurple` colors. This module should now be matching the CSS colors. I used the seq[tuple] syntax for defining the names. * Document colors changes. --- changelog.md | 2 + lib/pure/colors.nim | 307 +++++++++++++++++++++++--------------------- 2 files changed, 164 insertions(+), 145 deletions(-) diff --git a/changelog.md b/changelog.md index 6f47ef8a4..52159b865 100644 --- a/changelog.md +++ b/changelog.md @@ -15,11 +15,13 @@ `experimental:flexibleOptionalParams`. - `std/sharedstrings` module is removed. +- Constants `colors.colPaleVioletRed` and `colors.colMediumPurple` changed to match the CSS color standard. ## Standard library additions and changes - `macros.parseExpr` and `macros.parseStmt` now accept an optional filename argument for more informative errors. +- Module `colors` expanded with missing colors from the CSS color standard. ## `std/smtp` diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 2193f69a6..8cda2fab8 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -6,7 +6,8 @@ # distribution, for details about the copyright. # -## This module implements color handling for Nim. +## This module implements color handling for Nim, +## namely color mixing and parsing the CSS color names. import strutils from algorithm import binarySearch @@ -170,6 +171,7 @@ const colDarkGoldenRod* = Color(0xB8860B) colDarkGray* = Color(0xA9A9A9) colDarkGreen* = Color(0x006400) + colDarkGrey* = Color(0xA9A9A9) colDarkKhaki* = Color(0xBDB76B) colDarkMagenta* = Color(0x8B008B) colDarkOliveGreen* = Color(0x556B2F) @@ -180,11 +182,13 @@ const colDarkSeaGreen* = Color(0x8FBC8F) colDarkSlateBlue* = Color(0x483D8B) colDarkSlateGray* = Color(0x2F4F4F) + colDarkSlateGrey* = Color(0x2F4F4F) colDarkTurquoise* = Color(0x00CED1) colDarkViolet* = Color(0x9400D3) colDeepPink* = Color(0xFF1493) colDeepSkyBlue* = Color(0x00BFFF) colDimGray* = Color(0x696969) + colDimGrey* = Color(0x696969) colDodgerBlue* = Color(0x1E90FF) colFireBrick* = Color(0xB22222) colFloralWhite* = Color(0xFFFAF0) @@ -196,6 +200,7 @@ const colGoldenRod* = Color(0xDAA520) colGray* = Color(0x808080) colGreen* = Color(0x008000) + colGrey* = Color(0x808080) colGreenYellow* = Color(0xADFF2F) colHoneyDew* = Color(0xF0FFF0) colHotPink* = Color(0xFF69B4) @@ -211,13 +216,15 @@ const colLightCoral* = Color(0xF08080) colLightCyan* = Color(0xE0FFFF) colLightGoldenRodYellow* = Color(0xFAFAD2) - colLightGrey* = Color(0xD3D3D3) + colLightGray* = Color(0xD3D3D3) colLightGreen* = Color(0x90EE90) + colLightGrey* = Color(0xD3D3D3) colLightPink* = Color(0xFFB6C1) colLightSalmon* = Color(0xFFA07A) colLightSeaGreen* = Color(0x20B2AA) colLightSkyBlue* = Color(0x87CEFA) colLightSlateGray* = Color(0x778899) + colLightSlateGrey* = Color(0x778899) colLightSteelBlue* = Color(0xB0C4DE) colLightYellow* = Color(0xFFFFE0) colLime* = Color(0x00FF00) @@ -228,7 +235,7 @@ const colMediumAquaMarine* = Color(0x66CDAA) colMediumBlue* = Color(0x0000CD) colMediumOrchid* = Color(0xBA55D3) - colMediumPurple* = Color(0x9370D8) + colMediumPurple* = Color(0x9370DB) colMediumSeaGreen* = Color(0x3CB371) colMediumSlateBlue* = Color(0x7B68EE) colMediumSpringGreen* = Color(0x00FA9A) @@ -249,7 +256,7 @@ const colPaleGoldenRod* = Color(0xEEE8AA) colPaleGreen* = Color(0x98FB98) colPaleTurquoise* = Color(0xAFEEEE) - colPaleVioletRed* = Color(0xD87093) + colPaleVioletRed* = Color(0xDB7093) colPapayaWhip* = Color(0xFFEFD5) colPeachPuff* = Color(0xFFDAB9) colPeru* = Color(0xCD853F) @@ -257,6 +264,7 @@ const colPlum* = Color(0xDDA0DD) colPowderBlue* = Color(0xB0E0E6) colPurple* = Color(0x800080) + colRebeccaPurple* = Color(0x663399) colRed* = Color(0xFF0000) colRosyBrown* = Color(0xBC8F8F) colRoyalBlue* = Color(0x4169E1) @@ -270,6 +278,7 @@ const colSkyBlue* = Color(0x87CEEB) colSlateBlue* = Color(0x6A5ACD) colSlateGray* = Color(0x708090) + colSlateGrey* = Color(0x708090) colSnow* = Color(0xFFFAFA) colSpringGreen* = Color(0x00FF7F) colSteelBlue* = Color(0x4682B4) @@ -285,147 +294,155 @@ const colYellow* = Color(0xFFFF00) colYellowGreen* = Color(0x9ACD32) - colorNames = [ - ("aliceblue", colAliceBlue), - ("antiquewhite", colAntiqueWhite), - ("aqua", colAqua), - ("aquamarine", colAquamarine), - ("azure", colAzure), - ("beige", colBeige), - ("bisque", colBisque), - ("black", colBlack), - ("blanchedalmond", colBlanchedAlmond), - ("blue", colBlue), - ("blueviolet", colBlueViolet), - ("brown", colBrown), - ("burlywood", colBurlyWood), - ("cadetblue", colCadetBlue), - ("chartreuse", colChartreuse), - ("chocolate", colChocolate), - ("coral", colCoral), - ("cornflowerblue", colCornflowerBlue), - ("cornsilk", colCornsilk), - ("crimson", colCrimson), - ("cyan", colCyan), - ("darkblue", colDarkBlue), - ("darkcyan", colDarkCyan), - ("darkgoldenrod", colDarkGoldenRod), - ("darkgray", colDarkGray), - ("darkgreen", colDarkGreen), - ("darkkhaki", colDarkKhaki), - ("darkmagenta", colDarkMagenta), - ("darkolivegreen", colDarkOliveGreen), - ("darkorange", colDarkorange), - ("darkorchid", colDarkOrchid), - ("darkred", colDarkRed), - ("darksalmon", colDarkSalmon), - ("darkseagreen", colDarkSeaGreen), - ("darkslateblue", colDarkSlateBlue), - ("darkslategray", colDarkSlateGray), - ("darkturquoise", colDarkTurquoise), - ("darkviolet", colDarkViolet), - ("deeppink", colDeepPink), - ("deepskyblue", colDeepSkyBlue), - ("dimgray", colDimGray), - ("dodgerblue", colDodgerBlue), - ("firebrick", colFireBrick), - ("floralwhite", colFloralWhite), - ("forestgreen", colForestGreen), - ("fuchsia", colFuchsia), - ("gainsboro", colGainsboro), - ("ghostwhite", colGhostWhite), - ("gold", colGold), - ("goldenrod", colGoldenRod), - ("gray", colGray), - ("green", colGreen), - ("greenyellow", colGreenYellow), - ("honeydew", colHoneyDew), - ("hotpink", colHotPink), - ("indianred", colIndianRed), - ("indigo", colIndigo), - ("ivory", colIvory), - ("khaki", colKhaki), - ("lavender", colLavender), - ("lavenderblush", colLavenderBlush), - ("lawngreen", colLawnGreen), - ("lemonchiffon", colLemonChiffon), - ("lightblue", colLightBlue), - ("lightcoral", colLightCoral), - ("lightcyan", colLightCyan), - ("lightgoldenrodyellow", colLightGoldenRodYellow), - ("lightgreen", colLightGreen), - ("lightgrey", colLightGrey), - ("lightpink", colLightPink), - ("lightsalmon", colLightSalmon), - ("lightseagreen", colLightSeaGreen), - ("lightskyblue", colLightSkyBlue), - ("lightslategray", colLightSlateGray), - ("lightsteelblue", colLightSteelBlue), - ("lightyellow", colLightYellow), - ("lime", colLime), - ("limegreen", colLimeGreen), - ("linen", colLinen), - ("magenta", colMagenta), - ("maroon", colMaroon), - ("mediumaquamarine", colMediumAquaMarine), - ("mediumblue", colMediumBlue), - ("mediumorchid", colMediumOrchid), - ("mediumpurple", colMediumPurple), - ("mediumseagreen", colMediumSeaGreen), - ("mediumslateblue", colMediumSlateBlue), - ("mediumspringgreen", colMediumSpringGreen), - ("mediumturquoise", colMediumTurquoise), - ("mediumvioletred", colMediumVioletRed), - ("midnightblue", colMidnightBlue), - ("mintcream", colMintCream), - ("mistyrose", colMistyRose), - ("moccasin", colMoccasin), - ("navajowhite", colNavajoWhite), - ("navy", colNavy), - ("oldlace", colOldLace), - ("olive", colOlive), - ("olivedrab", colOliveDrab), - ("orange", colOrange), - ("orangered", colOrangeRed), - ("orchid", colOrchid), - ("palegoldenrod", colPaleGoldenRod), - ("palegreen", colPaleGreen), - ("paleturquoise", colPaleTurquoise), - ("palevioletred", colPaleVioletRed), - ("papayawhip", colPapayaWhip), - ("peachpuff", colPeachPuff), - ("peru", colPeru), - ("pink", colPink), - ("plum", colPlum), - ("powderblue", colPowderBlue), - ("purple", colPurple), - ("red", colRed), - ("rosybrown", colRosyBrown), - ("royalblue", colRoyalBlue), - ("saddlebrown", colSaddleBrown), - ("salmon", colSalmon), - ("sandybrown", colSandyBrown), - ("seagreen", colSeaGreen), - ("seashell", colSeaShell), - ("sienna", colSienna), - ("silver", colSilver), - ("skyblue", colSkyBlue), - ("slateblue", colSlateBlue), - ("slategray", colSlateGray), - ("snow", colSnow), - ("springgreen", colSpringGreen), - ("steelblue", colSteelBlue), - ("tan", colTan), - ("teal", colTeal), - ("thistle", colThistle), - ("tomato", colTomato), - ("turquoise", colTurquoise), - ("violet", colViolet), - ("wheat", colWheat), - ("white", colWhite), - ("whitesmoke", colWhiteSmoke), - ("yellow", colYellow), - ("yellowgreen", colYellowGreen)] + colorNames = { + "aliceblue": colAliceBlue, + "antiquewhite": colAntiqueWhite, + "aqua": colAqua, + "aquamarine": colAquamarine, + "azure": colAzure, + "beige": colBeige, + "bisque": colBisque, + "black": colBlack, + "blanchedalmond": colBlanchedAlmond, + "blue": colBlue, + "blueviolet": colBlueViolet, + "brown": colBrown, + "burlywood": colBurlyWood, + "cadetblue": colCadetBlue, + "chartreuse": colChartreuse, + "chocolate": colChocolate, + "coral": colCoral, + "cornflowerblue": colCornflowerBlue, + "cornsilk": colCornsilk, + "crimson": colCrimson, + "cyan": colCyan, + "darkblue": colDarkBlue, + "darkcyan": colDarkCyan, + "darkgoldenrod": colDarkGoldenRod, + "darkgray": colDarkGray, + "darkgreen": colDarkGreen, + "darkgrey": colDarkGrey, + "darkkhaki": colDarkKhaki, + "darkmagenta": colDarkMagenta, + "darkolivegreen": colDarkOliveGreen, + "darkorange": colDarkorange, + "darkorchid": colDarkOrchid, + "darkred": colDarkRed, + "darksalmon": colDarkSalmon, + "darkseagreen": colDarkSeaGreen, + "darkslateblue": colDarkSlateBlue, + "darkslategray": colDarkSlateGray, + "darkslategrey": colDarkSlateGrey, + "darkturquoise": colDarkTurquoise, + "darkviolet": colDarkViolet, + "deeppink": colDeepPink, + "deepskyblue": colDeepSkyBlue, + "dimgray": colDimGray, + "dimgrey": colDimGrey, + "dodgerblue": colDodgerBlue, + "firebrick": colFireBrick, + "floralwhite": colFloralWhite, + "forestgreen": colForestGreen, + "fuchsia": colFuchsia, + "gainsboro": colGainsboro, + "ghostwhite": colGhostWhite, + "gold": colGold, + "goldenrod": colGoldenRod, + "gray": colGray, + "green": colGreen, + "grey": colGrey, + "greenyellow": colGreenYellow, + "honeydew": colHoneyDew, + "hotpink": colHotPink, + "indianred": colIndianRed, + "indigo": colIndigo, + "ivory": colIvory, + "khaki": colKhaki, + "lavender": colLavender, + "lavenderblush": colLavenderBlush, + "lawngreen": colLawnGreen, + "lemonchiffon": colLemonChiffon, + "lightblue": colLightBlue, + "lightcoral": colLightCoral, + "lightcyan": colLightCyan, + "lightgoldenrodyellow": colLightGoldenRodYellow, + "lightgray": colLightGray, + "lightgreen": colLightGreen, + "lightgrey": colLightGrey, + "lightpink": colLightPink, + "lightsalmon": colLightSalmon, + "lightseagreen": colLightSeaGreen, + "lightskyblue": colLightSkyBlue, + "lightslategray": colLightSlateGray, + "lightslategrey": colLightSlateGrey, + "lightsteelblue": colLightSteelBlue, + "lightyellow": colLightYellow, + "lime": colLime, + "limegreen": colLimeGreen, + "linen": colLinen, + "magenta": colMagenta, + "maroon": colMaroon, + "mediumaquamarine": colMediumAquaMarine, + "mediumblue": colMediumBlue, + "mediumorchid": colMediumOrchid, + "mediumpurple": colMediumPurple, + "mediumseagreen": colMediumSeaGreen, + "mediumslateblue": colMediumSlateBlue, + "mediumspringgreen": colMediumSpringGreen, + "mediumturquoise": colMediumTurquoise, + "mediumvioletred": colMediumVioletRed, + "midnightblue": colMidnightBlue, + "mintcream": colMintCream, + "mistyrose": colMistyRose, + "moccasin": colMoccasin, + "navajowhite": colNavajoWhite, + "navy": colNavy, + "oldlace": colOldLace, + "olive": colOlive, + "olivedrab": colOliveDrab, + "orange": colOrange, + "orangered": colOrangeRed, + "orchid": colOrchid, + "palegoldenrod": colPaleGoldenRod, + "palegreen": colPaleGreen, + "paleturquoise": colPaleTurquoise, + "palevioletred": colPaleVioletRed, + "papayawhip": colPapayaWhip, + "peachpuff": colPeachPuff, + "peru": colPeru, + "pink": colPink, + "plum": colPlum, + "powderblue": colPowderBlue, + "purple": colPurple, + "rebeccapurple": colRebeccaPurple, + "red": colRed, + "rosybrown": colRosyBrown, + "royalblue": colRoyalBlue, + "saddlebrown": colSaddleBrown, + "salmon": colSalmon, + "sandybrown": colSandyBrown, + "seagreen": colSeaGreen, + "seashell": colSeaShell, + "sienna": colSienna, + "silver": colSilver, + "skyblue": colSkyBlue, + "slateblue": colSlateBlue, + "slategray": colSlateGray, + "slategrey": colSlateGrey, + "snow": colSnow, + "springgreen": colSpringGreen, + "steelblue": colSteelBlue, + "tan": colTan, + "teal": colTeal, + "thistle": colThistle, + "tomato": colTomato, + "turquoise": colTurquoise, + "violet": colViolet, + "wheat": colWheat, + "white": colWhite, + "whitesmoke": colWhiteSmoke, + "yellow": colYellow, + "yellowgreen": colYellowGreen} proc `$`*(c: Color): string = ## Converts a color into its textual representation. From 4da7dbffc504db9159285ca59e2cdfe9b103afb8 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 21 Dec 2021 03:29:03 +1100 Subject: [PATCH 3203/4254] Extract runnables that specify `doccmd` (#19275) [backport:1.6] --- lib/core/macros.nim | 4 ++-- tests/stdlib/tmacros.nim | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 444783b5a..ed7e85c64 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1715,8 +1715,8 @@ proc extractDocCommentsAndRunnables*(n: NimNode): NimNode = case ni.kind of nnkCommentStmt: result.add ni - of nnkCall: - if ni[0].kind == nnkIdent and ni[0].strVal == "runnableExamples": + of nnkCall, nnkCommand: + if ni[0].kind == nnkIdent and ni[0].eqIdent "runnableExamples": result.add ni else: break else: break diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index 64a474743..299eac49b 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -124,3 +124,23 @@ block: # SameType assert not testTensorInt(x1) assert testTensorInt(x2) assert not testTensorInt(x3) + +block: # extractDocCommentsAndRunnables + macro checkRunnables(prc: untyped) = + let runnables = prc.body.extractDocCommentsAndRunnables() + doAssert runnables[0][0].eqIdent("runnableExamples") + + macro checkComments(comment: static[string], prc: untyped) = + let comments = prc.body.extractDocCommentsAndRunnables() + doAssert comments[0].strVal == comment + + proc a() {.checkRunnables.} = + runnableExamples: discard + discard + + proc b() {.checkRunnables.} = + runnableExamples "-d:ssl": discard + discard + + proc c() {.checkComments("Hello world").} = + ## Hello world From 19898e1225862560b216b765187fc0b98dca7608 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 20 Dec 2021 23:10:15 +0300 Subject: [PATCH 3204/4254] Fix group reference (with capital letters (#19196) in group name) --- compiler/docgen.nim | 3 +- lib/packages/docutils/rst.nim | 2 +- .../expected/subdir/subdir_b/utils.html | 28 +++++++++++++++++++ .../expected/subdir/subdir_b/utils.idx | 2 ++ nimdoc/testproject/expected/theindex.html | 6 ++++ nimdoc/testproject/subdir/subdir_b/utils.nim | 6 ++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 7ba952083..90e0f54b3 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1301,7 +1301,8 @@ proc finishGenerateDoc*(d: var PDoc) = let tooltip = "$1 ($2 overloads)" % [ k.toHumanStr & " " & plainName, $overloadChoices.len] addAnchorNim(d.sharedState, refn, tooltip, - LangSymbol(symKind: k.toHumanStr, name: plainName, + LangSymbol(symKind: k.toHumanStr, + name: nimIdentBackticksNormalize(plainName), isGroup: true), priority = symbolPriority(k), # select index `0` just to have any meaningful warning: diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 4c28894fb..a04eb696f 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -993,7 +993,7 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode, result.add s else: # when there are many overloads a link like foo_ points to all # of them, so selecting the group - var foundGroup = true + var foundGroup = false for s in sList: if s.langSym.isGroup: result.add s diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index c64039941..574ac5b9b 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -207,6 +207,13 @@ window.addEventListener('DOMContentLoaded', main);
  • fn10(a: int): int
  • + +
      funWithGenerics
    • Note that proc can be used in postfix form: binarySearch proc.

      Ref. type like G and type G and G[T] and type G*[T].

      +

      Group ref. with capital letters works: fN11 or fn11

      Ref. [] is the same as proc `[]`(G[T]) because there are no overloads. The full form: proc `[]`*[T](x: G[T]): TRef. []= aka `[]=`(G[T], int, T).Ref. $ aka proc $ or proc `$`.Ref. $(a: ref SomeType).Ref. foo_bar aka iterator foo_bar_.Ref. fn[T; U,V: SomeFloat]().Ref. 'big or func `'big` or `'big`(string).

      Types

      @@ -539,6 +547,26 @@ comment comment + +
      + + + +
      +
      +
      func fN11() {....raises: [], tags: [].}
      +
      + + + +
      +
      +
      +
      func fN11(x: int) {....raises: [], tags: [].}
      +
      + + +
      diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx index 441bd8675..5c8fee527 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx @@ -17,6 +17,8 @@ fn7 subdir/subdir_b/utils.html#fn7 utils: fn7() fn8 subdir/subdir_b/utils.html#fn8 utils: fn8(): auto fn9 subdir/subdir_b/utils.html#fn9,int utils: fn9(a: int): int fn10 subdir/subdir_b/utils.html#fn10,int utils: fn10(a: int): int +fN11 subdir/subdir_b/utils.html#fN11 utils: fN11() +fN11 subdir/subdir_b/utils.html#fN11,int utils: fN11(x: int) aEnum subdir/subdir_b/utils.html#aEnum.t utils: aEnum(): untyped bEnum subdir/subdir_b/utils.html#bEnum.t utils: bEnum(): untyped fromUtilsGen subdir/subdir_b/utils.html#fromUtilsGen.t utils: fromUtilsGen(): untyped diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index da76334d4..88d4b86aa 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -209,6 +209,12 @@ window.addEventListener('DOMContentLoaded', main);
    • utils: fn10(a: int): int
    +
    fN11:
    fn2:
    • utils: fn2()
    • diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index 5d881e620..e201a3d38 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -36,6 +36,7 @@ Note that `proc` can be used in postfix form: `binarySearch proc`_. Ref. type like G_ and `type G`_ and `G[T]`_ and `type G*[T]`_. +Group ref. with capital letters works: fN11_ or fn11_ ]## include ./utils_helpers @@ -77,6 +78,11 @@ proc fn8*(): auto = func fn9*(a: int): int = 42 ## comment func fn10*(a: int): int = a ## comment +# Note capital letter N will be handled correctly in +# group references like fN11_ or fn11_: +func fN11*() = discard +func fN11*(x: int) = discard + # bug #9235 template aEnum*(): untyped = From 7a5314c571ec2c370f63d5fab0afd336e04ec161 Mon Sep 17 00:00:00 2001 From: pkubaj Date: Thu, 23 Dec 2021 02:52:33 +0100 Subject: [PATCH 3205/4254] Fix build on FreeBSD/powerpc (#19282) It's currently misdetected as powerpc64. --- tools/niminst/buildsh.nimf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 464c70abf..5f1db9cd3 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -192,8 +192,10 @@ case $ucpu in mycpu="powerpc64" ;; *power*|*ppc* ) if [ "$myos" = "freebsd" ] ; then - COMP_FLAGS="$COMP_FLAGS -m64" - LINK_FLAGS="$LINK_FLAGS -m64" + if [ "$ucpu" != "powerpc" ] ; then + COMP_FLAGS="$COMP_FLAGS -m64" + LINK_FLAGS="$LINK_FLAGS -m64" + fi mycpu=`uname -p` case $mycpu in powerpc64le) From 81d32cf7e53b244776c4196098be154c1223d726 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 23 Dec 2021 07:03:40 +0100 Subject: [PATCH 3206/4254] Revert "Update uri.nim (#19148) [backport:1.0]" (#19280) This reverts commit a3ef5df680e55d9bf68027fcb0ec6358b4279d09. --- lib/pure/uri.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 5de333b8f..a828298c2 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -216,8 +216,6 @@ func parseAuthority(authority: string, result: var Uri) = result.isIpv6 = true of ']': inIPv6 = false - of '\0': - break else: if inPort: result.port.add(authority[i]) From fa96e56ad06f0562b5d608cc896a9b17c9512958 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Wed, 22 Dec 2021 23:12:56 -0700 Subject: [PATCH 3207/4254] Fixed object field access of static objects in generics (#19283) [backport] --- compiler/semexprs.nim | 2 +- tests/system/tstatic.nim | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0df332689..c593efe55 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1414,7 +1414,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass: ty = ty.lastSon - ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink}) + ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink, tyStatic}) while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias}) var check: PNode = nil if ty.kind == tyObject: diff --git a/tests/system/tstatic.nim b/tests/system/tstatic.nim index 1f1b9dbe3..6e2893e2b 100644 --- a/tests/system/tstatic.nim +++ b/tests/system/tstatic.nim @@ -44,6 +44,14 @@ template main() = proc parseInt(f: static[bool]): int {.used.} = discard doAssert "123".parseInt == 123 + block: + type + MyType = object + field: float32 + AType[T: static MyType] = distinct range[0f32 .. T.field] + var a: AType[MyType(field: 5f32)] + proc n(S: static Slice[int]): range[S.a..S.b] = discard + assert typeof(n 1..2) is range[1..2] static: main() From fdbec969d8601af0f666426b523e8ebba644ab56 Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Sat, 25 Dec 2021 18:31:35 +0900 Subject: [PATCH 3208/4254] Fix #19107 (#19286) [backport] --- lib/pure/strformat.nim | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 746f01ace..40a33951c 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -574,6 +574,9 @@ template formatValue(result: var string; value: cstring; specifier: string) = result.add value proc strformatImpl(f: string; openChar, closeChar: char): NimNode = + template missingCloseChar = + error("invalid format string: missing closing character '" & closeChar & "'") + if openChar == ':' or closeChar == ':': error "openChar and closeChar must not be ':'" var i = 0 @@ -618,6 +621,8 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = let start = i inc i i += f.skipWhitespace(i) + if i == f.len: + missingCloseChar if f[i] == closeChar or f[i] == ':': result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i])) else: @@ -627,6 +632,9 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = subexpr.add f[i] inc i + if i == f.len: + missingCloseChar + var x: NimNode try: x = parseExpr(subexpr) @@ -639,10 +647,10 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = while i < f.len and f[i] != closeChar: options.add f[i] inc i + if i == f.len: + missingCloseChar if f[i] == closeChar: inc i - else: - doAssert false, "invalid format string: missing '}'" result.add newCall(formatSym, res, x, newLit(options)) elif f[i] == closeChar: if i Date: Mon, 27 Dec 2021 17:28:19 +0100 Subject: [PATCH 3209/4254] fixes grammar typos [backport] (#19289) --- compiler/parser.nim | 6 +++--- doc/grammar.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 9ff847ef6..7bc2c78e0 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -582,10 +582,10 @@ proc parsePar(p: var Parser): PNode = #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' #| | 'when' | 'var' | 'mixin' #| par = '(' optInd - #| ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';' - #| | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';' + #| ( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';' + #| | ';' (ifExpr / complexOrSimpleStmt) ^+ ';' #| | pragmaStmt - #| | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? ) + #| | simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? ) #| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) #| optPar ')' # diff --git a/doc/grammar.txt b/doc/grammar.txt index 8f86dd98c..bf6d381de 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -37,10 +37,10 @@ parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' | 'when' | 'var' | 'mixin' par = '(' optInd - ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';' - | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';' + ( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';' + | ';' (ifExpr / complexOrSimpleStmt) ^+ ';' | pragmaStmt - | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? ) + | simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? ) | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) optPar ')' literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT From 77ad8b81e414088c3116bf33f96efacd27eeb471 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Wed, 29 Dec 2021 03:26:54 -0300 Subject: [PATCH 3210/4254] fix 19292 (#19293) --- lib/std/private/win_setenv.nim | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim index 067e656a3..91c3f15b0 100644 --- a/lib/std/private/win_setenv.nim +++ b/lib/std/private/win_setenv.nim @@ -23,20 +23,21 @@ check errno_t vs cint when not defined(windows): discard else: + type wchar_t {.importc: "wchar_t".} = int16 + proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {. stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA", sideEffect.} # same as winlean.setEnvironmentVariableA proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} - proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv", header: "".} + proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "".} var errno {.importc, header: "".}: cint - type wchar_t {.importc: "wchar_t".} = int16 var gWenviron {.importc:"_wenviron".}: ptr ptr wchar_t # xxx `ptr UncheckedArray[WideCString]` did not work - proc mbstowcs_s(pReturnValue: ptr csize_t, wcstr: WideCString, sizeInWords: csize_t, mbstr: cstring, count: csize_t): cint {.importc: "mbstowcs_s", header: "".} + proc mbstowcs_s(pReturnValue: ptr csize_t, wcstr: ptr wchar_t, sizeInWords: csize_t, mbstr: cstring, count: csize_t): cint {.importc: "mbstowcs_s", header: "".} # xxx cint vs errno_t? proc setEnvImpl*(name: cstring, value: cstring, overwrite: cint): cint = @@ -77,13 +78,15 @@ else: if gWenviron != nil: # var buf: array[MAX_ENV + 1, WideCString] var buf: array[MAX_ENV + 1, Utf16Char] - let buf2 = cast[WideCString](buf[0].addr) + let buf2 = cast[ptr wchar_t](buf[0].addr) var len: csize_t if mbstowcs_s(len.addr, buf2, buf.len.csize_t, name, MAX_ENV) != 0: errno = EINVAL return -1 - c_wgetenv(buf2)[0] = '\0'.Utf16Char - c_wgetenv(buf2)[1] = '='.Utf16Char + let ptrToEnv = cast[WideCString](c_wgetenv(buf2)) + ptrToEnv[0] = '\0'.Utf16Char + let ptrToEnv2 = cast[WideCString](c_wgetenv(buf2)) + ptrToEnv2[1] = '='.Utf16Char # And now, we have to update the outer environment to have a proper empty value. if setEnvironmentVariableA(name, value) == 0: From a9223d4cdd2e6c23506b666a0958cd2ae3bf5dfd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 29 Dec 2021 12:18:32 +0100 Subject: [PATCH 3211/4254] nep1: make header reflect reality (#19294) --- doc/nep1.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/nep1.rst b/doc/nep1.rst index fc69bab69..8eb31332f 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -1,6 +1,6 @@ -========================================================== -Nim Enhancement Proposal #1 - Standard Library Style Guide -========================================================== +============================ +Standard Library Style Guide +============================ :Author: Clay Sweetser, Dominik Picheta :Version: |nimversion| From 23d64be860958fb7149baed44f6e493394950d69 Mon Sep 17 00:00:00 2001 From: BarrOff <58253563+BarrOff@users.noreply.github.com> Date: Thu, 30 Dec 2021 20:10:36 +0000 Subject: [PATCH 3212/4254] enable `maxDescriptors` on Illumos/Solaris (#19295) --- lib/pure/asyncdispatch.nim | 4 ++-- lib/pure/selectors.nim | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 20ad60427..5e2a8d98e 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1974,11 +1974,11 @@ when defined(posix): import posix when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(zephyr) or defined(freertos): + defined(solaris) or defined(zephyr) or defined(freertos): proc maxDescriptors*(): int {.raises: OSError.} = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is - ## supported on the following OSes: Windows, Linux, OSX, BSD. + ## supported on the following OSes: Windows, Linux, OSX, BSD, Solaris. when defined(windows): result = 16_700_000 elif defined(zephyr) or defined(freertos): diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index ec441f6da..313702370 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -324,11 +324,11 @@ else: doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout) when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(zephyr) or defined(freertos): + defined(solaris) or defined(zephyr) or defined(freertos): template maxDescriptors*(): int = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is - ## supported on the following OSes: Windows, Linux, OSX, BSD. + ## supported on the following OSes: Windows, Linux, OSX, BSD, Solaris. when defined(windows): 16_700_000 elif defined(zephyr) or defined(freertos): From dc5c88ca79e871aefa76c7fefae4282c639a3283 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Thu, 30 Dec 2021 17:52:48 -0300 Subject: [PATCH 3213/4254] Fix #19297 - fixing broken list after adding empty list (#19299) * Update lists.nim * Update tlists.nim * removed check `if b.tail != nil` The tail of the list being null it is still possible to retrieve its end by going through all nodes from the head. So checking for null from `b.tail` is unnecessary. However, setting `a.tail = b.tail` only if `a.head != nil`, so you don't break a good list with an already broken one. --- lib/pure/collections/lists.nim | 11 ++++++----- tests/stdlib/tlists.nim | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 8b255fb60..de5550d6e 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -530,11 +530,12 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = ci assert s == [0, 1, 0, 1, 0, 1] - if a.tail != nil: - a.tail.next = b.head - a.tail = b.tail - if a.head == nil: - a.head = b.head + if b.head != nil: + if a.head == nil: + a.head = b.head + else: + a.tail.next = b.head + a.tail = b.tail if a.addr != b.addr: b.head = nil b.tail = nil diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 54fa8b24f..2f6d5ee6a 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -233,6 +233,18 @@ template main = doAssert l.toSeq == [1] doAssert l.remove(l.head) == true doAssert l.toSeq == [] + + block issue19297: # add (appends a shallow copy) + var a: SinglyLinkedList[int] + var b: SinglyLinkedList[int] + + doAssert a.toSeq == @[] + a.add(1) + doAssert a.toSeq == @[1] + a.add(b) + doAssert a.toSeq == @[1] + a.add(2) + doAssert a.toSeq == @[1, 2] static: main() main() From ac37eed5a28042d50e23d9ae145f2d46b8dc5058 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 31 Dec 2021 09:21:30 +0100 Subject: [PATCH 3214/4254] fixes #16617 [backport] (#19300) --- compiler/typeallowed.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index d00aa538f..78cd74e56 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -57,6 +57,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, of tyVar, tyLent: if kind in {skProc, skFunc, skConst} and (views notin c.features): result = t + elif taIsOpenArray in flags: + result = t elif t.kind == tyLent and ((kind != skResult and views notin c.features) or kind == skParam): # lent can't be used as parameters. result = t From faaf271928acaa19b53c40d9c5b37e6441cb96c1 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sat, 1 Jan 2022 15:33:16 +0300 Subject: [PATCH 3215/4254] Update JS and nimscript import tests (#19306) * add new modules, except experimental ones * remove deprecated modules mersenne and sharedlist * better describe why some modules fail and some modules don't --- tests/js/tstdlib_imports.nim | 43 +++++++++++++++++-------------- tests/test_nimscript.nims | 50 +++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim index 6fe3772d3..9986fa059 100644 --- a/tests/js/tstdlib_imports.nim +++ b/tests/js/tstdlib_imports.nim @@ -7,46 +7,48 @@ discard """ import std/[ # Core: bitops, typetraits, lenientops, macros, volatile, typeinfo, - # fails: endians, rlocks - # works but shouldn't: cpuinfo, locks + # fails due to FFI: rlocks + # fails due to cstring cast/copyMem: endians + # works but uses FFI: cpuinfo, locks # Algorithms: - algorithm, sequtils, + algorithm, enumutils, sequtils, setutils, # Collections: critbits, deques, heapqueue, intsets, lists, options, sets, - sharedlist, tables, - # fails: sharedtables + tables, packedsets, # Strings: cstrutils, editdistance, wordwrap, parseutils, ropes, pegs, punycode, strformat, strmisc, strscans, strtabs, strutils, unicode, unidecode, - # fails: encodings + # fails due to FFI: encodings # Time handling: monotimes, times, # Generic operator system services: os, streams, - # fails: distros, dynlib, marshal, memfiles, osproc, terminal + # fails intentionally: dynlib, marshal, memfiles + # fails due to FFI: osproc, terminal + # fails due to osproc import: distros # Math libraries: - complex, math, mersenne, random, rationals, stats, sums, - # works but shouldn't: fenv + complex, math, random, rationals, stats, sums, sysrand, + # works but uses FFI: fenv # Internet protocols: cookies, httpcore, mimetypes, uri, - # fails: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, + # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, # asyncnet, cgi, httpclient, nativesockets, net, selectors, smtp - # works but shouldn't test: asyncstreams, asyncfutures + # works but no need to test: asyncstreams, asyncfutures # Threading: - # fails: threadpool + # fails due to FFI: threadpool # Parsers: htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - parseopt, + parseopt, jsonutils, # XML processing: xmltree, xmlparser, @@ -56,16 +58,19 @@ import std/[ # Hashing: base64, hashes, - # fails: md5, oids, sha1 + # fails due to cstring cast/zeroMem/copyMem/moveMem: md5 + # fails due to cstring cast/endians import: oids + # fails due to copyMem/endians import: sha1 # Miscellaneous: - colors, logging, sugar, unittest, varints, - # fails: browsers, coro - # works but shouldn't: segfaults + colors, logging, sugar, unittest, varints, enumerate, with, + # fails due to FFI: browsers, coro + # works but uses FFI: segfaults # Modules for JS backend: - asyncjs, dom, jsconsole, jscore, jsffi, + asyncjs, dom, jsconsole, jscore, jsffi, jsbigints, # Unlisted in lib.html: - decls, compilesettings, with, wrapnils + decls, compilesettings, wrapnils, exitprocs, effecttraits, + genasts, importutils, isolation, jsfetch, jsformdata, jsheaders ] diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index ecb409677..761ddafdf 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -8,47 +8,49 @@ from stdtest/specialpaths import buildDir import std/[ # Core: bitops, typetraits, lenientops, macros, volatile, - # fails: typeinfo, endians - # works but shouldn't: cpuinfo, rlocks, locks + # fails due to FFI: typeinfo + # fails due to cstring cast/copyMem: endians + # works but uses FFI: cpuinfo, rlocks, locks # Algorithms: - algorithm, sequtils, + algorithm, enumutils, sequtils, setutils, # Collections: critbits, deques, heapqueue, intsets, lists, options, sets, - sharedlist, tables, - # fails: sharedtables + tables, packedsets, # Strings: editdistance, wordwrap, parseutils, ropes, pegs, punycode, strformat, strmisc, strscans, strtabs, - strutils, unicode, unidecode, - # works but shouldn't: cstrutils, encodings + strutils, unicode, unidecode, cstrutils, + # works but uses FFI: encodings # Time handling: - # fails: monotimes, times + # fails due to FFI: monotimes, times # but times.getTime() implemented for VM # Generic operator system services: - os, streams, - # fails: distros, dynlib, marshal, memfiles, osproc, terminal + os, streams, distros, + # fails due to FFI: memfiles, osproc, terminal + # works but uses FFI: dynlib + # intentionally fails: marshal # Math libraries: - complex, math, mersenne, random, rationals, stats, sums, - # works but shouldn't: fenv + complex, math, random, rationals, stats, sums, + # works but uses FFI: fenv, sysrand # Internet protocols: httpcore, mimetypes, uri, - # fails: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, + # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, # asyncnet, cgi, cookies, httpclient, nativesockets, net, selectors, smtp - # works but shouldn't test: asyncstreams, asyncfutures + # works but no need to test: asyncstreams, asyncfutures # Threading: - # fails: threadpool + # fails due to FFI: threadpool # Parsers: htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - parseopt, + parseopt, jsonutils, # XML processing: xmltree, xmlparser, @@ -58,17 +60,23 @@ import std/[ # Hashing: base64, hashes, - # fails: md5, oids, sha1 + # fails due to cstring cast/zeroMem/copyMem/moveMem: md5 + # fails due to cstring cast/times import/endians import: oids + # fails due to copyMem/endians import: sha1 # Miscellaneous: - colors, sugar, varints, - # fails: browsers, coro, logging (times), segfaults, unittest (uses methods) + colors, sugar, varints, enumerate, with, + # fails due to FFI: browsers, coro, segfaults + # fails due to times import/methods: logging + # fails due to methods: unittest # Modules for JS backend: - # fails: asyncjs, dom, jsconsole, jscore, jsffi, + # fails intentionally: asyncjs, dom, jsconsole, jscore, jsffi, jsbigints, + # jsfetch, jsformdata, jsheaders # Unlisted in lib.html: - decls, compilesettings, with, wrapnils + decls, compilesettings, wrapnils, effecttraits, genasts, + importutils, isolation ] # non-std imports From ef634cc2516ce81a05486f726e423ac458c4467a Mon Sep 17 00:00:00 2001 From: rockcavera Date: Sat, 1 Jan 2022 09:33:29 -0300 Subject: [PATCH 3216/4254] Update manual.rst (#19301) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index d9f5d4ea6..8788e53a3 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5018,7 +5018,7 @@ be used: See also: -- `Shared heap memory management `_. +- `Shared heap memory management `_. From 61d682e733005534a16af72fc9b0c0e74d2f9ebf Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 2 Jan 2022 09:29:55 +0300 Subject: [PATCH 3217/4254] Allow full commands and blocks in type sections (#19181) * allow full commands and blocks in type sections * update grammar * fix changelog [skip ci] * more tests * even more tests --- changelog.md | 3 + compiler/parser.nim | 28 ++- doc/grammar.txt | 5 +- tests/parser/ttypecommandcomma.nim | 9 + tests/parser/ttypecommandindent1.nim | 9 + tests/parser/ttypecommandindent2.nim | 11 + tests/parser/ttypecommandindent3.nim | 11 + tests/parser/ttypesectioncalls.nim | 328 +++++++++++++++++++++++++++ 8 files changed, 393 insertions(+), 11 deletions(-) create mode 100644 tests/parser/ttypecommandcomma.nim create mode 100644 tests/parser/ttypecommandindent1.nim create mode 100644 tests/parser/ttypecommandindent2.nim create mode 100644 tests/parser/ttypecommandindent3.nim create mode 100644 tests/parser/ttypesectioncalls.nim diff --git a/changelog.md b/changelog.md index 52159b865..89aaff664 100644 --- a/changelog.md +++ b/changelog.md @@ -61,6 +61,9 @@ ``` - [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental, meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. +- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed + for the right-hand side of type definitions in type sections. Previously + they would error with "invalid indentation". ## Compiler changes diff --git a/compiler/parser.nim b/compiler/parser.nim index 7bc2c78e0..0fb60440c 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -811,7 +811,7 @@ proc primarySuffix(p: var Parser, r: PNode, #| | DOTLIKEOP optInd symbol generalizedLit? #| | '[' optInd exprColonEqExprList optPar ']' #| | '{' optInd exprColonEqExprList optPar '}' - #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax + #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax result = r # progress guaranteed @@ -821,14 +821,14 @@ proc primarySuffix(p: var Parser, r: PNode, of tkParLe: # progress guaranteed if p.tok.strongSpaceA > 0: - # inside type sections, expressions such as `ref (int, bar)` - # are parsed as a nkCommand with a single tuple argument (nkPar) + result = commandExpr(p, result, mode) + # type sections allow full command syntax if mode == pmTypeDef: - result = newNodeP(nkCommand, p) - result.add r - result.add primary(p, pmNormal) - else: - result = commandExpr(p, result, mode) + var isFirstParam = false + while p.tok.tokType == tkComma: + getTok(p) + optInd(p, result) + result.add(commandParam(p, isFirstParam, mode)) break result = namedParams(p, result, nkCall, tkParRi) if result.len > 1 and result[1].kind == nkExprColonExpr: @@ -869,9 +869,18 @@ proc primarySuffix(p: var Parser, r: PNode, # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet # solution, but pragmas.nim can't handle that result = commandExpr(p, result, mode) + if mode == pmTypeDef: + var isFirstParam = false + while p.tok.tokType == tkComma: + getTok(p) + optInd(p, result) + result.add(commandParam(p, isFirstParam, mode)) break else: break + # type sections allow post-expr blocks + if mode == pmTypeDef: + result = postExprBlocks(p, result) proc parseOperators(p: var Parser, headNode: PNode, limit: int, mode: PrimaryMode): PNode = @@ -1342,7 +1351,8 @@ proc parseTypeDesc(p: var Parser): PNode = result = binaryNot(p, result) proc parseTypeDefAux(p: var Parser): PNode = - #| typeDefAux = simpleExpr ('not' expr)? + #| typeDefAux = simpleExpr ('not' expr + #| | postExprBlocks)? result = simpleExpr(p, pmTypeDef) result = binaryNot(p, result) diff --git a/doc/grammar.txt b/doc/grammar.txt index bf6d381de..1e41b9eeb 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -60,7 +60,7 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' | DOTLIKEOP optInd symbol generalizedLit? | '[' optInd exprColonEqExprList optPar ']' | '{' optInd exprColonEqExprList optPar '}' - | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax + | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}') identVis = symbol OPR? # postfix position identVisDot = symbol '.' optInd symbol OPR? @@ -93,7 +93,8 @@ primary = operatorB primary primarySuffix* | ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary / prefixOperator* identOrLiteral primarySuffix* typeDesc = simpleExpr ('not' expr)? -typeDefAux = simpleExpr ('not' expr)? +typeDefAux = simpleExpr ('not' expr + | postExprBlocks)? postExprBlocks = ':' stmt? ( IND{=} doBlock | IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt diff --git a/tests/parser/ttypecommandcomma.nim b/tests/parser/ttypecommandcomma.nim new file mode 100644 index 000000000..7ca59a799 --- /dev/null +++ b/tests/parser/ttypecommandcomma.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "invalid indentation" + line: 8 + column: 19 +""" + +type + Foo = call(1, 2), 3: + 4 \ No newline at end of file diff --git a/tests/parser/ttypecommandindent1.nim b/tests/parser/ttypecommandindent1.nim new file mode 100644 index 000000000..9aa274e2a --- /dev/null +++ b/tests/parser/ttypecommandindent1.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "invalid indentation" + line: 9 + column: 3 +""" + +type + Foo = call x, y, z: + abc diff --git a/tests/parser/ttypecommandindent2.nim b/tests/parser/ttypecommandindent2.nim new file mode 100644 index 000000000..0883df90f --- /dev/null +++ b/tests/parser/ttypecommandindent2.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "invalid indentation" + line: 10 + column: 5 +""" + +type + Foo = call x, y, z: + abc + do: + def diff --git a/tests/parser/ttypecommandindent3.nim b/tests/parser/ttypecommandindent3.nim new file mode 100644 index 000000000..f9fdcc1e4 --- /dev/null +++ b/tests/parser/ttypecommandindent3.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "expression expected, but found 'keyword do'" + line: 10 + column: 1 +""" + +type + Foo = call x, y, z: + abc +do: + def diff --git a/tests/parser/ttypesectioncalls.nim b/tests/parser/ttypesectioncalls.nim new file mode 100644 index 000000000..003444fc5 --- /dev/null +++ b/tests/parser/ttypesectioncalls.nim @@ -0,0 +1,328 @@ +discard """ +nimout: ''' +StmtList + TypeSection + TypeDef + Ident "A" + Empty + Call + Ident "call" + IntLit 1 + TypeSection + TypeDef + Ident "B" + Empty + Command + Ident "call" + IntLit 2 + TypeDef + Ident "C" + Empty + Call + Ident "call" + StmtList + IntLit 3 + TypeDef + Ident "D" + Empty + Call + Ident "call" + StmtList + IntLit 4 + TypeSection + TypeDef + Ident "E" + Empty + Call + Ident "call" + IntLit 5 + IntLit 6 + TypeDef + Ident "F" + Empty + Command + Ident "call" + IntLit 7 + IntLit 8 + TypeDef + Ident "G" + Empty + Call + Ident "call" + IntLit 9 + StmtList + IntLit 10 + TypeDef + Ident "H" + Empty + Call + Ident "call" + IntLit 11 + StmtList + IntLit 12 + TypeDef + Ident "I" + Empty + Command + Ident "call" + IntLit 13 + StmtList + IntLit 14 + TypeDef + Ident "J" + Empty + Command + Ident "call" + IntLit 15 + StmtList + IntLit 16 + TypeSection + TypeDef + Ident "K" + Empty + Call + Ident "call" + IntLit 17 + IntLit 18 + IntLit 19 + TypeDef + Ident "L" + Empty + Command + Ident "call" + IntLit 20 + IntLit 21 + IntLit 22 + TypeDef + Ident "M" + Empty + Call + Ident "call" + IntLit 23 + IntLit 24 + StmtList + IntLit 25 + TypeDef + Ident "N" + Empty + Command + Ident "call" + IntLit 26 + IntLit 27 + StmtList + IntLit 28 + TypeDef + Ident "O" + Empty + Command + Ident "call" + IntLit 29 + IntLit 30 + StmtList + IntLit 31 + TypeSection + TypeDef + Ident "P" + Empty + Command + Ident "call" + TupleConstr + IntLit 32 + IntLit 33 + Infix + Ident "+" + Infix + Ident "*" + IntLit 34 + IntLit 35 + IntLit 36 + StmtList + IntLit 37 + TypeDef + Ident "R" + Empty + Command + Ident "call" + Infix + Ident "@" + TupleConstr + IntLit 38 + IntLit 39 + Infix + Ident "shl" + IntLit 40 + IntLit 41 + Infix + Ident "-" + Infix + Ident "*" + IntLit 42 + IntLit 43 + IntLit 44 + StmtList + IntLit 45 + TypeDef + Ident "S" + Empty + Command + Ident "call" + IntLit 46 + StmtList + IntLit 47 + StmtList + IntLit 48 + TypeDef + Ident "T" + Empty + Call + Ident "call" + StmtList + IntLit 49 + StmtList + IntLit 50 + StmtList + IntLit 51 +a: IntLit 1 +a: IntLit 2 +a: StmtList + IntLit 3 +a: StmtList + IntLit 4 +a: IntLit 5 +b: IntLit 6 +a: IntLit 7 +b: IntLit 8 +a: IntLit 9 +b: StmtList + IntLit 10 +a: IntLit 11 +b: StmtList + IntLit 12 +a: IntLit 13 +b: StmtList + IntLit 14 +a: IntLit 15 +b: StmtList + IntLit 16 +a: IntLit 17 +b: IntLit 18 +c: IntLit 19 +a: IntLit 20 +b: IntLit 21 +c: IntLit 22 +a: IntLit 23 +b: IntLit 24 +c: StmtList + IntLit 25 +a: IntLit 26 +b: IntLit 27 +c: StmtList + IntLit 28 +a: IntLit 29 +b: IntLit 30 +c: StmtList + IntLit 31 +a: TupleConstr + IntLit 32 + IntLit 33 +b: Infix + Ident "+" + Infix + Ident "*" + IntLit 34 + IntLit 35 + IntLit 36 +c: StmtList + IntLit 37 +a: Infix + Ident "@" + TupleConstr + IntLit 38 + IntLit 39 + Infix + Ident "shl" + IntLit 40 + IntLit 41 +b: Infix + Ident "-" + Infix + Ident "*" + IntLit 42 + IntLit 43 + IntLit 44 +c: StmtList + IntLit 45 +a: IntLit 46 +b: StmtList + IntLit 47 +c: StmtList + IntLit 48 +a: StmtList + IntLit 49 +b: StmtList + IntLit 50 +c: StmtList + IntLit 51 +''' +""" +import macros + +macro call(a): untyped = + echo "a: ", a.treeRepr + result = ident"int" +macro call(a, b): untyped = + echo "a: ", a.treeRepr + echo "b: ", b.treeRepr + result = ident"int" +macro call(a, b, c): untyped = + echo "a: ", a.treeRepr + echo "b: ", b.treeRepr + echo "c: ", c.treeRepr + result = ident"int" + +macro sections(x): untyped = + echo x.treeRepr + result = newStmtList(x) + for ts in x: + for td in ts: + let t = td[0] + result.add quote do: + doAssert `t` is int + +sections: + type A = call(1) + type + B = call 2 + C = call: 3 + D = call(): 4 + type + E = call(5, 6) + F = call 7, 8 + G = call(9): 10 + H = call(11): + 12 + I = call 13: 14 + J = call 15: + 16 + type + K = call(17, 18, 19) + L = call 20, 21, 22 + M = call(23, 24): 25 + N = call 26, 27: 28 + O = call 29, 30: + 31 + type + P = call (32, 33), 34 * 35 + 36: + 37 + R = call (38, 39) @ 40 shl 41, 42 * 43 - 44: + 45 + S = call 46: + 47 + do: + 48 + T = call: + 49 + do: + 50 + do: + 51 From 53e1d57419431050a54dcdf539a2a02bf6d28c5b Mon Sep 17 00:00:00 2001 From: BarrOff <58253563+BarrOff@users.noreply.github.com> Date: Sun, 2 Jan 2022 06:37:13 +0000 Subject: [PATCH 3218/4254] add compile time option for POSIX sigwait on Illumos/Solaris (#19296) * add compile time option for POSIX sigwait on Illumos/Solaris * fix link to documentation of `sigwait` on Illumos/Solaris --- lib/posix/posix.nim | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 57dd6e2c7..912e395a7 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -772,6 +772,13 @@ else: proc sigtimedwait*(a1: var Sigset, a2: var SigInfo, a3: var Timespec): cint {.importc, header: "".} +when defined(sunos) or defined(solaris): + # The following compile time flag is needed on Illumos/Solaris to use the POSIX + # `sigwait` implementation. See the documentation here: + # https://docs.oracle.com/cd/E19455-01/806-5257/6je9h033k/index.html + # https://www.illumos.org/man/2/sigwait + {.passc: "-D_POSIX_PTHREAD_SEMANTICS".} + proc sigwait*(a1: var Sigset, a2: var cint): cint {. importc, header: "".} proc sigwaitinfo*(a1: var Sigset, a2: var SigInfo): cint {. From bbd5086bc319dc22971a06ef24d02dc49ff308f3 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 3 Jan 2022 16:02:58 +0800 Subject: [PATCH 3219/4254] [docs] clarify the raised exception (#19308) * [docs] clarify the raised exception Lest developers wanna know what the exception is. * Apply suggestions from @konsumlamm Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- lib/pure/uri.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index a828298c2..7583dbd1e 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -151,10 +151,10 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add(encodeUrl(val, usePlus)) iterator decodeQuery*(data: string): tuple[key, value: string] = - ## Reads and decodes query string `data` and yields the `(key, value)` pairs - ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, an - ## error is raised when there is an unencoded `=` character in a decoded - ## value, which was the behavior in Nim < 1.5.1 + ## Reads and decodes the query string `data` and yields the `(key, value)` pairs + ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, + ## a `UriParseError` is raised when there is an unencoded `=` character in a decoded + ## value, which was the behavior in Nim < 1.5.1. runnableExamples: import std/sequtils assert toSeq(decodeQuery("foo=1&bar=2=3")) == @[("foo", "1"), ("bar", "2=3")] From e49d52eb6174b2721293968e7811928c303c3776 Mon Sep 17 00:00:00 2001 From: Carlo Capocasa Date: Mon, 3 Jan 2022 09:11:23 +0100 Subject: [PATCH 3220/4254] Add Week-Of-Year Implementation to Times Module (#17223) * initial * more tests * Apply suggestions from code review idiomatize Co-authored-by: Timothee Cour * test iron age dates * add examples * fix typo * consistent param mention * add since pragrams * add changelog * Update lib/pure/times.nim Co-authored-by: Timothee Cour * fix examples * fix negative years * add getWeeksInYear tests * add back fix dropped by rebase * week-year tuple api * add changelog * fix doc tags * add docstrings * fix typos Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: Timothee Cour Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 6 +++ lib/pure/times.nim | 82 +++++++++++++++++++++++++++++++++++ tests/stdlib/ttimes.nim | 95 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) diff --git a/changelog.md b/changelog.md index 89aaff664..1b97fd99a 100644 --- a/changelog.md +++ b/changelog.md @@ -27,6 +27,12 @@ - Sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. +- Added `IsoWeekRange`, a range type to represent the number of weeks in an ISO week-based year. +- Added `IsoYear`, a distinct int type to prevent bugs from confusing the week-based year and the regular year. +- Added `initDateTime` in `times` to create a datetime from a weekday, and ISO 8601 week number and week-based year. +- Added `getIsoWeekAndYear` in `times` to get an ISO week number along with the corresponding ISO week-based year from a datetime. +- Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. + ## Language changes - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 113f73d2a..7851bf158 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -288,6 +288,13 @@ type YeardayRange* = range[0..365] NanosecondRange* = range[0..999_999_999] + IsoWeekRange* = range[1 .. 53] + ## An ISO 8601 calendar week number. + IsoYear* = distinct int + ## An ISO 8601 calendar year number. + ## + ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. + Time* = object ## Represents a point in time. seconds: int64 nanosecond: NanosecondRange @@ -529,6 +536,54 @@ proc getDaysInYear*(year: int): int = doAssert getDaysInYear(2001) == 365 result = 365 + (if isLeapYear(year): 1 else: 0) +proc `==`*(a, b: IsoYear): bool {.borrow.} +proc `$`*(p: IsoYear): string {.borrow.} + +proc getWeeksInIsoYear*(y: IsoYear): IsoWeekRange {.since: (1, 5).} = + ## Returns the number of weeks in the specified ISO 8601 week-based year, which can be + ## either 53 or 52. + runnableExamples: + assert getWeeksInIsoYear(IsoYear(2000)) == 52 + assert getWeeksInIsoYear(IsoYear(2001)) == 53 + + var y = int(y) + + # support negative years + y = if y < 0: 400 + y mod 400 else: y + + # source: https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm + let p = (y + (y div 4) - (y div 100) + (y div 400)) mod 7 + let y1 = y - 1 + let p1 = (y1 + (y1 div 4) - (y1 div 100) + (y1 div 400)) mod 7 + if p == 4 or p1 == 3: 53 else: 52 + +proc getIsoWeekAndYear*(dt: DateTime): + tuple[isoweek: IsoWeekRange, isoyear: IsoYear] {.since: (1, 5).} = + ## Returns the ISO 8601 week and year. + ## + ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. + runnableExamples: + assert getIsoWeekAndYear(initDateTime(21, mApr, 2018, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2018.IsoYear) + block: + let (w, y) = getIsoWeekAndYear(initDateTime(30, mDec, 2019, 00, 00, 00)) + assert w == 01.IsoWeekRange + assert y == 2020.IsoYear + assert getIsoWeekAndYear(initDateTime(13, mSep, 2020, 00, 00, 00)) == (isoweek: 37.IsoWeekRange, isoyear: 2020.IsoYear) + block: + let (w, y) = getIsoWeekAndYear(initDateTime(2, mJan, 2021, 00, 00, 00)) + assert w.int > 52 + assert w.int < 54 + assert y.int mod 100 == 20 + + # source: https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm + var w = (dt.yearday.int - dt.weekday.int + 10) div 7 + if w < 1: + (isoweek: getWeeksInIsoYear(IsoYear(dt.year - 1)), isoyear: IsoYear(dt.year - 1)) + elif (w > getWeeksInIsoYear(IsoYear(dt.year))): + (isoweek: IsoWeekRange(1), isoyear: IsoYear(dt.year + 1)) + else: + (isoweek: IsoWeekRange(w), isoyear: IsoYear(dt.year)) + proc stringifyUnit(value: int | int64, unit: TimeUnit): string = ## Stringify time unit with it's name, lowercased let strUnit = $unit @@ -2578,6 +2633,33 @@ proc `+=`*(t: var Time, b: TimeInterval) = proc `-=`*(t: var Time, b: TimeInterval) = t = t - b +# +# Day of year +# + +proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, + hour: HourRange, minute: MinuteRange, second: SecondRange, + nanosecond: NanosecondRange, + zone: Timezone = local()): DateTime {.since: (1, 5).} = + ## Create a new `DateTime <#DateTime>`_ from a weekday and an ISO 8601 week number and year + ## in the specified timezone. + ## + ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. + runnableExamples: + assert initDateTime(21, mApr, 2018, 00, 00, 00) == initDateTime(dSat, 16, 2018.IsoYear, 00, 00, 00) + assert initDateTime(30, mDec, 2019, 00, 00, 00) == initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) + assert initDateTime(13, mSep, 2020, 00, 00, 00) == initDateTime(dSun, 37, 2020.IsoYear, 00, 00, 00) + assert initDateTime(2, mJan, 2021, 00, 00, 00) == initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) + + # source https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm + let d = isoweek * 7 + weekday.int - initDateTime(4, mJan, isoyear.int, 00, 00, 00).weekday.int - 4 + initDateTime(1, mJan, isoyear.int, hour, minute, second, nanosecond, zone) + initTimeInterval(days=d) + +proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, + hour: HourRange, minute: MinuteRange, second: SecondRange, + zone: Timezone = local()): DateTime {.since: (1, 5).} = + initDateTime(weekday, isoweek, isoyear, hour, minute, second, 0, zone) + # # Other # diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 66157b91c..2cf945786 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -646,3 +646,98 @@ block: # ttimes doAssert initDuration(milliseconds = 500).inMilliseconds == 500 doAssert initDuration(milliseconds = -500).inMilliseconds == -500 doAssert initDuration(nanoseconds = -999999999).inMilliseconds == -999 + + block: # getIsoWeekAndYear + doAssert getIsoWeekAndYear(initDateTime(04, mNov, 2019, 00, 00, 00)) == (isoweek: 45.IsoWeekRange, isoyear: 2019.IsoYear) + doAssert initDateTime(dMon, 45, 2019.IsoYear, 00, 00, 00) == initDateTime(04, mNov, 2019, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(28, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear) + doAssert initDateTime(dSat, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(28, mDec, 2019, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(29, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear) + doAssert initDateTime(dSun, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(29, mDec, 2019, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(30, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(30, mDec, 2019, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dTue, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2019, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dWed, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dThu, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(05, mApr, 2020, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dSun, 14, 2020.IsoYear, 00, 00, 00) == initDateTime(05, mApr, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(06, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dMon, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(06, mApr, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(10, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dFri, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(10, mApr, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(12, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dSun, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(12, mApr, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(13, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dMon, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(13, mApr, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(15, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dThu, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(16, mApr, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(17, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dFri, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(17, mJul, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(19, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dSun, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(19, mJul, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(20, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dMon, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(20, mJul, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(23, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dThu, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(23, mJul, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2020, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dThu, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2020, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dFri, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2021, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2021, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(03, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear) + doAssert initDateTime(dSun, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(03, mJan, 2021, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(04, mJan, 2021, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2021.IsoYear) + doAssert initDateTime(dMon, 01, 2021.IsoYear, 00, 00, 00) == initDateTime(04, mJan, 2021, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 00, 00, 00)) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear) + doAssert initDateTime(dMon, 05, 2021.IsoYear, 00, 00, 00) == initDateTime(01, mFeb, 2021, 00, 00, 00) + + doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1))) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear) + doAssert initDateTime(dMon, 05, 2021.IsoYear, 01, 02, 03, 400_000_000, staticTz(hours=1)) == initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1)) + + doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0001.IsoYear) + doAssert initDateTime(dSun, 13, 0001.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0001, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0000, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0000.IsoYear) + doAssert initDateTime(dSat, 13, 0000.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0000, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: (-0001).IsoYear) + doAssert initDateTime(dThu, 13, (-0001).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0001, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0002, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0002).IsoYear) + doAssert initDateTime(dWed, 14, (-0002).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0002, 00, 00, 00) + doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0753, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0753).IsoYear) + doAssert initDateTime(dMon, 14, (-0753).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0753, 00, 00, 00) + + block: # getWeeksInIsoYear + doAssert getWeeksInIsoYear((-0014).IsoYear) == 52 + doAssert getWeeksInIsoYear((-0013).IsoYear) == 53 + doAssert getWeeksInIsoYear((-0012).IsoYear) == 52 + + doAssert getWeeksInIsoYear((-0009).IsoYear) == 52 + doAssert getWeeksInIsoYear((-0008).IsoYear) == 53 + doAssert getWeeksInIsoYear((-0007).IsoYear) == 52 + + doAssert getWeeksInIsoYear((-0003).IsoYear) == 52 + doAssert getWeeksInIsoYear((-0002).IsoYear) == 53 + doAssert getWeeksInIsoYear((-0001).IsoYear) == 52 + + doAssert getWeeksInIsoYear(0003.IsoYear) == 52 + doAssert getWeeksInIsoYear(0004.IsoYear) == 53 + doAssert getWeeksInIsoYear(0005.IsoYear) == 52 + + doAssert getWeeksInIsoYear(1653.IsoYear) == 52 + doAssert getWeeksInIsoYear(1654.IsoYear) == 53 + doAssert getWeeksInIsoYear(1655.IsoYear) == 52 + + doAssert getWeeksInIsoYear(1997.IsoYear) == 52 + doAssert getWeeksInIsoYear(1998.IsoYear) == 53 + doAssert getWeeksInIsoYear(1999.IsoYear) == 52 + + doAssert getWeeksInIsoYear(2008.IsoYear) == 52 + doAssert getWeeksInIsoYear(2009.IsoYear) == 53 + doAssert getWeeksInIsoYear(2010.IsoYear) == 52 + + doAssert getWeeksInIsoYear(2014.IsoYear) == 52 + doAssert getWeeksInIsoYear(2015.IsoYear) == 53 + doAssert getWeeksInIsoYear(2016.IsoYear) == 52 From bd4f76a2e3b9282548e62ba3b620b09d6c564373 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Mon, 3 Jan 2022 17:30:26 +0800 Subject: [PATCH 3221/4254] docs: Fix typo in tut1.rst (#19309) --- doc/tut1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 2856625b7..d8e0ec8e4 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -913,7 +913,7 @@ Let's return to the simple counting example: echo i Can a `countup `_ proc be written that -supports this loop? Lets try: +supports this loop? Let's try: .. code-block:: nim proc countup(a, b: int): int = From 19bcb43a0e21dd222ffd3fad8c5fb2d8e85d59ea Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 3 Jan 2022 20:40:43 +0800 Subject: [PATCH 3222/4254] enable multiple packages (arraymancer, fidget ...) (#19311) The cause of arraymancer failure has been tracked here: https://github.com/mratsim/Arraymancer/issues/505 And it was fixed by https://github.com/mratsim/Arraymancer/pull/542 --- testament/important_packages.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 7e15e7c65..381aa27ac 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -35,7 +35,7 @@ proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true, allowFailu pkg "alea", allowFailure = true pkg "argparse" -pkg "arraymancer", "nim c tests/tests_cpu.nim", allowFailure = true +pkg "arraymancer", "nim c tests/tests_cpu.nim" pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim", allowFailure = true pkg "asyncthreadpool" pkg "awk" @@ -63,7 +63,7 @@ pkg "delaunay" pkg "docopt" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" -pkg "fidget", allowFailure = true +pkg "fidget" pkg "fragments", "nim c -r fragments/dsl.nim" pkg "fusion" pkg "gara" @@ -91,7 +91,7 @@ pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" pkg "neo", "nim c -d:blas=openblas tests/all.nim" -pkg "nesm", "nimble tests", allowFailure = true # notice plural 'tests' +pkg "nesm", "nimble tests" # notice plural 'tests' pkg "netty" pkg "nico", allowFailure = true pkg "nicy", "nim c -r src/nicy.nim" From 526a32e1697489b73e54c1b984ba5413842f1252 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Mon, 3 Jan 2022 16:14:08 -0300 Subject: [PATCH 3223/4254] Fix #19314 - fixing broken `DoublyLinkedList` after adding empty `DoublyLinkedList` (#19315) [backport] * Update lists.nim * Update tlists.nim --- lib/pure/collections/lists.nim | 12 ++++++------ tests/stdlib/tlists.nim | 12 ++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index de5550d6e..f7627ae67 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -675,12 +675,12 @@ proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = assert s == [0, 1, 0, 1, 0, 1] if b.head != nil: - b.head.prev = a.tail - if a.tail != nil: - a.tail.next = b.head - a.tail = b.tail - if a.head == nil: - a.head = b.head + if a.head == nil: + a.head = b.head + else: + b.head.prev = a.tail + a.tail.next = b.head + a.tail = b.tail if a.addr != b.addr: b.head = nil b.tail = nil diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 2f6d5ee6a..14cbf2f9d 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -245,6 +245,18 @@ template main = doAssert a.toSeq == @[1] a.add(2) doAssert a.toSeq == @[1, 2] + + block issue19314: # add (appends a shallow copy) + var a: DoublyLinkedList[int] + var b: DoublyLinkedList[int] + + doAssert a.toSeq == @[] + a.add(1) + doAssert a.toSeq == @[1] + a.add(b) + doAssert a.toSeq == @[1] + a.add(2) + doAssert a.toSeq == @[1, 2] static: main() main() From fcf1df6e56934b1b5021a0898b9152b86e0cb5f7 Mon Sep 17 00:00:00 2001 From: Smarcy Date: Mon, 3 Jan 2022 21:04:15 +0100 Subject: [PATCH 3224/4254] fixed typos (#19316) --- nimpretty/nimpretty.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index a7940349d..e3b4c9a3a 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -69,8 +69,8 @@ proc main = var backup = false # when `on`, create a backup file of input in case - # `prettyPrint` could over-write it (note that the backup may happen even - # if input is not actually over-written, when nimpretty is a noop). + # `prettyPrint` could overwrite it (note that the backup may happen even + # if input is not actually overwritten, when nimpretty is a noop). # --backup was un-documented (rely on git instead). var opt = PrettyOptions(indWidth: 0, maxLineLen: 80) From 35cae73aa5c39b950386febfa5182bab920ddfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Tue, 4 Jan 2022 07:56:10 +0100 Subject: [PATCH 3225/4254] devel: style fix (#19318) this allows "--styleCheck:usages --styleCheck:error" --- lib/pure/nativesockets.nim | 2 +- lib/pure/net.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 4037d7181..eb0514a8f 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -810,7 +810,7 @@ proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (Socke ## child processes. ## ## Returns (osInvalidSocket, "") if an error occurred. - var sockAddress: Sockaddr + var sockAddress: SockAddr var addrLen = sizeof(sockAddress).SockLen var sock = when (defined(linux) or defined(bsd)) and not defined(nimdoc): diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ced6b2fb2..8dc92e9d6 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1778,7 +1778,7 @@ proc sendTo*(socket: Socket, address: IpAddress, port: Port, assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") var sa: Sockaddr_storage - var sl: Socklen + var sl: SockLen toSockAddr(address, port, sa, sl) result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint, cast[ptr SockAddr](addr sa), sl) From 39a27783fc0d43e9828bb031cc811042226407b9 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Tue, 4 Jan 2022 17:42:21 +0800 Subject: [PATCH 3226/4254] docs: Fix typo in tut1.rst (#19324) --- doc/tut1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index d8e0ec8e4..3107aef45 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1052,7 +1052,7 @@ errors. Lossless `Automatic type conversion`:idx: is performed in expressions where different kinds of integer types are used. However, if the type conversion -would cause loss of information, the ``RangeDefect``:idx: is raised (if the error +would cause loss of information, the `RangeDefect`:idx: is raised (if the error cannot be detected at compile time). From 0bcd7062c6e7a4131d166dacea41d661b7a09748 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 4 Jan 2022 18:10:46 +0800 Subject: [PATCH 3227/4254] correct the comments (#19322) --expandArc ``` var a b a = matrix(5, 5, 1.0) b = matrix(5, 5, 2.0) `=sink`(b, - let blitTmp = b wasMoved(b) blitTmp + a) `=destroy`(b) `=destroy`(a) ``` --- compiler/optimizer.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 744c82ab5..f484fdbf5 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -127,11 +127,11 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) = for i in 0 ..< n.len: analyse(c, b, n[i]) else: - #[ Test tmatrix.test3: + #[ Test destructor/tmatrix.test3: Prevent this from being elided. We should probably find a better solution... - `=sink`(b, - ( + `=sink`(b, - let blitTmp = b; wasMoved(b); blitTmp + a) From 1869826668e2e3a0fd69cc1b69fb12b07993e417 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 4 Jan 2022 18:49:54 +0800 Subject: [PATCH 3228/4254] add std/private/win_getsysteminfo; refactor the usage of `GetSystemInfo` (#19310) * add std/private/win_getsysteminfo * import at the top level * wrappers follow nep1 too * follow review comment --- lib/pure/concurrency/cpuinfo.nim | 24 ++++++------------------ lib/pure/reservedmem.nim | 19 ++----------------- lib/std/private/win_getsysteminfo.nim | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 35 deletions(-) create mode 100644 lib/std/private/win_getsysteminfo.nim diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index ee43b8e11..16d32002d 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -18,6 +18,9 @@ include "system/inclrtl" when defined(posix) and not (defined(macosx) or defined(bsd)): import posix +when defined(windows): + import std/private/win_getsysteminfo + when defined(freebsd) or defined(macosx): {.emit: "#include ".} @@ -54,25 +57,10 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = ## Returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. when defined(windows): - type - SYSTEM_INFO {.final, pure.} = object - u1: int32 - dwPageSize: int32 - lpMinimumApplicationAddress: pointer - lpMaximumApplicationAddress: pointer - dwActiveProcessorMask: ptr int32 - dwNumberOfProcessors: int32 - dwProcessorType: int32 - dwAllocationGranularity: int32 - wProcessorLevel: int16 - wProcessorRevision: int16 - - proc GetSystemInfo(lpSystemInfo: var SYSTEM_INFO) {.stdcall, dynlib: "kernel32", importc: "GetSystemInfo".} - var - si: SYSTEM_INFO - GetSystemInfo(si) - result = si.dwNumberOfProcessors + si: SystemInfo + getSystemInfo(addr si) + result = int(si.dwNumberOfProcessors) elif defined(macosx) or defined(bsd): var mib: array[0..3, cint] diff --git a/lib/pure/reservedmem.nim b/lib/pure/reservedmem.nim index 232a2b383..99fbe1429 100644 --- a/lib/pure/reservedmem.nim +++ b/lib/pure/reservedmem.nim @@ -42,25 +42,10 @@ type when defined(windows): import winlean - - type - SYSTEM_INFO {.final, pure.} = object - u1: uint32 - dwPageSize: uint32 - lpMinimumApplicationAddress: pointer - lpMaximumApplicationAddress: pointer - dwActiveProcessorMask: ptr uint32 - dwNumberOfProcessors: uint32 - dwProcessorType: uint32 - dwAllocationGranularity: uint32 - wProcessorLevel: uint16 - wProcessorRevision: uint16 - - proc getSystemInfo(lpSystemInfo: ptr SYSTEM_INFO) {.stdcall, - dynlib: "kernel32", importc: "GetSystemInfo".} + import std/private/win_getsysteminfo proc getAllocationGranularity: uint = - var sysInfo: SYSTEM_INFO + var sysInfo: SystemInfo getSystemInfo(addr sysInfo) return uint(sysInfo.dwAllocationGranularity) diff --git a/lib/std/private/win_getsysteminfo.nim b/lib/std/private/win_getsysteminfo.nim new file mode 100644 index 000000000..b98478231 --- /dev/null +++ b/lib/std/private/win_getsysteminfo.nim @@ -0,0 +1,15 @@ +type + SystemInfo* = object + u1: uint32 + dwPageSize: uint32 + lpMinimumApplicationAddress: pointer + lpMaximumApplicationAddress: pointer + dwActiveProcessorMask: ptr uint32 + dwNumberOfProcessors*: uint32 + dwProcessorType: uint32 + dwAllocationGranularity*: uint32 + wProcessorLevel: uint16 + wProcessorRevision: uint16 + +proc getSystemInfo*(lpSystemInfo: ptr SystemInfo) {.stdcall, + dynlib: "kernel32", importc: "GetSystemInfo".} From 9df195ef581879cf9e5c3c3154755bd1dba677c6 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 4 Jan 2022 20:29:50 +0800 Subject: [PATCH 3229/4254] style usages part one (openarray => openArray) (#19321) * style usages (openArray) * revert doc changes --- tests/arc/tmovebug.nim | 4 ++-- tests/arc/tmovebugcopy.nim | 4 ++-- tests/array/tarray.nim | 2 +- tests/async/tioselectors.nim | 4 ++-- tests/closure/tclosure.nim | 4 ++-- tests/compiles/trecursive_generic_in_compiles.nim | 2 +- tests/concepts/tconcepts_issues.nim | 8 ++++---- tests/converter/tconverter_with_varargs.nim | 2 +- tests/cpp/tcovariancerules.nim | 8 ++++---- tests/destructor/tmove_objconstr.nim | 2 +- tests/errmsgs/t17460.nim | 2 +- tests/errmsgs/tproper_stacktrace.nim | 2 +- tests/errmsgs/tsigmatch.nim | 4 ++-- tests/generics/tgenerics_issues.nim | 2 +- tests/generics/tgenerics_various.nim | 4 ++-- tests/iter/titer13.nim | 2 +- tests/iter/titer_issues.nim | 4 ++-- tests/iter/tmoditer.nim | 2 +- tests/iter/tpermutations.nim | 2 +- tests/js/t9410.nim | 4 ++-- tests/js/tbasics.nim | 2 +- tests/js/tbyvar.nim | 4 ++-- tests/lent/tbasic_lent_check.nim | 2 +- tests/magics/tmagics.nim | 2 +- tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim | 2 +- .../named_argument_bug/tri_engine/gfx/gl/primitive.nim | 2 +- tests/misc/t9039.nim | 2 +- tests/misc/theaproots.nim | 2 +- tests/misc/tsimplesort.nim | 2 +- tests/openarray/topena1.nim | 2 +- tests/openarray/topenarrayrepr.nim | 4 ++-- tests/openarray/topenlen.nim | 2 +- tests/openarray/tptrarrayderef.nim | 6 +++--- tests/overload/toverload_various.nim | 4 ++-- tests/showoff/tdrdobbs_examples.nim | 4 ++-- tests/stdlib/tdochelpers.nim | 4 ++-- tests/stdlib/tparseipv6.nim | 4 ++-- tests/stdlib/trepr.nim | 2 +- tests/system/tostring.nim | 2 +- tests/system/tsystem_misc.nim | 4 ++-- tests/template/otests.nim | 4 ++-- tests/template/sunset.nimf | 2 +- tests/template/template_issues.nim | 2 +- tests/tuples/tuple_with_nil.nim | 4 ++-- tests/typerel/tcommontype.nim | 2 +- tests/typerel/texplicitcmp.nim | 2 +- tests/typerel/tstr_as_openarray.nim | 6 +++--- tests/views/tviews1.nim | 2 +- tests/vm/tyaytypedesc.nim | 2 +- 49 files changed, 76 insertions(+), 76 deletions(-) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 7977d330a..002bd6796 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -292,7 +292,7 @@ when false: # bug #13456 -iterator combinations[T](s: openarray[T], k: int): seq[T] = +iterator combinations[T](s: openArray[T], k: int): seq[T] = let n = len(s) assert k >= 0 and k <= n var pos = newSeq[int](k) @@ -455,7 +455,7 @@ initFoo7(2) # bug #14902 -iterator zip[T](s: openarray[T]): (T, T) = +iterator zip[T](s: openArray[T]): (T, T) = var i = 0 while i < 10: yield (s[i mod 2], s[i mod 2 + 1]) diff --git a/tests/arc/tmovebugcopy.nim b/tests/arc/tmovebugcopy.nim index 7c5228147..ec4315777 100644 --- a/tests/arc/tmovebugcopy.nim +++ b/tests/arc/tmovebugcopy.nim @@ -253,7 +253,7 @@ when false: # bug #13456 -iterator combinations[T](s: openarray[T], k: int): seq[T] = +iterator combinations[T](s: openArray[T], k: int): seq[T] = let n = len(s) assert k >= 0 and k <= n var pos = newSeq[int](k) @@ -416,7 +416,7 @@ initFoo7(2) # bug #14902 -iterator zip[T](s: openarray[T]): (T, T) = +iterator zip[T](s: openArray[T]): (T, T) = var i = 0 while i < 10: yield (s[i mod 2], s[i mod 2 + 1]) diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index d10011ef2..e9f330e3b 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -44,7 +44,7 @@ block tarray: arr: TMyarray - proc sum(a: openarray[int]): int = + proc sum(a: openArray[int]): int = result = 0 var i = 0 while i < len(a): diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index f7487525a..fdb8d9597 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -288,8 +288,8 @@ when not defined(windows): events: set[Event] proc vnode_test(): bool = - proc validate(test: openarray[ReadyKey], - check: openarray[valType]): bool = + proc validate(test: openArray[ReadyKey], + check: openArray[valType]): bool = result = false if len(test) == len(check): for checkItem in check: diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim index 546d7026d..8ae6c44bb 100644 --- a/tests/closure/tclosure.nim +++ b/tests/closure/tclosure.nim @@ -38,10 +38,10 @@ joinable: false block tclosure: - proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) = + proc map(n: var openArray[int], fn: proc (x: int): int {.closure}) = for i in 0..n.len-1: n[i] = fn(n[i]) - proc each(n: openarray[int], fn: proc(x: int) {.closure.}) = + proc each(n: openArray[int], fn: proc(x: int) {.closure.}) = for i in 0..n.len-1: fn(n[i]) diff --git a/tests/compiles/trecursive_generic_in_compiles.nim b/tests/compiles/trecursive_generic_in_compiles.nim index 88d3faeed..ab31ad0f5 100644 --- a/tests/compiles/trecursive_generic_in_compiles.nim +++ b/tests/compiles/trecursive_generic_in_compiles.nim @@ -50,7 +50,7 @@ proc `==`*[T](xs, ys: List[T]): bool = proc asList*[T](xs: varargs[T]): List[T] = ## Creates list from varargs - proc initListImpl(i: int, xs: openarray[T]): List[T] = + proc initListImpl(i: int, xs: openArray[T]): List[T] = if i > high(xs): Nil[T]() else: diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index c76049bdd..1a0dd8063 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -324,15 +324,15 @@ block t6691: block t6782: type Reader = concept c - c.read(openarray[byte], int, int) is int + c.read(openArray[byte], int, int) is int Rdr = concept c - c.rd(openarray[byte], int, int) is int + c.rd(openArray[byte], int, int) is int type TestFile = object - proc read(r: TestFile, dest: openarray[byte], offset: int, limit: int): int = + proc read(r: TestFile, dest: openArray[byte], offset: int, limit: int): int = result = 0 - proc rd(r: TestFile, dest: openarray[byte], offset: int, limit: int): int = + proc rd(r: TestFile, dest: openArray[byte], offset: int, limit: int): int = result = 0 doAssert TestFile is Reader diff --git a/tests/converter/tconverter_with_varargs.nim b/tests/converter/tconverter_with_varargs.nim index 6d7e31e85..fae83221b 100644 --- a/tests/converter/tconverter_with_varargs.nim +++ b/tests/converter/tconverter_with_varargs.nim @@ -8,7 +8,7 @@ type converter to_py*(i: int) : PPyRef = nil when false: - proc to_tuple*(vals: openarray[PPyRef]): PPyRef = + proc to_tuple*(vals: openArray[PPyRef]): PPyRef = discard proc abc(args: varargs[PPyRef]) = diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim index 5ac7d8bac..9d49f2cbd 100644 --- a/tests/cpp/tcovariancerules.nim +++ b/tests/cpp/tcovariancerules.nim @@ -79,16 +79,16 @@ proc wantsCovariantSeq2(s: seq[AnimalRef]) = proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) = for a in s: echo a.x -proc wantsCovariantOpenArray(s: openarray[ref Animal]) = +proc wantsCovariantOpenArray(s: openArray[ref Animal]) = for a in s: echo a.x -proc modifiesCovariantOpenArray(s: var openarray[ref Animal]) = +proc modifiesCovariantOpenArray(s: var openArray[ref Animal]) = for a in s: echo a.x -proc modifiesDerivedOpenArray(s: var openarray[ref Dog]) = +proc modifiesDerivedOpenArray(s: var openArray[ref Dog]) = for a in s: echo a.x -proc wantsNonCovariantOpenArray(s: openarray[Animal]) = +proc wantsNonCovariantOpenArray(s: openArray[Animal]) = for a in s: echo a.x proc wantsCovariantArray(s: array[2, ref Animal]) = diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 5faaabb8b..9eee4bfdb 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -178,7 +178,7 @@ proc myfuncLoop(x: int): MySeqNonCopyable = discard myfuncLoop(3) #------------------------------------------------------------ -# Move into table via openarray +# Move into table via openArray #------------------------------------------------------------ type diff --git a/tests/errmsgs/t17460.nim b/tests/errmsgs/t17460.nim index 8192cc4c8..e377bc48a 100644 --- a/tests/errmsgs/t17460.nim +++ b/tests/errmsgs/t17460.nim @@ -3,7 +3,7 @@ discard """ errormsg: "wrong number of variables" """ -iterator xclusters*[T](a: openarray[T]; s: static[int]): array[s, T] {.inline.} = +iterator xclusters*[T](a: openArray[T]; s: static[int]): array[s, T] {.inline.} = var result: array[s, T] # iterators have no default result variable var i = 0 while i < len(a): diff --git a/tests/errmsgs/tproper_stacktrace.nim b/tests/errmsgs/tproper_stacktrace.nim index c7dfbaf2a..8617984fb 100644 --- a/tests/errmsgs/tproper_stacktrace.nim +++ b/tests/errmsgs/tproper_stacktrace.nim @@ -6,7 +6,7 @@ import strscans, strutils proc raiseTestException*() = raise newException(Exception, "test") -proc matchStackTrace(actualEntries: openarray[StackTraceEntry], expected: string) = +proc matchStackTrace(actualEntries: openArray[StackTraceEntry], expected: string) = var expectedEntries = newSeq[StackTraceEntry]() var i = 0 diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim index 023b7d518..8f32ef9e6 100644 --- a/tests/errmsgs/tsigmatch.nim +++ b/tests/errmsgs/tsigmatch.nim @@ -132,12 +132,12 @@ block: echo foo(fun) block: - # bug #10285 Function signature don't match when inside seq/array/openarray + # bug #10285 Function signature don't match when inside seq/array/openArray # Note: the error message now shows `closure` which helps debugging the issue # out why it doesn't match proc takesFunc(f: proc (x: int) {.gcsafe, locks: 0.}) = echo "takes single Func" - proc takesFuncs(fs: openarray[proc (x: int) {.gcsafe, locks: 0.}]) = + proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe, locks: 0.}]) = echo "takes multiple Func" takesFunc(proc (x: int) {.gcsafe, locks: 0.} = echo x) # works takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo x]) # fails diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 9e70efcd2..092926c01 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -603,7 +603,7 @@ block t7854: block t5864: - proc defaultStatic(s: openarray, N: static[int] = 1): int = N + proc defaultStatic(s: openArray, N: static[int] = 1): int = N proc defaultGeneric[T](a: T = 2): int = a let a = [1, 2, 3, 4].defaultStatic() diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim index 285108cd3..6c76502e1 100644 --- a/tests/generics/tgenerics_various.nim +++ b/tests/generics/tgenerics_various.nim @@ -230,8 +230,8 @@ block tvarargs_vs_generics: echo "direct" proc withDirectType[T](arg: T) = echo "generic" - proc withOpenArray(args: openarray[string]) = - echo "openarray" + proc withOpenArray(args: openArray[string]) = + echo "openArray" proc withOpenArray[T](arg: T) = echo "generic" proc withVarargs(args: varargs[string]) = diff --git a/tests/iter/titer13.nim b/tests/iter/titer13.nim index 0d4a399c5..086c40ca4 100644 --- a/tests/iter/titer13.nim +++ b/tests/iter/titer13.nim @@ -72,7 +72,7 @@ block: echo a block t5859: - proc flatIterator[T](s: openarray[T]): auto {.noSideEffect.}= + proc flatIterator[T](s: openArray[T]): auto {.noSideEffect.}= result = iterator(): auto = when (T is not seq|array): for item in s: diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index 4a76b2fb0..65f66ad26 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -135,7 +135,7 @@ block t3837_chained: block t3221_complex: - iterator permutations[T](ys: openarray[T]): seq[T] = + iterator permutations[T](ys: openArray[T]): seq[T] = var d = 1 c = newSeq[int](ys.len) @@ -228,7 +228,7 @@ block t2023_objiter: block: # bug #13739 - iterator myIter(arg: openarray[int]): int = + iterator myIter(arg: openArray[int]): int = var tmp = 0 let len = arg.len while tmp < len: diff --git a/tests/iter/tmoditer.nim b/tests/iter/tmoditer.nim index b92a416fb..99e5b642d 100644 --- a/tests/iter/tmoditer.nim +++ b/tests/iter/tmoditer.nim @@ -43,7 +43,7 @@ proc `=copy`(dst: var NonCopyable, src: NonCopyable) {.error.} proc `=sink`(dst: var NonCopyable, src: NonCopyable) = dst.x = src.x -iterator lentItems[T](a: openarray[T]): lent T = +iterator lentItems[T](a: openArray[T]): lent T = for i in 0..a.high: yield a[i] diff --git a/tests/iter/tpermutations.nim b/tests/iter/tpermutations.nim index c5067ba31..30a66460f 100644 --- a/tests/iter/tpermutations.nim +++ b/tests/iter/tpermutations.nim @@ -12,7 +12,7 @@ perm: 6778800.0 det: 0.0 import sequtils, sugar -iterator permutations*[T](ys: openarray[T]): tuple[perm: seq[T], sign: int] = +iterator permutations*[T](ys: openArray[T]): tuple[perm: seq[T], sign: int] = var d = 1 c = newSeq[int](ys.len) diff --git a/tests/js/t9410.nim b/tests/js/t9410.nim index 78c329a24..042520dc5 100644 --- a/tests/js/t9410.nim +++ b/tests/js/t9410.nim @@ -447,10 +447,10 @@ template tests = doAssert seqOfSeqs == @[@[10, 2], @[30, 4]] when false: - block: # openarray + block: # openArray # Error: internal error: genAddr: nkStmtListExpr var calls = 0 - proc getvarint(x: var openarray[int]): var int = + proc getvarint(x: var openArray[int]): var int = calls += 1 if true: x[1] diff --git a/tests/js/tbasics.nim b/tests/js/tbasics.nim index b297bb037..ef84f8bb5 100644 --- a/tests/js/tbasics.nim +++ b/tests/js/tbasics.nim @@ -54,7 +54,7 @@ for x in someGlobal: doAssert(x == 0) proc tdefault = var x = default(int) doAssert(x == 0) - proc inner(v: openarray[string]) = + proc inner(v: openArray[string]) = doAssert(v.len == 0) inner(default(seq[string])) diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim index a4c60b0b3..93724a2f1 100644 --- a/tests/js/tbyvar.nim +++ b/tests/js/tbyvar.nim @@ -39,9 +39,9 @@ proc main = main() -# Test: pass var seq to var openarray +# Test: pass var seq to var openArray var s = @[2, 1] -proc foo(a: var openarray[int]) = a[0] = 123 +proc foo(a: var openArray[int]) = a[0] = 123 proc bar(s: var seq[int], a: int) = doAssert(a == 5) diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index 049fa276a..e33da06f8 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -39,7 +39,7 @@ template main2 = # bug #15958 p[] = 20.0 doAssert byLent(p)[] == 20.0 - proc byLent2[T](a: openarray[T]): lent T = a[0] + proc byLent2[T](a: openArray[T]): lent T = a[0] doAssert byLent2(a) == 11 doAssert byLent2(a).unsafeAddr == a[0].unsafeAddr doAssert byLent2(b) == 21 diff --git a/tests/magics/tmagics.nim b/tests/magics/tmagics.nim index 70926a0d7..0e412940c 100644 --- a/tests/magics/tmagics.nim +++ b/tests/magics/tmagics.nim @@ -18,7 +18,7 @@ block tlowhigh: for i in low(a) .. high(a): a[i] = 0 - proc sum(a: openarray[int]): int = + proc sum(a: openArray[int]): int = result = 0 for i in low(a)..high(a): inc(result, a[i]) diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim index 7d787c07b..29e23f9d0 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim @@ -53,7 +53,7 @@ else: const glRealType* = cGLfloat -proc setUniformV4*[T](loc: GLint, vecs: var openarray[TV4[T]]) = +proc setUniformV4*[T](loc: GLint, vecs: var openArray[TV4[T]]) = glUniform4fv(loc, vecs.len.GLsizei, cast[ptr GLfloat](vecs[0].addr)) proc setUniformV4*[T](loc: GLint, vec: TV4[T]) = diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim index 3bfaf1cbc..accc2d96b 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim @@ -47,7 +47,7 @@ proc newVert*(rect: rect.TRect): seq[TVert] = proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: GLvoid): TVertAttrib = TVertAttrib(i: i, size: size, stride: stride, offset: offset) -proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openarray[T]): GLuint = +proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openArray[T]): GLuint = result = 0.GLuint ?glGenBuffers(1, result.addr) ?glBindBuffer(vboTarget, result) diff --git a/tests/misc/t9039.nim b/tests/misc/t9039.nim index ba636d1db..3271cd34e 100644 --- a/tests/misc/t9039.nim +++ b/tests/misc/t9039.nim @@ -15,7 +15,7 @@ but expression 'nesting + 1' is of type: int # line 15 func default(T: typedesc[array]): T = discard doAssert default(array[3, int]) == [0, 0, 0] -func shapeBad*[T: not char](s: openarray[T], rank: static[int], nesting = 0, parent_shape = default(array[rank, int])): array[rank, int] = +func shapeBad*[T: not char](s: openArray[T], rank: static[int], nesting = 0, parent_shape = default(array[rank, int])): array[rank, int] = result = parent_shape result[nesting] = s.len when (T is seq|array): diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim index 1ea3c86b9..2dd345254 100644 --- a/tests/misc/theaproots.nim +++ b/tests/misc/theaproots.nim @@ -28,7 +28,7 @@ proc acc(x: var Foo): var ref Bar = proc test(maybeFoo: var Foo, maybeSeq: var seq[ref Bar], - bars: var openarray[ref Bar], + bars: var openArray[ref Bar], maybeTup: var Tup) = var bb: ref Bar maybeFoo.rmaybe = bb diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim index e4a8e0b37..4793c63df 100644 --- a/tests/misc/tsimplesort.nim +++ b/tests/misc/tsimplesort.nim @@ -112,7 +112,7 @@ proc initTable*[A, B](initialSize=64): TTable[A, B] = result.counter = 0 newSeq(result.data, initialSize) -proc toTable*[A, B](pairs: openarray[tuple[key: A, +proc toTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): TTable[A, B] = ## creates a new hash table that contains the given `pairs`. result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) diff --git a/tests/openarray/topena1.nim b/tests/openarray/topena1.nim index ed3a0cedb..380c57f2a 100644 --- a/tests/openarray/topena1.nim +++ b/tests/openarray/topena1.nim @@ -6,4 +6,4 @@ discard """ # Tests a special bug var - x: ref openarray[string] #ERROR_MSG invalid type + x: ref openArray[string] #ERROR_MSG invalid type diff --git a/tests/openarray/topenarrayrepr.nim b/tests/openarray/topenarrayrepr.nim index 3784d4bbb..fc40d88c3 100644 --- a/tests/openarray/topenarrayrepr.nim +++ b/tests/openarray/topenarrayrepr.nim @@ -2,12 +2,12 @@ discard """ output: "5 - [1]" """ type - TProc = proc (n: int, m: openarray[int64]) {.nimcall.} + TProc = proc (n: int, m: openArray[int64]) {.nimcall.} proc Foo(x: int, P: TProc) = P(x, [ 1'i64 ]) -proc Bar(n: int, m: openarray[int64]) = +proc Bar(n: int, m: openArray[int64]) = echo($n & " - " & repr(m)) Foo(5, Bar) #OUT 5 - [1] diff --git a/tests/openarray/topenlen.nim b/tests/openarray/topenlen.nim index 83d58ac5c..164241b85 100644 --- a/tests/openarray/topenlen.nim +++ b/tests/openarray/topenlen.nim @@ -5,7 +5,7 @@ discard """ proc choose(b: openArray[string]): string = return b[0] -proc p(a, b: openarray[string]): int = +proc p(a, b: openArray[string]): int = result = a.len + b.len - 1 for j in 0 .. a.len: inc(result) discard choose(a) diff --git a/tests/openarray/tptrarrayderef.nim b/tests/openarray/tptrarrayderef.nim index 5e77430d1..1b7ef0df0 100644 --- a/tests/openarray/tptrarrayderef.nim +++ b/tests/openarray/tptrarrayderef.nim @@ -15,14 +15,14 @@ var raa = [11,12,13] #bug #3586 -proc mutate[T](arr:openarray[T], brr: openArray[T]) = +proc mutate[T](arr:openArray[T], brr: openArray[T]) = for i in 0..arr.len-1: doAssert(arr[i] == brr[i]) mutate(arr, arr) #bug #2240 -proc f(a: openarray[int], b: openArray[int]) = +proc f(a: openArray[int], b: openArray[int]) = for i in 0..a.len-1: doAssert(a[i] == b[i]) @@ -37,7 +37,7 @@ ra[2] = 13 f(ra[], raa) #bug #2240b -proc fillBuffer(buf: var openarray[char]) = +proc fillBuffer(buf: var openArray[char]) = for i in 0..buf.len-1: buf[i] = chr(i) diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 55a8d17e6..0741fce60 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -264,8 +264,8 @@ proc init*[T](hmctx: HMAC[T], key: ptr byte, ulen: uint) = const sizeBlock = hmctx.sizeBlock echo sizeBlock -proc hmac*[A, B](HashType: typedesc, key: openarray[A], - data: openarray[B]) = +proc hmac*[A, B](HashType: typedesc, key: openArray[A], + data: openArray[B]) = var ctx: HMAC[HashType] ctx.init(nil, 0) diff --git a/tests/showoff/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim index 0e10c6dd8..c61e177dc 100644 --- a/tests/showoff/tdrdobbs_examples.nim +++ b/tests/showoff/tdrdobbs_examples.nim @@ -40,12 +40,12 @@ const msb3999 = mostSignificantBit(3999) echo msb3999, " ", mostSignificantBit(0), " ", square(44) -proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] = +proc filter[T](a: openArray[T], predicate: proc (x: T): bool): seq[T] = result = @[] # @[] constructs the empty seq for x in a: if predicate(x): result.add(x) -proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] = +proc map[T, S](a: openArray[T], fn: proc (x: T): S): seq[S] = newSeq(result, a.len) for i in 0 ..< a.len: result[i] = fn(a[i]) diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim index 9d440a1d6..8dcb158ca 100644 --- a/tests/stdlib/tdochelpers.nim +++ b/tests/stdlib/tdochelpers.nim @@ -76,7 +76,7 @@ suite "Integration with Nim": check(input3.toLangSymbol == expected) test "advanced proc parsing with Nim identifier normalization": - let input = """`proc binarySearch*[T, K](a: openArray[T]; key: K; + let input = """`proc binarySearch*[T, K](a: openarray[T]; key: K; cmp: proc (x: T; y: K): int)`_""".rstParseTest let expected = LangSymbol(symKind: "proc", name: "binarysearch", @@ -90,7 +90,7 @@ suite "Integration with Nim": check(input.toLangSymbol == expected) test "the same without proc": - let input = """`binarySearch*[T, K](a: openArray[T]; key: K; + let input = """`binarySearch*[T, K](a: openarray[T]; key: K; cmp: proc (x: T; y: K): int {.closure.})`_""".rstParseTest let expected = LangSymbol(symKind: "", name: "binarysearch", diff --git a/tests/stdlib/tparseipv6.nim b/tests/stdlib/tparseipv6.nim index dd9abc511..9b9c464c7 100644 --- a/tests/stdlib/tparseipv6.nim +++ b/tests/stdlib/tparseipv6.nim @@ -210,12 +210,12 @@ const "::a:b:85:e4d9:252.9.229.056", ] -proc ok(pos: openarray[string]) = +proc ok(pos: openArray[string]) = for p in pos: if not isIpAddress(p): echo "failure ", p -proc notok(neg: openarray[string]) = +proc notok(neg: openArray[string]) = for n in neg: if isIpAddress(n): echo "failure ", n diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 83ae7b119..82c991805 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -64,7 +64,7 @@ template main() = doAssert repr(arr) == "[1, 2, 3]" block: # bug #7878 - proc reprOpenarray(variable: var openarray[int]): string = repr(variable) + proc reprOpenarray(variable: var openArray[int]): string = repr(variable) when defined(js): discard # BUG: doesn't work else: doAssert reprOpenarray(arr) == "[1, 2, 3]" diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index fa82acc3b..bdbaa2ce6 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -68,7 +68,7 @@ doAssert yy == "" proc bar(arg: cstring) = doAssert arg[0] == '\0' -proc baz(arg: openarray[char]) = +proc baz(arg: openArray[char]) = doAssert arg.len == 0 proc stringCompare() = diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 13b8c18a9..7f5914725 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -131,12 +131,12 @@ let str = "0123456789" foo(toOpenArrayByte(str, 0, str.high)) -template boundedOpenArray[T](x: seq[T], first, last: int): openarray[T] = +template boundedOpenArray[T](x: seq[T], first, last: int): openArray[T] = toOpenarray(x, max(0, first), min(x.high, last)) # bug #9281 -proc foo[T](x: openarray[T]) = +proc foo[T](x: openArray[T]) = echo x.len let a = @[1, 2, 3] diff --git a/tests/template/otests.nim b/tests/template/otests.nim index 120146343..9cb9d7fcb 100644 --- a/tests/template/otests.nim +++ b/tests/template/otests.nim @@ -163,7 +163,7 @@ when true: #embeddingTest """ # Expression template - proc test_expression(nums: openarray[int] = []): string = + proc test_expression(nums: openArray[int] = []): string = var i = 2 tmpli html""" $(no_substitution()) @@ -171,7 +171,7 @@ when true: #embeddingTest
      Age: $($nums[i] & "!!")
      """ - proc test_statements(nums: openarray[int] = []): string = + proc test_statements(nums: openArray[int] = []): string = tmpli html""" $(test_expression(nums)) $if true { diff --git a/tests/template/sunset.nimf b/tests/template/sunset.nimf index 465b12a5e..bd57bb8e1 100644 --- a/tests/template/sunset.nimf +++ b/tests/template/sunset.nimf @@ -1,6 +1,6 @@ #? stdtmpl #proc sunsetTemplate*(current, ticker, content: string, -# tabs: openarray[array[0..1, string]]): string = +# tabs: openArray[array[0..1, string]]): string = # result = "" diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index 502c6d1ee..1fed694ef 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -173,7 +173,7 @@ block t2585: st echo "a ", $fb - proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2; + proc render(rdat: var RenderData; passes: var openArray[RenderPass]; proj: Mat2; indexType = 1) = for i in 0 ..< len(passes): echo "blah ", repr(passes[i]) diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim index 7136c8cab..9cad6eccd 100644 --- a/tests/tuples/tuple_with_nil.nim +++ b/tests/tuples/tuple_with_nil.nim @@ -477,7 +477,7 @@ proc writeformat(o: var Writer; b: bool; fmt: Format) = 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[system.any]; fmt: Format) = +proc writeformat(o: var Writer; ary: openArray[system.any]; fmt: Format) = ## Write array `ary` according to format `fmt` using output object ## `o` and output function `add`. if ary.len == 0: return @@ -657,7 +657,7 @@ proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} = result = newLit(x) proc generatefmt(fmtstr: string; - args: var openarray[tuple[arg:NimNode, cnt:int]]; + args: var openArray[tuple[arg:NimNode, cnt:int]]; arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} = ## fmtstr ## the format string diff --git a/tests/typerel/tcommontype.nim b/tests/typerel/tcommontype.nim index 8215ebd5e..488047fd1 100644 --- a/tests/typerel/tcommontype.nim +++ b/tests/typerel/tcommontype.nim @@ -12,7 +12,7 @@ type proc newDog():PDog = new(result) proc newCat():PCat = new(result) -proc test(a:openarray[PAnimal])= +proc test(a:openArray[PAnimal])= echo("dummy") #test(newDog(),newCat()) #does not work diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim index b11aa2f4e..57f1e81b6 100644 --- a/tests/typerel/texplicitcmp.nim +++ b/tests/typerel/texplicitcmp.nim @@ -8,7 +8,7 @@ discard """ import json, tables, algorithm -proc outp(a: openarray[int]) = +proc outp(a: openArray[int]) = stdout.write "[" for i in a: stdout.write($i & " ") stdout.write "]\n" diff --git a/tests/typerel/tstr_as_openarray.nim b/tests/typerel/tstr_as_openarray.nim index fc28d6c93..14cd21479 100644 --- a/tests/typerel/tstr_as_openarray.nim +++ b/tests/typerel/tstr_as_openarray.nim @@ -3,18 +3,18 @@ discard """ """ var s = "HI" -proc x (zz: openarray[char]) = +proc x (zz: openArray[char]) = discard x s -proc z [T] (zz: openarray[T]) = +proc z [T] (zz: openArray[T]) = discard z s z([s,s,s]) -proc y [T] (arg: var openarray[T]) = +proc y [T] (arg: var openArray[T]) = arg[0] = 'X' y s doAssert s == "XI" diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index ced487ce8..249058eb6 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -44,7 +44,7 @@ echo foo(x) type F = object - oa: openarray[int] + oa: openArray[int] let s1 = @[1,3,4,5,6] var test = F(oa: toOpenArray(s1, 0, 2)) diff --git a/tests/vm/tyaytypedesc.nim b/tests/vm/tyaytypedesc.nim index a3ad9b707..aab94d643 100644 --- a/tests/vm/tyaytypedesc.nim +++ b/tests/vm/tyaytypedesc.nim @@ -10,7 +10,7 @@ type NodeType* = enum type TokenType* = enum ttWhitespace -proc enumTable*[A, B, C](a: openarray[tuple[key: A, val: B]], ret: typedesc[C]): C = +proc enumTable*[A, B, C](a: openArray[tuple[key: A, val: B]], ret: typedesc[C]): C = for item in a: result[item.key] = item.val From 5ec8b609421a2e74e7d5f8d00293194faf4437d4 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Thu, 6 Jan 2022 08:19:32 -0300 Subject: [PATCH 3230/4254] Update net.nim (#19327) [backport] --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 8dc92e9d6..c1d4c6228 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1628,7 +1628,7 @@ proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: ## used. Therefore if `socket` contains something in its buffer this ## function will make no effort to return it. template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) = - var addrLen = sizeof(sockAddress).SockLen + var addrLen = SockLen(sizeof(sockAddress)) result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) From c7d5b8c83ddf204c6e0cd7b6937d33318320ed91 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Fri, 7 Jan 2022 04:26:55 -0300 Subject: [PATCH 3231/4254] Fix #19038 - making the Nim compiler work again on Windows XP (#19331) * Update osenv.nim * Update win_setenv.nim * Update lib/pure/includes/osenv.nim * Update lib/pure/includes/osenv.nim * fixing cstring Co-authored-by: Andreas Rumpf --- lib/pure/includes/osenv.nim | 5 +++-- lib/std/private/win_setenv.nim | 41 +++++++++++++++++----------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index 1a01ab9bc..4a776eb78 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -45,7 +45,7 @@ when not defined(nimscript): proc c_getenv(env: cstring): cstring {. importc: "getenv", header: "".} when defined(windows): - proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "".} from std/private/win_setenv import setEnvImpl else: proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} @@ -121,7 +121,8 @@ when not defined(nimscript): ]# if key.len == 0 or '=' in key: raise newException(OSError, "invalid key, got: " & key) - if c_putenv_s(key, "") != 0'i32: bail + let envToDel = key & "=" + if c_putenv(cstring envToDel) != 0'i32: bail else: if c_unsetenv(key) != 0'i32: bail diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim index 91c3f15b0..0dfe0ed46 100644 --- a/lib/std/private/win_setenv.nim +++ b/lib/std/private/win_setenv.nim @@ -30,44 +30,45 @@ else: # same as winlean.setEnvironmentVariableA proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} - proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "".} proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "".} var errno {.importc, header: "".}: cint - var gWenviron {.importc:"_wenviron".}: ptr ptr wchar_t + var gWenviron {.importc: "_wenviron".}: ptr ptr wchar_t # xxx `ptr UncheckedArray[WideCString]` did not work - proc mbstowcs_s(pReturnValue: ptr csize_t, wcstr: ptr wchar_t, sizeInWords: csize_t, mbstr: cstring, count: csize_t): cint {.importc: "mbstowcs_s", header: "".} + proc mbstowcs(wcstr: ptr wchar_t, mbstr: cstring, count: csize_t): csize_t {.importc: "mbstowcs", header: "".} # xxx cint vs errno_t? - proc setEnvImpl*(name: cstring, value: cstring, overwrite: cint): cint = + proc setEnvImpl*(name: string, value: string, overwrite: cint): cint = const EINVAL = cint(22) - const MAX_ENV = 32767 - # xxx get it from: `var MAX_ENV {.importc: "_MAX_ENV", header:"".}: cint` - if overwrite == 0 and c_getenv(name) != nil: return 0 - if value[0] != '\0': - let e = c_putenv_s(name, value) + if overwrite == 0 and c_getenv(cstring(name)) != nil: return 0 + if value != "": + let envstring = name & "=" & value + let e = c_putenv(cstring(envstring)) if e != 0: - errno = e + errno = EINVAL return -1 return 0 #[ - We are trying to set the value to an empty string, but `_putenv_s` deletes + We are trying to set the value to an empty string, but `_putenv` deletes entries if the value is an empty string, and just calling SetEnvironmentVariableA doesn't update `_environ`, so we have to do these terrible things. ]# - if c_putenv_s(name, " ") != 0: + let envstring = name & "= " + if c_putenv(cstring(envstring)) != 0: errno = EINVAL return -1 # Here lies the documentation we blatently ignore to make this work. - var s = c_getenv(name) + var s = c_getenv(cstring(name)) s[0] = '\0' #[ This would result in a double null termination, which normally signifies the end of the environment variable list, so we stick a completely empty environment variable into the list instead. ]# + s = c_getenv(cstring(name)) s[1] = '=' #[ If gWenviron is null, the wide environment has not been initialized @@ -77,19 +78,19 @@ else: ]# if gWenviron != nil: # var buf: array[MAX_ENV + 1, WideCString] - var buf: array[MAX_ENV + 1, Utf16Char] + let requiredSize = mbstowcs(nil, cstring(name), 0).int + var buf = newSeq[Utf16Char](requiredSize + 1) let buf2 = cast[ptr wchar_t](buf[0].addr) - var len: csize_t - if mbstowcs_s(len.addr, buf2, buf.len.csize_t, name, MAX_ENV) != 0: + if mbstowcs(buf2, cstring(name), csize_t(requiredSize + 1)) == csize_t(high(uint)): errno = EINVAL return -1 - let ptrToEnv = cast[WideCString](c_wgetenv(buf2)) + var ptrToEnv = cast[WideCString](c_wgetenv(buf2)) ptrToEnv[0] = '\0'.Utf16Char - let ptrToEnv2 = cast[WideCString](c_wgetenv(buf2)) - ptrToEnv2[1] = '='.Utf16Char + ptrToEnv = cast[WideCString](c_wgetenv(buf2)) + ptrToEnv[1] = '='.Utf16Char # And now, we have to update the outer environment to have a proper empty value. - if setEnvironmentVariableA(name, value) == 0: + if setEnvironmentVariableA(cstring(name), cstring(value)) == 0: errno = EINVAL return -1 return 0 From 4306d8fb36d3810b8d38a665f98dc89ce107740e Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 8 Jan 2022 12:06:28 +0800 Subject: [PATCH 3232/4254] disable fragments (#19341) The original repo has moved to Rust, while the package path stay unchanged. And it causes troubles to https://github.com/nim-lang/Nim/pull/19338 --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 381aa27ac..853a58698 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -64,7 +64,7 @@ pkg "docopt" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "elvis" pkg "fidget" -pkg "fragments", "nim c -r fragments/dsl.nim" +pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115 pkg "fusion" pkg "gara" pkg "glob" From 58656aa5bba572672f093499280b69bb0f0d4c06 Mon Sep 17 00:00:00 2001 From: Zachary Marquez Date: Sat, 8 Jan 2022 03:22:56 -0600 Subject: [PATCH 3233/4254] fix nim-lang#19343 (#19344) [backport] Ensure HttpClient onProgress is called once per second Ensure that reported speed is accurate --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 7686d15bd..5b6e439db 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -673,7 +673,7 @@ proc reportProgress(client: HttpClient | AsyncHttpClient, progress: BiggestInt) {.multisync.} = client.contentProgress += progress client.oneSecondProgress += progress - if (getMonoTime() - client.lastProgressReport).inSeconds > 1: + if (getMonoTime() - client.lastProgressReport).inSeconds >= 1: if not client.onProgressChanged.isNil: await client.onProgressChanged(client.contentTotal, client.contentProgress, From ae92eac06031ed57a755c01efdbb9cc5b72e5dbf Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 9 Jan 2022 04:34:22 +0800 Subject: [PATCH 3234/4254] stylecheck usages part two: stdlib cleanup (#19338) * stylecheck usages part two: stdlib cleanup typeinfo.nim: importCompilerProc => importcompilerproc nre.nim: newLineFlags => newlineFlags system.nim: JSRoot => JsRoot ref #19319 * prefer importCompilerProc --- compiler/wordrecg.nim | 2 +- lib/impure/nre.nim | 2 +- lib/pure/os.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 22f6cc71d..c819f4306 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -41,7 +41,7 @@ type wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor", wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp", wCppNonPod = "cppNonPod", - wImportObjC = "importobjc", wImportCompilerProc = "importcompilerproc", + wImportObjC = "importobjc", wImportCompilerProc = "importCompilerProc", wImportc = "importc", wImportJs = "importjs", wExportc = "exportc", wExportCpp = "exportcpp", wExportNims = "exportnims", wIncompleteStruct = "incompleteStruct", # deprecated diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index f346d84cb..03cbf5220 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -281,7 +281,7 @@ proc matchesCrLf(pattern: Regex): bool = let newlineFlags = flags and (pcre.NEWLINE_CRLF or pcre.NEWLINE_ANY or pcre.NEWLINE_ANYCRLF) - if newLineFlags > 0u32: + if newlineFlags > 0u32: return true # get flags from build config diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 9b08fe2e1..81b432d7f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2888,7 +2888,7 @@ when defined(nimdoc): elif defined(nimscript): discard elif defined(nodejs): - type Argv = object of JSRoot + type Argv = object of JsRoot let argv {.importjs: "process.argv".} : Argv proc len(argv: Argv): int {.importjs: "#.length".} proc `[]`(argv: Argv, i: int): cstring {.importjs: "#[#]".} From b098546da051ed026e85a9f398e74c396c79a8ad Mon Sep 17 00:00:00 2001 From: Smarcy Date: Sun, 9 Jan 2022 14:02:08 +0100 Subject: [PATCH 3235/4254] added filemode docs (#19346) --- lib/system/io.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 661d1a9ba..04a43328d 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -22,6 +22,8 @@ type FileMode* = enum ## The file mode when opening a file. fmRead, ## Open the file for read access only. + ## If the file does not exist, it will not + ## be created. fmWrite, ## Open the file for write access only. ## If the file does not exist, it will be ## created. Existing files will be cleared! @@ -32,7 +34,8 @@ type ## If the file does not exist, it will not be ## created. The existing file will not be cleared. fmAppend ## Open the file for writing only; append data - ## at the end. + ## at the end. If the file does not exist, it + ## will be created. FileHandle* = cint ## type that represents an OS file handle; this is ## useful for low-level file access From 955040f0f1d4f9b2eab68c385fab9d4cfbef8ea5 Mon Sep 17 00:00:00 2001 From: gecko Date: Mon, 10 Jan 2022 09:27:59 +0000 Subject: [PATCH 3236/4254] Fix `remove` on last node of singly-linked list [backport:1.6] (#19353) --- changelog.md | 1 + lib/pure/collections/lists.nim | 2 ++ tests/stdlib/tlists.nim | 13 +++++++++++++ 3 files changed, 16 insertions(+) diff --git a/changelog.md b/changelog.md index 1b97fd99a..d07f80623 100644 --- a/changelog.md +++ b/changelog.md @@ -22,6 +22,7 @@ - `macros.parseExpr` and `macros.parseStmt` now accept an optional filename argument for more informative errors. - Module `colors` expanded with missing colors from the CSS color standard. +- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). ## `std/smtp` diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index f7627ae67..d1de0ea67 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -739,6 +739,8 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.disc if prev.next == nil: return false prev.next = n.next + if L.tail == n: + L.tail = prev # update tail if we removed the last node true proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 14cbf2f9d..00c5b1a27 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -258,5 +258,18 @@ template main = a.add(2) doAssert a.toSeq == @[1, 2] + block RemoveLastNodeFromSinglyLinkedList: + var list = initSinglyLinkedList[string]() + let n1 = newSinglyLinkedNode("sonic") + let n2 = newSinglyLinkedNode("the") + let n3 = newSinglyLinkedNode("tiger") + let n4 = newSinglyLinkedNode("hedgehog") + list.add(n1) + list.add(n2) + list.add(n3) + list.remove(n3) + list.add(n4) + doAssert list.toSeq == @["sonic", "the", "hedgehog"] + static: main() main() From 92e5573b20f30f4114a4eb1f35eddc7064bfcd71 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 10 Jan 2022 17:29:04 +0800 Subject: [PATCH 3237/4254] fix stylecheck error with asyncdispatch (#19350) * stylecheck usages part two: stdlib cleanup typeinfo.nim: importCompilerProc => importcompilerproc nre.nim: newLineFlags => newlineFlags system.nim: JSRoot => JsRoot ref #19319 * prefer importCompilerProc * fix stylecheck error with asyncdispatch it is a partial regression since #12842 * add tests * don't use echo in tests --- compiler/semtempl.nim | 3 ++- tests/stylecheck/taccept.nim | 17 +++++++++++++++++ tests/stylecheck/treject.nim | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/stylecheck/taccept.nim create mode 100644 tests/stylecheck/treject.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 49ce55a64..b921fda2c 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -270,7 +270,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode = # Issue #12832 when defined(nimsuggest): suggestSym(c.graph, n.info, s, c.graph.usageSym, false) - if {optStyleHint, optStyleError} * c.config.globalOptions != {}: + # field access (dot expr) will be handled by builtinFieldAccess + if not isField and {optStyleHint, optStyleError} * c.config.globalOptions != {}: styleCheckUse(c.config, n.info, s) proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = diff --git a/tests/stylecheck/taccept.nim b/tests/stylecheck/taccept.nim new file mode 100644 index 000000000..6fb55f835 --- /dev/null +++ b/tests/stylecheck/taccept.nim @@ -0,0 +1,17 @@ +discard """ + matrix: "--styleCheck:error --styleCheck:usages" +""" + +import asyncdispatch + +type + Name = object + id: int + +template hello = + var iD = "string" + var name: Name + doAssert name.id == 0 + doAssert iD == "string" + +hello() diff --git a/tests/stylecheck/treject.nim b/tests/stylecheck/treject.nim new file mode 100644 index 000000000..b9d97a58d --- /dev/null +++ b/tests/stylecheck/treject.nim @@ -0,0 +1,17 @@ +discard """ + action: reject + nimout: '''treject.nim(14, 13) Error: 'iD' should be: 'id' [field declared in treject.nim(9, 5)]''' + matrix: "--styleCheck:error --styleCheck:usages" +""" + +type + Name = object + id: int + +template hello = + var iD = "string" + var name: Name + echo name.iD + echo iD + +hello() \ No newline at end of file From bcbeff36321aa203cd258fd02c82d9276badf31f Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 10 Jan 2022 18:59:44 +0800 Subject: [PATCH 3238/4254] remove spaces between an identifier and a star (#19355) It makes search easier by searching `+`* instead of `+` which filter lots of unexported versions. Follow https://github.com/nim-lang/Nim/pull/18681 --- lib/js/jsffi.nim | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 937e3727b..ac963eb89 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -163,28 +163,28 @@ macro jsFromAst*(n: untyped): untyped = proc `&`*(a, b: cstring): cstring {.importjs: "(# + #)".} ## Concatenation operator for JavaScript strings. -proc `+` *(x, y: JsObject): JsObject {.importjs: "(# + #)".} -proc `-` *(x, y: JsObject): JsObject {.importjs: "(# - #)".} -proc `*` *(x, y: JsObject): JsObject {.importjs: "(# * #)".} -proc `/` *(x, y: JsObject): JsObject {.importjs: "(# / #)".} -proc `%` *(x, y: JsObject): JsObject {.importjs: "(# % #)".} -proc `+=` *(x, y: JsObject): JsObject {.importjs: "(# += #)", discardable.} -proc `-=` *(x, y: JsObject): JsObject {.importjs: "(# -= #)", discardable.} -proc `*=` *(x, y: JsObject): JsObject {.importjs: "(# *= #)", discardable.} -proc `/=` *(x, y: JsObject): JsObject {.importjs: "(# /= #)", discardable.} -proc `%=` *(x, y: JsObject): JsObject {.importjs: "(# %= #)", discardable.} -proc `++` *(x: JsObject): JsObject {.importjs: "(++#)".} -proc `--` *(x: JsObject): JsObject {.importjs: "(--#)".} -proc `>` *(x, y: JsObject): JsObject {.importjs: "(# > #)".} -proc `<` *(x, y: JsObject): JsObject {.importjs: "(# < #)".} -proc `>=` *(x, y: JsObject): JsObject {.importjs: "(# >= #)".} -proc `<=` *(x, y: JsObject): JsObject {.importjs: "(# <= #)".} -proc `**` *(x, y: JsObject): JsObject {.importjs: "((#) ** #)".} +proc `+`*(x, y: JsObject): JsObject {.importjs: "(# + #)".} +proc `-`*(x, y: JsObject): JsObject {.importjs: "(# - #)".} +proc `*`*(x, y: JsObject): JsObject {.importjs: "(# * #)".} +proc `/`*(x, y: JsObject): JsObject {.importjs: "(# / #)".} +proc `%`*(x, y: JsObject): JsObject {.importjs: "(# % #)".} +proc `+=`*(x, y: JsObject): JsObject {.importjs: "(# += #)", discardable.} +proc `-=`*(x, y: JsObject): JsObject {.importjs: "(# -= #)", discardable.} +proc `*=`*(x, y: JsObject): JsObject {.importjs: "(# *= #)", discardable.} +proc `/=`*(x, y: JsObject): JsObject {.importjs: "(# /= #)", discardable.} +proc `%=`*(x, y: JsObject): JsObject {.importjs: "(# %= #)", discardable.} +proc `++`*(x: JsObject): JsObject {.importjs: "(++#)".} +proc `--`*(x: JsObject): JsObject {.importjs: "(--#)".} +proc `>`*(x, y: JsObject): JsObject {.importjs: "(# > #)".} +proc `<`*(x, y: JsObject): JsObject {.importjs: "(# < #)".} +proc `>=`*(x, y: JsObject): JsObject {.importjs: "(# >= #)".} +proc `<=`*(x, y: JsObject): JsObject {.importjs: "(# <= #)".} +proc `**`*(x, y: JsObject): JsObject {.importjs: "((#) ** #)".} # (#) needed, refs https://github.com/nim-lang/Nim/pull/16409#issuecomment-760550812 proc `and`*(x, y: JsObject): JsObject {.importjs: "(# && #)".} -proc `or` *(x, y: JsObject): JsObject {.importjs: "(# || #)".} +proc `or`*(x, y: JsObject): JsObject {.importjs: "(# || #)".} proc `not`*(x: JsObject): JsObject {.importjs: "(!#)".} -proc `in` *(x, y: JsObject): JsObject {.importjs: "(# in #)".} +proc `in`*(x, y: JsObject): JsObject {.importjs: "(# in #)".} proc `[]`*(obj: JsObject, field: cstring): JsObject {.importjs: getImpl.} ## Returns the value of a property of name `field` from a JsObject `obj`. From 9888a29c3de09c73202b2a955e09e2a7b5e56ea4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 11 Jan 2022 10:16:51 +0100 Subject: [PATCH 3239/4254] bitsets.nim: cleanup (#19361) --- compiler/bitsets.nim | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim index 2e8aa1db6..e0d94409e 100644 --- a/compiler/bitsets.nim +++ b/compiler/bitsets.nim @@ -23,53 +23,40 @@ const template modElemSize(arg: untyped): untyped = arg and 7 template divElemSize(arg: untyped): untyped = arg shr 3 -proc bitSetInit*(b: var TBitSet, length: int) -proc bitSetUnion*(x: var TBitSet, y: TBitSet) -proc bitSetDiff*(x: var TBitSet, y: TBitSet) -proc bitSetSymDiff*(x: var TBitSet, y: TBitSet) -proc bitSetIntersect*(x: var TBitSet, y: TBitSet) -proc bitSetIncl*(x: var TBitSet, elem: BiggestInt) -proc bitSetExcl*(x: var TBitSet, elem: BiggestInt) -proc bitSetIn*(x: TBitSet, e: BiggestInt): bool -proc bitSetEquals*(x, y: TBitSet): bool -proc bitSetContains*(x, y: TBitSet): bool -proc bitSetCard*(x: TBitSet): BiggestInt -# implementation - -proc bitSetIn(x: TBitSet, e: BiggestInt): bool = +proc bitSetIn*(x: TBitSet, e: BiggestInt): bool = result = (x[int(e.divElemSize)] and (One shl e.modElemSize)) != Zero -proc bitSetIncl(x: var TBitSet, elem: BiggestInt) = +proc bitSetIncl*(x: var TBitSet, elem: BiggestInt) = assert(elem >= 0) x[int(elem.divElemSize)] = x[int(elem.divElemSize)] or (One shl elem.modElemSize) -proc bitSetExcl(x: var TBitSet, elem: BiggestInt) = +proc bitSetExcl*(x: var TBitSet, elem: BiggestInt) = x[int(elem.divElemSize)] = x[int(elem.divElemSize)] and not(One shl elem.modElemSize) -proc bitSetInit(b: var TBitSet, length: int) = +proc bitSetInit*(b: var TBitSet, length: int) = newSeq(b, length) -proc bitSetUnion(x: var TBitSet, y: TBitSet) = +proc bitSetUnion*(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] or y[i] -proc bitSetDiff(x: var TBitSet, y: TBitSet) = +proc bitSetDiff*(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] and not y[i] -proc bitSetSymDiff(x: var TBitSet, y: TBitSet) = +proc bitSetSymDiff*(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] xor y[i] -proc bitSetIntersect(x: var TBitSet, y: TBitSet) = +proc bitSetIntersect*(x: var TBitSet, y: TBitSet) = for i in 0..high(x): x[i] = x[i] and y[i] -proc bitSetEquals(x, y: TBitSet): bool = +proc bitSetEquals*(x, y: TBitSet): bool = for i in 0..high(x): if x[i] != y[i]: return false result = true -proc bitSetContains(x, y: TBitSet): bool = +proc bitSetContains*(x, y: TBitSet): bool = for i in 0..high(x): if (x[i] and not y[i]) != Zero: return false @@ -96,6 +83,6 @@ const populationCount: array[uint8, uint8] = block: arr -proc bitSetCard(x: TBitSet): BiggestInt = +proc bitSetCard*(x: TBitSet): BiggestInt = for it in x: result.inc int(populationCount[it]) From 9a32905d89d23e423bca2d0ce643b9331a6741c0 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 13 Jan 2022 15:02:41 +0800 Subject: [PATCH 3240/4254] nimscript ignore the threads option (#19370) because nimscript doesn't support threads and causes troubles when the threads option is on --- compiler/commands.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index c4df46bc2..8e79a4477 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -717,7 +717,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info) of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info) of "threads": - if conf.backend == backendJs: discard + if conf.backend == backendJs or conf.cmd == cmdNimscript: discard else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info) #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe) of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) From ada815e45957e5675a9ac978b85b8467d68c5945 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 13 Jan 2022 15:03:14 +0800 Subject: [PATCH 3241/4254] make rst thread safe (#19369) split for the convenience of review --- lib/packages/docutils/rst.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index a04eb696f..791953767 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -2822,7 +2822,7 @@ type DirFlag = enum hasArg, hasOptions, argIsFile, argIsWord DirFlags = set[DirFlag] - SectionParser = proc (p: var RstParser): PRstNode {.nimcall.} + SectionParser = proc (p: var RstParser): PRstNode {.nimcall, gcsafe.} proc parseDirective(p: var RstParser, k: RstNodeKind, flags: DirFlags): PRstNode = ## Parses arguments and options for a directive block. @@ -2869,7 +2869,7 @@ proc indFollows(p: RstParser): bool = result = currentTok(p).kind == tkIndent and currentTok(p).ival > currInd(p) proc parseBlockContent(p: var RstParser, father: var PRstNode, - contentParser: SectionParser): bool = + contentParser: SectionParser): bool {.gcsafe.} = ## parse the final content part of explicit markup blocks (directives, ## footnotes, etc). Returns true if succeeded. if currentTok(p).kind != tkIndent or indFollows(p): @@ -3123,7 +3123,7 @@ proc prefix(ftnType: FootnoteType): string = of fnAutoSymbol: result = "footnotesym-" of fnCitation: result = "citation-" -proc parseFootnote(p: var RstParser): PRstNode = +proc parseFootnote(p: var RstParser): PRstNode {.gcsafe.} = ## Parses footnotes and citations, always returns 2 sons: ## ## 1) footnote label, always containing rnInner with 1 or more sons From a9135095f02587430b179a33ae03910d0d4201cd Mon Sep 17 00:00:00 2001 From: Leon Date: Fri, 14 Jan 2022 00:40:27 +1100 Subject: [PATCH 3242/4254] docs: Mention `import foo {.all.}` syntax (#19377) Mention the `import foo {.all.}` syntax in the manual, with a caveat about private imports. Also link to the experimental importutils module. Co-authored-by: adigitoleo --- doc/manual_experimental.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 4ed8439df..0f82b9950 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -168,6 +168,17 @@ This feature will likely be superseded in the future by support for recursive module dependencies. +Importing private symbols +========================= + +In some situations, it may be useful to import all symbols (public or private) +from a module. The syntax `import foo {.all.}` can be used to import all +symbols from the module `foo`. Note that importing private symbols is +generally not recommended. + +See also the experimental `importutils `_ module. + + Code reordering =============== From 40a9c33eff099a37be236826f84eb2064d0ec247 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 13 Jan 2022 21:43:35 +0800 Subject: [PATCH 3243/4254] update copyright year (#19381) --- compiler/options.nim | 2 +- copying.txt | 2 +- readme.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 9e957332f..5cfe58119 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -19,7 +19,7 @@ const useEffectSystem* = true useWriteTracking* = false hasFFI* = defined(nimHasLibFFI) - copyrightYear* = "2021" + copyrightYear* = "2022" nimEnableCovariance* = defined(nimEnableCovariance) diff --git a/copying.txt b/copying.txt index a498a9525..60b6a0217 100644 --- a/copying.txt +++ b/copying.txt @@ -1,7 +1,7 @@ ===================================================== Nim -- a Compiler for Nim. https://nim-lang.org/ -Copyright (C) 2006-2021 Andreas Rumpf. All rights reserved. +Copyright (C) 2006-2022 Andreas Rumpf. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index 7d45556db..6bc7a2385 100644 --- a/readme.md +++ b/readme.md @@ -203,7 +203,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2021 Andreas Rumpf, all rights reserved. +Copyright © 2006-2022 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org From 5853303be09464832ce0f189513c90c9dd15f4a0 Mon Sep 17 00:00:00 2001 From: Leon Date: Fri, 14 Jan 2022 00:45:47 +1100 Subject: [PATCH 3244/4254] docs: Fix broken cross references to `rfind` in strutils (#19382) [backport] Fixes three broken cross references to `rfind` in strutils. Breakage due to signature changes of the `rfind` methods. Co-authored-by: adigitoleo --- lib/pure/strutils.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index e4a4a5ec1..5e505ec3a 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1865,7 +1865,7 @@ func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, ## Use `s[start..last].rfind` for a `start`-origin index. ## ## See also: - ## * `rfind func<#rfind,string,char,Natural>`_ + ## * `rfind func<#rfind,string,char,Natural,int>`_ ## * `replace func<#replace,string,char,char>`_ let last = if last == 0: s.high else: last when nimvm: @@ -1893,7 +1893,7 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. ## Use `s[start..last].find` for a `start`-origin index. ## ## See also: - ## * `rfind func<#rfind,string,set[char],Natural>`_ + ## * `rfind func<#rfind,string,set[char],Natural,int>`_ ## * `multiReplace func<#multiReplace,string,varargs[]>`_ let last = if last == 0: s.high else: last for i in int(start)..last: @@ -1910,7 +1910,7 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, ## Use `s[start..last].find` for a `start`-origin index. ## ## See also: - ## * `rfind func<#rfind,string,string,Natural>`_ + ## * `rfind func<#rfind,string,string,Natural,int>`_ ## * `replace func<#replace,string,string,string>`_ if sub.len > s.len - start: return -1 if sub.len == 1: return find(s, sub[0], start, last) From 9b9ae8a487c6fbf77c8c72196e2b74f3371382b2 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 14 Jan 2022 00:39:17 +0800 Subject: [PATCH 3245/4254] nrvo shouldn't touch bycopy object[backport:1.2] (#19385) fix nim-lang#19342 --- compiler/ccgtypes.nim | 2 +- tests/objects/m19342.c | 12 ++++++++++++ tests/objects/t19342.nim | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/objects/m19342.c create mode 100644 tests/objects/t19342.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 740ce5f19..df1874b26 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -220,7 +220,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. - if rettype == nil or getSize(conf, rettype) > conf.target.floatSize*3: + if rettype == nil or (tfByCopy notin rettype.flags and getSize(conf, rettype) > conf.target.floatSize*3): result = true else: case mapType(conf, rettype, skResult) diff --git a/tests/objects/m19342.c b/tests/objects/m19342.c new file mode 100644 index 000000000..113f65309 --- /dev/null +++ b/tests/objects/m19342.c @@ -0,0 +1,12 @@ +struct Node +{ + int data[25]; +}; + + +struct Node hello(int name) { + struct Node x = {999, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9, + 1, 2, 3, 4, 5}; + return x; +} \ No newline at end of file diff --git a/tests/objects/t19342.nim b/tests/objects/t19342.nim new file mode 100644 index 000000000..d40d15a4b --- /dev/null +++ b/tests/objects/t19342.nim @@ -0,0 +1,18 @@ +discard """ + targets: "c cpp" +""" + +{.compile: "m19342.c".} + +# bug #19342 +type + Node* {.bycopy.} = object + data: array[25, cint] + +proc myproc(name: cint): Node {.importc: "hello", cdecl.} + +proc parse = + let node = myproc(10) + doAssert node.data[0] == 999 + +parse() From a93f6e7acc9e02deb40a864d345e4c715346a98c Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Thu, 13 Jan 2022 09:39:55 -0700 Subject: [PATCH 3246/4254] Generic parameters now can constrain statics in type definitions (#19362) * Parameters now can constrain static in type definitions resolved regression with generic procedures * Update compiler/sigmatch.nim Co-authored-by: Andreas Rumpf --- compiler/sigmatch.nim | 14 +++++++-- tests/generics/tstatic_constrained.nim | 42 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/generics/tstatic_constrained.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 93be92676..4d8e03fe9 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1739,11 +1739,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let prev = PType(idTableGet(c.bindings, f)) if prev == nil: if aOrig.kind == tyStatic: - if f.base.kind != tyNone: + if f.base.kind notin {tyNone, tyGenericParam}: result = typeRel(c, f.base, a, flags) if result != isNone and f.n != nil: if not exprStructuralEquivalent(f.n, aOrig.n): result = isNone + elif f.base.kind == tyGenericParam: + # Handling things like `type A[T; Y: static T] = object` + if f.base.len > 0: # There is a constraint, handle it + result = typeRel(c, f.base.lastSon, a, flags) + else: + # No constraint + if tfGenericTypeParam in f.flags: + result = isGeneric + else: + # for things like `proc fun[T](a: static[T])` + result = typeRel(c, f.base, a, flags) else: result = isGeneric if result != isNone: put(c, f, aOrig) @@ -1993,7 +2004,6 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, arg = argSemantized a = a c = m.c - if tfHasStatic in fMaybeStatic.flags: # XXX: When implicit statics are the default # this will be done earlier - we just have to diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim new file mode 100644 index 000000000..07318d1bd --- /dev/null +++ b/tests/generics/tstatic_constrained.nim @@ -0,0 +1,42 @@ +discard """ + cmd: "nim check --hints:off --warnings:off $file" + action: "reject" + nimout:''' +tstatic_constrained.nim(41, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +got: +but expected: +tstatic_constrained.nim(41, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +got: +but expected: +tstatic_constrained.nim(41, 29) Error: object constructor needs an object type [proxy] +tstatic_constrained.nim(41, 29) Error: expression '' has no type (or is ambiguous) +tstatic_constrained.nim(42, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +got: +but expected: +tstatic_constrained.nim(42, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +got: +but expected: +tstatic_constrained.nim(42, 32) Error: object constructor needs an object type [proxy] +tstatic_constrained.nim(42, 32) Error: expression '' has no type (or is ambiguous) +''' +""" + +type + MyType[T; X: static T] = object + data: T + MyOtherType[T: float or string, Y: static T] = object + +func f[T,X](a: MyType[T,X]): MyType[T,X] = + when T is string: + MyType[T,X](data: a.data & X) + else: + MyType[T,X](data: a.data + X) + +discard MyType[int, 2](data: 1) +discard MyType[string, "Helelello"](data: "Hmmm") +discard MyType[int, 2](data: 1).f() +discard MyType[string, "Helelello"](data: "Hmmm").f() +discard MyOtherType[float, 1.3]() +discard MyOtherType[string, "Hello"]() +discard MyOtherType[int, 10]() +discard MyOtherType[byte, 10u8]() \ No newline at end of file From 7bdfeb78190ca9ff6a0cf702c6ec202f379bff2f Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sat, 15 Jan 2022 01:24:23 -0700 Subject: [PATCH 3247/4254] Fixed concept constraints for static types (#19391) --- compiler/sigmatch.nim | 9 +++ tests/generics/tstatic_constrained.nim | 87 ++++++++++++++++++-------- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4d8e03fe9..e1195d04a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1634,6 +1634,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, bindConcreteTypeToUserTypeClass(matched, a) if doBind: put(c, f, matched) result = isGeneric + elif a.len > 0 and a.lastSon == f: + # Needed for checking `Y` == `Addable` in the following + #[ + type + Addable = concept a, type A + a + a is A + MyType[T: Addable; Y: static T] = object + ]# + result = isGeneric else: result = isNone diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim index 07318d1bd..3c9201548 100644 --- a/tests/generics/tstatic_constrained.nim +++ b/tests/generics/tstatic_constrained.nim @@ -2,41 +2,78 @@ discard """ cmd: "nim check --hints:off --warnings:off $file" action: "reject" nimout:''' -tstatic_constrained.nim(41, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: but expected: -tstatic_constrained.nim(41, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: but expected: -tstatic_constrained.nim(41, 29) Error: object constructor needs an object type [proxy] -tstatic_constrained.nim(41, 29) Error: expression '' has no type (or is ambiguous) -tstatic_constrained.nim(42, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [proxy] +tstatic_constrained.nim(44, 31) Error: expression '' has no type (or is ambiguous) +tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: but expected: -tstatic_constrained.nim(42, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)] +tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: but expected: -tstatic_constrained.nim(42, 32) Error: object constructor needs an object type [proxy] -tstatic_constrained.nim(42, 32) Error: expression '' has no type (or is ambiguous) +tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [proxy] +tstatic_constrained.nim(45, 34) Error: expression '' has no type (or is ambiguous) +tstatic_constrained.nim(77, 14) Error: cannot instantiate MyType [type declared in tstatic_constrained.nim(71, 5)] +got: +but expected: ''' """ +block: + type + MyType[T; X: static T] = object + data: T + MyOtherType[T: float or string, Y: static T] = object -type - MyType[T; X: static T] = object - data: T - MyOtherType[T: float or string, Y: static T] = object + func f[T,X](a: MyType[T,X]): MyType[T,X] = + when T is string: + MyType[T,X](data: a.data & X) + else: + MyType[T,X](data: a.data + X) -func f[T,X](a: MyType[T,X]): MyType[T,X] = - when T is string: - MyType[T,X](data: a.data & X) - else: - MyType[T,X](data: a.data + X) + discard MyType[int, 2](data: 1) + discard MyType[string, "Helelello"](data: "Hmmm") + discard MyType[int, 2](data: 1).f() + discard MyType[string, "Helelello"](data: "Hmmm").f() + discard MyOtherType[float, 1.3]() + discard MyOtherType[string, "Hello"]() + discard MyOtherType[int, 10]() + discard MyOtherType[byte, 10u8]() -discard MyType[int, 2](data: 1) -discard MyType[string, "Helelello"](data: "Hmmm") -discard MyType[int, 2](data: 1).f() -discard MyType[string, "Helelello"](data: "Hmmm").f() -discard MyOtherType[float, 1.3]() -discard MyOtherType[string, "Hello"]() -discard MyOtherType[int, 10]() -discard MyOtherType[byte, 10u8]() \ No newline at end of file +block: + type + Moduloable = concept m, type M + m mod m is M + Addable = concept a, type A + a + a is A + Modulo[T: Moduloable; Mod: static T] = distinct T + ModuloAdd[T: Moduloable or Addable; Mod: static T] = distinct T + ModuAddable = Addable or Moduloable + ModdAddClass[T: ModuAddable; Mod: static T] = distinct T + + proc toMod[T](val: T, modVal: static T): Modulo[T, modVal] = + mixin `mod` + Modulo[T, modVal](val mod modVal) + var + a = 3231.toMod(10) + b = 5483.toMod(10) + discard ModuloAdd[int, 3](0) + discard ModdAddClass[int, 3](0) + +block: + type + MyConstraint = int or string + MyOtherConstraint[T] = object + MyType[T: MyConstraint; Y: static T] = object + MyOtherType[T: MyOtherConstraint; Y: static T] = object + + var + a: MyType[int, 10] + b: MyType[string, "hello"] + c: MyType[float, 10d] + d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()] + e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()] \ No newline at end of file From 342b74ef70e6a71c09ba536d20e23a7e887d2fb8 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 15 Jan 2022 18:25:09 +0800 Subject: [PATCH 3248/4254] move type operation section and remove deepcopy document (#19389) ref #19173; because deepcopy is not fit for ORC/ARC which was used for spawn and spawn will be removed from compiler --- doc/manual.rst | 12 +++++++++ doc/manual_experimental.rst | 54 ++++++++++--------------------------- 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 8788e53a3..007b14b2d 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3902,6 +3902,18 @@ the operator is in scope (including if it is private). Type bound operators are: `=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`. +These operations can be *overridden* instead of *overloaded*. This means that +the implementation is automatically lifted to structured types. For instance, +if the type `T` has an overridden assignment operator `=`, this operator is +also used for assignments of the type `seq[T]`. + +Since these operations are bound to a type, they have to be bound to a +nominal type for reasons of simplicity of implementation; this means an +overridden `deepCopy` for `ref T` is really bound to `T` and not to `ref T`. +This also means that one cannot override `deepCopy` for both `ptr T` and +`ref T` at the same time, instead a distinct or object helper type has to be +used for one pointer type. + For more details on some of those procs, see `Lifetime-tracking hooks `_. diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 0f82b9950..10958c29a 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1192,51 +1192,25 @@ object inheritance syntax involving the `of` keyword: the `vtptr` magic produced types bound to `ptr` types. -Type bound operations -===================== +.. + deepCopy + -------- + `=deepCopy` is a builtin that is invoked whenever data is passed to + a `spawn`'ed proc to ensure memory safety. The programmer can override its + behaviour for a specific `ref` or `ptr` type `T`. (Later versions of the + language may weaken this restriction.) -There are 4 operations that are bound to a type: + The signature has to be: -1. Assignment -2. Moves -3. Destruction -4. Deep copying for communication between threads + .. code-block:: nim -These operations can be *overridden* instead of *overloaded*. This means that -the implementation is automatically lifted to structured types. For instance, -if the type `T` has an overridden assignment operator `=`, this operator is -also used for assignments of the type `seq[T]`. + proc `=deepCopy`(x: T): T -Since these operations are bound to a type, they have to be bound to a -nominal type for reasons of simplicity of implementation; this means an -overridden `deepCopy` for `ref T` is really bound to `T` and not to `ref T`. -This also means that one cannot override `deepCopy` for both `ptr T` and -`ref T` at the same time, instead a distinct or object helper type has to be -used for one pointer type. + This mechanism will be used by most data structures that support shared memory, + like channels, to implement thread safe automatic memory management. -Assignments, moves and destruction are specified in -the `destructors `_ document. - - -deepCopy --------- - -`=deepCopy` is a builtin that is invoked whenever data is passed to -a `spawn`'ed proc to ensure memory safety. The programmer can override its -behaviour for a specific `ref` or `ptr` type `T`. (Later versions of the -language may weaken this restriction.) - -The signature has to be: - -.. code-block:: nim - - proc `=deepCopy`(x: T): T - -This mechanism will be used by most data structures that support shared memory, -like channels, to implement thread safe automatic memory management. - -The builtin `deepCopy` can even clone closures and their environments. See -the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details. + The builtin `deepCopy` can even clone closures and their environments. See + the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details. Dynamic arguments for bindSym From a95399143fdbd518f4d5fe33487b656c4cde7d6d Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sat, 15 Jan 2022 15:19:05 +0300 Subject: [PATCH 3249/4254] Use openarray of bytes in md5 (#19307) * Use openarray of bytes in md5 * fix CI * cleanup * use noSideEffect for bootstrapping * fix CI again * actually fix CI by checking if it works * this is getting ridiculous * put old md5 version in compiler, remove vmop --- changelog.md | 1 + compiler/md5_old.nim | 297 +++++++++++++++++++++++++++++++++++ compiler/modulegraphs.nim | 2 +- compiler/sighashes.nim | 2 +- compiler/vmops.nim | 6 - lib/pure/md5.nim | 131 +++++++++++---- tests/js/tstdlib_imports.nim | 3 +- tests/stdlib/tmd5.nim | 19 ++- tests/test_nimscript.nims | 3 +- 9 files changed, 413 insertions(+), 51 deletions(-) create mode 100644 compiler/md5_old.nim diff --git a/changelog.md b/changelog.md index d07f80623..4d27be3a0 100644 --- a/changelog.md +++ b/changelog.md @@ -23,6 +23,7 @@ filename argument for more informative errors. - Module `colors` expanded with missing colors from the CSS color standard. - Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). +- `md5` now works at compile time and in JavaScript. ## `std/smtp` diff --git a/compiler/md5_old.nim b/compiler/md5_old.nim new file mode 100644 index 000000000..da4a51198 --- /dev/null +++ b/compiler/md5_old.nim @@ -0,0 +1,297 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# `std/md5` without VM and JavaScript support, to circumvent a bug with +# openarrays on Nim < 1.4. + +when defined(nimHasStyleChecks): + {.push styleChecks: off.} + +type + MD5State = array[0..3, uint32] + MD5Block = array[0..15, uint32] + MD5CBits = array[0..7, uint8] + MD5Digest* = array[0..15, uint8] + ## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_. + MD5Buffer = array[0..63, uint8] + MD5Context* {.final.} = object + state: MD5State + count: array[0..1, uint32] + buffer: MD5Buffer + +const + padding: array[0..63, uint8] = [ + 0x80'u8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + ] + +proc F(x, y, z: uint32): uint32 {.inline.} = + result = (x and y) or ((not x) and z) + +proc G(x, y, z: uint32): uint32 {.inline.} = + result = (x and z) or (y and (not z)) + +proc H(x, y, z: uint32): uint32 {.inline.} = + result = x xor y xor z + +proc I(x, y, z: uint32): uint32 {.inline.} = + result = y xor (x or (not z)) + +proc rot(x: var uint32, n: uint8) {.inline.} = + x = (x shl n) or (x shr (32'u32 - n)) + +proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) = + a = a + F(b, c, d) + x + ac + rot(a, s) + a = a + b + +proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) = + a = a + G(b, c, d) + x + ac + rot(a, s) + a = a + b + +proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) = + a = a + H(b, c, d) + x + ac + rot(a, s) + a = a + b + +proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) = + a = a + I(b, c, d) + x + ac + rot(a, s) + a = a + b + +proc encode(dest: var MD5Block, src: openArray[uint8]) = + var j = 0 + for i in 0..high(dest): + dest[i] = uint32(ord(src[j])) or + uint32(ord(src[j+1])) shl 8 or + uint32(ord(src[j+2])) shl 16 or + uint32(ord(src[j+3])) shl 24 + inc(j, 4) + +proc decode(dest: var openArray[uint8], src: openArray[uint32]) = + var i = 0 + for j in 0..high(src): + dest[i] = uint8(src[j] and 0xff'u32) + dest[i+1] = uint8(src[j] shr 8 and 0xff'u32) + dest[i+2] = uint8(src[j] shr 16 and 0xff'u32) + dest[i+3] = uint8(src[j] shr 24 and 0xff'u32) + inc(i, 4) + +template slice(s: string | cstring, a, b): openArray[uint8] = + s.toOpenArrayByte(a, b) + +template slice(s: openArray[uint8], a, b): openArray[uint8] = + s.toOpenArray(a, b) + +proc transform(buffer: openArray[uint8], state: var MD5State) = + var + myBlock: MD5Block + encode(myBlock, buffer) + var a = state[0] + var b = state[1] + var c = state[2] + var d = state[3] + FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32) + FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32) + FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32) + FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32) + FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32) + FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32) + FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32) + FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32) + FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32) + FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32) + FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32) + FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32) + FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32) + FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32) + FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32) + FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32) + GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32) + GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32) + GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32) + GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32) + GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32) + GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32) + GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32) + GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32) + GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32) + GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32) + GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32) + GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32) + GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32) + GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32) + GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32) + GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32) + HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32) + HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32) + HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32) + HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32) + HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32) + HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32) + HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32) + HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32) + HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32) + HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32) + HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32) + HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32) + HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32) + HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32) + HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32) + HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32) + II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32) + II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32) + II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32) + II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32) + II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32) + II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32) + II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32) + II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32) + II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32) + II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32) + II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32) + II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32) + II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32) + II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32) + II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32) + II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32) + state[0] = state[0] + a + state[1] = state[1] + b + state[2] = state[2] + c + state[3] = state[3] + d + +proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.} +proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [], + tags: [], gcsafe.} +proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.} + +proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [], + tags: [], gcsafe.} = + ## Updates the `MD5Context` with the `input` data of length `len`. + ## + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this + ## function explicitly. + md5Update(c, input.slice(0, len - 1)) + + +proc toMD5*(s: string): MD5Digest = + ## Computes the `MD5Digest` value for a string `s`. + ## + ## **See also:** + ## * `getMD5 proc <#getMD5,string>`_ which returns a string representation + ## of the `MD5Digest` + ## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string + runnableExamples: + assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72" + + var c: MD5Context + md5Init(c) + md5Update(c, s.slice(0, s.len - 1)) + md5Final(c, result) + +proc `$`*(d: MD5Digest): string = + ## Converts a `MD5Digest` value into its string representation. + const digits = "0123456789abcdef" + result = "" + for i in 0..15: + add(result, digits[(d[i].int shr 4) and 0xF]) + add(result, digits[d[i].int and 0xF]) + +proc getMD5*(s: string): string = + ## Computes an MD5 value of `s` and returns its string representation. + ## + ## **See also:** + ## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string + runnableExamples: + assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72" + + var + c: MD5Context + d: MD5Digest + md5Init(c) + md5Update(c, s.slice(0, s.len - 1)) + md5Final(c, d) + result = $d + +proc `==`*(D1, D2: MD5Digest): bool = + ## Checks if two `MD5Digest` values are identical. + for i in 0..15: + if D1[i] != D2[i]: return false + return true + + +proc clearBuffer(c: var MD5Context) {.inline.} = + zeroMem(addr(c.buffer), sizeof(MD5Buffer)) + +proc md5Init*(c: var MD5Context) = + ## Initializes an `MD5Context`. + ## + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this + ## function explicitly. + c.state[0] = 0x67452301'u32 + c.state[1] = 0xEFCDAB89'u32 + c.state[2] = 0x98BADCFE'u32 + c.state[3] = 0x10325476'u32 + c.count[0] = 0'u32 + c.count[1] = 0'u32 + clearBuffer(c) + +proc writeBuffer(c: var MD5Context, index: int, + input: openArray[uint8], inputIndex, len: int) {.inline.} = + copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len) + +proc md5Update*(c: var MD5Context, input: openArray[uint8]) = + ## Updates the `MD5Context` with the `input` data. + ## + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this + ## function explicitly. + var Index = int((c.count[0] shr 3) and 0x3F) + c.count[0] = c.count[0] + (uint32(input.len) shl 3) + if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32 + c.count[1] = c.count[1] + (uint32(input.len) shr 29) + var PartLen = 64 - Index + if input.len >= PartLen: + writeBuffer(c, Index, input, 0, PartLen) + transform(c.buffer, c.state) + var i = PartLen + while i + 63 < input.len: + transform(input.slice(i, i + 63), c.state) + inc(i, 64) + if i < input.len: + writeBuffer(c, 0, input, i, input.len - i) + elif input.len > 0: + writeBuffer(c, Index, input, 0, input.len) + +proc md5Final*(c: var MD5Context, digest: var MD5Digest) = + ## Finishes the `MD5Context` and stores the result in `digest`. + ## + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this + ## function explicitly. + var + Bits: MD5CBits + PadLen: int + decode(Bits, c.count) + var Index = int((c.count[0] shr 3) and 0x3F) + if Index < 56: PadLen = 56 - Index + else: PadLen = 120 - Index + md5Update(c, padding.slice(0, PadLen - 1)) + md5Update(c, Bits) + decode(digest, c.state) + clearBuffer(c) + + +when defined(nimHasStyleChecks): + {.pop.} #{.push styleChecks: off.} diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 90b130e92..28e0ddb82 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -11,7 +11,7 @@ ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -import intsets, tables, hashes, md5 +import intsets, tables, hashes, md5_old import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils import ic / [packed_ast, ic] diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index d02728627..3d36d2533 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -9,7 +9,7 @@ ## Computes hash values for routine (proc, method etc) signatures. -import ast, tables, ropes, md5, modulegraphs +import ast, tables, ropes, md5_old, modulegraphs from hashes import Hash import types diff --git a/compiler/vmops.nim b/compiler/vmops.nim index b9801234d..22a632ee9 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -25,7 +25,6 @@ when declared(math.signbit): from std/os import getEnv, existsEnv, delEnv, putEnv, envPairs, dirExists, fileExists, walkDir, getAppFilename, raiseOSError, osLastError -from std/md5 import getMD5 from std/times import cpuTime from std/hashes import hash from std/osproc import nil @@ -53,9 +52,6 @@ template ioop(op) {.dirty.} = template macrosop(op) {.dirty.} = registerCallback(c, "stdlib.macros." & astToStr(op), `op Wrapper`) -template md5op(op) {.dirty.} = - registerCallback(c, "stdlib.md5." & astToStr(op), `op Wrapper`) - template wrap1f_math(op) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = doAssert a.numArgs == 1 @@ -212,8 +208,6 @@ proc registerAdditionalOps*(c: PCtx) = of 2: setResult(a, round(getFloat(a, 0), getInt(a, 1).int)) else: doAssert false, $n - wrap1s(getMD5, md5op) - proc `mod Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1))) registerCallback(c, "stdlib.math.mod", `mod Wrapper`) diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index 11c324548..06c5608a4 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -9,7 +9,7 @@ ## Module for computing [MD5 checksums](https://en.wikipedia.org/wiki/MD5). ## -## **Note:** The procs in this module can be used at compile time. +## This module also works at compile time and in JavaScript. ## ## See also ## ======== @@ -34,15 +34,16 @@ type buffer: MD5Buffer const - padding: cstring = "\x80\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0\0\0\0\0" & - "\0\0\0\0" + padding: array[0..63, uint8] = [ + 0x80'u8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + ] proc F(x, y, z: uint32): uint32 {.inline.} = result = (x and y) or ((not x) and z) @@ -79,7 +80,7 @@ proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) = rot(a, s) a = a + b -proc encode(dest: var MD5Block, src: cstring) = +proc encode(dest: var MD5Block, src: openArray[uint8]) = var j = 0 for i in 0..high(dest): dest[i] = uint32(ord(src[j])) or @@ -97,10 +98,48 @@ proc decode(dest: var openArray[uint8], src: openArray[uint32]) = dest[i+3] = uint8(src[j] shr 24 and 0xff'u32) inc(i, 4) -proc transform(buffer: pointer, state: var MD5State) = +template slice(s: string, a, b): openArray[uint8] = + when nimvm: + # toOpenArray is not implemented in VM + var s2 = newSeq[uint8](s.len) + for i in 0 ..< s2.len: + s2[i] = uint8(s[i]) + s2 + else: + s.toOpenArrayByte(a, b) + +template slice(s: cstring, a, b): openArray[uint8] = + when nimvm: + # toOpenArray is not implemented in VM + slice($s, a, b) + else: + when defined(js): + # toOpenArrayByte for cstring is not implemented in JS + slice($s, a, b) + else: + s.toOpenArrayByte(a, b) + +template slice(s: openArray[uint8], a, b): openArray[uint8] = + when nimvm: + s[a .. b] + else: + s.toOpenArray(a, b) + +const useMem = declared(copyMem) + +template memOrNot(withMem, withoutMem): untyped = + when nimvm: + withoutMem + else: + when useMem: + withMem + else: + withoutMem + +proc transform(buffer: openArray[uint8], state: var MD5State) = var myBlock: MD5Block - encode(myBlock, cast[cstring](buffer)) + encode(myBlock, buffer) var a = state[0] var b = state[1] var c = state[2] @@ -175,10 +214,18 @@ proc transform(buffer: pointer, state: var MD5State) = state[3] = state[3] + d proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.} -proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [], +proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [], tags: [], gcsafe.} proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.} +proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [], + tags: [], gcsafe.} = + ## Updates the `MD5Context` with the `input` data of length `len`. + ## + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this + ## function explicitly. + md5Update(c, input.slice(0, len - 1)) + proc toMD5*(s: string): MD5Digest = ## Computes the `MD5Digest` value for a string `s`. @@ -192,7 +239,7 @@ proc toMD5*(s: string): MD5Digest = var c: MD5Context md5Init(c) - md5Update(c, cstring(s), len(s)) + md5Update(c, s.slice(0, s.len - 1)) md5Final(c, result) proc `$`*(d: MD5Digest): string = @@ -215,7 +262,7 @@ proc getMD5*(s: string): string = c: MD5Context d: MD5Digest md5Init(c) - md5Update(c, cstring(s), len(s)) + md5Update(c, s.slice(0, s.len - 1)) md5Final(c, d) result = $d @@ -226,6 +273,12 @@ proc `==`*(D1, D2: MD5Digest): bool = return true +proc clearBuffer(c: var MD5Context) {.inline.} = + memOrNot: + zeroMem(addr(c.buffer), sizeof(MD5Buffer)) + do: + reset(c.buffer) + proc md5Init*(c: var MD5Context) = ## Initializes an `MD5Context`. ## @@ -237,29 +290,39 @@ proc md5Init*(c: var MD5Context) = c.state[3] = 0x10325476'u32 c.count[0] = 0'u32 c.count[1] = 0'u32 - zeroMem(addr(c.buffer), sizeof(MD5Buffer)) + clearBuffer(c) -proc md5Update*(c: var MD5Context, input: cstring, len: int) = - ## Updates the `MD5Context` with the `input` data of length `len`. +proc writeBuffer(c: var MD5Context, index: int, + input: openArray[uint8], inputIndex, len: int) {.inline.} = + memOrNot: + copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len) + do: + # cannot use system.`[]=` for arrays and openarrays as + # it can raise RangeDefect which gets tracked + for i in 0..`_, there's no need to call this ## function explicitly. - var input = input var Index = int((c.count[0] shr 3) and 0x3F) - c.count[0] = c.count[0] + (uint32(len) shl 3) - if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32 - c.count[1] = c.count[1] + (uint32(len) shr 29) + c.count[0] = c.count[0] + (uint32(input.len) shl 3) + if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32 + c.count[1] = c.count[1] + (uint32(input.len) shr 29) var PartLen = 64 - Index - if len >= PartLen: - copyMem(addr(c.buffer[Index]), input, PartLen) - transform(addr(c.buffer), c.state) + if input.len >= PartLen: + writeBuffer(c, Index, input, 0, PartLen) + transform(c.buffer, c.state) var i = PartLen - while i + 63 < len: - transform(addr(input[i]), c.state) + while i + 63 < input.len: + transform(input.slice(i, i + 63), c.state) inc(i, 64) - copyMem(addr(c.buffer[0]), addr(input[i]), len-i) - else: - copyMem(addr(c.buffer[Index]), addr(input[0]), len) + if i < input.len: + writeBuffer(c, 0, input, i, input.len - i) + elif input.len > 0: + writeBuffer(c, Index, input, 0, input.len) proc md5Final*(c: var MD5Context, digest: var MD5Digest) = ## Finishes the `MD5Context` and stores the result in `digest`. @@ -273,10 +336,10 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) = var Index = int((c.count[0] shr 3) and 0x3F) if Index < 56: PadLen = 56 - Index else: PadLen = 120 - Index - md5Update(c, padding, PadLen) - md5Update(c, cast[cstring](addr(Bits)), 8) + md5Update(c, padding.slice(0, PadLen - 1)) + md5Update(c, Bits) decode(digest, c.state) - zeroMem(addr(c), sizeof(MD5Context)) + clearBuffer(c) when defined(nimHasStyleChecks): diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim index 9986fa059..30aca7561 100644 --- a/tests/js/tstdlib_imports.nim +++ b/tests/js/tstdlib_imports.nim @@ -57,8 +57,7 @@ import std/[ htmlgen, # Hashing: - base64, hashes, - # fails due to cstring cast/zeroMem/copyMem/moveMem: md5 + base64, hashes, md5, # fails due to cstring cast/endians import: oids # fails due to copyMem/endians import: sha1 diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim index 88a7b8d37..4017ac677 100644 --- a/tests/stdlib/tmd5.nim +++ b/tests/stdlib/tmd5.nim @@ -1,7 +1,16 @@ +discard """ + targets: "c cpp js" +""" + import md5 -doAssert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "a3cca2b2aa1e3b5b3b5aad99a8529074") -doAssert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "7e716d0e702df0505fc72e2b89467910") -doAssert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") +proc main() {.raises: [].} = + doAssert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == + "a3cca2b2aa1e3b5b3b5aad99a8529074") + doAssert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == + "7e716d0e702df0505fc72e2b89467910") + doAssert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") + +main() + +static: main() diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 761ddafdf..22a566307 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -59,8 +59,7 @@ import std/[ htmlgen, # Hashing: - base64, hashes, - # fails due to cstring cast/zeroMem/copyMem/moveMem: md5 + base64, hashes, md5, # fails due to cstring cast/times import/endians import: oids # fails due to copyMem/endians import: sha1 From d102b2f54c41f19a0545f28109d0a93550b5d886 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 16 Jan 2022 18:08:38 +0800 Subject: [PATCH 3250/4254] deprecate unsafeAddr; extend addr (#19373) * deprecate unsafeAddr; extend addr addr is now available for all addressable locations, unsafeAddr is deprecated and become an alias for addr * follow @Vindaar's advice * change the signature of addr * unsafeAddr => addr (stdlib) * Update changelog.md * unsafeAddr => addr (tests) * Revert "unsafeAddr => addr (stdlib)" This reverts commit ab83c99c507048a8396e636bf22d55fdd84d7d1c. * doc changes; thanks to @konsumlamm Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 3 +++ compiler/isolation_check.nim | 2 +- compiler/semmagic.nim | 9 ++----- doc/manual.rst | 15 ++++------- doc/manual_experimental.rst | 2 +- lib/system.nim | 26 +++++++++++++------ tests/arc/tcustomtrace.nim | 2 +- tests/arc/thard_alignment.nim | 2 +- tests/async/tioselectors.nim | 2 +- tests/ccgbugs/tnoalias.nim | 2 +- tests/compiles/t8630.nim | 2 +- tests/concepts/tconcepts_issues.nim | 4 +-- tests/destructor/t12037.nim | 6 ++--- tests/destructor/tarray_indexing.nim | 2 +- tests/destructor/tcustomseqs.nim | 2 +- tests/destructor/tcustomstrings.nim | 2 +- .../destructor/tuse_result_prevents_sinks.nim | 2 +- tests/errmsgs/t10594.nim | 2 +- tests/errmsgs/tnon_concrete_cast.nim | 2 +- tests/js/tfieldchecks.nim | 2 +- tests/lent/tbasic_lent_check.nim | 10 +++---- tests/misc/taddr.nim | 2 +- tests/overload/t8829.nim | 4 +-- tests/overload/tstatic_with_converter.nim | 2 +- tests/stdlib/tdecls.nim | 14 +++++----- tests/stdlib/tmemory.nim | 2 +- tests/stdlib/tsqlitebindatas.nim | 4 +-- tests/strictnotnil/tnilcheck.nim | 2 +- tests/system/tostring.nim | 2 +- tests/types/tlent_var.nim | 2 +- 30 files changed, 69 insertions(+), 66 deletions(-) diff --git a/changelog.md b/changelog.md index 4d27be3a0..9b74d6d9f 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,9 @@ - `std/sharedstrings` module is removed. - Constants `colors.colPaleVioletRed` and `colors.colMediumPurple` changed to match the CSS color standard. +- `addr` is now available for all addressable locations, `unsafeAddr` is deprecated and +becomes an alias for `addr`. + ## Standard library additions and changes - `macros.parseExpr` and `macros.parseStmt` now accept an optional diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index a8c5a3651..68a212794 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -71,7 +71,7 @@ proc isValueOnlyType(t: PType): bool = proc canAlias*(arg, ret: PType): bool = if isValueOnlyType(arg): - # can alias only with unsafeAddr(arg.x) and we don't care if it is not safe + # can alias only with addr(arg.x) and we don't care if it is not safe result = false else: var marker = initIntSet() diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 874098294..c7fc75620 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -14,13 +14,8 @@ proc semAddrArg(c: PContext; n: PNode; isUnsafeAddr = false): PNode = let x = semExprWithType(c, n) if x.kind == nkSym: x.sym.flags.incl(sfAddrTaken) - if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}: - # Do not suggest the use of unsafeAddr if this expression already is a - # unsafeAddr - if isUnsafeAddr: - localError(c.config, n.info, errExprHasNoAddress) - else: - localError(c.config, n.info, errExprHasNoAddress & "; maybe use 'unsafeAddr'") + if isAssignable(c, x, true) notin {arLValue, arLocalLValue}: + localError(c.config, n.info, errExprHasNoAddress) result = x proc semTypeOf(c: PContext; n: PNode): PNode = diff --git a/doc/manual.rst b/doc/manual.rst index 007b14b2d..4eabd0225 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3502,8 +3502,9 @@ location is `T`, the `addr` operator result is of the type `ptr T`. An address is always an untraced reference. Taking the address of an object that resides on the stack is **unsafe**, as the pointer may live longer than the object on the stack and can thus reference a non-existing object. One can get -the address of variables, but one can't use it on variables declared through -`let` statements: +the address of variables. For easier interoperability with other compiled languages +such as C, retrieving the address of a `let` variable, a parameter, +or a `for` loop variable can be accomplished too: .. code-block:: nim @@ -3515,24 +3516,18 @@ the address of variables, but one can't use it on variables declared through # --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello" echo cast[ptr string](t3)[] # --> Hello - # The following line doesn't compile: + # The following line also works echo repr(addr(t1)) - # Error: expression has no address - The unsafeAddr operator ----------------------- -For easier interoperability with other compiled languages such as C, retrieving -the address of a `let` variable, a parameter, or a `for` loop variable can -be accomplished by using the `unsafeAddr` operation: +The `unsafeAddr` operator is a deprecated alias for the `addr` operator: .. code-block:: nim - let myArray = [1, 2, 3] foreignProcThatTakesAnAddr(unsafeAddr myArray) - Procedures ========== diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 10958c29a..407924a13 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -603,7 +603,7 @@ has `source` as the owner. A path expression `e` is defined recursively: - Object field access `e.field` is a path expression. - `system.toOpenArray(e, ...)` is a path expression. - Pointer dereference `e[]` is a path expression. -- An address `addr e`, `unsafeAddr e` is a path expression. +- An address `addr e` is a path expression. - A type conversion `T(e)` is a path expression. - A cast expression `cast[T](e)` is a path expression. - `f(e, ...)` is a path expression if `f`'s return type is a view type. diff --git a/lib/system.nim b/lib/system.nim index c424cbc1b..3b3e28344 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -190,8 +190,16 @@ when defined(nimHasDeclaredMagic): else: proc declaredInScope*(x: untyped): bool {.magic: "DefinedInScope", noSideEffect, compileTime.} -proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = +proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory location. + ## + ## .. note:: This works for `let` variables or parameters + ## for better interop with C. When you use it to write a wrapper + ## for a C library and take the address of `let` variables or parameters, + ## you should always check that the original library + ## does never write to data behind the pointer that is returned from + ## this procedure. + ## ## Cannot be overloaded. ## ## See also: @@ -205,15 +213,17 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## echo p[] # b discard -proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = +proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect, + deprecated: "'unsafeAddr' is a deprecated alias for 'addr'".} = ## Builtin `addr` operator for taking the address of a memory - ## location. This works even for `let` variables or parameters - ## for better interop with C and so it is considered even more - ## unsafe than the ordinary `addr <#addr,T>`_. + ## location. ## - ## **Note**: When you use it to write a wrapper for a C library, you should - ## always check that the original library does never write to data behind the - ## pointer that is returned from this procedure. + ## .. note:: This works for `let` variables or parameters + ## for better interop with C. When you use it to write a wrapper + ## for a C library and take the address of `let` variables or parameters, + ## you should always check that the original library + ## does never write to data behind the pointer that is returned from + ## this procedure. ## ## Cannot be overloaded. discard diff --git a/tests/arc/tcustomtrace.nim b/tests/arc/tcustomtrace.nim index 3977194d9..5e0ecfb24 100644 --- a/tests/arc/tcustomtrace.nim +++ b/tests/arc/tcustomtrace.nim @@ -130,7 +130,7 @@ proc createSeq*[T](elems: varargs[T]): myseq[T] = result.data = cast[type(result.data)](alloc0(result.cap * sizeof(T))) inc allocCount when supportsCopyMem(T): - copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + copyMem(result.data, addr(elems[0]), result.cap * sizeof(T)) else: for i in 0.. 0 doAssert cmpMem(b.addr, a.addr, sizeof(SomeHash)) < 0 - doAssert cmpMem(a.addr, c.unsafeAddr, sizeof(SomeHash)) == 0 + doAssert cmpMem(a.addr, c.addr, sizeof(SomeHash)) == 0 diff --git a/tests/stdlib/tsqlitebindatas.nim b/tests/stdlib/tsqlitebindatas.nim index 754c80ae1..b2c3247fa 100644 --- a/tests/stdlib/tsqlitebindatas.nim +++ b/tests/stdlib/tsqlitebindatas.nim @@ -27,7 +27,7 @@ block tsqlitebindatas: ## db_sqlite binary data db.exec(createTableStr) var dbuf = newSeq[byte](orig.len*sizeof(float64)) - copyMem(unsafeAddr(dbuf[0]), unsafeAddr(orig[0]), dbuf.len) + copyMem(addr(dbuf[0]), addr(orig[0]), dbuf.len) var insertStmt = db.prepare("INSERT INTO test (id, name, data) VALUES (?, ?, ?)") insertStmt.bindParams(1, origName, dbuf) @@ -42,7 +42,7 @@ block tsqlitebindatas: ## db_sqlite binary data var dataTest = db.getValue(sql"SELECT data FROM test WHERE id = ?", 1) let seqSize = int(dataTest.len*sizeof(byte)/sizeof(float64)) var res: seq[float64] = newSeq[float64](seqSize) - copyMem(unsafeAddr(res[0]), addr(dataTest[0]), dataTest.len) + copyMem(addr(res[0]), addr(dataTest[0]), dataTest.len) doAssert res.len == orig.len doAssert res == orig diff --git a/tests/strictnotnil/tnilcheck.nim b/tests/strictnotnil/tnilcheck.nim index 5b9292522..c2d009b70 100644 --- a/tests/strictnotnil/tnilcheck.nim +++ b/tests/strictnotnil/tnilcheck.nim @@ -194,7 +194,7 @@ proc testAliasChanging(a: Nilable) = # # proc testPtrAlias(a: Nilable) = # # # pointer to a: hm. # # # alias to a? -# # var ptrA = a.unsafeAddr # {0, 1} +# # var ptrA = a.addr # {0, 1} # # if not a.isNil: # {0, 1} # # ptrA[] = nil # {0, 1} 0: MaybeNil 1: MaybeNil # # echo a.a #[ tt.Warning diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index bdbaa2ce6..cae20865e 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -47,7 +47,7 @@ import strutils let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0'] doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\\x00']" -doAssert $cstring(unsafeAddr arr) == "Hello World!" +doAssert $cstring(addr arr) == "Hello World!" proc takes(c: cstring) = doAssert c == cstring"" diff --git a/tests/types/tlent_var.nim b/tests/types/tlent_var.nim index 491f6fde8..73b5bef9b 100644 --- a/tests/types/tlent_var.nim +++ b/tests/types/tlent_var.nim @@ -15,7 +15,7 @@ proc test_var(x: var MyObj): var int = var x = MyObj(a: 5) doAssert: test_var(x).addr == x.a.addr -doAssert: test_lent(x).unsafeAddr == x.a.addr +doAssert: test_lent(x).addr == x.a.addr proc varProc(x: var int) = x = 100 From 15e3813d96ad5646476b629f3a20ece89dff064d Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 17 Jan 2022 04:10:35 +0800 Subject: [PATCH 3251/4254] add mm to compilesettings; deprecate gc (#19394) --- compiler/vmops.nim | 1 + lib/std/compilesettings.nim | 3 ++- tests/vm/tcompilesetting.nim | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 22a632ee9..018e7b9c6 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -135,6 +135,7 @@ when defined(nimHasInvariant): of backend: result = $conf.backend of libPath: result = conf.libpath.string of gc: result = $conf.selectedGC + of mm: result = $conf.selectedGC proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim index 5bb0bd673..6d8bd22f4 100644 --- a/lib/std/compilesettings.nim +++ b/lib/std/compilesettings.nim @@ -32,7 +32,8 @@ type backend ## the backend (eg: c|cpp|objc|js); both `nim doc --backend:js` ## and `nim js` would imply backend=js libPath ## the absolute path to the stdlib library, i.e. nim's `--lib`, since 1.5.1 - gc ## gc selected + gc {.deprecated.} ## gc selected + mm ## memory management selected MultipleValueSetting* {.pure.} = enum ## \ ## settings resulting in a seq of string values diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim index 5bf559c74..d6c08e70f 100644 --- a/tests/vm/tcompilesetting.nim +++ b/tests/vm/tcompilesetting.nim @@ -1,5 +1,5 @@ discard """ -cmd: "nim c --nimcache:build/myNimCache --nimblePath:myNimblePath $file" +cmd: "nim c --nimcache:build/myNimCache --nimblePath:myNimblePath --gc:arc $file" joinable: false """ @@ -12,6 +12,7 @@ template main = doAssert "myNimblePath" in nimblePaths.querySettingSeq[0] doAssert querySetting(backend) == "c" doAssert fileExists(libPath.querySetting / "system.nim") + doAssert querySetting(mm) == "arc" static: main() main() From 2c5b367001cc53859048d9adf450a5db3a949b92 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 17 Jan 2022 11:54:27 +0800 Subject: [PATCH 3252/4254] improve changelog a bit (#19400) --- changelog.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 9b74d6d9f..16b526f85 100644 --- a/changelog.md +++ b/changelog.md @@ -28,9 +28,7 @@ becomes an alias for `addr`. - Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). - `md5` now works at compile time and in JavaScript. -## `std/smtp` - -- Sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. +- `std/smtp` sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. - Added `IsoWeekRange`, a range type to represent the number of weeks in an ISO week-based year. - Added `IsoYear`, a distinct int type to prevent bugs from confusing the week-based year and the regular year. From 4f6b59de9698d0c29a2170ecc23c8d009b3181b7 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 17 Jan 2022 18:14:13 +0800 Subject: [PATCH 3253/4254] mangle names in nimbase.h using cppDefine (#19395) [backport] mangle names in nimbase.h fix comments --- config/config.nims | 5 +++++ tests/ccgbugs/tmangle.nim | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/ccgbugs/tmangle.nim diff --git a/config/config.nims b/config/config.nims index 893d6960f..88c344642 100644 --- a/config/config.nims +++ b/config/config.nims @@ -3,6 +3,11 @@ cppDefine "errno" cppDefine "unix" +# mangle the macro names in nimbase.h +cppDefine "NAN_INFINITY" +cppDefine "INF" +cppDefine "NAN" + when defined(nimStrictMode): # xxx add more flags here, and use `-d:nimStrictMode` in more contexts in CI. diff --git a/tests/ccgbugs/tmangle.nim b/tests/ccgbugs/tmangle.nim new file mode 100644 index 000000000..0050cef92 --- /dev/null +++ b/tests/ccgbugs/tmangle.nim @@ -0,0 +1,16 @@ +block: + proc hello() = + let NAN_INFINITY = 12 + doAssert NAN_INFINITY == 12 + let INF = "2.0" + doAssert INF == "2.0" + let NAN = 2.3 + doAssert NAN == 2.3 + + hello() + +block: + proc hello(NAN: float) = + doAssert NAN == 2.0 + + hello(2.0) From dc8ac66873d5189f2e5cf5dbf56a12ab64a38140 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Mon, 17 Jan 2022 04:02:31 -0800 Subject: [PATCH 3254/4254] fix no net compilation on zephyr (#19399) Co-authored-by: Jaremy J. Creechley --- lib/posix/posix_other.nim | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 688867b98..941e13192 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -399,16 +399,20 @@ elif defined(zephyr): const Sockaddr_max_length* = 24 elif defined(net_raw): const Sockaddr_max_length* = 20 - else: + elif defined(net_ipv4): const Sockaddr_max_length* = 8 + else: + const Sockaddr_max_length* = 255 # just for compilation purposes + const Sockaddr_un_path_length* = Sockaddr_max_length # Zephyr is heavily customizable so it's easy to get to a state # where Nim & Zephyr IPv6 settings are out of sync, causing painful runtime failures. - {.emit: ["NIM_STATIC_ASSERT(NET_SOCKADDR_MAX_SIZE == ", - Sockaddr_max_length, - ",\"NET_SOCKADDR_MAX_SIZE and Sockaddr_max_length size mismatch!", - " Check that Nim and Zephyr IPv4/IPv6 settings match.", - " Try adding -d:net_ipv6 to enable IPv6 for Nim on Zephyr.\" );"].} + when defined(net_ipv4) or defined(net_ipv6) or defined(net_raw): + {.emit: ["NIM_STATIC_ASSERT(NET_SOCKADDR_MAX_SIZE == ", + Sockaddr_max_length, + ",\"NET_SOCKADDR_MAX_SIZE and Sockaddr_max_length size mismatch!", + " Check that Nim and Zephyr IPv4/IPv6 settings match.", + " Try adding -d:net_ipv6 to enable IPv6 for Nim on Zephyr.\" );"].} elif defined(freertos) or defined(lwip): const Sockaddr_max_length* = 14 const Sockaddr_un_path_length* = 108 From 07c7a8a526cf4fd12c96192cda7a750fbea3382f Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Mon, 17 Jan 2022 15:03:40 +0300 Subject: [PATCH 3255/4254] Optimize lent in JS [backport:1.6] (#19393) * Optimize lent in JS [backport:1.6] * addr on lent doesn't work anymore, don't use it * use unsafeAddr in test again for older versions --- compiler/jsgen.nim | 51 ++++++++++++++++++++++---------- tests/js/tlent.nim | 33 +++++++++++++++++++++ tests/lent/tbasic_lent_check.nim | 20 ++++++++----- 3 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 tests/js/tlent.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 7e8c25173..0a7036b46 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -178,7 +178,7 @@ const proc mapType(typ: PType): TJSTypeKind = let t = skipTypes(typ, abstractInst) case t.kind - of tyVar, tyRef, tyPtr, tyLent: + of tyVar, tyRef, tyPtr: if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: result = etyObject else: @@ -186,7 +186,8 @@ proc mapType(typ: PType): TJSTypeKind = of tyPointer: # treat a tyPointer like a typed pointer to an array of bytes result = etyBaseIndex - of tyRange, tyDistinct, tyOrdinal, tyProxy: + of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent: + # tyLent is no-op as JS has pass-by-reference semantics result = mapType(t[0]) of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt of tyBool: result = etyBool @@ -1060,14 +1061,14 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = xtyp = etySeq case xtyp of etySeq: - if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") lineF(p, "$1 = nimCopy(null, $2, $3);$n", [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: - if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") @@ -1092,10 +1093,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) lineF(p, "$1 = $2;$n", [a.address, b.res]) lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) + elif a.typ == etyBaseIndex: + # array indexing may not map to var type + if b.address != nil: + lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) + else: + lineF(p, "$1 = $2;$n", [a.address, b.res]) else: internalError(p.config, x.info, $("genAsgn", b.typ, a.typ)) - else: + elif b.address != nil: lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) + else: + lineF(p, "$1 = $2;$n", [a.address, b.res]) else: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) @@ -1288,7 +1297,7 @@ template isIndirect(x: PSym): bool = v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator, skConst, skTemp, skLet}) -proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = +proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = let s = n.sym if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") case s.kind @@ -1456,13 +1465,17 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = else: if s.loc.r == nil: internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) - r.res = s.loc.r + if mapType(p, s.typ) == etyBaseIndex: + r.address = s.loc.r + r.res = s.loc.r & "_Idx" + else: + r.res = s.loc.r r.kind = resVal proc genDeref(p: PProc, n: PNode, r: var TCompRes) = let it = n[0] let t = mapType(p, it.typ) - if t == etyObject: + if t == etyObject or it.typ.kind == tyLent: gen(p, it, r) else: var a: TCompRes @@ -1703,7 +1716,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) - of tyRange, tyGenericInst, tyAlias, tySink, tyOwned: + of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent: result = createVar(p, lastSon(typ), indirect) of tySet: result = putToSeq("{}", indirect) @@ -1745,7 +1758,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = createObjInitList(p, t, initIntSet(), initList) result = ("({$1})") % [initList] if indirect: result = "[$1]" % [result] - of tyVar, tyPtr, tyLent, tyRef, tyPointer: + of tyVar, tyPtr, tyRef, tyPointer: if mapType(p, t) == etyBaseIndex: result = putToSeq("[null, 0]", indirect) else: @@ -2394,16 +2407,17 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = if prc.typ[0] != nil and sfPure notin prc.flags: resultSym = prc.ast[resultPos].sym let mname = mangleName(p.module, resultSym) - if not isIndirect(resultSym) and + let returnAddress = not isIndirect(resultSym) and resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and - mapType(p, resultSym.typ) == etyBaseIndex: + mapType(p, resultSym.typ) == etyBaseIndex + if returnAddress: resultAsgn = p.indentLine(("var $# = null;$n") % [mname]) resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) else: let resVar = createVar(p, resultSym.typ, isIndirect(resultSym)) resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar]) gen(p, prc.ast[resultPos], a) - if mapType(p, resultSym.typ) == etyBaseIndex: + if returnAddress: returnStmt = "return [$#, $#];$n" % [a.address, a.res] else: returnStmt = "return $#;$n" % [a.res] @@ -2579,8 +2593,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkObjConstr: genObjConstr(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkAddr, nkHiddenAddr: - genAddr(p, n, r) - of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r) + if n.typ.kind in {tyLent}: + gen(p, n[0], r) + else: + genAddr(p, n, r) + of nkDerefExpr, nkHiddenDeref: + if n.typ.kind in {tyLent}: + gen(p, n[0], r) + else: + genDeref(p, n, r) of nkBracketExpr: genArrayAccess(p, n, r) of nkDotExpr: genFieldAccess(p, n, r) of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r) diff --git a/tests/js/tlent.nim b/tests/js/tlent.nim new file mode 100644 index 000000000..2546e5b1d --- /dev/null +++ b/tests/js/tlent.nim @@ -0,0 +1,33 @@ +discard """ + output: ''' +hmm +100 +hmm +100 +''' +""" + +# #16800 + +type A = object + b: int +var t = A(b: 100) +block: + proc getValues: lent int = + echo "hmm" + result = t.b + echo getValues() +block: + proc getValues: lent int = + echo "hmm" + t.b + echo getValues() + +when false: # still an issue, #16908 + template main = + iterator fn[T](a:T): lent T = yield a + let a = @[10] + for b in fn(a): echo b + + static: main() + main() diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index 0787e36d9..92d731451 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -17,22 +17,26 @@ proc main = main() template main2 = # bug #15958 + when defined(js): + proc sameAddress[T](a, b: T): bool {.importjs: "(# === #)".} + else: + template sameAddress(a, b): bool = a.unsafeAddr == b.unsafeAddr proc byLent[T](a: T): lent T = a let a = [11,12] let b = @[21,23] let ss = {1, 2, 3, 5} doAssert byLent(a) == [11,12] - doAssert byLent(a).addr == a.addr + doAssert sameAddress(byLent(a), a) doAssert byLent(b) == @[21,23] - when not defined(js): # pending bug #16073 - doAssert byLent(b).addr == b.addr + # pending bug #16073 + doAssert sameAddress(byLent(b), b) doAssert byLent(ss) == {1, 2, 3, 5} - doAssert byLent(ss).addr == ss.addr + doAssert sameAddress(byLent(ss), ss) let r = new(float) r[] = 10.0 - when not defined(js): # pending bug #16073 - doAssert byLent(r)[] == 10.0 + # bug #16073 + doAssert byLent(r)[] == 10.0 when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372 let p = create(float) @@ -41,9 +45,9 @@ template main2 = # bug #15958 proc byLent2[T](a: openArray[T]): lent T = a[0] doAssert byLent2(a) == 11 - doAssert byLent2(a).addr == a[0].addr + doAssert sameAddress(byLent2(a), a[0]) doAssert byLent2(b) == 21 - doAssert byLent2(b).addr == b[0].addr + doAssert sameAddress(byLent2(b), b[0]) proc byLent3[T](a: varargs[T]): lent T = a[1] let From bc3bee54698b108977766b6b2daf8a33bd00d1ef Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 17 Jan 2022 20:06:31 +0800 Subject: [PATCH 3256/4254] Added `std/oserrors` for OS error reporting (#19390) * Added 'std/oserrors' for OS error reporting * add a simple test * New code should not support -d:useWinAnsi anymore thanks to @Araq --- changelog.md | 2 + lib/std/oserrors.nim | 118 +++++++++++++++++++++++++++++++++++++ tests/stdlib/toserrors.nim | 9 +++ 3 files changed, 129 insertions(+) create mode 100644 lib/std/oserrors.nim create mode 100644 tests/stdlib/toserrors.nim diff --git a/changelog.md b/changelog.md index 16b526f85..82f9daa1e 100644 --- a/changelog.md +++ b/changelog.md @@ -74,6 +74,8 @@ becomes an alias for `addr`. for the right-hand side of type definitions in type sections. Previously they would error with "invalid indentation". +- Added `std/oserrors` for OS error reporting. + ## Compiler changes - `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, diff --git a/lib/std/oserrors.nim b/lib/std/oserrors.nim new file mode 100644 index 000000000..9c2649eab --- /dev/null +++ b/lib/std/oserrors.nim @@ -0,0 +1,118 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2022 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +## The `std/oserrors` module implements OS error reporting. + +type + OSErrorCode* = distinct int32 ## Specifies an OS Error Code. + +when not defined(nimscript): + when defined(windows): + import winlean + else: + var errno {.importc, header: "".}: cint + + proc c_strerror(errnum: cint): cstring {. + importc: "strerror", header: "".} + +proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} +proc `$`*(err: OSErrorCode): string {.borrow.} + +proc osErrorMsg*(errorCode: OSErrorCode): string = + ## Converts an OS error code into a human readable string. + ## + ## The error code can be retrieved using the `osLastError proc`_. + ## + ## If conversion fails, or `errorCode` is `0` then `""` will be + ## returned. + ## + ## See also: + ## * `raiseOSError proc`_ + ## * `osLastError proc`_ + runnableExamples: + when defined(linux): + assert osErrorMsg(OSErrorCode(0)) == "" + assert osErrorMsg(OSErrorCode(1)) == "Operation not permitted" + assert osErrorMsg(OSErrorCode(2)) == "No such file or directory" + + result = "" + when defined(nimscript): + discard + elif defined(windows): + if errorCode != OSErrorCode(0'i32): + var msgbuf: WideCString + if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, + nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32: + result = $msgbuf + if msgbuf != nil: localFree(cast[pointer](msgbuf)) + else: + if errorCode != OSErrorCode(0'i32): + result = $c_strerror(errorCode.int32) + +proc newOSError*( + errorCode: OSErrorCode, additionalInfo = "" +): owned(ref OSError) {.noinline.} = + ## Creates a new `OSError exception `_. + ## + ## The `errorCode` will determine the + ## message, `osErrorMsg proc`_ will be used + ## to get this message. + ## + ## The error code can be retrieved using the `osLastError proc`_. + ## + ## If the error code is `0` or an error message could not be retrieved, + ## the message `unknown OS error` will be used. + ## + ## See also: + ## * `osErrorMsg proc`_ + ## * `osLastError proc`_ + var e: owned(ref OSError); new(e) + e.errorCode = errorCode.int32 + e.msg = osErrorMsg(errorCode) + if additionalInfo.len > 0: + if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n' + e.msg.add "Additional info: " + e.msg.add additionalInfo + # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs. + if e.msg == "": + e.msg = "unknown OS error" + return e + +proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} = + ## Raises an `OSError exception `_. + ## + ## Read the description of the `newOSError proc`_ to learn + ## how the exception object is created. + raise newOSError(errorCode, additionalInfo) + +{.push stackTrace:off.} +proc osLastError*(): OSErrorCode {.sideEffect.} = + ## Retrieves the last operating system error code. + ## + ## This procedure is useful in the event when an OS call fails. In that case + ## this procedure will return the error code describing the reason why the + ## OS call failed. The `OSErrorMsg` procedure can then be used to convert + ## this code into a string. + ## + ## .. warning:: The behaviour of this procedure varies between Windows and POSIX systems. + ## On Windows some OS calls can reset the error code to `0` causing this + ## procedure to return `0`. It is therefore advised to call this procedure + ## immediately after an OS call fails. On POSIX systems this is not a problem. + ## + ## See also: + ## * `osErrorMsg proc`_ + ## * `raiseOSError proc`_ + when defined(nimscript): + discard + elif defined(windows): + result = cast[OSErrorCode](getLastError()) + else: + result = OSErrorCode(errno) +{.pop.} diff --git a/tests/stdlib/toserrors.nim b/tests/stdlib/toserrors.nim new file mode 100644 index 000000000..e907dfe63 --- /dev/null +++ b/tests/stdlib/toserrors.nim @@ -0,0 +1,9 @@ +discard """ + action: compile +""" + +import std/oserrors + +let x1 = osLastError() +raiseOSError(x1) +echo osErrorMsg(x1) From 5d303762f156a276cb37162229e6b82b01e08253 Mon Sep 17 00:00:00 2001 From: Hamid Bluri Date: Tue, 18 Jan 2022 12:55:39 -0800 Subject: [PATCH 3257/4254] update deprecated example (#19415) `toNimIdent` proc is deprecated, so I replaced it with `ident` proc --- lib/core/macros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index ed7e85c64..8ab893d21 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1373,7 +1373,7 @@ template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} = ## ## .. code-block:: nim ## var res = findChild(n, it.kind == nnkPostfix and - ## it.basename.ident == toNimIdent"foo") + ## it.basename.ident == ident"foo") block: var res: NimNode for it in n.children: From d7869a80092354468594f7d5c5dfdd91f564fec7 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 18 Jan 2022 23:58:18 +0300 Subject: [PATCH 3258/4254] Improve Zshell completion (#19354) --- tools/nim.zsh-completion | 258 +++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 144 deletions(-) diff --git a/tools/nim.zsh-completion b/tools/nim.zsh-completion index 45477d860..1c3670fd9 100644 --- a/tools/nim.zsh-completion +++ b/tools/nim.zsh-completion @@ -1,150 +1,120 @@ #compdef nim +# Installation note: +# Please name this file as _nim (with underscore!) and copy it to a +# completions directory, either: +# - system wide one, like /usr/share/zsh/functions/Completion/Unix/ on Linux +# - or to a user directory like ~/scripts. Then you also need to add +# that directory in your ~/.zshrc to `fpath` array like so: +# fpath=( ~/scripts "${fpath[@]}" ) + _nim() { - _arguments -C \ - ':command:(( - {compile,c}\:compile\ project\ with\ default\ code\ generator\ C - doc\:generate\ the\ documentation\ for\ inputfile - {compileToC,cc}\:compile\ project\ with\ C\ code\ generator - {compileToCpp,cpp}\:compile\ project\ to\ C++\ code - {compileToOC,objc}\:compile\ project\ to\ Objective\ C\ code - js\:compile\ project\ to\ Javascript - e\:run\ a\ Nimscript\ file - rst2html\:convert\ a\ reStructuredText\ file\ to\ HTML - rst2tex\:convert\ a\ reStructuredText\ file\ to\ TeX - jsondoc\:extract\ the\ documentation\ to\ a\ json\ file - buildIndex\:build\ an\ index\ for\ the\ whole\ documentation - genDepend\:generate\ a\ DOT\ file\ containing\ the\ module\ dependency\ graph - dump\:dump\ all\ defined\ conditionals\ and\ search\ paths - check\:checks\ the\ project\ for\ syntax\ and\ semantic - ))' \ - '*-r[run the application]' \ - '*--run[run the application]' \ - '*-p=[add path to search paths]' \ - '*--path=[add path to search paths]' \ - '*-d=[define a conditional symbol]' \ - '*--define=[define a conditional symbol]' \ - '*-u=[undefine a conditional symbol]' \ - '*--undef=[undefine a conditional symbol]' \ - '*-f[force rebuilding of all modules]' \ - '*--forceBuild[force rebuilding of all modules]' \ - '*--stackTrace=on[turn stack tracing on]' \ - '*--stackTrace=off[turn stack tracing off]' \ - '*--lineTrace=on[turn line tracing on]' \ - '*--lineTrace=off[turn line tracing off]' \ - '*--threads=on[turn support for multi-threading on]' \ - '*--threads=off[turn support for multi-threading off]' \ - '*-x=on[turn all runtime checks on]' \ - '*-x=off[turn all runtime checks off]' \ - '*--checks=on[turn all runtime checks on]' \ - '*--checks=off[turn all runtime checks off]' \ - '*--objChecks=on[turn obj conversion checks on]' \ - '*--objChecks=off[turn obj conversion checks off]' \ - '*--fieldChecks=on[turn case variant field checks on]' \ - '*--fieldChecks=off[turn case variant field checks off]' \ - '*--rangeChecks=on[turn range checks on]' \ - '*--rangeChecks=off[turn range checks off]' \ - '*--boundChecks=on[turn bound checks on]' \ - '*--boundChecks=off[turn bound checks off]' \ - '*--overflowChecks=on[turn int over-/underflow checks on]' \ - '*--overflowChecks=off[turn int over-/underflow checks off]' \ - '*-a[turn assertions on]' \ - '*-a[turn assertions off]' \ - '*--assertions=on[turn assertions on]' \ - '*--assertions=off[turn assertions off]' \ - '*--floatChecks=on[turn all floating point (NaN/Inf) checks on]' \ - '*--floatChecks=off[turn all floating point (NaN/Inf) checks off]' \ - '*--nanChecks=on[turn NaN checks on]' \ - '*--nanChecks=off[turn NaN checks off]' \ - '*--infChecks=on[turn Inf checks on]' \ - '*--infChecks=off[turn Inf checks off]' \ - '*--nilChecks=on[turn nil checks on]' \ - '*--nilChecks=off[turn nil checks off]' \ - '*--opt=none[do not optimize]' \ - '*--opt=speed[optimize for speed|size - use -d:release for a release build]' \ - '*--opt=size[optimize for size]' \ - '*--debugger:native[use native debugger (gdb)]' \ - '*--app=console[generate a console app]' \ - '*--app=gui[generate a GUI app]' \ - '*--app=lib[generate a dynamic library]' \ - '*--app=staticlib[generate a static library]' \ - '*--cpu=alpha[compile for Alpha architecture]' \ - '*--cpu=amd64[compile for x86_64 architecture]' \ - '*--cpu=arm[compile for ARM architecture]' \ - '*--cpu=arm64[compile for ARM64 architecture]' \ - '*--cpu=avr[compile for AVR architecture]' \ - '*--cpu=esp[compile for ESP architecture]' \ - '*--cpu=e2k[compile for Elbrus 2000 architecture]' \ - '*--cpu=hppa[compile for HPPA architecture]' \ - '*--cpu=i386[compile for i386 architecture]' \ - '*--cpu=ia64[compile for ia64 architecture]' \ - '*--cpu=js[compile to JavaScript]' \ - '*--cpu=m68k[compile for m68k architecture]' \ - '*--cpu=mips[compile for MIPS architecture]' \ - '*--cpu=mipsel[compile for MIPS EL architecture]' \ - '*--cpu=mips64[compile for MIPS64 architecture]' \ - '*--cpu=mips64el[compile for MIPS64 EL architecture]' \ - '*--cpu=msp430[compile for msp430 architecture]' \ - '*--cpu=nimvm[compile for Nim VM]' \ - '*--cpu=powerpc[compile for PowerPC architecture]' \ - '*--cpu=powerpc64[compile for PowerPC64 architecture]' \ - '*--cpu=powerpc64el[compile for PowerPC64 EL architecture]' \ - '*--cpu=riscv32[compile for RISC-V 32 architecture]' \ - '*--cpu=riscv64[compile for RISC-V 64 architecture]' \ - '*--cpu=sparc[compile for SPARC architecture]' \ - '*--cpu=sparc64[compile for SPARC64 architecture]' \ - '*--cpu=vm[compile for Nim VM]' \ - '*--cpu=wasm32[compile to WASM 32]' \ - '*--cpu=loongarch64[compile for LoongArch64 architecture]' \ - '*--gc=refc[use reference counting garbage collection]' \ - '*--gc=arc[use ARC garbage collection]' \ - '*--gc=orc[use ORC garbage collection]' \ - '*--gc=markAndSweep[use mark-and-sweep garbage collection]' \ - '*--gc=boehm[use Boehm garbage collection]' \ - '*--gc=go[use Go garbage collection]' \ - '*--gc=regions[use region-based memory management]' \ - '*--gc=none[disable garbage collection]' \ - '*--os=Standalone[generate a stand-alone executable]' \ - '*--os=AIX[compile for AIX]' \ - '*--os=Amiga[compile for Amiga OS]' \ - '*--os=Android[compile for Android]' \ - '*--os=Any[compile for any OS]' \ - '*--os=Atari[compile for Atari]' \ - '*--os=DOS[compile for DOS]' \ - '*--os=DragonFly[compile for DragonFly]' \ - '*--os=FreeBSD[compile for FreeBSD]' \ - '*--os=FreeRTOS[compile for FreeRTOS]' \ - '*--os=Genode[compile for Genode]' \ - '*--os=Haiku[compile for Haiku]' \ - '*--os=iOS[compile for iOS]' \ - '*--os=Irix[compile for Irix]' \ - '*--os=Linux[compile for Linux]' \ - '*--os=MacOS[compile for MacOS]' \ - '*--os=MacOSX[compile for MacOSX]' \ - '*--os=MorphOS[compile for MorphOS]' \ - '*--os=NetBSD[compile for NetBSD]' \ - '*--os=Netware[compile for Netware]' \ - '*--os=NimVM[compile for NimVM]' \ - '*--os=NintendoSwitch[compile for NintendoSwitch]' \ - '*--os=OS2[compile for OS2]' \ - '*--os=OpenBSD[compile for OpenBSD]' \ - '*--os=PalmOS[compile for PalmOS]' \ - '*--os=QNX[compile for QNX]' \ - '*--os=SkyOS[compile for SkyOS]' \ - '*--os=Solaris[compile for Solaris]' \ - '*--os=VxWorks[compile for VxWorks]' \ - '*--os=Windows[compile for Windows]' \ - '*--os=JS[generate javascript]' \ - '*--panics=off[turn panics into process terminations: off by default]' \ - '*--panics=on[turn panics into process terminations]' \ - '*--verbosity=0[set verbosity to 0]' \ - '*--verbosity=1[set verbosity to 1 (default)]' \ - '*--verbosity=2[set verbosity to 2]' \ - '*--verbosity=3[set verbosity to 3]' \ - '*--hints=on[print compilation hints]' \ - '*--hints=off[disable compilation hints]' \ - '*--hints=list[print compilation hints list]' \ - ':filename:_files -g"*.nim"' + local -a nimCommands=( + {compile,c}:'compile project with default code generator C' + {compileToC,cc}:'compile project with C code generator' + {compileToCpp,cpp}:'compile project to C++ code' + {compileToOC,objc}:'compile project to Objective C code' + 'js:compile project to Javascript' + 'e:run a Nimscript file' + 'doc:generate the HTML documentation for inputfile' + 'rst2html:convert a reStructuredText file to HTML' + 'doc2tex:generate the documentation for inputfile to LaTeX' + 'rst2tex:convert a reStructuredText file to TeX' + 'jsondoc:extract the documentation to a json file' + 'buildIndex:build an index for the whole documentation' + 'genDepend:generate a DOT file containing the module dependency graph' + 'dump:dump all defined conditionals and search paths' + 'check:checks the project for syntax and semantic' + {--help,-h}:'basic help' + '--fullhelp:show all switches' + {-v,--version}:'show version' + ) + + _arguments '*:: :->anyState' && return 0 + + if (( CURRENT == 1 )); then + _describe -t commands "Nim commands" nimCommands -V1 + return + fi + + local -a conditionalSymbols=( + release danger mingw androidNDK useNimRtl useMalloc noSignalHandler ssl + debug leanCompiler gcDestructors) + local -a sharedOpts=( + {--define\\:-,-d\\:-}'[define a conditional symbol]:x:($conditionalSymbols)' + {--undef\\:-,-u\\:-}'[undefine a conditional symbol]:x:($conditionalSymbols)' + {--path\\:-,-p\\:-}'[add path to search paths]:x:_files' + '--verbosity\:-[set verbosity level (default\: 1)]:x:(0 1 2 3)' + '--hints\:-[print compilation hints? (or `list`)]:x:(on off list)' + ) + local runOpts=( + {--run,-r}'[run the application]' + ) + local docOpts=( + '--index\:-[enable index .idx files?]:x:(on off)' + '--project\:-[output any dependency for doc?]:x:(on off)' + '--docInternal\:-[generate module-private documentation?]:x:(on off)' + ) + local -a codeOpts=( + {--forceBuild,-f}'[force rebuilding of all modules]' + '--stackTrace\:-[enable stack tracing?]:x:(on off)' + '--lineTrace\:-[enable line tracing?]:x:(on off)' + '--threads\:-[enable support for multi-threading?]:x:(on off)' + {--checks\\:-,-x\\:-}'[enable/disable all runtime checks?]:x:(on off)' + '--objChecks\:-[enable obj conversion checks]:x:(on off)' + '--fieldChecks\:-[enable case variant field checks?]:x:(on off)' + '--rangeChecks\:-[enable range checks?]:x:(on off)' + '--boundChecks\:-[enable bound checks?]:x:(on off)' + '--overflowChecks\:-[enable integer over-/underflow checks?]:x:(on off)' + {--assertions\\:-,-a\\:-}'[enable assertions?]:x:(on off)' + '--floatChecks\:-[enable floating point (NaN/Inf) checks?]:x:(on off)' + '--nanChecks\:-[enable NaN checks?]:x:(on off)' + '--infChecks\:-[enable Inf checks?]:x:(on off)' + '--nilChecks\:-[enable nil checks?]:x:(on off)' + '--expandArc\:-[show how given proc looks before final backend pass]' + '--expandMacro\:-[dump every generated AST from given macro]' + ) + local -a nativeOpts=( + '--opt\:-[optimization mode]:x:(none speed size)' + '--debugger\:native[use native debugger (gdb)]' + '--app\:-[generate this type of app (lib=dynamic)]:x:(console gui lib staticlib)' + '--cpu\:-[target architecture]:x:(alpha amd64 arm arm64 avr e2k esp hppa i386 ia64 js loongarch64 m68k mips mipsel mips64 mips64el msp430 nimvm powerpc powerpc64 powerpc64el riscv32 riscv64 sparc sparc64 vm wasm32)' + '--gc\:-[memory management algorithm to use (default\: refc)]:x:(refc arc orc markAndSweep boehm go regions none)' + '--os\:-[operating system to compile for]:x:(AIX Amiga Android Any Atari DOS DragonFly FreeBSD FreeRTOS Genode Haiku iOS Irix JS Linux MacOS MacOSX MorphOS NetBSD Netware NimVM NintendoSwitch OS2 OpenBSD PalmOS Standalone QNX SkyOS Solaris VxWorks Windows)' + '--panics\:-[turn panics into process termination (default\: off)]:x:(off on)' + ) + + case "$words[1]" in + compile|c|compileToC|cpp|compileToCpp|compileToOC|objc) + _arguments $codeOpts $runOpts $sharedOpts $nativeOpts \ + '*:filename:_files -g"*.nim"' + ;; + js) + _arguments $codeOpts $runOpts $sharedOpts \ + '*:filename:_files -g"*.nim"' + ;; + e) + _arguments $codeOpts $runOpts $sharedOpts \ + '*:filename:_files -g"*.nims"' + ;; + doc|doc2tex|jsondoc) + _arguments $runOpts $sharedOpts '*:filename:_files -g"*.nim"' + ;; + rst2html|rst2tex) + _arguments $runOpts $sharedOpts $docOpts '*:filename:_files -g"*.rst"' + ;; + buildIndex|genDepend|check) + _arguments $sharedOpts '*:filename:_files -g"*.nim"' + ;; + dump) + _arguments $sharedOpts + ;; + *) + _arguments '*:filename:_files -g"*"' + ;; + esac + + return 1 } _nim "$@" From aac54b9c7ffb75c9aab446574171b33bf23a29ed Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 19 Jan 2022 05:02:35 +0800 Subject: [PATCH 3259/4254] fix stricteffects (nimsuggest/sexp) (#19405) * fix stricteffects (nimsuggest/sexp) * Update tstrict_effects3.nim * Update tests/effects/tstrict_effects3.nim --- nimsuggest/sexp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimsuggest/sexp.nim b/nimsuggest/sexp.nim index cee538b6e..31f4988e1 100644 --- a/nimsuggest/sexp.nim +++ b/nimsuggest/sexp.nim @@ -409,7 +409,7 @@ macro convertSexp*(x: untyped): untyped = ## `%` for every element. result = toSexp(x) -proc `==`* (a,b: SexpNode): bool = +proc `==`* (a, b: SexpNode): bool {.noSideEffect.} = ## Check two nodes for equality if a.isNil: if b.isNil: return true From b3c178c2024f679a83275f63ca9e21a8b5ba73d7 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 19 Jan 2022 15:39:22 +0800 Subject: [PATCH 3260/4254] suppress deprecated warnings (#19408) * suppress deprecated warnings once bump version to 1.7.3 enable deprecated messages * deprecate later --- lib/system.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 3b3e28344..02da048e4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -213,8 +213,7 @@ proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## echo p[] # b discard -proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect, - deprecated: "'unsafeAddr' is a deprecated alias for 'addr'".} = +proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory ## location. ## From 23c4bbedcbf12a7ab87baefe589b472837d89dbf Mon Sep 17 00:00:00 2001 From: nblaxall <43897322+nblaxall@users.noreply.github.com> Date: Thu, 20 Jan 2022 00:25:21 +1300 Subject: [PATCH 3261/4254] add an example to setControlCHook (#19416) * add an example to setControlCHook * [skip CI] format example for setControlCHook Co-authored-by: Nathan Blaxall --- lib/system.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index 02da048e4..09de9fcde 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2319,6 +2319,15 @@ when notJSnotNims: proc setControlCHook*(hook: proc () {.noconv.}) ## Allows you to override the behaviour of your application when CTRL+C ## is pressed. Only one such hook is supported. + ## Example: + ## + ## .. code-block:: Nim + ## proc ctrlc() {.noconv.} = + ## echo "Ctrl+C fired!" + ## # do clean up stuff + ## quit() + ## + ## setControlCHook(ctrlc) when not defined(noSignalHandler) and not defined(useNimRtl): proc unsetControlCHook*() From 5d34e81f2363e1de97916ac60b028b9a8b287a4b Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 19 Jan 2022 19:37:30 +0800 Subject: [PATCH 3262/4254] fix term rewriting with sideeffect (#19410) * fix term rewriting with sideeffect fix #6217 * add tests * Update tests/template/template_various.nim --- compiler/parampatterns.nim | 7 +++++-- tests/template/t6217.nim | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/template/t6217.nim diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index eb99004ab..bfbc72675 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -143,8 +143,11 @@ proc checkForSideEffects*(n: PNode): TSideEffectAnalysis = let s = op.sym if sfSideEffect in s.flags: return seSideEffect - # assume no side effect: - result = seNoSideEffect + elif tfNoSideEffect in op.typ.flags: + result = seNoSideEffect + else: + # assume side effect: + result = seSideEffect elif tfNoSideEffect in op.typ.flags: # indirect call without side effects: result = seNoSideEffect diff --git a/tests/template/t6217.nim b/tests/template/t6217.nim new file mode 100644 index 000000000..b27b61881 --- /dev/null +++ b/tests/template/t6217.nim @@ -0,0 +1,19 @@ +discard """ + output: ''' +start +side effect! +end +''' +""" + +# bug #6217 + +template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a + +proc f(): int = + echo "side effect!" + result = 55 + +echo "start" +doAssert f() * 2 == 110 +echo "end" From 08261cb9e33445553144219023900b4ced0b0f55 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Wed, 19 Jan 2022 14:38:14 +0300 Subject: [PATCH 3263/4254] Don't reject types directly on AST (#19407) Instead of rejecting type expressions based on node kind, evaluate the expression as a type. This is already the behavior for call results, and it has its own error for non-types, which is the same error you would normally get with 2 words swapped. --- compiler/semtypes.nim | 6 ++++-- tests/types/tnontype.nim | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/types/tnontype.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d03fa88a8..b4f385fe6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1993,8 +1993,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkStmtListType: result = semStmtListType(c, n, prev) of nkBlockType: result = semBlockType(c, n, prev) else: - localError(c.config, n.info, "type expected, but got: " & renderTree(n)) - result = newOrPrevType(tyError, prev, c) + result = semTypeExpr(c, n, prev) + when false: + localError(c.config, n.info, "type expected, but got: " & renderTree(n)) + result = newOrPrevType(tyError, prev, c) n.typ = result dec c.inTypeContext diff --git a/tests/types/tnontype.nim b/tests/types/tnontype.nim new file mode 100644 index 000000000..4e2bafb32 --- /dev/null +++ b/tests/types/tnontype.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "expected type, but got: 3" +""" + +type + Foo = (block: + int) + + Bar = 3 From ce44cf03cc4a78741c423b2b3963b48b6d9e6755 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 19 Jan 2022 09:41:11 -0700 Subject: [PATCH 3264/4254] Add noQuit option (#19419) [backport:1.6] * Add noQuit option * Add nim prefix in case of conflicts Co-authored-by: flywind Co-authored-by: flywind --- lib/system.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 09de9fcde..63cdc3ca8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1198,8 +1198,8 @@ proc align(address, alignment: int): int = else: result = (address + (alignment - 1)) and not (alignment - 1) -when defined(nimdoc): - proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} +when defined(nimNoQuit): + proc quit*(errorcode: int = QuitSuccess) = discard "ignoring quit" ## Stops the program immediately with an exit code. ## ## Before stopping the program the "exit procedures" are called in the @@ -1223,6 +1223,9 @@ when defined(nimdoc): ## It does *not* call the garbage collector to free all the memory, ## unless an `addExitProc` proc calls `GC_fullCollect <#GC_fullCollect>`_. +elif defined(nimdoc): + proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} + elif defined(genode): include genode/env From 4a38092ac1f8368cb1ebb0245c99c701963662f8 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 20 Jan 2022 20:55:19 +0800 Subject: [PATCH 3265/4254] Added `std/envvars` for env vars handling (#19421) --- changelog.md | 4 +- lib/std/envvars.nim | 212 ++++++++++++++++++++++++++++++++++++++ tests/stdlib/tenvvars.nim | 59 +++++++++++ 3 files changed, 273 insertions(+), 2 deletions(-) create mode 100644 lib/std/envvars.nim create mode 100644 tests/stdlib/tenvvars.nim diff --git a/changelog.md b/changelog.md index 82f9daa1e..bbbaf6e97 100644 --- a/changelog.md +++ b/changelog.md @@ -36,6 +36,8 @@ becomes an alias for `addr`. - Added `getIsoWeekAndYear` in `times` to get an ISO week number along with the corresponding ISO week-based year from a datetime. - Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. +- Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. + ## Language changes - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, @@ -74,8 +76,6 @@ becomes an alias for `addr`. for the right-hand side of type definitions in type sections. Previously they would error with "invalid indentation". -- Added `std/oserrors` for OS error reporting. - ## Compiler changes - `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim new file mode 100644 index 000000000..5b135cbd3 --- /dev/null +++ b/lib/std/envvars.nim @@ -0,0 +1,212 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2022 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +## The `std/envvars` module implements environment variables handling. +import std/oserrors + +type + ReadEnvEffect* = object of ReadIOEffect ## Effect that denotes a read + ## from an environment variable. + WriteEnvEffect* = object of WriteIOEffect ## Effect that denotes a write + ## to an environment variable. + + +when not defined(nimscript): + when defined(nodejs): + proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = + var ret = default.cstring + let key2 = key.cstring + {.emit: "const value = process.env[`key2`];".} + {.emit: "if (value !== undefined) { `ret` = value };".} + result = $ret + + proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + var key2 = key.cstring + var ret: bool + {.emit: "`ret` = `key2` in process.env;".} + result = ret + + proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + var key2 = key.cstring + var val2 = val.cstring + {.emit: "process.env[`key2`] = `val2`;".} + + proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + var key2 = key.cstring + {.emit: "delete process.env[`key2`];".} + + iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = + var num: int + var keys: RootObj + {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".} + for i in 0..".} + when defined(windows): + proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "".} + from std/private/win_setenv import setEnvImpl + import winlean + else: + proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} + proc c_unsetenv(env: cstring): cint {.importc: "unsetenv", header: "".} + + proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = + ## Returns the value of the `environment variable`:idx: named `key`. + ## + ## If the variable does not exist, `""` is returned. To distinguish + ## whether a variable exists or it's value is just `""`, call + ## `existsEnv(key) proc`_. + ## + ## See also: + ## * `existsEnv proc`_ + ## * `putEnv proc`_ + ## * `delEnv proc`_ + ## * `envPairs iterator`_ + runnableExamples: + assert getEnv("unknownEnv") == "" + assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" + + let env = c_getenv(key) + if env == nil: return default + result = $env + + proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = + ## Checks whether the environment variable named `key` exists. + ## Returns true if it exists, false otherwise. + ## + ## See also: + ## * `getEnv proc`_ + ## * `putEnv proc`_ + ## * `delEnv proc`_ + ## * `envPairs iterator`_ + runnableExamples: + assert not existsEnv("unknownEnv") + + return c_getenv(key) != nil + + proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = + ## Sets the value of the `environment variable`:idx: named `key` to `val`. + ## If an error occurs, `OSError` is raised. + ## + ## See also: + ## * `getEnv proc`_ + ## * `existsEnv proc`_ + ## * `delEnv proc`_ + ## * `envPairs iterator`_ + when defined(windows): + if key.len == 0 or '=' in key: + raise newException(OSError, "invalid key, got: " & $(key, val)) + if setEnvImpl(key, val, 1'i32) != 0'i32: + raiseOSError(osLastError(), $(key, val)) + else: + if c_setenv(key, val, 1'i32) != 0'i32: + raiseOSError(osLastError(), $(key, val)) + + proc delEnv*(key: string) {.tags: [WriteEnvEffect].} = + ## Deletes the `environment variable`:idx: named `key`. + ## If an error occurs, `OSError` is raised. + ## + ## See also:ven + ## * `getEnv proc`_ + ## * `existsEnv proc`_ + ## * `putEnv proc`_ + ## * `envPairs iterator`_ + template bail = raiseOSError(osLastError(), key) + when defined(windows): + #[ + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160 + > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string + note that nil is not legal + ]# + if key.len == 0 or '=' in key: + raise newException(OSError, "invalid key, got: " & key) + let envToDel = key & "=" + if c_putenv(cstring envToDel) != 0'i32: bail + else: + if c_unsetenv(key) != 0'i32: bail + + when defined(windows): + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", + header: "".} + else: + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importc: "wcschr", + header: "".} + elif defined(macosx) and not defined(ios) and not defined(emscripten): + # From the manual: + # Shared libraries and bundles don't have direct access to environ, + # which is only available to the loader ld(1) when a complete program + # is being linked. + # The environment routines can still be used, but if direct access to + # environ is needed, the _NSGetEnviron() routine, defined in + # , can be used to retrieve the address of environ + # at runtime. + proc NSGetEnviron(): ptr cstringArray {.importc: "_NSGetEnviron", + header: "".} + elif defined(haiku): + var gEnv {.importc: "environ", header: "".}: cstringArray + else: + var gEnv {.importc: "environ".}: cstringArray + + iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = + when defined(windows): + block: + template impl(get_fun, typ, size, zero, free_fun) = + let env = get_fun() + var e = env + if e == nil: break + while true: + let eend = strEnd(e) + let kv = $e + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) + e = cast[typ](cast[ByteAddress](eend)+size) + if typeof(zero)(eend[1]) == zero: break + discard free_fun(env) + impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW) + else: + var i = 0 + when defined(macosx) and not defined(ios) and not defined(emscripten): + var gEnv = NSGetEnviron()[] + while gEnv[i] != nil: + let kv = $gEnv[i] + inc(i) + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) + +proc envPairsImplSeq(): seq[tuple[key, value: string]] = discard # vmops + +iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = + ## Iterate over all `environments variables`:idx:. + ## + ## In the first component of the tuple is the name of the current variable stored, + ## in the second its value. + ## + ## Works in native backends, nodejs and vm, like the following APIs: + ## * `getEnv proc`_ + ## * `existsEnv proc`_ + ## * `putEnv proc`_ + ## * `delEnv proc`_ + when nimvm: + for ai in envPairsImplSeq(): yield ai + else: + when defined(nimscript): discard + else: + for ai in envPairsImpl(): yield ai diff --git a/tests/stdlib/tenvvars.nim b/tests/stdlib/tenvvars.nim new file mode 100644 index 000000000..406aa3230 --- /dev/null +++ b/tests/stdlib/tenvvars.nim @@ -0,0 +1,59 @@ +discard """ + matrix: "--threads:on" + joinable: false + targets: "c js cpp" +""" + +import std/envvars +from std/sequtils import toSeq +import stdtest/testutils + +template main = + block: # delEnv, existsEnv, getEnv, envPairs + for val in ["val", ""]: # ensures empty val works too + const key = "NIM_TESTS_TOSENV_KEY" + doAssert not existsEnv(key) + + putEnv(key, "tempval") + doAssert existsEnv(key) + doAssert getEnv(key) == "tempval" + + putEnv(key, val) # change a key that already exists + doAssert existsEnv(key) + doAssert getEnv(key) == val + + doAssert (key, val) in toSeq(envPairs()) + delEnv(key) + doAssert (key, val) notin toSeq(envPairs()) + doAssert not existsEnv(key) + delEnv(key) # deleting an already deleted env var + doAssert not existsEnv(key) + + block: + doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == "" + doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " " + doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval" + + whenVMorJs: discard # xxx improve + do: + doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE")) + doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE")) + doAssert not existsEnv("") + doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE") + doAssert not existsEnv("NIM_TESTS_TOSENV_PUT") + +main() + +when not defined(js) and not defined(nimscript): + block: # bug #18533 + proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} + var thr: Thread[void] + proc threadFunc {.thread.} = putEnv("foo", "fooVal2") + + putEnv("foo", "fooVal1") + doAssert getEnv("foo") == "fooVal1" + createThread(thr, threadFunc) + joinThreads(thr) + doAssert getEnv("foo") == $c_getenv("foo") + + doAssertRaises(OSError): delEnv("foo=bar") From 851e515bbae6edf6b28cf6723b2c7a45acce1869 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 20 Jan 2022 04:58:59 -0800 Subject: [PATCH 3266/4254] Resolve cross file resolution errors in atomics (#19422) [backport:1.6] * Resolve call undeclared routine testAndSet * Fix undeclared field atomicType --- lib/pure/concurrency/atomics.nim | 17 +++++++---------- tests/stdlib/concurrency/atomicSample.nim | 9 +++++++++ tests/stdlib/concurrency/tatomic_import.nim | 11 +++++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 tests/stdlib/concurrency/atomicSample.nim create mode 100644 tests/stdlib/concurrency/tatomic_import.nim diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index b252789fb..c0a122bf9 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -293,19 +293,16 @@ else: AtomicInt32 {.importc: "_Atomic NI32".} = int32 AtomicInt64 {.importc: "_Atomic NI64".} = int64 - template atomicType*(T: typedesc[Trivial]): untyped = - # Maps the size of a trivial type to it's internal atomic type - when sizeof(T) == 1: AtomicInt8 - elif sizeof(T) == 2: AtomicInt16 - elif sizeof(T) == 4: AtomicInt32 - elif sizeof(T) == 8: AtomicInt64 - type AtomicFlag* {.importc: "atomic_flag", size: 1.} = object Atomic*[T] = object when T is Trivial: - value: T.atomicType + # Maps the size of a trivial type to it's internal atomic type + when sizeof(T) == 1: value: AtomicInt8 + elif sizeof(T) == 2: value: AtomicInt16 + elif sizeof(T) == 4: value: AtomicInt32 + elif sizeof(T) == 8: value: AtomicInt64 else: nonAtomicValue: T guard: AtomicFlag @@ -364,11 +361,11 @@ else: cast[T](atomic_fetch_xor_explicit(addr(location.value), cast[nonAtomicType(T)](value), order)) template withLock[T: not Trivial](location: var Atomic[T]; order: MemoryOrder; body: untyped): untyped = - while location.guard.testAndSet(moAcquire): discard + while testAndSet(location.guard, moAcquire): discard try: body finally: - location.guard.clear(moRelease) + clear(location.guard, moRelease) proc load*[T: not Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} = withLock(location, order): diff --git a/tests/stdlib/concurrency/atomicSample.nim b/tests/stdlib/concurrency/atomicSample.nim new file mode 100644 index 000000000..d56d867df --- /dev/null +++ b/tests/stdlib/concurrency/atomicSample.nim @@ -0,0 +1,9 @@ +import atomics + +type + AtomicWithGeneric*[T] = object + value: Atomic[T] + +proc initAtomicWithGeneric*[T](value: T): AtomicWithGeneric[T] = + result.value.store(value) + diff --git a/tests/stdlib/concurrency/tatomic_import.nim b/tests/stdlib/concurrency/tatomic_import.nim new file mode 100644 index 000000000..e8faaae20 --- /dev/null +++ b/tests/stdlib/concurrency/tatomic_import.nim @@ -0,0 +1,11 @@ +import atomicSample + +block crossFileObjectContainingAGenericWithAComplexObject: + discard initAtomicWithGeneric[string]("foo") + +block crossFileObjectContainingAGenericWithAnInteger: + discard initAtomicWithGeneric[int](1) + discard initAtomicWithGeneric[int8](1) + discard initAtomicWithGeneric[int16](1) + discard initAtomicWithGeneric[int32](1) + discard initAtomicWithGeneric[int64](1) From 927fa890ec91cf13d7e3aa87267b994c2812bdc8 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 20 Jan 2022 20:59:36 +0800 Subject: [PATCH 3267/4254] enable weave (#19363) [backport:1.6] * enable weave * workaround CI --- compiler/cgen.nim | 9 +++++++-- testament/important_packages.nim | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 032c22ec0..246b8c0e9 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -48,8 +48,13 @@ proc addForwardedProc(m: BModule, prc: PSym) = m.g.forwardedProcs.add(prc) proc findPendingModule(m: BModule, s: PSym): BModule = - let ms = s.itemId.module #getModule(s) - result = m.g.modules[ms] + # TODO fixme + if m.config.symbolFiles == v2Sf: + let ms = s.itemId.module #getModule(s) + result = m.g.modules[ms] + else: + var ms = getModule(s) + result = m.g.modules[ms.position] proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) = result.k = k diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 853a58698..5f6e19b52 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -157,7 +157,7 @@ pkg "tiny_sqlite" pkg "unicodedb", "nim c -d:release -r tests/tests.nim" pkg "unicodeplus", "nim c -d:release -r tests/tests.nim" pkg "unpack" -pkg "weave", "nimble test_gc_arc", allowFailure = true +pkg "weave", "nimble test_gc_arc" pkg "websocket", "nim c websocket.nim" pkg "winim", "nim c winim.nim" pkg "with" From 1563cb2f6e37f07c303d095dabde74955be1e523 Mon Sep 17 00:00:00 2001 From: Regis Caillaud <35006197+Clonkk@users.noreply.github.com> Date: Thu, 20 Jan 2022 20:50:36 +0100 Subject: [PATCH 3268/4254] Fix #11923 (#19427) * Apply commit https://github.com/nim-lang/Nim/commit/5da931fe811717a45f2dd272ea6281979c3e8f0b that was never merged (was part of a bigger PR). Should fix issue #11932 * add a generic object for custom pragma --- lib/core/macros.nim | 7 ++++++- tests/pragmas/tcustom_pragma.nim | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 8ab893d21..28106493f 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1523,7 +1523,12 @@ proc customPragmaNode(n: NimNode): NimNode = if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}: let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1]) let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0]) - var typDef = getImpl(if typInst.kind == nnkVarTy: typInst[0] else: typInst) + var typDef = getImpl( + if typInst.kind == nnkVarTy or + typInst.kind == nnkBracketExpr: + typInst[0] + else: typInst + ) while typDef != nil: typDef.expectKind(nnkTypeDef) let typ = typDef[2] diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index b197a7c55..1c3709b26 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -17,11 +17,21 @@ block: MyObj = object myField1, myField2 {.myAttr: "hi".}: int + MyGenericObj[T] = object + myField1, myField2 {.myAttr: "hi".}: int + + var o: MyObj static: doAssert o.myField2.hasCustomPragma(myAttr) doAssert(not o.myField1.hasCustomPragma(myAttr)) + var ogen: MyGenericObj[int] + static: + doAssert ogen.myField2.hasCustomPragma(myAttr) + doAssert(not ogen.myField1.hasCustomPragma(myAttr)) + + import custom_pragma block: # A bit more advanced case type From 2bd1aa186e09565b2103394bd281478fa1b10ef1 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Thu, 20 Jan 2022 22:57:50 +0300 Subject: [PATCH 3269/4254] New/better macro pragmas, mark some as experimental (#19406) * New/better macro pragmas, make some experimental fix #15920, close #18212, close #14781, close #6696, close https://github.com/nim-lang/RFCs/issues/220 Variable macro pragmas have been changed to only take a unary section node. They can now also be applied in sections with multiple variables, as well as `const` sections. They also accept arguments. Templates now support macro pragmas, mirroring other routine types. Type and variable macro pragmas have been made experimental. Symbols without parentheses instatiating nullary macros or templates has also been documented in the experimental manual. A check for a redefinition error based on the left hand side of variable definitions when using variable macro pragmas was disabled. This nerfs `byaddr` specifically, however this has been documented as a consequence of the experimental features `byaddr` uses. Given how simple these changes are I'm worried if I'm missing something. * accomodate compiler boot * allow weird pragmas * add test for #10994 * remove some control flow, try remove some logic --- compiler/semstmts.nim | 280 +++++++++++++++++++------------- compiler/semtempl.nim | 5 + doc/manual.rst | 28 ++-- doc/manual_experimental.rst | 72 +++++++- lib/std/decls.nim | 39 +++-- tests/pragmas/tpragmas_misc.nim | 24 ++- tests/pragmas/tvar_macro.nim | 128 +++++++++++++++ tests/stdlib/tdecls.nim | 64 ++------ 8 files changed, 435 insertions(+), 205 deletions(-) create mode 100644 tests/pragmas/tvar_macro.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f302dd4c3..33e304ab2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -341,8 +341,12 @@ proc checkNilable(c: PContext; v: PSym) = #include liftdestructors -proc addToVarSection(c: PContext; result: PNode; orig, identDefs: PNode) = - let value = identDefs[^1] +proc addToVarSection(c: PContext; result: var PNode; n: PNode) = + if result.kind != nkStmtList: + result = makeStmtList(result) + result.add n + +proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) = if result.kind == nkStmtList: let o = copyNode(orig) o.add identDefs @@ -445,55 +449,115 @@ proc setVarType(c: PContext; v: PSym, typ: PType) = "; new type is: " & typeToString(typ, preferDesc)) v.typ = typ -proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode = - var b = a[0] - if b.kind == nkPragmaExpr: - if b[1].len != 1: - # we could in future support pragmas w args e.g.: `var foo {.bar:"goo".} = expr` - return nil - let nodePragma = b[1][0] - # see: `singlePragma` +proc isPossibleMacroPragma(c: PContext, it: PNode, key: PNode): bool = + # make sure it's not a normal pragma, and calls an identifier + # considerQuotedIdent below will fail on non-identifiers + result = whichPragma(it) == wInvalid and key.kind in nkIdentKinds + if result: + # make sure it's not a user pragma + let ident = considerQuotedIdent(c, key) + result = strTableGet(c.userPragmas, ident) == nil + if result: + # make sure it's not a custom pragma + var amb = false + let sym = searchInScopes(c, ident, amb) + result = sym == nil or sfCustomPragma notin sym.flags - var amb = false - var sym: PSym = nil - case nodePragma.kind - of nkIdent, nkAccQuoted: - let ident = considerQuotedIdent(c, nodePragma) - var userPragma = strTableGet(c.userPragmas, ident) - if userPragma != nil: return nil - let w = nodePragma.whichPragma - if n.kind == nkVarSection and w in varPragmas or - n.kind == nkLetSection and w in letPragmas or - n.kind == nkConstSection and w in constPragmas: - return nil - sym = searchInScopes(c, ident, amb) - # XXX what if amb is true? - # CHECKME: should that test also apply to `nkSym` case? - if sym == nil or sfCustomPragma in sym.flags: return nil - of nkSym: - sym = nodePragma.sym - else: - return nil - # skip if not in scope; skip `template myAttr() {.pragma.}` +proc copyExcept(n: PNode, i: int): PNode = + result = copyNode(n) + for j in 0..= 1: it[0] else: it + + when false: + let lhs = b[0] + let clash = strTableGet(c.currentScope.symbols, lhs.ident) + if clash != nil: + # refs https://github.com/nim-lang/Nim/issues/8275 + wrongRedefinition(c, lhs.info, lhs.ident.s, clash.info) - result = newTree(nkCall) - result.add nodePragma - result.add lhs - if a[1].kind != nkEmpty: - result.add a[1] - else: - result.add newNodeIT(nkNilLit, a.info, c.graph.sysTypes[tyNil]) - result.add a[2] - result.info = a.info - let ret = newNodeI(nkStmtList, a.info) - ret.add result - result = semExprNoType(c, ret) + if isPossibleMacroPragma(c, it, key): + # we transform ``var p {.m, rest.}`` into ``m(do: var p {.rest.})`` and + # let the semantic checker deal with it: + var x = newNodeI(nkCall, key.info) + x.add(key) + + if it.kind in nkPragmaCallKinds and it.len > 1: + # pass pragma arguments to the macro too: + for i in 1..= 1: it[0] else: it - if whichPragma(it) != wInvalid: - # Not a custom pragma - continue - else: - let ident = considerQuotedIdent(c, key) - if strTableGet(c.userPragmas, ident) != nil: - continue # User defined pragma + if isPossibleMacroPragma(c, it, key): + # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and + # let the semantic checker deal with it: + var x = newNodeI(nkCall, key.info) + x.add(key) + + if it.kind in nkPragmaCallKinds and it.len > 1: + # pass pragma arguments to the macro too: + for i in 1.. 1: - # pass pragma arguments to the macro too: - for i in 1..` instead. Foreign function interface diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 407924a13..3089755cb 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -404,6 +404,76 @@ to use this operator. doAssert (a.b)(c) == `()`(a.b, c) +Extended macro pragmas +====================== + +Macro pragmas as described in `the manual `_ +can also be applied to type, variable and constant declarations. + +For types: + +.. code-block:: nim + type + MyObject {.schema: "schema.protobuf".} = object + +This is translated to a call to the `schema` macro with a `nnkTypeDef` +AST node capturing the left-hand side, remaining pragmas and the right-hand +side of the definition. The macro can return either a type section or +another `nnkTypeDef` node, both of which will replace the original row +in the type section. + +In the future, this `nnkTypeDef` argument may be replaced with a unary +type section node containing the type definition, or some other node that may +be more convenient to work with. The ability to return nodes other than type +definitions may also be supported, however currently this is not convenient +when dealing with mutual type recursion. For now, macros can return an unused +type definition where the right-hand node is of kind `nnkStmtListType`. +Declarations in this node will be attached to the same scope as +the parent scope of the type section. + +------ + +For variables and constants, it is largely the same, except a unary node with +the same kind as the section containing a single definition is passed to macros, +and macros can return any expression. + +.. code-block:: nim + var + a = ... + b {.importc, foo, nodecl.} = ... + c = ... + +Assuming `foo` is a macro or a template, this is roughly equivalent to: + +.. code-block:: nim + var a = ... + foo: + var b {.importc, nodecl.} = ... + var c = ... + + +Symbols as template/macro calls +=============================== + +Templates and macros that take no arguments can be called as lone symbols, +i.e. without parentheses. This is useful for repeated uses of complex +expressions that cannot conveniently be represented as runtime values. + +.. code-block:: nim + type Foo = object + bar: int + + var foo = Foo(bar: 10) + template bar: untyped = foo.bar + assert bar == 10 + bar = 15 + assert bar == 15 + +In the future, this may require more specific information on template or macro +signatures to be used. Specializations for some applications of this may also +be introduced to guarantee consistency and circumvent bugs. + + Not nil annotation ================== @@ -613,7 +683,7 @@ has `source` as the owner. A path expression `e` is defined recursively: If a view type is used as a return type, the location must borrow from a location that is derived from the first parameter that is passed to the proc. -See `the manual `_ +See `the manual `_ for details about how this is done for `var T`. A mutable view can borrow from a mutable location, an immutable view can borrow diff --git a/lib/std/decls.nim b/lib/std/decls.nim index dd7d19da7..7b907f5e1 100644 --- a/lib/std/decls.nim +++ b/lib/std/decls.nim @@ -1,19 +1,32 @@ # see `semLowerLetVarCustomPragma` for compiler support that enables these # lowerings -template byaddr*(lhs, typ, ex) = - ## Allows a syntax for lvalue reference, exact analog to - ## `auto& a = ex;` in C++ +import macros + +macro byaddr*(sect) = + ## Allows a syntax for l-value references, being an exact analog to + ## `auto& a = ex;` in C++. + ## + ## Warning: This makes use of 2 experimental features, namely nullary + ## templates instantiated as symbols and variable macro pragmas. + ## For this reason, its behavior is not stable. The current implementation + ## allows redefinition, but this is not an intended consequence. runnableExamples: - var s = @[10,11,12] + var s = @[10, 11, 12] var a {.byaddr.} = s[0] - a+=100 - doAssert s == @[110,11,12] - doAssert a is int + a += 100 + assert s == @[110, 11, 12] + assert a is int var b {.byaddr.}: int = s[0] - doAssert a.addr == b.addr - when typ is typeof(nil): - let tmp = addr(ex) - else: - let tmp: ptr typ = addr(ex) - template lhs: untyped = tmp[] + assert a.addr == b.addr + expectLen sect, 1 + let def = sect[0] + let + lhs = def[0] + typ = def[1] + ex = def[2] + addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ) + result = quote do: + let tmp: `addrTyp` = addr(`ex`) + template `lhs`: untyped = tmp[] + result.copyLineInfo(def) diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim index 8cab74053..6dc2e6b80 100644 --- a/tests/pragmas/tpragmas_misc.nim +++ b/tests/pragmas/tpragmas_misc.nim @@ -13,8 +13,8 @@ block: block: # (partial fix) bug #15920 block: # var template pragmas don't work in templates - template foo(lhs, typ, expr) = - let lhs = expr + template foo(expr) = + expr proc fun1()= let a {.foo.} = 1 template fun2()= @@ -24,23 +24,22 @@ block: # (partial fix) bug #15920 template foo2() = discard # distractor (template or other symbol kind) block: - template foo2(lhs, typ, expr) = - let lhs = expr + template foo2(expr) = + expr proc fun1()= let a {.foo2.} = 1 template fun2()= let a {.foo2.} = 1 fun1() # ok - when false: # bug: Error: invalid pragma: foo2 - fun2() + fun2() # bug: Error: invalid pragma: foo2 - block: # proc template pragmas don't work in templates + block: # template pragmas don't work for templates, #18212 # adapted from $nim/lib/std/private/since.nim # case without overload template since3(version: (int, int), body: untyped) {.dirty.} = when (NimMajor, NimMinor) >= version: body - when false: # bug + when true: # bug template fun3(): int {.since3: (1, 3).} = 12 block: # ditto, w @@ -51,7 +50,7 @@ block: # (partial fix) bug #15920 template since2(version: (int, int, int), body: untyped) {.dirty.} = when (NimMajor, NimMinor, NimPatch) >= version: body - when false: # bug + when true: # bug template fun3(): int {.since2: (1, 3).} = 12 when true: # D20210801T100514:here @@ -62,3 +61,10 @@ when true: # D20210801T100514:here discard ret fn() static: discard genSym() + +block: # issue #10994 + macro foo(x): untyped = x + template bar {.pragma.} + + proc a {.bar.} = discard # works + proc b {.bar, foo.} = discard # doesn't diff --git a/tests/pragmas/tvar_macro.nim b/tests/pragmas/tvar_macro.nim new file mode 100644 index 000000000..d6a4ff983 --- /dev/null +++ b/tests/pragmas/tvar_macro.nim @@ -0,0 +1,128 @@ +import macros + +block: # test usage + macro modify(sec) = + result = copy sec + result[0][0] = ident(repr(result[0][0]) & "Modified") + + block: + let foo {.modify.} = 3 + doAssert fooModified == 3 + + block: # in section + let + a = 1 + b {.modify.} = 2 + c = 3 + doAssert (a, bModified, c) == (1, 2, 3) + +block: # with single argument + macro appendToName(name: static string, sec) = + result = sec + result[0][0] = ident(repr(result[0][0]) & name) + + block: + let foo {.appendToName: "Bar".} = 3 + doAssert fooBar == 3 + + block: + let + a = 1 + b {.appendToName("").} = 2 + c = 3 + doAssert (a, b, c) == (1, 2, 3) + +macro appendToNameAndAdd(name: static string, incr: static int, sec) = + result = sec + result[0][0] = ident(repr(result[0][0]) & name) + result[0][2] = infix(result[0][2], "+", newLit(incr)) + +block: # with multiple arguments + block: + let foo {.appendToNameAndAdd("Bar", 5).} = 3 + doAssert fooBar == 8 + + block: + let + a = 1 + b {.appendToNameAndAdd("", 15).} = 2 + c = 3 + doAssert (a, b, c) == (1, 17, 3) + +block: # in other kinds of sections + block: + const + a = 1 + b {.appendToNameAndAdd("", 15).} = 2 + c = 3 + doAssert (a, b, c) == (1, 17, 3) + doAssert static(b) == b + + block: + var + a = 1 + b {.appendToNameAndAdd("", 15).} = 2 + c = 3 + doAssert (a, b, c) == (1, 17, 3) + b += a + c += b + doAssert (a, b, c) == (1, 18, 21) + +block: # with other pragmas + macro appendToNameAndAdd(name: static string, incr, sec) = + result = sec + result[0][0][0] = ident(repr(result[0][0][0]) & name) + result[0][0][1].add(ident"deprecated") + result[0][2] = infix(result[0][2], "+", incr) + + var + a = 1 + foo {.exportc: "exportedFooBar", appendToNameAndAdd("Bar", {'0'..'9'}), used.} = {'a'..'z', 'A'..'Z'} + b = 2 + + doAssert (a, b) == (1, 2) + + let importedFooBar {.importc: "exportedFooBar", nodecl.}: set[char] + + doAssert importedFooBar == fooBar #[tt.Warning + ^ fooBar is deprecated + ]# + + +block: # with stropping + macro `cast`(def) = + let def = def[0] + let + lhs = def[0] + typ = def[1] + ex = def[2] + addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ) + result = quote do: + let tmp: `addrTyp` = unsafeAddr(`ex`) + template `lhs`: untyped = tmp[] + + macro assign(def) = + result = getAst(`cast`(def)) + + block: + let s = @["foo", "bar"] + let a {.`assign`.} = s[0] + doAssert a == "foo" + doAssert a[0].addr == s[0][0].addr + + block: + let + s = @["foo", "bar"] + a {.`cast`.} = s[0] + doAssert a == "foo" + doAssert a[0].addr == s[0][0].addr + +block: # bug #15920 + macro foo(def) = + result = def + proc fun1()= + let a {.foo.} = 1 + template fun2()= + let a {.foo.} = 1 + fun1() # ok + fun2() # BUG diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim index c0d6f8a08..4e7407045 100644 --- a/tests/stdlib/tdecls.nim +++ b/tests/stdlib/tdecls.nim @@ -13,15 +13,18 @@ template fun() = var b {.byaddr.}: int = s[0] doAssert a.addr == b.addr - doAssert not compiles(block: - # redeclaration not allowed - var foo = 0 - var foo {.byaddr.} = s[0]) + when false: + # template specific redeclaration issue + # see https://github.com/nim-lang/Nim/issues/8275 + doAssert not compiles(block: + # redeclaration not allowed + var foo = 0 + var foo {.byaddr.} = s[0]) - doAssert not compiles(block: - # ditto - var foo {.byaddr.} = s[0] - var foo {.byaddr.} = s[0]) + doAssert not compiles(block: + # ditto + var foo {.byaddr.} = s[0] + var foo {.byaddr.} = s[0]) block: var b {.byaddr.} = s[1] # redeclaration ok in sub scope @@ -44,48 +47,3 @@ fun2() static: fun2() when false: # pending bug #13887 static: fun() - -## We can define custom pragmas in user code -template byUnsafeAddr(lhs, typ, expr) = - when typ is type(nil): - let tmp = addr(expr) - else: - let tmp: ptr typ = addr(expr) - template lhs: untyped = tmp[] - -block: - let s = @["foo", "bar"] - let a {.byUnsafeAddr.} = s[0] - doAssert a == "foo" - doAssert a[0].addr == s[0][0].addr - -block: # nkAccQuoted - # shows using a keyword, which requires nkAccQuoted - template `cast`(lhs, typ, expr) = - when typ is type(nil): - let tmp = addr(expr) - else: - let tmp: ptr typ = addr(expr) - template lhs: untyped = tmp[] - - block: - let s = @["foo", "bar"] - let a {.`byUnsafeAddr`.} = s[0] - doAssert a == "foo" - doAssert a[0].addr == s[0][0].addr - - block: - let s = @["foo", "bar"] - let a {.`cast`.} = s[0] - doAssert a == "foo" - doAssert a[0].addr == s[0][0].addr - -block: # bug #15920 - template foo(lhs, typ, expr) = - let lhs = expr - proc fun1()= - let a {.foo.} = 1 - template fun2()= - let a {.foo.} = 1 - fun1() # ok - fun2() # BUG From 15f54de5c4ee2f70e1304201ebc8c8634b731c9a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 22 Jan 2022 20:33:55 +0100 Subject: [PATCH 3270/4254] RST: allow empty number-lines directives just like it was done for a decade; all my documents rely on this feature [backport (#19431) --- lib/packages/docutils/rstgen.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 9018087f7..d2180cb91 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -931,7 +931,8 @@ proc getField1Int(d: PDoc, n: PRstNode, fieldName: string): int = let nChars = parseInt(value, number) if nChars == 0: if value.len == 0: - err("field $1 requires an argument" % [fieldName]) + # use a good default value: + result = 1 else: err("field $1 requires an integer, but '$2' was given" % [fieldName, value]) From f7c4fb0014f320824d8f05e2e4d9776c09f51711 Mon Sep 17 00:00:00 2001 From: ehmry Date: Mon, 24 Jan 2022 20:57:37 +0100 Subject: [PATCH 3271/4254] os: faster getFileSize (#19438) Use "stat" rather than "open", "seek", and "close" system calls. The Windows implementation remains the same. --- lib/pure/os.nim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 81b432d7f..07040d611 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -3216,11 +3216,10 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", result = rdFileSize(a) findClose(resA) else: - var f: File - if open(f, file): - result = getFileSize(f) - close(f) - else: raiseOSError(osLastError(), file) + var rawInfo: Stat + if stat(file, rawInfo) < 0'i32: + raiseOSError(osLastError(), file) + rawInfo.st_size when defined(windows) or weirdTarget: type From 6ea622552345fc9a6c451615079d2a0ebbc6c4ca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 25 Jan 2022 08:08:22 +0100 Subject: [PATCH 3272/4254] bugfix: varargs count as open arrays (#19447) --- compiler/typeallowed.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 78cd74e56..3d6ea0edb 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -233,7 +233,7 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind = case t.kind of tyVar: result = mutableView - of tyLent, tyOpenArray: + of tyLent, tyOpenArray, tyVarargs: result = immutableView of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned, tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic: From 4b723c0f5350c5bfb9722dace7a40c66a4630a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Tue, 25 Jan 2022 10:31:24 +0100 Subject: [PATCH 3273/4254] change run command for numericalnim (#19448) Now it makes runs the custom `nimCI` task that installs the external dependencies --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 5f6e19b52..40a3aef36 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -117,7 +117,7 @@ pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" pkg "norm", "testament r tests/sqlite/trows.nim" pkg "npeg", "nimble testarc" -pkg "numericalnim", "nim c -r tests/test_integrate.nim" +pkg "numericalnim", "nimble nimCI" pkg "optionsutils" pkg "ormin", "nim c -o:orminn ormin.nim" pkg "parsetoml" From 6319b00ef7f93fa8d7d44c981f850262d8e0ed6a Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 27 Jan 2022 22:23:34 +0800 Subject: [PATCH 3274/4254] support set other GCs after `mm = orc` or `mm = arc` is set in the global config (#19455) * support set other GCs after arc/orc in global config fix #15535 * set before --- compiler/commands.nim | 54 +++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 8e79a4477..a1fa55e74 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -497,6 +497,32 @@ proc specialDefine(conf: ConfigRef, key: string; pass: TCmdLinePass) = optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir} conf.globalOptions.excl {optCDebug} +proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) = + if isOrc: + conf.selectedGC = gcOrc + defineSymbol(conf.symbols, "gcorc") + else: + conf.selectedGC = gcArc + defineSymbol(conf.symbols, "gcarc") + + defineSymbol(conf.symbols, "gcdestructors") + incl conf.globalOptions, optSeqDestructors + incl conf.globalOptions, optTinyRtti + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimV2") + if conf.exc == excNone and conf.backend != backendCpp: + conf.exc = excGoto + +proc unregisterArcOrc(conf: ConfigRef) = + undefSymbol(conf.symbols, "gcdestructors") + undefSymbol(conf.symbols, "gcarc") + undefSymbol(conf.symbols, "gcorc") + undefSymbol(conf.symbols, "nimSeqsV2") + undefSymbol(conf.symbols, "nimV2") + excl conf.globalOptions, optSeqDestructors + excl conf.globalOptions, optTinyRtti + proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = var @@ -602,36 +628,21 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: case arg.normalize of "boehm": + unregisterArcOrc(conf) conf.selectedGC = gcBoehm defineSymbol(conf.symbols, "boehmgc") incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS of "refc": + unregisterArcOrc(conf) conf.selectedGC = gcRefc of "markandsweep": + unregisterArcOrc(conf) conf.selectedGC = gcMarkAndSweep defineSymbol(conf.symbols, "gcmarkandsweep") of "destructors", "arc": - conf.selectedGC = gcArc - defineSymbol(conf.symbols, "gcdestructors") - defineSymbol(conf.symbols, "gcarc") - incl conf.globalOptions, optSeqDestructors - incl conf.globalOptions, optTinyRtti - if pass in {passCmd2, passPP}: - defineSymbol(conf.symbols, "nimSeqsV2") - defineSymbol(conf.symbols, "nimV2") - if conf.exc == excNone and conf.backend != backendCpp: - conf.exc = excGoto + registerArcOrc(pass, conf, false) of "orc": - conf.selectedGC = gcOrc - defineSymbol(conf.symbols, "gcdestructors") - defineSymbol(conf.symbols, "gcorc") - incl conf.globalOptions, optSeqDestructors - incl conf.globalOptions, optTinyRtti - if pass in {passCmd2, passPP}: - defineSymbol(conf.symbols, "nimSeqsV2") - defineSymbol(conf.symbols, "nimV2") - if conf.exc == excNone and conf.backend != backendCpp: - conf.exc = excGoto + registerArcOrc(pass, conf, true) of "hooks": conf.selectedGC = gcHooks defineSymbol(conf.symbols, "gchooks") @@ -640,12 +651,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: defineSymbol(conf.symbols, "nimSeqsV2") of "go": + unregisterArcOrc(conf) conf.selectedGC = gcGo defineSymbol(conf.symbols, "gogc") of "none": + unregisterArcOrc(conf) conf.selectedGC = gcNone defineSymbol(conf.symbols, "nogc") of "stack", "regions": + unregisterArcOrc(conf) conf.selectedGC = gcRegions defineSymbol(conf.symbols, "gcregions") of "v2": warningOptionNoop(arg) From 0c3892c3c707e75520d6c8b5a65a0eaf8c15fcd4 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 28 Jan 2022 16:53:42 +0800 Subject: [PATCH 3275/4254] nvro don't touch cdecl types [backport: 1.6] (#19461) * nvro don't touch cdecl types; fix #19342 again --- compiler/ast.nim | 2 +- compiler/ccgcalls.nim | 6 +++--- compiler/ccgstmts.nim | 21 ++++++++++++++------- compiler/ccgtypes.nim | 18 ++++++++++++------ compiler/cgen.nim | 4 ++-- compiler/semstmts.nim | 1 + tests/objects/t19342_2.nim | 18 ++++++++++++++++++ 7 files changed, 51 insertions(+), 19 deletions(-) create mode 100644 tests/objects/t19342_2.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 4286f940f..ad5ec12f5 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -501,7 +501,7 @@ type nfHasComment # node has a comment TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45) tfVarargs, # procedure has C styled varargs # tyArray type represeting a varargs list tfNoSideEffect, # procedure type does not allow side effects diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index fe0516f9a..197728ccf 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -76,7 +76,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) if typ[0] != nil: - if isInvalidReturnType(p.config, typ[0]): + if isInvalidReturnType(p.config, typ): if params != nil: pl.add(~", ") # beware of 'result = p(result)'. We may need to allocate a temporary: if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri): @@ -439,7 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = let rawProc = getClosureType(p.module, typ, clHalf) let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0]) if typ[0] != nil: - if isInvalidReturnType(p.config, typ[0]): + if isInvalidReturnType(p.config, typ): if ri.len > 1: pl.add(~", ") # beware of 'result = p(result)'. We may need to allocate a temporary: if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri): @@ -737,7 +737,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add(~": ") pl.add(genArg(p, ri[i], param, ri)) if typ[0] != nil: - if isInvalidReturnType(p.config, typ[0]): + if isInvalidReturnType(p.config, typ): if ri.len > 1: pl.add(~" ") # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 7fecc1475..58a6dd015 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -32,13 +32,20 @@ proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) = "$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc]) proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = - if n.kind == nkEmpty: return false - if isInvalidReturnType(conf, n.typ): - # var v = f() - # is transformed into: var v; f(addr v) - # where 'f' **does not** initialize the result! - return false - result = true + if n.kind == nkEmpty: + result = false + elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc: + if isInvalidReturnType(conf, n[0].typ, true): + # var v = f() + # is transformed into: var v; f(addr v) + # where 'f' **does not** initialize the result! + result = false + else: + result = true + elif isInvalidReturnType(conf, n.typ, false): + result = false + else: + result = true proc inExceptBlockLen(p: BProc): int = for x in p.nestedTryStmts: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index df1874b26..f010b25c9 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -215,12 +215,18 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and (typ[0] == nil) or isPureObject(typ)) -proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = +proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool = # Arrays and sets cannot be returned by a C procedure, because C is # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. - if rettype == nil or (tfByCopy notin rettype.flags and getSize(conf, rettype) > conf.target.floatSize*3): + var rettype = typ + var isAllowedCall = true + if isProc: + rettype = rettype[0] + isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall} + if rettype == nil or (isAllowedCall and + getSize(conf, rettype) > conf.target.floatSize*3): result = true else: case mapType(conf, rettype, skResult) @@ -257,11 +263,11 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) = # see `testCodegenABICheck` for example error message it generates -proc fillResult(conf: ConfigRef; param: PNode) = +proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) = fillLoc(param.sym.loc, locParam, param, ~"Result", OnStack) let t = param.sym.typ - if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t): + if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype): incl(param.sym.loc.flags, lfIndirect) param.sym.loc.storage = OnUnknown @@ -426,7 +432,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, check: var IntSet, declareEnvironment=true; weakDep=false) = params = nil - if t[0] == nil or isInvalidReturnType(m.config, t[0]): + if t[0] == nil or isInvalidReturnType(m.config, t): rettype = ~"void" else: rettype = getTypeDescAux(m, t[0], check, skResult) @@ -461,7 +467,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, params.addf(", NI $1Len_$2", [param.loc.r, j.rope]) inc(j) arr = arr[0].skipTypes({tySink}) - if t[0] != nil and isInvalidReturnType(m.config, t[0]): + if t[0] != nil and isInvalidReturnType(m.config, t): var arr = t[0] if params != nil: params.add(", ") if mapReturnType(m.config, t[0]) != ctArray: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 246b8c0e9..10b4b55d0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1039,7 +1039,7 @@ proc genProcAux(m: BModule, prc: PSym) = internalError(m.config, prc.info, "proc has no result symbol") let resNode = prc.ast[resultPos] let res = resNode.sym # get result symbol - if not isInvalidReturnType(m.config, prc.typ[0]): + if not isInvalidReturnType(m.config, prc.typ): if sfNoInit in prc.flags: incl(res.flags, sfNoInit) if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil): var decl = localVarDecl(p, resNode) @@ -1053,7 +1053,7 @@ proc genProcAux(m: BModule, prc: PSym) = initLocalVar(p, res, immediateAsgn=false) returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) else: - fillResult(p.config, resNode) + fillResult(p.config, resNode, prc.typ) assignParam(p, res, prc.typ[0]) # We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)' # to 'unsureAsgn(result, x)' diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 33e304ab2..c2b385c80 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2137,6 +2137,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, incl(s.flags, sfWasForwarded) elif sfBorrow in s.flags: semBorrow(c, n, s) sideEffectsCheck(c, s) + closeScope(c) # close scope for parameters # c.currentScope = oldScope popOwner(c) diff --git a/tests/objects/t19342_2.nim b/tests/objects/t19342_2.nim new file mode 100644 index 000000000..6f6d0f2b3 --- /dev/null +++ b/tests/objects/t19342_2.nim @@ -0,0 +1,18 @@ +discard """ + targets: "c cpp" +""" + +{.compile: "m19342.c".} + +# bug #19342 +type + Node* {.byRef.} = object + data: array[25, cint] + +proc myproc(name: cint): Node {.importc: "hello", cdecl.} + +proc parse = + let node = myproc(10) + doAssert node.data[0] == 999 + +parse() \ No newline at end of file From 520881af9add94b26ef7d0630352ad425bb84490 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 29 Jan 2022 10:08:38 +0800 Subject: [PATCH 3276/4254] update outdated link (#19465) Ref https://github.com/nim-lang/Nim/issues/19463 --- doc/intern.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/intern.rst b/doc/intern.rst index e8fb4ac86..a8846ae02 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -166,7 +166,7 @@ current commit: You can also bisect using custom options to build the compiler, for example if you don't need a debug version of the compiler (which runs slower), you can replace -`./koch temp`:cmd: by explicit compilation command, see `Rebuilding the compiler`_. +`./koch temp`:cmd: by explicit compilation command, see `Bootstrapping the compiler`_. Runtimes From cb894c7094fb49014f85815a9dafc38b5dda743e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 29 Jan 2022 13:03:01 +0000 Subject: [PATCH 3277/4254] Merge pull request from GHSA-ggrq-h43f-3w7m This fixes a CVE (currently https://github.com/nim-lang/Nim/security/advisories/GHSA-ggrq-h43f-3w7m) --- compiler/docgen.nim | 2 +- lib/packages/docutils/rst.nim | 22 ++++++++++++++--- tests/stdlib/trstgen.nim | 45 +++++++++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 90e0f54b3..235922349 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -282,7 +282,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.cache = cache result.outDir = conf.outDir.string result.isPureRst = isPureRst - var options= {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown} + var options= {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown, roSandboxDisabled} if not isPureRst: options.incl roNimFile result.sharedState = newRstSharedState( options, filename.string, diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 791953767..93c2231dc 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -235,6 +235,12 @@ type ## to Markdown) -- implies `roSupportMarkdown` roNimFile ## set for Nim files where default interpreted ## text role should be :nim: + roSandboxDisabled ## this option enables certain options + ## (e.g. raw, include) + ## which are disabled by default as they can + ## enable users to read arbitrary data and + ## perform XSS if the parser is used in a web + ## app. RstParseOptions* = set[RstParseOption] @@ -260,7 +266,8 @@ type mwBrokenLink = "broken link '$1'", mwUnsupportedLanguage = "language '$1' not supported", mwUnsupportedField = "field '$1' not supported", - mwRstStyle = "RST style: $1" + mwRstStyle = "RST style: $1", + meSandboxedDirective = "disabled directive: '$1'", MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind, arg: string) {.closure, gcsafe.} ## what to do in case of an error @@ -315,6 +322,7 @@ const ":geek:": "icon_e_geek", ":ugeek:": "icon_e_ugeek" } + SandboxDirAllowlist = ["image", "code", "code-block"] type TokType = enum @@ -2987,10 +2995,14 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = ## ## As an extension this proc will process the ``file`` extension field and if ## present will replace the code block with the contents of the referenced - ## file. + ## file. This behaviour is disabled in sandboxed mode and can be re-enabled + ## with the `roSandboxDisabled` flag. result = parseDirective(p, rnCodeBlock, {hasArg, hasOptions}, parseLiteralBlock) var filename = strip(getFieldValue(result, "file")) if filename != "": + if roSandboxDisabled notin p.s.options: + let tok = p.tok[p.idx-2] + rstMessage(p, meSandboxedDirective, "file", tok.line, tok.col) var path = p.findRelativeFile(filename) if path == "": rstMessage(p, meCannotOpenFile, filename) var n = newRstNode(rnLiteralBlock) @@ -3086,6 +3098,11 @@ proc dirRaw(p: var RstParser): PRstNode = proc selectDir(p: var RstParser, d: string): PRstNode = result = nil + let tok = p.tok[p.idx-2] # report on directive in ".. directive::" + if roSandboxDisabled notin p.s.options: + if d notin SandboxDirAllowlist: + rstMessage(p, meSandboxedDirective, d, tok.line, tok.col) + case d of "admonition", "attention", "caution": result = dirAdmonition(p, d) of "code": result = dirCodeBlock(p) @@ -3112,7 +3129,6 @@ proc selectDir(p: var RstParser, d: string): PRstNode = of "title": result = dirTitle(p) of "warning": result = dirAdmonition(p, d) else: - let tok = p.tok[p.idx-2] # report on directive in ".. directive::" rstMessage(p, meInvalidDirective, d, tok.line, tok.col) proc prefix(ftnType: FootnoteType): string = diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 2be65b35b..995c0a151 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -47,6 +47,10 @@ proc optionListLabel(opt: string): string = opt & "
      " +const + NoSandboxOpts = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled} + + suite "YAML syntax highlighting": test "Basics": let input = """.. code-block:: yaml @@ -631,7 +635,9 @@ let x = 1 let p3 = """

      Par3 """ & id"value3" & ".

      " let p4 = """

      Par4 value4.

      """ let expected = p1 & p2 & "\n" & p3 & "\n" & p4 - check(input.toHtml == expected) + check( + input.toHtml(NoSandboxOpts) == expected + ) test "role directive": let input = dedent""" @@ -642,7 +648,10 @@ let x = 1 :language: brainhelp """ var warnings = new seq[string] - let output = input.toHtml(warnings=warnings) + let output = input.toHtml( + NoSandboxOpts, + warnings=warnings + ) check(warnings[].len == 1 and "language 'brainhelp' not supported" in warnings[0]) test "RST comments": @@ -1187,7 +1196,9 @@ Test1 .. tip:: endOf tip .. warning:: endOf warning """ - let output0 = input0.toHtml + let output0 = input0.toHtml( + NoSandboxOpts + ) for a in ["admonition", "attention", "caution", "danger", "error", "hint", "important", "note", "tip", "warning" ]: doAssert "endOf " & a & "" in output0 @@ -1198,7 +1209,9 @@ Test1 Test paragraph. """ - let output1 = input1.toHtml + let output1 = input1.toHtml( + NoSandboxOpts + ) doAssert "endOfError" in output1 doAssert "

      Test paragraph.

      " in output1 doAssert "class=\"admonition admonition-error\"" in output1 @@ -1210,7 +1223,9 @@ Test1 Test paragraph. """ - let output2 = input2.toHtml + let output2 = input2.toHtml( + NoSandboxOpts + ) doAssert "endOfError Test2p." in output2 doAssert "

      Test paragraph.

      " in output2 doAssert "class=\"admonition admonition-error\"" in output2 @@ -1218,7 +1233,9 @@ Test1 let input3 = dedent """ .. note:: endOfNote """ - let output3 = input3.toHtml + let output3 = input3.toHtml( + NoSandboxOpts + ) doAssert "endOfNote" in output3 doAssert "class=\"admonition admonition-info\"" in output3 @@ -1303,7 +1320,9 @@ Test1 That was a transition. """ - let output1 = input1.toHtml + let output1 = input1.toHtml( + NoSandboxOpts + ) doAssert "

      Nim))""") check("(([Nim](javascript://nim-lang.org/)))".toHtml == """((Nim))""") + +suite "local file inclusion": + test "cannot include files in sandboxed mode": + var error = new string + discard ".. include:: ./readme.md".toHtml(error=error) + check(error[] == "input(1, 11) Error: disabled directive: 'include'") + + test "code-block file directive is disabled": + var error = new string + discard ".. code-block:: nim\n :file: ./readme.md".toHtml(error=error) + check(error[] == "input(2, 20) Error: disabled directive: 'file'") + From 33cd883e27f7ba7564cbeb59d2d38fe02bb507bf Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 29 Jan 2022 21:06:54 +0800 Subject: [PATCH 3278/4254] [add testcase] NRVO does not occur with init procedures (#19462) * [add testcase] NRVO does not occur with init procedures close #19094 * Update tests/ccgbugs2/tcodegen.nim --- tests/ccgbugs2/tcodegen.nim | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/ccgbugs2/tcodegen.nim diff --git a/tests/ccgbugs2/tcodegen.nim b/tests/ccgbugs2/tcodegen.nim new file mode 100644 index 000000000..84cd76e2f --- /dev/null +++ b/tests/ccgbugs2/tcodegen.nim @@ -0,0 +1,28 @@ +discard """ + targets: "c cpp" +""" + +# bug #19094 +type + X = object + filler: array[2048, int] + innerAddress: uint + +proc initX(): X = + result.innerAddress = cast[uint](result.addr) + +proc initXInPlace(x: var X) = + x.innerAddress = cast[uint](x.addr) + +block: # NRVO1 + var x = initX() + let innerAddress = x.innerAddress + let outerAddress = cast[uint](x.addr) + doAssert(innerAddress == outerAddress) # [OK] + +block: # NRVO2 + var x: X + initXInPlace(x) + let innerAddress = x.innerAddress + let outerAddress = cast[uint](x.addr) + doAssert(innerAddress == outerAddress) # [OK] From 56a901f9e197dd03f8c70ab4ef1042dc33548af0 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 31 Jan 2022 20:49:20 +0800 Subject: [PATCH 3279/4254] fix broken CI (#19472) * fix broken CI * fix * fix tests --- compiler/docgen.nim | 1 + compiler/lineinfos.nim | 2 ++ tests/stdlib/trst.nim | 12 ++++++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 235922349..3e61032d8 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -237,6 +237,7 @@ template declareClosures = of meInvalidDirective: k = errRstInvalidDirectiveX of meInvalidField: k = errRstInvalidField of meFootnoteMismatch: k = errRstFootnoteMismatch + of meSandboxedDirective: k = errRstSandboxedDirective of mwRedefinitionOfLabel: k = warnRstRedefinitionOfLabel of mwUnknownSubstitution: k = warnRstUnknownSubstitutionX of mwAmbiguousLink: k = warnRstAmbiguousLink diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index e13387be6..575be6196 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -39,6 +39,7 @@ type errRstInvalidDirectiveX, errRstInvalidField, errRstFootnoteMismatch, + errRstSandboxedDirective, errProveInit, # deadcode errGenerated, errUser, @@ -110,6 +111,7 @@ const errRstInvalidDirectiveX: "invalid directive: '$1'", errRstInvalidField: "invalid field: $1", errRstFootnoteMismatch: "number of footnotes and their references don't match: $1", + errRstSandboxedDirective: "disabled directive: '$1'", errProveInit: "Cannot prove that '$1' is initialized.", # deadcode errGenerated: "$1", errUser: "$1", diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 0a9eb8038..771e02477 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -23,7 +23,7 @@ import std/private/miscdollars import os proc toAst(input: string, - rstOptions: RstParseOptions = {roPreferMarkdown, roSupportMarkdown, roNimFile}, + rstOptions: RstParseOptions = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}, error: ref string = nil, warnings: ref seq[string] = nil): string = ## If `error` is nil then no errors should be generated. @@ -866,7 +866,7 @@ suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") let input = ".. include:: other.rst" - doAssert "test1" == rstTohtml(input, {}, defaultConfig()) + doAssert "test1" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") test "Include starting from": @@ -880,7 +880,7 @@ OtherStart .. include:: other.rst :start-after: OtherStart """ - check "Visible" == rstTohtml(input, {}, defaultConfig()) + check "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") test "Include everything before": @@ -894,7 +894,7 @@ And this should **NOT** be visible in `docs.html` .. include:: other.rst :end-before: OtherEnd """ - doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") @@ -912,7 +912,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - check "Visible" == rstTohtml(input, {}, defaultConfig()) + check "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") @@ -932,7 +932,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") suite "RST escaping": From 22ae0bef63189dff28676b0dd5f6089864151120 Mon Sep 17 00:00:00 2001 From: tandy1000 Date: Tue, 1 Feb 2022 11:12:55 +0000 Subject: [PATCH 3280/4254] Update jsfetch with latest API and fix missing bindings (#19473) * Update with latest API and fix missing bindings remove deprecated `Body` remove implicit `cstring` convs add `Headers` to `FetchOptions` add `Request` init proc which takes `FetchOptions` * Update lib/std/jsfetch.nim Co-authored-by: Juan Carlos * Update lib/std/jsfetch.nim Co-authored-by: Juan Carlos * remove experimental flag Co-authored-by: Juan Carlos --- lib/std/jsfetch.nim | 46 ++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/std/jsfetch.nim b/lib/std/jsfetch.nim index a25fe7ca8..808d699b0 100644 --- a/lib/std/jsfetch.nim +++ b/lib/std/jsfetch.nim @@ -1,5 +1,4 @@ ## - Fetch for the JavaScript target: https://developer.mozilla.org/docs/Web/API/Fetch_API -## .. Note:: jsfetch is Experimental. when not defined(js): {.fatal: "Module jsfetch is designed to be used with the JavaScript backend.".} @@ -12,6 +11,7 @@ type keepalive*: bool metod* {.importjs: "method".}: cstring body*, integrity*, referrer*, mode*, credentials*, cache*, redirect*, referrerPolicy*: cstring + headers*: Headers FetchModes* = enum ## Mode options. fmCors = "cors" @@ -42,16 +42,13 @@ type frpOriginWhenCrossOrigin = "origin-when-cross-origin" frpUnsafeUrl = "unsafe-url" - Body* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Body - bodyUsed*: bool - Response* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Response bodyUsed*, ok*, redirected*: bool typ* {.importjs: "type".}: cstring url*, statusText*: cstring status*: cint headers*: Headers - body*: Body + body*: cstring Request* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Request bodyUsed*, ok*, redirected*: bool @@ -59,8 +56,7 @@ type url*, statusText*: cstring status*: cint headers*: Headers - body*: Body - + body*: cstring func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response(#))".} ## Constructor for `Response`. This does *not* call `fetch()`. Same as `new Response()`. @@ -68,30 +64,34 @@ func newResponse*(body: cstring | FormData): Response {.importjs: "(new Response func newRequest*(url: cstring): Request {.importjs: "(new Request(#))".} ## Constructor for `Request`. This does *not* call `fetch()`. Same as `new Request()`. +func newRequest*(url: cstring; fetchOptions: FetchOptions): Request {.importjs: "(new Request(#, #))".} + ## Constructor for `Request` with `fetchOptions`. Same as `fetch(url, fetchOptions)`. + func clone*(self: Response | Request): Response {.importjs: "#.$1()".} ## https://developer.mozilla.org/en-US/docs/Web/API/Response/clone proc text*(self: Response): Future[cstring] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Body/text + ## https://developer.mozilla.org/en-US/docs/Web/API/Response/text proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Body/json + ## https://developer.mozilla.org/en-US/docs/Web/API/Response/json -proc formData*(self: Body): Future[FormData] {.importjs: "#.$1()".} - ## https://developer.mozilla.org/en-US/docs/Web/API/Body/formData +proc formData*(self: Response): Future[FormData] {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Response/formData proc unsafeNewFetchOptions*(metod, body, mode, credentials, cache, referrerPolicy: cstring; - keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring): FetchOptions {.importjs: - "{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #}".} + keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring; headers: Headers = newHeaders()): FetchOptions {.importjs: + "{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #, headers: #}".} ## .. warning:: Unsafe `newfetchOptions`. func newfetchOptions*(metod: HttpMethod; body: cstring; mode: FetchModes; credentials: FetchCredentials; cache: FetchCaches; referrerPolicy: FetchReferrerPolicies; - keepalive: bool; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring): FetchOptions = + keepalive: bool; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring, + headers: Headers = newHeaders()): FetchOptions = ## Constructor for `FetchOptions`. result = FetchOptions( - body: body, mode: $mode, credentials: $credentials, cache: $cache, referrerPolicy: $referrerPolicy, - keepalive: keepalive, redirect: $redirect, referrer: referrer, integrity: integrity, + body: body, mode: cstring($mode), credentials: cstring($credentials), cache: cstring($cache), referrerPolicy: cstring($referrerPolicy), + keepalive: keepalive, redirect: cstring($redirect), referrer: referrer, integrity: integrity, metod: (case metod of HttpHead: "HEAD".cstring of HttpGet: "GET".cstring @@ -109,9 +109,9 @@ proc fetch*(url: cstring | Request): Future[Response] {.importjs: "$1(#)".} proc fetch*(url: cstring | Request; options: FetchOptions): Future[Response] {.importjs: "$1(#, #)".} ## `fetch()` API that takes a `FetchOptions`, returns a `Future[Response]`. -func toCstring*(self: Request | Response | Body | FetchOptions): cstring {.importjs: "JSON.stringify(#)".} +func toCstring*(self: Request | Response | FetchOptions): cstring {.importjs: "JSON.stringify(#)".} -func `$`*(self: Request | Response | Body | FetchOptions): string = $toCstring(self) +func `$`*(self: Request | Response | FetchOptions): string = $toCstring(self) runnableExamples("-r:off"): @@ -131,7 +131,8 @@ runnableExamples("-r:off"): keepalive = false, redirect = "follow".cstring, referrer = "client".cstring, - integrity = "".cstring + integrity = "".cstring, + headers = newHeaders() ) assert options0.keepalive == false assert options0.metod == "POST".cstring @@ -143,6 +144,7 @@ runnableExamples("-r:off"): assert options0.redirect == "follow".cstring assert options0.referrer == "client".cstring assert options0.integrity == "".cstring + assert options0.headers.len == 0 block: let options1: FetchOptions = newFetchOptions( @@ -155,7 +157,8 @@ runnableExamples("-r:off"): keepalive = false, redirect = frFollow, referrer = "client".cstring, - integrity = "".cstring + integrity = "".cstring, + headers = newHeaders() ) assert options1.keepalive == false assert options1.metod == $HttpPost @@ -167,6 +170,7 @@ runnableExamples("-r:off"): assert options1.redirect == $frFollow assert options1.referrer == "client".cstring assert options1.integrity == "".cstring + assert options1.headers.len == 0 block: let response: Response = newResponse(body = "-. .. --".cstring) @@ -182,7 +186,7 @@ runnableExamples("-r:off"): assert response.ok assert response.status == 200.cint assert response.headers is Headers - assert response.body is Body + assert response.body is cstring discard example() From 1830a3b505c33be5fc3b9e311c5e7720d9b37b32 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Wed, 2 Feb 2022 01:38:21 -0700 Subject: [PATCH 3281/4254] No longer segfault when using a typeclass with a self referencing type (#19467) --- compiler/sigmatch.nim | 3 ++- tests/generics/tgenerics_issues.nim | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e1195d04a..14f4c5e19 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1688,7 +1688,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, var aa = a while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0: aa = lastSon(aa) - if aa.kind == tyGenericParam: + if aa.kind in {tyGenericParam} + tyTypeClasses: + # If the constraint is a genericParam or typeClass this isGeneric return isGeneric result = typeRel(c, f.base, aa, flags) if result > isGeneric: result = isGeneric diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 092926c01..db7a16569 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -860,3 +860,15 @@ type var a: Tile3[int] +block: # Ensure no segfault from constraint + type + Regex[A: SomeOrdinal] = ref object + val: Regex[A] + MyConstraint = (seq or enum or set) + MyOtherType[A: MyConstraint] = ref object + val: MyOtherType[A] + + var + a = Regex[int]() + b = Regex[bool]() + c = MyOtherType[seq[int]]() From 486cb09ec2caef60011b3d182bfd188dadafdf62 Mon Sep 17 00:00:00 2001 From: Regis Caillaud <35006197+Clonkk@users.noreply.github.com> Date: Wed, 2 Feb 2022 09:44:51 +0100 Subject: [PATCH 3282/4254] Clonkk fix2 11923 (#19451) * fix nnkBracketExpr not compiling for getImpl on customPragmaNode * fix test import * fix alias not working with hasCustomPragmas --- lib/core/macros.nim | 27 ++++++++++++++++++++++----- tests/pragmas/tcustom_pragma.nim | 6 ++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 28106493f..c0e6e5154 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1493,6 +1493,22 @@ macro expandMacros*(body: typed): untyped = echo body.toStrLit result = body +proc extractTypeImpl(n: NimNode): NimNode = + ## attempts to extract the type definition of the given symbol + case n.kind + of nnkSym: # can extract an impl + result = n.getImpl.extractTypeImpl() + of nnkObjectTy, nnkRefTy, nnkPtrTy: result = n + of nnkBracketExpr: + if n.typeKind == ntyTypeDesc: + result = n[1].extractTypeImpl() + else: + doAssert n.typeKind == ntyGenericInst + result = n[0].getImpl() + of nnkTypeDef: + result = n[2] + else: error("Invalid node to retrieve type implementation of: " & $n.kind) + proc customPragmaNode(n: NimNode): NimNode = expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkCheckedFieldExpr}) let @@ -1501,7 +1517,10 @@ proc customPragmaNode(n: NimNode): NimNode = if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy: return typ[1][1] elif typ.typeKind == ntyTypeDesc: - let impl = typ[1].getImpl() + let impl = getImpl( + if kind(typ[1]) == nnkBracketExpr: typ[1][0] + else: typ[1] + ) if impl[0].kind == nnkPragmaExpr: return impl[0][1] else: @@ -1524,14 +1543,12 @@ proc customPragmaNode(n: NimNode): NimNode = let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1]) let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0]) var typDef = getImpl( - if typInst.kind == nnkVarTy or - typInst.kind == nnkBracketExpr: - typInst[0] + if typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst[0] else: typInst ) while typDef != nil: typDef.expectKind(nnkTypeDef) - let typ = typDef[2] + let typ = typDef[2].extractTypeImpl() typ.expectKind({nnkRefTy, nnkPtrTy, nnkObjectTy}) let isRef = typ.kind in {nnkRefTy, nnkPtrTy} if isRef and typ[0].kind in {nnkSym, nnkBracketExpr}: # defines ref type for another object(e.g. X = ref X) diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 1c3709b26..db2536188 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -20,16 +20,22 @@ block: MyGenericObj[T] = object myField1, myField2 {.myAttr: "hi".}: int + MyOtherObj = MyObj + var o: MyObj static: doAssert o.myField2.hasCustomPragma(myAttr) doAssert(not o.myField1.hasCustomPragma(myAttr)) + doAssert(not o.myField1.hasCustomPragma(MyObj)) + doAssert(not o.myField1.hasCustomPragma(MyOtherObj)) var ogen: MyGenericObj[int] static: doAssert ogen.myField2.hasCustomPragma(myAttr) doAssert(not ogen.myField1.hasCustomPragma(myAttr)) + doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj)) + doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj)) import custom_pragma From 891329cd4b3e7e3b0d995cf342c1018239ebcf81 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 3 Feb 2022 00:10:11 +0800 Subject: [PATCH 3283/4254] move io out of system (#19442) * move io out of system * fix tests * fix tests * next step * rename to syncio * rename * fix nimscript * comma * fix * fix parts of errors * good for now * fix test --- changelog.md | 2 ++ compiler/pathutils.nim | 3 ++ compiler/vmops.nim | 2 +- doc/tut1.rst | 8 ++--- lib/posix/posix.nim | 3 ++ lib/pure/htmlparser.nim | 3 ++ lib/pure/json.nim | 3 ++ lib/pure/logging.nim | 11 ++++--- lib/pure/memfiles.nim | 4 +-- lib/pure/os.nim | 3 ++ lib/pure/parsecfg.nim | 4 +++ lib/pure/parsecsv.nim | 3 ++ lib/pure/pegs.nim | 2 ++ lib/pure/ropes.nim | 3 ++ lib/pure/streams.nim | 9 ++++-- lib/pure/terminal.nim | 3 ++ lib/pure/xmlparser.nim | 3 ++ lib/{system/io.nim => std/syncio.nim} | 45 +++++++++++++-------------- lib/system.nim | 9 ++++-- lib/system_overview.rst | 1 - lib/windows/winlean.nim | 3 ++ tests/cpp/t6986.nim | 3 ++ tests/test_nimscript.nims | 3 ++ tools/kochdocs.nim | 1 - 24 files changed, 92 insertions(+), 42 deletions(-) rename lib/{system/io.nim => std/syncio.nim} (96%) diff --git a/changelog.md b/changelog.md index bbbaf6e97..412e046eb 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,8 @@ - `addr` is now available for all addressable locations, `unsafeAddr` is deprecated and becomes an alias for `addr`. +- io is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/syncio`. + ## Standard library additions and changes - `macros.parseExpr` and `macros.parseStmt` now accept an optional diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index d8f3613b0..8138a245a 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -12,6 +12,9 @@ import os, pathnorm +when defined(nimSlimSystem): + import std/syncio + type AbsoluteFile* = distinct string AbsoluteDir* = distinct string diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 018e7b9c6..6b06cc68d 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -47,7 +47,7 @@ template systemop(op) {.dirty.} = registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`) template ioop(op) {.dirty.} = - registerCallback(c, "stdlib.io." & astToStr(op), `op Wrapper`) + registerCallback(c, "stdlib.syncio." & astToStr(op), `op Wrapper`) template macrosop(op) {.dirty.} = registerCallback(c, "stdlib.macros." & astToStr(op), `op Wrapper`) diff --git a/doc/tut1.rst b/doc/tut1.rst index 3107aef45..405df57b1 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -84,8 +84,8 @@ done with spaces only, tabulators are not allowed. String literals are enclosed in double-quotes. The `var` statement declares a new variable named `name` of type `string` with the value that is -returned by the `readLine `_ procedure. Since the -compiler knows that `readLine `_ returns a string, +returned by the `readLine `_ procedure. Since the +compiler knows that `readLine `_ returns a string, you can leave out the type in the declaration (this is called `local type inference`:idx:). So this will work too: @@ -97,7 +97,7 @@ Note that this is basically the only form of type inference that exists in Nim: it is a good compromise between brevity and readability. The "hello world" program contains several identifiers that are already known -to the compiler: `echo`, `readLine `_, etc. +to the compiler: `echo`, `readLine `_, etc. These built-ins are declared in the system_ module which is implicitly imported by any other module. @@ -594,7 +594,7 @@ Procedures ========== To define new commands like `echo `_ -and `readLine `_ in the examples, the concept of a +and `readLine `_ in the examples, the concept of a *procedure* is needed. You might be used to them being called *methods* or *functions* in other languages, but Nim `differentiates these concepts `_. In diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 912e395a7..c10fc6ac9 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -37,6 +37,9 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} +when defined(nimSlimSystem): + import std/syncio + # TODO these constants don't seem to be fetched from a header file for unknown # platforms - where do they come from and why are they here? when false: diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 21dff69ff..6b1300f11 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -51,6 +51,9 @@ import strutils, streams, parsexml, xmltree, unicode, strtabs +when defined(nimPreviewSlimSystem): + import std/syncio + type HtmlTag* = enum ## list of all supported HTML tags; order will always be ## alphabetically diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 922cd4e2f..bdc9fe5ab 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -164,6 +164,9 @@ import hashes, tables, strutils, lexbase, streams, macros, parsejson import options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 import std/private/since +when defined(nimPreviewSlimSystem): + import std/syncio + export tables.`$` diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index b2ace79ab..6751a372a 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -48,7 +48,7 @@ ## .. warning:: ## For loggers that log to a console or to files, only error and fatal ## messages will cause their output buffers to be flushed immediately. -## Use the `flushFile proc `_ to flush the buffer +## Use the `flushFile proc `_ to flush the buffer ## manually if needed. ## ## Handlers @@ -146,6 +146,9 @@ import strutils, times when not defined(js): import os +when defined(nimPreviewSlimSystem): + import std/syncio + type Level* = enum ## \ ## Enumeration of logging levels. @@ -346,7 +349,7 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = ## ## **Note:** Only error and fatal messages will cause the output buffer ## to be flushed immediately. Use the `flushFile proc - ## `_ to flush the buffer manually if needed. + ## `_ to flush the buffer manually if needed. ## ## See also: ## * `log method<#log.e,FileLogger,Level,varargs[string,]>`_ @@ -422,7 +425,7 @@ when not defined(js): ## **Notes:** ## * Only error and fatal messages will cause the output buffer ## to be flushed immediately. Use the `flushFile proc - ## `_ to flush the buffer manually if needed. + ## `_ to flush the buffer manually if needed. ## * This method is not available for the JavaScript backend. ## ## See also: @@ -600,7 +603,7 @@ when not defined(js): ## **Notes:** ## * Only error and fatal messages will cause the output buffer ## to be flushed immediately. Use the `flushFile proc - ## `_ to flush the buffer manually if needed. + ## `_ to flush the buffer manually if needed. ## * This method is not available for the JavaScript backend. ## ## See also: diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 407a358fa..f65ca125e 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -431,7 +431,7 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline iterator lines*(mfile: MemFile, buf: var string, delim = '\l', eat = '\r'): string {.inline.} = ## Replace contents of passed buffer with each new line, like - ## `readLine(File) `_. + ## `readLine(File) `_. ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## @@ -450,7 +450,7 @@ iterator lines*(mfile: MemFile, buf: var string, delim = '\l', iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): string {.inline.} = ## Return each line in a file as a Nim string, like - ## `lines(File) `_. + ## `lines(File) `_. ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 07040d611..76164bc49 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -34,6 +34,9 @@ import std/private/since import strutils, pathnorm +when defined(nimPreviewSlimSystem): + import std/syncio + const weirdTarget = defined(nimscript) or defined(js) since (1, 1): diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 0ee19912c..54584a253 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -175,8 +175,12 @@ import strutils, lexbase, streams, tables import std/private/decode_helpers import std/private/since +when defined(nimPreviewSlimSystem): + import std/syncio + include "system/inclrtl" + type CfgEventKind* = enum ## enumeration of all events that may occur when parsing cfgEof, ## end of file reached diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 6db794682..a8d1cfaab 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -67,6 +67,9 @@ import lexbase, streams +when defined(nimPreviewSlimSystem): + import std/syncio + type CsvRow* = seq[string] ## A row in a CSV file. CsvParser* = object of BaseLexer ## The parser object. diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index bac8b1a0e..0eed1c388 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -16,6 +16,8 @@ ## include "system/inclrtl" +when defined(nimPreviewSlimSystem): + import std/syncio const useUnicode = true ## change this to deactivate proper UTF-8 support diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 1300b4479..84b5b47c2 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -19,6 +19,9 @@ include system/inclrtl import streams +when defined(nimPreviewSlimSystem): + import std/syncio + {.push debugger: off.} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 7dc81148f..7ad81685f 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -92,10 +92,13 @@ ## See also ## ======== ## * `asyncstreams module `_ -## * `io module `_ for `FileMode enum `_ +## * `io module `_ for `FileMode enum `_ import std/private/since +when defined(nimPreviewSlimSystem): + import std/syncio + proc newEIO(msg: string): owned(ref IOError) = new(result) result.msg = msg @@ -1331,7 +1334,7 @@ proc newFileStream*(f: File): owned FileStream = ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream ## from string. ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same - ## as using `open proc `_ + ## as using `open proc `_ ## on Examples. ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a ## file stream from the file name and the mode. @@ -1370,7 +1373,7 @@ proc newFileStream*(filename: string, mode: FileMode = fmRead, ## Creates a new stream from the file named `filename` with the mode `mode`. ## ## If the file cannot be opened, `nil` is returned. See the `io module - ## `_ for a list of available `FileMode enums `_. + ## `_ for a list of available `FileMode enums `_. ## ## **Note:** ## * **This function returns nil in case of failure.** diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index c9aafc037..5755e142a 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -66,6 +66,9 @@ import colors when defined(windows): import winlean +when defined(nimPreviewSlimSystem): + import std/syncio + type PTerminal = ref object trueColorIsSupported: bool diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 3d9c288ed..6785fa66e 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -11,6 +11,9 @@ import streams, parsexml, strtabs, xmltree +when defined(nimPreviewSlimSystem): + import std/syncio + type XmlError* = object of ValueError ## Exception that is raised ## for invalid XML. diff --git a/lib/system/io.nim b/lib/std/syncio.nim similarity index 96% rename from lib/system/io.nim rename to lib/std/syncio.nim index 04a43328d..eab96254a 100644 --- a/lib/system/io.nim +++ b/lib/std/syncio.nim @@ -1,18 +1,17 @@ # # # Nim's Runtime Library -# (c) Copyright 2019 Nim contributors +# (c) Copyright 2022 Nim contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This is a part of `system.nim`, you should not manually import it. +## This module implements various synchronized I/O operations. - -include inclrtl +include system/inclrtl import std/private/since -import formatfloat +import system/formatfloat # ----------------- IO Part ------------------------------------------------ type @@ -179,7 +178,7 @@ proc checkErr(f: File) = {.push stackTrace: off, profiler: off.} proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. tags: [ReadIOEffect], benign.} = - ## reads `len` bytes into the buffer pointed to by `buffer`. Returns + ## Reads `len` bytes into the buffer pointed to by `buffer`. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. result = cast[int](c_fread(buffer, 1, cast[csize_t](len), f)) @@ -188,13 +187,13 @@ proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {. tags: [ReadIOEffect], benign.} = - ## reads `len` bytes into the buffer `a` starting at `a[start]`. Returns + ## Reads `len` bytes into the buffer `a` starting at `a[start]`. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. result = readBuffer(f, addr(a[start]), len) proc readChars*(f: File, a: var openArray[char]): int {.tags: [ReadIOEffect], benign.} = - ## reads up to `a.len` bytes into the buffer `a`. Returns + ## Reads up to `a.len` bytes into the buffer `a`. Returns ## the actual number of bytes that have been read which may be less than ## `a.len` (if not as many bytes are remaining), but not greater. result = readBuffer(f, addr(a[0]), a.len) @@ -202,7 +201,7 @@ proc readChars*(f: File, a: var openArray[char]): int {.tags: [ReadIOEffect], be proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {. tags: [ReadIOEffect], benign, deprecated: "use other `readChars` overload, possibly via: readChars(toOpenArray(buf, start, len-1))".} = - ## reads `len` bytes into the buffer `a` starting at `a[start]`. Returns + ## Reads `len` bytes into the buffer `a` starting at `a[start]`. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. if (start + len) > len(a): @@ -216,7 +215,7 @@ proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.} = proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. tags: [WriteIOEffect], benign.} = - ## writes the bytes of buffer pointed to by the parameter `buffer` to the + ## Writes the bytes of buffer pointed to by the parameter `buffer` to the ## file `f`. Returns the number of actual written bytes, which may be less ## than `len` in case of an error. result = cast[int](c_fwrite(buffer, 1, cast[csize_t](len), f)) @@ -224,7 +223,7 @@ proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. tags: [WriteIOEffect], benign.} = - ## writes the bytes of `a[start..start+len-1]` to the file `f`. Returns + ## Writes the bytes of `a[start..start+len-1]` to the file `f`. Returns ## the number of actual written bytes, which may be less than `len` in case ## of an error. var x = cast[ptr UncheckedArray[int8]](a) @@ -232,7 +231,7 @@ proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {. tags: [WriteIOEffect], benign.} = - ## writes the bytes of `a[start..start+len-1]` to the file `f`. Returns + ## Writes the bytes of `a[start..start+len-1]` to the file `f`. Returns ## the number of actual written bytes, which may be less than `len` in case ## of an error. var x = cast[ptr UncheckedArray[int8]](a) @@ -341,7 +340,7 @@ proc flushFile*(f: File) {.tags: [WriteIOEffect].} = discard c_fflush(f) proc getFileHandle*(f: File): FileHandle = - ## returns the file handle of the file `f`. This is only useful for + ## Returns the file handle of the file `f`. This is only useful for ## platform specific programming. ## Note that on Windows this doesn't return the Windows-specific handle, ## but the C library's notion of a handle, whatever that means. @@ -349,7 +348,7 @@ proc getFileHandle*(f: File): FileHandle = c_fileno(f) proc getOsFileHandle*(f: File): FileHandle = - ## returns the OS file handle of the file `f`. This is only useful for + ## Returns the OS file handle of the file `f`. This is only useful for ## platform specific programming. when defined(windows): result = FileHandle getOsfhandle(cint getFileHandle(f)) @@ -380,7 +379,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], benign.} = - ## reads a line of text from the file `f` into `line`. May throw an IO + ## Reads a line of text from the file `f` into `line`. May throw an IO ## exception. ## A line of text may be delimited by `LF` or `CRLF`. The newline ## character(s) are not part of the returned string. Returns `false` @@ -500,7 +499,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], line.setLen(pos+sp) proc readLine*(f: File): string {.tags: [ReadIOEffect], benign.} = - ## reads a line of text from the file `f`. May throw an IO exception. + ## Reads a line of text from the file `f`. May throw an IO exception. ## A line of text may be delimited by `LF` or `CRLF`. The newline ## character(s) are not part of the returned string. result = newStringOfCap(80) @@ -602,7 +601,7 @@ proc readAll*(file: File): string {.tags: [ReadIOEffect], benign.} = proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, tags: [WriteIOEffect], benign.} = - ## writes the values `x` to `f` and then writes "\\n". + ## Writes the values `x` to `f` and then writes "\\n". ## May throw an IO exception. for i in items(x): write(f, i) @@ -723,7 +722,7 @@ proc open*(f: var File, filename: string, proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. tags: [], benign.} = - ## reopens the file `f` with given `filename` and `mode`. This + ## Reopens the file `f` with given `filename` and `mode`. This ## is often used to redirect the `stdin`, `stdout` or `stderr` ## file variables. ## @@ -765,19 +764,19 @@ proc open*(filename: string, sysFatal(IOError, "cannot open: " & filename) proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} = - ## sets the position of the file pointer that is used for read/write + ## Sets the position of the file pointer that is used for read/write ## operations. The file's first byte has the index zero. if c_fseek(f, pos, cint(relativeTo)) != 0: raiseEIO("cannot set file position") proc getFilePos*(f: File): int64 {.benign.} = - ## retrieves the current position of the file pointer that is used to + ## Retrieves the current position of the file pointer that is used to ## read from the file `f`. The file's first byte has the index zero. result = c_ftell(f) if result < 0: raiseEIO("cannot retrieve file position") proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} = - ## retrieves the file size (in bytes) of `f`. + ## Retrieves the file size (in bytes) of `f`. let oldPos = getFilePos(f) discard c_fseek(f, 0, 2) # seek the end of the file result = getFilePos(f) @@ -906,7 +905,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} = raise newException(IOError, "cannot open: " & filename) proc readLines*(filename: string, n: Natural): seq[string] = - ## read `n` lines from the file named `filename`. Raises an IO exception + ## Reads `n` lines from the file named `filename`. Raises an IO exception ## in case of an error. Raises EOF if file does not contain at least `n` lines. ## Available at compile time. A line of text may be delimited by `LF` or `CRLF`. ## The newline character(s) are not part of the returned strings. @@ -948,7 +947,7 @@ iterator lines*(filename: string): string {.tags: [ReadIOEffect].} = close(f) iterator lines*(f: File): string {.tags: [ReadIOEffect].} = - ## Iterate over any line in the file `f`. + ## Iterates over any line in the file `f`. ## ## The trailing newline character(s) are removed from the iterated lines. ## diff --git a/lib/system.nim b/lib/system.nim index 63cdc3ca8..56a6e2887 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2680,7 +2680,7 @@ proc slurp*(filename: string): string {.magic: "Slurp".} ## This is an alias for `staticRead <#staticRead,string>`_. proc staticRead*(filename: string): string {.magic: "Slurp".} - ## Compile-time `readFile `_ proc for easy + ## Compile-time `readFile `_ proc for easy ## `resource`:idx: embedding: ## ## The maximum file size limit that `staticRead` and `slurp` can read is @@ -3150,8 +3150,11 @@ when defined(genode): import system/widestrs export widestrs -import system/io -export io +when not defined(nimPreviewSlimSystem): + {.deprecated: """io is about to move out of system; use `-d:nimPreviewSlimSystem` and + import `std/syncio`.""".} + import std/syncio + export syncio when not defined(createNimHcr) and not defined(nimscript): include nimhcr diff --git a/lib/system_overview.rst b/lib/system_overview.rst index 0e4ffaf17..768fdcd6d 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -7,7 +7,6 @@ is in separate files: * `iterators `_ * `assertions `_ * `dollars `_ -* `io `_ * `widestrs `_ diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 6e626e4ba..c02cd9775 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -17,6 +17,9 @@ when defined(nimHasStyleChecks): {.passc: "-DWIN32_LEAN_AND_MEAN".} +when defined(nimPreviewSlimSystem): + from std/syncio import FileHandle + const useWinUnicode* = not defined(useWinAnsi) diff --git a/tests/cpp/t6986.nim b/tests/cpp/t6986.nim index ffd277adb..16e455c3b 100644 --- a/tests/cpp/t6986.nim +++ b/tests/cpp/t6986.nim @@ -5,6 +5,9 @@ discard """ import sequtils, strutils +when defined(nimPreviewSlimSystem): + import std/syncio + let rules = toSeq(lines("input")) .mapIt(it.split(" => ").mapIt(it.replace("/", ""))) diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 22a566307..b380570ff 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -5,6 +5,9 @@ from stdtest/specialpaths import buildDir +when defined(nimSlimSystem): + import std/syncio + import std/[ # Core: bitops, typetraits, lenientops, macros, volatile, diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 4fbea8c77..8fd9c84a5 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -187,7 +187,6 @@ proc getDocList(): seq[string] = # don't ignore these even though in lib/system (not include files) const goodSystem = """ -lib/system/io.nim lib/system/nimscript.nim lib/system/assertions.nim lib/system/iterators.nim From 772ed5eff29671b1e99ca17b63c646b341c88123 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 3 Feb 2022 11:15:46 +0800 Subject: [PATCH 3284/4254] correct typos (#19485) --- compiler/pathutils.nim | 2 +- lib/posix/posix.nim | 2 +- tests/test_nimscript.nims | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 8138a245a..3a501a417 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -12,7 +12,7 @@ import os, pathnorm -when defined(nimSlimSystem): +when defined(nimPreviewSlimSystem): import std/syncio type diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index c10fc6ac9..9c65d0732 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -37,7 +37,7 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(nimSlimSystem): +when defined(nimPreviewSlimSystem): import std/syncio # TODO these constants don't seem to be fetched from a header file for unknown diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index b380570ff..5fc77f6e4 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -5,7 +5,7 @@ from stdtest/specialpaths import buildDir -when defined(nimSlimSystem): +when defined(nimPreviewSlimSystem): import std/syncio import std/[ From 33bfe5b12cf771072d93d7316945f3f5e6c727ff Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 4 Feb 2022 20:47:03 +0800 Subject: [PATCH 3285/4254] fix parseEnum cannot parse enum with const fields (#19466) fix #19463 --- lib/std/enumutils.nim | 9 +++++++-- tests/stdlib/tstrutils.nim | 11 +++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 81e602ad5..b7d2b9f89 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -14,7 +14,7 @@ from typetraits import OrdinalEnum, HoleyEnum macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, userMin, userMax: static[int], normalizer: static[proc(s :string): string]): untyped = - # generates a case stmt, which assigns the correct enum field given + # Generates a case stmt, which assigns the correct enum field given # a normalized string comparison to the `argSym` input. # string normalization is done using passed normalizer. # NOTE: for an enum with fields Foo, Bar, ... we cannot generate @@ -49,7 +49,12 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, of nnkIntLit: fStr = f[0].strVal fNum = f[1].intVal - else: error("Invalid tuple syntax!", f[1]) + else: + let fAst = f[0].getImpl + if fAst.kind == nnkStrLit: + fStr = fAst.strVal + else: + error("Invalid tuple syntax!", f[1]) else: error("Invalid node for enum type `" & $f.kind & "`!", f) # add field if string not already added if fNum >= userMin and fNum <= userMax: diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 8000b6b07..26fc0c7b0 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -583,6 +583,17 @@ template main() = let g = parseEnum[Foo]("Bar", A) doAssert g == A + block: # bug #19463 + const CAMPAIGN_TABLE = "wikientries_campaign" + const CHARACTER_TABLE = "wikientries_character" + + type Tables = enum + a = CAMPAIGN_TABLE, + b = CHARACTER_TABLE, + + let myA = CAMPAIGN_TABLE + doAssert $parseEnum[Tables](myA) == "wikientries_campaign" + block: # check enum defined in block type Bar = enum From 7b09fd70ab8154eed3738dfd86f84c5642df3cf2 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 5 Feb 2022 06:10:24 +0800 Subject: [PATCH 3286/4254] undefine C symbols in JS backend [backport:1.6] (#19437) fix #19330; fix #19059 --- compiler/cmdlinehelper.nim | 3 ++- compiler/commands.nim | 5 +++-- tests/js/tcsymbol.nim | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/js/tcsymbol.nim diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index 007dc2319..02162755c 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -64,7 +64,8 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi if conf.cmd == cmdNimscript: return false # now process command line arguments again, because some options in the # command line can overwrite the config file's settings - extccomp.initVars(conf) + if conf.backend != backendJs: # bug #19059 + extccomp.initVars(conf) self.processCmdLine(passCmd2, "", conf) if conf.cmd == cmdNone: rawMessage(conf, errGenerated, "command missing") diff --git a/compiler/commands.nim b/compiler/commands.nim index a1fa55e74..fb2907bb1 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -899,8 +899,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; splitSwitch(conf, arg, key, val, pass, info) os.putEnv(key, val) of "cc": - expectArg(conf, switch, arg, pass, info) - setCC(conf, arg, info) + if conf.backend != backendJs: # bug #19330 + expectArg(conf, switch, arg, pass, info) + setCC(conf, arg, info) of "track": expectArg(conf, switch, arg, pass, info) track(conf, arg, info) diff --git a/tests/js/tcsymbol.nim b/tests/js/tcsymbol.nim new file mode 100644 index 000000000..07e52b9b6 --- /dev/null +++ b/tests/js/tcsymbol.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--cc:gcc; --cc:tcc" +""" + +doAssert not defined(gcc) +doAssert not defined(tcc) \ No newline at end of file From d0287748fefd9eae71cb3d66caef724473525b28 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 6 Feb 2022 15:51:03 +0800 Subject: [PATCH 3287/4254] setjump => setjmp [backport: 1.2] (#19496) --- compiler/commands.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index fb2907bb1..6d3f23197 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -238,7 +238,7 @@ const errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found" errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found" errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found" - errInvalidExceptionSystem = "'goto', 'setjump', 'cpp' or 'quirky' expected, but '$1' found" + errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found" template warningOptionNoop(switch: string) = warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch) From 6b302bb71b6d9aab708b91f8d68957652ec30480 Mon Sep 17 00:00:00 2001 From: Roj Date: Sun, 6 Feb 2022 18:28:54 -0800 Subject: [PATCH 3288/4254] Improve consistency (#19490) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 6bc7a2385..7ff056a20 100644 --- a/readme.md +++ b/readme.md @@ -28,7 +28,7 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( is the official Telegram channel. Not bridged to IRC. * [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related topics that includes posts about Nim. -* [Github Wiki][nim-wiki] - Misc user-contributed content. +* [GitHub Wiki][nim-wiki] - Misc user-contributed content. ## Compiling @@ -73,7 +73,7 @@ the installation instructions on the website to do so: https://nim-lang.org/inst For package maintainers: see [packaging guidelines](https://nim-lang.github.io/Nim/packaging.html). -First, get Nim from github: +First, get Nim from GitHub: ``` git clone https://github.com/nim-lang/Nim.git From 28180e47a99cda88abee3e2d8e130c18100f3a4f Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 7 Feb 2022 14:04:04 +0800 Subject: [PATCH 3289/4254] disable nimlsp (#19499) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 40a3aef36..456f42cd2 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -103,7 +103,7 @@ pkg "nimfp", "nim c -o:nfp -r src/fp.nim" pkg "nimgame2", "nim c -d:nimLegacyConvEnumEnum nimgame2/nimgame.nim" # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" -pkg "nimlsp" +pkg "nimlsp", allowFailure = true pkg "nimly", "nim c -r tests/test_readme_example.nim" pkg "nimongo", "nimble test_ci", allowFailure = true pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true From 4b0636fba018df407237811f9e687ed4fc249c10 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Mon, 7 Feb 2022 23:05:41 +0000 Subject: [PATCH 3290/4254] Add compilers and hints to default nim.cfg (#18424) --- config/nim.cfg | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index 59d7f48d2..7fe279f56 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -2,6 +2,7 @@ # (c) 2017 Andreas Rumpf # Feel free to edit the default values as you need. +# See https://nim-lang.org/docs/nimc.html # You may set environment variables with # @putenv "key" "val" @@ -17,11 +18,21 @@ hint[LineTooLong]=off #hint[XDeclaredButNotUsed]=off # Examples of how to setup a cross-compiler: +# Nim can target architectures and OSes different than the local host +# Syntax: ..gcc.exe = "" +# ..gcc.linkerexe = "" -# Cross-compiling for Raspberry Pi. -# (This compiler is available in gcc-arm-linux-gnueabihf package on Ubuntu) +# ARM e.g. Raspberry Pi 2: gcc-arm-linux-gnueabihf package on Debian/Ubuntu arm.linux.gcc.exe = "arm-linux-gnueabihf-gcc" arm.linux.gcc.linkerexe = "arm-linux-gnueabihf-gcc" +# ARM64/aarch64 e.g. Raspberry Pi 3: gcc-aarch64-linux-gnu package on Debian/Ubuntu +arm64.linux.gcc.exe = "aarch64-linux-gnu-gcc" +arm64.linux.gcc.linkerexe = "aarch64-linux-gnu-gcc" +# RISC-V: gcc-riscv64-linux-gnu package on Debian/Ubuntu +riscv32.linux.gcc.exe = "riscv64-linux-gnu-gcc" +riscv32.linux.gcc.linkerexe = "riscv64-linux-gnu-gcc" +riscv64.linux.gcc.exe = "riscv64-linux-gnu-gcc" +riscv64.linux.gcc.linkerexe = "arm-linux-gnueabihf-gcc" # For OpenWRT, you will also need to adjust PATH to point to your toolchain. mips.linux.gcc.exe = "mips-openwrt-linux-gcc" From 801c0f0369779a47da2ef6618abea11feb390973 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Tue, 8 Feb 2022 02:11:53 +0300 Subject: [PATCH 3291/4254] Fix bug 27 of #17340 (#19433) Fixes silent disappearance of Markdown (pseudo-)link when it's detected as unsafe protocol. Now it will be converted to plain text in spirit of [the specification](https://spec.commonmark.org/0.30/#links). For that sake the check for protocol is added to rst.nim also. --- lib/packages/docutils/rst.nim | 66 +++++++++++++++++++++++--------- lib/packages/docutils/rstgen.nim | 17 ++------ tests/stdlib/trst.nim | 27 ++++++++++--- tests/stdlib/trstgen.nim | 11 +++++- 4 files changed, 81 insertions(+), 40 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 93c2231dc..d4bfae48f 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -222,7 +222,7 @@ import os, strutils, rstast, dochelpers, std/enumutils, algorithm, lists, sequtils, - std/private/miscdollars, tables + std/private/miscdollars, tables, strscans from highlite import SourceLanguage, getSourceLanguage type @@ -1347,7 +1347,20 @@ proc match(p: RstParser, start: int, expr: string): bool = inc i result = true -proc fixupEmbeddedRef(n, a, b: PRstNode) = +proc safeProtocol*(linkStr: var string): string = + # Returns link's protocol and, if it's not safe, clears `linkStr` + result = "" + if scanf(linkStr, "$w:", result): + # if it has a protocol at all, ensure that it's not 'javascript:' or worse: + if cmpIgnoreCase(result, "http") == 0 or + cmpIgnoreCase(result, "https") == 0 or + cmpIgnoreCase(result, "ftp") == 0: + discard "it's fine" + else: + linkStr = "" + +proc fixupEmbeddedRef(p: var RstParser, n, a, b: PRstNode): bool = + # Returns `true` if the link belongs to an allowed protocol var sep = - 1 for i in countdown(n.len - 2, 0): if n.sons[i].text == "<": @@ -1355,7 +1368,15 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) = break var incr = if sep > 0 and n.sons[sep - 1].text[0] == ' ': 2 else: 1 for i in countup(0, sep - incr): a.add(n.sons[i]) - for i in countup(sep + 1, n.len - 2): b.add(n.sons[i]) + var linkStr = "" + for i in countup(sep + 1, n.len - 2): linkStr.add(n.sons[i].addNodes) + if linkStr != "": + let protocol = safeProtocol(linkStr) + result = linkStr != "" + if not result: + rstMessage(p, mwBrokenLink, protocol, + p.tok[p.idx-3].line, p.tok[p.idx-3].col) + b.add newLeaf(linkStr) proc whichRole(p: RstParser, sym: string): RstNodeKind = result = whichRoleAux(sym) @@ -1407,14 +1428,17 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">": var a = newRstNode(rnInner) var b = newRstNode(rnInner) - fixupEmbeddedRef(n, a, b) - if a.len == 0: - newKind = rnStandaloneHyperlink - newSons = @[b] - else: - newKind = rnHyperlink - newSons = @[a, b] - setRef(p, rstnodeToRefname(a), b, implicitHyperlinkAlias) + if fixupEmbeddedRef(p, n, a, b): + if a.len == 0: # e.g. ``_ + newKind = rnStandaloneHyperlink + newSons = @[b] + else: # e.g. `link title `_ + newKind = rnHyperlink + newSons = @[a, b] + setRef(p, rstnodeToRefname(a), b, implicitHyperlinkAlias) + else: # include as plain text, not a link + newKind = rnInner + newSons = n.sons result = newRstNode(newKind, newSons) else: # some link that will be resolved in `resolveSubs` newKind = rnRef @@ -1623,7 +1647,6 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = result.add(lb) proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = - result = true var desc, link = "" var i = p.idx @@ -1642,14 +1665,21 @@ proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = parse("]", desc) if p.tok[i].symbol != "(": return false + let linkIdx = i + 1 parse(")", link) - let child = newRstNode(rnHyperlink) - child.add desc - child.add link # only commit if we detected no syntax error: - father.add child - p.idx = i - result = true + let protocol = safeProtocol(link) + if link == "": + result = false + rstMessage(p, mwBrokenLink, protocol, + p.tok[linkIdx].line, p.tok[linkIdx].col) + else: + let child = newRstNode(rnHyperlink) + child.add desc + child.add link + father.add child + p.idx = i + result = true proc getFootnoteType(label: PRstNode): (FootnoteType, int) = if label.sons.len >= 1 and label.sons[0].kind == rnLeaf and diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index d2180cb91..d662a667c 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -40,7 +40,7 @@ ## can be done by simply searching for [footnoteName]. import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, - algorithm, parseutils, std/strbasics, strscans + algorithm, parseutils, std/strbasics import ../../std/private/since @@ -826,17 +826,6 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) = "\\rstov$4[$5]{$3}$2\n", [$n.level, rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName]) - -proc safeProtocol(linkStr: var string) = - var protocol = "" - if scanf(linkStr, "$w:", protocol): - # if it has a protocol at all, ensure that it's not 'javascript:' or worse: - if cmpIgnoreCase(protocol, "http") == 0 or cmpIgnoreCase(protocol, "https") == 0 or - cmpIgnoreCase(protocol, "ftp") == 0: - discard "it's fine" - else: - linkStr = "" - proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) = dispA(d.target, result, "

    • $2
    • \n", @@ -901,7 +890,7 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = # support for `:target:` links for images: var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl) - safeProtocol(target) + discard safeProtocol(target) if target.len > 0: # `htmlOut` needs to be of the following format for link to work for images: @@ -1205,7 +1194,7 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, d.escMode = emUrl renderRstToOut(d, link, linkStr) d.escMode = mode - safeProtocol(linkStr) + discard safeProtocol(linkStr) var textStr = "" renderRstToOut(d, text, textStr) let nimDocStr = if nimdoc: " nimdoc" else: "" diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 771e02477..8b98d1403 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -843,12 +843,7 @@ suite "Warnings": rnInner rnLeaf 'foo' rnInner - rnLeaf '#' - rnLeaf 'foo' - rnLeaf ',' - rnLeaf 'string' - rnLeaf ',' - rnLeaf 'string' + rnLeaf '#foo,string,string' rnParagraph anchor='foo' rnLeaf 'Paragraph' rnLeaf '.' @@ -1256,3 +1251,23 @@ suite "RST inline markup": rnLeaf 'my {link example' rnLeaf 'http://example.com/bracket_(symbol_[)' """) + + test "not a Markdown link": + # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe + var warnings = new seq[string] + check("[T](f: var Foo)".toAst(warnings = warnings) == + dedent""" + rnInner + rnLeaf '[' + rnLeaf 'T' + rnLeaf ']' + rnLeaf '(' + rnLeaf 'f' + rnLeaf ':' + rnLeaf ' ' + rnLeaf 'var' + rnLeaf ' ' + rnLeaf 'Foo' + rnLeaf ')' + """) + check(warnings[] == @["input(1, 5) Warning: broken link 'f'"]) diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 995c0a151..2c28fe506 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1593,8 +1593,15 @@ suite "invalid targets": test "invalid links": check("(([Nim](https://nim-lang.org/)))".toHtml == """((Nim))""") - check("(([Nim](javascript://nim-lang.org/)))".toHtml == - """((Nim))""") + # unknown protocol is treated just like plain text, not a link + var warnings = new seq[string] + check("(([Nim](javascript://nim-lang.org/)))".toHtml(warnings=warnings) == + """(([Nim](javascript://nim-lang.org/)))""") + check(warnings[] == @["input(1, 9) Warning: broken link 'javascript'"]) + warnings[].setLen 0 + check("`Nim `_".toHtml(warnings=warnings) == + """Nim <javascript://nim-lang.org/>""") + check(warnings[] == @["input(1, 33) Warning: broken link 'javascript'"]) suite "local file inclusion": test "cannot include files in sandboxed mode": From 27e548140b0f51a8dbc6f6094764e02f08ae509e Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 8 Feb 2022 15:34:44 +0800 Subject: [PATCH 3292/4254] don't use a temp for addr [backport: 1.6] (#19503) * don't use a temp for addr fix #19497 * Update compiler/ccgcalls.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * add a test Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- compiler/ccgcalls.nim | 4 ++-- tests/arc/tarc_orc.nim | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/arc/tarc_orc.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 197728ccf..ce5fbfdd7 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -376,8 +376,8 @@ proc genParams(p: BProc, ri: PNode, typ: PType): Rope = if not needTmp[i - 1]: needTmp[i - 1] = potentialAlias(n, potentialWrites) getPotentialWrites(ri[i], false, potentialWrites) - if ri[i].kind == nkHiddenAddr: - # Optimization: don't use a temp, if we would only take the adress anyway + if ri[i].kind in {nkHiddenAddr, nkAddr}: + # Optimization: don't use a temp, if we would only take the address anyway needTmp[i - 1] = false for i in 1.. Date: Fri, 11 Feb 2022 18:16:27 +0800 Subject: [PATCH 3293/4254] fix #16458; make useNimRtl compile for --gc:orc (#19512) * fix #16458; make useNimRtl compile for --gc:orc/arc * fix tests --- lib/system/mmdisp.nim | 5 +++-- lib/system/orc.nim | 4 ++-- lib/system/seqs_v2.nim | 3 ++- tests/arc/t16458.nim | 6 ++++++ 4 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 tests/arc/t16458.nim diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 3317ba627..e5038387f 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -82,8 +82,9 @@ else: # XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here include "system/gc_regions" elif defined(nimV2) or usesDestructors: - var allocator {.rtlThreadVar.}: MemRegion - instantiateForRegion(allocator) + when not defined(useNimRtl): + var allocator {.rtlThreadVar.}: MemRegion + instantiateForRegion(allocator) when defined(gcHooks): include "system/gc_hooks" elif defined(gcMarkAndSweep): diff --git a/lib/system/orc.nim b/lib/system/orc.nim index f9f5cd81f..4c23aea6c 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -119,7 +119,7 @@ template orcAssert(cond, msg) = when logOrc: proc strstr(s, sub: cstring): cstring {.header: "", importc.} -proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inline.} = +proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inl.} = let p = cast[ptr pointer](q) if p[] != nil: @@ -128,7 +128,7 @@ proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inli var j = cast[ptr GcEnv](env) j.traceStack.add(p, desc) -proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inline.} = +proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inl.} = let p = cast[ptr pointer](q) if p[] != nil: var j = cast[ptr GcEnv](env) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 0c487b31d..1194f40ef 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -75,7 +75,8 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} = when nimvm: - setLen(x, newLen) + {.cast(tags: []).}: + setLen(x, newLen) else: #sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" when not supportsCopyMem(T): diff --git a/tests/arc/t16458.nim b/tests/arc/t16458.nim new file mode 100644 index 000000000..6ae114287 --- /dev/null +++ b/tests/arc/t16458.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--gc:orc --d:useNimRtl" + action: "compile" +""" + +echo 134 \ No newline at end of file From ed0dce7292480002be96d0ea5b7775c38767134d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 Feb 2022 15:10:45 +0100 Subject: [PATCH 3294/4254] fixes #19404 by protecting the memory we borrow from. this replaces crashes with minor memory leaks which seems to be acceptable. In the longer run we need a better VM that didn't grow hacks over a decade. (#19515) Co-authored-by: flywind --- compiler/vm.nim | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 3343eb781..259648add 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -85,9 +85,9 @@ proc bailOut(c: PCtx; tos: PStackFrame) = when not defined(nimComputedGoto): {.pragma: computedGoto.} -proc ensureKind(n: var TFullReg, kind: TRegisterKind) = - if n.kind != kind: - n = TFullReg(kind: kind) +proc ensureKind(n: var TFullReg, k: TRegisterKind) {.inline.} = + if n.kind != k: + n = TFullReg(kind: k) template ensureKind(k: untyped) {.dirty.} = ensureKind(regs[ra], k) @@ -521,6 +521,11 @@ template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool = when not defined(nimHasSinkInference): {.pragma: nosinks.} +template takeAddress(reg, source) = + reg.nodeAddr = addr source + when defined(gcDestructors): + GC_ref source + proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -679,7 +684,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let idx = regs[rc].intVal.int let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[] if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len: - regs[ra].nodeAddr = addr src.sons[idx] + takeAddress regs[ra], src.sons[idx] else: stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1)) of opcLdStrIdx: @@ -747,11 +752,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of nkObjConstr: let n = src.sons[rc + 1] if n.kind == nkExprColonExpr: - regs[ra].nodeAddr = addr n.sons[1] + takeAddress regs[ra], n.sons[1] else: - regs[ra].nodeAddr = addr src.sons[rc + 1] + takeAddress regs[ra], src.sons[rc + 1] else: - regs[ra].nodeAddr = addr src.sons[rc] + takeAddress regs[ra], src.sons[rc] of opcWrObj: # a.b = c decodeBC(rkNode) @@ -778,7 +783,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNodeAddr) case regs[rb].kind of rkNode: - regs[ra].nodeAddr = addr(regs[rb].node) + takeAddress regs[ra], regs[rb].node of rkNodeAddr: # bug #14339 regs[ra].nodeAddr = regs[rb].nodeAddr else: From 551225d88808c6029d9246cf2bea5da349d1eb43 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Mon, 14 Feb 2022 08:50:38 +0100 Subject: [PATCH 3295/4254] Remove backslash in glob pattern (#19524) --- lib/pure/os.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 76164bc49..7c0c64276 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2131,7 +2131,7 @@ iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noWeirdT ## Iterate over all the files and directories that match the `pattern`. ## ## On POSIX this uses the `glob`:idx: call. - ## `pattern` is OS dependent, but at least the `"\*.ext"` + ## `pattern` is OS dependent, but at least the `"*.ext"` ## notation is supported. ## ## See also: @@ -2150,7 +2150,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTar ## Iterate over all the files that match the `pattern`. ## ## On POSIX this uses the `glob`:idx: call. - ## `pattern` is OS dependent, but at least the `"\*.ext"` + ## `pattern` is OS dependent, but at least the `"*.ext"` ## notation is supported. ## ## See also: @@ -2167,7 +2167,7 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarg ## Iterate over all the directories that match the `pattern`. ## ## On POSIX this uses the `glob`:idx: call. - ## `pattern` is OS dependent, but at least the `"\*.ext"` + ## `pattern` is OS dependent, but at least the `"*.ext"` ## notation is supported. ## ## See also: From cda77c15209519ea04f889a826ac79c7cbb7e152 Mon Sep 17 00:00:00 2001 From: David Krause Date: Mon, 14 Feb 2022 08:56:35 +0100 Subject: [PATCH 3296/4254] use OrderedTable instead of OrderedTableRef for mimedb (#19522) * use OrderedTable instead of OrderedTableRef for mimedb Signed-off-by: David Krause * added changelog entry for mimedb change Signed-off-by: David Krause --- changelog.md | 2 ++ lib/pure/mimetypes.nim | 4 ++-- tests/stdlib/tmimetypes.nim | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 412e046eb..b21784bae 100644 --- a/changelog.md +++ b/changelog.md @@ -40,6 +40,8 @@ becomes an alias for `addr`. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. +- Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. + ## Language changes - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index 6ae63a0ae..d1566d897 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -31,7 +31,7 @@ from strutils import startsWith, toLowerAscii, strip type MimeDB* = object - mimes: OrderedTableRef[string, string] + mimes: OrderedTable[string, string] const mimes* = { "123": "application/vnd.lotus-1-2-3", @@ -1904,7 +1904,7 @@ func newMimetypes*(): MimeDB = ## Creates a new Mimetypes database. The database will contain the most ## common mimetypes. {.cast(noSideEffect).}: - result.mimes = mimes.newOrderedTable() + result.mimes = mimes.toOrderedTable() func getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string = ## Gets mimetype which corresponds to `ext`. Returns `default` if `ext` diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim index 93c20d4a3..6435309e1 100644 --- a/tests/stdlib/tmimetypes.nim +++ b/tests/stdlib/tmimetypes.nim @@ -7,6 +7,8 @@ template main() = var m = newMimetypes() doAssert m.getMimetype("mp4") == "video/mp4" doAssert m.getExt("application/json") == "json" + m.register("foo", "baa") + doAssert m.getMimetype("foo") == "baa" # see also `runnableExamples`. # xxx we should have a way to avoid duplicating code between runnableExamples and tests From 42eeab5fd181ffca6d1197b704a15f056939cfa8 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 14 Feb 2022 00:09:21 -0800 Subject: [PATCH 3297/4254] Remove Deprecated oids.oidsToString (#19519) * Remove deprecated oids.oidToString * Remove deprecated oids.oidToString --- changelog.md | 2 ++ lib/pure/oids.nim | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index b21784bae..ec13152d0 100644 --- a/changelog.md +++ b/changelog.md @@ -39,6 +39,8 @@ becomes an alias for `addr`. - Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. +- Removed deprecated `oids.oidToString`. + - Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index da285a187..776c046b1 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -67,11 +67,6 @@ template toStringImpl[T: string | cstring](result: var T, oid: Oid) = when T is cstring: result[N] = '\0' -proc oidToString*(oid: Oid, str: cstring) {.deprecated: "unsafe; use `$`".} = - ## Converts an oid to a string which must have space allocated for 25 elements. - # work around a compiler bug: - var str = str - toStringImpl(str, oid) proc `$`*(oid: Oid): string = ## Converts an OID to a string. From 8e8231f9d6e586a32af7b80892244dc1033db871 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 14 Feb 2022 05:35:33 -0800 Subject: [PATCH 3298/4254] Remove deprecated math.c_frexp (#19518) * Remove Deprecated math proc * Remove Deprecated math proc * Remove Deprecated math proc --- changelog.md | 3 +++ lib/pure/math.nim | 5 ----- tests/stdlib/tmath.nim | 6 ------ 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index ec13152d0..3fd66dba8 100644 --- a/changelog.md +++ b/changelog.md @@ -44,6 +44,9 @@ becomes an alias for `addr`. - Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. +- Removed deprecated `math.c_frexp`. + + ## Language changes - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 66f1a2e2c..1c47258bc 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -69,11 +69,6 @@ when defined(c) or defined(cpp): proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "".} - func c_frexp*(x: cfloat, exponent: var cint): cfloat {. - importc: "frexpf", header: "", deprecated: "Use `frexp` instead".} - func c_frexp*(x: cdouble, exponent: var cint): cdouble {. - importc: "frexp", header: "", deprecated: "Use `frexp` instead".} - # don't export `c_frexp` in the future and remove `c_frexp2`. func c_frexp2(x: cfloat, exponent: var cint): cfloat {. importc: "frexpf", header: "".} diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 9bc5b994f..5e501c09b 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -437,12 +437,6 @@ template main() = doAssert lgamma(-0.0) == Inf doAssert lgamma(-1.0) == Inf - when nimvm: discard - else: - var exponent: cint - doAssert c_frexp(0.0, exponent) == 0.0 - doAssert c_frexp(-0.0, exponent) == -0.0 - doAssert classify(c_frexp(-0.0, exponent)) == fcNegZero static: main() main() From 2ef71c0a46b2209c906921f10f585306ce6199cc Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 14 Feb 2022 21:36:01 +0800 Subject: [PATCH 3299/4254] [testcase] genSym fails to make unique identifier for ref object types (#19506) close #15118 --- tests/macros/tmacros_various.nim | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 00d74cb5c..d702db56a 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -23,6 +23,8 @@ x: some string ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) 0 +0 +0 ''' """ @@ -270,3 +272,61 @@ block: # bug #13511 debugAst: add(foo(), component) + +block: # bug #15118 + macro flop(name: static string) = + let id = genSym(nskType, "env") + let r = + nnkStmtList.newTree( + nnkTypeSection.newTree( + nnkTypeDef.newTree( + id, + newEmptyNode(), + nnkRefTy.newTree( + nnkObjectTy.newTree( + newEmptyNode(), + newEmptyNode(), + nnkRecList.newTree( + nnkIdentDefs.newTree( + newIdentNode(name), + newIdentNode("int"), + newEmptyNode() + ) + ) + ) + ) + ) + ), + + # var f: T + + nnkVarSection.newTree( + nnkIdentDefs.newTree( + newIdentNode("f"), + id, + newEmptyNode() + ) + ), + + # echo f.a + nnkCommand.newTree( + newIdentNode("new"), + newIdentNode("f") + ), + + nnkCommand.newTree( + newIdentNode("echo"), + nnkDotExpr.newTree( + newIdentNode("f"), + newIdentNode(name) + ) + ) + ) + r + + + block: + flop("a") + + block: + flop("b") From b2c5d7b4ff070abe2145e998d090fb15b4df522f Mon Sep 17 00:00:00 2001 From: Sizhe Zhao Date: Tue, 15 Feb 2022 06:15:59 +0800 Subject: [PATCH 3300/4254] Documentation: Fix word usage (#19529) --- doc/lib.rst | 2 +- lib/pure/base64.nim | 4 ++-- lib/pure/hashes.nim | 2 +- lib/pure/md5.nim | 4 ++-- lib/std/sha1.nim | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/lib.rst b/doc/lib.rst index 881d857d3..f72012777 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -446,7 +446,7 @@ Hashing from the MongoDB interface and it thus binary compatible with a MongoDB OID. * `sha1 `_ - This module implements a sha1 encoder and decoder. + This module implements the SHA-1 checksum algorithm. Miscellaneous diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 513ec5826..9b7af88ef 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -56,8 +56,8 @@ runnableExamples: ## ======== ## ## * `hashes module`_ for efficient computations of hash values for diverse Nim types -## * `md5 module`_ implements the MD5 checksum algorithm -## * `sha1 module`_ implements a sha1 encoder and decoder +## * `md5 module`_ for the MD5 checksum algorithm +## * `sha1 module`_ for the SHA-1 checksum algorithm template cbBase(a, b): untyped = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index d9f534670..47dacec7d 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -62,7 +62,7 @@ runnableExamples: ## ======== ## * `md5 module `_ for the MD5 checksum algorithm ## * `base64 module `_ for a Base64 encoder and decoder -## * `std/sha1 module `_ for a SHA-1 encoder and decoder +## * `std/sha1 module `_ for the SHA-1 checksum algorithm ## * `tables module `_ for hash tables import std/private/since diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index 06c5608a4..cd4d1e6b8 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -13,8 +13,8 @@ ## ## See also ## ======== -## * `base64 module`_ implements a Base64 encoder and decoder -## * `std/sha1 module `_ for a SHA-1 encoder and decoder +## * `base64 module`_ for a Base64 encoder and decoder +## * `std/sha1 module `_ for the SHA-1 checksum algorithm ## * `hashes module`_ for efficient computations of hash values ## for diverse Nim types diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 120a81702..ed962707b 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -12,9 +12,9 @@ ## ## See also ## ======== -## * `base64 module`_ implements a Base64 encoder and decoder +## * `base64 module`_ for a Base64 encoder and decoder ## * `hashes module`_ for efficient computations of hash values for diverse Nim types -## * `md5 module`_ implements the MD5 checksum algorithm +## * `md5 module`_ for the MD5 checksum algorithm runnableExamples: let accessName = secureHash("John Doe") From 30e9f23ec04618616dcf2aaa7980794bad2135ed Mon Sep 17 00:00:00 2001 From: rockcavera Date: Thu, 17 Feb 2022 08:48:57 -0300 Subject: [PATCH 3301/4254] Update chcks.nim (#19540) --- lib/system/chcks.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 8c7c95795..a404e9d40 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -29,7 +29,7 @@ proc raiseFieldError(f: string) {.compilerproc, noinline.} = ## remove after bootstrap > 1.5.1 sysFatal(FieldDefect, f) -when defined(gcdestructors): +when defined(nimV2): proc raiseFieldError2(f: string, discVal: int) {.compilerproc, noinline.} = ## raised when field is inaccessible given runtime value of discriminant sysFatal(FieldError, f & $discVal & "'") From f019e999d491ecf462421bd750aec0465d308094 Mon Sep 17 00:00:00 2001 From: tersec Date: Fri, 18 Feb 2022 15:06:11 +0000 Subject: [PATCH 3302/4254] keep casing of noinit and noreturn pragmas consistently documented (#19535) --- doc/manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 2469a0525..e45133c38 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2818,7 +2818,7 @@ The implicit initialization can be avoided for optimization reasons with the .. code-block:: nim var - a {.noInit.}: array[0..1023, char] + a {.noinit.}: array[0..1023, char] If a proc is annotated with the `noinit` pragma, this refers to its implicit `result` variable: @@ -6636,7 +6636,7 @@ but accessed at runtime: doAssert nameToProc[2][1]() == "baz" -noReturn pragma +noreturn pragma --------------- The `noreturn` pragma is used to mark a proc that never returns. From 516db3bac389ea554166ee1a6671b5005159a30a Mon Sep 17 00:00:00 2001 From: locriacyber <74560659+locriacyber@users.noreply.github.com> Date: Fri, 18 Feb 2022 22:24:42 +0000 Subject: [PATCH 3303/4254] Remove trailing space in `nim r` command; Amend one error message (#19487) --- compiler/nim.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/nim.nim b/compiler/nim.nim index b8256d576..86c7ab524 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -116,7 +116,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = if cmdPrefix.len > 0: cmdPrefix.add " " # without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic: # `The parameter is incorrect` - execExternalProgram(conf, cmdPrefix & output.quoteShell & ' ' & conf.arguments) + let cmd = cmdPrefix & output.quoteShell & ' ' & conf.arguments + execExternalProgram(conf, cmd.strip(leading=false,trailing=true)) of cmdDocLike, cmdRst2html, cmdRst2tex: # bugfix(cmdRst2tex was missing) if conf.arguments.len > 0: # reserved for future use From 0c915b5e47e554d657f6533f262cebbcf1554e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Thu, 24 Feb 2022 08:31:40 +0100 Subject: [PATCH 3304/4254] compile pragma: cache the result sooner (#19554) extccomp.addExternalFileToCompile() relies on hashes to decide whether an external C file needs recompilation or not. Due to short-circuit evaluation of boolean expressions, the procedure that generates a corresponding hash file is not called the first time an external file is compiled, so an avoidable recompilation is triggered the next build. This patch fixes that by moving the proc call with a desired side effect from its boolean expression, so it's executed unconditionally. --- compiler/extccomp.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e7e1bcd51..124cc2c34 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -649,8 +649,10 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = close(f) proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = + # we want to generate the hash file unconditionally + let extFileChanged = externalFileChanged(conf, c) if optForceFullMake notin conf.globalOptions and fileExists(c.obj) and - not externalFileChanged(conf, c): + not extFileChanged: c.flags.incl CfileFlag.Cached else: # make sure Nim keeps recompiling the external file on reruns From 340b5a1676062aa9bc7f17a2e078eaba96821bf3 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 25 Feb 2022 07:16:46 +1100 Subject: [PATCH 3305/4254] Document links repect --out in .idx file (#19543) * Link in .idx file now respects --out:file switch * Use clearer chained calls Co-authored-by: Clay Sweetser --- compiler/docgen.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 3e61032d8..aad3b9409 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1499,7 +1499,10 @@ proc genOutFile(d: PDoc, groupedToc = false): string = # Extract the title. Non API modules generate an entry in the index table. if d.meta[metaTitle].len != 0: title = d.meta[metaTitle] - let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnixPath + let external = AbsoluteFile(d.destFile) + .relativeTo(d.conf.outDir, '/') + .changeFileExt(HtmlExt) + .string setIndexTerm(d[], external, "", title) else: # Modules get an automatic title for the HTML, but no entry in the index. From 9a49451124a781a2cd032b6e7616c67a7815fe57 Mon Sep 17 00:00:00 2001 From: PMunch Date: Fri, 25 Feb 2022 10:43:03 +0100 Subject: [PATCH 3306/4254] Remove volatiles when compiling with ARC/ORC (#19545) This removes volatiles on ARC/ORC targets in NimMain and PreMainInner. This avoids an issue where they couldn't be optimised out on microcontrollers leading to larger code. Since the stack bottom doesn't have to be initialised this way when using ARC or ORC (or None, which is also covered by this PR) these can be safely removed. --- compiler/cgen.nim | 68 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 10b4b55d0..b78ad10c4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1363,16 +1363,25 @@ proc genMainProc(m: BModule) = # The use of a volatile function pointer to call Pre/NimMainInner # prevents inlining of the NimMainInner function and dependent # functions, which might otherwise merge their stack frames. - PreMainBody = "$N" & + + PreMainVolatileBody = + "\tvoid (*volatile inner)(void);$N" & + "\tinner = PreMainInner;$N" & + "$1" & + "\t(*inner)();$N" + + PreMainNonVolatileBody = + "$1" & + "\tPreMainInner();$N" + + PreMainBodyStart = "$N" & "N_LIB_PRIVATE void PreMainInner(void) {$N" & "$2" & "}$N$N" & PosixCmdLine & - "N_LIB_PRIVATE void PreMain(void) {$N" & - "\tvoid (*volatile inner)(void);$N" & - "\tinner = PreMainInner;$N" & - "$1" & - "\t(*inner)();$N" & + "N_LIB_PRIVATE void PreMain(void) {$N" + + PreMainBodyEnd = "}$N$N" MainProcs = @@ -1385,17 +1394,32 @@ proc genMainProc(m: BModule) = "$1" & "}$N$N" - NimMainProc = - "N_CDECL(void, $5NimMain)(void) {$N" & - "\tvoid (*volatile inner)(void);$N" & - "$4" & - "\tinner = NimMainInner;$N" & - "$2" & - "\t(*inner)();$N" & + NimMainVolatileBody = + "\tvoid (*volatile inner)(void);$N" & + "$4" & + "\tinner = NimMainInner;$N" & + "$2" & + "\t(*inner)();$N" + + NimMainNonVolatileBody = + "$4" & + "$2" & + "\tNimMainInner();$N" + + NimMainProcStart = + "N_CDECL(void, $5NimMain)(void) {$N" + + NimMainProcEnd = "}$N$N" + NimMainProc = NimMainProcStart & NimMainVolatileBody & NimMainProcEnd + + NimSlimMainProc = NimMainProcStart & NimMainNonVolatileBody & NimMainProcEnd + NimMainBody = NimMainInner & NimMainProc + NimSlimMainBody = NimMainInner & NimSlimMainProc + PosixCMain = "int main(int argc, char** args, char** env) {$N" & "\tcmdLine = args;$N" & @@ -1456,10 +1480,13 @@ proc genMainProc(m: BModule) = m.includeHeader("") let initStackBottomCall = - if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope + if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []) inc(m.labels) - appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit]) + if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: + appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit]) + else: + appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainNonVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit]) if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: @@ -1484,9 +1511,14 @@ proc genMainProc(m: BModule) = appcg(m, m.s[cfsProcs], nimMain, [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) else: - const nimMain = NimMainBody - appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) + if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: + const nimMain = NimMainBody + appcg(m, m.s[cfsProcs], nimMain, + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) + else: + const nimMain = NimSlimMainBody + appcg(m, m.s[cfsProcs], nimMain, + [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) if optNoMain notin m.config.globalOptions: if m.config.cppCustomNamespace.len > 0: From fe791c67b4c028d2e439e6f74e0a4225ba6cc2f1 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 25 Feb 2022 01:43:35 -0800 Subject: [PATCH 3307/4254] Remove Deprecated jsre func (#19551) * Remove Deprecated jsre func * Remove Deprecated jsre func * ReStart CI, because OSX is dumb and I have no permission to restart --- changelog.md | 2 +- lib/js/jsre.nim | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 3fd66dba8..cbad9b4e6 100644 --- a/changelog.md +++ b/changelog.md @@ -43,7 +43,7 @@ becomes an alias for `addr`. - Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. - +- Removed deprecated `jsre.test` and `jsre.toString`. - Removed deprecated `math.c_frexp`. diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index a23fccaa8..cd8fb2be7 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -47,10 +47,6 @@ func toCstring*(self: RegExp): cstring {.importjs: "#.toString()".} func `$`*(self: RegExp): string = $toCstring(self) -func test*(self: RegExp; pattern: cstring): bool {.importjs: "#.test(#)", deprecated: "Use contains instead".} - -func toString*(self: RegExp): cstring {.importjs: "#.toString()", deprecated: "Use toCstring instead".} - func contains*(pattern: cstring; self: RegExp): bool = ## Tests for a substring match in its string parameter. runnableExamples: From ef3f343ec2979d22a5d4e51f4328e4a4c21d68dc Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 25 Feb 2022 12:57:58 +0100 Subject: [PATCH 3308/4254] Allow std/macros.params to work with nnkProcTy (#19563) * Allow std/macros.params to work with nnkProcTy * Add tests for proc params & pragma --- lib/core/macros.nim | 15 +++++++++++---- tests/macros/tprochelpers.nim | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tests/macros/tprochelpers.nim diff --git a/lib/core/macros.nim b/lib/core/macros.nim index c0e6e5154..4d040cebc 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1271,12 +1271,19 @@ proc `name=`*(someProc: NimNode; val: NimNode) = else: someProc[0] = val proc params*(someProc: NimNode): NimNode = - someProc.expectRoutine - result = someProc[3] + if someProc.kind == nnkProcTy: + someProc[0] + else: + someProc.expectRoutine + someProc[3] + proc `params=`* (someProc: NimNode; params: NimNode) = - someProc.expectRoutine expectKind(params, nnkFormalParams) - someProc[3] = params + if someProc.kind == nnkProcTy: + someProc[0] = params + else: + someProc.expectRoutine + someProc[3] = params proc pragma*(someProc: NimNode): NimNode = ## Get the pragma of a proc type. diff --git a/tests/macros/tprochelpers.nim b/tests/macros/tprochelpers.nim new file mode 100644 index 000000000..d95a2ced8 --- /dev/null +++ b/tests/macros/tprochelpers.nim @@ -0,0 +1,22 @@ +import std/macros +import stdtest/testutils + +macro test1(prc: untyped): untyped = + assertAll: + prc.params.len == 2 + prc.params[1].len == 4 + prc.pragma.len == 2 + + prc.params = nnkFormalParams.newTree( + ident("int") + ) + prc.pragma = newEmptyNode() + + assertAll: + prc.params.len == 1 + prc.pragma.len == 0 + prc + +proc test(a, b: int): int {.gcsafe, raises: [], test1.} = 5 + +type hello = proc(a, b: int): int {.gcsafe, raises: [], test1.} From 9c17a32e0ec45de83c21d84f98be7f351ccd1172 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 26 Feb 2022 03:33:28 +0800 Subject: [PATCH 3309/4254] fix #19266; allow reassign discriminant field (#19567) * add inUncheckedAssignSection * add one more test --- compiler/ccgexprs.nim | 16 +++++++++++++++- compiler/ccgstmts.nim | 2 +- compiler/cgendata.nim | 1 + tests/objvariant/treassign.nim | 22 ++++++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1f1035115..9848366a1 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2932,7 +2932,21 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard of nkPragma: genPragma(p, n) - of nkPragmaBlock: expr(p, n.lastSon, d) + of nkPragmaBlock: + var inUncheckedAssignSection = 0 + let pragmaList = n[0] + for pi in pragmaList: + if whichPragma(pi) == wCast: + case whichPragma(pi[1]) + of wUncheckedAssign: + inUncheckedAssignSection = 1 + else: + discard + + inc p.inUncheckedAssignSection, inUncheckedAssignSection + expr(p, n.lastSon, d) + dec p.inUncheckedAssignSection, inUncheckedAssignSection + of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: if n[genericParamsPos].kind == nkEmpty: var prc = n[namePos].sym diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 58a6dd015..240fa55c8 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1566,7 +1566,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = initLocExpr(p, e[0], a) getTemp(p, a.t, tmp) expr(p, e[1], tmp) - if optTinyRtti notin p.config.globalOptions: + if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0: let field = dotExpr[1].sym genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field) message(p.config, e.info, warnCaseTransition) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 88b8d4090..449076725 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -99,6 +99,7 @@ type withinTryWithExcept*: int # required for goto based exception handling withinBlockLeaveActions*: int # complex to explain sigConflicts*: CountTable[string] + inUncheckedAssignSection*: int TTypeSeq* = seq[PType] TypeCache* = Table[SigHash, Rope] diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim index 9549cb29c..527204616 100644 --- a/tests/objvariant/treassign.nim +++ b/tests/objvariant/treassign.nim @@ -34,3 +34,25 @@ proc passToVar(x: var Token) = discard t.curr = TokenObject(kind: t.curr.kind, foo: "abc") t.curr.kind = Token.foo + + +block: + type + TokenKind = enum + strLit, intLit + Token = object + case kind*: TokenKind + of strLit: + s*: string + of intLit: + i*: int64 + + var t = Token(kind: strLit, s: "abc") + + {.cast(uncheckedAssign).}: + + # inside the 'cast' section it is allowed to assign to the 't.kind' field directly: + t.kind = intLit + + {.cast(uncheckedAssign).}: + t.kind = strLit \ No newline at end of file From f0bfc0bd3f619c0933df5b71a0a04d4181d99880 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 25 Feb 2022 11:34:16 -0800 Subject: [PATCH 3310/4254] Remove define for jsfetch (#19530) * Remove define nimExperimentalAsyncjsThen for std/asyncjs.then and std/jsfetch * Remove define nimExperimentalAsyncjsThen for std/asyncjs.then and std/jsfetch * Remove define nimExperimentalAsyncjsThen for std/asyncjs.then and std/jsfetch * Remove define nimExperimentalAsyncjsThen for std/asyncjs.then and std/jsfetch --- changelog.md | 2 +- lib/js/asyncjs.nim | 148 ++++++++++++++++++++++---------------------- lib/std/jsfetch.nim | 15 +++-- tools/kochdocs.nim | 2 +- 4 files changed, 83 insertions(+), 84 deletions(-) diff --git a/changelog.md b/changelog.md index cbad9b4e6..011f95ddb 100644 --- a/changelog.md +++ b/changelog.md @@ -40,7 +40,7 @@ becomes an alias for `addr`. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - Removed deprecated `oids.oidToString`. - +- Remove define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. - Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. - Removed deprecated `jsre.test` and `jsre.toString`. diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 861fe3fe2..8f91e1acd 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -64,6 +64,7 @@ when not defined(js) and not defined(nimsuggest): import std/jsffi import std/macros +import std/private/since type Future*[T] = ref object @@ -163,92 +164,91 @@ template maybeFuture(T): untyped = when T is Future: T else: Future[T] -when defined(nimExperimentalAsyncjsThen): - import std/private/since - since (1, 5, 1): - #[ - TODO: - * map `Promise.all()` - * proc toString*(a: Error): cstring {.importjs: "#.toString()".} - Note: - We probably can't have a `waitFor` in js in browser (single threaded), but maybe it would be possible - in in nodejs, see https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options - and https://stackoverflow.com/questions/61377358/javascript-wait-for-async-call-to-finish-before-returning-from-function-witho - ]# +since (1, 5, 1): + #[ + TODO: + * map `Promise.all()` + * proc toString*(a: Error): cstring {.importjs: "#.toString()".} - type Error* {.importjs: "Error".} = ref object of JsRoot - ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error - message*: cstring - name*: cstring + Note: + We probably can't have a `waitFor` in js in browser (single threaded), but maybe it would be possible + in in nodejs, see https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options + and https://stackoverflow.com/questions/61377358/javascript-wait-for-async-call-to-finish-before-returning-from-function-witho + ]# - type OnReject* = proc(reason: Error) + type Error* {.importjs: "Error".} = ref object of JsRoot + ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error + message*: cstring + name*: cstring - proc then*[T](future: Future[T], onSuccess: proc, onReject: OnReject = nil): auto = - ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then - ## Returns a `Future` from the return type of `onSuccess(T.default)`. - runnableExamples("-d:nimExperimentalAsyncjsThen"): - from std/sugar import `=>` + type OnReject* = proc(reason: Error) - proc fn(n: int): Future[int] {.async.} = - if n >= 7: raise newException(ValueError, "foobar: " & $n) - else: result = n * 2 + proc then*[T](future: Future[T], onSuccess: proc, onReject: OnReject = nil): auto = + ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then + ## Returns a `Future` from the return type of `onSuccess(T.default)`. + runnableExamples("-r:off"): + from std/sugar import `=>` - proc asyncFact(n: int): Future[int] {.async.} = - if n > 0: result = n * await asyncFact(n-1) - else: result = 1 + proc fn(n: int): Future[int] {.async.} = + if n >= 7: raise newException(ValueError, "foobar: " & $n) + else: result = n * 2 - proc main() {.async.} = - block: # then - assert asyncFact(3).await == 3*2 - assert asyncFact(3).then(asyncFact).await == 6*5*4*3*2 - let x1 = await fn(3) - assert x1 == 3 * 2 - let x2 = await fn(4) - .then((a: int) => a.float) - .then((a: float) => $a) - assert x2 == "8.0" + proc asyncFact(n: int): Future[int] {.async.} = + if n > 0: result = n * await asyncFact(n-1) + else: result = 1 - block: # then with `onReject` callback - var witness = 1 - await fn(6).then((a: int) => (witness = 2), (r: Error) => (witness = 3)) - assert witness == 2 - await fn(7).then((a: int) => (witness = 2), (r: Error) => (witness = 3)) - assert witness == 3 + proc main() {.async.} = + block: # then + assert asyncFact(3).await == 3*2 + assert asyncFact(3).then(asyncFact).await == 6*5*4*3*2 + let x1 = await fn(3) + assert x1 == 3 * 2 + let x2 = await fn(4) + .then((a: int) => a.float) + .then((a: float) => $a) + assert x2 == "8.0" - template impl(call): untyped = - # see D20210421T014713 - when typeof(block: call) is void: - var ret: Future[void] - else: - var ret = default(maybeFuture(typeof(call))) - typeof(ret) - when T is void: - type A = impl(onSuccess()) + block: # then with `onReject` callback + var witness = 1 + await fn(6).then((a: int) => (witness = 2), (r: Error) => (witness = 3)) + assert witness == 2 + await fn(7).then((a: int) => (witness = 2), (r: Error) => (witness = 3)) + assert witness == 3 + + template impl(call): untyped = + # see D20210421T014713 + when typeof(block: call) is void: + var ret: Future[void] else: - type A = impl(onSuccess(default(T))) - var ret: A - asm "`ret` = `future`.then(`onSuccess`, `onReject`)" - return ret + var ret = default(maybeFuture(typeof(call))) + typeof(ret) + when T is void: + type A = impl(onSuccess()) + else: + type A = impl(onSuccess(default(T))) + var ret: A + asm "`ret` = `future`.then(`onSuccess`, `onReject`)" + return ret - proc catch*[T](future: Future[T], onReject: OnReject): Future[void] = - ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch - runnableExamples("-d:nimExperimentalAsyncjsThen"): - from std/sugar import `=>` - from std/strutils import contains + proc catch*[T](future: Future[T], onReject: OnReject): Future[void] = + ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch + runnableExamples("-r:off"): + from std/sugar import `=>` + from std/strutils import contains - proc fn(n: int): Future[int] {.async.} = - if n >= 7: raise newException(ValueError, "foobar: " & $n) - else: result = n * 2 + proc fn(n: int): Future[int] {.async.} = + if n >= 7: raise newException(ValueError, "foobar: " & $n) + else: result = n * 2 - proc main() {.async.} = - var reason: Error - await fn(6).catch((r: Error) => (reason = r)) # note: `()` are needed, `=> reason = r` would not work - assert reason == nil - await fn(7).catch((r: Error) => (reason = r)) - assert reason != nil - assert "foobar: 7" in $reason.message + proc main() {.async.} = + var reason: Error + await fn(6).catch((r: Error) => (reason = r)) # note: `()` are needed, `=> reason = r` would not work + assert reason == nil + await fn(7).catch((r: Error) => (reason = r)) + assert reason != nil + assert "foobar: 7" in $reason.message - discard main() + discard main() - asm "`result` = `future`.catch(`onReject`)" + asm "`result` = `future`.catch(`onReject`)" diff --git a/lib/std/jsfetch.nim b/lib/std/jsfetch.nim index 808d699b0..034bb6332 100644 --- a/lib/std/jsfetch.nim +++ b/lib/std/jsfetch.nim @@ -190,12 +190,11 @@ runnableExamples("-r:off"): discard example() - when defined(nimExperimentalAsyncjsThen): - block: - proc example2 {.async.} = - await fetch("https://api.github.com/users/torvalds".cstring) - .then((response: Response) => response.json()) - .then((json: JsObject) => console.log(json)) - .catch((err: Error) => console.log("Request Failed", err)) + block: + proc example2 {.async.} = + await fetch("https://api.github.com/users/torvalds".cstring) + .then((response: Response) => response.json()) + .then((json: JsObject) => console.log(json)) + .catch((err: Error) => console.log("Request Failed", err)) - discard example2() + discard example2() diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 8fd9c84a5..764146cf5 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -11,7 +11,7 @@ const gaCode* = " --doc.googleAnalytics:UA-48159761-1" # errormax: subsequent errors are probably consequences of 1st one; a simple # bug could cause unlimited number of errors otherwise, hard to debug in CI. - docDefines = "-d:nimExperimentalAsyncjsThen -d:nimExperimentalLinenoiseExtra" + docDefines = "-d:nimExperimentalLinenoiseExtra" nimArgs = "--errormax:3 --hint:Conf:off --hint:Path:off --hint:Processing:off --hint:XDeclaredButNotUsed:off --warning:UnusedImport:off -d:boot --putenv:nimversion=$# $#" % [system.NimVersion, docDefines] gitUrl = "https://github.com/nim-lang/Nim" docHtmlOutput = "doc/html" From c2c9fbd7458db7adb515aad30cfe65b98fba47bf Mon Sep 17 00:00:00 2001 From: solarizedalias <60473183+solarizedalias@users.noreply.github.com> Date: Sun, 27 Feb 2022 16:22:52 +0900 Subject: [PATCH 3311/4254] make compileOption("panics") work (#19568) --- compiler/commands.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/commands.nim b/compiler/commands.nim index 6d3f23197..8e1d96860 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -332,6 +332,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool result = contains(conf.options, optTrMacros) of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch) + of "panics": result = contains(conf.globalOptions, optPanics) else: invalidCmdLineOption(conf, passCmd1, switch, info) proc processPath(conf: ConfigRef; path: string, info: TLineInfo, From c870ff5946731dd1deff828abfe07c1900a5b364 Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Sun, 27 Feb 2022 23:36:16 +0900 Subject: [PATCH 3312/4254] Add error message to pointer size check assert in lib/nimbase.h (#19549) --- lib/nimbase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nimbase.h b/lib/nimbase.h index a83bd3006..e4dec0dd2 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -547,7 +547,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); } #endif // Test to see if Nim and the C compiler agree on the size of a pointer. -NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, ""); +NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, "Pointer size mismatch between Nim and C/C++ backend. You probably need to setup the backend compiler for target CPU."); #ifdef USE_NIM_NAMESPACE } From 207237cec229171eafbd3357dcf128bdd270332a Mon Sep 17 00:00:00 2001 From: Evan Typanski Date: Mon, 28 Feb 2022 07:18:41 -0500 Subject: [PATCH 3313/4254] Fix #18662 (#19534) --- compiler/jsgen.nim | 4 +++- compiler/ropes.nim | 7 ------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0a7036b46..f4097efa4 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2796,7 +2796,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = var map: SourceMap (code, map) = genSourceMap($(code), outFile.string) writeFile(outFile.string & ".map", $(%map)) - discard writeRopeIfNotEqual(code, outFile) + if not equalsFile(code, outFile): + if not writeRope(code, outFile): + rawMessage(m.config, errCannotOpenFile, outFile.string) proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 1e7957337..cd696a545 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -329,10 +329,3 @@ proc equalsFile*(r: Rope, filename: AbsoluteFile): bool = if result: result = equalsFile(r, f) close(f) - -proc writeRopeIfNotEqual*(r: Rope, filename: AbsoluteFile): bool = - # returns true if overwritten - if not equalsFile(r, filename): - result = writeRope(r, filename) - else: - result = false From d6d36093b18dfa1e2b8b6325016f1def015250b4 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 1 Mar 2022 14:46:08 +0800 Subject: [PATCH 3314/4254] apply changes from #18017 and some fixes (#19571) * implements https://github.com/nim-lang/RFCs/issues/369 * deprecate unsafeAddr; extend addr addr is now available for all addressable locations, unsafeAddr is deprecated and become an alias for addr * follow @Vindaar's advice * change the signature of addr * unsafeAddr => addr (stdlib) * Update changelog.md * unsafeAddr => addr (tests) * Revert "unsafeAddr => addr (stdlib)" This reverts commit ab83c99c507048a8396e636bf22d55fdd84d7d1c. * doc changes; thanks to @konsumlamm Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * merge * remove * fix bug Co-authored-by: Araq Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- compiler/parampatterns.nim | 60 ++++++++++++++++++++------------------ compiler/semexprs.nim | 14 +++++---- compiler/semmagic.nim | 6 ++-- lib/system.nim | 3 -- 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index bfbc72675..cceb236ae 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -179,6 +179,7 @@ type arLocalLValue, # is an l-value, but local var; must not escape # its stack frame! arDiscriminant, # is a discriminant + arAddressableConst, # an addressable const arLentValue, # lent value arStrange # it is a strange beast like 'typedesc[var T]' @@ -212,7 +213,7 @@ proc exprRoot*(n: PNode): PSym = else: break -proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult = +proc isAssignable*(owner: PSym, n: PNode): TAssignableResult = ## 'owner' can be nil! result = arNone case n.kind @@ -220,20 +221,20 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult if n.typ != nil and n.typ.kind in {tyVar}: result = arLValue of nkSym: - let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar} - else: {skVar, skResult, skTemp} - if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}: - result = arLValue - elif isUnsafeAddr and n.sym.kind == skParam: - result = arLValue - elif isUnsafeAddr and n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast): - result = arLValue + const kinds = {skVar, skResult, skTemp, skParam, skLet, skForVar} + if n.sym.kind == skParam: + result = if n.sym.typ.kind in {tyVar, tySink}: arLValue else: arAddressableConst + elif n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast): + result = arAddressableConst elif n.sym.kind in kinds: - if owner != nil and owner == n.sym.owner and - sfGlobal notin n.sym.flags: - result = arLocalLValue + if n.sym.kind in {skParam, skLet, skForVar}: + result = arAddressableConst else: - result = arLValue + if owner != nil and owner == n.sym.owner and + sfGlobal notin n.sym.flags: + result = arLocalLValue + else: + result = arLValue elif n.sym.kind == skType: let t = n.sym.typ.skipTypes({tyTypeDesc}) if t.kind in {tyVar}: result = arStrange @@ -241,10 +242,10 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc}) if t.kind in {tyVar, tySink, tyPtr, tyRef}: result = arLValue - elif isUnsafeAddr and t.kind == tyLent: - result = arLValue + elif t.kind == tyLent: + result = arAddressableConst else: - result = isAssignable(owner, n[0], isUnsafeAddr) + result = isAssignable(owner, n[0]) if result != arNone and n[1].kind == nkSym and sfDiscriminant in n[1].sym.flags: result = arDiscriminant @@ -252,23 +253,23 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc}) if t.kind in {tyVar, tySink, tyPtr, tyRef}: result = arLValue - elif isUnsafeAddr and t.kind == tyLent: - result = arLValue + elif t.kind == tyLent: + result = arAddressableConst else: - result = isAssignable(owner, n[0], isUnsafeAddr) + result = isAssignable(owner, n[0]) of nkHiddenStdConv, nkHiddenSubConv, nkConv: # Object and tuple conversions are still addressable, so we skip them # XXX why is 'tyOpenArray' allowed here? if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in {tyOpenArray, tyTuple, tyObject}: - result = isAssignable(owner, n[1], isUnsafeAddr) + result = isAssignable(owner, n[1]) elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct): # types that are equal modulo distinction preserve l-value: - result = isAssignable(owner, n[1], isUnsafeAddr) + result = isAssignable(owner, n[1]) of nkHiddenDeref: let n0 = n[0] if n0.typ.kind == tyLent: - if isUnsafeAddr or (n0.kind == nkSym and n0.sym.kind == skResult): + if n0.kind == nkSym and n0.sym.kind == skResult: result = arLValue else: result = arLentValue @@ -277,18 +278,19 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult of nkDerefExpr, nkHiddenAddr: result = arLValue of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: - result = isAssignable(owner, n[0], isUnsafeAddr) + result = isAssignable(owner, n[0]) of nkCallKinds: # builtin slice keeps lvalue-ness: if getMagic(n) in {mArrGet, mSlice}: - result = isAssignable(owner, n[1], isUnsafeAddr) - elif n.typ != nil and n.typ.kind in {tyVar}: - result = arLValue - elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent: - result = arLValue + result = isAssignable(owner, n[1]) + elif n.typ != nil: + case n.typ.kind + of tyVar: result = arLValue + of tyLent: result = arLentValue + else: discard of nkStmtList, nkStmtListExpr: if n.typ != nil: - result = isAssignable(owner, n.lastSon, isUnsafeAddr) + result = isAssignable(owner, n.lastSon) of nkVarTy: # XXX: The fact that this is here is a bit of a hack. # The goal is to allow the use of checks such as "foo(var T)" diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c593efe55..5f3d065b6 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -650,8 +650,8 @@ proc fixAbstractType(c: PContext, n: PNode) = changeType(c, it[1], s, check=true) n[i] = it[1] -proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult = - result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr) +proc isAssignable(c: PContext, n: PNode): TAssignableResult = + result = parampatterns.isAssignable(c.p.owner, n) proc isUnresolvedSym(s: PSym): bool = result = s.kind == skGenericParam @@ -1658,9 +1658,11 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = # `proc fun(a: var int): var int = a` discard else: discard - let valid = isAssignable(c, n, isLent) + let valid = isAssignable(c, n) if valid != arLValue: - if valid == arLocalLValue: + if valid in {arAddressableConst, arLentValue} and isLent: + discard "ok" + elif valid == arLocalLValue: localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments})) else: localError(c.config, n.info, errExprHasNoAddress) @@ -1784,7 +1786,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if le == nil: localError(c.config, a.info, "expression has no type") elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and - isAssignable(c, a) in {arNone, arLentValue}) or ( + isAssignable(c, a) in {arNone, arLentValue, arAddressableConst}) or ( skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features): # Direct assignment to a discriminant is allowed! localError(c.config, a.info, errXCannotBeAssignedTo % @@ -2267,7 +2269,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = markUsed(c, n.info, s) checkSonsLen(n, 2, c.config) result[0] = newSymNode(s, n[0].info) - result[1] = semAddrArg(c, n[1], s.name.s == "unsafeAddr") + result[1] = semAddrArg(c, n[1]) result.typ = makePtrType(c, result[1].typ) of mTypeOf: markUsed(c, n.info, s) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index c7fc75620..ed1826fd4 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -10,11 +10,11 @@ # This include file implements the semantic checking for magics. # included from sem.nim -proc semAddrArg(c: PContext; n: PNode; isUnsafeAddr = false): PNode = +proc semAddrArg(c: PContext; n: PNode): PNode = let x = semExprWithType(c, n) if x.kind == nkSym: x.sym.flags.incl(sfAddrTaken) - if isAssignable(c, x, true) notin {arLValue, arLocalLValue}: + if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}: localError(c.config, n.info, errExprHasNoAddress) result = x @@ -466,7 +466,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mAddr: checkSonsLen(n, 2, c.config) result = n - result[1] = semAddrArg(c, n[1], n[0].sym.name.s == "unsafeAddr") + result[1] = semAddrArg(c, n[1]) result.typ = makePtrType(c, result[1].typ) of mTypeOf: result = semTypeOf(c, n) diff --git a/lib/system.nim b/lib/system.nim index 56a6e2887..572768de2 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -202,9 +202,6 @@ proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## ## Cannot be overloaded. ## - ## See also: - ## * `unsafeAddr <#unsafeAddr,T>`_ - ## ## .. code-block:: Nim ## var ## buf: seq[char] = @['a','b','c'] From 590d39785243afb6da3662cf77c842a5ff4e1412 Mon Sep 17 00:00:00 2001 From: huantian Date: Wed, 2 Mar 2022 05:53:59 +0000 Subject: [PATCH 3315/4254] Fix typo in Nim Tutorial pt3 (#19579) --- doc/tut3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tut3.rst b/doc/tut3.rst index 6b5a3b5ca..1c497f1f5 100644 --- a/doc/tut3.rst +++ b/doc/tut3.rst @@ -244,7 +244,7 @@ Building Your First Macro ------------------------- To give a starting point to writing macros we will show now how to -implement the `myDebug` macro mentioned earlier. The first thing to +implement the `myAssert` macro mentioned earlier. The first thing to do is to build a simple example of the macro usage, and then just print the argument. This way it is possible to get an idea of what a correct argument should look like. From 488e18f90d342b5a3b528c0c84891b31b7d1e6ca Mon Sep 17 00:00:00 2001 From: VlkrS <47375452+VlkrS@users.noreply.github.com> Date: Thu, 3 Mar 2022 14:41:35 +0100 Subject: [PATCH 3316/4254] Fix CPU detection for i386 (#19577) * Fix CPU detection for i386 Commit 787def271b1cabc6f898caa42f892125de9fa908 breaks CPU detection for i386 on OpenBSD and probably on other platforms. [ isOpenIndiana -eq "yes" ] always returns 0, so mycpu is always set to "amd64". * Update buildsh.nimf Fix accidental bashism --- tools/niminst/buildsh.nimf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 5f1db9cd3..7a05ef342 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -164,7 +164,7 @@ esac case $ucpu in *i386* | *i486* | *i586* | *i686* | *bepc* | *i86pc* ) - if [ isOpenIndiana -eq "yes" ] ; then + if [ "$isOpenIndiana" = "yes" ] ; then mycpu="amd64" else mycpu="i386" From 645447293851749fcc3394cd387d7070d8a9c735 Mon Sep 17 00:00:00 2001 From: Hamid Bluri Date: Mon, 7 Mar 2022 12:51:42 +0330 Subject: [PATCH 3317/4254] fix not flushing stdout in MSYS (#19590) I did this pull request according to what xflywind said: https://github.com/nim-lang/Nim/pull/19584#issuecomment-1060085141 --- lib/impure/rdstdin.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 32048b131..adc0e212d 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -27,6 +27,7 @@ when defined(windows): tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a line from stdin. stdout.write(prompt) + stdout.flushFile() result = readLine(stdin) proc readLineFromStdin*(prompt: string, line: var string): bool {. From 8f9dd5b3492293e4e48647206c8858b58cd51666 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 9 Mar 2022 01:12:31 +0800 Subject: [PATCH 3318/4254] register callback for marshal in VM (#19578) * register callback for marshal in VM * remove unrelated code * polish * more tests * more tests * add loadVM and toVM --- compiler/vm.nim | 17 +++------------- compiler/vmdef.nim | 5 ++--- compiler/vmgen.nim | 27 ------------------------- compiler/vmops.nim | 36 ++++++++++++++++++++++++++++++++- lib/pure/marshal.nim | 28 ++++++++++++++++++-------- tests/stdlib/tmarshal.nim | 42 +++++++++++++++++++++++++++++++++------ 6 files changed, 96 insertions(+), 59 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 259648add..fa1c71c85 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -15,7 +15,7 @@ import std/[strutils, tables, parseutils], msgs, vmdef, vmgen, nimsets, types, passes, parser, vmdeps, idents, trees, renderer, options, transf, - vmmarshal, gorgeimpl, lineinfos, btrees, macrocacheimpl, + gorgeimpl, lineinfos, btrees, macrocacheimpl, modulegraphs, sighashes, int128, vmprofiler import ast except getstr @@ -1224,7 +1224,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = c.callbacks[-prc.offset-2].value( VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), currentException: c.currentExceptionA, - currentLineInfo: c.debug[pc])) + currentLineInfo: c.debug[pc]) + ) elif importcCond(c, prc): if compiletimeFFI notin c.config.features: globalError(c.config, c.debug[pc], "VM not allowed to do FFI, see `compiletimeFFI`") @@ -2100,18 +2101,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = while typ.kind == tyTypeDesc and typ.len > 0: typ = typ[0] createStr regs[ra] regs[ra].node.strVal = typ.typeToString(preferExported) - of opcMarshalLoad: - let ra = instr.regA - let rb = instr.regB - inc pc - let typ = c.types[c.code[pc].regBx - wordExcess] - putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.cache, c.config, c.idgen)) - of opcMarshalStore: - decodeB(rkNode) - inc pc - let typ = c.types[c.code[pc].regBx - wordExcess] - createStrKeepNode(regs[ra]) - storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) c.profiler.leave(c) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 2044b860a..ecdbeff89 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -180,7 +180,6 @@ type opcNBindSym, opcNDynBindSym, opcSetType, # dest.typ = types[Bx] opcTypeTrait, - opcMarshalLoad, opcMarshalStore, opcSymOwner, opcSymIsInstantiationOf @@ -307,8 +306,8 @@ proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.disca const firstABxInstr* = opcTJmp largeInstrs* = { # instructions which use 2 int32s instead of 1: - opcSubStr, opcConv, opcCast, opcNewSeq, opcOf, - opcMarshalLoad, opcMarshalStore} + opcSubStr, opcConv, opcCast, opcNewSeq, opcOf + } slotSomeTemp* = slotTempUnknown relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack} diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c0c4bac19..1551fbb80 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -99,11 +99,6 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) = let idx = x.regBx-wordExcess result.addf("\t$#\tr$#, $# ($#)", opc.toStr, x.regA, c.constants[idx].renderTree, $idx) - elif opc in {opcMarshalLoad, opcMarshalStore}: - let y = c.code[i+1] - result.addf("\t$#\tr$#, r$#, $#", opc.toStr, x.regA, x.regB, - c.types[y.regBx-wordExcess].typeToString) - inc i else: result.addf("\t$#\tr$#, $#", opc.toStr, x.regA, x.regBx-wordExcess) result.add("\t# ") @@ -1383,22 +1378,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = # mGCref, mGCunref, globalError(c.config, n.info, "cannot generate code for: " & $m) -proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) = - ## Signature: proc to*[T](data: string): T - if dest < 0: dest = c.getTemp(n.typ) - var tmp = c.genx(n[1]) - c.gABC(n, opcMarshalLoad, dest, tmp) - c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ)) - c.freeTemp(tmp) - -proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) = - ## Signature: proc `$$`*[T](x: T): string - if dest < 0: dest = c.getTemp(n.typ) - var tmp = c.genx(n[1]) - c.gABC(n, opcMarshalStore, dest, tmp) - c.gABx(n, opcMarshalStore, 0, c.genType(n[1].typ)) - c.freeTemp(tmp) - proc unneededIndirection(n: PNode): bool = n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef @@ -2054,12 +2033,6 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = elif s.kind == skMethod: localError(c.config, n.info, "cannot call method " & s.name.s & " at compile time") - elif matches(s, "stdlib.marshal.to"): - # XXX marshal load&store should not be opcodes, but use the - # general callback mechanisms. - genMarshalLoad(c, n, dest) - elif matches(s, "stdlib.marshal.$$"): - genMarshalStore(c, n, dest) else: genCall(c, n, dest) clearDest(c, n, dest) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 6b06cc68d..f13e4b1cc 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -32,7 +32,7 @@ from system/formatfloat import addFloatRoundtrip, addFloatSprintf # There are some useful procs in vmconv. -import vmconv +import vmconv, vmmarshal template mathop(op) {.dirty.} = registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) @@ -152,6 +152,7 @@ when defined(nimHasInvariant): proc stackTrace2(c: PCtx, msg: string, n: PNode) = stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info) + proc registerAdditionalOps*(c: PCtx) = template wrapIterator(fqname: string, iter: untyped) = @@ -344,3 +345,36 @@ proc registerAdditionalOps*(c: PCtx) = addFloatSprintf(p.strVal, x) wrapIterator("stdlib.os.envPairsImplSeq"): envPairs() + + registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) = + let typ = a.getNode(0).typ + case typ.kind + of tyInt..tyInt64, tyUInt..tyUInt64: + setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen).intVal) + of tyFloat..tyFloat128: + setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen).floatVal) + else: + setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen)) + + registerCallback c, "stdlib.marshal.loadVM", proc(a: VmArgs) = + let typ = a.getNode(0).typ + let p = a.getReg(1) + var res: string + + var node: PNode + case p.kind + of rkNone: + node = newNode(nkEmpty) + of rkInt: + node = newIntNode(nkIntLit, p.intVal) + of rkFloat: + node = newFloatNode(nkFloatLit, p.floatVal) + of rkNode: + node = p.node + of rkRegisterAddr: + node = p.regAddr.node + of rkNodeAddr: + node = p.nodeAddr[] + + storeAny(res, typ, node, c.config) + setResult(a, res) diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 993e0f510..452af54d5 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -298,6 +298,9 @@ proc store*[T](s: Stream, data: T) = shallowCopy(d, data) storeAny(s, toAny(d), stored) +proc loadVM[T](typ: typedesc[T], x: T): string = + discard "the implementation is in the compiler/vmops" + proc `$$`*[T](x: T): string = ## Returns a string representation of `x` (serialization, marshalling). ## @@ -313,12 +316,18 @@ proc `$$`*[T](x: T): string = let y = $$x assert y == """{"id": 1, "bar": "baz"}""" - var stored = initIntSet() - var d: T - shallowCopy(d, x) - var s = newStringStream() - storeAny(s, toAny(d), stored) - result = s.data + when nimvm: + result = loadVM(T, x) + else: + var stored = initIntSet() + var d: T + shallowCopy(d, x) + var s = newStringStream() + storeAny(s, toAny(d), stored) + result = s.data + +proc toVM[T](typ: typedesc[T], data: string): T = + discard "the implementation is in the compiler/vmops" proc to*[T](data: string): T = ## Reads data and transforms it to a type `T` (deserialization, unmarshalling). @@ -335,5 +344,8 @@ proc to*[T](data: string): T = assert z.id == 1 assert z.bar == "baz" - var tab = initTable[BiggestInt, pointer]() - loadAny(newStringStream(data), toAny(result), tab) + when nimvm: + result = toVM(T, data) + else: + var tab = initTable[BiggestInt, pointer]() + loadAny(newStringStream(data), toAny(result), tab) diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index 508205c3a..e539b1c34 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -4,12 +4,16 @@ import std/marshal proc testit[T](x: T): string = $$to[T]($$x) -let test1: array[0..1, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] -doAssert testit(test1) == - """[["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]""" -let test2: tuple[name: string, s: int] = ("tuple test", 56) -doAssert testit(test2) == """{"Field0": "tuple test", "Field1": 56}""" +template check1 = + let test1: array[0..1, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] + doAssert testit(test1) == + """[["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]""" + let test2: tuple[name: string, s: int] = ("tuple test", 56) + doAssert testit(test2) == """{"Field0": "tuple test", "Field1": 56}""" + +static: check1() +check1() type TE = enum @@ -146,3 +150,29 @@ block: let a: ref A = new(B) doAssert $$a[] == "{}" # not "{f: 0}" + +template checkMarshal(data: typed) = + let orig = data + let m = $$orig + + let old = to[typeof(orig)](m) + doAssert data == old + +template main() = + type + Book = object + page: int + name: string + + let book = Book(page: 12, name: "persona") + + checkMarshal(486) + checkMarshal(3.14) + checkMarshal("azure sky") + checkMarshal(book) + checkMarshal([1, 2, 3]) + checkMarshal(@[1.5, 2.7, 3.9, 4.2]) + checkMarshal(@["dream", "is", "possible"]) + +static: main() +main() From 0d6795a771e46b07244f3a3f43502602acbebdc3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 9 Mar 2022 07:22:10 +0100 Subject: [PATCH 3319/4254] fixes #19569 (#19595) [backport] * minor code refactorings * fixes #19569 --- compiler/cgen.nim | 2 +- compiler/sizealignoffsetimpl.nim | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b78ad10c4..2865473fb 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -881,7 +881,7 @@ proc containsResult(n: PNode): bool = if containsResult(n[i]): return true const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef, - nkMacroDef, nkMixinStmt, nkBindStmt} + + nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} + declarativeDefs proc easyResultAsgn(n: PNode): PNode = diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index c5cd3ba64..c2e97aa53 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -40,15 +40,15 @@ proc inc(arg: var OffsetAccum; value: int) = else: arg.offset += value -proc alignmentMax(a,b: int): int = +proc alignmentMax(a, b: int): int = if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion() if a == szUnknownSize or b == szUnknownSize: szUnknownSize else: - max(a,b) + max(a, b) proc align(arg: var OffsetAccum; value: int) = - if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() + if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() if value == szUnknownSize or arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize: arg.maxAlign = szUnknownSize arg.offset = szUnknownSize @@ -112,7 +112,7 @@ proc setOffsetsToUnknown(n: PNode) = for i in 0.. Date: Wed, 9 Mar 2022 11:42:09 +0100 Subject: [PATCH 3320/4254] fixes #19575 (#19596) [backport] * fixes #19575 * better bugfix --- compiler/closureiters.nim | 6 ++++-- tests/iter/titer_issues.nim | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index a8da7485e..4d9aeb3f7 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -1351,13 +1351,15 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode = case n.kind of nkTryStmt: let f = n.lastSon + var didAddSomething = false if f.kind == nkFinally: c.finallys.add f.lastSon + didAddSomething = true for i in 0 ..< n.len: result[i] = preprocess(c, n[i]) - if f.kind == nkFinally: + if didAddSomething: discard c.finallys.pop() of nkWhileStmt, nkBlockStmt: @@ -1384,7 +1386,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode = result = newNodeI(nkStmtList, n.info) for i in countdown(c.finallys.high, fin): var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info, idgen: c.idgen) - result.add freshVars(preprocess(c, c.finallys[i]), vars) + result.add freshVars(copyTree(c.finallys[i]), vars) c.idgen = vars.idgen result.add n of nkSkip: discard diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index 65f66ad26..15fe867c8 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -251,3 +251,26 @@ block: for x in ff(@[1, 2], @[1, 2, 3]): echo x + + +# bug #19575 + +iterator bb() {.closure.} = + while true: + try: discard + except: break + finally: break + +var a = bb + +iterator cc() {.closure.} = + while true: + try: discard + except: + if true: + break + finally: + if true: + break + +var a2 = cc From 6773ffa63d0b3ab8b8894e84ed417f4eaced9122 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 9 Mar 2022 19:55:20 +0800 Subject: [PATCH 3321/4254] enable nimPreviewDotLikeOps (#19598) --- config/config.nims | 1 + tests/config.nims | 1 - tests/stdlib/texperimental.nim | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/texperimental.nim diff --git a/config/config.nims b/config/config.nims index 88c344642..08d9d9f55 100644 --- a/config/config.nims +++ b/config/config.nims @@ -21,3 +21,4 @@ when defined(nimStrictMode): # future work: XDeclaredButNotUsed switch("define", "nimVersion:" & NimVersion) +switch("define", "nimPreviewDotLikeOps") diff --git a/tests/config.nims b/tests/config.nims index 894c4bea0..8c4305521 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -37,6 +37,5 @@ switch("define", "nimExperimentalLinenoiseExtra") # preview APIs are expected to be the new default in upcoming versions switch("define", "nimPreviewFloatRoundtrip") -switch("define", "nimPreviewDotLikeOps") switch("define", "nimPreviewJsonutilsHoleyEnum") switch("define", "nimPreviewHashRef") diff --git a/tests/stdlib/texperimental.nim b/tests/stdlib/texperimental.nim new file mode 100644 index 000000000..ba8c4eb80 --- /dev/null +++ b/tests/stdlib/texperimental.nim @@ -0,0 +1 @@ +doAssert defined(nimPreviewDotLikeOps) \ No newline at end of file From 4c76f9f1523a72f560138709642c2d51ea365b85 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 11 Mar 2022 00:01:27 +0800 Subject: [PATCH 3322/4254] support useVersion:1.6 (#19601) --- compiler/commands.nim | 4 +++ compiler/options.nim | 1 + doc/advopt.txt | 2 +- doc/manual.rst | 5 ---- tests/system/tuse_version.nim | 5 ++-- tests/system/tuse_version16.nim | 49 +++++++++++++++++++++++++++++++++ 6 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 tests/system/tuse_version16.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 8e1d96860..b21b48801 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -1043,6 +1043,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "NimMajor", "1") defineSymbol(conf.symbols, "NimMinor", "2") conf.globalOptions.incl optNimV12Emulation + of "1.6": + defineSymbol(conf.symbols, "NimMajor", "1") + defineSymbol(conf.symbols, "NimMinor", "6") + conf.globalOptions.incl optNimV16Emulation else: localError(conf, info, "unknown Nim version; currently supported values are: `1.0`, `1.2`") # always be compatible with 1.x.100: diff --git a/compiler/options.nim b/compiler/options.nim index 5cfe58119..9c0c9df72 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -96,6 +96,7 @@ type # please make sure we have under 32 options optPanics # turn panics (sysFatal) into a process termination optNimV1Emulation # emulate Nim v1.0 optNimV12Emulation # emulate Nim v1.2 + optNimV16Emulation # emulate Nim v1.6 optSourcemap optProfileVM # enable VM profiler optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types. diff --git a/doc/advopt.txt b/doc/advopt.txt index e27c75ada..0a2349597 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -161,7 +161,7 @@ Advanced options: enable experimental language feature --legacy:$2 enable obsolete/legacy language feature - --useVersion:1.0|1.2 emulate Nim version X of the Nim compiler, for testing + --useVersion:1.0|1.2|1.6 emulate Nim version X of the Nim compiler, for testing --benchmarkVM:on|off turn benchmarking of VM code with cpuTime() on|off --profileVM:on|off turn compile time VM profiler on|off --sinkInference:on|off turn sink parameter inference on|off (default: on) diff --git a/doc/manual.rst b/doc/manual.rst index e45133c38..4c4b9c506 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5797,11 +5797,6 @@ However, this means that the method call syntax is not available for tmp(12) -**Note**: The Nim compiler prior to version 1 was more lenient about this -requirement. Use the `--useVersion:0.19`:option: switch for a transition period. - - - Limitations of the method call syntax ------------------------------------- diff --git a/tests/system/tuse_version.nim b/tests/system/tuse_version.nim index 36dac46ec..116ef3596 100644 --- a/tests/system/tuse_version.nim +++ b/tests/system/tuse_version.nim @@ -1,6 +1,5 @@ discard """ - cmd: "nim c --useVersion:1.0 -r $file" - output: "1.0.100" + matrix: "--useVersion:1.0" """ {.warning[UnusedImport]: off.} @@ -47,4 +46,4 @@ import std/[ ] -echo NimVersion +doAssert NimVersion == "1.0.100" diff --git a/tests/system/tuse_version16.nim b/tests/system/tuse_version16.nim new file mode 100644 index 000000000..d5430db32 --- /dev/null +++ b/tests/system/tuse_version16.nim @@ -0,0 +1,49 @@ +discard """ + matrix: "--useVersion:1.6" +""" + +{.warning[UnusedImport]: off.} + +import std/[ + # Core: + bitops, typetraits, lenientops, macros, volatile, + + # Algorithms: + algorithm, sequtils, + + # Collections: + critbits, deques, heapqueue, intsets, lists, options, sets, + sharedlist, tables, + + # Strings: + editdistance, wordwrap, parseutils, ropes, + pegs, punycode, strformat, strmisc, strscans, strtabs, + strutils, unicode, unidecode, + + # Generic operator system services: + os, streams, + + # Math libraries: + complex, math, mersenne, random, rationals, stats, sums, + + # Internet protocols: + httpcore, mimetypes, uri, + + # Parsers: + htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, + + # XML processing: + xmltree, xmlparser, + + # Generators: + htmlgen, + + # Hashing: + base64, hashes, + + # Miscellaneous: + colors, sugar, varints, +] + + +doAssert NimVersion == "1.6.100" From 7a50d663467f0e64ea8390e8c86269b25f312816 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 18 Mar 2022 03:54:20 -0300 Subject: [PATCH 3323/4254] Removed deprecated httpcore func (#19550) * Remove Deprecated httpcore func * Remove Deprecated httpcore func * Fix a test with Deprecated func * Restart CI, Apple can code shit anymore I tell you --- changelog.md | 1 + lib/pure/httpcore.nim | 10 ---------- tests/stdlib/tasynchttpserver.nim | 8 ++++---- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 011f95ddb..a9bf3842a 100644 --- a/changelog.md +++ b/changelog.md @@ -45,6 +45,7 @@ becomes an alias for `addr`. - Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. - Removed deprecated `jsre.test` and `jsre.toString`. - Removed deprecated `math.c_frexp`. +- Removed deprecated ``` httpcore.`==` ```. ## Language changes diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index fdd5926f7..7e995ac46 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -347,16 +347,6 @@ func `$`*(code: HttpCode): string = func `==`*(a, b: HttpCode): bool {.borrow.} -proc `==`*(rawCode: string, code: HttpCode): bool - {.deprecated: "Deprecated since v1.2; use rawCode == $code instead".} = - ## Compare the string form of the status code with a HttpCode - ## - ## **Note**: According to HTTP/1.1 specification, the reason phrase is - ## optional and should be ignored by the client, making this - ## proc only suitable for comparing the `HttpCode` against the - ## string form of itself. - return cmpIgnoreCase(rawCode, $code) == 0 - func is1xx*(code: HttpCode): bool {.inline, since: (1, 5).} = ## Determines whether `code` is a 1xx HTTP status code. runnableExamples: diff --git a/tests/stdlib/tasynchttpserver.nim b/tests/stdlib/tasynchttpserver.nim index 77ad7a071..d4176d55a 100644 --- a/tests/stdlib/tasynchttpserver.nim +++ b/tests/stdlib/tasynchttpserver.nim @@ -39,7 +39,7 @@ proc test200() {.async.} = return clientResponse proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == Http200) + doAssert(response.status == $Http200) doAssert(body == "Hello World, 200") doAssert(response.headers.hasKey("Content-Length")) doAssert(response.headers["Content-Length"] == "16") @@ -60,7 +60,7 @@ proc test404() {.async.} = return clientResponse proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == Http404) + doAssert(response.status == $Http404) doAssert(body == "Hello World, 404") doAssert(response.headers.hasKey("Content-Length")) doAssert(response.headers["Content-Length"] == "16") @@ -81,7 +81,7 @@ proc testCustomEmptyHeaders() {.async.} = return clientResponse proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == Http200) + doAssert(response.status == $Http200) doAssert(body == "Hello World, 200") doAssert(response.headers.hasKey("Content-Length")) doAssert(response.headers["Content-Length"] == "16") @@ -104,7 +104,7 @@ proc testCustomContentLength() {.async.} = return clientResponse proc test(response: AsyncResponse, body: string) {.async.} = - doAssert(response.status == Http200) + doAssert(response.status == $Http200) doAssert(body == "") doAssert(response.headers.hasKey("Content-Length")) doAssert(response.headers["Content-Length"] == "0") From 7b811deeffc762f8370b4cf7e8a353fd516d6543 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 18 Mar 2022 14:17:54 +0100 Subject: [PATCH 3324/4254] db_sqlite: added a space --- lib/impure/db_sqlite.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index b600576df..1638d38c6 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -700,7 +700,7 @@ proc insert*(db: DbConn, query: SqlQuery, pkName: string, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect], since: (1, 3).} = ## same as insertId - result = tryInsert(db, query,pkName, args) + result = tryInsert(db, query, pkName, args) if result < 0: dbError(db) proc execAffectedRows*(db: DbConn, query: SqlQuery, From 3e83d73f272afe8de85189da7d6d513916cc2efd Mon Sep 17 00:00:00 2001 From: Clyybber Date: Fri, 18 Mar 2022 16:41:45 +0100 Subject: [PATCH 3325/4254] compiler: Handle nkCheckedFieldExpr better in dfa (#19616) Simply recurse into their first child, which is always a nkDotExpr instead of treating them seperately. This fixes the rhs sym of a nkCheckedFieldExpr being checked twice in aliases. This double checking didn't cause any issues, but was unintentional and redundant. --- compiler/dfa.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0539f6699..d68e7be82 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -605,11 +605,11 @@ proc aliases*(obj, field: PNode): AliasKind = var n = n while true: case n.kind - of PathKinds0 - {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}: + of PathKinds0 - {nkDotExpr, nkBracketExpr}: n = n[0] of PathKinds1: n = n[1] - of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr: + of nkDotExpr, nkBracketExpr: result.add n n = n[0] of nkSym: @@ -642,8 +642,6 @@ proc aliases*(obj, field: PNode): AliasKind = if currFieldPath.sym != currObjPath.sym: return no of nkDotExpr: if currFieldPath[1].sym != currObjPath[1].sym: return no - of nkCheckedFieldExpr: - if currFieldPath[0][1].sym != currObjPath[0][1].sym: return no of nkBracketExpr: if currFieldPath[1].kind in nkLiterals and currObjPath[1].kind in nkLiterals: if currFieldPath[1].intVal != currObjPath[1].intVal: From 731eabc9309997775c8be41f3e5eb5512460aad0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Mar 2022 14:02:44 +0100 Subject: [PATCH 3326/4254] fixes #19631 (#19618) Aliasing is hard and we have to watch out not to compile 'x = f(x.a)' into 'f(x.a, addr x)' --- compiler/ccgcalls.nim | 11 ++++++++--- tests/ccgbugs/tcgbug.nim | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index ce5fbfdd7..05be51a45 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -21,7 +21,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool = # we have to be *very* conservative: result = canRaiseConservative(n) -proc preventNrvo(p: BProc; le, ri: PNode): bool = +proc preventNrvo(p: BProc; dest, le, ri: PNode): bool = proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool = var n = le while true: @@ -54,6 +54,11 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool = if canRaise(ri[0]) and locationEscapes(p, le, p.nestedTryStmts.len > 0): message(p.config, le.info, warnObservableStores, $le) + # bug #19613 prevent dangerous aliasing too: + if dest != nil and dest != le: + for i in 1.. 1: pl.add(~", ") # beware of 'result = p(result)'. We may need to allocate a temporary: - if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri): + if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): # Great, we can use 'd': if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim index db9c116be..0fe4b8852 100644 --- a/tests/ccgbugs/tcgbug.nim +++ b/tests/ccgbugs/tcgbug.nim @@ -91,3 +91,34 @@ proc test(c: Helper): string = c.formatted echo test(Helper(isKind: true, formatted: "ok")) + + +# bug #19613 + +type + Eth2Digest = object + data: array[42, byte] + + BlockId* = object + root*: Eth2Digest + + BlockSlotId* = object + bid*: BlockId + slot*: uint64 + +func init*(T: type BlockSlotId, bid: BlockId, slot: uint64): T = + #debugecho "init ", bid, " ", slot + BlockSlotId(bid: bid, slot: slot) + +proc bug19613 = + var x: BlockSlotId + x.bid.root.data[0] = 42 + + x = + if x.slot > 0: + BlockSlotId.init(x.bid, x.slot) + else: + BlockSlotId.init(x.bid, x.slot) + doAssert x.bid.root.data[0] == 42 + +bug19613() From c4a0d4c5e35f09430a1c3d465fc62eb1001b7f9f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 22 Mar 2022 15:36:49 +0100 Subject: [PATCH 3327/4254] =?UTF-8?q?fixes=20#19615;=20emit=20better=20cod?= =?UTF-8?q?e=20for=20integer=20divisions=20when=20the=20divisor=E2=80=A6?= =?UTF-8?q?=20(#19626)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixes #19615; emit better code for integer divisions when the divisor is known at compile-time * proper bugfix: unsigned numbers cannot be -1 --- compiler/ccgexprs.nim | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 9848366a1..1a3e217b2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -584,13 +584,23 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = else: # we handle div by zero here so that we know that the compilerproc's # result is only for overflows. + var needsOverflowCheck = true if m in {mDivI, mModI}: - linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); $2}$n", - [rdLoc(b), raiseInstr(p)]) - - let res = binaryArithOverflowRaw(p, t, a, b, - if t.kind == tyInt64: prc64[m] else: prc[m]) - putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) + var canBeZero = true + if e[2].kind in {nkIntLit..nkUInt64Lit}: + canBeZero = e[2].intVal == 0 + if e[2].kind in {nkIntLit..nkInt64Lit}: + needsOverflowCheck = e[2].intVal == -1 + if canBeZero: + linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); $2}$n", + [rdLoc(b), raiseInstr(p)]) + if needsOverflowCheck: + let res = binaryArithOverflowRaw(p, t, a, b, + if t.kind == tyInt64: prc64[m] else: prc[m]) + putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) + else: + let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)] + putIntoDest(p, d, e, res) proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = var From 4c8934305c48bb52ed0e5a59b47229521cb333ce Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Tue, 22 Mar 2022 12:08:31 -0700 Subject: [PATCH 3328/4254] system: thread: stack dealloction on Zephyr (#19633) [backport:1.6] Try to free the stack allocation when a thread exits. Possibly works for FreeRTOS as well. --- lib/system/threads.nim | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index ac727be0a..1c1d1ca1c 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -47,7 +47,10 @@ when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} -when defined(zephyr) or defined(freertos): +const + hasAllocStack = defined(zephyr) # maybe freertos too? + +when hasAllocStack or defined(zephyr) or defined(freertos): const nimThreadStackSize {.intdefine.} = 8192 nimThreadStackGuard {.intdefine.} = 128 @@ -68,6 +71,12 @@ else: #const globalsSlot = ThreadVarSlot(0) #sysAssert checkSlot.int == globalsSlot.int +# Zephyr doesn't include this properly without some help +when defined(zephyr): + {.emit: """/*INCLUDESECTION*/ + #include + """.} + # create for the main thread. Note: do not insert this data into the list # of all threads; it's not to be stopped etc. when not defined(useNimRtl): @@ -98,6 +107,8 @@ type else: dataFn: proc (m: TArg) {.nimcall, gcsafe.} data: TArg + when hasAllocStack: + rawStack: pointer proc `=copy`*[TArg](x: var Thread[TArg], y: Thread[TArg]) {.error.} @@ -161,6 +172,8 @@ else: threadTrouble() finally: afterThreadRuns() + when hasAllocStack: + deallocShared(thrd.rawStack) proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) {.raises: [].} = when defined(boehmgc): @@ -330,11 +343,12 @@ else: when hasSharedHeap: t.core.stackSize = ThreadStackSize var a {.noinit.}: Pthread_attr doAssert pthread_attr_init(a) == 0 - when defined(zephyr): + when hasAllocStack: var rawstk = allocShared0(ThreadStackSize + StackGuardSize) stk = cast[pointer](cast[uint](rawstk) + StackGuardSize) let setstacksizeResult = pthread_attr_setstack(addr a, stk, ThreadStackSize) + t.rawStack = rawstk else: let setstacksizeResult = pthread_attr_setstacksize(a, ThreadStackSize) From a8b5ad845c4218b4f20595df097c593acee53d50 Mon Sep 17 00:00:00 2001 From: Dominic Ward Date: Wed, 23 Mar 2022 06:50:36 +0000 Subject: [PATCH 3329/4254] Fix process lines iterator (#19605) * Ensure lines when process done * eliminate post-EOF exit test * Recommend fixes for execCmdEx/execProcess --- lib/pure/osproc.nim | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 6a0ac9a8b..3da9737ec 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -451,7 +451,7 @@ proc execProcesses*(cmds: openArray[string], if afterRunEvent != nil: afterRunEvent(i, p) close(p) -iterator lines*(p: Process): string {.since: (1, 3), tags: [ReadIOEffect].} = +iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), tags: [ReadIOEffect].} = ## Convenience iterator for working with `startProcess` to read data from a ## background process. ## @@ -474,11 +474,11 @@ iterator lines*(p: Process): string {.since: (1, 3), tags: [ReadIOEffect].} = ## p.close var outp = p.outputStream var line = newStringOfCap(120) - while true: - if outp.readLine(line): - yield line - else: - if p.peekExitCode != -1: break + while outp.readLine(line): + if keepNewLines: + line.add("\n") + yield line + discard waitForExit(p) proc readLines*(p: Process): (seq[string], int) {.since: (1, 3).} = ## Convenience function for working with `startProcess` to read data from a @@ -514,6 +514,7 @@ when not defined(useNimRtl): var outp = outputStream(p) result = "" var line = newStringOfCap(120) + # consider `p.lines(keepNewLines=true)` to circumvent `running` busy-wait while true: # FIXME: converts CR-LF to LF. if outp.readLine(line): @@ -1622,6 +1623,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { inputStream(p).write(input) close inputStream(p) + # consider `p.lines(keepNewLines=true)` to avoid exit code test result = ("", -1) var line = newStringOfCap(120) while true: From 7f6e800cafc7b73625893fb5280eb8b51a15b252 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 24 Mar 2022 03:34:53 +0800 Subject: [PATCH 3330/4254] move assertions out of system (#19599) --- compiler/aliases.nim | 3 +++ compiler/ast.nim | 3 +++ compiler/astalgo.nim | 3 +++ compiler/bitsets.nim | 3 +++ compiler/btrees.nim | 3 +++ compiler/ccgutils.nim | 3 +++ compiler/cgen.nim | 4 ++++ compiler/cgmeth.nim | 4 ++++ compiler/closureiters.nim | 3 +++ compiler/commands.nim | 3 +++ compiler/concepts.nim | 3 +++ compiler/dfa.nim | 3 +++ compiler/enumtostr.nim | 4 ++++ compiler/errorhandling.nim | 3 +++ compiler/extccomp.nim | 3 +++ compiler/gorgeimpl.nim | 3 +++ compiler/guards.nim | 3 +++ compiler/hlo.nim | 3 +++ compiler/ic/bitabs.nim | 3 +++ compiler/ic/cbackend.nim | 3 +++ compiler/ic/dce.nim | 4 ++++ compiler/ic/ic.nim | 3 +++ compiler/ic/integrity.nim | 4 ++++ compiler/ic/navigator.nim | 3 +++ compiler/ic/packed_ast.nim | 3 +++ compiler/ic/replayer.nim | 3 +++ compiler/ic/rodfiles.nim | 3 +++ compiler/idents.nim | 3 +++ compiler/importer.nim | 3 +++ compiler/injectdestructors.nim | 3 +++ compiler/int128.nim | 3 +++ compiler/isolation_check.nim | 3 +++ compiler/lambdalifting.nim | 3 +++ compiler/lexer.nim | 3 +++ compiler/liftdestructors.nim | 3 +++ compiler/llstream.nim | 3 +++ compiler/lookups.nim | 4 ++++ compiler/lowerings.nim | 3 +++ compiler/main.nim | 4 ++++ compiler/modulegraphs.nim | 3 +++ compiler/modules.nim | 3 +++ compiler/msgs.nim | 4 ++++ compiler/ndi.nim | 3 +++ compiler/nilcheck.nim | 3 +++ compiler/nim.nim | 4 ++++ compiler/nimblecmd.nim | 3 +++ compiler/nimconf.nim | 3 +++ compiler/nimlexbase.nim | 3 +++ compiler/nimpaths.nim | 4 ++++ compiler/nimsets.nim | 3 +++ compiler/options.nim | 5 +++++ compiler/parser.nim | 3 +++ compiler/passes.nim | 3 +++ compiler/pathutils.nim | 2 +- compiler/patterns.nim | 3 +++ compiler/platform.nim | 4 ++++ compiler/pragmas.nim | 3 +++ compiler/renderer.nim | 3 +++ compiler/reorder.nim | 3 +++ compiler/rodutils.nim | 3 +++ compiler/ropes.nim | 4 ++++ compiler/scriptconfig.nim | 3 +++ compiler/semdata.nim | 3 +++ compiler/semfold.nim | 3 +++ compiler/sempass2.nim | 3 +++ compiler/semtypinst.nim | 3 +++ compiler/sighashes.nim | 4 ++++ compiler/sigmatch.nim | 3 +++ compiler/syntaxes.nim | 3 +++ compiler/transf.nim | 3 +++ compiler/treetab.nim | 3 +++ compiler/typeallowed.nim | 3 +++ compiler/types.nim | 3 +++ compiler/varpartitions.nim | 3 +++ compiler/vmdeps.nim | 3 +++ compiler/vmgen.nim | 3 +++ compiler/vmhooks.nim | 3 +++ compiler/vmmarshal.nim | 3 +++ compiler/vmops.nim | 4 ++++ lib/core/macros.nim | 4 ++++ lib/pure/algorithm.nim | 4 ++++ lib/pure/browsers.nim | 3 +++ lib/pure/collections/hashcommon.nim | 4 ++++ lib/pure/collections/sequtils.nim | 4 ++++ lib/pure/hashes.nim | 4 ++++ lib/pure/json.nim | 2 +- lib/pure/lexbase.nim | 3 +++ lib/pure/math.nim | 4 ++++ lib/pure/options.nim | 4 ++++ lib/pure/os.nim | 2 +- lib/pure/osproc.nim | 4 ++++ lib/pure/parsejson.nim | 3 +++ lib/pure/streamwrapper.nim | 4 ++++ lib/pure/strformat.nim | 4 ++++ lib/pure/strtabs.nim | 4 ++++ lib/pure/strutils.nim | 3 +++ lib/pure/terminal.nim | 2 +- lib/pure/times.nim | 4 ++++ lib/pure/typetraits.nim | 4 ++++ lib/{system => std}/assertions.nim | 14 ++++++++++---- lib/std/enumutils.nim | 4 ++++ lib/std/jsonutils.nim | 3 +++ lib/std/packedsets.nim | 3 +++ lib/std/private/globs.nim | 4 ++++ lib/std/sha1.nim | 3 +++ lib/system.nim | 7 +++++-- lib/system/dragonbox.nim | 2 ++ lib/system/formatfloat.nim | 3 +++ lib/system/iterators.nim | 3 +++ lib/system/schubfach.nim | 3 +++ 110 files changed, 361 insertions(+), 10 deletions(-) rename lib/{system => std}/assertions.nim (94%) diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 0006c9fe6..9ec72faa4 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -12,6 +12,9 @@ import ast, astalgo, types, trees, intsets +when defined(nimPreviewSlimSystem): + import std/assertions + type TAnalysisResult* = enum arNo, arMaybe, arYes diff --git a/compiler/ast.nim b/compiler/ast.nim index ad5ec12f5..d1e5ae2bf 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -13,6 +13,9 @@ import lineinfos, hashes, options, ropes, idents, int128, tables from strutils import toLowerAscii +when defined(nimPreviewSlimSystem): + import std/assertions + export int128 type diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 94fa9da93..bc5b7d6e1 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -15,6 +15,9 @@ import ast, hashes, intsets, strutils, options, lineinfos, ropes, idents, rodutils, msgs +when defined(nimPreviewSlimSystem): + import std/assertions + proc hashNode*(p: RootRef): Hash proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope # Convert a tree into its YAML representation; this is used by the diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim index e0d94409e..67598f9ca 100644 --- a/compiler/bitsets.nim +++ b/compiler/bitsets.nim @@ -10,6 +10,9 @@ # this unit handles Nim sets; it implements bit sets # the code here should be reused in the Nim standard library +when defined(nimPreviewSlimSystem): + import std/assertions + type ElemType = byte TBitSet* = seq[ElemType] # we use byte here to avoid issues with diff --git a/compiler/btrees.nim b/compiler/btrees.nim index d5e7e8099..1701f8d7b 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -10,6 +10,9 @@ ## BTree implementation with few features, but good enough for the ## Nim compiler's needs. +when defined(nimPreviewSlimSystem): + import std/assertions + const M = 512 # max children per B-tree node = M-1 # (must be even and greater than 2) diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 06b75a20f..e19fccfa7 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -13,6 +13,9 @@ import ast, types, hashes, strutils, msgs, wordrecg, platform, trees, options, cgendata +when defined(nimPreviewSlimSystem): + import std/assertions + proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = case n.kind of nkStmtList: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 2865473fb..ad59b759f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -17,6 +17,10 @@ import lowerings, tables, sets, ndi, lineinfos, pathutils, transf, injectdestructors, astmsgs + +when defined(nimPreviewSlimSystem): + import std/assertions + when not defined(leanCompiler): import spawn, semparallel diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 484bc9d97..dab8826c1 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -13,6 +13,10 @@ import intsets, options, ast, msgs, idents, renderer, types, magicsys, sempass2, strutils, modulegraphs, lineinfos +when defined(nimPreviewSlimSystem): + import std/assertions + + proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = var dest = skipTypes(d, abstractPtrs) var source = skipTypes(n.typ, abstractPtrs) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 4d9aeb3f7..6370d0dcb 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -133,6 +133,9 @@ import renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos, tables, options +when defined(nimPreviewSlimSystem): + import std/assertions + type Ctx = object g: ModuleGraph diff --git a/compiler/commands.nim b/compiler/commands.nim index b21b48801..4c1cec3d2 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -31,6 +31,9 @@ import from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect +when defined(nimPreviewSlimSystem): + import std/assertions + # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") bootSwitch(usedFFI, hasFFI, "-d:nimHasLibFFI") diff --git a/compiler/concepts.nim b/compiler/concepts.nim index 885b69c60..89a2bdc10 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -15,6 +15,9 @@ import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, from magicsys import addSonSkipIntLit +when defined(nimPreviewSlimSystem): + import std/assertions + const logBindings = false diff --git a/compiler/dfa.nim b/compiler/dfa.nim index d68e7be82..5b048ff6e 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -32,6 +32,9 @@ import ast, intsets, lineinfos, renderer import std/private/asciitables +when defined(nimPreviewSlimSystem): + import std/assertions + type InstrKind* = enum goto, fork, def, use diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 9bfa7001a..4a28d066c 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -1,6 +1,10 @@ import ast, idents, lineinfos, modulegraphs, magicsys +when defined(nimPreviewSlimSystem): + import std/assertions + + proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info) diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim index cda7ab3f4..a8361105e 100644 --- a/compiler/errorhandling.nim +++ b/compiler/errorhandling.nim @@ -12,6 +12,9 @@ import ast, renderer, options, strutils, types +when defined(nimPreviewSlimSystem): + import std/assertions + type ErrorKind* = enum ## expand as you need. RawTypeMismatchError diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 124cc2c34..09a1dfbb3 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -16,6 +16,9 @@ import ropes, platform, condsyms, options, msgs, lineinfos, pathutils import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar] +when defined(nimPreviewSlimSystem): + import std/syncio + type TInfoCCProp* = enum # properties of the C compiler: hasSwitchRange, # CC allows ranges in switch statements (GNU C) diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index d4aeb6a77..f58ac5de9 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -12,6 +12,9 @@ import msgs, std / sha1, os, osproc, streams, options, lineinfos, pathutils +when defined(nimPreviewSlimSystem): + import std/syncio + proc readOutput(p: Process): (string, int) = result[0] = "" var output = p.outputStream diff --git a/compiler/guards.nim b/compiler/guards.nim index d1265d42c..a50593aca 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -12,6 +12,9 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, saturate, modulegraphs, options, lineinfos, int128 +when defined(nimPreviewSlimSystem): + import std/assertions + const someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, mEqStr, mEqSet, mEqCString} diff --git a/compiler/hlo.nim b/compiler/hlo.nim index af54cabbb..8620c4c4d 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -9,6 +9,9 @@ # This include implements the high level optimization pass. +when defined(nimPreviewSlimSystem): + import std/assertions + proc hlo(c: PContext, n: PNode): PNode proc evalPattern(c: PContext, n, orig: PNode): PNode = diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim index 0bce30b5d..ae673b574 100644 --- a/compiler/ic/bitabs.nim +++ b/compiler/ic/bitabs.nim @@ -3,6 +3,9 @@ import hashes, rodfiles +when defined(nimPreviewSlimSystem): + import std/assertions + type LitId* = distinct uint32 diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index f5811cb3b..e7ab000e6 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -20,6 +20,9 @@ import std/packedsets, algorithm, tables +when defined(nimPreviewSlimSystem): + import std/assertions + import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen, pathutils, extccomp, msgs] diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index 0a436a5d1..bc61a38de 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -10,6 +10,10 @@ ## Dead code elimination (=DCE) for IC. import std/[intsets, tables] + +when defined(nimPreviewSlimSystem): + import std/assertions + import ".." / [ast, options, lineinfos, types] import packed_ast, ic, bitabs diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 7387d165b..193e5f517 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -14,6 +14,9 @@ import ".." / [ast, idents, lineinfos, msgs, ropes, options, #import ".." / [renderer, astalgo] from os import removeFile, isAbsolute +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + type PackedConfig* = object backend: TBackend diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim index ed367ef61..d341fd653 100644 --- a/compiler/ic/integrity.nim +++ b/compiler/ic/integrity.nim @@ -11,6 +11,10 @@ ## The set must cover a complete Nim project. import sets + +when defined(nimPreviewSlimSystem): + import std/assertions + import ".." / [ast, modulegraphs] import packed_ast, bitabs, ic diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index a1a14885d..cbba591c5 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -16,6 +16,9 @@ import sets from os import nil from std/private/miscdollars import toLocation +when defined(nimPreviewSlimSystem): + import std/assertions + import ".." / [ast, modulegraphs, msgs, options] import packed_ast, bitabs, ic diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 17beda2c1..c78fe56f5 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -16,6 +16,9 @@ import hashes, tables, strtabs import bitabs import ".." / [ast, options] +when defined(nimPreviewSlimSystem): + import std/assertions + type SymId* = distinct int32 ModuleId* = distinct int32 diff --git a/compiler/ic/replayer.nim b/compiler/ic/replayer.nim index 61aa0e697..0188eaee3 100644 --- a/compiler/ic/replayer.nim +++ b/compiler/ic/replayer.nim @@ -16,6 +16,9 @@ import ".." / [ast, modulegraphs, trees, extccomp, btrees, import tables +when defined(nimPreviewSlimSystem): + import std/assertions + import packed_ast, ic, bitabs proc replayStateChanges*(module: PSym; g: ModuleGraph) = diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index a52bd18b3..d811b9b99 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -16,6 +16,9 @@ from typetraits import supportsCopyMem +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + ## Overview ## ======== ## `RodFile` represents a Rod File (versioned binary format), and the diff --git a/compiler/idents.nim b/compiler/idents.nim index d2a84fd36..f36ce09f3 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -14,6 +14,9 @@ import hashes, wordrecg +when defined(nimPreviewSlimSystem): + import std/assertions + type PIdent* = ref TIdent TIdent*{.acyclic.} = object diff --git a/compiler/importer.nim b/compiler/importer.nim index acca2c644..719b75f0f 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -15,6 +15,9 @@ import modulegraphs, wordrecg, tables from strutils import `%` +when defined(nimPreviewSlimSystem): + import std/assertions + proc readExceptSet*(c: PContext, n: PNode): IntSet = assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} result = initIntSet() diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 985f27878..6500c5bc7 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -19,6 +19,9 @@ import lineinfos, parampatterns, sighashes, liftdestructors, optimizer, varpartitions +when defined(nimPreviewSlimSystem): + import std/assertions + from trees import exprStructuralEquivalent, getRoot type diff --git a/compiler/int128.nim b/compiler/int128.nim index 6ba7c1961..afa07094b 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -5,6 +5,9 @@ from math import trunc +when defined(nimPreviewSlimSystem): + import std/assertions + type Int128* = object udata: array[4, uint32] diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 68a212794..2674605dc 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -13,6 +13,9 @@ import ast, types, renderer, intsets +when defined(nimPreviewSlimSystem): + import std/assertions + proc canAlias(arg, ret: PType; marker: var IntSet): bool proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool = diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index a622f6de6..6838fd80d 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -14,6 +14,9 @@ import idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos, transf, liftdestructors, typeallowed +when defined(nimPreviewSlimSystem): + import std/assertions + discard """ The basic approach is that captured vars need to be put on the heap and that the calling chain needs to be explicitly modelled. Things to consider: diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 506b0e924..e795d52c0 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -19,6 +19,9 @@ import hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream, wordrecg, lineinfos, pathutils, parseutils +when defined(nimPreviewSlimSystem): + import std/assertions + const MaxLineLength* = 80 # lines longer than this lead to a warning numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'} diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 51b4ddfb0..68c93a179 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -15,6 +15,9 @@ import modulegraphs, lineinfos, idents, ast, renderer, semdata, from trees import isCaseObj +when defined(nimPreviewSlimSystem): + import std/assertions + type TLiftCtx = object g: ModuleGraph diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 865a98ee0..004d990fa 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -12,6 +12,9 @@ import pathutils +when defined(nimPreviewSlimSystem): + import std/syncio + # support `useGnuReadline`, `useLinenoise` for backwards compatibility const hasRstdin = (defined(nimUseLinenoise) or defined(useLinenoise) or defined(useGnuReadline)) and not defined(windows) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index fc30408e5..d61e15915 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -9,6 +9,10 @@ # This module implements lookup helpers. import std/[algorithm, strutils] + +when defined(nimPreviewSlimSystem): + import std/assertions + import intsets, ast, astalgo, idents, semdata, types, msgs, options, renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 37405d8d9..20003b946 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -15,6 +15,9 @@ const import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs, lineinfos +when defined(nimPreviewSlimSystem): + import std/assertions + proc newDeref*(n: PNode): PNode {.inline.} = result = newNodeIT(nkHiddenDeref, n.info, n.typ[0]) result.add n diff --git a/compiler/main.nim b/compiler/main.nim index e4ec4d729..3cddbffb3 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -22,6 +22,10 @@ import modules, modulegraphs, lineinfos, pathutils, vmprofiler + +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + import ic / [cbackend, integrity, navigator] from ic / ic import rodViewer diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 28e0ddb82..c44908dc3 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -15,6 +15,9 @@ import intsets, tables, hashes, md5_old import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils import ic / [packed_ast, ic] +when defined(nimPreviewSlimSystem): + import std/assertions + type SigHash* = distinct MD5Digest diff --git a/compiler/modules.nim b/compiler/modules.nim index 6fba606b2..dd5db63fa 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -14,6 +14,9 @@ import idents, lexer, passes, syntaxes, llstream, modulegraphs, lineinfos, pathutils, tables +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + import ic / replayer proc resetSystemArtifacts*(g: ModuleGraph) = diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 56531eb68..9d111b2e2 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -12,6 +12,10 @@ import std/private/miscdollars, options, ropes, lineinfos, pathutils, strutils2 +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + + type InstantiationInfo* = typeof(instantiationInfo()) template instLoc*(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) diff --git a/compiler/ndi.nim b/compiler/ndi.nim index 5af87237f..a9d9cfe79 100644 --- a/compiler/ndi.nim +++ b/compiler/ndi.nim @@ -12,6 +12,9 @@ import ast, msgs, ropes, options, pathutils +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + type NdiFile* = object enabled: bool diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 9c2d091f7..49ceb8942 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -10,6 +10,9 @@ import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes import sequtils, strutils, sets +when defined(nimPreviewSlimSystem): + import std/assertions + # IMPORTANT: notes not up to date, i'll update this comment again # # notes: diff --git a/compiler/nim.nim b/compiler/nim.nim index 86c7ab524..bfb07ba20 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -8,6 +8,10 @@ # import std/[os, strutils, parseopt] + +when defined(nimPreviewSlimSystem): + import std/assertions + when defined(windows) and not defined(nimKochBootstrap): # remove workaround pending bootstrap >= 1.5.1 # refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536 diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 9cd2941ba..b6b08ccd4 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -12,6 +12,9 @@ import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils, std/sha1, tables +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) = if not conf.searchPaths.contains(path): conf.searchPaths.insert(path, 0) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 1cf22e20a..319a3de6d 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -13,6 +13,9 @@ import llstream, commands, os, strutils, msgs, lexer, ast, options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig +when defined(nimPreviewSlimSystem): + import std/syncio + # ---------------- configuration file parser ----------------------------- # we use Nim's lexer here to save space and work diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index b8cb9f78a..3bc9af9c9 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -15,6 +15,9 @@ import llstream, strutils +when defined(nimPreviewSlimSystem): + import std/assertions + const Lrz* = ' ' Apo* = '\'' diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim index a93b488fd..216071c5c 100644 --- a/compiler/nimpaths.nim +++ b/compiler/nimpaths.nim @@ -19,6 +19,10 @@ Unstable API import os, strutils +when defined(nimPreviewSlimSystem): + import std/assertions + + const docCss* = "$nimr/doc/nimdoc.css" docHackNim* = "$nimr/tools/dochack/dochack.nim" diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 8683604af..49c80065a 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -12,6 +12,9 @@ import ast, astalgo, lineinfos, bitsets, types, options +when defined(nimPreviewSlimSystem): + import std/assertions + proc inSet*(s: PNode, elem: PNode): bool = assert s.kind == nkCurly if s.kind != nkCurly: diff --git a/compiler/options.nim b/compiler/options.nim index 9c0c9df72..69eafb67f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -14,6 +14,11 @@ import from terminal import isatty from times import utc, fromUnix, local, getTime, format, DateTime from std/private/globs import nativeToUnixPath + +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + + const hasTinyCBackend* = defined(tinyc) useEffectSystem* = true diff --git a/compiler/parser.nim b/compiler/parser.nim index 0fb60440c..7973f7d37 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -36,6 +36,9 @@ import when defined(nimpretty): import layouter +when defined(nimPreviewSlimSystem): + import std/assertions + type Parser* = object # A Parser object represents a file that # is being parsed diff --git a/compiler/passes.nim b/compiler/passes.nim index 3debce1f6..ce52b10c5 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -16,6 +16,9 @@ import syntaxes, modulegraphs, reorder, lineinfos, pathutils +when defined(nimPreviewSlimSystem): + import std/syncio + type TPassData* = tuple[input: PNode, closeOutput: PNode] diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 3a501a417..1ef0143d5 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -13,7 +13,7 @@ import os, pathnorm when defined(nimPreviewSlimSystem): - import std/syncio + import std/[syncio, assertions] type AbsoluteFile* = distinct string diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 4b39de3ba..87e9c825c 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -13,6 +13,9 @@ import ast, types, semdata, sigmatch, idents, aliases, parampatterns, trees +when defined(nimPreviewSlimSystem): + import std/assertions + type TPatternContext = object owner: PSym diff --git a/compiler/platform.nim b/compiler/platform.nim index 4e6054d5c..4b4316bc2 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -16,6 +16,10 @@ import strutils +when defined(nimPreviewSlimSystem): + import std/assertions + + type TSystemOS* = enum # Also add OS in initialization section and alias # conditionals to condsyms (end of module). diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 702a9e082..01399d4ff 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -14,6 +14,9 @@ import wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, types, lookups, lineinfos, pathutils, linter +when defined(nimPreviewSlimSystem): + import std/assertions + from ic / ic import addCompilerProc const diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 22a2d4cbd..3503c4bf6 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -17,6 +17,9 @@ when defined(nimHasUsed): import lexer, options, idents, strutils, ast, msgs, lineinfos +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + type TRenderFlag* = enum renderNone, renderNoBody, renderNoComments, renderDocComments, diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 65c1fb9ee..daeb48248 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -4,6 +4,9 @@ import msgs, modulegraphs, syntaxes, options, modulepaths, lineinfos +when defined(nimPreviewSlimSystem): + import std/assertions + type DepN = ref object pnode: PNode diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index a4f7a5146..95b7b2d9e 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -10,6 +10,9 @@ ## Serialization utilities for the compiler. import strutils, math +when defined(nimPreviewSlimSystem): + import std/assertions + # bcc on windows doesn't have C99 functions when defined(windows) and defined(bcc): {.emit: """#if defined(_MSC_VER) && _MSC_VER < 1900 diff --git a/compiler/ropes.nim b/compiler/ropes.nim index cd696a545..a44d84ddc 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -60,6 +60,10 @@ import from pathutils import AbsoluteFile +when defined(nimPreviewSlimSystem): + import std/[assertions, syncio] + + type FormatStr* = string # later we may change it to CString for better # performance of the code generator (assignments diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 89510f6b2..adc228d1e 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -16,6 +16,9 @@ import os, times, osproc, wordrecg, strtabs, modulegraphs, pathutils +when defined(nimPreviewSlimSystem): + import std/syncio + # we support 'cmpIgnoreStyle' natively for efficiency: from strutils import cmpIgnoreStyle, contains diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 422d1223a..d7a4d2c1c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -11,6 +11,9 @@ import tables +when defined(nimPreviewSlimSystem): + import std/assertions + import intsets, options, ast, astalgo, msgs, idents, renderer, magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils diff --git a/compiler/semfold.nim b/compiler/semfold.nim index d0473b5ce..d2bbc63be 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -17,6 +17,9 @@ import from system/memory import nimCStrLen +when defined(nimPreviewSlimSystem): + import std/assertions + proc errorType*(g: ModuleGraph): PType = ## creates a type representing an error state result = newType(tyError, nextTypeId(g.idgen), g.owners[^1]) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d6cc4180b..9bc811a03 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -12,6 +12,9 @@ import wordrecg, strutils, options, guards, lineinfos, semfold, semdata, modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables +when defined(nimPreviewSlimSystem): + import std/assertions + when defined(useDfa): import dfa diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 5d300fc58..504b83b4c 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -14,6 +14,9 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer, options, from concepts import makeTypeDesc +when defined(nimPreviewSlimSystem): + import std/assertions + const tfInstClearedFlags = {tfHasMeta, tfUnresolved} proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 3d36d2533..1835d9d0f 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -13,6 +13,10 @@ import ast, tables, ropes, md5_old, modulegraphs from hashes import Hash import types +when defined(nimPreviewSlimSystem): + import std/assertions + + proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) proc `&=`(c: var MD5Context, ch: char) = # XXX suspicious code here; relies on ch being zero terminated? diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 14f4c5e19..f195c4e45 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -15,6 +15,9 @@ import magicsys, idents, lexer, options, parampatterns, strutils, trees, linter, lineinfos, lowerings, modulegraphs, concepts +when defined(nimPreviewSlimSystem): + import std/assertions + type MismatchKind* = enum kUnknown, kAlreadyGiven, kUnknownNamedParam, kTypeMismatch, kVarNeeded, diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 03a9702a3..e47b0483d 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -13,6 +13,9 @@ import strutils, llstream, ast, idents, lexer, options, msgs, parser, filters, filter_tmpl, renderer, lineinfos, pathutils +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + export Parser, parseAll, parseTopLevelStmt, closeParser type diff --git a/compiler/transf.nim b/compiler/transf.nim index edb8d3573..bdd7c680c 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -24,6 +24,9 @@ import lowerings, liftlocals, modulegraphs, lineinfos +when defined(nimPreviewSlimSystem): + import std/assertions + proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, cache: bool): PNode import closureiters, lambdalifting diff --git a/compiler/treetab.nim b/compiler/treetab.nim index 26afd102c..d8dd8d33e 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -12,6 +12,9 @@ import hashes, ast, astalgo, types +when defined(nimPreviewSlimSystem): + import std/assertions + proc hashTree*(n: PNode): Hash = if n.isNil: return diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 3d6ea0edb..57dd039ad 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -13,6 +13,9 @@ import intsets, ast, renderer, options, semdata, types +when defined(nimPreviewSlimSystem): + import std/assertions + type TTypeAllowedFlag* = enum taField, diff --git a/compiler/types.nim b/compiler/types.nim index 007a61356..4d2801633 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -13,6 +13,9 @@ import intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options, lineinfos, int128, modulegraphs, astmsgs +when defined(nimPreviewSlimSystem): + import std/assertions + type TPreferedDesc* = enum preferName, # default diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 721de900e..d04a7b40c 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -32,6 +32,9 @@ import ast, types, lineinfos, options, msgs, renderer, typeallowed, modulegraphs from trees import getMagic, isNoSideEffectPragma, stupidStmtListExpr from isolation_check import canAlias +when defined(nimPreviewSlimSystem): + import std/assertions + type AbstractTime = distinct int diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 1afda14b0..118a3031e 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -10,6 +10,9 @@ import ast, types, msgs, os, options, idents, lineinfos from pathutils import AbsoluteFile +when defined(nimPreviewSlimSystem): + import std/syncio + proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string = try: var filename = parentDir(toFullPath(conf, info)) / file diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 1551fbb80..72bcef4db 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -29,6 +29,9 @@ import tables +when defined(nimPreviewSlimSystem): + import std/assertions + import strutils, ast, types, msgs, renderer, vmdef, intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim index 1ede87e5e..84ecf586f 100644 --- a/compiler/vmhooks.nim +++ b/compiler/vmhooks.nim @@ -9,6 +9,9 @@ import pathutils +when defined(nimPreviewSlimSystem): + import std/assertions + template setX(k, field) {.dirty.} = a.slots[a.ra].ensureKind(k) a.slots[a.ra].field = v diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index d28f0325b..83c441283 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -12,6 +12,9 @@ import streams, json, intsets, tables, ast, astalgo, idents, types, msgs, options, lineinfos +when defined(nimPreviewSlimSystem): + import std/assertions + proc ptrToInt(x: PNode): int {.inline.} = result = cast[int](x) # don't skip alignment diff --git a/compiler/vmops.nim b/compiler/vmops.nim index f13e4b1cc..640826cc8 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -31,6 +31,10 @@ from std/osproc import nil from system/formatfloat import addFloatRoundtrip, addFloatSprintf +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + + # There are some useful procs in vmconv. import vmconv, vmmarshal diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 4d040cebc..f20ca9385 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -10,6 +10,10 @@ include "system/inclrtl" import std/private/since +when defined(nimPreviewSlimSystem): + import std/assertions + + ## This module contains the interface to the compiler's abstract syntax ## tree (`AST`:idx:). Macros operate on this tree. ## diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 1ddcc9843..c43545f78 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -44,6 +44,10 @@ runnableExamples: import std/private/since +when defined(nimPreviewSlimSystem): + import std/assertions + + type SortOrder* = enum Descending, Ascending diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 08f5208d2..c36e31b11 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -16,6 +16,9 @@ import std/private/since import strutils +when defined(nimPreviewSlimSystem): + import std/assertions + when defined(windows): import winlean from os import absolutePath diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index a169418ce..deff8fa21 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -10,6 +10,10 @@ # An `include` file which contains common code for # hash sets and tables. +when defined(nimPreviewSlimSystem): + import std/assertions + + const growthFactor = 2 diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 64a7be7a9..5e9b492c2 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -84,6 +84,10 @@ import std/private/since import macros +when defined(nimPreviewSlimSystem): + import std/assertions + + when defined(nimHasEffectsOf): {.experimental: "strictEffects".} else: diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 47dacec7d..e88210757 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -67,6 +67,10 @@ runnableExamples: import std/private/since +when defined(nimPreviewSlimSystem): + import std/assertions + + type Hash* = int ## A hash value. Hash tables using these values should ## always have a size of a power of two so they can use the `and` diff --git a/lib/pure/json.nim b/lib/pure/json.nim index bdc9fe5ab..dd9232ea6 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -165,7 +165,7 @@ import options # xxx remove this dependency using same approach as https://githu import std/private/since when defined(nimPreviewSlimSystem): - import std/syncio + import std/[syncio, assertions] export tables.`$` diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index bbc0a38ae..336a57ec1 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -14,6 +14,9 @@ import strutils, streams +when defined(nimPreviewSlimSystem): + import std/assertions + const EndOfFile* = '\0' ## end of file marker NewLines* = {'\c', '\L'} diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 1c47258bc..15324f882 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -60,6 +60,10 @@ import std/private/since import bitops, fenv +when defined(nimPreviewSlimSystem): + import std/assertions + + when defined(c) or defined(cpp): proc c_isnan(x: float): bool {.importc: "isnan", header: "".} # a generic like `x: SomeFloat` might work too if this is implemented via a C macro. diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 850bfa555..562ed6361 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -71,6 +71,10 @@ supports pattern matching on `Option`s, with the `Some()` and import typetraits +when defined(nimPreviewSlimSystem): + import std/assertions + + when (NimMajor, NimMinor) >= (1, 1): type SomePointer = ref | ptr | pointer | proc diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 7c0c64276..fa379a228 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -35,7 +35,7 @@ import std/private/since import strutils, pathnorm when defined(nimPreviewSlimSystem): - import std/syncio + import std/[syncio, assertions] const weirdTarget = defined(nimscript) or defined(js) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 3da9737ec..dca5099a4 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -31,6 +31,10 @@ else: when defined(linux) and defined(useClone): import linux +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] + + type ProcessOption* = enum ## Options that can be passed to `startProcess proc ## <#startProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_. diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim index 196d8c360..c92eac26e 100644 --- a/lib/pure/parsejson.nim +++ b/lib/pure/parsejson.nim @@ -14,6 +14,9 @@ import strutils, lexbase, streams, unicode import std/private/decode_helpers +when defined(nimPreviewSlimSystem): + import std/assertions + type JsonEventKind* = enum ## enumeration of all events that may occur when parsing jsonError, ## an error occurred during parsing diff --git a/lib/pure/streamwrapper.nim b/lib/pure/streamwrapper.nim index 7a501760b..a6c1901d2 100644 --- a/lib/pure/streamwrapper.nim +++ b/lib/pure/streamwrapper.nim @@ -13,6 +13,10 @@ import deques, streams +when defined(nimPreviewSlimSystem): + import std/assertions + + type PipeOutStream*[T] = ref object of T # When stream peek operation is called, it reads from base stream diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 40a33951c..ce3439600 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -316,6 +316,10 @@ single letter DSLs. import macros, parseutils, unicode import strutils except format +when defined(nimPreviewSlimSystem): + import std/assertions + + proc mkDigit(v: int, typ: char): string {.inline.} = assert(v < 26) if v < 10: diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 3b90fea50..aa2886cfa 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -53,6 +53,10 @@ import std/private/since import hashes, strutils +when defined(nimPreviewSlimSystem): + import std/assertions + + when defined(js) or defined(nimscript) or defined(Standalone): {.pragma: rtlFunc.} else: diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 5e505ec3a..bf7bd6aa8 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -82,6 +82,9 @@ include "system/inclrtl" import std/private/since from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl +when defined(nimPreviewSlimSystem): + import std/assertions + const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 5755e142a..571c9b13c 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -67,7 +67,7 @@ when defined(windows): import winlean when defined(nimPreviewSlimSystem): - import std/syncio + import std/[syncio, assertions] type PTerminal = ref object diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 7851bf158..b70c5cedc 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -201,6 +201,10 @@ import strutils, math, options import std/private/since include "system/inclrtl" +when defined(nimPreviewSlimSystem): + import std/assertions + + when defined(js): import jscore diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 8dc1b8cf2..3fc1c7c5c 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -15,6 +15,10 @@ import std/private/since export system.`$` # for backward compatibility +when defined(nimPreviewSlimSystem): + import std/assertions + + type HoleyEnum* = (not Ordinal) and enum ## Enum with holes. type OrdinalEnum* = Ordinal and enum ## Enum without holes. diff --git a/lib/system/assertions.nim b/lib/std/assertions.nim similarity index 94% rename from lib/system/assertions.nim rename to lib/std/assertions.nim index 6f64a55b7..3d2112b1a 100644 --- a/lib/system/assertions.nim +++ b/lib/std/assertions.nim @@ -1,7 +1,13 @@ -## This module provides various assertion utilities. -## -## **Note:** This module is reexported by `system` and thus does not need to be -## imported directly (with `system/assertions`). +# +# +# Nim's Runtime Library +# (c) Copyright 2022 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements assertion handling. when not declared(sysFatal): include "system/fatal" diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index b7d2b9f89..9d4ff1bcf 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -10,6 +10,10 @@ import macros from typetraits import OrdinalEnum, HoleyEnum +when defined(nimPreviewSlimSystem): + import std/assertions + + # xxx `genEnumCaseStmt` needs tests and runnableExamples macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 19384b5d1..722ea49b5 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -34,6 +34,9 @@ import macros from enumutils import symbolName from typetraits import OrdinalEnum +when defined(nimPreviewSlimSystem): + import std/assertions + when not defined(nimFixedForwardGeneric): # xxx remove pending csources_v1 update >= 1.2.0 proc to[T](node: JsonNode, t: typedesc[T]): T = diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index b2ee917eb..1e2892658 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -24,6 +24,9 @@ import std/private/since import hashes +when defined(nimPreviewSlimSystem): + import std/assertions + type BitScalar = uint diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index 190316f93..28a810372 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -8,6 +8,10 @@ import os when defined(windows): from strutils import replace +when defined(nimPreviewSlimSystem): + import std/assertions + + when defined(nimHasEffectsOf): {.experimental: "strictEffects".} else: diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index ed962707b..50175024c 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -29,6 +29,9 @@ runnableExamples("-r:off"): import strutils from endians import bigEndian32, bigEndian64 +when defined(nimPreviewSlimSystem): + import std/syncio + const Sha1DigestSize = 20 type diff --git a/lib/system.nim b/lib/system.nim index 572768de2..4080fee06 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1830,8 +1830,11 @@ when not defined(nimscript): when defined(nimV2): include system/arc -import system/assertions -export assertions +when not defined(nimPreviewSlimSystem): + {.deprecated: """assertions is about to move out of system; use `-d:nimPreviewSlimSystem` and + import `std/assertions`.""".} + import std/assertions + export assertions import system/iterators export iterators diff --git a/lib/system/dragonbox.nim b/lib/system/dragonbox.nim index 336c982c1..34ae9e210 100644 --- a/lib/system/dragonbox.nim +++ b/lib/system/dragonbox.nim @@ -24,6 +24,8 @@ import std/private/digitsutils +when defined(nimPreviewSlimSystem): + import std/assertions const dtoaMinBufferLength*: cint = 64 diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim index 3bcd3257b..aada3e1bf 100644 --- a/lib/system/formatfloat.nim +++ b/lib/system/formatfloat.nim @@ -7,6 +7,9 @@ # distribution, for details about the copyright. # +when defined(nimPreviewSlimSystem): + import std/assertions + proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "", discardable.} proc addCstringN(result: var string, buf: cstring; buflen: int) = diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index f23f7aa11..6d33fc0bc 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -1,3 +1,6 @@ +when defined(nimPreviewSlimSystem): + import std/assertions + when defined(nimHasLentIterators) and not defined(nimNoLentIterators): template lent2(T): untyped = lent T else: diff --git a/lib/system/schubfach.nim b/lib/system/schubfach.nim index 06813f632..7d6861e35 100644 --- a/lib/system/schubfach.nim +++ b/lib/system/schubfach.nim @@ -12,6 +12,9 @@ import std/private/digitsutils +when defined(nimPreviewSlimSystem): + import std/assertions + template sf_Assert(x: untyped): untyped = assert(x) From e93eaac223045543e753643765b6982a109b41a1 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 24 Mar 2022 03:42:08 +0800 Subject: [PATCH 3331/4254] build external deps with userversion:1.6 (#19612) --- koch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index 295b1584b..a3cfd5930 100644 --- a/koch.nim +++ b/koch.nim @@ -142,7 +142,7 @@ proc csource(args: string) = proc bundleC2nim(args: string) = cloneDependency(distDir, "https://github.com/nim-lang/c2nim.git") nimCompile("dist/c2nim/c2nim", - options = "--noNimblePath --path:. " & args) + options = "--noNimblePath --useVersion:1.6 --path:. " & args) proc bundleNimbleExe(latest: bool, args: string) = let commit = if latest: "HEAD" else: NimbleStableCommit @@ -150,7 +150,7 @@ proc bundleNimbleExe(latest: bool, args: string) = commit = commit, allowBundled = true) # installer.ini expects it under $nim/bin nimCompile("dist/nimble/src/nimble.nim", - options = "-d:release --noNimblePath " & args) + options = "-d:release --useVersion:1.6 --noNimblePath " & args) proc bundleNimsuggest(args: string) = nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim", From d14e8e8dccc87671acb832b4aea8e736ce60c13e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 23 Mar 2022 16:42:54 -0300 Subject: [PATCH 3332/4254] Remove Deprecated Nimscript proc (#19629) --- lib/system/nimscript.nim | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index b4554d778..0ef5fc584 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -136,14 +136,6 @@ proc dirExists*(dir: string): bool {. ## Checks if the directory `dir` exists. builtin -template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = - # xxx: warning won't be shown for nimsscript because of current logic handling - # `foreignPackageNotes` - fileExists(args) - -template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = - dirExists(args) - proc selfExe*(): string = ## Returns the currently running nim or nimble executable. # TODO: consider making this as deprecated alias of `getCurrentCompilerExe` From d7a966c4ebdb13a1cc414ce98bbff87ffa922261 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 23 Mar 2022 16:43:28 -0300 Subject: [PATCH 3333/4254] Remove Deprecated domextension (#19630) * Remove Deprecated domextension * Remove Deprecated domextension --- changelog.md | 1 + lib/js/dom_extensions.nim | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 lib/js/dom_extensions.nim diff --git a/changelog.md b/changelog.md index a9bf3842a..73cb5e2b5 100644 --- a/changelog.md +++ b/changelog.md @@ -46,6 +46,7 @@ becomes an alias for `addr`. - Removed deprecated `jsre.test` and `jsre.toString`. - Removed deprecated `math.c_frexp`. - Removed deprecated ``` httpcore.`==` ```. +- Removed deprecated `std/dom_extensions`. ## Language changes diff --git a/lib/js/dom_extensions.nim b/lib/js/dom_extensions.nim deleted file mode 100644 index c15a03195..000000000 --- a/lib/js/dom_extensions.nim +++ /dev/null @@ -1,3 +0,0 @@ -import std/dom -export elementsFromPoint -{.deprecated: "use `std/dom` instead".} From b0bd4320a0cd9a90acf44bca0dddf10fa5022969 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 23 Mar 2022 16:43:58 -0300 Subject: [PATCH 3334/4254] Remove deprecated typo poDemon (#19631) * Remove Deprecated poDemon * Remove Deprecated poDemon --- changelog.md | 2 ++ lib/pure/osproc.nim | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 73cb5e2b5..92d2612e8 100644 --- a/changelog.md +++ b/changelog.md @@ -48,6 +48,8 @@ becomes an alias for `addr`. - Removed deprecated ``` httpcore.`==` ```. - Removed deprecated `std/dom_extensions`. +- Remove deprecated `osproc.poDemon`, symbol with typo. + ## Language changes diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index dca5099a4..512db92a4 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -70,11 +70,6 @@ type Process* = ref ProcessObj ## Represents an operating system process. -const poDemon* {.deprecated.} = poDaemon ## Nim versions before 0.20 - ## used the wrong spelling ("demon"). - ## Now `ProcessOption` uses the correct spelling ("daemon"), - ## and this is needed just for backward compatibility. - proc execProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, From 2c01c9c4c8a20772ebbb91f3333feb5dbcc94e9e Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 24 Mar 2022 03:57:13 +0800 Subject: [PATCH 3335/4254] output byref types into --header file [backport: 1.6] (#19505) * output byref types into --header file fix #19445 * fix comments * set targets --- compiler/ccgtypes.nim | 9 +++++++-- tests/ccgbugs/m19445.c | 3 +++ tests/ccgbugs/t19445.nim | 13 +++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 tests/ccgbugs/m19445.c create mode 100644 tests/ccgbugs/t19445.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index f010b25c9..c5b4d3857 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -471,8 +471,13 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, var arr = t[0] if params != nil: params.add(", ") if mapReturnType(m.config, t[0]) != ctArray: - params.add(getTypeDescWeak(m, arr, check, skResult)) - params.add("*") + if isHeaderFile in m.flags: + # still generates types for `--header` + params.add(getTypeDescAux(m, arr, check, skResult)) + params.add("*") + else: + params.add(getTypeDescWeak(m, arr, check, skResult)) + params.add("*") else: params.add(getTypeDescAux(m, arr, check, skResult)) params.addf(" Result", []) diff --git a/tests/ccgbugs/m19445.c b/tests/ccgbugs/m19445.c new file mode 100644 index 000000000..74c23d4b4 --- /dev/null +++ b/tests/ccgbugs/m19445.c @@ -0,0 +1,3 @@ +#include "m19445.h" + +const Foo f = {10, 20, 30, 40}; \ No newline at end of file diff --git a/tests/ccgbugs/t19445.nim b/tests/ccgbugs/t19445.nim new file mode 100644 index 000000000..b6e8d028c --- /dev/null +++ b/tests/ccgbugs/t19445.nim @@ -0,0 +1,13 @@ +discard """ + matrix: "--nimcache:tests/ccgbugs/nimcache19445 --cincludes:nimcache19445 --header:m19445" + targets: "c" +""" + +# bug #19445 +type + Foo* {.exportc.} = object + a*, b*, c*, d*: int + +proc dummy(): Foo {.exportc.} = discard + +{.compile:"m19445.c".} \ No newline at end of file From a262a87bbebdaf41ea248f7caa780f8ea27e20e1 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 24 Mar 2022 04:07:05 +0800 Subject: [PATCH 3336/4254] [add testcase] arc problems with recursive types (#19456) * [add testcase] arc problems with recursive types close #9650 * do test * expand * Update tests/arc/t9650.nim --- tests/arc/t9650.nim | 87 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 tests/arc/t9650.nim diff --git a/tests/arc/t9650.nim b/tests/arc/t9650.nim new file mode 100644 index 000000000..a8182db68 --- /dev/null +++ b/tests/arc/t9650.nim @@ -0,0 +1,87 @@ +discard """ + matrix: "--gc:arc" +""" + +import typetraits + +# bug #9650 +type + SharedPtr*[T] = object + val: ptr tuple[atomicCounter: int, value: T] + + Node*[T] = object + value: T + next: SharedPtr[Node[T]] + + ForwardList*[T] = object + first: SharedPtr[Node[T]] + +proc `=destroy`*[T](p: var SharedPtr[T]) = + if p.val != nil: + let c = atomicDec(p.val[].atomicCounter) + if c == 0: + when not supportsCopyMem(T): + `=destroy`(p.val[]) + dealloc(p.val) + p.val = nil + +proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) = + if dest.val != src.val: + if dest.val != nil: + `=destroy`(dest) + if src.val != nil: + discard atomicInc(src.val[].atomicCounter) + dest.val = src.val + +proc `=sink`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) = + if dest.val != nil and dest.val != src.val: + `=destroy`(dest) + dest.val = src.val + + +proc newSharedPtr*[T](val: sink T): SharedPtr[T] = + result.val = cast[type(result.val)](alloc(sizeof(result.val[]))) + reset(result.val[]) + result.val.atomicCounter = 1 + result.val.value = val + +proc isNil*[T](p: SharedPtr[T]): bool = + p.val == nil + +template `->`*[T](p: SharedPtr[T], name: untyped): untyped = + p.val.value.name + +proc createNode[T](val: T): SharedPtr[ Node[T] ]= + result = newSharedPtr(Node[T](value: val)) + +proc push_front*[T](list: var ForwardList[T], val: T) = + var newElem = createNode(val) + newElem->next = list.first + list.first = newElem + +proc pop_front*[T](list: var ForwardList[T]) = + let head = list.first + list.first = head->next + +proc toString*[T](list: ForwardList[T]): string = + result = "[" + var head = list.first + while not head.isNil: + result &= $(head->value) & ", " + head = head->next + result &= ']' + +block: + var x: ForwardList[int] + x.push_front(1) + x.push_front(2) + x.push_front(3) + + doAssert toString(x) == "[3, 2, 1, ]" + + x.pop_front() + x.pop_front() + doAssert toString(x) == "[1, ]" + + x.pop_front() + doAssert toString(x) == "[]" From 7c3c61f2f1e898e5c70dfd619d94d09e339836e4 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 24 Mar 2022 04:09:44 +0800 Subject: [PATCH 3337/4254] fix nim check nimscript [backport: 1.6] (#19444) fix #19440; fix #3858 --- compiler/commands.nim | 2 ++ compiler/main.nim | 6 +++++- tests/newconfig/tconfigcheck.nims | 11 +++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/newconfig/tconfigcheck.nims diff --git a/compiler/commands.nim b/compiler/commands.nim index 4c1cec3d2..98537e9ef 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -1112,6 +1112,8 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; else: if pass == passCmd1: config.commandArgs.add p.key if argsCount == 1: + if p.key.endsWith(".nims"): + incl(config.globalOptions, optWasNimscript) # support UNIX style filenames everywhere for portable build scripts: if config.projectName.len == 0: config.projectName = unixToNativePath(p.key) diff --git a/compiler/main.nim b/compiler/main.nim index 3cddbffb3..e27a4f6d1 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -62,6 +62,9 @@ proc commandCheck(graph: ModuleGraph) = let conf = graph.config conf.setErrorMaxHighMaybe defineSymbol(conf.symbols, "nimcheck") + if optWasNimscript in conf.globalOptions: + defineSymbol(conf.symbols, "nimscript") + defineSymbol(conf.symbols, "nimconfig") semanticPasses(graph) # use an empty backend for semantic checking only compileProject(graph) @@ -367,7 +370,8 @@ proc mainCommand*(graph: ModuleGraph) = msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook}) for it in conf.searchPaths: msgWriteln(conf, it.string) - of cmdCheck: commandCheck(graph) + of cmdCheck: + commandCheck(graph) of cmdParse: wantMainModule(conf) discard parseFile(conf.projectMainIdx, cache, conf) diff --git a/tests/newconfig/tconfigcheck.nims b/tests/newconfig/tconfigcheck.nims new file mode 100644 index 000000000..2e12a0bda --- /dev/null +++ b/tests/newconfig/tconfigcheck.nims @@ -0,0 +1,11 @@ +discard """ + cmd: "nim check $file" +""" + +mode = ScriptMode.Verbose +proc build() = + echo "building nim... " + exec "sleep 10" + echo getCurrentDir() + +echo "hello" From 400e0260b854f34a91af47bbe0a1b1c9d112e51b Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 23 Mar 2022 23:35:29 -0700 Subject: [PATCH 3338/4254] Add more info for {.bycopy.} (#18815) * Add more info for {.bycopy.} See confusion here: https://github.com/nim-lang/Nim/issues/18807 I hope this will help people googling to find this. * Update doc/manual.rst Co-authored-by: Andreas Rumpf --- doc/manual.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/manual.rst b/doc/manual.rst index 4c4b9c506..8206d8342 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7912,6 +7912,7 @@ instructs the compiler to pass the type by value to procs: Vector {.bycopy.} = object x, y, z: float +The Nim compiler automatically determines whether a parameter is passed by value or by reference based on the parameter type's size. If a parameter must be passed by value or by reference, (such as when interfacing with a C library) use the bycopy or byref pragmas. Byref pragma ------------ From afbcba909b37b8c06250b141ddb9da4bf5bb9922 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 25 Mar 2022 17:46:42 +0800 Subject: [PATCH 3339/4254] remove unnecessary framePtr code (#19645) --- compiler/jsgen.nim | 9 ++++++--- lib/system/jssys.nim | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index f4097efa4..d7955b2f9 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -773,7 +773,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = var tmpFramePtr = rope"F" if optStackTrace notin p.options: tmpFramePtr = p.getTemp(true) - line(p, tmpFramePtr & " = framePtr;\L") + if hasFrameInfo(p): + line(p, tmpFramePtr & " = framePtr;\L") lineF(p, "try {$n", []) var a: TCompRes gen(p, n[0], a) @@ -782,7 +783,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if catchBranchesExist: p.body.addf("--excHandler;$n} catch (EXCEPTION) {$n var prevJSError = lastJSError;$n" & " lastJSError = EXCEPTION;$n --excHandler;$n", []) - line(p, "framePtr = $1;$n" % [tmpFramePtr]) + if hasFrameInfo(p): + line(p, "framePtr = $1;$n" % [tmpFramePtr]) while i < n.len and n[i].kind == nkExceptBranch: if n[i].len == 1: # general except section: @@ -841,7 +843,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = line(p, "}\L") lineF(p, "lastJSError = prevJSError;$n") line(p, "} finally {\L") - line(p, "framePtr = $1;$n" % [tmpFramePtr]) + if hasFrameInfo(p): + line(p, "framePtr = $1;$n" % [tmpFramePtr]) if i < n.len and n[i].kind == nkFinally: genStmt(p, n[i][0]) line(p, "}\L") diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 6608a2927..00a4a8ab6 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -130,7 +130,8 @@ proc unhandledException(e: ref Exception) {. when NimStackTrace: add(buf, rawWriteStackTrace()) let cbuf = cstring(buf) - framePtr = nil + when NimStackTrace: + framePtr = nil {.emit: """ if (typeof(Error) !== "undefined") { throw new Error(`cbuf`); From 12a0f88a52bae74e31d6d612f0e2aae3f90340a9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 26 Mar 2022 06:37:04 +0100 Subject: [PATCH 3340/4254] mitigates #19364 [backport]; we make this bug more unlikely to appear by producing better code to begin with; real fix will come later (#19647) --- compiler/lowerings.nim | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 20003b946..382e48a16 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -74,14 +74,20 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), - owner, value.info, g.config.options) - temp.typ = skipTypes(value.typ, abstractInst) - incl(temp.flags, sfFromGeneric) + var tempAsNode: PNode + let avoidTemp = value.kind == nkSym + if avoidTemp: + tempAsNode = value + else: + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), + owner, value.info, g.config.options) + temp.typ = skipTypes(value.typ, abstractInst) + incl(temp.flags, sfFromGeneric) + tempAsNode = newSymNode(temp) var v = newNodeI(nkVarSection, value.info) - let tempAsNode = newSymNode(temp) - v.addVar(tempAsNode, value) + if not avoidTemp: + v.addVar(tempAsNode, value) result.add(v) for i in 0.. Date: Sat, 26 Mar 2022 06:47:04 +0100 Subject: [PATCH 3341/4254] fixes #19603; some pragmas were really only supported as top level statements. Now this is enforced properly. (#19646) --- compiler/pragmas.nim | 15 +++++++++------ compiler/semexprs.nim | 8 +++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 01399d4ff..81c6a42d3 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -47,18 +47,21 @@ const wDiscardable, wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wGcSafe, wRequires, wEnsures} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect} - stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks, - wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks, - wStyleChecks, wAssertions, - wWarnings, wHints, - wLineDir, wStackTrace, wLineTrace, wOptimization, wHint, wWarning, wError, + stmtPragmas* = { + wHint, wWarning, wError, wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop, wPassl, wPassc, wLocalPassc, wDeadCodeElimUnused, # deprecated, always on wDeprecated, - wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, + wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto, wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert} + stmtPragmasTopLevel* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks, + wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks, + wStyleChecks, wAssertions, + wWarnings, wHints, + wLineDir, wStackTrace, wLineTrace, wOptimization, + wFloatChecks, wInfChecks, wNanChecks} lambdaPragmas* = {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader, wThread, wAsmNoStackFrame, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5f3d065b6..f224bd0b3 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2769,6 +2769,12 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode = onUse(info, a) a = nextOverloadIter(o, c, n) +proc semPragmaStmt(c: PContext; n: PNode) = + if c.p.owner.kind == skModule: + pragma(c, c.p.owner, n, stmtPragmas+stmtPragmasTopLevel, true) + else: + pragma(c, c.p.owner, n, stmtPragmas, true) + proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind @@ -3017,7 +3023,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkUsingStmt: result = semUsing(c, n) of nkAsmStmt: result = semAsm(c, n) of nkYieldStmt: result = semYield(c, n) - of nkPragma: pragma(c, c.p.owner, n, stmtPragmas, true) + of nkPragma: semPragmaStmt(c, n) of nkIteratorDef: result = semIterator(c, n) of nkProcDef: result = semProc(c, n) of nkFuncDef: result = semFunc(c, n) From 4dfe420c2f1791c722ff949072e1a74f3e7c1499 Mon Sep 17 00:00:00 2001 From: tandy1000 Date: Sat, 26 Mar 2022 05:57:39 +0000 Subject: [PATCH 3342/4254] Add support for `Window.matchMedia` (#19648) --- lib/js/dom.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index aca79faca..c1a677258 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1322,6 +1322,11 @@ type `block`*: cstring inline*: cstring + MediaQueryList* = ref MediaQueryListObj + MediaQueryListObj {.importc.} = object of EventTargetObj + matches*: bool + media*: cstring + since (1, 3): type DomParser* = ref object @@ -1529,6 +1534,7 @@ proc setTimeout*(w: Window, function: proc (), pause: int): Interval proc stop*(w: Window) proc requestAnimationFrame*(w: Window, function: proc (time: float)): int proc cancelAnimationFrame*(w: Window, id: int) +proc matchMedia*(w: Window, mediaQueryString: cstring): MediaQueryList # Node "methods" proc appendData*(n: Node, data: cstring) From 84ac0035190e81cb991544460786bd5618386bec Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 26 Mar 2022 15:57:29 +0800 Subject: [PATCH 3343/4254] remove tmpFramePtr when optStackTrace is absent (#19649) --- compiler/jsgen.nim | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index d7955b2f9..b9a73daf9 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -771,10 +771,6 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if catchBranchesExist: p.body.add("++excHandler;\L") var tmpFramePtr = rope"F" - if optStackTrace notin p.options: - tmpFramePtr = p.getTemp(true) - if hasFrameInfo(p): - line(p, tmpFramePtr & " = framePtr;\L") lineF(p, "try {$n", []) var a: TCompRes gen(p, n[0], a) From 86e93eb2938329db921d5edb718fa7f3ecee83b1 Mon Sep 17 00:00:00 2001 From: Omar Flores <47699779+yoyojambo@users.noreply.github.com> Date: Sat, 26 Mar 2022 02:56:10 -0600 Subject: [PATCH 3344/4254] Fixed description as option in advopt.txt (#19635) * Fixed formatting error in warningAsError. There was only a single space character between the warning and its description, so it shows up as part of the name (in bold) and with no description. Copied the way hotCodeReloading was formatted, with the description in a new line. Also changed descriptions from 'ditto' to what the description it references says. * Fixed typo in advopt.txt Corrected 'hints' to 'warnings' in updated advopt.txt. --- doc/advopt.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 0a2349597..244fe035b 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -55,9 +55,13 @@ Advanced options: (only `all:off` is supported). --hintAsError:X:on|off turn specific hint X into an error on|off -w:on|off|list, --warnings:on|off|list - same as `--hints` but for warnings. - --warning:X:on|off ditto - --warningAsError:X:on|off ditto + `on|off` enables or disables warnings. + `list` reports which warnings are selected. + --warning:X:on|off turn specific warning X on|off. `warning:X` means `warning:X:on`, + as with similar flags. `all` is the set of all warning + (only `all:off` is supported). + --warningAsError:X:on|off + turn specific warning X into an error on|off --styleCheck:off|hint|error produce hints or errors for Nim identifiers that do not adhere to Nim's official style guide From 8cdd8867c0237c28f7a43e6f871507eda207a15d Mon Sep 17 00:00:00 2001 From: John Titor Date: Sat, 26 Mar 2022 10:43:26 +0000 Subject: [PATCH 3345/4254] Fix dial ignoring buffered parameter (#19650) [backport] --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c1d4c6228..9922bbfa4 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1963,7 +1963,7 @@ proc dial*(address: string, port: Port, closeUnusedFds(ord(domain)) if success: - result = newSocket(lastFd, domain, sockType, protocol) + result = newSocket(lastFd, domain, sockType, protocol, buffered) elif lastError != 0.OSErrorCode: raiseOSError(lastError) else: From 82319ef00dc9ce6f65b1664024a10ee5d9465f38 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 26 Mar 2022 18:50:15 +0800 Subject: [PATCH 3346/4254] fix #8219; nim check/dump shouldn't run single nimscript project [backport: 1.6] (#19641) * fix #8219; nim check/dump shouldn't run single nimscript project [backport: 1.6] --- compiler/nimconf.nim | 3 ++- tests/misc/trunner.nim | 5 +++++ tests/newconfig/{tconfigcheck.nims => mconfigcheck.nims} | 6 ++---- 3 files changed, 9 insertions(+), 5 deletions(-) rename tests/newconfig/{tconfigcheck.nims => mconfigcheck.nims} (74%) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 319a3de6d..fceedb2c4 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -301,7 +301,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: if conf.cmd == cmdNimscript: showHintConf() conf.configFiles.setLen 0 - if conf.cmd != cmdIdeTools: + if conf.cmd notin {cmdIdeTools, cmdCheck, cmdDump}: if conf.cmd == cmdNimscript: runNimScriptIfExists(conf.projectFull, isMain = true) else: @@ -311,5 +311,6 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: runNimScriptIfExists(scriptFile, isMain = true) else: # 'nimsuggest foo.nims' means to just auto-complete the NimScript file + # `nim check foo.nims' means to check the syntax of the NimScript file discard showHintConf() diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index f874d38d9..5d12c38b6 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -249,6 +249,11 @@ tests/newconfig/bar/mfoo.nims""".splitLines expected.add &"Hint: used config file '{b}' [Conf]\n" doAssert outp.endsWith expected, outp & "\n" & expected + block: # bug #8219 + let file = "tests/newconfig/mconfigcheck.nims" + let cmd = fmt"{nim} check --hints:off {file}" + check execCmdEx(cmd) == ("", 0) + block: # mfoo2.customext let filename = testsDir / "newconfig/foo2/mfoo2.customext" let cmd = fmt"{nim} e --hint:conf {filename}" diff --git a/tests/newconfig/tconfigcheck.nims b/tests/newconfig/mconfigcheck.nims similarity index 74% rename from tests/newconfig/tconfigcheck.nims rename to tests/newconfig/mconfigcheck.nims index 2e12a0bda..8df6715f6 100644 --- a/tests/newconfig/tconfigcheck.nims +++ b/tests/newconfig/mconfigcheck.nims @@ -1,11 +1,9 @@ -discard """ - cmd: "nim check $file" -""" - mode = ScriptMode.Verbose proc build() = echo "building nim... " exec "sleep 10" + exec "nonexistant command" echo getCurrentDir() echo "hello" +build() From 7d32425a577053bda356ca71c81d6701d8ad6372 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 26 Mar 2022 13:29:04 +0100 Subject: [PATCH 3347/4254] fixes #14318 (#14335) --- compiler/pragmas.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 81c6a42d3..458c7547a 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -656,7 +656,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = x.typ = makeTypeFromExpr(c, x) else: var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs) - if t.kind != tyObject and not t.isMetaType: + if t.kind notin {tyObject, tyOr}: localError(c.config, x.info, errGenerated, "invalid type for raises/tags list") x.typ = t From eae29e8eafded41ce966c131bff5e66964354805 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Mon, 28 Mar 2022 03:37:59 -0700 Subject: [PATCH 3348/4254] Embedded Network patches - eventfd & socket getters (#19632) --- lib/pure/ioselects/ioselectors_poll.nim | 35 ++++++++++++++++++------- lib/pure/net.nim | 10 +++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 0d8fef78a..12812ac80 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -14,6 +14,12 @@ import posix, times # Maximum number of events that can be returned const MAX_POLL_EVENTS = 64 +const hasEventFds = defined(zephyr) or defined(nimPollHasEventFds) + +when hasEventFds: + proc eventfd(count: cuint, flags: cint): cint + {.cdecl, importc: "eventfd", header: "".} + when hasThreadSupport: type SelectorImpl[T] = object @@ -184,14 +190,22 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = s.pollRemove(fdi.cint) proc newSelectEvent*(): SelectEvent = - var fds: array[2, cint] - if posix.pipe(fds) != 0: - raiseIOSelectorsError(osLastError()) - setNonBlocking(fds[0]) - setNonBlocking(fds[1]) - result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) - result.rfd = fds[0] - result.wfd = fds[1] + when not hasEventFds: + var fds: array[2, cint] + if posix.pipe(fds) != 0: + raiseIOSelectorsError(osLastError()) + setNonBlocking(fds[0]) + setNonBlocking(fds[1]) + result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) + result.rfd = fds[0] + result.wfd = fds[1] + else: + let fdci = eventfd(0, posix.O_NONBLOCK) + if fdci == -1: + raiseIOSelectorsError(osLastError()) + result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl))) + result.rfd = fdci + result.wfd = fdci proc trigger*(ev: SelectEvent) = var data: uint64 = 1 @@ -200,7 +214,10 @@ proc trigger*(ev: SelectEvent) = proc close*(ev: SelectEvent) = let res1 = posix.close(ev.rfd) - let res2 = posix.close(ev.wfd) + let res2 = + when hasEventFds: 0 + else: posix.close(ev.wfd) + deallocShared(cast[pointer](ev)) if res1 != 0 or res2 != 0: raiseIOSelectorsError(osLastError()) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9922bbfa4..c59a4e563 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1798,6 +1798,16 @@ proc isSsl*(socket: Socket): bool = proc getFd*(socket: Socket): SocketHandle = return socket.fd ## Returns the socket's file descriptor +when defined(zephyr) or defined(nimNetSocketExtras): # Remove in future + proc getDomain*(socket: Socket): Domain = return socket.domain + ## Returns the socket's domain + + proc getType*(socket: Socket): SockType = return socket.sockType + ## Returns the socket's type + + proc getProtocol*(socket: Socket): Protocol = return socket.protocol + ## Returns the socket's protocol + when defined(nimHasStyleChecks): {.push styleChecks: off.} From 49844415ce829cb627d0b02dd6b057a1574f44d6 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 31 Mar 2022 16:06:13 -0300 Subject: [PATCH 3349/4254] Deprecate selfExe (#19660) * Deprecate selfExe Nimscript * Deprecate selfExe Nimscript --- changelog.md | 2 ++ lib/system/nimscript.nim | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 92d2612e8..8b9d0bc29 100644 --- a/changelog.md +++ b/changelog.md @@ -50,6 +50,8 @@ becomes an alias for `addr`. - Remove deprecated `osproc.poDemon`, symbol with typo. +- Deprecated `selfExe` for Nimscript. + ## Language changes diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 0ef5fc584..5d1916c7f 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -136,9 +136,8 @@ proc dirExists*(dir: string): bool {. ## Checks if the directory `dir` exists. builtin -proc selfExe*(): string = +proc selfExe*(): string {.deprecated: "Deprecated since v1.7; Use getCurrentCompilerExe".} = ## Returns the currently running nim or nimble executable. - # TODO: consider making this as deprecated alias of `getCurrentCompilerExe` builtin proc toExe*(filename: string): string = From 1275763284d540c0e8ad53b3c27e52743ee08f2b Mon Sep 17 00:00:00 2001 From: rockcavera Date: Fri, 1 Apr 2022 03:01:51 -0300 Subject: [PATCH 3350/4254] fix 19655 - fixing url fragment (#19667) --- lib/pure/parseopt.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index b2d024a39..aff9312f9 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -16,7 +16,7 @@ ## ## The following syntax is supported when arguments for the `shortNoVal` and ## `longNoVal` parameters, which are -## `described later<#shortnoval-and-longnoval>`_, are not provided: +## `described later<#nimshortnoval-and-nimlongnoval>`_, are not provided: ## ## 1. Short options: `-abcd`, `-e:5`, `-e=5` ## 2. Long options: `--foo:bar`, `--foo=bar`, `--foo` From a7024f49afe5623ce90a800986dea7447e249d3b Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Sat, 2 Apr 2022 01:29:15 +0800 Subject: [PATCH 3351/4254] fix 19655 - fixing more url fragments (#19669) --- lib/pure/parseopt.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index aff9312f9..71deaa535 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -203,7 +203,7 @@ proc initOptParser*(cmdline = "", shortNoVal: set[char] = {}, ## ## `shortNoVal` and `longNoVal` are used to specify which options ## do not take values. See the `documentation about these - ## parameters<#shortnoval-and-longnoval>`_ for more information on + ## parameters<#nimshortnoval-and-nimlongnoval>`_ for more information on ## how this affects parsing. ## ## See also: @@ -465,7 +465,7 @@ iterator getopt*(cmdline: seq[string] = @[], ## ## `shortNoVal` and `longNoVal` are used to specify which options ## do not take values. See the `documentation about these - ## parameters<#shortnoval-and-longnoval>`_ for more information on + ## parameters<#nimshortnoval-and-nimlongnoval>`_ for more information on ## how this affects parsing. ## ## There is no need to check for `cmdEnd` while iterating. From c3f03cfa5dfa2ca47f8e4cf99bbcdbf5a7d16eda Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 2 Apr 2022 01:30:02 +0800 Subject: [PATCH 3352/4254] add somes links to docs (#19668) --- lib/core/macros.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index f20ca9385..4d0e64868 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -933,21 +933,21 @@ proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indent proc treeRepr*(n: NimNode): string {.benign.} = ## Convert the AST `n` to a human-readable tree-like string. ## - ## See also `repr`, `lispRepr`, and `astGenRepr`. + ## See also `repr`, `lispRepr`_, and `astGenRepr`_. result = "" n.treeTraverse(result, isLisp = false, indented = true) proc lispRepr*(n: NimNode; indented = false): string {.benign.} = ## Convert the AST `n` to a human-readable lisp-like string. ## - ## See also `repr`, `treeRepr`, and `astGenRepr`. + ## See also `repr`, `treeRepr`_, and `astGenRepr`_. result = "" n.treeTraverse(result, isLisp = true, indented = indented) proc astGenRepr*(n: NimNode): string {.benign.} = ## Convert the AST `n` to the code required to generate that AST. ## - ## See also `repr`, `treeRepr`, and `lispRepr`. + ## See also `repr`_, `treeRepr`_, and `lispRepr`_. const NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt} @@ -1602,7 +1602,7 @@ macro hasCustomPragma*(n: typed, cp: typed{nkSym}): untyped = ## Expands to `true` if expression `n` which is expected to be `nnkDotExpr` ## (if checking a field), a proc or a type has custom pragma `cp`. ## - ## See also `getCustomPragmaVal`. + ## See also `getCustomPragmaVal`_. ## ## .. code-block:: nim ## template myAttr() {.pragma.} @@ -1626,7 +1626,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = ## Expands to value of custom pragma `cp` of expression `n` which is expected ## to be `nnkDotExpr`, a proc or a type. ## - ## See also `hasCustomPragma` + ## See also `hasCustomPragma`_. ## ## .. code-block:: nim ## template serializationKey(key: string) {.pragma.} From 83dabb69ae0f6c0bb269594a5b73af964b809bc7 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 4 Apr 2022 18:05:23 +0800 Subject: [PATCH 3353/4254] Fix bug in freshVarForClosureIter. Fixes #18474 (#19675) [backport] * Fix bug in freshVarForClosureIter. Fixes #18474. freshVarForClosureIter was returning non-fresh symbols sometimes. Fixed by making addField return the generated PSym. * remove discardable Co-authored-by: Nick Smallbone --- compiler/lambdalifting.nim | 13 ++++--------- compiler/lowerings.nim | 3 ++- compiler/spawn.nim | 22 +++++++++++----------- tests/iter/tclosureiters.nim | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6838fd80d..4b7ca89cd 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -275,16 +275,11 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: PSym): PNode = let envParam = getHiddenParam(g, owner) let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr}) - addField(obj, s, g.cache, idgen) + let field = addField(obj, s, g.cache, idgen) var access = newSymNode(envParam) assert obj.kind == tyObject - let field = getFieldFromObj(obj, s) - if field != nil: - result = rawIndirectAccess(access, field, s.info) - else: - localError(g.config, s.info, "internal error: cannot generate fresh variable") - result = access + result = rawIndirectAccess(access, field, s.info) # ------------------ new stuff ------------------------------------------- @@ -452,7 +447,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if s.name.id == getIdent(c.graph.cache, ":state").id: obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) else: - addField(obj, s, c.graph.cache, c.idgen) + discard addField(obj, s, c.graph.cache, c.idgen) # direct or indirect dependency: elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s): discard """ @@ -474,7 +469,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr}) #getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) - addField(obj, s, c.graph.cache, c.idgen) + discard addField(obj, s, c.graph.cache, c.idgen) # create required upFields: var w = owner.skipGenericOwner if isInnerProc(w) or owner.isIterator: diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 382e48a16..de2f678d7 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -230,7 +230,7 @@ proc lookupInRecord(n: PNode, id: ItemId): PSym = if n.sym.itemId.module == id.module and n.sym.itemId.item == -abs(id.item): result = n.sym else: discard -proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) = +proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym = # because of 'gensym' support, we have to mangle the name with its ID. # This is hacky but the clean solution is much more complex than it looks. var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), @@ -244,6 +244,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) = field.flags = s.flags * {sfCursor} obj.n.add newSymNode(field) fieldCheck() + result = field proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} = result = lookupInRecord(obj.n, s.itemId) diff --git a/compiler/spawn.nim b/compiler/spawn.nim index e57686cb4..581f722d5 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -221,7 +221,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; let fieldname = if i < formals.len: formals[i].sym.name else: tmpName var field = newSym(skField, fieldname, nextSymId idgen, objType.owner, n.info, g.config.options) field.typ = argType - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) let temp = addLocalVar(g, varSection, varInit, idgen, owner, argType, @@ -260,17 +260,17 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; slice[0].typ = getSysType(g, n.info, tyInt) # fake type var fieldB = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) fieldB.typ = getSysType(g, n.info, tyInt) - objType.addField(fieldB, g.cache, idgen) + discard objType.addField(fieldB, g.cache, idgen) if getMagic(n) == mSlice: let a = genAddrOf(n[1], idgen) field.typ = a.typ - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) var fieldA = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) fieldA.typ = getSysType(g, n.info, tyInt) - objType.addField(fieldA, g.cache, idgen) + discard objType.addField(fieldA, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) @@ -281,7 +281,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; else: let a = genAddrOf(n, idgen) field.typ = a.typ - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n)) @@ -299,7 +299,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; # it is more efficient to pass a pointer instead: let a = genAddrOf(n, idgen) field.typ = a.typ - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) let threadLocal = addLocalVar(g, varSection, nil, idgen, owner, field.typ, indirectAccess(castExpr, field, n.info), @@ -308,7 +308,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; else: # boring case field.typ = argType - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) let threadLocal = addLocalVar(g, varSection, varInit, idgen, owner, field.typ, @@ -377,7 +377,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var argType = n[0].typ.skipTypes(abstractInst) var field = newSym(skField, getIdent(g.cache, "fn"), nextSymId idgen, owner, n.info, g.config.options) field.typ = argType - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) fn = indirectAccess(castExpr, field, n.info) elif fn.kind == nkSym and fn.sym.kind == skIterator: @@ -399,7 +399,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) var field = newSym(skField, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info, g.config.options) field.typ = typ - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) barrierAsExpr = indirectAccess(castExpr, field, n.info) @@ -407,7 +407,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp if spawnKind == srFlowVar: var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) field.typ = retType - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) fvField = newDotExpr(scratchObj, field) fvAsExpr = indirectAccess(castExpr, field, n.info) # create flowVar: @@ -419,7 +419,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) field.typ = newType(tyPtr, nextTypeId idgen, objType.owner) field.typ.rawAddSon(retType) - objType.addField(field, g.cache, idgen) + discard objType.addField(field, g.cache, idgen) fvAsExpr = indirectAccess(castExpr, field, n.info) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest, idgen)) diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim index afeaabc7d..85611373c 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -21,6 +21,15 @@ discard """ 2 70 0 +(1, 1) +(1, 2) +(1, 3) +(2, 1) +(2, 2) +(2, 3) +(3, 1) +(3, 2) +(3, 3) ''' """ @@ -152,3 +161,12 @@ var love = iterator: int {.closure.} = for i in love(): echo i + +# bug #18474 +iterator pairs(): (int, int) {.closure.} = + for i in 1..3: + for j in 1..3: + yield (i, j) + +for pair in pairs(): + echo pair From 5a995ffc53ac7c1a51ab62440a58af2f4e43963b Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 6 Apr 2022 22:17:09 +0800 Subject: [PATCH 3354/4254] fix #18986; Import/except doesn't work on devel [backport: 1.6] (#19687) * fix #18986; Import/except doesn't work on devel [backport: 1.6] * add testcase --- compiler/importer.nim | 2 +- tests/converter/m18986.nim | 3 +++ tests/converter/t18986.nim | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/converter/m18986.nim create mode 100644 tests/converter/t18986.nim diff --git a/compiler/importer.nim b/compiler/importer.nim index 719b75f0f..c4e37c269 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -202,7 +202,7 @@ template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} = proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet) - addUnnamedIt(c, fromMod, it.sym.id notin exceptSet) + addUnnamedIt(c, fromMod, it.sym.name.id notin exceptSet) proc importAllSymbols*(c: PContext, fromMod: PSym) = c.addImport ImportedModule(m: fromMod, mode: importAll) diff --git a/tests/converter/m18986.nim b/tests/converter/m18986.nim new file mode 100644 index 000000000..0ebf343ae --- /dev/null +++ b/tests/converter/m18986.nim @@ -0,0 +1,3 @@ +import std/macros + +converter Lit*(x: uint): NimNode = newLit(x) diff --git a/tests/converter/t18986.nim b/tests/converter/t18986.nim new file mode 100644 index 000000000..ef300fa49 --- /dev/null +++ b/tests/converter/t18986.nim @@ -0,0 +1,10 @@ +discard """ + output: "Found a 0" +""" + +import m18986 except Lit +import std/macros + +# bug #18986 +var x = 0.uint +echo "Found a ", x From c322faaf384bfcde4dd5a6e6eb9355d10c2e9597 Mon Sep 17 00:00:00 2001 From: Miran Date: Wed, 6 Apr 2022 16:18:10 +0200 Subject: [PATCH 3355/4254] [backport] fix broken SSL tests (#19684) * [backport] fix broken SSL tests * remove a flaky one --- tests/untestable/thttpclient_ssl_remotenetwork.nim | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim index d8137e516..cbb86dc13 100644 --- a/tests/untestable/thttpclient_ssl_remotenetwork.nim +++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim @@ -32,7 +32,7 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win good, bad, dubious, good_broken, bad_broken, dubious_broken CertTest = tuple[url:string, category:Category, desc: string] - const certificate_tests: array[0..55, CertTest] = [ + const certificate_tests: array[0..54, CertTest] = [ ("https://wrong.host.badssl.com/", bad, "wrong.host"), ("https://captive-portal.badssl.com/", bad, "captive-portal"), ("https://expired.badssl.com/", bad, "expired"), @@ -41,13 +41,12 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win ("https://untrusted-root.badssl.com/", bad, "untrusted-root"), ("https://revoked.badssl.com/", bad_broken, "revoked"), ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"), - ("https://no-common-name.badssl.com/", dubious_broken, "no-common-name"), - ("https://no-subject.badssl.com/", dubious_broken, "no-subject"), - ("https://incomplete-chain.badssl.com/", dubious_broken, "incomplete-chain"), + ("https://no-common-name.badssl.com/", bad, "no-common-name"), + ("https://no-subject.badssl.com/", bad, "no-subject"), ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), ("https://sha256.badssl.com/", good, "sha256"), - ("https://sha384.badssl.com/", good, "sha384"), - ("https://sha512.badssl.com/", good, "sha512"), + ("https://sha384.badssl.com/", bad, "sha384"), + ("https://sha512.badssl.com/", bad, "sha512"), ("https://1000-sans.badssl.com/", bad, "1000-sans"), ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), ("https://ecc256.badssl.com/", good, "ecc256"), From abe3b0eb644c60be4423bd3595382a126c4746db Mon Sep 17 00:00:00 2001 From: locriacyber <74560659+locriacyber@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:08:27 +0000 Subject: [PATCH 3356/4254] Load Google Fonts last (#19683) --- config/nimdoc.cfg | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index c1074f344..0ae768bfd 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -233,10 +233,6 @@ doc.file = """ - - - - $title @@ -282,8 +278,6 @@ function main() { } } } - -window.addEventListener('DOMContentLoaded', main); @@ -301,7 +295,15 @@ window.addEventListener('DOMContentLoaded', main); + + + $analytics + + + + + """ From e649ddd09ba0b1195163f456dbf6b1308affec37 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 7 Apr 2022 02:27:51 +0800 Subject: [PATCH 3357/4254] Revert "Load Google Fonts last (#19683)" (#19693) This reverts commit abe3b0eb644c60be4423bd3595382a126c4746db. --- config/nimdoc.cfg | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 0ae768bfd..c1074f344 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -233,6 +233,10 @@ doc.file = """ + + + + $title @@ -278,6 +282,8 @@ function main() { } } } + +window.addEventListener('DOMContentLoaded', main); @@ -295,15 +301,7 @@ function main() { - - - $analytics - - - - - """ From cb6ce80cb8dcf21733b437606ada1dfff9884316 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 6 Apr 2022 20:28:37 +0200 Subject: [PATCH 3358/4254] std/tasks: fix spelling (#19691) [backport] why aren't these not being caught by style check options? --styleCheck:usages finds it. Co-authored-by: flywind --- lib/std/tasks.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index e2ea5377f..dbe2e265b 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -87,7 +87,7 @@ template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr let isolatedTemp = genSym(nskTemp, "isoTemp") scratchAssignList.add newVarStmt(isolatedTemp, newCall(newidentNode("isolate"), procParam)) scratchAssignList.add newAssignment(scratchDotExpr, - newcall(newIdentNode("extract"), isolatedTemp)) + newCall(newIdentNode("extract"), isolatedTemp)) template addAllNode(assignParam: NimNode, procParam: NimNode) = let scratchDotExpr = newDotExpr(scratchIdent, formalParams[i][0]) @@ -154,7 +154,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter") let seqType = nnkBracketExpr.newTree(newIdentNode("seq"), param[1]) - seqCallNode = newcall("@", e[i]) + seqCallNode = newCall("@", e[i]) addAllNode(seqType, seqCallNode) else: addAllNode(param, e[i]) From 065f568470af944cfc43ecfed8df6ac8021b7cbe Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Thu, 7 Apr 2022 02:28:58 +0800 Subject: [PATCH 3359/4254] No need to export pos from OptParser (#19688) Co-authored-by: flywind --- lib/pure/parseopt.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 71deaa535..fef354733 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -164,7 +164,7 @@ type ## ## To initialize it, use the ## `initOptParser proc<#initOptParser,string,set[char],seq[string]>`_. - pos*: int + pos: int inShortState: bool allowWhitespaceAfterColon: bool shortNoVal: set[char] From e1929deac7dd41595e998ce68ee703a113ce8746 Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 7 Apr 2022 07:11:25 +0800 Subject: [PATCH 3360/4254] remove useless compilation condition (#19690) ref https://github.com/nim-lang/Nim/pull/18546 --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 456f42cd2..6b0b15fd8 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -100,7 +100,7 @@ pkg "nimcrypto", "nim r --path:. tests/testall.nim" # `--path:.` workaround need pkg "NimData", "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", "nim c src/nimes.nim" pkg "nimfp", "nim c -o:nfp -r src/fp.nim" -pkg "nimgame2", "nim c -d:nimLegacyConvEnumEnum nimgame2/nimgame.nim" +pkg "nimgame2", "nim c nimgame2/nimgame.nim" # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" pkg "nimlsp", allowFailure = true From 0978276ed9882a25782f91795b355a0dca7b0d3b Mon Sep 17 00:00:00 2001 From: flywind Date: Thu, 7 Apr 2022 13:07:39 +0800 Subject: [PATCH 3361/4254] use two spaces indentation (#19696) --- lib/core/macros.nim | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 4d0e64868..ba19712cf 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1505,20 +1505,20 @@ macro expandMacros*(body: typed): untyped = result = body proc extractTypeImpl(n: NimNode): NimNode = - ## attempts to extract the type definition of the given symbol - case n.kind - of nnkSym: # can extract an impl - result = n.getImpl.extractTypeImpl() - of nnkObjectTy, nnkRefTy, nnkPtrTy: result = n - of nnkBracketExpr: - if n.typeKind == ntyTypeDesc: - result = n[1].extractTypeImpl() - else: - doAssert n.typeKind == ntyGenericInst - result = n[0].getImpl() - of nnkTypeDef: - result = n[2] - else: error("Invalid node to retrieve type implementation of: " & $n.kind) + ## attempts to extract the type definition of the given symbol + case n.kind + of nnkSym: # can extract an impl + result = n.getImpl.extractTypeImpl() + of nnkObjectTy, nnkRefTy, nnkPtrTy: result = n + of nnkBracketExpr: + if n.typeKind == ntyTypeDesc: + result = n[1].extractTypeImpl() + else: + doAssert n.typeKind == ntyGenericInst + result = n[0].getImpl() + of nnkTypeDef: + result = n[2] + else: error("Invalid node to retrieve type implementation of: " & $n.kind) proc customPragmaNode(n: NimNode): NimNode = expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkCheckedFieldExpr}) From 810d5e91e435fffb7898ac26b5e4cc5fbb1678d7 Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Thu, 7 Apr 2022 14:39:27 +0300 Subject: [PATCH 3362/4254] [nimsuggest] return the type when on symbol in let/var (#19639) - make sure `suggestSym` is called after `PSym.typ` is set. --- compiler/semstmts.nim | 9 ++++++--- nimsuggest/tests/tdef_let.nim | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 nimsuggest/tests/tdef_let.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c2b385c80..3513fd767 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -306,7 +306,7 @@ proc identWithin(n: PNode, s: PIdent): bool = if identWithin(n[i], s): return true result = n.kind == nkSym and n.sym.name.id == s.id -proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = +proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym = if isTopLevel(c): result = semIdentWithPragma(c, kind, n, {sfExported}) incl(result.flags, sfGlobal) @@ -330,7 +330,8 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = discard result = n.info let info = getLineInfo(n) - suggestSym(c.graph, info, result, c.graph.usageSym) + if reportToNimsuggest: + suggestSym(c.graph, info, result, c.graph.usageSym) proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and v.typ.requiresInit: @@ -660,7 +661,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if a.kind != nkVarTuple: typ else: tup[j]) addToVarSection(c, result, n, a) continue - var v = semIdentDef(c, a[j], symkind) + var v = semIdentDef(c, a[j], symkind, false) styleCheckDef(c.config, v) onDef(a[j].info, v) if sfGenSym notin v.flags: @@ -725,6 +726,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if v.flags * {sfGlobal, sfThread} == {sfGlobal}: message(c.config, v.info, hintGlobalVar) + suggestSym(c.graph, v.info, v, c.graph.usageSym) + proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) inc c.inStaticContext diff --git a/nimsuggest/tests/tdef_let.nim b/nimsuggest/tests/tdef_let.nim new file mode 100644 index 000000000..3e9456d2f --- /dev/null +++ b/nimsuggest/tests/tdef_let.nim @@ -0,0 +1,7 @@ +discard """ +$nimsuggest --tester $file +>def $1 +def;;skLet;;tdef_let.intVar;;int;;$file;;7;;4;;"";;100 +""" + +let int#[!]#Var = 10 From c8aeea9d6205198306c3cd802136915f909ba5dc Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 8 Apr 2022 02:56:34 +0800 Subject: [PATCH 3363/4254] improve the error messages for std/tasks [backport: 1.6] (#19695) --- lib/std/tasks.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index dbe2e265b..3ceb4c8ba 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -111,10 +111,10 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC when compileOption("threads"): if not isGcSafe(e[0]): - error("'toTask' takes a GC safe call expression") + error("'toTask' takes a GC safe call expression", e) if hasClosure(e[0]): - error("closure call is not allowed") + error("closure call is not allowed", e) if e.len > 1: let scratchIdent = genSym(kind = nskTemp, ident = "scratch") @@ -141,17 +141,17 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC param = param[0] if param.typeKind in {ntyExpr, ntyStmt}: - error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter") + error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter", e) case param.kind of nnkVarTy: - error("'toTask'ed function cannot have a 'var' parameter") + error("'toTask'ed function cannot have a 'var' parameter", e) of nnkBracketExpr: if param[0].typeKind == ntyTypeDesc: callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) elif param[0].typeKind in {ntyVarargs, ntyOpenArray}: if param[1].typeKind in {ntyExpr, ntyStmt}: - error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter") + error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter", e) let seqType = nnkBracketExpr.newTree(newIdentNode("seq"), param[1]) seqCallNode = newCall("@", e[i]) @@ -167,7 +167,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC of nnkCharLit..nnkNilLit: callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) else: - error("not supported type kinds") + error("'toTask'ed function cannot have a parameter of " & $param.kind & " kind", e) let scratchObjType = genSym(kind = nskType, ident = "ScratchObj") let scratchObj = nnkTypeSection.newTree( From 1807de38e52f45c2fb88dac9b99b47729b12ebae Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 8 Apr 2022 02:57:50 +0800 Subject: [PATCH 3364/4254] add testcase for #16462 (#19692) --- tests/enum/m16462_1.nim | 3 +++ tests/enum/m16462_2.nim | 3 +++ tests/enum/t16462.nim | 5 +++++ 3 files changed, 11 insertions(+) create mode 100644 tests/enum/m16462_1.nim create mode 100644 tests/enum/m16462_2.nim create mode 100644 tests/enum/t16462.nim diff --git a/tests/enum/m16462_1.nim b/tests/enum/m16462_1.nim new file mode 100644 index 000000000..631c63256 --- /dev/null +++ b/tests/enum/m16462_1.nim @@ -0,0 +1,3 @@ +type + Scancode* {.pure.} = enum + SCANCODE_LEFT = 80 \ No newline at end of file diff --git a/tests/enum/m16462_2.nim b/tests/enum/m16462_2.nim new file mode 100644 index 000000000..631c63256 --- /dev/null +++ b/tests/enum/m16462_2.nim @@ -0,0 +1,3 @@ +type + Scancode* {.pure.} = enum + SCANCODE_LEFT = 80 \ No newline at end of file diff --git a/tests/enum/t16462.nim b/tests/enum/t16462.nim new file mode 100644 index 000000000..9f38286bb --- /dev/null +++ b/tests/enum/t16462.nim @@ -0,0 +1,5 @@ +import m16462_1 except Scancode +import m16462_2 + +# bug #16462 +let a = SCANCODE_LEFT \ No newline at end of file From e78ef57c93d66da483e0482ce0907dfe16dc8d27 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 7 Apr 2022 14:38:01 -0700 Subject: [PATCH 3365/4254] typetraits: add toSigned, toUnsigned (#18445) * typetraits: add toSigned, toUnsigned * improve and add tests Co-authored-by: Andreas Rumpf Co-authored-by: flywind --- lib/pure/bitops.nim | 26 ++++++++-------------- lib/pure/typetraits.nim | 38 +++++++++++++++++++++++++++----- lib/std/private/bitops_utils.nim | 15 ++++++++----- lib/system/countbits_impl.nim | 6 ++--- tests/metatype/ttypetraits.nim | 15 +++++++++++++ tests/stdlib/tbitops_utils.nim | 14 ++++++++++++ tests/stdlib/ttypetraits.nim | 4 ++-- 7 files changed, 85 insertions(+), 33 deletions(-) create mode 100644 tests/stdlib/tbitops_utils.nim diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 1b3838621..a518c25d2 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -27,7 +27,7 @@ import macros import std/private/since -from std/private/bitops_utils import forwardImpl, toUnsigned +from std/private/bitops_utils import forwardImpl, castToUnsigned func bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI".} ## Computes the `bitwise complement` of the integer `x`. @@ -72,7 +72,7 @@ func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, let upmost = sizeof(T) * 8 - 1 - uv = when v is SomeUnsignedInt: v else: v.toUnsigned + uv = v.castToUnsigned (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = @@ -84,7 +84,7 @@ proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, let upmost = sizeof(T) * 8 - 1 - uv = when v is SomeUnsignedInt: v else: v.toUnsigned + uv = v.castToUnsigned v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = @@ -95,10 +95,7 @@ func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = let upmost = sizeof(T) * 8 - 1 - bitmask = when T is SomeUnsignedInt: - bitnot(0.T) - else: - bitnot(0.T).toUnsigned + bitmask = bitnot(0.T).castToUnsigned (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T proc masked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = @@ -505,8 +502,7 @@ func parityBits*(x: SomeInteger): int {.inline.} = # Can be used a base if creating ASM version. # https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd - when x is SomeSignedInt: - let x = x.toUnsigned + let x = x.castToUnsigned when nimvm: result = forwardImpl(parityImpl, x) else: @@ -529,8 +525,7 @@ func firstSetBit*(x: SomeInteger): int {.inline.} = doAssert firstSetBit(0b0000_1111'u8) == 1 # GCC builtin 'builtin_ffs' already handle zero input. - when x is SomeSignedInt: - let x = x.toUnsigned + let x = x.castToUnsigned when nimvm: when noUndefined: if x == 0: @@ -572,8 +567,7 @@ func fastLog2*(x: SomeInteger): int {.inline.} = doAssert fastLog2(0b0000_1000'u8) == 3 doAssert fastLog2(0b0000_1111'u8) == 3 - when x is SomeSignedInt: - let x = x.toUnsigned + let x = x.castToUnsigned when noUndefined: if x == 0: return -1 @@ -615,8 +609,7 @@ func countLeadingZeroBits*(x: SomeInteger): int {.inline.} = doAssert countLeadingZeroBits(0b0000_1000'u8) == 4 doAssert countLeadingZeroBits(0b0000_1111'u8) == 4 - when x is SomeSignedInt: - let x = x.toUnsigned + let x = x.castToUnsigned when noUndefined: if x == 0: return 0 @@ -644,8 +637,7 @@ func countTrailingZeroBits*(x: SomeInteger): int {.inline.} = doAssert countTrailingZeroBits(0b0000_1000'u8) == 3 doAssert countTrailingZeroBits(0b0000_1111'u8) == 0 - when x is SomeSignedInt: - let x = x.toUnsigned + let x = x.castToUnsigned when noUndefined: if x == 0: return 0 diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 3fc1c7c5c..c20f9e645 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -35,7 +35,7 @@ runnableExamples: assert C[float] is HoleyEnum proc name*(t: typedesc): string {.magic: "TypeTrait".} = - ## Returns the name of the given type. + ## Returns the name of `t`. ## ## Alias for `system.\`$\`(t) `_ since Nim v0.20. runnableExamples: @@ -43,7 +43,7 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".} = doAssert name(seq[string]) == "seq[string]" proc arity*(t: typedesc): int {.magic: "TypeTrait".} = - ## Returns the arity of the given type. This is the number of "type" + ## Returns the arity of `t`. This is the number of "type" ## components or the number of generic parameters a given type `t` has. runnableExamples: doAssert arity(int) == 0 @@ -92,8 +92,7 @@ proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} = doAssert stripGenericParams(int) is int proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".} - ## This trait returns true if the type `t` is safe to use for - ## `copyMem`:idx:. + ## Returns true if `t` is safe to use for `copyMem`:idx:. ## ## Other languages name a type like these `blob`:idx:. @@ -289,9 +288,38 @@ since (1, 1): proc hasClosureImpl(n: NimNode): bool = discard "see compiler/vmops.nim" proc hasClosure*(fn: NimNode): bool {.since: (1, 5, 1).} = - ## Return true if the func/proc/etc `fn` has `closure`. + ## Returns true if the func/proc/etc `fn` has `closure`. ## `fn` has to be a resolved symbol of kind `nnkSym`. This ## implies that the macro that calls this proc should accept `typed` ## arguments and not `untyped` arguments. expectKind fn, nnkSym result = hasClosureImpl(fn) + +template toUnsigned*(T: typedesc[SomeInteger and not range]): untyped = + ## Returns an unsigned type with same bit size as `T`. + runnableExamples: + assert int8.toUnsigned is uint8 + assert uint.toUnsigned is uint + assert int.toUnsigned is uint + # range types are currently unsupported: + assert not compiles(toUnsigned(range[0..7])) + when T is int8: uint8 + elif T is int16: uint16 + elif T is int32: uint32 + elif T is int64: uint64 + elif T is int: uint + else: T + +template toSigned*(T: typedesc[SomeInteger and not range]): untyped = + ## Returns a signed type with same bit size as `T`. + runnableExamples: + assert int8.toSigned is int8 + assert uint16.toSigned is int16 + # range types are currently unsupported: + assert not compiles(toSigned(range[0..7])) + when T is uint8: int8 + elif T is uint16: int16 + elif T is uint32: int32 + elif T is uint64: int64 + elif T is uint: int + else: T diff --git a/lib/std/private/bitops_utils.nim b/lib/std/private/bitops_utils.nim index d54977b4e..0b9484416 100644 --- a/lib/std/private/bitops_utils.nim +++ b/lib/std/private/bitops_utils.nim @@ -10,8 +10,13 @@ template forwardImpl*(impl, arg) {.dirty.} = else: impl(x.uint64) -template toUnsigned*(x: int8): uint8 = cast[uint8](x) -template toUnsigned*(x: int16): uint16 = cast[uint16](x) -template toUnsigned*(x: int32): uint32 = cast[uint32](x) -template toUnsigned*(x: int64): uint64 = cast[uint64](x) -template toUnsigned*(x: int): uint = cast[uint](x) +# this could also be implemented via: +# import std/typetraits +# template castToUnsigned*(x: SomeInteger): auto = cast[toUnsigned(typeof(x))](x) + +template castToUnsigned*(x: int8): uint8 = cast[uint8](x) +template castToUnsigned*(x: int16): uint16 = cast[uint16](x) +template castToUnsigned*(x: int32): uint32 = cast[uint32](x) +template castToUnsigned*(x: int64): uint64 = cast[uint64](x) +template castToUnsigned*(x: int): uint = cast[uint](x) +template castToUnsigned*[T: SomeUnsignedInt](x: T): T = x diff --git a/lib/system/countbits_impl.nim b/lib/system/countbits_impl.nim index 020423e01..34969cb32 100644 --- a/lib/system/countbits_impl.nim +++ b/lib/system/countbits_impl.nim @@ -9,8 +9,7 @@ ## Contains the used algorithms for counting bits. -from std/private/bitops_utils import forwardImpl, toUnsigned - +from std/private/bitops_utils import forwardImpl, castToUnsigned const useBuiltins* = not defined(noIntrinsicsBitOpts) const noUndefined* = defined(noUndefinedBitOpts) @@ -65,8 +64,7 @@ func countSetBitsImpl*(x: SomeInteger): int {.inline.} = ## Counts the set bits in an integer (also called `Hamming weight`:idx:). # TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT. # like GCC and MSVC - when x is SomeSignedInt: - let x = x.toUnsigned + let x = x.castToUnsigned when nimvm: result = forwardImpl(countBitsImpl, x) else: diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 3ff5c5ea6..bfaa23057 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -1,6 +1,21 @@ import typetraits import macros +block: # toUnsigned, toSigned + var a1: toSigned(int16) + doAssert a1 is int16 + var a2: toSigned(uint16) + doAssert $a2.typeof == "int16" + doAssert toSigned(uint32) is int32 + doAssert uint64.toSigned is int64 + doAssert int64.toSigned is int64 + doAssert int64.toUnsigned is uint64 + doAssert int.toUnsigned is uint + doAssert $uint.toUnsigned == "uint" + # disallowed for now + doAssert not compiles(toUnsigned(range[0..7])) + doAssert not compiles(toSigned(range[0..7])) + block: # isNamedTuple type Foo1 = (a:1,).type type Foo2 = (Field0:1,).type diff --git a/tests/stdlib/tbitops_utils.nim b/tests/stdlib/tbitops_utils.nim new file mode 100644 index 000000000..b571baeae --- /dev/null +++ b/tests/stdlib/tbitops_utils.nim @@ -0,0 +1,14 @@ +import std/private/bitops_utils + +template chk(a, b) = + let a2 = castToUnsigned(a) + doAssert a2 == b + doAssert type(a2) is type(b) + doAssert type(b) is type(a2) + +chk 1'i8, 1'u8 +chk -1'i8, 255'u8 +chk 1'u8, 1'u8 +chk 1'u, 1'u +chk -1, cast[uint](-1) +chk -1'i64, cast[uint64](-1) diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim index de8259ab0..799bcf6e2 100644 --- a/tests/stdlib/ttypetraits.nim +++ b/tests/stdlib/ttypetraits.nim @@ -2,10 +2,10 @@ discard """ targets: "c cpp js" """ +# xxx merge with tests/metatype/ttypetraits.nim + import std/typetraits - - macro testClosure(fn: typed, flag: static bool) = if flag: doAssert hasClosure(fn) From 00775f6880733695d187d84bb742e8c9d6c65d6d Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 8 Apr 2022 14:04:46 +0800 Subject: [PATCH 3366/4254] fix stylecheck bug with nre (#19356) * stylecheck usages part two: stdlib cleanup typeinfo.nim: importCompilerProc => importcompilerproc nre.nim: newLineFlags => newlineFlags system.nim: JSRoot => JsRoot ref #19319 * prefer importCompilerProc * fix stylecheck error with asyncdispatch it is a partial regression since #12842 * add tests * don't use echo in tests * fix stylecheck bug with nre * Update compiler/linter.nim * no need to check dotexpr again * neither did let/var/const --- compiler/semexprs.nim | 9 ++++++--- tests/stylecheck/taccept.nim | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f224bd0b3..702b47929 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1188,7 +1188,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = let s = getGenSym(c, sym) case s.kind of skConst: - markUsed(c, n.info, s) + if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess + markUsed(c, n.info, s) onUse(n.info, s) let typ = skipTypes(s.typ, abstractInst-{tyTypeDesc}) case typ.kind @@ -1249,7 +1250,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if s.magic == mNimvm: localError(c.config, n.info, "illegal context for 'nimvm' magic") - markUsed(c, n.info, s) + if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess + markUsed(c, n.info, s) onUse(n.info, s) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still @@ -1270,7 +1272,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = n.typ = s.typ return n of skType: - markUsed(c, n.info, s) + if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess + markUsed(c, n.info, s) onUse(n.info, s) if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil: return s.typ.n diff --git a/tests/stylecheck/taccept.nim b/tests/stylecheck/taccept.nim index 6fb55f835..afe02a65c 100644 --- a/tests/stylecheck/taccept.nim +++ b/tests/stylecheck/taccept.nim @@ -2,7 +2,7 @@ discard """ matrix: "--styleCheck:error --styleCheck:usages" """ -import asyncdispatch +import std/[asyncdispatch, nre] type Name = object From ded8b0e5410518ffed24b46565eb6e42f18a63f1 Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 9 Apr 2022 23:50:57 +0800 Subject: [PATCH 3367/4254] rewrite docs JS in Nim (#19701) * rewrite docs JS in Nim * fixup * fix nimdoc/rsttester --- config/nimdoc.cfg | 43 ------------------- nimdoc/rst2html/expected/rst_examples.html | 43 ------------------- .../expected/index.html | 43 ------------------- .../expected/theindex.html | 43 ------------------- .../expected/subdir/subdir_b/utils.html | 43 ------------------- nimdoc/testproject/expected/testproject.html | 43 ------------------- nimdoc/testproject/expected/theindex.html | 43 ------------------- tools/dochack/dochack.nim | 36 +++++++++++++++- 8 files changed, 35 insertions(+), 302 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index c1074f344..4efa1f637 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -243,49 +243,6 @@ doc.file = """ - -
      diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 1df91ff1f..2b5218d9f 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -22,49 +22,6 @@ - -
      diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 69dd2eb2e..c6a116bd6 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -22,49 +22,6 @@ - -
      diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index 34ddf8f6a..8ee62a330 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -22,49 +22,6 @@ - -
      diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 574ac5b9b..f94da7f40 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -22,49 +22,6 @@ - -
      diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index e45492dac..cba9391af 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -22,49 +22,6 @@ - -
      diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 88d4b86aa..47fae2491 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -22,49 +22,6 @@ - -
      diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 3a663808d..c7b8232ef 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -1,6 +1,39 @@ import dom import fuzzysearch + +proc switchTheme(event: Event) = + if event.target.checked: + document.documentElement.setAttribute("data-theme", "dark") + window.localStorage.setItem("theme", "dark") + else: + document.documentElement.setAttribute("data-theme", "light") + window.localStorage.setItem("theme", "light") + + +proc nimThemeSwitch(event: Event) {.exportC.} = + var pragmaDots = document.getElementsByClassName("pragmadots") + for i in 0.. 0: + document.documentElement.setAttribute("data-theme", currentTheme); + + if currentTheme == "dark" and toggleSwitch != nil: + toggleSwitch.checked = true + proc textContent(e: Element): cstring {. importcpp: "#.textContent", nodecl.} @@ -396,5 +429,6 @@ proc copyToClipboard*() {.exportc.} = """ .} - + copyToClipboard() +window.addEventListener("DOMContentLoaded", nimThemeSwitch) \ No newline at end of file From 152dab09838adc5a4ab8dc220c5017c868563467 Mon Sep 17 00:00:00 2001 From: Leon Date: Sun, 10 Apr 2022 01:51:44 +1000 Subject: [PATCH 3368/4254] fix: Fix introductory macro examples (#19706) Co-authored-by: adigitoleo --- doc/tut3.rst | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/doc/tut3.rst b/doc/tut3.rst index 1c497f1f5..c2c956107 100644 --- a/doc/tut3.rst +++ b/doc/tut3.rst @@ -188,21 +188,35 @@ Backticks are used to insert code from `NimNode` symbols into the generated expression. .. code-block:: nim - macro a(i) = quote do: let `i` = 0 + :test: "nim c $1" + import std/macros + macro a(i) = quote do: + let `i` = 0 + a b + doAssert b == 0 A custom prefix operator can be defined whenever backticks are needed. .. code-block:: nim - macro a(i) = quote("@") do: assert @i == 0 + :test: "nim c $1" + import std/macros + macro a(i) = quote("@") do: + assert @i == 0 + let b = 0 a b The injected symbol needs accent quoted when it resolves to a symbol. .. code-block:: nim - macro a(i) = quote("@") do: let `@i` == 0 + :test: "nim c $1" + import std/macros + macro a(i) = quote("@") do: + let `@i` = 0 + a b + doAssert b == 0 Make sure to inject only symbols of type `NimNode` into the generated syntax tree. You can use `newLit` to convert arbitrary values into From a77ffdb7ea4ec66983d3481cc486c821a5df6b1b Mon Sep 17 00:00:00 2001 From: flywind Date: Sat, 9 Apr 2022 23:52:11 +0800 Subject: [PATCH 3369/4254] fix #17286 nim check -b:js works (#19704) * fix #17286 nim check -b:js works * fix --- compiler/main.nim | 2 ++ tests/misc/t17286.nim | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/misc/t17286.nim diff --git a/compiler/main.nim b/compiler/main.nim index e27a4f6d1..a4425e510 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -65,6 +65,8 @@ proc commandCheck(graph: ModuleGraph) = if optWasNimscript in conf.globalOptions: defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimconfig") + elif conf.backend == backendJs: + setTarget(conf.target, osJS, cpuJS) semanticPasses(graph) # use an empty backend for semantic checking only compileProject(graph) diff --git a/tests/misc/t17286.nim b/tests/misc/t17286.nim new file mode 100644 index 000000000..3a54e624e --- /dev/null +++ b/tests/misc/t17286.nim @@ -0,0 +1,16 @@ +discard """ + cmd: "nim check -b:js $file" + action: "compile" +""" + +# bug #17286 + +import std/compilesettings + +static: + doAssert querySetting(backend) == "js" + doAssert defined(js) + doAssert not defined(c) + +import random +randomize() \ No newline at end of file From 26acc97864ede8e19dddd52aa04e0139da356e3e Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Mon, 11 Apr 2022 06:27:12 -0600 Subject: [PATCH 3370/4254] StringStreams no longer errors when intialized with literals on arc/orc (#19708) --- lib/pure/streams.nim | 2 ++ tests/stdlib/tstreams.nim | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 7ad81685f..84451f989 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1274,6 +1274,8 @@ else: # after 1.3 or JS not defined new(result) result.data = s + when defined(gcOrc) or defined(gcArc): + prepareMutation(result.data) # Allows us to mutate using `addr` logic like `copyMem`, otherwise it errors. result.pos = 0 result.closeImpl = ssClose result.atEndImpl = ssAtEnd diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index c2ceed624..d70d4995a 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -74,3 +74,5 @@ block: doAssert(ss.peekLine(str)) doAssert(str == "uick brown fox jumped over the lazy dog.") doAssert(ss.getPosition == 5) # haven't moved + ss.setPosition(0) # Ensure we dont error with writing over literals on arc/orc #19707 + ss.write("hello") From 26bcf18f918b2bcc7b6b2e230ae74d7726dca6d0 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 12 Apr 2022 15:48:48 +0800 Subject: [PATCH 3371/4254] fix #19680; check if stderr is static (#19709) --- compiler/vmgen.nim | 2 +- tests/misc/tvarious1.nim | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 72bcef4db..dadcc3865 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1479,7 +1479,7 @@ proc checkCanEval(c: PCtx; n: PNode) = # proc foo() = var x ... let s = n.sym if {sfCompileTime, sfGlobal} <= s.flags: return - if s.importcCondVar: return + if compiletimeFFI in c.config.features and s.importcCondVar: return if s.kind in {skVar, skTemp, skLet, skParam, skResult} and not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl: # little hack ahead for bug #12612: assume gensym'ed variables diff --git a/tests/misc/tvarious1.nim b/tests/misc/tvarious1.nim index 9c0b541db..9c912ee8e 100644 --- a/tests/misc/tvarious1.nim +++ b/tests/misc/tvarious1.nim @@ -46,3 +46,13 @@ echo value var ys = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] #var x = int(ys.high / 2) #echo ys[x] # Works echo ys[int(ys.high / 2)] # Doesn't work + + +# bug #19680 +var here = "" +when stderr is static: + doAssert false +else: + here = "works" + +doAssert here == "works" From 98cebad7debddfb147ee22bc6f3d81221582c4d6 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 13 Apr 2022 17:53:02 +0800 Subject: [PATCH 3372/4254] enable style:usages for stdlib tests [backport: 1.6] (#19715) * enable style:usages for stdlib tests * freeAddrInfo * more tests * importc * bufSize * fix more * => parseSql and renderSql --- lib/impure/db_mysql.nim | 20 +++--- lib/posix/posix.nim | 2 +- lib/pure/asyncdispatch.nim | 6 +- lib/pure/asyncnet.nim | 6 +- lib/pure/cookies.nim | 2 +- lib/pure/ioselects/ioselectors_epoll.nim | 2 +- lib/pure/ioselects/ioselectors_select.nim | 16 ++--- lib/pure/json.nim | 12 ++-- lib/pure/nativesockets.nim | 4 +- lib/pure/net.nim | 14 ++-- lib/pure/parsesql.nim | 12 ++-- lib/pure/pegs.nim | 4 +- lib/pure/segfaults.nim | 2 +- lib/std/strbasics.nim | 2 +- lib/std/tasks.nim | 2 +- lib/windows/registry.nim | 18 ++--- lib/windows/winlean.nim | 2 +- tests/stdlib/config.nims | 2 + tests/stdlib/nre/misc.nim | 4 +- tests/stdlib/talgorithm.nim | 4 +- tests/stdlib/tasynchttpserver.nim | 8 +-- tests/stdlib/tbase64.nim | 6 +- tests/stdlib/tbitops.nim | 4 +- tests/stdlib/thttpclient.nim | 2 +- tests/stdlib/tjsonmacro.nim | 4 +- tests/stdlib/tjsonutils.nim | 2 +- tests/stdlib/tnet.nim | 2 +- tests/stdlib/tnetdial.nim | 2 +- tests/stdlib/tosproc.nim | 2 +- tests/stdlib/tparsesql.nim | 86 +++++++++++------------ tests/stdlib/trst.nim | 10 +-- tests/stdlib/trstgen.nim | 8 +-- tests/stdlib/tsha1.nim | 2 +- tests/stdlib/tssl.nim | 4 +- tests/stdlib/tstrbasics.nim | 2 +- tests/stdlib/tstreams.nim | 2 +- tests/stdlib/tstrset.nim | 2 +- tests/stdlib/ttimes.nim | 2 +- tests/stdlib/ttypeinfo.nim | 2 +- tests/stdlib/ttypeinfo.nims | 1 + tests/stdlib/tunicode.nim | 4 +- tests/stdlib/tvarints.nim | 2 +- 42 files changed, 149 insertions(+), 146 deletions(-) create mode 100644 tests/stdlib/config.nims create mode 100644 tests/stdlib/ttypeinfo.nims diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 242ea1b0d..df878e25a 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -150,17 +150,17 @@ proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {. tags: [ReadDbEffect, WriteDbEffect].} = ## tries to execute the query and returns true if successful, false otherwise. var q = dbFormat(query, args) - return mysql.realQuery(PMySQL db, q, q.len) == 0'i32 + return mysql.real_query(PMySQL db, q, q.len) == 0'i32 proc rawExec(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) = var q = dbFormat(query, args) - if mysql.realQuery(PMySQL db, q, q.len) != 0'i32: dbError(db) + if mysql.real_query(PMySQL db, q, q.len) != 0'i32: dbError(db) proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {. tags: [ReadDbEffect, WriteDbEffect].} = ## executes the query and raises EDB if not successful. var q = dbFormat(query, args) - if mysql.realQuery(PMySQL db, q, q.len) != 0'i32: dbError(db) + if mysql.real_query(PMySQL db, q, q.len) != 0'i32: dbError(db) proc newRow(L: int): Row = newSeq(result, L) @@ -168,7 +168,7 @@ proc newRow(L: int): Row = proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) = if row != nil: - while mysql.fetchRow(sqlres) != nil: discard + while mysql.fetch_row(sqlres) != nil: discard mysql.freeResult(sqlres) iterator fastRows*(db: DbConn, query: SqlQuery, @@ -190,7 +190,7 @@ iterator fastRows*(db: DbConn, query: SqlQuery, backup: Row newSeq(result, L) while true: - row = mysql.fetchRow(sqlres) + row = mysql.fetch_row(sqlres) if row == nil: break for i in 0..L-1: setLen(result[i], 0) @@ -209,7 +209,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery, let L = int(mysql.numFields(sqlres)) var row: cstringArray while true: - row = mysql.fetchRow(sqlres) + row = mysql.fetch_row(sqlres) if row == nil: break yield InstantRow(row: row, len: L) properFreeResult(sqlres, row) @@ -290,7 +290,7 @@ iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery; setColumnInfo(columns, sqlres, L) var row: cstringArray while true: - row = mysql.fetchRow(sqlres) + row = mysql.fetch_row(sqlres) if row == nil: break yield InstantRow(row: row, len: L) properFreeResult(sqlres, row) @@ -317,7 +317,7 @@ proc getRow*(db: DbConn, query: SqlQuery, if sqlres != nil: var L = int(mysql.numFields(sqlres)) result = newRow(L) - var row = mysql.fetchRow(sqlres) + var row = mysql.fetch_row(sqlres) if row != nil: for i in 0..L-1: setLen(result[i], 0) @@ -335,7 +335,7 @@ proc getAllRows*(db: DbConn, query: SqlQuery, var row: cstringArray var j = 0 while true: - row = mysql.fetchRow(sqlres) + row = mysql.fetch_row(sqlres) if row == nil: break setLen(result, j+1) newSeq(result[j], L) @@ -361,7 +361,7 @@ proc tryInsertId*(db: DbConn, query: SqlQuery, ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. var q = dbFormat(query, args) - if mysql.realQuery(PMySQL db, q, q.len) != 0'i32: + if mysql.real_query(PMySQL db, q, q.len) != 0'i32: result = -1'i64 else: result = mysql.insertId(PMySQL db) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 9c65d0732..146ba886f 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1016,7 +1016,7 @@ proc endhostent*() {.importc, header: "".} proc endnetent*() {.importc, header: "".} proc endprotoent*() {.importc, header: "".} proc endservent*() {.importc, header: "".} -proc freeaddrinfo*(a1: ptr AddrInfo) {.importc, header: "".} +proc freeAddrInfo*(a1: ptr AddrInfo) {.importc: "freeaddrinfo", header: "".} proc gai_strerror*(a1: cint): cstring {.importc:"(char *)$1", header: "".} diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5e2a8d98e..b67b0c308 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1791,7 +1791,7 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, curAddrInfo = curAddrInfo.ai_next if curAddrInfo == nil: - freeaddrinfo(addrInfo) + freeAddrInfo(addrInfo) when shouldCreateFd: closeUnusedFds() if lastException != nil: @@ -1807,7 +1807,7 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, try: curFd = createAsyncNativeSocket(domain, sockType, protocol) except: - freeaddrinfo(addrInfo) + freeAddrInfo(addrInfo) closeUnusedFds() raise getCurrentException() when defined(windows): @@ -1817,7 +1817,7 @@ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo curAddrInfo = curAddrInfo.ai_next else: - freeaddrinfo(addrInfo) + freeAddrInfo(addrInfo) when shouldCreateFd: closeUnusedFds(ord(domain)) retFuture.complete(curFd) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index abb4dd075..61c2fc75a 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -648,9 +648,9 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: - freeaddrinfo(aiList) + freeAddrInfo(aiList) raiseOSError(osLastError()) - freeaddrinfo(aiList) + freeAddrInfo(aiList) proc hasDataBuffered*(s: AsyncSocket): bool {.since: (1, 5).} = ## Determines whether an AsyncSocket has data buffered. @@ -859,7 +859,7 @@ proc sendTo*(socket: AsyncSocket, address: string, port: Port, data: string, it = it.ai_next - freeaddrinfo(aiList) + freeAddrInfo(aiList) if not success: if lastException != nil: diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 7bf34f75b..0306558d6 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -75,4 +75,4 @@ proc setCookie*(key, value: string, expires: DateTime|Time, ## `Set-Cookie: key=value; Domain=...; ...` result = setCookie(key, value, domain, path, format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"), - noname, secure, httpOnly, maxAge, sameSite) + noName, secure, httpOnly, maxAge, sameSite) diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 05d9d19a8..8526eb8a3 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -526,4 +526,4 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, body2 proc getFd*[T](s: Selector[T]): int = - return s.epollFd.int + return s.epollFD.int diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 88cbaf28c..4c38ba604 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -26,27 +26,27 @@ else: #include #include """ type - Fdset {.importc: "fd_set", header: platformHeaders, pure, final.} = object + FdSet {.importc: "fd_set", header: platformHeaders, pure, final.} = object var FD_SETSIZE {.importc: "FD_SETSIZE", header: platformHeaders.}: cint -proc IOFD_SET(fd: SocketHandle, fdset: ptr Fdset) +proc IOFD_SET(fd: SocketHandle, fdset: ptr FdSet) {.cdecl, importc: "FD_SET", header: platformHeaders, inline.} -proc IOFD_CLR(fd: SocketHandle, fdset: ptr Fdset) +proc IOFD_CLR(fd: SocketHandle, fdset: ptr FdSet) {.cdecl, importc: "FD_CLR", header: platformHeaders, inline.} -proc IOFD_ZERO(fdset: ptr Fdset) +proc IOFD_ZERO(fdset: ptr FdSet) {.cdecl, importc: "FD_ZERO", header: platformHeaders, inline.} when defined(windows): - proc IOFD_ISSET(fd: SocketHandle, fdset: ptr Fdset): cint + proc IOFD_ISSET(fd: SocketHandle, fdset: ptr FdSet): cint {.stdcall, importc: "FD_ISSET", header: platformHeaders, inline.} - proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr Fdset, + proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr FdSet, timeout: ptr Timeval): cint {.stdcall, importc: "select", header: platformHeaders.} else: - proc IOFD_ISSET(fd: SocketHandle, fdset: ptr Fdset): cint + proc IOFD_ISSET(fd: SocketHandle, fdset: ptr FdSet): cint {.cdecl, importc: "FD_ISSET", header: platformHeaders, inline.} - proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr Fdset, + proc ioselect(nfds: cint, readFds, writeFds, exceptFds: ptr FdSet, timeout: ptr Timeval): cint {.cdecl, importc: "select", header: platformHeaders.} diff --git a/lib/pure/json.nim b/lib/pure/json.nim index dd9232ea6..8e4db93b0 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -958,12 +958,12 @@ proc parseJson*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats when defined(js): from math import `mod` - from std/jsffi import JSObject, `[]`, to + from std/jsffi import JsObject, `[]`, to from std/private/jsutils import getProtoName, isInteger, isSafeInteger - proc parseNativeJson(x: cstring): JSObject {.importjs: "JSON.parse(#)".} + proc parseNativeJson(x: cstring): JsObject {.importjs: "JSON.parse(#)".} - proc getVarType(x: JSObject, isRawNumber: var bool): JsonNodeKind = + proc getVarType(x: JsObject, isRawNumber: var bool): JsonNodeKind = result = JNull case $getProtoName(x) # TODO: Implicit returns fail here. of "[object Array]": return JArray @@ -982,12 +982,12 @@ when defined(js): of "[object String]": return JString else: assert false - proc len(x: JSObject): int = + proc len(x: JsObject): int = asm """ `result` = `x`.length; """ - proc convertObject(x: JSObject): JsonNode = + proc convertObject(x: JsObject): JsonNode = var isRawNumber = false case getVarType(x, isRawNumber) of JArray: @@ -1000,7 +1000,7 @@ when defined(js): if (`x`.hasOwnProperty(property)) { """ var nimProperty: cstring - var nimValue: JSObject + var nimValue: JsObject asm "`nimProperty` = property; `nimValue` = `x`[property];" result[$nimProperty] = nimValue.convertObject() asm "}}" diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index eb0514a8f..5453226a0 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -633,8 +633,8 @@ when useNimNetLite: INET_ADDRSTRLEN = 16 INET6_ADDRSTRLEN = 46 # it's actually 46 in both cases - proc sockAddrToStr(sa: ptr Sockaddr): string {.noinit.} = - let af_family = sa.sa_family + proc sockAddrToStr(sa: ptr SockAddr): string {.noinit.} = + let af_family = sa.sa_family var nl, v4Slice: cint var si_addr: ptr InAddr diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c59a4e563..370b83e54 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -984,11 +984,11 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: - freeaddrinfo(aiList) + freeAddrInfo(aiList) var address2: string address2.addQuoted address raiseOSError(osLastError(), "address: $# port: $#" % [address2, $port]) - freeaddrinfo(aiList) + freeAddrInfo(aiList) proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, flags = {SocketFlag.SafeDisconn}, @@ -1745,7 +1745,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, it = it.ai_next let osError = osLastError() - freeaddrinfo(aiList) + freeAddrInfo(aiList) if not success: raiseOSError(osError) @@ -1960,7 +1960,7 @@ proc dial*(address: string, port: Port, # network system problem (e.g. not enough FDs), and not an unreachable # address. let err = osLastError() - freeaddrinfo(aiList) + freeAddrInfo(aiList) closeUnusedFds() raiseOSError(err) fdPerDomain[ord(domain)] = lastFd @@ -1969,7 +1969,7 @@ proc dial*(address: string, port: Port, break lastError = osLastError() it = it.ai_next - freeaddrinfo(aiList) + freeAddrInfo(aiList) closeUnusedFds(ord(domain)) if success: @@ -1999,7 +1999,7 @@ proc connect*(socket: Socket, address: string, else: lastError = osLastError() it = it.ai_next - freeaddrinfo(aiList) + freeAddrInfo(aiList) if not success: raiseOSError(lastError) when defineSsl: @@ -2051,7 +2051,7 @@ proc connectAsync(socket: Socket, name: string, port = Port(0), it = it.ai_next - freeaddrinfo(aiList) + freeAddrInfo(aiList) if not success: raiseOSError(lastError) proc connect*(socket: Socket, address: string, port = Port(0), diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 9d74d08d0..61196aead 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -1451,7 +1451,7 @@ proc ra(n: SqlNode, s: var SqlWriter) = s.addKeyw("enum") rs(n, s) -proc renderSQL*(n: SqlNode, upperCase = false): string = +proc renderSql*(n: SqlNode, upperCase = false): string = ## Converts an SQL abstract syntax tree to its string representation. var s: SqlWriter s.buffer = "" @@ -1460,8 +1460,8 @@ proc renderSQL*(n: SqlNode, upperCase = false): string = return s.buffer proc `$`*(n: SqlNode): string = - ## an alias for `renderSQL`. - renderSQL(n) + ## an alias for `renderSql`. + renderSql(n) proc treeReprAux(s: SqlNode, level: int, result: var string) = result.add('\n') @@ -1493,7 +1493,7 @@ proc open(p: var SqlParser, input: Stream, filename: string) = p.tok.literal = "" getTok(p) -proc parseSQL*(input: Stream, filename: string): SqlNode = +proc parseSql*(input: Stream, filename: string): SqlNode = ## parses the SQL from `input` into an AST and returns the AST. ## `filename` is only used for error messages. ## Syntax errors raise an `SqlParseError` exception. @@ -1504,8 +1504,8 @@ proc parseSQL*(input: Stream, filename: string): SqlNode = finally: close(p) -proc parseSQL*(input: string, filename = ""): SqlNode = +proc parseSql*(input: string, filename = ""): SqlNode = ## parses the SQL from `input` into an AST and returns the AST. ## `filename` is only used for error messages. ## Syntax errors raise an `SqlParseError` exception. - parseSQL(newStringStream(input), "") + parseSql(newStringStream(input), "") diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 0eed1c388..78f03d308 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1023,7 +1023,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = ## Symbols declared in an *enter* handler can be made visible in the ## corresponding *leave* handler by annotating them with an *inject* pragma. proc rawParse(s: string, p: Peg, start: int, c: var Captures): int - {.genSym.} = + {.gensym.} = # binding from *macros* bind strVal @@ -1058,7 +1058,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = matchOrParse(parseIt) parseIt(s, p, start, c) - proc parser(s: string): int {.genSym.} = + proc parser(s: string): int {.gensym.} = # the proc to be returned var ms: array[MaxSubpatterns, (int, int)] diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim index e0da8b81d..b0eac2299 100644 --- a/lib/pure/segfaults.nim +++ b/lib/pure/segfaults.nim @@ -30,7 +30,7 @@ when defined(windows): const EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005'i32) - EXCEPTION_CONTINUE_SEARCH = Long(0) + EXCEPTION_CONTINUE_SEARCH = LONG(0) type PEXCEPTION_RECORD = ptr object diff --git a/lib/std/strbasics.nim b/lib/std/strbasics.nim index 0d4c96f44..6f6db5c37 100644 --- a/lib/std/strbasics.nim +++ b/lib/std/strbasics.nim @@ -46,7 +46,7 @@ func setSlice*(s: var string, slice: Slice[int]) = import std/sugar var a = "Hello, Nim!" - doassert a.dup(setSlice(7 .. 9)) == "Nim" + doAssert a.dup(setSlice(7 .. 9)) == "Nim" doAssert a.dup(setSlice(0 .. 0)) == "H" doAssert a.dup(setSlice(0 .. 1)) == "He" doAssert a.dup(setSlice(0 .. 10)) == a diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index 3ceb4c8ba..7b931ab14 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -85,7 +85,7 @@ template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr # var isoTempB = isolate(literal) # scratch.b = extract(isolateB) let isolatedTemp = genSym(nskTemp, "isoTemp") - scratchAssignList.add newVarStmt(isolatedTemp, newCall(newidentNode("isolate"), procParam)) + scratchAssignList.add newVarStmt(isolatedTemp, newCall(newIdentNode("isolate"), procParam)) scratchAssignList.add newAssignment(scratchDotExpr, newCall(newIdentNode("extract"), isolatedTemp)) diff --git a/lib/windows/registry.nim b/lib/windows/registry.nim index ab7d0b1fe..44e4e4420 100644 --- a/lib/windows/registry.nim +++ b/lib/windows/registry.nim @@ -46,26 +46,26 @@ template call(f) = proc getUnicodeValue*(path, key: string; handle: HKEY): string = let hh = newWideCString path let kk = newWideCString key - var bufsize: int32 + var bufSize: int32 # try a couple of different flag settings: var flags: int32 = RRF_RT_ANY - let err = regGetValue(handle, hh, kk, flags, nil, nil, addr bufsize) + let err = regGetValue(handle, hh, kk, flags, nil, nil, addr bufSize) if err != 0: var newHandle: HKEY call regOpenKeyEx(handle, hh, 0, KEY_READ or KEY_WOW64_64KEY, newHandle) - call regGetValue(newHandle, nil, kk, flags, nil, nil, addr bufsize) + call regGetValue(newHandle, nil, kk, flags, nil, nil, addr bufSize) if bufSize > 0: - var res = newWideCString(bufsize) + var res = newWideCString(bufSize) call regGetValue(newHandle, nil, kk, flags, nil, addr res[0], - addr bufsize) - result = res $ bufsize + addr bufSize) + result = res $ bufSize call regCloseKey(newHandle) else: if bufSize > 0: - var res = newWideCString(bufsize) + var res = newWideCString(bufSize) call regGetValue(handle, hh, kk, flags, nil, addr res[0], - addr bufsize) - result = res $ bufsize + addr bufSize) + result = res $ bufSize proc regSetValue(key: HKEY, lpSubKey, lpValueName: WideCString, dwType: int32; lpData: WideCString; cbData: int32): int32 {. diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index c02cd9775..cd59b68a4 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -670,7 +670,7 @@ proc getaddrinfo*(nodename, servname: cstring, hints: ptr AddrInfo, res: var ptr AddrInfo): cint {. stdcall, importc: "getaddrinfo", dynlib: ws2dll.} -proc freeaddrinfo*(ai: ptr AddrInfo) {. +proc freeAddrInfo*(ai: ptr AddrInfo) {. stdcall, importc: "freeaddrinfo", dynlib: ws2dll.} proc inet_ntoa*(i: InAddr): cstring {. diff --git a/tests/stdlib/config.nims b/tests/stdlib/config.nims new file mode 100644 index 000000000..0c0c5bd88 --- /dev/null +++ b/tests/stdlib/config.nims @@ -0,0 +1,2 @@ +switch("styleCheck", "usages") +switch("styleCheck", "error") \ No newline at end of file diff --git a/tests/stdlib/nre/misc.nim b/tests/stdlib/nre/misc.nim index dbb0ecdf9..b7df08ee9 100644 --- a/tests/stdlib/nre/misc.nim +++ b/tests/stdlib/nre/misc.nim @@ -6,8 +6,8 @@ block: # Misc tests check("перевірка".replace(re"(*U)\w", "") == "") block: # empty or non-empty match - check("abc".findall(re"|.").join(":") == ":a::b::c:") - check("abc".findall(re".|").join(":") == "a:b:c:") + check("abc".findAll(re"|.").join(":") == ":a::b::c:") + check("abc".findAll(re".|").join(":") == "a:b:c:") check("abc".replace(re"|.", "x") == "xxxxxxx") check("abc".replace(re".|", "x") == "xxxx") diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 5bb5a6bdf..61d2bc62f 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -101,10 +101,10 @@ block: doAssert binarySearch(noData, 7) == -1 let oneData = @[1] doAssert binarySearch(oneData, 1) == 0 - doAssert binarySearch(onedata, 7) == -1 + doAssert binarySearch(oneData, 7) == -1 let someData = @[1, 3, 4, 7] doAssert binarySearch(someData, 1) == 0 - doAssert binarySearch(somedata, 7) == 3 + doAssert binarySearch(someData, 7) == 3 doAssert binarySearch(someData, -1) == -1 doAssert binarySearch(someData, 5) == -1 doAssert binarySearch(someData, 13) == -1 diff --git a/tests/stdlib/tasynchttpserver.nim b/tests/stdlib/tasynchttpserver.nim index d4176d55a..aed21099d 100644 --- a/tests/stdlib/tasynchttpserver.nim +++ b/tests/stdlib/tasynchttpserver.nim @@ -111,9 +111,9 @@ proc testCustomContentLength() {.async.} = runTest(handler, request, test) -waitfor(test200()) -waitfor(test404()) -waitfor(testCustomEmptyHeaders()) -waitfor(testCustomContentLength()) +waitFor(test200()) +waitFor(test404()) +waitFor(testCustomEmptyHeaders()) +waitFor(testCustomContentLength()) echo "OK" diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index 491ec5db0..8ef5adf57 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -27,13 +27,13 @@ template main() = const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", "asure.", longText, testInputExpandsTo76, testInputExpands] - doAssert encodeMIME("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6" + doAssert encodeMime("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6" doAssert decode("Zm9v\r\nYmFy\r\nYmF6") == "foobarbaz" for t in items(tests): doAssert decode(encode(t)) == t - doAssert decode(encodeMIME(t, lineLen=40)) == t - doAssert decode(encodeMIME(t, lineLen=76)) == t + doAssert decode(encodeMime(t, lineLen=40)) == t + doAssert decode(encodeMime(t, lineLen=76)) == t doAssertRaises(ValueError): discard decode("SGVsbG\x008gV29ybGQ=") diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index 6b5e0aeb9..f807993d6 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -263,8 +263,8 @@ proc main() = doAssert v == 0b1000_0010 v.flipBit(1) doAssert v == 0b1000_0000 - doAssert v.testbit(7) - doAssert not v.testbit(6) + doAssert v.testBit(7) + doAssert not v.testBit(6) block: # multi bit operations var v: uint8 diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim index e81590d95..8563a0c26 100644 --- a/tests/stdlib/thttpclient.nim +++ b/tests/stdlib/thttpclient.nim @@ -21,7 +21,7 @@ proc makeIPv6HttpServer(hostname: string, port: Port, let fd = createNativeSocket(AF_INET6) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, AF_INET6) - if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: + if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: freeAddrInfo(aiList) raiseOSError(osLastError()) freeAddrInfo(aiList) diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 779c0ce65..9b59c7dc3 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -259,7 +259,7 @@ proc testJson() = colors: array[2, BirdColor] var red = BirdColor(name: "red", rgb: [1.0, 0.0, 0.0]) - var blue = Birdcolor(name: "blue", rgb: [0.0, 0.0, 1.0]) + var blue = BirdColor(name: "blue", rgb: [0.0, 0.0, 1.0]) var b = Bird(age: 3, height: 1.734, name: "bardo", colors: [red, blue]) let jnode = %b let data = jnode.to(Bird) @@ -497,7 +497,7 @@ proc testJson() = doAssert array[3, float](t.arr) == [1.0,2.0,7.0] doAssert MyRef(t.person).name == "boney" - doAssert MyObj(t.distFruit).color == 11 + doAssert MyObj(t.distfruit).color == 11 doAssert t.dog.name == "honey" doAssert t.fruit.color == 10 doAssert seq[string](t.emails) == @["abc", "123"] diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 205160471..d5809ee73 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -320,7 +320,7 @@ template fn() = b: int var a = A() - fromJson(a, """{"is_a": true, "a":1, "extra_key": 1}""".parse_json, Joptions(allowExtraKeys: true)) + fromJson(a, """{"is_a": true, "a":1, "extra_key": 1}""".parseJson, Joptions(allowExtraKeys: true)) doAssert $a[] == "(is_a: true, a: 1)" block testAllowMissingKeys: diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 671e0f7bc..4ec62d88f 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -93,7 +93,7 @@ block: # "IpAddress/Sockaddr conversion" doAssert($ipaddrstr == $ipaddr_1) var sockaddr: Sockaddr_storage - var socklen: Socklen + var socklen: SockLen var ipaddr_2: IpAddress var port_2: Port diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim index 3de00ff99..b836fb78d 100644 --- a/tests/stdlib/tnetdial.nim +++ b/tests/stdlib/tnetdial.nim @@ -14,7 +14,7 @@ proc initIPv6Server(hostname: string, port: Port): AsyncFD = let fd = createNativeSocket(AF_INET6) setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1) var aiList = getAddrInfo(hostname, port, AF_INET6) - if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: + if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: freeAddrInfo(aiList) raiseOSError(osLastError()) freeAddrInfo(aiList) diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index d767aac80..c54e0d112 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -12,7 +12,7 @@ see also: tests/osproc/*.nim; consider merging those into a single test here when defined(case_testfile): # compiled test file for child process from posix import exitnow - proc c_exit2(code: c_int): void {.importc: "_exit", header: "".} + proc c_exit2(code: cint): void {.importc: "_exit", header: "".} import os var a = 0 proc fun(b = 0) = diff --git a/tests/stdlib/tparsesql.nim b/tests/stdlib/tparsesql.nim index b440dc90f..8ef67f5dc 100644 --- a/tests/stdlib/tparsesql.nim +++ b/tests/stdlib/tparsesql.nim @@ -14,8 +14,8 @@ nkStmtList nkIntegerLit 10 nkNumericLit 5.5""" -doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;" -doAssert $parseSQL(""" +doAssert $parseSql("SELECT foo FROM table;") == "select foo from table;" +doAssert $parseSql(""" SELECT CustomerName, ContactName, @@ -31,26 +31,26 @@ SELECT Country FROM table;""") == "select CustomerName, ContactName, Address, City, PostalCode, Country, CustomerName, ContactName, Address, City, PostalCode, Country from table;" -doAssert $parseSQL("SELECT foo FROM table limit 10") == "select foo from table limit 10;" -doAssert $parseSQL("SELECT foo, bar, baz FROM table limit 10") == "select foo, bar, baz from table limit 10;" -doAssert $parseSQL("SELECT foo AS bar FROM table") == "select foo as bar from table;" -doAssert $parseSQL("SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table") == "select foo as foo_prime, bar as bar_prime, baz as baz_prime from table;" -doAssert $parseSQL("SELECT * FROM table") == "select * from table;" -doAssert $parseSQL("SELECT count(*) FROM table") == "select count(*) from table;" -doAssert $parseSQL("SELECT count(*) as 'Total' FROM table") == "select count(*) as 'Total' from table;" -doAssert $parseSQL("SELECT count(*) as 'Total', sum(a) as 'Aggr' FROM table") == "select count(*) as 'Total', sum(a) as 'Aggr' from table;" +doAssert $parseSql("SELECT foo FROM table limit 10") == "select foo from table limit 10;" +doAssert $parseSql("SELECT foo, bar, baz FROM table limit 10") == "select foo, bar, baz from table limit 10;" +doAssert $parseSql("SELECT foo AS bar FROM table") == "select foo as bar from table;" +doAssert $parseSql("SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table") == "select foo as foo_prime, bar as bar_prime, baz as baz_prime from table;" +doAssert $parseSql("SELECT * FROM table") == "select * from table;" +doAssert $parseSql("SELECT count(*) FROM table") == "select count(*) from table;" +doAssert $parseSql("SELECT count(*) as 'Total' FROM table") == "select count(*) as 'Total' from table;" +doAssert $parseSql("SELECT count(*) as 'Total', sum(a) as 'Aggr' FROM table") == "select count(*) as 'Total', sum(a) as 'Aggr' from table;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table WHERE a = b and c = d """) == "select * from table where a = b and c = d;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table WHERE not b """) == "select * from table where not b;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM @@ -59,63 +59,63 @@ WHERE a and not b """) == "select * from table where a and not b;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table ORDER BY 1 """) == "select * from table order by 1;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table GROUP BY 1 ORDER BY 1 """) == "select * from table group by 1 order by 1;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table ORDER BY 1 LIMIT 100 """) == "select * from table order by 1 limit 100;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table WHERE a = b and c = d or n is null and not b + 1 = 3 """) == "select * from table where a = b and c = d or n is null and not b + 1 = 3;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table WHERE (a = b and c = d) or (n is null and not b + 1 = 3) """) == "select * from table where(a = b and c = d) or (n is null and not b + 1 = 3);" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM table HAVING a = b and c = d """) == "select * from table having a = b and c = d;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT a, b FROM table GROUP BY a """) == "select a, b from table group by a;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT a, b FROM table GROUP BY 1, 2 """) == "select a, b from table group by 1, 2;" -doAssert $parseSQL("SELECT t.a FROM t as t") == "select t.a from t as t;" +doAssert $parseSql("SELECT t.a FROM t as t") == "select t.a from t as t;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT a, b FROM ( SELECT * FROM t ) """) == "select a, b from(select * from t);" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT a, b FROM ( SELECT * FROM t ) as foo """) == "select a, b from(select * from t) as foo;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT a, b FROM ( SELECT * FROM ( SELECT * FROM ( @@ -127,49 +127,49 @@ SELECT a, b FROM ( ) as inner5 """) == "select a, b from(select * from(select * from(select * from(select * from innerTable as inner1) as inner2) as inner3) as inner4) as inner5;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT a, b FROM (SELECT * FROM a), (SELECT * FROM b), (SELECT * FROM c) """) == "select a, b from(select * from a),(select * from b),(select * from c);" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM Products WHERE Price BETWEEN 10 AND 20; """) == "select * from Products where Price between 10 and 20;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT id FROM a JOIN b ON a.id == b.id """) == "select id from a join b on a.id == b.id;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT id FROM a JOIN (SELECT id from c) as b ON a.id == b.id """) == "select id from a join(select id from c) as b on a.id == b.id;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT id FROM a INNER JOIN b ON a.id == b.id """) == "select id from a inner join b on a.id == b.id;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT id FROM a OUTER JOIN b ON a.id == b.id """) == "select id from a outer join b on a.id == b.id;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT id FROM a CROSS JOIN b ON a.id == b.id """) == "select id from a cross join b on a.id == b.id;" -doAssert $parseSQL(""" +doAssert $parseSql(""" CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic'); CREATE TABLE holidays ( num_weeks int, @@ -179,16 +179,16 @@ CREATE INDEX table1_attr1 ON table1(attr1); SELECT * FROM myTab WHERE col1 = 'happy'; """) == "create type happiness as enum ('happy' , 'very happy' , 'ecstatic' ); create table holidays(num_weeks int , happiness happiness );; create index table1_attr1 on table1(attr1 );; select * from myTab where col1 = 'happy';" -doAssert $parseSQL(""" +doAssert $parseSql(""" INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country) VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway'); """) == "insert into Customers (CustomerName , ContactName , Address , City , PostalCode , Country ) values ('Cardinal' , 'Tom B. Erichsen' , 'Skagen 21' , 'Stavanger' , '4006' , 'Norway' );" -doAssert $parseSQL(""" +doAssert $parseSql(""" INSERT INTO TableName DEFAULT VALUES """) == "insert into TableName default values;" -doAssert $parseSQL(""" +doAssert $parseSql(""" UPDATE Customers SET ContactName = 'Alfred Schmidt', City= 'Frankfurt' WHERE CustomerID = 1; @@ -209,9 +209,9 @@ nkStmtList nkStringLit Frankfurt nkNone""" -doAssert $parseSQL("DELETE FROM table_name;") == "delete from table_name;" +doAssert $parseSql("DELETE FROM table_name;") == "delete from table_name;" -doAssert treeRepr(parseSQL("DELETE FROM table_name;") +doAssert treeRepr(parseSql("DELETE FROM table_name;") ) == """ nkStmtList @@ -219,14 +219,14 @@ nkStmtList nkIdent table_name nkNone""" -doAssert $parseSQL("DELETE * FROM table_name;") == "delete from table_name;" +doAssert $parseSql("DELETE * FROM table_name;") == "delete from table_name;" -doAssert $parseSQL(""" +doAssert $parseSql(""" --Select all: SELECT * FROM Customers; """) == "select * from Customers;" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT * FROM Customers WHERE (CustomerName LIKE 'L%' OR CustomerName LIKE 'R%' /*OR CustomerName LIKE 'S%' OR CustomerName LIKE 'T%'*/ OR CustomerName LIKE 'W%') @@ -235,9 +235,9 @@ ORDER BY CustomerName; """) == "select * from Customers where(CustomerName like 'L%' or CustomerName like 'R%' or CustomerName like 'W%') and Country = 'USA' order by CustomerName;" # parse quoted keywords as identifires -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT `SELECT`, `FROM` as `GROUP` FROM `WHERE`; """) == """select "SELECT", "FROM" as "GROUP" from "WHERE";""" -doAssert $parseSQL(""" +doAssert $parseSql(""" SELECT "SELECT", "FROM" as "GROUP" FROM "WHERE"; """) == """select "SELECT", "FROM" as "GROUP" from "WHERE";""" diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 8b98d1403..9787c13eb 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -861,7 +861,7 @@ suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") let input = ".. include:: other.rst" - doAssert "test1" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) + doAssert "test1" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") test "Include starting from": @@ -875,7 +875,7 @@ OtherStart .. include:: other.rst :start-after: OtherStart """ - check "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) + check "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") test "Include everything before": @@ -889,7 +889,7 @@ And this should **NOT** be visible in `docs.html` .. include:: other.rst :end-before: OtherEnd """ - doAssert "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) + doAssert "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") @@ -907,7 +907,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - check "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) + check "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") @@ -927,7 +927,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - doAssert "Visible" == rstTohtml(input, {roSandboxDisabled}, defaultConfig()) + doAssert "Visible" == rstToHtml(input, {roSandboxDisabled}, defaultConfig()) removeFile("other.rst") suite "RST escaping": diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 2c28fe506..d91b5615e 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -417,7 +417,7 @@ Some chapter """ var error9Bad = new string - let output9Bad = input9bad.toHtml(error=error9Bad) + let output9Bad = input9Bad.toHtml(error=error9Bad) check(error9Bad[] == "input(15, 1) Error: new section expected (section " & "level inconsistent: underline ~~~~~ unexpectedly found, while " & "the following intermediate section level(s) are missing on " & @@ -464,7 +464,7 @@ Some chapter rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames = files) rstGenera.renderRstToOut(rst, output) doAssert rstGenera.meta[metaTitle] == "Title0" - doAssert rstGenera.meta[metaSubTitle] == "SubTitle0" + doAssert rstGenera.meta[metaSubtitle] == "SubTitle0" doAssert "

      Level1

      " in output doAssert "

      Level2

      " in output doAssert "

      Level3

      " in output @@ -491,7 +491,7 @@ Some chapter rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) rstGenera.renderRstToOut(rst, output) doAssert rstGenera.meta[metaTitle] == "" - doAssert rstGenera.meta[metaSubTitle] == "" + doAssert rstGenera.meta[metaSubtitle] == "" doAssert "

      Title0

      " in output doAssert "

      SubTitle0

      " in output @@ -521,7 +521,7 @@ Some chapter rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files) rstGenera.renderRstToOut(rst, output) doAssert rstGenera.meta[metaTitle] == "Title0" - doAssert rstGenera.meta[metaSubTitle] == "" + doAssert rstGenera.meta[metaSubtitle] == "" doAssert output == "\n

      MySection1a

      " & # RST "\n

      MySection1b

      " & # Markdown diff --git a/tests/stdlib/tsha1.nim b/tests/stdlib/tsha1.nim index a20183039..6dca1f197 100644 --- a/tests/stdlib/tsha1.nim +++ b/tests/stdlib/tsha1.nim @@ -15,7 +15,7 @@ checkVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", proc testIsValidSha1Hash = doAssert not isValidSha1Hash("") doAssert not isValidSha1Hash("042D4BE2B90ED0672E717D71850ABDB0A2D19CD11") - doAssert not isValidSha1hash("042G4BE2B90ED0672E717D71850ABDB0A2D19CD1") + doAssert not isValidSha1Hash("042G4BE2B90ED0672E717D71850ABDB0A2D19CD1") doAssert isValidSha1Hash("042D4BE2B90ED0672E717D71850ABDB0A2D19CD1") doAssert isValidSha1Hash("042d4be2b90ed0672e717d71850abdb0a2d19cd1") doAssert isValidSha1Hash("042d4be2b90ed0672e717D71850ABDB0A2D19CD1") diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim index 7625f3694..379c1b1e5 100644 --- a/tests/stdlib/tssl.nim +++ b/tests/stdlib/tssl.nim @@ -37,8 +37,8 @@ proc notifiedShutdown(port: Port) {.thread.} = proc main() = when defined(posix): var - ignoreAction = SigAction(sa_handler: SIG_IGN) - oldSigPipeHandler: SigAction + ignoreAction = Sigaction(sa_handler: SIG_IGN) + oldSigPipeHandler: Sigaction if sigemptyset(ignoreAction.sa_mask) == -1: raiseOSError(osLastError(), "Couldn't create an empty signal set") if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1: diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim index b340ad509..bf562d9ec 100644 --- a/tests/stdlib/tstrbasics.nim +++ b/tests/stdlib/tstrbasics.nim @@ -73,7 +73,7 @@ proc main() = block: # setSlice var a = "Hello, Nim!" - doassert a.dup(setSlice(7 .. 9)) == "Nim" + doAssert a.dup(setSlice(7 .. 9)) == "Nim" doAssert a.dup(setSlice(0 .. 0)) == "H" doAssert a.dup(setSlice(0 .. 1)) == "He" doAssert a.dup(setSlice(0 .. 10)) == a diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index d70d4995a..d199037e3 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -40,7 +40,7 @@ block tstreams2: block tstreams3: try: var fs = openFileStream("shouldneverexist.txt") - except IoError: + except IOError: echo "threw exception" static: diff --git a/tests/stdlib/tstrset.nim b/tests/stdlib/tstrset.nim index 1b253f862..71a5520c2 100644 --- a/tests/stdlib/tstrset.nim +++ b/tests/stdlib/tstrset.nim @@ -50,7 +50,7 @@ proc search(r: PRadixNode, s: string): PRadixNode = proc contains*(r: PRadixNode, s: string): bool = return search(r, s) != nil -proc testOrincl*(r: var PRadixNode, s: string): bool = +proc testOrIncl*(r: var PRadixNode, s: string): bool = nil proc incl*(r: var PRadixNode, s: string) = discard testOrIncl(r, s) diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 2cf945786..fd440eb20 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -20,7 +20,7 @@ proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} = result.utcOffset = offset result.time = time - newTimezone("", zonedTimeFromTime, zonedTImeFromAdjTime) + newTimezone("", zonedTimeFromTime, zonedTimeFromAdjTime) template parseTest(s, f, sExpected: string, ydExpected: int) = let diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim index 61c661a58..1cddea781 100644 --- a/tests/stdlib/ttypeinfo.nim +++ b/tests/stdlib/ttypeinfo.nim @@ -50,7 +50,7 @@ doAssert($x4[].kind() == "akString") block: # gimme a new scope dammit - var myarr: array[0..4, array[0..4, string]] = [ + var myArr: array[0..4, array[0..4, string]] = [ ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] diff --git a/tests/stdlib/ttypeinfo.nims b/tests/stdlib/ttypeinfo.nims new file mode 100644 index 000000000..d31d0b26f --- /dev/null +++ b/tests/stdlib/ttypeinfo.nims @@ -0,0 +1 @@ +--styleCheck:off \ No newline at end of file diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim index 33405cf38..3a8206c8f 100644 --- a/tests/stdlib/tunicode.nim +++ b/tests/stdlib/tunicode.nim @@ -218,5 +218,5 @@ block: # bug #17768 let s1 = "abcdef" let s2 = "abcdéf" - doAssert s1.runeSubstr(0, -1) == "abcde" - doAssert s2.runeSubstr(0, -1) == "abcdé" + doAssert s1.runeSubStr(0, -1) == "abcde" + doAssert s2.runeSubStr(0, -1) == "abcdé" diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim index 772121f9f..3bba4f457 100644 --- a/tests/stdlib/tvarints.nim +++ b/tests/stdlib/tvarints.nim @@ -48,7 +48,7 @@ block: chk 0.1 chk Inf chk NegInf - chk Nan + chk NaN chk 3.1415926535897932384626433 block: From ef7d7f24594b1ea560fbf25d3fa0d6c51122725f Mon Sep 17 00:00:00 2001 From: huantian Date: Wed, 13 Apr 2022 14:03:46 -0700 Subject: [PATCH 3373/4254] Better error message and tests for bad await (#19622) * Better error message and tests for bad await * Use compiles to check if await is valid * temp: disable windows noasync test * Better error report, simplify test Co-authored-by: flywind --- lib/pure/asyncmacro.nim | 16 +++++++++++++--- tests/async/tasync_noasync.nim | 35 +++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index ce538913f..63c8e6e5c 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -126,9 +126,19 @@ template await*(f: typed): untyped {.used.} = error "await expects Future[T], got " & $typeof(f) template await*[T](f: Future[T]): auto {.used.} = - var internalTmpFuture: FutureBase = f - yield internalTmpFuture - (cast[typeof(f)](internalTmpFuture)).read() + template yieldFuture = yield FutureBase() + + when compiles(yieldFuture): + var internalTmpFuture: FutureBase = f + yield internalTmpFuture + (cast[typeof(f)](internalTmpFuture)).read() + else: + macro errorAsync(futureError: Future[T]) = + error( + "Can only 'await' inside a proc marked as 'async'. Use " & + "'waitFor' when calling an 'async' proc in a non-async scope instead", + futureError) + errorAsync(f) proc asyncSingleProc(prc: NimNode): NimNode = ## This macro transforms a single procedure into a closure iterator. diff --git a/tests/async/tasync_noasync.nim b/tests/async/tasync_noasync.nim index 54f4f597f..0927148bf 100644 --- a/tests/async/tasync_noasync.nim +++ b/tests/async/tasync_noasync.nim @@ -1,13 +1,42 @@ discard """ - errormsg: "'yield' only allowed in an iterator" - cmd: "nim c $file" - file: "asyncmacro.nim" + cmd: "nim check --hints:off --warnings:off $file" + action: "reject" + nimout: ''' +tasync_noasync.nim(21, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +tasync_noasync.nim(25, 12) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +tasync_noasync.nim(28, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +tasync_noasync.nim(31, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +tasync_noasync.nim(35, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +tasync_noasync.nim(38, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +tasync_noasync.nim(40, 8) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead +''' """ import async proc a {.async.} = discard +# Bad await usage +proc nonAsyncProc = + await a() + +proc nestedNonAsyncProc {.async.} = + proc nested = + await a() + +iterator customIterator: int = + await a() + +macro awaitInMacro = + await a() + +type DummyRef = ref object of RootObj +method awaitInMethod(_: DummyRef) {.base.} = + await a() + +proc improperMultisync {.multisync.} = + await a() + await a() # if we overload a fallback handler to get From dc4cc2dca53e3772efb3654a4ddbbe8350d1db43 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Thu, 14 Apr 2022 03:30:59 -0600 Subject: [PATCH 3374/4254] Fix string stream crashing when created on nimscript due to last fix (#19717) --- lib/pure/streams.nim | 2 +- tests/stdlib/tstreams.nim | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 84451f989..2ac6a82f1 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1274,7 +1274,7 @@ else: # after 1.3 or JS not defined new(result) result.data = s - when defined(gcOrc) or defined(gcArc): + when declared(prepareMutation): prepareMutation(result.data) # Allows us to mutate using `addr` logic like `copyMem`, otherwise it errors. result.pos = 0 result.closeImpl = ssClose diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index d199037e3..6fda30f51 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -76,3 +76,7 @@ block: doAssert(ss.getPosition == 5) # haven't moved ss.setPosition(0) # Ensure we dont error with writing over literals on arc/orc #19707 ss.write("hello") + +static: # Ensure streams it doesnt break with nimscript on arc/orc #19716 + let s = newStringStream("a") + discard s.data From bb839029d5065bcd8367661802bf04e1e7eebb58 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Thu, 21 Apr 2022 22:06:09 +0300 Subject: [PATCH 3375/4254] Move common Latex code into class nimdoc.cls (#19734) --- compiler/docgen.nim | 6 +- compiler/nimpaths.nim | 2 + config/nimdoc.tex.cfg | 188 +---------------------------------------- doc/nimdoc.cls | 190 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 198 insertions(+), 188 deletions(-) create mode 100644 doc/nimdoc.cls diff --git a/compiler/docgen.nim b/compiler/docgen.nim index aad3b9409..ecf98d0b6 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1576,7 +1576,11 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) = outfile.string) if not d.wroteSupportFiles: # nimdoc.css + dochack.js let nimr = $d.conf.getPrefixDir() - copyFile(docCss.interp(nimr = nimr), $d.conf.outDir / nimdocOutCss) + case d.target + of outHtml: + copyFile(docCss.interp(nimr = nimr), $d.conf.outDir / nimdocOutCss) + of outLatex: + copyFile(docCls.interp(nimr = nimr), $d.conf.outDir / nimdocOutCls) if optGenIndex in d.conf.globalOptions: let docHackJs2 = getDocHacksJs(nimr, nim = getAppFilename()) copyFile(docHackJs2, $d.conf.outDir / docHackJs2.lastPathPart) diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim index 216071c5c..c6e188289 100644 --- a/compiler/nimpaths.nim +++ b/compiler/nimpaths.nim @@ -25,11 +25,13 @@ when defined(nimPreviewSlimSystem): const docCss* = "$nimr/doc/nimdoc.css" + docCls* = "$nimr/doc/nimdoc.cls" docHackNim* = "$nimr/tools/dochack/dochack.nim" docHackJs* = docHackNim.changeFileExt("js") docHackJsFname* = docHackJs.lastPathPart theindexFname* = "theindex.html" nimdocOutCss* = "nimdoc.out.css" + nimdocOutCls* = "nimdoc.cls" # `out` to make it easier to use with gitignore in user's repos htmldocsDirname* = "htmldocs" dotdotMangle* = "_._" ## refs #13223 diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 3912d1279..4fb1aec90 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -69,198 +69,12 @@ doc.file = """ % makeindex file % xelatex file.tex % -\documentclass[a4paper,11pt]{article} -\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry} - -% for 2-sided printing with larger inner "binding" margin -%\usepackage[a4paper,xetex,twoside,left=4cm,right=2cm,top=1.5cm,bottom=2cm]{geometry} -% for e-readers with 1.77:1 aspect ratio (e.g. 1920x1080) -%\usepackage[xetex,paperheight=27.6cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} -% for e-readers with 1.45:1 aspect ratio (e.g. 1200x825) -%\usepackage[xetex,paperheight=22.5cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} -% for e-readers with 1.33:1 aspect ratio (e.g. 1872x1404) -%\usepackage[xetex,paperheight=20.7cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} - -\usepackage{fontspec} -% logic to select default font with some fall-back fonts. -\IfFontExistsTF{Times New Roman}{% - \setmainfont{Times New Roman} % the default font - \typeout{========================================= nim: using Times New Roman} -}{ - \IfFontExistsTF{FreeSerif}{% - \setmainfont{FreeSerif} % fallback #1 - official GNU font, resembles Times - \typeout{========================================= nim: using FreeSerif} - }{ - \IfFontExistsTF{DejaVuSerif}{% - \setmainfont{DejaVuSerif} % fallback #2 - very widespread free font - \typeout{========================================= nim: using DejaVuSerif} - }{ - \typeout{!!!!!!!!!!!!!!!!!!! Fonts not found !!!!!!!!!!!!!!!!!!!!!!!} - } - } -} - -% default monospace font for code: -\usepackage{GoMono} -\usepackage{relsize} -% make this monospace font 2 steps smaller to hold 80-character line -\newcommand{\rstverbblockfont}{\smaller[2]} -\newcommand{\rstverbinlinefont}{\smaller} - -\usepackage{parskip} % paragraphs delimited by vertical space, no indent -\usepackage{graphicx} - -\usepackage{makeidx} -\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}} -\makeindex - -\usepackage{dingbat} % for \carriagereturn, etc -\usepackage{fvextra} % for code blocks (works better than original fancyvrb) -\fvset{ - breaklines, - breakafter={=}:|\_\{\}[](){,}.;+-*/'", - breaksymbolleft=\color{red}{\ensuremath{\hookrightarrow}}, - breaksymbolright=\color{red}{\small\carriagereturn} -} -\fvinlineset{% - breaklines, - breakafter={=}:|\_\{\}[](){,}.;+-*/'", - % that does not work at all when we underline inline code by ulem :-( - commandchars=\\\{\} -} - -\usepackage{scrextend} % for the `addmargin` environment - -\usepackage{xcolor} -\usepackage[urlbordercolor=blue,linkbordercolor=cyan, - pdfborderstyle={/S/U/W 1}]{hyperref} -\usepackage{enumitem} % for option list, enumList, and rstfootnote - -\usepackage[most]{tcolorbox} % boxes around admonitions, code blocks, doc.item - -\newtcolorbox{rstadmonition}[1][]{blanker, breakable, - left=3mm, right=0mm, top=1mm, bottom=1mm, - before upper=\indent, parbox=false, #1} - -\newtcolorbox{rstquote}[1][]{blanker, breakable, - left=3mm, right=3mm, top=1mm, bottom=1mm, - parbox=false, - borderline west={0.3em}{0pt}{lightgray}, - borderline north={0.05em}{0pt}{lightgray}, - borderline east={0.05em}{0pt}{lightgray}, - borderline south={0.05em}{0pt}{lightgray}} - -\definecolor{rstframecolor}{rgb}{0.85, 0.8, 0.6} - -\newtcolorbox{rstprebox}[1][]{blanker, breakable, - left=3mm, right=3mm, top=1mm, bottom=1mm, - borderline ={0.1em}{0pt}{rstframecolor}, - before upper=\indent, parbox=false, #1} - -\newenvironment{rstpre}{% -\VerbatimEnvironment\begingroup\begin{rstprebox}% -\begin{Verbatim}[fontsize=\rstverbblockfont , commandchars=\\\{\}]}% -{\end{Verbatim}\end{rstprebox}\endgroup} - -\newtcolorbox{rstdocitembox}[1][]{blanker, breakable, - left=3mm, right=3mm, top=1mm, bottom=1mm, - borderline ={1pt}{0pt}{cyan}, - before upper=\indent, parbox=false, #1} - -% Inline code formatting: grey underline, -% use \Verb from fvextras e.g. to display -- correctly as double - -\usepackage[normalem]{ulem} -\newcommand\rstuline{\bgroup\markoverwith{\textcolor{rstframecolor}{\rule[-0.8ex]{2pt}{1.0pt}}}\ULon} - -\newcommand{\rstcode}[1]{% -{\rstverbinlinefont\Verb{\rstuline{#1}}}% -} - -\newcommand{\rstcodeitem}[1]{\Verb{#1}} - -\newenvironment{rstdocitem}{% -\VerbatimEnvironment\begingroup\begin{rstdocitembox}% -\begin{Verbatim}[fontsize=\rstverbblockfont , commandchars=\\\{\}]}% -{\end{Verbatim}\end{rstdocitembox}\endgroup} - - -\newenvironment{rstfootnote}{\begin{description}[labelindent=1em,leftmargin=1em,labelwidth=2.6em]}{\end{description}} -\ifdim\linewidth<30em - \def\rstoptleftmargin{0.4\linewidth} - \def\rstoptlabelwidth{0.35\linewidth} -\else - \def\rstoptleftmargin{12em} - \def\rstoptlabelwidth{10.5em} -\fi -\newenvironment{rstoptlist}{% -\begin{description}[font=\sffamily\bfseries,style=nextline,leftmargin=\rstoptleftmargin,labelwidth=\rstoptlabelwidth]}{\end{description}} - -\usepackage{tabulary} % tables with adjustable cell width and no overflow -% make tabulary prevent overflows (https://tex.stackexchange.com/a/195088) -\tymin=60pt -\tymax=\maxdimen -% to pack tabulary into a new environment, special syntax is needed :-( -\newenvironment{rsttab}[1]{\tabulary{\linewidth}{#1}}{\endtabulary} - -\newcommand{\rstsub}[1]{\raisebox{-0.5ex}{\scriptsize{#1}}} -\newcommand{\rstsup}[1]{\raisebox{0.5ex}{\scriptsize{#1}}} - -\newcommand{\rsthA}[2][]{\section[#1]{#2}} -\newcommand{\rsthB}[2][]{\subsection[#1]{#2}} -\newcommand{\rsthC}[2][]{\subsubsection[#1]{#2}} -\newcommand{\rsthD}[2][]{\paragraph[#1]{#2}} -\newcommand{\rsthE}[2][]{\paragraph[#1]{#2}} - -\newcommand{\rstovA}[2][]{\section*[#1]{#2}} -\newcommand{\rstovB}[2][]{\subsection*[#1]{#2}} -\newcommand{\rstovC}[2][]{\subsubsection*[#1]{#2}} -\newcommand{\rstovD}[2][]{\paragraph*[#1]{#2}} -\newcommand{\rstovE}[2][]{\paragraph*[#1]{#2}} - -% Syntax highlighting: -\newcommand{\spanDecNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanBinNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanHexNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanOctNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanFloatNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanIdentifier}[1]{#1} -\newcommand{\spanKeyword}[1]{\textbf{#1}} -\newcommand{\spanStringLit}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanLongStringLit}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanCharLit}[1]{#1} -\newcommand{\spanEscapeSequence}[1]{#1} -\newcommand{\spanOperator}[1]{\textbf{#1}} -\newcommand{\spanPunctuation}[1]{#1} -\newcommand{\spanComment}[1]{\emph{#1}} -\newcommand{\spanLongComment}[1]{\emph{#1}} -\newcommand{\spanRegularExpression}[1]{#1} -\newcommand{\spanTagStart}[1]{#1} -\newcommand{\spanTagEnd}[1]{#1} -\newcommand{\spanKey}[1]{#1} -\newcommand{\spanValue}[1]{#1} -\newcommand{\spanRawData}[1]{\textbf{\textcolor{darkgray}{#1}}} -\newcommand{\spanAssembler}[1]{#1} -\newcommand{\spanPreprocessor}[1]{#1} -\newcommand{\spanDirective}[1]{#1} -\newcommand{\spanCommand}[1]{#1} -\newcommand{\spanRule}[1]{#1} -\newcommand{\spanHyperlink}[1]{#1} -\newcommand{\spanLabel}[1]{#1} -\newcommand{\spanReference}[1]{#1} -\newcommand{\spanOther}[1]{#1} -\newcommand{\spantok}[1]{\fbox{#1}} -\newcommand{\spanPrompt}[1]{\textcolor{red}{\textbf{#1}}} -\newcommand{\spanProgramOutput}[1]{\textcolor{darkgray}{\textbf{#1}}} -\newcommand{\spanprogram}[1]{\textbf{\underline{#1}}} -\newcommand{\spanoption}[1]{\textbf{\textcolor{darkgray}{#1}}} +\documentclass{nimdoc} \begin{document} \title{$title $version $subtitle} \author{$author} -% Never allow text overflow to margin: -\setlength\emergencystretch{\hsize}\hbadness=10000 - \maketitle $content diff --git a/doc/nimdoc.cls b/doc/nimdoc.cls new file mode 100644 index 000000000..271dc5dc9 --- /dev/null +++ b/doc/nimdoc.cls @@ -0,0 +1,190 @@ +\ProvidesClass{nimdoc}[2022/04/17, 2018/01/01 LaTeX2e nonstandard class] + +\LoadClass[a4paper,11pt]{article} + +\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry} + +% for 2-sided printing with larger inner "binding" margin +%\usepackage[a4paper,xetex,twoside,left=4cm,right=2cm,top=1.5cm,bottom=2cm]{geometry} +% for e-readers with 1.77:1 aspect ratio (e.g. 1920x1080) +%\usepackage[xetex,paperheight=27.6cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} +% for e-readers with 1.45:1 aspect ratio (e.g. 1200x825) +%\usepackage[xetex,paperheight=22.5cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} +% for e-readers with 1.33:1 aspect ratio (e.g. 1872x1404) +%\usepackage[xetex,paperheight=20.7cm,paperwidth=15.5cm,left=3mm,right=3mm,top=3mm,bottom=3mm]{geometry} + +\usepackage{fontspec} +% logic to select default font with some fall-back fonts. +\IfFontExistsTF{Times New Roman}{% + \setmainfont{Times New Roman} % the default font + \typeout{========================================= nim: using Times New Roman} +}{ + \IfFontExistsTF{FreeSerif}{% + \setmainfont{FreeSerif} % fallback #1 - official GNU font, resembles Times + \typeout{========================================= nim: using FreeSerif} + }{ + \IfFontExistsTF{DejaVuSerif}{% + \setmainfont{DejaVuSerif} % fallback #2 - very widespread free font + \typeout{========================================= nim: using DejaVuSerif} + }{ + \typeout{!!!!!!!!!!!!!!!!!!! Fonts not found !!!!!!!!!!!!!!!!!!!!!!!} + } + } +} + +% default monospace font for code: +\usepackage{GoMono} +\usepackage{relsize} +% make this monospace font 2 steps smaller to hold 80-character line +\newcommand{\rstverbblockfont}{\smaller[2]} +\newcommand{\rstverbinlinefont}{\smaller} + +\usepackage{parskip} % paragraphs delimited by vertical space, no indent +\usepackage{graphicx} + +\usepackage{makeidx} +\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}} +\makeindex + +\usepackage{dingbat} % for \carriagereturn, etc +\usepackage{fvextra} % for code blocks (works better than original fancyvrb) +\fvset{ + breaklines, + breakafter={=}:|\_\{\}[](){,}.;+-*/'", + breaksymbolleft=\color{red}{\ensuremath{\hookrightarrow}}, + breaksymbolright=\color{red}{\small\carriagereturn} +} +\fvinlineset{% + breaklines, + breakafter={=}:|\_\{\}[](){,}.;+-*/'", + % that does not work at all when we underline inline code by ulem :-( + commandchars=\\\{\} +} + +\usepackage{scrextend} % for the `addmargin` environment + +\usepackage{xcolor} +\usepackage[urlbordercolor=blue,linkbordercolor=cyan, + pdfborderstyle={/S/U/W 1}]{hyperref} +\usepackage{enumitem} % for option list, enumList, and rstfootnote + +\usepackage[most]{tcolorbox} % boxes around admonitions, code blocks, doc.item + +\newtcolorbox{rstadmonition}[1][]{blanker, breakable, + left=3mm, right=0mm, top=1mm, bottom=1mm, + before upper=\indent, parbox=false, #1} + +\newtcolorbox{rstquote}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + parbox=false, + borderline west={0.3em}{0pt}{lightgray}, + borderline north={0.05em}{0pt}{lightgray}, + borderline east={0.05em}{0pt}{lightgray}, + borderline south={0.05em}{0pt}{lightgray}} + +\definecolor{rstframecolor}{rgb}{0.85, 0.8, 0.6} + +\newtcolorbox{rstprebox}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + borderline ={0.1em}{0pt}{rstframecolor}, + before upper=\indent, parbox=false, #1} + +\newenvironment{rstpre}{% +\VerbatimEnvironment\begingroup\begin{rstprebox}% +\begin{Verbatim}[fontsize=\rstverbblockfont , commandchars=\\\{\}]}% +{\end{Verbatim}\end{rstprebox}\endgroup} + +\newtcolorbox{rstdocitembox}[1][]{blanker, breakable, + left=3mm, right=3mm, top=1mm, bottom=1mm, + borderline ={1pt}{0pt}{cyan}, + before upper=\indent, parbox=false, #1} + +% Inline code formatting: grey underline, +% use \Verb from fvextras e.g. to display -- correctly as double - +\usepackage[normalem]{ulem} +\newcommand\rstuline{\bgroup\markoverwith{\textcolor{rstframecolor}{\rule[-0.8ex]{2pt}{1.0pt}}}\ULon} + +\newcommand{\rstcode}[1]{% +{\rstverbinlinefont\Verb{\rstuline{#1}}}% +} + +\newcommand{\rstcodeitem}[1]{\Verb{#1}} + +\newenvironment{rstdocitem}{% +\VerbatimEnvironment\begingroup\begin{rstdocitembox}% +\begin{Verbatim}[fontsize=\rstverbblockfont , commandchars=\\\{\}]}% +{\end{Verbatim}\end{rstdocitembox}\endgroup} + + +\newenvironment{rstfootnote}{\begin{description}[labelindent=1em,leftmargin=1em,labelwidth=2.6em]}{\end{description}} +\ifdim\linewidth<30em + \def\rstoptleftmargin{0.4\linewidth} + \def\rstoptlabelwidth{0.35\linewidth} +\else + \def\rstoptleftmargin{12em} + \def\rstoptlabelwidth{10.5em} +\fi +\newenvironment{rstoptlist}{% +\begin{description}[font=\sffamily\bfseries,style=nextline,leftmargin=\rstoptleftmargin,labelwidth=\rstoptlabelwidth]}{\end{description}} + +\usepackage{tabulary} % tables with adjustable cell width and no overflow +% make tabulary prevent overflows (https://tex.stackexchange.com/a/195088) +\tymin=60pt +\tymax=\maxdimen +% to pack tabulary into a new environment, special syntax is needed :-( +\newenvironment{rsttab}[1]{\tabulary{\linewidth}{#1}}{\endtabulary} + +\newcommand{\rstsub}[1]{\raisebox{-0.5ex}{\scriptsize{#1}}} +\newcommand{\rstsup}[1]{\raisebox{0.5ex}{\scriptsize{#1}}} + +\newcommand{\rsthA}[2][]{\section[#1]{#2}} +\newcommand{\rsthB}[2][]{\subsection[#1]{#2}} +\newcommand{\rsthC}[2][]{\subsubsection[#1]{#2}} +\newcommand{\rsthD}[2][]{\paragraph[#1]{#2}} +\newcommand{\rsthE}[2][]{\paragraph[#1]{#2}} + +\newcommand{\rstovA}[2][]{\section*[#1]{#2}} +\newcommand{\rstovB}[2][]{\subsection*[#1]{#2}} +\newcommand{\rstovC}[2][]{\subsubsection*[#1]{#2}} +\newcommand{\rstovD}[2][]{\paragraph*[#1]{#2}} +\newcommand{\rstovE}[2][]{\paragraph*[#1]{#2}} + +% Syntax highlighting: +\newcommand{\spanDecNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanBinNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanHexNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanOctNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanFloatNumber}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanIdentifier}[1]{#1} +\newcommand{\spanKeyword}[1]{\textbf{#1}} +\newcommand{\spanStringLit}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanLongStringLit}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanCharLit}[1]{#1} +\newcommand{\spanEscapeSequence}[1]{#1} +\newcommand{\spanOperator}[1]{\textbf{#1}} +\newcommand{\spanPunctuation}[1]{#1} +\newcommand{\spanComment}[1]{\emph{#1}} +\newcommand{\spanLongComment}[1]{\emph{#1}} +\newcommand{\spanRegularExpression}[1]{#1} +\newcommand{\spanTagStart}[1]{#1} +\newcommand{\spanTagEnd}[1]{#1} +\newcommand{\spanKey}[1]{#1} +\newcommand{\spanValue}[1]{#1} +\newcommand{\spanRawData}[1]{\textbf{\textcolor{darkgray}{#1}}} +\newcommand{\spanAssembler}[1]{#1} +\newcommand{\spanPreprocessor}[1]{#1} +\newcommand{\spanDirective}[1]{#1} +\newcommand{\spanCommand}[1]{#1} +\newcommand{\spanRule}[1]{#1} +\newcommand{\spanHyperlink}[1]{#1} +\newcommand{\spanLabel}[1]{#1} +\newcommand{\spanReference}[1]{#1} +\newcommand{\spanOther}[1]{#1} +\newcommand{\spantok}[1]{\fbox{#1}} +\newcommand{\spanPrompt}[1]{\textcolor{red}{\textbf{#1}}} +\newcommand{\spanProgramOutput}[1]{\textcolor{darkgray}{\textbf{#1}}} +\newcommand{\spanprogram}[1]{\textbf{\underline{#1}}} +\newcommand{\spanoption}[1]{\textbf{\textcolor{darkgray}{#1}}} + +% Never allow text overflow to margin: +\setlength\emergencystretch{\hsize}\hbadness=10000 From 02e8aa9660ae78a4d6a67656709f9379f30c5197 Mon Sep 17 00:00:00 2001 From: huantian Date: Sun, 24 Apr 2022 02:47:39 -0700 Subject: [PATCH 3376/4254] Fix doc: list of async backends (#19741) --- lib/pure/asyncdispatch.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index b67b0c308..b1e1c19fd 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -187,9 +187,9 @@ ## ## Known `async` backends include: ## -## * `none` - ``-d:asyncBackend=none`` - disable ``async`` support completely -## * `asyncdispatch -``-d:asyncBackend=asyncdispatch`` -## * `chronos ` - ``-d:asyncBackend=chronos`` +## * `-d:asyncBackend=none`: disable `async` support completely +## * `-d:asyncBackend=asyncdispatch`: https://nim-lang.org/docs/asyncdispatch.html +## * `-d:asyncBackend=chronos`: https://github.com/status-im/nim-chronos/ ## ## ``none`` can be used when a library supports both a synchronous and ## asynchronous API, to disable the latter. From b10f0e7bca43761316f6424786a771af33254e19 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 25 Apr 2022 02:20:18 +0800 Subject: [PATCH 3377/4254] fix db_sqlite.tryInsertID does raise exceptions in 1.6.0 #19743 (#19744) --- lib/impure/db_sqlite.nim | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 1638d38c6..db40dddd8 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -635,7 +635,7 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared): string proc tryInsertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 - {.tags: [WriteDbEffect], raises: [DbError].} = + {.tags: [WriteDbEffect], raises: [].} = ## Executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. ## @@ -650,16 +650,19 @@ proc tryInsertID*(db: DbConn, query: SqlQuery, ## 1, "item#1") == -1 ## db.close() assert(not db.isNil, "Database not connected.") - var q = dbFormat(query, args) - var stmt: sqlite3.PStmt result = -1 - if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: - if step(stmt) == SQLITE_DONE: - result = last_insert_rowid(db) - if finalize(stmt) != SQLITE_OK: - result = -1 - else: - discard finalize(stmt) + try: + var q = dbFormat(query, args) + var stmt: sqlite3.PStmt + if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: + if step(stmt) == SQLITE_DONE: + result = last_insert_rowid(db) + if finalize(stmt) != SQLITE_OK: + result = -1 + else: + discard finalize(stmt) + except DbError: + discard proc insertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect].} = @@ -692,7 +695,7 @@ proc insertID*(db: DbConn, query: SqlQuery, proc tryInsert*(db: DbConn, query: SqlQuery, pkName: string, args: varargs[string, `$`]): int64 - {.tags: [WriteDbEffect], raises: [DbError], since: (1, 3).} = + {.tags: [WriteDbEffect], raises: [], since: (1, 3).} = ## same as tryInsertID tryInsertID(db, query, args) From 8e6136dd59c737dab7c244e69f52864bd3fa65c9 Mon Sep 17 00:00:00 2001 From: tersec Date: Mon, 25 Apr 2022 09:06:53 +0000 Subject: [PATCH 3378/4254] document localPassC consistently with compiler; fix ANSI capitalization (#19721) --- doc/manual.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 8206d8342..adc1d9d16 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1370,7 +1370,7 @@ cstring type The `cstring` type meaning `compatible string` is the native representation of a string for the compilation backend. For the C backend the `cstring` type represents a pointer to a zero-terminated char array -compatible with the type `char*` in Ansi C. Its primary purpose lies in easy +compatible with the type `char*` in ANSI C. Its primary purpose lies in easy interfacing with C. The index operation `s[i]` means the i-th *char* of `s`; however no bounds checking for `cstring` is performed making the index operation unsafe. @@ -7218,16 +7218,16 @@ during semantic analysis: {.passc: gorge("pkg-config --cflags sdl").} -LocalPassc pragma +localPassC pragma ----------------- -The `localPassc` pragma can be used to pass additional parameters to the C +The `localPassC` pragma can be used to pass additional parameters to the C compiler, but only for the C/C++ file that is produced from the Nim module the pragma resides in: .. code-block:: Nim # Module A.nim # Produces: A.nim.cpp - {.localPassc: "-Wall -Werror".} # Passed when compiling A.nim.cpp + {.localPassC: "-Wall -Werror".} # Passed when compiling A.nim.cpp PassL pragma From efaa6777a464b94d88cb948390397b490ccee5b8 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 25 Apr 2022 17:07:55 +0800 Subject: [PATCH 3379/4254] fix #19435; don't create TypeBoundOps for tyOpenArray, tyVarargs [backport: 1.6] (#19723) * fix #19435; openArray wronyly registers typebounds * add testcase * don't create TypeBoundOps for tyOpenArray, tyVarargs --- compiler/sempass2.nim | 2 +- tests/arc/t19435.nim | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/arc/t19435.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 9bc811a03..0ee806f36 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1054,7 +1054,7 @@ proc track(tracked: PEffects, n: PNode) = addAsgnFact(tracked.guards, n[0], n[1]) notNilCheck(tracked, n[1], n[0].typ) when false: cstringCheck(tracked, n) - if tracked.owner.kind != skMacro: + if tracked.owner.kind != skMacro and n[0].typ.kind notin {tyOpenArray, tyVarargs}: createTypeBoundOps(tracked, n[0].typ, n.info) if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym): checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n[1]) diff --git a/tests/arc/t19435.nim b/tests/arc/t19435.nim new file mode 100644 index 000000000..519216bad --- /dev/null +++ b/tests/arc/t19435.nim @@ -0,0 +1,29 @@ +discard """ + matrix: "--gc:arc" +""" + +# bug #19435 +{.experimental: "views".} + +type + Bar = object + placeholder: int + Foo = object + placeholder: int + c: seq[Bar] # remove this line to make things right + +func children*(s: var seq[Foo]): openArray[Foo] = + s.toOpenArray(0, s.len-1) + +proc test = + var foos = @[Foo(), Foo()] + + assert foos.children.len == 2 + var flag = true + for a in foos.children: + flag = false + + if flag: + doAssert false + +test() \ No newline at end of file From 2f32b450d39030c287df4d56be9d06473772f5cd Mon Sep 17 00:00:00 2001 From: Danil Yarantsev Date: Mon, 25 Apr 2022 12:15:03 +0300 Subject: [PATCH 3380/4254] Really fix StringStream with ARC at compile-time, improve streams test (#19739) * Fix compile-time StringStream with ARC * make readDataStr work with ARC, improve test --- lib/pure/streams.nim | 10 ++++++++-- tests/stdlib/tstreams.nim | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 2ac6a82f1..f58273ee8 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -243,6 +243,9 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int = result = s.readDataStrImpl(s, buffer, slice) else: # fallback + when declared(prepareMutation): + # buffer might potentially be a CoW literal with ARC + prepareMutation(buffer) result = s.readData(addr buffer[slice.a], slice.b + 1 - slice.a) template jsOrVmBlock(caseJsOrVm, caseElse: untyped): untyped = @@ -1274,8 +1277,11 @@ else: # after 1.3 or JS not defined new(result) result.data = s - when declared(prepareMutation): - prepareMutation(result.data) # Allows us to mutate using `addr` logic like `copyMem`, otherwise it errors. + when nimvm: + discard + else: + when declared(prepareMutation): + prepareMutation(result.data) # Allows us to mutate using `addr` logic like `copyMem`, otherwise it errors. result.pos = 0 result.closeImpl = ssClose result.atEndImpl = ssAtEnd diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 6fda30f51..d9857926e 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--gc:refc; --gc:arc" input: "Arne" output: ''' Hello! What is your name? @@ -74,9 +75,13 @@ block: doAssert(ss.peekLine(str)) doAssert(str == "uick brown fox jumped over the lazy dog.") doAssert(ss.getPosition == 5) # haven't moved - ss.setPosition(0) # Ensure we dont error with writing over literals on arc/orc #19707 + # bug #19707 - Ensure we dont error with writing over literals on arc/orc + ss.setPosition(0) ss.write("hello") + ss.setPosition(0) + doAssert(ss.peekStr(5) == "hello") +# bug #19716 static: # Ensure streams it doesnt break with nimscript on arc/orc #19716 let s = newStringStream("a") - discard s.data + doAssert s.data == "a" From 465fd06d50d0dd2e65762b718ea9a726d94c110b Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 25 Apr 2022 17:18:26 +0800 Subject: [PATCH 3381/4254] add warnings for gc:option (#19722) --- compiler/commands.nim | 91 +++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 98537e9ef..bab98b376 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -527,6 +527,50 @@ proc unregisterArcOrc(conf: ConfigRef) = excl conf.globalOptions, optSeqDestructors excl conf.globalOptions, optTinyRtti +proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass, + info: TLineInfo; conf: ConfigRef) = + if conf.backend == backendJs: return # for: bug #16033 + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + case arg.normalize + of "boehm": + unregisterArcOrc(conf) + conf.selectedGC = gcBoehm + defineSymbol(conf.symbols, "boehmgc") + incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS + of "refc": + unregisterArcOrc(conf) + conf.selectedGC = gcRefc + of "markandsweep": + unregisterArcOrc(conf) + conf.selectedGC = gcMarkAndSweep + defineSymbol(conf.symbols, "gcmarkandsweep") + of "destructors", "arc": + registerArcOrc(pass, conf, false) + of "orc": + registerArcOrc(pass, conf, true) + of "hooks": + conf.selectedGC = gcHooks + defineSymbol(conf.symbols, "gchooks") + incl conf.globalOptions, optSeqDestructors + processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + of "go": + unregisterArcOrc(conf) + conf.selectedGC = gcGo + defineSymbol(conf.symbols, "gogc") + of "none": + unregisterArcOrc(conf) + conf.selectedGC = gcNone + defineSymbol(conf.symbols, "nogc") + of "stack", "regions": + unregisterArcOrc(conf) + conf.selectedGC = gcRegions + defineSymbol(conf.symbols, "gcregions") + of "v2": warningOptionNoop(arg) + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) + proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf: ConfigRef) = var @@ -626,48 +670,11 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info) of "project": processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) - of "gc", "mm": - if conf.backend == backendJs: return # for: bug #16033 - expectArg(conf, switch, arg, pass, info) - if pass in {passCmd2, passPP}: - case arg.normalize - of "boehm": - unregisterArcOrc(conf) - conf.selectedGC = gcBoehm - defineSymbol(conf.symbols, "boehmgc") - incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS - of "refc": - unregisterArcOrc(conf) - conf.selectedGC = gcRefc - of "markandsweep": - unregisterArcOrc(conf) - conf.selectedGC = gcMarkAndSweep - defineSymbol(conf.symbols, "gcmarkandsweep") - of "destructors", "arc": - registerArcOrc(pass, conf, false) - of "orc": - registerArcOrc(pass, conf, true) - of "hooks": - conf.selectedGC = gcHooks - defineSymbol(conf.symbols, "gchooks") - incl conf.globalOptions, optSeqDestructors - processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) - if pass in {passCmd2, passPP}: - defineSymbol(conf.symbols, "nimSeqsV2") - of "go": - unregisterArcOrc(conf) - conf.selectedGC = gcGo - defineSymbol(conf.symbols, "gogc") - of "none": - unregisterArcOrc(conf) - conf.selectedGC = gcNone - defineSymbol(conf.symbols, "nogc") - of "stack", "regions": - unregisterArcOrc(conf) - conf.selectedGC = gcRegions - defineSymbol(conf.symbols, "gcregions") - of "v2": warningOptionNoop(arg) - else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) + of "gc": + warningDeprecated(conf, info, "`gc:option` is deprecated; use `mm:option` instead") + processMemoryManagementOption(switch, arg, pass, info, conf) + of "mm": + processMemoryManagementOption(switch, arg, pass, info, conf) of "warnings", "w": if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) From 15ae9323e8f1e045bdd68e16231528f8c08fb611 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 25 Apr 2022 17:19:21 +0800 Subject: [PATCH 3382/4254] fix NimNode comment repr() regression [backport: 1.2] (#19726) --- compiler/renderer.nim | 2 ++ tests/macros/tmacros1.nim | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 3503c4bf6..f847aa094 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -165,6 +165,7 @@ proc putNL(g: var TSrcGen) = proc optNL(g: var TSrcGen, indent: int) = g.pendingNL = indent g.lineLen = indent + g.col = g.indent when defined(nimpretty): g.pendingNewlineCount = 0 proc optNL(g: var TSrcGen) = @@ -173,6 +174,7 @@ proc optNL(g: var TSrcGen) = proc optNL(g: var TSrcGen; a, b: PNode) = g.pendingNL = g.indent g.lineLen = g.indent + g.col = g.indent when defined(nimpretty): g.pendingNewlineCount = lineDiff(a, b) proc indentNL(g: var TSrcGen) = diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim index 53af4287c..c588ff7e6 100644 --- a/tests/macros/tmacros1.nim +++ b/tests/macros/tmacros1.nim @@ -60,3 +60,22 @@ macro foo(t: static Tuple): untyped = doAssert t.b == 12345 foo((a: "foo", b: 12345)) + + +# bug #16307 + +macro bug(x: untyped): string = + newLit repr(x) + +let res = bug: + block: + ## one + ## two + ## three + +doAssert res == """ + +block: + ## one + ## two + ## three""" From ee0a47029443e6d717ed4a85825b7dcf971dbdf8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 25 Apr 2022 11:59:37 +0200 Subject: [PATCH 3383/4254] Revert "fix db_sqlite.tryInsertID does raise exceptions in 1.6.0 #19743 (#19744)" (#19745) This reverts commit b10f0e7bca43761316f6424786a771af33254e19. --- lib/impure/db_sqlite.nim | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index db40dddd8..1638d38c6 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -635,7 +635,7 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared): string proc tryInsertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 - {.tags: [WriteDbEffect], raises: [].} = + {.tags: [WriteDbEffect], raises: [DbError].} = ## Executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. ## @@ -650,19 +650,16 @@ proc tryInsertID*(db: DbConn, query: SqlQuery, ## 1, "item#1") == -1 ## db.close() assert(not db.isNil, "Database not connected.") + var q = dbFormat(query, args) + var stmt: sqlite3.PStmt result = -1 - try: - var q = dbFormat(query, args) - var stmt: sqlite3.PStmt - if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: - if step(stmt) == SQLITE_DONE: - result = last_insert_rowid(db) - if finalize(stmt) != SQLITE_OK: - result = -1 - else: - discard finalize(stmt) - except DbError: - discard + if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: + if step(stmt) == SQLITE_DONE: + result = last_insert_rowid(db) + if finalize(stmt) != SQLITE_OK: + result = -1 + else: + discard finalize(stmt) proc insertID*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect].} = @@ -695,7 +692,7 @@ proc insertID*(db: DbConn, query: SqlQuery, proc tryInsert*(db: DbConn, query: SqlQuery, pkName: string, args: varargs[string, `$`]): int64 - {.tags: [WriteDbEffect], raises: [], since: (1, 3).} = + {.tags: [WriteDbEffect], raises: [DbError], since: (1, 3).} = ## same as tryInsertID tryInsertID(db, query, args) From 42ac50e988a4734624b204740613c795a0e789a3 Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 25 Apr 2022 18:00:23 +0800 Subject: [PATCH 3384/4254] fixes #19662; Indent level errored for first line (#19718) --- compiler/parser.nim | 4 ++++ compiler/passes.nim | 1 + compiler/syntaxes.nim | 2 +- tests/parser/t19662.nim | 6 ++++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/parser/t19662.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index 7973f7d37..52466d9fa 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -2393,6 +2393,10 @@ proc parseAll(p: var Parser): PNode = if p.tok.indent != 0: parMessage(p, errInvalidIndentation) +proc checkFirstLineIndentation*(p: var Parser) = + if p.tok.indent != 0 and p.tok.strongSpaceA > 0: + parMessage(p, errInvalidIndentation) + proc parseTopLevelStmt(p: var Parser): PNode = ## Implements an iterator which, when called repeatedly, returns the next ## top-level statement or emptyNode if end of stream. diff --git a/compiler/passes.nim b/compiler/passes.nim index ce52b10c5..7fb2842f5 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -150,6 +150,7 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; processImplicits graph, graph.config.implicitImports, nkImportStmt, a, module processImplicits graph, graph.config.implicitIncludes, nkIncludeStmt, a, module + checkFirstLineIndentation(p) while true: if graph.stopCompile(): break var n = parseTopLevelStmt(p) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index e47b0483d..c00fe8b67 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -16,7 +16,7 @@ import when defined(nimPreviewSlimSystem): import std/[syncio, assertions] -export Parser, parseAll, parseTopLevelStmt, closeParser +export Parser, parseAll, parseTopLevelStmt, checkFirstLineIndentation, closeParser type FilterKind = enum diff --git a/tests/parser/t19662.nim b/tests/parser/t19662.nim new file mode 100644 index 000000000..7a1864ac6 --- /dev/null +++ b/tests/parser/t19662.nim @@ -0,0 +1,6 @@ + var i: int # bug #19662 +echo i + +discard """ + errormsg: "invalid indentation" +""" \ No newline at end of file From 82680a12a7a6acfbb6f5fdd22c042e409081b812 Mon Sep 17 00:00:00 2001 From: ehmry Date: Mon, 25 Apr 2022 15:16:11 -0500 Subject: [PATCH 3385/4254] macros: make hasCustomPragma more permissive (#19747) Make hasCustomPragma return false rather than fail for invalid parameters. --- lib/core/macros.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index ba19712cf..b370aaa7b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1521,7 +1521,7 @@ proc extractTypeImpl(n: NimNode): NimNode = else: error("Invalid node to retrieve type implementation of: " & $n.kind) proc customPragmaNode(n: NimNode): NimNode = - expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkCheckedFieldExpr}) + expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkType, nnkCheckedFieldExpr}) let typ = n.getTypeInst() @@ -1532,7 +1532,9 @@ proc customPragmaNode(n: NimNode): NimNode = if kind(typ[1]) == nnkBracketExpr: typ[1][0] else: typ[1] ) - if impl[0].kind == nnkPragmaExpr: + if impl.kind == nnkNilLit: + return impl + elif impl[0].kind == nnkPragmaExpr: return impl[0][1] else: return impl[0] # handle types which don't have macro at all @@ -1560,7 +1562,7 @@ proc customPragmaNode(n: NimNode): NimNode = while typDef != nil: typDef.expectKind(nnkTypeDef) let typ = typDef[2].extractTypeImpl() - typ.expectKind({nnkRefTy, nnkPtrTy, nnkObjectTy}) + if typ.kind notin {nnkRefTy, nnkPtrTy, nnkObjectTy}: break let isRef = typ.kind in {nnkRefTy, nnkPtrTy} if isRef and typ[0].kind in {nnkSym, nnkBracketExpr}: # defines ref type for another object(e.g. X = ref X) typDef = getImpl(typ[0]) From ef4ac5a0d23fcffac9963670b73fa69ad0d0aa73 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 26 Apr 2022 08:58:15 +0200 Subject: [PATCH 3386/4254] use signed comparisons for the index checking in the hope it improves the code generation (#19712) --- compiler/ccgexprs.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1a3e217b2..5a58b4bcd 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -988,12 +988,12 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = if reifiedOpenArray(arr.lode): linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n", + "($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError(); $4}$n", [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) else: linefmt(p, cpsStmts, - "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n", + "if ($2-$1 != -1 && ($1 < 0 || $1 >= $3Len_0 || $2 < 0 || $2 >= $3Len_0))" & + "{ #raiseIndexError(); $4}$n", [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) of tyArray: let first = intLiteral(firstOrd(p.config, ty)) @@ -1004,7 +1004,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)){ #raiseIndexError(); $4}$n", + "($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError(); $4}$n", [rdLoc(a), rdLoc(b), lenExpr(p, arr), raiseInstr(p)]) else: discard @@ -1015,14 +1015,14 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = if not reifiedOpenArray(x): # emit range check: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", + linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2Len_0){ #raiseIndexError2($1,$2Len_0-1); $3}$n", [rdCharLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) else: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.Field1)){ #raiseIndexError2($1,$2.Field1-1); $3}$n", + linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2.Field1){ #raiseIndexError2($1,$2.Field1-1); $3}$n", [rdCharLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, @@ -1037,7 +1037,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: linefmt(p, cpsStmts, - "if ((NU)($1) >= (NU)$2){ #raiseIndexError2($1,$2-1); $3}$n", + "if ($1 < 0 || $1 >= $2){ #raiseIndexError2($1,$2-1); $3}$n", [rdCharLoc(b), lenExpr(p, a), raiseInstr(p)]) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: From 8bfc396a4dfa722239818f399a119452a53fe07f Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 27 Apr 2022 02:14:39 +0800 Subject: [PATCH 3387/4254] fixes #18612; apply cache and memcmp for methods in arc/orc (#19749) * try using endsWith * use memcmp * add cache * cleanup * better * minor * fix * improve test coverage for methods with ARC --- compiler/ccgexprs.nim | 7 +++++-- lib/system/arc.nim | 30 +++++++++++++++++++++++++++--- tests/metatype/ttypedesc3.nim | 3 ++- tests/method/tgeneric_methods.nim | 1 + tests/method/tmethod_issues.nim | 1 + tests/method/tmethod_various.nim | 1 + tests/method/tsingle_methods.nim | 2 +- tests/misc/parsecomb.nim | 4 ++++ tests/pragmas/tlocks.nim | 3 +++ 9 files changed, 45 insertions(+), 7 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 5a58b4bcd..8e7a21c67 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1615,8 +1615,11 @@ proc genNewFinalize(p: BProc, e: PNode) = proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = if optTinyRtti in p.config.globalOptions: - result = ropecg(p.module, "#isObj($1.m_type, $2)", - [a, genTypeInfo2Name(p.module, dest)]) + let ti = genTypeInfo2Name(p.module, dest) + inc p.module.labels + let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope + p.module.s[cfsVars].addf("static TNimTypeV2* $#[2];$n", [cache]) + result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) else: # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we # have to call it here first: diff --git a/lib/system/arc.nim b/lib/system/arc.nim index d66f4b997..17142b277 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -227,10 +227,34 @@ template tearDownForeignThreadGc* = ## With `--gc:arc` a nop. discard -proc isObj(obj: PNimTypeV2, subclass: cstring): bool {.compilerRtl, inl.} = - proc strstr(s, sub: cstring): cstring {.header: "", importc.} +type ObjCheckCache = array[0..1, PNimTypeV2] - result = strstr(obj.name, subclass) != nil +proc memcmp(str1, str2: cstring, n: csize_t): cint {.importc, header: "".} + +func endsWith(s, suffix: cstring): bool {.inline.} = + let + sLen = s.len + suffixLen = suffix.len + + if suffixLen <= sLen: + result = memcmp(cstring(addr s[sLen - suffixLen]), suffix, csize_t(suffixLen)) == 0 + +proc isObj(obj: PNimTypeV2, subclass: cstring): bool {.compilerRtl, inl.} = + result = endsWith(obj.name, subclass) + +proc isObjSlowPath(obj: PNimTypeV2, subclass: cstring, cache: var ObjCheckCache): bool {.compilerRtl, inline.} = + if endsWith(obj.name, subclass): + cache[1] = obj + result = true + else: + cache[0] = obj + result = false + +proc isObjWithCache(obj: PNimTypeV2, subclass: cstring, cache: var ObjCheckCache): bool {.compilerRtl.} = + if cache[0] == obj: result = false + elif cache[1] == obj: result = true + else: + result = isObjSlowPath(obj, subclass, cache) proc chckObj(obj: PNimTypeV2, subclass: cstring) {.compilerRtl.} = # checks if obj is of type subclass: diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim index 98a59f613..d3a58853d 100644 --- a/tests/metatype/ttypedesc3.nim +++ b/tests/metatype/ttypedesc3.nim @@ -1,5 +1,6 @@ discard """ -output: ''' + matrix: "--mm:arc; --mm:refc" + output: ''' proc Base proc Child method Base diff --git a/tests/method/tgeneric_methods.nim b/tests/method/tgeneric_methods.nim index 0e2aeeede..ab92c66d8 100644 --- a/tests/method/tgeneric_methods.nim +++ b/tests/method/tgeneric_methods.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:arc; --mm:refc" output: '''wow2 X 1 X 3''' diff --git a/tests/method/tmethod_issues.nim b/tests/method/tmethod_issues.nim index df4c3771a..13467f2b3 100644 --- a/tests/method/tmethod_issues.nim +++ b/tests/method/tmethod_issues.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:arc; --mm:refc" output: ''' wof! wof! diff --git a/tests/method/tmethod_various.nim b/tests/method/tmethod_various.nim index fd022717b..f9d067a72 100644 --- a/tests/method/tmethod_various.nim +++ b/tests/method/tmethod_various.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:arc; --mm:refc" output: ''' do nothing HELLO WORLD! diff --git a/tests/method/tsingle_methods.nim b/tests/method/tsingle_methods.nim index 40269559a..b564e7d87 100644 --- a/tests/method/tsingle_methods.nim +++ b/tests/method/tsingle_methods.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim c --multimethods:off $file" + matrix: "--mm:arc --multimethods:off; --mm:refc --multimethods:off" output: '''base base base diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim index 4ff2f65d2..4f149cbf6 100644 --- a/tests/misc/parsecomb.nim +++ b/tests/misc/parsecomb.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:arc; --mm:refc" +""" + type Input[T] = object toks: seq[T] index: int diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim index ba66a2dca..6c2a9f9e9 100644 --- a/tests/pragmas/tlocks.nim +++ b/tests/pragmas/tlocks.nim @@ -1,3 +1,6 @@ +discard """ + matrix: "--mm:arc; --mm:refc" +""" type SomeBase* = ref object of RootObj type SomeDerived* = ref object of SomeBase From e4a2c2d474f725b01acfa3a6169686f5e16f2ce9 Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Fri, 29 Apr 2022 12:16:07 +0300 Subject: [PATCH 3388/4254] Make sure that field usage preserves the original line info (#19751) Currently `struct.field` will generate a node with `info` that points to the symbol definition instead of having the actual node location. --- compiler/semexprs.nim | 2 ++ nimsuggest/tests/tuse_structure.nim | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 nimsuggest/tests/tuse_structure.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 702b47929..b8742ff65 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1436,8 +1436,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # is the access to a public field or in the same module or in a friend? markUsed(c, n[1].info, f) onUse(n[1].info, f) + let info = n[1].info n[0] = makeDeref(n[0]) n[1] = newSymNode(f) # we now have the correct field + n[1].info = info # preserve the original info n.typ = f.typ if check == nil: result = n diff --git a/nimsuggest/tests/tuse_structure.nim b/nimsuggest/tests/tuse_structure.nim new file mode 100644 index 000000000..f65ab9060 --- /dev/null +++ b/nimsuggest/tests/tuse_structure.nim @@ -0,0 +1,15 @@ +# tests for use and structures + +type + Foo* = ref object of RootObj + bar*: string + +proc test(f: Foo) = + echo f.#[!]#bar + +discard """ +$nimsuggest --tester $file +>use $1 +def skField tuse_structure.Foo.bar string $file 5 4 "" 100 +use skField tuse_structure.Foo.bar string $file 8 9 "" 100 +""" From 4680ab61c06782d142492d1fcdebf8e942373c09 Mon Sep 17 00:00:00 2001 From: nc-x Date: Sat, 30 Apr 2022 19:28:58 +0530 Subject: [PATCH 3389/4254] Fix fixAbstractType for user defined typeclasses, fixes #19730 & #18409 (#19732) --- compiler/semexprs.nim | 2 +- tests/concepts/t18409.nim | 37 +++++++++++++++++++++++++++++++++++++ tests/concepts/t19730.nim | 20 ++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/concepts/t18409.nim create mode 100644 tests/concepts/t19730.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b8742ff65..ed28d8145 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -645,7 +645,7 @@ proc fixAbstractType(c: PContext, n: PNode) = skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}: if skipTypes(it[1].typ, abstractVar).kind in {tyNil, tyTuple, tySet} or it[1].isArrayConstr: - var s = skipTypes(it.typ, abstractVar) + var s = skipTypes(it.typ, abstractVar + tyUserTypeClasses) if s.kind != tyUntyped: changeType(c, it[1], s, check=true) n[i] = it[1] diff --git a/tests/concepts/t18409.nim b/tests/concepts/t18409.nim new file mode 100644 index 000000000..0edba2d31 --- /dev/null +++ b/tests/concepts/t18409.nim @@ -0,0 +1,37 @@ +discard """ + action: "compile" +""" + +# A vector space over a field F concept. +type VectorSpace*[F] = concept x, y, type V + vector_add(x, y) is V + scalar_mul(x, F) is V + dimension(V) is Natural + +# Real numbers (here floats) form a vector space. +func vector_add*(v: float, w: float): float = v + w +func scalar_mul*(v: float, s: float): float = v * s +func dimension*(x: typedesc[float]): Natural = 1 + +# 2-tuples of real numbers form a vector space. +func vector_add*(v, w: (float, float)): (float, float) = + (vector_add(v[0], w[0]), vector_add(v[1], w[1])) + +func scalar_mul*(v: (float, float), s: float): (float, float) = + (scalar_mul(v[0], s), scalar_mul(v[1], s)) + +func dimension*(x: typedesc[(float, float)]): Natural = 2 + +# Check concept requirements. +assert float is VectorSpace +assert (float, float) is VectorSpace + +# Commutivity axiom for vector spaces over the same field. +func axiom_commutivity*[F](u, v: VectorSpace[F]): bool = + vector_add(u, v) == vector_add(v, u) + +# This is okay. +assert axiom_commutivity(2.2, 3.3) + +# This is not. +assert axiom_commutivity((2.2, 3.3), (4.4, 5.5)) diff --git a/tests/concepts/t19730.nim b/tests/concepts/t19730.nim new file mode 100644 index 000000000..575d45dda --- /dev/null +++ b/tests/concepts/t19730.nim @@ -0,0 +1,20 @@ +discard """ + output: '''1.01.01.01.0 +1.01.01.01.0 +''' +""" + +type + Color = concept c + c.r is SomeFloat + c.g is SomeFloat + c.b is SomeFloat + c.a is SomeFloat + +proc useColor(color: Color) = + echo(color.r, color.g, color.b, color.a) + +let color = (r: 1.0, g: 1.0, b: 1.0, a: 1.0) +useColor(color) + +useColor((r: 1.0, g: 1.0, b: 1.0, a: 1.0)) From 927978345bbf57631828287850eda13b82277eb7 Mon Sep 17 00:00:00 2001 From: huantian Date: Mon, 2 May 2022 09:06:57 -0700 Subject: [PATCH 3390/4254] Rework discarding futures documentation in asyncdispatch (#19738) * Rework discarding futures docs in asyncdispatch * Fix typos Co-authored-by: Danil Yarantsev * Use rst note:: Co-authored-by: flywind * Split discarding and handling futures. * Update lib/pure/asyncdispatch.nim * Update lib/pure/asyncdispatch.nim * Update lib/pure/asyncdispatch.nim * Update lib/pure/asyncdispatch.nim Co-authored-by: Danil Yarantsev Co-authored-by: flywind Co-authored-by: Dominik Picheta --- lib/pure/asyncdispatch.nim | 39 ++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index b1e1c19fd..755f59ff7 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -123,15 +123,42 @@ ## if future.failed: ## # Handle exception ## -## ## Discarding futures ## ================== ## -## Futures should **never** be discarded. This is because they may contain -## errors. If you do not care for the result of a Future then you should -## use the `asyncCheck` procedure instead of the `discard` keyword. Note -## however that this does not wait for completion, and you should use -## `waitFor` for that purpose. +## Futures should **never** be discarded directly because they may contain +## errors. If you do not care for the result of a Future then you should use +## the `asyncCheck` procedure instead of the `discard` keyword. Note that this +## does not wait for completion, and you should use `waitFor` or `await` for that purpose. +## +## .. note:: `await` also checks if the future fails, so you can safely discard +## its result. +## +## Handling futures +## ================ +## +## There are many different operations that apply to a future. +## The three primary high-level operations are `asyncCheck`, +## `waitFor`, and `await`. +## +## * `asyncCheck`: Raises an exception if the future fails. It neither waits +## for the future to finish nor returns the result of the future. +## * `waitFor`: Polls the event loop and blocks the current thread until the +## future finishes. This is often used to call an async procedure from a +## synchronous context and should never be used in an `async` proc. +## * `await`: Pauses execution in the current async procedure until the future +## finishes. While the current procedure is paused, other async procedures will +## continue running. Should be used instead of `waitFor` in an async +## procedure. +## +## Here is a handy quick reference chart showing their high-level differences: +## ============== ===================== ======================= +## Procedure Context Blocking +## ============== ===================== ======================= +## `asyncCheck` non-async and async non-blocking +## `waitFor` non-async blocks current thread +## `await` async suspends current proc +## ============== ===================== ======================= ## ## Examples ## ======== From 832b8c50345eab6e6f3d037d6e521831007cb6ed Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 3 May 2022 12:08:39 +1000 Subject: [PATCH 3391/4254] Fix link to experimental manual in macro pragmas section [skip ci] (#19753) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index adc1d9d16..a92d6e18f 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7814,7 +7814,7 @@ the same way. There are a few more applications of macro pragmas, such as in type, variable and constant declarations, but this behavior is considered to be experimental and is documented in the `experimental manual -` instead. +`_ instead. Foreign function interface From 2ecae20c437179ff84e255f952dae7000f7ff316 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 3 May 2022 18:35:16 +0800 Subject: [PATCH 3392/4254] switch to mainline bigints (#19756) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 6b0b15fd8..a55327211 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -39,7 +39,7 @@ pkg "arraymancer", "nim c tests/tests_cpu.nim" pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim", allowFailure = true pkg "asyncthreadpool" pkg "awk" -pkg "bigints", url = "https://github.com/Araq/nim-bigints" +pkg "bigints" pkg "binaryheap", "nim c -r binaryheap.nim" pkg "BipBuffer" pkg "blscurve", allowFailure = true # pending https://github.com/status-im/nim-blscurve/issues/39 From 278ecad973c6581aeea0a6ff9372109b0dd6df5e Mon Sep 17 00:00:00 2001 From: Zoom Date: Wed, 4 May 2022 14:24:52 +0000 Subject: [PATCH 3393/4254] Add 'usages' option to the --stylechecks error msg (#19759) --- compiler/commands.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index bab98b376..2e08ad615 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -116,7 +116,7 @@ const errInvalidCmdLineOption = "invalid command line option: '$1'" errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found" errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found" - errOffHintsError = "'off', 'hint' or 'error' expected, but '$1' found" + errOffHintsError = "'off', 'hint', 'error' or 'usages' expected, but '$1' found" proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) = if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-") @@ -508,7 +508,7 @@ proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) = else: conf.selectedGC = gcArc defineSymbol(conf.symbols, "gcarc") - + defineSymbol(conf.symbols, "gcdestructors") incl conf.globalOptions, optSeqDestructors incl conf.globalOptions, optTinyRtti From a4401054cc7fbd199a8dfa3ec0f9760ca7498b8e Mon Sep 17 00:00:00 2001 From: Anthony Dario Date: Fri, 6 May 2022 02:16:00 -0700 Subject: [PATCH 3394/4254] Fix broken link in sets documentation. (#19769) --- lib/pure/collections/sets.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 7b1c58ac8..114e4582a 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -61,7 +61,7 @@ type HashSet*[A] {.myShallow.} = object ## \ ## A generic hash set. ## - ## Use `init proc <#init,HashSet[A]>`_ or `initHashSet proc <#initHashSet,int>`_ + ## Use `init proc <#init,HashSet[A]>`_ or `initHashSet proc <#initHashSet>`_ ## before calling other procs on it. data: KeyValuePairSeq[A] counter: int From 0455d24d555e4f83537af535c0b2e44291d1fe97 Mon Sep 17 00:00:00 2001 From: Zoom Date: Fri, 6 May 2022 09:19:27 +0000 Subject: [PATCH 3395/4254] Fix questionable suggestion in `strutils` docs (#19765) * Fix questionable suggestion in `stutils` docs - Removes the recommendation to pass a string slice for getting a relative index for `find` and `rfind` functions, as this currently makes a string copy, while a simple subtraction is enough. - Docstring for `SkipTable` type. * Doc layout fixup --- lib/pure/strutils.nim | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index bf7bd6aa8..b98bd2bec 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -278,7 +278,7 @@ func nimIdentNormalize*(s: string): string = ## except first one. ## ## .. Warning:: Backticks (`) are not handled: they remain *as is* and - ## spaces are preserved. See `nimIdentBackticksNormalize + ## spaces are preserved. See `nimIdentBackticksNormalize ## `_ for ## an alternative approach. runnableExamples: @@ -1808,11 +1808,15 @@ func join*[T: not string](a: openArray[T], sep: string = ""): string = add(result, $x) type - SkipTable* = array[char, int] + SkipTable* = array[char, int] ## Character table for efficient substring search. func initSkipTable*(a: var SkipTable, sub: string) {.rtl, extern: "nsuInitSkipTable".} = - ## Preprocess table `a` for `sub`. + ## Initializes table `a` for efficient search of substring `sub`. + ## + ## See also: + ## * `find func<#find,SkipTable,string,string,Natural,int>`_ + # TODO: this should be the `default()` initializer for the type. let m = len(sub) fill(a, m) @@ -1826,6 +1830,9 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. ## element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. + ## + ## See also: + ## * `initSkipTable func<#initSkipTable,SkipTable,string>`_ let last = if last == 0: s.high else: last subLast = sub.len - 1 @@ -1865,7 +1872,7 @@ func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].rfind` for a `start`-origin index. + ## Subtract `start` from the result for a `start`-origin index. ## ## See also: ## * `rfind func<#rfind,string,char,Natural,int>`_ @@ -1893,7 +1900,7 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. ## ## If `s` contains none of the characters in `chars`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].find` for a `start`-origin index. + ## Subtract `start` from the result for a `start`-origin index. ## ## See also: ## * `rfind func<#rfind,string,set[char],Natural,int>`_ @@ -1910,7 +1917,7 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].find` for a `start`-origin index. + ## Subtract `start` from the result for a `start`-origin index. ## ## See also: ## * `rfind func<#rfind,string,string,Natural,int>`_ @@ -1950,7 +1957,7 @@ func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].find` for a `start`-origin index. + ## Subtract `start` from the result for a `start`-origin index. ## ## See also: ## * `find func<#find,string,char,Natural,int>`_ @@ -1968,7 +1975,7 @@ func rfind*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. ## ## If `s` contains none of the characters in `chars`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].rfind` for a `start`-origin index. + ## Subtract `start` from the result for a `start`-origin index. ## ## See also: ## * `find func<#find,string,set[char],Natural,int>`_ @@ -1986,7 +1993,7 @@ func rfind*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. - ## Use `s[start..last].rfind` for a `start`-origin index. + ## Subtract `start` from the result for a `start`-origin index. ## ## See also: ## * `find func<#find,string,string,Natural,int>`_ From 2c73e84436a11cae1676c7da0228158ba1a885cc Mon Sep 17 00:00:00 2001 From: kraptor Date: Sat, 7 May 2022 20:46:45 +0200 Subject: [PATCH 3396/4254] "ip" protocol as id 0 is long gone (#19760) IANA is using id 0 for "HOPOPT" instead of "ip" for some time now and those systems that still support the old mapping will stop doing so at some point in the future. Some BSDs and openSUSE are already following this change as per IANA list here: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml As new unixes (and maybe Windows, who knows) start to adopt the updated IANA list, this will keep failing from time to time, so it's better to remove the "ip" check altogether. --- tests/stdlib/tgetprotobyname.nim | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim index 0b60d059f..014c18845 100644 --- a/tests/stdlib/tgetprotobyname.nim +++ b/tests/stdlib/tgetprotobyname.nim @@ -1,9 +1,5 @@ import nativesockets -when not defined(netbsd): - # Ref: https://github.com/nim-lang/Nim/issues/15452 - NetBSD doesn't define an `ip` protocol - doAssert getProtoByName("ip") == 0 - doAssert getProtoByName("ipv6") == 41 doAssert getProtoByName("tcp") == 6 doAssert getProtoByName("udp") == 17 From 8c100a37b93607806acec51733fe5e2fda392d44 Mon Sep 17 00:00:00 2001 From: kraptor Date: Sun, 8 May 2022 11:54:04 +0200 Subject: [PATCH 3397/4254] Add new self-signed 4096 bit certificate to testdata (#19758) The test tasyncssl may fail on modern linux versions as they require at least 2048 bit certificates. A new certificate and private key with default values has been added to meet this new requirement. --- tests/testdata/mycert.pem | 105 ++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 28 deletions(-) diff --git a/tests/testdata/mycert.pem b/tests/testdata/mycert.pem index 69039fe04..61dcb685c 100644 --- a/tests/testdata/mycert.pem +++ b/tests/testdata/mycert.pem @@ -1,32 +1,81 @@ -----BEGIN PRIVATE KEY----- -MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL9QXX/nuiFbizdI -Uhg1D9gG0GIANENvKwdWTlOlZAoOqvjXPFLGh+87yhvkq4f5FcICkSDao2SfeZcP -JsgD7T01owt8x48898+d91i7nIpr6IXGPyBxHOuaxAITY1D+MbbkhIGUVrEqKEOm -qfS9cqPZaDNkx8xVef0HPCmqEme9AgMBAAECgYBxqrQCvJFQJG3QiL2N+GjTdyj0 -MR7cOf6cu2CKPifz+ccHVgpXO/Gj6Cgq7nAjt5B/1rqXhI+zxzSc1bm6+OpIfakS -E0DLCFacECmL0v3c+XLxTtMhFZF5u7Yq0UMsuWmDSfRb4sbRjC+s+c51i5N0485k -b3un/MDI/i/jD/YZGQJBAPLtcuMIwEblUR1uw7NFezXdauXCRFkekoSlJNvpdM/Z -XDRcuWioek5yD8FvMpTz7H2e26Ev645JT5lIuN4Eti8CQQDJm+Qt9NYUohRsU279 -GYI3vXsXKKqmA22at4I3KRXPSeYV1vtQLYWWqGAXzgGkUEVBY0chmHyDcNwkUsNw -svHTAkEAwOTpD/vX6bOXOD7GqKgoULozcqNScE2FXExhuzliJtTakT17f+4fyABs -IFWynXIevBUTIqeRbJcr3HRRTwIAwwJBAJQ8XkL4IaxcG/4mPpY0ek13sZiumwKj -xKQcx869E78tS9LFFlW2kuHafYUjQIvLRZC1aWinUO3oPsUqYW9s82cCQFjoods5 -YsWEJB2RKCT5nhyAXEZLehxF+FXr+JjLMHkuEINKTnHHKjHJ7LbMcTCKUJAcKDTA -qZFEq5N1aT6DrAU= +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDgpWhnNdNSUbwJ +39mKf+PA879K1wyT23LC3Ipo5g5vaRjB4vrSh5vzrjK5Q/z42yRDLQ2ojEdUne19 +1xMaM+WqTXnfkf9sou4VJ0HsdQ6jOU1LDRPrPvCjHLZjyMu18sGvQf4FATBwWN3n +QhmvcbleTeyv2pgMNeQDfjuIhRJ/aCIi/WYQ466+Rcj0y3/udYX1yPYf2mszXnSE +i2iWgdsjx0qkDU/nJhnKXhKfucAm9Ds0YfQdZYN3rEzfGkJzZUhDG1n30ghu+vUg +qqLi6HU/HqBxKxBlJf2HdMNK4VLkJuFC+wCI0JfF6VYhcNmtZzlQy3M9WjYvbXUY +nvMkQzUECaSaAtmbhFFfgey1Q3IEQS/j1lsVxtuGUE3YaoyaK22/CkVInDz0aka9 +CKq77x7S/V5PP/wwPV4s8XsbT6/34KemuY3oU84+bf5SBuWdzBY0hnDO9c/FaOnZ +4yjLMQi285HLpK417Z32DmzIkb7GjKtP9WLvsWGgbgquEjcFaIT+erkN09cDjsG/ +URWbKcsQkz8v9E4zj0rxdanXoJEtg1gm+dPsiXokZOLTeaMVtDoTkWeCM/VAp25J +MTc656QRUTSzUODK5tXQ3JgE2XIPGV/PsMi7T/q9xFBQmhUk5kfLNlQ1cy/aiTWK +8pjHcmxbyD121AimuTtv9CFYnYtzyQIDAQABAoICAAMYZFrfs/yzYZrlObMd1f6H +nUAjvGmhIXCr50BQwywnz46EWR5jffOal9pTpH2tT0+ZpFGJNUZmMqqENyAqTOTO +0noRIerWR9+EvfTLHBuFo5oAISEhqeEleSHg12W3ZZHLn/tjq84we0Y/c+kl8P7q +pfM6WNP6Ph0KNTnJU5rrzWScBzb+XB8FCSLOVwHrHqBnV3TS5p07lPFqllNUkLdq +fI3MHSi7LqnKKAmJXqtqvBIZs2pgRrJ0bk64pue+IoPCMbgnbbRRwuTjVQE5YLww +6NcGV+B86IRgSHyUpDa+jmYE3VoFPcIdV/F4A5fPD0wcsYbL4mk+4dkn/4OlZWqV +NZILp2IGejKaKtM1fr7fV2IRUbGUBN/+rX4I0SRnuq6Q4Ipx8VASbpgXQPBo9XTg +SHHsFbEu2DL8BHVgXdOy4PW6jQ0Ux2LhuJk6AQ5nIlFBYA+c8rSlZQXJbEbk1VZu +1i7iSOn/kx3ULMjUfhI/Ddm6rQqtiLbXSubXCzu1HMPT1FG9LUfAbq6EpiVkpAk1 +TqlciBHsyz//mk2RmIEx0Bt+0bX8FFGTIUiGyrp5s4hAHbgQZbXBAUYMRzWxhZ2Q +G0KBXx46bv3hJUb0GOgbNVxcaPnyrXaS/Hafcbx2LXlEtKiwGnC/yKJ7Hmcrt+AQ +RTaqNU1o/bkSYC7vHMZdAoIBAQD79uYPZPv5GLCKPZ64gc3+tbFXNqkmL7qv14yD +Gr3VubRbJe3Fx+T1cS+t9cjgOofhjFnwsDaFRoyWOYqRV/znwFsvvsDhHOLBr1u6 +qWQiF2CT1uMdXR3P6KD8h2DUVNNccxKqqIJNCR5oD/ngnnByWkQobzlsnoIdXgZm +ozBZjGr2XUMO5dJqUxaXZwY3j4I2hk/Ka9uroApyptl+DTVbPHvjk3MzU9QKUNor +vXEtQ8EmM8Oy6v/33HBmNs6cF5fMpgWz6u+B357OTxAfu8B42jZ18OeLrvkHFxzu +phOB1uXvqtQ0tdksSHHWj3IIZRK7GDGudnDEZ23vbCaxH4zbAoIBAQDkPn+5N3px +7UAECWrvT10TD3xKeqMkFhqRA9gmDE4N9AdoN6T6PzD7Tr3gOgGLq1tXjCjBqAlx +ZIDTnih3IK3xoRk2zmhq5+LfM8LQRAxAC8IsoQMXAsmW1KlS6MR70m50pFR8NK6r +UmOdrwVUKp3K6Mecid3LmMVLXGMUKwIJc1k7LJHtwrfi0i5xfBtiqQeaR0lJg4Zr ++zEL/4rHfcq06/P3k0+4uLKZ1LGOvwLPiTA3DADPWZbzUXo7McKOFWF/ycGQBrJq +AJikx15dVLnB16bnHXdxrlrd0LON2R+XfT4+dfRymqZLzrBI3L39t/elTmVYnD3P +punkmZuVwNErAoIBAQD5xOiOPibh6S2n/CmI8XQImIgx0kefSRUhFuV9WVbxtOMq +r9CijONUw1zmb40vahYk6gKGa8fAGg1nJadNKRHVkoNSMx/0h7PpGDIwOZa/jLj6 +FLyS8SmKXiqn6nN8SJI1RQUuE1kHkJCJy7yCg80oLn7+LjOYjxCgmAJ0YDSfsGif +zBebfws0xyTP9RrenO4RqtcR7BWYbk+tE+Tp5aIMzUpqcFJ0gRbjGv8K+QJmQpIH +kqzegcI4LFdnm9D4PxMFlVZ14eCGt+wuy4VKT84efwIZrDN77nmCI9FUaWFRBnxt +NsShc9rS4QWoEg6Sb88/lF47ecGTkIwUGPvJ/WKdAoIBAQClF7/zDPn4Zg+j29wJ +dXJxUwYoKUTP2V0l/43dF5Ft7lFdRMKEcCjR3kbhZZOwnyXW0X65dP4/kt7MMt46 +LN0kpc5DIlHM4iXsJNiJJG9n9BljhqNhhZajDvfbDJrypWdX33Vs0f511YZQjERi +eODh4DZiOCbCGaK7u/u+ns0+YLzuXHLBc9Lmsfj+BTMZzgG9ykpsbkJQ4MS9VP3h +BlAVRYaWUWucxZwKQRqdkfRKgYTqjDgZw0e4f/rVzkxX0YdQk3L65p0up3fB2KOd +BqfGWmJTUbEP/XmkcE0wERkUznazX0aNjucydjJ0wZZ7axIp8+bCjWD4TldoDuPH +Ek05AoIBAECgPfBHLQTAsI+wHbFsu/are28BOiJCSEXjRv88CbUbj/qgAppFuXbx +900WwJ1rVWd5x3LFa3VfyuAqYMi5jzmX9kWgEsC0WhgfyIRFiynw45LlcT4u3fWg +vJEx01lGgFVjnYfFUDS9d1MuiXGxIHrNhzHOP2x2CsS5vrFHav7iwG9YULEk8tJr +My0wzjF3UJ2/5DjGK56WuzauLYKrQ6Faw8dWUy4e/bNYId8wglhQQW548JwJEGmq +nq+EzTfEupXH57Bw7MGEOfdlhv98zNT9VcvBAN09vHeF3Hh6AM4aiGSUIt2HIkto +zvw+fqZ2Sk9O5qva+KE1QMVtY1EICI8= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICgDCCAemgAwIBAgIJANpVfZSDAyNgMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMjA2MDMxMjI4 -MDhaFw0xMzA2MDMxMjI4MDhaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l -LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAv1Bdf+e6 -IVuLN0hSGDUP2AbQYgA0Q28rB1ZOU6VkCg6q+Nc8UsaH7zvKG+Srh/kVwgKRINqj -ZJ95lw8myAPtPTWjC3zHjzz3z533WLucimvohcY/IHEc65rEAhNjUP4xtuSEgZRW -sSooQ6ap9L1yo9loM2THzFV5/Qc8KaoSZ70CAwEAAaNQME4wHQYDVR0OBBYEFF2n -Of61swO+XSNrYb4T02tGx8afMB8GA1UdIwQYMBaAFF2nOf61swO+XSNrYb4T02tG -x8afMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAEPHofdf4acaph5/e -+BzZGsMfRqdPgwp5sxjFKeTQI1A49VL7ykkb0iLKGfKZtvE8MjMrYjzt20E2bIZj -8eCivT6TbNrVRoACCly/lH9fZfWOG6dBu/85IrTAhSKi8yjbRzmjWUkdrcEJ+ZtV -1cahfFar4l4QwYgqp2pDd6ie+zE= +MIIFCTCCAvGgAwIBAgIUKqDcJ71wiMObIQ5sga2sZItNseowDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMDUwNDExMzAwN1oXDTIyMDYw +MzExMzAwN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4KVoZzXTUlG8Cd/Zin/jwPO/StcMk9tywtyKaOYOb2kY +weL60oeb864yuUP8+NskQy0NqIxHVJ3tfdcTGjPlqk1535H/bKLuFSdB7HUOozlN +Sw0T6z7woxy2Y8jLtfLBr0H+BQEwcFjd50IZr3G5Xk3sr9qYDDXkA347iIUSf2gi +Iv1mEOOuvkXI9Mt/7nWF9cj2H9prM150hItoloHbI8dKpA1P5yYZyl4Sn7nAJvQ7 +NGH0HWWDd6xM3xpCc2VIQxtZ99IIbvr1IKqi4uh1Px6gcSsQZSX9h3TDSuFS5Cbh +QvsAiNCXxelWIXDZrWc5UMtzPVo2L211GJ7zJEM1BAmkmgLZm4RRX4HstUNyBEEv +49ZbFcbbhlBN2GqMmittvwpFSJw89GpGvQiqu+8e0v1eTz/8MD1eLPF7G0+v9+Cn +prmN6FPOPm3+UgblncwWNIZwzvXPxWjp2eMoyzEItvORy6SuNe2d9g5syJG+xoyr +T/Vi77FhoG4KrhI3BWiE/nq5DdPXA47Bv1EVmynLEJM/L/ROM49K8XWp16CRLYNY +JvnT7Il6JGTi03mjFbQ6E5FngjP1QKduSTE3OuekEVE0s1DgyubV0NyYBNlyDxlf +z7DIu0/6vcRQUJoVJOZHyzZUNXMv2ok1ivKYx3JsW8g9dtQIprk7b/QhWJ2Lc8kC +AwEAAaNTMFEwHQYDVR0OBBYEFEZcUeqH6MfIzC56BlD3NSs2mCgGMB8GA1UdIwQY +MBaAFEZcUeqH6MfIzC56BlD3NSs2mCgGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggIBADGc7WONP6I6Trb7ici9fQ9qT3wh/RGDcmUDmDtARn9SFtOF +hsbszOMZg1Flj10fuD6OYDonKz4rv+Ieo5VkAYXxxd3J+bx2x1pqd1YSIsvugTwv +pnx39uBR9cjOmt4W7RyzhFnXoVfuSBE6LpkBUjcrqi5xwrQ31mOSCPwe8uDZYEWS +pX49MiHXGTyjQ481QLiOtTBZJa5igfnHUJbJbyZMa86zBQ/clS7+OeDwkvaEpjov +2VQf3QouVLghfLZYWSxWdEKD9+IWHn8rV6qksEb/Ogu4ZtzDRGqJow4j0DeSSEu7 +ns1YeT2mVTFwHjGXCWS+0iE885NDVX/b5YptlwH5PW7aqeXyCS9Hrd1C1GnXoXGp +NHltYRTyNWm974xWg7eu2gbbB8Ng02chXysdkBq7l+7OyA0a2EfX3Cbz3/49+Mqn +viqwNO5toSHVCdfV9Jd0p0CcqryYgyt2YNpJB+2nUQpiW4jviAs49PZg2PpCVw/2 +0cqtaPeUh26Si8UzDOuT697PIuGkZ9Q9QVwccVXtCyA0UpJ13P0fMrA+yEMhtwSs +k1tRm0pUQa6t3v26/cAy+kMhviHBJFwi5dx+y3OMvqQqpQJrgfZawm/o2ZQHy1KP +8m4ngrJzb13evKf216qCwllmQo6Ts4yeI1Ddx8UpdX7RUWpD8Uw4zSi7Th4r -----END CERTIFICATE----- From 61c1142667fabec11a7440b0404ce5688cad54d2 Mon Sep 17 00:00:00 2001 From: huantian Date: Sun, 8 May 2022 02:54:25 -0700 Subject: [PATCH 3398/4254] Update nimscript `withDir` doc example (#19776) --- lib/system/nimscript.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 5d1916c7f..0b49ea2e7 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -342,17 +342,17 @@ template withDir*(dir: string; body: untyped): untyped = ## Usage example: ## ## .. code-block:: nim + ## # inside /some/path/ ## withDir "foo": - ## # inside foo - ## #back to last dir - var curDir = getCurrentDir() + ## # move to /some/path/foo/ + ## # back in /some/path/ + let curDir = getCurrentDir() try: cd(dir) body finally: cd(curDir) - proc writeTask(name, desc: string) = if desc.len > 0: var spaces = " " From b2b878f4d62ff2dcaf69979bb0f96e6015b47605 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 8 May 2022 06:56:46 -0300 Subject: [PATCH 3399/4254] Remove deprecated posix proc (#19774) * Remove deprecated posix proc that takes wrong argument types * Remove deprecated posix proc that takes wrong argument types --- changelog.md | 2 +- lib/posix/posix.nim | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 8b9d0bc29..3b2685547 100644 --- a/changelog.md +++ b/changelog.md @@ -47,7 +47,7 @@ becomes an alias for `addr`. - Removed deprecated `math.c_frexp`. - Removed deprecated ``` httpcore.`==` ```. - Removed deprecated `std/dom_extensions`. - +- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. - Remove deprecated `osproc.poDemon`, symbol with typo. - Deprecated `selfExe` for Nimscript. diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 146ba886f..4ebae4361 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -894,19 +894,9 @@ proc CMSG_NXTHDR*(mhdr: ptr Tmsghdr, cmsg: ptr Tcmsghdr): ptr Tcmsghdr {. proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {. importc, header: "".} -{.push warning[deprecated]: off.} -proc CMSG_SPACE*(len: csize): csize {. - importc, header: "", deprecated: "argument `len` should be of type `csize_t`".} -{.pop.} - proc CMSG_SPACE*(len: csize_t): csize_t {. importc, header: "".} -{.push warning[deprecated]: off.} -proc CMSG_LEN*(len: csize): csize {. - importc, header: "", deprecated: "argument `len` should be of type `csize_t`".} -{.pop.} - proc CMSG_LEN*(len: csize_t): csize_t {. importc, header: "".} From 85bc8326acc9bf18e748055e770a40890e7ac069 Mon Sep 17 00:00:00 2001 From: Alfred Morgan Date: Tue, 10 May 2022 05:21:35 -0700 Subject: [PATCH 3400/4254] varargs example erroneously transformed "abc" to "def" (#19781) --- doc/manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index a92d6e18f..126b0f0d6 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1556,7 +1556,7 @@ type conversions in this context: myWriteln(stdout, 123, "abc", 4.0) # is transformed to: - myWriteln(stdout, [$123, $"def", $4.0]) + myWriteln(stdout, [$123, $"abc", $4.0]) In this example `$` is applied to any argument that is passed to the parameter `a`. (Note that `$` applied to strings is a nop.) From b9f243eb2aeb4930ba552f8bf487719d628f4a2a Mon Sep 17 00:00:00 2001 From: Alfred Morgan Date: Tue, 10 May 2022 08:45:57 -0700 Subject: [PATCH 3401/4254] string is missing formatting when calling fmt (#19780) it appears the documentation intends to compare & with .fmt but there is no formatting in the string. even though the assert is true it doesn't quite prove that .fmt is an equivalent formatter. --- lib/pure/strformat.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index ce3439600..247d0a296 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -705,6 +705,6 @@ macro `&`*(pattern: string{lit}): string = runnableExamples: let x = 7 assert &"{x}\n" == "7\n" # regular string literal - assert &"{x}\n" == "7\n".fmt # `fmt` can be used instead - assert &"{x}\n" != fmt"7\n" # see `fmt` docs, this would use a raw string literal + assert &"{x}\n" == "{x}\n".fmt # `fmt` can be used instead + assert &"{x}\n" != fmt"{x}\n" # see `fmt` docs, this would use a raw string literal strformatImpl(pattern.strVal, '{', '}') From c61eb5df32c66431d0d08417c39e268fdf236132 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 13 May 2022 01:03:30 +0800 Subject: [PATCH 3402/4254] disable polypbren (#19787) * disable polypbren * Update important_packages.nim --- testament/important_packages.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index a55327211..c8fb5ad3c 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -103,7 +103,7 @@ pkg "nimfp", "nim c -o:nfp -r src/fp.nim" pkg "nimgame2", "nim c nimgame2/nimgame.nim" # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" -pkg "nimlsp", allowFailure = true +pkg "nimlsp" pkg "nimly", "nim c -r tests/test_readme_example.nim" pkg "nimongo", "nimble test_ci", allowFailure = true pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true @@ -125,7 +125,7 @@ pkg "patty" pkg "pixie" pkg "plotly", "nim c examples/all.nim" pkg "pnm" -pkg "polypbren" +pkg "polypbren", allowFailure = true pkg "prologue", "nimble tcompile" pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim" pkg "pylib" From 19001c070bbe7645ff45fcbd66ab221235715302 Mon Sep 17 00:00:00 2001 From: Anthony Dario Date: Thu, 12 May 2022 20:19:42 -0700 Subject: [PATCH 3403/4254] Fix typo in sequtils documentation (#19789) Found another small typo. --- lib/pure/collections/sequtils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 5e9b492c2..39908e9c1 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -914,7 +914,7 @@ template foldl*(sequence, operation, first): untyped = ## ## The `operation` parameter should be an expression which uses the variables ## `a` and `b` for each step of the fold. The `first` parameter is the - ## start value (the first `a`) and therefor defines the type of the result. + ## start value (the first `a`) and therefore defines the type of the result. ## ## **See also:** ## * `foldr template<#foldr.t,untyped,untyped>`_ From 33888a73840a7f9fa46f79e613d488de2d193916 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 17 May 2022 13:37:26 +0800 Subject: [PATCH 3404/4254] [manual] TLock => Lock (#19785) * [manual] TLock => Lock * minor --- doc/manual.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 126b0f0d6..bfcb41b7a 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -8112,7 +8112,9 @@ Object fields and global variables can be annotated via a `guard` pragma: .. code-block:: nim - var glock: TLock + import std/locks + + var glock: Lock var gdata {.guard: glock.}: int The compiler then ensures that every access of `gdata` is within a `locks` @@ -8139,7 +8141,7 @@ that also implement some form of locking at runtime: .. code-block:: nim - template lock(a: TLock; body: untyped) = + template lock(a: Lock; body: untyped) = pthread_mutex_lock(a) {.locks: [a].}: try: @@ -8181,10 +8183,12 @@ the expressivity of the language: .. code-block:: nim + import std/locks + type ProtectedCounter = object v {.guard: L.}: int - L: TLock + L: Lock proc incCounters(counters: var openArray[ProtectedCounter]) = for i in 0..counters.high: From 06f02bb7716066241b04b2a92a3a61f539eadff2 Mon Sep 17 00:00:00 2001 From: Yardanico Date: Tue, 17 May 2022 10:56:39 +0300 Subject: [PATCH 3405/4254] Always use httpclient in nimgrab (#19767) --- tools/nimgrab.nim | 37 +--- tools/urldownloader.nim | 431 ---------------------------------------- 2 files changed, 9 insertions(+), 459 deletions(-) delete mode 100644 tools/urldownloader.nim diff --git a/tools/nimgrab.nim b/tools/nimgrab.nim index ee5eced1e..7e4161faf 100644 --- a/tools/nimgrab.nim +++ b/tools/nimgrab.nim @@ -1,33 +1,14 @@ +import std/[os, httpclient] +proc syncDownload(url, file: string) = + var client = newHttpClient() + proc onProgressChanged(total, progress, speed: BiggestInt) = + echo "Downloading " & url & " " & $(speed div 1000) & "kb/s" + echo clamp(int(progress*100 div total), 0, 100), "%" -when defined(windows): - import os, urldownloader - - proc syncDownload(url, file: string) = - proc progress(status: DownloadStatus, progress: uint, total: uint, - message: string) {.gcsafe.} = - echo "Downloading " & url - let t = total.BiggestInt - if t != 0: - echo clamp(int(progress.BiggestInt*100 div t), 0, 100), "%" - else: - echo "0%" - - downloadToFile(url, file, {optUseCache}, progress) - echo "100%" - -else: - import os, asyncdispatch, httpclient - - proc syncDownload(url, file: string) = - var client = newHttpClient() - proc onProgressChanged(total, progress, speed: BiggestInt) = - echo "Downloading " & url & " " & $(speed div 1000) & "kb/s" - echo clamp(int(progress*100 div total), 0, 100), "%" - - client.onProgressChanged = onProgressChanged - client.downloadFile(url, file) - echo "100%" + client.onProgressChanged = onProgressChanged + client.downloadFile(url, file) + echo "100%" if os.paramCount() != 2: quit "Usage: nimgrab " diff --git a/tools/urldownloader.nim b/tools/urldownloader.nim deleted file mode 100644 index 73e4034c9..000000000 --- a/tools/urldownloader.nim +++ /dev/null @@ -1,431 +0,0 @@ - -# -# -# Windows native FTP/HTTP/HTTPS file downloader -# (c) Copyright 2017 Eugene Kabanov -# -# See the file "LICENSE", included in this -# distribution, for details about the copyright. -# - -## This module implements native Windows FTP/HTTP/HTTPS downloading feature, -## using ``urlmon.UrlDownloadToFile()``. -## -## - -when not (defined(windows) or defined(nimdoc)): - {.error: "Platform is not supported.".} - -import os - -type - DownloadOptions* = enum - ## Available download options - optUseCache, ## Use Windows cache. - optUseProgressCallback, ## Report progress via callback. - optIgnoreSecurity ## Ignore HTTPS security problems. - - DownloadStatus* = enum - ## Available download status sent to ``progress`` callback. - statusProxyDetecting, ## Automatic Proxy detection. - statusCookieSent ## Cookie will be sent with request. - statusResolving, ## Resolving URL with DNS. - statusConnecting, ## Establish connection to server. - statusRedirecting ## HTTP redirection pending. - statusRequesting, ## Sending request to server. - statusMimetypeAvailable, ## Mimetype received from server. - statusBeginDownloading, ## Download process starting. - statusDownloading, ## Download process pending. - statusEndDownloading, ## Download process finished. - statusCacheAvailable ## File found in Windows cache. - statusUnsupported ## Unsupported status. - statusError ## Error happens. - - DownloadProgressCallback* = proc(status: DownloadStatus, progress: uint, - progressMax: uint, - message: string) - ## Progress callback. - ## - ## status - ## Indicate current stage of downloading process. - ## - ## progress - ## Number of bytes currently downloaded. Available only, if ``status`` is - ## ``statusBeginDownloading``, ``statusDownloading`` or - ## ``statusEndDownloading``. - ## - ## progressMax - ## Number of bytes expected to download. Available only, if ``status`` is - ## ``statusBeginDownloading``, ``statusDownloading`` or - ## ``statusEndDownloading``. - ## - ## message - ## Status message, which depends on ``status`` code. - ## - ## Available messages' values: - ## - ## statusResolving - ## URL hostname to be resolved. - ## statusConnecting - ## IP address - ## statusMimetypeAvailable - ## Downloading resource MIME type. - ## statusCacheAvailable - ## Path to filename stored in Windows cache. - -type - UUID = array[4, uint32] - - LONG = clong - ULONG = culong - HRESULT = clong - DWORD = uint32 - OLECHAR = uint16 - OLESTR = ptr OLECHAR - LPWSTR = OLESTR - UINT = cuint - REFIID = ptr UUID - -const - E_NOINTERFACE = 0x80004002'i32 - E_NOTIMPL = 0x80004001'i32 - S_OK = 0x00000000'i32 - - CP_UTF8 = 65001'u32 - - IID_IUnknown = UUID([0'u32, 0'u32, 192'u32, 1174405120'u32]) - IID_IBindStatusCallback = UUID([2045430209'u32, 298760953'u32, - 2852160140'u32, 195644160'u32]) - - BINDF_GETNEWESTVERSION = 0x00000010'u32 - BINDF_IGNORESECURITYPROBLEM = 0x00000100'u32 - BINDF_RESYNCHRONIZE = 0x00000200'u32 - BINDF_NO_UI = 0x00000800'u32 - BINDF_SILENTOPERATION = 0x00001000'u32 - BINDF_PRAGMA_NO_CACHE = 0x00002000'u32 - - ERROR_FILE_NOT_FOUND = 2 - ERROR_ACCESS_DENIED = 5 - - BINDSTATUS_FINDINGRESOURCE = 1 - BINDSTATUS_CONNECTING = 2 - BINDSTATUS_REDIRECTING = 3 - BINDSTATUS_BEGINDOWNLOADDATA = 4 - BINDSTATUS_DOWNLOADINGDATA = 5 - BINDSTATUS_ENDDOWNLOADDATA = 6 - BINDSTATUS_SENDINGREQUEST = 11 - BINDSTATUS_MIMETYPEAVAILABLE = 13 - BINDSTATUS_CACHEFILENAMEAVAILABLE = 14 - BINDSTATUS_PROXYDETECTING = 32 - BINDSTATUS_COOKIE_SENT = 34 - -type - STGMEDIUM = object - tymed: DWORD - pstg: pointer - pUnkForRelease: pointer - - SECURITY_ATTRIBUTES = object - nLength*: uint32 - lpSecurityDescriptor*: pointer - bInheritHandle*: int32 - - BINDINFO = object - cbSize: ULONG - stgmedData: STGMEDIUM - szExtraInfo: LPWSTR - grfBindInfoF: DWORD - dwBindVerb: DWORD - szCustomVerb: LPWSTR - cbstgmedData: DWORD - dwOptions: DWORD - dwOptionsFlags: DWORD - dwCodePage: DWORD - securityAttributes: SECURITY_ATTRIBUTES - iid: UUID - pUnk: pointer - dwReserved: DWORD - - IBindStatusCallback = object - vtable: ptr IBindStatusCallbackVTable - options: set[DownloadOptions] - objectRefCount: ULONG - binfoFlags: DWORD - progressCallback: DownloadProgressCallback - - PIBindStatusCallback = ptr IBindStatusCallback - LPBINDSTATUSCALLBACK = PIBindStatusCallback - - IBindStatusCallbackVTable = object - QueryInterface: proc (self: PIBindStatusCallback, - riid: ptr UUID, - pvObject: ptr pointer): HRESULT {.gcsafe,stdcall.} - AddRef: proc(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} - Release: proc(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} - OnStartBinding: proc(self: PIBindStatusCallback, - dwReserved: DWORD, pib: pointer): HRESULT - {.gcsafe, stdcall.} - GetPriority: proc(self: PIBindStatusCallback, pnPriority: ptr LONG): HRESULT - {.gcsafe, stdcall.} - OnLowResource: proc(self: PIBindStatusCallback, dwReserved: DWORD): HRESULT - {.gcsafe, stdcall.} - OnProgress: proc(self: PIBindStatusCallback, ulProgress: ULONG, - ulProgressMax: ULONG, ulStatusCode: ULONG, - szStatusText: LPWSTR): HRESULT - {.gcsafe, stdcall.} - OnStopBinding: proc(self: PIBindStatusCallback, hresult: HRESULT, - szError: LPWSTR): HRESULT - {.gcsafe, stdcall.} - GetBindInfo: proc(self: PIBindStatusCallback, grfBINDF: ptr DWORD, - pbindinfo: ptr BINDINFO): HRESULT - {.gcsafe, stdcall.} - OnDataAvailable: proc(self: PIBindStatusCallback, grfBSCF: DWORD, - dwSize: DWORD, pformatetc: pointer, - pstgmed: pointer): HRESULT - {.gcsafe, stdcall.} - OnObjectAvailable: proc(self: PIBindStatusCallback, riid: REFIID, - punk: pointer): HRESULT - {.gcsafe, stdcall.} - -template FAILED(hr: HRESULT): bool = - (hr < 0) - -proc URLDownloadToFile(pCaller: pointer, szUrl: LPWSTR, szFileName: LPWSTR, - dwReserved: DWORD, - lpfnCb: LPBINDSTATUSCALLBACK): HRESULT - {.stdcall, dynlib: "urlmon.dll", importc: "URLDownloadToFileW".} - -proc WideCharToMultiByte(CodePage: UINT, dwFlags: DWORD, - lpWideCharStr: ptr OLECHAR, cchWideChar: cint, - lpMultiByteStr: ptr char, cbMultiByte: cint, - lpDefaultChar: ptr char, - lpUsedDefaultChar: ptr uint32): cint - {.stdcall, dynlib: "kernel32.dll", importc: "WideCharToMultiByte".} - -proc MultiByteToWideChar(CodePage: UINT, dwFlags: DWORD, - lpMultiByteStr: ptr char, cbMultiByte: cint, - lpWideCharStr: ptr OLECHAR, cchWideChar: cint): cint - {.stdcall, dynlib: "kernel32.dll", importc: "MultiByteToWideChar".} -proc DeleteUrlCacheEntry(lpszUrlName: LPWSTR): int32 - {.stdcall, dynlib: "wininet.dll", importc: "DeleteUrlCacheEntryW".} - -proc `==`(a, b: UUID): bool = - result = false - if a[0] == b[0] and a[1] == b[1] and - a[2] == b[2] and a[3] == b[3]: - result = true - -proc `$`(bstr: LPWSTR): string = - var buffer: char - var count = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(buffer), 0, - nil, nil) - if count == 0: - raiseOsError(osLastError()) - else: - result = newString(count + 8) - let res = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(result[0]), count, - nil, nil) - if res == 0: - raiseOsError(osLastError()) - result.setLen(res - 1) - -proc toBstring(str: string): LPWSTR = - var buffer: OLECHAR - var count = MultiByteToWideChar(CP_UTF8, 0, unsafeAddr(str[0]), -1, - addr(buffer), 0) - if count == 0: - raiseOsError(osLastError()) - else: - result = cast[LPWSTR](alloc0((count + 1) * sizeof(OLECHAR))) - let res = MultiByteToWideChar(CP_UTF8, 0, unsafeAddr(str[0]), -1, - result, count) - if res == 0: - raiseOsError(osLastError()) - -proc freeBstring(bstr: LPWSTR) = - dealloc(bstr) - -proc getStatus(scode: ULONG): DownloadStatus = - case scode - of 0: result = statusError - of BINDSTATUS_PROXYDETECTING: result = statusProxyDetecting - of BINDSTATUS_REDIRECTING: result = statusRedirecting - of BINDSTATUS_COOKIE_SENT: result = statusCookieSent - of BINDSTATUS_FINDINGRESOURCE: result = statusResolving - of BINDSTATUS_CONNECTING: result = statusConnecting - of BINDSTATUS_SENDINGREQUEST: result = statusRequesting - of BINDSTATUS_MIMETYPEAVAILABLE: result = statusMimetypeAvailable - of BINDSTATUS_BEGINDOWNLOADDATA: result = statusBeginDownloading - of BINDSTATUS_DOWNLOADINGDATA: result = statusDownloading - of BINDSTATUS_ENDDOWNLOADDATA: result = statusEndDownloading - of BINDSTATUS_CACHEFILENAMEAVAILABLE: result = statusCacheAvailable - else: result = statusUnsupported - -proc addRef(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} = - inc(self.objectRefCount) - result = self.objectRefCount - -proc release(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} = - dec(self.objectRefCount) - result = self.objectRefCount - -proc queryInterface(self: PIBindStatusCallback, riid: ptr UUID, - pvObject: ptr pointer): HRESULT {.gcsafe,stdcall.} = - pvObject[] = nil - - if riid[] == IID_IUnknown: - pvObject[] = cast[pointer](self) - elif riid[] == IID_IBindStatusCallback: - pvObject[] = cast[pointer](self) - - if not isNil(pvObject[]): - discard addRef(self) - result = S_OK - else: - result = E_NOINTERFACE - -proc onStartBinding(self: PIBindStatusCallback, dwReserved: DWORD, - pib: pointer): HRESULT {.gcsafe, stdcall.} = - result = S_OK - -proc getPriority(self: PIBindStatusCallback, - pnPriority: ptr LONG): HRESULT {.gcsafe, stdcall.} = - result = E_NOTIMPL - -proc onLowResource(self: PIBindStatusCallback, - dwReserved: DWORD): HRESULT {.gcsafe, stdcall.} = - result = S_OK - -proc onStopBinding(self: PIBindStatusCallback, - hresult: HRESULT, szError: LPWSTR): HRESULT - {.gcsafe, stdcall.} = - result = S_OK - -proc getBindInfo(self: PIBindStatusCallback, - grfBINDF: ptr DWORD, pbindinfo: ptr BINDINFO): HRESULT - {.gcsafe, stdcall.} = - var cbSize = pbindinfo.cbSize - zeroMem(cast[pointer](pbindinfo), cbSize) - pbindinfo.cbSize = cbSize - grfBINDF[] = self.binfoFlags - result = S_OK - -proc onDataAvailable(self: PIBindStatusCallback, - grfBSCF: DWORD, dwSize: DWORD, pformatetc: pointer, - pstgmed: pointer): HRESULT {.gcsafe, stdcall.} = - result = S_OK - -proc onObjectAvailable(self: PIBindStatusCallback, - riid: REFIID, punk: pointer): HRESULT - {.gcsafe, stdcall.} = - result = S_OK - -proc onProgress(self: PIBindStatusCallback, - ulProgress: ULONG, ulProgressMax: ULONG, ulStatusCode: ULONG, - szStatusText: LPWSTR): HRESULT {.gcsafe, stdcall.} = - var message: string - if optUseProgressCallback in self.options: - if not isNil(szStatusText): - message = $szStatusText - else: - message = "" - self.progressCallback(getStatus(ulStatusCode), uint(ulProgress), - uint(ulProgressMax), message) - result = S_OK - -proc newBindStatusCallback(): IBindStatusCallback = - result = IBindStatusCallback() - result.vtable = cast[ptr IBindStatusCallbackVTable]( - alloc0(sizeof(IBindStatusCallbackVTable)) - ) - result.vtable.QueryInterface = queryInterface - result.vtable.AddRef = addRef - result.vtable.Release = release - result.vtable.OnStartBinding = onStartBinding - result.vtable.GetPriority = getPriority - result.vtable.OnLowResource = onLowResource - result.vtable.OnStopBinding = onStopBinding - result.vtable.GetBindInfo = getBindInfo - result.vtable.OnDataAvailable = onDataAvailable - result.vtable.OnObjectAvailable = onObjectAvailable - result.vtable.OnProgress = onProgress - result.objectRefCount = 1 - -proc freeBindStatusCallback(v: var IBindStatusCallback) = - dealloc(v.vtable) - -proc downloadToFile*(szUrl: string, szFileName: string, - options: set[DownloadOptions] = {}, - progresscb: DownloadProgressCallback = nil) = - ## Downloads from URL specified in ``szUrl`` to local filesystem path - ## specified in ``szFileName``. - ## - ## szUrl - ## URL to download, international names are supported. - ## szFileName - ## Destination path for downloading resource. - ## options - ## Downloading options. Currently only 2 options supported. - ## progresscb - ## Callback procedure, which will be called throughout the download - ## process, indicating status and progress. - ## - ## Available downloading options: - ## - ## optUseCache - ## Try to use Windows cache when downloading. - ## optIgnoreSecurity - ## Ignore HTTPS security problems, e.g. self-signed HTTPS certificate. - ## - var bszUrl = szUrl.toBstring() - var bszFile = szFileName.toBstring() - var bstatus = newBindStatusCallback() - - bstatus.options = {} - - if optUseCache notin options: - bstatus.options.incl(optUseCache) - let res = DeleteUrlCacheEntry(bszUrl) - if res == 0: - let err = osLastError() - if err.int notin {ERROR_ACCESS_DENIED, ERROR_FILE_NOT_FOUND}: - freeBindStatusCallback(bstatus) - freeBstring(bszUrl) - freeBstring(bszFile) - raiseOsError(err) - - bstatus.binfoFlags = BINDF_GETNEWESTVERSION or BINDF_RESYNCHRONIZE or - BINDF_PRAGMA_NO_CACHE or BINDF_NO_UI or - BINDF_SILENTOPERATION - - if optIgnoreSecurity in options: - bstatus.binfoFlags = bstatus.binfoFlags or BINDF_IGNORESECURITYPROBLEM - - if not isNil(progresscb): - bstatus.options.incl(optUseProgressCallback) - bstatus.progressCallback = progresscb - - let res = URLDownloadToFile(nil, bszUrl, bszFile, 0, addr bstatus) - if FAILED(res): - freeBindStatusCallback(bstatus) - freeBstring(bszUrl) - freeBstring(bszFile) - raiseOsError(OSErrorCode(res)) - - freeBindStatusCallback(bstatus) - freeBstring(bszUrl) - freeBstring(bszFile) - -when isMainModule: - proc progress(status: DownloadStatus, progress: uint, progressMax: uint, - message: string) {.gcsafe.} = - const downset: set[DownloadStatus] = {statusBeginDownloading, - statusDownloading, statusEndDownloading} - if status in downset: - var message = "Downloaded " & $progress & " of " & $progressMax & "\c" - stdout.write(message) - else: - echo "Status [" & $status & "] message = [" & $message & "]" - - downloadToFile("https://nim-lang.org/download/mingw64.7z", - "test.zip", {optUseCache}, progress) From 63cca93ea9bcab3c1fea39ff3789fd3a656d2db2 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 19 May 2022 17:11:53 +0200 Subject: [PATCH 3406/4254] testament: include extra options in test name (#19801) there's currently no (simple) way to disambiguate which option failed --- testament/categories.nim | 12 +++--- testament/testament.nim | 79 +++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index 46cc3b210..a092fec84 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -437,7 +437,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = if pkg.allowFailure: inc r.passed inc r.failedButAllowed - addResult(r, test, targetC, "", cmd & "\n" & outp, reFailed, allowFailure = pkg.allowFailure) + addResult(r, test, targetC, "", "", cmd & "\n" & outp, reFailed, allowFailure = pkg.allowFailure) continue outp @@ -450,21 +450,21 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) = discard tryCommand("nimble install --depsOnly -y", maxRetries = 3) discard tryCommand(pkg.cmd, reFailed = reBuildFailed) inc r.passed - r.addResult(test, targetC, "", "", reSuccess, allowFailure = pkg.allowFailure) + r.addResult(test, targetC, "", "", "", reSuccess, allowFailure = pkg.allowFailure) errors = r.total - r.passed if errors == 0: - r.addResult(packageFileTest, targetC, "", "", reSuccess) + r.addResult(packageFileTest, targetC, "", "", "", reSuccess) else: - r.addResult(packageFileTest, targetC, "", "", reBuildFailed) + r.addResult(packageFileTest, targetC, "", "", "", reBuildFailed) except JsonParsingError: errors = 1 - r.addResult(packageFileTest, targetC, "", "Invalid package file", reBuildFailed) + r.addResult(packageFileTest, targetC, "", "", "Invalid package file", reBuildFailed) raise except ValueError: errors = 1 - r.addResult(packageFileTest, targetC, "", "Unknown package", reBuildFailed) + r.addResult(packageFileTest, targetC, "", "", "Unknown package", reBuildFailed) raise # bug #18805 finally: if errors == 0: removeDir(packagesDir) diff --git a/testament/testament.nim b/testament/testament.nim index 4b5a8a147..a4329b982 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -259,7 +259,8 @@ Tests skipped: $4 / $1
      """ % [$x.total, $x.passed, $x.failedButAllowed, $x.skipped] proc addResult(r: var TResults, test: TTest, target: TTarget, - expected, given: string, successOrig: TResultEnum, allowFailure = false, givenSpec: ptr TSpec = nil) = + extraOptions, expected, given: string, successOrig: TResultEnum, + allowFailure = false, givenSpec: ptr TSpec = nil) = # instead of `ptr TSpec` we could also use `Option[TSpec]`; passing `givenSpec` makes it easier to get what we need # instead of having to pass individual fields, or abusing existing ones like expected vs given. # test.name is easier to find than test.name.extractFilename @@ -269,6 +270,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, if allowFailure: name.add " (allowed to fail) " if test.options.len > 0: name.add ' ' & test.options + if extraOptions.len > 0: name.add ' ' & extraOptions let duration = epochTime() - test.startTime let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout @@ -333,7 +335,8 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, discard waitForExit(p) close(p) -proc checkForInlineErrors(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = +proc checkForInlineErrors(r: var TResults, expected, given: TSpec, test: TTest, + target: TTarget, extraOptions: string) = let pegLine = peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' {[^:]*} ':' \s* {.*}" var covered = initIntSet() for line in splitLines(given.nimout): @@ -367,10 +370,10 @@ proc checkForInlineErrors(r: var TResults, expected, given: TSpec, test: TTest, e.add ": " e.add expected.inlineErrors[j].msg - r.addResult(test, target, e, given.nimout, reMsgsDiffer) + r.addResult(test, target, extraOptions, e, given.nimout, reMsgsDiffer) break coverCheck - r.addResult(test, target, "", given.msg, reSuccess) + r.addResult(test, target, extraOptions, "", given.msg, reSuccess) inc(r.passed) proc nimoutCheck(expected, given: TSpec): bool = @@ -381,22 +384,23 @@ proc nimoutCheck(expected, given: TSpec): bool = elif expected.nimout.len > 0 and not greedyOrderedSubsetLines(expected.nimout, given.nimout): result = false -proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = +proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, + target: TTarget, extraOptions: string) = if expected.inlineErrors.len > 0: - checkForInlineErrors(r, expected, given, test, target) + checkForInlineErrors(r, expected, given, test, target, extraOptions) elif strip(expected.msg) notin strip(given.msg): - r.addResult(test, target, expected.msg, given.msg, reMsgsDiffer) + r.addResult(test, target, extraOptions, expected.msg, given.msg, reMsgsDiffer) elif not nimoutCheck(expected, given): - r.addResult(test, target, expected.nimout, given.nimout, reMsgsDiffer) + r.addResult(test, target, extraOptions, expected.nimout, given.nimout, reMsgsDiffer) elif extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: - r.addResult(test, target, expected.file, given.file, reFilesDiffer) + r.addResult(test, target, extraOptions, expected.file, given.file, reFilesDiffer) elif expected.line != given.line and expected.line != 0 or expected.column != given.column and expected.column != 0: - r.addResult(test, target, $expected.line & ':' & $expected.column, + r.addResult(test, target, extraOptions, $expected.line & ':' & $expected.column, $given.line & ':' & $given.column, reLinesDiffer) else: - r.addResult(test, target, expected.msg, given.msg, reSuccess) + r.addResult(test, target, extraOptions, expected.msg, given.msg, reSuccess) inc(r.passed) proc generatedFile(test: TTest, target: TTarget): string = @@ -434,8 +438,8 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st given.err = reCodeNotFound echo getCurrentExceptionMsg() -proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, - expected: TSpec; r: var TResults) = +proc compilerOutputTests(test: TTest, target: TTarget, extraOptions: string, + given: var TSpec, expected: TSpec; r: var TResults) = var expectedmsg: string = "" var givenmsg: string = "" if given.err == reSuccess: @@ -449,7 +453,7 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, else: givenmsg = "$ " & given.cmd & '\n' & given.nimout if given.err == reSuccess: inc(r.passed) - r.addResult(test, target, expectedmsg, givenmsg, given.err) + r.addResult(test, target, extraOptions, expectedmsg, givenmsg, given.err) proc getTestSpecTarget(): TTarget = if getEnv("NIM_COMPILE_TO_CPP", "false") == "true": @@ -457,16 +461,6 @@ proc getTestSpecTarget(): TTarget = else: result = targetC -proc checkDisabled(r: var TResults, test: TTest): bool = - if test.spec.err in {reDisabled, reJoined}: - # targetC is a lie, but parameter is required - r.addResult(test, targetC, "", "", test.spec.err) - inc(r.skipped) - inc(r.total) - result = false - else: - result = true - var count = 0 proc equalModuloLastNewline(a, b: string): bool = @@ -474,8 +468,13 @@ proc equalModuloLastNewline(a, b: string): bool = result = a == b or b.endsWith("\n") and a == b[0 ..< ^1] proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, - target: TTarget, nimcache: string, extraOptions = "") = + target: TTarget, extraOptions: string, nimcache: string) = test.startTime = epochTime() + if test.spec.err in {reDisabled, reJoined}: + r.addResult(test, target, extraOptions, "", "", test.spec.err) + inc(r.skipped) + return + template callNimCompilerImpl(): untyped = # xxx this used to also pass: `--stdout --hint:Path:off`, but was done inconsistently # with other branches @@ -483,21 +482,21 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, case expected.action of actionCompile: var given = callNimCompilerImpl() - compilerOutputTests(test, target, given, expected, r) + compilerOutputTests(test, target, extraOptions, given, expected, r) of actionRun: var given = callNimCompilerImpl() if given.err != reSuccess: - r.addResult(test, target, "", "$ " & given.cmd & '\n' & given.nimout, given.err, givenSpec = given.addr) + r.addResult(test, target, extraOptions, "", "$ " & given.cmd & '\n' & given.nimout, given.err, givenSpec = given.addr) else: let isJsTarget = target == targetJS var exeFile = changeFileExt(test.name, if isJsTarget: "js" else: ExeExt) if not fileExists(exeFile): - r.addResult(test, target, expected.output, + r.addResult(test, target, extraOptions, expected.output, "executable not found: " & exeFile, reExeNotFound) else: let nodejs = if isJsTarget: findNodeJs() else: "" if isJsTarget and nodejs == "": - r.addResult(test, target, expected.output, "nodejs binary not in PATH", + r.addResult(test, target, extraOptions, expected.output, "nodejs binary not in PATH", reExeNotFound) else: var exeCmd: string @@ -528,24 +527,24 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, else: buf if exitCode != expected.exitCode: - r.addResult(test, target, "exitcode: " & $expected.exitCode, + r.addResult(test, target, extraOptions, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode & "\n\nOutput:\n" & bufB, reExitcodesDiffer) elif (expected.outputCheck == ocEqual and not expected.output.equalModuloLastNewline(bufB)) or (expected.outputCheck == ocSubstr and expected.output notin bufB): given.err = reOutputsDiffer - r.addResult(test, target, expected.output, bufB, reOutputsDiffer) + r.addResult(test, target, extraOptions, expected.output, bufB, reOutputsDiffer) else: - compilerOutputTests(test, target, given, expected, r) + compilerOutputTests(test, target, extraOptions, given, expected, r) of actionReject: let given = callNimCompilerImpl() - cmpMsgs(r, expected, given, test, target) + cmpMsgs(r, expected, given, test, target, extraOptions) -proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions = "") = +proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: string) = for target in expected.targets: inc(r.total) if target notin gTargets: - r.addResult(test, target, "", "", reDisabled) + r.addResult(test, target, extraOptions, "", "", reDisabled) inc(r.skipped) elif simulate: inc count @@ -553,16 +552,15 @@ proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions = else: let nimcache = nimcacheDir(test.name, test.options, target) var testClone = test - testSpecHelper(r, testClone, expected, target, nimcache, extraOptions) + testSpecHelper(r, testClone, expected, target, extraOptions, nimcache) proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) = var expected = test.spec if expected.parseErrors.len > 0: # targetC is a lie, but a parameter is required - r.addResult(test, targetC, "", expected.parseErrors, reInvalidSpec) + r.addResult(test, targetC, "", "", expected.parseErrors, reInvalidSpec) inc(r.total) return - if not checkDisabled(r, test): return expected.targets.incl targets # still no target specified at all @@ -572,14 +570,13 @@ proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) = for m in test.spec.matrix: targetHelper(r, test, expected, m) else: - targetHelper(r, test, expected) + targetHelper(r, test, expected, "") proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) {.used.} = - if not checkDisabled(r, test): return for target in test.spec.targets: inc(r.total) var testClone = test - testSpecHelper(r, testClone, test.spec, target, nimcache) + testSpecHelper(r, testClone, test.spec, target, "", nimcache) proc makeTest(test, options: string, cat: Category): TTest = result.cat = cat From a8426fc7890f1bea1c507ddb2fe42662f7a574f8 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Mon, 23 May 2022 00:12:34 -0400 Subject: [PATCH 3407/4254] Fix default testament target in docs and cli help (#19796) Co-authored-by: quantimnot --- doc/testament.rst | 4 ++-- testament/testament.nim | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/testament.rst b/doc/testament.rst index 5590cc6d7..427a7ff71 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -36,7 +36,7 @@ Options (for debugging) --failing Only show failing/ignored tests --targets:"c cpp js objc" - Run tests for specified targets (default: all) + Run tests for specified targets (default: c) --nim:path Use a particular nim executable (default: $PATH/nim) --directory:dir Change to directory dir before reading the tests or doing anything else. @@ -164,7 +164,7 @@ Example "template" **to edit** and write a Testament unittest: # Timeout seconds to run the test. Fractional values are supported. timeout: 1.5 - # Targets to run the test into (c, cpp, objc, js). + # Targets to run the test into (c, cpp, objc, js). Defaults to c. targets: "c js" # flags with which to run the test, delimited by `;` diff --git a/testament/testament.nim b/testament/testament.nim index a4329b982..d2b0e7fb4 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -54,7 +54,7 @@ Options: --verbose print commands (compiling and running tests) --simulate see what tests would be run but don't run them (for debugging) --failing only show failing/ignored tests - --targets:"c cpp js objc" run tests for specified targets (default: all) + --targets:"c cpp js objc" run tests for specified targets (default: c) --nim:path use a particular nim executable (default: $$PATH/nim) --directory:dir Change to directory dir before reading the tests or doing anything else. --colors:on|off Turn messages coloring on|off. From 05c0419658e3f97c29a12a16e99c0f8b842622c8 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Mon, 23 May 2022 00:17:32 -0400 Subject: [PATCH 3408/4254] Fix global destructor injection for JS backend (#19797) * Fix global destructor injection for JS backend * Moved global destructors injection before the final call to transform and generate JS code. It had previously been after and thus not no JS was generated for them. * Added some internal documentation of `jsgen`. * Enable a current destructor test to cover the JS backend as well. * Fixes the JS aspect of #17237. * Fixed global destructor injection order for JS backend Co-authored-by: quantimnot --- compiler/jsgen.nim | 30 +++++++++++++++++++++++++----- tests/destructor/t5342.nim | 3 ++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index b9a73daf9..6d34fcae2 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2392,6 +2392,7 @@ proc optionalLine(p: Rope): Rope = return p & "\L" proc genProc(oldProc: PProc, prc: PSym): Rope = + ## Generate a JS procedure ('function'). var resultSym: PSym a: TCompRes @@ -2673,6 +2674,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind) proc newModule(g: ModuleGraph; module: PSym): BModule = + ## Create a new JS backend module node. new(result) result.module = module result.sigConflicts = initCountTable[SigHash]() @@ -2684,6 +2686,7 @@ proc newModule(g: ModuleGraph; module: PSym): BModule = PGlobals(g.backend).inSystem = true proc genHeader(): Rope = + ## Generate the JS header. result = rope("""/* Generated by the Nim Compiler v$1 */ var framePtr = null; var excHandler = 0; @@ -2714,6 +2717,8 @@ proc addHcrInitGuards(p: PProc, n: PNode, genStmt(p, n) proc genModule(p: PProc, n: PNode) = + ## Generate the JS module code. + ## Called for each top level node in a Nim module. if optStackTrace in p.options: p.body.add(frameCreate(p, makeJSString("module " & p.module.module.name.s), @@ -2742,6 +2747,7 @@ proc genModule(p: PProc, n: PNode) = p.body.add(frameDestroy(p)) proc myProcess(b: PPassContext, n: PNode): PNode = + ## Generate JS code for a node. result = n let m = BModule(b) if passes.skipCodegen(m.config, n): return n @@ -2754,6 +2760,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode = p.g.code.add(p.body) proc wholeCode(graph: ModuleGraph; m: BModule): Rope = + ## Combine source code from all nodes. let globals = PGlobals(graph.backend) for prc in globals.forwarded: if not globals.generatedSyms.containsOrIncl(prc.id): @@ -2779,28 +2786,41 @@ proc getClassName(t: PType): Rope = else: result = rope(s.name.s) proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = - result = myProcess(b, n) + ## Finalize JS code generation of a Nim module. + ## Param `n` may contain nodes returned from the last module close call. var m = BModule(b) if sfMainModule in m.module.flags: - for destructorCall in graph.globalDestructors: - n.add destructorCall + # Add global destructors to the module. + # This must come before the last call to `myProcess`. + for i in countdown(high(graph.globalDestructors), 0): + n.add graph.globalDestructors[i] + # Process any nodes left over from the last call to `myClose`. + result = myProcess(b, n) + # Some codegen is different (such as no stacktraces; see `initProcOptions`) + # when `std/system` is being processed. if sfSystemModule in m.module.flags: PGlobals(graph.backend).inSystem = false + # Check if codegen should continue before any files are generated. + # It may bail early is if too many errors have been raised. if passes.skipCodegen(m.config, n): return n + # Nim modules are compiled into a single JS file. + # If this is the main module, then this is the final call to `myClose`. if sfMainModule in m.module.flags: var code = genHeader() & wholeCode(graph, m) let outFile = m.config.prepareToWriteOutput() - + # Generate an optional source map. if optSourcemap in m.config.globalOptions: var map: SourceMap (code, map) = genSourceMap($(code), outFile.string) writeFile(outFile.string & ".map", $(%map)) + # Check if the generated JS code matches the output file, or else + # write it to the file. if not equalsFile(code, outFile): if not writeRope(code, outFile): rawMessage(m.config, errCannotOpenFile, outFile.string) - proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = + ## Create the JS backend pass context `BModule` for a Nim module. result = newModule(graph, s) result.idgen = idgen diff --git a/tests/destructor/t5342.nim b/tests/destructor/t5342.nim index 19354ea64..0acd5ef9d 100644 --- a/tests/destructor/t5342.nim +++ b/tests/destructor/t5342.nim @@ -1,5 +1,6 @@ discard """ - matrix: "--gc:refc; --gc:arc" + matrix: "--mm:refc; --mm:arc" + targets: "c js" output: ''' 1 2 From b1b5e3ab10749851e942d624ee85188d8b06822e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 24 May 2022 12:37:19 -0300 Subject: [PATCH 3409/4254] Add Array.shift (#19811) * Add Array.shift for JavaScript targets * Add Array.shift for JavaScript targets --- changelog.md | 2 +- lib/js/jscore.nim | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 3b2685547..e120dcfb8 100644 --- a/changelog.md +++ b/changelog.md @@ -37,7 +37,7 @@ becomes an alias for `addr`. - Added `initDateTime` in `times` to create a datetime from a weekday, and ISO 8601 week number and week-based year. - Added `getIsoWeekAndYear` in `times` to get an ISO week number along with the corresponding ISO week-based year from a datetime. - Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. - +- Added [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) for JavaScript targets. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - Removed deprecated `oids.oidToString`. - Remove define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 61c188431..4518f32ce 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -123,3 +123,12 @@ since (1, 5): assert [1, 2, 3, 4, 5].copyWithin(0, 3) == @[4, 5, 3, 4, 5] assert [1, 2, 3, 4, 5].copyWithin(0, 3, 4) == @[4, 2, 3, 4, 5] assert [1, 2, 3, 4, 5].copyWithin(-2, -3, -1) == @[1, 2, 3, 3, 4] + + +since (1, 7): + func shift*[T](self: seq[T]): T {.importjs: "#.$1()".} = + ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift + runnableExamples: + var arrai = @[1, 2, 3] + assert arrai.shift() == 1 + assert arrai == @[2, 3] From ec0cec3170a3f175b9e02ca98e82c963fe64df4f Mon Sep 17 00:00:00 2001 From: tandy1000 Date: Tue, 24 May 2022 16:37:39 +0100 Subject: [PATCH 3410/4254] Add `document.hidden` and `document.visibilityState` properties (#19817) --- lib/js/dom.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index c1a677258..1a62780a7 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -216,11 +216,13 @@ type defaultCharset*: cstring fgColor*: cstring head*: Element + hidden*: bool lastModified*: cstring linkColor*: cstring referrer*: cstring title*: cstring URL*: cstring + visibilityState*: cstring vlinkColor*: cstring anchors*: seq[AnchorElement] forms*: seq[FormElement] From d81edcacc6740a99b0360cf31ddc2f2a1626006c Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 24 May 2022 23:53:01 +0800 Subject: [PATCH 3411/4254] Add link to std/tempfiles in the docs; fix #19155 (#19807) --- doc/lib.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/lib.rst b/doc/lib.rst index f72012777..2f3a315a8 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -251,6 +251,10 @@ Generic Operating System Services This module contains a few procedures to control the *terminal* (also called *console*). The implementation simply uses ANSI escape sequences and does not depend on any other module. + +* `tempfiles `_ + This module provides some utils to generate temporary path names and + create temporary files and directories. Math libraries From 14960fa754f42c820727bed9308e075b2cb923f6 Mon Sep 17 00:00:00 2001 From: Michael New Date: Sun, 29 May 2022 19:40:15 -0700 Subject: [PATCH 3412/4254] Fix typo and incorrect pragma name (#19847) --- doc/manual_experimental_strictnotnil.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual_experimental_strictnotnil.rst b/doc/manual_experimental_strictnotnil.rst index b14e5f9f3..ebfca7e51 100644 --- a/doc/manual_experimental_strictnotnil.rst +++ b/doc/manual_experimental_strictnotnil.rst @@ -172,7 +172,7 @@ We might need to check for `strictFuncs` pure funcs and not do that then. For field expressions `a.field`, we calculate an integer value based on a hash of the tree and just accept equivalent trees as equivalent expressions. For item expression `a[index]`, we also calculate an integer value based on a hash of the tree and accept equivalent trees as equivalent expressions: for static values only. -For now we support only constant indices: we dont track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the `{.warning[StrictCheckNotNil]:off}.`. +For now we support only constant indices: we dont track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the `{.warning[StrictNotNil]:off.}`. For bracket expressions, in the future we might count `a[]` as the same general expression. This means we should should the index but otherwise handle it the same for assign (maybe "aliasing" all the non-static elements) and differentiate only for static: e.g. `a[0]` and `a[1]`. From 004fc23a3fa79fc32e0fb5d4f438ddc22964b0da Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 30 May 2022 16:41:24 +0800 Subject: [PATCH 3413/4254] [vm] remove unused opcSubstr opcode (#19834) remove unused opcSubstr --- compiler/vm.nim | 8 -------- compiler/vmdef.nim | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index fa1c71c85..bbcff77ba 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1185,14 +1185,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcContainsSet: decodeBC(rkInt) regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) - of opcSubStr: - decodeBC(rkNode) - inc pc - assert c.code[pc].opcode == opcSubStr - let rd = c.code[pc].regA - createStr regs[ra] - regs[ra].node.strVal = substr(regs[rb].node.strVal, - regs[rc].intVal.int, regs[rd].intVal.int) of opcParseFloat: decodeBC(rkInt) inc pc diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index ecdbeff89..c653501ca 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -102,7 +102,7 @@ type opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcIsNil, opcOf, opcIs, - opcSubStr, opcParseFloat, opcConv, opcCast, + opcParseFloat, opcConv, opcCast, opcQuit, opcInvalidField, opcNarrowS, opcNarrowU, opcSignExtend, @@ -306,7 +306,7 @@ proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.disca const firstABxInstr* = opcTJmp largeInstrs* = { # instructions which use 2 int32s instead of 1: - opcSubStr, opcConv, opcCast, opcNewSeq, opcOf + opcConv, opcCast, opcNewSeq, opcOf } slotSomeTemp* = slotTempUnknown relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack} From 497af2c0d9f311e050ba57842a6326ca70489d55 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Mon, 30 May 2022 05:07:47 -0400 Subject: [PATCH 3414/4254] Doc preferred import style in compiler (#19832) Doc prefered import style in compiler Co-authored-by: quantimnot --- doc/intern.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/intern.rst b/doc/intern.rst index a8846ae02..4ca7eff20 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -186,6 +186,7 @@ Coding Guidelines * Use a space after a colon, but not before it. * [deprecated] Start types with a capital `T`, unless they are pointers/references which start with `P`. +* Prefer `import package`:nim: over `from package import symbol`:nim:. See also the `API naming design `_ document. From 15f0b4867679120580b2f14bbb7a8b302505b34d Mon Sep 17 00:00:00 2001 From: Alfred Morgan Date: Mon, 30 May 2022 03:09:18 -0700 Subject: [PATCH 3415/4254] Zectbumo fixes 19824 (#19825) * borrowed `$` to make Time string friendly * added sep character parameter * Revert "added sep character parameter" This reverts commit 45f4b019a4883b6ba577ade1f94677266beb5960. * added sep character parameter * Revert "borrowed `$` to make Time string friendly" This reverts commit 10e2e44c9a04970f38cf66556635bdbb50b69136. * added uri tests and made changelong entry * Update lib/pure/uri.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update lib/pure/uri.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update tests/stdlib/turi.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * Update tests/stdlib/turi.nim Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 1 + lib/pure/uri.nim | 14 ++++++++------ tests/stdlib/turi.nim | 4 ++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index e120dcfb8..9548f3034 100644 --- a/changelog.md +++ b/changelog.md @@ -39,6 +39,7 @@ becomes an alias for `addr`. - Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. - Added [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) for JavaScript targets. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. +- Added `sep` parameter in `std/uri` to specify the query separator. - Removed deprecated `oids.oidToString`. - Remove define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 7583dbd1e..1dbb018c2 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -123,13 +123,13 @@ func decodeUrl*(s: string, decodePlus = true): string = setLen(result, j) func encodeQuery*(query: openArray[(string, string)], usePlus = true, - omitEq = true): string = + omitEq = true, sep = '&'): string = ## Encodes a set of (key, value) parameters into a URL query string. ## ## Every (key, value) pair is URL-encoded and written as `key=value`. If the ## value is an empty string then the `=` is omitted, unless `omitEq` is ## false. - ## The pairs are joined together by a `&` character. + ## The pairs are joined together by the `sep` character. ## ## The `usePlus` parameter is passed down to the `encodeUrl` function that ## is used for the URL encoding of the string values. @@ -140,9 +140,10 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, assert encodeQuery({: }) == "" assert encodeQuery({"a": "1", "b": "2"}) == "a=1&b=2" assert encodeQuery({"a": "1", "b": ""}) == "a=1&b" + assert encodeQuery({"a": "1", "b": ""}, omitEq = false, sep = ';') == "a=1;b=" for elem in query: - # Encode the `key = value` pairs and separate them with a '&' - if result.len > 0: result.add('&') + # Encode the `key = value` pairs and separate them with 'sep' + if result.len > 0: result.add(sep) let (key, val) = elem result.add(encodeUrl(key, usePlus)) # Omit the '=' if the value string is empty @@ -150,7 +151,7 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add('=') result.add(encodeUrl(val, usePlus)) -iterator decodeQuery*(data: string): tuple[key, value: string] = +iterator decodeQuery*(data: string, sep = '&'): tuple[key, value: string] = ## Reads and decodes the query string `data` and yields the `(key, value)` pairs ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, ## a `UriParseError` is raised when there is an unencoded `=` character in a decoded @@ -158,6 +159,7 @@ iterator decodeQuery*(data: string): tuple[key, value: string] = runnableExamples: import std/sequtils assert toSeq(decodeQuery("foo=1&bar=2=3")) == @[("foo", "1"), ("bar", "2=3")] + assert toSeq(decodeQuery("foo=1;bar=2=3", ';')) == @[("foo", "1"), ("bar", "2=3")] assert toSeq(decodeQuery("&a&=b&=&&")) == @[("", ""), ("a", ""), ("", "b"), ("", ""), ("", "")] proc parseData(data: string, i: int, field: var string, sep: char): int = @@ -186,7 +188,7 @@ iterator decodeQuery*(data: string): tuple[key, value: string] = when defined(nimLegacyParseQueryStrict): i = parseData(data, i, value, '=') else: - i = parseData(data, i, value, '&') + i = parseData(data, i, value, sep) yield (name, value) if i < data.len: when defined(nimLegacyParseQueryStrict): diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index a3b6afe2c..79ddd773b 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -274,7 +274,9 @@ template main() = doAssert encodeQuery({"foo": ""}) == "foo" doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo=" doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3" + doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, sep = ';') == "a=1;b;c=3" doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3" + doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false, sep = ';') == "a=1;b=;c=3" block: # `?` block: @@ -300,7 +302,9 @@ template main() = block: # decodeQuery doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] + doAssert toSeq(decodeQuery("a=1;b=0", sep = ';')) == @[("a", "1"), ("b", "0")] doAssert toSeq(decodeQuery("a=1&b=2c=6")) == @[("a", "1"), ("b", "2c=6")] + doAssert toSeq(decodeQuery("a=1;b=2c=6", sep = ';')) == @[("a", "1"), ("b", "2c=6")] block: # bug #17481 let u1 = parseUri("./") From d30c6419a051a815e3fdb354ac79522f17e55bda Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Mon, 30 May 2022 12:52:19 -0400 Subject: [PATCH 3416/4254] Refactor and doc package handling, module name mangling (#19821) * Refactor and doc package handling, module name mangling * Consolidate, de-duplicate and extend package handling * Alter how duplicate module names of a package are handled * Alter how module names are mangled * Fix crash when another package is named 'stdlib' (test case added) * Doc what defines a package in the manual Modules with duplicate names within a package used to be given 'fake' packages to resolve conflicts. That prevented the ability to discern if a module belonged to the current project package or a foreign package. They now have the proper package owner and the names are mangled in a consistent manner to prevent codegen clashes. All module names are now mangled the same. Stdlib was treated special before, but now it is same as any other package. This fixes a crash when a foreign package is named 'stdlib'. Module mangling is altered for both file paths and symbols used by the backends. Removed an unused module name to package mapping that may have been intended for IC. The mapping was removed because it wasn't being used and was complicating the issue of package modules with duplicate names not having the proper package owner assigned. * Fix some tests * Refactor `packagehandling` * Remove `packagehandling.withPackageName` and its uses * Move module path mangling from `packagehandling` to `modulepaths` * Move `options.toRodFile` to `ic` to break import cycle * Changed import style to match preferred style Co-authored-by: quantimnot --- compiler/ast.nim | 21 ---- compiler/cgen.nim | 27 ++--- compiler/docgen.nim | 13 +-- compiler/docgen2.nim | 4 +- compiler/extccomp.nim | 11 ++- compiler/ic/cbackend.nim | 5 +- compiler/ic/ic.nim | 19 ++-- compiler/modulegraphs.nim | 18 +++- compiler/modulepaths.nim | 109 +++------------------ compiler/modules.nim | 51 +--------- compiler/options.nim | 7 +- compiler/packagehandling.nim | 23 +---- compiler/packages.nim | 49 +++++++++ compiler/passes.nim | 12 +-- compiler/pragmas.nim | 3 +- doc/manual.rst | 13 +++ tests/ccgbugs/tforward_decl_only.nim | 2 +- tests/modules/a/module_name_clashes.nim | 8 ++ tests/modules/b/module_name_clashes.nim | 3 + tests/modules/tmodule_name_clashes.nim | 16 +++ tests/package/stdlib/stdlib.nimble | 0 tests/package/stdlib/system.nim | 2 + tests/package/tstdlib_name_not_special.nim | 3 + 23 files changed, 175 insertions(+), 244 deletions(-) create mode 100644 compiler/packages.nim create mode 100644 tests/modules/a/module_name_clashes.nim create mode 100644 tests/modules/b/module_name_clashes.nim create mode 100644 tests/modules/tmodule_name_clashes.nim create mode 100644 tests/package/stdlib/stdlib.nimble create mode 100644 tests/package/stdlib/system.nim create mode 100644 tests/package/tstdlib_name_not_special.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index d1e5ae2bf..f8343c1a3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1108,21 +1108,6 @@ proc getPIdent*(a: PNode): PIdent {.inline.} = of nkIdent: a.ident else: nil -proc getnimblePkg*(a: PSym): PSym = - result = a - while result != nil: - case result.kind - of skModule: - result = result.owner - assert result.kind == skPackage - of skPackage: - if result.owner == nil: - break - else: - result = result.owner - else: - assert false, $result.kind - const moduleShift = when defined(cpu32): 20 else: 24 @@ -1167,13 +1152,7 @@ when false: assert dest.ItemId.item <= src.ItemId.item dest = src -proc getnimblePkgId*(a: PSym): int = - let b = a.getnimblePkg - result = if b == nil: -1 else: b.id - var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things -#var -# gMainPackageId*: int proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ad59b759f..8d24f30c5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -15,8 +15,7 @@ import ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, rodutils, renderer, cgendata, aliases, lowerings, tables, sets, ndi, lineinfos, pathutils, transf, - injectdestructors, astmsgs - + injectdestructors, astmsgs, modulepaths when defined(nimPreviewSlimSystem): import std/assertions @@ -1306,17 +1305,19 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L") addNimDefines(result, conf) -proc getSomeNameForModule(m: PSym): Rope = - assert m.kind == skModule - assert m.owner.kind == skPackage - if {sfSystemModule, sfMainModule} * m.flags == {}: - result = m.owner.name.s.mangle.rope - result.add "_" - result.add m.name.s.mangle +proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope = + ## Returns a mangled module name. + result.add mangleModuleName(conf, filename).mangle + +proc getSomeNameForModule(m: BModule): Rope = + ## Returns a mangled module name. + assert m.module.kind == skModule + assert m.module.owner.kind == skPackage + result.add mangleModuleName(m.g.config, m.filename).mangle proc getSomeInitName(m: BModule, suffix: string): Rope = if not m.hcrOn: - result = getSomeNameForModule(m.module) + result = getSomeNameForModule(m) result.add suffix proc getInitName(m: BModule): Rope = @@ -1555,11 +1556,11 @@ proc genMainProc(m: BModule) = proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) = ## Called from the IC backend. if HasDatInitProc in flags: - let datInit = getSomeNameForModule(m) & "DatInit000" + let datInit = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "DatInit000" g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) g.mainDatInit.addf("\t$1();$N", [datInit]) if HasModuleInitProc in flags: - let init = getSomeNameForModule(m) & "Init000" + let init = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "Init000" g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) let initCall = "\t$1();$N" % [init] if sfMainModule in m.flags: @@ -1940,7 +1941,7 @@ proc getCFile(m: BModule): AbsoluteFile = if m.compileToCpp: ".nim.cpp" elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m" else: ".nim.c" - result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext) + result = changeFileExt(completeCfilePath(m.config, mangleModuleName(m.config, m.cfilename).AbsoluteFile), ext) when false: proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = diff --git a/compiler/docgen.nim b/compiler/docgen.nim index ecf98d0b6..f633a57a0 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -16,7 +16,7 @@ import packages/docutils/[rst, rstgen, dochelpers], json, xmltree, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, tables, nimpaths, renderverbatim, osproc + pathutils, tables, nimpaths, renderverbatim, osproc, packages import packages/docutils/rstast except FileIndex, TLineInfo from uri import encodeUrl @@ -413,9 +413,6 @@ proc getPlainDocstring(n: PNode): string = result = getPlainDocstring(n[i]) if result.len > 0: return -proc belongsToPackage(conf: ConfigRef; module: PSym): bool = - result = module.kind == skModule and module.getnimblePkgId == conf.mainPackageId - proc externalDep(d: PDoc; module: PSym): string = if optWholeProject in d.conf.globalOptions or d.conf.docRoot.len > 0: let full = AbsoluteFile toFullPath(d.conf, FileIndex module.position) @@ -471,7 +468,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string; "\\spanIdentifier{$1}", [escLit, procLink]) elif s != nil and s.kind in {skType, skVar, skLet, skConst} and sfExported in s.flags and s.owner != nil and - belongsToPackage(d.conf, s.owner) and d.target == outHtml: + belongsToProjectPackage(d.conf, s.owner) and d.target == outHtml: let external = externalDep(d, s.owner) result.addf "$3", [changeFileExt(external, "html"), literal, @@ -1131,7 +1128,7 @@ proc traceDeps(d: PDoc, it: PNode) = for x in it[2]: a[2] = x traceDeps(d, a) - elif it.kind == nkSym and belongsToPackage(d.conf, it.sym): + elif it.kind == nkSym and belongsToProjectPackage(d.conf, it.sym): let external = externalDep(d, it.sym) if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") dispA(d.conf, d.section[k].finalMarkup, @@ -1141,7 +1138,7 @@ proc traceDeps(d: PDoc, it: PNode) = proc exportSym(d: PDoc; s: PSym) = const k = exportSection - if s.kind == skModule and belongsToPackage(d.conf, s): + if s.kind == skModule and belongsToProjectPackage(d.conf, s): let external = externalDep(d, s) if d.section[k].finalMarkup != "": d.section[k].finalMarkup.add(", ") dispA(d.conf, d.section[k].finalMarkup, @@ -1150,7 +1147,7 @@ proc exportSym(d: PDoc; s: PSym) = changeFileExt(external, "html")]) elif s.kind != skModule and s.owner != nil: let module = originatingModule(s) - if belongsToPackage(d.conf, module): + if belongsToProjectPackage(d.conf, module): let complexSymbol = complexName(s.kind, s.ast, s.name.s) symbolOrId = d.newUniquePlainSymbol(complexSymbol) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index bfdb4568c..9abde9f52 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -11,7 +11,7 @@ # semantic checking. import - options, ast, msgs, passes, docgen, lineinfos, pathutils + options, ast, msgs, passes, docgen, lineinfos, pathutils, packages from modulegraphs import ModuleGraph, PPassContext @@ -23,7 +23,7 @@ type PGen = ref TGen proc shouldProcess(g: PGen): bool = - (optWholeProject in g.doc.conf.globalOptions and g.module.getnimblePkgId == g.doc.conf.mainPackageId) or + (optWholeProject in g.doc.conf.globalOptions and g.doc.conf.belongsToProjectPackage(g.module)) or sfMainModule in g.module.flags or g.config.projectMainIdx == g.module.info.fileIndex template closeImpl(body: untyped) {.dirty.} = diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 09a1dfbb3..515c7ba29 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -12,7 +12,7 @@ # from a lineinfos file, to provide generalized procedures to compile # nim files. -import ropes, platform, condsyms, options, msgs, lineinfos, pathutils +import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar] @@ -370,6 +370,7 @@ proc initVars*(conf: ConfigRef) = proc completeCfilePath*(conf: ConfigRef; cfile: AbsoluteFile, createSubDir: bool = true): AbsoluteFile = + ## Generate the absolute file path to the generated modules. result = completeGeneratedFilePath(conf, cfile, createSubDir) proc toObjFile*(conf: ConfigRef; filename: AbsoluteFile): AbsoluteFile = @@ -380,7 +381,7 @@ proc addFileToCompile*(conf: ConfigRef; cf: Cfile) = conf.toCompile.add(cf) proc addLocalCompileOption*(conf: ConfigRef; option: string; nimfile: AbsoluteFile) = - let key = completeCfilePath(conf, withPackageName(conf, nimfile)).string + let key = completeCfilePath(conf, mangleModuleName(conf, nimfile).AbsoluteFile).string var value = conf.cfileSpecificOptions.getOrDefault(key) if strutils.find(value, option, 0) < 0: addOpt(value, option) @@ -637,7 +638,7 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = if conf.backend == backendJs: return false # pre-existing behavior, but not sure it's good - let hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") + let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1") let currentHash = footprint(conf, cfile) var f: File if open(f, hashFile.string, fmRead): @@ -845,9 +846,9 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string = if conf.hasHint(hintCC): if optListCmd in conf.globalOptions or conf.verbosity > 1: - result = MsgKindToStr[hintCC] % (demanglePackageName(path.splitFile.name) & ": " & compileCmd) + result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd) else: - result = MsgKindToStr[hintCC] % demanglePackageName(path.splitFile.name) + result = MsgKindToStr[hintCC] % demangleModuleName(path.splitFile.name) proc callCCompiler*(conf: ConfigRef) = var diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index e7ab000e6..815078a36 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -24,7 +24,7 @@ when defined(nimPreviewSlimSystem): import std/assertions import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen, - pathutils, extccomp, msgs] + pathutils, extccomp, msgs, modulepaths] import packed_ast, ic, dce, rodfiles @@ -64,7 +64,8 @@ proc addFileToLink(config: ConfigRef; m: PSym) = if config.backend == backendCpp: ".nim.cpp" elif config.backend == backendObjc: ".nim.m" else: ".nim.c" - let cfile = changeFileExt(completeCfilePath(config, withPackageName(config, filename)), ext) + let cfile = changeFileExt(completeCfilePath(config, + mangleModuleName(config, filename).AbsoluteFile), ext) let objFile = completeCfilePath(config, toObjFile(config, cfile)) if fileExists(objFile): var cf = Cfile(nimname: m.name.s, cname: cfile, diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 193e5f517..38b6987f9 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -10,7 +10,7 @@ import hashes, tables, intsets, std/sha1 import packed_ast, bitabs, rodfiles import ".." / [ast, idents, lineinfos, msgs, ropes, options, - pathutils, condsyms] + pathutils, condsyms, packages, modulepaths] #import ".." / [renderer, astalgo] from os import removeFile, isAbsolute @@ -551,6 +551,10 @@ proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) = rawMessage(config, warnCannotOpenFile, filename.string & " reason: " & $err) #echo "Error: ", $err, " loading file: ", filename.string +proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile = + result = changeFileExt(completeGeneratedFilePath(conf, + mangleModuleName(conf, f).AbsoluteFile), ext) + proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef; ignoreConfig = false): RodFileError = var f = rodfiles.open(filename.string) @@ -930,17 +934,6 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t result = g[si].types[t.item] assert result.itemId.item > 0 -proc newPackage(config: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym = - let filename = AbsoluteFile toFullPath(config, fileIdx) - let name = getIdent(cache, splitFile(filename).name) - let info = newLineInfo(fileIdx, 1, 1) - let - pck = getPackageName(config, filename.string) - pck2 = if pck.len > 0: pck else: "unknown" - pack = getIdent(cache, pck2) - result = newSym(skPackage, getIdent(cache, pck2), - ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info) - proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex; m: var LoadedModule) = m.iface = initTable[PIdent, seq[PackedItemId]]() @@ -968,7 +961,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa name: getIdent(cache, splitFile(filename).name), info: newLineInfo(fileIdx, 1, 1), position: int(fileIdx)) - m.module.owner = newPackage(conf, cache, fileIdx) + m.module.owner = getPackage(conf, cache, fileIdx) m.module.flags = m.fromDisk.moduleFlags proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index c44908dc3..147381910 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -12,7 +12,7 @@ ## or stored in a rod-file. import intsets, tables, hashes, md5_old -import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils +import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages import ic / [packed_ast, ic] when defined(nimPreviewSlimSystem): @@ -67,7 +67,6 @@ type startupPackedConfig*: PackedConfig packageSyms*: TStrTable - modulesPerPackage*: Table[ItemId, TStrTable] deps*: IntSet # the dependency graph or potentially its transitive closure. importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies suggestMode*: bool # whether we are in nimsuggest mode or not. @@ -597,3 +596,18 @@ proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, let fromModule2 = if fromModule != nil: $fromModule.name.s else: "(toplevel)" let mode = if isNimscript: "(nims) " else: "" rawMessage(conf, hintProcessing, "$#$# $#: $#: $#" % [mode, indent, fromModule2, moduleStatus, path]) + +proc getPackage*(graph: ModuleGraph; fileIdx: FileIndex): PSym = + ## Returns a package symbol for yet to be defined module for fileIdx. + ## The package symbol is added to the graph if it doesn't exist. + let pkgSym = getPackage(graph.config, graph.cache, fileIdx) + # check if the package is already in the graph + result = graph.packageSyms.strTableGet(pkgSym.name) + if result == nil: + # the package isn't in the graph, so create and add it + result = pkgSym + graph.packageSyms.strTableAdd(pkgSym) + +func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool = + ## Check if symbol belongs to the 'stdlib' package. + sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index a16b669c4..e80ea3fa6 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -10,100 +10,6 @@ import ast, renderer, strutils, msgs, options, idents, os, lineinfos, pathutils -when false: - const - considerParentDirs = not defined(noParentProjects) - considerNimbleDirs = not defined(noNimbleDirs) - - proc findInNimbleDir(pkg, subdir, dir: string): string = - var best = "" - var bestv = "" - for k, p in os.walkDir(dir, relative=true): - if k == pcDir and p.len > pkg.len+1 and - p[pkg.len] == '-' and p.startsWith(pkg): - let (_, a, _) = getPathVersionChecksum(p) - if bestv.len == 0 or bestv < a: - bestv = a - best = dir / p - - if best.len > 0: - var f: File - if open(f, best / changeFileExt(pkg, ".nimble-link")): - # the second line contains what we're interested in, see: - # https://github.com/nim-lang/nimble#nimble-link - var override = "" - discard readLine(f, override) - discard readLine(f, override) - close(f) - if not override.isAbsolute(): - best = best / override - else: - best = override - let f = if subdir.len == 0: pkg else: subdir - let res = addFileExt(best / f, "nim") - if best.len > 0 and fileExists(res): - result = res - -when false: - proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string = - template attempt(a) = - let x = addFileExt(a, "nim") - if fileExists(x): return x - - case pkg - of "stdlib": - if subdir.len == 0: - return options.libpath - else: - for candidate in stdlibDirs: - attempt(options.libpath / candidate / subdir) - of "root": - let root = project.splitFile.dir - if subdir.len == 0: - return root - else: - attempt(root / subdir) - else: - when considerParentDirs: - var p = parentDir(source.splitFile.dir) - # support 'import $karax': - let f = if subdir.len == 0: pkg else: subdir - - while p.len > 0: - let dir = p / pkg - if dirExists(dir): - attempt(dir / f) - # 2nd attempt: try to use 'karax/karax' - attempt(dir / pkg / f) - # 3rd attempt: try to use 'karax/src/karax' - attempt(dir / "src" / f) - attempt(dir / "src" / pkg / f) - p = parentDir(p) - - when considerNimbleDirs: - if not options.gNoNimblePath: - var nimbleDir = getEnv("NIMBLE_DIR") - if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" - result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs") - if result.len > 0: return result - when not defined(windows): - result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs") - if result.len > 0: return result - - proc scriptableImport(pkg, sub: string; info: TLineInfo): string = - resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) - - proc lookupPackage(pkg, subdir: PNode): string = - let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" - case pkg.kind - of nkStrLit, nkRStrLit, nkTripleStrLit: - result = scriptableImport(pkg.strVal, sub, pkg.info) - of nkIdent: - result = scriptableImport(pkg.ident.s, sub, pkg.info) - else: - localError(pkg.info, "package name must be an identifier or string literal") - result = "" - proc getModuleName*(conf: ConfigRef; n: PNode): string = # This returns a short relative module name without the nim extension # e.g. like "system", "importer" or "somepath/module" @@ -163,3 +69,18 @@ proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex = result = InvalidFileIdx else: result = fileInfoIdx(conf, fullPath) + +proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string = + ## Mangle a relative module path to avoid path and symbol collisions. + ## + ## Used by backends that need to generate intermediary files from Nim modules. + ## This is needed because the compiler uses a flat cache file hierarchy. + ## + ## Example: + ## `foo-#head/../bar` becomes `@foo-@hhead@s..@sbar` + "@m" & relativeTo(path, conf.projectPath).string.multiReplace( + {$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"}) + +proc demangleModuleName*(path: string): string = + ## Demangle a relative module path. + result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"}) diff --git a/compiler/modules.nim b/compiler/modules.nim index dd5db63fa..2becef38f 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -12,7 +12,7 @@ import ast, astalgo, magicsys, msgs, options, idents, lexer, passes, syntaxes, llstream, modulegraphs, - lineinfos, pathutils, tables + lineinfos, pathutils, tables, packages when defined(nimPreviewSlimSystem): import std/[syncio, assertions] @@ -25,56 +25,11 @@ proc resetSystemArtifacts*(g: ModuleGraph) = template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent = getIdent(graph.cache, splitFile(filename).name) -template packageId(): untyped {.dirty.} = ItemId(module: PackageModuleId, item: int32(fileIdx)) - -proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym = - ## returns package symbol (skPackage) for yet to be defined module for fileIdx - let filename = AbsoluteFile toFullPath(graph.config, fileIdx) - let name = getModuleIdent(graph, filename) - let info = newLineInfo(fileIdx, 1, 1) - let - pck = getPackageName(graph.config, filename.string) - pck2 = if pck.len > 0: pck else: "unknown" - pack = getIdent(graph.cache, pck2) - result = graph.packageSyms.strTableGet(pack) - if result == nil: - result = newSym(skPackage, getIdent(graph.cache, pck2), packageId(), nil, info) - #initStrTable(packSym.tab) - graph.packageSyms.strTableAdd(result) - else: - let modules = graph.modulesPerPackage.getOrDefault(result.itemId) - let existing = if modules.data.len > 0: strTableGet(modules, name) else: nil - if existing != nil and existing.info.fileIndex != info.fileIndex: - when false: - # we used to produce an error: - localError(graph.config, info, - "module names need to be unique per Nimble package; module clashes with " & - toFullPath(graph.config, existing.info.fileIndex)) - else: - # but starting with version 0.20 we now produce a fake Nimble package instead - # to resolve the conflicts: - let pck3 = fakePackageName(graph.config, filename) - # this makes the new `result`'s owner be the original `result` - result = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), result, info) - #initStrTable(packSym.tab) - graph.packageSyms.strTableAdd(result) - proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = let packSym = getPackage(graph, fileIdx) result.owner = packSym result.position = int fileIdx - #initStrTable(result.tab(graph)) - when false: - strTableAdd(result.tab, result) # a module knows itself - # This is now implemented via - # c.moduleScope.addSym(module) # a module knows itself - # in sem.nim, around line 527 - - if graph.modulesPerPackage.getOrDefault(packSym.itemId).data.len == 0: - graph.modulesPerPackage[packSym.itemId] = newStrTable() - graph.modulesPerPackage[packSym.itemId].strTableAdd(result) - proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = let filename = AbsoluteFile toFullPath(graph.config, fileIdx) # We cannot call ``newSym`` here, because we have to circumvent the ID @@ -136,7 +91,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = # localError(result.info, errAttemptToRedefine, result.name.s) # restore the notes for outer module: graph.config.notes = - if s.getnimblePkgId == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes + if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes else: graph.config.foreignPackageNotes proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode = @@ -171,7 +126,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = conf.projectMainIdx2 = projectFile let packSym = getPackage(graph, projectFile) - graph.config.mainPackageId = packSym.getnimblePkgId + graph.config.mainPackageId = packSym.getPackageId graph.importStack.add projectFile if projectFile == systemFileIdx: diff --git a/compiler/options.nim b/compiler/options.nim index 69eafb67f..545dfb1d1 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -807,6 +807,8 @@ proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile, proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, createSubDir: bool = true): AbsoluteFile = + ## Return an absolute path of a generated intermediary file. + ## Optionally creates the cache directory if `createSubDir` is `true`. let subdir = getNimcacheDir(conf) if createSubDir: try: @@ -814,11 +816,6 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, except OSError: conf.quitOrRaise "cannot create directory: " & subdir.string result = subdir / RelativeFile f.string.splitPath.tail - #echo "completeGeneratedFilePath(", f, ") = ", result - -proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile = - result = changeFileExt(completeGeneratedFilePath(conf, - withPackageName(conf, f)), ext) proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile = for it in conf.searchPaths: diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 4af0c28fa..8cf209779 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -37,24 +37,7 @@ proc getNimbleFile*(conf: ConfigRef; path: string): string = proc getPackageName*(conf: ConfigRef; path: string): string = ## returns nimble package name, e.g.: `cligen` let path = getNimbleFile(conf, path) - result = path.splitFile.name - -proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string = - # Convert `path` so that 2 modules with same name - # in different directory get different name and they can be - # placed in a directory. - # foo-#head/../bar becomes @foo-@hhead@s..@sbar - result = "@m" & relativeTo(path, conf.projectPath).string.multiReplace( - {$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"}) - -proc demanglePackageName*(path: string): string = - result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"}) - -proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile = - let x = getPackageName(conf, path.string) - let (p, file, ext) = path.splitFile - if x == "stdlib": - # Hot code reloading now relies on 'stdlib_system' names etc. - result = p / RelativeFile((x & '_' & file) & ext) + if path.len > 0: + return path.splitFile.name else: - result = p / RelativeFile(fakePackageName(conf, path)) + return "unknown" diff --git a/compiler/packages.nim b/compiler/packages.nim new file mode 100644 index 000000000..6ceeb1ccc --- /dev/null +++ b/compiler/packages.nim @@ -0,0 +1,49 @@ +# +# +# The Nim Compiler +# (c) Copyright 2022 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Package related procs. +## +## See Also: +## * `packagehandling` for package path handling +## * `modulegraphs.getPackage` +## * `modulegraphs.belongsToStdlib` + +import "." / [options, ast, lineinfos, idents, pathutils, msgs] + +proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym = + ## Return a new package symbol. + ## + ## See Also: + ## * `modulegraphs.getPackage` + let + filename = AbsoluteFile toFullPath(conf, fileIdx) + name = getIdent(cache, splitFile(filename).name) + info = newLineInfo(fileIdx, 1, 1) + pkgName = getPackageName(conf, filename.string) + pkgIdent = getIdent(cache, pkgName) + newSym(skPackage, pkgIdent, ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info) + +func getPackageSymbol*(sym: PSym): PSym = + ## Return the owning package symbol. + assert sym != nil + result = sym + while result.kind != skPackage: + result = result.owner + assert result != nil, repr(sym.info) + +func getPackageId*(sym: PSym): int = + ## Return the owning package ID. + sym.getPackageSymbol.id + +func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool = + ## Return whether the symbol belongs to the project's package. + ## + ## See Also: + ## * `modulegraphs.belongsToStdlib` + conf.mainPackageId == sym.getPackageId diff --git a/compiler/passes.nim b/compiler/passes.nim index 7fb2842f5..3de27575b 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -14,7 +14,7 @@ import options, ast, llstream, msgs, idents, syntaxes, modulegraphs, reorder, - lineinfos, pathutils + lineinfos, pathutils, packages when defined(nimPreviewSlimSystem): import std/syncio @@ -104,7 +104,7 @@ const proc prepareConfigNotes(graph: ModuleGraph; module: PSym) = # don't be verbose unless the module belongs to the main package: - if module.getnimblePkgId == graph.config.mainPackageId: + if graph.config.belongsToProjectPackage(module): graph.config.notes = graph.config.mainPackageNotes else: if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes @@ -114,12 +114,6 @@ proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} = result = true #module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange") -proc partOfStdlib(x: PSym): bool = - var it = x.owner - while it != nil and it.kind == skPackage and it.owner != nil: - it = it.owner - result = it != nil and it.name.s == "stdlib" - proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; stream: PLLStream): bool {.discardable.} = if graph.stopCompile(): return true @@ -141,7 +135,7 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; while true: openParser(p, fileIdx, s, graph.cache, graph.config) - if not partOfStdlib(module) or module.name.s == "distros": + if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"): # XXX what about caching? no processing then? what if I change the # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 458c7547a..2262e441b 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -641,12 +641,13 @@ proc pragmaLine(c: PContext, n: PNode) = n.info = getInfoContext(c.config, -1) proc processPragma(c: PContext, n: PNode, i: int) = + ## Create and add a new custom pragma `{.pragma: name.}` node to the module's context. let it = n[i] if it.kind notin nkPragmaCallKinds and it.safeLen == 2: invalidPragma(c, n) elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent: invalidPragma(c, n) - var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), nil, it.info, c.config.options) + var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), c.module, it.info, c.config.options) userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1]) strTableAdd(c.userPragmas, userPragma) diff --git a/doc/manual.rst b/doc/manual.rst index bfcb41b7a..5ab257fec 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6551,6 +6551,19 @@ iterator in which case the overloading resolution takes place: write(stdout, x) # not ambiguous: uses the module C's x +Packages +-------- +A collection of modules in a file tree with an ``identifier.nimble`` file in the +root of the tree is called a Nimble package. A valid package name can only be a +valid Nim identifier and thus its filename is ``identifier.nimble`` where +``identifier`` is the desired package name. A module without a ``.nimble`` file +is assigned the package identifier: `unknown`. + +The distinction between packages allows diagnostic compiler messages to be +scoped to the current project's package vs foreign packages. + + + Compiler Messages ================= diff --git a/tests/ccgbugs/tforward_decl_only.nim b/tests/ccgbugs/tforward_decl_only.nim index 74fbae303..416e50eb5 100644 --- a/tests/ccgbugs/tforward_decl_only.nim +++ b/tests/ccgbugs/tforward_decl_only.nim @@ -1,7 +1,7 @@ discard """ ccodecheck: "\\i !@('struct tyObject_MyRefObject'[0-z]+' {')" ccodecheck: "\\i !@('mymoduleInit')" -ccodecheck: "\\i @('mymoduleDatInit')" +ccodecheck: "\\i @('atmmymoduledotnim_DatInit000')" output: "hello" """ diff --git a/tests/modules/a/module_name_clashes.nim b/tests/modules/a/module_name_clashes.nim new file mode 100644 index 000000000..209526e22 --- /dev/null +++ b/tests/modules/a/module_name_clashes.nim @@ -0,0 +1,8 @@ +# See `tmodule_name_clashes` + +import ../b/module_name_clashes +type A* = object + b*: B + +proc print*(a: A) = + echo repr a diff --git a/tests/modules/b/module_name_clashes.nim b/tests/modules/b/module_name_clashes.nim new file mode 100644 index 000000000..6a10cac33 --- /dev/null +++ b/tests/modules/b/module_name_clashes.nim @@ -0,0 +1,3 @@ +# See `tmodule_name_clashes` + +type B* = object diff --git a/tests/modules/tmodule_name_clashes.nim b/tests/modules/tmodule_name_clashes.nim new file mode 100644 index 000000000..73b166c77 --- /dev/null +++ b/tests/modules/tmodule_name_clashes.nim @@ -0,0 +1,16 @@ +discard """ +targets: "c" +ccodecheck: "\\i @('atmaatsmodule_name_clashesdotnim_DatInit000')" +ccodecheck: "\\i @('atmbatsmodule_name_clashesdotnim_DatInit000')" +joinable: false +""" + +# Test module name clashes within same package. +# This was created to test that module symbol mangling functioned correctly +# for the C backend when there are one or more modules with the same name in +# a package, and more than one of them require module initialization procs. +# I'm not sure of the simplest method to cause the init procs to be generated. + +import a/module_name_clashes + +print A() diff --git a/tests/package/stdlib/stdlib.nimble b/tests/package/stdlib/stdlib.nimble new file mode 100644 index 000000000..e69de29bb diff --git a/tests/package/stdlib/system.nim b/tests/package/stdlib/system.nim new file mode 100644 index 000000000..475f8ec5b --- /dev/null +++ b/tests/package/stdlib/system.nim @@ -0,0 +1,2 @@ +# this module is part of tstdlib_name_not_special +doAssert true \ No newline at end of file diff --git a/tests/package/tstdlib_name_not_special.nim b/tests/package/tstdlib_name_not_special.nim new file mode 100644 index 000000000..e8226a82d --- /dev/null +++ b/tests/package/tstdlib_name_not_special.nim @@ -0,0 +1,3 @@ +# Test whether a another package named 'stdlib' can be imported and used. +# This caused a crash in the past. +import stdlib/system \ No newline at end of file From 4e3eb7414cfedad3d29b2eeab451de4206d91df4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 1 Jun 2022 20:44:26 +0800 Subject: [PATCH 3417/4254] [Minor] remove unused and unnecessary local variable (#19853) --- lib/system/reprjs.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 28935a4ef..f5a0ed3ea 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -115,7 +115,6 @@ proc reprArray(a: pointer, typ: PNimType, # We prepend @ to seq, the C backend prepends the pointer to the seq. result = if typ.kind == tySequence: "@[" else: "[" var len: int = 0 - var i: int = 0 {. emit: "`len` = `a`.length;\n" .} var dereffed: pointer = a From 68aeb4c1a64ce73f38a471372277f5ec788f5a6e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 1 Jun 2022 21:01:17 +0800 Subject: [PATCH 3418/4254] change the type of mangleJsName; fixes CStringConv warnings (#19852) change the type of mangleJsName since mangleJsName is used in macros, there is no need to use cstring. Using cstring may increase conversions and cause warnings. --- lib/js/jsffi.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index ac963eb89..35cbf2864 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -64,7 +64,7 @@ proc validJsName(name: string): bool = if chr notin {'A'..'Z','a'..'z','_','$','0'..'9'}: return false -template mangleJsName(name: cstring): cstring = +template mangleJsName(name: string): string = inc nameCounter "mangledName" & $nameCounter @@ -233,7 +233,7 @@ macro `.`*(obj: JsObject, field: untyped): JsObject = helper(`obj`) else: if not mangledNames.hasKey($field): - mangledNames[$field] = $mangleJsName($field) + mangledNames[$field] = mangleJsName($field) let importString = "#." & mangledNames[$field] result = quote do: proc helper(o: JsObject): JsObject @@ -251,7 +251,7 @@ macro `.=`*(obj: JsObject, field, value: untyped): untyped = helper(`obj`, `value`) else: if not mangledNames.hasKey($field): - mangledNames[$field] = $mangleJsName($field) + mangledNames[$field] = mangleJsName($field) let importString = "#." & mangledNames[$field] & " = #" result = quote do: proc helper(o: JsObject, v: auto) @@ -282,7 +282,7 @@ macro `.()`*(obj: JsObject, importString = "#." & $field & "(@)" else: if not mangledNames.hasKey($field): - mangledNames[$field] = $mangleJsName($field) + mangledNames[$field] = mangleJsName($field) importString = "#." & mangledNames[$field] & "(@)" result = quote: proc helper(o: JsObject): JsObject @@ -302,7 +302,7 @@ macro `.`*[K: cstring, V](obj: JsAssoc[K, V], importString = "#." & $field else: if not mangledNames.hasKey($field): - mangledNames[$field] = $mangleJsName($field) + mangledNames[$field] = mangleJsName($field) importString = "#." & mangledNames[$field] result = quote do: proc helper(o: type(`obj`)): `obj`.V @@ -319,7 +319,7 @@ macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], importString = "#." & $field & " = #" else: if not mangledNames.hasKey($field): - mangledNames[$field] = $mangleJsName($field) + mangledNames[$field] = mangleJsName($field) importString = "#." & mangledNames[$field] & " = #" result = quote do: proc helper(o: type(`obj`), v: `obj`.V) From f7a13f62d634300c3cf68e36dd7926a6a235d52f Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Sat, 4 Jun 2022 00:25:21 -0400 Subject: [PATCH 3419/4254] Stop type aliases from inheriting sfUsed (#19861) Fixes #18201 Co-authored-by: quantimnot --- compiler/ast.nim | 2 +- tests/errmsgs/treportunused.nim | 53 +++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index f8343c1a3..6610a1333 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1506,7 +1506,7 @@ proc assignType*(dest, src: PType) = # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: - dest.sym.flags.incl src.sym.flags-{sfExported} + dest.sym.flags.incl src.sym.flags-{sfUsed, sfExported} if dest.sym.annex == nil: dest.sym.annex = src.sym.annex mergeLoc(dest.sym.loc, src.sym.loc) else: diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim index f5ee79afa..46afe163d 100644 --- a/tests/errmsgs/treportunused.nim +++ b/tests/errmsgs/treportunused.nim @@ -2,19 +2,27 @@ discard """ matrix: "--hint:all:off --hint:XDeclaredButNotUsed" nimoutFull: true nimout: ''' -treportunused.nim(23, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(24, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(25, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(26, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(27, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(28, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(29, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(30, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(31, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(32, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(33, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(37, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] -treportunused.nim(38, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(51, 5) Hint: 'A' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(52, 5) Hint: 'B' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(55, 5) Hint: 'D' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(56, 5) Hint: 'E' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(59, 5) Hint: 'G' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(60, 5) Hint: 'H' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(64, 5) Hint: 'K' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(65, 5) Hint: 'L' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(31, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(32, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(33, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(34, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(35, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(36, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(37, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(38, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(39, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(40, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(41, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(45, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed] +treportunused.nim(46, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed] ''' action: compile """ @@ -36,3 +44,22 @@ type s11 = type(1.2) let `v0.99` = "0.99" `v0.99.99` = "0.99.99" + +block: # bug #18201 + # Test that unused type aliases raise hint XDeclaredButNotUsed. + type + A = int + B = distinct int + + C = object + D = C + E = distinct C + + F = string + G = F + H = distinct F + + J = enum + Foo + K = J + L = distinct J From 4341b06f65396c63eec3689d0f8bb00db26c362f Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Sat, 4 Jun 2022 08:03:03 +0300 Subject: [PATCH 3420/4254] RST: improve simple tables (#19859) * RST: improve simple tables * nim 1.0 gotchas * Still allow legacy boundaries like `----` --- compiler/docgen.nim | 1 + compiler/lineinfos.nim | 2 + doc/apis.rst | 6 +- doc/astspec.txt | 12 +- doc/manual.rst | 2 +- doc/nep1.rst | 6 +- doc/nimdoc.cls | 8 +- doc/niminst.rst | 22 +-- doc/tut1.rst | 6 +- lib/packages/docutils/rst.nim | 223 +++++++++++++++++++++--------- lib/packages/docutils/rstast.nim | 13 ++ lib/packages/docutils/rstgen.nim | 55 +++++--- lib/pure/coro.nim | 4 +- lib/pure/os.nim | 12 +- lib/pure/xmltree.nim | 6 +- tests/stdlib/trst.nim | 229 +++++++++++++++++++++++++++++++ 16 files changed, 487 insertions(+), 120 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f633a57a0..390f44f2e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -232,6 +232,7 @@ template declareClosures = of meExpected: k = errXExpected of meGridTableNotImplemented: k = errRstGridTableNotImplemented of meMarkdownIllformedTable: k = errRstMarkdownIllformedTable + of meIllformedTable: k = errRstIllformedTable of meNewSectionExpected: k = errRstNewSectionExpected of meGeneralParseError: k = errRstGeneralParseError of meInvalidDirective: k = errRstInvalidDirectiveX diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 575be6196..105de1636 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -34,6 +34,7 @@ type errXExpected, errRstGridTableNotImplemented, errRstMarkdownIllformedTable, + errRstIllformedTable, errRstNewSectionExpected, errRstGeneralParseError, errRstInvalidDirectiveX, @@ -106,6 +107,7 @@ const errXExpected: "'$1' expected", errRstGridTableNotImplemented: "grid table is not implemented", errRstMarkdownIllformedTable: "illformed delimiter row of a markdown table", + errRstIllformedTable: "Illformed table: $1", errRstNewSectionExpected: "new section expected $1", errRstGeneralParseError: "general parse error", errRstInvalidDirectiveX: "invalid directive: '$1'", diff --git a/doc/apis.rst b/doc/apis.rst index e8313749d..f0b8c93e5 100644 --- a/doc/apis.rst +++ b/doc/apis.rst @@ -18,9 +18,9 @@ been renamed to fit this scheme. The ultimate goal is that the programmer can *guess* a name. -------------------- ------------ -------------------------------------- +=================== ============ ====================================== English word To use Notes -------------------- ------------ -------------------------------------- +=================== ============ ====================================== initialize initT `init` is used to create a value type `T` new newP `new` is used to create a @@ -82,4 +82,4 @@ literal lit string str identifier ident indentation indent -------------------- ------------ -------------------------------------- +=================== ============ ====================================== diff --git a/doc/astspec.txt b/doc/astspec.txt index 6d3fa1f8c..dbbe2799d 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -50,9 +50,9 @@ A leaf of the AST often corresponds to a terminal symbol in the concrete syntax. Note that the default ``float`` in Nim maps to ``float64`` such that the default AST for a float is ``nnkFloat64Lit`` as below. ------------------ --------------------------------------------- +================= ============================================= Nim expression Corresponding AST ------------------ --------------------------------------------- +================= ============================================= ``42`` ``nnkIntLit(intVal = 42)`` ``42'i8`` ``nnkInt8Lit(intVal = 42)`` ``42'i16`` ``nnkInt16Lit(intVal = 42)`` @@ -72,7 +72,7 @@ Nim expression Corresponding AST ``nil`` ``nnkNilLit()`` ``myIdentifier`` ``nnkIdent(strVal = "myIdentifier")`` ``myIdentifier`` after lookup pass: ``nnkSym(strVal = "myIdentifier", ...)`` ------------------ --------------------------------------------- +================= ============================================= Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes get transferred into ``nnkSym`` nodes. @@ -1211,9 +1211,9 @@ AST: In general, declaring types mirrors this syntax (i.e., ``nnkStaticTy`` for ``static``, etc.). Examples follow (exceptions marked by ``*``): -------------- --------------------------------------------- +============= ============================================= Nim type Corresponding AST -------------- --------------------------------------------- +============= ============================================= ``static`` ``nnkStaticTy`` ``tuple`` ``nnkTupleTy`` ``var`` ``nnkVarTy`` @@ -1226,7 +1226,7 @@ Nim type Corresponding AST ``proc`` ``nnkProcTy`` ``iterator`` ``nnkIteratorTy`` ``object`` ``nnkObjectTy`` -------------- --------------------------------------------- +============= ============================================= Take special care when declaring types as ``proc``. The behavior is similar to ``Procedure declaration``, below, but does not treat ``nnkGenericParams``. diff --git a/doc/manual.rst b/doc/manual.rst index 5ab257fec..82c9f5758 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -363,7 +363,7 @@ contain the following `escape sequences`:idx:\ : ``\\`` `backslash`:idx: ``\"`` `quotation mark`:idx: ``\'`` `apostrophe`:idx: - ``\`` '0'..'9'+ `character with decimal value d`:idx:; + ``\`` '0'..'9'+ `character with decimal value d`:idx:; all decimal digits directly following are used for the character ``\a`` `alert`:idx: diff --git a/doc/nep1.rst b/doc/nep1.rst index 8eb31332f..9627071bf 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -153,9 +153,9 @@ The library uses a simple naming scheme that makes use of common abbreviations to keep the names short but meaningful. -------------------- ------------ -------------------------------------- +=================== ============ ====================================== English word To use Notes -------------------- ------------ -------------------------------------- +=================== ============ ====================================== initialize initFoo initializes a value type `Foo` new newFoo initializes a reference type `Foo` via `new` or a value type `Foo` @@ -220,7 +220,7 @@ literal lit string str identifier ident indentation indent -------------------- ------------ -------------------------------------- +=================== ============ ====================================== Coding Conventions diff --git a/doc/nimdoc.cls b/doc/nimdoc.cls index 271dc5dc9..37039f130 100644 --- a/doc/nimdoc.cls +++ b/doc/nimdoc.cls @@ -63,7 +63,7 @@ \usepackage{scrextend} % for the `addmargin` environment -\usepackage{xcolor} +\usepackage[table]{xcolor} \usepackage[urlbordercolor=blue,linkbordercolor=cyan, pdfborderstyle={/S/U/W 1}]{hyperref} \usepackage{enumitem} % for option list, enumList, and rstfootnote @@ -84,6 +84,11 @@ \definecolor{rstframecolor}{rgb}{0.85, 0.8, 0.6} +\usepackage{booktabs} +\belowrulesep=0ex +\aboverulesep=0ex +\renewcommand{\arraystretch}{1.1} + \newtcolorbox{rstprebox}[1][]{blanker, breakable, left=3mm, right=3mm, top=1mm, bottom=1mm, borderline ={0.1em}{0pt}{rstframecolor}, @@ -127,6 +132,7 @@ \newenvironment{rstoptlist}{% \begin{description}[font=\sffamily\bfseries,style=nextline,leftmargin=\rstoptleftmargin,labelwidth=\rstoptlabelwidth]}{\end{description}} +\usepackage{multirow} \usepackage{tabulary} % tables with adjustable cell width and no overflow % make tabulary prevent overflows (https://tex.stackexchange.com/a/195088) \tymin=60pt diff --git a/doc/niminst.rst b/doc/niminst.rst index 8fff1f0e8..2da8664a9 100644 --- a/doc/niminst.rst +++ b/doc/niminst.rst @@ -49,20 +49,20 @@ contain the following key-value pairs: ==================== ======================================================= Key description ==================== ======================================================= -`Name` the project's name; this needs to be a single word -`DisplayName` the project's long name; this can contain spaces. If +`Name` the project's name; this needs to be a single word +`DisplayName` the project's long name; this can contain spaces. If not specified, this is the same as `Name`. -`Version` the project's version -`OS` the OSes to generate C code for; for example: +`Version` the project's version +`OS` the OSes to generate C code for; for example: `"windows;linux;macosx"` -`CPU` the CPUs to generate C code for; for example: +`CPU` the CPUs to generate C code for; for example: `"i386;amd64;powerpc"` -`Authors` the project's authors -`Description` the project's description -`App` the application's type: "Console" or "GUI". If +`Authors` the project's authors +`Description` the project's description +`App` the application's type: "Console" or "GUI". If "Console", niminst generates a special batch file for Windows to open up the command-line shell. -`License` the filename of the application's license +`License` the filename of the application's license ==================== ======================================================= @@ -149,9 +149,9 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -`InstallScript` boolean flag whether an installation shell script +`InstallScript` boolean flag whether an installation shell script should be generated. Example: `InstallScript: "Yes"` -`UninstallScript` boolean flag whether a de-installation shell script +`UninstallScript` boolean flag whether a de-installation shell script should be generated. Example: `UninstallScript: "Yes"` ==================== ======================================================= diff --git a/doc/tut1.rst b/doc/tut1.rst index 405df57b1..66a4c3274 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1185,9 +1185,9 @@ subranges) are called ordinal types. Ordinal types have quite a few special operations: ------------------ -------------------------------------------------------- +================= ======================================================== Operation Comment ------------------ -------------------------------------------------------- +================= ======================================================== `ord(x)` returns the integer value that is used to represent `x`'s value `inc(x)` increments `x` by one @@ -1198,7 +1198,7 @@ Operation Comment `succ(x, n)` returns the `n`'th successor of `x` `pred(x)` returns the predecessor of `x` `pred(x, n)` returns the `n`'th predecessor of `x` ------------------ -------------------------------------------------------- +================= ======================================================== The `inc `_, `dec `_, `succ diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index d4bfae48f..cd5f26278 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -255,6 +255,7 @@ type meExpected = "'$1' expected", meGridTableNotImplemented = "grid table is not implemented", meMarkdownIllformedTable = "illformed delimiter row of a Markdown table", + meIllformedTable = "Illformed table: $1", meNewSectionExpected = "new section expected $1", meGeneralParseError = "general parse error", meInvalidDirective = "invalid directive: '$1'", @@ -2467,81 +2468,175 @@ proc parseOverline(p: var RstParser): PRstNode = anchorType=headlineAnchor) type - IntSeq = seq[int] - ColumnLimits = tuple + ColSpec = object + start, stop: int + RstCols = seq[ColSpec] + ColumnLimits = tuple # for Markdown first, last: int ColSeq = seq[ColumnLimits] -proc tokEnd(p: RstParser): int = - result = currentTok(p).col + currentTok(p).symbol.len - 1 +proc tokStart(p: RstParser, idx: int): int = + result = p.tok[idx].col -proc getColumns(p: var RstParser, cols: var IntSeq) = +proc tokStart(p: RstParser): int = + result = tokStart(p, p.idx) + +proc tokEnd(p: RstParser, idx: int): int = + result = p.tok[idx].col + p.tok[idx].symbol.len - 1 + +proc tokEnd(p: RstParser): int = + result = tokEnd(p, p.idx) + +proc getColumns(p: RstParser, cols: var RstCols, startIdx: int): int = + # Fills table column specification (or separator) `cols` and returns + # the next parser index after it. var L = 0 + result = startIdx while true: inc L setLen(cols, L) - cols[L - 1] = tokEnd(p) - assert(currentTok(p).kind == tkAdornment) - inc p.idx - if currentTok(p).kind != tkWhite: break - inc p.idx - if currentTok(p).kind != tkAdornment: break - if currentTok(p).kind == tkIndent: inc p.idx - # last column has no limit: - cols[L - 1] = 32000 + cols[L - 1].start = tokStart(p, result) + cols[L - 1].stop = tokEnd(p, result) + assert(p.tok[result].kind == tkAdornment) + inc result + if p.tok[result].kind != tkWhite: break + inc result + if p.tok[result].kind != tkAdornment: break + if p.tok[result].kind == tkIndent: inc result + +proc checkColumns(p: RstParser, cols: RstCols) = + var + i = p.idx + col = 0 + if p.tok[i].symbol[0] != '=': + rstMessage(p, mwRstStyle, + "only tables with `=` columns specification are allowed") + for col in 0 ..< cols.len: + if tokEnd(p, i) != cols[col].stop: + rstMessage(p, meIllformedTable, + "end of table column #$1 should end at position $2" % [ + $(col+1), $(cols[col].stop+ColRstOffset)], + p.tok[i].line, tokEnd(p, i)) + inc i + if col == cols.len - 1: + if p.tok[i].kind == tkWhite: + inc i + if p.tok[i].kind notin {tkIndent, tkEof}: + rstMessage(p, meIllformedTable, "extraneous column specification") + elif p.tok[i].kind == tkWhite: + inc i + else: + rstMessage(p, meIllformedTable, "no enough table columns", + p.tok[i].line, p.tok[i].col) + +proc getSpans(p: RstParser, nextLine: int, + cols: RstCols, unitedCols: RstCols): seq[int] = + ## Calculates how many columns a joined cell occupies. + if unitedCols.len > 0: + result = newSeq[int](unitedCols.len) + var + iCell = 0 + jCell = 0 + uCell = 0 + while jCell < cols.len: + if cols[jCell].stop < unitedCols[uCell].stop: + inc jCell + elif cols[jCell].stop == unitedCols[uCell].stop: + result[uCell] = jCell - iCell + 1 + iCell = jCell + 1 + jCell = jCell + 1 + inc uCell + else: + rstMessage(p, meIllformedTable, + "spanning underline does not match main table columns", + p.tok[nextLine].line, p.tok[nextLine].col) + +proc parseSimpleTableRow(p: var RstParser, cols: RstCols, colChar: char): PRstNode = + ## Parses 1 row in RST simple table. + # Consider that columns may be spanning (united by using underline like ----): + let nextLine = tokenAfterNewline(p) + var unitedCols: RstCols + var afterSpan: int + if p.tok[nextLine].kind == tkAdornment and p.tok[nextLine].symbol[0] == '-': + afterSpan = getColumns(p, unitedCols, nextLine) + if unitedCols == cols and p.tok[nextLine].symbol[0] == colChar: + # legacy rst.nim compat.: allow punctuation like `----` in main boundaries + afterSpan = nextLine + unitedCols.setLen 0 + else: + afterSpan = nextLine + template colEnd(i): int = + if i == cols.len - 1: high(int) # last column has no limit + elif unitedCols.len > 0: unitedCols[i].stop else: cols[i].stop + template colStart(i): int = + if unitedCols.len > 0: unitedCols[i].start else: cols[i].start + var row = newSeq[string](if unitedCols.len > 0: unitedCols.len else: cols.len) + var spans: seq[int] = getSpans(p, nextLine, cols, unitedCols) + + let line = currentTok(p).line + # Iterate over the lines a single cell may span: + while true: + var nCell = 0 + # distribute tokens between cells in the current line: + while currentTok(p).kind notin {tkIndent, tkEof}: + if tokEnd(p) <= colEnd(nCell): + if tokStart(p) < colStart(nCell): + if currentTok(p).kind != tkWhite: + rstMessage(p, meIllformedTable, + "this word crosses table column from the left") + else: + inc p.idx + else: + row[nCell].add(currentTok(p).symbol) + inc p.idx + else: + if tokStart(p) < colEnd(nCell) and currentTok(p).kind != tkWhite: + rstMessage(p, meIllformedTable, + "this word crosses table column from the right") + inc nCell + if currentTok(p).kind == tkIndent: inc p.idx + if tokEnd(p) <= colEnd(0): break + # Continued current cells because the 1st column is empty. + if currentTok(p).kind in {tkEof, tkAdornment}: + break + for nCell in countup(1, high(row)): row[nCell].add('\n') + result = newRstNode(rnTableRow) + var q: RstParser + for uCell in 0 ..< row.len: + initParser(q, p.s) + q.col = colStart(uCell) + q.line = line - 1 + getTokens(row[uCell], q.tok) + let cell = newRstNode(rnTableDataCell) + cell.span = if spans.len == 0: 0 else: spans[uCell] + cell.add(parseDoc(q)) + result.add(cell) + if afterSpan > p.idx: + p.idx = afterSpan proc parseSimpleTable(p: var RstParser): PRstNode = - var - cols: IntSeq - row: seq[string] - i, last, line: int - c: char - q: RstParser - a, b: PRstNode + var cols: RstCols result = newRstNodeA(p, rnTable) - cols = @[] - row = @[] - a = nil - c = currentTok(p).symbol[0] + let startIdx = getColumns(p, cols, p.idx) + let colChar = currentTok(p).symbol[0] + checkColumns(p, cols) + p.idx = startIdx + result.colCount = cols.len while true: if currentTok(p).kind == tkAdornment: - last = tokenAfterNewline(p) - if p.tok[last].kind in {tkEof, tkIndent}: + checkColumns(p, cols) + p.idx = tokenAfterNewline(p) + if currentTok(p).kind in {tkEof, tkIndent}: # skip last adornment line: - p.idx = last break - getColumns(p, cols) - setLen(row, cols.len) - if a != nil: - for j in 0 ..< a.len: # fix rnTableDataCell -> rnTableHeaderCell - a.sons[j] = newRstNode(rnTableHeaderCell, a.sons[j].sons) + if result.sons.len > 0: result.sons[^1].endsHeader = true + # fix rnTableDataCell -> rnTableHeaderCell for previous table rows: + for nRow in 0 ..< result.sons.len: + for nCell in 0 ..< result.sons[nRow].len: + result.sons[nRow].sons[nCell].kind = rnTableHeaderCell if currentTok(p).kind == tkEof: break - for j in countup(0, high(row)): row[j] = "" - # the following while loop iterates over the lines a single cell may span: - line = currentTok(p).line - while true: - i = 0 - while currentTok(p).kind notin {tkIndent, tkEof}: - if tokEnd(p) <= cols[i]: - row[i].add(currentTok(p).symbol) - inc p.idx - else: - if currentTok(p).kind == tkWhite: inc p.idx - inc i - if currentTok(p).kind == tkIndent: inc p.idx - if tokEnd(p) <= cols[0]: break - if currentTok(p).kind in {tkEof, tkAdornment}: break - for j in countup(1, high(row)): row[j].add('\n') - a = newRstNode(rnTableRow) - for j in countup(0, high(row)): - initParser(q, p.s) - q.col = cols[j] - q.line = line - 1 - getTokens(row[j], q.tok) - b = newRstNode(rnTableDataCell) - b.add(parseDoc(q)) - a.add(b) - result.add(a) + let tabRow = parseSimpleTableRow(p, cols, colChar) + result.add tabRow proc readTableRow(p: var RstParser): ColSeq = if currentTok(p).symbol == "|": inc p.idx @@ -2574,17 +2669,16 @@ proc isValidDelimiterRow(p: var RstParser, colNum: int): bool = proc parseMarkdownTable(p: var RstParser): PRstNode = var row: ColSeq - colNum: int a, b: PRstNode q: RstParser result = newRstNodeA(p, rnMarkdownTable) proc parseRow(p: var RstParser, cellKind: RstNodeKind, result: PRstNode) = row = readTableRow(p) - if colNum == 0: colNum = row.len # table header - elif row.len < colNum: row.setLen(colNum) + if result.colCount == 0: result.colCount = row.len # table header + elif row.len < result.colCount: row.setLen(result.colCount) a = newRstNode(rnTableRow) - for j in 0 ..< colNum: + for j in 0 ..< result.colCount: b = newRstNode(cellKind) initParser(q, p.s) q.col = p.col @@ -2595,7 +2689,8 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = result.add(a) parseRow(p, rnTableHeaderCell, result) - if not isValidDelimiterRow(p, colNum): rstMessage(p, meMarkdownIllformedTable) + if not isValidDelimiterRow(p, result.colCount): + rstMessage(p, meMarkdownIllformedTable) while predNL(p) and currentTok(p).symbol == "|": parseRow(p, rnTableDataCell, result) diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 1d5da5e1c..bf0bc1be5 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -112,6 +112,12 @@ type ## nodes that are post-processed after parsing of rnNimdocRef: tooltip*: string + of rnTable, rnGridTable, rnMarkdownTable: + colCount*: int ## Number of (not-united) cells in the table + of rnTableRow: + endsHeader*: bool ## Is last row in the header of table? + of rnTableHeaderCell, rnTableDataCell: + span*: int ## Number of table columns that the cell occupies else: discard anchor*: string ## anchor, internal link target @@ -416,6 +422,13 @@ proc treeRepr*(node: PRstNode, indent=0): string = result.add (if node.order == 0: "" else: " order=" & $node.order) of rnMarkdownBlockQuoteItem: result.add " quotationDepth=" & $node.quotationDepth + of rnTable, rnGridTable, rnMarkdownTable: + result.add " colCount=" & $node.colCount + of rnTableHeaderCell, rnTableDataCell: + if node.span > 0: + result.add " span=" & $node.span + of rnTableRow: + if node.endsHeader: result.add " endsHeader" else: discard result.add (if node.anchor == "": "" else: " anchor='" & node.anchor & "'") diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index d662a667c..8eb4be675 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1091,10 +1091,6 @@ proc renderContainer(d: PDoc, n: PRstNode, result: var string) = else: dispA(d.target, result, "
      $2
      ", "$2", [arg, tmp]) -proc texColumns(n: PRstNode): string = - let nColumns = if n.sons.len > 0: len(n.sons[0]) else: 1 - result = "L".repeat(nColumns) - proc renderField(d: PDoc, n: PRstNode, result: var string) = var b = false if d.target == outLatex: @@ -1323,24 +1319,49 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "$1", "\n$2\n\\begin{rsttab}{" & - texColumns(n) & "}\n\\hline\n$1\\end{rsttab}", result) + "L".repeat(n.colCount) & "}\n\\toprule\n$1" & + "\\addlinespace[0.1em]\\bottomrule\n\\end{rsttab}", result) of rnTableRow: if len(n) >= 1: - if d.target == outLatex: - #var tmp = "" - renderRstToOut(d, n.sons[0], result) - for i in countup(1, len(n) - 1): - result.add(" & ") - renderRstToOut(d, n.sons[i], result) - result.add("\\\\\n\\hline\n") - else: + case d.target + of outHtml: result.add("") renderAux(d, n, result) result.add("\n") - of rnTableDataCell: - renderAux(d, n, "$1", "$1", result) - of rnTableHeaderCell: - renderAux(d, n, "$1", "\\textbf{$1}", result) + of outLatex: + if n.sons[0].kind == rnTableHeaderCell: + result.add "\\rowcolor{gray!15} " + var spanLines: seq[(int, int)] + var nCell = 0 + for uCell in 0 .. n.len - 1: + renderRstToOut(d, n.sons[uCell], result) + if n.sons[uCell].span > 0: + spanLines.add (nCell + 1, nCell + n.sons[uCell].span) + nCell += n.sons[uCell].span + else: + nCell += 1 + if uCell != n.len - 1: + result.add(" & ") + result.add("\\\\") + if n.endsHeader: result.add("\\midrule\n") + for (start, stop) in spanLines: + result.add("\\cmidrule(lr){$1-$2}" % [$start, $stop]) + result.add("\n") + of rnTableHeaderCell, rnTableDataCell: + case d.target + of outHtml: + let tag = if n.kind == rnTableHeaderCell: "th" else: "td" + var spanSpec: string + if n.span <= 1: spanSpec = "" + else: + spanSpec = " colspan=\"" & $n.span & "\" style=\"text-align: center\"" + renderAux(d, n, "<$1$2>$$1" % [tag, spanSpec], "", result) + of outLatex: + let text = if n.kind == rnTableHeaderCell: "\\textbf{$1}" else: "$1" + var latexStr: string + if n.span <= 1: latexStr = text + else: latexStr = "\\multicolumn{" & $n.span & "}{c}{" & text & "}" + renderAux(d, n, "", latexStr, result) of rnFootnoteGroup: renderAux(d, n, "
      " & diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index f4495a536..aaf442a83 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -8,11 +8,11 @@ # ## Nim coroutines implementation, supports several context switching methods: -## -------- ------------ +## ======== ============ ## ucontext available on unix and alike (default) ## setjmp available on unix and alike (x86/64 only) ## fibers available and required on windows. -## -------- ------------ +## ======== ============ ## ## -d:nimCoroutines Required to build this module. ## -d:nimCoroutinesUcontext Use ucontext backend. diff --git a/lib/pure/os.nim b/lib/pure/os.nim index fa379a228..247a0d089 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2383,21 +2383,21 @@ iterator walkDirRec*(dir: string, ## ## Walking is recursive. `followFilter` controls the behaviour of the iterator: ## - ## --------------------- --------------------------------------------- + ## ===================== ============================================= ## yieldFilter meaning - ## --------------------- --------------------------------------------- + ## ===================== ============================================= ## ``pcFile`` yield real files (default) ## ``pcLinkToFile`` yield symbolic links to files ## ``pcDir`` yield real directories ## ``pcLinkToDir`` yield symbolic links to directories - ## --------------------- --------------------------------------------- + ## ===================== ============================================= ## - ## --------------------- --------------------------------------------- + ## ===================== ============================================= ## followFilter meaning - ## --------------------- --------------------------------------------- + ## ===================== ============================================= ## ``pcDir`` follow real directories (default) ## ``pcLinkToDir`` follow symbolic links to directories - ## --------------------- --------------------------------------------- + ## ===================== ============================================= ## ## ## See also: diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index fdb2c3fc5..9a9ecde57 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -552,15 +552,15 @@ proc escape*(s: string): string = ## ## Escapes these characters: ## - ## ------------ ------------------- + ## ============ =================== ## char is converted to - ## ------------ ------------------- + ## ============ =================== ## ``<`` ``<`` ## ``>`` ``>`` ## ``&`` ``&`` ## ``"`` ``"`` ## ``'`` ``'`` - ## ------------ ------------------- + ## ============ =================== ## ## You can also use `addEscaped proc <#addEscaped,string,string>`_. result = newStringOfCap(s.len) diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 9787c13eb..24bc03027 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -3,6 +3,8 @@ discard """ [Suite] RST parsing +[Suite] RST tables + [Suite] RST indentation [Suite] Warnings @@ -618,6 +620,233 @@ suite "RST parsing": rnLeaf 'code' """) +suite "RST tables": + + test "formatting in tables works": + check( + dedent""" + ========= === + `build` `a` + ========= === + """.toAst == + dedent""" + rnTable colCount=2 + rnTableRow + rnTableDataCell + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf 'build' + rnTableDataCell + rnInlineCode + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf 'a' + """) + + test "tables with slightly overflowed cells cause an error (1)": + var error = new string + check( + dedent""" + ====== ====== + Inputs Output + ====== ====== + """.toAst(error=error) == "") + check(error[] == "input(2, 2) Error: Illformed table: " & + "this word crosses table column from the right") + + test "tables with slightly overflowed cells cause an error (2)": + var error = new string + check("" == dedent""" + ===== ===== ====== + Input Output + ===== ===== ====== + False False False + ===== ===== ====== + """.toAst(error=error)) + check(error[] == "input(2, 8) Error: Illformed table: " & + "this word crosses table column from the right") + + test "tables with slightly underflowed cells cause an error": + var error = new string + check("" == dedent""" + ===== ===== ====== + Input Output + ===== ===== ====== + False False False + ===== ===== ====== + """.toAst(error=error)) + check(error[] == "input(2, 7) Error: Illformed table: " & + "this word crosses table column from the left") + + test "tables with unequal underlines should be reported (1)": + var error = new string + error[] = "none" + check("" == dedent""" + ===== ====== + Input Output + ===== ====== + False False + ===== ======= + """.toAst(error=error)) + check(error[] == "input(5, 14) Error: Illformed table: " & + "end of table column #2 should end at position 13") + + test "tables with unequal underlines should be reported (2)": + var error = new string + check("" == dedent""" + ===== ====== + Input Output + ===== ======= + False False + ===== ====== + """.toAst(error=error)) + check(error[] == "input(3, 14) Error: Illformed table: " & + "end of table column #2 should end at position 13") + + test "tables with empty first cells": + check( + dedent""" + = = = + x y z + t + = = = + """.toAst == + dedent""" + rnTable colCount=3 + rnTableRow + rnTableDataCell + rnLeaf 'x' + rnTableDataCell + rnInner + rnLeaf 'y' + rnLeaf ' ' + rnTableDataCell + rnInner + rnLeaf 'z' + rnLeaf ' ' + rnLeaf 't' + """) + + test "tables with spanning cells & separators": + check( + dedent""" + ===== ===== ====== + Inputs Output + ------------ ------ + A B A or B + ===== ===== ====== + False False False + True False True + ----- ----- ------ + False True True + True True True + ===== ===== ====== + """.toAst == + dedent""" + rnTable colCount=3 + rnTableRow + rnTableHeaderCell span=2 + rnLeaf 'Inputs' + rnTableHeaderCell span=1 + rnLeaf 'Output' + rnTableRow endsHeader + rnTableHeaderCell + rnLeaf 'A' + rnTableHeaderCell + rnLeaf 'B' + rnTableHeaderCell + rnInner + rnLeaf 'A' + rnLeaf ' ' + rnLeaf 'or' + rnLeaf ' ' + rnLeaf 'B' + rnTableRow + rnTableDataCell + rnLeaf 'False' + rnTableDataCell + rnLeaf 'False' + rnTableDataCell + rnLeaf 'False' + rnTableRow + rnTableDataCell span=1 + rnLeaf 'True' + rnTableDataCell span=1 + rnLeaf 'False' + rnTableDataCell span=1 + rnLeaf 'True' + rnTableRow + rnTableDataCell + rnLeaf 'False' + rnTableDataCell + rnLeaf 'True' + rnTableDataCell + rnLeaf 'True' + rnTableRow + rnTableDataCell + rnLeaf 'True' + rnTableDataCell + rnLeaf 'True' + rnTableDataCell + rnLeaf 'True' + """) + + test "tables with spanning cells with uneqal underlines cause an error": + var error = new string + check( + dedent""" + ===== ===== ====== + Inputs Output + ------------- ------ + A B A or B + ===== ===== ====== + """.toAst(error=error) == "") + check(error[] == "input(3, 1) Error: Illformed table: " & + "spanning underline does not match main table columns") + + let expTable = dedent""" + rnTable colCount=2 + rnTableRow + rnTableDataCell + rnLeaf 'Inputs' + rnTableDataCell + rnLeaf 'Output' + """ + + test "only tables with `=` columns specs are allowed (1)": + var warnings = new seq[string] + check( + dedent""" + ------ ------ + Inputs Output + ------ ------ + """.toAst(warnings=warnings) == + expTable) + check(warnings[] == + @["input(1, 1) Warning: RST style: " & + "only tables with `=` columns specification are allowed", + "input(3, 1) Warning: RST style: " & + "only tables with `=` columns specification are allowed"]) + + test "only tables with `=` columns specs are allowed (2)": + var warnings = new seq[string] + check( + dedent""" + ====== ====== + Inputs Output + ~~~~~~ ~~~~~~ + """.toAst(warnings=warnings) == + expTable) + check(warnings[] == + @["input(3, 1) Warning: RST style: "& + "only tables with `=` columns specification are allowed"]) + + suite "RST indentation": test "nested bullet lists": let input = dedent """ From d0232f0e5b97b697a640c2f622c7596ce6d10eb5 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 4 Jun 2022 02:03:25 -0300 Subject: [PATCH 3421/4254] Add Microtasks (#19860) * Add Microtasks * Add Microtasks --- changelog.md | 2 +- lib/js/jscore.nim | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 9548f3034..2ae64d543 100644 --- a/changelog.md +++ b/changelog.md @@ -50,7 +50,7 @@ becomes an alias for `addr`. - Removed deprecated `std/dom_extensions`. - Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. - Remove deprecated `osproc.poDemon`, symbol with typo. - +- Added [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) for JavaScript targets. - Deprecated `selfExe` for Nimscript. diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 4518f32ce..e6060535b 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -132,3 +132,8 @@ since (1, 7): var arrai = @[1, 2, 3] assert arrai.shift() == 1 assert arrai == @[2, 3] + + func queueMicrotask*(function: proc) {.importjs: "$1(#)".} = + ## * https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask + ## * https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide + runnableExamples: queueMicrotask(proc() = echo "Microtask") From b024a45163ce1a2224ec5891c81cf2cc7d399f11 Mon Sep 17 00:00:00 2001 From: Zoom Date: Tue, 7 Jun 2022 08:35:06 +0000 Subject: [PATCH 3422/4254] Fix `find` routines' api to default to `last=-1` (#19761) This changes the default for the `last` parameter of various `find` routines from `0` to `-1`. Previous default prevents limiting the search to the first character. This is a logic error, as full text search was performed for 2 *valid* values of `last`: `0` and `last.high()`. Adds an overload for `initSkipTable` which returns a newly initialized table. This encapsulates every single usage of a `var`-acting original func in this module. Co-authored-by: flywind --- lib/pure/strutils.nim | 91 +++++++++++++++++++++----------------- tests/stdlib/tstrutils.nim | 42 ++++++++++-------- 2 files changed, 73 insertions(+), 60 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index b98bd2bec..ffbefd0fb 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1815,6 +1815,7 @@ func initSkipTable*(a: var SkipTable, sub: string) {.rtl, ## Initializes table `a` for efficient search of substring `sub`. ## ## See also: + ## * `initSkipTable func<#initSkipTable,string>`_ ## * `find func<#find,SkipTable,string,string,Natural,int>`_ # TODO: this should be the `default()` initializer for the type. let m = len(sub) @@ -1823,7 +1824,16 @@ func initSkipTable*(a: var SkipTable, sub: string) {.rtl, for i in 0 ..< m - 1: a[sub[i]] = m - 1 - i -func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. +func initSkipTable*(sub: string): SkipTable {.noinit, rtl, + extern: "nsuInitNewSkipTable".} = + ## Returns a new table initialized for `sub`. + ## + ## See also: + ## * `initSkipTable func<#initSkipTable,SkipTable,string>`_ + ## * `find func<#find,SkipTable,string,string,Natural,int>`_ + initSkipTable(result, sub) + +func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = -1): int {. rtl, extern: "nsuFindStrA".} = ## Searches for `sub` in `s` inside range `start..last` using preprocessed ## table `a`. If `last` is unspecified, it defaults to `s.high` (the last @@ -1832,9 +1842,10 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## ## See also: + ## * `initSkipTable func<#initSkipTable,string>`_ ## * `initSkipTable func<#initSkipTable,SkipTable,string>`_ let - last = if last == 0: s.high else: last + last = if last < 0: s.high else: last subLast = sub.len - 1 if subLast == -1: @@ -1844,6 +1855,7 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. # This is an implementation of the Boyer-Moore Horspool algorithms # https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm + result = -1 var skip = start while last - skip >= subLast: @@ -1853,7 +1865,6 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {. return skip dec i inc skip, a[s[skip + subLast]] - return -1 when not (defined(js) or defined(nimdoc) or defined(nimscript)): func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. @@ -1865,10 +1876,10 @@ when not (defined(js) or defined(nimdoc) or defined(nimscript)): else: const hasCStringBuiltin = false -func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, +func find*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, extern: "nsuFindChar".} = ## Searches for `sub` in `s` inside range `start..last` (both ends included). - ## If `last` is unspecified, it defaults to `s.high` (the last element). + ## If `last` is unspecified or negative, it defaults to `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. @@ -1877,26 +1888,30 @@ func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl, ## See also: ## * `rfind func<#rfind,string,char,Natural,int>`_ ## * `replace func<#replace,string,char,char>`_ - let last = if last == 0: s.high else: last - when nimvm: + result = -1 + let last = if last < 0: s.high else: last + + template findImpl = for i in int(start)..last: - if sub == s[i]: return i + if s[i] == sub: + return i + + when nimvm: + findImpl() else: when hasCStringBuiltin: - let L = last-start+1 - if L > 0: - let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](L)) + let length = last-start+1 + if length > 0: + let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](length)) if not found.isNil: return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: - for i in int(start)..last: - if sub == s[i]: return i - return -1 + findImpl() -func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. +func find*(s: string, chars: set[char], start: Natural = 0, last = -1): int {. rtl, extern: "nsuFindCharSet".} = ## Searches for `chars` in `s` inside range `start..last` (both ends included). - ## If `last` is unspecified, it defaults to `s.high` (the last element). + ## If `last` is unspecified or negative, it defaults to `s.high` (the last element). ## ## If `s` contains none of the characters in `chars`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. @@ -1905,15 +1920,16 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {. ## See also: ## * `rfind func<#rfind,string,set[char],Natural,int>`_ ## * `multiReplace func<#multiReplace,string,varargs[]>`_ - let last = if last == 0: s.high else: last + result = -1 + let last = if last < 0: s.high else: last for i in int(start)..last: - if s[i] in chars: return i - return -1 + if s[i] in chars: + return i -func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, +func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, extern: "nsuFindStr".} = ## Searches for `sub` in `s` inside range `start..last` (both ends included). - ## If `last` is unspecified, it defaults to `s.high` (the last element). + ## If `last` is unspecified or negative, it defaults to `s.high` (the last element). ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. ## Otherwise the index returned is relative to `s[0]`, not `start`. @@ -1925,28 +1941,23 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl, if sub.len > s.len - start: return -1 if sub.len == 1: return find(s, sub[0], start, last) - template useSkipTable {.dirty.} = - var a {.noinit.}: SkipTable - initSkipTable(a, sub) - result = find(a, s, sub, start, last) + template useSkipTable = + result = find(initSkipTable(sub), s, sub, start, last) - when not hasCStringBuiltin: + when nimvm: useSkipTable() else: - when nimvm: - useSkipTable() - else: - when hasCStringBuiltin: - if last == 0 and s.len > start: - let found = c_strstr(s[start].unsafeAddr, sub) - if not found.isNil: - result = cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) + when hasCStringBuiltin: + if last < 0 and start < s.len: + let found = c_strstr(s[start].unsafeAddr, sub) + result = if not found.isNil: + cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: - result = -1 - else: - useSkipTable() + -1 else: useSkipTable() + else: + useSkipTable() func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, extern: "nsuRFindChar".} = @@ -2121,8 +2132,7 @@ func replace*(s, sub: string, by = ""): string {.rtl, # copy the rest: add result, substr(s, i) else: - var a {.noinit.}: SkipTable - initSkipTable(a, sub) + var a = initSkipTable(sub) let last = s.high var i = 0 while true: @@ -2162,9 +2172,8 @@ func replaceWord*(s, sub: string, by = ""): string {.rtl, ## replaced. if sub.len == 0: return s const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} - var a {.noinit.}: SkipTable result = "" - initSkipTable(a, sub) + var a = initSkipTable(sub) var i = 0 let last = s.high let sublen = sub.len diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 26fc0c7b0..e17277ef2 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -232,18 +232,22 @@ template main() = {.pop.} block: # find - doAssert "0123456789ABCDEFGH".find('A') == 10 - doAssert "0123456789ABCDEFGH".find('A', 5) == 10 - doAssert "0123456789ABCDEFGH".find('A', 5, 10) == 10 - doAssert "0123456789ABCDEFGH".find('A', 5, 9) == -1 - doAssert "0123456789ABCDEFGH".find("A") == 10 - doAssert "0123456789ABCDEFGH".find("A", 5) == 10 - doAssert "0123456789ABCDEFGH".find("A", 5, 10) == 10 - doAssert "0123456789ABCDEFGH".find("A", 5, 9) == -1 - doAssert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 - doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 - doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 - doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 + const haystack: string = "0123456789ABCDEFGH" + doAssert haystack.find('A') == 10 + doAssert haystack.find('A', 5) == 10 + doAssert haystack.find('A', 5, 10) == 10 + doAssert haystack.find('A', 5, 9) == -1 + doAssert haystack.find("A") == 10 + doAssert haystack.find("A", 5) == 10 + doAssert haystack.find("A", 5, 10) == 10 + doAssert haystack.find("A", 5, 9) == -1 + doAssert haystack.find({'A'..'C'}) == 10 + doAssert haystack.find({'A'..'C'}, 5) == 10 + doAssert haystack.find({'A'..'C'}, 5, 10) == 10 + doAssert haystack.find({'A'..'C'}, 5, 9) == -1 + doAssert haystack.find('A', 0, 0) == -1 # search limited to the first char + doAssert haystack.find('A', 5, 0) == -1 # last < start + doAssert haystack.find('A', 5, 4) == -1 # last < start block: const haystack: string = "ABCABABABABCAB" @@ -290,17 +294,17 @@ template main() = # when last <= start, searching for non-empty string block: - let last: int = -1 - doAssert "abcd".find("ab", start=0, last=last) == -1 - doAssert "abcd".find("ab", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=1, last=last) == -1 - doAssert "abcd".find("bc", start=2, last=last) == -1 - block: - let last: int = 0 + let last: int = -1 # searching through whole line doAssert "abcd".find("ab", start=0, last=last) == 0 doAssert "abcd".find("ab", start=1, last=last) == -1 doAssert "abcd".find("bc", start=1, last=last) == 1 doAssert "abcd".find("bc", start=2, last=last) == -1 + block: + let last: int = 0 + doAssert "abcd".find("ab", start=0, last=last) == -1 + doAssert "abcd".find("ab", start=1, last=last) == -1 + doAssert "abcd".find("bc", start=1, last=last) == -1 + doAssert "abcd".find("bc", start=2, last=last) == -1 block: let last: int = 1 doAssert "abcd".find("ab", start=0, last=last) == 0 From f2b16c490df858328cbd884ff9ca9d1a675a4a31 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 8 Jun 2022 11:10:52 -0300 Subject: [PATCH 3423/4254] Add Microtasks docs (#19870) * Add Microtasks * Add Microtasks * Workaround to build js docs in older NodeJS versions --- lib/js/jscore.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index e6060535b..781e8fd57 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -136,4 +136,4 @@ since (1, 7): func queueMicrotask*(function: proc) {.importjs: "$1(#)".} = ## * https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask ## * https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide - runnableExamples: queueMicrotask(proc() = echo "Microtask") + runnableExamples"-r:off": queueMicrotask(proc() = echo "Microtask") From e1702ae1e6da5bf560d7b692bcd5fa513ece8a69 Mon Sep 17 00:00:00 2001 From: Zoom Date: Wed, 8 Jun 2022 14:11:22 +0000 Subject: [PATCH 3424/4254] `changelog.md`: Add `strutils.find` changes (#19868) Added `strutils.find` changes Standard library section restructured to group by `changed/added/deprecated/removed` with paragraphs marked by markdown comments. --- changelog.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/changelog.md b/changelog.md index 2ae64d543..356ee9263 100644 --- a/changelog.md +++ b/changelog.md @@ -24,35 +24,39 @@ becomes an alias for `addr`. ## Standard library additions and changes -- `macros.parseExpr` and `macros.parseStmt` now accept an optional +[//]: # "Changes:" +- `macros.parseExpr` and `macros.parseStmt` now accept an optional. filename argument for more informative errors. - Module `colors` expanded with missing colors from the CSS color standard. - Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). - `md5` now works at compile time and in JavaScript. - - `std/smtp` sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. +- Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. +- `strutils.find` now use and default to `last=-1` for whole string searches, making limiting it to just the first char (`last=0`) valid. +[//]: # "Additions:" - Added `IsoWeekRange`, a range type to represent the number of weeks in an ISO week-based year. - Added `IsoYear`, a distinct int type to prevent bugs from confusing the week-based year and the regular year. - Added `initDateTime` in `times` to create a datetime from a weekday, and ISO 8601 week number and week-based year. - Added `getIsoWeekAndYear` in `times` to get an ISO week number along with the corresponding ISO week-based year from a datetime. - Added `getIsoWeeksInYear` in `times` to return the number of weeks in an ISO week-based year. -- Added [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) for JavaScript targets. - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - Added `sep` parameter in `std/uri` to specify the query separator. -- Removed deprecated `oids.oidToString`. -- Remove define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. - -- Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. -- Removed deprecated `jsre.test` and `jsre.toString`. -- Removed deprecated `math.c_frexp`. -- Removed deprecated ``` httpcore.`==` ```. -- Removed deprecated `std/dom_extensions`. -- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. -- Remove deprecated `osproc.poDemon`, symbol with typo. +- Added [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) for JavaScript targets. - Added [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) for JavaScript targets. + +[//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. +[//]: # "Removals:" +- Removed deprecated `oids.oidToString`. +- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. +- Removed deprecated `jsre.test` and `jsre.toString`. +- Removed deprecated `math.c_frexp`. +- Removed deprecated `` httpcore.`==` ``. +- Removed deprecated `std/dom_extensions`. +- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. +- Removed deprecated `osproc.poDemon`, symbol with typo. ## Language changes From 415689323c625afb7d39d923c4165a541beb9927 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 9 Jun 2022 00:17:25 +0800 Subject: [PATCH 3425/4254] clarify how to restart CI (#19845) --- doc/contributing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/contributing.rst b/doc/contributing.rst index d3b2770f3..0ca0d0cbc 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -539,6 +539,7 @@ Debugging CI failures, flaky tests, etc 2. If CI failure seems unrelated to your PR, it could be caused by a flaky test. File a bug for it if it isn't already reported. A PR push (or opening/closing PR) will re-trigger all CI jobs (even successful ones, which can be wasteful). Instead, + request collaboration from the Nim team. The Nim team should follow these instructions to only restart the jobs that failed: * Azure: if on your own fork, it's possible from inside azure console From 836b95c896087a3f24bedad9bc1bcb2c5db1c5a8 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Thu, 9 Jun 2022 09:27:31 +0300 Subject: [PATCH 3426/4254] Deprecate std/sums (#18439) * Deprecate sums * Update changelog.md * Update lib/std/sums.nim * log * format * remove * Update changelog.md Co-authored-by: sandytypical <43030857+xflywind@users.noreply.github.com> --- changelog.md | 2 ++ lib/std/sums.nim | 2 ++ 2 files changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 356ee9263..6bd3c99e3 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,8 @@ or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). Nim uses `Math.trunc` for the division and modulo operators for integers. +- Deprecated `std/sums`. + - Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via `experimental:flexibleOptionalParams`. diff --git a/lib/std/sums.nim b/lib/std/sums.nim index b68858ef7..a6ce1b85d 100644 --- a/lib/std/sums.nim +++ b/lib/std/sums.nim @@ -8,6 +8,8 @@ ## Accurate summation functions. +{.deprecated: "use the nimble package `sums` instead.".} + runnableExamples: import std/math From 25d89269eb7fe7ebed142f2d3136959db11c9f02 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 9 Jun 2022 14:21:18 +0200 Subject: [PATCH 3427/4254] give a better error message for some template expansions (#19871) --- compiler/semstmts.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 3513fd767..0516d08ce 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -140,7 +140,9 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) = n[0] = result elif result.typ.kind != tyError and c.config.cmd != cmdInteractive: var n = result - while n.kind in skipForDiscardable: n = n.lastSon + while n.kind in skipForDiscardable: + if n.kind == nkTryStmt: n = n[0] + else: n = n.lastSon var s = "expression '" & $n & "' is of type '" & result.typ.typeToString & "' and has to be used (or discarded)" if result.info.line != n.info.line or @@ -483,7 +485,7 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode = for i in 0 ..< pragmas.len: let it = pragmas[i] let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it - + when false: let lhs = b[0] let clash = strTableGet(c.currentScope.symbols, lhs.ident) From 1972005439306a12088400ef338c40c3d3c2ce28 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 9 Jun 2022 22:51:17 +0800 Subject: [PATCH 3428/4254] fix #19862; make widestrs consistent between refc and orc (#19874) [backport] fix #19862; make widestrs consistent in refc and orc --- lib/system/widestrs.nim | 3 +++ tests/arc/t19862.nim | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/arc/t19862.nim diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 8b08959b5..bb348fd67 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -224,3 +224,6 @@ when defined(nimv2): proc `$`*(s: WideCStringObj): string = $(s.data) + + proc len*(w: WideCStringObj): int {.inline.} = + len(w.data) diff --git a/tests/arc/t19862.nim b/tests/arc/t19862.nim new file mode 100644 index 000000000..f7146ec26 --- /dev/null +++ b/tests/arc/t19862.nim @@ -0,0 +1,13 @@ +discard """ + matrix: "--gc:refc; --gc:arc" +""" + +# bug #19862 +type NewString = object + +proc len(s: NewString): int = 10 + +converter toNewString(x: WideCStringObj): NewString = discard + +let w = newWideCString("test") +doAssert len(w) == 4 From eefca1b81f334a5ccdb7d180de5b6a9969f12793 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 10 Jun 2022 21:24:28 +0800 Subject: [PATCH 3429/4254] not generate initStackBottomWith in arc/orc [backport] (#19875) not generate initStackBottomWith in arc/orc --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 8d24f30c5..862f31107 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2094,7 +2094,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = discard cgsym(m, "rawWrite") # raise dependencies on behalf of genMainProc - if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone: + if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: discard cgsym(m, "initStackBottomWith") if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: discard cgsym(m, "initThreadVarsEmulation") From 8cde6ba6bcf236478f1d5d5aa722977ce9723a57 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 11 Jun 2022 02:32:27 +0800 Subject: [PATCH 3430/4254] remove noop option `gc:v2` (#19810) * remove noop option gc:v2 * changelog --- changelog.md | 2 ++ compiler/ccgstmts.nim | 2 +- compiler/ccgtypes.nim | 4 ++-- compiler/commands.nim | 2 -- compiler/options.nim | 1 - lib/system/sysstr.nim | 14 ++------------ 6 files changed, 7 insertions(+), 18 deletions(-) diff --git a/changelog.md b/changelog.md index 6bd3c99e3..98655eaa3 100644 --- a/changelog.md +++ b/changelog.md @@ -24,6 +24,8 @@ becomes an alias for `addr`. - io is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/syncio`. +- The `gc:v2` option is removed. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 240fa55c8..e791318ee 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -16,7 +16,7 @@ const # above X strings a hash-switch for strings is generated proc getTraverseProc(p: BProc, v: PSym): Rope = - if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcV2, gcRefc} and + if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcRefc} and optOwnedRefs notin p.config.globalOptions and containsGarbageCollectedRef(v.loc.t): # we register a specialized marked proc here; this has the advantage diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index c5b4d3857..7c26db40d 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1483,12 +1483,12 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = genTupleInfo(m, x, x, result, info) of tySequence: genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}: + if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcGo}: let markerProc = genTraverseProc(m, origType, sig) m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) of tyRef: genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}: + if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcGo}: let markerProc = genTraverseProc(m, origType, sig) m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) diff --git a/compiler/commands.nim b/compiler/commands.nim index 2e08ad615..31e637aba 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -262,7 +262,6 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo of "go": result = conf.selectedGC == gcGo of "none": result = conf.selectedGC == gcNone of "stack", "regions": result = conf.selectedGC == gcRegions - of "v2", "generational": warningOptionNoop(arg) else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "opt": case arg.normalize @@ -568,7 +567,6 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass, unregisterArcOrc(conf) conf.selectedGC = gcRegions defineSymbol(conf.symbols, "gcregions") - of "v2": warningOptionNoop(arg) else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; diff --git a/compiler/options.nim b/compiler/options.nim index 545dfb1d1..89fb66d5f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -183,7 +183,6 @@ type gcMarkAndSweep = "markAndSweep" gcHooks = "hooks" gcRefc = "refc" - gcV2 = "v2" gcGo = "go" # gcRefc and the GCs that follow it use a write barrier, # as far as usesWriteBarrier() is concerned diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 49fff41e9..c4f0db718 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -304,20 +304,10 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS when not defined(boehmGC) and not defined(nogc) and not defined(gcMarkAndSweep) and not defined(gogc) and not defined(gcRegions): - when false: # deadcode: was used by `compileOption("gc", "v2")` + if ntfNoRefs notin extGetCellType(result).base.flags: for i in newLen..result.len-1: - let len0 = gch.tempStack.len forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), - extGetCellType(result).base, waPush) - let len1 = gch.tempStack.len - for i in len0 ..< len1: - doDecRef(gch.tempStack.d[i], LocalHeap, MaybeCyclic) - gch.tempStack.len = len0 - else: - if ntfNoRefs notin extGetCellType(result).base.flags: - for i in newLen..result.len-1: - forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), - extGetCellType(result).base, waZctDecRef) + extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out # cell is aliased by another pointer (ie proc parameter or a let variable). From 1e5dd9022b0d86d63d616431a0f9959ca4c10f40 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 11 Jun 2022 02:33:44 +0800 Subject: [PATCH 3431/4254] [js] add testcase for array indexDefect and remove todo (#19838) * remove unused opcSubstr * [js] add testcase for array indexDefect * Revert "remove unused opcSubstr" This reverts commit cb461f2545234d62c1e0b83318f3e5495c97de52. --- lib/system/jssys.nim | 4 ---- tests/js/tindexdefect.nim | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 tests/js/tindexdefect.nim diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 00a4a8ab6..a31de0d86 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -731,10 +731,6 @@ proc parseFloatNative(a: string): float = `result` = Number(`a2`); """ -#[ -xxx how come code like this doesn't give IndexDefect ? -let z = s[10000] == 'a' -]# proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int {.compilerproc.} = var sign: bool var i = start diff --git a/tests/js/tindexdefect.nim b/tests/js/tindexdefect.nim new file mode 100644 index 000000000..37994ec2e --- /dev/null +++ b/tests/js/tindexdefect.nim @@ -0,0 +1,9 @@ +discard """ + outputsub: "unhandled exception: index 10000 not in 0 .. 0 [IndexDefect]" + exitcode: 1 + joinable: false +""" + +var s = ['a'] +let z = s[10000] == 'a' +echo z \ No newline at end of file From 6f4bacff67e2e219ef914e24d9f9aaf34a6d1eb1 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Fri, 10 Jun 2022 14:40:08 -0400 Subject: [PATCH 3432/4254] Extend and document compiler debugging utilities (#19841) * Add two debugutils procs that native debuggers can break on use to execute commands when code of interest is being compiled. * Add GDB and LLDB programs to disable and enable breakpoints and watchpoints when code of interest is being compiled. * Extend the `intern.rst` docs regarding debugging the compiler. Co-authored-by: quantimnot --- compiler/debugutils.nim | 16 +++ doc/intern.rst | 222 +++++++++++++++++++++++++++++++++------- doc/koch.rst | 3 + tools/compiler.gdb | 39 +++++++ tools/compiler.lldb | 40 ++++++++ 5 files changed, 281 insertions(+), 39 deletions(-) create mode 100644 tools/compiler.gdb create mode 100644 tools/compiler.lldb diff --git a/compiler/debugutils.nim b/compiler/debugutils.nim index d109d2121..adbb0517f 100644 --- a/compiler/debugutils.nim +++ b/compiler/debugutils.nim @@ -54,3 +54,19 @@ proc isCompilerDebug*(): bool = {.undef(nimCompilerDebug).} echo 'x' conf0.isDefined("nimCompilerDebug") + +proc enteringDebugSection*() {.exportc, dynlib.} = + ## Provides a way for native debuggers to enable breakpoints, watchpoints, etc + ## when code of interest is being compiled. + ## + ## Set your debugger to break on entering `nimCompilerIsEnteringDebugSection` + ## and then execute a desired command. + discard + +proc exitingDebugSection*() {.exportc, dynlib.} = + ## Provides a way for native debuggers to disable breakpoints, watchpoints, etc + ## when code of interest is no longer being compiled. + ## + ## Set your debugger to break on entering `exitingDebugSection` + ## and then execute a desired command. + discard diff --git a/doc/intern.rst b/doc/intern.rst index 4ca7eff20..9103c694c 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -79,55 +79,216 @@ Set the compilation timestamp with the `SOURCE_DATE_EPOCH` environment variable. koch boot # or `./build_all.sh` -Developing the compiler -======================= +Debugging the compiler +====================== -To create a new compiler for each run, use `koch temp`:cmd:\: + +Bisecting for regressions +------------------------- + +There are often times when there is a bug that is caused by a regression in the +compiler or stdlib. Bisecting the Nim repo commits is a usefull tool to identify +what commit introduced the regression. + +Even if it's not known whether a bug is caused by a regression, bisection can reduce +debugging time by ruling it out. If the bug is found to be a regression, then you +focus on the changes introduced by that one specific commit. + +`koch temp`:cmd: returns 125 as the exit code in case the compiler +compilation fails. This exit code tells `git bisect`:cmd: to skip the +current commit: .. code:: cmd - koch temp c test.nim + git bisect start bad-commit good-commit + git bisect run ./koch temp -r c test-source.nim -`koch temp`:cmd: creates a debug build of the compiler, which is useful -to create stacktraces for compiler debugging. +You can also bisect using custom options to build the compiler, for example if +you don't need a debug version of the compiler (which runs slower), you can replace +`./koch temp`:cmd: by explicit compilation command, see `Bootstrapping the compiler`_. -You can of course use GDB or Visual Studio to debug the -compiler (via `--debuginfo --lineDir:on`:option:). However, there -are also lots of procs that aid in debugging: +Building an instrumented compiler +--------------------------------- + +Considering that a useful method of debugging the compiler is inserting debug +logging, or changing code and then observing the outcome of a testcase, it is +fastest to build a compiler that is instrumented for debugging from an +existing release build. `koch temp`:cmd: provides a convenient method of doing +just that. + +By default running `koch temp`:cmd: will build a lean version of the compiler +with `-d:debug`:option: enabled. The compiler is written to `bin/nim_temp` by +default. A lean version of the compiler lacks JS and documentation generation. + +`bin/nim_temp` can be directly used to run testcases, or used with testament +with `testament --nim:bin/nim_temp r tests/category/tsometest`:cmd:. + +`koch temp`:cmd: will build the temporary compiler with the `-d:debug`:option: +enabled. Here are compiler options that are of interest for debugging: + +* `-d:debug`:option:\: enables `assert` statements and stacktraces and all + runtime checks +* `--opt:speed`:option:\: build with optimizations enabled +* `--debugger:native`:option:\: enables `--debuginfo --lineDir:on`:option: for using + a native debugger like GDB, LLDB or CDB +* `-d:nimDebug`:option: cause calls to `quit` to raise an assertion exception +* `-d:nimDebugUtils`:option:\: enables various debugging utilities; + see `compiler/debugutils` +* `-d:stacktraceMsgs -d:nimCompilerStacktraceHints`:option:\: adds some additional + stacktrace hints; see https://github.com/nim-lang/Nim/pull/13351 +* `-u:leanCompiler`:option:\: enable JS and doc generation + +Another method to build and run the compiler is directly through `koch`:cmd:\: + +.. code:: cmd + + koch temp [options] c test.nim + + # (will build with js support) + koch temp [options] js test.nim + + # (will build with doc support) + koch temp [options] doc test.nim + +Debug logging +------------- + +"Printf debugging" is still the most appropriate way to debug many problems +arising in compiler development. The typical usage of breakpoints to debug +the code is often less practical, because almost all of the code paths in the +compiler will be executed hundreds of times before a particular section of the +tested program is reached where the newly developed code must be activated. + +To work-around this problem, you'll typically introduce an if statement in the +compiler code detecting more precisely the conditions where the tested feature +is being used. One very common way to achieve this is to use the `mdbg` condition, +which will be true only in contexts, processing expressions and statements from +the currently compiled main module: .. code-block:: nim - # dealing with PNode: - echo renderTree(someNode) - debug(someNode) # some JSON representation + # inside some compiler module + if mdbg: + debug someAstNode - # dealing with PType: +Using the `isCompilerDebug`:nim: condition along with inserting some statements +into the testcase provides more granular logging: + +.. code-block:: nim + + # compilermodule.nim + if isCompilerDebug(): + debug someAstNode + + # testcase.nim + proc main = + {.define(nimCompilerDebug).} + let a = 2.5 * 3 + {.undef(nimCompilerDebug).} + +Logging can also be scoped to a specific filename as well. This will of course +match against every module with that name. + +.. code-block:: nim + + if `??`(conf, n.info, "module.nim"): + debug(n) + +The above examples also makes use of the `debug`:nim: proc, which is able to +print a human-readable form of an arbitrary AST tree. Other common ways to print +information about the internal compiler types include: + +.. code-block:: nim + + # pretty print PNode + + # pretty prints the Nim ast + echo renderTree(someNode) + + # pretty prints the Nim ast, but annotates symbol IDs + echo renderTree(someNode, {renderIds}) + + # pretty print ast as JSON + debug(someNode) + + # print as YAML + echo treeToYaml(config, someNode) + + + # pretty print PType + + # print type name echo typeToString(someType) + + # pretty print as JSON debug(someType) - # dealing with PSym: + # print as YAML + echo typeToYaml(config, someType) + + + # pretty print PSym + + # print the symbol's name echo symbol.name.s + + # pretty print as JSON debug(symbol) - # pretty prints the Nim ast, but annotates symbol IDs: - echo renderTree(someNode, {renderIds}) - if `??`(conf, n.info, "temp.nim"): - # only output when it comes from "temp.nim" - echo renderTree(n) - if `??`(conf, n.info, "temp.nim"): - # why does it process temp.nim here? - writeStackTrace() + # print as YAML + echo symToYaml(config, symbol) + + + # pretty print TLineInfo + lineInfoToStr(lineInfo) + + + # print the structure of any type + repr(someVar) + +Here are some other helpful utilities: + +.. code-block:: nim + + # how did execution reach this location? + writeStackTrace() These procs may not already be imported by the module you're editing. You can import them directly for debugging: .. code-block:: nim + from astalgo import debug from types import typeToString from renderer import renderTree from msgs import `??` +Native debugging +---------------- + +Stepping through the compiler with a native debugger is a very powerful tool to +both learn and debug it. However, there is still the need to constrain when +breakpoints are triggered. The same methods as in `Debug logging`_ can be applied +here when combined with calls to the debug helpers `enteringDebugSection()`:nim: +and `exitingDebugSection()`:nim:. + +#. Compile the temp compiler with `--debugger:native -d:nimDebugUtils`:option: +#. Set your desired breakpoints or watchpoints. +#. Configure your debugger: + * GDB: execute `source tools/compiler.gdb` at startup + * LLDB execute `command source tools/compiler.lldb` at startup +#. Use one of the scoping helpers like so: + +.. code-block:: nim + + if isCompilerDebug(): + enteringDebugSection() + else: + exitingDebugSection() + +A caveat of this method is that all breakpoints and watchpoints are enabled or +disabled. Also, due to a bug, only breakpoints can be constrained for LLDB. The compiler's architecture =========================== @@ -152,23 +313,6 @@ for the type definitions. The `macros `_ module contains many examples how the AST represents each syntactic structure. -Bisecting for regressions -========================= - -`koch temp`:cmd: returns 125 as the exit code in case the compiler -compilation fails. This exit code tells `git bisect`:cmd: to skip the -current commit: - -.. code:: cmd - - git bisect start bad-commit good-commit - git bisect run ./koch temp -r c test-source.nim - -You can also bisect using custom options to build the compiler, for example if -you don't need a debug version of the compiler (which runs slower), you can replace -`./koch temp`:cmd: by explicit compilation command, see `Bootstrapping the compiler`_. - - Runtimes ======== diff --git a/doc/koch.rst b/doc/koch.rst index b8d85dff4..91dd5d570 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -38,6 +38,9 @@ options: unless you are debugging the compiler. -d:nimUseLinenoise Use the linenoise library for interactive mode (not needed on Windows). +-d:leanCompiler Produce a compiler without JS codegen or + documentation generator in order to use less RAM + for bootstrapping. After compilation is finished you will hopefully end up with the nim compiler in the `bin` directory. You can add Nim's `bin` directory to diff --git a/tools/compiler.gdb b/tools/compiler.gdb new file mode 100644 index 000000000..c81f47152 --- /dev/null +++ b/tools/compiler.gdb @@ -0,0 +1,39 @@ +# create a breakpoint on `debugutils.enteringDebugSection` +define enable_enteringDebugSection + break -function enteringDebugSection + # run these commands once breakpoint enteringDebugSection is hit + command + # enable all breakpoints and watchpoints + enable + # continue execution + cont + end +end + +# create a breakpoint on `debugutils.exitingDebugSection` named exitingDebugSection +define enable_exitingDebugSection + break -function exitingDebugSection + # run these commands once breakpoint exitingDebugSection is hit + command + # disable all breakpoints and watchpoints + disable + # but enable the enteringDebugSection breakpoint + enable_enteringDebugSection + # continue execution + cont + end +end + +# some commands can't be set until the process is running, so set an entry breakpoint +break -function NimMain +# run these commands once breakpoint NimMain is hit +command + # disable all breakpoints and watchpoints + disable + # but enable the enteringDebugSection breakpoint + enable_enteringDebugSection + # no longer need this breakpoint + delete -function NimMain + # continue execution + cont +end diff --git a/tools/compiler.lldb b/tools/compiler.lldb new file mode 100644 index 000000000..e0b375055 --- /dev/null +++ b/tools/compiler.lldb @@ -0,0 +1,40 @@ +# create a breakpoint on `debugutils.enteringDebugSection` named enteringDebugSection +breakpoint set -n 'enteringDebugSection' -N enteringDebugSection +# run these commands once breakpoint enteringDebugSection is hit +breakpoint command add enteringDebugSection + # enable all breakpoints + breakpoint enable + # enable all watchpoints + # watchpoint enable # FIXME: not currently working for unknown reason + # continue execution + continue +DONE + +# create a breakpoint on `debugutils.exitingDebugSection` named exitingDebugSection +breakpoint set -n 'exitingDebugSection' -N exitingDebugSection +# run these commands once breakpoint exitingDebugSection is hit +breakpoint command add exitingDebugSection + # disable all breakpoints + breakpoint disable + # disable all watchpoints + # watchpoint disable # FIXME: not currently working for unknown reason + breakpoint enable enteringDebugSection + # continue execution + continue +DONE + +# some commands can't be set until the process is running, so set an entry breakpoint +breakpoint set -n NimMain -N NimMain +# run these commands once breakpoint NimMain is hit +breakpoint command add NimMain + # disable all breakpoints + breakpoint disable + # disable all watchpoints + # watchpoint disable # FIXME: not currently working for unknown reason + # enable the enteringDebugSection breakpoint though + breakpoint enable enteringDebugSection + # no longer need this breakpoint + breakpoint delete NimMain + # continue execution + continue +DONE From ac89eead8a40a1a8ee170a4650a1d47e203da14c Mon Sep 17 00:00:00 2001 From: Bung Date: Sat, 11 Jun 2022 02:40:34 +0800 Subject: [PATCH 3433/4254] test for #19046 (#19839) * test for #19046 * add threads flag --- tests/misc/t19046.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/misc/t19046.nim diff --git a/tests/misc/t19046.nim b/tests/misc/t19046.nim new file mode 100644 index 000000000..b3bfec7ae --- /dev/null +++ b/tests/misc/t19046.nim @@ -0,0 +1,19 @@ +discard """ + targets: "c cpp" + matrix: "--threads:on" + disabled: "win" + disabled: "osx" + action: compile +""" + +# bug #19046 + +import std/os + +var t: Thread[void] + +proc test = discard +proc main = + createThread(t, test) + pinToCpu(t, 1) +main() \ No newline at end of file From e2e663a14389500b07e2f6fcd5c231536bdf76a0 Mon Sep 17 00:00:00 2001 From: Carlo Capocasa Date: Sat, 11 Jun 2022 18:23:31 +0200 Subject: [PATCH 3434/4254] Friendlier error message with solution (#19880) * Add helpful suggestion, should always apply * mention var param limitation in async docs * Update compiler/lambdalifting.nim whoops thanks Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com> --- compiler/lambdalifting.nim | 3 ++- lib/pure/asyncdispatch.nim | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 4b7ca89cd..96edba8c8 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -288,7 +288,8 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = if illegalCapture(s): localError(g.config, n.info, ("'$1' is of type <$2> which cannot be captured as it would violate memory" & - " safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases") % + " safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." & + " Consider using a which can be captured.") % [s.name.s, typeToString(s.typ), g.config$s.info]) elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags): localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 755f59ff7..0d406b271 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -98,6 +98,10 @@ ## `await`. The following section shows different ways that you can handle ## exceptions in async procs. ## +## .. caution:: +## Procedures marked {.async.} do not support mutable parameters such +## as `var int`. References such as `ref int` should be used instead. +## ## Handling Exceptions ## ------------------- ## @@ -192,6 +196,7 @@ ## ================ ## ## * The effect system (`raises: []`) does not work with async procedures. +## * Mutable parameters are not supported by async procedures. ## ## ## Multiple async backend support From 8fa2c0b532be9fdfd7682e5a8cc846b60bd4ea6c Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Mon, 13 Jun 2022 16:03:40 +1000 Subject: [PATCH 3435/4254] Pass headers and body correctly to FetchOptions (#19884) [backport] * Pass headers to FetchOptions Don't pass body if method is HttpGet or HttpHead * Syntax fixes * Restart CI --- lib/std/jsfetch.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/std/jsfetch.nim b/lib/std/jsfetch.nim index 034bb6332..7fe154325 100644 --- a/lib/std/jsfetch.nim +++ b/lib/std/jsfetch.nim @@ -90,8 +90,9 @@ func newfetchOptions*(metod: HttpMethod; body: cstring; headers: Headers = newHeaders()): FetchOptions = ## Constructor for `FetchOptions`. result = FetchOptions( - body: body, mode: cstring($mode), credentials: cstring($credentials), cache: cstring($cache), referrerPolicy: cstring($referrerPolicy), - keepalive: keepalive, redirect: cstring($redirect), referrer: referrer, integrity: integrity, + body: if metod notin {HttpHead, HttpGet}: body else: nil, + mode: cstring($mode), credentials: cstring($credentials), cache: cstring($cache), referrerPolicy: cstring($referrerPolicy), + keepalive: keepalive, redirect: cstring($redirect), referrer: referrer, integrity: integrity, headers: headers, metod: (case metod of HttpHead: "HEAD".cstring of HttpGet: "GET".cstring From 2f4900615ab0c42c9608910dd30a14be52455f91 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 13 Jun 2022 14:10:40 +0800 Subject: [PATCH 3436/4254] [cleanup] remove unnecessary procs in vm (#19888) remove unused procs --- compiler/vm.nim | 1 - compiler/vmgen.nim | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index bbcff77ba..1b11cb4f3 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2252,7 +2252,6 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg = else: var n = x if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n[1] - n = n.canonValue n.flags.incl nfIsRef n.typ = x.typ result = TFullReg(kind: rkNode, node: n) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index dadcc3865..2e7f6d8b0 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -439,14 +439,11 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) = c.gABC(n, opcAsgnInt, dest, tmp) freeTemp(c, tmp) -proc canonValue*(n: PNode): PNode = - result = n - proc rawGenLiteral(c: PCtx; n: PNode): int = result = c.constants.len #assert(n.kind != nkCall) n.flags.incl nfAllConst - c.constants.add n.canonValue + c.constants.add n internalAssert c.config, result < regBxMax proc sameConstant*(a, b: PNode): bool = @@ -1857,7 +1854,7 @@ proc genVarSection(c: PCtx; n: PNode) = else: let sa = getNullValue(s.typ, a.info, c.config) #if s.ast.isNil: getNullValue(s.typ, a.info) - #else: canonValue(s.ast) + #else: s.ast assert sa.kind != nkCall c.globals.add(sa) s.position = c.globals.len From ab477075860364db2690a0411c0b2c330532042f Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 13 Jun 2022 15:01:40 +0800 Subject: [PATCH 3437/4254] [semfold] fix #19199; properly fold uint to float conversion (#19890) [backport] fix #19199; properly fold float conversion --- compiler/semfold.nim | 2 +- tests/vm/t19199.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/vm/t19199.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index d2bbc63be..72c8abaa9 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -409,7 +409,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P rangeCheck(n, getInt(result), g) of tyFloat..tyFloat64: case srcTyp.kind - of tyInt..tyInt64, tyEnum, tyBool, tyChar: + of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar: result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g) else: result = a diff --git a/tests/vm/t19199.nim b/tests/vm/t19199.nim new file mode 100644 index 000000000..6ae48cb54 --- /dev/null +++ b/tests/vm/t19199.nim @@ -0,0 +1,6 @@ +# bug #19199 +proc mikasa(x: float) = doAssert x == 42 + +static: + mikasa 42.uint.float +mikasa 42.uint.float From a4fdaa88ccfa03bf30113ffc194284fcb45d3054 Mon Sep 17 00:00:00 2001 From: Ardek Romak Date: Mon, 13 Jun 2022 10:22:20 +0300 Subject: [PATCH 3438/4254] Correctly import libcrypto functions using dynlib (#19881) --- lib/wrappers/openssl.nim | 72 +++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 00ec160cb..1db3fc239 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -93,6 +93,9 @@ else: import dynlib +{.pragma: lcrypto, cdecl, dynlib: DLLUtilName, importc.} +{.pragma: lssl, cdecl, dynlib: DLLSSLName, importc.} + type SslStruct {.final, pure.} = object SslPtr* = ptr SslStruct @@ -102,7 +105,6 @@ type PSTACK* = SslPtr PX509* = SslPtr PX509_NAME* = SslPtr - PEVP_MD* = SslPtr PBIO_METHOD* = SslPtr BIO* = SslPtr EVP_PKEY* = SslPtr @@ -684,48 +686,48 @@ proc RSA_free*(rsa: PRSA) {.cdecl, dynlib: DLLUtilName, importc.} proc RSA_size*(rsa: PRSA): cint {.cdecl, dynlib: DLLUtilName, importc.} # sha types -proc EVP_md_null*(): EVP_MD {.cdecl, importc.} -proc EVP_md2*(): EVP_MD {.cdecl, importc.} -proc EVP_md4*(): EVP_MD {.cdecl, importc.} -proc EVP_md5*(): EVP_MD {.cdecl, importc.} -proc EVP_sha*(): EVP_MD {.cdecl, importc.} -proc EVP_sha1*(): EVP_MD {.cdecl, importc.} -proc EVP_dss*(): EVP_MD {.cdecl, importc.} -proc EVP_dss1*(): EVP_MD {.cdecl, importc.} -proc EVP_ecdsa*(): EVP_MD {.cdecl, importc.} -proc EVP_sha224*(): EVP_MD {.cdecl, importc.} -proc EVP_sha256*(): EVP_MD {.cdecl, importc.} -proc EVP_sha384*(): EVP_MD {.cdecl, importc.} -proc EVP_sha512*(): EVP_MD {.cdecl, importc.} -proc EVP_mdc2*(): EVP_MD {.cdecl, importc.} -proc EVP_ripemd160*(): EVP_MD {.cdecl, importc.} -proc EVP_whirlpool*(): EVP_MD {.cdecl, importc.} -proc EVP_MD_size*(md: EVP_MD): cint {.cdecl, importc.} +proc EVP_md_null*(): EVP_MD {.lcrypto.} +proc EVP_md2*(): EVP_MD {.lcrypto.} +proc EVP_md4*(): EVP_MD {.lcrypto.} +proc EVP_md5*(): EVP_MD {.lcrypto.} +proc EVP_sha*(): EVP_MD {.lcrypto.} +proc EVP_sha1*(): EVP_MD {.lcrypto.} +proc EVP_dss*(): EVP_MD {.lcrypto.} +proc EVP_dss1*(): EVP_MD {.lcrypto.} +proc EVP_ecdsa*(): EVP_MD {.lcrypto.} +proc EVP_sha224*(): EVP_MD {.lcrypto.} +proc EVP_sha256*(): EVP_MD {.lcrypto.} +proc EVP_sha384*(): EVP_MD {.lcrypto.} +proc EVP_sha512*(): EVP_MD {.lcrypto.} +proc EVP_mdc2*(): EVP_MD {.lcrypto.} +proc EVP_ripemd160*(): EVP_MD {.lcrypto.} +proc EVP_whirlpool*(): EVP_MD {.lcrypto.} +proc EVP_MD_size*(md: EVP_MD): cint {.lcrypto.} # hmac functions -proc HMAC*(evp_md: EVP_MD; key: pointer; key_len: cint; d: cstring; n: csize_t; md: cstring; md_len: ptr cuint): cstring {.cdecl, importc.} +proc HMAC*(evp_md: EVP_MD; key: pointer; key_len: cint; d: cstring; n: csize_t; md: cstring; md_len: ptr cuint): cstring {.lcrypto.} # RSA key functions -proc PEM_read_bio_PrivateKey*(bp: BIO, x: ptr EVP_PKEY, cb: pointer, u: pointer): EVP_PKEY {.cdecl, importc.} -proc EVP_PKEY_free*(p: EVP_PKEY) {.cdecl, importc.} -proc EVP_DigestSignInit*(ctx: EVP_MD_CTX, pctx: ptr EVP_PKEY_CTX, typ: EVP_MD, e: ENGINE, pkey: EVP_PKEY): cint {.cdecl, importc.} -proc EVP_DigestInit_ex*(ctx: EVP_MD_CTX, typ: PEVP_MD, engine: SslPtr = nil): cint {.cdecl, importc.} -proc EVP_DigestUpdate*(ctx: EVP_MD_CTX, data: pointer, len: cuint): cint {.cdecl, importc.} -proc EVP_DigestFinal_ex*(ctx: EVP_MD_CTX, buffer: pointer, size: ptr cuint): cint {.cdecl, importc.} -proc EVP_DigestSignFinal*(ctx: EVP_MD_CTX, data: pointer, len: ptr csize_t): cint {.cdecl, importc.} -proc EVP_PKEY_CTX_new*(pkey: EVP_PKEY, e: ENGINE): EVP_PKEY_CTX {.cdecl, importc.} -proc EVP_PKEY_CTX_free*(pkeyCtx: EVP_PKEY_CTX) {.cdecl, importc.} -proc EVP_PKEY_sign_init*(c: EVP_PKEY_CTX): cint {.cdecl, importc.} +proc PEM_read_bio_PrivateKey*(bp: BIO, x: ptr EVP_PKEY, cb: pointer, u: pointer): EVP_PKEY {.lcrypto.} +proc EVP_PKEY_free*(p: EVP_PKEY) {.lcrypto.} +proc EVP_DigestSignInit*(ctx: EVP_MD_CTX, pctx: ptr EVP_PKEY_CTX, typ: EVP_MD, e: ENGINE, pkey: EVP_PKEY): cint {.lcrypto.} +proc EVP_DigestInit_ex*(ctx: EVP_MD_CTX, typ: EVP_MD, engine: SslPtr = nil): cint {.lcrypto.} +proc EVP_DigestUpdate*(ctx: EVP_MD_CTX, data: pointer, len: cuint): cint {.lcrypto.} +proc EVP_DigestFinal_ex*(ctx: EVP_MD_CTX, buffer: pointer, size: ptr cuint): cint {.lcrypto.} +proc EVP_DigestSignFinal*(ctx: EVP_MD_CTX, data: pointer, len: ptr csize_t): cint {.lcrypto.} +proc EVP_PKEY_CTX_new*(pkey: EVP_PKEY, e: ENGINE): EVP_PKEY_CTX {.lcrypto.} +proc EVP_PKEY_CTX_free*(pkeyCtx: EVP_PKEY_CTX) {.lcrypto.} +proc EVP_PKEY_sign_init*(c: EVP_PKEY_CTX): cint {.lcrypto.} when defined(macosx) or defined(windows): - proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc.} - proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc.} - proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.cdecl, importc.} + proc EVP_MD_CTX_create*(): EVP_MD_CTX {.lcrypto.} + proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.lcrypto.} + proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.lcrypto.} else: # some times you will need this instead: - proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc: "EVP_MD_CTX_new".} - proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc: "EVP_MD_CTX_free".} - proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.cdecl, importc: "EVP_MD_CTX_cleanup".} + proc EVP_MD_CTX_create*(): EVP_MD_CTX {.cdecl, importc: "EVP_MD_CTX_new", dynlib: DLLUtilName.} + proc EVP_MD_CTX_destroy*(ctx: EVP_MD_CTX) {.cdecl, importc: "EVP_MD_CTX_free", dynlib: DLLUtilName.} + proc EVP_MD_CTX_cleanup*(ctx: EVP_MD_CTX): cint {.cdecl, importc: "EVP_MD_CTX_cleanup", dynlib: DLLUtilName.} # type From b41226001ce596fe520fd326a302c6f4e91c2504 Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Mon, 13 Jun 2022 12:33:44 +0300 Subject: [PATCH 3439/4254] Initial implementation of nimsuggest v3 (#19826) * Initial implementation of nimsuggest v3 Rework `nimsuggest` to use caching to make usage of ide commands more efficient. Previously, all commands no matter what the state of the process is were causing clean build. In the context of Language Server Protocol(LSP) and lsp clients this was causing perf issues and overall instability. Overall, the goal of v3 is to fit to LSP Server needs - added two new commands: - `recompile` to do clean compilation - `changed` which can be used by the IDEs to notify that a particular file has been changed. The later can be utilized when using LSP file watches. - `globalSymbols` - searching global references - added `segfaults` dependency to allow fallback to clean build when incremental fails. I wish the error to be propagated to the client so we can work on fixing the incremental build failures (typically hitting pointer) - more efficient rebuild flow. ATM incremental rebuild is triggered when the command needs that(i. e. it is global) while the commands that work on the current source rebuild only it Things missing in this PR: - Documentation - Extensive unit testing. Although functional I still see this more as a POC that this approach can work. Next steps: - Implement `sug` request. - Rework/extend the protocol to allow better client/server communication. Ideally we will need push events, diagnostics should be restructored to allow per file notifications, etc. - implement v3 test suite. - better logging * Add tests for v3 and implement ideSug * Remove typeInstCache/procInstCache cleanup * Add ideChkFile command * Avoid contains call when adding symbol info * Remove log * Remove segfaults --- compiler/modulegraphs.nim | 82 ++++++++++--- compiler/options.nim | 13 +- compiler/passes.nim | 7 +- compiler/suggest.nim | 12 +- nimsuggest/nimsuggest.nim | 242 +++++++++++++++++++++++++++++++++++--- nimsuggest/tester.nim | 5 +- nimsuggest/tests/tv3.nim | 25 ++++ 7 files changed, 349 insertions(+), 37 deletions(-) create mode 100644 nimsuggest/tests/tv3.nim diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 147381910..8294d863e 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -11,7 +11,7 @@ ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -import intsets, tables, hashes, md5_old +import intsets, tables, hashes, md5_old, sequtils import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages import ic / [packed_ast, ic] @@ -83,6 +83,8 @@ type doStopCompile*: proc(): bool {.closure.} usageSym*: PSym # for nimsuggest owners*: seq[PSym] + suggestSymbols*: Table[FileIndex, seq[tuple[sym: PSym, info: TLineInfo]]] + suggestErrors*: Table[FileIndex, seq[Suggest]] methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization! systemModule*: PSym sysTypes*: array[TTypeKind, PType] @@ -385,9 +387,19 @@ when defined(nimfind): c.graph.onDefinitionResolveForward(c.graph, s, info) else: - template onUse*(info: TLineInfo; s: PSym) = discard - template onDef*(info: TLineInfo; s: PSym) = discard - template onDefResolveForward*(info: TLineInfo; s: PSym) = discard + when defined(nimsuggest): + template onUse*(info: TLineInfo; s: PSym) = discard + + template onDef*(info: TLineInfo; s: PSym) = + let c = getPContext() + if c.graph.config.suggestVersion == 3: + suggestSym(c.graph, info, s, c.graph.usageSym) + + template onDefResolveForward*(info: TLineInfo; s: PSym) = discard + else: + template onUse*(info: TLineInfo; s: PSym) = discard + template onDef*(info: TLineInfo; s: PSym) = discard + template onDefResolveForward*(info: TLineInfo; s: PSym) = discard proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = g.doStopCompile != nil and g.doStopCompile() @@ -434,8 +446,7 @@ proc initOperators*(g: ModuleGraph): Operators = result.opNot = createMagic(g, "not", mNot) result.opContains = createMagic(g, "contains", mInSet) -proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = - result = ModuleGraph() +proc initModuleGraphFields(result: ModuleGraph) = # A module ID of -1 means that the symbol is not attached to a module at all, # but to the module graph: result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32) @@ -445,9 +456,9 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.ifaces = @[] result.importStack = @[] result.inclToMod = initTable[FileIndex, FileIndex]() - result.config = config - result.cache = cache result.owners = @[] + result.suggestSymbols = initTable[FileIndex, seq[tuple[sym: PSym, info: TLineInfo]]]() + result.suggestErrors = initTable[FileIndex, seq[Suggest]]() result.methods = @[] initStrTable(result.compilerprocs) initStrTable(result.exposed) @@ -461,6 +472,12 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.operators = initOperators(result) result.emittedTypeInfo = initTable[string, FileIndex]() +proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = + result = ModuleGraph() + result.config = config + result.cache = cache + initModuleGraphFields(result) + proc resetAllModules*(g: ModuleGraph) = initStrTable(g.packageSyms) g.deps = initIntSet() @@ -472,6 +489,7 @@ proc resetAllModules*(g: ModuleGraph) = g.methods = @[] initStrTable(g.compilerprocs) initStrTable(g.exposed) + initModuleGraphFields(g) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = if fileIdx.int32 >= 0: @@ -550,7 +568,19 @@ proc transitiveClosure(g: var IntSet; n: int) = proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) = let m = g.getModule fileIdx - if m != nil: incl m.flags, sfDirty + if m != nil: + g.suggestSymbols.del(fileIdx) + g.suggestErrors.del(fileIdx) + incl m.flags, sfDirty + +proc unmarkAllDirty*(g: ModuleGraph) = + for i in 0i32.. 100: + break + else: + myLog fmt "Discarding {cmd}" + +# v3 end when isMainModule: handleCmdLine(newIdentCache(), newConfigRef()) else: @@ -726,8 +939,9 @@ else: if self.loadConfigsAndProcessCmdLine(cache, conf, graph): mockCommand(graph) if gLogging: + log("Search paths:") for it in conf.searchPaths: - log(it.string) + log(" " & it.string) retval.doStopCompile = proc (): bool = false return NimSuggest(graph: retval, idle: 0, cachedMsgs: @[]) diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 1db33706a..fea0a8d45 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -252,7 +252,10 @@ proc runEpcTest(filename: string): int = for cmd in s.startup: if not runCmd(cmd, s.dest): quit "invalid command: " & cmd - let epccmd = s.cmd.replace("--tester", "--epc --v2 --log") + let epccmd = if s.cmd.contains("--v3"): + s.cmd.replace("--tester", "--epc --log") + else: + s.cmd.replace("--tester", "--epc --v2 --log") let cl = parseCmdLine(epccmd) var p = startProcess(command=cl[0], args=cl[1 .. ^1], options={poStdErrToStdOut, poUsePath, diff --git a/nimsuggest/tests/tv3.nim b/nimsuggest/tests/tv3.nim new file mode 100644 index 000000000..99caa987b --- /dev/null +++ b/nimsuggest/tests/tv3.nim @@ -0,0 +1,25 @@ +# tests v3 + +type + Foo* = ref object of RootObj + bar*: string + +proc test(f: Foo) = + echo f.ba#[!]#r + +discard """ +$nimsuggest --v3 --tester $file +>use $1 +def skField tv3.Foo.bar string $file 5 4 "" 100 +use skField tv3.Foo.bar string $file 8 9 "" 100 +>def $1 +def skField tv3.Foo.bar string $file 5 4 "" 100 +>outline $1 +outline skType tv3.Foo Foo $file 4 2 "" 100 +outline skField tv3.Foo.bar string $file 5 4 "" 100 +outline skProc tv3.test proc (f: Foo){.gcsafe, locks: 0.} $file 7 5 "" 100 +>sug $1 +sug skField bar string $file 5 4 "" 100 Prefix +>globalSymbols test +def skProc tv3.test proc (f: Foo){.gcsafe, locks: 0.} $file 7 5 "" 100 +""" From 251bdc1d5aed98fccb31677dda3c3ead9be2f6bf Mon Sep 17 00:00:00 2001 From: Tanguy Date: Tue, 14 Jun 2022 12:37:31 +0200 Subject: [PATCH 3440/4254] Windows: enable nimRawSetjmp by default [backport] (#19891) * Windows: enable nimRawSetjmp by default See #19197. The default setjmp can randomly segfault on windows * Attempt to disable the flag for bootstraping * Disable styleCheck for c_setjmp --- config/config.nims | 5 +++++ lib/system/ansi_c.nim | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/config/config.nims b/config/config.nims index 08d9d9f55..b50181eaf 100644 --- a/config/config.nims +++ b/config/config.nims @@ -20,5 +20,10 @@ when defined(nimStrictMode): switch("hintAsError", "ConvFromXtoItselfNotNeeded") # future work: XDeclaredButNotUsed +when defined(windows) and not defined(booting): + # Avoid some rare stack corruption while using exceptions with a SEH-enabled + # toolchain: https://github.com/nim-lang/Nim/pull/19197 + switch("define", "nimRawSetjmp") + switch("define", "nimVersion:" & NimVersion) switch("define", "nimPreviewDotLikeOps") diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 23fb9fdef..5d0ecc01c 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -116,6 +116,7 @@ elif defined(nimBuiltinSetjmp): proc c_builtin_setjmp(jmpb: ptr pointer): cint {. importc: "__builtin_setjmp", nodecl.} c_builtin_setjmp(unsafeAddr jmpb[0]) + elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): when defined(windows): # No `_longjmp()` on Windows. @@ -127,10 +128,16 @@ elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): # prone to stack corruption during unwinding, so we disable that by setting # it to NULL. # More details: https://github.com/status-im/nimbus-eth2/issues/3121 + when defined(nimHasStyleChecks): + {.push styleChecks: off.} + proc c_setjmp*(jmpb: C_JmpBuf): cint = proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {. header: "", importc: "_setjmp".} c_setjmp_win(jmpb, nil) + + when defined(nimHasStyleChecks): + {.pop.} else: proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "_longjmp".} From 789b1bcbb60278b335a81df416be1d5a663d7e30 Mon Sep 17 00:00:00 2001 From: Don-Duong Quach Date: Tue, 14 Jun 2022 23:20:34 -0700 Subject: [PATCH 3441/4254] Fixes #19883 so genscript works with vcc (#19893) --- compiler/extccomp.nim | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 515c7ba29..5c074d284 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -434,7 +434,13 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} = # really: Cross compilation from Linux to Linux for example is entirely # reasonable. # `optGenMapping` is included here for niminst. - result = conf.globalOptions * {optGenScript, optGenMapping} != {} + # We use absolute paths for vcc / cl, see issue #19883. + let options = + if conf.cCompiler == ccVcc: + {optGenMapping} + else: + {optGenScript, optGenMapping} + result = conf.globalOptions * options != {} proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string = result = conf.compileOptions @@ -921,7 +927,7 @@ proc callCCompiler*(conf: ConfigRef) = objfiles.add(' ') objfiles.add(quoteShell(objFile)) let mainOutput = if optGenScript notin conf.globalOptions: conf.prepareToWriteOutput - else: AbsoluteFile(conf.projectName) + else: AbsoluteFile(conf.outFile) linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true) extraCmds = getExtraCmds(conf, mainOutput) From e7e8f437c4f95f4f5d038cdddf5036462733288a Mon Sep 17 00:00:00 2001 From: JJ <35242550+j-james@users.noreply.github.com> Date: Wed, 15 Jun 2022 06:40:56 -0700 Subject: [PATCH 3442/4254] Keep the doc sidebar on the screen while scrolling (#19851) * [docgen] Group sidebar sections into
      (open by default) * [docgen] Consistent indentation in generated HTML (this is a boon for working on docgen's html/css output) * [docgen] Move Source/Edit buttons inside main div This makes styling the documentation significantly easier. * [docgen] Somewhat consistent CSS formatting * [docgen] Keep the sidebar onscreen while scrolling * [docgen] Tweak CSS for the sticky sidebar * [docgen] search type=text ==> type=search * [docgen] Update expected doc output * [docgen] Fix Group by Type sidebar placement bug * [docgen] Curse you, whitespace (fix tests) * [docgen] Fix rst2html tests Co-authored-by: sandytypical <43030857+xflywind@users.noreply.github.com> --- config/nimdoc.cfg | 216 ++- doc/nimdoc.css | 164 +- nimdoc/rst2html/expected/rst_examples.html | 85 +- .../expected/index.html | 122 +- .../expected/theindex.html | 24 +- nimdoc/testproject/expected/nimdoc.out.css | 164 +- .../expected/subdir/subdir_b/utils.html | 758 ++++----- nimdoc/testproject/expected/testproject.html | 1454 ++++++++--------- nimdoc/testproject/expected/theindex.html | 24 +- 9 files changed, 1401 insertions(+), 1610 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 4efa1f637..725f9e0a5 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -9,25 +9,28 @@ split.item.toc = "20" doc.section = """
      -

      $sectionTitle

      -
      -$content -
      +

      $sectionTitle

      +
      + $content +
      +
      """ doc.section.toc = """
    • - $sectionTitle -
        - $content -
      +
      + $sectionTitle +
        + $content +
      +
    • """ doc.section.toc2 = """ -
        $plainName - $content -
      +
        $plainName + $content +
      """ # Chunk of HTML emitted for each entry in the HTML table of contents. @@ -47,12 +50,12 @@ doc.section.toc2 = """ doc.item = """
      -
      $header
      -
      -$deprecationMsg -$desc -$seeSrc -
      +
      $header
      +
      + $deprecationMsg + $desc + $seeSrc +
      """ @@ -61,9 +64,8 @@ $seeSrc # * $overloadGroupName - the anchor for this whole group # * $content - string containing `doc.item`s themselves doc.item2 = """ -
      -$content + $content
      """ @@ -73,18 +75,14 @@ $content # This is used for TOC items which are not overloadable (e.g. types). # `$header_plain` would be too verbose here, so we use $name. doc.item.toc = """ -
    • $name
    • +
    • $name
    • """ # This is used for TOC items which are grouped by the same name (e.g. procs). doc.item.tocTable = """ -
    • $header_plain
    • +
    • $header_plain
    • """ - - # HTML rendered for doc.item's seeSrc variable. Note that this will render to # the empty string if you don't pass anything through --git.url. Available # substitutaion variables here are: @@ -94,32 +92,31 @@ doc.item.tocTable = """ # * $line: line of the item in the original source file. # * $url: whatever you did pass through the --git.url switch (which also # gets variables path/line replaced!) -doc.item.seesrc = """  Source -  Edit +doc.item.seesrc = """ +Source   +Edit   """ doc.deprecationmsg = """ -
      - $label $message -
      +
      + $label $message +
      """ doc.toc = """
        -$content + $content
      """ doc.body_toc_groupsection = """ -
      - Group by: - -
      +
      + Group by: + +
      """ @if boot: @@ -130,36 +127,36 @@ doc.body_toc_groupsection = """ doc.body_toc_group = """
      -
      - -     Dark Mode +
      + +     Dark Mode +
      + +
      + Search: +
      + $body_toc_groupsection +
      + $tableofcontents
      - -
      - Search: -
      - $body_toc_groupsection - $tableofcontents -
      - $seeSrc
      -
      - $deprecationMsg -

      $moduledesc

      - $content + $seeSrc + $deprecationMsg +

      $moduledesc

      + $content
      """ @@ -169,39 +166,36 @@ doc.body_toc_group = """ doc.body_toc_group = """
      -
      - -     Dark Mode +
      + +     Dark Mode +
      + +
      + Search: +
      +
      + Group by: + +
      +
      + $tableofcontents
      - -
      - Search: -
      -
      - Group by: - -
      - $tableofcontents -
      - $seeSrc
      -
      - $deprecationMsg -

      $moduledesc

      - $content + $seeSrc + $deprecationMsg +

      $moduledesc

      + $content
      """ @@ -220,14 +214,13 @@ doc.listing_end = "
    " # * $analytics: Google analytics location, includes - -
    -
    -

    $title

    $subtitle - $content -
    +
    +
    +

    $title

    $subtitle + $content
    -
    -$analytics + $analytics """ diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 0014cf196..e72c4a213 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -159,24 +159,28 @@ body { padding: 0; box-sizing: border-box; } -.column, -.columns { +.column, .columns { width: 100%; float: left; box-sizing: border-box; - margin-left: 1%; -} + margin-left: 1%; } -.column:first-child, -.columns:first-child { +.column:first-child, .columns:first-child { margin-left: 0; } +.container .row { + display: flex; } + .three.columns { - width: 22%; -} + width: 25.0%; + height: 100vh; + position: sticky; + top: 0px; + overflow-y: auto; } .nine.columns { - width: 77.0%; } + width: 75.0%; + padding-left: 1.5em; } .twelve.columns { width: 100%; @@ -269,25 +273,26 @@ a.nimdoc { a.toc-backref { text-decoration: none; - color: var(--text); } + color: var(--text); +} a.link-seesrc { color: #607c9f; font-size: 0.9em; - font-style: italic; } + font-style: italic; +} -a:hover, -a:focus { +a:hover, a:focus { color: var(--anchor-focus); - text-decoration: underline; } + text-decoration: underline; +} a:hover span.Identifier { color: var(--anchor); } -sub, -sup { +sub, sup { position: relative; font-size: 75%; line-height: 0; @@ -314,8 +319,7 @@ img { background: transparent !important; box-shadow: none !important; } - a, - a:visited { + a, a:visited { text-decoration: underline; } a[href]:after { @@ -329,16 +333,14 @@ img { a[href^="#"]:after { content: ""; } - pre, - blockquote { + pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; } - tr, - img { + tr, img { page-break-inside: avoid; } img { @@ -353,22 +355,18 @@ img { h1.title { page-break-before: avoid; } - p, - h2, - h3 { + p, h2, h3 { orphans: 3; widows: 3; } - h2, - h3 { + h2, h3 { page-break-after: avoid; } } p { margin-top: 0.5em; - margin-bottom: 0.5em; -} + margin-bottom: 0.5em; } small { font-size: 85%; } @@ -376,8 +374,7 @@ small { strong { font-weight: 600; font-size: 0.95em; - color: var(--strong); -} + color: var(--strong); } em { font-style: italic; } @@ -398,8 +395,7 @@ h1.title { text-align: center; font-weight: 900; margin-top: 0.75em; - margin-bottom: 0em; -} + margin-bottom: 0em; } h2 { font-size: 1.3em; @@ -426,36 +422,29 @@ h6 { font-size: 1.1em; } -ul, -ol { +ul, ol { padding: 0; margin-top: 0.5em; margin-left: 0.75em; } -ul ul, -ul ol, -ol ol, -ol ul { +ul ul, ul ol, ol ol, ol ul { margin-bottom: 0; margin-left: 1.25em; } ul.simple > li { - list-style-type: circle; -} + list-style-type: circle; } ul.simple-boot li { - list-style-type: none; - margin-left: 0em; - margin-bottom: 0.5em; -} + list-style-type: none; + margin-left: 0em; + margin-bottom: 0.5em; } ol.simple > li, ul.simple > li { margin-bottom: 0.2em; margin-left: 0.4em } ul.simple.simple-toc > li { - margin-top: 1em; -} + margin-top: 1em; } ul.simple-toc { list-style: none; @@ -464,8 +453,7 @@ ul.simple-toc { margin-top: 1em; } ul.simple-toc > li { - list-style-type: none; -} + list-style-type: none; } ul.simple-toc-section { list-style-type: circle; @@ -475,12 +463,10 @@ ul.simple-toc-section { ul.nested-toc-section { list-style-type: circle; margin-left: -0.75em; - color: var(--text); -} + color: var(--text); } ul.nested-toc-section > li { - margin-left: 1.25em; -} + margin-left: 1.25em; } ol.arabic { @@ -527,7 +513,8 @@ hr.footnote { margin-top: 0.15em; } div.footnote-group { - margin-left: 1em; } + margin-left: 1em; +} div.footnote-label { display: inline-block; min-width: 1.7em; @@ -611,7 +598,7 @@ pre { border: 1px solid var(--border); -webkit-border-radius: 6px; -moz-border-radius: 6px; - border-radius: 6px; + border-radius: 6px; } .copyToClipBoardBtn { @@ -629,7 +616,7 @@ pre { .copyToClipBoard:hover .copyToClipBoardBtn { visibility: visible; -} +} .pre-scrollable { max-height: 340px; @@ -694,8 +681,8 @@ table th { font-weight: bold; } table th.docinfo-name { - background-color: transparent; - text-align: right; + background-color: transparent; + text-align: right; } table tr:hover { @@ -712,31 +699,31 @@ table.borderless td, table.borderless th { padding: 0 0.5em 0 0 !important; } .admonition { - padding: 0.3em; - background-color: var(--secondary-background); - border-left: 0.4em solid #7f7f84; - margin-bottom: 0.5em; - -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); - -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); - box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + padding: 0.3em; + background-color: var(--secondary-background); + border-left: 0.4em solid #7f7f84; + margin-bottom: 0.5em; + -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); } .admonition-info { - border-color: var(--info-background); + border-color: var(--info-background); } .admonition-info-text { - color: var(--info-background); + color: var(--info-background); } .admonition-warning { - border-color: var(--warning-background); + border-color: var(--warning-background); } .admonition-warning-text { - color: var(--warning-background); + color: var(--warning-background); } .admonition-error { - border-color: var(--error-background); + border-color: var(--error-background); } .admonition-error-text { - color: var(--error-background); + color: var(--error-background); } .first { @@ -770,8 +757,7 @@ div.footer, div.header { font-size: smaller; } div.footer { - padding-top: 5em; -} + padding-top: 5em; } div.line-block { display: block; @@ -790,17 +776,14 @@ div.search_results { background-color: var(--third-background); margin: 3em; padding: 1em; - border: 1px solid #4d4d4d; -} + border: 1px solid #4d4d4d; } div#global-links ul { margin-left: 0; - list-style-type: none; -} + list-style-type: none; } div#global-links > simple-boot { - margin-left: 3em; -} + margin-left: 3em; } hr.docutils { width: 75%; } @@ -980,8 +963,7 @@ span.Directive { span.option { font-weight: bold; font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - color: var(--option); -} + color: var(--option); } span.Prompt { font-weight: bold; @@ -997,11 +979,10 @@ span.program { text-decoration: underline; text-decoration-color: var(--hint); text-decoration-thickness: 0.05em; - text-underline-offset: 0.15em; -} + text-underline-offset: 0.15em; } -span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, -span.Other { +span.Command, span.Rule, span.Hyperlink, +span.Label, span.Reference, span.Other { color: var(--other); } /* Pop type, const, proc, and iterator defs in nim def blocks */ @@ -1039,17 +1020,14 @@ span.pragmadots { border-radius: 4px; margin: 0 2px; cursor: pointer; - font-size: 0.8em; -} + font-size: 0.8em; } span.pragmadots:hover { - background-color: var(--hint); -} + background-color: var(--hint); } + span.pragmawrap { - display: none; -} + display: none; } span.attachedType { display: none; - visibility: hidden; -} + visibility: hidden; } diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 2b5218d9f..532917055 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -1,12 +1,11 @@ - + - + - +Not a Nim Manual @@ -17,45 +16,42 @@ -Not a Nim Manual + - -
    -
    -

    Not a Nim Manual

    -
    +
    +
    +

    Not a Nim Manual

    +
    -
    - -     Dark Mode -
    - -
    - Search: -
    -
    - Group by: - -
    -
    -
    -
    - -

    + + +

    Authors:Andreas Rumpf, Zahary Karadjov
    Authors:Andreas Rumpf, Zahary Karadjov
    Version:|nimversion|

    "Complexity" seems to be a lot like "energy": you can transfer it from the end-user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran

    @@ -262,19 +257,17 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements F2 without pipe

    not in table

    - +
    -
    -
    - + diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index c6a116bd6..0c0dc2268 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -1,12 +1,11 @@ - + - + - +nimdoc/test_out_index_dot_html/foo @@ -17,94 +16,89 @@ -nimdoc/test_out_index_dot_html/foo + - -
    -
    -

    nimdoc/test_out_index_dot_html/foo

    -
    +
    +
    +

    nimdoc/test_out_index_dot_html/foo

    +
    -
    - -     Dark Mode -
    - -
    - Search: -
    -
    - Group by: - -
    -
      -
    • - Procs -
        +
        + +     Dark Mode +
        + +
        + Search: +
        +
        + Group by: + +
        +
        + +
      +
    -
    -
    - -

    -
    -

    Procs

    -
    - -
    -
    -
    proc foo() {....raises: [], tags: [].}
    -
    - -I do foo - -
    + + +

    +
    +

    Procs

    +
    +
    +
    +
    proc foo() {....raises: [], tags: [].}
    +
    + + I do foo + +
    -
    +
    +
    -
    -
    - + diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index 8ee62a330..00c81189e 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -1,12 +1,11 @@ - + - + - +Index @@ -17,31 +16,28 @@ -Index + - -
    -
    -

    Index

    - Modules: index.

    API symbols

    +
    +
    +

    Index

    + Modules: index.

    API symbols

    foo:
    -
    -
    - + diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 0014cf196..e72c4a213 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -159,24 +159,28 @@ body { padding: 0; box-sizing: border-box; } -.column, -.columns { +.column, .columns { width: 100%; float: left; box-sizing: border-box; - margin-left: 1%; -} + margin-left: 1%; } -.column:first-child, -.columns:first-child { +.column:first-child, .columns:first-child { margin-left: 0; } +.container .row { + display: flex; } + .three.columns { - width: 22%; -} + width: 25.0%; + height: 100vh; + position: sticky; + top: 0px; + overflow-y: auto; } .nine.columns { - width: 77.0%; } + width: 75.0%; + padding-left: 1.5em; } .twelve.columns { width: 100%; @@ -269,25 +273,26 @@ a.nimdoc { a.toc-backref { text-decoration: none; - color: var(--text); } + color: var(--text); +} a.link-seesrc { color: #607c9f; font-size: 0.9em; - font-style: italic; } + font-style: italic; +} -a:hover, -a:focus { +a:hover, a:focus { color: var(--anchor-focus); - text-decoration: underline; } + text-decoration: underline; +} a:hover span.Identifier { color: var(--anchor); } -sub, -sup { +sub, sup { position: relative; font-size: 75%; line-height: 0; @@ -314,8 +319,7 @@ img { background: transparent !important; box-shadow: none !important; } - a, - a:visited { + a, a:visited { text-decoration: underline; } a[href]:after { @@ -329,16 +333,14 @@ img { a[href^="#"]:after { content: ""; } - pre, - blockquote { + pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; } - tr, - img { + tr, img { page-break-inside: avoid; } img { @@ -353,22 +355,18 @@ img { h1.title { page-break-before: avoid; } - p, - h2, - h3 { + p, h2, h3 { orphans: 3; widows: 3; } - h2, - h3 { + h2, h3 { page-break-after: avoid; } } p { margin-top: 0.5em; - margin-bottom: 0.5em; -} + margin-bottom: 0.5em; } small { font-size: 85%; } @@ -376,8 +374,7 @@ small { strong { font-weight: 600; font-size: 0.95em; - color: var(--strong); -} + color: var(--strong); } em { font-style: italic; } @@ -398,8 +395,7 @@ h1.title { text-align: center; font-weight: 900; margin-top: 0.75em; - margin-bottom: 0em; -} + margin-bottom: 0em; } h2 { font-size: 1.3em; @@ -426,36 +422,29 @@ h6 { font-size: 1.1em; } -ul, -ol { +ul, ol { padding: 0; margin-top: 0.5em; margin-left: 0.75em; } -ul ul, -ul ol, -ol ol, -ol ul { +ul ul, ul ol, ol ol, ol ul { margin-bottom: 0; margin-left: 1.25em; } ul.simple > li { - list-style-type: circle; -} + list-style-type: circle; } ul.simple-boot li { - list-style-type: none; - margin-left: 0em; - margin-bottom: 0.5em; -} + list-style-type: none; + margin-left: 0em; + margin-bottom: 0.5em; } ol.simple > li, ul.simple > li { margin-bottom: 0.2em; margin-left: 0.4em } ul.simple.simple-toc > li { - margin-top: 1em; -} + margin-top: 1em; } ul.simple-toc { list-style: none; @@ -464,8 +453,7 @@ ul.simple-toc { margin-top: 1em; } ul.simple-toc > li { - list-style-type: none; -} + list-style-type: none; } ul.simple-toc-section { list-style-type: circle; @@ -475,12 +463,10 @@ ul.simple-toc-section { ul.nested-toc-section { list-style-type: circle; margin-left: -0.75em; - color: var(--text); -} + color: var(--text); } ul.nested-toc-section > li { - margin-left: 1.25em; -} + margin-left: 1.25em; } ol.arabic { @@ -527,7 +513,8 @@ hr.footnote { margin-top: 0.15em; } div.footnote-group { - margin-left: 1em; } + margin-left: 1em; +} div.footnote-label { display: inline-block; min-width: 1.7em; @@ -611,7 +598,7 @@ pre { border: 1px solid var(--border); -webkit-border-radius: 6px; -moz-border-radius: 6px; - border-radius: 6px; + border-radius: 6px; } .copyToClipBoardBtn { @@ -629,7 +616,7 @@ pre { .copyToClipBoard:hover .copyToClipBoardBtn { visibility: visible; -} +} .pre-scrollable { max-height: 340px; @@ -694,8 +681,8 @@ table th { font-weight: bold; } table th.docinfo-name { - background-color: transparent; - text-align: right; + background-color: transparent; + text-align: right; } table tr:hover { @@ -712,31 +699,31 @@ table.borderless td, table.borderless th { padding: 0 0.5em 0 0 !important; } .admonition { - padding: 0.3em; - background-color: var(--secondary-background); - border-left: 0.4em solid #7f7f84; - margin-bottom: 0.5em; - -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); - -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); - box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + padding: 0.3em; + background-color: var(--secondary-background); + border-left: 0.4em solid #7f7f84; + margin-bottom: 0.5em; + -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); } .admonition-info { - border-color: var(--info-background); + border-color: var(--info-background); } .admonition-info-text { - color: var(--info-background); + color: var(--info-background); } .admonition-warning { - border-color: var(--warning-background); + border-color: var(--warning-background); } .admonition-warning-text { - color: var(--warning-background); + color: var(--warning-background); } .admonition-error { - border-color: var(--error-background); + border-color: var(--error-background); } .admonition-error-text { - color: var(--error-background); + color: var(--error-background); } .first { @@ -770,8 +757,7 @@ div.footer, div.header { font-size: smaller; } div.footer { - padding-top: 5em; -} + padding-top: 5em; } div.line-block { display: block; @@ -790,17 +776,14 @@ div.search_results { background-color: var(--third-background); margin: 3em; padding: 1em; - border: 1px solid #4d4d4d; -} + border: 1px solid #4d4d4d; } div#global-links ul { margin-left: 0; - list-style-type: none; -} + list-style-type: none; } div#global-links > simple-boot { - margin-left: 3em; -} + margin-left: 3em; } hr.docutils { width: 75%; } @@ -980,8 +963,7 @@ span.Directive { span.option { font-weight: bold; font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - color: var(--option); -} + color: var(--option); } span.Prompt { font-weight: bold; @@ -997,11 +979,10 @@ span.program { text-decoration: underline; text-decoration-color: var(--hint); text-decoration-thickness: 0.05em; - text-underline-offset: 0.15em; -} + text-underline-offset: 0.15em; } -span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, -span.Other { +span.Command, span.Rule, span.Hyperlink, +span.Label, span.Reference, span.Other { color: var(--other); } /* Pop type, const, proc, and iterator defs in nim def blocks */ @@ -1039,17 +1020,14 @@ span.pragmadots { border-radius: 4px; margin: 0 2px; cursor: pointer; - font-size: 0.8em; -} + font-size: 0.8em; } span.pragmadots:hover { - background-color: var(--hint); -} + background-color: var(--hint); } + span.pragmawrap { - display: none; -} + display: none; } span.attachedType { display: none; - visibility: hidden; -} + visibility: hidden; } diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index f94da7f40..d5a3b84c7 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -1,12 +1,11 @@ - + - + - +subdir/subdir_b/utils @@ -17,215 +16,189 @@ -subdir/subdir_b/utils + - -
    -
    -

    subdir/subdir_b/utils

    -
    +
    +
    +

    subdir/subdir_b/utils

    +
    -
    - -     Dark Mode -
    - -
    - Search: -
    -
    - Group by: - -
    - +
  • - Templates - + +
  • -
    -
    - -

    This is a description of the utils module.

    + + +

    This is a description of the utils module.

    Links work:

    • other module: iterators (not in this dir, just an example)
    • internal: fn2(x)
    • @@ -256,377 +229,356 @@

      Ref. type like G and type G and G[T] and type G*[T].

      Group ref. with capital letters works: fN11 or fn11

      Ref. [] is the same as proc `[]`(G[T]) because there are no overloads. The full form: proc `[]`*[T](x: G[T]): TRef. []= aka `[]=`(G[T], int, T).Ref. $ aka proc $ or proc `$`.Ref. $(a: ref SomeType).Ref. foo_bar aka iterator foo_bar_.Ref. fn[T; U,V: SomeFloat]().Ref. 'big or func `'big` or `'big`(string).

      -
      -

      Types

      -
      -
      -
      G[T] = object
      +    
      +

      Types

      +
      +
      +
      G[T] = object
         val: T
       
      -
      - - - -
      +
      + + + +
      -
      SomeType = enum
      +  
      SomeType = enum
         enumValueA, enumValueB, enumValueC
      -
      - - - -
      +
      + + + +
      -
      +
      +
      -

      Procs

      -
      - -
      -
      -
      proc `$`[T](a: G[T]): string
      -
      - - - -
      +

      Procs

      +
      +
      +
      +
      proc `$`[T](a: G[T]): string
      +
      + + + +
      -
      proc `$`[T](a: ref SomeType): string
      -
      - - - -
      +
      proc `$`[T](a: ref SomeType): string
      +
      + + + +
      -
      -
      -
      func `'big`(a: string): SomeType {....raises: [], tags: [].}
      -
      - - - -
      +
      +
      func `'big`(a: string): SomeType {....raises: [], tags: [].}
      +
      + + + +
      -
      -
      -
      proc `[]`[T](x: G[T]): T
      -
      - - - -
      +
      +
      proc `[]`[T](x: G[T]): T
      +
      + + + +
      -
      -
      -
      proc `[]=`[T](a: var G[T]; index: int; value: T)
      -
      - - - -
      +
      +
      proc `[]=`[T](a: var G[T]; index: int; value: T)
      +
      + + + +
      -
      -
      -
      proc binarySearch[T, K](a: openArray[T]; key: K;
      +  
      +
      proc binarySearch[T, K](a: openArray[T]; key: K;
                               cmp: proc (x: T; y: K): int {.closure.}): int
      -
      - - - -
      +
      + + + +
      -
      -
      -
      proc f(x: G[int]) {....raises: [], tags: [].}
      -
      - -There is also variant f(G[string]) - -
      +
      +
      proc f(x: G[int]) {....raises: [], tags: [].}
      +
      + + There is also variant f(G[string]) + +
      -
      proc f(x: G[string]) {....raises: [], tags: [].}
      -
      - -See also f(G[int]). - -
      +
      proc f(x: G[string]) {....raises: [], tags: [].}
      +
      + + See also f(G[int]). + +
      -
      -
      -
      proc fn[T; U, V: SomeFloat]()
      -
      - - - -
      +
      +
      proc fn[T; U, V: SomeFloat]()
      +
      + + + +
      -
      -
      -
      proc fn2() {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn2() {....raises: [], tags: [].}
      +
      + + comment + +
      -
      proc fn2(x: int) {....raises: [], tags: [].}
      -
      - -fn2 comment - -
      +
      proc fn2(x: int) {....raises: [], tags: [].}
      +
      + + fn2 comment + +
      -
      proc fn2(x: int; y: float) {....raises: [], tags: [].}
      -
      - - - -
      +
      proc fn2(x: int; y: float) {....raises: [], tags: [].}
      +
      + + + +
      -
      -
      -
      proc fn3(): auto {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn3(): auto {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      proc fn4(): auto {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn4(): auto {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      proc fn5() {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn5() {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      proc fn6() {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn6() {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      proc fn7() {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn7() {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      proc fn8(): auto {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      proc fn8(): auto {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      func fn9(a: int): int {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      func fn9(a: int): int {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      func fn10(a: int): int {....raises: [], tags: [].}
      -
      - -comment - -
      +
      +
      func fn10(a: int): int {....raises: [], tags: [].}
      +
      + + comment + +
      -
      -
      -
      func fN11() {....raises: [], tags: [].}
      -
      - - - -
      +
      +
      func fN11() {....raises: [], tags: [].}
      +
      + + + +
      -
      func fN11(x: int) {....raises: [], tags: [].}
      -
      - - - -
      +
      func fN11(x: int) {....raises: [], tags: [].}
      +
      + + + +
      -
      -
      -
      proc funWithGenerics[T, U: SomeFloat](a: T; b: U)
      -
      - - - -
      +
      +
      proc funWithGenerics[T, U: SomeFloat](a: T; b: U)
      +
      + + + +
      -
      -
      -
      proc someType(): SomeType {....raises: [], tags: [].}
      -
      - -constructor. - -
      +
      +
      proc someType(): SomeType {....raises: [], tags: [].}
      +
      + + constructor. + +
      -
      +
      +
      -

      Iterators

      -
      - -
      -
      -
      iterator fooBar(a: seq[SomeType]): int {....raises: [], tags: [].}
      -
      - - - -
      +

      Iterators

      +
      +
      +
      +
      iterator fooBar(a: seq[SomeType]): int {....raises: [], tags: [].}
      +
      + + + +
      -
      +
      +
      -

      Templates

      -
      - -
      -
      -
      template aEnum(): untyped
      -
      - - - -
      +

      Templates

      +
      +
      +
      +
      template aEnum(): untyped
      +
      + + + +
      -
      -
      -
      template bEnum(): untyped
      -
      - - - -
      +
      +
      template bEnum(): untyped
      +
      + + + +
      -
      -
      -
      template fromUtilsGen(): untyped
      -
      - -should be shown in utils.html only +
      +
      template fromUtilsGen(): untyped
      +
      + + should be shown in utils.html only

      Example:

      discard "should be in utils.html only, not in module that calls fromUtilsGen"
      ditto - -
      + +
      -
      +
      +
    -
    -
    - + diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index cba9391af..49f24d204 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -1,12 +1,11 @@ - + - + - +testproject @@ -17,372 +16,327 @@ -testproject + - -
    -
    -

    testproject

    -
    +
    +
    +

    testproject

    +
    -
    - -     Dark Mode -
    - -
    - Search: -
    -
    - Group by: - -
    - +
  • - Methods - + +
  • - Iterators - + +
  • - Macros - + +
  • - Templates - + +
  • -
    -
    - -

    This is the top level module. + + +

    This is the top level module.

    Example:

    import testproject
     import subdir / subdir_b / utils
    @@ -396,133 +350,136 @@
     

    Example:

    import testproject
     discard "in top3"
    top3 after

    - +
    -

    Types

    -
    -
    -
    A {.inject.} = enum
    +  

    Types

    +
    +
    +
    A {.inject.} = enum
       aA
    -
    - -The enum A. - -
    +
    + + The enum A. + +
    -
    B {.inject.} = enum
    +  
    B {.inject.} = enum
       bB
    -
    - -The enum B. - -
    +
    + + The enum B. + +
    -
    Foo = enum
    +  
    Foo = enum
       enumValueA2
    -
    - - - -
    +
    + + + +
    -
    FooBuzz {....deprecated: "FooBuzz msg".} = int
    -
    -
    - Deprecated: FooBuzz msg -
    +
    FooBuzz {....deprecated: "FooBuzz msg".} = int
    +
    +
    + Deprecated: FooBuzz msg +
    - - -
    + + +
    -
    Shapes = enum
    +  
    Shapes = enum
       Circle,                   ## A circle
       Triangle,                 ## A three-sided shape
       Rectangle                  ## A four-sided shape
    -
    - -Some shapes. - -
    +
    + + Some shapes. + +
    -
    +
    +
    -

    Vars

    -
    -
    -
    aVariable: array[1, int]
    -
    - - - -
    +

    Vars

    +
    +
    +
    aVariable: array[1, int]
    +
    + + + +
    -
    someVariable: bool
    -
    - -This should be visible. - -
    +
    someVariable: bool
    +
    + + This should be visible. + +
    -
    +
    +
    -

    Consts

    -
    -
    -
    C_A = 0x7FF0000000000000'f64
    -
    - - - -
    +

    Consts

    +
    +
    +
    C_A = 0x7FF0000000000000'f64
    +
    + + + +
    -
    C_B = 0o377'i8
    -
    - - - -
    +
    C_B = 0o377'i8
    +
    + + + +
    -
    C_C = 0o277'i8
    -
    - - - -
    +
    C_C = 0o277'i8
    +
    + + + +
    -
    C_D = 0o177777'i16
    -
    - - - -
    +
    C_D = 0o177777'i16
    +
    + + + +
    -
    +
    +
    -

    Procs

    -
    - -
    -
    -
    proc addfBug14485() {....raises: [], tags: [].}
    -
    - -Some proc +

    Procs

    +
    +
    +
    +
    proc addfBug14485() {....raises: [], tags: [].}
    +
    + + Some proc

    Example:

    discard "foo() = " & $[1]
     #[
    @@ -535,208 +492,194 @@ Some proc
     6: </script
     7: end of broken html
     ]#
    - -
    + +
    -
    -
    -
    proc anything() {....raises: [], tags: [].}
    -
    - -There is no block quote after blank lines at the beginning. - -
    +
    +
    proc anything() {....raises: [], tags: [].}
    +
    + + There is no block quote after blank lines at the beginning. + +
    -
    -
    -
    proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
    +  
    +
    proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
                                     tags: [RootEffect].}
    -
    - -ok1 - -
    +
    + + ok1 + +
    -
    -
    -
    proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    -
    - - - -
    +
    +
    proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    +
    + + + +
    -
    -
    -
    proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    -
    - - +
    +
    proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect].}
    +
    + +

    Example:

    discard
    ok1 - -
    + +
    -
    -
    -
    proc bar[T](a, b: T): T
    -
    - - - -
    +
    +
    proc bar[T](a, b: T): T
    +
    + + + +
    -
    -
    -
    proc baz() {....raises: [], tags: [].}
    -
    - - - -
    +
    +
    proc baz() {....raises: [], tags: [].}
    +
    + + + +
    -
    proc baz[T](a, b: T): T {....deprecated.}
    -
    -
    - Deprecated -
    +
    proc baz[T](a, b: T): T {....deprecated.}
    +
    +
    + Deprecated +
    -This is deprecated without message. - -
    + This is deprecated without message. + +
    -
    -
    -
    proc buzz[T](a, b: T): T {....deprecated: "since v0.20".}
    -
    -
    - Deprecated: since v0.20 -
    +
    +
    proc buzz[T](a, b: T): T {....deprecated: "since v0.20".}
    +
    +
    + Deprecated: since v0.20 +
    -This is deprecated with a message. - -
    + This is deprecated with a message. + +
    -
    -
    -
    proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
    +  
    +
    proc c_nonexistent(frmt: cstring): cint {.importc: "nonexistent",
         header: "<stdio.h>", varargs, discardable, ...raises: [], tags: [].}
    -
    - - - -
    +
    + + + +
    -
    -
    -
    proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
    +  
    +
    proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>",
                                          varargs, discardable, ...raises: [], tags: [].}
    -
    - -the c printf. etc. - -
    +
    + + the c printf. etc. + +
    -
    -
    -
    proc fromUtils3() {....raises: [], tags: [].}
    -
    - -came form utils but should be shown where fromUtilsGen is called +
    +
    proc fromUtils3() {....raises: [], tags: [].}
    +
    + + came form utils but should be shown where fromUtilsGen is called

    Example:

    discard """should be shown as examples for fromUtils3
            in module calling fromUtilsGen"""
    - -
    + +
    -
    -
    -
    proc isValid[T](x: T): bool
    -
    - - - -
    +
    +
    proc isValid[T](x: T): bool
    +
    + + + +
    -
    -
    -
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    +  
    +
    proc low[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
         ...raises: [], tags: [].}
    -
    - -

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    +
    + +

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    See also:

    low(2) # => -9223372036854775808
    - -
    + +
    -
    -
    -
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
    +  
    +
    proc low2[T: Ordinal | enum | range](x: T): T {.magic: "Low", noSideEffect,
         ...raises: [], tags: [].}
    -
    - -

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    +
    + +

    Returns the lowest possible value of an ordinal value x. As a special semantic rule, x may also be a type identifier.

    See also:

    low2(2) # => -9223372036854775808

    Example:

    discard "in low2"
    - -
    + +
    -
    -
    -
    proc p1() {....raises: [], tags: [].}
    -
    - -cp1 +
    +
    proc p1() {....raises: [], tags: [].}
    +
    + + cp1

    Example:

    doAssert 1 == 1 # regular comments work here
    c4

    Example:

    @@ -753,30 +696,28 @@ this is a nested doc comment ]## discard "c9" # also work after
    - - + +
    -
    -
    -
    func someFunc() {....raises: [], tags: [].}
    -
    - -My someFunc. Stuff in quotes here. Some link - -
    +
    +
    func someFunc() {....raises: [], tags: [].}
    +
    + + My someFunc. Stuff in quotes here. Some link + +
    -
    -
    -
    proc tripleStrLitTest() {....raises: [], tags: [].}
    -
    - - +
    +
    proc tripleStrLitTest() {....raises: [], tags: [].}
    +
    + +

    Example: cmd: --hint:XDeclaredButNotUsed:off

    ## mullitline string litterals are tricky as their indentation can span
     ## below that of the runnableExamples
    @@ -813,365 +754,343 @@ at indent 0
       """ ]
     discard
     # should be in
    - -
    + +
    -
    -
    -
    proc z1(): Foo {....raises: [], tags: [].}
    -
    - -cz1 - -
    +
    +
    proc z1(): Foo {....raises: [], tags: [].}
    +
    + + cz1 + +
    -
    -
    -
    proc z2() {....raises: [], tags: [].}
    -
    - -cz2 +
    +
    proc z2() {....raises: [], tags: [].}
    +
    + + cz2

    Example:

    discard "in cz2"
    - -
    + +
    -
    -
    -
    proc z3() {....raises: [], tags: [].}
    -
    - -cz3 - -
    +
    +
    proc z3() {....raises: [], tags: [].}
    +
    + + cz3 + +
    -
    -
    -
    proc z4() {....raises: [], tags: [].}
    -
    - -cz4 - -
    +
    +
    proc z4() {....raises: [], tags: [].}
    +
    + + cz4 + +
    -
    -
    -
    proc z5(): int {....raises: [], tags: [].}
    -
    - -cz5 - -
    +
    +
    proc z5(): int {....raises: [], tags: [].}
    +
    + + cz5 + +
    -
    -
    -
    proc z6(): int {....raises: [], tags: [].}
    -
    - -cz6 - -
    +
    +
    proc z6(): int {....raises: [], tags: [].}
    +
    + + cz6 + +
    -
    -
    -
    proc z7(): int {....raises: [], tags: [].}
    -
    - -cz7 - -
    +
    +
    proc z7(): int {....raises: [], tags: [].}
    +
    + + cz7 + +
    -
    -
    -
    proc z8(): int {....raises: [], tags: [].}
    -
    - -cz8 - -
    +
    +
    proc z8(): int {....raises: [], tags: [].}
    +
    + + cz8 + +
    -
    -
    -
    proc z9() {....raises: [], tags: [].}
    -
    - - +
    +
    proc z9() {....raises: [], tags: [].}
    +
    + +

    Example:

    doAssert 1 + 1 == 2
    - -
    + +
    -
    -
    -
    proc z10() {....raises: [], tags: [].}
    -
    - - +
    +
    proc z10() {....raises: [], tags: [].}
    +
    + +

    Example: cmd: -d:foobar

    discard 1
    cz10 - -
    + +
    -
    -
    -
    proc z11() {....raises: [], tags: [].}
    -
    - - +
    +
    proc z11() {....raises: [], tags: [].}
    +
    + +

    Example:

    discard 1
    - -
    + +
    -
    -
    -
    proc z12(): int {....raises: [], tags: [].}
    -
    - - +
    +
    proc z12(): int {....raises: [], tags: [].}
    +
    + +

    Example:

    discard 1
    - -
    + +
    -
    -
    -
    proc z13() {....raises: [], tags: [].}
    -
    - -cz13 +
    +
    proc z13() {....raises: [], tags: [].}
    +
    + + cz13

    Example:

    discard
    - -
    + +
    -
    -
    -
    proc z17() {....raises: [], tags: [].}
    -
    - -cz17 rest +
    +
    proc z17() {....raises: [], tags: [].}
    +
    + + cz17 rest

    Example:

    discard 1
    rest - -
    + +
    -
    + +
    -

    Methods

    -
    - -
    -
    -
    method method1(self: Moo) {.base, ...raises: [], tags: [].}
    -
    - -foo1 - -
    +

    Methods

    +
    +
    +
    +
    method method1(self: Moo) {.base, ...raises: [], tags: [].}
    +
    + + foo1 + +
    -
    -
    -
    method method2(self: Moo): int {.base, ...raises: [], tags: [].}
    -
    - -foo2 - -
    +
    +
    method method2(self: Moo): int {.base, ...raises: [], tags: [].}
    +
    + + foo2 + +
    -
    -
    -
    method method3(self: Moo): int {.base, ...raises: [], tags: [].}
    -
    - -foo3 - -
    +
    +
    method method3(self: Moo): int {.base, ...raises: [], tags: [].}
    +
    + + foo3 + +
    -
    +
    +
    -

    Iterators

    -
    - -
    -
    -
    iterator fromUtils1(): int {....raises: [], tags: [].}
    -
    - - +

    Iterators

    +
    +
    +
    +
    iterator fromUtils1(): int {....raises: [], tags: [].}
    +
    + +

    Example:

    # ok1
     assert 1 == 1
     # ok2
    - -
    + +
    -
    -
    -
    iterator iter1(n: int): int {....raises: [], tags: [].}
    -
    - -foo1 - -
    +
    +
    iterator iter1(n: int): int {....raises: [], tags: [].}
    +
    + + foo1 + +
    -
    -
    -
    iterator iter2(n: int): int {....raises: [], tags: [].}
    -
    - -foo2 +
    +
    iterator iter2(n: int): int {....raises: [], tags: [].}
    +
    + + foo2

    Example:

    discard # bar
    - -
    + +
    -
    + +
    -

    Macros

    -
    - -
    -
    -
    macro bar(): untyped
    -
    - - - -
    +

    Macros

    +
    +
    +
    +
    macro bar(): untyped
    +
    + + + +
    -
    -
    -
    macro z16()
    -
    - - +
    +
    macro z16()
    +
    + +

    Example:

    discard 1
    cz16 after

    Example:

    doAssert 2 == 1 + 1
    - -
    + +
    -
    -
    -
    macro z18(): int
    -
    - -cz18 - -
    +
    +
    macro z18(): int
    +
    + + cz18 + +
    -
    +
    +
    -

    Templates

    -
    - -
    -
    -
    template foo(a, b: SomeType)
    -
    - -This does nothing - -
    +

    Templates

    +
    +
    +
    +
    template foo(a, b: SomeType)
    +
    + + This does nothing + +
    -
    -
    -
    template fromUtils2()
    -
    - -ok3 +
    +
    template fromUtils2()
    +
    + + ok3

    Example:

    discard """should be shown as examples for fromUtils2
            in module calling fromUtilsGen"""
    - -
    + +
    -
    -
    -
    template myfn()
    -
    - - +
    +
    template myfn()
    +
    + +

    Example:

    import std/strutils
     ## issue #8871 preserve formatting
    @@ -1187,58 +1106,54 @@ bar
     block:
       discard 0xff # elu par cette crapule
     # should be in
    should be still in - -
    + +
    -
    -
    -
    template testNimDocTrailingExample()
    -
    - - +
    +
    template testNimDocTrailingExample()
    +
    + +

    Example:

    discard 2
    - -
    + +
    -
    -
    -
    template z6t(): int
    -
    - -cz6t - -
    +
    +
    template z6t(): int
    +
    + + cz6t + +
    -
    -
    -
    template z14()
    -
    - -cz14 +
    +
    template z14()
    +
    + + cz14

    Example:

    discard
    - -
    + +
    -
    -
    -
    template z15()
    -
    - -cz15 +
    +
    template z15()
    +
    + + cz15

    Example:

    discard

    Example:

    @@ -1249,26 +1164,25 @@ cz15
    assert true

    Example:

    discard 1
    in or out? - -
    + +
    -
    +
    +
    -
    -
    - + diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 47fae2491..c62b4c7db 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -1,12 +1,11 @@ - + - + - +Index @@ -17,17 +16,16 @@ -Index + - -
    -
    -

    Index

    - Modules: subdir/subdir_b/utils, testproject.

    API symbols

    +
    +
    +

    Index

    + Modules: subdir/subdir_b/utils, testproject.

    API symbols

    `$`:
    -
    -
    - + From d33e1127666be23ad2dc879c2f89a41c179e2093 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Wed, 15 Jun 2022 16:38:12 +0200 Subject: [PATCH 3443/4254] Better range error messages (#19867) * Better range error messages * Revert to old behavior for arrays * Small corrections --- compiler/ccgexprs.nim | 6 +++--- lib/system/chcks.nim | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 8e7a21c67..4c15101a9 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -988,12 +988,12 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = if reifiedOpenArray(arr.lode): linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError(); $4}$n", + "($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError4($1, $2, $3.Field1); $4}$n", [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) else: linefmt(p, cpsStmts, "if ($2-$1 != -1 && ($1 < 0 || $1 >= $3Len_0 || $2 < 0 || $2 >= $3Len_0))" & - "{ #raiseIndexError(); $4}$n", + "{ #raiseIndexError4($1, $2, $3Len_0); $4}$n", [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) of tyArray: let first = intLiteral(firstOrd(p.config, ty)) @@ -1004,7 +1004,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError(); $4}$n", + "($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError4($1, $2, $3); $4}$n", [rdLoc(a), rdLoc(b), lenExpr(p, arr), raiseInstr(p)]) else: discard diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index a404e9d40..1e1ce9c87 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -16,6 +16,9 @@ proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = else: sysFatal(RangeDefect, "value out of range: ", $val) +proc raiseIndexError4(l1, h1, h2: int) {.compilerproc, noinline.} = + sysFatal(IndexDefect, "index out of bounds: " & $l1 & ".." & $h1 & " notin 0.." & $(h2 - 1)) + proc raiseIndexError3(i, a, b: int) {.compilerproc, noinline.} = sysFatal(IndexDefect, formatErrorIndexBound(i, a, b)) From ef2dd2e473d7082d60088ece05beef81062850bb Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 16 Jun 2022 14:46:59 +0800 Subject: [PATCH 3444/4254] document nimTestsNimdocFixup for rsttester (#19894) --- nimdoc/rsttester.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nimdoc/rsttester.nim b/nimdoc/rsttester.nim index daca3dfc7..a0bdfca1e 100644 --- a/nimdoc/rsttester.nim +++ b/nimdoc/rsttester.nim @@ -1,9 +1,14 @@ +# To run this, cd to the git repo root, and run "nim r nimdoc/rsttester.nim". +# to change expected results (after carefully verifying everything), use -d:nimTestsNimdocFixup + import os, strutils from std/private/gitutils import diffFiles const baseDir = "nimdoc/rst2html" +const fixup = defined(nimTestsNimdocFixup) + var failures = 0 proc exec(cmd: string) = @@ -29,7 +34,7 @@ proc testRst2Html(fixup = false) = if failures == 0: removeDir(baseDir / "source/htmldocs") -testRst2Html(defined(fixup)) +testRst2Html(fixup) # Check for failures if failures > 0: quit($failures & " failures occurred.") From 332aa0af75baf328416068459931d5a6e4292d34 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 19 Jun 2022 13:35:25 +0800 Subject: [PATCH 3445/4254] [vm] refactor `stdlib.marshal.load` (#19905) refactor stdlib.marshal.load --- compiler/vmops.nim | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 640826cc8..04b753ef6 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -364,21 +364,5 @@ proc registerAdditionalOps*(c: PCtx) = let typ = a.getNode(0).typ let p = a.getReg(1) var res: string - - var node: PNode - case p.kind - of rkNone: - node = newNode(nkEmpty) - of rkInt: - node = newIntNode(nkIntLit, p.intVal) - of rkFloat: - node = newFloatNode(nkFloatLit, p.floatVal) - of rkNode: - node = p.node - of rkRegisterAddr: - node = p.regAddr.node - of rkNodeAddr: - node = p.nodeAddr[] - - storeAny(res, typ, node, c.config) + storeAny(res, typ, regToNode(p[]), c.config) setResult(a, res) From dd4cc266cd39d7cecfd7215e683b0c6499fc4a36 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sun, 19 Jun 2022 15:36:33 +1000 Subject: [PATCH 3446/4254] Fixes #19900 (#19906) Fixed tocRoot placement --- config/nimdoc.cfg | 4 ++-- nimdoc/rst2html/expected/rst_examples.html | 2 +- nimdoc/test_out_index_dot_html/expected/index.html | 2 +- nimdoc/testproject/expected/subdir/subdir_b/utils.html | 2 +- nimdoc/testproject/expected/testproject.html | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 725f9e0a5..3b0afe8d6 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -149,11 +149,11 @@ doc.body_toc_group = """ onkeyup="search()" />
    $body_toc_groupsection -
    $tableofcontents
    $seeSrc +
    $deprecationMsg

    $moduledesc

    $content @@ -188,11 +188,11 @@ doc.body_toc_group = """
    -
    $tableofcontents
    $seeSrc +
    $deprecationMsg

    $moduledesc

    $content diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 532917055..efc8ac414 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -49,7 +49,6 @@
    -
    +

    diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 0c0dc2268..43285db6b 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -49,7 +49,6 @@ -
    • @@ -69,6 +68,7 @@
      +

      diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index d5a3b84c7..4d753ad8f 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -49,7 +49,6 @@
      -
      +

      This is a description of the utils module.

      Links work:

      diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 49f24d204..24dfdc13f 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -49,7 +49,6 @@
      -
      • @@ -335,6 +334,7 @@
        +

        This is the top level module.

        Example:

        From 5e32fc785527d9b71ebab643f142fbab13eb29ce Mon Sep 17 00:00:00 2001 From: tersec Date: Mon, 20 Jun 2022 06:01:41 +0000 Subject: [PATCH 3447/4254] Recommend gcc 5.x or newer (#19910) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 7ff056a20..8999091e6 100644 --- a/readme.md +++ b/readme.md @@ -51,8 +51,8 @@ Nim programming language. Those C sources are available within the Next, to build from source you will need: - * A C compiler such as ``gcc`` 3.x/later or an alternative such as ``clang``, - ``Visual C++`` or ``Intel C++``. It is recommended to use ``gcc`` 3.x or + * A C compiler such as ``gcc`` 5.x/later or an alternative such as ``clang``, + ``Visual C++`` or ``Intel C++``. It is recommended to use ``gcc`` 5.x or later. * Either ``git`` or ``wget`` to download the needed source repositories. * The ``build-essential`` package when using ``gcc`` on Ubuntu (and likely From 40464fa7626a616a3881c0b16a74b9ec7d788720 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Mon, 20 Jun 2022 08:21:20 +0200 Subject: [PATCH 3448/4254] Fix nimRawSetjmp for VCC [backport: 1.2] (#19899) --- lib/system/ansi_c.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 5d0ecc01c..74f79167a 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -118,7 +118,7 @@ elif defined(nimBuiltinSetjmp): c_builtin_setjmp(unsafeAddr jmpb[0]) elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): - when defined(windows): + when defined(windows) and not defined(vcc): # No `_longjmp()` on Windows. proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "longjmp".} From 0ae44e562f693d270e3cad77675ce5f68474921d Mon Sep 17 00:00:00 2001 From: flintforge Date: Tue, 21 Jun 2022 03:53:46 +0200 Subject: [PATCH 3449/4254] fix typo in nre.nim (#19915) Update nre.nim typo in proc replace description --- lib/impure/nre.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 03cbf5220..1012c7c36 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -695,8 +695,7 @@ proc replace*(str: string, pattern: Regex, ## each match and the return value is the replacement value. ## ## If `subproc` is a `proc (string): string`, then it is executed with the - ## full text of the match and and the return value is the replacement - ## value. + ## full text of the match and the return value is the replacement value. ## ## If `subproc` is a string, the syntax is as follows: ## From a65db5e2e924c51af7c654f8e564332299b95cb3 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 21 Jun 2022 15:37:23 +0800 Subject: [PATCH 3450/4254] [Tiny] correct comment opcDeref => opcLdDeref (#19908) correct comment opcDeref => opcLdDeref --- compiler/vm.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 1b11cb4f3..656508793 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -642,7 +642,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNodeToReg: let ra = instr.regA let rb = instr.regB - # opcDeref might already have loaded it into a register. XXX Let's hope + # opcLdDeref might already have loaded it into a register. XXX Let's hope # this is still correct this way: if regs[rb].kind != rkNode: regs[ra] = regs[rb] From 3cb2d7af0591b12044d4be20dfb6d7f7ff79a4ff Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 22 Jun 2022 14:43:58 +0800 Subject: [PATCH 3451/4254] [vm]fixes #15974 #12551 #19464 #16020 #16780 #16613 #14553 #19909 #18641 (#19902) [backport] * revert #12217 since the root problem seems to have been fixed; fix #15974;fix #12551; fix #19464 * fix #16020; fix #16780 * fix tests and #16613 * fix #14553 * fix #19909; skip skipRegisterAddr * fix #18641 --- compiler/vm.nim | 28 +++--- compiler/vmgen.nim | 3 - tests/vm/tissues.nim | 50 ++++++++++- tests/vm/tmisc_vm.nim | 196 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 263 insertions(+), 14 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 656508793..e681bbc96 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -523,8 +523,7 @@ when not defined(nimHasSinkInference): template takeAddress(reg, source) = reg.nodeAddr = addr source - when defined(gcDestructors): - GC_ref source + GC_ref source proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start @@ -1011,6 +1010,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeBC(rkInt) template getTyp(n): untyped = n.typ.skipTypes(abstractInst) + template skipRegisterAddr(n: TFullReg): TFullReg = + var tmp = n + while tmp.kind == rkRegisterAddr: + tmp = tmp.regAddr[] + tmp + proc ptrEquality(n1: ptr PNode, n2: PNode): bool = ## true if n2.intVal represents a ptr equal to n1 let p1 = cast[int](n1) @@ -1024,16 +1029,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = return t2.kind in PtrLikeKinds and n2.intVal == p1 else: return false - if regs[rb].kind == rkNodeAddr: - if regs[rc].kind == rkNodeAddr: - ret = regs[rb].nodeAddr == regs[rc].nodeAddr + let rbReg = skipRegisterAddr(regs[rb]) + let rcReg = skipRegisterAddr(regs[rc]) + + if rbReg.kind == rkNodeAddr: + if rcReg.kind == rkNodeAddr: + ret = rbReg.nodeAddr == rcReg.nodeAddr else: - ret = ptrEquality(regs[rb].nodeAddr, regs[rc].node) - elif regs[rc].kind == rkNodeAddr: - ret = ptrEquality(regs[rc].nodeAddr, regs[rb].node) + ret = ptrEquality(rbReg.nodeAddr, rcReg.node) + elif rcReg.kind == rkNodeAddr: + ret = ptrEquality(rcReg.nodeAddr, rbReg.node) else: - let nb = regs[rb].node - let nc = regs[rc].node + let nb = rbReg.node + let nc = rcReg.node if nb.kind != nc.kind: discard elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional elif nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ != nil and nb.typ.kind == tyProc and sameConstant(nb, nc): diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 2e7f6d8b0..aa2bdbe4c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1382,9 +1382,6 @@ proc unneededIndirection(n: PNode): bool = n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef proc canElimAddr(n: PNode): PNode = - if n[0].typ.skipTypes(abstractInst).kind in {tyObject, tyTuple, tyArray}: - # objects are reference types in the VM - return n[0] case n[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: var m = n[0][0] diff --git a/tests/vm/tissues.nim b/tests/vm/tissues.nim index 1cf3afc00..f0ae6c296 100644 --- a/tests/vm/tissues.nim +++ b/tests/vm/tissues.nim @@ -1,6 +1,6 @@ import macros -block t9043: # issue #9043 +block t9043: # bug #9043 proc foo[N: static[int]](dims: array[N, int]): string = const N1 = N const N2 = dims.len @@ -26,3 +26,51 @@ block t4952: let tree = newTree(nnkExprColonExpr) let t = (n: tree) doAssert: t.n.kind == tree.kind + + +# bug #19909 +type + SinglyLinkedList[T] = ref object + SinglyLinkedListObj[T] = ref object + + +proc addMoved[T](a, b: var SinglyLinkedList[T]) = + if a.addr != b.addr: discard + +proc addMoved[T](a, b: var SinglyLinkedListObj[T]) = + if a.addr != b.addr: discard + +proc main = + var a: SinglyLinkedList[int]; new a + var b: SinglyLinkedList[int]; new b + a.addMoved b + + var a0: SinglyLinkedListObj[int] + var b0: SinglyLinkedListObj[int] + a0.addMoved b0 + +static: main() + + +# bug #18641 + +type A = object + ha1: int +static: + var a = A() + var a2 = a.addr + a2.ha1 = 11 + doAssert a2.ha1 == 11 + a.ha1 = 12 + doAssert a.ha1 == 12 + doAssert a2.ha1 == 12 # ok +static: + proc fn() = + var a = A() + var a2 = a.addr + a2.ha1 = 11 + doAssert a2.ha1 == 11 + a.ha1 = 12 + doAssert a.ha1 == 12 + doAssert a2.ha1 == 12 # fails + fn() diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim index bbf618622..af09e8871 100644 --- a/tests/vm/tmisc_vm.nim +++ b/tests/vm/tmisc_vm.nim @@ -1,7 +1,12 @@ discard """ + targets: "c js" output: ''' [127, 127, 0, 255][127, 127, 0, 255] (data: 1) +(2, 1) +(2, 1) +(2, 1) +(f0: 5) ''' nimout: '''caught Exception @@ -17,6 +22,19 @@ foo4 (a: 0, b: 0) (a: 0, b: 0) (a: 0, b: 0) +z1 m: (lo: 12) +z2 a: (lo: 3) +x1 a: (lo: 3) +x2 a: (lo: 6) +x3 a: (lo: 0) +z3 a: (lo: 3) +x1 a: (lo: 3) +x2 a: (lo: 6) +x3 a: (lo: 0) +(2, 1) +(2, 1) +(2, 1) +(f0: 5) ''' """ import std/sets @@ -249,3 +267,181 @@ static: echo x2[] let x3 = new(ref MyObject) # cannot generate VM code for ref MyObject echo x3[] + +# bug #19464 +type + Wrapper = object + inner: int + +proc assign(r: var Wrapper, a: Wrapper) = + r = a + +proc myEcho(a: Wrapper) = + var tmp = a + assign(tmp, Wrapper(inner: 0)) # this shouldn't modify `a` + doAssert a.inner == 1 + +static: + var result: Wrapper + assign(result, Wrapper(inner: 1)) + myEcho(result) + +when true: + # bug #15974 + type Foo = object + f0: int + + proc fn(a: var Foo) = + var s: Foo + a = Foo(f0: 2) + s = a + doAssert s.f0 == 2 + a = Foo(f0: 3) + doAssert s.f0 == 2 + + proc test2()= + var a = Foo(f0: 1) + fn(a) + + static: test2() + test2() + +# bug #12551 +type + StUint = object + lo: uint64 + +func `+=`(x: var Stuint, y: Stuint) = + x.lo += y.lo + +func `-`(x, y: Stuint): Stuint = + result.lo = x.lo - y.lo + +func `+`(x, y: Stuint): Stuint = + result.lo = x.lo + y.lo + +func `-=`(x: var Stuint, y: Stuint) = + x = x - y + +func `<`(x, y: Stuint): bool= + x.lo < y.lo + +func `==`(x, y: Stuint): bool = + x.lo == y.lo + +func `<=`(x, y: Stuint): bool = + x.lo <= y.lo + +proc div3n2n(r: var Stuint, b: Stuint) = + var d: Stuint + r = d + r += b + +func div2n1n(r: var Stuint, b: Stuint) = + div3n2n(r, b) + +func divmodBZ(x, y: Stuint, r: var Stuint)= + div2n1n(r, y) + r.lo = 3 + +func `mod`(x, y: Stuint): Stuint = + divmodBZ(x, y, result) + +func doublemod_internal(a, m: Stuint): Stuint = + result = a + if a >= m - a: + result -= m + result += a + +func mulmod_internal(a, b, m: Stuint): Stuint = + var (a, b) = (a, b) + swap(a, b) + debugEcho "x1 a: ", a + a = doublemod_internal(a, m) + debugEcho "x2 a: ", a + a = doublemod_internal(a, m) + debugEcho "x3 a: ", a + +func powmod_internal(a, m: Stuint): Stuint = + var a = a + debugEcho "z1 m: ", m + debugEcho "z2 a: ", a + result = mulmod_internal(result, a, m) + debugEcho "z3 a: ", a + a = mulmod_internal(a, a, m) + +func powmod*(a, m: Stuint) = + discard powmod_internal(a mod m, m) + +static: + var x = Stuint(lo: high(uint64)) + var y = Stuint(lo: 12) + + powmod(x, y) + +# bug #16780 +when true: + template swap*[T](a, b: var T) = + var a2 = addr(a) + var b2 = addr(b) + var aOld = a2[] + a2[] = b2[] + b2[] = aOld + + proc rather = + block: + var a = 1 + var b = 2 + swap(a, b) + echo (a,b) + + block: + type Foo = ref object + x: int + var a = Foo(x:1) + var b = Foo(x:2) + swap(a, b) + echo (a.x, b.x) + + block: + type Foo = object + x: int + var a = Foo(x:1) + var b = Foo(x:2) + swap(a, b) + echo (a.x,b.x) + + static: rather() + rather() + +# bug #16020 +when true: + block: + type Foo = object + f0: int + proc main= + var f = Foo(f0: 3) + var f2 = f.addr + f2[].f0 += 1 + f2.f0 += 1 + echo f + static: main() + main() + +import tables, strutils + +# bug #14553 +const PpcPatterns = @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] + +static: + var + needSecondIdentifier = initTable[uint32, seq[(string, string)]]() + + for (name, pattern) in PpcPatterns: + let + firstPart = 0'u32 + lastPart = "test" + + needSecondIdentifier.mgetOrPut(firstPart, @[]).add((name, pattern)) + + doAssert needSecondIdentifier[0] == @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] From caf6aff06b6dd36ef0bbe8c1f8b527952790e208 Mon Sep 17 00:00:00 2001 From: Khaled Hammouda Date: Wed, 22 Jun 2022 06:36:30 -0400 Subject: [PATCH 3452/4254] Fix distinct requiresInit test and manual (#19901) fix distinct test and manual --- doc/manual.rst | 11 +++++++---- tests/distinct/tdistinct.nim | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 82c9f5758..b63a2f68f 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2851,7 +2851,10 @@ Given the following distinct type definitions: .. code-block:: nim type - DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject + Foo = object + x: string + + DistinctFoo {.requiresInit, borrow: `.`.} = distinct Foo DistinctString {.requiresInit.} = distinct string The following code blocks will fail to compile: @@ -2864,7 +2867,7 @@ The following code blocks will fail to compile: .. code-block:: nim var s: DistinctString s = "test" - doAssert s == "test" + doAssert string(s) == "test" But these ones will compile successfully: @@ -2873,8 +2876,8 @@ But these ones will compile successfully: doAssert foo.x == "test" .. code-block:: nim - let s = "test" - doAssert s == "test" + let s = DistinctString("test") + doAssert string(s) == "test" Let statement ------------- diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index dd8237854..8ec083020 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -135,11 +135,11 @@ block tRequiresInit: reject: var s: DistinctString s = "test" - doAssert s == "test" + doAssert string(s) == "test" accept: - let s = "test" - doAssert s == "test" + let s = DistinctString("test") + doAssert string(s) == "test" block: #17322 type From 0189122d4fadc73a3de18a7a781997c506f837aa Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 27 Jun 2022 23:57:07 +0800 Subject: [PATCH 3453/4254] ref #19830; multiple definition of in Nim generated static libraries (#19934) * ref #19830; multiple definition of in Nim generated static libraries * fix compile errors --- compiler/cgen.nim | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 862f31107..c0b94ebbb 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1323,7 +1323,7 @@ proc getSomeInitName(m: BModule, suffix: string): Rope = proc getInitName(m: BModule): Rope = if sfMainModule in m.module.flags: # generate constant name for main module, for "easy" debugging. - result = rope"NimMainModule" + result = rope(m.config.nimMainPrefix) & rope"NimMainModule" else: result = getSomeInitName(m, "Init000") @@ -1356,35 +1356,35 @@ proc genMainProc(m: BModule) = preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L") preMainCode.add("\t(*inner)();\L") else: - preMainCode.add("\tPreMain();\L") + preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix]) + + var posixCmdLine: Rope + if optNoMain notin m.config.globalOptions: + posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L" + posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L" + posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L" const - # not a big deal if we always compile these 3 global vars... makes the HCR code easier - PosixCmdLine = - "N_LIB_PRIVATE int cmdCount;$N" & - "N_LIB_PRIVATE char** cmdLine;$N" & - "N_LIB_PRIVATE char** gEnv;$N" - # The use of a volatile function pointer to call Pre/NimMainInner # prevents inlining of the NimMainInner function and dependent # functions, which might otherwise merge their stack frames. PreMainVolatileBody = "\tvoid (*volatile inner)(void);$N" & - "\tinner = PreMainInner;$N" & + "\tinner = $3PreMainInner;$N" & "$1" & "\t(*inner)();$N" PreMainNonVolatileBody = "$1" & - "\tPreMainInner();$N" + "\t$3PreMainInner();$N" PreMainBodyStart = "$N" & - "N_LIB_PRIVATE void PreMainInner(void) {$N" & + "N_LIB_PRIVATE void $3PreMainInner(void) {$N" & "$2" & "}$N$N" & - PosixCmdLine & - "N_LIB_PRIVATE void PreMain(void) {$N" + "$4" & + "N_LIB_PRIVATE void $3PreMain(void) {$N" PreMainBodyEnd = "}$N$N" @@ -1395,21 +1395,21 @@ proc genMainProc(m: BModule) = MainProcsWithResult = MainProcs & ("\treturn $1nim_program_result;$N") - NimMainInner = "N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {$N" & + NimMainInner = "N_LIB_PRIVATE N_CDECL(void, $5NimMainInner)(void) {$N" & "$1" & "}$N$N" NimMainVolatileBody = "\tvoid (*volatile inner)(void);$N" & "$4" & - "\tinner = NimMainInner;$N" & + "\tinner = $5NimMainInner;$N" & "$2" & "\t(*inner)();$N" NimMainNonVolatileBody = "$4" & "$2" & - "\tNimMainInner();$N" + "\t$5NimMainInner();$N" NimMainProcStart = "N_CDECL(void, $5NimMain)(void) {$N" @@ -1489,9 +1489,9 @@ proc genMainProc(m: BModule) = else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []) inc(m.labels) if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: - appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit]) + appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine]) else: - appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainNonVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit]) + appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainNonVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine]) if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: From 7c31b6a47b5cfb6f2d1f296390eb457bd75e55c2 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 28 Jun 2022 03:13:17 -0300 Subject: [PATCH 3454/4254] Fix jsre (#19917) * Fixes for jsre to make it more safe at runtime on some edge cases * https://github.com/nim-lang/Nim/pull/19917#issuecomment-1162692893 --- lib/js/jsre.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index cd8fb2be7..0cc2f8a87 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -33,13 +33,13 @@ func compile*(self: RegExp; pattern: cstring; flags: cstring) {.importjs: "#.com func replace*(pattern: cstring; self: RegExp; replacement: cstring): cstring {.importjs: "#.replace(#, #)".} ## Returns a new string with some or all matches of a pattern replaced by given replacement -func split*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "#.split(#)".} +func split*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "(#.split(#) || [])".} ## Divides a string into an ordered list of substrings and returns the array -func match*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "#.match(#)".} +func match*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "(#.match(#) || [])".} ## Returns an array of matches of a RegExp against given string -func exec*(self: RegExp; pattern: cstring): seq[cstring] {.importjs: "#.exec(#)".} +func exec*(self: RegExp; pattern: cstring): seq[cstring] {.importjs: "(#.exec(#) || [])".} ## Executes a search for a match in its string parameter. func toCstring*(self: RegExp): cstring {.importjs: "#.toString()".} @@ -87,3 +87,5 @@ runnableExamples: assert "do1ne".split(jsregex) == @["do".cstring, "ne".cstring] jsregex.compile(r"[lw]", r"i") assert "hello world".replace(jsregex,"X") == "heXlo world" + let digitsRegex: RegExp = newRegExp(r"\d") + assert "foo".match(digitsRegex) == @[] From 8a344cb25b9b9d1b185ba6e5a8e1cf14421fedb4 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 28 Jun 2022 16:49:31 +0800 Subject: [PATCH 3455/4254] closes #11042; add testcase (#19935) close #11042; add testcase --- tests/closure/t11042.nim | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/closure/t11042.nim diff --git a/tests/closure/t11042.nim b/tests/closure/t11042.nim new file mode 100644 index 000000000..6a3928316 --- /dev/null +++ b/tests/closure/t11042.nim @@ -0,0 +1,55 @@ +discard """ + output:''' +foo: 1 +foo: 2 +bar: 1 +bar: 2 +foo: 1 +foo: 2 +bar: 1 +bar: 2 +bar: 3 +bar: 4 +bar: 5 +bar: 6 +bar: 7 +bar: 8 +bar: 9 +''' +""" + +# bug #11042 +block: + iterator foo: int = + for x in 1..2: + echo "foo: ", x + for y in 1..2: + discard + + for x in foo(): discard + + let bar = iterator: int = + for x in 1..2: + echo "bar: ", x + for y in 1..2: + discard + + for x in bar(): discard + + +block: + iterator foo: int = + for x in 1..2: + echo "foo: ", x + for y in 1..2: + discard + + for x in foo(): discard + + let bar = iterator: int = + for x in 1..9: + echo "bar: ", x + for y in 1..2: + discard + + for x in bar(): discard \ No newline at end of file From bcff13debcbdd8108237c8033e4dc9c38bb331e0 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 29 Jun 2022 22:37:24 +0800 Subject: [PATCH 3456/4254] dec inLoop after exiting the while scope in computeLiveRanges [backport] (#19918) * dec inLoop after exiting the while scope in computeLiveRanges * add testcase --- compiler/varpartitions.nim | 2 +- tests/arc/tcursorloop.nim | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/arc/tcursorloop.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index d04a7b40c..a93104b06 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -851,7 +851,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = # connect(graph, cursorVar) inc c.inLoop for child in n: computeLiveRanges(c, child) - inc c.inLoop + dec c.inLoop of nkElifBranch, nkElifExpr, nkElse, nkOfBranch: inc c.inConditional for child in n: computeLiveRanges(c, child) diff --git a/tests/arc/tcursorloop.nim b/tests/arc/tcursorloop.nim new file mode 100644 index 000000000..a37a6a036 --- /dev/null +++ b/tests/arc/tcursorloop.nim @@ -0,0 +1,45 @@ +discard """ + cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' + nimout: ''' +--expandArc: traverse + +var + it + jt_cursor +try: + `=copy`(it, root) + block :tmp: + while ( + not (it == nil)): + if true: + echo [it.s] + `=copy`(it, it.ri) + jt_cursor = root + if ( + not (jt_cursor == nil)): + echo [jt_cursor.s] + jt_cursor = jt_cursor.ri +finally: + `=destroy`(it) +-- end of expandArc ------------------------ +''' +""" + +type + Node = ref object + le, ri: Node + s: string + +proc traverse(root: Node) = + var it = root + while it != nil: + if true: + echo it.s + it = it.ri + + var jt = root + if jt != nil: + echo jt.s + jt = jt.ri + +traverse(nil) From ad430c0daad16019a6c440ab735a61856523329a Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 30 Jun 2022 10:20:19 +0200 Subject: [PATCH 3457/4254] once C++, always C++ [backport] (#19938) * once C++, always C++ When using `{.compile: "file.cc".}` in a nim module, even when compiling with `nim c` the C++ compiler should be used - once any C++ file has been compiled, the C++ linker also needs to be used. * more strict C++ check * simplify code --- compiler/extccomp.nim | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 5c074d284..f1dc01f44 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -493,7 +493,10 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} = (conf.target.hostOS == osWindows) proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool = - conf.backend == backendCpp and not cfile.string.endsWith(".c") + # List of possible file extensions taken from gcc + for ext in [".C", ".cc", ".cpp", ".CPP", ".c++", ".cp", ".cxx"]: + if cfile.string.endsWith(ext): return true + false proc envFlags(conf: ConfigRef): string = result = if conf.backend == backendCpp: @@ -501,14 +504,14 @@ proc envFlags(conf: ConfigRef): string = else: getEnv("CFLAGS") -proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string = +proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; isCpp: bool): string = if compiler == ccEnv: - result = if useCpp(conf, cfile): + result = if isCpp: getEnv("CXX") else: getEnv("CC") else: - result = if useCpp(conf, cfile): + result = if isCpp: CC[compiler].cppCompiler else: CC[compiler].compilerExe @@ -547,22 +550,25 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool = proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe - elif optMixedMode in conf.globalOptions and conf.backend != backendCpp: CC[compiler].cppCompiler - else: getCompilerExe(conf, compiler, AbsoluteFile"") + else: getCompilerExe(conf, compiler, optMixedMode in conf.globalOptions or conf.backend == backendCpp) proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, isMainFile = false; produceOutput = false): string = - let c = conf.cCompiler + let + c = conf.cCompiler + isCpp = useCpp(conf, cfile.cname) # We produce files like module.nim.cpp, so the absolute Nim filename is not # cfile.name but `cfile.cname.changeFileExt("")`: var options = cFileSpecificOptions(conf, cfile.nimname, cfile.cname.changeFileExt("").string) - if useCpp(conf, cfile.cname): + if isCpp: # needs to be prepended so that --passc:-std=c++17 can override default. # we could avoid allocation by making cFileSpecificOptions inplace options = CC[c].cppXsupport & ' ' & options + # If any C++ file was compiled, we need to use C++ driver for linking as well + incl conf.globalOptions, optMixedMode var exe = getConfigVar(conf, c, ".exe") - if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname) + if exe.len == 0: exe = getCompilerExe(conf, c, isCpp) if needsExeExt(conf): exe = addFileExt(exe, "exe") if (optGenDynLib in conf.globalOptions or (conf.hcrOn and not isMainFile)) and @@ -582,7 +588,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, compilePattern = joinPath(conf.cCompilerPath, exe) else: - compilePattern = getCompilerExe(conf, c, cfile.cname) + compilePattern = getCompilerExe(conf, c, isCpp) includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)])) From 306810a748ab3e0182f798bea7d2792c64ab856a Mon Sep 17 00:00:00 2001 From: Sam Zaydel Date: Thu, 30 Jun 2022 14:16:50 -0700 Subject: [PATCH 3458/4254] Enable nim-lang to build correctly on illumos-based systems (#19952) --- tools/niminst/buildsh.nimf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf index 7a05ef342..6b99c49ee 100644 --- a/tools/niminst/buildsh.nimf +++ b/tools/niminst/buildsh.nimf @@ -164,7 +164,7 @@ esac case $ucpu in *i386* | *i486* | *i586* | *i686* | *bepc* | *i86pc* ) - if [ "$isOpenIndiana" = "yes" ] ; then + if [ "$isOpenIndiana" = "yes" ] || [ `uname -o` == "illumos" ] ; then mycpu="amd64" else mycpu="i386" From 2c0aaac3045a63b5e4a24468341bf9ccfc8820cc Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 30 Jun 2022 18:18:11 -0300 Subject: [PATCH 3459/4254] jsffi add missing braces (#19948) js codegen add missing whitespaces and braces --- lib/js/jsffi.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 35cbf2864..aca4fc292 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -348,8 +348,8 @@ iterator pairs*(obj: JsObject): (cstring, JsObject) = var k: cstring var v: JsObject {.emit: "for (var `k` in `obj`) {".} - {.emit: " if (!`obj`.hasOwnProperty(`k`)) continue;".} - {.emit: " `v`=`obj`[`k`];".} + {.emit: " if (!`obj`.hasOwnProperty(`k`)) { continue; }".} + {.emit: " `v` = `obj`[`k`];".} yield (k, v) {.emit: "}".} @@ -357,8 +357,8 @@ iterator items*(obj: JsObject): JsObject = ## Yields the `values` of each field in a JsObject, wrapped into a JsObject. var v: JsObject {.emit: "for (var k in `obj`) {".} - {.emit: " if (!`obj`.hasOwnProperty(k)) continue;".} - {.emit: " `v`=`obj`[k];".} + {.emit: " if (!`obj`.hasOwnProperty(k)) { continue; }".} + {.emit: " `v` = `obj`[k];".} yield v {.emit: "}".} @@ -366,7 +366,7 @@ iterator keys*(obj: JsObject): cstring = ## Yields the `names` of each field in a JsObject. var k: cstring {.emit: "for (var `k` in `obj`) {".} - {.emit: " if (!`obj`.hasOwnProperty(`k`)) continue;".} + {.emit: " if (!`obj`.hasOwnProperty(`k`)) { continue; }".} yield k {.emit: "}".} @@ -376,8 +376,8 @@ iterator pairs*[K: JsKey, V](assoc: JsAssoc[K, V]): (K,V) = var k: cstring var v: V {.emit: "for (var `k` in `assoc`) {".} - {.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".} - {.emit: " `v`=`assoc`[`k`];".} + {.emit: " if (!`assoc`.hasOwnProperty(`k`)) { continue; }".} + {.emit: " `v` = `assoc`[`k`];".} yield (k.toJsKey(K), v) {.emit: "}".} @@ -385,8 +385,8 @@ iterator items*[K, V](assoc: JsAssoc[K, V]): V = ## Yields the `values` in a JsAssoc. var v: V {.emit: "for (var k in `assoc`) {".} - {.emit: " if (!`assoc`.hasOwnProperty(k)) continue;".} - {.emit: " `v`=`assoc`[k];".} + {.emit: " if (!`assoc`.hasOwnProperty(k)) { continue; }".} + {.emit: " `v` = `assoc`[k];".} yield v {.emit: "}".} @@ -394,7 +394,7 @@ iterator keys*[K: JsKey, V](assoc: JsAssoc[K, V]): K = ## Yields the `keys` in a JsAssoc. var k: cstring {.emit: "for (var `k` in `assoc`) {".} - {.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".} + {.emit: " if (!`assoc`.hasOwnProperty(`k`)) { continue; }".} yield k.toJsKey(K) {.emit: "}".} From ce4078acd40bb27de5d05832f486dbc95918a3c9 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Thu, 30 Jun 2022 23:19:04 +0200 Subject: [PATCH 3460/4254] Allow recursive closure iterators (#19939) --- compiler/semexprs.nim | 3 ++- doc/manual.rst | 5 +---- tests/iter/titer_issues.nim | 13 +++++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ed28d8145..e07a98417 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -886,7 +886,8 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, case callee.kind of skMacro, skTemplate: discard else: - if callee.kind == skIterator and callee.id == c.p.owner.id: + if callee.kind == skIterator and callee.id == c.p.owner.id and + not isClosureIterator(c.p.owner.typ): localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s) # error correction, prevents endless for loop elimination in transf. # See bug #2051: diff --git a/doc/manual.rst b/doc/manual.rst index b63a2f68f..571379a87 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4326,13 +4326,10 @@ Closure iterators and inline iterators have some restrictions: 1. For now, a closure iterator cannot be executed at compile time. 2. `return` is allowed in a closure iterator but not in an inline iterator (but rarely useful) and ends the iteration. -3. Neither inline nor closure iterators can be (directly)* recursive. +3. Inline iterators cannot be recursive. 4. Neither inline nor closure iterators have the special `result` variable. 5. Closure iterators are not supported by the JS backend. -(*) Closure iterators can be co-recursive with a factory proc which results -in similar syntax to a recursive iterator. More details follow. - Iterators that are neither marked `{.closure.}` nor `{.inline.}` explicitly default to being inline, but this may change in future versions of the implementation. diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index 15fe867c8..1f7e41e69 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -29,6 +29,7 @@ end 9018 @[1, 2] @[1, 2, 3] +1 ''' """ @@ -274,3 +275,15 @@ iterator cc() {.closure.} = break var a2 = cc + +# bug #16876 +block: + iterator a(num: int): int {.closure.} = + if num == 1: + yield num + else: + for i in a(num - 1): + yield i + + for i in a(5): + echo i From 4897c47c8004e85474b760d770d9d09ae1d58771 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 2 Jul 2022 16:51:21 +0800 Subject: [PATCH 3461/4254] closes #15897; add testcase (#19961) --- tests/views/tviews1.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index 249058eb6..b81b17f30 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -66,3 +66,14 @@ proc mainB = assert foo.x.y == @[1, 2, 3] mainB() + + +# bug #15897 +type Outer = ref object + value: int +type Inner = object + owner: var Outer + +var o = Outer(value: 1234) +var v = Inner(owner: o).owner.value +doAssert v == 1234 From d2d8f1342b3125aac8e0592da25df61e6feb95b2 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Mon, 4 Jul 2022 08:52:44 -0300 Subject: [PATCH 3462/4254] Fixing `nimRawSetJmp` for vcc and clangcl on Windows (#19959) * fix vcc rawsetjmp * changing `_longjmp()` to `longjmp()` and `_setjmp()` to `setjmp()` * fix * fix setjmp to clangcl on Windows * fix genTrySetjmp() to clangcl on Windows --- compiler/ccgstmts.nim | 19 ++++++++++++------- lib/system/ansi_c.nim | 34 +++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e791318ee..3ecf68402 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1367,13 +1367,18 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint]) elif isDefined(p.config, "nimRawSetjmp"): if isDefined(p.config, "mswindows"): - # The Windows `_setjmp()` takes two arguments, with the second being an - # undocumented buffer used by the SEH mechanism for stack unwinding. - # Mingw-w64 has been trying to get it right for years, but it's still - # prone to stack corruption during unwinding, so we disable that by setting - # it to NULL. - # More details: https://github.com/status-im/nimbus-eth2/issues/3121 - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint]) + if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"): + # For the vcc compiler, use `setjmp()` with one argument. + # See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170 + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) + else: + # The Windows `_setjmp()` takes two arguments, with the second being an + # undocumented buffer used by the SEH mechanism for stack unwinding. + # Mingw-w64 has been trying to get it right for years, but it's still + # prone to stack corruption during unwinding, so we disable that by setting + # it to NULL. + # More details: https://github.com/status-im/nimbus-eth2/issues/3121 + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint]) else: linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) else: diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 74f79167a..0dbded126 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -118,26 +118,30 @@ elif defined(nimBuiltinSetjmp): c_builtin_setjmp(unsafeAddr jmpb[0]) elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): - when defined(windows) and not defined(vcc): + when defined(windows): # No `_longjmp()` on Windows. proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "longjmp".} - # The Windows `_setjmp()` takes two arguments, with the second being an - # undocumented buffer used by the SEH mechanism for stack unwinding. - # Mingw-w64 has been trying to get it right for years, but it's still - # prone to stack corruption during unwinding, so we disable that by setting - # it to NULL. - # More details: https://github.com/status-im/nimbus-eth2/issues/3121 - when defined(nimHasStyleChecks): - {.push styleChecks: off.} + when defined(vcc) or defined(clangcl): + proc c_setjmp*(jmpb: C_JmpBuf): cint {. + header: "", importc: "setjmp".} + else: + # The Windows `_setjmp()` takes two arguments, with the second being an + # undocumented buffer used by the SEH mechanism for stack unwinding. + # Mingw-w64 has been trying to get it right for years, but it's still + # prone to stack corruption during unwinding, so we disable that by setting + # it to NULL. + # More details: https://github.com/status-im/nimbus-eth2/issues/3121 + when defined(nimHasStyleChecks): + {.push styleChecks: off.} - proc c_setjmp*(jmpb: C_JmpBuf): cint = - proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {. - header: "", importc: "_setjmp".} - c_setjmp_win(jmpb, nil) + proc c_setjmp*(jmpb: C_JmpBuf): cint = + proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {. + header: "", importc: "_setjmp".} + c_setjmp_win(jmpb, nil) - when defined(nimHasStyleChecks): - {.pop.} + when defined(nimHasStyleChecks): + {.pop.} else: proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {. header: "", importc: "_longjmp".} From 7d0285853f4327a0a4f683e13971dc3429aad1f3 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 5 Jul 2022 16:11:34 +0800 Subject: [PATCH 3463/4254] rename gc to mm (#19971) --- compiler/msgs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 9d111b2e2..371a886f4 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -677,7 +677,7 @@ proc genSuccessX*(conf: ConfigRef) = const debugModeHints = "none (DEBUG BUILD, `-d:release` generates faster code)" if conf.cmd in cmdBackends: if conf.backend != backendJs: - build.add "gc: $#; " % $conf.selectedGC + build.add "mm: $#; " % $conf.selectedGC if optThreads in conf.globalOptions: build.add "threads: on; " build.add "opt: " if optOptimizeSpeed in conf.options: build.add "speed" From 01b40dc1d7c7c5331361341bdf305084c799c05b Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Wed, 6 Jul 2022 06:29:05 +1000 Subject: [PATCH 3464/4254] Fixes return values of execCmd on macos (#19963) * Fixes return values of execCmd on macos * update tests to use existing structure Co-authored-by: daniel --- lib/pure/osproc.nim | 2 +- tests/stdlib/tosproc.nim | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 512db92a4..666ccdda8 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1523,7 +1523,7 @@ elif not defined(useNimRtl): header: "".} proc execCmd(command: string): int = - when defined(linux): + when defined(posix): let tmp = csystem(command) result = if tmp == -1: tmp else: exitStatusLikeShell(tmp) else: diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index c54e0d112..f55dd3e21 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -29,6 +29,12 @@ when defined(case_testfile): # compiled test file for child process case arg of "exit_0": if true: quit(0) + of "exit_1": + if true: quit(1) + of "exit_2": + if true: quit(2) + of "exit_42": + if true: quit(42) of "exitnow_139": if true: exitnow(139) of "c_exit2_139": @@ -115,6 +121,13 @@ else: # main driver runTest("c_exit2_139", 139) runTest("quit_139", 139) + block execCmdTest: + let output = compileNimProg("-d:release -d:case_testfile", "D20220705T221100") + doAssert execCmd(output & " exit_0") == 0 + doAssert execCmd(output & " exit_1") == 1 + doAssert execCmd(output & " exit_2") == 2 + doAssert execCmd(output & " exit_42") == 42 + import std/streams block execProcessTest: From 430a1793075866179b34790a461936023fca1c0a Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:06:41 +0800 Subject: [PATCH 3465/4254] default threads on (#19368) * default threads on * make rst gcsafe * ignore threads option for nimscript * threads off * use createShared for threads * test without threads * avr threds off * avr threads off * async threads off * threads off * fix ci * restore option * make CI pleased * fix ic tests * Update config.nims * add changelog * Update changelog.md Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- changelog.md | 2 ++ config/nim.cfg | 2 ++ testament/categories.nim | 10 +++++----- tests/avr/thello.nim | 2 +- tests/destructor/trecursive.nim | 2 +- tests/ic/config.nims | 2 ++ tests/manyloc/standalone2/tavr.nim.cfg | 1 + tests/niminaction/Chapter7/Tweeter/src/tweeter.nim | 1 + tests/stdlib/ttasks.nim | 2 +- tests/system/tgcnone.nim | 2 +- 10 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 tests/ic/config.nims diff --git a/changelog.md b/changelog.md index 98655eaa3..c35a403e6 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,8 @@ becomes an alias for `addr`. - The `gc:v2` option is removed. +- The `threads:on` option becomes the default. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/config/nim.cfg b/config/nim.cfg index 7fe279f56..37d12a02d 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -17,6 +17,8 @@ cc = gcc hint[LineTooLong]=off #hint[XDeclaredButNotUsed]=off +threads:on + # Examples of how to setup a cross-compiler: # Nim can target architectures and OSes different than the local host # Syntax: ..gcc.exe = "" diff --git a/testament/categories.nim b/testament/categories.nim index a092fec84..43ea9f0ee 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -59,10 +59,10 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = var test2 = makeTest("tests/dll/server.nim", options & " --threads:on" & rpath, cat) test2.spec.action = actionCompile testSpec c, test2 - var test3 = makeTest("lib/nimhcr.nim", options & " --outdir:tests/dll" & rpath, cat) + var test3 = makeTest("lib/nimhcr.nim", options & " --threads:off --outdir:tests/dll" & rpath, cat) test3.spec.action = actionCompile testSpec c, test3 - var test4 = makeTest("tests/dll/visibility.nim", options & " --app:lib" & rpath, cat) + var test4 = makeTest("tests/dll/visibility.nim", options & " --threads:off --app:lib" & rpath, cat) test4.spec.action = actionCompile testSpec c, test4 @@ -77,13 +77,13 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = defer: putEnv(libpathenv, libpath) testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) - testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & rpath, cat) - testSpec r, makeTest("tests/dll/visibility.nim", options & rpath, cat) + testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) + testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) if "boehm" notin options: # force build required - see the comments in the .nim file for more details var hcri = makeTest("tests/dll/nimhcr_integration.nim", - options & " --forceBuild --hotCodeReloading:on" & rpath, cat) + options & " --threads:off --forceBuild --hotCodeReloading:on" & rpath, cat) let nimcache = nimcacheDir(hcri.name, hcri.options, getTestSpecTarget()) let cmd = prepareTestCmd(hcri.spec.getCmd, hcri.name, hcri.options, nimcache, getTestSpecTarget()) diff --git a/tests/avr/thello.nim b/tests/avr/thello.nim index a0191815c..7ebaeae5f 100644 --- a/tests/avr/thello.nim +++ b/tests/avr/thello.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim c --compileOnly --os:standalone --exceptions:quirky -d:noSignalHandler -d:danger $file" + cmd: "nim c --compileOnly --os:standalone --exceptions:quirky -d:noSignalHandler -d:danger --threads:off $file" action: "compile" """ diff --git a/tests/destructor/trecursive.nim b/tests/destructor/trecursive.nim index 17a40e5a9..e7afa6ba9 100644 --- a/tests/destructor/trecursive.nim +++ b/tests/destructor/trecursive.nim @@ -47,7 +47,7 @@ proc `=destroy`(x: var MyObject) = proc `=`(x: var MyObject, y: MyObject) {.error.} proc newMyObject(i: int): MyObject = - result.p = create(int) + result.p = createShared(int) result.p[] = i proc test: seq[MyObject] = diff --git a/tests/ic/config.nims b/tests/ic/config.nims new file mode 100644 index 000000000..76b29a6aa --- /dev/null +++ b/tests/ic/config.nims @@ -0,0 +1,2 @@ +when defined(windows): + --threads:off diff --git a/tests/manyloc/standalone2/tavr.nim.cfg b/tests/manyloc/standalone2/tavr.nim.cfg index e5291969d..2a31618d0 100644 --- a/tests/manyloc/standalone2/tavr.nim.cfg +++ b/tests/manyloc/standalone2/tavr.nim.cfg @@ -2,3 +2,4 @@ --cpu:avr --os:standalone --compileOnly +--threads:off diff --git a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim index fe39278fb..2fac949b9 100644 --- a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim +++ b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim @@ -1,5 +1,6 @@ discard """ action: compile +matrix: "--threads:off" """ import asyncdispatch, times diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim index 75fed9f9b..e90823aba 100644 --- a/tests/stdlib/ttasks.nim +++ b/tests/stdlib/ttasks.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp" - matrix: "--gc:orc" + matrix: "--gc:orc --threads:off" """ import std/[tasks, strformat] diff --git a/tests/system/tgcnone.nim b/tests/system/tgcnone.nim index 700176d5f..47c6c6014 100644 --- a/tests/system/tgcnone.nim +++ b/tests/system/tgcnone.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--gc:none -d:useMalloc" + matrix: "--gc:none -d:useMalloc --threads:off" """ # bug #15617 let x = 4 From dcb28fd061743ba141b3914501512b5eb352aa1b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 7 Jul 2022 20:14:05 +0800 Subject: [PATCH 3466/4254] cache rope when threads are enabled (#19981) * cache rope * add threadvar --- compiler/ropes.nim | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/ropes.nim b/compiler/ropes.nim index a44d84ddc..610159c75 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -86,13 +86,12 @@ proc newRope(data: string = ""): Rope = result.L = -data.len result.data = data -when not compileOption("threads"): - var - cache: array[0..2048*2 - 1, Rope] +var + cache {.threadvar.} : array[0..2048*2 - 1, Rope] - proc resetRopeCache* = - for i in low(cache)..high(cache): - cache[i] = nil +proc resetRopeCache* = + for i in low(cache)..high(cache): + cache[i] = nil proc ropeInvariant(r: Rope): bool = if r == nil: From ad0aee535435ac9b22c2ee9ef02085ffdc901d48 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 7 Jul 2022 15:26:58 +0200 Subject: [PATCH 3467/4254] sysrand: fix syscall signature [backport] (#19982) sysrand: fix syscall signature `syscall` is a `C` varags function --- lib/std/sysrand.nim | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 1b7b2c024..4ee25d01e 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -170,9 +170,8 @@ elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten): const syscallHeader = """#include #include """ - proc syscall( - n: clong, buf: pointer, bufLen: cint, flags: cuint - ): clong {.importc: "syscall", header: syscallHeader.} + proc syscall(n: clong): clong {. + importc: "syscall", varargs, header: syscallHeader.} # When reading from the urandom source (GRND_RANDOM is not set), # getrandom() will block until the entropy pool has been # initialized (unless the GRND_NONBLOCK flag was specified). If a @@ -211,7 +210,7 @@ elif defined(zephyr): proc sys_csrand_get(dst: pointer, length: csize_t): cint {.importc: "sys_csrand_get", header: "".} # Fill the destination buffer with cryptographically secure # random data values - # + # proc getRandomImpl(p: pointer, size: int): int {.inline.} = # 0 if success, -EIO if entropy reseed error From 7a29a782f84ebceec0fb5c3d39bb484621831fca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 9 Jul 2022 06:46:05 +0200 Subject: [PATCH 3468/4254] removed caching logic; saves 400MB for an ORC booting compiler (#19989) --- compiler/injectdestructors.nim | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 6500c5bc7..867d30d96 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -80,12 +80,6 @@ import sets, hashes proc hash(n: PNode): Hash = hash(cast[pointer](n)) -proc aliasesCached(cache: var Table[(PNode, PNode), AliasKind], obj, field: PNode): AliasKind = - let key = (obj, field) - if not cache.hasKey(key): - cache[key] = aliases(obj, field) - cache[key] - type State = ref object lastReads: IntSet @@ -116,9 +110,8 @@ proc mergeStates(a: var State, b: sink State) = a.alreadySeen.incl b.alreadySeen proc computeLastReadsAndFirstWrites(cfg: ControlFlowGraph) = - var cache = initTable[(PNode, PNode), AliasKind]() template aliasesCached(obj, field: PNode): AliasKind = - aliasesCached(cache, obj, field) + aliases(obj, field) var cfg = cfg preprocessCfg(cfg) From e8ee2f9c2ad06cad2f62fe7505acbb43530f28d7 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sat, 9 Jul 2022 17:28:14 +0800 Subject: [PATCH 3469/4254] update section regarding `std/assertions` in changelog (#19992) Update changelog.md --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index c35a403e6..770393e13 100644 --- a/changelog.md +++ b/changelog.md @@ -22,7 +22,7 @@ - `addr` is now available for all addressable locations, `unsafeAddr` is deprecated and becomes an alias for `addr`. -- io is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/syncio`. +- `io` and `assertions` are about to move out of system; use `-d:nimPreviewSlimSystem`, import `std/syncio` and import `std/assertions`. - The `gc:v2` option is removed. From ed2bf02a511ae230243ce384ad16c318ca3fe661 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Sun, 10 Jul 2022 15:37:15 +0800 Subject: [PATCH 3470/4254] remove `when declared(cache)`; cache is always there (#19991) --- compiler/ropes.nim | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 610159c75..677a3ce09 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -111,16 +111,13 @@ var gCacheMisses* = 0 var gCacheIntTries* = 0 proc insertInCache(s: string): Rope = - when declared(cache): - inc gCacheTries - var h = hash(s) and high(cache) - result = cache[h] - if isNil(result) or result.data != s: - inc gCacheMisses - result = newRope(s) - cache[h] = result - else: + inc gCacheTries + var h = hash(s) and high(cache) + result = cache[h] + if isNil(result) or result.data != s: + inc gCacheMisses result = newRope(s) + cache[h] = result proc rope*(s: string): Rope = ## Converts a string to a rope. From a90763ebd762a4862e2af1dab7d4429f4e984a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sun, 10 Jul 2022 15:40:26 +0200 Subject: [PATCH 3471/4254] Fixes Compilation error with --app:lib (#19965) Fixes Compilation error with --app:lib when a module tries to pull os.paramStr on posix by throwing a runtime exception instead. More details here: #19964 --- lib/pure/os.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 247a0d089..a60e913f1 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2939,7 +2939,7 @@ elif defined(genode): proc paramCount*(): int = raise newException(OSError, "paramCount is not implemented on Genode") -elif weirdTarget: +elif weirdTarget or (defined(posix) and appType == "lib"): proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = raise newException(OSError, "paramStr is not implemented on current platform") From fb5fbf1e087563f0288b8ed684c8dcc1891730b0 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Mon, 11 Jul 2022 11:28:52 +0200 Subject: [PATCH 3472/4254] Fix nested finally handling in closureiters [backport] (#19933) * Fix nested finally handling in closureiters * Fix CI * review comment * third time the charm * Update compiler/closureiters.nim Co-authored-by: Dominik Picheta Co-authored-by: Dominik Picheta --- compiler/closureiters.nim | 31 ++++++++++++--- tests/iter/titer_issues.nim | 75 +++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 6370d0dcb..2848942fa 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -121,7 +121,10 @@ # yield 2 # if :unrollFinally: # This node is created by `newEndFinallyNode` # if :curExc.isNil: -# return :tmpResult +# if nearestFinally == 0: +# return :tmpResult +# else: +# :state = nearestFinally # bubble up # else: # closureIterSetupExc(nil) # raise @@ -807,7 +810,10 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode = # Generate the following code: # if :unrollFinally: # if :curExc.isNil: - # return :tmpResult + # if nearestFinally == 0: + # return :tmpResult + # else: + # :state = nearestFinally # bubble up # else: # raise let curExc = ctx.newCurExcAccess() @@ -816,11 +822,17 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode = let cmp = newTree(nkCall, newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info), curExc, nilnode) cmp.typ = ctx.g.getSysType(info, tyBool) - let asgn = newTree(nkFastAsgn, - newSymNode(getClosureIterResult(ctx.g, ctx.fn, ctx.idgen), info), - ctx.newTmpResultAccess()) + let retStmt = + if ctx.nearestFinally == 0: + # last finally, we can return + let asgn = newTree(nkFastAsgn, + newSymNode(getClosureIterResult(ctx.g, ctx.fn, ctx.idgen), info), + ctx.newTmpResultAccess()) + newTree(nkReturnStmt, asgn) + else: + # bubble up to next finally + newTree(nkGotoState, ctx.g.newIntLit(info, ctx.nearestFinally)) - let retStmt = newTree(nkReturnStmt, asgn) let branch = newTree(nkElifBranch, cmp, retStmt) let nullifyExc = newTree(nkCall, newSymNode(ctx.g.getCompilerProc("closureIterSetupExc")), nilnode) @@ -864,6 +876,13 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = of nkSkip: discard + of nkTryStmt: + if n.hasYields: + # the inner try will handle these transformations + discard + else: + for i in 0.. try + iterator p1: int {.closure.} = + try: + yield 0 + try: + return + finally: + echo "nested finally" + echo "shouldn't run" + finally: + echo "outer finally" + echo "shouldn't run" + + for _ in p1(): + discard + + # try -> try yield + iterator p2: int {.closure.} = + try: + try: + yield 0 + return + finally: + echo "nested finally" + echo "shouldn't run" + finally: + echo "outer finally" + echo "shouldn't run" + + for _ in p2(): + discard + + # try yield -> try yield + iterator p3: int {.closure.} = + try: + yield 0 + try: + yield 0 + return + finally: + echo "nested finally" + echo "shouldn't run" + finally: + echo "outer finally" + echo "shouldn't run" + + for _ in p3(): + discard + + # try -> try + iterator p4: int {.closure.} = + try: + try: + return + finally: + echo "nested finally" + echo "shouldn't run" + finally: + echo "outer finally" + echo "shouldn't run" + + for _ in p4(): + discard From cf1c14936670ef0c175149f6fba4dffc1cf4ba43 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 11 Jul 2022 23:27:01 +0800 Subject: [PATCH 3473/4254] tracking the memory usage of orc-booting compiler for each commit (#19941) * yaml * pub * redo * let's comment * now action * newly * code name * build * ready * remove submodule * build * modify name * fix * rephrase * trigger when PR is merged --- .github/workflows/ci_publish.yml | 90 ++++++++++++++++++++++++++++++++ ci/action.nim | 28 ++++++++++ 2 files changed, 118 insertions(+) create mode 100644 .github/workflows/ci_publish.yml create mode 100644 ci/action.nim diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml new file mode 100644 index 000000000..94ea5ff8f --- /dev/null +++ b/.github/workflows/ci_publish.yml @@ -0,0 +1,90 @@ +name: Tracking orc-booting compiler memory usage + +on: + push: + branches: + - devel + + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04] + cpu: [amd64] + name: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: 'Install node.js 16.x' + uses: actions/setup-node@v2 + with: + node-version: '16.x' + + - name: 'Install dependencies (Linux amd64)' + if: runner.os == 'Linux' && matrix.cpu == 'amd64' + run: | + sudo apt-fast update -qq + DEBIAN_FRONTEND='noninteractive' \ + sudo apt-fast install --no-install-recommends -yq \ + libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ + valgrind libc6-dbg libblas-dev xorg-dev + - name: 'Install dependencies (macOS)' + if: runner.os == 'macOS' + run: brew install boehmgc make sfml gtk+3 + - name: 'Install dependencies (Windows)' + if: runner.os == 'Windows' + shell: bash + run: | + set -e + . ci/funs.sh + nimInternalInstallDepsWindows + echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" + + - name: 'Add build binaries to PATH' + shell: bash + run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" + + - name: 'System information' + shell: bash + run: . ci/funs.sh && nimCiSystemInfo + + - name: 'Build csourcesAny' + shell: bash + run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' + + - name: 'Build koch' + shell: bash + run: nim c koch + + - name: 'Build Nim' + shell: bash + run: ./koch boot -d:release -d:nimStrictMode --lib:lib + + - name: 'Action' + shell: bash + run: nim c -r -d:release ci/action.nim + + - name: 'Comment' + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + + try { + const data = fs.readFileSync('ci/nimcache/results.txt', 'utf8'); + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: data + }) + } catch (err) { + console.error(err); + } + diff --git a/ci/action.nim b/ci/action.nim new file mode 100644 index 000000000..8c3260096 --- /dev/null +++ b/ci/action.nim @@ -0,0 +1,28 @@ +import std/[strutils, os, osproc, parseutils, strformat] + + +proc main() = + var msg = "" + const cmd = "./koch boot --gc:orc -d:release" + + let (output, exitCode) = execCmdEx(cmd) + + doAssert exitCode == 0, output + + var start = rfind(output, "Hint: gc") + if start < 0: + start = rfind(output, "Hint: mm") + doAssert parseUntil(output, msg, "; proj", start) > 0, output + + let (commitHash, _) = execCmdEx("""git log --format="%H" -n 1""") + + let welcomeMessage = fmt"""Thanks for your hard work on this PR! +The lines below are statistics of the Nim compiler built from {commitHash} + +{msg} +""" + createDir "ci/nimcache" + writeFile "ci/nimcache/results.txt", welcomeMessage + +when isMainModule: + main() \ No newline at end of file From d0bae989d63f91345cd0991e00502c05d18dbf6b Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 12 Jul 2022 09:05:50 +0800 Subject: [PATCH 3474/4254] fix github script failure (#20006) * yaml * pub * redo * let's comment * now action * newly * code name * build * ready * remove submodule * build * modify name * fix * rephrase * trigger when PR is merged * fix CI failure --- .github/workflows/ci_publish.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml index 94ea5ff8f..90a3438a7 100644 --- a/.github/workflows/ci_publish.yml +++ b/.github/workflows/ci_publish.yml @@ -1,13 +1,13 @@ name: Tracking orc-booting compiler memory usage on: - push: - branches: - - devel + pull_request: + types: [closed] jobs: build: + if: github.event.pull_request.merged == true strategy: fail-fast: false matrix: From a97b00ad8d18d836d693c224909b607d2af0c4b1 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Tue, 12 Jul 2022 19:07:18 +0800 Subject: [PATCH 3475/4254] try to optimize hot spots for orc-booting compiler (#20001) * optimize hot spots fro orc-booting compiler * remove GC_ref * minor * remove comments * Revert "minor" This reverts commit 4965a190a2d6457044faa1442795e55bdad57602. * emulate cursor --- compiler/astalgo.nim | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index bc5b7d6e1..22f4257fc 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -18,6 +18,9 @@ import when defined(nimPreviewSlimSystem): import std/assertions +when not defined(nimHasCursor): + {.pragma: cursor.} + proc hashNode*(p: RootRef): Hash proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope # Convert a tree into its YAML representation; this is used by the @@ -815,16 +818,21 @@ type name*: PIdent proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym = + # hot spots var h = ti.h and high(tab.data) var start = h - result = tab.data[h] - while result != nil: - if result.name.id == ti.name.id: break + var p {.cursor.} = tab.data[h] + while p != nil: + if p.name.id == ti.name.id: break h = nextTry(h, high(tab.data)) if h == start: - result = nil + p = nil break - result = tab.data[h] + p = tab.data[h] + if p != nil: + result = p # increase the count + else: + result = nil ti.h = nextTry(h, high(tab.data)) proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = From 5c510a9ab96f265ffb0323a18deadb5bb175cfdc Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Tue, 12 Jul 2022 19:03:58 +0300 Subject: [PATCH 3476/4254] allow dots in defined() (#20010) * allow dots in defined() refs https://github.com/nim-lang/RFCs/issues/181 * mention accents in older versions --- changelog.md | 3 +++ compiler/semexprs.nim | 14 +++++++++++++- tests/misc/tdefine.nim | 19 +++++++++++++++++-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 770393e13..7498a9567 100644 --- a/changelog.md +++ b/changelog.md @@ -101,6 +101,9 @@ becomes an alias for `addr`. - Full command syntax and block arguments i.e. `foo a, b: c` are now allowed for the right-hand side of type definitions in type sections. Previously they would error with "invalid indentation". +- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. + In the command line, this is defined as `-d:a.b.c`. Older versions can + use accents as in ``defined(`a.b.c`)`` to access such defines. ## Compiler changes diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e07a98417..fed9cae21 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1938,11 +1938,23 @@ proc semYield(c: PContext, n: PNode): PNode = elif c.p.owner.typ[0] != nil: localError(c.config, n.info, errGenerated, "yield statement must yield a value") +proc considerQuotedIdentOrDot(c: PContext, n: PNode, origin: PNode = nil): PIdent = + if n.kind == nkDotExpr: + let a = considerQuotedIdentOrDot(c, n[0], origin).s + let b = considerQuotedIdentOrDot(c, n[1], origin).s + var s = newStringOfCap(a.len + b.len + 1) + s.add(a) + s.add('.') + s.add(b) + result = getIdent(c.cache, s) + else: + result = considerQuotedIdent(c, n, origin) + proc semDefined(c: PContext, n: PNode): PNode = checkSonsLen(n, 2, c.config) # we replace this node by a 'true' or 'false' node: result = newIntNode(nkIntLit, 0) - result.intVal = ord isDefined(c.config, considerQuotedIdent(c, n[1], n).s) + result.intVal = ord isDefined(c.config, considerQuotedIdentOrDot(c, n[1], n).s) result.info = n.info result.typ = getSysType(c.graph, n.info, tyBool) diff --git a/tests/misc/tdefine.nim b/tests/misc/tdefine.nim index f1c6e7a96..c4d11c941 100644 --- a/tests/misc/tdefine.nim +++ b/tests/misc/tdefine.nim @@ -1,6 +1,6 @@ discard """ joinable: false -cmd: "nim c -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -r $file" +cmd: "nim c -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -d:namespaced.define=false -d:double.namespaced.define -r $file" """ const booldef {.booldefine.} = false @@ -27,4 +27,19 @@ type T = object when intdef2 == 1: field2: int when strdef2 == "abc": - field3: int \ No newline at end of file + field3: int + +doAssert not defined(booldef3) +doAssert not defined(intdef2) +doAssert not defined(strdef2) +discard T(field1: 1, field2: 2, field3: 3) + +doAssert defined(namespaced.define) +const `namespaced.define` {.booldefine.} = true +doAssert not `namespaced.define` + +doAssert defined(double.namespaced.define) +const `double.namespaced.define` {.booldefine.} = false +doAssert `double.namespaced.define` + +doAssert not defined(namespaced.butnotdefined) From 0180c6179aa0ff2dacaa6c063c0fa24cf459a84d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 13 Jul 2022 01:35:08 +0800 Subject: [PATCH 3477/4254] fix #18735; genDepend broken for duplicate module names in separate folders (#19988) --- compiler/depends.nim | 58 ++++++++++++++++++++++++++++++++++++++------ compiler/options.nim | 2 +- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/compiler/depends.nim b/compiler/depends.nim index 30fc961c5..1dcdec989 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -9,10 +9,12 @@ # This module implements a dependency file generator. -import - options, ast, ropes, idents, passes, modulepaths, pathutils +import options, ast, ropes, passes, pathutils, msgs, lineinfos -from modulegraphs import ModuleGraph, PPassContext +import modulegraphs + +import std/[os, strutils, parseutils] +import std/private/globs type TGen = object of PPassContext @@ -28,6 +30,50 @@ proc addDependencyAux(b: Backend; importing, imported: string) = b.dotGraph.addf("\"$1\" -> \"$2\";$n", [rope(importing), rope(imported)]) # s1 -> s2_4[label="[0-9]"]; +proc toNimblePath(s: string, isStdlib: bool): string = + const stdPrefix = "std/" + const pkgPrefix = "pkg/" + if isStdlib: + let sub = "lib/" + var start = s.find(sub) + if start < 0: + doAssert false + else: + start += sub.len + let base = s[start..^1] + + if base.startsWith("system") or base.startsWith("std"): + result = base + else: + for dir in stdlibDirs: + if base.startsWith(dir): + return stdPrefix & base.splitFile.name + + result = stdPrefix & base + else: + var sub = getEnv("NIMBLE_DIR") + if sub.len == 0: + sub = ".nimble/pkgs/" + else: + sub.add "/pkgs/" + var start = s.find(sub) + if start < 0: + result = s + else: + start += sub.len + start += skipUntil(s, '/', start) + start += 1 + result = pkgPrefix & s[start..^1] + +proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) = + doAssert n.kind == nkSym, $n.kind + + let path = splitFile(toProjPath(g.config, n.sym.position.FileIndex)) + let modulePath = splitFile(toProjPath(g.config, g.module.position.FileIndex)) + let parent = nativeToUnixPath(modulePath.dir / modulePath.name).toNimblePath(belongsToStdlib(g.graph, g.module)) + let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym)) + addDependencyAux(b, parent, child) + proc addDotDependency(c: PPassContext, n: PNode): PNode = result = n let g = PGen(c) @@ -35,11 +81,9 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode = case n.kind of nkImportStmt: for i in 0.. 0 and not ret.startsWith ".." -const stdlibDirs = [ +const stdlibDirs* = [ "pure", "core", "arch", "pure/collections", "pure/concurrency", From af140966ea5b58ea248459acb74bf84537deb423 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Wed, 13 Jul 2022 00:24:17 +0300 Subject: [PATCH 3478/4254] Add #19406 changes to changelog (#20011) --- changelog.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 7498a9567..68b133040 100644 --- a/changelog.md +++ b/changelog.md @@ -66,6 +66,12 @@ becomes an alias for `addr`. ## Language changes +- [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental, + meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. +- Templates now accept [macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas). +- Macro pragmas for var/let/const sections have been redesigned in a way that works + similarly to routine macro pragmas. The new behavior is documented in the + [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas). - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, allowing multiple type definitions to be injected in place of the original type definition. @@ -96,8 +102,6 @@ becomes an alias for `addr`. x, y, z: int Baz = object ``` -- [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental, - meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. - Full command syntax and block arguments i.e. `foo a, b: c` are now allowed for the right-hand side of type definitions in type sections. Previously they would error with "invalid indentation". From 489f6ddfefc4993af97eb2884b6d8173a4ee8b9d Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Wed, 13 Jul 2022 22:55:33 +1000 Subject: [PATCH 3479/4254] fix #20012 (#20013) * replace gcc asm with __asm__ and add a test * update test case to specify gcc or clang and not cpp Co-authored-by: daniel --- compiler/extccomp.nim | 2 +- tests/compiler/tasm.nim | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/compiler/tasm.nim diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f1dc01f44..23c43cb67 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -86,7 +86,7 @@ compiler gcc: linkLibCmd: " -l$1", debug: "", pic: "-fPIC", - asmStmtFrmt: "asm($1);$n", + asmStmtFrmt: "__asm__($1);$n", structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name produceAsm: gnuAsmListing, cppXsupport: "-std=gnu++14 -funsigned-char", diff --git a/tests/compiler/tasm.nim b/tests/compiler/tasm.nim new file mode 100644 index 000000000..9f60231e0 --- /dev/null +++ b/tests/compiler/tasm.nim @@ -0,0 +1,15 @@ +proc testAsm() = + let src = 41 + var dst = 0 + + asm """ + mov %1, %0\n\t + add $1, %0 + : "=r" (`dst`) + : "r" (`src`)""" + + doAssert dst == 42 + +when defined(gcc) or defined(clang) and not defined(cpp): + {.passc: "-std=c99".} + testAsm() \ No newline at end of file From 73ee34f56fc267e6b8b29d12b22f969f7f8a7788 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Wed, 13 Jul 2022 22:37:31 +0800 Subject: [PATCH 3480/4254] use pull_request_target (#20020) --- .github/workflows/ci_publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml index 90a3438a7..a56ff9a7e 100644 --- a/.github/workflows/ci_publish.yml +++ b/.github/workflows/ci_publish.yml @@ -1,7 +1,7 @@ name: Tracking orc-booting compiler memory usage on: - pull_request: + pull_request_target: types: [closed] From 93211a2bddf8e6a806c3fd4e9322ca21f0a2a9c4 Mon Sep 17 00:00:00 2001 From: silent-observer Date: Thu, 14 Jul 2022 13:03:16 +0300 Subject: [PATCH 3481/4254] Add sink and lent annotations to the critbits module (#20021) * Add sink and lent to critbits * Remove lent for pairs I guess lent doesn't work well inside tuples * Remove lent from template in critbits Apparently this also doesn't work, because some checks failed --- lib/pure/collections/critbits.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index e12984995..dca60b37b 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -197,7 +197,7 @@ proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = discard exclImpl(c, key) result = c.count == oldCount -proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = +proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: sink T): bool = ## Returns true if `c` contains the given `key`. If the key does not exist, ## `c[key] = val` is performed. ## @@ -270,7 +270,7 @@ proc incl*(c: var CritBitTree[void], key: string) = discard rawInsert(c, key) -proc incl*[T](c: var CritBitTree[T], key: string, val: T) = +proc incl*[T](c: var CritBitTree[T], key: string, val: sink T) = ## Inserts `key` with value `val` into `c`. ## ## **See also:** @@ -284,7 +284,7 @@ proc incl*[T](c: var CritBitTree[T], key: string, val: T) = var n = rawInsert(c, key) n.val = val -proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = +proc `[]=`*[T](c: var CritBitTree[T], key: string, val: sink T) = ## Alias for `incl <#incl,CritBitTree[T],string,T>`_. ## ## **See also:** @@ -300,7 +300,7 @@ template get[T](c: CritBitTree[T], key: string): T = n.val -func `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = +func `[]`*[T](c: CritBitTree[T], key: string): lent T {.inline.} = ## Retrieves the value at `c[key]`. If `key` is not in `t`, the ## `KeyError` exception is raised. One can check with `hasKey` whether ## the key exists. @@ -342,7 +342,7 @@ iterator keys*[T](c: CritBitTree[T]): string = for x in leaves(c.root): yield x.key -iterator values*[T](c: CritBitTree[T]): T = +iterator values*[T](c: CritBitTree[T]): lent T = ## Yields all values of `c` in the lexicographical order of the ## corresponding keys. ## @@ -415,7 +415,7 @@ iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string): string = let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.key -iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): T = +iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): lent T = ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. ## @@ -518,7 +518,7 @@ func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = else: c.root.byte else: 0 -proc toCritBitTree*[T](pairs: openArray[(string, T)]): CritBitTree[T] {.since: (1, 3).} = +proc toCritBitTree*[T](pairs: sink openArray[(string, T)]): CritBitTree[T] {.since: (1, 3).} = ## Creates a new `CritBitTree` that contains the given `pairs`. runnableExamples: doAssert {"a": "0", "b": "1", "c": "2"}.toCritBitTree is CritBitTree[string] @@ -526,7 +526,7 @@ proc toCritBitTree*[T](pairs: openArray[(string, T)]): CritBitTree[T] {.since: ( for item in pairs: result.incl item[0], item[1] -proc toCritBitTree*(items: openArray[string]): CritBitTree[void] {.since: (1, 3).} = +proc toCritBitTree*(items: sink openArray[string]): CritBitTree[void] {.since: (1, 3).} = ## Creates a new `CritBitTree` that contains the given `items`. runnableExamples: doAssert ["a", "b", "c"].toCritBitTree is CritBitTree[void] From 10c8e2037db9ec3dc53fdaf1cc27e837e204af76 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Thu, 14 Jul 2022 18:42:56 +0800 Subject: [PATCH 3482/4254] fixes #20015; document `shallowCopy` does a deep copy with ARC/ORC (#20025) --- lib/system.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index 4080fee06..6e8519cf6 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -473,6 +473,8 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} ## Be careful with the changed semantics though! ## There is a reason why the default assignment does a deep copy of sequences ## and strings. + ## + ## .. warning:: `shallowCopy` does a deep copy with ARC/ORC. # :array|openArray|string|seq|cstring|tuple proc `[]`*[I: Ordinal;T](a: T; i: I): T {. From 800cb006e74f8c52bde69cfc1eb9e55fcc439633 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Thu, 14 Jul 2022 08:20:40 -0400 Subject: [PATCH 3483/4254] Change `styleCheck` to ignore foreign packages (#19822) * Change `styleCheck` to ignore foreign packages * Symbols from foreign packages are now ignored. * Fixed `styleCheck` violations in `compiler` package. * Added symbol ownership to custom annotation pragmas. * Minor refactors to cleanup style check callsites. * Minor internal documentation of reasons why a symbol isn't checked. Style violations were fixed in the compiler after thet were exposed by the changes. The compiler wouldn't compile otherwise. Symbol ownership for custom pragma annotations is needed for checking the annotation's style. A NPE was raised otherwise. Fixes #10201 See also nim-lang/RFCs#456 * Fix a misunderstanding about excluding field style checks I had refactored the callsites of `styleCheckUse` to apply the DRY principle, but I misunderstood the field access handling in a template as a general case. This corrects it. * Fix some `styleCheck` violations in `compiler/evalffi` The violations were exposed in CI when the compiler was built with libffi. * Removed some uneeded transitionary code * Add changelog entry Co-authored-by: quantimnot --- changelog.md | 2 ++ compiler/evalffi.nim | 8 ++--- compiler/ic/bitabs.nim | 8 ++--- compiler/linter.nim | 67 +++++++++++++++++++++++++----------------- compiler/msgs.nim | 4 +-- compiler/pragmas.nim | 6 ++-- compiler/semexprs.nim | 2 +- compiler/semgnrc.nim | 2 +- compiler/semmagic.nim | 2 +- compiler/semstmts.nim | 14 ++++----- compiler/semtempl.nim | 12 ++++---- compiler/semtypes.nim | 8 ++--- compiler/suggest.nim | 3 +- compiler/vm.nim | 8 ++--- compiler/vmops.nim | 64 ++++++++++++++++++++-------------------- compiler/wordrecg.nim | 14 ++++----- 16 files changed, 118 insertions(+), 106 deletions(-) diff --git a/changelog.md b/changelog.md index 68b133040..47479fc5c 100644 --- a/changelog.md +++ b/changelog.md @@ -114,6 +114,8 @@ becomes an alias for `addr`. - `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, without requiring `-d:nimVersion140` which is now a noop. +- `--styleCheck` now only applies to the current package. + ## Tool changes diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 5004011ed..d1d88a1fa 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -110,8 +110,8 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI else: globalError(conf, info, "cannot map calling convention to FFI") -template rd(T, p: untyped): untyped = (cast[ptr T](p))[] -template wr(T, p, v: untyped): untyped = (cast[ptr T](p))[] = v +template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[] +template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v template `+!`(x, y: untyped): untyped = cast[pointer](cast[ByteAddress](x) + y) @@ -177,8 +177,8 @@ const maxPackDepth = 20 var packRecCheck = 0 proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) = - template awr(T, v: untyped): untyped = - wr(T, res, v) + template awr(typ, v: untyped): untyped = + wr(typ, res, v) case typ.kind of tyBool: awr(bool, v.intVal != 0) diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim index ae673b574..8adab8388 100644 --- a/compiler/ic/bitabs.nim +++ b/compiler/ic/bitabs.nim @@ -93,13 +93,13 @@ proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId = t.vals.add v -proc `[]`*[T](t: var BiTable[T]; LitId: LitId): var T {.inline.} = - let idx = idToIdx LitId +proc `[]`*[T](t: var BiTable[T]; litId: LitId): var T {.inline.} = + let idx = idToIdx litId assert idx < t.vals.len result = t.vals[idx] -proc `[]`*[T](t: BiTable[T]; LitId: LitId): lent T {.inline.} = - let idx = idToIdx LitId +proc `[]`*[T](t: BiTable[T]; litId: LitId): lent T {.inline.} = + let idx = idToIdx litId assert idx < t.vals.len result = t.vals[idx] diff --git a/compiler/linter.nim b/compiler/linter.nim index 5fb646051..2c0ad4d6f 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -12,7 +12,8 @@ import std/strutils from std/sugar import dup -import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs +import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages +export packages const Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'} @@ -85,24 +86,32 @@ proc differ*(line: string, a, b: int, x: string): string = result = y proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = - # operators stay as they are: - if k in {skResult, skTemp} or s.name.s[0] notin Letters: return - if k in {skType, skGenericParam} and sfAnon in s.flags: return - if s.typ != nil and s.typ.kind == tyTypeDesc: return - if {sfImportc, sfExportc} * s.flags != {}: return - if optStyleCheck notin s.options: return let beau = beautifyName(s.name.s, k) if s.name.s != beau: lintReport(conf, info, beau, s.name.s) -template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = - if {optStyleHint, optStyleError} * conf.globalOptions != {} and optStyleUsages notin conf.globalOptions: - nep1CheckDefImpl(conf, info, s, k) +template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind) = + ## Check symbol definitions adhere to NEP1 style rules. + if optStyleCheck in ctx.config.options and # ignore if styleChecks are off + hintName in ctx.config.notes and # ignore if name checks are not requested + ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages + optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage + sym.kind != skResult and # ignore `result` + sym.kind != skTemp and # ignore temporary variables created by the compiler + sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols??? + k notin {skType, skGenericParam} and # ignore types and generic params + (sym.typ == nil or sym.typ.kind != tyTypeDesc) and # ignore `typedesc` + {sfImportc, sfExportc} * sym.flags == {} and # ignore FFI + sfAnon notin sym.flags: # ignore if created by compiler + nep1CheckDefImpl(ctx.config, info, sym, k) -template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym) = - styleCheckDef(conf, info, s, s.kind) -template styleCheckDef*(conf: ConfigRef; s: PSym) = - styleCheckDef(conf, s.info, s, s.kind) +template styleCheckDef*(ctx: PContext; info: TLineInfo; s: PSym) = + ## Check symbol definitions adhere to NEP1 style rules. + styleCheckDef(ctx, info, s, s.kind) + +template styleCheckDef*(ctx: PContext; s: PSym) = + ## Check symbol definitions adhere to NEP1 style rules. + styleCheckDef(ctx, s.info, s, s.kind) proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string = let line = sourceLine(conf, info) @@ -116,23 +125,27 @@ proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string = let last = first+identLen(line, first)-1 result = differ(line, first, last, newName) -proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) = - if info.fileIndex.int < 0: return - # we simply convert it to what it looks like in the definition - # for consistency - - # operators stay as they are: - if s.kind == skTemp or s.name.s[0] notin Letters or sfAnon in s.flags: - return - +proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) = let newName = s.name.s let badName = differs(conf, info, newName) if badName.len > 0: - # special rules for historical reasons - let forceHint = badName == "nnkArgList" and newName == "nnkArglist" or badName == "nnkArglist" and newName == "nnkArgList" - lintReport(conf, info, newName, badName, forceHint = forceHint, extraMsg = "".dup(addDeclaredLoc(conf, s))) + lintReport(conf, info, newName, badName, "".dup(addDeclaredLoc(conf, s))) -proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = +template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) = + ## Check symbol uses match their definition's style. + if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off + hintName in ctx.config.notes and # ignore if name checks are not requested + ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages + sym.kind != skTemp and # ignore temporary variables created by the compiler + sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols??? + sfAnon notin sym.flags: # ignore temporary variables created by the compiler + styleCheckUseImpl(ctx.config, info, sym) + +proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = let wanted = $w if pragmaName != wanted: lintReport(conf, info, wanted, pragmaName) + +template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = + if {optStyleHint, optStyleError} * conf.globalOptions != {}: + checkPragmaUseImpl(conf, info, w, pragmaName) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 371a886f4..6d770e72f 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -622,9 +622,9 @@ template internalAssert*(conf: ConfigRef, e: bool) = let arg = info2.toFileLineCol internalErrorImpl(conf, unknownLineInfo, arg, info2) -template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, forceHint = false, extraMsg = "") = +template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraMsg = "") = let m = "'$1' should be: '$2'$3" % [got, beau, extraMsg] - let msg = if optStyleError in conf.globalOptions and not forceHint: errGenerated else: hintName + let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName liMessage(conf, info, msg, m, doNothing, instLoc()) proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 2262e441b..1487a871d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -829,8 +829,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, let ident = considerQuotedIdent(c, key) var userPragma = strTableGet(c.userPragmas, ident) if userPragma != nil: - if {optStyleHint, optStyleError} * c.config.globalOptions != {}: - styleCheckUse(c.config, key.info, userPragma) + styleCheckUse(c, key.info, userPragma) # number of pragmas increase/decrease with user pragma expansion inc c.instCounter @@ -844,8 +843,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: let k = whichKeyword(ident) if k in validPragmas: - if {optStyleHint, optStyleError} * c.config.globalOptions != {}: - checkPragmaUse(c.config, key.info, k, ident.s) + checkPragmaUse(c.config, key.info, k, ident.s) case k of wExportc, wExportCpp: makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fed9cae21..1bb4f49ce 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2599,7 +2599,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode = labl.owner = c.p.owner n[0] = newSymNode(labl, n[0].info) suggestSym(c.graph, n[0].info, labl, c.graph.usageSym) - styleCheckDef(c.config, labl) + styleCheckDef(c, labl) onDef(n[0].info, labl) n[1] = semExpr(c, n[1], flags) n.typ = n[1].typ diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index e249d88e8..ca0b05fa2 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -179,7 +179,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = let s = newSymS(skUnknown, getIdentNode(c, n), c) addPrelimDecl(c, s) - styleCheckDef(c.config, n.info, s, kind) + styleCheckDef(c, n.info, s, kind) onDef(n.info, s) proc semGenericStmt(c: PContext, n: PNode, diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index ed1826fd4..d3e12670b 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -428,7 +428,7 @@ proc semQuantifier(c: PContext; n: PNode): PNode = let op = considerQuotedIdent(c, it[0]) if op.id == ord(wIn): let v = newSymS(skForVar, it[1], c) - styleCheckDef(c.config, v) + styleCheckDef(c, v) onDef(it[1].info, v) let domain = semExprWithType(c, it[2], {efWantIterator}) v.typ = domain.typ diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0516d08ce..03c30b6e6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -375,7 +375,7 @@ proc semUsing(c: PContext; n: PNode): PNode = let typ = semTypeNode(c, a[^2], nil) for j in 0.. 0: @@ -271,8 +271,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode = when defined(nimsuggest): suggestSym(c.graph, n.info, s, c.graph.usageSym, false) # field access (dot expr) will be handled by builtinFieldAccess - if not isField and {optStyleHint, optStyleError} * c.config.globalOptions != {}: - styleCheckUse(c.config, n.info, s) + if not isField: + styleCheckUse(c, n.info, s) proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = result = n @@ -297,7 +297,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = var s = newGenSym(k, ident, c) s.ast = n addPrelimDecl(c.c, s) - styleCheckDef(c.c.config, n.info, s) + styleCheckDef(c.c, n.info, s) onDef(n.info, s) n[namePos] = newSymNode(s, n[namePos].info) else: @@ -431,7 +431,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # labels are always 'gensym'ed: let s = newGenSym(skLabel, n[0], c) addPrelimDecl(c.c, s) - styleCheckDef(c.c.config, s) + styleCheckDef(c.c, s) onDef(n[0].info, s) n[0] = newSymNode(s, n[0].info) n[1] = semTemplBody(c, n[1]) @@ -624,7 +624,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = s.owner.name.s == "vm" and s.name.s == "stackTrace": incl(s.flags, sfCallsite) - styleCheckDef(c.config, s) + styleCheckDef(c, s) onDef(n[namePos].info, s) # check parameter list: #s.scope = c.currentScope diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index b4f385fe6..584da1305 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -139,7 +139,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e.flags.incl {sfUsed, sfExported} result.n.add symNode - styleCheckDef(c.config, e) + styleCheckDef(c, e) onDef(e.info, e) if sfGenSym notin e.flags: if not isPure: @@ -476,7 +476,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = else: result.n.add newSymNode(field) addSonSkipIntLit(result, typ, c.idgen) - styleCheckDef(c.config, a[j].info, field) + styleCheckDef(c, a[j].info, field) onDef(field.info, field) if result.n.len == 0: result.n = nil if isTupleRecursive(result): @@ -808,7 +808,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, localError(c.config, info, "attempt to redefine: '" & f.name.s & "'") if a.kind == nkEmpty: father.add newSymNode(f) else: a.add newSymNode(f) - styleCheckDef(c.config, f) + styleCheckDef(c, f) onDef(f.info, f) if a.kind != nkEmpty: father.add a of nkSym: @@ -1315,7 +1315,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result.n.add newSymNode(arg) rawAddSon(result, finalType) addParamOrResult(c, arg, kind) - styleCheckDef(c.config, a[j].info, arg) + styleCheckDef(c, a[j].info, arg) onDef(a[j].info, arg) if {optNimV1Emulation, optNimV12Emulation} * c.config.globalOptions == {}: a[j] = newSymNode(arg) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 38751fcc7..4b48ef5bb 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -598,8 +598,7 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) = if sfError in s.flags: userError(conf, info, s) when defined(nimsuggest): suggestSym(c.graph, info, s, c.graph.usageSym, false) - if {optStyleHint, optStyleError} * conf.globalOptions != {}: - styleCheckUse(conf, info, s) + styleCheckUse(c, info, s) markOwnerModuleAsUsed(c, s) proc safeSemExpr*(c: PContext, n: PNode): PNode = diff --git a/compiler/vm.nim b/compiler/vm.nim index e681bbc96..3cb699482 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -119,13 +119,13 @@ template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b) proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: bool): bool = # nim bug: `isAssign: static bool` doesn't work, giving odd compiler error - template fun(field, T, rkind) = + template fun(field, typ, rkind) = if isAssign: - cast[ptr T](address)[] = T(r.field) + cast[ptr typ](address)[] = typ(r.field) else: r.ensureKind(rkind) - let val = cast[ptr T](address)[] - when T is SomeInteger | char: + let val = cast[ptr typ](address)[] + when typ is SomeInteger | char: r.field = BiggestInt(val) else: r.field = val diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 04b753ef6..69599ece3 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -56,13 +56,13 @@ template ioop(op) {.dirty.} = template macrosop(op) {.dirty.} = registerCallback(c, "stdlib.macros." & astToStr(op), `op Wrapper`) -template wrap1f_math(op) {.dirty.} = +template wrap1fMath(op) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = doAssert a.numArgs == 1 setResult(a, op(getFloat(a, 0))) mathop op -template wrap2f_math(op) {.dirty.} = +template wrap2fMath(op) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getFloat(a, 0), getFloat(a, 1))) mathop op @@ -172,40 +172,40 @@ proc registerAdditionalOps*(c: PCtx) = proc getProjectPathWrapper(a: VmArgs) = setResult a, c.config.projectPath.string - wrap1f_math(sqrt) - wrap1f_math(cbrt) - wrap1f_math(ln) - wrap1f_math(log10) - wrap1f_math(log2) - wrap1f_math(exp) - wrap1f_math(arccos) - wrap1f_math(arcsin) - wrap1f_math(arctan) - wrap1f_math(arcsinh) - wrap1f_math(arccosh) - wrap1f_math(arctanh) - wrap2f_math(arctan2) - wrap1f_math(cos) - wrap1f_math(cosh) - wrap2f_math(hypot) - wrap1f_math(sinh) - wrap1f_math(sin) - wrap1f_math(tan) - wrap1f_math(tanh) - wrap2f_math(pow) - wrap1f_math(trunc) - wrap1f_math(floor) - wrap1f_math(ceil) - wrap1f_math(erf) - wrap1f_math(erfc) - wrap1f_math(gamma) - wrap1f_math(lgamma) + wrap1fMath(sqrt) + wrap1fMath(cbrt) + wrap1fMath(ln) + wrap1fMath(log10) + wrap1fMath(log2) + wrap1fMath(exp) + wrap1fMath(arccos) + wrap1fMath(arcsin) + wrap1fMath(arctan) + wrap1fMath(arcsinh) + wrap1fMath(arccosh) + wrap1fMath(arctanh) + wrap2fMath(arctan2) + wrap1fMath(cos) + wrap1fMath(cosh) + wrap2fMath(hypot) + wrap1fMath(sinh) + wrap1fMath(sin) + wrap1fMath(tan) + wrap1fMath(tanh) + wrap2fMath(pow) + wrap1fMath(trunc) + wrap1fMath(floor) + wrap1fMath(ceil) + wrap1fMath(erf) + wrap1fMath(erfc) + wrap1fMath(gamma) + wrap1fMath(lgamma) when declared(copySign): - wrap2f_math(copySign) + wrap2fMath(copySign) when declared(signbit): - wrap1f_math(signbit) + wrap1fMath(signbit) registerCallback c, "stdlib.math.round", proc (a: VmArgs) {.nimcall.} = let n = a.numArgs diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index c819f4306..cf2f768b1 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -89,23 +89,23 @@ type wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises", wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", - wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default", - wDelete = "delete", wDouble = "double", wDynamic_cast = "dynamic_cast", + wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default", + wDelete = "delete", wDouble = "double", wDynamicCast = "dynamic_cast", wExplicit = "explicit", wExtern = "extern", wFalse = "false", wFloat = "float", wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable", wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private", wProtected = "protected", wPublic = "public", wRegister = "register", - wReinterpret_cast = "reinterpret_cast", wRestrict = "restrict", wShort = "short", - wSigned = "signed", wSizeof = "sizeof", wStatic_cast = "static_cast", wStruct = "struct", + wReinterpretCast = "reinterpret_cast", wRestrict = "restrict", wShort = "short", + wSigned = "signed", wSizeof = "sizeof", wStaticCast = "static_cast", wStruct = "struct", wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef", wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename", wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual", - wVoid = "void", wVolatile = "volatile", wWchar_t = "wchar_t", + wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t", wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype", wNullptr = "nullptr", wNoexcept = "noexcept", - wThread_local = "thread_local", wStatic_assert = "static_assert", - wChar16_t = "char16_t", wChar32_t = "char32_t", + wThreadLocal = "thread_local", wStaticAssert = "static_assert", + wChar16 = "char16_t", wChar32 = "char32_t", wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr", From 286fcef68ef6f0e3a20ab5b25307c9b4705ce54d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Fri, 15 Jul 2022 15:42:54 +0800 Subject: [PATCH 3484/4254] [Orc] fixes "streams.readDataStr segafaults" when accepting a string literal (#20019) [backport] fixes streams.readDataStr accept a string literal --- lib/pure/streams.nim | 5 +++++ tests/stdlib/tstreams.nim | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index f58273ee8..50b3085d2 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1197,6 +1197,11 @@ else: # after 1.3 or JS not defined proc ssReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = var s = StringStream(s) + when nimvm: + discard + else: + when declared(prepareMutation): + prepareMutation(buffer) # buffer might potentially be a CoW literal with ARC result = min(slice.b + 1 - slice.a, s.data.len - s.pos) if result > 0: jsOrVmBlock: diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index d9857926e..cc1343651 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -85,3 +85,13 @@ block: static: # Ensure streams it doesnt break with nimscript on arc/orc #19716 let s = newStringStream("a") doAssert s.data == "a" + +template main = + var strm = newStringStream("abcde") + var buffer = "12345" + doAssert strm.readDataStr(buffer, 0..3) == 4 + doAssert buffer == "abcd5" + strm.close() + +static: main() +main() From f35c9cf73ddb3150ab6dbe449db4975866ee8a11 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Fri, 15 Jul 2022 13:37:08 +0300 Subject: [PATCH 3485/4254] fix #20002 (#20004) While this fix seems innocent, this unlocks the hidden behavior of method calls not being able to call gensym'ed routines inside templates. --- compiler/semtempl.nim | 2 +- tests/template/tinnerouterproc.nim | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/template/tinnerouterproc.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index a599edb9c..1f76aff75 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -78,7 +78,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule; result = newNodeIT(kind, info, newTypeS(tyNone, c)) a = initOverloadIter(o, c, n) while a != nil: - if a.kind != skModule and (not isField or sfGenSym notin s.flags): + if a.kind != skModule and (not isField or sfGenSym notin a.flags): incl(a.flags, sfUsed) markOwnerModuleAsUsed(c, a) result.add newSymNode(a, info) diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim new file mode 100644 index 000000000..1f15fb13e --- /dev/null +++ b/tests/template/tinnerouterproc.nim @@ -0,0 +1,8 @@ +block: # #20002 + proc bar(x: int): int = 10 + template foo = + proc bar(x: int): int {.gensym.} = x + 2 + doAssert bar(3) == 5 + discard 3.bar # evaluates to 10 but only check if it compiles for now + block: + foo() From 417b90a7e5b88bfc0ad1bfbbc81a3205c99e128e Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Fri, 15 Jul 2022 20:27:54 +0300 Subject: [PATCH 3486/4254] Improve Markdown code blocks & start moving docs to Markdown style (#19954) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add additional parameters parsing (other implementations will just ignore them). E.g. if in RST we have: .. code:: nim :test: "nim c $1" ... then in Markdown that will be: ```nim test="nim c $1" ... ``` - implement Markdown interpretation of additional indentation which is less than 4 spaces (>=4 spaces is a code block but it's not implemented yet). RST interpretes it as quoted block, for Markdown it's just normal paragraphs. - add separate `md2html` and `md2tex` commands. This is to separate Markdown behavior in cases when it diverges w.r.t. RST significantly — most conspicously like in the case of additional indentation above, and also currently the contradicting inline rule of Markdown is also turned on only in `md2html` and `md2tex`. **Rationale:** mixing Markdown and RST arbitrarily is a way to nowhere, we need to provide a way to fix the particular behavior. Note that still all commands have **both** Markdown and RST features **enabled**. In this PR `*.nim` files can be processed only in Markdown mode, while `md2html` is for `*.md` files and `rst2html` for `*.rst` files. - rename `*.rst` files to `.*md` as our current default behavior is already Markdown-ish - convert code blocks in `docgen.rst` to Markdown style as an example. Other code blocks will be converted in the follow-up PRs - fix indentation inside Markdown code blocks — additional indentation is preserved there - allow more than 3 backticks open/close blocks (tildas \~ are still not allowed to avoid conflict with RST adornment headings) see also https://github.com/nim-lang/RFCs/issues/355 - better error messages - (other) fix a bug that admonitions cannot be used in sandbox mode; fix annoying warning on line 2711 --- compiler/commands.nim | 5 +- compiler/docgen.nim | 33 ++-- compiler/lineinfos.nim | 2 + compiler/main.nim | 13 +- compiler/nim.nim | 2 +- compiler/options.nim | 2 + doc/{apis.rst => apis.md} | 0 doc/{backends.rst => backends.md} | 3 +- doc/{contributing.rst => contributing.md} | 2 +- doc/{destructors.rst => destructors.md} | 0 doc/{docgen.rst => docgen.md} | 63 ++++---- doc/{docs.rst => docs.md} | 0 doc/{docstyle.rst => docstyle.md} | 0 doc/{drnim.rst => drnim.md} | 0 doc/{estp.rst => estp.md} | 0 doc/{filters.rst => filters.md} | 0 doc/{hcr.rst => hcr.md} | 0 doc/{idetools.rst => idetools.md} | 0 doc/{intern.rst => intern.md} | 6 +- doc/{koch.rst => koch.md} | 0 doc/{lib.rst => lib.md} | 0 doc/{manual.rst => manual.md} | 8 +- .../{var_t_return.rst => var_t_return.md} | 0 ...xperimental.rst => manual_experimental.md} | 2 +- ...st => manual_experimental_strictnotnil.md} | 0 doc/{mm.rst => mm.md} | 2 +- doc/{nep1.rst => nep1.md} | 0 doc/{nimc.rst => nimc.md} | 6 +- doc/{nimfix.rst => nimfix.md} | 0 doc/{nimgrep.rst => nimgrep.md} | 2 +- doc/{niminst.rst => niminst.md} | 0 doc/{nims.rst => nims.md} | 0 doc/{nimsuggest.rst => nimsuggest.md} | 0 doc/{overview.rst => overview.md} | 2 +- doc/{packaging.rst => packaging.md} | 0 doc/{refc.rst => refc.md} | 0 doc/{testament.rst => testament.md} | 0 doc/{tools.rst => tools.md} | 0 doc/{tut1.rst => tut1.md} | 0 doc/{tut2.rst => tut2.md} | 2 +- doc/{tut3.rst => tut3.md} | 2 +- lib/packages/docutils/highlite.nim | 4 +- lib/packages/docutils/rst.nim | 151 ++++++++++++++---- tests/stdlib/thighlite.nim | 6 + tests/stdlib/trst.nim | 117 +++++++++++++- tests/stdlib/trstgen.nim | 16 +- tools/kochdocs.nim | 16 +- 47 files changed, 341 insertions(+), 126 deletions(-) rename doc/{apis.rst => apis.md} (100%) rename doc/{backends.rst => backends.md} (99%) rename doc/{contributing.rst => contributing.md} (99%) rename doc/{destructors.rst => destructors.md} (100%) rename doc/{docgen.rst => docgen.md} (98%) rename doc/{docs.rst => docs.md} (100%) rename doc/{docstyle.rst => docstyle.md} (100%) rename doc/{drnim.rst => drnim.md} (100%) rename doc/{estp.rst => estp.md} (100%) rename doc/{filters.rst => filters.md} (100%) rename doc/{hcr.rst => hcr.md} (100%) rename doc/{idetools.rst => idetools.md} (100%) rename doc/{intern.rst => intern.md} (99%) rename doc/{koch.rst => koch.md} (100%) rename doc/{lib.rst => lib.md} (100%) rename doc/{manual.rst => manual.md} (99%) rename doc/manual/{var_t_return.rst => var_t_return.md} (100%) rename doc/{manual_experimental.rst => manual_experimental.md} (99%) rename doc/{manual_experimental_strictnotnil.rst => manual_experimental_strictnotnil.md} (100%) rename doc/{mm.rst => mm.md} (98%) rename doc/{nep1.rst => nep1.md} (100%) rename doc/{nimc.rst => nimc.md} (99%) rename doc/{nimfix.rst => nimfix.md} (100%) rename doc/{nimgrep.rst => nimgrep.md} (99%) rename doc/{niminst.rst => niminst.md} (100%) rename doc/{nims.rst => nims.md} (100%) rename doc/{nimsuggest.rst => nimsuggest.md} (100%) rename doc/{overview.rst => overview.md} (86%) rename doc/{packaging.rst => packaging.md} (100%) rename doc/{refc.rst => refc.md} (100%) rename doc/{testament.rst => testament.md} (100%) rename doc/{tools.rst => tools.md} (100%) rename doc/{tut1.rst => tut1.md} (100%) rename doc/{tut2.rst => tut2.md} (99%) rename doc/{tut3.rst => tut3.md} (99%) diff --git a/compiler/commands.nim b/compiler/commands.nim index 31e637aba..b849f503d 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -449,6 +449,8 @@ proc parseCommand*(command: string): Command = of "doc2", "doc": cmdDoc of "doc2tex": cmdDoc2tex of "rst2html": cmdRst2html + of "md2tex": cmdMd2tex + of "md2html": cmdMd2html of "rst2tex": cmdRst2tex of "jsondoc0": cmdJsondoc0 of "jsondoc2", "jsondoc": cmdJsondoc @@ -480,7 +482,8 @@ proc setCommandEarly*(conf: ConfigRef, command: string) = # command early customizations # must be handled here to honor subsequent `--hint:x:on|off` case conf.cmd - of cmdRst2html, cmdRst2tex: # xxx see whether to add others: cmdGendepend, etc. + of cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex: + # xxx see whether to add others: cmdGendepend, etc. conf.foreignPackageNotes = {hintSuccessX} else: conf.foreignPackageNotes = foreignPackageNotesDefault diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 390f44f2e..ed5fe06ef 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -88,7 +88,7 @@ type jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering types: TStrTable sharedState: PRstSharedState - isPureRst: bool + standaloneDoc: bool conf*: ConfigRef cache*: IdentCache exampleCounter: int @@ -230,6 +230,7 @@ template declareClosures = case msgKind of meCannotOpenFile: k = errCannotOpenFile of meExpected: k = errXExpected + of meMissingClosing: k = errRstMissingClosing of meGridTableNotImplemented: k = errRstGridTableNotImplemented of meMarkdownIllformedTable: k = errRstMarkdownIllformedTable of meIllformedTable: k = errRstIllformedTable @@ -276,16 +277,18 @@ proc isLatexCmd(conf: ConfigRef): bool = conf.cmd in {cmdRst2tex, cmdDoc2tex} proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, outExt: string = HtmlExt, module: PSym = nil, - isPureRst = false): PDoc = + standaloneDoc = false, preferMarkdown = true): PDoc = declareClosures() new(result) result.module = module result.conf = conf result.cache = cache result.outDir = conf.outDir.string - result.isPureRst = isPureRst - var options= {roSupportRawDirective, roSupportMarkdown, roPreferMarkdown, roSandboxDisabled} - if not isPureRst: options.incl roNimFile + result.standaloneDoc = standaloneDoc + var options= {roSupportRawDirective, roSupportMarkdown, roSandboxDisabled} + if preferMarkdown: + options.incl roPreferMarkdown + if not standaloneDoc: options.incl roNimFile result.sharedState = newRstSharedState( options, filename.string, docgenFindFile, compilerMsgHandler) @@ -333,7 +336,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, # Make sure the destination directory exists createDir(outp.splitFile.dir) # Include the current file if we're parsing a nim file - let importStmt = if d.isPureRst: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")] + let importStmt = if d.standaloneDoc: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")] writeFile(outp, importStmt & content) proc interpSnippetCmd(cmd: string): string = @@ -1512,7 +1515,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = "\\\\\\vspace{0.5em}\\large $1", [esc(d.target, d.meta[metaSubtitle])]) var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection") - let bodyname = if d.hasToc and not d.isPureRst and not d.conf.isLatexCmd: + let bodyname = if d.hasToc and not d.standaloneDoc and not d.conf.isLatexCmd: groupsection.setLen 0 "doc.body_toc_group" elif d.hasToc: "doc.body_toc" @@ -1626,9 +1629,11 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) = generateIndex(d) proc commandRstAux(cache: IdentCache, conf: ConfigRef; - filename: AbsoluteFile, outExt: string) = + filename: AbsoluteFile, outExt: string, + preferMarkdown: bool) = var filen = addFileExt(filename, "txt") - var d = newDocumentor(filen, cache, conf, outExt, isPureRst = true) + var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true, + preferMarkdown = preferMarkdown) let rst = parseRst(readFile(filen.string), line=LineRstInit, column=ColRstInit, conf, d.sharedState) @@ -1637,11 +1642,13 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; writeOutput(d) generateIndex(d) -proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) = - commandRstAux(cache, conf, conf.projectFull, HtmlExt) +proc commandRst2Html*(cache: IdentCache, conf: ConfigRef, + preferMarkdown=false) = + commandRstAux(cache, conf, conf.projectFull, HtmlExt, preferMarkdown) -proc commandRst2TeX*(cache: IdentCache, conf: ConfigRef) = - commandRstAux(cache, conf, conf.projectFull, TexExt) +proc commandRst2TeX*(cache: IdentCache, conf: ConfigRef, + preferMarkdown=false) = + commandRstAux(cache, conf, conf.projectFull, TexExt, preferMarkdown) proc commandJson*(cache: IdentCache, conf: ConfigRef) = ## implementation of a deprecated jsondoc0 command diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 105de1636..071316f15 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -32,6 +32,7 @@ type # non-fatal errors errIllFormedAstX, errCannotOpenFile, errXExpected, + errRstMissingClosing, errRstGridTableNotImplemented, errRstMarkdownIllformedTable, errRstIllformedTable, @@ -105,6 +106,7 @@ const errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open '$1'", errXExpected: "'$1' expected", + errRstMissingClosing: "$1", errRstGridTableNotImplemented: "grid table is not implemented", errRstMarkdownIllformedTable: "illformed delimiter row of a markdown table", errRstIllformedTable: "Illformed table: $1", diff --git a/compiler/main.nim b/compiler/main.nim index a4425e510..0354bec9c 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -276,7 +276,8 @@ proc mainCommand*(graph: ModuleGraph) = var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) else: conf.projectPath doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee - if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex}: ret = ret / htmldocsDir + if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex}: + ret = ret / htmldocsDir conf.outDir = ret ## process all commands @@ -302,7 +303,7 @@ proc mainCommand*(graph: ModuleGraph) = commandDoc2(graph, HtmlExt) if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions: commandBuildIndex(conf, $conf.outDir) - of cmdRst2html: + of cmdRst2html, cmdMd2html: # XXX: why are warnings disabled by default for rst2html and rst2tex? for warn in rstWarnings: conf.setNoteDefaults(warn, true) @@ -311,16 +312,16 @@ proc mainCommand*(graph: ModuleGraph) = conf.quitOrRaise "compiler wasn't built with documentation generator" else: loadConfigs(DocConfig, cache, conf, graph.idgen) - commandRst2Html(cache, conf) - of cmdRst2tex, cmdDoc2tex: + commandRst2Html(cache, conf, preferMarkdown = (conf.cmd == cmdMd2html)) + of cmdRst2tex, cmdMd2tex, cmdDoc2tex: for warn in rstWarnings: conf.setNoteDefaults(warn, true) when defined(leanCompiler): conf.quitOrRaise "compiler wasn't built with documentation generator" else: - if conf.cmd == cmdRst2tex: + if conf.cmd in {cmdRst2tex, cmdMd2tex}: loadConfigs(DocTexConfig, cache, conf, graph.idgen) - commandRst2TeX(cache, conf) + commandRst2TeX(cache, conf, preferMarkdown = (conf.cmd == cmdMd2tex)) else: docLikeCmd commandDoc2(graph, TexExt) of cmdJsondoc0: docLikeCmd commandJson(cache, conf) diff --git a/compiler/nim.nim b/compiler/nim.nim index bfb07ba20..48472507d 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -122,7 +122,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = # `The parameter is incorrect` let cmd = cmdPrefix & output.quoteShell & ' ' & conf.arguments execExternalProgram(conf, cmd.strip(leading=false,trailing=true)) - of cmdDocLike, cmdRst2html, cmdRst2tex: # bugfix(cmdRst2tex was missing) + of cmdDocLike, cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex: # bugfix(cmdRst2tex was missing) if conf.arguments.len > 0: # reserved for future use rawMessage(conf, errGenerated, "'$1 cannot handle arguments" % [$conf.cmd]) diff --git a/compiler/options.nim b/compiler/options.nim index 1ba157587..d567927cb 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -153,6 +153,8 @@ type cmdDoc2tex # convert .nim doc comments to LaTeX cmdRst2html # convert a reStructuredText file to HTML cmdRst2tex # convert a reStructuredText file to TeX + cmdMd2html # convert a Markdown file to HTML + cmdMd2tex # convert a Markdown file to TeX cmdJsondoc0 cmdJsondoc cmdCtags diff --git a/doc/apis.rst b/doc/apis.md similarity index 100% rename from doc/apis.rst rename to doc/apis.md diff --git a/doc/backends.rst b/doc/backends.md similarity index 99% rename from doc/backends.rst rename to doc/backends.md index 65dd8a6f2..a135e78b0 100644 --- a/doc/backends.rst +++ b/doc/backends.md @@ -10,7 +10,8 @@ .. no syntax highlighting here by default: .. contents:: - "Heresy grows from idleness." -- Unknown. + +> "Heresy grows from idleness." -- Unknown. Introduction diff --git a/doc/contributing.rst b/doc/contributing.md similarity index 99% rename from doc/contributing.rst rename to doc/contributing.md index 0ca0d0cbc..51d1d5065 100644 --- a/doc/contributing.rst +++ b/doc/contributing.md @@ -581,7 +581,7 @@ Code reviews -.. include:: docstyle.rst +.. include:: docstyle.md Evolving the stdlib diff --git a/doc/destructors.rst b/doc/destructors.md similarity index 100% rename from doc/destructors.rst rename to doc/destructors.md diff --git a/doc/docgen.rst b/doc/docgen.md similarity index 98% rename from doc/docgen.rst rename to doc/docgen.md index 48166b2c5..5f5c4ecc0 100644 --- a/doc/docgen.rst +++ b/doc/docgen.md @@ -35,14 +35,13 @@ Quick start Generate HTML documentation for a file: -.. code:: cmd - + ```cmd nim doc .nim + ``` Generate HTML documentation for a whole project: -.. code:: cmd - + ```cmd # delete any htmldocs/*.idx file before starting nim doc --project --index:on --git.url: --git.commit: --outdir:htmldocs .nim # this will generate html files, a theindex.html index, css and js under `htmldocs` @@ -54,7 +53,7 @@ Generate HTML documentation for a whole project: # or `$nimcache/htmldocs` with `--usenimcache` which avoids clobbering your sources; # and likewise without `--project`. # Adding `-r` will open in a browser directly. - + ``` Documentation Comments ---------------------- @@ -120,8 +119,8 @@ Example of Nim file input The following examples will generate documentation for this sample *Nim* module, aptly named ``doc/docgen_sample.nim``: -.. code:: nim - :file: docgen_sample.nim + ```nim file=docgen_sample.nim + ``` All the below commands save their output to ``htmldocs`` directory relative to the directory of file; @@ -137,9 +136,9 @@ optionally, an index file. The `doc`:option: command: -.. code:: cmd - + ```cmd nim doc docgen_sample.nim + ``` Partial Output:: ... @@ -159,8 +158,7 @@ HTML -> PDF conversion). The `doc2tex`:option: command: -.. code:: cmd - + ```cmd nim doc2tex docgen_sample.nim cd htmldocs xelatex docgen_sample.tex @@ -169,6 +167,7 @@ The `doc2tex`:option: command: # large documents) to get all labels generated. # That depends on this warning in the end of `xelatex` output: # LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. + ``` The output is ``docgen_sample.pdf``. @@ -183,9 +182,9 @@ Note that this tool is built off of the `doc`:option: command The `jsondoc`:option: command: -.. code:: cmd - + ```cmd nim jsondoc docgen_sample.nim + ``` Output:: { @@ -209,9 +208,9 @@ renamed to `jsondoc0`:option:. The `jsondoc0`:option: command: -.. code:: cmd - + ```cmd nim jsondoc0 docgen_sample.nim + ``` Output:: [ @@ -249,9 +248,9 @@ the anchor [*]_ of Nim symbol that corresponds to link text. If you have a constant: -.. code:: Nim - + ```Nim const pi* = 3.14 + ``` then it should be referenced in one of the 2 forms: @@ -262,9 +261,9 @@ B. qualified (with symbol kind specification):: For routine kinds there are more options. Consider this definition: -.. code:: Nim - + ```Nim proc foo*(a: int, b: float): string + ``` Generally following syntax is allowed for referencing `foo`: @@ -352,11 +351,11 @@ recognized fine:: (without parameter names, see form A.2 above). E.g. for this signature: - .. code:: Nim - + ```Nim proc binarySearch*[T, K](a: openArray[T]; key: K; cmp: proc (x: T; y: K): int {.closure.}): int ~~ ~~ ~~~~~ + ``` you cannot use names underlined by `~~` so it must be referenced with ``cmp: proc(T, K)``. Hence these forms are valid:: @@ -379,10 +378,10 @@ recognized fine:: .. Note:: A bit special case is operators (as their signature is also defined with `\``): - .. code:: Nim - + ```Nim func `$`(x: MyType): string func `[]`*[T](x: openArray[T]): T + ``` A short form works without additional backticks:: @@ -412,9 +411,9 @@ Related Options Project switch -------------- -.. code:: cmd - + ```cmd nim doc --project filename.nim + ``` This will recursively generate documentation of all Nim modules imported into the input module that belong to the Nimble package that ``filename.nim`` @@ -425,9 +424,9 @@ also be generated. Index switch ------------ -.. code:: cmd - + ```cmd nim doc --index:on filename.nim + ``` This will generate an index of all the exported symbols in the input Nim module, and put it into a neighboring file with the extension of ``.idx``. The @@ -443,9 +442,9 @@ file. See source switch ----------------- -.. code:: cmd - + ```cmd nim doc --git.url: filename.nim + ``` With the `git.url`:option: switch the *See source* hyperlink will appear below each documented item in your source code pointing to the implementation of that @@ -490,9 +489,9 @@ supports highlighting of a few other languages supported by the Usage: -.. code:: cmd - + ```cmd nim rst2html docgen.rst + ``` Output:: You're reading it! @@ -528,7 +527,7 @@ HTML file, most browsers will go to the first one. To differentiate the rest, you will need to use the complex name. A complex name for a callable type is made up of several parts: - (**plain symbol**)(**.type**),(**first param**)?(**,param type**)\* + (**plain symbol**)(**.type**),(**first param**)?(**,param type**)\* The first thing to note is that all callable types have at least a comma, even if they don't have any parameters. If there are parameters, they are diff --git a/doc/docs.rst b/doc/docs.md similarity index 100% rename from doc/docs.rst rename to doc/docs.md diff --git a/doc/docstyle.rst b/doc/docstyle.md similarity index 100% rename from doc/docstyle.rst rename to doc/docstyle.md diff --git a/doc/drnim.rst b/doc/drnim.md similarity index 100% rename from doc/drnim.rst rename to doc/drnim.md diff --git a/doc/estp.rst b/doc/estp.md similarity index 100% rename from doc/estp.rst rename to doc/estp.md diff --git a/doc/filters.rst b/doc/filters.md similarity index 100% rename from doc/filters.rst rename to doc/filters.md diff --git a/doc/hcr.rst b/doc/hcr.md similarity index 100% rename from doc/hcr.rst rename to doc/hcr.md diff --git a/doc/idetools.rst b/doc/idetools.md similarity index 100% rename from doc/idetools.rst rename to doc/idetools.md diff --git a/doc/intern.rst b/doc/intern.md similarity index 99% rename from doc/intern.rst rename to doc/intern.md index 9103c694c..0fd995582 100644 --- a/doc/intern.rst +++ b/doc/intern.md @@ -10,7 +10,7 @@ .. include:: rstcommon.rst .. contents:: - "Abstraction is layering ignorance on top of reality." -- Richard Gabriel +> "Abstraction is layering ignorance on top of reality." -- Richard Gabriel Directory structure @@ -276,8 +276,8 @@ and `exitingDebugSection()`:nim:. #. Compile the temp compiler with `--debugger:native -d:nimDebugUtils`:option: #. Set your desired breakpoints or watchpoints. #. Configure your debugger: - * GDB: execute `source tools/compiler.gdb` at startup - * LLDB execute `command source tools/compiler.lldb` at startup + * GDB: execute `source tools/compiler.gdb` at startup + * LLDB execute `command source tools/compiler.lldb` at startup #. Use one of the scoping helpers like so: .. code-block:: nim diff --git a/doc/koch.rst b/doc/koch.md similarity index 100% rename from doc/koch.rst rename to doc/koch.md diff --git a/doc/lib.rst b/doc/lib.md similarity index 100% rename from doc/lib.rst rename to doc/lib.md diff --git a/doc/manual.rst b/doc/manual.md similarity index 99% rename from doc/manual.rst rename to doc/manual.md index 571379a87..503b9538b 100644 --- a/doc/manual.rst +++ b/doc/manual.md @@ -10,9 +10,9 @@ Nim Manual .. contents:: - "Complexity" seems to be a lot like "energy": you can transfer it from the - end-user to one/some of the other players, but the total amount seems to remain - pretty much constant for a given task. -- Ran +> "Complexity" seems to be a lot like "energy": you can transfer it from the +> end-user to one/some of the other players, but the total amount seems to remain +> pretty much constant for a given task. -- Ran About this document @@ -4025,7 +4025,7 @@ In the standard library every name of a routine that returns a `var` type starts with the prefix `m` per convention. -.. include:: manual/var_t_return.rst +.. include:: manual/var_t_return.md Future directions ~~~~~~~~~~~~~~~~~ diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.md similarity index 100% rename from doc/manual/var_t_return.rst rename to doc/manual/var_t_return.md diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.md similarity index 99% rename from doc/manual_experimental.rst rename to doc/manual_experimental.md index 3089755cb..3968163c5 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.md @@ -505,7 +505,7 @@ The compiler ensures that every code path initializes variables which contain non-nilable pointers. The details of this analysis are still to be specified here. -.. include:: manual_experimental_strictnotnil.rst +.. include:: manual_experimental_strictnotnil.md Aliasing restrictions in parameter passing diff --git a/doc/manual_experimental_strictnotnil.rst b/doc/manual_experimental_strictnotnil.md similarity index 100% rename from doc/manual_experimental_strictnotnil.rst rename to doc/manual_experimental_strictnotnil.md diff --git a/doc/mm.rst b/doc/mm.md similarity index 98% rename from doc/mm.rst rename to doc/mm.md index b6941a901..09b235228 100644 --- a/doc/mm.rst +++ b/doc/mm.md @@ -11,7 +11,7 @@ Nim's Memory Management .. - "The road to hell is paved with good intentions." +> "The road to hell is paved with good intentions." Multi-paradigm Memory Management Strategies diff --git a/doc/nep1.rst b/doc/nep1.md similarity index 100% rename from doc/nep1.rst rename to doc/nep1.md diff --git a/doc/nimc.rst b/doc/nimc.md similarity index 99% rename from doc/nimc.rst rename to doc/nimc.md index aa6650491..28a917d92 100644 --- a/doc/nimc.rst +++ b/doc/nimc.md @@ -11,9 +11,9 @@ .. - "Look at you, hacker. A pathetic creature of meat and bone, panting and - sweating as you run through my corridors. How can you challenge a perfect, - immortal machine?" +> "Look at you, hacker. A pathetic creature of meat and bone, panting and +> sweating as you run through my corridors. How can you challenge a perfect, +> immortal machine?" Introduction diff --git a/doc/nimfix.rst b/doc/nimfix.md similarity index 100% rename from doc/nimfix.rst rename to doc/nimfix.md diff --git a/doc/nimgrep.rst b/doc/nimgrep.md similarity index 99% rename from doc/nimgrep.rst rename to doc/nimgrep.md index 6088a4c45..ff2bf3a8d 100644 --- a/doc/nimgrep.rst +++ b/doc/nimgrep.md @@ -54,7 +54,7 @@ All examples below use default PCRE Regex patterns: nimgrep --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$' # short: --ed:'^\.git$' --ed:'^\.hg$' --ed:'^\.svn$' -+ To search only in paths containing the `tests` sub-directory recursively:: ++ To search only in paths containing the `tests` sub-directory recursively: .. code:: cmd nimgrep --recursive --includeDir:'(^|/)tests($|/)' diff --git a/doc/niminst.rst b/doc/niminst.md similarity index 100% rename from doc/niminst.rst rename to doc/niminst.md diff --git a/doc/nims.rst b/doc/nims.md similarity index 100% rename from doc/nims.rst rename to doc/nims.md diff --git a/doc/nimsuggest.rst b/doc/nimsuggest.md similarity index 100% rename from doc/nimsuggest.rst rename to doc/nimsuggest.md diff --git a/doc/overview.rst b/doc/overview.md similarity index 86% rename from doc/overview.rst rename to doc/overview.md index e01520d7c..b21eb1e68 100644 --- a/doc/overview.rst +++ b/doc/overview.md @@ -5,5 +5,5 @@ Nim Documentation Overview :Author: Andreas Rumpf :Version: |nimversion| -.. include:: docs.rst +.. include:: docs.md diff --git a/doc/packaging.rst b/doc/packaging.md similarity index 100% rename from doc/packaging.rst rename to doc/packaging.md diff --git a/doc/refc.rst b/doc/refc.md similarity index 100% rename from doc/refc.rst rename to doc/refc.md diff --git a/doc/testament.rst b/doc/testament.md similarity index 100% rename from doc/testament.rst rename to doc/testament.md diff --git a/doc/tools.rst b/doc/tools.md similarity index 100% rename from doc/tools.rst rename to doc/tools.md diff --git a/doc/tut1.rst b/doc/tut1.md similarity index 100% rename from doc/tut1.rst rename to doc/tut1.md diff --git a/doc/tut2.rst b/doc/tut2.md similarity index 99% rename from doc/tut2.rst rename to doc/tut2.md index 725f68dd5..d37d6a16a 100644 --- a/doc/tut2.rst +++ b/doc/tut2.md @@ -13,7 +13,7 @@ Nim Tutorial (Part II) Introduction ============ - "Repetition renders the ridiculous reasonable." -- Norman Wildberger +> "Repetition renders the ridiculous reasonable." -- Norman Wildberger This document is a tutorial for the advanced constructs of the *Nim* programming language. **Note that this document is somewhat obsolete as the** diff --git a/doc/tut3.rst b/doc/tut3.md similarity index 99% rename from doc/tut3.rst rename to doc/tut3.md index c2c956107..2fcfd4220 100644 --- a/doc/tut3.rst +++ b/doc/tut3.md @@ -13,7 +13,7 @@ Nim Tutorial (Part III) Introduction ============ - "With Great Power Comes Great Responsibility." -- Spider Man's Uncle +> "With Great Power Comes Great Responsibility." -- Spider Man's Uncle This document is a tutorial about Nim's macro system. A macro is a function that is executed at compile-time and transforms diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index d36b2c877..3af94ab21 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -125,9 +125,7 @@ proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: cstring) = g.length = 0 g.state = low(TokenClass) g.lang = low(SourceLanguage) - var pos = 0 # skip initial whitespace: - while g.buf[pos] in {' ', '\t'..'\r'}: inc(pos) - g.pos = pos + g.pos = 0 proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: string) = initGeneralTokenizer(g, cstring(buf)) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index cd5f26278..1721674c8 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -8,20 +8,23 @@ # ## ================================== -## rst +## packages/docutils/rst ## ================================== ## ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Nim-flavored reStructuredText and Markdown ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## -## This module implements a `reStructuredText`:idx: (RST) parser. +## This module implements a `reStructuredText`:idx: (RST) and +## `Markdown`:idx: parser. ## A large subset is implemented with some limitations_ and ## `Nim-specific features`_. -## A few `extra features`_ of the `Markdown`:idx: syntax are -## also supported. +## Both Markdown and RST are mark-up languages whose goal is to +## typeset texts with complex structure, formatting and references +## using simple plaintext representation. ## -## Nim can output the result to HTML [#html]_ or Latex [#latex]_. +## This module is also embedded into Nim compiler; the compiler can output +## the result to HTML [#html]_ or Latex [#latex]_. ## ## .. [#html] commands `nim doc`:cmd: for ``*.nim`` files and ## `nim rst2html`:cmd: for ``*.rst`` files @@ -29,11 +32,13 @@ ## .. [#latex] commands `nim doc2tex`:cmd: for ``*.nim`` and ## `nim rst2tex`:cmd: for ``*.rst``. ## -## If you are new to RST please consider reading the following: +## If you are new to Markdown/RST please consider reading the following: ## -## 1) a short `quick introduction`_ -## 2) an `RST reference`_: a comprehensive cheatsheet for RST -## 3) a more formal 50-page `RST specification`_. +## 1) `Markdown Basic Syntax`_ +## 2) a long specification of Markdown: `CommonMark Spec`_ +## 3) a short `quick introduction`_ to RST +## 4) an `RST reference`_: a comprehensive cheatsheet for RST +## 5) a more formal 50-page `RST specification`_. ## ## Features ## -------- @@ -120,7 +125,13 @@ ## ## * emoji / smiley symbols ## * Markdown tables -## * Markdown code blocks +## * Markdown code blocks. For them the same additional arguments as for RST +## code blocks can be provided (e.g. `test` or `number-lines`) but with +## a one-line syntax like this:: +## +## ```nim test number-lines=10 +## echo "ok" +## ``` ## * Markdown links ## * Markdown headlines ## * Markdown block quotes @@ -211,6 +222,8 @@ ## See `packages/docutils/rstgen module `_ to know how to ## generate HTML or Latex strings to embed them into your documents. ## +## .. _Markdown Basic Syntax: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax +## .. _CommonMark Spec: https://spec.commonmark.org/0.30 ## .. _quick introduction: https://docutils.sourceforge.io/docs/user/rst/quickstart.html ## .. _RST reference: https://docutils.sourceforge.io/docs/user/rst/quickref.html ## .. _RST specification: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html @@ -253,6 +266,7 @@ type MsgKind* = enum ## the possible messages meCannotOpenFile = "cannot open '$1'", meExpected = "'$1' expected", + meMissingClosing = "$1", meGridTableNotImplemented = "grid table is not implemented", meMarkdownIllformedTable = "illformed delimiter row of a Markdown table", meIllformedTable = "Illformed table: $1", @@ -323,7 +337,10 @@ const ":geek:": "icon_e_geek", ":ugeek:": "icon_e_ugeek" } - SandboxDirAllowlist = ["image", "code", "code-block"] + SandboxDirAllowlist = [ + "image", "code", "code-block", "admonition", "attention", "caution", + "container", "contents", "danger", "default-role", "error", "figure", + "hint", "important", "index", "note", "role", "tip", "title", "warning"] type TokType = enum @@ -1616,35 +1633,89 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, inc p.idx else: rstMessage(p, meExpected, postfix, line, col) +proc parseMarkdownCodeblockFields(p: var RstParser): PRstNode = + ## Parses additional (after language string) code block parameters + ## in a format *suggested* in the `CommonMark Spec`_ with handling of `"`. + if currentTok(p).kind == tkIndent: + result = nil + else: + result = newRstNode(rnFieldList) + while currentTok(p).kind != tkIndent: + if currentTok(p).kind == tkWhite: + inc p.idx + else: + let field = newRstNode(rnField) + var fieldName = "" + while currentTok(p).kind notin {tkWhite, tkIndent, tkEof} and + currentTok(p).symbol != "=": + fieldName.add currentTok(p).symbol + inc p.idx + field.add(newRstNode(rnFieldName, @[newLeaf(fieldName)])) + if currentTok(p).kind == tkWhite: inc p.idx + let fieldBody = newRstNode(rnFieldBody) + if currentTok(p).symbol == "=": + inc p.idx + if currentTok(p).kind == tkWhite: inc p.idx + var fieldValue = "" + if currentTok(p).symbol == "\"": + while true: + fieldValue.add currentTok(p).symbol + inc p.idx + if currentTok(p).kind == tkEof: + rstMessage(p, meExpected, "\"") + elif currentTok(p).symbol == "\"": + fieldValue.add "\"" + inc p.idx + break + else: + while currentTok(p).kind notin {tkWhite, tkIndent, tkEof}: + fieldValue.add currentTok(p).symbol + inc p.idx + fieldBody.add newLeaf(fieldValue) + field.add(fieldBody) + result.add(field) + proc parseMarkdownCodeblock(p: var RstParser): PRstNode = result = newRstNodeA(p, rnCodeBlock) + let line = curLine(p) + let baseCol = currentTok(p).col + let baseSym = currentTok(p).symbol # usually just ``` + inc p.idx result.info = lineInfo(p) var args = newRstNode(rnDirArg) + var fields: PRstNode = nil if currentTok(p).kind == tkWord: args.add(newLeaf(p)) inc p.idx + fields = parseMarkdownCodeblockFields(p) else: args = nil var n = newLeaf("") while true: - case currentTok(p).kind - of tkEof: - rstMessage(p, meExpected, "```") + if currentTok(p).kind == tkEof: + rstMessage(p, meMissingClosing, + "$1 (started at line $2)" % [baseSym, $line]) break - of tkPunct, tkAdornment: - if currentTok(p).symbol == "```": - inc p.idx - break - else: - n.text.add(currentTok(p).symbol) - inc p.idx + elif nextTok(p).kind in {tkPunct, tkAdornment} and + nextTok(p).symbol[0] == baseSym[0] and + nextTok(p).symbol.len >= baseSym.len: + inc p.idx, 2 + break + elif currentTok(p).kind == tkIndent: + n.text.add "\n" + if currentTok(p).ival > baseCol: + n.text.add " ".repeat(currentTok(p).ival - baseCol) + elif currentTok(p).ival < baseCol: + rstMessage(p, mwRstStyle, + "unexpected de-indentation in Markdown code block") + inc p.idx else: n.text.add(currentTok(p).symbol) inc p.idx var lb = newRstNode(rnLiteralBlock) lb.add(n) result.add(args) - result.add(PRstNode(nil)) + result.add(fields) result.add(lb) proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = @@ -1730,6 +1801,12 @@ proc parseFootnoteName(p: var RstParser, reference: bool): PRstNode = inc i p.idx = i +proc isMarkdownCodeBlock(p: RstParser): bool = + result = (roSupportMarkdown in p.s.options and + currentTok(p).kind in {tkPunct, tkAdornment} and + currentTok(p).symbol[0] == '`' and # tilde ~ is not supported + currentTok(p).symbol.len >= 3) + proc parseInline(p: var RstParser, father: PRstNode) = var n: PRstNode # to be used in `if` condition let saveIdx = p.idx @@ -1755,8 +1832,7 @@ proc parseInline(p: var RstParser, father: PRstNode) = addAnchorRst(p, name = linkName(n), refn = refn, reset = true, anchorType=manualInlineAnchor) father.add(n) - elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": - inc p.idx + elif isMarkdownCodeBlock(p): father.add(parseMarkdownCodeblock(p)) elif isInlineMarkupStart(p, "``"): var n = newRstNode(rnInlineLiteral) @@ -1816,8 +1892,7 @@ proc parseInline(p: var RstParser, father: PRstNode) = return parseWordOrRef(p, father) of tkAdornment, tkOther, tkWhite: - if roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": - inc p.idx + if isMarkdownCodeBlock(p): father.add(parseMarkdownCodeblock(p)) return if roSupportSmilies in p.s.options: @@ -2194,7 +2269,7 @@ proc findPipe(p: RstParser, start: int): bool = proc whichSection(p: RstParser): RstNodeKind = if currentTok(p).kind in {tkAdornment, tkPunct}: # for punctuation sequences that can be both tkAdornment and tkPunct - if roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": + if isMarkdownCodeBlock(p): return rnCodeBlock elif currentTok(p).symbol == "::": return rnLiteralBlock @@ -2633,7 +2708,9 @@ proc parseSimpleTable(p: var RstParser): PRstNode = # fix rnTableDataCell -> rnTableHeaderCell for previous table rows: for nRow in 0 ..< result.sons.len: for nCell in 0 ..< result.sons[nRow].len: - result.sons[nRow].sons[nCell].kind = rnTableHeaderCell + template cell: PRstNode = result.sons[nRow].sons[nCell] + cell = PRstNode(kind: rnTableHeaderCell, sons: cell.sons, + span: cell.span, anchor: cell.anchor) if currentTok(p).kind == tkEof: break let tabRow = parseSimpleTableRow(p, cols, colChar) result.add tabRow @@ -2892,11 +2969,19 @@ proc parseSection(p: var RstParser, result: PRstNode) = if currInd(p) == currentTok(p).ival: inc p.idx elif currentTok(p).ival > currInd(p): - pushInd(p, currentTok(p).ival) - var a = newRstNodeA(p, rnBlockQuote) - parseSection(p, a) - result.add(a) - popInd(p) + if roPreferMarkdown in p.s.options: # Markdown => normal paragraphs + if currentTok(p).ival - currInd(p) >= 4: + rstMessage(p, mwRstStyle, + "Markdown indented code not implemented") + pushInd(p, currentTok(p).ival) + parseSection(p, result) + popInd(p) + else: # RST mode => block quotes + pushInd(p, currentTok(p).ival) + var a = newRstNodeA(p, rnBlockQuote) + parseSection(p, a) + result.add(a) + popInd(p) else: while currentTok(p).kind != tkEof and nextTok(p).kind == tkIndent: inc p.idx # skip blank lines diff --git a/tests/stdlib/thighlite.nim b/tests/stdlib/thighlite.nim index 4113a6a80..5134215c1 100644 --- a/tests/stdlib/thighlite.nim +++ b/tests/stdlib/thighlite.nim @@ -12,6 +12,12 @@ block: # Nim tokenizing @[("\"\"\"ok1\\nok2\\nok3\"\"\"", gtLongStringLit) ]) + test "whitespace at beginning of line is preserved": + check(" discard 1".tokenize(langNim) == + @[(" ", gtWhitespace), ("discard", gtKeyword), (" ", gtWhitespace), + ("1", gtDecNumber) + ]) + block: # Cmd (shell) tokenizing test "cmd with dollar and output": check( diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 24bc03027..823697336 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -24,8 +24,11 @@ import unittest, strutils import std/private/miscdollars import os +const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled} +const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled} + proc toAst(input: string, - rstOptions: RstParseOptions = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}, + rstOptions: RstParseOptions = preferMarkdown, error: ref string = nil, warnings: ref seq[string] = nil): string = ## If `error` is nil then no errors should be generated. @@ -451,7 +454,7 @@ suite "RST parsing": > - y > > Paragraph. - """.toAst == dedent""" + """.toAst(rstOptions = preferRst) == dedent""" rnMarkdownBlockQuote rnMarkdownBlockQuoteItem quotationDepth=1 rnInner @@ -468,6 +471,93 @@ suite "RST parsing": rnLeaf '.' """) + test "Markdown code blocks with more > 3 backticks": + check(dedent""" + ```` + let a = 1 + ``` + ````""".toAst == + dedent""" + rnCodeBlock + [nil] + [nil] + rnLiteralBlock + rnLeaf ' + let a = 1 + ```' + """) + + test "Markdown code blocks with Nim-specific arguments": + check(dedent""" + ```nim number-lines=1 test + let a = 1 + ```""".toAst == + dedent""" + rnCodeBlock + rnDirArg + rnLeaf 'nim' + rnFieldList + rnField + rnFieldName + rnLeaf 'number-lines' + rnFieldBody + rnLeaf '1' + rnField + rnFieldName + rnLeaf 'test' + rnFieldBody + rnLiteralBlock + rnLeaf ' + let a = 1' + """) + + check(dedent""" + ```nim test = "nim c $1" number-lines = 1 + let a = 1 + ```""".toAst == + dedent""" + rnCodeBlock + rnDirArg + rnLeaf 'nim' + rnFieldList + rnField + rnFieldName + rnLeaf 'test' + rnFieldBody + rnLeaf '"nim c $1"' + rnField + rnFieldName + rnLeaf 'number-lines' + rnFieldBody + rnLeaf '1' + rnLiteralBlock + rnLeaf ' + let a = 1' + """) + + test "additional indentation < 4 spaces is handled fine": + check(dedent""" + Indentation + + ```nim + let a = 1 + ```""".toAst == + dedent""" + rnInner + rnParagraph + rnLeaf 'Indentation' + rnParagraph + rnCodeBlock + rnDirArg + rnLeaf 'nim' + [nil] + rnLiteralBlock + rnLeaf ' + let a = 1' + """) + # | | + # | \ indentation of exactly two spaces before 'let a = 1' + test "option list has priority over definition list": check(dedent""" --defusages @@ -562,7 +652,7 @@ suite "RST parsing": notAcomment1 notAcomment2 - someParagraph""".toAst == + someParagraph""".toAst(rstOptions = preferRst) == dedent""" rnInner rnBlockQuote @@ -574,6 +664,25 @@ suite "RST parsing": rnLeaf 'someParagraph' """) + test "check that additional line right after .. ends comment (Markdown mode)": + # in Markdown small indentation does not matter so this should + # just be split to 2 paragraphs. + check(dedent""" + .. + + notAcomment1 + notAcomment2 + someParagraph""".toAst == + dedent""" + rnInner + rnInner + rnLeaf 'notAcomment1' + rnLeaf ' ' + rnLeaf 'notAcomment2' + rnParagraph + rnLeaf 'someParagraph' + """) + test "but blank lines after 2nd non-empty line don't end the comment": check(dedent""" .. @@ -592,7 +701,7 @@ suite "RST parsing": .. - someBlockQuote""".toAst == + someBlockQuote""".toAst(rstOptions = preferRst) == dedent""" rnInner rnAdmonition adType=note diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index d91b5615e..7fae4ba8b 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -9,8 +9,13 @@ import ../../lib/packages/docutils/rst import unittest, strutils, strtabs import std/private/miscdollars +const + NoSandboxOpts = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled} + preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile} + preferRst = {roSupportMarkdown, roNimFile} + proc toHtml(input: string, - rstOptions: RstParseOptions = {roPreferMarkdown, roSupportMarkdown, roNimFile}, + rstOptions: RstParseOptions = preferMarkdown, error: ref string = nil, warnings: ref seq[string] = nil): string = ## If `error` is nil then no errors should be generated. @@ -47,9 +52,6 @@ proc optionListLabel(opt: string): string = opt & "
        " -const - NoSandboxOpts = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled} - suite "YAML syntax highlighting": test "Basics": @@ -1180,7 +1182,7 @@ Test1 "input(8, 4) Warning: language 'anotherLang' not supported" ]) check(output == "
        anything
        " & - "

        \nsomeCode\n

        ") + "

        \nsomeCode

        ") test "RST admonitions": # check that all admonitions are implemented @@ -1321,7 +1323,7 @@ Test1 That was a transition. """ let output1 = input1.toHtml( - NoSandboxOpts + preferRst ) doAssert "

        text""" & "\n

    Authors:Andreas Rumpf, Zahary Karadjov
    Version:|nimversion|
    ") test "Field list: body after newline": - let output = dedent """ + let output = dedent""" :field: text1""".toHtml check " Date: Fri, 15 Jul 2022 20:56:05 +0300 Subject: [PATCH 3487/4254] Implement type command (#19944) * Implement type command - this will be mapped to textDocument/typeDefinition in LSP protocol. It will be very useful for `nim` in particular because typically most of the time the type is inferred. * Update nimsuggest/nimsuggest.nim Co-authored-by: Andreas Rumpf --- compiler/options.nim | 4 +++- nimsuggest/nimsuggest.nim | 12 +++++++++- nimsuggest/tester.nim | 2 +- nimsuggest/tests/tv3_typeDefinition.nim | 32 +++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 nimsuggest/tests/tv3_typeDefinition.nim diff --git a/compiler/options.nim b/compiler/options.nim index d567927cb..9031e86c1 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -192,7 +192,7 @@ type IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod, ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols, - ideRecompile, ideChanged + ideRecompile, ideChanged, ideType Feature* = enum ## experimental features; DO NOT RENAME THESE! implicitDeref, @@ -1006,6 +1006,7 @@ proc parseIdeCmd*(s: string): IdeCmd = of "globalSymbols": ideGlobalSymbols of "recompile": ideRecompile of "changed": ideChanged + of "type": ideType else: ideNone proc `$`*(c: IdeCmd): string = @@ -1027,6 +1028,7 @@ proc `$`*(c: IdeCmd): string = of ideGlobalSymbols: "globalSymbols" of ideRecompile: "recompile" of ideChanged: "changed" + of ideType: "type" proc floatInt64Align*(conf: ConfigRef): int16 = ## Returns either 4 or 8 depending on reasons. diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index a18b2f960..6f35be925 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -457,6 +457,7 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = of "globalsymbols": conf.ideCmd = ideGlobalSymbols of "chkfile": conf.ideCmd = ideChkFile of "recompile": conf.ideCmd = ideRecompile + of "type": conf.ideCmd = ideType else: err() var dirtyfile = "" var orig = "" @@ -786,7 +787,7 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, graph.unmarkAllDirty() # these commands require partially compiled project - elif cmd in {ideSug, ideOutline, ideHighlight, ideDef, ideChkFile} and + elif cmd in {ideSug, ideOutline, ideHighlight, ideDef, ideChkFile, ideType} and (graph.needsCompilation(fileIndex) or cmd == ideSug): # for ideSug use v2 implementation if cmd == ideSug: @@ -802,6 +803,15 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, let (sym, info) = graph.findSymData(file, line, col) if sym != nil: graph.suggestResult(sym, sym.info) + of ideType: + let (sym, _) = graph.findSymData(file, line, col) + if sym != nil: + let typeSym = sym.typ.sym + if typeSym != nil: + graph.suggestResult(typeSym, typeSym.info, ideType) + elif sym.typ.len != 0: + let genericType = sym.typ[0].sym + graph.suggestResult(genericType, genericType.info, ideType) of ideUse, ideDus: let symbol = graph.findSymData(file, line, col).sym if symbol != nil: diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index fea0a8d45..6e068e067 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -282,7 +282,7 @@ proc runEpcTest(filename: string): int = socket.sendEpcStr(req) let sx = parseSexp(socket.recvEpc()) if not req.startsWith("mod "): - let answer = sexpToAnswer(sx) + let answer = if sx[2].kind == SNil: "" else: sexpToAnswer(sx) doReport(filename, answer, resp, report) socket.sendEpcStr "return arg" diff --git a/nimsuggest/tests/tv3_typeDefinition.nim b/nimsuggest/tests/tv3_typeDefinition.nim new file mode 100644 index 000000000..f86d12cc6 --- /dev/null +++ b/nimsuggest/tests/tv3_typeDefinition.nim @@ -0,0 +1,32 @@ +# tests v3 + +type + Foo* = ref object of RootObj + bar*: string + +proc test(ff: Foo) = + echo f#[!]#f.bar + +type + Fo#[!]#o2* = ref object of RootObj + +type + FooGeneric[T] = ref object of RootObj + bar*: T + +let fooGeneric = FooGeneric[string]() +echo fo#[!]#oGeneric.bar + +# bad type +echo unde#[!]#fined + +discard """ +$nimsuggest --v3 --tester $file +>type $1 +type skType tv3_typeDefinition.Foo Foo $file 4 2 "" 100 +>type $2 +type skType tv3_typeDefinition.Foo2 Foo2 $file 11 2 "" 100 +>type $3 +type skType tv3_typeDefinition.FooGeneric FooGeneric $file 14 2 "" 100 +>type $4 +""" From b0b9a3e5fade002b8f117f7ffb4d8fb93686401d Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Fri, 15 Jul 2022 20:56:33 +0300 Subject: [PATCH 3488/4254] Use module actual file instead of PSym.info (#19956) After this you can do goto module from module import --- compiler/suggest.nim | 30 ++++++++++++++++++------------ nimsuggest/tests/tv3_import.nim | 7 +++++++ 2 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 nimsuggest/tests/tv3_import.nim diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 4b48ef5bb..7e7d876fb 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -157,19 +157,25 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info result.forth = "" when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): result.doc = extractDocComment(g, s) - let infox = - if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}: - info - else: - s.info - result.filePath = toFullPath(g.config, infox) - result.line = toLinenumber(infox) - result.column = toColumn(infox) + if s.kind == skModule and s.ast.len != 0 and section != ideHighlight: + result.filePath = toFullPath(g.config, s.ast[0].info) + result.line = 1 + result.column = 0 + result.tokenLen = 0 + else: + let infox = + if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}: + info + else: + s.info + result.filePath = toFullPath(g.config, infox) + result.line = toLinenumber(infox) + result.column = toColumn(infox) + result.tokenLen = if section != ideHighlight: + s.name.s.len + else: + getTokenLenFromSource(g.config, s.name.s, infox) result.version = g.config.suggestVersion - result.tokenLen = if section != ideHighlight: - s.name.s.len - else: - getTokenLenFromSource(g.config, s.name.s, infox) proc `$`*(suggest: Suggest): string = result = $suggest.section diff --git a/nimsuggest/tests/tv3_import.nim b/nimsuggest/tests/tv3_import.nim new file mode 100644 index 000000000..3c128f85b --- /dev/null +++ b/nimsuggest/tests/tv3_import.nim @@ -0,0 +1,7 @@ +import tv#[!]#3 + +discard """ +$nimsuggest --v3 --tester $file +>def $1 +def skModule tv3 */tv3.nim 1 0 "" 100 +""" From 60dd38c50262774cadb1d365e649696380c0595e Mon Sep 17 00:00:00 2001 From: David Krause Date: Sat, 16 Jul 2022 11:59:58 +0200 Subject: [PATCH 3489/4254] make AsyncSocket.getPeerAddr work ; fix #15022 (#20038) Signed-off-by: David Krause --- lib/pure/asyncdispatch.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 0d406b271..ed786cefb 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1733,6 +1733,8 @@ when defined(windows) or defined(nimdoc): proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = if not retFuture.finished: if errcode == OSErrorCode(-1): + const SO_UPDATE_CONNECT_CONTEXT = 0x7010 + socket.SocketHandle.setSockOptInt(SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, 1) # 15022 retFuture.complete() else: retFuture.fail(newException(OSError, osErrorMsg(errcode))) From cf78c02b70ed105a173cce956ffab90bd57468a1 Mon Sep 17 00:00:00 2001 From: Amjad Ben Hedhili Date: Sat, 16 Jul 2022 21:51:27 +0100 Subject: [PATCH 3490/4254] Make `random.rand` work with `Ordinal` (#20043) * Make `random.rand` work with `Ordinal` * Add changelog entry * It's fine to cast to char --- changelog.md | 1 + lib/pure/random.nim | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 47479fc5c..c1dc6e27d 100644 --- a/changelog.md +++ b/changelog.md @@ -39,6 +39,7 @@ becomes an alias for `addr`. - `std/smtp` sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback. - Changed mimedb to use an `OrderedTable` instead of `OrderedTableRef`, to use it in a const. - `strutils.find` now use and default to `last=-1` for whole string searches, making limiting it to just the first char (`last=0`) valid. +- `random.rand` now works with `Ordinal`s. [//]: # "Additions:" - Added `IsoWeekRange`, a range type to represent the number of weeks in an ISO week-based year. diff --git a/lib/pure/random.nim b/lib/pure/random.nim index b8aeb86e0..832d54e3d 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -353,8 +353,8 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = result = rand(state, x) -proc rand*[T: SomeInteger](t: typedesc[T]): T = - ## Returns a random integer in the range `low(T)..high(T)`. +proc rand*[T: Ordinal](t: typedesc[T]): T = + ## Returns a random Ordinal in the range `low(T)..high(T)`. ## ## If `randomize <#randomize>`_ has not been called, the sequence of random ## numbers returned from this proc will always be the same. @@ -368,13 +368,16 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T = ## that accepts a slice runnableExamples: randomize(567) + type E = enum a, b, c, d if false: # implementation defined - assert rand(int8) == -42 - assert rand(uint32) == 578980729'u32 - assert rand(range[1..16]) == 11 + assert rand(E) in a..d + assert rand(char) in low(char)..high(char) + assert rand(int8) in low(int8)..high(int8) + assert rand(uint32) in low(uint32)..high(uint32) + assert rand(range[1..16]) in 1..16 # pending csources >= 1.4.0 or fixing https://github.com/timotheecour/Nim/issues/251#issuecomment-831599772, # use `runnableExamples("-r:off")` instead of `if false` - when T is range: + when T is range or T is enum or T is bool: result = rand(state, low(T)..high(T)) else: result = cast[T](state.next) From 094d86f99783f1366394fa444277c417dcbd1af3 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Sat, 16 Jul 2022 22:56:54 +0200 Subject: [PATCH 3491/4254] testament: use full test name in skips [backport] (#19937) testament: use full test name in skips --- testament/testament.nim | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/testament/testament.nim b/testament/testament.nim index d2b0e7fb4..98fc3c2aa 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -258,6 +258,15 @@ Tests failed and allowed to fail: $3 / $1
    Tests skipped: $4 / $1
    """ % [$x.total, $x.passed, $x.failedButAllowed, $x.skipped] +proc testName(test: TTest, target: TTarget, extraOptions: string, allowFailure: bool): string = + var name = test.name.replace(DirSep, '/') + name.add ' ' & $target + if allowFailure: + name.add " (allowed to fail) " + if test.options.len > 0: name.add ' ' & test.options + if extraOptions.len > 0: name.add ' ' & extraOptions + name.strip() + proc addResult(r: var TResults, test: TTest, target: TTarget, extraOptions, expected, given: string, successOrig: TResultEnum, allowFailure = false, givenSpec: ptr TSpec = nil) = @@ -265,13 +274,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, # instead of having to pass individual fields, or abusing existing ones like expected vs given. # test.name is easier to find than test.name.extractFilename # A bit hacky but simple and works with tests/testament/tshould_not_work.nim - var name = test.name.replace(DirSep, '/') - name.add ' ' & $target - if allowFailure: - name.add " (allowed to fail) " - if test.options.len > 0: name.add ' ' & test.options - if extraOptions.len > 0: name.add ' ' & extraOptions - + let name = testName(test, target, extraOptions, allowFailure) let duration = epochTime() - test.startTime let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout else: successOrig @@ -470,6 +473,9 @@ proc equalModuloLastNewline(a, b: string): bool = proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, target: TTarget, extraOptions: string, nimcache: string) = test.startTime = epochTime() + if testName(test, target, extraOptions, false) in skips: + test.spec.err = reDisabled + if test.spec.err in {reDisabled, reJoined}: r.addResult(test, target, extraOptions, "", "", test.spec.err) inc(r.skipped) From c43a377057c56d5213eb298feba883363f2b2a26 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sun, 17 Jul 2022 07:41:18 +1000 Subject: [PATCH 3492/4254] Make imports/exports not be a dropdown in sidebar (#19907) * Don't make a section be a dropdown if it has no child links * - Cleaned up code - Updated tests * Document what the 'if' is checking --- compiler/docgen.nim | 17 ++++++++++++++--- config/nimdoc.cfg | 8 ++++++++ nimdoc/testproject/expected/testproject.html | 7 +------ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index ed5fe06ef..d728c535f 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1474,10 +1474,21 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = for item in d.tocSimple[kind].sorted(cmp): d.toc2[kind].add item.content - d.toc[kind] = getConfigVar(d.conf, "doc.section.toc") % [ - "sectionid", $ord(kind), "sectionTitle", title, - "sectionTitleID", $(ord(kind) + 50), "content", d.toc2[kind]] + let sectionValues = @[ + "sectionID", $ord(kind), "sectionTitleID", $(ord(kind) + 50), + "sectionTitle", title + ] + # Check if the toc has any children + if d.toc2[kind] != "": + # Use the dropdown version instead and store the children in the dropdown + d.toc[kind] = getConfigVar(d.conf, "doc.section.toc") % (sectionValues & @[ + "content", d.toc2[kind] + ]) + else: + # Just have the link + d.toc[kind] = getConfigVar(d.conf, "doc.section.toc_item") % sectionValues + proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): string = $relativeTo(outDir / linkto, destFile.splitFile().dir, '/') diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 3b0afe8d6..7aee50d8c 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -16,6 +16,14 @@ doc.section = """ """ +# Just a single item in the TOC (e.g. imports, exports) +doc.section.toc_item = """ +
  • + $sectionTitle +
  • +""" + +# This is a section (e.g. procs, types) in the TOC which gets turned into a drop down doc.section.toc = """
  • diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 24dfdc13f..5fb9e697c 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -51,12 +51,7 @@
      baz @@ -539,7 +540,15 @@
      -
      +
      +
      proc bar(f: FooBuzz) {....raises: [], tags: [], forbids: [].}
      +
      + + + +
      +
      +
      proc bar[T](a, b: T): T
      diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 4d0e63c0c..4d0172313 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -7,6 +7,7 @@ bar testproject.html#bar,T,T testproject: bar[T](a, b: T): T baz testproject.html#baz,T,T testproject: baz[T](a, b: T): T buzz testproject.html#buzz,T,T testproject: buzz[T](a, b: T): T FooBuzz testproject.html#FooBuzz testproject: FooBuzz +bar testproject.html#bar testproject: bar(f: FooBuzz) aVariable testproject.html#aVariable testproject: aVariable A testproject.html#A testproject: A B testproject.html#B testproject: B diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 402541540..9f73040f2 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -78,6 +78,8 @@
    bar:
    • testproject: bar(f: FooBuzz)
    • +
    • testproject: bar[T](a, b: T): T
    • testproject: bar(): untyped
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 57960c69f..d236552ac 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -42,6 +42,11 @@ proc buzz*[T](a, b: T): T {.deprecated: "since v0.20".} = type FooBuzz* {.deprecated: "FooBuzz msg".} = int +using f: FooBuzz + +proc bar*(f) = # `f` should be expanded to `f: FooBuzz` + discard + import std/macros var aVariable*: array[1, int] From 28bed059aadf808fe56eaf2b36274bdf6baec053 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 12 Dec 2022 11:46:51 +0100 Subject: [PATCH 4050/4254] closes #20808 (#21077) --- tests/effects/tfuncs_cannot_mutate3.nim | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/effects/tfuncs_cannot_mutate3.nim diff --git a/tests/effects/tfuncs_cannot_mutate3.nim b/tests/effects/tfuncs_cannot_mutate3.nim new file mode 100644 index 000000000..029152029 --- /dev/null +++ b/tests/effects/tfuncs_cannot_mutate3.nim @@ -0,0 +1,35 @@ +discard """ + errormsg: "cannot mutate location kid.parent within a strict func" + line: 16 +""" + +{.experimental: "strictFuncs".} + +type + Node = ref object + name: string + kids: seq[Node] + parent: Node + +func initParents(tree: Node) = + for kid in tree.kids: + kid.parent = tree + initParents(kid) + +proc process(intro: Node): Node = + var tree = Node(name: "root", kids: @[ + intro, + Node(name: "one", kids: @[ + Node(name: "two"), + Node(name: "three"), + ]), + Node(name: "four"), + ]) + initParents(tree) + +proc main() = + var intro = Node(name: "intro") + var tree = process(intro) + echo intro.parent.name + +main() From 19923aa8b7bb93f687b71942b2ab3de39cba2f5a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 12 Dec 2022 21:14:24 +0800 Subject: [PATCH 4051/4254] work around chronos (#21079) * work around chronos chronos has tests against the devel branch, it will be eventually fine. * Apply suggestions from code review * Update testament/important_packages.nim --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 75283edbc..d0c87919b 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -52,7 +52,7 @@ pkg "cascade" pkg "cello", url = "https://github.com/nim-lang/cello", useHead = true pkg "chroma" pkg "chronicles", "nimble install -y stew@#head; nim c -o:chr -r chronicles.nim" -pkg "chronos", "nimble install -y bearssl@#head stew@#head httputils@#head; nim c -r -d:release tests/testall" +pkg "chronos", "nim c -r -d:release tests/testall", url = "https://github.com/nim-lang/nim-chronos" pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" pkg "compactdict" From fd7da7da629f9f569503220b656047fb2f8da125 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 12 Dec 2022 21:57:27 +0800 Subject: [PATCH 4052/4254] add a changelog for nimble (#21078) --- changelog.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 8efb7200c..5762d18ad 100644 --- a/changelog.md +++ b/changelog.md @@ -292,6 +292,4 @@ ## Tool changes -- Nim now supports Nimble version 0.14 which added support for lock-files. This is done by - a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg` - replace `pkgs` by `pkgs2`. +- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). From 584cfa6af81303caeaffe4084472167ad47216fe Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 12 Dec 2022 22:59:09 +0800 Subject: [PATCH 4053/4254] remove implicitDeref feature enum (#21075) remove implicitDeref feature --- compiler/options.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index a94405e05..7e4f6898f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -196,7 +196,6 @@ type ideRecompile, ideChanged, ideType, ideDeclaration Feature* = enum ## experimental features; DO NOT RENAME THESE! - implicitDeref, # deadcode; remains here for backwards compatibility dotOperators, callOperator, parallel, @@ -457,7 +456,7 @@ when false: fn(globalOptions) fn(selectedGC) -const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} +const oldExperimentalFeatures* = {dotOperators, callOperator, parallel} const ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, From 438863601047cc974d831c6c0dd5533e4e3f0dc5 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 12 Dec 2022 23:14:44 +0800 Subject: [PATCH 4054/4254] fixes #21043; fixes a named exception in the infixAs expression which generate an implicit uninitialized let statement (#21081) * fixes #21043; fixes a named exception in the infixAs expression which generate an implicit uninitialized let statement * Update compiler/sempass2.nim Co-authored-by: Andreas Rumpf Co-authored-by: Andreas Rumpf --- compiler/sempass2.nim | 4 ++++ tests/init/tlet.nim | 23 ++++++++++++++++++++++- tests/iter/tyieldintry.nim | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 4520609e3..f13d8d8d4 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -491,6 +491,10 @@ proc trackTryStmt(tracked: PEffects, n: PNode) = let b = n[i] if b.kind == nkExceptBranch: setLen(tracked.init, oldState) + for j in 0.. Date: Tue, 13 Dec 2022 08:19:02 +1100 Subject: [PATCH 4055/4254] Nimsuggest now defines the backends symbol (#21083) * Add testcase * Define the backend symbol * Remove unneeded whitespace --- nimsuggest/nimsuggest.nim | 7 +++++-- nimsuggest/tests/t20440.nim | 7 +++++++ nimsuggest/tests/t20440.nims | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 nimsuggest/tests/t20440.nim create mode 100644 nimsuggest/tests/t20440.nims diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index c4798e88c..c5e015ce9 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -27,7 +27,7 @@ import compiler / [options, commands, modules, sem, passes, passaux, msgs, sigmatch, ast, idents, modulegraphs, prefixmatches, lineinfos, cmdlinehelper, - pathutils] + pathutils, condsyms] when defined(nimPreviewSlimSystem): import std/typedthreads @@ -553,6 +553,7 @@ proc mainCommand(graph: ModuleGraph) = registerPass graph, verbosePass registerPass graph, semPass conf.setCmd cmdIdeTools + defineSymbol(conf.symbols, $conf.backend) wantMainModule(conf) if not fileExists(conf.projectFull): @@ -952,10 +953,12 @@ else: proc mockCommand(graph: ModuleGraph) = retval = graph let conf = graph.config + conf.setCmd cmdIdeTools + defineSymbol(conf.symbols, $conf.backend) clearPasses(graph) registerPass graph, verbosePass registerPass graph, semPass - conf.setCmd cmdIdeTools + wantMainModule(conf) if not fileExists(conf.projectFull): diff --git a/nimsuggest/tests/t20440.nim b/nimsuggest/tests/t20440.nim new file mode 100644 index 000000000..0456aa074 --- /dev/null +++ b/nimsuggest/tests/t20440.nim @@ -0,0 +1,7 @@ +when not defined(js): + {.fatal: "Crash".} +echo 4 + +discard """ +$nimsuggest --v3 --tester $file +""" diff --git a/nimsuggest/tests/t20440.nims b/nimsuggest/tests/t20440.nims new file mode 100644 index 000000000..1336be3d4 --- /dev/null +++ b/nimsuggest/tests/t20440.nims @@ -0,0 +1 @@ +switch("backend", "js") From d84f64d2e7a28d69c9a5b22b8434d1fb2f00ebf2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 13 Dec 2022 09:52:35 +0800 Subject: [PATCH 4056/4254] add CI for version-2-0 branch (#21084) --- .github/workflows/ci_packages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 93f5bfe19..0bec4cc21 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -4,6 +4,7 @@ on: push: branches: - 'devel' + - 'version-2-0' - 'version-1-6' - 'version-1-2' From 1fefb8e92a62c647028d0f00ebd9fc04da169789 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 13 Dec 2022 15:21:51 +1100 Subject: [PATCH 4057/4254] Refactor JS sourcemap generator (#21053) * Parse the new line format * Fix pattern Didn't have space after the path * Remove duplicate sources Sources would sometimes double up with a new line at the end * Remove unused variable * Refactor sourcemap.nim Removes the multiple translations needed, now goes from single high level type to the final SourceMap Adds documentation for procs * Line numbers line up properly now Files aren't linking correctly though * Files now link up correctly Lines are sometimes off but overall seems pretty good Just need to implement parser * Add column info to output Add sourceMappingURL to rope directly to prevent copy * Properly handle columns * Remove debug lines * Add testcase * Finish testcase * Use the outdir folder instead of the folder the test is in to find the sourcemap Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- compiler/jsgen.nim | 8 +- compiler/sourcemap.nim | 540 ++++++++++++++-------------------------- tests/js/tsourcemap.nim | 96 +++++++ 3 files changed, 283 insertions(+), 361 deletions(-) create mode 100644 tests/js/tsourcemap.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index bcabc42ed..42a3dcf31 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -724,8 +724,9 @@ proc hasFrameInfo(p: PProc): bool = ((p.prc == nil) or not (sfPure in p.prc.flags)) proc lineDir(config: ConfigRef, info: TLineInfo, line: int): Rope = - ropes.`%`("/* line $2 \"$1\" */$n", - [rope(toFullPath(config, info)), rope(line)]) + "/* line $2:$3 \"$1\" */$n" % [ + rope(toFullPath(config, info)), rope(line), rope(info.toColumn) + ] proc genLineDir(p: PProc, n: PNode) = let line = toLinenumber(n.info) @@ -2885,7 +2886,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = # Generate an optional source map. if optSourcemap in m.config.globalOptions: var map: SourceMap - (code, map) = genSourceMap($(code), outFile.string) + map = genSourceMap($code, outFile.string) + code &= "\n//# sourceMappingURL=$#.map" % [outFile.string] writeFile(outFile.string & ".map", $(%map)) # Check if the generated JS code matches the output file, or else # write it to the file. diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim index b87de75f3..2245250ac 100644 --- a/compiler/sourcemap.nim +++ b/compiler/sourcemap.nim @@ -1,383 +1,207 @@ -import os, strformat, strutils, tables, sets, ropes, json, algorithm +import std/[strutils, strscans, parseutils, assertions] type - SourceNode* = ref object - line*: int - column*: int - source*: string - name*: string - children*: seq[Child] + Segment = object + ## Segment refers to a block of something in the JS output. + ## This could be a token or an entire line + original: int # Column in the Nim source + generated: int # Column in the generated JS + name: int # Index into names list (-1 for no name) - C = enum cSourceNode, cSourceString + Mapping = object + ## Mapping refers to a line in the JS output. + ## It is made up of segments which refer to the tokens in the line + case inSource: bool # Whether the line in JS has Nim equivilant + of true: + file: int # Index into files list + line: int # 0 indexed line of code in the Nim source + segments: seq[Segment] + else: discard - Child* = ref object - case kind*: C: - of cSourceNode: - node*: SourceNode - of cSourceString: - s*: string + SourceInfo = object + mappings: seq[Mapping] + names, files: seq[string] - SourceMap* = ref object + SourceMap* = object version*: int sources*: seq[string] names*: seq[string] mappings*: string file*: string - # sourceRoot*: string - # sourcesContent*: string - SourceMapGenerator = ref object - file: string - sourceRoot: string - skipValidation: bool - sources: seq[string] - names: seq[string] - mappings: seq[Mapping] +func addSegment(info: var SourceInfo, original, generated: int, name: string = "") {.raises: [].} = + ## Adds a new segment into the current line + assert info.mappings.len > 0, "No lines have been added yet" + var segment = Segment(original: original, generated: generated, name: -1) + if name != "": + # Make name be index into names list + segment.name = info.names.find(name) + if segment.name == -1: + segment.name = info.names.len + info.names &= name - Mapping* = ref object - source*: string - original*: tuple[line: int, column: int] - generated*: tuple[line: int, column: int] - name*: string - noSource*: bool - noName*: bool + assert info.mappings[^1].inSource, "Current line isn't in Nim source" + info.mappings[^1].segments &= segment +func newLine(info: var SourceInfo) {.raises: [].} = + ## Add new mapping which doesn't appear in the Nim source + info.mappings &= Mapping(inSource: false) -proc child*(s: string): Child = - Child(kind: cSourceString, s: s) - - -proc child*(node: SourceNode): Child = - Child(kind: cSourceNode, node: node) - - -proc newSourceNode(line: int, column: int, path: string, node: SourceNode, name: string = ""): SourceNode = - SourceNode(line: line, column: column, source: path, name: name, children: @[child(node)]) - - -proc newSourceNode(line: int, column: int, path: string, s: string, name: string = ""): SourceNode = - SourceNode(line: line, column: column, source: path, name: name, children: @[child(s)]) - - -proc newSourceNode(line: int, column: int, path: string, children: seq[Child], name: string = ""): SourceNode = - SourceNode(line: line, column: column, source: path, name: name, children: children) - - - - -# debugging - - -proc text*(sourceNode: SourceNode, depth: int): string = - let empty = " " - result = &"{repeat(empty, depth)}SourceNode({sourceNode.source}:{sourceNode.line}:{sourceNode.column}):\n" - for child in sourceNode.children: - if child.kind == cSourceString: - result.add(&"{repeat(empty, depth + 1)}{child.s}\n") - else: - result.add(child.node.text(depth + 1)) - - -proc `$`*(sourceNode: SourceNode): string = text(sourceNode, 0) +func newLine(info: var SourceInfo, file: string, line: int) {.raises: [].} = + ## Starts a new line in the mappings. Call addSegment after this to add + ## segments into the line + var mapping = Mapping(inSource: true, line: line) + # Set file to file position. Add in if needed + mapping.file = info.files.find(file) + if mapping.file == -1: + mapping.file = info.files.len + info.files &= file + info.mappings &= mapping # base64_VLQ +func encode*(values: seq[int]): string {.raises: [].} = + ## Encodes a series of integers into a VLQ base64 encoded string + # References: + # - https://www.lucidchart.com/techblog/2019/08/22/decode-encoding-base64-vlqs-source-maps/ + # - https://github.com/rails/sprockets/blob/main/guides/source_maps.md#source-map-file + const + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + shift = 5 + continueBit = 1 shl 5 + mask = continueBit - 1 + for val in values: + # Sign is stored in first bit + var newVal = abs(val) shl 1 + if val < 0: + newVal = newVal or 1 + # Now comes the variable length part + # This is how we are able to store large numbers + while true: + # We only encode 5 bits. + var masked = newVal and mask + newVal = newVal shr shift + # If there is still something left + # then signify with the continue bit that the + # decoder should keep decoding + if newVal > 0: + masked = masked or continueBit + result &= alphabet[masked] + # If the value is zero then we have nothing left to encode + if newVal == 0: + break +iterator tokenize*(line: string): (int, string) = + ## Goes through a line and splits it into Nim identifiers and + ## normal JS code. This allows us to map mangled names back to Nim names. + ## Yields (column, name). Doesn't yield anything but identifiers. + ## See mangleName in compiler/jsgen.nim for how name mangling is done + var + col = 0 + token = "" + while col < line.len: + var + token: string + name: string + # First we find the next identifier + col += line.skipWhitespace(col) + col += line.skipUntil(IdentStartChars, col) + let identStart = col + col += line.parseIdent(token, col) + # Idents will either be originalName_randomInt or HEXhexCode_randomInt + if token.startsWith("HEX"): + var hex: int + # 3 = "HEX".len and we only want to parse the two integers after it + discard token[3 ..< 5].parseHex(hex) + name = $chr(hex) + elif not token.endsWith("_Idx"): # Ignore address indexes + # It might be in the form originalName_randomInt + let lastUnderscore = token.rfind('_') + if lastUnderscore != -1: + name = token[0.. 0: - var e = n and 31 - n = n shr 5 - if n > 0: - e = e or 32 - - result.add(integers[e]) - z += 1 - - -type TokenState = enum Normal, String, Ident, Mangled - -iterator tokenize*(line: string): (bool, string) = - # result = @[] - var state = Normal - var token = "" - var isMangled = false - for z, ch in line: - if ch.isAlphaAscii: - if state == Normal: - state = Ident - if token.len > 0: - yield (isMangled, token) - token = $ch - isMangled = false - else: - token.add(ch) - elif ch == '_': - if state == Ident: - state = Mangled - isMangled = true - token.add($ch) - elif ch != '"' and not ch.isAlphaNumeric: - if state in {Ident, Mangled}: - state = Normal - if token.len > 0: - yield (isMangled, token) - token = $ch - isMangled = false - else: - token.add($ch) - elif ch == '"': - if state != String: - state = String - if token.len > 0: - yield (isMangled, token) - token = $ch - isMangled = false - else: - state = Normal - token.add($ch) - if token.len > 0: - yield (isMangled, token) - isMangled = false - token = "" +func parse*(source: string): SourceInfo = + ## Parses the JS output for embedded line info + ## So it can convert those into a series of mappings + var + skipFirstLine = true + currColumn = 0 + currLine = 0 + currFile = "" + # Add each line as a node into the output + for line in source.splitLines(): + var + lineNumber: int + linePath: string + column: int + if line.strip().scanf("/* line $i:$i \"$+\" */", lineNumber, column, linePath): + # When we reach the first line mappinsegmentg then we can assume + # we can map the rest of the JS lines to Nim lines + currColumn = column # Column is already zero indexed + currLine = lineNumber - 1 + currFile = linePath + # Lines are zero indexed + result.newLine(currFile, currLine) + # Skip whitespace to find the starting column + result.addSegment(currColumn, line.skipWhitespace()) + elif currFile != "": + result.newLine(currFile, currLine) + # There mightn't be any tokens so add a starting segment + result.addSegment(currColumn, line.skipWhitespace()) + for jsColumn, token in line.tokenize: + result.addSegment(currColumn, jsColumn, token) else: - token.add($ch) - if token.len > 0: - yield (isMangled, token) + result.newLine() -proc parse*(source: string, path: string): SourceNode = - let lines = source.splitLines() - var lastLocation: SourceNode = nil - result = newSourceNode(0, 0, path, @[]) - - # we just use one single parent and add all nim lines - # as its children, I guess in typical codegen - # that happens recursively on ast level - # we also don't have column info, but I doubt more one nim lines can compile to one js - # maybe in macros? +func toSourceMap*(info: SourceInfo, file: string): SourceMap {.raises: [].} = + ## Convert from high level SourceInfo into the required SourceMap object + # Add basic info + result.version = 3 + result.file = file + result.sources = info.files + result.names = info.names + # Convert nodes into mappings. + # Mappings are split into blocks where each block referes to a line in the outputted JS. + # Blocks can be seperated into statements which refere to tokens on the line. + # Since the mappings depend on previous values we need to + # keep track of previous file, name, etc + var + prevFile = 0 + prevLine = 0 + prevName = 0 + prevNimCol = 0 - for i, originalLine in lines: - let line = originalLine.strip - if line.len == 0: - continue - - # this shouldn't be a problem: - # jsgen doesn't generate comments - # and if you emit // line you probably know what you're doing - if line.startsWith("// line"): - if result.children.len > 0: - result.children[^1].node.children.add(child(line & "\n")) - let pos = line.find(" ", 8) - let lineNumber = line[8 .. pos - 1].parseInt - let linePath = line[pos + 2 .. ^2] # quotes - - lastLocation = newSourceNode( - lineNumber, - 0, - linePath, - @[]) - result.children.add(child(lastLocation)) - else: - var last: SourceNode - for token in line.tokenize(): - var name = "" - if token[0]: - name = token[1].split('_', 1)[0] - - - if result.children.len > 0: - result.children[^1].node.children.add( - child( - newSourceNode( - result.children[^1].node.line, - 0, - result.children[^1].node.source, - token[1], - name))) - last = result.children[^1].node.children[^1].node - else: - result.children.add( - child( - newSourceNode(i + 1, 0, path, token[1], name))) - last = result.children[^1].node - let nl = "\n" - if not last.isNil: - last.source.add(nl) + for mapping in info.mappings: + # We know need to encode segments with the following fields + # All these fields are relative to their previous values + # - 0: Column in generated code + # - 1: Index of Nim file in source list + # - 2: Line in Nim source + # - 3: Column in Nim source + # - 4: Index in names list + if mapping.inSource: + # JS Column is special in that it is reset after every line + var prevJSCol = 0 + for segment in mapping.segments: + var values = @[segment.generated - prevJSCol, mapping.file - prevFile, mapping.line - prevLine, segment.original - prevNimCol] + # Add name field if needed + if segment.name != -1: + values &= segment.name - prevName + prevName = segment.name + prevJSCol = segment.generated + prevNimCol = segment.original + prevFile = mapping.file + prevLine = mapping.line + result.mappings &= encode(values) & "," + # Remove trailing , + if mapping.segments.len > 0: + result.mappings.setLen(result.mappings.len - 1) -proc cmp(a: Mapping, b: Mapping): int = - var c = cmp(a.generated, b.generated) - if c != 0: - return c + result.mappings &= ";" - c = cmp(a.source, b.source) - if c != 0: - return c - - c = cmp(a.original, b.original) - if c != 0: - return c - - return cmp(a.name, b.name) - - -proc index*[T](elements: seq[T], element: T): int = - for z in 0 ..< elements.len: - if elements[z] == element: - return z - return -1 - - -proc serializeMappings(map: SourceMapGenerator, mappings: seq[Mapping]): string = - var previous = Mapping(generated: (line: 1, column: 0), original: (line: 0, column: 0), name: "", source: "") - var previousSourceId = 0 - var previousNameId = 0 - var next = "" - var nameId = 0 - var sourceId = 0 - result = "" - - for z, mapping in mappings: - next = "" - - if mapping.generated.line != previous.generated.line: - previous.generated.column = 0 - - while mapping.generated.line != previous.generated.line: - next.add(";") - previous.generated.line += 1 - - else: - if z > 0: - if cmp(mapping, mappings[z - 1]) == 0: - continue - next.add(",") - - next.add(encode(mapping.generated.column - previous.generated.column)) - previous.generated.column = mapping.generated.column - - if not mapping.noSource and mapping.source.len > 0: - sourceId = map.sources.index(mapping.source) - next.add(encode(sourceId - previousSourceId)) - previousSourceId = sourceId - next.add(encode(mapping.original.line - 1 - previous.original.line)) - previous.original.line = mapping.original.line - 1 - next.add(encode(mapping.original.column - previous.original.column)) - previous.original.column = mapping.original.column - - if not mapping.noName and mapping.name.len > 0: - nameId = map.names.index(mapping.name) - next.add(encode(nameId - previousNameId)) - previousNameId = nameId - - result.add(next) - - -proc gen*(map: SourceMapGenerator): SourceMap = - var mappings = map.mappings.sorted do (a: Mapping, b: Mapping) -> int: - cmp(a, b) - result = SourceMap( - file: map.file, - version: 3, - sources: map.sources[0..^1], - names: map.names[0..^1], - mappings: map.serializeMappings(mappings)) - - - -proc addMapping*(map: SourceMapGenerator, mapping: Mapping) = - if not mapping.noSource and mapping.source notin map.sources: - map.sources.add(mapping.source) - - if not mapping.noName and mapping.name.len > 0 and mapping.name notin map.names: - map.names.add(mapping.name) - - # echo "map ", mapping.source, " ", mapping.original, " ", mapping.generated, " ", mapping.name - map.mappings.add(mapping) - - -proc walk*(node: SourceNode, fn: proc(line: string, original: SourceNode)) = - for child in node.children: - if child.kind == cSourceString and child.s.len > 0: - fn(child.s, node) - else: - child.node.walk(fn) - - -proc toSourceMap*(node: SourceNode, file: string): SourceMapGenerator = - var map = SourceMapGenerator(file: file, sources: @[], names: @[], mappings: @[]) - - var generated = (line: 1, column: 0) - var sourceMappingActive = false - var lastOriginal = SourceNode(source: "", line: -1, column: 0, name: "", children: @[]) - - node.walk do (line: string, original: SourceNode): - if original.source.endsWith(".js"): - # ignore it - discard - else: - if original.line != -1: - if lastOriginal.source != original.source or - lastOriginal.line != original.line or - lastOriginal.column != original.column or - lastOriginal.name != original.name: - map.addMapping( - Mapping( - source: original.source, - original: (line: original.line, column: original.column), - generated: (line: generated.line, column: generated.column), - name: original.name)) - - lastOriginal = SourceNode( - source: original.source, - line: original.line, - column: original.column, - name: original.name, - children: lastOriginal.children) - sourceMappingActive = true - elif sourceMappingActive: - map.addMapping( - Mapping( - noSource: true, - noName: true, - generated: (line: generated.line, column: generated.column), - original: (line: -1, column: -1))) - lastOriginal.line = -1 - sourceMappingActive = false - - for z in 0 ..< line.len: - if line[z] in Newlines: - generated.line += 1 - generated.column = 0 - - if z == line.len - 1: - lastOriginal.line = -1 - sourceMappingActive = false - elif sourceMappingActive: - map.addMapping( - Mapping( - source: original.source, - original: (line: original.line, column: original.column), - generated: (line: generated.line, column: generated.column), - name: original.name)) - else: - generated.column += 1 - - map - - -proc genSourceMap*(source: string, outFile: string): (Rope, SourceMap) = - let node = parse(source, outFile) - let map = node.toSourceMap(file = outFile) - ((&"{source}\n//# sourceMappingURL={outFile}.map").rope, map.gen) +proc genSourceMap*(source: string, outFile: string): SourceMap = + let node = parse(source) + result = node.toSourceMap(outFile) diff --git a/tests/js/tsourcemap.nim b/tests/js/tsourcemap.nim new file mode 100644 index 000000000..ff6f6122f --- /dev/null +++ b/tests/js/tsourcemap.nim @@ -0,0 +1,96 @@ +discard """ + action: "run" + target: "js" + cmd: "nim js -r -d:nodejs $options --sourceMap:on $file" +""" +import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings] + +# Implements a very basic sourcemap parser and then runs it on itself. +# Allows to check for basic problems such as bad counts and lines missing (e.g. issue #21052) + +type + SourceMap = object + version: int + sources: seq[string] + names: seq[string] + mappings: string + file: string + + Line = object + line, column: int + file: string + +const + flag = 1 shl 5 + signBit = 0b1 + fourBits = 0b1111 + fiveBits = 0b11111 + mask = (1 shl 5) - 1 + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +var b64Table: seq[int] = 0.repeat(max(alphabet.mapIt(it.ord)) + 1) +for i, b in alphabet.pairs: + b64Table[b.ord] = i + +# From https://github.com/juancarlospaco/nodejs/blob/main/src/nodejs/jsfs.nim +proc importFs*() {.importjs: "var fs = require(\"fs\");".} +proc readFileSync*(path: cstring): cstring {.importjs: "(fs.$1(#).toString())".} +importFS() +# Read in needed files +let + jsFileName = string(querySetting(outDir).Path / "tsourcemap.js".Path) + mapFileName = jsFileName & ".map" + + data = parseJson($mapFileName.cstring.readFileSync()).to(SourceMap) + jsFile = $readFileSync(jsFileName.cstring) + +proc decodeVLQ(inp: string): seq[int] = + var + shift, value: int + for v in inp.mapIt(b64Table[it.ord]): + value += (v and mask) shl shift + if (v and flag) > 0: + shift += 5 + continue + result &= (value shr 1) * (if (value and 1) > 0: -1 else: 1) + shift = 0 + value = 0 + + +# Keep track of state +var + line = 0 + source = 0 + name = 0 + column = 0 + jsLine = 1 + lines: seq[Line] + +for gline in data.mappings.split(';'): + jsLine += 1 + var jsColumn = 0 + for item in gline.strip().split(','): + let value = item.decodeVLQ() + doAssert value.len in [0, 1, 4, 5] + if value.len == 0: + continue + jsColumn += value[0] + if value.len >= 4: + source += value[1] + line += value[2] + column += value[3] + lines &= Line(line: line, column: column, file: data.sources[source]) + +let jsLines = jsFile.splitLines().len +# There needs to be a mapping for every line in the JS +# If there isn't then the JS lines wont match up with Nim lines. +# Except we don't care about the final line since that doesn't need to line up +doAssert data.mappings.count(';') == jsLines - 1 + +# Check we can find this file somewhere in the source map +var foundSelf = false +for line in lines: + if "tsourcemap.nim" in line.file: + foundSelf = true + doAssert line.line in 0.. Date: Tue, 13 Dec 2022 18:43:37 +1100 Subject: [PATCH 4058/4254] JS backend properly extends string with `setLen` (#21087) * Add test case * Extend string with '0' when setting length to be longer --- compiler/jsgen.nim | 4 +++- tests/js/t20235.nim | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/js/t20235.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 42a3dcf31..d8fb6d57d 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2209,7 +2209,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true) of mSetLengthStr: - binaryExpr(p, n, r, "mnewString", "($1.length = $2)") + binaryExpr(p, n, r, "mnewString", + """if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); } + else {$3.length = $4; }""") of mSetLengthSeq: var x, y: TCompRes gen(p, n[1], x) diff --git a/tests/js/t20235.nim b/tests/js/t20235.nim new file mode 100644 index 000000000..3a69c2bd6 --- /dev/null +++ b/tests/js/t20235.nim @@ -0,0 +1,11 @@ +discard """ + action: "run" + output: "0 4" +""" + +proc main = + var s = "" + s.setLen(4) + echo s[0].ord, " ", s.len + +main() From e4aadcf1c1b39a5fef55ce9f164b3251c44ca000 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 13 Dec 2022 08:47:01 +0100 Subject: [PATCH 4059/4254] Document that system:pop() may raise IndexDefect (#21070) * Document system:pop() may raise IndexDefect * Add backticks to KeyError --- lib/pure/collections/sets.nim | 6 +++--- lib/system.nim | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 09648ea65..11e324923 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -347,7 +347,7 @@ proc missingOrExcl*[A](s: var HashSet[A], key: A): bool = proc pop*[A](s: var HashSet[A]): A = ## Removes and returns an arbitrary element from the set `s`. ## - ## Raises KeyError if the set `s` is empty. + ## Raises `KeyError` if the set `s` is empty. ## ## See also: ## * `clear proc <#clear,HashSet[A]>`_ @@ -425,7 +425,7 @@ proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] = assert c == toHashSet(["b"]) result = initHashSet[A](max(min(s1.data.len, s2.data.len), 2)) - + # iterate over the elements of the smaller set if s1.data.len < s2.data.len: for item in s1: @@ -433,7 +433,7 @@ proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] = else: for item in s2: if item in s1: incl(result, item) - + proc difference*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the difference of the sets `s1` and `s2`. diff --git a/lib/system.nim b/lib/system.nim index d0f78bfbd..65055f145 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1664,6 +1664,8 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}= proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = ## Returns the last item of `s` and decreases `s.len` by one. This treats ## `s` as a stack and implements the common *pop* operation. + ## + ## Raises `IndexDefect` if `s` is empty. runnableExamples: var a = @[1, 3, 5, 7] let b = pop(a) From 2564b5c938602e4f8820d2ed2b778c6d4f1d0cd5 Mon Sep 17 00:00:00 2001 From: Aditya Siram Date: Tue, 13 Dec 2022 08:57:07 -0600 Subject: [PATCH 4060/4254] Fix #20416. Enable the recursion limit for ref/ptr types. (#21092) --- compiler/semtypinst.nim | 18 ++++++++++++++---- tests/generics/tgenerics_issues.nim | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 945667a81..0a0ac1704 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -499,10 +499,20 @@ proc propagateFieldFlags(t: PType, n: PNode) = proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = template bailout = - if t.sym != nil and sfGeneratedType in t.sym.flags: - # Only consider the recursion limit if the symbol is a type with generic - # parameters that have not been explicitly supplied, typechecking should - # terminate when generic parameters are explicitly supplied. + if (t.sym == nil) or (t.sym != nil and sfGeneratedType in t.sym.flags): + # In the first case 't.sym' can be 'nil' if the type is a ref/ptr, see + # issue https://github.com/nim-lang/Nim/issues/20416 for more details. + # Fortunately for us this works for now because partial ref/ptr types are + # not allowed in object construction, eg. + # type + # Container[T] = ... + # O = object + # val: ref Container + # + # In the second case only consider the recursion limit if the symbol is a + # type with generic parameters that have not been explicitly supplied, + # typechecking should terminate when generic parameters are explicitly + # supplied. if cl.recursionLimit > 100: # bail out, see bug #2509. But note this caching is in general wrong, # look at this example where TwoVectors should not share the generic diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index db7a16569..3068a22f2 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -872,3 +872,23 @@ block: # Ensure no segfault from constraint a = Regex[int]() b = Regex[bool]() c = MyOtherType[seq[int]]() + +block: # https://github.com/nim-lang/Nim/issues/20416 + type + Item[T] = object + link:ptr Item[T] + data:T + + KVSeq[A,B] = seq[(A,B)] + + MyTable[A,B] = object + data: KVSeq[A,B] + + Container[T] = object + a: MyTable[int,ref Item[T]] + + proc p1(sg:Container) = discard # Make sure that a non parameterized 'Container' argument still compiles + + proc p2[T](sg:Container[T]) = discard + var v : Container[int] + p2(v) From 9a50033d5b09ec3263a53bd2bb4182a8a50e6f4d Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 13 Dec 2022 23:20:55 +0300 Subject: [PATCH 4061/4254] generic `define` pragma + string alias (#20979) * generic `define` pragma + string alias * clean * add tests and document * remove char/float, minimize changelog --- changelog.md | 30 +++++++++- compiler/ast.nim | 2 +- compiler/condsyms.nim | 2 + compiler/pragmas.nim | 23 +++++--- compiler/semfold.nim | 109 ++++++++++++++++++++++++++++--------- doc/manual.md | 18 ++++++ doc/manual_experimental.md | 23 ++++++++ tests/misc/tdefine.nim | 64 ++++++++++++++++------ 8 files changed, 218 insertions(+), 53 deletions(-) diff --git a/changelog.md b/changelog.md index 5762d18ad..0181d03d2 100644 --- a/changelog.md +++ b/changelog.md @@ -221,9 +221,33 @@ - Full command syntax and block arguments i.e. `foo a, b: c` are now allowed for the right-hand side of type definitions in type sections. Previously they would error with "invalid indentation". -- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. - In the command line, this is defined as `-d:a.b.c`. Older versions can - use accents as in ``defined(`a.b.c`)`` to access such defines. + +- Compile-time define changes: + - `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. + In the command line, this is defined as `-d:a.b.c`. Older versions can + use accents as in ``defined(`a.b.c`)`` to access such defines. + - [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas) + now support a string argument for qualified define names. + + ```nim + # -d:package.FooBar=42 + const FooBar {.intdefine: "package.FooBar".}: int = 5 + echo FooBar # 42 + ``` + + This was added to help disambiguate similar define names for different packages. + In older versions, this could only be achieved with something like the following: + + ```nim + const FooBar = block: + const `package.FooBar` {.intdefine.}: int = 5 + `package.FooBar` + ``` + - A generic `define` pragma for constants has been added that interprets + the value of the define based on the type of the constant value. + See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma) + for a list of supported types. + - [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes: - Templates now accept macro pragmas. - Macro pragmas for var/let/const sections have been redesigned in a way that works diff --git a/compiler/ast.nim b/compiler/ast.nim index 198d21bea..c85a94860 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -712,7 +712,7 @@ type mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, - mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, + mNimvm, mIntDefine, mStrDefine, mBoolDefine, mGenericDefine, mRunnableExamples, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 182e49bf8..41b4c83aa 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -149,3 +149,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasOutParams") defineSymbol("nimHasSystemRaisesDefect") defineSymbol("nimHasWarnUnnamedBreak") + defineSymbol("nimHasGenericDefine") + defineSymbol("nimHasDefineAliases") diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index b60331b29..993e6edce 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -81,7 +81,8 @@ const wGuard, wGoto, wCursor, wNoalias, wAlign} constPragmas* = declPragmas + {wHeader, wMagic, wGensym, wInject, - wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore} + wIntDefine, wStrDefine, wBoolDefine, wDefine, + wCompilerProc, wCore} paramPragmas* = {wNoalias, wInject, wGensym} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, @@ -476,8 +477,16 @@ proc processPop(c: PContext, n: PNode) = when defined(debugOptions): echo c.config $ n.info, " POP config is now ", c.config.options -proc processDefine(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): +proc processDefineConst(c: PContext, n: PNode, sym: PSym, kind: TMagic) = + sym.magic = kind + if n.kind in nkPragmaCallKinds and n.len == 2: + # could also use TLib + n[1] = getStrLitNode(c, n) + +proc processDefine(c: PContext, n: PNode, sym: PSym) = + if sym != nil and sym.kind == skConst: + processDefineConst(c, n, sym, mGenericDefine) + elif (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): defineSymbol(c.config.symbols, n[1].ident.s) else: invalidPragma(c, n) @@ -1066,7 +1075,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, recordPragma(c, it, "error", s) localError(c.config, it.info, errUser, s) of wFatal: fatal(c.config, it.info, expectStrLit(c, it)) - of wDefine: processDefine(c, it) + of wDefine: processDefine(c, it, sym) of wUndef: processUndef(c, it) of wCompile: processCompile(c, it) of wLink: processLink(c, it) @@ -1213,11 +1222,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, noVal(c, it) sym.flags.incl sfBase of wIntDefine: - sym.magic = mIntDefine + processDefineConst(c, n, sym, mIntDefine) of wStrDefine: - sym.magic = mStrDefine + processDefineConst(c, n, sym, mStrDefine) of wBoolDefine: - sym.magic = mBoolDefine + processDefineConst(c, n, sym, mBoolDefine) of wUsed: noVal(c, it) if sym == nil: invalidPragma(c, it) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 9e45e3b2d..7c57eb370 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -13,7 +13,7 @@ import strutils, options, ast, trees, nimsets, platform, math, msgs, idents, renderer, types, - commands, magicsys, modulegraphs, strtabs, lineinfos + commands, magicsys, modulegraphs, strtabs, lineinfos, wordrecg from system/memory import nimCStrLen @@ -371,6 +371,11 @@ proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) = localError(g.config, n.info, "cannot convert " & $value & " to " & typeToString(n.typ)) +proc floatRangeCheck(n: PNode, value: BiggestFloat; g: ModuleGraph) = + if value < firstFloat(n.typ) or value > lastFloat(n.typ): + localError(g.config, n.info, "cannot convert " & $value & + " to " & typeToString(n.typ)) + proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): PNode = let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc}) let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc}) @@ -490,6 +495,81 @@ proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode = else: result.typ = s.typ +proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = + var name = s.name.s + let prag = extractPragma(s) + if prag != nil: + for it in prag: + if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent: + let word = whichKeyword(it[0].ident) + if word in {wStrDefine, wIntDefine, wBoolDefine, wDefine}: + # should be processed in pragmas.nim already + if it[1].kind in {nkStrLit, nkRStrLit, nkTripleStrLit}: + name = it[1].strVal + if isDefined(g.config, name): + let str = g.config.symbols[name] + case s.magic + of mIntDefine: + try: + result = newIntNodeT(toInt128(str.parseInt), n, idgen, g) + except ValueError: + localError(g.config, s.info, + "{.intdefine.} const was set to an invalid integer: '" & + str & "'") + of mStrDefine: + result = newStrNodeT(str, n, g) + of mBoolDefine: + try: + result = newIntNodeT(toInt128(str.parseBool.int), n, idgen, g) + except ValueError: + localError(g.config, s.info, + "{.booldefine.} const was set to an invalid bool: '" & + str & "'") + of mGenericDefine: + let rawTyp = s.typ + # pretend we don't support distinct types + let typ = rawTyp.skipTypes(abstractVarRange-{tyDistinct}) + try: + template intNode(value): PNode = + let val = toInt128(value) + rangeCheck(n, val, g) + newIntNodeT(val, n, idgen, g) + case typ.kind + of tyString, tyCstring: + result = newStrNodeT(str, n, g) + of tyInt..tyInt64: + result = intNode(str.parseBiggestInt) + of tyUInt..tyUInt64: + result = intNode(str.parseBiggestUInt) + of tyBool: + result = intNode(str.parseBool.int) + of tyEnum: + # compile time parseEnum + let ident = getIdent(g.cache, str) + for e in typ.n: + if e.kind != nkSym: internalError(g.config, "foldDefine for enum") + let es = e.sym + let match = + if es.ast.isNil: + es.name.id == ident.id + else: + es.ast.strVal == str + if match: + result = intNode(es.position) + break + if result.isNil: + raise newException(ValueError, "invalid enum value: " & str) + else: + localError(g.config, s.info, "unsupported type $1 for define '$2'" % + [name, typeToString(rawTyp)]) + except ValueError as e: + localError(g.config, s.info, + "could not process define '$1' of type $2; $3" % + [name, typeToString(rawTyp), e.msg]) + else: result = copyTree(s.astdef) # unreachable + else: + result = copyTree(s.astdef) + proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = result = nil case n.kind @@ -509,31 +589,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g) of mBuildCPU: result = newStrNodeT(platform.CPU[g.config.target.hostCPU].name.toLowerAscii, n, g) of mAppType: result = getAppType(n, g) - of mIntDefine: - if isDefined(g.config, s.name.s): - try: - result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, idgen, g) - except ValueError: - localError(g.config, s.info, - "{.intdefine.} const was set to an invalid integer: '" & - g.config.symbols[s.name.s] & "'") - else: - result = copyTree(s.astdef) - of mStrDefine: - if isDefined(g.config, s.name.s): - result = newStrNodeT(g.config.symbols[s.name.s], n, g) - else: - result = copyTree(s.astdef) - of mBoolDefine: - if isDefined(g.config, s.name.s): - try: - result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, idgen, g) - except ValueError: - localError(g.config, s.info, - "{.booldefine.} const was set to an invalid bool: '" & - g.config.symbols[s.name.s] & "'") - else: - result = copyTree(s.astdef) + of mIntDefine, mStrDefine, mBoolDefine, mGenericDefine: + result = foldDefine(m, s, n, idgen, g) else: result = copyTree(s.astdef) of skProc, skFunc, skMethod: diff --git a/doc/manual.md b/doc/manual.md index bd2cf8568..0a295fdb5 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -8049,6 +8049,24 @@ used. To see if a value was provided, `defined(FooBar)` can be used. The syntax `-d:flag`:option: is actually just a shortcut for `-d:flag=true`:option:. +These pragmas also accept an optional string argument for qualified +define names. + + ```nim + const FooBar {.intdefine: "package.FooBar".}: int = 5 + echo FooBar + ``` + + ```cmd + nim c -d:package.FooBar=42 foobar.nim + ``` + +This helps disambiguate define names in different packages. + +See also the [generic `define` pragma](manual_experimental.html#generic-define-pragma) +for a version of these pragmas that detects the type of the define based on +the constant value. + User-defined pragmas ==================== diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 6f5906019..2a56c1354 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -65,6 +65,29 @@ However, a `void` type cannot be inferred in generic code: The `void` type is only valid for parameters and return types; other symbols cannot have the type `void`. +Generic `define` pragma +======================= + +Aside the [typed define pragmas for constants](manual.html#implementation-specific-pragmas-compileminustime-define-pragmas), +there is a generic `{.define.}` pragma that interprets the value of the define +based on the type of the constant value. + + ```nim + const foo {.define: "package.foo".} = 123 + const bar {.define: "package.bar".} = false + ``` + + ```cmd + nim c -d:package.foo=456 -d:package.bar foobar.nim + ``` + +The following types are supported: + +* `string` and `cstring` +* Signed and unsigned integer types +* `bool` +* Enums + Top-down type inference ======================= diff --git a/tests/misc/tdefine.nim b/tests/misc/tdefine.nim index c4d11c941..f3fa4711f 100644 --- a/tests/misc/tdefine.nim +++ b/tests/misc/tdefine.nim @@ -1,12 +1,23 @@ discard """ joinable: false -cmd: "nim c -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -d:namespaced.define=false -d:double.namespaced.define -r $file" +cmd: "nim c $options -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -d:namespaced.define=false -d:double.namespaced.define -r $file" +matrix: "; -d:useGenericDefine" """ -const booldef {.booldefine.} = false -const booldef2 {.booldefine.} = true -const intdef {.intdefine.} = 0 -const strdef {.strdefine.} = "" +when defined(useGenericDefine): + {.pragma: booldefine2, define.} + {.pragma: intdefine2, define.} + {.pragma: strdefine2, define.} +else: + + {.pragma: booldefine2, booldefine.} + {.pragma: intdefine2, intdefine.} + {.pragma: strdefine2, strdefine.} + +const booldef {.booldefine2.} = false +const booldef2 {.booldefine2.} = true +const intdef {.intdefine2.} = 0 +const strdef {.strdefine2.} = "" doAssert defined(booldef) doAssert defined(booldef2) @@ -17,17 +28,28 @@ doAssert not booldef2 doAssert intdef == 2 doAssert strdef == "foobar" +when defined(useGenericDefine): + block: + const uintdef {.define: "intdef".}: uint = 17 + doAssert intdef == int(uintdef) + const cstrdef {.define: "strdef".}: cstring = "not strdef" + doAssert $cstrdef == strdef + type FooBar = enum foo, bar, foobar + const enumdef {.define: "strdef".} = foo + doAssert $enumdef == strdef + doAssert enumdef == foobar + # Intentionally not defined from command line -const booldef3 {.booldefine.} = true -const intdef2 {.intdefine.} = 1 -const strdef2 {.strdefine.} = "abc" +const booldef3 {.booldefine2.} = true +const intdef2 {.intdefine2.} = 1 +const strdef2 {.strdefine2.} = "abc" type T = object - when booldef3: - field1: int - when intdef2 == 1: - field2: int - when strdef2 == "abc": - field3: int + when booldef3: + field1: int + when intdef2 == 1: + field2: int + when strdef2 == "abc": + field3: int doAssert not defined(booldef3) doAssert not defined(intdef2) @@ -35,11 +57,21 @@ doAssert not defined(strdef2) discard T(field1: 1, field2: 2, field3: 3) doAssert defined(namespaced.define) -const `namespaced.define` {.booldefine.} = true +const `namespaced.define` {.booldefine2.} = true doAssert not `namespaced.define` +when defined(useGenericDefine): + const aliasToNamespacedDefine {.define: "namespaced.define".} = not `namespaced.define` +else: + const aliasToNamespacedDefine {.booldefine: "namespaced.define".} = not `namespaced.define` +doAssert aliasToNamespacedDefine == `namespaced.define` doAssert defined(double.namespaced.define) -const `double.namespaced.define` {.booldefine.} = false +const `double.namespaced.define` {.booldefine2.} = false doAssert `double.namespaced.define` +when defined(useGenericDefine): + const aliasToDoubleNamespacedDefine {.define: "double.namespaced.define".} = not `double.namespaced.define` +else: + const aliasToDoubleNamespacedDefine {.booldefine: "double.namespaced.define".} = not `double.namespaced.define` +doAssert aliasToDoubleNamespacedDefine == `double.namespaced.define` doAssert not defined(namespaced.butnotdefined) From 91ce8c385d4ccbaab8048cf0393b01cd72282272 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 15 Dec 2022 13:45:36 +0800 Subject: [PATCH 4062/4254] fix #19580; add warning for bare except: clause (#21099) * fix #19580; add warning for bare except: clause * fixes some easy ones * Update doc/manual.md * fixes docs * Update changelog.md * addition * Apply suggestions from code review Co-authored-by: Jacek Sieka * Update doc/tut2.md Co-authored-by: Jacek Sieka --- changelog.md | 2 ++ compiler/condsyms.nim | 1 + compiler/docgen.nim | 8 ++++---- compiler/extccomp.nim | 4 ++-- compiler/lineinfos.nim | 2 ++ compiler/nim.cfg | 4 ++++ compiler/semstmts.nim | 5 ++++- compiler/types.nim | 12 ++++++++++++ doc/manual.md | 20 +++++++++----------- doc/tut2.md | 4 ++-- lib/packages/docutils/rst.nim | 6 +++--- lib/pure/htmlparser.nim | 4 ++-- lib/std/assertions.nim | 2 ++ tests/nimdoc/trunnableexamples.nim | 2 +- 14 files changed, 50 insertions(+), 26 deletions(-) diff --git a/changelog.md b/changelog.md index 0181d03d2..00bdb50c2 100644 --- a/changelog.md +++ b/changelog.md @@ -133,6 +133,8 @@ `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. +- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 41b4c83aa..9d081ef0a 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -151,3 +151,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasWarnUnnamedBreak") defineSymbol("nimHasGenericDefine") defineSymbol("nimHasDefineAliases") + defineSymbol("nimHasWarnBareExcept") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index fc37bd596..f8a804cec 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1746,7 +1746,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) = let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt) try: writeFile(filename, content) - except: + except IOError: rawMessage(conf, errCannotOpenFile, filename.string) proc commandTags*(cache: IdentCache, conf: ConfigRef) = @@ -1768,7 +1768,7 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) = let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt) try: writeFile(filename, content) - except: + except IOError: rawMessage(conf, errCannotOpenFile, filename.string) proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") = @@ -1789,7 +1789,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") try: writeFile(filename, code) - except: + except IOError: rawMessage(conf, errCannotOpenFile, filename.string) proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile"") = @@ -1803,5 +1803,5 @@ proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile try: writeFile(filename, $body) - except: + except IOError: rawMessage(conf, errCannotOpenFile, filename.string) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 256e02b22..66de46556 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -528,7 +528,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool = var exe = getConfigVar(conf, conf.cCompiler, ".exe") if exe.len == 0: exe = CC[conf.cCompiler].compilerExe # NOTE: should we need the full version, use -dumpfullversion - let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except: ("", 1) + let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1) if exitCode == 0: var major: int discard parseInt(s, major) @@ -1018,7 +1018,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = var bcache: BuildCache try: bcache.fromJson(jsonFile.string.parseFile) - except: + except ValueError, KeyError, JsonKindError: let e = getCurrentException() conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" % [e.msg, e.getStackTrace(), jsonFile.string] diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index ab9c902c3..cb60d8949 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -86,6 +86,7 @@ type warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition", warnUnnamedBreak = "UnnamedBreak", warnStmtListLambda = "StmtListLambda", + warnBareExcept = "BareExcept", warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -185,6 +186,7 @@ const warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma", warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead", warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead", + warnBareExcept: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 20ce3810f..96b47b0e6 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -38,3 +38,7 @@ define:useStdoutAsStdmsg @if nimHasWarnUnnamedBreak: warningAserror[UnnamedBreak]:on @end + +@if nimHasWarnBareExcept: + warningAserror[BareExcept]:on +@end diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d19d75611..a7a02d7fa 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -210,6 +210,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil) isImported = true elif not isException(typ): localError(c.config, typeNode.info, errExprCannotBeRaised) + elif not isDefectOrCatchableError(typ): + message(c.config, a.info, warnBareExcept, "catch a more precise Exception deriving from CatchableError or Defect.") if containsOrIncl(check, typ.id): localError(c.config, typeNode.info, errExceptionAlreadyHandled) @@ -251,7 +253,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil) elif a.len == 1: # count number of ``except: body`` blocks inc catchAllExcepts - + message(c.config, a.info, warnBareExcept, + "The bare except clause is deprecated; use `except CatchableError:` instead") else: # support ``except KeyError, ValueError, ... : body`` if catchAllExcepts > 0: diff --git a/compiler/types.nim b/compiler/types.nim index 4bbbaf13c..457568e32 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1721,6 +1721,18 @@ proc isDefectException*(t: PType): bool = t = skipTypes(t[0], abstractPtrs) return false +proc isDefectOrCatchableError*(t: PType): bool = + var t = t.skipTypes(abstractPtrs) + while t.kind == tyObject: + if t.sym != nil and t.sym.owner != nil and + sfSystemModule in t.sym.owner.flags and + (t.sym.name.s == "Defect" or + t.sym.name.s == "CatchableError"): + return true + if t[0] == nil: break + t = skipTypes(t[0], abstractPtrs) + return false + proc isSinkTypeForParam*(t: PType): bool = # a parameter like 'seq[owned T]' must not be used only once, but its # elements must, so we detect this case here: diff --git a/doc/manual.md b/doc/manual.md index 0a295fdb5..779e99186 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -4773,8 +4773,8 @@ Example: echo "overflow!" except ValueError, IOError: echo "catch multiple exceptions!" - except: - echo "Unknown exception!" + except CatchableError: + echo "Catchable exception!" finally: close(f) ``` @@ -4786,9 +4786,6 @@ listed in an `except` clause, the corresponding statements are executed. The statements following the `except` clauses are called `exception handlers`:idx:. -The empty `except`:idx: clause is executed if there is an exception that is -not listed otherwise. It is similar to an `else` clause in `if` statements. - If there is a `finally`:idx: clause, it is always executed after the exception handlers. @@ -4806,11 +4803,11 @@ Try can also be used as an expression; the type of the `try` branch then needs to fit the types of `except` branches, but the type of the `finally` branch always has to be `void`: - ```nim + ```nim test from std/strutils import parseInt let x = try: parseInt("133a") - except: -1 + except ValueError: -1 finally: echo "hi" ``` @@ -4818,8 +4815,9 @@ branch always has to be `void`: To prevent confusing code there is a parsing limitation; if the `try` follows a `(` it has to be written as a one liner: - ```nim - let x = (try: parseInt("133a") except: -1) + ```nim test + from std/strutils import parseInt + let x = (try: parseInt("133a") except ValueError: -1) ``` @@ -4867,7 +4865,7 @@ error message from `e`, and for such situations, it is enough to use ```nim try: # ... - except: + except CatchableError: echo getCurrentExceptionMsg() ``` @@ -5055,7 +5053,7 @@ An empty `raises` list (`raises: []`) means that no exception may be raised: try: unsafeCall() result = true - except: + except CatchableError: result = false ``` diff --git a/doc/tut2.md b/doc/tut2.md index 3c858c64e..4b9049082 100644 --- a/doc/tut2.md +++ b/doc/tut2.md @@ -393,7 +393,7 @@ The `try` statement handles exceptions: echo "could not convert string to integer" except IOError: echo "IO error!" - except: + except CatchableError: echo "Unknown exception!" # reraise the unknown exception: raise @@ -425,7 +425,7 @@ module. Example: ```nim try: doSomethingHere() - except: + except CatchableError: let e = getCurrentException() msg = getCurrentExceptionMsg() diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index f81be7a50..e9f76a26f 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1610,7 +1610,7 @@ proc getFootnoteType(label: PRstNode): (FootnoteType, int) = elif label.len == 1 and label.sons[0].kind == rnLeaf: try: result = (fnManualNumber, parseInt(label.sons[0].text)) - except: + except ValueError: result = (fnCitation, -1) else: result = (fnCitation, -1) @@ -2899,13 +2899,13 @@ proc parseEnumList(p: var RstParser): PRstNode = let enumerator = p.tok[p.idx + 1 + wildIndex[w]].symbol # check that it's in sequence: enumerator == next(prevEnum) if "n" in wildcards[w]: # arabic numeral - let prevEnumI = try: parseInt(prevEnum) except: 1 + let prevEnumI = try: parseInt(prevEnum) except ValueError: 1 if enumerator in autoEnums: if prevAE != "" and enumerator != prevAE: break prevAE = enumerator curEnum = prevEnumI + 1 - else: curEnum = (try: parseInt(enumerator) except: 1) + else: curEnum = (try: parseInt(enumerator) except ValueError: 1) if curEnum - prevEnumI != 1: break prevEnum = enumerator diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 6b1300f11..24eab3abb 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -394,10 +394,10 @@ proc entityToRune*(entity: string): Rune = case entity[1] of '0'..'9': try: runeValue = parseInt(entity[1..^1]) - except: discard + except ValueError: discard of 'x', 'X': # not case sensitive here try: runeValue = parseHexInt(entity[2..^1]) - except: discard + except ValueError: discard else: discard # other entities are not defined with prefix `#` if runeValue notin 0..0x10FFFF: runeValue = 0 # only return legal values return Rune(runeValue) diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim index 03bab1b1b..5623ff8ef 100644 --- a/lib/std/assertions.nim +++ b/lib/std/assertions.nim @@ -98,6 +98,7 @@ template doAssertRaises*(exception: typedesc, code: untyped) = const begin = "expected raising '" & astToStr(exception) & "', instead" const msgEnd = " by: " & astToStr(code) template raisedForeign {.gensym.} = raiseAssert(begin & " raised foreign exception" & msgEnd) + {.warning[BareExcept]:off.} when Exception is exception: try: if true: @@ -116,5 +117,6 @@ template doAssertRaises*(exception: typedesc, code: untyped) = mixin `$` # alternatively, we could define $cstring in this module raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd) except: raisedForeign() + {.warning[BareExcept]:on.} if wrong: raiseAssert(begin & " nothing was raised" & msgEnd) diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim index ac7a0e26f..c88d8fa3f 100644 --- a/tests/nimdoc/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -65,7 +65,7 @@ when true: # issue #12746 runnableExamples: try: discard - except: + except CatchableError: # just the general except will work discard From d88f46df388604c1d21a2a95482c3255dc5884b6 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 16 Dec 2022 02:05:34 +1100 Subject: [PATCH 4063/4254] Make async stacktraces less verbose (#21091) * Name iterators something human readable Remove intermediate async procs from stacktraces Clean async traceback message from reraises message * Remove unused import/variable * Fix failing tests Don't add {.stackTrace: off.} to anonymous procs (They already don't appear in stacktrace) * Fix failing tests in pragma category Now check that the nim is a routine type first so we don't run into any assertion defects * Hide stack trace pragma in docs and update doc tests User doesn't need to know if something won't appear so this more becomes verbose noise If this is a bad idea we can always add a `when defined(nimdoc)` switch so we don't add {.stackTrace: off.} to the Future[T] returning proc for docs --- compiler/renderer.nim | 4 +- lib/pure/asyncfutures.nim | 16 ++----- lib/pure/asyncmacro.nim | 16 ++++--- nimdoc/testproject/expected/testproject.html | 11 ++--- tests/async/tasync_gcunsafe.nim | 2 +- tests/async/tasync_traceback.nim | 47 ++++---------------- 6 files changed, 33 insertions(+), 63 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ad74cf2fe..cd0d83eb0 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -619,7 +619,9 @@ proc isHideable(config: ConfigRef, n: PNode): bool = # xxx compare `ident` directly with `getIdent(cache, wRaises)`, but # this requires a `cache`. case n.kind - of nkExprColonExpr: result = n[0].kind == nkIdent and n[0].ident.s in ["raises", "tags", "extern", "deprecated", "forbids"] + of nkExprColonExpr: + result = n[0].kind == nkIdent and + n[0].ident.s.nimIdentNormalize in ["raises", "tags", "extern", "deprecated", "forbids", "stacktrace"] of nkIdent: result = n.ident.s in ["gcsafe", "deprecated"] else: result = false diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 035b6182d..edf5f7277 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -329,29 +329,21 @@ proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string = if leftLen > longestLeft: longestLeft = leftLen - var indent = 2 # Format the entries. for entry in entries: let (filename, procname) = getFilenameProcname(entry) - if procname == "": - if entry.line == reraisedFromBegin: - result.add(spaces(indent) & "#[\n") - indent.inc(2) - elif entry.line == reraisedFromEnd: - indent.dec(2) - result.add(spaces(indent) & "]#\n") - continue + if procname == "" and entry.line == reraisedFromBegin: + break let left = "$#($#)" % [filename, $entry.line] - result.add((spaces(indent) & "$#$# $#\n") % [ + result.add((spaces(2) & "$# $#\n") % [ left, - spaces(longestLeft - left.len + 2), procname ]) let hint = getHint(entry) if hint.len > 0: - result.add(spaces(indent+2) & "## " & hint & "\n") + result.add(spaces(4) & "## " & hint & "\n") proc injectStacktrace[T](future: Future[T]) = when not defined(release): diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index c4f6fd80e..d80a47101 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -20,9 +20,8 @@ proc newCallWithLineInfo(fromNode: NimNode; theProc: NimNode, args: varargs[NimN template createCb(retFutureSym, iteratorNameSym, strName, identName, futureVarCompletions: untyped) = bind finished - var nameIterVar = iteratorNameSym - proc identName {.closure.} = + proc identName {.closure, stackTrace: off.} = try: if not nameIterVar.finished: var next = nameIterVar() @@ -151,6 +150,10 @@ proc asyncSingleProc(prc: NimNode): NimNode = result[0][0] = quote do: Future[void] return result + if prc.kind in RoutineNodes and prc.name.kind != nnkEmpty: + # Only non anonymous functions need/can have stack trace disabled + prc.addPragma(nnkExprColonExpr.newTree(ident"stackTrace", ident"off")) + if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: error("Cannot transform this node kind into an async proc." & " proc/method definition or lambda node expected.", prc) @@ -209,7 +212,7 @@ proc asyncSingleProc(prc: NimNode): NimNode = # -> {.pop.} # -> # -> complete(retFuture, result) - var iteratorNameSym = genSym(nskIterator, $prcName & "Iter") + var iteratorNameSym = genSym(nskIterator, $prcName & " (Async)") var procBody = prc.body.processBody(retFutureSym, futureVarIdents) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: @@ -251,9 +254,10 @@ proc asyncSingleProc(prc: NimNode): NimNode = # friendlier stack traces: var cbName = genSym(nskProc, prcName & NimAsyncContinueSuffix) var procCb = getAst createCb(retFutureSym, iteratorNameSym, - newStrLitNode(prcName), - cbName, - createFutureVarCompletions(futureVarIdents, nil)) + newStrLitNode(prcName), + cbName, + createFutureVarCompletions(futureVarIdents, nil) + ) outerProcBody.add procCb # -> return retFuture diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index b68b721ff..7d10d7900 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -503,7 +503,8 @@
      -
      proc asyncFun1(): Future[int] {....raises: [Exception, ValueError],
      +  
      proc asyncFun1(): Future[int] {....stackTrace: false,
      +                                raises: [Exception, ValueError],
                                       tags: [RootEffect], forbids: [].}
      @@ -515,8 +516,8 @@
      -
      proc asyncFun2(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect],
      -                                        forbids: [].}
      +
      proc asyncFun2(): owned(Future[void]) {....stackTrace: false, raises: [Exception],
      +                                        tags: [RootEffect], forbids: [].}
      @@ -527,8 +528,8 @@
      -
      proc asyncFun3(): owned(Future[void]) {....raises: [Exception], tags: [RootEffect],
      -                                        forbids: [].}
      +
      proc asyncFun3(): owned(Future[void]) {....stackTrace: false, raises: [Exception],
      +                                        tags: [RootEffect], forbids: [].}
      diff --git a/tests/async/tasync_gcunsafe.nim b/tests/async/tasync_gcunsafe.nim index 00c92b109..f3e6bc691 100644 --- a/tests/async/tasync_gcunsafe.nim +++ b/tests/async/tasync_gcunsafe.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'asyncGCUnsafeProc'" + errormsg: "'anotherGCSafeAsyncProc (Async)' is not GC-safe as it calls 'asyncGCUnsafeProc'" cmd: "nim c --threads:on $file" file: "asyncmacro.nim" """ diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim index ec67d34f9..98f71b192 100644 --- a/tests/async/tasync_traceback.nim +++ b/tests/async/tasync_traceback.nim @@ -67,51 +67,22 @@ import re const expected = """ b failure Async traceback: - tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback - asyncmacro\.nim\(\d+?\)\s+?a - asyncmacro\.nim\(\d+?\)\s+?aNimAsyncContinue - ## Resumes an async procedure - tasync_traceback\.nim\(\d+?\)\s+?aIter - asyncmacro\.nim\(\d+?\)\s+?b - asyncmacro\.nim\(\d+?\)\s+?bNimAsyncContinue - ## Resumes an async procedure - tasync_traceback\.nim\(\d+?\)\s+?bIter - #\[ - tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback - asyncmacro\.nim\(\d+?\)\s+?a - asyncmacro\.nim\(\d+?\)\s+?aNimAsyncContinue - ## Resumes an async procedure - asyncmacro\.nim\(\d+?\)\s+?aIter - asyncfutures\.nim\(\d+?\)\s+?read - \]# + tasync_traceback\.nim\(\d+?\) tasync_traceback + tasync_traceback\.nim\(\d+?\) a \(Async\) + tasync_traceback\.nim\(\d+?\) b \(Async\) Exception message: b failure bar failure Async traceback: - tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback - asyncdispatch\.nim\(\d+?\)\s+?waitFor - asyncdispatch\.nim\(\d+?\)\s+?poll + tasync_traceback\.nim\(\d+?\) tasync_traceback + asyncdispatch\.nim\(\d+?\) waitFor + asyncdispatch\.nim\(\d+?\) poll ## Processes asynchronous completion events - asyncdispatch\.nim\(\d+?\)\s+?runOnce - asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks + asyncdispatch\.nim\(\d+?\) runOnce + asyncdispatch\.nim\(\d+?\) processPendingCallbacks ## Executes pending callbacks - asyncmacro\.nim\(\d+?\)\s+?barNimAsyncContinue - ## Resumes an async procedure - tasync_traceback\.nim\(\d+?\)\s+?barIter - #\[ - tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback - asyncdispatch\.nim\(\d+?\)\s+?waitFor - asyncdispatch\.nim\(\d+?\)\s+?poll - ## Processes asynchronous completion events - asyncdispatch\.nim\(\d+?\)\s+?runOnce - asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks - ## Executes pending callbacks - asyncmacro\.nim\(\d+?\)\s+?fooNimAsyncContinue - ## Resumes an async procedure - asyncmacro\.nim\(\d+?\)\s+?fooIter - asyncfutures\.nim\(\d+?\)\s+?read - \]# + tasync_traceback\.nim\(\d+?\) bar \(Async\) Exception message: bar failure """ From 8054be6e529db9e65a18e4c4a37ec54f64f9121c Mon Sep 17 00:00:00 2001 From: Bung Date: Thu, 15 Dec 2022 23:12:17 +0800 Subject: [PATCH 4064/4254] fix #20588 (#21104) --- compiler/semexprs.nim | 2 ++ tests/arc/t20588.nim | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/arc/t20588.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2efa1259a..8ac8f4750 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -319,6 +319,8 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = return evaluated else: targetType = targetType.base + of tyAnything, tyUntyped, tyTyped: + localError(c.config, n.info, "illegal type conversion to '$1'" % typeToString(targetType)) else: discard maybeLiftType(targetType, c, n[0].info) diff --git a/tests/arc/t20588.nim b/tests/arc/t20588.nim new file mode 100644 index 000000000..d747c656d --- /dev/null +++ b/tests/arc/t20588.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim check --warnings:off --hints:off $file" + errormsg: "" + nimout: ''' +t20588.nim(20, 12) Error: illegal type conversion to 'auto' +t20588.nim(21, 14) Error: illegal type conversion to 'typed' +t20588.nim(22, 16) Error: illegal type conversion to 'untyped' +''' +""" + + + + + + + + + + +discard 0.0.auto +discard typed("abc") +discard untyped(4) From d00477dffb2c62732b87a440c61706de5b480f48 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 16 Dec 2022 05:22:45 +1100 Subject: [PATCH 4065/4254] Check file exists in `{.compile.}` pragma (#21105) * Add test * Check file exists before adding it into compilation * Make error message look like other error messages i.e. following the format `error msg: file` --- compiler/pragmas.nim | 7 +++++-- tests/pragmas/tcompile_missing_file.nim | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 tests/pragmas/tcompile_missing_file.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 993e6edce..92e3d1922 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -513,8 +513,11 @@ proc processCompile(c: PContext, n: PNode) = var cf = Cfile(nimname: splitFile(src).name, cname: src, obj: dest, flags: {CfileFlag.External}, customArgs: customArgs) - extccomp.addExternalFileToCompile(c.config, cf) - recordPragma(c, it, "compile", src.string, dest.string, customArgs) + if not fileExists(src): + localError(c.config, n.info, "cannot find: " & src.string) + else: + extccomp.addExternalFileToCompile(c.config, cf) + recordPragma(c, it, "compile", src.string, dest.string, customArgs) proc getStrLit(c: PContext, n: PNode; i: int): string = n[i] = c.semConstExpr(c, n[i]) diff --git a/tests/pragmas/tcompile_missing_file.nim b/tests/pragmas/tcompile_missing_file.nim new file mode 100644 index 000000000..fd90bd57d --- /dev/null +++ b/tests/pragmas/tcompile_missing_file.nim @@ -0,0 +1,5 @@ +discard """ + joinable: false + errormsg: "cannot find: noexist.c" +""" +{.compile: "noexist.c".} From 78b68421da0a678deb0c17cd03345d62410dbeac Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 16 Dec 2022 11:36:52 +0800 Subject: [PATCH 4066/4254] fixes chronicles (#21114) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d0c87919b..c134be6f9 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -51,7 +51,7 @@ pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" pkg "cello", url = "https://github.com/nim-lang/cello", useHead = true pkg "chroma" -pkg "chronicles", "nimble install -y stew@#head; nim c -o:chr -r chronicles.nim" +pkg "chronicles", "nim c -o:chr -r chronicles.nim", url = "https://github.com/nim-lang/nim-chronicles" pkg "chronos", "nim c -r -d:release tests/testall", url = "https://github.com/nim-lang/nim-chronos" pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" From 644318ad9cbf079f33d8d7b6c5ead4a4429adb3e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 16 Dec 2022 14:58:40 +0800 Subject: [PATCH 4067/4254] the devel branch now uses csources_v2 (#21108) * the devel branch now uses csources_v2 * fixes hash * bump csources_v2 --- .gitignore | 1 + config/build_config.txt | 6 +++--- nim.nimble | 2 +- readme.md | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index d228b498c..d0c4558df 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ testament.db /csources /csources_v1 +/csources_v2 /dist/ # /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it diff --git a/config/build_config.txt b/config/build_config.txt index 15f44bb57..3ae618f00 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -1,5 +1,5 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" -nim_csourcesDir=csources_v1 -nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git +nim_csourcesDir=csources_v2 +nim_csourcesUrl=https://github.com/nim-lang/csources_v2.git nim_csourcesBranch=master -nim_csourcesHash=561b417c65791cd8356b5f73620914ceff845d10 +nim_csourcesHash=ffd834c20915dc04c78eb0d3b2162832e7ec9c13 diff --git a/nim.nimble b/nim.nimble index a629c0e04..5d1be49b1 100644 --- a/nim.nimble +++ b/nim.nimble @@ -5,7 +5,7 @@ license = "MIT" bin = @["compiler/nim", "nimsuggest/nimsuggest"] skipFiles = @["azure-pipelines.yml" , "build_all.bat" , "build_all.sh" , "build_nimble.bat" , "build_nimble.sh" , "changelog.md" , "koch.nim.cfg" , "nimblemeta.json" , "readme.md" , "security.md" ] -skipDirs = @["build" , "changelogs" , "ci" , "csources_v1" , "drnim" , "nimdoc", "testament"] +skipDirs = @["build" , "changelogs" , "ci" , "csources_v2" , "drnim" , "nimdoc", "testament"] before install: when defined(windows): diff --git a/readme.md b/readme.md index 3d32bcf87..a0f47eb41 100644 --- a/readme.md +++ b/readme.md @@ -47,7 +47,7 @@ Compiling the Nim compiler is quite straightforward if you follow these steps: First, the C source of an older version of the Nim compiler is needed to bootstrap the latest version because the Nim compiler itself is written in the Nim programming language. Those C sources are available within the -[``nim-lang/csources_v1``][csources-v1-repo] repository. +[``nim-lang/csources_v2``][csources-v2-repo] repository. Next, to build from source you will need: @@ -223,7 +223,7 @@ Copyright © 2006-2022 Andreas Rumpf, all rights reserved. [nimble-repo]: https://github.com/nim-lang/nimble [nimsuggest-repo]: https://github.com/nim-lang/nimsuggest [csources-repo-deprecated]: https://github.com/nim-lang/csources -[csources-v1-repo]: https://github.com/nim-lang/csources_v1 +[csources-v2-repo]: https://github.com/nim-lang/csources_v2 [badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square [badge-nim-discord]: https://img.shields.io/discord/371759389889003530?color=blue&label=discord&logo=discord&logoColor=gold&style=flat-square [badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square From 8a3b76b28733a87e5cffa3f4b7b99d76f13ee2ba Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 16 Dec 2022 14:59:18 +0800 Subject: [PATCH 4068/4254] csource building prefers `bin/nim` (#21115) --- tools/niminst/niminst.nim | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index cd2e5a481..bc763a56f 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -515,6 +515,17 @@ template gatherFiles(fun, libpath, outDir) = # commenting out for now, see discussion in https://github.com/nim-lang/Nim/pull/13413 # copySrc(libpath / "lib/wrappers/linenoise/linenoise.h") +proc exe(f: string): string = + result = addFileExt(f, ExeExt) + when defined(windows): + result = result.replace('/','\\') + +proc findNim(): string = + let nim = "nim".exe + result = quoteShell("bin" / nim) + if not fileExists(result): + result = "nim" + proc srcdist(c: var ConfigData) = let cCodeDir = getOutputDir(c) / "c_code" if not dirExists(cCodeDir): createDir(cCodeDir) @@ -533,10 +544,10 @@ proc srcdist(c: var ConfigData) = var dir = getOutputDir(c) / buildDir(osA, cpuA) if dirExists(dir): removeDir(dir) createDir(dir) - var cmd = ("nim compile -f --symbolfiles:off --compileonly " & + var cmd = ("$# compile -f --symbolfiles:off --compileonly " & "--gen_mapping --cc:gcc --skipUserCfg" & " --os:$# --cpu:$# $# $#") % - [osname, cpuname, c.nimArgs, c.mainfile] + [findNim(), osname, cpuname, c.nimArgs, c.mainfile] echo(cmd) if execShellCmd(cmd) != 0: quit("Error: call to nim compiler failed") From a9bd78d579168ba50f42d3bc418cd7de70a226f9 Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 16 Dec 2022 15:01:15 +0800 Subject: [PATCH 4069/4254] fix #12122 (#21096) --- compiler/astalgo.nim | 2 +- compiler/evalffi.nim | 8 ++-- lib/core/typeinfo.nim | 4 +- lib/pure/coro.nim | 4 +- lib/pure/memfiles.nim | 8 ++-- lib/pure/oids.nim | 4 +- lib/pure/strutils.nim | 4 +- lib/std/envvars.nim | 2 +- lib/std/private/strimpl.nim | 4 +- lib/std/syncio.nim | 2 +- lib/system/alloc.nim | 70 ++++++++++++++++----------------- lib/system/assign.nim | 28 ++++++------- lib/system/channels_builtin.nim | 12 +++--- lib/system/ctypes.nim | 2 +- lib/system/deepcopy.nim | 16 ++++---- lib/system/gc.nim | 24 +++++------ lib/system/gc2.nim | 22 +++++------ lib/system/gc_common.nim | 24 +++++------ lib/system/gc_ms.nim | 18 ++++----- lib/system/osalloc.nim | 6 +-- lib/system/repr.nim | 10 ++--- lib/system/sysstr.nim | 4 +- tests/parallel/tguard1.nim | 2 +- 23 files changed, 140 insertions(+), 140 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 28c38129e..e9ed1497a 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -333,7 +333,7 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int, sonsRope = rope("null") elif containsOrIncl(marker, n.id): sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope( - strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))] + strutils.toHex(cast[int](n), sizeof(n) * 2))] else: if n.len > 0: sonsRope = rope("[") diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 37edef86c..0577619b8 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -77,7 +77,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode = theAddr = dllhandle.symAddr(name.cstring) if theAddr.isNil: globalError(conf, sym.info, "cannot import symbol: " & name & " from " & libPathMsg) - result.intVal = cast[ByteAddress](theAddr) + result.intVal = cast[int](theAddr) proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = if t == nil: return addr libffi.type_void @@ -113,7 +113,7 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[] template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v template `+!`(x, y: untyped): untyped = - cast[pointer](cast[ByteAddress](x) + y) + cast[pointer](cast[int](x) + y) proc packSize(conf: ConfigRef, v: PNode, typ: PType): int = ## computes the size of the blob @@ -369,13 +369,13 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = # in their unboxed representation so nothing it to be unpacked: result = n else: - awi(nkPtrLit, cast[ByteAddress](p)) + awi(nkPtrLit, cast[int](p)) of tyPtr, tyRef, tyVar, tyLent: let p = rd(pointer, x) if p.isNil: setNil() elif n == nil or n.kind == nkPtrLit: - awi(nkPtrLit, cast[ByteAddress](p)) + awi(nkPtrLit, cast[int](p)) elif n != nil and n.len == 1: internalAssert(conf, n.kind == nkRefTy) n[0] = unpack(conf, p, typ.lastSon, n[0]) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 89b1deb31..5075c8458 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -132,12 +132,12 @@ else: proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. importCompilerProc.} -template `+!!`(a, b): untyped = cast[pointer](cast[ByteAddress](a) + b) +template `+!!`(a, b): untyped = cast[pointer](cast[int](a) + b) proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = assert(n.kind == nkCase) var d: int - let a = cast[ByteAddress](aa) + let a = cast[int](aa) case n.typ.size of 1: d = int(cast[ptr uint8](a +% n.offset)[]) of 2: d = int(cast[ptr uint16](a +% n.offset)[]) diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 47dfdd791..3b9bba59b 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -281,8 +281,8 @@ proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discar (proc(p: pointer) {.stdcall.} = runCurrentTask()), nil) else: coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine) + stacksize)) - coro.stack.top = cast[pointer](cast[ByteAddress](coro) + sizeof(Coroutine)) - coro.stack.bottom = cast[pointer](cast[ByteAddress](coro.stack.top) + stacksize) + coro.stack.top = cast[pointer](cast[int](coro) + sizeof(Coroutine)) + coro.stack.bottom = cast[pointer](cast[int](coro.stack.top) + stacksize) when coroBackend == CORO_BACKEND_UCONTEXT: discard getcontext(coro.execContext) coro.execContext.uc_stack.ss_sp = coro.stack.top diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 48c07b149..9ff8bcd74 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -495,8 +495,8 @@ proc mmsSetPosition(s: Stream, pos: int) = proc mmsGetPosition(s: Stream): int = MemMapFileStream(s).pos proc mmsPeekData(s: Stream, buffer: pointer, bufLen: int): int = - let startAddress = cast[ByteAddress](MemMapFileStream(s).mf.mem) - let p = cast[ByteAddress](MemMapFileStream(s).pos) + let startAddress = cast[int](MemMapFileStream(s).mf.mem) + let p = cast[int](MemMapFileStream(s).pos) let l = min(bufLen, MemMapFileStream(s).mf.size - p) moveMem(buffer, cast[pointer](startAddress + p), l) result = l @@ -511,8 +511,8 @@ proc mmsWriteData(s: Stream, buffer: pointer, bufLen: int) = let size = MemMapFileStream(s).mf.size if MemMapFileStream(s).pos + bufLen > size: raise newEIO("cannot write to stream") - let p = cast[ByteAddress](MemMapFileStream(s).mf.mem) + - cast[ByteAddress](MemMapFileStream(s).pos) + let p = cast[int](MemMapFileStream(s).mf.mem) + + cast[int](MemMapFileStream(s).pos) moveMem(cast[pointer](p), buffer, bufLen) inc(MemMapFileStream(s).pos, bufLen) diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index e6e5e6e56..ad8eeefd7 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -44,7 +44,7 @@ proc hexbyte*(hex: char): int {.inline.} = proc parseOid*(str: cstring): Oid = ## Parses an OID. - var bytes = cast[cstring](cast[pointer](cast[ByteAddress](addr(result.time)) + 4)) + var bytes = cast[cstring](cast[pointer](cast[int](addr(result.time)) + 4)) var i = 0 while i < 12: bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1])) @@ -57,7 +57,7 @@ proc `$`*(oid: Oid): string = result.setLen 24 var o = oid - var bytes = cast[cstring](cast[pointer](cast[ByteAddress](addr(o)) + 4)) + var bytes = cast[cstring](cast[pointer](cast[int](addr(o)) + 4)) var i = 0 while i < 12: let b = bytes[i].ord diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 0367ea1e5..f628cfc2d 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1914,7 +1914,7 @@ func find*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, if length > 0: let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](length)) if not found.isNil: - return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) + return cast[int](found) -% cast[int](s.cstring) else: findImpl() @@ -1970,7 +1970,7 @@ func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, if last < 0 and start < s.len and subLen != 0: let found = memmem(s[start].unsafeAddr, csize_t(s.len - start), sub.cstring, csize_t(subLen)) result = if not found.isNil: - cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) + cast[int](found) -% cast[int](s.cstring) else: -1 else: diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim index 46595a3cf..817a155ec 100644 --- a/lib/std/envvars.nim +++ b/lib/std/envvars.nim @@ -183,7 +183,7 @@ when not defined(nimscript): let kv = $e let p = find(kv, '=') yield (substr(kv, 0, p-1), substr(kv, p+1)) - e = cast[typ](cast[ByteAddress](eend)+size) + e = cast[typ](cast[int](eend)+size) if typeof(zero)(eend[1]) == zero: break discard free_fun(env) impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW) diff --git a/lib/std/private/strimpl.nim b/lib/std/private/strimpl.nim index 6a38cbfd2..f8c9236a5 100644 --- a/lib/std/private/strimpl.nim +++ b/lib/std/private/strimpl.nim @@ -93,7 +93,7 @@ func find*(s: cstring, sub: char, start: Natural = 0, last = 0): int = if L > 0: let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](L)) if not found.isNil: - return cast[ByteAddress](found) -% cast[ByteAddress](s) + return cast[int](found) -% cast[int](s) return -1 func find*(s, sub: cstring, start: Natural = 0, last = 0): int = @@ -108,6 +108,6 @@ func find*(s, sub: cstring, start: Natural = 0, last = 0): int = if last == 0 and s.len > start: let found = c_strstr(cast[cstring](s[start].unsafeAddr), sub) if not found.isNil: - result = cast[ByteAddress](found) -% cast[ByteAddress](s) + result = cast[int](found) -% cast[int](s) else: result = -1 diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index 2b5ea6a3c..46f113450 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -480,7 +480,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], let m = c_memchr(addr line[pos], '\L'.ord, cast[csize_t](sp)) if m != nil: # \l found: Could be our own or the one by fgets, in any case, we're done - var last = cast[ByteAddress](m) - cast[ByteAddress](addr line[0]) + var last = cast[int](m) - cast[int](addr line[0]) if last > 0 and line[last-1] == '\c': line.setLen(last-1) return last > 1 or fgetsSuccess diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index a7db3704b..5d1548977 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -290,7 +290,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer = a.llmem.size = PageSize - sizeof(LLChunk) a.llmem.acc = sizeof(LLChunk) a.llmem.next = old - result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc) + result = cast[pointer](cast[int](a.llmem) + a.llmem.acc) dec(a.llmem.size, size) inc(a.llmem.acc, size) zeroMem(result, size) @@ -422,7 +422,7 @@ iterator allObjects(m: var MemRegion): pointer {.inline.} = var c = cast[PSmallChunk](c) let size = c.size - var a = cast[ByteAddress](addr(c.data)) + var a = cast[int](addr(c.data)) let limit = a + c.acc while a <% limit: yield cast[pointer](a) @@ -441,13 +441,13 @@ when not defined(gcDestructors): # ------------- chunk management ---------------------------------------------- proc pageIndex(c: PChunk): int {.inline.} = - result = cast[ByteAddress](c) shr PageShift + result = cast[int](c) shr PageShift proc pageIndex(p: pointer): int {.inline.} = - result = cast[ByteAddress](p) shr PageShift + result = cast[int](p) shr PageShift proc pageAddr(p: pointer): PChunk {.inline.} = - result = cast[PChunk](cast[ByteAddress](p) and not PageMask) + result = cast[PChunk](cast[int](p) and not PageMask) #sysAssert(Contains(allocator.chunkStarts, pageIndex(result))) when false: @@ -495,13 +495,13 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = when defined(memtracker): trackLocation(addr result.size, sizeof(int)) - sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1") + sysAssert((cast[int](result) and PageMask) == 0, "requestOsChunks 1") #zeroMem(result, size) result.next = nil result.prev = nil result.size = size # update next.prevSize: - var nxt = cast[ByteAddress](result) +% size + var nxt = cast[int](result) +% size sysAssert((nxt and PageMask) == 0, "requestOsChunks 2") var next = cast[PChunk](nxt) if pageIndex(next) in a.chunkStarts: @@ -509,7 +509,7 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = next.prevSize = size or (next.prevSize and 1) # set result.prevSize: var lastSize = if a.lastSize != 0: a.lastSize else: PageSize - var prv = cast[ByteAddress](result) -% lastSize + var prv = cast[int](result) -% lastSize sysAssert((nxt and PageMask) == 0, "requestOsChunks 3") var prev = cast[PChunk](prv) if pageIndex(prev) in a.chunkStarts and prev.size == lastSize: @@ -555,13 +555,13 @@ proc listRemove[T](head: var T, c: T) {.inline.} = proc updatePrevSize(a: var MemRegion, c: PBigChunk, prevSize: int) {.inline.} = - var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) - sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize") + var ri = cast[PChunk](cast[int](c) +% c.size) + sysAssert((cast[int](ri) and PageMask) == 0, "updatePrevSize") if isAccessible(a, ri): ri.prevSize = prevSize or (ri.prevSize and 1) proc splitChunk2(a: var MemRegion, c: PBigChunk, size: int): PBigChunk = - result = cast[PBigChunk](cast[ByteAddress](c) +% size) + result = cast[PBigChunk](cast[int](c) +% size) result.size = c.size - size track("result.size", addr result.size, sizeof(int)) when not defined(nimOptimizedSplitChunk): @@ -590,8 +590,8 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = when coalescLeft: let prevSize = c.prevSize if prevSize != 0: - var le = cast[PChunk](cast[ByteAddress](c) -% prevSize) - sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4") + var le = cast[PChunk](cast[int](c) -% prevSize) + sysAssert((cast[int](le) and PageMask) == 0, "freeBigChunk 4") if isAccessible(a, le) and chunkUnused(le): sysAssert(not isSmallChunk(le), "freeBigChunk 5") if not isSmallChunk(le) and le.size < MaxBigChunkSize: @@ -607,8 +607,8 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = addChunkToMatrix(a, c) c = rest when coalescRight: - var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) - sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "freeBigChunk 2") + var ri = cast[PChunk](cast[int](c) +% c.size) + sysAssert((cast[int](ri) and PageMask) == 0, "freeBigChunk 2") if isAccessible(a, ri) and chunkUnused(ri): sysAssert(not isSmallChunk(ri), "freeBigChunk 3") if not isSmallChunk(ri) and c.size < MaxBigChunkSize: @@ -669,7 +669,7 @@ proc getHugeChunk(a: var MemRegion; size: int): PBigChunk = incCurrMem(a, size) # XXX add this to the heap links. But also remove it from it later. when false: a.addHeapLink(result, size) - sysAssert((cast[ByteAddress](result) and PageMask) == 0, "getHugeChunk") + sysAssert((cast[int](result) and PageMask) == 0, "getHugeChunk") result.next = nil result.prev = nil result.size = size @@ -838,7 +838,7 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = c.prev = nil listAdd(a.freeSmallChunks[s], c) result = addr(c.data) - sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4") + sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 4") else: sysAssert(allocInv(a), "rawAlloc: begin c != nil") sysAssert c.next != c, "rawAlloc 5" @@ -856,7 +856,7 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = if c.freeList == nil: sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, "rawAlloc 7") - result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc) + result = cast[pointer](cast[int](addr(c.data)) +% c.acc) inc(c.acc, size) else: result = c.freeList @@ -864,14 +864,14 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert(c.freeList.zeroField == 0, "rawAlloc 8") c.freeList = c.freeList.next dec(c.free, size) - sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9") + sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 9") sysAssert(allocInv(a), "rawAlloc: end c != nil") sysAssert(allocInv(a), "rawAlloc: before c.free < size") if c.free < size: sysAssert(allocInv(a), "rawAlloc: before listRemove test") listRemove(a.freeSmallChunks[s], c) sysAssert(allocInv(a), "rawAlloc: end listRemove test") - sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[int](result) and PageMask) - smallChunkOverhead()) %% size == 0, "rawAlloc 21") sysAssert(allocInv(a), "rawAlloc: end small size") inc a.occ, size @@ -893,11 +893,11 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert c.prev == nil, "rawAlloc 10" sysAssert c.next == nil, "rawAlloc 11" result = addr(c.data) - sysAssert((cast[ByteAddress](c) and (MemAlign-1)) == 0, "rawAlloc 13") - sysAssert((cast[ByteAddress](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary") + sysAssert((cast[int](c) and (MemAlign-1)) == 0, "rawAlloc 13") + sysAssert((cast[int](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary") when not defined(gcDestructors): if a.root == nil: a.root = getBottom(a) - add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size) + add(a, a.root, cast[int](result), cast[int](result)+%size) inc a.occ, c.size trackSize(c.size) sysAssert(isAccessible(a, result), "rawAlloc 14") @@ -927,10 +927,10 @@ proc rawDealloc(a: var MemRegion, p: pointer) = dec a.occ, s untrackSize(s) sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case A)" - sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %% s == 0, "rawDealloc 3") when not defined(gcDestructors): - #echo("setting to nil: ", $cast[ByteAddress](addr(f.zeroField))) + #echo("setting to nil: ", $cast[int](addr(f.zeroField))) sysAssert(f.zeroField != 0, "rawDealloc 1") f.zeroField = 0 f.next = c.freeList @@ -953,7 +953,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) = else: when defined(gcDestructors): addToSharedFreeList(c, f) - sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %% s == 0, "rawDealloc 2") else: # set to 0xff to check for usage after free bugs: @@ -975,7 +975,7 @@ when not defined(gcDestructors): if not chunkUnused(c): if isSmallChunk(c): var c = cast[PSmallChunk](c) - var offset = (cast[ByteAddress](p) and (PageSize-1)) -% + var offset = (cast[int](p) and (PageSize-1)) -% smallChunkOverhead() result = (c.acc >% offset) and (offset %% c.size == 0) and (cast[ptr FreeCell](p).zeroField >% 1) @@ -993,12 +993,12 @@ when not defined(gcDestructors): if not chunkUnused(c): if isSmallChunk(c): var c = cast[PSmallChunk](c) - var offset = (cast[ByteAddress](p) and (PageSize-1)) -% + var offset = (cast[int](p) and (PageSize-1)) -% smallChunkOverhead() if c.acc >% offset: - sysAssert(cast[ByteAddress](addr(c.data)) +% offset == - cast[ByteAddress](p), "offset is not what you think it is") - var d = cast[ptr FreeCell](cast[ByteAddress](addr(c.data)) +% + sysAssert(cast[int](addr(c.data)) +% offset == + cast[int](p), "offset is not what you think it is") + var d = cast[ptr FreeCell](cast[int](addr(c.data)) +% offset -% (offset %% c.size)) if d.zeroField >% 1: result = d @@ -1025,7 +1025,7 @@ when not defined(gcDestructors): proc ptrSize(p: pointer): int = when not defined(gcDestructors): - var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell)) + var x = cast[pointer](cast[int](p) -% sizeof(FreeCell)) var c = pageAddr(p) sysAssert(not chunkUnused(c), "ptrSize") result = c.size -% sizeof(FreeCell) @@ -1043,7 +1043,7 @@ proc alloc(allocator: var MemRegion, size: Natural): pointer {.gcsafe.} = result = rawAlloc(allocator, size+sizeof(FreeCell)) cast[ptr FreeCell](result).zeroField = 1 # mark it as used sysAssert(not isAllocatedPtr(allocator, result), "alloc") - result = cast[pointer](cast[ByteAddress](result) +% sizeof(FreeCell)) + result = cast[pointer](cast[int](result) +% sizeof(FreeCell)) track("alloc", result, size) else: result = rawAlloc(allocator, size) @@ -1055,7 +1055,7 @@ proc alloc0(allocator: var MemRegion, size: Natural): pointer = proc dealloc(allocator: var MemRegion, p: pointer) = when not defined(gcDestructors): sysAssert(p != nil, "dealloc: p is nil") - var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell)) + var x = cast[pointer](cast[int](p) -% sizeof(FreeCell)) sysAssert(x != nil, "dealloc: x is nil") sysAssert(isAccessible(allocator, x), "is not accessible") sysAssert(cast[ptr FreeCell](x).zeroField == 1, "dealloc: object header corrupted") @@ -1116,7 +1116,7 @@ template instantiateForRegion(allocator: untyped) {.dirty.} = result = interiorAllocatedPtr(allocator, p) proc isAllocatedPtr*(p: pointer): bool = - let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(Cell))) + let p = cast[pointer](cast[int](p)-%ByteAddress(sizeof(Cell))) result = isAllocatedPtr(allocator, p) proc deallocOsPages = deallocOsPages(allocator) diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 20b854107..42587929c 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -15,8 +15,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign. proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, shallow: bool) {.benign.} = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) case n.kind of nkSlot: genericAssignAux(cast[pointer](d +% n.offset), @@ -56,8 +56,8 @@ template deepSeqAssignImpl(operation, additionalArg) {.dirty.} = proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) sysAssert(mt != nil, "genericAssignAux 2") case mt.kind of tyString: @@ -89,17 +89,17 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var ss = nimNewSeqOfCap(mt, seq.len) cast[PGenericSeq](ss).len = seq.len unsureAsgnRef(x, ss) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) + var dst = cast[int](cast[PPointer](dest)[]) copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)), + cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align)), seq.len *% mt.base.size) else: unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) + var dst = cast[int](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericAssignAux( cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), + cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ), mt.base, shallow) of tyObject: var it = mt.base @@ -181,15 +181,15 @@ proc genericSeqAssign(dest, src: pointer, mt: PNimType) {.compilerproc.} = proc genericAssignOpenArray(dest, src: pointer, len: int, mt: PNimType) {.compilerproc.} = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) for i in 0..len-1: genericAssign(cast[pointer](d +% i *% mt.base.size), cast[pointer](s +% i *% mt.base.size), mt.base) proc objectInit(dest: pointer, typ: PNimType) {.compilerproc, benign.} proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) case n.kind of nkNone: sysAssert(false, "objectInitAux") of nkSlot: objectInit(cast[pointer](d +% n.offset), n.typ) @@ -203,7 +203,7 @@ proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} = proc objectInit(dest: pointer, typ: PNimType) = # the generic init proc that takes care of initialization of complex # objects on the stack or heap - var d = cast[ByteAddress](dest) + var d = cast[int](dest) case typ.kind of tyObject: # iterate over any structural type @@ -226,7 +226,7 @@ proc objectInit(dest: pointer, typ: PNimType) = proc genericReset(dest: pointer, mt: PNimType) {.compilerproc, benign.} proc genericResetAux(dest: pointer, n: ptr TNimNode) = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) case n.kind of nkNone: sysAssert(false, "genericResetAux") of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ) @@ -238,7 +238,7 @@ proc genericResetAux(dest: pointer, n: ptr TNimNode) = zeroMem(cast[pointer](d +% n.offset), n.typ.size) proc genericReset(dest: pointer, mt: PNimType) = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) sysAssert(mt != nil, "genericReset 2") case mt.kind of tyRef: diff --git a/lib/system/channels_builtin.nim b/lib/system/channels_builtin.nim index fbe3f0e98..e04f2a0db 100644 --- a/lib/system/channels_builtin.nim +++ b/lib/system/channels_builtin.nim @@ -185,8 +185,8 @@ when not usesDestructors: proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, mode: LoadStoreMode) {.benign.} = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) case n.kind of nkSlot: storeAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), n.typ, t, mode) @@ -205,8 +205,8 @@ when not usesDestructors: cast[pointer](cast[int](p) +% x) var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) sysAssert(mt != nil, "mt == nil") case mt.kind of tyString: @@ -245,14 +245,14 @@ when not usesDestructors: x[] = alloc0(t.region, align(GenericSeqSize, mt.base.align) +% seq.len *% mt.base.size) else: unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) + var dst = cast[int](cast[PPointer](dest)[]) var dstseq = cast[PGenericSeq](dst) dstseq.len = seq.len dstseq.reserved = seq.len for i in 0..seq.len-1: storeAux( cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% + cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), mt.base, t, mode) if mode != mStore: dealloc(t.region, s2) diff --git a/lib/system/ctypes.nim b/lib/system/ctypes.nim index 6ba28ed49..f6a341477 100644 --- a/lib/system/ctypes.nim +++ b/lib/system/ctypes.nim @@ -67,7 +67,7 @@ type # these work for most platforms: ## This is the same as the type `unsigned long long` in *C*. type - ByteAddress* = int + ByteAddress* {.deprecated: "use `uint`".} = int ## is the signed integer type that should be used for converting ## pointers to integer addresses for readability. diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 1f30b8427..72d35f518 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -61,8 +61,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode; tab: var PtrTable) {.benign.} = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) case n.kind of nkSlot: genericDeepCopyAux(cast[pointer](d +% n.offset), @@ -85,8 +85,8 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode; proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) sysAssert(mt != nil, "genericDeepCopyAux 2") case mt.kind of tyString: @@ -113,11 +113,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = return sysAssert(dest != nil, "genericDeepCopyAux 3") unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[ByteAddress](cast[PPointer](dest)[]) + var dst = cast[int](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericDeepCopyAux( cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), - cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), + cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), mt.base, tab) of tyObject: # we need to copy m_type field for tyObject, as it could be empty for @@ -199,8 +199,8 @@ proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = proc genericDeepCopyOpenArray(dest, src: pointer, len: int, mt: PNimType) {.compilerproc.} = var - d = cast[ByteAddress](dest) - s = cast[ByteAddress](src) + d = cast[int](dest) + s = cast[int](src) for i in 0..len-1: genericDeepCopy(cast[pointer](d +% i *% mt.base.size), cast[pointer](s +% i *% mt.base.size), mt.base) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index b36822aad..7db2b6567 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -170,11 +170,11 @@ proc addZCT(s: var CellSeq, c: PCell) {.noinline.} = proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) + result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) + result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging @@ -336,7 +336,7 @@ proc cellsetReset(s: var CellSet) = {.push stacktrace:off.} proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -356,7 +356,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -382,7 +382,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[ByteAddress](cellToUsr(cell)) + var d = cast[int](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: @@ -457,7 +457,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = collectCT(gch) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) #gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small" - gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ setFrameInfo(res) @@ -507,7 +507,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} = var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc") - sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + sysAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ setFrameInfo(res) @@ -549,9 +549,9 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len * elemSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[int](res) +% oldsize +% sizeof(Cell)), newsize-oldsize) - sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") # This can be wrong for intermediate temps that are nevertheless on the # heap because of lambda lifting: #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4") @@ -683,7 +683,7 @@ proc collectCycles(gch: var GcHeap) {.raises: [].} = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: sysAssert(allocInv(gch.region), "gcMark begin") - var c = cast[ByteAddress](p) + var c = cast[int](p) if c >% PageSize: # fast check: does it look like a cell? var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p)) @@ -848,10 +848,10 @@ when withRealTime: stack.bottomSaved = stack.bottom when stackIncreases: stack.bottom = cast[pointer]( - cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize) + cast[int](stack.pos) - sizeof(pointer) * 6 - stackSize) else: stack.bottom = cast[pointer]( - cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize) + cast[int](stack.pos) + sizeof(pointer) * 6 + stackSize) GC_step(gch, us, strongAdvice) diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index 0593b396e..ed046b5fd 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -133,11 +133,11 @@ template gcAssert(cond: bool, msg: string) = proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) + result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) + result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging @@ -252,7 +252,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc.} = dest[] = src proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -264,7 +264,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -290,7 +290,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[ByteAddress](cellToUsr(cell)) + var d = cast[int](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: @@ -330,7 +330,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) - gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -388,9 +388,9 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[int](res)+% oldsize +% sizeof(Cell)), newsize-oldsize) - sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") when false: # this is wrong since seqs can be shared via 'shallow': when reallyDealloc: rawDealloc(gch.region, ol) @@ -593,7 +593,7 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: sysAssert(allocInv(gch.region), "gcMark begin") var cell = usrToCell(p) - var c = cast[ByteAddress](cell) + var c = cast[int](cell) if c >% PageSize: # fast check: does it look like a cell? var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) @@ -697,10 +697,10 @@ when withRealTime: stack.bottomSaved = stack.bottom when stackIncreases: stack.bottom = cast[pointer]( - cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize) + cast[int](stack.pos) - sizeof(pointer) * 6 - stackSize) else: stack.bottom = cast[pointer]( - cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize) + cast[int](stack.pos) + sizeof(pointer) * 6 + stackSize) GC_step(gch, us, strongAdvice) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index f5f4f164f..54c51e783 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -222,9 +222,9 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} = if pos != nil: when stackIncreases: - result = cast[ByteAddress](pos) -% cast[ByteAddress](stack.bottom) + result = cast[int](pos) -% cast[int](stack.bottom) else: - result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](pos) + result = cast[int](stack.bottom) -% cast[int](pos) else: result = 0 @@ -295,8 +295,8 @@ when not defined(useNimRtl): # the first init must be the one that defines the stack bottom: gch.stack.bottom = theStackBottom elif theStackBottom != gch.stack.bottom: - var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2 - var b = cast[ByteAddress](gch.stack.bottom) + var a = cast[int](theStackBottom) # and not PageMask - PageSize*2 + var b = cast[int](gch.stack.bottom) #c_fprintf(stdout, "old: %p new: %p;\n",gch.stack.bottom,theStackBottom) when stackIncreases: gch.stack.bottom = cast[pointer](min(a, b)) @@ -312,11 +312,11 @@ when not defined(useNimRtl): proc isOnStack(p: pointer): bool = var stackTop {.volatile, noinit.}: pointer stackTop = addr(stackTop) - var a = cast[ByteAddress](gch.getActiveStack().bottom) - var b = cast[ByteAddress](stackTop) + var a = cast[int](gch.getActiveStack().bottom) + var b = cast[int](stackTop) when not stackIncreases: swap(a, b) - var x = cast[ByteAddress](p) + var x = cast[int](p) result = a <=% x and x <=% b when defined(sparc): # For SPARC architecture. @@ -337,7 +337,7 @@ when defined(sparc): # For SPARC architecture. # Addresses decrease as the stack grows. while sp <= max: gcMark(gch, sp[]) - sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer)) + sp = cast[PPointer](cast[int](sp) +% sizeof(pointer)) elif defined(ELATE): {.error: "stack marking code is to be written for this architecture".} @@ -354,8 +354,8 @@ elif stackIncreases: template forEachStackSlotAux(gch, gcMark: untyped) {.dirty.} = for stack in gch.stack.items(): - var max = cast[ByteAddress](gch.stack.bottom) - var sp = cast[ByteAddress](addr(registers)) -% sizeof(pointer) + var max = cast[int](gch.stack.bottom) + var sp = cast[int](addr(registers)) -% sizeof(pointer) while sp >=% max: gcMark(gch, cast[PPointer](sp)[]) sp = sp -% sizeof(pointer) @@ -383,8 +383,8 @@ else: gch.getActiveStack().setPosition(addr(registers)) if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. for stack in gch.stack.items(): - var max = cast[ByteAddress](stack.bottom) - var sp = cast[ByteAddress](addr(registers)) + var max = cast[int](stack.bottom) + var sp = cast[int](addr(registers)) when defined(amd64): if stack.isActiveStack(): # words within the jmp_buf structure may not be properly aligned. diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index f91b37b94..72d22f08b 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -94,11 +94,11 @@ template gcAssert(cond: bool, msg: string) = proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) + result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) + result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging @@ -217,7 +217,7 @@ proc initGC() = gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID") proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -229,7 +229,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[ByteAddress](dest) + var d = cast[int](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -255,7 +255,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: when not defined(nimSeqsV2): - var d = cast[ByteAddress](cellToUsr(cell)) + var d = cast[int](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: for i in 0..s.len-1: @@ -268,7 +268,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch, size + sizeof(Cell)) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) - gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -336,9 +336,9 @@ when not defined(nimSeqsV2): var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[int](res)+% oldsize +% sizeof(Cell)), newsize-oldsize) - sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") when withBitvectors: incl(gch.allocated, res) when useCellIds: inc gch.idGenerator @@ -446,7 +446,7 @@ proc markGlobals(gch: var GcHeap) = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: - var c = cast[ByteAddress](p) + var c = cast[int](p) if c >% PageSize: # fast check: does it look like a cell? var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p)) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 4817059be..925e98ed3 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -80,12 +80,12 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): let pos = cast[int](result) # Convert pointer to PageSize correct one. - var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize)) + var new_pos = cast[int](pos) +% (PageSize - (pos %% PageSize)) if (new_pos-pos) < sizeof(EmscriptenMMapBlock): new_pos = new_pos +% PageSize result = cast[pointer](new_pos) - var mmapDescrPos = cast[ByteAddress](result) -% sizeof(EmscriptenMMapBlock) + var mmapDescrPos = cast[int](result) -% sizeof(EmscriptenMMapBlock) var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) mmapDescr.realSize = realSize @@ -96,7 +96,7 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): proc osTryAllocPages(size: int): pointer = osAllocPages(size) proc osDeallocPages(p: pointer, size: int) {.inline.} = - var mmapDescrPos = cast[ByteAddress](p) -% sizeof(EmscriptenMMapBlock) + var mmapDescrPos = cast[int](p) -% sizeof(EmscriptenMMapBlock) var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) munmap(mmapDescr.realPointer, mmapDescr.realSize) diff --git a/lib/system/repr.nim b/lib/system/repr.nim index e47220656..6b6f7e340 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -155,7 +155,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..typ.size div bs - 1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), typ.base, cl) + reprAux(result, cast[pointer](cast[int](p) + i*bs), typ.base, cl) add result, "]" when defined(nimSeqsV2): @@ -183,7 +183,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..cast[PGenericSeq](p).len-1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[ByteAddress](payloadPtr(p)) + align(payloadOffset, typ.align) + i*bs), + reprAux(result, cast[pointer](cast[int](payloadPtr(p)) + align(payloadOffset, typ.align) + i*bs), typ.base, cl) add result, "]" @@ -194,14 +194,14 @@ when not defined(useNimRtl): of nkSlot: add result, $n.name add result, " = " - reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl) + reprAux(result, cast[pointer](cast[int](p) + n.offset), n.typ, cl) of nkList: for i in 0..n.len-1: if i > 0: add result, ",\n" reprRecordAux(result, p, n.sons[i], cl) of nkCase: var m = selectBranch(p, n) - reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl) + reprAux(result, cast[pointer](cast[int](p) + n.offset), n.typ, cl) if m != nil: reprRecordAux(result, p, m, cl) proc reprRecord(result: var string, p: pointer, typ: PNimType, @@ -307,7 +307,7 @@ when not defined(useNimRtl): var bs = elemtyp.size for i in 0..length - 1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), elemtyp, cl) + reprAux(result, cast[pointer](cast[int](p) + i*bs), elemtyp, cl) add result, "]" deinitReprClosure(cl) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index be32652d8..b8dc7101d 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -17,10 +17,10 @@ proc dataPointer(a: PGenericSeq, elemAlign: int): pointer = - cast[pointer](cast[ByteAddress](a) +% align(GenericSeqSize, elemAlign)) + cast[pointer](cast[int](a) +% align(GenericSeqSize, elemAlign)) proc dataPointer(a: PGenericSeq, elemAlign, elemSize, index: int): pointer = - cast[pointer](cast[ByteAddress](a) +% align(GenericSeqSize, elemAlign) +% (index*%elemSize)) + cast[pointer](cast[int](a) +% align(GenericSeqSize, elemAlign) +% (index*%elemSize)) proc resize(old: int): int {.inline.} = if old <= 0: result = 4 diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim index b1eb7e7c5..f4c92319b 100644 --- a/tests/parallel/tguard1.nim +++ b/tests/parallel/tguard1.nim @@ -5,7 +5,7 @@ output: "90" when false: template lock(a, b: ptr Lock; body: stmt) = - if cast[ByteAddress](a) < cast[ByteAddress](b): + if cast[int](a) < cast[int](b): pthread_mutex_lock(a) pthread_mutex_lock(b) else: From 84200f28a114ef9744ecf2b6060ef140e350139b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:42:31 +0800 Subject: [PATCH 4070/4254] bump csource_v2 hash (#21118) --- config/build_config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/build_config.txt b/config/build_config.txt index 3ae618f00..0ea963c39 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -2,4 +2,4 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" nim_csourcesDir=csources_v2 nim_csourcesUrl=https://github.com/nim-lang/csources_v2.git nim_csourcesBranch=master -nim_csourcesHash=ffd834c20915dc04c78eb0d3b2162832e7ec9c13 +nim_csourcesHash=32cf8431bb19f8803352a0ab3dbee5fec35d5ec6 From 296e7f598e58430415369a34f83552915f57f3f5 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 16 Dec 2022 19:49:26 +0800 Subject: [PATCH 4071/4254] Bump the devel version to 1.9.1 (#21117) --- lib/system/compilation.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim index 6109e9874..234e8cafe 100644 --- a/lib/system/compilation.nim +++ b/lib/system/compilation.nim @@ -6,11 +6,11 @@ const ## ``` # see also std/private/since - NimMinor* {.intdefine.}: int = 7 + NimMinor* {.intdefine.}: int = 9 ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 3 + NimPatch* {.intdefine.}: int = 1 ## is the patch number of Nim's version. ## Odd for devel, even for releases. From 7fa983f5e6b5f52a20e477e2443c8fdede244290 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 17 Dec 2022 00:21:07 +0800 Subject: [PATCH 4072/4254] Nim now ships nimble with 0.14.1 version (#21120) * Nimble now uses latest patch * Update koch.nim --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 84d0911ac..6b3d327f5 100644 --- a/koch.nim +++ b/koch.nim @@ -10,7 +10,7 @@ # const - NimbleStableCommit = "0777f33d1ddbd505b3aa7b714032125349323ceb" # master + NimbleStableCommit = "afd03bc000f4013c48f52381728327dabfccfc4c" # master # examples of possible values: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" HeadHash = "#head" From d83f66a24d990f2e4a135a4a64e1c464702b953d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:10:56 +0800 Subject: [PATCH 4073/4254] fixes #21116; always mangles the param (#21121) * fixes #21116; always mangles the param * idOrSig * fixes tests * Apply suggestions from code review --- compiler/ccgtypes.nim | 6 +----- tests/ccgbugs/t21116.nim | 10 ++++++++++ tests/ccgbugs/tnoalias.nim | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 tests/ccgbugs/t21116.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index d7b56de5b..3c9f9d923 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -48,11 +48,9 @@ proc fillBackendName(m: BModule; s: PSym) = writeMangledName(m.ndi, s, m.config) proc fillParamName(m: BModule; s: PSym) = - ## we cannot use 'sigConflicts' here since we have a BModule, not a BProc. - ## Fortunately C's scoping rules are sane enough so that that doesn't - ## cause any trouble. if s.loc.r == "": var res = s.name.s.mangle + res.add idOrSig(s, res, m.sigConflicts) # Take into account if HCR is on because of the following scenario: # if a module gets imported and it has some more importc symbols in it, # some param names might receive the "_0" suffix to distinguish from what @@ -69,8 +67,6 @@ proc fillParamName(m: BModule; s: PSym) = # and a function called in main or proxy uses `socket` as a parameter name. # That would lead to either needing to reload `proxy` or to overwrite the # executable file for the main module, which is running (or both!) -> error. - if m.hcrOn or isKeyword(s.name) or m.g.config.cppDefines.contains(res): - res.add "_0" s.loc.r = res.rope writeMangledName(m.ndi, s, m.config) diff --git a/tests/ccgbugs/t21116.nim b/tests/ccgbugs/t21116.nim new file mode 100644 index 000000000..6418df539 --- /dev/null +++ b/tests/ccgbugs/t21116.nim @@ -0,0 +1,10 @@ +discard """ + target: "c cpp" + disabled: windows +""" +# bug #21116 +import std/os + +proc p(glob: string) = + for _ in walkFiles(glob): discard +p("dir/*") diff --git a/tests/ccgbugs/tnoalias.nim b/tests/ccgbugs/tnoalias.nim index f200992d7..96c3d390b 100644 --- a/tests/ccgbugs/tnoalias.nim +++ b/tests/ccgbugs/tnoalias.nim @@ -1,5 +1,5 @@ discard """ - ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x,' @'void* NIM_NOALIAS q'" + ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x__0qEngDE9aYoYsF8tWnyPacw,' @'void* NIM_NOALIAS q'" """ type From ae4645e8dfec5c7b5f2d8cbdb672b7a0d55dfb37 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:28:59 +0800 Subject: [PATCH 4074/4254] add 2.0 changelog (#21107) [backport: 2.0] add v2.0 changelog --- changelog.md | 296 +------------------------------ changelogs/changelog_2_0_0.md | 321 ++++++++++++++++++++++++++++++++++ 2 files changed, 324 insertions(+), 293 deletions(-) create mode 100644 changelogs/changelog_2_0_0.md diff --git a/changelog.md b/changelog.md index 00bdb50c2..0389faad9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,321 +1,31 @@ -# v2.0.0 - yyyy-mm-dd +# v2.2.0 - yyyy-mm-dd ## Changes affecting backward compatibility -- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`. -- `addr` is now available for all addressable locations, - `unsafeAddr` is now deprecated and an alias for `addr`. - -- Certain definitions from the default `system` module have been moved to - the following new modules: - - - `std/syncio` - - `std/assertions` - - `std/formatfloat` - - `std/objectdollar` - - `std/widestrs` - - `std/typedthreads` - - `std/sysatomics` - - In the future, these definitions will be removed from the `system` module, - and their respective modules will have to be imported to use them. - Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option - may be used. - -- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated - symbols in the `system` module: - - Aliases with `Error` suffix to exception types that have a `Defect` suffix - (see [exceptions](https://nim-lang.org/docs/exceptions.html)): - `ArithmeticError`, `DivByZeroError`, `OverflowError`, - `AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`, - `FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`, - `ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`, - `FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`, - `DeadThreadError`, `NilAccessError` - - `addQuitProc`, replaced by `exitprocs.addExitProc` - - Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32` - - `TaintedString`, formerly a distinct alias to `string` - - `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to - `ptr int32`, `ptr int64`, `ptr float32`, `ptr float64` - -- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in - in the `system` module. - -- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore. - -- The `gc:v2` option is removed. - -- The `mainmodule` and `m` options are removed. - -- The `threads:on` option is now the default. - -- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via - `experimental:flexibleOptionalParams`. - -- Automatic dereferencing (experimental feature) is removed. - -- The `Math.trunc` polyfill for targeting Internet Explorer was - previously included in most JavaScript output files. - Now, it is only included with `-d:nimJsMathTruncPolyfill`. - If you are targeting Internet Explorer, you may choose to enable this option - or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). - Nim uses `Math.trunc` for the division and modulo operators for integers. - -- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and -`sink` for optimization purposes. - -- The `nimPreviewDotLikeOps` define is going to be removed or deprecated. - -- The `{.this.}` pragma, deprecated since 0.19, has been removed. -- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead. - ```nim - type Foo = distinct ptr int - - # Before: - var x: Foo = nil - # After: - var x: Foo = Foo(nil) - ``` -- Removed two type pragma syntaxes deprecated since 0.20, namely - `type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. - -- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent - with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. - This decision was made with the assumption that the old syntax was used rarely; - if your code used the old syntax, please be aware of this change. - -- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators - are no longer experimental. - -- Removed the `nimIncrSeqV3` define. - -- `macros.getImpl` for `const` symbols now returns the full definition node - (as `nnkConstDef`) rather than the AST of the constant value. - -- Lock levels are deprecated, now a noop. - -- ORC is now the default memory management strategy. Use - `--mm:refc` for a transition period. - -- `strictEffects` are no longer experimental. - Use `legacy:laxEffects` to keep backward compatibility. - -- The `gorge`/`staticExec` calls will now return a descriptive message in the output - if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`. - -- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning. - This warning will become an error in future versions! Use a `cast` operation - like `cast[cstring](x)` instead. - -- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`. - -- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details. - -- Redefining templates with the same signature was previously - allowed to support certain macro code. To do this explicitly, the - `{.redefine.}` pragma has been added. Note that this is only for templates. - Implicit redefinition of templates is now deprecated and will give an error in the future. - -- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. - -- Several Standard libraries are moved to nimble packages, use `nimble` to install them: - - `std/punycode` => `punycode` - - `std/asyncftpclient` => `asyncftpclient` - - `std/smtp` => `smtp` - - `std/db_common` => `db_connector/db_common` - - `std/db_sqlite` => `db_connector/db_sqlite` - - `std/db_mysql` => `db_connector/db_mysql` - - `std/db_postgres` => `db_connector/db_postgres` - - `std/db_odbc` => `db_connector/db_odbc` - -- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of - `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. - This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. - -- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. ## Standard library additions and changes [//]: # "Changes:" -- OpenSSL 3 is now supported. -- `macros.parseExpr` and `macros.parseStmt` now accept an optional - filename argument for more informative errors. -- Module `colors` expanded with missing colors from the CSS color standard. - `colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard. -- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). -- The `md5` module now works at compile time and in JavaScript. -- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables. -- `strutils.find` now uses and defaults to `last = -1` for whole string searches, - making limiting it to just the first char (`last = 0`) valid. -- `random.rand` now works with `Ordinal`s. -- Undeprecated `os.isvalidfilename`. -- `std/oids` now uses `int64` to store time internally (before it was int32). -- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`. -- `std/uri.Uri.isIpv6` is now exported. -- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2. - - -- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`. -- `std/jsfetch.newFetchOptions` now has default values for all parameters -- `std/jsformdata` now accepts `Blob` data type. [//]: # "Additions:" -- Added ISO 8601 week date utilities in `times`: - - Added `IsoWeekRange`, a range type for weeks in a week-based year. - - Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year. - - Added a `initDateTime` overload to create a datetime from an ISO week date. - - Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime. - - Added `getIsoWeeksInYear` to return the number of weeks in a week-based year. -- Added new modules which were part of `std/os`: - - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - - Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`. - - Added `std/cmdline` for reading command line parameters. -- Added `sep` parameter in `std/uri` to specify the query separator. -- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) - and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) - in `jscore` for JavaScript targets. -- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`. -- Added `complex.sgn` for obtaining the phase of complex numbers. -- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`, - `after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`, - `hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`, - `replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`, - `toggleAttribute`, and `matches` to `std/dom`. -- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices) -- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460 -- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse. -- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse. -- Added `safe` parameter to `base64.encodeMime`. + [//]: # "Deprecations:" -- Deprecated `selfExe` for Nimscript. -- Deprecated `std/sums`. -- Deprecated `std/base64.encode` for collections of arbitrary integer element type. - Now only `byte` and `char` are supported. + [//]: # "Removals:" -- Removed deprecated module `parseopt2`. -- Removed deprecated module `sharedstrings`. -- Removed deprecated module `dom_extensions`. -- Removed deprecated module `LockFreeHash`. -- Removed deprecated module `events`. -- Removed deprecated `oids.oidToString`. -- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. -- Removed deprecated `jsre.test` and `jsre.toString`. -- Removed deprecated `math.c_frexp`. -- Removed deprecated `` httpcore.`==` ``. -- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. -- Removed deprecated `osproc.poDemon`, symbol with typo. -- Removed deprecated `tables.rightSize`. - - -- Removed deprecated `posix.CLONE_STOPPED`. ## Language changes -- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma - which can be used to disable certain effects in proc types. -- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental, - meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. -- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed - for the right-hand side of type definitions in type sections. Previously - they would error with "invalid indentation". - -- Compile-time define changes: - - `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. - In the command line, this is defined as `-d:a.b.c`. Older versions can - use accents as in ``defined(`a.b.c`)`` to access such defines. - - [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas) - now support a string argument for qualified define names. - - ```nim - # -d:package.FooBar=42 - const FooBar {.intdefine: "package.FooBar".}: int = 5 - echo FooBar # 42 - ``` - - This was added to help disambiguate similar define names for different packages. - In older versions, this could only be achieved with something like the following: - - ```nim - const FooBar = block: - const `package.FooBar` {.intdefine.}: int = 5 - `package.FooBar` - ``` - - A generic `define` pragma for constants has been added that interprets - the value of the define based on the type of the constant value. - See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma) - for a list of supported types. - -- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes: - - Templates now accept macro pragmas. - - Macro pragmas for var/let/const sections have been redesigned in a way that works - similarly to routine macro pragmas. The new behavior is documented in the - [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas). - - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, - allowing multiple type definitions to be injected in place of the original type definition. - - ```nim - import macros - macro multiply(amount: static int, s: untyped): untyped = - let name = $s[0].basename - result = newNimNode(nnkTypeSection) - for i in 1 .. amount: - result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) - type - Foo = object - Bar {.multiply: 3.} = object - x, y, z: int - Baz = object - # becomes - type - Foo = object - Bar1 = object - x, y, z: int - Bar2 = object - x, y, z: int - Bar3 = object - x, y, z: int - Baz = object - ``` - -- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) - has been implemented for a variety of basic cases. For example, code like the following now compiles: - - ```nim - let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")] - ``` - -- `cstring` is now accepted as a selector in `case` statements, removing the - need to convert to `string`. On the JS backend, this is translated directly - to a `switch` statement. - -- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters). -- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`. ## Compiler changes -- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the - reality better. (Nim moved away from all techniques based on "tracing".) -- Defines the `gcRefc` symbol which allows writing specific code for the refc GC. - -- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, - without requiring `-d:nimVersion140` which is now a noop. - -- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package. - -- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and - related functions produced on the backend. This prevents conflicts with other Nim - static libraries. - -- When compiling for Release the flag `-fno-math-errno` is used for GCC. ## Tool changes -- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md new file mode 100644 index 000000000..00bdb50c2 --- /dev/null +++ b/changelogs/changelog_2_0_0.md @@ -0,0 +1,321 @@ +# v2.0.0 - yyyy-mm-dd + + +## Changes affecting backward compatibility +- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`. + +- `addr` is now available for all addressable locations, + `unsafeAddr` is now deprecated and an alias for `addr`. + +- Certain definitions from the default `system` module have been moved to + the following new modules: + + - `std/syncio` + - `std/assertions` + - `std/formatfloat` + - `std/objectdollar` + - `std/widestrs` + - `std/typedthreads` + - `std/sysatomics` + + In the future, these definitions will be removed from the `system` module, + and their respective modules will have to be imported to use them. + Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option + may be used. + +- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated + symbols in the `system` module: + - Aliases with `Error` suffix to exception types that have a `Defect` suffix + (see [exceptions](https://nim-lang.org/docs/exceptions.html)): + `ArithmeticError`, `DivByZeroError`, `OverflowError`, + `AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`, + `FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`, + `ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`, + `FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`, + `DeadThreadError`, `NilAccessError` + - `addQuitProc`, replaced by `exitprocs.addExitProc` + - Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32` + - `TaintedString`, formerly a distinct alias to `string` + - `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to + `ptr int32`, `ptr int64`, `ptr float32`, `ptr float64` + +- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in + in the `system` module. + +- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore. + +- The `gc:v2` option is removed. + +- The `mainmodule` and `m` options are removed. + +- The `threads:on` option is now the default. + +- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via + `experimental:flexibleOptionalParams`. + +- Automatic dereferencing (experimental feature) is removed. + +- The `Math.trunc` polyfill for targeting Internet Explorer was + previously included in most JavaScript output files. + Now, it is only included with `-d:nimJsMathTruncPolyfill`. + If you are targeting Internet Explorer, you may choose to enable this option + or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). + Nim uses `Math.trunc` for the division and modulo operators for integers. + +- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and +`sink` for optimization purposes. + +- The `nimPreviewDotLikeOps` define is going to be removed or deprecated. + +- The `{.this.}` pragma, deprecated since 0.19, has been removed. +- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead. + ```nim + type Foo = distinct ptr int + + # Before: + var x: Foo = nil + # After: + var x: Foo = Foo(nil) + ``` +- Removed two type pragma syntaxes deprecated since 0.20, namely + `type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. + +- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent + with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. + This decision was made with the assumption that the old syntax was used rarely; + if your code used the old syntax, please be aware of this change. + +- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators + are no longer experimental. + +- Removed the `nimIncrSeqV3` define. + +- `macros.getImpl` for `const` symbols now returns the full definition node + (as `nnkConstDef`) rather than the AST of the constant value. + +- Lock levels are deprecated, now a noop. + +- ORC is now the default memory management strategy. Use + `--mm:refc` for a transition period. + +- `strictEffects` are no longer experimental. + Use `legacy:laxEffects` to keep backward compatibility. + +- The `gorge`/`staticExec` calls will now return a descriptive message in the output + if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`. + +- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning. + This warning will become an error in future versions! Use a `cast` operation + like `cast[cstring](x)` instead. + +- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`. + +- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details. + +- Redefining templates with the same signature was previously + allowed to support certain macro code. To do this explicitly, the + `{.redefine.}` pragma has been added. Note that this is only for templates. + Implicit redefinition of templates is now deprecated and will give an error in the future. + +- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. + +- Several Standard libraries are moved to nimble packages, use `nimble` to install them: + - `std/punycode` => `punycode` + - `std/asyncftpclient` => `asyncftpclient` + - `std/smtp` => `smtp` + - `std/db_common` => `db_connector/db_common` + - `std/db_sqlite` => `db_connector/db_sqlite` + - `std/db_mysql` => `db_connector/db_mysql` + - `std/db_postgres` => `db_connector/db_postgres` + - `std/db_odbc` => `db_connector/db_odbc` + +- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of + `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. + This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. + +- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. + +## Standard library additions and changes + +[//]: # "Changes:" +- OpenSSL 3 is now supported. +- `macros.parseExpr` and `macros.parseStmt` now accept an optional + filename argument for more informative errors. +- Module `colors` expanded with missing colors from the CSS color standard. + `colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard. +- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). +- The `md5` module now works at compile time and in JavaScript. +- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables. +- `strutils.find` now uses and defaults to `last = -1` for whole string searches, + making limiting it to just the first char (`last = 0`) valid. +- `random.rand` now works with `Ordinal`s. +- Undeprecated `os.isvalidfilename`. +- `std/oids` now uses `int64` to store time internally (before it was int32). +- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`. +- `std/uri.Uri.isIpv6` is now exported. +- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2. + + +- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`. +- `std/jsfetch.newFetchOptions` now has default values for all parameters +- `std/jsformdata` now accepts `Blob` data type. + + +[//]: # "Additions:" +- Added ISO 8601 week date utilities in `times`: + - Added `IsoWeekRange`, a range type for weeks in a week-based year. + - Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year. + - Added a `initDateTime` overload to create a datetime from an ISO week date. + - Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime. + - Added `getIsoWeeksInYear` to return the number of weeks in a week-based year. +- Added new modules which were part of `std/os`: + - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. + - Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`. + - Added `std/cmdline` for reading command line parameters. +- Added `sep` parameter in `std/uri` to specify the query separator. +- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) + and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) + in `jscore` for JavaScript targets. +- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`. +- Added `complex.sgn` for obtaining the phase of complex numbers. +- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`, + `after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`, + `hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`, + `replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`, + `toggleAttribute`, and `matches` to `std/dom`. +- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices) +- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460 +- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse. +- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse. +- Added `safe` parameter to `base64.encodeMime`. + +[//]: # "Deprecations:" +- Deprecated `selfExe` for Nimscript. +- Deprecated `std/sums`. +- Deprecated `std/base64.encode` for collections of arbitrary integer element type. + Now only `byte` and `char` are supported. + +[//]: # "Removals:" +- Removed deprecated module `parseopt2`. +- Removed deprecated module `sharedstrings`. +- Removed deprecated module `dom_extensions`. +- Removed deprecated module `LockFreeHash`. +- Removed deprecated module `events`. +- Removed deprecated `oids.oidToString`. +- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. +- Removed deprecated `jsre.test` and `jsre.toString`. +- Removed deprecated `math.c_frexp`. +- Removed deprecated `` httpcore.`==` ``. +- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. +- Removed deprecated `osproc.poDemon`, symbol with typo. +- Removed deprecated `tables.rightSize`. + + +- Removed deprecated `posix.CLONE_STOPPED`. + + +## Language changes + +- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma + which can be used to disable certain effects in proc types. +- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental, + meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. +- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed + for the right-hand side of type definitions in type sections. Previously + they would error with "invalid indentation". + +- Compile-time define changes: + - `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. + In the command line, this is defined as `-d:a.b.c`. Older versions can + use accents as in ``defined(`a.b.c`)`` to access such defines. + - [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas) + now support a string argument for qualified define names. + + ```nim + # -d:package.FooBar=42 + const FooBar {.intdefine: "package.FooBar".}: int = 5 + echo FooBar # 42 + ``` + + This was added to help disambiguate similar define names for different packages. + In older versions, this could only be achieved with something like the following: + + ```nim + const FooBar = block: + const `package.FooBar` {.intdefine.}: int = 5 + `package.FooBar` + ``` + - A generic `define` pragma for constants has been added that interprets + the value of the define based on the type of the constant value. + See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma) + for a list of supported types. + +- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes: + - Templates now accept macro pragmas. + - Macro pragmas for var/let/const sections have been redesigned in a way that works + similarly to routine macro pragmas. The new behavior is documented in the + [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas). + - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, + allowing multiple type definitions to be injected in place of the original type definition. + + ```nim + import macros + macro multiply(amount: static int, s: untyped): untyped = + let name = $s[0].basename + result = newNimNode(nnkTypeSection) + for i in 1 .. amount: + result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) + type + Foo = object + Bar {.multiply: 3.} = object + x, y, z: int + Baz = object + # becomes + type + Foo = object + Bar1 = object + x, y, z: int + Bar2 = object + x, y, z: int + Bar3 = object + x, y, z: int + Baz = object + ``` + +- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) + has been implemented for a variety of basic cases. For example, code like the following now compiles: + + ```nim + let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")] + ``` + +- `cstring` is now accepted as a selector in `case` statements, removing the + need to convert to `string`. On the JS backend, this is translated directly + to a `switch` statement. + +- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters). +- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`. + + +## Compiler changes + +- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the + reality better. (Nim moved away from all techniques based on "tracing".) + +- Defines the `gcRefc` symbol which allows writing specific code for the refc GC. + +- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, + without requiring `-d:nimVersion140` which is now a noop. + +- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package. + +- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and + related functions produced on the backend. This prevents conflicts with other Nim + static libraries. + +- When compiling for Release the flag `-fno-math-errno` is used for GCC. + + +## Tool changes + +- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). From b8d200683a77487e7ef5d78abd4c1b981709bddd Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 17 Dec 2022 20:44:30 +0800 Subject: [PATCH 4075/4254] remove unused imports (#21126) --- lib/impure/rdstdin.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 935c83671..b0c648373 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -22,8 +22,6 @@ runnableExamples("-r:off"): if line.len > 0: echo line echo "exiting" -when defined(nimPreviewSlimSystem): - import std/syncio when defined(windows): when defined(nimPreviewSlimSystem): From 100b304ac2aaa65222d7a9043acd0c534ed484cb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 17 Dec 2022 21:42:29 +0800 Subject: [PATCH 4076/4254] fixes misplaced changelog entries; pre-existing issue (#21125) * move misplaced changelog entries to the right place * fixes misplaced changelog --- changelogs/changelog.md | 33 --------------------------------- changelogs/changelog_2_0_0.md | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 33 deletions(-) delete mode 100644 changelogs/changelog.md diff --git a/changelogs/changelog.md b/changelogs/changelog.md deleted file mode 100644 index d793c4313..000000000 --- a/changelogs/changelog.md +++ /dev/null @@ -1,33 +0,0 @@ -# v1.xx.x - yyyy-mm-dd - -## Changes affecting backward compatibility - -## Standard library additions and changes - -- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433). - -### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall - -This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17. - -On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall. - -When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be: -```sh -$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details -$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8 -$ sh build.sh # per unix install instructions -$ bin/nim c koch # per unix install instructions -$ ./koch boot -d:release # per unix install instructions -$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall -``` - -This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular). - -## Language changes - - -## Compiler changes - - -## Tool changes diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 00bdb50c2..f34336ff7 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -160,6 +160,25 @@ - `std/jsfetch.newFetchOptions` now has default values for all parameters - `std/jsformdata` now accepts `Blob` data type. +- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433). + +- New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall. + + This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17. + + On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall. + + When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be: + ```sh + $ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details + $ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8 + $ sh build.sh # per unix install instructions + $ bin/nim c koch # per unix install instructions + $ ./koch boot -d:release # per unix install instructions + $ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall + ``` + + This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular). [//]: # "Additions:" - Added ISO 8601 week date utilities in `times`: From 53eed2be4515a3ae853ae4d2fbd84daa49c1d6d6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 18 Dec 2022 22:31:13 +0800 Subject: [PATCH 4077/4254] close #11705; add a testcase (#21128) --- tests/template/t11705.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/template/t11705.nim diff --git a/tests/template/t11705.nim b/tests/template/t11705.nim new file mode 100644 index 000000000..65ddc7e6c --- /dev/null +++ b/tests/template/t11705.nim @@ -0,0 +1,17 @@ +type RefObj = ref object + +proc `[]`(val: static[int]) = # works with different name/overload or without static arg + discard + +template noRef*(T: typedesc): typedesc = # works without template indirection + typeof(default(T)[]) + +proc `=destroy`(x: var noRef(RefObj)) = + discard + +proc foo = + var x = new RefObj + doAssert $(x[]) == "()" + +# bug #11705 +foo() From 70c575095e89497c63af5d8b2c3ed7dca802179f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:56:49 +0800 Subject: [PATCH 4078/4254] add changelog for the new strict function checking algorithm (#21129) add changelog for the new strict function checking --- changelogs/changelog_2_0_0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index f34336ff7..a899bb929 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -135,6 +135,8 @@ - If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. +- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. + ## Standard library additions and changes [//]: # "Changes:" From e278a781fc5bfc115326ed6c1873268d51b25303 Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 19 Dec 2022 19:35:15 +0800 Subject: [PATCH 4079/4254] fix #21109 (#21127) --- compiler/semexprs.nim | 2 ++ tests/misc/t21109.nim | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/misc/t21109.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8ac8f4750..612af482a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1947,6 +1947,8 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent) else: localError(c.config, n[0].info, errXExpected, "tuple constructor") + elif e.kind == tyEmpty: + localError(c.config, n[0].info, errTypeExpected) else: when false: # XXX investigate what we really need here. diff --git a/tests/misc/t21109.nim b/tests/misc/t21109.nim new file mode 100644 index 000000000..0f7980896 --- /dev/null +++ b/tests/misc/t21109.nim @@ -0,0 +1,13 @@ +discard """ + action: reject + errormsg: "type expected" + file: "iterators.nim" +""" + + +template b(j: untyped) = j +template m() = discard + +b: + for t, f in @[]: + m() From 886572a5162beea672d696fb03422e7777f56cfb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 20 Dec 2022 15:04:13 +0800 Subject: [PATCH 4080/4254] disable "Warning: gc is deprecated" in compiler (#21137) * disable "Warning: gc is deprecated" in compiler * Apply @tersec 's suggestion --- compiler/vmops.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index edf457295..d4a91b22d 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -145,6 +145,7 @@ when defined(nimHasInvariant): from std / compilesettings import SingleValueSetting, MultipleValueSetting proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string = + {.push warning[Deprecated]:off.} case SingleValueSetting(switch) of arguments: result = conf.arguments of outFile: result = conf.outFile.string @@ -162,6 +163,7 @@ when defined(nimHasInvariant): of libPath: result = conf.libpath.string of gc: result = $conf.selectedGC of mm: result = $conf.selectedGC + {.pop.} proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = From 40b5c4c4c340d44ee724183306716286e40002cb Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 21 Dec 2022 03:23:48 +0800 Subject: [PATCH 4081/4254] fix #20248;fix #6215;turns into simple CT error (#21141) --- compiler/semtypes.nim | 2 ++ tests/array/t20248.nim | 14 ++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/array/t20248.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index dca0d753b..534861e97 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -328,6 +328,8 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType = proc semArrayIndex(c: PContext, n: PNode): PType = if isRange(n): result = semRangeAux(c, n, nil) + elif n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "..<": + result = errorType(c) else: let e = semExprWithType(c, n, {efDetermineType}) if e.typ.kind == tyFromExpr: diff --git a/tests/array/t20248.nim b/tests/array/t20248.nim new file mode 100644 index 000000000..66142548b --- /dev/null +++ b/tests/array/t20248.nim @@ -0,0 +1,14 @@ +discard """ +cmd: "nim check --hints:off $file" +errormsg: "ordinal type expected; given: Error Type" +nimout: ''' +t20248.nim(10, 36) Error: ordinal type expected; given: Error Type +t20248.nim(14, 20) Error: ordinal type expected; given: Error Type +''' +""" + +type Vec[N: static[int]] = array[0 ..< N, float] + +var v: Vec[32] + +var stuff: array[0 ..< 16, int] From 0aec095b261bed8b5841beba7ce8cd52de4d54be Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 21 Dec 2022 03:26:32 +0800 Subject: [PATCH 4082/4254] fixes #19292; fixes #21122; fixes putEnv and setEnv with vcc (#21143) * fixes #19292; fixes 21122; fixes putEnv and setEnv with vcc * add a test --- lib/std/envvars.nim | 8 ++++++-- lib/std/private/win_setenv.nim | 26 +++++++++++++------------- tests/misc/t21443.nim | 6 ++++++ 3 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 tests/misc/t21443.nim diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim index 817a155ec..ce90f66ba 100644 --- a/lib/std/envvars.nim +++ b/lib/std/envvars.nim @@ -63,9 +63,13 @@ when not defined(nimscript): import winlean when defined(nimPreviewSlimSystem): import std/widestrs - proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv", + + type wchar_t {.importc: "wchar_t", header: "".} = int16 + proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "".} - proc getEnvImpl(env: cstring): WideCString = c_wgetenv(env.newWideCString) + proc getEnvImpl(env: cstring): WideCString = + let r: WideCString = env.newWideCString + cast[WideCString](c_wgetenv(cast[ptr wchar_t](r))) else: proc c_getenv(env: cstring): cstring {. importc: "getenv", header: "".} diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim index 303889a40..66e199dfe 100644 --- a/lib/std/private/win_setenv.nim +++ b/lib/std/private/win_setenv.nim @@ -33,25 +33,25 @@ else: # same as winlean.setEnvironmentVariableA proc c_getenv(varname: cstring): cstring {.importc: "getenv", header: "".} - proc c_wputenv(envstring: WideCString): cint {.importc: "_wputenv", header: "".} - proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv", header: "".} + proc c_wputenv(envstring: ptr wchar_t): cint {.importc: "_wputenv", header: "".} + proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "".} var errno {.importc, header: "".}: cint var genviron {.importc: "_environ".}: ptr ptr char # xxx `ptr UncheckedArray[WideCString]` did not work - proc wcstombs(wcstr: ptr char, mbstr: WideCString, count: csize_t): csize_t {.importc, header: "".} + proc wcstombs(wcstr: ptr char, mbstr: ptr wchar_t, count: csize_t): csize_t {.importc, header: "".} # xxx cint vs errno_t? proc setEnvImpl*(name: string, value: string, overwrite: cint): cint = const EINVAL = cint(22) - let wideName = newWideCString(name) - if overwrite == 0 and c_wgetenv(wideName) != nil: + let wideName: WideCString = newWideCString(name) + if overwrite == 0 and c_wgetenv(cast[ptr wchar_t](wideName)) != nil: return 0 if value != "": - let envstring = name & "=" & value - let e = c_wputenv(newWideCString(envstring)) + let envstring: WideCString = newWideCString(name & "=" & value) + let e = c_wputenv(cast[ptr wchar_t](envstring)) if e != 0: errno = EINVAL return -1 @@ -62,19 +62,19 @@ else: SetEnvironmentVariableA doesn't update `_environ`, so we have to do these terrible things. ]# - let envstring = name & "= " - if c_wputenv(newWideCString(envstring)) != 0: + let envstring: WideCString = newWideCString(name & "= ") + if c_wputenv(cast[ptr wchar_t](envstring)) != 0: errno = EINVAL return -1 # Here lies the documentation we blatently ignore to make this work. - var s = c_wgetenv(wideName) + var s = cast[WideCString](c_wgetenv(cast[ptr wchar_t](wideName))) s[0] = Utf16Char('\0') #[ This would result in a double null termination, which normally signifies the end of the environment variable list, so we stick a completely empty environment variable into the list instead. ]# - s = c_wgetenv(wideName) + s = cast[WideCString](c_wgetenv(cast[ptr wchar_t](wideName))) s[1] = Utf16Char('=') #[ If genviron is null, the MBCS environment has not been initialized @@ -88,12 +88,12 @@ else: # in the current codepage. Skip updating MBCS environment in this case. # For some reason, second `wcstombs` can find non-convertible characters # that the first `wcstombs` cannot. - let requiredSizeS = wcstombs(nil, wideName, 0) + let requiredSizeS = wcstombs(nil, cast[ptr wchar_t](wideName), 0) if requiredSizeS != high(csize_t): let requiredSize = requiredSizeS.int var buf = newSeq[char](requiredSize + 1) let buf2 = buf[0].addr - if wcstombs(buf2, wideName, csize_t(requiredSize + 1)) != high(csize_t): + if wcstombs(buf2, cast[ptr wchar_t](wideName), csize_t(requiredSize + 1)) != high(csize_t): var ptrToEnv = c_getenv(cast[cstring](buf2)) ptrToEnv[0] = '\0' ptrToEnv = c_getenv(cast[cstring](buf2)) diff --git a/tests/misc/t21443.nim b/tests/misc/t21443.nim new file mode 100644 index 000000000..70413c5b3 --- /dev/null +++ b/tests/misc/t21443.nim @@ -0,0 +1,6 @@ +import std/envvars + +# bug #19292 +putEnv("NimPutEnvTest", "test") +# bug #21122 +doAssert getEnv("NimPutEnvTest") == "test" From 8a77798dac66a55b42005db8837508a5af0547cf Mon Sep 17 00:00:00 2001 From: Luca Guzzon Date: Tue, 20 Dec 2022 20:29:42 +0100 Subject: [PATCH 4083/4254] ucpu fix-up for arm64 value on macos m1 (#21142) --- tools/niminst/makefile.nimf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf index 2fe89ed69..b392ab472 100644 --- a/tools/niminst/makefile.nimf +++ b/tools/niminst/makefile.nimf @@ -173,6 +173,9 @@ endif ifeq ($(ucpu),aarch64) mycpu = arm64 endif +ifeq ($(ucpu),arm64) + mycpu = arm64 +endif ifeq ($(ucpu),riscv64) mycpu = riscv64 endif From 81d8ea95af0cfaaedca2fd1881199e113e6f5b41 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:18:47 +0800 Subject: [PATCH 4084/4254] bump csource_v2 to include fixes for macos m1 (#21147) --- config/build_config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/build_config.txt b/config/build_config.txt index 0ea963c39..286e0dc2a 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -2,4 +2,4 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" nim_csourcesDir=csources_v2 nim_csourcesUrl=https://github.com/nim-lang/csources_v2.git nim_csourcesBranch=master -nim_csourcesHash=32cf8431bb19f8803352a0ab3dbee5fec35d5ec6 +nim_csourcesHash=b66c420697c574be18a20dd4720248a715b4287e From d0721eadf8cd6bf9436b5e5c9113c4c7bcfcc770 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 22 Dec 2022 04:46:14 +0800 Subject: [PATCH 4085/4254] fixes #21144; try expression will not match the less indentation except (#21152) fixes #21144; try expression will not match the less indent except --- compiler/parser.nim | 4 +++- tests/parser/ttry.nim | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/parser/ttry.nim diff --git a/compiler/parser.nim b/compiler/parser.nim index 6b3cebb7f..00013c218 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1770,11 +1770,13 @@ proc parseTry(p: var Parser; isExpr: bool): PNode = #| (optInd 'except' optionalExprList colcom stmt)* #| (optInd 'finally' colcom stmt)? result = newNodeP(nkTryStmt, p) + let parentIndent = p.currInd # isExpr getTok(p) colcom(p, result) result.add(parseStmt(p)) var b: PNode = nil - while sameOrNoInd(p) or isExpr: + + while sameOrNoInd(p) or (isExpr and parentIndent <= p.tok.indent): case p.tok.tokType of tkExcept: b = newNodeP(nkExceptBranch, p) diff --git a/tests/parser/ttry.nim b/tests/parser/ttry.nim new file mode 100644 index 000000000..190b0b8dc --- /dev/null +++ b/tests/parser/ttry.nim @@ -0,0 +1,27 @@ +# bug #21144 +block: + try: + let c = try: + 10 + except ValueError as exc: + 10 + except ValueError as exc: + discard + +if true: + block: + let c = try: + 10 + except ValueError as exc: + 10 + except OSError: + 99 + + +try: + let c = try: + 10 + except ValueError as exc: + 10 +except ValueError as exc: + discard \ No newline at end of file From 613829f7a4da5506269fadb3acc78d64ee0cbddf Mon Sep 17 00:00:00 2001 From: Peter Munch-Ellingsen Date: Thu, 22 Dec 2022 04:34:36 +0100 Subject: [PATCH 4086/4254] Implement setLineInfo (#21153) * Implement setLineInfo * Add tests --- compiler/msgs.nim | 7 +++++++ compiler/vm.nim | 14 ++++++++++++-- compiler/vmdef.nim | 3 ++- compiler/vmgen.nim | 14 +++++++++++++- lib/core/macros.nim | 16 ++++++++++++++++ tests/macros/tmacros_various.nim | 23 ++++++++++++++++++++++- 6 files changed, 72 insertions(+), 5 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 2c807806e..8b44c8dc6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -128,6 +128,13 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex = var dummy: bool result = fileInfoIdx(conf, filename, dummy) +proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex = + fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile) + +proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex = + var dummy: bool + fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy) + proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = result.fileIndex = fileInfoIdx if line < int high(uint16): diff --git a/compiler/vm.nim b/compiler/vm.nim index 53a16bcb0..61261c44c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1934,14 +1934,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of 1: # getLine regs[ra].node = newIntNode(nkIntLit, n.info.line.int) of 2: # getColumn - regs[ra].node = newIntNode(nkIntLit, n.info.col) + regs[ra].node = newIntNode(nkIntLit, n.info.col.int) else: internalAssert c.config, false regs[ra].node.info = n.info regs[ra].node.typ = n.typ - of opcNSetLineInfo: + of opcNCopyLineInfo: decodeB(rkNode) regs[ra].node.info = regs[rb].node.info + of opcNSetLineInfoLine: + decodeB(rkNode) + regs[ra].node.info.line = regs[rb].intVal.uint16 + of opcNSetLineInfoColumn: + decodeB(rkNode) + regs[ra].node.info.col = regs[rb].intVal.int16 + of opcNSetLineInfoFile: + decodeB(rkNode) + regs[ra].node.info.fileIndex = + fileInfoIdx(c.config, RelativeFile regs[rb].node.strVal) of opcEqIdent: decodeBC(rkInt) # aliases for shorter and easier to understand code below diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 54876f37d..114a49557 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -141,7 +141,8 @@ type opcNError, opcNWarning, opcNHint, - opcNGetLineInfo, opcNSetLineInfo, + opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine, + opcNSetLineInfoColumn, opcNSetLineInfoFile opcEqIdent, opcStrToIdent, opcGetImpl, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 1fdfea7c4..6a2ab1d11 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1335,7 +1335,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of "copyLineInfo": internalAssert c.config, n.len == 3 unused(c, n, dest) - genBinaryStmt(c, n, opcNSetLineInfo) + genBinaryStmt(c, n, opcNCopyLineInfo) + of "setLine": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfoLine) + of "setColumn": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfoColumn) + of "setFile": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfoFile) else: internalAssert c.config, false of mNHint: unused(c, n, dest) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 18a70f20c..138ec47a0 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -533,6 +533,22 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.} ## Copy lineinfo from `info`. +proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.} +proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.} +proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.} + +proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) = + ## Sets the line info on the NimNode. The file needs to exists, but can be a + ## relative path. If you want to attach line info to a block using `quote` + ## you'll need to add the line information after the quote block. + arg.setFile(file) + arg.setLine(line.uint16) + arg.setColumn(column.int16) + +proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) = + ## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_ + setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column) + proc lineInfoObj*(n: NimNode): LineInfo = ## Returns `LineInfo` of `n`, using absolute path for `filename`. result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn) diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index d702db56a..08be4602c 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -91,7 +91,7 @@ block tlexerex: -block tlineinfo: +block tcopylineinfo: # issue #5617, feature request type Test = object @@ -103,6 +103,27 @@ block tlineinfo: var z = mixer(Test) doAssert z +block tsetgetlineinfo: + # issue #21098, feature request + type Test = object + + macro mixer1(n: typed): untyped = + let x = newIdentNode("echo") + var lineInfo = n.lineInfoObj + x.setLineInfo lineInfo + result = newLit(x.lineInfo == n.lineInfo) + + macro mixer2(n: typed): untyped = + let x = newIdentNode("echo") + var lineInfo = n.lineInfoObj + lineInfo.line += 1 + x.setLineInfo lineInfo + result = newLit(x.lineInfo != n.lineInfo) + + doAssert mixer1(Test) + + doAssert mixer2(Test) + block tdebugstmt: From c5a72ebddd88b6d3a2712230d36367f180faa7da Mon Sep 17 00:00:00 2001 From: Bung Date: Thu, 22 Dec 2022 13:16:25 +0800 Subject: [PATCH 4087/4254] fix #16541 (#21148) --- compiler/sigmatch.nim | 2 ++ tests/misc/t16541.nim | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/misc/t16541.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 51728b103..61a4395f3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2150,6 +2150,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, elif arg.sym.kind in {skMacro, skTemplate}: return nil else: + if arg.sym.ast == nil: + return nil let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info) result = newSymNode(inferred, arg.info) if r == isInferredConvertible: diff --git a/tests/misc/t16541.nim b/tests/misc/t16541.nim new file mode 100644 index 000000000..452327e8f --- /dev/null +++ b/tests/misc/t16541.nim @@ -0,0 +1,12 @@ +discard """ + action: "reject" + +""" + +import strutils, sugar, nre + +proc my_replace*(s: string, r: Regex, by: string | (proc (match: string): string)): string = + nre.replace(s, r, by) + +discard my_replace("abcde", re"[bcd]", match => match.to_upper) == "aBCDe" +discard my_replace("abcde", re"[bcd]", (match: string) => match.to_upper) == "aBCDe" From 70fe360456b77912ec7f5014f7815137fa089fce Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Thu, 22 Dec 2022 18:25:24 +1100 Subject: [PATCH 4088/4254] Use `ErrorColor` when a warning that is turned into an error is raised (#21131) Use ErrorColor when a warning that is turned into an error is raised --- compiler/msgs.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 8b44c8dc6..8e391f2fb 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -541,10 +541,11 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, ignoreMsg = not conf.hasWarn(msg) if not ignoreMsg and msg in conf.warningAsErrors: title = ErrorTitle + color = ErrorColor else: title = WarningTitle + color = WarningColor if not ignoreMsg: writeContext(conf, info) - color = WarningColor inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint From 93b59da4902886cd68dd7df1dce09a1b455a06dc Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 22 Dec 2022 15:27:11 +0800 Subject: [PATCH 4089/4254] fixes #20244; fixes castSizes warnings (#21102) * fixes #20244; fixes castSizes warnings * fixes js * fixes js * fixes js * fixes * typo * extend using uint64 * Update lib/std/syncio.nim --- compiler/ccgutils.nim | 2 +- compiler/condsyms.nim | 1 + compiler/nim.cfg | 4 ++++ lib/pure/strutils.nim | 16 ++++++++++++++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index e19fccfa7..d86ebe461 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -53,7 +53,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt = a = a + (a shl 3) a = a xor (a shr 11) a = a + (a shl 15) - result = cast[Hash](a) + result = cast[Hash](uint(a)) template getUniqueType*(key: PType): PType = key diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 9d081ef0a..24c6d82d5 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -146,6 +146,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasCallsitePragma") defineSymbol("nimHasAmbiguousEnumHint") + defineSymbol("nimHasWarnCastSizes") defineSymbol("nimHasOutParams") defineSymbol("nimHasSystemRaisesDefect") defineSymbol("nimHasWarnUnnamedBreak") diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 96b47b0e6..b9c8fdc08 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -31,6 +31,10 @@ define:useStdoutAsStdmsg warning[ObservableStores]:off @end +@if nimHasWarnCastSizes: + warning[CastSizes]:on +@end + @if nimHasWarningAsError: warningAsError[GcUnsafe2]:on @end diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f628cfc2d..dbdd0d6a1 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -944,14 +944,26 @@ func toHex*[T: SomeInteger](x: T, len: Positive): string = doAssert b.toHex(4) == "1001" doAssert toHex(62, 3) == "03E" doAssert toHex(-8, 6) == "FFFFF8" - toHexImpl(cast[BiggestUInt](x), len, x < 0) + when defined(js): + toHexImpl(cast[BiggestUInt](x), len, x < 0) + else: + when T is SomeSignedInt: + toHexImpl(cast[BiggestUInt](BiggestInt(x)), len, x < 0) + else: + toHexImpl(BiggestUInt(x), len, x < 0) func toHex*[T: SomeInteger](x: T): string = ## Shortcut for `toHex(x, T.sizeof * 2)` runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" doAssert toHex(1984'i16) == "07C0" - toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) + when defined(js): + toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) + else: + when T is SomeSignedInt: + toHexImpl(cast[BiggestUInt](BiggestInt(x)), 2*sizeof(T), x < 0) + else: + toHexImpl(BiggestUInt(x), 2*sizeof(T), x < 0) func toHex*(s: string): string {.rtl.} = ## Converts a bytes string to its hexadecimal representation. From 7931bdac956cb3ad6734eab91c62920f4e80f919 Mon Sep 17 00:00:00 2001 From: Michael Voronin Date: Thu, 22 Dec 2022 10:32:12 +0300 Subject: [PATCH 4090/4254] Feature/xmltree additions (#20988) * [change] add/insert/delete family of xmltree expanded with several variations. Added replace methods family * [change] Lifted child limitations on insert methods (consulted with @araq) * [tests] add/insert/replace/delete of xmltree XmlNodes tests added --- lib/pure/xmltree.nim | 153 ++++++++++++++++++++++++++++++++++- tests/xml/ttree_add.nim | 51 ++++++++++++ tests/xml/ttree_add1.nim | 53 ++++++++++++ tests/xml/ttree_delete.nim | 47 +++++++++++ tests/xml/ttree_delete1.nim | 48 +++++++++++ tests/xml/ttree_insert.nim | 53 ++++++++++++ tests/xml/ttree_insert1.nim | 51 ++++++++++++ tests/xml/ttree_replace.nim | 46 +++++++++++ tests/xml/ttree_replace1.nim | 53 ++++++++++++ 9 files changed, 552 insertions(+), 3 deletions(-) create mode 100644 tests/xml/ttree_add.nim create mode 100644 tests/xml/ttree_add1.nim create mode 100644 tests/xml/ttree_delete.nim create mode 100644 tests/xml/ttree_delete1.nim create mode 100644 tests/xml/ttree_insert.nim create mode 100644 tests/xml/ttree_insert1.nim create mode 100644 tests/xml/ttree_replace.nim create mode 100644 tests/xml/ttree_replace1.nim diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 6228bd10f..7a2cebe87 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -31,7 +31,7 @@ runnableExamples: ## * `htmlgen module `_ for html code generator import std/private/since -import macros, strtabs, strutils +import macros, strtabs, strutils, sequtils when defined(nimPreviewSlimSystem): import std/assertions @@ -298,26 +298,60 @@ proc innerText*(n: XmlNode): string = proc add*(father, son: XmlNode) {.inline.} = ## Adds the child `son` to `father`. + ## `father` must be of `xnElement` type ## ## See also: + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ ## * `delete proc <#delete,XmlNode,Natural>`_ + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ runnableExamples: var f = newElement("myTag") f.add newText("my text") f.add newElement("sonTag") f.add newEntity("my entity") assert $f == "my text&my entity;" + + assert father.k == xnElement add(father.s, son) +proc add*(father: XmlNode, sons: openArray[XmlNode]) {.inline.} = + ## Adds the children `sons` to `father`. + ## `father` must be of `xnElement` type + ## + ## See also: + ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ + ## * `delete proc <#delete,XmlNode,Natural>`_ + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ + runnableExamples: + var f = newElement("myTag") + f.add(@[newText("my text"), newElement("sonTag"), newEntity("my entity")]) + assert $f == "my text&my entity;" + + assert father.k == xnElement + add(father.s, sons) + + proc insert*(father, son: XmlNode, index: int) {.inline.} = ## Inserts the child `son` to a given position in `father`. ## - ## `father` and `son` must be of `xnElement` kind. + ## `father` must be of `xnElement` kind. ## ## See also: + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ ## * `delete proc <#delete,XmlNode,Natural>`_ + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ runnableExamples: var f = newElement("myTag") f.add newElement("first") @@ -327,18 +361,52 @@ proc insert*(father, son: XmlNode, index: int) {.inline.} = """ - assert father.k == xnElement and son.k == xnElement + assert father.k == xnElement if len(father.s) > index: insert(father.s, son, index) else: insert(father.s, son, len(father.s)) +proc insert*(father: XmlNode, sons: openArray[XmlNode], index: int) {.inline.} = + ## Inserts the children openArray[`sons`] to a given position in `father`. + ## + ## `father` must be of `xnElement` kind. + ## + ## See also: + ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ + ## * `delete proc <#delete,XmlNode,Natural>`_ + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ + runnableExamples: + var f = newElement("myTag") + f.add newElement("first") + f.insert([newElement("second"), newElement("third")], 0) + assert $f == """ + + + +""" + + assert father.k == xnElement + if len(father.s) > index: + insert(father.s, sons, index) + else: + insert(father.s, sons, len(father.s)) + proc delete*(n: XmlNode, i: Natural) = ## Deletes the `i`'th child of `n`. ## ## See also: + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ runnableExamples: var f = newElement("myTag") f.add newElement("first") @@ -351,6 +419,85 @@ proc delete*(n: XmlNode, i: Natural) = assert n.k == xnElement n.s.delete(i) +proc delete*(n: XmlNode, slice: Slice[int]) = + ## Deletes the items `n[slice]` of `n`. + ## + ## See also: + ## * `delete proc <#delete.XmlNode,int>`_ + ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ + ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ + runnableExamples: + var f = newElement("myTag") + f.add newElement("first") + f.insert([newElement("second"), newElement("third")], 0) + f.delete(0..1) + assert $f == """ + +""" + + assert n.k == xnElement + n.s.delete(slice) + +proc replace*(n: XmlNode, i: Natural, replacement: openArray[XmlNode]) = + ## Replaces the `i`'th child of `n` with `replacement` openArray. + ## + ## `n` must be of `xnElement` kind. + ## + ## See also: + ## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_ + ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ + ## * `delete proc <#delete,XmlNode,Natural>`_ + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ + ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ + runnableExamples: + var f = newElement("myTag") + f.add newElement("first") + f.insert(newElement("second"), 0) + f.replace(0, @[newElement("third"), newElement("fourth")]) + assert $f == """ + + + +""" + + assert n.k == xnElement + n.s.delete(i) + n.s.insert(replacement, i) + +proc replace*(n: XmlNode, slice: Slice[int], replacement: openArray[XmlNode]) = + ## Deletes the items `n[slice]` of `n`. + ## + ## `n` must be of `xnElement` kind. + ## + ## See also: + ## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_ + ## * `add proc <#add,XmlNode,XmlNode>`_ + ## * `add proc <#add,XmlNode,openArray[XmlNode]>`_ + ## * `delete proc <#delete,XmlNode,Natural>`_ + ## * `delete proc <#delete.XmlNode,Slice[int]>`_ + ## * `insert proc <#insert,XmlNode,XmlNode,int>`_ + ## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_ + runnableExamples: + var f = newElement("myTag") + f.add newElement("first") + f.insert([newElement("second"), newElement("fifth")], 0) + f.replace(0..1, @[newElement("third"), newElement("fourth")]) + assert $f == """ + + + +""" + + assert n.k == xnElement + n.s.delete(slice) + n.s.insert(replacement, slice.a) + proc len*(n: XmlNode): int {.inline.} = ## Returns the number of `n`'s children. runnableExamples: diff --git a/tests/xml/ttree_add.nim b/tests/xml/ttree_add.nim new file mode 100644 index 000000000..4c6ef6cf9 --- /dev/null +++ b/tests/xml/ttree_add.nim @@ -0,0 +1,51 @@ +discard """ + output: ''' + +
      Some text in body
      +
      Some more text in body
      + + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +var baseDocHead = """ + + +
      Some text
      +
      Some more text
      + +
      +""" +var baseDocHeadTree = parseXml(baseDocHead) +var baseDocBody = """ + +
      Some text in body
      +
      Some more text in body
      + +""" +var baseDocBodyTree = parseXml(baseDocBody) + +proc test_add() = + var testDoc = baseDocHeadTree + var newBody = newElement("body") + for item in baseDocBodyTree.items(): + newBody.add(item) + + echo $newBody + + testDoc.add(newBody) + echo $testDoc + +test_add() diff --git a/tests/xml/ttree_add1.nim b/tests/xml/ttree_add1.nim new file mode 100644 index 000000000..30ec83c02 --- /dev/null +++ b/tests/xml/ttree_add1.nim @@ -0,0 +1,53 @@ +discard """ + output: ''' + +
      Some text in body
      +
      Some more text in body
      + + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +var baseDocHead = """ + + +
      Some text
      +
      Some more text
      + +
      +""" +var baseDocHeadTree = parseXml(baseDocHead) +var baseDocBody = """ + +
      Some text in body
      +
      Some more text in body
      + +""" +var baseDocBodyTree = parseXml(baseDocBody) + +proc test_add() = + var testDoc = baseDocHeadTree + var newBody = newElement("body") + var bodyItems: seq[XmlNode] = @[] + for item in baseDocBodyTree.items(): + bodyItems.add(item) + newBody.add(bodyItems) + + echo $newBody + + testDoc.add(newBody) + echo $testDoc + +test_add() diff --git a/tests/xml/ttree_delete.nim b/tests/xml/ttree_delete.nim new file mode 100644 index 000000000..32b477839 --- /dev/null +++ b/tests/xml/ttree_delete.nim @@ -0,0 +1,47 @@ +discard """ + output: ''' + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +let initialDocBase = """ + + +
      Some text
      +
      Some more text
      + + +
      MORE TEXT
      +
      MORE TEXT Some more text
      +
      + +
      MORE TEXT
      +
      MORE TEXT Some more text
      +
      + +
      Some text in body
      +
      Some more text in body
      + +
      +""" +var initialDocBaseTree = parseXml(initialDocBase) + +proc test_delete() = + var testDoc = initialDocBaseTree + + testDoc.delete(1..2) + echo $testDoc + +test_delete() diff --git a/tests/xml/ttree_delete1.nim b/tests/xml/ttree_delete1.nim new file mode 100644 index 000000000..a8442a093 --- /dev/null +++ b/tests/xml/ttree_delete1.nim @@ -0,0 +1,48 @@ +discard """ + output: ''' + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +let initialDocBase = """ + + +
      Some text
      +
      Some more text
      + + +
      MORE TEXT
      +
      MORE TEXT Some more text
      +
      + +
      MORE TEXT
      +
      MORE TEXT Some more text
      +
      + +
      Some text in body
      +
      Some more text in body
      + +
      +""" +var initialDocBaseTree = parseXml(initialDocBase) + +proc test_delete() = + var testDoc = initialDocBaseTree + + testDoc.delete(1) + testDoc.delete(1) + echo $testDoc + +test_delete() diff --git a/tests/xml/ttree_insert.nim b/tests/xml/ttree_insert.nim new file mode 100644 index 000000000..b2941395b --- /dev/null +++ b/tests/xml/ttree_insert.nim @@ -0,0 +1,53 @@ +discard """ + output: ''' + +
      Some text in body
      +
      Some more text in body
      + + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +var baseDocHead = """ + + +
      Some text
      +
      Some more text
      + +
      +""" +var baseDocHeadTree = parseXml(baseDocHead) +var baseDocBody = """ + +
      Some text in body
      +
      Some more text in body
      + +""" +var baseDocBodyTree = parseXml(baseDocBody) + +proc test_insert() = + var testDoc = baseDocHeadTree + var newBody = newElement("body") + var bodyItems: seq[XmlNode] = @[] + for item in baseDocBodyTree.items(): + bodyItems.insert(item, len(bodyItems)) + newBody.insert(bodyItems, 1) + + echo $newBody + + testDoc.insert(newBody, 1) + echo $testDoc + +test_insert() diff --git a/tests/xml/ttree_insert1.nim b/tests/xml/ttree_insert1.nim new file mode 100644 index 000000000..9aa3faf69 --- /dev/null +++ b/tests/xml/ttree_insert1.nim @@ -0,0 +1,51 @@ +discard """ + output: ''' + +
      Some text in body
      +
      Some more text in body
      + + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +var baseDocHead = """ + + +
      Some text
      +
      Some more text
      + +
      +""" +var baseDocHeadTree = parseXml(baseDocHead) +var baseDocBody = """ + +
      Some text in body
      +
      Some more text in body
      + +""" +var baseDocBodyTree = parseXml(baseDocBody) + +proc test_insert() = + var testDoc = baseDocHeadTree + var newBody = newElement("body") + for item in baseDocBodyTree.items(): + newBody.insert(item, len(newBody)) + + echo $newBody + + testDoc.insert(newBody, 1) + echo $testDoc + +test_insert() diff --git a/tests/xml/ttree_replace.nim b/tests/xml/ttree_replace.nim new file mode 100644 index 000000000..97d2db638 --- /dev/null +++ b/tests/xml/ttree_replace.nim @@ -0,0 +1,46 @@ +discard """ + output: ''' + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +var baseDocBody = """ + +
      Some text in body
      +
      Some more text in body
      + +""" +var baseDocBodyTree = parseXml(baseDocBody) +let initialDocBase = """ + + +
      Some text
      +
      Some more text
      + + +
      Some text in body before replace
      +
      Some more text in body before replace
      + +
      +""" +var initialDocBaseTree = parseXml(initialDocBase) + +proc test_replace() = + var testDoc = initialDocBaseTree + + testDoc.replace(1, @[baseDocBodyTree]) + echo $testDoc + +test_replace() diff --git a/tests/xml/ttree_replace1.nim b/tests/xml/ttree_replace1.nim new file mode 100644 index 000000000..059ce2085 --- /dev/null +++ b/tests/xml/ttree_replace1.nim @@ -0,0 +1,53 @@ +discard """ + output: ''' + + +
      Some text
      +
      Some more text
      + + +
      Some text in body
      +
      Some more text in body
      + +
      +''' +""" + +# Test xmltree add/insert/delete/replace operations +import xmlparser +import xmltree +var baseDocHead = """ + +
      Some text
      +
      Some more text
      + +""" +var baseDocHeadTree = parseXml(baseDocHead) +var baseDocBody = """ + +
      Some text in body
      +
      Some more text in body
      + +""" +var baseDocBodyTree = parseXml(baseDocBody) +let initialDocBase = """ + + +
      Some text before replace
      +
      Some more text before replace
      + + +
      Some text in body before replace
      +
      Some more text in body before replace
      + +
      +""" +var initialDocBaseTree = parseXml(initialDocBase) + +proc test_replace() = + var testDoc = initialDocBaseTree + + testDoc.replace(0..1, @[baseDocHeadTree, baseDocBodyTree]) + echo $testDoc + +test_replace() From 314a24472e83eedf058ffa614edf432e8744d0cb Mon Sep 17 00:00:00 2001 From: Peder Bergebakken Sundt Date: Thu, 22 Dec 2022 09:54:17 +0100 Subject: [PATCH 4091/4254] add link to setutils in system module docs (#21130) --- lib/system_overview.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/system_overview.rst b/lib/system_overview.rst index b338845d6..cc0643bf1 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -99,6 +99,7 @@ Proc Usage =============================== ====================================== **See also:** +* `setutils module `_ for bit set convenience functions * `sets module `_ for hash sets * `intsets module `_ for efficient int sets From 37daed389735ac66f5c950be9ee1c6658b019016 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 22 Dec 2022 11:54:41 +0300 Subject: [PATCH 4092/4254] remove misleading slimsystem deprecated warnings (#21156) refs #20967 --- lib/std/formatfloat.nim | 2 -- lib/system.nim | 3 --- 2 files changed, 5 deletions(-) diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim index 8abbe59cd..b216d1fd0 100644 --- a/lib/std/formatfloat.nim +++ b/lib/std/formatfloat.nim @@ -11,8 +11,6 @@ when defined(nimPreviewSlimSystem): import std/assertions -else: - {.deprecated: "formatfloat is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/formatfloat`".} proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "", discardable.} diff --git a/lib/system.nim b/lib/system.nim index 65055f145..1b6235fb3 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1630,7 +1630,6 @@ template newException*(exceptn: typedesc, message: string; (ref exceptn)(msg: message, parent: parentException) when not defined(nimPreviewSlimSystem): - {.deprecated: "assertions is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/assertions`".} import std/assertions export assertions @@ -2068,7 +2067,6 @@ when not defined(js): when hostOS != "standalone": include system/threadimpl when not defined(nimPreviewSlimSystem): - {.deprecated: "threads is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/typedthreads`".} import std/typedthreads export typedthreads @@ -2782,7 +2780,6 @@ when notJSnotNims: releaseSys echoLock when not defined(nimPreviewSlimSystem): - {.deprecated: "io is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/syncio`".} import std/syncio export syncio From 18c115c8d0b38e6dbb7fae5bdda94bfca1a0ecef Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 23 Dec 2022 00:44:10 +1100 Subject: [PATCH 4093/4254] Don't repeat suggestions for same symbol (#21140) * Track seen module graphs so symbols from the same module aren't repeated Add test case * Track symbols instead of modules * Don't show duplicate symbols in spell checker Removes the declared location from the message. Since we don't show duplicates anymore it would be a bit misleading if we only show the location for the first declaration of the symbol --- compiler/lookups.nim | 25 ++++++++++++++++++++----- compiler/suggest.nim | 6 +++--- tests/misc/tspellsuggest.nim | 30 +++++++++++++++--------------- tests/misc/tspellsuggest2.nim | 24 ++++++++++++------------ tests/misc/tspellsuggest3.nim | 21 +++++++++++++++++++++ 5 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 tests/misc/tspellsuggest3.nim diff --git a/compiler/lookups.nim b/compiler/lookups.nim index df5a5333e..d50fc6e27 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -15,7 +15,7 @@ when defined(nimPreviewSlimSystem): import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs + renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -170,6 +170,7 @@ iterator allSyms*(c: PContext): (PSym, int, bool) = # really iterate over all symbols in all the scopes. This is expensive # and only used by suggest.nim. var isLocal = true + var scopeN = 0 for scope in allScopes(c.currentScope): if scope == c.topLevelScope: isLocal = false @@ -184,6 +185,17 @@ iterator allSyms*(c: PContext): (PSym, int, bool) = assert s != nil yield (s, scopeN, isLocal) +iterator uniqueSyms*(c: PContext): (PSym, int, bool) = + ## Like [allSyms] except only returns unique symbols (Uniqueness determined by line + name) + # Track seen symbols so we don't duplicate them. + # The int is for the symbols name, and line info is + # to be able to tell apart symbols with same name but on different lines + var seen = initHashSet[(TLineInfo, int)]() + for res in allSyms(c): + if not seen.containsOrIncl((res[0].info, res[0].name.id)): + yield res + + proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym = var marked = initIntSet() var symSet = OverloadableSyms @@ -445,12 +457,13 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) = let dist = editDistance(name0, sym.name.s.nimIdentNormalize) var msg: string msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s] - addDeclaredLoc(msg, c.config, sym) # `msg` needed for deterministic ordering. list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym) if list.len == 0: return let e0 = list[0] - var count = 0 + var + count = 0 + last: PIdent = nil while true: # pending https://github.com/timotheecour/Nim/issues/373 use more efficient `itemsSorted`. if list.len == 0: break @@ -466,8 +479,10 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) = elif count >= c.config.spellSuggestMax: break if count == 0: result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': " - result.add e.msg - count.inc + if e.sym.name != last: + result.add e.msg + count.inc + last = e.sym.name proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PSym = var err = "ambiguous identifier: '" & s.name.s & "'" diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 41d39ccab..e0b0fb516 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -289,7 +289,7 @@ proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var s.getQuality, pm, c.inTypeContext > 0, 0)) template wholeSymTab(cond, section: untyped) {.dirty.} = - for (item, scopeN, isLocal) in allSyms(c): + for (item, scopeN, isLocal) in uniqueSyms(c): let it = item var pm: PrefixMatch if cond: @@ -362,7 +362,7 @@ proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Sugges proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = # do not produce too many symbols: - for (it, scopeN, isLocal) in allSyms(c): + for (it, scopeN, isLocal) in uniqueSyms(c): var pm: PrefixMatch if filterSym(it, f, pm): outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, n.info, @@ -680,7 +680,7 @@ proc suggestSentinel*(c: PContext) = inc(c.compilesContextId) var outputs: Suggestions = @[] # suggest everything: - for (it, scopeN, isLocal) in allSyms(c): + for (it, scopeN, isLocal) in uniqueSyms(c): var pm: PrefixMatch if filterSymNoOpr(it, nil, pm): outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, diff --git a/tests/misc/tspellsuggest.nim b/tests/misc/tspellsuggest.nim index 033ed0afc..345458bb1 100644 --- a/tests/misc/tspellsuggest.nim +++ b/tests/misc/tspellsuggest.nim @@ -5,21 +5,21 @@ discard """ nimout: ''' tspellsuggest.nim(45, 13) Error: undeclared identifier: 'fooBar' candidates (edit distance, scope distance); see '--spellSuggest': - (1, 0): 'fooBar8' [var declared in tspellsuggest.nim(43, 9)] - (1, 1): 'fooBar7' [var declared in tspellsuggest.nim(41, 7)] - (1, 3): 'fooBar1' [var declared in tspellsuggest.nim(33, 5)] - (1, 3): 'fooBar2' [let declared in tspellsuggest.nim(34, 5)] - (1, 3): 'fooBar3' [const declared in tspellsuggest.nim(35, 7)] - (1, 3): 'fooBar4' [proc declared in tspellsuggest.nim(36, 6)] - (1, 3): 'fooBar5' [template declared in tspellsuggest.nim(37, 10)] - (1, 3): 'fooBar6' [macro declared in tspellsuggest.nim(38, 7)] - (1, 5): 'FooBar' [type declared in mspellsuggest.nim(5, 6)] - (1, 5): 'fooBar4' [proc declared in mspellsuggest.nim(1, 6)] - (1, 5): 'fooBar9' [var declared in mspellsuggest.nim(2, 5)] - (1, 5): 'fooCar' [var declared in mspellsuggest.nim(4, 5)] - (2, 5): 'FooCar' [type declared in mspellsuggest.nim(6, 6)] - (2, 5): 'GooBa' [type declared in mspellsuggest.nim(7, 6)] - (3, 0): 'fooBarBaz' [const declared in tspellsuggest.nim(44, 11)] + (1, 0): 'fooBar8' + (1, 1): 'fooBar7' + (1, 3): 'fooBar1' + (1, 3): 'fooBar2' + (1, 3): 'fooBar3' + (1, 3): 'fooBar4' + (1, 3): 'fooBar5' + (1, 3): 'fooBar6' + (1, 5): 'FooBar' + (1, 5): 'fooBar4' + (1, 5): 'fooBar9' + (1, 5): 'fooCar' + (2, 5): 'FooCar' + (2, 5): 'GooBa' + (3, 0): 'fooBarBaz' ''' """ diff --git a/tests/misc/tspellsuggest2.nim b/tests/misc/tspellsuggest2.nim index 78504c513..bf76cc208 100644 --- a/tests/misc/tspellsuggest2.nim +++ b/tests/misc/tspellsuggest2.nim @@ -5,18 +5,18 @@ discard """ nimout: ''' tspellsuggest2.nim(45, 13) Error: undeclared identifier: 'fooBar' candidates (edit distance, scope distance); see '--spellSuggest': - (1, 0): 'fooBar8' [var declared in tspellsuggest2.nim(43, 9)] - (1, 1): 'fooBar7' [var declared in tspellsuggest2.nim(41, 7)] - (1, 3): 'fooBar1' [var declared in tspellsuggest2.nim(33, 5)] - (1, 3): 'fooBar2' [let declared in tspellsuggest2.nim(34, 5)] - (1, 3): 'fooBar3' [const declared in tspellsuggest2.nim(35, 7)] - (1, 3): 'fooBar4' [proc declared in tspellsuggest2.nim(36, 6)] - (1, 3): 'fooBar5' [template declared in tspellsuggest2.nim(37, 10)] - (1, 3): 'fooBar6' [macro declared in tspellsuggest2.nim(38, 7)] - (1, 5): 'FooBar' [type declared in mspellsuggest.nim(5, 6)] - (1, 5): 'fooBar4' [proc declared in mspellsuggest.nim(1, 6)] - (1, 5): 'fooBar9' [var declared in mspellsuggest.nim(2, 5)] - (1, 5): 'fooCar' [var declared in mspellsuggest.nim(4, 5)] + (1, 0): 'fooBar8' + (1, 1): 'fooBar7' + (1, 3): 'fooBar1' + (1, 3): 'fooBar2' + (1, 3): 'fooBar3' + (1, 3): 'fooBar4' + (1, 3): 'fooBar5' + (1, 3): 'fooBar6' + (1, 5): 'FooBar' + (1, 5): 'fooBar4' + (1, 5): 'fooBar9' + (1, 5): 'fooCar' ''' """ diff --git a/tests/misc/tspellsuggest3.nim b/tests/misc/tspellsuggest3.nim new file mode 100644 index 000000000..9b0b84602 --- /dev/null +++ b/tests/misc/tspellsuggest3.nim @@ -0,0 +1,21 @@ +discard """ + # pending bug #16521 (bug 12) use `matrix` + cmd: "nim c --spellsuggest:4 --hints:off $file" + action: "reject" + nimout: ''' +tspellsuggest3.nim(21, 1) Error: undeclared identifier: 'fooBar' +candidates (edit distance, scope distance); see '--spellSuggest': + (1, 2): 'FooBar' + (1, 2): 'fooBar4' + (1, 2): 'fooBar9' + (1, 2): 'fooCar' +''' +""" + +import ./mspellsuggest +import ./mspellsuggest +import ./mspellsuggest +import ./mspellsuggest + + +fooBar From 3bba2b34fd632a4c01a6eb0e6f13d4e3a20bf104 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Thu, 22 Dec 2022 13:43:27 -0700 Subject: [PATCH 4094/4254] fix socket send for string types (#21155) * fix socket send for string types * include windows version Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/pure/net.nim | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 1dfdbbbe6..be9f2e48c 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1735,15 +1735,36 @@ proc send*(socket: Socket, data: pointer, size: int): int {. result = send(socket.fd, data, size, int32(MSG_NOSIGNAL)) proc send*(socket: Socket, data: string, - flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} = - ## sends data to a socket. - let sent = send(socket, cstring(data), data.len) - if sent < 0: - let lastError = osLastError() - socketError(socket, lastError = lastError, flags = flags) + flags = {SocketFlag.SafeDisconn}, maxRetries = 100) {.tags: [WriteIOEffect].} = + ## Sends data to a socket. Will try to send all the data by handling interrupts + ## and incomplete writes up to `maxRetries`. + var written = 0 + var attempts = 0 + while data.len - written > 0: + let sent = send(socket, cstring(data), data.len) - if sent != data.len: - raiseOSError(osLastError(), "Could not send all data.") + if sent < 0: + let lastError = osLastError() + let isBlockingErr = + when defined(nimdoc): + false + elif useWinVersion: + lastError.int32 == WSAEINTR or + lastError.int32 == WSAEWOULDBLOCK + else: + lastError.int32 == EINTR or + lastError.int32 == EWOULDBLOCK or + lastError.int32 == EAGAIN + + if not isBlockingErr: + let lastError = osLastError() + socketError(socket, lastError = lastError, flags = flags) + else: + attempts.inc() + if attempts > maxRetries: + raiseOSError(osLastError(), "Could not send all data.") + else: + written.inc(sent) template `&=`*(socket: Socket; data: typed) = ## an alias for 'send'. From 13251c2ac9c7e76fb506eeb686a5e5d19d67d0de Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 23 Dec 2022 16:47:01 +0800 Subject: [PATCH 4095/4254] fix #12946 Bad C++ codegen on distinct generics C++ types (#21157) --- compiler/ccgtypes.nim | 9 +++++---- tests/cpp/t12946.nim | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 tests/cpp/t12946.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 3c9f9d923..e7677f2f2 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -826,7 +826,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin m.s[cfsTypes].addf("typedef $1 $2[$3];$n", [foo, result, rope(n)]) of tyObject, tyTuple: - if isImportedCppType(t) and origTyp.kind == tyGenericInst: + let tt = origTyp.skipTypes({tyDistinct}) + if isImportedCppType(t) and tt.kind == tyGenericInst: let cppNameAsRope = getTypeName(m, t, sig) let cppName = $cppNameAsRope var i = 0 @@ -849,7 +850,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin result.add cppName.substr(chunkStart, chunkEnd) chunkStart = i - let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars) + let typeInSlot = resolveStarsInCppType(tt, idx + 1, stars) addResultType(typeInSlot) else: inc i @@ -858,9 +859,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin result.add cppName.substr(chunkStart) else: result = cppNameAsRope & "<" - for i in 1.. 1: result.add(" COMMA ") - addResultType(origTyp[i]) + addResultType(tt[i]) result.add("> ") # always call for sideeffects: assert t.kind != tyTuple diff --git a/tests/cpp/t12946.nim b/tests/cpp/t12946.nim new file mode 100644 index 000000000..cf6bf5cfc --- /dev/null +++ b/tests/cpp/t12946.nim @@ -0,0 +1,4 @@ +import std/atomics +type Futex = distinct Atomic[int32] + +var x: Futex From ca9c74391a2169be0b0e5c7b6705eaf9560a44bd Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 23 Dec 2022 18:32:03 +0800 Subject: [PATCH 4096/4254] fix #11634 (#21146) --- compiler/semstmts.nim | 9 ++++++--- tests/misc/t11634.nim | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/misc/t11634.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a7a02d7fa..356c2d63e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -725,9 +725,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)): localError(c.config, a.info, errLetNeedsInit) if sfCompileTime in v.flags: - var x = newNodeI(result.kind, v.info) - x.add result[i] - vm.setupCompileTimeVar(c.module, c.idgen, c.graph, x) + if a.kind != nkVarTuple: + var x = newNodeI(result.kind, v.info) + x.add result[i] + vm.setupCompileTimeVar(c.module, c.idgen, c.graph, x) + else: + localError(c.config, a.info, "cannot destructure to compile time variable") if v.flags * {sfGlobal, sfThread} == {sfGlobal}: message(c.config, v.info, hintGlobalVar) if {sfGlobal, sfPure} <= v.flags: diff --git a/tests/misc/t11634.nim b/tests/misc/t11634.nim new file mode 100644 index 000000000..4ecb6a53c --- /dev/null +++ b/tests/misc/t11634.nim @@ -0,0 +1,20 @@ +discard """ + action: reject + nimout: ''' +t11634.nim(20, 7) Error: cannot destructure to compile time variable +''' +""" + +type Foo = ref object + val: int + +proc divmod(a, b: Foo): (Foo, Foo) = + ( + Foo(val: a.val div b.val), + Foo(val: a.val mod b.val) + ) + +block: + let a {.compileTime.} = Foo(val: 2) + let b {.compileTime.} = Foo(val: 3) + let (c11634 {.compileTime.}, d11634 {.compileTime.}) = divmod(a, b) From 0b319fee3de90759987beba289df3c48ab6d3f1a Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 23 Dec 2022 19:20:25 +0800 Subject: [PATCH 4097/4254] =?UTF-8?q?fix=20#20997=20calling=20system.card[?= =?UTF-8?q?T](x:=20set[T])=20with=20T=20of=20int8=20or=20uint8=20=E2=80=A6?= =?UTF-8?q?=20(#21010)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix #20997 calling system.card[T](x: set[T]) with T of int8 or uint8 uses mismatched C array sizes * fullfil set variant --- compiler/ccgexprs.nim | 2 +- lib/system/sets.nim | 8 +++++--- tests/sets/t20997.nim | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/sets/t20997.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2a4335144..d7ef024b1 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2126,7 +2126,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mCard: var a: TLoc initLocExpr(p, e[1], a) - putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size])) + putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size])) of mLtSet, mLeSet: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter initLocExpr(p, e[1], a) diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 103c8d343..e230985e0 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -10,10 +10,9 @@ # set handling type - NimSet = array[0..4*2048-1, uint8] + NimSet = array[0..8192-1, uint8] - -proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = +proc cardSetImpl(s: openArray[uint8], len: int): int {.inline.} = var i = 0 result = 0 when defined(x86) or defined(amd64): @@ -24,3 +23,6 @@ proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = while i < len: inc(result, countBits32(uint32(s[i]))) inc(i, 1) + +proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = + result = cardSetImpl(s, len) diff --git a/tests/sets/t20997.nim b/tests/sets/t20997.nim new file mode 100644 index 000000000..b320eee1a --- /dev/null +++ b/tests/sets/t20997.nim @@ -0,0 +1,18 @@ +discard """ + joinable: false +""" + +{.passC: "-flto".} +{.passL: "-flto".} + +template f(n: int) = discard card(default(set[range[0 .. (1 shl n) - 1]])) +f( 7) +f( 8) +f( 9) +f(10) +f(11) +f(12) +f(13) +f(14) +f(15) +f(16) From 0ffc322cf615685ae4d528e26ddd13f6ea072684 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 23 Dec 2022 22:31:53 +0800 Subject: [PATCH 4098/4254] add the cpp target (#21164) The issue is related to cpp codegen, the previous test doesn't test cpp backend, which will join into the megatest. --- tests/cpp/t12946.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cpp/t12946.nim b/tests/cpp/t12946.nim index cf6bf5cfc..79cd56251 100644 --- a/tests/cpp/t12946.nim +++ b/tests/cpp/t12946.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c cpp" +""" + import std/atomics type Futex = distinct Atomic[int32] From ac5a36c0a4be3de6565f2a071c04d1fd8f1b67da Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 23 Dec 2022 23:50:07 +0800 Subject: [PATCH 4099/4254] re and nre now link to regex and tinyre (#21161) --- lib/impure/nre.nim | 8 +++++--- lib/impure/re.nim | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index e9dd49df0..2c1b1deae 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -20,15 +20,17 @@ when defined(js): ## search the internet for a wide variety of third-party documentation and ## tools. ## -## **Note**: If you love `sequtils.toSeq` we have bad news for you. This -## library doesn't work with it due to documented compiler limitations. As -## a workaround, use this: +## .. warning:: If you love `sequtils.toSeq` we have bad news for you. This +## library doesn't work with it due to documented compiler limitations. As +## a workaround, use this: runnableExamples: # either `import std/nre except toSeq` or fully qualify `sequtils.toSeq`: import std/sequtils iterator iota(n: int): int = for i in 0.. Date: Sat, 24 Dec 2022 05:20:51 +1100 Subject: [PATCH 4100/4254] Make search results be relative to documentation root (#21145) Use Nim instead of JS for searching --- tools/dochack/dochack.nim | 48 ++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 4067d2ed4..0753248bc 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -1,5 +1,6 @@ import dom import fuzzysearch +import std/[jsfetch, asyncjs] proc setTheme(theme: cstring) {.exportc.} = @@ -252,21 +253,7 @@ proc escapeCString(x: var cstring) = proc dosearch(value: cstring): Element = if db.len == 0: - var stuff: Element - {.emit: """ - var request = new XMLHttpRequest(); - request.open("GET", document.getElementById("indexLink").href, false); - request.send(null); - - var doc = document.implementation.createHTMLDocument("theindex"); - doc.documentElement.innerHTML = request.responseText; - - `stuff` = doc.documentElement; - """.} - db = stuff.getElementsByClass"reference" - contents = @[] - for ahref in db: - contents.add ahref.getAttribute("data-doc-search-tag") + return let ul = tree("UL") result = tree("DIV") result.setClass"search_results" @@ -293,8 +280,28 @@ proc dosearch(value: cstring): Element = result.add tree("B", text"search results") result.add ul -var oldtoc: Element -var timer: Timeout +proc loadIndex() {.async.} = + ## Loads theindex.html to enable searching + let + indexURL = document.getElementById("indexLink").getAttribute("href") + # Get root of project documentation by cutting off theindex.html from index href + rootURL = ($indexURL)[0 ..< ^"theindex.html".len] + var resp = fetch(indexURL).await().text().await() + # Convert into element so we can use DOM functions to parse the html + var indexElem = document.createElement("div") + indexElem.innerHtml = resp + # Add items into the DB/contents + for href in indexElem.getElementsByClass("reference"): + # Make links be relative to project root instead of current page + href.setAttr("href", cstring(rootURL & $href.getAttribute("href"))) + db &= href + contents &= href.getAttribute("data-doc-search-tag") + + +var + oldtoc: Element + timer: Timeout + loadIndexFut: Future[void] = nil proc search*() {.exportc.} = proc wrapper() = @@ -307,7 +314,12 @@ proc search*() {.exportc.} = replaceById("tocRoot", results) elif not oldtoc.isNil: replaceById("tocRoot", oldtoc) - + # Start loading index as soon as user starts typing. + # Will only be loaded the once anyways + if loadIndexFut == nil: + loadIndexFut = loadIndex() + # Run wrapper once loaded so we don't miss the users query + discard loadIndexFut.then(wrapper) if timer != nil: clearTimeout(timer) timer = setTimeout(wrapper, 400) From 9323cb7b2a761543df9d875c05f4963c1a8b050f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 24 Dec 2022 17:37:32 +0800 Subject: [PATCH 4101/4254] enforce void for nkWhileStmt [backport: 2.0] (#21170) enforce void for nkWhileStmt --- compiler/semstmts.nim | 1 - tests/discard/tdiscardable.nim | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 356c2d63e..96883255c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -105,7 +105,6 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode = result.typ = n[1].typ elif implicitlyDiscardable(n[1]): result[1].typ = c.enforceVoidContext - result.typ = c.enforceVoidContext proc semProc(c: PContext, n: PNode): PNode diff --git a/tests/discard/tdiscardable.nim b/tests/discard/tdiscardable.nim index b13130a13..69cb9f6a1 100644 --- a/tests/discard/tdiscardable.nim +++ b/tests/discard/tdiscardable.nim @@ -99,3 +99,14 @@ block: # bug #13583 let t = test doAssert t() == 12 +block: + proc bar(): string {.discardable.} = + "15" + + proc foo(): int = + while true: + raise newException(ValueError, "check") + 12 + + doAssertRaises(ValueError): + doAssert foo() == 12 From b08c50bb553364eec1e20ab788d990b63f4548e0 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 26 Dec 2022 13:52:40 +0800 Subject: [PATCH 4102/4254] sync some changes from release notes (#21173) --- changelogs/changelog_2_0_0.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index a899bb929..614d97d85 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -2,7 +2,7 @@ ## Changes affecting backward compatibility -- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`. +- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`. - `addr` is now available for all addressable locations, `unsafeAddr` is now deprecated and an alias for `addr`. @@ -65,7 +65,7 @@ - `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and `sink` for optimization purposes. -- The `nimPreviewDotLikeOps` define is going to be removed or deprecated. +- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises. - The `{.this.}` pragma, deprecated since 0.19, has been removed. - `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead. @@ -110,8 +110,6 @@ - `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`. -- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details. - - Redefining templates with the same signature was previously allowed to support certain macro code. To do this explicitly, the `{.redefine.}` pragma has been added. Note that this is only for templates. From f7c203fb6c89b5cef83c4f326aeb23ef8c4a2c40 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 26 Dec 2022 20:20:05 +0800 Subject: [PATCH 4103/4254] remove legacy code (#21134) * remove legacy code * fixes --- compiler/astalgo.nim | 3 - compiler/cgen.nim | 2 - compiler/condsyms.nim | 47 +-- compiler/depends.nim | 3 - compiler/renderer.nim | 7 +- compiler/sem.nim | 3 - compiler/sigmatch.nim | 2 - compiler/vm.nim | 5 - compiler/vmops.nim | 72 +++-- lib/core/macros.nim | 9 +- lib/pure/collections/lists.nim | 3 - lib/pure/hashes.nim | 40 +-- lib/pure/json.nim | 540 ++++++++++++++++---------------- lib/pure/nimprof.nim | 3 +- lib/std/assertions.nim | 2 - lib/std/jsonutils.nim | 18 +- lib/std/private/miscdollars.nim | 16 +- lib/system.nim | 35 +-- lib/system/alloc.nim | 10 +- lib/system/arithm.nim | 425 ------------------------- lib/system/arithmetics.nim | 140 +++------ lib/system/compilation.nim | 40 +-- lib/system/fatal.nim | 5 +- lib/system/inclrtl.nim | 3 +- lib/system/iterators.nim | 2 +- lib/system/jssys.nim | 22 -- lib/system/strmantle.nim | 7 +- 27 files changed, 432 insertions(+), 1032 deletions(-) delete mode 100644 lib/system/arithm.nim diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index e9ed1497a..4e09fab02 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -20,9 +20,6 @@ import strutils except addf when defined(nimPreviewSlimSystem): import std/assertions -when not defined(nimHasCursor): - {.pragma: cursor.} - proc hashNode*(p: RootRef): Hash proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope # Convert a tree into its YAML representation; this is used by the diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e85cfd773..f6457f1e0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1929,8 +1929,6 @@ template injectG() {.dirty.} = graph.backend = newModuleList(graph) let g = BModuleList(graph.backend) -when not defined(nimHasSinkInference): - {.pragma: nosinks.} proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = injectG() diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 24c6d82d5..c05aaf10b 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -84,10 +84,24 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasSignatureHashInMacro") # deadcode defineSymbol("nimHasDefault") # deadcode defineSymbol("nimMacrosSizealignof") # deadcode + defineSymbol("nimNoZeroExtendMagic") # deadcode + defineSymbol("nimMacrosGetNodeId") # deadcode + defineSymbol("nimFixedForwardGeneric") # deadcode + defineSymbol("nimToOpenArrayCString") # deadcode + defineSymbol("nimHasUsed") # deadcode + defineSymbol("nimnomagic64") # deadcode + defineSymbol("nimNewShiftOps") # deadcode + defineSymbol("nimHasCursor") # deadcode + defineSymbol("nimAlignPragma") # deadcode + defineSymbol("nimHasExceptionsQuery") # deadcode + defineSymbol("nimHasIsNamedTuple") # deadcode + defineSymbol("nimHashOrdinalFixed") # deadcode + defineSymbol("nimHasSinkInference") # deadcode + defineSymbol("nimNewIntegerOps") # deadcode + defineSymbol("nimHasInvariant") # deadcode + + - # > 0.20.0 - defineSymbol("nimNoZeroExtendMagic") - defineSymbol("nimMacrosGetNodeId") for f in Feature: defineSymbol("nimHas" & $f) @@ -98,31 +112,18 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimFixedOwned") defineSymbol("nimHasStyleChecks") - defineSymbol("nimToOpenArrayCString") - defineSymbol("nimHasUsed") - defineSymbol("nimFixedForwardGeneric") - defineSymbol("nimnomagic64") - defineSymbol("nimNewShiftOps") - defineSymbol("nimHasCursor") - defineSymbol("nimAlignPragma") - defineSymbol("nimHasExceptionsQuery") - defineSymbol("nimHasIsNamedTuple") - defineSymbol("nimHashOrdinalFixed") when defined(nimHasLibFFI): # Renaming as we can't conflate input vs output define flags; e.g. this # will report the right thing regardless of whether user adds # `-d:nimHasLibFFI` in his user config. - defineSymbol("nimHasLibFFIEnabled") + defineSymbol("nimHasLibFFIEnabled") # deadcode - defineSymbol("nimHasSinkInference") - defineSymbol("nimNewIntegerOps") - defineSymbol("nimHasInvariant") - defineSymbol("nimHasStacktraceMsgs") + defineSymbol("nimHasStacktraceMsgs") # deadcode defineSymbol("nimDoesntTrackDefects") - defineSymbol("nimHasLentIterators") - defineSymbol("nimHasDeclaredMagic") - defineSymbol("nimHasStacktracesModule") + defineSymbol("nimHasLentIterators") # deadcode + defineSymbol("nimHasDeclaredMagic") # deadcode + defineSymbol("nimHasStacktracesModule") # deadcode defineSymbol("nimHasEffectTraitsModule") defineSymbol("nimHasCastPragmaBlocks") defineSymbol("nimHasDeclaredLocs") @@ -133,8 +134,8 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasCustomLiterals") defineSymbol("nimHasUnifiedTuple") defineSymbol("nimHasIterable") - defineSymbol("nimHasTypeofVoid") - defineSymbol("nimHasDragonBox") + defineSymbol("nimHasTypeofVoid") # deadcode + defineSymbol("nimHasDragonBox") # deadcode defineSymbol("nimHasHintAll") defineSymbol("nimHasTrace") defineSymbol("nimHasEffectsOf") diff --git a/compiler/depends.nim b/compiler/depends.nim index 93f34dc7c..59cdc0330 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -100,9 +100,6 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) = rope(project.splitFile.name), b.dotGraph], changeFileExt(project, "dot")) -when not defined(nimHasSinkInference): - {.pragma: nosinks.} - proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = var g: PGen new(g) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index cd0d83eb0..87a5e6580 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -9,10 +9,9 @@ # This module implements the renderer of the standard Nim representation. -when defined(nimHasUsed): - # 'import renderer' is so useful for debugging - # that Nim shouldn't produce a warning for that: - {.used.} +# 'import renderer' is so useful for debugging +# that Nim shouldn't produce a warning for that: +{.used.} import lexer, options, idents, strutils, ast, msgs, lineinfos diff --git a/compiler/sem.nim b/compiler/sem.nim index 1f8e217b3..f5283fa3d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -405,9 +405,6 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedTyp evaluated = evalAtCompileTime(c, result) if evaluated != nil: return evaluated -when not defined(nimHasSinkInference): - {.pragma: nosinks.} - include hlo, seminst, semcall proc resetSemFlag(n: PNode) = diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 61a4395f3..d05503c00 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2661,8 +2661,6 @@ proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool = # pattern templates do not allow for conversions except from int literal res != nil and m.convMatches == 0 and m.intConvMatches in [0, 256] -when not defined(nimHasSinkInference): - {.pragma: nosinks.} proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; op: TTypeAttachedOp; col: int): PSym {.nosinks.} = diff --git a/compiler/vm.nim b/compiler/vm.nim index 61261c44c..d87fa33ba 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -32,8 +32,6 @@ const when hasFFI: import evalffi -when not defined(nimHasCursor): - {.pragma: cursor.} proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = if x != nil: @@ -533,9 +531,6 @@ template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool = else: false -when not defined(nimHasSinkInference): - {.pragma: nosinks.} - template takeAddress(reg, source) = reg.nodeAddr = addr source GC_ref source diff --git a/compiler/vmops.nim b/compiler/vmops.nim index d4a91b22d..bb943b8a0 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -141,41 +141,40 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode = for k, f in walkDir(path, relative): result.add toLit((k, f)) -when defined(nimHasInvariant): - from std / compilesettings import SingleValueSetting, MultipleValueSetting +from std / compilesettings import SingleValueSetting, MultipleValueSetting - proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string = - {.push warning[Deprecated]:off.} - case SingleValueSetting(switch) - of arguments: result = conf.arguments - of outFile: result = conf.outFile.string - of outDir: result = conf.outDir.string - of nimcacheDir: result = conf.getNimcacheDir().string - of projectName: result = conf.projectName - of projectPath: result = conf.projectPath.string - of projectFull: result = conf.projectFull.string - of command: result = conf.command - of commandLine: result = conf.commandLine - of linkOptions: result = conf.linkOptions - of compileOptions: result = conf.compileOptions - of ccompilerPath: result = conf.cCompilerPath - of backend: result = $conf.backend - of libPath: result = conf.libpath.string - of gc: result = $conf.selectedGC - of mm: result = $conf.selectedGC - {.pop.} +proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string = + {.push warning[Deprecated]:off.} + case SingleValueSetting(switch) + of arguments: result = conf.arguments + of outFile: result = conf.outFile.string + of outDir: result = conf.outDir.string + of nimcacheDir: result = conf.getNimcacheDir().string + of projectName: result = conf.projectName + of projectPath: result = conf.projectPath.string + of projectFull: result = conf.projectFull.string + of command: result = conf.command + of commandLine: result = conf.commandLine + of linkOptions: result = conf.linkOptions + of compileOptions: result = conf.compileOptions + of ccompilerPath: result = conf.cCompilerPath + of backend: result = $conf.backend + of libPath: result = conf.libpath.string + of gc: result = $conf.selectedGC + of mm: result = $conf.selectedGC + {.pop.} - proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = - template copySeq(field: untyped): untyped = - for i in field: result.add i.string +proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = + template copySeq(field: untyped): untyped = + for i in field: result.add i.string - case MultipleValueSetting(switch) - of nimblePaths: copySeq(conf.nimblePaths) - of searchPaths: copySeq(conf.searchPaths) - of lazyPaths: copySeq(conf.lazyPaths) - of commandArgs: result = conf.commandArgs - of cincludes: copySeq(conf.cIncludes) - of clibs: copySeq(conf.cLibs) + case MultipleValueSetting(switch) + of nimblePaths: copySeq(conf.nimblePaths) + of searchPaths: copySeq(conf.searchPaths) + of lazyPaths: copySeq(conf.lazyPaths) + of commandArgs: result = conf.commandArgs + of cincludes: copySeq(conf.cIncludes) + of clibs: copySeq(conf.cLibs) proc stackTrace2(c: PCtx, msg: string, n: PNode) = stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info) @@ -257,11 +256,10 @@ proc registerAdditionalOps*(c: PCtx) = systemop getCurrentException registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) - when defined(nimHasInvariant): - registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) = - setResult(a, querySettingImpl(c.config, getInt(a, 0))) - registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) = - setResult(a, querySettingSeqImpl(c.config, getInt(a, 0))) + registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) = + setResult(a, querySettingImpl(c.config, getInt(a, 0))) + registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) = + setResult(a, querySettingSeqImpl(c.config, getInt(a, 0))) if defined(nimsuggest) or c.config.cmd == cmdCheck: discard "don't run staticExec for 'nim suggest'" diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 138ec47a0..bcc16038b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1519,11 +1519,10 @@ proc boolVal*(n: NimNode): bool {.noSideEffect.} = if n.kind == nnkIntLit: n.intVal != 0 else: n == bindSym"true" # hacky solution for now -when defined(nimMacrosGetNodeId): - proc nodeID*(n: NimNode): int {.magic: "NodeId".} - ## Returns the id of `n`, when the compiler has been compiled - ## with the flag `-d:useNodeids`, otherwise returns `-1`. This - ## proc is for the purpose to debug the compiler only. +proc nodeID*(n: NimNode): int {.magic: "NodeId".} + ## Returns the id of `n`, when the compiler has been compiled + ## with the flag `-d:useNodeids`, otherwise returns `-1`. This + ## proc is for the purpose to debug the compiler only. macro expandMacros*(body: typed): untyped = ## Expands one level of macro - useful for debugging. diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 829ec2ccb..a08c62964 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -62,9 +62,6 @@ import std/private/since when defined(nimPreviewSlimSystem): import std/assertions -when not defined(nimHasCursor): - {.pragma: cursor.} - type DoublyLinkedNodeObj*[T] = object ## A node of a doubly linked list. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index e88210757..09e072812 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -380,16 +380,10 @@ proc hash*(x: string): Hash = runnableExamples: doAssert hash("abracadabra") != hash("AbracadabrA") - when not defined(nimToOpenArrayCString): - result = 0 - for c in x: - result = result !& ord(c) - result = !$result + when nimvm: + result = hashVmImpl(x, 0, high(x)) else: - when nimvm: - result = hashVmImpl(x, 0, high(x)) - else: - result = murmurHash(toOpenArrayByte(x, 0, high(x))) + result = murmurHash(toOpenArrayByte(x, 0, high(x))) proc hash*(x: cstring): Hash = ## Efficient hashing of null-terminated strings. @@ -398,22 +392,14 @@ proc hash*(x: cstring): Hash = doAssert hash(cstring"AbracadabrA") == hash("AbracadabrA") doAssert hash(cstring"abracadabra") != hash(cstring"AbracadabrA") - when not defined(nimToOpenArrayCString): - result = 0 - var i = 0 - while x[i] != '\0': - result = result !& ord(x[i]) - inc i - result = !$result + when nimvm: + hashVmImpl(x, 0, high(x)) else: - when nimvm: - hashVmImpl(x, 0, high(x)) + when not defined(js): + murmurHash(toOpenArrayByte(x, 0, x.high)) else: - when not defined(js) and defined(nimToOpenArrayCString): - murmurHash(toOpenArrayByte(x, 0, x.high)) - else: - let xx = $x - murmurHash(toOpenArrayByte(xx, 0, high(xx))) + let xx = $x + murmurHash(toOpenArrayByte(xx, 0, high(xx))) proc hash*(sBuf: string, sPos, ePos: int): Hash = ## Efficient hashing of a string buffer, from starting @@ -424,13 +410,7 @@ proc hash*(sBuf: string, sPos, ePos: int): Hash = var a = "abracadabra" doAssert hash(a, 0, 3) == hash(a, 7, 10) - when not defined(nimToOpenArrayCString): - result = 0 - for i in sPos..ePos: - result = result !& ord(sBuf[i]) - result = !$result - else: - murmurHash(toOpenArrayByte(sBuf, sPos, ePos)) + murmurHash(toOpenArrayByte(sBuf, sPos, ePos)) proc hashIgnoreStyle*(x: string): Hash = ## Efficient hashing of strings; style is ignored. diff --git a/lib/pure/json.nim b/lib/pure/json.nim index d0b1a4051..78d6bd5bd 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1059,310 +1059,308 @@ template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind], ] raise newException(JsonKindError, msg) -when defined(nimFixedForwardGeneric): +macro isRefSkipDistinct*(arg: typed): untyped = + ## internal only, do not use + var impl = getTypeImpl(arg) + if impl.kind == nnkBracketExpr and impl[0].eqIdent("typeDesc"): + impl = getTypeImpl(impl[1]) + while impl.kind == nnkDistinctTy: + impl = getTypeImpl(impl[0]) + result = newLit(impl.kind == nnkRefTy) - macro isRefSkipDistinct*(arg: typed): untyped = - ## internal only, do not use - var impl = getTypeImpl(arg) - if impl.kind == nnkBracketExpr and impl[0].eqIdent("typeDesc"): - impl = getTypeImpl(impl[1]) - while impl.kind == nnkDistinctTy: - impl = getTypeImpl(impl[0]) - result = newLit(impl.kind == nnkRefTy) +# The following forward declarations don't work in older versions of Nim - # The following forward declarations don't work in older versions of Nim +# forward declare all initFromJson - # forward declare all initFromJson +proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) +proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[S, T](dst: var array[S, T]; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T](dst: var Table[string, T]; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T](dst: var OrderedTable[string, T]; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) +proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) - proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[S, T](dst: var array[S, T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var Table[string, T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var OrderedTable[string, T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) - proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) +# initFromJson definitions - # initFromJson definitions +proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JString, JNull}, jsonPath) + # since strings don't have a nil state anymore, this mapping of + # JNull to the default string is questionable. `none(string)` and + # `some("")` have the same potentional json value `JNull`. + if jsonNode.kind == JNull: + dst = "" + else: + dst = jsonNode.str - proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JString, JNull}, jsonPath) - # since strings don't have a nil state anymore, this mapping of - # JNull to the default string is questionable. `none(string)` and - # `some("")` have the same potentional json value `JNull`. - if jsonNode.kind == JNull: - dst = "" +proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JBool}, jsonPath) + dst = jsonNode.bval + +proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = + if jsonNode == nil: + raise newException(KeyError, "key not found: " & jsonPath) + dst = jsonNode.copy + +proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = + when T is uint|uint64 or (not defined(js) and int.sizeof == 4): + verifyJsonKind(jsonNode, {JInt, JString}, jsonPath) + case jsonNode.kind + of JString: + let x = parseBiggestUInt(jsonNode.str) + dst = cast[T](x) else: - dst = jsonNode.str + dst = T(jsonNode.num) + else: + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = cast[T](jsonNode.num) - proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JBool}, jsonPath) - dst = jsonNode.bval - - proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = - if jsonNode == nil: - raise newException(KeyError, "key not found: " & jsonPath) - dst = jsonNode.copy - - proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - when T is uint|uint64 or (not defined(js) and int.sizeof == 4): - verifyJsonKind(jsonNode, {JInt, JString}, jsonPath) - case jsonNode.kind - of JString: - let x = parseBiggestUInt(jsonNode.str) - dst = cast[T](x) - else: - dst = T(jsonNode.num) +proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + if jsonNode.kind == JString: + case jsonNode.str + of "nan": + let b = NaN + dst = T(b) + # dst = NaN # would fail some tests because range conversions would cause CT error + # in some cases; but this is not a hot-spot inside this branch and backend can optimize this. + of "inf": + let b = Inf + dst = T(b) + of "-inf": + let b = -Inf + dst = T(b) + else: raise newException(JsonKindError, "expected 'nan|inf|-inf', got " & jsonNode.str) + else: + verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) + if jsonNode.kind == JFloat: + dst = T(jsonNode.fnum) else: - verifyJsonKind(jsonNode, {JInt}, jsonPath) - dst = cast[T](jsonNode.num) + dst = T(jsonNode.num) - proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - if jsonNode.kind == JString: - case jsonNode.str - of "nan": - let b = NaN - dst = T(b) - # dst = NaN # would fail some tests because range conversions would cause CT error - # in some cases; but this is not a hot-spot inside this branch and backend can optimize this. - of "inf": - let b = Inf - dst = T(b) - of "-inf": - let b = -Inf - dst = T(b) - else: raise newException(JsonKindError, "expected 'nan|inf|-inf', got " & jsonNode.str) +proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JString}, jsonPath) + dst = parseEnum[T](jsonNode.getStr) + +proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JArray}, jsonPath) + dst.setLen jsonNode.len + let orignalJsonPathLen = jsonPath.len + for i in 0 ..< jsonNode.len: + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + initFromJson(dst[i], jsonNode[i], jsonPath) + jsonPath.setLen orignalJsonPathLen + +proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JArray}, jsonPath) + let originalJsonPathLen = jsonPath.len + for i in 0 ..< jsonNode.len: + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + initFromJson(dst[i.S], jsonNode[i], jsonPath) # `.S` for enum indexed arrays + jsonPath.setLen originalJsonPathLen + +proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) = + dst = initTable[string, T]() + verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len + for key in keys(jsonNode.fields): + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen + +proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) = + dst = initOrderedTable[string,T]() + verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len + for key in keys(jsonNode.fields): + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen + +proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath) + if jsonNode.kind == JNull: + dst = nil + else: + dst = new(T) + initFromJson(dst[], jsonNode, jsonPath) + +proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) = + if jsonNode != nil and jsonNode.kind != JNull: + when T is ref: + dst = some(new(T)) else: - verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) - if jsonNode.kind == JFloat: - dst = T(jsonNode.fnum) - else: - dst = T(jsonNode.num) + dst = some(default(T)) + initFromJson(dst.get, jsonNode, jsonPath) - proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JString}, jsonPath) - dst = parseEnum[T](jsonNode.getStr) +macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = + let typInst = getTypeInst(dst) + let typImpl = getTypeImpl(dst) + let baseTyp = typImpl[0] - proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JArray}, jsonPath) - dst.setLen jsonNode.len - let orignalJsonPathLen = jsonPath.len - for i in 0 ..< jsonNode.len: - jsonPath.add '[' - jsonPath.addInt i - jsonPath.add ']' - initFromJson(dst[i], jsonNode[i], jsonPath) - jsonPath.setLen orignalJsonPathLen - - proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JArray}, jsonPath) - let originalJsonPathLen = jsonPath.len - for i in 0 ..< jsonNode.len: - jsonPath.add '[' - jsonPath.addInt i - jsonPath.add ']' - initFromJson(dst[i.S], jsonNode[i], jsonPath) # `.S` for enum indexed arrays - jsonPath.setLen originalJsonPathLen - - proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) = - dst = initTable[string, T]() - verifyJsonKind(jsonNode, {JObject}, jsonPath) - let originalJsonPathLen = jsonPath.len - for key in keys(jsonNode.fields): - jsonPath.add '.' - jsonPath.add key - initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) - jsonPath.setLen originalJsonPathLen - - proc initFromJson[T](dst: var OrderedTable[string,T]; jsonNode: JsonNode; jsonPath: var string) = - dst = initOrderedTable[string,T]() - verifyJsonKind(jsonNode, {JObject}, jsonPath) - let originalJsonPathLen = jsonPath.len - for key in keys(jsonNode.fields): - jsonPath.add '.' - jsonPath.add key - initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) - jsonPath.setLen originalJsonPathLen - - proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = - verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath) - if jsonNode.kind == JNull: - dst = nil + result = quote do: + when nimvm: + # workaround #12282 + var tmp: `baseTyp` + initFromJson( tmp, `jsonNode`, `jsonPath`) + `dst` = `typInst`(tmp) else: - dst = new(T) - initFromJson(dst[], jsonNode, jsonPath) + initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) - proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) = - if jsonNode != nil and jsonNode.kind != JNull: - when T is ref: - dst = some(new(T)) - else: - dst = some(default(T)) - initFromJson(dst.get, jsonNode, jsonPath) +proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + assignDistinctImpl(dst, jsonNode, jsonPath) - macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = - let typInst = getTypeInst(dst) - let typImpl = getTypeImpl(dst) - let baseTyp = typImpl[0] +proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode) = + if typeExpr.kind == nnkTupleConstr: + error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) - result = quote do: +proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathLen: NimNode) = + case typeNode.kind + of nnkEmpty: + discard + of nnkRecList, nnkTupleTy: + for it in typeNode: + foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, originalJsonPathLen) + + of nnkIdentDefs: + typeNode.expectLen 3 + let fieldSym = typeNode[0] + let fieldNameLit = newLit(fieldSym.strVal) + let fieldPathLit = newLit("." & fieldSym.strVal) + let fieldType = typeNode[1] + + # Detecting incompatiple tuple types in `assignObjectImpl` only + # would be much cleaner, but the ast for tuple types does not + # contain usable type information. + detectIncompatibleType(fieldType, fieldSym) + + dst.add quote do: + jsonPath.add `fieldPathLit` when nimvm: - # workaround #12282 - var tmp: `baseTyp` - initFromJson( tmp, `jsonNode`, `jsonPath`) - `dst` = `typInst`(tmp) - else: - initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) - - proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - assignDistinctImpl(dst, jsonNode, jsonPath) - - proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode) = - if typeExpr.kind == nnkTupleConstr: - error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) - - proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathLen: NimNode) = - case typeNode.kind - of nnkEmpty: - discard - of nnkRecList, nnkTupleTy: - for it in typeNode: - foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, originalJsonPathLen) - - of nnkIdentDefs: - typeNode.expectLen 3 - let fieldSym = typeNode[0] - let fieldNameLit = newLit(fieldSym.strVal) - let fieldPathLit = newLit("." & fieldSym.strVal) - let fieldType = typeNode[1] - - # Detecting incompatiple tuple types in `assignObjectImpl` only - # would be much cleaner, but the ast for tuple types does not - # contain usable type information. - detectIncompatibleType(fieldType, fieldSym) - - dst.add quote do: - jsonPath.add `fieldPathLit` - when nimvm: - when isRefSkipDistinct(`tmpSym`.`fieldSym`): - # workaround #12489 - var tmp: `fieldType` - initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) - `tmpSym`.`fieldSym` = tmp - else: - initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + when isRefSkipDistinct(`tmpSym`.`fieldSym`): + # workaround #12489 + var tmp: `fieldType` + initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + `tmpSym`.`fieldSym` = tmp else: initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) - jsonPath.setLen `originalJsonPathLen` + else: + initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + jsonPath.setLen `originalJsonPathLen` - of nnkRecCase: - let kindSym = typeNode[0][0] - let kindNameLit = newLit(kindSym.strVal) - let kindPathLit = newLit("." & kindSym.strVal) - let kindType = typeNode[0][1] - let kindOffsetLit = newLit(uint(getOffset(kindSym))) - dst.add quote do: - var kindTmp: `kindType` - jsonPath.add `kindPathLit` - initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`) - jsonPath.setLen `originalJsonPathLen` - when defined js: + of nnkRecCase: + let kindSym = typeNode[0][0] + let kindNameLit = newLit(kindSym.strVal) + let kindPathLit = newLit("." & kindSym.strVal) + let kindType = typeNode[0][1] + let kindOffsetLit = newLit(uint(getOffset(kindSym))) + dst.add quote do: + var kindTmp: `kindType` + jsonPath.add `kindPathLit` + initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`) + jsonPath.setLen `originalJsonPathLen` + when defined js: + `tmpSym`.`kindSym` = kindTmp + else: + when nimvm: `tmpSym`.`kindSym` = kindTmp else: - when nimvm: - `tmpSym`.`kindSym` = kindTmp - else: - # fuck it, assign kind field anyway - ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp - dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) - for i in 1 ..< typeNode.len: - foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, originalJsonPathLen) + # fuck it, assign kind field anyway + ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp + dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) + for i in 1 ..< typeNode.len: + foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, originalJsonPathLen) - of nnkOfBranch, nnkElse: - let ofBranch = newNimNode(typeNode.kind) - for i in 0 ..< typeNode.len-1: - ofBranch.add copyNimTree(typeNode[i]) - let dstInner = newNimNode(nnkStmtListExpr) - foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, originalJsonPathLen) - # resOuter now contains the inner stmtList - ofBranch.add dstInner - dst[^1].expectKind nnkCaseStmt - dst[^1].add ofBranch + of nnkOfBranch, nnkElse: + let ofBranch = newNimNode(typeNode.kind) + for i in 0 ..< typeNode.len-1: + ofBranch.add copyNimTree(typeNode[i]) + let dstInner = newNimNode(nnkStmtListExpr) + foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, originalJsonPathLen) + # resOuter now contains the inner stmtList + ofBranch.add dstInner + dst[^1].expectKind nnkCaseStmt + dst[^1].add ofBranch - of nnkObjectTy: - typeNode[0].expectKind nnkEmpty - typeNode[1].expectKind {nnkEmpty, nnkOfInherit} - if typeNode[1].kind == nnkOfInherit: - let base = typeNode[1][0] - var impl = getTypeImpl(base) - while impl.kind in {nnkRefTy, nnkPtrTy}: - impl = getTypeImpl(impl[0]) - foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, originalJsonPathLen) - let body = typeNode[2] - foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, originalJsonPathLen) + of nnkObjectTy: + typeNode[0].expectKind nnkEmpty + typeNode[1].expectKind {nnkEmpty, nnkOfInherit} + if typeNode[1].kind == nnkOfInherit: + let base = typeNode[1][0] + var impl = getTypeImpl(base) + while impl.kind in {nnkRefTy, nnkPtrTy}: + impl = getTypeImpl(impl[0]) + foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, originalJsonPathLen) + let body = typeNode[2] + foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, originalJsonPathLen) - else: - error("unhandled kind: " & $typeNode.kind, typeNode) + else: + error("unhandled kind: " & $typeNode.kind, typeNode) - macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - let typeSym = getTypeInst(dst) - let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen") - result = newStmtList() - result.add quote do: - let `originalJsonPathLen` = len(`jsonPath`) - if typeSym.kind in {nnkTupleTy, nnkTupleConstr}: - # both, `dst` and `typeSym` don't have good lineinfo. But nothing - # else is available here. - detectIncompatibleType(typeSym, dst) - foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, originalJsonPathLen) - else: - foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen) +macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + let typeSym = getTypeInst(dst) + let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen") + result = newStmtList() + result.add quote do: + let `originalJsonPathLen` = len(`jsonPath`) + if typeSym.kind in {nnkTupleTy, nnkTupleConstr}: + # both, `dst` and `typeSym` don't have good lineinfo. But nothing + # else is available here. + detectIncompatibleType(typeSym, dst) + foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, originalJsonPathLen) + else: + foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen) - proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = - assignObjectImpl(dst, jsonNode, jsonPath) +proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + assignObjectImpl(dst, jsonNode, jsonPath) - proc to*[T](node: JsonNode, t: typedesc[T]): T = - ## `Unmarshals`:idx: the specified node into the object type specified. - ## - ## Known limitations: - ## - ## * Heterogeneous arrays are not supported. - ## * Sets in object variants are not supported. - ## * Not nil annotations are not supported. - ## - runnableExamples: - let jsonNode = parseJson(""" - { - "person": { - "name": "Nimmer", - "age": 21 - }, - "list": [1, 2, 3, 4] - } - """) +proc to*[T](node: JsonNode, t: typedesc[T]): T = + ## `Unmarshals`:idx: the specified node into the object type specified. + ## + ## Known limitations: + ## + ## * Heterogeneous arrays are not supported. + ## * Sets in object variants are not supported. + ## * Not nil annotations are not supported. + ## + runnableExamples: + let jsonNode = parseJson(""" + { + "person": { + "name": "Nimmer", + "age": 21 + }, + "list": [1, 2, 3, 4] + } + """) - type - Person = object - name: string - age: int + type + Person = object + name: string + age: int - Data = object - person: Person - list: seq[int] + Data = object + person: Person + list: seq[int] - var data = to(jsonNode, Data) - doAssert data.person.name == "Nimmer" - doAssert data.person.age == 21 - doAssert data.list == @[1, 2, 3, 4] + var data = to(jsonNode, Data) + doAssert data.person.name == "Nimmer" + doAssert data.person.age == 21 + doAssert data.list == @[1, 2, 3, 4] - var jsonPath = "" - initFromJson(result, node, jsonPath) + var jsonPath = "" + initFromJson(result, node, jsonPath) when false: import os diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 7f493418e..9849e42db 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -15,8 +15,7 @@ when not defined(profiler) and not defined(memProfiler): {.error: "Profiling support is turned off! Enable profiling by passing `--profiler:on --stackTrace:on` to the compiler (see the Nim Compiler User Guide for more options).".} -when defined(nimHasUsed): - {.used.} +{.used.} # We don't want to profile the profiling code ... {.push profiler: off.} diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim index 5623ff8ef..229033c58 100644 --- a/lib/std/assertions.nim +++ b/lib/std/assertions.nim @@ -23,8 +23,6 @@ proc `$`(info: InstantiationInfo): string = # --------------------------------------------------------------------------- -when not defined(nimHasSinkInference): - {.pragma: nosinks.} proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = ## Raises an `AssertionDefect` with `msg`. diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index eec8dea7d..17d08e02e 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -37,22 +37,8 @@ from typetraits import OrdinalEnum, tupleLen when defined(nimPreviewSlimSystem): import std/assertions -when not defined(nimFixedForwardGeneric): - # xxx remove pending csources_v1 update >= 1.2.0 - proc to[T](node: JsonNode, t: typedesc[T]): T = - when T is string: node.getStr - elif T is bool: node.getBool - else: static: doAssert false, $T # support as needed (only needed during bootstrap) - proc isNamedTuple(T: typedesc): bool = # old implementation - when T isnot tuple: result = false - else: - var t: T - for name, _ in t.fieldPairs: - when name == "Field0": return compiles(t.Field0) - else: return true - return false -else: - proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} + +proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} type Joptions* = object # xxx rename FromJsonOptions diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim index 47b788ee9..06fda6fa1 100644 --- a/lib/std/private/miscdollars.nim +++ b/lib/std/private/miscdollars.nim @@ -13,21 +13,7 @@ template toLocation*(result: var string, file: string | cstring, line: int, col: addInt(result, col) result.add ")" -when defined(nimHasIsNamedTuple): - proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} -else: - # for bootstrap; remove after release 1.2 - proc isNamedTuple(T: typedesc): bool = - # Taken from typetraits. - when T isnot tuple: result = false - else: - var t: T - for name, _ in t.fieldPairs: - when name == "Field0": - return compiles(t.Field0) - else: - return true - return false +proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} template tupleObjectDollar*[T: tuple | object](result: var string, x: T) = result = "(" diff --git a/lib/system.nim b/lib/system.nim index 1b6235fb3..e9c9ebfeb 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -85,17 +85,12 @@ when defined(nimHasIterable): type iterable*[T] {.magic: IterableType.} ## Represents an expression that yields `T` -when defined(nimHashOrdinalFixed): - type - Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, - ## bool, character, and enumeration types - ## as well as their subtypes. See also - ## `SomeOrdinal`. -else: - # bootstrap < 1.2.0 - type - OrdinalImpl[T] {.magic: Ordinal.} - Ordinal* = OrdinalImpl | uint | uint64 +type + Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, + ## bool, character, and enumeration types + ## as well as their subtypes. See also + ## `SomeOrdinal`. + proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory location. @@ -451,9 +446,7 @@ type ## However, objects that have no ancestor are also allowed. RootRef* = ref RootObj ## Reference to `RootObj`. -const NimStackTraceMsgs = - when defined(nimHasStacktraceMsgs): compileOption("stacktraceMsgs") - else: false +const NimStackTraceMsgs = compileOption("stacktraceMsgs") type RootEffect* {.compilerproc.} = object of RootObj ## \ @@ -2113,10 +2106,7 @@ when notJSnotNims: # we cannot compile this with stack tracing on # as it would recurse endlessly! - when defined(nimNewIntegerOps): - include "system/integerops" - else: - include "system/arithm" + include "system/integerops" {.pop.} @@ -2660,11 +2650,10 @@ when defined(nimconfig): when not defined(js): proc toOpenArray*[T](x: ptr UncheckedArray[T]; first, last: int): openArray[T] {. magic: "Slice".} - when defined(nimToOpenArrayCString): - proc toOpenArray*(x: cstring; first, last: int): openArray[char] {. - magic: "Slice".} - proc toOpenArrayByte*(x: cstring; first, last: int): openArray[byte] {. - magic: "Slice".} + proc toOpenArray*(x: cstring; first, last: int): openArray[char] {. + magic: "Slice".} + proc toOpenArrayByte*(x: cstring; first, last: int): openArray[byte] {. + magic: "Slice".} proc toOpenArray*[T](x: seq[T]; first, last: int): openArray[T] {. magic: "Slice".} diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 5d1548977..cee70f677 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -95,17 +95,11 @@ type acc: int # accumulator for small object allocation when defined(gcDestructors): sharedFreeList: ptr FreeCell # make no attempt at avoiding false sharing for now for this object field - when defined(nimAlignPragma): - data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory - else: - data: UncheckedArray[byte] + data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory BigChunk = object of BaseChunk # not necessarily > PageSize! next, prev: PBigChunk # chunks of the same (or bigger) size - when defined(nimAlignPragma): - data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory - else: - data: UncheckedArray[byte] + data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory HeapLinks = object len: int diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim deleted file mode 100644 index 158f40177..000000000 --- a/lib/system/arithm.nim +++ /dev/null @@ -1,425 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - - -# simple integer arithmetic with overflow checking - -proc raiseOverflow {.compilerproc, noinline.} = - # a single proc to reduce code size to a minimum - sysFatal(OverflowDefect, "over- or underflow") - -proc raiseDivByZero {.compilerproc, noinline.} = - sysFatal(DivByZeroDefect, "division by zero") - -when defined(builtinOverflow): - # Builtin compiler functions for improved performance - when sizeof(clong) == 8: - proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. - importc: "__builtin_saddl_overflow", nodecl, nosideeffect.} - - proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. - importc: "__builtin_ssubl_overflow", nodecl, nosideeffect.} - - proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. - importc: "__builtin_smull_overflow", nodecl, nosideeffect.} - - elif sizeof(clonglong) == 8: - proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. - importc: "__builtin_saddll_overflow", nodecl, nosideeffect.} - - proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. - importc: "__builtin_ssubll_overflow", nodecl, nosideeffect.} - - proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. - importc: "__builtin_smulll_overflow", nodecl, nosideeffect.} - - when sizeof(int) == 8: - proc addIntOverflow(a, b: int, c: var int): bool {.inline.} = - addInt64Overflow(a, b, c) - - proc subIntOverflow(a, b: int, c: var int): bool {.inline.} = - subInt64Overflow(a, b, c) - - proc mulIntOverflow(a, b: int, c: var int): bool {.inline.} = - mulInt64Overflow(a, b, c) - - elif sizeof(int) == 4 and sizeof(cint) == 4: - proc addIntOverflow(a, b: int, c: var int): bool {. - importc: "__builtin_sadd_overflow", nodecl, nosideeffect.} - - proc subIntOverflow(a, b: int, c: var int): bool {. - importc: "__builtin_ssub_overflow", nodecl, nosideeffect.} - - proc mulIntOverflow(a, b: int, c: var int): bool {. - importc: "__builtin_smul_overflow", nodecl, nosideeffect.} - - proc addInt64(a, b: int64): int64 {.compilerproc, inline.} = - if addInt64Overflow(a, b, result): - raiseOverflow() - - proc subInt64(a, b: int64): int64 {.compilerproc, inline.} = - if subInt64Overflow(a, b, result): - raiseOverflow() - - proc mulInt64(a, b: int64): int64 {.compilerproc, inline.} = - if mulInt64Overflow(a, b, result): - raiseOverflow() -else: - proc addInt64(a, b: int64): int64 {.compilerproc, inline.} = - result = a +% b - if (result xor a) >= int64(0) or (result xor b) >= int64(0): - return result - raiseOverflow() - - proc subInt64(a, b: int64): int64 {.compilerproc, inline.} = - result = a -% b - if (result xor a) >= int64(0) or (result xor not b) >= int64(0): - return result - raiseOverflow() - - # - # This code has been inspired by Python's source code. - # The native int product x*y is either exactly right or *way* off, being - # just the last n bits of the true product, where n is the number of bits - # in an int (the delivered product is the true product plus i*2**n for - # some integer i). - # - # The native float64 product x*y is subject to three - # rounding errors: on a sizeof(int)==8 box, each cast to double can lose - # info, and even on a sizeof(int)==4 box, the multiplication can lose info. - # But, unlike the native int product, it's not in *range* trouble: even - # if sizeof(int)==32 (256-bit ints), the product easily fits in the - # dynamic range of a float64. So the leading 50 (or so) bits of the float64 - # product are correct. - # - # We check these two ways against each other, and declare victory if they're - # approximately the same. Else, because the native int product is the only - # one that can lose catastrophic amounts of information, it's the native int - # product that must have overflowed. - # - proc mulInt64(a, b: int64): int64 {.compilerproc.} = - var - resAsFloat, floatProd: float64 - result = a *% b - floatProd = toBiggestFloat(a) # conversion - floatProd = floatProd * toBiggestFloat(b) - resAsFloat = toBiggestFloat(result) - - # Fast path for normal case: small multiplicands, and no info - # is lost in either method. - if resAsFloat == floatProd: return result - - # Somebody somewhere lost info. Close enough, or way off? Note - # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). - # The difference either is or isn't significant compared to the - # true value (of which floatProd is a good approximation). - - # abs(diff)/abs(prod) <= 1/32 iff - # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" - if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): - return result - raiseOverflow() - -proc negInt64(a: int64): int64 {.compilerproc, inline.} = - if a != low(int64): return -a - raiseOverflow() - -proc absInt64(a: int64): int64 {.compilerproc, inline.} = - if a != low(int64): - if a >= 0: return a - else: return -a - raiseOverflow() - -proc divInt64(a, b: int64): int64 {.compilerproc, inline.} = - if b == int64(0): - raiseDivByZero() - if a == low(int64) and b == int64(-1): - raiseOverflow() - return a div b - -proc modInt64(a, b: int64): int64 {.compilerproc, inline.} = - if b == int64(0): - raiseDivByZero() - return a mod b - -proc absInt(a: int): int {.compilerproc, inline.} = - if a != low(int): - if a >= 0: return a - else: return -a - raiseOverflow() - -const - asmVersion = defined(i386) and (defined(vcc) or defined(wcc) or - defined(dmc) or defined(gcc) or defined(llvm_gcc)) - # my Version of Borland C++Builder does not have - # tasm32, which is needed for assembler blocks - # this is why Borland is not included in the 'when' - -when asmVersion and not defined(gcc) and not defined(llvm_gcc): - # assembler optimized versions for compilers that - # have an intel syntax assembler: - proc addInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = - # a in eax, and b in edx - asm """ - mov eax, ecx - add eax, edx - jno theEnd - call `raiseOverflow` - theEnd: - ret - """ - - proc subInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - mov eax, ecx - sub eax, edx - jno theEnd - call `raiseOverflow` - theEnd: - ret - """ - - proc negInt(a: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - mov eax, ecx - neg eax - jno theEnd - call `raiseOverflow` - theEnd: - ret - """ - - proc divInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - test edx, edx - jne L_NOT_ZERO - call `raiseDivByZero` - L_NOT_ZERO: - cmp ecx, 0x80000000 - jne L_DO_DIV - cmp edx, -1 - jne L_DO_DIV - call `raiseOverflow` - L_DO_DIV: - mov eax, ecx - mov ecx, edx - cdq - idiv ecx - ret - """ - - proc modInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - test edx, edx - jne L_NOT_ZERO - call `raiseDivByZero` - L_NOT_ZERO: - cmp ecx, 0x80000000 - jne L_DO_DIV - cmp edx, -1 - jne L_DO_DIV - call `raiseOverflow` - L_DO_DIV: - mov eax, ecx - mov ecx, edx - cdq - idiv ecx - mov eax, edx - ret - """ - - proc mulInt(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - mov eax, ecx - mov ecx, edx - xor edx, edx - imul ecx - jno theEnd - call `raiseOverflow` - theEnd: - ret - """ - -elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)): - proc addInt(a, b: int): int {.compilerproc, inline.} = - # don't use a pure proc here! - asm """ - "addl %%ecx, %%eax\n" - "jno 1\n" - "call _raiseOverflow\n" - "1: \n" - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - """ - #".intel_syntax noprefix" - #/* Intel syntax here */ - #".att_syntax" - - proc subInt(a, b: int): int {.compilerproc, inline.} = - asm """ "subl %%ecx,%%eax\n" - "jno 1\n" - "call _raiseOverflow\n" - "1: \n" - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - """ - - proc mulInt(a, b: int): int {.compilerproc, inline.} = - asm """ "xorl %%edx, %%edx\n" - "imull %%ecx\n" - "jno 1\n" - "call _raiseOverflow\n" - "1: \n" - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - :"%edx" - """ - - proc negInt(a: int): int {.compilerproc, inline.} = - asm """ "negl %%eax\n" - "jno 1\n" - "call _raiseOverflow\n" - "1: \n" - :"=a"(`result`) - :"a"(`a`) - """ - - proc divInt(a, b: int): int {.compilerproc, inline.} = - asm """ "xorl %%edx, %%edx\n" - "idivl %%ecx\n" - "jno 1\n" - "call _raiseOverflow\n" - "1: \n" - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - :"%edx" - """ - - proc modInt(a, b: int): int {.compilerproc, inline.} = - asm """ "xorl %%edx, %%edx\n" - "idivl %%ecx\n" - "jno 1\n" - "call _raiseOverflow\n" - "1: \n" - "movl %%edx, %%eax" - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - :"%edx" - """ - -when not declared(addInt) and defined(builtinOverflow): - proc addInt(a, b: int): int {.compilerproc, inline.} = - if addIntOverflow(a, b, result): - raiseOverflow() - -when not declared(subInt) and defined(builtinOverflow): - proc subInt(a, b: int): int {.compilerproc, inline.} = - if subIntOverflow(a, b, result): - raiseOverflow() - -when not declared(mulInt) and defined(builtinOverflow): - proc mulInt(a, b: int): int {.compilerproc, inline.} = - if mulIntOverflow(a, b, result): - raiseOverflow() - -# Platform independent versions of the above (slower!) -when not declared(addInt): - proc addInt(a, b: int): int {.compilerproc, inline.} = - result = a +% b - if (result xor a) >= 0 or (result xor b) >= 0: - return result - raiseOverflow() - -when not declared(subInt): - proc subInt(a, b: int): int {.compilerproc, inline.} = - result = a -% b - if (result xor a) >= 0 or (result xor not b) >= 0: - return result - raiseOverflow() - -when not declared(negInt): - proc negInt(a: int): int {.compilerproc, inline.} = - if a != low(int): return -a - raiseOverflow() - -when not declared(divInt): - proc divInt(a, b: int): int {.compilerproc, inline.} = - if b == 0: - raiseDivByZero() - if a == low(int) and b == -1: - raiseOverflow() - return a div b - -when not declared(modInt): - proc modInt(a, b: int): int {.compilerproc, inline.} = - if b == 0: - raiseDivByZero() - return a mod b - -when not declared(mulInt): - # - # This code has been inspired by Python's source code. - # The native int product x*y is either exactly right or *way* off, being - # just the last n bits of the true product, where n is the number of bits - # in an int (the delivered product is the true product plus i*2**n for - # some integer i). - # - # The native float64 product x*y is subject to three - # rounding errors: on a sizeof(int)==8 box, each cast to double can lose - # info, and even on a sizeof(int)==4 box, the multiplication can lose info. - # But, unlike the native int product, it's not in *range* trouble: even - # if sizeof(int)==32 (256-bit ints), the product easily fits in the - # dynamic range of a float64. So the leading 50 (or so) bits of the float64 - # product are correct. - # - # We check these two ways against each other, and declare victory if - # they're approximately the same. Else, because the native int product is - # the only one that can lose catastrophic amounts of information, it's the - # native int product that must have overflowed. - # - proc mulInt(a, b: int): int {.compilerproc.} = - var - resAsFloat, floatProd: float - - result = a *% b - floatProd = toFloat(a) * toFloat(b) - resAsFloat = toFloat(result) - - # Fast path for normal case: small multiplicands, and no info - # is lost in either method. - if resAsFloat == floatProd: return result - - # Somebody somewhere lost info. Close enough, or way off? Note - # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). - # The difference either is or isn't significant compared to the - # true value (of which floatProd is a good approximation). - - # abs(diff)/abs(prod) <= 1/32 iff - # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" - if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): - return result - raiseOverflow() - -# We avoid setting the FPU control word here for compatibility with libraries -# written in other languages. - -proc raiseFloatInvalidOp {.compilerproc, noinline.} = - sysFatal(FloatInvalidOpDefect, "FPU operation caused a NaN result") - -proc nanCheck(x: float64) {.compilerproc, inline.} = - if x != x: raiseFloatInvalidOp() - -proc raiseFloatOverflow(x: float64) {.compilerproc, noinline.} = - if x > 0.0: - sysFatal(FloatOverflowDefect, "FPU operation caused an overflow") - else: - sysFatal(FloatUnderflowDefect, "FPU operations caused an underflow") - -proc infCheck(x: float64) {.compilerproc, inline.} = - if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x) diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index d05aaaa5b..5c21e56ef 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -405,105 +405,57 @@ proc `%%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) mod cast proc `%%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) mod cast[uint64](y)) when not defined(nimPreviewSlimSystem): - when defined(nimNoZeroExtendMagic): - proc ze*(x: int8): int {.deprecated.} = - ## zero extends a smaller integer type to `int`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int](uint(cast[uint8](x))) + proc ze*(x: int8): int {.deprecated.} = + ## zero extends a smaller integer type to `int`. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int](uint(cast[uint8](x))) - proc ze*(x: int16): int {.deprecated.} = - ## zero extends a smaller integer type to `int`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int](uint(cast[uint16](x))) + proc ze*(x: int16): int {.deprecated.} = + ## zero extends a smaller integer type to `int`. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int](uint(cast[uint16](x))) - proc ze64*(x: int8): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint8](x))) + proc ze64*(x: int8): int64 {.deprecated.} = + ## zero extends a smaller integer type to `int64`. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint8](x))) - proc ze64*(x: int16): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint16](x))) + proc ze64*(x: int16): int64 {.deprecated.} = + ## zero extends a smaller integer type to `int64`. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint16](x))) - proc ze64*(x: int32): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint32](x))) + proc ze64*(x: int32): int64 {.deprecated.} = + ## zero extends a smaller integer type to `int64`. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint32](x))) - proc ze64*(x: int): int64 {.deprecated.} = - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. Does nothing if the size of an `int` is the same as `int64`. - ## (This is the case on 64 bit processors.) - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint](x))) + proc ze64*(x: int): int64 {.deprecated.} = + ## zero extends a smaller integer type to `int64`. This treats `x` as + ## unsigned. Does nothing if the size of an `int` is the same as `int64`. + ## (This is the case on 64 bit processors.) + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint](x))) - proc toU8*(x: int): int8 {.deprecated.} = - ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits - ## from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int8](x) + proc toU8*(x: int): int8 {.deprecated.} = + ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits + ## from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int8](x) - proc toU16*(x: int): int16 {.deprecated.} = - ## treats `x` as unsigned and converts it to an `int16` by taking the last - ## 16 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int16](x) + proc toU16*(x: int): int16 {.deprecated.} = + ## treats `x` as unsigned and converts it to an `int16` by taking the last + ## 16 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int16](x) - proc toU32*(x: int64): int32 {.deprecated.} = - ## treats `x` as unsigned and converts it to an `int32` by taking the - ## last 32 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int32](x) - - elif not defined(js): - proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect, deprecated.} - ## zero extends a smaller integer type to `int`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect, deprecated.} - ## zero extends a smaller integer type to `int`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to `int64`. This treats `x` as - ## unsigned. Does nothing if the size of an `int` is the same as `int64`. - ## (This is the case on 64 bit processors.) - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits - ## from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to an `int16` by taking the last - ## 16 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to an `int32` by taking the - ## last 32 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + proc toU32*(x: int64): int32 {.deprecated.} = + ## treats `x` as unsigned and converts it to an `int32` by taking the + ## last 32 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int32](x) diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim index 234e8cafe..c04990277 100644 --- a/lib/system/compilation.nim +++ b/lib/system/compilation.nim @@ -51,30 +51,24 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## * `compileOption <#compileOption,string,string>`_ for enum options ## * `define pragmas `_ -when defined(nimHasDeclaredMagic): - proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} - ## Special compile-time procedure that checks whether `x` is - ## declared. `x` has to be an identifier or a qualified identifier. - ## - ## This can be used to check whether a library provides a certain - ## feature or not: - ## ``` - ## when not declared(strutils.toUpper): - ## # provide our own toUpper proc here, because strutils is - ## # missing it. - ## ``` - ## - ## See also: - ## * `declaredInScope <#declaredInScope,untyped>`_ -else: - proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} +proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} + ## Special compile-time procedure that checks whether `x` is + ## declared. `x` has to be an identifier or a qualified identifier. + ## + ## This can be used to check whether a library provides a certain + ## feature or not: + ## ``` + ## when not declared(strutils.toUpper): + ## # provide our own toUpper proc here, because strutils is + ## # missing it. + ## ``` + ## + ## See also: + ## * `declaredInScope <#declaredInScope,untyped>`_ -when defined(nimHasDeclaredMagic): - proc declaredInScope*(x: untyped): bool {.magic: "DeclaredInScope", noSideEffect, compileTime.} - ## Special compile-time procedure that checks whether `x` is - ## declared in the current scope. `x` has to be an identifier. -else: - proc declaredInScope*(x: untyped): bool {.magic: "DefinedInScope", noSideEffect, compileTime.} +proc declaredInScope*(x: untyped): bool {.magic: "DeclaredInScope", noSideEffect, compileTime.} + ## Special compile-time procedure that checks whether `x` is + ## declared in the current scope. `x` has to be an identifier. proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} = ## Special compile-time procedure that checks whether `x` can be compiled diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index a55af2dc3..6073ee779 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -9,10 +9,7 @@ {.push profiler: off.} -when defined(nimHasExceptionsQuery): - const gotoBasedExceptions = compileOption("exceptions", "goto") -else: - const gotoBasedExceptions = false +const gotoBasedExceptions = compileOption("exceptions", "goto") when hostOS == "standalone": include "$projectpath/panicoverride" diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 42c85ad26..3bf0b9893 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -47,5 +47,4 @@ else: {.pragma: benign, gcsafe.} -when defined(nimHasSinkInference): - {.push sinkInference: on.} +{.push sinkInference: on.} diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index b16a605b7..4bd12680f 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -3,7 +3,7 @@ when defined(nimPreviewSlimSystem): import std/assertions -when defined(nimHasLentIterators) and not defined(nimNoLentIterators): +when not defined(nimNoLentIterators): template lent2(T): untyped = lent T else: template lent2(T): untyped = T diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 9dfa80877..4f64403fe 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -503,28 +503,6 @@ proc absInt(a: int): int {.compilerproc.} = proc absInt64(a: int64): int64 {.compilerproc.} = result = if a < 0: a*(-1) else: a -when not defined(nimNoZeroExtendMagic): - proc ze*(a: int): int {.compilerproc.} = - result = a - - proc ze64*(a: int64): int64 {.compilerproc.} = - result = a - - proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} = - asm """ - return `a`; - """ - - proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} = - asm """ - return `a`; - """ - - proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} = - asm """ - return `a`; - """ - proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index 0b2578280..f4733ed21 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -75,8 +75,8 @@ const 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22] -when defined(nimHasInvariant): - {.push staticBoundChecks: off.} + +{.push staticBoundChecks: off.} proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, ): int {.compilerproc.} = @@ -234,8 +234,7 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, t[ti-3] = ('0'.ord + absExponent mod 10).char number = c_strtod(cast[cstring](addr t), nil) -when defined(nimHasInvariant): - {.pop.} # staticBoundChecks +{.pop.} # staticBoundChecks proc nimBoolToStr(x: bool): string {.compilerRtl.} = return if x: "true" else: "false" From 9b4516fbcb4ad9c5db1e6f563601855f0e9982a0 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Tue, 27 Dec 2022 01:13:05 -0300 Subject: [PATCH 4104/4254] fix in msg `doAssert()` to update grammar.txt (#21179) --- compiler/parser.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 00013c218..0c8edd2a8 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -42,7 +42,7 @@ when isMainModule or defined(nimTestGrammar): proc checkSameGrammar*() = doAssert sameFileContent(newGrammarText, "doc/grammar.txt"), - "execute 'nim r compiler.nim' to keep grammar.txt up-to-date" + "execute 'nim r compiler/parser.nim' to keep grammar.txt up-to-date" else: writeGrammarFile("doc/grammar.txt") import ".." / tools / grammar_nanny From f232329bb12fc9d93fe1e09769e291eae4e2953d Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 27 Dec 2022 19:07:15 +0800 Subject: [PATCH 4105/4254] add test case for #20289 (#21180) --- tests/misc/t20289.nim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/misc/t20289.nim diff --git a/tests/misc/t20289.nim b/tests/misc/t20289.nim new file mode 100644 index 000000000..5a0a269f0 --- /dev/null +++ b/tests/misc/t20289.nim @@ -0,0 +1,15 @@ +discard """ + action: reject +""" + +type E[T] = object + v: T + +template j[T](R: type E[T], x: untyped): R = R(v: x) +template d[T](O: type E, v: T): E[T] = E[T].j(v) + +proc w[T](): E[T] = + template r(k: int): auto = default(T) + E.d r + +discard w[int]() From 82d80e6e2cb09652e15d8ec81621bba734872aaa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 27 Dec 2022 14:30:26 +0100 Subject: [PATCH 4106/4254] atlas: minor doc improvements (#21183) * closes #20808 * atlas: better docs --- tools/atlas/atlas.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index a36817dc5..ee770cd62 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -28,7 +28,7 @@ a `nim.cfg` file for the compiler. For example: ``` The version selection is deterministic, it picks up the *minimum* required -version. Thanks to this design, lock files are not required. +version. Thanks to this design, lock files are much less important. ## Dependencies @@ -75,3 +75,7 @@ then `clone ` is performed. Search the package index `packages.json` for a package that the given terms in its description (or name or list of tags). + +### Install + +Use the .nimble file to setup the project's dependencies. From 56840931355fdf8ce12a59ad085d90b04404f831 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 27 Dec 2022 23:24:00 +0300 Subject: [PATCH 4107/4254] fix for bad error message with const in case statement (#21182) * preliminary fix for bad error message with const * add test case * fix tmatrixconcept and tmatrixlib --- compiler/semfold.nim | 4 ++++ tests/errmsgs/tconstinfo.nim | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/errmsgs/tconstinfo.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 7c57eb370..7f966c6fd 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -569,6 +569,8 @@ proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode else: result = copyTree(s.astdef) # unreachable else: result = copyTree(s.astdef) + if result != nil: + result.info = n.info proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = result = nil @@ -593,6 +595,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode result = foldDefine(m, s, n, idgen, g) else: result = copyTree(s.astdef) + if result != nil: + result.info = n.info of skProc, skFunc, skMethod: result = n of skParam: diff --git a/tests/errmsgs/tconstinfo.nim b/tests/errmsgs/tconstinfo.nim new file mode 100644 index 000000000..170972b9f --- /dev/null +++ b/tests/errmsgs/tconstinfo.nim @@ -0,0 +1,7 @@ +# https://forum.nim-lang.org/t/9762 + +const foo = "abc" +case 'a' +of foo: echo "should error" #[tt.Error + ^ type mismatch: got but expected 'char']# +else: discard From 9e35631191ad67994bb45cfad4d9452f790534e0 Mon Sep 17 00:00:00 2001 From: Phil Krylov Date: Wed, 28 Dec 2022 03:26:52 +0100 Subject: [PATCH 4108/4254] std/encodings: Fix open() documentation in regard to exception raised (#21187) --- lib/pure/encodings.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 26b6e1f22..0d7e878e5 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -339,7 +339,7 @@ proc getCurrentEncoding*(uiApp = false): string = proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter = ## Opens a converter that can convert from `srcEncoding` to `destEncoding`. - ## Raises `IOError` if it cannot fulfill the request. + ## Raises `EncodingError` if it cannot fulfill the request. when not defined(windows): result = iconvOpen(destEncoding, srcEncoding) if result == nil: From 9efa56a8bbacab2075a4c2fe4c5424d57b6eab46 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Tue, 27 Dec 2022 23:40:17 -0300 Subject: [PATCH 4109/4254] [backport: 2.0] prevents the jsonscript command from exceeding the maximum length of a command line during linking (#21186) --- compiler/extccomp.nim | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 66de46556..6515f6968 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -851,6 +851,17 @@ proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string = else: result = MsgKindToStr[hintCC] % demangleModuleName(path.splitFile.name) +proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) = + # Prevent linkcmd from exceeding the maximum command line length. + # Windows's command line limit is about 8K (8191 characters) so C compilers on + # Windows support a feature where the command line can be passed via ``@linkcmd`` + # to them. + const MaxCmdLen = when defined(windows): 8_000 else: 32_000 + if linkCmd.len > MaxCmdLen: + linkViaResponseFile(conf, linkCmd) + else: + execLinkCmd(conf, linkCmd) + proc callCCompiler*(conf: ConfigRef) = var linkCmd: string @@ -927,14 +938,7 @@ proc callCCompiler*(conf: ConfigRef) = linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true) extraCmds = getExtraCmds(conf, mainOutput) if optCompileOnly notin conf.globalOptions: - const MaxCmdLen = when defined(windows): 8_000 else: 32_000 - if linkCmd.len > MaxCmdLen: - # Windows's command line limit is about 8K (don't laugh...) so C compilers on - # Windows support a feature where the command line can be passed via ``@linkcmd`` - # to them. - linkViaResponseFile(conf, linkCmd) - else: - execLinkCmd(conf, linkCmd) + preventLinkCmdMaxCmdLen(conf, linkCmd) for cmd in extraCmds: execExternalProgram(conf, cmd, hintExecuting) else: @@ -1035,7 +1039,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = cmds.add cmd prettyCmds.add displayProgressCC(conf, name, cmd) execCmdsInParallel(conf, cmds, prettyCb) - execLinkCmd(conf, bcache.linkcmd) + preventLinkCmdMaxCmdLen(conf, bcache.linkcmd) for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting) proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = From 3d5dbf8f96a5106a3b817a45a926303bc5623786 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Wed, 28 Dec 2022 17:35:11 +1100 Subject: [PATCH 4110/4254] Fix nimsuggest not suggesting fields in when theres static parameters (#21189) Don't check against empty arguments Add test case --- compiler/sigmatch.nim | 2 +- nimsuggest/tests/t21185.nim | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 nimsuggest/tests/t21185.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d05503c00..68068cd26 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2055,7 +2055,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, a.n == nil and tfGenericTypeParam notin a.flags: return newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg)) - else: + elif arg.kind != nkEmpty: var evaluated = c.semTryConstExpr(c, arg) if evaluated != nil: # Don't build the type in-place because `evaluated` and `arg` may point diff --git a/nimsuggest/tests/t21185.nim b/nimsuggest/tests/t21185.nim new file mode 100644 index 000000000..bf5a0e3cc --- /dev/null +++ b/nimsuggest/tests/t21185.nim @@ -0,0 +1,18 @@ + +# Reduced case of 21185. Issue was first parameter being static +proc foo(x: static[int]) = discard + +type + Person = object + name: string + age: int + +let p = Person() +p.#[!]# + +discard """ +$nimsuggest --tester --v3 --maxresults:2 $file +>sug $1 +sug;;skField;;age;;int;;$file;;8;;4;;"";;100;;None +sug;;skField;;name;;string;;$file;;7;;4;;"";;100;;None +""" From 7a74c2dc3a82488671237555faa95fb38ef31bd5 Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 28 Dec 2022 15:28:48 +0800 Subject: [PATCH 4111/4254] fix #14667 (#21190) --- compiler/ccgexprs.nim | 4 ++++ compiler/cgendata.nim | 1 + tests/misc/t14667.nim | 12 ++++++++++++ 3 files changed, 17 insertions(+) create mode 100644 tests/misc/t14667.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index d7ef024b1..e2885a294 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3200,6 +3200,8 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = result.add "}" of tyTuple: result.add "{" + if p.vccAndC and t.len == 0: + result.add "0" for i in 0.. 0: result.add ", " getDefaultValue(p, t[i], info, result) @@ -3338,6 +3340,8 @@ proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) = proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Rope) = result.add "{" + if p.vccAndC and n.len == 0: + result.add "0" for i in 0.. 0: result.add ",\n" diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 2daa8da7c..f75598652 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -172,6 +172,7 @@ type template config*(m: BModule): ConfigRef = m.g.config template config*(p: BProc): ConfigRef = p.module.g.config +template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC proc includeHeader*(this: BModule; header: string) = if not this.headerFiles.contains header: diff --git a/tests/misc/t14667.nim b/tests/misc/t14667.nim new file mode 100644 index 000000000..3034e2841 --- /dev/null +++ b/tests/misc/t14667.nim @@ -0,0 +1,12 @@ +discard """ + matrix: "--cc:vcc" + disabled: "linux" + disabled: "bsd" + disabled: "osx" + disabled: "unix" + disabled: "posix" +""" + +type A = tuple +discard () +discard default(A) From 4b63ac4b87c54a1b31d60b7555e2c60d232817c8 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 28 Dec 2022 23:23:37 +0800 Subject: [PATCH 4112/4254] fixes #21171; dynamic acyclic refs need to use dyn decRef (#21184) * fixes #21171; dyn destructors for acyclic inherited refs * add a test * Update compiler/liftdestructors.nim --- compiler/liftdestructors.nim | 7 ++++ lib/system/orc.nim | 13 ++++++ tests/arc/t21184.nim | 77 ++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 tests/arc/t21184.nim diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 5174a908f..2b27a58fc 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -609,6 +609,11 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen) let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType) + let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and + (not isPureObject(elemType)) and + tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags + # dynamic Acyclic refs need to use dyn decRef + let tmp = if isCyclic and c.kind in {attachedAsgn, attachedSink}: declareTempOf(c, body, x) @@ -632,6 +637,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo) else: cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp) + elif isInheritableAcyclicRef: + cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x) else: cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x) cond.typ = getSysType(c.g, x.info, tyBool) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 83b983ee1..a56a0c057 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -485,6 +485,19 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = #if cell.color == colPurple: rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[]) +proc nimDecRefIsLastDyn(p: pointer): bool {.compilerRtl, inl.} = + if p != nil: + var cell = head(p) + if (cell.rc and not rcMask) == 0: + result = true + #cprintf("[DESTROY] %p\n", p) + else: + dec cell.rc, rcIncrement + #if cell.color == colPurple: + if result: + if cell.rootIdx > 0: + unregisterCycle(cell) + proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} = if p != nil: var cell = head(p) diff --git a/tests/arc/t21184.nim b/tests/arc/t21184.nim new file mode 100644 index 000000000..91d0c42c7 --- /dev/null +++ b/tests/arc/t21184.nim @@ -0,0 +1,77 @@ +discard """ + matrix: "--mm:orc" +""" + +import std/[with] + +type + Node* {.acyclic.} = ref object of RootObj + name: string + data: pointer + children: seq[Node] + TextNode = ref object of Node + text: string + +proc fakeEcho(s: string) = + if s.len < 0: + echo s + +proc newNode[T: Node](parent: Node): T = + new result + result.data = alloc0(250) + parent.children.add(result) + +proc newRootNode(): Node = + new result + result.data = alloc0(250) + +method printNode(node: Node) {.base.} = + fakeEcho node.name + +method printNode(node: TextNode) = + procCall printNode(Node(node)) + fakeEcho node.text + +proc printChildren(node: Node) = + for child in node.children: + child.printNode() + printChildren(child) + +proc free(node: Node) = + for child in node.children: + free(child) + dealloc(node.data) + +template node(parent: Node, body: untyped): untyped = + var node = newNode[Node](parent) + with node: + body + +proc textNode(parent: Node, text: string) = + var node = newNode[TextNode](parent) + node.text = text + +template withRootNode(body: untyped): untyped = + var root = newRootNode() + root.name = "root" + with root: + body + root.printNode() + printChildren(root) + root.free() + +proc doTest() = + withRootNode: + node: + name = "child1" + node: + name = "child2" + node: + name = "child3" + textNode "Hello, world!" + + +# bug #21171 +if isMainModule: + for i in 0..100000: + doTest() From 646932b3f316d6b8e3ceb6b94b9d01232d5cdb33 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 29 Dec 2022 03:41:27 +0800 Subject: [PATCH 4113/4254] fixes warnings when building csources (#21194) * replace `symbolfiles` with `incremental`; fixes warnings when build csources * fixes self conversion warnings --- tools/niminst/niminst.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index bc763a56f..81b46653d 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -168,11 +168,11 @@ proc parseCmdLine(c: var ConfigData) = next(p) var kind = p.kind var key = p.key - var val = p.val.string + var val = p.val case kind of cmdArgument: if c.actions == {}: - for a in split(normalize(key.string), {';', ','}): + for a in split(normalize(key), {';', ','}): case a of "csource": incl(c.actions, actionCSource) of "scripts": incl(c.actions, actionScripts) @@ -183,11 +183,11 @@ proc parseCmdLine(c: var ConfigData) = of "deb": incl(c.actions, actionDeb) else: quit(Usage) else: - c.infile = addFileExt(key.string, "ini") - c.nimArgs = cmdLineRest(p).string + c.infile = addFileExt(key, "ini") + c.nimArgs = cmdLineRest(p) break of cmdLongOption, cmdShortOption: - case normalize(key.string) + case normalize(key) of "help", "h": stdout.write(Usage) quit(0) @@ -544,7 +544,7 @@ proc srcdist(c: var ConfigData) = var dir = getOutputDir(c) / buildDir(osA, cpuA) if dirExists(dir): removeDir(dir) createDir(dir) - var cmd = ("$# compile -f --symbolfiles:off --compileonly " & + var cmd = ("$# compile -f --incremental:off --compileonly " & "--gen_mapping --cc:gcc --skipUserCfg" & " --os:$# --cpu:$# $# $#") % [findNim(), osname, cpuname, c.nimArgs, c.mainfile] From 761c5a0830a18cb0db721d27aff53a07ca30b1c3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 29 Dec 2022 03:54:15 +0800 Subject: [PATCH 4114/4254] less verbose type mismatch messages (#21191) * less verbose type mismatch messages * Update compiler/types.nim * fixes i386 * fixes i386 --- changelogs/changelog_2_0_0.md | 2 ++ compiler/options.nim | 1 + compiler/semcall.nim | 44 +++++++++++++++++++------ compiler/sigmatch.nim | 40 ++++++++++++---------- tests/config.nims | 1 + tests/errmsgs/tconcisetypemismatch.nim | 23 +++++++++++++ tests/errmsgs/tconcisetypemismatch.nims | 21 ++++++++++++ 7 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 tests/errmsgs/tconcisetypemismatch.nim create mode 100644 tests/errmsgs/tconcisetypemismatch.nims diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 614d97d85..29d906d62 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -135,6 +135,8 @@ - The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. +- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/options.nim b/compiler/options.nim index 7e4f6898f..ded084ae4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -231,6 +231,7 @@ type ## are not anymore. laxEffects ## Lax effects system prior to Nim 2.0. + verboseTypeMismatch SymbolFilesOption* = enum disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 31b490781..2147a9645 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -10,7 +10,8 @@ ## This module implements semantic checking for calls. # included from sem.nim -from algorithm import sort +from std/algorithm import sort + proc sameMethodDispatcher(a, b: PSym): bool = result = false @@ -192,7 +193,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): # argument in order to remove plenty of candidates. This is # comparable to what C# does and C# is doing fine. var filterOnlyFirst = false - if optShowAllMismatches notin c.config.globalOptions: + if optShowAllMismatches notin c.config.globalOptions and verboseTypeMismatch in c.config.legacyFeatures: for err in errors: if err.firstMismatch.arg > 1: filterOnlyFirst = true @@ -208,6 +209,10 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): if filterOnlyFirst and err.firstMismatch.arg == 1: inc skipped continue + + if verboseTypeMismatch notin c.config.legacyFeatures: + candidates.add "[" & $err.firstMismatch.arg & "] " + if err.sym.kind in routineKinds and err.sym.ast != nil: candidates.add(renderTree(err.sym.ast, {renderNoBody, renderNoComments, renderNoPragmas})) @@ -217,7 +222,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add("\n") let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: "" - if n.len > 1: + if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures: candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg) # candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging case err.firstMismatch.kind @@ -274,11 +279,28 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): const errTypeMismatch = "type mismatch: got <" errButExpected = "but expected one of:" + errExpectedPosition = "Expected one of (first mismatch at position [#]):" errUndeclaredField = "undeclared field: '$1'" errUndeclaredRoutine = "attempting to call undeclared routine: '$1'" errBadRoutine = "attempting to call routine: '$1'$2" errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3" +proc describeParamList(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string = + result = "Expression: " & $n + for i in startIdx..') + if candidates != "": + result.add("\n" & errButExpected & "\n" & candidates) + localError(c.config, n.info, result & "\nexpression: " & $n) + proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = # Gives a detailed error message; this is separated from semOverloadedCall, # as semOverloadedCall is already pretty slow (and we need this information @@ -306,13 +328,15 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree) return - let (prefer, candidates) = presentFailedCandidates(c, n, errors) - var result = errTypeMismatch - result.add(describeArgs(c, n, 1, prefer)) - result.add('>') - if candidates != "": - result.add("\n" & errButExpected & "\n" & candidates) - localError(c.config, n.info, result & "\nexpression: " & $n) + if verboseTypeMismatch in c.config.legacyFeatures: + legacynotFoundError(c, n, errors) + else: + let (prefer, candidates) = presentFailedCandidates(c, n, errors) + var result = "type mismatch\n" + result.add describeParamList(c, n, 1, prefer) + if candidates != "": + result.add("\n" & errExpectedPosition & "\n" & candidates) + localError(c.config, n.info, result) proc bracketNotFoundError(c: PContext; n: PNode) = var errors: CandidateErrors = @[] diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 68068cd26..75e3e5428 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -322,26 +322,32 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string = else: result = arg.typ.typeToString(prefer) +template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName) = + var arg = n[i] + if n[i].kind == nkExprEqExpr: + result.add renderTree(n[i][0]) + result.add ": " + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}: + # XXX we really need to 'tryExpr' here! + arg = c.semOperand(c, n[i][1]) + n[i].typ = arg.typ + n[i][1] = arg + else: + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse, + nkOfBranch, nkElifBranch, + nkExceptBranch}: + arg = c.semOperand(c, n[i]) + n[i] = arg + if arg.typ != nil and arg.typ.kind == tyError: return + result.add argTypeToString(arg, prefer) + +proc describeArg*(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName): string = + describeArgImpl(c, n, i, startIdx, prefer) + proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string = result = "" for i in startIdx..= (1,5,1): + # to make it easier to test against older nim versions, (best effort only) + switch("filenames", "legacyRelProj") + switch("spellSuggest", "0") + +# for std/unittest +switch("define", "nimUnittestOutputLevel:PRINT_FAILURES") +switch("define", "nimUnittestColor:off") + +hint("Processing", off) From e602ebeb66986e3de65324c81253513b139c7f0e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 29 Dec 2022 15:29:40 +0800 Subject: [PATCH 4115/4254] fixes #19997; ships changelogs directory for a release (#21200) fixes #19997; ship changelogs directory for a release --- compiler/installer.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/installer.ini b/compiler/installer.ini index 094b92a68..1e57455c6 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -70,6 +70,7 @@ Files: "nimpretty" Files: "testament" Files: "nimsuggest" Files: "nimsuggest/tests/*.nim" +Files: "changelogs/*.md" [Lib] Files: "lib" From 705da9d452d19536689a32a8d4378bcce2ec320a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 30 Dec 2022 00:06:57 +0800 Subject: [PATCH 4116/4254] fixes #14444; add `genLineDir` before assignment (#21201) * fixes #14444; add `genLineDir` before raises * add a test case * fixes differently --- compiler/ccgstmts.nim | 1 + tests/errmsgs/t14444.nim | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/errmsgs/t14444.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index fbdb9a347..9d6640fe2 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1620,6 +1620,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) + genLineDir(p, le) # it can be a nkBracketExpr, which may raise expr(p, le, a) a.flags.excl(lfPrepareForMutation) if fastAsgn: incl(a.flags, lfNoDeepCopy) diff --git a/tests/errmsgs/t14444.nim b/tests/errmsgs/t14444.nim new file mode 100644 index 000000000..143b4542e --- /dev/null +++ b/tests/errmsgs/t14444.nim @@ -0,0 +1,14 @@ +discard """ + matrix: "--hints:off" + exitcode: "1" + output: ''' +t14444.nim(13) t14444 +fatal.nim(51) sysFatal +Error: unhandled exception: index out of bounds, the container is empty [IndexDefect] +''' +""" + +when true: # bug #14444 + var i: string + i[10] = 'j' + echo i \ No newline at end of file From ebd1c678be5e0acee4fca67e1b7060234821ccf6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 30 Dec 2022 03:15:08 +0800 Subject: [PATCH 4117/4254] fixes #21195; `std/assertions` continue to use `sysFatal` when `nimPreviewSlimSystem` is not defined (#21196) * fixes #21195; `std/assertions` continue to use `sysFatal` * try includes * make `std/assertions` self-contained * fixes tests * fixes tests --- lib/std/assertions.nim | 9 ++++++++- lib/system.nim | 28 +++------------------------- lib/system/rawquits.nim | 27 +++++++++++++++++++++++++++ tests/assert/panicoverride.nim | 15 +++++++++++++++ tests/assert/t21195.nim | 6 ++++++ tests/assert/tassert_c.nim | 4 ++-- tests/errmsgs/t9768.nim | 4 ++-- 7 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 lib/system/rawquits.nim create mode 100644 tests/assert/panicoverride.nim create mode 100644 tests/assert/t21195.nim diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim index 229033c58..a249d7751 100644 --- a/lib/std/assertions.nim +++ b/lib/std/assertions.nim @@ -7,6 +7,10 @@ # distribution, for details about the copyright. # +when not defined(nimPreviewSlimSystem) and not declared(sysFatal): + include "system/rawquits" + include "system/fatal" + ## This module implements assertion handling. import std/private/miscdollars @@ -26,7 +30,10 @@ proc `$`(info: InstantiationInfo): string = proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = ## Raises an `AssertionDefect` with `msg`. - raise newException(AssertionDefect, msg) + when defined(nimPreviewSlimSystem): + raise newException(AssertionDefect, msg) + else: + sysFatal(AssertionDefect, msg) proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = ## Raises an `AssertionDefect` with `msg`, but this is hidden diff --git a/lib/system.nim b/lib/system.nim index e9c9ebfeb..d8fafc0ef 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1081,31 +1081,9 @@ proc align(address, alignment: int): int = else: result = (address + (alignment - 1)) and not (alignment - 1) -when defined(nimNoQuit): - proc rawQuit(errorcode: int = QuitSuccess) = discard "ignoring quit" - -elif defined(genode): - import genode/env - - var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr - - type GenodeEnv* = GenodeEnvPtr - ## Opaque type representing Genode environment. - - proc rawQuit(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn, - importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "".} - - proc rawQuit(errorcode: int = QuitSuccess) {.inline, noreturn.} = - systemEnv.rawQuit(errorcode) - - -elif defined(js) and defined(nodejs) and not defined(nimscript): - proc rawQuit(errorcode: int = QuitSuccess) {.magic: "Exit", - importc: "process.exit", noreturn.} - -else: - proc rawQuit(errorcode: cint) {. - magic: "Exit", importc: "exit", header: "", noreturn.} +include system/rawquits +when defined(genode): + export GenodeEnv template sysAssert(cond: bool, msg: string) = when defined(useSysAssert): diff --git a/lib/system/rawquits.nim b/lib/system/rawquits.nim new file mode 100644 index 000000000..f0ead10c6 --- /dev/null +++ b/lib/system/rawquits.nim @@ -0,0 +1,27 @@ +import system/ctypes + +when defined(nimNoQuit): + proc rawQuit(errorcode: int = QuitSuccess) = discard "ignoring quit" + +elif defined(genode): + import genode/env + + var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr + + type GenodeEnv = GenodeEnvPtr + ## Opaque type representing Genode environment. + + proc rawQuit(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn, + importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "".} + + proc rawQuit(errorcode: int = QuitSuccess) {.inline, noreturn.} = + systemEnv.rawQuit(errorcode) + + +elif defined(js) and defined(nodejs) and not defined(nimscript): + proc rawQuit(errorcode: int = QuitSuccess) {.magic: "Exit", + importc: "process.exit", noreturn.} + +else: + proc rawQuit(errorcode: cint) {. + magic: "Exit", importc: "exit", header: "", noreturn.} \ No newline at end of file diff --git a/tests/assert/panicoverride.nim b/tests/assert/panicoverride.nim new file mode 100644 index 000000000..53ad64215 --- /dev/null +++ b/tests/assert/panicoverride.nim @@ -0,0 +1,15 @@ +# panicoverride.nim + +proc printf(fmt: cstring) {.varargs, importc, header:"stdio.h".} +proc exit(code: cint) {.importc, header:"stdlib.h".} + +{.push stack_trace: off, profiler:off.} + +proc rawoutput(s: cstring) = + printf("RAW: %s\n", s) + +proc panic(s: cstring) {.noreturn.} = + printf("PANIC: %s\n", s) + exit(0) + +{.pop.} \ No newline at end of file diff --git a/tests/assert/t21195.nim b/tests/assert/t21195.nim new file mode 100644 index 000000000..b690d22a0 --- /dev/null +++ b/tests/assert/t21195.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--verbosity:0 --os:standalone --mm:none" +""" +# bug #21195 +var n = 11 +assert(n == 12) diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index 110a9aabf..4d49a6035 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -1,8 +1,8 @@ discard """ - cmd: "nim $target $options --excessiveStackTrace:off $file" + cmd: "nim $target $options -d:nimPreviewSlimSystem --excessiveStackTrace:off $file" output: '''true''' """ - +import std/assertions const expected = """ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo diff --git a/tests/errmsgs/t9768.nim b/tests/errmsgs/t9768.nim index 058d297b3..b5ff58367 100644 --- a/tests/errmsgs/t9768.nim +++ b/tests/errmsgs/t9768.nim @@ -1,14 +1,14 @@ discard """ errormsg: "unhandled exception: t9768.nim(24, 3) `a < 4` [AssertionDefect]" file: "std/assertions.nim" + matrix: "-d:nimPreviewSlimSystem" nimout: ''' stack trace: (most recent call last) t9768.nim(29, 33) main t9768.nim(24, 11) foo1 ''' """ - - +import std/assertions From c598d0b6eccd3133bfca710fc5fcc4576501862c Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 30 Dec 2022 07:50:12 +0800 Subject: [PATCH 4118/4254] fix #15117 zero size array cause incorrect codegen for VCC compiler (#21197) fix #15117 --- compiler/ccgexprs.nim | 2 ++ tests/array/t15117.nim | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/array/t15117.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e2885a294..844a37997 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3331,6 +3331,8 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool; result: var Rope) = proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) = result.add "{" + if p.vccAndC and n.len == 0 and n.typ.kind == tyArray: + getDefaultValue(p, n.typ[1], n.info, result) for i in 0.. 0: result.add ",\n" diff --git a/tests/array/t15117.nim b/tests/array/t15117.nim new file mode 100644 index 000000000..157b04bee --- /dev/null +++ b/tests/array/t15117.nim @@ -0,0 +1,27 @@ +discard """ + matrix: "--cc:vcc" + disabled: "linux" + disabled: "bsd" + disabled: "osx" + disabled: "unix" + disabled: "posix" +""" +{.experimental: "views".} + +let a: array[0, byte] = [] +discard a + +type B = object + a:int +let b: array[0, B] = [] +let c: array[0, ptr B] = [] +let d: array[0, ref B] = [] +discard b +discard c +discard d + +discard default(array[0, B]) + +type + View1 = openArray[byte] +discard default(View1) From e5639408d55c3b9164790bee37580a74a15b666f Mon Sep 17 00:00:00 2001 From: rockcavera Date: Fri, 30 Dec 2022 05:20:32 -0300 Subject: [PATCH 4119/4254] avoiding unnecessary allocation for dollar IpAddress (#21199) * avoiding allocating an unnecessary byte for IPv4 The inet.h file uses 16 as the string in C needs the last null byte https://github.com/torvalds/linux/blob/1b929c02afd37871d5afb9d498426f83432e71c2/include/linux/inet.h#L49 However, strings in Nim do not need this. So one byte is being allocated unnecessary and will never be used. * avoid unnecessary allocation in IPv6 dollar It is currently allocating 48 bytes. However, the Nim implementation for IPv6 will print a maximum of 39 characters. Nim does not implement IPv6 "0000:0000:0000:0000:0000:ffff:255.255.255.255" (45 characters) nor "0000:0000:0000:0000:0000:ffff:255.255.255.255%3" (47 characters). The indication in inet.h for 48 is due to the maximum use of 47 characters of a C string that needs a null byte at the end. So 48. https://github.com/torvalds/linux/blob/1b929c02afd37871d5afb9d498426f83432e71c2/include/linux/inet.h#L50 --- lib/pure/net.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index be9f2e48c..76a39226f 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1921,7 +1921,7 @@ proc `$`*(address: IpAddress): string = ## Converts an IpAddress into the textual representation case address.family of IpAddressFamily.IPv4: - result = newStringOfCap(16) + result = newStringOfCap(15) result.addInt address.address_v4[0] result.add '.' result.addInt address.address_v4[1] @@ -1930,7 +1930,7 @@ proc `$`*(address: IpAddress): string = result.add '.' result.addInt address.address_v4[3] of IpAddressFamily.IPv6: - result = newStringOfCap(48) + result = newStringOfCap(39) var currentZeroStart = -1 currentZeroCount = 0 From 4032eb4baafcfb4a1cb8fd41a474daac70103856 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 1 Jan 2023 16:51:58 +0800 Subject: [PATCH 4120/4254] fixes #20906; update copyright year [backport 1.6] (#21210) --- compiler/options.nim | 2 +- copying.txt | 2 +- readme.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index ded084ae4..47e8155f8 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -24,7 +24,7 @@ const useEffectSystem* = true useWriteTracking* = false hasFFI* = defined(nimHasLibFFI) - copyrightYear* = "2022" + copyrightYear* = "2023" nimEnableCovariance* = defined(nimEnableCovariance) diff --git a/copying.txt b/copying.txt index 60b6a0217..ae3a162a7 100644 --- a/copying.txt +++ b/copying.txt @@ -1,7 +1,7 @@ ===================================================== Nim -- a Compiler for Nim. https://nim-lang.org/ -Copyright (C) 2006-2022 Andreas Rumpf. All rights reserved. +Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index a0f47eb41..325e8fff9 100644 --- a/readme.md +++ b/readme.md @@ -203,7 +203,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2022 Andreas Rumpf, all rights reserved. +Copyright © 2006-2023 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org From 5b20f0685c71e68ab08f7a1941f7e160d91e538f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 1 Jan 2023 17:25:04 +0800 Subject: [PATCH 4121/4254] fixes pragmas reorder (#21205) --- compiler/reorder.nim | 1 + tests/pragmas/tpragmas_reorder.nim | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/pragmas/tpragmas_reorder.nim diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 4fabf9041..4ad3f1219 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -106,6 +106,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev if a.kind == nkExprColonExpr and a[0].kind == nkIdent and a[0].ident.s == "pragma": # user defined pragma decl(a[1]) + for i in 1.. Date: Mon, 2 Jan 2023 08:16:18 +0000 Subject: [PATCH 4122/4254] Update nim.cfg (#21204) tlsEmulation:on under NetBSD-10Beta and NetBSD-current produces an executable which crashes immediately as follows: Core was generated by `koch'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x000000000047b4c2 in nimZeroMem () (gdb) bt #0 0x000000000047b4c2 in nimZeroMem () #1 0x00000000004897b2 in threadVarAlloc__system_2162 () #2 0x000000000048980e in initThreadVarsEmulation () #3 0x0000000000489848 in PreMain () #4 0x000000000048986a in NimMain () #5 0x00000000004898a9 in main () I can't speak about the other BSDs. --- config/nim.cfg | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index 1601ebe08..f7b7c119a 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -181,10 +181,9 @@ nimblepath="$home/.nimble/pkgs/" gcc.maxerrorsimpl = "-fmax-errors=3" -@if freebsd: +@if freebsd or netbsd: tlsEmulation:off @elif bsd: - # at least NetBSD has problems with thread local storage: tlsEmulation:on @end From cf1b16ef8ba1c9f8411e551d317784c5ffaece0c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 2 Jan 2023 10:39:17 +0100 Subject: [PATCH 4123/4254] minor code cleanups (#21215) --- lib/posix/posix.nim | 8 ++++---- lib/posix/posix_utils.nim | 6 +++--- lib/std/enumerate.nim | 2 +- lib/std/enumutils.nim | 2 +- lib/std/envvars.nim | 35 +++++++++++++++++------------------ lib/std/oserrors.nim | 15 ++++++--------- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index ddf00cbb7..43346608d 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1140,12 +1140,12 @@ type ## The getrlimit() and setrlimit() system calls get and set resource limits respectively. ## Each resource has an associated soft and hard limit, as defined by the RLimit structure -proc setrlimit*(resource: cint, rlp: var RLimit): cint - {.importc: "setrlimit",header: "".} +proc setrlimit*(resource: cint, rlp: var RLimit): cint {. + importc: "setrlimit", header: "".} ## The setrlimit() system calls sets resource limits. -proc getrlimit*(resource: cint, rlp: var RLimit): cint - {.importc: "getrlimit",header: "".} +proc getrlimit*(resource: cint, rlp: var RLimit): cint {. + importc: "getrlimit", header: "".} ## The getrlimit() system call gets resource limits. when defined(nimHasStyleChecks): diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 92fe0940d..7e4a2eeda 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -43,8 +43,8 @@ proc uname*(): Uname = result.machine = charArrayToString u.machine proc fsync*(fd: int) = - ## synchronize a file's buffer cache to the storage device - if fsync(fd.cint) != 0: + ## synchronize a file's buffer cache to the storage device + if fsync(fd.cint) != 0: raise newException(OSError, $strerror(errno)) proc stat*(path: string): Stat = @@ -90,7 +90,7 @@ proc mkstemp*(prefix: string, suffix=""): (string, File) = ## Returns the filename and a file opened in r/w mode. var tmpl = cstring(prefix & "XXXXXX" & suffix) let fd = - if len(suffix)==0: + if len(suffix) == 0: when declared(mkostemp): mkostemp(tmpl, O_CLOEXEC) else: diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim index a8f0e1ba7..4f0161b7c 100644 --- a/lib/std/enumerate.nim +++ b/lib/std/enumerate.nim @@ -21,7 +21,7 @@ macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = ## The default starting count `0` can be manually overridden if needed. runnableExamples: let a = [10, 20, 30] - var b: seq[(int, int)] + var b: seq[(int, int)] = @[] for i, x in enumerate(a): b.add((i, x)) assert b == @[(0, 10), (1, 20), (2, 30)] diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 9d4ff1bcf..59fb112ed 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -112,9 +112,9 @@ const invalidSlot = uint8.high proc genLookup[T: typedesc[HoleyEnum]](_: T): auto = const n = span(T) - var ret: array[n, uint8] var i = 0 assert n <= invalidSlot.int + var ret {.noinit.}: array[n, uint8] for ai in mitems(ret): ai = invalidSlot for ai in items(T): ret[ai.ord - T.low.ord] = uint8(i) diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim index ce90f66ba..ab5c9f06e 100644 --- a/lib/std/envvars.nim +++ b/lib/std/envvars.nim @@ -94,8 +94,10 @@ when not defined(nimscript): assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" let env = getEnvImpl(key) - if env == nil: return default - result = $env + if env == nil: + result = default + else: + result = $env proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = ## Checks whether the environment variable named `key` exists. @@ -109,7 +111,7 @@ when not defined(nimscript): runnableExamples: assert not existsEnv("unknownEnv") - return getEnvImpl(key) != nil + result = getEnvImpl(key) != nil proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = ## Sets the value of the `environment variable`:idx: named `key` to `val`. @@ -140,7 +142,7 @@ when not defined(nimscript): ## * `envPairs iterator`_ template bail = raiseOSError(osLastError(), key) when defined(windows): - #[ + #[ # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160 > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string note that nil is not legal @@ -177,20 +179,17 @@ when not defined(nimscript): iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = when defined(windows): - block implBlock: - template impl(get_fun, typ, size, zero, free_fun) = - let env = get_fun() - var e = env - if e == nil: break implBlock - while true: - let eend = strEnd(e) - let kv = $e - let p = find(kv, '=') - yield (substr(kv, 0, p-1), substr(kv, p+1)) - e = cast[typ](cast[int](eend)+size) - if typeof(zero)(eend[1]) == zero: break - discard free_fun(env) - impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW) + let env = getEnvironmentStringsW() + var e = env + if e != nil: + while true: + let eend = strEnd(e) + let kv = $e + let p = find(kv, '=') + yield (substr(kv, 0, p-1), substr(kv, p+1)) + e = cast[WideCString](cast[ByteAddress](eend)+2) + if int(eend[1]) == 0: break + discard freeEnvironmentStringsW(env) else: var i = 0 when defined(macosx) and not defined(ios) and not defined(emscripten): diff --git a/lib/std/oserrors.nim b/lib/std/oserrors.nim index 8d06c41da..a641a7f47 100644 --- a/lib/std/oserrors.nim +++ b/lib/std/oserrors.nim @@ -75,17 +75,14 @@ proc newOSError*( ## See also: ## * `osErrorMsg proc`_ ## * `osLastError proc`_ - var e: owned(ref OSError); new(e) - e.errorCode = errorCode.int32 - e.msg = osErrorMsg(errorCode) + result = (ref OSError)(errorCode: errorCode.int32, msg: osErrorMsg(errorCode)) if additionalInfo.len > 0: - if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n' - e.msg.add "Additional info: " - e.msg.add additionalInfo + if result.msg.len > 0 and result.msg[^1] != '\n': result.msg.add '\n' + result.msg.add "Additional info: " + result.msg.add additionalInfo # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs. - if e.msg == "": - e.msg = "unknown OS error" - return e + if result.msg == "": + result.msg = "unknown OS error" proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} = ## Raises an `OSError exception `_. From 3b965f463b41eace340393af636e4abcd9c223d6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 2 Jan 2023 22:10:26 +0800 Subject: [PATCH 4124/4254] bump csource_v2 to include fix for linking parameter maximum length (#21216) > If accepted, I believe it should be used in csources_v2 and also backport 2.0 ref https://github.com/nim-lang/Nim/pull/21186 --- config/build_config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/build_config.txt b/config/build_config.txt index 286e0dc2a..66390e695 100644 --- a/config/build_config.txt +++ b/config/build_config.txt @@ -2,4 +2,4 @@ nim_comment="key-value pairs for windows/posix bootstrapping build scripts" nim_csourcesDir=csources_v2 nim_csourcesUrl=https://github.com/nim-lang/csources_v2.git nim_csourcesBranch=master -nim_csourcesHash=b66c420697c574be18a20dd4720248a715b4287e +nim_csourcesHash=86742fb02c6606ab01a532a0085784effb2e753e From 81b7f9108f139bbf237f3e121fdbe9ff32a7193f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 3 Jan 2023 15:15:10 +0800 Subject: [PATCH 4125/4254] fixes #21207; reports redefinition error in the definition of enums (#21217) * fixes #21207; reports redefinition in the enums * add a test --- compiler/semtypes.nim | 4 ++-- tests/enum/tredefinition.nim | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/enum/tredefinition.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 534861e97..a8b147eef 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -73,7 +73,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = rawAddSon(result, base) let isPure = result.sym != nil and sfPure in result.sym.flags var symbols: TStrTable - if isPure: initStrTable(symbols) + initStrTable(symbols) var hasNull = false for i in 1.. Date: Wed, 4 Jan 2023 12:10:44 -0800 Subject: [PATCH 4126/4254] make it printer friendly (#21218) --- doc/nimdoc.css | 9 +++++++++ nimdoc/testproject/expected/nimdoc.out.css | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index f924f5a36..1417d9eff 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -147,6 +147,15 @@ body { box-sizing: border-box; margin-left: 1%; } +@media print { + #global-links, .link-seesrc, .theme-switch-wrapper, #searchInputDiv, .search-groupby { + display:none; + } + .columns { + width:100% !important; + } +} + .column:first-child, .columns:first-child { margin-left: 0; } diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index f924f5a36..1417d9eff 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -147,6 +147,15 @@ body { box-sizing: border-box; margin-left: 1%; } +@media print { + #global-links, .link-seesrc, .theme-switch-wrapper, #searchInputDiv, .search-groupby { + display:none; + } + .columns { + width:100% !important; + } +} + .column:first-child, .columns:first-child { margin-left: 0; } From 2620da9bf9994d09da3d5b31b29c95855fb79a41 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Wed, 4 Jan 2023 23:19:01 +0300 Subject: [PATCH 4127/4254] docgen: implement cross-document links (#20990) * docgen: implement cross-document links Fully implements https://github.com/nim-lang/RFCs/issues/125 Follow-up of: https://github.com/nim-lang/Nim/pull/18642 (for internal links) and https://github.com/nim-lang/Nim/issues/20127. Overview -------- Explicit import-like directive is required, called `.. importdoc::`. (the syntax is % RST, Markdown will use it for a while). Then one can reference any symbols/headings/anchors, as if they were in the local file (but they will be prefixed with a module name or markup document in link text). It's possible to reference anything from anywhere (any direction in `.nim`/`.md`/`.rst` files). See `doc/docgen.md` for full description. Working is based on `.idx` files, hence one needs to generate all `.idx` beforehand. A dedicated option `--index:only` is introduced (and a separate stage for `--index:only` is added to `kochdocs.nim`). Performance note ---------------- Full run for `./koch docs` now takes 185% of the time before this PR. (After: 315 s, before: 170 s on my PC). All the time seems to be spent on `--index:only` run, which takes almost as much (85%) of normal doc run -- it seems that most time is spent on file parsing, turning off HTML generation phase has not helped much. (One could avoid it by specifying list of files that can be referenced and pre-processing only them. But it can become error-prone and I assume that these linke will be **everywhere** in the repository anyway, especially considering https://github.com/nim-lang/RFCs/issues/478. So every `.nim`/`.md` file is processed for `.idx` first). But that's all without significant part of repository converted to cross-module auto links. To estimate impact I checked the time for `doc`ing a few files (after all indexes have been generated), and everywhere difference was **negligible**. E.g. for `lib/std/private/osfiles.nim` that `importdoc`s large `os.idx` and hence should have been a case with relatively large performance impact, but: * After: 0.59 s. * Before: 0.59 s. So Nim compiler works so slow that doc part basically does not matter :-) Testing ------- 1) added `extlinks` test to `nimdoc/` 2) checked that `theindex.html` is still correct 2) fixed broken auto-links for modules that were derived from `os.nim` by adding appropriate ``importdoc`` Implementation note ------------------- Parsing and formating of `.idx` entries is moved into a dedicated `rstidx.nim` module from `rstgen.nim`. `.idx` file format changed: * fields are not escaped in most cases because we need original strings for referencing, not HTML ones (the exception is linkTitle for titles and headings). Escaping happens later -- on the stage of `rstgen` buildIndex, etc. * all lines have fixed number of columns 6 * added discriminator tag as a first column, it always allows distinguish Nim/markup entries, titles/headings, etc. `rstgen` does not rely any more (in most cases) on ad-hoc logic to determine what type each entry is. * there is now always a title entry added at the first line. * add a line number as 6th column * linkTitle (4th) column has a different format: before it was like `module: funcName()`, now it's `proc funcName()`. (This format is also propagated to `theindex.html` and search results, I kept it that way since I like it more though it's discussible.) This column is what used for Nim symbols resolution. * also changed details on column format for headings and titles: "keyword" is original, "linkTitle" is HTML one * fix paths on Windows + more clear code * Update compiler/docgen.nim Co-authored-by: Andreas Rumpf * Handle .md and .nim paths uniformly in findRefFile * handle titles better + more comments * don't allow markup overwrite index title for .nim files Co-authored-by: Andreas Rumpf --- compiler/commands.nim | 8 +- compiler/docgen.nim | 200 ++++++++---- compiler/lineinfos.nim | 2 + compiler/options.nim | 2 + doc/advopt.txt | 4 +- doc/docgen.md | 309 ++++++++++++++++-- doc/markdown_rst.md | 84 +++++ lib/core/macros.nim | 2 + lib/packages/docutils/dochelpers.nim | 27 +- lib/packages/docutils/rst.nim | 263 +++++++++++++-- lib/packages/docutils/rstgen.nim | 200 ++++-------- lib/packages/docutils/rstidx.nim | 138 ++++++++ lib/pure/os.nim | 2 + lib/std/appdirs.nim | 2 + lib/std/private/osappdirs.nim | 2 + lib/std/private/oscommon.nim | 2 + lib/std/private/osdirs.nim | 2 + lib/std/private/osfiles.nim | 3 +- lib/std/private/ospaths2.nim | 2 + lib/std/private/osseps.nim | 2 + lib/std/private/ossymlinks.nim | 1 + lib/std/symlinks.nim | 3 +- nimdoc/extlinks/project/doc/manual.md | 17 + .../extlinks/project/expected/_._/util.html | 104 ++++++ nimdoc/extlinks/project/expected/_._/util.idx | 2 + .../extlinks/project/expected/doc/manual.html | 44 +++ .../extlinks/project/expected/doc/manual.idx | 3 + nimdoc/extlinks/project/expected/main.html | 144 ++++++++ nimdoc/extlinks/project/expected/main.idx | 4 + .../project/expected/sub/submodule.html | 130 ++++++++ .../project/expected/sub/submodule.idx | 3 + .../extlinks/project/expected/theindex.html | 58 ++++ nimdoc/extlinks/project/main.nim | 23 ++ nimdoc/extlinks/project/sub/submodule.nim | 13 + nimdoc/extlinks/util.nim | 2 + .../test_out_index_dot_html/expected/foo.idx | 3 +- .../expected/theindex.html | 2 +- nimdoc/tester.nim | 63 ++++ .../expected/subdir/subdir_b/utils.html | 6 +- .../expected/subdir/subdir_b/utils.idx | 87 ++--- nimdoc/testproject/expected/testproject.idx | 131 ++++---- nimdoc/testproject/expected/theindex.html | 196 +++++------ tests/stdlib/tdochelpers.nim | 16 + tests/stdlib/trst.nim | 2 +- tools/kochdocs.nim | 41 ++- 45 files changed, 1863 insertions(+), 491 deletions(-) create mode 100644 lib/packages/docutils/rstidx.nim create mode 100644 nimdoc/extlinks/project/doc/manual.md create mode 100644 nimdoc/extlinks/project/expected/_._/util.html create mode 100644 nimdoc/extlinks/project/expected/_._/util.idx create mode 100644 nimdoc/extlinks/project/expected/doc/manual.html create mode 100644 nimdoc/extlinks/project/expected/doc/manual.idx create mode 100644 nimdoc/extlinks/project/expected/main.html create mode 100644 nimdoc/extlinks/project/expected/main.idx create mode 100644 nimdoc/extlinks/project/expected/sub/submodule.html create mode 100644 nimdoc/extlinks/project/expected/sub/submodule.idx create mode 100644 nimdoc/extlinks/project/expected/theindex.html create mode 100644 nimdoc/extlinks/project/main.nim create mode 100644 nimdoc/extlinks/project/sub/submodule.nim create mode 100644 nimdoc/extlinks/util.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index a252f505f..73140036a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -820,7 +820,13 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if conf != nil: conf.headerFile = arg incl(conf.globalOptions, optGenIndex) of "index": - processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info) + case arg.normalize + of "", "on": conf.globalOptions.incl {optGenIndex} + of "only": conf.globalOptions.incl {optGenIndexOnly, optGenIndex} + of "off": conf.globalOptions.excl {optGenIndex, optGenIndexOnly} + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) + of "noimportdoc": + processOnOffSwitchG(conf, {optNoImportdoc}, arg, pass, info) of "import": expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f8a804cec..cab334e7a 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -7,13 +7,17 @@ # distribution, for details about the copyright. # -# This is the documentation generator. Cross-references are generated -# by knowing how the anchors are going to be named. +## This is the Nim documentation generator. Cross-references are generated +## by knowing how the anchors are going to be named. +## +## .. importdoc:: ../docgen.md +## +## For corresponding users' documentation see [Nim DocGen Tools Guide]. import ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents, wordrecg, syntaxes, renderer, lexer, - packages/docutils/[rst, rstgen, dochelpers], + packages/docutils/[rst, rstidx, rstgen, dochelpers], json, xmltree, trees, types, typesrenderer, astalgo, lineinfos, intsets, pathutils, tables, nimpaths, renderverbatim, osproc, packages @@ -91,7 +95,7 @@ type jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering types: TStrTable sharedState: PRstSharedState - standaloneDoc: bool + standaloneDoc: bool # is markup (.rst/.md) document? conf*: ConfigRef cache*: IdentCache exampleCounter: int @@ -225,7 +229,7 @@ proc attachToType(d: PDoc; p: PSym): PSym = if params.len > 0: check(0) for i in 2.."), "itemSymOrIDEnc", symbolOrIdEnc]) - # Ironically for types the complexSymbol is *cleaner* than the plainName - # because it doesn't include object fields or documentation comments. So we - # use the plain one for callable elements, and the complex for the rest. - var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": " - if n.kind in routineDefs: linkTitle.add(xmltree.escape(plainName.strip)) - else: linkTitle.add(xmltree.escape(complexSymbol.strip)) - - setIndexTerm(d[], external, symbolOrId, name, linkTitle, - xmltree.escape(plainDocstring.docstringSummary)) + setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name, + linkTitle = detailedName, + linkDesc = xmltree.escape(plainDocstring.docstringSummary), + line = n.info.line.int) if k == skType and nameNode.kind == nkSym: d.types.strTableAdd nameNode.sym proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem = if not isVisible(d, nameNode): return var - name = getName(d, nameNode) + name = getNameEsc(d, nameNode) comm = genRecComment(d, n) r: TSrcGen initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}) @@ -1337,9 +1369,31 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) = proc overloadGroupName(s: string, k: TSymKind): string = ## Turns a name like `f` into anchor `f-procs-all` - #s & " " & k.toHumanStr & "s all" s & "-" & k.toHumanStr & "s-all" +proc setIndexTitle(d: PDoc, useMetaTitle: bool) = + let titleKind = if d.standaloneDoc: ieMarkupTitle else: ieNimTitle + let external = AbsoluteFile(d.destFile) + .relativeTo(d.conf.outDir, '/') + .changeFileExt(HtmlExt) + .string + var term, linkTitle: string + if useMetaTitle and d.meta[metaTitle].len != 0: + term = d.meta[metaTitleRaw] + linkTitle = d.meta[metaTitleRaw] + else: + let filename = extractFilename(d.filename) + term = + if d.standaloneDoc: filename # keep .rst/.md extension + else: changeFileExt(filename, "") # rm .nim extension + linkTitle = + if d.standaloneDoc: term # keep .rst/.md extension + else: canonicalImport(d.conf, AbsoluteFile d.filename) + if not d.standaloneDoc: + linkTitle = "module " & linkTitle + setIndexTerm(d[], titleKind, htmlFile = external, id = "", + term = term, linkTitle = linkTitle) + proc finishGenerateDoc*(d: var PDoc) = ## Perform 2nd RST pass for resolution of links/footnotes/headings... # copy file map `filenames` to ``rstgen.nim`` for its warnings @@ -1352,7 +1406,24 @@ proc finishGenerateDoc*(d: var PDoc) = firstRst = fragment.rst break d.hasToc = d.hasToc or d.sharedState.hasToc - preparePass2(d.sharedState, firstRst) + # in --index:only mode we do NOT want to load other .idx, only write ours: + let importdoc = optGenIndexOnly notin d.conf.globalOptions and + optNoImportdoc notin d.conf.globalOptions + preparePass2(d.sharedState, firstRst, importdoc) + + if optGenIndexOnly in d.conf.globalOptions: + # Top-level doc.comments may contain titles and :idx: statements: + for fragment in d.modDescPre: + if fragment.isRst: + traverseForIndex(d[], fragment.rst) + setIndexTitle(d, useMetaTitle = d.standaloneDoc) + # Symbol-associated doc.comments may contain :idx: statements: + for k in TSymKind: + for _, overloadChoices in d.section[k].secItems: + for item in overloadChoices: + for fragment in item.descRst: + if fragment.isRst: + traverseForIndex(d[], fragment.rst) # add anchors to overload groups before RST resolution for k in TSymKind: @@ -1362,14 +1433,25 @@ proc finishGenerateDoc*(d: var PDoc) = let refn = overloadGroupName(plainName, k) let tooltip = "$1 ($2 overloads)" % [ k.toHumanStr & " " & plainName, $overloadChoices.len] - addAnchorNim(d.sharedState, refn, tooltip, + let name = nimIdentBackticksNormalize(plainName) + # save overload group to ``.idx`` + let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/'). + changeFileExt(HtmlExt).string + setIndexTerm(d[], ieNimGroup, htmlFile = external, id = refn, + term = name, linkTitle = k.toHumanStr, + linkDesc = "", line = overloadChoices[0].info.line.int) + if optGenIndexOnly in d.conf.globalOptions: continue + addAnchorNim(d.sharedState, external=false, refn, tooltip, LangSymbol(symKind: k.toHumanStr, - name: nimIdentBackticksNormalize(plainName), + name: name, isGroup: true), priority = symbolPriority(k), # select index `0` just to have any meaningful warning: info = overloadChoices[0].info) + if optGenIndexOnly in d.conf.globalOptions: + return + # Finalize fragments of ``.nim`` or ``.rst`` file proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) = for f in fragments: @@ -1421,6 +1503,9 @@ proc finishGenerateDoc*(d: var PDoc) = d.jEntriesFinal.add entry.json # generates docs + setIndexTitle(d, useMetaTitle = d.standaloneDoc) + completePass2(d.sharedState) + proc add(d: PDoc; j: JsonItem) = if j.json != nil or j.rst != nil: d.jEntriesPre.add j @@ -1467,7 +1552,7 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = else: discard proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string = - result = getName(d, nameNode) & "\n" + result = getNameEsc(d, nameNode) & "\n" proc generateTags*(d: PDoc, n: PNode, r: var string) = case n.kind @@ -1574,13 +1659,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = # Extract the title. Non API modules generate an entry in the index table. if d.meta[metaTitle].len != 0: title = d.meta[metaTitle] - let external = AbsoluteFile(d.destFile) - .relativeTo(d.conf.outDir, '/') - .changeFileExt(HtmlExt) - .string - setIndexTerm(d[], external, "", title) else: - # Modules get an automatic title for the HTML, but no entry in the index. title = canonicalImport(d.conf, AbsoluteFile d.filename) title = esc(d.target, title) var subtitle = "" @@ -1619,11 +1698,17 @@ proc genOutFile(d: PDoc, groupedToc = false): string = code = content result = code +proc indexFile(d: PDoc): AbsoluteFile = + let dir = d.conf.outDir + result = dir / changeFileExt(presentationPath(d.conf, + AbsoluteFile d.filename), + IndexExt) + let (finalDir, _, _) = result.string.splitFile + createDir(finalDir) + proc generateIndex*(d: PDoc) = if optGenIndex in d.conf.globalOptions: - let dir = d.conf.outDir - createDir(dir) - let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt) + let dest = indexFile(d) writeIndexFile(d[], dest.string) proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = @@ -1634,6 +1719,9 @@ proc updateOutfile(d: PDoc, outfile: AbsoluteFile) = d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) = + if optGenIndexOnly in d.conf.globalOptions: + d.conf.outFile = indexFile(d).relativeTo(d.conf.outDir) # just for display + return runAllExamples(d) var content = genOutFile(d, groupedToc) if optStdout in d.conf.globalOptions: @@ -1772,6 +1860,8 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) = rawMessage(conf, errCannotOpenFile, filename.string) proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") = + if optGenIndexOnly in conf.globalOptions: + return var content = mergeIndexes(dir) var outFile = outFile diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index cb60d8949..89aff57df 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -57,6 +57,7 @@ type warnRstBrokenLink = "BrokenLink", warnRstLanguageXNotSupported = "LanguageXNotSupported", warnRstFieldXNotSupported = "FieldXNotSupported", + warnRstUnusedImportdoc = "UnusedImportdoc", warnRstStyle = "warnRstStyle", warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam", @@ -142,6 +143,7 @@ const warnRstBrokenLink: "broken link '$1'", warnRstLanguageXNotSupported: "language '$1' not supported", warnRstFieldXNotSupported: "field '$1' not supported", + warnRstUnusedImportdoc: "importdoc for '$1' is not used", warnRstStyle: "RST style: $1", warnCommentXIgnored: "comment '$1' ignored", warnTypelessParam: "", # deadcode diff --git a/compiler/options.nim b/compiler/options.nim index 47e8155f8..fc970e420 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -78,6 +78,8 @@ type # please make sure we have under 32 options optThreadAnalysis, # thread analysis pass optTlsEmulation, # thread var emulation turned on optGenIndex # generate index file for documentation; + optGenIndexOnly # generate only index file for documentation + optNoImportdoc # disable loading external documentation files optEmbedOrigSrc # embed the original source in the generated code # also: generate header file optIdeDebug # idetools: debug mode diff --git a/doc/advopt.txt b/doc/advopt.txt index 3f439fdab..efff428e8 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -130,7 +130,9 @@ Advanced options: select which memory management to use; default is 'orc' --exceptions:setjmp|cpp|goto|quirky select the exception handling implementation - --index:on|off turn index file generation on|off + --index:on|off|only docgen: turn index file generation? (`only` means + not generate output files like HTML) + --noImportdoc:on|off disable loading documentation ``.idx`` files? --putenv:key=value set an environment variable --NimblePath:PATH add a path for Nimble support --noNimblePath deactivate the Nimble path diff --git a/doc/docgen.md b/doc/docgen.md index e4b040064..70b41f17d 100644 --- a/doc/docgen.md +++ b/doc/docgen.md @@ -9,6 +9,7 @@ .. include:: rstcommon.rst .. contents:: +.. importdoc:: markdown_rst.md, compiler/docgen.nim Introduction ============ @@ -103,6 +104,64 @@ won't influence RST formatting. ## Paragraph. ``` +Structuring output directories +------------------------------ + +Basic directory for output is set by `--outdir:OUTDIR`:option: switch, +by default `OUTDIR` is ``htmldocs`` sub-directory in the directory of +the processed file. + +There are 2 basic options as to how generated HTML output files are stored: + +1) complex hierarchy when docgen-compiling with `--project`:option:, + which follows directory structure of the project itself. + So `nim doc`:cmd: replicates project's directory structure + inside `--outdir:OUTDIR`:option: directory. + `--project`:option: is well suited for projects that have 1 main module. + File name clashes are impossible in this case. + +2) flattened structure, where user-provided script goes through all + needed input files and calls commands like `nim doc`:cmd: + with `--outdir:OUTDIR`:option: switch, thus putting all HTML (and + ``.idx``) files into 1 directory. + + .. Important:: Make sure that you don't have files with same base name + like ``x.nim`` and ``x.md`` in the same package, otherwise you'll + have name conflict for ``x.html``. + + .. Tip:: To structure your output directories and avoid file name + clashes you can split your project into + different *packages* -- parts of your repository that are + docgen-compiled with different `--outdir:OUTDIR`:option: options. + + An example of such strategy is Nim repository itself which has: + + * its stdlib ``.nim`` files from different directories and ``.md`` + documentation from ``doc/`` directory are all docgen-compiled + into `--outdir:web/upload//`:option: directory + * its ``.nim`` files from ``compiler/`` directory are docgen-compiled + into `--outdir:web/upload//compiler/`:option: directory. + Interestingly, it's compiled with complex hierarchy using + `--project`:option: switch. + + Contents of ``web/upload/`` are then deployed into Nim's + Web server. + + This output directory structure allows to work correctly with files like + ``compiler/docgen.nim`` (implementation) and ``doc/docgen.md`` (user + documentation) in 1 repository. + + +Index files +----------- + +Index (``.idx``) files are used for 2 different purposes: + +1. easy cross-referencing between different ``.nim`` and/or ``.md`` / ``.rst`` + files described in [Nim external referencing] +2. creating a whole-project index for searching of symbols and keywords, + see [Buildindex command]. + Document Types ============== @@ -226,13 +285,46 @@ Note that the `jsondoc`:option: command outputs its JSON without pretty-printing while `jsondoc0`:option: outputs pretty-printed JSON. -Referencing Nim symbols: simple documentation links -=================================================== +Simple documentation links +========================== -You can reference Nim identifiers from Nim documentation comments, currently -only inside their ``.nim`` file (or inside a ``.rst`` file included from -a ``.nim``). The point is that such links will be resolved automatically -by `nim doc`:cmd: (or `nim jsondoc`:cmd: or `nim doc2tex`:cmd:). +It's possible to use normal Markdown/RST syntax to *manually* +reference Nim symbols using HTML anchors, however Nim has an *automatic* +facility that makes referencing inside ``.nim`` and ``.md/.rst`` files and +between them easy and seamless. +The point is that such links will be resolved automatically +by `nim doc`:cmd: (or `md2html`:option:, or `jsondoc`:option:, +or `doc2tex`:option:, ...). And, unlike manual links, such automatic +links **check** that their target exists -- a warning is emitted for +any broken link, so you avoid broken links in your project. + +Nim treats both ``.md/.rst`` files and ``.nim`` modules (their doc comment +part) as *documents* uniformly. +Hence all directions of referencing are equally possible having the same syntax: + +1. ``.md/rst`` -> itself (internal). See [Markup local referencing]. +2. ``.md/rst`` -> external ``.md/rst``. See [Markup external referencing]. + To summarize, referencing in `.md`/`.rst` files was already described in + [Nim-flavored Markdown and reStructuredText] + (particularly it described usage of index files for referencing), + while in this document we focus on Nim-specific details. +3. ``.md/rst`` -> external ``.nim``. See [Nim external referencing]. +4. ``.nim`` -> itself (internal). See [Nim local referencing]. +5. ``.nim`` -> external ``.md/rst``. See [Markup external referencing]. +6. ``.nim`` -> external ``.nim``. See [Nim external referencing]. + +To put it shortly, local referencing always works out of the box, +external referencing requires to use ``.. importdoc:: `` +directive to import `file` and to ensure that the corresponding +``.idx`` file was generated. + + +Nim local referencing +--------------------- + +You can reference Nim identifiers from Nim documentation comments +inside their ``.nim`` file (or inside a ``.rst`` file included from +a ``.nim``). This pertains to any exported symbol like `proc`, `const`, `iterator`, etc. Syntax for referencing is basically a normal RST one: addition of underscore `_` to a *link text*. @@ -405,6 +497,143 @@ recognized fine: ... ## Ref. `CopyFlag enum`_ +Nim external referencing +------------------------ + +Just like for [Markup external referencing], which saves markup anchors, +the Nim symbols are also saved in ``.idx`` files, so one needs +to generate them beforehand, and they should be loaded by +an ``.. importdoc::`` directive. Arguments to ``.. importdoc::`` is a +comma-separated list of Nim modules or Markdown/RST documents. + +`--index:only`:option: tells Nim to only generate ``.idx`` file and +do **not** attempt to generate HTML/LaTeX output. +For ``.nim`` modules there are 2 alternatives to work with ``.idx`` files: + +1. using [Project switch] implies generation of ``.idx`` files, + however, if ``importdoc`` is called on upper modules as its arguments, + their ``.idx`` are not yet created. Thus one should generate **all** + required ``.idx`` first: + ```cmd + nim doc --project --index:only
      .nim + nim doc --project
      .nim + ``` +2. or run `nim doc --index:only `:cmd: command for **all** (used) + Nim modules in your project. Then run `nim doc ` on them for + output HTML generation. + + .. Warning:: A mere `nim doc --index:on`:cmd: may fail on an attempt to do + ``importdoc`` from another module (for which ``.idx`` was not yet + generated), that's why `--index:only`:option: shall be used instead. + + For ``.md``/``.rst`` markup documents point 2 is the only option. + +Then, you can freely use something like this in ``your_module.nim``: + + ```nim + ## .. importdoc:: user_manual.md, another_module.nim + + ... + ## Ref. [some section from User Manual]. + + ... + ## Ref. [proc f] + ## (assuming you have a proc `f` in ``another_module``). + ``` + +and compile it by `nim doc`:cmd:. Note that link text will +be automatically prefixed by the module name of symbol, +so you will see something like "Ref. [another_module: proc f](#)" +in the generated output. + +It's also possible to reference a whole module by prefixing or +suffixing full canonical module name with "module": + + Ref. [module subdir/name] or [subdir/name module]. + +Markup documents as a whole can be referenced just by their title +(or by their file name if the title was not set) without any prefix. + +.. Tip:: During development process the stage of ``.idx`` files generation + can be done only *once*, after that you use already generated ``.idx`` + files while working with a document *being developed* (unless you do + incompatible changes to *referenced* documents). + +.. Hint:: After changing a *referenced* document file one may need + to regenerate its corresponding ``.idx`` file to get correct results. + Of course, when referencing *internally* inside any given ``.nim`` file, + it's not needed, one can even immediately use any freshly added anchor + (a document's own ``.idx`` file is not used for resolving its internal links). + +If an ``importdoc`` directive fails to find a ``.idx``, then an error +is emitted. + +In case of such compilation failures please note that: + +* **all** relative paths, given to ``importdoc``, relate to insides of + ``OUTDIR``, and **not** project's directory structure. + +* ``importdoc`` searches for ``.idx`` in `--outdir:OUTDIR`:option: directory + (``htmldocs`` by default) and **not** around original modules, so: + + .. Tip:: look into ``OUTDIR`` to understand what's going on. + +* also keep in mind that ``.html`` and ``.idx`` files should always be + output to the same directory, so check this and, if it's not true, check + that both runs *with* and *without* `--index:only`:option: have all + other options the same. + +To summarize, for 2 basic options of [Structuring output directories] +compilation options are different: + +1) complex hierarchy with `--project`:option: switch. + + As the **original** project's directory structure is replicated in + `OUTDIR`, all passed paths are related to this structure also. + + E.g. if a module ``path1/module.nim`` does + ``.. importdoc:: path2/another.nim`` then docgen tries to load file + ``OUTDIR/path1/path2/another.idx``. + + .. Note:: markup documents are just placed into the specified directory + `OUTDIR`:option: by default (i.e. they are **not** affected by + `--project`:option:), so if you have ``PROJECT/doc/manual.md`` + document and want to use complex hirearchy (with ``doc/``), + compile it with `--docroot`:option:\: + ```cmd + # 1st stage + nim md2html --outdir:OUTDIR --docroot:/absolute/path/to/PROJECT \ + --index:only PROJECT/doc/manual.md + ... + # 2nd stage + nim md2html --outdir:OUTDIR --docroot:/absolute/path/to/PROJECT \ + PROJECT/doc/manual.md + ``` + + Then the output file will be placed as ``OUTDIR/doc/manual.idx``. + So if you have ``PROJECT/path1/module.nim``, then ``manual.md`` can + be referenced as ``../doc/manual.md``. + +2) flattened structure. + + E.g. if a module ``path1/module.nim`` does + ``.. importdoc:: path2/another.nim`` then docgen tries to load + ``OUTDIR/path2/another.idx``, so the path ``path1`` + does not matter and providing ``path2`` can be useful only + in the case it contains another package that was placed there + using `--outdir:OUTDIR/path2`:option:. + + The links' text will be prefixed as ``another: ...`` in both cases. + + .. Warning:: Again, the same `--outdir:OUTDIR`:option: option should + be provided to both `doc --index:only`:option: / + `md2html --index:only`:option: and final generation by + `doc`:option:/`md2html`:option: inside 1 package. + +To temporarily disable ``importdoc``, e.g. if you don't need +correct link resolution at the moment, use a `--noImportdoc`:option: switch +(only warnings about unresolved links will be generated for external references). + Related Options =============== @@ -434,10 +663,21 @@ index file is line-oriented (newlines have to be escaped). Each line represents a tab-separated record of several columns, the first two mandatory, the rest optional. See the [Index (idx) file format] section for details. +.. Note:: `--index`:option: switch only affects creation of ``.idx`` + index files, while user-searchable Index HTML file is created by + `buildIndex`:option: commmand. + +Buildindex command +------------------ + Once index files have been generated for one or more modules, the Nim -compiler command `buildIndex directory` can be run to go over all the index +compiler command `nim buildIndex directory`:cmd: can be run to go over all the index files in the specified directory to generate a [theindex.html](theindex.html) -file. +file: + + ```cmd + nim buildIndex -o:path/to/htmldocs/theindex.html path/to/htmldocs + ``` See source switch ----------------- @@ -568,10 +808,22 @@ references so they can be later concatenated into a big index file with the file format in detail. Index files are line-oriented and tab-separated (newline and tab characters -have to be escaped). Each line represents a record with at least two fields -but can have up to four (additional columns are ignored). The content of these -columns is: +have to be escaped). Each line represents a record with 6 fields. +The content of these columns is: +0. Discriminator tag denoting type of the index entry, allowed values are: + `markupTitle` + : a title for ``.md``/``.rst`` document + `nimTitle` + : a title of ``.nim`` module + `heading` + : heading of sections, can be both in Nim and markup files + `idx` + : terms marked with :idx: role + `nim` + : a Nim symbol + `nimgrp` + : a Nim group for overloadable symbols like `proc`s 1. Mandatory term being indexed. Terms can include quoting according to Nim's rules (e.g. \`^\`). 2. Base filename plus anchor hyperlink (e.g. ``algorithm.html#*,int,SortOrder``). @@ -581,29 +833,20 @@ columns is: not for an API symbol but for a TOC entry. 4. Optional title or description of the hyperlink. Browsers usually display this as a tooltip after hovering a moment over the hyperlink. +5. A line number of file where the entry was defined. -The index generation tools try to differentiate between documentation -generated from ``.nim`` files and documentation generated from ``.txt`` or -``.rst`` files. The former are always closely related to source code and -consist mainly of API entries. The latter are generic documents meant for -human reading. +The index generation tools differentiate between documentation +generated from ``.nim`` files and documentation generated from ``.md`` or +``.rst`` files by tag `nimTitle` or `markupTitle` in the 1st line of +the ``.idx`` file. -To differentiate both types (documents and APIs), the index generator will add -to the index of documents an entry with the title of the document. Since the -title is the topmost element, it will be added with a second field containing -just the filename without any HTML anchor. By convention, this entry without -anchor is the *title entry*, and since entries in the index file are added as -they are scanned, the title entry will be the first line. The title for APIs -is not present because it can be generated concatenating the name of the file -to the word **Module**. - -Normal symbols are added to the index with surrounding whitespaces removed. An -exception to this are the table of content (TOC) entries. TOC entries are added to -the index file with their third column having as much prefix spaces as their -level is in the TOC (at least 1 character). The prefix whitespace helps to -filter TOC entries from API or text symbols. This is important because the -amount of spaces is used to replicate the hierarchy for document TOCs in the -final index, and TOC entries found in ``.nim`` files are discarded. +.. TODO Normal symbols are added to the index with surrounding whitespaces removed. An + exception to this are the table of content (TOC) entries. TOC entries are added to + the index file with their third column having as much prefix spaces as their + level is in the TOC (at least 1 character). The prefix whitespace helps to + filter TOC entries from API or text symbols. This is important because the + amount of spaces is used to replicate the hierarchy for document TOCs in the + final index, and TOC entries found in ``.nim`` files are discarded. Additional resources @@ -615,6 +858,8 @@ Additional resources [Markdown and RST markup languages](markdown_rst.html), which also contains the list of implemented features of these markup languages. +* the implementation is in [module compiler/docgen]. + The output for HTML and LaTeX comes from the ``config/nimdoc.cfg`` and ``config/nimdoc.tex.cfg`` configuration files. You can add and modify these files to your project to change the look of the docgen output. diff --git a/doc/markdown_rst.md b/doc/markdown_rst.md index 5fb3caefc..a374749cb 100644 --- a/doc/markdown_rst.md +++ b/doc/markdown_rst.md @@ -9,6 +9,8 @@ Nim-flavored Markdown and reStructuredText .. include:: rstcommon.rst .. contents:: +.. importdoc:: docgen.md + Both `Markdown`:idx: (md) and `reStructuredText`:idx: (RST) are markup languages whose goal is to typeset texts with complex structure, formatting and references using simple plaintext representation. @@ -110,6 +112,8 @@ Supported standard RST features: Additional Nim-specific features -------------------------------- +* referencing to definitions in external files, see + [Markup external referencing] section * directives: ``code-block`` \[cmp:Sphinx], ``title``, ``index`` \[cmp:Sphinx] * predefined roles @@ -170,6 +174,86 @@ Optional additional features, by default turned on: .. warning:: Using Nim-specific features can cause other RST implementations to fail on your document. +Referencing +=========== + +To be able to copy and share links Nim generates anchors for all +main document elements: + +* headlines (including document title) +* footnotes +* explicitly set anchors: RST internal cross-references and + inline internal targets +* Nim symbols (external referencing), see [Nim DocGen Tools Guide] for details. + +But direct use of those anchors have 2 problems: + +1. the anchors are usually mangled (e.g. spaces substituted to minus + signs, etc). +2. manual usage of anchors is not checked, so it's easy to get broken + links inside your project if e.g. spelling has changed for a heading + or you use a wrong relative path to your document. + +That's why Nim implementation has syntax for using +*original* labels for referencing. +Such referencing can be either local/internal or external: + +* Local referencing (inside any given file) is defined by + RST standard or Pandoc Markdown User guide. +* External (cross-document) referencing is a Nim-specific feature, + though it's not really different from local referencing by its syntax. + +Markup local referencing +------------------------ + +There are 2 syntax option available for referencing to objects +inside any given file, e.g. for headlines: + + Markdown RST + + Some headline Some headline + ============= ============= + + Ref. [Some headline] Ref. `Some headline`_ + + +Markup external referencing +--------------------------- + +The syntax is the same as for local referencing, but the anchors are +saved in ``.idx`` files, so one needs to generate them beforehand, +and they should be loaded by an `.. importdoc::` directive. +E.g. if we want to reference section "Some headline" in ``file1.md`` +from ``file2.md``, then ``file2.md`` may look like: + +``` +.. importdoc:: file1.md + +Ref. [Some headline] +``` + +```cmd +nim md2html --index:only file1.md # creates ``htmldocs/file1.idx`` +nim md2html file2.md # creates ``htmldocs/file2.html`` +``` + +To allow cross-references between any files in any order (especially, if +circular references are present), it's strongly reccommended +to make a run for creating all the indexes first: + +```cmd +nim md2html --index:only file1.md # creates ``htmldocs/file1.idx`` +nim md2html --index:only file2.md # creates ``htmldocs/file2.idx`` +nim md2html file1.md # creates ``htmldocs/file1.html`` +nim md2html file2.md # creates ``htmldocs/file2.html`` +``` + +and then one can freely reference any objects as if these 2 documents +are actually 1 file. + +Other +===== + Idiosyncrasies -------------- diff --git a/lib/core/macros.nim b/lib/core/macros.nim index bcc16038b..beb3aa695 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -23,6 +23,8 @@ when defined(nimPreviewSlimSystem): ## .. include:: ../../doc/astspec.txt +## .. importdoc:: system.nim + # If you look for the implementation of the magic symbol # ``{.magic: "Foo".}``, search for `mFoo` and `opcFoo`. diff --git a/lib/packages/docutils/dochelpers.nim b/lib/packages/docutils/dochelpers.nim index c7f7f73f5..b7cdd16d2 100644 --- a/lib/packages/docutils/dochelpers.nim +++ b/lib/packages/docutils/dochelpers.nim @@ -13,7 +13,7 @@ ## `type LangSymbol`_ in ``rst.nim``, while `match(generated, docLink)`_ ## matches it with `generated`, produced from `PNode` by ``docgen.rst``. -import rstast +import rstast, strutils when defined(nimPreviewSlimSystem): import std/[assertions, syncio] @@ -35,6 +35,12 @@ type ## name-type seq, e.g. for proc outType*: string ## result type, e.g. for proc +proc `$`*(s: LangSymbol): string = # for debug + ("(symkind=$1, symTypeKind=$2, name=$3, generics=$4, isGroup=$5, " & + "parametersProvided=$6, parameters=$7, outType=$8)") % [ + s.symKind, s.symTypeKind , s.name, s.generics, $s.isGroup, + $s.parametersProvided, $s.parameters, s.outType] + func nimIdentBackticksNormalize*(s: string): string = ## Normalizes the string `s` as a Nim identifier. ## @@ -71,6 +77,12 @@ func nimIdentBackticksNormalize*(s: string): string = else: discard # just omit '`' or ' ' if j != s.len: setLen(result, j) +proc langSymbolGroup*(kind: string, name: string): LangSymbol = + if kind notin ["proc", "func", "macro", "method", "iterator", + "template", "converter"]: + raise newException(ValueError, "unknown symbol kind $1" % [kind]) + result = LangSymbol(symKind: kind, name: name, isGroup: true) + proc toLangSymbol*(linkText: PRstNode): LangSymbol = ## Parses `linkText` into a more structured form using a state machine. ## @@ -82,11 +94,14 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol = ## ## This proc should be kept in sync with the `renderTypes` proc from ## ``compiler/typesrenderer.nim``. - assert linkText.kind in {rnRstRef, rnInner} + template fail(msg: string) = + raise newException(ValueError, msg) + if linkText.kind notin {rnRstRef, rnInner}: + fail("toLangSymbol: wrong input kind " & $linkText.kind) const NimDefs = ["proc", "func", "macro", "method", "iterator", "template", "converter", "const", "type", "var", - "enum", "object", "tuple"] + "enum", "object", "tuple", "module"] template resolveSymKind(x: string) = if x in ["enum", "object", "tuple"]: result.symKind = "type" @@ -109,11 +124,11 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol = template flushIdent() = if curIdent != "": case state - of inBeginning: doAssert false, "incorrect state inBeginning" + of inBeginning: fail("incorrect state inBeginning") of afterSymKind: resolveSymKind curIdent - of beforeSymbolName: doAssert false, "incorrect state beforeSymbolName" + of beforeSymbolName: fail("incorrect state beforeSymbolName") of atSymbolName: result.name = curIdent.nimIdentBackticksNormalize - of afterSymbolName: doAssert false, "incorrect state afterSymbolName" + of afterSymbolName: fail("incorrect state afterSymbolName") of genericsPar: result.generics = curIdent of parameterName: result.parameters.add (curIdent, "") of parameterType: diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index e9f76a26f..b3b1fb9c0 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -22,7 +22,7 @@ import os, strutils, rstast, dochelpers, std/enumutils, algorithm, lists, sequtils, - std/private/miscdollars, tables, strscans + std/private/miscdollars, tables, strscans, rstidx from highlite import SourceLanguage, getSourceLanguage when defined(nimPreviewSlimSystem): @@ -40,7 +40,7 @@ type roNimFile ## set for Nim files where default interpreted ## text role should be :nim: roSandboxDisabled ## this option enables certain options - ## (e.g. raw, include) + ## (e.g. raw, include, importdoc) ## which are disabled by default as they can ## enable users to read arbitrary data and ## perform XSS if the parser is used in a web @@ -73,11 +73,17 @@ type mwUnsupportedLanguage = "language '$1' not supported", mwUnsupportedField = "field '$1' not supported", mwRstStyle = "RST style: $1", + mwUnusedImportdoc = "importdoc for '$1' is not used", meSandboxedDirective = "disabled directive: '$1'", MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind, arg: string) {.closure, gcsafe.} ## what to do in case of an error FindFileHandler* = proc (filename: string): string {.closure, gcsafe.} + FindRefFileHandler* = + proc (targetRelPath: string): + tuple[targetPath: string, linkRelPath: string] {.closure, gcsafe.} + ## returns where .html or .idx file should be found by its relative path; + ## `linkRelPath` is a prefix to be added before a link anchor from such file proc rstnodeToRefname*(n: PRstNode): string proc addNodes*(n: PRstNode): string @@ -333,7 +339,8 @@ type arInternalRst, ## For automatically generated RST anchors (from ## headings, footnotes, inline internal targets): ## case-insensitive, 1-space-significant (by RST spec) - arNim ## For anchors generated by ``docgen.rst``: Nim-style case + arExternalRst, ## For external .nim doc comments or .rst/.md + arNim ## For anchors generated by ``docgen.nim``: Nim-style case ## sensitivity, etc. (see `proc normalizeNimName`_ for details) arHyperlink, ## For links with manually set anchors in ## form `text `_ @@ -349,11 +356,15 @@ type of arInternalRst: anchorType: RstAnchorKind target: PRstNode + of arExternalRst: + anchorTypeExt: RstAnchorKind + refnameExt: string of arNim: tooltip: string # displayed tooltip for Nim-generated anchors langSym: LangSymbol refname: string # A reference name that will be inserted directly # into HTML/Latex. + external: bool AnchorSubstTable = Table[string, seq[AnchorSubst]] # use `seq` to account for duplicate anchors FootnoteType = enum @@ -372,6 +383,12 @@ type RstFileTable* = object filenameToIdx*: Table[string, FileIndex] idxToFilename*: seq[string] + ImportdocInfo = object + used: bool # was this import used? + fromInfo: TLineInfo # place of `.. importdoc::` directive + idxPath: string # full path to ``.idx`` file + linkRelPath: string # prefix before target anchor + title: string # document title obtained from ``.idx`` RstSharedState = object options*: RstParseOptions # parsing options hLevels: LevelMap # hierarchy of heading styles @@ -393,12 +410,17 @@ type footnotes: seq[FootnoteSubst] # correspondence b/w footnote label, # number, order of occurrence msgHandler: MsgHandler # How to handle errors. - findFile: FindFileHandler # How to find files. + findFile: FindFileHandler # How to find files for include. + findRefFile: FindRefFileHandler + # How to find files imported by importdoc. filenames*: RstFileTable # map file name <-> FileIndex (for storing # file names for warnings after 1st stage) currFileIdx*: FileIndex # current index in `filenames` tocPart*: seq[PRstNode] # all the headings of a document hasToc*: bool + idxImports*: Table[string, ImportdocInfo] + # map `importdoc`ed filename -> it's info + nimFileImported*: bool # Was any ``.nim`` module `importdoc`ed ? PRstSharedState* = ref RstSharedState ManualAnchor = object @@ -452,6 +474,9 @@ proc defaultFindFile*(filename: string): string = if fileExists(filename): result = filename else: result = "" +proc defaultFindRefFile*(filename: string): (string, string) = + (filename, "") + proc defaultRole(options: RstParseOptions): string = if roNimFile in options: "nim" else: "literal" @@ -492,12 +517,16 @@ proc getFilename(filenames: RstFileTable, fid: FileIndex): string = $fid.int, $(filenames.len - 1)]) result = filenames.idxToFilename[fid.int] +proc getFilename(s: PRstSharedState, subst: AnchorSubst): string = + getFilename(s.filenames, subst.info.fileIndex) + proc currFilename(s: PRstSharedState): string = getFilename(s.filenames, s.currFileIdx) proc newRstSharedState*(options: RstParseOptions, filename: string, findFile: FindFileHandler, + findRefFile: FindRefFileHandler, msgHandler: MsgHandler, hasToc: bool): PRstSharedState = let r = defaultRole(options) @@ -507,6 +536,9 @@ proc newRstSharedState*(options: RstParseOptions, options: options, msgHandler: if not isNil(msgHandler): msgHandler else: defaultMsgHandler, findFile: if not isNil(findFile): findFile else: defaultFindFile, + findRefFile: + if not isNil(findRefFile): findRefFile + else: defaultFindRefFile, hasToc: hasToc ) setCurrFilename(result, filename) @@ -525,6 +557,14 @@ proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = proc rstMessage(s: PRstSharedState, msgKind: MsgKind, arg: string) = s.msgHandler(s.currFilename, LineRstInit, ColRstInit, msgKind, arg) +proc rstMessage(s: PRstSharedState, msgKind: MsgKind, arg: string; + line, col: int) = + s.msgHandler(s.currFilename, line, col, msgKind, arg) + +proc rstMessage(s: PRstSharedState, filename: string, msgKind: MsgKind, + arg: string) = + s.msgHandler(filename, LineRstInit, ColRstInit, msgKind, arg) + proc rstMessage*(filenames: RstFileTable, f: MsgHandler, info: TLineInfo, msgKind: MsgKind, arg: string) = ## Print warnings using `info`, i.e. in 2nd-pass warnings for @@ -756,6 +796,14 @@ proc internalRefPriority(k: RstAnchorKind): int = of footnoteAnchor: result = 4 of headlineAnchor: result = 3 +proc `$`(subst: AnchorSubst): string = # for debug + let s = + case subst.kind + of arInternalRst: "type=" & $subst.anchorType + of arExternalRst: "type=" & $subst.anchorTypeExt + of arNim: "langsym=" & $subst.langSym + result = "(kind=$1, priority=$2, $3)" % [$subst.kind, $subst.priority, s] + proc addAnchorRst(p: var RstParser, name: string, target: PRstNode, anchorType: RstAnchorKind) = ## Associates node `target` (which has field `anchor`) with an @@ -771,31 +819,49 @@ proc addAnchorRst(p: var RstParser, name: string, target: PRstNode, info: prevLineInfo(p), anchorType: anchorType)) p.curAnchors.setLen 0 -proc addAnchorNim*(s: var PRstSharedState, refn: string, tooltip: string, +proc addAnchorExtRst(s: var PRstSharedState, key: string, refn: string, + anchorType: RstAnchorKind, info: TLineInfo) = + let name = key.toLowerAscii + let prio = internalRefPriority(anchorType) + s.anchors.mgetOrPut(name, newSeq[AnchorSubst]()).add( + AnchorSubst(kind: arExternalRst, refnameExt: refn, priority: prio, + info: info, + anchorTypeExt: anchorType)) + +proc addAnchorNim*(s: var PRstSharedState, external: bool, refn: string, tooltip: string, langSym: LangSymbol, priority: int, info: TLineInfo) = ## Adds an anchor `refn`, which follows ## the rule `arNim` (i.e. a symbol in ``*.nim`` file) s.anchors.mgetOrPut(langSym.name, newSeq[AnchorSubst]()).add( - AnchorSubst(kind: arNim, refname: refn, langSym: langSym, + AnchorSubst(kind: arNim, external: external, refname: refn, langSym: langSym, tooltip: tooltip, priority: priority, info: info)) proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode, info: TLineInfo): seq[AnchorSubst] = - let langSym = toLangSymbol(signature) + var langSym: LangSymbol + try: + langSym = toLangSymbol(signature) + except ValueError: # parsing failed, not a Nim symbol + return let substitutions = s.anchors.getOrDefault(langSym.name, newSeq[AnchorSubst]()) if substitutions.len == 0: return - # map symKind (like "proc") -> found symbols/groups: - var found: Table[string, seq[AnchorSubst]] - for s in substitutions: - if s.kind == arNim: - if match(s.langSym, langSym): - found.mgetOrPut(s.langSym.symKind, newSeq[AnchorSubst]()).add s - for symKind, sList in found: + # logic to select only groups instead of concrete symbols + # with overloads, note that the same symbol can be defined + # in multiple modules and `importdoc`ed: + type GroupKey = tuple[symKind: string, origModule: string] + # map (symKind, file) (like "proc", "os.nim") -> found symbols/groups: + var found: Table[GroupKey, seq[AnchorSubst]] + for subst in substitutions: + if subst.kind == arNim: + if match(subst.langSym, langSym): + let key: GroupKey = (subst.langSym.symKind, getFilename(s, subst)) + found.mgetOrPut(key, newSeq[AnchorSubst]()).add subst + for key, sList in found: if sList.len == 1: result.add sList[0] else: # > 1, there are overloads, potential ambiguity in this `symKind` @@ -812,14 +878,16 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode, result.add s foundGroup = true break - doAssert foundGroup, "docgen has not generated the group" + doAssert(foundGroup, + "docgen has not generated the group for $1 (file $2)" % [ + langSym.name, getFilename(s, sList[0]) ]) proc findMainAnchorRst(s: PRstSharedState, linkText: string, info: TLineInfo): seq[AnchorSubst] = let name = linkText.toLowerAscii let substitutions = s.anchors.getOrDefault(name, newSeq[AnchorSubst]()) for s in substitutions: - if s.kind == arInternalRst: + if s.kind in {arInternalRst, arExternalRst}: result.add s proc addFootnoteNumManual(p: var RstParser, num: int) = @@ -3251,6 +3319,15 @@ proc dirRaw(p: var RstParser): PRstNode = else: dirRawAux(p, result, rnRaw, parseSectionWrapper) +proc dirImportdoc(p: var RstParser): PRstNode = + result = parseDirective(p, rnDirective, {}, parseLiteralBlock) + assert result.sons[2].kind == rnLiteralBlock + assert result.sons[2].sons[0].kind == rnLeaf + let filenames: seq[string] = split(result.sons[2].sons[0].text, seps = {','}) + proc rmSpaces(s: string): string = s.split.join("") + for origFilename in filenames: + p.s.idxImports[origFilename.rmSpaces] = ImportdocInfo(fromInfo: lineInfo(p)) + proc selectDir(p: var RstParser, d: string): PRstNode = result = nil let tok = p.tok[p.idx-2] # report on directive in ".. directive::" @@ -3271,6 +3348,7 @@ proc selectDir(p: var RstParser, d: string): PRstNode = of "hint": result = dirAdmonition(p, d) of "image": result = dirImage(p) of "important": result = dirAdmonition(p, d) + of "importdoc": result = dirImportdoc(p) of "include": result = dirInclude(p) of "index": result = dirIndex(p) of "note": result = dirAdmonition(p, d) @@ -3401,11 +3479,90 @@ proc rstParsePass1*(fragment: string, getTokens(fragment, p.tok) result = parseDoc(p) -proc preparePass2*(s: PRstSharedState, mainNode: PRstNode) = +proc extractLinkEnd(x: string): string = + ## From links like `path/to/file.html#/%` extract `file.html#/%`. + let i = find(x, '#') + let last = + if i >= 0: i + else: x.len - 1 + let j = rfind(x, '/', start=0, last=last) + if j >= 0: + result = x[j+1 .. ^1] + else: + result = x + +proc loadIdxFile(s: var PRstSharedState, origFilename: string) = + doAssert roSandboxDisabled in s.options + var info: TLineInfo + info.fileIndex = addFilename(s, origFilename) + var (dir, basename, ext) = origFilename.splitFile + if ext notin [".md", ".rst", ".nim", ""]: + rstMessage(s.filenames, s.msgHandler, s.idxImports[origFilename].fromInfo, + meCannotOpenFile, origFilename & ": unknown extension") + let idxFilename = dir / basename & ".idx" + let (idxPath, linkRelPath) = s.findRefFile(idxFilename) + s.idxImports[origFilename].linkRelPath = linkRelPath + var + fileEntries: seq[IndexEntry] + title: IndexEntry + try: + (fileEntries, title) = parseIdxFile(idxPath) + except IOError: + rstMessage(s.filenames, s.msgHandler, s.idxImports[origFilename].fromInfo, + meCannotOpenFile, idxPath) + except ValueError as e: + s.msgHandler(idxPath, LineRstInit, ColRstInit, meInvalidField, e.msg) + + var isMarkup = false # for sanity check to avoid mixing .md <-> .nim + for entry in fileEntries: + # Though target .idx already has inside it the path to HTML relative + # project's root, we won't rely on it and use `linkRelPath` instead. + let refn = extractLinkEnd(entry.link) + # select either markup (rst/md) or Nim cases: + if entry.kind in {ieMarkupTitle, ieNimTitle}: + s.idxImports[origFilename].title = entry.keyword + case entry.kind + of ieIdxRole, ieHeading, ieMarkupTitle: + if ext == ".nim" and entry.kind == ieMarkupTitle: + rstMessage(s, idxPath, meInvalidField, + $ieMarkupTitle & " in supposedly .nim-derived file") + if entry.kind == ieMarkupTitle: + isMarkup = true + info.line = entry.line.uint16 + addAnchorExtRst(s, key = entry.keyword, refn = refn, + anchorType = headlineAnchor, info=info) + of ieNim, ieNimGroup, ieNimTitle: + if ext in [".md", ".rst"] or isMarkup: + rstMessage(s, idxPath, meInvalidField, + $entry.kind & " in supposedly markup-derived file") + s.nimFileImported = true + var langSym: LangSymbol + if entry.kind in {ieNim, ieNimTitle}: + var q: RstParser + initParser(q, s) + info.line = entry.line.uint16 + setLen(q.tok, 0) + q.idx = 0 + getTokens(entry.linkTitle, q.tok) + var sons = newSeq[PRstNode](q.tok.len) + for i in 0 ..< q.tok.len: sons[i] = newLeaf(q.tok[i].symbol) + let linkTitle = newRstNode(rnInner, sons) + langSym = linkTitle.toLangSymbol + else: # entry.kind == ieNimGroup + langSym = langSymbolGroup(kind=entry.linkTitle, name=entry.keyword) + addAnchorNim(s, external = true, refn = refn, tooltip = entry.linkDesc, + langSym = langSym, priority = -4, # lowest + info=info) + doAssert s.idxImports[origFilename].title != "" + +proc preparePass2*(s: var PRstSharedState, mainNode: PRstNode, importdoc = true) = ## Records titles in node `mainNode` and orders footnotes. countTitles(s, mainNode) fixHeadlines(s) orderFootnotes(s) + if importdoc: + for origFilename in s.idxImports.keys: + loadIdxFile(s, origFilename) proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode = # Associate this link alias with its target and change node kind to @@ -3423,6 +3580,9 @@ proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode = tooltip: string target: PRstNode info: TLineInfo + externFilename: string + # when external anchor: origin filename where anchor was defined + isTitle: bool proc cmp(x, y: LinkDef): int = result = cmp(x.priority, y.priority) if result == 0: @@ -3435,26 +3595,67 @@ proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode = target: y.value, info: y.info, tooltip: "(" & $y.kind & ")") let substRst = findMainAnchorRst(s, alias.addNodes, n.info) + template getExternFilename(subst: AnchorSubst): string = + if subst.kind == arExternalRst or + (subst.kind == arNim and subst.external): + getFilename(s, subst) + else: "" for subst in substRst: - foundLinks.add LinkDef(ar: arInternalRst, priority: subst.priority, - target: newLeaf(subst.target.anchor), + var refname, fullRefname: string + if subst.kind == arInternalRst: + refname = subst.target.anchor + fullRefname = refname + else: # arExternalRst + refname = subst.refnameExt + fullRefname = s.idxImports[getFilename(s, subst)].linkRelPath & + "/" & refname + let anchorType = + if subst.kind == arInternalRst: subst.anchorType + else: subst.anchorTypeExt # arExternalRst + foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority, + target: newLeaf(fullRefname), info: subst.info, - tooltip: "(" & $subst.anchorType & ")") + externFilename: getExternFilename(subst), + isTitle: isDocumentationTitle(refname), + tooltip: "(" & $anchorType & ")") # find anchors automatically generated from Nim symbols - if roNimFile in s.options: + if roNimFile in s.options or s.nimFileImported: let substNim = findMainAnchorNim(s, signature=alias, n.info) for subst in substNim: - foundLinks.add LinkDef(ar: arNim, priority: subst.priority, - target: newLeaf(subst.refname), + let fullRefname = + if subst.external: + s.idxImports[getFilename(s, subst)].linkRelPath & + "/" & subst.refname + else: subst.refname + foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority, + target: newLeaf(fullRefname), + externFilename: getExternFilename(subst), + isTitle: isDocumentationTitle(subst.refname), info: subst.info, tooltip: subst.tooltip) foundLinks.sort(cmp = cmp, order = Descending) let aliasStr = addNodes(alias) if foundLinks.len >= 1: - let kind = if foundLinks[0].ar == arHyperlink: rnHyperlink - elif foundLinks[0].ar == arNim: rnNimdocRef + if foundLinks[0].externFilename != "": + s.idxImports[foundLinks[0].externFilename].used = true + let kind = if foundLinks[0].ar in {arHyperlink, arExternalRst}: rnHyperlink + elif foundLinks[0].ar == arNim: + if foundLinks[0].externFilename == "": rnNimdocRef + else: rnHyperlink else: rnInternalRef result = newRstNode(kind) - result.sons = @[newRstNode(rnInner, desc.sons), foundLinks[0].target] + let documentName = # filename without ext for `.nim`, title for `.md` + if foundLinks[0].ar == arNim: + changeFileExt(foundLinks[0].externFilename.extractFilename, "") + elif foundLinks[0].externFilename != "": + s.idxImports[foundLinks[0].externFilename].title + else: foundLinks[0].externFilename.extractFilename + let linkText = + if foundLinks[0].externFilename != "": + if foundLinks[0].isTitle: newLeaf(addNodes(desc)) + else: newLeaf(documentName & ": " & addNodes(desc)) + else: + newRstNode(rnInner, desc.sons) + result.sons = @[linkText, foundLinks[0].target] if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip if foundLinks.len > 1: # report ambiguous link var targets = newSeq[string]() @@ -3568,20 +3769,28 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = inc i result.sons = newSons +proc completePass2*(s: PRstSharedState) = + for (filename, importdocInfo) in s.idxImports.pairs: + if not importdocInfo.used: + rstMessage(s.filenames, s.msgHandler, importdocInfo.fromInfo, + mwUnusedImportdoc, filename) + proc rstParse*(text, filename: string, line, column: int, options: RstParseOptions, findFile: FindFileHandler = nil, + findRefFile: FindRefFileHandler = nil, msgHandler: MsgHandler = nil): tuple[node: PRstNode, filenames: RstFileTable, hasToc: bool] = ## Parses the whole `text`. The result is ready for `rstgen.renderRstToOut`, ## note that 2nd tuple element should be fed to `initRstGenerator` ## argument `filenames` (it is being filled here at least with `filename` ## and possibly with other files from RST ``.. include::`` statement). - var sharedState = newRstSharedState(options, filename, findFile, + var sharedState = newRstSharedState(options, filename, findFile, findRefFile, msgHandler, hasToc=false) let unresolved = rstParsePass1(text, line, column, sharedState) preparePass2(sharedState, unresolved) result.node = resolveSubs(sharedState, unresolved) + completePass2(sharedState) result.filenames = sharedState.filenames result.hasToc = sharedState.hasToc diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 597ee1553..57bc00fcb 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -39,7 +39,8 @@ ## No backreferences are generated since finding all references of a footnote ## can be done by simply searching for ``[footnoteName]``. -import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, +import strutils, os, hashes, strtabs, rstast, rst, rstidx, + highlite, tables, sequtils, algorithm, parseutils, std/strbasics @@ -59,7 +60,7 @@ type outLatex # output is Latex MetaEnum* = enum - metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion + metaNone, metaTitleRaw, metaTitle, metaSubtitle, metaAuthor, metaVersion EscapeMode* = enum # in Latex text inside options [] and URLs is # escaped slightly differently than in normal text @@ -321,31 +322,8 @@ proc renderAux(d: PDoc, n: PRstNode, html, tex: string, result: var string) = # ---------------- index handling -------------------------------------------- -proc quoteIndexColumn(text: string): string = - ## Returns a safe version of `text` for serialization to the ``.idx`` file. - ## - ## The returned version can be put without worries in a line based tab - ## separated column text file. The following character sequence replacements - ## will be performed for that goal: - ## - ## * ``"\\"`` => ``"\\\\"`` - ## * ``"\n"`` => ``"\\n"`` - ## * ``"\t"`` => ``"\\t"`` - result = newStringOfCap(text.len + 3) - for c in text: - case c - of '\\': result.add "\\" - of '\L': result.add "\\n" - of '\C': discard - of '\t': result.add "\\t" - else: result.add c - -proc unquoteIndexColumn(text: string): string = - ## Returns the unquoted version generated by ``quoteIndexColumn``. - result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\")) - -proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string, - linkTitle, linkDesc = "") = +proc setIndexTerm*(d: var RstGenerator; k: IndexEntryKind, htmlFile, id, term: string, + linkTitle, linkDesc = "", line = 0) = ## Adds a `term` to the index using the specified hyperlink identifier. ## ## A new entry will be added to the index using the format @@ -368,21 +346,8 @@ proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string, ## <#writeIndexFile,RstGenerator,string>`_. The purpose of the index is ## documented in the `docgen tools guide ## `_. - var - entry = term - isTitle = false - entry.add('\t') - entry.add(htmlFile) - if id.len > 0: - entry.add('#') - entry.add(id) - else: - isTitle = true - if linkTitle.len > 0 or linkDesc.len > 0: - entry.add('\t' & linkTitle.quoteIndexColumn) - entry.add('\t' & linkDesc.quoteIndexColumn) - entry.add("\n") - + let (entry, isTitle) = formatIndexEntry(k, htmlFile, id, term, + linkTitle, linkDesc, line) if isTitle: d.theIndex.insert(entry) else: d.theIndex.add(entry) @@ -395,6 +360,15 @@ proc hash(n: PRstNode): int = result = result !& hash(n.sons[i]) result = !$result +proc htmlFileRelPath(d: PDoc): string = + if d.outDir.len == 0: + # /foo/bar/zoo.nim -> zoo.html + changeFileExt(extractFilename(d.filename), HtmlExt) + else: # d is initialized in docgen.nim + # outDir = /foo -\ + # destFile = /foo/bar/zoo.html -|-> bar/zoo.html + d.destFile.relativePath(d.outDir, '/') + proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = ## Renders the string decorated within \`foobar\`\:idx\: markers. ## @@ -411,17 +385,12 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = var term = "" renderAux(d, n, term) - setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection) + setIndexTerm(d, ieIdxRole, + htmlFileRelPath(d), id, term, d.currentSection) dispA(d.target, result, "$2", "\\nimindexterm{$1}{$2}", [id, term]) type - IndexEntry* = object - keyword*: string - link*: string - linkTitle*: string ## contains a prettier text for the href - linkDesc*: string ## the title attribute of the final href - IndexedDocs* = Table[IndexEntry, seq[IndexEntry]] ## \ ## Contains the index sequences for doc types. ## @@ -432,21 +401,6 @@ type ## The value indexed by this IndexEntry is a sequence with the real index ## entries found in the ``.idx`` file. -proc cmp(a, b: IndexEntry): int = - ## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`. - result = cmpIgnoreStyle(a.keyword, b.keyword) - if result == 0: - result = cmpIgnoreStyle(a.link, b.link) - -proc hash(x: IndexEntry): Hash = - ## Returns the hash for the combined fields of the type. - ## - ## The hash is computed as the chained hash of the individual string hashes. - result = x.keyword.hash !& x.link.hash - result = result !& x.linkTitle.hash - result = result !& x.linkDesc.hash - result = !$result - when defined(gcDestructors): template `<-`(a, b: var IndexEntry) = a = move(b) else: @@ -455,6 +409,7 @@ else: shallowCopy a.link, b.link shallowCopy a.linkTitle, b.linkTitle shallowCopy a.linkDesc, b.linkDesc + shallowCopy a.module, b.module proc sortIndex(a: var openArray[IndexEntry]) = # we use shellsort here; fast and simple @@ -494,16 +449,20 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string = result = "
      " var i = 0 while i < symbols.len: - let keyword = symbols[i].keyword + let keyword = esc(outHtml, symbols[i].keyword) let cleanedKeyword = keyword.escapeLink result.addf("
      $1:
        \n", [keyword, cleanedKeyword]) var j = i - while j < symbols.len and keyword == symbols[j].keyword: + while j < symbols.len and symbols[i].keyword == symbols[j].keyword: let url = symbols[j].link.escapeLink - text = if symbols[j].linkTitle.len > 0: symbols[j].linkTitle else: url - desc = if symbols[j].linkDesc.len > 0: symbols[j].linkDesc else: "" + module = symbols[j].module + text = + if symbols[j].linkTitle.len > 0: + esc(outHtml, module & ": " & symbols[j].linkTitle) + else: url + desc = symbols[j].linkDesc if desc.len > 0: result.addf("""
      • $2
      • @@ -517,13 +476,6 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string = i = j result.add("
      ") -proc isDocumentationTitle(hyperlink: string): bool = - ## Returns true if the hyperlink is actually a documentation title. - ## - ## Documentation titles lack the hash. See `mergeIndexes() - ## <#mergeIndexes,string>`_ for a more detailed explanation. - result = hyperlink.find('#') < 0 - proc stripTocLevel(s: string): tuple[level: int, text: string] = ## Returns the *level* of the toc along with the text without it. for c in 0 ..< s.len: @@ -557,17 +509,15 @@ proc generateDocumentationToc(entries: seq[IndexEntry]): string = level = 1 levels.newSeq(entries.len) for entry in entries: - let (rawLevel, rawText) = stripTocLevel(entry.linkTitle or entry.keyword) + let (rawLevel, rawText) = stripTocLevel(entry.linkTitle) if rawLevel < 1: # This is a normal symbol, push it *inside* one level from the last one. levels[L].level = level + 1 - # Also, ignore the linkTitle and use directly the keyword. - levels[L].text = entry.keyword else: # The level did change, update the level indicator. level = rawLevel levels[L].level = rawLevel - levels[L].text = rawText + levels[L].text = rawText inc L # Now generate hierarchical lists based on the precalculated levels. @@ -598,7 +548,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string = for title in titles: let tocList = generateDocumentationToc(docs.getOrDefault(title)) result.add("\n") + title.link & "\">" & title.linkTitle & "\n" & tocList & "
    \n") proc generateDocumentationJumps(docs: IndexedDocs): string = ## Returns a plain list of hyperlinks to documentation TOCs in HTML. @@ -610,7 +560,7 @@ proc generateDocumentationJumps(docs: IndexedDocs): string = var chunks: seq[string] = @[] for title in titles: - chunks.add("" & title.keyword & "") + chunks.add("" & title.linkTitle & "") result.add(chunks.join(", ") & ".
    ") @@ -639,39 +589,11 @@ proc readIndexDir*(dir: string): # Scan index files and build the list of symbols. for path in walkDirRec(dir): if path.endsWith(IndexExt): - var - fileEntries: seq[IndexEntry] - title: IndexEntry - f = 0 - newSeq(fileEntries, 500) - setLen(fileEntries, 0) - for line in lines(path): - let s = line.find('\t') - if s < 0: continue - setLen(fileEntries, f+1) - fileEntries[f].keyword = line.substr(0, s-1) - fileEntries[f].link = line.substr(s+1) - # See if we detect a title, a link without a `#foobar` trailing part. - if title.keyword.len == 0 and fileEntries[f].link.isDocumentationTitle: - title.keyword = fileEntries[f].keyword - title.link = fileEntries[f].link - - if fileEntries[f].link.find('\t') > 0: - let extraCols = fileEntries[f].link.split('\t') - fileEntries[f].link = extraCols[0] - assert extraCols.len == 3 - fileEntries[f].linkTitle = extraCols[1].unquoteIndexColumn - fileEntries[f].linkDesc = extraCols[2].unquoteIndexColumn - else: - fileEntries[f].linkTitle = "" - fileEntries[f].linkDesc = "" - inc f + var (fileEntries, title) = parseIdxFile(path) # Depending on type add this to the list of symbols or table of APIs. - if title.keyword.len == 0: - for i in 0 ..< f: - # Don't add to symbols TOC entries (they start with a whitespace). - let toc = fileEntries[i].linkTitle - if toc.len > 0 and toc[0] == ' ': + if title.kind == ieNimTitle: + for i in 0 ..< fileEntries.len: + if fileEntries[i].kind != ieNim: continue # Ok, non TOC entry, add it. setLen(result.symbols, L + 1) @@ -687,7 +609,7 @@ proc readIndexDir*(dir: string): result.modules.add(x.changeFileExt("")) else: # Generate the symbolic anchor for index quickjumps. - title.linkTitle = "doc_toc_" & $result.docs.len + title.aux = "doc_toc_" & $result.docs.len result.docs[title] = fileEntries proc mergeIndexes*(dir: string): string = @@ -747,24 +669,6 @@ proc mergeIndexes*(dir: string): string = # ---------------------------------------------------------------------------- -proc stripTocHtml(s: string): string = - ## Ugly quick hack to remove HTML tags from TOC titles. - ## - ## A TocEntry.header field already contains rendered HTML tags. Instead of - ## implementing a proper version of renderRstToOut() which recursively - ## renders an rst tree to plain text, we simply remove text found between - ## angled brackets. Given the limited possibilities of rst inside TOC titles - ## this should be enough. - result = s - var first = result.find('<') - while first >= 0: - let last = result.find('>', first) - if last < 0: - # Abort, since we didn't found a closing angled bracket. - return - result.delete(first..last) - first = result.find('<', first) - proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = var tmp = "" for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp) @@ -785,19 +689,12 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = # Generate index entry using spaces to indicate TOC level for the output HTML. assert n.level >= 0 - let - htmlFileRelPath = if d.outDir.len == 0: - # /foo/bar/zoo.nim -> zoo.html - changeFileExt(extractFilename(d.filename), HtmlExt) - else: # d is initialized in docgen.nim - # outDir = /foo -\ - # destFile = /foo/bar/zoo.html -|-> bar/zoo.html - d.destFile.relativePath(d.outDir, '/') - setIndexTerm(d, htmlFileRelPath, n.anchor, tmp.stripTocHtml, - spaces(max(0, n.level)) & tmp) + setIndexTerm(d, ieHeading, htmlFile = d.htmlFileRelPath, id = n.anchor, + term = n.addNodes, linkTitle = spaces(max(0, n.level)) & tmp) proc renderOverline(d: PDoc, n: PRstNode, result: var string) = if n.level == 0 and d.meta[metaTitle].len == 0: + d.meta[metaTitleRaw] = n.addNodes for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], d.meta[metaTitle]) d.currentSection = d.meta[metaTitle] @@ -813,6 +710,8 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) = dispA(d.target, result, "
    $3
    ", "\\rstov$4[$5]{$3}$2\n", [$n.level, n.anchor.idS, tmp, $chr(n.level - 1 + ord('A')), tocName]) + setIndexTerm(d, ieHeading, htmlFile = d.htmlFileRelPath, id = n.anchor, + term = n.addNodes, linkTitle = spaces(max(0, n.level)) & tmp) proc renderTocEntry(d: PDoc, n: PRstNode, result: var string) = var header = "" @@ -1197,6 +1096,18 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [textStr, linkStr, nimDocStr, tooltipStr]) +proc traverseForIndex*(d: PDoc, n: PRstNode) = + ## A version of [renderRstToOut] that only fills entries for ``.idx`` files. + var discarded: string + if n == nil: return + case n.kind + of rnIdx: renderIndexTerm(d, n, discarded) + of rnHeadline, rnMarkdownHeadline: renderHeadline(d, n, discarded) + of rnOverline: renderOverline(d, n, discarded) + else: + for i in 0 ..< len(n): + traverseForIndex(d, n.sons[i]) + proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = if n == nil: return case n.kind @@ -1451,6 +1362,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnTitle: d.meta[metaTitle] = "" renderRstToOut(d, n.sons[0], d.meta[metaTitle]) + d.meta[metaTitleRaw] = n.sons[0].addNodes # ----------------------------------------------------------------------------- @@ -1616,11 +1528,13 @@ proc rstToHtml*(s: string, options: RstParseOptions, proc myFindFile(filename: string): string = # we don't find any files in online mode: result = "" + proc myFindRefFile(filename: string): (string, string) = + result = ("", "") const filen = "input" let (rst, filenames, t) = rstParse(s, filen, line=LineRstInit, column=ColRstInit, - options, myFindFile, msgHandler) + options, myFindFile, myFindRefFile, msgHandler) var d: RstGenerator initRstGenerator(d, outHtml, config, filen, myFindFile, msgHandler, filenames, hasToc = t) diff --git a/lib/packages/docutils/rstidx.nim b/lib/packages/docutils/rstidx.nim new file mode 100644 index 000000000..c109636d7 --- /dev/null +++ b/lib/packages/docutils/rstidx.nim @@ -0,0 +1,138 @@ +# +# Nim's Runtime Library +# (c) Copyright 2022 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. + +## Nim `idx`:idx: file format related definitions. + +import strutils, std/syncio, hashes +from os import splitFile + +type + IndexEntryKind* = enum ## discriminator tag + ieMarkupTitle = "markupTitle" + ## RST/Markdown title, text in `keyword` + + ## HTML text in `linkTitle` + ieNimTitle = "nimTitle" + ## Nim title + ieHeading = "heading" ## RST/Markdown markup heading, escaped + ieIdxRole = "idx" ## RST :idx: definition, escaped + ieNim = "nim" ## Nim symbol, unescaped + ieNimGroup = "nimgrp" ## Nim overload group, unescaped + IndexEntry* = object + kind*: IndexEntryKind ## 0. + keyword*: string ## 1. + link*: string ## 2. + linkTitle*: string ## 3. contains a prettier text for the href + linkDesc*: string ## 4. the title attribute of the final href + line*: int ## 5. + module*: string ## origin file, NOT a field in ``.idx`` file + aux*: string ## auxuliary field, NOT a field in ``.idx`` file + +proc isDocumentationTitle*(hyperlink: string): bool = + ## Returns true if the hyperlink is actually a documentation title. + ## + ## Documentation titles lack the hash. See `mergeIndexes() + ## <#mergeIndexes,string>`_ for a more detailed explanation. + result = hyperlink.find('#') < 0 + +proc `$`*(e: IndexEntry): string = + """("$1", "$2", "$3", "$4", $5)""" % [ + e.keyword, e.link, e.linkTitle, e.linkDesc, $e.line] + +proc quoteIndexColumn(text: string): string = + ## Returns a safe version of `text` for serialization to the ``.idx`` file. + ## + ## The returned version can be put without worries in a line based tab + ## separated column text file. The following character sequence replacements + ## will be performed for that goal: + ## + ## * ``"\\"`` => ``"\\\\"`` + ## * ``"\n"`` => ``"\\n"`` + ## * ``"\t"`` => ``"\\t"`` + result = newStringOfCap(text.len + 3) + for c in text: + case c + of '\\': result.add "\\" + of '\L': result.add "\\n" + of '\C': discard + of '\t': result.add "\\t" + else: result.add c + +proc unquoteIndexColumn*(text: string): string = + ## Returns the unquoted version generated by ``quoteIndexColumn``. + result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\")) + +proc formatIndexEntry*(kind: IndexEntryKind; htmlFile, id, term, linkTitle, + linkDesc: string, line: int): + tuple[entry: string, isTitle: bool] = + result.entry = $kind + result.entry.add('\t') + result.entry.add term + result.entry.add('\t') + result.entry.add(htmlFile) + if id.len > 0: + result.entry.add('#') + result.entry.add(id) + result.isTitle = false + else: + result.isTitle = true + result.entry.add('\t' & linkTitle.quoteIndexColumn) + result.entry.add('\t' & linkDesc.quoteIndexColumn) + result.entry.add('\t' & $line) + result.entry.add("\n") + +proc parseIndexEntryKind(s: string): IndexEntryKind = + result = case s: + of "nim": ieNim + of "nimgrp": ieNimGroup + of "heading": ieHeading + of "idx": ieIdxRole + of "nimTitle": ieNimTitle + of "markupTitle": ieMarkupTitle + else: raise newException(ValueError, "unknown index entry value $1" % [s]) + +proc parseIdxFile*(path: string): + tuple[fileEntries: seq[IndexEntry], title: IndexEntry] = + var + f = 0 + newSeq(result.fileEntries, 500) + setLen(result.fileEntries, 0) + let (_, base, _) = path.splitFile + for line in lines(path): + let s = line.find('\t') + if s < 0: continue + setLen(result.fileEntries, f+1) + let cols = line.split('\t') + result.fileEntries[f].kind = parseIndexEntryKind(cols[0]) + result.fileEntries[f].keyword = cols[1] + result.fileEntries[f].link = cols[2] + if result.title.keyword.len == 0: + result.fileEntries[f].module = base + else: + result.fileEntries[f].module = result.title.keyword + + result.fileEntries[f].linkTitle = cols[3].unquoteIndexColumn + result.fileEntries[f].linkDesc = cols[4].unquoteIndexColumn + result.fileEntries[f].line = parseInt(cols[5]) + + if result.fileEntries[f].kind in {ieNimTitle, ieMarkupTitle}: + result.title = result.fileEntries[f] + inc f + +proc cmp*(a, b: IndexEntry): int = + ## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`. + result = cmpIgnoreStyle(a.keyword, b.keyword) + if result == 0: + result = cmpIgnoreStyle(a.link, b.link) + +proc hash*(x: IndexEntry): Hash = + ## Returns the hash for the combined fields of the type. + ## + ## The hash is computed as the chained hash of the individual string hashes. + result = x.keyword.hash !& x.link.hash + result = result !& x.linkTitle.hash + result = result !& x.linkDesc.hash + result = !$result diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 5f8f116d3..ecceed671 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -11,6 +11,8 @@ ## retrieving environment variables, working with directories, ## running shell commands, etc. +## .. importdoc:: symlinks.nim, appdirs.nim, dirs.nim, ospaths2.nim + runnableExamples: let myFile = "/path/to/my/file.nim" assert splitPath(myFile) == (head: "/path/to/my", tail: "file.nim") diff --git a/lib/std/appdirs.nim b/lib/std/appdirs.nim index e648fe0c1..c945ba8ec 100644 --- a/lib/std/appdirs.nim +++ b/lib/std/appdirs.nim @@ -1,5 +1,7 @@ ## This module implements helpers for determining special directories used by apps. +## .. importdoc:: paths.nim + from std/private/osappdirs import nil import std/paths import std/envvars diff --git a/lib/std/private/osappdirs.nim b/lib/std/private/osappdirs.nim index 8e6ae00f8..581b511ff 100644 --- a/lib/std/private/osappdirs.nim +++ b/lib/std/private/osappdirs.nim @@ -1,3 +1,5 @@ +## .. importdoc:: paths.nim, dirs.nim + include system/inclrtl import std/envvars import std/private/ospaths2 diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim index 5b4e1d7e3..3aac58636 100644 --- a/lib/std/private/oscommon.nim +++ b/lib/std/private/oscommon.nim @@ -5,6 +5,8 @@ import std/[oserrors] when defined(nimPreviewSlimSystem): import std/[syncio, assertions, widestrs] +## .. importdoc:: osdirs.nim, os.nim + const weirdTarget* = defined(nimscript) or defined(js) diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index add9ed424..4af418ead 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -1,3 +1,5 @@ +## .. importdoc:: osfiles.nim, appdirs.nim, paths.nim + include system/inclrtl import std/oserrors diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index 301f14600..a7a595d97 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -7,6 +7,7 @@ export fileExists import ospaths2, ossymlinks +## .. importdoc:: osdirs.nim, os.nim when defined(nimPreviewSlimSystem): import std/[syncio, assertions, widestrs] @@ -420,4 +421,4 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", removeFile(source) except: discard tryRemoveFile(dest) - raise \ No newline at end of file + raise diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 75c34ecf5..5e3bece68 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -10,6 +10,8 @@ export ReadDirEffect, WriteDirEffect when defined(nimPreviewSlimSystem): import std/[syncio, assertions, widestrs] +## .. importdoc:: osappdirs.nim, osdirs.nim, osseps.nim, os.nim + const weirdTarget = defined(nimscript) or defined(js) when weirdTarget: diff --git a/lib/std/private/osseps.nim b/lib/std/private/osseps.nim index 1ea587e3c..f2d49d886 100644 --- a/lib/std/private/osseps.nim +++ b/lib/std/private/osseps.nim @@ -3,6 +3,8 @@ # Improved based on info in 'compiler/platform.nim' +## .. importdoc:: ospaths2.nim + const doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS) diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim index cb6287bde..53f59f939 100644 --- a/lib/std/private/ossymlinks.nim +++ b/lib/std/private/ossymlinks.nim @@ -31,6 +31,7 @@ elif defined(js): else: {.pragma: noNimJs.} +## .. importdoc:: os.nim proc createSymlink*(src, dest: string) {.noWeirdTarget.} = ## Create a symbolic link at `dest` which points to the item specified diff --git a/lib/std/symlinks.nim b/lib/std/symlinks.nim index 9e77bbe2a..54ab7b677 100644 --- a/lib/std/symlinks.nim +++ b/lib/std/symlinks.nim @@ -1,10 +1,11 @@ ## This module implements symlink (symbolic link) handling. +## .. importdoc:: os.nim + from paths import Path, ReadDirEffect from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink - proc symlinkExists*(link: Path): bool {.inline, tags: [ReadDirEffect].} = ## Returns true if the symlink `link` exists. Will return true ## regardless of whether the link points to a directory or file. diff --git a/nimdoc/extlinks/project/doc/manual.md b/nimdoc/extlinks/project/doc/manual.md new file mode 100644 index 000000000..d44b5ca39 --- /dev/null +++ b/nimdoc/extlinks/project/doc/manual.md @@ -0,0 +1,17 @@ +=================== +Nothing User Manual +=================== + +.. importdoc:: ../main.nim, .. / sub / submodule.nim, ../../util.nim + +First section +============= + +Second *section* & +================== + +Ref. [``] or [submoduleInt] from [module nimdoc/extlinks/project/sub/submodule]. + +Ref. [proc mainfunction*(): int]. + +Ref. [utilfunction(x: int)]. diff --git a/nimdoc/extlinks/project/expected/_._/util.html b/nimdoc/extlinks/project/expected/_._/util.html new file mode 100644 index 000000000..9b9b29a4f --- /dev/null +++ b/nimdoc/extlinks/project/expected/_._/util.html @@ -0,0 +1,104 @@ + + + + + + + +nimdoc/extlinks/util + + + + + + + + + + + + +
    +
    +

    nimdoc/extlinks/util

    +
    +
    +
    + + +
    + +
    + Search: +
    +
    + Group by: + +
    + + +
    +
    + +
    + +

    +
    +

    Procs

    +
    +
    +
    +
    proc utilfunction(x: int): int {....raises: [], tags: [], forbids: [].}
    +
    + + + +
    +
    + +
    + +
    +
    + +
    +
    + + +
    +
    + + + + + + diff --git a/nimdoc/extlinks/project/expected/_._/util.idx b/nimdoc/extlinks/project/expected/_._/util.idx new file mode 100644 index 000000000..d83d8c97d --- /dev/null +++ b/nimdoc/extlinks/project/expected/_._/util.idx @@ -0,0 +1,2 @@ +nimTitle util _._/util.html module nimdoc/extlinks/util 0 +nim utilfunction _._/util.html#utilfunction,int proc utilfunction(x: int): int 1 diff --git a/nimdoc/extlinks/project/expected/doc/manual.html b/nimdoc/extlinks/project/expected/doc/manual.html new file mode 100644 index 000000000..7b964f4ac --- /dev/null +++ b/nimdoc/extlinks/project/expected/doc/manual.html @@ -0,0 +1,44 @@ + + + + + + + +Nothing User Manual + + + + + + + + + + + + +
    +
    +

    Nothing User Manual

    + +

    First section

    +

    Second section &

    Ref. submodule: `</a>` or submodule: submoduleInt from module nimdoc/extlinks/project/sub/submodule.

    +

    Ref. main: proc mainfunction*(): int.

    +

    Ref. util: utilfunction(x: int).

    + + + + +
    +
    + + + + + + diff --git a/nimdoc/extlinks/project/expected/doc/manual.idx b/nimdoc/extlinks/project/expected/doc/manual.idx new file mode 100644 index 000000000..158a758f0 --- /dev/null +++ b/nimdoc/extlinks/project/expected/doc/manual.idx @@ -0,0 +1,3 @@ +markupTitle Nothing User Manual doc/manual.html Nothing User Manual 0 +heading First section doc/manual.html#first-section First section 0 +heading Second section & doc/manual.html#second-section-amp Second section & 0 diff --git a/nimdoc/extlinks/project/expected/main.html b/nimdoc/extlinks/project/expected/main.html new file mode 100644 index 000000000..5facedb3b --- /dev/null +++ b/nimdoc/extlinks/project/expected/main.html @@ -0,0 +1,144 @@ + + + + + + + +nimdoc/extlinks/project/main + + + + + + + + + + + + +
    +
    +

    nimdoc/extlinks/project/main

    +
    +
    +
    + + +
    + +
    + Search: +
    +
    + Group by: + +
    + + +
    +
    + +
    + +

    +

    my heading

    See also module nimdoc/extlinks/util or nimdoc/extlinks/project/sub/submodule module.

    +

    Ref. submodule: `</a>` proc.

    +

    Ref. Nothing User Manual: First section or Nothing User Manual: Second section & from Nothing User Manual.

    +

    + +
    +

    Types

    +
    +
    +
    A = object
    +  x: int
    +
    +
    + + + +
    +
    + +
    +
    +
    +

    Procs

    +
    +
    +
    +
    proc mainfunction(): int {....raises: [], tags: [], forbids: [].}
    +
    + + + +
    +
    + +
    + +
    +
    + +
    +
    + + +
    +
    + + + + + + diff --git a/nimdoc/extlinks/project/expected/main.idx b/nimdoc/extlinks/project/expected/main.idx new file mode 100644 index 000000000..d01f2e4c5 --- /dev/null +++ b/nimdoc/extlinks/project/expected/main.idx @@ -0,0 +1,4 @@ +nimTitle main main.html module nimdoc/extlinks/project/main 0 +nim A main.html#A object A 17 +nim mainfunction main.html#mainfunction proc mainfunction(): int 20 +heading my heading main.html#my-heading my heading 0 diff --git a/nimdoc/extlinks/project/expected/sub/submodule.html b/nimdoc/extlinks/project/expected/sub/submodule.html new file mode 100644 index 000000000..913138d6e --- /dev/null +++ b/nimdoc/extlinks/project/expected/sub/submodule.html @@ -0,0 +1,130 @@ + + + + + + + +nimdoc/extlinks/project/sub/submodule + + + + + + + + + + + + +
    +
    +

    nimdoc/extlinks/project/sub/submodule

    +
    +
    +
    + + +
    + +
    + Search: +
    +
    + Group by: + +
    + + +
    +
    + +
    + +

    Ref. main: object A from module nimdoc/extlinks/project/main.

    +

    Ref. util: utilfunction(x: int).

    +

    Ref. Nothing User Manual: Second section & from Nothing User Manual.

    +

    +
    +

    Types

    +
    +
    +
    submoduleInt = distinct int
    +
    + + + +
    +
    + +
    +
    +
    +

    Procs

    +
    +
    +
    +
    proc `</a>`(x, y: int): bool {....raises: [], tags: [], forbids: [].}
    +
    + + Attempt to break HTML formatting. + +
    +
    + +
    + +
    +
    + +
    +
    + + +
    +
    + + + + + + diff --git a/nimdoc/extlinks/project/expected/sub/submodule.idx b/nimdoc/extlinks/project/expected/sub/submodule.idx new file mode 100644 index 000000000..2b02c889e --- /dev/null +++ b/nimdoc/extlinks/project/expected/sub/submodule.idx @@ -0,0 +1,3 @@ +nimTitle submodule sub/submodule.html module nimdoc/extlinks/project/sub/submodule 0 +nim `` sub/submodule.html#,int,int proc ``(x, y: int): bool 9 +nim submoduleInt sub/submodule.html#submoduleInt type submoduleInt 13 diff --git a/nimdoc/extlinks/project/expected/theindex.html b/nimdoc/extlinks/project/expected/theindex.html new file mode 100644 index 000000000..9d2f6723c --- /dev/null +++ b/nimdoc/extlinks/project/expected/theindex.html @@ -0,0 +1,58 @@ + + + + + + + +Index + + + + + + + + + + + + + + + + + + + diff --git a/nimdoc/extlinks/project/main.nim b/nimdoc/extlinks/project/main.nim new file mode 100644 index 000000000..36b778af6 --- /dev/null +++ b/nimdoc/extlinks/project/main.nim @@ -0,0 +1,23 @@ +## my heading +## ========== +## +## .. importdoc:: sub/submodule.nim, ../util.nim, doc/manual.md +## +## .. See also [Second&&&] and particularly [first section] and [Second section &]. +## +## See also [module nimdoc/extlinks/util] or [nimdoc/extlinks/project/sub/submodule module]. +## +## Ref. [`` proc]. +## +## Ref. [First section] or [Second section &] from [Nothing User Manual]. + + +import ../util, sub/submodule + +type A* = object + x: int + +proc mainfunction*(): int = + # just to suppress "not used" warnings: + if ``(1, 2): + result = utilfunction(0) diff --git a/nimdoc/extlinks/project/sub/submodule.nim b/nimdoc/extlinks/project/sub/submodule.nim new file mode 100644 index 000000000..876e00684 --- /dev/null +++ b/nimdoc/extlinks/project/sub/submodule.nim @@ -0,0 +1,13 @@ +## .. importdoc:: ../../util.nim, ../main.nim, ../doc/manual.md +## +## Ref. [object A] from [module nimdoc/extlinks/project/main]. +## +## Ref. [utilfunction(x: int)]. +## +## Ref. [Second section &] from [Nothing User Manual]. + +proc ``*(x, y: int): bool = + ## Attempt to break HTML formatting. + result = x < y + +type submoduleInt* = distinct int diff --git a/nimdoc/extlinks/util.nim b/nimdoc/extlinks/util.nim new file mode 100644 index 000000000..f208f98c1 --- /dev/null +++ b/nimdoc/extlinks/util.nim @@ -0,0 +1,2 @@ +proc utilfunction*(x: int): int = + x + 42 diff --git a/nimdoc/test_out_index_dot_html/expected/foo.idx b/nimdoc/test_out_index_dot_html/expected/foo.idx index a8dabb67e..ac76aa532 100644 --- a/nimdoc/test_out_index_dot_html/expected/foo.idx +++ b/nimdoc/test_out_index_dot_html/expected/foo.idx @@ -1 +1,2 @@ -foo index.html#foo foo: foo() +nimTitle foo index.html module nimdoc/test_out_index_dot_html/foo 0 +nim foo index.html#foo proc foo() 1 diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index 2a0ea7900..ea3486d4b 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -24,7 +24,7 @@ Modules: index.

    API symbols

    foo:
    • foo: foo()
    • + data-doc-search-tag="foo: proc foo()" href="index.html#foo">foo: proc foo()
    @@ -97,8 +96,7 @@
    A = object
    -  x: int
    -
    +
    diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index f0f30536f..ee2618ab3 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -59,8 +59,7 @@
    Types
      -
    • G
    • +
    • G
    • SomeType
    • @@ -254,8 +253,7 @@ Ref.
      G[T] = object
      -  val: T
      -
      +
      diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 7d10d7900..45a53bb93 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -65,6 +65,8 @@ Circle, ## A circle Triangle, ## A three-sided shape Rectangle ## A four-sided shape">Shapes +
    • T19396
    @@ -399,6 +401,16 @@ Some shapes. +
    +
    +
    +
    T19396 = object
    +  a*: int
    +
    +
    + + +
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index e69bedf33..46ffaee72 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -63,5 +63,6 @@ nim Triangle testproject.html#Triangle Shapes.Triangle 380 nim Rectangle testproject.html#Rectangle Shapes.Rectangle 380 nim Shapes testproject.html#Shapes enum Shapes 380 nim anything testproject.html#anything proc anything() 387 +nim T19396 testproject.html#T19396 object T19396 392 nimgrp bar testproject.html#bar-procs-all proc 31 nimgrp baz testproject.html#baz-procs-all proc 34 diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 7b4a95561..f9488eb2d 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -308,6 +308,10 @@
  • testproject: var someVariable
  • +
    T19396:
    testNimDocTrailingExample:
    • testproject: template testNimDocTrailingExample()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index d236552ac..b5fa2ac37 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -388,3 +388,7 @@ when true: # issue #15184 ## ## There is no block quote after blank lines at the beginning. discard + +type T19396* = object # bug #19396 + a*: int + b: float From 900fe8f501838077a5a1ef3d6793a1e901083bf8 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Wed, 1 Feb 2023 20:00:10 +1100 Subject: [PATCH 4169/4254] Add `contains` to `std/macrocache` (#21304) * Add test cases * Implement contains for CacheSeq * Implement contains for CacheTable * Fix implementation of hasKey * Remove contains for CacheSeq Fix runnable examples I was accidently using --doccmd:skip so I didn't spot the failure locally * Implement hasKey as a VM callback instead of magic * Implement suggestions from PR Co-Authored-By: ringabout * Update lib/core/macrocache.nim --------- Co-authored-by: ringabout Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- compiler/vmops.nim | 6 ++++++ lib/core/macrocache.nim | 26 ++++++++++++++++++++++++++ tests/macros/tmacros_various.nim | 7 +++++++ 3 files changed, 39 insertions(+) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index f1a2e1e69..f51280ec5 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -284,6 +284,12 @@ proc registerAdditionalOps*(c: PCtx) = stackTrace2(c, "isExported() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n) setResult(a, sfExported in n.sym.flags) + registerCallback c, "stdlib.macrocache.hasKey", proc (a: VmArgs) = + let + table = getString(a, 0) + key = getString(a, 1) + setResult(a, table in c.graph.cacheTables and key in c.graph.cacheTables[table]) + registerCallback c, "stdlib.vmutils.vmTrace", proc (a: VmArgs) = c.config.isVmTrace = getBool(a, 0) diff --git a/lib/core/macrocache.nim b/lib/core/macrocache.nim index d4b103793..ffd07abb1 100644 --- a/lib/core/macrocache.nim +++ b/lib/core/macrocache.nim @@ -181,6 +181,32 @@ proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} = # get the NimNode back assert mcTable["toAdd"].kind == nnkStmtList +proc hasKey*(t: CacheTable; key: string): bool = + ## Returns true if `key` is in the table `t`. + ## + ## See also: + ## * [contains proc][contains(CacheTable, string)] for use with the `in` operator + runnableExamples: + import std/macros + const mcTable = CacheTable"hasKeyEx" + static: + assert not mcTable.hasKey("foo") + mcTable["foo"] = newEmptyNode() + # Will now be true since we inserted a value + assert mcTable.hasKey("foo") + discard "Implemented in vmops" + +proc contains*(t: CacheTable; key: string): bool {.inline.} = + ## Alias of [hasKey][hasKey(CacheTable, string)] for use with the `in` operator. + runnableExamples: + import std/macros + const mcTable = CacheTable"containsEx" + static: + mcTable["foo"] = newEmptyNode() + # Will be true since we gave it a value before + assert "foo" in mcTable + t.hasKey(key) + proc hasNext(t: CacheTable; iter: int): bool {.magic: "NctHasNext".} proc next(t: CacheTable; iter: int): (string, NimNode, int) {.magic: "NctNext".} diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 08be4602c..2446912ea 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -351,3 +351,10 @@ block: # bug #15118 block: flop("b") + +static: + block: + const containsTable = CacheTable"containsTable" + doAssert "foo" notin containsTable + containsTable["foo"] = newLit 42 + doAssert "foo" in containsTable From 43b1b9d077c6a96580f202101e643fdcd34e30fb Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Wed, 1 Feb 2023 11:38:22 +0200 Subject: [PATCH 4170/4254] Fix the nimble build on Windows (#21314) Fix the build on Windows - `nimble install` fails on Windows, the `./` is not needed. --- nim.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nim.nimble b/nim.nimble index 5d1be49b1..713fc9256 100644 --- a/nim.nimble +++ b/nim.nimble @@ -9,6 +9,6 @@ skipDirs = @["build" , "changelogs" , "ci" , "csources_v2" , "drnim" , "nimdoc", before install: when defined(windows): - exec "./build_all.bat" + exec "build_all.bat" else: exec "./build_all.sh" From 17115cbc7375cdd47affd06dded62591d887441e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 2 Feb 2023 23:44:14 +0800 Subject: [PATCH 4171/4254] fixes SSL version check logic [backport] (#21324) * fixed version check logic [backport] * add ciphersuites * debug nimble * fixes returns omission * finally * remove debug message * add ciphersuites --------- Co-authored-by: Araq --- lib/pure/asynchttpserver.nim | 4 ++-- lib/pure/net.nim | 6 +++--- lib/pure/unicode.nim | 2 +- lib/wrappers/openssl.nim | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 6694c4bc2..845875a1e 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -158,7 +158,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = proc sendStatus(client: AsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L\c\L") -func hasChunkedEncoding(request: Request): bool = +func hasChunkedEncoding(request: Request): bool = ## Searches for a chunked transfer encoding const transferEncoding = "Transfer-Encoding" @@ -300,7 +300,7 @@ proc processRequest( while true: lineFut.mget.setLen(0) lineFut.clean() - + # The encoding format alternates between specifying a number of bytes to read # and the data to be read, of the previously specified size if sizeOrData mod 2 == 0: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 76a39226f..1dfef3b30 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -621,7 +621,7 @@ when defineSsl: proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, certFile = "", keyFile = "", cipherList = CiphersIntermediate, - caDir = "", caFile = ""): SslContext = + caDir = "", caFile = "", ciphersuites = CiphersModern): SslContext = ## Creates an SSL context. ## ## Protocol version is currently ignored by default and TLS is used. @@ -675,10 +675,10 @@ when defineSsl: raiseSSLError() when not defined(openssl10) and not defined(libressl): let sslVersion = getOpenSSLVersion() - if sslVersion >= 0x010101000 and not sslVersion == 0x020000000: + if sslVersion >= 0x010101000 and sslVersion != 0x020000000: # In OpenSSL >= 1.1.1, TLSv1.3 cipher suites can only be configured via # this API. - if newCTX.SSL_CTX_set_ciphersuites(cipherList) != 1: + if newCTX.SSL_CTX_set_ciphersuites(ciphersuites) != 1: raiseSSLError() # Automatically the best ECDH curve for client exchange. Without this, ECDH # ciphers will be ignored by the server. diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 09233035f..c8d18831a 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -887,7 +887,7 @@ proc reversed*(s: openArray[char]): string = proc graphemeLen*(s: openArray[char]; i: Natural): Natural = ## The number of bytes belonging to byte index ``s[i]``, - ## including following combining code unit. + ## including following combining code units. runnableExamples: let a = "añyóng" doAssert a.graphemeLen(1) == 2 ## ñ diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index b3fe8a608..fcf52a8d9 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -467,10 +467,10 @@ else: raiseInvalidLibrary MainProc proc SSL_CTX_set_ciphersuites*(ctx: SslCtx, str: cstring): cint = - var theProc {.global.}: proc(ctx: SslCtx, str: cstring) {.cdecl, gcsafe.} + var theProc {.global.}: proc(ctx: SslCtx, str: cstring): cint {.cdecl, gcsafe.} if theProc.isNil: theProc = cast[typeof(theProc)](sslSymThrows("SSL_CTX_set_ciphersuites")) - theProc(ctx, str) + result = theProc(ctx, str) proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} From 8e53fba083a7450b8c2e9771cba8d477468a520e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 3 Feb 2023 02:11:20 +0800 Subject: [PATCH 4172/4254] replaces `pairs` with `keys` and `items`; saves 8 bytes (#21319) replace `pairs` with `keys` and `items` --- compiler/condsyms.nim | 2 +- compiler/semfold.nim | 6 +++--- compiler/seminst.nim | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index c05aaf10b..a499b7142 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -25,7 +25,7 @@ proc undefSymbol*(symbols: StringTableRef; symbol: string) = # result = if isDefined(symbol): gSymbols[symbol] else: nil iterator definedSymbolNames*(symbols: StringTableRef): string = - for key, val in pairs(symbols): + for key in keys(symbols): yield key proc countDefinedSymbols*(symbols: StringTableRef): int = diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 7f966c6fd..07c3b3ae4 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -685,7 +685,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode n[0] = a of nkBracket, nkCurly: result = copyNode(n) - for i, son in n.pairs: + for son in n.items: var a = getConstExpr(m, son, idgen, g) if a == nil: return nil result.add a @@ -709,7 +709,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode # tuple constructor result = copyNode(n) if (n.len > 0) and (n[0].kind == nkExprColonExpr): - for i, expr in n.pairs: + for expr in n.items: let exprNew = copyNode(expr) # nkExprColonExpr exprNew.add expr[0] let a = getConstExpr(m, expr[1], idgen, g) @@ -717,7 +717,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode exprNew.add a result.add exprNew else: - for i, expr in n.pairs: + for expr in n.items: let a = getConstExpr(m, expr, idgen, g) if a == nil: return nil result.add a diff --git a/compiler/seminst.nim b/compiler/seminst.nim index bd5eb1ec3..80d455d1e 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -40,7 +40,7 @@ const iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym = internalAssert c.config, n.kind == nkGenericParams - for i, a in n.pairs: + for a in n.items: internalAssert c.config, a.kind == nkSym var q = a.sym if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses: From 9f651f05d56407f63b9334917fecad975bdd49b4 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Tue, 7 Feb 2023 17:15:44 +0900 Subject: [PATCH 4173/4254] nimgrep: fix typo (#21337) occurences -> occurrences --- doc/nimgrep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nimgrep.md b/doc/nimgrep.md index 8fb86a9d3..63f760051 100644 --- a/doc/nimgrep.md +++ b/doc/nimgrep.md @@ -77,7 +77,7 @@ That means you can always use only 1 such an option with logical OR, e.g. .. Note:: If you want logical AND on patterns you should compose 1 appropriate pattern, possibly combined with multi-line mode `(?s)`:literal:. - E.g. to require that multi-line context of matches has occurences of + E.g. to require that multi-line context of matches has occurrences of **both** PAT1 and PAT2 use positive lookaheads (`(?=PAT)`:literal:): ```cmd nimgrep --inContext:'(?s)(?=.*PAT1)(?=.*PAT2)' From cbb6001d1e2e484986387e815a61339cd3dc916f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:27:44 +0800 Subject: [PATCH 4174/4254] fixes backticks in the documentation (#21340) --- lib/pure/collections/tables.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index cd08dcb9a..57a0107fd 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -2393,7 +2393,7 @@ proc contains*[A](t: CountTable[A], key: A): bool = return hasKey[A](t, key) proc getOrDefault*[A](t: CountTable[A], key: A; default: int = 0): int = - ## Retrieves the value at `t[key]` if`key` is in `t`. Otherwise, the + ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the ## integer value of `default` is returned. ## ## See also: @@ -2713,7 +2713,7 @@ proc contains*[A](t: CountTableRef[A], key: A): bool = return hasKey[A](t, key) proc getOrDefault*[A](t: CountTableRef[A], key: A, default: int): int = - ## Retrieves the value at `t[key]` if`key` is in `t`. Otherwise, the + ## Retrieves the value at `t[key]` if `key` is in `t`. Otherwise, the ## integer value of `default` is returned. ## ## See also: From 9fb4c2b3c765f993ba0055b281de19786a484c61 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 8 Feb 2023 20:55:01 +0100 Subject: [PATCH 4175/4254] fixes #21333; bad codegen for the at operator; [backport:1.6] (#21344) --- compiler/ccgexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 844a37997..fe7cb252e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1647,6 +1647,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = return if d.k == locNone: getTemp(p, n.typ, d) + initLocExpr(p, n[1], a) # generate call to newSeq before adding the elements per hand: let L = toInt(lengthOrd(p.config, n[1].typ)) if optSeqDestructors in p.config.globalOptions: @@ -1658,7 +1659,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = var lit = newRopeAppender() intLiteral(L, lit) genNewSeqAux(p, d, lit, L == 0) - initLocExpr(p, n[1], a) # bug #5007; do not produce excessive C source code: if L < 10: for i in 0.. Date: Thu, 9 Feb 2023 20:00:56 +0800 Subject: [PATCH 4176/4254] add `nimib` to important packages (#20697) r Co-authored-by: Clay Sweetser --- testament/important_packages.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 90d12df4e..b3a4bfb82 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -105,6 +105,7 @@ pkg "nimfp", "nim c -o:nfp -r src/fp.nim" pkg "nimgame2", "nim c --mm:refc nimgame2/nimgame.nim" # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" +pkg "nimib" pkg "nimlsp" pkg "nimly", "nim c -r tests/test_readme_example.nim" pkg "nimongo", "nimble test_ci", allowFailure = true From 51f410e1d5c19e42e97057f0b88e87056b7c43e2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 10 Feb 2023 05:14:39 +0800 Subject: [PATCH 4177/4254] megatest now checks refc too (#21341) * megatest now checks refc too * fixes refc --- testament/categories.nim | 2 ++ tests/enum/tenum.nim | 3 ++- tests/misc/t18079.nim | 4 ++++ tests/misc/tunsignedconv.nim | 3 ++- tests/typerel/ttypedesc_as_genericparam1_orc.nim | 6 +++++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index e8b13746a..cae699327 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -718,6 +718,8 @@ proc processCategory(r: var TResults, cat: Category, case cat2 of "megatest": runJoinedTest(r, cat, testsDir, options) + if isNimRepoTests(): + runJoinedTest(r, cat, testsDir, options & " --mm:refc") else: var testsRun = 0 var files: seq[string] diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index b11b02ec6..88d85ddcc 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -174,4 +174,5 @@ block: # bug #12589 proc typ(): OGRwkbGeometryType = return wkbPoint25D - doAssert $typ() == "wkbPoint25D" + when not defined(gcRefc): + doAssert $typ() == "wkbPoint25D" diff --git a/tests/misc/t18079.nim b/tests/misc/t18079.nim index 352348daf..ae64bbff9 100644 --- a/tests/misc/t18079.nim +++ b/tests/misc/t18079.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:orc" +""" + type Foo = object y: int diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim index 989f39277..c32f85b4d 100644 --- a/tests/misc/tunsignedconv.nim +++ b/tests/misc/tunsignedconv.nim @@ -66,7 +66,8 @@ let limit = 1'u64 let rangeVar = 0'u64 ..< limit -doAssert repr(rangeVar) == """0 .. 0""", repr(rangeVar) +when not defined(gcRefc): + doAssert repr(rangeVar) == """0 .. 0""", repr(rangeVar) # bug #15210 diff --git a/tests/typerel/ttypedesc_as_genericparam1_orc.nim b/tests/typerel/ttypedesc_as_genericparam1_orc.nim index 0ee4d8f92..d528a7421 100644 --- a/tests/typerel/ttypedesc_as_genericparam1_orc.nim +++ b/tests/typerel/ttypedesc_as_genericparam1_orc.nim @@ -1 +1,5 @@ -doAssert repr(int) == "int" \ No newline at end of file +discard """ + matrix: "--mm:orc" +""" + +doAssert repr(int) == "int" From 642136ec4f2cd93cdd753bf16fa4aec89b8fee82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Thu, 9 Feb 2023 21:19:05 +0000 Subject: [PATCH 4178/4254] Adds an extra optional argument to vcc: `vctoolset` Fixes #21335 (#21336) --- tools/vccexe/vccexe.nim | 15 +++++++++++---- tools/vccexe/vcvarsall.nim | 7 ++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/vccexe/vccexe.nim b/tools/vccexe/vccexe.nim index abe68c0a0..d548666b9 100644 --- a/tools/vccexe/vccexe.nim +++ b/tools/vccexe/vccexe.nim @@ -41,6 +41,7 @@ const platformPrefix = "--platform" sdktypePrefix = "--sdktype" sdkversionPrefix = "--sdkversion" + vctoolsetPrefix = "--vctoolset" verbosePrefix = "--verbose" vccversionSepIdx = vccversionPrefix.len @@ -49,6 +50,7 @@ const platformSepIdx = platformPrefix.len sdktypeSepIdx = sdktypePrefix.len sdkversionSepIdx = sdkversionPrefix.len + vctoolsetSepIdx = vctoolsetPrefix.len vcvarsallDefaultPath = "vcvarsall.bat" @@ -97,6 +99,8 @@ Options: "8.1" to use the windows 8.1 SDK --verbose Echoes the command line for loading the Developer Command Prompt and the command line passed on to the secondary command. + --vctoolset Optionally specifies the Visual Studio compiler toolset to use. + By default, the environment is set to use the current Visual Studio compiler toolset. Other command line arguments are passed on to the secondary command specified by --command or to the @@ -108,7 +112,7 @@ proc parseVccexeCmdLine(argseq: seq[string], vccversionArg: var seq[string], printPathArg: var bool, vcvarsallArg: var string, commandArg: var string, noCommandArg: var bool, platformArg: var VccArch, sdkTypeArg: var VccPlatformType, - sdkVersionArg: var string, verboseArg: var bool, + sdkVersionArg: var string, vctoolsetArg: var string, verboseArg: var bool, clArgs: var seq[string]) = ## Cannot use usual command-line argument parser here ## Since vccexe command-line arguments are intermingled @@ -125,7 +129,7 @@ proc parseVccexeCmdLine(argseq: seq[string], responseargs = parseCmdLine(responsecontent) parseVccexeCmdLine(responseargs, vccversionArg, printPathArg, vcvarsallArg, commandArg, noCommandArg, platformArg, sdkTypeArg, - sdkVersionArg, verboseArg, clArgs) + sdkVersionArg, vctoolsetArg, verboseArg, clArgs) elif wargv.startsWith(vccversionPrefix): # Check for vccversion vccversionArg.add(wargv.substr(vccversionSepIdx + 1)) elif wargv.cmpIgnoreCase(printPathPrefix) == 0: # Check for printPath @@ -142,6 +146,8 @@ proc parseVccexeCmdLine(argseq: seq[string], sdkTypeArg = parseEnum[VccPlatformType](wargv.substr(sdktypeSepIdx + 1)) elif wargv.startsWith(sdkversionPrefix): # Check for sdkversion sdkVersionArg = wargv.substr(sdkversionSepIdx + 1) + elif wargv.startsWith(vctoolsetPrefix): # Check for vctoolset + vctoolsetArg = wargv.substr(vctoolsetSepIdx + 1) elif wargv.startsWith(verbosePrefix): verboseArg = true else: # Regular cl.exe argument -> store for final cl.exe invocation @@ -158,13 +164,14 @@ when isMainModule: var platformArg: VccArch var sdkTypeArg: VccPlatformType var sdkVersionArg: string + var vctoolsetArg: string var verboseArg: bool = false var clArgs: seq[string] = @[] let wrapperArgs = commandLineParams() parseVccexeCmdLine(wrapperArgs, vccversionArg, printPathArg, vcvarsallArg, - commandArg, noCommandArg, platformArg, sdkTypeArg, sdkVersionArg, + commandArg, noCommandArg, platformArg, sdkTypeArg, sdkVersionArg, vctoolsetArg, verboseArg, clArgs) @@ -195,7 +202,7 @@ when isMainModule: echo "$1: $2" % [head, vcvarsallArg] # Call vcvarsall to get the appropriate VCC process environment - var vcvars = vccVarsAll(vcvarsallArg, platformArg, sdkTypeArg, sdkVersionArg, verboseArg) + var vcvars = vccVarsAll(vcvarsallArg, platformArg, sdkTypeArg, sdkVersionArg, vctoolsetArg, verboseArg) if vcvars != nil: for vccEnvKey, vccEnvVal in vcvars: putEnv(vccEnvKey, vccEnvVal) diff --git a/tools/vccexe/vcvarsall.nim b/tools/vccexe/vcvarsall.nim index 29d13cc7e..73b103e3c 100644 --- a/tools/vccexe/vcvarsall.nim +++ b/tools/vccexe/vcvarsall.nim @@ -33,7 +33,7 @@ type vccplatUWP = "uwp", ## Universal Windows Platform (UWP) Application vccplatOneCore = "onecore" # Undocumented platform type in the Windows SDK, probably XBox One SDK platform type. -proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type: VccPlatformType = vccplatEmpty, sdk_version: string = "", verbose: bool = false): StringTableRef = +proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type: VccPlatformType = vccplatEmpty, sdk_version, vctoolset: string = "", verbose: bool = false): StringTableRef = ## Returns a string table containing the proper process environment to successfully execute VCC compile commands for the specified SDK version, CPU architecture and platform type. ## ## path @@ -44,6 +44,8 @@ proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type ## The compile target Platform Type. Defaults to the Windows Desktop platform, i.e. a regular Windows executable binary. ## sdk_version ## The Windows SDK version to use. + ## vctoolset + ## Visual Studio compiler toolset to use. ## verbose ## Echo the command-line passed on to the system to load the VCC environment. Defaults to `false`. @@ -63,6 +65,9 @@ proc vccVarsAll*(path: string, arch: VccArch = vccarchUnspecified, platform_type if sdk_version.len > 0: args.add(sdk_version) + + if vctoolset.len > 0: + args.add("-vcvars_ver="&vctoolset) let argStr = args.join " " From 6c15958a835b645f3acdc3d1d012b10d0df43454 Mon Sep 17 00:00:00 2001 From: Gabriel Huber Date: Sun, 12 Feb 2023 16:41:27 +0100 Subject: [PATCH 4179/4254] Change the default stdlib location for Linux packaging (#21328) * Correctly evaluate the Nim prefix on Posix * Document new packaging layout --- compiler/options.nim | 22 ++++++++++++---------- doc/packaging.md | 7 +++++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 833d86a16..862b42446 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -717,22 +717,24 @@ proc getPrefixDir*(conf: ConfigRef): AbsoluteDir = ## clone or using installed nim, so that these exist: `result/doc/advopt.txt` ## and `result/lib/system.nim` if not conf.prefixDir.isEmpty: result = conf.prefixDir - else: result = AbsoluteDir splitPath(getAppDir()).head + else: + let binParent = AbsoluteDir splitPath(getAppDir()).head + when defined(posix): + if binParent == AbsoluteDir"/usr": + result = AbsoluteDir"/usr/lib/nim" + elif binParent == AbsoluteDir"/usr/local": + result = AbsoluteDir"/usr/local/lib/nim" + else: + result = binParent + else: + result = binParent proc setDefaultLibpath*(conf: ConfigRef) = # set default value (can be overwritten): if conf.libpath.isEmpty: # choose default libpath: var prefix = getPrefixDir(conf) - when defined(posix): - if prefix == AbsoluteDir"/usr": - conf.libpath = AbsoluteDir"/usr/lib/nim" - elif prefix == AbsoluteDir"/usr/local": - conf.libpath = AbsoluteDir"/usr/local/lib/nim" - else: - conf.libpath = prefix / RelativeDir"lib" - else: - conf.libpath = prefix / RelativeDir"lib" + conf.libpath = prefix / RelativeDir"lib" # Special rule to support other tools (nimble) which import the compiler # modules and make use of them. diff --git a/doc/packaging.md b/doc/packaging.md index 9a1cc0f6e..522ca6d44 100644 --- a/doc/packaging.md +++ b/doc/packaging.md @@ -69,8 +69,11 @@ Hints on the build process: What to install: -- The expected stdlib location is /usr/lib/nim -- Global configuration files under /etc/nim +- The expected stdlib location is `/usr/lib/nim/lib`, previously it was just `/usr/lib/nim` +- `nimdoc.css` and `nimdoc.cls` from the `doc` folder should go into `/usr/lib/nim/doc/` +- `tools/nim-gdb.py` should go into `/usr/lib/nim/tools/` +- `tools/dochack/dochack.js` should be installed to `/usr/lib/nim/tools/dochack/` +- Global configuration files under `/etc/nim` - Optionally: manpages, documentation, shell completion - When installing documentation, .idx files are not required - The "compiler" directory contains compiler sources and should not be part of the compiler binary package From 684c3b3aeb90ae549382ed0f9c3286464c72809f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 14 Feb 2023 14:00:29 +0800 Subject: [PATCH 4180/4254] fixes comments about type bound operations (#21365) --- compiler/liftdestructors.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 2b27a58fc..738f659b7 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -8,7 +8,7 @@ # ## This module implements lifting for type-bound operations -## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``). +## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``). import modulegraphs, lineinfos, idents, ast, renderer, semdata, sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils From 406d3021314c66fdf4c715efeeaea3c8f478fcaa Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 14 Feb 2023 14:29:30 +0800 Subject: [PATCH 4181/4254] allow omitting stmts using `finally` as post expr blocks; make it consistent with `else`, `except` etc. (#21361) allow omitting stmts using `finally` as post expr blocks --- compiler/parser.nim | 2 +- tests/parser/tpostexprblocks.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 14882d415..abfc7b323 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1496,7 +1496,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = result = makeCall(result) getTok(p) skipComment(p, result) - if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}: + if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept, tkFinally}: var stmtList = newNodeP(nkStmtList, p) stmtList.add parseStmt(p) # to keep backwards compatibility (see tests/vm/tstringnil) diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim index d272c712f..6cd4a8350 100644 --- a/tests/parser/tpostexprblocks.nim +++ b/tests/parser/tpostexprblocks.nim @@ -498,6 +498,13 @@ StmtList StmtList DiscardStmt Empty + + Call + Ident "foo" + Finally + StmtList + DiscardStmt + Empty ''' """ @@ -655,3 +662,7 @@ dumpTree: discard finally: discard + + foo: + finally: + discard From 1d06c2b6cf84bcf65b67e88667dba4fd5e8ba519 Mon Sep 17 00:00:00 2001 From: c-blake Date: Tue, 14 Feb 2023 02:00:30 -0500 Subject: [PATCH 4182/4254] This adds `parseutils.parseSize`, an inverse to `strutils.formatSize` (#21349) * This adds `parseutils.parseSize`, an inverse to `strutils.formatSize` which has existed since 2017. It is useful for parsing the compiler's own output logs (like SuccessX) or many other scenarios where "human readable" units have been chosen. The doc comment and tests explain accepted syntax in detail. Big units lead to small numbers, often with a fractional part, but we parse into an `int64` since that is what `formatSize` stringifies and this is an inverse over partial function slots. Although metric prefixes z & y for zettabyte & yottabyte are accepted, these will saturate the result at `int64.high` unless the qualified number is a small fraction. This should not be much of a problem until such sizes are common (at which point another overload with the parse result either `float64` or `int128` could be added). Tests avoids `test()` because of a weakly related static: test() failure as mentioned in https://github.com/nim-lang/Nim/pull/21325. This is a more elemental VM failure. As such, it needs its own failure exhibition issue that is a smaller test case. (I am working on that, but unless there is a burning need to `parseSize` at compile-time before run-time it need not hold up this PR.) * This worked with `int` but fails with `int64`. Try for green tests. * Lift 2-result matching into a `checkParseSize` template and format as a table of input & 2 expected outputs which seems nicer and to address https://github.com/nim-lang/Nim/pull/21349#pullrequestreview-1294407679 * Fix (probably) the i386 trouble by using `int64` consistently. * Improve documentation by mentioning saturation. * Improve documentation with `runnableExamples` and a little more detail in the main doc comment based on excellent code review by @juancarlospaco: https://github.com/nim-lang/Nim/pull/21349#pullrequestreview-1294564155 * Address some more @juancarlospaco code review concerns. * Remove a stray space. * Mention milli-bytes in docs to maybe help clarify why wild conventions are so prone to going case-insensitive-metric. * Add some parens. --- changelog.md | 2 +- lib/pure/parseutils.nim | 65 ++++++++++++++++++++++++++++++++++++ tests/stdlib/tparseutils.nim | 41 +++++++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 0389faad9..2db577d0b 100644 --- a/changelog.md +++ b/changelog.md @@ -10,7 +10,7 @@ [//]: # "Additions:" - +- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. [//]: # "Deprecations:" diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 2bb23c626..c4d59d892 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -592,6 +592,71 @@ proc parseFloat*(s: openArray[char], number: var float): int {. if result != 0: number = bf +func toLowerAscii(c: char): char = + if c in {'A'..'Z'}: char(uint8(c) xor 0b0010_0000'u8) else: c + +func parseSize*(s: openArray[char], size: var int64, alwaysBin=false): int = + ## Parse a size qualified by binary or metric units into `size`. This format + ## is often called "human readable". Result is the number of processed chars + ## or 0 on parse errors and size is rounded to the nearest integer. Trailing + ## garbage like "/s" in "1k/s" is allowed and detected by `result < s.len`. + ## + ## To simplify use, following non-rare wild conventions, and since fractional + ## data like milli-bytes is so rare, unit matching is case-insensitive but for + ## the 'i' distinguishing binary-metric from metric (which cannot be 'I'). + ## + ## An optional trailing 'B|b' is ignored but processed. I.e., you must still + ## know if units are bytes | bits or infer this fact via the case of s[^1] (if + ## users can even be relied upon to use 'B' for byte and 'b' for bit or have + ## that be s[^1]). + ## + ## If `alwaysBin==true` then scales are always binary-metric, but e.g. "KiB" + ## is still accepted for clarity. If the value would exceed the range of + ## `int64`, `size` saturates to `int64.high`. Supported metric prefix chars + ## include k, m, g, t, p, e, z, y (but z & y saturate unless the number is a + ## small fraction). + ## + ## **See also:** + ## * https://en.wikipedia.org/wiki/Binary_prefix + ## * `formatSize module`_ for formatting + runnableExamples: + var res: int64 # caller must still know if 'b' refers to bytes|bits + doAssert parseSize("10.5 MB", res) == 7 + doAssert res == 10_500_000 # decimal metric Mega prefix + doAssert parseSize("64 mib", res) == 6 + doAssert res == 67108864 # 64 shl 20 + doAssert parseSize("1G/h", res, true) == 2 # '/' stops parse + doAssert res == 1073741824 # 1 shl 30, forced binary metric + const prefix = "b" & "kmgtpezy" # byte|bit & lowCase metric-ish prefixes + const scaleM = [1.0, 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24] # 10^(3*idx) + const scaleB = [1.0, 1024, 1048576, 1073741824, 1099511627776.0, # 2^(10*idx) + 1125899906842624.0, 1152921504606846976.0, # ldexp? + 1.180591620717411303424e21, 1.208925819614629174706176e24] + var number: float + var scale = 1.0 + result = parseFloat(s, number) + if number < 0: # While parseFloat accepts negatives .. + result = 0 #.. we do not since sizes cannot be < 0 + if result > 0: + let start = result # Save spot to maybe unwind white to EOS + while result < s.len and s[result] in Whitespace: + inc result + if result < s.len: # Illegal starting char => unity + if (let si = prefix.find(s[result].toLowerAscii); si >= 0): + inc result # Now parse the scale + scale = if alwaysBin: scaleB[si] else: scaleM[si] + if result < s.len and s[result] == 'i': + scale = scaleB[si] # Switch from default to binary-metric + inc result + if result < s.len and s[result].toLowerAscii == 'b': + inc result # Skip optional '[bB]' + else: # Unwind result advancement when there.. + result = start #..is no unit to the end of `s`. + var sizeF = number * scale + 0.5 # Saturate to int64.high when too big + size = if sizeF > 9223372036854774784.0: int64.high else: sizeF.int64 +# Above constant=2^63-1024 avoids C UB; github.com/nim-lang/Nim/issues/20102 or +# stackoverflow.com/questions/20923556/math-pow2-63-1-math-pow2-63-512-is-true + type InterpolatedKind* = enum ## Describes for `interpolatedFragments` ## which part of the interpolated string is diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim index 102e74067..218dd08f6 100644 --- a/tests/stdlib/tparseutils.nim +++ b/tests/stdlib/tparseutils.nim @@ -55,5 +55,46 @@ proc test() = doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"), (17, "9.123456789012344"), (17, "8.123456789012344"), (16, "9.12345678901234"), (17, "9.123456789012344")] + test() static: test() + +block: # With this included, static: test() crashes the compiler (from a + # VM problem with parseSize calling parseFloat). + var sz: int64 + template checkParseSize(s, expectLen, expectVal) = + if (let got = parseSize(s, sz); got != expectLen): + raise newException(IOError, "got len " & $got & " != " & $expectLen) + if sz != expectVal: + raise newException(IOError, "got sz " & $sz & " != " & $expectVal) + # STRING LEN SZ + # Good, complete parses + checkParseSize "1 b" , 4, 1 + checkParseSize "1 B" , 4, 1 + checkParseSize "1k" , 2, 1000 + checkParseSize "1 kib" , 5, 1024 + checkParseSize "1 ki" , 4, 1024 + checkParseSize "1mi" , 3, 1048576 + checkParseSize "1 mi" , 4, 1048576 + checkParseSize "1 mib" , 5, 1048576 + checkParseSize "1 Mib" , 5, 1048576 + checkParseSize "1 MiB" , 5, 1048576 + checkParseSize "1.23GiB", 7, 1320702444 # 1320702443.52 rounded + checkParseSize "0.001k" , 6, 1 + checkParseSize "0.0004k", 7, 0 + checkParseSize "0.0006k", 7, 1 + # Incomplete parses + checkParseSize "1 " , 1, 1 # Trailing white IGNORED + checkParseSize "1 B " , 4, 1 # Trailing white IGNORED + checkParseSize "1 B/s" , 4, 1 # Trailing junk IGNORED + checkParseSize "1 kX" , 3, 1000 + checkParseSize "1 kiX" , 4, 1024 + checkParseSize "1j" , 1, 1 # Unknown prefix IGNORED + checkParseSize "1 jib" , 2, 1 # Unknown prefix post space + checkParseSize "1 ji" , 3, 1 + # Bad parses; `sz` should stay last good|incomplete value + checkParseSize "-1b" , 0, 1 # Negative numbers + checkParseSize "abc" , 0, 1 # Non-numeric + checkParseSize " 12" , 0, 1 # Leading white + # Value Edge cases + checkParseSize "9223372036854775807", 19, int64.high From cac49694c011e851707cb3a86a3263c741559b3d Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 14 Feb 2023 18:14:19 +1100 Subject: [PATCH 4183/4254] `std/asyncjs` allow transforming proc types (#21356) * Add test case * Implement JS async transform for nnkProcTy --- lib/js/asyncjs.nim | 10 +++++++++- tests/js/tasyncjs.nim | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 364f7a21a..8e2f85156 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -100,10 +100,18 @@ proc isFutureVoid(node: NimNode): bool = node[1].kind == nnkIdent and $node[1] == "void" proc generateJsasync(arg: NimNode): NimNode = - if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: + if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo, nnkProcTy}: error("Cannot transform this node kind into an async proc." & " proc/method definition or lambda node expected.") + # Transform type X = proc (): something {.async.} + # into type X = proc (): Future[something] + if arg.kind == nnkProcTy: + result = arg + if arg[0][0].kind == nnkEmpty: + result[0][0] = quote do: Future[void] + return result + result = arg var isVoid = false let jsResolve = ident("jsResolve") diff --git a/tests/js/tasyncjs.nim b/tests/js/tasyncjs.nim index 00753a16c..3de143643 100644 --- a/tests/js/tasyncjs.nim +++ b/tests/js/tasyncjs.nim @@ -94,4 +94,9 @@ proc main() {.async.} = doAssert "foobar: 7" in $reason.message echo "done" # justified here to make sure we're running this, since it's inside `async` +block asyncPragmaInType: + type Handler = proc () {.async.} + proc foo() {.async.} = discard + var x: Handler = foo + discard main() From 56a4d246a4288a7005de0b20e312fa4e4af89534 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 14 Feb 2023 20:11:14 +0800 Subject: [PATCH 4184/4254] Refines raises list in osproc (#21323) * Remove Exception from raises in closeImpl * Update osproc.nim * refine errors * add ValueError * cast raises * refactor raises lists * Update lib/pure/osproc.nim * Update lib/pure/osproc.nim --------- Co-authored-by: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Co-authored-by: Andreas Rumpf --- lib/pure/osproc.nim | 41 ++++++++++++++++++++------------------- lib/pure/streams.nim | 2 +- lib/std/socketstreams.nim | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 5e130b47a..9a0e5895d 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -76,7 +76,7 @@ type proc execProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): - string {.rtl, extern: "nosp$1", + string {.rtl, extern: "nosp$1", raises: [OSError, IOError], tags: [ExecIOEffect, ReadIOEffect, RootEffect].} ## A convenience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. @@ -120,7 +120,7 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", proc startProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut}): - owned(Process) {.rtl, extern: "nosp$1", + owned(Process) {.rtl, extern: "nosp$1", raises: [OSError, IOError], tags: [ExecIOEffect, ReadEnvEffect, RootEffect].} ## Starts a process. `Command` is the executable file, `workingDir` is the ## process's working directory. If ``workingDir == ""`` the current directory @@ -152,7 +152,7 @@ proc startProcess*(command: string, workingDir: string = "", ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## * `execCmd proc <#execCmd,string>`_ -proc close*(p: Process) {.rtl, extern: "nosp$1", tags: [WriteIOEffect].} +proc close*(p: Process) {.rtl, extern: "nosp$1", raises: [IOError, OSError], tags: [WriteIOEffect].} ## When the process has finished executing, cleanup related handles. ## ## .. warning:: If the process has not finished executing, this will forcibly @@ -201,7 +201,7 @@ proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## * `terminate proc <#terminate,Process>`_ ## * `posix_utils.sendSignal(pid: Pid, signal: int) `_ -proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} +proc running*(p: Process): bool {.rtl, extern: "nosp$1", raises: [OSError], tags: [].} ## Returns true if the process `p` is still running. Returns immediately. proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = @@ -212,7 +212,7 @@ proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = return p.id proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, - extern: "nosp$1", tags: [].} + extern: "nosp$1", raises: [OSError, ValueError], tags: [].} ## Waits for the process to finish and returns `p`'s error code. ## ## .. warning:: Be careful when using `waitForExit` for processes created without @@ -221,7 +221,7 @@ proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, ## On posix, if the process has exited because of a signal, 128 + signal ## number will be returned. -proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", tags: [].} +proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", raises: [OSError], tags: [].} ## Return `-1` if the process is still running. Otherwise the process' exit code. ## ## On posix, if the process has exited because of a signal, 128 + signal @@ -237,7 +237,7 @@ proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## * `outputStream proc <#outputStream,Process>`_ ## * `errorStream proc <#errorStream,Process>`_ -proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} +proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", raises: [IOError, OSError], tags: [].} ## Returns ``p``'s output stream for reading from. ## ## You cannot perform peek/write/setOption operations to this stream. @@ -289,7 +289,7 @@ proc peekableErrorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], ## * `errorStream proc <#errorStream,Process>`_ ## * `peekableOutputStream proc <#peekableOutputStream,Process>`_ -proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", +proc inputHandle*(p: Process): FileHandle {.rtl, raises: [], extern: "nosp$1", tags: [].} = ## Returns ``p``'s input file handle for writing to. ## @@ -302,7 +302,7 @@ proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", result = p.inHandle proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", - tags: [].} = + raises: [], tags: [].} = ## Returns ``p``'s output file handle for reading from. ## ## .. warning:: The returned `FileHandle` should not be closed manually as @@ -314,7 +314,7 @@ proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", result = p.outHandle proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", - tags: [].} = + raises: [], tags: [].} = ## Returns ``p``'s error file handle for reading from. ## ## .. warning:: The returned `FileHandle` should not be closed manually as @@ -325,7 +325,7 @@ proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", ## * `outputHandle proc <#outputHandle,Process>`_ result = p.errHandle -proc countProcessors*(): int {.rtl, extern: "nosp$1".} = +proc countProcessors*(): int {.rtl, extern: "nosp$1", raises: [].} = ## Returns the number of the processors/cores the machine has. ## Returns 0 if it cannot be detected. ## It is implemented just calling `cpuinfo.countProcessors`. @@ -339,6 +339,7 @@ proc execProcesses*(cmds: openArray[string], beforeRunEvent: proc(idx: int) = nil, afterRunEvent: proc(idx: int, p: Process) = nil): int {.rtl, extern: "nosp$1", + raises: [ValueError, OSError, IOError], tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect], effectsOf: [beforeRunEvent, afterRunEvent].} = ## Executes the commands `cmds` in parallel. @@ -452,7 +453,7 @@ proc execProcesses*(cmds: openArray[string], if afterRunEvent != nil: afterRunEvent(i, p) close(p) -iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), tags: [ReadIOEffect].} = +iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raises: [OSError, IOError, ValueError], tags: [ReadIOEffect].} = ## Convenience iterator for working with `startProcess` to read data from a ## background process. ## @@ -481,7 +482,8 @@ iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), tags: yield line discard waitForExit(p) -proc readLines*(p: Process): (seq[string], int) {.since: (1, 3).} = +proc readLines*(p: Process): (seq[string], int) {.since: (1, 3), + raises: [OSError, IOError, ValueError], tags: [ReadIOEffect].} = ## Convenience function for working with `startProcess` to read data from a ## background process. ## @@ -747,7 +749,7 @@ when defined(windows) and not defined(useNimRtl): const errFileNotFound = 2.int if lastError.int in {errInvalidParameter, errFileNotFound}: raiseOSError(lastError, - "Requested command not found: '$1'. OS error:" % command) + "Requested command not found: '" & command & "'. OS error:") else: raiseOSError(lastError, command) result.fProcessHandle = procInfo.hProcess @@ -955,13 +957,13 @@ elif not defined(useNimRtl): not defined(useClone) and not defined(linux) when useProcessAuxSpawn: proc startProcessAuxSpawn(data: StartProcessData): Pid {. - tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} + raises: [OSError], tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} else: proc startProcessAuxFork(data: StartProcessData): Pid {. - tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} + raises: [OSError], tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], gcsafe.} {.push stacktrace: off, profiler: off.} proc startProcessAfterFork(data: ptr StartProcessData) {. - tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} + raises: [OSError], tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} {.pop.} proc startProcess(command: string, workingDir: string = "", @@ -1131,8 +1133,7 @@ elif not defined(useNimRtl): let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error)) if sizeRead == sizeof(error): raiseOSError(osLastError(), - "Could not find command: '$1'. OS error: $2" % - [$data.sysCommand, $strerror(error)]) + "Could not find command: '" & $data.sysCommand & "'. OS error: " & $strerror(error)) return pid @@ -1578,7 +1579,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { poStdErrToStdOut, poUsePath}, env: StringTableRef = nil, workingDir = "", input = ""): tuple[ output: string, - exitCode: int] {.tags: + exitCode: int] {.raises: [OSError, IOError], tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = ## A convenience proc that runs the `command`, and returns its `output` and ## `exitCode`. `env` and `workingDir` params behave as for `startProcess`. diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 945e85934..003f8ca4c 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -115,7 +115,7 @@ type ## * That these fields here shouldn't be used directly. ## They are accessible so that a stream implementation can override them. closeImpl*: proc (s: Stream) - {.nimcall, raises: [Exception, IOError, OSError], tags: [WriteIOEffect], gcsafe.} + {.nimcall, raises: [IOError, OSError], tags: [WriteIOEffect], gcsafe.} atEndImpl*: proc (s: Stream): bool {.nimcall, raises: [Defect, IOError, OSError], tags: [], gcsafe.} setPositionImpl*: proc (s: Stream, pos: int) diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim index 5c882858d..b53d6a5d3 100644 --- a/lib/std/socketstreams.nim +++ b/lib/std/socketstreams.nim @@ -146,7 +146,7 @@ proc wsFlush(s: Stream) = s.lastFlush = s.buf.len proc rsClose(s: Stream) = - {.cast(tags: []).}: + {.cast(raises: [IOError, OSError]), cast(tags: []).}: # todo fixme maybe do something? var s = ReadSocketStream(s) s.data.close() From e24d0e5faf1f6f2906262457007261e2358f1e5d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 15 Feb 2023 20:03:11 +0800 Subject: [PATCH 4185/4254] remove legacy code; the first iteration now can build Nim with cpp backend (#21373) --- koch.nim | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/koch.nim b/koch.nim index 27953e05a..fa498e017 100644 --- a/koch.nim +++ b/koch.nim @@ -295,11 +295,7 @@ proc boot(args: string) = let nimStart = findStartNim().quoteShell() for i in 0..2: - # Nim versions < (1, 1) expect Nim's exception type to have a 'raiseId' field for - # C++ interop. Later Nim versions do this differently and removed the 'raiseId' field. - # Thus we always bootstrap the first iteration with "c" and not with "cpp" as - # a workaround. - let defaultCommand = if useCpp and i > 0: "cpp" else: "c" + let defaultCommand = if useCpp: "cpp" else: "c" let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: "" echo "iteration: ", i+1 var extraOption = "" From c91ef1a09f3284315e9e66c32532f5a8e3ba9297 Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 15 Feb 2023 11:41:28 -0500 Subject: [PATCH 4186/4254] Fix `closeHandle` bug, add `setFileSize`, make `resize` work on Windows (#21375) * Add general purpose `setFileSize` (unexported for now). Use to simplify `memfiles.open` as well as make robust (via hard allocation, not merely `ftruncate` address space allocation) on systems with `posix_fallocate`. As part of this, fix a bad `closeHandle` return check bug on Windows and add `MemFile.resize` for Windows now that setFileSize makes that easier. * Adapt existing test to exercise newly portable `MemFile.resize`. * Since Apple has never provided `posix_fallocate`, provide a fallback. This is presently written in terms of `ftruncate`, but it can be improved to use `F_PREALLOCATE` instead, as mentioned in a comment. --- lib/posix/posix.nim | 11 +++- lib/pure/memfiles.nim | 123 ++++++++++++++++++++++++------------ tests/stdlib/tmemfiles2.nim | 5 +- 3 files changed, 92 insertions(+), 47 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 43346608d..aee9308a6 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -195,8 +195,14 @@ proc open*(a1: cstring, a2: cint, mode: Mode | cint = 0.Mode): cint {.inline.} = proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {. importc, header: "".} -proc posix_fallocate*(a1: cint, a2, a3: Off): cint {. - importc, header: "".} + +proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "".} +when defined(osx): # 2001 POSIX evidently does not concern Apple + proc posix_fallocate*(a1: cint, a2, a3: Off): cint = + ftruncate(a1, a2 + a3) # Set size to off + len, max offset +else: # TODO: Use fcntl(fd, F_PREALLOCATE, ..) above + proc posix_fallocate*(a1: cint, a2, a3: Off): cint {. + importc, header: "".} when not defined(haiku) and not defined(openbsd): proc fmtmsg*(a1: int, a2: cstring, a3: cint, @@ -511,7 +517,6 @@ proc fpathconf*(a1, a2: cint): int {.importc, header: "".} proc fsync*(a1: cint): cint {.importc, header: "".} ## synchronize a file's buffer cache to the storage device -proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "".} proc getcwd*(a1: cstring, a2: int): cstring {.importc, header: "", sideEffect.} proc getuid*(): Uid {.importc, header: "", sideEffect.} ## returns the real user ID of the calling process diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 9ff8bcd74..58c4888f1 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -35,6 +35,31 @@ proc newEIO(msg: string): ref IOError = new(result) result.msg = msg +proc setFileSize(fh: FileHandle, newFileSize = -1): OSErrorCode = + ## Set the size of open file pointed to by `fh` to `newFileSize` if != -1. + ## Space is only allocated if that is cheaper than writing to the file. This + ## routine returns the last OSErrorCode found rather than raising to support + ## old rollback/clean-up code style. [ Should maybe move to std/osfiles. ] + if newFileSize == -1: + return + when defined(windows): + var sizeHigh = int32(newFileSize shr 32) + let sizeLow = int32(newFileSize and 0xffffffff) + let status = setFilePointer(fh, sizeLow, addr(sizeHigh), FILE_BEGIN) + let lastErr = osLastError() + if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or + setEndOfFile(fh) == 0: + result = lastErr + else: + var e: cint # posix_fallocate truncates up when needed. + when declared(posix_fallocate): + while (e = posix_fallocate(fh, 0, newFileSize); e == EINTR): + discard + if e in [EINVAL, EOPNOTSUPP] and ftruncate(fh, newFileSize) == -1: + result = osLastError() # fallback arguable; Most portable, but allows SEGV + elif e != 0: + result = osLastError() + type MemFile* = object ## represents a memory mapped file mem*: pointer ## a pointer to the memory mapped file. The pointer @@ -182,17 +207,8 @@ proc open*(filename: string, mode: FileMode = fmRead, if result.fHandle == INVALID_HANDLE_VALUE: fail(osLastError(), "error opening file") - if newFileSize != -1: - var - sizeHigh = int32(newFileSize shr 32) - sizeLow = int32(newFileSize and 0xffffffff) - - var status = setFilePointer(result.fHandle, sizeLow, addr(sizeHigh), - FILE_BEGIN) - let lastErr = osLastError() - if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or - (setEndOfFile(result.fHandle) == 0): - fail(lastErr, "error setting file size") + if (let e = setFileSize(result.fHandle.FileHandle, newFileSize); + e != 0.OSErrorCode): fail(e, "error setting file size") # since the strings are always 'nil', we simply always call # CreateFileMappingW which should be slightly faster anyway: @@ -226,7 +242,7 @@ proc open*(filename: string, mode: FileMode = fmRead, result.wasOpened = true if not allowRemap and result.fHandle != INVALID_HANDLE_VALUE: - if closeHandle(result.fHandle) == 0: + if closeHandle(result.fHandle) != 0: result.fHandle = INVALID_HANDLE_VALUE else: @@ -249,9 +265,8 @@ proc open*(filename: string, mode: FileMode = fmRead, # Is there an exception that wraps it? fail(osLastError(), "error opening file") - if newFileSize != -1: - if ftruncate(result.handle, newFileSize) == -1: - fail(osLastError(), "error setting file size") + if (let e = setFileSize(result.handle.FileHandle, newFileSize); + e != 0.OSErrorCode): fail(e, "error setting file size") if mappedSize != -1: result.size = mappedSize @@ -306,34 +321,58 @@ proc flush*(f: var MemFile; attempts: Natural = 3) = if lastErr != EBUSY.OSErrorCode: raiseOSError(lastErr, "error flushing mapping") -when defined(posix) or defined(nimdoc): - proc resize*(f: var MemFile, newFileSize: int) {.raises: [IOError, OSError].} = - ## resize and re-map the file underlying an `allowRemap MemFile`. - ## **Note**: this assumes the entire file is mapped read-write at offset zero. - ## Also, the value of `.mem` will probably change. - ## **Note**: This is not (yet) available on Windows. - when defined(posix): - if f.handle == -1: - raise newException(IOError, - "Cannot resize MemFile opened with allowRemap=false") - if ftruncate(f.handle, newFileSize) == -1: - raiseOSError(osLastError()) - when defined(linux): #Maybe NetBSD, too? - #On Linux this can be over 100 times faster than a munmap,mmap cycle. - proc mremap(old: pointer; oldSize, newSize: csize_t; flags: cint): - pointer {.importc: "mremap", header: "".} - let newAddr = mremap(f.mem, csize_t(f.size), csize_t(newFileSize), cint(1)) - if newAddr == cast[pointer](MAP_FAILED): - raiseOSError(osLastError()) - else: - if munmap(f.mem, f.size) != 0: - raiseOSError(osLastError()) - let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE, - f.flags, f.handle, 0) - if newAddr == cast[pointer](MAP_FAILED): - raiseOSError(osLastError()) - f.mem = newAddr +proc resize*(f: var MemFile, newFileSize: int) {.raises: [IOError, OSError].} = + ## Resize & re-map the file underlying an `allowRemap MemFile`. If the OS/FS + ## supports it, file space is reserved to ensure room for new virtual pages. + ## Caller should wait often enough for `flush` to finish to limit use of + ## system RAM for write buffering, perhaps just prior to this call. + ## **Note**: this assumes the entire file is mapped read-write at offset 0. + ## Also, the value of `.mem` will probably change. + if newFileSize < 1: # Q: include system/bitmasks & use PageSize ? + raise newException(IOError, "Cannot resize MemFile to < 1 byte") + when defined(windows): + if not f.wasOpened: + raise newException(IOError, "Cannot resize unopened MemFile") + if f.fHandle == INVALID_HANDLE_VALUE: + raise newException(IOError, + "Cannot resize MemFile opened with allowRemap=false") + if unmapViewOfFile(f.mem) == 0 or closeHandle(f.mapHandle) == 0: # Un-do map + raiseOSError(osLastError()) + if newFileSize != f.size: # Seek to size & `setEndOfFile` => allocated. + if (let e = setFileSize(f.fHandle.FileHandle, newFileSize); + e != 0.OSErrorCode): raiseOSError(e) + f.mapHandle = createFileMappingW(f.fHandle, nil, PAGE_READWRITE, 0,0,nil) + if f.mapHandle == 0: # Re-do map + raiseOSError(osLastError()) + if (let m = mapViewOfFileEx(f.mapHandle, FILE_MAP_READ or FILE_MAP_WRITE, + 0, 0, WinSizeT(newFileSize), nil); m != nil): + f.mem = m f.size = newFileSize + else: + raiseOSError(osLastError()) + elif defined(posix): + if f.handle == -1: + raise newException(IOError, + "Cannot resize MemFile opened with allowRemap=false") + if newFileSize != f.size: + if (let e = setFileSize(f.handle.FileHandle, newFileSize); + e != 0.OSErrorCode): raiseOSError(e) + when defined(linux): #Maybe NetBSD, too? + # On Linux this can be over 100 times faster than a munmap,mmap cycle. + proc mremap(old: pointer; oldSize, newSize: csize_t; flags: cint): + pointer {.importc: "mremap", header: "".} + let newAddr = mremap(f.mem, csize_t(f.size), csize_t(newFileSize), 1.cint) + if newAddr == cast[pointer](MAP_FAILED): + raiseOSError(osLastError()) + else: + if munmap(f.mem, f.size) != 0: + raiseOSError(osLastError()) + let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE, + f.flags, f.handle, 0) + if newAddr == cast[pointer](MAP_FAILED): + raiseOSError(osLastError()) + f.mem = newAddr + f.size = newFileSize proc close*(f: var MemFile) = ## closes the memory mapped file `f`. All changes are written back to the diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim index 6fee3c1ae..c79f85ebf 100644 --- a/tests/stdlib/tmemfiles2.nim +++ b/tests/stdlib/tmemfiles2.nim @@ -15,8 +15,9 @@ var if fileExists(fn): removeFile(fn) -# Create a new file, data all zeros -mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20) +# Create a new file, data all zeros, starting at size 10 +mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 10, allowRemap=true) +mm.resize 20 # resize up to 20 mm.close() # read, change From fc7385bfda7b3af93aa57c5cf446a90b470de348 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 16 Feb 2023 10:23:35 +0800 Subject: [PATCH 4187/4254] fixes #21360; discarding empty seqs/arrays now raises errors (#21374) * discarding empty seqs now raises errors * the same goes for sets --- compiler/semstmts.nim | 18 ++++++++++-------- tests/discard/tillegaldiscardtypes.nim | 14 ++++++++++++++ tests/typerel/ttypelessemptyset.nim | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 tests/discard/tillegaldiscardtypes.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c7e48db4c..7dc976c19 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -40,6 +40,13 @@ const proc implicitlyDiscardable(n: PNode): bool +proc hasEmpty(typ: PType): bool = + if typ.kind in {tySequence, tyArray, tySet}: + result = typ.lastSon.kind == tyEmpty + elif typ.kind == tyTuple: + for s in typ.sons: + result = result or hasEmpty(s) + proc semDiscard(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1, c.config) @@ -47,7 +54,9 @@ proc semDiscard(c: PContext, n: PNode): PNode = n[0] = semExprWithType(c, n[0]) let sonType = n[0].typ let sonKind = n[0].kind - if isEmptyType(sonType) or sonType.kind in {tyNone, tyTypeDesc} or sonKind == nkTypeOfExpr: + if isEmptyType(sonType) or hasEmpty(sonType) or + sonType.kind in {tyNone, tyTypeDesc} or + sonKind == nkTypeOfExpr: localError(c.config, n.info, errInvalidDiscard) if sonType.kind == tyProc and sonKind notin nkCallKinds: # tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant. @@ -410,13 +419,6 @@ proc semUsing(c: PContext; n: PNode): PNode = if a[^1].kind != nkEmpty: localError(c.config, a.info, "'using' sections cannot contain assignments") -proc hasEmpty(typ: PType): bool = - if typ.kind in {tySequence, tyArray, tySet}: - result = typ.lastSon.kind == tyEmpty - elif typ.kind == tyTuple: - for s in typ.sons: - result = result or hasEmpty(s) - proc hasUnresolvedParams(n: PNode; flags: TExprFlags): bool = result = tfUnresolved in n.typ.flags when false: diff --git a/tests/discard/tillegaldiscardtypes.nim b/tests/discard/tillegaldiscardtypes.nim new file mode 100644 index 000000000..b7877bcd2 --- /dev/null +++ b/tests/discard/tillegaldiscardtypes.nim @@ -0,0 +1,14 @@ +discard """ + cmd: "nim check $file" + errormsg: "statement returns no value that can be discarded" + nimout: ''' +tillegaldiscardtypes.nim(11, 3) Error: statement returns no value that can be discarded +tillegaldiscardtypes.nim(12, 3) Error: statement returns no value that can be discarded +''' +""" + +proc b(v: int) = # bug #21360 + discard @[] + discard [] + +b(0) \ No newline at end of file diff --git a/tests/typerel/ttypelessemptyset.nim b/tests/typerel/ttypelessemptyset.nim index 5f49c33fd..a4b6f003a 100644 --- a/tests/typerel/ttypelessemptyset.nim +++ b/tests/typerel/ttypelessemptyset.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "internal error: invalid kind for lastOrd(tyEmpty)" + errormsg: "statement returns no value that can be discarded" """ var q = false discard (if q: {} else: {}) From 93e4f278a1b68c83944842175ab78b61fe5fb7ca Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:34:32 +0800 Subject: [PATCH 4188/4254] add deprecated warnings for `{.deadcodeelim: on.}` (#21277) --- compiler/pragmas.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 92e3d1922..6d953dee7 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -929,7 +929,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wThreadVar: noVal(c, it) incl(sym.flags, {sfThread, sfGlobal}) - of wDeadCodeElimUnused: discard # deprecated, dead code elim always on + of wDeadCodeElimUnused: + warningDeprecated(c.config, n.info, "'{.deadcodeelim: on.}' is deprecated, now a noop") # deprecated, dead code elim always on of wNoForward: pragmaNoForward(c, it) of wReorder: pragmaNoForward(c, it, flag = sfReorder) of wMagic: processMagic(c, it, sym) From 3b9e9fd7b29de97b394811f350876732c66cff19 Mon Sep 17 00:00:00 2001 From: Century Systems Date: Thu, 16 Feb 2023 21:47:52 +0900 Subject: [PATCH 4189/4254] Add support for NuttX RTOS. (#21372) * Add support for NuttX RTOS. Signed-off-by: Takeyoshi Kikuchi * lib: pure: asyncdispatch: assign to result. Signed-off-by: Takeyoshi Kikuchi * lib: std: typedthreads: add support for parameters to adjust Thread Stack Size. Like FreeRTOS/Zephyr, add support for following configurations. -d:nimThreadStackSize=xxxxx -d:nimThreadStackGuard=yyyy Signed-off-by: Takeyoshi Kikuchi --------- Signed-off-by: Takeyoshi Kikuchi --- compiler/options.nim | 4 +++- compiler/platform.nim | 7 ++++++- lib/posix/posix_other.nim | 5 ++++- lib/posix/posix_other_consts.nim | 13 ++++++++++++- lib/pure/asyncdispatch.nim | 5 ++++- lib/pure/asynchttpserver.nim | 5 +++-- lib/pure/asyncnet.nim | 3 ++- lib/pure/ioselects/ioselectors_select.nim | 2 +- lib/pure/nativesockets.nim | 7 ++++--- lib/pure/net.nim | 3 ++- lib/pure/selectors.nim | 9 +++++++-- lib/std/typedthreads.nim | 3 ++- lib/system.nim | 1 + lib/system/dyncalls.nim | 2 +- 14 files changed, 52 insertions(+), 17 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 862b42446..51a8ff6f0 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -621,7 +621,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osQnx, osAtari, osAix, osHaiku, osVxWorks, osSolaris, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos, - osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr} + osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr, osNuttX} of "linux": result = conf.target.targetOS in {osLinux, osAndroid} of "bsd": @@ -643,6 +643,8 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = result = conf.target.targetOS == osFreeRTOS of "zephyr": result = conf.target.targetOS == osZephyr + of "nuttx": + result = conf.target.targetOS == osNuttX of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian of "cpu8": result = CPU[conf.target.targetCPU].bit == 8 diff --git a/compiler/platform.nim b/compiler/platform.nim index 4b4316bc2..b6d6a119e 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -26,7 +26,8 @@ type osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx, osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks - osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, osAny + osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, + osNuttX, osAny type TInfoOSProp* = enum @@ -193,6 +194,10 @@ const objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {ospPosix}), + (name: "NuttX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + props: {ospPosix}), (name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 941e13192..1b6734b51 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -10,7 +10,7 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(freertos) or defined(zephyr): +when defined(freertos) or defined(zephyr) or defined(nuttx): const hasSpawnH = false # should exist for every Posix system nowadays hasAioH = false @@ -640,6 +640,9 @@ when defined(linux) or defined(nimdoc): ## or UDP packets. (Requires Linux kernel > 3.9) else: const SO_REUSEPORT* = cint(15) +elif defined(nuttx): + # Not supported, use SO_REUSEADDR to avoid compilation errors. + var SO_REUSEPORT* {.importc: "SO_REUSEADDR", header: "".}: cint else: var SO_REUSEPORT* {.importc, header: "".}: cint diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 59ac6f9ed..4b1644f20 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -99,7 +99,10 @@ var EXDEV* {.importc: "EXDEV", header: "".}: cint # var F_DUPFD* {.importc: "F_DUPFD", header: "".}: cint -var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD", header: "".}: cint +when defined(nuttx): + var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD_CLOEXEC", header: "".}: cint +else: + var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD", header: "".}: cint var F_GETFD* {.importc: "F_GETFD", header: "".}: cint var F_SETFD* {.importc: "F_SETFD", header: "".}: cint var F_GETFL* {.importc: "F_GETFL", header: "".}: cint @@ -127,6 +130,11 @@ var O_RDONLY* {.importc: "O_RDONLY", header: "".}: cint var O_RDWR* {.importc: "O_RDWR", header: "".}: cint var O_WRONLY* {.importc: "O_WRONLY", header: "".}: cint var O_CLOEXEC* {.importc: "O_CLOEXEC", header: "".}: cint +when defined(nuttx): + var O_DIRECT* {.importc: "O_DIRECT", header: "".}: cint + var O_PATH* {.importc: "O_PATH", header: "".}: cint + var O_NOATIME* {.importc: "O_NOATIME", header: "".}: cint + var O_TMPFILE* {.importc: "O_TMPFILE", header: "".}: cint var POSIX_FADV_NORMAL* {.importc: "POSIX_FADV_NORMAL", header: "".}: cint var POSIX_FADV_SEQUENTIAL* {.importc: "POSIX_FADV_SEQUENTIAL", header: "".}: cint var POSIX_FADV_RANDOM* {.importc: "POSIX_FADV_RANDOM", header: "".}: cint @@ -465,6 +473,9 @@ var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint when defined(zephyr): # Zephyr specific hardcoded value var FD_MAX* {.importc: "CONFIG_POSIX_MAX_FDS ", header: "".}: cint +elif defined(nuttx): + # NuttX specific user configuration value + var NACTIVESOCKETS* {.importc: "CONFIG_NET_NACTIVESOCKETS", header: "".}: cint # var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 214b7d12c..64100afa7 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -2024,7 +2024,7 @@ when defined(posix): import posix when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(solaris) or defined(zephyr) or defined(freertos): + defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx): proc maxDescriptors*(): int {.raises: OSError.} = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is @@ -2033,6 +2033,9 @@ when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or result = 16_700_000 elif defined(zephyr) or defined(freertos): result = FD_MAX + elif defined(nuttx): + # The maximum number of concurrently active UDP and TCP ports. + result = NACTIVESOCKETS else: var fdLim: RLimit if getrlimit(RLIMIT_NOFILE, fdLim) < 0: diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 845875a1e..c09fe35ca 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -387,8 +387,9 @@ proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET server.socket = newAsyncSocket(domain) if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) - if server.reusePort: - server.socket.setSockOpt(OptReusePort, true) + when not defined(nuttx): + if server.reusePort: + server.socket.setSockOpt(OptReusePort, true) server.socket.bindAddr(port, address) server.socket.listen() diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 982459af7..d35dbdfaf 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -106,7 +106,8 @@ export SOBool # TODO: Remove duplication introduced by PR #4683. const defineSsl = defined(ssl) or defined(nimdoc) -const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) +const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or + defined(nuttx) when defineSsl: import openssl diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 34c88d85e..a6f54e791 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -313,7 +313,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, verifySelectParams(timeout) if timeout != -1: - when defined(genode) or defined(freertos) or defined(zephyr): + when defined(genode) or defined(freertos) or defined(zephyr) or defined(nuttx): tv.tv_sec = Time(timeout div 1_000) else: tv.tv_sec = timeout.int32 div 1_000 diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 14a318412..b3465ef14 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -23,7 +23,8 @@ when hostOS == "solaris": {.passl: "-lsocket -lnsl".} const useWinVersion = defined(windows) or defined(nimdoc) -const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) +const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or + defined(nuttx) when useWinVersion: import winlean @@ -304,7 +305,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, let socketPort = if sockType == SOCK_RAW: "" else: $port var gaiResult = getaddrinfo(address, socketPort.cstring, addr(hints), result) if gaiResult != 0'i32: - when useWinVersion or defined(freertos): + when useWinVersion or defined(freertos) or defined(nuttx): raiseOSError(osLastError()) else: raiseOSError(osLastError(), $gai_strerror(gaiResult)) @@ -351,7 +352,7 @@ proc getSockDomain*(socket: SocketHandle): Domain = else: raise newException(IOError, "Unknown socket family in getSockDomain") -when not useNimNetLite: +when not useNimNetLite: proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = ## Searches the database from the beginning and finds the first entry for ## which the service name specified by `name` matches the s_name member diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 1dfef3b30..d3a767eed 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -100,7 +100,8 @@ export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol const useWinVersion = defined(windows) or defined(nimdoc) -const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) +const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or + defined(nuttx) const defineSsl = defined(ssl) or defined(nimdoc) when useWinVersion: diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index be5037fe2..ef8736cdf 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -37,7 +37,7 @@ const hasThreadSupport = compileOption("threads") and defined(threadsafe) const ioselSupportedPlatform* = defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or - defined(dragonfly) or + defined(dragonfly) or defined(nuttx) or (defined(linux) and not defined(android) and not defined(emscripten)) ## This constant is used to determine whether the destination platform is ## fully supported by `ioselectors` module. @@ -328,7 +328,7 @@ else: doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout) when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(solaris) or defined(zephyr) or defined(freertos): + defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx): template maxDescriptors*(): int = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is @@ -337,6 +337,9 @@ else: 16_700_000 elif defined(zephyr) or defined(freertos): FD_MAX + elif defined(nuttx): + # The maximum number of concurrently active UDP and TCP ports. + NACTIVESOCKETS else: var fdLim: RLimit var res = int(getrlimit(RLIMIT_NOFILE, fdLim)) @@ -360,5 +363,7 @@ else: include ioselects/ioselectors_select elif defined(zephyr): include ioselects/ioselectors_poll + elif defined(nuttx): + include ioselects/ioselectors_epoll else: include ioselects/ioselectors_poll diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim index 970d381c3..b45ce8a61 100644 --- a/lib/std/typedthreads.nim +++ b/lib/std/typedthreads.nim @@ -46,7 +46,8 @@ when defined(genode): import genode/env -when hasAllocStack or defined(zephyr) or defined(freertos) or defined(cpu16) or defined(cpu8): +when hasAllocStack or defined(zephyr) or defined(freertos) or defined(nuttx) or + defined(cpu16) or defined(cpu8): const nimThreadStackSize {.intdefine.} = 8192 nimThreadStackGuard {.intdefine.} = 128 diff --git a/lib/system.nim b/lib/system.nim index d8fafc0ef..af7e0e4c8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2688,6 +2688,7 @@ when notJSnotNims: not defined(nintendoswitch) and not defined(freertos) and not defined(zephyr) and + not defined(nuttx) and hostOS != "any" proc raiseEIO(msg: string) {.noinline, noreturn.} = diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index de22f7cbb..2162b234f 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -176,7 +176,7 @@ elif defined(genode): proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = raiseAssert("nimGetProcAddr not implemented") -elif defined(nintendoswitch) or defined(freertos) or defined(zephyr): +elif defined(nintendoswitch) or defined(freertos) or defined(zephyr) or defined(nuttx): proc nimUnloadLibrary(lib: LibHandle) = cstderr.rawWrite("nimUnLoadLibrary not implemented") cstderr.rawWrite("\n") From 03dd853815173bcf63f80ef03b5a4db7177453ec Mon Sep 17 00:00:00 2001 From: "Qinsi (James) ZHU" Date: Fri, 17 Feb 2023 01:12:48 +0800 Subject: [PATCH 4190/4254] add .replace() with callback to jsre (#21371) --- lib/js/jsre.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/js/jsre.nim b/lib/js/jsre.nim index 19888aaa9..69bd75c3b 100644 --- a/lib/js/jsre.nim +++ b/lib/js/jsre.nim @@ -34,6 +34,9 @@ func compile*(self: RegExp; pattern: cstring; flags: cstring) {.importjs: "#.com func replace*(pattern: cstring; self: RegExp; replacement: cstring): cstring {.importjs: "#.replace(#, #)".} ## Returns a new string with some or all matches of a pattern replaced by given replacement +func replace*(pattern: cstring, self: RegExp, cb: proc (args: varargs[cstring]): cstring): cstring {.importcpp.} + ## Returns a new string with some or all matches of a pattern replaced by given callback function + func split*(pattern: cstring; self: RegExp): seq[cstring] {.importjs: "(#.split(#) || [])".} ## Divides a string into an ordered list of substrings and returns the array @@ -88,5 +91,7 @@ runnableExamples: assert "do1ne".split(jsregex) == @["do".cstring, "ne".cstring] jsregex.compile(r"[lw]", r"i") assert "hello world".replace(jsregex,"X") == "heXlo world" + jsregex.compile(r"([a-z])\1*", r"g") + assert "abbcccdddd".replace(jsregex, proc (m: varargs[cstring]): cstring = ($m[0] & $(m.len)).cstring) == "a1b2c3d4" let digitsRegex: RegExp = newRegExp(r"\d") assert "foo".match(digitsRegex) == @[] From 13711b101d5ec101b3a2e18832d80e2b71eb3c80 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 17 Feb 2023 21:24:25 +1100 Subject: [PATCH 4191/4254] `std/xmltree` Add the type of the node when the assertion fails (#21383) Print the type of the node when the assertion fails This way the user actually knows what the type was instead of just knowing it failed --- lib/pure/xmltree.nim | 52 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index c3923ca50..82513bc98 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -70,6 +70,14 @@ const xmlHeader* = "\n" ## Header to use for complete XML output. +template expect(node: XmlNode, kind: set[XmlNodeKind]) = + ## Check the node's kind is within a set of values + assert node.k in kind, "Got " & $node.k + +template expect(node: XmlNode, kind: XmlNodeKind) = + ## Check the node's kind equals a value + assert node.k == kind, "Got " & $node.k + proc newXmlNode(kind: XmlNodeKind): XmlNode = ## Creates a new ``XmlNode``. result = XmlNode(k: kind) @@ -182,7 +190,7 @@ proc text*(n: XmlNode): lent string {.inline.} = assert $c == "" assert c.text == "my comment" - assert n.k in {xnText, xnComment, xnCData, xnEntity} + n.expect {xnText, xnComment, xnCData, xnEntity} result = n.fText proc `text=`*(n: XmlNode, text: sink string) {.inline.} = @@ -200,7 +208,7 @@ proc `text=`*(n: XmlNode, text: sink string) {.inline.} = e.text = "a new entity text" assert $e == "&a new entity text;" - assert n.k in {xnText, xnComment, xnCData, xnEntity} + n.expect {xnText, xnComment, xnCData, xnEntity} n.fText = text proc tag*(n: XmlNode): lent string {.inline.} = @@ -221,7 +229,7 @@ proc tag*(n: XmlNode): lent string {.inline.} = """ assert a.tag == "firstTag" - assert n.k == xnElement + n.expect xnElement result = n.fTag proc `tag=`*(n: XmlNode, tag: sink string) {.inline.} = @@ -244,7 +252,7 @@ proc `tag=`*(n: XmlNode, tag: sink string) {.inline.} = """ - assert n.k == xnElement + n.expect xnElement n.fTag = tag proc rawText*(n: XmlNode): string {.inline.} = @@ -315,7 +323,7 @@ proc add*(father, son: XmlNode) {.inline.} = f.add newEntity("my entity") assert $f == "my text&my entity;" - assert father.k == xnElement + father.expect xnElement add(father.s, son) proc add*(father: XmlNode, sons: openArray[XmlNode]) {.inline.} = @@ -335,7 +343,7 @@ proc add*(father: XmlNode, sons: openArray[XmlNode]) {.inline.} = f.add(@[newText("my text"), newElement("sonTag"), newEntity("my entity")]) assert $f == "my text&my entity;" - assert father.k == xnElement + father.expect xnElement add(father.s, sons) @@ -361,7 +369,7 @@ proc insert*(father, son: XmlNode, index: int) {.inline.} = """ - assert father.k == xnElement + father.expect xnElement if len(father.s) > index: insert(father.s, son, index) else: @@ -390,7 +398,7 @@ proc insert*(father: XmlNode, sons: openArray[XmlNode], index: int) {.inline.} = """ - assert father.k == xnElement + father.expect xnElement if len(father.s) > index: insert(father.s, sons, index) else: @@ -416,7 +424,7 @@ proc delete*(n: XmlNode, i: Natural) = """ - assert n.k == xnElement + n.expect xnElement n.s.delete(i) proc delete*(n: XmlNode, slice: Slice[int]) = @@ -439,7 +447,7 @@ proc delete*(n: XmlNode, slice: Slice[int]) = """ - assert n.k == xnElement + n.expect xnElement n.s.delete(slice) proc replace*(n: XmlNode, i: Natural, replacement: openArray[XmlNode]) = @@ -466,7 +474,7 @@ proc replace*(n: XmlNode, i: Natural, replacement: openArray[XmlNode]) = """ - assert n.k == xnElement + n.expect xnElement n.s.delete(i) n.s.insert(replacement, i) @@ -494,7 +502,7 @@ proc replace*(n: XmlNode, slice: Slice[int], replacement: openArray[XmlNode]) = """ - assert n.k == xnElement + n.expect xnElement n.s.delete(slice) n.s.insert(replacement, slice.a) @@ -525,12 +533,12 @@ proc `[]`*(n: XmlNode, i: int): XmlNode {.inline.} = assert $f[1] == "" assert $f[0] == "" - assert n.k == xnElement + n.expect xnElement result = n.s[i] proc `[]`*(n: var XmlNode, i: int): var XmlNode {.inline.} = ## Returns the `i`'th child of `n` so that it can be modified. - assert n.k == xnElement + n.expect xnElement result = n.s[i] proc clear*(n: var XmlNode) = @@ -582,12 +590,12 @@ iterator items*(n: XmlNode): XmlNode {.inline.} = # # &some entity; - assert n.k == xnElement + n.expect xnElement for i in 0 .. n.len-1: yield n[i] iterator mitems*(n: var XmlNode): var XmlNode {.inline.} = ## Iterates over all direct children of `n` so that they can be modified. - assert n.k == xnElement + n.expect xnElement for i in 0 .. n.len-1: yield n[i] proc toXmlAttributes*(keyValuePairs: varargs[tuple[key, @@ -619,7 +627,7 @@ proc attrs*(n: XmlNode): XmlAttributes {.inline.} = j.attrs = att assert j.attrs == att - assert n.k == xnElement + n.expect xnElement result = n.fAttr proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = @@ -636,7 +644,7 @@ proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = j.attrs = att assert j.attrs == att - assert n.k == xnElement + n.expect xnElement n.fAttr = attr proc attrsLen*(n: XmlNode): int {.inline.} = @@ -653,7 +661,7 @@ proc attrsLen*(n: XmlNode): int {.inline.} = j.attrs = att assert j.attrsLen == 2 - assert n.k == xnElement + n.expect xnElement if not isNil(n.fAttr): result = len(n.fAttr) proc attr*(n: XmlNode, name: string): string = @@ -671,7 +679,7 @@ proc attr*(n: XmlNode, name: string): string = assert j.attr("key1") == "first value" assert j.attr("key2") == "second value" - assert n.kind == xnElement + n.expect xnElement if n.attrs == nil: return "" return n.attrs.getOrDefault(name) @@ -834,7 +842,7 @@ proc child*(n: XmlNode, name: string): XmlNode = f.add newElement("thirdSon") assert $(f.child("secondSon")) == "" - assert n.kind == xnElement + n.expect xnElement for i in items(n): if i.kind == xnElement: if i.tag == name: @@ -870,7 +878,7 @@ proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode], a.findAll("BAD", s, caseInsensitive = true) assert $s == "@[c text, d text]" - assert n.k == xnElement + n.expect xnElement for child in n.items(): if child.k != xnElement: continue From 6b93db7070c984121e18b502d938d5e455d4ba70 Mon Sep 17 00:00:00 2001 From: Matt Haggard Date: Fri, 17 Feb 2023 05:25:15 -0500 Subject: [PATCH 4192/4254] Fix long link commands on macOS (v2) (#21382) Handle long link commands on macOS with a script, since ar does not support response files --- compiler/extccomp.nim | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 6515f6968..db97de65c 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -834,6 +834,15 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) = finally: removeFile(linkerArgs) +proc linkViaShellScript(conf: ConfigRef; cmd: string) = + let linkerScript = conf.projectName & "_" & "linkerScript.sh" + writeFile(linkerScript, cmd) + let shell = getEnv("SHELL") + try: + execLinkCmd(conf, shell & " " & linkerScript) + finally: + removeFile(linkerScript) + proc getObjFilePath(conf: ConfigRef, f: Cfile): string = if noAbsolutePaths(conf): f.obj.extractFilename else: f.obj.string @@ -856,9 +865,12 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) = # Windows's command line limit is about 8K (8191 characters) so C compilers on # Windows support a feature where the command line can be passed via ``@linkcmd`` # to them. - const MaxCmdLen = when defined(windows): 8_000 else: 32_000 + const MaxCmdLen = when defined(windows): 8_000 elif defined(macosx): 260_000 else: 32_000 if linkCmd.len > MaxCmdLen: - linkViaResponseFile(conf, linkCmd) + when defined(macosx): + linkViaShellScript(conf, linkCmd) + else: + linkViaResponseFile(conf, linkCmd) else: execLinkCmd(conf, linkCmd) From e896977bd16b2471e4aaaa363690622420e99acc Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 19 Feb 2023 14:49:19 +0800 Subject: [PATCH 4193/4254] closes #1072; add a test case (#21396) --- tests/specialops/tcallops.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/specialops/tcallops.nim b/tests/specialops/tcallops.nim index 0508a37a1..c541a0c1d 100644 --- a/tests/specialops/tcallops.nim +++ b/tests/specialops/tcallops.nim @@ -37,3 +37,13 @@ doAssert a(b) == "(12)" doAssert a.b(c) == `()`(b, a, c) doAssert (a.b)(c) == `()`(a.b, c) doAssert `()`(a.b, c) == `()`(`()`(b, a), c) + +block: # bug #1072 + var x: int + + proc foo(some:int):int = some + proc `()`(l,r:string): string = discard + + block: + var foo = 42 + doAssert x.foo == 0 From c66dc913cefb08722c4bf9885948e26be1285c3f Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 21 Feb 2023 07:19:46 +1100 Subject: [PATCH 4194/4254] Support new runtime with nim-gdb (#21400) * Add support for orc strings * Cleaned up testing script Enums now printing properly Merged both old and new strings into the one printer Moving onto sets which seem kinda difficult * Sets working Instead of trying to imitate how Nim represents enums, I just call the dollar proc for each enum value While this runs into problems if the user doesn't call the dollar proc anywhere, I believe its a decent tradeoff I've cleaned up the error message for when it cannot find dollar proc (Might add in proper message on how to fix) * Support sequences V2 runtime seems to have sequences that don't have a len (Guessing its some kind of short seq optimisation?) but I've rolled the implementation into normal sequences since the implementation is practically the same * Clean up test program so it isn't using diff Also don't redirect the first nim compile to /dev/null so that we can check for any compilation errors I found the diff to be annoying to read (Seeing as the test script already performs diffing) * Tables are now supported * Add colours to test output It was getting difficult to tell apart test output from GDB output so I added colour to better tell them apart * Both old and new runtime are working Set exit code in python test script so that this could possibly be added to the CI. Only issue is that it can be flaky (GDB crashes randomly for some reason) * Remove old code that was commented out If I need it later I'll just use git * Remove branch that never runs * Remove the old test output [skip ci] --- .../untestable/gdb/gdb_pretty_printer_test.py | 30 +- .../gdb/gdb_pretty_printer_test_output.txt | 3 - .../gdb/gdb_pretty_printer_test_program.nim | 28 +- .../gdb/gdb_pretty_printer_test_run.sh | 20 +- tools/nim-gdb.py | 386 ++++++------------ 5 files changed, 160 insertions(+), 307 deletions(-) delete mode 100644 tests/untestable/gdb/gdb_pretty_printer_test_output.txt mode change 100644 => 100755 tests/untestable/gdb/gdb_pretty_printer_test_run.sh diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index 8f0f88e85..d28d01a60 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -1,10 +1,13 @@ import gdb +import re +import sys # this test should test the gdb pretty printers of the nim # library. But be aware this test is not complete. It only tests the # command line version of gdb. It does not test anything for the # machine interface of gdb. This means if if this test passes gdb # frontends might still be broken. +gdb.execute("set python print-stack full") gdb.execute("source ../../../tools/nim-gdb.py") # debug all instances of the generic function `myDebug`, should be 14 gdb.execute("rbreak myDebug") @@ -16,7 +19,7 @@ outputs = [ '"meTwo"', '{meOne, meThree}', 'MyOtherEnum(1)', - '5', + '{MyOtherEnum(0), MyOtherEnum(2)}', 'array = {1, 2, 3, 4, 5}', 'seq(0, 0)', 'seq(0, 10)', @@ -28,13 +31,17 @@ outputs = [ '{a = 1, b = "some string"}' ] +argRegex = re.compile("^.* = (?:No suitable Nim \$ operator found for type: \w+\s*)*(.*)$") +# Remove this error message which can pop up +noSuitableRegex = re.compile("(No suitable Nim \$ operator found for type: \w+\s*)") + for i, expected in enumerate(outputs): - gdb.write(f"{i+1}) expecting: {expected}: ", gdb.STDLOG) + gdb.write(f"\x1b[38;5;105m{i+1}) expecting: {expected}: \x1b[0m", gdb.STDLOG) gdb.flush() - - functionSymbol = gdb.selected_frame().block().function - assert functionSymbol.line == 41, str(functionSymbol.line) - + currFrame = gdb.selected_frame() + functionSymbol = currFrame.block().function + assert functionSymbol.line == 24, str(functionSymbol.line) + raw = "" if i == 6: # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack gdb.execute("up") @@ -44,10 +51,13 @@ for i, expected in enumerate(outputs): gdb.execute("up") raw = gdb.parse_and_eval("myOtherArray") else: - raw = gdb.parse_and_eval("arg") - + rawArg = re.sub(noSuitableRegex, "", gdb.execute("info args", to_string = True)) + raw = rawArg.split("=", 1)[-1].strip() output = str(raw) - assert output == expected, "{0} : output: ({1}) != expected: ({2})".format(i, output, expected) - gdb.write(f"passed\n", gdb.STDLOG) + if output != expected: + gdb.write(f"\x1b[38;5;196m ({output}) != expected: ({expected})\x1b[0m\n", gdb.STDERR) + gdb.execute("quit 1") + else: + gdb.write("\x1b[38;5;34mpassed\x1b[0m\n", gdb.STDLOG) gdb.execute("continue") diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_output.txt b/tests/untestable/gdb/gdb_pretty_printer_test_output.txt deleted file mode 100644 index 73d26016f..000000000 --- a/tests/untestable/gdb/gdb_pretty_printer_test_output.txt +++ /dev/null @@ -1,3 +0,0 @@ -Loading Nim Runtime support. -NimEnumPrinter: lookup global symbol 'NTI__z9cu80OJCfNgw9bUdzn5ZEzw_ failed for tyEnum_MyOtherEnum__z9cu80OJCfNgw9bUdzn5ZEzw. -8 diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim index d2acdd282..b54fc1a7f 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim +++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim @@ -18,23 +18,6 @@ type MyObj = object a*: int b*: string - - # MyVariant = ref object - # id*: int - # case kind*: MyEnum - # of meOne: mInt*: int - # of meTwo, meThree: discard - # of meFour: - # moInt*: int - # babies*: seq[MyVariant] - # after: float - - # MyIntVariant = ref object - # stuff*: int - # case myKind*: range[0..32766] - # of 0: mFloat*: float - # of 2: mString*: string - # else: mBabies*: seq[MyIntVariant] var counter = 0 @@ -97,16 +80,7 @@ proc testProc(): void = var obj = MyObj(a: 1, b: "some string") myDebug(obj) #15 - # var varObj = MyVariant(id: 13, kind: meFour, moInt: 94, - # babies: @[MyVariant(id: 18, kind: meOne, mInt: 7, after: 1.0), - # MyVariant(id: 21, kind: meThree, after: 2.0)], - # after: 3.0) - # myDebug(varObj) #16 - - # var varObjInt = MyIntVariant(stuff: 5, myKind: 2, mString: "this is my sweet string") - # myDebug(varObjInt) #17 - - echo(counter) + assert counter == 15 testProc() diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_run.sh b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh old mode 100644 new mode 100755 index 525f54705..411c68435 --- a/tests/untestable/gdb/gdb_pretty_printer_test_run.sh +++ b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh @@ -1,15 +1,13 @@ #!/usr/bin/env bash -# Exit if anything fails set -e -#!/usr/bin/env bash # Compile the test project with fresh debug information. -nim c --debugger:native gdb_pretty_printer_test_program.nim &> /dev/null +nim c --debugger:native --mm:orc --out:gdbNew gdb_pretty_printer_test_program.nim +echo "Running new runtime tests..." # 2>&1 redirects stderr to stdout (all output in stdout) -# <(...) is a bash feature that makes the output of a command into a -# file handle. -# diff compares the two files, the expected output, and the file -# handle that is created by the execution of gdb. -diff ./gdb_pretty_printer_test_output.txt <(gdb -x gdb_pretty_printer_test.py --batch-silent --args gdb_pretty_printer_test_program 2>&1) -# The exit code of diff is forwarded as the exit code of this -# script. So when the comparison fails, the exit code of this script -# won't be 0. So this script should be embeddable in a test suite. +gdb -x gdb_pretty_printer_test.py --batch-silent --args gdbNew 2>&1 + + +# Do it all again, but with old runtime +nim c --debugger:native --mm:refc --out:gdbOld gdb_pretty_printer_test_program.nim &> /dev/null +echo "Running old runtime tests" +gdb -x gdb_pretty_printer_test.py --batch-silent --args gdbOld 2>&1 diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py index f35b9a033..e3af0dde6 100644 --- a/tools/nim-gdb.py +++ b/tools/nim-gdb.py @@ -16,6 +16,10 @@ def printErrorOnce(id, message): errorSet.add(id) gdb.write("printErrorOnce: " + message, gdb.STDERR) +def debugPrint(x): + gdb.write(str(x) + "\n", gdb.STDERR) + +NIM_STRING_TYPES = ["NimStringDesc", "NimStringV2"] ################################################################################ ##### Type pretty printers @@ -23,23 +27,28 @@ def printErrorOnce(id, message): type_hash_regex = re.compile("^([A-Za-z0-9]*)_([A-Za-z0-9]*)_+([A-Za-z0-9]*)$") +def getNimName(typ): + if m := type_hash_regex.match(typ): + return m.group(2) + return f"unknown <{typ}>" + def getNimRti(type_name): """ Return a ``gdb.Value`` object for the Nim Runtime Information of ``type_name``. """ # Get static const TNimType variable. This should be available for # every non trivial Nim type. m = type_hash_regex.match(type_name) - lookups = [ - "NTI" + m.group(2).lower() + "__" + m.group(3) + "_", - "NTI" + "__" + m.group(3) + "_", - "NTI" + m.group(2).replace("colon", "58").lower() + "__" + m.group(3) + "_" - ] if m: - for l in lookups: - try: - return gdb.parse_and_eval(l) - except: - pass + lookups = [ + "NTI" + m.group(2).lower() + "__" + m.group(3) + "_", + "NTI" + "__" + m.group(3) + "_", + "NTI" + m.group(2).replace("colon", "58").lower() + "__" + m.group(3) + "_" + ] + for l in lookups: + try: + return gdb.parse_and_eval(l) + except: + pass None def getNameFromNimRti(rti): @@ -68,7 +77,7 @@ class NimTypeRecognizer: 'NIM_BOOL': 'bool', - 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string' + 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string', 'NimStringV2': 'string' } # object_type_pattern = re.compile("^(\w*):ObjectType$") @@ -136,7 +145,7 @@ class DollarPrintFunction (gdb.Function): "Nim's equivalent of $ operator as a gdb function, available in expressions `print $dollar(myvalue)" dollar_functions = re.findall( - 'NimStringDesc \*(dollar__[A-z0-9_]+?)\(([^,)]*)\);', + '(?:NimStringDesc \*|NimStringV2)\s?(dollar__[A-z0-9_]+?)\(([^,)]*)\);', gdb.execute("info functions dollar__", True, True) ) @@ -146,12 +155,9 @@ class DollarPrintFunction (gdb.Function): @staticmethod def invoke_static(arg): - - if arg.type.code == gdb.TYPE_CODE_PTR and arg.type.target().name == "NimStringDesc": + if arg.type.code == gdb.TYPE_CODE_PTR and arg.type.target().name in NIM_STRING_TYPES: return arg - argTypeName = str(arg.type) - for func, arg_typ in DollarPrintFunction.dollar_functions: # this way of overload resolution cannot deal with type aliases, # therefore it won't find all overloads. @@ -163,7 +169,8 @@ class DollarPrintFunction (gdb.Function): func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value() return func_value(arg.address) - printErrorOnce(argTypeName, "No suitable Nim $ operator found for type: " + argTypeName + "\n") + + debugPrint(f"No suitable Nim $ operator found for type: {getNimName(argTypeName)}\n") return None def invoke(self, arg): @@ -184,11 +191,11 @@ class NimStringEqFunction (gdb.Function): @staticmethod def invoke_static(arg1,arg2): - if arg1.type.code == gdb.TYPE_CODE_PTR and arg1.type.target().name == "NimStringDesc": + if arg1.type.code == gdb.TYPE_CODE_PTR and arg1.type.target().name in NIM_STRING_TYPES: str1 = NimStringPrinter(arg1).to_string() else: str1 = arg1.string() - if arg2.type.code == gdb.TYPE_CODE_PTR and arg2.type.target().name == "NimStringDesc": + if arg2.type.code == gdb.TYPE_CODE_PTR and arg2.type.target().name in NIM_STRING_TYPES: str2 = NimStringPrinter(arg1).to_string() else: str2 = arg2.string() @@ -216,7 +223,7 @@ class DollarPrintCmd (gdb.Command): strValue = DollarPrintFunction.invoke_static(param) if strValue: gdb.write( - NimStringPrinter(strValue).to_string() + "\n", + str(NimStringPrinter(strValue)) + "\n", gdb.STDOUT ) @@ -254,7 +261,6 @@ class KochCmd (gdb.Command): os.path.dirname(os.path.dirname(__file__)), "koch") def invoke(self, argument, from_tty): - import os subprocess.run([self.binary] + gdb.string_to_argv(argument)) KochCmd() @@ -308,8 +314,14 @@ class NimBoolPrinter: ################################################################################ +def strFromLazy(strVal): + if isinstance(strVal, str): + return strVal + else: + return strVal.value().string("utf-8") + class NimStringPrinter: - pattern = re.compile(r'^NimStringDesc \*$') + pattern = re.compile(r'^(NimStringDesc \*|NimStringV2)$') def __init__(self, val): self.val = val @@ -319,11 +331,19 @@ class NimStringPrinter: def to_string(self): if self.val: - l = int(self.val['Sup']['len']) - return self.val['data'].lazy_string(encoding="utf-8", length=l) + if self.val.type.name == "NimStringV2": + l = int(self.val["len"]) + data = self.val["p"]["data"] + else: + l = int(self.val['Sup']['len']) + data = self.val["data"] + return data.lazy_string(encoding="utf-8", length=l) else: return "" + def __str__(self): + return strFromLazy(self.to_string()) + class NimRopePrinter: pattern = re.compile(r'^tyObject_RopeObj__([A-Za-z0-9]*) \*$') @@ -345,39 +365,11 @@ class NimRopePrinter: ################################################################################ -# proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = -# ## Return string representation for enumeration values -# var n = typ.node -# if ntfEnumHole notin typ.flags: -# let o = e - n.sons[0].offset -# if o >= 0 and o <% typ.node.len: -# return $n.sons[o].name -# else: -# # ugh we need a slow linear search: -# var s = n.sons -# for i in 0 .. n.len-1: -# if s[i].offset == e: -# return $s[i].name -# result = $e & " (invalid data!)" - def reprEnum(e, typ): - """ this is a port of the nim runtime function `reprEnum` to python """ + # Casts the value to the enum type and then calls the enum printer e = int(e) - n = typ["node"] - flags = int(typ["flags"]) - # 1 << 6 is {ntfEnumHole} - if ((1 << 6) & flags) == 0: - o = e - int(n["sons"][0]["offset"]) - if o >= 0 and 0 < int(n["len"]): - return n["sons"][o]["name"].string("utf-8", "ignore") - else: - # ugh we need a slow linear search: - s = n["sons"] - for i in range(0, int(n["len"])): - if int(s[i]["offset"]) == e: - return s[i]["name"].string("utf-8", "ignore") - - return str(e) + " (invalid data!)" + val = gdb.Value(e).cast(typ) + return strFromLazy(NimEnumPrinter(val).to_string()) def enumNti(typeNimName, idString): typeInfoName = "NTI" + typeNimName.lower() + "__" + idString + "_" @@ -389,6 +381,7 @@ def enumNti(typeNimName, idString): class NimEnumPrinter: pattern = re.compile(r'^tyEnum_([A-Za-z0-9]+)__([A-Za-z0-9]*)$') + enumReprProc = gdb.lookup_global_symbol("reprEnum", gdb.SYMBOL_FUNCTIONS_DOMAIN) def __init__(self, val): self.val = val @@ -397,14 +390,18 @@ class NimEnumPrinter: self.typeNimName = match.group(1) typeInfoName, self.nti = enumNti(self.typeNimName, match.group(2)) - if self.nti is None: - printErrorOnce(typeInfoName, f"NimEnumPrinter: lookup global symbol: '{typeInfoName}' failed for {typeName}.\n") - def to_string(self): - if self.nti: - arg0 = self.val - arg1 = self.nti.value(gdb.newest_frame()) - return reprEnum(arg0, arg1) + if NimEnumPrinter.enumReprProc and self.nti: + # Use the old runtimes enumRepr function. + # We call the Nim proc itself so that the implementation is correct + f = gdb.newest_frame() + # We need to strip the quotes so it looks like an enum instead of a string + reprProc = NimEnumPrinter.enumReprProc.value() + return str(reprProc(self.val, self.nti.value(f).address)).strip('"') + elif dollarResult := DollarPrintFunction.invoke_static(self.val): + # New runtime doesn't use enumRepr so we instead try and call the + # dollar function for it + return str(NimStringPrinter(dollarResult)) else: return self.typeNimName + "(" + str(int(self.val)) + ")" @@ -421,26 +418,20 @@ class NimSetPrinter: typeName = self.val.type.name match = self.pattern.match(typeName) self.typeNimName = match.group(1) - typeInfoName, self.nti = enumNti(self.typeNimName, match.group(2)) - - if self.nti is None: - printErrorOnce(typeInfoName, f"NimSetPrinter: lookup global symbol: '{typeInfoName}' failed for {typeName}.\n") def to_string(self): - if self.nti: - nti = self.nti.value(gdb.newest_frame()) - enumStrings = [] - val = int(self.val) - i = 0 - while val > 0: - if (val & 1) == 1: - enumStrings.append(reprEnum(i, nti)) - val = val >> 1 - i += 1 + # Remove the tySet from the type name + typ = gdb.lookup_type(self.val.type.name[6:]) + enumStrings = [] + val = int(self.val) + i = 0 + while val > 0: + if (val & 1) == 1: + enumStrings.append(reprEnum(i, typ)) + val = val >> 1 + i += 1 - return '{' + ', '.join(enumStrings) + '}' - else: - return str(int(self.val)) + return '{' + ', '.join(enumStrings) + '}' ################################################################################ @@ -472,41 +463,81 @@ class NimHashSetPrinter: ################################################################################ -class NimSeqPrinter: - # the pointer is explicity part of the type. So it is part of - # ``pattern``. - pattern = re.compile(r'^tySequence_\w* \*$') +class NimSeq: + # Wrapper around sequences. + # This handles the differences between old and new runtime def __init__(self, val): self.val = val + # new runtime has sequences on stack, old has them on heap + self.new = val.type.code != gdb.TYPE_CODE_PTR + if self.new: + # Some seqs are just the content and to save repeating ourselves we do + # handle them here. Only thing that needs to check this is the len/data getters + self.isContent = val.type.name.endswith("Content") + + def __bool__(self): + if self.new: + return self.val is not None + else: + return bool(self.val) + + def __len__(self): + if not self: + return 0 + if self.new: + if self.isContent: + return int(self.val["cap"]) + else: + return int(self.val["len"]) + else: + return self.val["Sup"]["len"] + + @property + def data(self): + if self.new: + if self.isContent: + return self.val["data"] + elif self.val["p"]: + return self.val["p"]["data"] + else: + return self.val["data"] + + @property + def cap(self): + if not self: + return 0 + if self.new: + if self.isContent: + return int(self.val["cap"]) + elif self.val["p"]: + return int(self.val["p"]["cap"]) + else: + return 0 + return int(self.val['Sup']['reserved']) + +class NimSeqPrinter: + pattern = re.compile(r'^tySequence_\w*\s?\*?$') + + def __init__(self, val): + self.val = NimSeq(val) + def display_hint(self): return 'array' def to_string(self): - len = 0 - cap = 0 - if self.val: - len = int(self.val['Sup']['len']) - cap = int(self.val['Sup']['reserved']) - - return 'seq({0}, {1})'.format(len, cap) + return f'seq({len(self.val)}, {self.val.cap})' def children(self): if self.val: val = self.val - valType = val.type - length = int(val['Sup']['len']) + length = len(val) if length <= 0: return - dataType = valType['data'].type - data = val['data'] - - if self.val.type.name is None: - dataType = valType['data'].type.target().pointer() - data = val['data'].cast(dataType) + data = val.data inaccessible = False for i in range(length): @@ -585,7 +616,7 @@ class NimTablePrinter: if self.val: counter = int(self.val['counter']) if self.val['data']: - capacity = int(self.val['data']['Sup']['len']) + capacity = NimSeq(self.val["data"]).cap return 'Table({0}, {1})'.format(counter, capacity) @@ -597,163 +628,6 @@ class NimTablePrinter: yield (idxStr + '.Field1', entry['Field1']) yield (idxStr + '.Field2', entry['Field2']) -################################################################ - -# this is untested, therefore disabled - -# class NimObjectPrinter: -# pattern = re.compile(r'^tyObject_([A-Za-z0-9]+)__(_?[A-Za-z0-9]*)(:? \*)?$') - -# def __init__(self, val): -# self.val = val -# self.valType = None -# self.valTypeNimName = None - -# def display_hint(self): -# return 'object' - -# def _determineValType(self): -# if self.valType is None: -# vt = self.val.type -# if vt.name is None: -# target = vt.target() -# self.valType = target.pointer() -# self.fields = target.fields() -# self.valTypeName = target.name -# self.isPointer = True -# else: -# self.valType = vt -# self.fields = vt.fields() -# self.valTypeName = vt.name -# self.isPointer = False - -# def to_string(self): -# if self.valTypeNimName is None: -# self._determineValType() -# match = self.pattern.match(self.valTypeName) -# self.valTypeNimName = match.group(1) - -# return self.valTypeNimName - -# def children(self): -# self._determineValType() -# if self.isPointer and int(self.val) == 0: -# return -# self.baseVal = self.val.referenced_value() if self.isPointer else self.val - -# for c in self.handleFields(self.baseVal, getNimRti(self.valTypeName)): -# yield c - -# def handleFields(self, currVal, rti, fields = None): -# rtiSons = None -# discField = (0, None) -# seenSup = False -# if fields is None: -# fields = self.fields -# try: # XXX: remove try after finished debugging this method -# for (i, field) in enumerate(fields): -# if field.name == "Sup": # inherited data -# seenSup = True -# baseRef = rti['base'] -# if baseRef: -# baseRti = baseRef.referenced_value() -# baseVal = currVal['Sup'] -# baseValType = baseVal.type -# if baseValType.name is None: -# baseValType = baseValType.target().pointer() -# baseValFields = baseValType.target().fields() -# else: -# baseValFields = baseValType.fields() - -# for c in self.handleFields(baseVal, baseRti, baseValFields): -# yield c -# else: -# if field.type.code == gdb.TYPE_CODE_UNION: -# # if not rtiSons: -# rtiNode = rti['node'].referenced_value() -# rtiSons = rtiNode['sons'] - -# if not rtiSons and int(rtiNode['len']) == 0 and str(rtiNode['name']) != "0x0": -# rtiSons = [rti['node']] # sons are dereferenced by the consumer - -# if not rtiSons: -# printErrorOnce(self.valTypeName, f"NimObjectPrinter: UNION field can't be displayed without RTI {self.valTypeName}, using fallback.\n") -# # yield (field.name, self.baseVal[field]) # XXX: this fallback seems wrong -# return # XXX: this should probably continue instead? - -# if int(rtiNode['len']) != 0 and str(rtiNode['name']) != "0x0": -# gdb.write(f"wtf IT HAPPENED {self.valTypeName}\n", gdb.STDERR) - -# discNode = rtiSons[discField[0]].referenced_value() -# if not discNode: -# raise ValueError("Can't find union discriminant field in object RTI") - -# discNodeLen = int(discNode['len']) -# discFieldVal = int(currVal[discField[1].name]) - -# unionNodeRef = None -# if discFieldVal < discNodeLen: -# unionNodeRef = discNode['sons'][discFieldVal] -# if not unionNodeRef: -# unionNodeRef = discNode['sons'][discNodeLen] - -# if not unionNodeRef: -# printErrorOnce(self.valTypeName + "no union node", f"wtf is up with sons {self.valTypeName} {unionNodeRef} {rtiNode['offset']} {discNode} {discFieldVal} {discNodeLen} {discField[1].name} {field.name} {field.type}\n") -# continue - -# unionNode = unionNodeRef.referenced_value() - -# fieldName = "" if field.name == None else field.name.lower() -# unionNodeName = "" if not unionNode['name'] else unionNode['name'].string("utf-8", "ignore") -# if not unionNodeName or unionNodeName.lower() != fieldName: -# unionFieldName = f"_{discField[1].name.lower()}_{int(rti['node'].referenced_value()['len'])}" -# gdb.write(f"wtf i: {i} union: {unionFieldName} field: {fieldName} type: {field.type.name} tag: {field.type.tag}\n", gdb.STDERR) -# else: -# unionFieldName = unionNodeName - -# if discNodeLen == 0: -# yield (unionFieldName, currVal[unionFieldName]) -# else: -# unionNodeLen = int(unionNode['len']) -# if unionNodeLen > 0: -# for u in range(unionNodeLen): -# un = unionNode['sons'][u].referenced_value()['name'].string("utf-8", "ignore") -# yield (un, currVal[unionFieldName][un]) -# else: -# yield(unionNodeName, currVal[unionFieldName]) -# else: -# discIndex = i - 1 if seenSup else i -# discField = (discIndex, field) # discriminant field is the last normal field -# yield (field.name, currVal[field.name]) -# except GeneratorExit: -# raise -# except: -# gdb.write(f"wtf {self.valTypeName} {i} fn: {field.name} df: {discField} rti: {rti} rtiNode: {rti['node'].referenced_value()} rtiSons: {rtiSons} {sys.exc_info()} {traceback.format_tb(sys.exc_info()[2], limit = 10)}\n", gdb.STDERR) -# gdb.write(f"wtf {self.valTypeName} {i} {field.name}\n", gdb.STDERR) - -# # seenSup = False -# # for (i, field) in enumerate(fields): -# # # if field.name: -# # # val = currVal[field.name] -# # # else: -# # # val = None -# # rtiNode = rti['node'].referenced_value() -# # rtiLen = int(rtiNode['len']) -# # if int(rtiNode['len']) > 0: -# # sons = rtiNode['sons'] -# # elif int(rti['len']) == 0 and str(rti['name']) != "0x0": -# # sons = [rti['node']] # sons are dereferenced by the consumer -# # sonsIdx = i - 1 if seenSup else i -# # s = sons[sonsIdx].referenced_value() -# # addr = int(currVal.address) -# # off = addr + int(rtiNode['offset']) -# # seenSup = seenSup or field.name == "Sup" - -# # gdb.write(f"wtf: i: {i} sonsIdx: {sonsIdx} field: {field.name} rtiLen: {rtiLen} rti: {rti} rtiNode: {rtiNode} isUnion: {field.type.code == gdb.TYPE_CODE_UNION} s: {s}\n", gdb.STDERR) - -# raise - - ################################################################################ class NimFrameFilter: From c73c76fdc62e76a9e36e2595b9854a6f0cb9e904 Mon Sep 17 00:00:00 2001 From: Century Systems Date: Tue, 21 Feb 2023 11:38:25 +0900 Subject: [PATCH 4195/4254] NuttX added supports getrlimit(RLIMIT_NOFILE), so remove NuttX specific codes. (#21385) async: NuttX added supports getrlimit(RLIMIT_NOFILE), so remove NuttX-specific codes. Signed-off-by: Takeyoshi Kikuchi --- lib/posix/posix_other_consts.nim | 3 --- lib/pure/asyncdispatch.nim | 3 --- lib/pure/selectors.nim | 3 --- 3 files changed, 9 deletions(-) diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 4b1644f20..506c92158 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -473,9 +473,6 @@ var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint when defined(zephyr): # Zephyr specific hardcoded value var FD_MAX* {.importc: "CONFIG_POSIX_MAX_FDS ", header: "".}: cint -elif defined(nuttx): - # NuttX specific user configuration value - var NACTIVESOCKETS* {.importc: "CONFIG_NET_NACTIVESOCKETS", header: "".}: cint # var MSG_CTRUNC* {.importc: "MSG_CTRUNC", header: "".}: cint diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 64100afa7..2bfa8587c 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -2033,9 +2033,6 @@ when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or result = 16_700_000 elif defined(zephyr) or defined(freertos): result = FD_MAX - elif defined(nuttx): - # The maximum number of concurrently active UDP and TCP ports. - result = NACTIVESOCKETS else: var fdLim: RLimit if getrlimit(RLIMIT_NOFILE, fdLim) < 0: diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index ef8736cdf..b15a25a1d 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -337,9 +337,6 @@ else: 16_700_000 elif defined(zephyr) or defined(freertos): FD_MAX - elif defined(nuttx): - # The maximum number of concurrently active UDP and TCP ports. - NACTIVESOCKETS else: var fdLim: RLimit var res = int(getrlimit(RLIMIT_NOFILE, fdLim)) From f7bd2088aa5fe970902d4cafc94933354fdec8a7 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:27:42 +0800 Subject: [PATCH 4196/4254] corrects the linkerexe of riscv64 in config (#21292) --- config/nim.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/nim.cfg b/config/nim.cfg index f7b7c119a..973de077a 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -39,7 +39,7 @@ arm64.linux.gcc.linkerexe = "aarch64-linux-gnu-gcc" riscv32.linux.gcc.exe = "riscv64-linux-gnu-gcc" riscv32.linux.gcc.linkerexe = "riscv64-linux-gnu-gcc" riscv64.linux.gcc.exe = "riscv64-linux-gnu-gcc" -riscv64.linux.gcc.linkerexe = "arm-linux-gnueabihf-gcc" +riscv64.linux.gcc.linkerexe = "riscv64-linux-gnu-gcc" # For OpenWRT, you will also need to adjust PATH to point to your toolchain. mips.linux.gcc.exe = "mips-openwrt-linux-gcc" From ffd6bc87495ede82f9a8086d38c3348a40b11672 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:58:45 +0800 Subject: [PATCH 4197/4254] csources_v2 can build the ORC-booted compiler; building now uses strict mode (#21411) * csources_v2 can build the ORC-booted compiler; building now uses strict mode * test booting in refc --- koch.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index fa498e017..52378e43f 100644 --- a/koch.nim +++ b/koch.nim @@ -530,8 +530,7 @@ proc runCI(cmd: string) = # boot without -d:nimHasLibFFI to make sure this still works # `--lib:lib` is needed for bootstrap on openbsd, for reasons described in # https://github.com/nim-lang/Nim/pull/14291 (`getAppFilename` bugsfor older nim on openbsd). - kochExecFold("Boot in release mode", "boot -d:release --gc:refc -d:nimStrictMode --lib:lib") - kochExecFold("Boot Nim ORC", "boot -d:release --lib:lib") + kochExecFold("Boot Nim ORC", "boot -d:release -d:nimStrictMode --lib:lib") when false: # debugging: when you need to run only 1 test in CI, use something like this: execFold("debugging test", "nim r tests/stdlib/tosproc.nim") @@ -587,6 +586,9 @@ proc runCI(cmd: string) = execFold("Run atlas tests", "nim c -r -d:atlasTests tools/atlas/atlas.nim clone https://github.com/disruptek/balls") + kochExecFold("Testing booting in refc", "boot -d:release --mm:refc -d:nimStrictMode --lib:lib") + + proc testUnixInstall(cmdLineRest: string) = csource("-d:danger" & cmdLineRest) xz(false, cmdLineRest) From bdc850916fb5d23fa4b9282309985e0fdfb0db36 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 21 Feb 2023 18:46:50 +0800 Subject: [PATCH 4198/4254] improve invalid module names errors (#21412) I have seen these questions: "Why I got an invalid module name errors?". To eliminate this kind of questions, We might improve th error messages. Though, the question might evolve into "What is a valid Nim identifier", which should be more searchable on the Internet. --- compiler/modules.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/modules.nim b/compiler/modules.nim index 7f6ff8622..838a89d83 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -38,7 +38,8 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = name: getModuleIdent(graph, filename), info: newLineInfo(fileIdx, 1, 1)) if not isNimIdentifier(result.name.s): - rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s) + rawMessage(graph.config, errGenerated, "invalid module name: '" & result.name.s & + "'; a module name must be a valid Nim identifier.") partialInitModule(result, graph, fileIdx, filename) graph.registerModule(result) From e54d3cc418f9eab750563aa771070374d559fe57 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 21 Feb 2023 22:02:42 +1100 Subject: [PATCH 4199/4254] Support tuples in nim-gdb (#21410) * Support for printing tuple types * Add test of printing a tuple * Add support for printing tuples in GDB * Forgot to [skip ci] --- .../untestable/gdb/gdb_pretty_printer_test.py | 3 ++- .../gdb/gdb_pretty_printer_test_program.nim | 5 +++- tools/nim-gdb.py | 25 ++++++++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index d28d01a60..a96df9992 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -28,7 +28,8 @@ outputs = [ 'seq(3, 3) = {"one", "two", "three"}', 'Table(3, 64) = {[4] = "four", [5] = "five", [6] = "six"}', 'Table(3, 8) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', - '{a = 1, b = "some string"}' + '{a = 1, b = "some string"}', + '("hello", 42)' ] argRegex = re.compile("^.* = (?:No suitable Nim \$ operator found for type: \w+\s*)*(.*)$") diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim index b54fc1a7f..163c99860 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim +++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim @@ -80,7 +80,10 @@ proc testProc(): void = var obj = MyObj(a: 1, b: "some string") myDebug(obj) #15 - assert counter == 15 + var tup = ("hello", 42) + myDebug(tup) # 16 + + assert counter == 16 testProc() diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py index e3af0dde6..1050197c9 100644 --- a/tools/nim-gdb.py +++ b/tools/nim-gdb.py @@ -112,6 +112,12 @@ class NimTypeRecognizer: result = self.type_map_static.get(tname, None) if result: return result + elif tname.startswith("tyEnum_"): + return getNimName(tname) + elif tname.startswith("tyTuple__"): + # We make the name be the field types (Just like in Nim) + fields = ", ".join([self.recognize(field.type) for field in type_obj.fields()]) + return f"({fields})" rti = getNimRti(tname) if rti: @@ -154,7 +160,7 @@ class DollarPrintFunction (gdb.Function): @staticmethod - def invoke_static(arg): + def invoke_static(arg, ignore_errors = False): if arg.type.code == gdb.TYPE_CODE_PTR and arg.type.target().name in NIM_STRING_TYPES: return arg argTypeName = str(arg.type) @@ -169,8 +175,8 @@ class DollarPrintFunction (gdb.Function): func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value() return func_value(arg.address) - - debugPrint(f"No suitable Nim $ operator found for type: {getNimName(argTypeName)}\n") + if not ignore_errors: + debugPrint(f"No suitable Nim $ operator found for type: {getNimName(argTypeName)}\n") return None def invoke(self, arg): @@ -630,6 +636,19 @@ class NimTablePrinter: ################################################################################ +class NimTuplePrinter: + pattern = re.compile(r"^tyTuple__([A-Za-z0-9]*)") + + def __init__(self, val): + self.val = val + + def to_string(self): + # We don't have field names so just print out the tuple as if it was anonymous + tupleValues = [str(self.val[field.name]) for field in self.val.type.fields()] + return f"({', '.join(tupleValues)})" + +################################################################################ + class NimFrameFilter: def __init__(self): self.name = "nim-frame-filter" From 6d423f1856d086ea9e6b0995e3e5f831f4f89aa6 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 21 Feb 2023 22:04:27 +1100 Subject: [PATCH 4200/4254] Make `Time` work with `std/strformat` (#21409) * Add test case * Remove formatValue template for `Time` It didn't handle empty specifier correctly which caused it to be blank with strformat --- lib/pure/times.nim | 6 +----- tests/stdlib/t21406.nim | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 tests/stdlib/t21406.nim diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 3327b2510..70af466d9 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -2109,7 +2109,7 @@ proc format*(dt: DateTime, f: static[string]): string {.raises: [].} = const f2 = initTimeFormat(f) result = dt.format(f2) -proc formatValue*(result: var string; value: DateTime, specifier: string) = +proc formatValue*(result: var string; value: DateTime | Time, specifier: string) = ## adapter for strformat. Not intended to be called directly. result.add format(value, if specifier.len == 0: "yyyy-MM-dd'T'HH:mm:sszzz" else: specifier) @@ -2133,10 +2133,6 @@ proc format*(time: Time, f: static[string], zone: Timezone = local()): string const f2 = initTimeFormat(f) result = time.inZone(zone).format(f2) -template formatValue*(result: var string; value: Time, specifier: string) = - ## adapter for `strformat`. Not intended to be called directly. - result.add format(value, specifier) - proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), loc: DateTimeLocale = DefaultLocale): DateTime {.raises: [TimeParseError, Defect].} = diff --git a/tests/stdlib/t21406.nim b/tests/stdlib/t21406.nim new file mode 100644 index 000000000..5b96227ce --- /dev/null +++ b/tests/stdlib/t21406.nim @@ -0,0 +1,5 @@ +import std/[times, strformat] +import std/assertions + +doAssert fmt"{getTime()}" == $getTime() +doAssert fmt"{now()}" == $now() From de65b380edb0fe256054e217a1e6e64a6bb97527 Mon Sep 17 00:00:00 2001 From: Ecorous <49562894+Ecorous@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:14:41 +0000 Subject: [PATCH 4201/4254] Add `getDataDir` proc (#21408) * Add getDataDir() * Update lib/std/private/osappdirs.nim --------- Co-authored-by: Andreas Rumpf --- lib/std/private/osappdirs.nim | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/std/private/osappdirs.nim b/lib/std/private/osappdirs.nim index 581b511ff..07a6809bb 100644 --- a/lib/std/private/osappdirs.nim +++ b/lib/std/private/osappdirs.nim @@ -12,6 +12,7 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", ## for the convenience of processing paths coming from user configuration files. ## ## See also: + ## * `getDataDir proc`_ ## * `getConfigDir proc`_ ## * `getTempDir proc`_ ## * `expandTilde proc`_ @@ -24,6 +25,30 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", when defined(windows): return getEnv("USERPROFILE") & "\\" else: return getEnv("HOME") & "/" +proc getDataDir*(): string {.rtl, extern: "nos$1" + tags: [ReadEnvEffect, ReadIOEffect].} = + ## Returns the data directory of the current user for applications. + ## + ## On non-Windows OSs, this proc conforms to the XDG Base Directory + ## spec. Thus, this proc returns the value of the `XDG_DATA_HOME` environment + ## variable if it is set, otherwise it returns the default configuration + ## directory ("~/.local/share" or "~/Library/Application Support" on macOS). + ## + ## See also: + ## * `getHomeDir proc`_ + ## * `getConfigDir proc`_ + ## * `getTempDir proc`_ + ## * `expandTilde proc`_ + ## * `getCurrentDir proc`_ + ## * `setCurrentDir proc`_ + when defined(windows): + result = getEnv("APPDATA") + elif defined(macosx): + result = getEnv("XDG_DATA_HOME", getEnv("HOME") / "Library" / "Application Support") + else: + result = getEnv("XDG_DATA_HOME", getEnv("HOME") / ".local" / "share") + result.normalizePathEnd(trailingSep = true) + proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the config directory of the current user for applications. @@ -38,6 +63,7 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## ## See also: ## * `getHomeDir proc`_ + ## * `getDataDir proc`_ ## * `getTempDir proc`_ ## * `expandTilde proc`_ ## * `getCurrentDir proc`_ @@ -63,6 +89,7 @@ proc getCacheDir*(): string = ## * `getHomeDir proc`_ ## * `getTempDir proc`_ ## * `getConfigDir proc`_ + ## * `getDataDir proc`_ # follows https://crates.io/crates/platform-dirs when defined(windows): result = getEnv("LOCALAPPDATA") From 0a45543cc1e8a2e8db59eaed864cd908726bf48d Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 21 Feb 2023 22:27:12 +1100 Subject: [PATCH 4202/4254] Specify that address is taken when converter takes a var parameter (#21391) * Add test case * closes #21247 Add the sfAddrTaken flag to var parameters in converters This allows the JS backend to properly pass the parameter as a fat pointer --- compiler/sigmatch.nim | 1 + tests/js/t21247.nim | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/js/t21247.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 0dbd5e5f1..f8c7fa870 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1980,6 +1980,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c) elif src.kind in {tyVar}: # Analyse the converter return type + arg.sym.flags.incl sfAddrTaken param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1]) param.add copyTree(arg) else: diff --git a/tests/js/t21247.nim b/tests/js/t21247.nim new file mode 100644 index 000000000..5b38787b3 --- /dev/null +++ b/tests/js/t21247.nim @@ -0,0 +1,15 @@ +import std/typetraits + +type + QueryParams* = distinct seq[(string, string)] + +converter toBase*(params: var QueryParams): var seq[(string, string)] = + params.distinctBase + +proc foo(): QueryParams = + # Issue was that the implicit converter call didn't say that it took the + # address of the parameter it was converting. This led to the parameter not being + # passed as a fat pointer which toBase expected + result.add(("hello", "world")) + +assert foo().distinctBase() == @[("hello", "world")] From a3603c8a6ee4a8ae147d2f2099a18395e819a8a3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 22 Feb 2023 06:42:28 +0800 Subject: [PATCH 4203/4254] saves one unnecessary compare which is also a small regression (#21413) saves one unnecessary compare which is also a sall regression follow up https://github.com/nim-lang/Nim/commit/d30c6419a051a815e3fdb354ac79522f17e55bda --- compiler/passes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/passes.nim b/compiler/passes.nim index a8f67300c..c20763fc3 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -143,7 +143,7 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; while true: openParser(p, fileIdx, s, graph.cache, graph.config) - if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"): + if (not belongsToStdlib(graph, module)) or module.name.s == "distros": # XXX what about caching? no processing then? what if I change the # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only From 64a788cafb287ace8c63f5e86cb84c520eab3f2a Mon Sep 17 00:00:00 2001 From: Benji York Date: Wed, 22 Feb 2023 05:12:10 -0600 Subject: [PATCH 4204/4254] Fix a couple of small keyword issues. (#21416) In this section of the manual, "if" should be enclosed in backticks and "elif" should be lower case. --- doc/manual.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index 779e99186..ef790c362 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -3574,8 +3574,8 @@ Example: var y = if x > 8: 9 else: 10 ``` -An if expression always results in a value, so the `else` part is -required. `Elif` parts are also allowed. +An `if` expression always results in a value, so the `else` part is +required. `elif` parts are also allowed. When expression --------------- From ab1d4a5d58af8452b26f57f244bcd0d39b409c5e Mon Sep 17 00:00:00 2001 From: Century Systems Date: Thu, 23 Feb 2023 03:53:04 +0900 Subject: [PATCH 4205/4254] ioselectors_epoll: for NuttX, limit initial numFD to configured value. (#21421) ioselectors: ioselectors_epoll: for NuttX, limit initial numFD to configured value. In the NuttX build config, there is a setting called "FS_NEPOLL_DESCRIPTORS". -------- config FS_NEPOLL_DESCRIPTORS int "Maximum number of default epoll descriptors for epoll_create1(2)" default 8 ---help--- The maximum number of default epoll descriptors for epoll_create1(2) -------- For NuttX, change the number of fd arrays allocated by newSelector() to that value. Signed-off-by: Takeyoshi Kikuchi --- lib/posix/posix_other_consts.nim | 3 +++ lib/pure/ioselects/ioselectors_epoll.nim | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 506c92158..08069fe9a 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -750,3 +750,6 @@ var SEEK_SET* {.importc: "SEEK_SET", header: "".}: cint var SEEK_CUR* {.importc: "SEEK_CUR", header: "".}: cint var SEEK_END* {.importc: "SEEK_END", header: "".}: cint +# +when defined(nuttx): + var NEPOLL_MAX* {.importc: "CONFIG_FS_NEPOLL_DESCRIPTORS", header: "".}: cint diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 8526eb8a3..08cb6ed74 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -72,11 +72,16 @@ type SelectEvent* = ptr SelectEventImpl proc newSelector*[T](): Selector[T] = + proc initialNumFD(): int {.inline.} = + when defined(nuttx): + result = NEPOLL_MAX + else: + result = 1024 # Retrieve the maximum fd count (for current OS) via getrlimit() var maxFD = maxDescriptors() doAssert(maxFD > 0) # Start with a reasonable size, checkFd() will grow this on demand - const numFD = 1024 + let numFD = initialNumFD() var epollFD = epoll_create1(O_CLOEXEC) if epollFD < 0: From fdd75202576634f1fb8c7948d6031e34af9ea67e Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 22 Feb 2023 13:54:04 -0500 Subject: [PATCH 4206/4254] Fix the TODO portion of recently added `posix_fallocate` on OS X. (#21387) --- lib/posix/posix.nim | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index aee9308a6..07652c64d 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -198,9 +198,24 @@ proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {. proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "".} when defined(osx): # 2001 POSIX evidently does not concern Apple + type FStore {.importc: "fstore_t", header: "", bycopy.} = object + fst_flags: uint32 ## IN: flags word + fst_posmode: cint ## IN: indicates offset field + fst_offset, ## IN: start of the region + fst_length, ## IN: size of the region + fst_bytesalloc: Off ## OUT: number of bytes allocated + var F_PEOFPOSMODE {.importc, header: "".}: cint + var F_ALLOCATEALL {.importc, header: "".}: uint32 + var F_PREALLOCATE {.importc, header: "".}: cint proc posix_fallocate*(a1: cint, a2, a3: Off): cint = - ftruncate(a1, a2 + a3) # Set size to off + len, max offset -else: # TODO: Use fcntl(fd, F_PREALLOCATE, ..) above + var fst = FStore(fst_flags: F_ALLOCATEALL, fst_posmode: F_PEOFPOSMODE, + fst_offset: a2, fst_length: a3) + # Must also call ftruncate to match what POSIX does. Unlike posix_fallocate, + # this can shrink files. Could guard w/getFileSize, but caller likely knows + # present size & has no good reason to call this unless it is growing. + if fcntl(a1, F_PREALLOCATE, fst.addr) != cint(-1): ftruncate(a1, a2 + a3) + else: cint(-1) +else: proc posix_fallocate*(a1: cint, a2, a3: Off): cint {. importc, header: "".} From 38f876dd484fc1a3ce44788b1ed9601eea8619f6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 23 Feb 2023 03:34:20 +0800 Subject: [PATCH 4207/4254] fixes #19795; fixes #11852; fixes #19974; remove parsing pipeline, Nim now parses the whole module at one time (#21379) * fixes #19795; remove parse pipeline * isScript * fixes nimscriptapi * don't touch reorder * check script * fixes tests * it seems implicit imports of system cause troubles * access the first child of `nkStmtList` * ignore comments * minor messages * perhaps increases hloLoopDetector * the module is a stmtList, which changes the errors * fixes nimdoc * fixes tlinter * fixes nim secret tests * fixes arc_misc * fixes nim secret tests again * safe; fixes one more test * GlobalError is the root cause too * fixes parsing errors * put emit types to the cfsForwardTypes section * fixes #11852; `{.push checks:off}` now works in procs * disable navigator * fixes nimdoc * add tests for JS * fixes nimsuggest --- compiler/backendpragmas.nim | 25 ++++++ compiler/ccgstmts.nim | 10 ++- compiler/cgen.nim | 2 +- compiler/cgendata.nim | 1 + compiler/jsgen.nim | 10 ++- compiler/passes.nim | 7 +- compiler/pragmas.nim | 2 +- compiler/sem.nim | 6 ++ .../expected/subdir/subdir_b/utils.idx | 2 +- nimsuggest/tests/tchk1.nim | 2 +- tests/arc/tarcmisc.nim | 4 +- .../tdont_return_unowned_from_owned.nim | 35 ++++---- tests/errmsgs/t8064.nim | 8 +- tests/misc/tnoforward.nim | 1 + tests/misc/trunner.nim | 4 +- tests/modules/t8665.nim | 1 + tests/modules/treorder.nim | 2 +- tests/navigator/tincludefile.nim | 2 +- tests/navigator/tnav1.nim | 2 +- tests/nimdoc/trunnableexamples.nim | 4 +- .../{overflw => overflow}/tdistinct_range.nim | 0 tests/overflow/toverflow.nim | 82 +++++++++++++++++++ .../toverflw2.nim => overflow/toverflow2.nim} | 0 .../toverflow_reorder.nim} | 4 +- tests/{overflw => overflow}/tovfint.nim | 0 tests/parser/t20922.nim | 29 ++----- tests/pragmas/tpush.nim | 12 +++ tests/pragmas/treorder.nim | 1 + tests/proc/t19795.nim | 19 +++++ tests/tools/tlinter.nim | 2 +- tests/trmacros/tor.nim | 20 +++-- 31 files changed, 227 insertions(+), 72 deletions(-) create mode 100644 compiler/backendpragmas.nim rename tests/{overflw => overflow}/tdistinct_range.nim (100%) create mode 100644 tests/overflow/toverflow.nim rename tests/{overflw/toverflw2.nim => overflow/toverflow2.nim} (100%) rename tests/{overflw/toverflw.nim => overflow/toverflow_reorder.nim} (96%) rename tests/{overflw => overflow}/tovfint.nim (100%) create mode 100644 tests/proc/t19795.nim diff --git a/compiler/backendpragmas.nim b/compiler/backendpragmas.nim new file mode 100644 index 000000000..b18644810 --- /dev/null +++ b/compiler/backendpragmas.nim @@ -0,0 +1,25 @@ +import pragmas, options, ast, trees + +proc pushBackendOption(optionsStack: var seq[TOptions], options: var TOptions) = + optionsStack.add options + +proc popBackendOption(optionsStack: var seq[TOptions], options: var TOptions) = + options = optionsStack[^1] + optionsStack.setLen(optionsStack.len-1) + +proc processPushBackendOption*(optionsStack: var seq[TOptions], options: var TOptions, + n: PNode, start: int) = + pushBackendOption(optionsStack, options) + for i in start..= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: let sec = n[0].strVal - if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes + if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND elif sec.startsWith("/*VARSECTION*/"): result = cfsVars elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders @@ -1555,9 +1554,14 @@ proc genEmit(p: BProc, t: PNode) = line(p, cpsStmts, s) proc genPragma(p: BProc, n: PNode) = - for it in n.sons: + for i in 0.. 0 if we are within a loop splitDecls*: int # > 0 if we are in some context for C++ that diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 60399d3cd..572d19b13 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -33,7 +33,7 @@ import nversion, msgs, idents, types, ropes, passes, ccgutils, wordrecg, renderer, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - transf, injectdestructors, sourcemap, astmsgs + transf, injectdestructors, sourcemap, astmsgs, backendpragmas import json, sets, math, tables, intsets import strutils except addf @@ -98,6 +98,7 @@ type prc: PSym globals, locals, body: Rope options: TOptions + optionsStack: seq[TOptions] module: BModule g: PGlobals generatedParamCopies: IntSet @@ -2557,9 +2558,14 @@ proc genStmt(p: PProc, n: PNode) = if r.res != "": lineF(p, "$#;$n", [r.res]) proc genPragma(p: PProc, n: PNode) = - for it in n.sons: + for i in 0..> (toplevel): import(dirty): tests/tchk1.nim [Processing]";;0 chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but got \'keyword template\'";;0 chk;;skUnknown;;;;Error;;$file;;14;;0;;"nestable statement requires indentation";;0 -chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0 chk;;skUnknown;;;;Error;;$file;;17;;0;;"invalid indentation";;0 +chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0 chk;;skUnknown;;;;Hint;;$file;;12;;9;;"\'foo\' is declared but not used [XDeclaredButNotUsed]";;0 chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'main\' is declared but not used [XDeclaredButNotUsed]";;0 """ diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 6435f5e94..a03da6211 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -27,14 +27,14 @@ new line after - @['a'] finalizer aaaaa hello -ok true copying 123 42 -closed +ok destroying variable: 20 destroying variable: 10 +closed ''' cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file" """ diff --git a/tests/destructor/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim index d27626dea..ffe87cd76 100644 --- a/tests/destructor/tdont_return_unowned_from_owned.nim +++ b/tests/destructor/tdont_return_unowned_from_owned.nim @@ -1,9 +1,12 @@ discard """ cmd: "nim check --newruntime --hints:off $file" nimout: ''' -tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(39, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(42, 6) Error: type mismatch: got +tdont_return_unowned_from_owned.nim(26, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(27, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(31, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type +tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(46, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(49, 6) Error: type mismatch: got but expected one of: proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) first type mismatch at position: 2 @@ -11,17 +14,21 @@ proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) 2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them expression: new(result) -tdont_return_unowned_from_owned.nim(42, 6) Error: illformed AST: -tdont_return_unowned_from_owned.nim(50, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(51, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(55, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type +tdont_return_unowned_from_owned.nim(49, 6) Error: illformed AST: ''' - errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type" + errormsg: "illformed AST:" """ +proc testA(result: var (RootRef, RootRef)) = + let r: owned RootRef = RootRef() + result[0] = r + result[1] = RootRef() +proc testB(): RootRef = + let r: owned RootRef = RootRef() + result = r @@ -39,17 +46,11 @@ proc newObjB(): Obj = result = Obj() proc newObjC(): Obj = - new(result) + new(result) # illFormedAst raises GlobalError, + # without pipeline parsing, it needs to placed at the end + # in case that it disturbs other errors let a = newObjA() let b = newObjB() let c = newObjC() -proc testA(result: var (RootRef, RootRef)) = - let r: owned RootRef = RootRef() - result[0] = r - result[1] = RootRef() - -proc testB(): RootRef = - let r: owned RootRef = RootRef() - result = r diff --git a/tests/errmsgs/t8064.nim b/tests/errmsgs/t8064.nim index 10bb86299..e7941e36a 100644 --- a/tests/errmsgs/t8064.nim +++ b/tests/errmsgs/t8064.nim @@ -1,6 +1,8 @@ +import tables + +values + + discard """ errormsg: "expression has no type: values" """ -import tables - -values \ No newline at end of file diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim index b6a71897a..0d9b40c83 100644 --- a/tests/misc/tnoforward.nim +++ b/tests/misc/tnoforward.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--experimental:codeReordering" output: "10" """ diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 7fb437ce3..aca19f72d 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -342,8 +342,8 @@ tests/newconfig/bar/mfoo.nims""".splitLines when not defined(windows): check3 lines.len == 5 check3 lines[0].isDots - check3 lines[1].dup(removePrefix(">>> ")) == "3" # prompt depends on `nimUseLinenoise` - check3 lines[2].isDots + # check3 lines[1].isDots # todo nim secret might use parsing pipeline + check3 lines[2].dup(removePrefix(">>> ")) == "3" # prompt depends on `nimUseLinenoise` check3 lines[3] == "ab" check3 lines[4] == "" else: diff --git a/tests/modules/t8665.nim b/tests/modules/t8665.nim index 74d31452f..7cfdbdb00 100644 --- a/tests/modules/t8665.nim +++ b/tests/modules/t8665.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--experimental:codeReordering" action: compile """ diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim index c81715cd8..626d9684b 100644 --- a/tests/modules/treorder.nim +++ b/tests/modules/treorder.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim -d:testdef $target $file" + matrix: "--experimental:codeReordering -d:testdef" output: '''works 34 34 defined diff --git a/tests/navigator/tincludefile.nim b/tests/navigator/tincludefile.nim index f35ab2ec9..a913d0736 100644 --- a/tests/navigator/tincludefile.nim +++ b/tests/navigator/tincludefile.nim @@ -1,4 +1,5 @@ discard """ + disabled: true cmd: "nim check $options --defusages:$file,12,7 $file" nimout: '''def tincludefile_temp.nim(11, 10) usage tincludefile_temp.nim(12, 8) @@ -7,7 +8,6 @@ usage tincludefile_temp.nim(12, 8) - proc foo(x: int) = echo x diff --git a/tests/navigator/tnav1.nim b/tests/navigator/tnav1.nim index b6bbdbf19..e76c921f3 100644 --- a/tests/navigator/tnav1.nim +++ b/tests/navigator/tnav1.nim @@ -1,11 +1,11 @@ discard """ + disabled: true cmd: "nim check $options --defusages:$file,12,7 $file" nimout: '''def tnav1_temp.nim(11, 10) usage tnav1_temp.nim(12, 8) ''' """ - import std / [times] proc foo(x: int) = diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim index c88d8fa3f..1188cdd1b 100644 --- a/tests/nimdoc/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -7,7 +7,6 @@ foo1 foo2 foo3 foo5 -foo6 foo7 in examplesInTemplate1 doc in outer @@ -15,6 +14,7 @@ doc in inner1 doc in inner2 foo8 foo9 +foo6 ''' joinable: false """ @@ -43,7 +43,7 @@ proc fun*() = proc fun*()=echo "foo5" fun() - runnableExamples: + runnableExamples("--experimental:codeReordering --warnings:off"): # `codeReordering` only allowed at top level {.experimental: "codeReordering".} proc fun1() = fun2() diff --git a/tests/overflw/tdistinct_range.nim b/tests/overflow/tdistinct_range.nim similarity index 100% rename from tests/overflw/tdistinct_range.nim rename to tests/overflow/tdistinct_range.nim diff --git a/tests/overflow/toverflow.nim b/tests/overflow/toverflow.nim new file mode 100644 index 000000000..972f929c6 --- /dev/null +++ b/tests/overflow/toverflow.nim @@ -0,0 +1,82 @@ +discard """ + output: "ok" + matrix: "--overflowChecks:off; --overflowChecks:off --b:js" +""" +# Tests nim's ability to detect overflows + +{.push overflowChecks: on.} + +var + a = high(int) + b = -2 + overflowDetected = false + +try: + echo(b - a) +except OverflowDefect: + overflowDetected = true + +{.pop.} # overflow check + +doAssert(overflowDetected) + +block: # Overflow checks in a proc + var + a = high(int) + b = -2 + overflowDetected = false + + {.push overflowChecks: on.} + proc foo() = + let c = b - a + {.pop.} + + try: + foo() + except OverflowDefect: + overflowDetected = true + + doAssert(overflowDetected) + +block: # Overflow checks in a forward declared proc + var + a = high(int) + b = -2 + overflowDetected = false + + proc foo() + + {.push overflowChecks: on.} + proc foo() = + let c = b - a + {.pop.} + + try: + foo() + except OverflowDefect: + overflowDetected = true + + doAssert(overflowDetected) + +block: # Overflow checks doesn't affect fwd declaration + var + a = high(int) + b = -2 + overflowDetected = false + + {.push overflowChecks: on.} + proc foo() + {.pop.} + + proc foo() = + let c = b - a + + try: + foo() + except OverflowDefect: + overflowDetected = true + + doAssert(not overflowDetected) + + +echo "ok" diff --git a/tests/overflw/toverflw2.nim b/tests/overflow/toverflow2.nim similarity index 100% rename from tests/overflw/toverflw2.nim rename to tests/overflow/toverflow2.nim diff --git a/tests/overflw/toverflw.nim b/tests/overflow/toverflow_reorder.nim similarity index 96% rename from tests/overflw/toverflw.nim rename to tests/overflow/toverflow_reorder.nim index 164e16e5c..fcf7b0c82 100644 --- a/tests/overflw/toverflw.nim +++ b/tests/overflow/toverflow_reorder.nim @@ -1,3 +1,5 @@ +{.experimental: "codeReordering".} + discard """ output: "ok" cmd: "nim $target --overflowChecks:off $options $file" @@ -12,7 +14,7 @@ var overflowDetected = false try: - writeLine(stdout, b - a) + echo b - a except OverflowDefect: overflowDetected = true diff --git a/tests/overflw/tovfint.nim b/tests/overflow/tovfint.nim similarity index 100% rename from tests/overflw/tovfint.nim rename to tests/overflow/tovfint.nim diff --git a/tests/parser/t20922.nim b/tests/parser/t20922.nim index 01af9868f..110610fb1 100644 --- a/tests/parser/t20922.nim +++ b/tests/parser/t20922.nim @@ -1,28 +1,17 @@ discard """ - cmd: "nim check $options --verbosity:0 $file" + cmd: "nim check $options --verbosity:0 --hints:off $file" action: "reject" nimout: ''' -t20922.nim(37, 5) Error: expression expected, but found ':' +t20922.nim(26, 5) Error: expression expected, but found ':' +t20922.nim(34, 7) Error: expression expected, but found ':' +t20922.nim(35, 5) Error: ':' or '=' expected, but got 'keyword of' Error: in expression ' '+'': identifier expected, but found '' -t20922.nim(37, 7) Error: attempting to call undeclared routine: '' +t20922.nim(26, 7) Error: attempting to call undeclared routine: '' Error: in expression ' '+'': identifier expected, but found '' -t20922.nim(37, 7) Error: attempting to call undeclared routine: '' -t20922.nim(37, 7) Error: expression '' cannot be called -t20922.nim(37, 7) Error: expression '' has no type (or is ambiguous) -t20922.nim(37, 7) Error: VM problem: dest register is not set -t20922.nim(45, 7) Error: expression expected, but found ':' -t20922.nim(46, 5) Error: ':' or '=' expected, but got 'keyword of' -t20922.nim(45, 9) Error: undeclared identifier: 'x' -t20922.nim(45, 9) Error: expression 'x' has no type (or is ambiguous) -Error: in expression ' x': identifier expected, but found '' -t20922.nim(45, 9) Error: attempting to call undeclared routine: '' -Error: in expression ' x': identifier expected, but found '' -t20922.nim(45, 9) Error: attempting to call undeclared routine: '' -t20922.nim(45, 9) Error: expression '' cannot be called -t20922.nim(45, 9) Error: expression '' has no type (or is ambiguous) -t20922.nim(45, 9) Error: VM problem: dest register is not set -t20922.nim(33, 6) Hint: 'mapInstrToToken' is declared but not used [XDeclaredButNotUsed] -t20922.nim(43, 3) Hint: 'Foo' is declared but not used [XDeclaredButNotUsed] +t20922.nim(26, 7) Error: attempting to call undeclared routine: '' +t20922.nim(26, 7) Error: expression '' cannot be called +t20922.nim(26, 7) Error: expression '' has no type (or is ambiguous) +t20922.nim(26, 7) Error: VM problem: dest register is not set ''' """ # original test case issue #20922 diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim index 5ecfe9704..f2779ea70 100644 --- a/tests/pragmas/tpush.nim +++ b/tests/pragmas/tpush.nim @@ -13,3 +13,15 @@ proc WarnMe() = x: int echo(x) +# bug #11852 +proc foo(x: string, y: int, res: int) = + {.push checks: off} + var a: ptr char = unsafeAddr(x[y]) + {.pop.} + if x.len > y: + doAssert ord(a[]) == 51 + else: + doAssert x.len + 48 == res + +foo("", 0, 48) +foo("abc", 40, 51) diff --git a/tests/pragmas/treorder.nim b/tests/pragmas/treorder.nim index 09a98ef6a..72e8808b3 100644 --- a/tests/pragmas/treorder.nim +++ b/tests/pragmas/treorder.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--experimental:codeReordering" output:'''0 1 2 diff --git a/tests/proc/t19795.nim b/tests/proc/t19795.nim new file mode 100644 index 000000000..677ec0a63 --- /dev/null +++ b/tests/proc/t19795.nim @@ -0,0 +1,19 @@ +discard """ + matrix: "--mm:arc" +""" + +# bug #19795 +# bug #21085 + +type Vector = seq[int] + +var vect: Vector = newSeq[int](5) +doAssert vect == @[0, 0, 0, 0, 0] + +# Needed to get the problem. Could also use "var". +let vectCopy = vect + +# Then some procedure definition is needed to get the problem. +proc p(): int = 3 + +doAssert vect == @[0, 0, 0, 0, 0] \ No newline at end of file diff --git a/tests/tools/tlinter.nim b/tests/tools/tlinter.nim index a6d45ab3b..16f67905e 100644 --- a/tests/tools/tlinter.nim +++ b/tests/tools/tlinter.nim @@ -1,10 +1,10 @@ discard """ cmd: '''nim c --styleCheck:hint $file''' nimout: ''' +tlinter.nim(25, 1) Hint: 'tyPE' should be: 'type' [Name] tlinter.nim(21, 14) Hint: 'nosideeffect' should be: 'noSideEffect' [Name] tlinter.nim(21, 28) Hint: 'myown' should be: 'myOwn' [template declared in tlinter.nim(19, 9)] [Name] tlinter.nim(21, 35) Hint: 'inLine' should be: 'inline' [Name] -tlinter.nim(25, 1) Hint: 'tyPE' should be: 'type' [Name] tlinter.nim(23, 1) Hint: 'foO' should be: 'foo' [proc declared in tlinter.nim(21, 6)] [Name] tlinter.nim(27, 14) Hint: 'Foo_bar' should be: 'FooBar' [type declared in tlinter.nim(25, 6)] [Name] tlinter.nim(29, 6) Hint: 'someVAR' should be: 'someVar' [var declared in tlinter.nim(27, 5)] [Name] diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim index 087dc0d68..6b4e71216 100644 --- a/tests/trmacros/tor.nim +++ b/tests/trmacros/tor.nim @@ -1,9 +1,19 @@ discard """ - output: '''0 + output: ''' +3 +0 true -3''' +''' """ + +# bug #798 +template t012{(0|1|2){x}}(x: untyped): untyped = x+1 +let z = 1 +# outputs 3 thanks to fixpoint iteration: +echo z + + template arithOps: untyped = (`+` | `-` | `*`) template testOr{ (arithOps{f})(a, b) }(a, b, f: untyped): untyped = f(a mod 10, b) @@ -20,9 +30,3 @@ var c = false a = b and a echo a - -# bug #798 -template t012{(0|1|2){x}}(x: untyped): untyped = x+1 -let z = 1 -# outputs 3 thanks to fixpoint iteration: -echo z From 7dc80a7fefb0d2cecbdc2696c71ea2fa94d6aa76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francis=20Th=C3=A9rien?= Date: Wed, 22 Feb 2023 15:10:02 -0500 Subject: [PATCH 4208/4254] Mitigate issues related to compiler options when cross-compiling (#21330) * Document C compiler options config when cross-compiling * Allow empty string to override default --- compiler/extccomp.nim | 4 +++- doc/nimc.md | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index db97de65c..45a531852 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -328,7 +328,9 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = platform.OS[conf.target.targetOS].name & '.' & CC[c].name & fullSuffix result = getConfigVar(conf, fullCCname) - if result.len == 0: + if existsConfigVar(conf, fullCCname): + result = getConfigVar(conf, fullCCname) + else: # not overridden for this cross compilation setting? result = getConfigVar(conf, CC[c].name & fullSuffix) else: diff --git a/doc/nimc.md b/doc/nimc.md index 81a060d8a..7b0e99e06 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -316,14 +316,16 @@ Another way is to make Nim invoke a cross compiler toolchain: nim c --cpu:arm --os:linux myproject.nim ``` -For cross compilation, the compiler invokes a C compiler named -like `$cpu.$os.$cc` (for example arm.linux.gcc) and the configuration -system is used to provide meaningful defaults. For example for `ARM` your +For cross compilation, the compiler invokes a C compiler named like +`$cpu.$os.$cc` (for example `arm.linux.gcc`) with options defined in +`$cpu.$os.$cc.options.always`. The configuration system is used to provide +meaningful defaults. For example, for Linux on a 32-bit ARM CPU, your configuration file should contain something like: arm.linux.gcc.path = "/usr/bin" arm.linux.gcc.exe = "arm-linux-gcc" arm.linux.gcc.linkerexe = "arm-linux-gcc" + arm.linux.gcc.options.always = "-w -fmax-errors=3" Cross-compilation for Windows ============================= From 8a19ac20708c66fb3541533d55b60624cee56ab7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 24 Feb 2023 09:02:15 +0100 Subject: [PATCH 4209/4254] fixes #21393 and misc style changes (#21419) * fixes #21393 and misc style changes * progress --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- compiler/int128.nim | 39 +++++++++++++++-------------- compiler/sempass2.nim | 19 +++++++------- lib/pure/collections/tables.nim | 31 +++++++++++++++-------- lib/pure/hashes.nim | 5 +++- lib/pure/osproc.nim | 8 ++---- lib/std/private/digitsutils.nim | 4 +-- lib/std/private/ospaths2.nim | 2 +- lib/system/seqs_v2.nim | 3 ++- lib/system/strmantle.nim | 2 +- lib/windows/winlean.nim | 16 ++++++------ tests/effects/tstrictfuncs_misc.nim | 2 +- 11 files changed, 70 insertions(+), 61 deletions(-) diff --git a/compiler/int128.nim b/compiler/int128.nim index e357706b9..b0341eb37 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -33,26 +33,27 @@ template high*(t: typedesc[Int128]): Int128 = Max proc `$`*(a: Int128): string proc toInt128*[T: SomeInteger | bool](arg: T): Int128 = - when T is bool: result.sdata(0) = int32(arg) - elif T is SomeUnsignedInt: - when sizeof(arg) <= 4: - result.udata[0] = uint32(arg) + {.noSideEffect.}: + when T is bool: result.sdata(0) = int32(arg) + elif T is SomeUnsignedInt: + when sizeof(arg) <= 4: + result.udata[0] = uint32(arg) + else: + result.udata[0] = uint32(arg and T(0xffffffff)) + result.udata[1] = uint32(arg shr 32) + elif sizeof(arg) <= 4: + result.sdata(0) = int32(arg) + if arg < 0: # sign extend + result.sdata(1) = -1 + result.sdata(2) = -1 + result.sdata(3) = -1 else: - result.udata[0] = uint32(arg and T(0xffffffff)) - result.udata[1] = uint32(arg shr 32) - elif sizeof(arg) <= 4: - result.sdata(0) = int32(arg) - if arg < 0: # sign extend - result.sdata(1) = -1 - result.sdata(2) = -1 - result.sdata(3) = -1 - else: - let tmp = int64(arg) - result.udata[0] = uint32(tmp and 0xffffffff) - result.sdata(1) = int32(tmp shr 32) - if arg < 0: # sign extend - result.sdata(2) = -1 - result.sdata(3) = -1 + let tmp = int64(arg) + result.udata[0] = uint32(tmp and 0xffffffff) + result.sdata(1) = int32(tmp shr 32) + if arg < 0: # sign extend + result.sdata(2) = -1 + result.sdata(3) = -1 template isNegative(arg: Int128): bool = arg.sdata(3) < 0 diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e989eb4a6..396ea6606 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -822,9 +822,6 @@ proc checkForSink(tracked: PEffects; n: PNode) = if tracked.inIfStmt == 0 and optSinkInference in tracked.config.options: checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n) -proc strictFuncsActive(tracked: PEffects): bool {.inline.} = - sfNoSideEffect in tracked.owner.flags and strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects - proc trackCall(tracked: PEffects; n: PNode) = template gcsafeAndSideeffectCheck() = if notGcSafe(op) and not importedFromC(a): @@ -934,9 +931,11 @@ proc trackCall(tracked: PEffects; n: PNode) = # initialized until after the call. Since we do this after we analysed the # call, this is fine. initVar(tracked, n[i].skipAddr, false) - if tracked.strictFuncsActive and isDangerousLocation(n[i].skipAddr, tracked.owner): - localError(tracked.config, n[i].info, - "cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i])) + if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and + isDangerousLocation(n[i].skipAddr, tracked.owner): + if sfNoSideEffect in tracked.owner.flags: + localError(tracked.config, n[i].info, + "cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i])) tracked.hasSideEffect = true else: discard @@ -1090,10 +1089,12 @@ proc track(tracked: PEffects, n: PNode) = createTypeBoundOps(tracked, n[0].typ, n.info) if n[0].kind != nkSym or not isLocalSym(tracked, n[0].sym): checkForSink(tracked, n[1]) - if tracked.strictFuncsActive and isDangerousLocation(n[0], tracked.owner): + if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and + isDangerousLocation(n[0], tracked.owner): tracked.hasSideEffect = true - localError(tracked.config, n[0].info, - "cannot mutate location $1 within a strict func" % renderTree(n[0])) + if sfNoSideEffect in tracked.owner.flags: + localError(tracked.config, n[0].info, + "cannot mutate location $1 within a strict func" % renderTree(n[0])) of nkVarSection, nkLetSection: for child in n: let last = lastSon(child) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 57a0107fd..4737fa478 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -447,7 +447,7 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = ## ## ## Note that while the value returned is of type `var B`, - ## it is easy to accidentally create an copy of the value at `t[key]`. + ## it is easy to accidentally create a copy of the value at `t[key]`. ## Remember that seqs and strings are value types, and therefore ## cannot be copied into a separate variable for modification. ## See the example below. @@ -828,7 +828,8 @@ proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = b = newTable[char, seq[int]]() new(result) - result[] = initTable[A, B](initialSize) + {.noSideEffect.}: + result[] = initTable[A, B](initialSize) proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = ## Creates a new ref hash table that contains the given `pairs`. @@ -844,14 +845,16 @@ proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] = assert b == {'a': 5, 'b': 9}.newTable new(result) - result[] = toTable[A, B](pairs) + {.noSideEffect.}: + result[] = toTable[A, B](pairs) proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] result = newTable[C, B]() - for item in collection: - result[index(item)] = item + {.noSideEffect.}: + for item in collection: + result[index(item)] = item proc `[]`*[A, B](t: TableRef[A, B], key: A): var B = ## Retrieves the value at `t[key]`. @@ -1825,7 +1828,8 @@ proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableRef[A a = newOrderedTable[int, string]() b = newOrderedTable[char, seq[int]]() new(result) - result[] = initOrderedTable[A, B](initialSize) + {.noSideEffect.}: + result[] = initOrderedTable[A, B](initialSize) proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = ## Creates a new ordered ref hash table that contains the given `pairs`. @@ -1842,7 +1846,8 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] = assert b == {'a': 5, 'b': 9}.newOrderedTable result = newOrderedTable[A, B](pairs.len) - for key, val in items(pairs): result[key] = val + {.noSideEffect.}: + for key, val in items(pairs): result[key] = val proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = @@ -2641,13 +2646,15 @@ proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = ## * `initCountTable proc<#initCountTable>`_ for creating a ## `CountTable` new(result) - result[] = initCountTable[A](initialSize) + {.noSideEffect.}: + result[] = initCountTable[A](initialSize) proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = ## Creates a new ref count table with every member of a container `keys` ## having a count of how many times it occurs in that container. result = newCountTable[A](keys.len) - for key in items(keys): result.inc(key) + {.noSideEffect.}: + for key in items(keys): result.inc(key) proc `[]`*[A](t: CountTableRef[A], key: A): int = ## Retrieves the value at `t[key]` if `key` is in `t`. @@ -2671,7 +2678,8 @@ proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) = ## * `inc proc<#inc,CountTableRef[A],A,int>`_ for incrementing a ## value of a key assert val > 0 - t[][key] = val + {.noSideEffect.}: + t[][key] = val proc inc*[A](t: CountTableRef[A], key: A, val = 1) = ## Increments `t[key]` by `val` (default: 1). @@ -2680,7 +2688,8 @@ proc inc*[A](t: CountTableRef[A], key: A, val = 1) = a.inc('a') a.inc('b', 10) doAssert a == newCountTable("aaabbbbbbbbbbb") - t[].inc(key, val) + {.noSideEffect.}: + t[].inc(key, val) proc smallest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = ## Returns the `(key, value)` pair with the smallest `val`. Efficiency: O(n) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 09e072812..4ae4938c6 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -247,7 +247,7 @@ proc hash*[T](x: ptr[T]): Hash {.inline.} = when defined(nimPreviewHashRef) or defined(nimdoc): proc hash*[T](x: ref[T]): Hash {.inline.} = ## Efficient `hash` overload. - ## + ## ## .. important:: Use `-d:nimPreviewHashRef` to ## enable hashing `ref`s. It is expected that this behavior ## becomes the new default in upcoming versions. @@ -536,6 +536,7 @@ proc hash*[T: tuple | object | proc](x: T): Hash = elif T is (proc): result = hash(pointer(x)) else: + result = 0 for f in fields(x): result = result !& hash(f) result = !$result @@ -551,6 +552,7 @@ proc hash*[A](x: openArray[A]): Hash = else: result = murmurHash(toOpenArrayByte(x, 0, x.high)) else: + result = 0 for a in x: result = result !& hash(a) result = !$result @@ -583,6 +585,7 @@ proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash = proc hash*[A](x: set[A]): Hash = ## Efficient hashing of sets. ## There must be a `hash` proc defined for the element type `A`. + result = 0 for it in items(x): result = result !& hash(it) result = !$result diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9a0e5895d..bb6abc571 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -570,12 +570,8 @@ when defined(windows) and not defined(useNimRtl): if a == 0: raiseOSError(osLastError()) proc newFileHandleStream(handle: Handle): owned FileHandleStream = - new(result) - result.handle = handle - result.closeImpl = hsClose - result.atEndImpl = hsAtEnd - result.readDataImpl = hsReadData - result.writeDataImpl = hsWriteData + result = FileHandleStream(handle: handle, closeImpl: hsClose, atEndImpl: hsAtEnd, + readDataImpl: hsReadData, writeDataImpl: hsWriteData) proc buildCommandLine(a: string, args: openArray[string]): string = result = quoteShell(a) diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index b3dc5d14f..e051e5218 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -101,9 +101,7 @@ proc addInt*(result: var string; x: int64) {.enforceNoRaises.} = num = cast[uint64](x) else: num = uint64(-x) - let base = result.len - setLen(result, base + 1) - result[base] = '-' + result.add '-' else: num = uint64(x) addInt(result, num) diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 5e3bece68..78a806675 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -571,7 +571,7 @@ proc normExt(ext: string): string = proc searchExtPos*(path: string): int = ## Returns index of the `'.'` char in `path` if it signifies the beginning - ## of extension. Returns -1 otherwise. + ## of the file extension. Returns -1 otherwise. ## ## See also: ## * `splitFile proc`_ diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 50f23111c..d7ace446d 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -83,7 +83,8 @@ proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} = for i in countdown(x.len - 1, newLen): reset x[i] # XXX This is wrong for const seqs that were moved into 'x'! - cast[ptr NimSeqV2[T]](addr x).len = newLen + {.noSideEffect.}: + cast[ptr NimSeqV2[T]](addr x).len = newLen proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = let oldLen = x.len diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index f4733ed21..ab158d6b7 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -33,7 +33,7 @@ proc eqStrings(a, b: string): bool {.inline, compilerproc.} = proc hashString(s: string): int {.compilerproc.} = # the compiler needs exactly the same hash function! # this used to be used for efficient generation of string case statements - var h : uint = 0 + var h = 0'u for i in 0..len(s)-1: h = h + uint(s[i]) h = h + h shl 10 diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 93ab3dd2e..230f963f0 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -48,12 +48,12 @@ type HGLRC* = Handle BYTE* = uint8 - SECURITY_ATTRIBUTES* {.final, pure.} = object + SECURITY_ATTRIBUTES* = object nLength*: int32 lpSecurityDescriptor*: pointer bInheritHandle*: WINBOOL - STARTUPINFO* {.final, pure.} = object + STARTUPINFO* = object cb*: int32 lpReserved*: cstring lpDesktop*: cstring @@ -73,17 +73,17 @@ type hStdOutput*: Handle hStdError*: Handle - PROCESS_INFORMATION* {.final, pure.} = object + PROCESS_INFORMATION* = object hProcess*: Handle hThread*: Handle dwProcessId*: int32 dwThreadId*: int32 - FILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT + FILETIME* = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT dwLowDateTime*: DWORD dwHighDateTime*: DWORD - BY_HANDLE_FILE_INFORMATION* {.final, pure.} = object + BY_HANDLE_FILE_INFORMATION* = object dwFileAttributes*: DWORD ftCreationTime*: FILETIME ftLastAccessTime*: FILETIME @@ -95,7 +95,7 @@ type nFileIndexHigh*: DWORD nFileIndexLow*: DWORD - OSVERSIONINFO* {.final, pure.} = object + OSVERSIONINFO* = object dwOSVersionInfoSize*: DWORD dwMajorVersion*: DWORD dwMinorVersion*: DWORD @@ -820,7 +820,7 @@ type POVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD, para3: POVERLAPPED){.stdcall.} - GUID* {.final, pure.} = object + GUID* = object D1*: int32 D2*: int16 D3*: int16 @@ -1101,7 +1101,7 @@ proc wsaResetEvent*(hEvent: Handle): bool {.stdcall, importc: "WSAResetEvent", dynlib: "ws2_32.dll".} type - KEY_EVENT_RECORD* {.final, pure.} = object + KEY_EVENT_RECORD* = object eventType*: int16 bKeyDown*: WINBOOL wRepeatCount*: int16 diff --git a/tests/effects/tstrictfuncs_misc.nim b/tests/effects/tstrictfuncs_misc.nim index 59d850763..8c573bb3a 100644 --- a/tests/effects/tstrictfuncs_misc.nim +++ b/tests/effects/tstrictfuncs_misc.nim @@ -53,7 +53,7 @@ type JsonNode3 = ref object fields: MyTable -proc `[]`(t: var MyTable, key: string): var int = +proc `[]`(t: MyTable, key: string): int = result = t.data[0] proc `[]`(x: JsonNode3, key: string): int = From bbb6d2c69d1b2bca9987c708ebc6ffd2479bb822 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:02:44 +0800 Subject: [PATCH 4210/4254] fixes #20695; fixes object with distinct defaults and tables (#21428) --- compiler/semtypes.nim | 4 ++- tests/objects/tobject_default_value.nim | 39 ++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index aaffa1ea7..26493703d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -222,9 +222,11 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool = proc fitDefaultNode(c: PContext, n: PNode): PType = let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil + let oldType = n[^1].typ n[^1] = semConstExpr(c, n[^1], expectedType = expectedType) + n[^1].flags.incl nfSem if n[^2].kind != nkEmpty: - if expectedType != nil: + if expectedType != nil and oldType != expectedType: n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info) result = n[^1].typ else: diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index cdc6016e0..150fb0876 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -3,7 +3,7 @@ discard """ targets: "c cpp js" """ -import std/[times, macros] +import std/[times, macros, tables] type Guess = object @@ -236,6 +236,7 @@ template main {.dirty.} = doAssert x.obj.name.scale == 1 when nimvm: + # todo discard "fixme" else: when defined(gcArc) or defined(gcOrc): @@ -523,5 +524,41 @@ template main {.dirty.} = discard oToEither(O()) + block: # bug #20695 + type + Default = object + tabs: Table[string, int] = initTable[string, int]() + + let d = default(Default) + doAssert d.tabs.len == 0 + + block: + type + Default = object + tabs: Table[string, int] = Table[string, int]() + + let d = default(Default) + doAssert d.tabs.len == 0 + + + block: + type DjangoDateTime = distinct DateTime + + type Default = object + data: DjangoDateTime = DjangoDateTime(DateTime()) + + let x = default(Default) + doAssert x.data is DjangoDateTime + + block: + type DjangoDateTime = distinct DateTime + + type Default = object + data = DjangoDateTime(DateTime()) + + let x = default(Default) + doAssert x.data is DjangoDateTime + + static: main() main() From 7837e57e93b1cb89f5a80a779e853bad070de777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francis=20Th=C3=A9rien?= Date: Fri, 24 Feb 2023 03:07:35 -0500 Subject: [PATCH 4211/4254] Disable threads for os:any (#21425) --- config/nim.cfg | 5 +++++ lib/std/typedthreads.nim | 2 ++ 2 files changed, 7 insertions(+) diff --git a/config/nim.cfg b/config/nim.cfg index 973de077a..ef93ec99e 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -100,6 +100,11 @@ nimblepath="$home/.nimble/pkgs/" gcc.options.always %= "${gcc.options.always} -fsanitize=null -fsanitize-undefined-trap-on-error" @end +# Turn off threads support when compiling for bare-metal targets (--os:any) +@if any: + threads:off +@end + @if unix and mingw: # Cross compile for Windows from Linux/OSX using MinGW i386.windows.gcc.exe = "i686-w64-mingw32-gcc" diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim index b45ce8a61..8359ca353 100644 --- a/lib/std/typedthreads.nim +++ b/lib/std/typedthreads.nim @@ -45,6 +45,8 @@ when defined(nimPreviewSlimSystem): when defined(genode): import genode/env +when hostOS == "any": + {.error: "Threads not implemented for os:any. Please compile with --threads:off.".} when hasAllocStack or defined(zephyr) or defined(freertos) or defined(nuttx) or defined(cpu16) or defined(cpu8): From d4782c9e42ff6cee9f674a376b1595583e08c2a3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 25 Feb 2023 00:53:04 +0800 Subject: [PATCH 4212/4254] closes #17864; add a test case (#21434) --- tests/vm/tmisc_vm.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim index af09e8871..1ad830b5f 100644 --- a/tests/vm/tmisc_vm.nim +++ b/tests/vm/tmisc_vm.nim @@ -445,3 +445,15 @@ static: needSecondIdentifier.mgetOrPut(firstPart, @[]).add((name, pattern)) doAssert needSecondIdentifier[0] == @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] + +# bug #17864 +macro transform*(fn: typed) = + quote do: + `fn` + +var map: Table[string, HashSet[string]] +proc publish*(): void {.transform.} = + map["k"] = init_hash_set[string]() + map["k"].incl "d" + +publish() From b2edfe7a02f49f07eb9fcf71cd500215725c217e Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipenko <36101416+dkgitdev@users.noreply.github.com> Date: Sat, 25 Feb 2023 13:47:19 +0300 Subject: [PATCH 4213/4254] Fix: nintendoswitch compilation (#21368) * Fix: make nintendoswitch someGcc, remove symlink support for nintendoswitch, add getAppFilename for nintendoswitch * Fix: use getApplHeuristic on nintendoswitch --- lib/posix/posix.nim | 8 ++++++-- lib/pure/os.nim | 4 +++- lib/std/private/ossymlinks.nim | 2 +- lib/std/sysatomics.nim | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 07652c64d..12fc8fd57 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -584,7 +584,8 @@ proc pread*(a1: cint, a2: pointer, a3: int, a4: Off): int {. proc pwrite*(a1: cint, a2: pointer, a3: int, a4: Off): int {. importc, header: "".} proc read*(a1: cint, a2: pointer, a3: int): int {.importc, header: "".} -proc readlink*(a1, a2: cstring, a3: int): int {.importc, header: "".} +when not defined(nintendoswitch): + proc readlink*(a1, a2: cstring, a3: int): int {.importc, header: "".} proc ioctl*(f: FileHandle, device: uint): int {.importc: "ioctl", header: "", varargs, tags: [WriteIOEffect].} ## A system call for device-specific input/output operations and other @@ -603,7 +604,10 @@ proc setsid*(): Pid {.importc, header: "".} proc setuid*(a1: Uid): cint {.importc, header: "".} proc sleep*(a1: cint): cint {.importc, header: "".} proc swab*(a1, a2: pointer, a3: int) {.importc, header: "".} -proc symlink*(a1, a2: cstring): cint {.importc, header: "".} +when not defined(nintendoswitch): + proc symlink*(a1, a2: cstring): cint {.importc, header: "".} +else: + proc symlink*(a1, a2: cstring): cint = -1 proc sync*() {.importc, header: "".} proc sysconf*(a1: cint): int {.importc, header: "".} proc tcgetpgrp*(a1: cint): Pid {.importc, header: "".} diff --git a/lib/pure/os.nim b/lib/pure/os.nim index ecceed671..3285c07df 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -254,7 +254,7 @@ proc findExe*(exe: string, followSymlinks: bool = true; for ext in extensions: var x = addFileExt(x, ext) if fileExists(x): - when not defined(windows): + when not (defined(windows) or defined(nintendoswitch)): while followSymlinks: # doubles as if here if x.symlinkExists: var r = newString(maxSymlinkLen) @@ -702,6 +702,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW result = getApplHaiku() elif defined(openbsd): result = getApplOpenBsd() + elif defined(nintendoswitch): + result = "" # little heuristic that may work on other POSIX-like systems: if result.len == 0: diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim index 53f59f939..6b2de6237 100644 --- a/lib/std/private/ossymlinks.nim +++ b/lib/std/private/ossymlinks.nim @@ -67,7 +67,7 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} = ## ## See also: ## * `createSymlink proc`_ - when defined(windows): + when defined(windows) or defined(nintendoswitch): result = symlinkPath else: result = newString(maxSymlinkLen) diff --git a/lib/std/sysatomics.nim b/lib/std/sysatomics.nim index b7ccb4092..36a4e5537 100644 --- a/lib/std/sysatomics.nim +++ b/lib/std/sysatomics.nim @@ -15,7 +15,7 @@ when defined(nimPreviewSlimSystem): const hasThreadSupport = compileOption("threads") and not defined(nimscript) -const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang) +const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang) or defined(nintendoswitch) const someVcc = defined(vcc) or defined(clang_cl) type From 425225119a383511ac6f84ba5c02a691e6c51aea Mon Sep 17 00:00:00 2001 From: PhilippMDoerner Date: Sun, 26 Feb 2023 09:57:51 +0100 Subject: [PATCH 4214/4254] Add mention of breaking change about `[_]` in generics to changelog (#21437) Add mention of breaking change to changelog As described by #21435 , generic proc declarations making use of `_` as generic parameter are no longer possible. This is a change that was introduced by #21192 . During the debate over if this should be part of the intended spec in #21435 we concluded that it is and thus should be mentioned as a breaking change in the changelogs. --- changelogs/changelog_2_0_0.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index c8427cc2a..e081865be 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -149,6 +149,13 @@ proc foo(_, _: int): int = 123 echo foo(1, 2) ``` +- Underscores (`_`) as generic parameters are not supported and cannot be used. + Generics that use `_` as parameters will no longer compile requires you to replace `_` with something else: + + ```nim + proc foo[_](t: typedesc[_]): string = "BAR" # Can not compile + proc foo[T](t: typedesc[T]): string = "BAR" # Can compile + ``` - - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. From 4ae598762e7dac1886b481a48ae0875843e5153f Mon Sep 17 00:00:00 2001 From: Constantine Molchanov Date: Mon, 27 Feb 2023 02:56:43 +0300 Subject: [PATCH 4215/4254] fixes #21439; Add tyOpenArray to genTypeInfo. (#21440) * fixes #21439; Add tyOpenArray to genTypeInfo. * Add test. --- compiler/jstypes.nim | 2 +- tests/js/t21439.nim | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/js/t21439.nim diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 56d075af7..4b4ca9fe7 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -133,7 +133,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % [result, rope(ord(t.kind))] prepend(p.g.typeInfo, s) - of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet: + of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet, tyOpenArray: var s = "var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" % [result, rope(ord(t.kind))] diff --git a/tests/js/t21439.nim b/tests/js/t21439.nim new file mode 100644 index 000000000..972356cd0 --- /dev/null +++ b/tests/js/t21439.nim @@ -0,0 +1,14 @@ +discard """ + action: "compile" +""" + +proc test(a: openArray[string]): proc = + result = proc = + for i in a: + discard i + + +const a = ["t1", "t2"] + +discard test(a) + From 89a60939f8b0c60e8abf63b698491a8b138da772 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 27 Feb 2023 08:57:02 +0900 Subject: [PATCH 4216/4254] Fix typo in sourcemap.nim (#21438) seperated -> separated --- compiler/sourcemap.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim index 2245250ac..2fcc50bbe 100644 --- a/compiler/sourcemap.nim +++ b/compiler/sourcemap.nim @@ -164,7 +164,7 @@ func toSourceMap*(info: SourceInfo, file: string): SourceMap {.raises: [].} = result.names = info.names # Convert nodes into mappings. # Mappings are split into blocks where each block referes to a line in the outputted JS. - # Blocks can be seperated into statements which refere to tokens on the line. + # Blocks can be separated into statements which refere to tokens on the line. # Since the mappings depend on previous values we need to # keep track of previous file, name, etc var From 6fea221d65c999ef7923bf51bbdaa8421cb2e9df Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 27 Feb 2023 07:57:36 +0800 Subject: [PATCH 4217/4254] Overrides `=copy` for `PackedSets` (#21417) --- lib/std/packedsets.nim | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index 1e2892658..e8e03af9e 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -12,11 +12,6 @@ ## ## Supports any Ordinal type. ## -## .. note:: Currently the assignment operator `=` for `PackedSet[A]` -## performs some rather meaningless shallow copy. Since Nim currently does -## not allow the assignment operator to be overloaded, use the `assign proc -## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy. -## ## See also ## ======== ## * `sets module `_ for more general hash sets @@ -412,18 +407,9 @@ proc isNil*[A](x: PackedSet[A]): bool {.inline.} = x.head.isNil and x.elems == 0 -proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = +proc `=copy`*[A](dest: var PackedSet[A], src: PackedSet[A]) = ## Copies `src` to `dest`. ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_. - runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - b.incl(5) - b.incl(7) - a.assign(b) - assert len(a) == 2 - if src.elems <= src.a.len: dest.data = @[] dest.max = 0 @@ -452,6 +438,19 @@ proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = dest.data[h] = n it = it.next +proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) {.inline, deprecated.} = + ## Copies `src` to `dest`. + ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_. + runnableExamples: + var + a = initPackedSet[int]() + b = initPackedSet[int]() + b.incl(5) + b.incl(7) + a.assign(b) + assert len(a) == 2 + `=copy`(dest, src) + proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## Returns the union of the sets `s1` and `s2`. ## From 83e33207250643dedc541e44ecf32d58f3edd097 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Tue, 28 Feb 2023 15:17:21 +0200 Subject: [PATCH 4218/4254] Use a cast to suppress KeyError raises (#21451) --- lib/pure/json.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index e881fbff7..d91da3545 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -465,11 +465,12 @@ proc `==`*(a, b: JsonNode): bool {.noSideEffect.} = if a.fields.len != b.fields.len: return false for key, val in a.fields: if not b.fields.hasKey(key): return false - when defined(nimHasEffectsOf): - {.noSideEffect.}: + {.cast(raises: []).}: + when defined(nimHasEffectsOf): + {.noSideEffect.}: + if b.fields[key] != val: return false + else: if b.fields[key] != val: return false - else: - if b.fields[key] != val: return false result = true proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.} From dd629c8f450aa6bc871b54e4e549ad5fea2979a3 Mon Sep 17 00:00:00 2001 From: Century Systems Date: Tue, 28 Feb 2023 22:38:50 +0900 Subject: [PATCH 4219/4254] asyncdispatch: for NuttX, add destructor to clear global dispatcher. (#21432) * asyncdispatch: for NuttX, add destructor to clear global dispatcher using atexit(). Signed-off-by: Takeyoshi Kikuchi * std: exitprocs: remove "when defined(nuttx)" block. Signed-off-by: Takeyoshi Kikuchi --------- Signed-off-by: Takeyoshi Kikuchi --- lib/pure/asyncdispatch.nim | 13 ++++++++++++- lib/std/exitprocs.nim | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 2bfa8587c..63062d8da 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1216,6 +1216,15 @@ else: var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher + when defined(nuttx): + import std/exitprocs + + proc cleanDispatcher() {.noconv.} = + gDisp = nil + + proc addFinalyzer() = + addExitProc(cleanDispatcher) + proc setGlobalDispatcher*(disp: owned PDispatcher) = if not gDisp.isNil: assert gDisp.callbacks.len == 0 @@ -1225,6 +1234,8 @@ else: proc getGlobalDispatcher*(): PDispatcher = if gDisp.isNil: setGlobalDispatcher(newDispatcher()) + when defined(nuttx): + addFinalyzer() result = gDisp proc getIoHandler*(disp: PDispatcher): Selector[AsyncData] = @@ -1591,7 +1602,7 @@ else: owned(Future[tuple[address: string, client: AsyncFD]]) = var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr") - proc cb(sock: AsyncFD): bool = + proc cb(sock: AsyncFD): bool {.gcsafe.} = result = true var sockAddress: Sockaddr_storage var addrLen = sizeof(sockAddress).SockLen diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index d63c1abc5..48b4fca7f 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -45,6 +45,7 @@ proc callClosures() {.noconv.} = case fun.kind of kClosure: fun.fun1() of kNoconv: fun.fun2() + gFuns.setLen(0) template fun() = if gFuns.len == 0: From 39d0a93d0e0bc2ebf24a9801fe49cdb71c085527 Mon Sep 17 00:00:00 2001 From: Constantine Molchanov Date: Wed, 1 Mar 2023 05:30:38 +0300 Subject: [PATCH 4220/4254] Fix #21452; enable Norm in important packages. (#21455) * fix #21452; enable Norm in important packages. * Run test that doesn't require SQLite. --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index b3a4bfb82..0af0eb93e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -119,7 +119,7 @@ pkg "nimterop", "nimble minitest" pkg "nimwc", "nim c nimwc.nim", allowFailure = true pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" -pkg "norm", "testament r tests/sqlite/trows.nim", allowFailure = true +pkg "norm", "testament r tests/common/tmodel.nim" pkg "npeg", "nimble testarc" pkg "numericalnim", "nimble nimCI" pkg "optionsutils" From c4dd0c43016faadbdaaddb2decf95dc881eb772e Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Wed, 1 Mar 2023 17:17:05 +0100 Subject: [PATCH 4221/4254] suggestion for a simple fix for #21279 (#21378) --- compiler/cgen.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 60623b72d..c346a0b78 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -480,6 +480,9 @@ proc resetLoc(p: BProc, loc: var TLoc) = # on the bytes following the m_type field? genObjectInit(p, cpsStmts, loc.t, loc, constructObj) +proc isOrHasImportedCppType(typ: PType): bool = + searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) + proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: @@ -497,7 +500,7 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = if not isTemp or containsGarbageCollectedRef(loc.t): # don't use nimZeroMem for temporary values for performance if we can # avoid it: - if not isImportedCppType(typ): + if not isOrHasImportedCppType(typ): linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", [addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) genObjectInit(p, cpsStmts, loc.t, loc, constructObj) @@ -517,7 +520,10 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) + if p.module.compileToCpp and isOrHasImportedCppType(t): + linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r]) + else: + linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -575,7 +581,7 @@ proc assignLocalVar(p: BProc, n: PNode) = # this need not be fulfilled for inline procs; they are regenerated # for each module that uses them! let nl = if optLineDir in p.config.options: "" else: "\L" - let decl = localVarDecl(p, n) & ";" & nl + let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl line(p, cpsLocals, decl) include ccgthreadvars From 1b1412f3d148b02fb553f37d84505745cf3fb435 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 2 Mar 2023 00:18:09 +0800 Subject: [PATCH 4222/4254] fixes #10938; fixes #13312; fixes #13918; fixes #20985; always initializes global variables with null values in VM (#21351) * fixes #10938; always initialize global variable in VM * fixes importc vars * there is a pre-existing issue regarding closure types in the VM * add tests --- compiler/vmgen.nim | 12 ++++++++++++ tests/vm/tvmmisc.nim | 46 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index bdf7b679e..be7938e53 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1909,6 +1909,18 @@ proc genVarSection(c: PCtx; n: PNode) = c.genAdditionalCopy(a[2], opcWrDeref, tmp, 0, val) c.freeTemp(val) c.freeTemp(tmp) + elif not importcCondVar(s) and not (s.typ.kind == tyProc and s.typ.callConv == ccClosure): # fixes #10938 + # there is a pre-existing issue with closure types in VM + # if `(var s: proc () = default(proc ()); doAssert s == nil)` works for you; + # you might remove the second condition. + # the problem is that closure types are tuples in VM, but the types of its children + # shouldn't have the same type as closure types. + let tmp = c.genx(a[0], {gfNodeAddr}) + let sa = getNullValue(s.typ, a.info, c.config) + let val = c.genx(sa) + c.genAdditionalCopy(sa, opcWrDeref, tmp, 0, val) + c.freeTemp(val) + c.freeTemp(tmp) else: setSlot(c, s) if a[2].kind == nkEmpty: diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 2ce4703b0..673e3e965 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -564,14 +564,14 @@ block: block: static: let x = int 1 - echo x.type # Foo + doAssert $(x.type) == "Foo" # Foo block: static: let x = int 1 let y = x + 1 # Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect] - echo y + doAssert y == 2 type Atom* = object @@ -601,3 +601,45 @@ proc foo(s: sink string) = doAssert s.len == 3 static: foo("abc") + + +static: + for i in '1' .. '2': # bug #10938 + var s: set[char] + doAssert s == {} + incl(s, i) + + for _ in 0 ..< 3: # bug #13312 + var s: string + s.add("foo") + doAssert s == "foo" + + for i in 1 .. 5: # bug #13918 + var arr: array[3, int] + var val: int + doAssert arr == [0, 0, 0] and val == 0 + for j in 0 ..< len(arr): + arr[j] = i + val = i + +# bug #20985 +let a = block: + var groups: seq[seq[int]] + for i in 0 ..< 3: + var group: seq[int] + for j in 0 ..< 3: + group.add j + groups.add group + groups + +const b = block: + var groups: seq[seq[int]] + for i in 0 ..< 3: + var group: seq[int] + for j in 0 ..< 3: + group.add j + groups.add group + groups + +doAssert a == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] +doAssert b == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] From 89d8c0b24678a0b65820692069adffc7bec38ae7 Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 1 Mar 2023 22:00:58 +0500 Subject: [PATCH 4223/4254] tests/stylecheck: make sure necessary hints are enabled (#21240) --- tests/stylecheck/t20397_1.nim | 4 ++-- tests/stylecheck/treject.nim | 4 ++-- tests/stylecheck/tusages.nim | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/stylecheck/t20397_1.nim b/tests/stylecheck/t20397_1.nim index 24f5791f8..76c03dca1 100644 --- a/tests/stylecheck/t20397_1.nim +++ b/tests/stylecheck/t20397_1.nim @@ -1,8 +1,8 @@ discard """ - matrix: "--styleCheck:off" + matrix: "--styleCheck:off --hint:Name:on" """ {.hintAsError[Name]:on.} var a_b = 1 discard a_b -{.hintAsError[Name]:off.} \ No newline at end of file +{.hintAsError[Name]:off.} diff --git a/tests/stylecheck/treject.nim b/tests/stylecheck/treject.nim index b9d97a58d..458a2d039 100644 --- a/tests/stylecheck/treject.nim +++ b/tests/stylecheck/treject.nim @@ -1,7 +1,7 @@ discard """ action: reject nimout: '''treject.nim(14, 13) Error: 'iD' should be: 'id' [field declared in treject.nim(9, 5)]''' - matrix: "--styleCheck:error --styleCheck:usages" + matrix: "--styleCheck:error --styleCheck:usages --hint:Name:on" """ type @@ -14,4 +14,4 @@ template hello = echo name.iD echo iD -hello() \ No newline at end of file +hello() diff --git a/tests/stylecheck/tusages.nim b/tests/stylecheck/tusages.nim index 2f99c70c5..b689dabb3 100644 --- a/tests/stylecheck/tusages.nim +++ b/tests/stylecheck/tusages.nim @@ -1,11 +1,9 @@ discard """ action: reject - nimout: '''tusages.nim(22, 5) Error: 'BAD_STYLE' should be: 'BADSTYLE' [proc declared in tusages.nim(11, 6)]''' - matrix: "--styleCheck:error --styleCheck:usages" + nimout: '''tusages.nim(20, 5) Error: 'BAD_STYLE' should be: 'BADSTYLE' [proc declared in tusages.nim(9, 6)]''' + matrix: "--styleCheck:error --styleCheck:usages --hint:all:off --hint:Name:on" """ - - import strutils proc BADSTYLE(c: char) = discard From cf083af262d03f62af302a28920f7bfa4b0e6233 Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 1 Mar 2023 22:01:58 +0500 Subject: [PATCH 4224/4254] tests: explicitly enable stack traces where needed (#21236) * tests/assert/tassert_c.nim: explicitly enable stack traces * tests/errmsgs: explicitly enable stack traces --- tests/assert/tassert_c.nim | 2 +- tests/errmsgs/tproper_stacktrace.nim | 31 ++++++++++++++------------- tests/errmsgs/tproper_stacktrace2.nim | 3 ++- tests/errmsgs/tproper_stacktrace3.nim | 3 ++- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index 4d49a6035..e3e3b8147 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim $target $options -d:nimPreviewSlimSystem --excessiveStackTrace:off $file" + matrix: "-d:nimPreviewSlimSystem --stackTrace:on --excessiveStackTrace:off" output: '''true''' """ import std/assertions diff --git a/tests/errmsgs/tproper_stacktrace.nim b/tests/errmsgs/tproper_stacktrace.nim index 8617984fb..b0a008840 100644 --- a/tests/errmsgs/tproper_stacktrace.nim +++ b/tests/errmsgs/tproper_stacktrace.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--stackTrace:on --hint:all:off --warnings:off" output: '''ok''' """ import strscans, strutils @@ -76,10 +77,10 @@ when true: bar() const expectedStackTrace = """ - tproper_stacktrace.nim(86) tproper_stacktrace - tproper_stacktrace.nim(76) foo - tproper_stacktrace.nim(73) bar - tproper_stacktrace.nim(7) raiseTestException + tproper_stacktrace.nim(87) tproper_stacktrace + tproper_stacktrace.nim(77) foo + tproper_stacktrace.nim(74) bar + tproper_stacktrace.nim(8) raiseTestException """ verifyStackTrace expectedStackTrace: @@ -93,9 +94,9 @@ when true: bar(x) const expectedStackTrace = """ - tproper_stacktrace.nim(103) tproper_stacktrace - tproper_stacktrace.nim(90) bar - tproper_stacktrace.nim(7) raiseTestException + tproper_stacktrace.nim(104) tproper_stacktrace + tproper_stacktrace.nim(91) bar + tproper_stacktrace.nim(8) raiseTestException """ verifyStackTrace expectedStackTrace: @@ -110,10 +111,10 @@ when true: bar() const expectedStackTrace = """ - tproper_stacktrace.nim(120) tproper_stacktrace - tproper_stacktrace.nim(110) foo - tproper_stacktrace.nim(107) bar - tproper_stacktrace.nim(7) raiseTestException + tproper_stacktrace.nim(121) tproper_stacktrace + tproper_stacktrace.nim(111) foo + tproper_stacktrace.nim(108) bar + tproper_stacktrace.nim(8) raiseTestException """ verifyStackTrace expectedStackTrace: @@ -129,10 +130,10 @@ when true: bar() const expectedStackTrace = """ - tproper_stacktrace.nim(139) tproper_stacktrace - tproper_stacktrace.nim(129) foo - tproper_stacktrace.nim(125) baz - tproper_stacktrace.nim(7) raiseTestException + tproper_stacktrace.nim(140) tproper_stacktrace + tproper_stacktrace.nim(130) foo + tproper_stacktrace.nim(126) baz + tproper_stacktrace.nim(8) raiseTestException """ verifyStackTrace expectedStackTrace: diff --git a/tests/errmsgs/tproper_stacktrace2.nim b/tests/errmsgs/tproper_stacktrace2.nim index 44b208c87..5a6ca3fcb 100644 --- a/tests/errmsgs/tproper_stacktrace2.nim +++ b/tests/errmsgs/tproper_stacktrace2.nim @@ -1,5 +1,6 @@ discard """ - outputsub: '''tproper_stacktrace2.nim(20) main''' + matrix: "--stackTrace:on" + outputsub: '''tproper_stacktrace2.nim(21) main''' exitcode: 1 """ diff --git a/tests/errmsgs/tproper_stacktrace3.nim b/tests/errmsgs/tproper_stacktrace3.nim index c292fa092..97d63e6ec 100644 --- a/tests/errmsgs/tproper_stacktrace3.nim +++ b/tests/errmsgs/tproper_stacktrace3.nim @@ -1,5 +1,6 @@ discard """ - outputsub: '''tproper_stacktrace3.nim(21) main''' + matrix: "--stackTrace:on" + outputsub: '''tproper_stacktrace3.nim(22) main''' exitcode: 1 """ From 070938720ad1a06e3273c164db53edb470bdb9a8 Mon Sep 17 00:00:00 2001 From: Anna Date: Thu, 2 Mar 2023 01:29:23 +0500 Subject: [PATCH 4225/4254] tests/errmsgs/tcall_with_default_arg.nim: sync (#21237) --- tests/errmsgs/tcall_with_default_arg.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/errmsgs/tcall_with_default_arg.nim b/tests/errmsgs/tcall_with_default_arg.nim index 1cc86638f..44752f1ee 100644 --- a/tests/errmsgs/tcall_with_default_arg.nim +++ b/tests/errmsgs/tcall_with_default_arg.nim @@ -1,5 +1,5 @@ discard """ -outputsub: '''tcall_with_default_arg.nim(16) anotherFoo''' +outputsub: '''tcall_with_default_arg.nim(8) fail''' exitcode: 1 """ # issue: #5604 From 9948fed919389229a48347aa9fa5adce9b7e0a98 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 2 Mar 2023 12:25:55 +0800 Subject: [PATCH 4226/4254] fixes #21326; fixes #7375; fixes #11986; fixes #9607; rework quote do; `getAst` uses type info to annotate the type of quoted variables; no more type erasures for quoted variables (#21433) * fixes #21326; getAst uses type info to annotateType quoted variables * simplify logics; sem types first * fixes important packages * add testcases * tiny --- compiler/semexprs.nim | 11 ++- compiler/vm.nim | 5 +- testament/important_packages.nim | 6 +- tests/stdlib/tmacros.nim | 136 +++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 8 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7454c7f8e..9cf206b4c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2203,10 +2203,13 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = if ids.len > 0: dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info) dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type - ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type - ids.add c.graph.emptyNode # no default value - dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids) - + dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode) + for i in 1.. Date: Thu, 2 Mar 2023 12:29:40 +0800 Subject: [PATCH 4227/4254] fixes #19291; implements `wasMoved` hook (#21303) * fixes #19291; implements `wasMoved` hook * basics * checkpoint * finish `wasMoved` * add a test for #19291 * add documentation and changelog * work `attachedWasMoved` with generics * fixes optimizer * register `=wasMoved` * handle wasMoved magcis * check another round * some patches * try `op == nil` * nicer * generate `wasMoved` before `destroy` * try again * fixes tests * default wasMoved * Update tests/destructor/tv2_cast.nim * Update tests/destructor/tv2_cast.nim * Update tests/arc/topt_refcursors.nim --- changelogs/changelog_2_0_0.md | 2 ++ compiler/ast.nim | 3 +- compiler/injectdestructors.nim | 17 +++++++--- compiler/liftdestructors.nim | 41 ++++++++++++++++++++--- compiler/optimizer.nim | 9 +++-- compiler/semstmts.nim | 5 ++- doc/manual.md | 2 +- tests/arc/topt_no_cursor.nim | 19 ++++++----- tests/arc/topt_refcursors.nim | 8 +++-- tests/arc/topt_wasmoved_destroy_pairs.nim | 13 ++++--- tests/destructor/tv2_cast.nim | 14 ++++---- tests/destructor/twasmoved_error.nim | 37 ++++++++++++++++++++ 12 files changed, 131 insertions(+), 39 deletions(-) create mode 100644 tests/destructor/twasmoved_error.nim diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index e081865be..cbe755478 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -341,6 +341,8 @@ - IBM Z architecture and macOS m1 arm64 architecture are supported. +- `=wasMoved` can be overridden by users. + ## Compiler changes - The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the diff --git a/compiler/ast.nim b/compiler/ast.nim index aa70560ed..f93c8d910 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -935,6 +935,7 @@ type TTypeSeq* = seq[PType] TTypeAttachedOp* = enum ## as usual, order is important here + attachedWasMoved, attachedDestructor, attachedAsgn, attachedSink, @@ -1502,7 +1503,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, const AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=destroy", "=copy", "=sink", "=trace", "=deepcopy"] + "=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"] proc `$`*(s: PSym): string = if s != nil: diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 20e790202..13141b765 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -354,11 +354,18 @@ It is best to factor out piece of object that needs custom destructor into separ result.add newTree(nkFastAsgn, le, tmp) proc genWasMoved(c: var Con, n: PNode): PNode = - result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved))) - result.add copyTree(n) #mWasMoved does not take the address - #if n.kind != nkSym: - # message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")") + let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + let op = getAttachedOp(c.graph, n.typ, attachedWasMoved) + if op != nil: + if sfError in op.flags: + c.checkForErrorPragma(n.typ, n, "=wasMoved") + result = genOp(c, op, n) + else: + result = newNodeI(nkCall, n.info) + result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved))) + result.add copyTree(n) #mWasMoved does not take the address + #if n.kind != nkSym: + # message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")") proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = result = newNodeI(nkCall, info) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 738f659b7..c7464d39e 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -88,6 +88,8 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let call = genBuiltin(c, mDefault, "default", x) call.typ = t body.add newAsgnStmt(x, call) + elif c.kind == attachedWasMoved: + body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc genAddr(c: var TLiftCtx; x: PNode): PNode = if x.kind == nkHiddenDeref: @@ -145,6 +147,11 @@ proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = else: result = destroy +proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = + result = newNodeIT(nkCall, x.info, op.typ[0]) + result.add(newSymNode(op)) + result.add genAddr(c, x) + proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) = case n.kind of nkSym: @@ -442,6 +449,20 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = body.add newDeepCopyCall(c, op, x, y) result = true + of attachedWasMoved: + var op = getAttachedOp(c.g, t, attachedWasMoved) + if op != nil and sfOverriden in op.flags: + + if op.ast.isGenericRoutine: + # patch generic destructor: + op = instantiateGeneric(c, op, t, t.typeInst) + setAttachedOp(c.g, c.idgen.module, t, attachedWasMoved, op) + + #markUsed(c.g.config, c.info, op, c.g.usageSym) + onUse(c.info, op) + body.add genWasMovedCall(c, op, x) + result = true + proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info) temp.typ = getSysType(c.g, body.info, tyInt) @@ -524,6 +545,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if canFormAcycle(t.elemType): # follow all elements: forallElements(c, t, body, x, y) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = createTypeBoundOps(c.g, c.c, t, body.info, c.idgen) @@ -561,6 +583,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if op == nil: return # protect from recursion body.add newHookCall(c, op, x, y) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -576,6 +599,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc cyclicType*(t: PType): bool = case t.kind @@ -674,6 +698,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # If the ref is polymorphic we have to account for this body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y) #echo "can follow ", elemType, " static ", isFinal(elemType) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ## Closures are really like refs except they always use a virtual destructor @@ -722,6 +748,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -746,6 +773,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) @@ -771,6 +799,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, x, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind == attachedDeepCopy: @@ -805,6 +834,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) @@ -820,6 +850,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind @@ -935,7 +966,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp result.typ = newProcType(info, nextTypeId(idgen), owner) result.typ.addParam dest - if kind != attachedDestructor: + if kind notin {attachedDestructor, attachedWasMoved}: result.typ.addParam src if kind == attachedAsgn and g.config.selectedGC == gcOrc and @@ -975,7 +1006,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; let dest = result.typ.n[1].sym let d = newDeref(newSymNode(dest)) - let src = if kind == attachedDestructor: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) + let src = if kind in {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) else: newSymNode(result.typ.n[2].sym) # register this operation already: @@ -1103,15 +1134,15 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf # bug #15122: We need to produce all prototypes before entering the # mind boggling recursion. Hacks like these imply we should rewrite # this module. - var generics: array[attachedDestructor..attachedTrace, bool] - for k in attachedDestructor..lastAttached: + var generics: array[attachedWasMoved..attachedTrace, bool] + for k in attachedWasMoved..lastAttached: generics[k] = getAttachedOp(g, canon, k) != nil if not generics[k]: setAttachedOp(g, idgen.module, canon, k, symPrototype(g, canon, canon.owner, k, info, idgen)) # we generate the destructor first so that other operators can depend on it: - for k in attachedDestructor..lastAttached: + for k in attachedWasMoved..lastAttached: if not generics[k]: discard produceSym(g, c, canon, k, info, idgen) else: diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 98939f80d..0b26e8d34 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -16,6 +16,8 @@ import from trees import exprStructuralEquivalent +import std/strutils + const nfMarkForDeletion = nfNone # faster than a lookup table @@ -110,16 +112,17 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) = var reverse = false if n[0].kind == nkSym: let s = n[0].sym - if s.magic == mWasMoved: + let name = s.name.s.normalize + if s.magic == mWasMoved or name == "=wasmoved": b.wasMovedLocs.add n special = true - elif s.name.s == "=destroy": + elif name == "=destroy": if c.inFinally > 0 and (b.hasReturn or b.hasBreak): discard "cannot optimize away the destructor" else: c.wasMovedDestroyPair b, n special = true - elif s.name.s == "=sink": + elif name == "=sink": reverse = true if not special: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 7dc976c19..6237e6eb0 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1779,7 +1779,7 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType = proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = let t = s.typ var noError = false - let cond = if op == attachedDestructor: + let cond = if op in {attachedDestructor, attachedWasMoved}: t.len == 2 and t[0] == nil and t[1].kind == tyVar elif op == attachedTrace: t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer @@ -1894,6 +1894,9 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = of "=trace": if s.magic != mTrace: bindTypeHook(c, s, n, attachedTrace) + of "=wasmoved": + if s.magic != mWasMoved: + bindTypeHook(c, s, n, attachedWasMoved) else: if sfOverriden in s.flags: localError(c.config, n.info, errGenerated, diff --git a/doc/manual.md b/doc/manual.md index ef790c362..31c620ca7 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -4122,7 +4122,7 @@ the operator is in scope (including if it is private). ``` Type bound operators are: -`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`. +`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`, `=wasMoved`. These operations can be *overridden* instead of *overloaded*. This means that the implementation is automatically lifted to structured types. For instance, diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 30d4c316c..50dfa26ac 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -1,7 +1,8 @@ discard """ nimoutFull: true cmd: '''nim c -r --warnings:off --hints:off --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' - nimout: '''--expandArc: newTarget + nimout: ''' +--expandArc: newTarget var splat @@ -11,9 +12,9 @@ splat = splitDrive do: let blitTmp = path blitTmp :tmp = splat.drive -wasMoved(splat.drive) +`=wasMoved`(splat.drive) :tmp_1 = splat.path_1 -wasMoved(splat.path_1) +`=wasMoved`(splat.path_1) result = ( let blitTmp_1 = :tmp blitTmp_1, @@ -60,10 +61,10 @@ var try: it_cursor = x a = ( - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, it_cursor.key) :tmpD, - wasMoved(:tmpD_1) + `=wasMoved`(:tmpD_1) `=copy`(:tmpD_1, it_cursor.val) :tmpD_1) echo [ @@ -112,7 +113,7 @@ block :tmp: var :tmpD sym = shadowScope.symbols[i] addInterfaceDecl(c): - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy_1`(:tmpD, sym) :tmpD inc(i, 1) @@ -125,7 +126,7 @@ this.isValid = fileExists(this.value) if dirExists(this.value): var :tmpD par = (dir: - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, this.value) :tmpD, front: "") else: var @@ -133,10 +134,10 @@ if dirExists(this.value): :tmpD_2 :tmpD_3 par = (dir_1: parentDir(this.value), front_1: - wasMoved(:tmpD_1) + `=wasMoved`(:tmpD_1) `=copy`(:tmpD_1, :tmpD_3 = splitDrive do: - wasMoved(:tmpD_2) + `=wasMoved`(:tmpD_2) `=copy`(:tmpD_2, this.value) :tmpD_2 :tmpD_3.path) diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim index c13d81bad..8c638a4a1 100644 --- a/tests/arc/topt_refcursors.nim +++ b/tests/arc/topt_refcursors.nim @@ -1,7 +1,8 @@ discard """ output: '''''' cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' - nimout: '''--expandArc: traverse + nimout: ''' +--expandArc: traverse var it_cursor @@ -22,12 +23,13 @@ try: `=copy`(ri_1, jt.ri) echo [jt.s] `=sink`(jt, ri_1) - wasMoved(ri_1) + `=wasMoved`(ri_1) finally: `=destroy`(ri_1) finally: `=destroy`(jt) --- end of expandArc ------------------------''' +-- end of expandArc ------------------------ +''' """ type diff --git a/tests/arc/topt_wasmoved_destroy_pairs.nim b/tests/arc/topt_wasmoved_destroy_pairs.nim index 2f971f112..6577d6787 100644 --- a/tests/arc/topt_wasmoved_destroy_pairs.nim +++ b/tests/arc/topt_wasmoved_destroy_pairs.nim @@ -1,7 +1,8 @@ discard """ output: '''''' cmd: '''nim c --gc:arc --expandArc:main --expandArc:tfor --hint:Performance:off $file''' - nimout: '''--expandArc: main + nimout: ''' +--expandArc: main var a @@ -29,6 +30,7 @@ try: x = f() block :tmp: var i_cursor + mixin inc var i_1 = 0 block :tmp_1: while i_1 < 4: @@ -37,25 +39,26 @@ try: if i_cursor == 2: return add(a): - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, x) :tmpD inc i_1, 1 if cond: add(a): let blitTmp = x - wasMoved(x) + `=wasMoved`(x) blitTmp else: add(b): let blitTmp_1 = x - wasMoved(x) + `=wasMoved`(x) blitTmp_1 finally: `=destroy`(x) `=destroy_1`(b) `=destroy_1`(a) --- end of expandArc ------------------------''' +-- end of expandArc ------------------------ +''' """ proc f(): seq[int] = diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 917cf0eb3..6fa419996 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -4,7 +4,8 @@ discard """ @[1953719668, 875770417] destroying O1''' cmd: '''nim c --gc:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file''' - nimout: '''--expandArc: main + nimout: ''' +--expandArc: main var data @@ -12,7 +13,7 @@ var :tmpD_1 :tmpD_2 data = - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, cast[string]( :tmpD_2 = encode(cast[seq[byte]]( :tmpD_1 = newString(100) @@ -32,7 +33,7 @@ var :tmpD_1 s = newString(100) data = - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, cast[string]( :tmpD_1 = encode(toOpenArrayByte(s, 0, len(s) - 1)) :tmpD_1)) @@ -50,7 +51,7 @@ var :tmpD_1 s = newSeq(100) data = - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, cast[string]( :tmpD_1 = encode(s) :tmpD_1)) @@ -67,7 +68,7 @@ var :tmpD_1 :tmpD_2 data = - wasMoved(:tmpD) + `=wasMoved`(:tmpD) `=copy`(:tmpD, cast[string]( :tmpD_2 = encode do: :tmpD_1 = newSeq(100) @@ -77,7 +78,8 @@ data = `=destroy`(:tmpD_2) `=destroy`(:tmpD_1) `=destroy_1`(data) --- end of expandArc ------------------------''' +-- end of expandArc ------------------------ +''' """ func encode*(src: openArray[byte]): seq[byte] = diff --git a/tests/destructor/twasmoved_error.nim b/tests/destructor/twasmoved_error.nim new file mode 100644 index 000000000..1cd57e3df --- /dev/null +++ b/tests/destructor/twasmoved_error.nim @@ -0,0 +1,37 @@ +discard """ + cmd: '''nim c --mm:arc $file''' + errormsg: "'=wasMoved' is not available for type ; routine: main" +""" + +# bug #19291 + +const + screenWidth = 800 + screenHeight = 450 + +var + ready = false +type + Game = object + +proc `=destroy`(x: var Game) = + assert ready, "Window is already opened" + ready = false + +proc `=sink`(x: var Game; y: Game) {.error.} +proc `=copy`(x: var Game; y: Game) {.error.} +proc `=wasMoved`(x: var Game) {.error.} + +proc initGame(width, height: int32, title: string): Game = + assert not ready, "Window is already closed" + ready = true + +proc update(x: Game) = discard + +proc main = + var g = initGame(screenWidth, screenHeight, "Tetris raylib") + g.update() + var g2 = g + echo "hello" + +main() From 9b5ae2b2eb2ba5aca219de109b03f1bb5637a777 Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Thu, 2 Mar 2023 06:30:55 +0200 Subject: [PATCH 4228/4254] Define the version of nim package without using system module (#21415) This is follow up from https://github.com/nim-lang/Nim/pull/21313 --- nim.nimble | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nim.nimble b/nim.nimble index 713fc9256..380ffbce8 100644 --- a/nim.nimble +++ b/nim.nimble @@ -1,4 +1,5 @@ -version = system.NimVersion +include "lib/system/compilation.nim" +version = $NimMajor & "." & $NimMinor & "." & $NimPatch author = "Andreas Rumpf" description = "Compiler package providing the compiler sources as a library." license = "MIT" From 612abda4f40b2a0fd8dd0e4ad119c4415b9c34cb Mon Sep 17 00:00:00 2001 From: tersec Date: Thu, 2 Mar 2023 04:51:54 +0000 Subject: [PATCH 4229/4254] remove decades-deprecated Win32 API *A function support (#21315) --- lib/pure/asyncfile.nim | 11 +- lib/pure/browsers.nim | 2 +- lib/pure/memfiles.nim | 7 +- lib/pure/os.nim | 93 ++++-------- lib/pure/osproc.nim | 35 ++--- lib/std/cmdline.nim | 5 +- lib/std/private/oscommon.nim | 65 +++------ lib/std/private/osdirs.nim | 17 +-- lib/std/private/osfiles.nim | 43 ++---- lib/std/private/ospaths2.nim | 35 ++--- lib/std/private/ossymlinks.nim | 12 +- lib/std/syncio.nim | 4 +- lib/windows/winlean.nim | 258 ++++++++++----------------------- 13 files changed, 173 insertions(+), 414 deletions(-) diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 88fa90406..96d5e6d2e 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -102,14 +102,9 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile = let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL let desiredAccess = getDesiredAccess(mode) let creationDisposition = getCreationDisposition(mode, filename) - when useWinUnicode: - let fd = createFileW(newWideCString(filename), desiredAccess, - FILE_SHARE_READ, - nil, creationDisposition, flags, 0) - else: - let fd = createFileA(filename, desiredAccess, - FILE_SHARE_READ, - nil, creationDisposition, flags, 0) + let fd = createFileW(newWideCString(filename), desiredAccess, + FILE_SHARE_READ, + nil, creationDisposition, flags, 0) if fd == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index b78034fe3..ab248db36 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -21,7 +21,7 @@ when defined(nimPreviewSlimSystem): when defined(windows): import winlean - when useWinUnicode and defined(nimPreviewSlimSystem): + when defined(nimPreviewSlimSystem): import std/widestrs from os import absolutePath else: diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 58c4888f1..74065bc2e 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -17,7 +17,7 @@ when defined(windows): import winlean - when useWinUnicode and defined(nimPreviewSlimSystem): + when defined(nimPreviewSlimSystem): import std/widestrs elif defined(posix): import posix @@ -199,10 +199,7 @@ proc open*(filename: string, mode: FileMode = fmRead, else: FILE_ATTRIBUTE_NORMAL or flags, 0) - when useWinUnicode: - result.fHandle = callCreateFile(createFileW, newWideCString(filename)) - else: - result.fHandle = callCreateFile(createFileA, filename) + result.fHandle = callCreateFile(createFileW, newWideCString(filename)) if result.fHandle == INVALID_HANDLE_VALUE: fail(osLastError(), "error opening file") diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 3285c07df..0569e6cab 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -422,32 +422,18 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", ## Raises `OSError` in case of an error. Follows symlinks. when defined(windows): var bufsize = MAX_PATH.int32 - when useWinUnicode: - var unused: WideCString = nil - var res = newWideCString("", bufsize) - while true: - var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused) - if L == 0'i32: - raiseOSError(osLastError(), filename) - elif L > bufsize: - res = newWideCString("", L) - bufsize = L - else: - result = res$L - break - else: - var unused: cstring = nil - result = newString(bufsize) - while true: - var L = getFullPathNameA(filename, bufsize, result, unused) - if L == 0'i32: - raiseOSError(osLastError(), filename) - elif L > bufsize: - result = newString(L) - bufsize = L - else: - setLen(result, L) - break + var unused: WideCString = nil + var res = newWideCString("", bufsize) + while true: + var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused) + if L == 0'i32: + raiseOSError(osLastError(), filename) + elif L > bufsize: + res = newWideCString("", L) + bufsize = L + else: + result = res$L + break # getFullPathName doesn't do case corrections, so we have to use this convoluted # way of retrieving the true filename for x in walkFiles(result): @@ -483,14 +469,10 @@ proc createHardlink*(src, dest: string) {.noWeirdTarget.} = ## See also: ## * `createSymlink proc`_ when defined(windows): - when useWinUnicode: - var wSrc = newWideCString(src) - var wDst = newWideCString(dest) - if createHardLinkW(wDst, wSrc, nil) == 0: - raiseOSError(osLastError(), $(src, dest)) - else: - if createHardLinkA(dest, src, nil) == 0: - raiseOSError(osLastError(), $(src, dest)) + var wSrc = newWideCString(src) + var wDst = newWideCString(dest) + if createHardLinkW(wDst, wSrc, nil) == 0: + raiseOSError(osLastError(), $(src, dest)) else: if link(src, dest) != 0: raiseOSError(osLastError(), $(src, dest)) @@ -655,32 +637,18 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW # /proc//path/a.out (complete pathname) when defined(windows): var bufsize = int32(MAX_PATH) - when useWinUnicode: - var buf = newWideCString("", bufsize) - while true: - var L = getModuleFileNameW(0, buf, bufsize) - if L == 0'i32: - result = "" # error! - break - elif L > bufsize: - buf = newWideCString("", L) - bufsize = L - else: - result = buf$L - break - else: - result = newString(bufsize) - while true: - var L = getModuleFileNameA(0, result, bufsize) - if L == 0'i32: - result = "" # error! - break - elif L > bufsize: - result = newString(L) - bufsize = L - else: - setLen(result, L) - break + var buf = newWideCString("", bufsize) + while true: + var L = getModuleFileNameW(0, buf, bufsize) + if L == 0'i32: + result = "" # error! + break + elif L > bufsize: + buf = newWideCString("", L) + bufsize = L + else: + result = buf$L + break elif defined(macosx): var size = cuint32(0) getExecPath1(nil, size) @@ -977,10 +945,7 @@ proc isHidden*(path: string): bool {.noWeirdTarget.} = assert ".foo/".isHidden when defined(windows): - when useWinUnicode: - wrapUnary(attributes, getFileAttributesW, path) - else: - var attributes = getFileAttributesA(path) + wrapUnary(attributes, getFileAttributesW, path) if attributes != -1'i32: result = (attributes and FILE_ATTRIBUTE_HIDDEN) != 0'i32 else: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index bb6abc571..4cdd98c0d 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -714,22 +714,15 @@ when defined(windows) and not defined(useNimRtl): if len(workingDir) > 0: wd = workingDir if env != nil: e = buildEnv(env) if poEchoCmd in options: echo($cmdl) - when useWinUnicode: - var tmp = newWideCString(cmdl) - var ee = - if e.str.isNil: newWideCString(cstring(nil)) - else: newWideCString(e.str, e.len) - var wwd = newWideCString(wd) - var flags = NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT - if poDaemon in options: flags = flags or CREATE_NO_WINDOW - success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags, - ee, wwd, si, procInfo) - else: - var ee = - if e.str.isNil: cstring(nil) - else: cstring(e.str) - success = winlean.createProcessA(nil, - cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, ee, wd, si, procInfo) + var tmp = newWideCString(cmdl) + var ee = + if e.str.isNil: newWideCString(cstring(nil)) + else: newWideCString(e.str, e.len) + var wwd = newWideCString(wd) + var flags = NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT + if poDaemon in options: flags = flags or CREATE_NO_WINDOW + success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags, + ee, wwd, si, procInfo) let lastError = osLastError() if poParentStreams notin options: @@ -870,13 +863,9 @@ when defined(windows) and not defined(useNimRtl): si.hStdError = getStdHandle(STD_ERROR_HANDLE) si.hStdInput = getStdHandle(STD_INPUT_HANDLE) si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE) - when useWinUnicode: - var c = newWideCString(command) - var res = winlean.createProcessW(nil, c, nil, nil, 0, - NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) - else: - var res = winlean.createProcessA(nil, command, nil, nil, 0, - NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) + var c = newWideCString(command) + var res = winlean.createProcessW(nil, c, nil, nil, 0, + NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) if res == 0: raiseOSError(osLastError()) else: diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim index 3208da1b8..6788dacde 100644 --- a/lib/std/cmdline.nim +++ b/lib/std/cmdline.nim @@ -40,10 +40,7 @@ else: # Needed by windows in order to obtain the command line for targets # other than command line targets when defined(windows) and not weirdTarget: - when useWinUnicode: - template getCommandLine*(): untyped = getCommandLineW() - else: - template getCommandLine*(): untyped = getCommandLineA() + template getCommandLine*(): untyped = getCommandLineW() proc parseCmdLine*(c: string): seq[string] {. diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim index 3aac58636..b747e33f1 100644 --- a/lib/std/private/oscommon.nim +++ b/lib/std/private/oscommon.nim @@ -47,23 +47,17 @@ else: when defined(windows) and not weirdTarget: - when useWinUnicode: - template wrapUnary*(varname, winApiProc, arg: untyped) = - var varname = winApiProc(newWideCString(arg)) + template wrapUnary*(varname, winApiProc, arg: untyped) = + var varname = winApiProc(newWideCString(arg)) - template wrapBinary*(varname, winApiProc, arg, arg2: untyped) = - var varname = winApiProc(newWideCString(arg), arg2) - proc findFirstFile*(a: string, b: var WIN32_FIND_DATA): Handle = - result = findFirstFileW(newWideCString(a), b) - template findNextFile*(a, b: untyped): untyped = findNextFileW(a, b) + template wrapBinary*(varname, winApiProc, arg, arg2: untyped) = + var varname = winApiProc(newWideCString(arg), arg2) + proc findFirstFile*(a: string, b: var WIN32_FIND_DATA): Handle = + result = findFirstFileW(newWideCString(a), b) + template findNextFile*(a, b: untyped): untyped = findNextFileW(a, b) - template getFilename*(f: untyped): untyped = - $cast[WideCString](addr(f.cFileName[0])) - else: - template findFirstFile*(a, b: untyped): untyped = findFirstFileA(a, b) - template findNextFile*(a, b: untyped): untyped = findNextFileA(a, b) - - template getFilename*(f: untyped): untyped = $cast[cstring](addr f.cFileName) + template getFilename*(f: untyped): untyped = + $cast[WideCString](addr(f.cFileName[0])) proc skipFindData*(f: WIN32_FIND_DATA): bool {.inline.} = # Note - takes advantage of null delimiter in the cstring @@ -104,12 +98,9 @@ proc tryMoveFSObject*(source, dest: string, isDir: bool): bool {.noWeirdTarget.} ## In case of other errors `OSError` is raised. ## Returns true in case of success. when defined(windows): - when useWinUnicode: - let s = newWideCString(source) - let d = newWideCString(dest) - result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32 - else: - result = moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32 + let s = newWideCString(source) + let d = newWideCString(dest) + result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32 else: result = c_rename(source, dest) == 0'i32 @@ -137,10 +128,7 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", ## * `dirExists proc`_ ## * `symlinkExists proc`_ when defined(windows): - when useWinUnicode: - wrapUnary(a, getFileAttributesW, filename) - else: - var a = getFileAttributesA(filename) + wrapUnary(a, getFileAttributesW, filename) if a != -1'i32: result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32 else: @@ -157,10 +145,7 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect] ## * `fileExists proc`_ ## * `symlinkExists proc`_ when defined(windows): - when useWinUnicode: - wrapUnary(a, getFileAttributesW, dir) - else: - var a = getFileAttributesA(dir) + wrapUnary(a, getFileAttributesW, dir) if a != -1'i32: result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32 else: @@ -178,10 +163,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", ## * `fileExists proc`_ ## * `dirExists proc`_ when defined(windows): - when useWinUnicode: - wrapUnary(a, getFileAttributesW, link) - else: - var a = getFileAttributesA(link) + wrapUnary(a, getFileAttributesW, link) if a != -1'i32: # xxx see: bug #16784 (bug9); checking `IO_REPARSE_TAG_SYMLINK` # may also be needed. @@ -197,15 +179,8 @@ when defined(windows) and not weirdTarget: flags = flags or FILE_FLAG_OPEN_REPARSE_POINT let access = if writeAccess: GENERIC_WRITE else: 0'i32 - when useWinUnicode: - result = createFileW( - newWideCString(path), access, - FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, - nil, OPEN_EXISTING, flags, 0 - ) - else: - result = createFileA( - path, access, - FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, - nil, OPEN_EXISTING, flags, 0 - ) + result = createFileW( + newWideCString(path), access, + FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, + nil, OPEN_EXISTING, flags, 0 + ) diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index 4af418ead..a4318367d 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -328,10 +328,7 @@ iterator walkDirRec*(dir: string, proc rawRemoveDir(dir: string) {.noWeirdTarget.} = when defined(windows): - when useWinUnicode: - wrapUnary(res, removeDirectoryW, dir) - else: - var res = removeDirectoryA(dir) + wrapUnary(res, removeDirectoryW, dir) let lastError = osLastError() if res == 0'i32 and lastError.int32 != 3'i32 and lastError.int32 != 18'i32 and lastError.int32 != 2'i32: @@ -396,10 +393,7 @@ proc rawCreateDir(dir: string): bool {.noWeirdTarget.} = #echo res raiseOSError(osLastError(), dir) else: - when useWinUnicode: - wrapUnary(res, createDirectoryW, dir) - else: - let res = createDirectoryA(dir) + wrapUnary(res, createDirectoryW, dir) if res != 0'i32: result = true @@ -561,10 +555,7 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} = ## * `getTempDir proc`_ ## * `getCurrentDir proc`_ when defined(windows): - when useWinUnicode: - if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: - raiseOSError(osLastError(), newDir) - else: - if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError(), newDir) + if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: + raiseOSError(osLastError(), newDir) else: if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir) diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index a7a595d97..7f822ffcc 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -84,10 +84,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {. if (a.st_mode and S_IWOTH.Mode) != 0.Mode: result.incl(fpOthersWrite) if (a.st_mode and S_IXOTH.Mode) != 0.Mode: result.incl(fpOthersExec) else: - when useWinUnicode: - wrapUnary(res, getFileAttributesW, filename) - else: - var res = getFileAttributesA(filename) + wrapUnary(res, getFileAttributesW, filename) if res == -1'i32: raiseOSError(osLastError(), filename) if (res and FILE_ATTRIBUTE_READONLY) != 0'i32: result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, @@ -136,19 +133,13 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission], if chmod(filename, cast[Mode](p)) != 0: raiseOSError(osLastError(), $(filename, permissions)) else: - when useWinUnicode: - wrapUnary(res, getFileAttributesW, filename) - else: - var res = getFileAttributesA(filename) + wrapUnary(res, getFileAttributesW, filename) if res == -1'i32: raiseOSError(osLastError(), filename) if fpUserWrite in permissions: res = res and not FILE_ATTRIBUTE_READONLY else: res = res or FILE_ATTRIBUTE_READONLY - when useWinUnicode: - wrapBinary(res2, setFileAttributesW, filename, res) - else: - var res2 = setFileAttributesA(filename, res) + wrapBinary(res2, setFileAttributesW, filename, res) if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions)) @@ -221,14 +212,10 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl, if isSymlink and (cfSymlinkIgnore in options or defined(windows)): return when defined(windows): - when useWinUnicode: - let s = newWideCString(source) - let d = newWideCString(dest) - if copyFileW(s, d, 0'i32) == 0'i32: - raiseOSError(osLastError(), $(source, dest)) - else: - if copyFileA(source, dest, 0'i32) == 0'i32: - raiseOSError(osLastError(), $(source, dest)) + let s = newWideCString(source) + let d = newWideCString(dest) + if copyFileW(s, d, 0'i32) == 0'i32: + raiseOSError(osLastError(), $(source, dest)) else: if isSymlink and cfSymlinkAsIs in options: createSymlink(expandSymlink(source), dest) @@ -334,14 +321,9 @@ when not declared(ENOENT) and not defined(windows): var ENOENT {.importc, header: "".}: cint when defined(windows) and not weirdTarget: - when useWinUnicode: - template deleteFile(file: untyped): untyped = deleteFileW(file) - template setFileAttributes(file, attrs: untyped): untyped = - setFileAttributesW(file, attrs) - else: - template deleteFile(file: untyped): untyped = deleteFileA(file) - template setFileAttributes(file, attrs: untyped): untyped = - setFileAttributesA(file, attrs) + template deleteFile(file: untyped): untyped = deleteFileW(file) + template setFileAttributes(file, attrs: untyped): untyped = + setFileAttributesW(file, attrs) proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = ## Removes the `file`. @@ -358,10 +340,7 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE ## * `moveFile proc`_ result = true when defined(windows): - when useWinUnicode: - let f = newWideCString(file) - else: - let f = file + let f = newWideCString(file) if deleteFile(f) == 0: result = false let err = getLastError() diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 78a806675..612003023 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -849,30 +849,17 @@ when not defined(nimscript): doAssert false, "use -d:nodejs to have `getCurrentDir` defined" elif defined(windows): var bufsize = MAX_PATH.int32 - when useWinUnicode: - var res = newWideCString("", bufsize) - while true: - var L = getCurrentDirectoryW(bufsize, res) - if L == 0'i32: - raiseOSError(osLastError()) - elif L > bufsize: - res = newWideCString("", L) - bufsize = L - else: - result = res$L - break - else: - result = newString(bufsize) - while true: - var L = getCurrentDirectoryA(bufsize, result) - if L == 0'i32: - raiseOSError(osLastError()) - elif L > bufsize: - result = newString(L) - bufsize = L - else: - setLen(result, L) - break + var res = newWideCString("", bufsize) + while true: + var L = getCurrentDirectoryW(bufsize, res) + if L == 0'i32: + raiseOSError(osLastError()) + elif L > bufsize: + res = newWideCString("", L) + bufsize = L + else: + result = res$L + break else: var bufsize = 1024 # should be enough result = newString(bufsize) diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim index 6b2de6237..18737b8b5 100644 --- a/lib/std/private/ossymlinks.nim +++ b/lib/std/private/ossymlinks.nim @@ -48,14 +48,10 @@ proc createSymlink*(src, dest: string) {.noWeirdTarget.} = const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2 # allows anyone with developer mode on to create a link let flag = dirExists(src).int32 or SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE - when useWinUnicode: - var wSrc = newWideCString(src) - var wDst = newWideCString(dest) - if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0: - raiseOSError(osLastError(), $(src, dest)) - else: - if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0: - raiseOSError(osLastError(), $(src, dest)) + var wSrc = newWideCString(src) + var wDst = newWideCString(dest) + if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0: + raiseOSError(osLastError(), $(src, dest)) else: if symlink(src, dest) != 0: raiseOSError(osLastError(), $(src, dest)) diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index 83b2d6d13..77d4fa04c 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -390,7 +390,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], proc c_memchr(s: pointer, c: cint, n: csize_t): pointer {. importc: "memchr", header: "".} - when defined(windows) and not defined(useWinAnsi): + when defined(windows): proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer, nNumberOfCharsToRead: int32, lpNumberOfCharsRead: ptr int32, @@ -612,7 +612,7 @@ proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, # interface to the C procs: -when defined(windows) and not defined(useWinAnsi): +when defined(windows): when defined(cpp): proc wfopen(filename, mode: WideCString): pointer {. importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.} diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 230f963f0..f8c6ce021 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -21,13 +21,7 @@ when defined(nimPreviewSlimSystem): from std/syncio import FileHandle import std/widestrs -const - useWinUnicode* = not defined(useWinAnsi) - -when useWinUnicode: - type WinChar* = Utf16Char -else: - type WinChar* = char +type WinChar* = Utf16Char # See https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types type @@ -184,26 +178,14 @@ proc peekNamedPipe*(hNamedPipe: Handle, lpBuffer: pointer=nil, lpBytesLeftThisMessage: ptr int32 = nil): bool {. stdcall, dynlib: "kernel32", importc: "PeekNamedPipe".} -when useWinUnicode: - proc createProcessW*(lpApplicationName, lpCommandLine: WideCString, - lpProcessAttributes: ptr SECURITY_ATTRIBUTES, - lpThreadAttributes: ptr SECURITY_ATTRIBUTES, - bInheritHandles: WINBOOL, dwCreationFlags: int32, - lpEnvironment, lpCurrentDirectory: WideCString, - lpStartupInfo: var STARTUPINFO, - lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{. - stdcall, dynlib: "kernel32", importc: "CreateProcessW", sideEffect.} - -else: - proc createProcessA*(lpApplicationName, lpCommandLine: cstring, - lpProcessAttributes: ptr SECURITY_ATTRIBUTES, - lpThreadAttributes: ptr SECURITY_ATTRIBUTES, - bInheritHandles: WINBOOL, dwCreationFlags: int32, - lpEnvironment: pointer, lpCurrentDirectory: cstring, - lpStartupInfo: var STARTUPINFO, - lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{. - stdcall, dynlib: "kernel32", importc: "CreateProcessA", sideEffect.} - +proc createProcessW*(lpApplicationName, lpCommandLine: WideCString, + lpProcessAttributes: ptr SECURITY_ATTRIBUTES, + lpThreadAttributes: ptr SECURITY_ATTRIBUTES, + bInheritHandles: WINBOOL, dwCreationFlags: int32, + lpEnvironment, lpCurrentDirectory: WideCString, + lpStartupInfo: var STARTUPINFO, + lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "CreateProcessW", sideEffect.} proc suspendThread*(hThread: Handle): int32 {.stdcall, dynlib: "kernel32", importc: "SuspendThread", sideEffect.} @@ -232,67 +214,37 @@ proc getLastError*(): int32 {.importc: "GetLastError", proc setLastError*(error: int32) {.importc: "SetLastError", stdcall, dynlib: "kernel32", sideEffect.} -when useWinUnicode: - proc formatMessageW*(dwFlags: int32, lpSource: pointer, - dwMessageId, dwLanguageId: int32, - lpBuffer: pointer, nSize: int32, - arguments: pointer): int32 {. - importc: "FormatMessageW", stdcall, dynlib: "kernel32".} -else: - proc formatMessageA*(dwFlags: int32, lpSource: pointer, +proc formatMessageW*(dwFlags: int32, lpSource: pointer, dwMessageId, dwLanguageId: int32, lpBuffer: pointer, nSize: int32, arguments: pointer): int32 {. - importc: "FormatMessageA", stdcall, dynlib: "kernel32".} + importc: "FormatMessageW", stdcall, dynlib: "kernel32".} proc localFree*(p: pointer) {. importc: "LocalFree", stdcall, dynlib: "kernel32".} -when useWinUnicode: - proc getCurrentDirectoryW*(nBufferLength: int32, - lpBuffer: WideCString): int32 {. - importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} - proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {. - importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} - proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {. - importc: "CreateDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} - proc removeDirectoryW*(lpPathName: WideCString): int32 {. - importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} - proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {. - stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW", sideEffect.} +proc getCurrentDirectoryW*(nBufferLength: int32, + lpBuffer: WideCString): int32 {. + importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} +proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {. + importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} +proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {. + importc: "CreateDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} +proc removeDirectoryW*(lpPathName: WideCString): int32 {. + importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall, sideEffect.} +proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {. + stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW", sideEffect.} - proc getModuleFileNameW*(handle: Handle, buf: WideCString, - size: int32): int32 {.importc: "GetModuleFileNameW", - dynlib: "kernel32", stdcall.} -else: - proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {. - importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} - proc setCurrentDirectoryA*(lpPathName: cstring): int32 {. - importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} - proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {. - importc: "CreateDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} - proc removeDirectoryA*(lpPathName: cstring): int32 {. - importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall, sideEffect.} - proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {. - stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA", sideEffect.} +proc getModuleFileNameW*(handle: Handle, buf: WideCString, + size: int32): int32 {.importc: "GetModuleFileNameW", + dynlib: "kernel32", stdcall.} - proc getModuleFileNameA*(handle: Handle, buf: cstring, size: int32): int32 {. - importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.} - -when useWinUnicode: - proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString, - flags: DWORD): int32 {. - importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall, sideEffect.} - proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString, - security: pointer=nil): int32 {. - importc:"CreateHardLinkW", dynlib: "kernel32", stdcall, sideEffect.} -else: - proc createSymbolicLinkA*(lpSymlinkFileName, lpTargetFileName: cstring, - flags: DWORD): int32 {. - importc:"CreateSymbolicLinkA", dynlib: "kernel32", stdcall, sideEffect.} - proc createHardLinkA*(lpFileName, lpExistingFileName: cstring, - security: pointer=nil): int32 {. - importc:"CreateHardLinkA", dynlib: "kernel32", stdcall, sideEffect.} +proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString, + flags: DWORD): int32 {. + importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall, sideEffect.} +proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString, + security: pointer=nil): int32 {. + importc:"CreateHardLinkW", dynlib: "kernel32", stdcall, sideEffect.} const FILE_ATTRIBUTE_READONLY* = 0x00000001'i32 @@ -343,84 +295,45 @@ type cFileName*: array[0..(MAX_PATH) - 1, WinChar] cAlternateFileName*: array[0..13, WinChar] -when useWinUnicode: - proc findFirstFileW*(lpFileName: WideCString, - lpFindFileData: var WIN32_FIND_DATA): Handle {. - stdcall, dynlib: "kernel32", importc: "FindFirstFileW", sideEffect.} - proc findNextFileW*(hFindFile: Handle, - lpFindFileData: var WIN32_FIND_DATA): int32 {. - stdcall, dynlib: "kernel32", importc: "FindNextFileW", sideEffect.} -else: - proc findFirstFileA*(lpFileName: cstring, - lpFindFileData: var WIN32_FIND_DATA): Handle {. - stdcall, dynlib: "kernel32", importc: "FindFirstFileA", sideEffect.} - proc findNextFileA*(hFindFile: Handle, - lpFindFileData: var WIN32_FIND_DATA): int32 {. - stdcall, dynlib: "kernel32", importc: "FindNextFileA", sideEffect.} +proc findFirstFileW*(lpFileName: WideCString, + lpFindFileData: var WIN32_FIND_DATA): Handle {. + stdcall, dynlib: "kernel32", importc: "FindFirstFileW", sideEffect.} +proc findNextFileW*(hFindFile: Handle, + lpFindFileData: var WIN32_FIND_DATA): int32 {. + stdcall, dynlib: "kernel32", importc: "FindNextFileW", sideEffect.} proc findClose*(hFindFile: Handle) {.stdcall, dynlib: "kernel32", importc: "FindClose".} -when useWinUnicode: - proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32, - lpBuffer: WideCString, - lpFilePart: var WideCString): int32 {. +proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32, + lpBuffer: WideCString, + lpFilePart: var WideCString): int32 {. + stdcall, dynlib: "kernel32", + importc: "GetFullPathNameW", sideEffect.} +proc getFileAttributesW*(lpFileName: WideCString): int32 {. stdcall, dynlib: "kernel32", - importc: "GetFullPathNameW", sideEffect.} - proc getFileAttributesW*(lpFileName: WideCString): int32 {. - stdcall, dynlib: "kernel32", - importc: "GetFileAttributesW", sideEffect.} - proc setFileAttributesW*(lpFileName: WideCString, - dwFileAttributes: int32): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "SetFileAttributesW", sideEffect.} + importc: "GetFileAttributesW", sideEffect.} +proc setFileAttributesW*(lpFileName: WideCString, + dwFileAttributes: int32): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "SetFileAttributesW", sideEffect.} - proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString, - bFailIfExists: WINBOOL): WINBOOL {. - importc: "CopyFileW", stdcall, dynlib: "kernel32", sideEffect.} +proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString, + bFailIfExists: WINBOOL): WINBOOL {. + importc: "CopyFileW", stdcall, dynlib: "kernel32", sideEffect.} - proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {. - importc: "MoveFileW", stdcall, dynlib: "kernel32", sideEffect.} - proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString, - flags: DWORD): WINBOOL {. - importc: "MoveFileExW", stdcall, dynlib: "kernel32", sideEffect.} +proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {. + importc: "MoveFileW", stdcall, dynlib: "kernel32", sideEffect.} +proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString, + flags: DWORD): WINBOOL {. + importc: "MoveFileExW", stdcall, dynlib: "kernel32", sideEffect.} - proc getEnvironmentStringsW*(): WideCString {. - stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW", sideEffect.} - proc freeEnvironmentStringsW*(para1: WideCString): int32 {. - stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW", sideEffect.} +proc getEnvironmentStringsW*(): WideCString {. + stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW", sideEffect.} +proc freeEnvironmentStringsW*(para1: WideCString): int32 {. + stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW", sideEffect.} - proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW", - stdcall, dynlib: "kernel32", sideEffect.} - -else: - proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32, - lpBuffer: cstring, lpFilePart: var cstring): int32 {. - stdcall, dynlib: "kernel32", - importc: "GetFullPathNameA", sideEffect.} - proc getFileAttributesA*(lpFileName: cstring): int32 {. - stdcall, dynlib: "kernel32", - importc: "GetFileAttributesA", sideEffect.} - proc setFileAttributesA*(lpFileName: cstring, - dwFileAttributes: int32): WINBOOL {. - stdcall, dynlib: "kernel32", importc: "SetFileAttributesA", sideEffect.} - - proc copyFileA*(lpExistingFileName, lpNewFileName: cstring, - bFailIfExists: cint): cint {. - importc: "CopyFileA", stdcall, dynlib: "kernel32", sideEffect.} - - proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {. - importc: "MoveFileA", stdcall, dynlib: "kernel32", sideEffect.} - proc moveFileExA*(lpExistingFileName, lpNewFileName: cstring, - flags: DWORD): WINBOOL {. - importc: "MoveFileExA", stdcall, dynlib: "kernel32", sideEffect.} - - proc getEnvironmentStringsA*(): cstring {. - stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA", sideEffect.} - proc freeEnvironmentStringsA*(para1: cstring): int32 {. - stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsA", sideEffect.} - - proc getCommandLineA*(): cstring {. - importc: "GetCommandLineA", stdcall, dynlib: "kernel32", sideEffect.} +proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW", + stdcall, dynlib: "kernel32", sideEffect.} proc rdFileTime*(f: FILETIME): int64 = result = int64(cast[uint32](f.dwLowDateTime)) or (int64(cast[uint32](f.dwHighDateTime)) shl 32) @@ -434,17 +347,10 @@ proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {. proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32", importc: "Sleep", sideEffect.} -when useWinUnicode: - proc shellExecuteW*(hwnd: Handle, lpOperation, lpFile, - lpParameters, lpDirectory: WideCString, - nShowCmd: int32): Handle{. - stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW", sideEffect.} - -else: - proc shellExecuteA*(hwnd: Handle, lpOperation, lpFile, - lpParameters, lpDirectory: cstring, - nShowCmd: int32): Handle{. - stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA", sideEffect.} +proc shellExecuteW*(hwnd: Handle, lpOperation, lpFile, + lpParameters, lpDirectory: WideCString, + nShowCmd: int32): Handle{. + stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW", sideEffect.} proc getFileInformationByHandle*(hFile: Handle, lpFileInformation: ptr BY_HANDLE_FILE_INFORMATION): WINBOOL{. @@ -794,13 +700,6 @@ proc createFileMappingW*(hFile: Handle, lpName: pointer): Handle {. stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".} -when not useWinUnicode: - proc createFileMappingA*(hFile: Handle, - lpFileMappingAttributes: pointer, - flProtect, dwMaximumSizeHigh: DWORD, - dwMaximumSizeLow: DWORD, lpName: cstring): Handle {. - stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".} - proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall, dynlib: "kernel32", importc: "UnmapViewOfFile".} @@ -976,7 +875,7 @@ proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, stringBufSize: int32): cstring {.stdcall.} = var ver: OSVERSIONINFO ver.dwOSVersionInfoSize = sizeof(ver).DWORD - let res = when useWinUnicode: getVersionExW(ver.addr) else: getVersionExA(ver.addr) + let res = getVersionExW(ver.addr) if res == 0: result = nil elif ver.dwMajorVersion >= 6: @@ -1060,16 +959,10 @@ proc openProcess*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, dwProcessId: DWORD): Handle {.stdcall, dynlib: "kernel32", importc: "OpenProcess".} -when defined(useWinAnsi): - proc createEvent*(lpEventAttributes: ptr SECURITY_ATTRIBUTES, - bManualReset: DWORD, bInitialState: DWORD, - lpName: cstring): Handle - {.stdcall, dynlib: "kernel32", importc: "CreateEventA".} -else: - proc createEvent*(lpEventAttributes: ptr SECURITY_ATTRIBUTES, - bManualReset: DWORD, bInitialState: DWORD, - lpName: ptr Utf16Char): Handle - {.stdcall, dynlib: "kernel32", importc: "CreateEventW".} +proc createEvent*(lpEventAttributes: ptr SECURITY_ATTRIBUTES, + bManualReset: DWORD, bInitialState: DWORD, + lpName: ptr Utf16Char): Handle + {.stdcall, dynlib: "kernel32", importc: "CreateEventW".} proc setEvent*(hEvent: Handle): cint {.stdcall, dynlib: "kernel32", importc: "SetEvent".} @@ -1110,14 +1003,9 @@ type uChar*: int16 dwControlKeyState*: DWORD -when defined(useWinAnsi): - proc readConsoleInput*(hConsoleInput: Handle, lpBuffer: pointer, nLength: cint, - lpNumberOfEventsRead: ptr cint): cint - {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputA".} -else: - proc readConsoleInput*(hConsoleInput: Handle, lpBuffer: pointer, nLength: cint, - lpNumberOfEventsRead: ptr cint): cint - {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} +proc readConsoleInput*(hConsoleInput: Handle, lpBuffer: pointer, nLength: cint, + lpNumberOfEventsRead: ptr cint): cint + {.stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} type LPFIBER_START_ROUTINE* = proc (param: pointer) {.stdcall.} From 50baf21eacfaf1c9d6949bf2b2e9f931b0e1509c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 2 Mar 2023 08:36:02 +0100 Subject: [PATCH 4230/4254] =?UTF-8?q?fixes=20#20422;=20emit=20nimPrepareSt?= =?UTF-8?q?rMutationV2=20for=20toOpenArray=20to=20keep=20th=E2=80=A6=20(#2?= =?UTF-8?q?1459)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #20422; emit nimPrepareStrMutationV2 for toOpenArray to keep the abstraction of mutable strings which have immutable string literals --- compiler/ccgcalls.nim | 4 +++- compiler/ccgexprs.nim | 5 ++++- tests/arc/topenarray.nim | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 9993322fb..48e7fd290 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -156,7 +156,7 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} = else: result = true -proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) = +proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) = var a, b, c: TLoc initLocExpr(p, q[1], a) initLocExpr(p, q[2], b) @@ -164,6 +164,8 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, # but first produce the required index checks: if optBoundsCheck in p.options: genBoundsCheck(p, a, b, c) + if prepareForMutation: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) let ty = skipTypes(a.t, abstractVar+{tyPtr}) let dest = getTypeDesc(p.module, destType) let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)] diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index fe7cb252e..f428324b7 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2408,7 +2408,10 @@ proc genDispose(p: BProc; n: PNode) = lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)]) proc genSlice(p: BProc; e: PNode; d: var TLoc) = - let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon) + let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon, + prepareForMutation = e[1].kind == nkHiddenDeref and + e[1].typ.skipTypes(abstractInst).kind == tyString and + p.config.selectedGC in {gcArc, gcOrc}) if d.k == locNone: getTemp(p, e.typ, d) linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y]) when false: diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim index 47c26a11f..0e45f3ec7 100644 --- a/tests/arc/topenarray.nim +++ b/tests/arc/topenarray.nim @@ -6,6 +6,8 @@ Nim ''' matrix: "--gc:arc -d:useMalloc; --gc:arc" """ +{.experimental: "views".} + block: # bug 18627 proc setPosition(params: openArray[string]) = for i in params.toOpenArray(0, params.len - 1): @@ -38,3 +40,13 @@ block: # bug #20954 var v: seq[int] echo len(toOpenArray(v, 20, 30)) + +# bug #20422 + +proc f(a: var string) = + var v = a.toOpenArray(1, 3) + v[0] = 'a' + +var a = "Hello" +f(a) +doAssert a == "Hallo" From 38d299dfc0c9f1315cf412aa76cb041642d62f07 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:16:28 +0800 Subject: [PATCH 4231/4254] fixes #20139; hash types based on its path relative to its package path (#21274) [backport:1.6] * fixes #20139; hash types based on its path relative its project * add a test case * fixes procs * better implementation and test case --------- Co-authored-by: Andreas Rumpf --- compiler/ccgexprs.nim | 4 +- compiler/ccgstmts.nim | 6 +-- compiler/ccgtypes.nim | 38 +++++++-------- compiler/cgen.nim | 2 +- compiler/injectdestructors.nim | 2 +- compiler/jsgen.nim | 4 +- compiler/liftdestructors.nim | 4 +- compiler/pathutils.nim | 51 +++++++++++++++++++- compiler/sighashes.nim | 86 +++++++++++++++++----------------- compiler/vm.nim | 2 +- tests/ccgbugs/m1/defs.nim | 4 ++ tests/ccgbugs/m2/defs.nim | 4 ++ tests/ccgbugs/t20139.nim | 10 ++++ 13 files changed, 143 insertions(+), 74 deletions(-) create mode 100644 tests/ccgbugs/m1/defs.nim create mode 100644 tests/ccgbugs/m2/defs.nim create mode 100644 tests/ccgbugs/t20139.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f428324b7..a64a42219 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1704,7 +1704,7 @@ proc genNewFinalize(p: BProc, e: PNode) = proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Rope) = if optTinyRtti in p.config.globalOptions: - let token = $genDisplayElem(MD5Digest(hashType(dest))) + let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) appcg(p.module, result, "#isObjDisplayCheck($#.m_type, $#, $#)", [a, getObjDepth(dest), token]) else: # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we @@ -2779,7 +2779,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = rdMType(p, a, nilCheck, r) if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(dest) - let token = $genDisplayElem(MD5Digest(hashType(dest))) + let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) if nilCheck != "": linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ", [nilCheck, r, checkFor, token]) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index db839b21b..7ade85b42 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1081,7 +1081,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(typeNode.typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1300,7 +1300,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(t[i][j].typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1445,7 +1445,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(t[i][j].typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e7677f2f2..98c1fc55f 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -43,14 +43,14 @@ proc fillBackendName(m: BModule; s: PSym) = result.add rope s.itemId.item if m.hcrOn: result.add "_" - result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts)) + result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config)) s.loc.r = result writeMangledName(m.ndi, s, m.config) proc fillParamName(m: BModule; s: PSym) = if s.loc.r == "": var res = s.name.s.mangle - res.add idOrSig(s, res, m.sigConflicts) + res.add idOrSig(s, res, m.sigConflicts, m.config) # Take into account if HCR is on because of the following scenario: # if a module gets imported and it has some more importc symbols in it, # some param names might receive the "_0" suffix to distinguish from what @@ -302,7 +302,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = else: result = "" if result != "" and typ.isImportedType(): - let sig = hashType typ + let sig = hashType(typ, m.config) if cacheGetType(m.typeCache, sig) == "": m.typeCache[sig] = result @@ -362,10 +362,10 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R if isImportedCppType(etB) and t.kind == tyGenericInst: result = getTypeDescAux(m, t, check, kind) else: - result = getTypeForward(m, t, hashType(t)) + result = getTypeForward(m, t, hashType(t, m.config)) pushType(m, t) of tySequence: - let sig = hashType(t) + let sig = hashType(t, m.config) if optSeqDestructors in m.config.globalOptions: if skipTypes(etB[0], typedescInst).kind == tyEmpty: internalError(m.config, "cannot map the empty seq type to a C type") @@ -398,7 +398,7 @@ proc getSeqPayloadType(m: BModule; t: PType): Rope = #result = getTypeForward(m, t, hashType(t)) & "_Content" proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = - let sig = hashType(t) + let sig = hashType(t, m.config) let result = cacheGetType(m.typeCache, sig) if result == "": discard getTypeDescAux(m, t, check, skVar) @@ -664,7 +664,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = else: result.elemType proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope = - let sig = hashType(t) + let sig = hashType(t, m.config) if kind == skParam: result = getTypeDescWeak(m, t[0], check, kind) & "*" else: @@ -688,7 +688,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin # C type generation into an analysis and a code generation phase somehow. if t.sym != nil: useHeader(m, t.sym) if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym) - let sig = hashType(origTyp) + let sig = hashType(origTyp, m.config) defer: # defer is the simplest in this case if isImportedType(t) and not m.typeABICache.containsOrIncl(sig): @@ -717,7 +717,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin result = getTypeDescAux(m, et, check, kind) & star else: # no restriction! We have a forward declaration for structs - let name = getTypeForward(m, et, hashType et) + let name = getTypeForward(m, et, hashType(et, m.config)) result = name & star m.typeCache[sig] = result of tySequence: @@ -726,7 +726,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin m.typeCache[sig] = result else: # no restriction! We have a forward declaration for structs - let name = getTypeForward(m, et, hashType et) + let name = getTypeForward(m, et, hashType(et, m.config)) result = name & seqStar(m) & star m.typeCache[sig] = result pushType(m, et) @@ -893,7 +893,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin # Don't use the imported name as it may be scoped: 'Foo::SomeKind' result = rope("tySet_") t.lastSon.typeName(result) - result.add $t.lastSon.hashType + result.add $t.lastSon.hashType(m.config) m.typeCache[sig] = result if not isImportedType(t): let s = int(getSize(m.config, t)) @@ -1066,7 +1066,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope = objtype = objtype[0].skipTypes(abstractPtrs) if objtype.sym == nil: internalError(m.config, d.info, "anonymous obj with discriminator") - result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)] + result = "NimDT_$1_$2" % [rope($hashType(objtype, m.config)), rope(d.name.s.mangle)] proc rope(arg: Int128): Rope = rope($arg) @@ -1285,7 +1285,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope = result.add m.name.s & "." result.add it.sym.name.s else: - result = $hashType(it) + result = $hashType(it, m.config) result = makeCString(result) proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0 @@ -1329,14 +1329,14 @@ proc genDisplayElem(d: MD5Digest): uint32 = result += uint32(d[i]) result = result shl 8 -proc genDisplay(t: PType, depth: int): Rope = +proc genDisplay(m: BModule, t: PType, depth: int): Rope = result = Rope"{" var x = t var seqs = newSeq[string](depth+1) var i = 0 while x != nil: x = skipTypes(x, skipPtrs) - seqs[i] = $genDisplayElem(MD5Digest(hashType(x))) + seqs[i] = $genDisplayElem(MD5Digest(hashType(x, m.config))) x = x[0] inc i @@ -1376,7 +1376,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin [name, getTypeDesc(m, t), rope(objDepth), rope(flags)]) if objDepth >= 0: - let objDisplay = genDisplay(t, objDepth) + let objDisplay = genDisplay(m, t, objDepth) let objDisplayStore = getTempName(m) m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)]) @@ -1408,7 +1408,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn [getTypeDesc(m, t), rope(objDepth)]) if objDepth >= 0: - let objDisplay = genDisplay(t, objDepth) + let objDisplay = genDisplay(m, t, objDepth) let objDisplayStore = getTempName(m) m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, ", .display = $1", [rope(objDisplayStore)]) @@ -1435,7 +1435,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = let prefixTI = if m.hcrOn: "(" else: "(&" - let sig = hashType(origType) + let sig = hashType(origType, m.config) result = m.typeInfoMarkerV2.getOrDefault(sig) if result != "": return prefixTI.rope & result & ")".rope @@ -1509,7 +1509,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = let prefixTI = if m.hcrOn: "(" else: "(&" - let sig = hashType(origType) + let sig = hashType(origType, m.config) result = m.typeInfoMarker.getOrDefault(sig) if result != "": return prefixTI.rope & result & ")".rope diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c346a0b78..ab6e6559f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1630,7 +1630,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = hcrModuleMeta.addf("\t\"\"};$n", []) hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", []) hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n", - [($sigHash(m.module)).rope]) + [($sigHash(m.module, m.config)).rope]) if sfMainModule in m.module.flags: g.mainModProcs.add(hcrModuleMeta) g.mainModProcs.addf("static void* hcr_handle;$N", []) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 13141b765..d58f28289 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -217,7 +217,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode var op = getAttachedOp(c.graph, t, kind) if op == nil or op.ast.isGenericRoutine: # give up and find the canonical type instead: - let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct}) + let h = sighashes.hashType(t, c.graph.config, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.graph.canonTypes.getOrDefault(h) if canon != nil: op = getAttachedOp(c.graph, canon, kind) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 572d19b13..6619963b0 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -262,7 +262,7 @@ proc mangleName(m: BModule, s: PSym): Rope = if m.config.hcrOn: # When hot reloading is enabled, we must ensure that the names # of functions and types will be preserved across rebuilds: - result.add(idOrSig(s, m.module.name.s, m.sigConflicts)) + result.add(idOrSig(s, m.module.name.s, m.sigConflicts, m.config)) else: result.add("_") result.add(rope(s.id)) @@ -2813,7 +2813,7 @@ proc genModule(p: PProc, n: PNode) = if p.config.hcrOn and n.kind == nkStmtList: let moduleSym = p.module.module var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" & - idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts) + idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts, p.config) lineF(p, "var $1;$n", [moduleLoadedVar]) var inGuardedBlock = false diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index c7464d39e..d7b1f2daa 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -553,7 +553,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # operation here: var t = t if t.assignment == nil or t.destructor == nil: - let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct}) + let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.g.canonTypes.getOrDefault(h) if canon != nil: t = canon @@ -1113,7 +1113,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink}) if isEmptyContainer(skipped) or skipped.kind == tyStatic: return - let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct}) + let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct}) var canon = g.canonTypes.getOrDefault(h) if canon == nil: g.canonTypes[h] = skipped diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 1ef0143d5..d9779deab 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -10,7 +10,7 @@ ## Path handling utilities for Nim. Strictly typed code in order ## to avoid the never ending time sink in getting path handling right. -import os, pathnorm +import os, pathnorm, strutils when defined(nimPreviewSlimSystem): import std/[syncio, assertions] @@ -102,3 +102,52 @@ when true: proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.} proc writeFile*(x: AbsoluteFile; content: string) {.borrow.} + +proc skipHomeDir(x: string): int = + when defined(windows): + if x.continuesWith("Users/", len("C:/")): + result = 3 + else: + result = 0 + else: + if x.startsWith("/home/") or x.startsWith("/Users/"): + result = 3 + elif x.startsWith("/mnt/") and x.continuesWith("/Users/", len("/mnt/c")): + result = 5 + else: + result = 0 + +proc relevantPart(s: string; afterSlashX: int): string = + result = newStringOfCap(s.len - 8) + var slashes = afterSlashX + for i in 0.. + # //user/ + if not isAbsolute(x): + result = customPathImpl(canonSlashes(getCurrentDir() / x)) + else: + let slashes = skipHomeDir(x) + if slashes > 0: + result = "//user/" & relevantPart(x, slashes) + else: + result = x + +proc customPath*(x: string): string = + customPathImpl canonSlashes x diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 3508a146a..7e2a0b660 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -9,10 +9,12 @@ ## Computes hash values for routine (proc, method etc) signatures. -import ast, tables, ropes, md5, modulegraphs +import ast, tables, ropes, md5, modulegraphs, options, msgs, packages, pathutils from hashes import Hash import types +import std/os + when defined(nimPreviewSlimSystem): import std/assertions @@ -42,8 +44,7 @@ type CoDistinct CoHashTypeInsideNode -proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) - +proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef) proc hashSym(c: var MD5Context, s: PSym) = if sfAnon in s.flags or s.kind == skGenericParam: c &= ":anon" @@ -54,20 +55,21 @@ proc hashSym(c: var MD5Context, s: PSym) = c &= "." it = it.owner -proc hashTypeSym(c: var MD5Context, s: PSym) = +proc hashTypeSym(c: var MD5Context, s: PSym; conf: ConfigRef) = if sfAnon in s.flags or s.kind == skGenericParam: c &= ":anon" else: var it = s + c &= customPath(conf.toFullPath(s.info)) while it != nil: if sfFromGeneric in it.flags and it.kind in routineKinds and it.typ != nil: - hashType c, it.typ, {CoProc} + hashType c, it.typ, {CoProc}, conf c &= it.name.s c &= "." it = it.owner -proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) = +proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: ConfigRef) = if n == nil: c &= "\255" return @@ -82,7 +84,7 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) = of nkSym: hashSym(c, n.sym) if CoHashTypeInsideNode in flags and n.sym.typ != nil: - hashType(c, n.sym.typ, flags) + hashType(c, n.sym.typ, flags, conf) of nkCharLit..nkUInt64Lit: let v = n.intVal lowlevel v @@ -92,9 +94,9 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) = of nkStrLit..nkTripleStrLit: c &= n.strVal else: - for i in 0.. 0 and t[0] != nil: - hashType c, t[0], flags + hashType c, t[0], flags, conf of tyRef, tyPtr, tyGenericBody, tyVar: c &= char(t.kind) if t.sons.len > 0: - c.hashType t.lastSon, flags + c.hashType t.lastSon, flags, conf if tfVarIsPtr in t.flags: c &= ".varisptr" of tyFromExpr: c &= char(t.kind) - c.hashTree(t.n, {}) + c.hashTree(t.n, {}, conf) of tyTuple: c &= char(t.kind) if t.n != nil and CoType notin flags: @@ -199,19 +201,19 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = assert(t.n[i].kind == nkSym) c &= t.n[i].sym.name.s c &= ':' - c.hashType(t[i], flags+{CoIgnoreRange}) + c.hashType(t[i], flags+{CoIgnoreRange}, conf) c &= ',' else: - for i in 0.. 1) order by hash; -proc hashType*(t: PType; flags: set[ConsiderFlag] = {CoType}): SigHash = +proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash = var c: MD5Context md5Init c - hashType c, t, flags+{CoOwnerSig} + hashType c, t, flags+{CoOwnerSig}, conf md5Final c, result.MD5Digest when defined(debugSigHashes): db.exec(sql"INSERT OR IGNORE INTO sighashes(type, hash) VALUES (?, ?)", typeToString(t), $result) -proc hashProc*(s: PSym): SigHash = +proc hashProc*(s: PSym; conf: ConfigRef): SigHash = var c: MD5Context md5Init c - hashType c, s.typ, {CoProc} + hashType c, s.typ, {CoProc}, conf var m = s while m.kind != skModule: m = m.owner @@ -315,9 +317,9 @@ proc hashOwner*(s: PSym): SigHash = md5Final c, result.MD5Digest -proc sigHash*(s: PSym): SigHash = +proc sigHash*(s: PSym; conf: ConfigRef): SigHash = if s.kind in routineKinds and s.typ != nil: - result = hashProc(s) + result = hashProc(s, conf) else: result = hashNonProc(s) @@ -378,7 +380,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash = var c: MD5Context md5Init(c) - c.hashType(sym.typ, {CoProc}) + c.hashType(sym.typ, {CoProc}, graph.config) c &= char(sym.kind) c.md5Final(result.MD5Digest) graph.symBodyHashes[sym.id] = result # protect from recursion in the body @@ -391,12 +393,12 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash = graph.symBodyHashes[sym.id] = result proc idOrSig*(s: PSym, currentModule: string, - sigCollisions: var CountTable[SigHash]): Rope = + sigCollisions: var CountTable[SigHash]; conf: ConfigRef): Rope = if s.kind in routineKinds and s.typ != nil: # signatures for exported routines are reliable enough to # produce a unique name and this means produced C++ is more stable regarding # Nim changes: - let sig = hashProc(s) + let sig = hashProc(s, conf) result = rope($sig) #let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m let counter = sigCollisions.getOrDefault(sig) diff --git a/compiler/vm.nim b/compiler/vm.nim index 38b856277..18d840613 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1855,7 +1855,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if regs[rb].node.kind != nkSym: stackTrace(c, tos, pc, "node is not a symbol") else: - regs[ra].node.strVal = $sigHash(regs[rb].node.sym) + regs[ra].node.strVal = $sigHash(regs[rb].node.sym, c.config) of opcSlurp: decodeB(rkNode) createStr regs[ra] diff --git a/tests/ccgbugs/m1/defs.nim b/tests/ccgbugs/m1/defs.nim new file mode 100644 index 000000000..ed78d8b72 --- /dev/null +++ b/tests/ccgbugs/m1/defs.nim @@ -0,0 +1,4 @@ +type MyObj* = object + field1*: int + s*: string + ch*: char diff --git a/tests/ccgbugs/m2/defs.nim b/tests/ccgbugs/m2/defs.nim new file mode 100644 index 000000000..798d1fea8 --- /dev/null +++ b/tests/ccgbugs/m2/defs.nim @@ -0,0 +1,4 @@ +type MyObj* = object + s*: string + field1*: int + ch*: char diff --git a/tests/ccgbugs/t20139.nim b/tests/ccgbugs/t20139.nim new file mode 100644 index 000000000..4592b994d --- /dev/null +++ b/tests/ccgbugs/t20139.nim @@ -0,0 +1,10 @@ +discard """ + joinable: false +""" + +# bug #20139 +import m1/defs as md1 +import m2/defs as md2 + +doAssert $(md1.MyObj(field1: 1)) == """(field1: 1, s: "", ch: '\x00')""" +doAssert $(md2.MyObj(field1: 1)) == """(s: "", field1: 1, ch: '\x00')""" From d4d28f2ffe522d2509dccfa7be0eef709732d93f Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 3 Mar 2023 06:27:10 +1100 Subject: [PATCH 4232/4254] Allow `futureLogging` in release builds (#21448) * Add test case * Fixes 21447: Keeps stackTrace around when using futureLogging * Remove extra whitespace --- lib/pure/asyncfutures.nim | 2 +- tests/async/t21447.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/async/t21447.nim diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index edf5f7277..51aaaca36 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -29,7 +29,7 @@ type finished: bool error*: ref Exception ## Stored exception errorStackTrace*: string - when not defined(release): + when not defined(release) or defined(futureLogging): stackTrace: seq[StackTraceEntry] ## For debugging purposes only. id: int fromProc: string diff --git a/tests/async/t21447.nim b/tests/async/t21447.nim new file mode 100644 index 000000000..e4f7ae31f --- /dev/null +++ b/tests/async/t21447.nim @@ -0,0 +1,6 @@ +discard """ + action: "compile" + cmd: "nim c -d:release -d:futureLogging $file" +""" + +import std/asyncdispatch From d51a392149df1c0783fa526eabbc904ce0cd0cbd Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 3 Mar 2023 14:36:38 +0800 Subject: [PATCH 4233/4254] replaces implicit passes array registed at runtime with explicit function calls; simplify compilation pipeline (#21444) * abolish using passes in the compiler; simplify compilation pipeline * duplicate code * Really cool to have the same signature... * haul * unify other backends * refactor process * introduce PipelinePhase * refactor compiler * fixes passes * fixes nimsuggest * add a sentinel * enable docs checkj * activate doc testing * clean up * complete cleanups --- compiler/cgen.nim | 25 +--- compiler/depends.nim | 9 +- compiler/docgen2.nim | 25 ++-- compiler/jsgen.nim | 19 ++- compiler/main.nim | 67 +++++----- compiler/modulegraphs.nim | 13 ++ compiler/modules.nim | 96 +------------- compiler/nimeval.nim | 29 +++-- compiler/passes.nim | 187 +++++++++++++++++---------- compiler/pipelines.nim | 254 +++++++++++++++++++++++++++++++++++++ compiler/pipelineutils.nim | 26 ++++ compiler/scriptconfig.nim | 15 +-- compiler/sem.nim | 63 +++++---- compiler/suggest.nim | 2 +- compiler/vm.nim | 11 +- doc/refc.md | 1 + nimsuggest/nimsuggest.nim | 2 +- 17 files changed, 531 insertions(+), 313 deletions(-) create mode 100644 compiler/pipelines.nim create mode 100644 compiler/pipelineutils.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ab6e6559f..d051934b5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -12,11 +12,13 @@ import ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, nversion, nimsets, msgs, bitsets, idents, types, - ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, + ccgutils, os, ropes, math, wordrecg, treetab, cgmeth, rodutils, renderer, cgendata, aliases, lowerings, tables, sets, ndi, lineinfos, pathutils, transf, injectdestructors, astmsgs, modulepaths, backendpragmas +import pipelineutils + when defined(nimPreviewSlimSystem): import std/assertions @@ -1938,8 +1940,7 @@ template injectG() {.dirty.} = graph.backend = newModuleList(graph) let g = BModuleList(graph.backend) - -proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = injectG() result = newModule(g, module, graph.config) result.idgen = idgen @@ -2007,7 +2008,7 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) = proc genTopLevelStmt*(m: BModule; n: PNode) = ## Also called from `ic/cbackend.nim`. - if passes.skipCodegen(m.config, n): return + if pipelineutils.skipCodegen(m.config, n): return m.initProc.options = initProcOptions(m) #softRnl = if optLineDir in m.config.options: noRnl else: rnl # XXX replicate this logic! @@ -2020,12 +2021,6 @@ proc genTopLevelStmt*(m: BModule; n: PNode) = else: genProcBody(m.initProc, transformedN) -proc myProcess(b: PPassContext, n: PNode): PNode = - result = n - if b != nil: - var m = BModule(b) - genTopLevelStmt(m, n) - proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = if optForceFullMake notin m.config.globalOptions: if not moduleHasChanged(m.g.graph, m.module): @@ -2102,7 +2097,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}: for i in countdown(high(graph.globalDestructors), 0): n.add graph.globalDestructors[i] - if passes.skipCodegen(m.config, n): return + if pipelineutils.skipCodegen(m.config, n): return if moduleHasChanged(graph, m.module): # if the module is cached, we don't regenerate the main proc # nor the dispatchers? But if the dispatchers changed? @@ -2143,12 +2138,6 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = let mm = m m.g.modulesClosed.add mm - -proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = - result = n - if b == nil: return - finalCodegenActions(graph, BModule(b), n) - proc genForwardedProcs(g: BModuleList) = # Forward declared proc:s lack bodies when first encountered, so they're given # a second pass here @@ -2175,5 +2164,3 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = m.writeModule(pending=true) writeMapping(config, g.mapping) if g.generatedHeader != nil: writeHeader(g.generatedHeader) - -const cgenPass* = makePass(myOpen, myProcess, myClose) diff --git a/compiler/depends.nim b/compiler/depends.nim index 59cdc0330..2087198f2 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -9,7 +9,7 @@ # This module implements a dependency file generator. -import options, ast, ropes, passes, pathutils, msgs, lineinfos +import options, ast, ropes, pathutils, msgs, lineinfos import modulegraphs @@ -79,7 +79,7 @@ proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) = let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym)) addDependencyAux(b, parent, child) -proc addDotDependency(c: PPassContext, n: PNode): PNode = +proc addDotDependency*(c: PPassContext, n: PNode): PNode = result = n let g = PGen(c) let b = Backend(g.graph.backend) @@ -100,7 +100,7 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) = rope(project.splitFile.name), b.dotGraph], changeFileExt(project, "dot")) -proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = var g: PGen new(g) g.module = module @@ -109,6 +109,3 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext if graph.backend == nil: graph.backend = Backend(dotGraph: "") result = g - -const gendependPass* = makePass(open = myOpen, process = addDotDependency) - diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index e5669937f..0941be78a 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -11,7 +11,7 @@ # semantic checking. import - options, ast, msgs, passes, docgen, lineinfos, pathutils, packages + options, ast, msgs, docgen, lineinfos, pathutils, packages from modulegraphs import ModuleGraph, PPassContext @@ -38,21 +38,21 @@ template closeImpl(body: untyped) {.dirty.} = except IOError: discard -proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = +proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: writeOutput(g.doc, useWarning, groupedToc) -proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = +proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: writeOutputJson(g.doc, useWarning) -proc processNode(c: PPassContext, n: PNode): PNode = +proc processNode*(c: PPassContext, n: PNode): PNode = result = n var g = PGen(c) if shouldProcess(g): generateDoc(g.doc, n, n, g.config) -proc processNodeJson(c: PPassContext, n: PNode): PNode = +proc processNodeJson*(c: PPassContext, n: PNode): PNode = result = n var g = PGen(c) if shouldProcess(g): @@ -68,20 +68,11 @@ template myOpenImpl(ext: untyped) {.dirty.} = g.doc = d result = g -proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = +proc openHtml*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = myOpenImpl(HtmlExt) -proc myOpenTex(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = +proc openTex*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = myOpenImpl(TexExt) -proc myOpenJson(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = +proc openJson*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = myOpenImpl(JsonExt) - -const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close) -const docgen2TexPass* = makePass(open = myOpenTex, process = processNode, - close = close) -const docgen2JsonPass* = makePass(open = myOpenJson, process = processNodeJson, - close = closeJson) - -proc finishDoc2Pass*(project: string) = - discard diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 6619963b0..5df40b996 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -31,10 +31,12 @@ implements the required case distinction. import ast, trees, magicsys, options, nversion, msgs, idents, types, - ropes, passes, ccgutils, wordrecg, renderer, + ropes, ccgutils, wordrecg, renderer, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, transf, injectdestructors, sourcemap, astmsgs, backendpragmas +import pipelineutils + import json, sets, math, tables, intsets import strutils except addf @@ -2830,11 +2832,11 @@ proc genModule(p: PProc, n: PNode) = if optStackTrace in p.options: p.body.add(frameDestroy(p)) -proc myProcess(b: PPassContext, n: PNode): PNode = +proc processJSCodeGen*(b: PPassContext, n: PNode): PNode = ## Generate JS code for a node. result = n let m = BModule(b) - if passes.skipCodegen(m.config, n): return n + if pipelineutils.skipCodegen(m.config, n): return n if m.module == nil: internalError(m.config, n.info, "myProcess") let globals = PGlobals(m.graph.backend) var p = newInitProc(globals, m) @@ -2869,7 +2871,7 @@ proc getClassName(t: PType): Rope = if s.loc.r != "": result = s.loc.r else: result = rope(s.name.s) -proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = +proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = ## Finalize JS code generation of a Nim module. ## Param `n` may contain nodes returned from the last module close call. var m = BModule(b) @@ -2879,14 +2881,14 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = for i in countdown(high(graph.globalDestructors), 0): n.add graph.globalDestructors[i] # Process any nodes left over from the last call to `myClose`. - result = myProcess(b, n) + result = processJSCodeGen(b, n) # Some codegen is different (such as no stacktraces; see `initProcOptions`) # when `std/system` is being processed. if sfSystemModule in m.module.flags: PGlobals(graph.backend).inSystem = false # Check if codegen should continue before any files are generated. # It may bail early is if too many errors have been raised. - if passes.skipCodegen(m.config, n): return n + if pipelineutils.skipCodegen(m.config, n): return n # Nim modules are compiled into a single JS file. # If this is the main module, then this is the final call to `myClose`. if sfMainModule in m.module.flags: @@ -2904,9 +2906,6 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if not writeRope(code, outFile): rawMessage(m.config, errCannotOpenFile, outFile.string) -proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = - ## Create the JS backend pass context `BModule` for a Nim module. +proc setupJSgen*(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext = result = newModule(graph, s) result.idgen = idgen - -const JSgenPass* = makePass(myOpen, myProcess, myClose) diff --git a/compiler/main.nim b/compiler/main.nim index b8e0e2f12..d37d26478 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -16,9 +16,9 @@ import std/[strutils, os, times, tables, sha1, with, json], llstream, ast, lexer, syntaxes, options, msgs, condsyms, - sem, idents, passes, extccomp, + idents, extccomp, cgen, nversion, - platform, nimconf, passaux, depends, vm, + platform, nimconf, depends, modules, modulegraphs, lineinfos, pathutils, vmprofiler @@ -29,12 +29,10 @@ when defined(nimPreviewSlimSystem): import ic / [cbackend, integrity, navigator] from ic / ic import rodViewer -when not defined(leanCompiler): - import jsgen, docgen, docgen2 +import pipelines -proc semanticPasses(g: ModuleGraph) = - registerPass g, verbosePass - registerPass g, semPass +when not defined(leanCompiler): + import docgen proc writeDepsFile(g: ModuleGraph) = let fname = g.config.nimcacheDir / RelativeFile(g.config.projectName & ".deps") @@ -68,9 +66,8 @@ proc writeCMakeDepsFile(conf: ConfigRef) = fl.close() proc commandGenDepend(graph: ModuleGraph) = - semanticPasses(graph) - registerPass(graph, gendependPass) - compileProject(graph) + setPipeLinePass(graph, GenDependPass) + compilePipelineProject(graph) let project = graph.config.projectFull writeDepsFile(graph) generateDot(graph, project) @@ -87,8 +84,8 @@ proc commandCheck(graph: ModuleGraph) = defineSymbol(conf.symbols, "nimconfig") elif conf.backend == backendJs: setTarget(conf.target, osJS, cpuJS) - semanticPasses(graph) # use an empty backend for semantic checking only - compileProject(graph) + setPipeLinePass(graph, SemPass) + compilePipelineProject(graph) if conf.symbolFiles != disabledSf: case conf.ideCmd @@ -102,22 +99,20 @@ when not defined(leanCompiler): proc commandDoc2(graph: ModuleGraph; ext: string) = handleDocOutputOptions graph.config graph.config.setErrorMaxHighMaybe - semanticPasses(graph) case ext: - of TexExt: registerPass(graph, docgen2TexPass) - of JsonExt: registerPass(graph, docgen2JsonPass) - of HtmlExt: registerPass(graph, docgen2Pass) + of TexExt: + setPipeLinePass(graph, Docgen2TexPass) + of JsonExt: + setPipeLinePass(graph, Docgen2JsonPass) + of HtmlExt: + setPipeLinePass(graph, Docgen2Pass) else: doAssert false, $ext - compileProject(graph) - finishDoc2Pass(graph.config.projectName) + compilePipelineProject(graph) proc commandCompileToC(graph: ModuleGraph) = let conf = graph.config extccomp.initVars(conf) - semanticPasses(graph) if conf.symbolFiles == disabledSf: - registerPass(graph, cgenPass) - if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"): if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile): # nothing changed @@ -127,7 +122,11 @@ proc commandCompileToC(graph: ModuleGraph) = if not extccomp.ccHasSaneOverflow(conf): conf.symbols.defineSymbol("nimEmulateOverflowChecks") - compileProject(graph) + if conf.symbolFiles == disabledSf: + setPipeLinePass(graph, CgenPass) + else: + setPipeLinePass(graph, SemPass) + compilePipelineProject(graph) if graph.config.errorCounter > 0: return # issue #9933 if conf.symbolFiles == disabledSf: @@ -160,33 +159,27 @@ proc commandCompileToJS(graph: ModuleGraph) = conf.exc = excCpp setTarget(conf.target, osJS, cpuJS) defineSymbol(conf.symbols, "ecmascript") # For backward compatibility - semanticPasses(graph) - registerPass(graph, JSgenPass) - compileProject(graph) + setPipeLinePass(graph, JSgenPass) + compilePipelineProject(graph) if optGenScript in conf.globalOptions: writeDepsFile(graph) -proc interactivePasses(graph: ModuleGraph) = +proc commandInteractive(graph: ModuleGraph) = + graph.config.setErrorMaxHighMaybe initDefines(graph.config.symbols) defineSymbol(graph.config.symbols, "nimscript") # note: seems redundant with -d:nimHasLibFFI when hasFFI: defineSymbol(graph.config.symbols, "nimffi") - registerPass(graph, verbosePass) - registerPass(graph, semPass) - registerPass(graph, evalPass) - -proc commandInteractive(graph: ModuleGraph) = - graph.config.setErrorMaxHighMaybe - interactivePasses(graph) - compileSystemModule(graph) + setPipeLinePass(graph, InterpreterPass) + compilePipelineSystemModule(graph) if graph.config.commandArgs.len > 0: - discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {}) + discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {}) else: var m = graph.makeStdinModule() incl(m.flags, sfMainModule) var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config)) - processModule(graph, m, idgen, s) + discard processPipelineModule(graph, m, idgen, s) proc commandScan(cache: IdentCache, config: ConfigRef) = var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt) @@ -241,8 +234,6 @@ proc mainCommand*(graph: ModuleGraph) = let conf = graph.config let cache = graph.cache - # In "nim serve" scenario, each command must reset the registered passes - clearPasses(graph) conf.lastCmdTime = epochTime() conf.searchPaths.add(conf.libpath) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 598959a37..8ffbe20a5 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -57,6 +57,18 @@ type sym*: PSym info*: TLineInfo + PipelinePass* = enum + NonePass + SemPass + JSgenPass + CgenPass + EvalPass + InterpreterPass + GenDependPass + Docgen2TexPass + Docgen2JsonPass + Docgen2Pass + ModuleGraph* {.acyclic.} = ref object ifaces*: seq[Iface] ## indexed by int32 fileIdx packed*: PackedModuleGraph @@ -104,6 +116,7 @@ type cacheCounters*: Table[string, BiggestInt] # IC: implemented cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented passes*: seq[TPass] + pipelinePass*: PipelinePass onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} diff --git a/compiler/modules.nim b/compiler/modules.nim index 838a89d83..0aa1c8930 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -11,13 +11,8 @@ import ast, magicsys, msgs, options, - idents, lexer, passes, syntaxes, llstream, modulegraphs, - lineinfos, pathutils, tables, packages - -when defined(nimPreviewSlimSystem): - import std/[syncio, assertions] - -import ic / replayer + idents, lexer, syntaxes, modulegraphs, + lineinfos, pathutils proc resetSystemArtifacts*(g: ModuleGraph) = magicsys.resetSysTypes(g) @@ -25,12 +20,12 @@ proc resetSystemArtifacts*(g: ModuleGraph) = template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent = getIdent(graph.cache, splitFile(filename).name) -proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = +proc partialInitModule*(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = let packSym = getPackage(graph, fileIdx) result.owner = packSym result.position = int fileIdx -proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = +proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym = let filename = AbsoluteFile toFullPath(graph.config, fileIdx) # We cannot call ``newSym`` here, because we have to circumvent the ID # mechanism, which we do in order to assign each module a persistent ID. @@ -43,99 +38,16 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = partialInitModule(result, graph, fileIdx, filename) graph.registerModule(result) -proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym = - var flags = flags - if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule - result = graph.getModule(fileIdx) - - template processModuleAux(moduleStatus) = - onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule) - var s: PLLStream - if sfMainModule in flags: - if graph.config.projectIsStdin: s = stdin.llStreamOpen - elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput) - discard processModule(graph, result, idGeneratorFromModule(result), s) - if result == nil: - var cachedModules: seq[FileIndex] - result = moduleFromRodFile(graph, fileIdx, cachedModules) - let filename = AbsoluteFile toFullPath(graph.config, fileIdx) - if result == nil: - result = newModule(graph, fileIdx) - result.flags.incl flags - registerModule(graph, result) - processModuleAux("import") - else: - if sfSystemModule in flags: - graph.systemModule = result - partialInitModule(result, graph, fileIdx, filename) - for m in cachedModules: - registerModuleById(graph, m) - replayStateChanges(graph.packed[m.int].module, graph) - replayGenericCacheInformation(graph, m.int) - elif graph.isDirty(result): - result.flags.excl sfDirty - # reset module fields: - initStrTables(graph, result) - result.ast = nil - processModuleAux("import(dirty)") - graph.markClientsDirty(fileIdx) - -proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = - # this is called by the semantic checking phase - assert graph.config != nil - result = compileModule(graph, fileIdx, {}, s) - graph.addDep(s, fileIdx) - # keep track of import relationships - if graph.config.hcrOn: - graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx) - #if sfSystemModule in result.flags: - # localError(result.info, errAttemptToRedefine, result.name.s) - # restore the notes for outer module: - graph.config.notes = - if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes - else: graph.config.foreignPackageNotes - proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode = result = syntaxes.parseFile(fileIdx, graph.cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(s.position.FileIndex, fileIdx) -proc connectCallbacks*(graph: ModuleGraph) = - graph.includeFileCallback = includeModule - graph.importModuleCallback = importModule - -proc compileSystemModule*(graph: ModuleGraph) = - if graph.systemModule == nil: - connectCallbacks(graph) - graph.config.m.systemFileIdx = fileInfoIdx(graph.config, - graph.config.libpath / RelativeFile"system.nim") - discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule}) - proc wantMainModule*(conf: ConfigRef) = if conf.projectFull.isEmpty: fatal(conf, gCmdLineInfo, "command expects a filename") conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt)) -proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = - connectCallbacks(graph) - let conf = graph.config - wantMainModule(conf) - configComplete(graph) - - let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim") - let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx - conf.projectMainIdx2 = projectFile - - let packSym = getPackage(graph, projectFile) - graph.config.mainPackageId = packSym.getPackageId - graph.importStack.add projectFile - - if projectFile == systemFileIdx: - discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule}) - else: - graph.compileSystemModule() - discard graph.compileModule(projectFile, {sfMainModule}) - proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym = result = graph.newModule(fileInfoIdx(graph.config, filename)) registerModule(graph, result) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 82e2f0812..8e8f4ac7b 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -9,10 +9,16 @@ ## exposes the Nim VM to clients. import - ast, astalgo, modules, passes, condsyms, - options, sem, llstream, lineinfos, vm, + ast, modules, condsyms, + options, llstream, lineinfos, vm, vmdef, modulegraphs, idents, os, pathutils, - passaux, scriptconfig, std/compilesettings + scriptconfig, std/compilesettings + +import pipelines + + +when defined(nimPreviewSlimSystem): + import std/[assertions, syncio] type Interpreter* = ref object ## Use Nim as an interpreter with this object @@ -76,7 +82,7 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) = let s = if scriptStream != nil: scriptStream else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead) - processModule(i.graph, i.mainModule, i.idgen, s) + discard processPipelineModule(i.graph, i.mainModule, i.idgen, s) proc findNimStdLib*(): string = ## Tries to find a path to a valid "system.nim" file. @@ -109,12 +115,10 @@ proc createInterpreter*(scriptName: string; var conf = newConfigRef() var cache = newIdentCache() var graph = newModuleGraph(cache, conf) - connectCallbacks(graph) + connectPipelineCallbacks(graph) initDefines(conf.symbols) for define in defines: defineSymbol(conf.symbols, define[0], define[1]) - registerPass(graph, semPass) - registerPass(graph, evalPass) for p in searchPaths: conf.searchPaths.add(AbsoluteDir p) @@ -129,7 +133,8 @@ proc createInterpreter*(scriptName: string; if registerOps: vm.registerAdditionalOps() # Required to register parts of stdlib modules graph.vm = vm - graph.compileSystemModule() + setPipeLinePass(graph, EvalPass) + graph.compilePipelineSystemModule() result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName, idgen: idgen) proc destroyInterpreter*(i: Interpreter) = @@ -159,13 +164,11 @@ proc runRepl*(r: TLLRepl; defineSymbol(conf.symbols, "nimscript") if supportNimscript: defineSymbol(conf.symbols, "nimconfig") when hasFFI: defineSymbol(graph.config.symbols, "nimffi") - registerPass(graph, verbosePass) - registerPass(graph, semPass) - registerPass(graph, evalPass) var m = graph.makeStdinModule() incl(m.flags, sfMainModule) var idgen = idGeneratorFromModule(m) if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen) - graph.compileSystemModule() - processModule(graph, m, idgen, llStreamOpenStdIn(r)) + setPipeLinePass(graph, InterpreterPass) + graph.compilePipelineSystemModule() + discard processPipelineModule(graph, m, idgen, llStreamOpenStdIn(r)) diff --git a/compiler/passes.nim b/compiler/passes.nim index 74c5ff77c..38c133d69 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -14,13 +14,22 @@ import options, ast, llstream, msgs, idents, syntaxes, modulegraphs, reorder, - lineinfos, pathutils, packages + lineinfos, + pipelineutils, + modules, pathutils, packages, + sem, semdata + +import ic/replayer + +export skipCodegen, resolveMod, prepareConfigNotes when defined(nimsuggest): import std/sha1 when defined(nimPreviewSlimSystem): - import std/syncio + import std/[syncio, assertions] + +import std/tables type TPassData* = tuple[input: PNode, closeOutput: PNode] @@ -38,12 +47,6 @@ proc makePass*(open: TPassOpen = nil, result.process = process result.isFrontend = isFrontend -proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} = - # can be used by codegen passes to determine whether they should do - # something with `n`. Currently, this ignores `n` and uses the global - # error count instead. - result = config.errorCounter > 0 - const maxPasses = 10 @@ -80,13 +83,6 @@ proc processTopLevelStmt(graph: ModuleGraph, n: PNode, a: var TPassContextArray) if isNil(m): return false result = true -proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex = - let fullPath = findModule(conf, module, relativeTo) - if fullPath.isEmpty: - result = InvalidFileIdx - else: - result = fileInfoIdx(conf, fullPath) - proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind, a: var TPassContextArray; m: PSym) = # XXX fixme this should actually be relative to the config file! @@ -100,23 +96,6 @@ proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNod importStmt.add str if not processTopLevelStmt(graph, importStmt, a): break -const - imperativeCode = {low(TNodeKind)..high(TNodeKind)} - {nkTemplateDef, nkProcDef, nkMethodDef, - nkMacroDef, nkConverterDef, nkIteratorDef, nkFuncDef, nkPragma, - nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt} - -proc prepareConfigNotes(graph: ModuleGraph; module: PSym) = - # don't be verbose unless the module belongs to the main package: - if graph.config.belongsToProjectPackage(module): - graph.config.notes = graph.config.mainPackageNotes - else: - if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes - graph.config.notes = graph.config.foreignPackageNotes - -proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} = - result = true - #module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange") - proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; stream: PLLStream): bool {.discardable.} = if graph.stopCompile(): return true @@ -153,42 +132,22 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; processImplicits graph, graph.config.implicitIncludes, nkIncludeStmt, a, module checkFirstLineIndentation(p) - while true: - if graph.stopCompile(): break - var n = parseTopLevelStmt(p) # todo merge it - if n.kind == nkEmpty: break + block processCode: + if graph.stopCompile(): break processCode + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break processCode - if true: - # read everything, no streaming possible - var sl = newNodeI(nkStmtList, n.info) + # read everything, no streaming possible + var sl = newNodeI(nkStmtList, n.info) + sl.add n + while true: + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break sl.add n - while true: - var n = parseTopLevelStmt(p) - if n.kind == nkEmpty: break - sl.add n - if sfReorder in module.flags or codeReordering in graph.config.features: - sl = reorder(graph, sl, module) - discard processTopLevelStmt(graph, sl, a) - break - elif n.kind in imperativeCode: - # read everything until the next proc declaration etc. - var sl = newNodeI(nkStmtList, n.info) - sl.add n - var rest: PNode = nil - while true: - var n = parseTopLevelStmt(p) - if n.kind == nkEmpty or n.kind notin imperativeCode: - rest = n - break - sl.add n - #echo "-----\n", sl - if not processTopLevelStmt(graph, sl, a): break - if rest != nil: - #echo "-----\n", rest - if not processTopLevelStmt(graph, rest, a): break - else: - #echo "----- single\n", n - if not processTopLevelStmt(graph, n, a): break + if sfReorder in module.flags or codeReordering in graph.config.features: + sl = reorder(graph, sl, module) + discard processTopLevelStmt(graph, sl, a) + closeParser(p) if s.kind != llsStdIn: break closePasses(graph, a) @@ -198,3 +157,99 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; # They are responsible for closing the rod files. See `cbackend.nim`. closeRodFile(graph, module) result = true + +proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym = + var flags = flags + if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule + result = graph.getModule(fileIdx) + + template processModuleAux(moduleStatus) = + onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule) + var s: PLLStream + if sfMainModule in flags: + if graph.config.projectIsStdin: s = stdin.llStreamOpen + elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput) + discard processModule(graph, result, idGeneratorFromModule(result), s) + if result == nil: + var cachedModules: seq[FileIndex] + result = moduleFromRodFile(graph, fileIdx, cachedModules) + let filename = AbsoluteFile toFullPath(graph.config, fileIdx) + if result == nil: + result = newModule(graph, fileIdx) + result.flags.incl flags + registerModule(graph, result) + processModuleAux("import") + else: + if sfSystemModule in flags: + graph.systemModule = result + partialInitModule(result, graph, fileIdx, filename) + for m in cachedModules: + registerModuleById(graph, m) + replayStateChanges(graph.packed[m.int].module, graph) + replayGenericCacheInformation(graph, m.int) + elif graph.isDirty(result): + result.flags.excl sfDirty + # reset module fields: + initStrTables(graph, result) + result.ast = nil + processModuleAux("import(dirty)") + graph.markClientsDirty(fileIdx) + +proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = + # this is called by the semantic checking phase + assert graph.config != nil + result = compileModule(graph, fileIdx, {}, s) + graph.addDep(s, fileIdx) + # keep track of import relationships + if graph.config.hcrOn: + graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx) + #if sfSystemModule in result.flags: + # localError(result.info, errAttemptToRedefine, result.name.s) + # restore the notes for outer module: + graph.config.notes = + if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes + else: graph.config.foreignPackageNotes + +proc connectCallbacks*(graph: ModuleGraph) = + graph.includeFileCallback = modules.includeModule + graph.importModuleCallback = importModule + +proc compileSystemModule*(graph: ModuleGraph) = + if graph.systemModule == nil: + connectCallbacks(graph) + graph.config.m.systemFileIdx = fileInfoIdx(graph.config, + graph.config.libpath / RelativeFile"system.nim") + discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule}) + +proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = + connectCallbacks(graph) + let conf = graph.config + wantMainModule(conf) + configComplete(graph) + + let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim") + let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx + conf.projectMainIdx2 = projectFile + + let packSym = getPackage(graph, projectFile) + graph.config.mainPackageId = packSym.getPackageId + graph.importStack.add projectFile + + if projectFile == systemFileIdx: + discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule}) + else: + graph.compileSystemModule() + discard graph.compileModule(projectFile, {sfMainModule}) + +proc mySemOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = + result = preparePContext(graph, module, idgen) + +proc mySemClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = + var c = PContext(context) + closePContext(graph, c, n) + +proc mySemProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = + result = semWithPContext(PContext(context), n) + +const semPass* = makePass(mySemOpen, mySemProcess, mySemClose, + isFrontend = true) diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim new file mode 100644 index 000000000..b80681c4b --- /dev/null +++ b/compiler/pipelines.nim @@ -0,0 +1,254 @@ +import sem, cgen, modulegraphs, ast, llstream, parser, msgs, + lineinfos, reorder, options, semdata, cgendata, modules, pathutils, + packages, syntaxes, depends, vm + +import pipelineutils + +when not defined(leanCompiler): + import jsgen, docgen2 + +import std/[syncio, objectdollar, assertions, tables] +import renderer +import ic/replayer + + +proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) = + graph.pipelinePass = pass + +proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): PNode = + case graph.pipelinePass + of CgenPass: + result = semNode + if bModule != nil: + genTopLevelStmt(BModule(bModule), result) + of JSgenPass: + when not defined(leanCompiler): + result = processJSCodeGen(bModule, semNode) + of GenDependPass: + result = addDotDependency(bModule, semNode) + of SemPass: + result = graph.emptyNode + of Docgen2Pass, Docgen2TexPass: + when not defined(leanCompiler): + result = processNode(bModule, semNode) + of Docgen2JsonPass: + when not defined(leanCompiler): + result = processNodeJson(bModule, semNode) + of EvalPass, InterpreterPass: + result = interpreterCode(bModule, semNode) + of NonePass: + doAssert false, "use setPipeLinePass to set a proper PipelinePass" + +proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind, + m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator, + ) = + # XXX fixme this should actually be relative to the config file! + let relativeTo = toFullPath(graph.config, m.info) + for module in items(implicits): + # implicit imports should not lead to a module importing itself + if m.position != resolveMod(graph.config, module, relativeTo).int32: + var importStmt = newNodeI(nodeKind, m.info) + var str = newStrNode(nkStrLit, module) + str.info = m.info + importStmt.add str + message(graph.config, importStmt.info, hintProcessingStmt, $idgen[]) + let semNode = semWithPContext(ctx, importStmt) + if semNode == nil or processPipeline(graph, semNode, bModule) == nil: + break + +proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; + stream: PLLStream): bool = + if graph.stopCompile(): return true + var + p: Parser + s: PLLStream + fileIdx = module.fileIdx + + prepareConfigNotes(graph, module) + let ctx = preparePContext(graph, module, idgen) + let bModule: PPassContext = + case graph.pipelinePass + of CgenPass: + setupCgen(graph, module, idgen) + of JSgenPass: + when not defined(leanCompiler): + setupJSgen(graph, module, idgen) + else: + nil + of EvalPass, InterpreterPass: + setupEvalGen(graph, module, idgen) + of GenDependPass: + setupDependPass(graph, module, idgen) + of Docgen2Pass: + when not defined(leanCompiler): + openHtml(graph, module, idgen) + else: + nil + of Docgen2TexPass: + when not defined(leanCompiler): + openTex(graph, module, idgen) + else: + nil + of Docgen2JsonPass: + when not defined(leanCompiler): + openJson(graph, module, idgen) + else: + nil + of SemPass: + nil + of NonePass: + doAssert false, "use setPipeLinePass to set a proper PipelinePass" + nil + + if stream == nil: + let filename = toFullPathConsiderDirty(graph.config, fileIdx) + s = llStreamOpen(filename, fmRead) + if s == nil: + rawMessage(graph.config, errCannotOpenFile, filename.string) + return false + else: + s = stream + + while true: + syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config) + + if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"): + # XXX what about caching? no processing then? what if I change the + # modules to include between compilation runs? we'd need to track that + # in ROD files. I think we should enable this feature only + # for the interactive mode. + if module.name.s != "nimscriptapi": + processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen + processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen + + checkFirstLineIndentation(p) + block processCode: + if graph.stopCompile(): break processCode + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break processCode + # read everything, no streaming possible + var sl = newNodeI(nkStmtList, n.info) + sl.add n + while true: + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break + sl.add n + if sfReorder in module.flags or codeReordering in graph.config.features: + sl = reorder(graph, sl, module) + if graph.pipelinePass != EvalPass: + message(graph.config, sl.info, hintProcessingStmt, $idgen[]) + var semNode = semWithPContext(ctx, sl) + discard processPipeline(graph, semNode, bModule) + + closeParser(p) + if s.kind != llsStdIn: break + let finalNode = closePContext(graph, ctx, nil) + case graph.pipelinePass + of CgenPass: + if bModule != nil: + finalCodegenActions(graph, BModule(bModule), finalNode) + of JSgenPass: + when not defined(leanCompiler): + discard finalJSCodeGen(graph, bModule, finalNode) + of EvalPass, InterpreterPass: + discard interpreterCode(bModule, finalNode) + of SemPass, GenDependPass: + discard + of Docgen2Pass, Docgen2TexPass: + when not defined(leanCompiler): + discard closeDoc(graph, bModule, finalNode) + of Docgen2JsonPass: + when not defined(leanCompiler): + discard closeJson(graph, bModule, finalNode) + of NonePass: + doAssert false, "use setPipeLinePass to set a proper PipelinePass" + + if graph.config.backend notin {backendC, backendCpp, backendObjc}: + # We only write rod files here if no C-like backend is active. + # The C-like backends have been patched to support the IC mechanism. + # They are responsible for closing the rod files. See `cbackend.nim`. + closeRodFile(graph, module) + result = true + +proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym = + var flags = flags + if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule + result = graph.getModule(fileIdx) + + template processModuleAux(moduleStatus) = + onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule) + var s: PLLStream + if sfMainModule in flags: + if graph.config.projectIsStdin: s = stdin.llStreamOpen + elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput) + discard processPipelineModule(graph, result, idGeneratorFromModule(result), s) + if result == nil: + var cachedModules: seq[FileIndex] + result = moduleFromRodFile(graph, fileIdx, cachedModules) + let filename = AbsoluteFile toFullPath(graph.config, fileIdx) + if result == nil: + result = newModule(graph, fileIdx) + result.flags.incl flags + registerModule(graph, result) + processModuleAux("import") + else: + if sfSystemModule in flags: + graph.systemModule = result + partialInitModule(result, graph, fileIdx, filename) + for m in cachedModules: + registerModuleById(graph, m) + replayStateChanges(graph.packed[m.int].module, graph) + replayGenericCacheInformation(graph, m.int) + elif graph.isDirty(result): + result.flags.excl sfDirty + # reset module fields: + initStrTables(graph, result) + result.ast = nil + processModuleAux("import(dirty)") + graph.markClientsDirty(fileIdx) + +proc importPipelineModule(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym = + # this is called by the semantic checking phase + assert graph.config != nil + result = compilePipelineModule(graph, fileIdx, {}, s) + graph.addDep(s, fileIdx) + # keep track of import relationships + if graph.config.hcrOn: + graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx) + #if sfSystemModule in result.flags: + # localError(result.info, errAttemptToRedefine, result.name.s) + # restore the notes for outer module: + graph.config.notes = + if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes + else: graph.config.foreignPackageNotes + +proc connectPipelineCallbacks*(graph: ModuleGraph) = + graph.includeFileCallback = modules.includeModule + graph.importModuleCallback = importPipelineModule + +proc compilePipelineSystemModule*(graph: ModuleGraph) = + if graph.systemModule == nil: + connectPipelineCallbacks(graph) + graph.config.m.systemFileIdx = fileInfoIdx(graph.config, + graph.config.libpath / RelativeFile"system.nim") + discard graph.compilePipelineModule(graph.config.m.systemFileIdx, {sfSystemModule}) + +proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = + connectPipelineCallbacks(graph) + let conf = graph.config + wantMainModule(conf) + configComplete(graph) + + let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim") + let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx + conf.projectMainIdx2 = projectFile + + let packSym = getPackage(graph, projectFile) + graph.config.mainPackageId = packSym.getPackageId + graph.importStack.add projectFile + + if projectFile == systemFileIdx: + discard graph.compilePipelineModule(projectFile, {sfMainModule, sfSystemModule}) + else: + graph.compilePipelineSystemModule() + discard graph.compilePipelineModule(projectFile, {sfMainModule}) diff --git a/compiler/pipelineutils.nim b/compiler/pipelineutils.nim new file mode 100644 index 000000000..75ba33f14 --- /dev/null +++ b/compiler/pipelineutils.nim @@ -0,0 +1,26 @@ +import ast, options, lineinfos, pathutils, msgs, modulegraphs, packages + +proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} = + # can be used by codegen passes to determine whether they should do + # something with `n`. Currently, this ignores `n` and uses the global + # error count instead. + result = config.errorCounter > 0 + +proc resolveMod*(conf: ConfigRef; module, relativeTo: string): FileIndex = + let fullPath = findModule(conf, module, relativeTo) + if fullPath.isEmpty: + result = InvalidFileIdx + else: + result = fileInfoIdx(conf, fullPath) + +proc prepareConfigNotes*(graph: ModuleGraph; module: PSym) = + # don't be verbose unless the module belongs to the main package: + if graph.config.belongsToProjectPackage(module): + graph.config.notes = graph.config.mainPackageNotes + else: + if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes + graph.config.notes = graph.config.foreignPackageNotes + +proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} = + result = true + #module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange") diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 009e90fd5..27ea94aae 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -11,10 +11,10 @@ ## language. import - ast, modules, idents, passes, condsyms, - options, sem, llstream, vm, vmdef, commands, + ast, modules, idents, condsyms, + options, llstream, vm, vmdef, commands, os, times, osproc, wordrecg, strtabs, modulegraphs, - pathutils + pathutils, pipelines when defined(nimPreviewSlimSystem): import std/syncio @@ -197,13 +197,11 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; conf.symbolFiles = disabledSf let graph = newModuleGraph(cache, conf) - connectCallbacks(graph) + connectPipelineCallbacks(graph) if freshDefines: initDefines(conf.symbols) defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimconfig") - registerPass(graph, semPass) - registerPass(graph, evalPass) conf.searchPaths.add(conf.libpath) @@ -218,8 +216,9 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; var vm = setupVM(m, cache, scriptName.string, graph, idgen) graph.vm = vm - graph.compileSystemModule() - discard graph.processModule(m, vm.idgen, stream) + graph.setPipeLinePass(EvalPass) + graph.compilePipelineSystemModule() + discard graph.processPipelineModule(m, vm.idgen, stream) # watch out, "newruntime" can be set within NimScript itself and then we need # to remember this: diff --git a/compiler/sem.nim b/compiler/sem.nim index 78596d5b2..a5d06f3fe 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -13,7 +13,7 @@ import ast, strutils, options, astalgo, trees, wordrecg, ropes, msgs, idents, renderer, types, platform, math, magicsys, nversion, nimsets, semfold, modulepaths, importer, - procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, + procfind, lookups, pragmas, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, lowerings, plugins/active, lineinfos, strtabs, int128, @@ -666,38 +666,37 @@ proc addCodeForGenerics(c: PContext, n: PNode) = n.add prc.ast c.lastGenericIdx = c.generics.len -proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = - var c = newContext(graph, module) - c.idgen = idgen - c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil) - c.voidType = newType(tyVoid, nextTypeId(idgen), nil) +proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PContext {.nosinks.} = + result = newContext(graph, module) + result.idgen = idgen + result.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil) + result.voidType = newType(tyVoid, nextTypeId(idgen), nil) - if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") - c.semConstExpr = semConstExpr - c.semExpr = semExpr - c.semTryExpr = tryExpr - c.semTryConstExpr = tryConstExpr - c.computeRequiresInit = computeRequiresInit - c.semOperand = semOperand - c.semConstBoolExpr = semConstBoolExpr - c.semOverloadedCall = semOverloadedCall - c.semInferredLambda = semInferredLambda - c.semGenerateInstance = generateInstance - c.semTypeNode = semTypeNode - c.instTypeBoundOp = sigmatch.instTypeBoundOp - c.hasUnresolvedArgs = hasUnresolvedArgs - c.templInstCounter = new int + if result.p != nil: internalError(graph.config, module.info, "sem.preparePContext") + result.semConstExpr = semConstExpr + result.semExpr = semExpr + result.semTryExpr = tryExpr + result.semTryConstExpr = tryConstExpr + result.computeRequiresInit = computeRequiresInit + result.semOperand = semOperand + result.semConstBoolExpr = semConstBoolExpr + result.semOverloadedCall = semOverloadedCall + result.semInferredLambda = semInferredLambda + result.semGenerateInstance = generateInstance + result.semTypeNode = semTypeNode + result.instTypeBoundOp = sigmatch.instTypeBoundOp + result.hasUnresolvedArgs = hasUnresolvedArgs + result.templInstCounter = new int - pushProcCon(c, module) - pushOwner(c, c.module) + pushProcCon(result, module) + pushOwner(result, result.module) - c.moduleScope = openScope(c) - c.moduleScope.addSym(module) # a module knows itself + result.moduleScope = openScope(result) + result.moduleScope.addSym(module) # a module knows itself if sfSystemModule in module.flags: graph.systemModule = module - c.topLevelScope = openScope(c) - result = c + result.topLevelScope = openScope(result) proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool = if g.systemModule == nil: return false @@ -771,8 +770,7 @@ proc recoverContext(c: PContext) = while getCurrOwner(c).kind != skModule: popOwner(c) while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next -proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = - var c = PContext(context) +proc semWithPContext*(c: PContext, n: PNode): PNode {.nosinks.} = # no need for an expensive 'try' if we stop after the first error anyway: if c.config.errorMax <= 1: result = semStmtAndGenerateGenerics(c, n) @@ -793,13 +791,13 @@ proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = #if c.config.cmd == cmdIdeTools: findSuggest(c, n) storeRodNode(c, result) + proc reportUnusedModules(c: PContext) = for i in 0..high(c.unusedImports): if sfUsed notin c.unusedImports[i][0].flags: message(c.config, c.unusedImports[i][1], warnUnusedImportX, c.unusedImports[i][0].name.s) -proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = - var c = PContext(context) +proc closePContext*(graph: ModuleGraph; c: PContext, n: PNode): PNode = if c.config.cmd == cmdIdeTools and not c.suggestionsMade: suggestSentinel(c) closeScope(c) # close module's scope @@ -814,6 +812,3 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = popOwner(c) popProcCon(c) sealRodFile(c) - -const semPass* = makePass(myOpen, myProcess, myClose, - isFrontend = true) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 637010ad5..384ceb271 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -36,7 +36,7 @@ import algorithm, sets, prefixmatches, parseutils, tables from wordrecg import wDeprecated, wError, wAddr, wYield when defined(nimsuggest): - import passes, tables, pathutils # importer + import tables, pathutils # importer const sep = '\t' diff --git a/compiler/vm.nim b/compiler/vm.nim index 18d840613..96f05c0f9 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -13,7 +13,7 @@ import semmacrosanity import std/[strutils, tables, parseutils], - msgs, vmdef, vmgen, nimsets, types, passes, + msgs, vmdef, vmgen, nimsets, types, parser, vmdeps, idents, trees, renderer, options, transf, gorgeimpl, lineinfos, btrees, macrocacheimpl, modulegraphs, sighashes, int128, vmprofiler @@ -2309,7 +2309,7 @@ proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) = else: refresh(PCtx graph.vm, module, idgen) -proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc setupEvalGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = #var c = newEvalContext(module, emRepl) #c.features = {allowCast, allowInfiniteLoops} #pushStackFrame(c, newStackFrame()) @@ -2318,7 +2318,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext setupGlobalCtx(module, graph, idgen) result = PCtx graph.vm -proc myProcess(c: PPassContext, n: PNode): PNode = +proc interpreterCode*(c: PPassContext, n: PNode): PNode = let c = PCtx(c) # don't eval errornous code: if c.oldErrorCount == c.config.errorCounter: @@ -2328,11 +2328,6 @@ proc myProcess(c: PPassContext, n: PNode): PNode = result = n c.oldErrorCount = c.config.errorCounter -proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = - result = myProcess(c, n) - -const evalPass* = makePass(myOpen, myProcess, myClose) - proc evalConstExprAux(module: PSym; idgen: IdGenerator; g: ModuleGraph; prc: PSym, n: PNode, mode: TEvalMode): PNode = diff --git a/doc/refc.md b/doc/refc.md index 6e4672ac5..4023748e6 100644 --- a/doc/refc.md +++ b/doc/refc.md @@ -138,6 +138,7 @@ The garbage collector won't try to free them, you need to call their respective when you are done with them or they will leak. + Heap dump ========= diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index a0a3b8e82..ce9681975 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -23,7 +23,7 @@ import strutils, os, parseopt, parseutils, sequtils, net, rdstdin, sexp # Do NOT import suggest. It will lead to weird bugs with # suggestionResultHook, because suggest.nim is included by sigmatch. # So we import that one instead. -import compiler / [options, commands, modules, sem, +import compiler / [options, commands, modules, passes, passaux, msgs, sigmatch, ast, idents, modulegraphs, prefixmatches, lineinfos, cmdlinehelper, From 2e2affb13ce13723e5ab1996d05f7b82c184a090 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 3 Mar 2023 23:13:27 +0800 Subject: [PATCH 4234/4254] test DLL generation with ORC (#21445) * test DLL generation with ORC * fixes * fixes refc * Update testament/categories.nim --- testament/categories.nim | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/testament/categories.nim b/testament/categories.nim index cae699327..c428ffc04 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -47,21 +47,24 @@ proc isTestFile*(file: string): bool = # --------------------- DLL generation tests ---------------------------------- -proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = +proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = false) = const rpath = when defined(macosx): " --passL:-rpath --passL:@loader_path" else: "" - var test1 = makeTest("lib/nimrtl.nim", options & " --outdir:tests/dll", cat) - test1.spec.action = actionCompile - testSpec c, test1 + if not defined(windows) or not isOrc: # todo fix me on windows + var test1 = makeTest("lib/nimrtl.nim", options & " --outdir:tests/dll", cat) + test1.spec.action = actionCompile + testSpec c, test1 var test2 = makeTest("tests/dll/server.nim", options & " --threads:on" & rpath, cat) test2.spec.action = actionCompile testSpec c, test2 - var test3 = makeTest("lib/nimhcr.nim", options & " --threads:off --outdir:tests/dll" & rpath, cat) - test3.spec.action = actionCompile - testSpec c, test3 + + if not isOrc: + var test3 = makeTest("lib/nimhcr.nim", options & " --threads:off --outdir:tests/dll" & rpath, cat) + test3.spec.action = actionCompile + testSpec c, test3 var test4 = makeTest("tests/dll/visibility.nim", options & " --threads:off --app:lib" & rpath, cat) test4.spec.action = actionCompile testSpec c, test4 @@ -76,8 +79,9 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: "")) defer: putEnv(libpathenv, libpath) - testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) - testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) + if not isOrc: + testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) + testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) if "boehm" notin options: @@ -96,6 +100,8 @@ proc dllTests(r: var TResults, cat: Category, options: string) = runBasicDLLTest c, r, cat, options & " --mm:refc" runBasicDLLTest c, r, cat, options & " -d:release --mm:refc" + runBasicDLLTest c, r, cat, options, isOrc = true + runBasicDLLTest c, r, cat, options & " -d:release", isOrc = true when not defined(windows): # still cannot find a recent Windows version of boehm.dll: runBasicDLLTest c, r, cat, options & " --gc:boehm" From b2c5f8a05f2f9db6ed06663a077882eb112b3e3f Mon Sep 17 00:00:00 2001 From: Arnaud Moura Date: Fri, 3 Mar 2023 23:37:12 +0100 Subject: [PATCH 4235/4254] fixes #21461 (#21463) * fixes #21461; Move nim-gdb.py and add nim-lldb.py * fixes bad path for nim-gdb.py --- bin/nim-gdb | 2 +- bin/nim-gdb.bat | 2 +- compiler/installer.ini | 2 +- doc/packaging.md | 2 +- .../untestable/gdb/gdb_pretty_printer_test.py | 2 +- tools/{ => debug}/nim-gdb.py | 0 tools/debug/nim-lldb.py | 1039 +++++++++++++++++ 7 files changed, 1044 insertions(+), 5 deletions(-) rename tools/{ => debug}/nim-gdb.py (100%) create mode 100644 tools/debug/nim-lldb.py diff --git a/bin/nim-gdb b/bin/nim-gdb index 13b361f93..d4d60e432 100755 --- a/bin/nim-gdb +++ b/bin/nim-gdb @@ -14,7 +14,7 @@ else fi # Find out where the pretty printer Python module is -GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py" +GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py" # Run GDB with the additional arguments that load the pretty printers # Set the environment variable `NIM_GDB` to overwrite the call to a diff --git a/bin/nim-gdb.bat b/bin/nim-gdb.bat index e98a2063c..b5537dd9d 100644 --- a/bin/nim-gdb.bat +++ b/bin/nim-gdb.bat @@ -3,7 +3,7 @@ for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i) for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi) -set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py +set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\debug\nim-gdb.py set @NIM_GDB=gdb.exe @echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt diff --git a/compiler/installer.ini b/compiler/installer.ini index f67ca5c25..226682715 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -65,7 +65,7 @@ Files: "compiler" Files: "doc" Files: "doc/html" Files: "tools" -Files: "tools/nim-gdb.py" +Files: "tools/debug/nim-gdb.py" Files: "nimpretty" Files: "testament" Files: "nimsuggest" diff --git a/doc/packaging.md b/doc/packaging.md index 522ca6d44..b742bef28 100644 --- a/doc/packaging.md +++ b/doc/packaging.md @@ -71,7 +71,7 @@ What to install: - The expected stdlib location is `/usr/lib/nim/lib`, previously it was just `/usr/lib/nim` - `nimdoc.css` and `nimdoc.cls` from the `doc` folder should go into `/usr/lib/nim/doc/` -- `tools/nim-gdb.py` should go into `/usr/lib/nim/tools/` +- `tools/debug/nim-gdb.py` should go into `/usr/lib/nim/tools/` - `tools/dochack/dochack.js` should be installed to `/usr/lib/nim/tools/dochack/` - Global configuration files under `/etc/nim` - Optionally: manpages, documentation, shell completion diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index a96df9992..aed0cfeb0 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -8,7 +8,7 @@ import sys # frontends might still be broken. gdb.execute("set python print-stack full") -gdb.execute("source ../../../tools/nim-gdb.py") +gdb.execute("source ../../../tools/debug/nim-gdb.py") # debug all instances of the generic function `myDebug`, should be 14 gdb.execute("rbreak myDebug") gdb.execute("run") diff --git a/tools/nim-gdb.py b/tools/debug/nim-gdb.py similarity index 100% rename from tools/nim-gdb.py rename to tools/debug/nim-gdb.py diff --git a/tools/debug/nim-lldb.py b/tools/debug/nim-lldb.py new file mode 100644 index 000000000..625b75988 --- /dev/null +++ b/tools/debug/nim-lldb.py @@ -0,0 +1,1039 @@ +import lldb +from collections import OrderedDict +from typing import Union + + +def sbvaluegetitem(self: lldb.SBValue, name: Union[int, str]) -> lldb.SBValue: + if isinstance(name, str): + return self.GetChildMemberWithName(name) + else: + return self.GetChildAtIndex(name) + + +# Make this easier to work with +lldb.SBValue.__getitem__ = sbvaluegetitem + + +def colored(in_str, *args, **kwargs): + # TODO: Output in color if user is in terminal + return in_str + + +def reprEnum(val, typ): + """ + this is a port of the nim runtime function `reprEnum` to python + NOTE: DOES NOT WORK WITH ORC + """ + val = int(val) + n = typ["node"] + sons_type = n["sons"].type.GetPointeeType().GetPointeeType() + sons = n["sons"].deref.Cast(sons_type.GetPointerType().GetArrayType(3)) + flags = int(typ["flags"].unsigned) + # 1 << 6 is {ntfEnumHole} + if ((1 << 6) & flags) == 0: + offset = val - sons[0]["offset"].unsigned + if offset >= 0 and 0 < n["len"].unsigned: + return NCSTRING(sons[offset]["name"])[1:-1] + else: + # ugh we need a slow linear search: + for i in range(n["len"].unsigned): + if sons[i]["offset"].unsigned == val: + return NCSTRING(sons[i]["name"])[1:-1] + + return str(val) + " (invalid data!)" + + +def get_nti(value, nim_name=None): + """DOES NOT WORK WITH ORC""" + name_split = value.type.name.split("_") + type_nim_name = nim_name or name_split[1] + id_string = name_split[-1].split(" ")[0] + + type_info_name = "NTI" + type_nim_name.lower() + "__" + id_string + "_" + print("TYPEINFONAME: ", type_info_name) + nti = value.target.FindFirstGlobalVariable(type_info_name) + if nti is None: + type_info_name = "NTI" + "__" + id_string + "_" + nti = value.target.FindFirstGlobalVariable(type_info_name) + if nti is None: + print( + f"NimEnumPrinter: lookup global symbol: '{type_info_name}' failed for {value.type.name}.\n" + ) + return type_nim_name, nti + + +def enum_to_string(value): + type_nim_name, nti = get_nti(value) + if nti is None: + return type_nim_name + "(" + str(value.unsigned) + ")" + return reprEnum(value.signed, nti), nti + + +def to_string(value): + # For getting NimStringDesc * value + data = value["data"] + try: + size = int(value["Sup"]["len"].unsigned) + if size > 2**14: + return None + except TypeError: + return None + + cast = data.Cast(value.target.FindFirstType("char").GetArrayType(size)) + return bytearray(cast.data.uint8s).decode("utf-8") + + +def to_stringV2(value: lldb.SBValue): + # For getting NimStringDesc * value + data = value["p"]["data"] + try: + size = int(value["len"].signed) + if size > 2**14: + return "... (too long)" + except TypeError: + return "" + + base_data_type = data.type.GetArrayElementType().GetTypedefedType() + cast = data.Cast(base_data_type.GetArrayType(size)) + return bytearray(cast.data.uint8s).decode("utf-8") + + +def NimStringDesc(value, internal_dict): + res = to_string(value) + if res: + return colored('"' + res + '"', "red") + else: + return str(value) + + +def NimStringV2(value: lldb.SBValue, internal_dict): + res = to_stringV2(value.GetNonSyntheticValue()) + if res is not None: + return colored('"' + res + '"', "red") + else: + return str(value) + + +def NCSTRING(value: lldb.SBValue, internal_dict=None): + ty = value.Dereference().type + val = value.target.CreateValueFromAddress( + value.name or "temp", lldb.SBAddress(value.unsigned, value.target), ty + ).AddressOf() + return val.summary + + +def ObjectV1(value, internal_dict): + if not value.num_children and not value.value: + return "" + + ignore_fields = set() + if "colonObjectType" in value.type.name: + value = value.Dereference() + ignore_fields.add("Sup") + + if not value.type.name: + return "" + + summary = value.summary + if summary is not None: + return summary + + if "_" in value.type.name: + obj_name = value.type.name.split("_")[1].replace("colonObjectType", "") + else: + obj_name = value.type.name + + obj_name = colored(obj_name, "green") + + num_children = value.num_children + + fields = ", ".join( + [ + value[i].name + + ": " + + (value[i].summary or value[i].value or value[i].type.name or "not found") + for i in range(num_children) + if value[i].name not in ignore_fields + ] + ) + + res = f"{obj_name}({fields})" + return res + + +def ObjectV2(value: lldb.SBValue, internal_dict): + custom_summary = get_summary(value) + if not custom_summary is None: + return custom_summary + + orig_value = value.GetNonSyntheticValue() + while orig_value.type.is_pointer: + orig_value = orig_value.Dereference() + + if "_" in orig_value.type.name: + obj_name = orig_value.type.name.split("_")[1].replace("colonObjectType", "") + else: + obj_name = orig_value.type.name + + num_children = value.num_children + fields = [] + + for i in range(num_children): + fields.append(f"{value[i].name}: {value[i].summary}") + + res = f"{obj_name}(" + ", ".join(fields) + ")" + return res + + +def Number(value: lldb.SBValue, internal_dict): + while value.type.is_pointer: + value = value.Dereference() + return colored(str(value.signed), "yellow") + + +def Float(value: lldb.SBValue, internal_dict): + while value.type.is_pointer: + value = value.Dereference() + return colored(str(value.value), "yellow") + + +def UnsignedNumber(value: lldb.SBValue, internal_dict): + while value.type.is_pointer: + value = value.Dereference() + return colored(str(value.unsigned), "yellow") + + +def Bool(value: lldb.SBValue, internal_dict): + while value.type.is_pointer: + value = value.Dereference() + return colored(str(value.GetValue()), "red") + + +def CharArray(value: lldb.SBValue, internal_dict): + return str([colored(f"'{char}'", "red") for char in value.uint8s]) + + +def Array(value: lldb.SBValue, internal_dict): + value = value.GetNonSyntheticValue() + return "[" + ", ".join([value[i].summary for i in range(value.num_children)]) + "]" + + +def Tuple(value: lldb.SBValue, internal_dict): + while value.type.is_pointer: + value = value.Dereference() + + num_children = value.num_children + + fields = [] + + for i in range(num_children): + key = value[i].name + val = value[i].summary + if key.startswith("Field"): + fields.append(f"{val}") + else: + fields.append(f"{key}: {val}") + + return "(" + ", ".join(fields) + f")" + + +def Enum(value, internal_dict): + tname = value.type.name.split("_")[1] + return colored(f"{tname}." + str(value.signed), "blue") + + +def EnumSet(value, internal_dict): + type_nim_name = value.type.name.split("_")[2] + # type_nim_name, nti = get_nti(value, type_nim_name) + + val = int(value.signed) + # if nti: + # enum_strings = [] + # i = 0 + # while val > 0: + # if (val & 1) == 1: + # enum_strings.append(reprEnum(i, nti)) + # val = val >> 1 + # i += 1 + + # return '{' + ', '.join(enum_strings) + '}' + return colored(f"{type_nim_name}." + str(val), "blue") + + +def Set(value, internal_dict): + vals = [] + max_vals = 7 + for child in value.children: + vals.append(child.value) + if len(vals) > max_vals: + vals.append("...") + break + + return "{" + ", ".join(vals) + "}" + + +def Table(value: lldb.SBValue, internal_dict): + fields = [] + + for i in range(value.num_children): + key = value[i].name + val = value[i].summary + fields.append(f"{key}: {val}") + + table_suffix = "Table" + return "{" + ", ".join(fields) + f"}}.{table_suffix}" + + +def HashSet(value: lldb.SBValue, internal_dict): + fields = [] + + for i in range(value.num_children): + fields.append(f"{value[i].summary}") + + table_suffix = "HashSet" + + return "{" + ", ".join(fields) + f"}}.{table_suffix}" + + +def StringTable(value: lldb.SBValue, internal_dict): + table = value.GetNonSyntheticValue() + mode = table["mode"].unsigned + + table_suffix = "StringTable" + + table_mode = "" + if mode == 0: + table_mode = "Case Sensitive" + elif mode == 1: + table_mode = "Case Insensitive" + elif mode == 2: + table_mode = "Style Insensitive" + + fields = [] + + for i in range(value.num_children): + key = value[i].name + val = value[i].summary + fields.append(f"{key}: {val}") + + return "{" + ", ".join(fields) + f"}}.{table_suffix}({table_mode})" + + +def Sequence(value: lldb.SBValue, internal_dict): + value = value.GetNonSyntheticValue() + + data_len = int(value["len"].unsigned) + data = value["p"]["data"] + base_data_type = data.type.GetArrayElementType() + + cast = data.Cast(base_data_type.GetArrayType(data_len)) + + return ( + "@[" + + ", ".join([cast[i].summary or cast[i].type.name for i in range(data_len)]) + + "]" + ) + + +class StringChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.data_type: lldb.SBType + self.first_element: lldb.SBValue + self.update() + self.count = 0 + + def num_children(self): + return self.count + + def get_child_index(self, name): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + offset = index * self.data_size + return self.first_element.CreateChildAtOffset( + "[" + str(index) + "]", offset, self.data_type + ) + + def update(self): + data = self.value["p"]["data"] + size = int(self.value["len"].unsigned) + + self.count = size + self.first_element = data + + self.data_type = data.type.GetArrayElementType().GetTypedefedType() + self.data_size = self.data_type.GetByteSize() + + def has_children(self): + return bool(self.num_children()) + + +class ArrayChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.data_type: lldb.SBType + self.first_element: lldb.SBValue + self.update() + + def num_children(self): + return self.value.num_children + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + offset = index * self.value[index].GetByteSize() + return self.first_element.CreateChildAtOffset( + "[" + str(index) + "]", offset, self.data_type + ) + + def update(self): + if not self.has_children(): + return + + self.first_element = self.value[0] + self.data_type = self.value.type.GetArrayElementType() + + def has_children(self): + return bool(self.num_children()) + + +class SeqChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.data_type: lldb.SBType + self.first_element: lldb.SBValue + self.data: lldb.SBValue + self.update() + + def num_children(self): + return int(self.value["len"].unsigned) + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + offset = index * self.data[index].GetByteSize() + return self.first_element.CreateChildAtOffset( + "[" + str(index) + "]", offset, self.data_type + ) + + def update(self): + if not self.has_children(): + return + + data = self.value["p"]["data"] + self.data_type = data.type.GetArrayElementType() + + self.data = data.Cast(self.data_type.GetArrayType(self.num_children())) + self.first_element = self.data + + def has_children(self): + return bool(self.num_children()) + + +class ObjectChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.data_type: lldb.SBType + self.first_element: lldb.SBValue + self.data: lldb.SBValue + self.children: OrderedDict[str, int] = OrderedDict() + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.children) + + def get_child_index(self, name: str): + return self.children[name] + + def get_child_at_index(self, index): + return self.child_list[index] + + def populate_children(self): + self.children.clear() + self.child_list = [] + stack = [self.value] + + index = 0 + + while stack: + cur_val = stack.pop() + while cur_val.type.is_pointer: + cur_val = cur_val.Dereference() + + if cur_val.num_children > 0 and cur_val[0].name == "m_type": + if "_" in cur_val.type.name: + tname = cur_val.type.name.split("_")[1].replace( + "colonObjectType", "" + ) + else: + tname = cur_val.type.name + if tname == "TNimTypeV2": + # We've reached the end + break + + if ( + cur_val.num_children > 0 + and cur_val[0].name == "Sup" + and cur_val[0].type.name.startswith("tyObject") + ): + stack.append(cur_val[0]) + + for i in range(cur_val.num_children): + child = cur_val[i] + if child.name == "Sup": + continue + self.children[child.name] = index + self.child_list.append(child) + index += 1 + + def update(self): + self.populate_children() + + def has_children(self): + return bool(self.num_children()) + + +class HashSetChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.child_list = [] + data = self.value["data"] + + tuple_len = int(data["len"].unsigned) + tuple = data["p"]["data"] + + base_data_type = tuple.type.GetArrayElementType() + + cast = tuple.Cast(base_data_type.GetArrayType(tuple_len)) + + index = 0 + for i in range(tuple_len): + el = cast[i] + field0 = int(el["Field0"].unsigned) + if field0 == 0: + continue + key = el["Field1"] + child = key.CreateValueFromAddress( + f"[{str(index)}]", key.GetLoadAddress(), key.GetType() + ) + index += 1 + + self.child_list.append(child) + + def has_children(self): + return bool(self.num_children()) + + +class SetCharChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.ty = self.value.target.FindFirstType("char") + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.child_list = [] + cur_pos = 0 + for child in self.value.children: + child_val = child.signed + if child_val != 0: + temp = child_val + num_bits = 8 + while temp != 0: + is_set = temp & 1 + if is_set == 1: + data = lldb.SBData.CreateDataFromInt(cur_pos) + child = self.value.synthetic_child_from_data( + f"[{len(self.child_list)}]", data, self.ty + ) + self.child_list.append(child) + temp = temp >> 1 + cur_pos += 1 + num_bits -= 1 + cur_pos += num_bits + else: + cur_pos += 8 + + def has_children(self): + return bool(self.num_children()) + + +class SetIntChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.ty = self.value.target.FindFirstType(f"NI64") + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.child_list = [] + bits = self.value.GetByteSize() * 8 + + cur_pos = -(bits // 2) + + if self.value.num_children > 0: + children = self.value.children + else: + children = [self.value] + + for child in children: + child_val = child.signed + if child_val != 0: + temp = child_val + num_bits = 8 + while temp != 0: + is_set = temp & 1 + if is_set == 1: + data = lldb.SBData.CreateDataFromInt(cur_pos) + child = self.value.synthetic_child_from_data( + f"[{len(self.child_list)}]", data, self.ty + ) + self.child_list.append(child) + temp = temp >> 1 + cur_pos += 1 + num_bits -= 1 + cur_pos += num_bits + else: + cur_pos += 8 + + def has_children(self): + return bool(self.num_children()) + + +class SetUIntChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.ty = self.value.target.FindFirstType(f"NU64") + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.child_list = [] + + cur_pos = 0 + if self.value.num_children > 0: + children = self.value.children + else: + children = [self.value] + + for child in children: + child_val = child.signed + if child_val != 0: + temp = child_val + num_bits = 8 + while temp != 0: + is_set = temp & 1 + if is_set == 1: + data = lldb.SBData.CreateDataFromInt(cur_pos) + child = self.value.synthetic_child_from_data( + f"[{len(self.child_list)}]", data, self.ty + ) + self.child_list.append(child) + temp = temp >> 1 + cur_pos += 1 + num_bits -= 1 + cur_pos += num_bits + else: + cur_pos += 8 + + def has_children(self): + return bool(self.num_children()) + + +class SetEnumChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.ty = self.value.target.FindFirstType(f"NU64") + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return int(name.lstrip("[").rstrip("]")) + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.child_list = [] + + cur_pos = 0 + if self.value.num_children > 0: + children = self.value.children + else: + children = [self.value] + + for child in children: + child_val = child.unsigned + if child_val != 0: + temp = child_val + num_bits = 8 + while temp != 0: + is_set = temp & 1 + if is_set == 1: + data = lldb.SBData.CreateDataFromInt(cur_pos) + child = self.value.synthetic_child_from_data( + f"[{len(self.child_list)}]", data, self.ty + ) + self.child_list.append(child) + temp = temp >> 1 + cur_pos += 1 + num_bits -= 1 + cur_pos += num_bits + else: + cur_pos += 8 + + def has_children(self): + return bool(self.num_children()) + + +class TableChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.children: OrderedDict[str, int] = OrderedDict() + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return self.children[name] + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.child_list = [] + data = self.value["data"] + + tuple_len = int(data["len"].unsigned) + tuple = data["p"]["data"] + + base_data_type = tuple.type.GetArrayElementType() + + cast = tuple.Cast(base_data_type.GetArrayType(tuple_len)) + + index = 0 + for i in range(tuple_len): + el = cast[i] + field0 = int(el["Field0"].unsigned) + if field0 == 0: + continue + key = el["Field1"] + val = el["Field2"] + child = val.CreateValueFromAddress( + key.summary, val.GetLoadAddress(), val.GetType() + ) + self.child_list.append(child) + self.children[key.summary] = index + index += 1 + + def has_children(self): + return bool(self.num_children()) + + +class StringTableChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + self.value = value + self.children: OrderedDict[str, int] = OrderedDict() + self.child_list: list[lldb.SBValue] = [] + self.update() + + def num_children(self): + return len(self.child_list) + + def get_child_index(self, name: str): + return self.children[name] + + def get_child_at_index(self, index): + return self.child_list[index] + + def update(self): + self.children.clear() + self.child_list = [] + data = self.value["data"] + + tuple_len = int(data["len"].unsigned) + tuple = data["p"]["data"] + + base_data_type = tuple.type.GetArrayElementType() + + cast = tuple.Cast(base_data_type.GetArrayType(tuple_len)) + + index = 0 + for i in range(tuple_len): + el = cast[i] + field0 = int(el["Field2"].unsigned) + if field0 == 0: + continue + key = el["Field0"] + val = el["Field1"] + child = val.CreateValueFromAddress( + key.summary, val.GetLoadAddress(), val.GetType() + ) + self.child_list.append(child) + self.children[key.summary] = index + index += 1 + + def has_children(self): + return bool(self.num_children()) + + +class CustomObjectChildrenProvider: + def __init__(self, value: lldb.SBValue, internalDict): + print("CUSTOMOBJ: ", value.name) + self.value: lldb.SBValue = get_synthetic(value) or value + for child in self.value.children: + print(child) + + def num_children(self): + return self.value.num_children + + def get_child_index(self, name: str): + return self.value.GetIndexOfChildWithName(name) + + def get_child_at_index(self, index): + return self.value.GetChildAtIndex(index) + + def update(self): + pass + + def has_children(self): + return self.num_children() > 0 + + +def echo(debugger: lldb.SBDebugger, command: str, result, internal_dict): + debugger.HandleCommand("po " + command) + + +SUMMARY_FUNCTIONS: dict[str, lldb.SBFunction] = {} +SYNTHETIC_FUNCTIONS: dict[str, lldb.SBFunction] = {} + + +def get_summary(value: lldb.SBValue) -> Union[str, None]: + base_type = get_base_type(value.type) + + fn = SUMMARY_FUNCTIONS.get(base_type.name) + if fn is None: + return None + + res = executeCommand( + f"{fn.name}(*({base_type.GetPointerType().name})" + str(value.GetLoadAddress()) + ");" + ) + + if res.error.fail: + return None + + return res.summary.strip('"') + + +def get_synthetic(value: lldb.SBValue) -> Union[lldb.SBValue, None]: + base_type = get_base_type(value.type) + + fn = SYNTHETIC_FUNCTIONS.get(base_type.name) + if fn is None: + return None + + res = executeCommand( + f"{fn.name}(*({base_type.GetPointerType().name})" + str(value.GetLoadAddress()) + ");" + ) + + if res.error.fail: + return None + + return res + + +def get_base_type(ty: lldb.SBType) -> lldb.SBType: + temp = ty + while temp.IsPointerType(): + temp = temp.GetPointeeType() + return temp + + +def breakpoint_function_wrapper(frame: lldb.SBFrame, bp_loc, internal_dict): + """This allows function calls to Nim for custom object summaries and synthetic children""" + debugger = lldb.debugger + + global SUMMARY_FUNCTIONS + global SYNTHETIC_FUNCTIONS + for tname, fn in SYNTHETIC_FUNCTIONS.items(): + print("DELETING SYNTH: ", tname) + debugger.HandleCommand(f"type synthetic delete -w nim {tname}") + + SUMMARY_FUNCTIONS = {} + SYNTHETIC_FUNCTIONS = {} + + target: lldb.SBTarget = debugger.GetSelectedTarget() + print("BREAKPOINT") + module = frame.GetSymbolContext(lldb.eSymbolContextModule).module + + for sym in module: + if not sym.name.startswith("lldbDebugSummary") and not sym.name.startswith( + "lldbDebugSynthetic" + ): + continue + + print("SYM: ", sym.name) + + fn_syms: lldb.SBSymbolContextList = target.FindFunctions(sym.name) + if not fn_syms.GetSize() > 0: + continue + fn_sym: lldb.SBSymbolContext = fn_syms.GetContextAtIndex(0) + + print("fn found!") + + fn: lldb.SBFunction = fn_sym.function + fn_type: lldb.SBType = fn.type + arg_types: lldb.SBTypeList = fn_type.GetFunctionArgumentTypes() + + if not arg_types.GetSize() > 0: + continue + arg_type: lldb.SBType = get_base_type(arg_types.GetTypeAtIndex(0)) + + print("FIRST ARG TYPE: ", arg_type.name) + + if sym.name.startswith("lldbDebugSummary"): + SUMMARY_FUNCTIONS[arg_type.name] = fn + elif sym.name.startswith("lldbDebugSynthetic"): + SYNTHETIC_FUNCTIONS[arg_type.name] = fn + debugger.HandleCommand( + f"type synthetic add -w nim -l {__name__}.CustomObjectChildrenProvider -x {arg_type.name}$" + ) + + +def executeCommand(command, *args): + debugger = lldb.debugger + process = debugger.GetSelectedTarget().GetProcess() + frame: lldb.SBFrame = process.GetSelectedThread().GetSelectedFrame() + # module = frame.GetSymbolContext(lldb.eSymbolContextModule).module + # for sym in module: + # print("SYM: ", sym.name) + # target = debugger.GetSelectedTarget() + + expr_options = lldb.SBExpressionOptions() + expr_options.SetIgnoreBreakpoints(False) + expr_options.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) + expr_options.SetTimeoutInMicroSeconds(30 * 1000 * 1000) # 30 second timeout + expr_options.SetTryAllThreads(True) + expr_options.SetUnwindOnError(False) + expr_options.SetGenerateDebugInfo(True) + expr_options.SetLanguage(lldb.eLanguageTypeC) + expr_options.SetCoerceResultToId(True) + res = frame.EvaluateExpression(command, expr_options) + # if res.error.fail: + # print("ERROR: ", res.error.GetError()) + # return str(res.error) + return res + + +def __lldb_init_module(debugger, internal_dict): + # debugger.HandleCommand(f"type summary add -w nim -n any -F {__name__}.CatchAll -x .*") + debugger.HandleCommand(f"type summary add -w nim -n sequence -F {__name__}.Sequence -x tySequence_+[[:alnum:]]+$") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SeqChildrenProvider -x tySequence_+[[:alnum:]]+$") + + debugger.HandleCommand(f"type summary add -w nim -n chararray -F {__name__}.CharArray -x char\s+[\d+]") + debugger.HandleCommand(f"type summary add -w nim -n array -F {__name__}.Array -x tyArray_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.ArrayChildrenProvider -x tyArray_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n string -F {__name__}.NimStringDesc NimStringDesc") + + debugger.HandleCommand(f"type summary add -w nim -n stringv2 -F {__name__}.NimStringV2 -x NimStringV2$") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringChildrenProvider -x NimStringV2$") + + debugger.HandleCommand(f"type summary add -w nim -n cstring -F {__name__}.NCSTRING NCSTRING") + + debugger.HandleCommand(f"type summary add -w nim -n object -F {__name__}.ObjectV2 -x tyObject_+[[:alnum:]]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.ObjectChildrenProvider -x tyObject_+[[:alnum:]]+_+[[:alnum:]]+$") + + debugger.HandleCommand(f"type summary add -w nim -n tframe -F {__name__}.ObjectV2 -x TFrame$") + + debugger.HandleCommand(f"type summary add -w nim -n rootobj -F {__name__}.ObjectV2 -x RootObj$") + + debugger.HandleCommand(f"type summary add -w nim -n enum -F {__name__}.Enum -x tyEnum_+[[:alnum:]]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n hashset -F {__name__}.HashSet -x tyObject_+HashSet_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.HashSetChildrenProvider -x tyObject_+HashSet_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n setuint -F {__name__}.Set -x tySet_+tyInt_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetIntChildrenProvider -x tySet_+tyInt[0-9]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n setint -F {__name__}.Set -x tySet_+tyInt[0-9]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n setuint2 -F {__name__}.Set -x tySet_+tyUInt[0-9]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyUInt[0-9]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyInt_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n setenum -F {__name__}.EnumSet -x tySet_+tyEnum_+[[:alnum:]]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyEnum_+[[:alnum:]]+_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n setchar -F {__name__}.Set -x tySet_+tyChar_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetCharChildrenProvider -x tySet_+tyChar_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n table -F {__name__}.Table -x tyObject_+Table_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.TableChildrenProvider -x tyObject_+Table_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n stringtable -F {__name__}.StringTable -x tyObject_+StringTableObj_+[[:alnum:]]+") + debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringTableChildrenProvider -x tyObject_+StringTableObj_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n tuple2 -F {__name__}.Tuple -x tyObject_+Tuple_+[[:alnum:]]+") + debugger.HandleCommand(f"type summary add -w nim -n tuple -F {__name__}.Tuple -x tyTuple_+[[:alnum:]]+") + # debugger.HandleCommand(f"type summary add -w nim -n TNimType -F {__name__}.Object TNimType") + debugger.HandleCommand(f"type summary add -w nim -n TNimTypeV2 -F {__name__}.ObjectV2 TNimTypeV2") + # debugger.HandleCommand(f"type summary add -w nim -n TNimNode -F {__name__}.Object TNimNode") + debugger.HandleCommand(f"type summary add -w nim -n float -F {__name__}.Float NF") + debugger.HandleCommand(f"type summary add -w nim -n float32 -F {__name__}.Float NF32") + debugger.HandleCommand(f"type summary add -w nim -n float64 -F {__name__}.Float NF64") + debugger.HandleCommand(f"type summary add -w nim -n integer -F {__name__}.Number -x NI") + debugger.HandleCommand(f"type summary add -w nim -n integer8 -F {__name__}.Number -x NI8") + debugger.HandleCommand(f"type summary add -w nim -n integer16 -F {__name__}.Number -x NI16") + debugger.HandleCommand(f"type summary add -w nim -n integer32 -F {__name__}.Number -x NI32") + debugger.HandleCommand(f"type summary add -w nim -n integer64 -F {__name__}.Number -x NI64") + debugger.HandleCommand(f"type summary add -w nim -n bool -F {__name__}.Bool -x bool") + debugger.HandleCommand(f"type summary add -w nim -n bool2 -F {__name__}.Bool -x NIM_BOOL") + debugger.HandleCommand(f"type summary add -w nim -n uinteger -F {__name__}.UnsignedNumber -x NU") + debugger.HandleCommand(f"type summary add -w nim -n uinteger8 -F {__name__}.UnsignedNumber -x NU8") + debugger.HandleCommand(f"type summary add -w nim -n uinteger16 -F {__name__}.UnsignedNumber -x NU16") + debugger.HandleCommand(f"type summary add -w nim -n uinteger32 -F {__name__}.UnsignedNumber -x NU32") + debugger.HandleCommand(f"type summary add -w nim -n uinteger64 -F {__name__}.UnsignedNumber -x NU64") + debugger.HandleCommand("type category enable nim") + debugger.HandleCommand(f"command script add -f {__name__}.echo echo") + debugger.HandleCommand(f"command script add -f {__name__}.handle_command ddp") + debugger.HandleCommand(f"breakpoint command add -F {__name__}.breakpoint_function_wrapper --script-type python 1") \ No newline at end of file From 6994e1b1d7962f9c61887c7e606aeccbebf9bef6 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Sat, 4 Mar 2023 01:57:30 -0500 Subject: [PATCH 4236/4254] `--embedsrc` for JavaScript (#21467) Co-authored-by: quantimnot --- compiler/jsgen.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 5df40b996..d0a143793 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -735,6 +735,8 @@ proc genLineDir(p: PProc, n: PNode) = let line = toLinenumber(n.info) if line < 0: return + if optEmbedOrigSrc in p.config.globalOptions: + lineF(p, "//$1$n", [sourceLine(p.config, n.info)]) if optLineDir in p.options or optLineDir in p.config.options: lineF(p, "$1", [lineDir(p.config, n.info, line)]) if hasFrameInfo(p): From d950e5f3a8efe0c3be8e773cce4a89807833ffea Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 4 Mar 2023 20:07:33 +0800 Subject: [PATCH 4237/4254] remove nosinks hacks from compiler (#21469) --- compiler/cgen.nim | 2 +- compiler/depends.nim | 2 +- compiler/passes.nim | 4 ++-- compiler/sem.nim | 4 ++-- compiler/semcall.nim | 2 +- compiler/seminst.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/sigmatch.nim | 2 +- compiler/vm.nim | 6 +++--- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d051934b5..e24a2cb1e 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1940,7 +1940,7 @@ template injectG() {.dirty.} = graph.backend = newModuleList(graph) let g = BModuleList(graph.backend) -proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = injectG() result = newModule(g, module, graph.config) result.idgen = idgen diff --git a/compiler/depends.nim b/compiler/depends.nim index 2087198f2..823e0f970 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -100,7 +100,7 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) = rope(project.splitFile.name), b.dotGraph], changeFileExt(project, "dot")) -proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = var g: PGen new(g) g.module = module diff --git a/compiler/passes.nim b/compiler/passes.nim index 38c133d69..536a64714 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -241,14 +241,14 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = graph.compileSystemModule() discard graph.compileModule(projectFile, {sfMainModule}) -proc mySemOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc mySemOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = result = preparePContext(graph, module, idgen) proc mySemClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = var c = PContext(context) closePContext(graph, c, n) -proc mySemProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = +proc mySemProcess(context: PPassContext, n: PNode): PNode = result = semWithPContext(PContext(context), n) const semPass* = makePass(mySemOpen, mySemProcess, mySemClose, diff --git a/compiler/sem.nim b/compiler/sem.nim index a5d06f3fe..48a7d56c8 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -666,7 +666,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) = n.add prc.ast c.lastGenericIdx = c.generics.len -proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PContext {.nosinks.} = +proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PContext = result = newContext(graph, module) result.idgen = idgen result.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil) @@ -770,7 +770,7 @@ proc recoverContext(c: PContext) = while getCurrOwner(c).kind != skModule: popOwner(c) while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next -proc semWithPContext*(c: PContext, n: PNode): PNode {.nosinks.} = +proc semWithPContext*(c: PContext, n: PNode): PNode = # no need for an expensive 'try' if we stop after the first error anyway: if c.config.errorMax <= 1: result = semStmtAndGenerateGenerics(c, n) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 2147a9645..ba7908aa5 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -601,7 +601,7 @@ proc tryDeref(n: PNode): PNode = result.add n proc semOverloadedCall(c: PContext, n, nOrig: PNode, - filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} = + filter: TSymKinds, flags: TExprFlags): PNode = var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) if r.state == csMatch: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 80d455d1e..b5fe244b0 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -314,7 +314,7 @@ proc fillMixinScope(c: PContext) = p = p.next proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, - info: TLineInfo): PSym {.nosinks.} = + info: TLineInfo): PSym = ## Generates a new instance of a generic procedure. ## The `pt` parameter is a type-unsafe mapping table used to link generic ## parameters to their concrete types within the generic instance. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6237e6eb0..6d1ce388d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1692,7 +1692,7 @@ proc semProcAnnotation(c: PContext, prc: PNode; return result -proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} = +proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = ## used for resolving 'auto' in lambdas based on their callsite var n = n let original = n[namePos].sym diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index f8c7fa870..87a4fdf1c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2674,7 +2674,7 @@ proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool = proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; - op: TTypeAttachedOp; col: int): PSym {.nosinks.} = + op: TTypeAttachedOp; col: int): PSym = var m = newCandidate(c, dc.typ) if col >= dc.typ.len: localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") diff --git a/compiler/vm.nim b/compiler/vm.nim index 96f05c0f9..e00f0f02e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1893,7 +1893,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var error: string let ast = parseString(regs[rb].node.strVal, c.cache, c.config, regs[rc].node.strVal, 0, - proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = + proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) if error.len > 0: @@ -1908,7 +1908,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var error: string let ast = parseString(regs[rb].node.strVal, c.cache, c.config, regs[rc].node.strVal, 0, - proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = + proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) if error.len > 0: @@ -2309,7 +2309,7 @@ proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) = else: refresh(PCtx graph.vm, module, idgen) -proc setupEvalGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = +proc setupEvalGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = #var c = newEvalContext(module, emRepl) #c.features = {allowCast, allowInfiniteLoops} #pushStackFrame(c, newStackFrame()) From 04a494f8cfe960104150dd288d587d7e2cf3bd8a Mon Sep 17 00:00:00 2001 From: Sultan Al Isaiee Date: Sat, 4 Mar 2023 18:53:57 +0400 Subject: [PATCH 4238/4254] Add warning to specify timeout value in milliseconds, Fix #21449 (#21471) a warning message been added to the documentation to remind users that the timeout parameter is expressed in milliseconds, not seconds. to help prevent confusion and unexpected behaviours. --- lib/pure/osproc.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 4cdd98c0d..915337f12 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -220,6 +220,10 @@ proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, ## ## On posix, if the process has exited because of a signal, 128 + signal ## number will be returned. + ## + ## .. warning:: When working with `timeout` parameters, remember that the value is + ## typically expressed in milliseconds, and ensure that the correct unit of time + ## is used to avoid unexpected behavior. proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", raises: [OSError], tags: [].} ## Return `-1` if the process is still running. Otherwise the process' exit code. From 7bde421e4dae1f078ad5940dda8199df00b725cc Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:56:51 +0100 Subject: [PATCH 4239/4254] Fix #21272: Rewrite parts of pickBestCandidate (#21465) * Make pickBestCandidate store syms * Remove useless cursor * Try making pickBestCandidate more readable * Fix advance order * Revert back to seq with lots of comments --------- Co-authored-by: SirOlaf <> --- compiler/semcall.nim | 86 +++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index ba7908aa5..54f03026f 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -43,6 +43,7 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode, best, alt: var TCandidate, o: var TOverloadIter, diagnostics: bool): seq[tuple[s: PSym, scope: int]] = + ## puts all overloads into a seq and prepares best+alt result = @[] var symx = initOverloadIter(o, c, headSymbol) while symx != nil: @@ -64,36 +65,35 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, errors: var CandidateErrors, diagnosticsFlag: bool, errorsEnabled: bool, flags: TExprFlags) = + # `matches` may find new symbols, so keep track of count + var symCount = c.currentScope.symbols.counter + var o: TOverloadIter - var sym = initOverloadIter(o, c, headSymbol) - var scope = o.lastOverloadScope - # Thanks to the lazy semchecking for operands, we need to check whether - # 'initCandidate' modifies the symbol table (via semExpr). - # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))' - let counterInitial = c.currentScope.symbols.counter - var syms: seq[tuple[s: PSym, scope: int]] - var noSyms = true - var nextSymIndex = 0 - while sym != nil: - if sym.kind in filter: - # Initialise 'best' and 'alt' with the first available symbol - initCandidate(c, best, sym, initialBinding, scope, diagnosticsFlag) - initCandidate(c, alt, sym, initialBinding, scope, diagnosticsFlag) - best.state = csNoMatch - break - else: - sym = nextOverloadIter(o, c, headSymbol) - scope = o.lastOverloadScope - var z: TCandidate - while sym != nil: - if sym.kind notin filter: - sym = nextOverloadIter(o, c, headSymbol) - scope = o.lastOverloadScope - continue + # https://github.com/nim-lang/Nim/issues/21272 + # prevent mutation during iteration by storing them in a seq + # luckily `initCandidateSymbols` does just that + var syms = initCandidateSymbols(c, headSymbol, initialBinding, filter, + best, alt, o, diagnosticsFlag) + if len(syms) == 0: + return + # current overload being considered + var sym = syms[0].s + var scope = syms[0].scope + + # starts at 1 because 0 is already done with setup, only needs checking + var nextSymIndex = 1 + var z: TCandidate # current candidate + while true: determineType(c, sym) initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag) - if c.currentScope.symbols.counter == counterInitial or syms.len != 0: + + # this is kinda backwards as without a check here the described + # problems in recalc would not happen, but instead it 100% + # does check forever in some cases + if c.currentScope.symbols.counter == symCount: + # may introduce new symbols with caveats described in recalc branch matches(c, n, orig, z) + if z.state == csMatch: # little hack so that iterators are preferred over everything else: if sym.kind == skIterator: @@ -113,22 +113,36 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, firstMismatch: z.firstMismatch, diagnostics: z.diagnostics)) else: + # this branch feels like a ticking timebomb + # one of two bad things could happen + # 1) new symbols are discovered but the loop ends before we recalc + # 2) new symbols are discovered and resemmed forever + # not 100% sure if these are possible though as they would rely + # on somehow introducing a new overload during overload resolution + # Symbol table has been modified. Restart and pre-calculate all syms # before any further candidate init and compare. SLOW, but rare case. syms = initCandidateSymbols(c, headSymbol, initialBinding, filter, best, alt, o, diagnosticsFlag) - noSyms = false - if noSyms: - sym = nextOverloadIter(o, c, headSymbol) - scope = o.lastOverloadScope - elif nextSymIndex < syms.len: - # rare case: retrieve the next pre-calculated symbol - sym = syms[nextSymIndex].s - scope = syms[nextSymIndex].scope - nextSymIndex += 1 - else: + + # reset counter because syms may be in a new order + symCount = c.currentScope.symbols.counter + nextSymIndex = 0 + + # just in case, should be impossible though + if syms.len == 0: + break + + if nextSymIndex > high(syms): + # we have reached the end break + # advance to next sym + sym = syms[nextSymIndex].s + scope = syms[nextSymIndex].scope + inc(nextSymIndex) + + proc effectProblem(f, a: PType; result: var string; c: PContext) = if f.kind == tyProc and a.kind == tyProc: if tfThread in f.flags and tfThread notin a.flags: From 05e8a60bb4fe40d450aaec4603209e310ea490a4 Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 5 Mar 2023 12:14:59 -0700 Subject: [PATCH 4240/4254] Add line directives for C code variables (#21466) * Add line directives for C code variables * Refactor genCLineDir to only use toFullPath if necessary --- compiler/cgen.nim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e24a2cb1e..d2095016c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -273,7 +273,8 @@ proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) = [rope(makeSingleLineCString(filename)), rope(line)]) proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) = - genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf) + if optLineDir in conf.options: + genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf) proc freshLineInfo(p: BProc; info: TLineInfo): bool = if p.lastLineInfo.line != info.line or @@ -287,7 +288,7 @@ proc genLineDir(p: BProc, t: PNode) = if optEmbedOrigSrc in p.config.globalOptions: p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L") - genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config) + genCLineDir(p.s(cpsStmts), t.info, p.config) if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx: if freshLineInfo(p, t.info): @@ -566,6 +567,9 @@ proc localVarDecl(p: BProc; n: PNode): Rope = if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) + + genCLineDir(result, n.info, p.config) + result.add getTypeDesc(p.module, s.typ, skVar) if s.constraint.isNil: if sfRegister in s.flags: result.add(" register") From 4d76725299e524e19d515c04d923bd408607a966 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 6 Mar 2023 14:12:47 +0800 Subject: [PATCH 4241/4254] closes #16654; add a test case (#21478) --- tests/errmsgs/t16654.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/errmsgs/t16654.nim diff --git a/tests/errmsgs/t16654.nim b/tests/errmsgs/t16654.nim new file mode 100644 index 000000000..749707c06 --- /dev/null +++ b/tests/errmsgs/t16654.nim @@ -0,0 +1,12 @@ +discard """ + cmd: "nim check $options $file" + errormsg: "type mismatch: got but expected 'float'" +""" + +when true: # bug #16654 + func fn[T](a: T, op: proc(a: T): float) = discard + proc main() = + let v = 1 + proc bar(r: auto): auto = v + fn(1, bar) + main() From 2d9af2bd559d03c4f6b2a5f89be316f2465a091b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 6 Mar 2023 17:34:41 +0800 Subject: [PATCH 4242/4254] closes #20704; add a test case (#21480) --- tests/stdlib/tsugar.nim | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index 6ef3ae519..1b629165a 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -3,7 +3,7 @@ discard """ x + y = 30 ''' """ -import std/[sugar, algorithm, random, sets, tables, strutils] +import std/[sugar, algorithm, random, sets, tables, strutils, sequtils] import std/[syncio, assertions] type # for capture test, ref #20679 @@ -287,6 +287,17 @@ proc mainProc() = doAssertRaises(AssertionDefect): doAssert false doAssert "except AssertionDefect" in s2 + block: # bug #20704 + proc test() = + var xs, ys: seq[int] + for i in 0..5: + xs.add(i) + + xs.apply(d => ys.add(d)) + doAssert ys == @[0, 1, 2, 3, 4, 5] + + test() + static: main() mainProc() From 64a0355f3f95c9ec8ca3597f8028819b489f08c8 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 6 Mar 2023 22:30:22 +0800 Subject: [PATCH 4243/4254] fixes #21377; fixes `@[]` and `{}` type inference as returns in generics (#21475) * fixes `@[]` type inference in generics * add issue links * fixes macros and iterators * refactor * add one more test --- compiler/semexprs.nim | 2 +- compiler/seminst.nim | 11 +++++++-- compiler/semmagic.nim | 6 ++++- tests/types/ttopdowninference.nim | 37 ++++++++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9cf206b4c..976d7c757 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -998,7 +998,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) if callee.magic != mNone: - result = magicsAfterOverloadResolution(c, result, flags) + result = magicsAfterOverloadResolution(c, result, flags, expectedType) when false: if result.typ != nil and not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty): diff --git a/compiler/seminst.nim b/compiler/seminst.nim index b5fe244b0..25e5b267e 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -127,11 +127,18 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) = if sfGenSym in param.flags: idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym) freshGenSyms(c, b, result, orig, symMap) - + if sfBorrow notin orig.flags: # We do not want to generate a body for generic borrowed procs. # As body is a sym to the borrowed proc. - b = semProcBody(c, b) + let resultType = # todo probably refactor it into a function + if result.kind == skMacro: + sysTypeFromName(c.graph, n.info, "NimNode") + elif not isInlineIterator(result.typ): + result.typ[0] + else: + nil + b = semProcBody(c, b, resultType) result.ast[bodyPos] = hloBody(c, b) excl(result.flags, sfForward) trackProc(c, result, result.ast[bodyPos]) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 751ca8fe7..b4c6cd275 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -526,7 +526,7 @@ proc checkDefault(c: PContext, n: PNode): PNode = message(c.config, n.info, warnUnsafeDefault, typeToString(constructed)) proc magicsAfterOverloadResolution(c: PContext, n: PNode, - flags: TExprFlags): PNode = + flags: TExprFlags; expectedType: PType = nil): PNode = ## This is the preferred code point to implement magics. ## ``c`` the current module, a symbol table to a very good approximation ## ``n`` the ast like it would be passed to a real macro @@ -635,5 +635,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = n of mPrivateAccess: result = semPrivateAccess(c, n) + of mArrToSeq: + result = n + if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty: + result.typ = expectedType # type inference for empty sequence # bug #21377 else: result = n diff --git a/tests/types/ttopdowninference.nim b/tests/types/ttopdowninference.nim index 310dbb2ad..cabc798ed 100644 --- a/tests/types/ttopdowninference.nim +++ b/tests/types/ttopdowninference.nim @@ -245,7 +245,7 @@ block: # bug #11777 var s: S = {1, 2} doAssert 1 in s -block: # regression #20807 +block: # bug #20807 var s: seq[string] template fail = s = @[] @@ -255,3 +255,38 @@ block: # regression #20807 test: fail() doAssert not (compiles do: let x: seq[int] = `@`[string]([])) + +block: # bug #21377 + proc b[T](v: T): seq[int] = + let x = 0 + @[] + + doAssert b(0) == @[] + +block: # bug #21377 + proc b[T](v: T): seq[T] = + let x = 0 + @[] + + doAssert b(0) == @[] + +block: # bug #21377 + proc b[T](v: T): set[bool] = + let x = 0 + {} + + doAssert b(0) == {} + +block: # bug #21377 + proc b[T](v: T): array[0, int] = + let x = 0 + [] + + doAssert b(0) == [] + +block: # bug #21377 + proc b[T](v: T): array[0, (string, string)] = + let x = 0 + {:} + + doAssert b(0) == {:} From 25eef64fe1969581436696556e0bf10ef25aa3ec Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 7 Mar 2023 01:31:53 +1100 Subject: [PATCH 4244/4254] Remove Defect from raises list in `std/times` (#21473) * Remove Defect from raises list Since defects aren't tracked anymore this causes a hint to pop up mentioning it * Still track Defect when getting ran with an older Nim version The raises followed a pattern so moving them into a pragma didn't seem to cause any extra problems --- lib/pure/times.nim | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 70af466d9..138f2d9ec 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -408,6 +408,16 @@ const unitWeights: array[FixedTimeUnit, int64] = [ 7 * secondsInDay * 1e9.int64, ] +when (NimMajor, NimMinor) >= (1, 4): + # Newer versions of Nim don't track defects + {.pragma: parseFormatRaises, raises: [TimeParseError, TimeFormatParseError].} + {.pragma: parseRaises, raises: [TimeParseError].} +else: + # Still track when using older versions + {.pragma: parseFormatRaises, raises: [TimeParseError, TimeFormatParseError, Defect].} + {.pragma: parseRaises, raises: [TimeParseError, Defect].} + + # # Helper procs # @@ -2134,8 +2144,7 @@ proc format*(time: Time, f: static[string], zone: Timezone = local()): string result = time.inZone(zone).format(f2) proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), - loc: DateTimeLocale = DefaultLocale): DateTime - {.raises: [TimeParseError, Defect].} = + loc: DateTimeLocale = DefaultLocale): DateTime {.parseRaises.} = ## Parses `input` as a `DateTime` using the format specified by `f`. ## If no UTC offset was parsed, then `input` is assumed to be specified in ## the `zone` timezone. If a UTC offset was parsed, the result will be @@ -2178,8 +2187,7 @@ proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), result = toDateTime(parsed, zone, f, input) proc parse*(input, f: string, tz: Timezone = local(), - loc: DateTimeLocale = DefaultLocale): DateTime - {.raises: [TimeParseError, TimeFormatParseError, Defect].} = + loc: DateTimeLocale = DefaultLocale): DateTime {.parseFormatRaises.} = ## Shorthand for constructing a `TimeFormat` and using it to parse ## `input` as a `DateTime`. ## @@ -2192,14 +2200,12 @@ proc parse*(input, f: string, tz: Timezone = local(), result = input.parse(dtFormat, tz, loc = loc) proc parse*(input: string, f: static[string], zone: Timezone = local(), - loc: DateTimeLocale = DefaultLocale): - DateTime {.raises: [TimeParseError, Defect].} = + loc: DateTimeLocale = DefaultLocale): DateTime {.parseRaises.} = ## Overload that validates `f` at compile time. const f2 = initTimeFormat(f) result = input.parse(f2, zone, loc = loc) -proc parseTime*(input, f: string, zone: Timezone): Time - {.raises: [TimeParseError, TimeFormatParseError, Defect].} = +proc parseTime*(input, f: string, zone: Timezone): Time {.parseFormatRaises.} = ## Shorthand for constructing a `TimeFormat` and using it to parse ## `input` as a `DateTime`, then converting it a `Time`. ## @@ -2211,7 +2217,7 @@ proc parseTime*(input, f: string, zone: Timezone): Time parse(input, f, zone).toTime() proc parseTime*(input: string, f: static[string], zone: Timezone): Time - {.raises: [TimeParseError, Defect].} = + {.parseRaises.} = ## Overload that validates `format` at compile time. const f2 = initTimeFormat(f) result = input.parse(f2, zone).toTime() From 6ef94301538f0a17461630c08c456112954e66bb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:34:02 +0800 Subject: [PATCH 4245/4254] closes #6231; add a test case (#21485) --- tests/generics/tgenerics_various.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim index 37b6e43a1..4cfa47809 100644 --- a/tests/generics/tgenerics_various.nim +++ b/tests/generics/tgenerics_various.nim @@ -262,3 +262,8 @@ proc doSomething[A, B](t: tuple[a: A, b: B]) = discard discard identity((c: 1, d: 2)) doSomething(identity((1, 2))) + +# bug #6231 +proc myProc[T, U](x: T or U) = discard + +myProc[int, string](x = 2) From 2f89f1eb780ab32be31dbe4074af70b587ad2f36 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 7 Mar 2023 20:17:05 +0800 Subject: [PATCH 4246/4254] closes #8295; add a test case (#21486) --- tests/generics/tgeneric0.nim | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index 44c34917d..b5e1c4bb4 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -153,3 +153,16 @@ proc unzip*[T,U](xs: List[tuple[t: T, u: U]]): (List[T], List[U]) = discard proc unzip2*[T,U](xs: List[(T,U)]): (List[T], List[U]) = discard +type + AtomicType = pointer|ptr|int + + Atomic[T: AtomicType] = distinct T + + Block[T: AtomicType] = object + + AtomicContainer[T: AtomicType] = object + b: Atomic[ptr Block[T]] + +# bug #8295 +var x = AtomicContainer[int]() +doAssert (ptr Block[int])(x.b) == nil From 8e9fc5e63968177c75d93af08d32717bf6c97693 Mon Sep 17 00:00:00 2001 From: ghost <97684920+sslime336@users.noreply.github.com> Date: Thu, 9 Mar 2023 05:34:59 +0800 Subject: [PATCH 4247/4254] a better message if graphviz's dot/nodejs is not found in PATH (#21488) * finish issue #21474: a better message if dot is not found locally when using gendepend * fix a typo in compiler * trim empty path reported in `findNodeJs` * compiler/main.nim: switch raise to simply quit --- compiler/main.nim | 7 +++++++ compiler/nodejs.nim | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/main.nim b/compiler/main.nim index d37d26478..ff870a14a 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -71,6 +71,13 @@ proc commandGenDepend(graph: ModuleGraph) = let project = graph.config.projectFull writeDepsFile(graph) generateDot(graph, project) + + # dot in graphivz tool kit is required + let graphvizDotPath = findExe("dot") + if graphvizDotPath.len == 0: + quit("gendepend: Graphviz's tool dot is required," & + "see https://graphviz.org/download for downloading") + execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png").string & ' ' & changeFileExt(project, "dot").string) diff --git a/compiler/nodejs.nim b/compiler/nodejs.nim index 283643e8d..c1feb196a 100644 --- a/compiler/nodejs.nim +++ b/compiler/nodejs.nim @@ -7,4 +7,4 @@ proc findNodeJs*(): string {.inline.} = result = findExe("node") if result.len == 0: echo "Please install NodeJS first, see https://nodejs.org/en/download" - raise newException(IOError, "NodeJS not found in PATH: " & result) + raise newException(IOError, "NodeJS not found in PATH") From 72e262666bdf2bb3c239183dd32b48bb05d113aa Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 9 Mar 2023 15:09:08 +0800 Subject: [PATCH 4248/4254] fixes quoted variables with typedesc types (#21493) --- compiler/semexprs.nim | 2 +- tests/stdlib/tmacros.nim | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 976d7c757..cfa34fcdc 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2206,7 +2206,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode) for i in 1.. Date: Fri, 10 Mar 2023 16:28:51 +0800 Subject: [PATCH 4249/4254] fixes #21023; Segfault when mixing seqs, orc, variants and futures (#21497) * fixes #21023; Segfault when mixing seqs, orc, variants and futures * fixes none of the branches were explicitly selected * add one more test * one more test --- compiler/semobjconstr.nim | 61 +++++++++++++++++-------- tests/arc/tcaseobj.nim | 61 +++++++++++++++++++++++++ tests/objects/tobject_default_value.nim | 32 +++++++++++++ 3 files changed, 136 insertions(+), 18 deletions(-) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 15e53a639..29067cfa4 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -142,15 +142,45 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin if result.len != 0: result.add ", " result.add field.sym.name.s.quoteStr +proc locateFieldInDefaults(sym: PSym, defaults: seq[PNode]): bool = + result = false + for d in defaults: + if sym.id == d[0].sym.id: + return true + proc collectMissingFields(c: PContext, fieldsRecList: PNode, - constrCtx: var ObjConstrContext) = - for r in directFieldsInRecList(fieldsRecList): - if constrCtx.needsFullInit or - sfRequiresInit in r.sym.flags or - r.sym.typ.requiresInit: + constrCtx: var ObjConstrContext, defaults: seq[PNode] + ): seq[PSym] = + for r in directFieldsInRecList(fieldsRecList): let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr) - if assignment == nil: - constrCtx.missingFields.add r.sym + if assignment == nil and not locateFieldInDefaults(r.sym, defaults): + if constrCtx.needsFullInit or + sfRequiresInit in r.sym.flags or + r.sym.typ.requiresInit: + constrCtx.missingFields.add r.sym + else: + result.add r.sym + +proc collectMissingCaseFields(c: PContext, branchNode: PNode, + constrCtx: var ObjConstrContext, defaults: seq[PNode]): seq[PSym] = + if branchNode != nil: + let fieldsRecList = branchNode[^1] + result = collectMissingFields(c, fieldsRecList, constrCtx, defaults) + +proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode, + constrCtx: var ObjConstrContext, defaults: var seq[PNode]) = + let res = collectMissingCaseFields(c, branchNode, constrCtx, defaults) + for sym in res: + let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), sym.typ.owner) + let recTyp = sym.typ.skipTypes(defaultFieldsSkipTypes) + rawAddSon(asgnType, recTyp) + let asgnExpr = newTree(nkCall, + newSymNode(getSysMagic(c.graph, constrCtx.initExpr.info, "zeroDefault", mZeroDefault)), + newNodeIT(nkType, constrCtx.initExpr.info, asgnType) + ) + asgnExpr.flags.incl nfUseDefaultField + asgnExpr.typ = recTyp + defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr) proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] = @@ -166,11 +196,6 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, let fields = branch[^1] fieldsPresentInInitExpr(c, fields, constrCtx.initExpr) - template collectMissingFields(branchNode: PNode) = - if branchNode != nil: - let fields = branchNode[^1] - collectMissingFields(c, fields, constrCtx) - let discriminator = n[0] internalAssert c.config, discriminator.kind == nkSym var selectedBranch = -1 @@ -288,8 +313,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, # When a branch is selected with a partial match, some of the fields # that were not initialized may be mandatory. We must check for this: if result.status == initPartial: - collectMissingFields branchNode - + collectOrAddMissingCaseFields(c, branchNode, constrCtx, result.defaults) else: result.status = initNone let discriminatorVal = semConstrField(c, flags + {efPreferStatic}, @@ -302,7 +326,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, # a result: let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0) let matchedBranch = n.pickCaseBranch defaultValue - collectMissingFields matchedBranch + discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[]) else: result.status = initPartial if discriminatorVal.kind == nkIntLit: @@ -312,11 +336,12 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, if matchedBranch != nil: let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags) result.defaults.add defaults - collectMissingFields matchedBranch + collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults) else: # All bets are off. If any of the branches has a mandatory # fields we must produce an error: - for i in 1.. Date: Fri, 10 Mar 2023 21:19:31 +0800 Subject: [PATCH 4250/4254] fixes #21306; fixes #20485; don't transform yields in the var section when introducing new local vars [backport: 1.6] (#21489) * fixes #21306; don't transform yields in the var section when introducing new local vars * adds `inVarSection` so the var section in the var section is freshed * use `isIntroducingNewLocalVars` to avoid yield transformations in var sections * fixes comments --- compiler/transf.nim | 5 +- tests/iter/t21306.nim | 114 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 tests/iter/t21306.nim diff --git a/compiler/transf.nim b/compiler/transf.nim index 7277e6898..445bc1df1 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -50,6 +50,7 @@ type module: PSym transCon: PTransCon # top of a TransCon stack inlining: int # > 0 if we are in inlining context (copy vars) + isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields) contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' deferDetected, tooEarly: bool graph: ModuleGraph @@ -450,7 +451,9 @@ proc transformYield(c: PTransf, n: PNode): PNode = result.add(c.transCon.forLoopBody) else: # we need to introduce new local variables: + c.isIntroducingNewLocalVars = true # don't transform yields when introducing new local vars result.add(introduceNewLocalVars(c, c.transCon.forLoopBody)) + c.isIntroducingNewLocalVars = false for idx in 0 ..< result.len: var changeNode = result[idx] @@ -1036,7 +1039,7 @@ proc transform(c: PTransf, n: PNode): PNode = else: result = transformSons(c, n) of nkYieldStmt: - if c.inlining > 0: + if c.inlining > 0 and not c.isIntroducingNewLocalVars: result = transformYield(c, n) else: result = transformSons(c, n) diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim new file mode 100644 index 000000000..43fea9c80 --- /dev/null +++ b/tests/iter/t21306.nim @@ -0,0 +1,114 @@ +# bug #21306 +type + FutureState {.pure.} = enum + Pending, Finished, Cancelled, Failed + + FutureBase = ref object of RootObj + state: FutureState + error: ref CatchableError + id: uint + + Future[T] = ref object of FutureBase + closure: iterator(f: Future[T]): FutureBase {.raises: [Defect, CatchableError, Exception], gcsafe.} + value: T + +template setupFutureBase() = + new(result) + result.state = FutureState.Pending + +proc newFutureImpl[T](): Future[T] = + setupFutureBase() + +template newFuture[T](fromProc: static[string] = ""): Future[T] = + newFutureImpl[T]() + +proc internalRead[T](fut: Future[T]): T = + when T isnot void: + return fut.value + +template await[T](f: Future[T]): untyped = + when declared(chronosInternalRetFuture): + when not declaredInScope(chronosInternalTmpFuture): + var chronosInternalTmpFuture {.inject.}: FutureBase = f + else: + chronosInternalTmpFuture = f + + yield chronosInternalTmpFuture + + when T isnot void: + cast[type(f)](chronosInternalTmpFuture).internalRead() + +type + VerifierError {.pure.} = enum + Invalid + MissingParent + UnviableFork + Duplicate + ProcessingCallback = proc() {.gcsafe, raises: [Defect].} + BlockVerifier = + proc(signedBlock: int): + Future[VerifierError] {.gcsafe, raises: [Defect].} + + SyncQueueKind {.pure.} = enum + Forward, Backward + + SyncRequest[T] = object + kind: SyncQueueKind + index: uint64 + slot: uint64 + count: uint64 + item: T + + SyncResult[T] = object + request: SyncRequest[T] + data: seq[ref int] + + SyncQueue[T] = ref object + kind: SyncQueueKind + readyQueue: seq[SyncResult[T]] + blockVerifier: BlockVerifier + +iterator blocks[T](sq: SyncQueue[T], + sr: SyncResult[T]): ref int = + case sq.kind + of SyncQueueKind.Forward: + for i in countup(0, len(sr.data) - 1): + yield sr.data[i] + of SyncQueueKind.Backward: + for i in countdown(len(sr.data) - 1, 0): + yield sr.data[i] + +proc push[T](sq: SyncQueue[T]; sr: SyncRequest[T]; data: seq[ref int]; + processingCb: ProcessingCallback = nil): Future[void] {. + stackTrace: off, gcsafe.} = + iterator push_436208182(chronosInternalRetFuture: Future[void]): FutureBase {. + closure, gcsafe, raises: [Defect, CatchableError, Exception].} = + block: + template result(): auto {.used.} = + {.fatal: "You should not reference the `result` variable inside" & + " a void async proc".} + + let item = default(SyncResult[T]) + for blk in sq.blocks(item): + let res = await sq.blockVerifier(blk[]) + + var resultFuture = newFuture[void]("push") + resultFuture.closure = push_436208182 + return resultFuture + +type + SomeTPeer = ref object + score: int + +proc getSlice(): seq[ref int] = + discard + +template smokeTest(kkind: SyncQueueKind, start, finish: uint64, + chunkSize: uint64) = + var queue: SyncQueue[SomeTPeer] + var request: SyncRequest[SomeTPeer] + discard queue.push(request, getSlice()) + +for k in {SyncQueueKind.Forward}: + for item in [(uint64(1181), uint64(1399), 41'u64)]: + smokeTest(k, item[0], item[1], item[2]) \ No newline at end of file From 46d2161c23c2aa1905571512b9a1ef7d61ae670e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Mar 2023 14:20:30 +0100 Subject: [PATCH 4251/4254] minor refactoring (#21499) --- compiler/liftdestructors.nim | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index d7b1f2daa..467f015d8 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -1085,13 +1085,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I let op = getAttachedOp(g, t, kind) if op != nil and op.ast != nil and op.ast.isGenericRoutine: if t.typeInst != nil: - var a: TLiftCtx - a.info = info - a.g = g - a.kind = kind - a.c = c - a.idgen = idgen - + var a = TLiftCtx(info: info, g: g, kind: kind, c: c, idgen: idgen) let opInst = instantiateGeneric(a, op, t, t.typeInst) if opInst.ast != nil: patchBody(g, c, opInst.ast, info, a.idgen) From af086b68f2f718a4ad20e37bf3a00d9a57abec4d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:01:12 +0800 Subject: [PATCH 4252/4254] fixes sinkinference documentation, which has been disabled (#21470) since https://github.com/nim-lang/Nim/pull/15105 --- doc/advopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/advopt.txt b/doc/advopt.txt index 122a7c6ea..4db89062b 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -172,6 +172,6 @@ Advanced options: --useVersion:1.0|1.2|1.6 emulate Nim version X of the Nim compiler, for testing --benchmarkVM:on|off turn benchmarking of VM code with cpuTime() on|off --profileVM:on|off turn compile time VM profiler on|off - --sinkInference:on|off turn sink parameter inference on|off (default: on) + --sinkInference:on|off turn sink parameter inference on|off (default: off) --panics:on|off turn panics into process terminations (default: off) --deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc`` From ffadc75afead6baed0885877edb2c3b1c9ef1b2e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 13 Mar 2023 03:03:14 +0800 Subject: [PATCH 4253/4254] fixes #21496; Ambiguous calls compiles when module name are equal (#21500) * fixes #21496; Ambiguous calls compiles when module name are equal * add a test case --- compiler/lookups.nim | 3 ++- tests/import/buzz/m21496.nim | 1 + tests/import/fizz/m21496.nim | 1 + tests/import/t21496.nim | 9 +++++++++ 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/import/buzz/m21496.nim create mode 100644 tests/import/fizz/m21496.nim create mode 100644 tests/import/t21496.nim diff --git a/compiler/lookups.nim b/compiler/lookups.nim index e7bca08bc..3f028a52f 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -343,7 +343,8 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = if sym.name.s == "_": return let conflict = scope.addUniqueSym(sym) if conflict != nil: - if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner: + if sym.kind == skModule and conflict.kind == skModule and + sym.position == conflict.position: # e.g.: import foo; import foo # xxx we could refine this by issuing a different hint for the case # where a duplicate import happens inside an include. diff --git a/tests/import/buzz/m21496.nim b/tests/import/buzz/m21496.nim new file mode 100644 index 000000000..7c87e2c04 --- /dev/null +++ b/tests/import/buzz/m21496.nim @@ -0,0 +1 @@ +proc fb* = echo "buzz!" \ No newline at end of file diff --git a/tests/import/fizz/m21496.nim b/tests/import/fizz/m21496.nim new file mode 100644 index 000000000..834c11eae --- /dev/null +++ b/tests/import/fizz/m21496.nim @@ -0,0 +1 @@ +proc fb* = echo "fizz!" \ No newline at end of file diff --git a/tests/import/t21496.nim b/tests/import/t21496.nim new file mode 100644 index 000000000..568f2ac51 --- /dev/null +++ b/tests/import/t21496.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "redefinition of 'm21496'; previous declaration here: t21496.nim(5, 12)" +""" + +import fizz/m21496, buzz/m21496 + +# bug #21496 + +m21496.fb() From b2c1dcbbc9b097c9c13dda4951e824cdb5f16225 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 13 Mar 2023 03:03:46 +0800 Subject: [PATCH 4254/4254] fixes explicit globals in macros (#21502) --- compiler/vmgen.nim | 3 ++- tests/vm/tvmmisc.nim | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index be7938e53..937d4b095 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1909,7 +1909,8 @@ proc genVarSection(c: PCtx; n: PNode) = c.genAdditionalCopy(a[2], opcWrDeref, tmp, 0, val) c.freeTemp(val) c.freeTemp(tmp) - elif not importcCondVar(s) and not (s.typ.kind == tyProc and s.typ.callConv == ccClosure): # fixes #10938 + elif not importcCondVar(s) and not (s.typ.kind == tyProc and s.typ.callConv == ccClosure) and + sfPure notin s.flags: # fixes #10938 # there is a pre-existing issue with closure types in VM # if `(var s: proc () = default(proc ()); doAssert s == nil)` works for you; # you might remove the second condition. diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 673e3e965..14818375d 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -643,3 +643,16 @@ const b = block: doAssert a == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] doAssert b == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] + +macro m1(s: string): int = + var ProcID {.global, compileTime.}: int + inc(ProcID) + result = newLit(ProcID) + +proc macroGlobal = + doAssert m1("Macro argument") == 1 + doAssert m1("Macro argument") == 2 + doAssert m1("Macro argument") == 3 + +static: macroGlobal() +macroGlobal()